diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000000..16bd810a18 --- /dev/null +++ b/.clang-format @@ -0,0 +1,7 @@ +--- +Language: Cpp +BasedOnStyle: LLVM +SortIncludes: false +Standard: Cpp11 +TabWidth: 2 +UseTab: Never diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000000..74f239821f --- /dev/null +++ b/.flake8 @@ -0,0 +1,35 @@ +[flake8] +max-line-length = 88 +ignore = + # Unnecessary dict/list/tuple call - rewrite as a literal + C408 + # whitespace before ':' - doesn't work well with black + E203 + # missing whitespace around operator - let black worry about that + E225 + # inline comment should start with '# ' + E262 + # block comment should start with '# ' + E265 + # too many leading '#' for block comment + E266 + # expected 2 blank lines, found 1 + E302 + # module level import not at top of file + E402 + # line too long - let black handle that + E501 + # comparison to None should be + E711 + # comparison to False/True should be + E712 + # ambiguous variable name + E741 + # may be undefined, or defined from star imports + F405 + # trailing + W291 + # line break occurred before a binary operator - let black worry about that + W503 + # line break occurred after a binary operator - let black worry about that + W504 \ No newline at end of file diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs new file mode 100644 index 0000000000..fc176d06bc --- /dev/null +++ b/.git-blame-ignore-revs @@ -0,0 +1 @@ +d3c6274e83eab857f122aacad925cf276e99212f diff --git a/.gitattributes b/.gitattributes index 8eb62bf889..1ea7eb0ad0 100644 --- a/.gitattributes +++ b/.gitattributes @@ -11,7 +11,6 @@ run_code_coverage_upload.sh export-ignore release-notes.sh export-ignore print-test-results.sh export-ignore appveyor.yml export-ignore -.travis.yml export-ignore astyle.sh export-ignore create_mapaxisorder_csv.py export-ignore genhtml.patch export-ignore diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000000..862b21d517 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,4 @@ +# point to OSGeo sponsor page +github: [OSGeo] +# point to PayPal directly +custom: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=KRJ2X44N3HA6U&source=url \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 0000000000..52a582b0b3 --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,44 @@ + + +## Expected behavior and actual behavior. + +For example (please modify !!!): I expected the following request to work +(paste request) and it returns an error message instead (paste error). + +## Steps to reproduce the problem. + +For example (please modify !!!): "mapserv -nh QUERY_STRING='map=test.map&...'" + +## Attach simple test case (drag/drop it here) + +Please create a .zip file that contains: + - small .map file + - data + - commands.txt (containing commands to reproduce your problem such as + map2img, mapserv, etc. + +## Operating system + +For example (please modify !!!): Ubuntu 16.04 64 bit + +## MapServer version and installation method + +For example (please modify !!!): the 7.6.1 version from ubuntugis-unstable PPA diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000000..5ace4600a1 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,6 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml index e0eae734f6..caa422363d 100644 --- a/.github/workflows/backport.yml +++ b/.github/workflows/backport.yml @@ -1,20 +1,18 @@ name: Backport on: - pull_request: + pull_request_target: types: - closed - labeled jobs: backport: - runs-on: ubuntu-18.04 + runs-on: ubuntu-latest name: Backport steps: - name: Backport Bot + id: backport if: github.event.pull_request.merged && ( ( github.event.action == 'closed' && contains( join( github.event.pull_request.labels.*.name ), 'backport') ) || contains( github.event.label.name, 'backport' ) ) - uses: Gaurav0/backport@v1.0.26 + uses: m-kuhn/backport@7f3cab83e4b3b26aefcffda21851c3dc3d389f45 #v1.2.7 with: - bot_username: MapServer-backport-bot - bot_token: 0cba09450792aa8130ae6ef3de09915654afc8cb - bot_token_key: 665c2358a46ddf0589de5e24a316cdcc64820b2e github_token: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/build-mapscript-php.yml b/.github/workflows/build-mapscript-php.yml new file mode 100644 index 0000000000..d5cc47ad95 --- /dev/null +++ b/.github/workflows/build-mapscript-php.yml @@ -0,0 +1,38 @@ +name: Build and test PHP MapScript + +on: + push: + branches: + - '*' + except: + - /^(cherry-pick-)?backport-\d+-to-/ + pull_request: + branches: + - '*' + except: + - /^(cherry-pick-)?backport-\d+-to-/ + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.ref }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + build: + runs-on: ubuntu-24.04 + strategy: + matrix: + php-version: [8.5, 8.4] + + steps: + - name: Checkout code + uses: actions/checkout@v7 + + - name: Set up PHP and Install Dependencies + run: | + docker run \ + -e WORK_DIR="$PWD" \ + -e PHP_VERSION="${{ matrix.php-version }}" \ + -v $PWD:$PWD ubuntu:24.04 $PWD/scripts/build-mapscript-php.sh diff --git a/.github/workflows/build-mapscript-python.yml b/.github/workflows/build-mapscript-python.yml new file mode 100644 index 0000000000..58058ff143 --- /dev/null +++ b/.github/workflows/build-mapscript-python.yml @@ -0,0 +1,34 @@ +name: Build and test Python MapScript + +on: + push: + branches: + - '*' + except: + - /^(cherry-pick-)?backport-\d+-to-/ + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.ref }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ["3.10", 3.11, 3.12, 3.13, 3.14] + + steps: + - name: Checkout code + uses: actions/checkout@v7 + + - name: Set up Python and Install Dependencies + run: | + docker run \ + -e WORK_DIR="$PWD" \ + -e PYTHON_VERSION="${{ matrix.python-version }}" \ + -e MAPSCRIPT_PYTHON_ONLY="true" \ + -v $PWD:$PWD ubuntu:24.04 $PWD/scripts/build-mapscript-python.sh diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000000..085c01b0ff --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,48 @@ +name: Build + +on: [push, pull_request] + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.ref }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + build: + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + include: + - name: Regular, with coverage + WITH_ASAN: "false" + WITH_COVERAGE: "true" + + - name: Address_sanitizer + WITH_ASAN: "true" + WITH_COVERAGE: "false" + + name: ${{ matrix.name }} + + steps: + - name: Checkout repository contents + uses: actions/checkout@v7 + + - name: Build + run: | + docker run \ + -e WORK_DIR="$PWD" \ + -e WITH_ASAN="${{ matrix.WITH_ASAN }}" \ + -e WITH_COVERAGE="${{ matrix.WITH_COVERAGE }}" \ + -v $PWD:$PWD ubuntu:24.04 $PWD/.github/workflows/start.sh + + - name: Coveralls + uses: coverallsapp/github-action@v2 + if: ${{ matrix.WITH_COVERAGE == 'true' }} + with: + format: lcov + file: mapserver.info + fail-on-error: false diff --git a/.github/workflows/build_alpine.sh b/.github/workflows/build_alpine.sh new file mode 100755 index 0000000000..ad80c3dc93 --- /dev/null +++ b/.github/workflows/build_alpine.sh @@ -0,0 +1,37 @@ +#!/bin/sh + +set -eu + +cd "$WORK_DIR" + +apk add \ + g++ \ + make \ + cmake \ + gdal-dev \ + proj-dev \ + geos-dev \ + curl-dev \ + fcgi-dev \ + libxml2-dev \ + protobuf-c-dev \ + freetype-dev \ + fribidi-dev \ + harfbuzz-dev \ + exempi-dev \ + giflib-dev \ + libpq-dev \ + python3-dev \ + swig + +mkdir build +cd build + +cmake .. \ + -DCMAKE_CXX_FLAGS="-Werror" \ + -DCMAKE_C_FLAGS="-Werror" \ + -DWITH_CLIENT_WFS=1 -DWITH_CLIENT_WMS=1 -DWITH_KML=1 -DWITH_SOS=1 \ + -DWITH_PYTHON=1 -DWITH_THREAD_SAFETY=1 -DWITH_FRIBIDI=1 -DWITH_FCGI=1 -DWITH_EXEMPI=1 \ + -DCMAKE_BUILD_TYPE=Release -DWITH_CURL=1 -DWITH_HARFBUZZ=1 + +make -j$(nproc) diff --git a/.github/workflows/build_alpine.yml b/.github/workflows/build_alpine.yml new file mode 100644 index 0000000000..91e38b3c82 --- /dev/null +++ b/.github/workflows/build_alpine.yml @@ -0,0 +1,25 @@ +name: Build Alpine Linux + +on: [push, pull_request] + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.ref }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + build: + runs-on: ubuntu-latest + name: build_alpine + + steps: + - name: Checkout repository contents + uses: actions/checkout@v7 + + - name: Build + run: | + docker run \ + -e WORK_DIR="$PWD" \ + -v $PWD:$PWD alpine:edge $PWD/.github/workflows/build_alpine.sh diff --git a/.github/workflows/check-crlf.yml b/.github/workflows/check-crlf.yml new file mode 100644 index 0000000000..2389a0df8e --- /dev/null +++ b/.github/workflows/check-crlf.yml @@ -0,0 +1,27 @@ +# check for Windows CRLF in files +# homepage: https://github.com/marketplace/actions/check-crlf + +name: Check CRLF + +on: [push, pull_request] + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.ref }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + Check-CRLF: + name: verify that only LF linefeeds are used + runs-on: ubuntu-latest + + steps: + - name: Checkout repository contents + uses: actions/checkout@v7 + + - name: Use action to check for CRLF endings + uses: erclu/check-crlf@master + with: # ignore directories containing *.pdf and *.tab + exclude: msautotest/misc/data/ /msautotest/renderers/expected/ diff --git a/.github/workflows/cifuzz.yml b/.github/workflows/cifuzz.yml new file mode 100644 index 0000000000..b62778143c --- /dev/null +++ b/.github/workflows/cifuzz.yml @@ -0,0 +1,32 @@ +name: CIFuzz +on: [pull_request] + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.ref }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + Fuzzing: + runs-on: ubuntu-latest + steps: + - name: Build Fuzzers + id: build + uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master + with: + oss-fuzz-project-name: 'mapserver' + dry-run: false + - name: Run Fuzzers + uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master + with: + oss-fuzz-project-name: 'mapserver' + fuzz-seconds: 600 + dry-run: false + - name: Upload Crash + uses: actions/upload-artifact@v7 + if: failure() && steps.build.outcome == 'success' + with: + name: artifacts + path: ./out/artifacts diff --git a/.github/workflows/code_checks.yml b/.github/workflows/code_checks.yml new file mode 100644 index 0000000000..f3202ca2be --- /dev/null +++ b/.github/workflows/code_checks.yml @@ -0,0 +1,21 @@ +name: Code Checks + +on: [push, pull_request] + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.ref }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + + linting: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + - uses: actions/setup-python@v6 + with: + python-version: '3.12' + - uses: pre-commit/action@v3.0.1 diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000000..ce5bd1e390 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,113 @@ +name: "CodeQL" + +on: + push: + pull_request: + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.ref }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + analyze: + name: Analyze + # Runner size impacts CodeQL analysis time. To learn more, please see: + # - https://gh.io/recommended-hardware-resources-for-running-codeql + # - https://gh.io/supported-runners-and-hardware-resources + # - https://gh.io/using-larger-runners + # Consider using larger runners for possible analysis time improvements. + runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }} + timeout-minutes: ${{ (matrix.language == 'swift' && 120) || 360 }} + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'c-cpp' ] + # CodeQL supports [ 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift' ] + # Use only 'java-kotlin' to analyze code written in Java, Kotlin or both + # Use only 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both + # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support + + steps: + - name: Checkout repository + uses: actions/checkout@v7 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v4 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + + # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs + # queries: security-extended,security-and-quality + config: | + query-filters: + - exclude: + id: cpp/non-https-url + - name: Install dependencies + run: | + sudo apt update + sudo apt-get install -y ccache cmake g++ + sudo apt-get install -y --allow-unauthenticated build-essential protobuf-c-compiler libprotobuf-c-dev bison flex libfribidi-dev \ + librsvg2-dev colordiff libpq-dev libpng-dev libjpeg-dev libgif-dev libgeos-dev libfreetype6-dev libfcgi-dev libcurl4-gnutls-dev \ + libcairo2-dev libgdal-dev libproj-dev libxml2-dev libexempi-dev libharfbuzz-dev + # cache the .ccache directory + # key it on the runner os, build type, deps, and arch + # It's especially important to include arch in the key because we + # may get runtime errors with -mavx2 from objects built on a + # different architecture. + - name: Restore build cache + if: matrix.language == 'c-cpp' + id: restore-cache + uses: actions/cache/restore@v6 + with: + path: ${{ github.workspace }}/.ccache + key: ${{ matrix.id }}-${{ steps.get-arch.outputs.arch }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ${{ matrix.id }}-${{ steps.get-arch.outputs.arch }}-${{ github.ref_name }} + ${{ matrix.id }}-${{ steps.get-arch.outputs.arch }} + - name: Configure ccache + if: matrix.language == 'c-cpp' + run: | + echo CCACHE_BASEDIR=${{ github.workspace }} >> ${GITHUB_ENV} + echo CCACHE_DIR=${{ github.workspace }}/.ccache >> ${GITHUB_ENV} + echo CCACHE_MAXSIZE=250M >> ${GITHUB_ENV} + ccache -z + - name: Build + if: matrix.language == 'c-cpp' + run: | + mkdir build + cd build + export CC="ccache gcc" + export CXX="ccache g++" + cmake .. -DCMAKE_BUILD_TYPE=RelWithDebInfo \ + -DWITH_CLIENT_WMS=1 \ + -DWITH_CLIENT_WFS=1 -DWITH_KML=1 -DWITH_SOS=1 \ + -DWITH_THREAD_SAFETY=1 -DWITH_FRIBIDI=1 -DWITH_FCGI=1 -DWITH_EXEMPI=1 \ + -DWITH_RSVG=1 -DWITH_CURL=1 -DWITH_HARFBUZZ=1 -DWITH_MSSQL2008=ON + make -j$(nproc) + - name: Summarize ccache + if: matrix.language == 'c-cpp' + run: | + ccache -s + - name: Save build cache + if: matrix.language == 'c-cpp' + uses: actions/cache/save@v6 + with: + path: ${{ github.workspace }}/.ccache + key: ${{ steps.restore-cache.outputs.cache-primary-key }} + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v4 + with: + category: "/language:${{matrix.language}}" diff --git a/.github/workflows/conda.yml b/.github/workflows/conda.yml new file mode 100644 index 0000000000..45afa926e0 --- /dev/null +++ b/.github/workflows/conda.yml @@ -0,0 +1,56 @@ + +name: Conda-Forge builds +on: [push, pull_request] + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.ref }} + cancel-in-progress: true + +jobs: + build: + name: CF ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [macos-latest, windows-latest, ubuntu-latest] + + steps: + - uses: actions/checkout@v7 + - uses: ilammy/msvc-dev-cmd@v1 + if: matrix.os == 'windows-latest' + - name: Support longpaths + run: git config --system core.longpaths true + if: matrix.os == 'windows-latest' + - uses: mamba-org/setup-micromamba@v3 + with: + init-shell: bash + environment-file: ci/conda/environment.yml + environment-name: "build" + cache-environment: true + cache-downloads: true + + - name: Setup + shell: bash -l {0} + run: | + mkdir build + + - name: CMake + shell: bash -l {0} + + run: | + + if [ "$RUNNER_OS" == "Windows" ]; then + export CC=cl.exe + export CXX=cl.exe + fi + + ../ci/conda/cmake.sh + + working-directory: ./build + + - name: Compile + shell: bash -l {0} + run: | + ninja + working-directory: ./build + diff --git a/.github/workflows/coverity-scan.yml b/.github/workflows/coverity-scan.yml new file mode 100644 index 0000000000..cf58514653 --- /dev/null +++ b/.github/workflows/coverity-scan.yml @@ -0,0 +1,33 @@ +name: coverity-scan + +# Controls when the action will run. +on: + # Run this action on a schedule (we're allowed a maximum of two per day) + schedule: + - cron: '0 18 * * SUN' # Sunday at 18:00 UTC + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.ref }} + cancel-in-progress: true + +permissions: + contents: read + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + build: + runs-on: ubuntu-latest + if: github.repository == 'MapServer/MapServer' + steps: + - uses: actions/checkout@v7 + + - name: Build + run: | + docker run \ + -e WORK_DIR="$PWD" \ + -e TOKEN="${{ secrets.COVERITY_SCAN_TOKEN }}" \ + -v $PWD:$PWD ubuntu:24.04 $PWD/scripts/coverity-scan.sh + diff --git a/.github/workflows/cppcheck.yml b/.github/workflows/cppcheck.yml new file mode 100644 index 0000000000..a726907485 --- /dev/null +++ b/.github/workflows/cppcheck.yml @@ -0,0 +1,25 @@ +name: cppcheck + +on: [push, pull_request] + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.ref }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + + cppcheck_2004: + runs-on: ubuntu-latest + if: "!contains(github.event.head_commit.message, '[ci skip]') && !contains(github.event.head_commit.message, '[skip ci]')" + steps: + - name: Checkout + uses: actions/checkout@v7 + + - name: Run cppcheck test + run: | + docker run \ + -e WORK_DIR="$PWD" \ + -v $PWD:$PWD ubuntu:24.04 $PWD/scripts/cppcheck.sh diff --git a/.github/workflows/irc_notify.yml b/.github/workflows/irc_notify.yml new file mode 100644 index 0000000000..b89db2f9eb --- /dev/null +++ b/.github/workflows/irc_notify.yml @@ -0,0 +1,53 @@ +# send build notifications to the #mapserver IRC channel +# homepage: https://github.com/marketplace/actions/notify-irc + +name: "IRC Push Notification" +on: + push: + branches: + - main + pull_request: + branches: + - main + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.ref }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + irc_notify: + runs-on: ubuntu-latest + #if: github.repository == 'MapServer/MapServer' + steps: + - name: irc push + uses: rectalogic/notify-irc@v2 + if: github.event_name == 'push' + with: + channel: "#mapserver" + server: "irc.libera.chat" + nickname: mapserver-github-notifier + message: | + ${{ github.actor }} pushed ${{ github.event.ref }} ${{ github.event.compare }} + ${{ join(github.event.commits.*.message) }} + - name: irc pull request + uses: rectalogic/notify-irc@v2 + if: github.event_name == 'pull_request' + with: + channel: "#mapserver" + server: "irc.libera.chat" + nickname: mapserver-github-notifier + message: | + ${{ github.actor }} opened PR ${{ github.event.pull_request.html_url }} + ${{ github.event.pull_request.title }} + - name: irc tag created + uses: rectalogic/notify-irc@v2 + if: github.event_name == 'create' && github.event.ref_type == 'tag' + with: + channel: "#mapserver" + server: "irc.libera.chat" + nickname: mapserver-github-notifier + message: | + ${{ github.actor }} tagged ${{ github.repository }} ${{ github.event.ref }} diff --git a/.github/workflows/start.sh b/.github/workflows/start.sh new file mode 100755 index 0000000000..34559a9626 --- /dev/null +++ b/.github/workflows/start.sh @@ -0,0 +1,200 @@ +#!/bin/bash + +set -e + +apt-get update -y + +export PYTHON_VERSION=system + +LANG=en_US.UTF-8 +export LANG +DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ + sudo locales tzdata software-properties-common python3-dev python3-venv python3-pip python3-setuptools git curl \ + apt-transport-https ca-certificates gnupg software-properties-common wget +#install PHP 8.1 +DEBIAN_FRONTEND=noninteractive add-apt-repository ppa:ondrej/php -y +DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ + sudo php8.1-dev php8.1-xml php8.1-mbstring && \ + echo "$LANG UTF-8" > /etc/locale.gen && \ + dpkg-reconfigure --frontend=noninteractive locales && \ + update-locale LANG=$LANG + +USER=root +export USER + +# Install pyenv +curl -L https://github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-installer | bash +export PATH="/root/.pyenv/bin:$PATH" +eval "$(pyenv init -)" +eval "$(pyenv virtualenv-init -)" +# ensure python points to python3 +ln -s /usr/bin/python3 /usr/bin/python + +# set the global Python version +pyenv global $PYTHON_VERSION + +cd "$WORK_DIR" + +ci/ubuntu/setup.sh +ci/ubuntu/build.sh + +# Validate openapi document +pip install check-jsonschema --break-system-packages +wget https://raw.githubusercontent.com/OAI/OpenAPI-Specification/refs/heads/main/_archive_/schemas/v3.0/schema.yaml -O openapi_schema.yaml +echo "Run check-jsonschema --schemafile openapi_schema.yaml msautotest/api/expected/ogcapi_api.json" +check-jsonschema --schemafile openapi_schema.yaml msautotest/api/expected/ogcapi_api.json + +##################################### +# Test MapServer as CGI and FastCGI # +##################################### + +make cmakebuild_nocoverage MFLAGS="-j${nproc}" + +ln -s mapserv /tmp/install-mapserver/bin/mapserv.cgi +ln -s mapserv /tmp/install-mapserver/bin/mapserv.fcgi + +DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends apache2 libapache2-mod-fcgid +a2enmod fcgid cgid +a2disconf serve-cgi-bin +a2dissite 000-default + +echo "ServerName www.example.com" > /etc/apache2/conf-available/servername.conf +a2enconf servername + +cat </etc/apache2/sites-available/001-mapserver.conf + + ErrorLog \${APACHE_LOG_DIR}/mapserv-error.log + CustomLog \${APACHE_LOG_DIR}/mapserv-access.log combined + + SetEnv MAPSERVER_CONFIG_FILE ${WORK_DIR}/msautotest/etc/mapserv.conf + FcgidInitialEnv MAPSERVER_CONFIG_FILE ${WORK_DIR}/msautotest/etc/mapserv.conf + + ScriptAlias /cgi-bin/ "/tmp/install-mapserver/bin/" + + AddHandler fcgid-script .fcgi + AddHandler cgi-script .cgi + AllowOverride All + Options +ExecCGI -MultiViews +FollowSymLinks + Order Allow,Deny + Allow from all + Require all granted + + +EOF + +a2ensite 001-mapserver + +service apache2 restart + +# Prepare mapfile and related resources +cat msautotest/wxs/wfs_simple.map | sed "s/\.\/data\/epsg2/\/tmp\/data\/epsg2/" | sed "s/SHAPEPATH \.\/data/SHAPEPATH \/tmp\/data/" | sed "s/ etc/ \/tmp\/etc/" > /tmp/wfs_simple.map +cp -r $WORK_DIR/msautotest/wxs/data /tmp +cp -r $WORK_DIR/msautotest/wxs/etc /tmp + +echo "Running CGI query" +curl -s "http://localhost/cgi-bin/mapserv.cgi?MAP=/tmp/wfs_simple.map&SERVICE=WFS&REQUEST=GetCapabilities" > /tmp/res.xml +cat /tmp/res.xml | grep wfs:WFS_Capabilities >/dev/null || (cat /tmp/res.xml && /bin/false) + +echo "Running FastCGI query" +curl -s "http://localhost/cgi-bin/mapserv.fcgi?MAP=/tmp/wfs_simple.map&SERVICE=WFS&REQUEST=GetCapabilities" > /tmp/res.xml +cat /tmp/res.xml | grep wfs:WFS_Capabilities >/dev/null || (cat /tmp/res.xml && /bin/false) + +echo "Running FastCGI query again" +curl -s "http://localhost/cgi-bin/mapserv.fcgi?MAP=/tmp/wfs_simple.map&SERVICE=WFS&REQUEST=GetCapabilities" > /tmp/res.xml +cat /tmp/res.xml | grep wfs:WFS_Capabilities >/dev/null || (cat /tmp/res.xml && /bin/false) + +echo "Check that we return an error if given no arguments" +curl -s "http://localhost/cgi-bin/mapserv.fcgi" > /tmp/res.xml +cat /tmp/res.xml | grep -q 'QUERY_STRING is set, but empty' || (cat /tmp/res.xml && /bin/false) + +echo "Check again to make sure further errors are reported (#6543)" +curl -s "http://localhost/cgi-bin/mapserv.fcgi" > /tmp/res.xml +cat /tmp/res.xml | grep -q 'QUERY_STRING is set, but empty' || (cat /tmp/res.xml && /bin/false) + +cd msautotest/wxs + +export PATH=/tmp/install-mapserver/bin:$PATH + +# Demonstrate that mapserv will error out if cannot find config file +mapserv 2>&1 | grep "msLoadConfig(): Unable to access file" >/dev/null && echo yes +mapserv QUERY_STRING="MAP=wfs_simple.map&REQUEST=GetCapabilities" 2>&1 | grep "msLoadConfig(): Unable to access file" >/dev/null && echo yes +mapserv QUERY_STRING="map=ows_context.map&CONTEXT=ows_context.xml&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetCapabilities" 2>&1 | grep "msLoadConfig(): Unable to access file" >/dev/null && echo "Check that we can't load a OWS context file if MS_CONTEXT_PATTERN is not defined: yes" + +echo "Check that MS_MAP_NO_PATH works" +cat </tmp/mapserver.conf +CONFIG + ENV + "MS_MAP_NO_PATH" "1" + END + MAPS + "MYMAPFILE" "/tmp/wfs_simple.map" + END +END +EOF +# Also demonstrate that mapserv can find config file in ${CMAKE_INSTALL_FULL_SYSCONFDIR}/etc/mapserver.conf by default +ln -s /tmp/mapserver.conf /tmp/install-mapserver/etc +mapserv QUERY_STRING="MAP=MYMAPFILE&SERVICE=WFS&REQUEST=GetCapabilities" > /tmp/res.txt +rm /tmp/install-mapserver/etc/mapserver.conf +cat /tmp/res.txt | grep wfs:WFS_Capabilities >/dev/null || (cat /tmp/res.txt && /bin/false) + +echo "Check that -conf switch parameter works in a non-CGI context" +mapserv QUERY_STRING="MAP=MYMAPFILE&SERVICE=WFS&REQUEST=GetCapabilities" -conf /tmp/mapserver.conf > /tmp/res.txt +cat /tmp/res.txt | grep wfs:WFS_Capabilities >/dev/null || (cat /tmp/res.txt && /bin/false) + +echo "Check that MS_MAP_NO_PATH works (rejecting a value not defined in the MAPS section)" +MAPSERVER_CONFIG_FILE=/tmp/mapserver.conf mapserv QUERY_STRING="MAP=FOO&SERVICE=WFS&REQUEST=GetCapabilities" > /tmp/res.txt +cat /tmp/res.txt | grep "Web application error" >/dev/null || (cat /tmp/res.txt && /bin/false) + +echo "Check that MS_MAP_PATTERN works (accepting valid MAP)" +cat </tmp/mapserver.conf +CONFIG + ENV + "MS_MAP_PATTERN" "^wfs_simple\.map$" + END +END +EOF +MAPSERVER_CONFIG_FILE=/tmp/mapserver.conf mapserv QUERY_STRING="MAP=wfs_simple.map&SERVICE=WFS&REQUEST=GetCapabilities" > /tmp/res.txt +cat /tmp/res.txt | grep wfs:WFS_Capabilities >/dev/null || (cat /tmp/res.txt && /bin/false) + +echo "Check that MS_MAP_PATTERN works (rejecting invalid MAP)" +cat </tmp/mapserver.conf +CONFIG + ENV + "MS_MAP_PATTERN" "mypatternmapserv" + END +END +EOF +MAPSERVER_CONFIG_FILE=/tmp/mapserver.conf mapserv QUERY_STRING="MAP=wfs_simple.map&SERVICE=WFS&REQUEST=GetCapabilities" > /tmp/res.txt +cat /tmp/res.txt | grep "Web application error" >/dev/null || (cat /tmp/res.txt && /bin/false) + +echo "Check that MS_MAPFILE works alone" +cat </tmp/mapserver.conf +CONFIG + ENV + "MS_MAPFILE" "wfs_simple.map" + END +END +EOF +MAPSERVER_CONFIG_FILE=/tmp/mapserver.conf mapserv QUERY_STRING="SERVICE=WFS&REQUEST=GetCapabilities" > /tmp/res.txt +cat /tmp/res.txt | grep wfs:WFS_Capabilities >/dev/null || (cat /tmp/res.txt && /bin/false) + +echo "Check that a MAP query parameter isn't accepted when MS_MAPFILE and MS_MAP_NO_PATH are specified" +cat </tmp/mapserver.conf +CONFIG + ENV + "MS_MAPFILE" "wfs_simple.map" + "MS_MAP_NO_PATH" "1" + END +END +EOF +MAPSERVER_CONFIG_FILE=/tmp/mapserver.conf mapserv QUERY_STRING="MAP=wfs_simple.map&SERVICE=WFS&REQUEST=GetCapabilities" > /tmp/res.txt +cat /tmp/res.txt | grep "Web application error" >/dev/null || (cat /tmp/res.txt && /bin/false) + +# Check https://github.com/MapServer/MapServer/security/advisories/GHSA-xqj6-vjqr-33vv +MAPSERVER_CONFIG_FILE=${WORK_DIR}/msautotest/etc/mapserv.conf SCRIPT_NAME=mapserv SERVER_PORT=80 HTTP_X_FORWARDED_HOST="with'single'quote" mapserv QUERY_STRING="MAP=wms_simple_no_onlineresource.map&SERVICE=WMS&VERSION=1.1.0&REQUEST=GetMap&SRS=EPSG:4326&BBOX=-67.5725,42.3683,-58.9275,48.13&FORMAT=application/openlayers&WIDTH=300&HEIGHT=200&STYLES=&LAYERS=road" > /tmp/res.txt +# We need to escape backslash once for the grep regexp, and once for the shell... +# Hence 4 backslashes for one in the actual output +cat /tmp/res.txt | grep "with\\\\'single\\\\'quote" >/dev/null || (cat /tmp/res.txt && /bin/false) + + +echo "Done !" diff --git a/.gitignore b/.gitignore index bf0b47bcf6..672e1a772b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,7 @@ build build_vagrant +build_vagrant_proj7 +install-vagrant-proj *.swp nbproject tags diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000000..b441890308 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,34 @@ +repos: + - repo: https://github.com/psf/black + rev: 22.3.0 + hooks: + - id: black + - repo: https://github.com/timothycrosley/isort + rev: 5.12.0 + hooks: + - id: isort + args: ["--profile", "black"] + - repo: https://github.com/pycqa/flake8 + rev: 7.2.0 + hooks: + - id: flake8 + - repo: https://github.com/pre-commit/mirrors-clang-format + rev: 'v15.0.7' + hooks: + - id: clang-format + exclude_types: [c#, java, javascript, json, proto] + exclude: > + (?x)^( + build | + src/renderers/agg/ | + src/flatgeobuf/ | + src/opengl/ | + src/third-party/ | + src/maplexer.c | + src/mapparser.c | + src/mapparser.h | + src/dejavu-sans-condensed.h | + src/cql2textparser.cpp| + src/cql2textparser.hpp| + src/uthash.h + ) diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 780251daef..0000000000 --- a/.travis.yml +++ /dev/null @@ -1,91 +0,0 @@ -branches: - except: - - /^(cherry-pick-)?backport-\d+-to-/ - -dist: trusty -language: php - -matrix: - include: - - - php: 5.6 - env: - - BUILD_NAME=PHP_5.6 - - - php: 7.0 - env: - - BUILD_NAME=PHP_7.0 - - - php: 7.1 - env: - - BUILD_NAME=PHP_7.1 - - - php: 7.2 - env: - - BUILD_NAME=PHP_7.2_WITH_ASAN - - - php: 7.3 - env: - - BUILD_NAME=PHP_7.3_WITH_PROJ6 - -cache: - apt: true - directories: - - $HOME/.ccache - -env: - global: -# Encrypted private key of the deploy key of the github.com/mapserver/coverage.git repository - - secure: "B1Tt18Q4F82+cXlj4fBoZDiyWbXLuzpJD6jt828qiS/i9ws8IEqYF7x3V4fo\nAnO1pZ84hdIOEfcSj2tFnysCPZ+zpOPzN2ma7iVEgmFTPNXf8pSx8CTXtiI/\nohUEcnARRCyuCK7cjEP5m4iWGazI+Pc563X4g67ToRPkLhIdrEg=" - - secure: "OvxCriM3Dwa0wkZ+nQL8e6nuMrG2hrfET+QEPRps/fPSGSR+yRWo04hBqRn2\niBTJGpi0JvaTN0pxjCx2I/+4jbzkNt+J6IqSz2KTUzseiWA3tyAN8uel6fIo\nkS90UJ7OeKUuYkvzfVwYn6pxM6b+CN6+DTs0dlWgxyMg/AtVdz8=" - - secure: "Vcf+jOzNtXapBf8qfM8N0ZTarQ9B7qqvG8X8fLJP5M2uDO2BrruMIZPpxwcL\nGMBkkZZGuofeqOs+BNxwnO1l4YOC+JUzQGQnExbEi02QDVzdR4+3sUvruXtL\nU/ppXvjghchgqvVp8QMjiVkUG1Ja1qwwCDM0GSN/PTfBy+Pjav0=" - - secure: "FcCFPhMjgeAcSMFiTaZC6cp3IrAP9PvpAiuiKchG2smlQe85nvwdUbap7aFu\nJ8ujnuqzQJ1pc2+GAtCn0OZZ1Bh9mW31FEESiU74TphaKOFY8qAKrR7TamWx\n5XLqHvNu16LlOy/Cy8G82dMCGzPJCadM/ZwdI/RsWwRqjHgIHv0=" - - secure: "Zs2+0yF2P6WWVT4o1kmgkSRmHUL1dkAYk+tHU0Piie+czblouMmqdJwsBNP6\nQF454VinL3Pu2tgbDAF10V+HknW/0ZevvmcrNa9k+Hjry8VtMNdM7jMqv4it\nYU5IGR55wfRg5q6c1jRxIPwc3Ssh2VOlz7HByppPG6i37prYO8I=" - - secure: "rnFScHTmX9VDMUquOlP1FPGCr/GpCu64xw4m5AC5nIP/BCSdFSak02cc/JgC\nJPvuoud5xftyBspPRDB2eBP4YXOcPuSEdysibpGGBagKj7faCNQmCZSDd3zR\nWvLJwlfuQ39PoTIHU6O/TCX4U+v/gm4WJMwm1Tip1ID+wqqyoNU=" - - secure: "h57JVvts9A0XF9ckGGokZwuD1hTBDOS0o1Yq3lD0Xd2BeJrgAXwgnKsBnBNP\nEMTBfRLGVyTgR8hiamySlWUUyVVQXMuLvKu1JnlrnZltMC8YGH4QEQwc7Twj\ni2GmsouUUHGOHU10U1F+YllSWZJjfLa6kgjkMNHg617c+PZfPLg=" - - secure: "gB/9lGc5o6xeJSLler3s5ZmP0Kn+x1knSw5BIUQkke7rzWlMIaeZHqEf1iQm\n49Q2Aepo0I+RdAaGNlPHR3KrUc3P3/ZokWZ1zv449Mh0OKLNrLSE+CruuVYj\n2XcOrLC2vjSsMfaM9520spdjbvVpcTUKJho9kGRTPKLs8YbGLv8=" - - secure: "px+guXOAtfmiBRub6sgvzlidKEmCNVthyAcaRHRzdtl6j7XoXHPGL2QHb8YH\nxV/wtDnLFIZi1eoShpLwABGvqQ1KQ20X+nz8FWZDnmDK3PXVBTqaUMyarmEB\nT7UohY94d8S2NqWJqeiOqVfMBOsIve9N1g3mcSUAlYMngEYoVt0=" - - secure: "jPxrLpA61LxMH2a8k9P22l3/7Yx+Lhzmrne61xkFGo1F9oqwHap88AKm0gP3\nEApgDmCVRvHgetfEFIxapF+6yPZinE0EsqJonKS1NCeKjs91LMsM7Dr3UiU3\nNaco2w3B0v6dDOdG1JhAV6N/CqdWXz85hooSWsLrWpYMtPbOfJQ=" - - secure: "dFvmnenj189QmbFdTW2ckHPbYojouowtz8cURDrR/2BiU0a3GUUDHP0h9O+c\nLDfJ1g03hsMr8m/45QdpL/x2lROimczFNu/U+uS8Vtja1z4SYaOMDjW4p3pq\nqPzQc/WmlpBY8wmfCH1WqmRRPvrfKceEDtVhWXruxpSZUx/OvoY=" - - secure: "TmOZmx8kyEOCUOMmWKuPpKzqBpbCKMOJpankHhhEAwJ00iJ3bMzdZk7dFsMV\nq9sk2nAgkARsVakfhiUvM516CKgf3J5rskUq+AQs6JdFP8w9A3LKowLHxlqg\nCvhQtOm3ff1EVQKeDOfgUxaI20Ulq6sl+b1/uq2W1v25IqwR1ps=" - - secure: "rYU47VfOGgheYhF/Xy6DM9iRi+NPSoyfMQ9B0Hoznm7k/TI1ojEky/wnIp3A\n+UdkoNo0xYzLZdjY4b1UBukMTKZJXVpYHs+KwKMhJQU3UaXpWEWo0Hqr8fU1\nOf7nspF27o79xcc3R+Okuz7L2J8+jD6Ggi2NW5vvp2S+jQW4Py4=" - - secure: "PXqhXu3cK9nf80Pv4AgqS2R8HVLAHVGozqfAeAgPDOZQYUCbAyEm/QZ5WbPb\nzNQAYuEFVjt59H0b3fOM5rUSX8Igx0NeG9rxG6WYyitXZWinXyeKeZ5yKn1f\nI/gIZPVH1r1H30+TCOH9sD9rH/2eRzb5ycDGKccZfv5/MocwKwg=" - - secure: "KK6YzOtwmbd3UbfiavTowvUkTGXN23ZMONwP7OpTTDZ+1/XVBeiuGLJAdHsn\nLPOImlytI9SavQekA6w4EaPb9VLRoC+O1CXOlllEjxfo0LojXDBKCaoyXOx3\nu1K8aXjyeZ2dPagjz06NV6r+y9tGypHrR7qXArVANRkzsajpABM=" - - secure: "XH1YshS/QJTOWxlccDjHVCSnN3IDYqug8hw+xOpNXeKR/VbZ82lv6s1gURHh\nKI6jDPGUFiD/OA37SDmArT/CbZ2zDJtSB8YNDr8w/wInlp7vnWBoRWlFQ3eP\nsJDexlZTCvo3TUogHFpLrbq9WuEXLCJ/yfYq1zJfFvipDWR6MhQ=" - - secure: "QoM0cJU0QioMMcD8Vs4xD04+jMGrTmbxxESpR4fwllAhP0ZpZt8E1qPQV9Hq\nVNzRVF/FLMlmDL8LzAYOFzVZASpb0X0l5KmxqRN3rRkSDc/LLSQf+701W00T\nJLAUXB05JPvJE5QBM5VgqNivO1JAC/Y0D83Pio8fHxYFUG6M9DM=" - - secure: "LufnBePmcGefhwb3ofhBiPWdiGjGMa8G83HNdYv4BGMNyJqGa4rVaFg5yPa2\nLZx0JPwEoWK+i3QuI2ug37bSSBMf0130sUOn+E+Vy4fHeGrCdt3WrwSjACq5\nGgaBQ1JN6zLI8Gt4ekcOBOZNme6a+eMoW6asAhroIPoU1Jo/5o0=" - - secure: "LZorvKqv/ncsk6sZS5NaZch/msx3HCHcy3e6BEJwudQHnF5iLz8TGbJFL9UL\nXjVX6H+CmnOQW9qbMEWTfMVXuLEXCVpX0YoQuhYwYEbhdSmz8PFJlv8BxxJg\n3OOZo0QgD2ZZ/KBenj3XIVVKeS2jHBUhXKP8G6D88xmdt3GtzRY=" - - secure: "JmHFSkvxfoY6vfSM35K2eC4X0GN9n1SWapBzIFT70rz3PNKAY2QAGlvcMI2W\nZZ5JouXHHESXR+mujllzZRcx9ZJQ67k65OxG+a1ID+rivTO1A0kU36chBy8Q\nNgskyAD68gixuYts+4MXb1biXKdEO9AmUTu3zDvgqo5vcTIjvPU=" - - secure: "QMjLOqEDegfPTTlm1f4SX2/77XLqAjpPrQ483EGRY59/xrS1aI0l9jTgpgTv\nZ/JyuYOX+JkbQBeW1ZuAhaXH1Q2AZ7Sun+adJ0B4yLZTHFiiy2mIFe7CcUCi\np+WgxwSPvi+uZUvEEAczKFWDKvM8qyUwZoHqaYj7VU4mComfsyE=" - - secure: "RynRoItVw0gkM5OznZYhoDuukwOXVVXS5sF75G53FpoobXQYaUR20BoPFqtT\nHptuGei3f23Afiq3j807GWNoOxqVIaIoijMVxEBk6/xu43DYqUO3Nx4fB6Bk\nHdp4qNTfTVtsqy7IuXzbB3koS5xc1DUPHFDYh10pH5xWItUxlEc=" - - secure: "UVtqSIfAKYSW0J06QEo+HveY+krqc7rEvnO5SNVzcQCFahnfWOIec6WQPd6O\nF/wPRjcC/zxg8PK/u5RHOKDNY6/nFNnRE7b8+MkxKcWZiFy0TipGjr57n6GW\nzgBGFi4Kw8XqFkC4hKC2eqiA8iYC+xCVzLNtnT3zp0fBG/nSrR8=" - - secure: "jGoUxEIa0Mi1RZU+nZpgO9c5vw82Yl4s1h+0bimQ17OA44mmOD4UQ4ygkH+1\nKsDwJ1JxP85K2EVZdwI4EswHCH1gYRzHyO0Mo6r9LOB8aGb60mq4BCQj80oI\nlw/i4K037sb0zqys7uu0J0UD9Xep0F49uYBdrnXl5l/fLzHTm1w=" - - secure: "CzFKm/g+wLUdsu4ecEx6v93ZS/CM0/3hcBxPtt/nRbmF95KW+QZMIpwUbmsH\nIZhljPkWjKOceB1sotdJjXWzEuPMj64rh9cJyWw2WO7eGG0NtbovZPUEZF4P\nz6sa3KcjNnLYAMq3Op29p23DLaZWzJqy6yzFvYQF8lxUYIyhLDU=" - - secure: "fwO9vY9pIHgsCoETgQCkTVzKguuItFwLnkWOzZtzvt8fiJw2/ZafycnsTJMc\nh3/jZpn1+K+dQr7jMks9vKTXLq5101Z4SBbxaa0bt9NjyGlL72gf8sB331Oh\nLZ/E/415jeRT8sFoYNvKOfL+rtqqHaimJkaS/XvRUfru/zrb5Rw=" - - secure: "TN6ig2qgH6EFGEttDtD9rxj2bH3BUJA4rJafjOXiAdQUVcH9E6lWeIaorzy9\n5Empsi/iC2rXF9i+JwE+OreUh47NL3P9jQN8dNkRmyLiuGpVVmreXynLydsS\nmaxPVwRKKSkL1PR54ICQ/Blw0vR27AqlvxO/gLcESG9Xu3Isa4o=" - - secure: "BacSp+HDt0fEiSElLIzfTxi72sjO1VZkQc2/+AEJqYnGmBse1eofV9XRSlfd\nfm2qDXER34y2PerxBL5EmF3D0kG8vhBANOtHTHw5LlTR8xa/MJIMZag6zw7q\nBacSmiRNbw9XpTN+lcYvzrKFaf29exBvdKCGBv7qdMzLcEMxBVw=" - - secure: "Bj/9iVBA6DGVcGRdbt3bQms8VglgSjdhI7IwvRkO3Gfvq0FTg1Hu8nodAiwM\nrfMfHzvTGNZudAkBRmPE6xZtIbID6v89S8CqEx3iGU+qbvni2nVt1SzEppb4\n8oZLKlZf3dCthrR2rpIdVMcccWhW3AjDfHKO9OlV2VR90NkWKz4=" - - secure: "OJqQvNnWc0MWNOxsyhtfnn6XLj3Ssmcl+nRAp2KBwI691HvXMDsqmIXBEjq1\nql+iuNn7sxn9v+ooGXmrFS9CHndncmtKEvNzdi1HKlJhEAG0+MCYnwYwaQHr\n+6HhCnLoZ2wiE+OANFjodkQRNQ4VyATOEn5WFnp56CEtiFQiNzM=" - -compiler: - - gcc - - clang - -before_install: - - ./ci/travis/before_install.sh - -script: - - ./ci/travis/script.sh - -after_success: - - ./ci/travis/after_success.sh - -notifications: - email: - recipients: - - thomas.bonfort@gmail.com - irc: - channels: - - "irc.freenode.org#mapserver" - use_notice: true - diff --git a/CITATION.cff b/CITATION.cff new file mode 100644 index 0000000000..fc58e2dfb9 --- /dev/null +++ b/CITATION.cff @@ -0,0 +1,64 @@ +cff-version: 1.2.0 +title: MapServer +message: If you use this software, please cite it using the metadata from this file. +version: 8.6.4 +date-released: 2026-06-01 +abstract: MapServer is an Open Source platform for publishing spatial data and interactive mapping applications to the web. +type: software +authors: + - family-names: McKenna + given-names: Jeff + affiliation: GatewayGeo + orcid: https://orcid.org/0000-0003-3900-1863 + - family-names: Lime + given-names: Steve + affiliation: MNIT DNR + - family-names: Bonfort + given-names: Thomas + affiliation: Airbus + - family-names: Boué + given-names: Jérome + - family-names: Butler + given-names: Howard + affiliation: Hobu Inc + orcid: https://orcid.org/0000-0002-5340-1380 + - family-names: Girvin + given-names: Seth + affiliation: Geographika + - family-names: Kralidis + given-names: Tom + - family-names: Meissl + given-names: Stephan + affiliation: EOX + orcid: https://orcid.org/0000-0002-1407-8859 + - family-names: Morissette + given-names: Daniel + affiliation: Mapgears + - family-names: Nacionales + given-names: Perry + affiliation: University of Minnesota + - family-names: Rahkonen + given-names: Jukka + affiliation: National Land Survey of Finland + - family-names: Rouault + given-names: Even + affiliation: Spatialys + orcid: https://orcid.org/0000-0002-5068-0476 + - family-names: Smith + given-names: Mike + affiliation: US Army Corps of Engineers + - family-names: Szekeres + given-names: Tamas +repository-code: https://github.com/MapServer/MapServer +license: MIT +doi: 10.5281/zenodo.6994443 +keywords: + - web + - geospatial + - software + - ogc + - standards + - gdal + - open source + - free software + - MIT diff --git a/CMakeLists.txt b/CMakeLists.txt index 526ca67735..d63fc64439 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required (VERSION 3.0) +cmake_minimum_required(VERSION 3.16...3.29) project (MapServer) @@ -11,28 +11,28 @@ endif("${PROJECT_SOURCE_DIR}" STREQUAL "${PROJECT_BINARY_DIR}") include(CheckLibraryExists) include(CheckFunctionExists) +include(CheckSymbolExists) include(CheckIncludeFile) include(CheckCSourceCompiles) - -set (MapServer_VERSION_MAJOR 7) +set (MapServer_VERSION_MAJOR 8) set (MapServer_VERSION_MINOR 7) set (MapServer_VERSION_REVISION 0) set (MapServer_VERSION_SUFFIX "") # Set C++ version # Make CMAKE_CXX_STANDARD available as cache option overridable by user -set(CMAKE_CXX_STANDARD 11 - CACHE STRING "C++ standard version to use (default is 11)") +set(CMAKE_CXX_STANDARD 17 + CACHE STRING "C++ standard version to use (default is 17)") message(STATUS "Requiring C++${CMAKE_CXX_STANDARD}") set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) message(STATUS "Requiring C++${CMAKE_CXX_STANDARD} - done") -# Set C99 version +# Set C version # Make CMAKE_C_STANDARD available as cache option overridable by user -set(CMAKE_C_STANDARD 99 - CACHE STRING "C standard version to use (default is 99)") +set(CMAKE_C_STANDARD 17 + CACHE STRING "C standard version to use (default is 17)") message(STATUS "Requiring C${CMAKE_C_STANDARD}") set(CMAKE_C_STANDARD_REQUIRED ON) set(CMAKE_C_EXTENSIONS OFF) @@ -51,9 +51,11 @@ endif(MapServer_IS_DEV_VERSION) MATH(EXPR MapServer_VERSION_NUM "${MapServer_VERSION_MAJOR}*10000+${MapServer_VERSION_MINOR}*100+${MapServer_VERSION_REVISION}") SET(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake ${CMAKE_MODULE_PATH}) - -# Add custom function to check Python modules are installed -include(FindPythonModule) +foreach(_version IN ITEMS 3.20) + if(CMAKE_VERSION VERSION_LESS "${_version}") + list(INSERT CMAKE_MODULE_PATH 0 "${PROJECT_SOURCE_DIR}/cmake/${_version}") + endif() +endforeach() if (APPLE) set(CMAKE_FIND_FRAMEWORK "LAST") @@ -80,10 +82,10 @@ endforeach() macro (ms_link_libraries) if(BUILD_DYNAMIC) - target_link_libraries(mapserver ${ARGV}) + target_link_libraries(mapserver PRIVATE ${ARGV}) endif(BUILD_DYNAMIC) if(BUILD_STATIC) - target_link_libraries(mapserver_static ${ARGV}) + target_link_libraries(mapserver_static PRIVATE ${ARGV}) endif(BUILD_STATIC) endmacro() @@ -118,7 +120,16 @@ check_function_exists("strlcat" HAVE_STRLCAT) check_function_exists("strlcpy" HAVE_STRLCPY) check_function_exists("strlen" HAVE_STRLEN) check_function_exists("strncasecmp" HAVE_STRNCASECMP) -check_function_exists("vsnprintf" HAVE_VSNPRINTF) + +IF((HAVE_STRLCAT OR HAVE_STRLCPY) AND CMAKE_SYSTEM_NAME MATCHES "Linux") + add_definitions(-D_DEFAULT_SOURCE) +ENDIF() + +check_symbol_exists(vsnprintf stdio.h HAVE_VSNPRINTF) +IF(NOT HAVE_VSNPRINTF) + check_function_exists("vsnprintf" HAVE_VSNPRINTF) +ENDIF() + check_function_exists("lrintf" HAVE_LRINTF) check_function_exists("lrint" HAVE_LRINT) @@ -136,12 +147,12 @@ int main(int argc, char **argv) { include_directories(${CMAKE_CURRENT_BINARY_DIR}) -#options suported by the cmake builder +#options supported by the cmake builder option(WITH_PROTOBUFC "Choose if protocol buffers support should be built in (required for vector tiles)" ON) option(WITH_KML "Enable native KML output support (requires libxml2 support)" OFF) option(WITH_SOS "Enable SOS Server support (requires PROJ and libxml2 support)" OFF) -option(WITH_WMS "Enable WMS Server support (requires proj support)" ON) -option(WITH_FRIBIDI "Choose if FriBidi glyph shaping support should be built in (usefull for right-to-left languages) (requires HARFBUZZ)" ON) +option(WITH_WMS "Enable WMS Server support (requires PROJ support)" ON) +option(WITH_FRIBIDI "Choose if FriBidi glyph shaping support should be built in (useful for right-to-left languages) (requires HARFBUZZ)" ON) option(WITH_HARFBUZZ "Choose if Harfbuzz complex text layout should be included (needed for e.g. arabic and hindi) (requires FRIBIDI)" ON) option(WITH_ICONV "Choose if Iconv Internationalization support should be built in" ON) option(WITH_CAIRO "Choose if CAIRO rendering support should be built in (required for SVG and PDF output)" ON) @@ -151,34 +162,43 @@ option(WITH_MYSQL "Choose if MYSQL joining support should be built in" OFF) option(WITH_FCGI "Choose if FastCGI support should be built in" ON) option(WITH_GEOS "Choose if GEOS geometry operations support should be built in" ON) option(WITH_POSTGIS "Choose if Postgis input support should be built in" ON) -option(WITH_CLIENT_WMS "Enable Client WMS Layer support (requires CURL and GDAL support)" OFF) -option(WITH_CLIENT_WFS "Enable Client WMS Layer support (requires CURL and OGR support)" OFF) +option(WITH_CLIENT_WMS "Enable Client WMS Layer support (requires CURL)" OFF) +option(WITH_CLIENT_WFS "Enable Client WMS Layer support (requires CURL)" OFF) option(WITH_CURL "Enable Curl HTTP support (required for wms/wfs client, and remote SLD)" OFF) option(WITH_WFS "Enable WFS Server support (requires PROJ and OGR support)" ON) option(WITH_WCS "Enable WCS Server support (requires PROJ and GDAL support)" ON) +option(WITH_OGCAPI "Enable OGCAPI Server support (requires PROJ and OGR support)" ON) option(WITH_LIBXML2 "Choose if libxml2 support should be built in (used for sos, wcs 1.1,2.0 and wfs 1.1)" ON) option(WITH_THREAD_SAFETY "Choose if a thread-safe version of libmapserver should be built (only recommended for some mapscripts)" OFF) option(WITH_GIF "Enable GIF support (for PIXMAP loading)" ON) option(WITH_PYTHON "Enable Python mapscript support" OFF) -option(WITH_PHP "Enable PHP mapscript support" OFF) option(WITH_PHPNG "Enable PHPNG (SWIG) mapscript support" OFF) option(WITH_PERL "Enable Perl mapscript support" OFF) option(WITH_RUBY "Enable Ruby mapscript support" OFF) option(WITH_JAVA "Enable Java mapscript support" OFF) option(WITH_CSHARP "Enable C# mapscript support" OFF) -option(WITH_POINT_Z_M "include Z and M coordinates in point structure" ON) option(WITH_ORACLESPATIAL "include oracle spatial database input support" OFF) option(WITH_ORACLE_PLUGIN "include oracle spatial database input support as plugin" OFF) option(WITH_MSSQL2008 "include mssql 2008 database input support as plugin" OFF) option(WITH_EXEMPI "include xmp output metadata support" OFF) option(WITH_XMLMAPFILE "include native xml mapfile support (requires libxslt/libexslt)" OFF) -option(WITH_V8 "include javacript v8 scripting" OFF) +option(WITH_V8 "include javascript v8 scripting" OFF) option(WITH_PIXMAN "use (experimental) support for pixman for layer compositing operations" OFF) option(BUILD_STATIC "Also build a static version of mapserver" OFF) option(LINK_STATIC_LIBMAPSERVER "Link to static version of libmapserver (also for mapscripts)" OFF) option(WITH_APACHE_MODULE "include (experimental) support for apache module" OFF) option(WITH_GENERIC_NINT "generic rounding" OFF) +option(WITH_PYMAPSCRIPT_ANNOTATIONS "Add annotations to Python mapscript output" OFF) +option(INSTALL_HTML_BOOTSTRAP "Whether to install HTML Bootstrap resources for OGCAPIs" ON) + +option(FUZZER "Build fuzzers using libFuzzer (requires Clang, will disable executable - mapserv, etc. - generation)" OFF) +mark_as_advanced(FUZZER) +option(BUILD_FUZZER_REPRODUCER "Build fuzzer reproducer programs" ON) + +if(FUZZER AND BUILD_FUZZER_REPRODUCER) + message(FATAL_ERROR "FUZZER and BUILD_FUZZER_REPRODUCER options are mutually exclusive") +endif() #TODO: USE_OGL? , USE_SDE, USE_CLUSTER_EXTERNAL USE_CLUSTER_PLUGIN, USE_MSSQL2008, USE_MSSQL2008_PLUGIN # SIGNORE_MISSING_DATA, CGI_CL_DEBUG_ARGS, EXTRA DEBUG FLAGS?, @@ -190,6 +210,15 @@ if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_COMPILER_IS_GNUCC OR CMAKE_CXX_COMPILER_ID set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Werror=format-security") endif() +if(FUZZER) + if (NOT CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + message(FATAL_ERROR "Need clang for libFuzzer support") + endif() + + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=fuzzer,address -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=fuzzer,address -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION") +endif() + if(NOT DEFINED CMAKE_INSTALL_LIBDIR) set(_LIBDIR_DEFAULT "lib") # Override this default 'lib' with 'lib64' iff: @@ -215,8 +244,10 @@ if(NOT DEFINED CMAKE_INSTALL_LIBDIR) set(CMAKE_INSTALL_LIBDIR "${_LIBDIR_DEFAULT}" CACHE PATH "object code libraries (${_LIBDIR_DEFAULT})") endif() -SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}") -SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) +if(NOT DEFINED CMAKE_INSTALL_RPATH) + SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}") + SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) +endif() SET(CMAKE_MACOSX_RPATH ON) if(LINK_STATIC_LIBMAPSERVER) @@ -229,31 +260,54 @@ else(LINK_STATIC_LIBMAPSERVER) endif(LINK_STATIC_LIBMAPSERVER) set(agg_SOURCES -renderers/agg/src/agg_arc.cpp -renderers/agg/src/agg_vcgen_dash.cpp -renderers/agg/src/agg_vcgen_contour.cpp -renderers/agg/src/agg_curves.cpp -renderers/agg/src/agg_embedded_raster_fonts.cpp -renderers/agg/src/agg_trans_affine.cpp -renderers/agg/src/agg_vcgen_stroke.cpp -renderers/agg/src/agg_font_freetype.cpp -renderers/agg/src/agg_line_aa_basics.cpp -renderers/agg/src/clipper.cpp +src/renderers/agg/src/agg_arc.cpp +src/renderers/agg/src/agg_vcgen_dash.cpp +src/renderers/agg/src/agg_vcgen_contour.cpp +src/renderers/agg/src/agg_curves.cpp +src/renderers/agg/src/agg_embedded_raster_fonts.cpp +src/renderers/agg/src/agg_trans_affine.cpp +src/renderers/agg/src/agg_vcgen_stroke.cpp +src/renderers/agg/src/agg_font_freetype.cpp +src/renderers/agg/src/agg_line_aa_basics.cpp +src/renderers/agg/src/clipper.cpp ) -include_directories(renderers/agg/include) +include_directories(src/renderers/agg/include) set(v8_SOURCES - mapscript/v8/v8_object_wrap.hpp - mapscript/v8/point.cpp - mapscript/v8/line.cpp - mapscript/v8/shape.cpp - mapscript/v8/v8_mapscript.cpp - mapv8.cpp + src/mapscript/v8/v8_object_wrap.hpp + src/mapscript/v8/point.cpp + src/mapscript/v8/line.cpp + src/mapscript/v8/shape.cpp + src/mapscript/v8/v8_mapscript.cpp + src/mapv8.cpp +) +include_directories(src/mapscript/v8/) + +# point to FlatGeobuf files +set(flatgeobuf_SOURCES +src/flatgeobuf/flatgeobuf_c.cpp +src/flatgeobuf/geometryreader.cpp +src/flatgeobuf/packedrtree.cpp ) -include_directories(mapscript/v8/) +include_directories(src/flatgeobuf/include) + +find_package(PCRE2) +set(WITH_PCRE2_DEFAULT OFF) +if(WIN32 AND (NOT DEFINED REGEX_DIR) AND PCRE2_FOUND) + set(WITH_PCRE2_DEFAULT ON) +endif() +option(WITH_PCRE2 "Use PCRE2 instead of POSIX regex" ${PCRE2_FOUND}) +if(WITH_PCRE2 AND NOT PCRE2_FOUND) + message(FATAL_ERROR "WITH_PCRE2=ON set, but PCRE2 not found") +endif() #add_definitions(-DHASH_DEBUG=1) -if(WIN32) +set(REGEX_SOURCES "") + +if(WIN32 AND NOT WITH_PCRE2) + if(NOT DEFINED REGEX_DIR) + message(FATAL_ERROR "Variable REGEX_DIR should point to regex-0.12 source directory, or PCRE2 library should be available") + endif() set(REGEX_SOURCES ${REGEX_DIR}/regex.c) include_directories(${REGEX_DIR}) add_definitions(-DREGEX_MALLOC -DUSE_GENERIC_MS_NINT -DHAVE_STRING_H) @@ -261,47 +315,54 @@ if(WIN32) set(REGEX_MALLOC 1) set(USE_GENERIC_MS_NINT 1) set(HAVE_STRING_H 0) - # Suppress warnings for regex.c - set_source_files_properties(${REGEX_SOURCES} PROPERTIES COMPILE_FLAGS /w) -else(WIN32) - set(REGEX_SOURCES "") -endif(WIN32) + if(MSVC) + # Suppress warnings for regex.c + set_source_files_properties(${REGEX_SOURCES} PROPERTIES COMPILE_FLAGS /w) + endif(MSVC) + if(MINGW) + # mingw provides stdlib.h + add_definitions(-DSTDC_HEADERS=1) + endif(MINGW) +endif() -set(mapserver_SOURCES fontcache.c -cgiutil.c mapgeos.c maporaclespatial.c mapsearch.c mapwms.cpp classobject.c -mapgml.c mapoutput.c mapwmslayer.c layerobject.c mapgraticule.c mapows.c -mapservutil.c mapxbase.c maphash.c mapowscommon.c mapshape.c mapxml.c mapbits.c -maphttp.c mapparser.c mapstring.cpp mapxmp.c mapcairo.c mapimageio.c -mappluginlayer.c mapsymbol.c mapchart.c mapimagemap.c mappool.c maptclutf.c -mapcluster.c mapio.c mappostgis.cpp maptemplate.c mapcontext.c mapjoin.c -mappostgresql.c mapthread.c mapcopy.c maplabel.c mapprimitive.c maptile.c -mapcpl.c maplayer.c mapproject.c maptime.c mapcrypto.c maplegend.c hittest.c -maptree.c mapdebug.c maplexer.c mapquantization.c mapunion.c -mapdraw.c maplibxml2.c mapquery.c maputil.c strptime.c mapdrawgdal.c -mapraster.c mapuvraster.c mapdummyrenderer.c mapobject.c maprasterquery.c -mapwcs.cpp maperror.c mapogcfilter.cpp mapregex.c mapwcs11.cpp mapfile.c -mapogcfiltercommon.cpp maprendering.c mapwcs20.cpp mapogcsld.c mapmetadata.c -mapresample.c mapwfs.cpp mapgdal.c mapogcsos.c mapscale.c mapwfs11.cpp mapwfs20.c -mapgeomtransform.c mapogroutput.cpp mapwfslayer.c mapagg.cpp mapkml.cpp -mapgeomutil.cpp mapkmlrenderer.cpp fontcache.c textlayout.c maputfgrid.cpp -mapogr.cpp mapcontour.c mapsmoothing.c mapv8.cpp ${REGEX_SOURCES} kerneldensity.c -mapcompositingfilter.c mapmvt.c mapiconv.c) +set(mapserver_SOURCES src/fontcache.c +src/cgiutil.c src/mapgeos.c src/maporaclespatial.c src/mapsearch.c src/mapwms.cpp src/classobject.c +src/mapgml.c src/mapoutput.c src/mapwmslayer.c src/layerobject.c src/mapgraticule.c src/mapows.cpp src/mapogcapi.cpp +src/mapservutil.c src/mapxbase.c src/maphash.c src/mapowscommon.c src/mapshape.c src/mapxml.c src/mapbits.c +src/maphttp.c src/mapparser.c src/mapstring.cpp src/mapxmp.c src/mapcairo.c src/mapimageio.c +src/mappluginlayer.c src/mapsymbol.c src/mapchart.c src/mapimagemap.c src/mappool.c src/maptclutf.c +src/mapcluster.c src/mapio.c src/mappostgis.cpp src/maptemplate.c src/mapcontext.c src/mapjoin.c +src/mappostgresql.c src/mapthread.c src/mapcopy.c src/maplabel.c src/mapprimitive.cpp src/maptile.c +src/mapcpl.c src/maplayer.c src/mapproject.c src/maptime.c src/mapcrypto.c src/maplegend.c src/hittest.c +src/maptree.c src/mapdebug.c src/maplexer.c src/mapquantization.c src/mapunion.cpp +src/mapdraw.c src/maplibxml2.c src/mapquery.cpp src/maputil.c src/strptime.c src/mapdrawgdal.c +src/mapraster.c src/mapuvraster.cpp src/mapdummyrenderer.c src/mapobject.c src/maprasterquery.c +src/mapwcs.cpp src/maperror.c src/mapogcfilter.cpp src/mapregex.c src/mapwcs11.cpp src/mapfile.c +src/mapogcfiltercommon.cpp src/maprendering.c src/mapwcs20.cpp src/mapogcsld.cpp src/mapmetadata.c +src/mapresample.c src/mapwfs.cpp src/mapgdal.cpp src/mapogcsos.c src/mapscale.c src/mapwfs11.cpp src/mapwfs20.c +src/mapgeomtransform.c src/mapogroutput.cpp src/mapwfslayer.c src/mapagg.cpp src/mapkml.cpp +src/mapgeomutil.cpp src/mapkmlrenderer.cpp src/fontcache.c src/textlayout.c src/maputfgrid.cpp +src/mapogr.cpp src/mapcontour.c src/mapsmoothing.c src/mapv8.cpp ${REGEX_SOURCES} src/kerneldensity.c +src/idw.c src/interpolation.c src/mapflatgeobuf.c src/mapcompositingfilter.c src/mapmvt.c src/mapiconv.c +src/mapgraph.cpp src/mapserv-config.cpp src/maprasterlabel.cpp src/mapserv-index.cpp +src/cql2.cpp src/cql2json.cpp src/cql2text.cpp src/cql2textparser.cpp) set(mapserver_HEADERS -cgiutil.h dejavu-sans-condensed.h dxfcolor.h fontcache.h hittest.h mapagg.h -mapaxisorder.h mapcopy.h mapentities.h maperror.h mapfile.h mapgml.h maphash.h -maphttp.h mapio.h mapkmlrenderer.h maplibxml2.h mapogcfilter.h mapogcsld.h -mapoglcontext.h mapoglrenderer.h mapowscommon.h mapows.h mapparser.h -mappostgis.h mapprimitive.h mapproject.h mapraster.h mapregex.h mapresample.h -mapserver-api.h mapserver.h mapserv.h mapshape.h mapsymbol.h maptemplate.h -mapthread.h maptile.h maptime.h maptree.h maputfgrid.h mapwcs.h uthash.h mapiconv.h) +src/cgiutil.h src/dejavu-sans-condensed.h src/dxfcolor.h src/fontcache.h src/hittest.h src/mapagg.h +src/mapaxisorder.h src/mapcopy.h src/mapentities.h src/maperror.h src/mapfile.h src/mapgml.h src/maphash.h +src/maphttp.h src/mapio.h src/mapkmlrenderer.h src/maplibxml2.h src/mapogcfilter.h src/mapogcsld.h +src/mapoglcontext.h src/mapoglrenderer.h src/mapowscommon.h src/mapows.h src/mapparser.h src/mapogcapi.h +src/mappostgis.h src/mapprimitive.h src/mapproject.h src/mapraster.h src/mapregex.h src/mapresample.h +src/mapserver-api.h src/mapserver.h src/apps/mapserv.h src/mapshape.h src/mapsymbol.h src/maptemplate.h +src/mapthread.h src/maptile.h src/maptime.h src/maptree.h src/maputfgrid.h src/mapwcs.h src/uthash.h src/mapiconv.h +src/mapflatgeobuf.h src/mapgraph.h src/mapserv-config.h src/mapserv-index.h) if(WIN32) configure_file( - ${CMAKE_CURRENT_SOURCE_DIR}/version.rc.in - ${CMAKE_CURRENT_BINARY_DIR}/version.rc + ${CMAKE_CURRENT_SOURCE_DIR}/src/version.rc.in + ${CMAKE_CURRENT_BINARY_DIR}/src/version.rc @ONLY) - set(mapserver_SOURCES ${mapserver_SOURCES} ${CMAKE_CURRENT_BINARY_DIR}/version.rc) + set(mapserver_SOURCES ${mapserver_SOURCES} ${CMAKE_CURRENT_BINARY_DIR}/src/version.rc) endif(WIN32) if(WITH_PROTOBUFC) @@ -315,7 +376,7 @@ if(WITH_PROTOBUFC) # Create custom command for protoc-c ADD_CUSTOM_COMMAND( COMMAND ${PROTOBUFC_COMPILER} - ARGS --c_out=${PROJECT_BINARY_DIR}/renderers/mvt --proto_path=${PROJECT_SOURCE_DIR}/renderers/mvt ${PROJECT_SOURCE_DIR}/renderers/mvt/vector_tile.proto + ARGS --c_out=${PROJECT_BINARY_DIR}/renderers/mvt --proto_path=${PROJECT_SOURCE_DIR}/src/renderers/mvt ${PROJECT_SOURCE_DIR}/src/renderers/mvt/vector_tile.proto OUTPUT ${PROJECT_BINARY_DIR}/renderers/mvt/vector_tile.pb-c.c ${PROJECT_BINARY_DIR}/renderers/mvt/vector_tile.pb-c.h ) @@ -328,19 +389,19 @@ endif (WITH_PROTOBUFC) if(BUILD_DYNAMIC) - add_library(mapserver SHARED ${vectortile_SOURCES} ${mapserver_SOURCES} ${agg_SOURCES} ${v8_SOURCES}) + add_library(mapserver SHARED ${vectortile_SOURCES} ${mapserver_SOURCES} ${agg_SOURCES} ${v8_SOURCES} ${flatgeobuf_SOURCES}) set_target_properties( mapserver PROPERTIES VERSION ${MapServer_VERSION_STRING} SOVERSION 2 -) +) endif(BUILD_DYNAMIC) if(BUILD_STATIC) - add_library(mapserver_static STATIC ${vectortile_SOURCES} ${mapserver_SOURCES} ${agg_SOURCES} ${v8_SOURCES}) + add_library(mapserver_static STATIC ${vectortile_SOURCES} ${mapserver_SOURCES} ${agg_SOURCES} ${v8_SOURCES} ${flatgeobuf_SOURCES}) set_target_properties( mapserver_static PROPERTIES VERSION ${MapServer_VERSION_STRING} SOVERSION 2 - ) + ) endif(BUILD_STATIC) #SOVERSION is not necessarily the same as the @@ -350,31 +411,34 @@ endif(BUILD_STATIC) #the SOVERSION to be incremented. Similar rules hold of course for #non-opaque data-structures. -add_executable(mapserv mapserv.c) +if( NOT FUZZER ) +add_executable(mapserv src/apps/mapserv.c) target_link_libraries(mapserv ${MAPSERVER_LIBMAPSERVER}) -add_executable(shp2img shp2img.c) -target_link_libraries(shp2img ${MAPSERVER_LIBMAPSERVER}) -add_executable(shptree shptree.c) +add_executable(map2img src/apps/map2img.c) +target_link_libraries(map2img ${MAPSERVER_LIBMAPSERVER}) +add_executable(shptree src/apps/shptree.c) target_link_libraries(shptree ${MAPSERVER_LIBMAPSERVER}) -add_executable(shptreevis shptreevis.c) +add_executable(coshp src/apps/coshp.c) +target_link_libraries(coshp ${MAPSERVER_LIBMAPSERVER}) +add_executable(shptreevis src/apps/shptreevis.c) target_link_libraries(shptreevis ${MAPSERVER_LIBMAPSERVER}) -add_executable(sortshp sortshp.c) +add_executable(sortshp src/apps/sortshp.c) target_link_libraries(sortshp ${MAPSERVER_LIBMAPSERVER}) -add_executable(legend legend.c) +add_executable(legend src/apps/legend.c) target_link_libraries(legend ${MAPSERVER_LIBMAPSERVER}) -add_executable(scalebar scalebar.c) +add_executable(scalebar src/apps/scalebar.c) target_link_libraries(scalebar ${MAPSERVER_LIBMAPSERVER}) -add_executable(msencrypt msencrypt.c) +add_executable(msencrypt src/apps/msencrypt.c) target_link_libraries(msencrypt ${MAPSERVER_LIBMAPSERVER}) -add_executable(tile4ms tile4ms.c) +add_executable(tile4ms src/apps/tile4ms.c) target_link_libraries(tile4ms ${MAPSERVER_LIBMAPSERVER}) -add_executable(shptreetst shptreetst.c) +add_executable(shptreetst src/apps/shptreetst.c) target_link_libraries(shptreetst ${MAPSERVER_LIBMAPSERVER}) +endif() - -if (CMAKE_BUILD_TYPE STREQUAL "Debug") +if (CMAKE_BUILD_TYPE STREQUAL "Debug") set(USE_EXTENDED_DEBUG 1) -endif (CMAKE_BUILD_TYPE STREQUAL "Debug") +endif (CMAKE_BUILD_TYPE STREQUAL "Debug") find_package(PNG) if(PNG_FOUND) @@ -400,9 +464,9 @@ find_package(Freetype) if(NOT FREETYPE_FOUND) report_mandatory_not_found(FREETYPE) endif(NOT FREETYPE_FOUND) -include_directories(${FREETYPE_INCLUDE_DIR}) +include_directories(${FREETYPE_INCLUDE_DIRS}) ms_link_libraries( ${FREETYPE_LIBRARY}) -list(APPEND ALL_INCLUDE_DIRS ${FREETYPE_INCLUDE_DIR}) +list(APPEND ALL_INCLUDE_DIRS ${FREETYPE_INCLUDE_DIRS}) find_package(Proj) @@ -421,7 +485,7 @@ if(USE_PBF) endif() if(WITH_PIXMAN) - find_package(Pixman) + find_package(PIXMAN) if(PIXMAN_FOUND) include_directories(${PIXMAN_INCLUDE_DIR}) ms_link_libraries(${PIXMAN_LIBRARY}) @@ -472,11 +536,11 @@ endif( USE_FRIBIDI AND NOT(USE_HARFBUZZ) ) if(WITH_ICONV) - find_package(ICONV) + find_package(Iconv) if(ICONV_FOUND) - include_directories(${ICONV_INCLUDE_DIR}) - ms_link_libraries( ${ICONV_LIBRARY}) - list(APPEND ALL_INCLUDE_DIRS ${ICONV_INCLUDE_DIR}) + include_directories(${Iconv_INCLUDE_DIR}) + ms_link_libraries( ${Iconv_LIBRARY}) + list(APPEND ALL_INCLUDE_DIRS ${Iconv_INCLUDE_DIR}) set (USE_ICONV 1) else(ICONV_FOUND) report_optional_not_found(ICONV) @@ -507,6 +571,11 @@ if(WITH_MYSQL) ms_link_libraries( ${MYSQL_LIBRARY}) list(APPEND ALL_INCLUDE_DIRS ${MYSQL_INCLUDE_DIR}) set (USE_MYSQL 1) + if (WIN32) + find_package(Zstd REQUIRED CONFIG) + include_directories(${ZSTD_INCLUDE_DIRS}) + ms_link_libraries(zstd::libzstd_shared) + endif (WIN32) else(MYSQL_FOUND) report_optional_not_found(MYSQL) endif(MYSQL_FOUND) @@ -520,7 +589,7 @@ if(WITH_ORACLESPATIAL OR WITH_ORACLE_PLUGIN) if(NOT DEFINED ENV{ORACLE_HOME}) MESSAGE( SEND_ERROR "ORACLE_HOME environment variable not set, needed for detection") endif() - find_package(Oracle) + find_package(ORACLE) if(ORACLE_FOUND) include_directories(${ORACLE_INCLUDE_DIR}) list(APPEND ALL_INCLUDE_DIRS ${ORACLE_INCLUDE_DIR}) @@ -537,7 +606,7 @@ if(ORACLE_FOUND AND WITH_ORACLESPATIAL) endif(ORACLE_FOUND AND WITH_ORACLESPATIAL) if(ORACLE_FOUND AND WITH_ORACLE_PLUGIN) - add_library(msplugin_oracle MODULE maporaclespatial.c) + add_library(msplugin_oracle MODULE src/maporaclespatial.c) target_link_libraries(msplugin_oracle ${ORACLE_LIBRARY} ${MAPSERVER_LIBMAPSERVER}) set_target_properties(msplugin_oracle PROPERTIES COMPILE_FLAGS -DUSE_ORACLE_PLUGIN) set (USE_ORACLE_PLUGIN 1) @@ -546,11 +615,10 @@ endif(ORACLE_FOUND AND WITH_ORACLE_PLUGIN) if(WITH_MSSQL2008) find_package(ODBC) if(ODBC_FOUND) - add_library(msplugin_mssql2008 MODULE mapmssql2008.c) - target_link_libraries(msplugin_mssql2008 ${ODBC_LIBRARY} ${MAPSERVER_LIBMAPSERVER}) - set_target_properties(msplugin_mssql2008 PROPERTIES COMPILE_FLAGS "-DUSE_MSSQL2008_PLUGIN -DUSE_MSSQL2008") - list(APPEND ALL_INCLUDE_DIRS ${ODBC_INCLUDE_DIR}) - set (USE_MSSQL2008 1) + add_library(msplugin_mssql2008 MODULE src/mapmssql2008.c) + target_link_libraries(msplugin_mssql2008 PRIVATE ODBC::ODBC ${MAPSERVER_LIBMAPSERVER}) + target_compile_definitions(msplugin_mssql2008 PRIVATE USE_MSSQL2008_PLUGIN USE_MSSQL2008) + set (USE_MSSQL2008 1) else(ODBC_FOUND) report_optional_not_found(ODBC) endif(ODBC_FOUND) @@ -560,7 +628,9 @@ if(WITH_FCGI) find_package(FCGI) if(FCGI_FOUND) include_directories(${FCGI_INCLUDE_DIR}) - target_link_libraries(mapserv ${FCGI_LIBRARY}) + if( NOT FUZZER ) + target_link_libraries(mapserv ${FCGI_LIBRARY}) + endif() list(APPEND ALL_INCLUDE_DIRS ${FCGI_INCLUDE_DIR}) set (USE_FASTCGI 1) else(FCGI_FOUND) @@ -582,6 +652,12 @@ endif (WITH_GEOS) if(WITH_POSTGIS) find_package(PostgreSQL) + + # map new module variables to uppercase variables + set (POSTGRESQL_FOUND ${PostgreSQL_FOUND}) + set (POSTGRESQL_LIBRARY ${PostgreSQL_LIBRARIES}) + set (POSTGRESQL_INCLUDE_DIR ${PostgreSQL_INCLUDE_DIRS}) + if(POSTGRESQL_FOUND) #uppercase our variables if ( NOT DEFINED POSTGRESQL_LIBRARY ) @@ -685,6 +761,10 @@ if(WITH_WCS) set(USE_WCS_SVR 1) endif(WITH_WCS) +if(WITH_OGCAPI) + set(USE_OGCAPI_SVR 1) +endif(WITH_OGCAPI) + if(WITH_LIBXML2) find_package(LibXml2) if(LIBXML2_FOUND) @@ -715,10 +795,6 @@ if(WITH_SOS) endif(USE_LIBXML2) endif(WITH_SOS) -if(WITH_POINT_Z_M) - set(USE_POINT_Z_M 1) -endif(WITH_POINT_Z_M) - if(WITH_KML) if(USE_LIBXML2) set(USE_KML 1) @@ -740,7 +816,7 @@ if(WITH_XMLMAPFILE) if(NOT USE_LIBXML2) report_dependency_error(KML LIBXML2) endif(NOT USE_LIBXML2) - + #check for xslt and exslt find_package(LibXslt) if(LIBXSLT_FOUND) @@ -774,18 +850,18 @@ endif(WITH_GIF) if(WITH_EXEMPI) find_package(Exempi) - if(LIBEXEMPI_FOUND) + if(EXEMPI_FOUND) include_directories(${LIBEXEMPI_INCLUDE_DIR}) ms_link_libraries( ${LIBEXEMPI_LIBRARY}) list(APPEND ALL_INCLUDE_DIRS ${LIBEXEMPI_INCLUDE_DIR}) set(USE_EXEMPI 1) - else(LIBEXEMPI_FOUND) + else(EXEMPI_FOUND) report_optional_not_found(EXEMPI) - endif(LIBEXEMPI_FOUND) + endif(EXEMPI_FOUND) endif(WITH_EXEMPI) if(WITH_PYTHON) - add_subdirectory("mapscript/python") + add_subdirectory("src/mapscript/python") set(USE_PYTHON_MAPSCRIPT 1) endif(WITH_PYTHON) @@ -805,48 +881,51 @@ if(WITH_V8) ENDIF() ENDIF(WITH_V8) -if(WITH_PHP) - add_subdirectory("mapscript/php") - set(USE_PHP_MAPSCRIPT 1) -endif(WITH_PHP) +if(WITH_PCRE2) + SET(USE_PCRE2 1) + ms_link_libraries(PCRE2::PCRE2-POSIX) +endif() if(WITH_PHPNG) - add_subdirectory("mapscript/phpng") + add_subdirectory("src/mapscript/phpng") set(USE_PHPNG_MAPSCRIPT 1) endif(WITH_PHPNG) if(WITH_APACHE_MODULE) - add_subdirectory("apache") + add_subdirectory("src/apache") set(USE_APACHE_MODULE 1) endif(WITH_APACHE_MODULE) - if(WITH_PERL) - add_subdirectory("mapscript/perl") + add_subdirectory("src/mapscript/perl") set(USE_PERL_MAPSCRIPT 1) endif(WITH_PERL) if(WITH_RUBY) - add_subdirectory("mapscript/ruby") + add_subdirectory("src/mapscript/ruby") set(USE_RUBY_MAPSCRIPT 1) endif(WITH_RUBY) if(WITH_JAVA) - add_subdirectory("mapscript/java") + add_subdirectory("src/mapscript/java") set(USE_JAVA_MAPSCRIPT 1) endif(WITH_JAVA) if(WITH_CSHARP) - add_subdirectory("mapscript/csharp") + add_subdirectory("src/mapscript/csharp") set(USE_CSHARP_MAPSCRIPT 1) endif(WITH_CSHARP) +if(FUZZER OR BUILD_FUZZER_REPRODUCER) +add_subdirectory("fuzzers") +endif() + if(UNIX) ms_link_libraries( ${CMAKE_DL_LIBS} m ) endif(UNIX) if (WIN32) - ms_link_libraries( ${MS_EXTERNAL_LIBS} ws2_32.lib) + ms_link_libraries( ${MS_EXTERNAL_LIBS} ws2_32.lib ) if (MSVC) #4701 : Potentially uninitialized local variable 'name' used (https://docs.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-level-4-c4701) set_target_properties(mapserver PROPERTIES COMPILE_FLAGS "/EHsc /wd4267 /wd4244 /wd4018 /w14701") @@ -854,12 +933,12 @@ if (WIN32) endif (WIN32) configure_file ( - "${PROJECT_SOURCE_DIR}/mapserver-config.h.in" + "${PROJECT_SOURCE_DIR}/src/mapserver-config.h.in" "${PROJECT_BINARY_DIR}/mapserver-config.h" ) configure_file ( - "${PROJECT_SOURCE_DIR}/mapserver-version.h.in" + "${PROJECT_SOURCE_DIR}/src/mapserver-version.h.in" "${PROJECT_BINARY_DIR}/mapserver-version.h" ) @@ -867,6 +946,10 @@ if(BUILD_DYNAMIC) set_target_properties(mapserver PROPERTIES PUBLIC_HEADER "${mapserver_HEADERS};${PROJECT_BINARY_DIR}/mapserver-config.h;${PROJECT_BINARY_DIR}/mapserver-version.h" ) + + if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_COMPILER_IS_GNUCC OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + target_compile_options(mapserver PRIVATE -Wall -Wextra -Werror=format-security) + endif() endif(BUILD_DYNAMIC) if (NOT("${LIBMAPSERVER_EXTRA_FLAGS}" STREQUAL "")) @@ -896,11 +979,11 @@ message(STATUS " * png: ${PNG_LIBRARY}") message(STATUS " * jpeg: ${JPEG_LIBRARY}") message(STATUS " * freetype: ${FREETYPE_LIBRARY}") message(STATUS " * Optional components") +status_optional_component("PCRE2" "${USE_PCRE2}" "${PCRE2-POSIX_LIBRARY}") status_optional_component("GIF" "${USE_GIF}" "${GIF_LIBRARY}") status_optional_component("MYSQL" "${USE_MYSQL}" "${MYSQL_LIBRARY}") status_optional_component("FRIBIDI" "${USE_FRIBIDI}" "${FRIBIDI_LIBRARY}") status_optional_component("HARFBUZZ" "${USE_HARFBUZZ}" "${HARFBUZZ_LIBRARY}") -status_optional_component("GIF" "${USE_GIF}" "${GIF_LIBRARY}") status_optional_component("CAIRO" "${USE_CAIRO}" "${CAIRO_LIBRARY}") status_optional_component("SVGCAIRO" "${USE_SVG_CAIRO}" "${SVGCAIRO_LIBRARY}") status_optional_component("RSVG" "${USE_RSVG}" "${RSVG_LIBRARY}") @@ -929,17 +1012,17 @@ status_optional_feature("WMS SERVER" "${USE_WMS_SVR}") status_optional_feature("WFS SERVER" "${USE_WFS_SVR}") status_optional_feature("WCS SERVER" "${USE_WCS_SVR}") status_optional_feature("SOS SERVER" "${USE_SOS_SVR}") +status_optional_feature("OGCAPI SERVER" "${USE_OGCAPI_SVR}") +status_optional_feature("Install HTML Bootstrap resources for OGCAPI" "${INSTALL_HTML_BOOTSTRAP}") status_optional_feature("WMS CLIENT" "${USE_WMS_LYR}") status_optional_feature("WFS CLIENT" "${USE_WFS_LYR}") status_optional_feature("ICONV" "${USE_ICONV}") status_optional_feature("Thread-safety support" "${USE_THREAD}") status_optional_feature("KML output" "${USE_KML}") -status_optional_feature("Z+M point coordinate support" "${USE_POINT_Z_M}") status_optional_feature("XML Mapfile support" "${USE_XMLMAPFILE}") message(STATUS " * Mapscripts") status_optional_feature("Python" "${USE_PYTHON_MAPSCRIPT}") -status_optional_feature("PHP" "${USE_PHP_MAPSCRIPT}") status_optional_feature("PHPNG" "${USE_PHPNG_MAPSCRIPT}") status_optional_feature("PERL" "${USE_PERL_MAPSCRIPT}") status_optional_feature("RUBY" "${USE_RUBY_MAPSCRIPT}") @@ -947,20 +1030,60 @@ status_optional_feature("JAVA" "${USE_JAVA_MAPSCRIPT}") status_optional_feature("C#" "${USE_CSHARP_MAPSCRIPT}") status_optional_feature("V8 Javascript" "${USE_V8_MAPSCRIPT}") status_optional_feature("Apache Module (Experimental)" "${USE_APACHE_MODULE}") +status_optional_feature("Python MapScript Annotations" "${WITH_PYMAPSCRIPT_ANNOTATIONS}") message(STATUS "") message(STATUS "PROJECT_BINARY_DIR is set to ${PROJECT_BINARY_DIR}") message(STATUS "Will install files to ${CMAKE_INSTALL_PREFIX}") message(STATUS "Will install libraries to ${INSTALL_LIB_DIR}") +########################################################### +# Targets to refresh cql2textparser.cpp +########################################################### + +# Those targets need to be run manually each time cql2textparser.y +# is modified. +# We could of course run them automatically, but that would make building +# harder. + +# This target checks that cql2textparser.y md5sum has not changed +# If it has, then it should be updated and the generate_cql2text_parser target +# should be manually run +add_custom_target(check_cql2text_parser_md5 ALL + COMMAND ${CMAKE_COMMAND} + "-DIN_FILE=cql2textparser.y" + "-DTARGET=generate_cql2text_parser" + "-DEXPECTED_MD5SUM=dadf2802080f36becdca009199acfa36" + "-DFILENAME_CMAKE=${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt" + -P "${PROJECT_SOURCE_DIR}/src/check_md5sum.cmake" + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/src" + DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/cql2textparser.y" + VERBATIM) + +find_package(BISON) +add_custom_target(generate_cql2text_parser + COMMAND ${CMAKE_COMMAND} + "-DBISON_FOUND=${BISON_FOUND}" + "-DBISON_EXECUTABLE=${BISON_EXECUTABLE}" + -P "${CMAKE_CURRENT_SOURCE_DIR}/src/generate_cql2text_parser.cmake" + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/src" + VERBATIM) + include_directories("${PROJECT_BINARY_DIR}") if(WIN32) set(REGEX_MALLOC 1) set(USE_GENERIC_MS_NINT 1) + +# FIXME: https://stackoverflow.com/a/65321305 this handles older MSVC +# SDKs that are used by Conda Forge windows builds +add_definitions(-D_XKEYCHECK_H=1) endif(WIN32) +# Defines M_PI in particular +add_definitions(-D_USE_MATH_DEFINES) + #INSTALL(FILES mapserver-api.h ${PROJECT_BINARY_DIR}/mapserver-version.h DESTINATION include) if(USE_ORACLE_PLUGIN) @@ -971,10 +1094,11 @@ if(USE_MSSQL2008) INSTALL(TARGETS msplugin_mssql2008 DESTINATION ${INSTALL_LIB_DIR}) endif(USE_MSSQL2008) - -INSTALL(TARGETS sortshp shptree shptreevis msencrypt legend scalebar tile4ms shptreetst shp2img mapserv - RUNTIME DESTINATION ${INSTALL_BIN_DIR} COMPONENT bin -) +if(NOT FUZZER) + INSTALL(TARGETS coshp sortshp shptree shptreevis msencrypt legend scalebar tile4ms shptreetst map2img mapserv + RUNTIME DESTINATION ${INSTALL_BIN_DIR} COMPONENT bin + ) +endif() if(BUILD_STATIC) INSTALL(TARGETS mapserver_static @@ -1008,14 +1132,14 @@ if(BUILD_DYNAMIC) # ... for the build tree set(CONF_INCLUDE_DIRS "${PROJECT_SOURCE_DIR}" "${PROJECT_BINARY_DIR}") - configure_file(mapserver-config.cmake.in "${PROJECT_BINARY_DIR}/mapserver-config.cmake" @ONLY) + configure_file(src/mapserver-config.cmake.in "${PROJECT_BINARY_DIR}/mapserver-config.cmake" @ONLY) # ... for the install tree set(CONF_INCLUDE_DIRS "\${MAPSERVER_CMAKE_DIR}/${REL_INCLUDE_DIR}") - configure_file(mapserver-config.cmake.in "${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/mapserver-config.cmake" @ONLY) + configure_file(src/mapserver-config.cmake.in "${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/mapserver-config.cmake" @ONLY) # ... for both - configure_file(mapserver-config-version.cmake.in "${PROJECT_BINARY_DIR}/mapserver-config-version.cmake" @ONLY) + configure_file(src/mapserver-config-version.cmake.in "${PROJECT_BINARY_DIR}/mapserver-config-version.cmake" @ONLY) # Install the mapserver-config.cmake and mapserver-config-version.cmake install(FILES "${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/mapserver-config.cmake" @@ -1028,3 +1152,86 @@ if(BUILD_DYNAMIC) DESTINATION "${INSTALL_CMAKE_DIR}" COMPONENT dev ) endif(BUILD_DYNAMIC) + +if(UNIX) + include(GNUInstallDirs) + set(DEFAULT_DATA_SUBDIR ${CMAKE_INSTALL_DATAROOTDIR}/mapserver) +else() + set(DEFAULT_DATA_SUBDIR share/mapserver) +endif() +set(DEFAULT_CONFIG_FILE ${CMAKE_INSTALL_FULL_SYSCONFDIR}/mapserver.conf) + +# Locations are changeable by user to customize layout of MapServer installation +# (default values are platform-specific) +set(MAPSERVER_DATA_SUBDIR ${DEFAULT_DATA_SUBDIR} CACHE STRING + "Subdirectory where data will be installed") + +set(MAPSERVER_CONFIG_FILE "${DEFAULT_CONFIG_FILE}" CACHE STRING + "Full file name for default configuration file (mapserver.conf)") + +# Mark *DIR variables as advanced and dedicated to use by power-users only. +mark_as_advanced( + MAPSERVER_DATA_SUBDIR + MAPSERVER_CONFIG_FILE +) +add_definitions(-DMAPSERVER_BUILD) +add_definitions(-DMAPSERVER_CONFIG_FILE="${MAPSERVER_CONFIG_FILE}") + +install( + FILES ${PROJECT_SOURCE_DIR}/share/ogcapi/templates/html-plain/collection.html + ${PROJECT_SOURCE_DIR}/share/ogcapi/templates/html-plain/collection-item.html + ${PROJECT_SOURCE_DIR}/share/ogcapi/templates/html-plain/collection-items.html + ${PROJECT_SOURCE_DIR}/share/ogcapi/templates/html-plain/collections.html + ${PROJECT_SOURCE_DIR}/share/ogcapi/templates/html-plain/conformance.html + ${PROJECT_SOURCE_DIR}/share/ogcapi/templates/html-plain/debug.html + ${PROJECT_SOURCE_DIR}/share/ogcapi/templates/html-plain/footer.html + ${PROJECT_SOURCE_DIR}/share/ogcapi/templates/html-plain/header.html + ${PROJECT_SOURCE_DIR}/share/ogcapi/templates/html-plain/landing.html + ${PROJECT_SOURCE_DIR}/share/ogcapi/templates/html-plain/openapi.html + DESTINATION ${MAPSERVER_DATA_SUBDIR}/ogcapi/templates/html-plain/ +) + +install( + FILES ${PROJECT_SOURCE_DIR}/share/ogcapi/templates/html-index-plain/footer.html + ${PROJECT_SOURCE_DIR}/share/ogcapi/templates/html-index-plain/header.html + ${PROJECT_SOURCE_DIR}/share/ogcapi/templates/html-index-plain/landing.html + ${PROJECT_SOURCE_DIR}/share/ogcapi/templates/html-index-plain/map.html + DESTINATION ${MAPSERVER_DATA_SUBDIR}/ogcapi/templates/html-index-plain/ +) + +if(INSTALL_HTML_BOOTSTRAP) + install( + FILES ${PROJECT_SOURCE_DIR}/share/ogcapi/templates/html-bootstrap/collection.html + ${PROJECT_SOURCE_DIR}/share/ogcapi/templates/html-bootstrap/collection-item.html + ${PROJECT_SOURCE_DIR}/share/ogcapi/templates/html-bootstrap/collection-items.html + ${PROJECT_SOURCE_DIR}/share/ogcapi/templates/html-bootstrap/collections.html + ${PROJECT_SOURCE_DIR}/share/ogcapi/templates/html-bootstrap/conformance.html + ${PROJECT_SOURCE_DIR}/share/ogcapi/templates/html-bootstrap/debug.html + ${PROJECT_SOURCE_DIR}/share/ogcapi/templates/html-bootstrap/footer.html + ${PROJECT_SOURCE_DIR}/share/ogcapi/templates/html-bootstrap/header.html + ${PROJECT_SOURCE_DIR}/share/ogcapi/templates/html-bootstrap/landing.html + ${PROJECT_SOURCE_DIR}/share/ogcapi/templates/html-bootstrap/openapi.html + DESTINATION ${MAPSERVER_DATA_SUBDIR}/ogcapi/templates/html-bootstrap/ + ) + + install( + FILES ${PROJECT_SOURCE_DIR}/share/ogcapi/templates/html-index-bootstrap/footer.html + ${PROJECT_SOURCE_DIR}/share/ogcapi/templates/html-index-bootstrap/header.html + ${PROJECT_SOURCE_DIR}/share/ogcapi/templates/html-index-bootstrap/landing.html + ${PROJECT_SOURCE_DIR}/share/ogcapi/templates/html-index-bootstrap/map.html + DESTINATION ${MAPSERVER_DATA_SUBDIR}/ogcapi/templates/html-index-bootstrap/ + ) +endif() + +install( + FILES ${PROJECT_SOURCE_DIR}/etc/mapserver-sample.conf + DESTINATION ${CMAKE_INSTALL_SYSCONFDIR}/ +) + +option(BUILD_TESTING "Build unit test" ON) +if(BUILD_DYNAMIC AND BUILD_TESTING) + enable_testing() + add_executable(unit_test tests/unit/test.cpp) + target_link_libraries(unit_test PRIVATE mapserver) + add_test(NAME unit_test COMMAND unit_test) +endif() diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c403a9f718..9704b24ac5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -5,28 +5,33 @@ tests, features, and patches. Note that all contributions are managed by the Ma ## Bugs and Help -GitHub issues should only be created to log bugs. For general help and support the MapServer [mailing lists](http://mapserver.org/community/lists.html) +GitHub issues should only be created to log bugs. For general help and support the MapServer [mailing lists](https://mapserver.org/community/lists.html) should be used. If you are unsure if you have discovered a bug, or may need help with configuring MapServer please -post to the [mapserver-users list](http://lists.osgeo.org/mailman/listinfo/mapserver-users). There is also -a [MapServer FAQ](http://www.mapserver.org/faq.html) which may have a solution to your problem. +post to the [mapserver-users list](https://lists.osgeo.org/mailman/listinfo/mapserver-users). There is also +a [MapServer FAQ](https://mapserver.org/faq.html) which may have a solution to your problem. -If you have discovered a bug, please refer to the [Bug Submission page](http://mapserver.org/development/bugs.html) for +If you have discovered a bug, please refer to the [Bug Submission page](https://mapserver.org/development/bugs.html) for guidelines on creating an issue on GitHub. Please also search the existing issues to see if the bug has already been reported, and add any further details to the existing issue. -For professional support please see the [MapServer Service Providers page](http://mapserver.org/community/service_providers.html). +For professional support please see the [MapServer Service Providers page](https://mapserver.org/community/service_providers.html). ## Development -A separate [mapserver-dev mailing list](http://lists.osgeo.org/mailman/listinfo/mapserver-dev) is available for developers -working on the MapServer code. +A separate [mapserver-dev mailing list](https://lists.osgeo.org/mailman/listinfo/mapserver-dev) is available for developers +working on the MapServer code. Send a short message there to introduce yourself +to the community, and mention what you are interested in working on. -Details on using GitHub can be found on the [MapServer GitHub page](http://mapserver.org/development/git.html) +Details on using GitHub can be found on the [MapServer GitHub page](https://mapserver.org/development/git.html). + +Request for Comments (RFCs), where upcoming major changes to the source +code are proposed, and a description of the various software tests & release +plans, can be found on the [MapServer Development page](https://mapserver.org/development/). Additional developer notes can be found in the [MapServer wiki](https://github.com/mapserver/mapserver/wiki#developer-notes), including coding style and guidelines, memory management, and working with Git. ## Documentation -The MapServer documentation is stored in a [separate repository](https://github.com/mapserver/docs). Please submit any documentation -issues or changes there. See the [Documentation Development Guide](http://mapserver.org/development/documentation.html) for further details. +The MapServer documentation is stored in a [separate repository](https://github.com/MapServer/MapServer-documentation). Please submit any documentation +issues or changes there. See the [Documentation Development Guide](https://mapserver.org/development/documentation.html) for further details. diff --git a/HISTORY.TXT b/HISTORY.TXT deleted file mode 100644 index e3067cf725..0000000000 --- a/HISTORY.TXT +++ /dev/null @@ -1,4492 +0,0 @@ - -MapServer Revision History -========================== - -This is a human-readable revision history which will attempt to document -required changes for users to migrate from one version of MapServer to the -next. Developers are strongly encouraged to document their changes and -their impacts on the users here. (Please add the most recent changes to -the top of the list.) - -For a complete change history, please see the Git log comments. For more -details about recent point releases, please see the online changelog at: -http://mapserver.org/development/changelog/ - -7.6.0 release (2020-05-08) --------------------------- - -- for essential WMS client layers set EXCEPTIONS to XML by default (#6066) - -7.6.0-rc4 release (2020-05-04) ------------------------------- - -- Fix case insensitive 'using unique' for PostGIS connections (#6062) - -- Add handling essential WMS layers (#6061) - -7.6.0-rc3 release (2020-04-24) ------------------------------- - -- Handle special characters in paths on Windows (#5995) - -- Add attribute binding for label ALIGN, OFFSET, POSITION (#6052) - -7.6.0-rc2 release (2020-04-10) ------------------------------- - -- Fix memory corruption in msGEOSGetCentroid (#6041) - -7.6.0-rc1 release (2020-04-05) ------------------------------- - -- Fix alpha value for hex colors (#6023) - -7.6.0-beta2 release (2020-03-28) --------------------------------- - -- fixed build with PHPNG + gnu_source (#6015) - -- fixed rendermode with geomtransform (#6021) - -7.6.0-beta1 release (2020-03-22) --------------------------------- - -- Full support for PROJ6 API (#5888) - -- Enable PointZM data support (X,Y,Z,M coordinates) by default - -- SLD support enhancements (RFC 124) except PR#5832 - -- CONNECTIONOPTIONS support in mapfile LAYER (RFC 125) - -- Enforce C99 and C++11 build requirements (RFC 128) - -7.4.4 release (2020-3-20) -------------------------- - -- Security release, see ticket #6014 for more information. - -7.4.3 release (2019-12-16) --------------------------- - -- No major changes, see detailed changelog for bug fixes - -7.4.2 release (2019-9-13) -------------------------- - -- No major changes, see detailed changelog for bug fixes - -7.4.1 release (2019-7-12) -------------------------- - -- No major changes, see detailed changelog for bug fixes - -7.4.0 release (2019-5-14) -------------------------- - -- No major changes, see detailed changelog for bug fixes - -7.4.0-rc2 release (2019-5-10) ----------------------------- - -- No major changes, see detailed changelog for bug fixes - -7.4.0-rc1 release (2019-5-1) ----------------------------- - -- No major changes, see detailed changelog for bug fixes - -7.4.0-beta2 release (2019-4-17) -------------------------------- - -- Addresses XSS issue with [layers] template tag (fix available in 6.4, 7.0 and 7.2 branches as well) - -- Added Perl/Mapscript to Travis CI - -- No other major changes, see detailed changelog for bug fixes - -7.4.0-beta1 release (2019-3-29) -------------------------------- - -- Python MapScript binding is available as installable Wheels with a full test suite and examples - -- C# MapScript binding is now compatible with .NET Core - -- PHP 7 MapScript binding support - both PHP/MapScript and Swig/MapScript - -- Added workaround to allow compiling against Proj 6 (#5766) - -7.2.2 release (2019-2-19) --------------------------- - -- No major changes, see detailed changelog for bug fixes - -7.2.1 release (2018-10-1) --------------------------- - -- No major changes, see detailed changelog for bug fixes - -7.2.0 release (2018-07-23) --------------------------- - -- Fixed issue with ring handling with polygons in MVT support (#5626) - -- No other major changes, see detailed changelog for bug fixes - -7.2.0-beta2 release (2018-6-13) - -- Update beta1 release notes to remove reference to PHP7 support - -- No other major changes, see detailed changelog for bug fixes - -7.2.0-beta1 release (2018-5-9) --------------------- - -- Support for Enhanced Layer Metadata Management (RFC82) - -- Calculate MINDISTANCE from label bounds instead of label center (#5369) - -- Reposition follow labels on maxoverlapangle colisions (RFC112) - -- Implement chainable compositing filters (RFC113) - -- Faster retrieval of shape count (RFC114) - -- WMS layer groups are now requestable - -- Support C-style multi-line content types (#5362) - -- Python 3.x support (#5561) - -- Support Vendor-Specific OGC FILTER parameter in WMS requests (RFC118) - -- Mapbox Vector Tile (MVT) Support (RFC119) - -- INSPIRE download service support for WCS 2.0 (RFC120) - -7.0.0 release (2015/07/24) --------------------------- - -- No major changes, see detailed changelog for bug fixes - -7.0.0-beta2 release (2015/06/29) --------------------------------- - -- No major changes, see detailed changelog for bug fixes - -7.0.0-beta1 release (2015/02/12) --------------------------------- - -- RFC91 Layer Filter Normalization - -- Implement WCS20 Extensions (#4898) - -- Require validation of ExternalGraphic OnlineResource (#4883) - -- Require validation on the CGI queryfile parameter. (#4874) - -- Apply RFC86 scaletoken substitutions to layer->PROCESSING entries - -- RFC113 Layer Compositing Pipeline - -- RFC109 Optimizing Runtime Substitutions - -- RFC108 Heatmap / Kernel-Density Layers - -- RFC106 Support of Geomtransform JavaScript Plugin - -- RFC105 Support for WFS 2.0 (server side) - -- RFC104 Bitmap Label removal, replaced with inlined truetype font - -- RFC103 Layer Level Character Encoding - -- RFC102 Support of Styleitem JavaScript Plugin - -- RFC99 GD removal - -- RFC98 Complex Text Rendering / Text Rendering Overhaul - -- RFC93 UTF Grid Support - -6.4 release (2013/09/17) ---------------------------- - -- RFC 101: Support for Content Dependant Legend Rendering - -- Add Support for librsvg as an alternative to libsvg-cairo - -- RFC100: Add support for raster tile index with tiles of mixed SRS (TILESRS keyword) - -- RFC94: Shape Smoothing - -- RFC95 : add EXPRESSION {value1,value2,...} support to parser (#4648) - -- RFC92: Migration from autotools to cmake (#4617) - -- RFC88: Saving MapServer Objects to Strings (#4563) - -- RFC90: Enable/Disable Layers in OGC Web Services by IP Lists - -- RFC85,89 Added Simplify,SimplityPT and Generalize geomtransform, implementation of - geomtransform at the layer level - -- RFC86: Scale-dependant token replacements (#4538) - -- Fix symbol scaling for vector symbols with no height (#4497,#3511) - -- Implementation of layer masking for WCS coverages (#4469) - -- Implementation of offsets on follow labels (#4399) - -6.2.0 release (git branch-6-2) 2012/11/14: --------------------------------------------------- - -- Fix WFS GetFeature result bounds are not written in requested projection (#4494) - -- Fixed wrong size in LegendURL of root layer (#4441) - -- Fixed wms_style_name in GetMap requests (#4439) - -- Fix segfault in queryByFilter function in MapScript - -- Adjusted WCS 2.0 to WCS Core 2.0.1 and GMLCOV 1.0.1 corrigenda (#4003) - -- Adjusted mediatype to multipart/related in WCS 2.0 (#4003) - -- Fix symbolObj.getImage seg fault in PHP/MapScript - -- Fix bad handling of startindex in some drivers (#4011) - WFSGetFeature also now uses a global maxfeatures and startindex to support - maxfeatures across layers rather than within layers - -- Fixed bugs with WCS 1.1/2.0 with VSIMEM (#4369) - -- Add notable changes here. Less important changes should go only in the - commit message and not appear here. - -- Fixed the OGR driver to use point or line spatial filter geometries in degenerated cases (#4420) - -- implement OFFSET x -99 on ANGLE FOLLOW labels (#4399) - -Version 6.2 (beta1: 20120629): -------------------------------------------------- - -- Fix WFS filter is produced as non-standard XML (#4171) - -- Fix pixmap symbol loading issue (#4329) - -- Added INSPIRE ExtendedCapabilities and DOCTYPE definition to WMS 1.1.1 (#3608) - -- Fix wms_enable_request-related errors are not properly tagged (#4187) - -- Fixed "msGetMarkerSize() called on unloaded pixmap symbol" in mapsymbol.c (#4225) - -- Fixed PHP MapScript support for PHP 5.4 (#4309) - -- Fix msOGREscapeSQLParam could return random data (#4335) - -- Fixed locations of supported and native formats in Capabilities and CoverageDescriptions for WCS 2.0 (#4003) - -- Made format parameter for WCS 2.0 GetCoverage requests optional (#4003) - -- Swig mapscript for multi-label support (#4310) - -- Fix creation of a vector symbolObj in mapscript (#4318) - -- Added coverage metadata in WCS (#4306) - -- Ignore unknown requets parameteres in WCS 2.0 (#4307). - -- Fixed getFeature request with custom output format fails on filter encoding (#4190) - -- Fixed resolution when UoM changes in WCS 2.0 (#4283) - -- Added missing DEFRESOLUTION parameter to msCopyMap() function (#4272) - -- Migrated svn to git, and issue tracking from trac to github - -- Fixed mapscript is unusable in a web application due to memory leaks (#4262) - -- Fixed legend image problem with annotation layers with label offsets (#4147) - -- Add support for mutiple labels per feature (RFC81) - -- Add support for INSPIRE view service (RFC 75) - -- Drop support for GDAL/OGR older than 1.5.0 (#4224) - -- PDF backend: add support for generating geospatial PDF, when - GDAL 2.0 with PDF driver is used, and the GEO_ENCODING FORMATOPTION - (set to ISO32000 or OGC_BP) is added to the OUTPUTFORMAT definition. (#4216) - -- Python mapscript: fix swig mappings to work with both python 2.5.and 2.6 (#3940) - -- Added classgroup CGI parameter support (#4207) - -- Java mapscript: renamed shared library and completed libtool support (#2595) - -- Fixed WCS 2.0 axis order (#4191) - -- Added MS_CJC_* constants in PHP/MapScript (#4183) - -- Fixed Memory Leak with Fribidi Strings (#4188) - -- Allow multiple label definitions within a class (RFC 77/#4127) - -- shp2img: make it possible to specify layers (with -l option) that match GROUP names. - -- reuse a pre-parsed mapfile across fastcgi loops in case the mapfile is - specified with the MS_MAPFILE env variable. (#4018) - -- Ability to do use PropertyIsLike with a column of a different type than text (postgis) (#4176) - -- Fixed SLD with FILTER doesn't apply properly to database layers (#4112) - -- Fixed lexer buffer size issue with single quotes in a string (#4175) - -- WFS Quote Escape issue (#4087) - -- Raster layer fails to be drawn if the window is less than half a pixel (#4172) - -- shptree: Improvement to reduce size of .qix files (#4169) - -- avoid potential gd fontcache deadlock on fastcgi exit signals(#4093) - -- Adjusted WCS GetCapabilities for an empty list of layers (#4140) - -- Adjusted WMS GetCapabilities for an empty list of layers (#3755) - -- Refactor cgi masperv to not call exit on argument errors (#3099) - -- Add --with-apache-module configure option to build an apache dso module - (#2565) - -- Use libtool to build object files and libraries - -- Dynamically link libmapserver to the created binaries by default - (requires the make install step to be run) - -- Python mapscript builds with make instead of setuptools - -- Fix LABELPNT geomtransform position for non-cached labels (#4121) - -- Add RFC80 font fallback support (#4114) - -- Added POLAROFFSET style option for a different symbol transform (#4117) - -- automatically translate vector symbol points (#4116) - -- Add RFC79 Layer masking (#4111) - -- Fixed single pixel coverages in WCS 2.0 (#4110) - -- Add svg symbols support (#3671) - -- Fixed subsetting in WCS 2.0 (#4099) - -- Upgrade clipper library to 4.6.3 - -- Make openlayers wms template request images with mimetype of outputformat - defined in the mapfile's imagetype - -- Fix memory leak in msSLDParseRasterSymbolizer() - -- Fix compilation error with clang in renderers/agg/include/agg_renderer_outline_aa.h - -- Add stable hatch rendering (#3847) - -- Added vector field rendering (#4094) - -- Add wms dimensions support (#3466) - -- Fixed segfault when calling classObj::updateFromString() with SYMBOL (#4062) - -- Use a renderer native follow text implementation if available. - -- Fixed layer with inline feature to support multiple classes (#4070) - -- Add support for rfc45 anchorpoint on marker symbols (#4066) - -- Add initial gap support for line marker symbols (#3879) - -- Fix center to center computation of gaps for line marker symbols - and polygon tile patterns (#3867) - -- Add initial gap support for line patterns (#3879) - -- Fixed grid of thin lines in polygon symbol fills (#3868) - -- Fixed cannot add a style to a label in PHP/SWIG Mapscript (#4038) - -- Fixed schema validity issue for WCS 1.1 GetCoverage responses (#4047) - -- remove default compiler search paths from the GD CFLAGS/LDFLAGS (#4046) - -- Fixed Python Mapscript does not write COLOR to reference map (#4042) - -- Added XMP support for metadata embedding, RFC 76, (#3932) - -- Added GetLegendGraphic Cascading support (#3923) - -- Rewrite postgres TIME queries to take advantage of indexes (#3374) - -- Unified OWS requests and applied to WCS (defaults to version 2.0 now) (#3925) - -- WCS 1.0: Fix crash with some _rangeset_axes values (#4020) - -- WCS 2.0: Adjusted offset vector and origin (#4006) - -- Added addParameter() method to MapScript (#3973) - -- Changed msDrawVectorLayer() not to cache shapes if attribute binding is present after the first style (#3976) - -- Fix mapscript to build when TRUE macro is not defined (#3926) - -- Fix mapscript php build issues with MSVC (#4004) - -- PHP MapScript is missing many styleObj properties (#3901) - -- PHP/Mapscript: Segmentation fault when getting complex object using PHP 5.2 (#3930) - -- PHP/Mapscript: Fixed webObj->metadata returns a webObj (#3971) - -- WCS 1.1: Added check for imageCRS in msOWSCommonBoundingBox() (#3966) - -- Fixed contains operator in logical expresions (#3974) - -- WCS 1.0: WCS Exceptions raise mapscript exceptions (#3972) - -- WMS: LAYERS parameter is optional when sld is given (#1166) - -- Add runtime substitution for "filename" output format option (#3571) and - allow setting defaults in either metadata or validation (preferred) blocks - for both layer and output format. - -- Add non antialiased text rendering for GD (#3896) - -- Fixed OGC filter using expressions (#3481) - -- Fix incorrect rendering of GD lines between 1 and 2 pixels wide (#3962) - -- Add gamma correction to AGG polygon rendering (#3165) - -- Initialize the scalebar image color to transparent by default (#3957) - -- Do not divide by zero in io read/write funcs (#4135) - -IMPORTANT SECURITY FIX: - -- Fixes to prevent SQL injections through OGC filter encoding (in WMS, WFS - and SOS), as well as a potential SQL injection in WMS time support. - Your system may be vulnerable if it has MapServer with OGC protocols - enabled, with layers connecting to an SQL RDBMS backend, either - natively or via OGR (#3903) - -- Fix performance issue with Oracle and scrollable cursors (#3905) - -- Fix attribute binding for layer styles (#3941) - -- Added missing fclose() when writing query files (#3943) - -- Fix double-free in msAddImageSymbol() when filename is a http resource (#3939) - -- Fix rendering of lines with outlinewidth set if not on first style (#3935) - -- Correct SLD with spatial filters bbox and intersects (#3929) - -- Applied patch for ticket (symbol writing issues) (#3589) - -- Added WMS GetFeatureInfo Cascading (#3764) - -- Fixed png lib is not found on multiarch systems (#3921) - -- Fixed PHP MapScript opacity property of StyleObj no longer works (#3920) - -- Fixed Using STYLEITEM AUTO, loadExpression fails when the label text - contains a space or begins with a double quote (#3481) - -- Fix for the cluster processing if the shape bounds doesn't overlap - with the given extent (#3913) - -- Add support for dashes on polygon hatches (#3912) - -- Union layer 3 new processing options added (#3900) - -- Changed msRemoveStyle to allow removing all styles (#3895) - -- Fixed mssql2008 to return correct geometries with chart layer type (#3894) - -- Ensure msLayerSetProcessingKey() supports setting a NULL value to clear - a processing key. - -- Write SYMBOLSET/END tags when saving a symbol file (#3885) - -- Make java threadtests work again (#3887) - -- Fix segfault on malformed filters (#3888) - -- Fixed the query handling problem with the Oracle spatial driver (#3878) - -- Fixed potential crash with AVERAGE resampling and crazy reprojection (#3886) - -- Adjusted OperationsMetadata for POST in WCS 2.0 GetCapabilities response - -- Fix for the warnings in mapunion.c (#3880) - -- SLD: correct when same layer is used with multiple styles (#1602) - -- Fixed the build problem in mapunion.c (#3877) - -- Implement to get all shapes with the clustered layer (#3873) - -- Union layer: Fixed the crash when styling source layers using attributes (#3870) - -- Added GEOS difference operator to expression support (#3871) - -- Improve rangeset item checking so that Bands=1,2,3 is supported with WCS 1.0 - (#3919). - -- Fix GetMapserverUnitUsingProj() for proj=latlong (#3883) - -- Add support for OGR output of 2.5D geometries (#3906) - - -Version 6.0.0 (2011-05-11) --------------------------- - -- apply fix for #3834 on legend icon rendering (#3866) - -- Union layer: Fixed a potential seg fault in msUnionLayerNextShape (#3859) - -- Cluster layer: Fixed the problem when returning undefined attribute (#3700) - -- Union layer: Fix for the item initialization at the source layer (#3859) - -- Union layer: Fixed the potential seg fault when STYLEITEM AUTO is used (#3859) - -Version 6.0.0-rc2 (2011-05-05) ------------------------------- - -- Fixed seg fault with [shpxy] tag... (#3860) - -- Removed obsolete msQueryByOperator() function - -- Call msLayerClose() before msLayerOpen() in the various query - functions (#3692) - -- Fix WMS 1.3.0 to use full list of epsg codes with inverted axis (#3582) - -- PHP/Mapscript: Added getResultsBounds() method in layer object (#2967) - -- Fix SLD containing a PropertyIsLike filter (#3855) - -- Fixed msUnionLayerNextShape to return correct values (#3859) - -- Union layer: fix for the failure if one or more of the source layers - are not in the current extent (#3858) - -- Fix memory leak in msResampleGDALToMap() (#3857) - -- Fix missing initialization of default formats in WCS 1.x. - -- Fix maxoverlapangle when value is set to 0 (#3856) - -Version 6.0.0-rc1 (2011-04-27) ------------------------------- - -- Fix for the styleitem handling with union layer (#3674) - -- Fixed mindistance label test to check layer indexes. (#3851) - -- Fixed segmentation fault in PHP/MapScript and improved the php object - method calls (#3730) - -- Fix build issue related to unnecessary use of gdal-config --dep-libs (#3316) - -Version 6.0.0-beta7 (2011-04-20) --------------------------------- - -- Union Layer: fix for the STYLEITEM AUTO option (#3674) - -- Union Layer: Add support for the layer FILTER expressions, - add "Union:SourceLayerVisible" predefined attribute (#3674) - -- fix circle layer drawing for edge case when point1.x==point2.x (#1356) - -- fix incorrect quantization for images with very large number of - colors (#3848) - -- fix poor performance of polygon hatching (#3846) - -- upgrade clipper library to 4.2 (related to #3846) - -- Fix configure output for "WFS Client" (was reporting WMS info, #3842) - -- KML: latlon bbox for raster layers could end up being wrong for non-square - requests (#3840) - -Version 6.0.0-beta6 (2011-04-13) --------------------------------- - -- define EQUAL/EQUALN macros if cpl_port.h was not included (#3844) - -- add configurable PNG/ZLIB compression level (#3841) - -- SLD: use pixmap size when parameter size is not specified (#2305) - -- fix memory leaks in mapgraticule.c (#3831) - -- fix runtime sub validation against web metadata, was using wrong lookup key - -- clean up the symbolset if we've used an alternate renderer for a - layer (#3834,#3616) - -- fix crash on embeded legend with cairo raster renderer - -- fix crashes in SVG renderer on polygon symbol fills (#3837) - -- fix crash/corruptions with raster layers in pdf outputs (#3799) - -- fix memory leak in msFreeLabelCacheSlot (#3829) - -- use a circle brush for wide GD lines (#3835) - -- fix segmentation fault with transparent layers containing symbols (#3834) - -- fix memory leak on tiled vector polygons - -- fix segfault with marker symbols on short lines (#3823) - -- wms_getmap_formatlist causes first defined outputformat to be returned by - getmap (#3826) - -- fix building of mapcluster.c when OGR support is disabled - -- fix some valgrind found memory leaks (offset symbols, and gd io contexts) - -- skip marker symbol with no defined SYMBOL (caused some memory leaks with - uninitialized vector points) - -- fix crash in GD lines with floating point dash patterns (#3823) - -- Check renderer before using it when calculating label size (#3822) - -- allow palette file path to be relative to mapfile (#2115) - -- use supplied offset for brushed lines (#3825, #3792) - -- fix division by 0 error in bar charts for some ill-defined cases (#3218) - -- add GAP, POSITION and CAPS/JOINS to mapfile writer (#3797) - -- fix GEOMTRANSFORM rotation orientation for vector symbols (#3802) - -- GD Driver broken in FastCGI (#3813) - -- configure: look for libexslt.so under lib64 as well - -- Coding style and formatting fixes (#3819, #3820, #3821, and more) - -- More improvements to OpenGL error handling (#3791) - -- Added WMS GetFeatureInfo RADIUS=bbox vendor-specific option (#3561) - -Version 6.0.0-beta5 (2011-04-06) --------------------------------- - -- Fix setting of top-level mapObj member variables in PHP MapScript (#3815) - -- More robust OpenGL context creation on older video cards and drivers (#3791) - -- Allow users to set the maximum number of vector features to be drawn (#3739) - -- Fixed FCGI on Windows problem related to lexer (#3812) - -- KML: Add ows/kml_exclude_items (#3560) - -- Removed all refs left to MS_SYMBOL_CARTOLINE (#3798) - -- Removed GAP, PATTERN, LINECAP/JOIN and POSITION from symbolObj (#3797) - -- Fixed handling of STYLEITEM AUTO label position codes 10,11,12 (#3806) - -- Fixed msGEOSGeometry2Shape to handle 'GEOMETRYCOLLECTION EMPTY' - as null geometry instead of raising an error (#3811) - -- Re-added the MYSQL JOIN support. Had been removed with the MYGIS - deprecated driver. - -- Add opacity to legend (#3740) - -- Updated PHP/MapScript with the new objects properties (#3735) - -- KML: set layer's projection when it is not defined (#3809) - -- Updated xml mapfile schema and xsl with the new lexer properties (#3735) - -- Updated PHP/MapScript for MS RFC 69: clustering. (#3700) - -- Move allocation of cgiRequestObj paramNames/Values to msAllocCgiObj() (#1888) - -- Add support for simple aggregates for the cluster layer attributes (#3700) - -- Improved error reporting in msSaveImage() (#3733) - -- configure: look for libxslt.so under lib64 as well - -- added missing ';' before charset in WFS DescribeFeatureType header (#3793) - -- add brushed line support for agg renderer (#3792) - -- fix bug with marker symbols along offset line - -- fix for the cluster layer returning invalid feature count (#3794) - -- remove some compiler warnings - -- fix incorrect scaling of hatch symbol spacing (#3773) - -- fix incorrect background color for INIMAGE exceptions (#3790) - -Version 6.0.0-beta4 (2011-03-30) --------------------------------- - -- Fix shp2img's -i flag to honour map level transparent, image quality and - interlace settings. - -- Make sure command-line programs use an exit status other than 0 - when an error is encountered. (#3753) - -- Applied patch to filter unwanted fribidi characters (#3763) - -- Fixed lexer to set the proper state on URL variable substitutions - -- Fixed Memory leak in PostGIS driver (#3768) - -- Fixed PHP/MapScript symbol property setter method - -- fix memory leak in bar charts - -- fix some valgrind errors on agg rotated pixmap symbols - -- WCS 2.0: Adjusted definition of NilValues. - -- Fixed handling of PROJ_LIB value relative to mapfile path (#3094) - -- Fixed compilation error with opengl support (#3769) - -- add support for gml:Box for spatial filters (#3789) - -- fix query map generation error introduced in beta2 when output format - initialized was made as needed. - -- fix incorrect PATTERN behavior on agg lines (#3787) - -- report SOS DescribeObservationType in Capabilities (#3777) - -- Updated lexer to detect time attribute bindings (e.g. `[item]`) in logical - expressions - -- Fixed layer context expressions (REQUIRES/LABELREQUIRES) (#3737) - -- KML: Output ExtendedData (#3728) - -- Fixed OWS usage of multiple layers with same name (#3778) - -- WCS implementation should not lookup wms_* metadata (#3779) - -- WCS 2.0: Adjusted definition of rangeType. - -- Fixed OWS GetCapabilities to report only requests/operations that are - enabled. - -- WCS 2.0: Report only bands in the range subset. - -- OWS requests should be completely blocked by default (#3755) - -- SLD: check for limit on dash arrays (#3772) - -- WMS: Apply sld after bbox and srs have been parsed (#3765) - -Version 6.0.0-beta3 (2011-03-23) --------------------------------- - -- apply min/max size/width style values to polygon spacing (vaguely related - to #3132) - -- assure that a created tile has a non-zero width and height (#3370) - -- use png_sig_cmp instead of png_check_sig (#3762) - -- Rendering: scale style OFFSET and GAP the same way we scale other style - attributes. Beforehand, we scaled them proportionaly to the computed width. - -- KML: fix rounding problem for point feautres (#3767) - -- KML: update code to reflect output changes. Fix true type symbols. (#3766) - -- SLD: Text Symbolizer now uses the new expression syntax (#3757) - -- WFS: correct bbox values for GetFeature with featureid request (#3761) - -- Mapscript Seg Fault on mapObj->getMetaData (#3738) - -- Correct double free in msCleanup(). - -- Initialize default formats in WCS. - -- Fix csharp Makefile.in (#3758) - -- Allow run-time subs in class->text (makes sense if you allow it in - class->expression). - -- Fix build problem when --enable-cgi-cl-debug-args is enabled (#2853) - -Version 6.0.0-beta2 (2011-03-18) --------------------------------- - -- correct scaling of symbol GAP and PATTERN (#3752) - -- remove references to SWF/MING - -- CGI runtime substitution requires a validation pattern (was optional - before) (#3522) - -- add a default png8 outputformat that uses AGG/PNG with quantization - -- change MS_INIT_COLOR to take alpha as a parameter - -- stop using style->opacity in rendering code, use alpha from colorObjs. - -- Fixed big Oracle memory leak when rendering in KML (#3719) - -- avoid linking in postgres dependencies unnecessarily (#3708) - -- don't initialize outputformats until they are selected - -- use "seamless" creation of tiles for polygon fills with vector symbols - -- Ability to escape single/double quotes inside a string (#3706) - -- Globally replace msCaseFindSubstring with strcasestr (#3255) - -- support GROUP layers in shp2img (#3746) - -- Honour MAXSIZE for WCS 2.0 responses (#3204). - -- fallback to ows_title for WCS ows:Title of CoverageDescription (#3528) - -- Added msIO_stripStdoutBufferContentHeaders() to strip off all - Content-* headers from a buffer (#3673, #3665). - -- Added raster classification support for STYLE level OPACITY. - -- Allow attribute references, that is [itemname], within a TEXT string (#3736) - -- Fixed segmentation fault when parsing invalid extent arguments in - shp2img (#3734) - -- Make "openlayers mode" work even without OWS support (#3732) - -- Add a static table to define the axis order for soem epsg codes (#3582) - -- Add possibility to use KML_NAME_ITEM (#3728) - -- Fixed mapfile parsing error when a label angle referenced an attribute - (e.g. ANGLE [angle]) #3727 - -- Removed executable flag on some source files (#3726) - -- Fixed SQL Spatial to be able to use UniqueIdentifier field as unique - key (#3722) - -- Fix PHP Windows build (#3714) - -- Fixed --with-opengl build issue: Look for OpenGL libs under /usr/lib64 as - well (#3724) - - -Version 6.0.0-beta1 (2011-03-09) --------------------------------- - -- Fixed Core Dump from Format=KML/Z with Oracle Spatial layers (#3713) - -- Call msPluginFreeVirtualTableFactory from msCleanup (#2164) - -- Avoid the crash if anglemode 'FOLLOW' is specified with bitmap fonts. (#3379) - -- Add argument check for processTemplate, processLegendTemplate and - processQueryTemplate in the C# bindings (#3699) - -- Remove shapeObj.line, shapeObj.values, lineObj.point from the SWIG API - which are redundant and undocumented. (#3269) - -- Remove map-oriented query modes (e.g. QUERYMAP). Use qformat parameter instead. (#3712) - -- Implement single-pass query handling in mssql2008 driver as per RFC 65. - -- Fixed Sql Server 2008 key column name truncation (#3654) - -- Added label position binding (#3612) and label shadow size binding (#2924) - -- Implement MS RFC 69: Support for clustering of features in point layers (#3700) - -- Implement MS RFC 68: Support for combining features from multiple layers (#3674) - -- Add support for WCS 1.1 Post (#3710) - -- Fixed OGR query handling according to RFC 65 (#3647) - -- Implement CLOSE_CONNECTION=ALWAYS to suppress the connection pooling - for a particular layer. - -- Implemented RFC 67: Enable/Disable layers in ogc web services (#3703) - -- Class title can now be used in legends. It's value takes precedence over class name. Previously - title was not used any place in the code but it is supported for read/write. (#3702) - -- Allow definition of nodata attribute for layers without results (via resultset tag). (#3701) - -- mapprojhack.c: restructure to avoid needing projects, or any internal - knowledge of PROJ.4. - -- Fix newlines around part boundaries in WCS multipart results (#3672) - -- Added minfeaturesize support at layer or class level (#1340) - -- Implemented support in for classifying rasters using the new - expression parsing (msGetClass()...) (#3663) - -- Implemented RFC 65 which improves and simplifies one-pass query support. This causes - a few MapScript regressions with getShape/getFeature/getResultsShape. (#3647) - -- Support setting filenames for WCS GetCoverage results (#3665) - -- OGR auto-styling: use the color parameter and set the style's opacity when it is available. - Allow symbols that can be stored externally (#3660) - -- Add possiblity to use symbols stored externally, accessed through http (#3662) - -- Better handling of temporary files (#3354) - -- Support curved features in PostGIS (#3621) - -- NODATA values now excluded from autoscaling min/max for non-eight - scaling computations (#3650) - -- Fixed missing time in msDrawMap logging (#3651) - -- Fixed Auto Angle - incorrectly placed Labels (#3648) - -- Fixed Improper validation of symbol index values (#3641) - -- Removed BACKGROUNDCOLOR, BACKGROUNDSHADOWCOLOR and BACKGROUNDSHADOWOFFSET label parameters (#3609) - -- Fixed Transformation from XML to MapFile only handles one PROCESSING element (#3631) - -- Fixed 16bit classification support - problem introduced with new - renderer architecture (#3624) - -- Cleanup open gdal datasets in msGDALCleanup() (if we have a very new - GDAL). This makes it easier to identify memory leaks. - -- Add support for per layer tuning of the shape to pixel conversion (SIMPLIFY, ROUND, - SNAPTOGRID, FULLRESOLUTION) - -- Fixed: Memory allocation results should always be checked (#3559) - -- Fixed free(): invalid next size in mapfile.c (#3604) - -- Added a built-in OpenLayers map viewer (#3549) - -- Fixed issues with static buffers and sprintf (#3537) - -- Fix for the memory corruption when mapping the string data type in the Java bindings (3491) - -- Fixed double free in shp2img.c (#3497) - -- Fixed number of CGI params is limited to 100 (#3583) - -- Fixed duplicated XML and HTML errors from WFS GetFeature (#3571) - -- Support group names for GetLegendGraphic and GetStyles (#3411) - -- apply patch (thanks rouault) to advertise resultType=hits in WFS 1.1 Capabilities (#3575) - -- mapshape.c: Fix writing of geometries with z/m and fail gracefully attempting - to create such files if USE_POINT_Z_M is not enabled (#3564) - -- sortshp.c: improve error handling (#3564) - -- MSSQL2008: Add support for geography data type by extending the DATA syntax - to 'geometry_column(geometry_type) from table_name' - -- Fixed ability to get the error message and code of an OWS exception (#3554) - -- Fixed msOGRGetSymbolId according to the changes in gdal 1.8 (#3556) - -- Support holding WMS client requests in RAM instead of writing to disk (#3555) - -- RFC-61: Enhance MapServer Feature Style Support (#3544) - -- Restrict cascaded WMS requests based on EXTENT (#3543) - -- Avoid EPSG lookups for WMS client layers if possible (#3533) - -- RFC-60: Add ability to skip ANGLE FOLLOW labels with too much character overlap (#3523) - -- Fixed SWF: not a valid Bitmap FillStyle (#3548) - -- Set dependency on libxml2 when building --with-wfs (#3512) - -- Fixed TRUE is undefined in shptreevis (#3545) - -- shptreevis: bug truncates visualization shapefile if there are more - nodes in the tree than there are shapes being indexed! - -- Fixed multiple include tags not supported in xml mapfiles (#3530) - -- Support reading .dbf files between 2GB and 4GB (#3514) - -- Avoid warnings about ms_cvsid being unused with gcc. - -- Ensure the class is not marked BeforeFieldInit causing memory corruption with C#/CLR4 (#3438) - -- Fixed MSSQL2008 driver returning invalid extent (#3498) - -- Added coordinate scaling to shpxy tag via parameters scale, scale_x or scale_y. - -- Fix computation of shape bounds when the first line contains no points - (#3119)(fixes #3383) - -- Allow map relative specification in the PROJ_LIB config item (#3094) - -- Try to report reprojection errors in SLD Filter evaluation (#3495) - -- Disabled some insecure (and potentially exploitable) mapserv command-line - debug arguments (#3485). The --enable-cgi-cl-debug-args configure switch - can be used to re-enable them for devs who really cannot get away without - them and who understand the potential security risk (not recommended for - production servers or those who don't understand the security implications). - -- Fixed segmentation fault in ogr driver when shape type is null - -- Fixed synchronized MS_UNITS and inchesPerUnits array (#3173) - -- Fixed possible buffer overflow in msTmpFile() (#3484) - -- Fixed Using STYLEITEM AUTO, loadExpression fails when the label text contains a double quote (#3481) - -- PHP/MapScript: Expose getGeomTransform/setGeomTransform instead of exposing the private vars for rfc48 (#2825) - -- PHP/MapScript: Fixed updateFromString functions to resolve symbol names (#3273) - -- PHP/MapScript: ability to use the php clone keyword (#3472) - -- Modified mapserver units enum order to fix some problems with external softwares (#3173) - -- Fixed configure does not detect libGD version dependencies (#3478) - -- Fixed Drawing inline text not working (bitmap) (#3475) - -- ensure well formed XML when msWCSGetCapabilities_CoverageOfferingBrief - returns MS_FAILURE (#3469) - -- Fixed msQueryByRect does not use tolerance (#3453) - -- Fixed MapScript processTemplate and processQueryTemplate seg fault (#3468) - -- Fixed shapeObj->toWkt() returns single point for multipoint geometry (#2762) - -- Fixed Internal server error when Oracle returns ora-28002 code (#3457) - -- Fixed PHP/MapScript ms_iogetstdoutbufferbytes() always returning 0 bytes written (#3041) - -- MapScript resultsGetShape() method fails with a OracleSpatial layer (#3462) - -- PHP/MapScript circular references between objects (#3405) - -- Handle null results with gml:Null/gml:null according to version (#3299) - -- Reworked mapfile writing to use helper functions so that core types (e.g. numbers, strings, - colors, keywords, etc...) are always written consistently. - -- Ensure mapwmslayer.c does not unlink file before closing connection on it (#3451) - -- Fix security exception issue in C# with MSVC2010 (#3438) - -- Write out join CONNECTIONTYPE when saving a mapfile. (#3435) - -- Fixed attribute queries to use an extent stored (and cached) as part of the queryObj - rather than the map->extent. (#3424) - -- Reverted msLayerWhichItems() to 5.4-like behavior although still supporting - retrieving all items (#3356,#3342) - -- Grid layer: remove drawing of unnecessary gird lines (#3433) - -- Avoid errors and debug output for CONNECTION-less OGR layers in mappool.c - if they have a tileindex. - -- Implement support for raw imagemodes to use NULLVALUE formatoption to set - the background value of result images, and to try and mark nodata (#1709) - -- Implement support for wcs_rangeset_nullvalue to set NULLVALUE and - return null value definition in describe coverage result (#655) - -- Try to avoid exhausting the color table when rendering 24bit key - images into 8bit results (#1594) - -- Avoid crash, and ensure error report when loading keyimage fails (#1594) - -- Improve the handling of simple string comparisons for raster classified - values (#3425) - -- Generate good SQL when using !BOX! token and no filter. (#3422) - -- Implement non-shapefile tileindex support for raster query (#2796). - -- Improve support for [red/green/blue] classification expressions for - raster query (#1021) - -- Fixed imageObj->saveImage() sends unnecessary headers (#3418) - -- Avoid automatically regenerating maplexer.c (#2310) - -- Change rounding rules for average resampling (#1932) - -- Implement support for filename encryption per RFC 18 for rasters (#3416) - -- Fixed segfault when using shapefile with empty geometry and tileindex (#3365) - -- Avoid race condition on core_lock on win32 mutex init (#3396) - -- Avoid use of inline keyword for C code (#3327) - -- Support WFS parsing through libxml2 (#3364) - -- Fixed PHP/MapScript imageObj->saveImage() function (#3410) - -- Implement wms_nonsquare_ok metadata item for WMS servers that do - not support non-square pixels (#3409) - -- Fixed MapScript shape->classindex is always 0 (#3406) - -- Fixed PHP MapScript integer passing broken on 64bit systems (#3412) - -- Fix MS_NONSQUARE to work in mode=map (#3413) - -- Support inclusion of raster layers in query map drawing even if the results - may not be that useful (#1842). - -- Fixed auto angle: incorrectly rotated Labels. Added AUTO2 angle mode. (#1688) - -- Preliminary implementation of validity mask (imageObj->img_mask) for raw - raster data (#2181) - -- Added libgd < 2.0.30 compatibility (#3293) - -- Incorporate support for GDAL nodata on RGB images (#2404) - -- Incorporated support for GDAL masks (GDAL RFC 15) (#2640) - -- Fixed XML transformation issues with expressions and symbols (#3397) - -- Check error returns from mapstring functions (#2988) - -- Add support for multiliple srs in WFS 1.1.0 (#3227) - -- Fixed PHP/MapScript owsRequestObj->loadParams() method when using php in a non cgi/fcgi/cli mode. (#1975) - -- Ensure that non-file raster datasets work (#3253) - -- Correct mutex locking problem with rasters with no inherent georef. (#3368) - -- Correct ungeoreferenced defaults via GetExtent() on raster layer (#3368) - -- PHP Mapscript refactoring: take full advantage of PHP 5 / Zend Engine 2 (#3278)" - -- Fixed msRemoveHashTable() to return the proper value on failure/success. - -- Correct one pass query problems and OGC filter query (#3305) - -- Fixed msMSSQL2008CloseConnection() to free the statement handle properly (#3244) - -- Fixed the query handling with the MSSQL2008 driver (#3058) - -- Fixed swig zoomRectangle() method: the maxy in the rect object have to be < miny value (#3286) - -- Fix crash with GRID layers with no classes (#3352) - -- Remove "legacy" raster support, all raster rendering via GDAL now. - -- Very preliminary render plugin support for raster rendering. (RFC 54) - -- support correct MIME type output for WFS 1.1.0 (#3295) - -- add WMS 1.3.0 LayerLimit support (#3284) - -- fix WFS 1.1.0 exception attributes (#3301) - -- add more useful error message when query file extension test fails (#3302) - -- s/gml:null/gml:Null for empty WFS GetFeature responses (#3299) - -- Support metatiling and buffers in mode=tile (#3323) - -- Enhance error messages in msGetTruetypeTextBBox() (#3314) - -- Report parsing errors in INCUDEd files using the line number within the file (#3329) - -- Avoid memory error when building SQL bbox (#3324) - -- Reproject rectangles as polygons to get datelin wrapping (#3179) - -- Add support for the WMS capabilities items AuthorityURL, Identifier (#3251) - -- Added support to write a null shape in a shape file. (#3277) - -- Apply ON_MISSING_DATA to zero-length WMS client calls (#2785, #3243) - -- PHP/Mapscript: added labelCacheMember object and mapObj::getLabel() method (#1794) - -- Add shplabel tag support in templates (#3241) - -- Bumped GEOS requirement to version 3.0+ (#3215) - -- Fixed memory leak related to templates (#2996) - -- Added support of 44xx gtypes in oracle spatial driver (#2830) - -- Fixed curl proxy auth support for http connections (#571) - -- PHP/MapScript: removed deprecated class properties (#2170) - -- Fixed OGR datasource double free (#3261) - -- Fix compilation warnings around use of strcasestr (#3257) - -- Made %substitution% strings case insensitive (#3250) - -- Added support to get the extent of a raster layer that use a tileindex (#3252) - -- Fixed configure to support FTGL 2.1.2 (#3247) - -- Changed msSaveImageBufferGD to be in accordance with msSaveImageGD (#3201) - -- PHP/Mapscript: added layerObj units property (#3249) - -- Changed the query map rendering implementation without adding extra layers to the map (#3069) - -- SQL Server 2008 plugin is not handling null field values correctly (#2893) - -- Hatch symbol not properly saved (#2905) - -- Expose symbolObj.inmapfile to the SWIG API, have already been exposed to PHP (#3233) - -- Expose getGeomTransform/setGeomTransform to SWIG instead of exposing the private vars for rfc48 (#3214) - -- Fixed writeSymbol to support writing 'ANGLE AUTO' (#3214) - -- Fixed problems with point queries not working via the CGI (mode=query or mode=nquery) (#3246) - -- Support QueryByShape() with point and line geometries (#3248) - -- Honour MAXSIZE for WCS responses (#3204) - -- Implemented RFC 52 LayerResultsGetShape support for OGR connection type. - -- Fixed uninitialized variable with malloc used in osPointCluster() (#3236) - -- Oracle driver: remove BLOB columns instead of changing them to null (#3228) - -- Fixed ogc sld functions to return proper values (#2165) - -- MAP EXTENT truncates GetFeature requests for data outside bounds (#1287) - -- Added msStringSplitComplex function (#471) - -- Mapserver WFS should send maxfeatures to the spatial database (#2605) - -- WFS paging support (#2799) - -- Fixed joins do not accept crypted passwords (#2912) - -- Fixed HTML legend image samples truncated (#2636) - -- WMS GetFeatureInfo should respect the scale like GetMap does (#842) - -- Filter encoding: simple filters using propertyislike not applied properly - #2720, #2840 - -- Fix VBAR Chart production when using GD for rendering (#3482) - - -Version 5.6.0 (2009-12-04): ---------------------------- - -- WFS hits count is incorrect if the request contain 2 layers or more (#3244) - -- Fixed a problem with layer plugin where copyVirtualTable didn't copy - the LayerResultsGetShape function pointer (#3223) - - -Version 5.6.0-rc1 (2009-11-27): -------------------------------- - -- Fixed a problem with shape-based queries against projected layers when - using a tolerance (#3211) - -- Fixed long expression evaluation (#2123) - -- Added simplfy and topologyPreservingSimplify to MapScript (#2753) - -- Fixed Oracle FastCGI memory leak (#3187) - -- layer->project flag not being reset properly for drawquerylayer (#673 #2079) - -- OGC SLD: support multi-polygons geometries for filters embedded in - an SLD (#3097) - -- [WMC] embedded SLD in context does not work with namespace prefix (#3115) - -- Support name aliases used in sld text symbolizer (#3114) - -- decode html and unicode entities for polygon truetype symbol fills (#3203) - -- Parse PropertyName parameter for wfs requests (#675) - -- Fixed when saving a map, layer->transform isn't written properly in - all cases. (#3198) - -- Fixed buffer overflow in oracle spatial driver with large sql data (#2694) - -- Improve FastCGI include file finding logic (#3200) - - -Version 5.6.0-beta5 (2009-11-04): ---------------------------------- - -- Apply a minimum width on label outline (new outlines were too thin by default) - -- Don't apply scalefactor to polygon outline widths (but apply the - resolutionfactor) - -- Fix vector symbol size calculation (#2896) - -- Applied code clean up patch for mapsearch.c. (#3189) - -- Fixed labels centering when the label is longer than the line (#2867) - -- Ensure Python MapScript building doesn't reorder the libraries, support the - 'subprocess' module where available for setup.py, and default to using the - "super" swig invocation described in the Python MapScript README when - mapscript_wrap.c isn't available on the file system. #2663 contains the - reordering issue. - -- Fixed memory leak with shapefiles associated with one-pass query - implementation (#3188) - -- Fix abs/fabs usage that prevented angle follow labels to be discarded if - they were too wrapped on themselves - -- Allow CGI mapshape and imgshape variables to consume WKT strings (#3185) - -- Added support for nautical miles unit (#3173) - -- Fixed encoding metadata ignored by a few wcs/wfs 1.1 and sos requests (#3182) - -- PHP/Mapscript: added "autofollow" and "repeatdistance" in labelObj (#3175) - -- Added charset in content-type http header for wms/wfs/sos/wcs requests (#2583) - -- Python/MapScript: improve compatibility for different swig versions (#3180) - -- maprasterquery.c: a few fixes since beta4 (#3181, #3168). - -- mapows.c: Generate WMS LatLongBoundingBox in WGS84 datum (#2578) - - -Version 5.6.0-beta4 (2009-10-18): ---------------------------------- - -- Allow processing of single shapefiles with no items (e.g. an empty dbf file) (#3147) - -- Added resolution scaling for swf, svg, pdf and imagemap drivers (#3157) - -- Correct cases where a valid WFS Layer might return errors if - map extent does not overlap the layer extent (#3139) - -- fix problem with 0-length line patterns in AGG - -- Fixed problem of text/html WMS GetFeatureInfo which was returning HTML - image map output instead of the expected text/html template output. - This was done by changing the imagemap outputformat to use the - "text/html; driver=imagemap" mime type (#3024) - -- more resolution fixes for resolution scaling (symbolscale case) (#3157) - -- Make sure layer extents are saved when a mapfile is written (#2969) - -- Fixed CurvePolygons from oracle not drawn (#2772) - -- Fixed raster queries (broken by RFC 52 changes) (#3166) - -- Fixed coordinate projection problem in some cases with WMS GetFeatureInfo - output in GML2 format (#2989) - -- Added resolution scaling of some properties for GD driver (#3157) - -- Modified GD functions API to be consistent with all others drivers (#3157) - -- OGC Filter: strip all namespaces (not only ogc, gml) (#1350) - -- Use decimal values for size and width in SVG output format (#2835) - -- Correct invalid test when loading movies in an swf ouput (#2524) - -- Return WMS GetCapabilities v1.3.0 by default as required by spec (#3169) - -- Fixed mapObj.zoomScale() and mapobj.zoomRectangle() scaling problem in - Mapscript (#3131) - -- Few more fixes for high res output (#3157) - -- Allow "DRIVER 'TEMPLATE'" or "DRIVER TEMPLATE" in output formats - -- Correct sld generated from mapserver classes (#3133) - -- Correct libjpeg v7 compatability issue in old jpeg interface code (#3167) - -- Correct FEATURE_COUNT limits on WMS GetFeatureInfo raster queries (#3168) - -- Correct SCALE_BUCKETS issue with 16bit raster scaling (#3174) - - -Version 5.6.0-beta3 (2009-10-07): ---------------------------------- - -- make RFC55 highres output be friendly with scaledependant rendering (#3157) - -- avoid fractured and overlapping glyphs with angle follow (#2812) - -- Fixed SDE layer seg fault (#3152) - -- Fixed placement of labels using ANGLE AUTO which were not always positioned - correctly (#3160) - -- Enable output of geometry in GML GetFeatureInfo if wms_geometries and - wms_geom_type are specified (#2989) - -- fix URN typo in mapwfs.c for urn:EPSG:geographicCRS:... - -- don't apply scalefactor to label outlines (#3157) - -- update namespaces and schema pointers (#2872) - -- add RFC49 and RFC40 keywords to copy functions (#2865) - -- minor fix to correct numberOfResults when maxfeatures is set in - mapfile (#2907) - -- Fixed possible crash with WFS GetFeature when no projection is specified - at the map level (#3129) - -- Fixed anchor point of vertically stacked bar graphs - -- Fixed TEXT property that cannot be removed in the CLASS object. - PHP/Mapscript (#3063) - -- Fixed use of minfeaturesize auto with curved labels (#3151) - -- Fixed msRemoveHashTable function when 2 keys have the same hash (#3146) - -- Fix raster thread deadlock condition on posix/linux (#3145) - -- Do not route thread debug output through msDebug which requires locking. - -- Fix WCS coverage metadata handling if size/resolution missing (#2683). - -- Fix WCS crash with use of datasets that aren't physical files (#2901). - -- Fix WCS failure with WCS 1.1 OGC URN (urn:ogc:def:crs:OGC::CRS84) (#3161). - - -Version 5.6.0-beta2 (2009-10-01): ---------------------------------- - -- Fixed a couple of issues with Oracle Spatial and single pass queries (#3069) - -- Added layer.resultsGetShape() to PHP MapScript for use with queries (#3069) - -- Fixed query maps under the new single pass query process (#3069) - -- WFS Client seg fault (OGR layer not opened) (#3136) - -- Reduce use of sqrt() calls when determining distances (#3134) - -- support axis ordering for WFS 1.1 (#2899) - -- const changes to avoid warnings with msLoadProjectionString() - -- mapgd.c: removed unused drawVectorSymbolGD() function. - -- Use http://www.mapserver.org/mapserver namespace URI in XML mapfile - schema (#3142) - -- Fixed issue with PHP_REGEX_INC in mapscript/php3/Makefile.in (#3078) - - -Version 5.6.0-beta1 (2009-09-23): ---------------------------------- - -- WMS 1.3.0 expects a CRS parameter instead of SRS (#2979) - -- Allow users to set wms getmap and getlegendgraphic image format list (#455) - -- Fixed MapScript shapeObj->toWkt() segfaults (#2763) - -- add vertical bar charts to dynamic charting (#3128) - -- Get the intersection points and labels #3101 - -- Fixed shp2img not to cause a crash when the map couldn't be loaded - -- Fix problem with overflowing shape->index for (most) query modes (#2850) - -- Useful error message when PK is missing and data is subselect (#3124) - -- Add WMS root Layer metadata support (#3121) - -- Fixed build problem of PHP/Mapscript when php is compiled with gd as - a shared extension (#3117) - -- Improve safety of srcx/y checks in nearest neighbour raster resampler (#3120) - -- Added support for 4d geometry types and oci bind variables for Oracle (#3107) - -- Implement SECTION support for the WCS 1.1 GetCapabilities request (#3105) - -- Fixed WCS processing when both crs and response_crs are specified (#3083) - -- Fixed msFreeMap causing memory corruption in msFreeOutputFormat (#3113) - -- Fix WMC XML output when Dimension is used (#3110) - -- Enable LOAD_WHOLE_IMAGE processing option by default when rendering - WMS client layer images (#3111). - -- add default values for CGI %key% substitutions (#3108) - -- fix clipping of polygon shapes in line layers (#3059) - -- RFC 51 implementation: XML Mapfiles Format (#2872) - -- Fix output for valid WCS 1.1 XML (#3086) - -- Avoid double free with postgresql joins. (#2936) - -- Don't attempt to project layers given in pixel coordinates - (layer->transform != MS_TRUE) (#3096) - -- Modify loading imagery from GDAL to load all bands at once to avoid multiple - passes through pixel interleaved data (mapdrawgdal.c). This is just an - optimization - there should be no change in results or features. - -- Modern GDALs clear the config when destroying driver manager. Skip this - call to avoid TLS leakage on cleanup (mapgdal.c). - -- Fixed msMSSQL2008LayerGetShape to retrieve proper wkb geometries (#3082) - -- Fixed the shape index for the inline layers (#3074) - -- Fixed MINDISTANCE not considering label size on lines (#3050) - -- Labeling enhancements: ability to repeat labels along a line/multiline (#3030) - -- Modified STYLEITEM code to use the new way of rendering thick lines (#3025) - -- Fixed template processor to respect layer order. (#2619) - -- Add MS_DEBUGLEVEL and MS_ERRORFILE commandline switches for mapserv.c. - -- Exposed msMapOffsetExtent, msMapScaleExtent and msMapSetCenter methods - in PHP/Mapscript (#2460) - -- Removed ZEND_DEBUG define in PHP/Mapscript (#2717) - -- Fixed PHP/Mapscript to support PHP 5.3 (#3065, #3066) - -- remove -O optimization flags to configure script if configured - with --enable-debug - -- Fixed performance bottleneck when computing a polygon center of gravity for - label point computation. (#3053) - -- make WFS numberOfFeatures match maxFeatures if passed (#2907) - -- Add logging in layer visibility tests to help users find why layers - don't draw (#3054) - -- include PNG libs first (#3046) - -- merge graphics branch: RFC54 implementation, cairo rendering (png, svg, pdf), - opengl rendering (non functionnal yet) - -- Do pre-emptive test for map.extent/layer.extent interaction (#3043) - -- Add centroid geomtransform (#2825) - -- Test database connections before using them (#2932) - -- Support non-numeric join criteria (#2006) - -- Ensure there's enough room in the SQL to hold a long (#1284) - -- Fix filter error in multi-clause filters (#2937) - -- Fix agg freetype character lookup when no unicode charmap is present (#3018) - -- Fix memory leak in SQL building (#2997) - -- Fork AGG rendering library in our trunk - -- Fixed a memory leak when unescaping quotes in logical expressions (#2938) - -- Fixed template code for item, shpxy and extent tags to properly initialize - tag arguments in cases where there are mutiple tags in one chunk of - template (#2990) - -- Fix mapogcfilter.c not to cause syntax error if PROJ.4 is not compiled - in (#2987) - -- Rework Python MapScript's setup.py to be more like Python's to fix - a number of issues including (#2637) and to use mapserver-config - and ditch the old mapscriptvars approach - -- Prevent from changing the connection type to MS_RASTER when - setConnectionType(MS_WMS) is used (#2908) - -- Improve rounding logic for computing the src_xoff/yoff (#2976) - -- Fix filename path processing for raster queries and WCS get coverage so - that non-filesystem filenames are not altered (#2901) - -- Improved security relative to untrusted directories and mapfiles (RFC 56) - -- Fixed several security issues found in an audit of the CGI - application (#2939, #2941, #2942, #2943, #2944) - -- setConnectionType(MS_WMS) doesn't work with mapscript (#2908) - -- Perl Mapscript: improvement of imageObj wrapper (#2962) - -- Improve control of output resolution (RFC 55, #2948) - -- mapraster.c: use GDALOpenShared(), and CLOSE_CONNECTION=DEFERRED (#2815) - -- AGG font outline method change (#1243) - -- Change mapbit.c bitmask type from char to new 32bit ms_bitarray (#2930) - -- Added resolution writing in image files (#2891) - -- Try to save resolution values to GeoTIFF via GDAL (#2891) - -- Refactor legend icon drawing (remove renderer specific versions) - Add label styling or markers for annotation layer legend icons (#2917) - -- Update EXTENT warning message (#2914) - -- add support for SRSNAME parameter (#2899) - -- add support for resultType (#2907) - -- WFS 1.1.0 should use OWS Common 1.0.0 (#2925) - -- clean up GEOS init and cleanup functions (#2929) - -- add support for disabling SLD (#1395) - -- fix to output gml:boundedBy again (#2907) - -- fix warning for change in bitmask type (#2930) - -- fix time advertising in WMS 1.3.0 (#2935) - -- fix SOS blockSeparator output (#3014) - -- fix MIME type support (#3020) - - -Version 5.4.0-beta3 (2009-3-5): --------------------------------- - -- SLD: Correct crash with large class names (#2915) - -- Added Java MapScript WIN64 support (#2250) - -- Fixed a problem with long running processes, embedded scalebars/legends - and AGG. (#2887) - -- Applied patch to deal with a couple of WCS issues (time ranges, #2487) - and PostGIS tileindex-based time filters (#1856) - -- Adding -DUSE_GENERIC_MS_NINT to the WIN64 MapScript builds (#2250) - -- Fixed C# the compiler options for MSVC 2008 (#2910) - -- Fix build problem with mapogcsld.c when OWS services are not available (#473) - -- Fix build on windows (maputil.c) - -Version 5.4.0-beta2 (2009-2-25): --------------------------------- - -- Fixed a problem where default shade symbols (solid fill, no size) were being - scaled and not rendered as expected (related to #2896 I believe) - -- Fixed a problem with offset polylines (AGG only) (#2868) - -- Generate SLD version 1.1.0 (#473) - -- Tracking original geometry type so we can make better decisions on what - positions to use with POSITION AUTO and annotation layers. (#2770) - -- Setting up the same size units between the OGR auto-style and the - OGR label attribute binding option (#2900) - -- Take better care of the extra items with the inline layers to - prevent from memory corruption (#2870) - -- Fixed the compiler options for MSVC 2008 (#2898) - -Version 5.4.0-beta1 (2009-2-18): --------------------------------- - -- restored much of the pre-5.0 capabilities to update a mapfile via URL but in - a more secure manner (RFC44) - -- WMS 1.3.0 support added (#473) - -- OWS GetCapabilities should skip layers with status == MS_DELETE (#2582) - -- Set the default symbol size to 1 instead of 0 (#2896) - -- fix WMS LegendURL to print sld_version for 1.3.0 Capabilities (#473) - -- add GetSchemaExtension to WMS to support GetStyles in Capabilities XML (#473) - -- move xlink declaration to root of WMS 1.3.0 DescribeLayerResponse - -- Fixed a scalebar rounding problem causing to draw zero scalebar width (#2890) - -- SLD: if it contains a Filter Encoding tag, try to always set the - layer's FILTER element (#2889) - -- Add support for rendering INLINE layers with layer attributes (items) (#2870) - -- Fix mapserver crash when rendering a query map in HILITE mode - and there are is no STYLE defined (#2803) - -- Added projection support to [...ext] tags for template output. - -- Removed the error generation when the OGR layer contains no fields (#2883) - -- Added enhancements to mapogr.cpp for style annotations (#2879) - -- Fixed memory leaks when using msUpdate*FromString methods. (#2857) - -- Fixed the problem when removing the attribute binding in mapscript. - -- SOS XML validity fixes (#2646) - -- add WFS calls for schema resolution (#2646) - -- add gml:id to om:Observation (#2646) - -- fix some XML validity issues (#2646) - -- Fixed endianness issues with wide character strings for ArcSDE (#2878). - Thanks Russell McOrmond - -- Fixed WMS request with LAYERS parameter: may cause segmentation fault (#2871) - -- fix when layer status = DEFAULT and passing list of layers (#2066) - -- Fixed msAddLabel may cause access violation in certain conditions - -- Changed base type of labelObj size, minsize and maxsize from int to double (#2766) - -- add support for WMS Server title in LAYER object (#885) - -- Fixed build problem using --with-gd=static and freetype (#2697) - -- RFC49 implementation (#2865) - -- Fixed Blobs not filtered in OracleSpatial Attribute/WFS queries (#2829) - -- Fixed memory leak of map::setProjection in PHP/MapScript (#2861) - -- Fixed "internal PHP GC memory leaks" in PHP/MapScript (#2767) - -- Fixed bug with wms layer group hierarchy (#2810) - -- Added updateFromString() methods for several objects in PHP/Mapscript (#2298) - -- Added ms_newMapObjFromString mapObj constructor in PHP/Mapscript (#2399) - -- Add support to compile mssql2008 when SDE or ORACLE is not compiled (#2851) - -- Add support for creating debug builds for the plugins on Windows - -- Correct half pixel error in WMS layer's BBOX request to remote WMS (#2843) - -- Expose Map/Layer's Projection objects in PHP/MapScript (#2845) - -- Added getUnits() methods to projectionObj in Mapscript (#2798) - -- Improved Tag parsing in template code. (#2781) - -- Added hashtable object and metadata methods for php-mapscript (#2773) - -- mappostgis.c: Fix trailing spaces in fixed varchar fields (#2817) - -- RFC48 implementation: GEOMTRANSFORM on styleObj (#2825) - -- mapwms.c: cleanup warnings with recent gcc versions (#2822) - -- mapogcsos.c: Cleanup warning and error messages - -- mapagg.cpp: Fix center of rotation for truetype marker symbols - -- mapowscommon.c: use msLibXml2GenerateList to generate listed XML elements - -- mapowscommon.c: output version string correctly (#2821) - -- Added removeLayer function to mapObj in PHP/MapScript. (#762) - -- Exposed PIXELS value via URL configuration - -- Add Support for SLD TextSymbolizer HALO and ANGLE (#2806) - -- IGNORE_MISSING_DATA: largely replaced by run-time CONFIG property, - ON_MISSING_DATA, which supports three modes: FAIL, LOG, and IGNORE. - (#2785) ms-rfc-47.txt - -- mapstring.c: msStringTrim(*char str), front-and-back whitespace trimmer - -- mappostgis.c: re-write to remove binary cursors and break up - logic into smaller parts, add support for maxfeatures - -- mapogcfilter.c: increase array size (code was assigning to out - of bounds subscript) - -- MapScript: Added getBinding method to label and style object (#2670) - -- mapowscommon.c: use strcasecmp to check for language value - -- raster query fix for tileindex with relative paths (#2722) - -- Fixed msOGRGetValues function to return default values if the object - type is not TEXT. (#2311) - -- Fix for the access violation caused by msMSSQL2008LayerGetShape (#2795) - -- Fixed msMSSQL2008LayerGetItems to retrieve the column names properly (#2791) - -- Prevent from calling msMSSQL2008CloseConnection from msMSSQL2008LayerClose - causing memory corruption issues (#2790) - -- new polygon label placement algorithm (#2793) - -- stop drawing an artificial outline around polygons to ensure - continuity - users needing this feature will have to explicitely - add an outlinecolor of the same color as the fill color - -- added formatoption QUANTIZE_NEW to force going through the pngquant - quantization algorithm instead of the GD one for imagemode RGB (the - GD one can be kind of buggy) - -- fix some integer rounding errors in the agg line offseter (#2659) - -- fix a bug with shapes with duplicate end points. was causing nans - in the angle follow placement code (#2695) - -- refactor msGetLabelSizeEx (now merged with msGetLabelSize) (#2390) - -- native label size computation for AGG when using angle follow (#2357) - -- memory leak in msInsertLayer, from Ned Harding (#2784) - -- label size computation refactoring (#2390) - -- don't draw label background if we're using angle follow. (#2726) - -- legend keyimage resampling with agg (#2715) - -- tileindexed rasters when DATA is manipulated via mapscript work (#2783) - -- styleObj width now supports attribute binding - -- RFC40 implementation: label text wrapping and alignment (#2383) - -- baseline adjustment for multiline labels (#1449) - -- Added support to access to the labelObj OUTLINEWIDTH property in - PHP/MapScript - -- PHP paste image should also work with AGG (#2682) - -- Fixed bug when QUERYMAP hilite color is set and the shape's color in a - layer is from a data source (#2769) - -- Decoupled AUTO label placement from the positions enum in mapserver.h. Added - explicit case for POLYGON layers where CC is the default and then we try UC, - LC, CL and CR. (#2770) - -- Changed base type of styleObj size and width from int to double (#2766) - -- Correct allocation error in mapmssql2008.c - -- Add possibility to use a full resolution setting for svg output (#1706) - -- Fixed GetFeature through tileindex bug: the tileindex of the shape found - wasn't set properly in the resultcache object. (#2359) - -- Removed comma to correct WCS 1.1 Coverages formatting in payload directory. - (#2764) - -- Correct bug when LABEL_NO_CLIP in combination with minfeaturesize (#2758) - -- Fix a label size computation for AGG bug when scalefactor is used (#2756) - -- various SOS updates for CITE compliance (#2646) - -- Added support for static linking with the lib gd in configure - script (#2696) - -- Support OpenLayer's ol:opacity extension to OGC Web Map Context docs (#2746) - -- Added MS_VERSION_NUM for use with #if statements in code based on - libmapserver (#2750) - -- Fixed the configure script: failed to detect php5 on ubuntu. (#2365) - -- Fixed a memory leak associated with not deleting the lexer buffer - before parsing certain types of strings. (#2729) - -- Added legend graphics for layer of type annotation - for the AGG and GD renderer (#1523) - -- Masking the out-of-range characters to avoid the crash - in the AGG renderer (#2739) - -- Accept WMS requests in which the optional SERVICE parameter is missing. - A new test was incorrectly added in 5.2.0 that resulted in the error - "Incomplete WFS request: SERVICE parameter missing" when the SERVICE - parameter was missing in WMS requests in which the SERVICE parameter is - optional (#2737) - -- Support for the MapInfo style zoom layering option (#2738) - -- Implement Equals and GetHashCode properly for the mapscript C# classes - -- Expose msConnectLayer to the SWIG mapscript interface with a new - layerObj.setConnectionType() method that should be used instead of - setting the layerObj.connectiontype directly (#2735) - -- SLD: when creating well known symbols on the fly the pen-up value - used should be -99. - -- SWF: Button names reflects the layer id and shape id (#2691) - -- Support reading projection parameter for OGC filters (#2712) - -- Several enhancements to STYLEITEM AUTO support for labels (#2708) and - TTF symbols (#2721) in OGR layers - -- Expose special attributes OGR:LabelText, OGR:LAbelAngle, OGR:LabelSize - and OGR:LabelColor to MapScript getShape() calls (#2719) - -Version 5.2.0 (2008-07-16): ---------------------------- - -- mapfile.c: Fixed a bug that prevented using named symbols via URL - configuration. (#2700) - -Version 5.2.0-rc1 (2008-07-09): -------------------------------- - -- mapowscommon.c: fix support multiple namespaces (#2690) - -- Fix OGC simple filters on SDE layers (#2685) - -- wfs11 getcapabilities: correct memory corruption (#2686) - -- Allow building against Curl 7.10.6 and older which lack CURLOPT_PROXYAUTH - option required for *_proxy_auth_type metadata (#571) - -- Avoid fatal error when creating new ShapeFileObj with MapScript (#2674) - -- Fixed problem with WMS INIMAGE exceptions vs AGG output formats (#2438) - -- mapshape.c: Fixed integer pointer math being applied to uchars (#2667) - -- Fixed seg fault with saveImage() in PHP MapScript due to #2673 (#2677) - -- Fixed configure error related to new fribidi2 pkg-config support (#2664) - -- Fixed windows build problem (#2676) - -- Fix raster query bounds problem (#2679) - - -Version 5.2.0-beta4 (2008-07-02): ---------------------------------- - -- Added support in configure script for pkg-config for fribidi2 (#2664) - -- Added more debug/tuning output to mapserv and shp2img at debug level 2 (#2673) - -- maptemplate.c: removed extra line feeds from mime header output. (#2672) - -- mapresample.c: fix for bug 2540 when using raster resampling and AGG. - -- mapsde.c: Check at compile time that we have SE_connection_test_server, - which appears to only be available for ArcSDE 9+ (#2665). - -- mapshape.c: restore old behavior of tiled shapes relative to shapepath - with new behavior for when shapepath is undefined (#2369) - -- maputil.c: fix a bug for offset lines with agg, when the first segment - was horizontal (#2659) - -- mapraster.c: fix for tiled rasters with relative shape paths defined, - from dfurhy (#2369) - -- maptemplate.c: fixed a problem with extent tags with _esc extension not - working (#2666) - -Version 5.2.0-beta3 (2008-06-26): ---------------------------------- - -- mapsde.c: processing option added to allow using fully qualified names - for attributes (#2423). - -- mapsde.c: Test for an active connection before closing it (#2498). - -- mapdraw.c: Fixed issue where path following labels were not being drawn - if FORCEd. (#2600) - -- mapshape.c: Applied patch to make the location of tiled data relative to the - tileindex directory if SHAPEPATH is not set. (#2369) - -- maptemplate.c: Fixed issues in RFC 36 implementation that prevented mapscript - mapObj->processQueryTemplate() method from working. - -- WMS/WFS: extend warning message (#1396) - -- WFS: Respect units for the DWhitin parameter (#2297) - -- WFS: correct OGC Contains filter (#2306) - -- WMS: set srsName correctly for GetFeatureInfo (#2502) - -- SOS: detect invalid time strings (#2560) - -- SOS: more srsName support (#2558) - -- mapserv.c, maptemplate.c: fixed problem with arguments to msGenerateImages(). (#2655) - -- WMS: produce warning if layer extent is null (#1396) - -- WFS: project LatLongBoundingBox if required (#2579) - -- SOS: generate error for some invalid filters (#2604) - -- SLD: Use style's width paramater when generating sld (#1192) - -Version 5.2.0-beta2 (2008-06-18): ---------------------------------- - -- mapogcsos.c: support invalid procedure in GetObservation (#2561) - -- Fixed possible buffer overrun with Oracle Spatial driver (#2572) - -- mapogcsos.c: support srsName in GetObservation (#2414) - -- Filter Encoding: Modify DWithin definition (#2564) - -- Added webObj legendformat and browseformat mapping in PHP MapScript (#2309) - -- Removed static buffer size limit in msIO_*printf() functions (#2214) - -- Fixed libiconv detection in configure for OSX 10.5 64 bit (#2396) - -- mapstring.c: possible buffer overflow in msGetPath (#2649) - -- maputil.c: Correct expression evaluation with text containing - apostrophes (#2641) - -- mapwfs.c: Possibly generate an error message when applying filter - encoding (#2444) - -- Added MS_LABEL_BINDING constants for SWIG MapScript (#2643) - -- mapogcsos.c: fix POST support (#2379) - -- maplibxml2.c: helper functions XML POST fix (#2379) - -- mapwfs.c: fix segfault when srsName is not passed on BBOX Filter (#2644) - -- mapwfs.c: do not return error for empty query results (#2444) - -- Remove C++-style comments and most other warnings thrown by -pedantic (#2598) - -- mapwfs.c/mapwfs11.c: set GML MIME type correctly - -- mapogcsos.c: advertise supported SRS list via - MAP.WEB.METADATA.sos_srs (#2414) - -- mapwfs.c: set layer extent to map extent for default - GetFeature requests with no spatial predicates (#1287) - -Version 5.2.0-beta1 (2008-06-11): ---------------------------------- - -- WMS/WFS layers can now specify a proxy servert (#571) - -- mapwmslayer.c: set QUERY_LAYERS correctly (#2001) - -- mapwcs.c: handle PARAMETER values correctly (#2509) - -- SOS: fix various memory leaks (#2412) - -- mapwcs.c: advertise temporal support in GetCapabilities (#2487) - -- Fixed flaw in findTag() in maptemplate.c that prevented multiple tags - on the same line being processed under certain conditions. (#2633) - -- Return results even when extents are missing (#2420) - -- Avoid displaying OGR connection strings in error messages (#2629) - -- WCS: respect wcs_name metadata for GetCoverage and DescribeCoverage - requests (#2036) - -- CGI: added -nh option to allow for the suppression of content headers from - the command line (#2594) - -- PostGIS: fix postgis idle-in-transaction problem (#2626) - -- AGG: enable ellipse symbol rotation for POINT/ANNOTATION layers (#2617) - -- RFC36: add more extensions to support templates (#2576) - -- AGG: allow dashed hatch symbols (#2614) - -- AGG: enable offset lines of type x -99 (#2588) - -- AGG: use an agg specific label size calculation function where - possible (#2357) - -- mapogcsld.c: fetch TextSymbolizer/Label/ogc:PropertyName correctly (#2611) - -- Don't ignore .qix file when DATA reference includes .shp extension (#590) - -- CGI able to alter layers with space and underscores (#2516) - -- WFS Multipoint query with PostGIS bug fixed (#2443) - -- Tiling API (RFC 43) mode=tile, tilemode=spheremerc, tile=x y zoom (#2581) - -- Remove C++-style comments and most other warnings thrown by -pedantic (#2598) - -- Fix PostGIS transaction behavior in fcgi situations (#2497, #2613) - -- Improve performance for large shape files (#2282) - -- encode WMS parameters correctly (#1296) - -- Added alignment option within a scalebar (#2468) - -- RFC-42 HTTP Cookie Forwarding (#2566) - -- Fixed handling of encrypted connection strings in postgis driver (#2563) - -- mapagg.cpp: AGG: add opacity at the style level (#1155) - -- mapwms.c: add Cache-Control max-age HTTP header support (#2551) - -- mapogcsos.c: support URI encoded procedures correctly (#2547) - -- Added support for EMPTY template with WMS GetFeatureInfo (#546) - -- Throw an exception if the WCS request does not overlap layer (#2503) - -- Acquire TLOCK_PROJ for pj_transform() calls (#2533). - -- Fixed problem with large imagemaps generating no output (#2526) - -- mapwms.c: make version optional for GetCapabilities again (#2528) - -- support URN scheme for components of observed property elements (#2522) - -- Fixed gdImagePtr gdPImg memory leak in msSaveImageBufferGD() (#2525) - -- mapogcsos.c: handle invalid POST requests (#2521) - -- mapogcsos.c: handle ACCEPTVERSIONS parameter (#2515) - -- mapwcs.c/mapwcs11.c: s/neighbour/neighbor/g (#2518) - -- mapwms.c: relax FORMAT parameter restrictions for GetFeatureInfo (#2517) - -- mapwcs.c: support COVERAGE lists for DescribeCoverage (#2508) - -- mapwcs.c: fix lonLatEnvelope/@srsName (#2507) - -- mapwcs.c: omit VendorSpecificCapabilities (#2506) - -- mapwcs.c: test for either resx/resy OR width/height (#2505) - -- mapwcs.c: make GetCoverage demand one of TIME or BBOX (#2504) - -- mapwms.c: make GetLegendGraphic listen to TRANSPARENT in OUTPUTFORMAT (#2494) - -- OWS: support updatesequence (#2384) - -- mapwms.c: test VERSION after service=WMS (#2475) - -- OWS: output Capabilities XML updateSequence if set (#2384) - -- mapwcs.c: better handling of REQUEST parameter (#2490) - -- mapwcs.c: point to correct exception schema (#2481) - -- mapows.c: add version negotiation (#996) - -- mapwfs.c: return default GML2 when invalid OUTPUTFORMAT passed (#2479) - -- mapowscommon.c: add OWS Common style version negotiation (#996) - -- mapwcs.c: better section parameter handling for CITE (#2485) - -- mapwfs.c: point to the correct schema for exceptions (#2480) - -- shp2img.c/shp2pdf.c: clean up usage text, check for invalid layers (#2066) - -- completed implementation of RFC24 (#2442, #2032) - -- mapwcs.c: require VERSION parameter for DescribeCoverage and - GetCoverage (#2473) - -- mapwcs.c: change error token to MS_WCSERR instead of MS_WMSERR (#2474) - -- mapwcs.c: set exception MIME type to application/vnd.ogc.se_xml - for 1.0.0 (#2470) - -- mapwcs.c: Generate a decently formatted exception if an WCS XML POST request - is received (#2476). - -- mapowscommon.c: support OWS Common 1.1.0 as well (#2071) - -- mapogcsos.c: support SOS 1.0.0 (#2246) - -- Implement mapObj.setCenter, mapObj.offsetExtent, mapObj.scaleExtent, - rectObj.getCenter at the SWIG API (#2346) - -- mapogcfilter.c: use USE_LIBXML2 in ifdefs (#2416) - -- clean up naming conventions of Shapefile API (#599) - -- use msComputeBounds() instead, since it's already in the codebase (#2087) - -- set shapeObj bounds from WKT (#2087) - -- fixed issue where path following labels sometimes used the supplied -setting for position. In all cases with ANGLE FOLLOW we want to force -position MS_CC regardless of what is set in the mapfile. - -- enforce (-99 -99) to be the penup value for vector symbols (#1036) - -- Support for labeling features (polygon & line) prior to clipping. This -results in stable label positions regardless of map extent. (#2447) - -- Support for quantization and forced palette png output with RGBA images - (#2436) - -- SLD using a single BBOX filter should generate an SQL ststement for - oracle/postgis/ogr (#2450) - -- Accurate Calculation of legend size for WMS LegendURL (#2435) - -- Converted mapogr.cpp to use OGR C API instead of C++ classes to allow - GDAL/OGR updates without having to recompile MapServer (#545, #697) - -- add missing space on dashed polygon outlines with svg (#2429) - -- Restored behavior of MS 4.10 and made WMS STYLES parameter optional - again in GetMap and GetFeatureInfo requests (#2427) - -- Speed up forced palette rendering (#2422) - -- WMS GetFeatureInfo: honour FEATURE_COUNT for any INFO_FORMAT and - apply the FEATURE_COUNT per layer instead of globally (#2423, #1686) - -- enable soft outlines on truetype labels. This is triggered with a new - keyword OUTLINEWIDTH for the LABEL block (#2417) - -- fix clipping rectangle to take width as well as size into account (#2411) - -- AGG: added and use a line and polygon adaptor to avoid copying shapeObj - points to an agg path_storage. avoids a few mallocs and a few copies. - -- fixed symbolsetObj not to set the SWIG immutable flag permanently - don't expose refcount and the symbol attributes (Ticket #2407) - -- fix for support of entity encoded text in angle follow text (#2403) - -- AGG: initial support for native computation of label sizes (#2357) - -- AGG: support text symbols specified by their character number (#2398) - -- AGG: fix angle orientation for various symbols - -- allow scientific notation for attributes binded to an int (#2394) - -- merge GD and AGG label cache drawing functions (#2390) - -- Enable AGG rendering of bitmap font labels instead of falling back to - GD (#2387) - -- clean up treatment of encoding and wrap caracter - -- Fix legend label placement for multiline labels (#2382) - -- enforce WRAP parameter in legend label (#2382) - -- AGG: pixel level simplification for line and polygon shapes (#2381) - -- fixed blue/green color swapping for space delimited strings bound to an - attribute. (bug 2378) - -- don't remove points that are checked as being colinear (#2366) - -- add initial(?) support for reading a pie chart's size from an - attribute (#2136) - -- don't bail out in map parsing if the outputformat had to be modified - (bug #2321) - -- use a renderer agnostic legend icon drawing function which switches - to the GD or AGG specific one depending on the outputformat (#2348) - -- AGG: switch alpha buffer when drawing query layer - -- Fixed legend icons not drawing when using maxscaledenom - -- AGG: fix embedded scalebar rendering when using postlabelcache (#2327) - -- AGG: allow for fast and aliased rendering of simple lines and polygons - thick lines and patterns (i.e. dashes)aren't supported. - this is triggered when the symbol is of TYPE SYMBOL *and* its ANTIALIAS - is off (wating to find a better solution to trigger this). - -- AGG: the pixmap of pixmap symbols is now cached in an agg-compatible state - the first time it is accessed. this avoids rereading and retransforming - it each time that symbol is used. - -- AGG: the imageObj now stores in what state it's alpha channel is in. The - number ofmsAlphaGD2AGG/AGG2GD calls is now reduced, but most importantly - each of these calls is usually just a check for this state and does - no computation. - -- AGG: fixed a few artifacts in embedded legend rendering on rgba images. - -- Fixed modulus operator in the parser (#2323) - -- maprasterquery.c: Fix crash when queryies on done on raster layers with - no styles (#2343) - -- maprasterquery.c: Modify msRASTERLayerOpen() to create a defaulted raster - layer info if there isn't one, to avoid the errors about open only being - supported after a query. Also wipe the raster layer info in case of - an empty result set, or failures of a query to reduce likelyhood of - leaking the raster layer info. - -- Improve out of memory handling in mapdrawgdal.c, and mapgd.c. (#2351) - -- Improve configuration logic for fastcgi (#2355). - -- WMS: image/wbmp should be image/vnd.wap.wbmp (#2360) - -- SOS: support maxfeatures for GetObservation requests (#2353) - -- mapdraw.c,mapquery.c: Reset layer->project flag for each full layer drawing - or query so that need to reproject will be reconsidered (#673). - -- PHP MapScript: fix for getStdoutBufferString() and getStdoutBufferBytes() - functions on win32 (#2401) - -- mapowscommon.c: fix namespace leak issues (#2375) - -- mapogcsos.c: add SWE DataBlock support (#2248) - -- mapogcsos.c: fix build warnings, namespace and schema pointers (#2248) - -- mappdf.c: support output in fastcgi case via msIO_fwrite() (#2406) - -- mapogcsos.c: Initial support for POST requests (#2379) and updated - msSOSDispatch() handling - -- mapogr.cpp: Use pooling api to ensure per-thread sharing of connections - only (#2408) - -- mapogcsos.c: change substituted variable from sensorid to procedure (#2409) - -- maplibxml2.c: Initial implementation of libxml2 convenience functions - -- configure: Modified so libxml2 support is requested for WCS and SOS, - and is indicated by USE_LIBXML2 definition. Use @ALL_ENABLED@ in - DEFINEs and mapscriptvars generation. - -- mapresample.c: Fixed support for multi-band data in RAW mode for bilinear - and nearest neighbour resamplers (#2364). - -- mapdraw.c: Improve error reporting if a raster layer requested in - a query map (#1842). - -- mapfile.c: add simple urn:ogc:def:crs:OGC::CRS84 support. - - -Version 5.0.0 (2007-09-17) --------------------------- - -- AGG: Fix angle computation for truetype marker symbols on lines (#2316) - -- Fix support for bilinear resampling of raster data with AGG (#2303) - - -Version 5.0.0-rc2 (2007-09-10) ------------------------------- - -- Prevent seg fault in msWMSLoadGetMapParams when request is missing (#2299) - -- Fixed calculation of scale in PHP MapScript mapObj.zoomScale() (#2300) - -- Fixed conflict between runtime substitution validation and qstring - validation. - -- Fixed agg configure logic (now should work with --with-agg alone) (#2295) - -- Fixed interleaving of multi-band results for raster query (#2294). - - -Version 5.0.0-rc1 (2007-09-05) ------------------------------- - -- Fixed "MinFeatureSize AUTO" labeling for polygon layers, works for polygon - annotation layers too (#2232) - -- Fixed path following labels with short (2/3 character) strings (#2223) - -- AGG fix a bug when rendering polygons with tiled pixmaps - -- Added requirement to provide validation pattern for cgi-based attribute - queries using the layer metadata key 'qstring_validation_pattern' (#2286) - -- Fixed msDebug causing a crash with VS2005 (#2287) - -- Added stronger checks on libpdf version in configure script (#2278) - -- Added msGetVersionInt() to MapScript (ms_GetVersionInt() in PHP) (#2279) - -- _isnan prototype for MSVC builds from #2277 - -- AGG: Fix a bug when rendering brushed lines with vector or pixmap symbols - (artifacts could appear on outline) - -- AGG: Adjust symbol height when brushing a line with a vector symbol so that - the line width isn't truncated - -- Only include process.h on win32 (non-cygwin) systems, moved from - maptemplate.h to mapserver.h. (#2276) - - -Version 5.0.0-beta6 (2007-08-29) --------------------------------- - -- Fixed problem with outline of polygons rendered twice with OGR - STYLEITEM AUTO and AGG output (#2271) - -- Fixed problem compiling with only WMS/WFS client but none of the - WMS, WFS, WCS or SOS server options enabled (#2272) - -- Fixed buffer overflow in handling of WMS SRS=AUTO:... (#1824) - -- AGG: render thick lines and polygon outlines with round caps and joins - by default - -- Typo in mapfile writing (#2267) - -- Fixed mapping of class->keyimage in PHP MapScript (#2268) - -- Look for libagg under lib64 subdir as well in configure (#2265) - -- AGG: revert previous optimizations. now use caching of the rendering object - to avoid the re-creation of some structures each time a shape is drawn - -- AGG: optimizations for faster rendering. we now do not initialize the font - cache when no text is to be rendered - -- AGG: fixed rendering of polygons with holes (#2264) - -- AGG - raster layers: fix typo in mapresample.c that produced random - background colors when using OFFSITE (#2263) - -- AGG: Fix a bug when rendering tiled polygons with truetype, pixmap or - vector symbols (usually only affected bright colors) - -- Avoid passing null to msInsertHashTable in processLegendTemplate - when layer.name or layer.group not specified (#2261) - -- Fixed problems with fonts in PDF output (#2142) - -- AGG: smooth font shadows - - -Version 5.0.0-beta5 (2007-08-22) --------------------------------- - -- Fixed XSS vulnerabilities (#2256) - -- Allow building with AGG from source when libaggfontfreetype is missing. - configure --with-agg=DIR now automatically tries to build - agg_font_freetype.o from source if libaggfontfreetype is missing (#2215) - -- Fixed possible buffer overflow in template processing (#2252) - -- fix blending of transparent layers with RGBA images - -- AGG: speed up rendering of pixmap marker symbols - -- Implement OGR thread-safety via use of an OGR lock (#1977). - -- Fixed compile warnings (#2226) - -- Fixed mappdf.c compile warnings, PDF support was probably unusable - before that fix (#2251) - -- Adding -DUSE_GENERIC_MS_NINT to the WIN64 builds (#2250) - -- Adding msSaveImageBuffer and use that function from the mapscript - library instead of the renderer specific functions. (#2241) - -- Split each format into it's own element in WCS describe - coverage results (#2244). - -- Support to run the mapscript c# examples on x64 platform (#2240) - -- Fixed problem introduced in 5.0.0-beta4: all HTML legend icons were - empty white images (#2243) - -- Fixed WMS Client to always send STYLES parameter with WMS GetMap - requests (#2242) - -- Fixed support for label encoding in SVG output (#2239) - -- Added support for label encoding in legend (#2239) - -- Fixed PHP MapScript layer->queryByAttributes() to not accept empty or - null qitem arg (#480) - -- AGG: fixed incorrect rendering of pixmaps on MSB architectures (#2235) - -- Added layer.getFeature() in PHP MapScript with optional tileindex arg, - and deprecated layer.getShape() to match what we had in SWIG (#900) - -- Added class.getTextString() and deprecated/renamed class.getExpression() - and layer.getFilter() to class.getExpressionString() and - layer.getFilterString() to match what we have in SWIG MapScript (#1892) - - -Version 5.0.0-beta4 (2007-08-15) --------------------------------- - -- Updated msImageCreateAGG to only allow RGB or RGBA pixel models (#2231) - -- Fixed problem with symbol.setImagePath() when file doesn't exist (#1962) - -- Python MapScript failures (#2230) - -- msInsertLayer should not free the incoming layer anymore (#2229) - -- Include only parsed in the first mapfile (#2021) - -- Incorrect lookup of symbol in symbolset (#2227) - -- Mapfile includes and MapScript (#2089) - -- Fixed alignment of GetLegendGraphic output when mapfile contains no - legend object (#966) - -- Fixed seg. fault when generaing HTML legend for raster layers with no - classes (#2228). The same issue was also causing several Chameleon apps - using HTML legend to seg fault (#2218) - -- Do not use case sensitive searches in string2list, which is used - for msWhichItems (#2067) - -- Ensure that we can write AGG images with Python MapScript's write() method - -- Support unicode attributes for ArcSDE 9.2 and above (#2225) - -- GD: Truetype line symbolization should follow line orientation only - if GAP is <=0 - -- AGG: Added truetype symbolization for lines and polygons - -- AGG: Draw an outline of size 1 of the fill color around polygons if an - outlinecolor isn't specified (avoids faint outline) - -- Added summary of options at end of configure output (#1966) - -- Updated configure script to detect and require GEOS 2.2.2+ (#1896) - -- Renamed --enable-coverage configure option to --enable-gcov to avoid - confusion with WCS or Arc/Info coverages (#2217) - -- Fixed --enable-gcov (formerly --enable-coverage) option to work with - php_mapscript.so (#2216) - -- check for OGR support in if SLD is used (#1998) - -- msWMSLoadGetMapParams: fixed handling of required parameters (#1088) - -- if any of srs, bbox, format, width, height are NOT found, throw exception - -- if styles AND sld are NOT found, throw an exception - -- NOTE: this may cause issues with some existing clients who do not pass - required parameters - - -Version 5.0.0-beta3 (2007-08-08) --------------------------------- - -Known issues: - -- This beta contains significant improvements and fixes on the AGG - rendering front. However some build issues remain on some platforms. - Please see ticket #2215 if building with AGG support doesn't work with - the default configure script: http://trac.osgeo.org/mapserver/ticket/2215 - -Bug fixes: - -- mapagg.cpp rewrite - the AGG renderer should now support all the GD features - -- Use AGG when requested for drawing the legend - -- Fixed problems with very large HTML legends producing no output (#1946) - -- Use OGR-specific destructors for objects that have them rather than - 'delete' (#697) - -- Include style-related info in HTML legend icon filenames to solve issues with - caching of icons when the class or style params are changed (#745) - -- Fixed issues with wms_layer_group metadata in WMS GetCapabilities (#2122) - -- Use msSaveImageBufferAGG for AGG formats in getBytes (#2205). - -- Make sure to emit $(AGG) to mapscriptvars because of conditional inclusion - of stuct members to imageObj. (#2205) - -- Make imageextra field in imageObj not conditional (not #ifdef'ed) (#2205) - -- AGG/PNG and AGG/JPEG are the only valid agg drivers. - Imagetypes aggpng24 and aggjpeg can be used to refer to the - default output formats. (#2195) - -- Fix memory leak with labepath object (#2199) - -- Fix memory leak msImageTruetypePolyline (#2200) - -- SWF: Fix incorrect symbol assignements (#2198) - -- Fixed memory leaks in processing of WFS requests (#2077) - -- Avoid use of uninitialised memory in msCopySymbol() (#2194) - - -Version 5.0.0-beta2 (2007-08-01) --------------------------------- - -- Oracle Spatial: Fixed some issues related with the maporaclespatial.c - source code: warnings with calls in gcc 4.x versions (#1845), gtype - translation error, generating memory problem (#2056), problems with items - allocation (#1961 and #1736), and some memory-leaks errors (#1662). - -- AGG: Fixed a significant number of rendering issues including conflicts with - OPACITY ALPHA and ANTIALIAS TRUE settings w/regards to polygon fills. Fixed - ellipse and vector markers. Fixed AGG/GD alpha channel conflicts by writing - conversion to/from functions. (#2191-partial, #2173, #2177) - -- SOS: Turn layer off if eventTime is not in the sos_offering_timeextent - (#2154) - -- WFS: Correct bugs related to query by featureid support (#2102) - -- WMS: Add svg as a supported format for GetMap request (#1347) - -- WMS: Correct WMS time overriding Filter paramter (#1261) - -- Fix problem with LUT scaling ranges with explicit value for 255 (#2167). - -- WCS: Fixed resampling/reprojecting for tileindex datasets (#2180) - -- Fixed formatting of configure --help (#2182) - -- Fixed AGG configure option to use 'test -f' instead of 'test -e' which - doesn't work on Solaris (#2183) - -- Fixed mapwms.c to support selecting AGG/ outputformats via FORMAT=. - -- Removed unused styleObj.isachild member (#2169) - - -Version 5.0.0-beta1 (2007-07-25) --------------------------------- - -New features in 5.0: - -- MS RFC 19: Added Style and Label attribute binding - -- MS RFC 21: Raster Color Correction via color lookup table - -- MS RFC 27: Added label priority - -- MS RFC 29: Added dynamic charting (pie and bar charts) - -- MS RFC 31: New mechanism to load/set objects via URL using mapfile syntax - -- MS RFC 32: Added support for map rendering using the AGG library for - better output quality - - -Long time issues resolved in 5.0: - -- MS RFC 17: Use dynamic allocation for symbols, layers, classes and styles - (got rid of the static limit on the number of instances of each in a map) - -- MS RFC 24: Improved memory management and garbage collection for MapScript - -- MS RFC 26: Terminology cleanup (layer transparency renamed to opacity, - scale becomes scaledenom, symbol style becomes symbol pattern) - -- MS RFC 28: Enhanced the debug/logging mechanism to facilitate - troubleshooting and tuning applications. Added support for multiple - debug levels and more control on output location. - - -Other fixes/enhancements in this beta: - -- Upgrade Filter encoding to use geos and support all missing operators (#2105) - -- Use of static color Palette support for gd output (#2096) - -- MapServer's main header file map.h has been renamed mapserver.h (#1437) - -- A mapserver-config script has been created - -- Single and double quotes escaping in string expressions used by FILTER. - (Resolves tickets #2123 and #2141) - -- SLD: Support of Graphic Stroke for a Linesymbolizer (#2139) - -- GD : draw symbols along a line using pixmap symbols (#2121) - -- SVG : Polygons should not be filled if color is not given (#2055) - -- WMS : fixed request with a BBOX and and SLD containing Filter - encoding (2079) - -- SWF : use highlight color from querymap (2074) - -- Support for embedding manifests as resources for the VS2005 builds. - (ticket #2048) - -- Changed OGRLayerGetAutoStyle not to pass NULL pointer to GetRGBFromString - causing access violation (bug 1950). - -- Fix SDE returning the row_id_column multiple times (bug 2040). - -- Fix text outline bug. (bug 2027) - -- Improve error reporting when OWS services are requested but the support - is not compiled in. (bug 2025) - -- Fix support for OFFSITE for simple greyscale rasters (bug 2024). - -- [SLD] : Error on last class in raster class names based on the ColorMapEntry - (bug 1844) - -- [Filter Encoding] : Check if Literal value in Filter is empty (bug 1995) - -- [SLD] : Else filters are now generated at the end of classes (bug 1925) - -- Enabled setting of a layer tileindex (e.g. map_layername_tileindex) via the - CGI program. (bug 1992) - -- Added feature to the CGI to check runtime substitutions against patterns - defined in layer metadata. (bug 1918) - -- Exposed label point computation to mapscript (bug 1979) - -- [SLD]: use the url as symbol name for external symbols (bug 1985) - -- [SLD] : support of mixing static text with column names (bug 1857) - -- maperror.c: fix for wrapping long in image errors, thanks to Chris - Schmidt (bug 1963) - -- maperror.c: fix closing of stderr/stdout after writing error msg (bug 1970) - -- Preliminary implementation of RFC 21 (Raster Color Correction). - -- [SLD] : when reading an SLD, sequence of classes was reversed (Bug 1925) - -- Fixed a bug with SDE capability requests where we were double - freeing because sde->row_id_column wasn't set to NULL in msSDELayerOpen - -- [OGC:SOS] : Fixed bugs realted to metadata and xml output - (1731, 1739, 1740, 1741). Fixed bug with large xml output (bug 1938) - -- fixed performance problem in raster reprojection (bug 1944) - -- added msOWSGetLanguage function in mapows.c/h (bug 1955) - -- added mapowscommon.c/mapowscommon.h and updated mapogcsos.c to use - mapowscommon.c functions (bug 1954) - -- added more Perl mapscript examples in mapscript/perl/examples/, most - of which exemplify recently added GEOS functionality - -- php_mapscript.c: Fixed setRotation() method to check for MS_SUCCESS, not - MS_TRUE (bug 1968) - -- mapobject.c: Fixed msMapSetExtent() to avoid trying to calcuate the - scale if the map size hasn't been set yet (bug 1968) - -- mapobject.c: ensure msMapComputeGeotransform() returns MS_FAILURE, not - MS_FALSE (bug 1968) - -- mapdraw.c: Actually report that we aren't configure with wms client - support if that is why we can't draw a layer. - -- mapows.c: fixed XML error (bug 2070) - -- mapwms.c: Fixed text/plain output duplicate (bug 1379) - -- mapwms.c: Attribution element output in GetCapabilities only 1.0.7 and - higher (bug 2080) - -- mapwms.c: UserDefinedSymbolization element output in GetCapabilities - only 1.0.7 and higher (bug 2081) - -- mapwms.c: GetLegendGraphic and GetStyles only appear in 1.1.1 and - higher responses (bug 1826) - -- mapwcs.c: - - msWCSDescribeCoverage: throw Exception if Coverage doesn't exist (bug 649) - - msWCSException: updated as per WCS 1.0 Appendix A.6 - -- mapogcsos.c: Added ability to output gml:id via MAP/LAYER/METADATA - ows/sos/gml_featureid (bug 1754) - -- mapcontext.c: Added ogc namespace (#2002) - -- Note that starting with this release the source code is now managed - in Subversion (SVN) instead of CVS and we have migrated from bugzilla - to Trac for bug tracking. - - -Version 4.10.0 (2006-10-04) ---------------------------- - -- No source code changes since 4.10.0-rc1 - -Known issues in 4.10.0: - -- PHP5 not detected properly on Mandriva Linux (bug 1923) - -- Mapfile INCLUDE does not work with relative paths on Windows (bug 1880) - -- Curved labels don't work with multibyte character encodings (bug 1921) - -- Quotes in DATA or CONNECTION strings produce parsing errors (bug 1549) - - - -Version 4.10.0-RC1 (2006-09-27) -------------------------------- - -- SLD: quantity values for raster sld can be float values instead of just - being integer - -- Hiding labelitemindex, labelsizeitemindex, labelangleitemindex - from the SWIG interface (bug 1906) - -- Fixed computation of geotransform to match BBOX (to edges of image) not - map.extent (to center of edge pixels). (bug 1916) - -- mapraster.c: Use msResampleGDALToMap() for "upside down" images. (bug 1904) - - -Version 4.10.0-beta3 (2006-09-06) ---------------------------------- - -- Web Map Context use format metadata when formatlist not available. (bug 1723) - -- Web Map Context boolean values true/false now interpreted. (bug 1692) - -- Added support for MULTIPOLYGON, MULTILINESTRING, and MULTIPOINT in - msShapeFromWKT() when going through OGR (i.e. GEOS disabled) (bug 1891) - -- Fixed MapScript getExpressionString() that was failing on expressions - longer that 256 chars (SWIG) and 512 chars (PHP). (bug 1428) - -- WMSSLD: use Title of Rule if Name not present (bug 1889) - -- Fixed syntax error (for visual c++) in mapimagemap.c. - -- Fixed mapgeos.c problems with multipoint and multilinestring WKT (bug 1897). - -- Implemented translation via OGR to WKT for multipoint, multiline and - multipolygon (bug 1618) - - -Version 4.10.0-beta2 (2006-08-28) ---------------------------------- - -- Applied patch supplied by Vilson Farias for extra commas with imagemap - output (bug 760). - -- Fixed possible heap overflow with oversized POST requests (bug 1885) - -- Set ./lib and ./include properly for MING support (bug 1866) - -- More robust library checking on OSX (bug 1867) - -- Removed mpatrol support (use valgrind instead for something - similar and less intrusive). (bug 1883) - -- Added mapserver compilation flags to the SWIG c# command line (bug 1881) - -- Fix OSX shared library options for PHP (bug 1877). - -- Added setSymbolByName to styleObj for the SWIG mapscript in order to - set both the symbol and the symbolname members (bug 1835) - -- Generate ogc filters now outputs the ocg name space (bug 1863) - -- Don't return a WCS ref in WMS DescribeLayer responses when layer type is - CONNECTIONTYPE WMS (cascaded WMS layers not supported for WCS) (bug 1874) - -- Correct partly the problem of translating regex to ogc:Literal (bug 1644) - -- schemas.opengeospatial.net has been shutdown, use schemas.opengis.net - instead as the default schema repository for OGC services (bug 1873) - -- MIGRATION_GUIDE.TXT has been created to document backwards incompatible - changes between 4.8 and 4.10 - -- Modify mapgd.c to use MS_NINT_GENERIC to avoid rounding issues. (bug 1716) - -- added --disable-fast-nint configure directive (bug 1716) - -- Fixed php_mapscript Windows build that was broken in beta1 (bug 1872) - -- Supported tag in SLD label (Bug 1857) - -- Use the label element in the ColorMapEntry for the raster symbolizer - (Bug 1844) - -- Adding Geos functions to php mapscript (bug 1327) - -- Added a type cast to msio.i so as to eliminate the warning with the - SWIG unix/osx builds - -- Fixed csharp/Makefile.in for supporting the OSX builds and creating - the platform dependent mapscript_csharp.dll.config file. - -- Fixed error in detection of libpdf.sl in configure.in (bug 1868). - - -Version 4.10.0-beta1 (2006-08-17) ---------------------------------- - -- Marking the following SWIG object members immutable (bug 1803) - layerObj.metadata, classObj.label, classObj.metadata, - fontSetObj.fonts, legendObj.label, mapObj.symbolset, - mapObj.fontset, mapObj.labelcache, mapObj.reference, - mapObj.scalebar, mapObj.legend, mapObj.querymap - mapObj.web, mapObj.configoptions, webObj.metadata, - imageObj.format, classObj.layer, legendObj.map, - webObj.map, referenceMapObj.map - labelPathObj was made completely hidden (according to Steve's suggestion) - -- Fixed problem with PHP MapScript's saveWebImage() filename collisions - when mapscript was loaded in php.ini with PHP as an Apache DSO (bug 1322) - -- Produce warning in WFS GetFeature output if ???_featureid is specified - but corresponding item is not found in layer (bug 1781). Also produce - a warning in GetCapabilities if ???_featureid not set (bug 1782) - -- Removed the default preallocation of 4 values causing memory leaks. - (related to bug 1801) Added initValues to achieve the similar - functionality if needed. - -- Fixed error in msAddImageSymbol() where a symbol's imagepath was not - set (bug 1832). - -- Added INCLUDE capability in mapfile parser (bug 279) - -- Revert changes to mapzoom.i that swapped miny and maxy (Bug 1817). - -- MapScript (swig) creation of an outputFormatObj will now set the inmapfile - flag so that it gets written out to saved maps by default (Bug 1816). - -- Converted GEOS support to use the GEOS C-API (versiopn 2.2.2 and higher). - Wrapped remaining relevant GEOS functionality and exposed via SWIG-based - MapScript. - -- If a layer has wms_timedefault metadata, make sure it is applied even - if there is no TIME= item in the url. (Bug 1810) - -- Support for GEOS/ICONV/XML2 use flags in Java Makefile.in (related to - bug 1801) - -- Missing GEOS support caused heap corruption using shapeObj C# on linux - (Bug 1801) - -- Fix time filter propogation for raster layers to their tileindex layers. - New code in maprasterquery.c (bug 1809) - -- Added logic to collect LD_SHARED even if PHP not requested in configure. - -- Fix problems with msio/rfc16 stuff on windows. Don't depend on comparing - function pointers or "stdio" handles. (mapio.c, mapio.h, msio.i) - -- Support WMC Min/Max scale in write mode (bug 1581) - -- Fixed leak of shapefile handles (shp/shx/dbf) on tiled layers (bug 1802) - -- Added webObj constructor and destructor to swig interface with - calls to initWeb and freeWeb (bug 1798). - -- mapows.c: ensure msOWSDispatch() is always available even if there are - no services to dispatch. This makes mapscript binding easier. - -- FLTAddToLayerResultCache wasn't properly closing the layer after it - was done with it. - -- Added ability to encrypt tokens (passwords, etc.) in database connection - strings (MS-RFC-18, bug 1792) - -- Fixed zoomRectangle in mapscript: miny and maxy were swapped, making it - impossible to zoom by rect; also the error message was referring to the - wrong rect. There were no open issues on bugzilla. Reverted because of 1817. - -- Implementation of RFC 16 mapio services (bug 1788). - -- Use lp->layerinfo for OGR connections (instead of ogrlayerinfo) (bug 331) - -- Support treating POLYGONZ as MS_SHAPE_POLYGON. (bug 1784) - -- Complete support for international languages in Java Mapscript - (bug 1753) - -- Output feature id as @fid instead of @gml:id in WFS 1.0.0 / GML 2.1.2 - GetFeature requests (bug 1759) - -- Allow use of wms/ows_include_items and wms/ows_exclude_items to control - which items to output in text/plain GetFeatureInfo. Making the behavior - of this INFO_FORMAT consistent with the new behavior of GML GetFeatureInfo - output introduced in v4.8. (bug 1761) - IMPORTANT NOTE: With this change if the *_include_items metadata - is not specified for a given layer then no items are output for that layer - (previous behavior was to always all items by default in text/plain) - -- Make sure mappostgis.c closes MYCURSOR in layer close function so that - CLOSE_CONNECTION=DEFER works properly. (bug 1757) - -- Support large (>2GB) raster files relative to SHAPEPATH. (bug 1748) - -- Set User-Agent in HTTP headers of client WMS/WFS connections (bug 1749) - -- Detection of os-dependent Java headers for Java mapscript (bug 1209) - -- Preventing to take ownership of the memory when constructing objects - with parent objects using C# mapscript (causing nullreference exception, Bug 1743) - -- SWF: Adding format option to turn off loading movies automatically (Bug 1696) - -- Fixed FP exception in mapgd.c when pixmap symbol 'sizey' not set (bug 1735) - -- Added config file for mapping the library file so the DllImport - is looking for to its unix equivalent (Bug 1596) Thanks to Scott Ellington - -- Added /csharp/Makefile.in for supporting the creation of Makefile - during configuration with MONO/Linux (fix for bug 1595 and 1597) - -- Added C# typemaps for char** and outputFormatObj** - -- Support for dispatching multiple error messages to the MapScript interface (bug 1704). - -- Fix inter-tile "cracking" problem (Bug 1715). - -- OGC FILTER: Correct bug when generating an sql expression containing an escape - character. - -- Allow a user to set a PROCESSING directive for an SDE layer to specify - using the attributes or spatial index first. (bug 1708). - -- Cheap and easy way of fudging the boundary extents for msSDEWhichShapes - in the case where the rectangle is really a point (bug 1699). - -- Implement QUANTIZE options for GD/PNG driver (Bug 1690, Bug 1701). - -- WMS: Publish the GetStyles operation in the capabilities document. - -- PHP_MAPSCRIPT: Add antialias parameter in the style object (Bug 1685) - -- WFS: Add the possiblity to set wfs_maxfeatures to 0 (Bug 1678) - -- SLD: set the default color on the style when using default settings - in PointSymbolizer. (bug 1681) - -- Incorporate range coloring support for rasters (bug 1673) - -- Fixed mapthread.c looking for the unix compiler symbol rather than just - testing whether or not _WIN32 is defined for the usage of posix threads - because unix is not defined on compilers like GCC 4.0.1 for OS X. - -- Fixed the fuzzy brush support so that the transition between 1 pixel aa lines - and brushes is less obvious. The old code would not allow for a 3x3 fuzzy - brush to be built. (bug 1659) - -- Added missing mapscript function msConnPoolCloseUnreferenced() (bug 1661) - We need to make conn. pooling handling transparent to mapscript users - so that they do not have to call this function once in a while, for instance - by creating an evictor thread. - -- Added calls to msSetup/msCleanup() at MapScript load/unload time (bug 1665) - -- Reorganized nmake.opt to be more focused on functionality groups rather - than the propensity of a section to be edited. Default values are now - all set to be pointed at the MapServer Build Kit, which can be obtained - at http://hobu.stat.iastate.edu/mapserver/ - -- configure.in/Makefile.in: Use PROJ_LIBS instead of PROJ_LIB. PROJ_LIB - is sometimes defined in the environment, but points to $prefix/share/proj - not the proj link libraries. - -- Update Web Map Context to 1.1.0, add the dimension support. (bug 1581) - -- Support SLD body in context document. (bug 887) - -- When generating an ogc filter for class regex expressions, use - the backslah as the default escape character (Bug 1637) - -- Add connectiontype initialization logic when the layer's virtual - table is initialized (Bug 1615) - -- Added modulus operator to mapparser.y. - -- Added new support for [item...] tag in CGI-based templates (bug 1636) - -- Reverted behaviour to pre-1.61: - do not allow for use of the FILTERITEM attribute (bug 1629) - -- Treat classindex as an int instead of a char in resultCacheMemberObj to - prevent problems with more than 128 classes (bug 1633) - -- WMS : SLD / stretch images when using FE (Bug 1627) - -- Add gml:lineStringMember in GML2 MultiLineString geometry (bug 1569). - -- PHP : add shape->sontainsshape that uses geos lib (Bug 1623). - -- Move gBYTE_ORDER inside the pg layerinfo structure to allow for differently - byte ordered connections (bug 1587). - -- Fix the memory allocation bug in sdeShapeCopy (Bug 1606) - -- Fixed OGR WKT support (Bug 1614). - -- Added shapeObj::toWkt() and ms_shapeObjFromWkt() to PHP MapScript (bug 1466) - -- Finished implementation of OGR Shape2WKT function (Bug 1614). - -- Detect/add -DHAVE_VSNPRINTF in configure script and prevent systematic - buffer overflow in imagemap code when vsnprintf() not available (bug 1613) - -- Default layer->project to MS_TRUE even if no projection is set, to allow - geotransforms (nonsquare pixels, etc) to be applied (bug 1645). - -- Force stdin into binary mode on win32 when reading post bodies. (bug 1768) - - -Version 4.8.0-rc2 (2006-01-09) ------------------------------- - -- Commit fix for GD on win32 when different heaps are in use. (Bug 1513) - -- Correct bound reprojection issue with ogc filer (Bug 1600) - -- Correct mapscript windows build problem when flag USE_WMS_SVR was - not set (Bug 1529) - -- Fix up allocation of the SDE ROW_ID columns and how the functions that - call it were using it. (bug 1605) - -- Fixed crash with 3D polygons in Oracle Spatial (bug 1593) - - -Version 4.8.0-rc1 (2005-12-22) ------------------------------- - -- Fixed shape projection to recompute shape bounds. (Bug 1586) - -- Fixed segfault when copying/removing styles via MapScript. (Bug 1565) - -- Fixed segfault when doing attribute queries on layers with a FILTER already - set but with no FILTERITEM. - - -Version 4.8.0-beta3 (2005-12-16) --------------------------------- - -- Initialize properly variable in php mapscript (Bug 1584) - -- New support for pseudo anti-aliased fat lines using brushes with variable - transparency. - -- Arbitrary rotation support for vector symbols courtesy of Map Media. - -- Support for user-defined mime-types for CGI-based browse and legend - templates (bug 1518). - -- mapraster.c: Allow mapresample.c code to be called even if projections - are not set on the map or layer object. This is no longer a requirement. - (Bug 1562) - -- Fix problem with WMS 1.1.1 OGC test problem with get capabilites dtd - (Bug 1576) - -- PDF : adding dash line support (Bug 492) - -- Fixed configure/build problem (empty include dir) when iconv.h is not - found (bug 1419) - -- PDF : segfault on annotation layer when no style is set (Bug 1559) - -- PostGIS layer test cases and fix for broken views and sub-selects (bug 1443). - -- SDE: Removed (commented out) support for SDE rasters at this time. As far - as I know, I'm the only one to ever get it to work, it hasn't kept up with - the connection pooling stuff we did, and its utility is quite limited in - comparison to regular gdal-based raster support (projections, - resampling, etc) (HB - bug 1560). - -- SDE: Put msSDELayerGetRowIDColumn at the top of mapsde.c so things - would compile correctly. This function is not included (or necessary) - in the rest of the MS RFC 3 layer virtualization at this time. - -- WFS : TYPENAME is manadatory for GetFeature request (Bug 1554). - -- SLD : error parsing font parameters with the keyword "normal" (Bug 1552) - -- mapgraticule.c: Use MIN/MAXINTERVAL value when we define grid position and - interval (bug 1530) - -- mapdrawgdal.c: Fix bug with nodata values not in the color table when - rendering some raster layers (bug 1541). - -- mapogcsld.c : If a RULE name is not given, set the class name to "Unknown" - (Bug 1451) - -Version 4.8.0-beta2 (2005-11-23) --------------------------------- - -- Use dynamic allocation for ellipse symbol's STYLE array, avoiding the - static limitation on the STYLE argument values. (bug 1539) - -- Fix bug in mapproject.c when splitting over the horizon lines. - -- Fix Tcl mapscript's getBytes method (bug 1533). - -- Use mapscript.i in-place when building Ruby mapscript, copying not necessary - (bug 1528). - -- Expose maximum lengths of layer, class, and style arrays in mapscript (bug - 1522). - -- correct msGetVersion to indicate if mapserver was build with MYGIS support. - -- Fixed hang in msProjectRect() for very small rectangles due to round off - problems (bug 1526). - - -Version 4.8.0-beta1 (2005-11-04) --------------------------------- - -- Bug 1509: Fixed bounding box calculation in mapresample.c. The bottom right - corner was being missed in the calculation. - -- MS RFC 2: added OGR based shape<->WKT implementation. - -- mapgdal.c: fixed some mutex lock release issues on error conditions. - -- MS RFC 8: External plugin layer providers (bug 1477) - -- SLD : syntax error when auto generating external symbols (Bug 1508). - -- MS RFC 3: Layer vtable architecture (bug 1477) - -- wms time : correct a problem when hadling wms times with tile index rasters - (bug 1506). - -- WMS TIME : Add suuport for multiple interval extents (Bug 1498) - -- Removed deprecated --with-php-regex-dir switch (bug 1468) - -- support wms_attribution element for LAYER's (Bug 1502) - -- Correct php/mapscript bug : initialization of scale happens when - preparequery is called (Bug 1334). - -- msProjectShape() will now project the lines it can, but completely - delete lines that cannot be projected properly and "NULL" the shape if - there are no lines left. (Bug 411) - -- Expose msLayerWhichShapes and msLayerNextShape in MapScript. (bug 1481) - -- Added support to MapScript to change images in a previously defined - symbol. (bug 1471) - -- mapogcfiler.c : bug 1490. Crash when size of sld filters was huge. - -- Fixed --enable-point-z-m fix in configure.in (== -> =) (bug 1485). - -- Extra scalebar layer creation is prevented with a typo fix in mapscale.c. - Good catch, Tamas (bug 1480). - -- mapwmslayer.c : use transparency set at the layer level on wms client - layers (Bug 1458) - -- mapresample.c: added BILINEAR/AVERAGE resampling options. - -- mapfile.c: avoid tail recursion in freeFeatureList(). - -- maplegend.c: fixed leak of imageObj when embedding legends. - -- msGDALCleanup(): better error handler cleanup. - -- Modified msResetErrorList() to free the last error link too, to ensure - msCleanup() scrubs all error related memory. - -- Fix in msGetGDALGetTransform() to use default geotransform even if - GDALGetGeoTransform() fails but alters the geotransform array. - -- Typemaps for C# to enable imageObj.getBytes() method (bug 1389). - -- Enable -DUSE_ZLIB via configure for compressed SVG output (bug 1307). - -- maputil.c/msAddLine(): rewrite msAddLine() to call - msAddLineDirectly, and use realloc() in msAddLineDirectly() to optimize - growth of shapeObjs. (bug 1432) - -- msTmpFile: ensure counter is incremented to avoid duplicate - temporary filenames. (bug 1312) - -- SLD external graphic symbol format tests now for mime type - like image/gif instead of just GIF. (bug 1430) - -- Added support for OGR layers to use SQL type filers (bug 1292) - -- mapio/cgiutil - fixed POST support in fastcgi mode. (bug 1259) - -- mapresample.c - ensure that multi-band raw results can be - resampled. (bug 1372) - -- Add support in OGC FE for matchCase attribute on - PropertyIsEqual and PropertyIsLike (bug 1416) - -- Fixed sortshp.c to free shapes after processing to avoid major - memory leak. (bug 1418) - -- fixed msHTTPInit() not ever being called which prevented msHTTPCleanup() - from properly cleaning up cUrl with curl_global_cleanup(). (bug 1417) - -- mapsde.c: add thread locking in msSDELCacheAdd - -- fixed mappool.c so that any thread can release a connection, - not just it's allocator. (bug 1402) - -- mapthread.c/h: Added TLOCK_SDE and TLOCK_ORACLE - not used yet. - -- Fixed copying of layer and join items. (bug 1403) - -- Fixed copying of processing directives within copy of a layer. (bug 1399) - -- Problems with string initialization. (bug 1312) - -- Fix svg output for multipolygons. (bug 1390) - -- Added querymapObj to PHP MapScript (bug 535) - - -Version 4.6.0 (2005-06-14) --------------------------- - -- Bug 1163 : Filter Encoding spatial operator is Intersects - and not Intersect. - -- Fixed GEOS to shapeObj for multipolgon geometries. - - -Version 4.6.0-rc1 (2005-06-09) ------------------------------- - -- Bug 1375: Fixed seg fault in mapscript caused by the USE_POINT_Z_M flag. - This flag was not carried to the mapscript Makefile(s). - -- Bug 1367: Fixed PHP MapScript's symbolObj->setPoints() to correctly - set symbolObj->sizex/sizey - -- Bug 1373: Added $layerObj->removeClass() to PHP MapScript (was already - in SWIG MapScript) - - -Version 4.6.0-beta3 (2005-05-27) --------------------------------- - -- Bug 1298 : enable Attribution element in wms Capabilities XML - -- Bug 1354: Added a regex wrapper, allowing MapServer to build with PHP - compiled with its builtin regex - -- Bug 1364: HTML legend templates: support [if] tests on "group_name" in - leg_group_html blocks, and for "class_name" in leg_class_html blocks. - -- Bug 1149: From WMS 1.1.1, SRS are given in individual tags in root Layer - element. - -- First pass at properly handling XML exceptions from CONNECTIONTYPE WMS - layers. Still needs some work. (bug 1246) - -- map.h/mapdraw.c: removed MAX/MIN macros in favour of MS_MAX/MS_MIN. - -- Bug 1341, 1342 : Parse the unit parameter for DWithin filter request. - Set the layer tolerance and toleranceunit with paramaters parsed. - -- Bug 1277 : Support of multiple logical operators in Filter Encoding. - -- mapwcs.c: If msDrawRasterLayerLow() fails, ensure that the error message - is posted as a WCS exception. - -- Added experimental support for "labelcache_map_edge_buffer" metadata to - define a buffer area with no labels around the edge of a map (bug 1353) - - -Version 4.6.0-beta2 (2005-05-11) --------------------------------- - -- Bug 179 : add a small buffer around the cliping rectangle to - avoid lines around the edges. - -- Finished code to convert back and forth between GEOS geometries. Buffer and - convex hull operations are exposed in mapscript. - -- fontset.fonts hash now exposed in mapscript (bug 1345). - -- Bug 1336 : Retreive distance value for DWithin filter request - done with line and polygon shapes/ - -- Bug 985 / 1015: Don't render raster layers as classified if none of - the classes has an expression set (gdal renderer only). - -- Bug 1344: Fixed several issues in writing of inline SYMBOLS when saving - mapfile (missing quotes around CHARACTER and other string members of SYMBOL - object, check for NULLs, and write correct identifiers for POSITION, - LINECAP and LINEJOIN). - - -Version 4.6.0-beta1 (2005-04-26) --------------------------------- - -- Bug 1305: Added support for gradient coloring in class styles - -- Bug 1335 : missing call to msInitShape in function msQueryByShape - -- Bug 804 : SWF output : Make sure that the layer index is consistent - when saving movies if some of the layers are not drawn (because the - status is off or out of scale ...) - -- Bug 1332 - shptreevis.c: fixed setting of this_rec, as the output dbf - file was not getting any records at all. - -- Fixed Makefile.vc to make .exe files depend on the DLL, so if the DLL - fails to build, things will stop. Avoids the need for unnecessary - cleans on win32. Also fixed the rule for MS_VERSION for mapscriptvars. - -- Bug 1262 : the SERVICE parameter is now required for wms and wfs - GetCapbilities request. It is not required for other WMS requests. - It is required for all WFS requests. - -- Bug 1302 : the wfs/ows_service parameter is not used any more. The - service is always set to WFS for WFS layers. - -- Bug 791: initialize some fields in msDBFCreate() - avoids crashes in - some circumstances. - -- Bug 1329 : Apply sld named layer on all layers of the same group - -- Bug 1328 : support style's width parameter for line and polygon layers. - -- Bug 564: Fixed old problem with labels occasionally drawn upside down - -- Bug 1325: php mapscript function $class->settext needs only 1 argument. - -- Bug 1319: Fixed mutex creation (was creator-owned) in mapthread.c. win32 - issue only. - -- Bug 1103: Set the default tolerance value based on the layer type. - The default is now 3 for point and line layers and 0 for all the others. - -- Bug 1244: Removing Z and M parameter from pointObj by default. A new - compilation option is available to active those option --enable-point-z-m. - This gives an overall performance gain around 7 to 10%. - -- Bug 1225: MapServer now requires GD 2.0.16 or more recent - -- MapScript: shapeObj allocates memory for 4 value strings, shapeObj.setValue() - lets users set values of a shapeObj. - -- MapScript: imageObj.getBytes() replaces imageObj.write() (bugs 1176, 1064). - -- Bug 1308: Correction of SQL expression generated on wfs filters for - postgis/oracle layers. - -- Bug 1304: Avoid extra white space in gml:coordinates for gml:Box. - -- mapogr.c: Insure that tile index reading is restarted in - msOGRLayerInitItemInfo() or else fastcgi repeat requests for a layer may - fail on subsequent renders. - -- mapogr.c: Set a real OGRPolygon spatial filter, not just an OGRLinearRing. - Otherwise GEOS enabled OGR builds will do expensive, and - incorrect Intersects() tests. - -- mapogr.cpp / mapprimitive.c: Optimize msAddLine() and add msAddLineDirectly() - -- mapprimitive.c: Optimizations in msTransformShapeToPixel() (avoid division) - -- map.h: Made MS_NINT inline assembly for win32, linux/i86. - -- mapprimitive.c: optimized msClipPolygonRect and msClipPolylineRect for - case where the shape is completely inside the clip rect. - -- Add support for SVG output. See Bug 1281 for details. - -- Bug 1231: use mimetype "image/png; mode=24bits" for 24bit png format. - This makes it seperately selectable by WMS. - -- Bug 1206: Applied locking patch for expression parser for rasters. - -- Bug 1273: Fixed case in msProjectPoint() were in or out are NULL and - a failure occurs to return NULL. Fixed problem of WMS capabilities with - 'inf' in it. - -- SLD generation bug 1150 : replacing tag to - -- Fixed bug 1118 in msOWSGetLayerExtent() (mapows.c). - -- Fixed ogcfilter bug #1252 - -- Turned all C++ (//) comments into C comments (bug 1238) - -- mapproject.h/configure.in: Don't check for USE_PROJ_API_H anymore. Assume - we have a modern PROJ.4. - -- Bug 839: Fix memory leak of font name in label cache (in mapfile.c). - -- Added msForceTmpFileBase() and mapserv -tmpbase switch to allow overriding - temporary file naming conventions. Mainly intended to make writing - testscripts using mapserv easier. FrankW. - -- maporaclespatil.c: Bug fix for: #1109, #1110, #1111, #1112, #1136, #1210, - #1211, #1212, #1213. Support for compound polygons, fixed internal sql to - stay more accurate for geodetic data, added the support for getextent - function. Added VERSION token for layer data string. - -- mapimagemap.c: Preliminary implementation of support for emitting - MS_SYMBOL_VECTOR symbols in msDrawMarkerSymbolIM(). - -- Bug 1204: Added multi-threading support in mapthread.c. List of connections - is managed within a mutex lock, and connections are only allowed to be used - by one thread at a time. - -- Bug 1185 : php/mapscript : add constant MS_GD_ALPHA - -- Bug 1173: In HTML legend, added opt_flag support for layer groups. - -- Bug 1179: added --with-warnings configure switch, overhauled warning logic. - -- Bug 1168: Improve autoscaling through classification rounding issues. - -- Fixed bug writing RGB/RGBA images via GDAL output on bigendian systems. - -- Bug 1152 : Fix WMS style capabilities output for FastCGI enabled builds. - -- Bug 1135 : Added support for rotating labels with the map if they were - rendered with some particular angle already. - -- Bug 1143 : Missing call to msInitShape. - -- Fixed PHP5 support for windows : Bug 1100. - -- Correct bug 1151 : generates twice a tag when generating an SLD. - This was happening the style did not have a size set. - -- Oracle Spatial. Fixed problem with LayerClose function. Added token NONE - for DATA statement. Thanks Valik with the hints about the LayerClose problem - and Francois with the hints about NONE token. - -- numpoints and stylelength memebers of the symbol object needs to be in sync - with the low level values after calles to setpoints ans setstyle (Bug 1137). - -- Use doubles instead of integers in function php3_ms_symbol_setPoints - (Bug 1137). - -- Change the output of the expression when using a wild card for - PropertyIsLike (Bug 1107). - -- Delete temporary sld file created on disk (Bug 1123) - -- Fixed msFreeFileCtx() to call free() instead of gdFree() as per bug 1125. - Also renamed gdFreeFileCtx() to msFreeFileCtx(). - -- Ensure error stack is cleared before accepting another call in FastCGI - mode in mapserv.c. Bug 1122 - -- Support translation of all geometry types to points in mapogr.cpp (now - also supports multipolygon, multilinestring and geometrycollection. - bug 1124. - -- Added support for passing OGR layer FILTER queries down to OGR via the - SetAttributeFilter() method if prefixed with WHERE keyword. Bug 1126. - -- Fixed support for SIZEUNITS based scaling of text when map is rotated. - Bug 1127. - - -Version 4.4.0 (2004-11-29) --------------------------- - -- Fixed WMS GetCapabilities 1.1.0 crash when wms_style_<...>_legendurl_* - metadata were used (bug 1096) - -- WCS GetCapabilities : Added ResponsibleParty support. - -- WMS GetCapabilities : Service online resource was not url encoded (bug 1093) - -- Fixed php mapscript problem with wfs_filter selection : Bug 1092. - -- Fixed encoding problem with WFS server when wfs_service_onlineresource - was not explicitly specified (bug 1082) - -- Add trailing "?" or "&" to connection string when required in WFS - client layers using GET method (bug 1082) - -- Fixed : SLD rasters was failing when there was Spatial Filter (Bug 1087) - -- Fixed mapwfslayer.c build error when WFS was not enabled (bug 1083) - -- Check that we have vsnprintf in mapimagemap.c before using it. - - -Version 4.4.0-beta3 (2004-11-22) --------------------------------- - -- Added tests to mimimize the threat of recursion problems when evaluating - LAYER REQUIRES or LABELREQUIRES expressions. Note that via MapScript it - is possible to circumvent that test by defining layers with problems - after running prepareImage. Other things crop up in that case too (symbol - scaling dies) so it should be considered bad programming practice - (bug 1059). - -- Added --with-sderaster configure option. - -- Make sure that msDrawWMSLayerLow calls msDrawLayer instead of - msDrawRasterLayerLow directly ensuring that some logic (transparency) that - are in msDrawLayer are applied (bug 541). - -- Force GD/JPEG outputFormatObjects to IMAGEMODE RGB and TRANSPARENT OFF - if they are RGBA or ON. Makes user error such as in bug 1703 less likely. - -- Advertize only gd and gdal formats for wms capabilities (bug 455). - -- Pass config option GML_FIELDTYPES=ALWAYS_STRING to OGR so that all GML - attributes are returned as strings to MapServer. This is most efficient - and prevents problems with autodetection of some attribute types (bug 1043). - -- msOGCWKT2ProjectionObj() now uses the OGRSpatialReference::SetFromUserInput() - method. This allows various convenient setting options, including the - ability to handle ESRI WKT by prefixing the WKT string with "ESRI::". - -- Fixed GetLegendGraphic in WMS Capabilities that were missing the '?' - or '&' separator if it was not included in wms_onlineresource (bug 1065). - -- Updated WMS/WFS client and server code to lookup "ows_*" metadata names - in addition to the default "wms_*" (or "wfs_*") metadatas (WCS was already - implemented this way). This reduces the amount of duplication in mapfiles - that support multiple OGC interfaces since "ows_*" metadata can be used - almost everywhere for common metadata items shared by multiple OGC - interfaces (bug 568). - -- Added ows_service_onlineresource metadata for WMS/WFS to distinguish - between service and GetMap/Capabilities onlineresources (bug 375). - -- Added map->setSize() to PHP MapScript (bug 1066). - -- Re-enabled building PHP MapScript using PHP's bundled regex/*.o. This is - needed to build in an environment with PHP configured as an Apache DSO - (bugs 990, 520). - -- Fixed problem with raster dither support on windows (related to ascii - encoding pointers) (bug 722). - -- Moved PHP/SWIG MapScript layer->getExtent() logic down to msLayerGetExtent() - to avoid code duplication (bug 1051). - -- Added SDE Raster drawing support (experimental). - -- HTML legends: Added [leg_header_html] and [leg_footer_html] (bug 1032). - -- Added "z" support in SWIG MapScript for pointObj (bug 871). - -- In PHP Mpascript when using ms_newrectobj, the members minx, miny, - maxx, maxy are initialized to -1 (bug 788). - -- Write out proper world file with remote WMS result, it was off by half - a pixel (bug 1050). - -- Send a warning in the wms capabilities if the layer status is set - to default (bug 638). - -- Fixed PHP MapScript compile warnings: dereferencing type-punned pointer - will break strict-aliasing rules (bug 1053). - -- Added $layer->isVisible() to PHP MapScript (bug 539). - -- Ported $layer->getExtent() to PHP MapScript (bug 826). - -- wms_group_abstract can now be used in the capabilities (bug 754). - -- If wms_stylelist is an empty string, do not output the tag - for MapContexts (bug 595). - -- Avoid passing FILE* to GD library by utilizing GD's gdIOCtx interface - (bug 1047). - -- Output warning in wms/wfs capabilities document if layer,group,map names have - space in them (bug 486, bug 646). - -- maporaclespatial.c: fixed declarations problems (bug 1044). - -- Allow use of msOWSPrintURLType with no metadata. In this case the default - parameters will be used (bug 1001). - -- Ensure the outputFormatObj attached to msImageLoadGDStream() results reflect - the interlacedness of the loaded image. Also ensure that the RGB PNG - reference images work (make imagemode match gdImg) (bug 1039). - -- Fixed support for non-square pixels in WCS (bug 1014). - -- Expose only GD formats for GetLegendGraphic in the capabilities (bug 1001). - -- Check for supported formats when process a GetLegendGraphic request - (bug 1030). - -- mapraster.c: fixed problem with leaks in tileindexed case where the - tile index is missing (bug 713). - -- Oracle Spatial: implemented connection pool support for Oracle Spatial. - New layer data parameters to support query functions, added - "using unique ". Added "FILTER", "RELATE" and "GEOMRELATE" - parameters, now permit users to choose the Oracle Spatial Filter. Modified - the internal SQL to always apply FILTER function. And improve the Oracle - Spatial performance. - -- Centralize "stdout binary mode setting" for win32 in msIO_needBinaryStdout(). - Use it when writing GDAL files to stdout in mapgdal.c. Fixes problems with - output of binary files from GDAL outputformat drivers on win32 via WMS/WCS. - -- MapServer now provides one default style named (default), title and - LegendURL when generating capabilities. Added also the possibility to use - the keyword default for STYLES parameter when doing a GetMap - (..&STYLES=default,defeault,...) (bug 1001). - -- Add xlink:type="simple" in WMS MetadataURL (bug 1027). - - -Version 4.4.0-beta2 (2004-11-03) --------------------------------- - -- free mapServObj properly in mapserv.c in OWS dispatch case to fix minor - memory leaks. - -- modified msCloseConnections() to also close raster layers so that - held raster query results will be freed. - -- modified raster queries to properly set the classindex in the resultcache. - -- modified msDrawQueryCache() to be very careful to not try and lookup - information on out-of-range classindex values. This seems to occur when - default shapes come back witha classindex of 0 even if there are no classes. - (ie. raster query results). - -- the loadmapcontext function has changed it behaviour. Before the 4.4 relase - when loading layers from a map context, the layer name was built using - a unique prefix + the name found in the context (eg for the 2nd layer in - map context named park, the layer name generated would possibly be l:2:park). - Now the loadmapcontext takes a 2nd optional argument to force the creation - of the unique names. The default behaviour is now to have the layer name - equals to the name found in the context file (bug 1023). - -- Fixed problem with WMS GetCapabilities aborting when wms_layer_group is - used for some layers but not for all (bug 1024). - -- Changed raster queries to return the list of all pixel values as an - attribute named "value_list" rather than "values" to avoid conflict with - special [values] substitution rule in maptemplate.c. - -- Fixed raster queries to reproject results back to map projection, and to - do point queries distance checking against the correct projection (bug 1021). - -- Get rid of WMS 1.0.8 support. It's not an officially supported verison - of the spec anyway: it's synonymous for 1.1.0 (bug 1022). - -- Allow use of '=' inside HTML template tag parser (bug 978). - -- Use metadata ows_schema_location for WMS/WFS/WCS/SLD (bugs 999, 1013, 938). - The default value if metadata is not found is - http://schemas.opengeospatial.net. - -- Generate a RULE tag when generating an SLD (bug 1010). - -- WMS GetLegendGraphic uses now the RULE value to return an icon for - a class that has the same name as the RULE value (bug 843). - -- Add msOWSPrintURLType: This funciton is a generic URL printing fuction for - OGC specification metadata (WMS, WFS, WCS, WMC, etc.) (bug 944). - -- Support MetadataURL, DataURL and LegendURL tags in WMS capabilities - document and MetadataURL in WFS capabilities. - -- SWIG mapscript: clone methods for layerObj, classObj, styleObj (bug 1012). - -- Implemented an intarray helper class for SWIG mapscript which allows for - multi-language manipulation of layer drawing order (bugs 853, 1005). - -- Fixed WMS GetLegendGraphic which was returning an exception (GD error) - when requested layer was out of scale (bug 1006). - -- Fixed maplexer.l to work with flex 2.5.31 (bug 975). - -- WMS GetMap requests now have MS_NONSQUARE enabled by default. This means - that if the width/height ratio doesn't match the extent's x/y ratio then - the map is stretched as stated in the WMS specification (bug 862). - -- In WMS, layers with no explicit projection defined will receive a copy - of the map's projectionObj if a new SRS is specified in the GetMap request - or if MS_NONSQUARE is enabled. This will prevent the problem with layers - that don't show up in WMS request when the server administrator forgets - to explicitly set projections on all the layers in a WMS mapfile (bug 947). - -- Implemented FastCGI cleanup support for win32 and unix in mapserv.c. - -- Solved configure/compile issues with libiconv (bugs 909, 1017). - - -Version 4.4.0-beta1 (2004-10-21) --------------------------------- - -- "shared" compilation target now supports some kind of versioning, - should at least prevent libmap.so version collisions when upgrading - MapServer on a server (bug 982). - -- When no RULE parameter has been specified in the WMS request - a legend should be returned with all classes for the specified LAYER. - Changes has been made in mapwms.c (bug 653). Also if the SCALE parameter - is provided in the WMS request is will be used to determine whether - the legend of the specified layer should be drawn in the case that the - layer is scale dependant (big 809). - -- Nested layers in the capabilities are supported by using a new metadata - tag WMS_LAYER_GROUP (bug 776). - -- Added greyscale+alpha render support if mapdrawgdal.c (bug 965). - -- Added --with-fastcgi support to configure. - -- support OGC mapcontext through mapserver cgi (bug 946). - -- support for reading 3d shape file (z) (bug 869). - -- add php mapscript functions to expose the z element (bug 870). - -- imageObj::write() method for SWIG mapscript (bug 941). - -- Protect users from 3 potential sources of threading problems: parsing - expression strings outside of msLoadMap, evaluating mapserver logical - expressions, and loading symbol set files outside of msLoadMap (bug 339). - -- Various fixes allowing unit tests to run leak free under valgrind on - i686. Memory is now properly freed when exiting from common error - states (bug 927). - -- Restored ability to render transparent (indexed or alpha) pixmap symbols - on RGB map images, including annotation layers and embedded scalebars. - This feature remains OFF by default for map layers and is enabled by - specifying TRANSPARENCY ALPHA (bugs 926, 490). - -- mapserv_fcgi.c removed. Committed new comprehensive FastCGI support. - -- New mapserver exceptions for Java mapscript thanks to Umberto Nicoletti - (bug 895). - -- Removed mapindex.c, mapindex.h, shpindex.c components of old unused - shapefile indexing method. - -- Use the symbol size instead of 1 for the default style size value. This is - done by setting the default size to -1 and adding msSymbolGetDefaultSize() - everywhere to get the default symbolsize (Bug 751). - -- Correct Bug with GML BBOX output when using a with a - GetFeature request (Bug 913). - -- Encode all metadatas and mapfile parameters outputed in a xml document - (Bug 802). - -- Implement the ENCODING label parameter to support internationalization. - Note this require the iconv library (Bug 858). - -- New and improved Java mapscript build provided by unicoletti@prometeo.it - and examples by Y.K. Choo (bug 876). - -- MapContext: Cleanup code to make future integration more easily and output - SRS and DataURL in the order required by the spec. - -- Fixed issue with polygon outline colors and brush caching (bug 868). - -- New C# mapscript makefiles and examples provided by Y.K. Choo - committed under mapscript/csharp/ (bug 867). - -- Renamed 'string' member of labelCacheMemberObj to 'text' to avoid - conflicts in SWIG mapscript with C# and Java types (bug 852). - -- Fixed Bug 866 : problem when generating an sld on a pplygon layer - -- SWIG mapscript: map's output image width and height should be set - simultaneously using new mapObj::setSize() method. This performs - necessary map geotransform computation. Direct setting of map width - and height is deprecated (bug 836). - -- Fixed bug 832 (validate srs value) : When the SRS parameter in a GetMap - request contains a SRS that is valid for some, but not all of the layers - being requested, then the server shall throw a Service Exception - (code = "InvalidSRS"). Before this fix, mapserver use to reproject - the layers to the requested SRS. - -- Fixed bug 834: SE_ROW_ID in SDE not initialized for unregistered SDE tables - -- Fixed bug 823 : adding a validation of the SRS parameter when doing - a GetMap request on a wms server. Here is the OGC statement : - 'When the SRS parameter in a GetMap request contains a SRS - that is valid for some, but not all of the layers being requested, - then the server shall throw a Service Exception (code = "InvalidSRS").' - -- Set the background color of polygons or circles when using transparent - PIXMAP symbol. - -- SWIG mapscript class extensions are completely moved from mapscript.i - into separate interface files under mapscript/swiginc. - -- Overhaul of mapscript unit testing framework with a comprehensive test - runner mapscript/python/tests/runtests.py. - -- Modified the MS_VALID_EXTENT macro to take an extent as its argument - instead of the quartet of members. MapServer now checks that extents input - through the mapfile are valid in mapfile.c (web, map, reference, - and layer). Modified msMapSetExtent in mapobject.c to use the new - macro instead of its home-grown version. Modified all cases that used - MS_VALID_EXTENT to the new use case. - -- Layers now accept an EXTENT through the mapfile (bug 786). Nothing - is done with it at this point, and getExtent still queries the - datasource rather than getting information from the mapfile-specified - extent. - -- Fixed problem with WMS GetFeatureInfo when map was reprojected. Was a - problem with msProjectRect and zero-size search rectangles (bug 794) - -- MapServer version now output to mapscriptvars and read by Perl Makefile.PL - and Python setup.py (bug 795). - -- Map.web, layer, and class metadata are exposed in SWIG mapscript as - first-class objects (bug 737). - -- Add support for spatial filters in the SLD (Bug 782) - -- A few fixes to allow php_mapscript to work with both PHP4 and PHP5. - PHP5 support should still be considered experimental. (bug 718) - -- Fixed SDE only recognizing SE_ROW_ID as the unique column (bug 536). - The code now autosenses the unique row id column. - -- Enhanced SDE support to include support for queries against - user-specified versions. The version name can be specified as the - last parameter of the CONNECTION string. - -- Fixed automated generation of onlineresource in OWS GetCapabilities - when the xxx_onlineresource metadata is not specified: the map= parameter - used to be omitted and is now included in the default onlineresource if - it was explicitly set in QUERY_STRING (bug 643) - -- Fixed possible crash when producing WMS errors INIMAGE (bug 644) - -- Fixed automated generation of onlineresource in OWS GetCapabilities - when the xxx_onlineresource metadata is not specified: the map= parameter - used to be omitted and is now included in the default onlineresource if - it was explicitly set in QUERY_STRING (bug 643) - -- Fixed an issue with annotation label overlap. There was an issue with - the way msRectToPolygon was computing it's bounding box. (bug 618) - -- Removed "xbasewohoo" debug output when using JOINs and fixed a few - error messages related to MySQL joins (bug 652) - -- Fixed "raster cracking" problem (bug 493) - -- Improvements to Makefile.vc, and nmake.opt so that a mapscriptvars file - can be produced on windows. - -- Updated setup.py so Python MapScript builds on win32. - -- Added preliminary raster query support. - -- No more Python-stopping but otherwise benign errors raised from - msDrawWMSLayer() (bug 650). - -- Finished prototyping all MapServer functions used by SWIG-Mapscript - and added 'void' to prototypes of no-arg functions, eliminating all - but two SWIG-Mapscript build warnings (bug 658). - -- Mapscript: resolved issue with pens and dynamic drawing of points (bug 663). - -- Mapscript: fixes to tests of shape copying and new image symbols. - -- Mapscript: new OWSRequest class based on cgiRequestObj structure in - cgiutil.h is a first step to allow programming with MapServer's OWS - dispatching (bug 670). - -- Mapscript: styles member of classObj structure is no longer exposed to - SWIG (bug 611). - -- Implementation geotransform/rotation support in cgi core, and mapscript.i. - -- Testing: fixed syntax error, 'EPSG' -> 'epsg' in test.map (bug 687). - Added an embedded scalebar which demonstrates that bug 519 is fixed. - The test data package is also made more complete by including two fonts - from Bitstream's open Vera fonts (bug 694). - -- Mapscript (SWIG): remove promote and demote methods from layerObj. Use - of container's moveLayerUp/moveLayerDown is better, and this brings - the module nearer to PHP-Mapscript (bug 692). - -- mapogr.cpp: Now echos CPLGetLastErrorMsg() results if OGR open fails. - -- mapraster.c: fixed tile index corruption problem (bug 698) - -- Mladen Turk's map copying macros in mapcopy.h clean up map cloning and - allow for copying of fontset and symbolset. Added cloning tests in - python/tests/testCloneMap.py and refactored testing suite (bugs 640 & 701). - -- Mapscript: removing obsolete python/setup_wnone.py file. - -- CONFIG MS_NONSQUARE YES now enables non-square pixel mode (mostly for WMS). - Changes in mapdraw.c (msDrawMap()) to use the geotransform "hack" to allow - non-square pixels. - -- When using the text/html mime type in a GetFeature request, if the - layer's template is not set to a valid file, errors occur. - Correction is : the text/html is not advertized by default and - will only be advertized if the user has defined - "WMS_FEATURE_INFO_MIME_TYPE" "text/html" (bug 736) - -- Make PHP MapScript's layer->open() produce a PHP Warning instead of a - Fatal error (bug 742) - -- MapServer hash tables are now a structure containing a items pointer - to hashObj. See maphash.h for new prototypes of hash table functions. - In SWIG mapscript, Map, Layer, and Class metadata are now instances of the - new hashTableObj class. fontset.fonts and Map.configoptions are also - instances of hashTableObj. The older getMetaData/setMetaData and - metadata iterator methods can be deprecated (bug 737). - -- Mapscript-SWIG: made the arguments of mapObj and layerObj constructors - optional. A layerObj can now exist outside of a map and can be added - to a mapObj using the insertLayer method. mapObj.removeLayer now - returns a copy of the removed Layer rather than an integer (bug 759). - -- Fixed $map->processTemplate() which was always returning NULL. - Bug introduced in version 4.0 in all flavours of MapScript (bug 410) - - -Version 4.2-beta1 (2004-04-17) ------------------------------- - -- Added support for WMS 1.1.1 in the WMS interface. - -- Added support for WMS-SLD in client and server mode. - -- Added support for attribute filters in the WFS interface. - -- WMS Interface: several fixes to address issues found in running tests - against the OGC testsuite. One of the side-effects is that incomplete - GetMap requests that used to work in previous versions will produce - errors now (see bug 622). - -- Modified configure scripts to be able to configure/build PHP MapScript - using an installed PHP instead of requiring the full source tree. - -- Added ability to combine multiple WMS connections to the same server - into a single request when the layers are adjacent and compatible. (bug 116) - -- Support POSTed requests without Content-Length set. - -- Added support for proper classification of non-8bit rasters. - -- Added support for BYTE rawmode output type. - -- Added support for multiple bands of output in rawmode. - -- MySQL joins available - -- Fixed problems with detection of OGRRegisterAll() with GDAL 1.1.9 in - configure due to GDAL's library name change. Fixed a few other minor - issues with GDAL/OGR in configure. - -- Modified configure to disable native TIFF/PNG/JPEG/GIF support by default - if GDAL is enabled. You can still enable them explicitly if you like. - -- Replace wms_style_%s_legendurl, wms_logourl, wms_descriptionurl, wms_dataurl - and wms_metadataurl metadata by four new metadata by metadata replaced. The - new metadata are called legendurl_width, legendurl_height, legendurl_format, - legendurl_href, logourl_width, etc... - Old dependancy to the metadata with four value in it , space separated, are - not kept. - -- Implement DataURL, MetadataURL and DescriptionURL metadata in - mapcontext.c (bug 523) - -- PHP MapScript's pasteImage() now takes a hex color value (e.g. 0xrrggbb) - for the transparent color instead of a color index. (bug 463) - -- OGR data sources with relative paths are now checked relative to - SHAPEPATH first, and if not found then we try again relative to the - mapfile location. (bug 295) - -- There is a new mapObj parameter called MAXSIZE to control maximum image - size to serve via the CGI and WMS interfaces. The default is 2048 as - before but it can be changed in the map file now. (bug 435) - -- Added simple dataset for unit and regression tests (bug 453) - -- PostGIS: added postresql_NOTICE_HANDLER() sending output via msDebug() - and only when layer->debug is set (bug 418) - -- Added Apache version detection in configure and added non-blocking flag - on stderr in msDebug() to work around Apache 2.x bug (bug 458) - -- MapScript rectObj: added optional bounding value args to constructor and - extended rectObj class with a toPolygon method (bug 508). - -- MapScript pointObj: added optional x/y args to constructor (bug 508). - -- MapScript colorObj: added optional RGB color value args to colorObj - constructor, and extended colorObj class with setRGB, setHex, and toHex - methods. The hex methods use hex color strings like '#ffffff' rather - than '0xffffff' for compatibility with HTML (bug 509). - -- MapScript outputFormatObj: extended with a getOption method (bug 510). - -- MapScript imageObj: added optional mapObj argument to the save method - resolving bug 549 without breaking current API. Also added optional - driver and filename arguments to constructor which allows imageObj - instances to be created with a specified driver or from files on disk - (bug 530). Added new code to Python MapScript which extends the - filename option to Python file-like objects (bug 550). This means - StringIO and urllib's network objects! - -- MapScript classObj and styleObj: added a new styleObj shadow class and - extended classObj with getStyle, insertStyle, and removeStyle methods. - MapScript now supports multiple styles for dynamically created classes - (bug 548). - -- MapScript layerObj: added getExtent, getNumFeatures extension methods, - allowing getShape to access inline features (bug 562). - -- Added fixes for AMD64/Linux in configure (bug 565) - -- Removed OGR_STATIC stuff in configure script that used to allow us to - build with OGR statically by pointing to the OGR source tree. That - means you can only build with OGR when *installed* as part of GDAL, - but that's what everyone is doing these days anyway. - -- Mapscript outputFormatObj: extended constructor to allow format names, - and mapObj methods to append and remove output formats from the - outputformatlist (bug 511). - -- New SWIG mapscript development documentation in the spirit of the - PHP-Mapscript readme file, but using reST (bug 576). - -- Paving way for future changes to SWIG mapscript API with new features - enabled by NEXT_GENERATION_API symbol (bug 586). - -- Added ability to set string member variables to NULL in PHP MapScript - (bug 591) - -- New key iterators for map, layer, and class metadata hash tables - (bug 434) and fontset fonts hash table (bug 439). - -- Fixed potential crash when using nquery with a querymap enabled and - some layers have a template set at the layer level instead of inside - classes (bug 569). - -- New CONFIG keyword in the MAP object in a .map file to be used - to set external configuration parameters such as PROJ_LIB and control - of some GDAL and OGR driver behaviours (bug 619) - -Version 4.0 (2003-08-01) ------------------------- - -- Fixed problem with truncated expressions (bugs 242 and 340) - -- Attempt at fixing GD vs libiconv dependency problems (bug 348) - -- Fixed problem with invalid BoundingBox tag in WMS capabilities (bug 34) - -- Fixed problems with SIZEUNITS not working properly (bug 373) - -- Fixed MacOSX configure problems for linking php_mapscript (bug 208) - -- Fixed problem with reference map marker symbol not showing up (bug 378) - -- Use in WMS 1.0.0 capabilities instead of (bug 129) - -- One-to-one and one-to-many joins now work for Xbase files and are available - to query templates. Low level one-to-one Xbase joins are available via - OGR. - -Version 4.0-beta2 (2003-07-11) ------------------------------- - -- Added prototype of FastCGI support in mapserv_fcgi.c (not built by default). - -- Report full error stack in the mapserv CGI and PHP MapScript (bug 346) - -- Old index (.qix) format is deprecated (bug 273) - -- Fixed problem with embedded legend and scalebar that would result in - layers being added to the HTML legends (bug 171) - -- Changed joins (XBase only at this point) over to the open-prepare-next... - next-close way of doing things. Compiles fine, but needs more testing. - One-to-many support should work now but it needs to be hooked into the - template code yet. Last thing before a candidate 4.0 release. - -- Added ability to generate images in MapScript processQueryTemplate (bug 341) - -- Added saving of output formats in msSaveMap() - -- Fixed problem in PHP MapScript with variables that were not dereferenced - before their values were changed by the MapScript wrappers (bug 323) - -- Added support for Web Map Context 1.0.0 - -- Treat zero-length template values as NULL so that it's possible to - set("template", "") from MapScript to make layer non-queryable (bug 338) - -- Ditched the shapepath argument to the shapefileObj constructor - -- CARTOLINE join style default changed to MS_CJC_NONE - -- Tweaked code in legend builder to handle polygon layers slightly different. - Now if a polygon layer contains only outlines and no fills (i.e. a polyline) - then it is drawn using the zigzag legend shape rather than the box. I'll - add legend outlines back in shortly. - -- Restored legend key outlines (triggered by setting OUTLINECOLOR). If an - outline is requested then line symbols are clipped to the outline, - otherwise lines are allowed to bleed a pixel or two beyond those - boundaries- for most cases this looks fine but for fat lines it is - gonna look goofy regardless. In those cases use the KEYIMAGE. - -- Fixed a bug in the scanline writer so that x coordinates can be in any - order when passed in to the function. (bug 336) - -- Updated loadExpressionString in mapfile.c to be a bit more tolerant of - input. Now if a string does not match the logical or regex pattern it is - automatically cast as a string expression. Removes the need for silly quotes. - - -Version 4.0-beta1 (2003-06-06) ------------------------------- - -- Added imagemap outputformat, which makes possible use of client-side - imagemaps in browsers. - -- Added MySQL support for non-spatial OpenGIS Simple Features SQL stored data - -- msQueryByShape and msQueryByFeature honor layer tolerances. In effect you - can to buffered queries now. At the momoment only polygon select features - are supported, but there's nothing inherent in the underlying computations - that says lines won't work as well. - -- Simple one-to-one joins are working again. Reworked the join code so that - table connections are persistant within a join (across joins is a todo). - Joins, like layers are wrapped with a connection neutral front end, that - sets us up to do MySQL or whatever in addition to XBase. - -- Removed shapepath argument to all layer access functions (affects MapScript). - It's still used but we leverage the layer pointer back to the parent mapObj - so the API is cleaner. - -- Changed default presentation of feature attributes to escape a few - problematic characters for HTML display (eg. > becomes >). - Added [itemname_raw] substitution to allow access to unaltered data. - -- Added initial version of Jan Hartman's connection pooling code. - -- Replaced libwww with libcurl for WMS/WFS client HTTP requests. - (libcurl 7.10 required, see http://curl.haxx.se/libcurl/c/) - -- Added CONNECTION to the list of mapfile parameters that can accept - %variable% substitutions when processed by the cgi version. This is useful - for passing in username and/or passwords to database data sources. - -- Added support for DATA and TEMPLATE (header/footer/etc...) filtering using - an regex declared in the mapfile (DATAPATTERN and TEMPLATEPATTERN). - Certain parameters in a mapfile cannot be changed via a URL without first - being filtered. - -- Added support for enviroment variable MS_MAPFILE_PATTERN. This allows you to - override the default regex in favor of one more restrictive (I would hope) of - your own. - -- Disabled CGI SAVEMAP option. - -- Removed CGI TEMPLATE option since you can use the map_web_template syntax. - Simplifies security maintenance by only having to deal with this option - in a single place. - -- Added offset support (styleObj) for raster based output (GD for sure, not - quite sure how OGR output is created although I believe is uses GD anyway). - This allows for feature drop shadows and support for cool linear symbols - like used to be supported in pre-3.4 versions. These offsets are not - scalable at the moment. - -- Null shapes (attributes but no vertices) are skipped for shapefiles using - the msLayerNextShape interface. Otherwise applications should check the - shapeObj type member for MS_SHAPE_NULL. - -- Changed where label cache is allocated and cleared. Now it isn't allocated - until drawing takes place. Any old cache is cleared before a new one is - allocated. The cache is still intact following rendering for post-processing - using MapScript. - -- Fixed screw up in pre-processing of logical expressions for item lists. - Under certain circumstances that list could get corrupted and expressions - would fail. - -- Added NOT operator to expression parser. - -- Added layer and map level DEBUG options to map file. - -- Major changes to support vector output (PDF, SWF, GML, ...): - imageObj is used by all rendering functions instead of gdImagePtr, - New msSaveImage() prototype - -- Support for GD-2.0, including 24 bits output. Dropped support for GD 1.x - -- Support for output to any GDAL-supported format via the new OUTPUTFORMAT - object. - -- New styleObj to replace the OVERLAY* parameter in classes. - -- PostGIS: Added Sean Gillies 's patch for "using unique - ". Added "using SRID=#" to specify a spatial reference - for an arbitrary sql query. - -- ... and numerous fixes not listed here... - - -Version 3.6.0-beta1 (2002-04-30) --------------------------------- - -- MapScript: qitem and qstring params added to layer->queryByAttribute(). - Instead of being driven by the layer's FILTER/FILTERITEM, the query by - attribute is now driven by the values passed via qitem,qstring, and the - layer's FILTER/FILTERITEM are ignored. - -- Symbol and MapFile changes: ANTIALIAS and FILLED keywords now take a - boolean (TRUE/FALSE) argument i.e. ANTIALIAS becomes ANTIALIAS TRUE - and FILLED becomes FILLED TRUE - -- Reference Map: - Added options to show a different marker when the reference box becomes - too small. See the mapfile reference docs for more details on the new - reference object parameters (MARKER, MARKERSIZE, MAXBOXSIZE, MINBOXSIZE) - -- Added MINSCALE/MAXSCALE at the CLASS level. - -- Support for tiled OGR datasets. - -- PHP 4.1.2 and 4.2.0 support for PHP MapScript. - -- Added LAYER TRANSPARENCY, value between 1-100 - -- Fixes to the SWIG interface for clean Java build. - -- New HTML legend templates for CGI and MapScript. See HTML-Legend-HOWTO. - -- WMS server now supports query results using HTML query templates instead - of just plain/text. - -- Added support functions for thread safety (--with-thread). Still not - 100% thread-safe. - - -Version 3.5.0 (2002-12-18) --------------------------- - -- No Revision history before version 3.5 - diff --git a/HISTORY.md b/HISTORY.md new file mode 100644 index 0000000000..d8efefc185 --- /dev/null +++ b/HISTORY.md @@ -0,0 +1,4794 @@ +MapServer Revision History +========================== + +This is a human-readable revision history which will attempt to document +required changes for users to migrate from one version of MapServer to the +next. Developers are strongly encouraged to document their changes and +their impacts on the users here. (Please add the most recent changes to +the top of the list.) + +For a complete change history, please see the Git log comments. For more +details about recent point releases, please see the online changelog at: +https://mapserver.org/development/changelog/ + +The online Migration Guide can be found at https://mapserver.org/MIGRATION_GUIDE.html + +8.6.4 release (2026-06-01) +-------------------------- + +- security: properly escape mapserv_onlineresource in OpenLayers viewer with WMS (#7517) + +- security: PostGIS: make sure identifier value is numeric when the declared type is numeric too (#7516) + +8.6.3 release (2026-05-07) +-------------------------- + +- security: fix out of bounds access on SLD with only a Rule with a ElseFilter but without a symbolizer (#7497) + +- Oracle: revert change regarding case insensitive ogc filters (#7493) + +- Oracle: revert change regarding adding subquery to apply sortBy before rownum paging (#7491) + +8.6.2 release (2026-04-19) +-------------------------- + +- security: only allow SRS or CRS parameters for OpenLayers template (#7480) + +- fix segmentation fault in PHP MapScriptNG (#7471) + +see detailed changelog for other fixes + +8.6.1 release (2026-03-23) +-------------------------- + +- security: fix potential heap buffer overflow (#7461) + +- No longer depend on GDAL's cpl_port.h MIN/MAX/ABS macros (#7438) + +see detailed changelog for other fixes + +8.6.0 release (2025-12-03) +-------------------------- + +- CI: upgrade PCRE2 to 10.47 release (#7400) +(see major changes below) + +8.6.0-rc1 release (2025-11-27) +------------------------------ + +- OGCAPI: return OGC-NumberReturned, OGC-NumberMatched and Link HTTP headers (#7390) + +- output GDAL files: fix from init=epsg:xxxx layers (#7392) + +8.6.0-beta2 release (2025-11-18) +-------------------------------- + +- additional URL creation logic for generated index URLs (#7388) + +8.6.0-beta1 release (2025-11-13) +-------------------------------- + +- allow append of additional query parameters for OGCAPI: Features (#7360) + +- new MapServer index page (#7350) + +- WMS GetFeatureInfo: add options to precisely identify points through their symbols (#7318) + +- add FALLBACK parameter for CLASS object, to be applied if none of the previously defined classes has been applied (#7309) + +- add vendorSpecificParameters to OpenAPI document (#7295) + +see detailed changelog for other fixes + +8.4.1 release (2025-09-19) +-------------------------- + +- security: add missing column name escaping for WFS filters through OGR (#7349) + +- fix opacity for gradient legend symbol (#7255) + +see detailed changelog for other fixes + +8.4.0 release (2025-01-15) +-------------------------- + +- add CITATION.cff, useful for Zenodo/DOI (#7209) +(see major changes below) + +8.4.0-rc1 release (2025-01-08) +------------------------------ + +- include stdbool.h in mapserver.h (#7205) + +8.4.0-beta2 release (2024-12-14) +-------------------------------- + +- add explicit error message when proj.db cannot be found (#7203) + +8.4.0-beta1 release (2024-12-13) +-------------------------------- + +- add PCRE2 support (#7073) + +- add CONNECTIONTYPE RASTERLABEL (#7135) + +- set MS_LEGEND_KEYSIZE_MAX to 1000 (#7154) + +- add 4 new COMPOSITE.COMPOP blending operations (#7065) + +- allow encryption key files to use paths relative to a mapfile (#7181) + +- allow use_default_extent_for_getfeature to be used for OGC Features API and PostGIS (#7197) + +see detailed changelog for other fixes + +8.2.2 release (2024-09-02) +-------------------------- + +- fix build against FreeType 2.13.3 release (#7142) + +see detailed changelog for other fixes + +8.2.1 release (2024-07-21) +-------------------------- + +- security: validate tostring() expression function (#7123) + +- handle PHP MapScript out of source builds (#7108) + +7.6.7 release (2024-07-21) +-------------------------- + +- security: validate tostring() expression function (#7123) + +8.2.0 release (2024-07-08) +-------------------------- + +RC3 was released as the final 8.2.0 (see major changes below) + +8.2.0-rc3 release (2024-06-28) +------------------------------ + +- fix memory corruption in msUpdate...FromString (#7038) + +8.2.0-rc2 release (2024-06-27) +------------------------------ + +- fix SWIG MapScript build failure (#7090) + +8.2.0-rc1 release (2024-06-14) +------------------------------ + +- no changes since beta3 (see major changes below) + +8.2.0-beta3 release (2024-06-11) +-------------------------------- + +- security fix to prevent SQL injections through regex validation (#7075) + +7.6.6 release (2024-06-11) +-------------------------- + +- security fix to prevent SQL injections through regex validation (#7075) + +8.2.0-beta2 release (2024-06-08) +-------------------------------- + +- fix Python MapScript installation (#7071) + +8.2.0-beta1 release (2024-06-06) +-------------------------------- + +- restructure repo to move source code into /src (#6837) + +- remove sym2img.c from codebase (#6593) + +- handle templates + includes (#6113) + +- handle empty query response (#6907) + +- remove support for GDAL < 3 (#6901) + +- remove support for PROJ < 6 (#6900) + +- OGC API Features: implement Part 2 - CRS (#6893) + +- allow custom projections to be requested via WMS (#6795) + +- allow mapfiles to be accessed via URL Keys (#6862) + +- allow expressions in LABEL PRIORITY (#6884) + +- reference SLD files in Mapfiles (#7034) + +see detailed changelog for other fixes + +8.0.1 release (2023-04-17) +-------------------------- + +- fix WFS paging on Oracle (#6774) + +- allow runtime substitutions on the Web template parameter (#6804) + +- handle multiple PROJ_DATA paths through config (#6863) + +see detailed changelog for other fixes + +8.0.0 release (2022-09-12) +-------------------------- + +RC2 was released as the final 8.0.0 (see major changes below) + +8.0.0-rc2 release (2022-09-05) +------------------------------ + +- fix !BOX! token not working for a PostGIS connection (#6601) + +- check if a LAYER has a NAME, before including it in a GROUP (#6603) + +8.0.0-rc1 release (2022-08-19) +------------------------------ + +- add missing include to fix build issue on some compilers (#6595) + +- update the distributed mapserver-sample.conf (#6598) + +8.0.0-beta2 release (2022-08-09) +-------------------------------- + +- install coshp utility (#6540) + +- improve error messages about missing mandatory metadata (#6542) + +- fix reprojection of lines crossing the antimeridian (#6557) + +- config file parsing: use msSetPROJ_LIB() when ENV PROJ_LIB is set (#6565) + +- handle PROJ_DATA as well as PROJ_LIB (#6573) + +- reset layer filteritem to its old value in case of no overlap (#6550) + +8.0.0-beta1 release (2022-06-27) +-------------------------------- + +- add new MapServer config file requirement (RFC 135) + +- initial OGC API support (RFC 134) + +- rename shp2img utility to map2img (RFC 136) + +- make STYLES parameter mandatory for WMS GetMap requests (#6012) + +- improve SLD label conformance (#6017) + +- enable PHP 8 MapScript support, through SWIG, re-enable unit tests, and remove old native PHP MapScript (#6430) + +- remove deprecated mapfile parameters (RFC 133) + +- improve numerical validation of mapfile parameter values (#6458) + +- fix various security vulnerabilities found by libFuzzer (#6419) + +- add new GEOMTRANSFORM 'centerline' labeling method for polygons (#6417) + +- upgrade Travis and GitHub CI to run on Ubuntu Focal (#6430) + +7.6.5 release (2023-04-17) +-------------------------- + +- remove password content from logs (#6621) + +- increase security and stability (#6818) + +see detailed changelog for other fixes + +7.6.4 release (2021-07-12) +-------------------------- + +- improved performance of GPKG and SpatiaLite queries (#6361) + +- WFS: fix paging with GPKG/Spatialite datasources and non-point geometries (#6325) + +- PostGIS: use ST_Intersects instead of && for bounding box (#6348) + +see detailed changelog for other fixes + +7.6.3 release (2021-04-30) +-------------------------- + +- fix security flaw for processing the MAP parameter (#6313) + +- fix code defects through Coverity Scan warnings (#6307) + +- add support for PROJ 8 (#6249) + +see detailed changelog for other fixes + +7.6.2 release (2020-12-07) +-------------------------- + +- No major changes, see detailed changelog for bug fixes + +7.6.1 release (2020-07-31) +-------------------------- + +- No major changes, see detailed changelog for bug fixes + +7.6.0 release (2020-05-08) +-------------------------- + +- for essential WMS client layers set EXCEPTIONS to XML by default (#6066) + +7.6.0-rc4 release (2020-05-04) +------------------------------ + +- Fix case insensitive 'using unique' for PostGIS connections (#6062) + +- Add handling essential WMS layers (#6061) + +7.6.0-rc3 release (2020-04-24) +------------------------------ + +- Handle special characters in paths on Windows (#5995) + +- Add attribute binding for label ALIGN, OFFSET, POSITION (#6052) + +7.6.0-rc2 release (2020-04-10) +------------------------------ + +- Fix memory corruption in msGEOSGetCentroid (#6041) + +7.6.0-rc1 release (2020-04-05) +------------------------------ + +- Fix alpha value for hex colors (#6023) + +7.6.0-beta2 release (2020-03-28) +-------------------------------- + +- fixed build with PHPNG + gnu_source (#6015) + +- fixed rendermode with geomtransform (#6021) + +7.6.0-beta1 release (2020-03-22) +-------------------------------- + +- Full support for PROJ6 API (#5888) + +- Enable PointZM data support (X,Y,Z,M coordinates) by default + +- SLD support enhancements (RFC 124) except PR#5832 + +- CONNECTIONOPTIONS support in mapfile LAYER (RFC 125) + +- Enforce C99 and C++11 build requirements (RFC 128) + +7.4.4 release (2020-3-20) +------------------------- + +- Security release, see ticket #6014 for more information. + +7.4.3 release (2019-12-16) +-------------------------- + +- No major changes, see detailed changelog for bug fixes + +7.4.2 release (2019-9-13) +------------------------- + +- No major changes, see detailed changelog for bug fixes + +7.4.1 release (2019-7-12) +------------------------- + +- No major changes, see detailed changelog for bug fixes + +7.4.0 release (2019-5-14) +------------------------- + +- No major changes, see detailed changelog for bug fixes + +7.4.0-rc2 release (2019-5-10) +---------------------------- + +- No major changes, see detailed changelog for bug fixes + +7.4.0-rc1 release (2019-5-1) +---------------------------- + +- No major changes, see detailed changelog for bug fixes + +7.4.0-beta2 release (2019-4-17) +------------------------------- + +- Addresses XSS issue with [layers] template tag (fix available in 6.4, 7.0 and 7.2 branches as well) + +- Added Perl/Mapscript to Travis CI + +- No other major changes, see detailed changelog for bug fixes + +7.4.0-beta1 release (2019-3-29) +------------------------------- + +- Python MapScript binding is available as installable Wheels with a full test suite and examples + +- C# MapScript binding is now compatible with .NET Core + +- PHP 7 MapScript binding support - both PHP/MapScript and Swig/MapScript + +- Added workaround to allow compiling against Proj 6 (#5766) + +7.2.2 release (2019-2-19) +-------------------------- + +- No major changes, see detailed changelog for bug fixes + +7.2.1 release (2018-10-1) +-------------------------- + +- No major changes, see detailed changelog for bug fixes + +7.2.0 release (2018-07-23) +-------------------------- + +- Fixed issue with ring handling with polygons in MVT support (#5626) + +- No other major changes, see detailed changelog for bug fixes + +7.2.0-beta2 release (2018-6-13) + +- Update beta1 release notes to remove reference to PHP7 support + +- No other major changes, see detailed changelog for bug fixes + +7.2.0-beta1 release (2018-5-9) +------------------------------ + +- Support for Enhanced Layer Metadata Management (RFC82) + +- Calculate MINDISTANCE from label bounds instead of label center (#5369) + +- Reposition follow labels on maxoverlapangle colisions (RFC112) + +- Implement chainable compositing filters (RFC113) + +- Faster retrieval of shape count (RFC114) + +- WMS layer groups are now requestable + +- Support C-style multi-line content types (#5362) + +- Python 3.x support (#5561) + +- Support Vendor-Specific OGC FILTER parameter in WMS requests (RFC118) + +- Mapbox Vector Tile (MVT) Support (RFC119) + +- INSPIRE download service support for WCS 2.0 (RFC120) + +7.0.0 release (2015/07/24) +-------------------------- + +- No major changes, see detailed changelog for bug fixes + +7.0.0-beta2 release (2015/06/29) +-------------------------------- + +- No major changes, see detailed changelog for bug fixes + +7.0.0-beta1 release (2015/02/12) +-------------------------------- + +- RFC91 Layer Filter Normalization + +- Implement WCS20 Extensions (#4898) + +- Require validation of ExternalGraphic OnlineResource (#4883) + +- Require validation on the CGI queryfile parameter. (#4874) + +- Apply RFC86 scaletoken substitutions to layer->PROCESSING entries + +- RFC113 Layer Compositing Pipeline + +- RFC109 Optimizing Runtime Substitutions + +- RFC108 Heatmap / Kernel-Density Layers + +- RFC106 Support of Geomtransform JavaScript Plugin + +- RFC105 Support for WFS 2.0 (server side) + +- RFC104 Bitmap Label removal, replaced with inlined truetype font + +- RFC103 Layer Level Character Encoding + +- RFC102 Support of Styleitem JavaScript Plugin + +- RFC99 GD removal + +- RFC98 Complex Text Rendering / Text Rendering Overhaul + +- RFC93 UTF Grid Support + +6.4 release (2013/09/17) +--------------------------- + +- RFC 101: Support for Content Dependent Legend Rendering + +- Add Support for librsvg as an alternative to libsvg-cairo + +- RFC100: Add support for raster tile index with tiles of mixed SRS (TILESRS keyword) + +- RFC94: Shape Smoothing + +- RFC95 : add EXPRESSION {value1,value2,...} support to parser (#4648) + +- RFC92: Migration from autotools to cmake (#4617) + +- RFC88: Saving MapServer Objects to Strings (#4563) + +- RFC90: Enable/Disable Layers in OGC Web Services by IP Lists + +- RFC85,89 Added Simplify,SimplityPT and Generalize geomtransform, implementation of + geomtransform at the layer level + +- RFC86: Scale-dependant token replacements (#4538) + +- Fix symbol scaling for vector symbols with no height (#4497,#3511) + +- Implementation of layer masking for WCS coverages (#4469) + +- Implementation of offsets on follow labels (#4399) + +6.2.0 release (git branch-6-2) 2012/11/14: +------------------------------------------ + +- Fix WFS GetFeature result bounds are not written in requested projection (#4494) + +- Fixed wrong size in LegendURL of root layer (#4441) + +- Fixed wms_style_name in GetMap requests (#4439) + +- Fix segfault in queryByFilter function in MapScript + +- Adjusted WCS 2.0 to WCS Core 2.0.1 and GMLCOV 1.0.1 corrigenda (#4003) + +- Adjusted mediatype to multipart/related in WCS 2.0 (#4003) + +- Fix symbolObj.getImage seg fault in PHP/MapScript + +- Fix bad handling of startindex in some drivers (#4011) + WFSGetFeature also now uses a global maxfeatures and startindex to support + maxfeatures across layers rather than within layers + +- Fixed bugs with WCS 1.1/2.0 with VSIMEM (#4369) + +- Add notable changes here. Less important changes should go only in the + commit message and not appear here. + +- Fixed the OGR driver to use point or line spatial filter geometries in degenerated cases (#4420) + +- implement OFFSET x -99 on ANGLE FOLLOW labels (#4399) + +Version 6.2 (beta1: 20120629): +------------------------------ + +- Fix WFS filter is produced as non-standard XML (#4171) + +- Fix pixmap symbol loading issue (#4329) + +- Added INSPIRE ExtendedCapabilities and DOCTYPE definition to WMS 1.1.1 (#3608) + +- Fix wms_enable_request-related errors are not properly tagged (#4187) + +- Fixed "msGetMarkerSize() called on unloaded pixmap symbol" in mapsymbol.c (#4225) + +- Fixed PHP MapScript support for PHP 5.4 (#4309) + +- Fix msOGREscapeSQLParam could return random data (#4335) + +- Fixed locations of supported and native formats in Capabilities and CoverageDescriptions for WCS 2.0 (#4003) + +- Made format parameter for WCS 2.0 GetCoverage requests optional (#4003) + +- Swig mapscript for multi-label support (#4310) + +- Fix creation of a vector symbolObj in mapscript (#4318) + +- Added coverage metadata in WCS (#4306) + +- Ignore unknown requets parameteres in WCS 2.0 (#4307). + +- Fixed getFeature request with custom output format fails on filter encoding (#4190) + +- Fixed resolution when UoM changes in WCS 2.0 (#4283) + +- Added missing DEFRESOLUTION parameter to msCopyMap() function (#4272) + +- Migrated svn to git, and issue tracking from trac to github + +- Fixed mapscript is unusable in a web application due to memory leaks (#4262) + +- Fixed legend image problem with annotation layers with label offsets (#4147) + +- Add support for multiple labels per feature (RFC81) + +- Add support for INSPIRE view service (RFC 75) + +- Drop support for GDAL/OGR older than 1.5.0 (#4224) + +- PDF backend: add support for generating geospatial PDF, when + GDAL 2.0 with PDF driver is used, and the GEO_ENCODING FORMATOPTION + (set to ISO32000 or OGC_BP) is added to the OUTPUTFORMAT definition. (#4216) + +- Python mapscript: fix swig mappings to work with both python 2.5.and 2.6 (#3940) + +- Added classgroup CGI parameter support (#4207) + +- Java mapscript: renamed shared library and completed libtool support (#2595) + +- Fixed WCS 2.0 axis order (#4191) + +- Added MS_CJC_* constants in PHP/MapScript (#4183) + +- Fixed Memory Leak with Fribidi Strings (#4188) + +- Allow multiple label definitions within a class (RFC 77/#4127) + +- shp2img: make it possible to specify layers (with -l option) that match GROUP names. + +- reuse a pre-parsed mapfile across fastcgi loops in case the mapfile is + specified with the MS_MAPFILE env variable. (#4018) + +- Ability to do use PropertyIsLike with a column of a different type than text (postgis) (#4176) + +- Fixed SLD with FILTER doesn't apply properly to database layers (#4112) + +- Fixed lexer buffer size issue with single quotes in a string (#4175) + +- WFS Quote Escape issue (#4087) + +- Raster layer fails to be drawn if the window is less than half a pixel (#4172) + +- shptree: Improvement to reduce size of .qix files (#4169) + +- avoid potential gd fontcache deadlock on fastcgi exit signals(#4093) + +- Adjusted WCS GetCapabilities for an empty list of layers (#4140) + +- Adjusted WMS GetCapabilities for an empty list of layers (#3755) + +- Refactor cgi masperv to not call exit on argument errors (#3099) + +- Add --with-apache-module configure option to build an apache dso module + (#2565) + +- Use libtool to build object files and libraries + +- Dynamically link libmapserver to the created binaries by default + (requires the make install step to be run) + +- Python mapscript builds with make instead of setuptools + +- Fix LABELPNT geomtransform position for non-cached labels (#4121) + +- Add RFC80 font fallback support (#4114) + +- Added POLAROFFSET style option for a different symbol transform (#4117) + +- automatically translate vector symbol points (#4116) + +- Add RFC79 Layer masking (#4111) + +- Fixed single pixel coverages in WCS 2.0 (#4110) + +- Add svg symbols support (#3671) + +- Fixed subsetting in WCS 2.0 (#4099) + +- Upgrade clipper library to 4.6.3 + +- Make openlayers wms template request images with mimetype of outputformat + defined in the mapfile's imagetype + +- Fix memory leak in msSLDParseRasterSymbolizer() + +- Fix compilation error with clang in renderers/agg/include/agg_renderer_outline_aa.h + +- Add stable hatch rendering (#3847) + +- Added vector field rendering (#4094) + +- Add wms dimensions support (#3466) + +- Fixed segfault when calling classObj::updateFromString() with SYMBOL (#4062) + +- Use a renderer native follow text implementation if available. + +- Fixed layer with inline feature to support multiple classes (#4070) + +- Add support for rfc45 anchorpoint on marker symbols (#4066) + +- Add initial gap support for line marker symbols (#3879) + +- Fix center to center computation of gaps for line marker symbols + and polygon tile patterns (#3867) + +- Add initial gap support for line patterns (#3879) + +- Fixed grid of thin lines in polygon symbol fills (#3868) + +- Fixed cannot add a style to a label in PHP/SWIG Mapscript (#4038) + +- Fixed schema validity issue for WCS 1.1 GetCoverage responses (#4047) + +- remove default compiler search paths from the GD CFLAGS/LDFLAGS (#4046) + +- Fixed Python Mapscript does not write COLOR to reference map (#4042) + +- Added XMP support for metadata embedding, RFC 76, (#3932) + +- Added GetLegendGraphic Cascading support (#3923) + +- Rewrite postgres TIME queries to take advantage of indexes (#3374) + +- Unified OWS requests and applied to WCS (defaults to version 2.0 now) (#3925) + +- WCS 1.0: Fix crash with some _rangeset_axes values (#4020) + +- WCS 2.0: Adjusted offset vector and origin (#4006) + +- Added addParameter() method to MapScript (#3973) + +- Changed msDrawVectorLayer() not to cache shapes if attribute binding is present after the first style (#3976) + +- Fix mapscript to build when TRUE macro is not defined (#3926) + +- Fix mapscript php build issues with MSVC (#4004) + +- PHP MapScript is missing many styleObj properties (#3901) + +- PHP/Mapscript: Segmentation fault when getting complex object using PHP 5.2 (#3930) + +- PHP/Mapscript: Fixed webObj->metadata returns a webObj (#3971) + +- WCS 1.1: Added check for imageCRS in msOWSCommonBoundingBox() (#3966) + +- Fixed contains operator in logical expressions (#3974) + +- WCS 1.0: WCS Exceptions raise mapscript exceptions (#3972) + +- WMS: LAYERS parameter is optional when sld is given (#1166) + +- Add runtime substitution for "filename" output format option (#3571) and + allow setting defaults in either metadata or validation (preferred) blocks + for both layer and output format. + +- Add non antialiased text rendering for GD (#3896) + +- Fixed OGC filter using expressions (#3481) + +- Fix incorrect rendering of GD lines between 1 and 2 pixels wide (#3962) + +- Add gamma correction to AGG polygon rendering (#3165) + +- Initialize the scalebar image color to transparent by default (#3957) + +- Do not divide by zero in io read/write funcs (#4135) + +IMPORTANT SECURITY FIX: + +- Fixes to prevent SQL injections through OGC filter encoding (in WMS, WFS + and SOS), as well as a potential SQL injection in WMS time support. + Your system may be vulnerable if it has MapServer with OGC protocols + enabled, with layers connecting to an SQL RDBMS backend, either + natively or via OGR (#3903) + +- Fix performance issue with Oracle and scrollable cursors (#3905) + +- Fix attribute binding for layer styles (#3941) + +- Added missing fclose() when writing query files (#3943) + +- Fix double-free in msAddImageSymbol() when filename is a http resource (#3939) + +- Fix rendering of lines with outlinewidth set if not on first style (#3935) + +- Correct SLD with spatial filters bbox and intersects (#3929) + +- Applied patch for ticket (symbol writing issues) (#3589) + +- Added WMS GetFeatureInfo Cascading (#3764) + +- Fixed png lib is not found on multiarch systems (#3921) + +- Fixed PHP MapScript opacity property of StyleObj no longer works (#3920) + +- Fixed Using STYLEITEM AUTO, loadExpression fails when the label text + contains a space or begins with a double quote (#3481) + +- Fix for the cluster processing if the shape bounds doesn't overlap + with the given extent (#3913) + +- Add support for dashes on polygon hatches (#3912) + +- Union layer 3 new processing options added (#3900) + +- Changed msRemoveStyle to allow removing all styles (#3895) + +- Fixed mssql2008 to return correct geometries with chart layer type (#3894) + +- Ensure msLayerSetProcessingKey() supports setting a NULL value to clear + a processing key. + +- Write SYMBOLSET/END tags when saving a symbol file (#3885) + +- Make java threadtests work again (#3887) + +- Fix segfault on malformed filters (#3888) + +- Fixed the query handling problem with the Oracle spatial driver (#3878) + +- Fixed potential crash with AVERAGE resampling and crazy reprojection (#3886) + +- Adjusted OperationsMetadata for POST in WCS 2.0 GetCapabilities response + +- Fix for the warnings in mapunion.c (#3880) + +- SLD: correct when same layer is used with multiple styles (#1602) + +- Fixed the build problem in mapunion.c (#3877) + +- Implement to get all shapes with the clustered layer (#3873) + +- Union layer: Fixed the crash when styling source layers using attributes (#3870) + +- Added GEOS difference operator to expression support (#3871) + +- Improve rangeset item checking so that Bands=1,2,3 is supported with WCS 1.0 + (#3919). + +- Fix GetMapserverUnitUsingProj() for proj=latlong (#3883) + +- Add support for OGR output of 2.5D geometries (#3906) + + +Version 6.0.0 (2011-05-11) +-------------------------- + +- apply fix for #3834 on legend icon rendering (#3866) + +- Union layer: Fixed a potential seg fault in msUnionLayerNextShape (#3859) + +- Cluster layer: Fixed the problem when returning undefined attribute (#3700) + +- Union layer: Fix for the item initialization at the source layer (#3859) + +- Union layer: Fixed the potential seg fault when STYLEITEM AUTO is used (#3859) + +Version 6.0.0-rc2 (2011-05-05) +------------------------------ + +- Fixed seg fault with [shpxy] tag... (#3860) + +- Removed obsolete msQueryByOperator() function + +- Call msLayerClose() before msLayerOpen() in the various query + functions (#3692) + +- Fix WMS 1.3.0 to use full list of epsg codes with inverted axis (#3582) + +- PHP/Mapscript: Added getResultsBounds() method in layer object (#2967) + +- Fix SLD containing a PropertyIsLike filter (#3855) + +- Fixed msUnionLayerNextShape to return correct values (#3859) + +- Union layer: fix for the failure if one or more of the source layers + are not in the current extent (#3858) + +- Fix memory leak in msResampleGDALToMap() (#3857) + +- Fix missing initialization of default formats in WCS 1.x. + +- Fix maxoverlapangle when value is set to 0 (#3856) + +Version 6.0.0-rc1 (2011-04-27) +------------------------------ + +- Fix for the styleitem handling with union layer (#3674) + +- Fixed mindistance label test to check layer indexes. (#3851) + +- Fixed segmentation fault in PHP/MapScript and improved the php object + method calls (#3730) + +- Fix build issue related to unnecessary use of gdal-config --dep-libs (#3316) + +Version 6.0.0-beta7 (2011-04-20) +-------------------------------- + +- Union Layer: fix for the STYLEITEM AUTO option (#3674) + +- Union Layer: Add support for the layer FILTER expressions, + add "Union:SourceLayerVisible" predefined attribute (#3674) + +- fix circle layer drawing for edge case when point1.x==point2.x (#1356) + +- fix incorrect quantization for images with very large number of + colors (#3848) + +- fix poor performance of polygon hatching (#3846) + +- upgrade clipper library to 4.2 (related to #3846) + +- Fix configure output for "WFS Client" (was reporting WMS info, #3842) + +- KML: latlon bbox for raster layers could end up being wrong for non-square + requests (#3840) + +Version 6.0.0-beta6 (2011-04-13) +-------------------------------- + +- define EQUAL/EQUALN macros if cpl_port.h was not included (#3844) + +- add configurable PNG/ZLIB compression level (#3841) + +- SLD: use pixmap size when parameter size is not specified (#2305) + +- fix memory leaks in mapgraticule.c (#3831) + +- fix runtime sub validation against web metadata, was using wrong lookup key + +- clean up the symbolset if we've used an alternate renderer for a + layer (#3834,#3616) + +- fix crash on embedded legend with cairo raster renderer + +- fix crashes in SVG renderer on polygon symbol fills (#3837) + +- fix crash/corruptions with raster layers in pdf outputs (#3799) + +- fix memory leak in msFreeLabelCacheSlot (#3829) + +- use a circle brush for wide GD lines (#3835) + +- fix segmentation fault with transparent layers containing symbols (#3834) + +- fix memory leak on tiled vector polygons + +- fix segfault with marker symbols on short lines (#3823) + +- wms_getmap_formatlist causes first defined outputformat to be returned by + getmap (#3826) + +- fix building of mapcluster.c when OGR support is disabled + +- fix some valgrind found memory leaks (offset symbols, and gd io contexts) + +- skip marker symbol with no defined SYMBOL (caused some memory leaks with + uninitialized vector points) + +- fix crash in GD lines with floating point dash patterns (#3823) + +- Check renderer before using it when calculating label size (#3822) + +- allow palette file path to be relative to mapfile (#2115) + +- use supplied offset for brushed lines (#3825, #3792) + +- fix division by 0 error in bar charts for some ill-defined cases (#3218) + +- add GAP, POSITION and CAPS/JOINS to mapfile writer (#3797) + +- fix GEOMTRANSFORM rotation orientation for vector symbols (#3802) + +- GD Driver broken in FastCGI (#3813) + +- configure: look for libexslt.so under lib64 as well + +- Coding style and formatting fixes (#3819, #3820, #3821, and more) + +- More improvements to OpenGL error handling (#3791) + +- Added WMS GetFeatureInfo RADIUS=bbox vendor-specific option (#3561) + +Version 6.0.0-beta5 (2011-04-06) +-------------------------------- + +- Fix setting of top-level mapObj member variables in PHP MapScript (#3815) + +- More robust OpenGL context creation on older video cards and drivers (#3791) + +- Allow users to set the maximum number of vector features to be drawn (#3739) + +- Fixed FCGI on Windows problem related to lexer (#3812) + +- KML: Add ows/kml_exclude_items (#3560) + +- Removed all refs left to MS_SYMBOL_CARTOLINE (#3798) + +- Removed GAP, PATTERN, LINECAP/JOIN and POSITION from symbolObj (#3797) + +- Fixed handling of STYLEITEM AUTO label position codes 10,11,12 (#3806) + +- Fixed msGEOSGeometry2Shape to handle 'GEOMETRYCOLLECTION EMPTY' + as null geometry instead of raising an error (#3811) + +- Re-added the MYSQL JOIN support. Had been removed with the MYGIS + deprecated driver. + +- Add opacity to legend (#3740) + +- Updated PHP/MapScript with the new objects properties (#3735) + +- KML: set layer's projection when it is not defined (#3809) + +- Updated xml mapfile schema and xsl with the new lexer properties (#3735) + +- Updated PHP/MapScript for MS RFC 69: clustering. (#3700) + +- Move allocation of cgiRequestObj paramNames/Values to msAllocCgiObj() (#1888) + +- Add support for simple aggregates for the cluster layer attributes (#3700) + +- Improved error reporting in msSaveImage() (#3733) + +- configure: look for libxslt.so under lib64 as well + +- added missing ';' before charset in WFS DescribeFeatureType header (#3793) + +- add brushed line support for agg renderer (#3792) + +- fix bug with marker symbols along offset line + +- fix for the cluster layer returning invalid feature count (#3794) + +- remove some compiler warnings + +- fix incorrect scaling of hatch symbol spacing (#3773) + +- fix incorrect background color for INIMAGE exceptions (#3790) + +Version 6.0.0-beta4 (2011-03-30) +-------------------------------- + +- Fix shp2img's -i flag to honour map level transparent, image quality and + interlace settings. + +- Make sure command-line programs use an exit status other than 0 + when an error is encountered. (#3753) + +- Applied patch to filter unwanted fribidi characters (#3763) + +- Fixed lexer to set the proper state on URL variable substitutions + +- Fixed Memory leak in PostGIS driver (#3768) + +- Fixed PHP/MapScript symbol property setter method + +- fix memory leak in bar charts + +- fix some valgrind errors on agg rotated pixmap symbols + +- WCS 2.0: Adjusted definition of NilValues. + +- Fixed handling of PROJ_LIB value relative to mapfile path (#3094) + +- Fixed compilation error with opengl support (#3769) + +- add support for gml:Box for spatial filters (#3789) + +- fix query map generation error introduced in beta2 when output format + initialized was made as needed. + +- fix incorrect PATTERN behavior on agg lines (#3787) + +- report SOS DescribeObservationType in Capabilities (#3777) + +- Updated lexer to detect time attribute bindings (e.g. `[item]`) in logical + expressions + +- Fixed layer context expressions (REQUIRES/LABELREQUIRES) (#3737) + +- KML: Output ExtendedData (#3728) + +- Fixed OWS usage of multiple layers with same name (#3778) + +- WCS implementation should not lookup wms_* metadata (#3779) + +- WCS 2.0: Adjusted definition of rangeType. + +- Fixed OWS GetCapabilities to report only requests/operations that are + enabled. + +- WCS 2.0: Report only bands in the range subset. + +- OWS requests should be completely blocked by default (#3755) + +- SLD: check for limit on dash arrays (#3772) + +- WMS: Apply sld after bbox and srs have been parsed (#3765) + +Version 6.0.0-beta3 (2011-03-23) +-------------------------------- + +- apply min/max size/width style values to polygon spacing (vaguely related + to #3132) + +- assure that a created tile has a non-zero width and height (#3370) + +- use png_sig_cmp instead of png_check_sig (#3762) + +- Rendering: scale style OFFSET and GAP the same way we scale other style + attributes. Beforehand, we scaled them proportionaly to the computed width. + +- KML: fix rounding problem for point feautres (#3767) + +- KML: update code to reflect output changes. Fix true type symbols. (#3766) + +- SLD: Text Symbolizer now uses the new expression syntax (#3757) + +- WFS: correct bbox values for GetFeature with featureid request (#3761) + +- Mapscript Seg Fault on mapObj->getMetaData (#3738) + +- Correct double free in msCleanup(). + +- Initialize default formats in WCS. + +- Fix csharp Makefile.in (#3758) + +- Allow run-time subs in class->text (makes sense if you allow it in + class->expression). + +- Fix build problem when --enable-cgi-cl-debug-args is enabled (#2853) + +Version 6.0.0-beta2 (2011-03-18) +-------------------------------- + +- correct scaling of symbol GAP and PATTERN (#3752) + +- remove references to SWF/MING + +- CGI runtime substitution requires a validation pattern (was optional + before) (#3522) + +- add a default png8 outputformat that uses AGG/PNG with quantization + +- change MS_INIT_COLOR to take alpha as a parameter + +- stop using style->opacity in rendering code, use alpha from colorObjs. + +- Fixed big Oracle memory leak when rendering in KML (#3719) + +- avoid linking in postgres dependencies unnecessarily (#3708) + +- don't initialize outputformats until they are selected + +- use "seamless" creation of tiles for polygon fills with vector symbols + +- Ability to escape single/double quotes inside a string (#3706) + +- Globally replace msCaseFindSubstring with strcasestr (#3255) + +- support GROUP layers in shp2img (#3746) + +- Honour MAXSIZE for WCS 2.0 responses (#3204). + +- fallback to ows_title for WCS ows:Title of CoverageDescription (#3528) + +- Added msIO_stripStdoutBufferContentHeaders() to strip off all + Content-* headers from a buffer (#3673, #3665). + +- Added raster classification support for STYLE level OPACITY. + +- Allow attribute references, that is [itemname], within a TEXT string (#3736) + +- Fixed segmentation fault when parsing invalid extent arguments in + shp2img (#3734) + +- Make "openlayers mode" work even without OWS support (#3732) + +- Add a static table to define the axis order for some epsg codes (#3582) + +- Add possibility to use KML_NAME_ITEM (#3728) + +- Fixed mapfile parsing error when a label angle referenced an attribute + (e.g. ANGLE [angle]) #3727 + +- Removed executable flag on some source files (#3726) + +- Fixed SQL Spatial to be able to use UniqueIdentifier field as unique + key (#3722) + +- Fix PHP Windows build (#3714) + +- Fixed --with-opengl build issue: Look for OpenGL libs under /usr/lib64 as + well (#3724) + + +Version 6.0.0-beta1 (2011-03-09) +-------------------------------- + +- Fixed Core Dump from Format=KML/Z with Oracle Spatial layers (#3713) + +- Call msPluginFreeVirtualTableFactory from msCleanup (#2164) + +- Avoid the crash if anglemode 'FOLLOW' is specified with bitmap fonts. (#3379) + +- Add argument check for processTemplate, processLegendTemplate and + processQueryTemplate in the C# bindings (#3699) + +- Remove shapeObj.line, shapeObj.values, lineObj.point from the SWIG API + which are redundant and undocumented. (#3269) + +- Remove map-oriented query modes (e.g. QUERYMAP). Use qformat parameter instead. (#3712) + +- Implement single-pass query handling in mssql2008 driver as per RFC 65. + +- Fixed Sql Server 2008 key column name truncation (#3654) + +- Added label position binding (#3612) and label shadow size binding (#2924) + +- Implement MS RFC 69: Support for clustering of features in point layers (#3700) + +- Implement MS RFC 68: Support for combining features from multiple layers (#3674) + +- Add support for WCS 1.1 Post (#3710) + +- Fixed OGR query handling according to RFC 65 (#3647) + +- Implement CLOSE_CONNECTION=ALWAYS to suppress the connection pooling + for a particular layer. + +- Implemented RFC 67: Enable/Disable layers in ogc web services (#3703) + +- Class title can now be used in legends. It's value takes precedence over class name. Previously + title was not used any place in the code but it is supported for read/write. (#3702) + +- Allow definition of nodata attribute for layers without results (via resultset tag). (#3701) + +- mapprojhack.c: restructure to avoid needing projects, or any internal + knowledge of PROJ.4. + +- Fix newlines around part boundaries in WCS multipart results (#3672) + +- Added minfeaturesize support at layer or class level (#1340) + +- Implemented support in for classifying rasters using the new + expression parsing (msGetClass()...) (#3663) + +- Implemented RFC 65 which improves and simplifies one-pass query support. This causes + a few MapScript regressions with getShape/getFeature/getResultsShape. (#3647) + +- Support setting filenames for WCS GetCoverage results (#3665) + +- OGR auto-styling: use the color parameter and set the style's opacity when it is available. + Allow symbols that can be stored externally (#3660) + +- Add possibility to use symbols stored externally, accessed through http (#3662) + +- Better handling of temporary files (#3354) + +- Support curved features in PostGIS (#3621) + +- NODATA values now excluded from autoscaling min/max for non-eight + scaling computations (#3650) + +- Fixed missing time in msDrawMap logging (#3651) + +- Fixed Auto Angle - incorrectly placed Labels (#3648) + +- Fixed Improper validation of symbol index values (#3641) + +- Removed BACKGROUNDCOLOR, BACKGROUNDSHADOWCOLOR and BACKGROUNDSHADOWOFFSET label parameters (#3609) + +- Fixed Transformation from XML to MapFile only handles one PROCESSING element (#3631) + +- Fixed 16bit classification support - problem introduced with new + renderer architecture (#3624) + +- Cleanup open gdal datasets in msGDALCleanup() (if we have a very new + GDAL). This makes it easier to identify memory leaks. + +- Add support for per layer tuning of the shape to pixel conversion (SIMPLIFY, ROUND, + SNAPTOGRID, FULLRESOLUTION) + +- Fixed: Memory allocation results should always be checked (#3559) + +- Fixed free(): invalid next size in mapfile.c (#3604) + +- Added a built-in OpenLayers map viewer (#3549) + +- Fixed issues with static buffers and sprintf (#3537) + +- Fix for the memory corruption when mapping the string data type in the Java bindings (3491) + +- Fixed double free in shp2img.c (#3497) + +- Fixed number of CGI params is limited to 100 (#3583) + +- Fixed duplicated XML and HTML errors from WFS GetFeature (#3571) + +- Support group names for GetLegendGraphic and GetStyles (#3411) + +- apply patch (thanks rouault) to advertise resultType=hits in WFS 1.1 Capabilities (#3575) + +- mapshape.c: Fix writing of geometries with z/m and fail gracefully attempting + to create such files if USE_POINT_Z_M is not enabled (#3564) + +- sortshp.c: improve error handling (#3564) + +- MSSQL2008: Add support for geography data type by extending the DATA syntax + to 'geometry_column(geometry_type) from table_name' + +- Fixed ability to get the error message and code of an OWS exception (#3554) + +- Fixed msOGRGetSymbolId according to the changes in gdal 1.8 (#3556) + +- Support holding WMS client requests in RAM instead of writing to disk (#3555) + +- RFC-61: Enhance MapServer Feature Style Support (#3544) + +- Restrict cascaded WMS requests based on EXTENT (#3543) + +- Avoid EPSG lookups for WMS client layers if possible (#3533) + +- RFC-60: Add ability to skip ANGLE FOLLOW labels with too much character overlap (#3523) + +- Fixed SWF: not a valid Bitmap FillStyle (#3548) + +- Set dependency on libxml2 when building --with-wfs (#3512) + +- Fixed TRUE is undefined in shptreevis (#3545) + +- shptreevis: bug truncates visualization shapefile if there are more + nodes in the tree than there are shapes being indexed! + +- Fixed multiple include tags not supported in xml mapfiles (#3530) + +- Support reading .dbf files between 2GB and 4GB (#3514) + +- Avoid warnings about ms_cvsid being unused with gcc. + +- Ensure the class is not marked BeforeFieldInit causing memory corruption with C#/CLR4 (#3438) + +- Fixed MSSQL2008 driver returning invalid extent (#3498) + +- Added coordinate scaling to shpxy tag via parameters scale, scale_x or scale_y. + +- Fix computation of shape bounds when the first line contains no points + (#3119)(fixes #3383) + +- Allow map relative specification in the PROJ_LIB config item (#3094) + +- Try to report reprojection errors in SLD Filter evaluation (#3495) + +- Disabled some insecure (and potentially exploitable) mapserv command-line + debug arguments (#3485). The --enable-cgi-cl-debug-args configure switch + can be used to re-enable them for devs who really cannot get away without + them and who understand the potential security risk (not recommended for + production servers or those who don't understand the security implications). + +- Fixed segmentation fault in ogr driver when shape type is null + +- Fixed synchronized MS_UNITS and inchesPerUnits array (#3173) + +- Fixed possible buffer overflow in msTmpFile() (#3484) + +- Fixed Using STYLEITEM AUTO, loadExpression fails when the label text contains a double quote (#3481) + +- PHP/MapScript: Expose getGeomTransform/setGeomTransform instead of exposing the private vars for rfc48 (#2825) + +- PHP/MapScript: Fixed updateFromString functions to resolve symbol names (#3273) + +- PHP/MapScript: ability to use the php clone keyword (#3472) + +- Modified mapserver units enum order to fix some problems with external software (#3173) + +- Fixed configure does not detect libGD version dependencies (#3478) + +- Fixed Drawing inline text not working (bitmap) (#3475) + +- ensure well formed XML when msWCSGetCapabilities_CoverageOfferingBrief + returns MS_FAILURE (#3469) + +- Fixed msQueryByRect does not use tolerance (#3453) + +- Fixed MapScript processTemplate and processQueryTemplate seg fault (#3468) + +- Fixed shapeObj->toWkt() returns single point for multipoint geometry (#2762) + +- Fixed Internal server error when Oracle returns ora-28002 code (#3457) + +- Fixed PHP/MapScript ms_iogetstdoutbufferbytes() always returning 0 bytes written (#3041) + +- MapScript resultsGetShape() method fails with a OracleSpatial layer (#3462) + +- PHP/MapScript circular references between objects (#3405) + +- Handle null results with gml:Null/gml:null according to version (#3299) + +- Reworked mapfile writing to use helper functions so that core types (e.g. numbers, strings, + colors, keywords, etc...) are always written consistently. + +- Ensure mapwmslayer.c does not unlink file before closing connection on it (#3451) + +- Fix security exception issue in C# with MSVC2010 (#3438) + +- Write out join CONNECTIONTYPE when saving a mapfile. (#3435) + +- Fixed attribute queries to use an extent stored (and cached) as part of the queryObj + rather than the map->extent. (#3424) + +- Reverted msLayerWhichItems() to 5.4-like behavior although still supporting + retrieving all items (#3356,#3342) + +- Grid layer: remove drawing of unnecessary gird lines (#3433) + +- Avoid errors and debug output for CONNECTION-less OGR layers in mappool.c + if they have a tileindex. + +- Implement support for raw imagemodes to use NULLVALUE formatoption to set + the background value of result images, and to try and mark nodata (#1709) + +- Implement support for wcs_rangeset_nullvalue to set NULLVALUE and + return null value definition in describe coverage result (#655) + +- Try to avoid exhausting the color table when rendering 24bit key + images into 8bit results (#1594) + +- Avoid crash, and ensure error report when loading keyimage fails (#1594) + +- Improve the handling of simple string comparisons for raster classified + values (#3425) + +- Generate good SQL when using !BOX! token and no filter. (#3422) + +- Implement non-shapefile tileindex support for raster query (#2796). + +- Improve support for [red/green/blue] classification expressions for + raster query (#1021) + +- Fixed imageObj->saveImage() sends unnecessary headers (#3418) + +- Avoid automatically regenerating maplexer.c (#2310) + +- Change rounding rules for average resampling (#1932) + +- Implement support for filename encryption per RFC 18 for rasters (#3416) + +- Fixed segfault when using shapefile with empty geometry and tileindex (#3365) + +- Avoid race condition on core_lock on win32 mutex init (#3396) + +- Avoid use of inline keyword for C code (#3327) + +- Support WFS parsing through libxml2 (#3364) + +- Fixed PHP/MapScript imageObj->saveImage() function (#3410) + +- Implement wms_nonsquare_ok metadata item for WMS servers that do + not support non-square pixels (#3409) + +- Fixed MapScript shape->classindex is always 0 (#3406) + +- Fixed PHP MapScript integer passing broken on 64bit systems (#3412) + +- Fix MS_NONSQUARE to work in mode=map (#3413) + +- Support inclusion of raster layers in query map drawing even if the results + may not be that useful (#1842). + +- Fixed auto angle: incorrectly rotated Labels. Added AUTO2 angle mode. (#1688) + +- Preliminary implementation of validity mask (imageObj->img_mask) for raw + raster data (#2181) + +- Added libgd < 2.0.30 compatibility (#3293) + +- Incorporate support for GDAL nodata on RGB images (#2404) + +- Incorporated support for GDAL masks (GDAL RFC 15) (#2640) + +- Fixed XML transformation issues with expressions and symbols (#3397) + +- Check error returns from mapstring functions (#2988) + +- Add support for multiliple srs in WFS 1.1.0 (#3227) + +- Fixed PHP/MapScript owsRequestObj->loadParams() method when using php in a non cgi/fcgi/cli mode. (#1975) + +- Ensure that non-file raster datasets work (#3253) + +- Correct mutex locking problem with rasters with no inherent georef. (#3368) + +- Correct ungeoreferenced defaults via GetExtent() on raster layer (#3368) + +- PHP Mapscript refactoring: take full advantage of PHP 5 / Zend Engine 2 (#3278)" + +- Fixed msRemoveHashTable() to return the proper value on failure/success. + +- Correct one pass query problems and OGC filter query (#3305) + +- Fixed msMSSQL2008CloseConnection() to free the statement handle properly (#3244) + +- Fixed the query handling with the MSSQL2008 driver (#3058) + +- Fixed swig zoomRectangle() method: the maxy in the rect object have to be < miny value (#3286) + +- Fix crash with GRID layers with no classes (#3352) + +- Remove "legacy" raster support, all raster rendering via GDAL now. + +- Very preliminary render plugin support for raster rendering. (RFC 54) + +- support correct MIME type output for WFS 1.1.0 (#3295) + +- add WMS 1.3.0 LayerLimit support (#3284) + +- fix WFS 1.1.0 exception attributes (#3301) + +- add more useful error message when query file extension test fails (#3302) + +- s/gml:null/gml:Null for empty WFS GetFeature responses (#3299) + +- Support metatiling and buffers in mode=tile (#3323) + +- Enhance error messages in msGetTruetypeTextBBox() (#3314) + +- Report parsing errors in INCLUDEd files using the line number within the file (#3329) + +- Avoid memory error when building SQL bbox (#3324) + +- Reproject rectangles as polygons to get datelin wrapping (#3179) + +- Add support for the WMS capabilities items AuthorityURL, Identifier (#3251) + +- Added support to write a null shape in a shape file. (#3277) + +- Apply ON_MISSING_DATA to zero-length WMS client calls (#2785, #3243) + +- PHP/Mapscript: added labelCacheMember object and mapObj::getLabel() method (#1794) + +- Add shplabel tag support in templates (#3241) + +- Bumped GEOS requirement to version 3.0+ (#3215) + +- Fixed memory leak related to templates (#2996) + +- Added support of 44xx gtypes in oracle spatial driver (#2830) + +- Fixed curl proxy auth support for http connections (#571) + +- PHP/MapScript: removed deprecated class properties (#2170) + +- Fixed OGR datasource double free (#3261) + +- Fix compilation warnings around use of strcasestr (#3257) + +- Made %substitution% strings case insensitive (#3250) + +- Added support to get the extent of a raster layer that use a tileindex (#3252) + +- Fixed configure to support FTGL 2.1.2 (#3247) + +- Changed msSaveImageBufferGD to be in accordance with msSaveImageGD (#3201) + +- PHP/Mapscript: added layerObj units property (#3249) + +- Changed the query map rendering implementation without adding extra layers to the map (#3069) + +- SQL Server 2008 plugin is not handling null field values correctly (#2893) + +- Hatch symbol not properly saved (#2905) + +- Expose symbolObj.inmapfile to the SWIG API, have already been exposed to PHP (#3233) + +- Expose getGeomTransform/setGeomTransform to SWIG instead of exposing the private vars for rfc48 (#3214) + +- Fixed writeSymbol to support writing 'ANGLE AUTO' (#3214) + +- Fixed problems with point queries not working via the CGI (mode=query or mode=nquery) (#3246) + +- Support QueryByShape() with point and line geometries (#3248) + +- Honour MAXSIZE for WCS responses (#3204) + +- Implemented RFC 52 LayerResultsGetShape support for OGR connection type. + +- Fixed uninitialized variable with malloc used in osPointCluster() (#3236) + +- Oracle driver: remove BLOB columns instead of changing them to null (#3228) + +- Fixed ogc sld functions to return proper values (#2165) + +- MAP EXTENT truncates GetFeature requests for data outside bounds (#1287) + +- Added msStringSplitComplex function (#471) + +- Mapserver WFS should send maxfeatures to the spatial database (#2605) + +- WFS paging support (#2799) + +- Fixed joins do not accept encrypted passwords (#2912) + +- Fixed HTML legend image samples truncated (#2636) + +- WMS GetFeatureInfo should respect the scale like GetMap does (#842) + +- Filter encoding: simple filters using propertyislike not applied properly + #2720, #2840 + +- Fix VBAR Chart production when using GD for rendering (#3482) + + +Version 5.6.0 (2009-12-04): +--------------------------- + +- WFS hits count is incorrect if the request contain 2 layers or more (#3244) + +- Fixed a problem with layer plugin where copyVirtualTable didn't copy + the LayerResultsGetShape function pointer (#3223) + + +Version 5.6.0-rc1 (2009-11-27): +------------------------------- + +- Fixed a problem with shape-based queries against projected layers when + using a tolerance (#3211) + +- Fixed long expression evaluation (#2123) + +- Added simplfy and topologyPreservingSimplify to MapScript (#2753) + +- Fixed Oracle FastCGI memory leak (#3187) + +- layer->project flag not being reset properly for drawquerylayer (#673 #2079) + +- OGC SLD: support multi-polygons geometries for filters embedded in + an SLD (#3097) + +- [WMC] embedded SLD in context does not work with namespace prefix (#3115) + +- Support name aliases used in sld text symbolizer (#3114) + +- decode html and unicode entities for polygon truetype symbol fills (#3203) + +- Parse PropertyName parameter for wfs requests (#675) + +- Fixed when saving a map, layer->transform isn't written properly in + all cases. (#3198) + +- Fixed buffer overflow in oracle spatial driver with large sql data (#2694) + +- Improve FastCGI include file finding logic (#3200) + + +Version 5.6.0-beta5 (2009-11-04): +--------------------------------- + +- Apply a minimum width on label outline (new outlines were too thin by default) + +- Don't apply scalefactor to polygon outline widths (but apply the + resolutionfactor) + +- Fix vector symbol size calculation (#2896) + +- Applied code clean up patch for mapsearch.c. (#3189) + +- Fixed labels centering when the label is longer than the line (#2867) + +- Ensure Python MapScript building doesn't reorder the libraries, support the + 'subprocess' module where available for setup.py, and default to using the + "super" swig invocation described in the Python MapScript README when + mapscript_wrap.c isn't available on the file system. #2663 contains the + reordering issue. + +- Fixed memory leak with shapefiles associated with one-pass query + implementation (#3188) + +- Fix abs/fabs usage that prevented angle follow labels to be discarded if + they were too wrapped on themselves + +- Allow CGI mapshape and imgshape variables to consume WKT strings (#3185) + +- Added support for nautical miles unit (#3173) + +- Fixed encoding metadata ignored by a few wcs/wfs 1.1 and sos requests (#3182) + +- PHP/Mapscript: added "autofollow" and "repeatdistance" in labelObj (#3175) + +- Added charset in content-type http header for wms/wfs/sos/wcs requests (#2583) + +- Python/MapScript: improve compatibility for different swig versions (#3180) + +- maprasterquery.c: a few fixes since beta4 (#3181, #3168). + +- mapows.c: Generate WMS LatLongBoundingBox in WGS84 datum (#2578) + + +Version 5.6.0-beta4 (2009-10-18): +--------------------------------- + +- Allow processing of single shapefiles with no items (e.g. an empty dbf file) (#3147) + +- Added resolution scaling for swf, svg, pdf and imagemap drivers (#3157) + +- Correct cases where a valid WFS Layer might return errors if + map extent does not overlap the layer extent (#3139) + +- fix problem with 0-length line patterns in AGG + +- Fixed problem of text/html WMS GetFeatureInfo which was returning HTML + image map output instead of the expected text/html template output. + This was done by changing the imagemap outputformat to use the + "text/html; driver=imagemap" mime type (#3024) + +- more resolution fixes for resolution scaling (symbolscale case) (#3157) + +- Make sure layer extents are saved when a mapfile is written (#2969) + +- Fixed CurvePolygons from oracle not drawn (#2772) + +- Fixed raster queries (broken by RFC 52 changes) (#3166) + +- Fixed coordinate projection problem in some cases with WMS GetFeatureInfo + output in GML2 format (#2989) + +- Added resolution scaling of some properties for GD driver (#3157) + +- Modified GD functions API to be consistent with all others drivers (#3157) + +- OGC Filter: strip all namespaces (not only ogc, gml) (#1350) + +- Use decimal values for size and width in SVG output format (#2835) + +- Correct invalid test when loading movies in an swf output (#2524) + +- Return WMS GetCapabilities v1.3.0 by default as required by spec (#3169) + +- Fixed mapObj.zoomScale() and mapobj.zoomRectangle() scaling problem in + Mapscript (#3131) + +- Few more fixes for high res output (#3157) + +- Allow "DRIVER 'TEMPLATE'" or "DRIVER TEMPLATE" in output formats + +- Correct sld generated from mapserver classes (#3133) + +- Correct libjpeg v7 compatibility issue in old jpeg interface code (#3167) + +- Correct FEATURE_COUNT limits on WMS GetFeatureInfo raster queries (#3168) + +- Correct SCALE_BUCKETS issue with 16bit raster scaling (#3174) + + +Version 5.6.0-beta3 (2009-10-07): +--------------------------------- + +- make RFC55 highres output be friendly with scaledependant rendering (#3157) + +- avoid fractured and overlapping glyphs with angle follow (#2812) + +- Fixed SDE layer seg fault (#3152) + +- Fixed placement of labels using ANGLE AUTO which were not always positioned + correctly (#3160) + +- Enable output of geometry in GML GetFeatureInfo if wms_geometries and + wms_geom_type are specified (#2989) + +- fix URN typo in mapwfs.c for urn:EPSG:geographicCRS:... + +- don't apply scalefactor to label outlines (#3157) + +- update namespaces and schema pointers (#2872) + +- add RFC49 and RFC40 keywords to copy functions (#2865) + +- minor fix to correct numberOfResults when maxfeatures is set in + mapfile (#2907) + +- Fixed possible crash with WFS GetFeature when no projection is specified + at the map level (#3129) + +- Fixed anchor point of vertically stacked bar graphs + +- Fixed TEXT property that cannot be removed in the CLASS object. + PHP/Mapscript (#3063) + +- Fixed use of minfeaturesize auto with curved labels (#3151) + +- Fixed msRemoveHashTable function when 2 keys have the same hash (#3146) + +- Fix raster thread deadlock condition on posix/linux (#3145) + +- Do not route thread debug output through msDebug which requires locking. + +- Fix WCS coverage metadata handling if size/resolution missing (#2683). + +- Fix WCS crash with use of datasets that aren't physical files (#2901). + +- Fix WCS failure with WCS 1.1 OGC URN (urn:ogc:def:crs:OGC::CRS84) (#3161). + + +Version 5.6.0-beta2 (2009-10-01): +--------------------------------- + +- Fixed a couple of issues with Oracle Spatial and single pass queries (#3069) + +- Added layer.resultsGetShape() to PHP MapScript for use with queries (#3069) + +- Fixed query maps under the new single pass query process (#3069) + +- WFS Client seg fault (OGR layer not opened) (#3136) + +- Reduce use of sqrt() calls when determining distances (#3134) + +- support axis ordering for WFS 1.1 (#2899) + +- const changes to avoid warnings with msLoadProjectionString() + +- mapgd.c: removed unused drawVectorSymbolGD() function. + +- Use http://www.mapserver.org/mapserver namespace URI in XML mapfile + schema (#3142) + +- Fixed issue with PHP_REGEX_INC in mapscript/php3/Makefile.in (#3078) + + +Version 5.6.0-beta1 (2009-09-23): +--------------------------------- + +- WMS 1.3.0 expects a CRS parameter instead of SRS (#2979) + +- Allow users to set wms getmap and getlegendgraphic image format list (#455) + +- Fixed MapScript shapeObj->toWkt() segfaults (#2763) + +- add vertical bar charts to dynamic charting (#3128) + +- Get the intersection points and labels #3101 + +- Fixed shp2img not to cause a crash when the map couldn't be loaded + +- Fix problem with overflowing shape->index for (most) query modes (#2850) + +- Useful error message when PK is missing and data is subselect (#3124) + +- Add WMS root Layer metadata support (#3121) + +- Fixed build problem of PHP/Mapscript when php is compiled with gd as + a shared extension (#3117) + +- Improve safety of srcx/y checks in nearest neighbour raster resampler (#3120) + +- Added support for 4d geometry types and oci bind variables for Oracle (#3107) + +- Implement SECTION support for the WCS 1.1 GetCapabilities request (#3105) + +- Fixed WCS processing when both crs and response_crs are specified (#3083) + +- Fixed msFreeMap causing memory corruption in msFreeOutputFormat (#3113) + +- Fix WMC XML output when Dimension is used (#3110) + +- Enable LOAD_WHOLE_IMAGE processing option by default when rendering + WMS client layer images (#3111). + +- add default values for CGI %key% substitutions (#3108) + +- fix clipping of polygon shapes in line layers (#3059) + +- RFC 51 implementation: XML Mapfiles Format (#2872) + +- Fix output for valid WCS 1.1 XML (#3086) + +- Avoid double free with postgresql joins. (#2936) + +- Don't attempt to project layers given in pixel coordinates + (layer->transform != MS_TRUE) (#3096) + +- Modify loading imagery from GDAL to load all bands at once to avoid multiple + passes through pixel interleaved data (mapdrawgdal.c). This is just an + optimization - there should be no change in results or features. + +- Modern GDALs clear the config when destroying driver manager. Skip this + call to avoid TLS leakage on cleanup (mapgdal.c). + +- Fixed msMSSQL2008LayerGetShape to retrieve proper wkb geometries (#3082) + +- Fixed the shape index for the inline layers (#3074) + +- Fixed MINDISTANCE not considering label size on lines (#3050) + +- Labeling enhancements: ability to repeat labels along a line/multiline (#3030) + +- Modified STYLEITEM code to use the new way of rendering thick lines (#3025) + +- Fixed template processor to respect layer order. (#2619) + +- Add MS_DEBUGLEVEL and MS_ERRORFILE commandline switches for mapserv.c. + +- Exposed msMapOffsetExtent, msMapScaleExtent and msMapSetCenter methods + in PHP/Mapscript (#2460) + +- Removed ZEND_DEBUG define in PHP/Mapscript (#2717) + +- Fixed PHP/Mapscript to support PHP 5.3 (#3065, #3066) + +- remove -O optimization flags to configure script if configured + with --enable-debug + +- Fixed performance bottleneck when computing a polygon center of gravity for + label point computation. (#3053) + +- make WFS numberOfFeatures match maxFeatures if passed (#2907) + +- Add logging in layer visibility tests to help users find why layers + don't draw (#3054) + +- include PNG libs first (#3046) + +- merge graphics branch: RFC54 implementation, cairo rendering (png, svg, pdf), + opengl rendering (non functional yet) + +- Do pre-emptive test for map.extent/layer.extent interaction (#3043) + +- Add centroid geomtransform (#2825) + +- Test database connections before using them (#2932) + +- Support non-numeric join criteria (#2006) + +- Ensure there's enough room in the SQL to hold a long (#1284) + +- Fix filter error in multi-clause filters (#2937) + +- Fix agg freetype character lookup when no unicode charmap is present (#3018) + +- Fix memory leak in SQL building (#2997) + +- Fork AGG rendering library in our trunk + +- Fixed a memory leak when unescaping quotes in logical expressions (#2938) + +- Fixed template code for item, shpxy and extent tags to properly initialize + tag arguments in cases where there are multiple tags in one chunk of + template (#2990) + +- Fix mapogcfilter.c not to cause syntax error if PROJ.4 is not compiled + in (#2987) + +- Rework Python MapScript's setup.py to be more like Python's to fix + a number of issues including (#2637) and to use mapserver-config + and ditch the old mapscriptvars approach + +- Prevent from changing the connection type to MS_RASTER when + setConnectionType(MS_WMS) is used (#2908) + +- Improve rounding logic for computing the src_xoff/yoff (#2976) + +- Fix filename path processing for raster queries and WCS get coverage so + that non-filesystem filenames are not altered (#2901) + +- Improved security relative to untrusted directories and mapfiles (RFC 56) + +- Fixed several security issues found in an audit of the CGI + application (#2939, #2941, #2942, #2943, #2944) + +- setConnectionType(MS_WMS) doesn't work with mapscript (#2908) + +- Perl Mapscript: improvement of imageObj wrapper (#2962) + +- Improve control of output resolution (RFC 55, #2948) + +- mapraster.c: use GDALOpenShared(), and CLOSE_CONNECTION=DEFERRED (#2815) + +- AGG font outline method change (#1243) + +- Change mapbit.c bitmask type from char to new 32bit ms_bitarray (#2930) + +- Added resolution writing in image files (#2891) + +- Try to save resolution values to GeoTIFF via GDAL (#2891) + +- Refactor legend icon drawing (remove renderer specific versions) + Add label styling or markers for annotation layer legend icons (#2917) + +- Update EXTENT warning message (#2914) + +- add support for SRSNAME parameter (#2899) + +- add support for resultType (#2907) + +- WFS 1.1.0 should use OWS Common 1.0.0 (#2925) + +- clean up GEOS init and cleanup functions (#2929) + +- add support for disabling SLD (#1395) + +- fix to output gml:boundedBy again (#2907) + +- fix warning for change in bitmask type (#2930) + +- fix time advertising in WMS 1.3.0 (#2935) + +- fix SOS blockSeparator output (#3014) + +- fix MIME type support (#3020) + + +Version 5.4.0-beta3 (2009-3-5): +-------------------------------- + +- SLD: Correct crash with large class names (#2915) + +- Added Java MapScript WIN64 support (#2250) + +- Fixed a problem with long running processes, embedded scalebars/legends + and AGG. (#2887) + +- Applied patch to deal with a couple of WCS issues (time ranges, #2487) + and PostGIS tileindex-based time filters (#1856) + +- Adding -DUSE_GENERIC_MS_NINT to the WIN64 MapScript builds (#2250) + +- Fixed C# the compiler options for MSVC 2008 (#2910) + +- Fix build problem with mapogcsld.c when OWS services are not available (#473) + +- Fix build on windows (maputil.c) + +Version 5.4.0-beta2 (2009-2-25): +-------------------------------- + +- Fixed a problem where default shade symbols (solid fill, no size) were being + scaled and not rendered as expected (related to #2896 I believe) + +- Fixed a problem with offset polylines (AGG only) (#2868) + +- Generate SLD version 1.1.0 (#473) + +- Tracking original geometry type so we can make better decisions on what + positions to use with POSITION AUTO and annotation layers. (#2770) + +- Setting up the same size units between the OGR auto-style and the + OGR label attribute binding option (#2900) + +- Take better care of the extra items with the inline layers to + prevent from memory corruption (#2870) + +- Fixed the compiler options for MSVC 2008 (#2898) + +Version 5.4.0-beta1 (2009-2-18): +-------------------------------- + +- restored much of the pre-5.0 capabilities to update a mapfile via URL but in + a more secure manner (RFC44) + +- WMS 1.3.0 support added (#473) + +- OWS GetCapabilities should skip layers with status == MS_DELETE (#2582) + +- Set the default symbol size to 1 instead of 0 (#2896) + +- fix WMS LegendURL to print sld_version for 1.3.0 Capabilities (#473) + +- add GetSchemaExtension to WMS to support GetStyles in Capabilities XML (#473) + +- move xlink declaration to root of WMS 1.3.0 DescribeLayerResponse + +- Fixed a scalebar rounding problem causing to draw zero scalebar width (#2890) + +- SLD: if it contains a Filter Encoding tag, try to always set the + layer's FILTER element (#2889) + +- Add support for rendering INLINE layers with layer attributes (items) (#2870) + +- Fix mapserver crash when rendering a query map in HILITE mode + and there are is no STYLE defined (#2803) + +- Added projection support to [...ext] tags for template output. + +- Removed the error generation when the OGR layer contains no fields (#2883) + +- Added enhancements to mapogr.cpp for style annotations (#2879) + +- Fixed memory leaks when using msUpdate*FromString methods. (#2857) + +- Fixed the problem when removing the attribute binding in mapscript. + +- SOS XML validity fixes (#2646) + +- add WFS calls for schema resolution (#2646) + +- add gml:id to om:Observation (#2646) + +- fix some XML validity issues (#2646) + +- Fixed endianness issues with wide character strings for ArcSDE (#2878). + Thanks Russell McOrmond + +- Fixed WMS request with LAYERS parameter: may cause segmentation fault (#2871) + +- fix when layer status = DEFAULT and passing list of layers (#2066) + +- Fixed msAddLabel may cause access violation in certain conditions + +- Changed base type of labelObj size, minsize and maxsize from int to double (#2766) + +- add support for WMS Server title in LAYER object (#885) + +- Fixed build problem using --with-gd=static and freetype (#2697) + +- RFC49 implementation (#2865) + +- Fixed Blobs not filtered in OracleSpatial Attribute/WFS queries (#2829) + +- Fixed memory leak of map::setProjection in PHP/MapScript (#2861) + +- Fixed "internal PHP GC memory leaks" in PHP/MapScript (#2767) + +- Fixed bug with wms layer group hierarchy (#2810) + +- Added updateFromString() methods for several objects in PHP/Mapscript (#2298) + +- Added ms_newMapObjFromString mapObj constructor in PHP/Mapscript (#2399) + +- Add support to compile mssql2008 when SDE or ORACLE is not compiled (#2851) + +- Add support for creating debug builds for the plugins on Windows + +- Correct half pixel error in WMS layer's BBOX request to remote WMS (#2843) + +- Expose Map/Layer's Projection objects in PHP/MapScript (#2845) + +- Added getUnits() methods to projectionObj in Mapscript (#2798) + +- Improved Tag parsing in template code. (#2781) + +- Added hashtable object and metadata methods for php-mapscript (#2773) + +- mappostgis.c: Fix trailing spaces in fixed varchar fields (#2817) + +- RFC48 implementation: GEOMTRANSFORM on styleObj (#2825) + +- mapwms.c: cleanup warnings with recent gcc versions (#2822) + +- mapogcsos.c: Cleanup warning and error messages + +- mapagg.cpp: Fix center of rotation for truetype marker symbols + +- mapowscommon.c: use msLibXml2GenerateList to generate listed XML elements + +- mapowscommon.c: output version string correctly (#2821) + +- Added removeLayer function to mapObj in PHP/MapScript. (#762) + +- Exposed PIXELS value via URL configuration + +- Add Support for SLD TextSymbolizer HALO and ANGLE (#2806) + +- IGNORE_MISSING_DATA: largely replaced by run-time CONFIG property, + ON_MISSING_DATA, which supports three modes: FAIL, LOG, and IGNORE. + (#2785) ms-rfc-47.txt + +- mapstring.c: msStringTrim(*char str), front-and-back whitespace trimmer + +- mappostgis.c: re-write to remove binary cursors and break up + logic into smaller parts, add support for maxfeatures + +- mapogcfilter.c: increase array size (code was assigning to out + of bounds subscript) + +- MapScript: Added getBinding method to label and style object (#2670) + +- mapowscommon.c: use strcasecmp to check for language value + +- raster query fix for tileindex with relative paths (#2722) + +- Fixed msOGRGetValues function to return default values if the object + type is not TEXT. (#2311) + +- Fix for the access violation caused by msMSSQL2008LayerGetShape (#2795) + +- Fixed msMSSQL2008LayerGetItems to retrieve the column names properly (#2791) + +- Prevent from calling msMSSQL2008CloseConnection from msMSSQL2008LayerClose + causing memory corruption issues (#2790) + +- new polygon label placement algorithm (#2793) + +- stop drawing an artificial outline around polygons to ensure + continuity - users needing this feature will have to explicitly + add an outlinecolor of the same color as the fill color + +- added formatoption QUANTIZE_NEW to force going through the pngquant + quantization algorithm instead of the GD one for imagemode RGB (the + GD one can be kind of buggy) + +- fix some integer rounding errors in the agg line offseter (#2659) + +- fix a bug with shapes with duplicate end points. was causing nans + in the angle follow placement code (#2695) + +- refactor msGetLabelSizeEx (now merged with msGetLabelSize) (#2390) + +- native label size computation for AGG when using angle follow (#2357) + +- memory leak in msInsertLayer, from Ned Harding (#2784) + +- label size computation refactoring (#2390) + +- don't draw label background if we're using angle follow. (#2726) + +- legend keyimage resampling with agg (#2715) + +- tileindexed rasters when DATA is manipulated via mapscript work (#2783) + +- styleObj width now supports attribute binding + +- RFC40 implementation: label text wrapping and alignment (#2383) + +- baseline adjustment for multiline labels (#1449) + +- Added support to access to the labelObj OUTLINEWIDTH property in + PHP/MapScript + +- PHP paste image should also work with AGG (#2682) + +- Fixed bug when QUERYMAP hilite color is set and the shape's color in a + layer is from a data source (#2769) + +- Decoupled AUTO label placement from the positions enum in mapserver.h. Added + explicit case for POLYGON layers where CC is the default and then we try UC, + LC, CL and CR. (#2770) + +- Changed base type of styleObj size and width from int to double (#2766) + +- Correct allocation error in mapmssql2008.c + +- Add possibility to use a full resolution setting for svg output (#1706) + +- Fixed GetFeature through tileindex bug: the tileindex of the shape found + wasn't set properly in the resultcache object. (#2359) + +- Removed comma to correct WCS 1.1 Coverages formatting in payload directory. + (#2764) + +- Correct bug when LABEL_NO_CLIP in combination with minfeaturesize (#2758) + +- Fix a label size computation for AGG bug when scalefactor is used (#2756) + +- various SOS updates for CITE compliance (#2646) + +- Added support for static linking with the lib gd in configure + script (#2696) + +- Support OpenLayer's ol:opacity extension to OGC Web Map Context docs (#2746) + +- Added MS_VERSION_NUM for use with #if statements in code based on + libmapserver (#2750) + +- Fixed the configure script: failed to detect php5 on ubuntu. (#2365) + +- Fixed a memory leak associated with not deleting the lexer buffer + before parsing certain types of strings. (#2729) + +- Added legend graphics for layer of type annotation + for the AGG and GD renderer (#1523) + +- Masking the out-of-range characters to avoid the crash + in the AGG renderer (#2739) + +- Accept WMS requests in which the optional SERVICE parameter is missing. + A new test was incorrectly added in 5.2.0 that resulted in the error + "Incomplete WFS request: SERVICE parameter missing" when the SERVICE + parameter was missing in WMS requests in which the SERVICE parameter is + optional (#2737) + +- Support for the MapInfo style zoom layering option (#2738) + +- Implement Equals and GetHashCode properly for the mapscript C# classes + +- Expose msConnectLayer to the SWIG mapscript interface with a new + layerObj.setConnectionType() method that should be used instead of + setting the layerObj.connectiontype directly (#2735) + +- SLD: when creating well known symbols on the fly the pen-up value + used should be -99. + +- SWF: Button names reflects the layer id and shape id (#2691) + +- Support reading projection parameter for OGC filters (#2712) + +- Several enhancements to STYLEITEM AUTO support for labels (#2708) and + TTF symbols (#2721) in OGR layers + +- Expose special attributes OGR:LabelText, OGR:LAbelAngle, OGR:LabelSize + and OGR:LabelColor to MapScript getShape() calls (#2719) + +Version 5.2.0 (2008-07-16): +--------------------------- + +- mapfile.c: Fixed a bug that prevented using named symbols via URL + configuration. (#2700) + +Version 5.2.0-rc1 (2008-07-09): +------------------------------- + +- mapowscommon.c: fix support multiple namespaces (#2690) + +- Fix OGC simple filters on SDE layers (#2685) + +- wfs11 getcapabilities: correct memory corruption (#2686) + +- Allow building against Curl 7.10.6 and older which lack CURLOPT_PROXYAUTH + option required for *_proxy_auth_type metadata (#571) + +- Avoid fatal error when creating new ShapeFileObj with MapScript (#2674) + +- Fixed problem with WMS INIMAGE exceptions vs AGG output formats (#2438) + +- mapshape.c: Fixed integer pointer math being applied to uchars (#2667) + +- Fixed seg fault with saveImage() in PHP MapScript due to #2673 (#2677) + +- Fixed configure error related to new fribidi2 pkg-config support (#2664) + +- Fixed windows build problem (#2676) + +- Fix raster query bounds problem (#2679) + + +Version 5.2.0-beta4 (2008-07-02): +--------------------------------- + +- Added support in configure script for pkg-config for fribidi2 (#2664) + +- Added more debug/tuning output to mapserv and shp2img at debug level 2 (#2673) + +- maptemplate.c: removed extra line feeds from mime header output. (#2672) + +- mapresample.c: fix for bug 2540 when using raster resampling and AGG. + +- mapsde.c: Check at compile time that we have SE_connection_test_server, + which appears to only be available for ArcSDE 9+ (#2665). + +- mapshape.c: restore old behavior of tiled shapes relative to shapepath + with new behavior for when shapepath is undefined (#2369) + +- maputil.c: fix a bug for offset lines with agg, when the first segment + was horizontal (#2659) + +- mapraster.c: fix for tiled rasters with relative shape paths defined, + from dfurhy (#2369) + +- maptemplate.c: fixed a problem with extent tags with _esc extension not + working (#2666) + +Version 5.2.0-beta3 (2008-06-26): +--------------------------------- + +- mapsde.c: processing option added to allow using fully qualified names + for attributes (#2423). + +- mapsde.c: Test for an active connection before closing it (#2498). + +- mapdraw.c: Fixed issue where path following labels were not being drawn + if FORCEd. (#2600) + +- mapshape.c: Applied patch to make the location of tiled data relative to the + tileindex directory if SHAPEPATH is not set. (#2369) + +- maptemplate.c: Fixed issues in RFC 36 implementation that prevented mapscript + mapObj->processQueryTemplate() method from working. + +- WMS/WFS: extend warning message (#1396) + +- WFS: Respect units for the DWhitin parameter (#2297) + +- WFS: correct OGC Contains filter (#2306) + +- WMS: set srsName correctly for GetFeatureInfo (#2502) + +- SOS: detect invalid time strings (#2560) + +- SOS: more srsName support (#2558) + +- mapserv.c, maptemplate.c: fixed problem with arguments to msGenerateImages(). (#2655) + +- WMS: produce warning if layer extent is null (#1396) + +- WFS: project LatLongBoundingBox if required (#2579) + +- SOS: generate error for some invalid filters (#2604) + +- SLD: Use style's width parameter when generating sld (#1192) + +Version 5.2.0-beta2 (2008-06-18): +--------------------------------- + +- mapogcsos.c: support invalid procedure in GetObservation (#2561) + +- Fixed possible buffer overrun with Oracle Spatial driver (#2572) + +- mapogcsos.c: support srsName in GetObservation (#2414) + +- Filter Encoding: Modify DWithin definition (#2564) + +- Added webObj legendformat and browseformat mapping in PHP MapScript (#2309) + +- Removed static buffer size limit in msIO_*printf() functions (#2214) + +- Fixed libiconv detection in configure for OSX 10.5 64 bit (#2396) + +- mapstring.c: possible buffer overflow in msGetPath (#2649) + +- maputil.c: Correct expression evaluation with text containing + apostrophes (#2641) + +- mapwfs.c: Possibly generate an error message when applying filter + encoding (#2444) + +- Added MS_LABEL_BINDING constants for SWIG MapScript (#2643) + +- mapogcsos.c: fix POST support (#2379) + +- maplibxml2.c: helper functions XML POST fix (#2379) + +- mapwfs.c: fix segfault when srsName is not passed on BBOX Filter (#2644) + +- mapwfs.c: do not return error for empty query results (#2444) + +- Remove C++-style comments and most other warnings thrown by -pedantic (#2598) + +- mapwfs.c/mapwfs11.c: set GML MIME type correctly + +- mapogcsos.c: advertise supported SRS list via + MAP.WEB.METADATA.sos_srs (#2414) + +- mapwfs.c: set layer extent to map extent for default + GetFeature requests with no spatial predicates (#1287) + +Version 5.2.0-beta1 (2008-06-11): +--------------------------------- + +- WMS/WFS layers can now specify a proxy servert (#571) + +- mapwmslayer.c: set QUERY_LAYERS correctly (#2001) + +- mapwcs.c: handle PARAMETER values correctly (#2509) + +- SOS: fix various memory leaks (#2412) + +- mapwcs.c: advertise temporal support in GetCapabilities (#2487) + +- Fixed flaw in findTag() in maptemplate.c that prevented multiple tags + on the same line being processed under certain conditions. (#2633) + +- Return results even when extents are missing (#2420) + +- Avoid displaying OGR connection strings in error messages (#2629) + +- WCS: respect wcs_name metadata for GetCoverage and DescribeCoverage + requests (#2036) + +- CGI: added -nh option to allow for the suppression of content headers from + the command line (#2594) + +- PostGIS: fix postgis idle-in-transaction problem (#2626) + +- AGG: enable ellipse symbol rotation for POINT/ANNOTATION layers (#2617) + +- RFC36: add more extensions to support templates (#2576) + +- AGG: allow dashed hatch symbols (#2614) + +- AGG: enable offset lines of type x -99 (#2588) + +- AGG: use an agg specific label size calculation function where + possible (#2357) + +- mapogcsld.c: fetch TextSymbolizer/Label/ogc:PropertyName correctly (#2611) + +- Don't ignore .qix file when DATA reference includes .shp extension (#590) + +- CGI able to alter layers with space and underscores (#2516) + +- WFS Multipoint query with PostGIS bug fixed (#2443) + +- Tiling API (RFC 43) mode=tile, tilemode=spheremerc, tile=x y zoom (#2581) + +- Remove C++-style comments and most other warnings thrown by -pedantic (#2598) + +- Fix PostGIS transaction behavior in fcgi situations (#2497, #2613) + +- Improve performance for large shape files (#2282) + +- encode WMS parameters correctly (#1296) + +- Added alignment option within a scalebar (#2468) + +- RFC-42 HTTP Cookie Forwarding (#2566) + +- Fixed handling of encrypted connection strings in postgis driver (#2563) + +- mapagg.cpp: AGG: add opacity at the style level (#1155) + +- mapwms.c: add Cache-Control max-age HTTP header support (#2551) + +- mapogcsos.c: support URI encoded procedures correctly (#2547) + +- Added support for EMPTY template with WMS GetFeatureInfo (#546) + +- Throw an exception if the WCS request does not overlap layer (#2503) + +- Acquire TLOCK_PROJ for pj_transform() calls (#2533). + +- Fixed problem with large imagemaps generating no output (#2526) + +- mapwms.c: make version optional for GetCapabilities again (#2528) + +- support URN scheme for components of observed property elements (#2522) + +- Fixed gdImagePtr gdPImg memory leak in msSaveImageBufferGD() (#2525) + +- mapogcsos.c: handle invalid POST requests (#2521) + +- mapogcsos.c: handle ACCEPTVERSIONS parameter (#2515) + +- mapwcs.c/mapwcs11.c: s/neighbour/neighbor/g (#2518) + +- mapwms.c: relax FORMAT parameter restrictions for GetFeatureInfo (#2517) + +- mapwcs.c: support COVERAGE lists for DescribeCoverage (#2508) + +- mapwcs.c: fix lonLatEnvelope/@srsName (#2507) + +- mapwcs.c: omit VendorSpecificCapabilities (#2506) + +- mapwcs.c: test for either resx/resy OR width/height (#2505) + +- mapwcs.c: make GetCoverage demand one of TIME or BBOX (#2504) + +- mapwms.c: make GetLegendGraphic listen to TRANSPARENT in OUTPUTFORMAT (#2494) + +- OWS: support updatesequence (#2384) + +- mapwms.c: test VERSION after service=WMS (#2475) + +- OWS: output Capabilities XML updateSequence if set (#2384) + +- mapwcs.c: better handling of REQUEST parameter (#2490) + +- mapwcs.c: point to correct exception schema (#2481) + +- mapows.c: add version negotiation (#996) + +- mapwfs.c: return default GML2 when invalid OUTPUTFORMAT passed (#2479) + +- mapowscommon.c: add OWS Common style version negotiation (#996) + +- mapwcs.c: better section parameter handling for CITE (#2485) + +- mapwfs.c: point to the correct schema for exceptions (#2480) + +- shp2img.c/shp2pdf.c: clean up usage text, check for invalid layers (#2066) + +- completed implementation of RFC24 (#2442, #2032) + +- mapwcs.c: require VERSION parameter for DescribeCoverage and + GetCoverage (#2473) + +- mapwcs.c: change error token to MS_WCSERR instead of MS_WMSERR (#2474) + +- mapwcs.c: set exception MIME type to application/vnd.ogc.se_xml + for 1.0.0 (#2470) + +- mapwcs.c: Generate a decently formatted exception if an WCS XML POST request + is received (#2476). + +- mapowscommon.c: support OWS Common 1.1.0 as well (#2071) + +- mapogcsos.c: support SOS 1.0.0 (#2246) + +- Implement mapObj.setCenter, mapObj.offsetExtent, mapObj.scaleExtent, + rectObj.getCenter at the SWIG API (#2346) + +- mapogcfilter.c: use USE_LIBXML2 in ifdefs (#2416) + +- clean up naming conventions of Shapefile API (#599) + +- use msComputeBounds() instead, since it's already in the codebase (#2087) + +- set shapeObj bounds from WKT (#2087) + +- fixed issue where path following labels sometimes used the supplied +setting for position. In all cases with ANGLE FOLLOW we want to force +position MS_CC regardless of what is set in the mapfile. + +- enforce (-99 -99) to be the penup value for vector symbols (#1036) + +- Support for labeling features (polygon & line) prior to clipping. This +results in stable label positions regardless of map extent. (#2447) + +- Support for quantization and forced palette png output with RGBA images + (#2436) + +- SLD using a single BBOX filter should generate an SQL ststement for + oracle/postgis/ogr (#2450) + +- Accurate Calculation of legend size for WMS LegendURL (#2435) + +- Converted mapogr.cpp to use OGR C API instead of C++ classes to allow + GDAL/OGR updates without having to recompile MapServer (#545, #697) + +- add missing space on dashed polygon outlines with svg (#2429) + +- Restored behavior of MS 4.10 and made WMS STYLES parameter optional + again in GetMap and GetFeatureInfo requests (#2427) + +- Speed up forced palette rendering (#2422) + +- WMS GetFeatureInfo: honour FEATURE_COUNT for any INFO_FORMAT and + apply the FEATURE_COUNT per layer instead of globally (#2423, #1686) + +- enable soft outlines on truetype labels. This is triggered with a new + keyword OUTLINEWIDTH for the LABEL block (#2417) + +- fix clipping rectangle to take width as well as size into account (#2411) + +- AGG: added and use a line and polygon adaptor to avoid copying shapeObj + points to an agg path_storage. avoids a few mallocs and a few copies. + +- fixed symbolsetObj not to set the SWIG immutable flag permanently + don't expose refcount and the symbol attributes (Ticket #2407) + +- fix for support of entity encoded text in angle follow text (#2403) + +- AGG: initial support for native computation of label sizes (#2357) + +- AGG: support text symbols specified by their character number (#2398) + +- AGG: fix angle orientation for various symbols + +- allow scientific notation for attributes binded to an int (#2394) + +- merge GD and AGG label cache drawing functions (#2390) + +- Enable AGG rendering of bitmap font labels instead of falling back to + GD (#2387) + +- clean up treatment of encoding and wrap character + +- Fix legend label placement for multiline labels (#2382) + +- enforce WRAP parameter in legend label (#2382) + +- AGG: pixel level simplification for line and polygon shapes (#2381) + +- fixed blue/green color swapping for space delimited strings bound to an + attribute. (bug 2378) + +- don't remove points that are checked as being colinear (#2366) + +- add initial(?) support for reading a pie chart's size from an + attribute (#2136) + +- don't bail out in map parsing if the outputformat had to be modified + (bug #2321) + +- use a renderer agnostic legend icon drawing function which switches + to the GD or AGG specific one depending on the outputformat (#2348) + +- AGG: switch alpha buffer when drawing query layer + +- Fixed legend icons not drawing when using maxscaledenom + +- AGG: fix embedded scalebar rendering when using postlabelcache (#2327) + +- AGG: allow for fast and aliased rendering of simple lines and polygons + thick lines and patterns (i.e. dashes)aren't supported. + this is triggered when the symbol is of TYPE SYMBOL *and* its ANTIALIAS + is off (waiting to find a better solution to trigger this). + +- AGG: the pixmap of pixmap symbols is now cached in an agg-compatible state + the first time it is accessed. this avoids rereading and retransforming + it each time that symbol is used. + +- AGG: the imageObj now stores in what state it's alpha channel is in. The + number ofmsAlphaGD2AGG/AGG2GD calls is now reduced, but most importantly + each of these calls is usually just a check for this state and does + no computation. + +- AGG: fixed a few artifacts in embedded legend rendering on rgba images. + +- Fixed modulus operator in the parser (#2323) + +- maprasterquery.c: Fix crash when queries on done on raster layers with + no styles (#2343) + +- maprasterquery.c: Modify msRASTERLayerOpen() to create a defaulted raster + layer info if there isn't one, to avoid the errors about open only being + supported after a query. Also wipe the raster layer info in case of + an empty result set, or failures of a query to reduce likelihood of + leaking the raster layer info. + +- Improve out of memory handling in mapdrawgdal.c, and mapgd.c. (#2351) + +- Improve configuration logic for fastcgi (#2355). + +- WMS: image/wbmp should be image/vnd.wap.wbmp (#2360) + +- SOS: support maxfeatures for GetObservation requests (#2353) + +- mapdraw.c,mapquery.c: Reset layer->project flag for each full layer drawing + or query so that need to reproject will be reconsidered (#673). + +- PHP MapScript: fix for getStdoutBufferString() and getStdoutBufferBytes() + functions on win32 (#2401) + +- mapowscommon.c: fix namespace leak issues (#2375) + +- mapogcsos.c: add SWE DataBlock support (#2248) + +- mapogcsos.c: fix build warnings, namespace and schema pointers (#2248) + +- mappdf.c: support output in fastcgi case via msIO_fwrite() (#2406) + +- mapogcsos.c: Initial support for POST requests (#2379) and updated + msSOSDispatch() handling + +- mapogr.cpp: Use pooling api to ensure per-thread sharing of connections + only (#2408) + +- mapogcsos.c: change substituted variable from sensorid to procedure (#2409) + +- maplibxml2.c: Initial implementation of libxml2 convenience functions + +- configure: Modified so libxml2 support is requested for WCS and SOS, + and is indicated by USE_LIBXML2 definition. Use @ALL_ENABLED@ in + DEFINEs and mapscriptvars generation. + +- mapresample.c: Fixed support for multi-band data in RAW mode for bilinear + and nearest neighbour resamplers (#2364). + +- mapdraw.c: Improve error reporting if a raster layer requested in + a query map (#1842). + +- mapfile.c: add simple urn:ogc:def:crs:OGC::CRS84 support. + + +Version 5.0.0 (2007-09-17) +-------------------------- + +- AGG: Fix angle computation for truetype marker symbols on lines (#2316) + +- Fix support for bilinear resampling of raster data with AGG (#2303) + + +Version 5.0.0-rc2 (2007-09-10) +------------------------------ + +- Prevent seg fault in msWMSLoadGetMapParams when request is missing (#2299) + +- Fixed calculation of scale in PHP MapScript mapObj.zoomScale() (#2300) + +- Fixed conflict between runtime substitution validation and qstring + validation. + +- Fixed agg configure logic (now should work with --with-agg alone) (#2295) + +- Fixed interleaving of multi-band results for raster query (#2294). + + +Version 5.0.0-rc1 (2007-09-05) +------------------------------ + +- Fixed "MinFeatureSize AUTO" labeling for polygon layers, works for polygon + annotation layers too (#2232) + +- Fixed path following labels with short (2/3 character) strings (#2223) + +- AGG fix a bug when rendering polygons with tiled pixmaps + +- Added requirement to provide validation pattern for cgi-based attribute + queries using the layer metadata key 'qstring_validation_pattern' (#2286) + +- Fixed msDebug causing a crash with VS2005 (#2287) + +- Added stronger checks on libpdf version in configure script (#2278) + +- Added msGetVersionInt() to MapScript (ms_GetVersionInt() in PHP) (#2279) + +- _isnan prototype for MSVC builds from #2277 + +- AGG: Fix a bug when rendering brushed lines with vector or pixmap symbols + (artifacts could appear on outline) + +- AGG: Adjust symbol height when brushing a line with a vector symbol so that + the line width isn't truncated + +- Only include process.h on win32 (non-cygwin) systems, moved from + maptemplate.h to mapserver.h. (#2276) + + +Version 5.0.0-beta6 (2007-08-29) +-------------------------------- + +- Fixed problem with outline of polygons rendered twice with OGR + STYLEITEM AUTO and AGG output (#2271) + +- Fixed problem compiling with only WMS/WFS client but none of the + WMS, WFS, WCS or SOS server options enabled (#2272) + +- Fixed buffer overflow in handling of WMS SRS=AUTO:... (#1824) + +- AGG: render thick lines and polygon outlines with round caps and joins + by default + +- Typo in mapfile writing (#2267) + +- Fixed mapping of class->keyimage in PHP MapScript (#2268) + +- Look for libagg under lib64 subdir as well in configure (#2265) + +- AGG: revert previous optimizations. now use caching of the rendering object + to avoid the re-creation of some structures each time a shape is drawn + +- AGG: optimizations for faster rendering. we now do not initialize the font + cache when no text is to be rendered + +- AGG: fixed rendering of polygons with holes (#2264) + +- AGG - raster layers: fix typo in mapresample.c that produced random + background colors when using OFFSITE (#2263) + +- AGG: Fix a bug when rendering tiled polygons with truetype, pixmap or + vector symbols (usually only affected bright colors) + +- Avoid passing null to msInsertHashTable in processLegendTemplate + when layer.name or layer.group not specified (#2261) + +- Fixed problems with fonts in PDF output (#2142) + +- AGG: smooth font shadows + + +Version 5.0.0-beta5 (2007-08-22) +-------------------------------- + +- Fixed XSS vulnerabilities (#2256) + +- Allow building with AGG from source when libaggfontfreetype is missing. + configure --with-agg=DIR now automatically tries to build + agg_font_freetype.o from source if libaggfontfreetype is missing (#2215) + +- Fixed possible buffer overflow in template processing (#2252) + +- fix blending of transparent layers with RGBA images + +- AGG: speed up rendering of pixmap marker symbols + +- Implement OGR thread-safety via use of an OGR lock (#1977). + +- Fixed compile warnings (#2226) + +- Fixed mappdf.c compile warnings, PDF support was probably unusable + before that fix (#2251) + +- Adding -DUSE_GENERIC_MS_NINT to the WIN64 builds (#2250) + +- Adding msSaveImageBuffer and use that function from the mapscript + library instead of the renderer specific functions. (#2241) + +- Split each format into it's own element in WCS describe + coverage results (#2244). + +- Support to run the mapscript c# examples on x64 platform (#2240) + +- Fixed problem introduced in 5.0.0-beta4: all HTML legend icons were + empty white images (#2243) + +- Fixed WMS Client to always send STYLES parameter with WMS GetMap + requests (#2242) + +- Fixed support for label encoding in SVG output (#2239) + +- Added support for label encoding in legend (#2239) + +- Fixed PHP MapScript layer->queryByAttributes() to not accept empty or + null qitem arg (#480) + +- AGG: fixed incorrect rendering of pixmaps on MSB architectures (#2235) + +- Added layer.getFeature() in PHP MapScript with optional tileindex arg, + and deprecated layer.getShape() to match what we had in SWIG (#900) + +- Added class.getTextString() and deprecated/renamed class.getExpression() + and layer.getFilter() to class.getExpressionString() and + layer.getFilterString() to match what we have in SWIG MapScript (#1892) + + +Version 5.0.0-beta4 (2007-08-15) +-------------------------------- + +- Updated msImageCreateAGG to only allow RGB or RGBA pixel models (#2231) + +- Fixed problem with symbol.setImagePath() when file doesn't exist (#1962) + +- Python MapScript failures (#2230) + +- msInsertLayer should not free the incoming layer anymore (#2229) + +- Include only parsed in the first mapfile (#2021) + +- Incorrect lookup of symbol in symbolset (#2227) + +- Mapfile includes and MapScript (#2089) + +- Fixed alignment of GetLegendGraphic output when mapfile contains no + legend object (#966) + +- Fixed seg. fault when generaing HTML legend for raster layers with no + classes (#2228). The same issue was also causing several Chameleon apps + using HTML legend to seg fault (#2218) + +- Do not use case sensitive searches in string2list, which is used + for msWhichItems (#2067) + +- Ensure that we can write AGG images with Python MapScript's write() method + +- Support unicode attributes for ArcSDE 9.2 and above (#2225) + +- GD: Truetype line symbolization should follow line orientation only + if GAP is <=0 + +- AGG: Added truetype symbolization for lines and polygons + +- AGG: Draw an outline of size 1 of the fill color around polygons if an + outlinecolor isn't specified (avoids faint outline) + +- Added summary of options at end of configure output (#1966) + +- Updated configure script to detect and require GEOS 2.2.2+ (#1896) + +- Renamed --enable-coverage configure option to --enable-gcov to avoid + confusion with WCS or Arc/Info coverages (#2217) + +- Fixed --enable-gcov (formerly --enable-coverage) option to work with + php_mapscript.so (#2216) + +- check for OGR support in if SLD is used (#1998) + +- msWMSLoadGetMapParams: fixed handling of required parameters (#1088) + +- if any of srs, bbox, format, width, height are NOT found, throw exception + +- if styles AND sld are NOT found, throw an exception + +- NOTE: this may cause issues with some existing clients who do not pass + required parameters + + +Version 5.0.0-beta3 (2007-08-08) +-------------------------------- + +Known issues: + +- This beta contains significant improvements and fixes on the AGG + rendering front. However some build issues remain on some platforms. + Please see ticket #2215 if building with AGG support doesn't work with + the default configure script: http://trac.osgeo.org/mapserver/ticket/2215 + +Bug fixes: + +- mapagg.cpp rewrite - the AGG renderer should now support all the GD features + +- Use AGG when requested for drawing the legend + +- Fixed problems with very large HTML legends producing no output (#1946) + +- Use OGR-specific destructors for objects that have them rather than + 'delete' (#697) + +- Include style-related info in HTML legend icon filenames to solve issues with + caching of icons when the class or style params are changed (#745) + +- Fixed issues with wms_layer_group metadata in WMS GetCapabilities (#2122) + +- Use msSaveImageBufferAGG for AGG formats in getBytes (#2205). + +- Make sure to emit $(AGG) to mapscriptvars because of conditional inclusion + of struct members to imageObj. (#2205) + +- Make imageextra field in imageObj not conditional (not #ifdef'ed) (#2205) + +- AGG/PNG and AGG/JPEG are the only valid agg drivers. + Imagetypes aggpng24 and aggjpeg can be used to refer to the + default output formats. (#2195) + +- Fix memory leak with labepath object (#2199) + +- Fix memory leak msImageTruetypePolyline (#2200) + +- SWF: Fix incorrect symbol assignments (#2198) + +- Fixed memory leaks in processing of WFS requests (#2077) + +- Avoid use of uninitialised memory in msCopySymbol() (#2194) + + +Version 5.0.0-beta2 (2007-08-01) +-------------------------------- + +- Oracle Spatial: Fixed some issues related with the maporaclespatial.c + source code: warnings with calls in gcc 4.x versions (#1845), gtype + translation error, generating memory problem (#2056), problems with items + allocation (#1961 and #1736), and some memory-leaks errors (#1662). + +- AGG: Fixed a significant number of rendering issues including conflicts with + OPACITY ALPHA and ANTIALIAS TRUE settings w/regards to polygon fills. Fixed + ellipse and vector markers. Fixed AGG/GD alpha channel conflicts by writing + conversion to/from functions. (#2191-partial, #2173, #2177) + +- SOS: Turn layer off if eventTime is not in the sos_offering_timeextent + (#2154) + +- WFS: Correct bugs related to query by featureid support (#2102) + +- WMS: Add svg as a supported format for GetMap request (#1347) + +- WMS: Correct WMS time overriding Filter parameter (#1261) + +- Fix problem with LUT scaling ranges with explicit value for 255 (#2167). + +- WCS: Fixed resampling/reprojecting for tileindex datasets (#2180) + +- Fixed formatting of configure --help (#2182) + +- Fixed AGG configure option to use 'test -f' instead of 'test -e' which + doesn't work on Solaris (#2183) + +- Fixed mapwms.c to support selecting AGG/ outputformats via FORMAT=. + +- Removed unused styleObj.isachild member (#2169) + + +Version 5.0.0-beta1 (2007-07-25) +-------------------------------- + +New features in 5.0: + +- MS RFC 19: Added Style and Label attribute binding + +- MS RFC 21: Raster Color Correction via color lookup table + +- MS RFC 27: Added label priority + +- MS RFC 29: Added dynamic charting (pie and bar charts) + +- MS RFC 31: New mechanism to load/set objects via URL using mapfile syntax + +- MS RFC 32: Added support for map rendering using the AGG library for + better output quality + + +Long time issues resolved in 5.0: + +- MS RFC 17: Use dynamic allocation for symbols, layers, classes and styles + (got rid of the static limit on the number of instances of each in a map) + +- MS RFC 24: Improved memory management and garbage collection for MapScript + +- MS RFC 26: Terminology cleanup (layer transparency renamed to opacity, + scale becomes scaledenom, symbol style becomes symbol pattern) + +- MS RFC 28: Enhanced the debug/logging mechanism to facilitate + troubleshooting and tuning applications. Added support for multiple + debug levels and more control on output location. + + +Other fixes/enhancements in this beta: + +- Upgrade Filter encoding to use geos and support all missing operators (#2105) + +- Use of static color Palette support for gd output (#2096) + +- MapServer's main header file map.h has been renamed mapserver.h (#1437) + +- A mapserver-config script has been created + +- Single and double quotes escaping in string expressions used by FILTER. + (Resolves tickets #2123 and #2141) + +- SLD: Support of Graphic Stroke for a Linesymbolizer (#2139) + +- GD : draw symbols along a line using pixmap symbols (#2121) + +- SVG : Polygons should not be filled if color is not given (#2055) + +- WMS : fixed request with a BBOX and and SLD containing Filter + encoding (2079) + +- SWF : use highlight color from querymap (2074) + +- Support for embedding manifests as resources for the VS2005 builds. + (ticket #2048) + +- Changed OGRLayerGetAutoStyle not to pass NULL pointer to GetRGBFromString + causing access violation (bug 1950). + +- Fix SDE returning the row_id_column multiple times (bug 2040). + +- Fix text outline bug. (bug 2027) + +- Improve error reporting when OWS services are requested but the support + is not compiled in. (bug 2025) + +- Fix support for OFFSITE for simple greyscale rasters (bug 2024). + +- [SLD] : Error on last class in raster class names based on the ColorMapEntry + (bug 1844) + +- [Filter Encoding] : Check if Literal value in Filter is empty (bug 1995) + +- [SLD] : Else filters are now generated at the end of classes (bug 1925) + +- Enabled setting of a layer tileindex (e.g. map_layername_tileindex) via the + CGI program. (bug 1992) + +- Added feature to the CGI to check runtime substitutions against patterns + defined in layer metadata. (bug 1918) + +- Exposed label point computation to mapscript (bug 1979) + +- [SLD]: use the url as symbol name for external symbols (bug 1985) + +- [SLD] : support of mixing static text with column names (bug 1857) + +- maperror.c: fix for wrapping long in image errors, thanks to Chris + Schmidt (bug 1963) + +- maperror.c: fix closing of stderr/stdout after writing error msg (bug 1970) + +- Preliminary implementation of RFC 21 (Raster Color Correction). + +- [SLD] : when reading an SLD, sequence of classes was reversed (Bug 1925) + +- Fixed a bug with SDE capability requests where we were double + freeing because sde->row_id_column wasn't set to NULL in msSDELayerOpen + +- [OGC:SOS] : Fixed bugs related to metadata and xml output + (1731, 1739, 1740, 1741). Fixed bug with large xml output (bug 1938) + +- fixed performance problem in raster reprojection (bug 1944) + +- added msOWSGetLanguage function in mapows.c/h (bug 1955) + +- added mapowscommon.c/mapowscommon.h and updated mapogcsos.c to use + mapowscommon.c functions (bug 1954) + +- added more Perl mapscript examples in mapscript/perl/examples/, most + of which exemplify recently added GEOS functionality + +- php_mapscript.c: Fixed setRotation() method to check for MS_SUCCESS, not + MS_TRUE (bug 1968) + +- mapobject.c: Fixed msMapSetExtent() to avoid trying to calculate the + scale if the map size hasn't been set yet (bug 1968) + +- mapobject.c: ensure msMapComputeGeotransform() returns MS_FAILURE, not + MS_FALSE (bug 1968) + +- mapdraw.c: Actually report that we aren't configure with wms client + support if that is why we can't draw a layer. + +- mapows.c: fixed XML error (bug 2070) + +- mapwms.c: Fixed text/plain output duplicate (bug 1379) + +- mapwms.c: Attribution element output in GetCapabilities only 1.0.7 and + higher (bug 2080) + +- mapwms.c: UserDefinedSymbolization element output in GetCapabilities + only 1.0.7 and higher (bug 2081) + +- mapwms.c: GetLegendGraphic and GetStyles only appear in 1.1.1 and + higher responses (bug 1826) + +- mapwcs.c: + - msWCSDescribeCoverage: throw Exception if Coverage doesn't exist (bug 649) + - msWCSException: updated as per WCS 1.0 Appendix A.6 + +- mapogcsos.c: Added ability to output gml:id via MAP/LAYER/METADATA + ows/sos/gml_featureid (bug 1754) + +- mapcontext.c: Added ogc namespace (#2002) + +- Note that starting with this release the source code is now managed + in Subversion (SVN) instead of CVS and we have migrated from bugzilla + to Trac for bug tracking. + + +Version 4.10.0 (2006-10-04) +--------------------------- + +- No source code changes since 4.10.0-rc1 + +Known issues in 4.10.0: + +- PHP5 not detected properly on Mandriva Linux (bug 1923) + +- Mapfile INCLUDE does not work with relative paths on Windows (bug 1880) + +- Curved labels don't work with multibyte character encodings (bug 1921) + +- Quotes in DATA or CONNECTION strings produce parsing errors (bug 1549) + + + +Version 4.10.0-RC1 (2006-09-27) +------------------------------- + +- SLD: quantity values for raster sld can be float values instead of just + being integer + +- Hiding labelitemindex, labelsizeitemindex, labelangleitemindex + from the SWIG interface (bug 1906) + +- Fixed computation of geotransform to match BBOX (to edges of image) not + map.extent (to center of edge pixels). (bug 1916) + +- mapraster.c: Use msResampleGDALToMap() for "upside down" images. (bug 1904) + + +Version 4.10.0-beta3 (2006-09-06) +--------------------------------- + +- Web Map Context use format metadata when formatlist not available. (bug 1723) + +- Web Map Context boolean values true/false now interpreted. (bug 1692) + +- Added support for MULTIPOLYGON, MULTILINESTRING, and MULTIPOINT in + msShapeFromWKT() when going through OGR (i.e. GEOS disabled) (bug 1891) + +- Fixed MapScript getExpressionString() that was failing on expressions + longer that 256 chars (SWIG) and 512 chars (PHP). (bug 1428) + +- WMSSLD: use Title of Rule if Name not present (bug 1889) + +- Fixed syntax error (for visual c++) in mapimagemap.c. + +- Fixed mapgeos.c problems with multipoint and multilinestring WKT (bug 1897). + +- Implemented translation via OGR to WKT for multipoint, multiline and + multipolygon (bug 1618) + + +Version 4.10.0-beta2 (2006-08-28) +--------------------------------- + +- Applied patch supplied by Vilson Farias for extra commas with imagemap + output (bug 760). + +- Fixed possible heap overflow with oversized POST requests (bug 1885) + +- Set ./lib and ./include properly for MING support (bug 1866) + +- More robust library checking on OSX (bug 1867) + +- Removed mpatrol support (use valgrind instead for something + similar and less intrusive). (bug 1883) + +- Added mapserver compilation flags to the SWIG c# command line (bug 1881) + +- Fix OSX shared library options for PHP (bug 1877). + +- Added setSymbolByName to styleObj for the SWIG mapscript in order to + set both the symbol and the symbolname members (bug 1835) + +- Generate ogc filters now outputs the ocg name space (bug 1863) + +- Don't return a WCS ref in WMS DescribeLayer responses when layer type is + CONNECTIONTYPE WMS (cascaded WMS layers not supported for WCS) (bug 1874) + +- Correct partly the problem of translating regex to ogc:Literal (bug 1644) + +- schemas.opengeospatial.net has been shutdown, use schemas.opengis.net + instead as the default schema repository for OGC services (bug 1873) + +- MIGRATION_GUIDE.TXT has been created to document backwards incompatible + changes between 4.8 and 4.10 + +- Modify mapgd.c to use MS_NINT_GENERIC to avoid rounding issues. (bug 1716) + +- added --disable-fast-nint configure directive (bug 1716) + +- Fixed php_mapscript Windows build that was broken in beta1 (bug 1872) + +- Supported tag in SLD label (Bug 1857) + +- Use the label element in the ColorMapEntry for the raster symbolizer + (Bug 1844) + +- Adding Geos functions to php mapscript (bug 1327) + +- Added a type cast to msio.i so as to eliminate the warning with the + SWIG unix/osx builds + +- Fixed csharp/Makefile.in for supporting the OSX builds and creating + the platform dependent mapscript_csharp.dll.config file. + +- Fixed error in detection of libpdf.sl in configure.in (bug 1868). + + +Version 4.10.0-beta1 (2006-08-17) +--------------------------------- + +- Marking the following SWIG object members immutable (bug 1803) + layerObj.metadata, classObj.label, classObj.metadata, + fontSetObj.fonts, legendObj.label, mapObj.symbolset, + mapObj.fontset, mapObj.labelcache, mapObj.reference, + mapObj.scalebar, mapObj.legend, mapObj.querymap + mapObj.web, mapObj.configoptions, webObj.metadata, + imageObj.format, classObj.layer, legendObj.map, + webObj.map, referenceMapObj.map + labelPathObj was made completely hidden (according to Steve's suggestion) + +- Fixed problem with PHP MapScript's saveWebImage() filename collisions + when mapscript was loaded in php.ini with PHP as an Apache DSO (bug 1322) + +- Produce warning in WFS GetFeature output if ???_featureid is specified + but corresponding item is not found in layer (bug 1781). Also produce + a warning in GetCapabilities if ???_featureid not set (bug 1782) + +- Removed the default preallocation of 4 values causing memory leaks. + (related to bug 1801) Added initValues to achieve the similar + functionality if needed. + +- Fixed error in msAddImageSymbol() where a symbol's imagepath was not + set (bug 1832). + +- Added INCLUDE capability in mapfile parser (bug 279) + +- Revert changes to mapzoom.i that swapped miny and maxy (Bug 1817). + +- MapScript (swig) creation of an outputFormatObj will now set the inmapfile + flag so that it gets written out to saved maps by default (Bug 1816). + +- Converted GEOS support to use the GEOS C-API (versiopn 2.2.2 and higher). + Wrapped remaining relevant GEOS functionality and exposed via SWIG-based + MapScript. + +- If a layer has wms_timedefault metadata, make sure it is applied even + if there is no TIME= item in the url. (Bug 1810) + +- Support for GEOS/ICONV/XML2 use flags in Java Makefile.in (related to + bug 1801) + +- Missing GEOS support caused heap corruption using shapeObj C# on linux + (Bug 1801) + +- Fix time filter propagation for raster layers to their tileindex layers. + New code in maprasterquery.c (bug 1809) + +- Added logic to collect LD_SHARED even if PHP not requested in configure. + +- Fix problems with msio/rfc16 stuff on windows. Don't depend on comparing + function pointers or "stdio" handles. (mapio.c, mapio.h, msio.i) + +- Support WMC Min/Max scale in write mode (bug 1581) + +- Fixed leak of shapefile handles (shp/shx/dbf) on tiled layers (bug 1802) + +- Added webObj constructor and destructor to swig interface with + calls to initWeb and freeWeb (bug 1798). + +- mapows.c: ensure msOWSDispatch() is always available even if there are + no services to dispatch. This makes mapscript binding easier. + +- FLTAddToLayerResultCache wasn't properly closing the layer after it + was done with it. + +- Added ability to encrypt tokens (passwords, etc.) in database connection + strings (MS-RFC-18, bug 1792) + +- Fixed zoomRectangle in mapscript: miny and maxy were swapped, making it + impossible to zoom by rect; also the error message was referring to the + wrong rect. There were no open issues on bugzilla. Reverted because of 1817. + +- Implementation of RFC 16 mapio services (bug 1788). + +- Use lp->layerinfo for OGR connections (instead of ogrlayerinfo) (bug 331) + +- Support treating POLYGONZ as MS_SHAPE_POLYGON. (bug 1784) + +- Complete support for international languages in Java Mapscript + (bug 1753) + +- Output feature id as @fid instead of @gml:id in WFS 1.0.0 / GML 2.1.2 + GetFeature requests (bug 1759) + +- Allow use of wms/ows_include_items and wms/ows_exclude_items to control + which items to output in text/plain GetFeatureInfo. Making the behavior + of this INFO_FORMAT consistent with the new behavior of GML GetFeatureInfo + output introduced in v4.8. (bug 1761) + IMPORTANT NOTE: With this change if the *_include_items metadata + is not specified for a given layer then no items are output for that layer + (previous behavior was to always all items by default in text/plain) + +- Make sure mappostgis.c closes MYCURSOR in layer close function so that + CLOSE_CONNECTION=DEFER works properly. (bug 1757) + +- Support large (>2GB) raster files relative to SHAPEPATH. (bug 1748) + +- Set User-Agent in HTTP headers of client WMS/WFS connections (bug 1749) + +- Detection of os-dependent Java headers for Java mapscript (bug 1209) + +- Preventing to take ownership of the memory when constructing objects + with parent objects using C# mapscript (causing nullreference exception, Bug 1743) + +- SWF: Adding format option to turn off loading movies automatically (Bug 1696) + +- Fixed FP exception in mapgd.c when pixmap symbol 'sizey' not set (bug 1735) + +- Added config file for mapping the library file so the DllImport + is looking for to its unix equivalent (Bug 1596) Thanks to Scott Ellington + +- Added /csharp/Makefile.in for supporting the creation of Makefile + during configuration with MONO/Linux (fix for bug 1595 and 1597) + +- Added C# typemaps for char** and outputFormatObj** + +- Support for dispatching multiple error messages to the MapScript interface (bug 1704). + +- Fix inter-tile "cracking" problem (Bug 1715). + +- OGC FILTER: Correct bug when generating an sql expression containing an escape + character. + +- Allow a user to set a PROCESSING directive for an SDE layer to specify + using the attributes or spatial index first. (bug 1708). + +- Cheap and easy way of fudging the boundary extents for msSDEWhichShapes + in the case where the rectangle is really a point (bug 1699). + +- Implement QUANTIZE options for GD/PNG driver (Bug 1690, Bug 1701). + +- WMS: Publish the GetStyles operation in the capabilities document. + +- PHP_MAPSCRIPT: Add antialias parameter in the style object (Bug 1685) + +- WFS: Add the possibility to set wfs_maxfeatures to 0 (Bug 1678) + +- SLD: set the default color on the style when using default settings + in PointSymbolizer. (bug 1681) + +- Incorporate range coloring support for rasters (bug 1673) + +- Fixed mapthread.c looking for the unix compiler symbol rather than just + testing whether or not _WIN32 is defined for the usage of posix threads + because unix is not defined on compilers like GCC 4.0.1 for OS X. + +- Fixed the fuzzy brush support so that the transition between 1 pixel aa lines + and brushes is less obvious. The old code would not allow for a 3x3 fuzzy + brush to be built. (bug 1659) + +- Added missing mapscript function msConnPoolCloseUnreferenced() (bug 1661) + We need to make conn. pooling handling transparent to mapscript users + so that they do not have to call this function once in a while, for instance + by creating an evictor thread. + +- Added calls to msSetup/msCleanup() at MapScript load/unload time (bug 1665) + +- Reorganized nmake.opt to be more focused on functionality groups rather + than the propensity of a section to be edited. Default values are now + all set to be pointed at the MapServer Build Kit, which can be obtained + at http://hobu.stat.iastate.edu/mapserver/ + +- configure.in/Makefile.in: Use PROJ_LIBS instead of PROJ_LIB. PROJ_LIB + is sometimes defined in the environment, but points to $prefix/share/proj + not the proj link libraries. + +- Update Web Map Context to 1.1.0, add the dimension support. (bug 1581) + +- Support SLD body in context document. (bug 887) + +- When generating an ogc filter for class regex expressions, use + the backslah as the default escape character (Bug 1637) + +- Add connectiontype initialization logic when the layer's virtual + table is initialized (Bug 1615) + +- Added modulus operator to mapparser.y. + +- Added new support for [item...] tag in CGI-based templates (bug 1636) + +- Reverted behavior to pre-1.61: + do not allow for use of the FILTERITEM attribute (bug 1629) + +- Treat classindex as an int instead of a char in resultCacheMemberObj to + prevent problems with more than 128 classes (bug 1633) + +- WMS : SLD / stretch images when using FE (Bug 1627) + +- Add gml:lineStringMember in GML2 MultiLineString geometry (bug 1569). + +- PHP : add shape->sontainsshape that uses geos lib (Bug 1623). + +- Move gBYTE_ORDER inside the pg layerinfo structure to allow for differently + byte ordered connections (bug 1587). + +- Fix the memory allocation bug in sdeShapeCopy (Bug 1606) + +- Fixed OGR WKT support (Bug 1614). + +- Added shapeObj::toWkt() and ms_shapeObjFromWkt() to PHP MapScript (bug 1466) + +- Finished implementation of OGR Shape2WKT function (Bug 1614). + +- Detect/add -DHAVE_VSNPRINTF in configure script and prevent systematic + buffer overflow in imagemap code when vsnprintf() not available (bug 1613) + +- Default layer->project to MS_TRUE even if no projection is set, to allow + geotransforms (nonsquare pixels, etc) to be applied (bug 1645). + +- Force stdin into binary mode on win32 when reading post bodies. (bug 1768) + + +Version 4.8.0-rc2 (2006-01-09) +------------------------------ + +- Commit fix for GD on win32 when different heaps are in use. (Bug 1513) + +- Correct bound reprojection issue with ogc filer (Bug 1600) + +- Correct mapscript windows build problem when flag USE_WMS_SVR was + not set (Bug 1529) + +- Fix up allocation of the SDE ROW_ID columns and how the functions that + call it were using it. (bug 1605) + +- Fixed crash with 3D polygons in Oracle Spatial (bug 1593) + + +Version 4.8.0-rc1 (2005-12-22) +------------------------------ + +- Fixed shape projection to recompute shape bounds. (Bug 1586) + +- Fixed segfault when copying/removing styles via MapScript. (Bug 1565) + +- Fixed segfault when doing attribute queries on layers with a FILTER already + set but with no FILTERITEM. + + +Version 4.8.0-beta3 (2005-12-16) +-------------------------------- + +- Initialize properly variable in php mapscript (Bug 1584) + +- New support for pseudo anti-aliased fat lines using brushes with variable + transparency. + +- Arbitrary rotation support for vector symbols courtesy of Map Media. + +- Support for user-defined mime-types for CGI-based browse and legend + templates (bug 1518). + +- mapraster.c: Allow mapresample.c code to be called even if projections + are not set on the map or layer object. This is no longer a requirement. + (Bug 1562) + +- Fix problem with WMS 1.1.1 OGC test problem with get capabilities dtd + (Bug 1576) + +- PDF : adding dash line support (Bug 492) + +- Fixed configure/build problem (empty include dir) when iconv.h is not + found (bug 1419) + +- PDF : segfault on annotation layer when no style is set (Bug 1559) + +- PostGIS layer test cases and fix for broken views and sub-selects (bug 1443). + +- SDE: Removed (commented out) support for SDE rasters at this time. As far + as I know, I'm the only one to ever get it to work, it hasn't kept up with + the connection pooling stuff we did, and its utility is quite limited in + comparison to regular gdal-based raster support (projections, + resampling, etc) (HB - bug 1560). + +- SDE: Put msSDELayerGetRowIDColumn at the top of mapsde.c so things + would compile correctly. This function is not included (or necessary) + in the rest of the MS RFC 3 layer virtualization at this time. + +- WFS : TYPENAME is manadatory for GetFeature request (Bug 1554). + +- SLD : error parsing font parameters with the keyword "normal" (Bug 1552) + +- mapgraticule.c: Use MIN/MAXINTERVAL value when we define grid position and + interval (bug 1530) + +- mapdrawgdal.c: Fix bug with nodata values not in the color table when + rendering some raster layers (bug 1541). + +- mapogcsld.c : If a RULE name is not given, set the class name to "Unknown" + (Bug 1451) + +Version 4.8.0-beta2 (2005-11-23) +-------------------------------- + +- Use dynamic allocation for ellipse symbol's STYLE array, avoiding the + static limitation on the STYLE argument values. (bug 1539) + +- Fix bug in mapproject.c when splitting over the horizon lines. + +- Fix Tcl mapscript's getBytes method (bug 1533). + +- Use mapscript.i in-place when building Ruby mapscript, copying not necessary + (bug 1528). + +- Expose maximum lengths of layer, class, and style arrays in mapscript (bug + 1522). + +- correct msGetVersion to indicate if mapserver was build with MYGIS support. + +- Fixed hang in msProjectRect() for very small rectangles due to round off + problems (bug 1526). + + +Version 4.8.0-beta1 (2005-11-04) +-------------------------------- + +- Bug 1509: Fixed bounding box calculation in mapresample.c. The bottom right + corner was being missed in the calculation. + +- MS RFC 2: added OGR based shape<->WKT implementation. + +- mapgdal.c: fixed some mutex lock release issues on error conditions. + +- MS RFC 8: External plugin layer providers (bug 1477) + +- SLD : syntax error when auto generating external symbols (Bug 1508). + +- MS RFC 3: Layer vtable architecture (bug 1477) + +- wms time : correct a problem when handling wms times with tile index rasters + (bug 1506). + +- WMS TIME : Add support for multiple interval extents (Bug 1498) + +- Removed deprecated --with-php-regex-dir switch (bug 1468) + +- support wms_attribution element for LAYER's (Bug 1502) + +- Correct php/mapscript bug : initialization of scale happens when + preparequery is called (Bug 1334). + +- msProjectShape() will now project the lines it can, but completely + delete lines that cannot be projected properly and "NULL" the shape if + there are no lines left. (Bug 411) + +- Expose msLayerWhichShapes and msLayerNextShape in MapScript. (bug 1481) + +- Added support to MapScript to change images in a previously defined + symbol. (bug 1471) + +- mapogcfiler.c : bug 1490. Crash when size of sld filters was huge. + +- Fixed --enable-point-z-m fix in configure.in (== -> =) (bug 1485). + +- Extra scalebar layer creation is prevented with a typo fix in mapscale.c. + Good catch, Tamas (bug 1480). + +- mapwmslayer.c : use transparency set at the layer level on wms client + layers (Bug 1458) + +- mapresample.c: added BILINEAR/AVERAGE resampling options. + +- mapfile.c: avoid tail recursion in freeFeatureList(). + +- maplegend.c: fixed leak of imageObj when embedding legends. + +- msGDALCleanup(): better error handler cleanup. + +- Modified msResetErrorList() to free the last error link too, to ensure + msCleanup() scrubs all error related memory. + +- Fix in msGetGDALGetTransform() to use default geotransform even if + GDALGetGeoTransform() fails but alters the geotransform array. + +- Typemaps for C# to enable imageObj.getBytes() method (bug 1389). + +- Enable -DUSE_ZLIB via configure for compressed SVG output (bug 1307). + +- maputil.c/msAddLine(): rewrite msAddLine() to call + msAddLineDirectly, and use realloc() in msAddLineDirectly() to optimize + growth of shapeObjs. (bug 1432) + +- msTmpFile: ensure counter is incremented to avoid duplicate + temporary filenames. (bug 1312) + +- SLD external graphic symbol format tests now for mime type + like image/gif instead of just GIF. (bug 1430) + +- Added support for OGR layers to use SQL type filers (bug 1292) + +- mapio/cgiutil - fixed POST support in fastcgi mode. (bug 1259) + +- mapresample.c - ensure that multi-band raw results can be + resampled. (bug 1372) + +- Add support in OGC FE for matchCase attribute on + PropertyIsEqual and PropertyIsLike (bug 1416) + +- Fixed sortshp.c to free shapes after processing to avoid major + memory leak. (bug 1418) + +- fixed msHTTPInit() not ever being called which prevented msHTTPCleanup() + from properly cleaning up cUrl with curl_global_cleanup(). (bug 1417) + +- mapsde.c: add thread locking in msSDELCacheAdd + +- fixed mappool.c so that any thread can release a connection, + not just it's allocator. (bug 1402) + +- mapthread.c/h: Added TLOCK_SDE and TLOCK_ORACLE - not used yet. + +- Fixed copying of layer and join items. (bug 1403) + +- Fixed copying of processing directives within copy of a layer. (bug 1399) + +- Problems with string initialization. (bug 1312) + +- Fix svg output for multipolygons. (bug 1390) + +- Added querymapObj to PHP MapScript (bug 535) + + +Version 4.6.0 (2005-06-14) +-------------------------- + +- Bug 1163 : Filter Encoding spatial operator is Intersects + and not Intersect. + +- Fixed GEOS to shapeObj for multipolgon geometries. + + +Version 4.6.0-rc1 (2005-06-09) +------------------------------ + +- Bug 1375: Fixed seg fault in mapscript caused by the USE_POINT_Z_M flag. + This flag was not carried to the mapscript Makefile(s). + +- Bug 1367: Fixed PHP MapScript's symbolObj->setPoints() to correctly + set symbolObj->sizex/sizey + +- Bug 1373: Added $layerObj->removeClass() to PHP MapScript (was already + in SWIG MapScript) + + +Version 4.6.0-beta3 (2005-05-27) +-------------------------------- + +- Bug 1298 : enable Attribution element in wms Capabilities XML + +- Bug 1354: Added a regex wrapper, allowing MapServer to build with PHP + compiled with its builtin regex + +- Bug 1364: HTML legend templates: support [if] tests on "group_name" in + leg_group_html blocks, and for "class_name" in leg_class_html blocks. + +- Bug 1149: From WMS 1.1.1, SRS are given in individual tags in root Layer + element. + +- First pass at properly handling XML exceptions from CONNECTIONTYPE WMS + layers. Still needs some work. (bug 1246) + +- map.h/mapdraw.c: removed MAX/MIN macros in favour of MS_MAX/MS_MIN. + +- Bug 1341, 1342 : Parse the unit parameter for DWithin filter request. + Set the layer tolerance and toleranceunit with parameters parsed. + +- Bug 1277 : Support of multiple logical operators in Filter Encoding. + +- mapwcs.c: If msDrawRasterLayerLow() fails, ensure that the error message + is posted as a WCS exception. + +- Added experimental support for "labelcache_map_edge_buffer" metadata to + define a buffer area with no labels around the edge of a map (bug 1353) + + +Version 4.6.0-beta2 (2005-05-11) +-------------------------------- + +- Bug 179 : add a small buffer around the cliping rectangle to + avoid lines around the edges. + +- Finished code to convert back and forth between GEOS geometries. Buffer and + convex hull operations are exposed in mapscript. + +- fontset.fonts hash now exposed in mapscript (bug 1345). + +- Bug 1336 : Retrieve distance value for DWithin filter request + done with line and polygon shapes/ + +- Bug 985 / 1015: Don't render raster layers as classified if none of + the classes has an expression set (gdal renderer only). + +- Bug 1344: Fixed several issues in writing of inline SYMBOLS when saving + mapfile (missing quotes around CHARACTER and other string members of SYMBOL + object, check for NULLs, and write correct identifiers for POSITION, + LINECAP and LINEJOIN). + + +Version 4.6.0-beta1 (2005-04-26) +-------------------------------- + +- Bug 1305: Added support for gradient coloring in class styles + +- Bug 1335 : missing call to msInitShape in function msQueryByShape + +- Bug 804 : SWF output : Make sure that the layer index is consistent + when saving movies if some of the layers are not drawn (because the + status is off or out of scale ...) + +- Bug 1332 - shptreevis.c: fixed setting of this_rec, as the output dbf + file was not getting any records at all. + +- Fixed Makefile.vc to make .exe files depend on the DLL, so if the DLL + fails to build, things will stop. Avoids the need for unnecessary + cleans on win32. Also fixed the rule for MS_VERSION for mapscriptvars. + +- Bug 1262 : the SERVICE parameter is now required for wms and wfs + GetCapbilities request. It is not required for other WMS requests. + It is required for all WFS requests. + +- Bug 1302 : the wfs/ows_service parameter is not used any more. The + service is always set to WFS for WFS layers. + +- Bug 791: initialize some fields in msDBFCreate() - avoids crashes in + some circumstances. + +- Bug 1329 : Apply sld named layer on all layers of the same group + +- Bug 1328 : support style's width parameter for line and polygon layers. + +- Bug 564: Fixed old problem with labels occasionally drawn upside down + +- Bug 1325: php mapscript function $class->settext needs only 1 argument. + +- Bug 1319: Fixed mutex creation (was creator-owned) in mapthread.c. win32 + issue only. + +- Bug 1103: Set the default tolerance value based on the layer type. + The default is now 3 for point and line layers and 0 for all the others. + +- Bug 1244: Removing Z and M parameter from pointObj by default. A new + compilation option is available to active those option --enable-point-z-m. + This gives an overall performance gain around 7 to 10%. + +- Bug 1225: MapServer now requires GD 2.0.16 or more recent + +- MapScript: shapeObj allocates memory for 4 value strings, shapeObj.setValue() + lets users set values of a shapeObj. + +- MapScript: imageObj.getBytes() replaces imageObj.write() (bugs 1176, 1064). + +- Bug 1308: Correction of SQL expression generated on wfs filters for + postgis/oracle layers. + +- Bug 1304: Avoid extra white space in gml:coordinates for gml:Box. + +- mapogr.c: Insure that tile index reading is restarted in + msOGRLayerInitItemInfo() or else fastcgi repeat requests for a layer may + fail on subsequent renders. + +- mapogr.c: Set a real OGRPolygon spatial filter, not just an OGRLinearRing. + Otherwise GEOS enabled OGR builds will do expensive, and + incorrect Intersects() tests. + +- mapogr.cpp / mapprimitive.c: Optimize msAddLine() and add msAddLineDirectly() + +- mapprimitive.c: Optimizations in msTransformShapeToPixel() (avoid division) + +- map.h: Made MS_NINT inline assembly for win32, linux/i86. + +- mapprimitive.c: optimized msClipPolygonRect and msClipPolylineRect for + case where the shape is completely inside the clip rect. + +- Add support for SVG output. See Bug 1281 for details. + +- Bug 1231: use mimetype "image/png; mode=24bits" for 24bit png format. + This makes it separately selectable by WMS. + +- Bug 1206: Applied locking patch for expression parser for rasters. + +- Bug 1273: Fixed case in msProjectPoint() were in or out are NULL and + a failure occurs to return NULL. Fixed problem of WMS capabilities with + 'inf' in it. + +- SLD generation bug 1150 : replacing tag to + +- Fixed bug 1118 in msOWSGetLayerExtent() (mapows.c). + +- Fixed ogcfilter bug #1252 + +- Turned all C++ (//) comments into C comments (bug 1238) + +- mapproject.h/configure.in: Don't check for USE_PROJ_API_H anymore. Assume + we have a modern PROJ.4. + +- Bug 839: Fix memory leak of font name in label cache (in mapfile.c). + +- Added msForceTmpFileBase() and mapserv -tmpbase switch to allow overriding + temporary file naming conventions. Mainly intended to make writing + testscripts using mapserv easier. FrankW. + +- maporaclespatil.c: Bug fix for: #1109, #1110, #1111, #1112, #1136, #1210, + #1211, #1212, #1213. Support for compound polygons, fixed internal sql to + stay more accurate for geodetic data, added the support for getextent + function. Added VERSION token for layer data string. + +- mapimagemap.c: Preliminary implementation of support for emitting + MS_SYMBOL_VECTOR symbols in msDrawMarkerSymbolIM(). + +- Bug 1204: Added multi-threading support in mapthread.c. List of connections + is managed within a mutex lock, and connections are only allowed to be used + by one thread at a time. + +- Bug 1185 : php/mapscript : add constant MS_GD_ALPHA + +- Bug 1173: In HTML legend, added opt_flag support for layer groups. + +- Bug 1179: added --with-warnings configure switch, overhauled warning logic. + +- Bug 1168: Improve autoscaling through classification rounding issues. + +- Fixed bug writing RGB/RGBA images via GDAL output on bigendian systems. + +- Bug 1152 : Fix WMS style capabilities output for FastCGI enabled builds. + +- Bug 1135 : Added support for rotating labels with the map if they were + rendered with some particular angle already. + +- Bug 1143 : Missing call to msInitShape. + +- Fixed PHP5 support for windows : Bug 1100. + +- Correct bug 1151 : generates twice a tag when generating an SLD. + This was happening the style did not have a size set. + +- Oracle Spatial. Fixed problem with LayerClose function. Added token NONE + for DATA statement. Thanks Valik with the hints about the LayerClose problem + and Francois with the hints about NONE token. + +- numpoints and stylelength members of the symbol object needs to be in sync + with the low level values after calls to setpoints ans setstyle (Bug 1137). + +- Use doubles instead of integers in function php3_ms_symbol_setPoints + (Bug 1137). + +- Change the output of the expression when using a wild card for + PropertyIsLike (Bug 1107). + +- Delete temporary sld file created on disk (Bug 1123) + +- Fixed msFreeFileCtx() to call free() instead of gdFree() as per bug 1125. + Also renamed gdFreeFileCtx() to msFreeFileCtx(). + +- Ensure error stack is cleared before accepting another call in FastCGI + mode in mapserv.c. Bug 1122 + +- Support translation of all geometry types to points in mapogr.cpp (now + also supports multipolygon, multilinestring and geometrycollection. + bug 1124. + +- Added support for passing OGR layer FILTER queries down to OGR via the + SetAttributeFilter() method if prefixed with WHERE keyword. Bug 1126. + +- Fixed support for SIZEUNITS based scaling of text when map is rotated. + Bug 1127. + + +Version 4.4.0 (2004-11-29) +-------------------------- + +- Fixed WMS GetCapabilities 1.1.0 crash when wms_style_<...>_legendurl_* + metadata were used (bug 1096) + +- WCS GetCapabilities : Added ResponsibleParty support. + +- WMS GetCapabilities : Service online resource was not url encoded (bug 1093) + +- Fixed php mapscript problem with wfs_filter selection : Bug 1092. + +- Fixed encoding problem with WFS server when wfs_service_onlineresource + was not explicitly specified (bug 1082) + +- Add trailing "?" or "&" to connection string when required in WFS + client layers using GET method (bug 1082) + +- Fixed : SLD rasters was failing when there was Spatial Filter (Bug 1087) + +- Fixed mapwfslayer.c build error when WFS was not enabled (bug 1083) + +- Check that we have vsnprintf in mapimagemap.c before using it. + + +Version 4.4.0-beta3 (2004-11-22) +-------------------------------- + +- Added tests to minimize the threat of recursion problems when evaluating + LAYER REQUIRES or LABELREQUIRES expressions. Note that via MapScript it + is possible to circumvent that test by defining layers with problems + after running prepareImage. Other things crop up in that case too (symbol + scaling dies) so it should be considered bad programming practice + (bug 1059). + +- Added --with-sderaster configure option. + +- Make sure that msDrawWMSLayerLow calls msDrawLayer instead of + msDrawRasterLayerLow directly ensuring that some logic (transparency) that + are in msDrawLayer are applied (bug 541). + +- Force GD/JPEG outputFormatObjects to IMAGEMODE RGB and TRANSPARENT OFF + if they are RGBA or ON. Makes user error such as in bug 1703 less likely. + +- Advertise only gd and gdal formats for wms capabilities (bug 455). + +- Pass config option GML_FIELDTYPES=ALWAYS_STRING to OGR so that all GML + attributes are returned as strings to MapServer. This is most efficient + and prevents problems with autodetection of some attribute types (bug 1043). + +- msOGCWKT2ProjectionObj() now uses the OGRSpatialReference::SetFromUserInput() + method. This allows various convenient setting options, including the + ability to handle ESRI WKT by prefixing the WKT string with "ESRI::". + +- Fixed GetLegendGraphic in WMS Capabilities that were missing the '?' + or '&' separator if it was not included in wms_onlineresource (bug 1065). + +- Updated WMS/WFS client and server code to lookup "ows_*" metadata names + in addition to the default "wms_*" (or "wfs_*") metadatas (WCS was already + implemented this way). This reduces the amount of duplication in mapfiles + that support multiple OGC interfaces since "ows_*" metadata can be used + almost everywhere for common metadata items shared by multiple OGC + interfaces (bug 568). + +- Added ows_service_onlineresource metadata for WMS/WFS to distinguish + between service and GetMap/Capabilities onlineresources (bug 375). + +- Added map->setSize() to PHP MapScript (bug 1066). + +- Re-enabled building PHP MapScript using PHP's bundled regex/*.o. This is + needed to build in an environment with PHP configured as an Apache DSO + (bugs 990, 520). + +- Fixed problem with raster dither support on windows (related to ascii + encoding pointers) (bug 722). + +- Moved PHP/SWIG MapScript layer->getExtent() logic down to msLayerGetExtent() + to avoid code duplication (bug 1051). + +- Added SDE Raster drawing support (experimental). + +- HTML legends: Added [leg_header_html] and [leg_footer_html] (bug 1032). + +- Added "z" support in SWIG MapScript for pointObj (bug 871). + +- In PHP Mpascript when using ms_newrectobj, the members minx, miny, + maxx, maxy are initialized to -1 (bug 788). + +- Write out proper world file with remote WMS result, it was off by half + a pixel (bug 1050). + +- Send a warning in the wms capabilities if the layer status is set + to default (bug 638). + +- Fixed PHP MapScript compile warnings: dereferencing type-punned pointer + will break strict-aliasing rules (bug 1053). + +- Added $layer->isVisible() to PHP MapScript (bug 539). + +- Ported $layer->getExtent() to PHP MapScript (bug 826). + +- wms_group_abstract can now be used in the capabilities (bug 754). + +- If wms_stylelist is an empty string, do not output the tag + for MapContexts (bug 595). + +- Avoid passing FILE* to GD library by utilizing GD's gdIOCtx interface + (bug 1047). + +- Output warning in wms/wfs capabilities document if layer,group,map names have + space in them (bug 486, bug 646). + +- maporaclespatial.c: fixed declarations problems (bug 1044). + +- Allow use of msOWSPrintURLType with no metadata. In this case the default + parameters will be used (bug 1001). + +- Ensure the outputFormatObj attached to msImageLoadGDStream() results reflect + the interlacedness of the loaded image. Also ensure that the RGB PNG + reference images work (make imagemode match gdImg) (bug 1039). + +- Fixed support for non-square pixels in WCS (bug 1014). + +- Expose only GD formats for GetLegendGraphic in the capabilities (bug 1001). + +- Check for supported formats when process a GetLegendGraphic request + (bug 1030). + +- mapraster.c: fixed problem with leaks in tileindexed case where the + tile index is missing (bug 713). + +- Oracle Spatial: implemented connection pool support for Oracle Spatial. + New layer data parameters to support query functions, added + "using unique ". Added "FILTER", "RELATE" and "GEOMRELATE" + parameters, now permit users to choose the Oracle Spatial Filter. Modified + the internal SQL to always apply FILTER function. And improve the Oracle + Spatial performance. + +- Centralize "stdout binary mode setting" for win32 in msIO_needBinaryStdout(). + Use it when writing GDAL files to stdout in mapgdal.c. Fixes problems with + output of binary files from GDAL outputformat drivers on win32 via WMS/WCS. + +- MapServer now provides one default style named (default), title and + LegendURL when generating capabilities. Added also the possibility to use + the keyword default for STYLES parameter when doing a GetMap + (..&STYLES=default,defeault,...) (bug 1001). + +- Add xlink:type="simple" in WMS MetadataURL (bug 1027). + + +Version 4.4.0-beta2 (2004-11-03) +-------------------------------- + +- free mapServObj properly in mapserv.c in OWS dispatch case to fix minor + memory leaks. + +- modified msCloseConnections() to also close raster layers so that + held raster query results will be freed. + +- modified raster queries to properly set the classindex in the resultcache. + +- modified msDrawQueryCache() to be very careful to not try and lookup + information on out-of-range classindex values. This seems to occur when + default shapes come back with a classindex of 0 even if there are no classes. + (ie. raster query results). + +- the loadmapcontext function has changed it behavior. Before the 4.4 release + when loading layers from a map context, the layer name was built using + a unique prefix + the name found in the context (eg for the 2nd layer in + map context named park, the layer name generated would possibly be l:2:park). + Now the loadmapcontext takes a 2nd optional argument to force the creation + of the unique names. The default behavior is now to have the layer name + equals to the name found in the context file (bug 1023). + +- Fixed problem with WMS GetCapabilities aborting when wms_layer_group is + used for some layers but not for all (bug 1024). + +- Changed raster queries to return the list of all pixel values as an + attribute named "value_list" rather than "values" to avoid conflict with + special [values] substitution rule in maptemplate.c. + +- Fixed raster queries to reproject results back to map projection, and to + do point queries distance checking against the correct projection (bug 1021). + +- Get rid of WMS 1.0.8 support. It's not an officially supported version + of the spec anyway: it's synonymous for 1.1.0 (bug 1022). + +- Allow use of '=' inside HTML template tag parser (bug 978). + +- Use metadata ows_schema_location for WMS/WFS/WCS/SLD (bugs 999, 1013, 938). + The default value if metadata is not found is + http://schemas.opengeospatial.net. + +- Generate a RULE tag when generating an SLD (bug 1010). + +- WMS GetLegendGraphic uses now the RULE value to return an icon for + a class that has the same name as the RULE value (bug 843). + +- Add msOWSPrintURLType: This function is a generic URL printing function for + OGC specification metadata (WMS, WFS, WCS, WMC, etc.) (bug 944). + +- Support MetadataURL, DataURL and LegendURL tags in WMS capabilities + document and MetadataURL in WFS capabilities. + +- SWIG mapscript: clone methods for layerObj, classObj, styleObj (bug 1012). + +- Implemented an intarray helper class for SWIG mapscript which allows for + multi-language manipulation of layer drawing order (bugs 853, 1005). + +- Fixed WMS GetLegendGraphic which was returning an exception (GD error) + when requested layer was out of scale (bug 1006). + +- Fixed maplexer.l to work with flex 2.5.31 (bug 975). + +- WMS GetMap requests now have MS_NONSQUARE enabled by default. This means + that if the width/height ratio doesn't match the extent's x/y ratio then + the map is stretched as stated in the WMS specification (bug 862). + +- In WMS, layers with no explicit projection defined will receive a copy + of the map's projectionObj if a new SRS is specified in the GetMap request + or if MS_NONSQUARE is enabled. This will prevent the problem with layers + that don't show up in WMS request when the server administrator forgets + to explicitly set projections on all the layers in a WMS mapfile (bug 947). + +- Implemented FastCGI cleanup support for win32 and unix in mapserv.c. + +- Solved configure/compile issues with libiconv (bugs 909, 1017). + + +Version 4.4.0-beta1 (2004-10-21) +-------------------------------- + +- "shared" compilation target now supports some kind of versioning, + should at least prevent libmap.so version collisions when upgrading + MapServer on a server (bug 982). + +- When no RULE parameter has been specified in the WMS request + a legend should be returned with all classes for the specified LAYER. + Changes has been made in mapwms.c (bug 653). Also if the SCALE parameter + is provided in the WMS request is will be used to determine whether + the legend of the specified layer should be drawn in the case that the + layer is scale dependent (big 809). + +- Nested layers in the capabilities are supported by using a new metadata + tag WMS_LAYER_GROUP (bug 776). + +- Added greyscale+alpha render support if mapdrawgdal.c (bug 965). + +- Added --with-fastcgi support to configure. + +- support OGC mapcontext through mapserver cgi (bug 946). + +- support for reading 3d shape file (z) (bug 869). + +- add php mapscript functions to expose the z element (bug 870). + +- imageObj::write() method for SWIG mapscript (bug 941). + +- Protect users from 3 potential sources of threading problems: parsing + expression strings outside of msLoadMap, evaluating mapserver logical + expressions, and loading symbol set files outside of msLoadMap (bug 339). + +- Various fixes allowing unit tests to run leak free under valgrind on + i686. Memory is now properly freed when exiting from common error + states (bug 927). + +- Restored ability to render transparent (indexed or alpha) pixmap symbols + on RGB map images, including annotation layers and embedded scalebars. + This feature remains OFF by default for map layers and is enabled by + specifying TRANSPARENCY ALPHA (bugs 926, 490). + +- mapserv_fcgi.c removed. Committed new comprehensive FastCGI support. + +- New mapserver exceptions for Java mapscript thanks to Umberto Nicoletti + (bug 895). + +- Removed mapindex.c, mapindex.h, shpindex.c components of old unused + shapefile indexing method. + +- Use the symbol size instead of 1 for the default style size value. This is + done by setting the default size to -1 and adding msSymbolGetDefaultSize() + everywhere to get the default symbolsize (Bug 751). + +- Correct Bug with GML BBOX output when using a with a + GetFeature request (Bug 913). + +- Encode all metadatas and mapfile parameters outputted in a xml document + (Bug 802). + +- Implement the ENCODING label parameter to support internationalization. + Note this require the iconv library (Bug 858). + +- New and improved Java mapscript build provided by unicoletti@prometeo.it + and examples by Y.K. Choo (bug 876). + +- MapContext: Cleanup code to make future integration more easily and output + SRS and DataURL in the order required by the spec. + +- Fixed issue with polygon outline colors and brush caching (bug 868). + +- New C# mapscript makefiles and examples provided by Y.K. Choo + committed under mapscript/csharp/ (bug 867). + +- Renamed 'string' member of labelCacheMemberObj to 'text' to avoid + conflicts in SWIG mapscript with C# and Java types (bug 852). + +- Fixed Bug 866 : problem when generating an sld on a pplygon layer + +- SWIG mapscript: map's output image width and height should be set + simultaneously using new mapObj::setSize() method. This performs + necessary map geotransform computation. Direct setting of map width + and height is deprecated (bug 836). + +- Fixed bug 832 (validate srs value) : When the SRS parameter in a GetMap + request contains a SRS that is valid for some, but not all of the layers + being requested, then the server shall throw a Service Exception + (code = "InvalidSRS"). Before this fix, mapserver use to reproject + the layers to the requested SRS. + +- Fixed bug 834: SE_ROW_ID in SDE not initialized for unregistered SDE tables + +- Fixed bug 823 : adding a validation of the SRS parameter when doing + a GetMap request on a wms server. Here is the OGC statement : + 'When the SRS parameter in a GetMap request contains a SRS + that is valid for some, but not all of the layers being requested, + then the server shall throw a Service Exception (code = "InvalidSRS").' + +- Set the background color of polygons or circles when using transparent + PIXMAP symbol. + +- SWIG mapscript class extensions are completely moved from mapscript.i + into separate interface files under mapscript/swiginc. + +- Overhaul of mapscript unit testing framework with a comprehensive test + runner mapscript/python/tests/runtests.py. + +- Modified the MS_VALID_EXTENT macro to take an extent as its argument + instead of the quartet of members. MapServer now checks that extents input + through the mapfile are valid in mapfile.c (web, map, reference, + and layer). Modified msMapSetExtent in mapobject.c to use the new + macro instead of its home-grown version. Modified all cases that used + MS_VALID_EXTENT to the new use case. + +- Layers now accept an EXTENT through the mapfile (bug 786). Nothing + is done with it at this point, and getExtent still queries the + datasource rather than getting information from the mapfile-specified + extent. + +- Fixed problem with WMS GetFeatureInfo when map was reprojected. Was a + problem with msProjectRect and zero-size search rectangles (bug 794) + +- MapServer version now output to mapscriptvars and read by Perl Makefile.PL + and Python setup.py (bug 795). + +- Map.web, layer, and class metadata are exposed in SWIG mapscript as + first-class objects (bug 737). + +- Add support for spatial filters in the SLD (Bug 782) + +- A few fixes to allow php_mapscript to work with both PHP4 and PHP5. + PHP5 support should still be considered experimental. (bug 718) + +- Fixed SDE only recognizing SE_ROW_ID as the unique column (bug 536). + The code now autosenses the unique row id column. + +- Enhanced SDE support to include support for queries against + user-specified versions. The version name can be specified as the + last parameter of the CONNECTION string. + +- Fixed automated generation of onlineresource in OWS GetCapabilities + when the xxx_onlineresource metadata is not specified: the map= parameter + used to be omitted and is now included in the default onlineresource if + it was explicitly set in QUERY_STRING (bug 643) + +- Fixed possible crash when producing WMS errors INIMAGE (bug 644) + +- Fixed automated generation of onlineresource in OWS GetCapabilities + when the xxx_onlineresource metadata is not specified: the map= parameter + used to be omitted and is now included in the default onlineresource if + it was explicitly set in QUERY_STRING (bug 643) + +- Fixed an issue with annotation label overlap. There was an issue with + the way msRectToPolygon was computing it's bounding box. (bug 618) + +- Removed "xbasewohoo" debug output when using JOINs and fixed a few + error messages related to MySQL joins (bug 652) + +- Fixed "raster cracking" problem (bug 493) + +- Improvements to Makefile.vc, and nmake.opt so that a mapscriptvars file + can be produced on windows. + +- Updated setup.py so Python MapScript builds on win32. + +- Added preliminary raster query support. + +- No more Python-stopping but otherwise benign errors raised from + msDrawWMSLayer() (bug 650). + +- Finished prototyping all MapServer functions used by SWIG-Mapscript + and added 'void' to prototypes of no-arg functions, eliminating all + but two SWIG-Mapscript build warnings (bug 658). + +- Mapscript: resolved issue with pens and dynamic drawing of points (bug 663). + +- Mapscript: fixes to tests of shape copying and new image symbols. + +- Mapscript: new OWSRequest class based on cgiRequestObj structure in + cgiutil.h is a first step to allow programming with MapServer's OWS + dispatching (bug 670). + +- Mapscript: styles member of classObj structure is no longer exposed to + SWIG (bug 611). + +- Implementation geotransform/rotation support in cgi core, and mapscript.i. + +- Testing: fixed syntax error, 'EPSG' -> 'epsg' in test.map (bug 687). + Added an embedded scalebar which demonstrates that bug 519 is fixed. + The test data package is also made more complete by including two fonts + from Bitstream's open Vera fonts (bug 694). + +- Mapscript (SWIG): remove promote and demote methods from layerObj. Use + of container's moveLayerUp/moveLayerDown is better, and this brings + the module nearer to PHP-Mapscript (bug 692). + +- mapogr.cpp: Now echos CPLGetLastErrorMsg() results if OGR open fails. + +- mapraster.c: fixed tile index corruption problem (bug 698) + +- Mladen Turk's map copying macros in mapcopy.h clean up map cloning and + allow for copying of fontset and symbolset. Added cloning tests in + python/tests/testCloneMap.py and refactored testing suite (bugs 640 & 701). + +- Mapscript: removing obsolete python/setup_wnone.py file. + +- CONFIG MS_NONSQUARE YES now enables non-square pixel mode (mostly for WMS). + Changes in mapdraw.c (msDrawMap()) to use the geotransform "hack" to allow + non-square pixels. + +- When using the text/html mime type in a GetFeature request, if the + layer's template is not set to a valid file, errors occur. + Correction is : the text/html is not advertized by default and + will only be advertized if the user has defined + "WMS_FEATURE_INFO_MIME_TYPE" "text/html" (bug 736) + +- Make PHP MapScript's layer->open() produce a PHP Warning instead of a + Fatal error (bug 742) + +- MapServer hash tables are now a structure containing a items pointer + to hashObj. See maphash.h for new prototypes of hash table functions. + In SWIG mapscript, Map, Layer, and Class metadata are now instances of the + new hashTableObj class. fontset.fonts and Map.configoptions are also + instances of hashTableObj. The older getMetaData/setMetaData and + metadata iterator methods can be deprecated (bug 737). + +- Mapscript-SWIG: made the arguments of mapObj and layerObj constructors + optional. A layerObj can now exist outside of a map and can be added + to a mapObj using the insertLayer method. mapObj.removeLayer now + returns a copy of the removed Layer rather than an integer (bug 759). + +- Fixed $map->processTemplate() which was always returning NULL. + Bug introduced in version 4.0 in all flavors of MapScript (bug 410) + + +Version 4.2-beta1 (2004-04-17) +------------------------------ + +- Added support for WMS 1.1.1 in the WMS interface. + +- Added support for WMS-SLD in client and server mode. + +- Added support for attribute filters in the WFS interface. + +- WMS Interface: several fixes to address issues found in running tests + against the OGC testsuite. One of the side-effects is that incomplete + GetMap requests that used to work in previous versions will produce + errors now (see bug 622). + +- Modified configure scripts to be able to configure/build PHP MapScript + using an installed PHP instead of requiring the full source tree. + +- Added ability to combine multiple WMS connections to the same server + into a single request when the layers are adjacent and compatible. (bug 116) + +- Support POSTed requests without Content-Length set. + +- Added support for proper classification of non-8bit rasters. + +- Added support for BYTE rawmode output type. + +- Added support for multiple bands of output in rawmode. + +- MySQL joins available + +- Fixed problems with detection of OGRRegisterAll() with GDAL 1.1.9 in + configure due to GDAL's library name change. Fixed a few other minor + issues with GDAL/OGR in configure. + +- Modified configure to disable native TIFF/PNG/JPEG/GIF support by default + if GDAL is enabled. You can still enable them explicitly if you like. + +- Replace wms_style_%s_legendurl, wms_logourl, wms_descriptionurl, wms_dataurl + and wms_metadataurl metadata by four new metadata by metadata replaced. The + new metadata are called legendurl_width, legendurl_height, legendurl_format, + legendurl_href, logourl_width, etc... + Old dependency to the metadata with four value in it , space separated, are + not kept. + +- Implement DataURL, MetadataURL and DescriptionURL metadata in + mapcontext.c (bug 523) + +- PHP MapScript's pasteImage() now takes a hex color value (e.g. 0xrrggbb) + for the transparent color instead of a color index. (bug 463) + +- OGR data sources with relative paths are now checked relative to + SHAPEPATH first, and if not found then we try again relative to the + mapfile location. (bug 295) + +- There is a new mapObj parameter called MAXSIZE to control maximum image + size to serve via the CGI and WMS interfaces. The default is 2048 as + before but it can be changed in the map file now. (bug 435) + +- Added simple dataset for unit and regression tests (bug 453) + +- PostGIS: added postresql_NOTICE_HANDLER() sending output via msDebug() + and only when layer->debug is set (bug 418) + +- Added Apache version detection in configure and added non-blocking flag + on stderr in msDebug() to work around Apache 2.x bug (bug 458) + +- MapScript rectObj: added optional bounding value args to constructor and + extended rectObj class with a toPolygon method (bug 508). + +- MapScript pointObj: added optional x/y args to constructor (bug 508). + +- MapScript colorObj: added optional RGB color value args to colorObj + constructor, and extended colorObj class with setRGB, setHex, and toHex + methods. The hex methods use hex color strings like '#ffffff' rather + than '0xffffff' for compatibility with HTML (bug 509). + +- MapScript outputFormatObj: extended with a getOption method (bug 510). + +- MapScript imageObj: added optional mapObj argument to the save method + resolving bug 549 without breaking current API. Also added optional + driver and filename arguments to constructor which allows imageObj + instances to be created with a specified driver or from files on disk + (bug 530). Added new code to Python MapScript which extends the + filename option to Python file-like objects (bug 550). This means + StringIO and urllib's network objects! + +- MapScript classObj and styleObj: added a new styleObj shadow class and + extended classObj with getStyle, insertStyle, and removeStyle methods. + MapScript now supports multiple styles for dynamically created classes + (bug 548). + +- MapScript layerObj: added getExtent, getNumFeatures extension methods, + allowing getShape to access inline features (bug 562). + +- Added fixes for AMD64/Linux in configure (bug 565) + +- Removed OGR_STATIC stuff in configure script that used to allow us to + build with OGR statically by pointing to the OGR source tree. That + means you can only build with OGR when *installed* as part of GDAL, + but that's what everyone is doing these days anyway. + +- Mapscript outputFormatObj: extended constructor to allow format names, + and mapObj methods to append and remove output formats from the + outputformatlist (bug 511). + +- New SWIG mapscript development documentation in the spirit of the + PHP-Mapscript readme file, but using reST (bug 576). + +- Paving way for future changes to SWIG mapscript API with new features + enabled by NEXT_GENERATION_API symbol (bug 586). + +- Added ability to set string member variables to NULL in PHP MapScript + (bug 591) + +- New key iterators for map, layer, and class metadata hash tables + (bug 434) and fontset fonts hash table (bug 439). + +- Fixed potential crash when using nquery with a querymap enabled and + some layers have a template set at the layer level instead of inside + classes (bug 569). + +- New CONFIG keyword in the MAP object in a .map file to be used + to set external configuration parameters such as PROJ_LIB and control + of some GDAL and OGR driver behaviours (bug 619) + +Version 4.0 (2003-08-01) +------------------------ + +- Fixed problem with truncated expressions (bugs 242 and 340) + +- Attempt at fixing GD vs libiconv dependency problems (bug 348) + +- Fixed problem with invalid BoundingBox tag in WMS capabilities (bug 34) + +- Fixed problems with SIZEUNITS not working properly (bug 373) + +- Fixed MacOSX configure problems for linking php_mapscript (bug 208) + +- Fixed problem with reference map marker symbol not showing up (bug 378) + +- Use in WMS 1.0.0 capabilities instead of (bug 129) + +- One-to-one and one-to-many joins now work for Xbase files and are available + to query templates. Low level one-to-one Xbase joins are available via + OGR. + +Version 4.0-beta2 (2003-07-11) +------------------------------ + +- Added prototype of FastCGI support in mapserv_fcgi.c (not built by default). + +- Report full error stack in the mapserv CGI and PHP MapScript (bug 346) + +- Old index (.qix) format is deprecated (bug 273) + +- Fixed problem with embedded legend and scalebar that would result in + layers being added to the HTML legends (bug 171) + +- Changed joins (XBase only at this point) over to the open-prepare-next... + next-close way of doing things. Compiles fine, but needs more testing. + One-to-many support should work now but it needs to be hooked into the + template code yet. Last thing before a candidate 4.0 release. + +- Added ability to generate images in MapScript processQueryTemplate (bug 341) + +- Added saving of output formats in msSaveMap() + +- Fixed problem in PHP MapScript with variables that were not dereferenced + before their values were changed by the MapScript wrappers (bug 323) + +- Added support for Web Map Context 1.0.0 + +- Treat zero-length template values as NULL so that it's possible to + set("template", "") from MapScript to make layer non-queryable (bug 338) + +- Ditched the shapepath argument to the shapefileObj constructor + +- CARTOLINE join style default changed to MS_CJC_NONE + +- Tweaked code in legend builder to handle polygon layers slightly different. + Now if a polygon layer contains only outlines and no fills (i.e. a polyline) + then it is drawn using the zigzag legend shape rather than the box. I'll + add legend outlines back in shortly. + +- Restored legend key outlines (triggered by setting OUTLINECOLOR). If an + outline is requested then line symbols are clipped to the outline, + otherwise lines are allowed to bleed a pixel or two beyond those + boundaries- for most cases this looks fine but for fat lines it is + gonna look goofy regardless. In those cases use the KEYIMAGE. + +- Fixed a bug in the scanline writer so that x coordinates can be in any + order when passed in to the function. (bug 336) + +- Updated loadExpressionString in mapfile.c to be a bit more tolerant of + input. Now if a string does not match the logical or regex pattern it is + automatically cast as a string expression. Removes the need for silly quotes. + + +Version 4.0-beta1 (2003-06-06) +------------------------------ + +- Added imagemap outputformat, which makes possible use of client-side + imagemaps in browsers. + +- Added MySQL support for non-spatial OpenGIS Simple Features SQL stored data + +- msQueryByShape and msQueryByFeature honor layer tolerances. In effect you + can to buffered queries now. At the moment only polygon select features + are supported, but there's nothing inherent in the underlying computations + that says lines won't work as well. + +- Simple one-to-one joins are working again. Reworked the join code so that + table connections are persistent within a join (across joins is a todo). + Joins, like layers are wrapped with a connection neutral front end, that + sets us up to do MySQL or whatever in addition to XBase. + +- Removed shapepath argument to all layer access functions (affects MapScript). + It's still used but we leverage the layer pointer back to the parent mapObj + so the API is cleaner. + +- Changed default presentation of feature attributes to escape a few + problematic characters for HTML display (eg. > becomes >). + Added [itemname_raw] substitution to allow access to unaltered data. + +- Added initial version of Jan Hartman's connection pooling code. + +- Replaced libwww with libcurl for WMS/WFS client HTTP requests. + (libcurl 7.10 required, see http://curl.haxx.se/libcurl/c/) + +- Added CONNECTION to the list of mapfile parameters that can accept + %variable% substitutions when processed by the cgi version. This is useful + for passing in username and/or passwords to database data sources. + +- Added support for DATA and TEMPLATE (header/footer/etc...) filtering using + an regex declared in the mapfile (DATAPATTERN and TEMPLATEPATTERN). + Certain parameters in a mapfile cannot be changed via a URL without first + being filtered. + +- Added support for environment variable MS_MAPFILE_PATTERN. This allows you to + override the default regex in favor of one more restrictive (I would hope) of + your own. + +- Disabled CGI SAVEMAP option. + +- Removed CGI TEMPLATE option since you can use the map_web_template syntax. + Simplifies security maintenance by only having to deal with this option + in a single place. + +- Added offset support (styleObj) for raster based output (GD for sure, not + quite sure how OGR output is created although I believe is uses GD anyway). + This allows for feature drop shadows and support for cool linear symbols + like used to be supported in pre-3.4 versions. These offsets are not + scalable at the moment. + +- Null shapes (attributes but no vertices) are skipped for shapefiles using + the msLayerNextShape interface. Otherwise applications should check the + shapeObj type member for MS_SHAPE_NULL. + +- Changed where label cache is allocated and cleared. Now it isn't allocated + until drawing takes place. Any old cache is cleared before a new one is + allocated. The cache is still intact following rendering for post-processing + using MapScript. + +- Fixed screw up in pre-processing of logical expressions for item lists. + Under certain circumstances that list could get corrupted and expressions + would fail. + +- Added NOT operator to expression parser. + +- Added layer and map level DEBUG options to map file. + +- Major changes to support vector output (PDF, SWF, GML, ...): + imageObj is used by all rendering functions instead of gdImagePtr, + New msSaveImage() prototype + +- Support for GD-2.0, including 24 bits output. Dropped support for GD 1.x + +- Support for output to any GDAL-supported format via the new OUTPUTFORMAT + object. + +- New styleObj to replace the OVERLAY* parameter in classes. + +- PostGIS: Added Sean Gillies 's patch for "using unique + ". Added "using SRID=#" to specify a spatial reference + for an arbitrary sql query. + +- ... and numerous fixes not listed here... + + +Version 3.6.0-beta1 (2002-04-30) +-------------------------------- + +- MapScript: qitem and qstring params added to layer->queryByAttribute(). + Instead of being driven by the layer's FILTER/FILTERITEM, the query by + attribute is now driven by the values passed via qitem,qstring, and the + layer's FILTER/FILTERITEM are ignored. + +- Symbol and MapFile changes: ANTIALIAS and FILLED keywords now take a + boolean (TRUE/FALSE) argument i.e. ANTIALIAS becomes ANTIALIAS TRUE + and FILLED becomes FILLED TRUE + +- Reference Map: + Added options to show a different marker when the reference box becomes + too small. See the mapfile reference docs for more details on the new + reference object parameters (MARKER, MARKERSIZE, MAXBOXSIZE, MINBOXSIZE) + +- Added MINSCALE/MAXSCALE at the CLASS level. + +- Support for tiled OGR datasets. + +- PHP 4.1.2 and 4.2.0 support for PHP MapScript. + +- Added LAYER TRANSPARENCY, value between 1-100 + +- Fixes to the SWIG interface for clean Java build. + +- New HTML legend templates for CGI and MapScript. See HTML-Legend-HOWTO. + +- WMS server now supports query results using HTML query templates instead + of just plain/text. + +- Added support functions for thread safety (--with-thread). Still not + 100% thread-safe. + + +Version 3.5.0 (2002-12-18) +-------------------------- + +- No Revision history before version 3.5 + diff --git a/INSTALL b/INSTALL deleted file mode 100644 index 77d45994d5..0000000000 --- a/INSTALL +++ /dev/null @@ -1,14 +0,0 @@ -Visit http://www.mapserver.org/ for full documentation and installation -instructions. - -Unix compilation instructions ------------------------------ - -See INSTALL.CMAKE or the document on the MapServer website at - - -Win32 compilation instructions ------------------------------- - -See README.WIN32 or the document on the MapServer website at - diff --git a/INSTALL.CMAKE b/INSTALL.CMAKE deleted file mode 100644 index d68599ce13..0000000000 --- a/INSTALL.CMAKE +++ /dev/null @@ -1,183 +0,0 @@ -CMake Build Instructions -======================== - -Since version 6.4, MapServer is built with the CMake build tool instead of the -previous autotools chain. CMake is opensource and free of charge and is usually -included in distribution packages, or can be downloaded and compiled with no -third party dependencies. -CMake itself does not do the actual compiling of the MapServer source code, it -mainly creates platform specific build files that can then be used by standard -build utilities (make on unixes, visual studio on windows, xcode on osx, etc...) - -Install CMake -------------- - -MapServer requires at least CMake version 2.6.0, although the build process with -such an old version has not been thouroughly tested. 2.8.0 and above are -recommended. - -Distro Packaged Version -....................... - -Linux distributions usually include the cmake package, that can be installed -with your usual package manager: apt-get, yum, yast, etc... - -Installing Your Own -................... - -Head over to http://www.cmake.org/cmake/resources/software.html to download -a source tarball (for unixes) or a binary installer (for windows). -If you are building from source, the build process is detailed in the tarball -readme files, and consists only in - - $ tar xzf cmake-x.y.z.tar.gz - $ cd cmake-x.y.z - $ ./bootstrap - $ make - # make install - - -Creating the MapServer platform specific project with CMake ------------------------------------------------------------ - -Although you can run and build from MapServer's source directory as created -by downloading a tarball or using a git clone, it is **highly** recommended -to run "out-of-source" builds, i.e. having all build files be compiled and -created in a different directory than the actual MapServer sources. This allows -to have different configurations running alongside each other (e.g. release and -debug builds, cross-compiling, enabled features, etc...). - -Running CMake From the Command Line -................................... - -mkdir build -cd build -cmake .. -## fix dependency issues -make - -Running the GUI version of cmake -................................ - -CMake can be run in graphical mode, in which case the list of available options -are presented in a more user-friendly manner - -mkdir build -cd build -ccmake .. -## follow instructions, fix dependency issues -make - -Options and Dependencies -........................ - -Depending on what packages are available in the default locations of your system, -the previous "cmake .." step will most probably have failed with messages indicating -missing dependencies (by default, MapServer has *many* of those). The error message -that CMake prints out should give you a rather good idea of what steps you should take -next, depending on wether the failed dependency is a feature you require in your build -or not. - -- Either disable the dependency by rerunning cmake with -DWITH_DEPENDENCY=0, e.g. - - $ cmake .. -DWITH_CAIRO=0 - -- Or, if the failed dependency relates to a feature you want built in, and that cmake has - not been able to find it's installation location, there are 3 possible reasons: - - 1 You have not installed the third party package, and/or the third party development - headers. Use your standard package manager to install the failing package, along - with it's development headers. The development packages on linux usually end with - "-dev" or "-devel", e.g. libcairo2-devel , libpng-dev, etc... - - $ (sudo) apt-get install libcairo-dev - $ cmake .. - - 2 You have installed the third party package in a non standard location, which you - must give to cmake so it can find the required headers and libraries - - $ cmake .. -DCMAKE_PREFIX_PATH=/opt/cairo-1.18.2 - - Cmake expects these nonstandard prefixes to contain standard subdirectories, i.e. - /opt/cairo-1.18.2/include/cairo.h and /opt/cairo-1.18.2/lib/libcairo.so. - You can specify multiple prefixes on the cmake command line by separating them with - the platform specific separator (e.g. ":" on unixes), e.g. - - $ cmake .. -DCMAKE_PREFIX_PATH=/opt/cairo-1.18.2:/opt/freeware - - 3 If you're certain that the packages development headers are installed, and/or that - you pointed to a valid installation prefix, but cmake is still failing, then there's - an issue with MapServer's cmake setup, and you can bring this up on the - mailing list or issue tracker. - -Available Options ------------------ - -Following is a list of option, taken from MapServer's CMakeLists.txt configuration file. -After the description of the option, the ON/OFF flag states if the option is enabled by -default (in which case the cmake step will fail if the dependency cannot be found). All -of these can be enabled or disabled by passing "-DWITH_XXX=0" or "-DWITH_XXX=1" to the -"cmake .." invocation in order to override a default selection. - -This Readme file may be out of sync with the actual CMakeLists files shipped. -Refer to the CMakeLists.txt file for up-to-date options. - - - option(WITH_PROJ "Choose if reprojection support should be built in" ON) - - option(WITH_KML "Enable native KML output support (requires libxml2 support)" OFF) - - option(WITH_SOS "Enable SOS Server support (requires PROJ and libxml2 support)" OFF) - - option(WITH_WMS "Enable WMS Server support (requires proj support)" ON) - - option(WITH_FRIBIDI "Choose if FriBidi glyph reordering should be enabled (usefull for left-to-right languages)(requires harfbuzz)" ON) - - option(WITH_HARFBUZZ "Choose if Harfbuzz complex script glyph shaping support should be built in (requires fribidi)" ON) - - option(WITH_ICONV "Choose if Iconv Internationalization support should be built in" ON) - - option(WITH_CAIRO "Choose if CAIRO rendering support should be built in (required for SVG and PDF output)" ON) - - option(WITH_SVGCAIRO "Choose if SVG symbology support (via libsvgcairo) should be built in (requires cairo, libsvg, libsvg-cairo. Incompatible with librsvg)" OFF) - - option(WITH_RSVG "Choose if SVG symbology support (via librsvg) should be built in (requires cairo, librsvg. Incompatible with libsvg-cairo)" OFF) - - option(WITH_MYSQL "Choose if MYSQL joining support should be built in" OFF) - - option(WITH_FCGI "Choose if FastCGI support should be built in" ON) - - option(WITH_GEOS "Choose if GEOS geometry operations support should be built in" ON) - - option(WITH_POSTGIS "Choose if Postgis input support should be built in" ON) - - option(WITH_GDAL "Choose if GDAL input raster support should be built in" ON) - - option(WITH_OGR "Choose if OGR/GDAL input vector support should be built in" ON) - - option(WITH_CURL "Enable Curl HTTP support (required for wms/wfs client, remote SLDs and pixmap symbols)" OFF) - - option(WITH_CLIENT_WMS "Enable Client WMS Layer support (requires CURL and GDAL support)" OFF) - - option(WITH_CLIENT_WFS "Enable Client WMS Layer support (requires CURL and OGR support)" OFF) - - option(WITH_WFS "Enable WFS Server support (requires PROJ and OGR support)" ON) - - option(WITH_WCS "Enable WCS Server support (requires PROJ and GDAL support)" ON) - - option(WITH_LIBXML2 "Choose if libxml2 support should be built in (used for sos, wcs 1.1,2.0 and wfs 1.1)" ON) - - option(WITH_THREAD_SAFETY "Choose if a thread-safe version of libmapserver should be built (only recommended for some mapscripts)" OFF) - - option(WITH_GIF "Enable GIF support (for PIXMAP loading)" ON) - - option(WITH_PYTHON "Enable Python mapscript support" OFF) - - option(WITH_PHP "Enable PHP mapscript support" OFF) - - option(WITH_PERL "Enable Perl mapscript support" OFF) - - option(WITH_RUBY "Enable Ruby mapscript support" OFF) - - option(WITH_JAVA "Enable Java mapscript support" OFF) - - option(WITH_CSHARP "Enable C# mapscript support" OFF) - - option(WITH_ORACLESPATIAL "include oracle spatial database input support" OFF) - - option(WITH_ORACLE_PLUGIN "include oracle spatial database input support as plugin" OFF) - - option(WITH_MSSQL2008 "include mssql 2008 database input support as plugin" OFF) - - option(WITH_SDE_PLUGIN "include ArcSDE support as a plugin (must specify SDE_INCLUDE_DIR and SDE_LIBRARY_DIR)." OFF) - - option(WITH_SDE "include ArcSDE support. Add -DSDE_VERSION=91 to use 9.1 arcSDE version" OFF) - - option(WITH_EXEMPI "include xmp output metadata support" OFF) - - option(WITH_XMLMAPFILE "include native xml mapfile support (requires libxslt/libexslt)" OFF) - - option(WITH_V8 "include javacript v8 scripting" OFF) - - -The following options are for advanced users, i.e. you should not enable them unless -you know what you are doing: - - - option(BUILD_STATIC "Also build a static version of mapserver" OFF) - - option(LINK_STATIC_LIBMAPSERVER "Link to static version of libmapserver (also for mapscripts)" OFF) - - option(WITH_APACHE_MODULE "include (experimental) support for apache module" OFF) - - option(WITH_GENERIC_NINT "generic rounding" OFF) - - option(WITH_POINT_Z_M "include Z and M coordinates in point structure (advanced, not recommended)" OFF) - -The following are some common CMake options not specific to MapServer itself: - - - CMAKE_INSTALL_PREFIX : path where mapserver binaries and libraries should be installed. Defaults - to /usr/local on unix. - - CMAKE_PREFIX_PATH : platform-specific separator separated list of prefixes where dependencies will be looked for, e.g. - "-DCMAKE_PREFIX_PATH=/opt/freeware:/opt/jdk-1.5.6" - - CMAKE_BUILD_TYPE : Specify the build type. Usually one of 'Debug' or 'Release', e.g. - "-DCMAKE_BUILD_TYPE=Release" "-DCMAKE_BUILD_TYPE=Debug" - -You can find a more extensive list of cmake variables here: http://www.cmake.org/Wiki/CMake_Useful_Variables diff --git a/INSTALL.md b/INSTALL.md new file mode 100644 index 0000000000..718af2303e --- /dev/null +++ b/INSTALL.md @@ -0,0 +1,14 @@ +Visit https://mapserver.org/ for full documentation and installation +instructions. + +Unix compilation instructions +----------------------------- + +See [INSTALL_CMAKE.md](INSTALL_CMAKE.md) or the document on the MapServer website at +https://mapserver.org/installation/unix.html + +Win32 compilation instructions +------------------------------ + +See README.WIN32 or the document on the MapServer website at +https://mapserver.org/installation/win32.html diff --git a/INSTALL_CMAKE.md b/INSTALL_CMAKE.md new file mode 100644 index 0000000000..5984e86121 --- /dev/null +++ b/INSTALL_CMAKE.md @@ -0,0 +1,193 @@ +# CMake Build Instructions + +Since version 6.4, MapServer must be built using the [CMake](https://cmake.org) +build tool, instead of the previous autotools chain. CMake is Open Source, +free of charge, and is usually included in distribution packages, or can be +downloaded and compiled with no third party dependencies. +CMake itself does not do the actual compiling of the MapServer source code, it +mainly creates platform specific build files that can then be used by standard +build utilities (make on Unix, Visual Studio on Windows, Xcode on OSX, etc...) + +## Install CMake + +MapServer requires at least CMake version 3.16, although the CMake process was +first implemented in MapServer 6.4 with CMake 2.6.0. + +### Distro Packaged Version + +Linux distributions usually include the cmake package, that can be installed +with your usual package manager: apt-get, yum, yast, etc... + +### Installing Your Own + +Head over to https://cmake.org/download/ to download +a source tarball (for unixes) or a binary installer (for Windows). +If you are building CMake from source, the build process is detailed in the +tarball readme files, such as: + +```bash + $ tar xzf cmake-x.y.z.tar.gz + $ cd cmake-x.y.z + $ ./bootstrap + $ make + # make install +``` + +## Creating the MapServer platform specific project with CMake + +Although you can run and build from MapServer's source directory as created +by downloading a tarball or using a git clone, it is **highly** recommended +to run "out-of-source" builds, i.e. having all build files be compiled and +created in a different directory than the actual MapServer sources. This allows +to have different configurations running alongside each other (e.g. release and +debug builds, cross-compiling, enabled features, etc...). + +### Running CMake From the Command Line + +```bash +mkdir build +cd build +cmake .. +## fix dependency issues +make +``` + +### Running the GUI version of cmake + +CMake can be run in graphical mode, in which case the list of available options +are presented in a more user-friendly manner, such as: + +```bash +mkdir build +cd build +ccmake .. +## follow instructions, fix dependency issues +make +``` + +### Options and Dependencies + +Depending on what packages are available in the default locations of your system, +the previous "cmake .." step will most probably have failed with messages indicating +missing dependencies (by default, MapServer has *many* of those). The error message +that CMake prints out should give you a rather good idea of what steps you should take +next, depending on whether the failed dependency is a feature you require in your build +or not. + +- Either disable the dependency by rerunning cmake with -DWITH_DEPENDENCY=0, e.g. + + ```bash + $ cmake .. -DWITH_CAIRO=0 + ``` + +- Or, if the failed dependency relates to a feature you want built in, and that cmake has + not been able to find it's installation location, there are 3 possible reasons: + + 1 You have not installed the third party package, and/or the third party development + headers. Use your standard package manager to install the failing package, along + with it's development headers. The development packages on linux usually end with + "-dev" or "-devel", e.g. libcairo2-devel , libpng-dev, etc... + + ```bash + $ (sudo) apt-get install libcairo-dev + $ cmake .. + ``` + + 2 You have installed the third party package in a non-standard location, which you + must give to cmake so it can find the required headers and libraries: + + ```bash + $ cmake .. -DCMAKE_PREFIX_PATH=/opt/cairo-1.18.2 + ``` + + CMake expects these non-standard prefixes to contain standard subdirectories, i.e. + /opt/cairo-1.18.2/include/cairo.h and /opt/cairo-1.18.2/lib/libcairo.so. + You can specify multiple prefixes on the cmake command line by separating them with + the platform specific separator (e.g. ":" on unixes), e.g. + + ```bash + $ cmake .. -DCMAKE_PREFIX_PATH=/opt/cairo-1.18.2:/opt/freeware + ``` + + 3 If you're certain that the packages development headers are installed, and/or that + you pointed to a valid installation prefix, but cmake is still failing, then there's + an issue with MapServer's cmake setup, and you can bring this up on the + mailing list or issue tracker. + +## Available Options + +The following is a list of options, taken from MapServer's [CMakeLists.txt](https://github.com/MapServer/MapServer/blob/main/CMakeLists.txt) +configuration file. After the description of the option, the ON/OFF flag states +if the option is enabled by default (in which case the cmake step will fail if +the dependency cannot be found). All of these can be enabled or disabled by +passing `"-DWITH_XXX=0"` or `"-DWITH_XXX=1"` to the `"cmake .."` invocation +in order to override a default selection. + +This Readme file may be out of sync with the actual CMakeLists files shipped. +Refer to the CMakeLists.txt file for up-to-date options. + + - `WITH_PROTOBUFC`: Choose if protocol buffers support should be built in (required for vector tiles) `(ON)` + - `WITH_KML`: Enable native KML output support (requires libxml2 support) `(OFF)` + - `WITH_SOS`: Enable SOS Server support (requires PROJ and libxml2 support) `(OFF)` + - `WITH_WMS`: Enable WMS Server support (requires PROJ support) `(ON)` + - `WITH_FRIBIDI`: Choose if FriBidi glyph shaping support should be built in (useful for right-to-left languages) (requires HARFBUZZ) `(ON)` + - `WITH_HARFBUZZ`: Choose if Harfbuzz complex text layout should be included (needed for e.g. arabic and hindi) (requires FRIBIDI) `(ON)` + - `WITH_ICONV`: Choose if Iconv Internationalization support should be built in `(ON)` + - `WITH_CAIRO`: Choose if CAIRO rendering support should be built in (required for SVG and PDF output) `(ON)` + - `WITH_SVGCAIRO`: Choose if SVG symbology support (via libsvgcairo) should be built in (requires cairo, libsvg, libsvg-cairo. Incompatible with librsvg) `(OFF)` + - `WITH_RSVG`: Choose if SVG symbology support (via librsvg) should be built in (requires cairo, librsvg. Incompatible with libsvg-cairo) `(OFF)` + - `WITH_MYSQL`: Choose if MYSQL joining support should be built in `(OFF)` + - `WITH_FCGI`: Choose if FastCGI support should be built in `(ON)` + - `WITH_GEOS`: Choose if GEOS geometry operations support should be built in `(ON)` + - `WITH_POSTGIS`: Choose if Postgis input support should be built in `(ON)` + - `WITH_CLIENT_WMS`: Enable Client WMS Layer support (requires CURL) `(OFF)` + - `WITH_CLIENT_WFS`: Enable Client WMS Layer support (requires CURL) `(OFF)` + - `WITH_CURL`: Enable Curl HTTP support (required for wms/wfs client, and remote SLD) `(OFF)` + - `WITH_WFS`: Enable WFS Server support (requires PROJ and OGR support) `(ON)` + - `WITH_WCS`: Enable WCS Server support (requires PROJ and GDAL support) `(ON)` + - `WITH_OGCAPI`: Enable OGCAPI Server support (requires PROJ and OGR support) `(ON)` + - `WITH_LIBXML2`: Choose if libxml2 support should be built in (used for sos, wcs 1.1,2.0 and wfs 1.1) `(ON)` + - `WITH_THREAD_SAFETY`: Choose if a thread-safe version of libmapserver should be built (only recommended for some mapscripts) `(OFF)` + - `WITH_GIF`: Enable GIF support (for PIXMAP loading) `(ON)` + - `WITH_PYTHON`: Enable Python mapscript support `(OFF)` + - `WITH_PHPNG`: Enable PHPNG (SWIG) mapscript support `(OFF)` + - `WITH_PERL`: Enable Perl mapscript support `(OFF)` + - `WITH_RUBY`: Enable Ruby mapscript support `(OFF)` + - `WITH_JAVA`: Enable Java mapscript support `(OFF)` + - `WITH_CSHARP`: Enable C# mapscript support `(OFF)` + - `WITH_ORACLESPATIAL`: include oracle spatial database input support `(OFF)` + - `WITH_ORACLE_PLUGIN`: include oracle spatial database input support as plugin `(OFF)` + - `WITH_MSSQL2008`: include mssql 2008 database input support as plugin `(OFF)` + - `WITH_EXEMPI`: include xmp output metadata support `(OFF)` + - `WITH_XMLMAPFILE`: include native xml mapfile support (requires libxslt/libexslt) `(OFF)` + - `WITH_V8`: include javascript v8 scripting `(OFF)` + - `WITH_PIXMAN`: use (experimental) support for pixman for layer compositing operations `(OFF)` + - `INSTALL_HTML_BOOTSTRAP`: Whether to install HTML Bootstrap resources for OGCAPIs `(ON)` + +The following options are for advanced users, i.e. you should not enable them unless +you know what you are doing: + + - `BUILD_STATIC`: Also build a static version of mapserver `(OFF)` + - `LINK_STATIC_LIBMAPSERVER`: Link to static version of libmapserver (also for mapscripts) `(OFF)` + - `WITH_APACHE_MODULE`: include (experimental) support for apache module `(OFF)` + - `WITH_GENERIC_NINT`: generic rounding `(OFF)` + - `WITH_PYMAPSCRIPT_ANNOTATIONS`: Add annotations to Python mapscript output `(OFF)` + - `FUZZER`: Build fuzzers using libFuzzer (requires Clang, will disable executable - mapserv, etc. - generation) `(OFF)` + - `BUILD_FUZZER_REPRODUCER`: Build fuzzer reproducer programs `(ON)` + +The following are some common CMake options not specific to MapServer itself: + + - `CMAKE_INSTALL_PREFIX`: path where mapserver binaries and libraries should be installed. Defaults + to /usr/local on unix. + - `CMAKE_PREFIX_PATH`: platform-specific separator separated list of prefixes where dependencies will be looked for, e.g. + ```bash" + -DCMAKE_PREFIX_PATH=/opt/freeware:/opt/jdk-1.5.6" + ``` + - `CMAKE_BUILD_TYPE`: Specify the build type. Usually one of 'Debug' or 'Release', e.g. + ```bash + "-DCMAKE_BUILD_TYPE=Release" + or + "-DCMAKE_BUILD_TYPE=Debug" + ``` + +You can find a more extensive list of CMake variables here: https://cmake.org/cmake/help/latest/manual/cmake-variables.7.html diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000000..a1efd88e0b --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,36 @@ +MapServer Licensing +=================== + +MapServer General +----------------- + +Copyright (c) 2008-2026 Open Source Geospatial Foundation. +Copyright (c) 1996-2008 Regents of the University of Minnesota. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies of this Software or works derived from this Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +FlatGeobuf +---------- + +Refer to the FlatGeobuf license found at [/src/flatgeobuf/LICENSE](src/flatgeobuf/LICENSE) + +FlatBuffers +----------- + +Refer to the FlatBuffers license found at [/src/flatgeobuf/include/flatbuffers/LICENSE](src/flatgeobuf/include/flatbuffers/LICENSE) \ No newline at end of file diff --git a/MIGRATION_GUIDE.md b/MIGRATION_GUIDE.md new file mode 100644 index 0000000000..28956387b0 --- /dev/null +++ b/MIGRATION_GUIDE.md @@ -0,0 +1,15 @@ +***************************************************************************** +MapServer Migration Guide +***************************************************************************** + +The current version of the MapServer Migration Guide is available online +at https://mapserver.org/MIGRATION_GUIDE.html. + + +For developers: + +The main copy of the MIGRATION_GUIDE is now located in the root of the +/MapServer/MapServer-documentation source tree ( https://github.com/MapServer/MapServer-documentation ). +Developers are welcome and encouraged to edit/update the guide in the documentation +tree directly. + diff --git a/MIGRATION_GUIDE.txt b/MIGRATION_GUIDE.txt deleted file mode 100644 index 8d7371516e..0000000000 --- a/MIGRATION_GUIDE.txt +++ /dev/null @@ -1,14 +0,0 @@ -***************************************************************************** -MapServer Migration Guide -***************************************************************************** - -The current version of the MapServer Migration Guide is available online -at http://www.mapserver.org/MIGRATION_GUIDE.html. - - -For developers: - -The master copy of the MIGRATION_GUIDE is now located in the root of the -mapserver/docs source tree (https://github.com/mapserver/docs). Developers -are welcome and encouraged to edit/update the guide in the docs tree directly. - diff --git a/Makefile b/Makefile index d75c6c9af3..58a1cf38a4 100644 --- a/Makefile +++ b/Makefile @@ -1,26 +1,63 @@ AUTOTEST_OPTS?=--strict_mode -PHP_MAPSCRIPT=build/mapscript/php/php_mapscript.so -PYTHON_MAPSCRIPT_PATH=build/mapscript/python -JAVA_MAPSCRIPT_PATH=build/mapscript/java -CSHARP_MAPSCRIPT_PATH=build/mapscript/csharp -PERL_MAPSCRIPT_PATH=build/mapscript/perl +PHP_MAPSCRIPT?=build/src/mapscript/phpng/php_mapscriptng.so +PYTHON_MAPSCRIPT_PATH=build/src/mapscript/python +JAVA_MAPSCRIPT_PATH=build/src/mapscript/java +CSHARP_MAPSCRIPT_PATH=build/src/mapscript/csharp +PERL_MAPSCRIPT_PATH=build/src/mapscript/perl BUILDPATH=../../build FLEX=flex YACC=yacc +CMAKEFLAGS_MAPSCRIPT_PYTHON=-DWITH_CLIENT_WMS=1 \ + -DWITH_CLIENT_WFS=1 -DWITH_KML=1 -DWITH_SOS=1 \ + -DWITH_PYTHON=1 -DWITH_THREAD_SAFETY=1 -DWITH_FRIBIDI=1 -DWITH_FCGI=1 -DWITH_EXEMPI=1 \ + -DCMAKE_BUILD_TYPE=Release -DWITH_RSVG=1 -DWITH_CURL=1 -DWITH_HARFBUZZ=1 \ + ${EXTRA_CMAKEFLAGS} -DLIBMAPSERVER_EXTRA_FLAGS="${LIBMAPSERVER_EXTRA_FLAGS}" \ + -DCMAKE_INSTALL_PREFIX=/tmp/install-mapserver + +CMAKEFLAGS_MAPSCRIPT_PHP=-DWITH_CLIENT_WMS=1 \ + -DWITH_CLIENT_WFS=1 -DWITH_KML=1 -DWITH_SOS=1 -DWITH_PHPNG=1 \ + -DWITH_PYTHON=0 -DWITH_THREAD_SAFETY=1 -DWITH_FRIBIDI=1 -DWITH_FCGI=1 -DWITH_EXEMPI=1 \ + -DCMAKE_BUILD_TYPE=Release -DWITH_RSVG=1 -DWITH_CURL=1 -DWITH_HARFBUZZ=1 \ + ${EXTRA_CMAKEFLAGS} -DLIBMAPSERVER_EXTRA_FLAGS="${LIBMAPSERVER_EXTRA_FLAGS}" \ + -DCMAKE_INSTALL_PREFIX=/tmp/install-mapserver + +CMAKEFLAGS_NOCOVERAGE=-DWITH_CLIENT_WMS=1 \ + -DWITH_CLIENT_WFS=1 -DWITH_KML=1 -DWITH_SOS=1 -DWITH_CSHARP=1 -DWITH_PHPNG=1 -DWITH_PERL=1 \ + -DWITH_PYTHON=1 -DWITH_JAVA=1 -DWITH_THREAD_SAFETY=1 -DWITH_FRIBIDI=1 -DWITH_FCGI=1 -DWITH_EXEMPI=1 \ + -DCMAKE_BUILD_TYPE=Release -DWITH_RSVG=1 -DWITH_CURL=1 -DWITH_HARFBUZZ=1 -DWITH_MSSQL2008=ON \ + ${EXTRA_CMAKEFLAGS} -DLIBMAPSERVER_EXTRA_FLAGS="${LIBMAPSERVER_EXTRA_FLAGS}" \ + -DCMAKE_INSTALL_PREFIX=/tmp/install-mapserver + CMAKEFLAGS=-DCMAKE_C_FLAGS="--coverage ${CMAKE_C_FLAGS}" -DCMAKE_CXX_FLAGS="--coverage ${CMAKE_CXX_FLAGS}" \ - -DCMAKE_SHARED_LINKER_FLAGS="-lgcov" -DWITH_CLIENT_WMS=1 \ - -DWITH_CLIENT_WFS=1 -DWITH_KML=1 -DWITH_SOS=1 -DWITH_CSHARP=1 -DWITH_PHP=1 -DWITH_PERL=1 \ - -DWITH_PYTHON=1 -DWITH_JAVA=1 -DWITH_THREAD_SAFETY=1 -DWITH_FRIBIDI=1 -DWITH_FCGI=0 -DWITH_EXEMPI=1 \ - -DCMAKE_BUILD_TYPE=Release -DWITH_RSVG=1 -DWITH_CURL=1 -DWITH_HARFBUZZ=1 -DWITH_POINT_Z_M=1 -DWITH_MSSQL2008=ON ${EXTRA_CMAKEFLAGS} -DLIBMAPSERVER_EXTRA_FLAGS="${LIBMAPSERVER_EXTRA_FLAGS}" + -DCMAKE_SHARED_LINKER_FLAGS="-lgcov" ${CMAKEFLAGS_NOCOVERAGE} + all: cmakebuild cmakebuild: lexer parser if test ! -s build/Makefile; then mkdir -p build ; cd build ; cmake .. $(CMAKEFLAGS); fi + cd build && $(MAKE) $(MFLAGS) && ctest -V + +cmakebuild_nocoverage: lexer parser + if test ! -s build_nocoverage/Makefile; then mkdir -p build_nocoverage ; cd build_nocoverage ; cmake .. $(CMAKEFLAGS_NOCOVERAGE); fi + cd build_nocoverage && $(MAKE) $(MFLAGS) && $(MAKE) $(MFLAGS) install + +cmakebuild_mapscript_python: lexer parser + if test ! -s build/Makefile; then mkdir -p build ; cd build ; cmake .. $(CMAKEFLAGS_MAPSCRIPT_PYTHON); fi + cd build && $(MAKE) $(MFLAGS) + +cmakebuild_mapscript_php: lexer parser + if test ! -s build/Makefile; then mkdir -p build ; cd build ; cmake .. $(CMAKEFLAGS_MAPSCRIPT_PHP); fi cd build && $(MAKE) $(MFLAGS) warning: $(error "This Makefile is used to run the \"test\" target") +api-testcase: + cd msautotest/api && rm -f result/* && export PATH=$(BUILDPATH):$(PATH) && (./run_test.py $(AUTOTEST_OPTS) || /bin/true) + +config-testcase: + cd msautotest/config && rm -f result/* && export PATH=$(BUILDPATH):$(PATH) && (./run_test.py $(AUTOTEST_OPTS) || /bin/true) + wxs-testcase: cd msautotest/wxs && chmod 777 tmp && rm -f result/* && export PATH=$(BUILDPATH):$(PATH) && (./run_test.py $(AUTOTEST_OPTS) || /bin/true) @@ -49,38 +86,38 @@ php-testcase: test -f "$(PHP_MAPSCRIPT)" && (export PHP_MAPSCRIPT_SO="../../$(PHP_MAPSCRIPT)" && cd msautotest/php && ./run_test.sh) java-testcase: - test -d "$(JAVA_MAPSCRIPT_PATH)" && (export JAVA_MAPSCRIPT_SO="../../$(JAVA_MAPSCRIPT_PATH)" && cd mapscript/java && ./run_test.sh) + test -d "$(JAVA_MAPSCRIPT_PATH)" && (export JAVA_MAPSCRIPT_SO="../../../$(JAVA_MAPSCRIPT_PATH)" && cd src/mapscript/java && ./run_test.sh) csharp-testcase: - test -d "$(CSHARP_MAPSCRIPT_PATH)" && (export CSHARP_MAPSCRIPT_SO="../../$(CSHARP_MAPSCRIPT_PATH)" && cd mapscript/csharp && ./run_test.sh) + test -d "$(CSHARP_MAPSCRIPT_PATH)" && (export CSHARP_MAPSCRIPT_SO="../../../$(CSHARP_MAPSCRIPT_PATH)" && cd src/mapscript/csharp && ./run_test.sh) perl-testcase: cd "$(PERL_MAPSCRIPT_PATH)" \ - && PERL5LIB=`pwd` \ + && export PERL5LIB=`pwd` \ && prove tests \ - && perl examples/RFC24.pl ../../../tests/test.map \ - && perl examples/shp_in_shp.pl --infile1 ../../../tests/line.shp --infile1_shpid 0 --infile2 ../../../tests/polygon.shp --infile2_shpid 0 \ - && perl examples/dump.pl --file ../../../tests/line.shp \ - && perl examples/thin.pl --input ../../../tests/polygon --output examples/junk --tolerance=5 + && perl examples/RFC24.pl ../../../../tests/test.map \ + && perl examples/shp_in_shp.pl --infile1 ../../../../tests/line.shp --infile1_shpid 0 --infile2 ../../../../tests/polygon.shp --infile2_shpid 0 \ + && perl examples/dump.pl --file ../../../../tests/line.shp \ + && perl examples/thin.pl --input ../../../../tests/polygon --output examples/junk --tolerance=5 test: cmakebuild - @$(MAKE) $(MFLAGS) wxs-testcase renderers-testcase misc-testcase gdal-testcase query-testcase sld-testcase mspython-testcase - @./print-test-results.sh + @$(MAKE) $(MFLAGS) api-testcase config-testcase wxs-testcase renderers-testcase misc-testcase gdal-testcase query-testcase sld-testcase mspython-testcase + @./scripts/print-test-results.sh @$(MAKE) $(MFLAGS) php-testcase @$(MAKE) $(MFLAGS) csharp-testcase @$(MAKE) $(MFLAGS) perl-testcase asan_compatible_tests: cmakebuild - @$(MAKE) $(MFLAGS) wxs-testcase renderers-testcase misc-testcase gdal-testcase query-testcase sld-testcase - @./print-test-results.sh + @$(MAKE) $(MFLAGS) api-testcase config-testcase wxs-testcase renderers-testcase misc-testcase gdal-testcase query-testcase sld-testcase + @./scripts/print-test-results.sh lexer: maplexer.c parser: mapparser.c -maplexer.c: maplexer.l - $(FLEX) --nounistd -Pmsyy -i -o$(CURDIR)/maplexer.c maplexer.l +maplexer.c: src/maplexer.l + $(FLEX) --nounistd -Pmsyy -i -o$(CURDIR)/src/maplexer.c src/maplexer.l -mapparser.c: mapparser.y - $(YACC) -d -o$(CURDIR)/mapparser.c mapparser.y +mapparser.c: src/mapparser.y + $(YACC) -d -o$(CURDIR)/src/mapparser.c src/mapparser.y diff --git a/README.WIN32 b/README.WIN32 index d7d760f641..cecdd45aaf 100644 --- a/README.WIN32 +++ b/README.WIN32 @@ -25,7 +25,7 @@ IMPORTANT - READ THIS FIRST: The easyest way to build Mapserver on Windows on your own is to use the build-system from http://gisinternals.com/. GISInternals provide a complete set of sources and dependencies and even -makefiles for the full version of Visual Studio (not Express oder Community). +makefiles for the full version of Visual Studio (not Express or Community). You don't have to download and compile them all by your own. If you are not using full version of Visual Studio you can not use the makefiles @@ -40,9 +40,9 @@ Windows with CMake and the GISInternals-Packages for the following reasons: you to buy it just tu build Mapserver on Windows - CMake is the configuration-system for Linux. Why should you use something else which needs to be maintainerd? - - as of today, PHP-Mapscript is not suppored for PHP-7. PHP-5.6 is build + - as of today, PHP-Mapscript is not supported for PHP-7. PHP-5.6 is build with VC11. To make PHP-Mapscript compatible with the downloadable - PHP-Version you need to build with VC11 wich is Visual Studio 2012. + PHP-Version you need to build with VC11 which is Visual Studio 2012. - GISInternals Downloads contain most dependencies. it's way easier If you want to compile Mapserver with any other version of Visual Studio you @@ -68,7 +68,7 @@ Tools Command Prompt by entering: For our first build, we will use stable releases to build mapserver. Download MSVC 2012 win32 Packages for GDAL-2.1.2 and Mapserver-7.0.2 from http://gisinternals.com/release.php. We need "Compiled binaries in a single .zip package", "GDAL and MapServer sources" and "Compiled libraries and headers". -Download the MSVC 2012 win32 Developement Kit from http://gisinternals.com/sdk.php. +Download the MSVC 2012 win32 Development Kit from http://gisinternals.com/sdk.php. Extract everything to C:\dev\work\release-1700-gdal-2-1-2-mapserver-7-0-2. There should be the directories inside now: bin, doc, gdal, include, lib, regex-0.12, relase-1700, ... After you got this done, feel free to use other packages which fit your needs better. @@ -105,7 +105,7 @@ correctly). 5. build nmake -Thats it. +That's it. You can use all CMake parameters and options as you are used from CMake to fit mapserver to your needs from here. Enjoy! @@ -122,7 +122,7 @@ instructions. Dependencies Part 2 -------------------------------------------------------------------- -The following sections descripe how to get mapserver dependencies when not +The following sections describe how to get mapserver dependencies when not downloading GISInternals packages. -------------------------------------------------------------------- @@ -208,8 +208,8 @@ downloading GISInternals packages. - Download and extract the library (at this time it is known to work with version 7.10.2 or more recent) - Open the workspace curlib.dsw located under curl-XXX/lib - - Build libcurl.dll. Note that the default active configuraion of the project - is Win32 Debug. You can modify the configuarion to Release version + - Build libcurl.dll. Note that the default active configuration of the project + is Win32 Debug. You can modify the configuration to Release version (Build/Set Active Configuration) @@ -220,11 +220,11 @@ downloading GISInternals packages. related to libcurl : * CURL_INC = -I../curl-7.10.2/include - * CURL_LIB = ../curl-7.10.2/lib/Relase/libcurl.lib + * CURL_LIB = ../curl-7.10.2/lib/Release/libcurl.lib * WINSOCK_LIB = "C:\Program Files\Microsoft Visual Studio\VC98\Lib\WSOCK32.LIB" You also need to install the libcurl.dll in your system directory. (The dll will - be located in libc-XXX/lib/Relase abfter your build of the library) + be located in libc-XXX/lib/Release abfter your build of the library) diff --git a/README.md b/README.md new file mode 100644 index 0000000000..ecbd9f8ed8 --- /dev/null +++ b/README.md @@ -0,0 +1,88 @@ +MapServer +========= + +[![Build Status](https://github.com/mapserver/mapserver/actions/workflows/build.yml/badge.svg)](https://github.com/mapserver/mapserver/actions?query=workflow%3A%22build%22+branch%3Amain) +[![Appveyor Build Status](https://ci.appveyor.com/api/projects/status/vw1n07095a8bg23u?svg=true)](https://ci.appveyor.com/project/mapserver/mapserver) +[![Coveralls Status](https://coveralls.io/repos/github/MapServer/MapServer/badge.svg?branch=main)](https://coveralls.io/github/MapServer/MapServer?branch=main) +[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.6994443.svg)](https://doi.org/10.5281/zenodo.6994443) +[![Release](https://img.shields.io/github/v/release/MapServer/MapServer)](https://github.com/MapServer/MapServer/releases) + +------- +Summary +------- + +MapServer is a system for developing web-based GIS applications. +The basic system consists of a CGI program that can be configured to +respond to a variety of spatial requests like making maps, scalebars, +and point, area and feature queries. Virtually all aspects of an +application, from web interface to map appearance can be developed +without any programming. For the more ambitious user, MapServer +applications can be enhanced using Python, PHP, Java, JavaScript or +many other web technologies. For more information and complete +documentation please visit: + + https://mapserver.org/ + +Bug reports and enhancement submissions can be reported in the MapServer +issue tracker at the following url. If you do make changes and/or enhancements, +please let us know so that they might be incorporated into future releases. + + https://github.com/MapServer/MapServer/issues + + +Join the MapServer user mailing list online at: + + https://mapserver.org/community/lists.html + +Credits +------- + +MapServer was originally written by Stephen Lime. Major funding for development of +MapServer has been provided by NASA through cooperative argreements with +the University of Minnesota, Department of Forest Resources. + +PHP/MapScript developed by DM Solutions Group. + +GDAL/OGR support and significant WMS support provided by DM Solutions Group +which received funding support from Canadian Government's GeoConnections +Program and the Canadian Forest Service. + +Raster support developed by Pete Olson of the State of Minnesota, Land +Management Information Center, and maintained by Frank Warmerdam (DM +Solutions). + +PostGIS spatial database support provided by Dave Blasby of Refractions +Research. + +PDF support developed by Jeff Spielberg and Jamie Wall of Market Insite Group, +Inc. + +OracleSpatial support developed by Rodrigo Cabral of CTTMAR/UNIVALI, Brazil. + +Portions Copyright (c) 1998 State of Minnesota, Land Management Information +Center. + +Portions derived from Shapelib, Copyright 1995-1999 Frank Warmerdam. + +Supporting packages are covered by their own copyrights. + +License +------- + +See [LICENSE.md](LICENSE.md) + +Security policy +--------------- + +See [SECURITY.md](SECURITY.md) + +How to Contribute +----------------- + +See [CONTRIBUTING.md](CONTRIBUTING.md) + +Documentation Repository +------------------------ + +Use the separate [MapServer-documentation](https://github.com/MapServer/MapServer-documentation) +repository for filing documentation tickets and changes. \ No newline at end of file diff --git a/README.rst b/README.rst deleted file mode 100644 index be676b4d46..0000000000 --- a/README.rst +++ /dev/null @@ -1,101 +0,0 @@ -MapServer -========= - -| |Build Status| |Appveyor Build Status| |Coveralls Status| - -------- -Summary -------- - -MapServer is a system for developing web-based GIS applications. -The basic system consists of a CGI program that can be configured to -respond to a variety of spatial requests like making maps, scalebars, -and point, area and feature queries. Virtually all aspects of an -application, from web interface to map appearance can be developed -without any programming. For the more ambitious user, MapServer -applications can be enhanced using Java, JavaScript or many other web -technologies. For more information and complete documentation please -visit: - - https://mapserver.org/ - -Bug reports and enhancement submissions can be reported in the MapServer -issue tracker at the following url. If you do make changes and/or enhancements, -please let us know so that they might be incorporated into future releases. - - https://github.com/mapserver/mapserver/issues - - -Join the MapServer user mailing list online at: - - https://mapserver.org/community/lists.html - - - -Credits -------- - -MapServer was originally written by Stephen Lime. Major funding for development of -MapServer has been provided by NASA through cooperative argreements with -the University of Minnesota, Department of Forest Resources. - -PHP/MapScript developed by DM Solutions Group. - -GDAL/OGR support and significant WMS support provided by DM Solutions Group -which received funding support from Canadian Government's GeoConnections -Program and the Canadian Forest Service. - -Raster support developed by Pete Olson of the State of Minnesota, Land -Management Information Center, and maintained by Frank Warmerdam (DM -Solutions). - -PostGIS spatial database support provided by Dave Blasby of Refractions -Research. - -PDF support developed by Jeff Spielberg and Jamie Wall of Market Insite Group, -Inc. - -OracleSpatial support developed by Rodrigo Cabral of CTTMAR/UNIVALI, Brazil. - -Portions Copyright (c) 1998 State of Minnesota, Land Management Information -Center. - -Portions derived from Shapelib, Copyright 1995-1999 Frank Warmerdam. - -Supporting packages are covered by their own copyrights. - -License -------- - -:: - - Copyright (c) 2008-2020 Open Source Geospatial Foundation. - Copyright (c) 1996-2008 Regents of the University of Minnesota. - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is furnished - to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies of this Software or works derived from this Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - - -.. |Build Status| image:: https://travis-ci.org/mapserver/mapserver.svg?branch=master - :target: https://travis-ci.org/mapserver/mapserver - -.. |Appveyor Build Status| image:: https://ci.appveyor.com/api/projects/status/vw1n07095a8bg23u?svg=true - :target: https://ci.appveyor.com/project/mapserver/mapserver - -.. |Coveralls Status| image:: https://coveralls.io/repos/github/mapserver/mapserver/badge.svg?branch=master - :target: https://coveralls.io/github/mapserver/mapserver?branch=master diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000000..ce3f6446f0 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,76 @@ +# MapServer Security Policy + +## Reporting a Vulnerability in MapServer + +Security/vulnerability reports should not be submitted through GitHub tickets or the public mailing lists, +but instead please provide details to the Project Steering Committee via the GitHub [Report a vulnerability](https://github.com/MapServer/MapServer/security/advisories/new) +option link at the top of this page, or send your report to the email address: +**mapserver-security nospam @ osgeo.org** (remove the blanks and ‘nospam’). + +Please follow the general guidelines for bug +submissions, when describing the vulnerability (see https://mapserver.org/development/bugs.html). + +## Note about use of AI/LLM/automated scanners + +While reporters are free to use any tool of their choice to detect issues, they +must *manually* confirm the findings of those tools with an actual reproducing +test case, not just a theoretical analysis. +The report must also be humanly checked and be kept as succint as possible. + +## Supported Versions + +The MapServer PSC (Project Steering Committee) will release patches for security vulnerabilities +for the last release branch of the **two most recent release series** (such as 8.x, 7.x, 6.x, etc..., +where "x" is the most recent release in the series, such as: 7.6.6 being supported, but +not 7.6.5). For example, once 8.8 is released, support for 8.6 will be dropped. + +Patches will only be provided **for a period of three years** from the release date of the current series. +For example, as 8.6 has been released, now 8.6.x will be supported/patched (7.6.x support ended on 2025-09-12, +which was three years from the date of the 8.0 series release). + +Currently, the following versions are supported: + +| Version | Supported | Support Until | +| ------- | ------------------ |-------------- | +| 8.6.x | :white_check_mark: | | +| 8.4.x | :x: | | +| 8.2.x | :x: | | +| 8.0.x | :x: | | +| 7.6.x | :x: | 2025-09-12 | +| 7.4.x | :x: | | +| 7.2.x | :x: | | +| 7.0.x | :x: | | +| 6.4.x | :x: | | +| < 6.4 | :x: | | + +- _MapServer 8.6.0 was released on 2025-12-03_ +- _MapServer 8.4.0 was released on 2025-01-15_ +- _MapServer 8.2.0 was released on 2024-07-08_ +- _MapServer 8.0.0 was released on 2022-09-12_ +- _MapServer 7.0.0 was released on 2015-07-24_ + +## Version Numbering: Explained + +version x.y.z means: + +**x** +- Major release series number. +- Major releases indicate substantial changes to the software and + backwards compatibility is not guaranteed across series. Current + release series is 8. + +**y** +- Minor release series number. +- Minor releases indicate smaller, functional additions or improvements + to the software and should be generally backwards compatible within a + major release series. Users should be able to confidently upgrade + from one minor release to another within the same release series, so + from 7.4.x to 7.6.x. + +**z** +- Point release series number. +- Point releases indicate maintenance releases - usually a combination of + bug and security fixes and perhaps small feature additions. Backwards + compatibility should be preserved and users should be able to confidently + upgrade between point releases within the same release series, + so from 7.6.4 to 7.6.5. diff --git a/Vagrantfile b/Vagrantfile index 3f3a1c664d..9a50de79f1 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -2,21 +2,22 @@ # vi: set ft=ruby : require 'socket' +require 'fileutils' # Vagrantfile API/syntax version. Don't touch unless you know what you're doing! VAGRANTFILE_API_VERSION = "2" $set_environment_variables = <\n" - " \n" - " \n" - "
\n" - " \n" - "\n" - ""; - -static char *olLayerMapServerTag = \ - "var mslayer = new OpenLayers.Layer.MapServer( \"MapServer Layer\",\n" - " \"[mapserv_onlineresource]\",\n" - " {layers: '[layers]'},\n" - " {singleTile: \"true\", ratio:1} )"; - -static char *olLayerWMSTag = \ - "var mslayer = new OpenLayers.Layer.WMS('MapServer Simple Viewer\',\n" - " '[mapserv_onlineresource]',\n" - " {layers: '[LAYERS]',\n" - " bbox: '[minx],[miny],[maxx],[maxy]',\n" - " width: [mapwidth], height: [mapheight], version: '[VERSION]', format:'[openlayers_format]'}," - " {singleTile: \"true\", ratio:1, projection: '[openlayers_projection]'});\n"; - -static char *processLine(mapservObj *mapserv, char *instr, FILE *stream, int mode); - -static int isValidTemplate(FILE *stream, const char *filename) -{ - char buffer[MS_BUFFER_LENGTH]; - - if(fgets(buffer, MS_BUFFER_LENGTH, stream) != NULL) { - if(!strcasestr(buffer, MS_TEMPLATE_MAGIC_STRING)) { - msSetError(MS_WEBERR, "Missing magic string, %s doesn't look like a MapServer template.", "isValidTemplate()", filename); - return MS_FALSE; - } - } - - return MS_TRUE; -} - -/* - * Redirect to (only use in CGI) - * -*/ -int msRedirect(char *url) -{ - msIO_setHeader("Status","302 Found"); - msIO_setHeader("Uri","%s",url); - msIO_setHeader("Location","%s",url); - msIO_setHeader("Content-Type","text/html"); - msIO_sendHeaders(); - return MS_SUCCESS; -} - -/* -** Sets the map extent under a variety of scenarios. -*/ -int setExtent(mapservObj *mapserv) -{ - double cellx,celly,cellsize; - - if(mapserv->Mode == TILE) { - if(MS_SUCCESS != msTileSetExtent(mapserv)) { - return MS_FAILURE; - } - } - switch(mapserv->CoordSource) { - case FROMUSERBOX: /* user passed in a map extent */ - break; - case FROMIMGBOX: /* fully interactive web, most likely with java front end */ - cellx = MS_CELLSIZE(mapserv->ImgExt.minx, mapserv->ImgExt.maxx, mapserv->ImgCols); - celly = MS_CELLSIZE(mapserv->ImgExt.miny, mapserv->ImgExt.maxy, mapserv->ImgRows); - mapserv->map->extent.minx = MS_IMAGE2MAP_X(mapserv->ImgBox.minx, mapserv->ImgExt.minx, cellx); - mapserv->map->extent.maxx = MS_IMAGE2MAP_X(mapserv->ImgBox.maxx, mapserv->ImgExt.minx, cellx); - mapserv->map->extent.maxy = MS_IMAGE2MAP_Y(mapserv->ImgBox.miny, mapserv->ImgExt.maxy, celly); /* y's are flip flopped because img/map coordinate systems are */ - mapserv->map->extent.miny = MS_IMAGE2MAP_Y(mapserv->ImgBox.maxy, mapserv->ImgExt.maxy, celly); - break; - case FROMIMGPNT: - cellx = MS_CELLSIZE(mapserv->ImgExt.minx, mapserv->ImgExt.maxx, mapserv->ImgCols); - celly = MS_CELLSIZE(mapserv->ImgExt.miny, mapserv->ImgExt.maxy, mapserv->ImgRows); - mapserv->mappnt.x = MS_IMAGE2MAP_X(mapserv->ImgPnt.x, mapserv->ImgExt.minx, cellx); - mapserv->mappnt.y = MS_IMAGE2MAP_Y(mapserv->ImgPnt.y, mapserv->ImgExt.maxy, celly); - - mapserv->map->extent.minx = mapserv->mappnt.x - .5*((mapserv->ImgExt.maxx - mapserv->ImgExt.minx)/mapserv->fZoom); /* create an extent around that point */ - mapserv->map->extent.miny = mapserv->mappnt.y - .5*((mapserv->ImgExt.maxy - mapserv->ImgExt.miny)/mapserv->fZoom); - mapserv->map->extent.maxx = mapserv->mappnt.x + .5*((mapserv->ImgExt.maxx - mapserv->ImgExt.minx)/mapserv->fZoom); - mapserv->map->extent.maxy = mapserv->mappnt.y + .5*((mapserv->ImgExt.maxy - mapserv->ImgExt.miny)/mapserv->fZoom); - break; - case FROMREFPNT: - cellx = MS_CELLSIZE(mapserv->map->reference.extent.minx, mapserv->map->reference.extent.maxx, mapserv->map->reference.width); - celly = MS_CELLSIZE(mapserv->map->reference.extent.miny, mapserv->map->reference.extent.maxy, mapserv->map->reference.height); - mapserv->mappnt.x = MS_IMAGE2MAP_X(mapserv->RefPnt.x, mapserv->map->reference.extent.minx, cellx); - mapserv->mappnt.y = MS_IMAGE2MAP_Y(mapserv->RefPnt.y, mapserv->map->reference.extent.maxy, celly); - - mapserv->map->extent.minx = mapserv->mappnt.x - .5*(mapserv->ImgExt.maxx - mapserv->ImgExt.minx); /* create an extent around that point */ - mapserv->map->extent.miny = mapserv->mappnt.y - .5*(mapserv->ImgExt.maxy - mapserv->ImgExt.miny); - mapserv->map->extent.maxx = mapserv->mappnt.x + .5*(mapserv->ImgExt.maxx - mapserv->ImgExt.minx); - mapserv->map->extent.maxy = mapserv->mappnt.y + .5*(mapserv->ImgExt.maxy - mapserv->ImgExt.miny); - break; - case FROMBUF: - mapserv->map->extent.minx = mapserv->mappnt.x - mapserv->Buffer; /* create an extent around that point, using the buffer */ - mapserv->map->extent.miny = mapserv->mappnt.y - mapserv->Buffer; - mapserv->map->extent.maxx = mapserv->mappnt.x + mapserv->Buffer; - mapserv->map->extent.maxy = mapserv->mappnt.y + mapserv->Buffer; - break; - case FROMSCALE: - cellsize = (mapserv->ScaleDenom/mapserv->map->resolution)/msInchesPerUnit(mapserv->map->units,0); /* user supplied a point and a scale denominator */ - mapserv->map->extent.minx = mapserv->mappnt.x - cellsize*(mapserv->map->width-1)/2.0; - mapserv->map->extent.miny = mapserv->mappnt.y - cellsize*(mapserv->map->height-1)/2.0; - mapserv->map->extent.maxx = mapserv->mappnt.x + cellsize*(mapserv->map->width-1)/2.0; - mapserv->map->extent.maxy = mapserv->mappnt.y + cellsize*(mapserv->map->height-1)/2.0; - break; - default: /* use the default in the mapfile if it exists */ - if((mapserv->map->extent.minx == mapserv->map->extent.maxx) && (mapserv->map->extent.miny == mapserv->map->extent.maxy)) { - msSetError(MS_WEBERR, "No way to generate map extent.", "mapserv()"); - return MS_FAILURE; - } - } - - mapserv->RawExt = mapserv->map->extent; /* save unaltered extent */ - - return MS_SUCCESS; -} - -int checkWebExtent(mapservObj *mapserv) -{ - return MS_SUCCESS; -} - -int checkWebScale(mapservObj *mapserv) -{ - int status; - rectObj work_extent = mapserv->map->extent; - - mapserv->map->cellsize = msAdjustExtent(&(work_extent), mapserv->map->width, mapserv->map->height); /* we do this cause we need a scale */ - if((status = msCalculateScale(work_extent, mapserv->map->units, mapserv->map->width, mapserv->map->height, mapserv->map->resolution, &mapserv->map->scaledenom)) != MS_SUCCESS) return status; - - if((mapserv->map->scaledenom < mapserv->map->web.minscaledenom) && (mapserv->map->web.minscaledenom > 0)) { - if(mapserv->map->web.mintemplate) { /* use the template provided */ - if(TEMPLATE_TYPE(mapserv->map->web.mintemplate) == MS_FILE) { - if((status = msReturnPage(mapserv, mapserv->map->web.mintemplate, BROWSE, NULL)) != MS_SUCCESS) return status; - } else { - if((status = msReturnURL(mapserv, mapserv->map->web.mintemplate, BROWSE)) != MS_SUCCESS) return status; - } - } else { /* force zoom = 1 (i.e. pan) */ - mapserv->fZoom = mapserv->Zoom = 1; - mapserv->ZoomDirection = 0; - mapserv->CoordSource = FROMSCALE; - mapserv->ScaleDenom = mapserv->map->web.minscaledenom; - mapserv->mappnt.x = (mapserv->map->extent.maxx + mapserv->map->extent.minx)/2; /* use center of bad extent */ - mapserv->mappnt.y = (mapserv->map->extent.maxy + mapserv->map->extent.miny)/2; - setExtent(mapserv); - mapserv->map->cellsize = msAdjustExtent(&(mapserv->map->extent), mapserv->map->width, mapserv->map->height); - if((status = msCalculateScale(mapserv->map->extent, mapserv->map->units, mapserv->map->width, mapserv->map->height, mapserv->map->resolution, &mapserv->map->scaledenom)) != MS_SUCCESS) return status; - } - } else { - if((mapserv->map->scaledenom > mapserv->map->web.maxscaledenom) && (mapserv->map->web.maxscaledenom > 0)) { - if(mapserv->map->web.maxtemplate) { /* use the template provided */ - if(TEMPLATE_TYPE(mapserv->map->web.maxtemplate) == MS_FILE) { - if((status = msReturnPage(mapserv, mapserv->map->web.maxtemplate, BROWSE, NULL)) != MS_SUCCESS) return status; - } else { - if((status = msReturnURL(mapserv, mapserv->map->web.maxtemplate, BROWSE)) != MS_SUCCESS) return status; - } - } else { /* force zoom = 1 (i.e. pan) */ - mapserv->fZoom = mapserv->Zoom = 1; - mapserv->ZoomDirection = 0; - mapserv->CoordSource = FROMSCALE; - mapserv->ScaleDenom = mapserv->map->web.maxscaledenom; - mapserv->mappnt.x = (mapserv->map->extent.maxx + mapserv->map->extent.minx)/2; /* use center of bad extent */ - mapserv->mappnt.y = (mapserv->map->extent.maxy + mapserv->map->extent.miny)/2; - setExtent(mapserv); - mapserv->map->cellsize = msAdjustExtent(&(mapserv->map->extent), mapserv->map->width, mapserv->map->height); - if((status = msCalculateScale(mapserv->map->extent, mapserv->map->units, mapserv->map->width, mapserv->map->height, mapserv->map->resolution, &mapserv->map->scaledenom)) != MS_SUCCESS) return status; - } - } - } - - return MS_SUCCESS; -} - -int msReturnTemplateQuery(mapservObj *mapserv, char *queryFormat, char **papszBuffer) -{ - imageObj *img = NULL; - int i, status; - - outputFormatObj *outputFormat=NULL; - mapObj *map = mapserv->map; - - if(!queryFormat) { - msSetError(MS_WEBERR, "Return format/mime-type not specified.", "msReturnTemplateQuery()"); - return MS_FAILURE; - } - - msApplyDefaultOutputFormats(map); - - i = msGetOutputFormatIndex(map, queryFormat); /* queryFormat can be a mime-type or name */ - if(i >= 0) outputFormat = map->outputformatlist[i]; - - if(outputFormat) { - if( MS_RENDERER_PLUGIN(outputFormat) ) { - msInitializeRendererVTable(outputFormat); - } - - /* if( MS_RENDERER_MVT(outputFormat) ) { - if( mapserv != NULL ) - checkWebScale(mapserv); - - status = msMVTWriteFromQuery(map, outputFormat, mapserv->sendheaders); - - return status; - } */ - - if( MS_RENDERER_OGR(outputFormat) ) { - if( mapserv != NULL ) - checkWebScale(mapserv); - - status = msOGRWriteFromQuery(map, outputFormat, mapserv->sendheaders); - - return status; - } - - if( !MS_RENDERER_TEMPLATE(outputFormat) ) { /* got an image format, return the query results that way */ - outputFormatObj *tempOutputFormat = map->outputformat; /* save format */ - - if( mapserv != NULL ) - checkWebScale(mapserv); - - map->outputformat = outputFormat; /* override what was given for IMAGETYPE */ - img = msDrawMap(map, MS_TRUE); - if(!img) return MS_FAILURE; - map->outputformat = tempOutputFormat; /* restore format */ - - if(mapserv == NULL || mapserv->sendheaders) { - msIO_setHeader("Content-Type", "%s", MS_IMAGE_MIME_TYPE(outputFormat)); - msIO_sendHeaders(); - } - status = msSaveImage(map, img, NULL); - msFreeImage(img); - - return status; - } - } - - /* - ** At this point we know we have a template of some sort, either the new style that references a or the old - ** style made up of external files slammed together. Either way we may have to compute a query map and other - ** images. We only create support images IF the querymap has status=MS_ON. - */ - if(map->querymap.status && mapserv != NULL ) { - checkWebScale(mapserv); - if(msGenerateImages(mapserv, MS_TRUE, MS_TRUE) != MS_SUCCESS) - return MS_FAILURE; - } - - if(outputFormat) { - const char *file = msGetOutputFormatOption( outputFormat, "FILE", NULL ); - if(!file) { - msSetError(MS_WEBERR, "Template driver requires \"FILE\" format option be set.", "msReturnTemplateQuery()"); - return MS_FAILURE; - } - - if(mapserv == NULL || mapserv->sendheaders) { - const char *attachment = msGetOutputFormatOption( outputFormat, "ATTACHMENT", NULL ); - if(attachment) - msIO_setHeader("Content-disposition","attachment; filename=%s", attachment); - msIO_setHeader("Content-Type", "%s", outputFormat->mimetype); - msIO_sendHeaders(); - } - if((status = msReturnPage(mapserv, (char *) file, BROWSE, papszBuffer)) != MS_SUCCESS) - return status; - } else { - if((status = msReturnNestedTemplateQuery(mapserv, queryFormat, papszBuffer)) != MS_SUCCESS) - return status; - } - - return MS_SUCCESS; -} - -/* -** Is a particular layer or group on, that is was it requested explicitly by the user. -*/ -int isOn(mapservObj *mapserv, char *name, char *group) -{ - int i; - - for(i=0; iNumLayers; i++) { - if(name && strcmp(mapserv->Layers[i], name) == 0) return(MS_TRUE); - if(group && strcmp(mapserv->Layers[i], group) == 0) return(MS_TRUE); - } - - return(MS_FALSE); -} - -/************************************************************************/ -/* int sortLayerByOrder(mapObj *map, char* pszOrder) */ -/* */ -/* sorth the displaying in ascending or descending order. */ -/************************************************************************/ -int sortLayerByOrder(mapObj *map, const char* pszOrder) -{ - int *panCurrentOrder = NULL; - int i = 0; - - if(!map) { - msSetError(MS_WEBERR, "Invalid pointer.", "sortLayerByOrder()"); - return MS_FAILURE; - } - /* ==================================================================== */ - /* The flag "ascending" is in fact not useful since the */ - /* default ordering is ascending. */ - /* ==================================================================== */ - - /* -------------------------------------------------------------------- */ - /* the map->layerorder should be set at this point in the */ - /* sortLayerByMetadata. */ - /* -------------------------------------------------------------------- */ - if(map->layerorder) { - panCurrentOrder = (int*)msSmallMalloc(map->numlayers * sizeof(int)); - for (i=0; inumlayers ; i++) - panCurrentOrder[i] = map->layerorder[i]; - - if(strcasecmp(pszOrder, "DESCENDING") == 0) { - for (i=0; inumlayers; i++) - map->layerorder[i] = panCurrentOrder[map->numlayers-1-i]; - } - - free(panCurrentOrder); - } - - return MS_SUCCESS; -} - - -/*! - * This function set the map->layerorder - * index order by the metadata collumn name -*/ -static int sortLayerByMetadata(mapObj *map, const char* pszMetadata) -{ - int nLegendOrder1; - int nLegendOrder2; - int i, j; - int tmp; - - if(!map) { - msSetError(MS_WEBERR, "Invalid pointer.", "sortLayerByMetadata()"); - return MS_FAILURE; - } - - /* - * Initiate to default order (Reverse mapfile order) - */ - if(map->layerorder) { - int *pnLayerOrder; - - /* Backup the original layer order to be able to reverse it */ - pnLayerOrder = (int*)msSmallMalloc(map->numlayers * sizeof(int)); - for (i=0; inumlayers ; i++) - pnLayerOrder[i] = map->layerorder[i]; - - /* Get a new layerorder array */ - free(map->layerorder); - map->layerorder = (int*)msSmallMalloc(map->numlayers * sizeof(int)); - - /* Reverse the layerorder array */ - for (i=0; inumlayers ; i++) - map->layerorder[i] = pnLayerOrder[map->numlayers - i - 1]; - - free(pnLayerOrder); - } else { - map->layerorder = (int*)msSmallMalloc(map->numlayers * sizeof(int)); - - for (i=0; inumlayers ; i++) - map->layerorder[i] = map->numlayers - i - 1; - } - - if(!pszMetadata) - return MS_SUCCESS; - - /* - * Bubble sort algo (not very efficient) - * should implement a kind of quick sort - * alog instead - */ - for (i=0; inumlayers-1; i++) { - for (j=0; jnumlayers-1-i; j++) { - const char* pszLegendOrder1 = msLookupHashTable(&(GET_LAYER(map, map->layerorder[j+1])->metadata), pszMetadata); - const char* pszLegendOrder2 = msLookupHashTable(&(GET_LAYER(map, map->layerorder[j])->metadata), pszMetadata); - - if(!pszLegendOrder1 || !pszLegendOrder2) - continue; - - nLegendOrder1 = atoi(pszLegendOrder1); - nLegendOrder2 = atoi(pszLegendOrder2); - - if(nLegendOrder1 < nLegendOrder2) { /* compare the two neighbors */ - tmp = map->layerorder[j]; /* swap a[j] and a[j+1] */ - map->layerorder[j] = map->layerorder[j+1]; - map->layerorder[j+1] = tmp; - } - } - } - - return MS_SUCCESS; -} - -/* -** This function return a pointer -** at the begining of the first occurence -** of pszTag in pszInstr. -** -** Tag can be [TAG] or [TAG something] -*/ -char *findTag(char *pszInstr, char *pszTag) -{ - char *pszTag1, *pszStart=NULL; - char *pszTemp; - int done=MS_FALSE; - int length; - - if(!pszInstr || !pszTag) { - msSetError(MS_WEBERR, "Invalid pointer.", "findTag()"); - return NULL; - } - - length = strlen(pszTag) + 1; /* adding [ character to the beginning */ - pszTag1 = (char*) msSmallMalloc(length+1); - - strcpy(pszTag1, "["); - strcat(pszTag1, pszTag); - - pszTemp = pszInstr; - while(!done) { - pszStart = strstr(pszTemp, pszTag1); - - if(pszStart == NULL) - done = MS_TRUE; /* tag not found */ - else if((*(pszStart+length) == ']' || *(pszStart+length) == ' ')) - done = MS_TRUE; /* valid tag */ - else - pszTemp += length; /* skip ahead and start over */ - } - - free(pszTag1); - - return pszStart; -} - -/* -** This function return a pointer -** to the end of the tag in pszTag -** -** The end of a tag is the next -** non-quoted ']' character. -** Return NULL if not found. -*/ - -char *findTagEnd(const char *pszTag) -{ - char *pszEnd = NULL, - *pszTmp = (char*)pszTag; - - while (pszTmp != NULL) { - if (*pszTmp == '"') - pszTmp = strchr(pszTmp+1,'"'); - if ((pszTmp == NULL) || (*pszTmp == ']')) { - pszEnd = pszTmp; - pszTmp = NULL; - } else - pszTmp++; - } - - return pszEnd; -} - -/* -** Return a hashtableobj from instr of all -** arguments. hashtable must be freed by caller. -*/ -int getTagArgs(char* pszTag, char* pszInstr, hashTableObj **ppoHashTable) -{ - char *pszStart, *pszEnd, *pszArgs; - int nLength; - char **papszArgs, **papszVarVal; - int nArgs, nDummy; - int i; - - if(!pszTag || !pszInstr) { - msSetError(MS_WEBERR, "Invalid pointer.", "getTagArgs()"); - return MS_FAILURE; - } - - /* set position to the begining of tag */ - pszStart = findTag(pszInstr, pszTag); - - if(pszStart) { - /* find ending position */ - pszEnd = findTagEnd(pszStart); - - if(pszEnd) { - /* skip the tag name */ - pszStart = pszStart + strlen(pszTag) + 1; - - /* get length of all args */ - nLength = pszEnd - pszStart; - - if(nLength > 0) { /* is there arguments ? */ - pszArgs = (char*)msSmallMalloc(nLength + 1); - strlcpy(pszArgs, pszStart, nLength+1); - - if(!(*ppoHashTable)) - *ppoHashTable = msCreateHashTable(); - - /* put all arguments seperate by space in a hash table */ - papszArgs = msStringTokenize(pszArgs, " ", &nArgs, MS_TRUE); - - /* msReturnTemplateQuerycheck all argument if they have values */ - for (i=0; i 0) { - *pszResult = (char*)msSmallMalloc(nLength + 1); - - /* copy string beetween start and end tag */ - strlcpy(*pszResult, pszStart, nLength+1); - - (*pszResult)[nLength] = '\0'; - } - } else { - msSetError(MS_WEBERR, "Malformed [%s] tag.", "getInlineTag()", pszTag); - return MS_FAILURE; - } - } - - msFree(pszEndTag); - - return MS_SUCCESS; -} - -/*! - * this function process all if tag in pszInstr. - * this function return a modified pszInstr. - * ht mus contain all variables needed by the function - * to interpret if expression. - * - * If bLastPass is true then all tests for 'null' values will be - * considered true if the corresponding value is not set. -*/ -int processIfTag(char **pszInstr, hashTableObj *ht, int bLastPass) -{ - /* char *pszNextInstr = pszInstr; */ - char *pszStart, *pszEnd=NULL; - const char *pszName, *pszValue, *pszOperator, *pszHTValue; - char *pszThen=NULL; - char *pszIfTag; - char *pszPatIn=NULL, *pszPatOut=NULL, *pszTmp; - int nInst = 0; - int bEmpty = 0; - int nLength; - - hashTableObj *ifArgs=NULL; - - if(!*pszInstr) { - msSetError(MS_WEBERR, "Invalid pointer.", "processIfTag()"); - return MS_FAILURE; - } - - /* find the if start tag */ - - pszStart = findTag(*pszInstr, "if"); - - while (pszStart) { - pszPatIn = findTag(pszStart, "if"); - pszPatOut = strstr(pszStart, "[/if]"); - pszTmp = pszPatIn; - - do { - if(pszPatIn && pszPatIn < pszPatOut) { - nInst++; - pszTmp = pszPatIn; - } - - if(pszPatOut && ((pszPatIn == NULL) || pszPatOut < pszPatIn)) { - pszEnd = pszPatOut; - nInst--; - pszTmp = pszPatOut; - } - - pszPatIn = findTag(pszTmp+1, "if"); - pszPatOut = strstr(pszTmp+1, "[/if]"); - - } while (pszTmp != NULL && nInst > 0); - - /* get the then string (if expression is true) */ - if(getInlineTag("if", pszStart, &pszThen) != MS_SUCCESS) { - msSetError(MS_WEBERR, "Malformed then if tag.", "processIfTag()"); - return MS_FAILURE; - } - - /* retrieve if tag args */ - if(getTagArgs("if", pszStart, &ifArgs) != MS_SUCCESS) { - msSetError(MS_WEBERR, "Malformed args if tag.", "processIfTag()"); - return MS_FAILURE; - } - - pszName = msLookupHashTable(ifArgs, "name"); - pszValue = msLookupHashTable(ifArgs, "value"); - pszOperator = msLookupHashTable(ifArgs, "oper"); - if(pszOperator == NULL) /* Default operator if not set is "eq" */ - pszOperator = "eq"; - - bEmpty = 0; - - if(pszName) { - /* build the complete if tag ([if all_args]then string[/if]) */ - /* to replace if by then string if expression is true */ - /* or by a white space if not. */ - nLength = pszEnd - pszStart; - pszIfTag = (char*)msSmallMalloc(nLength + 6); - strlcpy(pszIfTag, pszStart, nLength+1); - pszIfTag[nLength] = '\0'; - strcat(pszIfTag, "[/if]"); - - pszHTValue = msLookupHashTable(ht, pszName); - - if(strcmp(pszOperator, "neq") == 0) { - if(pszValue && pszHTValue && strcasecmp(pszValue, pszHTValue) != 0) { - *pszInstr = msReplaceSubstring(*pszInstr, pszIfTag, pszThen); - } else if(pszHTValue) { - *pszInstr = msReplaceSubstring(*pszInstr, pszIfTag, ""); - bEmpty = 1; - } - } else if(strcmp(pszOperator, "eq") == 0) { - if(pszValue && pszHTValue && strcasecmp(pszValue, pszHTValue) == 0) { - *pszInstr = msReplaceSubstring(*pszInstr, pszIfTag, pszThen); - } else if(pszHTValue) { - *pszInstr = msReplaceSubstring(*pszInstr, pszIfTag, ""); - bEmpty = 1; - } - } else if(strcmp(pszOperator, "isnull") == 0) { - if(pszHTValue != NULL) { - /* We met a non-null value... condition is false */ - *pszInstr = msReplaceSubstring(*pszInstr, pszIfTag, ""); - bEmpty = 1; - } else if(bLastPass) { - /* On last pass, if value is still null then condition is true */ - *pszInstr = msReplaceSubstring(*pszInstr, pszIfTag, pszThen); - } - } else if(strcmp(pszOperator, "isset") == 0) { - if(pszHTValue != NULL) { - /* Found a non-null value... condition is true */ - *pszInstr = msReplaceSubstring(*pszInstr, pszIfTag, pszThen); - } else if(bLastPass) { - /* On last pass, if value still not set then condition is false */ - *pszInstr = msReplaceSubstring(*pszInstr, pszIfTag, ""); - bEmpty = 1; - } - } else { - msSetError(MS_WEBERR, "Unsupported operator (%s) in if tag.", "processIfTag()", pszOperator); - return MS_FAILURE; - } - - if(pszIfTag) - free(pszIfTag); - - pszIfTag = NULL; - } - - if(pszThen) - free (pszThen); - - pszThen=NULL; - - msFreeHashTable(ifArgs); - ifArgs=NULL; - - /* find the if start tag */ - if(bEmpty) - pszStart = findTag(pszStart, "if"); - else - pszStart = findTag(pszStart + 1, "if"); - } - - return MS_SUCCESS; -} - -/* Helper function to return the text before the supplied string2 in string1. */ -static char *getPreTagText(const char *string1, const char *string2) -{ - int n; - char *result, *tmpstr; - - if((tmpstr = strstr(string1, string2)) == NULL) return msStrdup(""); /* return an empty string */ - - n = strlen(string1) - strlen(tmpstr); - result = (char *) msSmallMalloc(n + 1); - strlcpy(result, string1, n+1); - - return result; -} - -/* Helper function to retunr the text after the supplied string2 in string1. */ -static char *getPostTagText(const char *string1, const char *string2) -{ - char *tmpstr; - - if((tmpstr = strstr(string1, string2)) == NULL) return msStrdup(""); /* return an empty string */ - - tmpstr += strlen(string2); /* skip string2 */ - return msStrdup(tmpstr); -} - -/* -** Function to process a [feature ...] tag. This tag can *only* be found within -** a [resultset ...][/resultset] block. -*/ -static int processFeatureTag(mapservObj *mapserv, char **line, layerObj *layer) -{ - char *preTag, *postTag; /* text before and after the tag */ - - const char *argValue; - char *tag, *tagInstance, *tagStart; - hashTableObj *tagArgs=NULL; - - int limit=-1; - const char *trimLast=NULL; - - int i, j, status; - - if(!*line) { - msSetError(MS_WEBERR, "Invalid line pointer.", "processFeatureTag()"); - return(MS_FAILURE); - } - - tagStart = findTag(*line, "feature"); - if(!tagStart) return(MS_SUCCESS); /* OK, just return; */ - - /* check for any tag arguments */ - if(getTagArgs("feature", tagStart, &tagArgs) != MS_SUCCESS) return(MS_FAILURE); - if(tagArgs) { - argValue = msLookupHashTable(tagArgs, "limit"); - if(argValue) limit = atoi(argValue); - - argValue = msLookupHashTable(tagArgs, "trimlast"); - if(argValue) trimLast = argValue; - } - - if(strstr(*line, "[/feature]") == NULL) { /* we know the closing tag must be here, if not throw an error */ - msSetError(MS_WEBERR, "[feature] tag found without closing [/feature].", "processFeatureTag()"); - msFreeHashTable(tagArgs); - return(MS_FAILURE); - } - - if(getInlineTag("feature", *line, &tag) != MS_SUCCESS) { - msSetError(MS_WEBERR, "Malformed feature tag.", "processFeatureTag()"); - msFreeHashTable(tagArgs); - return MS_FAILURE; - } - - preTag = getPreTagText(*line, "[feature"); - postTag = getPostTagText(*line, "[/feature]"); - - /* start rebuilding **line */ - free(*line); - *line = preTag; - - /* we know the layer has query results or we wouldn't be in this code */ - -#if 0 - status = msLayerOpen(layer); /* open the layer */ - if(status != MS_SUCCESS) return status; - status = msLayerGetItems(layer); /* retrieve all the item names */ - if(status != MS_SUCCESS) return status; -#endif - - if(layer->numjoins > 0) { /* initialize necessary JOINs here */ - for(j=0; jnumjoins; j++) { - status = msJoinConnect(layer, &(layer->joins[j])); - if(status != MS_SUCCESS) { - msFreeHashTable(tagArgs); - msFree(postTag); - msFree(tag); - return status; - } - } - } - - mapserv->LRN = 1; /* layer result counter */ - mapserv->resultlayer = layer; - msInitShape(&(mapserv->resultshape)); - - if(limit == -1) /* return all */ - limit = layer->resultcache->numresults; - else - limit = MS_MIN(limit, layer->resultcache->numresults); - - for(i=0; iresultshape), &(layer->resultcache->results[i])); - if(status != MS_SUCCESS) { - msFreeHashTable(tagArgs); - msFree(postTag); - msFree(tag); - return status; - } - - mapserv->resultshape.classindex = msShapeGetClass(layer, layer->map, &mapserv->resultshape, NULL, -1); - - /* prepare any necessary JOINs here (one-to-one only) */ - if(layer->numjoins > 0) { - for(j=0; jnumjoins; j++) { - if(layer->joins[j].type == MS_JOIN_ONE_TO_ONE) { - msJoinPrepare(&(layer->joins[j]), &(mapserv->resultshape)); - msJoinNext(&(layer->joins[j])); /* fetch the first row */ - } - } - } - - /* - ** if necessary trim a few characters off the end of the tag - */ - if(trimLast && (i == limit-1)) { - char *ptr; - if((ptr = strrstr(tag, trimLast)) != NULL) - *ptr = '\0'; - } - - /* process the tag */ - tagInstance = processLine(mapserv, tag, NULL, QUERY); /* do substitutions */ - *line = msStringConcatenate(*line, tagInstance); /* grow the line */ - - free(tagInstance); - msFreeShape(&(mapserv->resultshape)); /* init too */ - - mapserv->RN++; /* increment counters */ - mapserv->LRN++; - } - - /* msLayerClose(layer); */ - mapserv->resultlayer = NULL; /* necessary? */ - - *line = msStringConcatenate(*line, postTag); - - /* - ** clean up - */ - free(postTag); - free(tag); - msFreeHashTable(tagArgs); - - return(MS_SUCCESS); -} - -/* -** Function to process a [resultset ...] tag. -*/ -static int processResultSetTag(mapservObj *mapserv, char **line, FILE *stream) -{ - char lineBuffer[MS_BUFFER_LENGTH]; - int foundTagEnd; - - char *preTag, *postTag; /* text before and after the tag */ - - char *tag, *tagStart; - hashTableObj *tagArgs=NULL; - - const char *layerName=NULL; - const char *nodata=NULL; - - int layerIndex=-1; - layerObj *lp; - - if(!*line) { - msSetError(MS_WEBERR, "Invalid line pointer.", "processResultSetTag()"); - return(MS_FAILURE); - } - - tagStart = findTag(*line, "resultset"); - if(!tagStart) return(MS_SUCCESS); /* OK, just return; */ - - while (tagStart) { - /* initialize the tag arguments */ - layerName = NULL; - - - /* check for any tag arguments */ - if(getTagArgs("resultset", tagStart, &tagArgs) != MS_SUCCESS) return(MS_FAILURE); - if(tagArgs) { - layerName = msLookupHashTable(tagArgs, "layer"); - nodata = msLookupHashTable(tagArgs, "nodata"); - } - - if(!layerName) { - msSetError(MS_WEBERR, "[resultset] tag missing required 'layer' argument.", "processResultSetTag()"); - msFreeHashTable(tagArgs); - return(MS_FAILURE); - } - - layerIndex = msGetLayerIndex(mapserv->map, layerName); - if(layerIndex>=mapserv->map->numlayers || layerIndex<0) { - msSetError(MS_MISCERR, "Layer named '%s' does not exist.", "processResultSetTag()", layerName); - msFreeHashTable(tagArgs); - return MS_FAILURE; - } - lp = GET_LAYER(mapserv->map, layerIndex); - - if(strstr(*line, "[/resultset]") == NULL) { /* read ahead */ - if(!stream) { - msSetError(MS_WEBERR, "Invalid file pointer.", "processResultSetTag()"); - msFreeHashTable(tagArgs); - return(MS_FAILURE); - } - - foundTagEnd = MS_FALSE; - while(!foundTagEnd) { - if(fgets(lineBuffer, MS_BUFFER_LENGTH, stream) != NULL) { - *line = msStringConcatenate(*line, lineBuffer); - if(strstr(*line, "[/resultset]") != NULL) - foundTagEnd = MS_TRUE; - } else - break; /* ran out of file */ - } - if(foundTagEnd == MS_FALSE) { - msSetError(MS_WEBERR, "[resultset] tag found without closing [/resultset].", "processResultSetTag()"); - msFreeHashTable(tagArgs); - return(MS_FAILURE); - } - } - - if(getInlineTag("resultset", *line, &tag) != MS_SUCCESS) { - msSetError(MS_WEBERR, "Malformed resultset tag.", "processResultSetTag()"); - msFreeHashTable(tagArgs); - return MS_FAILURE; - } - - preTag = getPreTagText(*line, "[resultset"); /* TODO: need to handle tags in these */ - postTag = getPostTagText(*line, "[/resultset]"); - - /* start rebuilding **line */ - free(*line); - *line = preTag; - - if(lp->resultcache && lp->resultcache->numresults > 0) { - /* probably will need a while-loop here to handle multiple instances of [feature ...] tags */ - if(processFeatureTag(mapserv, &tag, lp) != MS_SUCCESS) { - msFreeHashTable(tagArgs); - return(MS_FAILURE); /* TODO: how to handle */ - } - *line = msStringConcatenate(*line, tag); - } else if(nodata) { - *line = msStringConcatenate(*line, nodata); - } - - *line = msStringConcatenate(*line, postTag); - - /* clean up */ - free(postTag); - free(tag); - - tagStart = findTag(*line, "resultset"); - } - msFreeHashTable(tagArgs); - - return(MS_SUCCESS); -} - -/* -** Function process a [include src="..."] tag. -** -** TODO's: -** - allow URLs -*/ -static int processIncludeTag(mapservObj *mapserv, char **line, FILE *stream, int mode) -{ - char *tag, *tagStart, *tagEnd; - hashTableObj *tagArgs=NULL; - int tagOffset, tagLength; - - char *content=NULL, *processedContent=NULL; - const char *src=NULL; - - FILE *includeStream; - char buffer[MS_BUFFER_LENGTH], path[MS_MAXPATHLEN]; - - if(!*line) { - msSetError(MS_WEBERR, "Invalid line pointer.", "processIncludeTag()"); - return(MS_FAILURE); - } - - tagStart = findTag(*line, "include"); - - /* It is OK to have no include tags, just return. */ - if( !tagStart ) return MS_SUCCESS; - - while( tagStart ) { - tagOffset = tagStart - *line; - - /* check for any tag arguments */ - if(getTagArgs("include", tagStart, &tagArgs) != MS_SUCCESS) return(MS_FAILURE); - if(tagArgs) { - src = msLookupHashTable(tagArgs, "src"); - } - - if(!src) return(MS_SUCCESS); /* don't process the tag, could be something else so return MS_SUCCESS */ - - if((includeStream = fopen(msBuildPath(path, mapserv->map->mappath, src), "r")) == NULL) { - msSetError(MS_IOERR, "%s", "processIncludeTag()", src); - return MS_FAILURE; - } - - if(isValidTemplate(includeStream, src) != MS_TRUE) { - fclose(includeStream); - return MS_FAILURE; - } - - while(fgets(buffer, MS_BUFFER_LENGTH, includeStream) != NULL) - content = msStringConcatenate(content, buffer); - - /* done with included file handle */ - fclose(includeStream); - - /* find the end of the tag */ - tagEnd = findTagEnd(tagStart); - tagEnd++; - - /* build the complete tag so we can do substitution */ - tagLength = tagEnd - tagStart; - tag = (char *) msSmallMalloc(tagLength + 1); - strlcpy(tag, tagStart, tagLength+1); - - /* process any other tags in the content */ - processedContent = processLine(mapserv, content, stream, mode); - - /* do the replacement */ - *line = msReplaceSubstring(*line, tag, processedContent); - - /* clean up */ - free(tag); - tag = NULL; - msFreeHashTable(tagArgs); - tagArgs=NULL; - free(content); - free(processedContent); - - if((*line)[tagOffset] != '\0') - tagStart = findTag(*line+tagOffset+1, "include"); - else - tagStart = NULL; - } - - return(MS_SUCCESS); -} - -/* -** Function to process an [item ...] tag: line contains the tag, shape holds the attributes. -*/ -enum ITEM_ESCAPING {ESCAPE_HTML, ESCAPE_URL, ESCAPE_JSON, ESCAPE_NONE}; - -static int processItemTag(layerObj *layer, char **line, shapeObj *shape) -{ - int i, j; - - char *tag, *tagStart, *tagEnd; - hashTableObj *tagArgs=NULL; - int tagLength; - char *encodedTagValue=NULL, *tagValue=NULL; - - const char *argValue=NULL; - - const char *name=NULL, *pattern=NULL; - const char *format=NULL, *nullFormat=NULL; - int precision; - int padding; - int uc, lc, commify; - int escape; - - if(!*line) { - msSetError(MS_WEBERR, "Invalid line pointer.", "processItemTag()"); - return(MS_FAILURE); - } - - tagStart = findTag(*line, "item"); - - if(!tagStart) return(MS_SUCCESS); /* OK, just return; */ - - while (tagStart) { - format = "$value"; /* initialize the tag arguments */ - nullFormat = ""; - precision = -1; - padding = -1; - name = pattern = NULL; - uc = lc = commify = MS_FALSE; - escape=ESCAPE_HTML; - - /* check for any tag arguments */ - if(getTagArgs("item", tagStart, &tagArgs) != MS_SUCCESS) return(MS_FAILURE); - if(tagArgs) { - argValue = msLookupHashTable(tagArgs, "name"); - if(argValue) name = argValue; - - argValue = msLookupHashTable(tagArgs, "pattern"); - if(argValue) pattern = argValue; - - argValue = msLookupHashTable(tagArgs, "precision"); - if(argValue) precision = atoi(argValue); - - argValue = msLookupHashTable(tagArgs, "padding"); - if (argValue) padding = atoi(argValue); - - argValue = msLookupHashTable(tagArgs, "format"); - if(argValue) format = argValue; - - argValue = msLookupHashTable(tagArgs, "nullformat"); - if(argValue) nullFormat = argValue; - - argValue = msLookupHashTable(tagArgs, "uc"); - if(argValue && strcasecmp(argValue, "true") == 0) uc = MS_TRUE; - - argValue = msLookupHashTable(tagArgs, "lc"); - if(argValue && strcasecmp(argValue, "true") == 0) lc = MS_TRUE; - - argValue = msLookupHashTable(tagArgs, "commify"); - if(argValue && strcasecmp(argValue, "true") == 0) commify = MS_TRUE; - - argValue = msLookupHashTable(tagArgs, "escape"); - if(argValue && strcasecmp(argValue, "url") == 0) escape = ESCAPE_URL; - else if(argValue && strcasecmp(argValue, "none") == 0) escape = ESCAPE_NONE; - else if(argValue && strcasecmp(argValue, "json") == 0) escape = ESCAPE_JSON; - - /* TODO: deal with sub strings */ - } - - if(!name) { - msSetError(MS_WEBERR, "Item tag contains no name attribute.", "processItemTag()"); - return(MS_FAILURE); - } - - for(i=0; inumitems; i++) - if(strcasecmp(name, layer->items[i]) == 0) break; - - if(i == layer->numitems) { - msSetError(MS_WEBERR, "Item name (%s) not found in layer item list.", "processItemTag()", name); - return(MS_FAILURE); - } - - /* - ** now we know which item so build the tagValue - */ - if(shape->values[i] && strlen(shape->values[i]) > 0) { - char *itemValue=NULL; - - /* set tag text depending on pattern (if necessary), nullFormat can contain $value (#3637) */ - if(pattern && msEvalRegex(pattern, shape->values[i]) != MS_TRUE) - tagValue = msStrdup(nullFormat); - else - tagValue = msStrdup(format); - - if(precision != -1) { - char numberFormat[16]; - - itemValue = (char *) msSmallMalloc(64); /* plenty big */ - snprintf(numberFormat, sizeof(numberFormat), "%%.%dlf", precision); - snprintf(itemValue, 64, numberFormat, atof(shape->values[i])); - } else - itemValue = msStrdup(shape->values[i]); - - if(commify == MS_TRUE) - itemValue = msCommifyString(itemValue); - - /* apply other effects */ - if(uc == MS_TRUE) - for(j=0; j 0 && padding < 1000) { - int paddedSize = strlen(tagValue) + padding + 1; - char *paddedValue = NULL; - paddedValue = (char *) msSmallMalloc(paddedSize); - snprintf(paddedValue, paddedSize, "%-*s", padding, tagValue); - msFree(tagValue); - tagValue = paddedValue; - } - - if(!tagValue) { - msSetError(MS_WEBERR, "Error applying item format.", "processItemTag()"); - return(MS_FAILURE); /* todo leaking... */ - } - } else { - tagValue = msStrdup(nullFormat); /* attribute value is NULL or empty */ - } - - /* find the end of the tag */ - tagEnd = findTagEnd(tagStart); - tagEnd++; - - /* build the complete tag so we can do substitution */ - tagLength = tagEnd - tagStart; - tag = (char *) msSmallMalloc(tagLength + 1); - strlcpy(tag, tagStart, tagLength+1); - - /* do the replacement */ - switch(escape) { - case ESCAPE_HTML: - encodedTagValue = msEncodeHTMLEntities(tagValue); - *line = msReplaceSubstring(*line, tag, encodedTagValue); - break; - case ESCAPE_JSON: - encodedTagValue = msEscapeJSonString(tagValue); - *line = msReplaceSubstring(*line, tag, encodedTagValue); - break; - case ESCAPE_URL: - encodedTagValue = msEncodeUrl(tagValue); - *line = msReplaceSubstring(*line, tag, encodedTagValue); - break; - case ESCAPE_NONE: - *line = msReplaceSubstring(*line, tag, tagValue); - break; - default: - break; - } - - /* clean up */ - free(tag); - tag = NULL; - msFreeHashTable(tagArgs); - tagArgs=NULL; - msFree(tagValue); - tagValue=NULL; - msFree(encodedTagValue); - encodedTagValue=NULL; - - tagStart = findTag(*line, "item"); - } - - return(MS_SUCCESS); -} - -/* -** Function process any number of MapServer extent tags (e.g. shpext, mapext, etc...). -*/ -static int processExtentTag(mapservObj *mapserv, char **line, char *name, rectObj *extent, projectionObj *rectProj) -{ - char *tag, *tagStart, *tagEnd; - hashTableObj *tagArgs=NULL; - int tagOffset, tagLength; - - char *encodedTagValue=NULL, *tagValue=NULL; - - rectObj tempExtent; - int escape; - - char number[64]; /* holds a single number in the extent */ - char numberFormat[16]; - - if(!*line) { - msSetError(MS_WEBERR, "Invalid line pointer.", "processExtentTag()"); - return(MS_FAILURE); - } - - tagStart = findTag(*line, name); /* this supports any extent */ - - /* It is OK to have no include tags, just return. */ - if(!tagStart) return MS_SUCCESS; - - /* hack to handle tags like 'mapext_esc' easily */ - if(strstr(name, "_esc")) escape = ESCAPE_URL; - - while(tagStart) { - double xExpand = 0, yExpand = 0; /* set tag argument defaults */ - int precision = -1; - const char* format = "$minx $miny $maxx $maxy"; - const char* projectionString = NULL; - - if(strstr(name, "_esc")) - escape = ESCAPE_URL; - else - escape = ESCAPE_HTML; - - tagOffset = tagStart - *line; - - /* check for any tag arguments */ - if(getTagArgs(name, tagStart, &tagArgs) != MS_SUCCESS) return(MS_FAILURE); - if(tagArgs) { - const char* argValue = msLookupHashTable(tagArgs, "expand"); - if(argValue) { - if(strchr(argValue, '%') != NULL) { - float f; - sscanf(argValue, "%f%%", &f); - xExpand = ((f/100.0)*(extent->maxx-extent->minx))/2; - yExpand = ((f/100.0)*(extent->maxy-extent->miny))/2; - } else { - xExpand = atof(argValue); - yExpand = xExpand; - } - } - - argValue = msLookupHashTable(tagArgs, "escape"); - if(argValue && strcasecmp(argValue, "url") == 0) escape = ESCAPE_URL; - else if(argValue && strcasecmp(argValue, "none") == 0) escape = ESCAPE_NONE; - - argValue = msLookupHashTable(tagArgs, "format"); - if(argValue) format = argValue; - - argValue = msLookupHashTable(tagArgs, "precision"); - if(argValue) precision = atoi(argValue); - - argValue = msLookupHashTable(tagArgs, "proj"); - if(argValue) projectionString = argValue; - } - - tempExtent.minx = extent->minx - xExpand; - tempExtent.miny = extent->miny - yExpand; - tempExtent.maxx = extent->maxx + xExpand; - tempExtent.maxy = extent->maxy + yExpand; - - /* no big deal to convert from file to image coordinates, but what are the image parameters */ - if(rectProj && projectionString && strcasecmp(projectionString,"image") == 0) { - precision = 0; - - /* if necessary, project the shape to match the map */ - if(msProjectionsDiffer(rectProj, &(mapserv->map->projection))) - msProjectRect(rectProj, &mapserv->map->projection, &tempExtent); - - /* convert tempExtent to image coordinates based on the map extent and cellsize */ - tempExtent.minx = MS_MAP2IMAGE_X(tempExtent.minx, mapserv->map->extent.minx, mapserv->map->cellsize); - tempExtent.miny = MS_MAP2IMAGE_Y(tempExtent.miny, mapserv->map->extent.maxy, mapserv->map->cellsize); - tempExtent.maxx = MS_MAP2IMAGE_X(tempExtent.minx, mapserv->map->extent.minx, mapserv->map->cellsize); - tempExtent.maxy = MS_MAP2IMAGE_Y(tempExtent.miny, mapserv->map->extent.maxy, mapserv->map->cellsize); - } else if(rectProj && projectionString) { - projectionObj projection; - msInitProjection(&projection); - msProjectionInheritContextFrom(&projection, &mapserv->map->projection); - - if(MS_SUCCESS != msLoadProjectionString(&projection, projectionString)) return MS_FAILURE; - - if(msProjectionsDiffer(rectProj, &projection)) - msProjectRect(rectProj, &projection, &tempExtent); - } - - tagValue = msStrdup(format); - - if(precision != -1) - snprintf(numberFormat, sizeof(numberFormat), "%%.%dlf", precision); - else - snprintf(numberFormat, sizeof(numberFormat), "%%f"); - - snprintf(number, sizeof(number), numberFormat, tempExtent.minx); - tagValue = msReplaceSubstring(tagValue, "$minx", number); - snprintf(number, sizeof(number), numberFormat, tempExtent.miny); - tagValue = msReplaceSubstring(tagValue, "$miny", number); - snprintf(number, sizeof(number), numberFormat, tempExtent.maxx); - tagValue = msReplaceSubstring(tagValue, "$maxx", number); - snprintf(number, sizeof(number), numberFormat, tempExtent.maxy); - tagValue = msReplaceSubstring(tagValue, "$maxy", number); - - /* find the end of the tag */ - tagEnd = findTagEnd(tagStart); - tagEnd++; - - /* build the complete tag so we can do substitution */ - tagLength = tagEnd - tagStart; - tag = (char *) msSmallMalloc(tagLength + 1); - strlcpy(tag, tagStart, tagLength+1); - - /* do the replacement */ - switch(escape) { - case ESCAPE_HTML: - encodedTagValue = msEncodeHTMLEntities(tagValue); - *line = msReplaceSubstring(*line, tag, encodedTagValue); - break; - case ESCAPE_URL: - encodedTagValue = msEncodeUrl(tagValue); - *line = msReplaceSubstring(*line, tag, encodedTagValue); - break; - case ESCAPE_NONE: - *line = msReplaceSubstring(*line, tag, tagValue); - break; - default: - break; - } - - /* clean up */ - free(tag); - tag = NULL; - msFreeHashTable(tagArgs); - tagArgs=NULL; - msFree(tagValue); - tagValue=NULL; - msFree(encodedTagValue); - encodedTagValue=NULL; - - if((*line)[tagOffset] != '\0') - tagStart = findTag(*line+tagOffset+1, name); - else - tagStart = NULL; - } - - return(MS_SUCCESS); -} - -// RFC 77 TODO: Need to validate these changes with Assefa... -static int processShplabelTag(layerObj *layer, char **line, shapeObj *origshape) -{ - char *tag, *tagStart, *tagEnd; - char *tagValue=NULL; - hashTableObj *tagArgs=NULL; - int tagOffset, tagLength; - const char *format; - const char *argValue=NULL; - const char *projectionString=NULL; - shapeObj tShape; - int precision=0; - int clip_to_map=MS_TRUE; - int use_label_settings=MS_FALSE; - double cellsize=0; - int labelposvalid = MS_FALSE; - pointObj labelPos; - int status; - char number[64]; /* holds a single number in the extent */ - char numberFormat[16]; - shapeObj *shape = NULL; - - if(!*line) { - msSetError(MS_WEBERR, "Invalid line pointer.", "processShplabelTag()"); - return(MS_FAILURE); - } - if(msCheckParentPointer(layer->map,"map") == MS_FAILURE) - return MS_FAILURE; - - tagStart = findTag(*line, "shplabel"); - - /* It is OK to have no shplabel tags, just return. */ - if(!tagStart) - return MS_SUCCESS; - - if(!origshape || origshape->numlines <= 0) { /* I suppose we need to make sure the part has vertices (need shape checker?) */ - msSetError(MS_WEBERR, "Null or empty shape.", "processShplabelTag()"); - return(MS_FAILURE); - } - - while(tagStart) { - if(shape) msFreeShape(shape); - shape = (shapeObj *) msSmallMalloc(sizeof(shapeObj)); - msInitShape(shape); - msCopyShape(origshape, shape); - - projectionString = NULL; - format = "$x,$y"; - tagOffset = tagStart - *line; - - if(getTagArgs("shplabel", tagStart, &tagArgs) != MS_SUCCESS) return(MS_FAILURE); - if(tagArgs) { - argValue = msLookupHashTable(tagArgs, "format"); - if(argValue) format = argValue; - - argValue = msLookupHashTable(tagArgs, "precision"); - if(argValue) precision = atoi(argValue); - - argValue = msLookupHashTable(tagArgs, "proj"); - if(argValue) projectionString = argValue; - - argValue = msLookupHashTable(tagArgs, "clip_to_map"); - if(argValue) { - if(strcasecmp(argValue,"false") == 0) clip_to_map = MS_FALSE; - } - - argValue = msLookupHashTable(tagArgs, "use_label_settings"); - if(argValue) { - if(strcasecmp(argValue,"true") == 0) use_label_settings = MS_TRUE; - } - } - - labelPos.x = -1; - labelPos.y = -1; - msInitShape(&tShape); - - tShape.type = MS_SHAPE_LINE; - tShape.line = (lineObj *) msSmallMalloc(sizeof(lineObj)); - tShape.numlines = 1; - tShape.line[0].point = NULL; /* initialize the line */ - tShape.line[0].numpoints = 0; - - if(layer->map->cellsize <= 0) - cellsize = MS_MAX(MS_CELLSIZE(layer->map->extent.minx, layer->map->extent.maxx, layer->map->width), MS_CELLSIZE(layer->map->extent.miny, layer->map->extent.maxy, layer->map->height)); - else - cellsize = layer->map->cellsize ; - - if(shape->type == MS_SHAPE_POINT) { - labelposvalid = MS_FALSE; - if(shape->numlines > 0 && shape->line[0].numpoints > 0) { - labelposvalid = MS_TRUE; - labelPos = shape->line[0].point[0]; - if(layer->transform == MS_TRUE) { - if(layer->project && msProjectionsDiffer(&(layer->projection), &(layer->map->projection))) - { - if( layer->reprojectorLayerToMap == NULL ) - { - layer->reprojectorLayerToMap = msProjectCreateReprojector( - &layer->projection, &layer->map->projection); - } - if( layer->reprojectorLayerToMap ) - { - msProjectShapeEx(layer->reprojectorLayerToMap, shape); - } - } - - labelPos = shape->line[0].point[0]; - labelPos.x = MS_MAP2IMAGE_X(labelPos.x, layer->map->extent.minx, cellsize); - labelPos.y = MS_MAP2IMAGE_Y(labelPos.y, layer->map->extent.maxy, cellsize); - } - } - } else if(shape->type == MS_SHAPE_LINE) { - labelposvalid = MS_FALSE; - if(layer->transform == MS_TRUE) { - if(layer->project && msProjectionsDiffer(&(layer->projection), &(layer->map->projection))) - { - if( layer->reprojectorLayerToMap == NULL ) - { - layer->reprojectorLayerToMap = msProjectCreateReprojector( - &layer->projection, &layer->map->projection); - } - if( layer->reprojectorLayerToMap ) - { - msProjectShapeEx(layer->reprojectorLayerToMap, shape); - } - } - - if(clip_to_map) - msClipPolylineRect(shape, layer->map->extent); - - msTransformShapeToPixelRound(shape, layer->map->extent, cellsize); - } else - msOffsetShapeRelativeTo(shape, layer); - - if(shape->numlines > 0) { - struct label_auto_result lar; - memset(&lar,0,sizeof(struct label_auto_result)); - if(UNLIKELY(MS_FAILURE == msPolylineLabelPoint(layer->map, shape, NULL, NULL, &lar, 0))) { - free(lar.angles); - free(lar.label_points); - return MS_FAILURE; - } - if(lar.num_label_points > 0) { - /* convert to geo */ - labelPos.x = lar.label_points[0].x; - labelPos.y = lar.label_points[0].y; - labelposvalid = MS_TRUE; - } - free(lar.angles); - free(lar.label_points); - } - } else if (shape->type == MS_SHAPE_POLYGON) { - labelposvalid = MS_FALSE; - if(layer->transform == MS_TRUE) { - if(layer->project && msProjectionsDiffer(&(layer->projection), &(layer->map->projection))) - { - if( layer->reprojectorLayerToMap == NULL ) - { - layer->reprojectorLayerToMap = msProjectCreateReprojector( - &layer->projection, &layer->map->projection); - } - if( layer->reprojectorLayerToMap ) - { - msProjectShapeEx(layer->reprojectorLayerToMap, shape); - } - } - - if(clip_to_map) - msClipPolygonRect(shape, layer->map->extent); - - msTransformShapeToPixelRound(shape, layer->map->extent, cellsize); - } else - msOffsetShapeRelativeTo(shape, layer); - - if(shape->numlines > 0) { - if(msPolygonLabelPoint(shape, &labelPos, -1) == MS_SUCCESS) { - if(labelPos.x == -1 && labelPos.y == -1) - labelposvalid = MS_FALSE; - else - labelposvalid = MS_TRUE; - } - } - } - - if(labelposvalid == MS_TRUE) { - pointObj p1; - pointObj p2; - int label_offset_x, label_offset_y; - labelObj *label=NULL; - label_bounds lbounds; - lineObj lbounds_line; - pointObj lbounds_point[5]; - double tmp; - - p1.x =labelPos.x; - p1.y =labelPos.y; - - p2.x =labelPos.x; - p2.y =labelPos.y; - if(use_label_settings == MS_TRUE) { - - /* RFC 77: classes (and shapes) can have more than 1 piece of annotation, here we only use the first (index=0) */ - if(shape->classindex >= 0 && layer->class[shape->classindex]->numlabels > 0) { - label = layer->class[shape->classindex]->labels[0]; - if(msGetLabelStatus(layer->map,layer,shape,label) == MS_ON) { - char *annotext = msShapeGetLabelAnnotation(layer,shape,label); - if(annotext) { - textSymbolObj ts; - initTextSymbol(&ts); - msPopulateTextSymbolForLabelAndString(&ts, label, annotext, layer->scalefactor, 1.0, 0); - - label_offset_x = (int)(label->offsetx*layer->scalefactor); - label_offset_y = (int)(label->offsety*layer->scalefactor); - lbounds.poly = &lbounds_line; - lbounds_line.numpoints = 5; - lbounds_line.point = lbounds_point; - - p1 = get_metrics(&labelPos, label->position, ts.textpath, label_offset_x, label_offset_y, label->angle* MS_DEG_TO_RAD, 0, &lbounds); - - /* should we use the point returned from get_metrics?. From few test done, It seems - to return the UL corner of the text. For now use the bounds.minx/miny */ - p1.x = lbounds.bbox.minx; - p1.y = lbounds.bbox.miny; - p2.x = lbounds.bbox.maxx; - p2.y = lbounds.bbox.maxy; - freeTextSymbol(&ts); - } - } - } - } - - /* y's are flipped because it is in image coordinate systems */ - p1.x = MS_IMAGE2MAP_X(p1.x, layer->map->extent.minx, cellsize); - tmp = p1.y; - p1.y = MS_IMAGE2MAP_Y(p2.y, layer->map->extent.maxy, cellsize); - p2.x = MS_IMAGE2MAP_X(p2.x, layer->map->extent.minx, cellsize); - p2.y = MS_IMAGE2MAP_Y(tmp, layer->map->extent.maxy, cellsize); - if(layer->transform == MS_TRUE) { - if(layer->project && msProjectionsDiffer(&(layer->projection), &(layer->map->projection))) { - msProjectPoint(&layer->map->projection, &layer->projection, &p1); - msProjectPoint(&layer->map->projection, &layer->projection, &p2); - } - } - msAddPointToLine(&(tShape.line[0]), &p1); - msAddPointToLine(&(tShape.line[0]), &p2); - } else - tShape.numlines = 0; - - if(projectionString && strcasecmp(projectionString,"image") == 0) { - precision = 0; - - /* if necessary, project the shape to match the map */ - if(msProjectionsDiffer(&(layer->projection), &(layer->map->projection))) - { - if( layer->reprojectorLayerToMap == NULL ) - { - layer->reprojectorLayerToMap = msProjectCreateReprojector( - &layer->projection, &layer->map->projection); - } - if( layer->reprojectorLayerToMap ) - { - msProjectShapeEx(layer->reprojectorLayerToMap, &tShape); - } - } - - msClipPolylineRect(&tShape, layer->map->extent); - - msTransformShapeToPixelRound(&tShape, layer->map->extent, layer->map->cellsize); - } else if(projectionString) { - projectionObj projection; - msInitProjection(&projection); - msProjectionInheritContextFrom(&projection, &layer->map->projection); - - status = msLoadProjectionString(&projection, projectionString); - if(status != MS_SUCCESS) return MS_FAILURE; - - if(msProjectionsDiffer(&(layer->projection), &projection)) - msProjectShape(&layer->projection, &projection, &tShape); - } - - /* find the end of the tag */ - tagEnd = findTagEnd(tagStart); - tagEnd++; - - /* build the complete tag so we can do substitution */ - tagLength = tagEnd - tagStart; - tag = (char *) msSmallMalloc(tagLength + 1); - strlcpy(tag, tagStart, tagLength+1); - - /* do the replacement */ - tagValue = msStrdup(format); - if(precision > 0) - snprintf(numberFormat, sizeof(numberFormat), "%%.%dlf", precision); - else - snprintf(numberFormat, sizeof(numberFormat), "%%f"); - - if(tShape.numlines > 0) { - if(strcasestr(tagValue, "$x") != 0) { - snprintf(number, sizeof(number), numberFormat, tShape.line[0].point[0].x); - tagValue = msReplaceSubstring(tagValue, "$x", number); - } - if(strcasestr(tagValue, "$y") != 0) { - snprintf(number, sizeof(number), numberFormat, tShape.line[0].point[0].y); - tagValue = msReplaceSubstring(tagValue, "$y", number); - } - - if(strcasestr(tagValue, "$minx") != 0) { - snprintf(number, sizeof(number), numberFormat, tShape.line[0].point[0].x); - tagValue = msReplaceSubstring(tagValue, "$minx", number); - } - if(strcasestr(tagValue, "$miny") != 0) { - snprintf(number, sizeof(number), numberFormat, tShape.line[0].point[0].y); - tagValue = msReplaceSubstring(tagValue, "$miny", number); - } - if(strcasestr(tagValue, "$maxx") != 0) { - snprintf(number, sizeof(number), numberFormat, tShape.line[0].point[1].x); - tagValue = msReplaceSubstring(tagValue, "$maxx", number); - } - if(strcasestr(tagValue, "$maxy") != 0) { - snprintf(number, sizeof(number), numberFormat, tShape.line[0].point[1].y); - tagValue = msReplaceSubstring(tagValue, "$maxy", number); - } - } - - /* find the end of the tag */ - tagEnd = findTagEnd(tagStart); - tagEnd++; - - /* build the complete tag so we can do substitution */ - tagLength = tagEnd - tagStart; - tag = (char *) msSmallMalloc(tagLength + 1); - strlcpy(tag, tagStart, tagLength+1); - - *line = msReplaceSubstring(*line, tag, tagValue); - - /* clean up */ - msFreeShape(&tShape); - free(tag); - tag = NULL; - msFreeHashTable(tagArgs); - tagArgs=NULL; - msFree(tagValue); - tagValue=NULL; - - if((*line)[tagOffset] != '\0') - tagStart = findTag(*line+tagOffset+1, "shplabel"); - else - tagStart = NULL; - } - if(shape) - msFreeShape(shape); - - return(MS_SUCCESS); -} - -/* -** Function to process a [date ...] tag -*/ -static int processDateTag(char **line) -{ - struct tm *datetime; - time_t t; - int result; - char *tag=NULL, *tagStart, *tagEnd; - hashTableObj *tagArgs=NULL; - int tagOffset, tagLength; -#define DATE_BUFLEN 1024 - char datestr[DATE_BUFLEN]; - const char *argValue=NULL; - const char *format, *tz; /* tag parameters */ - - if(!*line) { - msSetError(MS_WEBERR, "Invalid line pointer.", "processDateTag()"); - return(MS_FAILURE); - } - - tagStart = findTag(*line, "date"); - - /* It is OK to have no date tags, just return. */ - if( !tagStart ) - return MS_SUCCESS; - - while (tagStart) { - /* set tag params to defaults */ - format = DEFAULT_DATE_FORMAT; - tz = ""; - - tagOffset = tagStart - *line; - - /* check for any tag arguments */ - if(getTagArgs("date", tagStart, &tagArgs) != MS_SUCCESS) return(MS_FAILURE); - - if(tagArgs) { - argValue = msLookupHashTable(tagArgs, "format"); - if(argValue) format = argValue; - argValue = msLookupHashTable(tagArgs, "tz"); - if(argValue) tz = argValue; - } - - t = time(NULL); - if( strncasecmp( tz, "gmt", 4 ) == 0 ) { - datetime = gmtime(&t); - } else { - datetime = localtime(&t); - } - result = strftime(datestr, DATE_BUFLEN, format, datetime); - - /* Only do the replacement if the date was successfully written */ - if( result > 0 ) { - /* find the end of the tag */ - tagEnd = findTagEnd(tagStart); - tagEnd++; - - /* build the complete tag so we can do substitution */ - tagLength = tagEnd - tagStart; - tag = (char *) msSmallMalloc(tagLength + 1); - strlcpy(tag, tagStart, tagLength+1); - - /* do the replacement */ - *line = msReplaceSubstring(*line, tag, datestr); - } - - /* clean up */ - msFree(tag); - tag = NULL; - msFreeHashTable(tagArgs); - tagArgs=NULL; - - if((*line)[tagOffset] != '\0') - tagStart = findTag(*line+tagOffset+1, "date"); - else - tagStart = NULL; - } - - return(MS_SUCCESS); - -} - -/* -** Function to process a [shpxy ...] tag: line contains the tag, shape holds the coordinates. -** -** TODO's: -** - May need to change attribute names. -** - Need generalization routines (not here, but in mapprimative.c). -** - Try to avoid all the realloc calls. -*/ -static int processShpxyTag(layerObj *layer, char **line, shapeObj *shape) -{ - int i,j,p; - int status; - - char *tag, *tagStart, *tagEnd; - hashTableObj *tagArgs=NULL; - int tagOffset, tagLength; - - const char *argValue=NULL; - char *pointFormat1=NULL, *pointFormat2=NULL; - int pointFormatLength; - - /* - ** Pointers to static strings, naming convention is: - ** char 1/2 - x=x, y=y, c=coordinate, p=part, s=shape, ir=inner ring, or=outer ring - ** last char - h=header, f=footer, s=seperator - */ - const char *xh, *xf, *yh, *yf; - const char *cs; - const char *ph, *pf, *ps; - const char *sh, *sf; - const char *irh, *irf; /* inner ring: necessary for complex polygons */ - const char *orh, *orf; /* outer ring */ - - int centroid; - int precision; - - double scale_x, scale_y; - - const char *projectionString=NULL; - - shapeObj tShape; - char *coords=NULL, point[128]; - - if(!*line) { - msSetError(MS_WEBERR, "Invalid line pointer.", "processShpxyTag()"); - return(MS_FAILURE); - } - if( msCheckParentPointer(layer->map,"map")==MS_FAILURE ) - return MS_FAILURE; - - tagStart = findTag(*line, "shpxy"); - - /* It is OK to have no shpxy tags, just return. */ - if( !tagStart ) - return MS_SUCCESS; - - if(!shape || shape->numlines <= 0) { /* I suppose we need to make sure the part has vertices (need shape checker?) */ - msSetError(MS_WEBERR, "Null or empty shape.", "processShpxyTag()"); - return(MS_FAILURE); - } - - while (tagStart) { -#ifdef USE_GEOS - double buffer = 0; - int bufferUnits = -1; -#endif - xh = yh = yf = ph = pf = sh = sf = ""; /* initialize the tag arguments */ - xf= ","; - irh = irf = orh = orf = ""; - ps = cs = " "; - - centroid = MS_FALSE; - precision = 0; - scale_x = scale_y = 1.0; - - projectionString = NULL; - - tagOffset = tagStart - *line; - - /* check for any tag arguments */ - if(getTagArgs("shpxy", tagStart, &tagArgs) != MS_SUCCESS) return(MS_FAILURE); - if(tagArgs) { - argValue = msLookupHashTable(tagArgs, "xh"); - if(argValue) xh = argValue; - argValue = msLookupHashTable(tagArgs, "xf"); - if(argValue) xf = argValue; - - argValue = msLookupHashTable(tagArgs, "yh"); - if(argValue) yh = argValue; - argValue = msLookupHashTable(tagArgs, "yf"); - if(argValue) yf = argValue; - - argValue = msLookupHashTable(tagArgs, "cs"); - if(argValue) cs = argValue; - - argValue = msLookupHashTable(tagArgs, "irh"); - if(argValue) irh = argValue; - argValue = msLookupHashTable(tagArgs, "irf"); - if(argValue) irf = argValue; - - argValue = msLookupHashTable(tagArgs, "orh"); - if(argValue) orh = argValue; - argValue = msLookupHashTable(tagArgs, "orf"); - if(argValue) orf = argValue; - - argValue = msLookupHashTable(tagArgs, "ph"); - if(argValue) ph = argValue; - argValue = msLookupHashTable(tagArgs, "pf"); - if(argValue) pf = argValue; - argValue = msLookupHashTable(tagArgs, "ps"); - if(argValue) ps = argValue; - - argValue = msLookupHashTable(tagArgs, "sh"); - if(argValue) sh = argValue; - argValue = msLookupHashTable(tagArgs, "sf"); - if(argValue) sf = argValue; - -#ifdef USE_GEOS - argValue = msLookupHashTable(tagArgs, "buffer"); - if(argValue) { - buffer = atof(argValue); - if(strstr(argValue, "px")) bufferUnits = MS_PIXELS; /* may support others at some point */ - } -#endif - - argValue = msLookupHashTable(tagArgs, "precision"); - if(argValue) precision = atoi(argValue); - - argValue = msLookupHashTable(tagArgs, "scale"); - if(argValue) { - scale_x = atof(argValue); - scale_y = scale_x; - } - - argValue = msLookupHashTable(tagArgs, "scale_x"); - if(argValue) scale_x = atof(argValue); - - argValue = msLookupHashTable(tagArgs, "scale_y"); - if(argValue) scale_y = atof(argValue); - - argValue = msLookupHashTable(tagArgs, "centroid"); - if(argValue) - if(strcasecmp(argValue,"true") == 0) centroid = MS_TRUE; - - argValue = msLookupHashTable(tagArgs, "proj"); - if(argValue) projectionString = argValue; - } - - /* build the per point format strings (version 1 contains the coordinate seperator, version 2 doesn't) */ - pointFormatLength = strlen(xh) + strlen(xf) + strlen(yh) + strlen(yf) + strlen(cs) + 12 + 1; - pointFormat1 = (char *) msSmallMalloc(pointFormatLength); - snprintf(pointFormat1, pointFormatLength, "%s%%.%dlf%s%s%%.%dlf%s%s", xh, precision, xf, yh, precision, yf, cs); - pointFormat2 = (char *) msSmallMalloc(pointFormatLength); - snprintf(pointFormat2, pointFormatLength, "%s%%.%dlf%s%s%%.%dlf%s", xh, precision, xf, yh, precision, yf); - - /* make a copy of the original shape or compute a centroid if necessary */ - msInitShape(&tShape); - if(centroid == MS_TRUE) { - pointObj p; - - p.x = (shape->bounds.minx + shape->bounds.maxx)/2; - p.y = (shape->bounds.miny + shape->bounds.maxy)/2; - - tShape.type = MS_SHAPE_POINT; - tShape.line = (lineObj *) msSmallMalloc(sizeof(lineObj)); - tShape.numlines = 1; - tShape.line[0].point = NULL; /* initialize the line */ - tShape.line[0].numpoints = 0; - - msAddPointToLine(&(tShape.line[0]), &p); - } - -#ifdef USE_GEOS - else if(buffer != 0 && bufferUnits != MS_PIXELS) { - shapeObj *bufferShape=NULL; - - bufferShape = msGEOSBuffer(shape, buffer); - if(!bufferShape) { - free(pointFormat1); - free(pointFormat2); - return(MS_FAILURE); /* buffer failed */ - } - msCopyShape(bufferShape, &tShape); - msFreeShape(bufferShape); - } -#endif - else { - status = msCopyShape(shape, &tShape); - if(status != 0) { - free(pointFormat1); - free(pointFormat2); - return(MS_FAILURE); /* copy failed */ - } - } - - /* no big deal to convert from file to image coordinates, but what are the image parameters */ - if(projectionString && strcasecmp(projectionString,"image") == 0) { - precision = 0; - - /* if necessary, project the shape to match the map */ - if(msProjectionsDiffer(&(layer->projection), &(layer->map->projection))) - { - if( layer->reprojectorLayerToMap == NULL ) - { - layer->reprojectorLayerToMap = msProjectCreateReprojector( - &layer->projection, &layer->map->projection); - } - if( layer->reprojectorLayerToMap ) - { - msProjectShapeEx(layer->reprojectorLayerToMap, &tShape); - } - } - - switch(tShape.type) { - case(MS_SHAPE_POINT): - /* no clipping necessary */ - break; - case(MS_SHAPE_LINE): - msClipPolylineRect(&tShape, layer->map->extent); - break; - case(MS_SHAPE_POLYGON): - msClipPolygonRect(&tShape, layer->map->extent); - break; - default: - /* TO DO: need an error message here */ - return(MS_FAILURE); - break; - } - msTransformShapeToPixelRound(&tShape, layer->map->extent, layer->map->cellsize); - -#ifdef USE_GEOS - if(buffer != 0 && bufferUnits == MS_PIXELS) { - shapeObj *bufferShape=NULL; - - bufferShape = msGEOSBuffer(&tShape, buffer); - if(!bufferShape) { - if(!msIsDegenerateShape(&tShape)) /* If shape is degenerate this is expected. */ - return(MS_FAILURE); /* buffer failed */ - } else { - msFreeShape(&tShape); /* avoid memory leak */ - msCopyShape(bufferShape, &tShape); - msFreeShape(bufferShape); - } - } -#endif - - } else if(projectionString) { - projectionObj projection; - msInitProjection(&projection); - msProjectionInheritContextFrom(&projection, &(layer->projection)); - - status = msLoadProjectionString(&projection, projectionString); - if(status != MS_SUCCESS) return MS_FAILURE; - - if(msProjectionsDiffer(&(layer->projection), &projection)) - msProjectShape(&layer->projection, &projection, &tShape); - } - - /* TODO: add thinning support here */ - - /* - ** build the coordinate string - */ - - if(strlen(sh) > 0) coords = msStringConcatenate(coords, sh); - - /* do we need to handle inner/outer rings */ - if(tShape.type == MS_SHAPE_POLYGON && strlen(orh) > 0 && strlen(irh) > 0) { - int *outers; - int firstPart; /* to keep track of inserting part separators before each part after the first */ - outers = msGetOuterList( &tShape ); - firstPart = 1; - /* loop over rings looking for outers*/ - for(i=0; i 0)) coords = msStringConcatenate(coords, ps); - firstPart = 0; - if(strlen(ph) > 0) coords = msStringConcatenate(coords, ph); - coords = msStringConcatenate(coords, orh); - for(p=0; p 0) coords = msStringConcatenate(coords, pf); - } - } /* end of loop over outer rings */ - free( outers ); - } else { /* output without ring formatting */ - - for(i=0; i 0) coords = msStringConcatenate(coords, ph); - - for(p=0; p 0) coords = msStringConcatenate(coords, pf); - - if((i < tShape.numlines-1) && (strlen(ps) > 0)) coords = msStringConcatenate(coords, ps); - } - } - if(strlen(sf) > 0) coords = msStringConcatenate(coords, sf); - - msFreeShape(&tShape); - - /* find the end of the tag */ - tagEnd = findTagEnd(tagStart); - tagEnd++; - - /* build the complete tag so we can do substitution */ - tagLength = tagEnd - tagStart; - tag = (char *) msSmallMalloc(tagLength + 1); - strlcpy(tag, tagStart, tagLength+1); - - /* do the replacement */ - *line = msReplaceSubstring(*line, tag, coords); - - /* clean up */ - free(tag); - tag = NULL; - msFreeHashTable(tagArgs); - tagArgs=NULL; - free(pointFormat1); - pointFormat1 = NULL; - free(pointFormat2); - pointFormat2 = NULL; - free(coords); - coords = NULL; - - if((*line)[tagOffset] != '\0') - tagStart = findTag(*line+tagOffset+1, "shpxy"); - else - tagStart = NULL; - } - - return(MS_SUCCESS); -} - -/*! - * this function process all metadata - * in pszInstr. ht mus contain all corresponding - * metadata value. - * - * this function return a modified pszInstr -*/ -int processMetadata(char** pszInstr, hashTableObj *ht) -{ - /* char *pszNextInstr = pszInstr; */ - char *pszEnd, *pszStart; - char *pszMetadataTag; - const char *pszHashName; - const char *pszHashValue; - int nLength, nOffset; - - hashTableObj *metadataArgs = NULL; - - if(!*pszInstr) { - msSetError(MS_WEBERR, "Invalid pointer.", "processMetadata()"); - return MS_FAILURE; - } - - /* set position to the begining of metadata tag */ - pszStart = findTag(*pszInstr, "metadata"); - - while (pszStart) { - /* get metadata args */ - if(getTagArgs("metadata", pszStart, &metadataArgs) != MS_SUCCESS) - return MS_FAILURE; - - pszHashName = msLookupHashTable(metadataArgs, "name"); - pszHashValue = msLookupHashTable(ht, pszHashName); - - nOffset = pszStart - *pszInstr; - - if(pszHashName && pszHashValue) { - /* set position to the end of metadata start tag */ - pszEnd = strchr(pszStart, ']'); - pszEnd++; - - /* build the complete metadata tag ([metadata all_args]) */ - /* to replace it by the corresponding value from ht */ - nLength = pszEnd - pszStart; - pszMetadataTag = (char*)msSmallMalloc(nLength + 1); - strlcpy(pszMetadataTag, pszStart, nLength+1); - - *pszInstr = msReplaceSubstring(*pszInstr, pszMetadataTag, pszHashValue); - - free(pszMetadataTag); - pszMetadataTag=NULL; - } - - msFreeHashTable(metadataArgs); - metadataArgs=NULL; - - - /* set position to the begining of the next metadata tag */ - if((*pszInstr)[nOffset] != '\0') - pszStart = findTag(*pszInstr+nOffset+1, "metadata"); - else - pszStart = NULL; - } - - return MS_SUCCESS; -} - -/*! - * this function process all icon tag - * from pszInstr. - * - * This func return a modified pszInstr. -*/ -int processIcon(mapObj *map, int nIdxLayer, int nIdxClass, char** pszInstr, char* pszPrefix) -{ - int nWidth, nHeight, nLen; - char szImgFname[1024], *pszFullImgFname=NULL, *pszImgTag; - char szPath[MS_MAXPATHLEN]; - hashTableObj *myHashTable=NULL; - FILE *fIcon; - - if(!map || - nIdxLayer > map->numlayers || - nIdxLayer < 0 ) { - msSetError(MS_WEBERR, "Invalid pointer.", "processIcon()"); - return MS_FAILURE; - } - - /* find the begining of tag */ - pszImgTag = strstr(*pszInstr, "[leg_icon"); - - while (pszImgTag) { - int i; - char szStyleCode[512] = ""; - classObj *thisClass=NULL; - - /* It's okay to have no classes... we'll generate an empty icon in this case */ - if(nIdxClass >= 0 && nIdxClass < GET_LAYER(map, nIdxLayer)->numclasses) - thisClass = GET_LAYER(map, nIdxLayer)->class[nIdxClass]; - - if(getTagArgs("leg_icon", pszImgTag, &myHashTable) != MS_SUCCESS) - return MS_FAILURE; - - /* if no specified width or height, set them to map default */ - if(!msLookupHashTable(myHashTable, "width") || !msLookupHashTable(myHashTable, "height")) { - nWidth = map->legend.keysizex; - nHeight= map->legend.keysizey; - } else { - nWidth = atoi(msLookupHashTable(myHashTable, "width")); - nHeight = atoi(msLookupHashTable(myHashTable, "height")); - } - - /* Create a unique and predictable filename to cache the legend icons. - * Include some key parameters from the first 2 styles - */ - for(i=0; i<2 && thisClass && inumstyles; i++) { - styleObj *style; - char *pszSymbolNameHash = NULL; - style = thisClass->styles[i]; - if(style->symbolname) - pszSymbolNameHash = msHashString(style->symbolname); - - snprintf(szStyleCode+strlen(szStyleCode), 255, - "s%d_%x_%x_%x_%d_%s_%g", - i, MS_COLOR_GETRGB(style->color), MS_COLOR_GETRGB(style->backgroundcolor), MS_COLOR_GETRGB(style->outlinecolor), - style->symbol, pszSymbolNameHash?pszSymbolNameHash:"", - style->angle); - msFree(pszSymbolNameHash); - } - - snprintf(szImgFname, sizeof(szImgFname), "%s_%d_%d_%d_%d_%s.%s%c", - pszPrefix, nIdxLayer, nIdxClass, nWidth, nHeight, - szStyleCode, MS_IMAGE_EXTENSION(map->outputformat),'\0'); - - pszFullImgFname = msStrdup(msBuildPath3(szPath, map->mappath, - map->web.imagepath, szImgFname)); - - /* check if icon already exist in cache */ - if((fIcon = fopen(pszFullImgFname, "r")) != NULL) { - /* File already exists. No need to generate it again */ - fclose(fIcon); - } else { - /* Create an image corresponding to the current class */ - imageObj *img=NULL; - - if(thisClass == NULL) { - /* Nonexistent class. Create an empty image */ - img = msCreateLegendIcon(map, NULL, NULL, nWidth, nHeight, MS_TRUE); - } else { - img = msCreateLegendIcon(map, GET_LAYER(map, nIdxLayer), - thisClass, nWidth, nHeight, MS_TRUE); - } - - if(!img) { - if(myHashTable) - msFreeHashTable(myHashTable); - - msSetError(MS_IMGERR, "Error while creating image.", "processIcon()"); - return MS_FAILURE; - } - - /* save it with a unique file name */ - if(msSaveImage(map, img, pszFullImgFname) != MS_SUCCESS) { - if(myHashTable) - msFreeHashTable(myHashTable); - - msFreeImage(img); - - msSetError(MS_IOERR, "Error saving GD image to disk (%s).", "processIcon()", pszFullImgFname); - msFree(pszFullImgFname); - return MS_FAILURE; - } - - msFreeImage(img); - } - - msFree(pszFullImgFname); - pszFullImgFname = NULL; - - nLen = (strchr(pszImgTag, ']') + 1) - pszImgTag; - - if(nLen > 0) { - char *pszTag; - - /* rebuid image tag ([leg_class_img all_args]) */ - /* to replace it by the image url */ - pszTag = (char*)msSmallMalloc(nLen + 1); - strlcpy(pszTag, pszImgTag, nLen+1); - - pszFullImgFname = (char*)msSmallMalloc(strlen(map->web.imageurl) + strlen(szImgFname) + 1); - strcpy(pszFullImgFname, map->web.imageurl); - strcat(pszFullImgFname, szImgFname); - - *pszInstr = msReplaceSubstring(*pszInstr, pszTag, pszFullImgFname); - - msFree(pszFullImgFname); - pszFullImgFname = NULL; - msFree(pszTag); - - /* find the begining of tag */ - pszImgTag = strstr(*pszInstr, "[leg_icon"); - } else { - pszImgTag = NULL; - } - - if(myHashTable) { - msFreeHashTable(myHashTable); - myHashTable = NULL; - } - } - - return MS_SUCCESS; -} - -/*! - * Replace all tags from group template - * with correct value. - * - * this function return a buffer containing - * the template with correct values. - * - * buffer must be freed by caller. -*/ -int generateGroupTemplate(char* pszGroupTemplate, mapObj *map, char* pszGroupName, hashTableObj *oGroupArgs, char **pszTemp, char* pszPrefix) -{ - hashTableObj *myHashTable; - char pszStatus[3]; - char *pszClassImg; - const char *pszOptFlag = NULL; - int i, j; - int nOptFlag = 15; - int bShowGroup; - - *pszTemp = NULL; - - if(!pszGroupName || !pszGroupTemplate) { - msSetError(MS_WEBERR, "Invalid pointer.", "generateGroupTemplate()"); - return MS_FAILURE; - } - - /* - * Get the opt_flag is any. - */ - if(oGroupArgs) - pszOptFlag = msLookupHashTable(oGroupArgs, "opt_flag"); - - if(pszOptFlag) - nOptFlag = atoi(pszOptFlag); - - /* - * Check all layers, if one in the group - * should be visible, print the group. - * (Check for opt_flag) - */ - bShowGroup = 0; - for (j=0; jnumlayers; j++) { - if(GET_LAYER(map, map->layerorder[j])->group && - strcmp(GET_LAYER(map, map->layerorder[j])->group, pszGroupName) == 0) { - /* dont display layer is off. */ - if( (nOptFlag & 2) == 0 && - GET_LAYER(map, map->layerorder[j])->status == MS_OFF ) - bShowGroup = 0; - else - bShowGroup = 1; - - /* dont display layer is query. */ - if( (nOptFlag & 4) == 0 && - GET_LAYER(map, map->layerorder[j])->type == MS_LAYER_QUERY ) - bShowGroup = 0; - - /* dont display layer if out of scale. */ - if((nOptFlag & 1) == 0) { - if(map->scaledenom > 0) { - if((GET_LAYER(map, map->layerorder[j])->maxscaledenom > 0) && - (map->scaledenom > GET_LAYER(map, map->layerorder[j])->maxscaledenom)) - bShowGroup = 0; - if((GET_LAYER(map, map->layerorder[j])->minscaledenom > 0) && - (map->scaledenom <= GET_LAYER(map, map->layerorder[j])->minscaledenom)) - bShowGroup = 0; - } - } - - /* The group contains one visible layer */ - /* Draw the group */ - if( bShowGroup ) - break; - } - } - - if( ! bShowGroup ) - return MS_SUCCESS; - - /* - * Work from a copy - */ - *pszTemp = (char*)msSmallMalloc(strlen(pszGroupTemplate) + 1); - strcpy(*pszTemp, pszGroupTemplate); - - /* - * Change group tags - */ - *pszTemp = msReplaceSubstring(*pszTemp, "[leg_group_name]", pszGroupName); - - - /* - * Create a hash table that contain info - * on current layer - */ - myHashTable = msCreateHashTable(); - - /* - * Check for the first layer - * that belong to this group. - * Get his status and check for if. - */ - for (j=0; jnumlayers; j++) { - if(GET_LAYER(map, map->layerorder[j])->group && strcmp(GET_LAYER(map, map->layerorder[j])->group, pszGroupName) == 0) { - snprintf(pszStatus, sizeof(pszStatus), "%d", GET_LAYER(map, map->layerorder[j])->status); - msInsertHashTable(myHashTable, "layer_status", pszStatus); - msInsertHashTable(myHashTable, "layer_visible", msLayerIsVisible(map, GET_LAYER(map, map->layerorder[j]))?"1":"0" ); - msInsertHashTable(myHashTable, "layer_queryable", msIsLayerQueryable(GET_LAYER(map, map->layerorder[j]))?"1":"0" ); - msInsertHashTable(myHashTable, "group_name", pszGroupName); - - if(processIfTag(pszTemp, myHashTable, MS_FALSE) != MS_SUCCESS) - return MS_FAILURE; - - if(processIfTag(pszTemp, &(GET_LAYER(map, map->layerorder[j])->metadata), MS_FALSE) != MS_SUCCESS) - return MS_FAILURE; - - if(processMetadata(pszTemp, &GET_LAYER(map, map->layerorder[j])->metadata) != MS_SUCCESS) - return MS_FAILURE; - - break; - } - } - - msFreeHashTable(myHashTable); - - /* - * Process all metadata tags - * only web object is accessible - */ - if(processMetadata(pszTemp, &(map->web.metadata)) != MS_SUCCESS) - return MS_FAILURE; - - /* - * check for if tag - */ - if(processIfTag(pszTemp, &(map->web.metadata), MS_TRUE) != MS_SUCCESS) - return MS_FAILURE; - - /* - * Check if leg_icon tag exist - * if so display the first layer first class icon - */ - pszClassImg = strstr(*pszTemp, "[leg_icon"); - if(pszClassImg) { - /* find first layer of this group */ - for (i=0; inumlayers; i++) - if(GET_LAYER(map, map->layerorder[i])->group && strcmp(GET_LAYER(map, map->layerorder[i])->group, pszGroupName) == 0) - processIcon(map, map->layerorder[i], 0, pszTemp, pszPrefix); - } - - return MS_SUCCESS; -} - -/*! - * Replace all tags from layer template - * with correct value. - * - * this function return a buffer containing - * the template with correct values. - * - * buffer must be freed by caller. -*/ -int generateLayerTemplate(char *pszLayerTemplate, mapObj *map, int nIdxLayer, hashTableObj *oLayerArgs, char **pszTemp, char* pszPrefix) -{ - hashTableObj *myHashTable; - char szStatus[10]; - char szType[10]; - - int nOptFlag=0; - const char *pszOptFlag = NULL; - char *pszClassImg; - - char szTmpstr[128]; /* easily big enough for the couple of instances we need */ - - *pszTemp = NULL; - - if(!pszLayerTemplate || - !map || - nIdxLayer > map->numlayers || - nIdxLayer < 0 ) { - msSetError(MS_WEBERR, "Invalid pointer.", "generateLayerTemplate()"); - return MS_FAILURE; - } - - if(oLayerArgs) - pszOptFlag = msLookupHashTable(oLayerArgs, "opt_flag"); - - if(pszOptFlag) - nOptFlag = atoi(pszOptFlag); - - /* don't display deleted layers */ - if(GET_LAYER(map, nIdxLayer)->status == MS_DELETE) - return MS_SUCCESS; - - /* dont display layer is off. */ - /* check this if Opt flag is not set */ - if((nOptFlag & 2) == 0 && GET_LAYER(map, nIdxLayer)->status == MS_OFF) - return MS_SUCCESS; - - /* dont display layer is query. */ - /* check this if Opt flag is not set */ - if((nOptFlag & 4) == 0 && GET_LAYER(map, nIdxLayer)->type == MS_LAYER_QUERY) - return MS_SUCCESS; - - /* dont display layer if out of scale. */ - /* check this if Opt flag is not set */ - if((nOptFlag & 1) == 0) { - if(map->scaledenom > 0) { - if((GET_LAYER(map, nIdxLayer)->maxscaledenom > 0) && (map->scaledenom > GET_LAYER(map, nIdxLayer)->maxscaledenom)) - return MS_SUCCESS; - if((GET_LAYER(map, nIdxLayer)->minscaledenom > 0) && (map->scaledenom <= GET_LAYER(map, nIdxLayer)->minscaledenom)) - return MS_SUCCESS; - } - } - - /* - * Work from a copy - */ - *pszTemp = msStrdup(pszLayerTemplate); - - /* - * Change layer tags - */ - *pszTemp = msReplaceSubstring(*pszTemp, "[leg_layer_name]", GET_LAYER(map, nIdxLayer)->name); - *pszTemp = msReplaceSubstring(*pszTemp, "[leg_layer_group]", GET_LAYER(map, nIdxLayer)->group); - - snprintf(szTmpstr, sizeof(szTmpstr), "%d", nIdxLayer); - *pszTemp = msReplaceSubstring(*pszTemp, "[leg_layer_index]", szTmpstr); - - snprintf(szTmpstr, sizeof(szTmpstr), "%g", GET_LAYER(map, nIdxLayer)->minscaledenom); - *pszTemp = msReplaceSubstring(*pszTemp, "[leg_layer_minscale]", szTmpstr); - *pszTemp = msReplaceSubstring(*pszTemp, "[leg_layer_minscaledenom]", szTmpstr); - snprintf(szTmpstr, sizeof(szTmpstr), "%g", GET_LAYER(map, nIdxLayer)->maxscaledenom); - *pszTemp = msReplaceSubstring(*pszTemp, "[leg_layer_maxscale]", szTmpstr); - *pszTemp = msReplaceSubstring(*pszTemp, "[leg_layer_maxscaledenom]", szTmpstr); - - /* - * Create a hash table that contain info - * on current layer - */ - myHashTable = msCreateHashTable(); - - /* - * for now, only status and type is required by template - */ - snprintf(szStatus, sizeof(szStatus), "%d", GET_LAYER(map, nIdxLayer)->status); - msInsertHashTable(myHashTable, "layer_status", szStatus); - - snprintf(szType, sizeof(szType), "%d", GET_LAYER(map, nIdxLayer)->type); - msInsertHashTable(myHashTable, "layer_type", szType); - - msInsertHashTable(myHashTable, "layer_name", (GET_LAYER(map, nIdxLayer)->name)? GET_LAYER(map, nIdxLayer)->name : ""); - msInsertHashTable(myHashTable, "layer_group", (GET_LAYER(map, nIdxLayer)->group)? GET_LAYER(map, nIdxLayer)->group : ""); - msInsertHashTable(myHashTable, "layer_visible", msLayerIsVisible(map, GET_LAYER(map, nIdxLayer))?"1":"0" ); - msInsertHashTable(myHashTable, "layer_queryable", msIsLayerQueryable(GET_LAYER(map, nIdxLayer))?"1":"0" ); - - if(processIfTag(pszTemp, myHashTable, MS_FALSE) != MS_SUCCESS) - return MS_FAILURE; - - if(processIfTag(pszTemp, &(GET_LAYER(map, nIdxLayer)->metadata), MS_FALSE) != MS_SUCCESS) - return MS_FAILURE; - - if(processIfTag(pszTemp, &(map->web.metadata), MS_TRUE) != MS_SUCCESS) - return MS_FAILURE; - - msFreeHashTable(myHashTable); - - /* - * Check if leg_icon tag exist - * if so display the first class icon - */ - pszClassImg = strstr(*pszTemp, "[leg_icon"); - if(pszClassImg) { - processIcon(map, nIdxLayer, 0, pszTemp, pszPrefix); - } - - /* process all metadata tags - * only current layer and web object - * metaddata are accessible - */ - if(processMetadata(pszTemp, &GET_LAYER(map, nIdxLayer)->metadata) != MS_SUCCESS) - return MS_FAILURE; - - if(processMetadata(pszTemp, &(map->web.metadata)) != MS_SUCCESS) - return MS_FAILURE; - - return MS_SUCCESS; -} - -/*! - * Replace all tags from class template - * with correct value. - * - * this function return a buffer containing - * the template with correct values. - * - * buffer must be freed by caller. -*/ -int generateClassTemplate(char* pszClassTemplate, mapObj *map, int nIdxLayer, int nIdxClass, hashTableObj *oClassArgs, char **pszTemp, char* pszPrefix) -{ - hashTableObj *myHashTable; - char szStatus[10]; - char szType[10]; - - char *pszClassImg; - int nOptFlag=0; - const char *pszOptFlag = NULL; - - char szTmpstr[128]; /* easily big enough for the couple of instances we need */ - - *pszTemp = NULL; - - if(!pszClassTemplate || - !map || - nIdxLayer > map->numlayers || - nIdxLayer < 0 || - nIdxClass > GET_LAYER(map, nIdxLayer)->numclasses || - nIdxClass < 0) { - - msSetError(MS_WEBERR, "Invalid pointer.", "generateClassTemplate()"); - return MS_FAILURE; - } - - if(oClassArgs) - pszOptFlag = msLookupHashTable(oClassArgs, "Opt_flag"); - - if(pszOptFlag) - nOptFlag = atoi(pszOptFlag); - - /* don't display deleted layers */ - if(GET_LAYER(map, nIdxLayer)->status == MS_DELETE) - return MS_SUCCESS; - - /* dont display class if layer is off. */ - /* check this if Opt flag is not set */ - if((nOptFlag & 2) == 0 && GET_LAYER(map, nIdxLayer)->status == MS_OFF) - return MS_SUCCESS; - - /* dont display class if layer is query. */ - /* check this if Opt flag is not set */ - if((nOptFlag & 4) == 0 && GET_LAYER(map, nIdxLayer)->type == MS_LAYER_QUERY) - return MS_SUCCESS; - - /* dont display layer if out of scale. */ - /* check this if Opt flag is not set */ - if((nOptFlag & 1) == 0) { - if(map->scaledenom > 0) { - if((GET_LAYER(map, nIdxLayer)->maxscaledenom > 0) && (map->scaledenom > GET_LAYER(map, nIdxLayer)->maxscaledenom)) - return MS_SUCCESS; - if((GET_LAYER(map, nIdxLayer)->minscaledenom > 0) && (map->scaledenom <= GET_LAYER(map, nIdxLayer)->minscaledenom)) - return MS_SUCCESS; - } - } - - /* - * Work from a copy - */ - *pszTemp = (char*)msSmallMalloc(strlen(pszClassTemplate) + 1); - strcpy(*pszTemp, pszClassTemplate); - - /* - * Change class tags - */ - *pszTemp = msReplaceSubstring(*pszTemp, "[leg_class_name]", GET_LAYER(map, nIdxLayer)->class[nIdxClass]->name); - *pszTemp = msReplaceSubstring(*pszTemp, "[leg_class_title]", GET_LAYER(map, nIdxLayer)->class[nIdxClass]->title); - *pszTemp = msReplaceSubstring(*pszTemp, "[leg_layer_name]", GET_LAYER(map, nIdxLayer)->name); - - snprintf(szTmpstr, sizeof(szTmpstr), "%d", nIdxClass); - *pszTemp = msReplaceSubstring(*pszTemp, "[leg_class_index]", szTmpstr); - - snprintf(szTmpstr, sizeof(szTmpstr), "%g", GET_LAYER(map, nIdxLayer)->class[nIdxClass]->minscaledenom); - *pszTemp = msReplaceSubstring(*pszTemp, "[leg_class_minscale]", szTmpstr); - *pszTemp = msReplaceSubstring(*pszTemp, "[leg_class_minscaledenom]", szTmpstr); - snprintf(szTmpstr, sizeof(szTmpstr), "%g", GET_LAYER(map, nIdxLayer)->class[nIdxClass]->maxscaledenom); - *pszTemp = msReplaceSubstring(*pszTemp, "[leg_class_maxscale]", szTmpstr); - *pszTemp = msReplaceSubstring(*pszTemp, "[leg_class_maxscaledenom]", szTmpstr); - - /* - * Create a hash table that contain info - * on current layer - */ - myHashTable = msCreateHashTable(); - - /* - * for now, only status, type, name and group are required by template - */ - snprintf(szStatus, sizeof(szStatus), "%d", GET_LAYER(map, nIdxLayer)->status); - msInsertHashTable(myHashTable, "layer_status", szStatus); - - snprintf(szType, sizeof(szType), "%d", GET_LAYER(map, nIdxLayer)->type); - msInsertHashTable(myHashTable, "layer_type", szType); - - msInsertHashTable(myHashTable, "layer_name", - (GET_LAYER(map, nIdxLayer)->name)? GET_LAYER(map, nIdxLayer)->name : ""); - msInsertHashTable(myHashTable, "layer_group", - (GET_LAYER(map, nIdxLayer)->group)? GET_LAYER(map, nIdxLayer)->group : ""); - msInsertHashTable(myHashTable, "layer_visible", msLayerIsVisible(map, GET_LAYER(map, nIdxLayer))?"1":"0" ); - msInsertHashTable(myHashTable, "layer_queryable", msIsLayerQueryable(GET_LAYER(map, nIdxLayer))?"1":"0" ); - msInsertHashTable(myHashTable, "class_name", - (GET_LAYER(map, nIdxLayer)->class[nIdxClass]->name)? GET_LAYER(map, nIdxLayer)->class[nIdxClass]->name : ""); - - if(processIfTag(pszTemp, myHashTable, MS_FALSE) != MS_SUCCESS) - return MS_FAILURE; - - if(processIfTag(pszTemp, &(GET_LAYER(map, nIdxLayer)->metadata), MS_FALSE) != MS_SUCCESS) - return MS_FAILURE; - - if(processIfTag(pszTemp, &(map->web.metadata), MS_TRUE) != MS_SUCCESS) - return MS_FAILURE; - - msFreeHashTable(myHashTable); - - /* - * Check if leg_icon tag exist - */ - pszClassImg = strstr(*pszTemp, "[leg_icon"); - if(pszClassImg) { - processIcon(map, nIdxLayer, nIdxClass, pszTemp, pszPrefix); - } - - /* process all metadata tags - * only current layer and web object - * metaddata are accessible - */ - if(processMetadata(pszTemp, &GET_LAYER(map, nIdxLayer)->metadata) != MS_SUCCESS) - return MS_FAILURE; - - if(processMetadata(pszTemp, &(map->web.metadata)) != MS_SUCCESS) - return MS_FAILURE; - - return MS_SUCCESS; -} - -char *generateLegendTemplate(mapservObj *mapserv) -{ - FILE *stream; - char *file = NULL; - int length; - char *pszResult = NULL; - char *legGroupHtml = NULL; - char *legLayerHtml = NULL; - char *legClassHtml = NULL; - char *legLayerHtmlCopy = NULL; - char *legClassHtmlCopy = NULL; - char *legGroupHtmlCopy = NULL; - - char *legHeaderHtml = NULL; - char *legFooterHtml = NULL; - - char *pszPrefix = NULL; - char *pszMapFname = NULL; - - struct stat tmpStat; - - const char *pszOrderMetadata = NULL; - const char *pszOrder = NULL; - - int i,j,k; - char **papszGroups = NULL; - int nGroupNames = 0; - - int nLegendOrder = 0; - const char *pszOrderValue; - - hashTableObj *groupArgs = NULL; - hashTableObj *layerArgs = NULL; - hashTableObj *classArgs = NULL; - - ms_regex_t re; /* compiled regular expression to be matched */ - - int *panCurrentDrawingOrder = NULL; - char szPath[MS_MAXPATHLEN]; - - if(ms_regcomp(&re, MS_TEMPLATE_EXPR, MS_REG_EXTENDED|MS_REG_NOSUB|MS_REG_ICASE) != 0) { - msSetError(MS_IOERR, "Error regcomp.", "generateLegendTemplate()"); - return NULL; - } - - if(ms_regexec(&re, mapserv->map->legend.template, 0, NULL, 0) != 0) { /* no match */ - msSetError(MS_IOERR, "Invalid template file name.", "generateLegendTemplate()"); - ms_regfree(&re); - return NULL; - } - ms_regfree(&re); - - /* -------------------------------------------------------------------- */ - /* Save the current drawing order. The drawing order is reset */ - /* at the end of the function. */ - /* -------------------------------------------------------------------- */ - if(mapserv && mapserv->map && mapserv->map->numlayers > 0) { - panCurrentDrawingOrder = - (int *)msSmallMalloc(sizeof(int)*mapserv->map->numlayers); - - for (i=0; imap->numlayers; i++) { - if(mapserv->map->layerorder) - panCurrentDrawingOrder[i] = mapserv->map->layerorder[i]; - else - panCurrentDrawingOrder[i] = i; - } - } - - /* - * build prefix filename - * for legend icon creation - */ - for(i=0; irequest->NumParams; i++) /* find the mapfile parameter first */ - if(strcasecmp(mapserv->request->ParamNames[i], "map") == 0) break; - - if(i == mapserv->request->NumParams) { - if( getenv("MS_MAPFILE")) - pszMapFname = msStringConcatenate(pszMapFname, getenv("MS_MAPFILE")); - } else { - if(getenv(mapserv->request->ParamValues[i])) /* an environment references the actual file to use */ - pszMapFname = msStringConcatenate(pszMapFname, getenv(mapserv->request->ParamValues[i])); - else - pszMapFname = msStringConcatenate(pszMapFname, mapserv->request->ParamValues[i]); - } - - if(pszMapFname) { - if(stat(pszMapFname, &tmpStat) != -1) { - int nLen; - - nLen = (mapserv->map->name?strlen(mapserv->map->name):0) + 50; - pszPrefix = (char*)msSmallMalloc((nLen+1) * sizeof(char)); - snprintf(pszPrefix, nLen, "%s_%ld_%ld", - mapserv->map->name, - (long) tmpStat.st_size, - (long) tmpStat.st_mtime); - pszPrefix[nLen] = '\0'; - } - - free(pszMapFname); - pszMapFname = NULL; - } else { - /* -------------------------------------------------------------------- */ - /* map file name may not be avaible when the template functions */ - /* are called from mapscript. Use the time stamp as prefix. */ - /* -------------------------------------------------------------------- */ - char pszTime[20]; - - snprintf(pszTime, sizeof(pszTime), "%ld", (long)time(NULL)); - pszPrefix = msStringConcatenate(pszPrefix, pszTime); - } - - /* open template */ - if((stream = fopen(msBuildPath(szPath, mapserv->map->mappath, mapserv->map->legend.template), "r")) == NULL) { - msSetError(MS_IOERR, "Error while opening template file.", "generateLegendTemplate()"); - if(pszResult) - free(pszResult); - pszResult=NULL; - goto error; - } - - fseek(stream, 0, SEEK_END); - length = ftell(stream); - rewind(stream); - - file = (char*)msSmallMalloc(length + 1); - - /* - * Read all the template file - */ - IGUR_sizet(fread(file, length, 1, stream)); - /* E. Rouault: the below issue is due to opening in "r" mode, which is a - * synonymous of "rt" on Windows. In that mode \r\n are turned into \n, - * consequently less bytes are written in the output buffer than requested. - * A potential fix might be to open in "rb" mode, but is the code ready - * to deal with Windows \r\n end of lines ? */ - /* Disabled for now due to Windows issue, see ticket #3814 - if( 1 != fread(file, length, 1, stream)) { - msSetError(MS_IOERR, "Error while reading template file.", "generateLegendTemplate()"); - free(file); - fclose(stream); - return NULL; - } - */ - file[length] = '\0'; - - if(msValidateContexts(mapserv->map) != MS_SUCCESS) { /* make sure there are no recursive REQUIRES or LABELREQUIRES expressions */ - if(pszResult) - free(pszResult); - pszResult=NULL; - goto error; - } - - /* - * Seperate header/footer, groups, layers and class - */ - getInlineTag("leg_header_html", file, &legHeaderHtml); - getInlineTag("leg_footer_html", file, &legFooterHtml); - getInlineTag("leg_group_html", file, &legGroupHtml); - getInlineTag("leg_layer_html", file, &legLayerHtml); - getInlineTag("leg_class_html", file, &legClassHtml); - - /* - * Retrieve arguments of all three parts - */ - if(legGroupHtml) - if(getTagArgs("leg_group_html", file, &groupArgs) != MS_SUCCESS) { - if(pszResult) - free(pszResult); - pszResult=NULL; - goto error; - } - - if(legLayerHtml) - if(getTagArgs("leg_layer_html", file, &layerArgs) != MS_SUCCESS) { - if(pszResult) - free(pszResult); - pszResult=NULL; - goto error; - } - - if(legClassHtml) - if(getTagArgs("leg_class_html", file, &classArgs) != MS_SUCCESS) { - if(pszResult) - free(pszResult); - pszResult=NULL; - goto error; - } - - - mapserv->map->cellsize = msAdjustExtent(&(mapserv->map->extent), - mapserv->map->width, - mapserv->map->height); - if(msCalculateScale(mapserv->map->extent, mapserv->map->units, - mapserv->map->width, mapserv->map->height, - mapserv->map->resolution, &mapserv->map->scaledenom) != MS_SUCCESS) { - if(pszResult) - free(pszResult); - pszResult=NULL; - goto error; - } - - /* start with the header if present */ - if(legHeaderHtml) pszResult = msStringConcatenate(pszResult, legHeaderHtml); - - /********************************************************************/ - - /* - * order layers if order_metadata args is set - * If not, keep default order - */ - pszOrderMetadata = msLookupHashTable(layerArgs, "order_metadata"); - - if(sortLayerByMetadata(mapserv->map, pszOrderMetadata) != MS_SUCCESS) { - if(pszResult) - free(pszResult); - pszResult=NULL; - goto error; - } - - /* -------------------------------------------------------------------- */ - /* if the order tag is set to ascending or descending, the */ - /* current order will be changed to correspond to that. */ - /* -------------------------------------------------------------------- */ - pszOrder = msLookupHashTable(layerArgs, "order"); - if(pszOrder && ((strcasecmp(pszOrder, "ASCENDING") == 0) || - (strcasecmp(pszOrder, "DESCENDING") == 0))) { - if(sortLayerByOrder(mapserv->map, pszOrder) != MS_SUCCESS) { - if(pszResult) - free(pszResult); - pszResult=NULL; - goto error; - } - } - - if(legGroupHtml) { - /* retrieve group names */ - papszGroups = msGetAllGroupNames(mapserv->map, &nGroupNames); - - for (i=0; imap, papszGroups[i], groupArgs, &legGroupHtmlCopy, pszPrefix) != MS_SUCCESS) { - if(pszResult) - free(pszResult); - pszResult=NULL; - goto error; - } - - /* concatenate it to final result */ - pszResult = msStringConcatenate(pszResult, legGroupHtmlCopy); - - /* - if(!pszResult) - { - if(pszResult) - free(pszResult); - pszResult=NULL; - goto error; - } - */ - - if(legGroupHtmlCopy) { - free(legGroupHtmlCopy); - legGroupHtmlCopy = NULL; - } - - /* for all layers in group */ - if(legLayerHtml) { - for (j=0; jmap->numlayers; j++) { - /* - * if order_metadata is set and the order - * value is less than 0, dont display it - */ - pszOrderMetadata = msLookupHashTable(layerArgs, "order_metadata"); - if(pszOrderMetadata) { - pszOrderValue = msLookupHashTable(&(GET_LAYER(mapserv->map, mapserv->map->layerorder[j])->metadata), pszOrderMetadata); - if(pszOrderValue) { - nLegendOrder = atoi(pszOrderValue); - if(nLegendOrder < 0) - continue; - } - } - if(mapserv->hittest && mapserv->hittest->layerhits[mapserv->map->layerorder[j]].status == 0) { - continue; - } - - if(GET_LAYER(mapserv->map, mapserv->map->layerorder[j])->group && strcmp(GET_LAYER(mapserv->map, mapserv->map->layerorder[j])->group, papszGroups[i]) == 0) { - /* process all layer tags */ - if(generateLayerTemplate(legLayerHtml, mapserv->map, mapserv->map->layerorder[j], layerArgs, &legLayerHtmlCopy, pszPrefix) != MS_SUCCESS) { - if(pszResult) - free(pszResult); - pszResult=NULL; - goto error; - } - - - /* concatenate to final result */ - pszResult = msStringConcatenate(pszResult, legLayerHtmlCopy); - - if(legLayerHtmlCopy) { - free(legLayerHtmlCopy); - legLayerHtmlCopy = NULL; - } - - - /* for all classes in layer */ - if(legClassHtml) { - for (k=0; kmap, mapserv->map->layerorder[j])->numclasses; k++) { - /* process all class tags */ - if(!GET_LAYER(mapserv->map, mapserv->map->layerorder[j])->class[k]->name) - continue; - if(mapserv->hittest && mapserv->hittest->layerhits[mapserv->map->layerorder[j]].classhits[k].status == 0) { - continue; - } - - if(generateClassTemplate(legClassHtml, mapserv->map, mapserv->map->layerorder[j], k, classArgs, &legClassHtmlCopy, pszPrefix) != MS_SUCCESS) { - if(pszResult) - free(pszResult); - pszResult=NULL; - goto error; - } - - - /* concatenate to final result */ - pszResult = msStringConcatenate(pszResult, legClassHtmlCopy); - - if(legClassHtmlCopy) { - free(legClassHtmlCopy); - legClassHtmlCopy = NULL; - } - } - } - } - } - } else if(legClassHtml) { /* no layer template specified but class and group template */ - for (j=0; jmap->numlayers; j++) { - /* - * if order_metadata is set and the order - * value is less than 0, dont display it - */ - pszOrderMetadata = msLookupHashTable(layerArgs, "order_metadata"); - if(pszOrderMetadata) { - pszOrderValue = msLookupHashTable(&(GET_LAYER(mapserv->map, mapserv->map->layerorder[j])->metadata), pszOrderMetadata); - if(pszOrderValue) { - nLegendOrder = atoi(pszOrderValue); - if(nLegendOrder < 0) - continue; - } - } - if(mapserv->hittest && mapserv->hittest->layerhits[mapserv->map->layerorder[j]].status == 0) { - continue; - } - - if(GET_LAYER(mapserv->map, mapserv->map->layerorder[j])->group && strcmp(GET_LAYER(mapserv->map, mapserv->map->layerorder[j])->group, papszGroups[i]) == 0) { - /* for all classes in layer */ - if(legClassHtml) { - for (k=0; kmap, mapserv->map->layerorder[j])->numclasses; k++) { - /* process all class tags */ - if(!GET_LAYER(mapserv->map, mapserv->map->layerorder[j])->class[k]->name) - continue; - if(mapserv->hittest && mapserv->hittest->layerhits[mapserv->map->layerorder[j]].classhits[k].status == 0) { - continue; - } - - if(generateClassTemplate(legClassHtml, mapserv->map, mapserv->map->layerorder[j], k, classArgs, &legClassHtmlCopy, pszPrefix) != MS_SUCCESS) { - if(pszResult) - free(pszResult); - pszResult=NULL; - goto error; - } - - - /* concatenate to final result */ - pszResult = msStringConcatenate(pszResult, legClassHtmlCopy); - - if(legClassHtmlCopy) { - free(legClassHtmlCopy); - legClassHtmlCopy = NULL; - } - } - } - } - } - } - } - } else { - /* if no group template specified */ - if(legLayerHtml) { - for (j=0; jmap->numlayers; j++) { - /* - * if order_metadata is set and the order - * value is less than 0, dont display it - */ - pszOrderMetadata = msLookupHashTable(layerArgs, "order_metadata"); - if(pszOrderMetadata) { - pszOrderValue = msLookupHashTable(&(GET_LAYER(mapserv->map, mapserv->map->layerorder[j])->metadata), pszOrderMetadata); - if(pszOrderValue) { - nLegendOrder = atoi(pszOrderValue); - if(nLegendOrder < 0) - continue; - } else - nLegendOrder=0; - } - if(mapserv->hittest && mapserv->hittest->layerhits[mapserv->map->layerorder[j]].status == 0) { - continue; - } - - /* process a layer tags */ - if(generateLayerTemplate(legLayerHtml, mapserv->map, mapserv->map->layerorder[j], layerArgs, &legLayerHtmlCopy, pszPrefix) != MS_SUCCESS) { - if(pszResult) - free(pszResult); - pszResult=NULL; - goto error; - } - - /* concatenate to final result */ - pszResult = msStringConcatenate(pszResult, legLayerHtmlCopy); - - if(legLayerHtmlCopy) { - free(legLayerHtmlCopy); - legLayerHtmlCopy = NULL; - } - - /* for all classes in layer */ - if(legClassHtml) { - for (k=0; kmap, mapserv->map->layerorder[j])->numclasses; k++) { - /* process all class tags */ - if(!GET_LAYER(mapserv->map, mapserv->map->layerorder[j])->class[k]->name) - continue; - if(mapserv->hittest && mapserv->hittest->layerhits[mapserv->map->layerorder[j]].classhits[k].status == 0) { - continue; - } - - if(generateClassTemplate(legClassHtml, mapserv->map, mapserv->map->layerorder[j], k, classArgs, &legClassHtmlCopy, pszPrefix) != MS_SUCCESS) { - if(pszResult) - free(pszResult); - pszResult=NULL; - goto error; - } - - - /* concatenate to final result */ - pszResult = msStringConcatenate(pszResult, legClassHtmlCopy); - - if(legClassHtmlCopy) { - free(legClassHtmlCopy); - legClassHtmlCopy = NULL; - } - } - } - } - } else { /* if no group and layer template specified */ - if(legClassHtml) { - for (j=0; jmap->numlayers; j++) { - /* - * if order_metadata is set and the order - * value is less than 0, dont display it - */ - pszOrderMetadata = msLookupHashTable(layerArgs, "order_metadata"); - if(pszOrderMetadata) { - pszOrderValue = msLookupHashTable(&(GET_LAYER(mapserv->map, mapserv->map->layerorder[j])->metadata), pszOrderMetadata); - if(pszOrderValue) { - nLegendOrder = atoi(pszOrderValue); - if(nLegendOrder < 0) - continue; - } - } - if(mapserv->hittest && mapserv->hittest->layerhits[mapserv->map->layerorder[j]].status == 0) { - continue; - } - - for (k=0; kmap, mapserv->map->layerorder[j])->numclasses; k++) { - if(!GET_LAYER(mapserv->map, mapserv->map->layerorder[j])->class[k]->name) - continue; - if(mapserv->hittest && mapserv->hittest->layerhits[mapserv->map->layerorder[j]].classhits[k].status == 0) { - continue; - } - - if(generateClassTemplate(legClassHtml, mapserv->map, mapserv->map->layerorder[j], k, classArgs, &legClassHtmlCopy, pszPrefix) != MS_SUCCESS) { - if(pszResult) - free(pszResult); - pszResult=NULL; - goto error; - } - - - pszResult = msStringConcatenate(pszResult, legClassHtmlCopy); - - if(legClassHtmlCopy) { - free(legClassHtmlCopy); - legClassHtmlCopy = NULL; - } - } - } - } - } - } - - /* finish with the footer if present */ - if(legFooterHtml) pszResult = msStringConcatenate(pszResult, legFooterHtml); - - /* - * if we reach this point, that mean no error was generated. - * So check if template is null and initialize it to . - */ - if(pszResult == NULL) { - pszResult = msStringConcatenate(pszResult, " "); - } - - - /********************************************************************/ - -error: - - if(papszGroups) { - for (i=0; imap->layerorder) { - for (i=0; imap->numlayers; i++) - mapserv->map->layerorder[i] = panCurrentDrawingOrder[i]; - - free(panCurrentDrawingOrder); - } - - return pszResult; -} - -char *processOneToManyJoin(mapservObj* mapserv, joinObj *join) -{ - int records=MS_FALSE; - FILE *stream=NULL; - char *outbuf; - char line[MS_BUFFER_LENGTH], *tmpline; - char szPath[MS_MAXPATHLEN]; - - if((outbuf = msStrdup("")) == NULL) return(NULL); /* empty at first */ - - msJoinPrepare(join, &(mapserv->resultshape)); /* execute the join */ - while(msJoinNext(join) == MS_SUCCESS) { - /* First time through, deal with the header (if necessary) and open the main template. We only */ - /* want to do this if there are joined records. */ - if(records == MS_FALSE) { - if(join->header != NULL) { - if(stream) fclose(stream); - if((stream = fopen(msBuildPath(szPath, mapserv->map->mappath, join->header), "r")) == NULL) { - msSetError(MS_IOERR, "Error while opening join header file %s.", "processOneToManyJoin()", join->header); - msFree(outbuf); - return(NULL); - } - - if(isValidTemplate(stream, join->header) != MS_TRUE) { - fclose(stream); - msFree(outbuf); - return NULL; - } - - /* echo file to the output buffer, no substitutions */ - while(fgets(line, MS_BUFFER_LENGTH, stream) != NULL) outbuf = msStringConcatenate(outbuf, line); - - fclose(stream); - stream = NULL; - } - - if((stream = fopen(msBuildPath(szPath, mapserv->map->mappath, join->template), "r")) == NULL) { - msSetError(MS_IOERR, "Error while opening join template file %s.", "processOneToManyJoin()", join->template); - msFree(outbuf); - return(NULL); - } - - if(isValidTemplate(stream, join->template) != MS_TRUE) { - fclose(stream); - msFree(outbuf); - return NULL; - } - - records = MS_TRUE; - } - - while(fgets(line, MS_BUFFER_LENGTH, stream) != NULL) { /* now on to the end of the template */ - if(strchr(line, '[') != NULL) { - tmpline = processLine(mapserv, line, NULL, QUERY); /* no multiline tags are allowed in a join */ - if(!tmpline) { - msFree(outbuf); - fclose(stream); - return NULL; - } - outbuf = msStringConcatenate(outbuf, tmpline); - free(tmpline); - } else /* no subs, just echo */ - outbuf = msStringConcatenate(outbuf, line); - } - - rewind(stream); - IGUR_voidp(fgets(line, MS_BUFFER_LENGTH, stream)); /* skip the first line since it's the magic string */ - } /* next record */ - - if(records==MS_TRUE && join->footer) { - if(stream) fclose(stream); - if((stream = fopen(msBuildPath(szPath, mapserv->map->mappath, join->footer), "r")) == NULL) { - msSetError(MS_IOERR, "Error while opening join footer file %s.", "processOneToManyJoin()", join->footer); - msFree(outbuf); - return(NULL); - } - - if(isValidTemplate(stream, join->footer) != MS_TRUE) { - msFree(outbuf); - fclose(stream); - return NULL; - } - - /* echo file to the output buffer, no substitutions */ - while(fgets(line, MS_BUFFER_LENGTH, stream) != NULL) outbuf = msStringConcatenate(outbuf, line); - - fclose(stream); - } - - /* clear any data associated with the join */ - msFreeCharArray(join->values, join->numitems); - join->values = NULL; - - return(outbuf); -} - -/* -** Process a single line in the template. A few tags (e.g. [resultset]...[/resultset]) can be multi-line so -** we pass the filehandle to look ahead if necessary. -*/ -static char *processLine(mapservObj *mapserv, char *instr, FILE *stream, int mode) -{ - int i, j; -#define PROCESSLINE_BUFLEN 5120 - char repstr[PROCESSLINE_BUFLEN], substr[PROCESSLINE_BUFLEN], *outstr; /* repstr = replace string, substr = sub string */ - struct hashObj *tp=NULL; - char *encodedstr; - - rectObj llextent; - pointObj llpoint; - - outstr = msStrdup(instr); /* work from a copy */ - - if(strstr(outstr, "[version]")) outstr = msReplaceSubstring(outstr, "[version]", msGetVersion()); - - snprintf(repstr, PROCESSLINE_BUFLEN, "%s%s%s.%s", mapserv->map->web.imageurl, mapserv->map->name, mapserv->Id, MS_IMAGE_EXTENSION(mapserv->map->outputformat)); - outstr = msReplaceSubstring(outstr, "[img]", repstr); - snprintf(repstr, PROCESSLINE_BUFLEN, "%s%sref%s.%s", mapserv->map->web.imageurl, mapserv->map->name, mapserv->Id, MS_IMAGE_EXTENSION(mapserv->map->outputformat)); - outstr = msReplaceSubstring(outstr, "[ref]", repstr); - - if(strstr(outstr, "[errmsg")) { - char *errmsg = msGetErrorString(";"); - if(!errmsg) errmsg = msStrdup("Error message buffer is empty."); /* should never happen, but just in case... */ - outstr = msReplaceSubstring(outstr, "[errmsg]", errmsg); - encodedstr = msEncodeUrl(errmsg); - outstr = msReplaceSubstring(outstr, "[errmsg_esc]", encodedstr); - free(errmsg); - free(encodedstr); - } - - if(strstr(outstr, "[legend]")) { - /* if there's a template legend specified, use it */ - if(mapserv->map->legend.template) { - char *legendTemplate; - - legendTemplate = generateLegendTemplate(mapserv); - if(legendTemplate) { - outstr = msReplaceSubstring(outstr, "[legend]", legendTemplate); - - free(legendTemplate); - } else /* error already generated by (generateLegendTemplate()) */ - return NULL; - } else { /* if not display gif image with all legend icon */ - snprintf(repstr, PROCESSLINE_BUFLEN, "%s%sleg%s.%s", mapserv->map->web.imageurl, mapserv->map->name, mapserv->Id, MS_IMAGE_EXTENSION(mapserv->map->outputformat)); - outstr = msReplaceSubstring(outstr, "[legend]", repstr); - } - } - - snprintf(repstr, PROCESSLINE_BUFLEN, "%s%ssb%s.%s", mapserv->map->web.imageurl, mapserv->map->name, mapserv->Id, MS_IMAGE_EXTENSION(mapserv->map->outputformat)); - outstr = msReplaceSubstring(outstr, "[scalebar]", repstr); - - if(mapserv->savequery) { - snprintf(repstr, PROCESSLINE_BUFLEN, "%s%s%s%s", mapserv->map->web.imagepath, mapserv->map->name, mapserv->Id, MS_QUERY_EXTENSION); - outstr = msReplaceSubstring(outstr, "[queryfile]", repstr); - } - - if(mapserv->savemap) { - snprintf(repstr, PROCESSLINE_BUFLEN, "%s%s%s.map", mapserv->map->web.imagepath, mapserv->map->name, mapserv->Id); - outstr = msReplaceSubstring(outstr, "[map]", repstr); - } - - if(strstr(outstr,"[mapserv_onlineresource]")) { - char *ol; -#if defined(USE_WMS_SVR) || defined (USE_WFS_SVR) || defined (USE_WCS_SVR) || defined(USE_SOS_SVR) || defined(USE_WMS_LYR) || defined(USE_WFS_LYR) - ol = msOWSGetOnlineResource(mapserv->map, "O", "onlineresource", mapserv->request); -#else - ol = msBuildOnlineResource(mapserv->map, mapserv->request); -#endif - outstr = msReplaceSubstring(outstr, "[mapserv_onlineresource]",ol); - msFree(ol); - } - - if(getenv("HTTP_HOST")) { - snprintf(repstr, PROCESSLINE_BUFLEN, "%s", getenv("HTTP_HOST")); - outstr = msReplaceSubstring(outstr, "[host]", repstr); - } - if(getenv("SERVER_PORT")) { - snprintf(repstr, PROCESSLINE_BUFLEN, "%s", getenv("SERVER_PORT")); - outstr = msReplaceSubstring(outstr, "[port]", repstr); - } - - snprintf(repstr, PROCESSLINE_BUFLEN, "%s", mapserv->Id); - outstr = msReplaceSubstring(outstr, "[id]", repstr); - - repstr[0] = '\0'; /* Layer list for a "POST" request */ - for(i=0; iNumLayers; i++) { - strlcat(repstr, mapserv->Layers[i], sizeof(repstr)); - strlcat(repstr, " ", sizeof(repstr)); - } - msStringTrimBlanks(repstr); - encodedstr = msEncodeHTMLEntities(repstr); - outstr = msReplaceSubstring(outstr, "[layers]", encodedstr); - free(encodedstr); - - encodedstr = msEncodeUrl(repstr); - outstr = msReplaceSubstring(outstr, "[layers_esc]", encodedstr); - free(encodedstr); - - strcpy(repstr, ""); /* list of ALL layers that can be toggled */ - repstr[0] = '\0'; - for(i=0; imap->numlayers; i++) { - if(GET_LAYER(mapserv->map, i)->status != MS_DEFAULT && GET_LAYER(mapserv->map, i)->name != NULL) { - strlcat(repstr, GET_LAYER(mapserv->map, i)->name, sizeof(repstr)); - strlcat(repstr, " ", sizeof(repstr)); - } - } - msStringTrimBlanks(repstr); - outstr = msReplaceSubstring(outstr, "[toggle_layers]", repstr); - - encodedstr = msEncodeUrl(repstr); - outstr = msReplaceSubstring(outstr, "[toggle_layers_esc]", encodedstr); - free(encodedstr); - - for(i=0; imap->numlayers; i++) { /* Set form widgets (i.e. checkboxes, radio and select lists), note that default layers don't show up here */ - if(isOn(mapserv, GET_LAYER(mapserv->map, i)->name, GET_LAYER(mapserv->map, i)->group) == MS_TRUE) { - if(GET_LAYER(mapserv->map, i)->group) { - snprintf(substr, PROCESSLINE_BUFLEN, "[%s_select]", GET_LAYER(mapserv->map, i)->group); - outstr = msReplaceSubstring(outstr, substr, "selected=\"selected\""); - snprintf(substr, PROCESSLINE_BUFLEN, "[%s_check]", GET_LAYER(mapserv->map, i)->group); - outstr = msReplaceSubstring(outstr, substr, "checked=\"checked\""); - } - if(GET_LAYER(mapserv->map, i)->name) { - snprintf(substr, PROCESSLINE_BUFLEN, "[%s_select]", GET_LAYER(mapserv->map, i)->name); - outstr = msReplaceSubstring(outstr, substr, "selected=\"selected\""); - snprintf(substr, PROCESSLINE_BUFLEN, "[%s_check]", GET_LAYER(mapserv->map, i)->name); - outstr = msReplaceSubstring(outstr, substr, "checked=\"checked\""); - } - } else { - if(GET_LAYER(mapserv->map, i)->group) { - snprintf(substr, PROCESSLINE_BUFLEN, "[%s_select]", GET_LAYER(mapserv->map, i)->group); - outstr = msReplaceSubstring(outstr, substr, ""); - snprintf(substr, PROCESSLINE_BUFLEN, "[%s_check]", GET_LAYER(mapserv->map, i)->group); - outstr = msReplaceSubstring(outstr, substr, ""); - } - if(GET_LAYER(mapserv->map, i)->name) { - snprintf(substr, PROCESSLINE_BUFLEN, "[%s_select]", GET_LAYER(mapserv->map, i)->name); - outstr = msReplaceSubstring(outstr, substr, ""); - snprintf(substr, PROCESSLINE_BUFLEN, "[%s_check]", GET_LAYER(mapserv->map, i)->name); - outstr = msReplaceSubstring(outstr, substr, ""); - } - } - } - - for(i=-1; i<=1; i++) { /* make zoom direction persistant */ - if(mapserv->ZoomDirection == i) { - snprintf(substr, sizeof(substr), "[zoomdir_%d_select]", i); - outstr = msReplaceSubstring(outstr, substr, "selected=\"selected\""); - snprintf(substr, sizeof(substr), "[zoomdir_%d_check]", i); - outstr = msReplaceSubstring(outstr, substr, "checked=\"checked\""); - } else { - snprintf(substr, sizeof(substr), "[zoomdir_%d_select]", i); - outstr = msReplaceSubstring(outstr, substr, ""); - snprintf(substr, sizeof(substr), "[zoomdir_%d_check]", i); - outstr = msReplaceSubstring(outstr, substr, ""); - } - } - - for(i=MINZOOM; i<=MAXZOOM; i++) { /* make zoom persistant */ - if(mapserv->Zoom == i) { - snprintf(substr, sizeof(substr), "[zoom_%d_select]", i); - outstr = msReplaceSubstring(outstr, substr, "selected=\"selected\""); - snprintf(substr, sizeof(substr), "[zoom_%d_check]", i); - outstr = msReplaceSubstring(outstr, substr, "checked=\"checked\""); - } else { - snprintf(substr, sizeof(substr), "[zoom_%d_select]", i); - outstr = msReplaceSubstring(outstr, substr, ""); - snprintf(substr, sizeof(substr), "[zoom_%d_check]", i); - outstr = msReplaceSubstring(outstr, substr, ""); - } - } - - /* allow web object metadata access in template */ - - /* - * reworked by SG to use HashTable methods - */ - - if(&(mapserv->map->web.metadata) && strstr(outstr, "web_")) { - for (j=0; jmap->web.metadata.items[j] != NULL) { - for(tp=mapserv->map->web.metadata.items[j]; tp!=NULL; tp=tp->next) { - snprintf(substr, PROCESSLINE_BUFLEN, "[web_%s]", tp->key); - outstr = msReplaceSubstring(outstr, substr, tp->data); - snprintf(substr, PROCESSLINE_BUFLEN, "[web_%s_esc]", tp->key); - - encodedstr = msEncodeUrl(tp->data); - outstr = msReplaceSubstring(outstr, substr, encodedstr); - free(encodedstr); - } - } - } - } - - /* allow layer metadata access in template */ - for(i=0; imap->numlayers; i++) { - if(&(GET_LAYER(mapserv->map, i)->metadata) && GET_LAYER(mapserv->map, i)->name && strstr(outstr, GET_LAYER(mapserv->map, i)->name)) { - for(j=0; jmap, i)->metadata.items[j] != NULL) { - for(tp=GET_LAYER(mapserv->map, i)->metadata.items[j]; tp!=NULL; tp=tp->next) { - snprintf(substr, PROCESSLINE_BUFLEN, "[%s_%s]", GET_LAYER(mapserv->map, i)->name, tp->key); - if(GET_LAYER(mapserv->map, i)->status == MS_ON) - outstr = msReplaceSubstring(outstr, substr, tp->data); - else - outstr = msReplaceSubstring(outstr, substr, ""); - snprintf(substr, PROCESSLINE_BUFLEN, "[%s_%s_esc]", GET_LAYER(mapserv->map, i)->name, tp->key); - if(GET_LAYER(mapserv->map, i)->status == MS_ON) { - encodedstr = msEncodeUrl(tp->data); - outstr = msReplaceSubstring(outstr, substr, encodedstr); - free(encodedstr); - } else - outstr = msReplaceSubstring(outstr, substr, ""); - } - } - } - } - } - - snprintf(repstr, sizeof(repstr), "%f", mapserv->mappnt.x); - outstr = msReplaceSubstring(outstr, "[mapx]", repstr); - snprintf(repstr, sizeof(repstr), "%f", mapserv->mappnt.y); - outstr = msReplaceSubstring(outstr, "[mapy]", repstr); - - snprintf(repstr, sizeof(repstr), "%f", mapserv->map->extent.minx); /* Individual mapextent elements for spatial query building, deprecated. */ - outstr = msReplaceSubstring(outstr, "[minx]", repstr); - snprintf(repstr, sizeof(repstr), "%f", mapserv->map->extent.maxx); - outstr = msReplaceSubstring(outstr, "[maxx]", repstr); - snprintf(repstr, sizeof(repstr), "%f", mapserv->map->extent.miny); - outstr = msReplaceSubstring(outstr, "[miny]", repstr); - snprintf(repstr, sizeof(repstr), "%f", mapserv->map->extent.maxy); - outstr = msReplaceSubstring(outstr, "[maxy]", repstr); - - if(processDateTag( &outstr ) != MS_SUCCESS) - return(NULL); - - if(processExtentTag(mapserv, &outstr, "mapext", &(mapserv->map->extent), &(mapserv->map->projection)) != MS_SUCCESS) - return(NULL); - if(processExtentTag(mapserv, &outstr, "mapext_esc", &(mapserv->map->extent), &(mapserv->map->projection)) != MS_SUCCESS) /* depricated */ - return(NULL); - - snprintf(repstr, sizeof(repstr), "%f", (mapserv->map->extent.maxx-mapserv->map->extent.minx)); /* useful for creating cachable extents (i.e. 0 0 dx dy) with legends and scalebars */ - outstr = msReplaceSubstring(outstr, "[dx]", repstr); - snprintf(repstr, sizeof(repstr), "%f", (mapserv->map->extent.maxy-mapserv->map->extent.miny)); - outstr = msReplaceSubstring(outstr, "[dy]", repstr); - - snprintf(repstr, sizeof(repstr), "%f", mapserv->RawExt.minx); /* Individual raw extent elements for spatial query building, deprecated. */ - outstr = msReplaceSubstring(outstr, "[rawminx]", repstr); - snprintf(repstr, sizeof(repstr), "%f", mapserv->RawExt.maxx); - outstr = msReplaceSubstring(outstr, "[rawmaxx]", repstr); - snprintf(repstr, sizeof(repstr), "%f", mapserv->RawExt.miny); - outstr = msReplaceSubstring(outstr, "[rawminy]", repstr); - snprintf(repstr, sizeof(repstr), "%f", mapserv->RawExt.maxy); - outstr = msReplaceSubstring(outstr, "[rawmaxy]", repstr); - - if(processExtentTag(mapserv, &outstr, "rawext", &(mapserv->RawExt), &(mapserv->map->projection)) != MS_SUCCESS) - return(NULL); - if(processExtentTag(mapserv, &outstr, "rawext_esc", &(mapserv->RawExt), &(mapserv->map->projection)) != MS_SUCCESS) /* depricated */ - return(NULL); - - if((strstr(outstr, "lat]") || strstr(outstr, "lon]") || strstr(outstr, "lon_esc]")) - && mapserv->map->projection.proj != NULL - && !msProjIsGeographicCRS(&(mapserv->map->projection)) ) { - llextent=mapserv->map->extent; - llpoint=mapserv->mappnt; - msProjectRect(&(mapserv->map->projection), &(mapserv->map->latlon), &llextent); - msProjectPoint(&(mapserv->map->projection), &(mapserv->map->latlon), &llpoint); - - snprintf(repstr, sizeof(repstr), "%f", llpoint.x); - outstr = msReplaceSubstring(outstr, "[maplon]", repstr); - snprintf(repstr, sizeof(repstr), "%f", llpoint.y); - outstr = msReplaceSubstring(outstr, "[maplat]", repstr); - - snprintf(repstr, sizeof(repstr), "%f", llextent.minx); /* map extent as lat/lon */ - outstr = msReplaceSubstring(outstr, "[minlon]", repstr); - snprintf(repstr, sizeof(repstr), "%f", llextent.maxx); - outstr = msReplaceSubstring(outstr, "[maxlon]", repstr); - snprintf(repstr, sizeof(repstr), "%f", llextent.miny); - outstr = msReplaceSubstring(outstr, "[minlat]", repstr); - snprintf(repstr, sizeof(repstr), "%f", llextent.maxy); - outstr = msReplaceSubstring(outstr, "[maxlat]", repstr); - - if(processExtentTag(mapserv, &outstr, "mapext_latlon", &(llextent), NULL) != MS_SUCCESS) - return(NULL); - if(processExtentTag(mapserv, &outstr, "mapext_latlon_esc", &(llextent), NULL) != MS_SUCCESS) /* depricated */ - return(NULL); - } - - /* submitted by J.F (bug 1102) */ - if(mapserv->map->reference.status == MS_ON) { - snprintf(repstr, sizeof(repstr), "%f", mapserv->map->reference.extent.minx); /* Individual reference map extent elements for spatial query building, depricated. */ - outstr = msReplaceSubstring(outstr, "[refminx]", repstr); - snprintf(repstr, sizeof(repstr), "%f", mapserv->map->reference.extent.maxx); - outstr = msReplaceSubstring(outstr, "[refmaxx]", repstr); - snprintf(repstr, sizeof(repstr), "%f", mapserv->map->reference.extent.miny); - outstr = msReplaceSubstring(outstr, "[refminy]", repstr); - snprintf(repstr, sizeof(repstr), "%f", mapserv->map->reference.extent.maxy); - outstr = msReplaceSubstring(outstr, "[refmaxy]", repstr); - - if(processExtentTag(mapserv, &outstr, "refext", &(mapserv->map->reference.extent), &(mapserv->map->projection)) != MS_SUCCESS) - return(NULL); - if(processExtentTag(mapserv, &outstr, "refext_esc", &(mapserv->map->reference.extent), &(mapserv->map->projection)) != MS_SUCCESS) /* depricated */ - return(NULL); - } - - snprintf(repstr, sizeof(repstr), "%d %d", mapserv->map->width, mapserv->map->height); - outstr = msReplaceSubstring(outstr, "[mapsize]", repstr); - - encodedstr = msEncodeUrl(repstr); - outstr = msReplaceSubstring(outstr, "[mapsize_esc]", encodedstr); - free(encodedstr); - - snprintf(repstr, sizeof(repstr), "%d", mapserv->map->width); - outstr = msReplaceSubstring(outstr, "[mapwidth]", repstr); - snprintf(repstr, sizeof(repstr), "%d", mapserv->map->height); - outstr = msReplaceSubstring(outstr, "[mapheight]", repstr); - - snprintf(repstr, sizeof(repstr), "%f", mapserv->map->scaledenom); - outstr = msReplaceSubstring(outstr, "[scale]", repstr); - outstr = msReplaceSubstring(outstr, "[scaledenom]", repstr); - snprintf(repstr, sizeof(repstr), "%f", mapserv->map->cellsize); - outstr = msReplaceSubstring(outstr, "[cellsize]", repstr); - - snprintf(repstr, sizeof(repstr), "%.1f %.1f", (mapserv->map->width)/2.0, (mapserv->map->height)/2.0); /* not subtracting 1 from image dimensions (see bug 633) */ - outstr = msReplaceSubstring(outstr, "[center]", repstr); - snprintf(repstr, sizeof(repstr), "%.1f", (mapserv->map->width)/2.0); - outstr = msReplaceSubstring(outstr, "[center_x]", repstr); - snprintf(repstr, sizeof(repstr), "%.1f", (mapserv->map->height)/2.0); - outstr = msReplaceSubstring(outstr, "[center_y]", repstr); - - /* These are really for situations with multiple result sets only, but often used in header/footer */ - snprintf(repstr, sizeof(repstr), "%d", mapserv->NR); /* total number of results */ - outstr = msReplaceSubstring(outstr, "[nr]", repstr); - snprintf(repstr, sizeof(repstr), "%d", mapserv->NL); /* total number of layers with results */ - outstr = msReplaceSubstring(outstr, "[nl]", repstr); - - if(mapserv->resultlayer) { - if(strstr(outstr, "[items]") != NULL) { - char *itemstr=NULL; - - itemstr = msJoinStrings(mapserv->resultlayer->items, mapserv->resultlayer->numitems, ","); - outstr = msReplaceSubstring(outstr, "[items]", itemstr); - free(itemstr); - } - - snprintf(repstr, sizeof(repstr), "%d", mapserv->NLR); /* total number of results within this layer */ - outstr = msReplaceSubstring(outstr, "[nlr]", repstr); - snprintf(repstr, sizeof(repstr), "%d", mapserv->RN); /* sequential (eg. 1..n) result number within all layers */ - outstr = msReplaceSubstring(outstr, "[rn]", repstr); - snprintf(repstr, sizeof(repstr), "%d", mapserv->LRN); /* sequential (eg. 1..n) result number within this layer */ - outstr = msReplaceSubstring(outstr, "[lrn]", repstr); - outstr = msReplaceSubstring(outstr, "[cl]", mapserv->resultlayer->name); /* current layer name */ - /* if(resultlayer->description) outstr = msReplaceSubstring(outstr, "[cd]", resultlayer->description); */ /* current layer description */ - - /* allow layer metadata access when there is a current result layer (implicitly a query template) */ - if(&(mapserv->resultlayer->metadata) && strstr(outstr, "[metadata_")) { - for(i=0; iresultlayer->metadata.items[i] != NULL) { - for(tp=mapserv->resultlayer->metadata.items[i]; tp!=NULL; tp=tp->next) { - snprintf(substr, PROCESSLINE_BUFLEN, "[metadata_%s]", tp->key); - outstr = msReplaceSubstring(outstr, substr, tp->data); - - snprintf(substr, PROCESSLINE_BUFLEN, "[metadata_%s_esc]", tp->key); - encodedstr = msEncodeUrl(tp->data); - outstr = msReplaceSubstring(outstr, substr, encodedstr); - free(encodedstr); - } - } - } - } - } - - if(mode != QUERY) { - if(processResultSetTag(mapserv, &outstr, stream) != MS_SUCCESS) { - msFree(outstr); - return(NULL); - } - } else { /* return shape and/or values */ - - snprintf(repstr, sizeof(repstr), "%f %f", (mapserv->resultshape.bounds.maxx + mapserv->resultshape.bounds.minx)/2, (mapserv->resultshape.bounds.maxy + mapserv->resultshape.bounds.miny)/2); - outstr = msReplaceSubstring(outstr, "[shpmid]", repstr); - snprintf(repstr, sizeof(repstr), "%f", (mapserv->resultshape.bounds.maxx + mapserv->resultshape.bounds.minx)/2); - outstr = msReplaceSubstring(outstr, "[shpmidx]", repstr); - snprintf(repstr, sizeof(repstr), "%f", (mapserv->resultshape.bounds.maxy + mapserv->resultshape.bounds.miny)/2); - outstr = msReplaceSubstring(outstr, "[shpmidy]", repstr); - - if(processExtentTag(mapserv, &outstr, "shpext", &(mapserv->resultshape.bounds), &(mapserv->resultlayer->projection)) != MS_SUCCESS) - return(NULL); - if(processExtentTag(mapserv, &outstr, "shpext_esc", &(mapserv->resultshape.bounds), &(mapserv->resultlayer->projection)) != MS_SUCCESS) /* depricated */ - return(NULL); - - snprintf(repstr, sizeof(repstr), "%d", mapserv->resultshape.classindex); - outstr = msReplaceSubstring(outstr, "[shpclass]", repstr); - - if(processShpxyTag(mapserv->resultlayer, &outstr, &mapserv->resultshape) != MS_SUCCESS) - return(NULL); - - if(processShplabelTag(mapserv->resultlayer, &outstr, &mapserv->resultshape) != MS_SUCCESS) - return(NULL); - - snprintf(repstr, sizeof(repstr), "%f", mapserv->resultshape.bounds.minx); - outstr = msReplaceSubstring(outstr, "[shpminx]", repstr); - snprintf(repstr, sizeof(repstr), "%f", mapserv->resultshape.bounds.miny); - outstr = msReplaceSubstring(outstr, "[shpminy]", repstr); - snprintf(repstr, sizeof(repstr), "%f", mapserv->resultshape.bounds.maxx); - outstr = msReplaceSubstring(outstr, "[shpmaxx]", repstr); - snprintf(repstr, sizeof(repstr), "%f", mapserv->resultshape.bounds.maxy); - outstr = msReplaceSubstring(outstr, "[shpmaxy]", repstr); - - snprintf(repstr, sizeof(repstr), "%ld", mapserv->resultshape.index); - outstr = msReplaceSubstring(outstr, "[shpidx]", repstr); - snprintf(repstr, sizeof(repstr), "%d", mapserv->resultshape.tileindex); - outstr = msReplaceSubstring(outstr, "[tileidx]", repstr); - - /* return ALL attributes in one delimeted list */ - if(strstr(outstr, "[values]") != NULL) { - char *valuestr=NULL; - - valuestr = msJoinStrings(mapserv->resultshape.values, mapserv->resultlayer->numitems, ","); - outstr = msReplaceSubstring(outstr, "[values]", valuestr); - free(valuestr); - } - - for(i=0; iresultlayer->numitems; i++) { - /* by default let's encode attributes for HTML presentation */ - snprintf(substr, PROCESSLINE_BUFLEN, "[%s]", mapserv->resultlayer->items[i]); - if(strstr(outstr, substr) != NULL) { - encodedstr = msEncodeHTMLEntities(mapserv->resultshape.values[i]); - outstr = msReplaceSubstring(outstr, substr, encodedstr); - free(encodedstr); - } - - /* of course you might want to embed that data in URLs */ - snprintf(substr, PROCESSLINE_BUFLEN, "[%s_esc]", mapserv->resultlayer->items[i]); - if(strstr(outstr, substr) != NULL) { - encodedstr = msEncodeUrl(mapserv->resultshape.values[i]); - outstr = msReplaceSubstring(outstr, substr, encodedstr); - free(encodedstr); - } - - /* or you might want to access the attributes unaltered */ - snprintf(substr, PROCESSLINE_BUFLEN, "[%s_raw]", mapserv->resultlayer->items[i]); - if(strstr(outstr, substr) != NULL) - outstr = msReplaceSubstring(outstr, substr, mapserv->resultshape.values[i]); - } - - if(processItemTag(mapserv->resultlayer, &outstr, &mapserv->resultshape) != MS_SUCCESS) - return(NULL); - - /* handle joins in this next section */ - for(i=0; iresultlayer->numjoins; i++) { - if(mapserv->resultlayer->joins[i].values) { /* join has data */ - for(j=0; jresultlayer->joins[i].numitems; j++) { - /* by default let's encode attributes for HTML presentation */ - snprintf(substr, PROCESSLINE_BUFLEN, "[%s_%s]", mapserv->resultlayer->joins[i].name, mapserv->resultlayer->joins[i].items[j]); - if(strstr(outstr, substr) != NULL) { - encodedstr = msEncodeHTMLEntities(mapserv->resultlayer->joins[i].values[j]); - outstr = msReplaceSubstring(outstr, substr, encodedstr); - free(encodedstr); - } - - /* of course you might want to embed that data in URLs */ - snprintf(substr, PROCESSLINE_BUFLEN, "[%s_%s_esc]", mapserv->resultlayer->joins[i].name, mapserv->resultlayer->joins[i].items[j]); - if(strstr(outstr, substr) != NULL) { - encodedstr = msEncodeUrl(mapserv->resultlayer->joins[i].values[j]); - outstr = msReplaceSubstring(outstr, substr, encodedstr); - free(encodedstr); - } - - /* or you might want to access the attributes unaltered */ - snprintf(substr, PROCESSLINE_BUFLEN, "[%s_%s_raw]", mapserv->resultlayer->joins[i].name, mapserv->resultlayer->joins[i].items[j]); - if(strstr(outstr, substr) != NULL) - outstr = msReplaceSubstring(outstr, substr, mapserv->resultlayer->joins[i].values[j]); - } - } else if(mapserv->resultlayer->joins[i].type == MS_JOIN_ONE_TO_MANY) { /* one-to-many join */ - char *joinTemplate=NULL; - - snprintf(substr, PROCESSLINE_BUFLEN, "[join_%s]", mapserv->resultlayer->joins[i].name); - if(strstr(outstr, substr) != NULL) { - joinTemplate = processOneToManyJoin(mapserv, &(mapserv->resultlayer->joins[i])); - if(joinTemplate) { - outstr = msReplaceSubstring(outstr, substr, joinTemplate); - free(joinTemplate); - } else - return NULL; - } - } - } /* next join */ - - } /* end query mode specific substitutions */ - - if(processIncludeTag(mapserv, &outstr, stream, mode) != MS_SUCCESS) - return(NULL); - - for(i=0; irequest->NumParams; i++) { - /* Replace [variable] tags using values from URL. We cannot offer a - * [variable_raw] option here due to the risk of XSS. - * - * Replacement is case-insensitive. (#4511) - */ - snprintf(substr, PROCESSLINE_BUFLEN, "[%s]", mapserv->request->ParamNames[i]); - encodedstr = msEncodeHTMLEntities(mapserv->request->ParamValues[i]); - outstr = msCaseReplaceSubstring(outstr, substr, encodedstr); - free(encodedstr); - - snprintf(substr, PROCESSLINE_BUFLEN, "[%s_esc]", mapserv->request->ParamNames[i]); - encodedstr = msEncodeUrl(mapserv->request->ParamValues[i]); - outstr = msCaseReplaceSubstring(outstr, substr, encodedstr); - free(encodedstr); - } - - return(outstr); -} - -#define MS_TEMPLATE_BUFFER 1024 /* 1k */ - -int msReturnPage(mapservObj *mapserv, char *html, int mode, char **papszBuffer) -{ - FILE *stream; - char line[MS_BUFFER_LENGTH], *tmpline; - int nBufferSize = 0; - int nCurrentSize = 0; - int nExpandBuffer = 0; - - ms_regex_t re; /* compiled regular expression to be matched */ - char szPath[MS_MAXPATHLEN]; - - if(!html) { - msSetError(MS_WEBERR, "No template specified", "msReturnPage()"); - return MS_FAILURE; - } - - if(ms_regcomp(&re, MS_TEMPLATE_EXPR, MS_REG_EXTENDED|MS_REG_NOSUB|MS_REG_ICASE) != 0) { - msSetError(MS_REGEXERR, NULL, "msReturnPage()"); - return MS_FAILURE; - } - - if(ms_regexec(&re, html, 0, NULL, 0) != 0) { /* no match */ - ms_regfree(&re); - msSetError(MS_WEBERR, "Malformed template name (%s).", "msReturnPage()", html); - return MS_FAILURE; - } - ms_regfree(&re); - - if((stream = fopen(msBuildPath(szPath, mapserv->map->mappath, html), "r")) == NULL) { - msSetError(MS_IOERR, "%s", "msReturnPage()", html); - return MS_FAILURE; - } - - if(isValidTemplate(stream, html) != MS_TRUE) { - fclose(stream); - return MS_FAILURE; - } - - if(papszBuffer) { - if((*papszBuffer) == NULL) { - (*papszBuffer) = (char *)msSmallMalloc(MS_TEMPLATE_BUFFER); - (*papszBuffer)[0] = '\0'; - nBufferSize = MS_TEMPLATE_BUFFER; - nCurrentSize = 0; - nExpandBuffer = 1; - } else { - nCurrentSize = strlen((*papszBuffer)); - nBufferSize = nCurrentSize; - nExpandBuffer = (nCurrentSize/MS_TEMPLATE_BUFFER) + 1; - } - } - - while(fgets(line, MS_BUFFER_LENGTH, stream) != NULL) { /* now on to the end of the file */ - - if(strchr(line, '[') != NULL) { - tmpline = processLine(mapserv, line, stream, mode); - if(!tmpline) - return MS_FAILURE; - - if(papszBuffer) { - if(nBufferSize <= (int)(nCurrentSize + strlen(tmpline) + 1)) { - nExpandBuffer = (strlen(tmpline) / MS_TEMPLATE_BUFFER) + 1; - nBufferSize = MS_TEMPLATE_BUFFER*nExpandBuffer + strlen((*papszBuffer)); - (*papszBuffer) = (char *) msSmallRealloc((*papszBuffer),sizeof(char)*nBufferSize); - } - strcat((*papszBuffer), tmpline); - nCurrentSize += strlen(tmpline); - } else - msIO_fwrite(tmpline, strlen(tmpline), 1, stdout); - - free(tmpline); - } else { - if(papszBuffer) { - if(nBufferSize <= (int)(nCurrentSize + strlen(line))) { - nExpandBuffer = (strlen(line) / MS_TEMPLATE_BUFFER) + 1; - nBufferSize = MS_TEMPLATE_BUFFER*nExpandBuffer + strlen((*papszBuffer)); - (*papszBuffer) = (char *)msSmallRealloc((*papszBuffer),sizeof(char)*nBufferSize); - } - strcat((*papszBuffer), line); - nCurrentSize += strlen(line); - } else - msIO_fwrite(line, strlen(line), 1, stdout); - } - if(!papszBuffer) - fflush(stdout); - } /* next line */ - - fclose(stream); - - return MS_SUCCESS; -} - -int msReturnURL(mapservObj* ms, char* url, int mode) -{ - char *tmpurl; - - if(url == NULL) { - msSetError(MS_WEBERR, "Empty URL.", "msReturnURL()"); - return MS_FAILURE; - } - - tmpurl = processLine(ms, url, NULL, mode); /* URL templates can't handle multi-line tags, hence the NULL file pointer */ - - if(!tmpurl) - return MS_FAILURE; - - msRedirect(tmpurl); - free(tmpurl); - - return MS_SUCCESS; -} - -/* -** Legacy query template parsing where you use headers, footers and such... -*/ -int msReturnNestedTemplateQuery(mapservObj* mapserv, char* pszMimeType, char **papszBuffer) -{ - int status; - int i,j,k; - char buffer[1024]; - int nBufferSize =0; - int nCurrentSize = 0; - int nExpandBuffer = 0; - - char *template; - - layerObj *lp=NULL; - - if(papszBuffer) { - (*papszBuffer) = (char *)msSmallMalloc(MS_TEMPLATE_BUFFER); - (*papszBuffer)[0] = '\0'; - nBufferSize = MS_TEMPLATE_BUFFER; - nCurrentSize = 0; - nExpandBuffer = 1; - } - - msInitShape(&(mapserv->resultshape)); - - if((mapserv->Mode == ITEMQUERY) || (mapserv->Mode == QUERY)) { /* may need to handle a URL result set since these modes return exactly 1 result */ - - for(i=(mapserv->map->numlayers-1); i>=0; i--) { - lp = (GET_LAYER(mapserv->map, i)); - - if(!lp->resultcache) continue; - if(lp->resultcache->numresults > 0) break; - } - - if(i >= 0) { /* at least if no result found, mapserver will display an empty template. */ - - if(lp->resultcache->results[0].classindex >= 0 && lp->class[(int)(lp->resultcache->results[0].classindex)]->template) - template = lp->class[(int)(lp->resultcache->results[0].classindex)]->template; - else - template = lp->template; - - if( template == NULL ) { - msSetError(MS_WEBERR, "No template for layer %s or it's classes.", "msReturnNestedTemplateQuery()", lp->name ); - return MS_FAILURE; - } - - if(TEMPLATE_TYPE(template) == MS_URL) { - mapserv->resultlayer = lp; - -#if 0 - status = msLayerOpen(lp); - if(status != MS_SUCCESS) return status; - - status = msLayerGetItems(lp); /* retrieve all the item names */ - if(status != MS_SUCCESS) return status; -#endif - - status = msLayerGetShape(lp, &(mapserv->resultshape), &(lp->resultcache->results[0])); - if(status != MS_SUCCESS) return status; - - if(lp->numjoins > 0) { - for(k=0; knumjoins; k++) { - status = msJoinConnect(lp, &(lp->joins[k])); - if(status != MS_SUCCESS) return status; - - msJoinPrepare(&(lp->joins[k]), &(mapserv->resultshape)); - msJoinNext(&(lp->joins[k])); /* fetch the first row */ - } - } - - if(papszBuffer == NULL) { - if(msReturnURL(mapserv, template, QUERY) != MS_SUCCESS) return MS_FAILURE; - } - - msFreeShape(&(mapserv->resultshape)); - /* msLayerClose(lp); */ - mapserv->resultlayer = NULL; - - return MS_SUCCESS; - } - } - } - - /* - ** Now we know we're making a template sandwich - */ - mapserv->NR = mapserv->NL = 0; - for(i=0; imap->numlayers; i++) { /* compute some totals */ - lp = (GET_LAYER(mapserv->map, i)); - - if(!lp->resultcache) continue; - - if(lp->resultcache->numresults > 0) { - mapserv->NL++; - mapserv->NR += lp->resultcache->numresults; - } - } - - /* - ** Is this step really necessary for buffered output? Legend and browse templates don't deal with mime-types - ** so why should this. Note that new-style templates don't buffer the mime-type either. - */ - if(papszBuffer && mapserv->sendheaders) { - snprintf(buffer, sizeof(buffer), "Content-Type: %s%c%c", pszMimeType, 10, 10); - if(nBufferSize <= (int)(nCurrentSize + strlen(buffer) + 1)) { - nExpandBuffer++; - (*papszBuffer) = (char *)msSmallRealloc((*papszBuffer), MS_TEMPLATE_BUFFER*nExpandBuffer); - nBufferSize = MS_TEMPLATE_BUFFER*nExpandBuffer; - } - strcat((*papszBuffer), buffer); - nCurrentSize += strlen(buffer); - } else if(mapserv->sendheaders) { - msIO_setHeader("Content-Type","%s",pszMimeType); - msIO_sendHeaders(); - } - - if(mapserv->map->web.header) { - if(msReturnPage(mapserv, mapserv->map->web.header, BROWSE, papszBuffer) != MS_SUCCESS) return MS_FAILURE; - } - - mapserv->RN = 1; /* overall result number */ - for(i=0; imap->numlayers; i++) { - mapserv->resultlayer = lp = (GET_LAYER(mapserv->map, mapserv->map->layerorder[i])); - - if(!lp->resultcache) continue; - if(lp->resultcache->numresults <= 0) continue; - - mapserv->NLR = lp->resultcache->numresults; - -#if 0 - status = msLayerOpen(lp); /* open this layer */ - if(status != MS_SUCCESS) return status; - - status = msLayerGetItems(lp); /* retrieve all the item names */ - if(status != MS_SUCCESS) return status; -#endif - - if(lp->numjoins > 0) { /* open any necessary JOINs here */ - for(k=0; knumjoins; k++) { - status = msJoinConnect(lp, &(lp->joins[k])); - if(status != MS_SUCCESS) return status; - } - } - - if(lp->header) { - if(msReturnPage(mapserv, lp->header, BROWSE, papszBuffer) != MS_SUCCESS) return MS_FAILURE; - } - - mapserv->LRN = 1; /* layer result number */ - for(j=0; jresultcache->numresults; j++) { - status = msLayerGetShape(lp, &(mapserv->resultshape), &(lp->resultcache->results[j])); - if(status != MS_SUCCESS) return status; - - /* prepare any necessary JOINs here (one-to-one only) */ - if(lp->numjoins > 0) { - for(k=0; knumjoins; k++) { - if(lp->joins[k].type == MS_JOIN_ONE_TO_ONE) { - msJoinPrepare(&(lp->joins[k]), &(mapserv->resultshape)); - msJoinNext(&(lp->joins[k])); /* fetch the first row */ - } - } - } - - if(lp->resultcache->results[j].classindex >= 0 && lp->class[(int)(lp->resultcache->results[j].classindex)]->template) - template = lp->class[(int)(lp->resultcache->results[j].classindex)]->template; - else - template = lp->template; - - if(msReturnPage(mapserv, template, QUERY, papszBuffer) != MS_SUCCESS) { - msFreeShape(&(mapserv->resultshape)); - return MS_FAILURE; - } - - msFreeShape(&(mapserv->resultshape)); /* init too */ - - mapserv->RN++; /* increment counters */ - mapserv->LRN++; - } - - if(lp->footer) { - if(msReturnPage(mapserv, lp->footer, BROWSE, papszBuffer) != MS_SUCCESS) return MS_FAILURE; - } - - /* msLayerClose(lp); */ - mapserv->resultlayer = NULL; - } - - if(mapserv->map->web.footer) - return msReturnPage(mapserv, mapserv->map->web.footer, BROWSE, papszBuffer); - - return MS_SUCCESS; -} - -int msReturnOpenLayersPage(mapservObj *mapserv) -{ - int i; - char *buffer = NULL, *layer = NULL; - const char *tmpUrl = NULL; - char *openlayersUrl = olUrl; - char *projection = NULL; - char *format = NULL; - - /* 2 CGI parameters are used in the template. we need to transform them - * to be sure the case match during the template processing. We also - * need to search the SRS/CRS parameter to get the projection info. OGC - * services version >= 1.3.0 uses CRS rather than SRS */ - for( i=0; irequest->NumParams; i++) { - if( (strcasecmp(mapserv->request->ParamNames[i], "SRS") == 0) || - (strcasecmp(mapserv->request->ParamNames[i], "CRS") == 0) ) { - projection = mapserv->request->ParamValues[i]; - } else if(strcasecmp(mapserv->request->ParamNames[i], "LAYERS") == 0) { - free(mapserv->request->ParamNames[i]); - mapserv->request->ParamNames[i] = msStrdup("LAYERS"); - } else if(strcasecmp(mapserv->request->ParamNames[i], "VERSION") == 0) { - free(mapserv->request->ParamNames[i]); - mapserv->request->ParamNames[i] = msStrdup("VERSION"); - } - } - if(mapserv->map->outputformat->mimetype && *mapserv->map->outputformat->mimetype) { - format = mapserv->map->outputformat->mimetype; - } - - /* check if the environment variable or config MS_OPENLAYERS_JS_URL is set */ - tmpUrl = msGetConfigOption(mapserv->map, "MS_OPENLAYERS_JS_URL"); - if (tmpUrl) - openlayersUrl = (char*)tmpUrl; - else if (getenv("MS_OPENLAYERS_JS_URL")) - openlayersUrl = getenv("MS_OPENLAYERS_JS_URL"); - - if (mapserv->Mode == BROWSE) { - msSetError(MS_WMSERR, "At least one layer name required in LAYERS.", - "msWMSLoadGetMapParams()"); - layer = processLine(mapserv, olLayerMapServerTag, NULL, BROWSE); - } else - layer = processLine(mapserv, olLayerWMSTag, NULL, BROWSE); - - buffer = processLine(mapserv, olTemplate, NULL, BROWSE); - buffer = msReplaceSubstring(buffer, "[openlayers_js_url]", openlayersUrl); - buffer = msReplaceSubstring(buffer, "[openlayers_layer]", layer); - if (projection) - buffer = msReplaceSubstring(buffer, "[openlayers_projection]", projection); - if (format) - buffer = msReplaceSubstring(buffer, "[openlayers_format]", format); - else - buffer = msReplaceSubstring(buffer, "[openlayers_format]", "image/jpeg"); - msIO_fwrite(buffer, strlen(buffer), 1, stdout); - free(layer); - free(buffer); - - return MS_SUCCESS; -} - -mapservObj *msAllocMapServObj() -{ - mapservObj *mapserv = msSmallMalloc(sizeof(mapservObj)); - - mapserv->savemap=MS_FALSE; - mapserv->savequery=MS_FALSE; /* should the query and/or map be saved */ - - mapserv->sendheaders = MS_TRUE; - - mapserv->request = msAllocCgiObj(); - - mapserv->map=NULL; - - mapserv->NumLayers=0; /* number of layers specfied by a user */ - mapserv->MaxLayers=0; /* allocated size of Layers[] array */ - mapserv->Layers = NULL; - - mapserv->icon = NULL; - - mapserv->RawExt.minx=-1; - mapserv->RawExt.miny=-1; - mapserv->RawExt.maxx=-1; - mapserv->RawExt.maxy=-1; - - mapserv->fZoom=1; - mapserv->Zoom=1; /* default for browsing */ - - mapserv->resultlayer=NULL; - - mapserv->UseShapes=MS_FALSE; - - mapserv->mappnt.x=-1; - mapserv->mappnt.y=-1; - - mapserv->ZoomDirection=0; /* whether zooming in or out, default is pan or 0 */ - - mapserv->Mode=BROWSE; /* can be BROWSE, QUERY, etc. */ - - sprintf(mapserv->Id, "%ld%d", (long)time(NULL), (int)getpid()); - - mapserv->CoordSource=NONE; - mapserv->ScaleDenom=0; - - mapserv->ImgRows=-1; - mapserv->ImgCols=-1; - - mapserv->ImgExt.minx=-1; - mapserv->ImgExt.miny=-1; - mapserv->ImgExt.maxx=-1; - mapserv->ImgExt.maxy=-1; - - mapserv->ImgBox.minx=-1; - mapserv->ImgBox.miny=-1; - mapserv->ImgBox.maxx=-1; - mapserv->ImgBox.maxy=-1; - - mapserv->RefPnt.x=-1; - mapserv->RefPnt.y=-1; - mapserv->ImgPnt.x=-1; - mapserv->ImgPnt.y=-1; - - mapserv->Buffer=0; - - /* - ** variables for multiple query results processing - */ - mapserv->RN=0; /* overall result number */ - mapserv->LRN=0; /* result number within a layer */ - mapserv->NL=0; /* total number of layers with results */ - mapserv->NR=0; /* total number or results */ - mapserv->NLR=0; /* number of results in a layer */ - - mapserv->SearchMap=MS_FALSE; /* apply pan/zoom BEFORE doing the query (e.g. query the output image rather than the input image) */ - - mapserv->QueryFile=NULL; - mapserv->QueryLayer=NULL; - mapserv->SelectLayer=NULL; - mapserv->QueryLayerIndex=-1; - mapserv->SelectLayerIndex=-1; - mapserv->QueryItem=NULL; - mapserv->QueryString=NULL; - mapserv->ShapeIndex=-1; - mapserv->TileIndex=-1; - mapserv->TileMode=TILE_GMAP; - mapserv->QueryCoordSource=NONE; - mapserv->ZoomSize=0; /* zoom absolute magnitude (i.e. > 0) */ - - mapserv->hittest = NULL; - - return mapserv; -} - -void msFreeMapServObj(mapservObj* mapserv) -{ - int i; - - if(mapserv) { - if( mapserv->map ) { - if(mapserv->hittest) { - freeMapHitTests(mapserv->map,mapserv->hittest); - free(mapserv->hittest); - } - msFreeMap(mapserv->map); - mapserv->map = NULL; - } - - if( mapserv->request ) { - msFreeCgiObj(mapserv->request); - mapserv->request = NULL; - } - - for(i=0; iNumLayers; i++) - msFree(mapserv->Layers[i]); - msFree(mapserv->Layers); - - msFree(mapserv->icon); - - msFree(mapserv->QueryItem); - msFree(mapserv->QueryString); - msFree(mapserv->QueryLayer); - msFree(mapserv->SelectLayer); - msFree(mapserv->QueryFile); - - msFree(mapserv); - } -} - -/* -** Ensure there is at least one free entry in the Layers array. -** -** This function is safe to use for the initial allocation of the Layers[] -** array as well (i.e. when MaxLayers==0 and Layers==NULL) -** -** Returns MS_SUCCESS/MS_FAILURE -*/ -int msGrowMapservLayers( mapservObj* mapserv ) -{ - /* Do we need to increase the size of Layers[] by MS_LAYER_ALLOCSIZE? */ - if(mapserv->NumLayers == mapserv->MaxLayers) { - int i; - - if(mapserv->MaxLayers == 0) { - /* initial allocation of array */ - mapserv->MaxLayers += MS_LAYER_ALLOCSIZE; - mapserv->NumLayers = 0; - mapserv->Layers = (char**)msSmallMalloc(mapserv->MaxLayers*sizeof(char*)); - } else { - /* realloc existing array */ - mapserv->MaxLayers += MS_LAYER_ALLOCSIZE; - mapserv->Layers = (char**)msSmallRealloc(mapserv->Layers, mapserv->MaxLayers*sizeof(char*)); - } - - if(mapserv->Layers == NULL) { - msSetError(MS_MEMERR, "Failed to allocate memory for Layers array.", "msGrowMappservLayers()"); - return MS_FAILURE; - } - - for(i=mapserv->NumLayers; iMaxLayers; i++) { - mapserv->Layers[i] = NULL; - } - } - - return MS_SUCCESS; -} - -/* -** Utility function to generate map, legend, scalebar and reference images. -** -** Parameters: -** - mapserv: mapserv object (used to extract the map object). -** - bQueryMap: if set to TRUE a query map will be created instead of a regular map. -** - bReturnOnError: if set to TRUE, the function will return on the first error, else it will try to generate all the images. -*/ -int msGenerateImages(mapservObj *mapserv, int bQueryMap, int bReturnOnError) -{ - char buffer[1024]; - - if(mapserv) { - - /* render the map OR query map */ - if((!bQueryMap && mapserv->map->status == MS_ON) || (bQueryMap && mapserv->map->querymap.status == MS_ON)) { - imageObj *image = NULL; - - image = msDrawMap(mapserv->map, bQueryMap); - if(image) { - snprintf(buffer, sizeof(buffer), "%s%s%s.%s", mapserv->map->web.imagepath, mapserv->map->name, mapserv->Id, MS_IMAGE_EXTENSION(mapserv->map->outputformat)); - - if(msSaveImage(mapserv->map, image, buffer) != MS_SUCCESS && bReturnOnError) { - msFreeImage(image); - return MS_FAILURE; - } - msFreeImage(image); - } else if(bReturnOnError) - return MS_FAILURE; - } - - /* render the legend */ - if(mapserv->map->legend.status == MS_ON) { - imageObj *image = NULL; - image = msDrawLegend(mapserv->map, MS_FALSE, NULL); - if(image) { - snprintf(buffer, sizeof(buffer), "%s%sleg%s.%s", mapserv->map->web.imagepath, mapserv->map->name, mapserv->Id, MS_IMAGE_EXTENSION(mapserv->map->outputformat)); - - if(msSaveImage(mapserv->map, image, buffer) != MS_SUCCESS && bReturnOnError) { - msFreeImage(image); - return MS_FAILURE; - } - msFreeImage(image); - } else if(bReturnOnError) - return MS_FAILURE; - } - - /* render the scalebar */ - if(mapserv->map->scalebar.status == MS_ON) { - imageObj *image = NULL; - image = msDrawScalebar(mapserv->map); - if(image) { - snprintf(buffer, sizeof(buffer), "%s%ssb%s.%s", mapserv->map->web.imagepath, mapserv->map->name, mapserv->Id, MS_IMAGE_EXTENSION(mapserv->map->outputformat)); - if(msSaveImage(mapserv->map, image, buffer) != MS_SUCCESS && bReturnOnError) { - msFreeImage(image); - return MS_FAILURE; - } - msFreeImage(image); - } else if(bReturnOnError) - return MS_FAILURE; - } - - /* render the reference map */ - if(mapserv->map->reference.status == MS_ON) { - imageObj *image; - image = msDrawReferenceMap(mapserv->map); - if(image) { - snprintf(buffer, sizeof(buffer), "%s%sref%s.%s", mapserv->map->web.imagepath, mapserv->map->name, mapserv->Id, MS_IMAGE_EXTENSION(mapserv->map->outputformat)); - if(msSaveImage(mapserv->map, image, buffer) != MS_SUCCESS && bReturnOnError) { - msFreeImage(image); - return MS_FAILURE; - } - msFreeImage(image); - } else if(bReturnOnError) - return MS_FAILURE; - } - - } - - return MS_SUCCESS; -} - -/* -** Utility function to open a template file, process it and -** and return into a buffer the processed template. Uses the -** template file from the web object. Returns NULL if there is -** an error. -*/ -char *msProcessTemplate(mapObj *map, int bGenerateImages, char **names, char **values, int numentries) -{ - char *pszBuffer = NULL; - - if(map) { - - /* Initialize object and set appropriate defaults. */ - mapservObj *mapserv = NULL; - mapserv = msAllocMapServObj(); - - mapserv->map = map; - mapserv->Mode = BROWSE; - - if(names && values && numentries > 0) { - msFreeCharArray(mapserv->request->ParamNames, mapserv->request->NumParams); - msFreeCharArray(mapserv->request->ParamValues, mapserv->request->NumParams); - mapserv->request->ParamNames = names; - mapserv->request->ParamValues = values; - mapserv->request->NumParams = numentries; - } - - /* - ** ISSUE/TODO : some of the name/values should be extracted and - ** processed (ex imgext, layers, ...) as it is done in function - ** loadform. - */ - - if(bGenerateImages) - msGenerateImages(mapserv, MS_FALSE, MS_FALSE); - - /* - ** Process the template. - ** - ** TODO : use web minscaledenom/maxscaledenom depending on the scale. - */ - if(msReturnPage(mapserv, mapserv->map->web.template, BROWSE, &pszBuffer) != MS_SUCCESS) { - msFree(pszBuffer); - pszBuffer = NULL; - } - - /* Don't free the map and names and values arrays since they were passed by reference. */ - mapserv->map = NULL; - mapserv->request->ParamNames = mapserv->request->ParamValues = NULL; - mapserv->request->NumParams = 0; - msFreeMapServObj(mapserv); - } - - return pszBuffer; -} - -/* -** Utility method to process the legend template. -*/ -char *msProcessLegendTemplate(mapObj *map, char **names, char **values, int numentries) -{ - char *pszOutBuf = NULL; - - if(map && map->legend.template) { - - /* Initialize object and set appropriate defaults. */ - mapservObj *mapserv = NULL; - mapserv = msAllocMapServObj(); - - mapserv->map = map; - mapserv->Mode = BROWSE; - - if(names && values && numentries > 0) { - msFreeCharArray(mapserv->request->ParamNames, mapserv->request->NumParams); - msFreeCharArray(mapserv->request->ParamValues, mapserv->request->NumParams); - mapserv->request->ParamNames = names; - mapserv->request->ParamValues = values; - mapserv->request->NumParams = numentries; - } - - pszOutBuf = generateLegendTemplate(mapserv); - - /* Don't free the map and names and values arrays since they were passed by reference. */ - mapserv->map = NULL; - mapserv->request->ParamNames = mapserv->request->ParamValues = NULL; - mapserv->request->NumParams = 0; - msFreeMapServObj(mapserv); - } - - return pszOutBuf; -} - -/* -** Utility function that process a template file(s) used in the -** query and return the processed template(s) in a buffer. -*/ -char *msProcessQueryTemplate(mapObj *map, int bGenerateImages, char **names, char **values, int numentries) -{ - char *pszBuffer = NULL; - - if(map) { - - /* Initialize object and set appropriate defaults. */ - mapservObj *mapserv = NULL; - mapserv = msAllocMapServObj(); - - mapserv->map = map; - mapserv->Mode = QUERY; - - if(names && values && numentries > 0) { - msFreeCharArray(mapserv->request->ParamNames, mapserv->request->NumParams); - msFreeCharArray(mapserv->request->ParamValues, mapserv->request->NumParams); - mapserv->request->ParamNames = names; - mapserv->request->ParamValues = values; - mapserv->request->NumParams = numentries; - } - - if(bGenerateImages) - msGenerateImages(mapserv, MS_TRUE, MS_FALSE); - - mapserv->sendheaders = MS_FALSE; - msReturnTemplateQuery(mapserv, mapserv->map->web.queryformat, &pszBuffer); - - mapserv->map = NULL; - mapserv->request->ParamNames = mapserv->request->ParamValues = NULL; - mapserv->request->NumParams = 0; - msFreeMapServObj(mapserv); - } - - return pszBuffer; -} diff --git a/maptemplate.h b/maptemplate.h deleted file mode 100644 index 1175f7828b..0000000000 --- a/maptemplate.h +++ /dev/null @@ -1,196 +0,0 @@ -/****************************************************************************** - * $Id$ - * - * Project: MapServer - * Purpose: Template processing related declarations. - * Author: Steve Lime and the MapServer team. - * - ****************************************************************************** - * Copyright (c) 1996-2005 Regents of the University of Minnesota. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies of this Software or works derived from this Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - ****************************************************************************/ - -#ifndef MAPTEMPLATE_H -#define MAPTEMPLATE_H - -#include "mapserver.h" -#include "maphash.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define IDPATTERN "^[0-9A-Za-z]{1,63}$" -#define IDSIZE 64 -#define TEMPLATE_TYPE(s) (((strncmp("http://", s, 7) == 0) || (strncmp("https://", s, 8) == 0) || (strncmp("ftp://", s, 6)) == 0) ? MS_URL : MS_FILE) -#define MAXZOOM 25 -#define MINZOOM -25 -#define DEFAULT_DATE_FORMAT "%d/%b/%Y:%H:%M:%S %z" - -enum coordSources {NONE, FROMIMGPNT, FROMIMGBOX, FROMIMGSHAPE, FROMREFPNT, FROMUSERPNT, FROMUSERBOX, FROMUSERSHAPE, FROMBUF, FROMSCALE, FROMTILE}; - -enum modes {BROWSE, ZOOMIN, ZOOMOUT, MAP, LEGEND, LEGENDICON, REFERENCE, SCALEBAR, COORDINATE, - QUERY, NQUERY, ITEMQUERY, ITEMNQUERY, - FEATUREQUERY, FEATURENQUERY, ITEMFEATUREQUERY, ITEMFEATURENQUERY, - INDEXQUERY, TILE, OWS, WFS, MAPLEGEND, MAPLEGENDICON - }; - - -/* struct mapservObj - * Global structure used by templates and mapserver CGI interface. - * - * This structur was created to seperate template functionality - * from the main mapserv file. Instead of moving all template - * related functions in a new file (maptemplate.c) and change - * their signatures to pass all global variables, we created this - * structure with all global variables needed by template. -*/ -typedef struct { - /* should the query and/or map be saved */ - int savemap, savequery; - - cgiRequestObj *request; - - int sendheaders; /* should mime-type header be output, default will be MS_TRUE */ - - mapObj *map; - - char **Layers; - char *icon; /* layer:class combination that defines a legend icon */ - - int NumLayers; /* number of layers specfied by a use */ - int MaxLayers; /* Allocated size of Layers[] array */ - - layerObj *resultlayer; - - int UseShapes; /* are results of a query to be used in calculating an extent of some sort */ - - shapeObj resultshape; - - rectObj RawExt; - - pointObj mappnt; - - double fZoom, Zoom; - int ZoomDirection; /* whether zooming in or out, default is pan or 0 */ - - int Mode; /* can be BROWSE, QUERY, etc. */ - - int TileMode; /* can be GMAP, VE */ - char *TileCoords; /* for GMAP: 0 0 1; for VE: 013021023 */ - - char Id[IDSIZE]; /* big enough for time + pid */ - - int CoordSource; - double ScaleDenom; /* used to create a map extent around a point */ - - int ImgRows, ImgCols; - rectObj ImgExt; /* Existing image's mapextent */ - rectObj ImgBox; - - pointObj RefPnt; - pointObj ImgPnt; - - double Buffer; - - int SearchMap; /* apply pan/zoom BEFORE doing the query (e.g. query the output image rather than the input image) */ - - char *QueryFile; - char *QueryLayer; - char *SelectLayer; - int QueryLayerIndex; - int SelectLayerIndex; - - char *QueryItem; - char *QueryString; - - int ShapeIndex; - int TileIndex; - - int QueryCoordSource; - - int ZoomSize; /* zoom absolute magnitude (i.e. > 0) */ - - /* - ** variables for multiple query results processing - */ - int RN; /* overall result number */ - int LRN; /* result number within a layer */ - int NL; /* total number of layers with results */ - int NR; /* total number or results */ - int NLR; /* number of results in a layer */ - - map_hittest *hittest; -} mapservObj; - - - -/*! \fn msAllocMapServObj - * Allocate memory for all variables in strusture - * and initiate default values -*/ -MS_DLL_EXPORT mapservObj* msAllocMapServObj(void); - -/*! \fn msFreeMapServObj - * free all variables in structure -*/ -MS_DLL_EXPORT void msFreeMapServObj(mapservObj* msObj); - -/* For Mapserv.c */ -MS_DLL_EXPORT int isOn(mapservObj* msObj, char *name, char *group); -MS_DLL_EXPORT int checkWebScale(mapservObj *msObj); -MS_DLL_EXPORT int setExtent(mapservObj *msObj); - -MS_DLL_EXPORT int msReturnPage(mapservObj* msObj, char* , int, char **); -MS_DLL_EXPORT int msReturnURL(mapservObj* msObj, char*, int); -MS_DLL_EXPORT int msReturnNestedTemplateQuery(mapservObj* msObj, char* pszMimeType, char **papszBuffer); -MS_DLL_EXPORT int msReturnTemplateQuery(mapservObj *msObj, char* pszMimeType, char **papszBuffer); -MS_DLL_EXPORT int msReturnOpenLayersPage(mapservObj *mapserv); - -MS_DLL_EXPORT int msRedirect(char* url); - -MS_DLL_EXPORT char *generateLegendTemplate(mapservObj *msObj); - -MS_DLL_EXPORT int msGenerateImages(mapservObj *msObj, int bQueryMap, int bReturnOnError); - - -MS_DLL_EXPORT char *msProcessTemplate(mapObj *map, int bGenerateImages, - char **names, char **values, - int numentries); - -MS_DLL_EXPORT char *msProcessLegendTemplate(mapObj *map, - char **names, char **values, - int numentries); - -MS_DLL_EXPORT char *msProcessQueryTemplate(mapObj *map, - int bGenerateImages, - char **names, char **values, - int numentries); - -MS_DLL_EXPORT int msGrowMapservLayers( mapservObj* msObj ); - -#ifdef __cplusplus -} /* extern C */ -#endif - -#endif - - - diff --git a/mapthread.h b/mapthread.h deleted file mode 100644 index d4d82f01e8..0000000000 --- a/mapthread.h +++ /dev/null @@ -1,88 +0,0 @@ -/****************************************************************************** - * $Id$ - * - * Project: MapServer - * Purpose: Multithreading / locking related declarations. - * Author: Frank Warmerdam - * - ****************************************************************************** - * Copyright (c) 1996-2005 Regents of the University of Minnesota. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies of this Software or works derived from this Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - ****************************************************************************/ - -#ifndef MAPTHREAD_H -#define MAPTHREAD_H - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef USE_THREAD - void msThreadInit(void); - void* msGetThreadId(void); - void msAcquireLock(int); - void msReleaseLock(int); -#else -#define msThreadInit() -#define msGetThreadId() (0) -#define msAcquireLock(x) -#define msReleaseLock(x) -#endif - - /* - ** lock ids - note there is a corresponding lock_names[] array in - ** mapthread.c that needs to be extended when new ids are added. - */ - -#define TLOCK_PARSER 1 -#define TLOCK_GDAL 2 -#define TLOCK_ERROROBJ 3 -#define TLOCK_PROJ 4 -#define TLOCK_TTF 5 -#define TLOCK_POOL 6 -#define TLOCK_SDE 7 -#define TLOCK_ORACLE 8 -#define TLOCK_OWS 9 -#define TLOCK_LAYER_VTABLE 10 -#define TLOCK_IOCONTEXT 11 -#define TLOCK_TMPFILE 12 -#define TLOCK_DEBUGOBJ 13 -#define TLOCK_OGR 14 -#define TLOCK_TIME 15 -#define TLOCK_FRIBIDI 16 -#define TLOCK_WxS 17 -#define TLOCK_GEOS 18 - -#define TLOCK_STATIC_MAX 20 -#define TLOCK_MAX 100 - -#ifdef __cplusplus -} -#endif - -#endif /* MAPTHREAD_H */ - - - - - - - - diff --git a/maptile.c b/maptile.c deleted file mode 100644 index 76f1cc47fc..0000000000 --- a/maptile.c +++ /dev/null @@ -1,533 +0,0 @@ -/****************************************************************************** - * $Id$ - * - * Project: MapServer - * Purpose: MapServer Tile Access API - * Author: Paul Ramsey - * - ****************************************************************************** - * Copyright (c) 2008, Paul Ramsey - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies of this Software or works derived from this Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - ****************************************************************************/ - -#include "maptile.h" -#include "mapproject.h" - -#ifdef USE_TILE_API -static void msTileResetMetatileLevel(mapObj *map) -{ - hashTableObj *meta = &(map->web.metadata); - const char *zero = "0"; - const char *value = NULL; - - /* Is the tile_metatile_levetl set... */ - if((value = msLookupHashTable(meta, "tile_metatile_level")) != NULL) { - msRemoveHashTable(meta, "tile_metatile_level"); - msInsertHashTable(meta, "tile_metatile_level", zero); - } - /* No tile_metatile_level value. */ - else { - msInsertHashTable(meta, "tile_metatile_level", zero); - } -} -#endif - -/************************************************************************ - * msTileGetGMapCoords * - ************************************************************************/ -static int msTileGetGMapCoords(const char *coordstring, int *x, int *y, int *zoom) -{ - - int num_coords = 0; - char **coords = NULL; - - if( coordstring ) { - coords = msStringSplit(coordstring, ' ', &(num_coords)); - if( num_coords != 3 ) { - msFreeCharArray(coords, num_coords); - msSetError(MS_WEBERR, "Invalid number of tile coordinates (should be three).", "msTileSetup()"); - return MS_FAILURE; - } - } else { - msSetError(MS_WEBERR, "Tile parameter not set.", "msTileSetup()"); - return MS_FAILURE; - } - - if( x ) - *x = strtol(coords[0], NULL, 10); - if( y ) - *y = strtol(coords[1], NULL, 10); - if( zoom ) - *zoom = strtol(coords[2], NULL, 10); - - msFreeCharArray(coords, 3); - return MS_SUCCESS; -} - - -/************************************************************************ - * msTileSetParams * - ************************************************************************/ -static void msTileGetParams(mapObj *map, tileParams *params) -{ - - const char *value = NULL; - hashTableObj *meta = &(map->web.metadata); - - params->tile_size = SPHEREMERC_IMAGE_SIZE; - - /* Check for tile buffer, set to buffer==0 as default */ - if((value = msLookupHashTable(meta, "tile_map_edge_buffer")) != NULL) { - params->map_edge_buffer = atoi(value); - if(map->debug) - msDebug("msTileSetParams(): tile_map_edge_buffer = %d\n", params->map_edge_buffer); - } else - params->map_edge_buffer = 0; - - /* Check for metatile size, set to tile==metatile as default */ - if((value = msLookupHashTable(meta, "tile_metatile_level")) != NULL) { - params->metatile_level = atoi(value); - /* Quietly force metatile_level to be sane */ - if( params->metatile_level < 0 ) - params->metatile_level = 0; - if( params->metatile_level > 2 ) - params->metatile_level = 2; - if(map->debug) - msDebug("msTileSetParams(): tile_metatile_level = %d\n", params->metatile_level); - } else - params->metatile_level = 0; - -} - -/************************************************************************ - * msTileExtractSubTile * - * * - ************************************************************************/ -static imageObj* msTileExtractSubTile(const mapservObj *msObj, const imageObj *img) -{ - - int width, mini, minj; - int zoom = 2; - imageObj* imgOut = NULL; - tileParams params; - rendererVTableObj *renderer; - rasterBufferObj imgBuffer; - - if( !MS_RENDERER_PLUGIN(msObj->map->outputformat) - || msObj->map->outputformat->renderer != img->format->renderer || - ! MS_MAP_RENDERER(msObj->map)->supports_pixel_buffer ) { - msSetError(MS_MISCERR,"unsupported or mixed renderers","msTileExtractSubTile()"); - return NULL; - } - renderer = MS_MAP_RENDERER(msObj->map); - - if (renderer->getRasterBufferHandle((imageObj*)img,&imgBuffer) != MS_SUCCESS) { - return NULL; - } - - - /* - ** Load the metatiling information from the map file. - */ - msTileGetParams(msObj->map, ¶ms); - - /* - ** Initialize values for the metatile clip area. - */ - width = img->width - 2*params.map_edge_buffer; - mini = params.map_edge_buffer; - minj = params.map_edge_buffer; - - if( msObj->TileMode == TILE_GMAP ) { - int x, y, zoom; - - if( msObj->TileCoords ) { - if( msTileGetGMapCoords(msObj->TileCoords, &x, &y, &zoom) == MS_FAILURE ) - return NULL; - } else { - msSetError(MS_WEBERR, "Tile parameter not set.", "msTileSetup()"); - return NULL; - } - - if(msObj->map->debug) - msDebug("msTileExtractSubTile(): gmaps coords (x: %d, y: %d)\n",x,y); - - /* - ** The bottom N bits of the coordinates give us the subtile - ** location relative to the metatile. - */ - x = (0xffff ^ (0xffff << params.metatile_level)) & x; - y = (0xffff ^ (0xffff << params.metatile_level)) & y; - - if(msObj->map->debug) - msDebug("msTileExtractSubTile(): gmaps image coords (x: %d, y: %d)\n",x,y); - - mini = mini + x * params.tile_size; - minj = minj + y * params.tile_size; - - } else if( msObj->TileMode == TILE_VE ) { - int tsize; - int i = 0; - char j = 0; - - if( (int)strlen( msObj->TileCoords ) - params.metatile_level < 0 ) { - return(NULL); - } - - /* - ** Process the last elements of the VE coordinate string to place the - ** requested tile in the context of the metatile - */ - for( i = strlen( msObj->TileCoords ) - params.metatile_level; - i < strlen( msObj->TileCoords ); - i++ ) { - j = msObj->TileCoords[i]; - tsize = width / zoom; - if( j == '1' || j == '3' ) mini += tsize; - if( j == '2' || j == '3' ) minj += tsize; - zoom *= 2; - } - } else { - return(NULL); /* Huh? Should have a mode. */ - } - - imgOut = msImageCreate(params.tile_size, params.tile_size, msObj->map->outputformat, NULL, NULL, msObj->map->resolution, msObj->map->defresolution, NULL); - - if( imgOut == NULL ) { - return NULL; - } - - if(msObj->map->debug) - msDebug("msTileExtractSubTile(): extracting (%d x %d) tile, top corner (%d, %d)\n",params.tile_size,params.tile_size,mini,minj); - - - - if(UNLIKELY(MS_FAILURE == renderer->mergeRasterBuffer(imgOut,&imgBuffer,1.0,mini, minj,0, 0,params.tile_size, params.tile_size))) { - msFreeImage(imgOut); - return NULL; - } - - return imgOut; -} - - -/************************************************************************ - * msTileSetup * - * * - * Called from mapserv.c, this is where the fun begins * - * Set up projections and test the parameters for legality. * - ************************************************************************/ -int msTileSetup(mapservObj* msObj) -{ -#ifdef USE_TILE_API - - char *outProjStr = NULL; - tileParams params; - - /* - ** Load the metatiling information from the map file. - */ - msTileGetParams(msObj->map, ¶ms); - - /* - ** Ensure all the LAYERs have a projection. - */ - if( msMapSetLayerProjections(msObj->map) != 0 ) { - return(MS_FAILURE); - } - - /* - ** Set the projection string for this mode. - */ - if( msObj->TileMode == TILE_GMAP || msObj->TileMode == TILE_VE ) { - outProjStr = SPHEREMERC_PROJ4; - } else { - return MS_FAILURE; /* Huh? No mode? */ - } - if( msLoadProjectionString(&(msObj->map->projection), outProjStr) != 0 ) { - msSetError(MS_CGIERR, "Unable to load projection string.", "msTileSetup()"); - return MS_FAILURE; - } - - /* - ** Set up the output extents for this tilemode and tile coordinates - */ - if( msObj->TileMode == TILE_GMAP ) { - - int x, y, zoom; - double zoomfactor; - - if( msObj->TileCoords ) { - if( msTileGetGMapCoords(msObj->TileCoords, &x, &y, &zoom) == MS_FAILURE ) - return MS_FAILURE; - } else { - msSetError(MS_WEBERR, "Tile parameter not set.", "msTileSetup()"); - return MS_FAILURE; - } - - if( params.metatile_level >= zoom ) { - msTileResetMetatileLevel(msObj->map); - } - - zoomfactor = pow(2.0, (double)zoom); - - /* - ** Check the input request for sanity. - */ - if( x >= zoomfactor || y >= zoomfactor ) { - msSetError(MS_CGIERR, "GMap tile coordinates are too large for supplied zoom.", "msTileSetup()"); - return(MS_FAILURE); - } - if( x < 0 || y < 0 ) { - msSetError(MS_CGIERR, "GMap tile coordinates should not be less than zero.", "msTileSetup()"); - return(MS_FAILURE); - } - - } else if ( msObj->TileMode == TILE_VE ) { - - if( strspn( msObj->TileCoords, "0123" ) < strlen( msObj->TileCoords ) ) { - msSetError(MS_CGIERR, "VE tile name should only include characters 0, 1, 2 and 3.", "msTileSetup()"); - return(MS_FAILURE); - } - - if( params.metatile_level >= strlen(msObj->TileCoords) ) { - msTileResetMetatileLevel(msObj->map); - } - - } else { - return(MS_FAILURE); /* Huh? Should have a mode. */ - } - - return MS_SUCCESS; -#else - msSetError(MS_CGIERR, "Tile API is not available.", "msTileSetup()"); - return(MS_FAILURE); -#endif -} - - - -/************************************************************************ - * msTileSetExtent * - * * - * Based on the input parameters, set the output extent for this * - * tile. * - ************************************************************************/ -int msTileSetExtent(mapservObj* msObj) -{ -#ifdef USE_TILE_API - - mapObj *map = msObj->map; - double dx, dy, buffer; - tileParams params; - - /* Read the tile-mode map file parameters */ - msTileGetParams(msObj->map, ¶ms); - - if( msObj->TileMode == TILE_GMAP ) { - int x, y, zoom; - double zoomfactor, tilesize, xmin, xmax, ymin, ymax; - - if( msObj->TileCoords ) { - if( msTileGetGMapCoords(msObj->TileCoords, &x, &y, &zoom) == MS_FAILURE ) - return MS_FAILURE; - } else { - msSetError(MS_WEBERR, "Tile parameter not set.", "msTileSetup()"); - return MS_FAILURE; - } - - if(map->debug) - msDebug("msTileSetExtent(): gmaps coords (x: %d, y: %d, z: %d)\n",x,y,zoom); - - /* - ** If we are metatiling, adjust the zoom level appropriately, - ** then scale back the x/y coordinates to match the new level. - */ - if( params.metatile_level > 0 ) { - zoom = zoom - params.metatile_level; - x = x >> params.metatile_level; - y = y >> params.metatile_level; - } - - if(map->debug) - msDebug("msTileSetExtent(): gmaps metacoords (x: %d, y: %d, z: %d)\n",x,y,zoom); - - zoomfactor = pow(2.0, (double)zoom); - - /* - ** Calculate the ground extents of the tile request. - */ - /* printf("X: %i Y: %i Z: %i\n",x,y,zoom); */ - tilesize = SPHEREMERC_GROUND_SIZE / zoomfactor; - xmin = (x * tilesize) - (SPHEREMERC_GROUND_SIZE / 2.0); - xmax = ((x + 1) * tilesize) - (SPHEREMERC_GROUND_SIZE / 2.0); - ymin = (SPHEREMERC_GROUND_SIZE / 2.0) - ((y + 1) * tilesize); - ymax = (SPHEREMERC_GROUND_SIZE / 2.0) - (y * tilesize); - - map->extent.minx = xmin; - map->extent.maxx = xmax; - map->extent.miny = ymin; - map->extent.maxy = ymax; - - } else if( msObj->TileMode == TILE_VE ) { - - double minx = SPHEREMERC_GROUND_SIZE / -2.0; - double miny = SPHEREMERC_GROUND_SIZE / -2.0; - double maxx = SPHEREMERC_GROUND_SIZE / 2.0; - double maxy = SPHEREMERC_GROUND_SIZE / 2.0; - double zoom = 2.0; - double tsize; - int i = 0; - char j = 0; - - /* - ** Walk down the VE URL string, adjusting the extent each time. - ** For meta-tiling cases, we stop early, to draw a larger image. - */ - for( i = 0; i < strlen( msObj->TileCoords ) - params.metatile_level; i++ ) { - j = msObj->TileCoords[i]; - tsize = SPHEREMERC_GROUND_SIZE / zoom; - if( j == '1' || j == '3' ) minx += tsize; - if( j == '0' || j == '2' ) maxx -= tsize; - if( j == '2' || j == '3' ) maxy -= tsize; - if( j == '0' || j == '1' ) miny += tsize; - zoom *= 2.0; - } - - map->extent.minx = minx; - map->extent.maxx = maxx; - map->extent.miny = miny; - map->extent.maxy = maxy; - - } else { - return(MS_FAILURE); /* Huh? Should have a mode. */ - } - - /* - ** Set the output tile size. - */ - msObj->ImgCols = SPHEREMERC_IMAGE_SIZE << params.metatile_level; - msObj->ImgRows = SPHEREMERC_IMAGE_SIZE << params.metatile_level; - map->width = SPHEREMERC_IMAGE_SIZE << params.metatile_level; - map->height = SPHEREMERC_IMAGE_SIZE << params.metatile_level; - - if(map->debug) - msDebug("msTileSetExtent(): base image size (%d x %d)\n",map->width,map->height); - - /* - ** Add the gutters - ** First calculate ground units in the buffer at current extent - */ - buffer = params.map_edge_buffer * (map->extent.maxx - map->extent.minx) / (double)map->width; - /* - ** Then adjust the map extents out by that amount - */ - map->extent.minx -= buffer; - map->extent.maxx += buffer; - map->extent.miny -= buffer; - map->extent.maxy += buffer; - /* - ** Finally adjust the map image size by the pixel buffer - */ - map->width += 2 * params.map_edge_buffer; - map->height += 2 * params.map_edge_buffer; - msObj->ImgCols += 2 * params.map_edge_buffer; - msObj->ImgRows += 2 * params.map_edge_buffer; - - if(map->debug) - msDebug("msTileSetExtent(): buffered image size (%d x %d)\n",map->width,map->height); - - /* - ** Adjust the extents inwards by 1/2 pixel so they are from - ** center-of-pixel to center-of-pixel, instead of edge-to-edge. - ** This is the way mapserver does it. - */ - dx = (map->extent.maxx - map->extent.minx) / map->width; - map->extent.minx += dx*0.5; - map->extent.maxx -= dx*0.5; - dy = (map->extent.maxy - map->extent.miny) / map->height; - map->extent.miny += dy*0.5; - map->extent.maxy -= dy*0.5; - - /* - ** Ensure the labelcache buffer is greater than the tile buffer. - */ - if( params.map_edge_buffer > 0 ) { - const char *value; - hashTableObj *meta = &(map->web.metadata); - char tilebufferstr[64]; - - /* Write the tile buffer to a string */ - snprintf(tilebufferstr, sizeof(tilebufferstr), "-%d", params.map_edge_buffer); - - /* Hm, the labelcache buffer is set... */ - if((value = msLookupHashTable(meta, "labelcache_map_edge_buffer")) != NULL) { - /* If it's too small, replace with a bigger one */ - if( params.map_edge_buffer > abs(atoi(value)) ) { - msRemoveHashTable(meta, "labelcache_map_edge_buffer"); - msInsertHashTable(meta, "labelcache_map_edge_buffer", tilebufferstr); - } - } - /* No labelcache buffer value? Then we use the tile buffer. */ - else { - msInsertHashTable(meta, "labelcache_map_edge_buffer", tilebufferstr); - } - } - - if(map->debug) { - msDebug( "msTileSetExtent (%f, %f) (%f, %f)\n", map->extent.minx, map->extent.miny, map->extent.maxx, map->extent.maxy); - } - - return MS_SUCCESS; -#else - msSetError(MS_CGIERR, "Tile API is not available.", "msTileSetExtent()"); - return(MS_FAILURE); -#endif -} - - - -/************************************************************************ - * msDrawTile * - * * - * Draw the tile once with gutters, metatiling and buffers, then * - * clip out the final tile. * - * WARNING: Call msTileSetExtent() first or this will be a pointless * - * fucnction call. * - ************************************************************************/ - -imageObj* msTileDraw(mapservObj *msObj) -{ - imageObj *img; - tileParams params; - msTileGetParams(msObj->map, ¶ms); - img = msDrawMap(msObj->map, MS_FALSE); - if( img == NULL ) - return NULL; - if( params.metatile_level > 0 || params.map_edge_buffer > 0 ) { - imageObj *tmp = msTileExtractSubTile(msObj, img); - msFreeImage(img); - if( tmp == NULL ) - return NULL; - img = tmp; - } - return img; -} - diff --git a/maptime.c b/maptime.c deleted file mode 100644 index 84c2c6df45..0000000000 --- a/maptime.c +++ /dev/null @@ -1,485 +0,0 @@ -/****************************************************************************** - * $id$ - * - * Project: MapServer - * Purpose: Date/Time utility functions. - * Author: Steve Lime and the MapServer team. - * - ****************************************************************************** - * Copyright (c) 1996-2005 Regents of the University of Minnesota. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies of this Software or works derived from this Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - ****************************************************************************/ - -#define _GNU_SOURCE /* glibc2 needs this for strptime() */ -#include -#include -#include - -#include "mapserver.h" -#include "maptime.h" -#include "maperror.h" -#include "mapthread.h" - -typedef struct { - char pattern[64]; - ms_regex_t *regex; - char format[32]; - char userformat[32]; - MS_TIME_RESOLUTION resolution; -} timeFormatObj; - -static timeFormatObj ms_timeFormats[] = { - {"^[0-9]{8}", NULL, "%Y%m%d","YYYYMMDD",TIME_RESOLUTION_DAY}, - {"^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z", NULL, "%Y-%m-%dT%H:%M:%SZ","YYYY-MM-DDTHH:MM:SSZ",TIME_RESOLUTION_SECOND}, - {"^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}", NULL, "%Y-%m-%dT%H:%M:%S", "YYYY-MM-DDTHH:MM:SS",TIME_RESOLUTION_SECOND}, - {"^[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}", NULL, "%Y-%m-%d %H:%M:%S", "YYYY-MM-DD HH:MM:SS", TIME_RESOLUTION_SECOND}, - {"^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}", NULL, "%Y-%m-%dT%H:%M", "YYYY-MM-DDTHH:MM",TIME_RESOLUTION_MINUTE}, - {"^[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}", NULL, "%Y-%m-%d %H:%M", "YYYY-MM-DD HH:MM",TIME_RESOLUTION_MINUTE}, - {"^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}", NULL, "%Y-%m-%dT%H", "YYYY-MM-DDTHH",TIME_RESOLUTION_HOUR}, - {"^[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}", NULL, "%Y-%m-%d %H", "YYYY-MM-DD HH",TIME_RESOLUTION_HOUR}, - {"^[0-9]{4}-[0-9]{2}-[0-9]{2}", NULL, "%Y-%m-%d", "YYYY-MM-DD", TIME_RESOLUTION_DAY}, - {"^[0-9]{4}-[0-9]{2}", NULL, "%Y-%m", "YYYY-MM",TIME_RESOLUTION_MONTH}, - {"^[0-9]{4}", NULL, "%Y", "YYYY",TIME_RESOLUTION_YEAR}, - {"^T[0-9]{2}:[0-9]{2}:[0-9]{2}Z", NULL, "T%H:%M:%SZ", "THH:MM:SSZ",TIME_RESOLUTION_SECOND}, - {"^T[0-9]{2}:[0-9]{2}:[0-9]{2}", NULL, "T%H:%M:%S", "THH:MM:SS", TIME_RESOLUTION_SECOND}, - {"^[0-9]{2}:[0-9]{2}:[0-9]{2}Z", NULL, "%H:%M:%SZ", "HH:MM:SSZ", TIME_RESOLUTION_SECOND}, - {"^[0-9]{2}:[0-9]{2}:[0-9]{2}", NULL, "%H:%M:%S", "HH:MM:SS", TIME_RESOLUTION_SECOND} -}; - -#define MS_NUMTIMEFORMATS (int)(sizeof(ms_timeFormats)/sizeof(ms_timeFormats[0])) - -int *ms_limited_pattern = NULL; -int ms_num_limited_pattern; - -int ms_time_inited = 0; -int msTimeSetup() -{ - if(!ms_time_inited) { - msAcquireLock(TLOCK_TIME); - if(!ms_time_inited) { - int i; - for(i=0;itm_sec = 0; /* set all members to zero */ - time->tm_min = 0; - time->tm_hour = 0; - time->tm_mday = 0; - time->tm_mon = 0; - time->tm_year = 0; - time->tm_wday = 0; - time->tm_yday = 0; - time->tm_isdst = 0; - - return; -} - -static int compareIntVals(int a, int b) -{ - if(ab) return 1; - else return 0; -} - -int msDateCompare(struct tm *time1, struct tm *time2) -{ - int result; - - if((result = compareIntVals(time1->tm_year, time2->tm_year)) != 0) - return result; /* not equal based on year */ - else if((result = compareIntVals(time1->tm_mon, time2->tm_mon)) != 0) - return result; /* not equal based on month */ - else if((result = compareIntVals(time1->tm_mday, time2->tm_mday)) != 0) - return result; /* not equal based on day of month */ - - return(0); /* must be equal */ -} - -int msTimeCompare(struct tm *time1, struct tm *time2) -{ - int result; - - // fprintf(stderr, "in msTimeCompare()...\n"); - // fprintf(stderr, "time1: %d %d %d %d %d %d\n", time1->tm_year, time1->tm_mon, time1->tm_mday, time1->tm_hour, time1->tm_min, time1->tm_sec); - // fprintf(stderr, "time2: %d %d %d %d %d %d\n", time2->tm_year, time2->tm_mon, time2->tm_mday, time2->tm_hour, time2->tm_min, time2->tm_sec); - - if((result = compareIntVals(time1->tm_year, time2->tm_year)) != 0) - return result; /* not equal based on year */ - else if((result = compareIntVals(time1->tm_mon, time2->tm_mon)) != 0) - return result; /* not equal based on month */ - else if((result = compareIntVals(time1->tm_mday, time2->tm_mday)) != 0) - return result; /* not equal based on day of month */ - else if((result = compareIntVals(time1->tm_hour, time2->tm_hour)) != 0) - return result; /* not equal based on hour */ - else if((result = compareIntVals(time1->tm_min, time2->tm_min)) != 0) - return result; /* not equal based on minute */ - else if((result = compareIntVals(time1->tm_sec, time2->tm_sec)) != 0) - return result; /* not equal based on second */ - - return(0); /* must be equal */ -} - -#if defined(_WIN32) && !defined(__CYGWIN__) -#include -void msGettimeofday(struct mstimeval* tp, void* tzp) -{ - struct _timeb theTime; - - _ftime(&theTime); - tp->tv_sec = theTime.time; - tp->tv_usec = theTime.millitm * 1000; -} -#endif - -#if defined(_WIN32) && !defined(__CYGWIN__) -/* we need to provide our own prototype on windows. */ -char *strptime( const char *buf, const char *format, struct tm *timeptr ); -#endif - -char *msStrptime(const char *s, const char *format, struct tm *tm) -{ - memset(tm, 0, sizeof(struct tm)); - return strptime(s, format, tm); -} - -/** - return MS_TRUE if the time string matchs the timeformat. - else return MS_FALSE. - */ -int msTimeMatchPattern(const char *timestring, const char *timeformat) -{ - int i =-1; - if(msTimeSetup() != MS_SUCCESS) { - return MS_FALSE; - } - - /* match the pattern format first and then check if the time string */ - /* matchs the pattern. If it is the case retrurn the MS_TRUE */ - for (i=0; i= 0 && i < MS_NUMTIMEFORMATS) { - int match = ms_regexec(ms_timeFormats[i].regex, timestring, 0, NULL, 0); - if(match == 0) - return MS_TRUE; - } - return MS_FALSE; -} - - -void msUnsetLimitedPatternToUse() -{ - msTimeSetup(); - ms_num_limited_pattern = 0; -} - -void msSetLimitedPatternsToUse(const char *patternstring) -{ - int *limitedpatternindice = NULL; - int numpatterns=0, i=0, j=0, ntmp=0; - char **patterns = NULL; - msTimeSetup(); - - limitedpatternindice = (int *)msSmallMalloc(sizeof(int)*MS_NUMTIMEFORMATS); - - /* free previous setting */ - msUnsetLimitedPatternToUse(); - - if (patternstring) { - patterns = msStringSplit(patternstring, ',', &ntmp); - if (patterns && ntmp >= 1) { - - for (i=0; i 0) { - for (i=0; i 0) - num_patterns = ms_num_limited_pattern; - else - num_patterns = MS_NUMTIMEFORMATS; - - for(i=0; i 0) - indice = ms_limited_pattern[i]; - else - indice = i; - - match = ms_regexec(ms_timeFormats[indice].regex, string, 0,NULL, 0); - /* test the expression against the string */ - if(match == 0) { - /* match */ - msStrptime(string, ms_timeFormats[indice].format, tm); - return(MS_TRUE); - } - } - - msSetError(MS_REGEXERR, "Unrecognized date or time format (%s).", "msParseTime()", string); - return(MS_FALSE); -} - -/** - * Parse the time string and return the reslution - */ -int msTimeGetResolution(const char *timestring) -{ - int i=0; - - if (!timestring) - return -1; - - for(i=0; i=2) { /*range */ - if (msParseTime(atimeelements[0], &tmtimestart) != MS_TRUE) { - msFreeCharArray(atimeelements, numelements); - return MS_FALSE; - } - if (msParseTime(atimeelements[1], &tmtimeend) != MS_TRUE) { - msFreeCharArray(atimeelements, numelements); - return MS_FALSE; - } - } - - msFreeCharArray(atimeelements, numelements); - - - /* Now parse the time extent. Extents can be - - one range (2004-09-21/2004-09-25/resolution) - - multiple rages 2004-09-21/2004-09-25/res1,2004-09-21/2004-09-25/res2 - - one value 2004-09-21 - - mutiple values 2004-09-21,2004-09-22,2004-09-23 - */ - - numextents = 0; - atimeextents = msStringSplit (timeextent, ',', &numextents); - if (numextents <= 0) { - msFreeCharArray(atimeextents, numextents); - return MS_FALSE; - } - - /*the time timestring should at be valid in one of the extents - defined */ - - for (i=0; i= 0) { - msFreeCharArray(atimerange, numranges); - msFreeCharArray(atimeextents, numextents); - return MS_TRUE; - } - } - /*2004-09-21/2004-09-25/res1*/ - else if (numranges >= 2) { - if (msParseTime(atimerange[0], &tmstart) == MS_TRUE && - msParseTime(atimerange[1], &tmend) == MS_TRUE && - msTimeCompare(&tmstart, &tmtimestart) <= 0 && - msTimeCompare(&tmend, &tmtimeend) >= 0) { - msFreeCharArray(atimerange, numranges); - msFreeCharArray(atimeextents, numextents); - return MS_TRUE; - } - } - msFreeCharArray(atimerange, numranges); - - - } - msFreeCharArray(atimeextents, numextents); - return MS_FALSE; - -} - -int msValidateTimeValue(const char *timestring, const char *timeextent) -{ - char **atimes = NULL; - int i, numtimes=0; - - /* we need to validate the time passsed in the request */ - /* against the time extent defined */ - - if (!timestring || !timeextent) - return MS_FALSE; - - /* To avoid SQL injections */ - if (strchr(timestring, '\'')) - return MS_FALSE; - - /* parse the time string. We support descrete times (eg 2004-09-21), */ - /* multiple times (2004-09-21, 2004-09-22, ...) */ - /* and range(s) (2004-09-21/2004-09-25, 2004-09-27/2004-09-29) */ - if (strstr(timestring, ",") == NULL && strstr(timestring, "/") == NULL) { /* discrete time */ - return _msValidateTime(timestring, timeextent); - } else { - atimes = msStringSplit(timestring, ',', &numtimes); - if (numtimes >=1) { /* multiple times */ - if (strstr(atimes[0], "/") == NULL) { /* multiple descrete times */ - for (i=0; inumshapes = 0; - node->ids = NULL; - - node->numsubnodes = 0; - - memcpy(&(node->rect), &(rect), sizeof(rectObj)); - - return node; -} - - -SHPTreeHandle msSHPDiskTreeOpen(const char * pszTree, int debug) -{ - char *pszFullname, *pszBasename; - SHPTreeHandle psTree; - - char pabyBuf[16]; - int i; - char bBigEndian; - - /* -------------------------------------------------------------------- */ - /* Establish the byte order on this machine. */ - /* -------------------------------------------------------------------- */ - i = 1; - if( *((uchar *) &i) == 1 ) - bBigEndian = MS_FALSE; - else - bBigEndian = MS_TRUE; - - /* -------------------------------------------------------------------- */ - /* Initialize the info structure. */ - /* -------------------------------------------------------------------- */ - psTree = (SHPTreeHandle) msSmallMalloc(sizeof(SHPTreeInfo)); - - /* -------------------------------------------------------------------- */ - /* Compute the base (layer) name. If there is any extension */ - /* on the passed in filename we will strip it off. */ - /* -------------------------------------------------------------------- */ - pszBasename = (char *) msSmallMalloc(strlen(pszTree)+5); - strcpy( pszBasename, pszTree ); - for( i = strlen(pszBasename)-1; - i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/' - && pszBasename[i] != '\\'; - i-- ) {} - - if( pszBasename[i] == '.' ) - pszBasename[i] = '\0'; - - /* -------------------------------------------------------------------- */ - /* Open the .shp and .shx files. Note that files pulled from */ - /* a PC to Unix with upper case filenames won't work! */ - /* -------------------------------------------------------------------- */ - pszFullname = (char *) msSmallMalloc(strlen(pszBasename) + 5); - sprintf( pszFullname, "%s%s", pszBasename, MS_INDEX_EXTENSION); - psTree->fp = fopen(pszFullname, "rb" ); - if( psTree->fp == NULL ) { - sprintf( pszFullname, "%s.QIX", pszBasename); - psTree->fp = fopen(pszFullname, "rb" ); - } - - msFree(pszBasename); /* don't need these any more */ - msFree(pszFullname); - - if( psTree->fp == NULL ) { - msFree(psTree); - return( NULL ); - } - - if( fread( pabyBuf, 8, 1, psTree->fp ) != 1 ) { - msFree(psTree); - return( NULL ); - } - - memcpy( &psTree->signature, pabyBuf, 3 ); - if( strncmp(psTree->signature,"SQT",3) ) { - /* ---------------------------------------------------------------------- */ - /* must check if the 2 first bytes equal 0 of max depth that cannot */ - /* be more than 65535. If yes, we must swap all value. The problem */ - /* here is if there's no Depth (bytea 5,6,7,8 in the file) all bytes */ - /* will be set to 0. So,we will test with the number of shapes (bytes */ - /* 1,2,3,4) that cannot be more than 65535 too. */ - /* ---------------------------------------------------------------------- */ - if (debug) { - msDebug("WARNING in msSHPDiskTreeOpen(): %s is in old index format " - "which has been deprecated. It is strongly recommended to " - "regenerate it in new format.\n", pszTree); - } - if((pabyBuf[4] == 0 && pabyBuf[5] == 0 && - pabyBuf[6] == 0 && pabyBuf[7] == 0)) { - psTree->LSB_order = !(pabyBuf[0] == 0 && pabyBuf[1] == 0); - } else { - psTree->LSB_order = !(pabyBuf[4] == 0 && pabyBuf[5] == 0); - } - psTree->needswap = ((psTree->LSB_order) != (!bBigEndian)); - - /* ---------------------------------------------------------------------- */ - /* poor hack to see if this quadtree was created by a computer with a */ - /* different Endian */ - /* ---------------------------------------------------------------------- */ - psTree->version = 0; - } else { - psTree->needswap = (( pabyBuf[3] == MS_NEW_MSB_ORDER ) ^ ( bBigEndian )); - - psTree->LSB_order = ( pabyBuf[3] == MS_NEW_LSB_ORDER ); - memcpy( &psTree->version, pabyBuf+4, 1 ); - memcpy( &psTree->flags, pabyBuf+5, 3 ); - - if( fread( pabyBuf, 8, 1, psTree->fp ) != 1 ) - { - msFree(psTree); - return( NULL ); - } - } - - if( psTree->needswap ) SwapWord( 4, pabyBuf ); - memcpy( &psTree->nShapes, pabyBuf, 4 ); - - if( psTree->needswap ) SwapWord( 4, pabyBuf+4 ); - memcpy( &psTree->nDepth, pabyBuf+4, 4 ); - - return( psTree ); -} - - -void msSHPDiskTreeClose(SHPTreeHandle disktree) -{ - fclose( disktree->fp ); - free( disktree ); -} - - -treeObj *msCreateTree(shapefileObj *shapefile, int maxdepth) -{ - int i; - treeObj *tree; - rectObj bounds; - - if(!shapefile) return NULL; - - /* -------------------------------------------------------------------- */ - /* Allocate the tree object */ - /* -------------------------------------------------------------------- */ - tree = (treeObj *) msSmallMalloc(sizeof(treeObj)); - - tree->numshapes = shapefile->numshapes; - tree->maxdepth = maxdepth; - - /* -------------------------------------------------------------------- */ - /* If no max depth was defined, try to select a reasonable one */ - /* that implies approximately 8 shapes per node. */ - /* -------------------------------------------------------------------- */ - if( tree->maxdepth == 0 ) { - int numnodes = 1; - - while(numnodes*4 < shapefile->numshapes) { - tree->maxdepth += 1; - numnodes = numnodes * 2; - } - } - - /* -------------------------------------------------------------------- */ - /* Allocate the root node. */ - /* -------------------------------------------------------------------- */ - tree->root = treeNodeCreate(shapefile->bounds); - - for(i=0; inumshapes; i++) { - if(msSHPReadBounds(shapefile->hSHP, i, &bounds) == MS_SUCCESS) - treeAddShapeId(tree, i, bounds); - } - - return tree; -} - -static void destroyTreeNode(treeNodeObj *node) -{ - int i; - - for(i=0; inumsubnodes; i++ ) { - if(node->subnode[i]) - destroyTreeNode(node->subnode[i]); - } - - if(node->ids) - free(node->ids); - - free(node); -} - -void msDestroyTree(treeObj *tree) -{ - destroyTreeNode(tree->root); - free(tree); -} - -static void treeSplitBounds( rectObj *in, rectObj *out1, rectObj *out2) -{ - double range; - - /* -------------------------------------------------------------------- */ - /* The output bounds will be very similar to the input bounds, */ - /* so just copy over to start. */ - /* -------------------------------------------------------------------- */ - memcpy(out1, in, sizeof(rectObj)); - memcpy(out2, in, sizeof(rectObj)); - - /* -------------------------------------------------------------------- */ - /* Split in X direction. */ - /* -------------------------------------------------------------------- */ - if((in->maxx - in->minx) > (in->maxy - in->miny)) { - range = in->maxx - in->minx; - - out1->maxx = in->minx + range * SPLITRATIO; - out2->minx = in->maxx - range * SPLITRATIO; - } - - /* -------------------------------------------------------------------- */ - /* Otherwise split in Y direction. */ - /* -------------------------------------------------------------------- */ - else { - range = in->maxy - in->miny; - - out1->maxy = in->miny + range * SPLITRATIO; - out2->miny = in->maxy - range * SPLITRATIO; - } -} - -static int treeNodeAddShapeId( treeNodeObj *node, int id, rectObj rect, int maxdepth) -{ - int i; - - /* -------------------------------------------------------------------- */ - /* If there are subnodes, then consider whether this object */ - /* will fit in them. */ - /* -------------------------------------------------------------------- */ - if( maxdepth > 1 && node->numsubnodes > 0 ) { - for(i=0; inumsubnodes; i++ ) { - if( msRectContained(&rect, &node->subnode[i]->rect)) { - return treeNodeAddShapeId( node->subnode[i], id, rect, maxdepth-1); - } - } - } - - /* -------------------------------------------------------------------- */ - /* Otherwise, consider creating four subnodes if could fit into */ - /* them, and adding to the appropriate subnode. */ - /* -------------------------------------------------------------------- */ -#if MAX_SUBNODES == 4 - else if( maxdepth > 1 && node->numsubnodes == 0 ) { - rectObj half1, half2, quad1, quad2, quad3, quad4; - - treeSplitBounds(&node->rect, &half1, &half2); - treeSplitBounds(&half1, &quad1, &quad2); - treeSplitBounds(&half2, &quad3, &quad4); - - if(msRectContained(&rect, &quad1) || msRectContained(&rect, &quad2) || msRectContained(&rect, &quad3) || msRectContained(&rect, &quad4)) { - node->numsubnodes = 4; - node->subnode[0] = treeNodeCreate(quad1); - node->subnode[1] = treeNodeCreate(quad2); - node->subnode[2] = treeNodeCreate(quad3); - node->subnode[3] = treeNodeCreate(quad4); - - /* recurse back on this node now that it has subnodes */ - return(treeNodeAddShapeId(node, id, rect, maxdepth)); - } - } -#endif - - /* -------------------------------------------------------------------- */ - /* Otherwise, consider creating two subnodes if could fit into */ - /* them, and adding to the appropriate subnode. */ - /* -------------------------------------------------------------------- */ -#if MAX_SUBNODE == 2 - else if( maxdepth > 1 && node->numsubnodes == 0 ) { - rectObj half1, half2; - - treeSplitBounds(&node->rect, &half1, &half2); - - if( msRectContained(&rect, &half1)) { - node->numsubnodes = 2; - node->subnode[0] = treeNodeCreate(half1); - node->subnode[1] = treeNodeCreate(half2); - - return(treeNodeAddShapeId(node->subnode[0], id, rect, maxdepth-1)); - } else if(msRectContained(&rect, &half2)) { - node->numsubnodes = 2; - node->subnode[0] = treeNodeCreate(&half1); - node->subnode[1] = treeNodeCreate(&half2); - - return(treeNodeAddShapeId(node->subnode[1], id, rect, maxdepth-1)); - } - } -#endif /* MAX_SUBNODE == 2 */ - - /* -------------------------------------------------------------------- */ - /* If none of that worked, just add it to this nodes list. */ - /* -------------------------------------------------------------------- */ - node->numshapes++; - - node->ids = SfRealloc( node->ids, sizeof(ms_int32) * node->numshapes ); - node->ids[node->numshapes-1] = id; - - return MS_TRUE; -} - -static int treeAddShapeId(treeObj *tree, int id, rectObj rect) -{ - return(treeNodeAddShapeId(tree->root, id, rect, tree->maxdepth)); -} - -static void treeCollectShapeIds(treeNodeObj *node, rectObj aoi, ms_bitarray status) -{ - int i; - - /* -------------------------------------------------------------------- */ - /* Does this node overlap the area of interest at all? If not, */ - /* return without adding to the list at all. */ - /* -------------------------------------------------------------------- */ - if(!msRectOverlap(&node->rect, &aoi)) - return; - - /* -------------------------------------------------------------------- */ - /* Add the local nodes shapeids to the list. */ - /* -------------------------------------------------------------------- */ - for(i=0; inumshapes; i++) - msSetBit(status, node->ids[i], 1); - - /* -------------------------------------------------------------------- */ - /* Recurse to subnodes if they exist. */ - /* -------------------------------------------------------------------- */ - for(i=0; inumsubnodes; i++) { - if(node->subnode[i]) - treeCollectShapeIds(node->subnode[i], aoi, status); - } -} - -ms_bitarray msSearchTree(const treeObj *tree, rectObj aoi) -{ - ms_bitarray status=NULL; - - status = msAllocBitArray(tree->numshapes); - if(!status) { - msSetError(MS_MEMERR, NULL, "msSearchTree()"); - return(NULL); - } - - treeCollectShapeIds(tree->root, aoi, status); - - return(status); -} - -static int treeNodeTrim( treeNodeObj *node ) -{ - int i; - - /* -------------------------------------------------------------------- */ - /* Trim subtrees, and free subnodes that come back empty. */ - /* -------------------------------------------------------------------- */ - for(i=0; inumsubnodes; i++ ) { - if(treeNodeTrim(node->subnode[i])) { - destroyTreeNode(node->subnode[i]); - node->subnode[i] = node->subnode[node->numsubnodes-1]; - node->numsubnodes--; - i--; /* process the new occupant of this subnode entry */ - } - } - - /* -------------------------------------------------------------------- */ - /* If the current node has 1 subnode and no shapes, promote that */ - /* subnode to the current node position. */ - /* -------------------------------------------------------------------- */ - if( node->numsubnodes == 1 && node->numshapes == 0) { - treeNodeObj* psSubNode = node->subnode[0]; - - memcpy(&node->rect, &psSubNode->rect, - sizeof(psSubNode->rect)); - node->numshapes = psSubNode->numshapes; - assert(node->ids == NULL); - node->ids = psSubNode->ids; - node->numsubnodes = psSubNode->numsubnodes; - for( i = 0; i < psSubNode->numsubnodes; i++ ) - node->subnode[i] = psSubNode->subnode[i]; - free(psSubNode); - } - - /* -------------------------------------------------------------------- */ - /* We should be trimmed if we have no subnodes, and no shapes. */ - /* -------------------------------------------------------------------- */ - - return(node->numsubnodes == 0 && node->numshapes == 0); -} - -void msTreeTrim(treeObj *tree) -{ - treeNodeTrim(tree->root); -} - -static void searchDiskTreeNode(SHPTreeHandle disktree, rectObj aoi, ms_bitarray status) -{ - int i; - ms_int32 offset; - ms_int32 numshapes, numsubnodes; - rectObj rect; - - int *ids=NULL; - - if( fread( &offset, 4, 1, disktree->fp ) != 1 ) - goto error; - if ( disktree->needswap ) SwapWord ( 4, &offset ); - - if( fread( &rect, sizeof(rectObj), 1, disktree->fp ) != 1 ) - goto error; - if ( disktree->needswap ) SwapWord ( 8, &rect.minx ); - if ( disktree->needswap ) SwapWord ( 8, &rect.miny ); - if ( disktree->needswap ) SwapWord ( 8, &rect.maxx ); - if ( disktree->needswap ) SwapWord ( 8, &rect.maxy ); - - if( fread( &numshapes, 4, 1, disktree->fp ) != 1 ) - goto error; - if ( disktree->needswap ) SwapWord ( 4, &numshapes ); - - if(!msRectOverlap(&rect, &aoi)) { /* skip rest of this node and sub-nodes */ - offset += numshapes*sizeof(ms_int32) + sizeof(ms_int32); - fseek(disktree->fp, offset, SEEK_CUR); - return; - } - if(numshapes > 0) { - ids = (int *)msSmallMalloc(numshapes*sizeof(ms_int32)); - - if( fread( ids, numshapes*sizeof(ms_int32), 1, disktree->fp ) != 1 ) - goto error; - if (disktree->needswap ) { - for( i=0; ifp ) != 1 ) - goto error; - if ( disktree->needswap ) SwapWord ( 4, &numsubnodes ); - - for(i=0; inShapes != numshapes) { - msSetError(MS_SHPERR, "The spatial index file %s is corrupt.", "msSearchDiskTree()", filename); - msSHPDiskTreeClose(disktree); - return(NULL); - } - - status = msAllocBitArray(disktree->nShapes); - if(!status) { - msSetError(MS_MEMERR, NULL, "msSearchDiskTree()"); - msSHPDiskTreeClose( disktree ); - return(NULL); - } - - searchDiskTreeNode(disktree, aoi, status); - - msSHPDiskTreeClose( disktree ); - return(status); -} - -treeNodeObj *readTreeNode( SHPTreeHandle disktree ) -{ - int i,res; - ms_int32 offset; - treeNodeObj *node; - - node = (treeNodeObj *) msSmallMalloc(sizeof(treeNodeObj)); - node->ids = NULL; - - res = fread( &offset, 4, 1, disktree->fp ); - if ( !res ) - { - free(node); - return NULL; - } - - if ( disktree->needswap ) SwapWord ( 4, &offset ); - - res = fread( &node->rect, sizeof(rectObj), 1, disktree->fp ); - if ( !res ) - { - free(node); - return NULL; - } - if ( disktree->needswap ) SwapWord ( 8, &node->rect.minx ); - if ( disktree->needswap ) SwapWord ( 8, &node->rect.miny ); - if ( disktree->needswap ) SwapWord ( 8, &node->rect.maxx ); - if ( disktree->needswap ) SwapWord ( 8, &node->rect.maxy ); - - res = fread( &node->numshapes, 4, 1, disktree->fp ); - if ( !res ) - { - free(node); - return NULL; - } - if ( disktree->needswap ) SwapWord ( 4, &node->numshapes ); - if( node->numshapes > 0 ) - node->ids = (ms_int32 *)msSmallMalloc(sizeof(ms_int32)*node->numshapes); - res = fread( node->ids, node->numshapes*4, 1, disktree->fp ); - if ( !res ) - { - free(node->ids); - free(node); - return NULL; - } - for( i=0; i < node->numshapes; i++ ) { - if ( disktree->needswap ) SwapWord ( 4, &node->ids[i] ); - } - - res = fread( &node->numsubnodes, 4, 1, disktree->fp ); - if ( !res ) - { - free(node->ids); - free(node); - return NULL; - } - if ( disktree->needswap ) SwapWord ( 4, &node->numsubnodes ); - - return node; -} - -treeObj *msReadTree(char *filename, int debug) -{ - treeObj *tree=NULL; - SHPTreeHandle disktree; - - disktree = msSHPDiskTreeOpen( filename, debug ); - if(!disktree) { - msSetError(MS_IOERR, NULL, "msReadTree()"); - return(NULL); - } - - tree = (treeObj *) malloc(sizeof(treeObj)); - MS_CHECK_ALLOC(tree, sizeof(treeObj), NULL); - - tree->numshapes = disktree->nShapes; - tree->maxdepth = disktree->nDepth; - - tree->root = readTreeNode( disktree ); - - return(tree); -} - -static ms_int32 getSubNodeOffset(treeNodeObj *node) -{ - int i; - ms_int32 offset=0; - - for(i=0; inumsubnodes; i++ ) { - if(node->subnode[i]) { - offset += sizeof(rectObj) + (node->subnode[i]->numshapes+3)*sizeof(int); - offset += getSubNodeOffset(node->subnode[i]); - } - } - - /* offset is the disk offset in the index file on disk */ - /* that format is (per node) */ - /* int offset 4 bytes */ - /* rectObj rect 4 * 8 bytes */ - /* int numShapes 4 bytes */ - /* int ids[numShapes] 4 * numShapes bytes */ - /* int numSubNodes 4 bytes */ - /* */ - - return(offset); -} - - -static void writeTreeNode(SHPTreeHandle disktree, treeNodeObj *node) -{ - int i,j; - ms_int32 offset; - char *pabyRec = NULL; - - offset = getSubNodeOffset(node); - - pabyRec = msSmallMalloc(sizeof(rectObj) + (3 * sizeof(ms_int32)) + (node->numshapes * sizeof(ms_int32)) ); - - memcpy( pabyRec, &offset, 4); - if( disktree->needswap ) SwapWord( 4, pabyRec ); - - memcpy( pabyRec+4, &node->rect, sizeof(rectObj)); - for (i=0; i < 4; i++) - if( disktree->needswap ) SwapWord( 8, pabyRec+4+(8*i) ); - - memcpy( pabyRec+36, &node->numshapes, 4); - if( disktree->needswap ) SwapWord( 4, pabyRec+36 ); - - j = node->numshapes*sizeof(ms_int32); - memcpy( pabyRec+40, node->ids, j); - for (i=0; inumshapes; i++) - if( disktree->needswap ) SwapWord( 4, pabyRec+40+(4*i)); - - memcpy( pabyRec+j+40, &node->numsubnodes, 4); - if( disktree->needswap ) SwapWord( 4, pabyRec+40+j ); - - fwrite( pabyRec, 44+j, 1, disktree->fp); - free (pabyRec); - - for(i=0; inumsubnodes; i++ ) { - if(node->subnode[i]) - writeTreeNode(disktree, node->subnode[i]); - } - - - return; - -} - -int msWriteTree(treeObj *tree, char *filename, int B_order) -{ - char signature[3] = "SQT"; - char version = 1; - char reserved[3] = {0,0,0}; - SHPTreeHandle disktree; - int i; - char mtBigEndian; - char pabyBuf[32]; - char *pszBasename, *pszFullname; - - - disktree = (SHPTreeHandle) malloc(sizeof(SHPTreeInfo)); - MS_CHECK_ALLOC(disktree, sizeof(SHPTreeInfo), MS_FALSE); - - /* -------------------------------------------------------------------- */ - /* Compute the base (layer) name. If there is any extension */ - /* on the passed in filename we will strip it off. */ - /* -------------------------------------------------------------------- */ - pszBasename = (char *) msSmallMalloc(strlen(filename)+5); - strcpy( pszBasename, filename ); - for( i = strlen(pszBasename)-1; - i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/' - && pszBasename[i] != '\\'; - i-- ) {} - - if( pszBasename[i] == '.' ) - pszBasename[i] = '\0'; - - /* -------------------------------------------------------------------- */ - /* Open the .shp and .shx files. Note that files pulled from */ - /* a PC to Unix with upper case filenames won't work! */ - /* -------------------------------------------------------------------- */ - pszFullname = (char *) msSmallMalloc(strlen(pszBasename) + 5); - sprintf( pszFullname, "%s%s", pszBasename, MS_INDEX_EXTENSION); - disktree->fp = fopen(pszFullname, "wb"); - - msFree(pszBasename); /* not needed */ - msFree(pszFullname); - - if(!disktree->fp) { - msFree(disktree); - msSetError(MS_IOERR, NULL, "msWriteTree()"); - return(MS_FALSE); - } - - - /* for efficiency, trim the tree */ - msTreeTrim(tree); - - /* -------------------------------------------------------------------- */ - /* Establish the byte order on this machine. */ - /* -------------------------------------------------------------------- */ - i = 1; - if( *((uchar *) &i) == 1 ) - mtBigEndian = MS_FALSE; - else - mtBigEndian = MS_TRUE; - - if( !(mtBigEndian ^ ( B_order == MS_LSB_ORDER || B_order == MS_NEW_LSB_ORDER )) ) - disktree->needswap = 1; - else - disktree->needswap = 0; - - if( B_order == MS_NATIVE_ORDER ) - disktree->needswap = 0; - - /* write the header */ - if ( B_order > 0 ) { - memcpy( pabyBuf, &signature, 3 ); - memcpy (&disktree->signature, &signature, 3); - pabyBuf[3] = B_order; - - memcpy( pabyBuf+4, &version, 1); - memcpy( pabyBuf+5, &reserved, 3); - - memcpy( &disktree->version, &version, 1); - memcpy( &disktree->flags, &reserved, 3); - - fwrite( pabyBuf, 8, 1, disktree->fp ); - } - - memcpy( pabyBuf, &tree->numshapes, 4 ); - if( disktree->needswap ) SwapWord( 4, pabyBuf ); - - memcpy( pabyBuf+4, &tree->maxdepth, 4 ); - if( disktree->needswap ) SwapWord( 4, pabyBuf+4 ); - - i = fwrite( pabyBuf, 8, 1, disktree->fp ); - if( !i ) { - fprintf (stderr, "unable to write to index file ... exiting \n"); - msSHPDiskTreeClose( disktree ); - return (MS_FALSE); - } - - writeTreeNode(disktree, tree->root); - - msSHPDiskTreeClose( disktree ); - - return(MS_TRUE); -} - -/* Function to filter search results further against feature bboxes */ -void msFilterTreeSearch(shapefileObj *shp, ms_bitarray status, rectObj search_rect) -{ - int i; - rectObj shape_rect; - - i = msGetNextBit(status, 0, shp->numshapes); - while(i >= 0) { - if(msSHPReadBounds(shp->hSHP, i, &shape_rect) == MS_SUCCESS) { - if(msRectOverlap(&shape_rect, &search_rect) != MS_TRUE) { - msSetBit(status, i, 0); - } - } - i = msGetNextBit(status, i+1, shp->numshapes); - } - -} diff --git a/maptree.h b/maptree.h deleted file mode 100644 index 61bf52f04f..0000000000 --- a/maptree.h +++ /dev/null @@ -1,99 +0,0 @@ -/****************************************************************************** - * $Id$ - * - * Project: MapServer - * Purpose: .qix spatial index declarations. - * Author: Steve Lime and the MapServer team. - * - ****************************************************************************** - * Copyright (c) 1996-2005 Regents of the University of Minnesota. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies of this Software or works derived from this Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - ****************************************************************************/ - -#ifndef MAPTREE_H -#define MAPTREE_H - -#ifdef __cplusplus -extern "C" { -#endif - - /* this can be 2 or 4 for binary or quad tree */ -#define MAX_SUBNODES 4 - - typedef struct shape_tree_node { - /* area covered by this node */ - rectObj rect; - - /* list of shapes stored at this node. */ - ms_int32 numshapes; - ms_int32 *ids; - - int numsubnodes; - struct shape_tree_node *subnode[MAX_SUBNODES]; - } treeNodeObj; - - typedef struct { - ms_int32 numshapes; - ms_int32 maxdepth; - treeNodeObj *root; - } treeObj; - - - typedef struct { - FILE *fp; - char signature[3]; - char LSB_order; - char needswap; - char version; - char flags[3]; - - ms_int32 nShapes; - ms_int32 nDepth; - } SHPTreeInfo; - typedef SHPTreeInfo * SHPTreeHandle; - -#define MS_LSB_ORDER -1 -#define MS_MSB_ORDER -2 -#define MS_NATIVE_ORDER 0 -#define MS_NEW_LSB_ORDER 1 -#define MS_NEW_MSB_ORDER 2 - - - MS_DLL_EXPORT SHPTreeHandle msSHPDiskTreeOpen(const char * pszTree, int debug); - MS_DLL_EXPORT void msSHPDiskTreeClose(SHPTreeHandle disktree); - MS_DLL_EXPORT treeNodeObj *readTreeNode( SHPTreeHandle disktree ); - - MS_DLL_EXPORT treeObj *msCreateTree(shapefileObj *shapefile, int maxdepth); - MS_DLL_EXPORT void msTreeTrim(treeObj *tree); - MS_DLL_EXPORT void msDestroyTree(treeObj *tree); - - MS_DLL_EXPORT ms_bitarray msSearchTree(const treeObj *tree, rectObj aoi); - MS_DLL_EXPORT ms_bitarray msSearchDiskTree(const char *filename, rectObj aoi, int debug, int numshapes); - - MS_DLL_EXPORT treeObj *msReadTree(char *filename, int debug); - MS_DLL_EXPORT int msWriteTree(treeObj *tree, char *filename, int LSB_order); - - MS_DLL_EXPORT void msFilterTreeSearch(shapefileObj *shp, ms_bitarray status, rectObj search_rect); - -#ifdef __cplusplus -} -#endif - -#endif /* MAPTREE_H */ diff --git a/mapunion.c b/mapunion.c deleted file mode 100644 index ddd4a86fd6..0000000000 --- a/mapunion.c +++ /dev/null @@ -1,753 +0,0 @@ -/****************************************************************************** - * $Id$ - * - * Project: MapServer - * Purpose: Implementation of the union layer data provider (RFC-68). - * Author: Tamas Szekeres (szekerest@gmail.com). - * - ****************************************************************************** - * Copyright (c) 1996-2005 Regents of the University of Minnesota. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies of this Software or works derived from this Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - ****************************************************************************/ - -#define _CRT_SECURE_NO_WARNINGS 1 - -/* $Id$ */ -#include -#include "mapserver.h" - - - -#define MSUNION_NUMITEMS 3 -#define MSUNION_SOURCELAYERNAME "Union_SourceLayerName" -#define MSUNION_SOURCELAYERNAMEINDEX -100 -#define MSUNION_SOURCELAYERGROUP "Union_SourceLayerGroup" -#define MSUNION_SOURCELAYERGROUPINDEX -101 -#define MSUNION_SOURCELAYERVISIBLE "Union_SourceLayerVisible" -#define MSUNION_SOURCELAYERVISIBLEINDEX -102 - -typedef struct { - int layerIndex; /* current source layer index */ - int classIndex; /* current class index */ - char* classText; /* current class text (autostyle) */ - int layerCount; /* number of the source layers */ - layerObj* layers; /* structure to the source layers */ - int *status; /* the layer status */ - int *classgroup; /* current array of the valid classes */ - int nclasses; /* number of the valid classes */ - reprojectionObj* reprojectorSrcLayerToLayer; - int reprojectorCurSrcLayer; -} msUnionLayerInfo; - -/* Close the the combined layer */ -int msUnionLayerClose(layerObj *layer) -{ - int i; - msUnionLayerInfo* layerinfo = (msUnionLayerInfo*)layer->layerinfo; - - if (!layerinfo) - return MS_SUCCESS; - - if (!layer->map) - return MS_FAILURE; - - msProjectDestroyReprojector(layerinfo->reprojectorSrcLayerToLayer); - for (i = 0; i < layerinfo->layerCount; i++) { - msLayerClose(&layerinfo->layers[i]); - freeLayer(&layerinfo->layers[i]); - } - msFree(layerinfo->layers); - msFree(layerinfo->status); - msFree(layerinfo->classgroup); - msFree(layerinfo->classText); - msFree(layerinfo); - layer->layerinfo = NULL; - - return MS_SUCCESS; -} - -int isScaleInRange(mapObj* map, layerObj *layer) -{ - if(map->scaledenom > 0) { - int i; - /* layer scale boundaries should be checked first */ - if((layer->maxscaledenom > 0) && (map->scaledenom > layer->maxscaledenom)) - return MS_FALSE; - - if((layer->minscaledenom > 0) && (map->scaledenom <= layer->minscaledenom)) - return MS_FALSE; - - /* now check class scale boundaries (all layers *must* pass these tests) */ - if(layer->numclasses > 0) { - for(i=0; inumclasses; i++) { - if((layer->class[i]->maxscaledenom > 0) && (map->scaledenom > layer->class[i]->maxscaledenom)) - continue; /* can skip this one, next class */ - if((layer->class[i]->minscaledenom > 0) && (map->scaledenom <= layer->class[i]->minscaledenom)) - continue; /* can skip this one, next class */ - - break; /* can't skip this class (or layer for that matter) */ - } - if(i == layer->numclasses) - return MS_FALSE; - - } - - if (layer->maxscaledenom <= 0 && layer->minscaledenom <= 0) { - if((layer->maxgeowidth > 0) && ((map->extent.maxx - map->extent.minx) > layer->maxgeowidth)) - return MS_FALSE; - - if((layer->mingeowidth > 0) && ((map->extent.maxx - map->extent.minx) < layer->mingeowidth)) - return MS_FALSE; - } - } - return MS_TRUE; -} - -int msUnionLayerOpen(layerObj *layer) -{ - msUnionLayerInfo *layerinfo; - char **layerNames; - mapObj* map; - int i; - int layerCount; - const char* pkey; - int status_check; - int scale_check; - - if (layer->layerinfo != NULL) { - return MS_SUCCESS; /* Nothing to do... layer is already opened */ - } - - if (!layer->connection) { - msSetError(MS_MISCERR, "The CONNECTION option is not specified for layer: %s", "msUnionLayerOpen()", layer->name); - return MS_FAILURE; - } - - if (!layer->map) { - msSetError(MS_MISCERR, "No map assigned to this layer: %s", "msUnionLayerOpen()", layer->name); - return MS_FAILURE; - } - - map = layer->map; - - layerinfo =(msUnionLayerInfo*)calloc(1, sizeof(msUnionLayerInfo)); - MS_CHECK_ALLOC(layerinfo, sizeof(msUnionLayerInfo), MS_FAILURE); - - layer->layerinfo = layerinfo; - layerinfo->layerIndex = 0; - - layerinfo->classgroup = NULL; - layerinfo->nclasses = 0; - - layerinfo->layerCount = 0; - - layerinfo->classText = NULL; - layerinfo->reprojectorCurSrcLayer = -1; - - pkey = msLayerGetProcessingKey(layer, "UNION_STATUS_CHECK"); - if(pkey && strcasecmp(pkey, "true") == 0) - status_check = MS_TRUE; - else - status_check = MS_FALSE; - - pkey = msLayerGetProcessingKey(layer, "UNION_SCALE_CHECK"); - if(pkey && strcasecmp(pkey, "false") == 0) - scale_check = MS_FALSE; - else - scale_check = MS_TRUE; - - pkey = msLayerGetProcessingKey(layer, "UNION_SRCLAYER_CLOSE_CONNECTION"); - - layerNames = msStringSplit(layer->connection, ',', &layerCount); - - if (layerCount == 0) { - msSetError(MS_MISCERR, "No source layers specified in layer: %s", "msUnionLayerOpen()", layer->name); - if(layerNames) - msFreeCharArray(layerNames, layerinfo->layerCount); - msUnionLayerClose(layer); - return MS_FAILURE; - } - - layerinfo->layers =(layerObj*)malloc(layerCount * sizeof(layerObj)); - MS_CHECK_ALLOC(layerinfo->layers, layerCount * sizeof(layerObj), MS_FAILURE); - - layerinfo->status =(int*)malloc(layerCount * sizeof(int)); - MS_CHECK_ALLOC(layerinfo->status, layerCount * sizeof(int), MS_FAILURE); - - for(i=0; i < layerCount; i++) { - int layerindex = msGetLayerIndex(map, layerNames[i]); - if (layerindex >= 0 && layerindex < map->numlayers) { - layerObj* srclayer = map->layers[layerindex]; - - if (srclayer->type != layer->type) { - msSetError(MS_MISCERR, "The type of the source layer doesn't match with the union layer: %s", "msUnionLayerOpen()", srclayer->name); - if(layerNames) - msFreeCharArray(layerNames, layerinfo->layerCount); - msUnionLayerClose(layer); - return MS_FAILURE; - } - - /* we need to create a new layer in order make the singlepass query to work */ - if(initLayer(&layerinfo->layers[i], map) == -1) { - msSetError(MS_MISCERR, "Cannot initialize source layer: %s", "msUnionLayerOpen()", srclayer->name); - if(layerNames) - msFreeCharArray(layerNames, layerinfo->layerCount); - msUnionLayerClose(layer); - return MS_FAILURE; - } - - ++layerinfo->layerCount; - - if (msCopyLayer(&layerinfo->layers[i], srclayer) != MS_SUCCESS) { - msSetError(MS_MISCERR, "Cannot copy source layer: %s", "msUnionLayerOpen()", srclayer->name); - if(layerNames) - msFreeCharArray(layerNames, layerinfo->layerCount); - msUnionLayerClose(layer); - return MS_FAILURE; - } - - if (pkey) { - /* override connection flag */ - msLayerSetProcessingKey(&layerinfo->layers[i], "CLOSE_CONNECTION", pkey); - } - - /* check is we should skip this source (status check) */ - if (status_check && layerinfo->layers[i].status == MS_OFF) { - layerinfo->status[i] = MS_DONE; - continue; - } - - /* check is we should skip this source (scale check) */ - if (scale_check && isScaleInRange(map, &layerinfo->layers[i]) == MS_FALSE) { - layerinfo->status[i] = MS_DONE; - continue; - } - - layerinfo->status[i] = msLayerOpen(&layerinfo->layers[i]); - if (layerinfo->status[i] != MS_SUCCESS) { - if(layerNames) - msFreeCharArray(layerNames, layerinfo->layerCount); - msUnionLayerClose(layer); - return MS_FAILURE; - } - } else { - msSetError(MS_MISCERR, "Invalid layer: %s", "msUnionLayerOpen()", layerNames[i]); - if(layerNames) - msFreeCharArray(layerNames, layerinfo->layerCount); - msUnionLayerClose(layer); - return MS_FAILURE; - } - } - - if(layerNames) - msFreeCharArray(layerNames, layerinfo->layerCount); - - return MS_SUCCESS; -} - -/* Return MS_TRUE if layer is open, MS_FALSE otherwise. */ -int msUnionLayerIsOpen(layerObj *layer) -{ - if (layer->layerinfo) - return(MS_TRUE); - else - return(MS_FALSE); -} - -/* Free the itemindexes array in a layer. */ -void msUnionLayerFreeItemInfo(layerObj *layer) -{ - int i; - msUnionLayerInfo* layerinfo = (msUnionLayerInfo*)layer->layerinfo; - - if (!layerinfo || !layer->map) - return; - - msFree(layer->iteminfo); - - layer->iteminfo = NULL; - - for (i = 0; i < layerinfo->layerCount; i++) { - msLayerFreeItemInfo(&layerinfo->layers[i]); - if(layerinfo->layers[i].items) { - /* need to remove the source layer items */ - msFreeCharArray(layerinfo->layers[i].items, layerinfo->layers[i].numitems); - layerinfo->layers[i].items = NULL; - layerinfo->layers[i].numitems = 0; - } - } -} - -/* clean up expression tokens */ -void msUnionLayerFreeExpressionTokens(layerObj *layer) -{ - int i,j; - msFreeExpressionTokens(&(layer->filter)); - msFreeExpressionTokens(&(layer->cluster.group)); - msFreeExpressionTokens(&(layer->cluster.filter)); - for(i=0; inumclasses; i++) { - msFreeExpressionTokens(&(layer->class[i]->expression)); - msFreeExpressionTokens(&(layer->class[i]->text)); - for(j=0; jclass[i]->numstyles; j++) - msFreeExpressionTokens(&(layer->class[i]->styles[j]->_geomtransform)); - } -} - -/* allocate the iteminfo index array - same order as the item list */ -int msUnionLayerInitItemInfo(layerObj *layer) -{ - int i, numitems; - int *itemindexes; - char* itemlist = NULL; - - msUnionLayerInfo* layerinfo = (msUnionLayerInfo*)layer->layerinfo; - - if(layer->numitems == 0) { - return MS_SUCCESS; - } - - if (!layerinfo || !layer->map) - return MS_FAILURE; - - /* Cleanup any previous item selection */ - msUnionLayerFreeItemInfo(layer); - - layer->iteminfo = (int *) malloc(sizeof(int) * layer->numitems); - MS_CHECK_ALLOC(layer->iteminfo, sizeof(int) * layer->numitems, MS_FAILURE); - - itemindexes = (int*)layer->iteminfo; - - /* check whether we require attributes from the source layers also */ - numitems = 0; - for (i = 0; i < layer->numitems; i++) { - if (EQUAL(layer->items[i], MSUNION_SOURCELAYERNAME)) - itemindexes[i] = MSUNION_SOURCELAYERNAMEINDEX; - else if (EQUAL(layer->items[i], MSUNION_SOURCELAYERGROUP)) - itemindexes[i] = MSUNION_SOURCELAYERGROUPINDEX; - else if (EQUAL(layer->items[i], MSUNION_SOURCELAYERVISIBLE)) - itemindexes[i] = MSUNION_SOURCELAYERVISIBLEINDEX; - else { - itemindexes[i] = numitems++; - if (itemlist) { - itemlist = msStringConcatenate(itemlist, ","); - itemlist = msStringConcatenate(itemlist, layer->items[i]); - } else { - itemlist = msStrdup(layer->items[i]); - } - } - } - - for (i = 0; i < layerinfo->layerCount; i++) { - layerObj* srclayer = &layerinfo->layers[i]; - - if (layerinfo->status[i] != MS_SUCCESS) - continue; /* skip empty layers */ - - msUnionLayerFreeExpressionTokens(srclayer); - - if (itemlist) { - /* get items requested by the union layer plus the required items */ - msLayerSetProcessingKey(srclayer, "ITEMS", itemlist); - if (msLayerWhichItems(srclayer, MS_TRUE, NULL) != MS_SUCCESS) { - msFree(itemlist); - return MS_FAILURE; - } - } else { - /* get only the required items */ - if (msLayerWhichItems(srclayer, MS_FALSE, NULL) != MS_SUCCESS) - return MS_FAILURE; - } - } - - msFree(itemlist); - return MS_SUCCESS; -} - -int msUnionLayerWhichShapes(layerObj *layer, rectObj rect, int isQuery) -{ - int i; - layerObj* srclayer; - rectObj srcRect; - msUnionLayerInfo* layerinfo = (msUnionLayerInfo*)layer->layerinfo; - - if (!layerinfo || !layer->map) - return MS_FAILURE; - - for (i = 0; i < layerinfo->layerCount; i++) { - layerObj* srclayer = &layerinfo->layers[i]; - - if (layerinfo->status[i] != MS_SUCCESS) - continue; /* skip empty layers */ - - if (layer->styleitem && layer->numitems == 0) { - /* need to initialize items */ - msUnionLayerFreeExpressionTokens(srclayer); - - /* get only the required items */ - if (msLayerWhichItems(srclayer, MS_FALSE, NULL) != MS_SUCCESS) - return MS_FAILURE; - } - - srcRect = rect; - - if(srclayer->transform == MS_TRUE && srclayer->project && layer->transform == MS_TRUE && layer->project &&msProjectionsDiffer(&(srclayer->projection), &(layer->projection))) - msProjectRect(&layer->projection, &srclayer->projection, &srcRect); /* project the searchrect to source coords */ - - layerinfo->status[i] = msLayerWhichShapes(srclayer, srcRect, isQuery); - if (layerinfo->status[i] == MS_FAILURE) - return MS_FAILURE; - } - - layerinfo->layerIndex = 0; - srclayer = &layerinfo->layers[0]; - - msFree(layerinfo->classgroup); - - layerinfo->classgroup = NULL; - layerinfo->nclasses = 0; - - if (srclayer->classgroup && srclayer->numclasses > 0) - layerinfo->classgroup = msAllocateValidClassGroups(srclayer, &layerinfo->nclasses); - - return MS_SUCCESS; -} - -static int BuildFeatureAttributes(layerObj *layer, layerObj* srclayer, shapeObj *shape) -{ - int i; - char **values; - int* itemindexes = layer->iteminfo; - - values = malloc(sizeof(char*) * (layer->numitems)); - MS_CHECK_ALLOC(values, layer->numitems * sizeof(char*), MS_FAILURE);; - - for (i = 0; i < layer->numitems; i++) { - if (itemindexes[i] == MSUNION_SOURCELAYERNAMEINDEX) - values[i] = msStrdup(srclayer->name); - else if (itemindexes[i] == MSUNION_SOURCELAYERGROUPINDEX) - values[i] = msStrdup(srclayer->group); - else if (itemindexes[i] == MSUNION_SOURCELAYERVISIBLEINDEX) { - if (srclayer->status == MS_OFF) - values[i] = msStrdup("0"); - else - values[i] = msStrdup("1"); - } else if (shape->values[itemindexes[i]]) - values[i] = msStrdup(shape->values[itemindexes[i]]); - else - values[i] = msStrdup(""); - } - - if (shape->values) - msFreeCharArray(shape->values, shape->numvalues); - - shape->values = values; - shape->numvalues = layer->numitems; - - return MS_SUCCESS; -} - -/* find the next shape with the appropriate shape type */ -/* also, load in the attribute data */ -/* MS_DONE => no more data */ -int msUnionLayerNextShape(layerObj *layer, shapeObj *shape) -{ - int rv; - layerObj* srclayer; - msUnionLayerInfo* layerinfo = (msUnionLayerInfo*)layer->layerinfo; - - if (!layerinfo || !layer->map) - return MS_FAILURE; - - if (layerinfo->layerIndex < 0 || layerinfo->layerIndex >= layerinfo->layerCount) - return MS_FAILURE; - - rv = MS_DONE; - - while (layerinfo->layerIndex < layerinfo->layerCount) { - srclayer = &layerinfo->layers[layerinfo->layerIndex]; - if (layerinfo->status[layerinfo->layerIndex] == MS_SUCCESS) { - while ((rv = srclayer->vtable->LayerNextShape(srclayer, shape)) == MS_SUCCESS) { - if(layer->styleitem) { - /* need to retrieve the source layer classindex if styleitem AUTO is set */ - layerinfo->classIndex = msShapeGetClass(srclayer, layer->map, shape, layerinfo->classgroup, layerinfo->nclasses); - if(layerinfo->classIndex < 0 || layerinfo->classIndex >= srclayer->numclasses) { - /* this shape is not visible, skip it */ - msFreeShape(shape); - if (rv == MS_SUCCESS) - continue; - else - break; - } - if(srclayer->styleitem && strcasecmp(srclayer->styleitem, "AUTO") != 0) { - /* Generic feature style handling as per RFC-61 */ - msLayerGetFeatureStyle(layer->map, srclayer, srclayer->class[layerinfo->classIndex], shape); - } - /* set up annotation */ - msFree(layerinfo->classText); - layerinfo->classText = NULL; - if(srclayer->class[layerinfo->classIndex]->numlabels > 0) { - /* pull text from the first label only */ - if(msGetLabelStatus(layer->map,layer,shape,srclayer->class[layerinfo->classIndex]->labels[0]) == MS_ON) { - layerinfo->classText = msShapeGetLabelAnnotation(layer,shape,srclayer->class[layerinfo->classIndex]->labels[0]); - } - } - } - - /* reproject to the target layer */ - if( layerinfo->reprojectorCurSrcLayer != layerinfo->layerIndex ) - { - msProjectDestroyReprojector(layerinfo->reprojectorSrcLayerToLayer); - layerinfo->reprojectorSrcLayerToLayer = NULL; - layerinfo->reprojectorCurSrcLayer = layerinfo->layerIndex; - if(srclayer->project && msProjectionsDiffer(&(srclayer->projection), &(layer->projection))) - layerinfo->reprojectorSrcLayerToLayer = msProjectCreateReprojector(&(srclayer->projection), &(layer->projection)); - else - srclayer->project = MS_FALSE; - } - if(layerinfo->reprojectorSrcLayerToLayer) - msProjectShapeEx(layerinfo->reprojectorSrcLayerToLayer, shape); - - /* update the layer styles with the bound values */ - if(msBindLayerToShape(srclayer, shape, MS_FALSE) != MS_SUCCESS) - return MS_FAILURE; - - shape->tileindex = layerinfo->layerIndex; - - /* construct the item array */ - if (layer->iteminfo) - rv = BuildFeatureAttributes(layer, srclayer, shape); - - /* check the layer filter condition */ - if(layer->filter.string != NULL && layer->numitems > 0 && layer->iteminfo) { - if (layer->filter.type == MS_EXPRESSION && layer->filter.tokens == NULL) - msTokenizeExpression(&(layer->filter), layer->items, &(layer->numitems)); - - if (!msEvalExpression(layer, shape, &(layer->filter), layer->filteritemindex)) { - /* this shape is filtered */ - msFreeShape(shape); - continue; - } - } - - return rv; - } - } - - ++layerinfo->layerIndex; - if (layerinfo->layerIndex == layerinfo->layerCount) { - layerinfo->layerIndex = 0; - return MS_DONE; - } - - /* allocate the classgroups for the next layer */ - msFree(layerinfo->classgroup); - - layerinfo->classgroup = NULL; - layerinfo->nclasses = 0; - - if (srclayer->classgroup && srclayer->numclasses > 0) - layerinfo->classgroup = msAllocateValidClassGroups(srclayer, &layerinfo->nclasses); - } - - return rv; -} - -/* Random access of the feature. */ -int msUnionLayerGetShape(layerObj *layer, shapeObj *shape, resultObj *record) -{ - int rv; - layerObj* srclayer; - long tile = record->tileindex; - msUnionLayerInfo* layerinfo = (msUnionLayerInfo*)layer->layerinfo; - - if (!layerinfo || !layer->map) - return MS_FAILURE; - - if (tile < 0 || tile >= layerinfo->layerCount) { - msSetError(MS_MISCERR, "Invalid tile index: %s", "msUnionLayerGetShape()", layer->name); - return MS_FAILURE; - } - - srclayer = &layerinfo->layers[tile]; - record->tileindex = 0; - rv = srclayer->vtable->LayerGetShape(srclayer, shape, record); - record->tileindex = tile; - - if (rv == MS_SUCCESS) { - /* reproject to the target layer */ - if( layerinfo->reprojectorCurSrcLayer != tile ) - { - msProjectDestroyReprojector(layerinfo->reprojectorSrcLayerToLayer); - layerinfo->reprojectorSrcLayerToLayer = NULL; - layerinfo->reprojectorCurSrcLayer = tile; - if(srclayer->project && msProjectionsDiffer(&(srclayer->projection), &(layer->projection))) - layerinfo->reprojectorSrcLayerToLayer = msProjectCreateReprojector(&(srclayer->projection), &(layer->projection)); - else - srclayer->project = MS_FALSE; - } - if(layerinfo->reprojectorSrcLayerToLayer) - msProjectShapeEx(layerinfo->reprojectorSrcLayerToLayer, shape); - - shape->tileindex = tile; - - /* construct the item array */ - if (layer->iteminfo) - rv = BuildFeatureAttributes(layer, srclayer, shape); - } - - return rv; -} - -/* Query for the items collection */ -int msUnionLayerGetItems(layerObj *layer) -{ - /* we support certain built in attributes */ - layer->numitems = 2; - layer->items = malloc(sizeof(char*) * (layer->numitems)); - MS_CHECK_ALLOC(layer->items, layer->numitems * sizeof(char*), MS_FAILURE); - layer->items[0] = msStrdup(MSUNION_SOURCELAYERNAME); - layer->items[1] = msStrdup(MSUNION_SOURCELAYERGROUP); - - return msUnionLayerInitItemInfo(layer); -} - -int msUnionLayerGetNumFeatures(layerObj *layer) -{ - int i, c, numFeatures; - msUnionLayerInfo* layerinfo = (msUnionLayerInfo*)layer->layerinfo; - - if (!layerinfo || !layer->map) - return 0; - - numFeatures = 0; - - for (i = 0; i < layerinfo->layerCount; i++) { - if (layerinfo->status[i] != MS_SUCCESS) - continue; /* skip empty layers */ - - c = msLayerGetNumFeatures(&layerinfo->layers[i]); - if (c > 0) - numFeatures += c; - } - - return numFeatures; -} - -static int msUnionLayerGetAutoStyle(mapObj *map, layerObj *layer, classObj *c, shapeObj* shape) -{ - layerObj* srclayer; - msUnionLayerInfo* layerinfo = (msUnionLayerInfo*)layer->layerinfo; - - if (!layerinfo || !layer->map) - return MS_FAILURE; - - if (shape->tileindex < 0 || shape->tileindex >= layerinfo->layerCount) { - msSetError(MS_MISCERR, "Invalid tile index: %s", "msUnionLayerGetAutoStyle()", layer->name); - return MS_FAILURE; - } - - srclayer = &layerinfo->layers[shape->tileindex]; - - if(srclayer->styleitem && strcasecmp(srclayer->styleitem, "AUTO") == 0) { - int rv; - int tileindex = shape->tileindex; - shape->tileindex = 0; - rv = msLayerGetAutoStyle(map, srclayer, c, shape); - shape->tileindex = tileindex; - return rv; - } else { - int i,j; - classObj* src = srclayer->class[layerinfo->classIndex]; - /* copy the style from the current class index */ - /* free any previous styles on the dst layer */ - - resetClassStyle(c); - - for (i = 0; i < src->numstyles; i++) { - if (msMaybeAllocateClassStyle(c, i)) - return MS_FAILURE; - - if (msCopyStyle(c->styles[i], src->styles[i]) != MS_SUCCESS) { - msSetError(MS_MEMERR, "Failed to copy style.", "msUnionLayerGetAutoStyle()"); - return MS_FAILURE; - } - /* remove the bindings on the style */ - for(j=0; jstyles[i]->bindings[j].item); - c->styles[i]->bindings[j].item = NULL; - } - c->styles[i]->numbindings = 0; - } - - for (i = 0; i < src->numlabels; i++) { - // RFC77 TODO: allocation need to be done, but is the right way (from mapcopy.c)? - if (msGrowClassLabels(c) == NULL) - return MS_FAILURE; - initLabel(c->labels[i]); - - if (msCopyLabel(c->labels[i], src->labels[i]) != MS_SUCCESS) { - msSetError(MS_MEMERR, "Failed to copy label.", "msUnionLayerGetAutoStyle()"); - return MS_FAILURE; - } - - /* remove the bindings on the label */ - for(j=0; jlabels[i]->bindings[j].item); - c->labels[i]->bindings[j].item = NULL; - } - c->labels[i]->numbindings = 0; - } - c->numlabels = src->numlabels; - - c->layer = layer; - c->text.string = layerinfo->classText; - layerinfo->classText = NULL; - } - return MS_SUCCESS; -} - -int msUnionLayerCopyVirtualTable(layerVTableObj* vtable) -{ - vtable->LayerInitItemInfo = msUnionLayerInitItemInfo; - vtable->LayerFreeItemInfo = msUnionLayerFreeItemInfo; - vtable->LayerOpen = msUnionLayerOpen; - vtable->LayerIsOpen = msUnionLayerIsOpen; - vtable->LayerWhichShapes = msUnionLayerWhichShapes; - vtable->LayerNextShape = msUnionLayerNextShape; - vtable->LayerGetShape = msUnionLayerGetShape; - /* layer->vtable->LayerGetShapeCount, use default */ - vtable->LayerClose = msUnionLayerClose; - - vtable->LayerGetItems = msUnionLayerGetItems; - vtable->LayerCloseConnection = msUnionLayerClose; - vtable->LayerGetAutoStyle = msUnionLayerGetAutoStyle; - - vtable->LayerGetNumFeatures = msUnionLayerGetNumFeatures; - - return MS_SUCCESS; -} - -int msUnionLayerInitializeVirtualTable(layerObj *layer) -{ - assert(layer != NULL); - assert(layer->vtable != NULL); - - return msUnionLayerCopyVirtualTable(layer->vtable); -} diff --git a/maputfgrid.cpp b/maputfgrid.cpp deleted file mode 100644 index d6beddda34..0000000000 --- a/maputfgrid.cpp +++ /dev/null @@ -1,861 +0,0 @@ -/****************************************************************************** - * $Id$ - * - * Project: MapServer - * Purpose: UTFGrid rendering functions (using AGG) - * Author: Francois Desjarlais - * - ****************************************************************************** - * Copyright (c) 1996-2007 Regents of the University of Minnesota. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies of this Software or works derived from this Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - *****************************************************************************/ - - -#include "mapserver.h" -#include "maputfgrid.h" -#include "mapagg.h" -#include "renderers/agg/include/agg_rasterizer_scanline_aa.h" -#include "renderers/agg/include/agg_basics.h" -#include "renderers/agg/include/agg_renderer_scanline.h" -#include "renderers/agg/include/agg_scanline_bin.h" -#include "renderers/agg/include/agg_gamma_functions.h" -#include "renderers/agg/include/agg_conv_stroke.h" -#include "renderers/agg/include/agg_ellipse.h" - -typedef mapserver::int32u band_type; -typedef mapserver::row_ptr_cache rendering_buffer; -typedef pixfmt_utf pixfmt_utf32; -typedef mapserver::renderer_base renderer_base; -typedef mapserver::rasterizer_scanline_aa<> rasterizer_scanline; -typedef mapserver::renderer_scanline_bin_solid renderer_scanline; - -static utfpix32 UTF_WATER = utfpix32(32); - -#define utfitem(c) utfpix32(c) - -struct shapeData -{ - char *datavalues; - char *itemvalue; - band_type utfvalue; - int serialid; -}; - -class lookupTable { -public: - lookupTable() - { - table = (shapeData*) msSmallMalloc(sizeof(shapeData)); - table->datavalues = NULL; - table->itemvalue = NULL; - table->utfvalue = 0; - table->serialid = 0; - size = 1; - counter = 0; - } - - ~lookupTable() - { - int i; - - for(i=0; ipoint; - *x = m_point->x/utfresolution; - *y = m_point->y/utfresolution; - m_point++; - return first ? mapserver::path_cmd_move_to : mapserver::path_cmd_line_to; - } - *x = *y = 0.0; - if(!m_stop) { - - m_line++; - if(m_line>=m_lend) { - m_stop=true; - return mapserver::path_cmd_end_poly; - } - - m_point=m_line->point; - m_pend=&(m_line->point[m_line->numpoints]); - return mapserver::path_cmd_end_poly; - } - return mapserver::path_cmd_stop; - } - -private: - int utfresolution; -}; - -/* - * UTFGrid specific line adaptor. - */ -class line_adaptor_utf:public line_adaptor -{ -public: - line_adaptor_utf(shapeObj *shape,int utfres_in):line_adaptor(shape) - { - utfresolution = utfres_in; - } - - virtual unsigned vertex(double* x, double* y) - { - if(m_point < m_pend) { - bool first = m_point == m_line->point; - *x = m_point->x/utfresolution; - *y = m_point->y/utfresolution; - m_point++; - return first ? mapserver::path_cmd_move_to : mapserver::path_cmd_line_to; - } - m_line++; - *x = *y = 0.0; - if(m_line>=m_lend) - return mapserver::path_cmd_stop; - - m_point=m_line->point; - m_pend=&(m_line->point[m_line->numpoints]); - - return vertex(x,y); - } - -private: - int utfresolution; -}; - -class UTFGridRenderer { -public: - UTFGridRenderer() - { - stroke = NULL; - } - ~UTFGridRenderer() - { - if(stroke) - delete stroke; - delete data; - } - - lookupTable *data; - int utfresolution; - int layerwatch; - int renderlayer; - int useutfitem; - int useutfdata; - int duplicates; - band_type utfvalue; - layerObj *utflayer; - band_type *buffer; - rendering_buffer m_rendering_buffer; - pixfmt_utf32 m_pixel_format; - renderer_base m_renderer_base; - rasterizer_scanline m_rasterizer; - renderer_scanline m_renderer_scanline; - mapserver::scanline_bin sl_utf; - mapserver::conv_stroke *stroke; -}; - -#define UTFGRID_RENDERER(image) ((UTFGridRenderer*) (image)->img.plugin) - -/* - * Encode to avoid unavailable char in the JSON - */ -unsigned int encodeForRendering(unsigned int toencode) -{ - unsigned int encoded; - encoded = toencode + 32; - /* 34 => " */ - if(encoded >= 34) { - encoded = encoded +1; - } - /* 92 => \ */ - if (encoded >= 92) { - encoded = encoded +1; - } - return encoded; -} - -/* - * Decode value to have the initial one - */ -unsigned int decodeRendered(unsigned int todecode) -{ - unsigned int decoded; - - if(todecode >= 92) - todecode --; - - if(todecode >= 34) - todecode --; - - decoded = todecode-32; - - return decoded; -} - -/* - * Allocate more memory to the table if necessary. - */ -int growTable(lookupTable *data) -{ - int i; - - data->table = (shapeData*) msSmallRealloc(data->table,sizeof(*data->table)*data->size*2); - data->size = data->size*2; - - for(i=data->counter; isize; i++) - { - data->table[i].datavalues = NULL; - data->table[i].itemvalue = NULL; - data->table[i].utfvalue = 0; - data->table[i].serialid = 0; - } - return MS_SUCCESS; -} - -/* - * Add the shapeObj UTFDATA and UTFITEM to the lookup table. - */ -band_type addToTable(UTFGridRenderer *r, shapeObj *p) -{ - band_type utfvalue; - - /* Looks for duplicates. */ - if(r->duplicates==0 && r->useutfitem==1) { - int i; - for(i=0; idata->counter; i++) { - if(!strcmp(p->values[r->utflayer->utfitemindex],r->data->table[i].itemvalue)) { - /* Found a copy of the values in the table. */ - utfvalue = r->data->table[i].utfvalue; - - return utfvalue; - } - } - } - - /* Grow size of table if necessary */ - if(r->data->size == r->data->counter) - growTable(r->data); - - utfvalue = (r->data->counter+1); - - /* Simple operation so we don't have unavailable char in the JSON */ - utfvalue = encodeForRendering(utfvalue); - - /* Data added to the table */ - r->data->table[r->data->counter].datavalues = msEvalTextExpressionJSonEscape(&r->utflayer->utfdata, p); - - /* If UTFITEM is set in the mapfile we add its value to the table */ - if(r->useutfitem) - r->data->table[r->data->counter].itemvalue = msStrdup(p->values[r->utflayer->utfitemindex]); - - r->data->table[r->data->counter].serialid = r->data->counter+1; - - r->data->table[r->data->counter].utfvalue = utfvalue; - - r->data->counter++; - - return utfvalue; -} - -/* - * Use AGG to render any path. - */ -template -int utfgridRenderPath(imageObj *img, vertex_source &path) -{ - UTFGridRenderer *r = UTFGRID_RENDERER(img); - r->m_rasterizer.reset(); - r->m_rasterizer.filling_rule(mapserver::fill_even_odd); - r->m_rasterizer.add_path(path); - r->m_renderer_scanline.color(utfitem(r->utfvalue)); - mapserver::render_scanlines(r->m_rasterizer, r->sl_utf, r->m_renderer_scanline); - return MS_SUCCESS; -} - -/* - * Initialize the renderer, create buffer, allocate memory. - */ -imageObj *utfgridCreateImage(int width, int height, outputFormatObj *format, colorObj * bg) -{ - UTFGridRenderer *r; - r = new UTFGridRenderer; - - r->data = new lookupTable; - - r->utfresolution = atof(msGetOutputFormatOption(format, "UTFRESOLUTION", "4")); - if(r->utfresolution < 1) { - msSetError(MS_MISCERR, "UTFRESOLUTION smaller that 1 in the mapfile.", "utfgridCreateImage()"); - return NULL; - } - - r->layerwatch = 0; - - r->renderlayer = 0; - - r->useutfitem = 0; - - r->useutfdata = 0; - - r->duplicates = EQUAL("true", msGetOutputFormatOption(format, "DUPLICATES", "true")); - - r->utfvalue = 0; - - r->buffer = (band_type*)msSmallMalloc(width/r->utfresolution * height/r->utfresolution * sizeof(band_type)); - - /* AGG specific operations */ - r->m_rendering_buffer.attach(r->buffer, width/r->utfresolution, height/r->utfresolution, width/r->utfresolution); - r->m_pixel_format.attach(r->m_rendering_buffer); - r->m_renderer_base.attach(r->m_pixel_format); - r->m_renderer_scanline.attach(r->m_renderer_base); - r->m_renderer_base.clear(UTF_WATER); - r->m_rasterizer.gamma(mapserver::gamma_none()); - - r->utflayer = NULL; - - imageObj *image = NULL; - image = (imageObj *) msSmallCalloc(1,sizeof(imageObj)); - image->img.plugin = (void*) r; - - return image; -} - -/* - * Free all the memory used by the renderer. - */ -int utfgridFreeImage(imageObj *img) -{ - UTFGridRenderer *r = UTFGRID_RENDERER(img); - - msFree(r->buffer); - delete r; - - img->img.plugin = NULL; - - return MS_SUCCESS; -} - -/* - * Update a character in the utfgrid. -*/ - -int utfgridUpdateChar(imageObj *img, band_type oldChar, band_type newChar) -{ - UTFGridRenderer *r = UTFGRID_RENDERER(img); - int i,bufferLength; - - bufferLength = (img->height/r->utfresolution) * (img->width/r->utfresolution); - - for(i=0;ibuffer[i] == oldChar) - r->buffer[i] = newChar; - } - - return MS_SUCCESS; -} - -/* - * Remove unnecessary data that didn't made it to the final grid. - */ - -int utfgridCleanData(imageObj *img) -{ - UTFGridRenderer *r = UTFGRID_RENDERER(img); - unsigned char* usedChar; - int i,bufferLength,itemFound,dataCounter; - shapeData* updatedData; - band_type utfvalue; - - bufferLength = (img->height/r->utfresolution) * (img->width/r->utfresolution); - - usedChar =(unsigned char*) msSmallMalloc(r->data->counter*sizeof(unsigned char)); - - for(i=0;idata->counter;i++){ - usedChar[i]=0; - } - - itemFound=0; - - for(i=0;ibuffer[i]) != 0 && usedChar[decodeRendered(r->buffer[i])-1]==0) - { - itemFound++; - usedChar[decodeRendered(r->buffer[i])-1] = 1; - } - } - - updatedData = (shapeData*) msSmallMalloc(itemFound * sizeof(shapeData)); - dataCounter = 0; - - for(i=0; i< r->data->counter; i++){ - if(usedChar[decodeRendered(r->data->table[i].utfvalue)-1]==1){ - updatedData[dataCounter] = r->data->table[i]; - - updatedData[dataCounter].serialid=dataCounter+1; - - utfvalue=encodeForRendering(dataCounter+1); - - utfgridUpdateChar(img,updatedData[dataCounter].utfvalue,utfvalue); - updatedData[dataCounter].utfvalue = utfvalue; - - dataCounter++; - } - else { - if(r->data->table[i].datavalues) - msFree(r->data->table[i].datavalues); - if(r->data->table[i].itemvalue) - msFree(r->data->table[i].itemvalue); - } - } - - msFree(usedChar); - - msFree(r->data->table); - - r->data->table = updatedData; - r->data->counter = dataCounter; - r->data->size = dataCounter; - - return MS_SUCCESS; -} - -/* - * Print the renderer data as JSON. - */ -int utfgridSaveImage(imageObj *img, mapObj *map, FILE *fp, outputFormatObj *format) -{ - int row, col, i, imgheight, imgwidth; - band_type pixelid; - char* pszEscaped; - - utfgridCleanData(img); - - UTFGridRenderer *renderer = UTFGRID_RENDERER(img); - - if(renderer->layerwatch>1) - return MS_FAILURE; - - imgheight = img->height/renderer->utfresolution; - imgwidth = img->width/renderer->utfresolution; - - msIO_fprintf(fp,"{\"grid\":["); - - /* Print the buffer */ - for(row=0; rowwidth/renderer->utfresolution; col++) { - /* Get the data from buffer. */ - pixelid = renderer->buffer[(row*imgwidth)+col]; - - *stringptr = pixelid; - stringptr++; - } - - /* Conversion to UTF-8 encoding */ - *stringptr = '\0'; - char * utf8; -#if defined(_WIN32) && !defined(__CYGWIN__) - const char* encoding = "UCS-2LE"; -#else - const char* encoding = "UCS-4LE"; -#endif - - utf8 = msConvertWideStringToUTF8(string, encoding); - msIO_fprintf(fp,"%s", utf8); - msFree(utf8); - msFree(string); - msIO_fprintf(fp,"\""); - } - - msIO_fprintf(fp,"],\"keys\":[\"\""); - - /* Print the specified key */ - for(i=0;idata->counter;i++) { - msIO_fprintf(fp,","); - - if(renderer->useutfitem) - { - pszEscaped = msEscapeJSonString(renderer->data->table[i].itemvalue); - msIO_fprintf(fp,"\"%s\"", pszEscaped); - msFree(pszEscaped); - } - /* If no UTFITEM specified use the serial ID as the key */ - else - msIO_fprintf(fp,"\"%i\"", renderer->data->table[i].serialid); - } - - msIO_fprintf(fp,"],\"data\":{"); - - /* Print the data */ - if(renderer->useutfdata) { - for(i=0;idata->counter;i++) { - if(i!=0) - msIO_fprintf(fp,","); - - if(renderer->useutfitem) - { - pszEscaped = msEscapeJSonString(renderer->data->table[i].itemvalue); - msIO_fprintf(fp,"\"%s\":", pszEscaped); - msFree(pszEscaped); - } - /* If no UTFITEM specified use the serial ID as the key */ - else - msIO_fprintf(fp,"\"%i\":", renderer->data->table[i].serialid); - - msIO_fprintf(fp,"%s", renderer->data->table[i].datavalues); - } - } - msIO_fprintf(fp,"}}"); - - return MS_SUCCESS; -} - -/* - * Starts a layer for UTFGrid renderer. - */ -int utfgridStartLayer(imageObj *img, mapObj *map, layerObj *layer) -{ - UTFGridRenderer *r = UTFGRID_RENDERER(img); - - /* Look if the layer uses the UTFGrid output format */ - if(layer->utfdata.string!=0) { - r->useutfdata = 1; - } - - /* layerwatch is set to 1 on first layer treated. Doesn't allow multiple layers. */ - if(!r->layerwatch) { - r->layerwatch++; - - r->renderlayer = 1; - r->utflayer = layer; - layer->refcount++; - - /* Verify if renderer needs to use UTFITEM */ - if(r->utflayer->utfitem) - r->useutfitem = 1; - } - /* If multiple layers, send error */ - else { - r->layerwatch++; - msSetError(MS_MISCERR, "MapServer does not support multiple UTFGrid layers rendering simultaneously.", "utfgridStartLayer()"); - return MS_FAILURE; - } - - return MS_SUCCESS; -} - -/* - * Tell renderer the layer is done. - */ -int utfgridEndLayer(imageObj *img, mapObj *map, layerObj *layer) -{ - UTFGridRenderer *r = UTFGRID_RENDERER(img); - - /* Look if the layer was rendered, if it was then turn off rendering. */ - if(r->renderlayer) { - r->utflayer = NULL; - layer->refcount--; - r->renderlayer = 0; - } - - return MS_SUCCESS; -} - -/* - * Do the table operations on the shapes. Allow multiple types of data to be rendered. - */ -int utfgridStartShape(imageObj *img, shapeObj *shape) -{ - UTFGridRenderer *r = UTFGRID_RENDERER(img); - - if(!r->renderlayer) - return MS_FAILURE; - - /* Table operations */ - r->utfvalue = addToTable(r, shape); - - return MS_SUCCESS; -} - -/* - * Tells the renderer that the shape's rendering is done. - */ -int utfgridEndShape(imageObj *img, shapeObj *shape) -{ - UTFGridRenderer *r = UTFGRID_RENDERER(img); - - r->utfvalue = 0; - return MS_SUCCESS; -} - -/* - * Function that renders polygons into UTFGrid. - */ -int utfgridRenderPolygon(imageObj *img, shapeObj *polygonshape, colorObj *color) -{ - UTFGridRenderer *r = UTFGRID_RENDERER(img); - - /* utfvalue is set to 0 if the shape isn't in the table. */ - if(r->utfvalue == 0) { - return MS_FAILURE; - } - - /* Render the polygon */ - polygon_adaptor_utf polygons(polygonshape, r->utfresolution); - utfgridRenderPath(img, polygons); - - return MS_SUCCESS; -} - -/* - * Function that renders lines into UTFGrid. Starts by looking if the line is a polygon - * outline, draw it if it's not. - */ -int utfgridRenderLine(imageObj *img, shapeObj *lineshape, strokeStyleObj *linestyle) -{ - UTFGridRenderer *r = UTFGRID_RENDERER(img); - - /* utfvalue is set to 0 if the shape isn't in the table. */ - if(r->utfvalue == 0) { - return MS_SUCCESS; - /* If we dont get a caracter to draw we just skip execution - * instead of failing - */ - } - - /* Render the line */ - line_adaptor_utf lines(lineshape, r->utfresolution); - - if(!r->stroke) { - r->stroke = new mapserver::conv_stroke(lines); - } else { - r->stroke->attach(lines); - } - r->stroke->width(linestyle->width/r->utfresolution); - utfgridRenderPath(img, *r->stroke); - - return MS_SUCCESS; -} - -/* - * Function that render vector type symbols into UTFGrid. - */ -int utfgridRenderVectorSymbol(imageObj *img, double x, double y, symbolObj *symbol, symbolStyleObj * style) -{ - UTFGridRenderer *r = UTFGRID_RENDERER(img); - double ox = symbol->sizex * 0.5; - double oy = symbol->sizey * 0.5; - - /* utfvalue is set to 0 if the shape isn't in the table. */ - if(r->utfvalue == 0) { - return MS_FAILURE; - } - - /* Pathing the symbol */ - mapserver::path_storage path = imageVectorSymbol(symbol); - - /* Transformation to the right size/scale. */ - mapserver::trans_affine mtx; - mtx *= mapserver::trans_affine_translation(-ox,-oy); - mtx *= mapserver::trans_affine_scaling(style->scale/r->utfresolution); - mtx *= mapserver::trans_affine_rotation(-style->rotation); - mtx *= mapserver::trans_affine_translation(x/r->utfresolution, y/r->utfresolution); - path.transform(mtx); - - /* Rendering the symbol. */ - utfgridRenderPath(img, path); - - return MS_SUCCESS; -} - -/* - * Function that renders Pixmap type symbols into UTFGrid. - */ -int utfgridRenderPixmapSymbol(imageObj *img, double x, double y, symbolObj *symbol, symbolStyleObj * style) -{ - UTFGridRenderer *r = UTFGRID_RENDERER(img); - rasterBufferObj *pixmap = symbol->pixmap_buffer; - - /* utfvalue is set to 0 if the shape isn't in the table. */ - if(r->utfvalue == 0) { - return MS_FAILURE; - } - - /* Pathing the symbol BBox */ - mapserver::path_storage pixmap_bbox; - double w, h; - w = pixmap->width*style->scale/(2.0); - h= pixmap->height*style->scale/(2.0); - pixmap_bbox.move_to((x-w)/r->utfresolution,(y-h)/r->utfresolution); - pixmap_bbox.line_to((x+w)/r->utfresolution,(y-h)/r->utfresolution); - pixmap_bbox.line_to((x+w)/r->utfresolution,(y+h)/r->utfresolution); - pixmap_bbox.line_to((x-w)/r->utfresolution,(y+h)/r->utfresolution); - - /* Rendering the symbol */ - utfgridRenderPath(img, pixmap_bbox); - - return MS_SUCCESS; -} - -/* - * Function that render ellipse type symbols into UTFGrid. - */ -int utfgridRenderEllipseSymbol(imageObj *img, double x, double y, symbolObj *symbol, symbolStyleObj * style) -{ - UTFGridRenderer *r = UTFGRID_RENDERER(img); - - /* utfvalue is set to 0 if the shape isn't in the table. */ - if(r->utfvalue == 0) { - return MS_FAILURE; - } - - /* Pathing the symbol. */ - mapserver::path_storage path; - mapserver::ellipse ellipse(x/r->utfresolution,y/r->utfresolution,symbol->sizex*style->scale/2/r->utfresolution,symbol->sizey*style->scale/2/r->utfresolution); - path.concat_path(ellipse); - - /* Rotation if necessary. */ - if( style->rotation != 0) { - mapserver::trans_affine mtx; - mtx *= mapserver::trans_affine_translation(-x/r->utfresolution,-y/r->utfresolution); - mtx *= mapserver::trans_affine_rotation(-style->rotation); - mtx *= mapserver::trans_affine_translation(x/r->utfresolution,y/r->utfresolution); - path.transform(mtx); - } - - /* Rendering the symbol. */ - utfgridRenderPath(img, path); - - return MS_SUCCESS; -} - -int utfgridRenderGlyphs(imageObj *img, textPathObj *tp, colorObj *c, colorObj *oc, int ow, int isMarker) { - - UTFGridRenderer *r = UTFGRID_RENDERER(img); - - /* If it's not a marker then it's a label or other thing and we dont - * want to draw it on the map - */ - if(!isMarker) { - return MS_SUCCESS; //Stop the rendering with no errors - } - - /* utfvalue is set to 0 if the shape isn't in the table. */ - if(r->utfvalue == 0) { - return MS_SUCCESS; //Stop the rendering with no errors - } - - /* Pathing the symbol BBox */ - mapserver::path_storage box; - double size, x, y; - - size = tp->glyph_size;; - x = tp->glyphs->pnt.x; - y = tp->glyphs->pnt.y; - - box.move_to((x)/r->utfresolution,(y)/r->utfresolution); - box.line_to((x+size)/r->utfresolution,(y)/r->utfresolution); - box.line_to((x+size)/r->utfresolution,(y-size)/r->utfresolution); - box.line_to((x)/r->utfresolution,(y-size)/r->utfresolution); - - /* Rotation if necessary. */ - if( tp->glyphs->rot != 0) { - mapserver::trans_affine mtx; - mtx *= mapserver::trans_affine_translation(-x/r->utfresolution,-y/r->utfresolution); - mtx *= mapserver::trans_affine_rotation(-tp->glyphs->rot); - mtx *= mapserver::trans_affine_translation(x/r->utfresolution,y/r->utfresolution); - box.transform(mtx); - } - - - /* Rendering the symbol */ - utfgridRenderPath(img, box); - - return MS_SUCCESS; -} - -int utfgridFreeSymbol(symbolObj * symbol) -{ - return MS_SUCCESS; -} - -/* - * Add the necessary functions for UTFGrid to the renderer VTable. - */ -int msPopulateRendererVTableUTFGrid( rendererVTableObj *renderer ) -{ - renderer->default_transform_mode = MS_TRANSFORM_SIMPLIFY; - - renderer->createImage = &utfgridCreateImage; - renderer->freeImage = &utfgridFreeImage; - renderer->saveImage = &utfgridSaveImage; - - renderer->startLayer = &utfgridStartLayer; - renderer->endLayer = &utfgridEndLayer; - - renderer->startShape = &utfgridStartShape; - renderer->endShape = &utfgridEndShape; - - renderer->renderPolygon = &utfgridRenderPolygon; - renderer->renderGlyphs = &utfgridRenderGlyphs; - renderer->renderLine = &utfgridRenderLine; - renderer->renderVectorSymbol = &utfgridRenderVectorSymbol; - renderer->renderPixmapSymbol = &utfgridRenderPixmapSymbol; - renderer->renderEllipseSymbol = &utfgridRenderEllipseSymbol; - - renderer->freeSymbol = &utfgridFreeSymbol; - - renderer->loadImageFromFile = msLoadMSRasterBufferFromFile; - - return MS_SUCCESS; -} diff --git a/maputfgrid.h b/maputfgrid.h deleted file mode 100644 index 2eac2741fe..0000000000 --- a/maputfgrid.h +++ /dev/null @@ -1,247 +0,0 @@ -/****************************************************************************** - * $Id$ - * - * Project: MapServer - * Purpose: UTFGrid rendering functions (using AGG) - * Author: Francois Desjarlais - * - ****************************************************************************** - * Copyright (c) 1996-2007 Regents of the University of Minnesota. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies of this Software or works derived from this Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - *****************************************************************************/ - -#include "renderers/agg/include/agg_renderer_base.h" -#include "renderers/agg/include/agg_rendering_buffer.h" - -/* - * Using AGG templates to create UTFGrid pixel. - */ - -//==================================================================utfpix32 -struct utfpix32 -{ - typedef mapserver::int32u value_type; - typedef mapserver::int64u calc_type; - typedef mapserver::int64 long_type; - - typedef utfpix32 self_type; - - value_type v; - - //-------------------------------------------------------------------- - utfpix32() {} - - //-------------------------------------------------------------------- - utfpix32(unsigned v_) : - v(mapserver::int32u(v_)) {} - - //-------------------------------------------------------------------- - utfpix32(const self_type& c) : - v(c.v) {} - - //-------------------------------------------------------------------- - void clear() - { - v = 0; - } - - //-------------------------------------------------------------------- - AGG_INLINE void add(const self_type& c, unsigned cover) - { - *this = c; - } -}; - -//=================================================pixfmt_utf -template -class pixfmt_utf -{ -public: - typedef RenBuf rbuf_type; - typedef typename rbuf_type::row_data row_data; - typedef ColorT color_type; - typedef typename color_type::value_type value_type; - typedef typename color_type::calc_type calc_type; - enum base_scale_e - { - pix_width = sizeof(value_type), - pix_step = Step, - pix_offset = Offset - }; - -private: - //-------------------------------------------------------------------- - static AGG_INLINE void copy_or_blend_pix(value_type* p, - const color_type& c, - unsigned cover) - { - *p = c.v; - } - - static AGG_INLINE void copy_or_blend_pix(value_type* p, - const color_type& c) - { - *p = c.v; - } - -public: - pixfmt_utf() : m_rbuf(0) {} - //-------------------------------------------------------------------- - explicit pixfmt_utf(rbuf_type& rb) : - m_rbuf(&rb) - {} - void attach(rbuf_type& rb) { m_rbuf = &rb; } - //-------------------------------------------------------------------- - - template - bool attach(PixFmt& pixf, int x1, int y1, int x2, int y2) - { - mapserver::rect_i r(x1, y1, x2, y2); - if(r.clip(mapserver::rect_i(0, 0, pixf.width()-1, pixf.height()-1))) - { - int stride = pixf.stride(); - m_rbuf->attach(pixf.pix_ptr(r.x1, stride < 0 ? r.y2 : r.y1), - (r.x2 - r.x1) + 1, - (r.y2 - r.y1) + 1, - stride); - return true; - } - return false; - } - - //-------------------------------------------------------------------- - AGG_INLINE unsigned width() const { return m_rbuf->width(); } - AGG_INLINE unsigned height() const { return m_rbuf->height(); } - AGG_INLINE int stride() const { return m_rbuf->stride(); } - - //-------------------------------------------------------------------- - mapserver::int8u* row_ptr(int y) { return m_rbuf->row_ptr(y); } - const mapserver::int8u* row_ptr(int y) const { return m_rbuf->row_ptr(y); } - row_data row(int y) const { return m_rbuf->row(y); } - - const mapserver::int8u* pix_ptr(int x, int y) const - { - return m_rbuf->row_ptr(y) + x * Step + Offset+1213; - } - - mapserver::int8u* pix_ptr(int x, int y) - { - return m_rbuf->row_ptr(y) + x * Step + Offset +1213; - } - - //-------------------------------------------------------------------- - AGG_INLINE static void make_pix(mapserver::int8u* p, const color_type& c) - { - *(value_type*)p = c.v; - } - - //-------------------------------------------------------------------- - AGG_INLINE color_type pixel(int x, int y) const - { - value_type* p = (value_type*)m_rbuf->row_ptr(y) + x * Step + Offset; - return color_type(*p); - } - - //-------------------------------------------------------------------- - AGG_INLINE void copy_pixel(int x, int y, const color_type& c) - { - *((value_type*)m_rbuf->row_ptr(x, y, 1) + x * Step + Offset) = c.v; - } - - //-------------------------------------------------------------------- - AGG_INLINE void blend_pixel(int x, int y, const color_type& c, mapserver::int8u cover) - { - copy_or_blend_pix((value_type*) - m_rbuf->row_ptr(x, y, 1) + x * Step + Offset, - c); - } - - - //-------------------------------------------------------------------- - AGG_INLINE void copy_hline(int x, int y, - unsigned len, - const color_type& c) - { - value_type* p = (value_type*) - m_rbuf->row_ptr(x, y, len) + x * Step + Offset; - - do - { - *p = c.v; - p += Step; - } - while(--len); - } - - - //-------------------------------------------------------------------- - AGG_INLINE void copy_vline(int x, int y, - unsigned len, - const color_type& c) - { - do - { - value_type* p = (value_type*) - m_rbuf->row_ptr(x, y++, 1) + x * Step + Offset; - - *p = c.v; - } - while(--len); - } - - - //-------------------------------------------------------------------- - void blend_hline(int x, int y, - unsigned len, - const color_type& c, - mapserver::int8u cover) - { - value_type* p = (value_type*) - m_rbuf->row_ptr(x, y, len) + x * Step + Offset; - - do - { - *p = c.v; - p += Step; - } - while(--len); - } - - - //-------------------------------------------------------------------- - void blend_vline(int x, int y, - unsigned len, - const color_type& c, - mapserver::int8u cover) - { - do - { - value_type* p = (value_type*) - m_rbuf->row_ptr(x, y++, 1) + x * Step + Offset; - - *p = c.v; - } - while(--len); - } - - -private: - rbuf_type* m_rbuf; -}; diff --git a/maputil.c b/maputil.c deleted file mode 100644 index 55490d5862..0000000000 --- a/maputil.c +++ /dev/null @@ -1,2795 +0,0 @@ -/****************************************************************************** - * $Id$ - * - * Project: MapServer - * Purpose: Various utility functions ... a real hodgepodge. - * Author: Steve Lime and the MapServer team. - * - * Notes: Some code (notably msAlphaBlend()) are directly derived from GD. See - * the mapserver/GD-COPYING file for the GD license. Use of this code in this - * manner is compatible with the MapServer license. - * - ****************************************************************************** - * Copyright (c) 1996-2005 Regents of the University of Minnesota. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies of this Software or works derived from this Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - *****************************************************************************/ - -#include - -#include "mapserver.h" -#include "maptime.h" -#include "mapthread.h" -#include "mapcopy.h" -#include "mapows.h" - -#include "gdal.h" - -#if defined(_WIN32) && !defined(__CYGWIN__) -# include -# include -# include -# include -#include -#endif - -#ifdef USE_RSVG -#include -#endif -#ifdef USE_GEOS -#include -#endif - - -extern char *msyystring_buffer; -extern int msyylex_destroy(void); -extern int yyparse(parseObj *); - -int msScaleInBounds(double scale, double minscale, double maxscale) -{ - if(scale > 0) { - if(maxscale != -1 && scale >= maxscale) return MS_FALSE; - if(minscale != -1 && scale < minscale) return MS_FALSE; - } - return MS_TRUE; -} - -/* -** Helper functions to convert from strings to other types or objects. -*/ -static int bindIntegerAttribute(int *attribute, const char *value) -{ - if(!value || strlen(value) == 0) return MS_FAILURE; - *attribute = MS_NINT(atof(value)); /*use atof instead of atoi as a fix for bug 2394*/ - return MS_SUCCESS; -} - -static int bindDoubleAttribute(double *attribute, const char *value) -{ - if(!value || strlen(value) == 0) return MS_FAILURE; - *attribute = atof(value); - return MS_SUCCESS; -} - -static int bindColorAttribute(colorObj *attribute, const char *value) -{ - int len; - - if(!value || ((len = strlen(value)) == 0)) return MS_FAILURE; - - if(value[0] == '#' && (len == 7 || len == 9)) { /* got a hex color */ - char hex[2]; - - hex[0] = value[1]; - hex[1] = value[2]; - attribute->red = msHexToInt(hex); - hex[0] = value[3]; - hex[1] = value[4]; - attribute->green = msHexToInt(hex); - hex[0] = value[5]; - hex[1] = value[6]; - attribute->blue = msHexToInt(hex); - if(len == 9) { - hex[0] = value[7]; - hex[1] = value[8]; - attribute->alpha = msHexToInt(hex); - } - return MS_SUCCESS; - } else { /* try a space delimited string */ - char **tokens=NULL; - int numtokens=0; - - tokens = msStringSplit(value, ' ', &numtokens); - if(tokens==NULL || numtokens != 3) { - msFreeCharArray(tokens, numtokens); - return MS_FAILURE; /* punt */ - } - - attribute->red = atoi(tokens[0]); - attribute->green = atoi(tokens[1]); - attribute->blue = atoi(tokens[2]); - msFreeCharArray(tokens, numtokens); - - return MS_SUCCESS; - } - - return MS_FAILURE; /* shouldn't get here */ -} - -static void bindStyle(layerObj *layer, shapeObj *shape, styleObj *style, int drawmode) -{ - int applyOpacity = MS_FALSE; - assert(MS_DRAW_FEATURES(drawmode)); - if(style->numbindings > 0) { - applyOpacity = MS_TRUE; - if(style->bindings[MS_STYLE_BINDING_SYMBOL].index != -1) { - style->symbol = msGetSymbolIndex(&(layer->map->symbolset), shape->values[style->bindings[MS_STYLE_BINDING_SYMBOL].index], MS_TRUE); - if(style->symbol == -1) style->symbol = 0; /* a reasonable default (perhaps should throw an error?) */ - } - if(style->bindings[MS_STYLE_BINDING_ANGLE].index != -1) { - style->angle = 360.0; - bindDoubleAttribute(&style->angle, shape->values[style->bindings[MS_STYLE_BINDING_ANGLE].index]); - } - if(style->bindings[MS_STYLE_BINDING_SIZE].index != -1) { - style->size = 1; - bindDoubleAttribute(&style->size, shape->values[style->bindings[MS_STYLE_BINDING_SIZE].index]); - } - if(style->bindings[MS_STYLE_BINDING_WIDTH].index != -1) { - style->width = 1; - bindDoubleAttribute(&style->width, shape->values[style->bindings[MS_STYLE_BINDING_WIDTH].index]); - } - if(style->bindings[MS_STYLE_BINDING_COLOR].index != -1 && !MS_DRAW_QUERY(drawmode)) { - MS_INIT_COLOR(style->color, -1,-1,-1,255); - bindColorAttribute(&style->color, shape->values[style->bindings[MS_STYLE_BINDING_COLOR].index]); - } - if(style->bindings[MS_STYLE_BINDING_OUTLINECOLOR].index != -1 && !MS_DRAW_QUERY(drawmode)) { - MS_INIT_COLOR(style->outlinecolor, -1,-1,-1,255); - bindColorAttribute(&style->outlinecolor, shape->values[style->bindings[MS_STYLE_BINDING_OUTLINECOLOR].index]); - } - if(style->bindings[MS_STYLE_BINDING_OUTLINEWIDTH].index != -1) { - style->outlinewidth = 1; - bindDoubleAttribute(&style->outlinewidth, shape->values[style->bindings[MS_STYLE_BINDING_OUTLINEWIDTH].index]); - } - if(style->bindings[MS_STYLE_BINDING_OPACITY].index != -1) { - style->opacity = 100; - bindIntegerAttribute(&style->opacity, shape->values[style->bindings[MS_STYLE_BINDING_OPACITY].index]); - } - if(style->bindings[MS_STYLE_BINDING_OFFSET_X].index != -1) { - style->offsetx = 0; - bindDoubleAttribute(&style->offsetx, shape->values[style->bindings[MS_STYLE_BINDING_OFFSET_X].index]); - } - if(style->bindings[MS_STYLE_BINDING_OFFSET_Y].index != -1) { - style->offsety = 0; - bindDoubleAttribute(&style->offsety, shape->values[style->bindings[MS_STYLE_BINDING_OFFSET_Y].index]); - } - if(style->bindings[MS_STYLE_BINDING_POLAROFFSET_PIXEL].index != -1) { - style->polaroffsetpixel = 0; - bindDoubleAttribute(&style->polaroffsetpixel, shape->values[style->bindings[MS_STYLE_BINDING_POLAROFFSET_PIXEL].index]); - } - if(style->bindings[MS_STYLE_BINDING_POLAROFFSET_ANGLE].index != -1) { - style->polaroffsetangle = 0; - bindDoubleAttribute(&style->polaroffsetangle, shape->values[style->bindings[MS_STYLE_BINDING_POLAROFFSET_ANGLE].index]); - } - } - if (style->nexprbindings > 0) - { - applyOpacity = MS_TRUE; - if (style->exprBindings[MS_STYLE_BINDING_OFFSET_X].type == MS_EXPRESSION) - { - style->offsetx = msEvalDoubleExpression( - &(style->exprBindings[MS_STYLE_BINDING_OFFSET_X]), - shape); - } - if (style->exprBindings[MS_STYLE_BINDING_OFFSET_Y].type == MS_EXPRESSION) - { - style->offsety = msEvalDoubleExpression( - &(style->exprBindings[MS_STYLE_BINDING_OFFSET_Y]), - shape); - } - if (style->exprBindings[MS_STYLE_BINDING_ANGLE].type == MS_EXPRESSION) - { - style->angle = msEvalDoubleExpression( - &(style->exprBindings[MS_STYLE_BINDING_ANGLE]), - shape); - } - if (style->exprBindings[MS_STYLE_BINDING_SIZE].type == MS_EXPRESSION) - { - style->size = msEvalDoubleExpression( - &(style->exprBindings[MS_STYLE_BINDING_SIZE]), - shape); - } - if (style->exprBindings[MS_STYLE_BINDING_WIDTH].type == MS_EXPRESSION) - { - style->width = msEvalDoubleExpression( - &(style->exprBindings[MS_STYLE_BINDING_WIDTH]), - shape); - } - if (style->exprBindings[MS_STYLE_BINDING_OPACITY].type == MS_EXPRESSION) - { - style->opacity = 100 * msEvalDoubleExpression( - &(style->exprBindings[MS_STYLE_BINDING_OPACITY]), - shape); - } - if (style->exprBindings[MS_STYLE_BINDING_OUTLINECOLOR].type == MS_EXPRESSION) - { - char* txt = msEvalTextExpression( - &(style->exprBindings[MS_STYLE_BINDING_OUTLINECOLOR]), shape); - bindColorAttribute(&style->outlinecolor, txt); - msFree(txt); - } - if (style->exprBindings[MS_STYLE_BINDING_COLOR].type == MS_EXPRESSION) - { - char* txt = msEvalTextExpression( - &(style->exprBindings[MS_STYLE_BINDING_COLOR]), shape); - bindColorAttribute(&style->color, txt); - msFree(txt); - } - } - - if(applyOpacity == MS_TRUE && (style->opacity < 100 || style->color.alpha != 255) ) { - int alpha; - alpha = MS_NINT(style->opacity*2.55); - style->color.alpha = alpha; - style->outlinecolor.alpha = alpha; - style->backgroundcolor.alpha = alpha; - style->mincolor.alpha = alpha; - style->maxcolor.alpha = alpha; - } -} - -static void bindLabel(layerObj *layer, shapeObj *shape, labelObj *label, int drawmode) -{ - int i; - assert(MS_DRAW_LABELS(drawmode)); - - /* check the label styleObj's (TODO: do we need to use querymapMode here? */ - for(i=0; inumstyles; i++) { - /* force MS_DRAWMODE_FEATURES for label styles */ - bindStyle(layer, shape, label->styles[i], drawmode|MS_DRAWMODE_FEATURES); - } - - if(label->numbindings > 0) { - if(label->bindings[MS_LABEL_BINDING_ANGLE].index != -1) { - label->angle = 0.0; - bindDoubleAttribute(&label->angle, shape->values[label->bindings[MS_LABEL_BINDING_ANGLE].index]); - } - - if(label->bindings[MS_LABEL_BINDING_SIZE].index != -1) { - label->size = 1; - bindIntegerAttribute(&label->size, shape->values[label->bindings[MS_LABEL_BINDING_SIZE].index]); - } - - if(label->bindings[MS_LABEL_BINDING_COLOR].index != -1) { - MS_INIT_COLOR(label->color, -1,-1,-1,255); - bindColorAttribute(&label->color, shape->values[label->bindings[MS_LABEL_BINDING_COLOR].index]); - } - - if(label->bindings[MS_LABEL_BINDING_OUTLINECOLOR].index != -1) { - MS_INIT_COLOR(label->outlinecolor, -1,-1,-1,255); - bindColorAttribute(&label->outlinecolor, shape->values[label->bindings[MS_LABEL_BINDING_OUTLINECOLOR].index]); - } - - if(label->bindings[MS_LABEL_BINDING_FONT].index != -1) { - msFree(label->font); - label->font = msStrdup(shape->values[label->bindings[MS_LABEL_BINDING_FONT].index]); - } - - if(label->bindings[MS_LABEL_BINDING_PRIORITY].index != -1) { - label->priority = MS_DEFAULT_LABEL_PRIORITY; - bindIntegerAttribute(&label->priority, shape->values[label->bindings[MS_LABEL_BINDING_PRIORITY].index]); - } - - if(label->bindings[MS_LABEL_BINDING_SHADOWSIZEX].index != -1) { - label->shadowsizex = 1; - bindIntegerAttribute(&label->shadowsizex, shape->values[label->bindings[MS_LABEL_BINDING_SHADOWSIZEX].index]); - } - if(label->bindings[MS_LABEL_BINDING_SHADOWSIZEY].index != -1) { - label->shadowsizey = 1; - bindIntegerAttribute(&label->shadowsizey, shape->values[label->bindings[MS_LABEL_BINDING_SHADOWSIZEY].index]); - } - - if(label->bindings[MS_LABEL_BINDING_OFFSET_X].index != -1) { - label->offsetx = 0; - bindIntegerAttribute(&label->offsetx, shape->values[label->bindings[MS_LABEL_BINDING_OFFSET_X].index]); - } - - if(label->bindings[MS_LABEL_BINDING_OFFSET_Y].index != -1) { - label->offsety = 0; - bindIntegerAttribute(&label->offsety, shape->values[label->bindings[MS_LABEL_BINDING_OFFSET_Y].index]); - } - - if(label->bindings[MS_LABEL_BINDING_ALIGN].index != -1) { - int tmpAlign = 0; - bindIntegerAttribute(&tmpAlign, shape->values[label->bindings[MS_LABEL_BINDING_ALIGN].index]); - if(tmpAlign != 0) { /* is this test sufficient? */ - label->align = tmpAlign; - } else { /* Integer binding failed, look for strings like cc, ul, lr, etc... */ - if(strlen(shape->values[label->bindings[MS_LABEL_BINDING_ALIGN].index]) >= 4) { - char *va = shape->values[label->bindings[MS_LABEL_BINDING_ALIGN].index]; - if(!strncasecmp(va,"center",5)) - label->align = MS_ALIGN_CENTER; - else if(!strncasecmp(va,"left",4)) - label->align = MS_ALIGN_LEFT; - else if(!strncasecmp(va,"right",5)) - label->align = MS_ALIGN_RIGHT; - } - } - } - - if(label->bindings[MS_LABEL_BINDING_POSITION].index != -1) { - int tmpPosition = 0; - bindIntegerAttribute(&tmpPosition, shape->values[label->bindings[MS_LABEL_BINDING_POSITION].index]); - if(tmpPosition != 0) { /* is this test sufficient? */ - label->position = tmpPosition; - } else { /* Integer binding failed, look for strings like cc, ul, lr, etc... */ - if(strlen(shape->values[label->bindings[MS_LABEL_BINDING_POSITION].index]) == 2) { - char *vp = shape->values[label->bindings[MS_LABEL_BINDING_POSITION].index]; - if(!strncasecmp(vp,"ul",2)) - label->position = MS_UL; - else if(!strncasecmp(vp,"lr",2)) - label->position = MS_LR; - else if(!strncasecmp(vp,"ur",2)) - label->position = MS_UR; - else if(!strncasecmp(vp,"ll",2)) - label->position = MS_LL; - else if(!strncasecmp(vp,"cr",2)) - label->position = MS_CR; - else if(!strncasecmp(vp,"cl",2)) - label->position = MS_CL; - else if(!strncasecmp(vp,"uc",2)) - label->position = MS_UC; - else if(!strncasecmp(vp,"lc",2)) - label->position = MS_LC; - else if(!strncasecmp(vp,"cc",2)) - label->position = MS_CC; - } - } - } - } - if (label->nexprbindings > 0) - { - if (label->exprBindings[MS_LABEL_BINDING_ANGLE].type == MS_EXPRESSION) - { - label->angle = msEvalDoubleExpression( - &(label->exprBindings[MS_LABEL_BINDING_ANGLE]), - shape); - } - if (label->exprBindings[MS_LABEL_BINDING_SIZE].type == MS_EXPRESSION) - { - label->size = msEvalDoubleExpression( - &(label->exprBindings[MS_LABEL_BINDING_SIZE]), - shape); - } - if (label->exprBindings[MS_LABEL_BINDING_COLOR].type == MS_EXPRESSION) - { - char* txt = msEvalTextExpression( - &(label->exprBindings[MS_LABEL_BINDING_COLOR]), shape); - bindColorAttribute(&label->color, txt); - msFree(txt); - } - if (label->exprBindings[MS_LABEL_BINDING_OUTLINECOLOR].type == MS_EXPRESSION) - { - char* txt = msEvalTextExpression( - &(label->exprBindings[MS_LABEL_BINDING_OUTLINECOLOR]), shape); - bindColorAttribute(&label->outlinecolor, txt); - msFree(txt); - } - } -} - -/* -** Function to bind various layer properties to shape attributes. -*/ -int msBindLayerToShape(layerObj *layer, shapeObj *shape, int drawmode) -{ - int i, j; - - if(!layer || !shape) return MS_FAILURE; - - for(i=0; inumclasses; i++) { - /* check the styleObj's */ - if(MS_DRAW_FEATURES(drawmode)) { - for(j=0; jclass[i]->numstyles; j++) { - bindStyle(layer, shape, layer->class[i]->styles[j], drawmode); - } - } - - /* check the labelObj's */ - if(MS_DRAW_LABELS(drawmode)) { - for(j=0; jclass[i]->numlabels; j++) { - bindLabel(layer, shape, layer->class[i]->labels[j], drawmode); - } - } - } /* next classObj */ - - return MS_SUCCESS; -} - -/* - * Used to get red, green, blue integers separately based upon the color index - */ -int getRgbColor(mapObj *map,int i,int *r,int *g,int *b) -{ - /* check index range */ - int status=1; - *r=*g=*b=-1; - if ((i > 0 ) && (i <= map->palette.numcolors) ) { - *r=map->palette.colors[i-1].red; - *g=map->palette.colors[i-1].green; - *b=map->palette.colors[i-1].blue; - status=0; - } - return status; -} - -static int searchContextForTag(mapObj *map, char **ltags, char *tag, char *context, int requires) -{ - int i; - - if(!context) return MS_FAILURE; - - /* printf("\tin searchContextForTag, searching %s for %s\n", context, tag); */ - - if(strstr(context, tag) != NULL) return MS_SUCCESS; /* found the tag */ - - /* check referenced layers for the tag too */ - for(i=0; inumlayers; i++) { - if(strstr(context, ltags[i]) != NULL) { /* need to check this layer */ - if(requires == MS_TRUE) { - if(searchContextForTag(map, ltags, tag, GET_LAYER(map, i)->requires, MS_TRUE) == MS_SUCCESS) return MS_SUCCESS; - } else { - if(searchContextForTag(map, ltags, tag, GET_LAYER(map, i)->labelrequires, MS_FALSE) == MS_SUCCESS) return MS_SUCCESS; - } - } - } - - return MS_FAILURE; -} - -/* -** Function to take a look at all layers with REQUIRES/LABELREQUIRES set to make sure there are no -** recursive context requirements set (e.g. layer1 requires layer2 and layer2 requires layer1). This -** is bug 1059. -*/ -int msValidateContexts(mapObj *map) -{ - int i; - char **ltags; - int status = MS_SUCCESS; - - ltags = (char **) msSmallMalloc(map->numlayers*sizeof(char *)); - for(i=0; inumlayers; i++) { - if(GET_LAYER(map, i)->name == NULL) { - ltags[i] = msStrdup("[NULL]"); - } else { - ltags[i] = (char *) msSmallMalloc(sizeof(char)*strlen(GET_LAYER(map, i)->name) + 3); - sprintf(ltags[i], "[%s]", GET_LAYER(map, i)->name); - } - } - - /* check each layer's REQUIRES and LABELREQUIRES parameters */ - for(i=0; inumlayers; i++) { - /* printf("working on layer %s, looking for references to %s\n", GET_LAYER(map, i)->name, ltags[i]); */ - if(searchContextForTag(map, ltags, ltags[i], GET_LAYER(map, i)->requires, MS_TRUE) == MS_SUCCESS) { - msSetError(MS_PARSEERR, "Recursion error found for REQUIRES parameter for layer %s.", "msValidateContexts", GET_LAYER(map, i)->name); - status = MS_FAILURE; - break; - } - if(searchContextForTag(map, ltags, ltags[i], GET_LAYER(map, i)->labelrequires, MS_FALSE) == MS_SUCCESS) { - msSetError(MS_PARSEERR, "Recursion error found for LABELREQUIRES parameter for layer %s.", "msValidateContexts", GET_LAYER(map, i)->name); - status = MS_FAILURE; - break; - } - /* printf("done layer %s\n", GET_LAYER(map, i)->name); */ - } - - /* clean up */ - msFreeCharArray(ltags, map->numlayers); - - return status; -} - -int msEvalContext(mapObj *map, layerObj *layer, char *context) -{ - int i, status; - char *tag=NULL; - - expressionObj e; - parseObj p; - - if(!context) return(MS_TRUE); - - /* initialize a temporary expression (e) */ - msInitExpression(&e); - - e.string = msStrdup(context); - e.type = MS_EXPRESSION; /* todo */ - - for(i=0; inumlayers; i++) { /* step through all the layers */ - if(layer->index == i) continue; /* skip the layer in question */ - if (GET_LAYER(map, i)->name == NULL) continue; /* Layer without name cannot be used in contexts */ - - tag = (char *)msSmallMalloc(sizeof(char)*strlen(GET_LAYER(map, i)->name) + 3); - sprintf(tag, "[%s]", GET_LAYER(map, i)->name); - - if(strstr(e.string, tag)) { - if(msLayerIsVisible(map, (GET_LAYER(map, i)))) - e.string = msReplaceSubstring(e.string, tag, "1"); - else - e.string = msReplaceSubstring(e.string, tag, "0"); - } - - free(tag); - } - - msTokenizeExpression(&e, NULL, NULL); - - p.shape = NULL; - p.expr = &e; - p.expr->curtoken = p.expr->tokens; /* reset */ - p.type = MS_PARSE_TYPE_BOOLEAN; - - status = yyparse(&p); - - msFreeExpression(&e); - - if (status != 0) { - msSetError(MS_PARSEERR, "Failed to parse context", "msEvalContext"); - return MS_FALSE; /* error in parse */ - } - - return p.result.intval; -} - -/* msEvalExpression() - * - * Evaluates a mapserver expression for a given set of attribute values and - * returns the result of the expression (MS_TRUE or MS_FALSE) - * May also return MS_FALSE in case of parsing errors or invalid expressions - * (check the error stack if you care) - * - */ -int msEvalExpression(layerObj *layer, shapeObj *shape, expressionObj *expression, int itemindex) -{ - if(MS_STRING_IS_NULL_OR_EMPTY(expression->string)) return MS_TRUE; /* NULL or empty expressions are ALWAYS true */ - if(expression->native_string != NULL) return MS_TRUE; /* expressions that are evaluated natively are ALWAYS true */ - - switch(expression->type) { - case(MS_STRING): - if(itemindex == -1) { - msSetError(MS_MISCERR, "Cannot evaluate expression, no item index defined.", "msEvalExpression()"); - return MS_FALSE; - } - if(itemindex >= layer->numitems || itemindex >= shape->numvalues) { - msSetError(MS_MISCERR, "Invalid item index.", "msEvalExpression()"); - return MS_FALSE; - } - if(expression->flags & MS_EXP_INSENSITIVE) { - if(strcasecmp(expression->string, shape->values[itemindex]) == 0) return MS_TRUE; /* got a match */ - } else { - if(strcmp(expression->string, shape->values[itemindex]) == 0) return MS_TRUE; /* got a match */ - } - break; - case(MS_LIST): - if(itemindex == -1) { - msSetError(MS_MISCERR, "Cannot evaluate expression, no item index defined.", "msEvalExpression()"); - return MS_FALSE; - } - if(itemindex >= layer->numitems || itemindex >= shape->numvalues) { - msSetError(MS_MISCERR, "Invalid item index.", "msEvalExpression()"); - return MS_FALSE; - } - { - char *start,*end; - int value_len = strlen(shape->values[itemindex]); - start = expression->string; - while((end = strchr(start,',')) != NULL) { - if(value_len == end-start && !strncmp(start,shape->values[itemindex],end-start)) return MS_TRUE; - start = end+1; - } - if(!strcmp(start,shape->values[itemindex])) return MS_TRUE; - } - break; - case(MS_EXPRESSION): { - int status; - parseObj p; - - p.shape = shape; - p.expr = expression; - p.expr->curtoken = p.expr->tokens; /* reset */ - p.type = MS_PARSE_TYPE_BOOLEAN; - - status = yyparse(&p); - - if (status != 0) { - msSetError(MS_PARSEERR, "Failed to parse expression: %s", "msEvalExpression", expression->string); - return MS_FALSE; - } - - return p.result.intval; - break; - } - case(MS_REGEX): - if(itemindex == -1) { - msSetError(MS_MISCERR, "Cannot evaluate expression, no item index defined.", "msEvalExpression()"); - return MS_FALSE; - } - if(itemindex >= layer->numitems || itemindex >= shape->numvalues) { - msSetError(MS_MISCERR, "Invalid item index.", "msEvalExpression()"); - return MS_FALSE; - } - - if(MS_STRING_IS_NULL_OR_EMPTY(shape->values[itemindex]) == MS_TRUE) return MS_FALSE; - - if(!expression->compiled) { - if(expression->flags & MS_EXP_INSENSITIVE) { - if(ms_regcomp(&(expression->regex), expression->string, MS_REG_EXTENDED|MS_REG_NOSUB|MS_REG_ICASE) != 0) { /* compile the expression */ - msSetError(MS_REGEXERR, "Invalid regular expression.", "msEvalExpression()"); - return MS_FALSE; - } - } else { - if(ms_regcomp(&(expression->regex), expression->string, MS_REG_EXTENDED|MS_REG_NOSUB) != 0) { /* compile the expression */ - msSetError(MS_REGEXERR, "Invalid regular expression.", "msEvalExpression()"); - return MS_FALSE; - } - } - expression->compiled = MS_TRUE; - } - - if(ms_regexec(&(expression->regex), shape->values[itemindex], 0, NULL, 0) == 0) return MS_TRUE; /* got a match */ - break; - } - - return MS_FALSE; -} - -int *msAllocateValidClassGroups(layerObj *lp, int *nclasses) -{ - int *classgroup = NULL; - int nvalidclass = 0, i=0; - - if (!lp || !lp->classgroup || lp->numclasses <=0 || !nclasses) - return NULL; - - classgroup = (int *)msSmallMalloc(sizeof(int)*lp->numclasses); - nvalidclass = 0; - for (i=0; inumclasses; i++) { - if (lp->class[i]->group && strcasecmp(lp->class[i]->group, lp->classgroup) == 0) { - classgroup[nvalidclass] = i; - nvalidclass++; - } - } - if (nvalidclass > 0) { - classgroup = (int *)msSmallRealloc(classgroup, sizeof(int)*nvalidclass); - *nclasses = nvalidclass; - return classgroup; - } - - if (classgroup) - msFree(classgroup); - - return NULL; - -} - -int msShapeGetClass(layerObj *layer, mapObj *map, shapeObj *shape, int *classgroup, int numclasses) -{ - return msShapeGetNextClass(-1, layer, map, shape, classgroup, numclasses); -} - -int msShapeGetNextClass(int currentclass, layerObj *layer, mapObj *map, - shapeObj *shape, int *classgroup, int numclasses) -{ - int i, iclass; - - if (currentclass < 0) - currentclass = -1; - - if (layer->numclasses > 0) { - if (classgroup == NULL || numclasses <=0) - numclasses = layer->numclasses; - - for(i=currentclass+1; i= layer->numclasses) - continue; /* this should never happen but just in case */ - - if(map->scaledenom > 0) { /* verify scaledenom here */ - if((layer->class[iclass]->maxscaledenom > 0) && (map->scaledenom > layer->class[iclass]->maxscaledenom)) - continue; /* can skip this one, next class */ - if((layer->class[iclass]->minscaledenom > 0) && (map->scaledenom <= layer->class[iclass]->minscaledenom)) - continue; /* can skip this one, next class */ - } - - /* verify the minfeaturesize */ - if ((shape->type == MS_SHAPE_LINE || shape->type == MS_SHAPE_POLYGON) && (layer->class[iclass]->minfeaturesize > 0)) { - double minfeaturesize = Pix2LayerGeoref(map, layer, - layer->class[iclass]->minfeaturesize); - if (msShapeCheckSize(shape, minfeaturesize) == MS_FALSE) - continue; /* skip this one, next class */ - } - - if(layer->class[iclass]->status != MS_DELETE && msEvalExpression(layer, shape, &(layer->class[iclass]->expression), layer->classitemindex) == MS_TRUE) - { - if (layer->class[iclass]->isfallback && currentclass != -1) - { - // Class is not applicable if it is flagged as fallback ( tag in SLD) - // but other classes have been applied before. - return -1; - } - else - { - return(iclass); - } - } - } - } - - return(-1); /* no match */ -} - -static -char *msEvalTextExpressionInternal(expressionObj *expr, shapeObj *shape, int bJSonEscape) -{ - char *result=NULL; - - if(!expr->string) return result; /* nothing to do */ - - switch(expr->type) { - case(MS_STRING): { - char *target=NULL; - char *pszEscaped; - tokenListNodeObjPtr node=NULL; - tokenListNodeObjPtr nextNode=NULL; - - result = msStrdup(expr->string); - - node = expr->tokens; - if(node) { - while(node != NULL) { - nextNode = node->next; - if(node->token == MS_TOKEN_BINDING_DOUBLE || node->token == MS_TOKEN_BINDING_INTEGER || node->token == MS_TOKEN_BINDING_STRING || node->token == MS_TOKEN_BINDING_TIME) { - target = (char *) msSmallMalloc(strlen(node->tokenval.bindval.item) + 3); - sprintf(target, "[%s]", node->tokenval.bindval.item); - if( bJSonEscape ) - pszEscaped = msEscapeJSonString(shape->values[node->tokenval.bindval.index]); - else - pszEscaped = msStrdup(shape->values[node->tokenval.bindval.index]); - result = msReplaceSubstring(result, target, pszEscaped); - msFree(pszEscaped); - msFree(target); - } - node = nextNode; - } - } - if(!strlen(result)) { - msFree(result); - result = NULL; - } - } - break; - case(MS_EXPRESSION): { - int status; - parseObj p; - - p.shape = shape; - p.expr = expr; - p.expr->curtoken = p.expr->tokens; /* reset */ - p.type = MS_PARSE_TYPE_STRING; - - status = yyparse(&p); - - if (status != 0) { - msSetError(MS_PARSEERR, "Failed to process text expression: %s", "msEvalTextExpression", expr->string); - return NULL; - } - - result = p.result.strval; - break; - } - default: - break; - } - if(result && !strlen(result)) { - msFree(result); - result = NULL; - } - return result; -} - -char *msEvalTextExpressionJSonEscape(expressionObj *expr, shapeObj *shape) -{ - return msEvalTextExpressionInternal(expr, shape, MS_TRUE); -} - -char *msEvalTextExpression(expressionObj *expr, shapeObj *shape) -{ - return msEvalTextExpressionInternal(expr, shape, MS_FALSE); -} - -double msEvalDoubleExpression(expressionObj *expression, shapeObj *shape) -{ - double value; - int status; - parseObj p; - p.shape = shape; - p.expr = expression; - p.expr->curtoken = p.expr->tokens; /* reset */ - p.type = MS_PARSE_TYPE_STRING; - status = yyparse(&p); - if (status != 0) { - msSetError(MS_PARSEERR, "Failed to parse expression: %s", - "bindStyle", expression->string); - value = 0.0; - } else { - value = atof(p.result.strval); - msFree(p.result.strval); - } - return value; -} - -char* msShapeGetLabelAnnotation(layerObj *layer, shapeObj *shape, labelObj *lbl) { - assert(shape && lbl); - if(lbl->text.string) { - return msEvalTextExpression(&(lbl->text), shape); - } else if(layer->class[shape->classindex]->text.string) { - return msEvalTextExpression(&(layer->class[shape->classindex]->text), shape); - } else { - if (shape->values && layer->labelitemindex >= 0 && shape->values[layer->labelitemindex] && strlen(shape->values[layer->labelitemindex]) ) - return msStrdup(shape->values[layer->labelitemindex]); - else if(shape->text) - return msStrdup(shape->text); /* last resort but common with iniline features */ - } - return NULL; -} - -int msGetLabelStatus(mapObj *map, layerObj *layer, shapeObj *shape, labelObj *lbl) { - assert(layer && lbl); - if(!msScaleInBounds(map->scaledenom,lbl->minscaledenom,lbl->maxscaledenom)) - return MS_OFF; - if(msEvalExpression(layer, shape, &(lbl->expression), layer->labelitemindex) != MS_TRUE) - return MS_OFF; - /* TODO: check for minfeaturesize here ? */ - return MS_ON; -} - -/* Check if the shape is enough big to be drawn with the - layer::minfeaturesize setting. The minfeaturesize parameter should be - the value in geo ref (not in pixel) and should have been multiplied by - the resolution factor. - */ -int msShapeCheckSize(shapeObj *shape, double minfeaturesize) -{ - double dx = (shape->bounds.maxx-shape->bounds.minx); - double dy = (shape->bounds.maxy-shape->bounds.miny); - - if (pow(minfeaturesize,2.0) > (pow(dx,2.0)+pow(dy,2.0))) - return MS_FALSE; - - return MS_TRUE; -} - -/* -** Adjusts an image size in one direction to fit an extent. -*/ -int msAdjustImage(rectObj rect, int *width, int *height) -{ - if(*width == -1 && *height == -1) { - msSetError(MS_MISCERR, "Cannot calculate both image height and width.", "msAdjustImage()"); - return(-1); - } - - if(*width > 0) - *height = MS_NINT((rect.maxy - rect.miny)/((rect.maxx - rect.minx)/(*width))); - else - *width = MS_NINT((rect.maxx - rect.minx)/((rect.maxy - rect.miny)/(*height))); - - return(0); -} - -/* -** Make sure extent fits image window to be created. Returns cellsize of output image. -*/ -double msAdjustExtent(rectObj *rect, int width, int height) -{ - double cellsize, ox, oy; - - if(width == 1 || height == 1) - return 0; - - cellsize = MS_MAX(MS_CELLSIZE(rect->minx, rect->maxx, width), MS_CELLSIZE(rect->miny, rect->maxy, height)); - - if(cellsize <= 0) /* avoid division by zero errors */ - return(0); - - ox = MS_MAX(((width-1) - (rect->maxx - rect->minx)/cellsize)/2,0); /* these were width-1 and height-1 */ - oy = MS_MAX(((height-1) - (rect->maxy - rect->miny)/cellsize)/2,0); - - rect->minx = rect->minx - ox*cellsize; - rect->miny = rect->miny - oy*cellsize; - rect->maxx = rect->maxx + ox*cellsize; - rect->maxy = rect->maxy + oy*cellsize; - - return(cellsize); -} - -/* -** Rect must always contain a portion of bounds. If not, rect is -** shifted to overlap by overlay percent. The dimensions of rect do -** not change but placement relative to bounds can. -*/ -int msConstrainExtent(rectObj *bounds, rectObj *rect, double overlay) -{ - double offset=0; - - /* check left edge, and if necessary the right edge of bounds */ - if(rect->maxx <= bounds->minx) { - offset = overlay*(rect->maxx - rect->minx); - rect->minx += offset; /* shift right */ - rect->maxx += offset; - } else if(rect->minx >= bounds->maxx) { - offset = overlay*(rect->maxx - rect->minx); - rect->minx -= offset; /* shift left */ - rect->maxx -= offset; - } - - /* check top edge, and if necessary the bottom edge of bounds */ - if(rect->maxy <= bounds->miny) { - offset = overlay*(rect->maxy - rect->miny); - rect->miny -= offset; /* shift down */ - rect->maxy -= offset; - } else if(rect->miny >= bounds->maxy) { - offset = overlay*(rect->maxy - rect->miny); - rect->miny += offset; /* shift up */ - rect->maxy += offset; - } - - return(MS_SUCCESS); -} - -/* -** Generic function to save an image to a file. -** -** Note that map may be NULL. If it is set, then it is used for two things: -** - Deal with relative imagepaths (compute absolute path relative to map path) -** - Extract the georeferenced extents and coordinate system -** of the map for writing out with the image when appropriate -** (primarily this means via msSaveImageGDAL() to something like GeoTIFF). -** -** The filename is NULL when the image is supposed to be written to stdout. -*/ - -int msSaveImage(mapObj *map, imageObj *img, const char *filename) -{ - int nReturnVal = MS_FAILURE; - char szPath[MS_MAXPATHLEN]; - struct mstimeval starttime={0}, endtime={0}; - - if(map && map->debug >= MS_DEBUGLEVEL_TUNING) { - msGettimeofday(&starttime, NULL); - } - - if (img) { - if( MS_DRIVER_GDAL(img->format) ) { - if (map != NULL && filename != NULL ) - nReturnVal = msSaveImageGDAL(map, img, - msBuildPath(szPath, map->mappath, - filename)); - else - nReturnVal = msSaveImageGDAL(map, img, filename); - } else - - if (MS_RENDERER_PLUGIN(img->format)) { - rendererVTableObj *renderer = img->format->vtable; - FILE *stream = NULL; - if(filename) { - if(map) - stream = fopen(msBuildPath(szPath, map->mappath, filename),"wb"); - else - stream = fopen(filename,"wb"); - - if(!stream) { - msSetError(MS_IOERR, - "Failed to create output file (%s).", - "msSaveImage()", (map?szPath:filename) ); - return MS_FAILURE; - } - - } else { - if ( msIO_needBinaryStdout() == MS_FAILURE ) - return MS_FAILURE; - stream = stdout; - } - - if(renderer->supports_pixel_buffer) { - rasterBufferObj data; - if(renderer->getRasterBufferHandle(img,&data) != MS_SUCCESS) { - if( stream != stdout ) - fclose(stream); - return MS_FAILURE; - } - - nReturnVal = msSaveRasterBuffer(map,&data,stream,img->format ); - } else { - nReturnVal = renderer->saveImage(img, map, stream, img->format); - } - if( stream != stdout ) - fclose(stream); - - } else if( MS_DRIVER_IMAGEMAP(img->format) ) - nReturnVal = msSaveImageIM(img, filename, img->format); - else - msSetError(MS_MISCERR, "Unknown image type", - "msSaveImage()"); - } - - if(map && map->debug >= MS_DEBUGLEVEL_TUNING) { - msGettimeofday(&endtime, NULL); - msDebug("msSaveImage(%s) total time: %.3fs\n", - (filename ? filename : "stdout"), - (endtime.tv_sec+endtime.tv_usec/1.0e6)- - (starttime.tv_sec+starttime.tv_usec/1.0e6) ); - } - - return nReturnVal; -} - -/* -** Generic function to save an image to a byte array. -** - the return value is the pointer to the byte array -** - size_ptr contains the number of bytes returned -** - format: the desired output format -** -** The caller is responsible to free the returned array -** The function returns NULL if the output format is not supported. -*/ - -unsigned char *msSaveImageBuffer(imageObj* image, int *size_ptr, outputFormatObj *format) -{ - int status = MS_SUCCESS; - *size_ptr = 0; - if( MS_RENDERER_PLUGIN(image->format)) { - rasterBufferObj data; - rendererVTableObj *renderer = image->format->vtable; - if(renderer->supports_pixel_buffer) { - bufferObj buffer; - msBufferInit(&buffer); - status = renderer->getRasterBufferHandle(image,&data); - if(UNLIKELY(status == MS_FAILURE)) { - return NULL; - } - msSaveRasterBufferToBuffer(&data,&buffer,format); - *size_ptr = buffer.size; - return buffer.data; - /* don't free the bufferObj as we don't own the bytes anymore */ - } else { - /* check if the renderer supports native buffer output */ - if (renderer->saveImageBuffer) - return renderer->saveImageBuffer(image, size_ptr, format); - - msSetError(MS_MISCERR, "Unsupported image type", "msSaveImageBuffer()"); - return NULL; - } - } - msSetError(MS_MISCERR, "Unsupported image type", "msSaveImage()"); - return NULL; -} - -/** - * Generic function to free the imageObj - */ -void msFreeImage(imageObj *image) -{ - if (image) { - if(MS_RENDERER_PLUGIN(image->format)) { - rendererVTableObj *renderer = image->format->vtable; - tileCacheObj *next,*cur = image->tilecache; - while(cur) { - msFreeImage(cur->image); - next = cur->next; - free(cur); - cur = next; - } - image->ntiles = 0; - renderer->freeImage(image); - } else if( MS_RENDERER_IMAGEMAP(image->format) ) - msFreeImageIM(image); - else if( MS_RENDERER_RAWDATA(image->format) ) - msFree(image->img.raw_16bit); - else - msSetError(MS_MISCERR, "Unknown image type", - "msFreeImage()"); - - if (image->imagepath) - free(image->imagepath); - if (image->imageurl) - free(image->imageurl); - - if( --image->format->refcount < 1 ) - msFreeOutputFormat( image->format ); - - image->imagepath = NULL; - image->imageurl = NULL; - - msFree( image->img_mask ); - image->img_mask= NULL; - - msFree( image ); - } -} - -/* -** Return an array containing all the layer's index given a group name. -** If nothing is found, NULL is returned. The nCount is initalized -** to the number of elements in the returned array. -** Note : the caller of the function should free the array. -*/ -int *msGetLayersIndexByGroup(mapObj *map, char *groupname, int *pnCount) -{ - int i; - int iLayer = 0; - int *aiIndex; - - if(!groupname || !map || !pnCount) { - return NULL; - } - - aiIndex = (int *)msSmallMalloc(sizeof(int) * map->numlayers); - - for(i=0; inumlayers; i++) { - if(!GET_LAYER(map, i)->group) /* skip it */ - continue; - if(strcmp(groupname, GET_LAYER(map, i)->group) == 0) { - aiIndex[iLayer] = i; - iLayer++; - } - } - - if (iLayer == 0) { - free(aiIndex); - aiIndex = NULL; - *pnCount = 0; - } else { - aiIndex = (int *)msSmallRealloc(aiIndex, sizeof(int)* iLayer); - *pnCount = iLayer; - } - - return aiIndex; -} - -/* ==================================================================== */ -/* Measured shape utility functions. */ -/* ==================================================================== */ - - -/************************************************************************/ -/* pointObj *msGetPointUsingMeasure(shapeObj *shape, double m) */ -/* */ -/* Using a measured value get the XY location it corresonds */ -/* to. */ -/* */ -/************************************************************************/ -pointObj *msGetPointUsingMeasure(shapeObj *shape, double m) -{ -#ifdef USE_POINT_Z_M - pointObj *point = NULL; - lineObj line; - double dfMin = 0; - double dfMax = 0; - int i,j = 0; - int bFound = 0; - double dfFirstPointX = 0; - double dfFirstPointY = 0; - double dfFirstPointM = 0; - double dfSecondPointX = 0; - double dfSecondPointY = 0; - double dfSecondPointM = 0; - double dfCurrentM = 0; - double dfFactor = 0; - - if (shape && shape->numlines > 0) { - /* -------------------------------------------------------------------- */ - /* check fir the first value (min) and the last value(max) to */ - /* see if the m is contained between these min and max. */ - /* -------------------------------------------------------------------- */ - line = shape->line[0]; - dfMin = line.point[0].m; - line = shape->line[shape->numlines-1]; - dfMax = line.point[line.numpoints-1].m; - - if (m >= dfMin && m <= dfMax) { - for (i=0; inumlines; i++) { - line = shape->line[i]; - - for (j=0; j m) { - bFound = 1; - - dfSecondPointX = line.point[j].x; - dfSecondPointY = line.point[j].y; - dfSecondPointM = line.point[j].m; - - /* -------------------------------------------------------------------- */ - /* get the previous node xy values. */ - /* -------------------------------------------------------------------- */ - if (j > 0) { /* not the first point of the line */ - dfFirstPointX = line.point[j-1].x; - dfFirstPointY = line.point[j-1].y; - dfFirstPointM = line.point[j-1].m; - } else { /* get last point of previous line */ - dfFirstPointX = shape->line[i-1].point[0].x; - dfFirstPointY = shape->line[i-1].point[0].y; - dfFirstPointM = shape->line[i-1].point[0].m; - } - break; - } - } - } - } - - if (!bFound) - return NULL; - - /* -------------------------------------------------------------------- */ - /* extrapolate the m value to get t he xy coordinate. */ - /* -------------------------------------------------------------------- */ - - if (dfFirstPointM != dfSecondPointM) - dfFactor = (m-dfFirstPointM)/(dfSecondPointM - dfFirstPointM); - else - dfFactor = 0; - - point = (pointObj *)msSmallMalloc(sizeof(pointObj)); - - point->x = dfFirstPointX + (dfFactor * (dfSecondPointX - dfFirstPointX)); - point->y = dfFirstPointY + - (dfFactor * (dfSecondPointY - dfFirstPointY)); - point->m = dfFirstPointM + - (dfFactor * (dfSecondPointM - dfFirstPointM)); - - return point; - } - - return NULL; -#else - msSetError(MS_MISCERR, - "The \"m\" parameter for points is unavailable in your build.", - "msGetPointUsingMeasure()"); - return NULL; -#endif /* USE_POINT_Z_M */ -} - - -/************************************************************************/ -/* IntersectionPointLinepointObj *p, pointObj *a, pointObj *b) */ -/* */ -/* Retunrs a point object corresponding to the intersection of */ -/* point p and a line formed of 2 points : a and b. */ -/* */ -/* Alorith base on : */ -/* http://www.faqs.org/faqs/graphics/algorithms-faq/ */ -/* */ -/* Subject 1.02:How do I find the distance from a point to a line? */ -/* */ -/* Let the point be C (Cx,Cy) and the line be AB (Ax,Ay) to (Bx,By).*/ -/* Let P be the point of perpendicular projection of C on AB. The parameter*/ -/* r, which indicates P's position along AB, is computed by the dot product */ -/* of AC and AB divided by the square of the length of AB: */ -/* */ -/* (1) AC dot AB */ -/* r = --------- */ -/* ||AB||^2 */ -/* */ -/* r has the following meaning: */ -/* */ -/* r=0 P = A */ -/* r=1 P = B */ -/* r<0 P is on the backward extension of AB */ -/* r>1 P is on the forward extension of AB */ -/* 00 C is right of AB */ -/* s=0 C is on AB */ -/* */ -/* Compute s as follows: */ -/* */ -/* (Ay-Cy)(Bx-Ax)-(Ax-Cx)(By-Ay) */ -/* s = ----------------------------- */ -/* L^2 */ -/* */ -/* */ -/* Then the distance from C to P = |s|*L. */ -/* */ -/************************************************************************/ -pointObj *msIntersectionPointLine(pointObj *p, pointObj *a, pointObj *b) -{ - double r = 0; - double L = 0; - pointObj *result = NULL; - - if (p && a && b) { - L = sqrt(((b->x - a->x)*(b->x - a->x)) + - ((b->y - a->y)*(b->y - a->y))); - - if (L != 0) - r = ((p->x - a->x)*(b->x - a->x) + (p->y - a->y)*(b->y - a->y))/(L*L); - else - r = 0; - - result = (pointObj *)msSmallMalloc(sizeof(pointObj)); - /* -------------------------------------------------------------------- */ - /* We want to make sure that the point returned is on the line */ - /* */ - /* r=0 P = A */ - /* r=1 P = B */ - /* r<0 P is on the backward extension of AB */ - /* r>1 P is on the forward extension of AB */ - /* 0x = a->x; - result->y = a->y; - } else if (r > 1) { - result->x = b->x; - result->y = b->y; - } else { - result->x = a->x + r*(b->x - a->x); - result->y = a->y + r*(b->y - a->y); - } -#ifdef USE_POINT_Z_M - result->m = 0; -#endif - } - - return result; -} - - -/************************************************************************/ -/* pointObj *msGetMeasureUsingPoint(shapeObj *shape, pointObj */ -/* *point) */ -/* */ -/* Calculate the intersection point betwwen the point and the */ -/* shape and return the Measured value at the intersection. */ -/************************************************************************/ -pointObj *msGetMeasureUsingPoint(shapeObj *shape, pointObj *point) -{ - double dfMinDist = 1e35; - double dfDist = 0; - pointObj oFirst; - pointObj oSecond; - int i, j = 0; - lineObj line; - pointObj *poIntersectionPt = NULL; -#ifdef USE_POINT_Z_M - double dfFactor = 0; - double dfDistTotal, dfDistToIntersection = 0; -#endif - - if (shape && point) { - for (i=0; inumlines; i++) { - line = shape->line[i]; - /* -------------------------------------------------------------------- */ - /* for each line (2 consecutive lines) get the distance between */ - /* the line and the point and determine which line segment is */ - /* the closeset to the point. */ - /* -------------------------------------------------------------------- */ - for (j=0; jx - oFirst.x)* - (poIntersectionPt->x - oFirst.x)) + - ((poIntersectionPt->y - oFirst.y)* - (poIntersectionPt->y - oFirst.y))); - - dfFactor = dfDistToIntersection / dfDistTotal; - - poIntersectionPt->m = oFirst.m + (oSecond.m - oFirst.m)*dfFactor; -#endif - - return poIntersectionPt; - } - - } - return NULL; -} - -/* ==================================================================== */ -/* End Measured shape utility functions. */ -/* ==================================================================== */ - - -char **msGetAllGroupNames(mapObj *map, int *numTok) -{ - char **papszGroups = NULL; - int bFound = 0; - int nCount = 0; - int i = 0, j = 0; - - assert(map); - *numTok = 0; - - if (!map->layerorder) { - map->layerorder = (int*)msSmallMalloc(map->numlayers * sizeof(int)); - - /* - * Initiate to default order - */ - for (i=0; inumlayers; i++) - map->layerorder[i] = i; - } - - if (map->numlayers > 0) { - nCount = map->numlayers; - papszGroups = (char **)msSmallMalloc(sizeof(char *)*nCount); - - for (i=0; ilayerorder[i])); - - bFound = 0; - if (lp->group && lp->status != MS_DELETE) { - for (j=0; j<*numTok; j++) { - if (papszGroups[j] && - strcmp(lp->group, papszGroups[j]) == 0) { - bFound = 1; - break; - } - } - if (!bFound) { - /* New group... add to the list of groups found */ - papszGroups[(*numTok)] = msStrdup(lp->group); - (*numTok)++; - } - } - } - - } - - return papszGroups; -} - -/************************************************************************/ -/* msForceTmpFileBase() */ -/************************************************************************/ - -static int tmpCount = 0; -static char *ForcedTmpBase = NULL; - -void msForceTmpFileBase( const char *new_base ) -{ - /* -------------------------------------------------------------------- */ - /* Clear previous setting, if any. */ - /* -------------------------------------------------------------------- */ - if( ForcedTmpBase != NULL ) { - free( ForcedTmpBase ); - ForcedTmpBase = NULL; - } - - tmpCount = -1; - - if( new_base == NULL ) - return; - - /* -------------------------------------------------------------------- */ - /* Record new base. */ - /* -------------------------------------------------------------------- */ - ForcedTmpBase = msStrdup( new_base ); - tmpCount = 0; -} - -/********************************************************************** - * msTmpFile() - * - * Generate a Unique temporary file. - * - * Returns char* which must be freed by caller. - **********************************************************************/ -char *msTmpFile(mapObj *map, const char *mappath, const char *tmppath, const char *ext) -{ - char szPath[MS_MAXPATHLEN]; - const char *fullFname; - char *tmpFileName; /* big enough for time + pid + ext */ - char *tmpBase = NULL; - - tmpBase = msTmpPath(map, mappath, tmppath); - tmpFileName = msTmpFilename(ext); - - fullFname = msBuildPath(szPath, tmpBase, tmpFileName); - - free(tmpFileName); - free(tmpBase); - - if (fullFname) - return msStrdup(fullFname); - - return NULL; -} - -/********************************************************************** - * msTmpPath() - * - * Return the temporary path based on the platform. - * - * Returns char* which must be freed by caller. - **********************************************************************/ -char *msTmpPath(mapObj *map, const char *mappath, const char *tmppath) -{ - char szPath[MS_MAXPATHLEN]; - const char *fullPath; - const char *tmpBase; -#ifdef _WIN32 - DWORD dwRetVal = 0; - TCHAR lpTempPathBuffer[MAX_PATH]; -#endif - - if( ForcedTmpBase != NULL ) - tmpBase = ForcedTmpBase; - else if (tmppath != NULL) - tmpBase = tmppath; - else if (getenv("MS_TEMPPATH")) - tmpBase = getenv("MS_TEMPPATH"); - else if (map && map->web.temppath) - tmpBase = map->web.temppath; - else { /* default paths */ -#ifndef _WIN32 - tmpBase = "/tmp/"; -#else - dwRetVal = GetTempPath(MAX_PATH, /* length of the buffer */ - lpTempPathBuffer); /* buffer for path */ - if (dwRetVal > MAX_PATH || (dwRetVal == 0)) { - tmpBase = "C:\\"; - } else { - tmpBase = (char*)lpTempPathBuffer; - } -#endif - } - - fullPath = msBuildPath(szPath, mappath, tmpBase); - return msStrdup(fullPath); -} - -/********************************************************************** - * msTmpFilename() - * - * Generate a Unique temporary filename. - * - * Returns char* which must be freed by caller. - **********************************************************************/ -char *msTmpFilename(const char *ext) -{ - char *tmpFname; - int tmpFnameBufsize; - char *fullFname; - char tmpId[128]; /* big enough for time + pid + ext */ - - snprintf(tmpId, sizeof(tmpId), "%lx_%x",(long)time(NULL),(int)getpid()); - - if (ext == NULL) ext = ""; - tmpFnameBufsize = strlen(tmpId) + 10 + strlen(ext) + 1; - tmpFname = (char*)msSmallMalloc(tmpFnameBufsize); - - msAcquireLock( TLOCK_TMPFILE ); - snprintf(tmpFname, tmpFnameBufsize, "%s_%x.%s", tmpId, tmpCount++, ext); - msReleaseLock( TLOCK_TMPFILE ); - - fullFname = msStrdup(tmpFname); - free(tmpFname); - - return fullFname; -} - -/** - * Generic function to Initalize an image object. - */ -imageObj *msImageCreate(int width, int height, outputFormatObj *format, - char *imagepath, char *imageurl, double resolution, - double defresolution, colorObj *bg) -{ - imageObj *image = NULL; - if(MS_RENDERER_PLUGIN(format)) { - - image = format->vtable->createImage(width,height,format,bg); - if (image == NULL) { - msSetError(MS_MEMERR, "Unable to create new image object.", "msImageCreate()"); - return NULL; - } - - image->format = format; - format->refcount++; - - image->width = width; - image->height = height; - image->imagepath = NULL; - image->imageurl = NULL; - image->tilecache = NULL; - image->ntiles = 0; - image->resolution = resolution; - image->resolutionfactor = resolution/defresolution; - - if (imagepath) - image->imagepath = msStrdup(imagepath); - if (imageurl) - image->imageurl = msStrdup(imageurl); - } else if( MS_RENDERER_RAWDATA(format) ) { - if( format->imagemode != MS_IMAGEMODE_INT16 - && format->imagemode != MS_IMAGEMODE_FLOAT32 - && format->imagemode != MS_IMAGEMODE_BYTE ) { - msSetError(MS_IMGERR, - "Attempt to use illegal imagemode with rawdata renderer.", - "msImageCreate()" ); - return NULL; - } - - image = (imageObj *)calloc(1,sizeof(imageObj)); - if (image == NULL) { - msSetError(MS_MEMERR, "Unable to create new image object.", "msImageCreate()"); - return NULL; - } - - if( format->imagemode == MS_IMAGEMODE_INT16 ) - image->img.raw_16bit = (short *) - msSmallCalloc(sizeof(short),width*height*format->bands); - else if( format->imagemode == MS_IMAGEMODE_FLOAT32 ) - image->img.raw_float = (float *) - msSmallCalloc(sizeof(float),width*height*format->bands); - else if( format->imagemode == MS_IMAGEMODE_BYTE ) - image->img.raw_byte = (unsigned char *) - msSmallCalloc(sizeof(unsigned char),width*height*format->bands); - - if( image->img.raw_16bit == NULL ) { - msFree( image ); - msSetError(MS_IMGERR, - "Attempt to allocate raw image failed, out of memory.", - "msImageCreate()" ); - return NULL; - } - - image->img_mask = msAllocBitArray( width*height ); - - image->format = format; - format->refcount++; - - image->width = width; - image->height = height; - image->imagepath = NULL; - image->imageurl = NULL; - image->resolution = resolution; - image->resolutionfactor = resolution/defresolution; - - if (imagepath) - image->imagepath = msStrdup(imagepath); - if (imageurl) - image->imageurl = msStrdup(imageurl); - - /* initialize to requested nullvalue if there is one */ - if( msGetOutputFormatOption(image->format,"NULLVALUE",NULL) != NULL ) { - int i = image->width * image->height * format->bands; - const char *nullvalue = msGetOutputFormatOption(image->format, - "NULLVALUE",NULL); - - if( atof(nullvalue) == 0.0 ) - /* nothing to do */; - else if( format->imagemode == MS_IMAGEMODE_INT16 ) { - short nv = atoi(nullvalue); - for( ; i > 0; ) - image->img.raw_16bit[--i] = nv; - } else if( format->imagemode == MS_IMAGEMODE_FLOAT32 ) { - float nv = atof(nullvalue); - for( ; i > 0; ) - image->img.raw_float[--i] = nv; - } else if( format->imagemode == MS_IMAGEMODE_BYTE ) { - unsigned char nv = (unsigned char) atoi(nullvalue); - - memset( image->img.raw_byte, nv, i ); - } - } - } else if( MS_RENDERER_IMAGEMAP(format) ) { - image = msImageCreateIM(width, height, format, - imagepath, imageurl, resolution, defresolution); - } else { - msSetError(MS_MISCERR, - "Unsupported renderer requested, unable to initialize image.", - "msImageCreate()"); - return NULL; - } - - if(!image) - msSetError(MS_IMGERR, "Unable to initialize image.", "msImageCreate()"); - image->refpt.x = image->refpt.y = 0; - return image; -} - - -/** - * Generic function to transorm a point. - * - */ -void msTransformPoint(pointObj *point, rectObj *extent, double cellsize, - imageObj *image) -{ - double invcellsize; - /*We should probabaly have a function defined at all the renders*/ - if (image != NULL && MS_RENDERER_PLUGIN(image->format)) { - if(image->format->renderer == MS_RENDER_WITH_KML) { - return; - } - } - invcellsize = 1.0/cellsize; - point->x = MS_MAP2IMAGE_X_IC_DBL(point->x, extent->minx, invcellsize); - point->y = MS_MAP2IMAGE_Y_IC_DBL(point->y, extent->maxy, invcellsize); -} - - -/* -** Helper functions supplied as part of bug #2868 solution. Consider moving these to -** mapprimitive.c for more general use. -*/ - -/* vector difference */ -static pointObj point_diff(const pointObj a, const pointObj b) -{ - pointObj retv; - retv.x = a.x-b.x; - retv.y = a.y-b.y; -#ifdef USE_POINT_Z_M - retv.z = a.z-b.z; - retv.m = a.m-b.m; -#endif - return retv; -} - -/* vector sum */ -static pointObj point_sum(const pointObj a, const pointObj b) -{ - pointObj retv; - retv.x = a.x+b.x; - retv.y = a.y+b.y; -#ifdef USE_POINT_Z_M - retv.z = a.z+b.z; - retv.m = a.m+b.m; -#endif - return retv; -} - -/* vector multiply */ -static pointObj point_mul(const pointObj a, double b) -{ - pointObj retv; - retv.x = a.x*b; - retv.y = a.y*b; -#ifdef USE_POINT_Z_M - retv.z = a.z*b; - retv.m = a.m*b; -#endif - return retv; -} - -/* vector ??? */ -static double point_abs2(const pointObj a) -{ -#ifdef USE_POINT_Z_M - return a.x*a.x+a.y*a.y+a.z*a.z+a.m*a.m; -#else - return a.x*a.x+a.y*a.y; -#endif -} - -/* vector normal */ -static pointObj point_norm(const pointObj a) -{ - double lenmul; - pointObj retv; - int norm_vector; - - norm_vector = a.x==0 && a.y==0; -#ifdef USE_POINT_Z_M - norm_vector = norm_vector && a.z==0 && a.m==0; -#endif - if (norm_vector) - return a; - - lenmul=1.0/sqrt(point_abs2(a)); /* this seems to be the costly operation */ - - retv.x = a.x*lenmul; - retv.y = a.y*lenmul; -#ifdef USE_POINT_Z_M - retv.z = a.z*lenmul; - retv.m = a.m*lenmul; -#endif - - return retv; -} - -/* rotate a vector 90 degrees */ -static pointObj point_rotz90(const pointObj a) -{ - double nx=-1.0*a.y, ny=a.x; - pointObj retv=a; - retv.x=nx; - retv.y=ny; - return retv; -} - -/* vector cross product (warning: z and m dimensions are ignored!) */ -static double point_cross(const pointObj a, const pointObj b) -{ - return a.x*b.y-a.y*b.x; -} - -shapeObj *msOffsetCurve(shapeObj *p, double offset) -{ - shapeObj *ret; - int i, j, first,idx,ok=0; -#if defined USE_GEOS && (GEOS_VERSION_MAJOR > 3 || (GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR >= 3)) - ret = msGEOSOffsetCurve(p,offset); - /* GEOS curve offsetting can fail sometimes, we continue with our own implementation - if that is the case.*/ - if(ret) - return ret; - /* clear error raised by geos in this case */ - msResetErrorList(); -#endif - /* - ** For offset corner point calculation 1/sin() is used - ** to avoid 1/0 division (and long spikes) we define a - ** limit for sin(). - */ -#define CURVE_SIN_LIMIT 0.3 - ret = (shapeObj*)msSmallMalloc(sizeof(shapeObj)); - msInitShape(ret); - ret->numlines = p->numlines; - ret->line=(lineObj*)msSmallMalloc(sizeof(lineObj)*ret->numlines); - for(i=0; inumlines; i++) { - ret->line[i].numpoints=p->line[i].numpoints; - ret->line[i].point=(pointObj*)msSmallMalloc(sizeof(pointObj)*ret->line[i].numpoints); - } - for (i = 0; i < p->numlines; i++) { - pointObj old_pt = {0}, old_diffdir, old_offdir; - if(p->line[i].numpoints<2) { - ret->line[i].numpoints = 0; - continue; /* skip degenerate points */ - } - ok = 1; - /* initialize old_offdir and old_diffdir, as gcc isn't smart enough to see that it - * is not an error to do so, and prints a warning */ - old_offdir.x=old_offdir.y=old_diffdir.x=old_diffdir.y = 0; - - idx=0; - first = 1; - - /* saved metrics of the last processed point */ - if (p->line[i].numpoints>0) - old_pt=p->line[i].point[0]; - for(j=1; jline[i].numpoints; j++) { - const pointObj pt = p->line[i].point[j]; /* place of the point */ - const pointObj diffdir = point_norm(point_diff(pt,old_pt)); /* direction of the line */ - const pointObj offdir = point_rotz90(diffdir); /* direction where the distance between the line and the offset is measured */ - pointObj offpt; /* this will be the corner point of the offset line */ - - /* offset line points computation */ - if(first == 1) { /* first point */ - first = 0; - offpt = point_sum(old_pt,point_mul(offdir,offset)); - } else { /* middle points */ - /* curve is the angle of the last and the current line's direction (supplementary angle of the shape's inner angle) */ - double sin_curve = point_cross(diffdir,old_diffdir); - double cos_curve = point_cross(old_offdir,diffdir); - if ((-1.0)*CURVE_SIN_LIMIT < sin_curve && sin_curve < CURVE_SIN_LIMIT) { - /* do not calculate 1/sin, instead use a corner point approximation: average of the last and current offset direction and length */ - - /* - ** TODO: fair for obtuse inner angles, however, positive and negative - ** acute inner angles would need special handling - similar to LINECAP - ** to avoid drawing of long spikes - */ - offpt = point_sum(old_pt, point_mul(point_sum(offdir, old_offdir),0.5*offset)); - } else { - double base_shift = -1.0*(1.0+cos_curve)/sin_curve; - offpt = point_sum(old_pt, point_mul(point_sum(point_mul(diffdir,base_shift),offdir), offset)); - } - } - ret->line[i].point[idx]=offpt; - idx++; - old_pt=pt; - old_diffdir=diffdir; - old_offdir=offdir; - } - - /* last point */ - if(first == 0) { - pointObj offpt=point_sum(old_pt,point_mul(old_offdir,offset)); - ret->line[i].point[idx]=offpt; - idx++; - } - - if(idx != p->line[i].numpoints) { - /* printf("shouldn't happen :(\n"); */ - ret->line[i].numpoints=idx; - ret->line=msSmallRealloc(ret->line,ret->line[i].numpoints*sizeof(pointObj)); - } - } - if(!ok) ret->numlines = 0; /* all lines where degenerate */ - return ret; -} - -shapeObj *msOffsetPolyline(shapeObj *p, double offsetx, double offsety) -{ - int i, j; - shapeObj *ret; - if(offsety == MS_STYLE_SINGLE_SIDED_OFFSET) { /* complex calculations */ - return msOffsetCurve(p,offsetx); - } else if(offsety == MS_STYLE_DOUBLE_SIDED_OFFSET) { - shapeObj *tmp1; - ret = msOffsetCurve(p,offsetx/2.0); - tmp1 = msOffsetCurve(p, -offsetx/2.0); - for(i=0;inumlines; i++) { - msAddLineDirectly(ret,tmp1->line + i); - } - msFreeShape(tmp1); - free(tmp1); - return ret; - } - - ret = (shapeObj*)msSmallMalloc(sizeof(shapeObj)); - msInitShape(ret); - ret->numlines = p->numlines; - ret->line=(lineObj*)msSmallMalloc(sizeof(lineObj)*ret->numlines); - for(i=0; inumlines; i++) { - ret->line[i].numpoints=p->line[i].numpoints; - ret->line[i].point=(pointObj*)msSmallMalloc(sizeof(pointObj)*ret->line[i].numpoints); - } - - for (i = 0; i < p->numlines; i++) { - for(j=0; jline[i].numpoints; j++) { - ret->line[i].point[j].x=p->line[i].point[j].x+offsetx; - ret->line[i].point[j].y=p->line[i].point[j].y+offsety; - } - } - - return ret; -} - -/* -------------------------------------------------------------------------------- - msSetup() - - Contributed by Jerry Pisk in bug 1203. Heads off potential race condition - in initializing GD font cache with multiple threads. Should be called from - mapscript module initialization code. -------------------------------------------------------------------------------- -*/ - -int msSetup() -{ -#ifdef _WIN32 - char* maxfiles = getenv("MS_MAX_OPEN_FILES"); - if (maxfiles) { - int res = _getmaxstdio(); - if (res < 2048) { - res = _setmaxstdio(atoi(maxfiles)); - assert(res != -1); - } - } -#endif - -#ifdef USE_THREAD - msThreadInit(); -#endif - - /* Use PROJ_LIB env vars if set */ - msProjLibInitFromEnv(); - - /* Use MS_ERRORFILE and MS_DEBUGLEVEL env vars if set */ - if (msDebugInitFromEnv() != MS_SUCCESS) - return MS_FAILURE; - -#ifdef USE_GEOS - msGEOSSetup(); -#endif - -#ifdef USE_RSVG -#if !GLIB_CHECK_VERSION(2, 35, 0) - g_type_init(); -#endif -#endif - - msFontCacheSetup(); - - - return MS_SUCCESS; -} - -/* This is intended to be a function to cleanup anything that "hangs around" - when all maps are destroyed, like Registered GDAL drivers, and so forth. */ -#ifndef NDEBUG -#if defined(USE_LIBXML2) -#include "maplibxml2.h" -#endif -#endif -void msCleanup() -{ - msForceTmpFileBase( NULL ); - msConnPoolFinalCleanup(); - /* Lexer string parsing variable */ - if (msyystring_buffer != NULL) { - msFree(msyystring_buffer); - msyystring_buffer = NULL; - } - msyylex_destroy(); - - msOGRCleanup(); - msGDALCleanup(); - - /* Release both GDAL and OGR resources */ - msAcquireLock( TLOCK_GDAL ); -#if GDAL_VERSION_MAJOR >= 3 || (GDAL_VERSION_MAJOR == 2 && GDAL_VERSION_MINOR == 4) - /* Cleanup some GDAL global resources in particular */ - GDALDestroy(); -#else - GDALDestroyDriverManager(); -#endif - msReleaseLock( TLOCK_GDAL ); - - -#if PROJ_VERSION_MAJOR < 6 -# if PJ_VERSION >= 480 - pj_clear_initcache(); -# endif - pj_deallocate_grids(); -#endif - msSetPROJ_LIB( NULL, NULL ); - msProjectionContextPoolCleanup(); - -#if defined(USE_CURL) - msHTTPCleanup(); -#endif - -#ifdef USE_GEOS - msGEOSCleanup(); -#endif - -/* make valgrind happy on debug code */ -#ifndef NDEBUG -#ifdef USE_CAIRO - msCairoCleanup(); -#endif -#if defined(USE_LIBXML2) - xmlCleanupParser(); -#endif -#endif - - msFontCacheCleanup(); - - msTimeCleanup(); - - msIO_Cleanup(); - - msResetErrorList(); - - /* Close/cleanup log/debug output. Keep this at the very end. */ - msDebugCleanup(); - - /* Clean up the vtable factory */ - msPluginFreeVirtualTableFactory(); -} - -/************************************************************************/ -/* msAlphaBlend() */ -/* */ -/* Function to overlay/blend an RGBA value into an existing */ -/* RGBA value using the Porter-Duff "over" operator. */ -/* Primarily intended for use with rasterBufferObj */ -/* raster rendering. The "src" is the overlay value, and "dst" */ -/* is the existing value being overlaid. dst is expected to be */ -/* premultiplied, but the source should not be. */ -/* */ -/* NOTE: alpha_dst may be NULL. */ -/************************************************************************/ - -void msAlphaBlend( unsigned char red_src, unsigned char green_src, - unsigned char blue_src, unsigned char alpha_src, - unsigned char *red_dst, unsigned char *green_dst, - unsigned char *blue_dst, unsigned char *alpha_dst ) -{ - /* -------------------------------------------------------------------- */ - /* Simple cases we want to handle fast. */ - /* -------------------------------------------------------------------- */ - if( alpha_src == 0 ) - return; - - if( alpha_src == 255 ) { - *red_dst = red_src; - *green_dst = green_src; - *blue_dst = blue_src; - if( alpha_dst ) - *alpha_dst = 255; - return; - } - - /* -------------------------------------------------------------------- */ - /* Premultiple alpha for source values now. */ - /* -------------------------------------------------------------------- */ - red_src = red_src * alpha_src / 255; - green_src = green_src * alpha_src / 255; - blue_src = blue_src * alpha_src / 255; - - /* -------------------------------------------------------------------- */ - /* Another pretty fast case if there is nothing in the */ - /* destination to mix with. */ - /* -------------------------------------------------------------------- */ - if( alpha_dst && *alpha_dst == 0) { - *red_dst = red_src; - *green_dst = green_src; - *blue_dst = blue_src; - *alpha_dst = alpha_src; - return; - } - - /* -------------------------------------------------------------------- */ - /* Cases with actual blending. */ - /* -------------------------------------------------------------------- */ - if(!alpha_dst || *alpha_dst == 255) { - int weight_dst = 256 - alpha_src; - - *red_dst = (256 * red_src + *red_dst * weight_dst) >> 8; - *green_dst = (256 * green_src + *green_dst * weight_dst) >> 8; - *blue_dst = (256 * blue_src + *blue_dst * weight_dst) >> 8; - } else { - int weight_dst = (256 - alpha_src); - - *red_dst = (256 * red_src + *red_dst * weight_dst) >> 8; - *green_dst = (256 * green_src + *green_dst * weight_dst) >> 8; - *blue_dst = (256 * blue_src + *blue_dst * weight_dst) >> 8; - - *alpha_dst = (256 * alpha_src + *alpha_dst * weight_dst) >> 8; - } -} - -/************************************************************************/ -/* msAlphaBlendPM() */ -/* */ -/* Same as msAlphaBlend() except that the source RGBA is */ -/* assumed to already be premultiplied. */ -/************************************************************************/ - -void msAlphaBlendPM( unsigned char red_src, unsigned char green_src, - unsigned char blue_src, unsigned char alpha_src, - unsigned char *red_dst, unsigned char *green_dst, - unsigned char *blue_dst, unsigned char *alpha_dst ) -{ - /* -------------------------------------------------------------------- */ - /* Simple cases we want to handle fast. */ - /* -------------------------------------------------------------------- */ - if( alpha_src == 0 ) - return; - - if( alpha_src == 255 ) { - *red_dst = red_src; - *green_dst = green_src; - *blue_dst = blue_src; - if( alpha_dst ) - *alpha_dst = 255; - return; - } - - /* -------------------------------------------------------------------- */ - /* Another pretty fast case if there is nothing in the */ - /* destination to mix with. */ - /* -------------------------------------------------------------------- */ - if( alpha_dst && *alpha_dst == 0) { - *red_dst = red_src; - *green_dst = green_src; - *blue_dst = blue_src; - *alpha_dst = alpha_src; - return; - } - - /* -------------------------------------------------------------------- */ - /* Cases with actual blending. */ - /* -------------------------------------------------------------------- */ - if(!alpha_dst || *alpha_dst == 255) { - int weight_dst = 255 - alpha_src; - - *red_dst = (alpha_src * red_src + *red_dst * weight_dst) >> 8; - *green_dst = (alpha_src * green_src + *green_dst * weight_dst) >> 8; - *blue_dst = (alpha_src * blue_src + *blue_dst * weight_dst) >> 8; - } else { - int weight_dst = (255 - alpha_src); - - *red_dst = (alpha_src * red_src + *red_dst * weight_dst) >> 8; - *green_dst = (alpha_src * green_src + *green_dst * weight_dst) >> 8; - *blue_dst = (alpha_src * blue_src + *blue_dst * weight_dst) >> 8; - - *alpha_dst = (255 * alpha_src + *alpha_dst * weight_dst) >> 8; - } -} - -void msRGBtoHSL(colorObj *rgb, double *h, double *s, double *l) { - double r = rgb->red/255.0, g = rgb->green/255.0, b = rgb->blue/255.0; - double maxv = MS_MAX(MS_MAX(r, g), b), minv = MS_MIN(MS_MIN(r, g), b); - double d = maxv - minv; - - *h = 0, *s = 0; - *l = (maxv + minv) / 2; - - if (maxv != minv) - { - *s = *l > 0.5 ? d / (2 - maxv - minv) : d / (maxv + minv); - if (maxv == r) { *h = (g - b) / d + (g < b ? 6 : 0); } - else if (maxv == g) { *h = (b - r) / d + 2; } - else if (maxv == b) { *h = (r - g) / d + 4; } - *h /= 6; - } -} - -static double hue_to_rgb(double p, double q, double t) { - if(t < 0) t += 1; - if(t > 1) t -= 1; - if(t < 0.1666666666666666) return p + (q - p) * 6 * t; - if(t < 0.5) return q; - if(t < 0.6666666666666666) return p + (q - p) * (0.666666666666 - t) * 6; - return p; -} - -void msHSLtoRGB(double h, double s, double l, colorObj *rgb) { - double r, g, b; - - if(s == 0){ - r = g = b = l; - } else { - - double q = l < 0.5 ? l * (1 + s) : l + s - l * s; - double p = 2 * l - q; - r = hue_to_rgb(p, q, h + 0.33333333333333333); - g = hue_to_rgb(p, q, h); - b = hue_to_rgb(p, q, h - 0.33333333333333333); - } - rgb->red = r * 255; - rgb->green = g * 255; - rgb->blue = b * 255; -} - -/* - RFC 24: check if the parent pointer is NULL and raise an error otherwise -*/ -int msCheckParentPointer(void* p, const char *objname) -{ - char* msg=NULL; - if (p == NULL) { - if(objname != NULL) { - msSetError(MS_NULLPARENTERR, "The %s parent object is null", "msCheckParentPointer()", msg); - } else { - msSetError(MS_NULLPARENTERR, "The parent object is null", "msCheckParentPointer()"); - } - return MS_FAILURE; - } - return MS_SUCCESS; -} - -void msBufferInit(bufferObj *buffer) -{ - buffer->data=NULL; - buffer->size=0; - buffer->available=0; - buffer->_next_allocation_size = MS_DEFAULT_BUFFER_ALLOC; -} - -void msBufferResize(bufferObj *buffer, size_t target_size) -{ - while(buffer->available <= target_size) { - buffer->data = msSmallRealloc(buffer->data,buffer->available+buffer->_next_allocation_size); - buffer->available += buffer->_next_allocation_size; - buffer->_next_allocation_size *= 2; - } -} - -void msBufferAppend(bufferObj *buffer, void *data, size_t length) -{ - if(buffer->available < buffer->size+length) { - msBufferResize(buffer,buffer->size+length); - } - memcpy(&(buffer->data[buffer->size]),data,length); - buffer->size += length; -} - -void msBufferFree(bufferObj *buffer) -{ - if(buffer->available>0) - free(buffer->data); -} - - -void msFreeRasterBuffer(rasterBufferObj *b) -{ - switch(b->type) { - case MS_BUFFER_BYTE_RGBA: - msFree(b->data.rgba.pixels); - b->data.rgba.pixels = NULL; - break; - case MS_BUFFER_BYTE_PALETTE: - msFree(b->data.palette.pixels); - msFree(b->data.palette.palette); - b->data.palette.pixels = NULL; - b->data.palette.palette = NULL; - break; - } - -} - -/* -** Issue #3043: Layer extent comparison short circuit. -** -** msExtentsOverlap() -** -** Returns MS_TRUE if map extent and layer extent overlap, -** MS_FALSE if they are disjoint, and MS_UNKNOWN if there is -** not enough info to calculate a deterministic answer. -** -*/ -int msExtentsOverlap(mapObj *map, layerObj *layer) -{ - rectObj map_extent; - rectObj layer_extent; - - /* No extent info? Nothing we can do, return MS_UNKNOWN. */ - if( (map->extent.minx == -1) && (map->extent.miny == -1) && (map->extent.maxx == -1 ) && (map->extent.maxy == -1) ) return MS_UNKNOWN; - if( (layer->extent.minx == -1) && (layer->extent.miny == -1) && (layer->extent.maxx == -1 ) && (layer->extent.maxy == -1) ) return MS_UNKNOWN; - - /* No map projection? Let someone else sort this out. */ - if( ! (map->projection.numargs > 0) ) - return MS_UNKNOWN; - - /* No layer projection? Perform naive comparison, because they are - ** in the same projection. */ - if( ! (layer->projection.numargs > 0) ) - return msRectOverlap( &(map->extent), &(layer->extent) ); - - /* In the case where map and layer projections are identical, and the */ - /* bounding boxes don't cross the dateline, do simple rectangle comparison */ - if( map->extent.minx < map->extent.maxx && - layer->extent.minx < layer->extent.maxx && - !msProjectionsDiffer(&(map->projection), &(layer->projection)) ) { - return msRectOverlap( &(map->extent), &(layer->extent) ); - } - - /* We need to transform our rectangles for comparison, - ** so we will work with copies and leave the originals intact. */ - MS_COPYRECT(&map_extent, &(map->extent) ); - MS_COPYRECT(&layer_extent, &(layer->extent) ); - - /* Transform map extents into geographics for comparison. */ - if( msProjectRect(&(map->projection), &(map->latlon), &map_extent) ) - return MS_UNKNOWN; - - /* Transform layer extents into geographics for comparison. */ - if( msProjectRect(&(layer->projection), &(map->latlon), &layer_extent) ) - return MS_UNKNOWN; - - /* Simple case? Return simple answer. */ - if ( map_extent.minx < map_extent.maxx && layer_extent.minx < layer_extent.maxx ) - return msRectOverlap( &(map_extent), &(layer_extent) ); - - /* Uh oh, one of the rects crosses the dateline! - ** Let someone else handle it. */ - return MS_UNKNOWN; -} - -/************************************************************************/ -/* msSmallMalloc() */ -/************************************************************************/ - -/* Safe version of malloc(). This function is taken from gdal/cpl. */ - -void *msSmallMalloc( size_t nSize ) -{ - void *pReturn; - - if( UNLIKELY(nSize == 0) ) - return NULL; - - pReturn = malloc( nSize ); - if( UNLIKELY(pReturn == NULL) ) { - msIO_fprintf(stderr, "msSmallMalloc(): Out of memory allocating %ld bytes.\n", - (long) nSize ); - exit(1); - } - - return pReturn; -} - -/************************************************************************/ -/* msSmallRealloc() */ -/************************************************************************/ - -/* Safe version of realloc(). This function is taken from gdal/cpl. */ - -void * msSmallRealloc( void * pData, size_t nNewSize ) -{ - void *pReturn; - - if ( UNLIKELY(nNewSize == 0) ) - return NULL; - - pReturn = realloc( pData, nNewSize ); - - if( UNLIKELY(pReturn == NULL) ) { - msIO_fprintf(stderr, "msSmallRealloc(): Out of memory allocating %ld bytes.\n", - (long)nNewSize ); - exit(1); - } - - return pReturn; -} - -/************************************************************************/ -/* msSmallCalloc() */ -/************************************************************************/ - -/* Safe version of calloc(). This function is taken from gdal/cpl. */ - -void *msSmallCalloc( size_t nCount, size_t nSize ) -{ - void *pReturn; - - if( UNLIKELY(nSize * nCount == 0) ) - return NULL; - - pReturn = calloc( nCount, nSize ); - if( UNLIKELY(pReturn == NULL) ) { - msIO_fprintf(stderr, "msSmallCalloc(): Out of memory allocating %ld bytes.\n", - (long)(nCount*nSize)); - exit(1); - } - - return pReturn; -} - -/* -** msBuildOnlineResource() -** -** Try to build the online resource (mapserv URL) for this service. -** "http://$(SERVER_NAME):$(SERVER_PORT)$(SCRIPT_NAME)?" -** (+append the map=... param if it was explicitly passed in QUERY_STRING) -** -** Returns a newly allocated string that should be freed by the caller or -** NULL in case of error. -*/ -char *msBuildOnlineResource(mapObj *map, cgiRequestObj *req) -{ - char *online_resource = NULL; - const char *value, *hostname, *port, *script, *protocol="http", *mapparam=NULL; - char **hostname_array = NULL; - int mapparam_len = 0, hostname_array_len = 0; - - hostname = getenv("HTTP_X_FORWARDED_HOST"); - if(!hostname) - hostname = getenv("SERVER_NAME"); - else { - if(strchr(hostname,',')) { - hostname_array = msStringSplit(hostname,',', &hostname_array_len); - hostname = hostname_array[0]; - } - } - - port = getenv("HTTP_X_FORWARDED_PORT"); - if(!port) - port = getenv("SERVER_PORT"); - - script = getenv("SCRIPT_NAME"); - - /* HTTPS is set by Apache to "on" in an HTTPS server ... if not set */ - /* then check SERVER_PORT: 443 is the default https port. */ - if ( ((value=getenv("HTTPS")) && strcasecmp(value, "on") == 0) || - ((value=getenv("SERVER_PORT")) && atoi(value) == 443) ) { - protocol = "https"; - } - if ( (value=getenv("HTTP_X_FORWARDED_PROTO")) ) { - protocol = value; - } - - /* If map=.. was explicitly set then we'll include it in onlineresource - */ - if (req->type == MS_GET_REQUEST) { - int i; - for(i=0; iNumParams; i++) { - if (strcasecmp(req->ParamNames[i], "map") == 0) { - mapparam = req->ParamValues[i]; - mapparam_len = strlen(mapparam)+5; /* +5 for "map="+"&" */ - break; - } - } - } - - if (hostname && port && script) { - size_t buffer_size; - buffer_size = strlen(hostname)+strlen(port)+strlen(script)+mapparam_len+11; /* 11 comes from https://[host]:[port][scriptname]?[map]\0, i.e. "https://:?\0" */ - online_resource = (char*)msSmallMalloc(buffer_size); - if ((atoi(port) == 80 && strcmp(protocol, "http") == 0) || - (atoi(port) == 443 && strcmp(protocol, "https") == 0) ) - snprintf(online_resource, buffer_size, "%s://%s%s?", protocol, hostname, script); - else - snprintf(online_resource, buffer_size, "%s://%s:%s%s?", protocol, hostname, port, script); - - if (mapparam) { - int baselen; - baselen = strlen(online_resource); - snprintf(online_resource+baselen, buffer_size-baselen, "map=%s&", mapparam); - } - } else { - msSetError(MS_CGIERR, "Impossible to establish server URL.", "msBuildOnlineResource()"); - return NULL; - } - if(hostname_array) { - msFreeCharArray(hostname_array, hostname_array_len); - } - - return online_resource; -} - - -/************************************************************************/ -/* msIntegerInArray() */ -/************************************************************************/ - -/* Check if a integer is in a array */ -int msIntegerInArray(const int value, int *array, int numelements) -{ - int i; - for (i=0; iprojection.numargs <= 0) { - msSetError(MS_WMSERR, "Cannot set new SRS on a map that doesn't " - "have any projection set. Please make sure your mapfile " - "has a PROJECTION defined at the top level.", - "msTileSetProjectionst()"); - return(MS_FAILURE); - } - - for(i=0; inumlayers; i++) { - layerObj *lp = GET_LAYER(map,i); - /* This layer is turned on and needs a projection? */ - if (lp->projection.numargs <= 0 && - lp->status != MS_OFF && - lp->transform == MS_TRUE) { - - /* Fetch main map projection string only now that we need it */ - if (mapProjStr == NULL) - mapProjStr = msGetProjectionString(&(map->projection)); - - /* Set the projection to the map file projection */ - if (msLoadProjectionString(&(lp->projection), mapProjStr) != 0) { - msSetError(MS_CGIERR, "Unable to set projection on layer.", "msMapSetLayerProjections()"); - return(MS_FAILURE); - } - lp->project = MS_TRUE; - if(lp->connection && IS_THIRDPARTY_LAYER_CONNECTIONTYPE(lp->connectiontype)) { - char **reflayers; - int numreflayers,j; - reflayers = msStringSplit(lp->connection,',',&numreflayers); - for(j=0; jprojection.numargs <= 0 && glp->transform == MS_TRUE) { - - /* Set the projection to the map file projection */ - if (msLoadProjectionString(&(glp->projection), mapProjStr) != 0) { - msSetError(MS_CGIERR, "Unable to set projection on layer.", "msMapSetLayerProjections()"); - return(MS_FAILURE); - } - glp->project = MS_TRUE; - } - } - free(lidx); - } else { - /* group name did not match, check by layer name */ - int layer_idx = msGetLayerIndex(map,lp->connection); - layerObj *glp = GET_LAYER(map,layer_idx); - if (glp->projection.numargs <= 0 && glp->transform == MS_TRUE) { - - /* Set the projection to the map file projection */ - if (msLoadProjectionString(&(glp->projection), mapProjStr) != 0) { - msSetError(MS_CGIERR, "Unable to set projection on layer.", "msMapSetLayerProjections()"); - return(MS_FAILURE); - } - glp->project = MS_TRUE; - } - } - } - msFreeCharArray(reflayers, numreflayers); - } - } - } - msFree(mapProjStr); - return(MS_SUCCESS); -} - - -/************************************************************************ - * msMapSetLanguageSpecificConnection * - * * - * Override DATA and CONNECTION of each layer with their specific * - * variant for the specified language. * - ************************************************************************/ - -void msMapSetLanguageSpecificConnection(mapObj* map, const char* validated_language) -{ - int i; - for(i=0; inumlayers; i++) { - layerObj *layer = GET_LAYER(map, i); - if(layer->data) layer->data = msCaseReplaceSubstring(layer->data, "%language%", validated_language); - if(layer->connection) layer->connection = msCaseReplaceSubstring(layer->connection, "%language%", validated_language); - } -} - -/* Generalize a shape based of the tolerance. - Ref: http://trac.osgeo.org/gdal/ticket/966 */ -shapeObj* msGeneralize(shapeObj *shape, double tolerance) -{ - lineObj newLine = {0,NULL}; - const double sqTolerance = tolerance*tolerance; - - shapeObj* newShape = (shapeObj*)msSmallMalloc(sizeof(shapeObj)); - msInitShape(newShape); - msCopyShape(shape, newShape); - - if (shape->numlines<1) - return newShape; - - /* Clean shape */ - for (int i=0; i < newShape->numlines; i++) - free(newShape->line[i].point); - newShape->numlines = 0; - if (newShape->line) free(newShape->line); - - msAddLine(newShape, &newLine); - - if (shape->line[0].numpoints==0) { - return newShape; - } - - msAddPointToLine(&newShape->line[0], - &shape->line[0].point[0]); - double dX0 = shape->line[0].point[0].x; - double dY0 = shape->line[0].point[0].y; - - for(int i=1; iline[0].numpoints; i++) - { - double dX1 = shape->line[0].point[i].x; - double dY1 = shape->line[0].point[i].y; - - const double dX = dX1-dX0; - const double dY = dY1-dY0; - const double dSqDist = dX*dX + dY*dY; - if (i == shape->line[0].numpoints-1 || dSqDist >= sqTolerance) - { - pointObj p; - p.x = dX1; - p.y = dY1; - - /* Keep this point (always keep the last point) */ - msAddPointToLine(&newShape->line[0], - &p); - dX0 = dX1; - dY0 = dY1; - } - } - - return newShape; -} - -void msSetLayerOpacity(layerObj *layer, int opacity) { - if(!layer->compositer) { - layer->compositer = msSmallMalloc(sizeof(LayerCompositer)); - initLayerCompositer(layer->compositer); - } - layer->compositer->opacity = opacity; -} diff --git a/mapuvraster.c b/mapuvraster.c deleted file mode 100644 index cc5a51b547..0000000000 --- a/mapuvraster.c +++ /dev/null @@ -1,1078 +0,0 @@ -/********************************************************************** - * $Id: mapuv.c 12629 2011-10-06 18:06:34Z aboudreault $ - * - * Project: MapServer - * Purpose: UV Layer - * Author: Alan Boudreault (aboudreault@mapgears.com) - * - ********************************************************************** - * Copyright (c) 2011, Alan Boudreault, MapGears - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies of this Software or works derived from this Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - **********************************************************************/ - -#include "mapserver.h" - -#include -#include -#include "mapows.h" -#include "mapresample.h" -#include "mapthread.h" - -#define MSUVRASTER_NUMITEMS 6 -#define MSUVRASTER_ANGLE "uv_angle" -#define MSUVRASTER_ANGLEINDEX -100 -#define MSUVRASTER_MINUS_ANGLE "uv_minus_angle" -#define MSUVRASTER_MINUSANGLEINDEX -101 -#define MSUVRASTER_LENGTH "uv_length" -#define MSUVRASTER_LENGTHINDEX -102 -#define MSUVRASTER_LENGTH_2 "uv_length_2" -#define MSUVRASTER_LENGTH2INDEX -103 -#define MSUVRASTER_U "u" -#define MSUVRASTER_UINDEX -104 -#define MSUVRASTER_V "v" -#define MSUVRASTER_VINDEX -105 - -#define RQM_UNKNOWN 0 -#define RQM_ENTRY_PER_PIXEL 1 -#define RQM_HIST_ON_CLASS 2 -#define RQM_HIST_ON_VALUE 3 - -typedef struct { - - /* query cache results */ - int query_results; - /* int query_alloc_max; - int query_request_max; - int query_result_hard_max; - int raster_query_mode; */ - int band_count; - - int refcount; - - /* query bound in force - shapeObj *searchshape;*/ - - /* Only nearest result to this point. - int range_mode; MS_QUERY_SINGLE, MS_QUERY_MULTIPLE or -1 (skip test) - double range_dist; - pointObj target_point;*/ - - /* double shape_tolerance; */ - - float **u; /* u values */ - float **v; /* v values */ - int width; - int height; - rectObj extent; - int next_shape; - int x, y; /* used internally in msUVRasterLayerNextShape() */ - - mapObj* mapToUseForWhichShapes; /* set if the map->extent and map->projection are valid in msUVRASTERLayerWhichShapes() */ - -} uvRasterLayerInfo; - -void msUVRASTERLayerUseMapExtentAndProjectionForNextWhichShapes(layerObj* layer, - mapObj* map) -{ - uvRasterLayerInfo *uvlinfo = (uvRasterLayerInfo *) layer->layerinfo; - uvlinfo->mapToUseForWhichShapes = map; -} - -static int msUVRASTERLayerInitItemInfo(layerObj *layer) -{ - uvRasterLayerInfo *uvlinfo = (uvRasterLayerInfo *) layer->layerinfo; - int i; - int *itemindexes; - int failed=0; - - if (layer->numitems == 0) - return MS_SUCCESS; - - if( uvlinfo == NULL ) { - msSetError(MS_MISCERR, "Assertion failed: GDAL layer not opened!!!", - "msUVRASTERLayerInitItemInfo()"); - return(MS_FAILURE); - } - - if (layer->iteminfo) - free(layer->iteminfo); - - if((layer->iteminfo = (int *)malloc(sizeof(int)*layer->numitems))== NULL) { - msSetError(MS_MEMERR, NULL, "msUVRASTERLayerInitItemInfo()"); - return(MS_FAILURE); - } - - itemindexes = (int*)layer->iteminfo; - for(i=0; inumitems; i++) { - /* Special case for handling text string and angle coming from */ - /* OGR style strings. We use special attribute snames. */ - if (EQUAL(layer->items[i], MSUVRASTER_ANGLE)) - itemindexes[i] = MSUVRASTER_ANGLEINDEX; - else if (EQUAL(layer->items[i], MSUVRASTER_MINUS_ANGLE)) - itemindexes[i] = MSUVRASTER_MINUSANGLEINDEX; - else if (EQUAL(layer->items[i], MSUVRASTER_LENGTH)) - itemindexes[i] = MSUVRASTER_LENGTHINDEX; - else if (EQUAL(layer->items[i], MSUVRASTER_LENGTH_2)) - itemindexes[i] = MSUVRASTER_LENGTH2INDEX; - else if (EQUAL(layer->items[i], MSUVRASTER_U)) - itemindexes[i] = MSUVRASTER_UINDEX; - else if (EQUAL(layer->items[i], MSUVRASTER_V)) - itemindexes[i] = MSUVRASTER_VINDEX; - else { - itemindexes[i] = -1; - msSetError(MS_OGRERR, - "Invalid Field name: %s", - "msUVRASTERLayerInitItemInfo()", - layer->items[i]); - failed=1; - } - } - - return failed ? (MS_FAILURE) : (MS_SUCCESS); -} - - -void msUVRASTERLayerFreeItemInfo(layerObj *layer) -{ - if (layer->iteminfo) - free(layer->iteminfo); - layer->iteminfo = NULL; -} - -static void msUVRasterLayerInfoInitialize(layerObj *layer) -{ - uvRasterLayerInfo *uvlinfo = (uvRasterLayerInfo *) layer->layerinfo; - - if( uvlinfo != NULL ) - return; - - uvlinfo = (uvRasterLayerInfo *) msSmallCalloc(1,sizeof(uvRasterLayerInfo)); - layer->layerinfo = uvlinfo; - - uvlinfo->band_count = -1; - /* uvlinfo->raster_query_mode = RQM_ENTRY_PER_PIXEL; */ - /* uvlinfo->range_mode = -1; /\* inactive *\/ */ - /* uvlinfo->refcount = 0; */ - /* uvlinfo->shape_tolerance = 0.0; */ - uvlinfo->u = NULL; - uvlinfo->v = NULL; - uvlinfo->width = 0; - uvlinfo->height = 0; - - /* Set attribute type to Real, unless the user has explicitly set */ - /* something else. */ - { - const char* const items[] = { - MSUVRASTER_ANGLE, - MSUVRASTER_MINUS_ANGLE, - MSUVRASTER_LENGTH, - MSUVRASTER_LENGTH_2, - MSUVRASTER_U, - MSUVRASTER_V, - }; - size_t i; - for( i = 0; i < sizeof(items)/sizeof(items[0]); ++i ) { - char szTmp[100]; - snprintf(szTmp, sizeof(szTmp), "%s_type", items[i]); - if (msOWSLookupMetadata(&(layer->metadata), "OFG", szTmp) == NULL) { - snprintf(szTmp, sizeof(szTmp), "gml_%s_type", items[i]); - msInsertHashTable(&(layer->metadata), szTmp, "Real"); - } - } - } - - /* uvlinfo->query_result_hard_max = 1000000; */ - - /* if( CSLFetchNameValue( layer->processing, "RASTER_QUERY_MAX_RESULT" ) */ - /* != NULL ) */ - /* { */ - /* uvlinfo->query_result_hard_max = */ - /* atoi(CSLFetchNameValue( layer->processing, "RASTER_QUERY_MAX_RESULT" )); */ - /* } */ -} - -static void msUVRasterLayerInfoFree( layerObj *layer ) - -{ - uvRasterLayerInfo *uvlinfo = (uvRasterLayerInfo *) layer->layerinfo; - int i; - - if( uvlinfo == NULL ) - return; - - if (uvlinfo->u) { - for (i=0; iwidth; ++i) { - free(uvlinfo->u[i]); - } - free(uvlinfo->u); - } - - if (uvlinfo->v) { - for (i=0; iwidth; ++i) { - free(uvlinfo->v[i]); - } - free(uvlinfo->v); - } - - free( uvlinfo ); - - layer->layerinfo = NULL; -} - -int msUVRASTERLayerOpen(layerObj *layer) -{ - uvRasterLayerInfo *uvlinfo; - - /* If we don't have info, initialize an empty one now */ - if( layer->layerinfo == NULL ) - msUVRasterLayerInfoInitialize( layer ); - - uvlinfo = (uvRasterLayerInfo *) layer->layerinfo; - - uvlinfo->refcount = uvlinfo->refcount + 1; - - return MS_SUCCESS; -} - -int msUVRASTERLayerIsOpen(layerObj *layer) -{ - if (layer->layerinfo) - return MS_TRUE; - return MS_FALSE; -} - - -int msUVRASTERLayerClose(layerObj *layer) -{ - uvRasterLayerInfo *uvlinfo = (uvRasterLayerInfo *) layer->layerinfo; - - if( uvlinfo != NULL ) { - uvlinfo->refcount--; - - if( uvlinfo->refcount < 1 ) - msUVRasterLayerInfoFree( layer ); - } - return MS_SUCCESS; -} - -int msUVRASTERLayerGetItems(layerObj *layer) -{ - uvRasterLayerInfo *uvlinfo = (uvRasterLayerInfo *) layer->layerinfo; - - if( uvlinfo == NULL ) - return MS_FAILURE; - - layer->numitems = 0; - layer->items = (char **) msSmallCalloc(sizeof(char *),10);; - - layer->items[layer->numitems++] = msStrdup(MSUVRASTER_ANGLE); - layer->items[layer->numitems++] = msStrdup(MSUVRASTER_MINUS_ANGLE); - layer->items[layer->numitems++] = msStrdup(MSUVRASTER_LENGTH); - layer->items[layer->numitems++] = msStrdup(MSUVRASTER_LENGTH_2); - layer->items[layer->numitems++] = msStrdup(MSUVRASTER_U); - layer->items[layer->numitems++] = msStrdup(MSUVRASTER_V); - layer->items[layer->numitems] = NULL; - - return msUVRASTERLayerInitItemInfo(layer); -} - -/********************************************************************** - * msUVRASTERGetValues() - * - * Special attribute names are used to return some UV params: uv_angle, - * uv_length, u and v. - **********************************************************************/ -static char **msUVRASTERGetValues(layerObj *layer, float *u, float *v) -{ - char **values; - int i = 0; - char tmp[100]; - float size_scale; - int *itemindexes = (int*)layer->iteminfo; - - if(layer->numitems == 0) - return(NULL); - - if(!layer->iteminfo) { /* Should not happen... but just in case! */ - if (msUVRASTERLayerInitItemInfo(layer) != MS_SUCCESS) - return NULL; - itemindexes = (int*)layer->iteminfo; /* reassign after malloc */ - } - - if((values = (char **)malloc(sizeof(char *)*layer->numitems)) == NULL) { - msSetError(MS_MEMERR, NULL, "msUVRASTERGetValues()"); - return(NULL); - } - - /* -------------------------------------------------------------------- */ - /* Determine desired size_scale. Default to 1 if not otherwise set */ - /* -------------------------------------------------------------------- */ - size_scale = 1; - if( CSLFetchNameValue( layer->processing, "UV_SIZE_SCALE" ) != NULL ) { - size_scale = - atof(CSLFetchNameValue( layer->processing, "UV_SIZE_SCALE" )); - } - - for(i=0; inumitems; i++) { - if (itemindexes[i] == MSUVRASTER_ANGLEINDEX) { - snprintf(tmp, 100, "%f", (atan2((double)*v, (double)*u) * 180 / MS_PI)); - values[i] = msStrdup(tmp); - } else if (itemindexes[i] == MSUVRASTER_MINUSANGLEINDEX) { - double minus_angle; - minus_angle = (atan2((double)*v, (double)*u) * 180 / MS_PI)+180; - if (minus_angle >= 360) - minus_angle -= 360; - snprintf(tmp, 100, "%f", minus_angle); - values[i] = msStrdup(tmp); - } else if ( (itemindexes[i] == MSUVRASTER_LENGTHINDEX) || - (itemindexes[i] == MSUVRASTER_LENGTH2INDEX) ) { - float length = sqrt((*u**u)+(*v**v))*size_scale; - - if (itemindexes[i] == MSUVRASTER_LENGTHINDEX) - snprintf(tmp, 100, "%f", length); - else - snprintf(tmp, 100, "%f", length/2); - - values[i] = msStrdup(tmp); - } else if (itemindexes[i] == MSUVRASTER_UINDEX) { - snprintf(tmp, 100, "%f",*u); - values[i] = msStrdup(tmp); - } else if (itemindexes[i] == MSUVRASTER_VINDEX) { - snprintf(tmp, 100, "%f",*v); - values[i] = msStrdup(tmp); - } else { - values[i] = NULL; - } - } - - return values; -} - -rectObj msUVRASTERGetSearchRect( layerObj* layer, mapObj* map ) -{ - rectObj searchrect = map->extent; - int bDone = MS_FALSE; - - /* For UVRaster, it is important that the searchrect is not too large */ - /* to avoid insufficient intermediate raster resolution, which could */ - /* happen if we use the default code path, given potential reprojection */ - /* issues when using a map extent that is not in the validity area of */ - /* the layer projection. */ - if( !layer->projection.gt.need_geotransform && - !(msProjIsGeographicCRS(&(map->projection)) && - msProjIsGeographicCRS(&(layer->projection))) ) { - rectObj layer_ori_extent; - - if( msLayerGetExtent(layer, &layer_ori_extent) == MS_SUCCESS ) { - projectionObj map_proj; - - double map_extent_minx = map->extent.minx; - double map_extent_miny = map->extent.miny; - double map_extent_maxx = map->extent.maxx; - double map_extent_maxy = map->extent.maxy; - rectObj layer_extent = layer_ori_extent; - - /* Create a variant of map->projection without geotransform for */ - /* conveniency */ - msInitProjection(&map_proj); - msCopyProjection(&map_proj, &map->projection); - map_proj.gt.need_geotransform = MS_FALSE; - if( map->projection.gt.need_geotransform ) { - map_extent_minx = map->projection.gt.geotransform[0] - + map->projection.gt.geotransform[1] * map->extent.minx - + map->projection.gt.geotransform[2] * map->extent.miny; - map_extent_miny = map->projection.gt.geotransform[3] - + map->projection.gt.geotransform[4] * map->extent.minx - + map->projection.gt.geotransform[5] * map->extent.miny; - map_extent_maxx = map->projection.gt.geotransform[0] - + map->projection.gt.geotransform[1] * map->extent.maxx - + map->projection.gt.geotransform[2] * map->extent.maxy; - map_extent_maxy = map->projection.gt.geotransform[3] - + map->projection.gt.geotransform[4] * map->extent.maxx - + map->projection.gt.geotransform[5] * map->extent.maxy; - } - - /* Reproject layer extent to map projection */ - msProjectRect(&layer->projection, &map_proj, &layer_extent); - - if( layer_extent.minx <= map_extent_minx && - layer_extent.miny <= map_extent_miny && - layer_extent.maxx >= map_extent_maxx && - layer_extent.maxy >= map_extent_maxy ) { - /* do nothing special if area to map is inside layer extent */ - } - else { - if( layer_extent.minx >= map_extent_minx && - layer_extent.maxx <= map_extent_maxx && - layer_extent.miny >= map_extent_miny && - layer_extent.maxy <= map_extent_maxy ) { - /* if the area to map is larger than the layer extent, then */ - /* use full layer extent and add some margin to reflect the */ - /* proportion of the useful area over the requested bbox */ - double extra_x = - (map_extent_maxx - map_extent_minx) / - (layer_extent.maxx - layer_extent.minx) * - (layer_ori_extent.maxx - layer_ori_extent.minx); - double extra_y = - (map_extent_maxy - map_extent_miny) / - (layer_extent.maxy - layer_extent.miny) * - (layer_ori_extent.maxy - layer_ori_extent.miny); - searchrect.minx = layer_ori_extent.minx - extra_x / 2; - searchrect.maxx = layer_ori_extent.maxx + extra_x / 2; - searchrect.miny = layer_ori_extent.miny - extra_y / 2; - searchrect.maxy = layer_ori_extent.maxy + extra_y / 2; - } - else - { - /* otherwise clip the map extent with the reprojected layer */ - /* extent */ - searchrect.minx = MS_MAX( map_extent_minx, layer_extent.minx ); - searchrect.maxx = MS_MIN( map_extent_maxx, layer_extent.maxx ); - searchrect.miny = MS_MAX( map_extent_miny, layer_extent.miny ); - searchrect.maxy = MS_MIN( map_extent_maxy, layer_extent.maxy ); - /* and reproject into the layer projection */ - msProjectRect(&map_proj, &layer->projection, &searchrect); - } - bDone = MS_TRUE; - } - - msFreeProjection(&map_proj); - } - } - - if( !bDone ) - msProjectRect(&map->projection, &layer->projection, &searchrect); /* project the searchrect to source coords */ - - return searchrect; -} - -int msUVRASTERLayerWhichShapes(layerObj *layer, rectObj rect, int isQuery) -{ - uvRasterLayerInfo *uvlinfo = (uvRasterLayerInfo *) layer->layerinfo; - imageObj *image_tmp; - outputFormatObj *outputformat = NULL; - mapObj *map_tmp; - double map_cellsize; - unsigned int spacing; - int width, height, u_src_off, v_src_off, i, x, y; - char **alteredProcessing = NULL, *saved_layer_mask; - char **savedProcessing = NULL; - int bHasLonWrap = MS_FALSE; - double dfLonWrap = 0.0; - rectObj oldLayerExtent = {0}; - char* oldLayerData = NULL; - projectionObj oldLayerProjection={0}; - int ret; - - if (layer->debug) - msDebug("Entering msUVRASTERLayerWhichShapes().\n"); - - if( uvlinfo == NULL ) - return MS_FAILURE; - - if( CSLFetchNameValue( layer->processing, "BANDS" ) == NULL ) { - msSetError( MS_MISCERR, "BANDS processing option is required for UV layer. You have to specified 2 bands.", - "msUVRASTERLayerWhichShapes()" ); - return MS_FAILURE; - } - - /* - ** Allocate mapObj structure - */ - map_tmp = (mapObj *)msSmallCalloc(sizeof(mapObj),1); - if(initMap(map_tmp) == -1) { /* initialize this map */ - msFree(map_tmp); - return(MS_FAILURE); - } - - /* -------------------------------------------------------------------- */ - /* Determine desired spacing. Default to 32 if not otherwise set */ - /* -------------------------------------------------------------------- */ - spacing = 32; - if( CSLFetchNameValue( layer->processing, "UV_SPACING" ) != NULL ) { - spacing = - atoi(CSLFetchNameValue( layer->processing, "UV_SPACING" )); - } - - width = (int)ceil(layer->map->width/spacing); - height = (int)ceil(layer->map->height/spacing); - - /* Initialize our dummy map */ - MS_INIT_COLOR(map_tmp->imagecolor, 255,255,255,255); - map_tmp->resolution = layer->map->resolution; - map_tmp->defresolution = layer->map->defresolution; - - outputformat = (outputFormatObj *) msSmallCalloc(1,sizeof(outputFormatObj)); - outputformat->bands = uvlinfo->band_count = 2; - outputformat->name = NULL; - outputformat->driver = NULL; - outputformat->refcount = 0; - outputformat->vtable = NULL; - outputformat->device = NULL; - outputformat->renderer = MS_RENDER_WITH_RAWDATA; - outputformat->imagemode = MS_IMAGEMODE_FLOAT32; - msAppendOutputFormat(map_tmp, outputformat); - - msCopyHashTable(&map_tmp->configoptions, &layer->map->configoptions); - map_tmp->mappath = msStrdup(layer->map->mappath); - map_tmp->shapepath = msStrdup(layer->map->shapepath); - map_tmp->gt.rotation_angle = 0.0; - - /* Custom msCopyProjection() that removes lon_wrap parameter */ - { - int i; - - map_tmp->projection.numargs = 0; - map_tmp->projection.gt = layer->projection.gt; - map_tmp->projection.automatic = layer->projection.automatic; - - for (i = 0; i < layer->projection.numargs; i++) { - if( strncmp(layer->projection.args[i], "lon_wrap=", - strlen("lon_wrap=")) == 0 ) { - bHasLonWrap = MS_TRUE; - dfLonWrap = atof( layer->projection.args[i] + strlen("lon_wrap=") ); - } - else { - map_tmp->projection.args[map_tmp->projection.numargs ++] = - msStrdup(layer->projection.args[i]); - } - } - if (map_tmp->projection.numargs != 0) { - msProcessProjection(&(map_tmp->projection)); - } - - map_tmp->projection.wellknownprojection = layer->projection.wellknownprojection; - } - - /* Very special case to improve quality for rasters referenced from lon=0 to 360 */ - /* We create a temporary VRT that swiches the 2 hemispheres, and then we */ - /* modify the georeferncing to be in the more standard [-180, 180] range */ - /* and we adjust the layer->data, extent and projection accordingly */ - if( layer->tileindex == NULL && - uvlinfo->mapToUseForWhichShapes && bHasLonWrap && dfLonWrap == 180.0 ) - { - rectObj layerExtent; - msLayerGetExtent(layer, &layerExtent); - if( layerExtent.minx == 0 && layerExtent.maxx == 360 ) - { - GDALDatasetH hDS = NULL; - char* decrypted_path; - - if( strncmp(layer->data, "data); - } - else - { - char szPath[MS_MAXPATHLEN]; - msTryBuildPath3(szPath, layer->map->mappath, - layer->map->shapepath, layer->data); - decrypted_path = msDecryptStringTokens( layer->map, szPath ); - } - - if( decrypted_path ) - { - char** connectionoptions; - GDALAllRegister(); - connectionoptions = msGetStringListFromHashTable(&(layer->connectionoptions)); - hDS = GDALOpenEx(decrypted_path, - GDAL_OF_RASTER, - NULL, - (const char* const*)connectionoptions, - NULL); - CSLDestroy(connectionoptions); - } - if( hDS != NULL ) - { - int iBand; - int nXSize = GDALGetRasterXSize( hDS ); - int nYSize = GDALGetRasterYSize( hDS ); - int nBands = GDALGetRasterCount( hDS ); - int nMaxLen = 100 + nBands * (800 + 2 * strlen(decrypted_path)); - int nOffset = 0; - char* pszInlineVRT = msSmallMalloc( nMaxLen ); - - snprintf(pszInlineVRT, nMaxLen, - "", - nXSize, nYSize); - nOffset = strlen(pszInlineVRT); - for( iBand = 1; iBand <= nBands; iBand++ ) - { - const char* pszDataType = "Byte"; - switch( GDALGetRasterDataType(GDALGetRasterBand(hDS, iBand)) ) - { - case GDT_Byte: pszDataType = "Byte"; break; - case GDT_Int16: pszDataType = "Int16"; break; - case GDT_UInt16: pszDataType = "UInt16"; break; - case GDT_Int32: pszDataType = "Int32"; break; - case GDT_UInt32: pszDataType = "UInt32"; break; - case GDT_Float32: pszDataType = "Float32"; break; - case GDT_Float64: pszDataType = "Float64"; break; - default: break; - } - - snprintf( pszInlineVRT + nOffset, nMaxLen - nOffset, - " " - " " - " " - " %d" - " " - " " - " " - " " - " " - " %d" - " " - " " - " " - " ", - pszDataType, iBand, - decrypted_path, iBand, - nXSize / 2, 0, nXSize - nXSize / 2, nYSize, - 0, 0, nXSize - nXSize / 2, nYSize, - decrypted_path, iBand, - 0, 0, nXSize / 2, nYSize, - nXSize - nXSize / 2, 0, nXSize / 2, nYSize ); - - nOffset += strlen(pszInlineVRT + nOffset); - } - snprintf(pszInlineVRT + nOffset, nMaxLen - nOffset, - ""); - - oldLayerExtent = layer->extent; - oldLayerData = layer->data; - oldLayerProjection = layer->projection; - layer->extent.minx = -180; - layer->extent.maxx = 180; - layer->data = pszInlineVRT; - layer->projection = map_tmp->projection; - - - /* map_tmp->projection is actually layer->projection without lon_wrap */ - rect = uvlinfo->mapToUseForWhichShapes->extent; - msProjectRect(&uvlinfo->mapToUseForWhichShapes->projection, - &map_tmp->projection, &rect); - bHasLonWrap = MS_FALSE; - - GDALClose(hDS); - } - msFree( decrypted_path ); - } - } - - if( isQuery ) - { - /* For query mode, use layer->map->extent reprojected rather than */ - /* the provided rect. Generic query code will filter returned features. */ - rect = msUVRASTERGetSearchRect(layer, layer->map); - } - - map_cellsize = MS_MAX(MS_CELLSIZE(rect.minx, rect.maxx,layer->map->width), - MS_CELLSIZE(rect.miny,rect.maxy,layer->map->height)); - map_tmp->cellsize = map_cellsize*spacing; - map_tmp->extent.minx = rect.minx-(0.5*map_cellsize)+(0.5*map_tmp->cellsize); - map_tmp->extent.miny = rect.miny-(0.5*map_cellsize)+(0.5*map_tmp->cellsize); - map_tmp->extent.maxx = map_tmp->extent.minx+((width-1)*map_tmp->cellsize); - map_tmp->extent.maxy = map_tmp->extent.miny+((height-1)*map_tmp->cellsize); - - if( bHasLonWrap && dfLonWrap == 180.0) { - if( map_tmp->extent.minx >= 180 ) { - /* Request on the right half of the shifted raster (= western hemisphere) */ - map_tmp->extent.minx -= 360; - map_tmp->extent.maxx -= 360; - } - else if( map_tmp->extent.maxx >= 180.0 ) { - /* Request spanning on the 2 hemispheres => drawing whole planet */ - /* Take only into account vertical resolution, as horizontal one */ - /* will be unreliable (assuming square pixels...) */ - map_cellsize = MS_CELLSIZE(rect.miny,rect.maxy,layer->map->height); - map_tmp->cellsize = map_cellsize*spacing; - - width = 360.0 / map_tmp->cellsize; - map_tmp->extent.minx = -180.0+(0.5*map_tmp->cellsize); - map_tmp->extent.maxx = 180.0-(0.5*map_tmp->cellsize); - } - } - - if (layer->debug) - msDebug("msUVRASTERLayerWhichShapes(): width: %d, height: %d, cellsize: %g\n", - width, height, map_tmp->cellsize); - - if (layer->debug == 5) - msDebug("msUVRASTERLayerWhichShapes(): extent: %g %g %g %g\n", - map_tmp->extent.minx, map_tmp->extent.miny, - map_tmp->extent.maxx, map_tmp->extent.maxy); - - /* important to use that function, to compute map - geotransform, used by the resampling*/ - msMapSetSize(map_tmp, width, height); - - if (layer->debug == 5) - msDebug("msUVRASTERLayerWhichShapes(): geotransform: %g %g %g %g %g %g\n", - map_tmp->gt.geotransform[0], map_tmp->gt.geotransform[1], - map_tmp->gt.geotransform[2], map_tmp->gt.geotransform[3], - map_tmp->gt.geotransform[4], map_tmp->gt.geotransform[5]); - - uvlinfo->extent = map_tmp->extent; - - image_tmp = msImageCreate(width, height, map_tmp->outputformatlist[0], - NULL, NULL, map_tmp->resolution, map_tmp->defresolution, - &(map_tmp->imagecolor)); - - /* Default set to AVERAGE resampling */ - if( CSLFetchNameValue( layer->processing, "RESAMPLE" ) == NULL ) { - alteredProcessing = CSLDuplicate( layer->processing ); - alteredProcessing = - CSLSetNameValue( alteredProcessing, "RESAMPLE", - "AVERAGE"); - savedProcessing = layer->processing; - layer->processing = alteredProcessing; - } - - /* disable masking at this level: we don't want to apply the mask at the raster level, - * it will be applied with the correct cellsize and image size in the vector rendering - * phase. - */ - saved_layer_mask = layer->mask; - layer->mask = NULL; - ret = msDrawRasterLayerLow(map_tmp, layer, image_tmp, NULL ); - - /* restore layer attributes if we went through the above on-the-fly VRT */ - if( oldLayerData ) - { - msFree(layer->data); - layer->data = oldLayerData; - layer->extent = oldLayerExtent; - layer->projection = oldLayerProjection; - } - - /* restore layer mask */ - layer->mask = saved_layer_mask; - - /* restore the saved processing */ - if (alteredProcessing != NULL) { - layer->processing = savedProcessing; - CSLDestroy(alteredProcessing); - } - - if( ret == MS_FAILURE) { - msSetError(MS_MISCERR, "Unable to draw raster data.", "msUVRASTERLayerWhichShapes()"); - - msFreeMap(map_tmp); - msFreeImage(image_tmp); - - return MS_FAILURE; - } - - /* free old query arrays */ - if (uvlinfo->u) { - for (i=0; iwidth; ++i) { - free(uvlinfo->u[i]); - } - free(uvlinfo->u); - } - - if (uvlinfo->v) { - for (i=0; iwidth; ++i) { - free(uvlinfo->v[i]); - } - free(uvlinfo->v); - } - - /* Update our uv layer structure */ - uvlinfo->width = width; - uvlinfo->height = height; - uvlinfo->query_results = width*height; - - uvlinfo->u = (float **)msSmallMalloc(sizeof(float *)*width); - uvlinfo->v = (float **)msSmallMalloc(sizeof(float *)*width); - - for (x = 0; x < width; ++x) { - uvlinfo->u[x] = (float *)msSmallMalloc(height * sizeof(float)); - uvlinfo->v[x] = (float *)msSmallMalloc(height * sizeof(float)); - - for (y = 0; y < height; ++y) { - u_src_off = v_src_off = x + y * width; - v_src_off += width*height; - - uvlinfo->u[x][y] = image_tmp->img.raw_float[u_src_off]; - uvlinfo->v[x][y] = image_tmp->img.raw_float[v_src_off]; - - /* null vector? update the number of results */ - if (uvlinfo->u[x][y] == 0 && uvlinfo->v[x][y] == 0) - --uvlinfo->query_results; - } - } - - msFreeImage(image_tmp); /* we do not need the imageObj anymore */ - msFreeMap(map_tmp); - - uvlinfo->next_shape = 0; - - return MS_SUCCESS; -} - -int msUVRASTERLayerGetShape(layerObj *layer, shapeObj *shape, resultObj *record) -{ - uvRasterLayerInfo *uvlinfo = (uvRasterLayerInfo *) layer->layerinfo; - lineObj line ; - pointObj point; - int i, j, k, x=0, y=0; - long shapeindex = record->shapeindex; - - msFreeShape(shape); - shape->type = MS_SHAPE_NULL; - - if( shapeindex < 0 || shapeindex >= uvlinfo->query_results ) { - msSetError(MS_MISCERR, - "Out of range shape index requested. Requested %ld\n" - "but only %d shapes available.", - "msUVRASTERLayerGetShape()", - shapeindex, uvlinfo->query_results ); - return MS_FAILURE; - } - - /* loop to the next non null vector */ - k = 0; - for (i=0, x=-1; iwidth && k<=shapeindex; ++i, ++x) { - for (j=0, y=-1; jheight && k<=shapeindex; ++j, ++k, ++y) { - if (uvlinfo->u[i][j] == 0 && uvlinfo->v[i][j] == 0) - --k; - } - } - - point.x = Pix2Georef(x, 0, uvlinfo->width-1, - uvlinfo->extent.minx, uvlinfo->extent.maxx, MS_FALSE); - point.y = Pix2Georef(y, 0, uvlinfo->height-1, - uvlinfo->extent.miny, uvlinfo->extent.maxy, MS_TRUE); - if (layer->debug == 5) - msDebug("msUVRASTERLayerWhichShapes(): shapeindex: %ld, x: %g, y: %g\n", - shapeindex, point.x, point.y); - -#ifdef USE_POINT_Z_M - point.m = 0.0; -#endif - - shape->type = MS_SHAPE_POINT; - line.numpoints = 1; - line.point = &point; - msAddLine( shape, &line ); - msComputeBounds( shape ); - - shape->numvalues = layer->numitems; - shape->values = msUVRASTERGetValues(layer, &uvlinfo->u[x][y], &uvlinfo->v[x][y]); - shape->index = shapeindex; - shape->resultindex = shapeindex; - - return MS_SUCCESS; - -} - -int msUVRASTERLayerNextShape(layerObj *layer, shapeObj *shape) -{ - uvRasterLayerInfo *uvlinfo = (uvRasterLayerInfo *) layer->layerinfo; - - if( uvlinfo->next_shape < 0 - || uvlinfo->next_shape >= uvlinfo->query_results ) { - msFreeShape(shape); - shape->type = MS_SHAPE_NULL; - return MS_DONE; - } else { - resultObj record; - - record.shapeindex = uvlinfo->next_shape++; - record.tileindex = 0; - record.classindex = record.resultindex = -1; - - return msUVRASTERLayerGetShape( layer, shape, &record); - } -} - -/************************************************************************/ -/* msUVRASTERLayerGetExtent() */ -/* Simple copy of the maprasterquery.c file. might change in the future */ -/************************************************************************/ - -int msUVRASTERLayerGetExtent(layerObj *layer, rectObj *extent) - -{ - char szPath[MS_MAXPATHLEN]; - mapObj *map = layer->map; - shapefileObj *tileshpfile; - int tilelayerindex = -1; - - if( (!layer->data || strlen(layer->data) == 0) - && layer->tileindex == NULL) { - /* should we be issuing a specific error about not supporting - extents for tileindexed raster layers? */ - return MS_FAILURE; - } - - if( map == NULL ) - return MS_FAILURE; - - /* If the layer use a tileindex, return the extent of the tileindex shapefile/referenced layer */ - if (layer->tileindex) { - tilelayerindex = msGetLayerIndex(map, layer->tileindex); - if(tilelayerindex != -1) /* does the tileindex reference another layer */ - return msLayerGetExtent(GET_LAYER(map, tilelayerindex), extent); - else { - tileshpfile = (shapefileObj *) malloc(sizeof(shapefileObj)); - MS_CHECK_ALLOC(tileshpfile, sizeof(shapefileObj), MS_FAILURE); - - if(msShapefileOpen(tileshpfile, "rb", msBuildPath3(szPath, map->mappath, map->shapepath, layer->tileindex), MS_TRUE) == -1) - if(msShapefileOpen(tileshpfile, "rb", msBuildPath(szPath, map->mappath, layer->tileindex), MS_TRUE) == -1) - return MS_FAILURE; - - *extent = tileshpfile->bounds; - msShapefileClose(tileshpfile); - free(tileshpfile); - return MS_SUCCESS; - } - } - - msTryBuildPath3(szPath, map->mappath, map->shapepath, layer->data); - char* decrypted_path = msDecryptStringTokens( map, szPath ); - if( !decrypted_path ) - return MS_FAILURE; - - GDALAllRegister(); - - char** connectionoptions = msGetStringListFromHashTable(&(layer->connectionoptions)); - GDALDatasetH hDS = GDALOpenEx(decrypted_path, - GDAL_OF_RASTER, - NULL, - (const char* const*)connectionoptions, - NULL); - CSLDestroy(connectionoptions); - msFree( decrypted_path ); - if( hDS == NULL ) { - return MS_FAILURE; - } - - const int nXSize = GDALGetRasterXSize( hDS ); - const int nYSize = GDALGetRasterYSize( hDS ); - double adfGeoTransform[6] = {0}; - const CPLErr eErr = GDALGetGeoTransform( hDS, adfGeoTransform ); - if( eErr != CE_None ) { - GDALClose( hDS ); - return MS_FAILURE; - } - - /* If this appears to be an ungeoreferenced raster than flip it for - mapservers purposes. */ - if( adfGeoTransform[5] == 1.0 && adfGeoTransform[3] == 0.0 ) { - adfGeoTransform[5] = -1.0; - adfGeoTransform[3] = nYSize; - } - - extent->minx = adfGeoTransform[0]; - extent->maxy = adfGeoTransform[3]; - - extent->maxx = adfGeoTransform[0] + nXSize * adfGeoTransform[1]; - extent->miny = adfGeoTransform[3] + nYSize * adfGeoTransform[5]; - - return MS_SUCCESS; -} - - -/************************************************************************/ -/* msUVRASTERLayerSetTimeFilter() */ -/* */ -/* This function is actually just used in the context of */ -/* setting a filter on the tileindex for time based queries. */ -/* For instance via WMS requests. So it isn't really related */ -/* to the "raster query" support at all. */ -/* */ -/* If a local shapefile tileindex is in use, we will set a */ -/* backtics filter (shapefile compatible). If another layer is */ -/* being used as the tileindex then we will forward the */ -/* SetTimeFilter call to it. If there is no tileindex in */ -/* place, we do nothing. */ -/************************************************************************/ - -int msUVRASTERLayerSetTimeFilter(layerObj *layer, const char *timestring, - const char *timefield) -{ - int tilelayerindex; - - /* -------------------------------------------------------------------- */ - /* If we don't have a tileindex the time filter has no effect. */ - /* -------------------------------------------------------------------- */ - if( layer->tileindex == NULL ) - return MS_SUCCESS; - - /* -------------------------------------------------------------------- */ - /* Find the tileindex layer. */ - /* -------------------------------------------------------------------- */ - tilelayerindex = msGetLayerIndex(layer->map, layer->tileindex); - - /* -------------------------------------------------------------------- */ - /* If we are using a local shapefile as our tileindex (that is */ - /* to say, the tileindex name is not of another layer), then we */ - /* just install a backtics style filter on the raster layer. */ - /* This is propogated to the "working layer" created for the */ - /* tileindex by code in mapraster.c. */ - /* -------------------------------------------------------------------- */ - if( tilelayerindex == -1 ) - return msLayerMakeBackticsTimeFilter( layer, timestring, timefield ); - - /* -------------------------------------------------------------------- */ - /* Otherwise we invoke the tileindex layers SetTimeFilter */ - /* method. */ - /* -------------------------------------------------------------------- */ - if ( msCheckParentPointer(layer->map,"map")==MS_FAILURE ) - return MS_FAILURE; - return msLayerSetTimeFilter( layer->GET_LAYER(map,tilelayerindex), - timestring, timefield ); -} - - -/************************************************************************/ -/* msRASTERLayerInitializeVirtualTable() */ -/************************************************************************/ - -int -msUVRASTERLayerInitializeVirtualTable(layerObj *layer) -{ - assert(layer != NULL); - assert(layer->vtable != NULL); - - layer->vtable->LayerInitItemInfo = msUVRASTERLayerInitItemInfo; - layer->vtable->LayerFreeItemInfo = msUVRASTERLayerFreeItemInfo; - layer->vtable->LayerOpen = msUVRASTERLayerOpen; - layer->vtable->LayerIsOpen = msUVRASTERLayerIsOpen; - layer->vtable->LayerWhichShapes = msUVRASTERLayerWhichShapes; - layer->vtable->LayerNextShape = msUVRASTERLayerNextShape; - layer->vtable->LayerGetShape = msUVRASTERLayerGetShape; - /* layer->vtable->LayerGetShapeCount, use default */ - layer->vtable->LayerClose = msUVRASTERLayerClose; - layer->vtable->LayerGetItems = msUVRASTERLayerGetItems; - layer->vtable->LayerGetExtent = msUVRASTERLayerGetExtent; - /* layer->vtable->LayerGetAutoStyle, use default */ - /* layer->vtable->LayerApplyFilterToLayer, use default */ - /* layer->vtable->LayerCloseConnection = msUVRASTERLayerClose; */ - /* we use backtics for proper tileindex shapefile functioning */ - layer->vtable->LayerSetTimeFilter = msUVRASTERLayerSetTimeFilter; - /* layer->vtable->LayerCreateItems, use default */ - /* layer->vtable->LayerGetNumFeatures, use default */ - - return MS_SUCCESS; -} diff --git a/mapwcs.cpp b/mapwcs.cpp deleted file mode 100644 index 100e663604..0000000000 --- a/mapwcs.cpp +++ /dev/null @@ -1,2840 +0,0 @@ -/****************************************************************************** - * $Id$ - * - * Project: MapServer - * Purpose: OpenGIS Web Coverage Server (WCS) Implementation. - * Author: Steve Lime and the MapServer team. - * - ****************************************************************************** - * Copyright (c) 1996-2005 Regents of the University of Minnesota. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies of this Software or works derived from this Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - *****************************************************************************/ - -#include "mapserver.h" -#include "maperror.h" -#include "mapthread.h" -#include "mapows.h" -#include - -#include - -#if defined(USE_WCS_SVR) - -#include "mapwcs.h" - -#include "maptime.h" -#include - -#include "gdal.h" -#include "cpl_string.h" /* GDAL string handling */ - -/************************************************************************/ -/* msWCSValidateRangeSetParam() */ -/************************************************************************/ -static int msWCSValidateRangeSetParam(layerObj *lp, char *name, const char *value) -{ - char **allowed_ri_values; - char **client_ri_values; - int allowed_count, client_count; - int i_client, i, all_match = 1; - char *tmpname = NULL; - const char *ri_values_list; - - if( name == NULL ) - return MS_FAILURE; - - /* Fetch the available values list for the rangeset item and tokenize */ - tmpname = (char *)msSmallMalloc(sizeof(char)*strlen(name) + 10); - sprintf(tmpname,"%s_values", name); - ri_values_list = msOWSLookupMetadata(&(lp->metadata), "CO", tmpname); - msFree( tmpname ); - - if (ri_values_list == NULL) - return MS_FAILURE; - - allowed_ri_values = msStringSplit( ri_values_list, ',', &allowed_count); - - /* Parse the client value list into tokens. */ - client_ri_values = msStringSplit( value, ',', &client_count ); - - /* test each client value against the allowed list. */ - - for( i_client = 0; all_match && i_client < client_count; i_client++ ) { - for( i = 0; - i < allowed_count - && strcasecmp(client_ri_values[i_client], - allowed_ri_values[i]) != 0; - i++ ) {} - - if( i == allowed_count ) - all_match = 0; - } - - msFreeCharArray(allowed_ri_values, allowed_count ); - msFreeCharArray(client_ri_values, client_count ); - - if (all_match == 0) - return MS_FAILURE; - else - return MS_SUCCESS; -} - -/************************************************************************/ -/* msWCSConvertRangeSetToString() */ -/************************************************************************/ -static char *msWCSConvertRangeSetToString(const char *value) -{ - char **tokens; - int numtokens; - double min, max, res; - double val; - char buf1[128], *buf2=NULL; - - if(strchr(value, '/')) { /* value is min/max/res */ - tokens = msStringSplit(value, '/', &numtokens); - if(tokens==NULL || numtokens != 3) { - msFreeCharArray(tokens, numtokens); - return NULL; /* not a set of equally spaced intervals */ - } - - min = atof(tokens[0]); - max = atof(tokens[1]); - res = atof(tokens[2]); - msFreeCharArray(tokens, numtokens); - - for(val=min; val<=max; val+=res) { - if(val == min) - snprintf(buf1, sizeof(buf1), "%g", val); - else - snprintf(buf1, sizeof(buf1), ",%g", val); - buf2 = msStringConcatenate(buf2, buf1); - } - - return buf2; - } else - return msStrdup(value); -} - -/************************************************************************/ -/* msWCSException() */ -/************************************************************************/ -int msWCSException(mapObj *map, const char *code, const char *locator, - const char *version ) -{ - char *pszEncodedVal = NULL; - char version_string[OWS_VERSION_MAXLEN]; - - if( version == NULL ) - version = "1.0.0"; - -#if defined(USE_LIBXML2) - if( msOWSParseVersionString(version) >= OWS_2_0_0 ) - return msWCSException20( map, code, locator, msOWSGetVersionString(msOWSParseVersionString(version), version_string) ); -#endif - - if( msOWSParseVersionString(version) >= OWS_1_1_0 ) - return msWCSException11( map, code, locator, msOWSGetVersionString(msOWSParseVersionString(version), version_string) ); - - msIO_setHeader("Content-Type","application/vnd.ogc.se_xml; charset=UTF-8"); - msIO_sendHeaders(); - - /* msIO_printf("Content-Type: text/xml%c%c",10,10); */ - - msIO_printf("\n"); - - msIO_printf("\n", - pszEncodedVal); - msFree(pszEncodedVal); - msIO_printf(" "); - msWriteErrorXML(stdout); - msIO_printf(" \n"); - msIO_printf("\n"); - - msResetErrorList(); - - return MS_FAILURE; -} - -/************************************************************************/ -/* msWCSPrintRequestCapability() */ -/************************************************************************/ - -static void msWCSPrintRequestCapability(const char *version, const char *request_tag, const char *script_url) -{ - msIO_printf(" <%s>\n", request_tag); - - msIO_printf(" \n"); - msIO_printf(" \n"); - msIO_printf(" \n", script_url); - msIO_printf(" \n"); - msIO_printf(" \n"); - msIO_printf(" \n"); - msIO_printf(" \n"); - msIO_printf(" \n", script_url); - msIO_printf(" \n"); - msIO_printf(" \n"); - - msIO_printf(" \n", request_tag); -} - -/************************************************************************/ -/* msWCSCreateParams() */ -/************************************************************************/ -static wcsParamsObj *msWCSCreateParams() -{ - wcsParamsObj *params; - - params = (wcsParamsObj *) calloc(1, sizeof(wcsParamsObj)); - MS_CHECK_ALLOC(params, sizeof(wcsParamsObj), NULL); - - return params; -} - -/************************************************************************/ -/* msWCSFreeParams() */ -/************************************************************************/ -void msWCSFreeParams(wcsParamsObj *params) -{ - if(params) { - /* TODO */ - if(params->version) free(params->version); - if(params->updatesequence) free(params->updatesequence); - if(params->request) free(params->request); - if(params->service) free(params->service); - if(params->section) free(params->section); - if(params->crs) free(params->crs); - if(params->response_crs) free(params->response_crs); - if(params->format) free(params->format); - if(params->exceptions) free(params->exceptions); - if(params->time) free(params->time); - if(params->interpolation) free(params->interpolation); - CSLDestroy( params->coverages ); - } -} - -/************************************************************************/ -/* msWCSIsLayerSupported() */ -/************************************************************************/ - -int msWCSIsLayerSupported(layerObj *layer) -{ - /* only raster layers, are elligible to be served via WCS, WMS rasters are not ok */ - if((layer->type == MS_LAYER_RASTER) && layer->connectiontype != MS_WMS && layer->name != NULL) return MS_TRUE; - - return MS_FALSE; -} - -/************************************************************************/ -/* msWCSGetRequestParameter() */ -/* */ -/************************************************************************/ - -const char *msWCSGetRequestParameter(cgiRequestObj *request, const char *name) -{ - int i; - - if(!request || !name) /* nothing to do */ - return NULL; - - if(request->NumParams > 0) { - for(i=0; iNumParams; i++) { - if(strcasecmp(request->ParamNames[i], name) == 0) - return request->ParamValues[i]; - } - } - - return NULL; -} - -/************************************************************************/ -/* msWCSSetDefaultBandsRangeSetInfo() */ -/************************************************************************/ - -void msWCSSetDefaultBandsRangeSetInfo( wcsParamsObj *params, - coverageMetadataObj *cm, - layerObj *lp ) -{ - - /* This function will provide default rangeset information for the "special" */ - /* "bands" rangeset if it appears in the axes list but has no specifics provided */ - /* in the metadata. */ - - const char *value; - char *bandlist; - size_t bufferSize = 0; - int i; - - /* Does this item exist in the axes list? */ - - value = msOWSLookupMetadata(&(lp->metadata), "CO", "rangeset_axes"); - if( value == NULL ) - return; - - value = strstr(value,"bands"); - if( value == NULL || (value[5] != '\0' && value[5] != ' ') ) - return; - - /* Are there any w*s_bands_ metadata already? If so, skip out. */ - if( msOWSLookupMetadata(&(lp->metadata), "CO", "bands_description") != NULL - || msOWSLookupMetadata(&(lp->metadata), "CO", "bands_name") != NULL - || msOWSLookupMetadata(&(lp->metadata), "CO", "bands_label") != NULL - || msOWSLookupMetadata(&(lp->metadata), "CO", "bands_values") != NULL - || msOWSLookupMetadata(&(lp->metadata), "CO", "bands_values_semantic") != NULL - || msOWSLookupMetadata(&(lp->metadata), "CO", "bands_values_type") != NULL - || msOWSLookupMetadata(&(lp->metadata), "CO", "bands_rangeitem") != NULL - || msOWSLookupMetadata(&(lp->metadata), "CO", "bands_semantic") != NULL - || msOWSLookupMetadata(&(lp->metadata), "CO", "bands_refsys") != NULL - || msOWSLookupMetadata(&(lp->metadata), "CO", "bands_refsyslabel") != NULL - || msOWSLookupMetadata(&(lp->metadata), "CO", "bands_interval") != NULL ) - return; - - /* OK, we have decided to fill in the information. */ - - msInsertHashTable( &(lp->metadata), "wcs_bands_name", "bands" ); - msInsertHashTable( &(lp->metadata), "wcs_bands_label", "Bands/Channels/Samples" ); - msInsertHashTable( &(lp->metadata), "wcs_bands_rangeitem", "_bands" ); /* ? */ - - bufferSize = cm->bandcount*30+30; - bandlist = (char *) msSmallMalloc(bufferSize); - strcpy( bandlist, "1" ); - for( i = 1; i < cm->bandcount; i++ ) - snprintf( bandlist+strlen(bandlist), bufferSize-strlen(bandlist), ",%d", i+1 ); - - msInsertHashTable( &(lp->metadata), "wcs_bands_values", bandlist ); - free( bandlist ); -} - -/************************************************************************/ -/* msWCSParseRequest() */ -/************************************************************************/ - -static int msWCSParseRequest(cgiRequestObj *request, wcsParamsObj *params, mapObj *map) -{ - int i, n; - char **tokens; - - if(!request || !params) /* nothing to do */ - return MS_SUCCESS; - - /* -------------------------------------------------------------------- */ - /* Check if this appears to be an XML POST WCS request. */ - /* -------------------------------------------------------------------- */ - - msDebug("msWCSParseRequest(): request is %s.\n", (request->type == MS_POST_REQUEST)?"POST":"KVP"); - - if( request->type == MS_POST_REQUEST - && request->postrequest ) { -#if defined(USE_LIBXML2) - xmlDocPtr doc = NULL; - xmlNodePtr root = NULL, child = NULL; - char *tmp = NULL; - - /* parse to DOM-Structure and get root element */ - if((doc = xmlParseMemory(request->postrequest, strlen(request->postrequest))) - == NULL) { - xmlErrorPtr error = xmlGetLastError(); - msSetError(MS_WCSERR, "XML parsing error: %s", - "msWCSParseRequest()", error->message); - return MS_FAILURE; - } - root = xmlDocGetRootElement(doc); - - /* Get service, version and request from root */ - params->request = msStrdup((char *) root->name); - if ((tmp = (char *) xmlGetProp(root, BAD_CAST "service")) != NULL) - params->service = tmp; - if ((tmp = (char *) xmlGetProp(root, BAD_CAST "version")) != NULL) - params->version = tmp; - - /* search first level children, either CoverageID, */ - for (child = root->children; child != NULL; child = child->next) { - if (EQUAL((char *)child->name, "AcceptVersions")) { - /* will be overridden to 1.1.1 anyway */ - } else if (EQUAL((char *) child->name, "UpdateSequence")) { - params->updatesequence = (char *)xmlNodeGetContent(child); - } else if (EQUAL((char *) child->name, "Sections")) { - xmlNodePtr sectionNode = NULL; - /* concatenate all sections by ',' */ - for(sectionNode = child->children; sectionNode != NULL; sectionNode = sectionNode->next) { - char *content; - if(!EQUAL((char *)sectionNode->name, "Section")) - continue; - content = (char *)xmlNodeGetContent(sectionNode); - if(!params->section) { - params->section = content; - } else { - params->section = msStringConcatenate(params->section, ","); - params->section = msStringConcatenate(params->section, content); - xmlFree(content); - } - } - } else if(EQUAL((char *) child->name, "AcceptFormats")) { - /* TODO: implement */ - } else if(EQUAL((char *) child->name, "Identifier")) { - char *content = (char *)xmlNodeGetContent(child); - params->coverages = CSLAddString(params->coverages, content); - xmlFree(content); - } else if(EQUAL((char *) child->name, "DomainSubset")) { - xmlNodePtr tmpNode = NULL; - for(tmpNode = child->children; tmpNode != NULL; tmpNode = tmpNode->next) { - if(EQUAL((char *) tmpNode->name, "BoundingBox")) { - xmlNodePtr cornerNode = NULL; - params->crs = (char *)xmlGetProp(tmpNode, BAD_CAST "crs"); - if( strncasecmp(params->crs,"urn:ogc:def:crs:",16) == 0 - && strncasecmp(params->crs+strlen(params->crs)-8,"imageCRS",8)==0) - strcpy( params->crs, "imageCRS" ); - for(cornerNode = tmpNode->children; cornerNode != NULL; cornerNode = cornerNode->next) { - if(EQUAL((char *) cornerNode->name, "LowerCorner")) { - char *value = (char *)xmlNodeGetContent(cornerNode); - tokens = msStringSplit(value, ' ', &n); - if(tokens==NULL || n < 2) { - msSetError(MS_WCSERR, "Wrong number of arguments for LowerCorner", - "msWCSParseRequest()"); - return msWCSException(map, "InvalidParameterValue", "LowerCorner", - params->version ); - } - params->bbox.minx = atof(tokens[0]); - params->bbox.miny = atof(tokens[1]); - msFreeCharArray(tokens, n); - xmlFree(value); - } - if(EQUAL((char *) cornerNode->name, "UpperCorner")) { - char *value = (char *)xmlNodeGetContent(cornerNode); - tokens = msStringSplit(value, ' ', &n); - if(tokens==NULL || n < 2) { - msSetError(MS_WCSERR, "Wrong number of arguments for UpperCorner", - "msWCSParseRequest()"); - return msWCSException(map, "InvalidParameterValue", "UpperCorner", - params->version ); - } - params->bbox.maxx = atof(tokens[0]); - params->bbox.maxy = atof(tokens[1]); - msFreeCharArray(tokens, n); - xmlFree(value); - } - } - } - } - } else if(EQUAL((char *) child->name, "RangeSubset")) { - /* TODO: not implemented in mapserver WCS 1.1? */ - } else if(EQUAL((char *) child->name, "Output")) { - xmlNodePtr tmpNode = NULL; - params->format = (char *)xmlGetProp(child, BAD_CAST "format"); - for(tmpNode = child->children; tmpNode != NULL; tmpNode = tmpNode->next) { - if(EQUAL((char *) tmpNode->name, "GridCRS")) { - xmlNodePtr crsNode = NULL; - for(crsNode = tmpNode->children; crsNode != NULL; crsNode = crsNode->next) { - if(EQUAL((char *) crsNode->name, "GridBaseCRS")) { - params->response_crs = (char *) xmlNodeGetContent(crsNode); - } else if (EQUAL((char *) crsNode->name, "GridOrigin")) { - char *value = (char *)xmlNodeGetContent(crsNode); - tokens = msStringSplit(value, ' ', &n); - if(tokens==NULL || n < 2) { - msSetError(MS_WCSERR, "Wrong number of arguments for GridOrigin", - "msWCSParseRequest()"); - return msWCSException(map, "InvalidParameterValue", "GridOffsets", - params->version ); - } - params->originx = atof(tokens[0]); - params->originy = atof(tokens[1]); - msFreeCharArray(tokens, n); - xmlFree(value); - } else if (EQUAL((char *) crsNode->name, "GridOffsets")) { - char *value = (char *)xmlNodeGetContent(crsNode); - tokens = msStringSplit(value, ' ', &n); - if(tokens==NULL || n < 2) { - msSetError(MS_WCSERR, "Wrong number of arguments for GridOffsets", - "msWCSParseRequest()"); - return msWCSException(map, "InvalidParameterValue", "GridOffsets", - params->version ); - } - /* take absolute values to convert to positive RESX/RESY style - WCS 1.0 behavior. *but* this does break some possibilities! */ - params->resx = fabs(atof(tokens[0])); - params->resy = fabs(atof(tokens[1])); - msFreeCharArray(tokens, n); - xmlFree(value); - } - } - } - } - } - } - xmlFreeDoc(doc); - xmlCleanupParser(); - return MS_SUCCESS; -#else /* defined(USE_LIBXML2) */ - msSetError(MS_WCSERR, "To enable POST requests, MapServer has to " - "be compiled with libxml2.", "msWCSParseRequest()"); - return MS_FAILURE; -#endif /* defined(USE_LIBXML2) */ - } - - /* -------------------------------------------------------------------- */ - /* Extract WCS KVP Parameters. */ - /* -------------------------------------------------------------------- */ - if(request->NumParams > 0) { - for(i=0; iNumParams; i++) { - - if(strcasecmp(request->ParamNames[i], "VERSION") == 0) - params->version = msStrdup(request->ParamValues[i]); - if(strcasecmp(request->ParamNames[i], "UPDATESEQUENCE") == 0) - params->updatesequence = msStrdup(request->ParamValues[i]); - else if(strcasecmp(request->ParamNames[i], "REQUEST") == 0) - params->request = msStrdup(request->ParamValues[i]); - else if(strcasecmp(request->ParamNames[i], "INTERPOLATION") == 0) - params->interpolation = msStrdup(request->ParamValues[i]); - else if(strcasecmp(request->ParamNames[i], "SERVICE") == 0) - params->service = msStrdup(request->ParamValues[i]); - else if(strcasecmp(request->ParamNames[i], "SECTION") == 0) /* 1.0 */ - params->section = msStrdup(request->ParamValues[i]); /* TODO: validate value here */ - else if(strcasecmp(request->ParamNames[i], "SECTIONS") == 0) /* 1.1 */ - params->section = msStrdup(request->ParamValues[i]); /* TODO: validate value here */ - - /* GetCoverage parameters. */ - else if(strcasecmp(request->ParamNames[i], "BBOX") == 0) { - tokens = msStringSplit(request->ParamValues[i], ',', &n); - if(tokens==NULL || n != 4) { - msSetError(MS_WCSERR, "Wrong number of arguments for BBOX.", "msWCSParseRequest()"); - return msWCSException(map, "InvalidParameterValue", "bbox", - params->version ); - } - params->bbox.minx = atof(tokens[0]); - params->bbox.miny = atof(tokens[1]); - params->bbox.maxx = atof(tokens[2]); - params->bbox.maxy = atof(tokens[3]); - - msFreeCharArray(tokens, n); - } else if(strcasecmp(request->ParamNames[i], "RESX") == 0) - params->resx = atof(request->ParamValues[i]); - else if(strcasecmp(request->ParamNames[i], "RESY") == 0) - params->resy = atof(request->ParamValues[i]); - else if(strcasecmp(request->ParamNames[i], "WIDTH") == 0) - params->width = atoi(request->ParamValues[i]); - else if(strcasecmp(request->ParamNames[i], "HEIGHT") == 0) - params->height = atoi(request->ParamValues[i]); - else if(strcasecmp(request->ParamNames[i], "COVERAGE") == 0) - params->coverages = CSLAddString(params->coverages, request->ParamValues[i]); - else if(strcasecmp(request->ParamNames[i], "TIME") == 0) - params->time = msStrdup(request->ParamValues[i]); - else if(strcasecmp(request->ParamNames[i], "FORMAT") == 0) - params->format = msStrdup(request->ParamValues[i]); - else if(strcasecmp(request->ParamNames[i], "CRS") == 0) - params->crs = msStrdup(request->ParamValues[i]); - else if(strcasecmp(request->ParamNames[i], "RESPONSE_CRS") == 0) - params->response_crs = msStrdup(request->ParamValues[i]); - - /* WCS 1.1 DescribeCoverage and GetCoverage ... */ - else if(strcasecmp(request->ParamNames[i], "IDENTIFIER") == 0 - || strcasecmp(request->ParamNames[i], "IDENTIFIERS") == 0 ) { - msDebug("msWCSParseRequest(): Whole String: %s\n", request->ParamValues[i]); - params->coverages = CSLAddString(params->coverages, request->ParamValues[i]); - } - /* WCS 1.1 style BOUNDINGBOX */ - else if(strcasecmp(request->ParamNames[i], "BOUNDINGBOX") == 0) { - tokens = msStringSplit(request->ParamValues[i], ',', &n); - if(tokens==NULL || n < 5) { - msSetError(MS_WCSERR, "Wrong number of arguments for BOUNDINGBOX.", "msWCSParseRequest()"); - return msWCSException(map, "InvalidParameterValue", "boundingbox", - params->version ); - } - - /* NOTE: WCS 1.1 boundingbox is center of pixel oriented, not edge - like in WCS 1.0. So bbox semantics are wonky till this is fixed - later in the GetCoverage processing. */ - params->bbox.minx = atof(tokens[0]); - params->bbox.miny = atof(tokens[1]); - params->bbox.maxx = atof(tokens[2]); - params->bbox.maxy = atof(tokens[3]); - - params->crs = msStrdup(tokens[4]); - msFreeCharArray(tokens, n); - /* normalize imageCRS urns to simply "imageCRS" */ - if( strncasecmp(params->crs,"urn:ogc:def:crs:",16) == 0 - && strncasecmp(params->crs+strlen(params->crs)-8,"imageCRS",8)==0) - strcpy( params->crs, "imageCRS" ); - } else if(strcasecmp(request->ParamNames[i], "GridOffsets") == 0) { - tokens = msStringSplit(request->ParamValues[i], ',', &n); - if(tokens==NULL || n < 2) { - msSetError(MS_WCSERR, "Wrong number of arguments for GridOffsets", - "msWCSParseRequest()"); - return msWCSException(map, "InvalidParameterValue", "GridOffsets", - params->version ); - } - /* take absolute values to convert to positive RESX/RESY style - WCS 1.0 behavior. *but* this does break some possibilities! */ - params->resx = fabs(atof(tokens[0])); - params->resy = fabs(atof(tokens[1])); - msFreeCharArray(tokens, n); - } else if(strcasecmp(request->ParamNames[i], "GridOrigin") == 0) { - tokens = msStringSplit(request->ParamValues[i], ',', &n); - if(tokens==NULL || n < 2) { - msSetError(MS_WCSERR, "Wrong number of arguments for GridOrigin", - "msWCSParseRequest()"); - return msWCSException(map, "InvalidParameterValue", "GridOffsets", - params->version ); - } - params->originx = atof(tokens[0]); - params->originy = atof(tokens[1]); - msFreeCharArray(tokens, n); - } - - /* and so on... */ - } - } - /* we are not dealing with an XML encoded request at this point */ - return MS_SUCCESS; -} - -/************************************************************************/ -/* msWCSGetCapabilities_Service_ResponsibleParty() */ -/************************************************************************/ - -static void msWCSGetCapabilities_Service_ResponsibleParty(mapObj *map) -{ - int bEnableTelephone=MS_FALSE, bEnableAddress=MS_FALSE, bEnableOnlineResource=MS_FALSE; - - /* the WCS-specific way */ - if(msOWSLookupMetadata(&(map->web.metadata), "CO", "responsibleparty_individualname") || - msOWSLookupMetadata(&(map->web.metadata), "CO", "responsibleparty_organizationname")) { - - msIO_printf("\n"); - msOWSPrintEncodeMetadata(stdout, &(map->web.metadata), "CO", "responsibleparty_individualname", OWS_NOERR, " %s\n", NULL); - msOWSPrintEncodeMetadata(stdout, &(map->web.metadata), "CO", "responsibleparty_organizationname", OWS_NOERR, " %s\n", NULL); - msOWSPrintEncodeMetadata(stdout, &(map->web.metadata), "CO", "responsibleparty_positionname", OWS_NOERR, " %s\n", NULL); - - if(msOWSLookupMetadata(&(map->web.metadata), "CO", "responsibleparty_phone_voice") || - msOWSLookupMetadata(&(map->web.metadata), "CO", "responsibleparty_phone_facsimile")) bEnableTelephone = MS_TRUE; - - if(msOWSLookupMetadata(&(map->web.metadata), "CO", "responsibleparty_address_deliverypoint") || - msOWSLookupMetadata(&(map->web.metadata), "CO", "responsibleparty_address_city") || - msOWSLookupMetadata(&(map->web.metadata), "CO", "responsibleparty_address_administrativearea") || - msOWSLookupMetadata(&(map->web.metadata), "CO", "responsibleparty_address_postalcode") || - msOWSLookupMetadata(&(map->web.metadata), "CO", "responsibleparty_address_country") || - msOWSLookupMetadata(&(map->web.metadata), "CO", "responsibleparty_address_electronicmailaddress")) bEnableAddress = MS_TRUE; - - if(msOWSLookupMetadata(&(map->web.metadata), "CO", "responsibleparty_onlineresource")) bEnableOnlineResource = MS_TRUE; - - if(bEnableTelephone || bEnableAddress || bEnableOnlineResource) { - msIO_printf(" \n"); - if(bEnableTelephone) { - msIO_printf(" \n"); - msOWSPrintEncodeMetadata(stdout, &(map->web.metadata), "CO", "responsibleparty_phone_voice", OWS_NOERR, " %s\n", NULL); - msOWSPrintEncodeMetadata(stdout, &(map->web.metadata), "CO", "responsibleparty_phone_facsimile", OWS_NOERR, " %s\n", NULL); - msIO_printf(" \n"); - } - if(bEnableAddress) { - msIO_printf("
\n"); - msOWSPrintEncodeMetadata(stdout, &(map->web.metadata), "CO", "responsibleparty_address_deliverypoint", OWS_NOERR, " %s\n", NULL); - msOWSPrintEncodeMetadata(stdout, &(map->web.metadata), "CO", "responsibleparty_address_city", OWS_NOERR, " %s\n", NULL); - msOWSPrintEncodeMetadata(stdout, &(map->web.metadata), "CO", "responsibleparty_address_administrativearea", OWS_NOERR, " %s\n", NULL); - msOWSPrintEncodeMetadata(stdout, &(map->web.metadata), "CO", "responsibleparty_address_postalcode", OWS_NOERR, " %s\n", NULL); - msOWSPrintEncodeMetadata(stdout, &(map->web.metadata), "CO", "responsibleparty_address_country", OWS_NOERR, " %s\n", NULL); - msOWSPrintEncodeMetadata(stdout, &(map->web.metadata), "CO", "responsibleparty_address_electronicmailaddress", OWS_NOERR, " %s\n", NULL); - msIO_printf("
\n"); - } - msOWSPrintEncodeMetadata(stdout, &(map->web.metadata), "CO", "responsibleparty_onlineresource", OWS_NOERR, " \n", NULL); - msIO_printf("
\n"); - } - - msIO_printf("
\n"); - - } else if(msOWSLookupMetadata(&(map->web.metadata), "CO", "contactperson") || - msOWSLookupMetadata(&(map->web.metadata), "CO", "contactorganization")) { /* leverage WMS contact information */ - - msIO_printf("\n"); - msOWSPrintEncodeMetadata(stdout, &(map->web.metadata), "CO", "contactperson", OWS_NOERR, " %s\n", NULL); - msOWSPrintEncodeMetadata(stdout, &(map->web.metadata), "CO", "contactorganization", OWS_NOERR, " %s\n", NULL); - msOWSPrintEncodeMetadata(stdout, &(map->web.metadata), "CO", "contactposition", OWS_NOERR, " %s\n", NULL); - - if(msOWSLookupMetadata(&(map->web.metadata), "CO", "contactvoicetelephone") || - msOWSLookupMetadata(&(map->web.metadata), "CO", "contactfacsimiletelephone")) bEnableTelephone = MS_TRUE; - - if(msOWSLookupMetadata(&(map->web.metadata), "CO", "address") || - msOWSLookupMetadata(&(map->web.metadata), "CO", "city") || - msOWSLookupMetadata(&(map->web.metadata), "CO", "stateorprovince") || - msOWSLookupMetadata(&(map->web.metadata), "CO", "postcode") || - msOWSLookupMetadata(&(map->web.metadata), "CO", "country") || - msOWSLookupMetadata(&(map->web.metadata), "CO", "contactelectronicmailaddress")) bEnableAddress = MS_TRUE; - - if(msOWSLookupMetadata(&(map->web.metadata), "CO", "service_onlineresource")) bEnableOnlineResource = MS_TRUE; - - if(bEnableTelephone || bEnableAddress || bEnableOnlineResource) { - msIO_printf(" \n"); - if(bEnableTelephone) { - msIO_printf(" \n"); - msOWSPrintEncodeMetadata(stdout, &(map->web.metadata), "CO", "contactvoicetelephone", OWS_NOERR, " %s\n", NULL); - msOWSPrintEncodeMetadata(stdout, &(map->web.metadata), "CO", "contactfacsimiletelephone", OWS_NOERR, " %s\n", NULL); - msIO_printf(" \n"); - } - if(bEnableAddress) { - msIO_printf("
\n"); - msOWSPrintEncodeMetadata(stdout, &(map->web.metadata), "CO", "address", OWS_NOERR, " %s\n", NULL); - msOWSPrintEncodeMetadata(stdout, &(map->web.metadata), "CO", "city", OWS_NOERR, " %s\n", NULL); - msOWSPrintEncodeMetadata(stdout, &(map->web.metadata), "CO", "stateorprovince", OWS_NOERR, " %s\n", NULL); - msOWSPrintEncodeMetadata(stdout, &(map->web.metadata), "CO", "postcode", OWS_NOERR, " %s\n", NULL); - msOWSPrintEncodeMetadata(stdout, &(map->web.metadata), "CO", "country", OWS_NOERR, " %s\n", NULL); - msOWSPrintEncodeMetadata(stdout, &(map->web.metadata), "CO", "contactelectronicmailaddress", OWS_NOERR, " %s\n", NULL); - msIO_printf("
\n"); - } - msOWSPrintEncodeMetadata(stdout, &(map->web.metadata), "CO", "service_onlineresource", OWS_NOERR, " \n", NULL); - msIO_printf("
\n"); - } - msIO_printf("
\n"); - } - - return; -} - -/************************************************************************/ -/* msWCSGetCapabilities_Service() */ -/************************************************************************/ - -static int msWCSGetCapabilities_Service(mapObj *map, wcsParamsObj *params) -{ - /* start the Service section, only need the full start tag if this is the only section requested */ - if(!params->section || (params->section && strcasecmp(params->section, "/") == 0)) - msIO_printf("\n"); - else - msIO_printf("\n", params->version, params->updatesequence, msOWSGetSchemasLocation(map), params->version); - - /* optional metadataLink */ - msOWSPrintURLType(stdout, &(map->web.metadata), "CO", "metadatalink", - OWS_NOERR, - " ", - NULL, " metadataType=\"%s\"", NULL, NULL, NULL, - " xlink:href=\"%s\"", MS_FALSE, MS_FALSE, MS_FALSE, - MS_FALSE, MS_TRUE, "other", NULL, NULL, NULL, NULL, NULL); - - msOWSPrintEncodeMetadata(stdout, &(map->web.metadata), "CO", "description", OWS_NOERR, " %s\n", NULL); - msOWSPrintEncodeMetadata(stdout, &(map->web.metadata), "CO", "name", OWS_NOERR, " %s\n", "MapServer WCS"); - msOWSPrintEncodeMetadata(stdout, &(map->web.metadata), "CO", "label", OWS_WARN, " \n", NULL); - - /* we are not supporting the optional keyword type, at least not yet */ - msOWSPrintEncodeMetadataList(stdout, &(map->web.metadata), "CO", "keywordlist", " \n", " \n", " %s\n", NULL); - - msWCSGetCapabilities_Service_ResponsibleParty(map); - - msOWSPrintEncodeMetadata(stdout, &(map->web.metadata), "CO", "fees", OWS_NOERR, " %s\n", "NONE"); - msOWSPrintEncodeMetadataList(stdout, &(map->web.metadata), "CO", "accessconstraints", " \n", " \n", " %s\n", "NONE"); - - /* done */ - msIO_printf("\n"); - - return MS_SUCCESS; -} - -/************************************************************************/ -/* msWCSGetCapabilities_Capability() */ -/************************************************************************/ - -static int msWCSGetCapabilities_Capability(mapObj *map, wcsParamsObj *params, cgiRequestObj *req) -{ - char *script_url=NULL, *script_url_encoded=NULL; - - /* we need this server's onlineresource for the request section */ - if((script_url=msOWSGetOnlineResource(map, "CO", "onlineresource", req)) == NULL || (script_url_encoded = msEncodeHTMLEntities(script_url)) == NULL) { - free(script_url); - free(script_url_encoded); - return msWCSException(map, NULL, NULL, params->version ); - } - - /* start the Capabilty section, only need the full start tag if this is the only section requested */ - if(!params->section || (params->section && strcasecmp(params->section, "/") == 0)) - msIO_printf("\n"); - else - msIO_printf("\n", params->version, params->updatesequence, msOWSGetSchemasLocation(map), params->version); - - /* describe the types of requests the server can handle */ - msIO_printf(" \n"); - - msWCSPrintRequestCapability(params->version, "GetCapabilities", script_url_encoded); - if (msOWSRequestIsEnabled(map, NULL, "C", "DescribeCoverage", MS_FALSE)) - msWCSPrintRequestCapability(params->version, "DescribeCoverage", script_url_encoded); - if (msOWSRequestIsEnabled(map, NULL, "C", "GetCoverage", MS_FALSE)) - msWCSPrintRequestCapability(params->version, "GetCoverage", script_url_encoded); - - msIO_printf(" \n"); - - /* describe the exception formats the server can produce */ - msIO_printf(" \n"); - msIO_printf(" application/vnd.ogc.se_xml\n"); - msIO_printf(" \n"); - - /* describe any vendor specific capabilities */ - /* msIO_printf(" \n"); */ /* none yet */ - - /* done */ - msIO_printf("\n"); - - free(script_url); - free(script_url_encoded); - - return MS_SUCCESS; -} - -/************************************************************************/ -/* msWCSPrintMetadataLink() */ -/************************************************************************/ - -static void msWCSPrintMetadataLink(layerObj *layer, const char *script_url_encoded) -{ - const char* list = msOWSLookupMetadata(&(layer->metadata), "CO", "metadatalink_list"); - if( list ) { - int ntokens = 0; - char** tokens = msStringSplit(list, ' ', &ntokens); - for( int i = 0; i < ntokens; i++ ) - { - std::string key("metadatalink_"); - key += tokens[i]; - msOWSPrintURLType(stdout, &(layer->metadata), "CO", key.c_str(), - OWS_NOERR, - " ", - NULL, " metadataType=\"%s\"", NULL, NULL, NULL, - " xlink:href=\"%s\"", MS_FALSE, MS_FALSE, MS_FALSE, - MS_FALSE, MS_TRUE, "other", NULL, NULL, NULL, NULL, NULL); - } - msFreeCharArray(tokens, ntokens); - return; - } - - /* optional metadataLink */ - if (! msOWSLookupMetadata(&(layer->metadata), "CO", "metadatalink_href")) - msMetadataSetGetMetadataURL(layer, script_url_encoded); - - msOWSPrintURLType(stdout, &(layer->metadata), "CO", "metadatalink", - OWS_NOERR, - " ", - NULL, " metadataType=\"%s\"", NULL, NULL, NULL, - " xlink:href=\"%s\"", MS_FALSE, MS_FALSE, MS_FALSE, - MS_FALSE, MS_TRUE, "other", NULL, NULL, NULL, NULL, NULL); - -} - -/************************************************************************/ -/* msWCSGetCapabilities_CoverageOfferingBrief() */ -/************************************************************************/ - -static int msWCSGetCapabilities_CoverageOfferingBrief(layerObj *layer, wcsParamsObj *params, const char *script_url_encoded) -{ - coverageMetadataObj cm; - int status; - - if((layer->status == MS_DELETE) || !msWCSIsLayerSupported(layer)) return MS_SUCCESS; /* not an error, this layer cannot be served via WCS */ - - status = msWCSGetCoverageMetadata(layer, &cm); - if(status != MS_SUCCESS) return MS_FAILURE; - - /* start the CoverageOfferingBrief section */ - msIO_printf(" \n"); /* is this tag right? (I hate schemas without ANY examples) */ - - msWCSPrintMetadataLink(layer, script_url_encoded); - - msOWSPrintEncodeMetadata(stdout, &(layer->metadata), "CO", "description", OWS_NOERR, " %s\n", NULL); - msOWSPrintEncodeMetadata(stdout, &(layer->metadata), "CO", "name", OWS_NOERR, " %s\n", layer->name); - - msOWSPrintEncodeMetadata(stdout, &(layer->metadata), "CO", "label", OWS_WARN, " \n", NULL); - - /* TODO: add elevation ranges to lonLatEnvelope (optional) */ - msIO_printf(" \n"); - msIO_printf(" %.15g %.15g\n", cm.llextent.minx, cm.llextent.miny); /* TODO: don't know if this is right */ - msIO_printf(" %.15g %.15g\n", cm.llextent.maxx, cm.llextent.maxy); - - msOWSPrintEncodeMetadataList(stdout, &(layer->metadata), "CO", "timeposition", NULL, NULL, " %s\n", NULL); - - msIO_printf(" \n"); - - /* we are not supporting the optional keyword type, at least not yet */ - msOWSPrintEncodeMetadataList(stdout, &(layer->metadata), "CO", "keywordlist", " \n", " \n", " %s\n", NULL); - - /* done */ - msIO_printf(" \n"); - - msWCSFreeCoverageMetadata(&cm); - - return MS_SUCCESS; -} - -/************************************************************************/ -/* msWCSGetCapabilities_ContentMetadata() */ -/************************************************************************/ - -static int msWCSGetCapabilities_ContentMetadata(mapObj *map, wcsParamsObj *params, owsRequestObj *ows_request, cgiRequestObj *req) -{ - int i; - char *script_url_encoded=NULL; - - { - char* pszTmp = msOWSGetOnlineResource(map, "CO", "onlineresource", req); - script_url_encoded = msEncodeHTMLEntities(pszTmp); - msFree(pszTmp); - } - - /* start the ContentMetadata section, only need the full start tag if this is the only section requested */ - /* TODO: add Xlink attributes for other sources of this information */ - if(!params->section || (params->section && strcasecmp(params->section, "/") == 0)) - msIO_printf("\n"); - else - msIO_printf("\n", params->version, params->updatesequence, msOWSGetSchemasLocation(map), params->version); - - if(ows_request->numlayers == 0) { - msIO_printf(" \n"); - } else { - for(i=0; inumlayers; i++) { - if (!msIntegerInArray(GET_LAYER(map, i)->index, ows_request->enabled_layers, ows_request->numlayers)) - continue; - - if(msWCSGetCapabilities_CoverageOfferingBrief((GET_LAYER(map, i)), params, script_url_encoded) != MS_SUCCESS ) { - msIO_printf(" \n"); - } - } - } - - msFree(script_url_encoded); - - /* done */ - msIO_printf("\n"); - - return MS_SUCCESS; -} - -/************************************************************************/ -/* msWCSGetCapabilities() */ -/************************************************************************/ - -static int msWCSGetCapabilities(mapObj *map, wcsParamsObj *params, cgiRequestObj *req, owsRequestObj *ows_request) -{ - char tmpString[OWS_VERSION_MAXLEN]; - int i, tmpInt = 0; - int wcsSupportedVersions[] = {OWS_1_1_2, OWS_1_1_1, OWS_1_1_0, OWS_1_0_0}; - int wcsNumSupportedVersions = 4; - const char *updatesequence=NULL; - - /* check version is valid */ - tmpInt = msOWSParseVersionString(params->version); - if (tmpInt == OWS_VERSION_BADFORMAT) { - return msWCSException(map, "InvalidParameterValue", - "version", "1.0.0 "); - } - - /* negotiate version */ - tmpInt = msOWSNegotiateVersion(tmpInt, wcsSupportedVersions, wcsNumSupportedVersions); - - /* set result as string and carry on */ - free(params->version); - params->version = msStrdup(msOWSGetVersionString(tmpInt, tmpString)); - - /* -------------------------------------------------------------------- */ - /* 1.1.x is sufficiently different we have a whole case for */ - /* it. The remainder of this function is for 1.0.0. */ - /* -------------------------------------------------------------------- */ - if( strncmp(params->version,"1.1",3) == 0 ) - return msWCSGetCapabilities11( map, params, req, ows_request); - - updatesequence = msOWSLookupMetadata(&(map->web.metadata), "CO", "updatesequence"); - - if (params->updatesequence != NULL) { - i = msOWSNegotiateUpdateSequence(params->updatesequence, updatesequence); - if (i == 0) { /* current */ - msSetError(MS_WCSERR, "UPDATESEQUENCE parameter (%s) is equal to server (%s)", "msWCSGetCapabilities()", params->updatesequence, updatesequence); - return msWCSException(map, "CurrentUpdateSequence", - "updatesequence", params->version ); - } - if (i > 0) { /* invalid */ - msSetError(MS_WCSERR, "UPDATESEQUENCE parameter (%s) is higher than server (%s)", "msWCSGetCapabilities()", params->updatesequence, updatesequence); - return msWCSException(map, "InvalidUpdateSequence", - "updatesequence", params->version ); - } - } - - else { /* set default updatesequence */ - if(!updatesequence) - updatesequence = "0"; - params->updatesequence = msStrdup(updatesequence); - } - - /* if a bum section param is passed, throw exception */ - if (params->section && - strcasecmp(params->section, "/WCS_Capabilities/Service") != 0 && - strcasecmp(params->section, "/WCS_Capabilities/Capability") != 0 && - strcasecmp(params->section, "/WCS_Capabilities/ContentMetadata") != 0 && - strcasecmp(params->section, "/") != 0) { - msIO_setHeader("Content-Type","application/vnd.ogc.se_xml; charset=UTF-8"); - msIO_sendHeaders(); - msSetError( MS_WCSERR, - "Invalid SECTION parameter \"%s\"", - "msWCSGetCapabilities()", params->section); - return msWCSException(map, "InvalidParameterValue", "section", - params->version ); - } - - else { - msIO_setHeader("Content-Type","text/xml; charset=UTF-8"); - msIO_sendHeaders(); - - /* print common capability elements */ - /* TODO: DocType? */ - - if (!updatesequence) - updatesequence = "0"; - - msIO_printf("\n"); - - if(!params->section || (params->section && strcasecmp(params->section, "/") == 0)) msIO_printf("\n", params->version, updatesequence, msOWSGetSchemasLocation(map), params->version); - - /* print the various capability sections */ - if(!params->section || strcasecmp(params->section, "/WCS_Capabilities/Service") == 0) - msWCSGetCapabilities_Service(map, params); - - if(!params->section || strcasecmp(params->section, "/WCS_Capabilities/Capability") == 0) - msWCSGetCapabilities_Capability(map, params, req); - - if(!params->section || strcasecmp(params->section, "/WCS_Capabilities/ContentMetadata") == 0) - msWCSGetCapabilities_ContentMetadata(map, params, ows_request, req); - - if(params->section && strcasecmp(params->section, "/") == 0) { - msWCSGetCapabilities_Service(map, params); - msWCSGetCapabilities_Capability(map, params, req); - msWCSGetCapabilities_ContentMetadata(map, params, ows_request, req); - } - - /* done */ - if(!params->section || (params->section && strcasecmp(params->section, "/") == 0)) msIO_printf("\n"); - } - - return MS_SUCCESS; -} - -/************************************************************************/ -/* msWCSDescribeCoverage_AxisDescription() */ -/************************************************************************/ - -static int msWCSDescribeCoverage_AxisDescription(layerObj *layer, char *name) -{ - const char *value; - char tag[100]; /* should be plenty of space */ - - msIO_printf(" \n"); - msIO_printf(" metadata), "CO", tag, OWS_NOERR, " semantic=\"%s\"", NULL); - snprintf(tag, sizeof(tag), "%s_refsys", name); - msOWSPrintEncodeMetadata(stdout, &(layer->metadata), "CO", tag, OWS_NOERR, " refSys=\"%s\"", NULL); - snprintf(tag, sizeof(tag), "%s_refsyslabel", name); - msOWSPrintEncodeMetadata(stdout, &(layer->metadata), "CO", tag, OWS_NOERR, " refSysLabel=\"%s\"", NULL); - msIO_printf(">\n"); - - /* TODO: add metadataLink (optional) */ - - snprintf(tag, sizeof(tag), "%s_description", name); - msOWSPrintEncodeMetadata(stdout, &(layer->metadata), "CO", tag, OWS_NOERR, " %s\n", NULL); - /* snprintf(tag, sizeof(tag), "%s_name", name); */ - /* msOWSPrintEncodeMetadata(stdout, &(layer->metadata), "CO", tag, OWS_WARN, " %s\n", NULL); */ - msIO_printf(" %s\n", name); - - snprintf(tag, sizeof(tag), "%s_label", name); - msOWSPrintEncodeMetadata(stdout, &(layer->metadata), "CO", tag, OWS_WARN, " \n", NULL); - - /* Values */ - msIO_printf(" metadata), "CO", tag, OWS_NOERR, " semantic=\"%s\"", NULL); - snprintf(tag, sizeof(tag), "%s_values_type", name); - msOWSPrintEncodeMetadata(stdout, &(layer->metadata), "CO", tag, OWS_NOERR, " type=\"%s\"", NULL); - msIO_printf(">\n"); - - /* single values, we do not support optional type and semantic attributes */ - snprintf(tag, sizeof(tag), "%s_values", name); - if(msOWSLookupMetadata(&(layer->metadata), "CO", tag)) - msOWSPrintEncodeMetadataList(stdout, &(layer->metadata), "CO", tag, NULL, NULL, " %s\n", NULL); - - /* intervals, only one per axis for now, we do not support optional type, atomic and semantic attributes */ - snprintf(tag, sizeof(tag), "%s_interval", name); - if((value = msOWSLookupMetadata(&(layer->metadata), "CO", tag)) != NULL) { - char **tokens; - int numtokens; - - tokens = msStringSplit(value, '/', &numtokens); - if(tokens && numtokens > 0) { - msIO_printf(" \n"); - if(numtokens >= 1) msIO_printf(" %s\n", tokens[0]); /* TODO: handle closure */ - if(numtokens >= 2) msIO_printf(" %s\n", tokens[1]); - if(numtokens >= 3) msIO_printf(" %s\n", tokens[2]); - msIO_printf(" \n"); - } - } - - /* TODO: add default (optional) */ - - msIO_printf(" \n"); - - msIO_printf(" \n"); - msIO_printf(" \n"); - - return MS_SUCCESS; -} - -/************************************************************************/ -/* msWCSDescribeCoverage_CoverageOffering() */ -/************************************************************************/ - -static int msWCSDescribeCoverage_CoverageOffering(layerObj *layer, wcsParamsObj *params, char *script_url_encoded) -{ - char **tokens; - int numtokens; - const char *value; - char *epsg_buf, *encoded_format; - coverageMetadataObj cm; - int i, status; - - if ( msCheckParentPointer(layer->map,"map")==MS_FAILURE ) - return MS_FAILURE; - - if(!msWCSIsLayerSupported(layer)) return MS_SUCCESS; /* not an error, this layer cannot be served via WCS */ - - - status = msWCSGetCoverageMetadata(layer, &cm); - if(status != MS_SUCCESS) return MS_FAILURE; - - /* fill in bands rangeset info, if required. */ - msWCSSetDefaultBandsRangeSetInfo( params, &cm, layer ); - - /* start the Coverage section */ - msIO_printf(" \n"); - - msWCSPrintMetadataLink(layer, script_url_encoded); - - msOWSPrintEncodeMetadata(stdout, &(layer->metadata), "CO", "description", OWS_NOERR, " %s\n", NULL); - msOWSPrintEncodeMetadata(stdout, &(layer->metadata), "CO", "name", OWS_NOERR, " %s\n", layer->name); - - msOWSPrintEncodeMetadata(stdout, &(layer->metadata), "CO", "label", OWS_WARN, " \n", NULL); - - /* TODO: add elevation ranges to lonLatEnvelope (optional) */ - msIO_printf(" \n"); - msIO_printf(" %.15g %.15g\n", cm.llextent.minx, cm.llextent.miny); - msIO_printf(" %.15g %.15g\n", cm.llextent.maxx, cm.llextent.maxy); - - msOWSPrintEncodeMetadataList(stdout, &(layer->metadata), "CO", "timeposition", NULL, NULL, " %s\n", NULL); - - msIO_printf(" \n"); - - /* we are not supporting the optional keyword type, at least not yet */ - msOWSPrintEncodeMetadataList(stdout, &(layer->metadata), "CO", "keywordlist", " \n", " \n", " %s\n", NULL); - - /* DomainSet: starting simple, just a spatial domain (gml:envelope) and optionally a temporal domain */ - msIO_printf(" \n"); - - /* SpatialDomain */ - msIO_printf(" \n"); - - /* envelope in lat/lon */ - msIO_printf(" \n"); - msIO_printf(" %.15g %.15g\n", cm.llextent.minx, cm.llextent.miny); - msIO_printf(" %.15g %.15g\n", cm.llextent.maxx, cm.llextent.maxy); - msIO_printf(" \n"); - - /* envelope in the native srs */ - msOWSGetEPSGProj(&(layer->projection), &(layer->metadata), "CO", MS_TRUE, &epsg_buf); - if(!epsg_buf) { - msOWSGetEPSGProj(&(layer->map->projection), &(layer->map->web.metadata), "CO", MS_TRUE, &epsg_buf); - } - if(epsg_buf) { - msIO_printf(" \n", epsg_buf); - msFree(epsg_buf); - } else { - msIO_printf(" \n"); - } - msIO_printf(" %.15g %.15g\n", cm.extent.minx, cm.extent.miny); - msIO_printf(" %.15g %.15g\n", cm.extent.maxx, cm.extent.maxy); - msIO_printf(" \n"); - - /* gml:rectifiedGrid */ - msIO_printf(" \n"); - msIO_printf(" \n"); - msIO_printf(" \n"); - msIO_printf(" 0 0\n"); - msIO_printf(" %d %d\n", cm.xsize-1, cm.ysize-1); - msIO_printf(" \n"); - msIO_printf(" \n"); - msIO_printf(" x\n"); - msIO_printf(" y\n"); - msIO_printf(" \n"); - msIO_printf(" %.15g %.15g\n", cm.geotransform[0], cm.geotransform[3]); - msIO_printf(" \n"); - msIO_printf(" %.15g %.15g\n", cm.geotransform[1], cm.geotransform[2]); /* offset vector in X direction */ - msIO_printf(" %.15g %.15g\n", cm.geotransform[4], cm.geotransform[5]); /* offset vector in Y direction */ - msIO_printf(" \n"); - - msIO_printf(" \n"); - - msWCSFreeCoverageMetadata(&cm); - - /* TemporalDomain */ - - /* TODO: figure out when a temporal domain is valid, for example only tiled rasters support time as a domain, plus we need a timeitem */ - if(msOWSLookupMetadata(&(layer->metadata), "CO", "timeposition") || msOWSLookupMetadata(&(layer->metadata), "CO", "timeperiod")) { - msIO_printf(" \n"); - - /* TimePosition (should support a value AUTO, then we could mine positions from the timeitem) */ - msOWSPrintEncodeMetadataList(stdout, &(layer->metadata), "CO", "timeposition", NULL, NULL, " %s\n", NULL); - - /* TODO: add TimePeriod (only one per layer) */ - - msIO_printf(" \n"); - } - - msIO_printf(" \n"); - - /* rangeSet */ - msIO_printf(" \n"); - msIO_printf(" \n"); /* TODO: there are some optional attributes */ - - /* TODO: add metadataLink (optional) */ - - msOWSPrintEncodeMetadata(stdout, &(layer->metadata), "CO", "rangeset_description", OWS_NOERR, " %s\n", NULL); - msOWSPrintEncodeMetadata(stdout, &(layer->metadata), "CO", "rangeset_name", OWS_WARN, " %s\n", NULL); - - msOWSPrintEncodeMetadata(stdout, &(layer->metadata), "CO", "rangeset_label", OWS_WARN, " \n", NULL); - - /* compound range sets */ - if((value = msOWSLookupMetadata(&(layer->metadata), "CO", "rangeset_axes")) != NULL) { - tokens = msStringSplit(value, ',', &numtokens); - if(tokens && numtokens > 0) { - for(i=0; imetadata), "CO", "rangeset_nullvalue")) != NULL) { - msIO_printf(" \n"); - msIO_printf(" %s\n", value); - msIO_printf(" \n"); - } - - msIO_printf(" \n"); - msIO_printf(" \n"); - - /* supportedCRSs */ - msIO_printf(" \n"); - - /* requestResposeCRSs: check the layer metadata/projection, and then the map metadata/projection if necessary (should never get to the error message) */ - msOWSGetEPSGProj(&(layer->projection), &(layer->metadata), "CO", MS_FALSE, &epsg_buf); - if(!epsg_buf) { - msOWSGetEPSGProj(&(layer->map->projection), &(layer->map->web.metadata), "CO", MS_FALSE, &epsg_buf); - } - if(epsg_buf) { - tokens = msStringSplit(epsg_buf, ' ', &numtokens); - if(tokens && numtokens > 0) { - for(i=0; i%s\n", tokens[i]); - msFreeCharArray(tokens, numtokens); - } - msFree(epsg_buf); - } else { - msIO_printf(" \n"); - } - - /* nativeCRSs (only one in our case) */ - msOWSGetEPSGProj(&(layer->projection), &(layer->metadata), "CO", MS_TRUE, &epsg_buf); - if(!epsg_buf) { - msOWSGetEPSGProj(&(layer->map->projection), &(layer->map->web.metadata), "CO", MS_TRUE, &epsg_buf); - } - if(epsg_buf) { - msIO_printf(" %s\n", epsg_buf); - msFree(epsg_buf); - } else { - msIO_printf(" \n"); - } - - msIO_printf(" \n"); - - - /* supportedFormats */ - msIO_printf(" metadata), "CO", "nativeformat", OWS_NOERR, " nativeFormat=\"%s\"", NULL); - msIO_printf(">\n"); - - if( (encoded_format = msOWSGetEncodeMetadata( &(layer->metadata), "CO", "formats", - "GTiff" )) != NULL ) { - tokens = msStringSplit(encoded_format, ' ', &numtokens); - if(tokens && numtokens > 0) { - for(i=0; i%s
\n", tokens[i]); - msFreeCharArray(tokens, numtokens); - } - msFree(encoded_format); - } - msIO_printf(" \n"); - - msIO_printf(" \n"); - msIO_printf(" nearest neighbor\n" ); - msIO_printf(" bilinear\n" ); - /* msIO_printf(" bicubic\n" ); */ - msIO_printf(" \n"); - - - /* done */ - msIO_printf(" \n"); - - return MS_SUCCESS; -} - -/************************************************************************/ -/* msWCSDescribeCoverage() */ -/************************************************************************/ - -static int msWCSDescribeCoverage(mapObj *map, wcsParamsObj *params, owsRequestObj *ows_request, cgiRequestObj *req) -{ - int i = 0,j = 0, k = 0; - const char *updatesequence=NULL; - char **coverages=NULL; - int numcoverages=0; - - char *coverageName=NULL; - char *script_url_encoded=NULL; - - /* -------------------------------------------------------------------- */ - /* 1.1.x is sufficiently different we have a whole case for */ - /* it. The remainder of this function is for 1.0.0. */ - /* -------------------------------------------------------------------- */ - if( strncmp(params->version,"1.1",3) == 0 ) - return msWCSDescribeCoverage11( map, params, ows_request); - - /* -------------------------------------------------------------------- */ - /* Process 1.0.0... */ - /* -------------------------------------------------------------------- */ - - if(params->coverages) { /* use the list, but validate it first */ - for(j=0; params->coverages[j]; j++) { - coverages = msStringSplit(params->coverages[j], ',', &numcoverages); - for(k=0; knumlayers; i++) { - coverageName = msOWSGetEncodeMetadata(&(GET_LAYER(map, i)->metadata), "CO", "name", GET_LAYER(map, i)->name); - if( coverageName != NULL && EQUAL(coverageName, coverages[k]) && - (msIntegerInArray(GET_LAYER(map, i)->index, ows_request->enabled_layers, ows_request->numlayers)) ) { - msFree(coverageName); - break; - } - msFree(coverageName); - } - - /* i = msGetLayerIndex(map, coverages[k]); */ - if(i == map->numlayers) { /* coverage not found */ - msSetError( MS_WCSERR, "COVERAGE %s cannot be opened / does not exist. A layer might be disabled for \ -this request. Check wcs/ows_enable_request settings.", "msWCSDescribeCoverage()", coverages[k]); - return msWCSException(map, "CoverageNotDefined", "coverage", params->version ); - } - } /* next coverage */ - msFreeCharArray(coverages,numcoverages); - } - } - - updatesequence = msOWSLookupMetadata(&(map->web.metadata), "CO", "updatesequence"); - if (!updatesequence) - updatesequence = "0"; - - /* printf("Content-Type: application/vnd.ogc.se_xml%c%c",10,10); */ - msIO_setHeader("Content-Type","text/xml; charset=UTF-8"); - msIO_sendHeaders(); - - /* print common capability elements */ - msIO_printf("\n"); - - /* start the DescribeCoverage section */ - msIO_printf("\n", params->version, updatesequence, msOWSGetSchemasLocation(map), params->version); - - { - char* pszTmp = msOWSGetOnlineResource(map, "CO", "onlineresource", req); - script_url_encoded = msEncodeHTMLEntities(pszTmp); - msFree(pszTmp); - } - - if(params->coverages) { /* use the list */ - for( j = 0; params->coverages[j]; j++ ) { - coverages = msStringSplit(params->coverages[j], ',', &numcoverages); - for(k=0; knumlayers; i++) { - coverageName = msOWSGetEncodeMetadata(&(GET_LAYER(map, i)->metadata), "CO", "name", GET_LAYER(map, i)->name); - if( coverageName != NULL && EQUAL(coverageName, coverages[k]) ) { - msFree(coverageName); - break; - } - msFree(coverageName); - } - msWCSDescribeCoverage_CoverageOffering((GET_LAYER(map, i)), params, script_url_encoded); - } - msFreeCharArray(coverages,numcoverages); - } - } else { /* return all layers */ - for(i=0; inumlayers; i++) { - if (!msIntegerInArray(GET_LAYER(map, i)->index, ows_request->enabled_layers, ows_request->numlayers)) - continue; - - msWCSDescribeCoverage_CoverageOffering((GET_LAYER(map, i)), params, script_url_encoded); - } - } - - msFree(script_url_encoded); - - /* done */ - msIO_printf("\n"); - - return MS_SUCCESS; -} - -/************************************************************************/ -/* msWCSGetCoverageBands10() */ -/************************************************************************/ - -static int msWCSGetCoverageBands10( mapObj *map, cgiRequestObj *request, - wcsParamsObj *params, layerObj *lp, - char **p_bandlist ) - -{ - const char *value = NULL; - int i; - - /* Are there any non-spatio/temporal ranges to do subsetting on (e.g. bands) */ - value = msOWSLookupMetadata(&(lp->metadata), "CO", "rangeset_axes"); /* this will get all the compound range sets */ - if(value) { - char **tokens; - int numtokens; - char tag[100]; - const char *rangeitem; - - tokens = msStringSplit(value, ',', &numtokens); - - for(i=0; iversion ); - msFreeCharArray(tokens, numtokens); - return ret; - } - - /* xxxxx_rangeitem tells us how to subset */ - snprintf(tag, sizeof(tag), "%s_rangeitem", tokens[i]); - if((rangeitem = msOWSLookupMetadata(&(lp->metadata), "CO", tag)) == NULL) { - msSetError( MS_WCSERR, "Missing required metadata element \"%s\", unable to process %s=%s.", "msWCSGetCoverage()", tag, tokens[i], value); - msFreeCharArray(tokens, numtokens); - return msWCSException(map, NULL, NULL, params->version); - } - - if(strcasecmp(rangeitem, "_bands") == 0) { /* special case, subset bands */ - *p_bandlist = msWCSConvertRangeSetToString(value); - - if(!*p_bandlist) { - msSetError( MS_WCSERR, "Error specifying \"%s\" parameter value(s).", "msWCSGetCoverage()", tokens[i]); - msFreeCharArray(tokens, numtokens); - return msWCSException(map, NULL, NULL, params->version ); - } - } else if(strcasecmp(rangeitem, "_pixels") == 0) { /* special case, subset pixels */ - msFreeCharArray(tokens, numtokens); - msSetError( MS_WCSERR, "Arbitrary range sets based on pixel values are not yet supported.", "msWCSGetCoverage()" ); - return msWCSException(map, NULL, NULL, params->version); - } else { - msFreeCharArray(tokens, numtokens); - msSetError( MS_WCSERR, "Arbitrary range sets based on tile (i.e. image) attributes are not yet supported.", "msWCSGetCoverage()" ); - return msWCSException(map, NULL, NULL, params->version ); - } - } - /* clean-up */ - msFreeCharArray(tokens, numtokens); - } - - return MS_SUCCESS; -} - -/************************************************************************/ -/* msWCSGetCoverage_ImageCRSSetup() */ -/* */ -/* The request was in imageCRS - update the map projection to */ -/* map the native projection of the layer, and reset the */ -/* bounding box to match the projected bounds corresponding to */ -/* the imageCRS request. */ -/************************************************************************/ - -static int msWCSGetCoverage_ImageCRSSetup( - mapObj *map, cgiRequestObj *request, wcsParamsObj *params, - coverageMetadataObj *cm, layerObj *layer ) - -{ - /* -------------------------------------------------------------------- */ - /* Load map with the layer (coverage) coordinate system. We */ - /* really need a set projectionObj from projectionObj function! */ - /* -------------------------------------------------------------------- */ - char *layer_proj = msGetProjectionString( &(layer->projection) ); - - if (msLoadProjectionString(&(map->projection), layer_proj) != 0) - return msWCSException( map, NULL, NULL, params->version ); - - free( layer_proj ); - layer_proj = NULL; - - /* -------------------------------------------------------------------- */ - /* Reset bounding box. */ - /* -------------------------------------------------------------------- */ - if( params->bbox.maxx != params->bbox.minx ) { - rectObj orig_bbox = params->bbox; - - params->bbox.minx = - cm->geotransform[0] - + orig_bbox.minx * cm->geotransform[1] - + orig_bbox.miny * cm->geotransform[2]; - params->bbox.maxy = - cm->geotransform[3] - + orig_bbox.minx * cm->geotransform[4] - + orig_bbox.miny * cm->geotransform[5]; - params->bbox.maxx = - cm->geotransform[0] - + (orig_bbox.maxx+1) * cm->geotransform[1] - + (orig_bbox.maxy+1) * cm->geotransform[2]; - params->bbox.miny = - cm->geotransform[3] - + (orig_bbox.maxx+1) * cm->geotransform[4] - + (orig_bbox.maxy+1) * cm->geotransform[5]; - - /* WCS 1.1 boundbox is center of pixel oriented. */ - if( strncasecmp(params->version,"1.1",3) == 0 ) { - params->bbox.minx += cm->geotransform[1]/2 + cm->geotransform[2]/2; - params->bbox.maxx -= cm->geotransform[1]/2 + cm->geotransform[2]/2; - params->bbox.maxy += cm->geotransform[4]/2 + cm->geotransform[5]/2; - params->bbox.miny -= cm->geotransform[4]/2 + cm->geotransform[5]/2; - } - } - - /* -------------------------------------------------------------------- */ - /* Reset resolution. */ - /* -------------------------------------------------------------------- */ - if( params->resx != 0.0 ) { - params->resx = cm->geotransform[1] * params->resx; - params->resy = fabs(cm->geotransform[5] * params->resy); - } - - return MS_SUCCESS; -} - -/************************************************************************/ -/* msWCSApplyLayerCreationOptions() */ -/************************************************************************/ - -void msWCSApplyLayerCreationOptions(layerObj* lp, - outputFormatObj* format, - const char* bandlist) - -{ - const char* pszKey; - char szKeyBeginning[256]; - size_t nKeyBeginningLength; - int nBands = 0; - char** papszBandNumbers = msStringSplit(bandlist, ' ', &nBands); - - snprintf(szKeyBeginning, sizeof(szKeyBeginning), - "wcs_outputformat_%s_creationoption_", format->name); - nKeyBeginningLength = strlen(szKeyBeginning); - - pszKey = msFirstKeyFromHashTable( &(lp->metadata) ); - for( ; pszKey != NULL; - pszKey = msNextKeyFromHashTable( &(lp->metadata), pszKey) ) - { - if( strncmp(pszKey, szKeyBeginning, nKeyBeginningLength) == 0 ) - { - const char* pszValue = msLookupHashTable( &(lp->metadata), pszKey); - const char* pszGDALKey = pszKey + nKeyBeginningLength; - if( EQUALN(pszGDALKey, "BAND_", strlen("BAND_")) ) - { - /* Remap BAND specific creation option to the real output - * band number, given the band subset of the request */ - int nKeyOriBandNumber = atoi(pszGDALKey + strlen("BAND_")); - int nTargetBandNumber = -1; - int i; - for(i = 0; i < nBands; i++ ) - { - if( nKeyOriBandNumber == atoi(papszBandNumbers[i]) ) - { - nTargetBandNumber = i + 1; - break; - } - } - if( nTargetBandNumber > 0 ) - { - char szModKey[256]; - const char* pszAfterBand = - strchr(pszGDALKey + strlen("BAND_"), '_'); - if( pszAfterBand != NULL ) - { - snprintf(szModKey, sizeof(szModKey), - "BAND_%d%s", - nTargetBandNumber, - pszAfterBand); - if( lp->debug >= MS_DEBUGLEVEL_VVV ) { - msDebug("Setting GDAL %s=%s creation option\n", - szModKey, pszValue); - } - msSetOutputFormatOption(format, szModKey, pszValue); - } - } - } - else - { - if( lp->debug >= MS_DEBUGLEVEL_VVV ) { - msDebug("Setting GDAL %s=%s creation option\n", - pszGDALKey, pszValue); - } - msSetOutputFormatOption(format, pszGDALKey, pszValue); - } - } - } - - msFreeCharArray( papszBandNumbers, nBands ); -} - -/************************************************************************/ -/* msWCSApplyDatasetMetadataAsCreationOptions() */ -/************************************************************************/ - -void msWCSApplyDatasetMetadataAsCreationOptions(layerObj* lp, - outputFormatObj* format, - const char* bandlist, - void* hDSIn) -{ - /* Requires GDAL 2.3 in practice. */ - /* Automatic forwarding of input dataset metadata if it is GRIB and the */ - /* output is GRIB as well, and wcs_outputformat_GRIB_creationoption* are */ - /* not defined. */ - GDALDatasetH hDS = (GDALDatasetH)hDSIn; - if( hDS && GDALGetDatasetDriver(hDS) && - EQUAL(GDALGetDriverShortName(GDALGetDatasetDriver(hDS)), "GRIB") && - EQUAL(format->driver, "GDAL/GRIB") ) - { - const char* pszKey; - char szKeyBeginning[256]; - size_t nKeyBeginningLength; - int bWCSMetadataFound = MS_FALSE; - - snprintf(szKeyBeginning, sizeof(szKeyBeginning), - "wcs_outputformat_%s_creationoption_", format->name); - nKeyBeginningLength = strlen(szKeyBeginning); - - for( pszKey = msFirstKeyFromHashTable( &(lp->metadata) ); - pszKey != NULL; - pszKey = msNextKeyFromHashTable( &(lp->metadata), pszKey) ) - { - if( strncmp(pszKey, szKeyBeginning, nKeyBeginningLength) == 0 ) - { - bWCSMetadataFound = MS_TRUE; - break; - } - } - if( !bWCSMetadataFound ) - { - int nBands = 0; - char** papszBandNumbers = msStringSplit(bandlist, ' ', &nBands); - int i; - for(i = 0; i < nBands; i++ ) - { - int nSrcBand = atoi(papszBandNumbers[i]); - int nDstBand = i + 1; - GDALRasterBandH hBand = GDALGetRasterBand(hDS, nSrcBand); - if( hBand ) - { - char** papszMD = GDALGetMetadata(hBand, NULL); - const char* pszMDI = CSLFetchNameValue(papszMD, "GRIB_IDS"); - // Make sure it is a GRIB2 band - if( pszMDI ) - { - char szKey[256]; - sprintf(szKey, "BAND_%d_IDS", nDstBand); - msSetOutputFormatOption(format, szKey, pszMDI); - - sprintf(szKey, "BAND_%d_DISCIPLINE", nDstBand); - msSetOutputFormatOption(format, szKey, - CSLFetchNameValue(papszMD, "DISCIPLINE")); - - sprintf(szKey, "BAND_%d_PDS_PDTN", nDstBand); - msSetOutputFormatOption(format, szKey, - CSLFetchNameValue(papszMD, "GRIB_PDS_PDTN")); - - sprintf(szKey, "BAND_%d_PDS_TEMPLATE_NUMBERS", - nDstBand); - msSetOutputFormatOption(format, szKey, - CSLFetchNameValue(papszMD, - "GRIB_PDS_TEMPLATE_NUMBERS")); - } - } - } - msFreeCharArray( papszBandNumbers, nBands ); - } - } -} - -/************************************************************************/ -/* msWCSGetCoverage() */ -/************************************************************************/ - -static int msWCSGetCoverage(mapObj *map, cgiRequestObj *request, - wcsParamsObj *params, owsRequestObj *ows_request) -{ - imageObj *image; - layerObj *lp; - int status, i; - const char *value; - outputFormatObj *format; - char *bandlist=NULL; - size_t bufferSize = 0; - char numbands[12]; /* should be large enough to hold the number of bands in the bandlist */ - coverageMetadataObj cm; - rectObj reqextent; - rectObj covextent; - rasterBufferObj rb; - int doDrawRasterLayerDraw = MS_TRUE; - GDALDatasetH hDS = NULL; - - char *coverageName; - - /* make sure all required parameters are available (at least the easy ones) */ - if(!params->crs) { - msSetError( MS_WCSERR, "Required parameter CRS was not supplied.", "msWCSGetCoverage()"); - return msWCSException(map, "MissingParameterValue", "crs", params->version); - } - - if(!params->time && !params->bbox.minx && !params->bbox.miny - && !params->bbox.maxx && !params->bbox.maxy) { - msSetError(MS_WCSERR, "One of BBOX or TIME is required", "msWCSGetCoverage()"); - return msWCSException(map, "MissingParameterValue", "bbox/time", params->version); - } - - if( params->coverages == NULL || params->coverages[0] == NULL ) { - msSetError( MS_WCSERR, - "Required parameter COVERAGE was not supplied.", - "msWCSGetCoverage()"); - return msWCSException(map, "MissingParameterValue", "coverage", params->version); - } - - /* For WCS 1.1, we need to normalize the axis order of the BBOX and - resolution values some coordinate systems (eg. EPSG geographic) */ - if( strncasecmp(params->version,"1.0",3) != 0 - && params->crs != NULL - && strncasecmp(params->crs,"urn:",4) == 0 ) { - projectionObj proj; - - msInitProjection( &proj ); - msProjectionInheritContextFrom(&proj, &(map->projection)); - if( msLoadProjectionString( &proj, (char *) params->crs ) == 0 ) { - msAxisNormalizePoints( &proj, 1, - &(params->bbox.minx), - &(params->bbox.miny) ); - msAxisNormalizePoints( &proj, 1, - &(params->bbox.maxx), - &(params->bbox.maxy) ); - msAxisNormalizePoints( &proj, 1, - &(params->resx), - &(params->resy) ); - msAxisNormalizePoints( &proj, 1, - &(params->originx), - &(params->originy) ); - } else - msResetErrorList(); - msFreeProjection( &proj ); - } - - /* find the layer we are working with */ - lp = NULL; - for(i=0; inumlayers; i++) { - coverageName = msOWSGetEncodeMetadata(&(GET_LAYER(map, i)->metadata), "CO", "name", GET_LAYER(map, i)->name); - if( coverageName != NULL && EQUAL(coverageName, params->coverages[0]) && - (msIntegerInArray(GET_LAYER(map, i)->index, ows_request->enabled_layers, ows_request->numlayers)) ) { - lp = GET_LAYER(map, i); - free( coverageName ); - break; - } - free( coverageName ); - } - - if(lp == NULL) { - msSetError( MS_WCSERR, "COVERAGE=%s not found, not in supported layer list. A layer might be disabled for \ -this request. Check wcs/ows_enable_request settings.", "msWCSGetCoverage()", params->coverages[0] ); - return msWCSException(map, "InvalidParameterValue", "coverage", params->version); - } - - /* make sure the layer is on */ - lp->status = MS_ON; - - /* If the layer has no projection set, set it to the map's projection (#4079) */ - if(lp->projection.numargs <=0) { - char *map_original_srs = msGetProjectionString(&(map->projection)); - if (msLoadProjectionString(&(lp->projection), map_original_srs) != 0) { - msSetError( MS_WCSERR, "Error when setting map projection to a layer with no projection", "msWCSGetCoverage()" ); - free(map_original_srs); - return msWCSException(map, NULL, NULL, params->version); - } - free(map_original_srs); - } - - /* we need the coverage metadata, since things like numbands may not be available otherwise */ - status = msWCSGetCoverageMetadata(lp, &cm); - if(status != MS_SUCCESS) return MS_FAILURE; - - /* fill in bands rangeset info, if required. */ - msWCSSetDefaultBandsRangeSetInfo(params, &cm, lp); - - /* handle the response CRS, that is, set the map object projection */ - if(params->response_crs || params->crs ) { - int iUnits; - const char *crs_to_use = params->response_crs; - - if( crs_to_use == NULL ) - crs_to_use = params->crs; - - if (strncasecmp(crs_to_use, "EPSG:", 5) == 0 || strncasecmp(crs_to_use,"urn:ogc:def:crs:",16) == 0 ) { - if (msLoadProjectionString(&(map->projection), (char *) crs_to_use) != 0) - return msWCSException( map, NULL, NULL,params->version); - } else if( strcasecmp(crs_to_use,"imageCRS") == 0 ) { - /* use layer native CRS, and rework bounding box accordingly */ - if( msWCSGetCoverage_ImageCRSSetup( map, request, params, &cm, lp ) != MS_SUCCESS ) { - msWCSFreeCoverageMetadata(&cm); - return MS_FAILURE; - } - } else { /* should we support WMS style AUTO: projections? (not for now) */ - msSetError(MS_WCSERR, "Unsupported SRS namespace (only EPSG currently supported).", "msWCSGetCoverage()"); - return msWCSException(map, "InvalidParameterValue", "srs", params->version); - } - - iUnits = GetMapserverUnitUsingProj(&(map->projection)); - if (iUnits != -1) - map->units = static_cast(iUnits); - } - - /* did we get a TIME value (support only a single value for now) */ - if(params->time) { - int tli; - layerObj *tlp=NULL; - - /* need to handle NOW case */ - - /* check format of TIME parameter */ - if(strchr(params->time, ',')) { - msWCSFreeCoverageMetadata(&cm); - msSetError( MS_WCSERR, "Temporal lists are not supported, only individual values.", "msWCSGetCoverage()" ); - return msWCSException(map, "InvalidParameterValue", "time", params->version); - } - if(strchr(params->time, '/')) { - msWCSFreeCoverageMetadata(&cm); - msSetError( MS_WCSERR, "Temporal ranges are not supported, only individual values.", "msWCSGetCoverage()" ); - return msWCSException(map, "InvalidParameterValue", "time", params->version); - } - - /* TODO: will need to expand this check if a time period is supported */ - value = msOWSLookupMetadata(&(lp->metadata), "CO", "timeposition"); - if(!value) { - msWCSFreeCoverageMetadata(&cm); - msSetError( MS_WCSERR, "The coverage does not support temporal subsetting.", "msWCSGetCoverage()" ); - return msWCSException(map, "InvalidParameterValue", "time", params->version ); - } - - /* check if timestamp is covered by the wcs_timeposition definition */ - if (msValidateTimeValue(params->time, value) == MS_FALSE) { - msWCSFreeCoverageMetadata(&cm); - msSetError( MS_WCSERR, "The coverage does not have a time position of %s.", "msWCSGetCoverage()", params->time ); - return msWCSException(map, "InvalidParameterValue", "time", params->version); - } - - /* make sure layer is tiled appropriately */ - if(!lp->tileindex) { - msWCSFreeCoverageMetadata(&cm); - msSetError( MS_WCSERR, "Underlying layer is not tiled, unable to do temporal subsetting.", "msWCSGetCoverage()" ); - return msWCSException(map, NULL, NULL, params->version); - } - tli = msGetLayerIndex(map, lp->tileindex); - if(tli == -1) { - msWCSFreeCoverageMetadata(&cm); - msSetError( MS_WCSERR, "Underlying layer does not use appropriate tiling mechanism.", "msWCSGetCoverage()" ); - return msWCSException(map, NULL, NULL, params->version); - } - - tlp = (GET_LAYER(map, tli)); - - /* make sure there is enough information to filter */ - value = msOWSLookupMetadata(&(lp->metadata), "CO", "timeitem"); - if(!tlp->filteritem && !value) { - msWCSFreeCoverageMetadata(&cm); - msSetError( MS_WCSERR, "Not enough information available to filter.", "msWCSGetCoverage()" ); - return msWCSException(map, NULL, NULL, params->version); - } - - /* override filteritem if specified in metadata */ - if(value) { - if(tlp->filteritem) free(tlp->filteritem); - tlp->filteritem = msStrdup(value); - } - - /* finally set the filter */ - msFreeExpression(&tlp->filter); - msLayerSetTimeFilter(tlp, params->time, value); - } - - if( strncasecmp(params->version,"1.0",3) == 0 ) - status = msWCSGetCoverageBands10( map, request, params, lp, &bandlist ); - else - status = msWCSGetCoverageBands11( map, request, params, lp, &bandlist ); - if( status != MS_SUCCESS ) { - msWCSFreeCoverageMetadata(&cm); - return status; - } - - /* did we get BBOX values? if not use the exent stored in the coverageMetadataObj */ - if( fabs((params->bbox.maxx - params->bbox.minx)) < 0.000000000001 || fabs(params->bbox.maxy - params->bbox.miny) < 0.000000000001 ) { - params->bbox = cm.extent; - - /* WCS 1.1 boundbox is center of pixel oriented. */ - if( strncasecmp(params->version,"1.1",3) == 0 ) { - params->bbox.minx += cm.geotransform[1]/2 + cm.geotransform[2]/2; - params->bbox.maxx -= cm.geotransform[1]/2 + cm.geotransform[2]/2; - params->bbox.maxy += cm.geotransform[4]/2 + cm.geotransform[5]/2; - params->bbox.miny -= cm.geotransform[4]/2 + cm.geotransform[5]/2; - } - } - - /* WCS 1.1+ GridOrigin is effectively resetting the minx/maxy - BOUNDINGBOX values, so apply that here */ - if( params->originx != 0.0 || params->originy != 0.0 ) { - assert( strncasecmp(params->version,"1.0",3) != 0 ); /* should always be 1.0 in this logic. */ - params->bbox.minx = params->originx; - params->bbox.maxy = params->originy; - } - - /* if necessary, project the BBOX to the map->projection */ - if(params->response_crs && params->crs) { - projectionObj tmp_proj; - - msInitProjection(&tmp_proj); - msProjectionInheritContextFrom(&tmp_proj, &(map->projection)); - if (msLoadProjectionString(&tmp_proj, (char *) params->crs) != 0) { - msWCSFreeCoverageMetadata(&cm); - return msWCSException( map, NULL, NULL, params->version); - } - msProjectRect(&tmp_proj, &map->projection, &(params->bbox)); - msFreeProjection(&tmp_proj); - } - - /* in WCS 1.1 the default is full resolution */ - if( strncasecmp(params->version,"1.1",3) == 0 && params->resx == 0.0 && params->resy == 0.0 ) { - params->resx = cm.geotransform[1]; - params->resy = fabs(cm.geotransform[5]); - } - - /* compute width/height from BBOX and cellsize. */ - if( (params->resx == 0.0 || params->resy == 0.0) && params->width != 0 && params->height != 0 ) { - assert( strncasecmp(params->version,"1.0",3) == 0 ); /* should always be 1.0 in this logic. */ - params->resx = (params->bbox.maxx -params->bbox.minx) / params->width; - params->resy = (params->bbox.maxy -params->bbox.miny) / params->height; - } - - /* compute cellsize/res from bbox and raster size. */ - if( (params->width == 0 || params->height == 0) && params->resx != 0 && params->resy != 0 ) { - - /* WCS 1.0 boundbox is edge of pixel oriented. */ - if( strncasecmp(params->version,"1.0",3) == 0 ) { - params->width = (int) ((params->bbox.maxx - params->bbox.minx) / params->resx + 0.5); - params->height = (int) ((params->bbox.maxy - params->bbox.miny) / params->resy + 0.5); - } else { - params->width = (int) ((params->bbox.maxx - params->bbox.minx) / params->resx + 1.000001); - params->height = (int) ((params->bbox.maxy - params->bbox.miny) / params->resy + 1.000001); - - /* recompute bounding box so we get exactly the origin and - resolution requested. */ - params->bbox.maxx = params->bbox.minx + (params->width-1) * params->resx; - params->bbox.miny = params->bbox.maxy - (params->height-1) * params->resy; - } - } - - /* are we still underspecified? */ - if( (params->width == 0 || params->height == 0) && (params->resx == 0.0 || params->resy == 0.0 )) { - msWCSFreeCoverageMetadata(&cm); - msSetError( MS_WCSERR, "A non-zero RESX/RESY or WIDTH/HEIGHT is required but neither was provided.", "msWCSGetCoverage()" ); - return msWCSException(map, "MissingParameterValue", "width/height/resx/resy", params->version); - } - - map->cellsize = params->resx; - - /* Do we need to force special handling? */ - if( fabs(params->resx/params->resy - 1.0) > 0.001 ) { - map->gt.need_geotransform = MS_TRUE; - if( map->debug ) msDebug( "RESX and RESY don't match. Using geotransform/resample.\n"); - } - - /* Do we have a specified interpolation method */ - if( params->interpolation != NULL ) { - if( strncasecmp(params->interpolation,"NEAREST",7) == 0 ) - msLayerSetProcessingKey(lp, "RESAMPLE", "NEAREST"); - else if( strcasecmp(params->interpolation,"BILINEAR") == 0 ) - msLayerSetProcessingKey(lp, "RESAMPLE", "BILINEAR"); - else if( strcasecmp(params->interpolation,"AVERAGE") == 0 ) - msLayerSetProcessingKey(lp, "RESAMPLE", "AVERAGE"); - else { - msWCSFreeCoverageMetadata(&cm); - msSetError( MS_WCSERR, "INTERPOLATION=%s specifies an unsupported interpolation method.", "msWCSGetCoverage()", params->interpolation ); - return msWCSException(map, "InvalidParameterValue", "interpolation", params->version); - } - } - - /* apply region and size to map object. */ - map->width = params->width; - map->height = params->height; - - /* Are we exceeding the MAXSIZE limit on result size? */ - if(map->width > map->maxsize || map->height > map->maxsize ) { - msWCSFreeCoverageMetadata(&cm); - msSetError(MS_WCSERR, "Raster size out of range, width and height of resulting coverage must be no more than MAXSIZE=%d.", "msWCSGetCoverage()", map->maxsize); - - return msWCSException(map, "InvalidParameterValue", - "width/height", params->version); - } - - /* adjust OWS BBOX to MapServer's pixel model */ - if( strncasecmp(params->version,"1.0",3) == 0 ) { - params->bbox.minx += params->resx*0.5; - params->bbox.miny += params->resy*0.5; - params->bbox.maxx -= params->resx*0.5; - params->bbox.maxy -= params->resy*0.5; - } - - map->extent = params->bbox; - - map->cellsize = params->resx; /* pick one, MapServer only supports square cells (what about msAdjustExtent here!) */ - - msMapComputeGeotransform(map); - - /* Do we need to fake out stuff for rotated support? */ - if( map->gt.need_geotransform ) - msMapSetFakedExtent( map ); - - map->projection.gt = map->gt; - - /* check for overlap */ - - /* get extent of bbox passed, and reproject */ - reqextent.minx = map->extent.minx; - reqextent.miny = map->extent.miny; - reqextent.maxx = map->extent.maxx; - reqextent.maxy = map->extent.maxy; - - /* reproject incoming bbox */ - msProjectRect(&map->projection, &lp->projection, &(reqextent)); - - /* get extent of layer */ - covextent.minx = cm.extent.minx; - covextent.miny = cm.extent.miny; - covextent.maxx = cm.extent.maxx; - covextent.maxy = cm.extent.maxy; - - if(msRectOverlap(&reqextent, &covextent) == MS_FALSE) { - msWCSFreeCoverageMetadata(&cm); - msSetError(MS_WCSERR, "Requested BBOX (%.15g,%.15g,%.15g,%.15g) is outside requested coverage BBOX (%.15g,%.15g,%.15g,%.15g)", - "msWCSGetCoverage()", - reqextent.minx, reqextent.miny, reqextent.maxx, reqextent.maxy, - covextent.minx, covextent.miny, covextent.maxx, covextent.maxy); - return msWCSException(map, "NoApplicableCode", "bbox", params->version); - } - - /* check and make sure there is a format, and that it's valid (TODO: make sure in the layer metadata) */ - if(!params->format) { - msWCSFreeCoverageMetadata(&cm); - msSetError( MS_WCSERR, "Missing required FORMAT parameter.", "msWCSGetCoverage()" ); - return msWCSException(map, "MissingParameterValue", "format", params->version); - } - msApplyDefaultOutputFormats(map); - if(msGetOutputFormatIndex(map,params->format) == -1) { - msWCSFreeCoverageMetadata(&cm); - msSetError( MS_WCSERR, "Unrecognized value for the FORMAT parameter.", "msWCSGetCoverage()" ); - return msWCSException(map, "InvalidParameterValue", "format", - params->version ); - } - - /* create a temporary outputformat (we likely will need to tweak parts) */ - format = msCloneOutputFormat(msSelectOutputFormat(map,params->format)); - msApplyOutputFormat(&(map->outputformat), format, MS_NOOVERRIDE, MS_NOOVERRIDE, MS_NOOVERRIDE); - - if(!bandlist) { /* build a bandlist (default is ALL bands) */ - bufferSize = cm.bandcount*30+30; - bandlist = (char *) msSmallMalloc(bufferSize); - strcpy(bandlist, "1"); - for(i = 1; i < cm.bandcount; i++) - snprintf(bandlist+strlen(bandlist), bufferSize-strlen(bandlist), ",%d", i+1); - } - - /* apply nullvalue to the output format object if we have it */ - if((value = msOWSLookupMetadata(&(lp->metadata), "CO", "rangeset_nullvalue")) != NULL) { - msSetOutputFormatOption( map->outputformat, "NULLVALUE", value ); - } - - msLayerSetProcessingKey(lp, "BANDS", bandlist); - snprintf(numbands, sizeof(numbands), "%d", msCountChars(bandlist, ',')+1); - msSetOutputFormatOption(map->outputformat, "BAND_COUNT", numbands); - - msWCSApplyLayerCreationOptions(lp, map->outputformat, bandlist); - - if( lp->tileindex == NULL && lp->data != NULL && - strlen(lp->data) > 0 && - lp->connectiontype != MS_KERNELDENSITY ) - { - if( msDrawRasterLayerLowCheckIfMustDraw(map, lp) ) - { - char* decrypted_path = NULL; - char szPath[MS_MAXPATHLEN]; - hDS = (GDALDatasetH)msDrawRasterLayerLowOpenDataset( - map, lp, lp->data, szPath, &decrypted_path); - msFree(decrypted_path); - if( hDS ) - msWCSApplyDatasetMetadataAsCreationOptions(lp, map->outputformat, bandlist, hDS); - } - else - { - doDrawRasterLayerDraw = MS_FALSE; - } - } - - free( bandlist ); - - if(lp->mask) { - int maskLayerIdx = msGetLayerIndex(map,lp->mask); - layerObj *maskLayer; - outputFormatObj *altFormat; - if(maskLayerIdx == -1) { - msWCSFreeCoverageMetadata(&cm); - msSetError(MS_MISCERR, "Layer (%s) references unknown mask layer (%s)", "msDrawLayer()", - lp->name,lp->mask); - msDrawRasterLayerLowCloseDataset(lp, hDS); - return msWCSException(map, NULL, NULL, params->version ); - } - maskLayer = GET_LAYER(map, maskLayerIdx); - if(!maskLayer->maskimage) { - int i,retcode; - int origstatus, origlabelcache; - char *origImageType = msStrdup(map->imagetype); - altFormat = msSelectOutputFormat(map, "png24"); - msInitializeRendererVTable(altFormat); - /* TODO: check the png24 format hasn't been tampered with, i.e. it's agg */ - maskLayer->maskimage= msImageCreate(map->width, map->height, altFormat, - map->web.imagepath, map->web.imageurl, map->resolution, map->defresolution, NULL); - if (!maskLayer->maskimage) { - msWCSFreeCoverageMetadata(&cm); - msSetError(MS_MISCERR, "Unable to initialize mask image.", "msDrawLayer()"); - msFree(origImageType); - msDrawRasterLayerLowCloseDataset(lp, hDS); - return msWCSException(map, NULL, NULL, params->version ); - } - - /* - * force the masked layer to status on, and turn off the labelcache so that - * eventual labels are added to the temporary image instead of being added - * to the labelcache - */ - origstatus = maskLayer->status; - origlabelcache = maskLayer->labelcache; - maskLayer->status = MS_ON; - maskLayer->labelcache = MS_OFF; - - /* draw the mask layer in the temporary image */ - retcode = msDrawLayer(map, maskLayer, maskLayer->maskimage); - maskLayer->status = origstatus; - maskLayer->labelcache = origlabelcache; - if(retcode != MS_SUCCESS) { - msWCSFreeCoverageMetadata(&cm); - /* set the imagetype from the original outputformat back (it was removed by msSelectOutputFormat() */ - msFree(map->imagetype); - map->imagetype = origImageType; - msDrawRasterLayerLowCloseDataset(lp, hDS); - return msWCSException(map, NULL, NULL, params->version ); - } - /* - * hack to work around bug #3834: if we have use an alternate renderer, the symbolset may contain - * symbols that reference it. We want to remove those references before the altFormat is destroyed - * to avoid a segfault and/or a leak, and so the the main renderer doesn't pick the cache up thinking - * it's for him. - */ - for(i=0; isymbolset.numsymbols; i++) { - if (map->symbolset.symbol[i]!=NULL) { - symbolObj *s = map->symbolset.symbol[i]; - if(s->renderer == MS_IMAGE_RENDERER(maskLayer->maskimage)) { - MS_IMAGE_RENDERER(maskLayer->maskimage)->freeSymbol(s); - s->renderer = NULL; - } - } - } - /* set the imagetype from the original outputformat back (it was removed by msSelectOutputFormat() */ - msFree(map->imagetype); - map->imagetype = origImageType; - - } - } - - /* create the image object */ - if(!map->outputformat) { - msWCSFreeCoverageMetadata(&cm); - msSetError(MS_WCSERR, "The map outputformat is missing!", "msWCSGetCoverage()"); - msDrawRasterLayerLowCloseDataset(lp, hDS); - return msWCSException(map, NULL, NULL, params->version ); - } else if( MS_RENDERER_RAWDATA(map->outputformat) || MS_RENDERER_PLUGIN(map->outputformat) ) { - image = msImageCreate(map->width, map->height, map->outputformat, map->web.imagepath, map->web.imageurl, map->resolution, map->defresolution, NULL); - } else { - msWCSFreeCoverageMetadata(&cm); - msSetError(MS_WCSERR, "Map outputformat not supported for WCS!", "msWCSGetCoverage()"); - msDrawRasterLayerLowCloseDataset(lp, hDS); - return msWCSException(map, NULL, NULL, params->version ); - } - - if( image == NULL ) { - msWCSFreeCoverageMetadata(&cm); - msDrawRasterLayerLowCloseDataset(lp, hDS); - return msWCSException(map, NULL, NULL, params->version ); - } - if( MS_RENDERER_RAWDATA(map->outputformat) ) { - if( doDrawRasterLayerDraw ) { - status = msDrawRasterLayerLowWithDataset( map, lp, image, NULL, hDS ); - } else { - status = MS_SUCCESS; - } - } else { - status = MS_IMAGE_RENDERER(image)->getRasterBufferHandle(image,&rb); - if(UNLIKELY(status == MS_FAILURE)) { - msWCSFreeCoverageMetadata(&cm); - msDrawRasterLayerLowCloseDataset(lp, hDS); - return MS_FAILURE; - } - - /* Actually produce the "grid". */ - if( doDrawRasterLayerDraw ) { - status = msDrawRasterLayerLowWithDataset( map, lp, image, &rb, hDS ); - } else { - status = MS_SUCCESS; - } - } - msDrawRasterLayerLowCloseDataset(lp, hDS); - - if( status != MS_SUCCESS ) { - msWCSFreeCoverageMetadata(&cm); - msFreeImage(image); - return msWCSException(map, NULL, NULL, params->version ); - } - - - if( strncmp(params->version, "1.1",3) == 0 ) { - msWCSReturnCoverage11( params, map, image ); - } else { /* WCS 1.0.0 - just return the binary data with a content type */ - const char *fo_filename; - - /* Do we have a predefined filename? */ - fo_filename = msGetOutputFormatOption( format, "FILENAME", NULL ); - if( fo_filename ) - msIO_setHeader("Content-Disposition","attachment; filename=%s", - fo_filename ); - - /* Emit back to client. */ - msOutputFormatResolveFromImage( map, image ); - msIO_setHeader("Content-Type","%s",MS_IMAGE_MIME_TYPE(map->outputformat)); - msIO_sendHeaders(); - status = msSaveImage(map, image, NULL); - - if( status != MS_SUCCESS ) { - /* unfortunately, the image content type will have already been sent - but that is hard for us to avoid. The main error that could happen - here is a misconfigured tmp directory or running out of space. */ - msWCSFreeCoverageMetadata(&cm); - return msWCSException(map, NULL, NULL, params->version ); - } - } - - /* Cleanup */ - msFreeImage(image); - msApplyOutputFormat(&(map->outputformat), NULL, MS_NOOVERRIDE, MS_NOOVERRIDE, MS_NOOVERRIDE); - /* msFreeOutputFormat(format); */ - - msWCSFreeCoverageMetadata(&cm); - return status; -} -#endif /* def USE_WCS_SVR */ - -/************************************************************************/ -/* msWCSDispatch() */ -/* */ -/* Entry point for WCS requests */ -/************************************************************************/ - -int msWCSDispatch(mapObj *map, cgiRequestObj *request, owsRequestObj *ows_request) -{ -#if defined(USE_WCS_SVR) - wcs20ParamsObj *params20 = NULL; - int status, retVal, operation; - - /* If SERVICE is not set or not WCS exit gracefully. */ - if (ows_request->service == NULL - || !EQUAL(ows_request->service, "WCS")) { - return MS_DONE; - } - - /* If no REQUEST is set, exit with an error */ - if (ows_request->request == NULL) { - /* The request has to be set. */ - msSetError(MS_WCSERR, "Missing REQUEST parameter", - "msWCSDispatch()"); - return msWCSException(map, "MissingParameterValue", "request", - ows_request->version ); - } - - if (EQUAL(ows_request->request, "GetCapabilities")) { - operation = MS_WCS_GET_CAPABILITIES; - } else if (EQUAL(ows_request->request, "DescribeCoverage")) { - operation = MS_WCS_DESCRIBE_COVERAGE; - } else if (EQUAL(ows_request->request, "GetCoverage")) { - operation = MS_WCS_GET_COVERAGE; - } else { - msSetError(MS_WCSERR, "Invalid REQUEST parameter \"%s\"", - "msWCSDispatch()", ows_request->request); - return msWCSException(map, "InvalidParameterValue", "request", - ows_request->version); - } - - /* Check the number of enabled layers for the REQUEST */ - msOWSRequestLayersEnabled(map, "C", ows_request->request, ows_request); - if (ows_request->numlayers == 0) { - int caps_globally_enabled = MS_FALSE, disabled = MS_FALSE; - const char *enable_request; - if(operation == MS_WCS_GET_CAPABILITIES) { - enable_request = msOWSLookupMetadata(&map->web.metadata, "OC", "enable_request"); - caps_globally_enabled = msOWSParseRequestMetadata(enable_request, "GetCapabilities", &disabled); - } - - if(caps_globally_enabled == MS_FALSE) { - msSetError(MS_WCSERR, "WCS request not enabled. Check " - "wcs/ows_enable_request settings.", - "msWCSDispatch()"); - return msWCSException(map, "InvalidParameterValue", "request", - ows_request->version ); - } - } - - /* Check the VERSION parameter */ - if (ows_request->version == NULL) { - /* If the VERSION parameter is not set, it is either */ - /* an error (Describe and GetCoverage), or it has to */ - /* be determined (GetCapabilities). To determine the */ - /* version, the request has to be fully parsed to */ - /* obtain the ACCEPTVERSIONS parameter. If this is */ - /* present also, set version to "2.0.1". */ - - if (operation == MS_WCS_GET_CAPABILITIES) { - /* Parse it as if it was a WCS 2.0 request */ - wcs20ParamsObjPtr params_tmp = msWCSCreateParamsObj20(); - status = msWCSParseRequest20(map, request, ows_request, params_tmp); - if (status == MS_FAILURE) { - msWCSFreeParamsObj20(params_tmp); - return msWCSException(map, "InvalidParameterValue", - "request", "2.0.1"); - } - - /* VERSION negotiation */ - if (params_tmp->accept_versions != NULL) { - /* choose highest acceptable */ - int i, highest_version = 0; - char version_string[OWS_VERSION_MAXLEN]; - for(i = 0; params_tmp->accept_versions[i] != NULL; ++i) { - int version = msOWSParseVersionString(params_tmp->accept_versions[i]); - if (version == OWS_VERSION_BADFORMAT) { - msWCSFreeParamsObj20(params_tmp); - return msWCSException(map, "InvalidParameterValue", - "version", NULL ); - } - if(version > highest_version) { - highest_version = version; - } - } - msOWSGetVersionString(highest_version, version_string); - params_tmp->version = msStrdup(version_string); - ows_request->version = msStrdup(version_string); - } else { - /* set to highest acceptable */ - params_tmp->version = msStrdup("2.0.1"); - ows_request->version = msStrdup("2.0.1"); - } - - /* check if we can keep the params object */ - if (EQUAL(params_tmp->version, "2.0.1")) { - params20 = params_tmp; - } else { - msWCSFreeParamsObj20(params_tmp); - } - } else { /* operation != GetCapabilities */ - /* VERSION is mandatory in other requests */ - msSetError(MS_WCSERR, "VERSION parameter not set.", - "msWCSDispatch()"); - return msWCSException(map, "InvalidParameterValue", "version", - NULL ); - } - } else { - /* Parse the VERSION parameter */ - int requested_version = msOWSParseVersionString(ows_request->version); - if (requested_version == OWS_VERSION_BADFORMAT) { - /* Return an error if the VERSION is */ - /* in an unsupported format. */ - return msWCSException(map, "InvalidParameterValue", - "version", NULL ); - } - - if (operation == MS_WCS_GET_CAPABILITIES) { - /* In case of GetCapabilities, make */ - char version_string[OWS_VERSION_MAXLEN]; - int version, supported_versions[] = - {OWS_2_0_1, OWS_2_0_0, OWS_1_1_2, OWS_1_1_1, OWS_1_1_0, OWS_1_0_0}; - version = msOWSNegotiateVersion(requested_version, - supported_versions, - sizeof(supported_versions)/sizeof(int)); - msOWSGetVersionString(version, version_string); - msFree(ows_request->version); - ows_request->version = msStrdup(version_string); - } - } - - /* VERSION specific request handler */ - if (strcmp(ows_request->version, "1.0.0") == 0 - || strcmp(ows_request->version, "1.1.0") == 0 - || strcmp(ows_request->version, "1.1.1") == 0 - || strcmp(ows_request->version, "1.1.2") == 0) { - auto paramsTmp = msWCSCreateParams(); - status = msWCSParseRequest(request, paramsTmp, map); - if (status == MS_FAILURE) { - msWCSFreeParams(paramsTmp); - free(paramsTmp); - return msWCSException(map, "InvalidParameterValue", - "request", "2.0"); - } - - retVal = MS_FAILURE; - if (operation == MS_WCS_GET_CAPABILITIES) { - retVal = msWCSGetCapabilities(map, paramsTmp, request, ows_request); - } else if (operation == MS_WCS_DESCRIBE_COVERAGE) { - retVal = msWCSDescribeCoverage(map, paramsTmp, ows_request, request); - } else if (operation == MS_WCS_GET_COVERAGE) { - retVal = msWCSGetCoverage(map, request, paramsTmp, ows_request); - } - msWCSFreeParams(paramsTmp); - free(paramsTmp); - return retVal; - } else if (strcmp(ows_request->version, "2.0.0") == 0 - || strcmp(ows_request->version, "2.0.1") == 0) { -#if defined(USE_LIBXML2) - int i; - - if (params20 == NULL) { - params20 = msWCSCreateParamsObj20(); - status = msWCSParseRequest20(map, request, ows_request, params20); - if (status == MS_FAILURE) { - msWCSFreeParamsObj20(params20); - return msWCSException(map, "InvalidParameterValue", - "request", "2.0.1"); - } - else if (status == MS_DONE) { - /* MS_DONE means, that the exception has already been written to the IO - buffer. - */ - msWCSFreeParamsObj20(params20); - return MS_FAILURE; - } - } - - /* check if all layer names are valid NCNames */ - for(i = 0; i < map->numlayers; ++i) { - if(!msWCSIsLayerSupported(map->layers[i])) - continue; - - /* Check if each layers name is a valid NCName. */ - if (msEvalRegex("^[a-zA-z_][a-zA-Z0-9_.-]*$" , map->layers[i]->name) == MS_FALSE) { - msSetError(MS_WCSERR, "Layer name '%s' is not a valid NCName.", - "msWCSDispatch()", map->layers[i]->name); - msWCSFreeParamsObj20(params20); - return msWCSException(map, "mapserv", "Internal", "2.0.1"); - } - } - - /* Call operation specific functions */ - if (operation == MS_WCS_GET_CAPABILITIES) { - retVal = msWCSGetCapabilities20(map, request, params20, ows_request); - } else if (operation == MS_WCS_DESCRIBE_COVERAGE) { - retVal = msWCSDescribeCoverage20(map, params20, ows_request); - } else if (operation == MS_WCS_GET_COVERAGE) { - retVal = msWCSGetCoverage20(map, request, params20, ows_request); - } else { - msSetError(MS_WCSERR, "Invalid request '%s'.", - "msWCSDispatch20()", ows_request->request); - retVal = msWCSException20(map, "InvalidParameterValue", - "request", "2.0.1"); - } - /* clean up */ - msWCSFreeParamsObj20(params20); - return retVal; -#else /* def USE_LIBXML2 */ - msSetError(MS_WCSERR, "WCS 2.0 needs mapserver to be compiled with libxml2.", - "msWCSDispatch()"); - return msWCSException(map, "mapserv", "NoApplicableCode", "2.0.1"); -#endif /* def USE_LIBXML2 */ - } else { /* unsupported version */ - msSetError(MS_WCSERR, "WCS Server does not support VERSION %s.", - "msWCSDispatch()", ows_request->version); - return msWCSException(map, "InvalidParameterValue", - "version", ows_request->version); - } - -#else - msSetError(MS_WCSERR, "WCS server support is not available.", "msWCSDispatch()"); - return MS_FAILURE; -#endif -} - -/************************************************************************/ -/* msWCSGetCoverageMetadata() */ -/************************************************************************/ - -#ifdef USE_WCS_SVR - -void msWCSFreeCoverageMetadata(coverageMetadataObj *cm) { - msFree(cm->srs_epsg); -} - -int msWCSGetCoverageMetadata( layerObj *layer, coverageMetadataObj *cm ) -{ - char *srs_urn = NULL; - int i = 0; - if ( msCheckParentPointer(layer->map,"map")==MS_FAILURE ) - return MS_FAILURE; - - /* -------------------------------------------------------------------- */ - /* Get the SRS in WCS 1.0 format (eg. EPSG:n) */ - /* -------------------------------------------------------------------- */ - msOWSGetEPSGProj(&(layer->projection), &(layer->metadata), "CO", MS_TRUE, &(cm->srs_epsg)); - if(!cm->srs_epsg) { - msOWSGetEPSGProj(&(layer->map->projection), &(layer->map->web.metadata), "CO", MS_TRUE, &(cm->srs_epsg)); - if(!cm->srs_epsg) { - msSetError(MS_WCSERR, "Unable to determine the SRS for this layer, no projection defined and no metadata available.", "msWCSGetCoverageMetadata()"); - return MS_FAILURE; - } - } - - /* -------------------------------------------------------------------- */ - /* Get the SRS in urn format. */ - /* -------------------------------------------------------------------- */ - if((srs_urn = msOWSGetProjURN(&(layer->projection), &(layer->metadata), - "CO", MS_TRUE)) == NULL) { - srs_urn = msOWSGetProjURN(&(layer->map->projection), - &(layer->map->web.metadata), - "CO", MS_TRUE); - } - - if( srs_urn != NULL ) { - if( strlen(srs_urn) > sizeof(cm->srs_urn) - 1 ) { - msSetError(MS_WCSERR, "SRS URN too long!", - "msWCSGetCoverageMetadata()"); - return MS_FAILURE; - } - - strcpy( cm->srs_urn, srs_urn ); - msFree( srs_urn ); - } else - cm->srs_urn[0] = '\0'; - - /* -------------------------------------------------------------------- */ - /* If we have "virtual dataset" metadata on the layer, then use */ - /* that in preference to inspecting the file(s). */ - /* We require extent and either size or resolution. */ - /* -------------------------------------------------------------------- */ - if( msOWSLookupMetadata(&(layer->metadata), "CO", "extent") != NULL - && (msOWSLookupMetadata(&(layer->metadata), "CO", "resolution") != NULL - || msOWSLookupMetadata(&(layer->metadata), "CO", "size") != NULL) ) { - const char *value; - - /* get extent */ - cm->extent.minx = 0.0; - cm->extent.maxx = 0.0; - cm->extent.miny = 0.0; - cm->extent.maxy = 0.0; - if( msOWSGetLayerExtent( layer->map, layer, "CO", &cm->extent ) == MS_FAILURE ) - return MS_FAILURE; - - /* get resolution */ - cm->xresolution = 0.0; - cm->yresolution = 0.0; - if( (value = msOWSLookupMetadata(&(layer->metadata), "CO", "resolution")) != NULL ) { - char **tokens; - int n; - - tokens = msStringSplit(value, ' ', &n); - if( tokens == NULL || n != 2 ) { - msSetError( MS_WCSERR, "Wrong number of arguments for wcs|ows_resolution metadata.", "msWCSGetCoverageMetadata()"); - msFreeCharArray( tokens, n ); - return MS_FAILURE; - } - cm->xresolution = atof(tokens[0]); - cm->yresolution = atof(tokens[1]); - msFreeCharArray( tokens, n ); - } - - /* get Size (in pixels and lines) */ - cm->xsize = 0; - cm->ysize = 0; - if( (value=msOWSLookupMetadata(&(layer->metadata), "CO", "size")) != NULL ) { - char **tokens; - int n; - - tokens = msStringSplit(value, ' ', &n); - if( tokens == NULL || n != 2 ) { - msSetError( MS_WCSERR, "Wrong number of arguments for wcs|ows_size metadata.", "msWCSGetCoverageDomain()"); - msFreeCharArray( tokens, n ); - return MS_FAILURE; - } - cm->xsize = atoi(tokens[0]); - cm->ysize = atoi(tokens[1]); - msFreeCharArray( tokens, n ); - } - - /* try to compute raster size */ - if( cm->xsize == 0 && cm->ysize == 0 && cm->xresolution != 0.0 && cm->yresolution != 0.0 && cm->extent.minx != cm->extent.maxx && cm->extent.miny != cm->extent.maxy ) { - cm->xsize = (int) ((cm->extent.maxx - cm->extent.minx) / cm->xresolution + 0.5); - cm->ysize = (int) fabs((cm->extent.maxy - cm->extent.miny) / cm->yresolution + 0.5); - } - - /* try to compute raster resolution */ - if( (cm->xresolution == 0.0 || cm->yresolution == 0.0) && cm->xsize != 0 && cm->ysize != 0 ) { - cm->xresolution = (cm->extent.maxx - cm->extent.minx) / cm->xsize; - cm->yresolution = (cm->extent.maxy - cm->extent.miny) / cm->ysize; - } - - /* do we have information to do anything */ - if( cm->xresolution == 0.0 || cm->yresolution == 0.0 || cm->xsize == 0 || cm->ysize == 0 ) { - msSetError( MS_WCSERR, "Failed to collect extent and resolution for WCS coverage from metadata for layer '%s'. Need value wcs|ows_resolution or wcs|ows_size values.", "msWCSGetCoverageMetadata()", layer->name ); - return MS_FAILURE; - } - - /* compute geotransform */ - cm->geotransform[0] = cm->extent.minx; - cm->geotransform[1] = cm->xresolution; - cm->geotransform[2] = 0.0; - cm->geotransform[3] = cm->extent.maxy; - cm->geotransform[4] = 0.0; - cm->geotransform[5] = -fabs(cm->yresolution); - - /* get bands count, or assume 1 if not found */ - cm->bandcount = 1; - if( (value=msOWSLookupMetadata(&(layer->metadata), "CO", "bandcount")) != NULL) { - cm->bandcount = atoi(value); - } - - /* get bands type, or assume float if not found */ - cm->imagemode = MS_IMAGEMODE_FLOAT32; - if( (value=msOWSLookupMetadata(&(layer->metadata), "CO", "imagemode")) != NULL ) { - if( EQUAL(value,"INT16") ) - cm->imagemode = MS_IMAGEMODE_INT16; - else if( EQUAL(value,"FLOAT32") ) - cm->imagemode = MS_IMAGEMODE_FLOAT32; - else if( EQUAL(value,"BYTE") ) - cm->imagemode = MS_IMAGEMODE_BYTE; - else { - msSetError( MS_WCSERR, "Content of wcs|ows_imagemode (%s) not recognised. Should be one of BYTE, INT16 or FLOAT32.", "msWCSGetCoverageMetadata()", value ); - return MS_FAILURE; - } - } - /* set color interpretation to undefined */ - /* TODO: find better solution */ - for(i = 0; i < 10; ++i) { - cm->bandinterpretation[i] = GDALGetColorInterpretationName(GCI_Undefined); - } - } else if( layer->data == NULL ) { /* no virtual metadata, not ok unless we're talking 1 image, hopefully we can fix that */ - msSetError( MS_WCSERR, "RASTER Layer with no DATA statement and no WCS virtual dataset metadata. Tileindexed raster layers not supported for WCS without virtual dataset metadata (cm->extent, wcs_res, wcs_size).", "msWCSGetCoverageDomain()" ); - return MS_FAILURE; - } else { /* work from the file (e.g. DATA) */ - GDALDatasetH hDS; - GDALRasterBandH hBand; - char szPath[MS_MAXPATHLEN]; - char *decrypted_path; - - msGDALInitialize(); - - msTryBuildPath3(szPath, layer->map->mappath, layer->map->shapepath, layer->data); - decrypted_path = msDecryptStringTokens( layer->map, szPath ); - if( !decrypted_path ) - return MS_FAILURE; - - msAcquireLock( TLOCK_GDAL ); - { - char** connectionoptions = msGetStringListFromHashTable(&(layer->connectionoptions)); - hDS = GDALOpenEx( decrypted_path, GDAL_OF_RASTER, NULL, - (const char* const*)connectionoptions, NULL); - CSLDestroy(connectionoptions); - } - if( hDS == NULL ) { - const char *cpl_error_msg = CPLGetLastErrorMsg(); - - /* we wish to avoid reporting decrypted paths */ - if( cpl_error_msg != NULL - && strstr(cpl_error_msg,decrypted_path) != NULL - && strcmp(decrypted_path,szPath) != 0 ) - cpl_error_msg = NULL; - - if( cpl_error_msg == NULL ) - cpl_error_msg = ""; - - msReleaseLock( TLOCK_GDAL ); - - msSetError( MS_IOERR, "%s", "msWCSGetCoverageMetadata()", - cpl_error_msg ); - - msFree( decrypted_path ); - return MS_FAILURE; - } - msFree( decrypted_path ); - - msGetGDALGeoTransform( hDS, layer->map, layer, cm->geotransform ); - - cm->xsize = GDALGetRasterXSize( hDS ); - cm->ysize = GDALGetRasterYSize( hDS ); - - cm->extent.minx = cm->geotransform[0]; - cm->extent.maxx = cm->geotransform[0] + cm->geotransform[1] * cm->xsize + cm->geotransform[2] * cm->ysize; - cm->extent.miny = cm->geotransform[3] + cm->geotransform[4] * cm->xsize + cm->geotransform[5] * cm->ysize; - cm->extent.maxy = cm->geotransform[3]; - - cm->xresolution = cm->geotransform[1]; - cm->yresolution = cm->geotransform[5]; - - /* TODO: need to set resolution */ - - cm->bandcount = GDALGetRasterCount( hDS ); - - if( cm->bandcount == 0 ) { - msReleaseLock( TLOCK_GDAL ); - msSetError( MS_WCSERR, "Raster file %s has no raster bands. This cannot be used in a layer.", "msWCSGetCoverageMetadata()", layer->data ); - return MS_FAILURE; - } - - hBand = GDALGetRasterBand( hDS, 1 ); - switch( GDALGetRasterDataType( hBand ) ) { - case GDT_Byte: - cm->imagemode = MS_IMAGEMODE_BYTE; - break; - case GDT_Int16: - cm->imagemode = MS_IMAGEMODE_INT16; - break; - default: - cm->imagemode = MS_IMAGEMODE_FLOAT32; - break; - } - - /* color interpretation */ - for(i = 1; i <= 10 && i <= cm->bandcount; ++i) { - GDALColorInterp colorInterp; - hBand = GDALGetRasterBand( hDS, i ); - colorInterp = GDALGetRasterColorInterpretation(hBand); - cm->bandinterpretation[i-1] = GDALGetColorInterpretationName(colorInterp); - } - - GDALClose( hDS ); - msReleaseLock( TLOCK_GDAL ); - } - - /* we must have the bounding box in lat/lon [WGS84(DD)/EPSG:4326] */ - cm->llextent = cm->extent; - - /* Already in latlong .. use directly. */ - if( layer->projection.proj != NULL && msProjIsGeographicCRS(&(layer->projection))) { - /* no change */ - } - - else if (layer->projection.numargs > 0 && !msProjIsGeographicCRS(&(layer->projection))) /* check the layer projection */ - msProjectRect(&(layer->projection), NULL, &(cm->llextent)); - - else if (layer->map->projection.numargs > 0 && !msProjIsGeographicCRS(&(layer->map->projection))) /* check the map projection */ - msProjectRect(&(layer->map->projection), NULL, &(cm->llextent)); - - else { /* projection was specified in the metadata only (EPSG:... only at the moment) */ - projectionObj proj; - char projstring[32]; - - msInitProjection(&proj); /* or bad things happen */ - msProjectionInheritContextFrom(&proj, &(layer->map->projection)); - - snprintf(projstring, sizeof(projstring), "init=epsg:%.20s", cm->srs_epsg+5); - if (msLoadProjectionString(&proj, projstring) != 0) return MS_FAILURE; - msProjectRect(&proj, NULL, &(cm->llextent)); - } - - return MS_SUCCESS; -} -#endif /* def USE_WCS_SVR */ - diff --git a/mapwcs.h b/mapwcs.h deleted file mode 100644 index fc203d043e..0000000000 --- a/mapwcs.h +++ /dev/null @@ -1,312 +0,0 @@ -/****************************************************************************** - * $Id$ - * - * Project: MapServer - * Purpose: OpenGIS Web Coverage Server (WCS) Declarations. - * Author: Steve Lime, Frank Warmerdam and the MapServer Team - * - ****************************************************************************** - * Copyright (c) 1996-2005 Regents of the University of Minnesota. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies of this Software or works derived from this Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - ****************************************************************************/ - -#ifndef MAPWCS_H -#define MAPWCS_H - -#include "mapserver.h" -#include "mapowscommon.h" -#include -#include -#include - -#ifndef _WIN32 -#include -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * Definitions - */ - -#define MS_WCS_GML_COVERAGETYPE_RECTIFIED_GRID_COVERAGE "RectifiedGridCoverage" - -enum { - MS_WCS_GET_CAPABILITIES, - MS_WCS_DESCRIBE_COVERAGE, - MS_WCS_GET_COVERAGE -}; - -/* -** Structure to hold metadata taken from the image or image tile index -*/ -typedef struct { - char *srs_epsg; - char srs_urn[500]; - rectObj extent, llextent; - double geotransform[6]; - int xsize, ysize; - double xresolution, yresolution; - int bandcount; - int imagemode; - const char *bandinterpretation[10]; -} coverageMetadataObj; - -typedef struct { - char *version; /* 1.0.0 for now */ - char *updatesequence; /* string, int or timestampe */ - char *request; /* GetCapabilities|DescribeCoverage|GetCoverage */ - char *service; /* MUST be WCS */ - char *section; /* of capabilities document: /WCS_Capabilities/Service|/WCS_Capabilities/Capability|/WCS_Capabilities/ContentMetadata */ - char **coverages; /* NULL terminated list of coverages (in the case of a GetCoverage there will only be 1) */ - char *crs; /* request coordinate reference system */ - char *response_crs; /* response coordinate reference system */ - rectObj bbox; /* subset bounding box (3D), although we'll only use 2D */ - char *time; - long width, height, depth; /* image dimensions */ - double originx, originy; /* WCS 1.1 GridOrigin */ - double resx, resy, resz; /* resolution */ - char *interpolation; /* interpolationMethod */ - char *format; - char *exceptions; /* exception MIME type, (default application=vnd.ogc.se_xml) */ -} wcsParamsObj; - -/* -------------------------------------------------------------------- */ -/* Prototypes from mapwcs.c used in mapwcs11.c. */ -/* */ -/* Note, all prototypes are deliberately not exported from DLL */ -/* since they are for internal use within the core. */ -/* -------------------------------------------------------------------- */ -void msWCSFreeParams(wcsParamsObj *params); -int msWCSException(mapObj *map, const char *code, const char *locator, - const char *version); -int msWCSIsLayerSupported(layerObj *layer); -int msWCSGetCoverageMetadata( layerObj *layer, coverageMetadataObj *cm ); -void msWCSFreeCoverageMetadata(coverageMetadataObj *cm); -void msWCSSetDefaultBandsRangeSetInfo( wcsParamsObj *params, - coverageMetadataObj *cm, - layerObj *lp ); -const char *msWCSGetRequestParameter(cgiRequestObj *request, const char *name); -void msWCSApplyLayerCreationOptions(layerObj* lp, - outputFormatObj* format, - const char* bandlist); -void msWCSApplyDatasetMetadataAsCreationOptions(layerObj* lp, - outputFormatObj* format, - const char* bandlist, - void* hDSIn); - -/* -------------------------------------------------------------------- */ -/* Some WCS 1.1 specific functions from mapwcs11.c */ -/* -------------------------------------------------------------------- */ -int msWCSGetCapabilities11(mapObj *map, wcsParamsObj *params, - cgiRequestObj *req, owsRequestObj *ows_request); -int msWCSDescribeCoverage11(mapObj *map, wcsParamsObj *params, owsRequestObj *ows_request); -int msWCSReturnCoverage11( wcsParamsObj *params, mapObj *map, imageObj *image); -int msWCSGetCoverageBands11( mapObj *map, cgiRequestObj *request, - wcsParamsObj *params, layerObj *lp, - char **p_bandlist ); -int msWCSException11(mapObj *map, const char *locator, - const char *exceptionCode, const char *version); - - -/* -------------------------------------------------------------------- */ -/* Some WCS 2.0 specific functions and structs from mapwcs20.c */ -/* -------------------------------------------------------------------- */ - -enum { - MS_WCS20_TRIM = 0, - MS_WCS20_SLICE = 1 -}; - -enum { - MS_WCS20_ERROR_VALUE = -1, - MS_WCS20_SCALAR_VALUE = 0, - MS_WCS20_TIME_VALUE = 1, - MS_WCS20_UNDEFINED_VALUE = 2 -}; - -#define MS_WCS20_UNBOUNDED DBL_MAX -#define MS_WCS20_UNBOUNDED_TIME 0xFFFFFFFF - -typedef struct { - union { - double scalar; - time_t time; - }; - int unbounded; /* 0 if bounded, 1 if unbounded */ -} timeScalarUnion; - -typedef struct { - char *axis; /* the name of the subsetted axis */ - int operation; /* Either TRIM or SLICE */ - char *crs; /* optional CRS to use */ - int timeOrScalar; /* 0 if scalar value, 1 if time value */ - timeScalarUnion min; /* Minimum and Maximum of the subsetted axis;*/ - timeScalarUnion max; -} wcs20SubsetObj; -typedef wcs20SubsetObj * wcs20SubsetObjPtr; - -typedef struct { - char *name; /* name of the axis */ - int size; /* pixelsize of the axis */ - double resolution; /* resolution of the axis */ - double scale; /* scale of the axis */ - char *resolutionUOM; /* resolution units of measure */ - wcs20SubsetObjPtr subset; -} wcs20AxisObj; -typedef wcs20AxisObj * wcs20AxisObjPtr; - -typedef struct { - char *version; /* 2.0.0 v 2.0.1 */ - char *request; /* GetCapabilities|DescribeCoverage|GetCoverage */ - char *service; /* MUST be WCS */ - char **accept_versions; /* NULL terminated list of Accepted versions */ - char **accept_languages; /* NULL terminated list of Accepted versions */ - char **sections; /* NULL terminated list of GetCapabilities sections */ - char *updatesequence; /* GetCapabilities updatesequence */ - char **ids; /* NULL terminated list of coverages (in the case of a GetCoverage there will only be 1) */ - long width, height; /* image dimensions */ - double resolutionX; /* image resolution in X axis */ - double resolutionY; /* image resolution in Y axis */ - double scale; /* Overall scale */ - double scaleX; /* X-Axis specific scale */ - double scaleY; /* Y-Axis specific scale */ - char *resolutionUnits; /* Units of Measure for resolution */ - char *format; /* requested output format */ - int multipart; /* flag for multipart GML+image */ - char *interpolation; /* requested interpolation method */ - char *outputcrs; /* requested CRS for output */ - char *subsetcrs; /* determined CRS of the subsets */ - rectObj bbox; /* determined Bounding Box */ - int numaxes; /* number of axes */ - wcs20AxisObjPtr *axes; /* list of axes, NULL if none*/ - char **range_subset; /* list of bands selected */ - char **format_options; /* list of format specific options, NULL terminated */ -} wcs20ParamsObj; -typedef wcs20ParamsObj * wcs20ParamsObjPtr; - -typedef struct { - union { - struct { - char *name; - char *interpretation; - char *uom; - char *definition; - char *description; - }; - char *values[5]; - }; - double interval_min; - double interval_max; - int significant_figures; -} wcs20rasterbandMetadataObj; -typedef wcs20rasterbandMetadataObj * wcs20rasterbandMetadataObjPtr; - -typedef struct { - char *native_format; /* mime type of the native format */ - char *srs_epsg; - char srs_uri[200]; - rectObj extent; - double geotransform[6]; - double xresolution; - double yresolution; - int xsize; - int ysize; - int imagemode; - size_t numnilvalues; - char **nilvalues; - char **nilvalues_reasons; - size_t numbands; - wcs20rasterbandMetadataObjPtr bands; -} wcs20coverageMetadataObj; -typedef wcs20coverageMetadataObj * wcs20coverageMetadataObjPtr; - -#define MS_WCS_20_PROFILE_CORE "http://www.opengis.net/spec/WCS/2.0/conf/core" -#define MS_WCS_20_PROFILE_KVP "http://www.opengis.net/spec/WCS_protocol-binding_get-kvp/1.0/conf/get-kvp" -#define MS_WCS_20_PROFILE_POST "http://www.opengis.net/spec/WCS_protocol-binding_post-xml/1.0/conf/post-xml" -#define MS_WCS_20_PROFILE_GML "http://www.opengis.net/spec/GMLCOV/1.0/conf/gml-coverage" -#define MS_WCS_20_PROFILE_GML_MULTIPART "http://www.opengis.net/spec/GMLCOV/1.0/conf/multipart" -#define MS_WCS_20_PROFILE_GML_SPECIAL "http://www.opengis.net/spec/GMLCOV/1.0/conf/special-format" -#define MS_WCS_20_PROFILE_GML_GEOTIFF "http://www.opengis.net/spec/GMLCOV_geotiff-coverages/1.0/conf/geotiff-coverage" -#define MS_WCS_20_PROFILE_CRS "http://www.opengis.net/spec/WCS_service-extension_crs/1.0/conf/crs" -#define MS_WCS_20_PROFILE_SCALING "http://www.opengis.net/spec/WCS_service-extension_scaling/1.0/conf/scaling" -#define MS_WCS_20_PROFILE_RANGESUBSET "http://www.opengis.net/spec/WCS_service-extension_range-subsetting/1.0/conf/record-subsetting" -#define MS_WCS_20_PROFILE_INTERPOLATION "http://www.opengis.net/spec/WCS_service-extension_interpolation/1.0/conf/interpolation" - -/* -------------------------------------------------------------------- */ -/* WCS 2.0 function prototypes. */ -/* -------------------------------------------------------------------- */ - -wcs20ParamsObjPtr msWCSCreateParamsObj20(); -void msWCSFreeParamsObj20(wcs20ParamsObjPtr params); -int msWCSParseRequest20(mapObj *map, cgiRequestObj *request, owsRequestObj *ows_request, wcs20ParamsObjPtr params); - -int msWCSException20(mapObj *map, const char *locator, const char *exceptionCode, const char *version); - -int msWCSGetCapabilities20(mapObj *map, cgiRequestObj *req, wcs20ParamsObjPtr params, owsRequestObj *ows_request); -int msWCSDescribeCoverage20(mapObj *map, wcs20ParamsObjPtr params, owsRequestObj *ows_request); -int msWCSGetCoverage20(mapObj *map, cgiRequestObj *request, wcs20ParamsObjPtr params, owsRequestObj *ows_request); - -/* -------------------------------------------------------------------- */ -/* XML parsing helper macros. */ -/* -------------------------------------------------------------------- */ - -#define XML_FOREACH_CHILD(parent_node, child_node) \ - for(child_node = parent_node->children; child_node != NULL; child_node = child_node->next) - -/* Makro to continue the iteration over an xml structure */ -/* when the current node has the type 'text' or 'comment' */ -#define XML_LOOP_IGNORE_COMMENT_OR_TEXT(node) \ - if(xmlNodeIsText(node) || node->type == XML_COMMENT_NODE) \ - { \ - continue; \ - } - -/* Makro to set an XML error that an unknown node type */ -/* occurred. */ -#define XML_UNKNOWN_NODE_ERROR(node) \ - msSetError(MS_WCSERR, "Unknown XML element '%s'.", \ - __FUNCTION__, (char *)node->name); \ - return MS_FAILURE; - -#define XML_ASSERT_NODE_NAME(node,nodename) \ - if(EQUAL((char *)node->name, nodename) == MS_FALSE) \ - { \ - XML_UNKNOWN_NODE_ERROR(node); \ - } - -#define MS_WCS_20_CAPABILITIES_INCLUDE_SECTION(params,section) \ - (params->sections == NULL \ - || CSLFindString(params->sections, "All") != -1 \ - || CSLFindString(params->sections, section) != -1) - - -#if defined(USE_LIBXML2) -#include "maplibxml2.h" -void msWCS_11_20_PrintMetadataLinks(layerObj *layer, xmlDocPtr doc, xmlNodePtr psCSummary); -#endif - -#ifdef __cplusplus -} /* extern C */ -#endif - -#endif /* nef MAPWCS_H */ diff --git a/mapwcs11.cpp b/mapwcs11.cpp deleted file mode 100644 index eaa99892f4..0000000000 --- a/mapwcs11.cpp +++ /dev/null @@ -1,1436 +0,0 @@ -/****************************************************************************** - * $Id$ - * - * Project: MapServer - * Purpose: OpenGIS Web Coverage Server (WCS) 1.1.0 Implementation. This - * file holds some WCS 1.1.0 specific functions but other parts - * are still implemented in mapwcs.c. - * Author: Frank Warmerdam and the MapServer team. - * - ****************************************************************************** - * Copyright (c) 2007, Frank Warmerdam - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies of this Software or works derived from this Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - *****************************************************************************/ - -#include -#include "mapserver.h" -#include "maperror.h" -#include "mapthread.h" -#include "mapows.h" -#include "mapwcs.h" - - - -#if defined(USE_WCS_SVR) -#include "mapwcs.h" -#include "gdal.h" -#include "cpl_string.h" /* GDAL string handling */ -#endif - -#if defined(USE_LIBXML2) -#include "maplibxml2.h" -#endif - -#include - -#if defined(USE_WCS_SVR) && defined(USE_LIBXML2) -/* -** msWCSException11() -** -** Report current MapServer error in XML exception format. -** Wrapper function around msOWSCommonExceptionReport. Merely -** passes WCS specific info. -** -*/ - -int msWCSException11(mapObj *map, const char *exceptionCode, - const char *locator, const char *version) -{ - int size = 0; - char *errorString = NULL; - char *schemasLocation = NULL; - - xmlDocPtr psDoc = NULL; - xmlNodePtr psRootNode = NULL; - xmlNsPtr psNsOws = NULL; - xmlChar *buffer = NULL; - - psNsOws = xmlNewNs(NULL, BAD_CAST "http://www.opengis.net/ows/1.1", BAD_CAST "ows"); - - errorString = msGetErrorString("\n"); - schemasLocation = msEncodeHTMLEntities(msOWSGetSchemasLocation(map)); - - psDoc = xmlNewDoc(BAD_CAST "1.0"); - - psRootNode = msOWSCommonExceptionReport(psNsOws, OWS_1_1_0, schemasLocation, version, msOWSGetLanguage(map, "exception"), exceptionCode, locator, errorString); - - xmlDocSetRootElement(psDoc, psRootNode); - - xmlNewNs(psRootNode, BAD_CAST "http://www.opengis.net/ows/1.1", BAD_CAST "ows"); - - msIO_setHeader("Content-Type","text/xml; charset=UTF-8"); - msIO_sendHeaders(); - - xmlDocDumpFormatMemoryEnc(psDoc, &buffer, &size, "UTF-8", 1); - - msIO_printf("%s", buffer); - - /*free buffer and the document */ - free(errorString); - free(schemasLocation); - xmlFree(buffer); - xmlFreeDoc(psDoc); - xmlFreeNs(psNsOws); - - /* clear error since we have already reported it */ - msResetErrorList(); - - return MS_FAILURE; -} - -/************************************************************************/ -/* msWCSGetFormatsList11() */ -/* */ -/* Fetch back a comma delimited formats list for the past layer */ -/* if one is supplied, otherwise for all formats supported by */ -/* the server. Formats should be identified by mime type. */ -/************************************************************************/ - -static char *msWCSGetFormatsList11( mapObj *map, layerObj *layer ) - -{ - char *format_list = msStrdup(""); - char **tokens = NULL, **formats = NULL; - int i, numtokens = 0, numformats; - char *value; - - msApplyDefaultOutputFormats(map); - - /* -------------------------------------------------------------------- */ - /* Parse from layer metadata. */ - /* -------------------------------------------------------------------- */ - if( layer != NULL - && (value = msOWSGetEncodeMetadata( &(layer->metadata),"CO","formats", - "GTiff" )) != NULL ) { - tokens = msStringSplit(value, ' ', &numtokens); - msFree(value); - } - - /* -------------------------------------------------------------------- */ - /* Parse from map.web metadata. */ - /* -------------------------------------------------------------------- */ - else if((value = msOWSGetEncodeMetadata( &(map->web.metadata), "CO", "formats", - NULL)) != NULL ) { - tokens = msStringSplit(value, ' ', &numtokens); - msFree(value); - } - - /* -------------------------------------------------------------------- */ - /* Or generate from all configured raster output formats that */ - /* look plausible. */ - /* -------------------------------------------------------------------- */ - else { - tokens = (char **) calloc(map->numoutputformats,sizeof(char*)); - for( i = 0; i < map->numoutputformats; i++ ) { - switch( map->outputformatlist[i]->renderer ) { - /* seeminly normal raster format */ - case MS_RENDER_WITH_AGG: - case MS_RENDER_WITH_RAWDATA: - tokens[numtokens++] = msStrdup(map->outputformatlist[i]->name); - break; - - /* rest of formats aren't really WCS compatible */ - default: - break; - - } - } - } - - /* -------------------------------------------------------------------- */ - /* Convert outputFormatObj names into mime types and remove */ - /* duplicates. */ - /* -------------------------------------------------------------------- */ - numformats = 0; - formats = (char **) calloc(sizeof(char*),numtokens); - - for( i = 0; i < numtokens; i++ ) { - int format_i, j; - const char *mimetype; - - for( format_i = 0; format_i < map->numoutputformats; format_i++ ) { - if( strcasecmp(map->outputformatlist[format_i]->name, - tokens[i]) == 0 ) - break; - } - - - if( format_i == map->numoutputformats ) { - msDebug("Failed to find outputformat info on format '%s', ignore.\n", - tokens[i] ); - continue; - } - - mimetype = map->outputformatlist[format_i]->mimetype; - if( mimetype == NULL || strlen(mimetype) == 0 ) { - msDebug("No mimetime for format '%s', ignoring.\n", - tokens[i] ); - continue; - } - - for( j = 0; j < numformats; j++ ) { - if( strcasecmp(mimetype,formats[j]) == 0 ) - break; - } - - if( j < numformats ) { - msDebug( "Format '%s' ignored since mimetype '%s' duplicates another outputFormatObj.\n", - tokens[i], mimetype ); - continue; - } - - formats[numformats++] = msStrdup(mimetype); - } - - msFreeCharArray(tokens,numtokens); - - /* -------------------------------------------------------------------- */ - /* Turn mimetype list into comma delimited form for easy use */ - /* with xml functions. */ - /* -------------------------------------------------------------------- */ - for(i=0; i 0) { - format_list = msStringConcatenate(format_list, (char *) ","); - } - format_list = msStringConcatenate(format_list, formats[i]); - } - msFreeCharArray(formats,numformats); - - return format_list; -} - -/************************************************************************/ -/* msWCS_11_20_PrintMetadataLink() */ -/************************************************************************/ - -static void msWCS_11_20_PrintMetadataLink(layerObj *layer, - const std::string& radix, - xmlDocPtr doc, - xmlNodePtr psCSummary) -{ - const char* value = msOWSLookupMetadata(&(layer->metadata), "CO", (radix + "_href").c_str()); - if (value) { - xmlNsPtr psOwsNs = xmlSearchNs( doc, xmlDocGetRootElement(doc), BAD_CAST "ows" ); - xmlNodePtr psMetadata = xmlNewChild(psCSummary, psOwsNs, BAD_CAST "Metadata", NULL); - xmlNsPtr psXlinkNs = xmlSearchNs( doc, xmlDocGetRootElement(doc), BAD_CAST "xlink" ); - const char *metadatalink_type = msOWSLookupMetadata(&(layer->metadata), "CO", (radix + "_type").c_str()); - const char *metadatalink_format = msOWSLookupMetadata(&(layer->metadata), "CO", (radix + "_format").c_str()); - - xmlNewNsProp(psMetadata, psXlinkNs, BAD_CAST "type", BAD_CAST "simple"); - xmlNewNsProp(psMetadata, psXlinkNs, BAD_CAST "href", BAD_CAST value); - if (metadatalink_type != NULL) { - xmlNewProp(psMetadata, BAD_CAST "about", BAD_CAST metadatalink_type); - } - if (metadatalink_format != NULL) { - xmlNewNsProp(psMetadata, psXlinkNs, BAD_CAST "role", BAD_CAST metadatalink_format); - } - } -} - -/************************************************************************/ -/* msWCS_11_20_PrintMetadataLinks() */ -/************************************************************************/ - -void msWCS_11_20_PrintMetadataLinks(layerObj *layer, xmlDocPtr doc, - xmlNodePtr psCSummary) -{ - const char* list = msOWSLookupMetadata(&(layer->metadata), "CO", "metadatalink_list"); - if( list ) { - int ntokens = 0; - char** tokens = msStringSplit(list, ' ', &ntokens); - for( int i = 0; i < ntokens; i++ ) - { - std::string key("metadatalink_"); - key += tokens[i]; - msWCS_11_20_PrintMetadataLink(layer, key, doc, psCSummary); - } - msFreeCharArray(tokens, ntokens); - return; - } - - msWCS_11_20_PrintMetadataLink(layer, "metadatalink", doc, psCSummary); -} - -/************************************************************************/ -/* msWCSGetCapabilities11_CoverageSummary() */ -/* */ -/* Generate a WCS 1.1 CoverageSummary. */ -/************************************************************************/ - -static int msWCSGetCapabilities11_CoverageSummary( - mapObj *map, wcsParamsObj *params, cgiRequestObj *req, - xmlDocPtr doc, xmlNodePtr psContents, layerObj *layer ) - -{ - coverageMetadataObj cm; - int status; - const char *value; - char *owned_value; - char *format_list; - xmlNodePtr psCSummary; - xmlNsPtr psOwsNs = xmlSearchNs( doc, psContents, BAD_CAST "ows" ); - char **tokens = NULL; - int i = 0; - int n = 0; - - status = msWCSGetCoverageMetadata(layer, &cm); - if(status != MS_SUCCESS) return MS_FAILURE; - - psCSummary = xmlNewChild( psContents, NULL, BAD_CAST "CoverageSummary", NULL ); - - /* -------------------------------------------------------------------- */ - /* Title (from description) */ - /* -------------------------------------------------------------------- */ - value = msOWSLookupMetadata( &(layer->metadata), "CO", "description"); - if( value == NULL ) - value = msOWSLookupMetadata( &(layer->metadata), "CO", "title"); - if( value == NULL ) - value = layer->name; - xmlNewChild( psCSummary, psOwsNs, BAD_CAST "Title", BAD_CAST value ); - - /* -------------------------------------------------------------------- */ - /* Abstract */ - /* -------------------------------------------------------------------- */ - value = msOWSLookupMetadata( &(layer->metadata), "CO", "abstract"); - xmlNewChild( psCSummary, psOwsNs, BAD_CAST "Abstract", BAD_CAST value ); - - /* -------------------------------------------------------------------- */ - /* Keywords */ - /* -------------------------------------------------------------------- */ - value = msOWSLookupMetadata(&(layer->metadata), "CO", "keywordlist"); - - if (value) { - xmlNodePtr psNode; - - psNode = xmlNewChild(psCSummary, psOwsNs, BAD_CAST "Keywords", NULL); - - tokens = msStringSplit(value, ',', &n); - if (tokens && n > 0) { - for (i=0; iprojection), &(layer->metadata), - "CO", MS_FALSE)) != NULL ) { - /* ok */ - } else if((owned_value = - msOWSGetProjURN( &(layer->map->projection), - &(layer->map->web.metadata), - "CO", MS_FALSE)) != NULL ) { - /* ok */ - } else - msDebug( "mapwcs.c: missing required information, no SRSs defined.\n"); - - if( owned_value != NULL && strlen(owned_value) > 0 ) - msLibXml2GenerateList( psCSummary, NULL, "SupportedCRS", - owned_value, ' ' ); - - msFree( owned_value ); - - /* -------------------------------------------------------------------- */ - /* SupportedFormats */ - /* -------------------------------------------------------------------- */ - format_list = msWCSGetFormatsList11( map, layer ); - - if (strlen(format_list) > 0 ) - msLibXml2GenerateList( psCSummary, NULL, "SupportedFormat", - format_list, ',' ); - - msFree( format_list ); - msWCSFreeCoverageMetadata(&cm); - - /* -------------------------------------------------------------------- */ - /* Identifier (layer name) */ - /* -------------------------------------------------------------------- */ - xmlNewChild( psCSummary, NULL, BAD_CAST "Identifier", BAD_CAST layer->name ); - - return MS_SUCCESS; -} - -/************************************************************************/ -/* msWCSGetCapabilities11() */ -/************************************************************************/ -int msWCSGetCapabilities11(mapObj *map, wcsParamsObj *params, - cgiRequestObj *req, owsRequestObj *ows_request) -{ - xmlDocPtr psDoc = NULL; /* document pointer */ - xmlNodePtr psRootNode, psMainNode, psNode; - char *identifier_list = NULL, *format_list = NULL; - const char *updatesequence=NULL; - xmlNsPtr psOwsNs, psXLinkNs; - char *schemaLocation = NULL; - char *xsi_schemaLocation = NULL; - char *script_url=NULL, *script_url_encoded=NULL; - - xmlChar *buffer = NULL; - int size = 0, i; - msIOContext *context = NULL; - - int ows_version = OWS_1_1_0; - - /* -------------------------------------------------------------------- */ - /* Handle updatesequence */ - /* -------------------------------------------------------------------- */ - - updatesequence = msOWSLookupMetadata(&(map->web.metadata), "CO", "updatesequence"); - - if (params->updatesequence != NULL) { - i = msOWSNegotiateUpdateSequence(params->updatesequence, updatesequence); - if (i == 0) { /* current */ - msSetError(MS_WCSERR, "UPDATESEQUENCE parameter (%s) is equal to server (%s)", "msWCSGetCapabilities11()", params->updatesequence, updatesequence); - return msWCSException11(map, "CurrentUpdateSequence", "updatesequence", params->version); - } - if (i > 0) { /* invalid */ - msSetError(MS_WCSERR, "UPDATESEQUENCE parameter (%s) is higher than server (%s)", "msWCSGetCapabilities11()", params->updatesequence, updatesequence); - return msWCSException11(map, "InvalidUpdateSequence", "updatesequence", params->version); - } - } - - /* -------------------------------------------------------------------- */ - /* Build list of layer identifiers available. */ - /* -------------------------------------------------------------------- */ - identifier_list = msStrdup(""); - for(i=0; inumlayers; i++) { - layerObj *layer = map->layers[i]; - int new_length; - - if(!msWCSIsLayerSupported(layer)) - continue; - - new_length = strlen(identifier_list) + strlen(layer->name) + 2; - identifier_list = (char *) realloc(identifier_list,new_length); - - if( strlen(identifier_list) > 0 ) - strcat( identifier_list, "," ); - strcat( identifier_list, layer->name ); - } - - /* -------------------------------------------------------------------- */ - /* Create document. */ - /* -------------------------------------------------------------------- */ - psDoc = xmlNewDoc(BAD_CAST "1.0"); - - psRootNode = xmlNewNode(NULL, BAD_CAST "Capabilities"); - - xmlDocSetRootElement(psDoc, psRootNode); - - /* -------------------------------------------------------------------- */ - /* Name spaces */ - /* -------------------------------------------------------------------- */ - xmlSetNs(psRootNode, xmlNewNs(psRootNode, BAD_CAST "http://www.opengis.net/wcs/1.1", NULL)); - psOwsNs = xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_OWS_110_NAMESPACE_URI, BAD_CAST MS_OWSCOMMON_OWS_NAMESPACE_PREFIX); - psXLinkNs = xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_W3C_XLINK_NAMESPACE_URI, BAD_CAST MS_OWSCOMMON_W3C_XLINK_NAMESPACE_PREFIX); - xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_W3C_XSI_NAMESPACE_URI, BAD_CAST MS_OWSCOMMON_W3C_XSI_NAMESPACE_PREFIX); - xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_OGC_NAMESPACE_URI, BAD_CAST MS_OWSCOMMON_OGC_NAMESPACE_PREFIX ); - - /*xmlNewProp(psRootNode, BAD_CAST " */ - xmlNewProp(psRootNode, BAD_CAST "version", BAD_CAST params->version ); - - updatesequence = msOWSLookupMetadata(&(map->web.metadata), "CO", "updatesequence"); - - if (updatesequence) - xmlNewProp(psRootNode, BAD_CAST "updateSequence", BAD_CAST updatesequence); - - schemaLocation = msEncodeHTMLEntities( msOWSGetSchemasLocation(map) ); - xsi_schemaLocation = msStrdup("http://www.opengis.net/wcs/1.1"); - xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, " "); - xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, schemaLocation); - xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, "/wcs/1.1/wcsGetCapabilities.xsd "); - xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, MS_OWSCOMMON_OWS_110_NAMESPACE_URI); - xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, " "); - xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, schemaLocation); - xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, "/ows/1.1.0/owsAll.xsd"); - xmlNewNsProp(psRootNode, NULL, BAD_CAST "xsi:schemaLocation", BAD_CAST xsi_schemaLocation); - msFree(schemaLocation); - msFree(xsi_schemaLocation); - - /* -------------------------------------------------------------------- */ - /* Service metadata. */ - /* -------------------------------------------------------------------- */ - if( params->section == NULL - || strstr(params->section,"All") != NULL - || strstr(params->section,"ServiceIdentification") != NULL ) { - xmlAddChild(psRootNode, msOWSCommonServiceIdentification( - psOwsNs, map, "OGC WCS", "2.0.1,1.1.1,1.0.0", "CO", NULL)); - } - - /*service provider*/ - if( params->section == NULL - || strstr(params->section,"All") != NULL - || strstr(params->section,"ServiceProvider") != NULL ) { - xmlAddChild(psRootNode, msOWSCommonServiceProvider( - psOwsNs, psXLinkNs, map, "CO", NULL)); - } - - /* -------------------------------------------------------------------- */ - /* Operations metadata. */ - /* -------------------------------------------------------------------- */ - /*operation metadata */ - if ((script_url=msOWSGetOnlineResource(map, "CO", "onlineresource", req)) == NULL - || (script_url_encoded = msEncodeHTMLEntities(script_url)) == NULL) { - msSetError(MS_WCSERR, "Server URL not found", "msWCSGetCapabilities11()"); - return msWCSException11(map, "NoApplicableCode", "mapserv", params->version); - } - free( script_url ); - - if( params->section == NULL - || strstr(params->section,"All") != NULL - || strstr(params->section,"OperationsMetadata") != NULL ) { - psMainNode= xmlAddChild(psRootNode,msOWSCommonOperationsMetadata(psOwsNs)); - - /* -------------------------------------------------------------------- */ - /* GetCapabilities - add Sections and AcceptVersions? */ - /* -------------------------------------------------------------------- */ - psNode = msOWSCommonOperationsMetadataOperation( - psOwsNs, psXLinkNs, - "GetCapabilities", OWS_METHOD_GETPOST, script_url_encoded); - - xmlAddChild(psMainNode, psNode); - xmlAddChild(psNode, msOWSCommonOperationsMetadataDomainType( - ows_version, psOwsNs, "Parameter", "service", "WCS")); - xmlAddChild(psNode, msOWSCommonOperationsMetadataDomainType( - ows_version, psOwsNs, "Parameter", "version", (char *)params->version)); - - /* -------------------------------------------------------------------- */ - /* DescribeCoverage */ - /* -------------------------------------------------------------------- */ - if (msOWSRequestIsEnabled(map, NULL, "C", "DescribeCoverage", MS_FALSE)) { - psNode = msOWSCommonOperationsMetadataOperation( - psOwsNs, psXLinkNs, - "DescribeCoverage", OWS_METHOD_GETPOST, script_url_encoded); - - xmlAddChild(psMainNode, psNode); - xmlAddChild(psNode, msOWSCommonOperationsMetadataDomainType( - ows_version, psOwsNs, "Parameter", "service", "WCS")); - xmlAddChild(psNode, msOWSCommonOperationsMetadataDomainType( - ows_version, psOwsNs, "Parameter", "version", (char *)params->version)); - xmlAddChild(psNode, msOWSCommonOperationsMetadataDomainType( - ows_version, psOwsNs, "Parameter", "identifiers", identifier_list )); - } - - /* -------------------------------------------------------------------- */ - /* GetCoverage */ - /* -------------------------------------------------------------------- */ - if (msOWSRequestIsEnabled(map, NULL, "C", "GetCoverage", MS_FALSE)) { - - psNode = msOWSCommonOperationsMetadataOperation( - psOwsNs, psXLinkNs, - "GetCoverage", OWS_METHOD_GETPOST, script_url_encoded); - - format_list = msWCSGetFormatsList11( map, NULL ); - - xmlAddChild(psMainNode, psNode); - xmlAddChild(psNode, msOWSCommonOperationsMetadataDomainType( - ows_version, psOwsNs, "Parameter", "service", "WCS")); - xmlAddChild(psNode, msOWSCommonOperationsMetadataDomainType( - ows_version, psOwsNs, "Parameter", "version", (char *)params->version)); - xmlAddChild(psNode, msOWSCommonOperationsMetadataDomainType( - ows_version, psOwsNs, "Parameter", "Identifier", identifier_list )); - xmlAddChild(psNode, msOWSCommonOperationsMetadataDomainType( - ows_version, psOwsNs, "Parameter", "InterpolationType", - "NEAREST_NEIGHBOUR,BILINEAR" )); - xmlAddChild(psNode, msOWSCommonOperationsMetadataDomainType( - ows_version, psOwsNs, "Parameter", "format", format_list )); - xmlAddChild(psNode, msOWSCommonOperationsMetadataDomainType( - ows_version, psOwsNs, "Parameter", "store", "false" )); - xmlAddChild(psNode, msOWSCommonOperationsMetadataDomainType( - ows_version, psOwsNs, "Parameter", "GridBaseCRS", - "urn:ogc:def:crs:epsg::4326" )); - - msFree( format_list ); - } - } - - /* -------------------------------------------------------------------- */ - /* Contents section. */ - /* -------------------------------------------------------------------- */ - if( params->section == NULL - || strstr(params->section,"All") != NULL - || strstr(params->section,"Contents") != NULL ) { - psMainNode = xmlNewChild( psRootNode, NULL, BAD_CAST "Contents", NULL ); - - if(ows_request->numlayers == 0) { - xmlAddChild(psMainNode, - xmlNewComment(BAD_CAST "WARNING: No WCS layers are enabled. " - "Check wcs/ows_enable_request settings.")); - } else { - for(i=0; inumlayers; i++) { - layerObj *layer = map->layers[i]; - int status; - - if(!msWCSIsLayerSupported(layer)) - continue; - - if (!msIntegerInArray(layer->index, ows_request->enabled_layers, ows_request->numlayers)) - continue; - - status = msWCSGetCapabilities11_CoverageSummary( - map, params, req, psDoc, psMainNode, layer ); - if(status != MS_SUCCESS) { - msFree(identifier_list); - return MS_FAILURE; - } - } - } - } - - /* -------------------------------------------------------------------- */ - /* Write out the document. */ - /* -------------------------------------------------------------------- */ - - if( msIO_needBinaryStdout() == MS_FAILURE ) - return MS_FAILURE; - - msIO_setHeader("Content-Type","text/xml; charset=UTF-8"); - msIO_sendHeaders(); - - context = msIO_getHandler(stdout); - - xmlDocDumpFormatMemoryEnc(psDoc, &buffer, &size, "UTF-8", 1); - msIO_contextWrite(context, buffer, size); - xmlFree(buffer); - - /*free buffer and the document */ - /*xmlFree(buffer);*/ - xmlFreeDoc(psDoc); - - xmlCleanupParser(); - - /* clean up */ - free( script_url_encoded ); - free( identifier_list ); - - return(MS_SUCCESS); -} - -/************************************************************************/ -/* msWCSDescribeCoverage_CoverageDescription11() */ -/************************************************************************/ - -static int -msWCSDescribeCoverage_CoverageDescription11( - layerObj *layer, wcsParamsObj *params, xmlNodePtr psRootNode, - xmlNsPtr psOwsNs ) - -{ - int status; - coverageMetadataObj cm; - xmlNodePtr psCD, psDomain, psSD, psGridCRS; - const char *value; - - /* -------------------------------------------------------------------- */ - /* Verify layer is processable. */ - /* -------------------------------------------------------------------- */ - if( msCheckParentPointer(layer->map,"map") == MS_FAILURE ) - return MS_FAILURE; - - if(!msWCSIsLayerSupported(layer)) - return MS_SUCCESS; - - /* -------------------------------------------------------------------- */ - /* Setup coverage metadata. */ - /* -------------------------------------------------------------------- */ - status = msWCSGetCoverageMetadata(layer, &cm); - if(status != MS_SUCCESS) return status; - - /* fill in bands rangeset info, if required. */ - msWCSSetDefaultBandsRangeSetInfo( params, &cm, layer ); - - /* -------------------------------------------------------------------- */ - /* Create CoverageDescription node. */ - /* -------------------------------------------------------------------- */ - psCD = xmlNewChild( psRootNode, NULL, BAD_CAST "CoverageDescription", NULL ); - - /* -------------------------------------------------------------------- */ - /* Title (from description) */ - /* -------------------------------------------------------------------- */ - value = msOWSLookupMetadata( &(layer->metadata), "CO", "description"); - if( value == NULL ) - value = layer->name; - xmlNewChild( psCD, psOwsNs, BAD_CAST "Title", BAD_CAST value ); - - /* -------------------------------------------------------------------- */ - /* Abstract */ - /* -------------------------------------------------------------------- */ - value = msOWSLookupMetadata( &(layer->metadata), "CO", "abstract"); - xmlNewChild( psCD, psOwsNs, BAD_CAST "Abstract", BAD_CAST value ); - - /* -------------------------------------------------------------------- */ - /* Keywords */ - /* -------------------------------------------------------------------- */ - value = msOWSLookupMetadata(&(layer->metadata), "CO", "keywordlist"); - - if (value) - msLibXml2GenerateList( - xmlNewChild(psCD, psOwsNs, BAD_CAST "Keywords", NULL), - NULL, "Keyword", value, ',' ); - - /* -------------------------------------------------------------------- */ - /* Identifier (layer name) */ - /* -------------------------------------------------------------------- */ - xmlNewChild( psCD, NULL, BAD_CAST "Identifier", BAD_CAST layer->name); - - /* -------------------------------------------------------------------- */ - /* Domain */ - /* -------------------------------------------------------------------- */ - psDomain = xmlNewChild( psCD, NULL, BAD_CAST "Domain", NULL ); - - /* -------------------------------------------------------------------- */ - /* SpatialDomain */ - /* -------------------------------------------------------------------- */ - psSD = xmlNewChild( psDomain, NULL, BAD_CAST "SpatialDomain", NULL ); - - /* -------------------------------------------------------------------- */ - /* imageCRS bounding box. */ - /* -------------------------------------------------------------------- */ - xmlAddChild( - psSD, - msOWSCommonBoundingBox( psOwsNs, "urn:ogc:def:crs:OGC::imageCRS", - 2, 0, 0, cm.xsize-1, cm.ysize-1 )); - - /* -------------------------------------------------------------------- */ - /* native CRS bounding box. */ - /* -------------------------------------------------------------------- */ - xmlAddChild( - psSD, - msOWSCommonBoundingBox( psOwsNs, cm.srs_urn, 2, - cm.extent.minx, cm.extent.miny, - cm.extent.maxx, cm.extent.maxy )); - - /* -------------------------------------------------------------------- */ - /* WGS84 bounding box. */ - /* -------------------------------------------------------------------- */ - xmlAddChild( - psSD, - msOWSCommonWGS84BoundingBox( psOwsNs, 2, - cm.llextent.minx, cm.llextent.miny, - cm.llextent.maxx, cm.llextent.maxy )); - - /* -------------------------------------------------------------------- */ - /* GridCRS */ - /* -------------------------------------------------------------------- */ - { - char format_buf[500]; - projectionObj proj; - double x0 = cm.geotransform[0]+cm.geotransform[1]/2+cm.geotransform[2]/2; - double y0 = cm.geotransform[3]+cm.geotransform[4]/2+cm.geotransform[5]/2; - double resx = cm.geotransform[1]; - double resy = cm.geotransform[5]; - - msInitProjection( &proj ); - msProjectionInheritContextFrom(&proj, &(layer->projection)); - if( msLoadProjectionString( &proj, cm.srs_urn ) == 0 ) { - msAxisNormalizePoints( &proj, 1, &x0, &y0 ); - msAxisNormalizePoints( &proj, 1, &resx, &resy ); - } - msFreeProjection( &proj ); - - psGridCRS = xmlNewChild( psSD, NULL, BAD_CAST "GridCRS", NULL ); - - xmlNewChild( psGridCRS, NULL, BAD_CAST "GridBaseCRS", BAD_CAST cm.srs_urn ); - xmlNewChild( psGridCRS, NULL, BAD_CAST "GridType", - BAD_CAST "urn:ogc:def:method:WCS:1.1:2dSimpleGrid" ); - - sprintf( format_buf, "%.15g %.15g", x0, y0 ); - xmlNewChild( psGridCRS, NULL, BAD_CAST "GridOrigin", BAD_CAST format_buf ); - - sprintf( format_buf, "%.15g %.15g", resx, resy ); - xmlNewChild( psGridCRS, NULL, BAD_CAST "GridOffsets", BAD_CAST format_buf ); - - xmlNewChild( psGridCRS, NULL, BAD_CAST "GridCS", - BAD_CAST "urn:ogc:def:cs:OGC:0.0:Grid2dSquareCS" ); - } - - - -#ifdef notdef - /* TemporalDomain */ - - /* TODO: figure out when a temporal domain is valid, for example only tiled rasters support time as a domain, plus we need a timeitem */ - if(msOWSLookupMetadata(&(layer->metadata), "CO", "timeposition") || msOWSLookupMetadata(&(layer->metadata), "CO", "timeperiod")) { - msIO_printf(" \n"); - - /* TimePosition (should support a value AUTO, then we could mine positions from the timeitem) */ - msOWSPrintEncodeMetadataList(stdout, &(layer->metadata), "CO", "timeposition", NULL, NULL, " %s\n", NULL); - - /* TODO: add TimePeriod (only one per layer) */ - - msIO_printf(" \n"); - } - - msIO_printf(" \n"); -#endif - - /* -------------------------------------------------------------------- */ - /* Range */ - /* -------------------------------------------------------------------- */ - { - xmlNodePtr psField, psInterpMethods, psAxis; - char *value; - - psField = - xmlNewChild( - xmlNewChild( psCD, NULL, BAD_CAST "Range", NULL ), - NULL, BAD_CAST "Field", NULL ); - - value = msOWSGetEncodeMetadata( &(layer->metadata), "CO", - "rangeset_label", NULL ); - if( value ) - xmlNewChild( psField, psOwsNs, BAD_CAST "Title", BAD_CAST value ); - msFree(value); - - /* ows:Abstract? TODO */ - - value = msOWSGetEncodeMetadata( &(layer->metadata), "CO", - "rangeset_name", "raster" ); - xmlNewChild( psField, NULL, BAD_CAST "Identifier", BAD_CAST value ); - msFree(value); - - xmlNewChild( - xmlNewChild( psField, NULL, BAD_CAST "Definition", NULL ), - psOwsNs, BAD_CAST "AnyValue", NULL ); - - /* NullValue */ - value = msOWSGetEncodeMetadata( &(layer->metadata), "CO", - "rangeset_nullvalue", NULL); - if( value ) - xmlNewChild( psField, NULL, BAD_CAST "NullValue", - BAD_CAST value ); - msFree(value); - - /* InterpolationMethods */ - psInterpMethods = - xmlNewChild( psField, NULL, BAD_CAST "InterpolationMethods", NULL ); - - xmlNewChild( psInterpMethods, NULL, BAD_CAST "InterpolationMethod", BAD_CAST "bilinear" ); - xmlNewChild( psInterpMethods, NULL, - BAD_CAST "Default", BAD_CAST "nearest neighbor" ); - - /* -------------------------------------------------------------------- */ - /* Bands axis. */ - /* -------------------------------------------------------------------- */ - { - xmlNodePtr psKeys; - int iBand; - - value = msOWSGetEncodeMetadata( &(layer->metadata), "CO", - "bands_name", "bands" ); - psAxis = xmlNewChild( psField, NULL, BAD_CAST "Axis", NULL ); - xmlNewProp( psAxis, BAD_CAST "identifier", BAD_CAST value ); - msFree(value); - - psKeys = xmlNewChild( psAxis, NULL, BAD_CAST - "AvailableKeys", NULL ); - - for( iBand = 0; iBand < cm.bandcount; iBand++ ) { - char szBandName[32]; - - snprintf( szBandName, sizeof(szBandName), "%d", iBand+1 ); - xmlNewChild( psKeys, NULL, BAD_CAST "Key", - BAD_CAST szBandName ); - } - } - } - - /* -------------------------------------------------------------------- */ - /* SupportedCRS */ - /* -------------------------------------------------------------------- */ - { - char *owned_value; - - if( (owned_value = - msOWSGetProjURN( &(layer->projection), &(layer->metadata), - "CO", MS_FALSE)) != NULL ) { - /* ok */ - } else if((owned_value = - msOWSGetProjURN( &(layer->map->projection), - &(layer->map->web.metadata), - "CO", MS_FALSE)) != NULL ) { - /* ok */ - } else - msDebug( "mapwcs.c: missing required information, no SRSs defined.\n"); - - if( owned_value != NULL && strlen(owned_value) > 0 ) - msLibXml2GenerateList( psCD, NULL, "SupportedCRS", - owned_value, ' ' ); - - msFree( owned_value ); - } - - /* -------------------------------------------------------------------- */ - /* SupportedFormats */ - /* -------------------------------------------------------------------- */ - { - char *format_list; - - format_list = msWCSGetFormatsList11( layer->map, layer ); - - if (strlen(format_list) > 0 ) - msLibXml2GenerateList( psCD, NULL, "SupportedFormat", - format_list, ',' ); - - msFree( format_list ); - } - msWCSFreeCoverageMetadata(&cm); - - return MS_SUCCESS; -} - -/************************************************************************/ -/* msWCSDescribeCoverage11() */ -/************************************************************************/ - -int msWCSDescribeCoverage11(mapObj *map, wcsParamsObj *params, owsRequestObj *ows_request) -{ - xmlDocPtr psDoc = NULL; /* document pointer */ - xmlNodePtr psRootNode; - xmlNsPtr psOwsNs; - char *schemaLocation = NULL; - char *xsi_schemaLocation = NULL; - - int i,j; - - /* -------------------------------------------------------------------- */ - /* We will actually get the coverages list as a single item in */ - /* a string list with that item having the comma delimited */ - /* coverage names. Split it up now, and assign back in place */ - /* of the old coverages list. */ - /* -------------------------------------------------------------------- */ - if( CSLCount(params->coverages) == 1 ) { - char **old_coverages = params->coverages; - params->coverages = CSLTokenizeStringComplex( old_coverages[0], ",", - FALSE, FALSE ); - CSLDestroy( old_coverages ); - } - - /* -------------------------------------------------------------------- */ - /* Validate that the requested coverages exist as named layers. */ - /* -------------------------------------------------------------------- */ - if(params->coverages) { /* use the list */ - for( j = 0; params->coverages[j]; j++ ) { - i = msGetLayerIndex(map, params->coverages[j]); - if ( (i == -1) || - (!msIntegerInArray(GET_LAYER(map, i)->index, ows_request->enabled_layers, ows_request->numlayers)) ) { - msSetError( MS_WCSERR, - "COVERAGE %s cannot be opened / does not exist", - "msWCSDescribeCoverage()", params->coverages[j]); - return msWCSException11(map, "CoverageNotDefined", "coverage", params->version); - } - } - } - - /* -------------------------------------------------------------------- */ - /* Create document. */ - /* -------------------------------------------------------------------- */ - psDoc = xmlNewDoc(BAD_CAST "1.0"); - - psRootNode = xmlNewNode(NULL, BAD_CAST "CoverageDescriptions"); - - xmlDocSetRootElement(psDoc, psRootNode); - - /* -------------------------------------------------------------------- */ - /* Name spaces */ - /* -------------------------------------------------------------------- */ - xmlSetNs(psRootNode, xmlNewNs(psRootNode, BAD_CAST "http://www.opengis.net/wcs/1.1", NULL)); - psOwsNs = xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_OWS_110_NAMESPACE_URI, BAD_CAST MS_OWSCOMMON_OWS_NAMESPACE_PREFIX); - xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_W3C_XLINK_NAMESPACE_URI, BAD_CAST MS_OWSCOMMON_W3C_XLINK_NAMESPACE_PREFIX); - xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_W3C_XSI_NAMESPACE_URI, BAD_CAST MS_OWSCOMMON_W3C_XSI_NAMESPACE_PREFIX); - xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_OGC_NAMESPACE_URI, BAD_CAST MS_OWSCOMMON_OGC_NAMESPACE_PREFIX ); - - schemaLocation = msEncodeHTMLEntities( msOWSGetSchemasLocation(map) ); - xsi_schemaLocation = msStrdup("http://www.opengis.net/wcs/1.1"); - xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, " "); - xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, schemaLocation); - xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, "/wcs/1.1/wcsDescribeCoverage.xsd "); - xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, MS_OWSCOMMON_OWS_110_NAMESPACE_URI); - xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, " "); - xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, schemaLocation); - xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, "/ows/1.1.0/owsAll.xsd"); - xmlNewNsProp(psRootNode, NULL, BAD_CAST "xsi:schemaLocation", BAD_CAST xsi_schemaLocation); - msFree(schemaLocation); - msFree(xsi_schemaLocation); - - /* -------------------------------------------------------------------- */ - /* Generate a CoverageDescription for each requested coverage. */ - /* -------------------------------------------------------------------- */ - - if(params->coverages) { /* use the list */ - for( j = 0; params->coverages[j]; j++ ) { - i = msGetLayerIndex(map, params->coverages[j]); - msWCSDescribeCoverage_CoverageDescription11((GET_LAYER(map, i)), - params, psRootNode, - psOwsNs ); - } - } else { /* return all layers */ - for(i=0; inumlayers; i++) { - - if (!msIntegerInArray(GET_LAYER(map, i)->index, ows_request->enabled_layers, ows_request->numlayers)) - continue; - - msWCSDescribeCoverage_CoverageDescription11((GET_LAYER(map, i)), - params, psRootNode, - psOwsNs ); - } - } - - /* -------------------------------------------------------------------- */ - /* Write out the document. */ - /* -------------------------------------------------------------------- */ - { - xmlChar *buffer = NULL; - int size = 0; - msIOContext *context = NULL; - - if( msIO_needBinaryStdout() == MS_FAILURE ) - return MS_FAILURE; - - msIO_setHeader("Content-Type","text/xml; charset=UTF-8"); - msIO_sendHeaders(); - - context = msIO_getHandler(stdout); - - xmlDocDumpFormatMemoryEnc(psDoc, &buffer, &size, "UTF-8", 1); - msIO_contextWrite(context, buffer, size); - xmlFree(buffer); - } - - /* -------------------------------------------------------------------- */ - /* Cleanup */ - /* -------------------------------------------------------------------- */ - xmlFreeDoc(psDoc); - xmlCleanupParser(); - - return MS_SUCCESS; -} - -#endif /* defined(USE_WCS_SVR) && defined(USE_LIBXML2) */ - -/************************************************************************/ -/* msWCSGetCoverageBands11() */ -/* */ -/* We expect input to be of the form: */ -/* RangeSubset=raster:interpolation[bands[1]]. */ -/* */ -/* RangeSet=raster:[bands[1,2]] */ -/* or */ -/* RangeSet=raster:bilinear */ -/* */ -/* This function tries to return a bandlist if found, and will */ -/* also push an INTERPOLATION keyword into the parameters list */ -/* if found in the RangeSubset. */ -/************************************************************************/ - -#if defined(USE_WCS_SVR) -int msWCSGetCoverageBands11( mapObj *map, cgiRequestObj *request, - wcsParamsObj *params, layerObj *lp, - char **p_bandlist ) - -{ - char *rangesubset, *field_id; - const char *axis_id; - int i; - - /* -------------------------------------------------------------------- */ - /* Fetch the RangeSubset from the parameters, skip building a */ - /* bands list if not found. */ - /* -------------------------------------------------------------------- */ - const char* value = msWCSGetRequestParameter(request, "RangeSubset"); - if( value == NULL ) - return MS_SUCCESS; - - rangesubset = msStrdup(value); - - /* -------------------------------------------------------------------- */ - /* What is the (rangeset_name)? */ - /* -------------------------------------------------------------------- */ - value = msOWSLookupMetadata( &(lp->metadata), "CO", "rangeset_name" ); - if( value == NULL ) - value = "raster"; - field_id = msStrdup(value); - - /* -------------------------------------------------------------------- */ - /* What is the (bands_name)? */ - /* -------------------------------------------------------------------- */ - axis_id = msOWSLookupMetadata( &(lp->metadata), "CO", "bands_name" ); - if( axis_id == NULL ) - axis_id = "bands"; - - /* -------------------------------------------------------------------- */ - /* Parse out the field identifier from the request and verify. */ - /* -------------------------------------------------------------------- */ - value = rangesubset + strlen(field_id); - - if( strcasecmp(rangesubset,field_id) == 0 ) { - free(rangesubset); - free(field_id); - return MS_SUCCESS; /* we only got field ... default options */ - } - - if( strlen(rangesubset) <= strlen(field_id)+1 - || strncasecmp(rangesubset,field_id,strlen(field_id)) != 0 - || (*value != '[' && *value != ':') ) { - msSetError( MS_WCSERR, - "RangeSubset field name malformed, expected '%s', got RangeSubset=%s", - "msWCSGetCoverageBands11()", - field_id, rangesubset ); - free(rangesubset); - free(field_id); - return msWCSException11(map, "NoApplicableCode", "mapserv", params->version); - } - - free( field_id ); - field_id = NULL; - - /* -------------------------------------------------------------------- */ - /* Parse out the interpolation, if found. */ - /* -------------------------------------------------------------------- */ - if( *value == ':' ) { - assert( params->interpolation == NULL ); - params->interpolation = msStrdup(value+1); - for( i = 0; params->interpolation[i] != '\0'; i++ ) { - if( params->interpolation[i] == '[' ) { - params->interpolation[i] = '\0'; - break; - } - } - - value += strlen(params->interpolation) + 1; - } - - /* -------------------------------------------------------------------- */ - /* Parse out the axis name, and verify. */ - /* -------------------------------------------------------------------- */ - if( *value != '[' ) { - free(rangesubset); - return MS_SUCCESS; - } - - value++; - - if( strlen(value) <= strlen(axis_id)+1 - || strncasecmp(value,axis_id,strlen(axis_id)) != 0 - || value[strlen(axis_id)] != '[' ) { - msSetError( MS_WCSERR, - "RangeSubset axis name malformed, expected '%s', got RangeSubset=%s", - "msWCSGetCoverageBands11()", - axis_id, rangesubset ); - free(rangesubset); - return msWCSException11(map, "NoApplicableCode", "mapserv", params->version); - } - - /* -------------------------------------------------------------------- */ - /* Parse the band list. Basically assuming the band list is */ - /* everything from here to a close ';'. */ - /* -------------------------------------------------------------------- */ - value += strlen(axis_id) + 1; - - *p_bandlist = msStrdup(value); - - for( i = 0; (*p_bandlist)[i] != '\0'; i++ ) { - if( (*p_bandlist)[i] == '[' ) { - (*p_bandlist)[i] = '\0'; - break; - } - } - free(rangesubset); - return MS_SUCCESS; -} -#endif - -/************************************************************************/ -/* msWCSReturnCoverage11() */ -/* */ -/* Return a render image as a coverage to the caller with WCS */ -/* 1.1 "mime" wrapping. */ -/************************************************************************/ - -#if defined(USE_WCS_SVR) -int msWCSReturnCoverage11( wcsParamsObj *params, mapObj *map, - imageObj *image ) -{ - int status, i; - char *filename = NULL; - char *base_dir = NULL; - const char *fo_filename; - - fo_filename = msGetOutputFormatOption( image->format, "FILENAME", NULL ); - - /* -------------------------------------------------------------------- */ - /* Fetch the driver we will be using and check if it supports */ - /* VSIL IO. */ - /* -------------------------------------------------------------------- */ - if( EQUALN(image->format->driver,"GDAL/",5) ) { - GDALDriverH hDriver; - const char *pszExtension = image->format->extension; - - msAcquireLock( TLOCK_GDAL ); - hDriver = GDALGetDriverByName( image->format->driver+5 ); - if( hDriver == NULL ) { - msReleaseLock( TLOCK_GDAL ); - msSetError( MS_MISCERR, - "Failed to find %s driver.", - "msWCSReturnCoverage11()", - image->format->driver+5 ); - return msWCSException11(map, "NoApplicableCode", "mapserv", - params->version); - } - - if( pszExtension == NULL ) - pszExtension = "img.tmp"; - - if( GDALGetMetadataItem( hDriver, GDAL_DCAP_VIRTUALIO, NULL ) - != NULL ) { - base_dir = msTmpFile(map, map->mappath, "/vsimem/wcsout", NULL); - if( fo_filename ) - filename = msStrdup(CPLFormFilename(base_dir, - fo_filename,NULL)); - else - filename = msStrdup(CPLFormFilename(base_dir, - "out", pszExtension )); - - /* CleanVSIDir( "/vsimem/wcsout" ); */ - - msReleaseLock( TLOCK_GDAL ); - status = msSaveImage(map, image, filename); - if( status != MS_SUCCESS ) { - msFree(filename); - msSetError(MS_MISCERR, "msSaveImage() failed", - "msWCSReturnCoverage11()"); - return msWCSException11(map, "NoApplicableCode", "mapserv", - params->version); - } - } - msReleaseLock( TLOCK_GDAL ); - } - - /* -------------------------------------------------------------------- */ - /* Output stock header. */ - /* -------------------------------------------------------------------- */ - msIO_setHeader("Content-Type","multipart/mixed; boundary=wcs"); - msIO_sendHeaders(); - msIO_printf( - "\r\n--wcs\r\n" - "Content-Type: text/xml; charset=UTF-8\r\n" - "Content-ID: wcs.xml\r\n\r\n" - "\n" - "\n" - " \n"); - - /* -------------------------------------------------------------------- */ - /* If we weren't able to write data under /vsimem, then we just */ - /* output a single "stock" filename. */ - /* -------------------------------------------------------------------- */ - if( filename == NULL ) { - msOutputFormatResolveFromImage( map, image ); - msIO_fprintf( - stdout, - " \n" - " \n" - "\n" - "\r\n--wcs\r\n" - "Content-Type: %s\r\n" - "Content-Description: coverage data\r\n" - "Content-Transfer-Encoding: binary\r\n" - "Content-ID: coverage/wcs.%s\r\n" - "Content-Disposition: INLINE\r\n\r\n", - MS_IMAGE_EXTENSION(map->outputformat), - MS_IMAGE_MIME_TYPE(map->outputformat), - MS_IMAGE_EXTENSION(map->outputformat)); - - status = msSaveImage(map, image, NULL); - if( status != MS_SUCCESS ) { - msSetError( MS_MISCERR, "msSaveImage() failed", "msWCSReturnCoverage11()"); - return msWCSException11(map, "NoApplicableCode", "mapserv", params->version); - } - - msIO_fprintf( stdout, "\r\n--wcs--\r\n" ); - return MS_SUCCESS; - } - - /* -------------------------------------------------------------------- */ - /* When potentially listing multiple files, we take great care */ - /* to identify the "primary" file and list it first. In fact */ - /* it is the only file listed in the coverages document. */ - /* -------------------------------------------------------------------- */ - { - char **all_files = CPLReadDir( base_dir ); - int count = CSLCount(all_files); - - if( msIO_needBinaryStdout() == MS_FAILURE ) - return MS_FAILURE; - - msAcquireLock( TLOCK_GDAL ); - for( i = count-1; i >= 0; i-- ) { - const char *this_file = all_files[i]; - - if( EQUAL(this_file,".") || EQUAL(this_file,"..") ) { - all_files = CSLRemoveStrings( all_files, i, 1, NULL ); - continue; - } - - if( i > 0 && EQUAL(this_file,CPLGetFilename(filename)) ) { - all_files = CSLRemoveStrings( all_files, i, 1, NULL ); - all_files = CSLInsertString(all_files,0,CPLGetFilename(filename)); - i++; - } - } - - msIO_fprintf( - stdout, - " \n" - " \n" - "\n", - CPLGetFilename(filename) ); - - /* -------------------------------------------------------------------- */ - /* Dump all the files in the memory directory as mime sections. */ - /* -------------------------------------------------------------------- */ - count = CSLCount(all_files); - - for( i = 0; i < count; i++ ) { - const char *mimetype = NULL; - FILE *fp; - unsigned char block[4000]; - int bytes_read; - - if( i == 0 ) - mimetype = MS_IMAGE_MIME_TYPE(map->outputformat); - - if( mimetype == NULL ) - mimetype = "application/octet-stream"; - - msIO_fprintf( - stdout, - "\r\n--wcs\r\n" - "Content-Type: %s\r\n" - "Content-Description: coverage data\r\n" - "Content-Transfer-Encoding: binary\r\n" - "Content-ID: coverage/%s\r\n" - "Content-Disposition: INLINE\r\n\r\n", - mimetype, - all_files[i]); - - fp = VSIFOpenL( - CPLFormFilename(base_dir, all_files[i], NULL), - "rb" ); - if( fp == NULL ) { - msReleaseLock( TLOCK_GDAL ); - msSetError( MS_MISCERR, - "Failed to open %s for streaming to stdout.", - "msWCSReturnCoverage11()", all_files[i] ); - return MS_FAILURE; - } - - while( (bytes_read = VSIFReadL(block, 1, sizeof(block), fp)) > 0 ) - msIO_fwrite( block, 1, bytes_read, stdout ); - - VSIFCloseL( fp ); - - VSIUnlink( CPLFormFilename(base_dir, all_files[i], NULL) ); - } - - msFree(base_dir); - msFree(filename); - CSLDestroy( all_files ); - msReleaseLock( TLOCK_GDAL ); - - msIO_fprintf( stdout, "\r\n--wcs--\r\n" ); - return MS_SUCCESS; - } -} -#endif /* defined(USE_WCS_SVR) && defined(USE_LIBXML2) */ - -/************************************************************************/ -/* ==================================================================== */ -/* If we don't have libxml2 but WCS SVR was selected, then */ -/* report WCS 1.1 requests as unsupported. */ -/* ==================================================================== */ -/************************************************************************/ - -#if defined(USE_WCS_SVR) && !defined(USE_LIBXML2) - -#include "mapwcs.h" - -/* ==================================================================== */ - -int msWCSDescribeCoverage11(mapObj *map, wcsParamsObj *params, - owsRequestObj *ows_request) -{ - msSetError( MS_WCSERR, - "WCS 1.1 request made, but mapserver requires libxml2 for WCS 1.1 services and this is not configured.", - "msWCSDescribeCoverage11()" ); - return msWCSException11(map, "NoApplicableCode", "mapserv", params->version); -} - -/* ==================================================================== */ - -int msWCSGetCapabilities11(mapObj *map, wcsParamsObj *params, - cgiRequestObj *req, owsRequestObj *ows_request) -{ - msSetError( MS_WCSERR, - "WCS 1.1 request made, but mapserver requires libxml2 for WCS 1.1 services and this is not configured.", - "msWCSGetCapabilities11()" ); - - return msWCSException11(map, "NoApplicableCode", "mapserv", params->version); -} - -int msWCSException11(mapObj *map, const char *exceptionCode, const char *locator, const char *version) -{ - /* fallback to reporting using 1.0 style exceptions. */ - return msWCSException( map, exceptionCode, locator, "1.0.0" ); -} - -#endif /* defined(USE_WCS_SVR) && !defined(USE_LIBXML2) */ diff --git a/mapwcs20.cpp b/mapwcs20.cpp deleted file mode 100644 index 9b8fe8ca9e..0000000000 --- a/mapwcs20.cpp +++ /dev/null @@ -1,5012 +0,0 @@ -/****************************************************************************** - * $Id$ - * - * Project: MapServer - * Purpose: OpenGIS Web Coverage Server (WCS) 2.0 implementation. - * Author: Stephan Meissl - * Fabian Schindler - * and the MapServer team. - * - ****************************************************************************** - * Copyright (c) 2010, 2011 EOX IT Services GmbH, Austria - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies of this Software or works derived from this Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - ****************************************************************************/ - -#include "mapserver-config.h" -#if defined(USE_WCS_SVR) - -#include -#include "mapserver.h" -#include "maperror.h" -#include "mapthread.h" -#include "mapows.h" -#include "mapwcs.h" -#include -#include "gdal.h" -#include "cpl_port.h" -#include "maptime.h" -#include "mapprimitive.h" -#include "cpl_string.h" -#include - -#if defined(USE_LIBXML2) - -#include -#include "maplibxml2.h" -#include - -#endif /* defined(USE_LIBXML2) */ - -#include - -/************************************************************************/ -/* msXMLStripIndentation */ -/************************************************************************/ - -static void msXMLStripIndentation(char* ptr) -{ - /* Remove spaces between > and < to get properly indented result */ - char* afterLastClosingBracket = NULL; - if( *ptr == ' ' ) - afterLastClosingBracket = ptr; - while( *ptr != '\0' ) - { - if( *ptr == '<' && afterLastClosingBracket != NULL ) - { - memmove(afterLastClosingBracket, ptr, strlen(ptr) + 1); - ptr = afterLastClosingBracket; - } - else if( *ptr == '>' ) - { - afterLastClosingBracket = ptr + 1; - } - else if( *ptr != ' ' && *ptr != '\n' ) - afterLastClosingBracket = NULL; - ptr ++; - } -} - - - -/************************************************************************/ -/* msStringParseInteger() */ -/* */ -/* Tries to parse a string as a integer value. If not possible */ -/* the value MS_WCS20_UNBOUNDED is stored as value. */ -/* If no characters could be parsed, MS_FAILURE is returned. If at */ -/* least some characters could be parsed, MS_DONE is returned and */ -/* only if all characters could be parsed, MS_SUCCESS is returned. */ -/************************************************************************/ - -static int msStringParseInteger(const char *string, int *dest) -{ - char *parse_check; - *dest = (int)strtol(string, &parse_check, 0); - if(parse_check == string) { - return MS_FAILURE; - } else if(parse_check - strlen(string) != string) { - return MS_DONE; - } - return MS_SUCCESS; -} - -/************************************************************************/ -/* msStringParseDouble() */ -/* */ -/* Tries to parse a string as a double value. If not possible */ -/* the value 0 is stored as value. */ -/* If no characters could be parsed, MS_FAILURE is returned. If at */ -/* least some characters could be parsed, MS_DONE is returned and */ -/* only if all characters could be parsed, MS_SUCCESS is returned. */ -/************************************************************************/ - -static int msStringParseDouble(const char *string, double *dest) -{ - char *parse_check = NULL; - *dest = strtod(string, &parse_check); - if(parse_check == string) { - return MS_FAILURE; - } else if(parse_check - strlen(string) != string) { - return MS_DONE; - } - return MS_SUCCESS; -} - -/************************************************************************/ -/* msWCSParseTimeOrScalar20() */ -/* */ -/* Parses a string, either as a time or a scalar value and */ -/* writes the output into the timeScalarUnion. */ -/************************************************************************/ - -static int msWCSParseTimeOrScalar20(timeScalarUnion *u, const char *string) -{ - struct tm time; - if (string) { - while(*string == ' ') - string ++; - } - - if (!string || strlen(string) == 0 || !u) { - msSetError(MS_WCSERR, "Invalid string", "msWCSParseTimeOrScalar20()"); - return MS_WCS20_ERROR_VALUE; - } - /* if the string is equal to "*" it means the value - * of the interval is unbounded */ - if (EQUAL(string, "*")) { - u->scalar = MS_WCS20_UNBOUNDED; - u->unbounded = 1; - return MS_WCS20_UNDEFINED_VALUE; - } - - /* if returned a valid value, use it */ - if (msStringParseDouble(string, &(u->scalar)) == MS_SUCCESS) { - return MS_WCS20_SCALAR_VALUE; - } - /* otherwise it might be a time value */ - msTimeInit(&time); - if (msParseTime(string, &time) == MS_TRUE) { - u->time = mktime(&time); - return MS_WCS20_TIME_VALUE; - } - /* the value could neither be parsed as a double nor as a time value */ - else { - msSetError(MS_WCSERR, - "String %s could not be parsed to a time or scalar value", - "msWCSParseTimeOrScalar20()",string); - return MS_WCS20_ERROR_VALUE; - } -} - -/************************************************************************/ -/* msWCSCreateSubsetObj20() */ -/* */ -/* Creates a new wcs20SubsetObj and initializes it to standard */ -/* values. */ -/************************************************************************/ - -static wcs20SubsetObjPtr msWCSCreateSubsetObj20() -{ - wcs20SubsetObjPtr subset = (wcs20SubsetObjPtr) malloc(sizeof(wcs20SubsetObj)); - MS_CHECK_ALLOC(subset, sizeof(wcs20SubsetObj), NULL); - - subset->axis = NULL; - subset->crs = NULL; - subset->min.scalar = subset->max.scalar = MS_WCS20_UNBOUNDED; - subset->min.unbounded = subset->max.unbounded = 0; - subset->operation = MS_WCS20_SLICE; - - return subset; -} - -/************************************************************************/ -/* msWCSFreeSubsetObj20() */ -/* */ -/* Frees a wcs20SubsetObj and releases all linked resources. */ -/************************************************************************/ - -static void msWCSFreeSubsetObj20(wcs20SubsetObjPtr subset) -{ - if (NULL == subset) { - return; - } - msFree(subset->axis); - msFree(subset->crs); - msFree(subset); -} - -/************************************************************************/ -/* msWCSCreateAxisObj20() */ -/* */ -/* Creates a new wcs20AxisObj and initializes it to standard */ -/* values. */ -/************************************************************************/ - -static wcs20AxisObjPtr msWCSCreateAxisObj20() -{ - wcs20AxisObj *axis = (wcs20AxisObjPtr)malloc(sizeof(wcs20AxisObj)); - MS_CHECK_ALLOC(axis, sizeof(wcs20AxisObj), NULL); - - axis->name = NULL; - axis->size = 0; - axis->resolution = MS_WCS20_UNBOUNDED; - axis->scale = MS_WCS20_UNBOUNDED; - axis->resolutionUOM = NULL; - axis->subset = NULL; - - return axis; -} - -/************************************************************************/ -/* msWCSFreeAxisObj20() */ -/* */ -/* Frees a wcs20AxisObj and releases all linked resources. */ -/************************************************************************/ - -static void msWCSFreeAxisObj20(wcs20AxisObjPtr axis) -{ - if(NULL == axis) { - return; - } - - msFree(axis->name); - msFree(axis->resolutionUOM); - msWCSFreeSubsetObj20(axis->subset); - msFree(axis); -} - -/************************************************************************/ -/* msWCSFindAxis20() */ -/* */ -/* Helper function to retrieve an axis by the name from a params */ -/* object. */ -/************************************************************************/ - -static wcs20AxisObjPtr msWCSFindAxis20(wcs20ParamsObjPtr params, - const char *name) -{ - int i = 0; - for(i = 0; i < params->numaxes; ++i) { - if(EQUAL(params->axes[i]->name, name)) { - return params->axes[i]; - } - } - return NULL; -} - -/************************************************************************/ -/* msWCSInsertAxisObj20() */ -/* */ -/* Helper function to insert an axis object into the axes list of */ -/* a params object. */ -/************************************************************************/ - -static void msWCSInsertAxisObj20(wcs20ParamsObjPtr params, wcs20AxisObjPtr axis) -{ - params->numaxes++; - params->axes = (wcs20AxisObjPtr*) msSmallRealloc(params->axes, - sizeof(wcs20AxisObjPtr) * (params->numaxes)); - params->axes[params->numaxes - 1] = axis; -} - -/************************************************************************/ -/* msWCSCreateParamsObj20() */ -/* */ -/* Creates a new wcs20ParamsObj and initializes it to standard */ -/* values. */ -/************************************************************************/ - -wcs20ParamsObjPtr msWCSCreateParamsObj20() -{ - wcs20ParamsObjPtr params - = (wcs20ParamsObjPtr) malloc(sizeof(wcs20ParamsObj)); - MS_CHECK_ALLOC(params, sizeof(wcs20ParamsObj), NULL); - - params->version = NULL; - params->request = NULL; - params->service = NULL; - params->accept_versions = NULL; - params->accept_languages = NULL; - params->sections = NULL; - params->updatesequence = NULL; - params->ids = NULL; - params->width = 0; - params->height = 0; - params->resolutionX = MS_WCS20_UNBOUNDED; - params->resolutionY = MS_WCS20_UNBOUNDED; - params->scale = MS_WCS20_UNBOUNDED; - params->scaleX = MS_WCS20_UNBOUNDED; - params->scaleY = MS_WCS20_UNBOUNDED; - params->resolutionUnits = NULL; - params->numaxes = 0; - params->axes = NULL; - params->format = NULL; - params->multipart = 0; - params->interpolation = NULL; - params->outputcrs = NULL; - params->subsetcrs = NULL; - params->bbox.minx = params->bbox.miny = -DBL_MAX; - params->bbox.maxx = params->bbox.maxy = DBL_MAX; - params->range_subset = NULL; - params->format_options = NULL; - - return params; -} - -/************************************************************************/ -/* msWCSFreeParamsObj20() */ -/* */ -/* Frees a wcs20ParamsObj and releases all linked resources. */ -/************************************************************************/ - -void msWCSFreeParamsObj20(wcs20ParamsObjPtr params) -{ - if (NULL == params) { - return; - } - - msFree(params->version); - msFree(params->request); - msFree(params->service); - CSLDestroy(params->accept_versions); - CSLDestroy(params->accept_languages); - CSLDestroy(params->sections); - msFree(params->updatesequence); - CSLDestroy(params->ids); - msFree(params->resolutionUnits); - msFree(params->format); - msFree(params->interpolation); - msFree(params->outputcrs); - msFree(params->subsetcrs); - while(params->numaxes > 0) { - params->numaxes -= 1; - msWCSFreeAxisObj20(params->axes[params->numaxes]); - } - msFree(params->axes); - CSLDestroy(params->range_subset); - CSLDestroy(params->format_options); - msFree(params); -} - -/************************************************************************/ -/* msWCSParseSubset20() */ -/* */ -/* Parses several string parameters and fills them into the */ -/* subset object. */ -/************************************************************************/ - -static int msWCSParseSubset20(wcs20SubsetObjPtr subset, const char *axis, - const char *crs, const char *min, const char *max) -{ - int ts1, ts2; - ts1 = ts2 = MS_WCS20_UNDEFINED_VALUE; - - if (subset == NULL) { - return MS_FAILURE; - } - - if (axis == NULL || strlen(axis) == 0) { - msSetError(MS_WCSERR, "Subset axis is not given.", - "msWCSParseSubset20()"); - return MS_FAILURE; - } - - subset->axis = msStrdup(axis); - if (crs != NULL) { - subset->crs = msStrdup(crs); - } - - /* Parse first (probably only) part of interval/point; - * check whether its a time value or a scalar value */ - ts1 = msWCSParseTimeOrScalar20(&(subset->min), min); - if (ts1 == MS_WCS20_ERROR_VALUE) { - return MS_FAILURE; - } - - /* check if its an interval */ - /* if there is a comma, then it is */ - if (max != NULL && strlen(max) > 0) { - subset->operation = MS_WCS20_TRIM; - - /* Parse the second value of the interval */ - ts2 = msWCSParseTimeOrScalar20(&(subset->max), max); - if (ts2 == MS_WCS20_ERROR_VALUE) { - return MS_FAILURE; - } - - /* if at least one boundary is defined, use that value */ - if ((ts1 == MS_WCS20_UNDEFINED_VALUE) ^ (ts2 - == MS_WCS20_UNDEFINED_VALUE)) { - if (ts1 == MS_WCS20_UNDEFINED_VALUE) { - ts1 = ts2; - } - } - /* if time and scalar values do not fit, throw an error */ - else if (ts1 != MS_WCS20_UNDEFINED_VALUE && ts2 - != MS_WCS20_UNDEFINED_VALUE && ts1 != ts2) { - msSetError(MS_WCSERR, - "Interval error: minimum is a %s value, maximum is a %s value", - "msWCSParseSubset20()", ts1 ? "time" : "scalar", - ts2 ? "time" : "scalar"); - return MS_FAILURE; - } - /* if both min and max are unbounded -> throw an error */ - if (subset->min.unbounded && subset->max.unbounded) { - msSetError(MS_WCSERR, "Invalid values: no bounds could be parsed", - "msWCSParseSubset20()"); - return MS_FAILURE; - } - } - /* there is no second value, therefore it is a point. - * consequently set the operation to slice */ - else { - subset->operation = MS_WCS20_SLICE; - if (ts1 == MS_WCS20_UNDEFINED_VALUE) { - msSetError(MS_WCSERR, "Invalid point value given", - "msWCSParseSubset20()"); - return MS_FAILURE; - } - } - - subset->timeOrScalar = ts1; - - /* check whether the min is smaller than the max */ - if (subset->operation == MS_WCS20_TRIM) { - if(subset->timeOrScalar == MS_WCS20_SCALAR_VALUE && subset->min.scalar == MS_WCS20_UNBOUNDED) { - subset->min.scalar = -MS_WCS20_UNBOUNDED; - } - - if (subset->timeOrScalar == MS_WCS20_TIME_VALUE && subset->min.time - > subset->max.time) { - msSetError(MS_WCSERR, - "Minimum value of subset axis %s is larger than maximum value", - "msWCSParseSubset20()", subset->axis); - return MS_FAILURE; - } - if (subset->timeOrScalar == MS_WCS20_SCALAR_VALUE && subset->min.scalar > subset->max.scalar) { - msSetError(MS_WCSERR, - "Minimum value (%f) of subset axis '%s' is larger than maximum value (%f).", - "msWCSParseSubset20()", subset->min.scalar, subset->axis, subset->max.scalar); - return MS_FAILURE; - } - } - return MS_SUCCESS; -} - -/************************************************************************/ -/* msWCSParseSubsetKVPString20() */ -/* */ -/* Creates a new wcs20SubsetObj, parses a string and fills */ -/* the parsed values into the object. Returns NULL on failure. */ -/* Subset string: axis [ , crs ] ( intervalOrPoint ) */ -/************************************************************************/ - -static int msWCSParseSubsetKVPString20(wcs20SubsetObjPtr subset, char *string) -{ - char *axis, *crs, *min, *max; - - axis = string; - crs = NULL; - min = NULL; - max = NULL; - - /* find first '(' */ - min = strchr(string, '('); - - /* if min could not be found, the string is invalid */ - if (min == NULL) { - msSetError(MS_WCSERR, "Invalid axis subset string: '%s'", - "msWCSParseSubsetKVPString20()", string); - return MS_FAILURE; - } - /* set min to first letter */ - *min = '\0'; - ++min; - - /* cut the trailing ')' */ - if (min[strlen(min) - 1] == ')') { - min[strlen(min) - 1] = '\0'; - } - /* look if also a max is defined */ - max = strchr(min, ','); - if (max != NULL) { - *max = '\0'; - ++max; - } - - /* look if also a crs is defined */ - crs = strchr(axis, ','); - if (crs != NULL) { - *crs = '\0'; - ++crs; - } - - return msWCSParseSubset20(subset, axis, crs, min, max); -} - -/************************************************************************/ -/* msWCSParseSizeString20() */ -/* */ -/* Parses a string containing the axis and the size as an integer. */ -/* Size string: axis ( size ) */ -/************************************************************************/ - -static int msWCSParseSizeString20(char *string, char *outAxis, size_t axisStringLen, int *outSize) -{ - char *number = NULL; - char *check = NULL; - - /* find first '(', the character before the number */ - number = strchr(string, '('); - - if(NULL == number) { - msSetError(MS_WCSERR, "Invalid size parameter value.", - "msWCSParseSize20()"); - return MS_FAILURE; - } - - /* cut trailing ')' */ - check = strchr(string, ')'); - if(NULL == check) { - msSetError(MS_WCSERR, "Invalid size parameter value.", - "msWCSParseSize20()"); - return MS_FAILURE; - } - *number = '\0'; - ++number; - *check = '\0'; - - strlcpy(outAxis, string, axisStringLen); - - /* parse size value */ - if(msStringParseInteger(number, outSize) != MS_SUCCESS) { - msSetError(MS_WCSERR, "Parameter value '%s' is not a valid integer.", - "msWCSParseSize20()", number); - return MS_FAILURE; - } - - return MS_SUCCESS; -} - -/************************************************************************/ -/* msWCSParseResolutionString20() */ -/* */ -/* Parses a resolution string and returns the axis, the units of */ -/* measure and the resolution value. */ -/* Subset string: axis ( value ) */ -/************************************************************************/ - -static int msWCSParseResolutionString20(char *string, - char *outAxis, size_t axisStringLen, double *outResolution) -{ - char *number = NULL; - char *check = NULL; - - /* find brackets */ - number = strchr(string, '('); - - if(NULL == number) { - msSetError(MS_WCSERR, "Invalid resolution parameter value : %s.", - "msWCSParseSize20()", string); - return MS_FAILURE; - } - - /* cut trailing ')' */ - check = strchr(string, ')'); - if(NULL == check) { - msSetError(MS_WCSERR, "Invalid size parameter value.", - "msWCSParseSize20()"); - return MS_FAILURE; - } - - *number = '\0'; - ++number; - *check = '\0'; - - strlcpy(outAxis, string, axisStringLen); - - if(msStringParseDouble(number, outResolution) != MS_SUCCESS) { - *outResolution = MS_WCS20_UNBOUNDED; - msSetError(MS_WCSERR, "Invalid resolution parameter value : %s.", - "msWCSParseSize20()", number); - return MS_FAILURE; - } - - return MS_SUCCESS; -} - -/************************************************************************/ -/* msWCSParseScaleString20() */ -/* */ -/* Parses a scale string and returns the axis, the and the value. */ -/* Subset string: axis ( value ) */ -/************************************************************************/ - -static int msWCSParseScaleString20(char *string, - char *outAxis, size_t axisStringLen, double *outScale) -{ - char *number = NULL; - char *check = NULL; - - /* find brackets */ - number = strchr(string, '('); - - if(NULL == number) { - msSetError(MS_WCSERR, "Invalid resolution parameter value : %s.", - "msWCSParseScaleString20()", string); - return MS_FAILURE; - } - - /* cut trailing ')' */ - check = strchr(string, ')'); - if(NULL == check || check < number) { - msSetError(MS_WCSERR, "Invalid scale parameter value.", - "msWCSParseScaleString20()"); - return MS_FAILURE; - } - - *number = '\0'; - ++number; - *check = '\0'; - - strlcpy(outAxis, string, axisStringLen); - - if(msStringParseDouble(number, outScale) != MS_SUCCESS || *outScale <= 0.0) { - *outScale = MS_WCS20_UNBOUNDED; - msSetError(MS_WCSERR, "Invalid scale parameter value : %s.", - "msWCSParseScaleString20()", number); - return MS_FAILURE; - } - - return MS_SUCCESS; -} - -/************************************************************************/ -/* msWCSParseResolutionString20() */ -/* */ -/* Parses a resolution string and returns the axis, the units of */ -/* measure and the resolution value. */ -/* Subset string: axis ( value ) */ -/************************************************************************/ - -static int msWCSParseScaleExtentString20(char *string, char *outAxis, - size_t axisStringLen, - int *outMin, int *outMax) -{ - char *number = NULL; - char *check = NULL; - char *colon = NULL; - - /* find brackets */ - number = strchr(string, '('); - - if(NULL == number) { - msSetError(MS_WCSERR, "Invalid extent parameter value : %s.", - "msWCSParseScaleExtentString20()", string); - return MS_FAILURE; - } - - /* find colon */ - colon = strchr(string, ':'); - - if(NULL == colon || colon < number) { - msSetError(MS_WCSERR, "Invalid extent parameter value : %s.", - "msWCSParseScaleExtentString20()", string); - return MS_FAILURE; - } - - /* cut trailing ')' */ - check = strchr(string, ')'); - - if(NULL == check || check < colon) { - msSetError(MS_WCSERR, "Invalid extent parameter value.", - "msWCSParseScaleExtentString20()"); - return MS_FAILURE; - } - - *number = '\0'; - ++number; - *colon = '\0'; - ++colon; - *check = '\0'; - - strlcpy(outAxis, string, axisStringLen); - - if(msStringParseInteger(number, outMin) != MS_SUCCESS) { - *outMin = 0; - msSetError(MS_WCSERR, "Invalid min parameter value : %s.", - "msWCSParseScaleExtentString20()", number); - return MS_FAILURE; - } - else if(msStringParseInteger(colon, outMax) != MS_SUCCESS) { - *outMax = 0; - msSetError(MS_WCSERR, "Invalid resolution parameter value : %s.", - "msWCSParseScaleExtentString20()", colon); - return MS_FAILURE; - } - - if (*outMin > *outMax) { - msSetError(MS_WCSERR, "Invalid extent: lower part is higher than upper part.", - "msWCSParseScaleExtentString20()"); - return MS_FAILURE; - } - - return MS_SUCCESS; -} - -#if defined(USE_LIBXML2) -/* - Utility function to get the first child of a node with a given node name - */ - -xmlNodePtr msLibXml2GetFirstChild(xmlNodePtr parent, const char *name) { - xmlNodePtr node; - if (!parent || !name) { - return NULL; - } - - XML_FOREACH_CHILD(parent, node) { - XML_LOOP_IGNORE_COMMENT_OR_TEXT(node); - if (EQUAL((char *)node->name, name)) { - return node; - } - } - return NULL; -} - - -/* - Utility function to get the first child of a node with a given node name and - namespace. - */ - -xmlNodePtr msLibXml2GetFirstChildNs(xmlNodePtr parent, const char *name, xmlNsPtr ns) { - xmlNodePtr node; - if (!parent || !name || !ns) { - return NULL; - } - - XML_FOREACH_CHILD(parent, node) { - XML_LOOP_IGNORE_COMMENT_OR_TEXT(node); - if (EQUAL((char *)node->name, name) && ns == node->ns) { - return node; - } - } - return NULL; -} - -/* - Utility function to get the first child of a node with a given node name - */ - -xmlNodePtr msLibXml2GetFirstChildElement(xmlNodePtr parent) { - xmlNodePtr node; - if (!parent) { - return NULL; - } - - XML_FOREACH_CHILD(parent, node) { - if (node->type == XML_ELEMENT_NODE) { - return node; - } - } - return NULL; -} -#endif /* defined(USE_LIBXML2) */ - -/************************************************************************/ -/* msWCSParseRequest20_XMLGetCapabilities() */ -/* */ -/* Parses a DOM element, representing a GetCapabilities-request */ -/* to a params object. */ -/************************************************************************/ -#if defined(USE_LIBXML2) -static int msWCSParseRequest20_XMLGetCapabilities( - xmlNodePtr root, wcs20ParamsObjPtr params) -{ - xmlNodePtr child; - char *content = NULL; - XML_FOREACH_CHILD(root, child) { - XML_LOOP_IGNORE_COMMENT_OR_TEXT(child) - else if (EQUAL((char *)child->name, "AcceptVersions")) { - xmlNodePtr versionNode = NULL; - XML_FOREACH_CHILD(child, versionNode) { - XML_LOOP_IGNORE_COMMENT_OR_TEXT(versionNode); - XML_ASSERT_NODE_NAME(versionNode, "Version"); - - content = (char *)xmlNodeGetContent(versionNode); - params->accept_versions = CSLAddString(params->accept_versions, content); - xmlFree(content); - } - } else if(EQUAL((char *)child->name, "Sections")) { - xmlNodePtr sectionNode = NULL; - XML_FOREACH_CHILD(child, sectionNode) { - XML_LOOP_IGNORE_COMMENT_OR_TEXT(sectionNode) - XML_ASSERT_NODE_NAME(sectionNode, "Section"); - - content = (char *)xmlNodeGetContent(sectionNode); - params->sections = CSLAddString(params->sections, content); - xmlFree(content); - } - } else if(EQUAL((char *)child->name, "UpdateSequence")) { - params->updatesequence = - (char *)xmlNodeGetContent(child); - } else if(EQUAL((char *)child->name, "AcceptFormats")) { - /* Maybe not necessary, since only format is xml. */ - /* At least ignore it, to not generate an error. */ - } else if(EQUAL((char *)child->name, "AcceptLanguages")) { - xmlNodePtr languageNode; - XML_FOREACH_CHILD(child, languageNode) { - XML_LOOP_IGNORE_COMMENT_OR_TEXT(languageNode) - XML_ASSERT_NODE_NAME(languageNode, "Language"); - - content = (char *)xmlNodeGetContent(languageNode); - params->accept_languages = CSLAddString(params->accept_languages, content); - xmlFree(content); - } - } else { - XML_UNKNOWN_NODE_ERROR(child); - } - } - return MS_SUCCESS; -} -#endif - -/************************************************************************/ -/* msWCSParseRequest20_XMLDescribeCoverage() */ -/* */ -/* Parses a DOM element, representing a DescribeCoverage-request */ -/* to a params object. */ -/************************************************************************/ -#if defined(USE_LIBXML2) -static int msWCSParseRequest20_XMLDescribeCoverage( - xmlNodePtr root, wcs20ParamsObjPtr params) -{ - xmlNodePtr child; - int numIds = 0; - char *id; - - XML_FOREACH_CHILD(root, child) { - XML_LOOP_IGNORE_COMMENT_OR_TEXT(child) - XML_ASSERT_NODE_NAME(child, "CoverageID"); - - /* Node content is the coverage ID */ - id = (char *)xmlNodeGetContent(child); - if (id == NULL || strlen(id) == 0) { - msSetError(MS_WCSERR, "CoverageID could not be parsed.", - "msWCSParseRequest20_XMLDescribeCoverage()"); - return MS_FAILURE; - } - /* insert coverage ID into the list */ - ++numIds; - params->ids = CSLAddString(params->ids, (char *)id); - xmlFree(id); - } - return MS_SUCCESS; -} -#endif - -/************************************************************************/ -/* msWCSParseRequest20_XMLGetCoverage() */ -/* */ -/* Parses a DOM element, representing a GetCoverage-request to a */ -/* params object. */ -/************************************************************************/ -#if defined(USE_LIBXML2) -static int msWCSParseRequest20_XMLGetCoverage( - mapObj* map, xmlNodePtr root, wcs20ParamsObjPtr params) -{ - xmlNodePtr child; - int numIds = 0; - char *id; - - XML_FOREACH_CHILD(root, child) { - XML_LOOP_IGNORE_COMMENT_OR_TEXT(child) - else if (EQUAL((char *)child->name, "CoverageID")) { - /* Node content is the coverage ID */ - id = (char *)xmlNodeGetContent(child); - if (id == NULL || strlen(id) == 0) { - msSetError(MS_WCSERR, "CoverageID could not be parsed.", - "msWCSParseRequest20_XMLGetCoverage()"); - return MS_FAILURE; - } - - /* insert coverage ID into the list */ - ++numIds; - params->ids = CSLAddString(params->ids, (char *)id); - xmlFree(id); - } else if (EQUAL((char *) child->name, "Format")) { - msFree(params->format); - params->format = (char *)xmlNodeGetContent(child); - } else if (EQUAL((char *) child->name, "Mediatype")) { - char *content = (char *)xmlNodeGetContent(child); - if(content != NULL && (EQUAL(content, "multipart/mixed") - || EQUAL(content, "multipart/related"))) { - params->multipart = MS_TRUE; - } - else { - msSetError(MS_WCSERR, "Invalid value '%s' for parameter 'Mediatype'.", - "msWCSParseRequest20()", content); - xmlFree(content); - return MS_FAILURE; - } - xmlFree(content); - } else if (EQUAL((char *) child->name, "DimensionTrim")) { - wcs20AxisObjPtr axis = NULL; - wcs20SubsetObjPtr subset = NULL; - xmlNodePtr node = NULL; - char *axisName = NULL, *min = NULL, *max = NULL, *crs = NULL; - - /* get strings for axis, min and max */ - XML_FOREACH_CHILD(child, node) { - XML_LOOP_IGNORE_COMMENT_OR_TEXT(node) - else if (EQUAL((char *)node->name, "Dimension")) { - if (axisName != NULL) { - msSetError(MS_WCSERR, - "Parameter 'Dimension' is already set.", - "msWCSParseRequest20_XMLGetCoverage()"); - return MS_FAILURE; - } - axisName = (char *) xmlNodeGetContent(node); - crs = (char *) xmlGetProp(node, BAD_CAST "crs"); - } else if (EQUAL((char *)node->name, "trimLow")) { - min = (char *) xmlNodeGetContent(node); - } else if (EQUAL((char *)node->name, "trimHigh")) { - max = (char *) xmlNodeGetContent(node); - } else { - msFree(axisName); - msFree(min); - msFree(max); - msFree(crs); - XML_UNKNOWN_NODE_ERROR(node); - } - } - if(NULL == (subset = msWCSCreateSubsetObj20())) { - msFree(axisName); - msFree(min); - msFree(max); - msFree(crs); - return MS_FAILURE; - } - - /* min and max have to have a value */ - if(min == NULL ) { - min = msStrdup("*"); - } - if(max == NULL) { - max = msStrdup("*"); - } - if (msWCSParseSubset20(subset, axisName, crs, min, max) - == MS_FAILURE) { - msWCSFreeSubsetObj20(subset); - msWCSException(map, "InvalidSubsetting", "subset", "2.0.1"); - return MS_DONE; - } - - if(NULL == (axis = msWCSFindAxis20(params, subset->axis))) { - if(NULL == (axis = msWCSCreateAxisObj20())) { - msFree(axisName); - msFree(min); - msFree(max); - msFree(crs); - return MS_FAILURE; - } - axis->name = msStrdup(subset->axis); - msWCSInsertAxisObj20(params, axis); - } - - axis->subset = subset; - - /* cleanup */ - msFree(axisName); - msFree(min); - msFree(max); - msFree(crs); - } else if(EQUAL((char *) child->name, "DimensionSlice")) { - msSetError(MS_WCSERR, "Operation '%s' is not supported by MapServer.", - "msWCSParseRequest20_XMLGetCoverage()", (char *)child->name); - return MS_FAILURE; - } else if(EQUAL((char *) child->name, "Size")) { - wcs20AxisObjPtr axis; - char *axisName; - char *content; - - if(NULL == (axisName = (char *) xmlGetProp(child, BAD_CAST "dimension")) ) { - msSetError(MS_WCSERR, "Attribute 'dimension' is missing in element 'Size'.", - "msWCSParseRequest20_XMLGetCoverage()"); - return MS_FAILURE; - } - - if(NULL == (axis = msWCSFindAxis20(params, axisName))) { - if(NULL == (axis = msWCSCreateAxisObj20())) { - xmlFree(axisName); - return MS_FAILURE; - } - axis->name = msStrdup(axisName); - msWCSInsertAxisObj20(params, axis); - } - xmlFree(axisName); - - content = (char *)xmlNodeGetContent(child); - if(msStringParseInteger(content, &(axis->size)) != MS_SUCCESS) { - xmlFree(content); - msSetError(MS_WCSERR, "Value of element 'Size' could not " - "be parsed to a valid integer.", - "msWCSParseRequest20_XMLGetCoverage()"); - return MS_FAILURE; - } - xmlFree(content); - } else if(EQUAL((char *) child->name, "Resolution")) { - wcs20AxisObjPtr axis; - char *axisName; - char *content; - - if(NULL == (axisName = (char *) xmlGetProp(child, BAD_CAST "dimension"))) { - msSetError(MS_WCSERR, "Attribute 'dimension' is missing " - "in element 'Resolution'.", - "msWCSParseRequest20_XMLGetCoverage()"); - return MS_FAILURE; - } - - if(NULL == (axis = msWCSFindAxis20(params, axisName))) { - if(NULL == (axis = msWCSCreateAxisObj20())) { - xmlFree(axisName); - return MS_FAILURE; - } - axis->name = msStrdup(axisName); - msWCSInsertAxisObj20(params, axis); - } - xmlFree(axisName); - - axis->resolutionUOM = (char *) xmlGetProp(child, BAD_CAST "uom"); - - content = (char *)xmlNodeGetContent(child); - if(msStringParseDouble(content, &(axis->resolution)) != MS_SUCCESS) { - msSetError(MS_WCSERR, "Value of element 'Resolution' could not " - "be parsed to a valid value.", - "msWCSParseRequest20_XMLGetCoverage()"); - xmlFree(content); - return MS_FAILURE; - } - xmlFree(content); - } else if(EQUAL((char *) child->name, "Interpolation")) { - /* Deprecated, use wcs:Extension/int:Interpolation/int:globalInterpolation */ - msFree(params->interpolation); - params->interpolation = (char *) xmlNodeGetContent(child); - } else if(EQUAL((char *) child->name, "OutputCRS")) { - params->outputcrs = (char *) xmlNodeGetContent(child); - } else if(EQUAL((char *) child->name, "rangeSubset")) { - /* Deprecated, use wcs:Extension/rsub:RangeSubset */ - xmlNodePtr bandNode = NULL; - XML_FOREACH_CHILD(child, bandNode) { - char *content = NULL; - XML_LOOP_IGNORE_COMMENT_OR_TEXT(bandNode); - XML_ASSERT_NODE_NAME(bandNode, "band"); - - content = (char *)xmlNodeGetContent(bandNode); - params->range_subset = - CSLAddString(params->range_subset, content); - xmlFree(content); - } - } else if (EQUAL((char *)child->name, "Extension")) { - xmlNodePtr extensionNode = NULL; - XML_FOREACH_CHILD(child, extensionNode) { - XML_LOOP_IGNORE_COMMENT_OR_TEXT(extensionNode); - - if (EQUAL((char *) extensionNode->name, "Scaling")) { - xmlNodePtr scaleMethodNode = msLibXml2GetFirstChildElement(extensionNode); - - if (EQUAL((char *) scaleMethodNode->name, "ScaleByFactor")) { - xmlNodePtr scaleFactorNode = msLibXml2GetFirstChildElement(scaleMethodNode); - char *content; - if (!scaleFactorNode || !EQUAL((char *)scaleFactorNode->name, "scaleFactor")) { - msSetError(MS_WCSERR, "Missing 'scaleFactor' node.", - "msWCSParseRequest20_XMLGetCoverage()"); - return MS_FAILURE; - } - content = (char *)xmlNodeGetContent(scaleFactorNode); - if (msStringParseDouble(content, &(params->scale)) != MS_SUCCESS - || params->scale < 0.0) { - msSetError(MS_WCSERR, "Invalid scaleFactor '%s'.", - "msWCSParseRequest20_XMLGetCoverage()", content); - xmlFree(content); - return MS_FAILURE; - } - xmlFree(content); - } - - else if (EQUAL((char *) scaleMethodNode->name, "ScaleAxesByFactor")) { - xmlNodePtr scaleAxisNode, axisNode, scaleFactorNode; - char *axisName, *content; - wcs20AxisObjPtr axis; - - XML_FOREACH_CHILD(scaleMethodNode, scaleAxisNode) { - XML_LOOP_IGNORE_COMMENT_OR_TEXT(scaleAxisNode); - - if (!EQUAL((char *)scaleAxisNode->name, "ScaleAxis")) { - msSetError(MS_WCSERR, "Invalid ScaleAxesByFactor.", - "msWCSParseRequest20_XMLGetCoverage()"); - return MS_FAILURE; - } - - /* axis */ - if (NULL == (axisNode = msLibXml2GetFirstChild(scaleAxisNode, "axis"))) { - msSetError(MS_WCSERR, "Missing axis node", - "msWCSParseRequest20_XMLGetCoverage()"); - return MS_FAILURE; - } - axisName = (char *)xmlNodeGetContent(axisNode); - if(NULL == (axis = msWCSFindAxis20(params, axisName))) { - if(NULL == (axis = msWCSCreateAxisObj20())) { - xmlFree(axisName); - return MS_FAILURE; - } - axis->name = msStrdup(axisName); - msWCSInsertAxisObj20(params, axis); - } - xmlFree(axisName); - - if (axis->scale != MS_WCS20_UNBOUNDED) { - msSetError(MS_WCSERR, "scaleFactor was already set for axis '%s'.", - "msWCSParseRequest20_XMLGetCoverage()", axis->name); - return MS_FAILURE; - } - - /* scaleFactor */ - if (NULL == (scaleFactorNode = msLibXml2GetFirstChild(scaleAxisNode, "scaleFactor"))) { - msSetError(MS_WCSERR, "Missing scaleFactor node", - "msWCSParseRequest20_XMLGetCoverage()"); - return MS_FAILURE; - } - - content = (char *)xmlNodeGetContent(scaleFactorNode); - if (msStringParseDouble(content, &(axis->scale)) != MS_SUCCESS - || axis->scale < 0.0) { - msSetError(MS_WCSERR, "Invalid scaleFactor '%s'.", - "msWCSParseRequest20_XMLGetCoverage()", content); - xmlFree(content); - return MS_FAILURE; - } - xmlFree(content); - } - } - - else if (EQUAL((char *) scaleMethodNode->name, "ScaleToSize")) { - xmlNodePtr scaleAxisNode, axisNode, targetSizeNode; - char *axisName, *content; - wcs20AxisObjPtr axis; - - XML_FOREACH_CHILD(scaleMethodNode, scaleAxisNode) { - XML_LOOP_IGNORE_COMMENT_OR_TEXT(scaleAxisNode); - - if (!EQUAL((char *)scaleAxisNode->name, "TargetAxisSize")) { - msSetError(MS_WCSERR, "Invalid ScaleToSize.", - "msWCSParseRequest20_XMLGetCoverage()"); - return MS_FAILURE; - } - - /* axis */ - if (NULL == (axisNode = msLibXml2GetFirstChild(scaleAxisNode, "axis"))) { - msSetError(MS_WCSERR, "Missing axis node", - "msWCSParseRequest20_XMLGetCoverage()"); - return MS_FAILURE; - } - axisName = (char *)xmlNodeGetContent(axisNode); - if(NULL == (axis = msWCSFindAxis20(params, axisName))) { - if(NULL == (axis = msWCSCreateAxisObj20())) { - xmlFree(axisName); - return MS_FAILURE; - } - axis->name = msStrdup(axisName); - msWCSInsertAxisObj20(params, axis); - } - xmlFree(axisName); - - if (axis->size != 0) { - msSetError(MS_WCSERR, "targetSize was already set for axis '%s'.", - "msWCSParseRequest20_XMLGetCoverage()", axis->name); - return MS_FAILURE; - } - - /* targetSize */ - if (NULL == (targetSizeNode = msLibXml2GetFirstChild(scaleAxisNode, "targetSize"))) { - msSetError(MS_WCSERR, "Missing targetSize node", - "msWCSParseRequest20_XMLGetCoverage()"); - return MS_FAILURE; - } - - content = (char *)xmlNodeGetContent(targetSizeNode); - if (msStringParseInteger(content, &(axis->size)) != MS_SUCCESS - || axis->size <= 0) { - msSetError(MS_WCSERR, "Invalid targetSize '%s'.", - "msWCSParseRequest20_XMLGetCoverage()", content); - xmlFree(content); - return MS_FAILURE; - } - xmlFree(content); - } - } - - else if (EQUAL((char *) scaleMethodNode->name, "ScaleToExtent")) { - xmlNodePtr scaleAxisNode, axisNode, lowNode, highNode; - char *axisName, *content; - wcs20AxisObjPtr axis; - int low, high; - - XML_FOREACH_CHILD(scaleMethodNode, scaleAxisNode) { - XML_LOOP_IGNORE_COMMENT_OR_TEXT(scaleAxisNode); - - if (!EQUAL((char *)scaleAxisNode->name, "TargetAxisExtent")) { - msSetError(MS_WCSERR, "Invalid ScaleToExtent.", - "msWCSParseRequest20_XMLGetCoverage()"); - return MS_FAILURE; - } - - /* axis */ - if (NULL == (axisNode = msLibXml2GetFirstChild(scaleAxisNode, "axis"))) { - msSetError(MS_WCSERR, "Missing axis node", - "msWCSParseRequest20_XMLGetCoverage()"); - return MS_FAILURE; - } - axisName = (char *)xmlNodeGetContent(axisNode); - if(NULL == (axis = msWCSFindAxis20(params, axisName))) { - if(NULL == (axis = msWCSCreateAxisObj20())) { - xmlFree(axisName); - return MS_FAILURE; - } - axis->name = msStrdup(axisName); - msWCSInsertAxisObj20(params, axis); - } - xmlFree(axisName); - - if (axis->size != 0) { - msSetError(MS_WCSERR, "targetSize was already set for axis '%s'.", - "msWCSParseRequest20_XMLGetCoverage()", axis->name); - return MS_FAILURE; - } - - /* targetSize */ - if (NULL == (lowNode = msLibXml2GetFirstChild(scaleAxisNode, "low"))) { - msSetError(MS_WCSERR, "Missing low node", - "msWCSParseRequest20_XMLGetCoverage()"); - return MS_FAILURE; - } - - if (NULL == (highNode = msLibXml2GetFirstChild(scaleAxisNode, "high"))) { - msSetError(MS_WCSERR, "Missing high node", - "msWCSParseRequest20_XMLGetCoverage()"); - return MS_FAILURE; - } - - content = (char *)xmlNodeGetContent(lowNode); - if (msStringParseInteger(content, &low) != MS_SUCCESS) { - msSetError(MS_WCSERR, "Invalid low value '%s'.", - "msWCSParseRequest20_XMLGetCoverage()", content); - xmlFree(content); - return MS_FAILURE; - } - xmlFree(content); - - - content = (char *)xmlNodeGetContent(highNode); - if (msStringParseInteger(content, &high) != MS_SUCCESS) { - msSetError(MS_WCSERR, "Invalid high value '%s'.", - "msWCSParseRequest20_XMLGetCoverage()", content); - xmlFree(content); - return MS_FAILURE; - } - xmlFree(content); - - if (high <= low) { - msSetError(MS_WCSERR, "Invalid extent, high is lower than low.", - "msWCSParseRequest20_XMLGetCoverage()"); - return MS_FAILURE; - } - - axis->size = high - low; - } - } - } - - /* Range Subset */ - else if(EQUAL((char *) extensionNode->name, "RangeSubset")) { - xmlNodePtr rangeItemNode = NULL; - - XML_FOREACH_CHILD(extensionNode, rangeItemNode) { - xmlNodePtr rangeItemNodeChild = msLibXml2GetFirstChildElement(rangeItemNode); - XML_LOOP_IGNORE_COMMENT_OR_TEXT(rangeItemNode); - - XML_ASSERT_NODE_NAME(rangeItemNode, "RangeItem"); - - if (!rangeItemNodeChild) { - msSetError(MS_WCSERR, "Missing RangeComponent or RangeInterval.", - "msWCSParseRequest20_XMLGetCoverage()"); - return MS_FAILURE; - } - else if (EQUAL((char *) rangeItemNodeChild->name, "RangeComponent")) { - char *content = (char *)xmlNodeGetContent(rangeItemNodeChild); - params->range_subset = - CSLAddString(params->range_subset, content); - xmlFree(content); - } - else if (EQUAL((char *) rangeItemNodeChild->name, "RangeInterval")) { - xmlNodePtr intervalNode = rangeItemNodeChild; - xmlNodePtr startComponentNode = msLibXml2GetFirstChild(intervalNode, "startComponent"); - xmlNodePtr endComponentNode = msLibXml2GetFirstChild(intervalNode, "endComponent"); - char *start; - char *stop; - - if (!startComponentNode || !endComponentNode) { - msSetError(MS_WCSERR, "Wrong RangeInterval.", - "msWCSParseRequest20_XMLGetCoverage()"); - return MS_FAILURE; - } - - start = (char *)xmlNodeGetContent(startComponentNode); - stop = (char *)xmlNodeGetContent(endComponentNode); - - std::string value(start); - value += ':'; - value += stop; - - xmlFree(start); - xmlFree(stop); - - params->range_subset = - CSLAddString(params->range_subset, value.c_str()); - } - } - } - - else if (EQUAL((char *) extensionNode->name, "subsettingCrs")) { - msFree(params->subsetcrs); - params->subsetcrs = (char *)xmlNodeGetContent(extensionNode); - } - - else if (EQUAL((char *) extensionNode->name, "outputCrs")) { - msFree(params->outputcrs); - params->outputcrs = (char *)xmlNodeGetContent(extensionNode); - } - - else if (EQUAL((char *) extensionNode->name, "Interpolation")) { - xmlNodePtr globalInterpolation = msLibXml2GetFirstChild(extensionNode, "globalInterpolation"); - char *content; - if (globalInterpolation == NULL) { - msSetError(MS_WCSERR, "Missing 'globalInterpolation' node.", - "msWCSParseRequest20_XMLGetCoverage()"); - return MS_FAILURE; - } - content = (char *)xmlNodeGetContent(globalInterpolation); - msFree(params->interpolation); - /* TODO: use URIs/URLs once they are specified */ - params->interpolation = msStrdup(content); - xmlFree(content); - } - - /* GeoTIFF parameters */ - else if (EQUAL((char *) extensionNode->name, "parameters") - && extensionNode->ns - && EQUAL((char *)extensionNode->ns->href, "http://www.opengis.net/gmlcov/geotiff/1.0")) { - - xmlNodePtr parameter; - - XML_FOREACH_CHILD(extensionNode, parameter) { - char *content; - XML_LOOP_IGNORE_COMMENT_OR_TEXT(parameter); - - content = (char *)xmlNodeGetContent(parameter); - - params->format_options = - CSLAddNameValue(params->format_options, (char *)parameter->name, content); - xmlFree(content); - } - } - } - } else { - XML_UNKNOWN_NODE_ERROR(child); - } - } - return MS_SUCCESS; -} -#endif - -/************************************************************************/ -/* msWCSParseRequest20() */ -/* */ -/* Parses a CGI-request to a WCS 20 params object. It is */ -/* either a POST or a GET request. In case of a POST request */ -/* the xml content has to be parsed to a DOM structure */ -/* before the parameters can be extracted. */ -/************************************************************************/ - -int msWCSParseRequest20(mapObj *map, - cgiRequestObj *request, - owsRequestObj *ows_request, - wcs20ParamsObjPtr params) -{ - int i; - if (params == NULL || request == NULL || ows_request == NULL) { - msSetError(MS_WCSERR, "Internal error.", "msWCSParseRequest20()"); - return MS_FAILURE; - } - - /* Copy arbitrary service, version and request. */ - params->service = msStrdup(ows_request->service); - if(ows_request->version != NULL) { - params->version = msStrdup(ows_request->version); - } - params->request = msStrdup(ows_request->request); - - - /* Parse the POST request */ - if (request->type == MS_POST_REQUEST) { -#if defined(USE_LIBXML2) - xmlDocPtr doc = static_cast(ows_request->document); - xmlNodePtr root = NULL; - const char *validate; - int ret = MS_SUCCESS; - - /* parse to DOM-Structure and get root element */ - if(doc == NULL) { - xmlErrorPtr error = xmlGetLastError(); - msSetError(MS_WCSERR, "XML parsing error: %s", - "msWCSParseRequest20()", error->message); - return MS_FAILURE; - } - - root = xmlDocGetRootElement(doc); - - validate = msOWSLookupMetadata(&(map->web.metadata), "CO", "validate_xml"); - if (validate != NULL && EQUAL(validate, "TRUE")) { - char *schema_dir = msStrdup(msOWSLookupMetadata(&(map->web.metadata), - "CO", "schemas_dir")); - if (schema_dir != NULL - && (params->version == NULL || - EQUALN(params->version, "2.0", 3))) { - schema_dir = msStringConcatenate(schema_dir, - "wcs/2.0.0/wcsAll.xsd"); - if (msOWSSchemaValidation(schema_dir, request->postrequest) != 0) { - msSetError(MS_WCSERR, "Invalid POST request. " - "XML is not valid", - "msWCSParseRequest20()"); - return MS_FAILURE; - } - } - msFree(schema_dir); - } - - if(EQUAL(params->request, "GetCapabilities")) { - ret = msWCSParseRequest20_XMLGetCapabilities(root, params); - } else if(params->version != NULL && EQUALN(params->version, "2.0", 3)) { - if(EQUAL(params->request, "DescribeCoverage")) { - ret = msWCSParseRequest20_XMLDescribeCoverage(root, params); - } else if(EQUAL(params->request, "GetCoverage")) { - ret = msWCSParseRequest20_XMLGetCoverage(map, root, params); - } - } - return ret; - -#else /* defined(USE_LIBXML2) */ - /* TODO: maybe with CPLXML? */ - return MS_FAILURE; -#endif /* defined(USE_LIBXML2) */ - } - - /* Parse the KVP GET request */ - for (i = 0; i < request->NumParams; ++i) { - char *key = NULL, *value = NULL; - char **tokens; - int num, j; - key = request->ParamNames[i]; - value = request->ParamValues[i]; - - if (EQUAL(key, "VERSION")) { - continue; - } else if (EQUAL(key, "REQUEST")) { - continue; - } else if (EQUAL(key, "SERVICE")) { - continue; - } else if (EQUAL(key, "ACCEPTVERSIONS")) { - tokens = msStringSplit(value, ',', &num); - for(j = 0; j < num; ++j) { - params->accept_versions = - CSLAddString(params->accept_versions, tokens[j]); - } - msFreeCharArray(tokens, num); - } else if (EQUAL(key, "SECTIONS")) { - tokens = msStringSplit(value, ',', &num); - for(j = 0; j < num; ++j) { - params->sections = - CSLAddString(params->sections, tokens[j]); - } - msFreeCharArray(tokens, num); - } else if (EQUAL(key, "UPDATESEQUENCE")) { - msFree(params->updatesequence); - params->updatesequence = msStrdup(value); - } else if (EQUAL(key, "ACCEPTFORMATS")) { - /* ignore */ - } else if (EQUAL(key, "ACCEPTLANGUAGES")) { - if (params->accept_languages != NULL) { - CSLDestroy(params->accept_languages); - } - params->accept_languages = CSLTokenizeString2(value, ",", 0); - } else if (EQUAL(key, "COVERAGEID")) { - if (params->ids != NULL) { - msSetError(MS_WCSERR, "Parameter 'CoverageID' is already set. " - "For multiple IDs use a comma separated list.", - "msWCSParseRequest20()"); - return MS_FAILURE; - } - params->ids = CSLTokenizeString2(value, ",",0); - } else if (EQUAL(key, "FORMAT")) { - msFree(params->format); - params->format = msStrdup(value); - } else if (EQUAL(key, "MEDIATYPE")) { - if(EQUAL(value, "multipart/mixed") || EQUAL(value, "multipart/related")) { - params->multipart = MS_TRUE; - } - else { - msSetError(MS_WCSERR, "Invalid value '%s' for parameter 'Mediatype'.", - "msWCSParseRequest20()", value); - return MS_FAILURE; - } - } else if (EQUAL(key, "INTERPOLATION")) { - msFree(params->interpolation); - params->interpolation = msStrdup(value); - } else if (EQUAL(key, "OUTPUTCRS")) { - msFree(params->outputcrs); - params->outputcrs = msStrdup(value); - } else if (EQUAL(key, "SUBSETTINGCRS")) { - msFree(params->subsetcrs); - params->subsetcrs = msStrdup(value); - } else if (EQUAL(key, "SCALEFACTOR")) { - double scale = MS_WCS20_UNBOUNDED; - if (params->scale != MS_WCS20_UNBOUNDED) { - msSetError(MS_WCSERR, "Parameter 'SCALEFACTOR' already set.", - "msWCSParseRequest20()"); - return MS_FAILURE; - } else if (msStringParseDouble(value, &scale) != MS_SUCCESS) { - msSetError(MS_WCSERR, "Could not parse parameter 'SCALEFACTOR'.", - "msWCSParseRequest20()"); - return MS_FAILURE; - } else if (scale <= 0.0) { - msSetError(MS_WCSERR, "Invalid value for 'SCALEFACTOR'.", - "msWCSParseRequest20()"); - return MS_FAILURE; - } - params->scale = scale; - } else if (EQUAL(key, "SCALEAXES")) { - wcs20AxisObjPtr axis = NULL; - tokens = msStringSplit(value, ',', &num); - for(j = 0; j < num; ++j) { - char axisName[500]; - double scale; - - if (msWCSParseScaleString20(tokens[j], axisName, sizeof(axisName), &scale) != MS_SUCCESS) { - msFreeCharArray(tokens, num); - return MS_FAILURE; - } - - if(NULL == (axis = msWCSFindAxis20(params, axisName))) { - if(NULL == (axis = msWCSCreateAxisObj20())) { - msFreeCharArray(tokens, num); - return MS_FAILURE; - } - axis->name = msStrdup(axisName); - msWCSInsertAxisObj20(params, axis); - } - - /* check if the size of the axis is already set */ - if(axis->scale != MS_WCS20_UNBOUNDED) { - msFreeCharArray(tokens, num); - msSetError(MS_WCSERR, "The scale of the axis is already set.", - "msWCSParseRequest20()"); - return MS_FAILURE; - } - axis->scale = scale; - } - msFreeCharArray(tokens, num); - } else if (EQUAL(key, "SCALESIZE")) { - wcs20AxisObjPtr axis = NULL; - tokens = msStringSplit(value, ',', &num); - for(j = 0; j < num; ++j) { - char axisName[500]; - int size; - - if (msWCSParseSizeString20(tokens[j], axisName, sizeof(axisName), &size) != MS_SUCCESS) { - msFreeCharArray(tokens, num); - return MS_FAILURE; - } - - if(NULL == (axis = msWCSFindAxis20(params, axisName))) { - if(NULL == (axis = msWCSCreateAxisObj20())) { - msFreeCharArray(tokens, num); - return MS_FAILURE; - } - axis->name = msStrdup(axisName); - msWCSInsertAxisObj20(params, axis); - } - - /* check if the size of the axis is already set */ - if(axis->size != 0) { - msFreeCharArray(tokens, num); - msSetError(MS_WCSERR, "The size of the axis is already set.", - "msWCSParseRequest20()"); - return MS_FAILURE; - } - axis->size = size; - } - msFreeCharArray(tokens, num); - } else if (EQUAL(key, "SCALEEXTENT")) { - wcs20AxisObjPtr axis = NULL; - /* No real support for scaleextent, we just interprete it as SCALESIZE */ - tokens = msStringSplit(value, ',', &num); - for(j = 0; j < num; ++j) { - char axisName[500]; - int min, max; - - if (msWCSParseScaleExtentString20(tokens[j], axisName, sizeof(axisName), - &min, &max) != MS_SUCCESS) { - msFreeCharArray(tokens, num); - return MS_FAILURE; - } - - if(NULL == (axis = msWCSFindAxis20(params, axisName))) { - if(NULL == (axis = msWCSCreateAxisObj20())) { - msFreeCharArray(tokens, num); - return MS_FAILURE; - } - axis->name = msStrdup(axisName); - msWCSInsertAxisObj20(params, axis); - } - - /* check if the size of the axis is already set */ - if(axis->size != 0) { - msFreeCharArray(tokens, num); - msSetError(MS_WCSERR, "The size of the axis is already set.", - "msWCSParseRequest20()"); - return MS_FAILURE; - } - axis->size = max - min; - } - msFreeCharArray(tokens, num); - /* We explicitly don't test for strict equality as the parameter name is supposed to be unique */ - } else if (EQUALN(key, "SIZE", 4)) { - /* Deprecated scaling */ - wcs20AxisObjPtr axis = NULL; - char axisName[500]; - int size = 0; - - if(msWCSParseSizeString20(value, axisName, sizeof(axisName), &size) == MS_FAILURE) { - return MS_FAILURE; - } - - if(NULL == (axis = msWCSFindAxis20(params, axisName))) { - if(NULL == (axis = msWCSCreateAxisObj20())) { - return MS_FAILURE; - } - axis->name = msStrdup(axisName); - msWCSInsertAxisObj20(params, axis); - } - - /* check if the size of the axis is already set */ - if(axis->size != 0) { - msSetError(MS_WCSERR, "The size of the axis is already set.", - "msWCSParseRequest20()"); - return MS_FAILURE; - } - axis->size = size; - /* We explicitly don't test for strict equality as the parameter name is supposed to be unique */ - } else if (EQUALN(key, "RESOLUTION", 10)) { - wcs20AxisObjPtr axis = NULL; - char axisName[500]; - double resolution = 0; - - if(msWCSParseResolutionString20(value, axisName, sizeof(axisName), &resolution) == MS_FAILURE) { - return MS_FAILURE; - } - - /* check if axis object already exists, otherwise create a new one */ - if(NULL == (axis = msWCSFindAxis20(params, axisName))) { - if(NULL == (axis = msWCSCreateAxisObj20())) { - return MS_FAILURE; - } - axis->name = msStrdup(axisName); - msWCSInsertAxisObj20(params, axis); - } - - /* check if the resolution of the axis is already set */ - if(axis->resolution != MS_WCS20_UNBOUNDED) { - msSetError(MS_WCSERR, "The resolution of the axis is already set.", - "msWCSParseRequest20()"); - return MS_FAILURE; - } - axis->resolution = resolution; - /* We explicitly don't test for strict equality as the parameter name is supposed to be unique */ - } else if (EQUALN(key, "SUBSET", 6)) { - wcs20AxisObjPtr axis = NULL; - wcs20SubsetObjPtr subset = msWCSCreateSubsetObj20(); - if(NULL == subset) { - return MS_FAILURE; - } - if (msWCSParseSubsetKVPString20(subset, value) == MS_FAILURE) { - msWCSFreeSubsetObj20(subset); - msWCSException(map, "InvalidSubsetting", "subset", ows_request->version); - return MS_DONE; - } - - if(NULL == (axis = msWCSFindAxis20(params, subset->axis))) { - if(NULL == (axis = msWCSCreateAxisObj20())) { - return MS_FAILURE; - } - axis->name = msStrdup(subset->axis); - msWCSInsertAxisObj20(params, axis); - } - - if(NULL != axis->subset) { - msSetError(MS_WCSERR, "The axis '%s' is already subsetted.", - "msWCSParseRequest20()", axis->name); - msWCSFreeSubsetObj20(subset); - msWCSException(map, "InvalidAxisLabel", "subset", ows_request->version); - return MS_DONE; - } - axis->subset = subset; - } else if(EQUAL(key, "RANGESUBSET")) { - tokens = msStringSplit(value, ',', &num); - for(j = 0; j < num; ++j) { - params->range_subset = - CSLAddString(params->range_subset, tokens[j]); - } - msFreeCharArray(tokens, num); - } else if (EQUALN(key, "GEOTIFF:", 8)) { - params->format_options = - CSLAddNameValue(params->format_options, key, value); - } - /* Ignore all other parameters here */ - } - - return MS_SUCCESS; -} - -#if defined(USE_LIBXML2) - -/************************************************************************/ -/* msWCSValidateAndFindSubsets20() */ -/* */ -/* Iterates over every axis in the parameters and checks if the */ -/* axis name is in any string list. If found, but there already is */ -/* a sample found for this axis, an Error is returned. Also if no */ -/* axis is found for a given axis, an error is returned. */ -/************************************************************************/ -static int msWCSValidateAndFindAxes20( - wcs20ParamsObjPtr params, - wcs20AxisObjPtr outAxes[]) -{ - static const int numAxis = 2; - const char * const validXAxisNames[] = {"x", "xaxis", "x-axis", "x_axis", "long", "long_axis", "long-axis", "lon", "lon_axis", "lon-axis", NULL}; - const char * const validYAxisNames[] = {"y", "yaxis", "y-axis", "y_axis", "lat", "lat_axis", "lat-axis", NULL}; - const char * const * const validAxisNames[2] = { validXAxisNames, validYAxisNames }; - int iParamAxis, iAcceptedAxis, iName, i; - - for(i = 0; i < numAxis; ++i) { - outAxes[i] = NULL; - } - - /* iterate over all subsets */ - for(iParamAxis = 0; iParamAxis < params->numaxes; ++iParamAxis) { - int found = 0; - - /* iterate over all given axes */ - for(iAcceptedAxis = 0; iAcceptedAxis < numAxis; ++iAcceptedAxis ) { - /* iterate over all possible names for the current axis */ - for(iName = 0; validAxisNames[iAcceptedAxis][iName] != NULL ; ++iName) { - /* compare axis name with current possible name */ - if(EQUAL(params->axes[iParamAxis]->name, validAxisNames[iAcceptedAxis][iName])) { - /* if there is already a sample for the axis, throw error */ - if(outAxes[iAcceptedAxis] != NULL) { - msSetError(MS_WCSERR, "The axis with the name '%s' corresponds " - "to the same axis as the subset with the name '%s'.", - "msWCSValidateAndFindAxes20()", - outAxes[iAcceptedAxis]->name, params->axes[iParamAxis]->name); - return MS_FAILURE; - } - - /* if match is found, save it */ - outAxes[iAcceptedAxis] = params->axes[iParamAxis]; - found = 1; - break; - } - } - if (found) { - break; - } - } - - /* no valid representation for current subset found */ - /* exit and throw error */ - if(found == 0) { - msSetError(MS_WCSERR, "Invalid subset axis '%s'.", - "msWCSValidateAndFindAxes20()", params->axes[iParamAxis]->name); - return MS_FAILURE; - } - } - return MS_SUCCESS; -} - -/************************************************************************/ -/* msWCSPrepareNamespaces20() */ -/* */ -/* Inserts namespace definitions into the root node of a DOM */ -/* structure. */ -/************************************************************************/ - -static void msWCSPrepareNamespaces20(xmlDocPtr pDoc, xmlNodePtr psRootNode, mapObj* map, int addInspire) -{ - xmlNsPtr psXsiNs; - char *schemaLocation = NULL; - char *xsi_schemaLocation = NULL; - - xmlSetNs(psRootNode, xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_WCS_20_NAMESPACE_URI, BAD_CAST MS_OWSCOMMON_WCS_NAMESPACE_PREFIX)); - - xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_OWS_20_NAMESPACE_URI, BAD_CAST MS_OWSCOMMON_OWS_NAMESPACE_PREFIX); - xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_OGC_NAMESPACE_URI, BAD_CAST MS_OWSCOMMON_OGC_NAMESPACE_PREFIX ); - xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_W3C_XSI_NAMESPACE_URI, BAD_CAST MS_OWSCOMMON_W3C_XSI_NAMESPACE_PREFIX); - xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_W3C_XLINK_NAMESPACE_URI, BAD_CAST MS_OWSCOMMON_W3C_XLINK_NAMESPACE_PREFIX); - xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_WCS_20_NAMESPACE_URI, BAD_CAST MS_OWSCOMMON_WCS_NAMESPACE_PREFIX); - xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_GML_32_NAMESPACE_URI, BAD_CAST MS_OWSCOMMON_GML_NAMESPACE_PREFIX); - xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_GMLCOV_10_NAMESPACE_URI, BAD_CAST MS_OWSCOMMON_GMLCOV_NAMESPACE_PREFIX); - xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_SWE_20_NAMESPACE_URI, BAD_CAST MS_OWSCOMMON_SWE_NAMESPACE_PREFIX); - - if (addInspire) { - xmlNewNs(psRootNode, BAD_CAST MS_INSPIRE_COMMON_NAMESPACE_URI, BAD_CAST MS_INSPIRE_COMMON_NAMESPACE_PREFIX); - xmlNewNs(psRootNode, BAD_CAST MS_INSPIRE_DLS_NAMESPACE_URI, BAD_CAST MS_INSPIRE_DLS_NAMESPACE_PREFIX); - } - - psXsiNs = xmlSearchNs(pDoc, psRootNode, BAD_CAST MS_OWSCOMMON_W3C_XSI_NAMESPACE_PREFIX); - - schemaLocation = msEncodeHTMLEntities( msOWSGetSchemasLocation(map) ); - xsi_schemaLocation = msStrdup(MS_OWSCOMMON_WCS_20_NAMESPACE_URI); - xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, " "); - xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, schemaLocation); - xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, MS_OWSCOMMON_WCS_20_SCHEMAS_LOCATION); - xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, " "); - - if (addInspire) { - xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, MS_INSPIRE_DLS_NAMESPACE_URI " "); - xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, msOWSGetInspireSchemasLocation(map)); - xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, MS_INSPIRE_DLS_SCHEMA_LOCATION); - } - - xmlNewNsProp(psRootNode, psXsiNs, BAD_CAST "schemaLocation", BAD_CAST xsi_schemaLocation); - - msFree(schemaLocation); - msFree(xsi_schemaLocation); -} - -/************************************************************************/ -/* msWCSGetFormatList20() */ -/* */ -/* Copied from mapwcs.c. */ -/************************************************************************/ - -static char *msWCSGetFormatsList20( mapObj *map, layerObj *layer ) -{ - char *format_list = msStrdup(""); - char **tokens = NULL, **formats = NULL; - int i, numtokens = 0, numformats; - char *value; - - /* -------------------------------------------------------------------- */ - /* Parse from layer metadata. */ - /* -------------------------------------------------------------------- */ - if( layer != NULL - && (value = msOWSGetEncodeMetadata( &(layer->metadata),"CO","formats", - NULL )) != NULL ) { - tokens = msStringSplit(value, ' ', &numtokens); - msFree(value); - } - - /* -------------------------------------------------------------------- */ - /* Parse from map.web metadata. */ - /* -------------------------------------------------------------------- */ - else if((value = msOWSGetEncodeMetadata( &(map->web.metadata), "CO", "formats", - NULL)) != NULL ) { - tokens = msStringSplit(value, ' ', &numtokens); - msFree(value); - } - - /* -------------------------------------------------------------------- */ - /* Or generate from all configured raster output formats that */ - /* look plausible. */ - /* -------------------------------------------------------------------- */ - else { - tokens = (char **) msSmallCalloc(map->numoutputformats,sizeof(char*)); - for( i = 0; i < map->numoutputformats; i++ ) { - switch( map->outputformatlist[i]->renderer ) { - /* seemingly normal raster format */ - case MS_RENDER_WITH_AGG: - case MS_RENDER_WITH_RAWDATA: - tokens[numtokens++] = msStrdup(map->outputformatlist[i]->name); - break; - /* rest of formats aren't really WCS compatible */ - default: - break; - } - } - } - - /* -------------------------------------------------------------------- */ - /* Convert outputFormatObj names into mime types and remove */ - /* duplicates. */ - /* -------------------------------------------------------------------- */ - numformats = 0; - formats = (char **) msSmallCalloc(sizeof(char*),numtokens); - - for( i = 0; i < numtokens; i++ ) { - int format_i, j; - const char *mimetype; - - for( format_i = 0; format_i < map->numoutputformats; format_i++ ) { - if( EQUAL(map->outputformatlist[format_i]->name, tokens[i]) ) - break; - } - - if( format_i == map->numoutputformats ) { - msDebug("Failed to find outputformat info on format '%s', ignore.\n", - tokens[i] ); - continue; - } - - mimetype = map->outputformatlist[format_i]->mimetype; - if( mimetype == NULL || strlen(mimetype) == 0 ) { - msDebug("No mimetime for format '%s', ignoring.\n", - tokens[i] ); - continue; - } - - for( j = 0; j < numformats; j++ ) { - if( EQUAL(mimetype,formats[j]) ) - break; - } - - if( j < numformats ) { - msDebug( "Format '%s' ignored since mimetype '%s' duplicates another outputFormatObj.\n", - tokens[i], mimetype ); - continue; - } - - formats[numformats++] = msStrdup(mimetype); - } - - msFreeCharArray(tokens,numtokens); - - /* -------------------------------------------------------------------- */ - /* Turn mimetype list into comma delimited form for easy use */ - /* with xml functions. */ - /* -------------------------------------------------------------------- */ - for(i = 0; i < numformats; i++) { - if(i > 0) { - format_list = msStringConcatenate(format_list, (char *) ","); - } - format_list = msStringConcatenate(format_list, formats[i]); - } - msFreeCharArray(formats,numformats); - - return format_list; -} - -/************************************************************************/ -/* msWCSSwapAxes20 */ -/* */ -/* Helper function to determine if a SRS mandates swapped axes. */ -/************************************************************************/ - -static int msWCSSwapAxes20(char *srs_uri) -{ - int srid = 0; - - /* get SRID from the srs uri */ - if(srs_uri != NULL && strlen(srs_uri) > 0) { - if(sscanf(srs_uri, "http://www.opengis.net/def/crs/EPSG/0/%d", &srid) != EOF) - ; - else if(sscanf(srs_uri, "http://www.opengis.net/def/crs/%d", &srid) != EOF) - ; - else - srid = 0; - } - if (srid == 0) - return MS_FALSE; - - return msIsAxisInverted(srid); -} - -/************************************************************************/ -/* msWCSCommon20_CreateBoundedBy() */ -/* */ -/* Inserts the BoundedBy section into an existing DOM structure. */ -/************************************************************************/ - -static void msWCSCommon20_CreateBoundedBy(layerObj *layer, wcs20coverageMetadataObjPtr cm, - xmlNsPtr psGmlNs, xmlNodePtr psRoot, projectionObj *projection, int swapAxes) -{ - xmlNodePtr psBoundedBy, psEnvelope; - char lowerCorner[100], upperCorner[100], axisLabels[100], uomLabels[100]; - - psBoundedBy = xmlNewChild( psRoot, psGmlNs, BAD_CAST "boundedBy", NULL); - { - psEnvelope = xmlNewChild(psBoundedBy, psGmlNs, BAD_CAST "Envelope", NULL); - { - xmlNewProp(psEnvelope, BAD_CAST "srsName", BAD_CAST cm->srs_uri); - - if(projection->proj != NULL && msProjIsGeographicCRS(projection)) { - if (swapAxes == MS_FALSE) { - strlcpy(axisLabels, "long lat", sizeof(axisLabels)); - } else { - strlcpy(axisLabels, "lat long", sizeof(axisLabels)); - } - strlcpy(uomLabels, "deg deg", sizeof(uomLabels)); - } else { - if (swapAxes == MS_FALSE) { - strlcpy(axisLabels, "x y", sizeof(axisLabels)); - } else { - strlcpy(axisLabels, "y x", sizeof(axisLabels)); - } - strlcpy(uomLabels, "m m", sizeof(uomLabels)); - } - xmlNewProp(psEnvelope, BAD_CAST "axisLabels", BAD_CAST axisLabels); - xmlNewProp(psEnvelope, BAD_CAST "uomLabels", BAD_CAST uomLabels); - xmlNewProp(psEnvelope, BAD_CAST "srsDimension", BAD_CAST "2"); - - if (swapAxes == MS_FALSE) { - snprintf(lowerCorner, sizeof(lowerCorner), "%.15g %.15g", cm->extent.minx, cm->extent.miny); - snprintf(upperCorner, sizeof(upperCorner), "%.15g %.15g", cm->extent.maxx, cm->extent.maxy); - } else { - snprintf(lowerCorner, sizeof(lowerCorner), "%.15g %.15g", cm->extent.miny, cm->extent.minx); - snprintf(upperCorner, sizeof(upperCorner), "%.15g %.15g", cm->extent.maxy, cm->extent.maxx); - } - - xmlNewChild(psEnvelope, psGmlNs, BAD_CAST "lowerCorner", BAD_CAST lowerCorner); - xmlNewChild(psEnvelope, psGmlNs, BAD_CAST "upperCorner", BAD_CAST upperCorner); - } - } -} - -/************************************************************************/ -/* msWCSCommon20_CreateDomainSet() */ -/* */ -/* Inserts the DomainSet section into an existing DOM structure. */ -/************************************************************************/ - -static void msWCSCommon20_CreateDomainSet(layerObj* layer, wcs20coverageMetadataObjPtr cm, - xmlNsPtr psGmlNs, xmlNodePtr psRoot, projectionObj *projection, int swapAxes) -{ - xmlNodePtr psDomainSet, psGrid, psLimits, psGridEnvelope, psOrigin, - psOffsetX, psOffsetY; - char low[100], high[100], id[100], point[100]; - char offsetVector1[100], offsetVector2[100], axisLabels[100]; - - psDomainSet = xmlNewChild( psRoot, psGmlNs, BAD_CAST "domainSet", NULL); - { - psGrid = xmlNewChild(psDomainSet, psGmlNs, BAD_CAST "RectifiedGrid", NULL); - { - double x0 = cm->geotransform[0]+cm->geotransform[1]/2+cm->geotransform[2]/2; - double y0 = cm->geotransform[3]+cm->geotransform[4]/2+cm->geotransform[5]/2; - double resx = cm->geotransform[1]; - double resy = cm->geotransform[5]; - - xmlNewProp(psGrid, BAD_CAST "dimension", BAD_CAST "2"); - snprintf(id, sizeof(id), "grid_%s", layer->name); - xmlNewNsProp(psGrid, psGmlNs, BAD_CAST "id", BAD_CAST id); - - psLimits = xmlNewChild(psGrid, psGmlNs, BAD_CAST "limits", NULL); - { - psGridEnvelope = xmlNewChild(psLimits, psGmlNs, BAD_CAST "GridEnvelope", NULL); - { - strlcpy(low, "0 0", sizeof(low)); - snprintf(high, sizeof(high), "%d %d", cm->xsize - 1, cm->ysize - 1); - - xmlNewChild(psGridEnvelope, psGmlNs, BAD_CAST "low", BAD_CAST low); - xmlNewChild(psGridEnvelope, psGmlNs, BAD_CAST "high", BAD_CAST high); - } - } - - if(projection->proj != NULL && msProjIsGeographicCRS(projection)) { - strlcpy(axisLabels, "long lat", sizeof(axisLabels)); - } else { - strlcpy(axisLabels, "x y", sizeof(axisLabels)); - } - - xmlNewChild(psGrid, psGmlNs, BAD_CAST "axisLabels", BAD_CAST axisLabels); - - psOrigin = xmlNewChild(psGrid, psGmlNs, BAD_CAST "origin", NULL); - { - if (swapAxes == MS_FALSE) { - snprintf(point, sizeof(point), "%f %f", x0, y0); - } else { - snprintf(point, sizeof(point), "%f %f", y0, x0); - } - psOrigin = xmlNewChild(psOrigin, psGmlNs, BAD_CAST "Point", NULL); - snprintf(id, sizeof(id), "grid_origin_%s", layer->name); - xmlNewNsProp(psOrigin, psGmlNs, BAD_CAST "id", BAD_CAST id); - xmlNewProp(psOrigin, BAD_CAST "srsName", BAD_CAST cm->srs_uri); - - xmlNewChild(psOrigin, psGmlNs, BAD_CAST "pos", BAD_CAST point); - } - - if (swapAxes == MS_FALSE) { - snprintf(offsetVector1, sizeof(offsetVector1), "%f 0", resx); - snprintf(offsetVector2, sizeof(offsetVector2), "0 %f", resy); - } else { - snprintf(offsetVector1, sizeof(offsetVector1), "0 %f", resx); - snprintf(offsetVector2, sizeof(offsetVector2), "%f 0", resy); - } - psOffsetX = xmlNewChild(psGrid, psGmlNs, BAD_CAST "offsetVector", BAD_CAST offsetVector1); - psOffsetY = xmlNewChild(psGrid, psGmlNs, BAD_CAST "offsetVector", BAD_CAST offsetVector2); - - xmlNewProp(psOffsetX, BAD_CAST "srsName", BAD_CAST cm->srs_uri); - xmlNewProp(psOffsetY, BAD_CAST "srsName", BAD_CAST cm->srs_uri); - } - } -} - -/************************************************************************/ -/* msWCSCommon20_CreateRangeType() */ -/* */ -/* Inserts the RangeType section into an existing DOM structure. */ -/************************************************************************/ - -static void msWCSCommon20_CreateRangeType(layerObj* layer, wcs20coverageMetadataObjPtr cm, char *bands, - xmlNsPtr psGmlNs, xmlNsPtr psGmlcovNs, xmlNsPtr psSweNs, xmlNsPtr psXLinkNs, xmlNodePtr psRoot) -{ - xmlNodePtr psRangeType, psDataRecord, psField, psQuantity, - psUom, psConstraint, psAllowedValues = NULL, psNilValues = NULL; - char **arr = NULL; - int num = 0; - - if(NULL != bands) { - arr = msStringSplit(bands, ',', &num); - } - - psRangeType = xmlNewChild( psRoot, psGmlcovNs, BAD_CAST "rangeType", NULL); - psDataRecord = xmlNewChild(psRangeType, psSweNs, BAD_CAST "DataRecord", NULL); - - /* iterate over every band */ - for(unsigned i = 0; i < cm->numbands; ++i) { - /* only add bands that are in the range subset */ - if (NULL != arr && num > 0) { - int found = MS_FALSE, j; - for(j = 0; j < num; ++j) { - int repr = 0; - msStringParseInteger(arr[j], &repr); - if(static_cast(repr) == i + 1) { - found = MS_TRUE; - break; - } - } - if(found == MS_FALSE) { - /* ignore this band since it is not in the range subset */ - continue; - } - } - - /* add field tag */ - psField = xmlNewChild(psDataRecord, psSweNs, BAD_CAST "field", NULL); - - if(cm->bands[i].name != NULL) { - xmlNewProp(psField, BAD_CAST "name", BAD_CAST cm->bands[i].name); - } else { - xmlNewProp(psField, BAD_CAST "name", BAD_CAST "band"); - } - /* add Quantity tag */ - psQuantity = xmlNewChild(psField, psSweNs, BAD_CAST "Quantity", NULL); - if(cm->bands[i].definition != NULL) { - xmlNewProp(psQuantity, BAD_CAST "definition", BAD_CAST cm->bands[i].definition); - } - if(cm->bands[i].description != NULL) { - xmlNewChild(psQuantity, psSweNs, BAD_CAST "description", BAD_CAST cm->bands[i].description); - } - - /* if there are given nilvalues -> add them to the first field */ - /* all other fields get a reference to these */ - if(cm->numnilvalues > 0) { - psNilValues = xmlNewChild( - xmlNewChild(psQuantity, psSweNs, BAD_CAST "nilValues", NULL), - psSweNs, BAD_CAST "NilValues", NULL); - for(unsigned j = 0; j < cm->numnilvalues; ++j) { - xmlNodePtr psTemp = - xmlNewChild(psNilValues, psSweNs, BAD_CAST "nilValue", BAD_CAST cm->nilvalues[j]); - if(j < cm->numnilvalues) - xmlNewProp(psTemp, BAD_CAST "reason", BAD_CAST cm->nilvalues_reasons[j]); - } - } else { /* create an empty nilValues tag */ - xmlNewChild(psQuantity, psSweNs, BAD_CAST "nilValues", NULL); - } - - psUom = xmlNewChild(psQuantity, psSweNs, BAD_CAST "uom", NULL); - if(cm->bands[i].uom != NULL) { - xmlNewProp(psUom, BAD_CAST "code", BAD_CAST cm->bands[i].uom); - } else { - xmlNewProp(psUom, BAD_CAST "code", BAD_CAST "W.m-2.Sr-1"); - } - - /* add constraint */ - psConstraint = xmlNewChild(psQuantity, psSweNs, BAD_CAST "constraint", NULL); - - { - char interval[100], significant_figures[100]; - psAllowedValues = xmlNewChild(psConstraint, psSweNs, BAD_CAST "AllowedValues", NULL); - - /* Interval */ - snprintf(interval, sizeof(interval), "%.5g %.5g", cm->bands[i].interval_min, cm->bands[i].interval_max); - xmlNewChild(psAllowedValues, psSweNs, BAD_CAST "interval", BAD_CAST interval); - - /* Significant figures */ - snprintf(significant_figures, sizeof(significant_figures), "%d", cm->bands[i].significant_figures); - xmlNewChild(psAllowedValues, psSweNs, BAD_CAST "significantFigures", BAD_CAST significant_figures); - } - } - msFreeCharArray(arr,num); -} - -/************************************************************************/ -/* msWCSWriteDocument20() */ -/* */ -/* Writes out an xml structure to the stream. */ -/************************************************************************/ - -static int msWCSWriteDocument20(mapObj* map, xmlDocPtr psDoc) -{ - xmlChar *buffer = NULL; - int size = 0; - msIOContext *context = NULL; - char *contenttype = NULL; - - if( msIO_needBinaryStdout() == MS_FAILURE ) { - return MS_FAILURE; - } - - if( EQUAL((char *)xmlDocGetRootElement(psDoc)->name, "RectifiedGridCoverage") ) - contenttype = msStrdup("application/gml+xml"); - else - contenttype = msStrdup("text/xml"); - - msIO_setHeader("Content-Type","%s; charset=UTF-8", contenttype); - msIO_sendHeaders(); - msFree(contenttype); - - context = msIO_getHandler(stdout); - - xmlDocDumpFormatMemoryEnc(psDoc, &buffer, &size, "UTF-8", 1); - msIO_contextWrite(context, buffer, size); - xmlFree(buffer); - - return MS_SUCCESS; -} - -/************************************************************************/ -/* msWCSWriteFile20() */ -/* */ -/* Writes an image object to the stream. If multipart is set, */ -/* then content sections are inserted. */ -/************************************************************************/ - -static int msWCSWriteFile20(mapObj* map, imageObj* image, wcs20ParamsObjPtr params, int multipart) -{ - int status; - char* filename = NULL; - char *base_dir = NULL; - const char *fo_filename; - int i; - - fo_filename = msGetOutputFormatOption( image->format, "FILENAME", NULL ); - - /* -------------------------------------------------------------------- */ - /* Fetch the driver we will be using and check if it supports */ - /* VSIL IO. */ - /* -------------------------------------------------------------------- */ - if( EQUALN(image->format->driver,"GDAL/",5) ) { - GDALDriverH hDriver; - const char *pszExtension = image->format->extension; - - msAcquireLock( TLOCK_GDAL ); - hDriver = GDALGetDriverByName( image->format->driver+5 ); - if( hDriver == NULL ) { - msReleaseLock( TLOCK_GDAL ); - msSetError( MS_MISCERR, - "Failed to find %s driver.", - "msWCSWriteFile20()", - image->format->driver+5 ); - return msWCSException(map, "NoApplicableCode", "mapserv", - params->version); - } - - if( pszExtension == NULL ) - pszExtension = "img.tmp"; - - if( GDALGetMetadataItem( hDriver, GDAL_DCAP_VIRTUALIO, NULL ) - != NULL ) { - base_dir = msTmpFile(map, map->mappath, "/vsimem/wcsout", NULL); - if( fo_filename ) - filename = msStrdup(CPLFormFilename(base_dir, - fo_filename,NULL)); - else - filename = msStrdup(CPLFormFilename(base_dir, - "out", pszExtension )); - - /* CleanVSIDir( "/vsimem/wcsout" ); */ - - msReleaseLock( TLOCK_GDAL ); - status = msSaveImage(map, image, filename); - if( status != MS_SUCCESS ) { - msSetError(MS_MISCERR, "msSaveImage() failed", - "msWCSWriteFile20()"); - return msWCSException20(map, "NoApplicableCode", "mapserv", - params->version); - } - } - msReleaseLock( TLOCK_GDAL ); - } - - /* -------------------------------------------------------------------- */ - /* If we weren't able to write data under /vsimem, then we just */ - /* output a single "stock" filename. */ - /* -------------------------------------------------------------------- */ - if( filename == NULL ) { - msOutputFormatResolveFromImage( map, image ); - if(multipart) { - msIO_fprintf( stdout, "\r\n--wcs\r\n" ); - msIO_fprintf( - stdout, - "Content-Type: %s\r\n" - "Content-Description: coverage data\r\n" - "Content-Transfer-Encoding: binary\r\n", - MS_IMAGE_MIME_TYPE(map->outputformat)); - - if( fo_filename != NULL ) - msIO_fprintf( stdout, - "Content-ID: coverage/%s\r\n" - "Content-Disposition: INLINE; filename=%s\r\n\r\n", - fo_filename, - fo_filename); - else - msIO_fprintf( stdout, - "Content-ID: coverage/wcs.%s\r\n" - "Content-Disposition: INLINE\r\n\r\n", - MS_IMAGE_EXTENSION(map->outputformat)); - } else { - msIO_setHeader("Content-Type","%s",MS_IMAGE_MIME_TYPE(map->outputformat)); - msIO_setHeader("Content-Description","coverage data"); - msIO_setHeader("Content-Transfer-Encoding","binary"); - - if( fo_filename != NULL ) { - msIO_setHeader("Content-ID","coverage/%s",fo_filename); - msIO_setHeader("Content-Disposition","INLINE; filename=%s",fo_filename); - } else { - msIO_setHeader("Content-ID","coverage/wcs.%s",MS_IMAGE_EXTENSION(map->outputformat)); - msIO_setHeader("Content-Disposition","INLINE"); - } - msIO_sendHeaders(); - } - - status = msSaveImage(map, image, NULL); - if( status != MS_SUCCESS ) { - msSetError( MS_MISCERR, "msSaveImage() failed", "msWCSWriteFile20()"); - return msWCSException(map, "NoApplicableCode", "mapserv", params->version); - } - if(multipart) - msIO_fprintf( stdout, "\r\n--wcs--\r\n" ); - return MS_SUCCESS; - } - - /* -------------------------------------------------------------------- */ - /* When potentially listing multiple files, we take great care */ - /* to identify the "primary" file and list it first. In fact */ - /* it is the only file listed in the coverages document. */ - /* -------------------------------------------------------------------- */ - { - char **all_files = CPLReadDir( base_dir ); - int count = CSLCount(all_files); - - if( msIO_needBinaryStdout() == MS_FAILURE ) - return MS_FAILURE; - - msAcquireLock( TLOCK_GDAL ); - for( i = count-1; i >= 0; i-- ) { - const char *this_file = all_files[i]; - - if( EQUAL(this_file,".") || EQUAL(this_file,"..") ) { - all_files = CSLRemoveStrings( all_files, i, 1, NULL ); - continue; - } - - if( i > 0 && EQUAL(this_file,CPLGetFilename(filename)) ) { - all_files = CSLRemoveStrings( all_files, i, 1, NULL ); - all_files = CSLInsertString(all_files,0,CPLGetFilename(filename)); - i++; - } - } - - /* -------------------------------------------------------------------- */ - /* Dump all the files in the memory directory as mime sections. */ - /* -------------------------------------------------------------------- */ - count = CSLCount(all_files); - - if(count > 1 && multipart == MS_FALSE) { - msDebug( "msWCSWriteFile20(): force multipart output without gml summary because we have multiple files in the result.\n" ); - - multipart = MS_TRUE; - msIO_setHeader("Content-Type","multipart/related; boundary=wcs"); - msIO_sendHeaders(); - } - - for( i = 0; i < count; i++ ) { - const char *mimetype = NULL; - FILE *fp; - unsigned char block[4000]; - int bytes_read; - - if( i == 0 - && !EQUAL(MS_IMAGE_MIME_TYPE(map->outputformat), "unknown") ) - mimetype = MS_IMAGE_MIME_TYPE(map->outputformat); - - if( mimetype == NULL ) - mimetype = "application/octet-stream"; - if(multipart) { - msIO_fprintf( stdout, "\r\n--wcs\r\n" ); - msIO_fprintf( - stdout, - "Content-Type: %s\r\n" - "Content-Description: coverage data\r\n" - "Content-Transfer-Encoding: binary\r\n" - "Content-ID: coverage/%s\r\n" - "Content-Disposition: INLINE; filename=%s\r\n\r\n", - mimetype, - all_files[i], - all_files[i]); - } else { - msIO_setHeader("Content-Type","%s",mimetype); - msIO_setHeader("Content-Description","coverage data"); - msIO_setHeader("Content-Transfer-Encoding","binary"); - msIO_setHeader("Content-ID","coverage/%s",all_files[i]); - msIO_setHeader("Content-Disposition","INLINE; filename=%s",all_files[i]); - msIO_sendHeaders(); - } - - - fp = VSIFOpenL( - CPLFormFilename(base_dir, all_files[i], NULL), - "rb" ); - if( fp == NULL ) { - msReleaseLock( TLOCK_GDAL ); - msSetError( MS_MISCERR, - "Failed to open %s for streaming to stdout.", - "msWCSWriteFile20()", all_files[i] ); - return MS_FAILURE; - } - - while( (bytes_read = VSIFReadL(block, 1, sizeof(block), fp)) > 0 ) - msIO_fwrite( block, 1, bytes_read, stdout ); - - VSIFCloseL( fp ); - - VSIUnlink( CPLFormFilename(base_dir, all_files[i], NULL) ); - } - - msFree(base_dir); - msFree(filename); - CSLDestroy( all_files ); - msReleaseLock( TLOCK_GDAL ); - if(multipart) - msIO_fprintf( stdout, "\r\n--wcs--\r\n" ); - return MS_SUCCESS; - } - - return MS_SUCCESS; -} - -/************************************************************************/ -/* msWCSGetRangesetAxisMetadata20() */ -/* */ -/* Looks up a layers metadata for a specific axis information. */ -/************************************************************************/ - -static const char *msWCSLookupRangesetAxisMetadata20(hashTableObj *table, - const char *axis, const char *item) -{ - char buf[500]; - const char* value; - - if(table == NULL || axis == NULL || item == NULL) { - return NULL; - } - - strlcpy(buf, axis, sizeof(buf)); - strlcat(buf, "_", sizeof(buf)); - strlcat(buf, item, sizeof(buf)); - if((value = msLookupHashTable(table, buf)) != NULL) { - return value; - } - return msOWSLookupMetadata(table, "CO", buf); -} - -/************************************************************************/ -/* msWCSGetCoverageMetadata20() */ -/* */ -/* Inits a coverageMetadataObj. Uses msWCSGetCoverageMetadata() */ -/* but exchanges the SRS URN by an URI for compliancy with 2.0. */ -/************************************************************************/ - -static int msWCSGetCoverageMetadata20(layerObj *layer, wcs20coverageMetadataObj *cm) -{ - char *srs_uri = NULL; - memset(cm,0,sizeof(wcs20coverageMetadataObj)); - if ( msCheckParentPointer(layer->map,"map") == MS_FAILURE ) - return MS_FAILURE; - - msOWSGetEPSGProj(&(layer->projection), &(layer->metadata), "CO", MS_TRUE, &(cm->srs_epsg)); - if(!cm->srs_epsg) { - msOWSGetEPSGProj(&(layer->map->projection), - &(layer->map->web.metadata), "CO", MS_TRUE, &cm->srs_epsg); - if(!cm->srs_epsg) { - msSetError(MS_WCSERR, "Unable to determine the SRS for this layer, " - "no projection defined and no metadata available.", - "msWCSGetCoverageMetadata20()"); - return MS_FAILURE; - } - } - - /* -------------------------------------------------------------------- */ - /* Get the SRS in uri format. */ - /* -------------------------------------------------------------------- */ - if((srs_uri = msOWSGetProjURI(&(layer->projection), &(layer->metadata), - "CO", MS_TRUE)) == NULL) { - srs_uri = msOWSGetProjURI(&(layer->map->projection), - &(layer->map->web.metadata), "CO", MS_TRUE); - } - - if( srs_uri != NULL ) { - if( strlen(srs_uri) > sizeof(cm->srs_uri) - 1 ) { - msSetError(MS_WCSERR, "SRS URI too long!", - "msWCSGetCoverageMetadata()"); - return MS_FAILURE; - } - - strlcpy( cm->srs_uri, srs_uri, sizeof(cm->srs_uri) ); - msFree( srs_uri ); - } else { - cm->srs_uri[0] = '\0'; - } - - /* setup nilvalues */ - cm->numnilvalues = 0; - cm->nilvalues = NULL; - cm->nilvalues_reasons = NULL; - cm->native_format = NULL; - - /* -------------------------------------------------------------------- */ - /* If we have "virtual dataset" metadata on the layer, then use */ - /* that in preference to inspecting the file(s). */ - /* We require extent and either size or resolution. */ - /* -------------------------------------------------------------------- */ - if( msOWSLookupMetadata(&(layer->metadata), "CO", "extent") != NULL - && (msOWSLookupMetadata(&(layer->metadata), "CO", "resolution") != NULL - || msOWSLookupMetadata(&(layer->metadata), "CO", "size") != NULL) ) { - const char *value; - - /* get extent */ - cm->extent.minx = 0.0; - cm->extent.maxx = 0.0; - cm->extent.miny = 0.0; - cm->extent.maxy = 0.0; - if( msOWSGetLayerExtent( layer->map, layer, "CO", &cm->extent ) == MS_FAILURE ) - return MS_FAILURE; - - /* get resolution */ - cm->xresolution = 0.0; - cm->yresolution = 0.0; - if( (value = msOWSLookupMetadata(&(layer->metadata), "CO", "resolution")) != NULL ) { - char **tokens; - int n; - - tokens = msStringSplit(value, ' ', &n); - if( tokens == NULL || n != 2 ) { - msSetError( MS_WCSERR, "Wrong number of arguments for wcs|ows_resolution metadata.", "msWCSGetCoverageMetadata20()"); - msFreeCharArray( tokens, n ); - return MS_FAILURE; - } - cm->xresolution = atof(tokens[0]); - cm->yresolution = atof(tokens[1]); - msFreeCharArray( tokens, n ); - } - - /* get Size (in pixels and lines) */ - cm->xsize = 0; - cm->ysize = 0; - if( (value=msOWSLookupMetadata(&(layer->metadata), "CO", "size")) != NULL ) { - char **tokens; - int n; - - tokens = msStringSplit(value, ' ', &n); - if( tokens == NULL || n != 2 ) { - msSetError( MS_WCSERR, "Wrong number of arguments for wcs|ows_size metadata.", "msWCSGetCoverageMetadata20()"); - msFreeCharArray( tokens, n ); - return MS_FAILURE; - } - cm->xsize = atoi(tokens[0]); - cm->ysize = atoi(tokens[1]); - msFreeCharArray( tokens, n ); - } - - /* try to compute raster size */ - if( cm->xsize == 0 && cm->ysize == 0 && cm->xresolution != 0.0 && cm->yresolution != 0.0 && cm->extent.minx != cm->extent.maxx && cm->extent.miny != cm->extent.maxy ) { - cm->xsize = (int) ((cm->extent.maxx - cm->extent.minx) / cm->xresolution + 0.5); - cm->ysize = (int) fabs((cm->extent.maxy - cm->extent.miny) / cm->yresolution + 0.5); - } - - /* try to compute raster resolution */ - if( (cm->xresolution == 0.0 || cm->yresolution == 0.0) && cm->xsize != 0 && cm->ysize != 0 ) { - cm->xresolution = (cm->extent.maxx - cm->extent.minx) / cm->xsize; - cm->yresolution = (cm->extent.maxy - cm->extent.miny) / cm->ysize; - } - - /* do we have information to do anything */ - if( cm->xresolution == 0.0 || cm->yresolution == 0.0 || cm->xsize == 0 || cm->ysize == 0 ) { - msSetError( MS_WCSERR, "Failed to collect extent and resolution for WCS coverage from metadata for layer '%s'. Need value wcs|ows_resolution or wcs|ows_size values.", "msWCSGetCoverageMetadata20()", layer->name ); - return MS_FAILURE; - } - - /* compute geotransform */ - cm->geotransform[0] = cm->extent.minx; - cm->geotransform[1] = cm->xresolution; - cm->geotransform[2] = 0.0; - cm->geotransform[3] = cm->extent.maxy; - cm->geotransform[4] = 0.0; - cm->geotransform[5] = -fabs(cm->yresolution); - - /* get bands count, or assume 1 if not found */ - cm->numbands = 1; - if( (value = msOWSLookupMetadata(&(layer->metadata), "CO", "bandcount")) != NULL) { - int numbands = 0; - msStringParseInteger(value, &numbands); - cm->numbands = (size_t)numbands; - } - - cm->bands = static_cast(msSmallCalloc(sizeof(wcs20rasterbandMetadataObj), cm->numbands)); - - /* get bands type, or assume float if not found */ - cm->imagemode = MS_IMAGEMODE_FLOAT32; - if( (value = msOWSLookupMetadata(&(layer->metadata), "CO", "imagemode")) != NULL ) { - if( EQUAL(value,"INT16") ) - cm->imagemode = MS_IMAGEMODE_INT16; - else if( EQUAL(value,"FLOAT32") ) - cm->imagemode = MS_IMAGEMODE_FLOAT32; - else if( EQUAL(value,"BYTE") ) - cm->imagemode = MS_IMAGEMODE_BYTE; - else { - msSetError( MS_WCSERR, "Content of wcs|ows_imagemode (%s) not recognised. Should be one of BYTE, INT16 or FLOAT32.", "msWCSGetCoverageMetadata20()", value ); - return MS_FAILURE; - } - } - - if( (value = msOWSLookupMetadata(&(layer->metadata), "CO", "native_format")) != NULL ) { - cm->native_format = msStrdup(value); - } - - /* determine nilvalues and reasons */ - { - int n_nilvalues = 0, n_nilvalues_reasons = 0; - char **t_nilvalues = NULL, **t_nilvalues_reasons = NULL; - if( (value = msOWSLookupMetadata(&(layer->metadata), "CO", "nilvalues")) != NULL ) { - t_nilvalues = msStringSplit(value, ' ', &n_nilvalues); - } else if((value = msOWSLookupMetadata(&(layer->metadata), "CO", "rangeset_nullvalue")) != NULL) { - t_nilvalues = msStringSplit(value, ' ', &n_nilvalues); - } - - if( (value = msOWSLookupMetadata(&(layer->metadata), "CO", "nilvalues_reasons")) != NULL ) { - t_nilvalues_reasons = msStringSplit(value, ' ', &n_nilvalues_reasons); - } - - if(n_nilvalues > 0) { - int i; - cm->numnilvalues = n_nilvalues; - cm->nilvalues = static_cast(msSmallCalloc(sizeof(char*), n_nilvalues)); - cm->nilvalues_reasons = static_cast(msSmallCalloc(sizeof(char*), n_nilvalues)); - for(i = 0; i < n_nilvalues; ++i) { - cm->nilvalues[i] = msStrdup(t_nilvalues[i]); - if(i < n_nilvalues_reasons) { - cm->nilvalues_reasons[i] = msStrdup(t_nilvalues_reasons[i]); - } else { - cm->nilvalues_reasons[i] = msStrdup(""); - } - } - } - msFreeCharArray(t_nilvalues, n_nilvalues); - msFreeCharArray(t_nilvalues_reasons, n_nilvalues_reasons); - } - - { - int num_band_names = 0, j; - char **band_names = NULL; - - const char *wcs11_band_names_key = "rangeset_axes"; - const char *wcs20_band_names_key = "band_names"; - - const char *wcs11_interval_key = "interval"; - const char *wcs20_interval_key = "interval"; - const char *interval_key = NULL; - - const char *significant_figures_key = "significant_figures"; - - const char *wcs11_keys[] = - { "label", "semantic", "values_type", "values_semantic", "description" }; - const char *wcs20_keys[] = - { "band_name", "band_interpretation", "band_uom", "band_definition", "band_description" }; - const char **keys = NULL; - - char **interval_array; - int num_interval; - - wcs20rasterbandMetadataObj default_values; - - /* Decide whether WCS1.1 or WCS2.0 keys should be used */ - if( (value = msOWSLookupMetadata(&(layer->metadata), "CO", wcs20_band_names_key) ) != NULL ) { - keys = wcs20_keys; - interval_key = wcs20_interval_key; - band_names = msStringSplit(value, ' ', &num_band_names); - } else if( (value = msOWSLookupMetadata(&(layer->metadata), "CO", wcs11_band_names_key)) != NULL ) { - keys = wcs11_keys; - interval_key = wcs11_interval_key; - /* "bands" has a special processing in WCS 1.0. See */ - /* msWCSSetDefaultBandsRangeSetInfo */ - if( EQUAL(value, "bands") ) - { - num_band_names = cm->numbands; - band_names = (char**) msSmallMalloc( sizeof(char*) * num_band_names ); - for( int i = 0; i < num_band_names; i++ ) - { - char szName[30]; - snprintf(szName, sizeof(szName), "Band%d", i+1); - band_names[i] = msStrdup(szName); - } - } - else - { - /* WARNING: in WCS 1.x,, "rangeset_axes" has never been intended */ - /* to contain the list of band names... This code should probably */ - /* be removed */ - band_names = msStringSplit(value, ' ', &num_band_names); - } - } - - /* return with error when number of bands does not match */ - /* the number of names */ - if (static_cast(num_band_names) != cm->numbands && num_band_names != 0) { - msFreeCharArray(band_names, num_band_names); - msSetError( MS_WCSERR, - "Wrong number of band names given in layer '%s'. " - "Expected %d, got %d.", "msWCSGetCoverageMetadata20()", - layer->name, (int)cm->numbands, num_band_names ); - return MS_FAILURE; - } - - /* look up default metadata values */ - for(j = 1; j < 5; ++j) { - if(keys != NULL) { - default_values.values[j] = (char *)msOWSLookupMetadata(&(layer->metadata), "CO", keys[j]); - } - } - - /* set default values for interval and significant figures */ - switch(cm->imagemode) { - case MS_IMAGEMODE_BYTE: - default_values.interval_min = 0.; - default_values.interval_max = 255.; - default_values.significant_figures = 3; - break; - case MS_IMAGEMODE_INT16: - default_values.interval_min = 0.; - default_values.interval_max = (double)USHRT_MAX; - default_values.significant_figures = 5; - break; - case MS_IMAGEMODE_FLOAT32: - default_values.interval_min = -FLT_MAX; - default_values.interval_max = FLT_MAX; - default_values.significant_figures = 12; - break; - default: - // other imagemodes are invalid (see above), just keep the compiler happy - msFreeCharArray(band_names, num_band_names); - return MS_FAILURE; - break; - } - - /* lookup default interval values */ - if (interval_key != NULL - && (value = msOWSLookupMetadata(&(layer->metadata), "CO", interval_key)) != NULL) { - interval_array = msStringSplit(value, ' ', &num_interval); - - if (num_interval != 2 - || msStringParseDouble(interval_array[0], &(default_values.interval_min)) != MS_SUCCESS - || msStringParseDouble(interval_array[1], &(default_values.interval_max)) != MS_SUCCESS) { - msFreeCharArray(band_names, num_band_names); - msFreeCharArray(interval_array, num_interval); - msSetError(MS_WCSERR, "Wrong interval format for default axis.", - "msWCSGetCoverageMetadata20()"); - return MS_FAILURE; - } - msFreeCharArray(interval_array, num_interval); - } - - /* lookup default value for significant figures */ - if((value = msOWSLookupMetadata(&(layer->metadata), "CO", significant_figures_key)) != NULL) { - if(msStringParseInteger(value, &(default_values.significant_figures)) != MS_SUCCESS) { - msFreeCharArray(band_names, num_band_names); - msSetError(MS_WCSERR, "Wrong significant figures format " - "for default axis.", - "msWCSGetCoverageMetadata20()"); - return MS_FAILURE; - } - } - - /* iterate over every band */ - for(unsigned i = 0; i < cm->numbands; ++i) { - cm->bands[i].name = NULL; - - /* look up band metadata or copy defaults */ - if(num_band_names != 0) { - cm->bands[i].name = msStrdup(band_names[i]); - for(j = 1; j < 5; ++j) { - value = (char *)msWCSLookupRangesetAxisMetadata20(&(layer->metadata), - cm->bands[i].name, keys[j]); - if(value != NULL) { - cm->bands[i].values[j] = msStrdup(value); - } else if(default_values.values[j] != NULL) { - cm->bands[i].values[j] = msStrdup(default_values.values[j]); - } - } - } - - /* set up interval */ - value = (char *)msWCSLookupRangesetAxisMetadata20(&(layer->metadata), - cm->bands[i].name, interval_key); - if(value != NULL) { - num_interval = 0; - interval_array = msStringSplit(value, ' ', &num_interval); - - if (num_interval != 2 - || msStringParseDouble(interval_array[0], &(cm->bands[i].interval_min)) != MS_SUCCESS - || msStringParseDouble(interval_array[1], &(cm->bands[i].interval_max)) != MS_SUCCESS) { - msFreeCharArray(band_names, num_band_names); - msFreeCharArray(interval_array, num_interval); - msSetError(MS_WCSERR, "Wrong interval format for axis %s.", - "msWCSGetCoverageMetadata20()", cm->bands[i].name); - return MS_FAILURE; - } - - msFreeCharArray(interval_array, num_interval); - } else { - cm->bands[i].interval_min = default_values.interval_min; - cm->bands[i].interval_max = default_values.interval_max; - } - - /* set up significant figures */ - value = (char *)msWCSLookupRangesetAxisMetadata20(&(layer->metadata), - cm->bands[i].name, significant_figures_key); - if(value != NULL) { - if(msStringParseInteger(value, &(cm->bands[i].significant_figures)) != MS_SUCCESS) { - msFreeCharArray(band_names, num_band_names); - msSetError(MS_WCSERR, "Wrong significant figures format " - "for axis %s.", - "msWCSGetCoverageMetadata20()", cm->bands[i].name); - return MS_FAILURE; - } - } else { - cm->bands[i].significant_figures = default_values.significant_figures; - } - } - - msFreeCharArray(band_names, num_band_names); - } - } else if( layer->data == NULL ) { - /* no virtual metadata, not ok unless we're talking 1 image, hopefully we can fix that */ - msSetError( MS_WCSERR, "RASTER Layer with no DATA statement and no WCS virtual dataset metadata. Tileindexed raster layers not supported for WCS without virtual dataset metadata (cm->extent, wcs_res, wcs_size).", "msWCSGetCoverageMetadata20()" ); - return MS_FAILURE; - } else { - /* work from the file (e.g. DATA) */ - GDALDatasetH hDS; - GDALDriverH hDriver; - GDALRasterBandH hBand; - char szPath[MS_MAXPATHLEN]; - const char *driver_short_name, *driver_long_name; - - msGDALInitialize(); - - msTryBuildPath3(szPath, layer->map->mappath, layer->map->shapepath, layer->data); - msAcquireLock( TLOCK_GDAL ); - { - char** connectionoptions = msGetStringListFromHashTable(&(layer->connectionoptions)); - hDS = GDALOpenEx( szPath, GDAL_OF_RASTER, NULL, - (const char* const*)connectionoptions, NULL); - CSLDestroy(connectionoptions); - } - if( hDS == NULL ) { - msReleaseLock( TLOCK_GDAL ); - msSetError( MS_IOERR, "%s", "msWCSGetCoverageMetadata20()", CPLGetLastErrorMsg() ); - return MS_FAILURE; - } - - msGetGDALGeoTransform( hDS, layer->map, layer, cm->geotransform ); - - cm->xsize = GDALGetRasterXSize( hDS ); - cm->ysize = GDALGetRasterYSize( hDS ); - - cm->extent.minx = cm->geotransform[0]; - cm->extent.maxx = cm->geotransform[0] + cm->geotransform[1] * cm->xsize + cm->geotransform[2] * cm->ysize; - cm->extent.miny = cm->geotransform[3] + cm->geotransform[4] * cm->xsize + cm->geotransform[5] * cm->ysize; - cm->extent.maxy = cm->geotransform[3]; - - cm->xresolution = cm->geotransform[1]; - cm->yresolution = cm->geotransform[5]; - - cm->numbands = GDALGetRasterCount( hDS ); - - /* TODO nilvalues? */ - - if( cm->numbands == 0 ) { - msReleaseLock( TLOCK_GDAL ); - msSetError( MS_WCSERR, "Raster file %s has no raster bands. This cannot be used in a layer.", "msWCSGetCoverageMetadata20()", layer->data ); - return MS_FAILURE; - } - - hBand = GDALGetRasterBand( hDS, 1 ); - switch( GDALGetRasterDataType( hBand ) ) { - case GDT_Byte: - cm->imagemode = MS_IMAGEMODE_BYTE; - break; - case GDT_Int16: - cm->imagemode = MS_IMAGEMODE_INT16; - break; - default: - cm->imagemode = MS_IMAGEMODE_FLOAT32; - break; - } - - cm->bands = static_cast(msSmallCalloc(sizeof(wcs20rasterbandMetadataObj), cm->numbands)); - - /* get as much band metadata as possible */ - for(unsigned i = 0; i < cm->numbands; ++i) { - char bandname[32]; - GDALColorInterp colorInterp; - hBand = GDALGetRasterBand(hDS, i + 1); - snprintf(bandname, sizeof(bandname), "band%d", i+1); - cm->bands[i].name = msStrdup(bandname); - colorInterp = GDALGetRasterColorInterpretation(hBand); - cm->bands[i].interpretation = msStrdup(GDALGetColorInterpretationName(colorInterp)); - cm->bands[i].uom = msStrdup(GDALGetRasterUnitType(hBand)); - if(strlen(cm->bands[i].uom) == 0) { - msFree(cm->bands[i].uom); - cm->bands[i].uom = NULL; - } - - /* set up interval and significant figures */ - switch(cm->imagemode) { - case MS_IMAGEMODE_BYTE: - case MS_IMAGEMODE_PC256: - cm->bands[i].interval_min = 0.; - cm->bands[i].interval_max = 255.; - cm->bands[i].significant_figures = 3; - break; - case MS_IMAGEMODE_INT16: - cm->bands[i].interval_min = 0.; - cm->bands[i].interval_max = (double)USHRT_MAX; - cm->bands[i].significant_figures = 5; - break; - case MS_IMAGEMODE_FLOAT32: - cm->bands[i].interval_min = -FLT_MAX; - cm->bands[i].interval_max = FLT_MAX; - cm->bands[i].significant_figures = 12; - break; - } - } - - hDriver = GDALGetDatasetDriver(hDS); - driver_short_name = GDALGetDriverShortName(hDriver); - driver_long_name = GDALGetDriverLongName(hDriver); - /* TODO: improve this, exchange strstr() */ - for(int i = 0; i < layer->map->numoutputformats; ++i) { - if(strstr( layer->map->outputformatlist[i]->driver, driver_short_name) != NULL - || strstr(layer->map->outputformatlist[i]->driver, driver_long_name) != NULL) { - cm->native_format = msStrdup(layer->map->outputformatlist[i]->mimetype); - break; - } - } - - GDALClose( hDS ); - msReleaseLock( TLOCK_GDAL ); - } - - return MS_SUCCESS; -} - -/************************************************************************/ -/* msWCSClearCoverageMetadata20() */ -/* */ -/* Returns all dynamically allocated memory from a coverage meta- */ -/* data object. */ -/************************************************************************/ - -static int msWCSClearCoverageMetadata20(wcs20coverageMetadataObj *cm) -{ - msFree(cm->native_format); - for(unsigned i = 0; i < cm->numnilvalues; ++i) { - msFree(cm->nilvalues[i]); - msFree(cm->nilvalues_reasons[i]); - } - msFree(cm->nilvalues); - msFree(cm->nilvalues_reasons); - - for(unsigned i = 0; i < cm->numbands; ++i) { - for(int j = 0; j < 5; ++j) { - msFree(cm->bands[i].values[j]); - } - } - msFree(cm->bands); - msFree(cm->srs_epsg); - return MS_SUCCESS; -} - -/************************************************************************/ -/* msWCSException20() */ -/* */ -/* Writes out an OWS compliant exception. */ -/************************************************************************/ - -int msWCSException20(mapObj *map, const char *exceptionCode, - const char *locator, const char *version) -{ - int size = 0; - const char *status = "400 Bad Request"; - char *errorString = NULL; - char *schemasLocation = NULL; - char *xsi_schemaLocation = NULL; - char version_string[OWS_VERSION_MAXLEN]; - - xmlDocPtr psDoc = NULL; - xmlNodePtr psRootNode = NULL; - xmlNodePtr psMainNode = NULL; - xmlNsPtr psNsOws = NULL; - xmlNsPtr psNsXsi = NULL; - xmlChar *buffer = NULL; - - errorString = msGetErrorString("\n"); - schemasLocation = msEncodeHTMLEntities(msOWSGetSchemasLocation(map)); - - psDoc = xmlNewDoc(BAD_CAST "1.0"); - - psRootNode = xmlNewNode(NULL, BAD_CAST "ExceptionReport"); - psNsOws = xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_OWS_20_NAMESPACE_URI, - BAD_CAST MS_OWSCOMMON_OWS_NAMESPACE_PREFIX); - xmlSetNs(psRootNode, psNsOws); - - psNsXsi = xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_W3C_XSI_NAMESPACE_URI, BAD_CAST MS_OWSCOMMON_W3C_XSI_NAMESPACE_PREFIX); - - /* add attributes to root element */ - xmlNewProp(psRootNode, BAD_CAST "version", BAD_CAST version); - xmlNewProp(psRootNode, BAD_CAST "xml:lang", BAD_CAST msOWSGetLanguage(map, "exception")); - - /* get 2 digits version string: '2.0' */ - msOWSGetVersionString(OWS_2_0_0, version_string); - version_string[3]= '\0'; - - xsi_schemaLocation = msStrdup((char *)psNsOws->href); - xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, " "); - xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, (char *)schemasLocation); - xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, "/ows/"); - xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, version_string); - xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, "/owsExceptionReport.xsd"); - - /* add namespace'd attributes to root element */ - xmlNewNsProp(psRootNode, psNsXsi, BAD_CAST "schemaLocation", BAD_CAST xsi_schemaLocation); - - /* add child element */ - psMainNode = xmlNewChild(psRootNode, NULL, BAD_CAST "Exception", NULL); - - /* add attributes to child */ - xmlNewProp(psMainNode, BAD_CAST "exceptionCode", BAD_CAST exceptionCode); - - if (locator != NULL) { - xmlNewProp(psMainNode, BAD_CAST "locator", BAD_CAST locator); - } - - if (errorString != NULL) { - char* errorMessage = msEncodeHTMLEntities(errorString); - xmlNewChild(psMainNode, NULL, BAD_CAST "ExceptionText", BAD_CAST errorMessage); - msFree(errorMessage); - } - - /*psRootNode = msOWSCommonExceptionReport(psNsOws, OWS_2_0_0, - schemasLocation, version, msOWSGetLanguage(map, "exception"), - exceptionCode, locator, errorMessage);*/ - - xmlDocSetRootElement(psDoc, psRootNode); - - if (exceptionCode == NULL) { - /* Do nothing */ - } - else if(EQUAL(exceptionCode, "OperationNotSupported") - || EQUAL(exceptionCode, "OptionNotSupported")) { - status = "501 Not Implemented"; - } - else if (EQUAL(exceptionCode, "NoSuchCoverage") - || EQUAL(exceptionCode, "emptyCoverageIdList") - || EQUAL(exceptionCode, "InvalidAxisLabel") - || EQUAL(exceptionCode, "InvalidSubsetting")) { - status = "404 Not Found"; - } - - msIO_setHeader("Status", "%s", status); - msIO_setHeader("Content-Type","text/xml; charset=UTF-8"); - msIO_sendHeaders(); - - xmlDocDumpFormatMemoryEnc(psDoc, &buffer, &size, "UTF-8", 1); - - msIO_printf("%s", buffer); - - /* free buffer and the document */ - free(errorString); - free(schemasLocation); - free(xsi_schemaLocation); - xmlFree(buffer); - xmlFreeDoc(psDoc); - - /* clear error since we have already reported it */ - msResetErrorList(); - return MS_FAILURE; -} - -#define MAX_MIMES 20 - -static int msWCSGetCapabilities20_CreateProfiles( - mapObj *map, xmlNodePtr psServiceIdentification, xmlNsPtr psOwsNs) -{ - xmlNodePtr psProfile, psTmpNode; - char *available_mime_types[MAX_MIMES]; - int i = 0; - - /* even indices are urls, uneven are mime-types, or null*/ - const char * const urls_and_mime_types[] = { - MS_WCS_20_PROFILE_CORE, NULL, - MS_WCS_20_PROFILE_KVP, NULL, - MS_WCS_20_PROFILE_POST, NULL, - MS_WCS_20_PROFILE_GML, NULL, - MS_WCS_20_PROFILE_GML_MULTIPART, NULL, - MS_WCS_20_PROFILE_GML_SPECIAL, NULL, - MS_WCS_20_PROFILE_GML_GEOTIFF, "image/tiff", - MS_WCS_20_PROFILE_CRS, NULL, - MS_WCS_20_PROFILE_SCALING, NULL, - MS_WCS_20_PROFILE_RANGESUBSET, NULL, - MS_WCS_20_PROFILE_INTERPOLATION, NULL, - NULL, NULL /* guardian */ - }; - - /* navigate to node where profiles shall be inserted */ - for(psTmpNode = psServiceIdentification->children; psTmpNode->next != NULL; psTmpNode = psTmpNode->next) { - if(EQUAL((char *)psTmpNode->name, "ServiceTypeVersion") && !EQUAL((char *)psTmpNode->next->name, "ServiceTypeVersion")) - break; - } - - /* get list of all available mime types */ - msGetOutputFormatMimeList(map, available_mime_types, MAX_MIMES); - - while(urls_and_mime_types[i] != NULL) { - const char* mime_type = urls_and_mime_types[i+1]; - - /* check if there is a mime type */ - if(mime_type != NULL) { - /* check if the mime_type is in the list of outputformats */ - if(CSLPartialFindString(available_mime_types, mime_type) == -1) - continue; - } - - /* create a new node and attach it in the tree */ - psProfile = xmlNewNode(psOwsNs, BAD_CAST "Profile"); - xmlNodeSetContent(psProfile, BAD_CAST urls_and_mime_types[i]); - xmlAddNextSibling(psTmpNode, psProfile); - - psTmpNode = psProfile; - i += 2; - } - return MS_SUCCESS; -} - -/************************************************************************/ -/* msWCSGetCapabilities20_CoverageSummary() */ -/* */ -/* Helper function to create a short summary for a specific */ -/* coverage. */ -/************************************************************************/ - -static int msWCSGetCapabilities20_CoverageSummary( - mapObj *map, wcs20ParamsObjPtr params, - xmlDocPtr doc, xmlNodePtr psContents, layerObj *layer ) -{ - wcs20coverageMetadataObj cm; - int status; - xmlNodePtr psCSummary; - - xmlNsPtr psWcsNs = xmlSearchNs( doc, xmlDocGetRootElement(doc), BAD_CAST "wcs" ); - - status = msWCSGetCoverageMetadata20(layer, &cm); - if(status != MS_SUCCESS) return MS_FAILURE; - - psCSummary = xmlNewChild( psContents, psWcsNs, BAD_CAST "CoverageSummary", NULL ); - xmlNewChild(psCSummary, psWcsNs, BAD_CAST "CoverageId", BAD_CAST layer->name); - xmlNewChild(psCSummary, psWcsNs, BAD_CAST "CoverageSubtype", BAD_CAST "RectifiedGridCoverage"); - - msWCS_11_20_PrintMetadataLinks(layer, doc, psCSummary); - - msWCSClearCoverageMetadata20(&cm); - - return MS_SUCCESS; -} - - -/************************************************************************/ -/* msWCSAddInspireDSID20 */ -/************************************************************************/ - -static void msWCSAddInspireDSID20(mapObj *map, - xmlNsPtr psNsInspireDls, - xmlNsPtr psNsInspireCommon, - xmlNodePtr pDlsExtendedCapabilities) -{ - const char* dsid_code = msOWSLookupMetadata(&(map->web.metadata), "CO", "inspire_dsid_code"); - const char* dsid_ns = msOWSLookupMetadata(&(map->web.metadata), "CO", "inspire_dsid_ns"); - if( dsid_code == NULL ) - { - xmlAddChild(pDlsExtendedCapabilities, xmlNewComment(BAD_CAST "WARNING: Required metadata \"inspire_dsid_code\" missing")); - } - else - { - int ntokensCode = 0, ntokensNS = 0; - char** tokensCode; - char** tokensNS = NULL; - int i; - - tokensCode = msStringSplit(dsid_code, ',', &ntokensCode); - if( dsid_ns != NULL ) - tokensNS = msStringSplitComplex( dsid_ns, ",", &ntokensNS, MS_ALLOWEMPTYTOKENS); - if( ntokensNS > 0 && ntokensNS != ntokensCode ) - { - xmlAddChild(pDlsExtendedCapabilities, - xmlNewComment(BAD_CAST "WARNING: \"inspire_dsid_code\" and \"inspire_dsid_ns\" have not the same number of elements. Ignoring inspire_dsid_ns")); - msFreeCharArray(tokensNS, ntokensNS); - tokensNS = NULL; - ntokensNS = 0; - } - for(i = 0; i 0 && tokensNS[i][0] != '\0' ) - xmlNewTextChild(pSDSI, psNsInspireCommon, BAD_CAST "Namespace", BAD_CAST tokensNS[i]); - } - msFreeCharArray(tokensCode, ntokensCode); - if( ntokensNS > 0 ) - msFreeCharArray(tokensNS, ntokensNS); - } -} - - -/************************************************************************/ -/* msWCSGetCapabilities20() */ -/* */ -/* Performs the GetCapabilities operation. Writes out a xml */ -/* structure with server specific information and a summary */ -/* of all available coverages. */ -/************************************************************************/ - -int msWCSGetCapabilities20(mapObj *map, cgiRequestObj *req, - wcs20ParamsObjPtr params, owsRequestObj *ows_request) -{ - xmlDocPtr psDoc = NULL; /* document pointer */ - xmlNodePtr psRootNode, - psOperationsNode, - psNode; - const char *updatesequence = NULL; - xmlNsPtr psOwsNs = NULL, - psXLinkNs = NULL, - psWcsNs = NULL, - psCrsNs = NULL, - psIntNs = NULL; - char *script_url=NULL, *script_url_encoded=NULL, *format_list=NULL; - int i; - xmlDocPtr pInspireTmpDoc = NULL; - - const char *inspire_capabilities = msOWSLookupMetadata(&(map->web.metadata), "CO", "inspire_capabilities"); - - char *validated_language = msOWSLanguageNegotiation(map, "CO", params->accept_languages, CSLCount(params->accept_languages)); - - /* -------------------------------------------------------------------- */ - /* Create document. */ - /* -------------------------------------------------------------------- */ - psDoc = xmlNewDoc(BAD_CAST "1.0"); - - psRootNode = xmlNewNode(NULL, BAD_CAST "Capabilities"); - - xmlDocSetRootElement(psDoc, psRootNode); - - /* -------------------------------------------------------------------- */ - /* Name spaces */ - /* -------------------------------------------------------------------- */ - - msWCSPrepareNamespaces20(psDoc, psRootNode, map, inspire_capabilities != NULL); - - /* lookup namespaces */ - psOwsNs = xmlSearchNs( psDoc, psRootNode, BAD_CAST MS_OWSCOMMON_OWS_NAMESPACE_PREFIX ); - psWcsNs = xmlSearchNs( psDoc, psRootNode, BAD_CAST MS_OWSCOMMON_WCS_NAMESPACE_PREFIX ); - xmlSearchNs( psDoc, psRootNode, BAD_CAST MS_OWSCOMMON_GML_NAMESPACE_PREFIX ); - psXLinkNs = xmlSearchNs( psDoc, psRootNode, BAD_CAST "xlink" ); - psCrsNs = xmlNewNs(psRootNode, BAD_CAST "http://www.opengis.net/wcs/crs/1.0", BAD_CAST "crs"); - psIntNs = xmlNewNs(psRootNode, BAD_CAST "http://www.opengis.net/wcs/interpolation/1.0", BAD_CAST "int"); - - xmlSetNs(psRootNode, psWcsNs); - - xmlNewProp(psRootNode, BAD_CAST "version", BAD_CAST params->version ); - - updatesequence = msOWSLookupMetadata(&(map->web.metadata), "CO", "updatesequence"); - if (params->updatesequence != NULL) { - i = msOWSNegotiateUpdateSequence(params->updatesequence, updatesequence); - if (i == 0) { /* current */ - msSetError(MS_WCSERR, "UPDATESEQUENCE parameter (%s) is equal to server (%s)", - "msWCSGetCapabilities20()", params->updatesequence, updatesequence); - xmlFreeDoc(psDoc); - return msWCSException(map, "CurrentUpdateSequence", "updatesequence", - params->version); - } - if (i > 0) { /* invalid */ - msSetError(MS_WCSERR, "UPDATESEQUENCE parameter (%s) is higher than server (%s)", - "msWCSGetCapabilities20()", params->updatesequence, updatesequence); - xmlFreeDoc(psDoc); - return msWCSException(map, "InvalidUpdateSequence", "updatesequence", - params->version); - } - } - if(updatesequence != NULL) { - xmlNewProp(psRootNode, BAD_CAST "updateSequence", BAD_CAST updatesequence); - } - - /* -------------------------------------------------------------------- */ - /* Service identification. */ - /* -------------------------------------------------------------------- */ - if ( MS_WCS_20_CAPABILITIES_INCLUDE_SECTION(params, "ServiceIdentification") ) { - psNode = xmlAddChild(psRootNode, msOWSCommonServiceIdentification( - psOwsNs, map, "OGC WCS", "2.0.1,1.1.1,1.0.0", "CO", validated_language)); - msWCSGetCapabilities20_CreateProfiles(map, psNode, psOwsNs); - } - - /* Service Provider */ - if ( MS_WCS_20_CAPABILITIES_INCLUDE_SECTION(params, "ServiceProvider") ) { - xmlAddChild(psRootNode, - msOWSCommonServiceProvider(psOwsNs, psXLinkNs, map, "CO", validated_language)); - } - - /* -------------------------------------------------------------------- */ - /* Operations metadata. */ - /* -------------------------------------------------------------------- */ - if ( MS_WCS_20_CAPABILITIES_INCLUDE_SECTION(params, "OperationsMetadata") ) { - if ((script_url = msOWSGetOnlineResource(map, "CO", "onlineresource", req)) == NULL - || (script_url_encoded = msEncodeHTMLEntities(script_url)) == NULL) { - xmlFreeDoc(psDoc); - msSetError(MS_WCSERR, "Server URL not found", "msWCSGetCapabilities20()"); - return msWCSException(map, "NoApplicableCode", "mapserv", params->version); - } - free(script_url); - - psOperationsNode = xmlAddChild(psRootNode,msOWSCommonOperationsMetadata(psOwsNs)); - - /* -------------------------------------------------------------------- */ - /* GetCapabilities - add Sections and AcceptVersions? */ - /* -------------------------------------------------------------------- */ - psNode = msOWSCommonOperationsMetadataOperation( - psOwsNs, psXLinkNs, - "GetCapabilities", OWS_METHOD_GETPOST, script_url_encoded); - - xmlAddChild(psNode->last->last->last, - msOWSCommonOperationsMetadataDomainType(OWS_2_0_0, psOwsNs, "Constraint", - "PostEncoding", "XML")); - xmlAddChild(psOperationsNode, psNode); - - /* -------------------------------------------------------------------- */ - /* DescribeCoverage */ - /* -------------------------------------------------------------------- */ - if (msOWSRequestIsEnabled(map, NULL, "C", "DescribeCoverage", MS_FALSE)) { - psNode = msOWSCommonOperationsMetadataOperation( - psOwsNs, psXLinkNs, - "DescribeCoverage", OWS_METHOD_GETPOST, script_url_encoded); - xmlAddChild(psNode->last->last->last, - msOWSCommonOperationsMetadataDomainType(OWS_2_0_0, psOwsNs, "Constraint", - "PostEncoding", "XML")); - xmlAddChild(psOperationsNode, psNode); - } - - /* -------------------------------------------------------------------- */ - /* GetCoverage */ - /* -------------------------------------------------------------------- */ - if (msOWSRequestIsEnabled(map, NULL, "C", "GetCoverage", MS_FALSE)) { - psNode = msOWSCommonOperationsMetadataOperation( - psOwsNs, psXLinkNs, - "GetCoverage", OWS_METHOD_GETPOST, script_url_encoded); - - xmlAddChild(psNode->last->last->last, - msOWSCommonOperationsMetadataDomainType(OWS_2_0_0, psOwsNs, "Constraint", - "PostEncoding", "XML")); - xmlAddChild(psOperationsNode, psNode); - } - msFree(script_url_encoded); - - - /* -------------------------------------------------------------------- */ - /* Extended Capabilities for inspire */ - /* -------------------------------------------------------------------- */ - - if (inspire_capabilities) { - msIOContext* old_context; - msIOContext* new_context; - msIOBuffer* buffer; - - xmlNodePtr pRoot; - xmlNodePtr pOWSExtendedCapabilities; - xmlNodePtr pDlsExtendedCapabilities; - xmlNodePtr pChild; - - xmlNsPtr psInspireCommonNs = xmlSearchNs( psDoc, psRootNode, BAD_CAST MS_INSPIRE_COMMON_NAMESPACE_PREFIX ); - xmlNsPtr psInspireDlsNs = xmlSearchNs( psDoc, psRootNode, BAD_CAST MS_INSPIRE_DLS_NAMESPACE_PREFIX ); - - - old_context = msIO_pushStdoutToBufferAndGetOldContext(); - msOWSPrintInspireCommonExtendedCapabilities(stdout, map, "CO", OWS_WARN, - "foo", - "xmlns:" MS_INSPIRE_COMMON_NAMESPACE_PREFIX "=\"" MS_INSPIRE_COMMON_NAMESPACE_URI "\" " - "xmlns:" MS_INSPIRE_DLS_NAMESPACE_PREFIX "=\"" MS_INSPIRE_DLS_NAMESPACE_URI "\" " - "xmlns:xsi=\"" MS_OWSCOMMON_W3C_XSI_NAMESPACE_URI "\"", validated_language, OWS_WCS); - - new_context = msIO_getHandler(stdout); - buffer = (msIOBuffer *) new_context->cbData; - - /* Remove spaces between > and < to get properly indented result */ - msXMLStripIndentation( (char*) buffer->data ); - - pInspireTmpDoc = xmlParseDoc((const xmlChar *)buffer->data); - pRoot = xmlDocGetRootElement(pInspireTmpDoc); - xmlReconciliateNs(psDoc, pRoot); - - pOWSExtendedCapabilities = xmlNewNode(psOwsNs, BAD_CAST "ExtendedCapabilities"); - xmlAddChild(psOperationsNode, pOWSExtendedCapabilities); - - pDlsExtendedCapabilities = xmlNewNode(psInspireDlsNs, BAD_CAST "ExtendedCapabilities"); - xmlAddChild(pOWSExtendedCapabilities, pDlsExtendedCapabilities); - - pChild = pRoot->children; - while(pChild != NULL) - { - xmlNodePtr pNext = pChild->next; - xmlUnlinkNode(pChild); - xmlAddChild(pDlsExtendedCapabilities, pChild); - pChild = pNext; - } - - msWCSAddInspireDSID20(map, psInspireDlsNs, psInspireCommonNs, pDlsExtendedCapabilities); - - msIO_restoreOldStdoutContext(old_context); - } - } - - /* -------------------------------------------------------------------- */ - /* Service metadata. */ - /* -------------------------------------------------------------------- */ - - if ( MS_WCS_20_CAPABILITIES_INCLUDE_SECTION(params, "ServiceMetadata") ) { - xmlNodePtr psExtensionNode = NULL; - psNode = xmlNewChild(psRootNode, psWcsNs, BAD_CAST "ServiceMetadata", NULL); - - /* Apply default formats */ - msApplyDefaultOutputFormats(map); - - /* Add formats list */ - format_list = msWCSGetFormatsList20(map, NULL); - msLibXml2GenerateList(psNode, psWcsNs, "formatSupported", format_list, ','); - msFree(format_list); - - psExtensionNode = xmlNewChild(psNode, psWcsNs, BAD_CAST "Extension", NULL); - /* interpolations supported */ - { - /* TODO: use URIs/URLs once they are specified */ - const char * const interpolation_methods[] = {"NEAREST", "AVERAGE", "BILINEAR"}; - int i; - xmlNodePtr imNode = xmlNewChild(psExtensionNode, psIntNs, - BAD_CAST "InterpolationMetadata", NULL); - - for (i=0; i < 3; ++i) { - xmlNewChild(imNode, psIntNs, BAD_CAST "InterpolationSupported", - BAD_CAST interpolation_methods[i]); - } - } - - /* Report the supported CRSs */ - { - char *crs_list = NULL; - xmlNodePtr crsMetadataNode = xmlNewChild(psExtensionNode, psCrsNs, - BAD_CAST "CrsMetadata", NULL); - - if((crs_list = msOWSGetProjURI(&(map->projection), - &(map->web.metadata), - "CO", MS_FALSE)) != NULL ) { - msLibXml2GenerateList(crsMetadataNode, psCrsNs, "crsSupported", - crs_list, ' '); - msFree(crs_list); - } else { - /* could not determine list of CRSs */ - } - } - } - - /* -------------------------------------------------------------------- */ - /* Contents section. */ - /* -------------------------------------------------------------------- */ - if ( MS_WCS_20_CAPABILITIES_INCLUDE_SECTION(params, "Contents") ) { - psNode = xmlNewChild( psRootNode, psWcsNs, BAD_CAST "Contents", NULL ); - - if(ows_request->numlayers == 0) { - xmlAddChild(psNode, - xmlNewComment(BAD_CAST("WARNING: No WCS layers are enabled. " - "Check wcs/ows_enable_request settings."))); - } else { - for(i = 0; i < map->numlayers; ++i) { - layerObj *layer = map->layers[i]; - int status; - - if(!msWCSIsLayerSupported(layer)) - continue; - - if (!msIntegerInArray(layer->index, ows_request->enabled_layers, ows_request->numlayers)) - continue; - - status = msWCSGetCapabilities20_CoverageSummary( - map, params, psDoc, psNode, layer ); - if(status != MS_SUCCESS) { - xmlFreeDoc(psDoc); - xmlCleanupParser(); - return msWCSException(map, "Internal", "mapserv", params->version); - } - } - } - } - /* -------------------------------------------------------------------- */ - /* Write out the document and clean up. */ - /* -------------------------------------------------------------------- */ - msWCSWriteDocument20(map, psDoc); - msFree(validated_language); - xmlFreeDoc(psDoc); - if( pInspireTmpDoc ) - xmlFreeDoc(pInspireTmpDoc); - xmlCleanupParser(); - return MS_SUCCESS; -} - -/************************************************************************/ -/* msWCSDescribeCoverage20_CoverageDescription() */ -/* */ -/* Creates a description of a specific coverage with the three */ -/* major sections: BoundedBy, DomainSet and RangeType. */ -/************************************************************************/ - -static int msWCSDescribeCoverage20_CoverageDescription(mapObj *map, - layerObj *layer, wcs20ParamsObjPtr params, xmlDocPtr psDoc, xmlNodePtr psRootNode ) -{ - int status, swapAxes; - wcs20coverageMetadataObj cm; - xmlNodePtr psCD; - xmlNsPtr psWcsNs, psGmlNs, psGmlcovNs, psSweNs, psXLinkNs; - psWcsNs = psGmlNs = psGmlcovNs = psSweNs = psXLinkNs = NULL; - - psWcsNs = xmlSearchNs(psDoc, xmlDocGetRootElement(psDoc), BAD_CAST MS_OWSCOMMON_WCS_NAMESPACE_PREFIX); - psGmlNs = xmlSearchNs(psDoc, xmlDocGetRootElement(psDoc), BAD_CAST MS_OWSCOMMON_GML_NAMESPACE_PREFIX); - psGmlcovNs = xmlSearchNs(psDoc, xmlDocGetRootElement(psDoc), BAD_CAST MS_OWSCOMMON_GMLCOV_NAMESPACE_PREFIX); - psSweNs = xmlSearchNs(psDoc, xmlDocGetRootElement(psDoc), BAD_CAST MS_OWSCOMMON_SWE_NAMESPACE_PREFIX); - psXLinkNs = xmlSearchNs(psDoc, xmlDocGetRootElement(psDoc), BAD_CAST MS_OWSCOMMON_W3C_XLINK_NAMESPACE_PREFIX); - - /* -------------------------------------------------------------------- */ - /* Verify layer is processable. */ - /* -------------------------------------------------------------------- */ - if( msCheckParentPointer(layer->map,"map") == MS_FAILURE ) - return MS_FAILURE; - - if(!msWCSIsLayerSupported(layer)) - return MS_SUCCESS; - - /* -------------------------------------------------------------------- */ - /* Setup coverage metadata. */ - /* -------------------------------------------------------------------- */ - status = msWCSGetCoverageMetadata20(layer, &cm); - if(status != MS_SUCCESS) - return status; - - swapAxes = msWCSSwapAxes20(cm.srs_uri); - - /* fill in bands rangeset info, if required. */ - /* msWCSSetDefaultBandsRangeSetInfo( NULL, &cm, layer ); */ - - /* -------------------------------------------------------------------- */ - /* Create CoverageDescription node. */ - /* -------------------------------------------------------------------- */ - psCD = xmlNewChild( psRootNode, psWcsNs, BAD_CAST "CoverageDescription", NULL ); - xmlNewNsProp(psCD, psGmlNs, BAD_CAST "id", BAD_CAST layer->name); - - /* -------------------------------------------------------------------- */ - /* gml:boundedBy */ - /* -------------------------------------------------------------------- */ - msWCSCommon20_CreateBoundedBy(layer, &cm, psGmlNs, psCD, &(layer->projection), swapAxes); - - xmlNewChild(psCD, psWcsNs, BAD_CAST "CoverageId", BAD_CAST layer->name); - - /* -------------------------------------------------------------------- */ - /* gml:domainSet */ - /* -------------------------------------------------------------------- */ - msWCSCommon20_CreateDomainSet(layer, &cm, psGmlNs, psCD, &(layer->projection), swapAxes); - - /* -------------------------------------------------------------------- */ - /* gmlcov:rangeType */ - /* -------------------------------------------------------------------- */ - msWCSCommon20_CreateRangeType(layer, &cm, NULL, psGmlNs, psGmlcovNs, psSweNs, psXLinkNs, psCD); - - /* -------------------------------------------------------------------- */ - /* wcs:ServiceParameters */ - /* -------------------------------------------------------------------- */ - { - xmlNodePtr psSP; - - psSP = xmlNewChild( psCD, psWcsNs, BAD_CAST "ServiceParameters", NULL); - xmlNewChild(psSP, psWcsNs, BAD_CAST "CoverageSubtype", BAD_CAST "RectifiedGridCoverage"); - - /* -------------------------------------------------------------------- */ - /* SupportedCRS */ - /* -------------------------------------------------------------------- */ - /* for now, WCS 2.0 does not allow per coverage CRS definitions */ - /*{ - xmlNodePtr psSupportedCrss; - char *owned_value; - - psSupportedCrss = xmlNewChild(psSP, psWcsNs, - BAD_CAST "SupportedCRSs", NULL); - - if ((owned_value = msOWSGetProjURI(&(layer->projection), - &(layer->metadata), "CO", MS_FALSE)) != NULL) - { } - else if ((owned_value = msOWSGetProjURI(&(layer->map->projection), - &(layer->map->web.metadata), "CO", MS_FALSE)) != NULL) - { } - else { - msDebug("missing required information, no SRSs defined.\n"); - } - - if (owned_value != NULL && strlen(owned_value) > 0) { - msLibXml2GenerateList(psSupportedCrss, psWcsNs, - "SupportedCRS", owned_value, ' '); - } - - xmlNewChild(psSupportedCrss, psWcsNs, - BAD_CAST "NativeCRS", BAD_CAST cm.srs_uri); - - msFree(owned_value); - }*/ - - /* -------------------------------------------------------------------- */ - /* SupportedFormats */ - /* -------------------------------------------------------------------- */ - /* for now, WCS 2.0 does not allow per coverage format definitions */ - /*{ - xmlNodePtr psSupportedFormats; - char *format_list; - - psSupportedFormats = - xmlNewChild(psSP, psWcsNs, BAD_CAST "SupportedFormats", NULL); - - format_list = msWCSGetFormatsList20(layer->map, layer); - - if (strlen(format_list) > 0) { - msLibXml2GenerateList(psSupportedFormats, psWcsNs, - "SupportedFormat", format_list, ','); - - msFree(format_list); - }*/ - - - /* -------------------------------------------------------------------- */ - /* nativeFormat */ - /* -------------------------------------------------------------------- */ - xmlNewChild(psSP, psWcsNs, - BAD_CAST "nativeFormat", BAD_CAST (cm.native_format ? - cm.native_format : "")); - - if (!cm.native_format) { - msDebug("msWCSDescribeCoverage20_CoverageDescription(): " - "No native format specified.\n"); - } - } - - msWCSClearCoverageMetadata20(&cm); - - return MS_SUCCESS; -} - -/************************************************************************/ -/* msWCSDescribeCoverage20() */ -/* */ -/* Implementation of the DescibeCoverage Operation. The result */ -/* of this operation is a xml document, containing specific */ -/* information about a coverage identified by an ID. The result */ -/* is written on the stream. */ -/************************************************************************/ - -int msWCSDescribeCoverage20(mapObj *map, wcs20ParamsObjPtr params, owsRequestObj *ows_request) -{ - xmlDocPtr psDoc = NULL; /* document pointer */ - xmlNodePtr psRootNode; - xmlNsPtr psWcsNs = NULL; - int i, j; - - /* create DOM document and root node */ - psDoc = xmlNewDoc(BAD_CAST "1.0"); - psRootNode = xmlNewNode(NULL, BAD_CAST "CoverageDescriptions"); - xmlDocSetRootElement(psDoc, psRootNode); - - /* prepare initial namespace definitions */ - msWCSPrepareNamespaces20(psDoc, psRootNode, map, MS_FALSE); - - psWcsNs = xmlSearchNs(psDoc, psRootNode, - BAD_CAST MS_OWSCOMMON_WCS_NAMESPACE_PREFIX); - xmlSetNs(psRootNode, psWcsNs); - - /* check if IDs are given */ - if (params->ids) { - /* for each given ID in the ID-list */ - for (j = 0; params->ids[j]; j++) { - i = msGetLayerIndex(map, params->ids[j]); - if (i == -1 || (!msIntegerInArray(GET_LAYER(map, i)->index, ows_request->enabled_layers, ows_request->numlayers)) ) { - msSetError(MS_WCSERR, "Unknown coverage: (%s)", - "msWCSDescribeCoverage20()", params->ids[j]); - return msWCSException(map, "NoSuchCoverage", "coverage", - params->version); - } - /* create coverage description for the specified layer */ - if(msWCSDescribeCoverage20_CoverageDescription(map, (GET_LAYER(map, i)), - params, psDoc, psRootNode) == MS_FAILURE) { - msSetError(MS_WCSERR, "Error retrieving coverage description.", "msWCSDescribeCoverage20()"); - return msWCSException(map, "MissingParameterValue", "coverage", - params->version); - } - } - } else { - /* Throw error, since IDs are mandatory */ - msSetError(MS_WCSERR, "Missing COVERAGEID parameter.", "msWCSDescribeCoverage20()"); - return msWCSException(map, "MissingParameterValue", "coverage", - params->version); - } - - /* write out the DOM document to the stream */ - msWCSWriteDocument20(map, psDoc); - - /* cleanup */ - xmlFreeDoc(psDoc); - xmlCleanupParser(); - - return MS_SUCCESS; -} - -/************************************************************************/ -/* msWCSGetCoverage_FinalizeParamsObj20() */ -/* */ -/* Finalizes a wcs20ParamsObj for a GetCoverage operation. In the */ -/* process, the params boundig box is adjusted to the subsets, */ -/* width, height and resolution are determined and the subset crs */ -/* is found out. */ -/************************************************************************/ - -static int msWCSGetCoverage20_FinalizeParamsObj(wcs20ParamsObjPtr params, wcs20AxisObjPtr *axes) -{ - char *crs = NULL; - int have_scale, have_size, have_resolution; - int have_global_scale = (params->scale != MS_WCS20_UNBOUNDED) ? 1 : 0; - - if (axes[0] != NULL) { - if(axes[0]->subset != NULL) { - msDebug("Subset for X-axis found: %s\n", axes[0]->subset->axis); - if (!axes[0]->subset->min.unbounded) - params->bbox.minx = axes[0]->subset->min.scalar; - if (!axes[0]->subset->max.unbounded) - params->bbox.maxx = axes[0]->subset->max.scalar; - crs = axes[0]->subset->crs; - } - params->width = axes[0]->size; - params->resolutionX = axes[0]->resolution; - params->scaleX = axes[0]->scale; - - if(axes[0]->resolutionUOM != NULL) { - params->resolutionUnits = msStrdup(axes[0]->resolutionUOM); - } - - have_scale = (params->scaleX != MS_WCS20_UNBOUNDED) ? 1 : 0; - have_size = (params->width != 0) ? 1 : 0; - have_resolution = (params->resolutionX != MS_WCS20_UNBOUNDED) ? 1 : 0; - - if ((have_global_scale + have_scale + have_size + have_resolution) > 1) { - msSetError(MS_WCSERR, "Axis '%s' defines scale, size and/or resolution multiple times.", - "msWCSGetCoverage20_FinalizeParamsObj()", axes[0]->name); - return MS_FAILURE; - } - } - - if (axes[1] != NULL) { - if(axes[1]->subset != NULL) { - msDebug("Subset for Y-axis found: %s\n", axes[1]->subset->axis); - if (!axes[1]->subset->min.unbounded) - params->bbox.miny = axes[1]->subset->min.scalar; - if (!axes[1]->subset->max.unbounded) - params->bbox.maxy = axes[1]->subset->max.scalar; - if(crs != NULL && axes[0] != NULL && axes[0]->subset!= NULL) { - if(!EQUAL(crs, axes[1]->subset->crs)) { - msSetError(MS_WCSERR, "CRS for axis %s and axis %s are not the same.", - "msWCSGetCoverage20_FinalizeParamsObj()", axes[0]->name, axes[1]->name); - return MS_FAILURE; - } - } else { - crs = axes[1]->subset->crs; - } - } - params->height = axes[1]->size; - params->resolutionY = axes[1]->resolution; - params->scaleY = axes[1]->scale; - - if(params->resolutionUnits == NULL && axes[1]->resolutionUOM != NULL) { - params->resolutionUnits = msStrdup(axes[1]->resolutionUOM); - } else if(params->resolutionUnits != NULL && axes[1]->resolutionUOM != NULL - && !EQUAL(params->resolutionUnits, axes[1]->resolutionUOM)) { - msSetError(MS_WCSERR, "The units of measure of the resolution for" - "axis %s and axis %s are not the same.", - "msWCSGetCoverage20_FinalizeParamsObj()", axes[0]->name, axes[1]->name); - return MS_FAILURE; - } - - have_scale = (params->scaleY != MS_WCS20_UNBOUNDED) ? 1 : 0; - have_size = (params->height != 0) ? 1 : 0; - have_resolution = (params->resolutionY != MS_WCS20_UNBOUNDED) ? 1 : 0; - - if ((have_global_scale + have_scale + have_size + have_resolution) > 1) { - msSetError(MS_WCSERR, "Axis '%s' defines scale, size and/or resolution multiple times.", - "msWCSGetCoverage20_FinalizeParamsObj()", axes[1]->name); - return MS_FAILURE; - } - } - - /* if scale is globally set, use this value instead */ - if (params->scale != MS_WCS20_UNBOUNDED) { - params->scaleX = params->scaleY = params->scale; - } - - /* check if projections are equal */ - if(crs != NULL) { - if (params->subsetcrs && !EQUAL(crs, params->subsetcrs)) { - /* already set and not equal -> raise exception */ - msSetError(MS_WCSERR, "SubsetCRS does not match the CRS of the axes: " - "'%s' != '%s'", - "msWCSCreateBoundingBox20()", params->subsetcrs, crs); - return MS_FAILURE; - } - else if (params->subsetcrs) { - /* equal, and already set -> do nothing */ - } - else { - /* not yet globally set -> set it */ - params->subsetcrs = msStrdup(crs); - } - } else if (!params->subsetcrs) { - /* default to CRS of image */ - /* leave params->subsetcrs to null */ - } - - return MS_SUCCESS; -} - -/************************************************************************/ -/* msWCSGetCoverage20_GetBands() */ -/* */ -/* Returns a string, containing a comma-separated list of band */ -/* indices. */ -/************************************************************************/ - -static int msWCSGetCoverage20_GetBands(mapObj *map, layerObj *layer, - wcs20ParamsObjPtr params, wcs20coverageMetadataObjPtr cm, char **bandlist) -{ - int maxlen, index; - char *interval_stop; - char **band_ids = NULL; - - /* if rangesubset parameter is not given, default to all bands */ - if(NULL == params->range_subset) { - *bandlist = msStrdup("1"); - for(unsigned i = 1; i < cm->numbands; ++i) { - char strnumber[12]; - snprintf(strnumber, sizeof(strnumber), ",%d", i + 1); - *bandlist = msStringConcatenate(*bandlist, strnumber); - } - return MS_SUCCESS; - } - - maxlen = cm->numbands * 4 * sizeof(char); - *bandlist = static_cast( msSmallCalloc(sizeof(char), maxlen)); - - /* Use WCS 2.0 metadata items in priority */ - { - char* tmp = msOWSGetEncodeMetadata(&layer->metadata, - "CO", "band_names", NULL); - - if( NULL == tmp ) { - /* Otherwise default to WCS 1.x*/ - tmp = msOWSGetEncodeMetadata(&layer->metadata, - "CO", "rangeset_axes", NULL); - /* "bands" has a special processing in WCS 1.0. See */ - /* msWCSSetDefaultBandsRangeSetInfo */ - if( tmp != NULL && EQUAL(tmp, "bands") ) - { - int num_band_names = cm->numbands; - band_ids = (char**) msSmallCalloc( sizeof(char*), (num_band_names + 1) ); - for( int i = 0; i < num_band_names; i++ ) - { - char szName[30]; - snprintf(szName, sizeof(szName), "Band%d", i+1); - band_ids[i] = msStrdup(szName); - } - } - } - - if(NULL != tmp && band_ids == NULL) { - band_ids = CSLTokenizeString2(tmp, " ", 0); - } - msFree(tmp); - } - - /* If we still don't have band names, use the band names from the coverage metadata */ - if (band_ids == NULL) { - band_ids = (char**) CPLCalloc(sizeof(char*), (cm->numbands + 1)); - for (unsigned i = 0; i < cm->numbands; ++i) { - band_ids[i] = CPLStrdup(cm->bands[i].name); - } - } - - /* Iterate over all supplied range */ - const int count = CSLCount(params->range_subset); - for(int i = 0; i < count; ++i) { - /* RangeInterval case: defined as ":" */ - if ((interval_stop = strchr(params->range_subset[i], ':')) != NULL) { - int start, stop; - *interval_stop = '\0'; - ++interval_stop; - - /* check if the string represents an integer */ - if (msStringParseInteger(params->range_subset[i], &start) == MS_SUCCESS) { - } - /* get index of start clause, or raise an error if none was found */ - else if ((start = CSLFindString(band_ids, params->range_subset[i])) != -1) { - start += 1; /* adjust index, since GDAL bands start with index 1 */ - } - else { - msSetError(MS_WCSERR, "'%s' is not a valid band identifier.", - "msWCSGetCoverage20_GetBands()", params->range_subset[i]); - return MS_FAILURE; - } - - /* check if the string represents an integer */ - if (msStringParseInteger(interval_stop, &stop) == MS_SUCCESS) { - } - /* get index of stop clause, or raise an error if none was found */ - else if ((stop = CSLFindString(band_ids, interval_stop)) != -1) { - stop += 1; /* adjust index, since GDAL bands start with index 1 */ - } - else { - msSetError(MS_WCSERR, "'%s' is not a valid band identifier.", - "msWCSGetCoverage20_GetBands()", interval_stop); - return MS_FAILURE; - } - - /* Check whether or not start and stop are different and stop is higher than start */ - if (stop <= start) { - msSetError(MS_WCSERR, "Invalid range interval given.", - "msWCSGetCoverage20_GetBands()"); - return MS_FAILURE; - } else if (start < 1 || static_cast(stop) > cm->numbands) { - msSetError(MS_WCSERR, "Band interval is out of the valid range: 1-%d", - "msWCSGetCoverage20_GetBands()", (int)cm->numbands); - return MS_FAILURE; - } - - /* expand the interval to a list of indices and push them on the list */ - for (int j = start; j <= stop; ++j) { - char* tmp; - if(i != 0 || j != start) { - strlcat(*bandlist, ",", maxlen); - } - tmp = msIntToString(j); - strlcat(*bandlist, tmp, maxlen); - msFree(tmp); - } - } - /* RangeComponent case */ - else { - if(i != 0) { - strlcat(*bandlist, ",", maxlen); - } - - /* check if the string represents an integer */ - if(msStringParseInteger(params->range_subset[i], &index) == MS_SUCCESS) { - char* tmp; - if (index < 1 || static_cast(index) > cm->numbands) { - msSetError(MS_WCSERR, "Band index is out of the valid range: 1-%d", - "msWCSGetCoverage20_GetBands()", (int)cm->numbands); - return MS_FAILURE; - } - - tmp = msIntToString((int)index); - strlcat(*bandlist, tmp, maxlen); - msFree(tmp); - continue; - } - - /* check if the string is equal to a band identifier */ - /* if so, what is the index of the band */ - if((index = CSLFindString(band_ids, params->range_subset[i])) != -1) { - char* tmp = msIntToString((int)index + 1); - strlcat(*bandlist, tmp, maxlen); - msFree(tmp); - } - else { - msSetError(MS_WCSERR, "'%s' is not a valid band identifier.", - "msWCSGetCoverage20_GetBands()", params->range_subset[i]); - return MS_FAILURE; - } - } - } - - CSLDestroy(band_ids); - return MS_SUCCESS; -} - -/* Fixes CPLParseNameValue to allow ':' characters for namespaced keys */ - -static const char * fixedCPLParseNameValue(const char* string, char **key) { - const char *value; - size_t size; - value = strchr(string, '='); - - if (value == NULL) { - *key = NULL; - return NULL; - } - - size = value - string; - *key = static_cast(msSmallMalloc(size + 1)); - strncpy(*key, string, size + 1); - (*key)[size] = '\0'; - return value + 1; -} - -/************************************************************************/ -/* msWCSSetFormatParams20() */ -/* */ -/* Parses the given format options and sets the appropriate */ -/* output format values. */ -/************************************************************************/ - -static int msWCSSetFormatParams20(outputFormatObj* format, char** format_options) { - /* currently geotiff only */ - char *format_option; - int i = 0; - int is_geotiff = (format->mimetype && EQUAL(format->mimetype, "image/tiff")); - - if (!is_geotiff || !format_options) { - /* Currently only geotiff available */ - return MS_SUCCESS; - } - - format_option = format_options[0]; - while (format_option) { - /* key, value */ - char *key; - const char *value = fixedCPLParseNameValue(format_option, &key); - - if (!key) { - msSetError(MS_WCSERR, "Could not deduct the option key.", - "msWCSSetFormatParams20()"); - return MS_FAILURE; - } - else if (!value) { - msSetError(MS_WCSERR, "Missing value for parameter '%s'.", - "msWCSSetFormatParams20()", key); - return MS_FAILURE; - } - - if (EQUAL(key, "geotiff:compression") && is_geotiff) { - /*COMPRESS=[JPEG/LZW/PACKBITS/DEFLATE/CCITTRLE/CCITTFAX3/CCITTFAX4/NONE]*/ - if (EQUAL(value, "None")) { - msSetOutputFormatOption(format, "COMPRESS", "NONE"); - } - else if (EQUAL(value, "PackBits")) { - msSetOutputFormatOption(format, "COMPRESS", "PACKBITS"); - } - else if (EQUAL(value, "Deflate")) { - msSetOutputFormatOption(format, "COMPRESS", "DEFLATE"); - } - else if (EQUAL(value, "Huffman")) { - msSetOutputFormatOption(format, "COMPRESS", "CCITTRLE"); - } - else if (EQUAL(value, "LZW")) { - msSetOutputFormatOption(format, "COMPRESS", "LZW"); - } - else if (EQUAL(value, "JPEG")) { - msSetOutputFormatOption(format, "COMPRESS", "JPEG"); - } - /* unsupported compression methods: CCITTFAX3/CCITTFAX4 */ - else { - msSetError(MS_WCSERR, "Compression method '%s' not supported.", - "msWCSSetFormatParams20()", value); - return MS_FAILURE; - } - } - - else if (EQUAL(key, "geotiff:jpeg_quality") && is_geotiff) { - int quality; - /* JPEG_QUALITY=[1-100] */ - if (msStringParseInteger(value, &quality) != MS_SUCCESS) { - msSetError(MS_WCSERR, "Could not parse jpeg_quality value.", - "msWCSSetFormatParams20()"); - return MS_FAILURE; - } - else if (quality < 1 || quality > 100) { - msSetError(MS_WCSERR, "Invalid jpeg_quality value '%d'.", - "msWCSSetFormatParams20()", quality); - return MS_FAILURE; - } - msSetOutputFormatOption(format, "JPEG_QUALITY", value); - } - else if (EQUAL(key, "geotiff:predictor") && is_geotiff) { - /* PREDICTOR=[None/Horizontal/FloatingPoint] */ - const char *predictor; - if (EQUAL(value, "None") || EQUAL(value, "1")) { - predictor = "1"; - } - else if (EQUAL(value, "Horizontal") || EQUAL(value, "2")) { - predictor = "2"; - } - else if (EQUAL(value, "FloatingPoint") || EQUAL(value, "3")) { - predictor = "3"; - } - else { - msSetError(MS_WCSERR, "Invalid predictor value '%s'.", - "msWCSSetFormatParams20()", value); - return MS_FAILURE; - } - msSetOutputFormatOption(format, "PREDICTOR", predictor); - } - else if (EQUAL(key, "geotiff:interleave") && is_geotiff) { - /* INTERLEAVE=[BAND,PIXEL] */ - if (EQUAL(value, "Band")) { - msSetOutputFormatOption(format, "INTERLEAVE", "BAND"); - } - else if (EQUAL(value, "Pixel")) { - msSetOutputFormatOption(format, "INTERLEAVE", "PIXEL"); - } - else { - msSetError(MS_WCSERR, "Interleave method '%s' not supported.", - "msWCSSetFormatParams20()", value); - return MS_FAILURE; - } - } - else if (EQUAL(key, "geotiff:tiling") && is_geotiff) { - /* TILED=YES */ - if (EQUAL(value, "true")) { - msSetOutputFormatOption(format, "TILED", "YES"); - } - else if (EQUAL(value, "false")) { - msSetOutputFormatOption(format, "TILED", "NO"); - } - else { - msSetError(MS_WCSERR, "Invalid boolean value '%s'.", - "msWCSSetFormatParams20()", value); - return MS_FAILURE; - } - } - else if (EQUAL(key, "geotiff:tileheight") && is_geotiff) { - /* BLOCKXSIZE=n */ - int tileheight; - - if (msStringParseInteger(value, &tileheight) != MS_SUCCESS) { - msSetError(MS_WCSERR, "Could not parse tileheight value.", - "msWCSSetFormatParams20()"); - return MS_FAILURE; - } - else if (tileheight < 1 || tileheight % 16) { - msSetError(MS_WCSERR, "Invalid tileheight value '%d'. " - "Must be greater than 0 and dividable by 16.", - "msWCSSetFormatParams20()", tileheight); - return MS_FAILURE; - } - msSetOutputFormatOption(format, "BLOCKXSIZE", value); - } - else if (EQUAL(key, "geotiff:tilewidth") && is_geotiff) { - /* BLOCKYSIZE=n */ - int tilewidth; - - if (msStringParseInteger(value, &tilewidth) != MS_SUCCESS) { - msSetError(MS_WCSERR, "Could not parse tilewidth value.", - "msWCSSetFormatParams20()"); - return MS_FAILURE; - } - else if (tilewidth < 1 || tilewidth % 16) { - msSetError(MS_WCSERR, "Invalid tilewidth value '%d'. " - "Must be greater than 0 and dividable by 16.", - "msWCSSetFormatParams20()", tilewidth); - return MS_FAILURE; - } - msSetOutputFormatOption(format, "BLOCKYSIZE", value); - } - else if (EQUALN(key, "geotiff:", 8)) { - msSetError(MS_WCSERR, "Unrecognized GeoTIFF parameter '%s'.", - "msWCSSetFormatParams20()", key); - return MS_FAILURE; - } - - msFree(key); - - /* fetch next option */ - format_option = format_options[++i]; - } - - return MS_SUCCESS; -} - -/************************************************************************/ -/* msWCSGetCoverage20() */ -/* */ -/* Implementation of the GetCoverage Operation. The coverage */ -/* is either returned as an image or as a multipart xml/image. */ -/* The result is written on the stream. */ -/************************************************************************/ - -int msWCSGetCoverage20(mapObj *map, cgiRequestObj *request, - wcs20ParamsObjPtr params, owsRequestObj *ows_request) -{ - layerObj *layer = NULL; - wcs20coverageMetadataObj cm; - imageObj *image = NULL; - outputFormatObj *format = NULL; - - rectObj subsets, bbox; - projectionObj imageProj; - - int status, i; - double x_1, x_2, y_1, y_2; - char *coverageName, *bandlist=NULL, numbands[12]; - - int doDrawRasterLayerDraw = MS_TRUE; - GDALDatasetH hDS = NULL; - - int widthFromComputationInImageCRS = 0; - int heightFromComputationInImageCRS = 0; - - /* number of coverage ids should be 1 */ - if (params->ids == NULL || params->ids[0] == NULL) { - msSetError(MS_WCSERR, "Required parameter CoverageID was not supplied.", - "msWCSGetCoverage20()"); - return msWCSException(map, "MissingParameterValue", "coverage", - params->version); - } - if (params->ids[1] != NULL) { - msSetError(MS_WCSERR, "GetCoverage operation supports only one coverage.", - "msWCSGetCoverage20()"); - return msWCSException(map, "TooManyParameterValues", "coverage", - params->version); - } - - /* find the right layer */ - layer = NULL; - for(i = 0; i < map->numlayers; i++) { - coverageName = msOWSGetEncodeMetadata(&(GET_LAYER(map, i)->metadata), - "CO", "name", - GET_LAYER(map, i)->name); - if (EQUAL(coverageName, params->ids[0]) && - (msIntegerInArray(GET_LAYER(map, i)->index, ows_request->enabled_layers, ows_request->numlayers))) { - layer = GET_LAYER(map, i); - i = map->numlayers; /* to exit loop don't use break, we want to free resources first */ - } - msFree(coverageName); - } - - /* throw exception if no Layer was found */ - if (layer == NULL) { - msSetError(MS_WCSERR, - "COVERAGEID=%s not found, not in supported layer list. A layer might be disabled for \ -this request. Check wcs/ows_enable_request settings.", "msWCSGetCoverage20()", params->ids[0]); - return msWCSException(map, "NoSuchCoverage", "coverageid", - params->version); - } - /* retrieve coverage metadata */ - status = msWCSGetCoverageMetadata20(layer, &cm); - if (status != MS_SUCCESS) { - msWCSClearCoverageMetadata20(&cm); - return MS_FAILURE; - } - - /* fill in bands rangeset info, if required. */ - /* msWCSSetDefaultBandsRangeSetInfo(NULL, &cm, layer ); */ - - /* set resolution, size and maximum extent */ - layer->extent = map->extent = cm.extent; - map->cellsize = cm.xresolution; - map->width = cm.xsize; - map->height = cm.ysize; - - /************************************************************************/ - /* finalize the params object. determine subset crs and subset */ - /* bbox. Also project the image to the subset crs. */ - /************************************************************************/ - - msInitProjection(&imageProj); - msProjectionInheritContextFrom(&imageProj, &(layer->projection)); - if (msLoadProjectionString(&imageProj, cm.srs_epsg) == -1) { - msFreeProjection(&imageProj); - msWCSClearCoverageMetadata20(&cm); - msSetError(MS_WCSERR, - "Error loading CRS %s.", - "msWCSGetCoverage20()", cm.srs_epsg); - return msWCSException(map, "InvalidParameterValue", - "projection", params->version); - } - - /* iterate over all subsets and check if they are valid*/ - for(i = 0; i < params->numaxes; ++i) { - if(params->axes[i]->subset != NULL) { - if(params->axes[i]->subset->timeOrScalar == MS_WCS20_TIME_VALUE) { - msFreeProjection(&imageProj); - msWCSClearCoverageMetadata20(&cm); - msSetError(MS_WCSERR, "Time values for subsets are not supported. ", - "msWCSGetCoverage20()"); - return msWCSException(map, "InvalidSubsetting", "subset", params->version); - } - if(params->axes[i]->subset->operation == MS_WCS20_SLICE) { - msFreeProjection(&imageProj); - msWCSClearCoverageMetadata20(&cm); - msSetError(MS_WCSERR, "Subset operation 'slice' is not supported.", - "msWCSGetCoverage20()"); - return msWCSException(map, "InvalidSubsetting", "subset", params->version); - } - } - } - - { - wcs20AxisObjPtr axes[2]; - if(msWCSValidateAndFindAxes20(params, axes) == MS_FAILURE) { - msFreeProjection(&imageProj); - msWCSClearCoverageMetadata20(&cm); - return msWCSException(map, "InvalidAxisLabel", "subset", params->version); - } - if(msWCSGetCoverage20_FinalizeParamsObj(params, axes) == MS_FAILURE) { - msFreeProjection(&imageProj); - msWCSClearCoverageMetadata20(&cm); - return msWCSException(map, "InvalidParameterValue", "extent", params->version); - } - } - - subsets = params->bbox; - - /* if no subsetCRS was specified use the coverages CRS - (Requirement 27 of the WCS 2.0 specification) */ - if (!params->subsetcrs) { - params->subsetcrs = msStrdup(cm.srs_epsg); - } - - if(EQUAL(params->subsetcrs, "imageCRS")) { - /* subsets are in imageCRS; reproject them to real coordinates */ - rectObj orig_bbox = subsets; - - msFreeProjection(&(map->projection)); - map->projection = imageProj; - - if(subsets.minx != -DBL_MAX || subsets.maxx != DBL_MAX) { - x_1 = cm.geotransform[0] - + orig_bbox.minx * cm.geotransform[1] - + orig_bbox.miny * cm.geotransform[2]; - x_2 = cm.geotransform[0] - + (orig_bbox.maxx+1) * cm.geotransform[1] - + (orig_bbox.maxy+1) * cm.geotransform[2]; - - subsets.minx = MS_MIN(x_1, x_2); - subsets.maxx = MS_MAX(x_1, x_2); - } - if(subsets.miny != -DBL_MAX || subsets.maxy != DBL_MAX) { - y_1 = cm.geotransform[3] - + (orig_bbox.maxx+1) * cm.geotransform[4] - + (orig_bbox.maxy+1) * cm.geotransform[5]; - /*subsets.miny -= cm.geotransform[4]/2 + cm.geotransform[5]/2;*/ - y_2 = cm.geotransform[3] - + orig_bbox.minx * cm.geotransform[4] - + orig_bbox.miny * cm.geotransform[5]; - - subsets.miny = MS_MIN(y_1, y_2); - subsets.maxy = MS_MAX(y_1, y_2); - } - } else { /* if crs is not the 'imageCRS' */ - projectionObj subsetProj; - - /* if the subsets have a crs given, project the image extent to it */ - msInitProjection(&subsetProj); - msProjectionInheritContextFrom(&subsetProj, &(layer->projection)); - if(msLoadProjectionString(&subsetProj, params->subsetcrs) != MS_SUCCESS) { - msFreeProjection(&subsetProj); - msFreeProjection(&imageProj); - msWCSClearCoverageMetadata20(&cm); - msSetError(MS_WCSERR, - "Error loading CRS %s.", - "msWCSGetCoverage20()", params->subsetcrs); - return msWCSException(map, "InvalidParameterValue", - "projection", params->version); - } - - if(msProjectionsDiffer(&imageProj, &subsetProj)) { - - /* Reprojection of source raster extent of (-180,-90,180,90) to any */ - /* projected CRS is going to exhibit strong anomalies. So instead */ - /* do the reverse, project the subset extent to the layer CRS, and */ - /* see how much the subset extent takes with respect to the source */ - /* raster extent. This is only used if output width and resolutionX (or */ - /* (height and resolutionY) are unknown. */ - if( ((params->width == 0 && params->resolutionX == MS_WCS20_UNBOUNDED) || - (params->height == 0 && params->resolutionY == MS_WCS20_UNBOUNDED)) && - (msProjIsGeographicCRS(&imageProj) && - !msProjIsGeographicCRS(&subsetProj) && - fabs(layer->extent.minx - -180.0) < 1e-5 && - fabs(layer->extent.miny - -90.0) < 1e-5 && - fabs(layer->extent.maxx - 180.0) < 1e-5 && - fabs(layer->extent.maxy - 90.0) < 1e-5) ) - { - rectObj subsetInImageProj = subsets; - if( msProjectRect(&subsetProj, &imageProj, &(subsetInImageProj)) == MS_SUCCESS ) - { - subsetInImageProj.minx = MS_MAX(subsetInImageProj.minx, layer->extent.minx); - subsetInImageProj.miny = MS_MAX(subsetInImageProj.miny, layer->extent.miny); - subsetInImageProj.maxx = MS_MIN(subsetInImageProj.maxx, layer->extent.maxx); - subsetInImageProj.maxy = MS_MIN(subsetInImageProj.maxy, layer->extent.maxy); - { - double total = ABS(layer->extent.maxx - layer->extent.minx); - double part = ABS(subsetInImageProj.maxx - subsetInImageProj.minx); - widthFromComputationInImageCRS = MS_NINT((part * map->width) / total); - } - { - double total = ABS(layer->extent.maxy - layer->extent.miny); - double part = ABS(subsetInImageProj.maxy - subsetInImageProj.miny); - heightFromComputationInImageCRS = MS_NINT((part * map->height) / total); - } - } - } - - msProjectRect(&imageProj, &subsetProj, &(layer->extent)); - map->extent = layer->extent; - msFreeProjection(&(map->projection)); - map->projection = subsetProj; - msFreeProjection(&imageProj); - } else { - msFreeProjection(&(map->projection)); - map->projection = imageProj; - msFreeProjection(&subsetProj); - } - } - - /* create boundings of params subsets and image extent */ - if(msRectOverlap(&subsets, &(layer->extent)) == MS_FALSE) { - /* extent and bbox do not overlap -> exit */ - msWCSClearCoverageMetadata20(&cm); - msSetError(MS_WCSERR, "Image extent does not intersect with desired region.", - "msWCSGetCoverage20()"); - return msWCSException(map, "ExtentError", "extent", params->version); - } - - /* write combined bounding box */ - bbox.minx = MS_MAX(subsets.minx, map->extent.minx); - bbox.miny = MS_MAX(subsets.miny, map->extent.miny); - bbox.maxx = MS_MIN(subsets.maxx, map->extent.maxx); - bbox.maxy = MS_MIN(subsets.maxy, map->extent.maxy); - - /* check if we are overspecified */ - if ((params->width != 0 && params->resolutionX != MS_WCS20_UNBOUNDED) - || (params->height != 0 && params->resolutionY != MS_WCS20_UNBOUNDED)) { - msWCSClearCoverageMetadata20(&cm); - msSetError(MS_WCSERR, "GetCoverage operation supports only one of SIZE or RESOLUTION per axis.", - "msWCSGetCoverage20()"); - return msWCSException(map, "TooManyParameterValues", "coverage", - params->version); - } - - /************************************************************************/ - /* check both axes: see if either size or resolution are given (and */ - /* calculate the other value). If both are not given, calculate them */ - /* from the bounding box. */ - /************************************************************************/ - - /* check x axis */ - if(params->width != 0) { - /* TODO Unit Of Measure? */ - params->resolutionX = (bbox.maxx - bbox.minx) / params->width; - } else if(params->resolutionX != MS_WCS20_UNBOUNDED) { - params->width = MS_NINT((bbox.maxx - bbox.minx) / params->resolutionX); - } else { - if( widthFromComputationInImageCRS != 0 ) { - params->width = widthFromComputationInImageCRS; - } else if(ABS(bbox.maxx - bbox.minx) != ABS(map->extent.maxx - map->extent.minx)) { - double total = ABS(map->extent.maxx - map->extent.minx), - part = ABS(bbox.maxx - bbox.minx); - params->width = MS_NINT((part * map->width) / total); - } else { - params->width = map->width; - } - - params->resolutionX = (bbox.maxx - bbox.minx) / params->width; - - if (params->scaleX != MS_WCS20_UNBOUNDED) { - params->resolutionX /= params->scaleX; - params->width = (long)(((double) params->width) * params->scaleX); - } - } - - /* check y axis */ - if(params->height != 0) { - params->resolutionY = (bbox.maxy - bbox.miny) / params->height; - } else if(params->resolutionY != MS_WCS20_UNBOUNDED) { - params->height = MS_NINT((bbox.maxy - bbox.miny) / params->resolutionY); - } else { - if( heightFromComputationInImageCRS != 0 ) { - params->height = heightFromComputationInImageCRS; - } else if(ABS(bbox.maxy - bbox.miny) != ABS(map->extent.maxy - map->extent.miny)) { - double total = ABS(map->extent.maxy - map->extent.miny), - part = ABS(bbox.maxy - bbox.miny); - params->height = MS_NINT((part * map->height) / total); - } else { - params->height = map->height; - } - - params->resolutionY = (bbox.maxy - bbox.miny) / params->height; - - if (params->scaleY != MS_WCS20_UNBOUNDED) { - params->resolutionY /= params->scaleY; - params->height = (long)(((double) params->height) * params->scaleY); - } - } - - /* WCS 2.0 is center of pixel oriented */ - bbox.minx += params->resolutionX * 0.5; - bbox.maxx -= params->resolutionX * 0.5; - bbox.miny += params->resolutionY * 0.5; - bbox.maxy -= params->resolutionY * 0.5; - - /* if parameter 'outputcrs' is given, project the image to this crs */ - if(params->outputcrs != NULL) { - projectionObj outputProj; - - msInitProjection(&outputProj); - msProjectionInheritContextFrom(&outputProj, &(layer->projection)); - if(msLoadProjectionString(&outputProj, params->outputcrs) == -1) { - msFreeProjection(&outputProj); - msWCSClearCoverageMetadata20(&cm); - return msWCSException(map, "InvalidParameterValue", "coverage", - params->version); - } - if(msProjectionsDiffer(&(map->projection), &outputProj)) { - - msDebug("msWCSGetCoverage20(): projecting to outputcrs %s\n", params->outputcrs); - - msProjectRect(&(map->projection), &outputProj, &bbox); - msFreeProjection(&(map->projection)); - map->projection = outputProj; - - /* recalculate resolutions, needed if UOM changes (e.g: deg -> m) */ - params->resolutionX = (bbox.maxx - bbox.minx) / params->width; - params->resolutionY = (bbox.maxy - bbox.miny) / params->height; - } - else { - msFreeProjection(&outputProj); - } - } - - /* set the bounding box as new map extent */ - map->extent = bbox; - map->width = params->width; - map->height = params->height; - - /* Are we exceeding the MAXSIZE limit on result size? */ - if(map->width > map->maxsize || map->height > map->maxsize ) { - msWCSClearCoverageMetadata20(&cm); - msSetError(MS_WCSERR, "Raster size out of range, width and height of " - "resulting coverage must be no more than MAXSIZE=%d.", - "msWCSGetCoverage20()", map->maxsize); - - return msWCSException(map, "InvalidParameterValue", - "size", params->version); - } - - /* Mapserver only supports square cells */ - if (params->resolutionX <= params->resolutionY) - map->cellsize = params->resolutionX; - else - map->cellsize = params->resolutionY; - - msDebug("msWCSGetCoverage20(): Set parameters from original" - "data. Width: %d, height: %d, cellsize: %f, extent: %f,%f,%f,%f\n", - map->width, map->height, map->cellsize, map->extent.minx, - map->extent.miny, map->extent.maxx, map->extent.maxy); - - /** - * Which format to use? - * - * 1) format parameter - * 2) native format (from metadata) or GDAL format of the input dataset - * 3) exception - **/ - - if (!params->format) { - if (cm.native_format) { - params->format = msStrdup(cm.native_format); - } - } - - if (!params->format) { - msSetError(MS_WCSERR, "Output format could not be automatically determined. " - "Use the FORMAT parameter to specify a format.", - "msWCSGetCoverage20()"); - msWCSClearCoverageMetadata20(&cm); - return msWCSException(map, "MissingParameterValue", "format", - params->version); - } - - /* make sure layer is on */ - layer->status = MS_ON; - - msMapComputeGeotransform(map); - - /* fill in bands rangeset info, if required. */ - /* msWCSSetDefaultBandsRangeSetInfo(params, &cm, layer); */ - /* msDebug("Bandcount: %d\n", cm.bandcount); */ - - msApplyDefaultOutputFormats(map); - - if (msGetOutputFormatIndex(map, params->format) == -1) { - msSetError(MS_WCSERR, "Unrecognized value '%s' for the FORMAT parameter.", - "msWCSGetCoverage20()", params->format); - msWCSClearCoverageMetadata20(&cm); - return msWCSException(map, "InvalidParameterValue", "format", - params->version); - } - - /* create a temporary outputformat (we likely will need to tweak parts) */ - format = msCloneOutputFormat(msSelectOutputFormat(map, params->format)); - msApplyOutputFormat(&(map->outputformat), format, MS_NOOVERRIDE, - MS_NOOVERRIDE, MS_NOOVERRIDE); - - /* set format specific parameters */ - if (msWCSSetFormatParams20(format, params->format_options) != MS_SUCCESS) { - msFree(bandlist); - msWCSClearCoverageMetadata20(&cm); - return msWCSException(map, "InvalidParameterValue", "format", - params->version); - } - - if(msWCSGetCoverage20_GetBands(map, layer, params, &cm, &bandlist) != MS_SUCCESS) { - msFree(bandlist); - msWCSClearCoverageMetadata20(&cm); - return msWCSException(map, "InvalidParameterValue", "rangesubset", - params->version); - } - msLayerSetProcessingKey(layer, "BANDS", bandlist); - snprintf(numbands, sizeof(numbands), "%d", msCountChars(bandlist, ',')+1); - msSetOutputFormatOption(map->outputformat, "BAND_COUNT", numbands); - - msWCSApplyLayerCreationOptions(layer, map->outputformat, bandlist); - - /* check for the interpolation */ - /* Defaults to NEAREST */ - if(params->interpolation != NULL) { - if(EQUALN(params->interpolation,"NEAREST",7)) { - msLayerSetProcessingKey(layer, "RESAMPLE", "NEAREST"); - } else if(EQUAL(params->interpolation,"BILINEAR")) { - msLayerSetProcessingKey(layer, "RESAMPLE", "BILINEAR"); - } else if(EQUAL(params->interpolation,"AVERAGE")) { - msLayerSetProcessingKey(layer, "RESAMPLE", "AVERAGE"); - } else { - msFree(bandlist); - msSetError( MS_WCSERR, "'%s' specifies an unsupported interpolation method.", - "msWCSGetCoverage20()", params->interpolation ); - msWCSClearCoverageMetadata20(&cm); - return msWCSException(map, "InvalidParameterValue", "interpolation", params->version); - } - } else { - msLayerSetProcessingKey(layer, "RESAMPLE", "NEAREST"); - } - - /* since the dataset is only used in one layer, set it to be */ - /* closed after drawing the layer. This normally defaults to */ - /* DEFER and will produce a memory leak, because the dataset */ - /* will not be closed. */ - if( msLayerGetProcessingKey(layer, "CLOSE_CONNECTION") == NULL ) { - msLayerSetProcessingKey(layer, "CLOSE_CONNECTION", "NORMAL"); - } - - if( layer->tileindex == NULL && layer->data != NULL && - strlen(layer->data) > 0 && - layer->connectiontype != MS_KERNELDENSITY ) - { - if( msDrawRasterLayerLowCheckIfMustDraw(map, layer) ) - { - char* decrypted_path = NULL; - char szPath[MS_MAXPATHLEN]; - hDS = (GDALDatasetH)msDrawRasterLayerLowOpenDataset( - map, layer, layer->data, szPath, &decrypted_path); - msFree(decrypted_path); - if( hDS ) - msWCSApplyDatasetMetadataAsCreationOptions(layer, map->outputformat, bandlist, hDS); - } - else - { - doDrawRasterLayerDraw = MS_FALSE; - } - } - - /* create the image object */ - if (!map->outputformat) { - msWCSClearCoverageMetadata20(&cm); - msFree(bandlist); - msSetError(MS_WCSERR, "The map outputformat is missing!", - "msWCSGetCoverage20()"); - msDrawRasterLayerLowCloseDataset(layer, hDS); - return msWCSException(map, NULL, NULL, params->version); - } else if (MS_RENDERER_PLUGIN(map->outputformat)) { - image = msImageCreate(map->width, map->height, map->outputformat, - map->web.imagepath, map->web.imageurl, map->resolution, - map->defresolution, &map->imagecolor); - } else if (MS_RENDERER_RAWDATA(map->outputformat)) { - image = msImageCreate(map->width, map->height, map->outputformat, - map->web.imagepath, map->web.imageurl, map->resolution, - map->defresolution, &map->imagecolor); - } else { - msFree(bandlist); - msWCSClearCoverageMetadata20(&cm); - msSetError(MS_WCSERR, "Map outputformat not supported for WCS!", - "msWCSGetCoverage20()"); - msDrawRasterLayerLowCloseDataset(layer, hDS); - return msWCSException(map, NULL, NULL, params->version); - } - - if (image == NULL) { - msFree(bandlist); - msWCSClearCoverageMetadata20(&cm); - msDrawRasterLayerLowCloseDataset(layer, hDS); - return msWCSException(map, NULL, NULL, params->version); - } - - if(layer->mask) { - int maskLayerIdx = msGetLayerIndex(map,layer->mask); - layerObj *maskLayer; - outputFormatObj *altFormat; - if(maskLayerIdx == -1) { - msSetError(MS_MISCERR, "Layer (%s) references unknown mask layer (%s)", "msDrawLayer()", - layer->name,layer->mask); - msFreeImage(image); - msFree(bandlist); - msWCSClearCoverageMetadata20(&cm); - msDrawRasterLayerLowCloseDataset(layer, hDS); - return msWCSException(map, NULL, NULL, params->version); - } - maskLayer = GET_LAYER(map, maskLayerIdx); - if(!maskLayer->maskimage) { - int i,retcode; - int origstatus, origlabelcache; - char *origImageType = msStrdup(map->imagetype); - altFormat = msSelectOutputFormat(map, "png24"); - msInitializeRendererVTable(altFormat); - /* TODO: check the png24 format hasn't been tampered with, i.e. it's agg */ - maskLayer->maskimage= msImageCreate(image->width, image->height,altFormat, - image->imagepath, image->imageurl, map->resolution, map->defresolution, NULL); - if (!maskLayer->maskimage) { - msSetError(MS_MISCERR, "Unable to initialize mask image.", "msDrawLayer()"); - msFreeImage(image); - msFree(bandlist); - msWCSClearCoverageMetadata20(&cm); - msDrawRasterLayerLowCloseDataset(layer, hDS); - return msWCSException(map, NULL, NULL, params->version); - } - - /* - * force the masked layer to status on, and turn off the labelcache so that - * eventual labels are added to the temporary image instead of being added - * to the labelcache - */ - origstatus = maskLayer->status; - origlabelcache = maskLayer->labelcache; - maskLayer->status = MS_ON; - maskLayer->labelcache = MS_OFF; - - /* draw the mask layer in the temporary image */ - retcode = msDrawLayer(map, maskLayer, maskLayer->maskimage); - maskLayer->status = origstatus; - maskLayer->labelcache = origlabelcache; - if(retcode != MS_SUCCESS) { - free(origImageType); - msFreeImage(image); - msFree(bandlist); - msWCSClearCoverageMetadata20(&cm); - msDrawRasterLayerLowCloseDataset(layer, hDS); - return msWCSException(map, NULL, NULL, params->version); - } - /* - * hack to work around bug #3834: if we have use an alternate renderer, the symbolset may contain - * symbols that reference it. We want to remove those references before the altFormat is destroyed - * to avoid a segfault and/or a leak, and so the the main renderer doesn't pick the cache up thinking - * it's for him. - */ - for(i=0; isymbolset.numsymbols; i++) { - if (map->symbolset.symbol[i]!=NULL) { - symbolObj *s = map->symbolset.symbol[i]; - if(s->renderer == MS_IMAGE_RENDERER(maskLayer->maskimage)) { - MS_IMAGE_RENDERER(maskLayer->maskimage)->freeSymbol(s); - s->renderer = NULL; - } - } - } - /* set the imagetype from the original outputformat back (it was removed by msSelectOutputFormat() */ - msFree(map->imagetype); - map->imagetype = origImageType; - - } - } - - /* Actually produce the "grid". */ - if( MS_RENDERER_RAWDATA(map->outputformat) ) { - if( doDrawRasterLayerDraw ) { - status = msDrawRasterLayerLowWithDataset( map, layer, image, NULL, hDS ); - } else { - status = MS_SUCCESS; - } - } else { - rasterBufferObj rb; - status = MS_IMAGE_RENDERER(image)->getRasterBufferHandle(image,&rb); - if(LIKELY(status == MS_SUCCESS)) { - if( doDrawRasterLayerDraw ) { - status = msDrawRasterLayerLowWithDataset( map, layer, image, &rb, hDS ); - } else { - status = MS_SUCCESS; - } - } - } - - msDrawRasterLayerLowCloseDataset(layer, hDS); - - if( status != MS_SUCCESS ) { - msFree(bandlist); - msFreeImage(image); - msWCSClearCoverageMetadata20(&cm); - return msWCSException(map, NULL, NULL, params->version ); - } - - /* GML+Image */ - /* Embed the image into multipart message */ - if(params->multipart == MS_TRUE) { - xmlDocPtr psDoc = NULL; /* document pointer */ - xmlNodePtr psRootNode, psRangeSet, psFile, psRangeParameters; - xmlNsPtr psGmlNs = NULL, - psGmlcovNs = NULL, - psSweNs = NULL, - psXLinkNs = NULL; - wcs20coverageMetadataObj tmpCm; - char *srs_uri, *default_filename; - const char *filename; - int swapAxes; - - /* Create Document */ - psDoc = xmlNewDoc(BAD_CAST "1.0"); - psRootNode = xmlNewNode(NULL, BAD_CAST MS_WCS_GML_COVERAGETYPE_RECTIFIED_GRID_COVERAGE); - xmlDocSetRootElement(psDoc, psRootNode); - - msWCSPrepareNamespaces20(psDoc, psRootNode, map, MS_FALSE); - - psGmlNs = xmlSearchNs(psDoc, psRootNode, BAD_CAST MS_OWSCOMMON_GML_NAMESPACE_PREFIX); - psGmlcovNs = xmlSearchNs(psDoc, psRootNode, BAD_CAST MS_OWSCOMMON_GMLCOV_NAMESPACE_PREFIX); - psSweNs = xmlSearchNs(psDoc, psRootNode, BAD_CAST MS_OWSCOMMON_SWE_NAMESPACE_PREFIX); - xmlSearchNs(psDoc, psRootNode, BAD_CAST MS_OWSCOMMON_WCS_NAMESPACE_PREFIX); - psXLinkNs = xmlSearchNs(psDoc, psRootNode, BAD_CAST MS_OWSCOMMON_W3C_XLINK_NAMESPACE_PREFIX); - - xmlNewNsProp(psRootNode, psGmlNs, BAD_CAST "id", BAD_CAST layer->name); - - xmlSetNs(psRootNode, psGmlcovNs); - - srs_uri = msOWSGetProjURI(&map->projection, NULL, "CO", 1); - - tmpCm = cm; - tmpCm.extent = map->extent; - tmpCm.xsize = map->width; - tmpCm.ysize = map->height; - strlcpy(tmpCm.srs_uri, srs_uri, sizeof(tmpCm.srs_uri)); - - tmpCm.xresolution = map->gt.geotransform[1]; - tmpCm.yresolution = map->gt.geotransform[5]; - - tmpCm.extent.minx = MS_MIN(map->gt.geotransform[0], map->gt.geotransform[0] + map->width * tmpCm.xresolution); - tmpCm.extent.miny = MS_MIN(map->gt.geotransform[3], map->gt.geotransform[3] + map->height * tmpCm.yresolution); - tmpCm.extent.maxx = MS_MAX(map->gt.geotransform[0], map->gt.geotransform[0] + map->width * tmpCm.xresolution); - tmpCm.extent.maxy = MS_MAX(map->gt.geotransform[3], map->gt.geotransform[3] + map->height * tmpCm.yresolution); - - swapAxes = msWCSSwapAxes20(srs_uri); - msFree(srs_uri); - - /* Setup layer information */ - msWCSCommon20_CreateBoundedBy(layer, &tmpCm, psGmlNs, psRootNode, &(map->projection), swapAxes); - msWCSCommon20_CreateDomainSet(layer, &tmpCm, psGmlNs, psRootNode, &(map->projection), swapAxes); - - psRangeSet = xmlNewChild(psRootNode, psGmlNs, BAD_CAST "rangeSet", NULL); - psFile = xmlNewChild(psRangeSet, psGmlNs, BAD_CAST "File", NULL); - - /* TODO: wait for updated specifications */ - psRangeParameters = xmlNewChild(psFile, psGmlNs, BAD_CAST "rangeParameters", NULL); - - default_filename = msStrdup("out."); - default_filename = msStringConcatenate(default_filename, MS_IMAGE_EXTENSION(image->format)); - - filename = msGetOutputFormatOption(image->format, "FILENAME", default_filename); - std::string file_ref("cid:coverage/"); - file_ref += filename; - - msFree(default_filename); - - std::string role; - if(EQUAL(MS_IMAGE_MIME_TYPE(map->outputformat), "image/tiff")) { - role = MS_WCS_20_PROFILE_GML_GEOTIFF; - } else { - role = MS_IMAGE_MIME_TYPE(map->outputformat); - } - - xmlNewNsProp(psRangeParameters, psXLinkNs, BAD_CAST "href", BAD_CAST file_ref.c_str()); - xmlNewNsProp(psRangeParameters, psXLinkNs, BAD_CAST "role", BAD_CAST role.c_str()); - xmlNewNsProp(psRangeParameters, psXLinkNs, BAD_CAST "arcrole", BAD_CAST "fileReference"); - - xmlNewChild(psFile, psGmlNs, BAD_CAST "fileReference", BAD_CAST file_ref.c_str()); - xmlNewChild(psFile, psGmlNs, BAD_CAST "fileStructure", NULL); - xmlNewChild(psFile, psGmlNs, BAD_CAST "mimeType", BAD_CAST MS_IMAGE_MIME_TYPE(map->outputformat)); - - msWCSCommon20_CreateRangeType(layer, &cm, bandlist, psGmlNs, psGmlcovNs, psSweNs, psXLinkNs, psRootNode); - - msIO_setHeader("Content-Type","multipart/related; boundary=wcs"); - msIO_sendHeaders(); - msIO_printf("\r\n--wcs\r\n"); - - msWCSWriteDocument20(map, psDoc); - msWCSWriteFile20(map, image, params, 1); - - xmlFreeDoc(psDoc); - xmlCleanupParser(); - /* just print out the file without gml */ - } else { - msWCSWriteFile20(map, image, params, 0); - } - - msFree(bandlist); - msWCSClearCoverageMetadata20(&cm); - msFreeImage(image); - return MS_SUCCESS; -} - -#endif /* defined(USE_LIBXML2) */ - -#endif /* defined(USE_WCS_SVR) */ diff --git a/mapwfs.cpp b/mapwfs.cpp deleted file mode 100644 index ddb0df3198..0000000000 --- a/mapwfs.cpp +++ /dev/null @@ -1,5532 +0,0 @@ -/********************************************************************** - * $Id$ - * - * Project: MapServer - * Purpose: WFS server implementation - * Author: Daniel Morissette, DM Solutions Group (morissette@dmsolutions.ca) - * - ********************************************************************** - * Copyright (c) 2002, Daniel Morissette, DM Solutions Group Inc - * Copyright (c) 2013, Even Rouault - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies of this Software or works derived from this Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - ****************************************************************************/ - -#include "mapserver.h" -#include "mapows.h" - -#include - - -#if defined(USE_WFS_SVR) - -/* There is a dependency to GDAL/OGR for the GML driver and MiniXML parser */ -#include "cpl_minixml.h" -#include "cpl_conv.h" -#include "cpl_string.h" - -#include "mapogcfilter.h" -#include "mapowscommon.h" -#include "maptemplate.h" - -#if defined(USE_LIBXML2) -#include "maplibxml2.h" -#endif - -#include - -static int msWFSAnalyzeStoredQuery(mapObj* map, - wfsParamsObj *wfsparams, - const char* id, - const char* pszResolvedQuery); -static void msWFSSimplifyPropertyNameAndFilter(wfsParamsObj *wfsparams); -static void msWFSAnalyzeStartIndexAndFeatureCount(mapObj *map, const wfsParamsObj *paramsObj, - int bIsHits, - int *pmaxfeatures, int* pstartindex); -static int msWFSRunBasicGetFeature(mapObj* map, - layerObj* lp, - const wfsParamsObj *paramsObj, - int nWFSVersion); - -/* Must be sorted from more recent to older one */ -static const int wfsSupportedVersions[] = {OWS_2_0_0, OWS_1_1_0, OWS_1_0_0}; -static const char* const wfsSupportedVersionsStr[] = { "2.0.0", "1.1.0", "1.0.0" }; -static const int wfsNumSupportedVersions = - (int)(sizeof(wfsSupportedVersions)/sizeof(wfsSupportedVersions[0])); -static const char* const wfsUnsupportedOperations[] = { "GetFeatureWithLock", - "LockFeature", - "Transaction", - "CreateStoredQuery", - "DropStoredQuery" }; -static const int wfsNumUnsupportedOperations = - (int)(sizeof(wfsUnsupportedOperations)/sizeof(wfsUnsupportedOperations[0])); - -#define WFS_LATEST_VERSION wfsSupportedVersionsStr[0] - -/* Supported DescribeFeature formats */ -typedef enum -{ - OWS_DEFAULT_SCHEMA, /* basically a GML 2.1 schema */ - OWS_SFE_SCHEMA, /* GML for simple feature exchange (formerly GML3L0) */ - OWS_GML32_SFE_SCHEMA /* GML 3.2 Simple Features Level 0 */ -} WFSSchemaVersion; - -/* -** msWFSGetIndexUnsupportedOperation() -** -** Return index of pszOp in wfsUnsupportedOperations, or -1 otherwise -*/ - -static int msWFSGetIndexUnsupportedOperation(const char* pszOp) -{ - int i; - for(i = 0; i < wfsNumUnsupportedOperations; i++ ) - { - if( strcasecmp(wfsUnsupportedOperations[i], pszOp) == 0 ) - return i; - } - return -1; -} - - -static -const char *msWFSGetDefaultVersion(mapObj *map); - -/* -** msWFSException() -** -** Report current MapServer error in XML exception format. -*/ - -static -int msWFSExceptionInternal(mapObj *map, const char *locator, const char *code, - const char *version, int locatorShouldBeNull ) -{ - char *schemalocation = NULL; - /* In WFS, exceptions are always XML. - */ - - if( version == NULL ) - version = msWFSGetDefaultVersion(map); - - if( msOWSParseVersionString(version) >= OWS_2_0_0 ) - return msWFSException20( map, (locatorShouldBeNull) ? NULL : locator, code ); - if( msOWSParseVersionString(version) >= OWS_1_1_0 ) - return msWFSException11( map, (locatorShouldBeNull) ? NULL : locator, code, version ); - - msIO_setHeader("Content-Type","text/xml; charset=UTF-8"); - msIO_sendHeaders(); - - msIO_printf("\n"); - - msIO_printf("\n", schemalocation); - free(schemalocation); - msIO_printf(" \n", code, locator); - /* Optional element currently unused. */ - /* msIO_printf(" \n"); */ - msWriteErrorXML(stdout); - /* msIO_printf(" \n"); */ - msIO_printf(" \n"); - msIO_printf("\n"); - - return MS_FAILURE; /* so we can call 'return msWFSException();' anywhere */ -} - -int msWFSException(mapObj *map, const char *locator, const char *code, - const char *version ) -{ - return msWFSExceptionInternal(map, locator, code, version, FALSE); -} - - -/* -** msWFSExceptionNoLocator() -** -** Report current MapServer error in XML exception format. -** For WFS >= 1.1.0, the locator will be ignored. It will be just used -** for legacy WFS 1.0 exceptions. -*/ - -static -int msWFSExceptionNoLocator(mapObj *map, const char *locator, const char *code, - const char *version ) -{ - return msWFSExceptionInternal(map, locator, code, version, TRUE); -} - -/* -** Helper function to build a list of output formats. -** -** Given a layer it will return all formats valid for that layer, otherwise -** all formats permitted on layers in the map are returned. The string -** returned should be freed by the caller. -*/ - -char *msWFSGetOutputFormatList(mapObj *map, layerObj *layer, int nWFSVersion ) -{ - int i, got_map_list = 0; - static const int out_list_size = 20000; - char *out_list = (char*) msSmallCalloc(1,out_list_size); - - if( nWFSVersion == OWS_1_0_0 ) - strcpy(out_list,"GML2"); - else if( nWFSVersion == OWS_1_1_0 ) - strcpy(out_list,"text/xml; subtype=gml/3.1.1"); - else - strcpy(out_list,"application/gml+xml; version=3.2," - "text/xml; subtype=gml/3.2.1," - "text/xml; subtype=gml/3.1.1," - "text/xml; subtype=gml/2.1.2"); - - for( i = 0; i < map->numlayers; i++ ) { - const char *format_list; - layerObj *lp; - int j, n; - char **tokens; - - lp = GET_LAYER(map, i); - if( layer != NULL && layer != lp ) - continue; - - format_list = msOWSLookupMetadata(&(lp->metadata), - "F","getfeature_formatlist"); - - if( format_list == NULL && !got_map_list ) { - format_list = msOWSLookupMetadata(&(map->web.metadata), - "F","getfeature_formatlist"); - got_map_list = 1; - } - - if( format_list == NULL ) - continue; - - n = 0; - tokens = msStringSplit(format_list, ',', &n); - - for( j = 0; j < n; j++ ) { - int iformat; - const char *fname, *hit; - outputFormatObj *format_obj; - - msStringTrim( tokens[j] ); - iformat = msGetOutputFormatIndex(map,tokens[j]); - if( iformat < 0 ) - continue; - - format_obj = map->outputformatlist[iformat]; - - fname = format_obj->name; - if( nWFSVersion >= OWS_1_1_0 - && format_obj->mimetype != NULL ) - fname = format_obj->mimetype; - - hit = strstr(out_list,fname); - if( hit != NULL - && (hit[strlen(fname)] == '\0' || hit[strlen(fname)] == ',')) - continue; - - if( strlen(out_list) + strlen(fname)+3 < out_list_size ) { - strcat( out_list, "," ); - strcat( out_list, fname ); - } else - break; - } - - msFreeCharArray( tokens, n ); - } - - return out_list; -} - -/* -** -*/ -static void msWFSPrintRequestCap(const char *wmtver, const char *request, - const char *script_url, - const char *format_tag, - const char *formats_list) -{ - msIO_printf(" <%s>\n", request); - - /* We expect to receive a NULL-terminated args list of formats */ - if (format_tag != NULL) { - int i, n; - char **tokens; - - n = 0; - tokens = msStringSplit(formats_list, ',', &n); - - msIO_printf(" <%s>\n", format_tag); - - for( i = 0; i < n; i++ ) { - msIO_printf(" <%s/>\n", tokens[i] ); - } - - msFreeCharArray( tokens, n ); - - msIO_printf(" \n", format_tag); - } - - msIO_printf(" \n"); - msIO_printf(" \n"); - msIO_printf(" \n", script_url); - msIO_printf(" \n"); - msIO_printf(" \n"); - msIO_printf(" \n"); - msIO_printf(" \n"); - msIO_printf(" \n", script_url); - msIO_printf(" \n"); - msIO_printf(" \n"); - - - msIO_printf(" \n", request); -} - - -/* msWFSLocateSRSInList() -** -** Utility function to check if a space separated list contains the one passed in argument. -** The list comes normaly from ows_srs metadata, and is expected to use the simple EPSG notation -** (EPSG:4326 ESPG:42304 ...). The srs comes from the query string and can either -** be of simple EPSG format or using gc:def:crs:EPSG:xxx format -*/ -int msWFSLocateSRSInList(const char *pszList, const char *srs) -{ - int nTokens,i; - char **tokens = NULL; - int bFound = MS_FALSE; - char epsg_string[100]; - const char *code; - - if (!pszList || !srs) - return MS_FALSE; - - if (strncasecmp(srs, "EPSG:",5) == 0) - code = srs+5; - else if (strncasecmp(srs, "urn:ogc:def:crs:EPSG:",21) == 0) { - if (srs[21] == ':') - code = srs+21; - else - code = srs+20; - - while( *code != ':' && *code != '\0') - code++; - if( *code == ':' ) - code++; - } else if (strncasecmp(srs, "urn:EPSG:geographicCRS:",23) == 0) - code = srs + 23; - else - return MS_FALSE; - - snprintf( epsg_string, sizeof(epsg_string), "EPSG:%s", code ); - - tokens = msStringSplit(pszList, ' ', &nTokens ); - if (tokens && nTokens > 0) { - for (i=0; iprojection), &(map->web.metadata), "FO", MS_TRUE, &pszMapSRS); - if(pszMapSRS && nWFSVersion > OWS_1_0_0){ - projectionObj proj; - msInitProjection(&proj); - msProjectionInheritContextFrom(&proj, &(map->projection)); - if (map->projection.numargs > 0 && msLoadProjectionStringEPSG(&proj, pszMapSRS) == 0) { - msProjectRect(&(map->projection), &proj, &map->extent); - } - msLoadProjectionStringEPSG(&(map->projection), pszMapSRS); - msFreeProjection(&proj); - } - - if (srs == NULL || nWFSVersion == OWS_1_0_0) { - for (i=0; inumlayers; i++) { - char *pszLayerSRS; - lp = GET_LAYER(map, i); - if (lp->status != MS_ON) - continue; - - if (pszMapSRS) - pszLayerSRS = pszMapSRS; - else - msOWSGetEPSGProj(&(lp->projection), &(lp->metadata), "FO", MS_TRUE, &pszLayerSRS); - - if (pszLayerSRS == NULL) { - msSetError(MS_WFSERR, - "Server config error: SRS must be set at least at the map or at the layer level.", - "msWFSGetFeature()"); - if (pszOutputSRS) - msFree(pszOutputSRS); - /*pszMapSrs would also be NULL, no use freeing*/ - return MS_FAILURE; - } - if (pszOutputSRS == NULL) - pszOutputSRS = msStrdup(pszLayerSRS); - else if (strcasecmp(pszLayerSRS,pszOutputSRS) != 0) { - msSetError(MS_WFSERR, - "Invalid GetFeature Request: All TYPENAMES in a single GetFeature request must have been advertized in the same SRS. Please check the capabilities and reformulate your request.", - "msWFSGetFeature()"); - if (pszOutputSRS) - msFree(pszOutputSRS); - if(pszLayerSRS != pszMapSRS) - msFree(pszLayerSRS); - msFree(pszMapSRS); - return MS_FAILURE; - } - if(pszLayerSRS != pszMapSRS) - msFree(pszLayerSRS); - } - } else { /*srs is given so it should be valid for all layers*/ - /*get all the srs defined at the map level and check them aginst the srsName passed - as argument*/ - msFree(pszMapSRS); - msOWSGetEPSGProj(&(map->projection), &(map->web.metadata), "FO", MS_FALSE, &pszMapSRS); - if (pszMapSRS) { - if (!msWFSLocateSRSInList(pszMapSRS, srs)) { - msSetError(MS_WFSERR, - "Invalid GetFeature Request:Invalid SRS. Please check the capabilities and reformulate your request.", - "msWFSGetFeature()"); - msFree(pszMapSRS); - return MS_FAILURE; - } - pszOutputSRS = msStrdup(srs); - } else { - for (i=0; inumlayers; i++) { - char *pszLayerSRS=NULL; - lp = GET_LAYER(map, i); - if (lp->status != MS_ON) - continue; - - msOWSGetEPSGProj(&(lp->projection), &(lp->metadata), "FO", MS_FALSE, &pszLayerSRS); - if (!pszLayerSRS) { - msSetError(MS_WFSERR, - "Server config error: SRS must be set at least at the map or at the layer level.", - "msWFSGetFeature()"); - msFree(pszMapSRS); - return MS_FAILURE; - } - if (!msWFSLocateSRSInList(pszLayerSRS, srs)) { - msSetError(MS_WFSERR, - "Invalid GetFeature Request:Invalid SRS. Please check the capabilities and reformulate your request.", - "msWFSGetFeature()"); - msFree(pszMapSRS); - msFree(pszLayerSRS); - return MS_FAILURE; - } - msFree(pszLayerSRS); - } - pszOutputSRS = msStrdup(srs); - } - } - - if (pszOutputSRS) { - projectionObj sProjTmp; - int nTmp=0; - - msInitProjection(&sProjTmp); - msProjectionInheritContextFrom(&sProjTmp, &(map->projection)); - if( nWFSVersion >= OWS_1_1_0 ) { - nTmp = msLoadProjectionStringEPSG(&(sProjTmp), pszOutputSRS); - } else { - nTmp = msLoadProjectionString(&(sProjTmp), pszOutputSRS); - } - if (nTmp == 0) { - msProjectRect(&(map->projection), &(sProjTmp), &map->extent); - } - msFreeProjection(&(sProjTmp)); - - if (nTmp != 0) { - msSetError(MS_WFSERR, "msLoadProjectionString() failed", "msWFSGetFeature()"); - return MS_FAILURE; - } - - /*we load the projection sting in the map and possibly - set the axis order*/ - if( nWFSVersion >= OWS_1_1_0 ) { - msLoadProjectionStringEPSG(&(map->projection), pszOutputSRS); - } else { - msLoadProjectionString(&(map->projection), pszOutputSRS); - } - - nTmp = GetMapserverUnitUsingProj(&(map->projection)); - if( nTmp != -1 ) { - map->units = static_cast(nTmp); - } - } - - msFree(pszOutputSRS); - msFree(pszMapSRS); - return MS_SUCCESS; -} - - -/* msWFSIsLayerSupported() -** -** Returns true (1) is this layer meets the requirements to be served as -** a WFS feature type. -*/ -int msWFSIsLayerSupported(layerObj *lp) -{ - /* In order to be supported, lp->type must be specified, even for - ** layers that are OGR, SDE, SDO, etc connections. - */ - if ((lp->type == MS_LAYER_POINT || - lp->type == MS_LAYER_LINE || - lp->type == MS_LAYER_POLYGON ) && - lp->connectiontype != MS_WMS && - lp->connectiontype != MS_GRATICULE) { - return 1; /* true */ - } - - return 0; /* false */ -} - -static int msWFSIsLayerAllowed(layerObj *lp, owsRequestObj *ows_request) -{ - return msWFSIsLayerSupported(lp) && - (msIntegerInArray(lp->index, ows_request->enabled_layers, ows_request->numlayers)); -} - -static layerObj* msWFSGetLayerByName(mapObj* map, owsRequestObj *ows_request, const char* name) -{ - int j; - for (j=0; jnumlayers; j++) { - layerObj *lp; - - lp = GET_LAYER(map, j); - - if (msWFSIsLayerAllowed(lp, ows_request) && lp->name && (strcasecmp(lp->name, name) == 0)) { - return lp; - } - } - return NULL; -} - -/* -** msWFSDumpLayer() -*/ -int msWFSDumpLayer(mapObj *map, layerObj *lp, const char *script_url_encoded) -{ - rectObj ext; - char *pszWfsSrs = NULL; - projectionObj poWfs; - - msIO_printf(" \n"); - - if (lp->name && strlen(lp->name) > 0 && - (msIsXMLTagValid(lp->name) == MS_FALSE || isdigit(lp->name[0]))) - msIO_fprintf(stdout, "\n",lp->name); - - msOWSPrintEncodeParam(stdout, "LAYER.NAME", lp->name, OWS_WARN, - " %s\n", NULL); - - msOWSPrintEncodeMetadata(stdout, &(lp->metadata), "FO", "title", - OWS_WARN, " %s\n", lp->name); - - msOWSPrintEncodeMetadata(stdout, &(lp->metadata), "FO", "abstract", - OWS_NOERR, " %s\n", NULL); - - msOWSPrintEncodeMetadataList(stdout, &(lp->metadata), "FO", - "keywordlist", - " \n", - " \n", - " %s\n", NULL); - - /* In WFS, every layer must have exactly one SRS and there is none at */ - /* the top level contrary to WMS */ - /* */ - /* So here is the way we'll deal with SRS: */ - /* 1- If a top-level map projection (or wfs_srs metadata) is set then */ - /* all layers are advertized in the map's projection and they will */ - /* be reprojected on the fly in the GetFeature request. */ - /* 2- If there is no top-level map projection (or wfs_srs metadata) then */ - /* each layer is advertized in its own projection as defined in the */ - /* layer's projection object or wfs_srs metadata. */ - /* */ - - /* if Map has a SRS, Use it for all layers. */ - msOWSGetEPSGProj(&(map->projection),&(map->web.metadata),"FO",MS_TRUE, &pszWfsSrs); - if(!pszWfsSrs) { - /* Map has no SRS. Use layer SRS or produce a warning. */ - msOWSGetEPSGProj(&(lp->projection),&(lp->metadata), "FO", MS_TRUE, &pszWfsSrs); - } - - msOWSPrintEncodeParam(stdout, "(at least one of) MAP.PROJECTION, LAYER.PROJECTION or wfs_srs metadata", - pszWfsSrs, OWS_WARN, " %s\n", NULL); - - /* If layer has no proj set then use map->proj for bounding box. */ - if (msOWSGetLayerExtent(map, lp, "FO", &ext) == MS_SUCCESS) { - msInitProjection(&poWfs); - msProjectionInheritContextFrom(&poWfs, &(map->projection)); - if (pszWfsSrs != NULL) - msLoadProjectionString(&(poWfs), pszWfsSrs); - - if(lp->projection.numargs > 0) { - msOWSPrintLatLonBoundingBox(stdout, " ", &(ext), - &(lp->projection), &(poWfs), OWS_WFS); - } else { - msOWSPrintLatLonBoundingBox(stdout, " ", &(ext), - &(map->projection), &(poWfs), OWS_WFS); - } - msFreeProjection(&poWfs); - } else { - msIO_printf("\n"); - } - - const char* metadataurl_list = msOWSLookupMetadata(&(lp->metadata), "FO", "metadataurl_list"); - if( metadataurl_list ) { - int ntokens = 0; - char** tokens = msStringSplit(metadataurl_list, ' ', &ntokens); - for( int i = 0; i < ntokens; i++ ) - { - std::string key("metadataurl_"); - key += tokens[i]; - msOWSPrintURLType(stdout, &(lp->metadata), "FO", key.c_str(), - OWS_WARN, NULL, "MetadataURL", " type=\"%s\"", - NULL, NULL, " format=\"%s\"", "%s", - MS_TRUE, MS_FALSE, MS_FALSE, MS_TRUE, MS_TRUE, - NULL, NULL, NULL, NULL, NULL, " "); - } - msFreeCharArray(tokens, ntokens); - } - else { - if (! msOWSLookupMetadata(&(lp->metadata), "FO", "metadataurl_href")) - msMetadataSetGetMetadataURL(lp, script_url_encoded); - - msOWSPrintURLType(stdout, &(lp->metadata), "FO", "metadataurl", - OWS_WARN, NULL, "MetadataURL", " type=\"%s\"", - NULL, NULL, " format=\"%s\"", "%s", - MS_TRUE, MS_FALSE, MS_FALSE, MS_TRUE, MS_TRUE, - NULL, NULL, NULL, NULL, NULL, " "); - } - - if (msOWSLookupMetadata(&(lp->metadata), "OFG", "featureid") == NULL) { - msIO_fprintf(stdout, "\n"); - } - - msIO_printf(" \n"); - - msFree(pszWfsSrs); - return MS_SUCCESS; -} - -/* -** msWFSHandleUpdateSequence() -*/ -int msWFSHandleUpdateSequence(mapObj *map, wfsParamsObj *params, const char* pszFunction) -{ - /* -------------------------------------------------------------------- */ - /* Handle updatesequence */ - /* -------------------------------------------------------------------- */ - - const char* updatesequence = msOWSLookupMetadata(&(map->web.metadata), "FO", "updatesequence"); - - if (params->pszUpdateSequence != NULL) { - int i = msOWSNegotiateUpdateSequence(params->pszUpdateSequence, updatesequence); - if (i == 0) { /* current */ - msSetError(MS_WFSERR, "UPDATESEQUENCE parameter (%s) is equal to server (%s)", pszFunction, params->pszUpdateSequence, updatesequence); - /* FIXME? : according to table 7 of OWS 1.1, we should return a service */ - /* metadata document with only “version” and “updateSequence” parameters */ - return msWFSException(map, "updatesequence", "CurrentUpdateSequence", params->pszVersion); - } - if (i > 0) { /* invalid */ - msSetError(MS_WFSERR, "UPDATESEQUENCE parameter (%s) is higher than server (%s)", pszFunction, params->pszUpdateSequence, updatesequence); - /* locator must be NULL. See Table 25 of OWS 1.1 */ - return msWFSExceptionNoLocator(map, "updatesequence", MS_OWS_ERROR_INVALID_UPDATE_SEQUENCE, params->pszVersion); - } - } - - return MS_SUCCESS; -} - - -/* -** msWFSGetCapabilitiesNegotiateVersion() -*/ -static int msWFSGetCapabilitiesNegotiateVersion(mapObj *map, wfsParamsObj *wfsparams) -{ - int iVersion = -1; - char tmpString[OWS_VERSION_MAXLEN]; - - /* acceptversions: do OWS Common style of version negotiation */ - if (wfsparams->pszAcceptVersions && strlen(wfsparams->pszAcceptVersions) > 0) { - char **tokens; - int i, j; - - tokens = msStringSplit(wfsparams->pszAcceptVersions, ',', &j); - for (i=0; ipszAcceptVersions); - /* locator must be NULL. See Table 25 of OWS 1.1 */ - return msWFSExceptionNoLocator(map, "acceptversions", MS_OWS_ERROR_VERSION_NEGOTIATION_FAILED,NULL); - } - } else { - /* negotiate version */ - int tmpInt; - iVersion = msOWSParseVersionString(wfsparams->pszVersion); - if( iVersion < 0 ) - { - return msWFSException(map, "version", MS_OWS_ERROR_INVALID_PARAMETER_VALUE, NULL); - } - tmpInt = msOWSCommonNegotiateVersion(iVersion, wfsSupportedVersions, wfsNumSupportedVersions); - /* Old style negociation : paragraph D.11 of OWS 1.1.0 spec */ - if( tmpInt < 0 ) - { - int i; - for( i = 0 ; i < wfsNumSupportedVersions; i++ ) - { - if( iVersion >= wfsSupportedVersions[i] ) - { - iVersion = wfsSupportedVersions[i]; - break; - } - } - if( i == wfsNumSupportedVersions ) - iVersion = wfsSupportedVersions[wfsNumSupportedVersions - 1]; - } - } - - /* set result as string and carry on */ - if (wfsparams->pszVersion) - msFree(wfsparams->pszVersion); - wfsparams->pszVersion = msStrdup(msOWSGetVersionString(iVersion, tmpString)); - - return MS_SUCCESS; -} - - -/* -** msWFSGetCapabilities() -*/ -int msWFSGetCapabilities(mapObj *map, wfsParamsObj *wfsparams, cgiRequestObj *req, owsRequestObj *ows_request) -{ - char *script_url=NULL, *script_url_encoded; - const char *updatesequence=NULL; - const char *wmtver=NULL; - char *formats_list; - int ret; - int iVersion; - int i=0; - - ret = msWFSGetCapabilitiesNegotiateVersion(map, wfsparams); - if( ret != MS_SUCCESS ) - return ret; - - iVersion = msOWSParseVersionString(wfsparams->pszVersion); - if( iVersion == OWS_2_0_0 ) - return msWFSGetCapabilities20( map, wfsparams, req, ows_request); - if( iVersion == OWS_1_1_0 ) - return msWFSGetCapabilities11( map, wfsparams, req, ows_request); - - /* Decide which version we're going to return... only 1.0.0 for now */ - wmtver = "1.0.0"; - - /* We need this server's onlineresource. */ - if ((script_url=msOWSGetOnlineResource(map, "FO", "onlineresource", req)) == NULL || - (script_url_encoded = msEncodeHTMLEntities(script_url)) == NULL) { - msSetError(MS_WFSERR, "Server URL not found", "msWFSGetCapabilities()"); - return msWFSException(map, "mapserv", MS_OWS_ERROR_NO_APPLICABLE_CODE, wmtver); - } - free(script_url); - script_url = NULL; - - ret = msWFSHandleUpdateSequence(map, wfsparams, "msWFSGetCapabilities()"); - if( ret != MS_SUCCESS ) - { - free(script_url_encoded); - return ret; - } - - msIO_setHeader("Content-Type","text/xml; charset=UTF-8"); - msIO_sendHeaders(); - - msIO_printf("\n"); - - updatesequence = msOWSLookupMetadata(&(map->web.metadata), "FO", "updatesequence"); - msIO_printf("\n", - wmtver, updatesequence ? updatesequence : "0", - msOWSGetSchemasLocation(map), wmtver); - - /* Report MapServer Version Information */ - msIO_printf("\n\n\n", msGetVersion()); - - /* - ** SERVICE definition - */ - msIO_printf("\n"); - msIO_printf(" MapServer WFS\n"); - - /* the majority of this section is dependent on appropriately named metadata in the WEB object */ - msOWSPrintEncodeMetadata(stdout, &(map->web.metadata), "FO", "title", - OWS_WARN, " %s\n", map->name); - msOWSPrintEncodeMetadata(stdout, &(map->web.metadata), "FO", "abstract", - OWS_NOERR, " %s\n", NULL); - - msOWSPrintEncodeMetadataList(stdout, &(map->web.metadata), "FO", - "keywordlist", - " \n", " \n", - " %s\n", NULL); - - /* Service/onlineresource */ - /* Defaults to same as request onlineresource if wfs_service_onlineresource */ - /* is not set. */ - msOWSPrintEncodeMetadata(stdout, &(map->web.metadata), - "FO", "service_onlineresource", OWS_NOERR, - " %s\n", - script_url_encoded); - - msOWSPrintEncodeMetadata(stdout, &(map->web.metadata), "FO", "fees", - OWS_NOERR, " %s\n", NULL); - - msOWSPrintEncodeMetadata(stdout, &(map->web.metadata), "FO", - "accessconstraints", OWS_NOERR, - " %s\n", - NULL); - - msIO_printf("\n\n"); - - /* - ** CAPABILITY definitions: list of supported requests - */ - - msIO_printf("\n"); - - msIO_printf(" \n"); - msWFSPrintRequestCap(wmtver, "GetCapabilities", script_url_encoded, - NULL, NULL); - /* msWFSPrintRequestCap(wmtver, "DescribeFeatureType", script_url_encoded, "SchemaDescriptionLanguage", "XMLSCHEMA", "SFE_XMLSCHEMA", NULL); */ - /* msWFSPrintRequestCap(wmtver, "GetFeature", script_url_encoded, "ResultFormat", "GML2", "GML3", NULL); */ - - /* don't advertise the GML3 or GML for SFE support */ - if (msOWSRequestIsEnabled(map, NULL, "F", "DescribeFeatureType", MS_TRUE)) - msWFSPrintRequestCap(wmtver, "DescribeFeatureType", script_url_encoded, "SchemaDescriptionLanguage", "XMLSCHEMA" ); - - if (msOWSRequestIsEnabled(map, NULL, "F", "GetFeature", MS_TRUE)) { - formats_list = msWFSGetOutputFormatList( map, NULL, OWS_1_0_0 ); - msWFSPrintRequestCap(wmtver, "GetFeature", script_url_encoded, "ResultFormat", formats_list ); - msFree( formats_list ); - } - - msIO_printf(" \n"); - msIO_printf("\n\n"); - - /* - ** FeatureTypeList: layers - */ - - msIO_printf("\n"); - - /* Operations supported... set default at top-level, and more operations */ - /* can be added inside each layer... for MapServer only query is supported */ - msIO_printf(" \n"); - msIO_printf(" \n"); - msIO_printf(" \n"); - - for(i=0; inumlayers; i++) { - layerObj *lp; - lp = GET_LAYER(map, i); - - if (lp->status == MS_DELETE) - continue; - - if (msWFSIsLayerAllowed(lp, ows_request)) { - msWFSDumpLayer(map, lp, script_url_encoded); - } - } - - msIO_printf("\n\n"); - - - /* - ** OGC Filter Capabilities ... for now we support only BBOX - */ - - msIO_printf("\n"); - msIO_printf(" \n"); - msIO_printf(" \n"); -#ifdef USE_GEOS - msIO_printf(" \n"); - msIO_printf(" \n"); - msIO_printf(" \n"); - msIO_printf(" \n"); - msIO_printf(" \n"); - msIO_printf(" \n"); - msIO_printf(" \n"); - msIO_printf(" \n"); - msIO_printf(" \n"); -#endif - msIO_printf(" \n"); - msIO_printf(" \n"); - msIO_printf(" \n"); - - msIO_printf(" \n"); - msIO_printf(" \n"); - msIO_printf(" \n"); - msIO_printf(" \n"); - msIO_printf(" \n"); - msIO_printf(" \n"); - msIO_printf(" \n"); - msIO_printf(" \n"); - - msIO_printf("\n\n"); - - /* - ** Done! - */ - msIO_printf("\n"); - - free(script_url_encoded); - - return MS_SUCCESS; -} - -/* -** Helper functions for producing XML schema. -*/ - -static const char *msWFSGetGeometryType(const char *type, OWSGMLVersion outputformat) -{ - if(!type) return "GeometryPropertyType"; - - if(strcasecmp(type, "point") == 0) { - switch(outputformat) { - case OWS_GML2: - case OWS_GML3: - case OWS_GML32: - return "PointPropertyType"; - } - } else if(strcasecmp(type, "multipoint") == 0) { - switch(outputformat) { - case OWS_GML2: - case OWS_GML3: - case OWS_GML32: - return "MultiPointPropertyType"; - } - } else if(strcasecmp(type, "line") == 0) { - switch(outputformat) { - case OWS_GML2: - return "LineStringPropertyType"; - case OWS_GML3: - case OWS_GML32: - return "CurvePropertyType"; - } - } else if(strcasecmp(type, "multiline") == 0) { - switch(outputformat) { - case OWS_GML2: - return "MultiLineStringPropertyType"; - case OWS_GML3: - case OWS_GML32: - return "MultiCurvePropertyType"; - } - } else if(strcasecmp(type, "polygon") == 0) { - switch(outputformat) { - case OWS_GML2: - return "PolygonPropertyType"; - case OWS_GML3: - case OWS_GML32: - return "SurfacePropertyType"; - } - } else if(strcasecmp(type, "multipolygon") == 0) { - switch(outputformat) { - case OWS_GML2: - return "MultiPolygonPropertyType"; - case OWS_GML3: - case OWS_GML32: - return "MultiSurfacePropertyType"; - } - } - - return "???unknown???"; -} - -static void msWFSWriteGeometryElement(FILE *stream, gmlGeometryListObj *geometryList, OWSGMLVersion outputformat, const char *tab) -{ - int i; - gmlGeometryObj *geometry=NULL; - - if(!stream || !tab) return; - if(geometryList && geometryList->numgeometries == 1 && strcasecmp(geometryList->geometries[0].name, "none") == 0) return; - - if(geometryList->numgeometries == 1) { - geometry = &(geometryList->geometries[0]); - msIO_fprintf(stream, "%sname, msWFSGetGeometryType(geometry->type, outputformat), geometry->occurmin); - if(geometry->occurmax == OWS_GML_OCCUR_UNBOUNDED) - msIO_fprintf(stream, " maxOccurs=\"unbounded\"/>\n"); - else - msIO_fprintf(stream, " maxOccurs=\"%d\"/>\n", geometry->occurmax); - } else { - msIO_fprintf(stream, "%s\n", tab); - for(i=0; inumgeometries; i++) { - geometry = &(geometryList->geometries[i]); - - msIO_fprintf(stream, " %sname, msWFSGetGeometryType(geometry->type, outputformat), geometry->occurmin); - if(geometry->occurmax == OWS_GML_OCCUR_UNBOUNDED) - msIO_fprintf(stream, " maxOccurs=\"unbounded\"/>\n"); - else - msIO_fprintf(stream, " maxOccurs=\"%d\"/>\n", geometry->occurmax); - } - msIO_fprintf(stream, "%s\n", tab); - } - - return; -} - -static OWSGMLVersion msWFSGetGMLVersionFromSchemaVersion(WFSSchemaVersion outputformat) -{ - switch( outputformat ) - { - case OWS_DEFAULT_SCHEMA: - return OWS_GML2; - case OWS_SFE_SCHEMA: - return OWS_GML3; - case OWS_GML32_SFE_SCHEMA: - return OWS_GML32; - } - return OWS_GML2; -} - -static void msWFSSchemaWriteGeometryElement(FILE *stream, gmlGeometryListObj *geometryList, WFSSchemaVersion outputformat, const char *tab) -{ - OWSGMLVersion gmlversion = msWFSGetGMLVersionFromSchemaVersion(outputformat); - msWFSWriteGeometryElement(stream,geometryList,gmlversion,tab); -} - -static const char* msWFSMapServTypeToXMLType(const char* type) -{ - const char *element_type = "string"; - /* Map from MapServer types to XSD types */ - if( strcasecmp(type,"Integer") == 0 ) - element_type = "integer"; - /* Note : xs:int and xs:integer differ */ - else if ( EQUAL(type,"int") ) - element_type = "int"; - if( strcasecmp(type,"Long") == 0 ) /* 64bit integer */ - element_type = "long"; - else if( EQUAL(type,"Real") || - EQUAL(type,"double") /* just in case someone provided the xsd type directly */ ) - element_type = "double"; - else if( EQUAL(type,"Character") ) - element_type = "string"; - else if( EQUAL(type,"Date") ) - element_type = "date"; - else if( EQUAL(type,"Time") ) - element_type = "time"; - else if( EQUAL(type,"DateTime") ) - element_type = "dateTime"; - else if( EQUAL(type,"Boolean") ) - element_type = "boolean"; - return element_type; -} - -static void msWFSWriteItemElement(FILE *stream, gmlItemObj *item, const char *tab, - WFSSchemaVersion outputformat, int is_nillable) -{ - const char *element_name; - const char *element_type = "string"; - const char *pszMinOccurs = ""; - const char* pszNillable = ""; - - if(!stream || !item || !tab) return; - if(!item->visible) return; /* not exposing this attribute */ - if(item->_template) return; /* can't adequately deal with templated items yet */ - - if(item->alias) /* TODO: what about name spaces embedded in the alias? */ - element_name = item->alias; - else - element_name = item->name; - - if(item->type) - { - if( outputformat == OWS_GML32_SFE_SCHEMA && - (EQUAL(item->type,"Date") || EQUAL(item->type,"Time") || EQUAL(item->type,"DateTime")) ) - element_type = "gml:TimeInstantType"; - else - element_type = msWFSMapServTypeToXMLType(item->type); - } - - if( item->minOccurs == 0 ) - pszMinOccurs = " minOccurs=\"0\""; - - if( is_nillable ) - pszNillable = " nillable=\"true\""; - - msIO_fprintf(stream, "%s\n", tab, element_name, pszMinOccurs, pszNillable, element_type); - - return; -} - -static void msWFSWriteConstantElement(FILE *stream, gmlConstantObj *constant, const char *tab) -{ - const char *element_type = "string"; - - if(!stream || !constant || !tab) return; - - if(constant->type) - element_type = msWFSMapServTypeToXMLType(constant->type); - - msIO_fprintf(stream, "%s\n", tab, constant->name, element_type); - - return; -} - -static void msWFSWriteGroupElement(FILE *stream, gmlGroupObj *group, const char *tab, const char *_namespace) -{ - if(group->type) - msIO_fprintf(stream, "%s\n", tab, group->name, _namespace, group->type); - else - msIO_fprintf(stream, "%s\n", tab, group->name, _namespace, group->name); - - return; -} - -static void msWFSWriteGroupElementType(FILE *stream, gmlGroupObj *group, - gmlItemListObj *itemList, - gmlConstantListObj *constantList, - const char *tab, - WFSSchemaVersion outputformat) -{ - int i, j; - char *element_tab; - - gmlItemObj *item=NULL; - gmlConstantObj *constant=NULL; - - /* setup the element tab */ - element_tab = (char *) msSmallMalloc(sizeof(char)*strlen(tab)+5); - sprintf(element_tab, "%s ", tab); - - if(group->type) - msIO_fprintf(stream, "%s\n", tab, group->type); - else - msIO_fprintf(stream, "%s\n", tab, group->name); - - msIO_fprintf(stream, "%s \n", tab); - - /* now the items/constants (e.g. elements) in the group */ - for(i=0; inumitems; i++) { - for(j=0; jnumconstants; j++) { /* find the right gmlConstantObj */ - constant = &(constantList->constants[j]); - if(strcasecmp(constant->name, group->items[i]) == 0) { - msWFSWriteConstantElement(stream, constant, element_tab); - break; - } - } - if(j != constantList->numconstants) continue; /* found this item */ - for(j=0; jnumitems; j++) { /* find the right gmlItemObj */ - item = &(itemList->items[j]); - if(strcasecmp(item->name, group->items[i]) == 0) { - msWFSWriteItemElement(stream, item, element_tab, outputformat, MS_FALSE); - break; - } - } - } - - msIO_fprintf(stream, "%s \n", tab); - msIO_fprintf(stream, "%s\n", tab); - free(element_tab); - - return; -} - -static const char* msWFSGetGMLSchemaLocation(OWSGMLVersion outputformat) -{ - switch( outputformat ) - { - case OWS_GML2: - return MS_OWSCOMMON_GML_212_SCHEMA_LOCATION; - case OWS_GML3: - return MS_OWSCOMMON_GML_311_SCHEMA_LOCATION; - case OWS_GML32: - return MS_OWSCOMMON_GML_321_SCHEMA_LOCATION; - } - return "/unknown.xsd"; -} - -static const char* msWFSGetGMLNamespaceURI(WFSSchemaVersion outputformat) -{ - switch( outputformat ) - { - case OWS_DEFAULT_SCHEMA: - return MS_OWSCOMMON_GML_NAMESPACE_URI; - case OWS_SFE_SCHEMA: - return MS_OWSCOMMON_GML_NAMESPACE_URI; - case OWS_GML32_SFE_SCHEMA: - return MS_OWSCOMMON_GML_32_NAMESPACE_URI; - } - return "http://unknown"; -} - -static const char* msWFSGetGMLNamespaceURIFromGMLVersion(OWSGMLVersion outputformat) -{ - switch( outputformat ) - { - case OWS_GML2: - return MS_OWSCOMMON_GML_NAMESPACE_URI; - case OWS_GML3: - return MS_OWSCOMMON_GML_NAMESPACE_URI; - case OWS_GML32: - return MS_OWSCOMMON_GML_32_NAMESPACE_URI; - } - return "http://unknown"; -} - -static void msWFS_NS_printf(const char* prefix, const char* uri) -{ - if( prefix == NULL ) - msIO_printf(" xmlns=\"%s\"\n", uri); - else - msIO_printf(" xmlns:%s=\"%s\"\n", prefix, uri); -} - -static void msWFSPrintAdditionalNamespaces(const gmlNamespaceListObj *namespaceList) -{ - int i; - /* any additional namespaces */ - for(i=0; inumnamespaces; i++) { - if(namespaceList->namespaces[i].uri) { - char *uri_encoded=NULL; - - uri_encoded = msEncodeHTMLEntities(namespaceList->namespaces[i].uri); - msWFS_NS_printf(namespaceList->namespaces[i].prefix, uri_encoded); - msFree(uri_encoded); - } - } -} - -static const char* msWFSStripNS(const char* name) -{ - const char* pszColon = strchr(name, ':'); - const char* pszSlash = strchr(name, '/'); - if( pszColon && (pszSlash == NULL || pszColon < pszSlash) ) - return pszColon + 1; - return name; -} - -/* -** msWFSDescribeFeatureType() -*/ -static -int msWFSDescribeFeatureType(mapObj *map, wfsParamsObj *paramsObj, owsRequestObj *ows_request, - int nWFSVersion) -{ - int i, numlayers=0; - char **layers = NULL; - - const char *value; - const char *user_namespace_prefix = MS_DEFAULT_NAMESPACE_PREFIX; - const char *user_namespace_uri = MS_DEFAULT_NAMESPACE_URI; - char *user_namespace_uri_encoded = NULL; - const char *collection_name = OWS_WFS_FEATURE_COLLECTION_NAME; - char *encoded; - - WFSSchemaVersion outputformat = OWS_DEFAULT_SCHEMA; /* default output is GML 2.1 compliant schema*/ - - gmlNamespaceListObj *namespaceList=NULL; /* for external application schema support */ - char *mimetype = NULL; - - if(paramsObj->pszTypeName && numlayers == 0) { - /* Parse comma-delimited list of type names (layers) */ - layers = msStringSplit(paramsObj->pszTypeName, ',', &numlayers); - if (numlayers > 0) { - /* strip namespace if there is one :ex TYPENAME=cdf:Other */ - for (i=0; ipszOutputFormat) { - if(strcasecmp(paramsObj->pszOutputFormat, "XMLSCHEMA") == 0 || - strstr(paramsObj->pszOutputFormat, "gml/2")!= NULL) { - mimetype = msEncodeHTMLEntities("text/xml; subtype=gml/2.1.2"); - outputformat = OWS_DEFAULT_SCHEMA; - } else if(strcasecmp(paramsObj->pszOutputFormat, "SFE_XMLSCHEMA") == 0 || - strstr(paramsObj->pszOutputFormat, "gml/3.1")!= NULL) { - mimetype = msEncodeHTMLEntities("text/xml; subtype=gml/3.1.1"); - outputformat = OWS_SFE_SCHEMA; - } else if(strstr(paramsObj->pszOutputFormat, "gml/3.2")!= NULL || - strstr(paramsObj->pszOutputFormat, "application/gml+xml; version=3.2")!= NULL) { - mimetype = msEncodeHTMLEntities("application/gml+xml; version=3.2"); - outputformat = OWS_GML32_SFE_SCHEMA; - } else { - msSetError(MS_WFSERR, "Unsupported DescribeFeatureType outputFormat (%s).", "msWFSDescribeFeatureType()", paramsObj->pszOutputFormat); - if( layers ) - msFreeCharArray(layers, numlayers); - msFree(mimetype); - return msWFSException(map, "outputformat", MS_OWS_ERROR_INVALID_PARAMETER_VALUE, paramsObj->pszVersion); - } - } - /* If no outputFormat explicitely asked, use a sensible default for the WFS version */ - else { - switch( nWFSVersion ) - { - case OWS_1_0_0: - default: - mimetype = msEncodeHTMLEntities("text/xml"); /* ERO: why not "text/xml; subtype=gml/2.1.2" ? */ - break; - - case OWS_1_1_0: - mimetype = msEncodeHTMLEntities("text/xml; subtype=gml/3.1.1"); - outputformat = OWS_SFE_SCHEMA; - break; - - case OWS_2_0_0: - mimetype = msEncodeHTMLEntities("application/gml+xml; version=3.2"); - outputformat = OWS_GML32_SFE_SCHEMA; - break; - } - } - - /* Validate layers */ - if (numlayers > 0) { - for (i=0; ipszTypeName); */ - if( layers ) - msFreeCharArray(layers, numlayers); - msFree(mimetype); - return msWFSException(map, "typename", MS_OWS_ERROR_INVALID_PARAMETER_VALUE, paramsObj->pszVersion); - } - } - } - - /* - ** retrieve any necessary external namespace/schema configuration information - */ - namespaceList = msGMLGetNamespaces(&(map->web), "G"); - if (namespaceList == NULL) { - msSetError(MS_MISCERR, "Unable to populate namespace list", "msWFSDescribeFeatureType()"); - return MS_FAILURE; - } - - /* - ** DescribeFeatureType response - */ - - msIO_setHeader("Content-Type","%s; charset=UTF-8",mimetype); - msIO_sendHeaders(); - - if (mimetype) - msFree(mimetype); - - msIO_printf("\n"); - - value = msOWSLookupMetadata(&(map->web.metadata), "FO", "namespace_uri"); - if(value) user_namespace_uri = value; - user_namespace_uri_encoded = msEncodeHTMLEntities(user_namespace_uri); - - value = msOWSLookupMetadata(&(map->web.metadata), "FO", "namespace_prefix"); - if(value) user_namespace_prefix = value; - if(user_namespace_prefix != NULL && msIsXMLTagValid(user_namespace_prefix) == MS_FALSE) - msIO_printf("\n", user_namespace_prefix); - - msIO_printf("\n"); - - encoded = msEncodeHTMLEntities( msOWSGetSchemasLocation(map) ); - - msIO_printf("\n \n", - msWFSGetGMLNamespaceURI(outputformat), - encoded, - msWFSGetGMLSchemaLocation(msWFSGetGMLVersionFromSchemaVersion(outputformat))); - - msFree(encoded); - - /* any additional namespace includes */ - for(i=0; inumnamespaces; i++) { - if(namespaceList->namespaces[i].uri && namespaceList->namespaces[i].schemalocation) { - char *schema_location_encoded=NULL, *uri_encoded=NULL; - - uri_encoded = msEncodeHTMLEntities(namespaceList->namespaces[i].uri); - schema_location_encoded = msEncodeHTMLEntities(namespaceList->namespaces[i].schemalocation); - msIO_printf("\n \n", uri_encoded, schema_location_encoded); - msFree(uri_encoded); - msFree(schema_location_encoded); - } - } - - /* output definition for the default feature container, can't use wfs:FeatureCollection with GML3: - kept here so that the behaviour with wfs1.0 and gml3 output is preserved. - We can use the wfs:FeatureCollection for wfs1.1*/ - if(outputformat == OWS_SFE_SCHEMA && nWFSVersion == OWS_1_0_0 ) { - value = msOWSLookupMetadata(&(map->web.metadata), "FO", "feature_collection"); - if(value) collection_name = value; - - msIO_printf(" \n", collection_name, user_namespace_prefix, collection_name); - msIO_printf(" \n", collection_name); - msIO_printf(" \n"); - msIO_printf(" \n"); - msIO_printf(" \n"); - msIO_printf(" \n"); - msIO_printf(" \n"); - msIO_printf(" \n"); - } - - /* - ** loop through layers - */ - for(i=0; inumlayers; i++) { - layerObj *lp; - int j, bFound = 0; - - lp = GET_LAYER(map, i); - - for (j=0; jname && strcasecmp(lp->name, layers[j]) == 0) - bFound = 1; - } - - if ((numlayers == 0 || bFound) && msWFSIsLayerAllowed(lp, ows_request) ) { - - /* - ** OK, describe this layer IF you can open it and retrieve items - */ - if (msLayerOpen(lp) == MS_SUCCESS) { - if (msLayerGetItems(lp) == MS_SUCCESS) { - int k; - gmlGroupListObj *groupList=NULL; - gmlItemListObj *itemList=NULL; - gmlConstantListObj *constantList=NULL; - gmlGeometryListObj *geometryList=NULL; - gmlItemObj *item=NULL; - gmlConstantObj *constant=NULL; - char *encoded_name = NULL; - - const char *layer_namespace_prefix; - const char *substitution_group; - char *encoded_type=NULL; - - itemList = msGMLGetItems(lp, "G"); /* GML-related metadata */ - constantList = msGMLGetConstants(lp, "G"); - groupList = msGMLGetGroups(lp, "G"); - geometryList = msGMLGetGeometries(lp, "GFO", MS_TRUE); - if (itemList == NULL || constantList == NULL || groupList == NULL || geometryList == NULL) { - msSetError(MS_MISCERR, "Unable to populate item and group metadata structures", "msWFSDescribeFeatureType()"); - return MS_FAILURE; - } - - value = msOWSLookupMetadata(&(lp->metadata), "OFG", "namespace_prefix"); - if(value) - layer_namespace_prefix = value; - else - layer_namespace_prefix = user_namespace_prefix; - - /* value = msOWSLookupMetadata(&(lp->metadata), "OFG", "layername"); */ - encoded_name = msEncodeHTMLEntities( lp->name ); - value = msOWSLookupMetadata(&(lp->metadata), "OFG", "layer_type"); - if(value) { - encoded_type = msEncodeHTMLEntities(value); - } else { - size_t sz = strlen(encoded_name) + strlen("Type") + 1; - encoded_type = (char*) msSmallMalloc(sz); - strlcpy(encoded_type, encoded_name, sz); - strlcat(encoded_type, "Type", sz); - } - - switch(outputformat) - { - case OWS_DEFAULT_SCHEMA: /* default GML 2.1.x schema */ - case OWS_SFE_SCHEMA: /* reference GML 3.1.1 schema */ - default: - substitution_group = "gml:_Feature"; - break; - - case OWS_GML32_SFE_SCHEMA: /* reference GML 3.2.1 schema */ - substitution_group = "gml:AbstractFeature"; - break; - } - - msIO_printf("\n" - " \n\n", - encoded_name, layer_namespace_prefix, encoded_type, - substitution_group); - msFree(encoded_type); - - if(strcmp(layer_namespace_prefix, user_namespace_prefix) != 0) { - msFree(encoded_name); - msGMLFreeItems(itemList); - msGMLFreeConstants(constantList); - msGMLFreeGroups(groupList); - msGMLFreeGeometries(geometryList); - continue; /* the rest is defined in an external schema */ - } - - msIO_printf(" \n", encoded_name); - msIO_printf(" \n"); - msIO_printf(" \n"); - msIO_printf(" \n"); - - /* write the geometry schema element(s) */ - msWFSSchemaWriteGeometryElement(stdout, geometryList, outputformat, " "); - - /* write the constant-based schema elements */ - for(k=0; knumconstants; k++) { - constant = &(constantList->constants[k]); - if(msItemInGroups(constant->name, groupList) == MS_FALSE) - msWFSWriteConstantElement(stdout, constant, " "); - } - - /* write the item-based schema elements */ - for(k=0; knumitems; k++) { - item = &(itemList->items[k]); - if(msItemInGroups(item->name, groupList) == MS_FALSE) { - int nillable = MS_FALSE; - char mdname[256]; - const char* pszNillable; - snprintf(mdname, sizeof(mdname), "%s_nillable", item->name); - pszNillable = msOWSLookupMetadata(&(lp->metadata), "G", mdname); - if( pszNillable && strcasecmp(pszNillable, "true") == 0 ) - nillable = MS_TRUE; - msWFSWriteItemElement(stdout, item, " ", outputformat, nillable); - } - } - - for(k=0; knumgroups; k++) - msWFSWriteGroupElement(stdout, &(groupList->groups[k]), " ", user_namespace_prefix); - - msIO_printf(" \n"); - msIO_printf(" \n"); - msIO_printf(" \n"); - msIO_printf(" \n"); - - /* any group types */ - for(k=0; knumgroups; k++) - msWFSWriteGroupElementType(stdout, &(groupList->groups[k]), itemList, constantList, " ", outputformat); - - msGMLFreeItems(itemList); - msGMLFreeConstants(constantList); - msGMLFreeGroups(groupList); - msGMLFreeGeometries(geometryList); - - msFree(encoded_name); - } - - msLayerClose(lp); - } else { - msIO_printf("\n\n\n\n", lp->name); - } - } - } - - /* - ** Done! - */ - msIO_printf("\n\n"); - - msFree(user_namespace_uri_encoded); - - if(layers) - msFreeCharArray(layers, numlayers); - - msGMLFreeNamespaces(namespaceList); - - return MS_SUCCESS; -} - -/* -** msWFSGetFeature_GMLPreamble() -** -** Generate the GML preamble up to the first feature for the builtin -** WFS GML support. -*/ - -typedef struct { - const char *user_namespace_prefix; - const char *user_namespace_uri; - char *user_namespace_uri_encoded; - const char *collection_name; - const char *_typename; - char *script_url, *script_url_encoded; - const char *output_mime_type; - const char *output_schema_format; -} WFSGMLInfo; - - -static void msWFSPrintURLAndXMLEncoded(const char* str) -{ - char* url_encoded = msEncodeUrl(str); - char* xml_encoded = msEncodeHTMLEntities(url_encoded); - msIO_printf("%s", xml_encoded); - msFree(xml_encoded); - msFree(url_encoded); -} - -static void msWFSGetFeature_PrintBasePrevNextURI(cgiRequestObj *req, - WFSGMLInfo *gmlinfo, - wfsParamsObj *paramsObj, - const char* encoded_version, - const char* encoded_typename, - const char* encoded_mime_type) -{ - int i; - int bFirstArg = MS_TRUE; - msIO_printf("%s", gmlinfo->script_url_encoded); - - if( req->postrequest != NULL ) - { - msIO_printf("SERVICE=WFS&VERSION="); - msIO_printf("%s", encoded_version); - msIO_printf("&REQUEST="); - msIO_printf("%s", paramsObj->pszRequest); - msIO_printf("&TYPENAMES="); - msIO_printf("%s", encoded_typename); - msIO_printf("&OUTPUTFORMAT="); - msIO_printf("%s", encoded_mime_type); - if( paramsObj->pszBbox != NULL ) - { - msIO_printf("&BBOX="); - msWFSPrintURLAndXMLEncoded(paramsObj->pszBbox); - } - if( paramsObj->pszSrs != NULL ) - { - msIO_printf("&SRSNAME="); - msWFSPrintURLAndXMLEncoded(paramsObj->pszSrs); - } - if( paramsObj->pszFilter != NULL ) - { - msIO_printf("&FILTER="); - msWFSPrintURLAndXMLEncoded(paramsObj->pszFilter); - } - if( paramsObj->pszPropertyName != NULL) - { - msIO_printf("&PROPERTYNAME="); - msWFSPrintURLAndXMLEncoded(paramsObj->pszPropertyName); - } - if( paramsObj->pszValueReference != NULL) - { - msIO_printf("&VALUEREFERENCE="); - msWFSPrintURLAndXMLEncoded(paramsObj->pszValueReference); - } - if( paramsObj->pszSortBy != NULL ) - { - msIO_printf("&SORTBY="); - msWFSPrintURLAndXMLEncoded(paramsObj->pszSortBy); - } - if( paramsObj->nMaxFeatures >= 0 ) - msIO_printf("&COUNT=%d", paramsObj->nMaxFeatures); - } - else - { - for(i=0; iNumParams; i++) { - if (req->ParamNames[i] && req->ParamValues[i] && - strcasecmp(req->ParamNames[i], "MAP") != 0 && - strcasecmp(req->ParamNames[i], "STARTINDEX") != 0 && - strcasecmp(req->ParamNames[i], "RESULTTYPE") != 0) { - if( !bFirstArg ) - msIO_printf("&"); - bFirstArg = MS_FALSE; - msIO_printf("%s=", req->ParamNames[i]); - msWFSPrintURLAndXMLEncoded(req->ParamValues[i]); - } - } - } -} - - -static void msWFSGetFeature_GetTimeStamp(char* timestring, size_t timestringlen) -{ - struct tm *now; - time_t tim=time(NULL); - - now=localtime(&tim); - - snprintf(timestring, timestringlen, "%d-%02d-%02dT%02d:%02d:%02d", - now->tm_year+1900, now->tm_mon+1, now->tm_mday, - now->tm_hour, now->tm_min, now->tm_sec); -} - -static int msWFSGetFeature_GMLPreamble( mapObj *map, - cgiRequestObj *req, - WFSGMLInfo *gmlinfo, - wfsParamsObj *paramsObj, - OWSGMLVersion outputformat, - int iResultTypeHits, - int iNumberOfFeatures, - int nMatchingFeatures, - int maxfeatures, - int bHasNextFeatures, - int nWFSVersion ) - -{ - const char *value; - char *encoded_version, *encoded_typename, *encoded_schema; - gmlNamespaceListObj *namespaceList=NULL; /* for external application schema support */ - char timestring[100]; - timestring[0] = '\0'; - - namespaceList = msGMLGetNamespaces(&(map->web), "G"); - if (namespaceList == NULL) { - msSetError(MS_MISCERR, "Unable to populate namespace list", "msWFSGetFeature_GMLPreamble()"); - return MS_FAILURE; - } - - /* - ** Establish script_url. - */ - - if ((gmlinfo->script_url=msOWSGetOnlineResource(map,"FO","onlineresource",req)) ==NULL || - (gmlinfo->script_url_encoded = msEncodeHTMLEntities(gmlinfo->script_url)) == NULL) { - msSetError(MS_WFSERR, "Server URL not found", "msWFSGetFeature()"); - msGMLFreeNamespaces(namespaceList); - return msWFSException(map, "mapserv", MS_OWS_ERROR_NO_APPLICABLE_CODE, paramsObj->pszVersion); - } - - /* - ** Write encoding. - */ - msIO_printf("\n"); - - value = msOWSLookupMetadata(&(map->web.metadata), "FO", "namespace_uri"); - if(value) gmlinfo->user_namespace_uri = value; - gmlinfo->user_namespace_uri_encoded = - msEncodeHTMLEntities(gmlinfo->user_namespace_uri); - - value = msOWSLookupMetadata(&(map->web.metadata), "FO", "namespace_prefix"); - if(value) gmlinfo->user_namespace_prefix = value; - - if(gmlinfo->user_namespace_prefix != NULL && msIsXMLTagValid(gmlinfo->user_namespace_prefix) == MS_FALSE) - msIO_printf("\n", gmlinfo->user_namespace_prefix); - - value = msOWSLookupMetadata(&(map->web.metadata), "FO", "feature_collection"); - if(value) gmlinfo->collection_name = value; - - encoded_version = msEncodeHTMLEntities( paramsObj->pszVersion ); - encoded_typename = msEncodeHTMLEntities( gmlinfo->_typename ); - encoded_schema = msEncodeHTMLEntities( msOWSGetSchemasLocation(map) ); - - if( nWFSVersion >= OWS_2_0_0) { - int nNextStartIndex; - char* tmp; - char* encoded_mime_type; - int bAbleToPrintPreviousOrNext = MS_TRUE; - - tmp = msEncodeUrl( gmlinfo->output_mime_type ); - encoded_mime_type = msEncodeHTMLEntities( tmp ); - msFree(tmp); - - msWFSGetFeature_GetTimeStamp(timestring, sizeof(timestring)); - - if( strcasecmp(paramsObj->pszRequest, "GetFeature") == 0 ) - msIO_printf("user_namespace_prefix, - gmlinfo->user_namespace_uri_encoded); - msWFS_NS_printf(MS_OWSCOMMON_GML_NAMESPACE_PREFIX, - msWFSGetGMLNamespaceURIFromGMLVersion(outputformat)); - msWFS_NS_printf(MS_OWSCOMMON_WFS_NAMESPACE_PREFIX, - MS_OWSCOMMON_WFS_20_NAMESPACE_URI); - msWFS_NS_printf(MS_OWSCOMMON_W3C_XSI_NAMESPACE_PREFIX, - MS_OWSCOMMON_W3C_XSI_NAMESPACE_URI); - msWFSPrintAdditionalNamespaces(namespaceList); - - msIO_printf(" xsi:schemaLocation=\"%s %sSERVICE=WFS&VERSION=%s&REQUEST=DescribeFeatureType&TYPENAME=%s&OUTPUTFORMAT=%s " - "%s %s%s " - "%s %s%s\"\n", - gmlinfo->user_namespace_uri_encoded, - gmlinfo->script_url_encoded, encoded_version, - encoded_typename, - gmlinfo->output_schema_format, - - MS_OWSCOMMON_WFS_20_NAMESPACE_URI, - encoded_schema, - MS_OWSCOMMON_WFS_20_SCHEMA_LOCATION, - - msWFSGetGMLNamespaceURIFromGMLVersion(outputformat), - encoded_schema, - msWFSGetGMLSchemaLocation(outputformat)); - - msIO_printf(" timeStamp=\"%s\" numberMatched=\"", timestring); - if( nMatchingFeatures < 0 ) - { - /* If we don't know the exact number, at least return something */ - /* equivalent to what we would return with WFS 1.1, otherwise */ - /* resultType=hits would not return anything usefull to the client. */ - if( iResultTypeHits == MS_TRUE ) - msIO_printf("%d", iNumberOfFeatures); - else - msIO_printf("unknown"); - } - else - msIO_printf("%d", nMatchingFeatures); - msIO_printf("\" numberReturned=\"%d\"", - (iResultTypeHits == 1) ? 0 : iNumberOfFeatures); - - /* TODO: in case of a multi-layer GetFeature POST, it is difficult to build a */ - /* valid GET KVP GetFeature/GetPropertyValue when some options are specified. So for now just */ - /* avoid those problematic cases */ - if( req->postrequest != NULL && (paramsObj->bHasPostStoredQuery || - (strchr(encoded_typename, ',') != NULL && - (paramsObj->pszFilter != NULL || paramsObj->pszPropertyName != NULL || - paramsObj->pszSortBy != NULL))) ) - { - bAbleToPrintPreviousOrNext = MS_FALSE; - } - - if( bAbleToPrintPreviousOrNext ) - { - if( maxfeatures > 0 && - iResultTypeHits != 1 && paramsObj->nStartIndex > 0 && - ((nMatchingFeatures < 0 && iNumberOfFeatures > 0) || - (nMatchingFeatures >= 0 && paramsObj->nStartIndex < nMatchingFeatures)) ) - { - int nPrevStartIndex; - - msIO_printf("\n"); - msIO_printf(" previous=\""); - msWFSGetFeature_PrintBasePrevNextURI(req,gmlinfo, paramsObj, - encoded_version, - encoded_typename, - encoded_mime_type); - - nPrevStartIndex = paramsObj->nStartIndex - maxfeatures; - if( nPrevStartIndex > 0 ) - msIO_printf("&STARTINDEX=%d", nPrevStartIndex); - msIO_printf("\""); - } - - if( iResultTypeHits != 1 && paramsObj->nStartIndex >= 0 ) - nNextStartIndex = paramsObj->nStartIndex; - else - nNextStartIndex = 0; - if( maxfeatures > 0 && (bHasNextFeatures || (nMatchingFeatures > 0 && - (iResultTypeHits == 1 || iNumberOfFeatures + nNextStartIndex < nMatchingFeatures))) ) - { - msIO_printf("\n"); - msIO_printf(" next=\""); - msWFSGetFeature_PrintBasePrevNextURI(req,gmlinfo, paramsObj, - encoded_version, - encoded_typename, - encoded_mime_type); - - if( iResultTypeHits != 1 ) - nNextStartIndex += iNumberOfFeatures; - - if( nNextStartIndex > 0 ) - msIO_printf("&STARTINDEX=%d", nNextStartIndex); - msIO_printf("\""); - } - } - - msIO_printf(">\n"); - - msFree(encoded_mime_type); - } - /* - ** GML 2.x - */ - else if(outputformat == OWS_GML2) { /* use a wfs:FeatureCollection */ - msIO_printf("user_namespace_prefix, - gmlinfo->user_namespace_uri_encoded); - msWFS_NS_printf(MS_OWSCOMMON_WFS_NAMESPACE_PREFIX, - MS_OWSCOMMON_WFS_NAMESPACE_URI); - msWFS_NS_printf(MS_OWSCOMMON_GML_NAMESPACE_PREFIX, - MS_OWSCOMMON_GML_NAMESPACE_URI); - msWFS_NS_printf(MS_OWSCOMMON_OGC_NAMESPACE_PREFIX, - MS_OWSCOMMON_OGC_NAMESPACE_URI); - msWFS_NS_printf(MS_OWSCOMMON_W3C_XSI_NAMESPACE_PREFIX, - MS_OWSCOMMON_W3C_XSI_NAMESPACE_URI); - msWFSPrintAdditionalNamespaces(namespaceList); - - /* FIXME ? : the schemaLocation will be only valid for WFS 1.0.0 */ - msIO_printf(" xsi:schemaLocation=\"http://www.opengis.net/wfs %s/wfs/%s/WFS-basic.xsd \n" - " %s %sSERVICE=WFS&VERSION=%s&REQUEST=DescribeFeatureType&TYPENAME=%s&OUTPUTFORMAT=%s\">\n", - encoded_schema, encoded_version, - gmlinfo->user_namespace_uri_encoded, - gmlinfo->script_url_encoded, encoded_version, - encoded_typename, gmlinfo->output_schema_format); - } - - /* - ** GML 3 - */ - else if( outputformat == OWS_GML3 ) { - if( nWFSVersion == OWS_1_1_0 ) { - msIO_printf("user_namespace_prefix, - gmlinfo->user_namespace_uri_encoded); - msWFS_NS_printf(MS_OWSCOMMON_GML_NAMESPACE_PREFIX, - MS_OWSCOMMON_GML_NAMESPACE_URI); - msWFS_NS_printf(MS_OWSCOMMON_WFS_NAMESPACE_PREFIX, - MS_OWSCOMMON_WFS_NAMESPACE_URI); - msWFS_NS_printf(MS_OWSCOMMON_OGC_NAMESPACE_PREFIX, - MS_OWSCOMMON_OGC_NAMESPACE_URI); - msWFS_NS_printf(MS_OWSCOMMON_W3C_XSI_NAMESPACE_PREFIX, - MS_OWSCOMMON_W3C_XSI_NAMESPACE_URI); - } else { - msIO_printf("<%s:%s\n" - " version=\"1.0.0\"\n", - gmlinfo->user_namespace_prefix, - gmlinfo->collection_name); - msWFS_NS_printf(gmlinfo->user_namespace_prefix, - gmlinfo->user_namespace_uri_encoded); - msWFS_NS_printf(MS_OWSCOMMON_GML_NAMESPACE_PREFIX, - MS_OWSCOMMON_GML_NAMESPACE_URI); - msWFS_NS_printf(MS_OWSCOMMON_OGC_NAMESPACE_PREFIX, - MS_OWSCOMMON_OGC_NAMESPACE_URI); - msWFS_NS_printf(MS_OWSCOMMON_W3C_XSI_NAMESPACE_PREFIX, - MS_OWSCOMMON_W3C_XSI_NAMESPACE_URI); - } - - msWFSPrintAdditionalNamespaces(namespaceList); - - msIO_printf(" xsi:schemaLocation=\"%s %sSERVICE=WFS&VERSION=%s&REQUEST=DescribeFeatureType&TYPENAME=%s&OUTPUTFORMAT=%s", - gmlinfo->user_namespace_uri_encoded, - gmlinfo->script_url_encoded, encoded_version, - encoded_typename, gmlinfo->output_schema_format); - - if( nWFSVersion == OWS_1_1_0 ) { - - msIO_printf(" %s %s%s", - MS_OWSCOMMON_WFS_NAMESPACE_URI, - encoded_schema, - MS_OWSCOMMON_WFS_11_SCHEMA_LOCATION); - - if (iResultTypeHits == 1) { - msWFSGetFeature_GetTimeStamp(timestring, sizeof(timestring)); - - msIO_printf("\" timeStamp=\"%s\" numberOfFeatures=\"%d", - timestring, iNumberOfFeatures); - } - } - msIO_printf("\">\n"); - } - - msFree(encoded_version); - msFree(encoded_schema); - msFree(encoded_typename); - - msGMLFreeNamespaces(namespaceList); - - return MS_SUCCESS; -} - -/* -** msWFSGetFeature_GMLPostfix() -** -** Generate the GML file tail closing the collection and cleanup a bit. -*/ - -static int msWFSGetFeature_GMLPostfix( mapObj *map, - cgiRequestObj *req, - WFSGMLInfo *gmlinfo, - wfsParamsObj *paramsObj, - OWSGMLVersion outputformat, - int maxfeatures, - int iResultTypeHits, - int iNumberOfFeatures, - int nWFSVersion ) - -{ - if (((iNumberOfFeatures==0) || (maxfeatures == 0)) && iResultTypeHits == 0) { - - if( nWFSVersion < OWS_2_0_0 ) - { - msIO_printf(" \n"); - if(outputformat == OWS_GML3 || outputformat == OWS_GML32 ) - msIO_printf(" missing\n"); - else - msIO_printf(" missing\n"); - msIO_printf(" \n"); - } - } - - if(outputformat == OWS_GML2) - msIO_printf("\n\n"); - else { - if( nWFSVersion >= OWS_1_1_0 ) - msIO_printf("\n\n"); - else - msIO_printf("\n\n", gmlinfo->user_namespace_prefix, gmlinfo->collection_name); - } - - return MS_SUCCESS; -} - -/* -** msWFSBuildParamList() -*/ -static void msWFSBuildParamList(char** ppszStrList, const char* pszValue, - const char* pszSep) -{ - if (*ppszStrList == NULL) - *ppszStrList = msStrdup(pszValue); - else - { - char* pszTmp = msStrdup(*ppszStrList); - *ppszStrList = - (char *)msSmallRealloc(*ppszStrList, - sizeof(char)* - (strlen(pszTmp)+ - strlen(pszSep)+ - strlen(pszValue)+1)); - - sprintf(*ppszStrList,"%s%s%s",pszTmp,pszSep,pszValue); - free(pszTmp); - } -} - -/* -** msWFSTurnOffAllLayer() -*/ -static void msWFSTurnOffAllLayer(mapObj* map) -{ - int j; - for(j=0; jnumlayers; j++) { - layerObj *lp; - lp = GET_LAYER(map, j); - lp->status = MS_OFF; - } -} - -/* -** msWFSRunFilter() -*/ -static int msWFSRunFilter(mapObj* map, - layerObj* lp, - const wfsParamsObj *paramsObj, - const char* pszFilter, - int nWFSVersion) -{ - int layerWasOpened; - FilterEncodingNode *psNode = NULL; - - psNode = FLTParseFilterEncoding(pszFilter); - - if (!psNode) { - msSetError(MS_WFSERR, - "Invalid or Unsupported FILTER in GetFeature : %s", - "msWFSGetFeature()", pszFilter); - return msWFSException(map, "filter", MS_OWS_ERROR_INVALID_PARAMETER_VALUE, paramsObj->pszVersion); - } - - /* Starting with WFS 1.1, we need to swap coordinates of BBOX or geometry */ - /* parameters in some circumstances */ - if( nWFSVersion >= OWS_1_1_0 ) - { - int bDefaultSRSNeedsAxisSwapping = MS_FALSE; - char* srs; - msOWSGetEPSGProj(&(map->projection),&(map->web.metadata),"FO",MS_TRUE,&srs); - if (!srs) - { - msOWSGetEPSGProj(&(lp->projection), &(lp->metadata), "FO", MS_TRUE, &srs); - } - if ( srs && strncasecmp(srs, "EPSG:", 5) == 0 ) - { - bDefaultSRSNeedsAxisSwapping = msIsAxisInverted(atoi(srs+5)); - } - msFree(srs); - FLTDoAxisSwappingIfNecessary(map, psNode, bDefaultSRSNeedsAxisSwapping); - } - - layerWasOpened = msLayerIsOpen(lp); - if( !layerWasOpened && msLayerOpen(lp) != MS_SUCCESS ) - { - FLTFreeFilterEncodingNode( psNode ); - return msWFSException(map, "mapserv", MS_OWS_ERROR_NO_APPLICABLE_CODE, paramsObj->pszVersion); - } - - FLTProcessPropertyIsNull(psNode, map, lp->index); - - /*preparse the filter for gml aliases*/ - FLTPreParseFilterForAliasAndGroup(psNode, map, lp->index, "G"); - - /* Check that FeatureId filters are consistent with the active layer */ - if( FLTCheckFeatureIdFilters(psNode, map, lp->index) == MS_FAILURE) - { - FLTFreeFilterEncodingNode( psNode ); - return msWFSException(map, "mapserv", MS_OWS_ERROR_NO_APPLICABLE_CODE, paramsObj->pszVersion); - } - - /* FIXME?: could probably apply to WFS 1.1 too */ - if( nWFSVersion >= OWS_2_0_0 ) - { - int nEvaluation; - - if( FLTCheckInvalidOperand(psNode) == MS_FAILURE) - { - FLTFreeFilterEncodingNode( psNode ); - return msWFSException(map, "filter", MS_WFS_ERROR_OPERATION_PROCESSING_FAILED, paramsObj->pszVersion); - } - - if( FLTCheckInvalidProperty(psNode, map, lp->index) == MS_FAILURE) - { - FLTFreeFilterEncodingNode( psNode ); - return msWFSException(map, "filter", MS_OWS_ERROR_INVALID_PARAMETER_VALUE, paramsObj->pszVersion); - } - - psNode = FLTSimplify(psNode, &nEvaluation); - if( psNode == NULL ) - { - FLTFreeFilterEncodingNode( psNode ); - if( nEvaluation == 1 ) { - /* return full layer */ - return msWFSRunBasicGetFeature(map, lp, paramsObj, nWFSVersion); - } - else { - /* return empty result set */ - return MS_SUCCESS; - } - } - - } - - /* run filter. If no results are found, do not throw exception */ - /* this is a null result */ - if( FLTApplyFilterToLayer(psNode, map, lp->index) != MS_SUCCESS ) { - errorObj* ms_error = msGetErrorObj(); - - if(ms_error->code != MS_NOTFOUND) { - msSetError(MS_WFSERR, "FLTApplyFilterToLayer() failed", "msWFSGetFeature()"); - FLTFreeFilterEncodingNode( psNode ); - return msWFSException(map, "mapserv", ( nWFSVersion >= OWS_2_0_0 ) ? MS_WFS_ERROR_OPERATION_PROCESSING_FAILED : MS_OWS_ERROR_NO_APPLICABLE_CODE, paramsObj->pszVersion); - } - } - - FLTFreeFilterEncodingNode( psNode ); - - return MS_SUCCESS; -} - -/* -** msWFSRunBasicGetFeature() -*/ -static int msWFSRunBasicGetFeature(mapObj* map, - layerObj* lp, - const wfsParamsObj *paramsObj, - int nWFSVersion) -{ - rectObj ext; - int status; - - map->query.type = MS_QUERY_BY_RECT; /* setup the query */ - map->query.mode = MS_QUERY_MULTIPLE; - map->query.rect = map->extent; - map->query.layer = lp->index; - - if( FLTLayerSetInvalidRectIfSupported(lp, &(map->query.rect)) ) - { - /* do nothing */ - } - else if (msOWSGetLayerExtent(map, lp, "FO", &ext) == MS_SUCCESS) { - char *pszMapSRS=NULL; - - /*if srsName was given for wfs 1.1.0, It is at this point loaded into the - map object and should be used*/ - if(!paramsObj->pszSrs) - msOWSGetEPSGProj(&(map->projection), &(map->web.metadata), "FO", MS_TRUE, &pszMapSRS); - - /* For a single point layer, to avoid numerical precision issues */ - /* when reprojection is involved */ - ext.minx -= 1e-5; - ext.miny -= 1e-5; - ext.maxx += 1e-5; - ext.maxy += 1e-5; - - if (pszMapSRS != NULL && strncmp(pszMapSRS, "EPSG:", 5) == 0) { - - if( nWFSVersion >= OWS_1_1_0 ) - status = msLoadProjectionStringEPSG(&(map->projection), pszMapSRS); - else - status = msLoadProjectionString(&(map->projection), pszMapSRS); - - if (status != 0) { - msSetError(MS_WFSERR, "msLoadProjectionString() failed: %s", - "msWFSGetFeature()", pszMapSRS); - msFree(pszMapSRS); - return msWFSException(map, "mapserv", MS_OWS_ERROR_NO_APPLICABLE_CODE, - paramsObj->pszVersion); - } - msFree(pszMapSRS); - - } - - /*make sure that the layer projection is loaded. - It could come from a ows/wfs_srs metadata*/ - if (lp->projection.numargs == 0) { - char *pszLayerSRS; - msOWSGetEPSGProj(&(lp->projection), &(lp->metadata), "FO", MS_TRUE, &pszLayerSRS); - if (pszLayerSRS) { - if (strncmp(pszLayerSRS, "EPSG:", 5) == 0) { - if( nWFSVersion >= OWS_1_1_0 ) - msLoadProjectionStringEPSG(&(lp->projection), pszLayerSRS); - else - msLoadProjectionString(&(lp->projection), pszLayerSRS); - } - } - msFree(pszLayerSRS); - } - - if (msProjectionsDiffer(&map->projection, &lp->projection) == MS_TRUE) { - msProjectRect(&lp->projection, &map->projection, &(ext)); - } - map->query.rect = ext; - } - - if(msQueryByRect(map) != MS_SUCCESS) { - errorObj *ms_error; - ms_error = msGetErrorObj(); - - if(ms_error->code != MS_NOTFOUND) { - msSetError(MS_WFSERR, "ms_error->code not found", "msWFSGetFeature()"); - return msWFSException(map, "mapserv", MS_OWS_ERROR_NO_APPLICABLE_CODE, paramsObj->pszVersion); - } - } - - return MS_SUCCESS; -} - - -/* -** msWFSRetrieveFeatures() -*/ -static int msWFSRetrieveFeatures(mapObj* map, - owsRequestObj* ows_request, - const wfsParamsObj *paramsObj, - const WFSGMLInfo* gmlinfo, - const char* pszFilter, - int bBBOXSet, - const char* pszBBOXSRS, - rectObj bbox, - const char* pszFeatureId, - char **layers, - int numlayers, - int maxfeatures, - int nWFSVersion, - int* pnOutTotalFeatures, - int* pnHasNext) -{ - int i, j; - int iNumberOfFeatures = 0; - - if (pszFilter && strlen(pszFilter) > 0) { - int nFilters; - char **paszFilter = NULL; - - /* -------------------------------------------------------------------- */ - /* Validate the parameters. When a FILTER parameter is given, */ - /* It needs the TYPENAME parameter for the layers. Also Filter */ - /* is Mutually exclusive with FEATUREID and BBOX (see wfs specs */ - /* 1.0 section 13.7.3 on GetFeature) */ - /* */ - /* -------------------------------------------------------------------- */ - - /* WFS 2.0 */ - if (nWFSVersion >= OWS_2_0_0 && - paramsObj->pszFilterLanguage != NULL && - strcasecmp(paramsObj->pszFilterLanguage, "urn:ogc:def:query Language:OGC-FES:Filter") != 0) { - msSetError(MS_WFSERR, - "Unhandled value for FILTER_LANGUAGE parameter. Only \"urn:ogc:def:query Language:OGC-FES:Filter\" accepted.", - "msWFSGetFeature()"); - return msWFSException(map, "filter_language", MS_OWS_ERROR_INVALID_PARAMETER_VALUE, paramsObj->pszVersion); - } - - if (gmlinfo->_typename == NULL || strlen(gmlinfo->_typename) <= 0 || layers == NULL || numlayers <= 0) { - msSetError(MS_WFSERR, - "Required %s parameter missing for GetFeature with a FILTER parameter.", - "msWFSGetFeature()", - (nWFSVersion >= OWS_2_0_0 ) ? "TYPENAMES": "TYPENAME" ); - return msWFSException(map, (nWFSVersion >= OWS_2_0_0 ) ? "typenames": "typename", - MS_OWS_ERROR_MISSING_PARAMETER_VALUE, paramsObj->pszVersion); - } - - if (bBBOXSet) { - msSetError(MS_WFSERR, - "BBOX parameter and FILTER parameter are mutually exclusive in GetFeature.", - "msWFSGetFeature()"); - return msWFSException(map, "mapserv", MS_OWS_ERROR_NO_APPLICABLE_CODE, paramsObj->pszVersion); - } - - if (pszFeatureId != NULL) { - msSetError(MS_WFSERR, - "%s parameter and FILTER parameter are mutually exclusive in GetFeature.", - "msWFSGetFeature()", - (nWFSVersion < OWS_2_0_0 ) ? "FEATUREID" : "RESOURCEID" ); - return msWFSException(map, "mapserv", MS_OWS_ERROR_NO_APPLICABLE_CODE, paramsObj->pszVersion); - } - - if (msWFSGetFeatureApplySRS(map, paramsObj->pszSrs, nWFSVersion) == MS_FAILURE) - return msWFSException(map, "srsname", MS_OWS_ERROR_INVALID_PARAMETER_VALUE, paramsObj->pszVersion); - - /* -------------------------------------------------------------------- */ - /* Parse the Filter parameter. If there are several Filter */ - /* parameters, each Filter is inside a parantheses. Eg : */ - /* FILTER=( */ - /* INWATERA_1M/WKB_GEOM|INWATERA_1M/WKB_GEOM */ - /* 10,10 20,20*/ - /* )( */ - /* INWATERA_1M/WKB_GEOM10,10*/ - /* 20,20) */ - /* -------------------------------------------------------------------- */ - nFilters = 0; - if (strlen(pszFilter) > 0 && pszFilter[0] == '(') { - paszFilter = FLTSplitFilters(pszFilter, &nFilters); - - if ( paszFilter && nFilters > 0 && numlayers != nFilters ) { - msFreeCharArray(paszFilter, nFilters); - } - } else if (numlayers == 1) { - nFilters=1; - paszFilter = (char **)msSmallMalloc(sizeof(char *)*nFilters); - paszFilter[0] = msStrdup(pszFilter); - } - - if (numlayers != nFilters) { - msSetError(MS_WFSERR, "Wrong number of filter elements, one filter must be specified for each feature type listed in the %s parameter.", - "msWFSGetFeature()", - (nWFSVersion >= OWS_2_0_0 ) ? "TYPENAMES": "TYPENAME" ); - return msWFSException(map, "filter", MS_OWS_ERROR_INVALID_PARAMETER_VALUE, paramsObj->pszVersion); - } - - /* -------------------------------------------------------------------- */ - /* run through the filters and build the class expressions. */ - /* -------------------------------------------------------------------- */ - for (i=0; iquery.maxfeatures >= 0 ) - { - if( lp->resultcache && lp->resultcache->numresults > 0 ) - { - map->query.maxfeatures -= lp->resultcache->numresults; - if( map->query.maxfeatures <= 0 ) - break; - } - } - } - - msFreeCharArray(paszFilter, nFilters); - }/* end if filter set */ - - - if (pszFeatureId != NULL) { - char **tokens = NULL; - int nTokens = 0, j=0, k=0; - FilterEncodingNode *psNode = NULL; - char **aFIDLayers = NULL; - char **aFIDValues = NULL; - int iFIDLayers = 0; - - /* Keep only selected layers, set to OFF by default. */ - msWFSTurnOffAllLayer(map); - - /*featureid can be a list INWATERA_1M.1234, INWATERA_1M.1235 - We will keep all the feature id from the same layer together - so that an OR would be applied if several of them are present - */ - tokens = msStringSplit(pszFeatureId, ',', &nTokens); - iFIDLayers = 0; - if (tokens && nTokens >=1) { - aFIDLayers = (char **)msSmallMalloc(sizeof(char *)*nTokens); - aFIDValues = (char **)msSmallMalloc(sizeof(char *)*nTokens); - for (j=0; jpszVersion); - } - } - } - } - if (tokens) - msFreeCharArray(tokens, nTokens); - - /*turn on the layers and make sure projections are set properly*/ - for (j=0; j< iFIDLayers; j++) { - layerObj *lp; - lp = msWFSGetLayerByName(map, ows_request, aFIDLayers[j]); - if( lp == NULL ) { - msSetError(MS_WFSERR, - "Invalid typename given with FeatureId in GetFeature : %s. A layer might be disabled for \ -this request. Check wfs/ows_enable_request settings.", "msWFSGetFeature()", - aFIDLayers[j]); - - msFreeCharArray(aFIDLayers, iFIDLayers); - msFreeCharArray(aFIDValues, iFIDLayers); - return msWFSException(map, "featureid", MS_OWS_ERROR_INVALID_PARAMETER_VALUE, paramsObj->pszVersion); - } - - lp->status = MS_ON; - } - - if( map->query.only_cache_result_count == MS_FALSE ) - msWFSAnalyzeStartIndexAndFeatureCount(map, paramsObj, FALSE, NULL, NULL); - - if (msWFSGetFeatureApplySRS(map, paramsObj->pszSrs, nWFSVersion) == MS_FAILURE) - return msWFSException(map, "srsname", MS_OWS_ERROR_INVALID_PARAMETER_VALUE, paramsObj->pszVersion); - - for (j=0; j< iFIDLayers; j++) { - layerObj *lp; - lp = msWFSGetLayerByName(map, ows_request, aFIDLayers[j]); - if (lp->_template == NULL) { - /* Force setting a template to enable query. */ - lp->_template = msStrdup("ttt.html"); - } - psNode = FLTCreateFeatureIdFilterEncoding(aFIDValues[j]); - - if( FLTApplyFilterToLayer(psNode, map, lp->index) != MS_SUCCESS ) { - msSetError(MS_WFSERR, "FLTApplyFilterToLayer() failed", "msWFSGetFeature"); - FLTFreeFilterEncodingNode( psNode ); - msFreeCharArray(aFIDLayers, iFIDLayers); - msFreeCharArray(aFIDValues, iFIDLayers); - return msWFSException(map, "mapserv", MS_OWS_ERROR_NO_APPLICABLE_CODE, paramsObj->pszVersion); - } - - FLTFreeFilterEncodingNode( psNode ); - psNode = NULL; - - /* Decrement the total maxfeatures */ - if( map->query.maxfeatures >= 0 ) - { - if( lp->resultcache && lp->resultcache->numresults > 0 ) - { - map->query.maxfeatures -= lp->resultcache->numresults; - if( map->query.maxfeatures <= 0 ) - break; - } - } - } - - msFreeCharArray(aFIDLayers, iFIDLayers); - msFreeCharArray(aFIDValues, iFIDLayers); - } - - /* - ** Perform Query (only BBOX for now) - */ - /* __TODO__ Using a rectangle query may not be the most efficient way */ - /* to do things here. */ - if (pszFilter == NULL && pszFeatureId == NULL) { - - /* Apply the requested SRS */ - if (msWFSGetFeatureApplySRS(map, paramsObj->pszSrs, nWFSVersion) == MS_FAILURE) - return msWFSException(map, "srsname", MS_OWS_ERROR_INVALID_PARAMETER_VALUE, paramsObj->pszVersion); - - if (!bBBOXSet) { - for(j=0; jnumlayers; j++) { - layerObj *lp; - lp = GET_LAYER(map, j); - if (lp->status == MS_ON) { - int status = msWFSRunBasicGetFeature(map, lp, paramsObj, nWFSVersion); - if( status != MS_SUCCESS ) - return status; - } - } - } else { - - char* sBBoxSrs = NULL; - - if( pszBBOXSRS != NULL ) - sBBoxSrs = msStrdup(pszBBOXSRS); - - /* On WFS 2.0.0, if the BBOX has no explicit SRS, use the map SRS */ - /* Should likely be used for WFS 1.1.0 too, but don't want to cause */ - /* issue at that point, since it can influence axis ordering */ - if( nWFSVersion >= OWS_2_0_0 && sBBoxSrs == NULL ) - { - projectionObj sProjTmp; - - msInitProjection(&sProjTmp); - msProjectionInheritContextFrom(&sProjTmp, &(map->projection)); - msOWSGetEPSGProj(&sProjTmp,&(map->web.metadata),"FO",MS_TRUE, &sBBoxSrs); - msFreeProjection(&sProjTmp); - } - - if (sBBoxSrs) { - int status; - projectionObj sProjTmp; - - msInitProjection(&sProjTmp); - msProjectionInheritContextFrom(&sProjTmp, &(map->projection)); - /*do the axis order for now. It is unclear if the bbox are expected - ro respect the axis oder defined in the projectsion #3296*/ - - if(nWFSVersion >= OWS_1_1_0) { - if ((status=msLoadProjectionStringEPSG(&sProjTmp, sBBoxSrs)) == 0) { - msAxisNormalizePoints( &sProjTmp, 1, &bbox.minx, &bbox.miny ); - msAxisNormalizePoints( &sProjTmp, 1, &bbox.maxx, &bbox.maxy ); - } - } else - status = msLoadProjectionString(&sProjTmp, sBBoxSrs); - - if (status == 0 && map->projection.numargs > 0) - msProjectRect(&sProjTmp, &map->projection, &bbox); - msFreeProjection(&sProjTmp); - - msFree(sBBoxSrs); - sBBoxSrs = NULL; - } - map->query.type = MS_QUERY_BY_RECT; /* setup the query */ - map->query.mode = MS_QUERY_MULTIPLE; - map->query.rect = bbox; - - /* - Retaining this block of code in case we want to setup a rendering path through - the query code at some point. - */ - /* if(map->outputformat && MS_DRIVER_MVT(map->outputformat)) { - const char *mvt_buffer = msGetOutputFormatOption(map->outputformat, "EDGE_BUFFER", "10"); - int buffer = MS_ABS(atoi(mvt_buffer)); - double res = (bbox.maxx - bbox.minx)/(double)map->width; - bbox.minx -= buffer * res; - bbox.maxx += buffer * res; - res = (bbox.maxy - bbox.miny)/(double)map->height; - bbox.miny -= buffer * res; - bbox.maxy += buffer * res; - map->width += buffer*2; - map->height += buffer*2; - msCalculateScale(bbox,map->units,map->width,map->height, map->resolution, &map->scaledenom); - map->query.rect = bbox; - } */ - - if(msQueryByRect(map) != MS_SUCCESS) { - errorObj *ms_error; - ms_error = msGetErrorObj(); - - if(ms_error->code != MS_NOTFOUND) { - msSetError(MS_WFSERR, "ms_error->code not found", "msWFSGetFeature()"); - return msWFSException(map, "mapserv", MS_OWS_ERROR_NO_APPLICABLE_CODE, paramsObj->pszVersion); - } - } - } - } - - /* Count total number of features retrieved */ - for(j=0; jnumlayers; j++) { - if (GET_LAYER(map, j)->resultcache && GET_LAYER(map, j)->resultcache->numresults > 0) { - iNumberOfFeatures += GET_LAYER(map, j)->resultcache->numresults; - } - } - - /* If maxfeatures is set, we have actually asked for 1 more feature than asked */ - /* to be able to know if there are next features. So it is now time to */ - /* remove this extra unasked feature from the result cache */ - if( maxfeatures >= 0 && iNumberOfFeatures == maxfeatures + 1 ) - { - int lastJ = -1; - for(j=0; jnumlayers; j++) { - if (GET_LAYER(map, j)->resultcache && GET_LAYER(map, j)->resultcache->numresults > 0) { - lastJ = j; - } - } - GET_LAYER(map, lastJ)->resultcache->numresults --; - GET_LAYER(map, lastJ)->resultcache->bounds = GET_LAYER(map, lastJ)->resultcache->previousBounds; - iNumberOfFeatures --; - if( pnHasNext ) - *pnHasNext = MS_TRUE; - } - else if( pnHasNext ) - *pnHasNext = MS_FALSE; - - *pnOutTotalFeatures = iNumberOfFeatures; - - return MS_SUCCESS; -} - -/* -** msWFSParsePropertyNameOrSortBy() -*/ -static char** msWFSParsePropertyNameOrSortBy(const char* pszPropertyName, - int numlayers) -{ - char** tokens = NULL; - int nPropertyNames = 0; - char** papszPropertyName = NULL; - int i; - - if( pszPropertyName == NULL ) - { - papszPropertyName = (char **)msSmallMalloc(sizeof(char *)*numlayers); - for (i=0; i 0) { - papszPropertyName[i] = msStrdup(tokens[i]); - /* remove trailing ) */ - papszPropertyName[i][strlen(papszPropertyName[i])-1] = '\0'; - } - else { - for ( i--; i>=0; i-- ) - msFree(papszPropertyName[i]); - msFree(papszPropertyName); - msFreeCharArray(tokens, nPropertyNames); - return NULL; - } - } - - msFreeCharArray(tokens, nPropertyNames); - - return papszPropertyName; -} - -static void msWFSInitGMLInfo(WFSGMLInfo* pgmlinfo) -{ - memset( pgmlinfo, 0, sizeof(WFSGMLInfo) ); - pgmlinfo->user_namespace_prefix = MS_DEFAULT_NAMESPACE_PREFIX; - pgmlinfo->user_namespace_uri = MS_DEFAULT_NAMESPACE_URI; - pgmlinfo->collection_name = OWS_WFS_FEATURE_COLLECTION_NAME; - pgmlinfo->_typename = ""; - pgmlinfo->output_mime_type = "text/xml"; - pgmlinfo->output_schema_format = "XMLSCHEMA"; -} - -static void msWFSCleanupGMLInfo(WFSGMLInfo* pgmlinfo) -{ - free(pgmlinfo->script_url); - free(pgmlinfo->script_url_encoded); - msFree(pgmlinfo->user_namespace_uri_encoded); -} - -static int msWFSGetGMLOutputFormat(mapObj *map, wfsParamsObj *paramsObj, - WFSGMLInfo* pgmlinfo, - int nWFSVersion) -{ - OWSGMLVersion outputformat = OWS_GML2; - - /* Validate outputformat */ - if (paramsObj->pszOutputFormat) { - /* We support GML2, GML3, GML3.2 for now. */ - if(strcasecmp(paramsObj->pszOutputFormat, "GML2") == 0 || - strcasecmp(paramsObj->pszOutputFormat, "text/xml; subtype=gml/2.1.2") == 0) { - outputformat = OWS_GML2; - pgmlinfo->output_schema_format = "XMLSCHEMA"; - /* FIXME? : subtype=gml/XXXX is invalid without quoting. Seen with CITE WFS 2.0 */ - pgmlinfo->output_mime_type = "text/xml; subtype=gml/2.1.2"; - } else if(strcasecmp(paramsObj->pszOutputFormat, "GML3") == 0 || - strcasecmp(paramsObj->pszOutputFormat, "text/xml; subtype=gml/3.1.1") == 0) { - outputformat = OWS_GML3; - pgmlinfo->output_schema_format = "SFE_XMLSCHEMA"; - /* FIXME? : subtype=gml/XXXX is invalid without quoting. Seen with CITE WFS 2.0 */ - pgmlinfo->output_mime_type = "text/xml; subtype=gml/3.1.1"; - } else if(strcasecmp(paramsObj->pszOutputFormat, "GML32") == 0 || - strcasecmp(paramsObj->pszOutputFormat, "text/xml; subtype=gml/3.2.1") == 0 || - strcasecmp(paramsObj->pszOutputFormat, "text/xml; subtype=\"gml/3.2.1\"") == 0 || - strcasecmp(paramsObj->pszOutputFormat, "application/gml+xml; version=3.2") == 0) { - outputformat = OWS_GML32; - pgmlinfo->output_schema_format = "application%2Fgml%2Bxml%3B%20version%3D3.2"; - pgmlinfo->output_mime_type = "text/xml; subtype=\"gml/3.2.1\""; - } else { - return -1; - } - - /* If OUTPUTFORMAT not set, default to gml */ - } else { - /*set the output format using the version if available*/ - if( nWFSVersion == OWS_1_1_0 ) { - outputformat = OWS_GML3; - pgmlinfo->output_schema_format = "text/xml;%20subtype=gml/3.1.1"; - /* FIXME? : subtype=gml/XXXX is invalid without quoting. Seen with CITE WFS 2.0 */ - pgmlinfo->output_mime_type = "text/xml; subtype=gml/3.1.1"; - } - else if( nWFSVersion >= OWS_2_0_0 ) { - outputformat = OWS_GML32; - pgmlinfo->output_schema_format = "application%2Fgml%2Bxml%3B%20version%3D3.2"; - pgmlinfo->output_mime_type = "text/xml; subtype=\"gml/3.2.1\""; - } - } - - if( nWFSVersion == OWS_1_0_0 ) { - pgmlinfo->output_mime_type = "text/xml"; - } - - return outputformat; -} - -static outputFormatObj* msWFSGetOtherOutputFormat(mapObj *map, wfsParamsObj *paramsObj) -{ - const char *format_list; - hashTableObj *md; - outputFormatObj* psFormat = NULL; - int j; - - /* validate selected format against all selected layers. */ - for(j=0; j < map->numlayers; j++) { - layerObj *lp; - - lp = GET_LAYER(map, j); - - if( lp->status != MS_ON ) - continue; - - md = &(lp->metadata); - format_list = msOWSLookupMetadata(md, "F","getfeature_formatlist"); - if( format_list == NULL ) { - md = &(map->web.metadata); - format_list = msOWSLookupMetadata(md, "F","getfeature_formatlist"); - } - if (format_list) { - psFormat = msOwsIsOutputFormatValid( - map, paramsObj->pszOutputFormat, md, - "F", "getfeature_formatlist"); - } - if (psFormat == NULL) { - msSetError(MS_WFSERR, - "'%s' is not a permitted output format for layer '%s', review wfs_getfeature_formatlist setting.", - "msWFSGetFeature()", - paramsObj->pszOutputFormat, - lp->name ); - return NULL; - } - - if( psFormat->imagemode != MS_IMAGEMODE_FEATURE ) { - msSetError(MS_WFSERR, - "OUTPUTFORMAT '%s' does not have IMAGEMODE FEATURE, and is not permitted for WFS output.", - "msWFSGetFeature()", - paramsObj->pszOutputFormat ); - return NULL; - } - } - - return psFormat; -} - -static void msWFSAnalyzeStartIndexAndFeatureCount(mapObj *map, const wfsParamsObj *paramsObj, - int bIsHits, - int *pmaxfeatures, int* pstartindex) -{ - const char *tmpmaxfeatures = NULL; - int maxfeatures=-1,startindex=-1; - int j; - - int nQueriedLayers=0; - layerObj *lpQueried=NULL; - - tmpmaxfeatures = msOWSLookupMetadata(&(map->web.metadata), "FO", "maxfeatures"); - if (tmpmaxfeatures) - maxfeatures = atoi(tmpmaxfeatures); - - if( bIsHits ) - { - const char* ignoreMaxFeaturesForHits = - msOWSLookupMetadata(&(map->web.metadata), "FO", "maxfeatures_ignore_for_resulttype_hits"); - - /* For PostGIS where we have an efficient implementation of hits, default to true */ - if( ignoreMaxFeaturesForHits == NULL ) - { - int bHasEfficientHits = MS_TRUE; - for(j=0; jnumlayers; j++) { - layerObj *lp; - lp = GET_LAYER(map, j); - if (lp->status == MS_ON) { - if( lp->connectiontype != MS_POSTGIS ) - { - bHasEfficientHits = MS_FALSE; - break; - } - } - } - - if (bHasEfficientHits ) - ignoreMaxFeaturesForHits = "true"; - } - - if( ignoreMaxFeaturesForHits != NULL && strcasecmp(ignoreMaxFeaturesForHits, "true") == 0 ) - maxfeatures = -1; - } - - if (paramsObj->nMaxFeatures >= 0) { - if (maxfeatures < 0 || (maxfeatures > 0 && paramsObj->nMaxFeatures < maxfeatures)) - maxfeatures = paramsObj->nMaxFeatures; - } - - nQueriedLayers=0; - for(j=0; jnumlayers; j++) { - layerObj *lp; - lp = GET_LAYER(map, j); - if (lp->status == MS_ON) { - /* No reason to handle tolerances for WFS GetFeature */ - lp->tolerance = 0; - lpQueried = GET_LAYER(map, j); - nQueriedLayers++; - } - } - - /* WFS convention is that STARTINDEX=0 means the first feature, whereas */ - /* in MapServer internals we used another interpretation with STARTINDEX=1 */ - /* being the first index. This was before that the SWG WFS clarified things */ - /* hence the mess. Ultimately we should likely fix our internals to avoid */ - /* possible confusion */ - if (paramsObj->nStartIndex >= 0) { - startindex = 1 + paramsObj->nStartIndex; - map->query.startindex = startindex; - } - - - /* maxfeatures set */ - if (maxfeatures >= 0) { - int extrafeature = 1; - for(j=0; jnumlayers; j++) { - layerObj *lp; - lp = GET_LAYER(map, j); - if (lp->status == MS_ON) { - /*over-ride the value only if it is unset or wfs maxfeatures is - lower that what is currently set*/ - if (lp->maxfeatures <=0 || (lp->maxfeatures > 0 && maxfeatures < lp->maxfeatures)) - { - /* TODO: We don't handle DESC sorting, as it would mean to be */ - /* able to evict the first property, which mapquery cannot handle */ - /* This would have impact on the resultcache.bounds */ - if( lp->sortBy.nProperties > 0 ) - { - int k; - int countDesc = 1; - for(k=0;ksortBy.nProperties;k++) - { - if( lp->sortBy.properties[k].sortOrder == SORT_DESC ) - countDesc ++; - } - if( countDesc > 0 ) - extrafeature = 0; - } - - /* + 1 to be able to detect if there are more features for a next request */ - lp->maxfeatures = maxfeatures + extrafeature; - } - } - } - /* + 1 to be able to detect if there are more features for a next request */ - map->query.maxfeatures = maxfeatures + extrafeature; - } - - /* startindex set */ - if (startindex > 0 && nQueriedLayers > 1) { - for(j=0; jnumlayers; j++) { - layerObj *lp; - lp = GET_LAYER(map, j); - if (lp->status == MS_ON) { - msLayerEnablePaging(lp, MS_FALSE); - } - } - } else if (startindex > 0 && lpQueried) { - lpQueried->startindex = startindex; - } - - if( pmaxfeatures ) - *pmaxfeatures = maxfeatures; - if( pstartindex ) - *pstartindex = startindex; -} - -static int msWFSAnalyzeBBOX(mapObj *map, wfsParamsObj *paramsObj, - rectObj* pbbox, char** pszBBoxSRS) -{ - /* Default filter is map extents */ - *pbbox = map->extent; - - if (paramsObj->pszBbox) { - char **tokens; - int n; - - tokens = msStringSplit(paramsObj->pszBbox, ',', &n); - if (tokens==NULL || (n != 4 && n !=5)) { - msSetError(MS_WFSERR, "Wrong number of arguments for BBOX.", "msWFSGetFeature()"); - msFreeCharArray(tokens, n); - return msWFSException(map, "bbox", MS_OWS_ERROR_INVALID_PARAMETER_VALUE, paramsObj->pszVersion); - } - pbbox->minx = atof(tokens[0]); - pbbox->miny = atof(tokens[1]); - pbbox->maxx = atof(tokens[2]); - pbbox->maxy = atof(tokens[3]); - /*5th aregument is assumed to be projection*/ - if (n == 5) - *pszBBoxSRS = msStrdup(tokens[4]); - - msFreeCharArray(tokens, n); - } - return 0; -} - -static int msWFSComputeMatchingFeatures(mapObj *map, - owsRequestObj *ows_request, - wfsParamsObj *paramsObj, - int iNumberOfFeatures, - int maxfeatures, - WFSGMLInfo* pgmlinfo, - rectObj bbox, - const char* sBBoxSrs, - char** layers, - int numlayers, - int nWFSVersion) -{ - int nMatchingFeatures = -1; - - if( nWFSVersion >= OWS_2_0_0 ) - { - /* If no features have been retrived and there was no feature count limit, then */ - /* it is obvious. We must test maxfeatures because if startindex is defined, */ - /* and above the number of matched features, iNumberOfFeatures can be 0. */ - if( iNumberOfFeatures == 0 && maxfeatures < 0 ) - { - nMatchingFeatures = 0; - } - - /* In the case we had limited the query by a maximum number of features, and */ - /* that the query has returned less features than the limit, or if there was */ - /* no limit in fature count, we are able to determine the number of matching */ - /* features */ - else if( iNumberOfFeatures > 0 && (maxfeatures < 0 || iNumberOfFeatures < maxfeatures) ) - { - if( paramsObj->nStartIndex >= 0 ) - nMatchingFeatures = iNumberOfFeatures + paramsObj->nStartIndex; - else - nMatchingFeatures = iNumberOfFeatures; - } - - /* Otherwise big hammer ! */ - else - { - /* The WFS 2.0 spec is not really clear on numberMatched behaviour */ - /* and there are interesting logic in server implementations. */ - /* */ - /* Deegree (http://deegree3-demo.deegree.org:80/inspire-workspace/services/wfs?) */ - /* will return numberMatched="19005" on the cp:CadastralParcel layer for a */ - /* resultType=hits request, whereas the server limitation is set to 15000 */ - /* But on a regular GetFeature (without count specified), it will return */ - /* numberMatched="15000" (and numberReturned="15000")) */ - /* */ - /* GeoServer 2.4.1 will also ignore its server limitation for a resultType=hits */ - /* but when using a regular GetFeature (without count specified), il will return */ - /* numberMatched=numberReturned=total_number_of_features_without_taking_into_account_server_limit */ - /* but the number of actually returned features will be truncated to the server */ - /* limit, likely a bug */ - /* */ - /* If wfs_compute_number_matched is set to TRUE, we will issue a full */ - /* count of potentially matching features, ignoring any client or server */ - /* side limits. */ - - const char* pszComputeNumberMatched = - msOWSLookupMetadata(&(map->web.metadata), "F", - "compute_number_matched"); - if( pszComputeNumberMatched != NULL && - strcasecmp(pszComputeNumberMatched, "true") == 0 ) - { - int j; - mapObj* mapTmp = (mapObj*)msSmallCalloc(1, sizeof(mapObj)); - initMap(mapTmp); - msCopyMap(mapTmp, map); - - /* Re-run the query but with no limit */ - mapTmp->query.maxfeatures = -1; - mapTmp->query.startindex = -1; - mapTmp->query.only_cache_result_count = MS_TRUE; - for(j=0; jnumlayers; j++) { - layerObj* lp = GET_LAYER(mapTmp, j); - /* Reset layer paging */ - lp->maxfeatures = -1; - lp->startindex = -1; - } - - nMatchingFeatures = 0; - msWFSRetrieveFeatures(mapTmp, - ows_request, - paramsObj, - pgmlinfo, - paramsObj->pszFilter, - paramsObj->pszBbox != NULL, - sBBoxSrs, - bbox, - paramsObj->pszFeatureId, - layers, - numlayers, - -1, - nWFSVersion, - &nMatchingFeatures, - NULL); - - msFreeMap(mapTmp); - } - } - } - - return nMatchingFeatures; -} - -static int msWFSResolveStoredQuery(mapObj *map, wfsParamsObj *paramsObj, cgiRequestObj *req) -{ - if (paramsObj->pszStoredQueryId != NULL ) - { - int i; - int status; - hashTableObj* hashTable = msCreateHashTable(); - char* pszResolvedQuery; - - if (req->NumParams > 0 && req->postrequest == NULL ) { - for(i=0; iNumParams; i++) { - if (req->ParamNames[i] && req->ParamValues[i]) { - msInsertHashTable(hashTable, req->ParamNames[i], req->ParamValues[i]); - } - } - } - - pszResolvedQuery = msWFSGetResolvedStoredQuery20(map, paramsObj, - paramsObj->pszStoredQueryId, - hashTable); - msFreeHashTable(hashTable); - - if( pszResolvedQuery == NULL ) - return MS_FAILURE; - - status = msWFSAnalyzeStoredQuery(map, paramsObj, - paramsObj->pszStoredQueryId, - pszResolvedQuery); - msFree(pszResolvedQuery); - - if( status != MS_SUCCESS ) - return status; - - msWFSSimplifyPropertyNameAndFilter(paramsObj); - } - return MS_SUCCESS; -} - -/* -** msWFSUnaliasItem() -*/ -static -const char* msWFSUnaliasItem(layerObj* lp, const char* name) -{ - const char* pszFullName; - char szTmp[256]; - int z; - for(z=0; znumitems; z++) { - if (!lp->items[z] || strlen(lp->items[z]) <= 0) - continue; - snprintf(szTmp, sizeof(szTmp), "%s_alias", lp->items[z]); - pszFullName = msOWSLookupMetadata(&(lp->metadata), "G", szTmp); - if (pszFullName && strcmp(name, pszFullName) == 0) - return lp->items[z]; - } - return name; -} - -/* -** msWFSIsAllowedItem() -*/ -static int msWFSIsAllowedItem(gmlItemListObj *itemList , const char* name) -{ - int z; - for(z=0; znumitems; z++) { - if (itemList->items[z].visible && - strcasecmp(name, itemList->items[z].name) == 0) { - return MS_TRUE; - } - } - return MS_FALSE; -} - -/* -** msWFSUngroupItem() -*/ -static -const char* msWFSUngroupItem(layerObj* lp, gmlGroupListObj* groupList, - const char* name, int* pnGroupIndex) -{ - int z; - - *pnGroupIndex = -1; - for(z=0; znumgroups; z++) { - const char* pszGroupName = groupList->groups[z].name; - size_t nGroupNameLen = strlen(pszGroupName); - - /* Is it a group name ? */ - if(strcasecmp(name, pszGroupName) == 0) - { - *pnGroupIndex = z; - return NULL; - } - - /* Is it an item of a group ? */ - if(strncasecmp(name, pszGroupName, nGroupNameLen) == 0 && - name[nGroupNameLen] == '/') { - - int w; - const char* pszSubName = msWFSStripNS(name+nGroupNameLen+1); - pszSubName = msWFSUnaliasItem(lp, pszSubName); - for(w=0;wgroups[z].numitems;w++) - { - if( strcasecmp(pszSubName, groupList->groups[z].items[w]) == 0 ) - { - return pszSubName; - } - } - } - } - - return name; -} - -/* -** msWFSApplySortBy() -*/ -static int msWFSApplySortBy(mapObj* map, wfsParamsObj *paramsObj, layerObj* lp, - const char* pszSortBy, - gmlItemListObj *itemList, - gmlGroupListObj* groupList) -{ - int y, n; - char** tokens; - int invalidSortBy = MS_FALSE; - sortByClause sortBy; - - if( !msLayerSupportsSorting(lp) ) - { - msSetError(MS_WFSERR, "Layer %s does not support sorting", "msWFSGetFeature()", lp->name); - return msWFSException(map, "mapserv", MS_WFS_ERROR_OPERATION_PROCESSING_FAILED, paramsObj->pszVersion); - } - - tokens = msStringSplit(pszSortBy, ',', &n); - sortBy.nProperties = n; - sortBy.properties = (sortByProperties* )msSmallMalloc(n * sizeof(sortByProperties)); - for(y=0; y= 0 ) - invalidSortBy = MS_TRUE; - - if( !msWFSIsAllowedItem(itemList, pszSortProperty) ) - invalidSortBy = MS_TRUE; - - pszTmp = msStrdup(pszSortProperty); - msFree(sortBy.properties[y].item); - sortBy.properties[y].item = pszTmp; - } - msFreeCharArray(tokens, n); - - if( !invalidSortBy ) - msLayerSetSort(lp, &sortBy); - - for(y=0; ypszVersion); - } - - return MS_SUCCESS; -} - -static void msWFSSetShapeCache(mapObj* map) -{ - const char* pszFeaturesCacheCount = - msOWSLookupMetadata(&(map->web.metadata), "F", - "features_cache_count"); - const char* pszFeaturesCacheSize = - msOWSLookupMetadata(&(map->web.metadata), "F", - "features_cache_size"); - if( pszFeaturesCacheCount ) - { - map->query.cache_shapes = MS_TRUE; - map->query.max_cached_shape_count = atoi(pszFeaturesCacheCount); - msDebug("Caching up to %d shapes\n", map->query.max_cached_shape_count); - } - - if( pszFeaturesCacheSize ) - { - map->query.cache_shapes = MS_TRUE; - map->query.max_cached_shape_ram_amount = atoi(pszFeaturesCacheSize); - if( strstr(pszFeaturesCacheSize, "mb") || strstr(pszFeaturesCacheSize, "MB") ) - map->query.max_cached_shape_ram_amount *= 1024 * 1024; - msDebug("Caching up to %d bytes of shapes\n", map->query.max_cached_shape_ram_amount); - } -} - -/* -** msWFSGetFeature() -*/ -static -int msWFSGetFeature(mapObj *map, wfsParamsObj *paramsObj, cgiRequestObj *req, - owsRequestObj *ows_request, int nWFSVersion) -{ - int status; - int maxfeatures=-1,startindex=-1; - rectObj bbox; - - char **layers = NULL; - int numlayers = 0; - - char *sBBoxSrs = NULL; - - WFSGMLInfo gmlinfo; - - OWSGMLVersion outputformat = OWS_GML2; /* default output is GML 2.1 */ - outputFormatObj *psFormat = NULL; - - int iNumberOfFeatures = 0; - int iResultTypeHits = 0; - int nMatchingFeatures = -1; - int bHasNextFeatures = MS_FALSE; - - char** papszGMLGroups = NULL; - char** papszGMLIncludeItems = NULL; - char** papszGMLGeometries = NULL; - - msIOContext* old_context = NULL; - - /* Initialize gml options */ - msWFSInitGMLInfo(&gmlinfo); - - if (paramsObj->pszResultType != NULL) { - if (strcasecmp(paramsObj->pszResultType, "hits") == 0) - iResultTypeHits = 1; - } - - status = msWFSResolveStoredQuery(map, paramsObj, req); - if( status != MS_SUCCESS ) - return status; - - /* typename is mandatory unless featureid is specfied. We do not - support featureid */ - if (paramsObj->pszTypeName==NULL && paramsObj->pszFeatureId == NULL) { - msSetError(MS_WFSERR, - "Incomplete WFS request: %s parameter missing", - "msWFSGetFeature()", - (nWFSVersion >= OWS_2_0_0 ) ? "TYPENAMES": "TYPENAME" ); - return msWFSException(map, (nWFSVersion >= OWS_2_0_0 ) ? "typenames": "typename", - MS_OWS_ERROR_MISSING_PARAMETER_VALUE, paramsObj->pszVersion); - } - - /* Is it a WFS 2.0 GetFeatureById stored query with an unknown id ? */ - /* If so, CITE interprets the spec as requesting to issue a OperationProcessingFailed */ - /* exception. A bit strange when a similar request but with RESOURCEID= should */ - /* produce an empty FeatureCollection */ - if( nWFSVersion >= OWS_2_0_0 && - paramsObj->pszTypeName != NULL && strcmp(paramsObj->pszTypeName, "?") == 0 && - paramsObj->pszFilter != NULL && paramsObj->pszFeatureId == NULL ) - { - CPLXMLNode* psDoc; - - psDoc = CPLParseXMLString(paramsObj->pszFilter); - if( psDoc != NULL ) - { - const char* rid; - - CPLStripXMLNamespace(psDoc, NULL, 1); - rid = CPLGetXMLValue(psDoc, "=Filter.ResourceId.rid", NULL); - if( rid != NULL ) - { - msSetError(MS_WFSERR, "Invalid rid '%s'", "msWFSGetFeature()", rid); - CPLDestroyXMLNode(psDoc); - return msWFSException(map, NULL, MS_WFS_ERROR_OPERATION_PROCESSING_FAILED, - paramsObj->pszVersion ); - } - CPLDestroyXMLNode(psDoc); - } - } - - papszGMLGroups = (char**) calloc(sizeof(char*), map->numlayers); - papszGMLIncludeItems = (char**) calloc(sizeof(char*), map->numlayers); - papszGMLGeometries = (char**) calloc(sizeof(char*), map->numlayers); - - if(paramsObj->pszTypeName) { - int k, y,z; - - char **tokens; - int n=0, i=0; - char **papszPropertyName = NULL; - char **papszSortBy = NULL; - - /* keep a ref for layer use. */ - gmlinfo._typename = paramsObj->pszTypeName; - - /* Parse comma-delimited list of type names (layers) */ - /* */ - /* __TODO__ Need to handle type grouping, e.g. "(l1,l2),l3,l4" */ - /* */ - layers = msStringSplit(gmlinfo._typename, ',', &numlayers); - - /* ==================================================================== */ - /* TODO: check if the typename contains namespaces (ex cdf:Other), */ - /* If that is the case extract only the layer name. */ - /* ==================================================================== */ - - if (layers==NULL || numlayers < 1) { - msSetError(MS_WFSERR, "At least one type name required in %s parameter.", "msWFSGetFeature()", - (nWFSVersion >= OWS_2_0_0 ) ? "TYPENAMES": "TYPENAME" ); - return msWFSException(map, (nWFSVersion >= OWS_2_0_0 ) ? "typenames": "typename" , - MS_OWS_ERROR_INVALID_PARAMETER_VALUE, paramsObj->pszVersion); - } - - /* strip namespace if there is one :ex TYPENAME=cdf:Other */ - for (i=0; ipszPropertyName, numlayers); - if( papszPropertyName == NULL ) { - msFreeCharArray(layers, numlayers); - msFreeCharArray(papszGMLGroups, map->numlayers); - msFreeCharArray(papszGMLIncludeItems, map->numlayers); - msFreeCharArray(papszGMLGeometries, map->numlayers); - msSetError(MS_WFSERR, - "Optional PROPERTYNAME parameter. A list of properties may be specified for each type name. Example TYPENAME=name1,name2&PROPERTYNAME=(prop1,prop2)(prop1)", - "msWFSGetFeature()"); - return msWFSException(map, "PROPERTYNAME", MS_OWS_ERROR_INVALID_PARAMETER_VALUE, paramsObj->pszVersion); - } - - papszSortBy = msWFSParsePropertyNameOrSortBy(paramsObj->pszSortBy, numlayers); - if( papszSortBy == NULL ) { - msFreeCharArray(layers, numlayers); - msFreeCharArray(papszPropertyName, numlayers); - msFreeCharArray(papszGMLGroups, map->numlayers); - msFreeCharArray(papszGMLIncludeItems, map->numlayers); - msFreeCharArray(papszGMLGeometries, map->numlayers); - msSetError(MS_WFSERR, - "Optional SORTBY parameter. A list may be specified for each type name. Example TYPENAME=name1,name2&SORTBY=(prop1,prop2)(prop1)", - "msWFSGetFeature()"); - return msWFSException(map, "SORTBY", MS_OWS_ERROR_INVALID_PARAMETER_VALUE, paramsObj->pszVersion); - } - - for (k=0; kstatus = MS_ON; - if (lp->_template == NULL) { - /* Force setting a template to enable query. */ - lp->_template = msStrdup("ttt.html"); - } - - /*do an alias replace for the current layer*/ - if (msLayerOpen(lp) == MS_SUCCESS && msLayerGetItems(lp) == MS_SUCCESS) { - - itemList = msGMLGetItems(lp, "G"); - groupList = msGMLGetGroups(lp, "G"); - - if( strcmp(papszSortBy[k], "!") != 0 ) - { - status = msWFSApplySortBy(map, paramsObj, lp, - papszSortBy[k], itemList, groupList); - if( status != MS_SUCCESS ) - { - msFreeCharArray(papszPropertyName, numlayers); - msFreeCharArray(papszSortBy, numlayers); - msFreeCharArray(layers, numlayers); - msFreeCharArray(papszGMLGroups, map->numlayers); - msFreeCharArray(papszGMLIncludeItems, map->numlayers); - msFreeCharArray(papszGMLGeometries, map->numlayers); - msGMLFreeItems(itemList); - msGMLFreeGroups(groupList); - return status; - } - } - - geometryList=msGMLGetGeometries(lp, "GFO", MS_TRUE); - - /* unalias, ungroup and validate that the property names passed are part of the items list*/ - tokens = msStringSplit(papszPropertyName[k], ',', &n); - for (y=0; y= 0 ) - continue; - - /* Check that the property name is allowed (#3563) */ - /*we need to check of the property name is the geometry name; In that case it - is a valid property name*/ - if (!msWFSIsAllowedItem(itemList,pszPropertyNameItem)) { - for(z=0; znumgeometries; z++) { - if (strcasecmp(pszPropertyNameItem, geometryList->geometries[z].name) == 0) - break; - } - - if (z == geometryList->numgeometries) { - msSetError(MS_WFSERR, - "Invalid PROPERTYNAME %s", "msWFSGetFeature()", tokens[y]); - msFreeCharArray(tokens, n); - msGMLFreeItems(itemList); - msGMLFreeGroups(groupList); - msGMLFreeGeometries(geometryList); - msFreeCharArray(papszPropertyName, numlayers); - msFreeCharArray(papszSortBy, numlayers); - msFreeCharArray(layers, numlayers); - msFreeCharArray(papszGMLGroups, map->numlayers); - msFreeCharArray(papszGMLIncludeItems, map->numlayers); - msFreeCharArray(papszGMLGeometries, map->numlayers); - return msWFSException(map, "PROPERTYNAME", MS_OWS_ERROR_INVALID_PARAMETER_VALUE, paramsObj->pszVersion); - } - } - else - { - char* pszTmp = msStrdup(pszPropertyNameItem); - msFree(tokens[y]); - tokens[y] = pszTmp; - } - } - - /* Add mandatory items that are not explicitely listed. */ - /* When the user specifies PROPERTYNAME, we might have to augment */ - /* the list of returned parameters so as to validate against the schema. */ - /* This is made clear in the WFS 1.0.0, 1.1.0 and 2.0.0 specs (#3319) */ - for(z=0; znumitems; z++) { - if( itemList->items[z].visible && - itemList->items[z].minOccurs == 1 ) - { - int bFound = MS_FALSE; - for (y=0; yitems[z].name) == 0 ) - { - bFound = MS_TRUE; - break; - } - } - if( !bFound ) - { - tokens = (char**) realloc(tokens, sizeof(char*) * (n+1)); - tokens[n] = msStrdup(itemList->items[z].name); - n ++; - } - } - } - - /* Rebuild papszPropertyName[k] */ - msFree(papszPropertyName[k]); - papszPropertyName[k] = NULL; - for (y=0; y 0) { - - if (strcasecmp(papszPropertyName[k], "*") == 0) { - /* Add all non-excluded items, including optional ones */ - msFree(papszPropertyName[k]); - papszPropertyName[k] = NULL; - for(z=0; znumitems; z++) { - if( itemList->items[z].visible ) { - if( papszPropertyName[k] != NULL ) - papszPropertyName[k] = msStringConcatenate( - papszPropertyName[k], ","); - papszPropertyName[k] = msStringConcatenate( - papszPropertyName[k], itemList->items[z].name); - } - } - if( papszPropertyName[k] ) - papszGMLIncludeItems[lp->index] = msStrdup(papszPropertyName[k]); - else - papszGMLIncludeItems[lp->index] = msStrdup(""); - - /* The user didn't specify explicity PROPERTYNAME for this layer */ - } else if (strcasecmp(papszPropertyName[k], "!") == 0) { - /* Add all non-excluded items, but only default and mandatory ones (and geometry) */ - msFree(papszPropertyName[k]); - papszPropertyName[k] = NULL; - for(z=0; znumitems; z++) { - if( itemList->items[z].visible && - (itemList->items[z].outputByDefault == 1 || - itemList->items[z].minOccurs == 1) ) { - if( papszPropertyName[k] != NULL ) - papszPropertyName[k] = msStringConcatenate( - papszPropertyName[k], ","); - papszPropertyName[k] = msStringConcatenate( - papszPropertyName[k], itemList->items[z].name); - } - } - if( papszPropertyName[k] ) - papszGMLIncludeItems[lp->index] = msStrdup(papszPropertyName[k]); - else - papszGMLIncludeItems[lp->index] = msStrdup(""); - - } else { - char* pszGeometryList = NULL; - - for(z=0; znumgroups; z++) { - const char* pszNeedle = strstr(papszPropertyName[k], groupList->groups[z].name); - char chAfterNeedle = 0; - if( pszNeedle != NULL ) - chAfterNeedle = papszPropertyName[k][strlen(groupList->groups[z].name)]; - if(pszNeedle != NULL && (chAfterNeedle == '\0' || chAfterNeedle == ',') ) { - int w; - for(w=0;wgroups[z].numitems;w++) - { - if(strstr(papszPropertyName[k], groupList->groups[z].items[w]) == NULL) { - papszPropertyName[k] = msStringConcatenate( - papszPropertyName[k], ","); - papszPropertyName[k] = msStringConcatenate( - papszPropertyName[k], groupList->groups[z].items[w]); - } - } - } - } - - papszGMLIncludeItems[lp->index] = msStrdup(papszPropertyName[k]); - - for(z=0; znumgeometries; z++) { - if (strstr(papszPropertyName[k], geometryList->geometries[z].name) != NULL) { - if( pszGeometryList != NULL ) - pszGeometryList = msStringConcatenate( - pszGeometryList, ","); - pszGeometryList = msStringConcatenate( - pszGeometryList, geometryList->geometries[z].name); - } - } - - if( pszGeometryList != NULL ) { - papszGMLGeometries[lp->index] = msStrdup(pszGeometryList); - msFree(pszGeometryList); - } else { - papszGMLGeometries[lp->index] = msStrdup("none"); - } - } - } else {/*empty string*/ - papszGMLGeometries[lp->index] = msStrdup("none"); - } - } - else - { - msFreeCharArray(papszPropertyName, numlayers); - msFreeCharArray(papszSortBy, numlayers); - msFreeCharArray(layers, numlayers); - msFreeCharArray(papszGMLGroups, map->numlayers); - msFreeCharArray(papszGMLIncludeItems, map->numlayers); - msFreeCharArray(papszGMLGeometries, map->numlayers); - msGMLFreeItems(itemList); - msGMLFreeGroups(groupList); - msGMLFreeGeometries(geometryList); - return msWFSException(map, "mapserv", MS_OWS_ERROR_NO_APPLICABLE_CODE, paramsObj->pszVersion); - } - - msGMLFreeItems(itemList); - msGMLFreeGroups(groupList); - msGMLFreeGeometries(geometryList); - } - else - { - /* Requested layer name was not in capabilities: - * either it just doesn't exist - */ - msSetError(MS_WFSERR, - "TYPENAME '%s' doesn't exist in this server. Please check the capabilities and reformulate your request.", - "msWFSGetFeature()", layers[k]); - msFreeCharArray(papszPropertyName, numlayers); - msFreeCharArray(papszSortBy, numlayers); - msFreeCharArray(layers, numlayers); - msFreeCharArray(papszGMLGroups, map->numlayers); - msFreeCharArray(papszGMLIncludeItems, map->numlayers); - msFreeCharArray(papszGMLGeometries, map->numlayers); - return msWFSException(map, "typename", MS_OWS_ERROR_INVALID_PARAMETER_VALUE, paramsObj->pszVersion); - } - } - - msFreeCharArray(papszPropertyName, numlayers); - msFreeCharArray(papszSortBy, numlayers); - } - - /* Validate outputformat */ - status = msWFSGetGMLOutputFormat(map, paramsObj, &gmlinfo, nWFSVersion); - if( status < 0 ) { - psFormat = msWFSGetOtherOutputFormat(map, paramsObj); - if( psFormat == NULL ) { - msFreeCharArray(layers, numlayers); - msFreeCharArray(papszGMLGroups, map->numlayers); - msFreeCharArray(papszGMLIncludeItems, map->numlayers); - msFreeCharArray(papszGMLGeometries, map->numlayers); - return msWFSException(map, "outputformat", - MS_OWS_ERROR_INVALID_PARAMETER_VALUE, - paramsObj->pszVersion ); - } - } - else { - outputformat = (OWSGMLVersion) status; - } - - msWFSAnalyzeStartIndexAndFeatureCount(map, paramsObj, iResultTypeHits, - &maxfeatures, &startindex); - - status = msWFSAnalyzeBBOX(map, paramsObj, &bbox, &sBBoxSrs); - if( status != 0 ) - { - msFreeCharArray(layers, numlayers); - msFreeCharArray(papszGMLGroups, map->numlayers); - msFreeCharArray(papszGMLIncludeItems, map->numlayers); - msFreeCharArray(papszGMLGeometries, map->numlayers); - return status; - } - - if( iResultTypeHits == 1 ) - { - map->query.only_cache_result_count = MS_TRUE; - } - else - { - msWFSSetShapeCache(map); - } - - status = msWFSRetrieveFeatures(map, - ows_request, - paramsObj, - &gmlinfo, - paramsObj->pszFilter, - paramsObj->pszBbox != NULL, - sBBoxSrs, - bbox, - paramsObj->pszFeatureId, - layers, - numlayers, - maxfeatures, - nWFSVersion, - &iNumberOfFeatures, - &bHasNextFeatures); - if( status != MS_SUCCESS ) - { - msFreeCharArray(layers, numlayers); - msFree(sBBoxSrs); - msFreeCharArray(papszGMLGroups, map->numlayers); - msFreeCharArray(papszGMLIncludeItems, map->numlayers); - msFreeCharArray(papszGMLGeometries, map->numlayers); - return status; - } - - /* ----------------------------------------- */ - /* Now compute nMatchingFeatures for WFS 2.0 */ - /* ----------------------------------------- */ - - nMatchingFeatures = msWFSComputeMatchingFeatures(map,ows_request,paramsObj, - iNumberOfFeatures, - maxfeatures, - &gmlinfo, - bbox, - sBBoxSrs, - layers, - numlayers, - nWFSVersion); - - msFreeCharArray(layers, numlayers); - - msFree(sBBoxSrs); - sBBoxSrs = NULL; - - /* - ** GML Header generation. - */ - - status = MS_SUCCESS; - - if( psFormat == NULL ) { - if( paramsObj->countGetFeatureById == 1 && maxfeatures != 0 && iResultTypeHits == 0 ) - { - /* When there's a single urn:ogc:def:query:OGC-WFS::GetFeatureById GetFeature request */ - /* we must not output a FeatureCollection but the object itself */ - /* We do that as a post-processing step, so let print into a buffer and modify the */ - /* XML afterwards */ - old_context = msIO_pushStdoutToBufferAndGetOldContext(); - } - else - { - msIO_setHeader("Content-Type","%s; charset=UTF-8", gmlinfo.output_mime_type); - msIO_sendHeaders(); - } - - status = msWFSGetFeature_GMLPreamble( map, req, &gmlinfo, paramsObj, - outputformat, - iResultTypeHits, - iNumberOfFeatures, - nMatchingFeatures, - maxfeatures, - bHasNextFeatures, - nWFSVersion ); - if(status != MS_SUCCESS) { - if( old_context != NULL ) - msIO_restoreOldStdoutContext(old_context); - msWFSCleanupGMLInfo(&gmlinfo); - msFreeCharArray(papszGMLGroups, map->numlayers); - msFreeCharArray(papszGMLIncludeItems, map->numlayers); - msFreeCharArray(papszGMLGeometries, map->numlayers); - return MS_FAILURE; - } - } - - { - int i; - for(i=0;inumlayers;i++) - { - layerObj* lp = GET_LAYER(map, i); - if( papszGMLGroups[i] ) - msInsertHashTable(&(lp->metadata), "GML_GROUPS", papszGMLGroups[i]); - if( papszGMLIncludeItems[i] ) - msInsertHashTable(&(lp->metadata), "GML_INCLUDE_ITEMS", papszGMLIncludeItems[i]); - if( papszGMLGeometries[i] ) - msInsertHashTable(&(lp->metadata), "GML_GEOMETRIES", papszGMLGeometries[i]); - } - } - - /* handle case of maxfeatures = 0 */ - /*internally use a start index that start with 0 as the first index*/ - if( psFormat == NULL ) { - if(maxfeatures != 0 && iResultTypeHits == 0) - { - int bWFS2MultipleFeatureCollection = MS_FALSE; - - /* Would make sense for WFS 1.1.0 too ! See #3576 */ - int bUseURN = (nWFSVersion == OWS_2_0_0); - const char* useurn = msOWSLookupMetadata(&(map->web.metadata), "F", "return_srs_as_urn"); - if (useurn && strcasecmp(useurn, "true") == 0) - bUseURN = 1; - else if (useurn && strcasecmp(useurn, "false") == 0) - bUseURN = 0; - - /* For WFS 2.0, when we request several types, we must present each type */ - /* in its own FeatureCollection (§ 11.3.3.5 ) */ - if( nWFSVersion >= OWS_2_0_0 && iResultTypeHits != 1 ) - { - int i; - int nLayersWithFeatures = 0; - for(i=0; inumlayers; i++) { - layerObj* lp = GET_LAYER(map, i); - if(lp->resultcache && lp->resultcache->numresults > 0) - nLayersWithFeatures ++; - } - if( nLayersWithFeatures > 1 ) - { - char timestring[100]; - resultCacheObj** saveResultCache = (resultCacheObj** ) - msSmallMalloc( map->numlayers * sizeof(resultCacheObj*)); - int iLastNonEmptyLayer = -1; - - msWFSGetFeature_GetTimeStamp(timestring, sizeof(timestring)); - - /* Emit global bounds */ - msGMLWriteWFSBounds(map, stdout, " ", outputformat, nWFSVersion, bUseURN); - - /* Save the result cache that contains the features that we want to */ - /* emit in the response */ - for(i=0; inumlayers; i++) { - layerObj* lp = GET_LAYER(map, i); - saveResultCache[i] = lp->resultcache; - if( lp->resultcache && lp->resultcache->numresults > 0) { - iLastNonEmptyLayer = i; - } - lp->resultcache = NULL; - } - - /* Just dump one layer at a time */ - for(i=0;inumlayers;i++) { - layerObj* lp = GET_LAYER(map, i); - lp->resultcache = saveResultCache[i]; - if( lp->resultcache && lp->resultcache->numresults > 0) { - msIO_fprintf(stdout, " \n"); - msIO_fprintf(stdout, " = 0 ) - msIO_fprintf(stdout, "%d", lp->resultcache->numresults ); - else - msIO_fprintf(stdout, "unknown" ); - msIO_fprintf(stdout, "\" numberReturned=\"%d\">\n", lp->resultcache->numresults ); - - msGMLWriteWFSQuery(map, stdout, - gmlinfo.user_namespace_prefix, - outputformat, - nWFSVersion, - bUseURN, - MS_FALSE); - msIO_fprintf(stdout, " \n"); - msIO_fprintf(stdout, " \n"); - } - lp->resultcache = NULL; - } - - /* Restore for later cleanup */ - for(i=0; inumlayers; i++) { - layerObj* lp = GET_LAYER(map, i); - lp->resultcache = saveResultCache[i]; - } - msFree(saveResultCache); - - bWFS2MultipleFeatureCollection = MS_TRUE; - } - } - - if( !bWFS2MultipleFeatureCollection ) - { - msGMLWriteWFSQuery(map, stdout, - gmlinfo.user_namespace_prefix, - outputformat, - nWFSVersion, - bUseURN, - MS_FALSE); - } - - status = MS_SUCCESS; - } - } else { - mapservObj *mapserv = msAllocMapServObj(); - - /* Setup dummy mapserv object */ - mapserv->sendheaders = MS_TRUE; - mapserv->map = map; - msFreeCgiObj(mapserv->request); - mapserv->request = req; - map->querymap.status = MS_FALSE; - - if( nMatchingFeatures >= 0 ) - { - char szMatchingFeatures[12]; - sprintf(szMatchingFeatures, "%d", nMatchingFeatures); - msSetOutputFormatOption( psFormat, "_matching_features_", - szMatchingFeatures); - } - else - { - msSetOutputFormatOption( psFormat, "_matching_features_", ""); - } - status = msReturnTemplateQuery( mapserv, psFormat->name, NULL ); - - mapserv->request = NULL; - mapserv->map = NULL; - - msFreeMapServObj( mapserv ); - - if( status != MS_SUCCESS ) { - msFreeCharArray(papszGMLGroups, map->numlayers); - msFreeCharArray(papszGMLIncludeItems, map->numlayers); - msFreeCharArray(papszGMLGeometries, map->numlayers); - return msWFSException(map, "mapserv", MS_OWS_ERROR_NO_APPLICABLE_CODE, - paramsObj->pszVersion ); - } - } - - msFreeCharArray(papszGMLGroups, map->numlayers); - msFreeCharArray(papszGMLIncludeItems, map->numlayers); - msFreeCharArray(papszGMLGeometries, map->numlayers); - - if( psFormat == NULL && status == MS_SUCCESS ) { - msWFSGetFeature_GMLPostfix( map, req, &gmlinfo, paramsObj, - outputformat, - maxfeatures, iResultTypeHits, iNumberOfFeatures, - nWFSVersion ); - } - - /*Special case for a single urn:ogc:def:query:OGC-WFS::GetFeatureById GetFeature request */ - if( old_context != NULL ) - { - msIOContext* new_context; - msIOBuffer* buffer; - CPLXMLNode* psRoot; - - new_context = msIO_getHandler(stdout); - buffer = (msIOBuffer *) new_context->cbData; - psRoot = CPLParseXMLString((const char*) buffer->data); - msIO_restoreOldStdoutContext(old_context); - if( psRoot != NULL ) - { - CPLXMLNode* psFeatureCollection = CPLGetXMLNode(psRoot, "=wfs:FeatureCollection"); - if( psFeatureCollection != NULL ) - { - CPLXMLNode* psMember = CPLGetXMLNode(psFeatureCollection, "wfs:member"); - if( psMember != NULL && psMember->psChild != NULL ) - { - CPLXMLNode* psIter; - CPLXMLNode* psFeatureNode; - char* pszTmpXML; - - /* Transfer all namespaces of FeatureCollection to the Feature */ - psFeatureNode = psMember->psChild; - psIter = psFeatureCollection->psChild; - while(psIter != NULL) - { - if( psIter->eType == CXT_Attribute && - (strncmp(psIter->pszValue, "xmlns:", strlen("xmlns:")) == 0 || - strncmp(psIter->pszValue, "xsi:", strlen("xsi:")) == 0) ) - { - CPLXMLNode* psIterNext = psIter->psNext; - psIter->psNext = NULL; - CPLAddXMLChild(psFeatureNode, CPLCloneXMLTree(psIter)); - psIter->psNext = psIterNext; - } - psIter = psIter->psNext; - } - - pszTmpXML = CPLSerializeXMLTree(psFeatureNode); - msIO_setHeader("Content-Type","%s; charset=UTF-8", gmlinfo.output_mime_type); - msIO_sendHeaders(); - msIO_printf("\n"); - msIO_printf("%s", pszTmpXML); - CPLFree(pszTmpXML); - } - else - { - status = msWFSException(map, NULL, MS_WFS_ERROR_OPERATION_PROCESSING_FAILED, - paramsObj->pszVersion ); - } - } - CPLDestroyXMLNode(psRoot); - } - } - - msWFSCleanupGMLInfo(&gmlinfo); - - return status; -} - -/* -** msWFSGetPropertyValue() -*/ -static -int msWFSGetPropertyValue(mapObj *map, wfsParamsObj *paramsObj, cgiRequestObj *req, - owsRequestObj *ows_request, int nWFSVersion) -{ - int status; - int maxfeatures=-1,startindex=-1; - rectObj bbox; - - char *sBBoxSrs = NULL; - - WFSGMLInfo gmlinfo; - - OWSGMLVersion outputformat = OWS_GML2; /* default output is GML 2.1 */ - - int iNumberOfFeatures = 0; - int iResultTypeHits = 0; - int nMatchingFeatures = -1; - int bHasNextFeatures = MS_FALSE; - - const char* pszTypeName; - layerObj *lp; - - char* pszGMLGroups = NULL; - char* pszGMLIncludeItems = NULL; - char* pszGMLGeometries = NULL; - - status = msWFSResolveStoredQuery(map, paramsObj, req); - if( status != MS_SUCCESS ) - return status; - - if (paramsObj->pszTypeName==NULL) { - msSetError(MS_WFSERR, - "Incomplete WFS request: TYPENAMES parameter missing", - "msWFSGetPropertyValue()"); - return msWFSException(map, "typenames", - MS_OWS_ERROR_MISSING_PARAMETER_VALUE, paramsObj->pszVersion); - } - - if (paramsObj->pszValueReference==NULL) { - msSetError(MS_WFSERR, - "Incomplete WFS request: VALUEREFERENCE parameter missing", - "msWFSGetPropertyValue()"); - return msWFSException(map, "valuereference", - MS_OWS_ERROR_MISSING_PARAMETER_VALUE, paramsObj->pszVersion); - } - - /* Keep only selected layers, set to OFF by default. */ - msWFSTurnOffAllLayer(map); - - /* Remove namespace prefix */ - pszTypeName = msWFSStripNS(paramsObj->pszTypeName); - - lp = msWFSGetLayerByName(map, ows_request, pszTypeName); - if( lp != NULL ) { - gmlItemListObj *itemList=NULL; - gmlGeometryListObj *geometryList=NULL; - gmlGroupListObj* groupList=NULL; - - lp->status = MS_ON; - if (lp->_template == NULL) { - /* Force setting a template to enable query. */ - lp->_template = msStrdup("ttt.html"); - } - - /*do an alias replace for the current layer*/ - if (msLayerOpen(lp) == MS_SUCCESS && msLayerGetItems(lp) == MS_SUCCESS) { - const char* pszValueReference; - int z; - int nGroupIndex = -1; - - itemList = msGMLGetItems(lp, "G"); - groupList = msGMLGetGroups(lp, "G"); - - if( paramsObj->pszSortBy != NULL && - strcmp(paramsObj->pszSortBy, "!") != 0 ) - { - status = msWFSApplySortBy(map, paramsObj, lp, - paramsObj->pszSortBy, itemList, groupList); - if( status != MS_SUCCESS ) - { - msGMLFreeItems(itemList); - msGMLFreeGroups(groupList); - return status; - } - } - - geometryList=msGMLGetGeometries(lp, "GFO", MS_TRUE); - - pszValueReference = msWFSStripNS(paramsObj->pszValueReference); - pszValueReference = msWFSUnaliasItem(lp, pszValueReference); - pszValueReference = msWFSUngroupItem(lp, groupList, pszValueReference, &nGroupIndex); - - if( strcmp(paramsObj->pszValueReference, "@gml:id") == 0 ) { - pszGMLGroups = msStrdup(""); - pszGMLIncludeItems = msStrdup(paramsObj->pszValueReference); - pszGMLGeometries = msStrdup("none"); - } - else if( nGroupIndex >= 0 ) { - int w; - char* pszItems = NULL; - for(w=0;wgroups[nGroupIndex].numitems;w++) { - if( w > 0 ) - pszItems = msStringConcatenate(pszItems, ","); - pszItems = msStringConcatenate(pszItems, groupList->groups[nGroupIndex].items[w]); - } - pszGMLGroups = msStrdup(groupList->groups[nGroupIndex].name); - pszGMLIncludeItems = msStrdup(pszItems); - pszGMLGeometries = msStrdup("none"); - msFree(pszItems); - } - else { - pszGMLGroups = msStrdup(""); - - /* Check that the property name is allowed (#3563) */ - /*we need to check of the property name is the geometry name; In that case it - is a valid property name*/ - if (!msWFSIsAllowedItem(itemList, pszValueReference)) { - for(z=0; znumgeometries; z++) { - if (strcasecmp(pszValueReference, geometryList->geometries[z].name) == 0) - break; - } - - if (z == geometryList->numgeometries) { - msSetError(MS_WFSERR, - "Invalid VALUEREFERENCE %s", "msWFSGetPropertyValue()", paramsObj->pszValueReference); - msFree(pszGMLGroups); - msGMLFreeItems(itemList); - msGMLFreeGroups(groupList); - msGMLFreeGeometries(geometryList); - return msWFSException(map, "valuereference", MS_OWS_ERROR_INVALID_PARAMETER_VALUE, paramsObj->pszVersion); - } - else { - pszGMLIncludeItems = msStrdup(""); - pszGMLGeometries = msStrdup(pszValueReference); - } - } - else { - pszGMLIncludeItems = msStrdup(pszValueReference); - pszGMLGeometries = msStrdup("none"); - } - } - - msLayerClose(lp); - - msGMLFreeItems(itemList); - msGMLFreeGroups(groupList); - msGMLFreeGeometries(geometryList); - } - } - else { - /* Requested layer name was not in capabilities: - * either it just doesn't exist - */ - msSetError(MS_WFSERR, - "TYPENAME '%s' doesn't exist in this server. Please check the capabilities and reformulate your request.", - "msWFSGetFeature()", paramsObj->pszTypeName); - msFree(pszGMLGroups); - msFree(pszGMLIncludeItems); - msFree(pszGMLGeometries); - return msWFSException(map, "typename", MS_OWS_ERROR_INVALID_PARAMETER_VALUE, paramsObj->pszVersion); - } - - /* Initialize gml options */ - msWFSInitGMLInfo(&gmlinfo); - - if (paramsObj->pszResultType != NULL) { - if (strcasecmp(paramsObj->pszResultType, "hits") == 0) - iResultTypeHits = 1; - } - - gmlinfo._typename = paramsObj->pszTypeName; - - /* Validate outputformat */ - status = msWFSGetGMLOutputFormat(map, paramsObj, &gmlinfo, nWFSVersion); - if( status < 0 ) { - msSetError(MS_WFSERR, - "'%s' is not a permitted output format for GetPropertyValue request.", - "msWFSGetPropertyValue()", - paramsObj->pszOutputFormat); - msFree(pszGMLGroups); - msFree(pszGMLIncludeItems); - msFree(pszGMLGeometries); - return msWFSException(map, "outputformat", - MS_OWS_ERROR_INVALID_PARAMETER_VALUE, - paramsObj->pszVersion ); - } - else { - outputformat = (OWSGMLVersion) status; - } - - msWFSAnalyzeStartIndexAndFeatureCount(map, paramsObj, iResultTypeHits, - &maxfeatures, &startindex); - - status = msWFSAnalyzeBBOX(map, paramsObj, &bbox, &sBBoxSrs); - if( status != 0 ) { - msFree(pszGMLGroups); - msFree(pszGMLIncludeItems); - msFree(pszGMLGeometries); - return status; - } - - if( iResultTypeHits == 1 ) - { - map->query.only_cache_result_count = MS_TRUE; - } - else - { - msWFSSetShapeCache(map); - } - - status = msWFSRetrieveFeatures(map, - ows_request, - paramsObj, - &gmlinfo, - paramsObj->pszFilter, - paramsObj->pszBbox != NULL, - sBBoxSrs, - bbox, - paramsObj->pszFeatureId, - (char**) &pszTypeName, - 1, - maxfeatures, - nWFSVersion, - &iNumberOfFeatures, - &bHasNextFeatures); - if( status != MS_SUCCESS ) - { - msFree(sBBoxSrs); - msFree(pszGMLGroups); - msFree(pszGMLIncludeItems); - msFree(pszGMLGeometries); - return status; - } - - /* ----------------------------------------- */ - /* Now compute nMatchingFeatures for WFS 2.0 */ - /* ----------------------------------------- */ - - nMatchingFeatures = msWFSComputeMatchingFeatures(map,ows_request,paramsObj, - iNumberOfFeatures, - maxfeatures, - &gmlinfo, - bbox, - sBBoxSrs, - (char**) &pszTypeName, - 1, - nWFSVersion); - - msFree(sBBoxSrs); - sBBoxSrs = NULL; - - /* - ** GML Header generation. - */ - msIO_setHeader("Content-Type","%s; charset=UTF-8", gmlinfo.output_mime_type); - msIO_sendHeaders(); - - status = msWFSGetFeature_GMLPreamble( map, req, &gmlinfo, paramsObj, - outputformat, - iResultTypeHits, - iNumberOfFeatures, - nMatchingFeatures, - maxfeatures, - bHasNextFeatures, - nWFSVersion ); - - if(status == MS_SUCCESS && maxfeatures != 0 && iResultTypeHits == 0) - { - if( pszGMLGroups ) - msInsertHashTable(&(lp->metadata), "GML_GROUPS", pszGMLGroups); - if( pszGMLIncludeItems ) - msInsertHashTable(&(lp->metadata), "GML_INCLUDE_ITEMS", pszGMLIncludeItems); - if( pszGMLGeometries ) - msInsertHashTable(&(lp->metadata), "GML_GEOMETRIES", pszGMLGeometries); - - status = msGMLWriteWFSQuery(map, stdout, - gmlinfo.user_namespace_prefix, - outputformat, - nWFSVersion, - MS_TRUE, - MS_TRUE); - } - - msIO_printf("\n"); - - msFree(pszGMLGroups); - msFree(pszGMLIncludeItems); - msFree(pszGMLGeometries); - - free(gmlinfo.script_url); - free(gmlinfo.script_url_encoded); - msFree(gmlinfo.user_namespace_uri_encoded); - - return status; -} - - -#endif /* USE_WFS_SVR */ - - -/* -** msWFSDispatch() is the entry point for WFS requests. -** - If this is a valid request then it is processed and MS_SUCCESS is returned -** on success, or MS_FAILURE on failure. -** - If this does not appear to be a valid WFS request then MS_DONE -** is returned and MapServer is expected to process this as a regular -** MapServer request. -*/ -int msWFSDispatch(mapObj *map, cgiRequestObj *requestobj, owsRequestObj *ows_request, int force_wfs_mode) -{ -#ifdef USE_WFS_SVR - int status; - int returnvalue = MS_DONE; - int nWFSVersion; - char* validated_language; - - /* static char *wmtver = NULL, *request=NULL, *service=NULL; */ - wfsParamsObj *paramsObj; - /* - ** Populate the Params object based on the request - */ - paramsObj = msWFSCreateParamsObj(); - /* TODO : store also parameters that are inside the map object */ - /* into the paramsObj. */ - status = msWFSParseRequest(map, requestobj, ows_request, paramsObj, force_wfs_mode); - if (status != MS_SUCCESS) - { - msWFSFreeParamsObj(paramsObj); - return status; - } - - validated_language = msOWSGetLanguageFromList(map, "FO", paramsObj->pszLanguage); - if (validated_language != NULL) { - msMapSetLanguageSpecificConnection(map, validated_language); - } - msFree(validated_language); - - if (force_wfs_mode) { - /*request is always required*/ - if (paramsObj->pszRequest==NULL || strlen(paramsObj->pszRequest)<=0) { - msSetError(MS_WFSERR, - "Incomplete WFS request: REQUEST parameter missing", - "msWFSDispatch()"); - returnvalue = msWFSException(map, "request", MS_OWS_ERROR_MISSING_PARAMETER_VALUE, paramsObj->pszVersion); - msWFSFreeParamsObj(paramsObj); - return returnvalue; - } - - /*version: - wfs 1.0 and 1.1.0 POST request: optional - wfs 1.0 and 1.1.0 GET request: optional for getcapabilities and required for describefeature and getfeature - */ - if (paramsObj->pszVersion == NULL && requestobj && requestobj->postrequest == NULL && - strcasecmp(paramsObj->pszRequest, "GetCapabilities") != 0) { - msSetError(MS_WFSERR, - "Invalid WFS request: VERSION parameter missing", - "msWFSDispatch()"); - returnvalue = msWFSException(map, "version", MS_OWS_ERROR_MISSING_PARAMETER_VALUE, paramsObj->pszVersion); - msWFSFreeParamsObj(paramsObj); - return returnvalue; - } - - if (paramsObj->pszVersion == NULL || strlen(paramsObj->pszVersion) <=0) - paramsObj->pszVersion = msStrdup(msWFSGetDefaultVersion(map)); - - /*service - wfs 1.0 and 1.1.0 GET: required and should be set to WFS - wfs 1.0 POST: required - wfs 1.1.1 POST: optional - */ - if ((paramsObj->pszService == NULL || strlen(paramsObj->pszService) == 0) && - ((requestobj && requestobj->postrequest == NULL) || strcasecmp(paramsObj->pszVersion,"1.0") ==0)) { - msSetError(MS_WFSERR, - "Invalid WFS request: Missing SERVICE parameter", - "msWFSDispatch()"); - returnvalue = msWFSException(map, "service", MS_OWS_ERROR_MISSING_PARAMETER_VALUE, paramsObj->pszVersion); - msWFSFreeParamsObj(paramsObj); - return returnvalue; - } - - if (paramsObj->pszService == NULL || strlen(paramsObj->pszService) == 0) - paramsObj->pszService = msStrdup("WFS"); - - if (paramsObj->pszService!=NULL && strcasecmp(paramsObj->pszService, "WFS") != 0) { - msSetError(MS_WFSERR, - "Invalid WFS request: SERVICE parameter must be set to WFS", - "msWFSDispatch()"); - returnvalue = msWFSException(map, "service", MS_OWS_ERROR_INVALID_PARAMETER_VALUE, paramsObj->pszVersion); - msWFSFreeParamsObj(paramsObj); - return returnvalue; - } - - } - /* If SERVICE is specified then it MUST be "WFS" */ - if (paramsObj->pszService != NULL && - strcasecmp(paramsObj->pszService, "WFS") != 0) { - msWFSFreeParamsObj(paramsObj); - return MS_DONE; /* Not a WFS request */ - } - - /* If SERVICE, VERSION and REQUEST not included than this isn't a WFS req*/ - if (paramsObj->pszService == NULL && paramsObj->pszVersion==NULL && - paramsObj->pszRequest==NULL) { - msWFSFreeParamsObj(paramsObj); - return MS_DONE; /* Not a WFS request */ - } - - /* VERSION *and* REQUEST *and* SERVICE required by all WFS requests including - * GetCapabilities. - */ - if (paramsObj->pszVersion==NULL || strlen(paramsObj->pszVersion)<=0) { - msSetError(MS_WFSERR, - "Incomplete WFS request: VERSION parameter missing", - "msWFSDispatch()"); - - returnvalue = msWFSException11(map, "version", MS_OWS_ERROR_MISSING_PARAMETER_VALUE, msWFSGetDefaultVersion(map)); - msWFSFreeParamsObj(paramsObj); - return returnvalue; - } - - if (paramsObj->pszRequest==NULL || strlen(paramsObj->pszRequest)<=0) { - msSetError(MS_WFSERR, - "Incomplete WFS request: REQUEST parameter missing", - "msWFSDispatch()"); - returnvalue = msWFSException(map, "request", MS_OWS_ERROR_MISSING_PARAMETER_VALUE, paramsObj->pszVersion); - msWFSFreeParamsObj(paramsObj); - return returnvalue; - } - - if (paramsObj->pszService==NULL || strlen(paramsObj->pszService)<=0) { - msSetError(MS_WFSERR, - "Incomplete WFS request: SERVICE parameter missing", - "msWFSDispatch()"); - - returnvalue = msWFSException(map, "service", MS_OWS_ERROR_MISSING_PARAMETER_VALUE, paramsObj->pszVersion); - msWFSFreeParamsObj(paramsObj); - return returnvalue; - } - - if ((status = msOWSMakeAllLayersUnique(map)) != MS_SUCCESS) { - msSetError(MS_WFSERR, "msOWSMakeAllLayersUnique() failed", "msWFSDispatch()"); - returnvalue = msWFSException(map, "mapserv", MS_OWS_ERROR_NO_APPLICABLE_CODE, paramsObj->pszVersion); - msWFSFreeParamsObj(paramsObj); - return returnvalue; - } - /* - ** Start dispatching requests - */ - if (strcasecmp(paramsObj->pszRequest, "GetCapabilities") == 0 ) { - msOWSRequestLayersEnabled(map, "F", paramsObj->pszRequest, ows_request); - if (ows_request->numlayers == 0) { - msSetError(MS_WFSERR, "WFS request not enabled. Check wfs/ows_enable_request settings.", "msWFSDispatch()"); - returnvalue = msWFSException(map, "request", MS_OWS_ERROR_INVALID_PARAMETER_VALUE, paramsObj->pszVersion); - msWFSFreeParamsObj(paramsObj); - return returnvalue; - } - - returnvalue = msWFSGetCapabilities(map, paramsObj, requestobj, ows_request); - msWFSFreeParamsObj(paramsObj); - return returnvalue; - } - - /* - ** Validate VERSION against the versions that we support... we don't do this - ** for GetCapabilities in order to allow version negociation. - */ - if (strcmp(paramsObj->pszVersion, "1.0.0") != 0 && - strcmp(paramsObj->pszVersion, "1.1.0") != 0 && - strcmp(paramsObj->pszVersion, "2.0.0") != 0) { - msSetError(MS_WFSERR, - "WFS Server does not support VERSION %s.", - "msWFSDispatch()", paramsObj->pszVersion); - returnvalue = msWFSException(map, "version", MS_OWS_ERROR_INVALID_PARAMETER_VALUE,msWFSGetDefaultVersion(map)); - msWFSFreeParamsObj(paramsObj); - return returnvalue; - - } - - nWFSVersion = msOWSParseVersionString(paramsObj->pszVersion); - - /* Since the function can still return MS_DONE, we add an extra service check to not call - msOWSRequestLayersEnabled twice */ - if (strcasecmp(paramsObj->pszService, "WFS") == 0) { - msOWSRequestLayersEnabled(map, "F", paramsObj->pszRequest, ows_request); - if (ows_request->numlayers == 0) { - msSetError(MS_WFSERR, "WFS request not enabled. Check wfs/ows_enable_request settings.", "msWFSDispatch()"); - returnvalue = msWFSException(map, "request", MS_OWS_ERROR_INVALID_PARAMETER_VALUE, paramsObj->pszVersion); - msWFSFreeParamsObj(paramsObj); - return returnvalue; - } - } - - returnvalue = MS_DONE; - /* Continue dispatching... - */ - if (strcasecmp(paramsObj->pszRequest, "DescribeFeatureType") == 0) - returnvalue = msWFSDescribeFeatureType(map, paramsObj, ows_request, nWFSVersion); - - else if (strcasecmp(paramsObj->pszRequest, "GetFeature") == 0) - returnvalue = msWFSGetFeature(map, paramsObj, requestobj, ows_request, nWFSVersion); - - else if (nWFSVersion >= OWS_2_0_0 && - strcasecmp(paramsObj->pszRequest, "GetPropertyValue") == 0) - returnvalue = msWFSGetPropertyValue(map, paramsObj, requestobj, ows_request, nWFSVersion); - - else if (nWFSVersion >= OWS_2_0_0 && - strcasecmp(paramsObj->pszRequest, "ListStoredQueries") == 0) - returnvalue = msWFSListStoredQueries20(map, paramsObj, requestobj, ows_request); - - else if (nWFSVersion >= OWS_2_0_0 && - strcasecmp(paramsObj->pszRequest, "DescribeStoredQueries") == 0) - returnvalue = msWFSDescribeStoredQueries20(map, paramsObj, requestobj, ows_request); - - else if (msWFSGetIndexUnsupportedOperation(paramsObj->pszRequest) >= 0 ) { - /* Unsupported WFS request */ - msSetError(MS_WFSERR, "Unsupported WFS request: %s", "msWFSDispatch()", - paramsObj->pszRequest); - returnvalue = msWFSException(map, paramsObj->pszRequest, MS_OWS_ERROR_OPERATION_NOT_SUPPORTED, paramsObj->pszVersion); - } else if (strcasecmp(paramsObj->pszService, "WFS") == 0) { - /* Invalid WFS request */ - msSetError(MS_WFSERR, "Invalid WFS request: %s", "msWFSDispatch()", - paramsObj->pszRequest); - returnvalue = msWFSException(map, "request", MS_OWS_ERROR_INVALID_PARAMETER_VALUE, paramsObj->pszVersion); - } - - /* This was not detected as a WFS request... let MapServer handle it */ - msWFSFreeParamsObj(paramsObj); - return returnvalue; - -#else - msSetError(MS_WFSERR, "WFS server support is not available.", - "msWFSDispatch()"); - return(MS_FAILURE); -#endif -} - -/************************************************************************/ -/* msWFSCreateParamsObj */ -/* */ -/* Create a parameter object, initialize it. */ -/* The caller should free the object using msWFSFreeParamsObj. */ -/************************************************************************/ -wfsParamsObj *msWFSCreateParamsObj() -{ - wfsParamsObj *paramsObj = (wfsParamsObj *)calloc(1, sizeof(wfsParamsObj)); - MS_CHECK_ALLOC(paramsObj, sizeof(wfsParamsObj), NULL); - - paramsObj->nMaxFeatures = -1; - paramsObj->nStartIndex = -1; - - return paramsObj; -} - - - -/************************************************************************/ -/* msWFSFreeParmsObj */ -/* */ -/* Free params object. */ -/************************************************************************/ -void msWFSFreeParamsObj(wfsParamsObj *wfsparams) -{ - if (wfsparams) { - free(wfsparams->pszVersion); - free(wfsparams->pszUpdateSequence); - free(wfsparams->pszRequest); - free(wfsparams->pszService); - free(wfsparams->pszTypeName); - free(wfsparams->pszFilter); - free(wfsparams->pszFilterLanguage); - free(wfsparams->pszBbox); - free(wfsparams->pszGeometryName); - free(wfsparams->pszOutputFormat); - free(wfsparams->pszFeatureId); - free(wfsparams->pszSrs); - free(wfsparams->pszResultType); - free(wfsparams->pszPropertyName); - free(wfsparams->pszAcceptVersions); - free(wfsparams->pszSections); - free(wfsparams->pszSortBy); - free(wfsparams->pszLanguage); - free(wfsparams->pszValueReference); - free(wfsparams->pszStoredQueryId); - - free(wfsparams); - } -} - -#ifdef USE_WFS_SVR -/************************************************************************/ -/* msWFSGetDefaultVersion */ -/************************************************************************/ -static -const char *msWFSGetDefaultVersion(mapObj *map) -{ - const char* pszVersion = - msOWSLookupMetadata(&(map->web.metadata), "F", "getcapabilities_version"); - if( pszVersion != NULL ) - { - /* Check that the metadata value is one of the recognized versions */ - int iVersion = msOWSParseVersionString(pszVersion); - int i; - for( i = 0; i < wfsNumSupportedVersions; i ++ ) - { - if( iVersion == wfsSupportedVersions[i] ) - return wfsSupportedVersionsStr[i]; - } - /* If not, use the default (= latest) version */ - msDebug("msWFSGetDefaultVersion(): invalid value for " - "wfs_getcapabilities_version: %s\n", pszVersion); - } - return WFS_LATEST_VERSION; -} - -/************************************************************************/ -/* msWFSSetParam */ -/************************************************************************/ -static int msWFSSetParam(char** ppszOut, cgiRequestObj *request, int i, - const char* pszExpectedParamName) -{ - if( strcasecmp(request->ParamNames[i], pszExpectedParamName) == 0 ) - { - if( *ppszOut == NULL ) - *ppszOut = msStrdup(request->ParamValues[i]); - return 1; - } - return 0; -} - -/************************************************************************/ -/* msWFSParseXMLQueryNode */ -/************************************************************************/ - -static void msWFSParseXMLQueryNode(CPLXMLNode* psQuery, wfsParamsObj *wfsparams) -{ - const char* pszTypename; - const char* pszValue; - char *pszSerializedFilter, *pszTmp, *pszTmp2; - CPLXMLNode* psPropertyName; - CPLXMLNode* psFilter; - CPLXMLNode* psSortBy; - char* pszSortBy = NULL; - - pszValue = CPLGetXMLValue(psQuery, "srsName", - NULL); - if (pszValue) - { - msFree(wfsparams->pszSrs); - wfsparams->pszSrs = msStrdup(pszValue); - } - - /* parse typenames */ - pszTypename = CPLGetXMLValue(psQuery, - "typename", NULL); - if( pszTypename == NULL ) /* WFS 2.0 */ - pszTypename = CPLGetXMLValue(psQuery, - "typeNames", NULL); - - /*parse property name*/ - psPropertyName = CPLGetXMLNode(psQuery, "PropertyName"); - pszTmp2= NULL; - - /*when there is no PropertyName, we output (!) so that it is parsed properly in GetFeature*/ - if (psPropertyName == NULL) - pszTmp2 = msStrdup("!"); - - while (psPropertyName) { - if (!psPropertyName->pszValue || - strcasecmp(psPropertyName->pszValue, "PropertyName") != 0) { - psPropertyName = psPropertyName->psNext; - continue; - } - pszValue = CPLGetXMLValue(psPropertyName, NULL, NULL); - if (pszTmp2 == NULL) { - pszTmp2 = msStrdup(pszValue); - } else { - pszTmp = msStrdup(pszTmp2); - pszTmp2 = (char *)msSmallRealloc(pszTmp2, sizeof(char)* (strlen(pszTmp)+ strlen(pszValue)+2)); - sprintf(pszTmp2,"%s,%s",pszTmp, pszValue); - msFree(pszTmp); - } - psPropertyName = psPropertyName->psNext; - } - if (pszTmp2) { - pszTmp = msStrdup(pszTmp2); - pszTmp2 = (char *)msSmallRealloc(pszTmp2, sizeof(char)* (strlen(pszTmp)+ 3)); - sprintf(pszTmp2,"(%s)", pszTmp); - msFree(pszTmp); - - msWFSBuildParamList(&(wfsparams->pszPropertyName), pszTmp2, ""); - msFree(pszTmp2); - pszTmp2 = NULL; - } - - /* parse filter */ - psFilter = CPLGetXMLNode(psQuery, "Filter"); - - if (psFilter == NULL) { - /*when there is no Filter, we output (!) so that it is parsed properly in GetFeature*/ - pszSerializedFilter = msStrdup("(!)"); - } else { - char* pszCPLTmp = CPLSerializeXMLTree(psFilter); - pszSerializedFilter = (char *)msSmallMalloc(sizeof(char)* - (strlen(pszCPLTmp)+3)); - sprintf(pszSerializedFilter, "(%s)", pszCPLTmp); - CPLFree(pszCPLTmp); - } - - msWFSBuildParamList(&(wfsparams->pszFilter), pszSerializedFilter, ""); - free(pszSerializedFilter); - - /* parse SortBy */ - psSortBy = CPLGetXMLNode(psQuery, "SortBy"); - if( psSortBy != NULL ) - { - int bFirstProperty = MS_TRUE; - CPLXMLNode* psIter = psSortBy->psChild; - - pszSortBy = msStringConcatenate(pszSortBy, "("); - - while( psIter != NULL ) - { - if( psIter->eType == CXT_Element && - strcmp(psIter->pszValue, "SortProperty") == 0 ) - { - const char* pszPropertyName = CPLGetXMLValue(psIter, "PropertyName", NULL); - if( pszPropertyName == NULL ) - pszPropertyName = CPLGetXMLValue(psIter, "ValueReference", NULL); - if( pszPropertyName != NULL ) - { - const char* pszSortOrder = CPLGetXMLValue(psIter, "SortOrder", NULL); - if( !bFirstProperty ) - pszSortBy = msStringConcatenate(pszSortBy, ","); - bFirstProperty = MS_FALSE; - - pszSortBy = msStringConcatenate(pszSortBy, pszPropertyName); - if( pszSortOrder != NULL ) - { - pszSortBy = msStringConcatenate(pszSortBy, " "); - pszSortBy = msStringConcatenate(pszSortBy, pszSortOrder); - } - } - } - psIter = psIter->psNext; - } - - pszSortBy = msStringConcatenate(pszSortBy, ")"); - } - else - { - pszSortBy = msStrdup("(!)"); - } - - msWFSBuildParamList(&(wfsparams->pszSortBy), pszSortBy, ""); - free(pszSortBy); - - /* Special case for "urn:ogc:def:query:OGC-WFS::GetFeatureById" */ - /* Resolve the property typename */ - if( pszTypename != NULL && strcmp(pszTypename, "?") == 0 && psFilter != NULL ) - { - const char* rid; - rid = CPLGetXMLValue(psFilter, "ResourceId.rid", NULL); - if( rid != NULL ) - { - char* pszTmpTypename = msStrdup(rid); - char* pszDot = strchr(pszTmpTypename, '.'); - if( pszDot ) - { - *pszDot = '\0'; - msWFSBuildParamList(&(wfsparams->pszTypeName), pszTmpTypename, ","); - pszTypename = NULL; - - if( wfsparams->countGetFeatureById >= 0 ) - wfsparams->countGetFeatureById ++; - } - else - wfsparams->countGetFeatureById = -1; - msFree(pszTmpTypename); - } - else - wfsparams->countGetFeatureById = -1; - } - else - wfsparams->countGetFeatureById = -1; - - if (pszTypename) { - msWFSBuildParamList(&(wfsparams->pszTypeName), pszTypename, ","); - } - -} - -/************************************************************************/ -/* msWFSAnalyzeStoredQuery */ -/************************************************************************/ - -static int msWFSAnalyzeStoredQuery(mapObj* map, - wfsParamsObj *wfsparams, - const char* id, - const char* pszResolvedQuery) -{ - CPLXMLNode* psRoot; - CPLXMLNode* psQuery; - CPLXMLNode* psIter; - - psRoot = CPLParseXMLString(pszResolvedQuery); - - if( psRoot == NULL ) - { - msSetError(MS_WFSERR, "Resolved definition for stored query '%s' is invalid", "msWFSParseRequest()", id); - msWFSException(map, "mapserv", MS_OWS_ERROR_NO_APPLICABLE_CODE, wfsparams->pszVersion); - return MS_FAILURE; - } - - CPLStripXMLNamespace(psRoot, NULL, 1); - psQuery = CPLGetXMLNode(psRoot, "=StoredQueryDescription.QueryExpressionText.Query"); - if( psQuery == NULL ) - { - msSetError(MS_WFSERR, "Resolved definition for stored query '%s' is invalid", "msWFSParseRequest()", id); - msWFSException(map, "mapserv", MS_OWS_ERROR_NO_APPLICABLE_CODE, wfsparams->pszVersion); - CPLDestroyXMLNode(psRoot); - return MS_FAILURE; - } - - psIter = psQuery; - while( psIter != NULL ) - { - if( psIter->eType == CXT_Element && strcmp(psIter->pszValue, "Query") == 0 ) { - msWFSParseXMLQueryNode(psIter, wfsparams); - } - psIter = psIter->psNext; - } - - CPLDestroyXMLNode(psRoot); - - return MS_SUCCESS; -} - -/************************************************************************/ -/* msWFSParseXMLStoredQueryNode */ -/************************************************************************/ - -static int msWFSParseXMLStoredQueryNode(mapObj* map, - wfsParamsObj *wfsparams, - CPLXMLNode* psQuery) -{ - const char* id; - CPLXMLNode* psIter; - hashTableObj * hashTable; - char* pszResolvedQuery; - int status; - - id = CPLGetXMLValue(psQuery, "id", NULL); - if( id == NULL ) - { - msSetError(MS_WFSERR, "Missing 'id' attribute in StoredQuery", "msWFSParseRequest()"); - return msWFSException(map, "id", MS_OWS_ERROR_MISSING_PARAMETER_VALUE, wfsparams->pszVersion); - } - - hashTable = msCreateHashTable(); - psIter = psQuery->psChild; - while(psIter != NULL) - { - if( psIter->eType == CXT_Element && - strcmp(psIter->pszValue, "Parameter") == 0 ) - { - const char* name; - CPLXMLNode* psIter2; - char* pszValue; - - name = CPLGetXMLValue(psIter, "name", NULL); - if( name == NULL ) - { - msSetError(MS_WFSERR, "Missing 'name' attribute in Parameter of StoredQuery", "msWFSParseRequest()"); - msFreeHashTable(hashTable); - return msWFSException(map, NULL, MS_OWS_ERROR_INVALID_PARAMETER_VALUE, wfsparams->pszVersion); - } - - psIter2 = psIter->psChild; - while( psIter2 != NULL ) - { - if( psIter2->eType != CXT_Attribute ) - break; - psIter2 = psIter2->psNext; - } - - pszValue = CPLSerializeXMLTree(psIter2); - msInsertHashTable(hashTable, name, pszValue); - CPLFree(pszValue); - } - psIter = psIter->psNext; - } - - pszResolvedQuery = msWFSGetResolvedStoredQuery20(map, wfsparams, id, hashTable); - msFreeHashTable(hashTable); - if( pszResolvedQuery == NULL) - return MS_FAILURE; - - status = msWFSAnalyzeStoredQuery(map, wfsparams, id, pszResolvedQuery); - - msFree(pszResolvedQuery); - - return status; -} - -/************************************************************************/ -/* msWFSSimplifyPropertyNameAndFilter */ -/************************************************************************/ - -static void msWFSSimplifyPropertyNameAndFilter(wfsParamsObj *wfsparams) -{ - int i; - - /* If no PropertyName at all was specified, then clear the field */ - /* that will be easier to generate valid 'next' and 'previous' uri */ - /* for WFS 2.0 GetFeature */ - if( wfsparams->pszPropertyName != NULL ) - { - i = 0; - while( strncmp(wfsparams->pszPropertyName + i, "(!)", 3) == 0 ) - i += 3; - if( wfsparams->pszPropertyName[i] == '\0' ) - { - msFree(wfsparams->pszPropertyName); - wfsparams->pszPropertyName = NULL; - } - } - - /* Same with filter */ - if( wfsparams->pszFilter != NULL ) - { - i = 0; - while( strncmp(wfsparams->pszFilter + i, "(!)", 3) == 0 ) - i += 3; - if( wfsparams->pszFilter[i] == '\0' ) - { - msFree(wfsparams->pszFilter); - wfsparams->pszFilter = NULL; - } - } - - /* Same with SortBy */ - if( wfsparams->pszSortBy != NULL ) - { - i = 0; - while( strncmp(wfsparams->pszSortBy + i, "(!)", 3) == 0 ) - i += 3; - if( wfsparams->pszSortBy[i] == '\0' ) - { - msFree(wfsparams->pszSortBy); - wfsparams->pszSortBy = NULL; - } - } -} - -#endif /* USE_WFS_SVR */ - - -/************************************************************************/ -/* msWFSParseRequest */ -/* */ -/* Parse request into the params object. */ -/************************************************************************/ -int msWFSParseRequest(mapObj *map, cgiRequestObj *request, owsRequestObj *ows_request, - wfsParamsObj *wfsparams, int force_wfs_mode) -{ -#ifdef USE_WFS_SVR - int i = 0; - - if (!request || !wfsparams) - return msWFSException(map, "request", "InvalidRequest", NULL); - - if (request->NumParams > 0 && request->postrequest == NULL ) { - for(i=0; iNumParams; i++) { - if (request->ParamNames[i] && request->ParamValues[i]) { - if( msWFSSetParam(&(wfsparams->pszVersion), request, i, "VERSION") ) - {} - - else if( msWFSSetParam(&(wfsparams->pszUpdateSequence), request, i, "UPDATESEQUENCE") ) - {} - - else if( msWFSSetParam(&(wfsparams->pszRequest), request, i, "REQUEST") ) - {} - - else if( msWFSSetParam(&(wfsparams->pszService), request, i, "SERVICE") ) - {} - - else if (strcasecmp(request->ParamNames[i], "MAXFEATURES") == 0) - wfsparams->nMaxFeatures = atoi(request->ParamValues[i]); - - /* WFS 2.0 */ - else if (strcasecmp(request->ParamNames[i], "COUNT") == 0) - wfsparams->nMaxFeatures = atoi(request->ParamValues[i]); - - else if (strcasecmp(request->ParamNames[i], "STARTINDEX") == 0) - wfsparams->nStartIndex = atoi(request->ParamValues[i]); - - else if( msWFSSetParam(&(wfsparams->pszBbox), request, i, "BBOX") ) - {} - - else if( msWFSSetParam(&(wfsparams->pszSrs), request, i, "SRSNAME") ) - {} - - else if( msWFSSetParam(&(wfsparams->pszResultType), request, i, "RESULTTYPE") ) - {} - - else if( msWFSSetParam(&(wfsparams->pszTypeName), request, i, "TYPENAME") ) - {} - - /* WFS 2.0 */ - else if( msWFSSetParam(&(wfsparams->pszTypeName), request, i, "TYPENAMES") ) - {} - - else if( msWFSSetParam(&(wfsparams->pszFilter), request, i, "FILTER") ) - {} - - /* WFS 2.0 */ - else if( msWFSSetParam(&(wfsparams->pszFilterLanguage), request, i, "FILTER_LANGUAGE") ) - {} - - else if( msWFSSetParam(&(wfsparams->pszOutputFormat), request, i, "OUTPUTFORMAT") ) - {} - - else if( msWFSSetParam(&(wfsparams->pszFeatureId), request, i, "FEATUREID") ) - {} - - /* WFS 2.0 */ - else if( msWFSSetParam(&(wfsparams->pszFeatureId), request, i, "RESOURCEID") ) - {} - - else if( msWFSSetParam(&(wfsparams->pszPropertyName), request, i, "PROPERTYNAME") ) - {} - - else if( msWFSSetParam(&(wfsparams->pszAcceptVersions), request, i, "ACCEPTVERSIONS") ) - {} - - else if( msWFSSetParam(&(wfsparams->pszSections), request, i, "SECTIONS") ) - {} - - else if( msWFSSetParam(&(wfsparams->pszSortBy), request, i, "SORTBY") ) - {} - - else if( msWFSSetParam(&(wfsparams->pszLanguage), request, i, "LANGUAGE") ) - {} - - else if( msWFSSetParam(&(wfsparams->pszValueReference), request, i, "VALUEREFERENCE") ) - {} - - else if( msWFSSetParam(&(wfsparams->pszStoredQueryId), request, i, "STOREDQUERY_ID") ) - {} - } - } - /* version is optional is the GetCapabilities. If not */ - /* provided, set it. Default it to latest implemented version */ - /* or to the specified one in wfs_getcapabilities_version */ - if (wfsparams->pszVersion == NULL && - wfsparams->pszRequest && - strcasecmp(wfsparams->pszRequest, "GetCapabilities") == 0) { - wfsparams->pszVersion = msStrdup(msWFSGetDefaultVersion(map)); - } - } - - /* -------------------------------------------------------------------- */ - /* Parse the post request. It is assumed to be an XML document. */ - /* -------------------------------------------------------------------- */ - if (request->postrequest != NULL) { - - CPLXMLNode *psRoot; - CPLXMLNode *psGetFeature = NULL; - CPLXMLNode *psGetCapabilities = NULL; - CPLXMLNode *psDescribeFeature = NULL; - CPLXMLNode *psGetPropertyValue = NULL; - CPLXMLNode *psListStoredQueries = NULL; - CPLXMLNode *psDescribeStoredQueries = NULL; - CPLXMLNode *psOperation = NULL; - const char *pszValue; - char *pszSchemaLocation = NULL; - - psRoot = CPLParseXMLString(request->postrequest); - if(map->debug == MS_DEBUGLEVEL_VVV) { - msDebug("msWFSParseRequest(): WFS post request: %s\n", request->postrequest); - } - if (psRoot) { - /* need to strip namespaces */ - CPLStripXMLNamespace(psRoot, NULL, 1); - - for( psOperation = psRoot; - psOperation != NULL; - psOperation = psOperation->psNext ) { - if(psOperation->eType == CXT_Element) { - - /* keep schemaLocation so as to be able to validate against appropriate */ - /* wfs.xsd schema afterwards */ - if( pszSchemaLocation == NULL && - CPLGetXMLValue(psOperation, "schemaLocation", NULL) != NULL ) - pszSchemaLocation = msStrdup( CPLGetXMLValue(psOperation, "schemaLocation", NULL) ); - - if(strcasecmp(psOperation->pszValue,"GetFeature")==0) { - psGetFeature = psOperation; - break; - } else if(strcasecmp(psOperation->pszValue,"GetCapabilities")==0) { - psGetCapabilities = psOperation; - break; - } else if(strcasecmp(psOperation->pszValue, - "DescribeFeatureType")==0) { - psDescribeFeature = psOperation; - break; - } else if(strcasecmp(psOperation->pszValue, - "GetPropertyValue")==0) { - psGetPropertyValue = psOperation; - break; - } else if(strcasecmp(psOperation->pszValue, - "ListStoredQueries")==0) { - psListStoredQueries = psOperation; - break; - } else if(strcasecmp(psOperation->pszValue, - "DescribeStoredQueries")==0) { - psDescribeStoredQueries = psOperation; - break; - } - /* these are unsupported requests. Just set the */ - /* request value and return; */ - else if (msWFSGetIndexUnsupportedOperation(psOperation->pszValue) >= 0) { - int idx = msWFSGetIndexUnsupportedOperation(psOperation->pszValue); - wfsparams->pszRequest = msStrdup(wfsUnsupportedOperations[idx]); - break; - } - } - } - - if( psOperation != NULL ) - { - pszValue = CPLGetXMLValue(psOperation, "version", - NULL); - if (pszValue) - wfsparams->pszVersion = msStrdup(pszValue); - - pszValue = CPLGetXMLValue(psOperation, "service", - NULL); - if (pszValue) - wfsparams->pszService = msStrdup(pszValue); - } - - /* -------------------------------------------------------------------- */ - /* Parse the GetFeature */ - /* -------------------------------------------------------------------- */ - if (psGetFeature) { - CPLXMLNode* psIter; - - wfsparams->pszRequest = msStrdup("GetFeature"); - - pszValue = CPLGetXMLValue(psGetFeature, "resultType", - NULL); - if (pszValue) - wfsparams->pszResultType = msStrdup(pszValue); - - pszValue = CPLGetXMLValue(psGetFeature, "maxFeatures", - NULL); - if (pszValue) - wfsparams->nMaxFeatures = atoi(pszValue); - else - { - /* WFS 2.0 */ - pszValue = CPLGetXMLValue(psGetFeature, "count", - NULL); - if (pszValue) - wfsparams->nMaxFeatures = atoi(pszValue); - } - - pszValue = CPLGetXMLValue(psGetFeature, "startIndex", - NULL); - if (pszValue) - wfsparams->nStartIndex = atoi(pszValue); - - pszValue = CPLGetXMLValue(psGetFeature, "outputFormat", - NULL); - if (pszValue) - wfsparams->pszOutputFormat = msStrdup(pszValue); - - /* -------------------------------------------------------------------- */ - /* Parse typenames and filters. If there are multiple queries, */ - /* typenames will be build with comma between thme */ - /* (typename1,typename2,...) and filters will be build with */ - /* bracets enclosinf the filters :(filter1)(filter2)... */ - /* propertynames are stored like (property1,property2)(property1) */ - /* -------------------------------------------------------------------- */ - psIter = psGetFeature->psChild; - while( psIter != NULL ) - { - if( psIter->eType == CXT_Element && - strcmp(psIter->pszValue, "Query") == 0 ) - { - msWFSParseXMLQueryNode(psIter, wfsparams); - } - else if( psIter->eType == CXT_Element && - strcmp(psIter->pszValue, "StoredQuery") == 0 ) - { - int status = msWFSParseXMLStoredQueryNode(map, wfsparams, psIter); - if( status != MS_SUCCESS ) - { - CPLDestroyXMLNode(psRoot); - msFree(pszSchemaLocation); - return status; - } - wfsparams->bHasPostStoredQuery = MS_TRUE; - } - psIter = psIter->psNext; - } - - msWFSSimplifyPropertyNameAndFilter(wfsparams); - }/* end of GetFeature */ - - - /* -------------------------------------------------------------------- */ - /* Parse the GetPropertyValue */ - /* -------------------------------------------------------------------- */ - if (psGetPropertyValue) { - CPLXMLNode* psIter; - - wfsparams->pszRequest = msStrdup("GetPropertyValue"); - - pszValue = CPLGetXMLValue(psGetPropertyValue, "valueReference", - NULL); - if (pszValue) - wfsparams->pszValueReference = msStrdup(pszValue); - - pszValue = CPLGetXMLValue(psGetPropertyValue, "resultType", - NULL); - if (pszValue) - wfsparams->pszResultType = msStrdup(pszValue); - - pszValue = CPLGetXMLValue(psGetPropertyValue, "count", - NULL); - if (pszValue) - wfsparams->nMaxFeatures = atoi(pszValue); - - pszValue = CPLGetXMLValue(psGetPropertyValue, "startIndex", - NULL); - if (pszValue) - wfsparams->nStartIndex = atoi(pszValue); - - pszValue = CPLGetXMLValue(psGetPropertyValue, "outputFormat", - NULL); - if (pszValue) - wfsparams->pszOutputFormat = msStrdup(pszValue); - - psIter = psGetPropertyValue->psChild; - while( psIter != NULL ) - { - if( psIter->eType == CXT_Element && - strcmp(psIter->pszValue, "Query") == 0 ) - { - msWFSParseXMLQueryNode(psIter, wfsparams); - /* Just one is allowed for GetPropertyValue */ - break; - } - else if( psIter->eType == CXT_Element && - strcmp(psIter->pszValue, "StoredQuery") == 0 ) - { - int status = msWFSParseXMLStoredQueryNode(map, wfsparams, psIter); - if( status != MS_SUCCESS ) - { - CPLDestroyXMLNode(psRoot); - msFree(pszSchemaLocation); - return status; - } - wfsparams->bHasPostStoredQuery = MS_TRUE; - /* Just one is allowed for GetPropertyValue */ - break; - } - psIter = psIter->psNext; - } - - msWFSSimplifyPropertyNameAndFilter(wfsparams); - }/* end of GetPropertyValue */ - - /* -------------------------------------------------------------------- */ - /* Parse GetCapabilities. */ - /* -------------------------------------------------------------------- */ - if (psGetCapabilities) { - CPLXMLNode* psAcceptVersions; - CPLXMLNode* psSections; - - wfsparams->pszRequest = msStrdup("GetCapabilities"); - - pszValue = CPLGetXMLValue(psGetCapabilities, "updateSequence", NULL); - if (pszValue) - wfsparams->pszUpdateSequence = msStrdup(pszValue); - - /* version is optional for the GetCapabilities. If not */ - /* provided, set it. */ - if (wfsparams->pszVersion == NULL) - wfsparams->pszVersion = msStrdup(msWFSGetDefaultVersion(map)); - - psAcceptVersions = CPLGetXMLNode(psGetCapabilities, "AcceptVersions"); - if( psAcceptVersions != NULL ) - { - CPLXMLNode* psIter = psAcceptVersions->psChild; - while( psIter != NULL ) - { - if( psIter->eType == CXT_Element && - strcmp(psIter->pszValue, "Version") == 0 ) - { - pszValue = CPLGetXMLValue(psIter, NULL, NULL); - if (pszValue) { - msWFSBuildParamList(&(wfsparams->pszAcceptVersions), pszValue, ","); - } - } - psIter = psIter->psNext; - } - } - - psSections = CPLGetXMLNode(psGetCapabilities, "Sections"); - if( psSections != NULL ) - { - CPLXMLNode* psIter = psSections->psChild; - while( psIter != NULL ) - { - if( psIter->eType == CXT_Element && - strcmp(psIter->pszValue, "Section") == 0 ) - { - pszValue = CPLGetXMLValue(psIter, NULL, NULL); - if (pszValue) { - msWFSBuildParamList(&(wfsparams->pszSections), pszValue, ","); - } - } - psIter = psIter->psNext; - } - } - }/* end of GetCapabilites */ - /* -------------------------------------------------------------------- */ - /* Parse DescribeFeatureType */ - /* -------------------------------------------------------------------- */ - if (psDescribeFeature) { - CPLXMLNode* psIter; - wfsparams->pszRequest = msStrdup("DescribeFeatureType"); - - pszValue = CPLGetXMLValue(psDescribeFeature, - "outputFormat", - NULL); - if (pszValue) - wfsparams->pszOutputFormat = msStrdup(pszValue); - - psIter = CPLGetXMLNode(psDescribeFeature, "TypeName"); - if (psIter) { - /* free typname and filter. There may have been */ - /* values if they were passed in the URL */ - if (wfsparams->pszTypeName) - free(wfsparams->pszTypeName); - wfsparams->pszTypeName = NULL; - - while (psIter ) - { - if( psIter->eType == CXT_Element && - strcasecmp(psIter->pszValue, "TypeName") == 0) { - pszValue = CPLGetXMLValue(psIter, NULL, NULL); - if (pszValue) { - msWFSBuildParamList(&(wfsparams->pszTypeName), pszValue, ","); - } - } - psIter = psIter->psNext; - } - } - - }/* end of DescibeFeatureType */ - - /* -------------------------------------------------------------------- */ - /* Parse the ListStoredQueries */ - /* -------------------------------------------------------------------- */ - if (psListStoredQueries) { - wfsparams->pszRequest = msStrdup("ListStoredQueries"); - }/* end of ListStoredQueries */ - - /* -------------------------------------------------------------------- */ - /* Parse the DescribeStoredQueries */ - /* -------------------------------------------------------------------- */ - if (psDescribeStoredQueries) { - CPLXMLNode* psIter; - - wfsparams->pszRequest = msStrdup("DescribeStoredQueries"); - - psIter = CPLGetXMLNode(psDescribeStoredQueries, "StoredQueryId"); - while (psIter ) - { - if( psIter->eType == CXT_Element && - strcasecmp(psIter->pszValue, "StoredQueryId") == 0) { - pszValue = CPLGetXMLValue(psIter, NULL, NULL); - if (pszValue) { - msWFSBuildParamList(&(wfsparams->pszStoredQueryId), pszValue, ","); - } - } - psIter = psIter->psNext; - } - }/* end of DescribeStoredQueries */ - - CPLDestroyXMLNode(psRoot); - } - -#if defined(USE_LIBXML2) - { - const char *schema_location=NULL, *validate=NULL; - - /*do we validate the xml ?*/ - validate = msOWSLookupMetadata(&(map->web.metadata), "FO", "validate_xml"); - if (validate && strcasecmp(validate, "true") == 0 && - (schema_location = msOWSLookupMetadata(&(map->web.metadata), "FO", "schemas_dir"))) - { - if ((wfsparams->pszService && strcmp(wfsparams->pszService, "WFS") == 0) || - force_wfs_mode) - { - char *schema_file =NULL; - if (pszSchemaLocation != NULL && strstr(pszSchemaLocation, "wfs/1.0") != NULL ) - { - schema_file = msStringConcatenate(schema_file, schema_location); - schema_file = msStringConcatenate(schema_file, MS_OWSCOMMON_WFS_10_SCHEMA_LOCATION); - } - else if (pszSchemaLocation != NULL && strstr(pszSchemaLocation, "wfs/1.1") != NULL ) - { - schema_file = msStringConcatenate(schema_file, schema_location); - schema_file = msStringConcatenate(schema_file, MS_OWSCOMMON_WFS_11_SCHEMA_LOCATION); - } - else if (pszSchemaLocation != NULL && strstr(pszSchemaLocation, "wfs/2.0") != NULL ) - { - schema_file = msStringConcatenate(schema_file, schema_location); - schema_file = msStringConcatenate(schema_file, MS_OWSCOMMON_WFS_20_SCHEMA_LOCATION); - } - if( schema_file != NULL ) - { - if (msOWSSchemaValidation(schema_file, request->postrequest) != 0) { - msSetError(MS_WFSERR, "Invalid POST request. XML is not valid", "msWFSParseRequest()"); - msFree(schema_file); - return msWFSException(map, "request", "InvalidRequest", NULL); - } - msFree(schema_file); - } - } - } - } -#endif - - msFree(pszSchemaLocation); - - } - -#endif - return MS_SUCCESS; -} - diff --git a/mapwfs11.cpp b/mapwfs11.cpp deleted file mode 100644 index 0f138877d0..0000000000 --- a/mapwfs11.cpp +++ /dev/null @@ -1,553 +0,0 @@ -/********************************************************************** - * $Id$ - * - * Project: MapServer - * Purpose: OGC WFS 1.1.0 implementation. This file holds some WFS 1.1.0 - * specific functions but other parts are still implemented in mapwfs.c. - * Author: Y. Assefa, DM Solutions Group (assefa@dmsolutions.ca) - * - ********************************************************************** - * Copyright (c) 2008, Y. Assefa, DM Solutions Group Inc - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies of this Software or works derived from this Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - ****************************************************************************/ - -#include "mapserver.h" -#include "mapows.h" - -#if defined(USE_WFS_SVR) && defined(USE_LIBXML2) -#include "maplibxml2.h" -#include "mapowscommon.h" -#include "mapogcfilter.h" - -#include - -/************************************************************************/ -/* msWFSException11() */ -/************************************************************************/ - -int msWFSException11(mapObj *map, const char *locator, - const char *exceptionCode, const char *version) -{ - int size = 0; - char *errorString = NULL; - char *schemasLocation = NULL; - - xmlDocPtr psDoc = NULL; - xmlNodePtr psRootNode = NULL; - xmlNsPtr psNsOws = NULL; - xmlChar *buffer = NULL; - - if (version == NULL) - version = "1.1.0"; - - psNsOws = xmlNewNs(NULL, BAD_CAST "http://www.opengis.net/ows", BAD_CAST "ows"); - - errorString = msGetErrorString("\n"); - schemasLocation = msEncodeHTMLEntities(msOWSGetSchemasLocation(map)); - - psDoc = xmlNewDoc(BAD_CAST "1.0"); - - psRootNode = msOWSCommonExceptionReport(psNsOws, OWS_1_0_0, schemasLocation, version, msOWSGetLanguage(map, "exception"), exceptionCode, locator, errorString); - - xmlDocSetRootElement(psDoc, psRootNode); - - xmlNewNs(psRootNode, BAD_CAST "http://www.opengis.net/ows", BAD_CAST "ows"); - - msIO_setHeader("Content-Type","text/xml; charset=UTF-8"); - msIO_sendHeaders(); - - xmlDocDumpFormatMemoryEnc(psDoc, &buffer, &size, ("UTF-8"), 1); - - msIO_printf("%s", buffer); - - /*free buffer and the document */ - free(errorString); - free(schemasLocation); - xmlFree(buffer); - xmlFreeDoc(psDoc); - xmlFreeNs(psNsOws); - - /* clear error since we have already reported it */ - msResetErrorList(); - - return MS_FAILURE; -} - -/************************************************************************/ -/* msWFSAddMetadataURL */ -/************************************************************************/ - -static void msWFSAddMetadataURL(layerObj* lp, - int nWFSVersion, - const std::string& radix, - xmlNodePtr psRootNode) -{ - const char* value = msOWSLookupMetadata(&(lp->metadata), "FO", (radix + "_href").c_str()); - - if (value) { - if( nWFSVersion >= OWS_2_0_0 ) - { - xmlNodePtr psNode = xmlNewChild(psRootNode, NULL, BAD_CAST "MetadataURL", NULL); - xmlNewProp(psNode, BAD_CAST "xlink:href", BAD_CAST value); - - value = msOWSLookupMetadata(&(lp->metadata), "FO", (radix + "_about").c_str()); - if( value != NULL ) - xmlNewProp(psNode, BAD_CAST "about", BAD_CAST value); - } - else - { - xmlNodePtr psNode = xmlNewTextChild(psRootNode, NULL, BAD_CAST "MetadataURL", BAD_CAST value); - - value = msOWSLookupMetadata(&(lp->metadata), "FO", (radix + "_format").c_str()); - - if (!value) - value = "text/html"; /* default */ - - xmlNewProp(psNode, BAD_CAST "format", BAD_CAST value); - - value = msOWSLookupMetadata(&(lp->metadata), "FO", (radix + "_type").c_str()); - - if (!value) - value = "FGDC"; /* default */ - - xmlNewProp(psNode, BAD_CAST "type", BAD_CAST value); - } - } -} - -/************************************************************************/ -/* msWFSDumpLayer11 */ -/************************************************************************/ -xmlNodePtr msWFSDumpLayer11(mapObj *map, layerObj *lp, xmlNsPtr psNsOws, - int nWFSVersion, const char* validate_language, - char *script_url) -{ - rectObj ext; - - xmlNodePtr psRootNode, psNode; - const char *value = NULL; - char *valueToFree; - char **tokens; - int n=0,i=0; - - psRootNode = xmlNewNode(NULL, BAD_CAST "FeatureType"); - - /* add namespace to layer name */ - value = msOWSLookupMetadata(&(map->web.metadata), "FO", "namespace_prefix"); - - /* FIXME? Should probably be applied to WFS 1.1 as well, but the addition */ - /* of the prefix can be disruptive for clients */ - if( value == NULL && nWFSVersion >= OWS_2_0_0 ) - value = MS_DEFAULT_NAMESPACE_PREFIX; - - if(value) { - n = strlen(value)+strlen(lp->name)+1+1; - valueToFree = (char *) msSmallMalloc(sizeof(char*)*n); - snprintf(valueToFree, n, "%s%s%s", (value ? value : ""), (value ? ":" : ""), lp->name); - - psNode = xmlNewTextChild(psRootNode, NULL, BAD_CAST "Name", BAD_CAST valueToFree); - msFree(valueToFree); - } else { - psNode = xmlNewTextChild(psRootNode, NULL, BAD_CAST "Name", BAD_CAST lp->name); - } - - if (lp->name && strlen(lp->name) > 0 && - (msIsXMLTagValid(lp->name) == MS_FALSE || isdigit(lp->name[0]))) - { - char szTmp[512]; - snprintf(szTmp, sizeof(szTmp), - "WARNING: The layer name '%s' might contain spaces or " - "invalid characters or may start with a number. This could lead to potential problems", - lp->name); - xmlAddSibling(psNode, xmlNewComment(BAD_CAST szTmp)); - } - - value = msOWSLookupMetadataWithLanguage(&(lp->metadata), "FO", "title", validate_language); - if (!value) - value =(const char*)lp->name; - - psNode = xmlNewTextChild(psRootNode, NULL, BAD_CAST "Title", BAD_CAST value); - - - value = msOWSLookupMetadataWithLanguage(&(lp->metadata), "FO", "abstract", validate_language); - if (value) - psNode = xmlNewTextChild(psRootNode, NULL, BAD_CAST "Abstract", BAD_CAST value); - - - - value = msOWSLookupMetadataWithLanguage(&(lp->metadata), "FO", "keywordlist", validate_language); - - if(value) - msLibXml2GenerateList( - xmlNewChild(psRootNode, psNsOws, BAD_CAST "Keywords", NULL), - NULL, "Keyword", value, ',' ); - - /*support DefaultSRS and OtherSRS*/ - valueToFree = msOWSGetProjURN(&(map->projection),&(map->web.metadata),"FO",MS_FALSE); - if (!valueToFree) - valueToFree = msOWSGetProjURN(&(lp->projection), &(lp->metadata), "FO", MS_FALSE); - - if (valueToFree) { - tokens = msStringSplit(valueToFree, ' ', &n); - if (tokens && n > 0) { - if( nWFSVersion == OWS_1_1_0 ) - psNode = xmlNewTextChild(psRootNode, NULL, BAD_CAST "DefaultSRS", BAD_CAST tokens[0]); - else - psNode = xmlNewTextChild(psRootNode, NULL, BAD_CAST "DefaultCRS", BAD_CAST tokens[0]); - for (i=1; iprojection.numargs > 0) - msOWSProjectToWGS84(&lp->projection, &ext); - else - msOWSProjectToWGS84(&map->projection, &ext); - - xmlAddChild(psRootNode, - msOWSCommonWGS84BoundingBox( psNsOws, 2, - ext.minx, ext.miny, - ext.maxx, ext.maxy)); - } else { - xmlNewChild(psRootNode, psNsOws, BAD_CAST "WGS84BoundingBox", NULL); - xmlAddSibling(psNode, - xmlNewComment(BAD_CAST "WARNING: Optional WGS84BoundingBox could not be established for this layer. Consider setting the EXTENT in the LAYER object, or wfs_extent metadata. Also check that your data exists in the DATA statement")); - } - - const char* metadataurl_list = msOWSLookupMetadata(&(lp->metadata), "FO", "metadataurl_list"); - if( metadataurl_list ) { - int ntokens = 0; - char** tokens = msStringSplit(metadataurl_list, ' ', &ntokens); - for( int i = 0; i < ntokens; i++ ) - { - std::string key("metadataurl_"); - key += tokens[i]; - msWFSAddMetadataURL(lp, nWFSVersion, key, psRootNode); - } - msFreeCharArray(tokens, ntokens); - } - else { - if (! msOWSLookupMetadata(&(lp->metadata), "FO", "metadataurl_href")) - msMetadataSetGetMetadataURL(lp, script_url); - - msWFSAddMetadataURL(lp, nWFSVersion, "metadataurl", psRootNode); - } - - return psRootNode; -} - -/************************************************************************/ -/* msWFSGetCapabilities11 */ -/* */ -/* Return the capabilities document for wfs 1.1.0 */ -/************************************************************************/ -int msWFSGetCapabilities11(mapObj *map, wfsParamsObj *params, - cgiRequestObj *req, owsRequestObj *ows_request) -{ - xmlDocPtr psDoc = NULL; /* document pointer */ - xmlNodePtr psRootNode, psMainNode, psNode, psFtNode; - const char *updatesequence=NULL; - xmlNsPtr psNsOws, psNsXLink, psNsOgc; - char *schemalocation = NULL; - char *xsi_schemaLocation = NULL; - const char *user_namespace_prefix = NULL; - const char *user_namespace_uri = NULL; - gmlNamespaceListObj *namespaceList=NULL; /* for external application schema support */ - - char *script_url=NULL, *formats_list; - const char *value = NULL; - - xmlChar *buffer = NULL; - int size = 0, i; - msIOContext *context = NULL; - - int ows_version = OWS_1_0_0; - int ret; - - /* -------------------------------------------------------------------- */ - /* Handle updatesequence */ - /* -------------------------------------------------------------------- */ - ret = msWFSHandleUpdateSequence(map, params, "msWFSGetCapabilities11()"); - if( ret != MS_SUCCESS ) - return ret; - - /* -------------------------------------------------------------------- */ - /* Create document. */ - /* -------------------------------------------------------------------- */ - psDoc = xmlNewDoc(BAD_CAST "1.0"); - - psRootNode = xmlNewNode(NULL, BAD_CAST "WFS_Capabilities"); - - xmlDocSetRootElement(psDoc, psRootNode); - - /* -------------------------------------------------------------------- */ - /* Name spaces */ - /* -------------------------------------------------------------------- */ - /*default name space*/ - xmlNewProp(psRootNode, BAD_CAST "xmlns", BAD_CAST "http://www.opengis.net/wfs"); - - xmlSetNs(psRootNode, xmlNewNs(psRootNode, BAD_CAST "http://www.opengis.net/gml", BAD_CAST "gml")); - xmlSetNs(psRootNode, xmlNewNs(psRootNode, BAD_CAST "http://www.opengis.net/wfs", BAD_CAST "wfs")); - - psNsOws = xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_OWS_NAMESPACE_URI, BAD_CAST MS_OWSCOMMON_OWS_NAMESPACE_PREFIX); - psNsXLink = xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_W3C_XLINK_NAMESPACE_URI, BAD_CAST MS_OWSCOMMON_W3C_XLINK_NAMESPACE_PREFIX); - xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_W3C_XSI_NAMESPACE_URI, BAD_CAST MS_OWSCOMMON_W3C_XSI_NAMESPACE_PREFIX); - xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_OGC_NAMESPACE_URI, BAD_CAST MS_OWSCOMMON_OGC_NAMESPACE_PREFIX ); - - value = msOWSLookupMetadata(&(map->web.metadata), "FO", "namespace_uri"); - if(value) user_namespace_uri = value; - - value = msOWSLookupMetadata(&(map->web.metadata), "FO", "namespace_prefix"); - if(value) user_namespace_prefix = value; - if(user_namespace_prefix != NULL && msIsXMLTagValid(user_namespace_prefix) == MS_FALSE) - msIO_printf("\n", user_namespace_prefix); - else - xmlNewNs(psRootNode, BAD_CAST user_namespace_uri, BAD_CAST user_namespace_prefix); - - /* any additional namespaces */ - namespaceList = msGMLGetNamespaces(&(map->web), "G"); - for(i=0; inumnamespaces; i++) { - if(namespaceList->namespaces[i].uri) { - xmlNewNs(psRootNode, BAD_CAST namespaceList->namespaces[i].uri, BAD_CAST namespaceList->namespaces[i].prefix); - } - } - msGMLFreeNamespaces(namespaceList); - - - xmlNewProp(psRootNode, BAD_CAST "version", BAD_CAST params->pszVersion ); - - updatesequence = msOWSLookupMetadata(&(map->web.metadata), "FO", "updatesequence"); - - if (updatesequence) - xmlNewProp(psRootNode, BAD_CAST "updateSequence", BAD_CAST updatesequence); - - /*schema*/ - schemalocation = msEncodeHTMLEntities( msOWSGetSchemasLocation(map) ); - xsi_schemaLocation = msStrdup("http://www.opengis.net/wfs"); - xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, " "); - xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, schemalocation); - xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, "/wfs/1.1.0/wfs.xsd"); - xmlNewNsProp(psRootNode, NULL, BAD_CAST "xsi:schemaLocation", BAD_CAST xsi_schemaLocation); - - /* -------------------------------------------------------------------- */ - /* Service metadata. */ - /* -------------------------------------------------------------------- */ - - xmlAddChild(psRootNode, - msOWSCommonServiceIdentification(psNsOws, map, "OGC WFS", params->pszVersion, "FO", NULL)); - - /*service provider*/ - xmlAddChild(psRootNode, msOWSCommonServiceProvider( - psNsOws, psNsXLink, map, "FO", NULL)); - - /*operation metadata */ - if ((script_url=msOWSGetOnlineResource(map, "FO", "onlineresource", req)) == NULL) { - msSetError(MS_WFSERR, "Server URL not found", "msWFSGetCapabilities11()"); - return msWFSException11(map, "mapserv", MS_OWS_ERROR_NO_APPLICABLE_CODE, params->pszVersion); - } - - /* -------------------------------------------------------------------- */ - /* Operations metadata. */ - /* -------------------------------------------------------------------- */ - psMainNode= xmlAddChild(psRootNode,msOWSCommonOperationsMetadata(psNsOws)); - - /* -------------------------------------------------------------------- */ - /* GetCapabilities */ - /* -------------------------------------------------------------------- */ - psNode = xmlAddChild(psMainNode, - msOWSCommonOperationsMetadataOperation(psNsOws,psNsXLink,"GetCapabilities", - OWS_METHOD_GETPOST, script_url)); - - xmlAddChild(psMainNode, psNode); - xmlAddChild(psNode, msOWSCommonOperationsMetadataDomainType( - ows_version, psNsOws, "Parameter", "service", "WFS")); - /*accept version*/ - xmlAddChild(psNode, msOWSCommonOperationsMetadataDomainType(ows_version, psNsOws, - "Parameter", "AcceptVersions", - "1.0.0,1.1.0")); - /*format*/ - xmlAddChild(psNode, msOWSCommonOperationsMetadataDomainType(ows_version, psNsOws, - "Parameter", "AcceptFormats", - "text/xml")); - - - /* -------------------------------------------------------------------- */ - /* DescribeFeatureType */ - /* -------------------------------------------------------------------- */ - if (msOWSRequestIsEnabled(map, NULL, "F", "DescribeFeatureType", MS_TRUE)) { - psNode = xmlAddChild(psMainNode, - msOWSCommonOperationsMetadataOperation(psNsOws,psNsXLink,"DescribeFeatureType", - OWS_METHOD_GETPOST, script_url)); - xmlAddChild(psMainNode, psNode); - - /*output format*/ - xmlAddChild(psNode, msOWSCommonOperationsMetadataDomainType(ows_version, psNsOws, - "Parameter", "outputFormat", - "XMLSCHEMA,text/xml; subtype=gml/2.1.2,text/xml; subtype=gml/3.1.1")); - } - - /* -------------------------------------------------------------------- */ - /* GetFeature */ - /* -------------------------------------------------------------------- */ - if (msOWSRequestIsEnabled(map, NULL, "F", "GetFeature", MS_TRUE)) { - - psNode = xmlAddChild(psMainNode, - msOWSCommonOperationsMetadataOperation(psNsOws,psNsXLink,"GetFeature", - OWS_METHOD_GETPOST, script_url)); - xmlAddChild(psMainNode, psNode); - - xmlAddChild(psNode, msOWSCommonOperationsMetadataDomainType(ows_version, psNsOws, - "Parameter", "resultType", - "results,hits")); - - formats_list = msWFSGetOutputFormatList( map, NULL, OWS_1_1_0 ); - xmlAddChild(psNode, msOWSCommonOperationsMetadataDomainType(ows_version, psNsOws, - "Parameter", "outputFormat", - formats_list)); - msFree( formats_list ); - - value = msOWSLookupMetadata(&(map->web.metadata), "FO", "maxfeatures"); - - if (value) { - xmlAddChild(psMainNode, msOWSCommonOperationsMetadataDomainType(ows_version, psNsOws, - "Constraint", "DefaultMaxFeatures", - (char *)value)); - } - } - - /* -------------------------------------------------------------------- */ - /* FeatureTypeList */ - /* -------------------------------------------------------------------- */ - - psFtNode = xmlNewNode(NULL, BAD_CAST "FeatureTypeList"); - xmlAddChild(psRootNode, psFtNode); - psNode = xmlNewChild(psFtNode, NULL, BAD_CAST "Operations", NULL); - xmlNewChild(psNode, NULL, BAD_CAST "Operation", BAD_CAST "Query"); - - for(i=0; inumlayers; i++) { - layerObj *lp; - lp = GET_LAYER(map, i); - - if (!msIntegerInArray(lp->index, ows_request->enabled_layers, ows_request->numlayers)) - continue; - - /* List only vector layers in which DUMP=TRUE */ - if (msWFSIsLayerSupported(lp)) - xmlAddChild(psFtNode, msWFSDumpLayer11(map, lp, psNsOws, OWS_1_1_0, NULL, script_url)); - } - - - - - - /* -------------------------------------------------------------------- */ - /* Filter capabilities. */ - /* -------------------------------------------------------------------- */ - - psNsOgc = xmlNewNs(NULL, BAD_CAST MS_OWSCOMMON_OGC_NAMESPACE_URI, BAD_CAST MS_OWSCOMMON_OGC_NAMESPACE_PREFIX); - xmlAddChild(psRootNode, FLTGetCapabilities(psNsOgc, psNsOgc, MS_FALSE)); - /* -------------------------------------------------------------------- */ - /* Write out the document. */ - /* -------------------------------------------------------------------- */ - - if( msIO_needBinaryStdout() == MS_FAILURE ) - return MS_FAILURE; - - msIO_setHeader("Content-Type","text/xml; charset=UTF-8"); - msIO_sendHeaders(); - - context = msIO_getHandler(stdout); - - xmlDocDumpFormatMemoryEnc(psDoc, &buffer, &size, ("UTF-8"), 1); - msIO_contextWrite(context, buffer, size); - xmlFree(buffer); - - /*free buffer and the document */ - /*xmlFree(buffer);*/ - xmlFreeDoc(psDoc); - xmlFreeNs(psNsOgc); - - free(script_url); - free(xsi_schemaLocation); - free(schemalocation); - - xmlCleanupParser(); - - return(MS_SUCCESS); -} - - -#endif /*defined(USE_WFS_SVR) && defined(USE_LIBXML2)*/ - -#if defined(USE_WFS_SVR) && !defined(USE_LIBXML2) - - - -int msWFSGetCapabilities11(mapObj *map, wfsParamsObj *params, - cgiRequestObj *req, owsRequestObj *ows_request) - -{ - msSetError( MS_WFSERR, - "WFS 1.1 request made, but mapserver requires libxml2 for WFS 1.1 services and this is not configured.", - "msWFSGetCapabilities11()" ); - - return msWFSException11(map, "mapserv", MS_OWS_ERROR_NO_APPLICABLE_CODE, params->pszVersion); -} - -int msWFSException11(mapObj *map, const char *locator, const char *exceptionCode, const char *version) -{ - /* fallback to reporting using 1.0 style exceptions. */ - return msWFSException( map, locator, exceptionCode, "1.0.0" ); -} - -#endif /* defined(USE_WFS_SVR) && !defined(USE_LIBXML2) */ diff --git a/mapwfs20.c b/mapwfs20.c deleted file mode 100644 index 3a7528eebc..0000000000 --- a/mapwfs20.c +++ /dev/null @@ -1,1418 +0,0 @@ -/********************************************************************** - * $Id$ - * - * Project: MapServer - * Purpose: OGC WFS 2.0.0 implementation. This file holds some WFS 2.0.0 - * specific functions but other parts are still implemented in mapwfs.c. - * Author: Even Rouault - * - ********************************************************************** - * Copyright (c) 2013, Even Rouault - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies of this Software or works derived from this Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - ****************************************************************************/ - -#include "mapserver.h" -#include "mapows.h" - -#if defined(USE_WFS_SVR) && defined(USE_LIBXML2) -#include "maplibxml2.h" -#include "mapowscommon.h" -#include "mapogcfilter.h" - -#define MS_OWS_11_NAMESPACE_PREFIX MS_OWSCOMMON_OWS_NAMESPACE_PREFIX -#define MS_OWS_11_NAMESPACE_URI MS_OWSCOMMON_OWS_110_NAMESPACE_URI - -#define URN_GET_FEATURE_BY_ID "urn:ogc:def:query:OGC-WFS::GetFeatureById" - -#define GET_FEATURE_BY_ID \ -"" \ -"Get feature by identifier" \ -"Returns the single feature whose value is equal to the specified value of the ID argument" \ -"" \ -"" \ -"" \ -"" \ -"" \ -"" \ -"" - -/************************************************************************/ -/* msWFSException20() */ -/************************************************************************/ - -int msWFSException20(mapObj *map, const char *locator, - const char *exceptionCode) -{ - int size = 0; - char *errorString = NULL; - - xmlDocPtr psDoc = NULL; - xmlNodePtr psRootNode = NULL; - xmlNsPtr psNsOws = NULL; - xmlChar *buffer = NULL; - const char* status = NULL; - - psNsOws = xmlNewNs(NULL, BAD_CAST MS_OWS_11_NAMESPACE_URI, BAD_CAST MS_OWS_11_NAMESPACE_PREFIX); - - errorString = msGetErrorString("\n"); - - psDoc = xmlNewDoc(BAD_CAST "1.0"); - - psRootNode = msOWSCommonExceptionReport(psNsOws, OWS_1_1_0, msOWSGetSchemasLocation(map), "2.0.0", msOWSGetLanguage(map, "exception"), exceptionCode, locator, errorString); - - xmlDocSetRootElement(psDoc, psRootNode); - - xmlNewNs(psRootNode, BAD_CAST MS_OWS_11_NAMESPACE_URI, BAD_CAST MS_OWS_11_NAMESPACE_PREFIX); - - /* Table D.2 OGC 09-025r1 - For CITE compliance */ - if( EQUAL(exceptionCode, MS_OWS_ERROR_OPERATION_NOT_SUPPORTED) || - EQUAL(exceptionCode, MS_OWS_ERROR_OPTION_NOT_SUPPORTED) ) { - status = "400 Not Implemented"; - } - else if( EQUAL(exceptionCode, MS_OWS_ERROR_MISSING_PARAMETER_VALUE) || - EQUAL(exceptionCode, MS_OWS_ERROR_INVALID_PARAMETER_VALUE) || - EQUAL(exceptionCode, MS_OWS_ERROR_VERSION_NEGOTIATION_FAILED) || - EQUAL(exceptionCode, MS_OWS_ERROR_INVALID_UPDATE_SEQUENCE) ) { - status = "400 Bad request"; - } - else if( EQUAL(exceptionCode, MS_WFS_ERROR_OPERATION_PROCESSING_FAILED) ) { - status = "403 Server processing failed"; - } - else if( EQUAL(exceptionCode, MS_OWS_ERROR_NO_APPLICABLE_CODE) ) { - status = "400 Internal Server Error"; - } - - if( status != NULL ) - { - msIO_setHeader("Status", "%s", status); - } - msIO_setHeader("Content-Type","text/xml; charset=UTF-8"); - msIO_sendHeaders(); - - xmlDocDumpFormatMemoryEnc(psDoc, &buffer, &size, "UTF-8", 1); - - msIO_printf("%s", buffer); - - /*free buffer and the document */ - free(errorString); - xmlFree(buffer); - xmlFreeDoc(psDoc); - xmlFreeNs(psNsOws); - - /* clear error since we have already reported it */ - msResetErrorList(); - - return MS_FAILURE; -} - -/************************************************************************/ -/* msWFSIncludeSection */ -/************************************************************************/ -static int msWFSIncludeSection(wfsParamsObj *params, const char* pszSection) -{ - int i; - if( params->pszSections == NULL ) - return TRUE; - for(i = 0; params->pszSections[i] != '\0'; i++ ) - { - if( strncasecmp( params->pszSections + i, "All", strlen("All")) == 0 ) - return TRUE; - if( strncasecmp( params->pszSections + i, pszSection, strlen(pszSection)) == 0 ) - return TRUE; - } - return FALSE; -} - -/************************************************************************/ -/* msWFSAddGlobalSRSNameParam */ -/************************************************************************/ - -static void msWFSAddGlobalSRSNameParam(xmlNodePtr psMainNode, - xmlNsPtr psNsOws, - mapObj* map) -{ -} - -/************************************************************************/ -/* msWFSConstraintDefaultValue */ -/************************************************************************/ - -static -xmlNodePtr msWFSConstraintDefaultValue(xmlNsPtr psNs, xmlNsPtr psNsOws, const char *name, const char* value) -{ - xmlNodePtr psRootNode = NULL; - - psRootNode = xmlNewNode(psNs, BAD_CAST "Constraint"); - - xmlNewProp(psRootNode, BAD_CAST "name", BAD_CAST name); - - xmlNewChild(psRootNode, psNsOws, BAD_CAST "NoValues", NULL ); - xmlNewTextChild(psRootNode, psNsOws, BAD_CAST "DefaultValue", BAD_CAST value); - - return psRootNode; -} - -/************************************************************************/ -/* msWFSOperator */ -/************************************************************************/ - -static -xmlNodePtr msWFSOperator(xmlNsPtr psNsFES, const char* pszOperatorType, const char* pszOperator) -{ - xmlNodePtr psNode = xmlNewNode(psNsFES, BAD_CAST pszOperatorType); - xmlNewProp(psNode, BAD_CAST "name", BAD_CAST pszOperator); - return psNode; -} - -/************************************************************************/ -/* msWFS20FilterCapabilities */ -/************************************************************************/ - -static -xmlNodePtr msWFS20FilterCapabilities(xmlNsPtr psNsFES, xmlNsPtr psNsOws, - int bImplementsSorting) -{ - xmlNodePtr psRootNode = NULL, psNode = NULL, psSubNode = NULL; - - psRootNode = xmlNewNode(psNsFES, BAD_CAST "Filter_Capabilities"); - - psNode = xmlNewChild(psRootNode, psNsFES, BAD_CAST "Conformance", NULL); - - xmlAddChild(psNode, msWFSConstraintDefaultValue(psNsFES, psNsOws, "ImplementsQuery", "TRUE")); - xmlAddChild(psNode, msWFSConstraintDefaultValue(psNsFES, psNsOws, "ImplementsAdHocQuery", "TRUE")); - xmlAddChild(psNode, msWFSConstraintDefaultValue(psNsFES, psNsOws, "ImplementsFunctions", "FALSE")); - xmlAddChild(psNode, msWFSConstraintDefaultValue(psNsFES, psNsOws, "ImplementsResourceId", "TRUE")); - xmlAddChild(psNode, msWFSConstraintDefaultValue(psNsFES, psNsOws, "ImplementsMinStandardFilter", "TRUE")); - xmlAddChild(psNode, msWFSConstraintDefaultValue(psNsFES, psNsOws, "ImplementsStandardFilter", "TRUE")); - xmlAddChild(psNode, msWFSConstraintDefaultValue(psNsFES, psNsOws, "ImplementsMinSpatialFilter", "TRUE")); - xmlAddChild(psNode, msWFSConstraintDefaultValue(psNsFES, psNsOws, "ImplementsSpatialFilter", "FALSE")); - xmlAddChild(psNode, msWFSConstraintDefaultValue(psNsFES, psNsOws, "ImplementsMinTemporalFilter", "TRUE")); - xmlAddChild(psNode, msWFSConstraintDefaultValue(psNsFES, psNsOws, "ImplementsTemporalFilter", "FALSE")); - xmlAddChild(psNode, msWFSConstraintDefaultValue(psNsFES, psNsOws, "ImplementsVersionNav", "FALSE")); - xmlAddChild(psNode, msWFSConstraintDefaultValue(psNsFES, psNsOws, "ImplementsSorting", ( bImplementsSorting ) ? "TRUE" : "FALSE")); - xmlAddChild(psNode, msWFSConstraintDefaultValue(psNsFES, psNsOws, "ImplementsExtendedOperators", "FALSE")); - xmlAddChild(psNode, msWFSConstraintDefaultValue(psNsFES, psNsOws, "ImplementsMinimumXPath", "TRUE")); - xmlAddChild(psNode, msWFSConstraintDefaultValue(psNsFES, psNsOws, "ImplementsSchemaElementFunc", "FALSE")); - - psNode = xmlNewChild(psRootNode, psNsFES, BAD_CAST "Id_Capabilities", NULL); - psSubNode = xmlNewChild(psNode, psNsFES, BAD_CAST "ResourceIdentifier", NULL ); - xmlNewProp(psSubNode, BAD_CAST "name", BAD_CAST "fes:ResourceId"); - - psNode = xmlNewChild(psRootNode, psNsFES, BAD_CAST "Scalar_Capabilities", NULL); - xmlNewChild(psNode, psNsFES, BAD_CAST "LogicalOperators", NULL); - psNode = xmlNewChild(psNode, psNsFES, BAD_CAST "ComparisonOperators", NULL); - xmlAddChild(psNode, msWFSOperator(psNsFES, "ComparisonOperator", "PropertyIsEqualTo")); - xmlAddChild(psNode, msWFSOperator(psNsFES, "ComparisonOperator", "PropertyIsNotEqualTo")); - xmlAddChild(psNode, msWFSOperator(psNsFES, "ComparisonOperator", "PropertyIsLessThan")); - xmlAddChild(psNode, msWFSOperator(psNsFES, "ComparisonOperator", "PropertyIsGreaterThan")); - xmlAddChild(psNode, msWFSOperator(psNsFES, "ComparisonOperator", "PropertyIsLessThanOrEqualTo")); - xmlAddChild(psNode, msWFSOperator(psNsFES, "ComparisonOperator", "PropertyIsGreaterThanOrEqualTo")); - xmlAddChild(psNode, msWFSOperator(psNsFES, "ComparisonOperator", "PropertyIsLike")); - xmlAddChild(psNode, msWFSOperator(psNsFES, "ComparisonOperator", "PropertyIsBetween")); - /* Missing: PropertyIsNull, PropertyIsNil */ - - psNode = xmlNewChild(psRootNode, psNsFES, BAD_CAST "Spatial_Capabilities", NULL); - - psSubNode = xmlNewChild(psNode, psNsFES, BAD_CAST "GeometryOperands", NULL); - xmlAddChild(psSubNode, msWFSOperator(psNsFES, "GeometryOperand", "gml:Point")); - xmlAddChild(psSubNode, msWFSOperator(psNsFES, "GeometryOperand", "gml:MultiPoint")); - xmlAddChild(psSubNode, msWFSOperator(psNsFES, "GeometryOperand", "gml:LineString")); - xmlAddChild(psSubNode, msWFSOperator(psNsFES, "GeometryOperand", "gml:MultiLineString")); - xmlAddChild(psSubNode, msWFSOperator(psNsFES, "GeometryOperand", "gml:Curve")); - xmlAddChild(psSubNode, msWFSOperator(psNsFES, "GeometryOperand", "gml:MultiCurve")); - xmlAddChild(psSubNode, msWFSOperator(psNsFES, "GeometryOperand", "gml:Polygon")); - xmlAddChild(psSubNode, msWFSOperator(psNsFES, "GeometryOperand", "gml:MultiPolygon")); - xmlAddChild(psSubNode, msWFSOperator(psNsFES, "GeometryOperand", "gml:Surface")); - xmlAddChild(psSubNode, msWFSOperator(psNsFES, "GeometryOperand", "gml:MultiSurface")); - /* xmlAddChild(psSubNode, msWFSOperator(psNsFES, "GeometryOperand", "gml:MultiGeometry")); */ - xmlAddChild(psSubNode, msWFSOperator(psNsFES, "GeometryOperand", "gml:Box")); - xmlAddChild(psSubNode, msWFSOperator(psNsFES, "GeometryOperand", "gml:Envelope")); - - psSubNode = xmlNewChild(psNode, psNsFES, BAD_CAST "SpatialOperators", NULL); -#ifdef USE_GEOS - xmlAddChild(psSubNode, msWFSOperator(psNsFES, "SpatialOperator", "Equals")); - xmlAddChild(psSubNode, msWFSOperator(psNsFES, "SpatialOperator", "Disjoint")); - xmlAddChild(psSubNode, msWFSOperator(psNsFES, "SpatialOperator", "Touches")); - xmlAddChild(psSubNode, msWFSOperator(psNsFES, "SpatialOperator", "Within")); - xmlAddChild(psSubNode, msWFSOperator(psNsFES, "SpatialOperator", "Overlaps")); - xmlAddChild(psSubNode, msWFSOperator(psNsFES, "SpatialOperator", "Crosses")); - xmlAddChild(psSubNode, msWFSOperator(psNsFES, "SpatialOperator", "Intersects")); - xmlAddChild(psSubNode, msWFSOperator(psNsFES, "SpatialOperator", "Contains")); - xmlAddChild(psSubNode, msWFSOperator(psNsFES, "SpatialOperator", "DWithin")); - xmlAddChild(psSubNode, msWFSOperator(psNsFES, "SpatialOperator", "Beyond")); -#endif - xmlAddChild(psSubNode, msWFSOperator(psNsFES, "SpatialOperator", "BBOX")); - - psNode = xmlNewChild(psRootNode, psNsFES, BAD_CAST "Temporal_Capabilities", NULL); - psSubNode = xmlNewChild(psNode, psNsFES, BAD_CAST "TemporalOperands", NULL); - xmlAddChild(psSubNode, msWFSOperator(psNsFES, "TemporalOperand", "gml:TimePeriod")); - xmlAddChild(psSubNode, msWFSOperator(psNsFES, "TemporalOperand", "gml:TimeInstant")); - - psSubNode = xmlNewChild(psNode, psNsFES, BAD_CAST "TemporalOperators", NULL); - xmlAddChild(psSubNode, msWFSOperator(psNsFES, "TemporalOperator", "During")); - - return psRootNode; -} - -/************************************************************************/ -/* msXMLStripIndentation */ -/************************************************************************/ - -static void msXMLStripIndentation(char* ptr) -{ - /* Remove spaces between > and < to get properly indented result */ - char* afterLastClosingBracket = NULL; - if( *ptr == ' ' ) - afterLastClosingBracket = ptr; - while( *ptr != '\0' ) - { - if( *ptr == '<' && afterLastClosingBracket != NULL ) - { - memmove(afterLastClosingBracket, ptr, strlen(ptr) + 1); - ptr = afterLastClosingBracket; - } - else if( *ptr == '>' ) - { - afterLastClosingBracket = ptr + 1; - } - else if( *ptr != ' ' && *ptr != '\n' ) - afterLastClosingBracket = NULL; - ptr ++; - } -} - -/************************************************************************/ -/* msWFSAddInspireDSID */ -/************************************************************************/ - -static void msWFSAddInspireDSID(mapObj *map, - xmlNsPtr psNsInspireDls, - xmlNsPtr psNsInspireCommon, - xmlNodePtr pDlsExtendedCapabilities) -{ - const char* dsid_code = msOWSLookupMetadata(&(map->web.metadata), "FO", "inspire_dsid_code"); - const char* dsid_ns = msOWSLookupMetadata(&(map->web.metadata), "FO", "inspire_dsid_ns"); - if( dsid_code == NULL ) - { - xmlAddChild(pDlsExtendedCapabilities, xmlNewComment(BAD_CAST "WARNING: Required metadata \"inspire_dsid_code\" missing")); - } - else - { - int ntokensCode = 0, ntokensNS = 0; - char** tokensCode; - char** tokensNS = NULL; - int i; - - tokensCode = msStringSplit(dsid_code, ',', &ntokensCode); - if( dsid_ns != NULL ) - tokensNS = msStringSplitComplex( dsid_ns, ",", &ntokensNS, MS_ALLOWEMPTYTOKENS); - if( ntokensNS > 0 && ntokensNS != ntokensCode ) - { - xmlAddChild(pDlsExtendedCapabilities, - xmlNewComment(BAD_CAST "WARNING: \"inspire_dsid_code\" and \"inspire_dsid_ns\" have not the same number of elements. Ignoring inspire_dsid_ns")); - msFreeCharArray(tokensNS, ntokensNS); - tokensNS = NULL; - ntokensNS = 0; - } - for(i = 0; i 0 && tokensNS[i][0] != '\0' ) - xmlNewTextChild(pSDSI, psNsInspireCommon, BAD_CAST "Namespace", BAD_CAST tokensNS[i]); - } - msFreeCharArray(tokensCode, ntokensCode); - if( ntokensNS > 0 ) - msFreeCharArray(tokensNS, ntokensNS); - } -} - - - -/************************************************************************/ -/* msWFSGetCapabilities20 */ -/* */ -/* Return the capabilities document for WFS 2.0.0 */ -/************************************************************************/ -int msWFSGetCapabilities20(mapObj *map, wfsParamsObj *params, - cgiRequestObj *req, owsRequestObj *ows_request) -{ - xmlDocPtr psDoc = NULL; /* document pointer */ - xmlNodePtr psRootNode, psMainNode, psNode, psFtNode = NULL; - const char *updatesequence=NULL; - xmlNsPtr psNsOws, psNsXLink; - xmlNsPtr psNsFES = NULL; - xmlNsPtr psNsInspireCommon = NULL; - xmlNsPtr psNsInspireDls = NULL; - xmlDocPtr pInspireTmpDoc = NULL; - char *xsi_schemaLocation = NULL; - const char *user_namespace_prefix = NULL; - const char *user_namespace_uri = NULL; - gmlNamespaceListObj *namespaceList=NULL; /* for external application schema support */ - - char *script_url=NULL, *formats_list; - const char *value = NULL; - - xmlChar *buffer = NULL; - int size = 0, i; - msIOContext *context = NULL; - - int ows_version = OWS_1_1_0; - int ret; - - char* validated_language; - int bImplementsSorting = MS_FALSE; - - /* -------------------------------------------------------------------- */ - /* Handle updatesequence */ - /* -------------------------------------------------------------------- */ - ret = msWFSHandleUpdateSequence(map, params, "msWFSGetCapabilities20()"); - if( ret != MS_SUCCESS ) - return ret; - - validated_language = msOWSGetLanguageFromList(map, "FO", params->pszLanguage); - - /* -------------------------------------------------------------------- */ - /* Create document. */ - /* -------------------------------------------------------------------- */ - psDoc = xmlNewDoc(BAD_CAST "1.0"); - - psRootNode = xmlNewNode(NULL, BAD_CAST "WFS_Capabilities"); - - xmlDocSetRootElement(psDoc, psRootNode); - - /* -------------------------------------------------------------------- */ - /* Name spaces */ - /* -------------------------------------------------------------------- */ - - /*default name space*/ - xmlNewProp(psRootNode, BAD_CAST "xmlns", BAD_CAST MS_OWSCOMMON_WFS_20_NAMESPACE_URI); - - xmlSetNs(psRootNode, xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_GML_32_NAMESPACE_URI, BAD_CAST MS_OWSCOMMON_GML_NAMESPACE_PREFIX)); - xmlSetNs(psRootNode, xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_WFS_20_NAMESPACE_URI, BAD_CAST MS_OWSCOMMON_WFS_NAMESPACE_PREFIX)); - - psNsOws = xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_OWS_110_NAMESPACE_URI, BAD_CAST MS_OWSCOMMON_OWS_NAMESPACE_PREFIX); - psNsXLink = xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_W3C_XLINK_NAMESPACE_URI, BAD_CAST MS_OWSCOMMON_W3C_XLINK_NAMESPACE_PREFIX); - xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_W3C_XSI_NAMESPACE_URI, BAD_CAST MS_OWSCOMMON_W3C_XSI_NAMESPACE_PREFIX); - xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_FES_20_NAMESPACE_URI, BAD_CAST MS_OWSCOMMON_FES_20_NAMESPACE_PREFIX ); - - value = msOWSLookupMetadata(&(map->web.metadata), "FO", "namespace_uri"); - if(value) - user_namespace_uri = value; - else - user_namespace_uri = MS_DEFAULT_NAMESPACE_URI; - - value = msOWSLookupMetadata(&(map->web.metadata), "FO", "namespace_prefix"); - if(value) - user_namespace_prefix = value; - else - user_namespace_prefix = MS_DEFAULT_NAMESPACE_PREFIX; - - if(user_namespace_prefix != NULL && msIsXMLTagValid(user_namespace_prefix) == MS_FALSE) - msIO_printf("\n", user_namespace_prefix); - else - xmlNewNs(psRootNode, BAD_CAST user_namespace_uri, BAD_CAST user_namespace_prefix); - - /* any additional namespaces */ - namespaceList = msGMLGetNamespaces(&(map->web), "G"); - for(i=0; inumnamespaces; i++) { - if(namespaceList->namespaces[i].uri) { - xmlNewNs(psRootNode, BAD_CAST namespaceList->namespaces[i].uri, BAD_CAST namespaceList->namespaces[i].prefix); - } - } - msGMLFreeNamespaces(namespaceList); - - if ( msOWSLookupMetadata(&(map->web.metadata), "FO", "inspire_capabilities") ) { - psNsInspireCommon = xmlNewNs(psRootNode, BAD_CAST MS_INSPIRE_COMMON_NAMESPACE_URI, BAD_CAST MS_INSPIRE_COMMON_NAMESPACE_PREFIX); - psNsInspireDls = xmlNewNs(psRootNode, BAD_CAST MS_INSPIRE_DLS_NAMESPACE_URI, BAD_CAST MS_INSPIRE_DLS_NAMESPACE_PREFIX); - } - - xmlNewProp(psRootNode, BAD_CAST "version", BAD_CAST params->pszVersion ); - - updatesequence = msOWSLookupMetadata(&(map->web.metadata), "FO", "updatesequence"); - - if (updatesequence) - xmlNewProp(psRootNode, BAD_CAST "updateSequence", BAD_CAST updatesequence); - - /*schema*/ - xsi_schemaLocation = msStrdup(MS_OWSCOMMON_WFS_20_NAMESPACE_URI); - xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, " "); - xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, msOWSGetSchemasLocation(map)); - xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, MS_OWSCOMMON_WFS_20_SCHEMA_LOCATION); - - if( psNsInspireDls != NULL ) - { - xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, " "); - xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, MS_INSPIRE_DLS_NAMESPACE_URI); - xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, " "); - xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, msOWSGetInspireSchemasLocation(map)); - xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, MS_INSPIRE_DLS_SCHEMA_LOCATION); - xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, " "); - xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, MS_INSPIRE_COMMON_NAMESPACE_URI); - xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, " "); - xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, msOWSGetInspireSchemasLocation(map)); - xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, MS_INSPIRE_COMMON_SCHEMA_LOCATION); - } - - xmlNewNsProp(psRootNode, NULL, BAD_CAST "xsi:schemaLocation", BAD_CAST xsi_schemaLocation); - free(xsi_schemaLocation); - - /* -------------------------------------------------------------------- */ - /* Service metadata. */ - /* -------------------------------------------------------------------- */ - - /* TODO? : also add 1.1.0 and 1.0.0 as extra . The OWS */ - /* schema would suggest to do so, and also the example */ - /* http://schemas.opengis.net/wfs/2.0/examples/GetCapabilities/GetCapabilities_Res_01.xml */ - /* and Deegree too, but GeoServer also only lists the current version. */ - if( msWFSIncludeSection(params, "ServiceIdentification") ) - { - xmlAddChild(psRootNode, - msOWSCommonServiceIdentification(psNsOws, map, "WFS", - params->pszVersion, "FO", validated_language)); - } - - /*service provider*/ - if( msWFSIncludeSection(params, "ServiceProvider") ) - { - xmlAddChild(psRootNode, msOWSCommonServiceProvider( - psNsOws, psNsXLink, map, "FO", validated_language)); - } - - /*operation metadata */ - if( msWFSIncludeSection(params, "OperationsMetadata") ) - { - if ((script_url=msOWSGetOnlineResource2(map, "FO", "onlineresource", req, validated_language)) == NULL) { - msSetError(MS_WFSERR, "Server URL not found", "msWFSGetCapabilities20()"); - return msWFSException11(map, "mapserv", MS_OWS_ERROR_NO_APPLICABLE_CODE, params->pszVersion); - } - - - /* -------------------------------------------------------------------- */ - /* Operations metadata. */ - /* -------------------------------------------------------------------- */ - psMainNode= xmlAddChild(psRootNode,msOWSCommonOperationsMetadata(psNsOws)); - - /* -------------------------------------------------------------------- */ - /* GetCapabilities */ - /* -------------------------------------------------------------------- */ - psNode = xmlAddChild(psMainNode, - msOWSCommonOperationsMetadataOperation(psNsOws,psNsXLink,"GetCapabilities", - OWS_METHOD_GETPOST, script_url)); - - xmlAddChild(psMainNode, psNode); - - /*accept version*/ - xmlAddChild(psNode, msOWSCommonOperationsMetadataDomainType(ows_version, psNsOws, - "Parameter", "AcceptVersions", - "2.0.0,1.1.0,1.0.0")); - /*format*/ - xmlAddChild(psNode, msOWSCommonOperationsMetadataDomainType(ows_version, psNsOws, - "Parameter", "AcceptFormats", - "text/xml")); - /*sections*/ - xmlAddChild(psNode, msOWSCommonOperationsMetadataDomainType(ows_version, psNsOws, - "Parameter", "Sections", - "ServiceIdentification,ServiceProvider,OperationsMetadata,FeatureTypeList,Filter_Capabilities")); - - /* -------------------------------------------------------------------- */ - /* DescribeFeatureType */ - /* -------------------------------------------------------------------- */ - if (msOWSRequestIsEnabled(map, NULL, "F", "DescribeFeatureType", MS_TRUE)) { - psNode = xmlAddChild(psMainNode, - msOWSCommonOperationsMetadataOperation(psNsOws,psNsXLink,"DescribeFeatureType", - OWS_METHOD_GETPOST, script_url)); - xmlAddChild(psMainNode, psNode); - - /*output format*/ - xmlAddChild(psNode, msOWSCommonOperationsMetadataDomainType(ows_version, psNsOws, - "Parameter", "outputFormat", - "application/gml+xml; version=3.2," - "text/xml; subtype=gml/3.2.1," - "text/xml; subtype=gml/3.1.1," - "text/xml; subtype=gml/2.1.2")); - } - - /* -------------------------------------------------------------------- */ - /* GetFeature */ - /* -------------------------------------------------------------------- */ - if (msOWSRequestIsEnabled(map, NULL, "F", "GetFeature", MS_TRUE)) { - - psNode = xmlAddChild(psMainNode, - msOWSCommonOperationsMetadataOperation(psNsOws,psNsXLink,"GetFeature", - OWS_METHOD_GETPOST, script_url)); - xmlAddChild(psMainNode, psNode); - - formats_list = msWFSGetOutputFormatList( map, NULL, OWS_2_0_0 ); - xmlAddChild(psNode, msOWSCommonOperationsMetadataDomainType(ows_version, psNsOws, - "Parameter", "outputFormat", - formats_list)); - msFree( formats_list ); - } - - /* -------------------------------------------------------------------- */ - /* GetPropertyValue */ - /* -------------------------------------------------------------------- */ - if (msOWSRequestIsEnabled(map, NULL, "F", "GetPropertyValue", MS_TRUE)) { - - psNode = xmlAddChild(psMainNode, - msOWSCommonOperationsMetadataOperation(psNsOws,psNsXLink,"GetPropertyValue", - OWS_METHOD_GETPOST, script_url)); - xmlAddChild(psMainNode, psNode); - - /* Only advertize built-in GML formats for GetPropertyValue. Not sure */ - /* it makes sense to advertize OGR formats. */ - xmlAddChild(psNode, msOWSCommonOperationsMetadataDomainType(ows_version, psNsOws, - "Parameter", "outputFormat", - "application/gml+xml; version=3.2," - "text/xml; subtype=gml/3.2.1," - "text/xml; subtype=gml/3.1.1," - "text/xml; subtype=gml/2.1.2")); - } - - /* -------------------------------------------------------------------- */ - /* ListStoredQueries */ - /* -------------------------------------------------------------------- */ - if (msOWSRequestIsEnabled(map, NULL, "F", "ListStoredQueries", MS_TRUE)) { - - psNode = xmlAddChild(psMainNode, - msOWSCommonOperationsMetadataOperation(psNsOws,psNsXLink,"ListStoredQueries", - OWS_METHOD_GETPOST, script_url)); - xmlAddChild(psMainNode, psNode); - } - - /* -------------------------------------------------------------------- */ - /* DescribeStoredQueries */ - /* -------------------------------------------------------------------- */ - if (msOWSRequestIsEnabled(map, NULL, "F", "DescribeStoredQueries", MS_TRUE)) { - - psNode = xmlAddChild(psMainNode, - msOWSCommonOperationsMetadataOperation(psNsOws,psNsXLink,"DescribeStoredQueries", - OWS_METHOD_GETPOST, script_url)); - xmlAddChild(psMainNode, psNode); - } - - xmlAddChild(psMainNode, msOWSCommonOperationsMetadataDomainType(ows_version, psNsOws, - "Parameter", "version", - "2.0.0,1.1.0,1.0.0")); - - msWFSAddGlobalSRSNameParam(psMainNode, psNsOws, map); - - /* Conformance declaration */ - xmlAddChild(psMainNode, msWFSConstraintDefaultValue(psNsOws, psNsOws, "ImplementsBasicWFS", "TRUE")); - xmlAddChild(psMainNode, msWFSConstraintDefaultValue(psNsOws, psNsOws, "ImplementsTransactionalWFS", "FALSE")); - xmlAddChild(psMainNode, msWFSConstraintDefaultValue(psNsOws, psNsOws, "ImplementsLockingWFS", "FALSE")); - xmlAddChild(psMainNode, msWFSConstraintDefaultValue(psNsOws, psNsOws, "KVPEncoding", "TRUE")); - xmlAddChild(psMainNode, msWFSConstraintDefaultValue(psNsOws, psNsOws, "XMLEncoding", "TRUE")); - xmlAddChild(psMainNode, msWFSConstraintDefaultValue(psNsOws, psNsOws, "SOAPEncoding", "FALSE")); - xmlAddChild(psMainNode, msWFSConstraintDefaultValue(psNsOws, psNsOws, "ImplementsInheritance", "FALSE")); - xmlAddChild(psMainNode, msWFSConstraintDefaultValue(psNsOws, psNsOws, "ImplementsRemoteResolve", "FALSE")); - xmlAddChild(psMainNode, msWFSConstraintDefaultValue(psNsOws, psNsOws, "ImplementsResultPaging", "TRUE")); - xmlAddChild(psMainNode, msWFSConstraintDefaultValue(psNsOws, psNsOws, "ImplementsStandardJoins", "FALSE")); - xmlAddChild(psMainNode, msWFSConstraintDefaultValue(psNsOws, psNsOws, "ImplementsSpatialJoins", "FALSE")); - xmlAddChild(psMainNode, msWFSConstraintDefaultValue(psNsOws, psNsOws, "ImplementsTemporalJoins", "FALSE")); - xmlAddChild(psMainNode, msWFSConstraintDefaultValue(psNsOws, psNsOws, "ImplementsFeatureVersioning", "FALSE")); - xmlAddChild(psMainNode, msWFSConstraintDefaultValue(psNsOws, psNsOws, "ManageStoredQueries", "FALSE")); - - /* Capacity declaration */ - xmlAddChild(psMainNode, msWFSConstraintDefaultValue(psNsOws, psNsOws, "PagingIsTransactionSafe", "FALSE")); - - value = msOWSLookupMetadata(&(map->web.metadata), "FO", "maxfeatures"); - if (value) { - xmlAddChild(psMainNode, msWFSConstraintDefaultValue(psNsOws, psNsOws, "CountDefault", value)); - } - - xmlAddChild(psMainNode, msOWSCommonOperationsMetadataDomainType(ows_version, psNsOws, - "Constraint", "QueryExpressions","wfs:Query,wfs:StoredQuery")); - - /* Add Inspire Download Services extended capabilities */ - if( psNsInspireDls != NULL ) - { - msIOContext* old_context; - msIOContext* new_context; - msIOBuffer* buffer; - xmlNodePtr pRoot; - xmlNodePtr pOWSExtendedCapabilities; - xmlNodePtr pDlsExtendedCapabilities; - xmlNodePtr pChild; - - old_context = msIO_pushStdoutToBufferAndGetOldContext(); - msOWSPrintInspireCommonExtendedCapabilities(stdout, map, "FO", OWS_WARN, - "foo", - "xmlns:" MS_INSPIRE_COMMON_NAMESPACE_PREFIX "=\"" MS_INSPIRE_COMMON_NAMESPACE_URI "\" " - "xmlns:" MS_INSPIRE_DLS_NAMESPACE_PREFIX "=\"" MS_INSPIRE_DLS_NAMESPACE_URI "\" " - "xmlns:xsi=\"" MS_OWSCOMMON_W3C_XSI_NAMESPACE_URI "\"", validated_language, OWS_WFS); - - new_context = msIO_getHandler(stdout); - buffer = (msIOBuffer *) new_context->cbData; - - /* Remove spaces between > and < to get properly indented result */ - msXMLStripIndentation( (char*) buffer->data ); - - pInspireTmpDoc = xmlParseDoc((const xmlChar *)buffer->data); - pRoot = xmlDocGetRootElement(pInspireTmpDoc); - xmlReconciliateNs(psDoc, pRoot); - - pOWSExtendedCapabilities = xmlNewNode(psNsOws, BAD_CAST "ExtendedCapabilities"); - xmlAddChild(psMainNode, pOWSExtendedCapabilities); - - pDlsExtendedCapabilities = xmlNewNode(psNsInspireDls, BAD_CAST "ExtendedCapabilities"); - xmlAddChild(pOWSExtendedCapabilities, pDlsExtendedCapabilities); - - pChild = pRoot->children; - while(pChild != NULL) - { - xmlNodePtr pNext = pChild->next; - xmlUnlinkNode(pChild); - xmlAddChild(pDlsExtendedCapabilities, pChild); - pChild = pNext; - } - - msWFSAddInspireDSID(map, psNsInspireDls, psNsInspireCommon, pDlsExtendedCapabilities); - - msIO_restoreOldStdoutContext(old_context); - } - } - - /* -------------------------------------------------------------------- */ - /* FeatureTypeList */ - /* -------------------------------------------------------------------- */ - if( msWFSIncludeSection(params, "FeatureTypeList") ) - { - psFtNode = xmlNewNode(NULL, BAD_CAST "FeatureTypeList"); - xmlAddChild(psRootNode, psFtNode); - } - - for(i=0; inumlayers; i++) { - layerObj *lp; - lp = GET_LAYER(map, i); - - if (!msIntegerInArray(lp->index, ows_request->enabled_layers, ows_request->numlayers)) - continue; - - /* List only vector layers in which DUMP=TRUE */ - if (msWFSIsLayerSupported(lp)) - { - if( psFtNode != NULL ) { - xmlAddChild(psFtNode, msWFSDumpLayer11(map, lp, psNsOws, OWS_2_0_0, validated_language, script_url)); - } - - /* As soon as at least one layer supports sorting, advertize sorting */ - if( msLayerSupportsSorting(lp) ) - bImplementsSorting = MS_TRUE; - } - } - - /* -------------------------------------------------------------------- */ - /* Filter capabilities. */ - /* -------------------------------------------------------------------- */ - if( msWFSIncludeSection(params, "Filter_Capabilities") ) - { - psNsFES = xmlNewNs(NULL, BAD_CAST MS_OWSCOMMON_FES_20_NAMESPACE_URI, BAD_CAST MS_OWSCOMMON_FES_20_NAMESPACE_PREFIX); - xmlAddChild(psRootNode, msWFS20FilterCapabilities(psNsFES, psNsOws, bImplementsSorting)); - } - - /* -------------------------------------------------------------------- */ - /* Write out the document. */ - /* -------------------------------------------------------------------- */ - - if( msIO_needBinaryStdout() == MS_FAILURE ) - return MS_FAILURE; - - msIO_setHeader("Content-Type","text/xml; charset=UTF-8"); - msIO_sendHeaders(); - - context = msIO_getHandler(stdout); - - xmlDocDumpFormatMemoryEnc(psDoc, &buffer, &size, ("UTF-8"), 1); - msIO_contextWrite(context, buffer, size); - xmlFree(buffer); - - /*free buffer and the document */ - /*xmlFree(buffer);*/ - xmlFreeDoc(psDoc); - if( psNsFES != NULL ) - xmlFreeNs(psNsFES); - if( pInspireTmpDoc != NULL ) - xmlFreeDoc(pInspireTmpDoc); - - free(script_url); - msFree(validated_language); - - xmlCleanupParser(); - - return(MS_SUCCESS); -} - -/************************************************************************/ -/* msWFSGetStoredQueries */ -/* */ -/* Result must be freed with msFreeCharArray() */ -/************************************************************************/ - -static char** msWFSGetStoredQueries(mapObj *map, int* pn) -{ - const char* value; - char** tokens; - int i,n; - - value = msOWSLookupMetadata(&(map->web.metadata), "F", "storedqueries"); - if( value != NULL ) - { - tokens = msStringSplit(value, ',', &n); - for(i=0;iweb.metadata), "F", szKey); - if( value != NULL ) - return msStrdup(value); - - snprintf(szKey, sizeof(szKey), "%s_filedef", pszURN); - value = msOWSLookupMetadata(&(map->web.metadata), "F", szKey); - if( value != NULL ) - { - FILE* f = fopen(value, "rb"); - if( f != NULL ) - { - char* pszBuffer; - int nread; - long length; - - fseek(f, 0, SEEK_END); - length = ftell(f); - if( length > 1000000 ) - { - msSetError(MS_WFSERR, "%s: too big (%ld bytes > 1000000)", - "msWFSGetStoredQuery()", value, length); - fclose(f); - } - else - { - fseek(f, 0, SEEK_SET); - pszBuffer = (char*) malloc((int)length + 1); - if( pszBuffer == NULL ) - { - msSetError(MS_WFSERR, "Cannot allocate %d bytes to read %s", - "msWFSGetStoredQuery()", - (int)length + 1, value); - fclose(f); - } - else - { - nread = (int)fread(pszBuffer, 1, length, f); - fclose(f); - if( nread == length ) - { - pszBuffer[nread] = '\0'; - return pszBuffer; - } - msSetError(MS_WFSERR, "Could only read %d bytes / %d of %s", - "msWFSGetStoredQuery()", - nread, (int)length, value); - msFree(pszBuffer); - } - } - } - else - { - msSetError(MS_WFSERR, "Cannot open %s", "msWFSGetStoredQuery()", value); - } - } - - if( strcasecmp(pszURN, URN_GET_FEATURE_BY_ID) == 0 ) - return msStrdup(GET_FEATURE_BY_ID); - return NULL; -} - -/************************************************************************/ -/* msWFSGetResolvedStoredQuery20 */ -/* */ -/* Result must be freed with msFree() */ -/************************************************************************/ - -char* msWFSGetResolvedStoredQuery20(mapObj *map, - wfsParamsObj *wfsparams, - const char* id, - hashTableObj* hashTable) -{ - char* storedQuery; - xmlDocPtr psStoredQueryDoc; - xmlNodePtr psStoredQueryRoot, pChild; - - storedQuery = msWFSGetStoredQuery(map, id); - if( storedQuery == NULL ) - { - msSetError(MS_WFSERR, "Unknown stored query id: %s", "msWFSGetResolvedStoredQuery20()", - id); - msWFSException(map, "storedqueryid", MS_OWS_ERROR_INVALID_PARAMETER_VALUE, wfsparams->pszVersion); - return NULL; - } - - psStoredQueryDoc = xmlParseDoc((const xmlChar*) storedQuery); - if( psStoredQueryDoc == NULL ) - { - msSetError(MS_WFSERR, "Definition for stored query '%s' is invalid", "msWFSGetResolvedStoredQuery20()", id); - msWFSException(map, "mapserv", MS_OWS_ERROR_NO_APPLICABLE_CODE, wfsparams->pszVersion); - msFree(storedQuery); - return NULL; - } - - psStoredQueryRoot = xmlDocGetRootElement(psStoredQueryDoc); - - /* Check that all parameters are provided */ - pChild = psStoredQueryRoot->children; - while(pChild != NULL) - { - if( pChild->type == XML_ELEMENT_NODE && - strcmp((const char*) pChild->name, "Parameter") == 0 ) - { - xmlChar* parameterName = xmlGetProp(pChild, BAD_CAST "name"); - if( parameterName != NULL ) - { - char szTmp[256]; - const char* value = msLookupHashTable(hashTable, (const char*)parameterName); - if( value == NULL ) - { - msSetError(MS_WFSERR, "Stored query '%s' requires parameter '%s'", "msWFSParseRequest()", - id, (const char*)parameterName); - msWFSException(map, (const char*)parameterName, MS_OWS_ERROR_MISSING_PARAMETER_VALUE, wfsparams->pszVersion); - msFree(storedQuery); - xmlFree(parameterName); - xmlFreeDoc(psStoredQueryDoc); - return NULL; - } - - snprintf(szTmp, sizeof(szTmp), "${%s}", (const char*)parameterName); - storedQuery = msReplaceSubstring(storedQuery, szTmp, value); - } - xmlFree(parameterName); - } - pChild = pChild->next; - } - - xmlFreeDoc(psStoredQueryDoc); - - return storedQuery; -} - -/************************************************************************/ -/* msWFSListStoredQueries20 */ -/************************************************************************/ - -int msWFSListStoredQueries20(mapObj *map, wfsParamsObj *params, - cgiRequestObj *req, owsRequestObj *ows_request) -{ - xmlDocPtr psDoc; - xmlChar *buffer = NULL; - int size = 0; - msIOContext *context = NULL; - xmlNodePtr psRootNode; - char *xsi_schemaLocation = NULL; - int i, j; - int nStoredQueries = 0; - char** storedQueries = NULL; - - xmlDocPtr psStoredQueryDoc; - xmlNodePtr psStoredQueryRoot; - - /* -------------------------------------------------------------------- */ - /* Create document. */ - /* -------------------------------------------------------------------- */ - psDoc = xmlNewDoc(BAD_CAST "1.0"); - - psRootNode = xmlNewNode(NULL, BAD_CAST "ListStoredQueriesResponse"); - - xmlDocSetRootElement(psDoc, psRootNode); - - /* -------------------------------------------------------------------- */ - /* Name spaces */ - /* -------------------------------------------------------------------- */ - - /*default name space*/ - xmlNewProp(psRootNode, BAD_CAST "xmlns", BAD_CAST MS_OWSCOMMON_WFS_20_NAMESPACE_URI); - - xmlSetNs(psRootNode, xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_WFS_20_NAMESPACE_URI, BAD_CAST MS_OWSCOMMON_WFS_NAMESPACE_PREFIX)); - - xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_W3C_XSI_NAMESPACE_URI, BAD_CAST MS_OWSCOMMON_W3C_XSI_NAMESPACE_PREFIX); - - /*schema*/ - xsi_schemaLocation = msStrdup(MS_OWSCOMMON_WFS_20_NAMESPACE_URI); - xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, " "); - xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, msOWSGetSchemasLocation(map)); - xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, MS_OWSCOMMON_WFS_20_SCHEMA_LOCATION); - - xmlNewNsProp(psRootNode, NULL, BAD_CAST "xsi:schemaLocation", BAD_CAST xsi_schemaLocation); - free(xsi_schemaLocation); - - /* -------------------------------------------------------------------- */ - /* Add queries */ - /* -------------------------------------------------------------------- */ - - storedQueries = msWFSGetStoredQueries(map, &nStoredQueries); - for(i = 0; i < nStoredQueries; i++) - { - char* query = msWFSGetStoredQuery(map, storedQueries[i]); - if( query != NULL ) - { - xmlNodePtr pChild; - xmlNodePtr psStoredQuery; - - psStoredQueryDoc = xmlParseDoc((const xmlChar*) query); - if( psStoredQueryDoc == NULL ) - { - char szMsg[256]; - msFree(query); - snprintf(szMsg, sizeof(szMsg), "WARNING: Definition for stored query %s is invalid", storedQueries[i]); - xmlAddChild(psRootNode, xmlNewComment(BAD_CAST szMsg)); - continue; - } - - psStoredQueryRoot = xmlDocGetRootElement(psStoredQueryDoc); - - psStoredQuery = xmlNewNode(NULL, BAD_CAST "StoredQuery" ); - xmlNewProp(psStoredQuery, BAD_CAST "id", BAD_CAST storedQueries[i]); - xmlAddChild(psRootNode, psStoredQuery); - - pChild = psStoredQueryRoot->children; - while(pChild != NULL) - { - xmlNodePtr pNext = pChild->next; - if( pChild->type == XML_ELEMENT_NODE && - strcmp((const char*) pChild->name, "Title") == 0 ) - { - xmlUnlinkNode(pChild); - xmlAddChild(psStoredQuery, pChild); - } - else if( pChild->type == XML_ELEMENT_NODE && - strcmp((const char*) pChild->name, "QueryExpressionText") == 0 ) - { - xmlNodePtr psReturnFeatureType; - - if( strcasecmp( storedQueries[i], URN_GET_FEATURE_BY_ID ) == 0 ) - { - for(j=0; jnumlayers; j++) { - layerObj *lp; - const char *user_namespace_prefix = MS_DEFAULT_NAMESPACE_PREFIX; - const char *user_namespace_uri = MS_DEFAULT_NAMESPACE_URI; - const char *value; - char szValue[256]; - - lp = GET_LAYER(map, j); - - if (!msIntegerInArray(lp->index, ows_request->enabled_layers, ows_request->numlayers) || - !msWFSIsLayerSupported(lp)) - continue; - - - value = msOWSLookupMetadata(&(map->web.metadata), "FO", "namespace_uri"); - if(value) user_namespace_uri = value; - - value = msOWSLookupMetadata(&(map->web.metadata), "FO", "namespace_prefix"); - if(value) user_namespace_prefix = value; - - psReturnFeatureType = xmlNewNode(NULL, BAD_CAST "ReturnFeatureType" ); - xmlNewNs(psReturnFeatureType, BAD_CAST user_namespace_uri, BAD_CAST user_namespace_prefix); - - xmlAddChild(psStoredQuery, psReturnFeatureType); - snprintf(szValue, sizeof(szValue), "%s:%s", user_namespace_prefix, lp->name); - xmlAddChild(psReturnFeatureType, xmlNewText( BAD_CAST szValue )); - } - } - else - { - xmlChar* returnFeatureTypes = xmlGetProp(pChild, BAD_CAST "returnFeatureTypes"); - if( returnFeatureTypes != NULL && strlen((const char*)returnFeatureTypes) > 0 ) - { - int ntypes; - char** types = msStringSplit((const char*)returnFeatureTypes, ' ', &ntypes); - for(j=0; jpszStoredQueryId != NULL ) { - storedQueries = msStringSplit(params->pszStoredQueryId,',',&nStoredQueries); - for(i = 0; i < nStoredQueries; i++) - { - char* query = msWFSGetStoredQuery(map, storedQueries[i]); - if( query == NULL ) - { - msSetError(MS_WFSERR, "Unknown stored query id: %s", "msWFSDescribeStoredQueries20()", - storedQueries[i]); - msFreeCharArray(storedQueries, nStoredQueries); - return msWFSException(map, "storedqueryid", MS_OWS_ERROR_INVALID_PARAMETER_VALUE, params->pszVersion); - } - msFree(query); - } - } else { - storedQueries = msWFSGetStoredQueries(map, &nStoredQueries); - } - - /* -------------------------------------------------------------------- */ - /* Create document. */ - /* -------------------------------------------------------------------- */ - psDoc = xmlNewDoc(BAD_CAST "1.0"); - - psRootNode = xmlNewNode(NULL, BAD_CAST "DescribeStoredQueriesResponse"); - - xmlDocSetRootElement(psDoc, psRootNode); - - /* -------------------------------------------------------------------- */ - /* Name spaces */ - /* -------------------------------------------------------------------- */ - - /*default name space*/ - xmlNewProp(psRootNode, BAD_CAST "xmlns", BAD_CAST MS_OWSCOMMON_WFS_20_NAMESPACE_URI); - - xmlSetNs(psRootNode, xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_WFS_20_NAMESPACE_URI, BAD_CAST MS_OWSCOMMON_WFS_NAMESPACE_PREFIX)); - - xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_W3C_XSI_NAMESPACE_URI, BAD_CAST MS_OWSCOMMON_W3C_XSI_NAMESPACE_PREFIX); - - /*schema*/ - xsi_schemaLocation = msStrdup(MS_OWSCOMMON_WFS_20_NAMESPACE_URI); - xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, " "); - xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, msOWSGetSchemasLocation(map)); - xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, MS_OWSCOMMON_WFS_20_SCHEMA_LOCATION); - - xmlNewNsProp(psRootNode, NULL, BAD_CAST "xsi:schemaLocation", BAD_CAST xsi_schemaLocation); - free(xsi_schemaLocation); - - /* -------------------------------------------------------------------- */ - /* Add queries */ - /* -------------------------------------------------------------------- */ - - for(i = 0; i < nStoredQueries; i++) - { - char* query = msWFSGetStoredQuery(map, storedQueries[i]); - if( query != NULL ) - { - xmlNodePtr pChild; - xmlNs* ns; - xmlNodePtr psStoredQuery; - - psStoredQueryDoc = xmlParseDoc((const xmlChar*) query); - if( psStoredQueryDoc == NULL ) - { - char szMsg[256]; - msFree(query); - snprintf(szMsg, sizeof(szMsg), "WARNING: Definition for stored query %s is invalid", storedQueries[i]); - xmlAddChild(psRootNode, xmlNewComment(BAD_CAST szMsg)); - continue; - } - - psStoredQueryRoot = xmlDocGetRootElement(psStoredQueryDoc); - - psStoredQuery = xmlNewNode(NULL, BAD_CAST "StoredQueryDescription" ); - xmlNewProp(psStoredQuery, BAD_CAST "id", BAD_CAST storedQueries[i]); - xmlAddChild(psRootNode, psStoredQuery); - - ns = psStoredQueryRoot->nsDef; - while( ns != NULL ) { - xmlNewNs(psStoredQuery, BAD_CAST ns->href, BAD_CAST ns->prefix); - ns = ns->next; - } - - pChild = psStoredQueryRoot->children; - while(pChild != NULL) - { - xmlNodePtr pNext = pChild->next; - - if( pChild->type == XML_ELEMENT_NODE && - strcmp((const char*) pChild->name, "QueryExpressionText") == 0 ) - { - if( strcasecmp( storedQueries[i], URN_GET_FEATURE_BY_ID ) == 0 ) - { - char** arrayNsPrefix = (char**) malloc( sizeof(char*) * map->numlayers ); - char** arrayNsUri = (char**) malloc( sizeof(char*) * map->numlayers ); - int arraysize = 0; - int k; - char* returnFeatureTypes = NULL; - xmlNodePtr psQueryExpressionText; - - psQueryExpressionText = xmlNewNode(NULL, BAD_CAST "QueryExpressionText" ); - xmlAddChild(psStoredQuery, psQueryExpressionText); - xmlNewProp(psQueryExpressionText, BAD_CAST "isPrivate", BAD_CAST "true"); - xmlNewProp(psQueryExpressionText, BAD_CAST "language", BAD_CAST "urn:ogc:def:queryLanguage:OGC-WFS::WFS_QueryExpression"); - - for(j=0; jnumlayers; j++) { - layerObj *lp; - const char *user_namespace_prefix = MS_DEFAULT_NAMESPACE_PREFIX; - const char *user_namespace_uri = MS_DEFAULT_NAMESPACE_URI; - const char *value; - char szValue[256]; - - lp = GET_LAYER(map, j); - - if (!msIntegerInArray(lp->index, ows_request->enabled_layers, ows_request->numlayers) || - !msWFSIsLayerSupported(lp)) - continue; - - value = msOWSLookupMetadata(&(map->web.metadata), "FO", "namespace_uri"); - if(value) user_namespace_uri = value; - - value = msOWSLookupMetadata(&(map->web.metadata), "FO", "namespace_prefix"); - if(value) user_namespace_prefix = value; - - for(k=0;kname); - returnFeatureTypes = msStringConcatenate(returnFeatureTypes, szValue); - } - - xmlNewProp(psQueryExpressionText, BAD_CAST "returnFeatureTypes", BAD_CAST returnFeatureTypes); - - msFree(returnFeatureTypes); - msFreeCharArray(arrayNsPrefix, arraysize); - msFreeCharArray(arrayNsUri, arraysize); - } - else - { - xmlChar* isPrivate = xmlGetProp(pChild, BAD_CAST "isPrivate"); - if( isPrivate != NULL && strcmp((const char*)isPrivate, "true") == 0) { - xmlNodePtr pSubChild = xmlFirstElementChild(pChild); - xmlUnlinkNode(pSubChild); - xmlFreeNode(pSubChild); - } - xmlUnlinkNode(pChild); - xmlAddChild(psStoredQuery, pChild); - msFree(isPrivate); - } - } - else { - xmlUnlinkNode(pChild); - xmlAddChild(psStoredQuery, pChild); - } - pChild = pNext; - } - - xmlReconciliateNs(psDoc, psStoredQuery); - xmlFreeDoc(psStoredQueryDoc); - msFree(query); - } - else - { - char szMsg[256]; - snprintf(szMsg, sizeof(szMsg), "WARNING: Definition for stored query %s missing", storedQueries[i]); - xmlAddChild(psRootNode, xmlNewComment(BAD_CAST szMsg)); - } - } - msFreeCharArray(storedQueries, nStoredQueries); - - /* -------------------------------------------------------------------- */ - /* Write out the document. */ - /* -------------------------------------------------------------------- */ - - if( msIO_needBinaryStdout() == MS_FAILURE ) - return MS_FAILURE; - - msIO_setHeader("Content-Type","text/xml; charset=UTF-8"); - msIO_sendHeaders(); - - context = msIO_getHandler(stdout); - - xmlDocDumpFormatMemoryEnc(psDoc, &buffer, &size, ("UTF-8"), 1); - msIO_contextWrite(context, buffer, size); - xmlFree(buffer); - - /*free buffer and the document */ - /*xmlFree(buffer);*/ - xmlFreeDoc(psDoc); - - xmlCleanupParser(); - - return(MS_SUCCESS); -} - -#endif /* defined(USE_WFS_SVR) && defined(USE_LIBXML2) */ - -#if defined(USE_WFS_SVR) && !defined(USE_LIBXML2) - -int msWFSException20(mapObj *map, const char *locator, - const char *exceptionCode) -{ - /* fallback to reporting using 1.0 style exceptions. */ - return msWFSException( map, locator, exceptionCode, "1.0.0" ); -} - -int msWFSGetCapabilities20(mapObj *map, wfsParamsObj *params, - cgiRequestObj *req, owsRequestObj *ows_request) - -{ - msSetError( MS_WFSERR, - "WFS 2.0 request made, but mapserver requires libxml2 for WFS 2.0 services and this is not configured.", - "msWFSGetCapabilities20()" ); - - return msWFSException11(map, "mapserv", MS_OWS_ERROR_NO_APPLICABLE_CODE, params->pszVersion); -} - -int msWFSListStoredQueries20(mapObj *map, wfsParamsObj *params, - cgiRequestObj *req, owsRequestObj *ows_request) -{ - msSetError( MS_WFSERR, - "WFS 2.0 request made, but mapserver requires libxml2 for WFS 2.0 services and this is not configured.", - "msWFSListStoredQueries20()"); - - return msWFSException11(map, "mapserv", MS_OWS_ERROR_NO_APPLICABLE_CODE, params->pszVersion); -} - -int msWFSDescribeStoredQueries20(mapObj *map, wfsParamsObj *params, - cgiRequestObj *req, owsRequestObj *ows_request) -{ - msSetError( MS_WFSERR, - "WFS 2.0 request made, but mapserver requires libxml2 for WFS 2.0 services and this is not configured.", - "msWFSDescribeStoredQueries20()" ); - - return msWFSException11(map, "mapserv", MS_OWS_ERROR_NO_APPLICABLE_CODE, params->pszVersion); -} - -char* msWFSGetResolvedStoredQuery20(mapObj *map, - wfsParamsObj *params, - const char* id, - hashTableObj* hashTable) -{ - msSetError( MS_WFSERR, - "WFS 2.0 request made, but mapserver requires libxml2 for WFS 2.0 services and this is not configured.", - "msWFSGetResolvedStoredQuery20()" ); - - msWFSException11(map, "mapserv", MS_OWS_ERROR_NO_APPLICABLE_CODE, params->pszVersion); - return NULL; -} - -#endif /* defined(USE_WFS_SVR) && !defined(USE_LIBXML2) */ diff --git a/mapwfslayer.c b/mapwfslayer.c deleted file mode 100644 index e5db8c7887..0000000000 --- a/mapwfslayer.c +++ /dev/null @@ -1,1296 +0,0 @@ -/********************************************************************** - * $Id$ - * - * Project: MapServer - * Purpose: Implementation of WFS CONNECTIONTYPE - client to WFS servers - * Author: Daniel Morissette, DM Solutions Group (morissette@dmsolutions.ca) - * - ********************************************************************** - * Copyright (c) 2002, Daniel Morissette, DM Solutions Group Inc - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies of this Software or works derived from this Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - ****************************************************************************/ - -#include "mapserver.h" -#include "maperror.h" -#include "mapows.h" -#include "mapproject.h" - -#include -#include - -#if defined(_WIN32) && !defined(__CYGWIN__) -#include -#endif - - - -#define WFS_V_0_0_14 14 -#define WFS_V_1_0_0 100 - - -/*==================================================================== - * Private (static) functions - *====================================================================*/ - -#ifdef USE_WFS_LYR - -/************************************************************************/ -/* msBuildRequestParms */ -/* */ -/* Build the params object based on the metadata */ -/* information. This object will be used when building the Get */ -/* and Post requsests. */ -/* Note : Verify the connection string to extract some values */ -/* for backward compatiblity. (It is though depricated). */ -/* This will also set layer projection and compute BBOX in that */ -/* projection. */ -/* */ -/************************************************************************/ -static wfsParamsObj *msBuildRequestParams(mapObj *map, layerObj *lp, - rectObj *bbox_ret) -{ - wfsParamsObj *psParams = NULL; - rectObj bbox; - const char *pszTmp; - int nLength, i = 0; - char *pszVersion, *pszTypeName; - - if (!map || !lp || !bbox_ret) - return NULL; - - if (lp->connection == NULL) - return NULL; - - psParams = msWFSCreateParamsObj(); - pszTmp = msOWSLookupMetadata(&(lp->metadata), "FO", "version"); - if (pszTmp) - psParams->pszVersion = msStrdup(pszTmp); - else { - pszTmp = strstr(lp->connection, "VERSION="); - if (!pszTmp) - pszTmp = strstr(lp->connection, "version="); - if (pszTmp) { - pszVersion = strchr(pszTmp, '=')+1; - if (strncmp(pszVersion, "0.0.14", 6) == 0) - psParams->pszVersion = msStrdup("0.0.14"); - else if (strncmp(pszVersion, "1.0.0", 5) == 0) - psParams->pszVersion = msStrdup("1.0.0"); - } - } - - /*the service is always set to WFS : see bug 1302 */ - psParams->pszService = msStrdup("WFS"); - - /* - pszTmp = msOWSLookupMetadata(&(lp->metadata), "FO", "service"); - if (pszTmp) - psParams->pszService = msStrdup(pszTmp); - else - { - pszTmp = strstr(lp->connection, "SERVICE="); - if (!pszTmp) - pszTmp = strstr(lp->connection, "service="); - if (pszTmp) - { - pszService = strchr(pszTmp, '=')+1; - if (strncmp(pszService, "WFS", 3) == 0) - psParams->pszService = msStrdup("WFS"); - } - } - */ - - pszTmp = msOWSLookupMetadata(&(lp->metadata), "FO", "geometryname"); - if (pszTmp) - psParams->pszGeometryName = msStrdup(pszTmp); - - pszTmp = msOWSLookupMetadata(&(lp->metadata), "FO", "typename"); - if (pszTmp) - psParams->pszTypeName = msStrdup(pszTmp); - else { - pszTmp = strstr(lp->connection, "TYPENAME="); - if (!pszTmp) - pszTmp = strstr(lp->connection, "typename="); - if (pszTmp) { - pszTypeName = strchr(pszTmp, '=')+1; - if (pszTypeName) { - nLength = strlen(pszTypeName); - if (nLength > 0) { - for (i=0; ipszTypeName = msStrdup(pszTypeNameTmp); - free(pszTypeNameTmp); - } else - psParams->pszTypeName = msStrdup(pszTypeName); - } - } - } - } - - pszTmp = msOWSLookupMetadata(&(lp->metadata), "FO", "filter"); - if (pszTmp && strlen(pszTmp) > 0) { - if (strstr(pszTmp, "") !=NULL || strstr(pszTmp, "pszFilter = msStrdup(pszTmp); - else { - psParams->pszFilter = msStringConcatenate(psParams->pszFilter, ""); - psParams->pszFilter = msStringConcatenate(psParams->pszFilter, (char*)pszTmp); - psParams->pszFilter = msStringConcatenate(psParams->pszFilter, ""); - } - } - - pszTmp = msOWSLookupMetadata(&(lp->metadata), "FO", "maxfeatures"); - if (pszTmp) - psParams->nMaxFeatures = atoi(pszTmp); - - /* Request is always GetFeature; */ - psParams->pszRequest = msStrdup("GetFeature"); - - - /* ------------------------------------------------------------------ - * Figure the SRS we'll use for the request. - * - Fetch the map SRS (if it's EPSG) - * - Check if map SRS is listed in layer wfs_srs metadata - * - If map SRS is valid for this layer then use it - * - Otherwise request layer in its default SRS and we'll reproject later - * ------------------------------------------------------------------ */ - - /* __TODO__ WFS servers support only one SRS... need to decide how we'll */ - /* handle this and document it well. */ - /* It's likely that we'll simply reproject the BBOX to teh layer's projection. */ - - /* ------------------------------------------------------------------ - * Set layer SRS and reproject map extents to the layer's SRS - * ------------------------------------------------------------------ */ -#ifdef __TODO__ - /* No need to set lp->proj if it's already set to the right EPSG code */ - if ((pszTmp = msGetEPSGProj(&(lp->projection), NULL, MS_TRUE)) == NULL || - strcasecmp(pszEPSG, pszTmp) != 0) { - char szProj[20]; - snprintf(szProj, sizeof(szProj), "init=epsg:%s", pszEPSG+5); - if (msLoadProjectionString(&(lp->projection), szProj) != 0) - return NULL; - } -#endif - - bbox = map->extent; - if (msProjectionsDiffer(&(map->projection), &(lp->projection))) { - msProjectRect(&(map->projection), &(lp->projection), &bbox); - } - - if (bbox_ret != NULL) - *bbox_ret = bbox; - - return psParams; - -} - -/********************************************************************** - * msBuildWFSLayerPostRequest() - * - * Build a WFS GetFeature xml document for a Post Request. - * - * Returns a reference to a newly allocated string that should be freed - * by the caller. - **********************************************************************/ -static char *msBuildWFSLayerPostRequest(mapObj *map, layerObj *lp, - rectObj *bbox, wfsParamsObj *psParams) -{ - char *pszPostReq = NULL; - char *pszFilter = NULL; - char *pszGeometryName = "Geometry"; - size_t bufferSize = 0; - - if (psParams->pszVersion == NULL || - (strncmp(psParams->pszVersion, "0.0.14", 6) != 0 && - strncmp(psParams->pszVersion, "1.0.0", 5)) != 0) { - msSetError(MS_WFSCONNERR, "MapServer supports only WFS 1.0.0 or 0.0.14 (please verify the version metadata wfs_version).", "msBuildWFSLayerPostRequest()"); - return NULL; - } - - - - if (psParams->pszTypeName == NULL) { - msSetError(MS_WFSCONNERR, "Metadata wfs_typename must be set in the layer", "msBuildWFSLayerPostRequest()"); - return NULL; - } - - - if (psParams->pszGeometryName) { - pszGeometryName = psParams->pszGeometryName; - } - - if (psParams->pszFilter) - pszFilter = psParams->pszFilter; - else { - bufferSize = 500; - pszFilter = (char *)msSmallMalloc(bufferSize); - snprintf(pszFilter, bufferSize, "\n" - "\n" - "%s\n" - "\n" - "%f,%f %f,%f\n" - "\n" - "\n" - "", pszGeometryName, bbox->minx, bbox->miny, bbox->maxx, bbox->maxy); - } - - bufferSize = strlen(pszFilter)+strlen(psParams->pszTypeName)+500; - pszPostReq = (char *)msSmallMalloc(bufferSize); - if (psParams->nMaxFeatures > 0) - snprintf(pszPostReq, bufferSize, "\n" - "\n" - "\n" - "%s" - "\n" - "\n", psParams->nMaxFeatures, psParams->pszTypeName, pszFilter); - else - snprintf(pszPostReq, bufferSize, "\n" - "\n" - "\n" - "%s" - "\n" - "\n", psParams->pszTypeName, pszFilter); - if (psParams->pszFilter == NULL) - free(pszFilter); - - - return pszPostReq; -} - -/********************************************************************** - * msBuildWFSLayerGetURL() - * - * Build a WFS GetFeature URL for a Get Request. - * - * Returns a reference to a newly allocated string that should be freed - * by the caller. - **********************************************************************/ -static char *msBuildWFSLayerGetURL(mapObj *map, layerObj *lp, rectObj *bbox, - wfsParamsObj *psParams) -{ - char *pszURL = NULL, *pszOnlineResource=NULL; - const char *pszTmp; - char *pszVersion, *pszService, *pszTypename = NULL; - int bVersionInConnection = 0, bServiceInConnection = 0; - int bTypenameInConnection = 0; - size_t bufferSize = 0; - - if (lp->connectiontype != MS_WFS || lp->connection == NULL) { - msSetError(MS_WFSCONNERR, "Call supported only for CONNECTIONTYPE WFS", - "msBuildWFSLayerGetURL()"); - return NULL; - } - - /* -------------------------------------------------------------------- */ - /* Find out request version. Look first for the wfs_version */ - /* metedata. If not available try to find out if the CONNECTION */ - /* string contains the version. This last test is done for */ - /* backward compatiblity but is depericated. */ - /* -------------------------------------------------------------------- */ - pszVersion = psParams->pszVersion; - if (!pszVersion) { - if ((pszTmp = strstr(lp->connection, "VERSION=")) == NULL && - (pszTmp = strstr(lp->connection, "version=")) == NULL ) { - msSetError(MS_WFSCONNERR, "Metadata wfs_version must be set in the layer", "msBuildWFSLayerGetURL()"); - return NULL; - } - pszVersion = strchr(pszTmp, '=')+1; - bVersionInConnection = 1; - } - - - if (strncmp(pszVersion, "0.0.14", 6) != 0 && - strncmp(pszVersion, "1.0.0", 5) != 0 && - strncmp(pszVersion, "1.1", 3) != 0) { - msSetError(MS_WFSCONNERR, "MapServer supports only WFS 1.0.0 or 0.0.14 (please verify the version metadata wfs_version).", "msBuildWFSLayerGetURL()"); - return NULL; - } - - /* -------------------------------------------------------------------- */ - /* Find out the service. It is always set to WFS in function */ - /* msBuildRequestParms (check Bug 1302 for details). */ - /* -------------------------------------------------------------------- */ - pszService = psParams->pszService; - - - /* -------------------------------------------------------------------- */ - /* Find out the typename. Look first for the wfs_tyename */ - /* metadata. If not available try to find out if the CONNECTION */ - /* string contains it. This last test is done for */ - /* backward compatiblity but is depericated. */ - /* -------------------------------------------------------------------- */ - pszTypename = psParams->pszTypeName; - if (!pszTypename) { - if ((pszTmp = strstr(lp->connection, "TYPENAME=")) == NULL && - (pszTmp = strstr(lp->connection, "typename=")) == NULL ) { - msSetError(MS_WFSCONNERR, "Metadata wfs_typename must be set in the layer", "msBuildWFSLayerGetURL()"); - return NULL; - } - bTypenameInConnection = 1; - } - - - /* -------------------------------------------------------------------- - * Build the request URL. - * At this point we set only the following parameters for GetFeature: - * REQUEST - * BBOX - * VERSION - * SERVICE - * TYPENAME - * FILTER - * MAXFEATURES - * - * For backward compatiblity the user could also have in the connection - * string the following parameters (but it is depricated): - * VERSION - * SERVICE - * TYPENAME - * -------------------------------------------------------------------- */ - /* Make sure we have a big enough buffer for the URL */ - bufferSize = strlen(lp->connection)+1024; - pszURL = (char *)malloc(bufferSize); - MS_CHECK_ALLOC(pszURL, bufferSize, NULL); - - /* __TODO__ We have to urlencode each value... especially the BBOX values */ - /* because if they end up in exponent format (123e+06) the + will be seen */ - /* as a space by the remote server. */ - - /* -------------------------------------------------------------------- */ - /* build the URL, */ - /* -------------------------------------------------------------------- */ - /* make sure connection ends with "&" or "?" */ - pszOnlineResource = msOWSTerminateOnlineResource(lp->connection); - snprintf(pszURL, bufferSize, "%s", pszOnlineResource); - msFree(pszOnlineResource); - - /* REQUEST */ - snprintf(pszURL + strlen(pszURL), bufferSize-strlen(pszURL), "&REQUEST=GetFeature"); - - /* VERSION */ - if (!bVersionInConnection) - snprintf(pszURL + strlen(pszURL), bufferSize-strlen(pszURL), "&VERSION=%s", pszVersion); - - /* SERVICE */ - if (!bServiceInConnection) - snprintf(pszURL + strlen(pszURL), bufferSize-strlen(pszURL), "&SERVICE=%s", pszService); - - /* TYPENAME */ - if (!bTypenameInConnection) - snprintf(pszURL + strlen(pszURL), bufferSize-strlen(pszURL), "&TYPENAME=%s", pszTypename); - - /* -------------------------------------------------------------------- */ - /* If the filter parameter is given in the wfs_filter metadata, */ - /* we use it and do not send the BBOX paramter as they are */ - /* mutually exclusive. */ - /* -------------------------------------------------------------------- */ - if (psParams->pszFilter) { - char *encoded_filter = msEncodeUrl(psParams->pszFilter); - snprintf(pszURL + strlen(pszURL), bufferSize-strlen(pszURL), "&FILTER=%s",encoded_filter); - free(encoded_filter); - } else { - /* - * take care about the axis order for WFS 1.1 - */ - char *projUrn; - char *projEpsg; - projUrn = msOWSGetProjURN(&(lp->projection), &(lp->metadata), "FO", 1); - msOWSGetEPSGProj(&(lp->projection), &(lp->metadata), "FO", 1, &projEpsg); - - /* - * WFS 1.1 supports including the SRS in the BBOX parameter, should - * respect axis order in the BBOX and has a separate SRSNAME parameter for - * the desired result SRS. - * WFS 1.0 is always easting, northing, doesn't include the SRS as part of - * the BBOX parameter and has no SRSNAME parameter: if we don't have a - * URN then fallback to WFS 1.0 style */ - if ((strncmp(pszVersion, "1.1", 3) == 0) && projUrn) { - if (projEpsg && (strncmp(projEpsg, "EPSG:", 5) == 0) && - msIsAxisInverted(atoi(projEpsg + 5))) { - snprintf(pszURL + strlen(pszURL), bufferSize - strlen(pszURL), - "&BBOX=%.15g,%.15g,%.15g,%.15g,%s&SRSNAME=%s", - bbox->miny, bbox->minx, bbox->maxy, bbox->maxx, - projUrn, projUrn); - } else { - snprintf(pszURL + strlen(pszURL), bufferSize - strlen(pszURL), - "&BBOX=%.15g,%.15g,%.15g,%.15g,%s&SRSNAME=%s", - bbox->minx, bbox->miny, bbox->maxx, bbox->maxy, - projUrn, projUrn); - } - } else { - snprintf(pszURL + strlen(pszURL), bufferSize - strlen(pszURL), - "&BBOX=%.15g,%.15g,%.15g,%.15g", - bbox->minx, bbox->miny, bbox->maxx, bbox->maxy); - } - - msFree(projUrn); - msFree(projEpsg); - } - - if (psParams->nMaxFeatures > 0) - snprintf(pszURL + strlen(pszURL), bufferSize-strlen(pszURL), - "&MAXFEATURES=%d", psParams->nMaxFeatures); - - return pszURL; - -} - -/********************************************************************** - * msWFSLayerInfo - * - **********************************************************************/ -typedef struct ms_wfs_layer_info_t { - char *pszGMLFilename; - rectObj rect; /* set by WhichShapes */ - char *pszGetUrl; - int nStatus; /* HTTP status */ - int bLayerHasValidGML; /* False until msWFSLayerWhichShapes() is called and determines the result GML is valid with features*/ -} msWFSLayerInfo; - - -/********************************************************************** - * msAllocWFSLayerInfo() - * - **********************************************************************/ -static msWFSLayerInfo *msAllocWFSLayerInfo(void) -{ - msWFSLayerInfo *psInfo; - - psInfo = (msWFSLayerInfo*)calloc(1,sizeof(msWFSLayerInfo)); - MS_CHECK_ALLOC(psInfo, sizeof(msWFSLayerInfo), NULL); - - psInfo->pszGMLFilename = NULL; - psInfo->rect.minx = psInfo->rect.maxx = 0; - psInfo->rect.miny = psInfo->rect.maxy = 0; - psInfo->pszGetUrl = NULL; - psInfo->nStatus = 0; - - return psInfo; -} - -/********************************************************************** - * msFreeWFSLayerInfo() - * - **********************************************************************/ -static void msFreeWFSLayerInfo(msWFSLayerInfo *psInfo) -{ - if (psInfo) { - if (psInfo->pszGMLFilename) - free(psInfo->pszGMLFilename); - if (psInfo->pszGetUrl) - free(psInfo->pszGetUrl); - - free(psInfo); - } -} - -#endif /* USE_WFS_LYR */ - -/*==================================================================== - * Public functions - *====================================================================*/ - -/********************************************************************** - * msPrepareWFSLayerRequest() - * - **********************************************************************/ - -int msPrepareWFSLayerRequest(int nLayerId, mapObj *map, layerObj *lp, - httpRequestObj *pasReqInfo, int *numRequests) -{ -#ifdef USE_WFS_LYR - char *pszURL = NULL; - const char *pszTmp; - rectObj bbox; - int nTimeout; - int nStatus = MS_SUCCESS; - msWFSLayerInfo *psInfo = NULL; - int bPostRequest = 0; - wfsParamsObj *psParams = NULL; - char *pszHTTPCookieData = NULL; - - - if (lp->connectiontype != MS_WFS || lp->connection == NULL) - return MS_FAILURE; - - /* ------------------------------------------------------------------ - * Build a params object that will be used by to build the request, - this will also set layer projection and compute BBOX in that projection. - * ------------------------------------------------------------------ */ - psParams = msBuildRequestParams(map, lp, &bbox); - if (!psParams) - return MS_FAILURE; - - /* -------------------------------------------------------------------- */ - /* Depending on the metadata wfs_request_method, build a Get or */ - /* a Post URL. */ - /* If it is a Get request the URL would contain all the parameters in*/ - /* the string; */ - /* If it is a Post request, the URL will only contain the */ - /* connection string comming from the layer. */ - /* -------------------------------------------------------------------- */ - if ((pszTmp = msOWSLookupMetadata(&(lp->metadata), - "FO", "request_method")) != NULL) { - if (strncmp(pszTmp, "GET", 3) ==0) { - pszURL = msBuildWFSLayerGetURL(map, lp, &bbox, psParams); - if (!pszURL) { - /* an error was already reported. */ - return MS_FAILURE; - } - } - } - /* else it is a post request and just get the connection string */ - if (!pszURL) { - bPostRequest = 1; - pszURL = msStrdup(lp->connection); - } - - /* ------------------------------------------------------------------ - * check to see if a the metadata wfs_connectiontimeout is set. If it is - * the case we will use it, else we use the default which is 30 seconds. - * First check the metadata in the layer object and then in the map object. - * ------------------------------------------------------------------ */ - nTimeout = 30; /* Default is 30 seconds */ - if ((pszTmp = msOWSLookupMetadata2(&(lp->metadata), &(map->web.metadata), - "FO", "connectiontimeout")) != NULL) { - nTimeout = atoi(pszTmp); - } - - /*------------------------------------------------------------------ - * Check to see if there's a HTTP Cookie to forward - * If Cookie differ between the two connection, it's NOT OK to merge - * the connection - * ------------------------------------------------------------------ */ - if ((pszTmp = msOWSLookupMetadata(&(lp->metadata), - "FO", "http_cookie")) != NULL) { - if(strcasecmp(pszTmp, "forward") == 0) { - pszTmp= msLookupHashTable(&(map->web.metadata),"http_cookie_data"); - if(pszTmp != NULL) { - pszHTTPCookieData = msStrdup(pszTmp); - } - } else { - pszHTTPCookieData = msStrdup(pszTmp); - } - } else if ((pszTmp = msOWSLookupMetadata(&(map->web.metadata), - "FO", "http_cookie")) != NULL) { - if(strcasecmp(pszTmp, "forward") == 0) { - pszTmp= msLookupHashTable(&(map->web.metadata),"http_cookie_data"); - if(pszTmp != NULL) { - pszHTTPCookieData = msStrdup(pszTmp); - } - } else { - pszHTTPCookieData = msStrdup(pszTmp); - } - } - - /* ------------------------------------------------------------------ - * If nLayerId == -1 then we need to figure it - * ------------------------------------------------------------------ */ - if (nLayerId == -1) { - int iLayer; - for(iLayer=0; iLayer < map->numlayers; iLayer++) { - if (GET_LAYER(map, iLayer) == lp) { - nLayerId = iLayer; - break; - } - } - } - - /* ------------------------------------------------------------------ - * Add a request to the array (already preallocated) - * ------------------------------------------------------------------ */ - pasReqInfo[(*numRequests)].nLayerId = nLayerId; - pasReqInfo[(*numRequests)].pszGetUrl = pszURL; - - if (bPostRequest) { - pasReqInfo[(*numRequests)].pszPostRequest = - msBuildWFSLayerPostRequest(map, lp, &bbox, psParams); - pasReqInfo[(*numRequests)].pszPostContentType = - msStrdup("text/xml"); - } - - - /* We'll store the remote server's response to a tmp file. */ - pasReqInfo[(*numRequests)].pszOutputFile = msTmpFile(map, map->mappath, NULL, "tmp.gml"); - - /* TODO: Implement Caching of GML responses. There was an older caching - * method, but it suffered from a race condition. See #3137. - */ - - pasReqInfo[(*numRequests)].pszHTTPCookieData = pszHTTPCookieData; - pszHTTPCookieData = NULL; - pasReqInfo[(*numRequests)].nStatus = 0; - pasReqInfo[(*numRequests)].nTimeout = nTimeout; - pasReqInfo[(*numRequests)].bbox = bbox; - pasReqInfo[(*numRequests)].debug = lp->debug; - - if (msHTTPAuthProxySetup(&(map->web.metadata), &(lp->metadata), - pasReqInfo, *numRequests, map, "FO") != MS_SUCCESS) { - if (psParams) { - msWFSFreeParamsObj(psParams); - } - return MS_FAILURE; - } - - /* ------------------------------------------------------------------ - * Pre-Open the layer now, (i.e. alloc and fill msWFSLayerInfo inside - * layer obj). Layer will be ready for use when the main mapserver - * code calls msLayerOpen(). - * ------------------------------------------------------------------ */ - if (lp->wfslayerinfo != NULL) { - psInfo =(msWFSLayerInfo*)(lp->wfslayerinfo); - } else { - lp->wfslayerinfo = psInfo = msAllocWFSLayerInfo(); - } - - if (psInfo->pszGMLFilename) - free(psInfo->pszGMLFilename); - psInfo->pszGMLFilename=msStrdup(pasReqInfo[(*numRequests)].pszOutputFile); - - psInfo->rect = pasReqInfo[(*numRequests)].bbox; - - if (psInfo->pszGetUrl) - free(psInfo->pszGetUrl); - psInfo->pszGetUrl = msStrdup(pasReqInfo[(*numRequests)].pszGetUrl); - - psInfo->nStatus = 0; - - (*numRequests)++; - - if (psParams) { - msWFSFreeParamsObj(psParams); - } - return nStatus; - -#else - /* ------------------------------------------------------------------ - * WFS CONNECTION Support not included... - * ------------------------------------------------------------------ */ - msSetError(MS_WFSCONNERR, "WFS CLIENT CONNECTION support is not available.", - "msPrepareWFSLayerRequest"); - return(MS_FAILURE); - -#endif /* USE_WFS_LYR */ - -} - -/********************************************************************** - * msWFSUpdateRequestInfo() - * - * This function is called after a WFS request has been completed so that - * we can copy request result information from the httpRequestObj to the - * msWFSLayerInfo struct. Things to copy here are the HTTP status, exceptions - * information, mime type, etc. - **********************************************************************/ -void msWFSUpdateRequestInfo(layerObj *lp, httpRequestObj *pasReqInfo) -{ -#ifdef USE_WFS_LYR - if (lp->wfslayerinfo) { - msWFSLayerInfo *psInfo = NULL; - - psInfo =(msWFSLayerInfo*)(lp->wfslayerinfo); - - /* Copy request results infos to msWFSLayerInfo struct */ - /* For now there is only nStatus, but we should eventually add */ - /* mime type and WFS exceptions information. */ - psInfo->nStatus = pasReqInfo->nStatus; - } -#else - /* ------------------------------------------------------------------ - * WFS CONNECTION Support not included... - * ------------------------------------------------------------------ */ - msSetError(MS_WFSCONNERR, "WFS CLIENT CONNECTION support is not available.", - "msWFSUpdateRequestInfo()"); -#endif /* USE_WFS_LYR */ -} - -/********************************************************************** - * msWFSLayerOpen() - * - * WFS layers are just a special case of OGR connection. Only the open/close - * methods differ since they have to download and maintain GML files in cache - * but the rest is mapped directly to OGR function calls in maplayer.c - * - **********************************************************************/ - -int msWFSLayerOpen(layerObj *lp, - const char *pszGMLFilename, rectObj *defaultBBOX) -{ -#ifdef USE_WFS_LYR - int status = MS_SUCCESS; - msWFSLayerInfo *psInfo = NULL; - - if ( msCheckParentPointer(lp->map,"map")==MS_FAILURE ) - return MS_FAILURE; - - if (lp->wfslayerinfo != NULL) { - psInfo =(msWFSLayerInfo*)lp->wfslayerinfo; - - /* Layer already opened. If explicit filename requested then check */ - /* that file was already opened with the same filename. */ - /* If no explicit filename requested then we'll try to reuse the */ - /* previously opened layer... this will happen in a msDrawMap() call. */ - if (pszGMLFilename == NULL || - (psInfo->pszGMLFilename && pszGMLFilename && - strcmp(psInfo->pszGMLFilename, pszGMLFilename) == 0) ) { - if (lp->layerinfo == NULL) { - if (msWFSLayerWhichShapes(lp, psInfo->rect, MS_FALSE) == MS_FAILURE) /* no access to context (draw vs. query) here, although I doubt it matters... */ - return MS_FAILURE; - } - return MS_SUCCESS; /* Nothing to do... layer is already opened */ - } else { - /* Hmmm... should we produce a fatal error? */ - /* For now we'll just close the layer and reopen it. */ - if (lp->debug) - msDebug("msWFSLayerOpen(): Layer already opened (%s)\n", - lp->name?lp->name:"(null)" ); - msWFSLayerClose(lp); - } - } - - /* ------------------------------------------------------------------ - * Alloc and fill msWFSLayerInfo inside layer obj - * ------------------------------------------------------------------ */ - lp->wfslayerinfo = psInfo = msAllocWFSLayerInfo(); - - if (pszGMLFilename) - psInfo->pszGMLFilename = msStrdup(pszGMLFilename); - else { - psInfo->pszGMLFilename = msTmpFile(lp->map, - lp->map->mappath, - NULL, - "tmp.gml"); - } - - if (defaultBBOX) { - /* __TODO__ If new bbox differs from current one then we should */ - /* invalidate current GML file in cache */ - psInfo->rect = *defaultBBOX; - } else { - /* Use map bbox by default */ - psInfo->rect = lp->map->extent; - } - - /* We will call whichshapes() now and force downloading layer right */ - /* away. This saves from having to call DescribeFeatureType and */ - /* parsing the response (being lazy I guess) and anyway given the */ - /* way we work with layers right now the bbox is unlikely to change */ - /* between now and the time whichshapes() would have been called by */ - /* the MapServer core. */ - - if((lp->map->projection.numargs > 0) && (lp->projection.numargs > 0)) - msProjectRect(&lp->map->projection, &lp->projection, &psInfo->rect); /* project the searchrect to source coords */ - - if (msWFSLayerWhichShapes(lp, psInfo->rect, MS_FALSE) == MS_FAILURE) /* no access to context (draw vs. query) here, although I doubt it matters... */ - status = MS_FAILURE; - - - return status; -#else - /* ------------------------------------------------------------------ - * WFS CONNECTION Support not included... - * ------------------------------------------------------------------ */ - msSetError(MS_WFSCONNERR, "WFS CLIENT CONNECTION support is not available.", - "msWFSLayerOpen()"); - return(MS_FAILURE); - -#endif /* USE_WFS_LYR */ -} - -/********************************************************************** - * msWFSLayerOpenVT() - * - * Overloaded version of msWFSLayerOpen for virtual table architecture - **********************************************************************/ -int -msWFSLayerOpenVT(layerObj *lp) -{ - return msWFSLayerOpen(lp, NULL, NULL); -} - -/********************************************************************** - * msWFSLayerIsOpen() - * - * Returns MS_TRUE if layer is already open, MS_FALSE otherwise. - * - **********************************************************************/ - -int msWFSLayerIsOpen(layerObj *lp) -{ -#ifdef USE_WFS_LYR - if (lp->wfslayerinfo != NULL) - return MS_TRUE; - - return MS_FALSE; -#else - /* ------------------------------------------------------------------ - * WFS CONNECTION Support not included... - * ------------------------------------------------------------------ */ - msSetError(MS_WFSCONNERR, "WFS CLIENT CONNECTION support is not available.", - "msWFSLayerIsOpen()"); - return(MS_FALSE); - -#endif /* USE_WFS_LYR */ -} - -/********************************************************************** - * msWFSLayerInitItemInfo() - * - **********************************************************************/ - -int msWFSLayerInitItemInfo(layerObj *layer) -{ - /* Nothing to do here. OGR will do its own initialization when it */ - /* opens the actual file. */ - /* Note that we didn't implement our own msWFSLayerFreeItemInfo() */ - /* so that the OGR one gets called. */ - return MS_SUCCESS; -} - -/********************************************************************** - * msWFSLayerGetShape() - * - **********************************************************************/ -int msWFSLayerGetShape(layerObj *layer, shapeObj *shape, resultObj *record) -{ -#ifdef USE_WFS_LYR - msWFSLayerInfo* psInfo = NULL; - - if(layer != NULL && layer->wfslayerinfo != NULL) - psInfo = (msWFSLayerInfo*)layer->wfslayerinfo; - else { - msSetError(MS_WFSERR, "Layer is not opened.", "msWFSLayerGetShape()"); - return MS_FAILURE; - } - - if(psInfo->bLayerHasValidGML) - return msOGRLayerGetShape(layer, shape, record); - else { - /* Layer is successful, but there is no data to process */ - msFreeShape(shape); - shape->type = MS_SHAPE_NULL; - return MS_FAILURE; - } -#else - /* ------------------------------------------------------------------ - * WFS CONNECTION Support not included... - * ------------------------------------------------------------------ */ - msSetError(MS_WFSCONNERR, "WFS CLIENT CONNECTION support is not available.", - "msWFSLayerGetShape()"); - return(MS_FAILURE); -#endif /* USE_WFS_LYR */ - -} - -/********************************************************************** - * msWFSLayerGetNextShape() - * - **********************************************************************/ -int msWFSLayerNextShape(layerObj *layer, shapeObj *shape) -{ -#ifdef USE_WFS_LYR - msWFSLayerInfo* psInfo = NULL; - - if(layer != NULL && layer->wfslayerinfo != NULL) - psInfo = (msWFSLayerInfo*)layer->wfslayerinfo; - else { - msSetError(MS_WFSERR, "Layer is not opened.", "msWFSLayerNextShape()"); - return MS_FAILURE; - } - - if(psInfo->bLayerHasValidGML) - return msOGRLayerNextShape(layer, shape); - else { - /* Layer is successful, but there is no data to process */ - msFreeShape(shape); - shape->type = MS_SHAPE_NULL; - return MS_FAILURE; - } -#else - /* ------------------------------------------------------------------ - * WFS CONNECTION Support not included... - * ------------------------------------------------------------------ */ - msSetError(MS_WFSCONNERR, "WFS CLIENT CONNECTION support is not available.", - "msWFSLayerNextShape()"); - return(MS_FAILURE); -#endif /* USE_WFS_LYR */ - -} - -/********************************************************************** - * msWFSLayerGetExtent() - * - **********************************************************************/ -int msWFSLayerGetExtent(layerObj *layer, rectObj *extent) -{ -#ifdef USE_WFS_LYR - msWFSLayerInfo* psInfo = NULL; - - if(layer != NULL && layer->wfslayerinfo != NULL) - psInfo = (msWFSLayerInfo*)layer->wfslayerinfo; - else { - msSetError(MS_WFSERR, "Layer is not opened.", "msWFSLayerGetExtent()"); - return MS_FAILURE; - } - - if(psInfo->bLayerHasValidGML) - return msOGRLayerGetExtent(layer, extent); - else { - /* Layer is successful, but there is no data to process */ - msSetError(MS_WFSERR, "Unable to get extents for this layer.", "msWFSLayerGetExtent()"); - return MS_FAILURE; - } -#else - /* ------------------------------------------------------------------ - * WFS CONNECTION Support not included... - * ------------------------------------------------------------------ */ - msSetError(MS_WFSCONNERR, "WFS CLIENT CONNECTION support is not available.", - "msWFSLayerGetExtent()"); - return(MS_FAILURE); -#endif /* USE_WFS_LYR */ - -} - -/********************************************************************** - * msWFSLayerGetItems() - * - **********************************************************************/ - -int msWFSLayerGetItems(layerObj *layer) -{ -#ifdef USE_WFS_LYR - /* For now this method simply lets OGR parse the GML and figure the */ - /* schema itself. */ - /* It could also be implemented to call DescribeFeatureType for */ - /* this layer, but we don't need to do it so why waste resources? */ - - msWFSLayerInfo* psInfo = NULL; - - if(layer != NULL && layer->wfslayerinfo != NULL) - psInfo = (msWFSLayerInfo*)layer->wfslayerinfo; - else { - msSetError(MS_WFSERR, "Layer is not opened.", "msWFSLayerGetItems()"); - return MS_FAILURE; - } - - if(psInfo->bLayerHasValidGML) - return msOGRLayerGetItems(layer); - else { - /* Layer is successful, but there is no data to process */ - layer->numitems = 0; - layer->items = NULL; - return MS_SUCCESS; - } -#else - /* ------------------------------------------------------------------ - * WFS CONNECTION Support not included... - * ------------------------------------------------------------------ */ - msSetError(MS_WFSCONNERR, "WFS CLIENT CONNECTION support is not available.", - "msWFSLayerGetItems()"); - return(MS_FAILURE); -#endif /* USE_WFS_LYR */ - -} - -/********************************************************************** - * msWFSLayerWhichShapes() - * - **********************************************************************/ - -int msWFSLayerWhichShapes(layerObj *lp, rectObj rect, int isQuery) -{ -#ifdef USE_WFS_LYR - msWFSLayerInfo *psInfo; - int status = MS_SUCCESS; - const char *pszTmp; - FILE *fp; - - if ( msCheckParentPointer(lp->map,"map")==MS_FAILURE ) - return MS_FAILURE; - - - psInfo =(msWFSLayerInfo*)lp->wfslayerinfo; - - if (psInfo == NULL) { - msSetError(MS_WFSCONNERR, "Assertion failed: WFS layer not opened!!!", - "msWFSLayerWhichShapes()"); - return(MS_FAILURE); - } - - /* ------------------------------------------------------------------ - * Check if layer overlaps current view window (using wfs_latlonboundingbox) - * ------------------------------------------------------------------ */ - if ((pszTmp = msOWSLookupMetadata(&(lp->metadata), - "FO", "latlonboundingbox")) != NULL) { - char **tokens; - int n; - rectObj ext; - - tokens = msStringSplit(pszTmp, ' ', &n); - if (tokens==NULL || n != 4) { - msSetError(MS_WFSCONNERR, "Wrong number of values in 'wfs_latlonboundingbox' metadata.", - "msWFSLayerWhichShapes()"); - return MS_FAILURE; - } - - ext.minx = atof(tokens[0]); - ext.miny = atof(tokens[1]); - ext.maxx = atof(tokens[2]); - ext.maxy = atof(tokens[3]); - - msFreeCharArray(tokens, n); - - /* Reproject latlonboundingbox to the selected SRS for the layer and */ - /* check if it overlaps the bbox that we calculated for the request */ - - msProjectRect(&(lp->map->latlon), &(lp->projection), &ext); - if (!msRectOverlap(&rect, &ext)) { - /* No overlap... nothing to do. If layer was never opened, go open it.*/ - if (lp->layerinfo) - return MS_DONE; /* No overlap. */ - } - } - - - /* ------------------------------------------------------------------ - * __TODO__ If new bbox differs from current one then we should - * invalidate current GML file in cache - * ------------------------------------------------------------------ */ - psInfo->rect = rect; - - - /* ------------------------------------------------------------------ - * If file not downloaded yet then do it now. - * ------------------------------------------------------------------ */ - if (psInfo->nStatus == 0) { - httpRequestObj asReqInfo[2]; - int numReq = 0; - - msHTTPInitRequestObj(asReqInfo, 2); - - if ( msPrepareWFSLayerRequest(-1, lp->map, lp, - asReqInfo, &numReq) == MS_FAILURE || - msOWSExecuteRequests(asReqInfo, numReq, - lp->map, MS_TRUE) == MS_FAILURE ) { - /* Delete tmp file... we don't want it to stick around. */ - unlink(asReqInfo[0].pszOutputFile); - return MS_FAILURE; - } - - /* Cleanup */ - msHTTPFreeRequestObj(asReqInfo, numReq); - - } - - if ( !MS_HTTP_SUCCESS( psInfo->nStatus ) ) { - /* Delete tmp file... we don't want it to stick around. */ - unlink(psInfo->pszGMLFilename); - - msSetError(MS_WFSCONNERR, - "Got HTTP status %d downloading WFS layer %s", - "msWFSLayerWhichShapes()", - psInfo->nStatus, lp->name?lp->name:"(null)"); - return(MS_FAILURE); - } - - /* ------------------------------------------------------------------ - * Check that file is really GML... it could be an exception, or just junk. - * ------------------------------------------------------------------ */ - if ((fp = fopen(psInfo->pszGMLFilename, "r")) != NULL) { - char szHeader[2000]; - int nBytes = 0; - - nBytes = fread( szHeader, 1, sizeof(szHeader)-1, fp ); - fclose(fp); - - if (nBytes < 0) - nBytes = 0; - szHeader[nBytes] = '\0'; - - if ( nBytes == 0 ) { - msSetError(MS_WFSCONNERR, - "WFS request produced no oputput for layer %s.", - "msWFSLayerWhichShapes()", - lp->name?lp->name:"(null)"); - return(MS_FAILURE); - - } - if ( strstr(szHeader, "") || - strstr(szHeader, "") ) { - msOWSProcessException(lp, psInfo->pszGMLFilename, - MS_WFSCONNERR, "msWFSLayerWhichShapes()" ); - return MS_FAILURE; - } else if ( strstr(szHeader,"opengis.net/gml") && - strstr(szHeader,"featureMember>") == NULL ) { - /* This looks like valid GML, but contains 0 features. */ - return MS_DONE; - } else if ( strstr(szHeader,"opengis.net/gml") == NULL || - strstr(szHeader,"featureMember>") == NULL ) { - /* This is probably just junk. */ - msSetError(MS_WFSCONNERR, - "WFS request produced unexpected output (junk?) for layer %s.", - "msWFSLayerWhichShapes()", - lp->name?lp->name:"(null)"); - return(MS_FAILURE); - } - - /* If we got this far, it must be a valid GML dataset... keep going */ - } - - - /* ------------------------------------------------------------------ - * Open GML file using OGR. - * ------------------------------------------------------------------ */ - if ((status = msOGRLayerOpen(lp, psInfo->pszGMLFilename)) != MS_SUCCESS) - return status; - - status = msOGRLayerWhichShapes(lp, rect, isQuery); - - /* Mark that the OGR Layer is valid */ - psInfo->bLayerHasValidGML = MS_TRUE; - - return status; -#else - /* ------------------------------------------------------------------ - * WFS CONNECTION Support not included... - * ------------------------------------------------------------------ */ - msSetError(MS_WFSCONNERR, "WFS CLIENT CONNECTION support is not available.", - "msWFSLayerWhichShapes()"); - return(MS_FAILURE); - -#endif /* USE_WFS_LYR */ -} - - - -/********************************************************************** - * msWFSLayerClose() - * - **********************************************************************/ - -int msWFSLayerClose(layerObj *lp) -{ -#ifdef USE_WFS_LYR - - /* ------------------------------------------------------------------ - * Cleanup OGR connection - * ------------------------------------------------------------------ */ - if (lp->layerinfo) - msOGRLayerClose(lp); - - /* ------------------------------------------------------------------ - * Cleanup WFS connection info. - * __TODO__ For now we flush everything, but we should try to cache some stuff - * ------------------------------------------------------------------ */ - /* __TODO__ unlink() .gml file and OGR's schema file if they exist */ - /* unlink( */ - - msFreeWFSLayerInfo(lp->wfslayerinfo); - lp->wfslayerinfo = NULL; - - return MS_SUCCESS; - -#else - /* ------------------------------------------------------------------ - * WFS CONNECTION Support not included... - * ------------------------------------------------------------------ */ - msSetError(MS_WFSCONNERR, "WFS CLIENT CONNECTION support is not available.", - "msWFSLayerClose()"); - return(MS_FAILURE); - -#endif /* USE_WFS_LYR */ - -} - -/********************************************************************** - * msWFSExecuteGetFeature() - * Returns the temporary gml file name. User shpuld free the return string. - **********************************************************************/ -char *msWFSExecuteGetFeature(layerObj *lp) -{ -#ifdef USE_WFS_LYR - char *gmltmpfile = NULL; - msWFSLayerInfo *psInfo = NULL; - - if (lp == NULL || lp->connectiontype != MS_WFS) - return NULL; - - msWFSLayerOpen(lp, NULL, NULL); - psInfo =(msWFSLayerInfo*)lp->wfslayerinfo; - if (psInfo && psInfo->pszGMLFilename) - gmltmpfile = msStrdup(psInfo->pszGMLFilename); - msWFSLayerClose(lp); - - return gmltmpfile; - -#else - /* ------------------------------------------------------------------ - * WFS CONNECTION Support not included... - * ------------------------------------------------------------------ */ - msSetError(MS_WFSCONNERR, "WFS CLIENT CONNECTION support is not available.", - "msExecuteWFSGetFeature()"); - return NULL; - -#endif /* USE_WFS_LYR */ - -} - -int -msWFSLayerInitializeVirtualTable(layerObj *layer) -{ - assert(layer != NULL); - assert(layer->vtable != NULL); - - layer->vtable->LayerInitItemInfo = msWFSLayerInitItemInfo; - layer->vtable->LayerFreeItemInfo = msOGRLayerFreeItemInfo; /* yes, OGR */ - layer->vtable->LayerOpen = msWFSLayerOpenVT; - layer->vtable->LayerIsOpen = msWFSLayerIsOpen; - layer->vtable->LayerWhichShapes = msWFSLayerWhichShapes; - layer->vtable->LayerNextShape = msWFSLayerNextShape; - /* layer->vtable->LayerResultsGetShape = msWFSLayerResultGetShape; */ - /* layer->vtable->LayerGetShapeCount, use default */ - layer->vtable->LayerGetShape = msWFSLayerGetShape; - layer->vtable->LayerClose = msWFSLayerClose; - layer->vtable->LayerGetItems = msWFSLayerGetItems; - layer->vtable->LayerGetExtent = msWFSLayerGetExtent; - /* layer->vtable->LayerGetAutoStyle, use default */ - /* layer->vtable->LayerApplyFilterToLayer, use default */ - /* layer->vtable->LayerCloseConnection, use default */ - layer->vtable->LayerSetTimeFilter = msLayerMakePlainTimeFilter; - /* layer->vtable->LayerCreateItems, use default */ - /* layer->vtable->LayerGetNumFeatures, use default */ - /* layer->vtable->LayerGetAutoProjection, use defaut*/ - - return MS_SUCCESS; -} diff --git a/mapwms.cpp b/mapwms.cpp deleted file mode 100644 index f188faebca..0000000000 --- a/mapwms.cpp +++ /dev/null @@ -1,5052 +0,0 @@ -/****************************************************************************** - * $Id$ - * - * Project: MapServer - * Purpose: OpenGIS Web Mapping Service support implementation. - * Author: Steve Lime and the MapServer team. - * - ****************************************************************************** - * Copyright (c) 1996-2005 Regents of the University of Minnesota. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies of this Software or works derived from this Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - *****************************************************************************/ - -#include "mapserver.h" -#include "maperror.h" -#include "mapthread.h" -#include "mapgml.h" -#include -#include "maptemplate.h" -#include "mapows.h" - -#include "mapogcsld.h" -#include "mapogcfilter.h" -#include "mapowscommon.h" - -#include "maptime.h" -#include "mapproject.h" - -#include -#include -#include - -#include -#include -#include - -#ifdef WIN32 -#include -#endif - -/* ================================================================== - * WMS Server stuff. - * ================================================================== */ -#ifdef USE_WMS_SVR - -/* -** msWMSException() -** -** Report current MapServer error in requested format. -*/ - -static -int msWMSException(mapObj *map, int nVersion, const char *exception_code, - const char *wms_exception_format) -{ - char *schemalocation = NULL; - - /* Default to WMS 1.3.0 exceptions if version not set yet */ - if (nVersion <= 0) - nVersion = OWS_1_3_0; - - /* get scheam location */ - schemalocation = msEncodeHTMLEntities( msOWSGetSchemasLocation(map) ); - - /* Establish default exception format depending on VERSION */ - if (wms_exception_format == NULL) { - if (nVersion <= OWS_1_0_0) - wms_exception_format = "INIMAGE"; /* WMS 1.0.0 */ - else if (nVersion <= OWS_1_0_7) - wms_exception_format = "SE_XML"; /* WMS 1.0.1 to 1.0.7 */ - else if (nVersion <= OWS_1_1_1) - wms_exception_format = "application/vnd.ogc.se_xml"; /* WMS 1.1.0 and later */ - else - wms_exception_format = "text/xml"; - } - - if (strcasecmp(wms_exception_format, "INIMAGE") == 0 || - strcasecmp(wms_exception_format, "BLANK") == 0 || - strcasecmp(wms_exception_format, "application/vnd.ogc.se_inimage")== 0 || - strcasecmp(wms_exception_format, "application/vnd.ogc.se_blank") == 0) { - int blank = 0; - - if (strcasecmp(wms_exception_format, "BLANK") == 0 || - strcasecmp(wms_exception_format, "application/vnd.ogc.se_blank") == 0) { - blank = 1; - } - - msWriteErrorImage(map, NULL, blank); - - } else if (strcasecmp(wms_exception_format, "WMS_XML") == 0) { /* Only in V1.0.0 */ - msIO_setHeader("Content-Type","text/xml; charset=UTF-8"); - msIO_sendHeaders(); - - msIO_printf("\n"); - msWriteErrorXML(stdout); - msIO_printf("\n"); - } else /* XML error, the default: SE_XML (1.0.1 to 1.0.7) */ - /* or application/vnd.ogc.se_xml (1.1.0 and later) */ - { - if (nVersion <= OWS_1_0_7) { - /* In V1.0.1 to 1.0.7, the MIME type was text/xml */ - msIO_setHeader("Content-Type","text/xml; charset=UTF-8"); - msIO_sendHeaders(); - - msIO_printf("\n"); - msIO_printf("\n"); - - msIO_printf("\n"); - } else if (nVersion <= OWS_1_1_0) { - /* In V1.1.0 and later, we have OGC-specific MIME types */ - /* we cannot return anything else than application/vnd.ogc.se_xml here. */ - msIO_setHeader("Content-Type","application/vnd.ogc.se_xml; charset=UTF-8"); - msIO_sendHeaders(); - - msIO_printf("\n"); - - msIO_printf("\n",schemalocation); - - msIO_printf("\n"); - } else if (nVersion <= OWS_1_1_1) { /* 1.1.1 */ - msIO_setHeader("Content-Type","application/vnd.ogc.se_xml; charset=UTF-8"); - msIO_sendHeaders(); - - msIO_printf("\n"); - msIO_printf("\n", schemalocation); - msIO_printf("\n"); - } else { /*1.3.0*/ - if (strcasecmp(wms_exception_format, "application/vnd.ogc.se_xml") == 0) { - msIO_setHeader("Content-Type","application/vnd.ogc.se_xml; charset=UTF-8"); - } else { - msIO_setHeader("Content-Type","text/xml; charset=UTF-8"); - } - msIO_sendHeaders(); - - msIO_printf("\n"); - msIO_printf("\n", - schemalocation); - } - - - if (exception_code) - msIO_printf("\n", exception_code); - else - msIO_printf("\n"); - msWriteErrorXML(stdout); - msIO_printf("\n"); - msIO_printf("\n"); - - } - free(schemalocation); - - return MS_FAILURE; /* so that we can call 'return msWMSException();' anywhere */ -} - -static bool msWMSSetTimePattern(const char *timepatternstring, const char *timestring, bool checkonly) -{ - if (timepatternstring && timestring) { - /* parse the time parameter to extract a distinct time. */ - /* time value can be dicrete times (eg 2004-09-21), */ - /* multiple times (2004-09-21, 2004-09-22, ...) */ - /* and range(s) (2004-09-21/2004-09-25, 2004-09-27/2004-09-29) */ - const auto atimes = msStringSplit(timestring, ','); - - /* get the pattern to use */ - if (!atimes.empty()) { - auto patterns = msStringSplit(timepatternstring, ','); - for (auto& pattern: patterns) { - msStringTrimBlanks(pattern); - msStringTrimLeft(pattern); - } - - for (const auto& atime: atimes) { - const auto ranges = msStringSplit(atime.c_str(), '/'); - for( const auto& range: ranges) { - bool match = false; - for (const auto& pattern: patterns) { - if (!pattern.empty()) { - if (msTimeMatchPattern(range.c_str(), pattern.c_str()) == MS_TRUE) { - if (!checkonly) msSetLimitedPatternsToUse(pattern.c_str()); - match = true; - break; - } - } - } - if (!match) { - msSetError(MS_WMSERR, "Time value %s given does not match the time format pattern.", "msWMSSetTimePattern", range.c_str()); - return false; - } - } - } - } - } - - return true; -} - -/* -** Apply the TIME parameter to layers that are time aware -*/ -static -int msWMSApplyTime(mapObj *map, int version, const char *time, const char *wms_exception_format) -{ - if (map) { - - const char* timepattern = msOWSLookupMetadata(&(map->web.metadata), "MO", "timeformat"); - - for (int i=0; inumlayers; i++) { - layerObj* lp = (GET_LAYER(map, i)); - if (lp->status != MS_ON && lp->status != MS_DEFAULT) - continue; - - /* check if the layer is time aware */ - const char* timeextent = msOWSLookupMetadata(&(lp->metadata), "MO", "timeextent"); - const char* timefield = msOWSLookupMetadata(&(lp->metadata), "MO", "timeitem"); - const char* timedefault = msOWSLookupMetadata(&(lp->metadata), "MO", "timedefault"); - - if (timeextent && timefield) { - /* check to see if the time value is given. If not */ - /* use default time. If default time is not available */ - /* send an exception */ - if (time == NULL || strlen(time) <=0) { - if (timedefault == NULL) { - msSetError(MS_WMSERR, "No Time value was given, and no default time value defined.", "msWMSApplyTime"); - return msWMSException(map, version, "MissingDimensionValue", wms_exception_format); - } else { - if (msValidateTimeValue((char *)timedefault, timeextent) == MS_FALSE) { - msSetError(MS_WMSERR, "No Time value was given, and the default time value %s is invalid or outside the time extent defined %s", "msWMSApplyTime", timedefault, timeextent); - /* return MS_FALSE; */ - return msWMSException(map, version, "InvalidDimensionValue", wms_exception_format); - } - msLayerSetTimeFilter(lp, timedefault, timefield); - } - } else { - /* - ** Check to see if there is a list of possible patterns defined. If it is the case, use - ** it to set the time pattern to use for the request. - ** - ** Last argument is set to TRUE (checkonly) to not trigger the patterns info setting, rather - ** to only apply the wms_timeformats on the user request values, not the mapfile values. - */ - if (timepattern && time && strlen(time) > 0) { - if (!msWMSSetTimePattern(timepattern, time, true)) - return msWMSException(map, version,"InvalidDimensionValue", wms_exception_format); - } - - /* check if given time is in the range */ - if (msValidateTimeValue(time, timeextent) == MS_FALSE) { - if (timedefault == NULL) { - msSetError(MS_WMSERR, "Time value(s) %s given is invalid or outside the time extent defined (%s).", "msWMSApplyTime", time, timeextent); - /* return MS_FALSE; */ - return msWMSException(map, version, - "InvalidDimensionValue", wms_exception_format); - } else { - if (msValidateTimeValue((char *)timedefault, timeextent) == MS_FALSE) { - msSetError(MS_WMSERR, "Time value(s) %s given is invalid or outside the time extent defined (%s), and default time set is invalid (%s)", "msWMSApplyTime", time, timeextent, timedefault); - /* return MS_FALSE; */ - return msWMSException(map, version, - "InvalidDimensionValue", wms_exception_format); - } else - msLayerSetTimeFilter(lp, timedefault, timefield); - } - - } else { - /* build the time string */ - msLayerSetTimeFilter(lp, time, timefield); - timeextent= NULL; - } - } - } - } - - /* last argument is MS_FALSE to trigger a method call that set the patterns - info. some drivers use it */ - if (timepattern && time && strlen(time) > 0) { - if (!msWMSSetTimePattern(timepattern, time, false)) - return msWMSException(map, version, "InvalidDimensionValue", wms_exception_format); - } - } - - return MS_SUCCESS; -} - -/* -** Apply the FILTER parameter to layers (RFC118) -*/ -static -int msWMSApplyFilter(mapObj *map, int version, const char *filter, - int def_srs_needs_axis_swap, const char *wms_exception_format, owsRequestObj *ows_request) -{ - // Empty filter should be ignored - if (!filter || strlen(filter) == 0) - return MS_SUCCESS; - - if (!map) - return MS_FAILURE; - - /* Count number of requested layers / groups / etc. - * Only layers with STATUS ON were in the LAYERS request param. - * Layers with STATUS DEFAULT were set in the mapfile and are - * not expected to have a corresponding filter in the request - */ - int numlayers = 0; - for(int i=0; inumlayers; i++) { - layerObj *lp=NULL; - - if(map->layerorder[i] != -1) { - lp = (GET_LAYER(map, map->layerorder[i])); - if (lp->status == MS_ON) - numlayers++; - } - } - - /* -------------------------------------------------------------------- */ - /* Parse the Filter parameter. If there are several Filter */ - /* parameters, each Filter is inside parentheses. */ - /* -------------------------------------------------------------------- */ - int numfilters = 0; - char **paszFilters = NULL; - if (filter[0] == '(') { - paszFilters = FLTSplitFilters(filter, &numfilters); - - } else if (numlayers == 1) { - numfilters=1; - paszFilters = (char **)msSmallMalloc(sizeof(char *)*numfilters); - paszFilters[0] = msStrdup(filter); - } - - if (numfilters != ows_request->numwmslayerargs) { - msSetError(MS_WMSERR, "Wrong number of filter elements, one filter must be specified for each requested layer or groups.", - "msWMSApplyFilter" ); - msFreeCharArray(paszFilters, numfilters); - return msWMSException(map, version, "InvalidParameterValue", wms_exception_format); - } - - /* We're good to go. Apply each filter to the corresponding layer */ - for(int i=0; inumlayers; i++) { - layerObj *lp=NULL; - - if(map->layerorder[i] != -1) - lp = (GET_LAYER(map, map->layerorder[i])); - - /* Only layers with STATUS ON were in the LAYERS request param.*/ - if (lp == NULL || lp->status != MS_ON) - continue; - - const int curfilter = ows_request->layerwmsfilterindex[lp->index]; - - /* Skip empty filters */ - if (paszFilters[curfilter][0] == '\0') { - continue; - } - - /* Force setting a template to enable query. */ - if (lp->_template == NULL) - lp->_template = msStrdup("ttt.html"); - - /* Parse filter */ - FilterEncodingNode* psNode = FLTParseFilterEncoding(paszFilters[curfilter]); - if (!psNode) { - msSetError(MS_WMSERR, - "Invalid or Unsupported FILTER : %s", - "msWMSApplyFilter()", paszFilters[curfilter]); - msFreeCharArray(paszFilters, numfilters); - return msWMSException(map, version, "InvalidParameterValue", wms_exception_format); - } - - /* For WMS 1.3 and up, we may need to swap the axis of bbox and geometry - * elements inside the filter(s) - */ - if (version >= OWS_1_3_0) - FLTDoAxisSwappingIfNecessary(map, psNode, def_srs_needs_axis_swap); - -#ifdef do_we_need_this - FLTProcessPropertyIsNull(psNode, map, lp->index); - - /*preparse the filter for gml aliases*/ - FLTPreParseFilterForAliasAndGroup(psNode, map, lp->index, "G"); - - /* Check that FeatureId filters are consistent with the active layer */ - if( FLTCheckFeatureIdFilters(psNode, map, lp->index) == MS_FAILURE) - { - FLTFreeFilterEncodingNode( psNode ); - return msWFSException(map, "mapserv", MS_OWS_ERROR_NO_APPLICABLE_CODE, paramsObj->pszVersion); - } - - /* FIXME?: could probably apply to WFS 1.1 too */ - if( nWFSVersion >= OWS_2_0_0 ) - { - int nEvaluation; - - if( FLTCheckInvalidOperand(psNode) == MS_FAILURE) - { - FLTFreeFilterEncodingNode( psNode ); - msFreeCharArray(paszFilters, numfilters); - return msWFSException(map, "filter", MS_WFS_ERROR_OPERATION_PROCESSING_FAILED, paramsObj->pszVersion); - } - - if( FLTCheckInvalidProperty(psNode, map, lp->index) == MS_FAILURE) - { - FLTFreeFilterEncodingNode( psNode ); - msFreeCharArray(paszFilters, numfilters); - return msWFSException(map, "filter", MS_OWS_ERROR_INVALID_PARAMETER_VALUE, paramsObj->pszVersion); - } - - psNode = FLTSimplify(psNode, &nEvaluation); - if( psNode == NULL ) - { - FLTFreeFilterEncodingNode( psNode ); - msFreeCharArray(paszFilters, numfilters); - if( nEvaluation == 1 ) { - /* return full layer */ - return msWFSRunBasicGetFeature(map, lp, paramsObj, nWFSVersion); - } - else { - /* return empty result set */ - return MS_SUCCESS; - } - } - - } - -#endif - - /* Apply filter to this layer */ - - /* But first, start by removing any wfs_use_default_extent_for_getfeature metadata item */ - /* that could result in the BBOX to be removed */ - std::string old_value_wfs_use_default_extent_for_getfeature; - { - const char* old_value_tmp = msLookupHashTable( - &(lp->metadata), "wfs_use_default_extent_for_getfeature"); - if( old_value_tmp ) - { - old_value_wfs_use_default_extent_for_getfeature = old_value_tmp; - msRemoveHashTable(&(lp->metadata), "wfs_use_default_extent_for_getfeature"); - } - } - - int ret = FLTApplyFilterToLayer(psNode, map, lp->index); - if( !old_value_wfs_use_default_extent_for_getfeature.empty() ) - { - msInsertHashTable(&(lp->metadata), "wfs_use_default_extent_for_getfeature", - old_value_wfs_use_default_extent_for_getfeature.c_str()); - } - - if( ret != MS_SUCCESS ) { - errorObj* ms_error = msGetErrorObj(); - - if(ms_error->code != MS_NOTFOUND) { - msSetError(MS_WMSERR, "FLTApplyFilterToLayer() failed", "msWMSApplyFilter()"); - FLTFreeFilterEncodingNode( psNode ); - msFreeCharArray(paszFilters, numfilters); - return msWMSException(map, version, "InvalidParameterValue", wms_exception_format); - } - } - - FLTFreeFilterEncodingNode( psNode ); - - }/* for */ - - msFreeCharArray(paszFilters, numfilters); - - return MS_SUCCESS; -} - -/* -** msWMSPrepareNestedGroups() -** -** purpose: Parse WMS_LAYER_GROUP settings into arrays -** -** params: -** - nestedGroups: This array holds the arrays of groups that have been set -** through the WMS_LAYER_GROUP metadata -** - numNestedGroups: This array holds the number of groups set in -** WMS_LAYER_GROUP for each layer -** - isUsedInNestedGroup: This array indicates if the layer is used as group -** as set through the WMS_LAYER_GROUP metadata -*/ -static -void msWMSPrepareNestedGroups(mapObj* map, int nVersion, char*** nestedGroups, int* numNestedGroups, int* isUsedInNestedGroup) -{ - //Create set to hold unique groups - std::set uniqgroups; - - for (int i = 0; i < map->numlayers; i++) { - nestedGroups[i] = NULL; /* default */ - numNestedGroups[i] = 0; /* default */ - isUsedInNestedGroup[i] = 0; /* default */ - - const char* groups = msOWSLookupMetadata(&(GET_LAYER(map, i)->metadata), "MO", "layer_group"); - if ((groups != NULL) && (strlen(groups) != 0)) { - if (GET_LAYER(map, i)->group != NULL && strlen(GET_LAYER(map, i)->group) != 0) { - const char* errorMsg = "It is not allowed to set both the GROUP and WMS_LAYER_GROUP for a layer"; - msSetError(MS_WMSERR, errorMsg, "msWMSPrepareNestedGroups()", NULL); - msIO_fprintf(stdout, "\n", errorMsg); - /* cannot return exception at this point because we are already writing to stdout */ - } else { - if (groups[0] != '/') { - const char* errorMsg = "The WMS_LAYER_GROUP metadata does not start with a '/'"; - msSetError(MS_WMSERR, errorMsg, "msWMSPrepareNestedGroups()", NULL); - msIO_fprintf(stdout, "\n", errorMsg); - /* cannot return exception at this point because we are already writing to stdout */ - } else { - /* split into subgroups. Start at address + 1 because the first '/' would cause an extra empty group */ - nestedGroups[i] = msStringSplit(groups + 1, '/', &numNestedGroups[i]); - /* Iterate through the groups and add them to the unique groups array */ - for (int k=0; knumlayers; i++) { - if( uniqgroups.find(msStringToLower(std::string(GET_LAYER(map, i)->name))) != uniqgroups.end() ) { - isUsedInNestedGroup[i] = 1; - } - } -} - - -/* -** Validate that a given dimension is inside the extents defined -*/ -static -bool msWMSValidateDimensionValue(const char *value, const char *dimensionextent, bool forcecharacter) -{ - std::vector aextentranges; - - bool isextentavalue = false; - bool isextentarange = false; - bool ischaracter = false; - - if (forcecharacter) - ischaracter = true; - - if (!value || !dimensionextent) - return false; - - /*for the value, we support descrete values (2005) */ - /* multiple values (abc, def, ...) */ - /* and range(s) (1000/2000, 3000/5000) */ - /** we do not support resolution*/ - - /* -------------------------------------------------------------------- */ - /* parse the extent first. */ - /* -------------------------------------------------------------------- */ - auto extents = msStringSplit (dimensionextent, ','); - for( auto& extent: extents ) // Make sure to get by reference so that it is updated in place - msStringTrim(extent); - - std::vector aextentvalues; - if (extents.size() == 1) { - if (strstr(dimensionextent, "/") == NULL) { - /*single value*/ - isextentavalue = true; - aextentvalues.push_back(dimensionextent); - if (!forcecharacter) - ischaracter= FLTIsNumeric(dimensionextent) == MS_FALSE; - - } else { - const auto ranges = msStringSplit (dimensionextent, '/'); - if(ranges.size() == 2 || ranges.size() == 3) { - /*single range*/ - isextentarange = true; - aextentranges.resize(1); - aextentranges[0].x = atof(ranges[0].c_str()); - aextentranges[0].y = atof(ranges[1].c_str()); - /*ranges should be numeric*/ - ischaracter = false; - } - } - } else if (extents.size() > 1) { /*check if it is muliple values or mutliple ranges*/ - if (strstr(dimensionextent, "/") == NULL) { - /*multiple values*/ - isextentavalue = true; - aextentvalues = extents; - if (!forcecharacter) - ischaracter= FLTIsNumeric(aextentvalues[0].c_str()) == MS_FALSE; - } else { /*multiple range extent*/ - int isvalidextent = MS_TRUE; - /*ranges should be numeric*/ - ischaracter = false; - isextentarange = true; - aextentranges.resize(extents.size()); - size_t nextentranges=0; - - for(const auto& extent: extents) { - const auto onerange = msStringSplit(extent.c_str(), '/'); - if (onerange.size() != 2 && onerange.size() != 3) { - isvalidextent = MS_FALSE; - break; - } - if (isvalidextent) { - - aextentranges[nextentranges].x = atof(onerange[0].c_str()); - aextentranges[nextentranges++].y = atof(onerange[1].c_str()); - } - } - if (!isvalidextent) { - nextentranges = 0; - isextentarange = false; - } - aextentranges.resize(nextentranges); - } - } - - /* make sure that we got a valid extent*/ - if (!isextentavalue && !isextentarange) { - return false; - } - - /*for the extent of the dimesion, we support - single value, or list of mulitiple values comma separated, - a single range or multipe ranges */ - - - const auto uservalues = msStringSplit (value, ','); - bool uservaluevalid = false; - if (uservalues.size() == 1) { - /*user iput=single*/ - /*is it descret or range*/ - const auto ranges = msStringSplit(uservalues[0].c_str(), '/'); - if (ranges.size() == 1) { /*discrete*/ - if (isextentavalue) { - /*single user value, single/multiple values extent*/ - for (const auto& extentvalue: aextentvalues) { - if (ischaracter) - uservaluevalid = (uservalues[0] == extentvalue); - else { - if (atof(uservalues[0].c_str()) == atof(extentvalue.c_str())) - uservaluevalid = true; - } - if(uservaluevalid) - break; - } - } else if (isextentarange) { - /*single user value, single/multiple range extent*/ - const float currentval = atof(uservalues[0].c_str()); - - for (const auto& extentrange: aextentranges) { - const float minval = extentrange.x; - const float maxval = extentrange.y; - if (currentval >= minval && currentval <= maxval) { - uservaluevalid= true; - break; - } - } - } - } else if (ranges.size() == 2 || ranges.size() == 3) { /*range*/ - /*user input=single range. In this case the extents must - be of a range type.*/ - const float mincurrentval = atof(ranges[0].c_str()); - const float maxcurrentval = atof(ranges[1].c_str()); - if (isextentarange) { - for (const auto& extentrange: aextentranges) { - const float minval = extentrange.x; - const float maxval = extentrange.y; - - if(minval <= mincurrentval && maxval >= maxcurrentval && - minval <= maxval) { - uservaluevalid= true; - break; - } - } - } - } - } else if (uservalues.size() > 1) { /*user input=multiple*/ - if (strstr(value, "/") == NULL) { - /*user input=multiple value*/ - bool valueisvalid = false; - for (const auto& uservalue: uservalues) { - valueisvalid = false; - if (isextentavalue) { - /*user input is multiple values, extent is defned as one or multiple values*/ - for (const auto& extentvalue: aextentvalues) { - if (ischaracter) { - if (uservalue == extentvalue) { - valueisvalid = true; - break; - } - } else { - if (atof(uservalue.c_str()) == atof(extentvalue.c_str())) { - valueisvalid = true; - break; - } - } - } - /*every value shoule be valid*/ - if (!valueisvalid) - break; - } else if (isextentarange) { - /*user input is multiple values, extent is defned as one or multiple ranges*/ - for (const auto& extentrange: aextentranges) { - const float minval = extentrange.x; - const float maxval = extentrange.y; - const float currentval = atof(uservalue.c_str()); - if(minval <= currentval && maxval >= currentval && - minval <= maxval) { - valueisvalid = true; - break; - } - } - if (!valueisvalid) - break; - } - } - uservaluevalid = valueisvalid; - } else { /*user input multiple ranges*/ - bool valueisvalid = true; - - for (const auto& uservalue: uservalues) { - /*each ranges should be valid*/ - const auto onerange = msStringSplit(uservalue.c_str(), '/'); - if (onerange.size() == 2 || onerange.size() == 3) { - const float mincurrentval = atof(onerange[0].c_str()); - const float maxcurrentval = atof(onerange[1].c_str()); - - /*extent must be defined also as a rangle*/ - if (isextentarange) { - bool found = false; - for (const auto& extentrange: aextentranges) { - const float mincurrentrange = extentrange.x; - const float maxcurrentrange = extentrange.y; - - if(mincurrentval >=mincurrentrange && maxcurrentval <= maxcurrentrange && - mincurrentval <= maxcurrentval) { - found = true; - break; - } - - } - if (!found) { - valueisvalid = false; - break; - } - } - } else { - valueisvalid = false; - } - } - uservaluevalid = valueisvalid; - } - - } - - return uservaluevalid; -} - -static -bool msWMSApplyDimensionLayer(layerObj *lp, const char *item, const char *value, bool forcecharacter) -{ - bool result = false; - - if (lp && item && value) { - /*for the value, we support descrete values (2005) */ - /* multiple values (abc, def, ...) */ - /* and range(s) (1000/2000, 3000/5000) */ - char* pszExpression = FLTGetExpressionForValuesRanges(lp, item, value, forcecharacter ? MS_TRUE : MS_FALSE); - - if (pszExpression) { - // If tileindex is set, the filter is applied to tileindex too. - int tlpindex = -1; - if (lp->tileindex && (tlpindex = msGetLayerIndex(lp->map, lp->tileindex)) != -1) { - result = FLTApplyExpressionToLayer((GET_LAYER(lp->map, tlpindex)), pszExpression) != MS_FALSE; - } else { - result = true; - } - result &= FLTApplyExpressionToLayer(lp, pszExpression) != MS_FALSE; - msFree(pszExpression); - } - } - return result; -} - -static -bool msWMSApplyDimension(layerObj *lp, int version, const char *dimensionname, const char *value, - const char *wms_exception_format) -{ - bool forcecharacter = false; - bool result = false; - - if (lp && dimensionname && value) { - /*check if the dimension name passes starts with dim_. All dimensions should start with dim_, except elevation*/ - std::string dimension; - if (strncasecmp(dimensionname, "dim_", 4) == 0) - dimension = dimensionname+4; - else - dimension = dimensionname; - - /*if value is empty and a default is defined, use it*/ - std::string currentvalue; - if (strlen(value) > 0) - currentvalue = value; - else { - const char* dimensiondefault = msOWSLookupMetadata(&(lp->metadata), "M", (dimension + "_default").c_str()); - if (dimensiondefault) - currentvalue = dimensiondefault; - } - - /*check if the manadatory metada related to the dimension are set*/ - const char* dimensionitem = msOWSLookupMetadata(&(lp->metadata), "M", (dimension + "_item").c_str()); - const char* dimensionextent = msOWSLookupMetadata(&(lp->metadata), "M", (dimension + "_extent").c_str()); - const char* dimensionunit = msOWSLookupMetadata(&(lp->metadata), "M", (dimension + "_units").c_str()); - - /*if the server want to force the type to character*/ - const char* dimensiontype = msOWSLookupMetadata(&(lp->metadata), "M", (dimension + "_type").c_str()); - if (dimensiontype && strcasecmp(dimensiontype, "Character") == 0) - forcecharacter = true; - - if (dimensionitem && dimensionextent && dimensionunit && !currentvalue.empty()) { - if(msWMSValidateDimensionValue(currentvalue.c_str(), dimensionextent, forcecharacter)) { - result = msWMSApplyDimensionLayer(lp, dimensionitem, currentvalue.c_str(), forcecharacter); - } else { - msSetError(MS_WMSERR, "Dimension %s with a value of %s is invalid or outside the extents defined", "msWMSApplyDimension", - dimension.c_str(), currentvalue.c_str()); - result = false; - } - } else - msSetError(MS_WMSERR, "Dimension %s : invalid settings. Make sure that item, units and extent are set.", "msWMSApplyDimension", - dimension.c_str()); - } - return result; -} -/* -** -*/ -int msWMSLoadGetMapParams(mapObj *map, int nVersion, - char **names, char **values, int numentries, const char *wms_exception_format, - const char *wms_request, owsRequestObj *ows_request) -{ - bool adjust_extent = false; - bool nonsquare_enabled = false; - int transparent = MS_NOOVERRIDE; - bool bbox_pixel_is_point = false; - outputFormatObj *format = NULL; - int validlayers = 0; - const char *styles = NULL; - int invalidlayers = 0; - std::string epsgbuf; - std::string srsbuffer; - bool epsgvalid = false; - bool timerequest = false; - const char *stime = NULL; - bool srsfound = false; - bool bboxfound = false; - bool formatfound = false; - bool widthfound = false; - bool heightfound = false; - const char *request = NULL; - int status = 0; - const char *layerlimit = NULL; - - const char *sldenabled=NULL; - const char *sld_url=NULL; - const char *sld_body=NULL; - - const char *filter = NULL; - - /* Some of the getMap parameters are actually required depending on the */ - /* request, but for now we assume all are optional and the map file */ - /* defaults will apply. */ - - msAdjustExtent(&(map->extent), map->width, map->height); - - /* - Check for SLDs first. If SLD is available LAYERS and STYLES parameters are non mandatory - */ - for(int i=0; iweb.metadata), "MO", "sld_enabled"); - - if (sldenabled == NULL) - sldenabled = "true"; - - if (strcasecmp(sldenabled, "true") == 0) { - if (strcasecmp(names[i], "SLD") == 0) { - sld_url = values[i]; - } - if (strcasecmp(names[i], "SLD_BODY") == 0) { - sld_body = values[i]; - } - } - } - } - - std::vector wmslayers; - for(int i=0; i layerOrder(map->numlayers); - - wmslayers = msStringSplit(values[i], ','); - if (wmslayers.empty()) { - if (sld_url == NULL && sld_body == NULL) { - msSetError(MS_WMSERR, "At least one layer name required in LAYERS.", - "msWMSLoadGetMapParams()"); - return msWMSException(map, nVersion, NULL, wms_exception_format); - } - } - - if (nVersion >= OWS_1_3_0) { - layerlimit = msOWSLookupMetadata(&(map->web.metadata), "MO", "layerlimit"); - if(layerlimit) { - if (static_cast(wmslayers.size()) > atoi(layerlimit)) { - msSetError(MS_WMSERR, "Number of layers requested exceeds LayerLimit.", - "msWMSLoadGetMapParams()"); - return msWMSException(map, nVersion, NULL, wms_exception_format); - } - } - } - - for (int iLayer=0; iLayer < map->numlayers; iLayer++) { - map->layerorder[iLayer] = iLayer; - } - - int nLayerOrder = 0; - for(int j=0; jnumlayers; j++) { - /* Keep only layers with status=DEFAULT by default */ - /* Layer with status DEFAULT is drawn first. */ - if (GET_LAYER(map, j)->status != MS_DEFAULT) - GET_LAYER(map, j)->status = MS_OFF; - else { - map->layerorder[nLayerOrder++] = j; - layerOrder[j] = 1; - } - } - - char*** nestedGroups = (char***)msSmallCalloc(map->numlayers, sizeof(char**)); - int* numNestedGroups = (int*)msSmallCalloc(map->numlayers, sizeof(int)); - int* isUsedInNestedGroup = (int*)msSmallCalloc(map->numlayers, sizeof(int)); - msWMSPrepareNestedGroups(map, nVersion, nestedGroups, numNestedGroups, isUsedInNestedGroup); - - if (ows_request->layerwmsfilterindex != NULL) - msFree(ows_request->layerwmsfilterindex); - ows_request->layerwmsfilterindex = (int*)msSmallMalloc(map->numlayers * sizeof(int)); - for(int j=0; jnumlayers; j++) { - ows_request->layerwmsfilterindex[j] = -1; - } - ows_request->numwmslayerargs = static_cast(wmslayers.size()); - - for (int k = 0; k < static_cast(wmslayers.size()); k++) { - const auto& wmslayer = wmslayers[k]; - bool layerfound = false; - for (int j=0; jnumlayers; j++) { - /* Turn on selected layers only. */ - if ( ((GET_LAYER(map, j)->name && - strcasecmp(GET_LAYER(map, j)->name, wmslayer.c_str()) == 0) || - (map->name && strcasecmp(map->name, wmslayer.c_str()) == 0) || - (GET_LAYER(map, j)->group && strcasecmp(GET_LAYER(map, j)->group, wmslayer.c_str()) == 0) || - ((numNestedGroups[j] >0) && msStringInArray(wmslayer.c_str(), nestedGroups[j], numNestedGroups[j]))) && - ((msIntegerInArray(GET_LAYER(map, j)->index, ows_request->enabled_layers, ows_request->numlayers))) ) { - if (GET_LAYER(map, j)->status != MS_DEFAULT) { - if (layerOrder[j] == 0) { - map->layerorder[nLayerOrder++] = j; - layerOrder[j] = 1; - GET_LAYER(map, j)->status = MS_ON; - } - } - ows_request->layerwmsfilterindex[j] = k; /* Assign the corresponding filter */ - validlayers++; - layerfound = true; - } - } - if (layerfound == false && !wmslayers.empty()) - invalidlayers++; - - } - - /* free the stuff used for nested layers */ - for (int k = 0; k < map->numlayers; k++) { - if (numNestedGroups[k] > 0) { - msFreeCharArray(nestedGroups[k], numNestedGroups[k]); - } - } - free(nestedGroups); - free(numNestedGroups); - free(isUsedInNestedGroup); - - /* set all layers with status off at end of array */ - for (int j=0; jnumlayers; j++) { - if (GET_LAYER(map, j)->status == MS_OFF) - if (layerOrder[j] == 0) - map->layerorder[nLayerOrder++] = j; - } - } else if (strcasecmp(names[i], "STYLES") == 0) { - styles = values[i]; - - } else if ((strcasecmp(names[i], "SRS") == 0 && nVersion < OWS_1_3_0) || - (strcasecmp(names[i], "CRS") == 0 && nVersion >= OWS_1_3_0)) { - srsfound = true; - /* SRS is in format "EPSG:epsg_id" or "AUTO:proj_id,unit_id,lon0,lat0" */ - if (strncasecmp(values[i], "EPSG:", 5) == 0) { - /* SRS=EPSG:xxxx */ - - /* don't need to copy init=xxx since the srsbuffer is only - used with msLoadProjection and that does alreay the job */ - - srsbuffer = "EPSG:"; - srsbuffer += (values[i]+5); - epsgbuf = srsbuffer; - - /* This test was to correct a request by the OCG cite 1.3.0 test - sending CRS=ESPG:4326, Bug:*/ - if (nVersion >= OWS_1_3_0) { - if (srsbuffer.back() == ',') - { - srsbuffer.resize(srsbuffer.size() - 1); - epsgbuf = srsbuffer; - } - } - - /* we need to wait until all params are read before */ - /* loding the projection into the map. This will help */ - /* insure that the passes srs is valid for all layers. */ - /* - if (msLoadProjectionString(&(map->projection), buffer) != 0) - return msWMSException(map, nVersion, NULL); - - iUnits = GetMapserverUnitUsingProj(&(map->projection)); - if (iUnits != -1) - map->units = iUnits; - */ - } else if (strncasecmp(values[i], "AUTO:", 5) == 0 && nVersion < OWS_1_3_0) { - srsbuffer = values[i]; - /* SRS=AUTO:proj_id,unit_id,lon0,lat0 */ - /* - if (msLoadProjectionString(&(map->projection), values[i]) != 0) - return msWMSException(map, nVersion, NULL); - - iUnits = GetMapserverUnitUsingProj(&(map->projection)); - if (iUnits != -1) - map->units = iUnits; - */ - } else if (nVersion >= OWS_1_3_0 && (strncasecmp(values[i], "AUTO2:", 6) == 0 || - strncasecmp(values[i], "CRS:", 4) == 0)) { - srsbuffer = values[i]; - } else { - if (nVersion >= OWS_1_3_0) { - msSetError(MS_WMSERR, - "Unsupported CRS namespace (only EPSG, AUTO2, CRS currently supported).", - "msWMSLoadGetMapParams()"); - return msWMSException(map, nVersion, "InvalidCRS", wms_exception_format); - } else { - msSetError(MS_WMSERR, - "Unsupported SRS namespace (only EPSG and AUTO currently supported).", - "msWMSLoadGetMapParams()"); - return msWMSException(map, nVersion, "InvalidSRS", wms_exception_format); - } - } - } else if (strcasecmp(names[i], "BBOX") == 0) { - bboxfound = true; - const auto tokens = msStringSplit(values[i], ','); - if (tokens.size() != 4) { - msSetError(MS_WMSERR, "Wrong number of arguments for BBOX.", - "msWMSLoadGetMapParams()"); - return msWMSException(map, nVersion, NULL, wms_exception_format); - } - map->extent.minx = atof(tokens[0].c_str()); - map->extent.miny = atof(tokens[1].c_str()); - map->extent.maxx = atof(tokens[2].c_str()); - map->extent.maxy = atof(tokens[3].c_str()); - - /*for wms 1.3.0 we will do the validation of the bbox after all parameters - are read to account for the axes order*/ - if (nVersion < OWS_1_3_0) { - - /* validate bbox values */ - if ( map->extent.minx >= map->extent.maxx || - map->extent.miny >= map->extent.maxy) { - msSetError(MS_WMSERR, - "Invalid values for BBOX.", - "msWMSLoadGetMapParams()"); - return msWMSException(map, nVersion, NULL, wms_exception_format); - } - adjust_extent = true; - } - } else if (strcasecmp(names[i], "WIDTH") == 0) { - widthfound = true; - map->width = atoi(values[i]); - } else if (strcasecmp(names[i], "HEIGHT") == 0) { - heightfound = true; - map->height = atoi(values[i]); - } else if (strcasecmp(names[i], "FORMAT") == 0) { - formatfound = true; - - if (strcasecmp(values[i], "application/openlayers")!=0) { - /*check to see if a predefined list is given*/ - const char* format_list = msOWSLookupMetadata(&(map->web.metadata), "M","getmap_formatlist"); - if (format_list) { - format = msOwsIsOutputFormatValid(map, values[i], &(map->web.metadata), - "M", "getmap_formatlist"); - if (format == NULL) { - msSetError(MS_IMGERR, - "Unsupported output format (%s).", - "msWMSLoadGetMapParams()", - values[i] ); - return msWMSException(map, nVersion, "InvalidFormat", wms_exception_format); - } - } else { - format = msSelectOutputFormat( map, values[i] ); - if( format == NULL || - (strncasecmp(format->driver, "MVT", 3) != 0 && - strncasecmp(format->driver, "GDAL/", 5) != 0 && - strncasecmp(format->driver, "AGG/", 4) != 0 && - strncasecmp(format->driver, "UTFGRID", 7) != 0 && - strncasecmp(format->driver, "CAIRO/", 6) != 0 && - strncasecmp(format->driver, "OGL/", 4) != 0 && - strncasecmp(format->driver, "KML", 3) != 0 && - strncasecmp(format->driver, "KMZ", 3) != 0)) { - msSetError(MS_IMGERR, - "Unsupported output format (%s).", - "msWMSLoadGetMapParams()", - values[i] ); - return msWMSException(map, nVersion, "InvalidFormat", wms_exception_format); - } - } - } - msFree( map->imagetype ); - map->imagetype = msStrdup(values[i]); - } else if (strcasecmp(names[i], "TRANSPARENT") == 0) { - transparent = (strcasecmp(values[i], "TRUE") == 0); - } else if (strcasecmp(names[i], "BGCOLOR") == 0) { - long c; - c = strtol(values[i], NULL, 16); - map->imagecolor.red = (c/0x10000)&0xff; - map->imagecolor.green = (c/0x100)&0xff; - map->imagecolor.blue = c&0xff; - } - - /* value of time can be empty. We should look for a default value */ - /* see function msWMSApplyTime */ - else if (strcasecmp(names[i], "TIME") == 0) { /* && values[i]) */ - stime = values[i]; - timerequest = true; - } - /* Vendor-specific ANGLE param (for map rotation), added in ticket #3332, - * also supported by GeoServer - */ - else if (strcasecmp(names[i], "ANGLE") == 0) { - msMapSetRotation(map, atof(values[i])); - } - /* Vendor-specific bbox_pixel_is_point, added in ticket #4652 */ - else if (strcasecmp(names[i], "BBOX_PIXEL_IS_POINT") == 0) { - bbox_pixel_is_point = (strcasecmp(values[i], "TRUE") == 0); - } - /* Vendor-specific FILTER, added in RFC-118 */ - else if (strcasecmp(names[i], "FILTER") == 0) { - filter = values[i]; - } - } - - /*validate the exception format WMS 1.3.0 section 7.3.3.11*/ - - if (nVersion >= OWS_1_3_0 && wms_exception_format != NULL) { - if (strcasecmp(wms_exception_format, "INIMAGE") != 0 && - strcasecmp(wms_exception_format, "BLANK") != 0 && - strcasecmp(wms_exception_format, "XML") != 0) { - msSetError(MS_WMSERR, - "Invalid format %s for the EXCEPTIONS parameter.", - "msWMSLoadGetMapParams()", wms_exception_format); - return msWMSException(map, nVersion, "InvalidFormat", wms_exception_format); - } - } - - int need_axis_swap = MS_FALSE; - if (bboxfound && nVersion >= OWS_1_3_0) { - rectObj rect; - projectionObj proj; - - /*we have already validated that the request format when reding - the request parameters*/ - rect = map->extent; - - /*try to adjust the axes if necessary*/ - if (srsbuffer.size() > 1) { - msInitProjection(&proj); - msProjectionInheritContextFrom(&proj, &(map->projection)); - if (msLoadProjectionStringEPSG(&proj, srsbuffer.c_str()) == 0 && - (need_axis_swap = msIsAxisInvertedProj(&proj) ) ) { - msAxisNormalizePoints( &proj, 1, &rect.minx, &rect.miny ); - msAxisNormalizePoints( &proj, 1, &rect.maxx, &rect.maxy ); - } - msFreeProjection( &proj ); - } - /*if the CRS is AUTO2:auto_crs_id,factor,lon0,lat0, - we need to grab the factor patameter and use it with the bbox*/ - if (srsbuffer.size() > 1 && strncasecmp(srsbuffer.c_str(), "AUTO2:", 6) == 0) { - const auto args = msStringSplit(srsbuffer.c_str(), ','); - if (args.size() == 4) { - const double factor = atof(args[1].c_str()); - if (factor > 0 && factor != 1.0) { - rect.minx = rect.minx*factor; - rect.miny = rect.miny*factor; - rect.maxx = rect.maxx*factor; - rect.maxx = rect.maxy*factor; - } - } - } - - map->extent = rect; - - /* validate bbox values */ - if ( map->extent.minx >= map->extent.maxx || - map->extent.miny >= map->extent.maxy) { - msSetError(MS_WMSERR, - "Invalid values for BBOX.", - "msWMSLoadGetMapParams()"); - return msWMSException(map, nVersion, NULL, wms_exception_format); - } - adjust_extent = true; - } - - /* - ** If any select layers have a default time, we will apply the default - ** time value even if no TIME request was in the url. - */ - if( !timerequest && map ) { - for (int i=0; inumlayers && !timerequest; i++) { - layerObj *lp = NULL; - - lp = (GET_LAYER(map, i)); - if (lp->status != MS_ON && lp->status != MS_DEFAULT) - continue; - - if( msOWSLookupMetadata(&(lp->metadata), "MO", "timedefault") ) - timerequest = true; - } - } - - /* - ** Apply time filters if available in the request. - */ - if (timerequest) { - if (msWMSApplyTime(map, nVersion, stime, wms_exception_format) == MS_FAILURE) { - return MS_FAILURE;/* msWMSException(map, nVersion, "InvalidTimeRequest"); */ - } - } - - /* - ** Check/apply wms dimensions - ** all dimension requests shoul start with dim_xxxx, except time and elevation. - */ - for (int i=0; inumlayers; i++) { - layerObj *lp = (GET_LAYER(map, i)); - if (lp->status != MS_ON && lp->status != MS_DEFAULT) - continue; - - const char* dimensionlist = msOWSLookupMetadata(&(lp->metadata), "M", "dimensionlist"); - if (dimensionlist) { - auto tokens = msStringSplit(dimensionlist, ','); - for (auto& token: tokens) { - msStringTrim(token); - for(int k=0; kmap, nVersion, "InvalidDimensionValue", wms_exception_format); - } - break; - } - } - } - } - } - - /* - ** Apply the selected output format (if one was selected), and override - ** the transparency if needed. - */ - - if( format != NULL ) - msApplyOutputFormat( &(map->outputformat), format, transparent, - MS_NOOVERRIDE, MS_NOOVERRIDE ); - - /* Validate all layers given. - ** If an invalid layer is sent, return an exception. - */ - if (validlayers == 0 || invalidlayers > 0) { - if (invalidlayers > 0) { - msSetError(MS_WMSERR, "Invalid layer(s) given in the LAYERS parameter. A layer might be disabled for \ -this request. Check wms/ows_enable_request settings.", - "msWMSLoadGetMapParams()"); - return msWMSException(map, nVersion, "LayerNotDefined", wms_exception_format); - } - if (validlayers == 0 && sld_url == NULL && sld_body == NULL) { - msSetError(MS_WMSERR, "Missing required parameter LAYERS", "msWMSLoadGetMapParams()"); - return msWMSException(map, nVersion, "MissingParameterValue", wms_exception_format); - } - } - - /* validate srs value: When the SRS parameter in a GetMap request contains a - ** SRS that is valid for some, but not all of the layers being requested, - ** then the server shall throw a Service Exception (code = "InvalidSRS"). - ** Validate first against epsg in the map and if no matching srs is found - ** validate all layers requested. - */ - if (epsgbuf.size() >= 2) { /*at least 2 chars*/ - char *projstring; - epsgvalid = false; - msOWSGetEPSGProj(&(map->projection), &(map->web.metadata), - "MO", MS_FALSE, &projstring); - if (projstring) { - const auto tokens = msStringSplit(projstring, ' '); - for( const auto& token: tokens) { - if (strcasecmp(token.c_str(), epsgbuf.c_str()) == 0) { - epsgvalid = true; - break; - } - } - msFree(projstring); - } - if (!epsgvalid) { - for (int i=0; inumlayers; i++) { - epsgvalid = false; - if (GET_LAYER(map, i)->status == MS_ON) { - msOWSGetEPSGProj(&(GET_LAYER(map, i)->projection), - &(GET_LAYER(map, i)->metadata), - "MO", MS_FALSE, &projstring); - if (projstring) { - const auto tokens = msStringSplit(projstring, ' '); - for( const auto& token: tokens) { - if (strcasecmp(token.c_str(), epsgbuf.c_str()) == 0) { - epsgvalid = true; - break; - } - } - msFree(projstring); - } - if (!epsgvalid) { - if (nVersion >= OWS_1_3_0) { - msSetError(MS_WMSERR, "Invalid CRS given : CRS must be valid for all requested layers.", - "msWMSLoadGetMapParams()"); - return msWMSException(map, nVersion, "InvalidSRS", wms_exception_format); - } else { - msSetError(MS_WMSERR, "Invalid SRS given : SRS must be valid for all requested layers.", - "msWMSLoadGetMapParams()"); - return msWMSException(map, nVersion, "InvalidSRS", wms_exception_format); - } - } - } - } - } - } - - /* Validate requested image size. - */ - if(map->width > map->maxsize || map->height > map->maxsize || - map->width < 1 || map->height < 1) { - msSetError(MS_WMSERR, "Image size out of range, WIDTH and HEIGHT must be between 1 and %d pixels.", "msWMSLoadGetMapParams()", map->maxsize); - - /* Restore valid default values in case errors INIMAGE are used */ - map->width = 400; - map->height= 300; - return msWMSException(map, nVersion, NULL, wms_exception_format); - } - - /* Check whether requested BBOX and width/height result in non-square pixels - */ - nonsquare_enabled = msTestConfigOption( map, "MS_NONSQUARE", MS_FALSE ) != MS_FALSE; - if (!nonsquare_enabled) { - const double dx = MS_ABS(map->extent.maxx - map->extent.minx); - const double dy = MS_ABS(map->extent.maxy - map->extent.miny); - - const double reqy = ((double)map->width) * dy / dx; - - /* Allow up to 1 pixel of error on the width/height ratios. */ - /* If more than 1 pixel then enable non-square pixels */ - if ( MS_ABS((reqy - (double)map->height)) > 1.0 ) { - if (map->debug) - msDebug("msWMSLoadGetMapParams(): enabling non-square pixels.\n"); - msSetConfigOption(map, "MS_NONSQUARE", "YES"); - nonsquare_enabled = true; - } - } - - /* If the requested SRS is different from the default mapfile projection, or - ** if a BBOX resulting in non-square pixels is requested then - ** copy the original mapfile's projection to any layer that doesn't already - ** have a projection. This will prevent problems when users forget to - ** explicitly set a projection on all layers in a WMS mapfile. - */ - if (srsbuffer.size() > 1 || nonsquare_enabled) { - projectionObj newProj; - - if (map->projection.numargs <= 0) { - if (nVersion >= OWS_1_3_0) { - msSetError(MS_WMSERR, "Cannot set new CRS on a map that doesn't " - "have any projection set. Please make sure your mapfile " - "has a projection defined at the top level.", - "msWMSLoadGetMapParams()"); - return msWMSException(map, nVersion, "InvalidCRS", wms_exception_format); - } else { - msSetError(MS_WMSERR, "Cannot set new SRS on a map that doesn't " - "have any projection set. Please make sure your mapfile " - "has a projection defined at the top level.", - "msWMSLoadGetMapParams()"); - return msWMSException(map, nVersion, "InvalidSRS", wms_exception_format); - } - } - - msInitProjection(&newProj); - msProjectionInheritContextFrom(&newProj, &map->projection); - if (srsbuffer.size() > 1) { - int nTmp; - - if (nVersion >= OWS_1_3_0) - nTmp = msLoadProjectionStringEPSG(&newProj, srsbuffer.c_str()); - else - nTmp = msLoadProjectionString(&newProj, srsbuffer.c_str()); - if (nTmp != 0) { - msFreeProjection(&newProj); - return msWMSException(map, nVersion, NULL, wms_exception_format); - } - } - - if (nonsquare_enabled || - msProjectionsDiffer(&(map->projection), &newProj)) { - msMapSetLayerProjections(map); - } - msFreeProjection(&newProj); - } - - /* apply the srs to the map file. This is only done after validating */ - /* that the srs given as parameter is valid for all layers */ - if (srsbuffer.size() > 1) { - int nTmp; - msFreeProjectionExceptContext(&map->projection); - if (nVersion >= OWS_1_3_0) - nTmp = msLoadProjectionStringEPSG(&(map->projection), srsbuffer.c_str()); - else - nTmp = msLoadProjectionString(&(map->projection), srsbuffer.c_str()); - - if (nTmp != 0) - return msWMSException(map, nVersion, NULL, wms_exception_format); - - nTmp = GetMapserverUnitUsingProj(&(map->projection)); - if( nTmp != -1 ) { - map->units = static_cast(nTmp); - } - } - - if (sld_url || sld_body) { - char *pszLayerNames = NULL; - const int nLayersBefore = map->numlayers; - - /* -------------------------------------------------------------------- */ - /* if LAYERS parameter was not given, set all layers to off */ - /* -------------------------------------------------------------------- */ - if (validlayers == 0) { /*no LAYERS parameter is give*/ - for(int j=0; jnumlayers; j++) { - if (GET_LAYER(map, j)->status != MS_DEFAULT) - GET_LAYER(map, j)->status = MS_OFF; - } - } - - /*apply sld if defined. This is done here so that bbox and srs are already applied*/ - if (sld_url) { - if ((status = msSLDApplySLDURL(map, sld_url, -1, NULL, &pszLayerNames)) != MS_SUCCESS) - return msWMSException(map, nVersion, NULL, wms_exception_format); - } else if (sld_body) { - if ((status =msSLDApplySLD(map, sld_body, -1, NULL, &pszLayerNames)) != MS_SUCCESS) - return msWMSException(map, nVersion, NULL, wms_exception_format); - } - /* -------------------------------------------------------------------- */ - /* SLD and styles can use the same layer multiple times. If */ - /* that is the case we duplicate the layer for drawing */ - /* purpose. We need to reset the ows request enable settings (#1602)*/ - /* -------------------------------------------------------------------- */ - const int nLayerAfter = map->numlayers; - if (nLayersBefore != nLayerAfter) { - msOWSRequestLayersEnabled(map, "M", "GetMap", ows_request); - } - - /* -------------------------------------------------------------------- */ - /* We need to take into account where the LAYERS parameter was */ - /* not given (the LAYERS is option when an SLD is given). In */ - /* this particular case, we need to turn on the layers */ - /* identified the SLD (#1166). */ - /* */ - /* -------------------------------------------------------------------- */ - if (validlayers == 0) { - if (pszLayerNames) { - const auto tokens = msStringSplit(pszLayerNames, ','); - for (const auto& token: tokens) { - for (int j=0; jnumlayers; j++) { - if ( ((GET_LAYER(map, j)->name && - strcasecmp(GET_LAYER(map, j)->name, token.c_str()) == 0) || - (map->name && strcasecmp(map->name, token.c_str()) == 0) || - (GET_LAYER(map, j)->group && strcasecmp(GET_LAYER(map, j)->group, token.c_str()) == 0)) && - ((msIntegerInArray(GET_LAYER(map, j)->index, ows_request->enabled_layers, ows_request->numlayers))) ) { - if (GET_LAYER(map, j)->status != MS_DEFAULT) - GET_LAYER(map, j)->status = MS_ON; - } - } - } - } - } - msFree(pszLayerNames); - - } - - /* Validate Styles : - ** MapServer advertize styles through th group setting in a class object. - ** If no styles are set MapServer expects to have empty values - ** for the styles parameter (...&STYLES=&...) Or for multiple Styles/Layers, - ** we could have ...&STYLES=,,,. If that is not the - ** case, we generate an exception. - */ - if(styles && strlen(styles) > 0) { - bool hasCheckedLayerUnicity = false; - int n=0; - char** tokens = msStringSplitComplex(styles, ",",&n,MS_ALLOWEMPTYTOKENS); - for (int i=0; i 0 && - strcasecmp(tokens[i],"default") != 0) { - if (!hasCheckedLayerUnicity) { - hasCheckedLayerUnicity = true; - bool bLayerInserted = false; - - /* -------------------------------------------------------------------- */ - /* If the same layer is given more that once, we need to */ - /* duplicate it. */ - /* -------------------------------------------------------------------- */ - for (size_t m=0; mvtable) - msInitializeVirtualTable(psTmpLayer); - - /*make the name unique*/ - char tmpId[128]; - snprintf(tmpId, sizeof(tmpId), "%lx_%x_%d",(long)time(NULL),(int)getpid(), - map->numlayers); - if (psTmpLayer->name) - msFree(psTmpLayer->name); - psTmpLayer->name = msStrdup(tmpId); - wmslayers[l] = tmpId; - msInsertLayer(map, psTmpLayer, -1); - bLayerInserted = true; - /* layer was copied, we need to decrement its refcount */ - MS_REFCNT_DECR(psTmpLayer); - } - } - } - - if (bLayerInserted) { - msOWSRequestLayersEnabled(map, "M", "GetMap", ows_request); - } - } - - if (static_cast(wmslayers.size()) == n) { - for (int j=0; jnumlayers; j++) { - layerObj* lp = GET_LAYER(map, j); - if ((lp->name && - strcasecmp(lp->name, wmslayers[i].c_str()) == 0) || - (lp->group && strcasecmp(lp->group, wmslayers[i].c_str()) == 0)) { - bool found = false; - for (int k=0; knumclasses; k++) { - if (lp->_class[k]->group && strcasecmp(lp->_class[k]->group, tokens[i]) == 0) { - msFree(lp->classgroup); - lp->classgroup = msStrdup( tokens[i]); - found = true; - break; - } - } - if (!found) { - msSetError(MS_WMSERR, "Style (%s) not defined on layer.", - "msWMSLoadGetMapParams()", tokens[i]); - msFreeCharArray(tokens, n); - - return msWMSException(map, nVersion, "StyleNotDefined", wms_exception_format); - } - /* Check the style of the root layer */ - } else if (map->name && strcasecmp(map->name, wmslayers[i].c_str()) == 0) { - const char* styleName = msOWSLookupMetadata(&(map->web.metadata), "MO", "style_name"); - if (styleName == NULL) - styleName = "default"; - char* pszEncodedStyleName = msEncodeHTMLEntities(styleName); - if (strcasecmp(pszEncodedStyleName, tokens[i]) != 0) { - msSetError(MS_WMSERR, "Style (%s) not defined on root layer.", - "msWMSLoadGetMapParams()", tokens[i]); - msFreeCharArray(tokens, n); - msFree(pszEncodedStyleName); - - return msWMSException(map, nVersion, "StyleNotDefined", wms_exception_format); - } - msFree(pszEncodedStyleName); - } - - } - } else { - msSetError(MS_WMSERR, "Invalid style (%s). Mapserver is expecting an empty string for the STYLES : STYLES= or STYLES=,,, or using keyword default STYLES=default,default, ...", - "msWMSLoadGetMapParams()", styles); - msFreeCharArray(tokens, n); - return msWMSException(map, nVersion, "StyleNotDefined", wms_exception_format); - } - } - } - msFreeCharArray(tokens, n); - } - - /* - ** WMS extents are edge to edge while MapServer extents are center of - ** pixel to center of pixel. Here we try to adjust the WMS extents - ** in by half a pixel. We wait till here because we want to ensure we - ** are doing this in terms of the correct WIDTH and HEIGHT. - */ - if( adjust_extent && map->width>1 && map->height>1 && !bbox_pixel_is_point) { - double dx, dy; - - dx = (map->extent.maxx - map->extent.minx) / map->width; - map->extent.minx += dx*0.5; - map->extent.maxx -= dx*0.5; - - dy = (map->extent.maxy - map->extent.miny) / map->height; - map->extent.miny += dy*0.5; - map->extent.maxy -= dy*0.5; - } - - if (request && strcasecmp(request, "DescribeLayer") != 0) { - if (!srsfound) { - if ( nVersion >= OWS_1_3_0) - msSetError(MS_WMSERR, "Missing required parameter CRS", "msWMSLoadGetMapParams()"); - else - msSetError(MS_WMSERR, "Missing required parameter SRS", "msWMSLoadGetMapParams()"); - - return msWMSException(map, nVersion, "MissingParameterValue", wms_exception_format); - } - - if (!bboxfound) { - msSetError(MS_WMSERR, "Missing required parameter BBOX", "msWMSLoadGetMapParams()"); - return msWMSException(map, nVersion, "MissingParameterValue", wms_exception_format); - } - - if (!formatfound && (strcasecmp(request, "GetMap") == 0 || strcasecmp(request, "map") == 0)) { - msSetError(MS_WMSERR, "Missing required parameter FORMAT", "msWMSLoadGetMapParams()"); - return msWMSException(map, nVersion, "MissingParameterValue", wms_exception_format); - } - - if (!widthfound) { - msSetError(MS_WMSERR, "Missing required parameter WIDTH", "msWMSLoadGetMapParams()"); - return msWMSException(map, nVersion, "MissingParameterValue", wms_exception_format); - } - - if (!heightfound) { - msSetError(MS_WMSERR, "Missing required parameter HEIGHT", "msWMSLoadGetMapParams()"); - return msWMSException(map, nVersion, "MissingParameterValue", wms_exception_format); - } - - if (styles == nullptr && sld_url == nullptr && sld_body == nullptr && - (strcasecmp(request, "GetMap") == 0 || - strcasecmp(request, "GetFeatureInfo") == 0) && - msOWSLookupMetadata(&(map->web.metadata), "M", - "allow_getmap_without_styles") == nullptr) { - msSetError(MS_WMSERR, - "Missing required parameter STYLES. Note to service administrators: " - "defining the \"wms_allow_getmap_without_styles\" \"true\" MAP.WEB.METADATA " - "item will disable this check (backward compatibility with behaviour " - "of MapServer < 8.0)", "msWMSLoadGetMapParams()"); - return msWMSException(map, nVersion, "MissingParameterValue", wms_exception_format); - } - } - - /* - ** Apply vendor-specific filter if specified - */ - if (filter) { - if (sld_url || sld_body) { - msSetError(MS_WMSERR, - "Vendor-specific FILTER parameter cannot be used with SLD or SLD_BODY.", - "msWMSLoadGetMapParams()"); - return msWMSException(map, nVersion, NULL, wms_exception_format); - } - - if (msWMSApplyFilter(map, nVersion, filter, need_axis_swap, wms_exception_format, ows_request) == MS_FAILURE) { - return MS_FAILURE;/* msWMSException(map, nVersion, "InvalidFilterRequest"); */ - } - } - - return MS_SUCCESS; -} - -/* -** -*/ -static void msWMSPrintRequestCap(int nVersion, const char *request, - const char *script_url, const char *formats, ...) -{ - va_list argp; - - msIO_printf(" <%s>\n", request); - - /* We expect to receive a NULL-terminated args list of formats */ - va_start(argp, formats); - const char* fmt = formats; - while(fmt != NULL) { - /* Special case for early WMS with subelements in Format (bug 908) */ - char *encoded; - if( nVersion <= OWS_1_0_7 ) { - encoded = msStrdup( fmt ); - } - - /* otherwise we HTML code special characters */ - else { - encoded = msEncodeHTMLEntities(fmt); - } - - msIO_printf(" %s\n", encoded); - msFree(encoded); - - fmt = va_arg(argp, const char *); - } - va_end(argp); - - msIO_printf(" \n"); - msIO_printf(" \n"); - /* The URL should already be HTML encoded. */ - if (nVersion == OWS_1_0_0) { - msIO_printf(" \n", script_url); - msIO_printf(" \n", script_url); - } else { - msIO_printf(" \n", script_url); - msIO_printf(" \n", script_url); - } - - msIO_printf(" \n"); - msIO_printf(" \n"); - msIO_printf(" \n", request); -} - - - -void msWMSPrintAttribution(FILE *stream, const char *tabspace, - hashTableObj *metadata, - const char *namespaces) -{ - if (stream && metadata) { - const char* title = msOWSLookupMetadata(metadata, "MO", - "attribution_title"); - const char* onlineres = msOWSLookupMetadata(metadata, "MO", - "attribution_onlineresource"); - const char* logourl = msOWSLookupMetadata(metadata, "MO", - "attribution_logourl_width"); - - if (title || onlineres || logourl) { - msIO_printf("%s\n",tabspace); - if (title) { - char* pszEncodedValue = msEncodeHTMLEntities(title); - msIO_fprintf(stream, "%s%s%s\n", tabspace, - tabspace, pszEncodedValue); - free(pszEncodedValue); - } - - if (onlineres) { - char* pszEncodedValue = msEncodeHTMLEntities(onlineres); - msIO_fprintf(stream, "%s%s\n", tabspace, tabspace, - pszEncodedValue); - free(pszEncodedValue); - } - - if (logourl) { - msOWSPrintURLType(stream, metadata, "MO","attribution_logourl", - OWS_NOERR, NULL, "LogoURL", NULL, - " width=\"%s\"", " height=\"%s\"", - ">\n %s\n" - " ", - MS_FALSE, MS_TRUE, MS_TRUE, MS_TRUE, MS_TRUE, - NULL, NULL, NULL, NULL, NULL, " "); - - - } - msIO_printf("%s\n", tabspace); - - } - } -} - - -/* -** msWMSPrintScaleHint() -** -** Print a Min/MaxScaleDenominator tag for the layer if applicable. -** used for WMS >=1.3.0 -*/ -void msWMSPrintScaleDenominator(const char *tabspace, double minscaledenom, - double maxscaledenom) -{ - if (minscaledenom > 0) - msIO_printf("%s%g\n", - tabspace, minscaledenom); - - if (maxscaledenom > 0) - msIO_printf("%s%g\n", - tabspace, maxscaledenom); -} - - - -/* -** msWMSPrintScaleHint() -** -** Print a ScaleHint tag for this layer if applicable. -** -** (see WMS 1.1.0 sect. 7.1.5.4) The WMS defines the scalehint values as -** the ground distance in meters of the southwest to northeast diagonal of -** the central pixel of a map. ScaleHint values are the min and max -** recommended values of that diagonal. -*/ -void msWMSPrintScaleHint(const char *tabspace, double minscaledenom, - double maxscaledenom, double resolution) -{ - double scalehintmin=0.0, scalehintmax=0.0; - - const double diag = sqrt(2.0); - - if (minscaledenom > 0) - scalehintmin = diag*(minscaledenom/resolution)/msInchesPerUnit(MS_METERS,0); - if (maxscaledenom > 0) - scalehintmax = diag*(maxscaledenom/resolution)/msInchesPerUnit(MS_METERS,0); - - if (scalehintmin > 0.0 || scalehintmax > 0.0) { - msIO_printf("%s\n", - tabspace, scalehintmin, scalehintmax); - if (scalehintmax == 0.0) - msIO_printf("%s\n", - tabspace); - } -} - -/* -** msWMSPrintAuthorityURL() -** -** Print an AuthorityURL tag if applicable. -*/ -void msWMSPrintAuthorityURL(FILE *stream, const char *tabspace, - hashTableObj *metadata, const char *namespaces) -{ - if (stream && metadata) { - const char* pszWmsAuthorityName = msOWSLookupMetadata(metadata, namespaces, "authorityurl_name"); - const char* pszWMSAuthorityHref = msOWSLookupMetadata(metadata, namespaces, "authorityurl_href"); - - /* AuthorityURL only makes sense if you have *both* the name and url */ - if( pszWmsAuthorityName && pszWMSAuthorityHref ) { - msOWSPrintEncodeMetadata(stream, metadata, namespaces, "authorityurl_name", - OWS_NOERR, - (std::string(tabspace) + "\n").c_str(), - NULL); - msOWSPrintEncodeMetadata(stream, metadata, namespaces, "authorityurl_href", - OWS_NOERR, - (std::string(tabspace) + " \n").c_str(), - NULL); - msIO_printf("%s\n", tabspace); - } else if ( pszWmsAuthorityName || pszWMSAuthorityHref ) { - msIO_printf("%s\n", tabspace); - } - } -} - -/* -** msWMSPrintIdentifier() -** -** Print an Identifier tag if applicable. -*/ -void msWMSPrintIdentifier(FILE *stream, const char *tabspace, - hashTableObj *metadata, const char *namespaces) -{ - if (stream && metadata) { - const char* pszWMSIdentifierAuthority = msOWSLookupMetadata(metadata, namespaces, "identifier_authority"); - const char* pszWMSIdentifierValue = msOWSLookupMetadata(metadata, namespaces, "identifier_value"); - - /* Identifier only makes sense if you have *both* the authority and value */ - if( pszWMSIdentifierAuthority && pszWMSIdentifierValue ) { - msOWSPrintEncodeMetadata(stream, metadata, namespaces, "identifier_authority", - OWS_NOERR, - (std::string(tabspace) + "").c_str(), - NULL); - msOWSPrintEncodeMetadata(stream, metadata, namespaces, "identifier_value", - OWS_NOERR, "%s\n", - NULL); - } else if ( pszWMSIdentifierAuthority || pszWMSIdentifierValue ) { - msIO_printf("%s\n", tabspace); - } - } -} - -/* -** msWMSPrintKeywordlist() -** -** Print a Keywordlist tag if applicable. -*/ -void msWMSPrintKeywordlist(FILE *stream, const char *tabspace, - const char *name, hashTableObj *metadata, - const char *namespaces, int nVersion) -{ - std::string newname(name); /* max. rootlayer_keywordlist_items */ - newname += "_items"; - - std::string vocname(name); /* max. rootlayer_keywordlist_vocabulary */ - vocname += "_vocabulary"; - - if (nVersion == OWS_1_0_0) { - /* in V 1.0.0 */ - /* The 1.0.0 spec doesn't specify which delimiter to use so let's use spaces */ - msOWSPrintEncodeMetadataList(stream, metadata, namespaces, - name, - (std::string(tabspace) + "").c_str(), - (std::string(tabspace) + "\n").c_str(), - "%s ", NULL); - } else if ( msOWSLookupMetadata(metadata, namespaces, name) || - msOWSLookupMetadata(metadata, namespaces, newname.c_str()) || - msOWSLookupMetadata(metadata, namespaces, vocname.c_str()) ) { - /* ... in V1.0.6+ */ - msIO_printf("%s\n", tabspace); - std::string template1(tabspace); - template1 += " %s\n"; - /* print old styled ..._keywordlist */ - msOWSPrintEncodeMetadataList(stream, metadata, namespaces, - name, NULL, NULL, - template1.c_str(), NULL); - /* print new styled ..._keywordlist_items */ - msOWSPrintEncodeMetadataList(stream, metadata, namespaces, - newname.c_str(), NULL, NULL, - template1.c_str(), NULL); - - /* find out if there's a vocabulary list set */ - const char* vocabularylist = msOWSLookupMetadata(metadata, namespaces, vocname.c_str()); - if ( vocabularylist && nVersion >= OWS_1_3_0 ) { - const auto tokens = msStringSplit(vocabularylist, ','); - for (const auto& token: tokens) { - msOWSPrintEncodeMetadataList( - stream, metadata, namespaces, - (std::string(name) + '_' + token + "_items").c_str(), - NULL, NULL, - (std::string(tabspace) + " %s\n").c_str(), - NULL); - } - } - msIO_printf("%s\n", tabspace); - } -} - -/* -** msDumpLayer() -*/ -static -int msDumpLayer(mapObj *map, layerObj *lp, int nVersion, - const char *script_url_encoded, const char *indent, - const char *validated_language, int grouplayer, - int hasQueryableSubLayers) -{ - rectObj ext; - char **classgroups = NULL; - int iclassgroups=0; - char *pszMapEPSG,*pszLayerEPSG; - - /* if the layer status is set to MS_DEFAULT, output a warning */ - if (lp->status == MS_DEFAULT) - msIO_fprintf(stdout, "\n"); - - if (nVersion <= OWS_1_0_7) { - msIO_printf("%s \n", - indent, hasQueryableSubLayers || msIsLayerQueryable(lp)); - } else { - /* 1.1.0 and later: opaque and cascaded are new. */ - int cascaded=0, opaque=0; - const char* value = msOWSLookupMetadata(&(lp->metadata), "MO", "opaque"); - if (value != NULL) - opaque = atoi(value); - if (lp->connectiontype == MS_WMS) - cascaded = 1; - - msIO_printf("%s \n", - indent, hasQueryableSubLayers || msIsLayerQueryable(lp), opaque, cascaded); - } - - if (lp->name && strlen(lp->name) > 0 && - (msIsXMLTagValid(lp->name) == MS_FALSE || isdigit(lp->name[0]))) - msIO_fprintf(stdout, "\n", - lp->name); - msOWSPrintEncodeParam(stdout, "LAYER.NAME", lp->name, OWS_NOERR, - " %s\n", NULL); - - /* the majority of this section is dependent on appropriately named metadata in the LAYER object */ - msOWSPrintEncodeMetadata2(stdout, &(lp->metadata), "MO", "title", - OWS_WARN, " %s\n", lp->name, validated_language); - - msOWSPrintEncodeMetadata2(stdout, &(lp->metadata), "MO", "abstract", - OWS_NOERR, " %s\n", NULL, validated_language); - - msWMSPrintKeywordlist(stdout, " ", "keywordlist", &(lp->metadata), "MO", nVersion); - - msOWSGetEPSGProj(&(map->projection),&(map->web.metadata), "MO", MS_FALSE, &pszMapEPSG); - msOWSGetEPSGProj(&(lp->projection),&(lp->metadata), "MO", MS_FALSE, &pszLayerEPSG); - if(pszMapEPSG == NULL) { - /* If map has no proj then every layer MUST have one or produce a warning */ - if (nVersion > OWS_1_1_0) { - /* starting 1.1.1 SRS are given in individual tags */ - if (nVersion >= OWS_1_3_0) { - msOWSPrintEncodeParamList(stdout, "(at least one of) " - "MAP.PROJECTION, LAYER.PROJECTION " - "or wms_srs metadata", - pszLayerEPSG, - OWS_WARN, ' ', NULL, NULL, - " %s\n", NULL); - } - else { - msOWSPrintEncodeParamList(stdout, "(at least one of) " - "MAP.PROJECTION, LAYER.PROJECTION " - "or wms_srs metadata", - pszLayerEPSG, - OWS_WARN, ' ', NULL, NULL, - " %s\n", NULL); - } - } else { - msOWSPrintEncodeParam(stdout, "(at least one of) MAP.PROJECTION, " - "LAYER.PROJECTION or wms_srs metadata", - pszLayerEPSG, - OWS_WARN, " %s\n", NULL); - } - } else { - /* No warning required in this case since there's at least a map proj. */ - if (nVersion > OWS_1_1_0) { - /* starting 1.1.1 SRS are given in individual tags */ - if (nVersion >= OWS_1_3_0) { - msOWSPrintEncodeParamList(stdout, "(at least one of) " - "MAP.PROJECTION, LAYER.PROJECTION " - "or wms_srs metadata", - pszLayerEPSG, - OWS_NOERR, ' ', NULL, NULL, - " %s\n", NULL); - } else { - msOWSPrintEncodeParamList(stdout, "(at least one of) " - "MAP.PROJECTION, LAYER.PROJECTION " - "or wms_srs metadata", - pszLayerEPSG, - OWS_NOERR, ' ', NULL, NULL, - " %s\n", NULL); - } - } else { - msOWSPrintEncodeParam(stdout, - " LAYER.PROJECTION (or wms_srs metadata)", - pszLayerEPSG, - OWS_NOERR, " %s\n", NULL); - } - } - msFree(pszLayerEPSG); - msFree(pszMapEPSG); - - /* If layer has no proj set then use map->proj for bounding box. */ - if (msOWSGetLayerExtent(map, lp, "MO", &ext) == MS_SUCCESS) { - if(lp->projection.numargs > 0) { - if (nVersion >= OWS_1_3_0) - msOWSPrintEX_GeographicBoundingBox(stdout, " ", &(ext), - &(lp->projection)); - else - msOWSPrintLatLonBoundingBox(stdout, " ", &(ext), - &(lp->projection), NULL, OWS_WMS); - - msOWSPrintBoundingBox( stdout," ", &(ext), &(lp->projection), - &(lp->metadata), &(map->web.metadata), "MO", nVersion ); - } else { - if (nVersion >= OWS_1_3_0) - msOWSPrintEX_GeographicBoundingBox(stdout, " ", &(ext), - &(map->projection)); - else - msOWSPrintLatLonBoundingBox(stdout, " ", &(ext), - &(map->projection), NULL, OWS_WMS); - msOWSPrintBoundingBox(stdout," ", &(ext), &(map->projection), - &(lp->metadata), &(map->web.metadata), "MO", nVersion ); - } - } else { - if (nVersion >= OWS_1_3_0) - msIO_printf(" \n"); - else - msIO_printf(" \n"); - } - - /* time support */ - const char* pszWmsTimeExtent = msOWSLookupMetadata(&(lp->metadata), "MO", "timeextent"); - if (pszWmsTimeExtent) { - const char* pszWmsTimeDefault = msOWSLookupMetadata(&(lp->metadata), "MO", - "timedefault"); - - if (nVersion >= OWS_1_3_0) { - if (pszWmsTimeDefault) - msIO_fprintf(stdout, " %s\n",pszWmsTimeDefault, pszWmsTimeExtent); - else - msIO_fprintf(stdout, " %s\n",pszWmsTimeExtent); - } - - else { - msIO_fprintf(stdout, " \n"); - if (pszWmsTimeDefault) - msIO_fprintf(stdout, " %s\n",pszWmsTimeDefault, pszWmsTimeExtent); - else - msIO_fprintf(stdout, " %s\n",pszWmsTimeExtent); - } - } - - /*dimensions support: elevation + other user defined dimensions*/ - const char* pszDimensionlist = msOWSLookupMetadata(&(lp->metadata), "M", "dimensionlist"); - if (pszDimensionlist) { - auto tokens = msStringSplit(pszDimensionlist, ','); - for( auto& dimension: tokens ) { - /*check if manadatory unit and extent are set. Item should also be set. default value is optional*/ - msStringTrim(dimension); - - const char* pszDimensionItem = msOWSLookupMetadata( - &(lp->metadata), "M", (dimension + "_item").c_str()); - const char* pszDimensionExtent = msOWSLookupMetadata( - &(lp->metadata), "M", (dimension + "_extent").c_str()); - const char* pszDimensionUnit = msOWSLookupMetadata( - &(lp->metadata), "M", (dimension + "_units").c_str()); - const char* pszDimensionDefault = msOWSLookupMetadata( - &(lp->metadata), "M", (dimension + "_default").c_str()); - - if (pszDimensionItem && pszDimensionExtent && pszDimensionUnit) { - if (nVersion >= OWS_1_3_0) { - if(pszDimensionDefault && strlen(pszDimensionDefault) > 0) - msIO_fprintf(stdout, " %s\n", - dimension.c_str(), pszDimensionUnit, pszDimensionDefault, pszDimensionExtent); - else - msIO_fprintf(stdout, " %s\n", - dimension.c_str(), pszDimensionUnit, pszDimensionExtent); - } else { - msIO_fprintf(stdout, " \n", dimension.c_str(), pszDimensionUnit); - if(pszDimensionDefault && strlen(pszDimensionDefault) > 0) - msIO_fprintf(stdout, " %s\n", - dimension.c_str(), pszDimensionDefault, pszDimensionExtent); - else - msIO_fprintf(stdout, " %s\n", - dimension.c_str(), pszDimensionExtent); - } - } - } - } - - - if (nVersion >= OWS_1_0_7) { - msWMSPrintAttribution(stdout, " ", &(lp->metadata), "MO"); - } - - /* AuthorityURL support and Identifier support, only available >= WMS 1.1.0 */ - if(nVersion >= OWS_1_1_0) { - msWMSPrintAuthorityURL(stdout, " ", &(lp->metadata), "MO"); - msWMSPrintIdentifier(stdout, " ", &(lp->metadata), "MO"); - } - - if(nVersion >= OWS_1_1_0) { - const char* metadataurl_list = msOWSLookupMetadata(&(lp->metadata), "MO", "metadataurl_list"); - if( metadataurl_list ) { - const auto tokens = msStringSplit(metadataurl_list, ' '); - for( const auto& token: tokens ) - { - std::string key("metadataurl_"); - key += token; - msOWSPrintURLType(stdout, &(lp->metadata), "MO", key.c_str(), - OWS_NOERR, NULL, "MetadataURL", " type=\"%s\"", - NULL, NULL, ">\n %s\n ", - MS_TRUE, MS_FALSE, MS_FALSE, MS_TRUE, MS_TRUE, - NULL, NULL, NULL, NULL, NULL, " "); - } - } - else { - if (! msOWSLookupMetadata(&(lp->metadata), "MO", "metadataurl_href")) - msMetadataSetGetMetadataURL(lp, script_url_encoded); - - msOWSPrintURLType(stdout, &(lp->metadata), "MO", "metadataurl", - OWS_NOERR, NULL, "MetadataURL", " type=\"%s\"", - NULL, NULL, ">\n %s\n ", - MS_TRUE, MS_FALSE, MS_FALSE, MS_TRUE, MS_TRUE, - NULL, NULL, NULL, NULL, NULL, " "); - } - } - - if(nVersion < OWS_1_1_0) - msOWSPrintEncodeMetadata(stdout, &(lp->metadata), "MO", "dataurl_href", - OWS_NOERR, " %s\n", - NULL); - else { - const char* dataurl_list = msOWSLookupMetadata(&(lp->metadata), "MO", "dataurl_list"); - if( dataurl_list ) { - const auto tokens = msStringSplit(dataurl_list, ' '); - for( const auto& token: tokens ) - { - std::string key("dataurl_"); - key += token; - msOWSPrintURLType(stdout, &(lp->metadata), "MO", key.c_str(), - OWS_NOERR, NULL, "DataURL", NULL, NULL, NULL, - ">\n %s\n ", - MS_FALSE, MS_FALSE, MS_FALSE, MS_TRUE, MS_TRUE, - NULL, NULL, NULL, NULL, NULL, " "); - } - } - else { - msOWSPrintURLType(stdout, &(lp->metadata), "MO", "dataurl", - OWS_NOERR, NULL, "DataURL", NULL, NULL, NULL, - ">\n %s\n ", - MS_FALSE, MS_FALSE, MS_FALSE, MS_TRUE, MS_TRUE, - NULL, NULL, NULL, NULL, NULL, " "); - } - } - - /* The LegendURL reside in a style. The Web Map Context spec already */ - /* included the support on this in mapserver. However, it is not in the */ - /* wms_legendurl_... metadatas it's in the styles metadata, */ - /* In wms_style__lengendurl_... metadata. So we have to detect */ - /* the current style before reading it. Also in the Style block, we need */ - /* a Title and a name. Title is derived from wms_style_\n"); - - } else if(nVersion >= OWS_1_1_0) { - if (pszLegendURL) { - /* First, print the style block */ - msIO_fprintf(stdout, " \n"); - - } else { - if (script_url_encoded) { - if (lp->connectiontype != MS_WMS && - lp->connectiontype != MS_WFS && - lp->connectiontype != MS_UNUSED_1 && - lp->numclasses > 0) { - bool classnameset = false; - for (int i=0; inumclasses; i++) { - if (lp->_class[i]->name && - strlen(lp->_class[i]->name) > 0) { - classnameset = true; - break; - } - } - if (classnameset) { - int size_x=0, size_y=0; - std::vector group_layers; - group_layers.reserve(map->numlayers); - - char ***nestedGroups = (char***)msSmallCalloc(map->numlayers, sizeof(char**)); - int *numNestedGroups = (int*)msSmallCalloc(map->numlayers, sizeof(int)); - int* isUsedInNestedGroup = (int*)msSmallCalloc(map->numlayers, sizeof(int)); - msWMSPrepareNestedGroups(map, nVersion, nestedGroups, numNestedGroups, isUsedInNestedGroup); - - group_layers.push_back(lp->index); - if (isUsedInNestedGroup[lp->index]) { - for (int j=0; j < map->numlayers; j++) { - if (j == lp->index) - continue; - for(int k = 0; k < numNestedGroups[j]; k++) { - if (strcasecmp(lp->name, nestedGroups[j][k]) == 0) { - group_layers.push_back(j); - break; - } - } - } - } - - if (msLegendCalcSize(map, 1, &size_x, &size_y, group_layers.data(), static_cast(group_layers.size()), NULL, 1) == MS_SUCCESS) { - const std::string width(std::to_string(size_x)); - const std::string height(std::to_string(size_y)); - - char* mimetype = NULL; -#if defined USE_PNG - mimetype = msEncodeHTMLEntities("image/png"); -#endif - -#if defined USE_JPEG - if (!mimetype) - mimetype = msEncodeHTMLEntities("image/jpeg"); -#endif - if (!mimetype) - mimetype = msEncodeHTMLEntities(MS_IMAGE_MIME_TYPE(map->outputformat)); - - /* -------------------------------------------------------------------- */ - /* check if the group parameters for the classes are set. We */ - /* should then publish the different class groups as different styles.*/ - /* -------------------------------------------------------------------- */ - iclassgroups = 0; - classgroups = NULL; - - const char* styleName = msOWSLookupMetadata(&(map->web.metadata), "MO", "style_name"); - if (styleName == NULL) - styleName = "default"; - char* pszEncodedStyleName = msEncodeHTMLEntities(styleName); - - for (int i=0; inumclasses; i++) { - if (lp->_class[i]->name && lp->_class[i]->group) { - /* Check that style is not inherited from root layer (#4442). */ - if (strcasecmp(pszEncodedStyleName, lp->_class[i]->group) == 0) - continue; - /* Check that style is not inherited from group layer(s) (#4442). */ - if (numNestedGroups[lp->index] > 0) { - int j=0; - layerObj *lp2 = NULL; - for (; jindex]; j++) { - int l = 0; - for (int k=0; k < map->numlayers; k++) { - if (GET_LAYER(map, k)->name && strcasecmp(GET_LAYER(map, k)->name, nestedGroups[lp->index][j]) == 0) { - lp2 = (GET_LAYER(map, k)); - for (l=0; l < lp2->numclasses; l++) { - if (strcasecmp(lp2->_class[l]->group, lp->_class[i]->group) == 0) - break; - } - break; - } - } - if (lp2 && l < lp2->numclasses) - break; - } - if (j < numNestedGroups[lp->index]) - continue; - } - if (!classgroups) { - classgroups = (char **)msSmallMalloc(sizeof(char *)); - classgroups[iclassgroups++]= msStrdup(lp->_class[i]->group); - } else { - /* Output style only once. */ - bool found = false; - for (int j=0; j_class[i]->group) == 0) { - found = true; - break; - } - } - if (!found) { - iclassgroups++; - classgroups = (char **)msSmallRealloc(classgroups, sizeof(char *)*iclassgroups); - classgroups[iclassgroups-1]= msStrdup(lp->_class[i]->group); - } - } - } - } - msFree(pszEncodedStyleName); - if (classgroups == NULL) { - classgroups = (char **)msSmallMalloc(sizeof(char *)); - classgroups[0]= msStrdup("default"); - iclassgroups = 1; - } - - for (int i=0; iname); - char *classgroup_encoded = msEncodeHTMLEntities(classgroups[i]); - std::string legendurl(script_url_encoded); - legendurl += "version="; - char szVersionBuf[OWS_VERSION_MAXLEN]; - legendurl += msOWSGetVersionString(nVersion, szVersionBuf); - legendurl += "&service=WMS&request=GetLegendGraphic&"; - if (nVersion >= OWS_1_3_0) { - legendurl += "sld_version=1.1.0&layer="; - } - else { - legendurl += "layer="; - } - legendurl += name_encoded; - legendurl += "&format="; - legendurl += mimetype; - legendurl += "&STYLE="; - legendurl += classgroup_encoded; - - msFree(name_encoded); - msFree(classgroup_encoded); - - msIO_fprintf(stdout, " \n"); - } - msFreeCharArray(classgroups, iclassgroups); - msFree(mimetype); - } - /* free the stuff used for nested layers */ - for (int i = 0; i < map->numlayers; i++) { - if (numNestedGroups[i] > 0) { - msFreeCharArray(nestedGroups[i], numNestedGroups[i]); - } - } - free(nestedGroups); - free(numNestedGroups); - free(isUsedInNestedGroup); - } - } - } - } - } - - /* print Min/Max ScaleDenominator */ - if (nVersion < OWS_1_3_0) - msWMSPrintScaleHint(" ", lp->minscaledenom, lp->maxscaledenom, map->resolution); - else - msWMSPrintScaleDenominator(" ", lp->minscaledenom, lp->maxscaledenom); - - if ( grouplayer == MS_FALSE ) - msIO_printf("%s \n", indent); - - return MS_SUCCESS; -} - -/* - * msWMSIsSubGroup - */ -static bool msWMSIsSubGroup(char** currentGroups, int currentLevel, char** otherGroups, int numOtherGroups) -{ - /* no match if otherGroups[] has less levels than currentLevel */ - if (numOtherGroups <= currentLevel) { - return false; - } - /* compare all groups below the current level */ - for (int i = 0; i <= currentLevel; i++) { - if (strcmp(currentGroups[i], otherGroups[i]) != 0) { - return false; /* if one of these is not equal it is not a sub group */ - } - } - return true; -} - -/* - * msWMSHasQueryableSubLayers - */ -static int msWMSHasQueryableSubLayers(mapObj* map, int index, int level, - char*** nestedGroups, int* numNestedGroups) -{ - for (int j = index; j < map->numlayers; j++) { - if (msWMSIsSubGroup(nestedGroups[index], level, nestedGroups[j], numNestedGroups[j])) { - if( msIsLayerQueryable( GET_LAYER(map,j) ) ) - return MS_TRUE; - } - } - return MS_FALSE; -} - -/*********************************************************************************** - * msWMSPrintNestedGroups() * - * * - * purpose: Writes the layers to the capabilities that have the * - * "WMS_LAYER_GROUP" metadata set. * - * * - * params: * - * -map: The main map object * - * -nVersion: OGC WMS version * - * -pabLayerProcessed: boolean array indicating which layers have been dealt with. * - * -index: the index of the current layer. * - * -level: the level of depth in the group tree (root = 0) * - * -nestedGroups: This array holds the arrays of groups that have * - * been set through the WMS_LAYER_GROUP metadata * - * -numNestedGroups: This array holds the number of nested groups for each layer * - ***********************************************************************************/ -void msWMSPrintNestedGroups(mapObj* map, int nVersion, char* pabLayerProcessed, - int index, int level, char*** nestedGroups, int* numNestedGroups, int* isUsedInNestedGroup, const char *script_url_encoded, const char *validated_language) -{ - bool groupAdded = false; - std::string indent; - for (int i = 0; i < level; i++) { - indent += " "; - } - - if (numNestedGroups[index] <= level) { /* no more subgroups */ - if ((!pabLayerProcessed[index]) && (!isUsedInNestedGroup[index])) { - /* we are at the deepest level of the group branchings, so add layer now. */ - msDumpLayer(map, GET_LAYER(map, index), nVersion, script_url_encoded, indent.c_str(), validated_language, MS_FALSE, MS_FALSE); - pabLayerProcessed[index] = 1; /* done */ - } - } else { /* not yet there, we have to deal with this group and possible subgroups and layers. */ - int j; - for (j = 0; j < map->numlayers; j++) { - if ( GET_LAYER(map, j)->name && strcasecmp(GET_LAYER(map, j)->name, nestedGroups[index][level]) == 0 ) { - break; - } - } - - /* Beginning of a new group... enclose the group in a layer block */ - if ( j < map->numlayers ) { - if (!pabLayerProcessed[j]) { - msDumpLayer(map, GET_LAYER(map, j), nVersion, script_url_encoded, - indent.c_str(), validated_language, MS_TRUE, - msWMSHasQueryableSubLayers(map, index, level, - nestedGroups, numNestedGroups)); - pabLayerProcessed[j] = 1; /* done */ - groupAdded = true; - } - } else { - msIO_printf("%s \n", indent.c_str(), - msWMSHasQueryableSubLayers(map, index, level, - nestedGroups, numNestedGroups) ? " queryable=\"1\"" : ""); - msIO_printf("%s %s\n", indent.c_str(), nestedGroups[index][level]); - msIO_printf("%s %s\n", indent.c_str(), nestedGroups[index][level]); - groupAdded = true; - } - - /* Look for one group deeper in the current layer */ - if (!pabLayerProcessed[index]) { - msWMSPrintNestedGroups(map, nVersion, pabLayerProcessed, - index, level + 1, nestedGroups, - numNestedGroups, isUsedInNestedGroup, - script_url_encoded, validated_language); - } - - /* look for subgroups in other layers. */ - for (j = index + 1; j < map->numlayers; j++) { - if (msWMSIsSubGroup(nestedGroups[index], level, nestedGroups[j], numNestedGroups[j])) { - if (!pabLayerProcessed[j]) { - msWMSPrintNestedGroups(map, nVersion, pabLayerProcessed, - j, level + 1, nestedGroups, - numNestedGroups, isUsedInNestedGroup, - script_url_encoded, validated_language); - } - } else { - /* TODO: if we would sort all layers on "WMS_LAYER_GROUP" beforehand */ - /* we could break out of this loop at this point, which would increase */ - /* performance. */ - } - } - /* Close group layer block */ - if (groupAdded) - msIO_printf("%s \n", indent.c_str()); - } -} /* msWMSPrintNestedGroups */ - -/* -** msWMSGetCapabilities() -*/ -static -int msWMSGetCapabilities(mapObj *map, int nVersion, cgiRequestObj *req, owsRequestObj *ows_request, - const char *requested_updatesequence, const char *wms_exception_format, const char *requested_language) -{ - const char* updatesequence = msOWSLookupMetadata(&(map->web.metadata), "MO", "updatesequence"); - - const char* sldenabled = msOWSLookupMetadata(&(map->web.metadata), "MO", "sld_enabled"); - - if (sldenabled == NULL) - sldenabled = "true"; - - if (requested_updatesequence != NULL) { - int i = msOWSNegotiateUpdateSequence(requested_updatesequence, updatesequence); - if (i == 0) { /* current */ - msSetError(MS_WMSERR, "UPDATESEQUENCE parameter (%s) is equal to server (%s)", "msWMSGetCapabilities()", requested_updatesequence, updatesequence); - return msWMSException(map, nVersion, "CurrentUpdateSequence", wms_exception_format); - } - if (i > 0) { /* invalid */ - msSetError(MS_WMSERR, "UPDATESEQUENCE parameter (%s) is higher than server (%s)", "msWMSGetCapabilities()", requested_updatesequence, updatesequence); - return msWMSException(map, nVersion, "InvalidUpdateSequence", wms_exception_format); - } - } - - std::string schemalocation; - { - char* pszSchemalocation = msEncodeHTMLEntities( msOWSGetSchemasLocation(map) ); - schemalocation = pszSchemalocation; - msFree(pszSchemalocation); - } - - if (nVersion < 0) - nVersion = OWS_1_3_0; /* Default to 1.3.0 */ - - /* Decide which version we're going to return. */ - std::string dtd_url; - if (nVersion < OWS_1_0_7) { - nVersion = OWS_1_0_0; - dtd_url = schemalocation; - dtd_url += "/wms/1.0.0/capabilities_1_0_0.dtd"; - } - - else if (nVersion < OWS_1_1_0) { - nVersion = OWS_1_0_7; - dtd_url = schemalocation; - dtd_url += "/wms/1.0.7/capabilities_1_0_7.dtd"; - } else if (nVersion < OWS_1_1_1) { - nVersion = OWS_1_1_0; - dtd_url = schemalocation; - dtd_url += "/wms/1.1.0/capabilities_1_1_0.dtd"; - } else if (nVersion < OWS_1_3_0) { - nVersion = OWS_1_1_1; - dtd_url = schemalocation; - /* this exception was added to accomadote the OGC test suite (Bug 1576)*/ - if (strcasecmp(schemalocation.c_str(), OWS_DEFAULT_SCHEMAS_LOCATION) == 0) - dtd_url += "/wms/1.1.1/WMS_MS_Capabilities.dtd"; - else - dtd_url += "/wms/1.1.1/capabilities_1_1_1.dtd"; - } else - nVersion = OWS_1_3_0; - - /* This function owns validated_language, so remember to free it later*/ - std::string validated_language; - { - char* pszValidated_language = msOWSGetLanguageFromList(map, "MO", requested_language); - if( pszValidated_language ) - { - validated_language = pszValidated_language; - msMapSetLanguageSpecificConnection(map, pszValidated_language); - } - msFree(pszValidated_language); - } - - /* We need this server's onlineresource. */ - /* Default to use the value of the "onlineresource" metadata, and if not */ - /* set then build it: "http://$(SERVER_NAME):$(SERVER_PORT)$(SCRIPT_NAME)?" */ - /* the returned string should be freed once we're done with it. */ - char *script_url_encoded=NULL; - { - char *script_url = msOWSGetOnlineResource2(map, "MO", "onlineresource", req, validated_language.c_str()); - if (script_url == NULL || - (script_url_encoded = msEncodeHTMLEntities(script_url)) == NULL) { - free(script_url); - return msWMSException(map, nVersion, NULL, wms_exception_format); - } - free(script_url); - } - - if (nVersion <= OWS_1_0_7 || nVersion >= OWS_1_3_0) /* 1.0.0 to 1.0.7 and >=1.3.0*/ - msIO_setHeader("Content-Type","text/xml; charset=UTF-8"); - else /* 1.1.0 and later */ - msIO_setHeader("Content-Type","application/vnd.ogc.wms_xml; charset=UTF-8"); - msIO_sendHeaders(); - - msIO_printf("\n"); - - /*TODO review wms1.3.0*/ - if ( nVersion < OWS_1_3_0) { - msIO_printf("web.metadata), "MO", "inspire_capabilities") ) { - msIO_printf("" - " " - "" - "" - "\n"); - } else { - /* some mapserver specific declarations will go here */ - msIO_printf(" \n"); - } - - msIO_printf(" ]> \n\n"); - } - - char szVersionBuf[OWS_VERSION_MAXLEN]; - const char* pszVersion = msOWSGetVersionString(nVersion, szVersionBuf); - if ( nVersion >= OWS_1_3_0) - msIO_printf("web.metadata), "MO", "inspire_capabilities") ) { - msIO_printf(" xmlns:" MS_INSPIRE_COMMON_NAMESPACE_PREFIX "=\"" MS_INSPIRE_COMMON_NAMESPACE_URI "\"" - " xmlns:" MS_INSPIRE_VS_NAMESPACE_PREFIX "=\"" MS_INSPIRE_VS_NAMESPACE_URI "\"" ); - } - - msIO_printf(" xsi:schemaLocation=\"http://www.opengis.net/wms %s/wms/%s/capabilities_1_3_0.xsd " - " http://www.opengis.net/sld %s/sld/1.1.0/sld_capabilities.xsd ", - msOWSGetSchemasLocation(map), pszVersion, msOWSGetSchemasLocation(map)); - - if ( msOWSLookupMetadata(&(map->web.metadata), "MO", "inspire_capabilities") ) { - char* inspireschemalocation = msEncodeHTMLEntities( msOWSGetInspireSchemasLocation(map) ); - msIO_printf(" " MS_INSPIRE_VS_NAMESPACE_URI " " - " %s%s", inspireschemalocation, MS_INSPIRE_VS_SCHEMA_LOCATION); - free(inspireschemalocation); - } - - msIO_printf(" http://mapserver.gis.umn.edu/mapserver %sservice=WMS&version=1.3.0&request=GetSchemaExtension\"", - script_url_encoded); - } - - msIO_printf(">\n"); - - - - /* Report MapServer Version Information */ - msIO_printf("\n\n\n", msGetVersion()); - - /* WMS definition */ - msIO_printf("\n"); - - /* Service name is defined by the spec and changed at v1.0.0 */ - if (nVersion <= OWS_1_0_7) - msIO_printf(" GetMap\n"); /* v 1.0.0 to 1.0.7 */ - else if (nVersion > OWS_1_0_7 && nVersion < OWS_1_3_0) - msIO_printf(" OGC:WMS\n"); /* v 1.1.0 to 1.1.1*/ - else - msIO_printf(" WMS\n"); /* v 1.3.0+ */ - - - /* the majority of this section is dependent on appropriately named metadata in the WEB object */ - msOWSPrintEncodeMetadata2(stdout, &(map->web.metadata), "MO", "title", - OWS_WARN, " %s\n", map->name, validated_language.c_str()); - msOWSPrintEncodeMetadata2(stdout, &(map->web.metadata), "MO", "abstract", - OWS_NOERR, " %s\n", NULL, validated_language.c_str()); - - msWMSPrintKeywordlist(stdout, " ", "keywordlist", &(map->web.metadata), "MO", nVersion); - - /* Service/onlineresource */ - /* Defaults to same as request onlineresource if wms_service_onlineresource */ - /* is not set. */ - if (nVersion== OWS_1_0_0) - msOWSPrintEncodeMetadata(stdout, &(map->web.metadata), - "MO", "service_onlineresource", OWS_NOERR, - " %s\n", - script_url_encoded); - else - msOWSPrintEncodeMetadata(stdout, &(map->web.metadata), - "MO", "service_onlineresource", OWS_NOERR, - " \n", - script_url_encoded); - - /* contact information is a required element in 1.0.7 but the */ - /* sub-elements such as ContactPersonPrimary, etc. are not! */ - /* In 1.1.0, ContactInformation becomes optional. */ - msOWSPrintContactInfo(stdout, " ", nVersion, &(map->web.metadata), "MO"); - - msOWSPrintEncodeMetadata(stdout, &(map->web.metadata), "MO", "fees", - OWS_NOERR, " %s\n", NULL); - - msOWSPrintEncodeMetadata(stdout, &(map->web.metadata), "MO", - "accessconstraints", OWS_NOERR, - " %s\n", NULL); - - if (nVersion >= OWS_1_3_0) { - const char* layerlimit = msOWSLookupMetadata(&(map->web.metadata), "MO", "layerlimit"); - if (layerlimit) { - msIO_printf(" %s\n", layerlimit); - } - msIO_printf(" %d\n", map->maxsize); - msIO_printf(" %d\n", map->maxsize); - } - - msIO_printf("\n\n"); - - /* WMS capabilities definitions */ - msIO_printf("\n"); - msIO_printf(" \n"); - - if (nVersion <= OWS_1_0_7) { - /* WMS 1.0.0 to 1.0.7 - We don't try to use outputformats list here for now */ - if (msOWSRequestIsEnabled(map, NULL, "M", "GetMap", MS_FALSE)) - msWMSPrintRequestCap(nVersion, "Map", script_url_encoded, "" - -#if defined USE_PNG - "" -#endif -#if defined USE_JPEG - "" -#endif - "" - , NULL); - if (msOWSRequestIsEnabled(map, NULL, "M", "GetCapabilities", MS_TRUE)) - msWMSPrintRequestCap(nVersion, "Capabilities", script_url_encoded, "", NULL); - if (msOWSRequestIsEnabled(map, NULL, "M", "GetFeatureInfo", MS_FALSE)) - msWMSPrintRequestCap(nVersion, "FeatureInfo", script_url_encoded, "", NULL); - } else { - const char *mime_list[20]; - int mime_count = 0; - int max_mime = 20; - /* WMS 1.1.0 and later */ - /* Note changes to the request names, their ordering, and to the formats */ - - if (msOWSRequestIsEnabled(map, NULL, "M", "GetCapabilities", MS_TRUE)) { - if (nVersion >= OWS_1_3_0) - msWMSPrintRequestCap(nVersion, "GetCapabilities", script_url_encoded, - "text/xml", - NULL); - else - msWMSPrintRequestCap(nVersion, "GetCapabilities", script_url_encoded, - "application/vnd.ogc.wms_xml", - NULL); - } - - msGetOutputFormatMimeListWMS(map,mime_list,sizeof(mime_list)/sizeof(char*)); - if (msOWSRequestIsEnabled(map, NULL, "M", "GetMap", MS_FALSE)) - msWMSPrintRequestCap(nVersion, "GetMap", script_url_encoded, - mime_list[0], mime_list[1], mime_list[2], mime_list[3], - mime_list[4], mime_list[5], mime_list[6], mime_list[7], - mime_list[8], mime_list[9], mime_list[10], mime_list[11], - mime_list[12], mime_list[13], mime_list[14], mime_list[15], - mime_list[16], mime_list[17], mime_list[18], mime_list[19], - NULL ); - - const char* format_list = msOWSLookupMetadata(&(map->web.metadata), "M", - "getfeatureinfo_formatlist"); - /*feature_info_mime_type depricated for MapServer 6.0*/ - if (!format_list) - format_list = msOWSLookupMetadata(&(map->web.metadata), "MO", - "feature_info_mime_type"); - - if (format_list && strlen(format_list) > 0) { - auto tokens = msStringSplit(format_list, ','); - for(auto& token: tokens) { - msStringTrim(token); - /*text plain and gml do not need to be a format and accepted by default*/ - /*can not really validate since the old way of using template - with wei->header, layer->template ... should be kept*/ - if (!token.empty() && mime_count0) { - if (mime_count= OWS_1_1_1) { - if (nVersion == OWS_1_3_0) { - if (msOWSRequestIsEnabled(map, NULL, "M", "GetLegendGraphic", MS_FALSE)) - msWMSPrintRequestCap(nVersion, "sld:GetLegendGraphic", script_url_encoded, - mime_list[0], mime_list[1], mime_list[2], mime_list[3], - mime_list[4], mime_list[5], mime_list[6], mime_list[7], - mime_list[8], mime_list[9], mime_list[10], mime_list[11], - mime_list[12], mime_list[13], mime_list[14], mime_list[15], - mime_list[16], mime_list[17], mime_list[18], mime_list[19], - NULL ); - if (msOWSRequestIsEnabled(map, NULL, "M", "GetStyles", MS_FALSE)) - msWMSPrintRequestCap(nVersion, "ms:GetStyles", script_url_encoded, "text/xml", NULL); - } else { - if (msOWSRequestIsEnabled(map, NULL, "M", "GetLegendGraphic", MS_FALSE)) - msWMSPrintRequestCap(nVersion, "GetLegendGraphic", script_url_encoded, - mime_list[0], mime_list[1], mime_list[2], mime_list[3], - mime_list[4], mime_list[5], mime_list[6], mime_list[7], - mime_list[8], mime_list[9], mime_list[10], mime_list[11], - mime_list[12], mime_list[13], mime_list[14], mime_list[15], - mime_list[16], mime_list[17], mime_list[18], mime_list[19], - NULL ); - if (msOWSRequestIsEnabled(map, NULL, "M", "GetStyles", MS_FALSE)) - msWMSPrintRequestCap(nVersion, "GetStyles", script_url_encoded, "text/xml", NULL); - } - } - } - } - - msIO_printf(" \n"); - - msIO_printf(" \n"); - if (nVersion <= OWS_1_0_7) - msIO_printf(" \n"); - else if (nVersion <= OWS_1_1_1) { - msIO_printf(" application/vnd.ogc.se_xml\n"); - msIO_printf(" application/vnd.ogc.se_inimage\n"); - msIO_printf(" application/vnd.ogc.se_blank\n"); - } else { /*>=1.3.0*/ - msIO_printf(" XML\n"); - msIO_printf(" INIMAGE\n"); - msIO_printf(" BLANK\n"); - - } - msIO_printf(" \n"); - - if (nVersion != OWS_1_3_0) { - /* INSPIRE extended capabilities for WMS 1.1.1 */ - if (nVersion == OWS_1_1_1 && msOWSLookupMetadata(&(map->web.metadata), "MO", "inspire_capabilities") ) { - msIO_printf(" \n"); - msOWSPrintInspireCommonExtendedCapabilities(stdout, map, "MO", OWS_WARN, "inspire_vs:ExtendedCapabilities", NULL, validated_language.c_str(), OWS_WMS); - msIO_printf(" \n"); - } else { - msIO_printf(" \n"); /* nothing yet */ - } - } - - /* SLD support */ - if (strcasecmp(sldenabled, "true") == 0) { - if (nVersion >= OWS_1_0_7) { - if (nVersion >= OWS_1_3_0) - msIO_printf(" \n"); - else - msIO_printf(" \n"); - } - } - - /* INSPIRE extended capabilities for WMS 1.3.0 */ - if (nVersion >= OWS_1_3_0 && msOWSLookupMetadata(&(map->web.metadata), "MO", "inspire_capabilities") ) { - msOWSPrintInspireCommonExtendedCapabilities(stdout, map, "MO", OWS_WARN, "inspire_vs:ExtendedCapabilities", NULL, validated_language.c_str(), OWS_WMS); - } - - /* Top-level layer with map extents and SRS, encloses all map layers */ - /* Output only if at least one layers is enabled. */ - if (ows_request->numlayers == 0) { - msIO_fprintf(stdout, " \n"); - } else { - int root_is_queryable = MS_FALSE; - - const char* rootlayer_name = msOWSLookupMetadata(&(map->web.metadata), "MO", "rootlayer_name"); - - /* Root layer is queryable if it has a valid name and at list one layer */ - /* is queryable */ - if( !rootlayer_name || strlen(rootlayer_name) > 0 ) { - int j; - for(j=0; jnumlayers; j++) { - layerObj* layer = GET_LAYER(map, j); - if( msIsLayerQueryable(layer) && - msIntegerInArray(layer->index, ows_request->enabled_layers, ows_request->numlayers) ) { - root_is_queryable = MS_TRUE; - break; - } - } - } - msIO_printf(" \n",root_is_queryable ? " queryable=\"1\"" : ""); - - /* Layer Name is optional but title is mandatory. */ - if (map->name && strlen(map->name) > 0 && - (msIsXMLTagValid(map->name) == MS_FALSE || isdigit(map->name[0]))) - msIO_fprintf(stdout, "\n", - map->name); - - if (rootlayer_name) { - if (strlen(rootlayer_name) > 0) { - msOWSPrintEncodeMetadata(stdout, &(map->web.metadata), "MO", "rootlayer_name", - OWS_NOERR, " %s\n", - NULL); - } - } - else { - msOWSPrintEncodeParam(stdout, "MAP.NAME", map->name, OWS_NOERR, - " %s\n", NULL); - } - - if (msOWSLookupMetadataWithLanguage(&(map->web.metadata), "MO", "rootlayer_title", validated_language.c_str())) - msOWSPrintEncodeMetadata2(stdout, &(map->web.metadata), "MO", "rootlayer_title", OWS_WARN, " %s\n", map->name, validated_language.c_str()); - - else - msOWSPrintEncodeMetadata2(stdout, &(map->web.metadata), "MO", "title", OWS_WARN, " %s\n", map->name, validated_language.c_str()); - - if (msOWSLookupMetadataWithLanguage(&(map->web.metadata), "MO", "rootlayer_abstract", validated_language.c_str())) - msOWSPrintEncodeMetadata2(stdout, &(map->web.metadata), "MO", "rootlayer_abstract", OWS_NOERR, " %s\n", map->name, validated_language.c_str()); - else - msOWSPrintEncodeMetadata2(stdout, &(map->web.metadata), "MO", "abstract", OWS_NOERR, " %s\n", map->name, validated_language.c_str()); - - const char* pszTmp; - if (msOWSLookupMetadata(&(map->web.metadata), "MO", "rootlayer_keywordlist") || - msOWSLookupMetadata(&(map->web.metadata), "MO", "rootlayer_keywordlist_vocabulary")) - pszTmp = "rootlayer_keywordlist"; - else - pszTmp = "keywordlist"; - msWMSPrintKeywordlist(stdout, " ", pszTmp, &(map->web.metadata), "MO", nVersion); - - /* According to normative comments in the 1.0.7 DTD, the root layer's SRS tag */ - /* is REQUIRED. It also suggests that we use an empty SRS element if there */ - /* is no common SRS. */ - char *pszMapEPSG; - msOWSGetEPSGProj(&(map->projection), &(map->web.metadata), "MO", MS_FALSE, &pszMapEPSG); - if (nVersion > OWS_1_1_0) { - /* starting 1.1.1 SRS are given in individual tags */ - if (nVersion >= OWS_1_3_0) { - msOWSPrintEncodeParamList(stdout, "(at least one of) " - "MAP.PROJECTION, LAYER.PROJECTION " - "or wms_srs metadata", - pszMapEPSG, - OWS_WARN, ' ', NULL, NULL, - " %s\n", ""); - } else { - msOWSPrintEncodeParamList(stdout, "(at least one of) " - "MAP.PROJECTION, LAYER.PROJECTION " - "or wms_srs metadata", - pszMapEPSG, - OWS_WARN, ' ', NULL, NULL, - " %s\n", ""); - } - } else { - /* If map has no proj then every layer MUST have one or produce a warning */ - msOWSPrintEncodeParam(stdout, "MAP.PROJECTION (or wms_srs metadata)", - pszMapEPSG, - OWS_WARN, " %s\n", ""); - } - msFree(pszMapEPSG); - - if (nVersion >= OWS_1_3_0) - msOWSPrintEX_GeographicBoundingBox(stdout, " ", &(map->extent), - &(map->projection)); - else - msOWSPrintLatLonBoundingBox(stdout, " ", &(map->extent), - &(map->projection), NULL, OWS_WMS); - - msOWSPrintBoundingBox( stdout, " ", &(map->extent), &(map->projection), - NULL, &(map->web.metadata), "MO", nVersion); - - if (nVersion >= OWS_1_0_7) { - msWMSPrintAttribution(stdout, " ", &(map->web.metadata), "MO"); - } - - /* AuthorityURL support and Identifier support, only available >= WMS 1.1.0 */ - if(nVersion >= OWS_1_1_0) { - msWMSPrintAuthorityURL(stdout, " ", &(map->web.metadata), "MO"); - msWMSPrintIdentifier(stdout, " ", &(map->web.metadata), "MO"); - } - - /* MetadataURL */ - if(nVersion >= OWS_1_1_0) - msOWSPrintURLType(stdout, &(map->web.metadata), "MO", "metadataurl", - OWS_NOERR, NULL, "MetadataURL", " type=\"%s\"", - NULL, NULL, ">\n %s\n ", - MS_TRUE, MS_FALSE, MS_FALSE, MS_TRUE, MS_TRUE, - NULL, NULL, NULL, NULL, NULL, " "); - - /* DataURL */ - if(nVersion < OWS_1_1_0) - msOWSPrintEncodeMetadata(stdout, &(map->web.metadata), "MO", "dataurl_href", - OWS_NOERR, " %s\n", - NULL); - else - msOWSPrintURLType(stdout, &(map->web.metadata), "MO", "dataurl", - OWS_NOERR, NULL, "DataURL", NULL, NULL, NULL, - ">\n %s\n ", - MS_FALSE, MS_FALSE, MS_FALSE, MS_TRUE, MS_TRUE, - NULL, NULL, NULL, NULL, NULL, " "); - - if (map->name && strlen(map->name) > 0 && msOWSLookupMetadata(&(map->web.metadata), "MO", "inspire_capabilities") ) { - char *pszEncodedName = NULL; - const char *styleName = NULL; - char *pszEncodedStyleName = NULL; - const char *legendURL = NULL; - - pszEncodedName = msEncodeHTMLEntities(map->name); - - styleName = msOWSLookupMetadata(&(map->web.metadata), "MO", "style_name"); - if (styleName == NULL) - styleName = "default"; - - pszEncodedStyleName = msEncodeHTMLEntities(styleName); - - msIO_fprintf(stdout, " \n"); - msFree(pszEncodedName); - msFree(pszEncodedStyleName); - - } - - if (nVersion < OWS_1_3_0) - msWMSPrintScaleHint(" ", map->web.minscaledenom, map->web.maxscaledenom, - map->resolution); - else - msWMSPrintScaleDenominator(" ", map->web.minscaledenom, map->web.maxscaledenom); - - /* */ - /* Dump list of layers organized by groups. Layers with no group are listed */ - /* individually, at the same level as the groups in the layer hierarchy */ - /* */ - if (map->numlayers) { - char ***nestedGroups = NULL; - int *numNestedGroups = NULL; - int *isUsedInNestedGroup = NULL; - - /* We'll use this array of booleans to track which layer/group have been */ - /* processed already */ - std::vector pabLayerProcessed(map->numlayers); - - /* Mark disabled layers as processed to prevent from being displayed in nested groups (#4533)*/ - for(int i=0; inumlayers; i++) { - if (!msIntegerInArray(GET_LAYER(map, i)->index, ows_request->enabled_layers, ows_request->numlayers)) - pabLayerProcessed[i] = 1; - } - - nestedGroups = (char***)msSmallCalloc(map->numlayers, sizeof(char**)); - numNestedGroups = (int*)msSmallCalloc(map->numlayers, sizeof(int)); - isUsedInNestedGroup = (int*)msSmallCalloc(map->numlayers, sizeof(int)); - msWMSPrepareNestedGroups(map, nVersion, nestedGroups, numNestedGroups, isUsedInNestedGroup); - - for(int i=0; inumlayers; i++) { - layerObj *lp = (GET_LAYER(map, i)); - - if (pabLayerProcessed[i] || (lp->status == MS_DELETE)) - continue; /* Layer is hidden or has already been handled */ - - if (numNestedGroups[i] > 0) { - /* Has nested groups. */ - msWMSPrintNestedGroups(map, nVersion, pabLayerProcessed.data(), i, 0, - nestedGroups, numNestedGroups, isUsedInNestedGroup, - script_url_encoded, validated_language.c_str()); - } else if (lp->group == NULL || strlen(lp->group) == 0) { - /* Don't dump layer if it is used in wms_group_layer. */ - if (!isUsedInNestedGroup[i]) { - /* This layer is not part of a group... dump it directly */ - msDumpLayer(map, lp, nVersion, script_url_encoded, "", validated_language.c_str(), MS_FALSE, MS_FALSE); - pabLayerProcessed[i] = 1; - } - } else { - bool group_is_queryable = false; - /* Group is queryable as soon as its member layers is. */ - for(int j=i; jnumlayers; j++) { - if (GET_LAYER(map, j)->group && - strcmp(lp->group, GET_LAYER(map, j)->group) == 0 && - msIntegerInArray(GET_LAYER(map, j)->index, ows_request->enabled_layers, ows_request->numlayers) && - msIsLayerQueryable(GET_LAYER(map, j)) ) { - group_is_queryable = true; - break; - } - } - /* Beginning of a new group... enclose the group in a layer block */ - msIO_printf(" \n", - group_is_queryable ? " queryable=\"1\"" : ""); - - /* Layer Name is optional but title is mandatory. */ - if (lp->group && strlen(lp->group) > 0 && - (msIsXMLTagValid(lp->group) == MS_FALSE || isdigit(lp->group[0]))) - msIO_fprintf(stdout, "\n", - lp->group); - msOWSPrintEncodeParam(stdout, "GROUP.NAME", lp->group, - OWS_NOERR, " %s\n", NULL); - msOWSPrintGroupMetadata2(stdout, map, lp->group, - "MO", "GROUP_TITLE", OWS_WARN, - " %s\n", lp->group, validated_language.c_str()); - msOWSPrintGroupMetadata2(stdout, map, lp->group, - "MO", "GROUP_ABSTRACT", OWS_NOERR, - " %s\n", lp->group, validated_language.c_str()); - - /*build a getlegendgraphicurl*/ - if( script_url_encoded) { - if (lp->group && strlen(lp->group) > 0) { - char *pszEncodedName = NULL; - const char *styleName = NULL; - char *pszEncodedStyleName = NULL; - const char *legendURL = NULL; - - pszEncodedName = msEncodeHTMLEntities(lp->group); - - styleName = msOWSLookupMetadata(&(lp->metadata), "MO", "group_style_name"); - if (styleName == NULL) - styleName = "default"; - - pszEncodedStyleName = msEncodeHTMLEntities(styleName); - - msIO_fprintf(stdout, " \n"); - msFree(pszEncodedName); - msFree(pszEncodedStyleName); - } - } - - /* Dump all layers for this group */ - for(int j=i; jnumlayers; j++) { - if (!pabLayerProcessed[j] && - GET_LAYER(map, j)->group && - strcmp(lp->group, GET_LAYER(map, j)->group) == 0 && - msIntegerInArray(GET_LAYER(map, j)->index, ows_request->enabled_layers, ows_request->numlayers)) { - msDumpLayer(map, (GET_LAYER(map, j)), nVersion, script_url_encoded, " ", validated_language.c_str(), MS_FALSE, MS_FALSE); - pabLayerProcessed[j] = 1; - } - } - /* Close group layer block */ - msIO_printf(" \n"); - } - } - - /* free the stuff used for nested layers */ - for (int i = 0; i < map->numlayers; i++) { - if (numNestedGroups[i] > 0) { - msFreeCharArray(nestedGroups[i], numNestedGroups[i]); - } - } - free(nestedGroups); - free(numNestedGroups); - free(isUsedInNestedGroup); - } - - msIO_printf(" \n"); - } - - msIO_printf("\n"); - if ( nVersion >= OWS_1_3_0) - msIO_printf("\n"); - else - msIO_printf("\n"); - - free(script_url_encoded); - - return(MS_SUCCESS); -} - -/* - * This function look for params that can be used - * by mapserv when generating template. -*/ -int msTranslateWMS2Mapserv(const char **names, const char **values, int numentries, char ***translated_names, char ***translated_values, int *translated_numentries) -{ - int num_allocated = numentries; - *translated_names = (char**)msSmallMalloc(num_allocated * sizeof(char*)); - *translated_values = (char**)msSmallMalloc(num_allocated * sizeof(char*)); - *translated_numentries = 0; - for (int i=0; i 0) || - (strcasecmp(names[i], "SLD_BODY") == 0 && values[i] && strlen(values[i]) > 0)) { - sldrequested = MS_TRUE; - break; - } - } - if (sldrequested) { - for (int i=0; inumlayers; i++) { - if (msLookupHashTable(&(GET_LAYER(map, i)->metadata), "tmp_wms_sld_query")) { - sldspatialfilter = MS_TRUE; - break; - } - } - } - /* If FILTER is passed then we'll render layers as querymap */ - for (int i=0; i 0)) { - drawquerymap = MS_TRUE; - map->querymap.status = MS_ON; - map->querymap.style = MS_SELECTED; - break; - } - } - - /* turn off layer if WMS GetMap is not enabled */ - for (int i=0; inumlayers; i++) - if (!msIntegerInArray(GET_LAYER(map, i)->index, ows_request->enabled_layers, ows_request->numlayers)) - GET_LAYER(map, i)->status = MS_OFF; - - if (sldrequested && sldspatialfilter) { - /* set the quermap style so that only selected features will be retruned */ - map->querymap.status = MS_ON; - map->querymap.style = MS_SELECTED; - - img = msPrepareImage(map, MS_TRUE); - - /* compute layer scale factors now */ - for(int i=0; inumlayers; i++) { - if(GET_LAYER(map, i)->sizeunits != MS_PIXELS) - GET_LAYER(map, i)->scalefactor = (msInchesPerUnit(GET_LAYER(map, i)->sizeunits,0)/msInchesPerUnit(map->units,0)) / map->cellsize; - else if(GET_LAYER(map, i)->symbolscaledenom > 0 && map->scaledenom > 0) - GET_LAYER(map, i)->scalefactor = GET_LAYER(map, i)->symbolscaledenom/map->scaledenom; - else - GET_LAYER(map, i)->scalefactor = 1; - } - for (int i=0; inumlayers; i++) { - if (msLookupHashTable(&(GET_LAYER(map, i)->metadata), "tmp_wms_sld_query") && - (GET_LAYER(map, i)->type == MS_LAYER_POINT || - GET_LAYER(map, i)->type == MS_LAYER_LINE || - GET_LAYER(map, i)->type == MS_LAYER_POLYGON || - GET_LAYER(map, i)->type == MS_LAYER_TILEINDEX)) - - { - /* make sure that there is a resultcache. If not just ignore */ - /* the layer */ - if (GET_LAYER(map, i)->resultcache) - msDrawQueryLayer(map, GET_LAYER(map, i), img); - } - - else - msDrawLayer(map, GET_LAYER(map, i), img); - } - - } else { - - /* intercept requests for Mapbox vector tiles */ - if(!strcmp(MS_IMAGE_MIME_TYPE(map->outputformat), "application/x-protobuf")) { - int status=0; - if((status = msMVTWriteTile(map, MS_TRUE)) != MS_SUCCESS) return MS_FAILURE; - return MS_SUCCESS; - } - - img = msDrawMap(map, drawquerymap); - } - - if (img == NULL) - return msWMSException(map, nVersion, NULL, wms_exception_format); - - /* Set the HTTP Cache-control headers if they are defined - in the map object */ - - const char* http_max_age = msOWSLookupMetadata(&(map->web.metadata), "MO", "http_max_age"); - if( http_max_age ) { - msIO_setHeader("Cache-Control","max-age=%s", http_max_age); - } - - if (strcasecmp(map->imagetype, "application/openlayers")!=0) { - if(!strcmp(MS_IMAGE_MIME_TYPE(map->outputformat), "application/json")) { - msIO_setHeader("Content-Type","application/json; charset=utf-8"); - } else { - msOutputFormatResolveFromImage( map, img ); - msIO_setHeader("Content-Type", "%s", MS_IMAGE_MIME_TYPE(map->outputformat)); - } - msIO_sendHeaders(); - if (msSaveImage(map, img, NULL) != MS_SUCCESS) { - msFreeImage(img); - return msWMSException(map, nVersion, NULL, wms_exception_format); - } - } - msFreeImage(img); - - return(MS_SUCCESS); -} - -static -int msDumpResult(mapObj *map, int bFormatHtml, int nVersion, const char *wms_exception_format) -{ - int numresults=0; - - for(int i=0; inumlayers; i++) { - layerObj *lp = (GET_LAYER(map, i)); - - if(lp->status != MS_ON || lp->resultcache==NULL || lp->resultcache->numresults == 0) - continue; - - /* if(msLayerOpen(lp) != MS_SUCCESS || msLayerGetItems(lp) != MS_SUCCESS) - return msWMSException(map, nVersion, NULL); */ - - /* Use metadata to control which fields to output. We use the same - * metadata names as for GML: - * wms/ows_include_items: comma delimited list or keyword 'all' - * wms/ows_exclude_items: comma delimited list (all items are excluded by default) - */ - /* get a list of items that should be excluded in output */ - std::vector incitems; - const char *value; - if((value = msOWSLookupMetadata(&(lp->metadata), "MO", "include_items")) != NULL) - incitems = msStringSplit(value, ','); - - /* get a list of items that should be excluded in output */ - std::vector excitems; - if((value = msOWSLookupMetadata(&(lp->metadata), "MO", "exclude_items")) != NULL) - excitems = msStringSplit(value, ','); - - std::vector itemvisible(lp->numitems); - for(int k=0; knumitems; k++) { - /* check visibility, included items first... */ - if(incitems.size() == 1 && strcasecmp("all", incitems[0].c_str()) == 0) { - itemvisible[k] = true; - } else { - for( const auto& incitem: incitems ) { - if(strcasecmp(lp->items[k], incitem.c_str()) == 0) - itemvisible[k] = true; - } - } - - /* ...and now excluded items */ - for( const auto& excitem: excitems ) { - if(strcasecmp(lp->items[k], excitem.c_str()) == 0) - itemvisible[k] = false; - } - } - - /* Output selected shapes for this layer */ - msIO_printf("\nLayer '%s'\n", lp->name); - - for(int j=0; jresultcache->numresults; j++) { - shapeObj shape; - - msInitShape(&shape); - if (msLayerGetShape(lp, &shape, &(lp->resultcache->results[j])) != MS_SUCCESS) { - return msWMSException(map, nVersion, NULL, wms_exception_format); - } - - msIO_printf(" Feature %ld: \n", lp->resultcache->results[j].shapeindex); - - for(int k=0; knumitems; k++) { - if (itemvisible[k]) { - value = msOWSLookupMetadata(&(lp->metadata), "MO", (std::string(lp->items[k]) + "_alias").c_str()); - const char *lineTemplate=" %s = '%s'\n"; - msIO_printf(lineTemplate, value != NULL ? value : lp->items[k], shape.values[k]); - } - } - - msFreeShape(&shape); - numresults++; - } - - /* msLayerClose(lp); */ - } - - return numresults; -} - - -/* -** msWMSFeatureInfo() -*/ -static -int msWMSFeatureInfo(mapObj *map, int nVersion, char **names, char **values, int numentries, - const char *wms_exception_format, owsRequestObj *ows_request) -{ - int feature_count=1, numlayers_found=0; - pointObj point = {-1.0, -1.0}; - const char *info_format="MIME"; - errorObj *ms_error = msGetErrorObj(); - int query_status=MS_NOERR; - int query_layer = 0; - const char *format_list=NULL; - int valid_format=MS_FALSE; - int format_found = MS_FALSE; - int use_bbox = MS_FALSE; - int wms_layer = MS_FALSE; - const char *wms_connection = NULL; - int numOWSLayers = 0; - - char*** nestedGroups = (char***)msSmallCalloc(map->numlayers, sizeof(char**)); - int* numNestedGroups = (int*)msSmallCalloc(map->numlayers, sizeof(int)); - int* isUsedInNestedGroup = (int*)msSmallCalloc(map->numlayers, sizeof(int)); - msWMSPrepareNestedGroups(map, nVersion, nestedGroups, numNestedGroups, isUsedInNestedGroup); - - for(int i=0; inumlayers; j++) { - /* Force all layers OFF by default */ - GET_LAYER(map, j)->status = MS_OFF; - } - - /* Special case for root layer */ - const char* rootlayer_name = msOWSLookupMetadata(&(map->web.metadata), "MO", "rootlayer_name"); - if( !rootlayer_name ) - rootlayer_name = map->name; - if( rootlayer_name && msStringInArray(rootlayer_name, wmslayers) ) { - for(int j=0; jnumlayers; j++) { - layerObj* layer = GET_LAYER(map, j); - if( msIsLayerQueryable(layer) && - msIntegerInArray(layer->index, ows_request->enabled_layers, ows_request->numlayers) ) { - if (layer->connectiontype == MS_WMS) { - wms_layer = MS_TRUE; - wms_connection = layer->connection; - } - - numlayers_found++; - layer->status = MS_ON; - } - } - } - - for(int j=0; jnumlayers; j++) { - layerObj* layer = GET_LAYER(map, j); - if( !msIsLayerQueryable(layer) ) - continue; - for(const auto& wmslayer: wmslayers) { - if (((layer->name && strcasecmp(layer->name, wmslayer.c_str()) == 0) || - (layer->group && strcasecmp(layer->group, wmslayer.c_str()) == 0) || - ((numNestedGroups[j] >0) && msStringInArray(wmslayer.c_str(), nestedGroups[j], numNestedGroups[j]))) && - (msIntegerInArray(layer->index, ows_request->enabled_layers, ows_request->numlayers)) ) { - - if (layer->connectiontype == MS_WMS) { - wms_layer = MS_TRUE; - wms_connection = layer->connection; - } - - numlayers_found++; - layer->status = MS_ON; - } - } - } - } else if (strcasecmp(names[i], "INFO_FORMAT") == 0) { - if (values[i] && strlen(values[i]) > 0) { - info_format = values[i]; - format_found = MS_TRUE; - } - } else if (strcasecmp(names[i], "FEATURE_COUNT") == 0) - feature_count = atoi(values[i]); - else if(strcasecmp(names[i], "X") == 0 || strcasecmp(names[i], "I") == 0) - point.x = atof(values[i]); - else if (strcasecmp(names[i], "Y") == 0 || strcasecmp(names[i], "J") == 0) - point.y = atof(values[i]); - else if (strcasecmp(names[i], "RADIUS") == 0) { - /* RADIUS in pixels. */ - /* This is not part of the spec, but some servers such as cubeserv */ - /* support it as a vendor-specific feature. */ - /* It's easy for MapServer to handle this so let's do it! */ - - /* Special RADIUS value that changes the query into a bbox query */ - /* based on the bbox in the request parameters. */ - if( strcasecmp(values[i], "BBOX") == 0) { - use_bbox = MS_TRUE; - } else { - int j; - for(j=0; jnumlayers; j++) { - GET_LAYER(map, j)->tolerance = atoi(values[i]); - GET_LAYER(map, j)->toleranceunits = MS_PIXELS; - } - } - } - - } - - /* free the stuff used for nested layers */ - for (int i = 0; i < map->numlayers; i++) { - if (numNestedGroups[i] > 0) { - msFreeCharArray(nestedGroups[i], numNestedGroups[i]); - } - } - free(nestedGroups); - free(numNestedGroups); - free(isUsedInNestedGroup); - - if(numlayers_found == 0) { - if (query_layer) { - msSetError(MS_WMSERR, "Layer(s) specified in QUERY_LAYERS parameter is not offered by the service instance.", "msWMSFeatureInfo()"); - return msWMSException(map, nVersion, "LayerNotDefined", wms_exception_format); - } else { - msSetError(MS_WMSERR, "Required QUERY_LAYERS parameter missing for getFeatureInfo.", "msWMSFeatureInfo()"); - return msWMSException(map, nVersion, "LayerNotDefined", wms_exception_format); - } - } - - /*make sure to initialize the map scale so that layers that are scale dependent are resepected for - the query*/ - msCalculateScale(map->extent,map->units,map->width,map->height, map->resolution, &map->scaledenom); - - /* -------------------------------------------------------------------- */ - /* check if all layers selected are queryable. If not send an */ - /* exception. */ - /* -------------------------------------------------------------------- */ - - /* If a layer of type WMS was found... all layers have to be of that type and with the same connection */ - for (int i=0; inumlayers; i++) { - if (GET_LAYER(map, i)->status == MS_ON) { - if (wms_layer == MS_TRUE) { - if ( (GET_LAYER(map, i)->connectiontype != MS_WMS) || (strcasecmp(wms_connection, GET_LAYER(map, i)->connection) != 0) ) { - msSetError(MS_WMSERR, "Requested WMS layer(s) are not queryable: type or connection differ", "msWMSFeatureInfo()"); - return msWMSException(map, nVersion, "LayerNotQueryable", wms_exception_format); - } - ++numOWSLayers; - } - } - } - - /* It's a valid Cascading WMS GetFeatureInfo request */ - if (wms_layer) - return msWMSLayerExecuteRequest(map, numOWSLayers, point.x, point.y, - feature_count, info_format, WMS_GETFEATUREINFO); - - if( use_bbox == MS_FALSE ) { - - if(point.x == -1.0 || point.y == -1.0) { - if (nVersion >= OWS_1_3_0) - msSetError(MS_WMSERR, "Required I/J parameters missing for getFeatureInfo.", "msWMSFeatureInfo()"); - else - msSetError(MS_WMSERR, "Required X/Y parameters missing for getFeatureInfo.", "msWMSFeatureInfo()"); - return msWMSException(map, nVersion, NULL, wms_exception_format); - } - - /*wms1.3.0: check if the points are valid*/ - if (nVersion >= OWS_1_3_0) { - if (point.x > map->width || point.y > map->height) { - msSetError(MS_WMSERR, "Invalid I/J values", "msWMSFeatureInfo()"); - return msWMSException(map, nVersion, "InvalidPoint", wms_exception_format); - } - } - /* Perform the actual query */ - const double cellx = MS_CELLSIZE(map->extent.minx, map->extent.maxx, map->width); /* note: don't adjust extent, WMS assumes incoming extent is correct */ - const double celly = MS_CELLSIZE(map->extent.miny, map->extent.maxy, map->height); - point.x = MS_IMAGE2MAP_X(point.x, map->extent.minx, cellx); - point.y = MS_IMAGE2MAP_Y(point.y, map->extent.maxy, celly); - - /* WMS 1.3.0 states that feature_count is *per layer*. - * Its value is a positive integer, if omitted then the default is 1 - */ - if (feature_count < 1) - feature_count = 1; - - map->query.type = MS_QUERY_BY_POINT; - map->query.mode = (feature_count==1?MS_QUERY_SINGLE:MS_QUERY_MULTIPLE); - map->query.layer = -1; - map->query.point = point; - map->query.buffer = 0; - map->query.maxresults = feature_count; - - if(msQueryByPoint(map) != MS_SUCCESS) - if((query_status=ms_error->code) != MS_NOTFOUND) return msWMSException(map, nVersion, NULL, wms_exception_format); - - } else { /* use_bbox == MS_TRUE */ - map->query.type = MS_QUERY_BY_RECT; - map->query.mode = MS_QUERY_MULTIPLE; - map->query.layer = -1; - map->query.rect = map->extent; - map->query.buffer = 0; - map->query.maxresults = feature_count; - if(msQueryByRect(map) != MS_SUCCESS) - if((query_status=ms_error->code) != MS_NOTFOUND) return msWMSException(map, nVersion, NULL, wms_exception_format); - } - - /*validate the INFO_FORMAT*/ - valid_format = MS_FALSE; - format_list = msOWSLookupMetadata(&(map->web.metadata), "M", - "getfeatureinfo_formatlist"); - /*feature_info_mime_type depricated for MapServer 6.0*/ - if (!format_list) - format_list = msOWSLookupMetadata(&(map->web.metadata), "MO", - "feature_info_mime_type"); - if (format_list) { - /*can not really validate if it is a valid output format - since old way of using template with web->header/footer and - layer templates need to still be supported. - We can only validate if it was part of the format list*/ - if (strcasestr(format_list, info_format)) - valid_format = MS_TRUE; - } - /*check to see if the format passed is text/plain or GML and if is - defined in the formatlist. If that is the case, It is a valid format*/ - if (strcasecmp(info_format, "MIME") == 0 || - strcasecmp(info_format, "text/plain") == 0 || - strncasecmp(info_format, "GML", 3) == 0 || - strcasecmp(info_format, "application/vnd.ogc.gml") == 0) - valid_format = MS_TRUE; - - - /*last case: if the info_format is not part of the request, it defaults to MIME*/ - if (!valid_format && format_found == MS_FALSE) - valid_format =MS_TRUE; - - if (!valid_format) { - msSetError(MS_WMSERR, "Unsupported INFO_FORMAT value (%s).", - "msWMSFeatureInfo()", info_format); - if (nVersion >= OWS_1_3_0) - return msWMSException(map, nVersion, "InvalidFormat", wms_exception_format); - else - return msWMSException(map, nVersion, NULL, wms_exception_format); - } - - /* Generate response */ - if (strcasecmp(info_format, "MIME") == 0 || - strcasecmp(info_format, "text/plain") == 0) { - - /* MIME response... we're free to use any valid MIME type */ - int numresults = 0; - - msIO_setHeader("Content-Type","text/plain; charset=UTF-8"); - msIO_sendHeaders(); - msIO_printf("GetFeatureInfo results:\n"); - - numresults = msDumpResult(map, 0, nVersion, wms_exception_format); - - if (numresults == 0) msIO_printf("\n Search returned no results.\n"); - - } else if (strncasecmp(info_format, "GML", 3) == 0 || /* accept GML.1 or GML */ - strcasecmp(info_format, "application/vnd.ogc.gml") == 0) { - - if (nVersion <= OWS_1_0_7) /* 1.0.0 to 1.0.7 */ - msIO_setHeader("Content-Type","text/xml; charset=UTF-8"); - else /* 1.1.0 and later */ - msIO_setHeader("Content-Type","application/vnd.ogc.gml; charset=UTF-8"); - msIO_sendHeaders(); - msGMLWriteQuery(map, NULL, "MGO"); /* default is stdout */ - - } else { - mapservObj *msObj; - - char **translated_names, **translated_values; - int translated_numentries; - msObj = msAllocMapServObj(); - - /* Translate some vars from WMS to mapserv */ - msTranslateWMS2Mapserv((const char**)names, (const char**)values, numentries, &translated_names, &translated_values, &translated_numentries); - - msObj->map = map; - msFreeCharArray(msObj->request->ParamNames, msObj->request->NumParams); - msFreeCharArray(msObj->request->ParamValues, msObj->request->NumParams); - msObj->request->ParamNames = translated_names; - msObj->request->ParamValues = translated_values; - msObj->Mode = QUERY; - msObj->request->NumParams = translated_numentries; - msObj->mappnt.x = point.x; - msObj->mappnt.y = point.y; - - if (query_status == MS_NOTFOUND && msObj->map->web.empty) { - if(msReturnURL(msObj, msObj->map->web.empty, BROWSE) != MS_SUCCESS) - return msWMSException(map, nVersion, NULL, wms_exception_format); - } else if (msReturnTemplateQuery(msObj, (char *)info_format, NULL) != MS_SUCCESS) - return msWMSException(map, nVersion, NULL, wms_exception_format); - - /* We don't want to free the map since it */ - /* belongs to the caller, set it to NULL before freeing the mapservObj */ - msObj->map = NULL; - - msFreeMapServObj(msObj); - } - - return(MS_SUCCESS); -} - -/* -** msWMSDescribeLayer() -*/ -static -int msWMSDescribeLayer(mapObj *map, int nVersion, char **names, - char **values, int numentries, const char *wms_exception_format) -{ - std::vector wmslayers; - const char *version = NULL; - const char *sld_version = NULL; - - for(int i=0; i= OWS_1_3_0 && sld_version == NULL) { - msSetError(MS_WMSERR, "Missing required parameter SLD_VERSION", "DescribeLayer()"); - return msWMSException(map, nVersion, "MissingParameterValue", wms_exception_format); - } - if (nVersion >= OWS_1_3_0 && strcasecmp(sld_version, "1.1.0") != 0) { - msSetError(MS_WMSERR, "SLD_VERSION must be 1.1.0", "DescribeLayer()"); - return msWMSException(map, nVersion, "InvalidParameterValue", wms_exception_format); - } - - msIO_setHeader("Content-Type","text/xml; charset=UTF-8"); - msIO_sendHeaders(); - - msIO_printf("\n"); - - { - char* schemalocation = msEncodeHTMLEntities(msOWSGetSchemasLocation(map)); - if (nVersion < OWS_1_3_0) { - - msIO_printf("\n", schemalocation); - - - msIO_printf("\n", version); - } else { - msIO_printf("\n", schemalocation); - msIO_printf("%s\n",sld_version); - } - free(schemalocation); - } - - /* check if map-level metadata wfs(wcs)_onlineresource is available */ - const char* pszOnlineResMapWFS = msOWSLookupMetadata(&(map->web.metadata), "FO", "onlineresource"); - if (pszOnlineResMapWFS && strlen(pszOnlineResMapWFS) == 0) - pszOnlineResMapWFS = NULL; - - const char* pszOnlineResMapWCS = msOWSLookupMetadata(&(map->web.metadata), "CO", "onlineresource"); - if (pszOnlineResMapWCS && strlen(pszOnlineResMapWCS) == 0) - pszOnlineResMapWCS = NULL; - - char*** nestedGroups = (char***)msSmallCalloc(map->numlayers, sizeof(char**)); - int* numNestedGroups = (int*)msSmallCalloc(map->numlayers, sizeof(int)); - int * isUsedInNestedGroup = (int*)msSmallCalloc(map->numlayers, sizeof(int)); - msWMSPrepareNestedGroups(map, nVersion, nestedGroups, numNestedGroups, isUsedInNestedGroup); - - for(const auto& wmslayer: wmslayers) { - for(int k=0; knumlayers; k++) { - layerObj* lp = GET_LAYER(map, k); - - if ((map->name && strcasecmp(map->name, wmslayer.c_str()) == 0) || - (lp->name && strcasecmp(lp->name, wmslayer.c_str()) == 0) || - (lp->group && strcasecmp(lp->group, wmslayer.c_str()) == 0) || - ((numNestedGroups[k] >0) && msStringInArray(wmslayer.c_str(), nestedGroups[k], numNestedGroups[k]))) { - /* Look for a WFS onlineresouce at the layer level and then at - * the map level. - */ - const char* pszOnlineResLyrWFS = msOWSLookupMetadata(&(lp->metadata), "FO", - "onlineresource"); - const char* pszOnlineResLyrWCS = msOWSLookupMetadata(&(lp->metadata), "CO", - "onlineresource"); - if (pszOnlineResLyrWFS == NULL || strlen(pszOnlineResLyrWFS) == 0) - pszOnlineResLyrWFS = pszOnlineResMapWFS; - - if (pszOnlineResLyrWCS == NULL || strlen(pszOnlineResLyrWCS) == 0) - pszOnlineResLyrWCS = pszOnlineResMapWCS; - - if (pszOnlineResLyrWFS && (lp->type == MS_LAYER_POINT || - lp->type == MS_LAYER_LINE || - lp->type == MS_LAYER_POLYGON) ) { - char* pszOnlineResEncoded = msEncodeHTMLEntities(pszOnlineResLyrWFS); - char* pszLayerName = msEncodeHTMLEntities(lp->name); - - if (nVersion < OWS_1_3_0) { - msIO_printf("\n", - pszLayerName, pszOnlineResEncoded, pszOnlineResEncoded); - msIO_printf("\n", pszLayerName); - msIO_printf("\n"); - } else { /*wms 1.3.0*/ - msIO_printf(" \n"); - msIO_printf(" wfs\n"); - msIO_printf(" \n", - pszOnlineResEncoded); - msIO_printf(" \n"); - msIO_printf(" %s\n",pszLayerName); - msIO_printf(" \n"); - msIO_printf(" \n"); - } - - msFree(pszOnlineResEncoded); - msFree(pszLayerName); - } else if (pszOnlineResLyrWCS && lp->type == MS_LAYER_RASTER && - lp->connectiontype != MS_WMS) { - char* pszOnlineResEncoded = msEncodeHTMLEntities(pszOnlineResLyrWCS); - char* pszLayerName = msEncodeHTMLEntities(lp->name); - - if (nVersion < OWS_1_3_0) { - msIO_printf("\n", - pszLayerName, pszOnlineResEncoded); - msIO_printf("\n", pszLayerName); - msIO_printf("\n"); - - msFree(pszOnlineResEncoded); - msFree(pszLayerName); - } else { - msIO_printf(" \n"); - msIO_printf(" wcs\n"); - msIO_printf(" \n", - pszOnlineResEncoded); - msIO_printf(" \n"); - msIO_printf(" %s\n",pszLayerName); - msIO_printf(" \n"); - msIO_printf(" \n"); - } - } else { - char *pszLayerName = msEncodeHTMLEntities(lp->name); - - if (nVersion < OWS_1_3_0) - msIO_printf("\n", - pszLayerName); - else { /*wms 1.3.0*/ - msIO_printf(" \n"); - /*need to have a owstype for the DescribeLayer to be valid*/ - if (lp->type == MS_LAYER_RASTER && lp->connectiontype != MS_WMS) - msIO_printf(" wcs\n"); - else - msIO_printf(" wfs\n"); - - msIO_printf(" \n"); - msIO_printf(" \n"); - if (lp->type == MS_LAYER_RASTER && lp->connectiontype != MS_WMS) - msIO_printf(" %s\n",pszLayerName); - else - msIO_printf(" %s\n",pszLayerName); - msIO_printf(" \n"); - msIO_printf(" \n"); - } - - msFree(pszLayerName); - } - /* break; */ - } - } - } - - if (nVersion < OWS_1_3_0) - msIO_printf("\n"); - else - msIO_printf("\n"); - - /* free the stuff used for nested layers */ - for (int i = 0; i < map->numlayers; i++) { - if (numNestedGroups[i] > 0) { - msFreeCharArray(nestedGroups[i], numNestedGroups[i]); - } - } - free(nestedGroups); - free(numNestedGroups); - free(isUsedInNestedGroup); - - return(MS_SUCCESS); -} - - -/* -** msWMSGetLegendGraphic() -*/ -static -int msWMSLegendGraphic(mapObj *map, int nVersion, char **names, - char **values, int numentries, const char *wms_exception_format, owsRequestObj *ows_request, - map_hittest *hittest) -{ - const char *pszLayer = NULL; - const char *pszFormat = NULL; - const char *psRule = NULL; - const char *psScale = NULL; - int iLayerIndex = -1; - outputFormatObj *psFormat = NULL; - imageObj *img=NULL; - int nWidth = -1, nHeight =-1; - const char *pszStyle = NULL; - const char *sld_version = NULL; - int wms_layer = MS_FALSE; - const char *sldenabled = NULL; - const char *format_list = NULL; - int nLayers =0; - - if(!hittest) { - /* we can skip alot of testing if we already have a hittest, as it has already been done in the hittesting phase */ - - - sldenabled = msOWSLookupMetadata(&(map->web.metadata), "MO", "sld_enabled"); - - if (sldenabled == NULL) - sldenabled = "true"; - - for(int i=0; i 0 && strcasecmp(sldenabled, "true") == 0) - msSLDApplySLDURL(map, values[i], -1, NULL, NULL); - else if (strcasecmp(names[i], "SLD_BODY") == 0 && - values[i] && strlen(values[i]) > 0 && strcasecmp(sldenabled, "true") == 0) - msSLDApplySLD(map, values[i], -1, NULL, NULL); - else if (strcasecmp(names[i], "RULE") == 0) - psRule = values[i]; - else if (strcasecmp(names[i], "STYLE") == 0) - pszStyle = values[i]; - - /* -------------------------------------------------------------------- */ - /* SLD support: */ - /* - because the request parameter "sld_version" is required in */ - /* in WMS 1.3.0, it will be set regardless of OGR support. */ - /* -------------------------------------------------------------------- */ - else if(strcasecmp(names[i], "SLD_VERSION") == 0) - sld_version = values[i]; - } - - if (!pszLayer) { - msSetError(MS_WMSERR, "Mandatory LAYER parameter missing in GetLegendGraphic request.", "msWMSGetLegendGraphic()"); - return msWMSException(map, nVersion, "LayerNotDefined", wms_exception_format); - } - if (!pszFormat) { - msSetError(MS_WMSERR, "Mandatory FORMAT parameter missing in GetLegendGraphic request.", "msWMSGetLegendGraphic()"); - return msWMSException(map, nVersion, "InvalidFormat", wms_exception_format); - } - - if (nVersion >= OWS_1_3_0 && sld_version == NULL) { - msSetError(MS_WMSERR, "Missing required parameter SLD_VERSION", "GetLegendGraphic()"); - return msWMSException(map, nVersion, "MissingParameterValue", wms_exception_format); - } - if (nVersion >= OWS_1_3_0 && strcasecmp(sld_version, "1.1.0") != 0) { - msSetError(MS_WMSERR, "SLD_VERSION must be 1.1.0", "GetLegendGraphic()"); - return msWMSException(map, nVersion, "InvalidParameterValue", wms_exception_format); - } - - char*** nestedGroups = (char***)msSmallCalloc(map->numlayers, sizeof(char**)); - int* numNestedGroups = (int*)msSmallCalloc(map->numlayers, sizeof(int)); - int* isUsedInNestedGroup = (int*)msSmallCalloc(map->numlayers, sizeof(int)); - msWMSPrepareNestedGroups(map, nVersion, nestedGroups, numNestedGroups, isUsedInNestedGroup); - - /* check if layer name is valid. we check for layer's and group's name */ - /* as well as wms_layer_group names */ - for (int i=0; inumlayers; i++) { - layerObj* lp = GET_LAYER(map, i); - if ( ((map->name && strcasecmp(map->name, pszLayer) == 0) || - (lp->name && strcasecmp(lp->name, pszLayer) == 0) || - (lp->group && strcasecmp(lp->group, pszLayer) == 0) || - ((numNestedGroups[i] >0) && (msStringInArray(pszLayer, nestedGroups[i], numNestedGroups[i]))) ) && - (msIntegerInArray(lp->index, ows_request->enabled_layers, ows_request->numlayers)) ) { - nLayers++; - lp->status = MS_ON; - iLayerIndex = i; - if (GET_LAYER(map, i)->connectiontype == MS_WMS) { - /* we do not cascade a wms layer if it contains at least - * one class with the property name set */ - wms_layer = MS_TRUE; - for (int j=0; jnumclasses; j++) { - if (lp->_class[j]->name != NULL && strlen(lp->_class[j]->name)>0) { - wms_layer = MS_FALSE; - break; - } - } - } - } else - lp->status = MS_OFF; - } - - /* free the stuff used for nested layers */ - for (int i = 0; i < map->numlayers; i++) { - if (numNestedGroups[i] > 0) { - msFreeCharArray(nestedGroups[i], numNestedGroups[i]); - } - } - free(nestedGroups); - free(numNestedGroups); - free(isUsedInNestedGroup); - - if (nLayers == 0) { - msSetError(MS_WMSERR, "Invalid layer given in the LAYER parameter. A layer might be disabled for \ -this request. Check wms/ows_enable_request settings.", -"msWMSGetLegendGraphic()"); - return msWMSException(map, nVersion, "LayerNotDefined", wms_exception_format); - } - - - /* if SCALE was provided in request, calculate an extent and use a default width and height */ - if ( psScale != NULL ) { - double scale, cellsize; - - scale = atof(psScale); - map->width = 600; - map->height = 600; - - cellsize = (scale/map->resolution)/msInchesPerUnit(map->units, 0.0); - - map->extent.maxx = cellsize*map->width/2.0; - map->extent.maxy = cellsize*map->height/2.0; - map->extent.minx = -map->extent.maxx; - map->extent.miny = -map->extent.maxy; - } - - /* It's a valid Cascading WMS GetLegendGraphic request */ - if (wms_layer) - return msWMSLayerExecuteRequest(map, 1, 0, 0, - 0, NULL, WMS_GETLEGENDGRAPHIC); - - /*if STYLE is set, check if it is a valid style (valid = at least one - of the classes have a the group value equals to the style */ - /*style is only validated when there is only one layer #3411*/ - if (nLayers == 1 && pszStyle && strlen(pszStyle) > 0 && strcasecmp(pszStyle, "default") != 0) { - bool found = false; - for (int i=0; inumclasses; i++) { - if (GET_LAYER(map, iLayerIndex)->_class[i]->group && - strcasecmp(GET_LAYER(map, iLayerIndex)->_class[i]->group, pszStyle) == 0) { - found = true; - break; - } - } - - if (!found) { - msSetError(MS_WMSERR, "style used in the STYLE parameter is not defined on the layer.", - "msWMSGetLegendGraphic()"); - return msWMSException(map, nVersion, "StyleNotDefined", wms_exception_format); - } else { - msFree(GET_LAYER(map, iLayerIndex)->classgroup); - GET_LAYER(map, iLayerIndex)->classgroup = msStrdup(pszStyle); - - } - } - } else { - /* extract the parameters we need */ - for(int i=0; iweb.metadata), "M","getlegendgraphic_formatlist"); - if (format_list) { - psFormat = msOwsIsOutputFormatValid(map, pszFormat, &(map->web.metadata), - "M", "getlegendgraphic_formatlist"); - if (psFormat == NULL) { - msSetError(MS_IMGERR, - "Unsupported output format (%s).", - "msWMSGetLegendGraphic()", - pszFormat); - return msWMSException(map, nVersion, "InvalidFormat", wms_exception_format); - } - } else { - psFormat = msSelectOutputFormat( map, pszFormat); - if( psFormat == NULL || ! MS_RENDERER_PLUGIN(psFormat) ) - /* msDrawLegend and msCreateLegendIcon both switch the alpha channel to gd - ** after creation, so they can be called here without going through - ** the msAlphaGD2AGG functions */ - { - msSetError(MS_IMGERR, - "Unsupported output format (%s).", - "msWMSGetLegendGraphic()", - pszFormat); - return msWMSException(map, nVersion, "InvalidFormat", wms_exception_format); - } - } - msApplyOutputFormat(&(map->outputformat), psFormat, MS_NOOVERRIDE, - MS_NOOVERRIDE, MS_NOOVERRIDE ); - - if ( psRule == NULL || nLayers > 1) { - if ( psScale != NULL ) { - /* Scale-dependent legend. map->scaledenom will be calculated in msDrawLegend */ - img = msDrawLegend(map, MS_FALSE, NULL); - } else { - /* Scale-independent legend */ - img = msDrawLegend(map, MS_TRUE, hittest); - } - } else { - /* RULE was specified. Get the class corresponding to the RULE */ - /* (RULE = class->name) */ - /* TBT FIXME? also check the map->scaledenom if multiple scale-dependant classes with same name */ - - layerObj* lp = GET_LAYER(map, iLayerIndex); - int i; - for (i=0; inumclasses; i++) { - if (lp->classgroup && - (lp->_class[i]->group == NULL || - strcasecmp(lp->_class[i]->group, - lp->classgroup) != 0)) - continue; - - if (lp->_class[i]->name && - strlen(lp->_class[i]->name) > 0 && - strcasecmp(lp->_class[i]->name,psRule) == 0) - break; - - } - if (i < lp->numclasses) { - /* set the map legend parameters */ - if (nWidth < 0) { - if (map->legend.keysizex > 0) - nWidth = map->legend.keysizex; - else - nWidth = 20; /* default values : this in not defined in the specs */ - } - if (nHeight < 0) { - if (map->legend.keysizey > 0) - nHeight = map->legend.keysizey; - else - nHeight = 20; - } - - if ( psScale != NULL ) { - /* Scale-dependent legend. calculate map->scaledenom */ - map->cellsize = msAdjustExtent(&(map->extent), map->width, map->height); - msCalculateScale(map->extent, map->units, map->width, map->height, map->resolution, &map->scaledenom); - img = msCreateLegendIcon(map, lp, - lp->_class[i], - nWidth, nHeight, MS_FALSE); - } else { - /* Scale-independent legend */ - img = msCreateLegendIcon(map, lp, - lp->_class[i], - nWidth, nHeight, MS_TRUE); - } - } - if (img == NULL) { - msSetError(MS_IMGERR, - "Unavailable RULE (%s).", - "msWMSGetLegendGraphic()", - psRule); - return msWMSException(map, nVersion, "InvalidRule", wms_exception_format); - } - } - - if (img == NULL) - return msWMSException(map, nVersion, NULL, wms_exception_format); - - msIO_setHeader("Content-Type", "%s", MS_IMAGE_MIME_TYPE(map->outputformat)); - msIO_sendHeaders(); - if (msSaveImage(map, img, NULL) != MS_SUCCESS) - return msWMSException(map, nVersion, NULL, wms_exception_format); - - msFreeImage(img); - - return(MS_SUCCESS); -} - -/* -** msWMSGetContentDependantLegend() -*/ -static -int msWMSGetContentDependantLegend(mapObj *map, int nVersion, char **names, char **values, int numentries, - const char *wms_exception_format, owsRequestObj *ows_request) { - - /* turn off layer if WMS GetMap is not enabled */ - for (int i=0; inumlayers; i++) - if (!msIntegerInArray(GET_LAYER(map, i)->index, ows_request->enabled_layers, ows_request->numlayers)) - GET_LAYER(map, i)->status = MS_OFF; - - map_hittest hittest; - initMapHitTests(map,&hittest); - int status = msHitTestMap(map,&hittest); - if(status == MS_SUCCESS) { - status = msWMSLegendGraphic(map,nVersion,names,values,numentries,wms_exception_format,ows_request,&hittest); - } - freeMapHitTests(map,&hittest); - if(status != MS_SUCCESS) { - return msWMSException(map, nVersion, NULL, wms_exception_format); - } else { - return MS_SUCCESS; - } -} - -/* -** msWMSGetStyles() : return an SLD document for all layers that -** have a status set to on or default. -*/ -static -int msWMSGetStyles(mapObj *map, int nVersion, char **names, - char **values, int numentries, const char *wms_exception_format) - -{ - bool validlayer = false; - - char*** nestedGroups = (char***)msSmallCalloc(map->numlayers, sizeof(char**)); - int* numNestedGroups = (int*)msSmallCalloc(map->numlayers, sizeof(int)); - int* isUsedInNestedGroup = (int*)msSmallCalloc(map->numlayers, sizeof(int)); - msWMSPrepareNestedGroups(map, nVersion, nestedGroups, numNestedGroups, isUsedInNestedGroup); - - const char* sldenabled = msOWSLookupMetadata(&(map->web.metadata), "MO", "sld_enabled"); - if (sldenabled == NULL) sldenabled = "true"; - - for(int i=0; inumlayers; j++) - GET_LAYER(map, j)->status = MS_OFF; - - for (int k=0; k < static_cast(wmslayers.size()); k++) { - const auto& wmslayer = wmslayers[k]; - for (int j=0; jnumlayers; j++) { - if ((map->name && - strcasecmp(map->name, wmslayer.c_str()) == 0) || - (GET_LAYER(map, j)->name && - strcasecmp(GET_LAYER(map, j)->name, wmslayer.c_str()) == 0) || - (GET_LAYER(map, j)->group && - strcasecmp(GET_LAYER(map, j)->group, wmslayer.c_str()) == 0) || - ((numNestedGroups[j] >0) && msStringInArray(wmslayer.c_str(), nestedGroups[j], numNestedGroups[j])) ) { - GET_LAYER(map, j)->status = MS_ON; - validlayer = true; - } - } - } - } - - else if (strcasecmp(names[i], "SLD") == 0 && - values[i] && strlen(values[i]) > 0 && - strcasecmp(sldenabled, "true") == 0) - { - msSLDApplySLDURL(map, values[i], -1, NULL, NULL); - } - - else if (strcasecmp(names[i], "SLD_BODY") == 0 && - values[i] && strlen(values[i]) > 0 && - strcasecmp(sldenabled, "true") == 0) - { - msSLDApplySLD(map, values[i], -1, NULL, NULL); - } - } - - /* free the stuff used for nested layers */ - for (int i = 0; i < map->numlayers; i++) { - if (numNestedGroups[i] > 0) { - msFreeCharArray(nestedGroups[i], numNestedGroups[i]); - } - } - free(nestedGroups); - free(numNestedGroups); - free(isUsedInNestedGroup); - - /* validate all layers given. If an invalid layer is sent, return an exception. */ - if (!validlayer) { - msSetError(MS_WMSERR, "Invalid layer(s) given in the LAYERS parameter. A layer might be disabled for \ -this request. Check wms/ows_enable_request settings.", - "msWMSGetStyles()"); - return msWMSException(map, nVersion, "LayerNotDefined", wms_exception_format); - } - - char *sld = NULL; - if (nVersion <= OWS_1_1_1) { - msIO_setHeader("Content-Type","application/vnd.ogc.sld+xml; charset=UTF-8"); - msIO_sendHeaders(); - sld = msSLDGenerateSLD(map, -1, "1.0.0"); - } else { - /*for wms 1.3.0 generate a 1.1 sld*/ - msIO_setHeader("Content-Type","text/xml; charset=UTF-8"); - msIO_sendHeaders(); - sld = msSLDGenerateSLD(map, -1, "1.1.0"); - } - if (sld) { - msIO_printf("%s\n", sld); - free(sld); - } - - return(MS_SUCCESS); -} - -int msWMSGetSchemaExtension(mapObj *map) -{ - char* schemalocation = msEncodeHTMLEntities(msOWSGetSchemasLocation(map)); - - msIO_setHeader("Content-Type","text/xml; charset=UTF-8"); - msIO_sendHeaders(); - - msIO_printf("\n"); - msIO_printf("\n"); - msIO_printf(" \n", schemalocation); - msIO_printf(" \n"); - msIO_printf(""); - - free(schemalocation); - - return(MS_SUCCESS); -} - -#endif /* USE_WMS_SVR */ - - -/* -** msWMSDispatch() is the entry point for WMS requests. -** - If this is a valid request then it is processed and MS_SUCCESS is returned -** on success, or MS_FAILURE on failure. -** - If this does not appear to be a valid WMS request then MS_DONE -** is returned and MapServer is expected to process this as a regular -** MapServer request. -*/ -int msWMSDispatch(mapObj *map, cgiRequestObj *req, owsRequestObj *ows_request, int force_wms_mode) -{ -#ifdef USE_WMS_SVR - int nVersion=OWS_VERSION_NOTSET; - const char *version=NULL, *request=NULL, *service=NULL, *format=NULL, *updatesequence=NULL, *language=NULL; - const char *wms_exception_format = NULL; - - /* - ** Process Params common to all requests - */ - /* VERSION (WMTVER in 1.0.0) and REQUEST must be present in a valid request */ - for(int i=0; iNumParams; i++) { - if(strcasecmp(req->ParamNames[i], "VERSION") == 0) - version = req->ParamValues[i]; - else if (strcasecmp(req->ParamNames[i], "WMTVER") == 0 && version == NULL) - version = req->ParamValues[i]; - else if (strcasecmp(req->ParamNames[i], "UPDATESEQUENCE") == 0) - updatesequence = req->ParamValues[i]; - else if (strcasecmp(req->ParamNames[i], "REQUEST") == 0) - request = req->ParamValues[i]; - else if (strcasecmp(req->ParamNames[i], "EXCEPTIONS") == 0) - wms_exception_format = req->ParamValues[i]; - else if (strcasecmp(req->ParamNames[i], "SERVICE") == 0) - service = req->ParamValues[i]; - else if (strcasecmp(req->ParamNames[i], "FORMAT") == 0) - format = req->ParamValues[i]; - else if (strcasecmp(req->ParamNames[i], "LANGUAGE") == 0 && msOWSLookupMetadata(&(map->web.metadata), "MO", "inspire_capabilities")) - language = req->ParamValues[i]; - } - - /* If SERVICE is specified then it MUST be "WMS" */ - if (service != NULL && strcasecmp(service, "WMS") != 0) - return MS_DONE; /* Not a WMS request */ - - nVersion = msOWSParseVersionString(version); - if (nVersion == OWS_VERSION_BADFORMAT) { - /* Invalid version format. msSetError() has been called by - * msOWSParseVersionString() and we return the error as an exception - */ - return msWMSException(map, OWS_VERSION_NOTSET, NULL, wms_exception_format); - } - - /* - ** GetCapbilities request needs the service parametr defined as WMS: - see section 7.1.3.2 wms 1.1.1 specs for decsription. - */ - if (request && service == NULL && - (strcasecmp(request, "capabilities") == 0 || - strcasecmp(request, "GetCapabilities") == 0) && - (nVersion >= OWS_1_0_7 || nVersion == OWS_VERSION_NOTSET)) { - if (force_wms_mode) { - msSetError(MS_WMSERR, "Required SERVICE parameter missing.", "msWMSDispatch"); - return msWMSException(map, nVersion, "ServiceNotDefined", wms_exception_format); - } else - return MS_DONE; - } - - /* - ** Dispatch request... we should probably do some validation on VERSION here - ** vs the versions we actually support. - */ - if (request && (strcasecmp(request, "capabilities") == 0 || - strcasecmp(request, "GetCapabilities") == 0) ) { - const char *enable_request; - int globally_enabled, disabled = MS_FALSE; - - if (nVersion == OWS_VERSION_NOTSET) { - version = msOWSLookupMetadata(&(map->web.metadata), "M", "getcapabilities_version"); - if (version) - nVersion = msOWSParseVersionString(version); - else - nVersion = OWS_1_3_0;/* VERSION is optional with getCapabilities only */ - } - - if (msOWSMakeAllLayersUnique(map) != MS_SUCCESS) - return msWMSException(map, nVersion, NULL, wms_exception_format); - - msOWSRequestLayersEnabled(map, "M", "GetCapabilities", ows_request); - - enable_request = msOWSLookupMetadata(&map->web.metadata, "OM", "enable_request"); - globally_enabled = msOWSParseRequestMetadata(enable_request, "GetCapabilities", &disabled); - - if (ows_request->numlayers == 0 && !globally_enabled) { - msSetError(MS_WMSERR, "WMS request not enabled. Check wms/ows_enable_request settings.", "msWMSGetCapabilities()"); - return msWMSException(map, nVersion, NULL, wms_exception_format); - } - msAcquireLock(TLOCK_WxS); - const int status=msWMSGetCapabilities(map, nVersion, req, ows_request, updatesequence, wms_exception_format, language); - msReleaseLock(TLOCK_WxS); - return status; - } else if (request && (strcasecmp(request, "context") == 0 || - strcasecmp(request, "GetContext") == 0) ) { - /* Return a context document with all layers in this mapfile - * This is not a standard WMS request. - * __TODO__ The real implementation should actually return only context - * info for selected layers in the LAYERS parameter. - */ - const char *getcontext_enabled; - getcontext_enabled = msOWSLookupMetadata(&(map->web.metadata), - "MO", "getcontext_enabled"); - - if (nVersion != OWS_VERSION_NOTSET) { - /* VERSION, if specified, is Map Context version, not WMS version */ - /* Pass it via wms_context_version metadata */ - char szVersion[OWS_VERSION_MAXLEN]; - msInsertHashTable(&(map->web.metadata), "wms_context_version", - msOWSGetVersionString(nVersion, szVersion)); - } - /* Now set version to 1.1.1 for error handling purposes */ - nVersion = OWS_1_1_1; - - if (getcontext_enabled==NULL || atoi(getcontext_enabled) == 0) { - msSetError(MS_WMSERR, "GetContext not enabled on this server.", - "msWMSDispatch()"); - return msWMSException(map, nVersion, NULL, wms_exception_format); - } - - if (msOWSMakeAllLayersUnique(map) != MS_SUCCESS) - return msWMSException(map, nVersion, NULL, wms_exception_format); - - msIO_setHeader("Content-Type","text/xml; charset=UTF-8"); - msIO_sendHeaders(); - - if ( msWriteMapContext(map, stdout) != MS_SUCCESS ) - return msWMSException(map, nVersion, NULL, wms_exception_format); - /* Request completed */ - return MS_SUCCESS; - } else if (request && strcasecmp(request, "GetMap") == 0 && - format && strcasecmp(format, "image/txt") == 0) { - /* Until someone adds full support for ASCII graphics this should do. ;) */ - msIO_setHeader("Content-Type","text/plain; charset=UTF-8"); - msIO_sendHeaders(); - msIO_printf(".\n ,,ggddY\"\"\"Ybbgg,,\n ,agd888b,_ " - "\"Y8, ___'\"\"Ybga,\n ,gdP\"\"88888888baa,.\"\"8b \"" - "888g,\n ,dP\" ]888888888P' \"Y '888Yb,\n ,dP\"" - " ,88888888P\" db, \"8P\"\"Yb,\n ,8\" ,8888" - "88888b, d8888a \"8,\n ,8' d88888888888,88P\"" - "' a, '8,\n,8' 88888888888888PP\" \"\" " - " '8,\nd' I88888888888P\" 'b\n8" - " '8\"88P\"\"Y8P' 8\n8 " - " Y 8[ _ \" 8\n8 \"Y8d8" - "b \"Y a 8\n8 '\"\"8d, __" - " 8\nY, '\"8bd888b, " - " ,P\n'8, ,d8888888baaa ,8'\n '8" - ", 888888888888' ,8'\n '8a " - " \"8888888888I a8'\n 'Yba 'Y88" - "88888P' adP'\n \"Yba '888888P' adY\"" - "\n '\"Yba, d8888P\" ,adP\"' \n '\"" - "Y8baa, ,d888P,ad8P\"' \n ''\"\"YYba8888P\"" - "\"''\n"); - return MS_SUCCESS; - } - - /* If SERVICE, VERSION and REQUEST not included than this isn't a WMS req*/ - if (service == NULL && nVersion == OWS_VERSION_NOTSET && request==NULL) - return MS_DONE; /* Not a WMS request */ - - /* VERSION *and* REQUEST required by both getMap and getFeatureInfo */ - if (nVersion == OWS_VERSION_NOTSET) { - msSetError(MS_WMSERR, - "Incomplete WMS request: VERSION parameter missing", - "msWMSDispatch()"); - return msWMSException(map, OWS_VERSION_NOTSET, NULL, wms_exception_format); - } - - /*check if the version is one of the supported vcersions*/ - if (nVersion != OWS_1_0_0 && nVersion != OWS_1_0_6 && - nVersion != OWS_1_0_7 && nVersion != OWS_1_1_0 && - nVersion != OWS_1_1_1 && nVersion != OWS_1_3_0) { - msSetError(MS_WMSERR, - "Invalid WMS version: VERSION %s is not supported. Supported versions are 1.0.0, 1.0.6, 1.0.7, 1.1.0, 1.1.1, 1.3.0", - "msWMSDispatch()", version); - return msWMSException(map, OWS_VERSION_NOTSET, NULL, wms_exception_format); - } - - if (request==NULL) { - msSetError(MS_WMSERR, - "Incomplete WMS request: REQUEST parameter missing", - "msWMSDispatch()"); - return msWMSException(map, nVersion, NULL, wms_exception_format); - } - - /* hack !? The function can return MS_DONE ... be sure it's a wms request - * before checking the enabled layers */ - if ( (strcasecmp(request, "GetStyles") == 0) || - (strcasecmp(request, "GetLegendGraphic") == 0) || - (strcasecmp(request, "GetSchemaExtension") == 0) || - (strcasecmp(request, "map") == 0 || strcasecmp(request, "GetMap") == 0) || - (strcasecmp(request, "feature_info") == 0 || strcasecmp(request, "GetFeatureInfo") == 0) || - (strcasecmp(request, "DescribeLayer") == 0) ) { - const char* request_tmp; - if (strcasecmp(request, "map") == 0) - request_tmp = "GetMap"; - else if (strcasecmp(request, "feature_info") == 0) - request_tmp = "GetFeatureInfo"; - else - request_tmp = request; - - msOWSRequestLayersEnabled(map, "M", request_tmp, ows_request); - if (ows_request->numlayers == 0) { - msSetError(MS_WMSERR, "WMS request not enabled. Check wms/ows_enable_request settings.", "msWMSDispatch()"); - return msWMSException(map, nVersion, NULL, wms_exception_format); - } - } - - if (msOWSMakeAllLayersUnique(map) != MS_SUCCESS) - return msWMSException(map, nVersion, NULL, wms_exception_format); - - bool isContentDependantLegend = false; - if (strcasecmp(request, "GetLegendGraphic") == 0) { - /* - * check for a BBOX in the request, in that case we have a content-dependant legend request, - * and should be following the GetMap path a bit more - */ - bool found = false; - for(int i=0; iNumParams; i++) { - if(strcasecmp(req->ParamNames[i], "BBOX") == 0) { - if(req->ParamValues[i] && *req->ParamValues[i]) { - found = true; - break; - } - } - } - if(found) { - isContentDependantLegend = true; - /* getLegendGraphic uses LAYER= , we need to create a LAYERS= value that is identical - * we'll suppose that the client is conformat and hasn't included a LAYERS= parameter - * in its request */ - for(int i=0; iNumParams; i++) { - if(strcasecmp(req->ParamNames[i], "LAYER") == 0) { - req->ParamNames[req->NumParams] = msStrdup("LAYERS"); - req->ParamValues[req->NumParams] = msStrdup(req->ParamValues[i]); - req->NumParams++; - } - } - } else { - return msWMSLegendGraphic(map, nVersion, req->ParamNames, req->ParamValues, req->NumParams, - wms_exception_format, ows_request, NULL); - } - } - - if (strcasecmp(request, "GetStyles") == 0) - return msWMSGetStyles(map, nVersion, req->ParamNames, req->ParamValues, req->NumParams, - wms_exception_format); - - else if (request && strcasecmp(request, "GetSchemaExtension") == 0) - return msWMSGetSchemaExtension(map); - - /* getMap parameters are used by both getMap, getFeatureInfo, and content dependant legendgraphics */ - if (strcasecmp(request, "map") == 0 || strcasecmp(request, "GetMap") == 0 || - strcasecmp(request, "feature_info") == 0 || strcasecmp(request, "GetFeatureInfo") == 0 || strcasecmp(request, "DescribeLayer") == 0 || isContentDependantLegend) { - - const int status = msWMSLoadGetMapParams(map, nVersion, req->ParamNames, req->ParamValues, req->NumParams, - wms_exception_format, request, ows_request); - if (status != MS_SUCCESS) return status; - } - - /* This function owns validated_language, so remember to free it later*/ - char* validated_language = msOWSGetLanguageFromList(map, "MO", language); - if (validated_language != NULL) { - msMapSetLanguageSpecificConnection(map, validated_language); - } - msFree(validated_language); - - if (strcasecmp(request, "map") == 0 || strcasecmp(request, "GetMap") == 0) - return msWMSGetMap(map, nVersion, req->ParamNames, req->ParamValues, req->NumParams, wms_exception_format, ows_request); - else if (strcasecmp(request, "feature_info") == 0 || strcasecmp(request, "GetFeatureInfo") == 0) - return msWMSFeatureInfo(map, nVersion, req->ParamNames, req->ParamValues, req->NumParams, wms_exception_format, ows_request); - else if (strcasecmp(request, "DescribeLayer") == 0) { - return msWMSDescribeLayer(map, nVersion, req->ParamNames, req->ParamValues, req->NumParams, - wms_exception_format); - } else if (isContentDependantLegend) { - return msWMSGetContentDependantLegend(map,nVersion, req->ParamNames, req->ParamValues, req->NumParams, wms_exception_format, ows_request); - } - - /* Hummmm... incomplete or unsupported WMS request */ - if (service != NULL && strcasecmp(service, "WMS") == 0) { - msSetError(MS_WMSERR, "Incomplete or unsupported WMS request", "msWMSDispatch()"); - return msWMSException(map, nVersion, NULL, wms_exception_format); - } else - return MS_DONE; /* Not a WMS request */ -#else - msSetError(MS_WMSERR, "WMS server support is not available.", "msWMSDispatch()"); - return(MS_FAILURE); -#endif -} - diff --git a/mapwmslayer.c b/mapwmslayer.c deleted file mode 100755 index 899db5e91f..0000000000 --- a/mapwmslayer.c +++ /dev/null @@ -1,1641 +0,0 @@ -/***************************************************************************** - * $Id$ - * - * Project: MapServer - * Purpose: Implementation of WMS CONNECTIONTYPE - client to WMS servers - * Author: Daniel Morissette, DM Solutions Group (morissette@dmsolutions.ca) - * - ***************************************************************************** - * Copyright (c) 2001-2004, Daniel Morissette, DM Solutions Group Inc - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies of this Software or works derived from this Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - *****************************************************************************/ - -#include "mapserver.h" -#include "maperror.h" -#include "mapogcsld.h" -#include "mapows.h" - -#include -#include - -#if defined(_WIN32) && !defined(__CYGWIN__) -#include -#include -#endif - -#include "cpl_vsi.h" - -/********************************************************************** - * msInitWmsParamsObj() - * - **********************************************************************/ -int msInitWmsParamsObj(wmsParamsObj *wmsparams) -{ - wmsparams->onlineresource = NULL; - wmsparams->params = msCreateHashTable(); - wmsparams->numparams=0; - wmsparams->httpcookiedata = NULL; - - return MS_SUCCESS; -} - -/********************************************************************** - * msFreeWmsParamsObj() - * - * Frees the contents of the object, but not the object itself. - **********************************************************************/ -void msFreeWmsParamsObj(wmsParamsObj *wmsparams) -{ - msFree(wmsparams->onlineresource); - wmsparams->onlineresource = NULL; - - msFreeHashTable(wmsparams->params); - wmsparams->params = NULL; - - msFree(wmsparams->httpcookiedata); - - wmsparams->numparams=0; -} - -/********************************************************************** - * msSetWMSParamString() - * - **********************************************************************/ - -#ifdef USE_WMS_LYR -static int msSetWMSParamString(wmsParamsObj *psWMSParams, - const char *name, const char * value, - int urlencode, int nVersion) -{ - if (urlencode) { - char *pszTmp; - - /* - * Special case handling for characters the WMS specification - * says should not be encoded, when they occur in certain - * parameters. - * - * Note: WMS 1.3 removes SRS and FORMAT from the set of - * exceptional cases, but renames SRS as CRS in any case. - */ - if( strcmp(name,"LAYERS") == 0 || - strcmp(name,"STYLES") == 0 || - strcmp(name,"BBOX") == 0 ) { - pszTmp = msEncodeUrlExcept(value,','); - } else if ( strcmp(name,"SRS") == 0 ) { - pszTmp = msEncodeUrlExcept(value,':'); - } else if ( nVersion < OWS_1_3_0 && strcmp(name,"FORMAT") == 0 ) { - pszTmp = msEncodeUrlExcept(value,'/'); - } else { - pszTmp = msEncodeUrl(value); - } - - msInsertHashTable(psWMSParams->params, name, pszTmp); - msFree(pszTmp); - } else { - msInsertHashTable(psWMSParams->params, name, value); - } - psWMSParams->numparams++; - - return MS_SUCCESS; -} -#endif /* def USE_WMS_LYR */ - -/********************************************************************** - * msSetWMSParamInt() - * - **********************************************************************/ - -#ifdef USE_WMS_LYR -static int msSetWMSParamInt(wmsParamsObj *wmsparams, - const char *name, int value) -{ - char szBuf[100]; - - snprintf(szBuf, sizeof(szBuf), "%d", value); - msInsertHashTable(wmsparams->params, name, szBuf); - wmsparams->numparams++; - - return MS_SUCCESS; -} -#endif /* def USE_WMS_LYR */ - -/********************************************************************** - * msBuildWMSParamsUrl() - * - **********************************************************************/ -static char *msBuildURLFromWMSParams(wmsParamsObj *wmsparams) -{ - const char *key, *value; - size_t bufferSize = 0; - int nLen; - char *pszURL; - - /* Compute size required for URL buffer - */ - nLen = strlen(wmsparams->onlineresource) + 3; - - key = msFirstKeyFromHashTable(wmsparams->params); - while (key != NULL) { - value = msLookupHashTable(wmsparams->params, key); - nLen += strlen(key) + strlen(value) + 2; - - key = msNextKeyFromHashTable(wmsparams->params, key); - } - - bufferSize = nLen+1; - pszURL = (char*)msSmallMalloc(bufferSize); - - /* Start with the onlineresource value and append trailing '?' or '&' - * if missing. - */ - strcpy(pszURL, wmsparams->onlineresource); - if (strchr(pszURL, '?') == NULL) - strcat(pszURL, "?"); - else { - char *c; - c = pszURL+strlen(pszURL)-1; - if (*c != '?' && *c != '&') - strcpy(c+1, "&"); - } - - /* Now add all the parameters - */ - nLen = strlen(pszURL); - key = msFirstKeyFromHashTable(wmsparams->params); - while (key != NULL) { - value = msLookupHashTable(wmsparams->params, key); - snprintf(pszURL+nLen, bufferSize-nLen, "%s=%s&", key, value); - nLen += strlen(key) + strlen(value) + 2; - key = msNextKeyFromHashTable(wmsparams->params, key); - } - - /* Get rid of trailing '&'*/ - pszURL[nLen-1] = '\0'; - - - return pszURL; -} - - - - -#ifdef USE_WMS_LYR -/********************************************************************** - * msBuildWMSLayerURLBase() - * - * Build the base of a GetMap or GetFeatureInfo URL using metadata. - * The parameters to set are: - * VERSION - * LAYERS - * FORMAT - * TRANSPARENT - * STYLES - * QUERY_LAYERS (for queriable layers only) - * - * Returns a reference to a newly allocated string that should be freed - * by the caller. - **********************************************************************/ -static int msBuildWMSLayerURLBase(mapObj *map, layerObj *lp, - wmsParamsObj *psWMSParams, int nRequestType) -{ - const char *pszOnlineResource, *pszVersion, *pszName, *pszFormat; - const char *pszFormatList, *pszStyle, /* *pszStyleList,*/ *pszTime; - const char *pszBgColor, *pszTransparent; - const char *pszSLD=NULL, *pszStyleSLDBody=NULL, *pszVersionKeyword=NULL; - const char *pszSLDBody=NULL, *pszSLDURL = NULL; - char *pszSLDGenerated = NULL; - int nVersion=OWS_VERSION_NOTSET; - - /* If lp->connection is not set then use wms_onlineresource metadata */ - pszOnlineResource = lp->connection; - if (pszOnlineResource == NULL) - pszOnlineResource = msOWSLookupMetadata(&(lp->metadata), - "MO", "onlineresource"); - - pszVersion = msOWSLookupMetadata(&(lp->metadata), "MO", "server_version"); - pszName = msOWSLookupMetadata(&(lp->metadata), "MO", "name"); - pszFormat = msOWSLookupMetadata(&(lp->metadata), "MO", "format"); - pszFormatList = msOWSLookupMetadata(&(lp->metadata), "MO", "formatlist"); - pszStyle = msOWSLookupMetadata(&(lp->metadata), "MO", "style"); - /*pszStyleList = msOWSLookupMetadata(&(lp->metadata), "MO", "stylelist");*/ - pszTime = msOWSLookupMetadata(&(lp->metadata), "MO", "time"); - pszSLDBody = msOWSLookupMetadata(&(lp->metadata), "MO", "sld_body"); - pszSLDURL = msOWSLookupMetadata(&(lp->metadata), "MO", "sld_url"); - pszBgColor = msOWSLookupMetadata(&(lp->metadata), "MO", "bgcolor"); - pszTransparent = msOWSLookupMetadata(&(lp->metadata), "MO", "transparent"); - - if (pszOnlineResource==NULL || pszVersion==NULL || pszName==NULL) { - msSetError(MS_WMSCONNERR, - "One of wms_onlineresource, wms_server_version, wms_name " - "metadata is missing in layer %s. " - "Please either provide a valid CONNECTION URL, or provide " - "those values in the layer's metadata.\n", - "msBuildWMSLayerURLBase()", lp->name); - return MS_FAILURE; - } - - psWMSParams->onlineresource = msStrdup(pszOnlineResource); - - if (strncmp(pszVersion, "1.0.7", 5) < 0) - pszVersionKeyword = "WMTVER"; - else - pszVersionKeyword = "VERSION"; - - nVersion = msOWSParseVersionString(pszVersion); - /* WMS 1.0.8 is really just 1.1.0 */ - if (nVersion == OWS_1_0_8) nVersion = OWS_1_1_0; - - msSetWMSParamString(psWMSParams, pszVersionKeyword, pszVersion, MS_FALSE, nVersion); - msSetWMSParamString(psWMSParams, "SERVICE", "WMS", MS_FALSE, nVersion); - msSetWMSParamString(psWMSParams, "LAYERS", pszName, MS_TRUE, nVersion); - - if (pszFormat==NULL && pszFormatList==NULL) { - msSetError(MS_WMSCONNERR, - "At least wms_format or wms_formatlist is required for " - "layer %s. " - "Please either provide a valid CONNECTION URL, or provide " - "those values in the layer's metadata.\n", - "msBuildWMSLayerURLBase()", lp->name); - return MS_FAILURE; - } - - if (pszFormat != NULL) { - msSetWMSParamString(psWMSParams, "FORMAT", pszFormat, MS_TRUE, nVersion); - } else { - /* Look for the first format in list that matches */ - char **papszTok; - int i, n; - papszTok = msStringSplit(pszFormatList, ',', &n); - - for(i=0; pszFormat==NULL && iname); - msFreeCharArray(papszTok, n); - return MS_FAILURE; - } - } - - if (pszStyle==NULL) { - /* When no style is selected, use "" which is a valid default. */ - pszStyle = ""; - } else { - /* Was a wms_style_..._sld URL provided? */ - char szBuf[100]; - snprintf(szBuf, sizeof(szBuf), "style_%.80s_sld", pszStyle); - pszSLD = msOWSLookupMetadata(&(lp->metadata), "MO", szBuf); - snprintf(szBuf, sizeof(szBuf), "style_%.80s_sld_body", pszStyle); - pszStyleSLDBody = msOWSLookupMetadata(&(lp->metadata), "MO", szBuf); - - if (pszSLD || pszStyleSLDBody) { - /* SLD URL is set. If this defn. came from a map context then */ - /* the style name may just be an internal name: "Style{%d}" if */ - /* that's the case then we should not pass this name via the URL */ - if (strncmp(pszStyle, "Style{", 6) == 0) - pszStyle = ""; - } - } - - /* set STYLE parameter no matter what, even if it's empty (i.e. "STYLES=") - * GetLegendGraphic doesn't support multiple styles and is named STYLE - */ - if (nRequestType == WMS_GETLEGENDGRAPHIC) { - msSetWMSParamString(psWMSParams, "STYLE", pszStyle, MS_TRUE, nVersion); - } else { - msSetWMSParamString(psWMSParams, "STYLES", pszStyle, MS_TRUE, nVersion); - } - - if (pszSLD != NULL) { - /* Only SLD is set */ - msSetWMSParamString(psWMSParams, "SLD", pszSLD, MS_TRUE, nVersion); - } else if (pszStyleSLDBody != NULL) { - /* SLDBODY are set */ - msSetWMSParamString(psWMSParams, "SLD_BODY", pszStyleSLDBody, MS_TRUE, nVersion); - } - - if (msIsLayerQueryable(lp)) { - msSetWMSParamString(psWMSParams, "QUERY_LAYERS", pszName, MS_TRUE, nVersion); - } - if (pszTime && strlen(pszTime) > 0) { - msSetWMSParamString(psWMSParams, "TIME", pszTime, MS_TRUE, nVersion); - } - - /* if the metadata wms_sld_body is set to AUTO, we generate - * the sld based on classes found in the map file and send - * it in the URL. If diffrent from AUTO, we are assuming that - * it is a valid sld. - */ - if (pszSLDBody) { - if (strcasecmp(pszSLDBody, "AUTO") == 0) { - if (pszVersion && strncmp(pszVersion, "1.3.0", 5) == 0) - pszSLDGenerated = msSLDGenerateSLD(map, lp->index, "1.1.0"); - else - pszSLDGenerated = msSLDGenerateSLD(map, lp->index, NULL); - - if (pszSLDGenerated) { - msSetWMSParamString(psWMSParams, "SLD_BODY", - pszSLDGenerated, MS_TRUE, nVersion); - free(pszSLDGenerated); - } - } else { - msSetWMSParamString(psWMSParams, "SLD_BODY", pszSLDBody, MS_TRUE, nVersion); - } - - } - - if (pszSLDURL) { - msSetWMSParamString(psWMSParams, "SLD", pszSLDURL, MS_TRUE, nVersion); - } - - if (pszBgColor) { - msSetWMSParamString(psWMSParams, "BGCOLOR", pszBgColor, MS_TRUE, nVersion); - } - - if (pszTransparent) { - msSetWMSParamString(psWMSParams, "TRANSPARENT", pszTransparent, MS_TRUE, nVersion); - } else { - msSetWMSParamString(psWMSParams, "TRANSPARENT", "TRUE", MS_TRUE, nVersion); - } - - return MS_SUCCESS; -} - -#endif /* USE_WMS_LYR */ - - -/********************************************************************** - * msBuildWMSLayerURL() - * - * Build a GetMap or GetFeatureInfo URL. - * - * Returns a reference to a newly allocated string that should be freed - * by the caller. - **********************************************************************/ - -static int -msBuildWMSLayerURL(mapObj *map, layerObj *lp, int nRequestType, - int nClickX, int nClickY, int nFeatureCount, - const char *pszInfoFormat, rectObj *bbox_ret, - int *width_ret, int *height_ret, - wmsParamsObj *psWMSParams) -{ -#ifdef USE_WMS_LYR - char *pszEPSG = NULL; - const char *pszVersion, *pszRequestParam, *pszExceptionsParam, - *pszSrsParamName="SRS", *pszLayer=NULL, *pszQueryLayers=NULL, - *pszUseStrictAxisOrder; - rectObj bbox; - int bbox_width = map->width, bbox_height = map->height; - int nVersion=OWS_VERSION_NOTSET; - int bUseStrictAxisOrder = MS_FALSE; /* this is the assumption up to 1.1.0 */ - int bFlipAxisOrder = MS_FALSE; - const char *pszTmp; - int bIsEssential = MS_FALSE; - - if (lp->connectiontype != MS_WMS) { - msSetError(MS_WMSCONNERR, "Call supported only for CONNECTIONTYPE WMS", - "msBuildWMSLayerURL()"); - return MS_FAILURE; - } - - /* ------------------------------------------------------------------ - * Find out request version - * ------------------------------------------------------------------ */ - if (lp->connection == NULL || - ((pszVersion = strstr(lp->connection, "VERSION=")) == NULL && - (pszVersion = strstr(lp->connection, "version=")) == NULL && - (pszVersion = strstr(lp->connection, "WMTVER=")) == NULL && - (pszVersion = strstr(lp->connection, "wmtver=")) == NULL ) ) { - /* CONNECTION missing or seems incomplete... try to build from metadata */ - if (msBuildWMSLayerURLBase(map, lp, psWMSParams, nRequestType) != MS_SUCCESS) - return MS_FAILURE; /* An error already produced. */ - - /* If we received MS_SUCCESS then version must have been set */ - pszVersion = msLookupHashTable(psWMSParams->params, "VERSION"); - if (pszVersion ==NULL) - pszVersion = msLookupHashTable(psWMSParams->params, "WMTVER"); - - nVersion = msOWSParseVersionString(pszVersion); - } else { - /* CONNECTION string seems complete, start with that. */ - char *pszDelimiter; - psWMSParams->onlineresource = msStrdup(lp->connection); - - /* Fetch version info */ - pszVersion = strchr(pszVersion, '=')+1; - pszDelimiter = strchr(pszVersion, '&'); - if (pszDelimiter != NULL) - *pszDelimiter = '\0'; - nVersion = msOWSParseVersionString(pszVersion); - if (pszDelimiter != NULL) - *pszDelimiter = '&'; - } - - switch (nVersion) { - case OWS_1_0_8: - nVersion = OWS_1_1_0; /* 1.0.8 == 1.1.0 */ - break; - case OWS_1_0_0: - case OWS_1_0_1: - case OWS_1_0_7: - case OWS_1_1_0: - case OWS_1_1_1: - /* All is good, this is a supported version. */ - break; - case OWS_1_3_0: - /* 1.3.0 introduces a few changes... */ - pszSrsParamName = "CRS"; - bUseStrictAxisOrder = MS_TRUE; /* this is the assumption for 1.3.0 */ - break; - default: - /* Not a supported version */ - msSetError(MS_WMSCONNERR, "MapServer supports only WMS 1.0.0 to 1.3.0 (please verify the VERSION parameter in the connection string).", "msBuildWMSLayerURL()"); - return MS_FAILURE; - } - - /* ------------------------------------------------------------------ - * For GetFeatureInfo requests, make sure QUERY_LAYERS is included - * ------------------------------------------------------------------ */ - if (nRequestType == WMS_GETFEATUREINFO && - strstr(psWMSParams->onlineresource, "QUERY_LAYERS=") == NULL && - strstr(psWMSParams->onlineresource, "query_layers=") == NULL && - msLookupHashTable(psWMSParams->params, "QUERY_LAYERS") == NULL) { - pszQueryLayers = msOWSLookupMetadata(&(lp->metadata), "MO", "name"); - - if (pszQueryLayers == NULL) { - msSetError(MS_WMSCONNERR, "wms_name not set or WMS Connection String must contain the QUERY_LAYERS parameter to support GetFeatureInfo requests (with name in uppercase).", "msBuildWMSLayerURL()"); - return MS_FAILURE; - } - } - - /* ------------------------------------------------------------------ - * For GetLegendGraphic requests, make sure LAYER is included - * ------------------------------------------------------------------ */ - if (nRequestType == WMS_GETLEGENDGRAPHIC && - strstr(psWMSParams->onlineresource, "LAYER=") == NULL && - strstr(psWMSParams->onlineresource, "layer=") == NULL && - msLookupHashTable(psWMSParams->params, "LAYER") == NULL) { - pszLayer = msOWSLookupMetadata(&(lp->metadata), "MO", "name"); - - if (pszLayer == NULL) { - msSetError(MS_WMSCONNERR, "wms_name not set or WMS Connection String must contain the LAYER parameter to support GetLegendGraphic requests (with name in uppercase).", "msBuildWMSLayerURL()"); - return MS_FAILURE; - } - } - - /* ------------------------------------------------------------------ - * Figure the SRS we'll use for the request. - * - Fetch the map SRS (if it's EPSG) - * - Check if map SRS is listed in layer wms_srs metadata - * - If map SRS is valid for this layer then use it - * - Otherwise request layer in its default SRS and we'll reproject later - * ------------------------------------------------------------------ */ - msOWSGetEPSGProj(&(map->projection),NULL, NULL, MS_TRUE, &pszEPSG); - if ( pszEPSG && - (strncasecmp(pszEPSG, "EPSG:", 5) == 0 || - strncasecmp(pszEPSG, "AUTO:", 5) == 0) ) { - const char *pszFound; - char *pszLyrEPSG; - int nLen; - char *pszPtr = NULL; - - /* If it's an AUTO projection then keep only id and strip off */ - /* the parameters for now (we'll restore them at the end) */ - if (strncasecmp(pszEPSG, "AUTO:", 5) == 0) { - if ((pszPtr = strchr(pszEPSG, ','))) - *pszPtr = '\0'; - } - - nLen = strlen(pszEPSG); - - msOWSGetEPSGProj(&(lp->projection), &(lp->metadata), "MO", MS_FALSE, &pszLyrEPSG); - - if (pszLyrEPSG == NULL || - (pszFound = strstr(pszLyrEPSG, pszEPSG)) == NULL || - ! ((*(pszFound+nLen) == '\0') || isspace(*(pszFound+nLen))) ) { - /* Not found in Layer's list of SRS (including projection object) */ - free(pszEPSG); - pszEPSG = NULL; - } - msFree(pszLyrEPSG); - if (pszEPSG && pszPtr) - *pszPtr = ','; /* Restore full AUTO:... definition */ - } - - if (pszEPSG == NULL) { - msOWSGetEPSGProj(&(lp->projection), &(lp->metadata),"MO", MS_TRUE, &pszEPSG); - if( pszEPSG == NULL || (strncasecmp(pszEPSG, "EPSG:", 5) != 0 && strncasecmp(pszEPSG, "AUTO:", 5) != 0) ) { - msSetError(MS_WMSCONNERR, "Layer must have an EPSG or AUTO projection code (in its PROJECTION object or wms_srs metadata)", "msBuildWMSLayerURL()"); - msFree(pszEPSG); - return MS_FAILURE; - } - } - - /* ------------------------------------------------------------------ - * For an AUTO projection, set the Units,lon0,lat0 if not already set - * ------------------------------------------------------------------ */ - if (strncasecmp(pszEPSG, "AUTO:", 5) == 0 && - strchr(pszEPSG, ',') == NULL) { - pointObj oPoint; - char *pszNewEPSG; - - /* Use center of map view for lon0,lat0 */ - oPoint.x = (map->extent.minx + map->extent.maxx)/2.0; - oPoint.y = (map->extent.miny + map->extent.maxy)/2.0; - msProjectPoint(&(map->projection), &(map->latlon), &oPoint); - - pszNewEPSG = (char*)msSmallMalloc(101*sizeof(char)); - - snprintf(pszNewEPSG, 100, "%s,9001,%.16g,%.16g", - pszEPSG, oPoint.x, oPoint.y); - pszNewEPSG[100]='\0'; - free(pszEPSG); - pszEPSG=pszNewEPSG; - } - - /* - * Work out whether we'll be wanting to flip the axis order for the request - */ - pszUseStrictAxisOrder = msOWSLookupMetadata(&(lp->metadata), "MO", "strict_axis_order"); - if (pszUseStrictAxisOrder != NULL) { - if (strncasecmp(pszUseStrictAxisOrder, "1", 1) == 0 || - strncasecmp(pszUseStrictAxisOrder, "true", 4) == 0) { - bUseStrictAxisOrder = MS_TRUE; - } else if (strncasecmp(pszUseStrictAxisOrder, "0", 1) == 0 || - strncasecmp(pszUseStrictAxisOrder, "false", 5) == 0) { - bUseStrictAxisOrder = MS_FALSE; - } - } - if (bUseStrictAxisOrder == MS_TRUE && pszEPSG && - strncasecmp(pszEPSG, "EPSG:", 5) == 0 && - msIsAxisInverted(atoi(pszEPSG + 5))) { - bFlipAxisOrder = MS_TRUE; - } - - /* ------------------------------------------------------------------ - * Set layer SRS. - * ------------------------------------------------------------------ */ - /* No need to set lp->proj if it's already set to the right EPSG code */ - { - char* pszEPSGCodeFromLayer = NULL; - msOWSGetEPSGProj(&(lp->projection), NULL, "MO", MS_TRUE, &pszEPSGCodeFromLayer); - if (pszEPSGCodeFromLayer == NULL || strcasecmp(pszEPSG, pszEPSGCodeFromLayer) != 0) { - char *ows_srs; - msOWSGetEPSGProj(NULL,&(lp->metadata), "MO", MS_FALSE, &ows_srs); - /* no need to set lp->proj if it is already set and there is only - one item in the _srs metadata for this layer - we will assume - the projection block matches the _srs metadata (the search for ' ' - in ows_srs is a test to see if there are multiple EPSG: codes) */ - if( lp->projection.numargs == 0 || ows_srs == NULL || (strchr(ows_srs,' ') != NULL) ) { - msFree(ows_srs); - if (strncasecmp(pszEPSG, "EPSG:", 5) == 0) { - char szProj[20]; - snprintf(szProj, sizeof(szProj), "init=epsg:%s", pszEPSG+5); - if (msLoadProjectionString(&(lp->projection), szProj) != 0) - return MS_FAILURE; - } else { - if (msLoadProjectionString(&(lp->projection), pszEPSG) != 0) - return MS_FAILURE; - } - } - } - msFree(pszEPSGCodeFromLayer); - } - - /* ------------------------------------------------------------------ - * Adjust for MapServer EXTENT being center of pixel and WMS BBOX being - * edge of pixel (#2843). - * ------------------------------------------------------------------ */ - bbox = map->extent; - - bbox.minx -= map->cellsize * 0.5; - bbox.maxx += map->cellsize * 0.5; - bbox.miny -= map->cellsize * 0.5; - bbox.maxy += map->cellsize * 0.5; - - /* -------------------------------------------------------------------- */ - /* Reproject if needed. */ - /* -------------------------------------------------------------------- */ - if (msProjectionsDiffer(&(map->projection), &(lp->projection))) { - msProjectRect(&(map->projection), &(lp->projection), &bbox); - - /* -------------------------------------------------------------------- */ - /* Sometimes our remote WMS only accepts square pixel */ - /* requests. If this is the case adjust adjust the number of */ - /* pixels or lines in the request so that the pixels are */ - /* square. */ - /* -------------------------------------------------------------------- */ - { - const char *nonsquare_ok = - msOWSLookupMetadata(&(lp->metadata), - "MO", "nonsquare_ok"); - - /* assume nonsquare_ok is false */ - if( nonsquare_ok != NULL - && (strcasecmp(nonsquare_ok,"no") == 0 - || strcasecmp(nonsquare_ok,"false") == 0) ) { - double cellsize_x = (bbox.maxx-bbox.minx) / bbox_width; - double cellsize_y = (bbox.maxy-bbox.miny) / bbox_height; - - if( cellsize_x < cellsize_y * 0.999999 ) { - int new_bbox_height = - ceil((cellsize_y/cellsize_x) * bbox_height); - - if (lp->debug) - msDebug("NONSQUARE_OK=%s, adjusted HEIGHT from %d to %d to equalize cellsize at %g.\n", - nonsquare_ok, - bbox_height, new_bbox_height, cellsize_x ); - bbox_height = new_bbox_height; - } else if( cellsize_y < cellsize_x * 0.999999 ) { - int new_bbox_width = - ceil((cellsize_x/cellsize_y) * bbox_width); - - if (lp->debug) - msDebug("NONSQUARE_OK=%s, adjusted WIDTH from %d to %d to equalize cellsize at %g.\n", - nonsquare_ok, - bbox_width, new_bbox_width, cellsize_y ); - bbox_width = new_bbox_width; - } else { - if (lp->debug) - msDebug("NONSQUARE_OK=%s, but cellsize was already square - no change.\n", - nonsquare_ok ); - } - } - } - } - - /* -------------------------------------------------------------------- */ - /* If the layer has predefined extents, and a predefined */ - /* projection that matches the request projection, then */ - /* consider restricting the BBOX to match the limits. */ - /* -------------------------------------------------------------------- */ - if( bbox_width != 0 ) { - char *ows_srs; - rectObj layer_rect; - - msOWSGetEPSGProj(&(lp->projection), &(lp->metadata), "MO", MS_FALSE, &ows_srs); - - if( ows_srs && strchr(ows_srs,' ') == NULL - && msOWSGetLayerExtent( map, lp, "MO", &layer_rect) == MS_SUCCESS ) { - /* fulloverlap */ - if( msRectContained( &bbox, &layer_rect ) ) { - /* no changes */ - } - - /* no overlap */ - else if( !msRectOverlap( &layer_rect, &bbox ) ) { - bbox_width = 0; - bbox_height = 0; - } - - else { - double cellsize_x = (bbox.maxx-bbox.minx) / bbox_width; - double cellsize_y = (bbox.maxy-bbox.miny) / bbox_height; - double cellsize = MS_MIN(cellsize_x,cellsize_y); - - msRectIntersect( &bbox, &layer_rect ); - - bbox_width = ceil((bbox.maxx - bbox.minx) / cellsize); - bbox_height = ceil((bbox.maxy - bbox.miny) / cellsize); - - /* Force going through the resampler if we're going to receive a clipped BBOX (#4931) */ - if(msLayerGetProcessingKey(lp, "RESAMPLE") == NULL) { - msLayerSetProcessingKey(lp, "RESAMPLE", "nearest"); - } - } - } - msFree(ows_srs); - } - - /* -------------------------------------------------------------------- */ - /* Potentially return the bbox. */ - /* -------------------------------------------------------------------- */ - if (bbox_ret != NULL) - *bbox_ret = bbox; - - if( width_ret != NULL ) - *width_ret = bbox_width; - - if( height_ret != NULL ) - *height_ret = bbox_height; - - /* ------------------------------------------------------------------ - * Build the request URL. - * At this point we set only the following parameters for GetMap: - * REQUEST - * SRS (or CRS) - * BBOX - * - * And for GetFeatureInfo: - * X (I for 1.3.0) - * Y (J for 1.3.0) - * INFO_FORMAT - * FEATURE_COUNT (only if nFeatureCount > 0) - * - * The connection string should contain all other required params, - * including: - * VERSION - * LAYERS - * FORMAT - * TRANSPARENT - * STYLES - * QUERY_LAYERS (for queryable layers only) - * ------------------------------------------------------------------ */ - - /* ------------------------------------------------------------------ - * Sometimes a requested layer is essential for the map, so if the - * request fails or an error is delivered, the map has not to be drawn - * ------------------------------------------------------------------ */ - if ((pszTmp = msOWSLookupMetadata(&(lp->metadata), - "MO", "essential")) != NULL) { - if( strcasecmp(pszTmp,"true") == 0 - || strcasecmp(pszTmp,"on") == 0 - || strcasecmp(pszTmp,"yes") == 0 ) - bIsEssential = MS_TRUE; - else - bIsEssential = atoi(pszTmp); - } - - if (nRequestType == WMS_GETFEATUREINFO) { - char szBuf[100] = ""; - - if (nVersion >= OWS_1_0_7) - pszRequestParam = "GetFeatureInfo"; - else - pszRequestParam = "feature_info"; - - if (nVersion >= OWS_1_3_0) - pszExceptionsParam = "XML"; - else if (nVersion >= OWS_1_1_0) /* 1.1.0 to 1.1.0 */ - pszExceptionsParam = "application/vnd.ogc.se_xml"; - else if (nVersion > OWS_1_0_0) /* 1.0.1 to 1.0.7 */ - pszExceptionsParam = "SE_XML"; - else - pszExceptionsParam = "WMS_XML"; - - msSetWMSParamString(psWMSParams, "REQUEST", pszRequestParam, MS_FALSE, nVersion); - msSetWMSParamInt( psWMSParams, "WIDTH", bbox_width); - msSetWMSParamInt( psWMSParams, "HEIGHT", bbox_height); - - msSetWMSParamString(psWMSParams, pszSrsParamName, pszEPSG, MS_FALSE, nVersion); - - if (bFlipAxisOrder == MS_TRUE) { - snprintf(szBuf, sizeof(szBuf), "%.15g,%.15g,%.15g,%.15g", - bbox.miny, bbox.minx, bbox.maxy, bbox.maxx); - } else { - snprintf(szBuf, sizeof(szBuf), "%.15g,%.15g,%.15g,%.15g", - bbox.minx, bbox.miny, bbox.maxx, bbox.maxy); - } - msSetWMSParamString(psWMSParams, "BBOX", szBuf, MS_TRUE, nVersion); - - if (nVersion >= OWS_1_3_0) { - msSetWMSParamInt( psWMSParams, "I", nClickX); - msSetWMSParamInt( psWMSParams, "J", nClickY); - } else { - msSetWMSParamInt( psWMSParams, "X", nClickX); - msSetWMSParamInt( psWMSParams, "Y", nClickY); - } - - msSetWMSParamString(psWMSParams, "EXCEPTIONS", pszExceptionsParam, MS_FALSE, nVersion); - msSetWMSParamString(psWMSParams, "INFO_FORMAT", pszInfoFormat, MS_TRUE, nVersion); - - if (pszQueryLayers) { /* not set in CONNECTION string */ - msSetWMSParamString(psWMSParams, "QUERY_LAYERS", pszQueryLayers, MS_FALSE, nVersion); - } - - /* If FEATURE_COUNT <= 0 then don't pass this parameter */ - /* The spec states that FEATURE_COUNT must be greater than zero */ - /* and if not passed then the behavior is up to the server */ - if (nFeatureCount > 0) { - msSetWMSParamInt(psWMSParams, "FEATURE_COUNT", nFeatureCount); - } - - } else if (nRequestType == WMS_GETLEGENDGRAPHIC) { - if(map->extent.maxx > map->extent.minx && map->width > 0 && map->height > 0) { - char szBuf[20] = ""; - double scaledenom; - msCalculateScale(map->extent, map->units, map->width, map->height, - map->resolution, &scaledenom); - snprintf(szBuf, 20, "%g",scaledenom); - msSetWMSParamString(psWMSParams, "SCALE", szBuf, MS_FALSE, nVersion); - } - pszRequestParam = "GetLegendGraphic"; - - pszExceptionsParam = msOWSLookupMetadata(&(lp->metadata), - "MO", "exceptions_format"); - if (pszExceptionsParam == NULL) { - if (nVersion >= OWS_1_1_0 && nVersion < OWS_1_3_0) - pszExceptionsParam = "application/vnd.ogc.se_inimage"; - else - pszExceptionsParam = "INIMAGE"; - } - - if (pszLayer) { /* not set in CONNECTION string */ - msSetWMSParamString(psWMSParams, "LAYER", pszLayer, MS_FALSE, nVersion); - } - - msSetWMSParamString(psWMSParams, "REQUEST", pszRequestParam, MS_FALSE, nVersion); - msSetWMSParamString(psWMSParams, pszSrsParamName, pszEPSG, MS_FALSE, nVersion); - - if (nVersion >= OWS_1_3_0) { - msSetWMSParamString(psWMSParams, "SLD_VERSION", "1.1.0", MS_FALSE, nVersion); - } - - } else { /* if (nRequestType == WMS_GETMAP) */ - char szBuf[100] = ""; - - if (nVersion >= OWS_1_0_7) - pszRequestParam = "GetMap"; - else - pszRequestParam = "map"; - - pszExceptionsParam = msOWSLookupMetadata(&(lp->metadata), - "MO", "exceptions_format"); - - if (!bIsEssential) { - if (pszExceptionsParam == NULL) { - if (nVersion >= OWS_1_1_0 && nVersion < OWS_1_3_0) - pszExceptionsParam = "application/vnd.ogc.se_inimage"; - else - pszExceptionsParam = "INIMAGE"; - } - } else { - /* if layer is essential, do not emit EXCEPTIONS parameter (defaults to XML) */ - pszExceptionsParam = NULL; - } - - msSetWMSParamString(psWMSParams, "REQUEST", pszRequestParam, MS_FALSE, nVersion); - msSetWMSParamInt( psWMSParams, "WIDTH", bbox_width); - msSetWMSParamInt( psWMSParams, "HEIGHT", bbox_height); - msSetWMSParamString(psWMSParams, pszSrsParamName, pszEPSG, MS_FALSE, nVersion); - - if (bFlipAxisOrder == MS_TRUE) { - snprintf(szBuf, sizeof(szBuf), "%.15g,%.15g,%.15g,%.15g", - bbox.miny, bbox.minx, bbox.maxy, bbox.maxx); - } else { - snprintf(szBuf, sizeof(szBuf), "%.15g,%.15g,%.15g,%.15g", - bbox.minx, bbox.miny, bbox.maxx, bbox.maxy); - } - msSetWMSParamString(psWMSParams, "BBOX", szBuf, MS_TRUE, nVersion); - if( pszExceptionsParam ) { - msSetWMSParamString(psWMSParams, "EXCEPTIONS", pszExceptionsParam, MS_FALSE, nVersion); - } - } - - free(pszEPSG); - - return MS_SUCCESS; - -#else - /* ------------------------------------------------------------------ - * WMS CONNECTION Support not included... - * ------------------------------------------------------------------ */ - msSetError(MS_WMSCONNERR, "WMS CLIENT CONNECTION support is not available.", - "msBuildWMSLayerURL()"); - return MS_FAILURE; - -#endif /* USE_WMS_LYR */ - -} - - -/********************************************************************** - * msWMSGetFeatureInfoURL() - * - * Build a GetFeatureInfo URL for this layer. - * - * Returns a reference to a newly allocated string that should be freed - * by the caller. - **********************************************************************/ -char *msWMSGetFeatureInfoURL(mapObj *map, layerObj *lp, - int nClickX, int nClickY, int nFeatureCount, - const char *pszInfoFormat) -{ - wmsParamsObj sThisWMSParams; - char *pszURL; - - msInitWmsParamsObj(&sThisWMSParams); - - if (msBuildWMSLayerURL(map, lp, WMS_GETFEATUREINFO, - nClickX, nClickY, nFeatureCount, - pszInfoFormat, NULL, NULL, NULL, - &sThisWMSParams)!= MS_SUCCESS) { - return NULL; - } - - pszURL = msBuildURLFromWMSParams(&sThisWMSParams); - msFreeWmsParamsObj(&sThisWMSParams); - - return pszURL; -} - -/********************************************************************** - * msPrepareWMSLayerRequest() - * - **********************************************************************/ - -int msPrepareWMSLayerRequest(int nLayerId, mapObj *map, layerObj *lp, - int nRequestType, enum MS_CONNECTION_TYPE lastconnectiontype, - wmsParamsObj *psLastWMSParams, - int nClickX, int nClickY, int nFeatureCount, const char *pszInfoFormat, - httpRequestObj *pasReqInfo, int *numRequests) -{ -#ifdef USE_WMS_LYR - char *pszURL = NULL, *pszHTTPCookieData = NULL; - const char *pszTmp; - rectObj bbox = { 0 }; - int bbox_width = 0, bbox_height = 0; - int nTimeout, bOkToMerge, bForceSeparateRequest, bCacheToDisk; - wmsParamsObj sThisWMSParams; - - if (lp->connectiontype != MS_WMS) - return MS_FAILURE; - - msInitWmsParamsObj(&sThisWMSParams); - - /* ------------------------------------------------------------------ - * Build the request URL, this will also set layer projection and - * compute BBOX in that projection. - * ------------------------------------------------------------------ */ - - - if (nRequestType == WMS_GETMAP && - ( msBuildWMSLayerURL(map, lp, WMS_GETMAP, - 0, 0, 0, NULL, &bbox, &bbox_width, &bbox_height, - &sThisWMSParams) != MS_SUCCESS) ) { - /* an error was already reported. */ - msFreeWmsParamsObj(&sThisWMSParams); - return MS_FAILURE; - } - - else if (nRequestType == WMS_GETFEATUREINFO && - msBuildWMSLayerURL(map, lp, WMS_GETFEATUREINFO, - nClickX, nClickY, nFeatureCount, pszInfoFormat, - NULL, NULL, NULL, - &sThisWMSParams) != MS_SUCCESS ) { - /* an error was already reported. */ - msFreeWmsParamsObj(&sThisWMSParams); - return MS_FAILURE; - } else if (nRequestType == WMS_GETLEGENDGRAPHIC && - msBuildWMSLayerURL(map, lp, WMS_GETLEGENDGRAPHIC, - 0, 0, 0, NULL, - NULL, NULL, NULL, - &sThisWMSParams) != MS_SUCCESS ) { - /* an error was already reported. */ - msFreeWmsParamsObj(&sThisWMSParams); - return MS_FAILURE; - } - - - /* ------------------------------------------------------------------ - * Check if the request is empty, perhaps due to reprojection problems - * or wms_extents restrictions. - * ------------------------------------------------------------------ */ - if ((nRequestType == WMS_GETMAP) && (bbox_width == 0 || bbox_height == 0) ) { - msFreeWmsParamsObj(&sThisWMSParams); - return MS_SUCCESS; /* No overlap. */ - } - - /* ------------------------------------------------------------------ - * Check if layer overlaps current view window (using wms_latlonboundingbox) - * ------------------------------------------------------------------ */ - if ((pszTmp = msOWSLookupMetadata(&(lp->metadata), - "MO", "latlonboundingbox")) != NULL) { - char **tokens; - int n; - rectObj ext; - - tokens = msStringSplit(pszTmp, ' ', &n); - if (tokens==NULL || n != 4) { - msSetError(MS_WMSCONNERR, "Wrong number of arguments for 'wms_latlonboundingbox' metadata.", - "msDrawWMSLayer()"); - msFreeWmsParamsObj(&sThisWMSParams); - return MS_FAILURE; - } - - ext.minx = atof(tokens[0]); - ext.miny = atof(tokens[1]); - ext.maxx = atof(tokens[2]); - ext.maxy = atof(tokens[3]); - - msFreeCharArray(tokens, n); - - /* Reproject latlonboundingbox to the selected SRS for the layer and */ - /* check if it overlaps the bbox that we calculated for the request */ - - msProjectRect(&(map->latlon), &(lp->projection), &ext); - if (!msRectOverlap(&bbox, &ext)) { - /* No overlap... nothing to do */ - - msFreeWmsParamsObj(&sThisWMSParams); - return MS_SUCCESS; /* No overlap. */ - } - } - - /* ------------------------------------------------------------------ - * check to see if a the metadata wms_connectiontimeout is set. If it is - * the case we will use it, else we use the default which is 30 seconds. - * First check the metadata in the layer object and then in the map object. - * ------------------------------------------------------------------ */ - nTimeout = 30; /* Default is 30 seconds */ - if ((pszTmp = msOWSLookupMetadata2(&(lp->metadata), &(map->web.metadata), - "MO", "connectiontimeout")) != NULL) { - nTimeout = atoi(pszTmp); - } - - /* ------------------------------------------------------------------ - * Check if we want to use in memory images instead of writing to disk. - * ------------------------------------------------------------------ */ - if ((pszTmp = msOWSLookupMetadata(&(lp->metadata), - "MO", "cache_to_disk")) != NULL) { - if( strcasecmp(pszTmp,"true") == 0 - || strcasecmp(pszTmp,"on") == 0 - || strcasecmp(pszTmp,"yes") == 0 ) - bCacheToDisk = MS_TRUE; - else - bCacheToDisk = atoi(pszTmp); - } else - bCacheToDisk = MS_FALSE; - - if( bCacheToDisk ) { - /* We'll store the remote server's response to a tmp file. */ - if (map->web.imagepath == NULL || strlen(map->web.imagepath) == 0) { - msSetError(MS_WMSERR, - "WEB.IMAGEPATH must be set to use WMS client connections.", - "msPrepareWMSLayerRequest()"); - return MS_FAILURE; - } - } - - /* ------------------------------------------------------------------ - * Check if layer can be merged with previous WMS layer requests - * Metadata wms_force_separate_request can be set to 1 to prevent this - * this layer from being combined with any other layer. - * ------------------------------------------------------------------ */ - bForceSeparateRequest = MS_FALSE; - if ((pszTmp = msOWSLookupMetadata(&(lp->metadata), - "MO", "force_separate_request")) != NULL) { - bForceSeparateRequest = atoi(pszTmp); - } - bOkToMerge = MS_FALSE; - if (!bForceSeparateRequest && - lastconnectiontype == MS_WMS && - psLastWMSParams != NULL && - sThisWMSParams.numparams == psLastWMSParams->numparams && - strcmp(sThisWMSParams.onlineresource, - psLastWMSParams->onlineresource) == 0) { - const char *key, *value1, *value2; - bOkToMerge = MS_TRUE; - - key = msFirstKeyFromHashTable(sThisWMSParams.params); - while (key != NULL && bOkToMerge == MS_TRUE) { - /* Skip parameters whose values can be different */ - if (!(strcmp(key, "LAYERS") == 0 || - strcmp(key, "QUERY_LAYERS") == 0 || - strcmp(key, "STYLES") == 0) ) { - value1 = msLookupHashTable(psLastWMSParams->params, key); - value2 = msLookupHashTable(sThisWMSParams.params, key); - - if (value1==NULL || value2==NULL || - strcmp(value1, value2) != 0) { - bOkToMerge = MS_FALSE; - break; - } - } - key = msNextKeyFromHashTable(sThisWMSParams.params, key); - } - } - - /*------------------------------------------------------------------ - * Check to see if there's a HTTP Cookie to forward - * If Cookie differ between the two connection, it's NOT OK to merge - * the connection - * ------------------------------------------------------------------ */ - if ((pszTmp = msOWSLookupMetadata(&(lp->metadata), - "MO", "http_cookie")) != NULL) { - if(strcasecmp(pszTmp, "forward") == 0) { - pszTmp= msLookupHashTable(&(map->web.metadata),"http_cookie_data"); - if(pszTmp != NULL) { - pszHTTPCookieData = msStrdup(pszTmp); - } - } else { - pszHTTPCookieData = msStrdup(pszTmp); - } - } else if ((pszTmp = msOWSLookupMetadata(&(map->web.metadata), - "MO", "http_cookie")) != NULL) { - if(strcasecmp(pszTmp, "forward") == 0) { - pszTmp= msLookupHashTable(&(map->web.metadata),"http_cookie_data"); - if(pszTmp != NULL) { - pszHTTPCookieData = msStrdup(pszTmp); - } - } else { - pszHTTPCookieData = msStrdup(pszTmp); - } - } - - if(bOkToMerge && pszHTTPCookieData != sThisWMSParams.httpcookiedata) { - if(pszHTTPCookieData == NULL || sThisWMSParams.httpcookiedata == NULL) { - bOkToMerge = MS_FALSE; - } - if(strcmp(pszHTTPCookieData, sThisWMSParams.httpcookiedata) != 0) { - bOkToMerge = MS_FALSE; - } - } - - if (bOkToMerge) { - /* Merge both requests into sThisWMSParams - */ - const char *value1, *value2; - char *keys[] = {"LAYERS", "QUERY_LAYERS", "STYLES"}; - int i; - - for(i=0; i<3; i++) { - value1 = msLookupHashTable(psLastWMSParams->params, keys[i]); - value2 = msLookupHashTable(sThisWMSParams.params, keys[i]); - if (value1 && value2) { - char *pszBuf; - int nLen; - - nLen = strlen(value1) + strlen(value2) +2; - pszBuf = malloc(nLen); - MS_CHECK_ALLOC(pszBuf, nLen, MS_FAILURE); - - snprintf(pszBuf, nLen, "%s,%s", value1, value2); - /* TODO should really send the server request version here */ - msSetWMSParamString(&sThisWMSParams, keys[i], pszBuf,MS_FALSE, OWS_VERSION_NOTSET); - - /* This key existed already, we don't want it counted twice */ - sThisWMSParams.numparams--; - - msFree(pszBuf); - } - } - } - - - /* ------------------------------------------------------------------ - * Build new request URL - * ------------------------------------------------------------------ */ - pszURL = msBuildURLFromWMSParams(&sThisWMSParams); - - if (bOkToMerge && (*numRequests)>0) { - /* ------------------------------------------------------------------ - * Update the last request in the array: (*numRequests)-1 - * ------------------------------------------------------------------ */ - msFree(pasReqInfo[(*numRequests)-1].pszGetUrl); - pasReqInfo[(*numRequests)-1].pszGetUrl = pszURL; - pszURL = NULL; - pasReqInfo[(*numRequests)-1].debug |= lp->debug; - if (nTimeout > pasReqInfo[(*numRequests)-1].nTimeout) - pasReqInfo[(*numRequests)-1].nTimeout = nTimeout; - } else { - /* ------------------------------------------------------------------ - * Add a request to the array (already preallocated) - * ------------------------------------------------------------------ */ - pasReqInfo[(*numRequests)].nLayerId = nLayerId; - pasReqInfo[(*numRequests)].pszGetUrl = pszURL; - - pszURL = NULL; - pasReqInfo[(*numRequests)].pszHTTPCookieData = pszHTTPCookieData; - pszHTTPCookieData = NULL; - if( bCacheToDisk ) { - pasReqInfo[(*numRequests)].pszOutputFile = - msTmpFile(map, map->mappath, NULL, "wms.tmp"); - } else - pasReqInfo[(*numRequests)].pszOutputFile = NULL; - pasReqInfo[(*numRequests)].nStatus = 0; - pasReqInfo[(*numRequests)].nTimeout = nTimeout; - pasReqInfo[(*numRequests)].bbox = bbox; - pasReqInfo[(*numRequests)].width = bbox_width; - pasReqInfo[(*numRequests)].height = bbox_height; - pasReqInfo[(*numRequests)].debug = lp->debug; - - if (msHTTPAuthProxySetup(&(map->web.metadata), &(lp->metadata), - pasReqInfo, *numRequests, map, "MO") != MS_SUCCESS) - return MS_FAILURE; - - (*numRequests)++; - } - - - /* ------------------------------------------------------------------ - * Replace contents of psLastWMSParams with sThisWMSParams - * unless bForceSeparateRequest is set in which case we make it empty - * ------------------------------------------------------------------ */ - if (psLastWMSParams) { - msFreeWmsParamsObj(psLastWMSParams); - if (!bForceSeparateRequest) - *psLastWMSParams = sThisWMSParams; - else - msInitWmsParamsObj(psLastWMSParams); - } else { - /* Can't copy it, so we just free it */ - msFreeWmsParamsObj(&sThisWMSParams); - } - - return MS_SUCCESS; - -#else - /* ------------------------------------------------------------------ - * WMS CONNECTION Support not included... - * ------------------------------------------------------------------ */ - msSetError(MS_WMSCONNERR, "WMS CLIENT CONNECTION support is not available.", - "msDrawWMSLayer()"); - return(MS_FAILURE); - -#endif /* USE_WMS_LYR */ - -} - -/********************************************************************** - * msDrawWMSLayerLow() - * - **********************************************************************/ - -int msDrawWMSLayerLow(int nLayerId, httpRequestObj *pasReqInfo, - int numRequests, mapObj *map, layerObj *lp, imageObj *img) -{ -#ifdef USE_WMS_LYR - int status = MS_SUCCESS; - int iReq = -1; - char szPath[MS_MAXPATHLEN]; - int currenttype; - int currentconnectiontype; - int numclasses; - char *mem_filename = NULL; - const char *pszTmp; - int bIsEssential = MS_FALSE; - - /* ------------------------------------------------------------------ - * Sometimes a requested layer is essential for the map, so if the - * request fails or an error is delivered, the map has not to be drawn - * ------------------------------------------------------------------ */ - if ((pszTmp = msOWSLookupMetadata(&(lp->metadata), - "MO", "essential")) != NULL) { - if( strcasecmp(pszTmp,"true") == 0 - || strcasecmp(pszTmp,"on") == 0 - || strcasecmp(pszTmp,"yes") == 0 ) - bIsEssential = MS_TRUE; - else - bIsEssential = atoi(pszTmp); - } - - /* ------------------------------------------------------------------ - * Find the request info for this layer in the array, based on nLayerId - * ------------------------------------------------------------------ */ - for(iReq=0; iReqname?lp->name:"(null)"), - pasReqInfo[iReq].nStatus, pasReqInfo[iReq].pszErrBuf ); - - if (!bIsEssential) - return MS_SUCCESS; - else - return MS_FAILURE; - } - - /* ------------------------------------------------------------------ - * Check the Content-Type of the response to see if we got an exception, - * if yes then try to parse it and pass the info to msSetError(). - * We log an error but we still return SUCCESS here so that the layer - * is only skipped instead of aborting the whole draw map. - * If the layer is essential the map is not to be drawn. - * ------------------------------------------------------------------ */ - if (pasReqInfo[iReq].pszContentType && - (strcmp(pasReqInfo[iReq].pszContentType, "text/xml") == 0 || - strcmp(pasReqInfo[iReq].pszContentType, "application/vnd.ogc.se_xml") == 0)) { - FILE *fp; - char szBuf[MS_BUFFER_LENGTH]; - - if( pasReqInfo[iReq].pszOutputFile ) { - fp = fopen(pasReqInfo[iReq].pszOutputFile, "r"); - if (fp) { - /* TODO: For now we'll only read the first chunk and return it - * via msSetError()... we should really try to parse the XML - * and extract the exception code/message though - */ - size_t nSize; - - nSize = fread(szBuf, sizeof(char), MS_BUFFER_LENGTH-1, fp); - if (nSize < MS_BUFFER_LENGTH) - szBuf[nSize] = '\0'; - else { - strlcpy(szBuf, "(!!!)", sizeof(szBuf)); /* This should never happen */ - } - - fclose(fp); - - /* We're done with the remote server's response... delete it. */ - if (!lp->debug) - unlink(pasReqInfo[iReq].pszOutputFile); - } else { - strlcpy(szBuf, "(Failed to open exception response)", sizeof(szBuf)); - } - } else { - strlcpy( szBuf, pasReqInfo[iReq].result_data, MS_BUFFER_LENGTH ); - } - - if (lp->debug) - msDebug("WMS GetMap request got XML exception for layer '%s': %s.", - (lp->name?lp->name:"(null)"), szBuf ); - - msSetError(MS_WMSERR, - "WMS GetMap request got XML exception for layer '%s': %s.", - "msDrawWMSLayerLow()", - (lp->name?lp->name:"(null)"), szBuf ); - - if (!bIsEssential) - return MS_SUCCESS; - else - return MS_FAILURE; - } - - /* ------------------------------------------------------------------ - * If the output was written to a memory buffer, then we will need - * to attach a "VSI" name to this buffer. - * ------------------------------------------------------------------ */ - if( pasReqInfo[iReq].pszOutputFile == NULL ) { - msCleanVSIDir( "/vsimem/msout" ); - mem_filename = msTmpFile(map, NULL, "/vsimem/msout/", "img.tmp" ); - - VSIFCloseL( - VSIFileFromMemBuffer( mem_filename, - (GByte*) pasReqInfo[iReq].result_data, - (vsi_l_offset) pasReqInfo[iReq].result_size, - FALSE ) ); - } - - /* ------------------------------------------------------------------ - * Prepare layer for drawing, reprojecting the image received from the - * server if needed... - * ------------------------------------------------------------------ */ - /* keep the current type that will be restored at the end of this */ - /* function. */ - currenttype = lp->type; - currentconnectiontype = lp->connectiontype; - lp->type = MS_LAYER_RASTER; - lp->connectiontype = MS_SHAPEFILE; - - /* set the classes to 0 so that It won't do client side */ - /* classification if an sld was set. */ - numclasses = lp->numclasses; - - /* ensure the file connection is closed right away after the layer */ - /* is rendered */ - msLayerSetProcessingKey( lp, "CLOSE_CONNECTION", "NORMAL"); - - if (msOWSLookupMetadata(&(lp->metadata), "MO", "sld_body") || - msOWSLookupMetadata(&(lp->metadata), "MO", "sld_url")) - lp->numclasses = 0; - - if (lp->data) free(lp->data); - if( mem_filename != NULL ) - lp->data = mem_filename; - else - lp->data = msStrdup(pasReqInfo[iReq].pszOutputFile); - - /* #3138 If PROCESSING "RESAMPLE=..." is set we cannot use the simple case */ - if (!msProjectionsDiffer(&(map->projection), &(lp->projection)) && - (msLayerGetProcessingKey(lp, "RESAMPLE") == NULL) ) { - /* The simple case... no reprojection needed... render layer directly. */ - lp->transform = MS_FALSE; - /* if (msDrawRasterLayerLow(map, lp, img) != 0) */ - /* status = MS_FAILURE; */ - if (msDrawLayer(map, lp, img) != 0) - status = MS_FAILURE; - } else { - FILE *fp; - char *wldfile; - /* OK, we have to resample the raster to map projection... */ - lp->transform = MS_TRUE; - msLayerSetProcessingKey( lp, "LOAD_WHOLE_IMAGE", "YES" ); - - /* Create a world file with raster extents */ - /* One line per value, in this order: cx, 0, 0, cy, ulx, uly */ - wldfile = msBuildPath(szPath, lp->map->mappath, lp->data); - if (wldfile && (strlen(wldfile)>=3)) - strcpy(wldfile+strlen(wldfile)-3, "wld"); - if (wldfile && (fp = VSIFOpenL(wldfile, "wt")) != NULL) { - double dfCellSizeX = MS_OWS_CELLSIZE(pasReqInfo[iReq].bbox.minx, - pasReqInfo[iReq].bbox.maxx, - pasReqInfo[iReq].width); - double dfCellSizeY = MS_OWS_CELLSIZE(pasReqInfo[iReq].bbox.maxy, - pasReqInfo[iReq].bbox.miny, - pasReqInfo[iReq].height); - char world_text[5000]; - - sprintf( world_text, "%.12f\n0\n0\n%.12f\n%.12f\n%.12f\n", - dfCellSizeX, - dfCellSizeY, - pasReqInfo[iReq].bbox.minx + dfCellSizeX * 0.5, - pasReqInfo[iReq].bbox.maxy + dfCellSizeY * 0.5 ); - - VSIFWriteL( world_text, 1, strlen(world_text), fp ); - VSIFCloseL( fp ); - - /* GDAL should be called to reproject automatically. */ - if (msDrawLayer(map, lp, img) != 0) - status = MS_FAILURE; - - if (!lp->debug) - VSIUnlink( wldfile ); - } else { - msSetError(MS_WMSCONNERR, - "Unable to create wld file for WMS slide.", - "msDrawWMSLayer()"); - status = MS_FAILURE; - } - - } - - /* We're done with the remote server's response... delete it. */ - if (!lp->debug) - VSIUnlink(lp->data); - - /* restore prveious type */ - lp->type = currenttype; - lp->connectiontype = currentconnectiontype; - - /* restore previous numclasses */ - lp->numclasses = numclasses; - - free(lp->data); - lp->data = NULL; - - return status; - -#else - /* ------------------------------------------------------------------ - * WMS CONNECTION Support not included... - * ------------------------------------------------------------------ */ - msSetError(MS_WMSCONNERR, "WMS CLIENT CONNECTION support is not available.", - "msDrawWMSLayer()"); - return(MS_FAILURE); - -#endif /* USE_WMS_LYR */ - -} - - -int msWMSLayerExecuteRequest(mapObj *map, int nOWSLayers, int nClickX, int nClickY, - int nFeatureCount, const char *pszInfoFormat, int type) -{ -#ifdef USE_WMS_LYR - - msIOContext *context; - - httpRequestObj *pasReqInfo; - wmsParamsObj sLastWMSParams; - int i, numReq = 0; - - pasReqInfo = (httpRequestObj *)msSmallMalloc((nOWSLayers+1)*sizeof(httpRequestObj)); - msHTTPInitRequestObj(pasReqInfo, nOWSLayers+1); - msInitWmsParamsObj(&sLastWMSParams); - - /* Generate the http request */ - for (i=0; inumlayers; i++) { - if (GET_LAYER(map,map->layerorder[i])->status == MS_ON) { - if (type == WMS_GETFEATUREINFO ) { - if( msPrepareWMSLayerRequest(map->layerorder[i], map, GET_LAYER(map,map->layerorder[i]), - WMS_GETFEATUREINFO, - MS_WMS, &sLastWMSParams, - nClickX, nClickY, nFeatureCount, pszInfoFormat, - pasReqInfo, &numReq) == MS_FAILURE) { - msFreeWmsParamsObj(&sLastWMSParams); - msFree(pasReqInfo); - return MS_FAILURE; - } - } else if (msPrepareWMSLayerRequest(map->layerorder[i], map, GET_LAYER(map,map->layerorder[i]), - WMS_GETLEGENDGRAPHIC, - MS_WMS, &sLastWMSParams, - 0, 0, 0, NULL, - pasReqInfo, &numReq) == MS_FAILURE) { - msFreeWmsParamsObj(&sLastWMSParams); - msFree(pasReqInfo); - return MS_FAILURE; - } - } - } - - if (msOWSExecuteRequests(pasReqInfo, numReq, map, MS_FALSE) == MS_FAILURE) { - msHTTPFreeRequestObj(pasReqInfo, numReq); - msFree(pasReqInfo); - msFreeWmsParamsObj(&sLastWMSParams); - return MS_FAILURE; - } - - context = msIO_getHandler( stdout ); - if( context == NULL ) { - msHTTPFreeRequestObj(pasReqInfo, numReq); - msFree(pasReqInfo); - msFreeWmsParamsObj(&sLastWMSParams); - return MS_FAILURE; - } - - msIO_printf("Content-Type: %s%c%c",pasReqInfo[0].pszContentType, 10,10); - - if( pasReqInfo[0].pszOutputFile ) { - FILE *fp; - char szBuf[MS_BUFFER_LENGTH]; - - fp = fopen(pasReqInfo[0].pszOutputFile, "r"); - if (fp) { - while(1) { - size_t nSize; - nSize = fread(szBuf, sizeof(char), MS_BUFFER_LENGTH-1, fp); - if (nSize > 0) - msIO_contextWrite( context, - szBuf, - nSize); - if (nSize != MS_BUFFER_LENGTH-1) - break; - } - fclose(fp); - if (!map->debug) - unlink(pasReqInfo[0].pszOutputFile); - } else { - msSetError(MS_IOERR, "'%s'.", - "msWMSLayerExecuteRequest()", pasReqInfo[0].pszOutputFile); - return MS_FAILURE; - } - } else { - msIO_contextWrite( context, - pasReqInfo[0].result_data, - pasReqInfo[0].result_size ); - } - - msHTTPFreeRequestObj(pasReqInfo, numReq); - msFree(pasReqInfo); - msFreeWmsParamsObj(&sLastWMSParams); - - return MS_SUCCESS; -#else - /* ------------------------------------------------------------------ - * WMS CONNECTION Support not included... - * ------------------------------------------------------------------ */ - msSetError(MS_WMSCONNERR, "WMS CLIENT CONNECTION support is not available.", - "msWMSLayerExecuteRequest()"); - return(MS_FAILURE); - -#endif /* USE_WMS_LYR */ - -} diff --git a/mapxbase.c b/mapxbase.c deleted file mode 100644 index c283259693..0000000000 --- a/mapxbase.c +++ /dev/null @@ -1,898 +0,0 @@ -/****************************************************************************** - * $Id$ - * - * Project: MapServer - * Purpose: .dbf access API. Derived from shapelib, and relicensed with - * permission of Frank Warmerdam (shapelib author). - * Author: Steve Lime and the MapServer team. - * - ****************************************************************************** - * Copyright (c) 1996-2005 Regents of the University of Minnesota. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies of this Software or works derived from this Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - ****************************************************************************/ - -#include "mapserver.h" -#include /* for atof() and atoi() */ -#include - -#include "cpl_vsi.h" - -static inline void IGUR_sizet(size_t ignored) { (void)ignored; } /* Ignore GCC Unused Result */ - -/************************************************************************/ -/* SfRealloc() */ -/* */ -/* A realloc cover function that will access a NULL pointer as */ -/* a valid input. */ -/************************************************************************/ -static void * SfRealloc( void * pMem, int nNewSize ) - -{ - return( (void *) realloc(pMem,nNewSize) ); -} - -/************************************************************************/ -/* writeHeader() */ -/* */ -/* This is called to write out the file header, and field */ -/* descriptions before writing any actual data records. This */ -/* also computes all the DBFDataSet field offset/size/decimals */ -/* and so forth values. */ -/************************************************************************/ -static void writeHeader(DBFHandle psDBF) - -{ - uchar abyHeader[32]; - int i; - - if( !psDBF->bNoHeader ) - return; - - psDBF->bNoHeader = MS_FALSE; - - /* -------------------------------------------------------------------- */ - /* Initialize the file header information. */ - /* -------------------------------------------------------------------- */ - for( i = 0; i < 32; i++ ) - abyHeader[i] = 0; - - abyHeader[0] = 0x03; /* memo field? - just copying */ - - /* date updated on close, record count preset at zero */ - - abyHeader[8] = psDBF->nHeaderLength % 256; - abyHeader[9] = psDBF->nHeaderLength / 256; - - abyHeader[10] = psDBF->nRecordLength % 256; - abyHeader[11] = psDBF->nRecordLength / 256; - - /* -------------------------------------------------------------------- */ - /* Write the initial 32 byte file header, and all the field */ - /* descriptions. */ - /* -------------------------------------------------------------------- */ - VSIFSeekL( psDBF->fp, 0, 0 ); - VSIFWriteL( abyHeader, 32, 1, psDBF->fp ); - VSIFWriteL( psDBF->pszHeader, 32, psDBF->nFields, psDBF->fp ); - - /* -------------------------------------------------------------------- */ - /* Write out the newline character if there is room for it. */ - /* -------------------------------------------------------------------- */ - if( psDBF->nHeaderLength > 32*psDBF->nFields + 32 ) { - char cNewline; - - cNewline = 0x0d; - VSIFWriteL( &cNewline, 1, 1, psDBF->fp ); - } -} - -/************************************************************************/ -/* flushRecord() */ -/* */ -/* Write out the current record if there is one. */ -/************************************************************************/ -static void flushRecord( DBFHandle psDBF ) - -{ - unsigned int nRecordOffset; - - if( psDBF->bCurrentRecordModified && psDBF->nCurrentRecord > -1 ) { - psDBF->bCurrentRecordModified = MS_FALSE; - - nRecordOffset = psDBF->nRecordLength * psDBF->nCurrentRecord - + psDBF->nHeaderLength; - - VSIFSeekL( psDBF->fp, nRecordOffset, 0 ); - VSIFWriteL( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp ); - } -} - -/************************************************************************/ -/* msDBFOpen() */ -/* */ -/* Open a .dbf file. */ -/************************************************************************/ -DBFHandle msDBFOpen( const char * pszFilename, const char * pszAccess ) - -{ - DBFHandle psDBF; - uchar *pabyBuf; - int nFields, nRecords, nHeadLen, nRecLen, iField; - char *pszDBFFilename; - - /* -------------------------------------------------------------------- */ - /* We only allow the access strings "rb" and "r+". */ - /* -------------------------------------------------------------------- */ - if( strcmp(pszAccess,"r") != 0 && strcmp(pszAccess,"r+") != 0 - && strcmp(pszAccess,"rb") != 0 && strcmp(pszAccess,"r+b") != 0 ) - return( NULL ); - - /* -------------------------------------------------------------------- */ - /* Ensure the extension is converted to dbf or DBF if it is */ - /* currently .shp or .shx. */ - /* -------------------------------------------------------------------- */ - pszDBFFilename = (char *) msSmallMalloc(strlen(pszFilename)+1); - strcpy( pszDBFFilename, pszFilename ); - - if( strcmp(pszFilename+strlen(pszFilename)-4,".shp") == 0 - || strcmp(pszFilename+strlen(pszFilename)-4,".shx") == 0 ) { - strcpy( pszDBFFilename+strlen(pszDBFFilename)-4, ".dbf"); - } else if( strcmp(pszFilename+strlen(pszFilename)-4,".SHP") == 0 - || strcmp(pszFilename+strlen(pszFilename)-4,".SHX") == 0 ) { - strcpy( pszDBFFilename+strlen(pszDBFFilename)-4, ".DBF"); - } - - /* -------------------------------------------------------------------- */ - /* Open the file. */ - /* -------------------------------------------------------------------- */ - psDBF = (DBFHandle) calloc( 1, sizeof(DBFInfo) ); - MS_CHECK_ALLOC(psDBF, sizeof(DBFInfo), NULL); - psDBF->fp = VSIFOpenL( pszDBFFilename, pszAccess ); - if( psDBF->fp == NULL ) - { - if( strcmp(pszDBFFilename+strlen(pszDBFFilename)-4,".dbf") == 0 ) { - strcpy( pszDBFFilename+strlen(pszDBFFilename)-4, ".DBF"); - psDBF->fp = VSIFOpenL( pszDBFFilename, pszAccess ); - } - } - if( psDBF->fp == NULL ) { - msFree(pszDBFFilename); - msFree(psDBF); - return( NULL ); - } - - psDBF->bNoHeader = MS_FALSE; - psDBF->nCurrentRecord = -1; - psDBF->bCurrentRecordModified = MS_FALSE; - - psDBF->pszStringField = NULL; - psDBF->nStringFieldLen = 0; - - free( pszDBFFilename ); - - /* -------------------------------------------------------------------- */ - /* Read Table Header info */ - /* -------------------------------------------------------------------- */ - pabyBuf = (uchar *) msSmallMalloc(500); - if( VSIFReadL( pabyBuf, 32, 1, psDBF->fp ) != 1 ) - { - msFree(psDBF); - msFree(pabyBuf); - return( NULL ); - } - - psDBF->nRecords = nRecords = - pabyBuf[4] + pabyBuf[5]*256 + pabyBuf[6]*256*256 + pabyBuf[7]*256*256*256; - - psDBF->nHeaderLength = nHeadLen = pabyBuf[8] + pabyBuf[9]*256; - psDBF->nRecordLength = nRecLen = pabyBuf[10] + pabyBuf[11]*256; - - psDBF->nFields = nFields = (nHeadLen - 32) / 32; - - psDBF->pszCurrentRecord = (char *) msSmallMalloc(nRecLen); - - /* -------------------------------------------------------------------- */ - /* Read in Field Definitions */ - /* -------------------------------------------------------------------- */ - pabyBuf = (uchar *) SfRealloc(pabyBuf,nHeadLen); - psDBF->pszHeader = (char *) pabyBuf; - - VSIFSeekL( psDBF->fp, 32, 0 ); - if( VSIFReadL( pabyBuf, nHeadLen - 32, 1, psDBF->fp ) != 1 ) - { - msFree(psDBF->pszCurrentRecord); - msFree(psDBF); - msFree(pabyBuf); - return( NULL ); - } - - psDBF->panFieldOffset = (int *) msSmallMalloc(sizeof(int) * nFields); - psDBF->panFieldSize = (int *) msSmallMalloc(sizeof(int) * nFields); - psDBF->panFieldDecimals = (int *) msSmallMalloc(sizeof(int) * nFields); - psDBF->pachFieldType = (char *) msSmallMalloc(sizeof(char) * nFields); - - for( iField = 0; iField < nFields; iField++ ) { - uchar *pabyFInfo; - - pabyFInfo = pabyBuf+iField*32; - - if( pabyFInfo[11] == 'N' || pabyFInfo[11] == 'F' ) { - psDBF->panFieldSize[iField] = pabyFInfo[16]; - psDBF->panFieldDecimals[iField] = pabyFInfo[17]; - } else { - psDBF->panFieldSize[iField] = pabyFInfo[16] + pabyFInfo[17]*256; - psDBF->panFieldDecimals[iField] = 0; - } - - psDBF->pachFieldType[iField] = (char) pabyFInfo[11]; - if( iField == 0 ) - psDBF->panFieldOffset[iField] = 1; - else - psDBF->panFieldOffset[iField] = - psDBF->panFieldOffset[iField-1] + psDBF->panFieldSize[iField-1]; - } - - return( psDBF ); -} - -/************************************************************************/ -/* msDBFClose() */ -/************************************************************************/ - -void msDBFClose(DBFHandle psDBF) -{ - /* -------------------------------------------------------------------- */ - /* Write out header if not already written. */ - /* -------------------------------------------------------------------- */ - if( psDBF->bNoHeader ) - writeHeader( psDBF ); - - flushRecord( psDBF ); - - /* -------------------------------------------------------------------- */ - /* Update last access date, and number of records if we have */ - /* write access. */ - /* -------------------------------------------------------------------- */ - if( psDBF->bUpdated ) { - uchar abyFileHeader[32]; - - VSIFSeekL( psDBF->fp, 0, 0 ); - IGUR_sizet(VSIFReadL( abyFileHeader, 32, 1, psDBF->fp )); - - abyFileHeader[1] = 95; /* YY */ - abyFileHeader[2] = 7; /* MM */ - abyFileHeader[3] = 26; /* DD */ - - abyFileHeader[4] = psDBF->nRecords % 256; - abyFileHeader[5] = (psDBF->nRecords/256) % 256; - abyFileHeader[6] = (psDBF->nRecords/(256*256)) % 256; - abyFileHeader[7] = (psDBF->nRecords/(256*256*256)) % 256; - - VSIFSeekL( psDBF->fp, 0, 0 ); - VSIFWriteL( abyFileHeader, 32, 1, psDBF->fp ); - } - - /* -------------------------------------------------------------------- */ - /* Close, and free resources. */ - /* -------------------------------------------------------------------- */ - VSIFCloseL( psDBF->fp ); - - if( psDBF->panFieldOffset != NULL ) { - free( psDBF->panFieldOffset ); - free( psDBF->panFieldSize ); - free( psDBF->panFieldDecimals ); - free( psDBF->pachFieldType ); - } - - free( psDBF->pszHeader ); - free( psDBF->pszCurrentRecord ); - - free(psDBF->pszStringField); - - free( psDBF ); -} - -/************************************************************************/ -/* msDBFCreate() */ -/* */ -/* Create a new .dbf file. */ -/************************************************************************/ -DBFHandle msDBFCreate( const char * pszFilename ) - -{ - DBFHandle psDBF; - VSILFILE *fp; - - /* -------------------------------------------------------------------- */ - /* Create the file. */ - /* -------------------------------------------------------------------- */ - fp = VSIFOpenL( pszFilename, "wb" ); - if( fp == NULL ) - return( NULL ); - - { - char ch = 0; - VSIFWriteL(&ch, 1, 1, fp); - } - VSIFCloseL( fp ); - - fp = VSIFOpenL( pszFilename, "rb+" ); - if( fp == NULL ) - return( NULL ); - - /* -------------------------------------------------------------------- */ - /* Create the info structure. */ - /* -------------------------------------------------------------------- */ - psDBF = (DBFHandle) malloc(sizeof(DBFInfo)); - if (psDBF == NULL) { - msSetError(MS_MEMERR, "%s: %d: Out of memory allocating %u bytes.\n", "msDBFCreate()", - __FILE__, __LINE__, (unsigned int)sizeof(DBFInfo)); - VSIFCloseL(fp); - return NULL; - } - - psDBF->fp = fp; - psDBF->nRecords = 0; - psDBF->nFields = 0; - psDBF->nRecordLength = 1; - psDBF->nHeaderLength = 33; - - psDBF->panFieldOffset = NULL; - psDBF->panFieldSize = NULL; - psDBF->panFieldDecimals = NULL; - psDBF->pachFieldType = NULL; - psDBF->pszHeader = NULL; - - psDBF->nCurrentRecord = -1; - psDBF->bCurrentRecordModified = MS_FALSE; - psDBF->pszCurrentRecord = NULL; - - psDBF->pszStringField = NULL; - psDBF->nStringFieldLen = 0; - - psDBF->bNoHeader = MS_TRUE; - psDBF->bUpdated = MS_FALSE; - - return( psDBF ); -} - -/************************************************************************/ -/* msDBFAddField() */ -/* */ -/* Add a field to a newly created .dbf file before any records */ -/* are written. */ -/************************************************************************/ -int msDBFAddField(DBFHandle psDBF, const char * pszFieldName, DBFFieldType eType, int nWidth, int nDecimals ) -{ - char *pszFInfo; - int i; - - /* -------------------------------------------------------------------- */ - /* Do some checking to ensure we can add records to this file. */ - /* -------------------------------------------------------------------- */ - if( psDBF->nRecords > 0 ) - return( MS_FALSE ); - - if( !psDBF->bNoHeader ) - return( MS_FALSE ); - - if( eType != FTDouble && nDecimals != 0 ) - return( MS_FALSE ); - - /* -------------------------------------------------------------------- */ - /* SfRealloc all the arrays larger to hold the additional field */ - /* information. */ - /* -------------------------------------------------------------------- */ - psDBF->nFields++; - - psDBF->panFieldOffset = (int *) - SfRealloc( psDBF->panFieldOffset, sizeof(int) * psDBF->nFields ); - - psDBF->panFieldSize = (int *) - SfRealloc( psDBF->panFieldSize, sizeof(int) * psDBF->nFields ); - - psDBF->panFieldDecimals = (int *) - SfRealloc( psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields ); - - psDBF->pachFieldType = (char *) - SfRealloc( psDBF->pachFieldType, sizeof(char) * psDBF->nFields ); - - /* -------------------------------------------------------------------- */ - /* Assign the new field information fields. */ - /* -------------------------------------------------------------------- */ - psDBF->panFieldOffset[psDBF->nFields-1] = psDBF->nRecordLength; - psDBF->nRecordLength += nWidth; - psDBF->panFieldSize[psDBF->nFields-1] = nWidth; - psDBF->panFieldDecimals[psDBF->nFields-1] = nDecimals; - - if( eType == FTString ) - psDBF->pachFieldType[psDBF->nFields-1] = 'C'; - else - psDBF->pachFieldType[psDBF->nFields-1] = 'N'; - - /* -------------------------------------------------------------------- */ - /* Extend the required header information. */ - /* -------------------------------------------------------------------- */ - psDBF->nHeaderLength += 32; - psDBF->bUpdated = MS_FALSE; - - psDBF->pszHeader = (char *) SfRealloc(psDBF->pszHeader,psDBF->nFields*32); - - pszFInfo = psDBF->pszHeader + 32 * (psDBF->nFields-1); - - for( i = 0; i < 32; i++ ) - pszFInfo[i] = '\0'; - - strncpy( pszFInfo, pszFieldName, 10); - - pszFInfo[11] = psDBF->pachFieldType[psDBF->nFields-1]; - - if( eType == FTString ) { - pszFInfo[16] = nWidth % 256; - pszFInfo[17] = nWidth / 256; - } else { - pszFInfo[16] = nWidth; - pszFInfo[17] = nDecimals; - } - - /* -------------------------------------------------------------------- */ - /* Make the current record buffer appropriately larger. */ - /* -------------------------------------------------------------------- */ - psDBF->pszCurrentRecord = (char *) SfRealloc(psDBF->pszCurrentRecord, - psDBF->nRecordLength); - - return( psDBF->nFields-1 ); -} - -/************************************************************************/ -/* DBFIsValueNULL() */ -/* */ -/* Return TRUE if value is NULL (in DBF terms). */ -/* */ -/* Based on DBFIsAttributeNULL of shapelib */ -/************************************************************************/ - -static int DBFIsValueNULL( const char* pszValue, char type ) - -{ - switch(type) { - case 'N': - case 'F': - /* NULL numeric fields have value "****************" */ - return pszValue[0] == '*'; - - case 'D': - /* NULL date fields have value "00000000" */ - return strncmp(pszValue,"00000000",8) == 0; - - case 'L': - /* NULL boolean fields have value "?" */ - return pszValue[0] == '?'; - - default: - /* empty string fields are considered NULL */ - return strlen(pszValue) == 0; - } -} - -/************************************************************************/ -/* msDBFReadAttribute() */ -/* */ -/* Read one of the attribute fields of a record. */ -/************************************************************************/ -static const char *msDBFReadAttribute(DBFHandle psDBF, int hEntity, int iField ) - -{ - int i; - unsigned int nRecordOffset; - const uchar *pabyRec; - const char *pReturnField = NULL; - - /* -------------------------------------------------------------------- */ - /* Is the request valid? */ - /* -------------------------------------------------------------------- */ - if( iField < 0 || iField >= psDBF->nFields ) { - msSetError(MS_DBFERR, "Invalid field index %d.", "msDBFReadAttribute()",iField ); - return( NULL ); - } - - if( hEntity < 0 || hEntity >= psDBF->nRecords ) { - msSetError(MS_DBFERR, "Invalid record number %d.", "msDBFReadAttribute()",hEntity ); - return( NULL ); - } - - /* -------------------------------------------------------------------- */ - /* Have we read the record? */ - /* -------------------------------------------------------------------- */ - if( psDBF->nCurrentRecord != hEntity ) { - flushRecord( psDBF ); - - nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength; - - VSIFSeekL( psDBF->fp, nRecordOffset, 0 ); - if( VSIFReadL( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp ) != 1 ) - { - msSetError(MS_DBFERR, "Cannot read record %d.", "msDBFReadAttribute()",hEntity ); - return( NULL ); - } - - psDBF->nCurrentRecord = hEntity; - } - - pabyRec = (const uchar *) psDBF->pszCurrentRecord; - /* DEBUG */ - /* printf("CurrentRecord(%c):%s\n", psDBF->pachFieldType[iField], pabyRec); */ - - /* -------------------------------------------------------------------- */ - /* Ensure our field buffer is large enough to hold this buffer. */ - /* -------------------------------------------------------------------- */ - if( psDBF->panFieldSize[iField]+1 > psDBF->nStringFieldLen ) { - psDBF->nStringFieldLen = psDBF->panFieldSize[iField]*2 + 10; - psDBF->pszStringField = (char *) SfRealloc(psDBF->pszStringField,psDBF->nStringFieldLen); - } - - /* -------------------------------------------------------------------- */ - /* Extract the requested field. */ - /* -------------------------------------------------------------------- */ - strncpy( psDBF->pszStringField,(const char *) pabyRec+psDBF->panFieldOffset[iField], psDBF->panFieldSize[iField] ); - psDBF->pszStringField[psDBF->panFieldSize[iField]] = '\0'; - - /* - ** Trim trailing blanks (SDL Modification) - */ - for(i=strlen(psDBF->pszStringField)-1; i>=0; i--) { - if(psDBF->pszStringField[i] != ' ') { - psDBF->pszStringField[i+1] = '\0'; - break; - } - } - - if(i == -1) psDBF->pszStringField[0] = '\0'; /* whole string is blank (SDL fix) */ - - /* - ** Trim/skip leading blanks (SDL/DM Modification - only on numeric types) - */ - if( psDBF->pachFieldType[iField] == 'N' || psDBF->pachFieldType[iField] == 'F' || psDBF->pachFieldType[iField] == 'D' ) { - for(i=0; psDBF->pszStringField[i] != '\0' ; i++) { - if(psDBF->pszStringField[i] != ' ') - break; - } - pReturnField = psDBF->pszStringField+i; - } else - pReturnField = psDBF->pszStringField; - - /* detect null values */ - if ( DBFIsValueNULL( pReturnField, psDBF->pachFieldType[iField] ) ) { - if (psDBF->pachFieldType[iField] == 'N' || psDBF->pachFieldType[iField] == 'F' || psDBF->pachFieldType[iField] == 'D') - pReturnField="0"; - } - return( pReturnField ); -} - -/************************************************************************/ -/* msDBFReadIntAttribute() */ -/* */ -/* Read an integer attribute. */ -/************************************************************************/ -int msDBFReadIntegerAttribute( DBFHandle psDBF, int iRecord, int iField ) - -{ - return(atoi(msDBFReadAttribute( psDBF, iRecord, iField ))); -} - -/************************************************************************/ -/* msDBFReadDoubleAttribute() */ -/* */ -/* Read a double attribute. */ -/************************************************************************/ -double msDBFReadDoubleAttribute( DBFHandle psDBF, int iRecord, int iField ) -{ - return(atof(msDBFReadAttribute( psDBF, iRecord, iField ))); -} - -/************************************************************************/ -/* msDBFReadStringAttribute() */ -/* */ -/* Read a string attribute. */ -/************************************************************************/ -const char *msDBFReadStringAttribute( DBFHandle psDBF, int iRecord, int iField ) -{ - return( msDBFReadAttribute( psDBF, iRecord, iField ) ); -} - -/************************************************************************/ -/* msDBFGetFieldCount() */ -/* */ -/* Return the number of fields in this table. */ -/************************************************************************/ -int msDBFGetFieldCount( DBFHandle psDBF ) -{ - return( psDBF->nFields ); -} - -/************************************************************************/ -/* msDBFGetRecordCount() */ -/* */ -/* Return the number of records in this table. */ -/************************************************************************/ -int msDBFGetRecordCount( DBFHandle psDBF ) -{ - return( psDBF->nRecords ); -} - -/************************************************************************/ -/* msDBFGetFieldInfo() */ -/* */ -/* Return any requested information about the field. */ -/************************************************************************/ -DBFFieldType msDBFGetFieldInfo( DBFHandle psDBF, int iField, char * pszFieldName, int * pnWidth, int * pnDecimals ) -{ - if( iField < 0 || iField >= psDBF->nFields ) - return( FTInvalid ); - - if( pnWidth != NULL ) - *pnWidth = psDBF->panFieldSize[iField]; - - if( pnDecimals != NULL ) - *pnDecimals = psDBF->panFieldDecimals[iField]; - - if( pszFieldName != NULL ) { - int i; - - strncpy( pszFieldName, (char *) psDBF->pszHeader+iField*32, 11 ); - pszFieldName[11] = '\0'; - for( i = 10; i > 0 && pszFieldName[i] == ' '; i-- ) - pszFieldName[i] = '\0'; - } - - if( psDBF->pachFieldType[iField] == 'N' - || psDBF->pachFieldType[iField] == 'F' - || psDBF->pachFieldType[iField] == 'D' ) { - if( psDBF->panFieldDecimals[iField] > 0 ) - return( FTDouble ); - else - return( FTInteger ); - } else { - return( FTString ); - } -} - -/************************************************************************/ -/* msDBFWriteAttribute() */ -/* */ -/* Write an attribute record to the file. */ -/************************************************************************/ -static int msDBFWriteAttribute(DBFHandle psDBF, int hEntity, int iField, void * pValue ) -{ - unsigned int nRecordOffset; - int i, len; - uchar *pabyRec; - char szSField[40]; - - /* -------------------------------------------------------------------- */ - /* Is this a valid record? */ - /* -------------------------------------------------------------------- */ - if( hEntity < 0 || hEntity > psDBF->nRecords ) - return( MS_FALSE ); - - if( psDBF->bNoHeader ) - writeHeader(psDBF); - - /* -------------------------------------------------------------------- */ - /* Is this a brand new record? */ - /* -------------------------------------------------------------------- */ - if( hEntity == psDBF->nRecords ) { - flushRecord( psDBF ); - - psDBF->nRecords++; - for( i = 0; i < psDBF->nRecordLength; i++ ) - psDBF->pszCurrentRecord[i] = ' '; - - psDBF->nCurrentRecord = hEntity; - } - - /* -------------------------------------------------------------------- */ - /* Is this an existing record, but different than the last one */ - /* we accessed? */ - /* -------------------------------------------------------------------- */ - if( psDBF->nCurrentRecord != hEntity ) { - flushRecord( psDBF ); - - nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength; - - VSIFSeekL( psDBF->fp, nRecordOffset, 0 ); - if( VSIFReadL( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp ) != 1 ) - return MS_FALSE; - - psDBF->nCurrentRecord = hEntity; - } - - pabyRec = (uchar *) psDBF->pszCurrentRecord; - - /* -------------------------------------------------------------------- */ - /* Assign all the record fields. */ - /* -------------------------------------------------------------------- */ - switch( psDBF->pachFieldType[iField] ) { - case 'D': - case 'N': - case 'F': - snprintf(szSField, sizeof(szSField), "%*.*f", psDBF->panFieldSize[iField], psDBF->panFieldDecimals[iField], *(double*) pValue); - len = strlen((char *) szSField); - memcpy(pabyRec+psDBF->panFieldOffset[iField], szSField, MS_MIN(len, psDBF->panFieldSize[iField])); - break; - - default: - len = strlen((char *) pValue); - memcpy(pabyRec+psDBF->panFieldOffset[iField], pValue, MS_MIN(len, psDBF->panFieldSize[iField])); - break; - } - - psDBF->bCurrentRecordModified = MS_TRUE; - psDBF->bUpdated = MS_TRUE; - - return( MS_TRUE ); -} - -/************************************************************************/ -/* msDBFWriteDoubleAttribute() */ -/* */ -/* Write a double attribute. */ -/************************************************************************/ -int msDBFWriteDoubleAttribute( DBFHandle psDBF, int iRecord, int iField, double dValue ) -{ - return( msDBFWriteAttribute( psDBF, iRecord, iField, (void *) &dValue ) ); -} - -/************************************************************************/ -/* msDBFWriteIntegerAttribute() */ -/* */ -/* Write a integer attribute. */ -/************************************************************************/ - -int msDBFWriteIntegerAttribute( DBFHandle psDBF, int iRecord, int iField, int nValue ) -{ - double dValue = nValue; - - return( msDBFWriteAttribute( psDBF, iRecord, iField, (void *) &dValue ) ); -} - -/************************************************************************/ -/* msDBFWriteStringAttribute() */ -/* */ -/* Write a string attribute. */ -/************************************************************************/ -int msDBFWriteStringAttribute( DBFHandle psDBF, int iRecord, int iField, const char * pszValue ) -{ - return( msDBFWriteAttribute( psDBF, iRecord, iField, (void *) pszValue ) ); -} - -/* -** Which column number in the .DBF file does the item correspond to -*/ -int msDBFGetItemIndex(DBFHandle dbffile, char *name) -{ - int i; - int fWidth,fnDecimals; /* field width and number of decimals */ - char fName[32]; /* field name */ - - if(!name) { - msSetError(MS_MISCERR, "NULL item name passed.", "msGetItemIndex()"); - return(-1); - } - - /* does name exist as a field? */ - for(i=0; i - * - ****************************************************************************** - * Copyright (c) 1996-2007 Regents of the University of Minnesota. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies of this Software or works derived from this Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - ****************************************************************************/ - -#include "mapserver.h" - - -#ifdef USE_EXEMPI - -/* To pull parts out of hash keys */ -#include - -/* To write the XMP XML into the files */ -#include -#include - -/** -* Get standard Exempi namespace URI for a given namespace string -*/ -static const char* -msXmpUri(char *ns_name) -{ - /* Creative Commons */ - if( strcmp(ns_name, "cc") == 0 ) - return NS_CC; - /* Dublin Core */ - else if( strcmp(ns_name, "dc") == 0 ) - return NS_DC; - /* XMP Meta */ - else if( strcmp(ns_name, "meta") == 0 ) - return NS_XMP_META; - /* XMP Rights */ - else if( strcmp(ns_name, "rights") == 0 ) - return NS_XAP_RIGHTS; - /* EXIF */ - else if( strcmp(ns_name, "exif") == 0 ) - return NS_EXIF; - /* TIFF */ - else if( strcmp(ns_name, "tiff") == 0 ) - return NS_TIFF; - /* Photoshop Camera Raw Schema */ - else if( strcmp(ns_name, "crs") == 0 ) - return NS_CAMERA_RAW_SETTINGS; - /* Photoshop */ - else if( strcmp(ns_name, "photoshop") == 0 ) - return NS_PHOTOSHOP; - else - return NULL; -} - -#endif - -/** -* Is there any XMP metadata in the map file for us to worry about? -*/ -int -msXmpPresent( mapObj *map ) -{ -#ifdef USE_EXEMPI - - /* Read the WEB.METADATA */ - hashTableObj hash_metadata = map->web.metadata; - const char *key = NULL; - int rv = MS_FALSE; - - /* Check all the keys for "xmp_" start pattern */ - key = msFirstKeyFromHashTable(&hash_metadata); - - /* No first key? No license info. */ - if ( ! key ) - return MS_FALSE; - - do { - /* Found one! Break out and return true */ - if ( strcasestr(key, "xmp_") == key ) { - rv = MS_TRUE; - break; - } - } while( (key = msNextKeyFromHashTable(&hash_metadata, key)) ); - - return rv; - -#else - return MS_FALSE; -#endif -} - - -/** -* Is there any XMP metadata in the map file for us to worry about? -*/ -int -msXmpWrite( mapObj *map, const char *filename ) -{ -#ifdef USE_EXEMPI - - /* Should hold our keys */ - hashTableObj hash_metadata = map->web.metadata; - /* Temporary place for custom name spaces */ - hashTableObj hash_ns; - /* We use regex to strip out the namespace and XMP key value from the metadata key */ - regex_t xmp_regex; - const char *xmp_ns_str = "^xmp_(.+)_namespace$"; - const char *xmp_tag_str = "^xmp_(.+)_(.+)$"; - const char *key = NULL; - static int regflags = REG_ICASE | REG_EXTENDED; - - /* XMP object and file pointers */ - XmpPtr xmp; - XmpFilePtr f; - - /* Force the hash table to empty */ - hash_ns.numitems = 0; - - /* Prepare XMP library */ - xmp_init(); - f = xmp_files_open_new(filename, XMP_OPEN_FORUPDATE); - if ( ! f ) { - msSetError( MS_MISCERR, - "Unable to open temporary file '%s' to write XMP info", - "msXmpWrite()", filename ); - return MS_FAILURE; - } - - /* Create a new XMP structure if the file doesn't already have one */ - xmp = xmp_files_get_new_xmp(f); - if ( xmp == NULL ) - xmp = xmp_new_empty(); - - /* Check we can write to the file */ - if ( ! xmp_files_can_put_xmp(f, xmp) ) { - msSetError( MS_MISCERR, - "Unable to write XMP information to '%s'", - "msXmpWrite()", filename ); - return MS_FAILURE; - } - - /* Compile our "xmp_*_namespace" regex */ - if ( regcomp(&xmp_regex, xmp_ns_str, regflags) ) { - msSetError( MS_MISCERR, - "Unable compile regex '%s'", - "msXmpWrite()", xmp_ns_str ); - return MS_FAILURE; - } - - /* Check all the keys for "xmp_*_namespace" pattern */ - initHashTable(&hash_ns); - key = msFirstKeyFromHashTable(&hash_metadata); - - /* No first key? No license info. We shouldn't get here. */ - if ( ! key ) - return MS_SUCCESS; - - do { - /* Our regex has one match slot */ - regmatch_t matches[2]; - - /* Found a custom namespace entry! Store it for later. */ - if ( 0 == regexec(&xmp_regex, key, 2, matches, 0) ) { - size_t ns_size = 0; - char *ns_name = NULL; - const char *ns_uri; - - /* Copy in the namespace name */ - ns_size = matches[1].rm_eo - matches[1].rm_so; - ns_name = msSmallMalloc(ns_size + 1); - memcpy(ns_name, key + matches[1].rm_so, ns_size); - ns_name[ns_size] = 0; /* null terminate */ - - /* Copy in the namespace uri */ - ns_uri = msLookupHashTable(&hash_metadata, key); - msInsertHashTable(&hash_ns, ns_name, ns_uri); - xmp_register_namespace(ns_uri, ns_name, NULL); - msFree(ns_name); - } - } while( (key = msNextKeyFromHashTable(&hash_metadata, key)) ); - /* Clean up regex */ - regfree(&xmp_regex); - - - /* Compile our "xmp_*_*" regex */ - if ( regcomp(&xmp_regex, xmp_tag_str, regflags) ) { - msFreeHashItems(&hash_ns); - msSetError( MS_MISCERR, - "Unable compile regex '%s'", - "msXmpWrite()", xmp_tag_str ); - return MS_FAILURE; - } - - /* Check all the keys for "xmp_*_*" pattern */ - key = msFirstKeyFromHashTable(&hash_metadata); - do { - /* Our regex has two match slots */ - regmatch_t matches[3]; - - /* Found a namespace entry! Write it into XMP. */ - if ( 0 == regexec(&xmp_regex, key, 3, matches, 0) ) { - /* Get the namespace and tag name */ - size_t ns_name_size = matches[1].rm_eo - matches[1].rm_so; - size_t ns_tag_size = matches[2].rm_eo - matches[2].rm_so; - char *ns_name = msSmallMalloc(ns_name_size + 1); - char *ns_tag = msSmallMalloc(ns_tag_size + 1); - const char *ns_uri = NULL; - memcpy(ns_name, key + matches[1].rm_so, ns_name_size); - memcpy(ns_tag, key + matches[2].rm_so, ns_tag_size); - ns_name[ns_name_size] = 0; /* null terminate */ - ns_tag[ns_tag_size] = 0; /* null terminate */ - - if ( strcmp(ns_tag,"namespace") == 0 ) { - msFree(ns_name); - msFree(ns_tag); - continue; - } - - /* If this is a default name space?... */ - if ( (ns_uri = msXmpUri(ns_name)) ) { - xmp_register_namespace(ns_uri, ns_name, NULL); - xmp_set_property(xmp, ns_uri, ns_tag, msLookupHashTable(&hash_metadata, key), 0); - } - /* Or maybe it's a custom one?... */ - else if ( (ns_uri = msLookupHashTable(&hash_ns, ns_name)) ) { - xmp_set_property(xmp, ns_uri, ns_tag, msLookupHashTable(&hash_metadata, key), 0); - } - /* Or perhaps we're screwed. */ - else { - msSetError( MS_MISCERR, - "Unable to identify XMP namespace '%s' in metadata key '%s'", - "msXmpWrite()", ns_name, key ); - msFreeHashItems(&hash_ns); - msFree(ns_name); - msFree(ns_tag); - return MS_FAILURE; - } - msFree(ns_name); - msFree(ns_tag); - } - } while( (key = msNextKeyFromHashTable(&hash_metadata, key)) ); - - /* Clean up regex */ - regfree(&xmp_regex); - - /* Write out the XMP */ - if ( !xmp_files_put_xmp(f, xmp) ) { - msFreeHashItems(&hash_ns); - msSetError( MS_MISCERR, - "Unable to execute '%s' on pointer %p", - "msXmpWrite()", "xmp_files_put_xmp", f ); - return MS_FAILURE; - } - - /* Write out the file and flush */ - if ( !xmp_files_close(f, XMP_CLOSE_SAFEUPDATE) ) { - msFreeHashItems(&hash_ns); - msSetError( MS_MISCERR, - "Unable to execute '%s' on pointer %p", - "msXmpWrite()", "xmp_files_close", f ); - return MS_FAILURE; - } - - msFreeHashItems(&hash_ns); - xmp_free(xmp); - xmp_terminate(); - - return MS_SUCCESS; - -#else - return MS_FAILURE; -#endif -} - diff --git a/msautotest/README b/msautotest/README index e83faf0958..a5f2f39dd9 100644 --- a/msautotest/README +++ b/msautotest/README @@ -1,6 +1,12 @@ See: - http://www.mapserver.org/development/tests/autotest.html + https://mapserver.org/development/tests/autotest.html -Send new tests via MapServer Issue Tracker at https://github.com/mapserver/mapserver/issues/ +Send new tests via MapServer Issue Tracker at https://github.com/MapServer/MapServer/issues/ (use the label 'Msautotest'). + +Note that a number of tests expect to be run under Ubuntu 20.04 with the prerequisites +of ci/setup.sh to yield the expected test results. A Vagrant environment +(https://mapserver.org/development/tests/vagrant.html) can be conveniently used +to meet those prerequisites. + diff --git a/msautotest/api/6631.map b/msautotest/api/6631.map new file mode 100644 index 0000000000..40ecd1b5c5 --- /dev/null +++ b/msautotest/api/6631.map @@ -0,0 +1,68 @@ +# RUN_PARMS: ogcapi_collections_tanzania1_items.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/tanzania1/items" "QUERY_STRING=f=json" > [RESULT_DEMIME] +# RUN_PARMS: ogcapi_collections_tanzania2_items.json [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/tanzania2/items" "QUERY_STRING=f=json" > [RESULT_DEMIME] +# RUN_PARMS: ogcapi_collections_tanzania1_items.html.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/tanzania1/items" "QUERY_STRING=f=html" > [RESULT_DEMIME] +# RUN_PARMS: ogcapi_collections_tanzania2_items.html [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/tanzania2/items" "QUERY_STRING=f=html" > [RESULT_DEMIME] + +MAP + EXTENT 29.339998 -11.720938 40.316590 -0.950000 + SIZE 800 800 + + PROJECTION "+init=epsg:4326" END + UNITS METERS + + WEB + METADATA + "oga_html_template_directory" "../../share/ogcapi/templates/html-plain" + "oga_title" "Issue #6631" ## REQUIRED + "oga_description" "This is a test OGC API server description for issue #6631." + "oga_contactperson" "Contact person" + "oga_contacturl" "http://example.com/contact" + "oga_contactelectronicmailaddress" "email@example.com" + "oga_termsofservice" "Terms of Service" + "oga_onlineresource" "http://localhost/cgi-bin/mapserv/6631/ogcapi" ## REQUIRED + "oga_server_description" "Server description" + "oga_enable_request" "OGCAPI" ## REQUIRED + "oga_geometry_precision" "4" + END + END + + LAYER + NAME "tanzania1" + DATA "data/countries-tanzania" + TYPE POLYGON + STATUS OFF + METADATA + "oga_keywords" "boundary,Tanzania" # falls back to wfs_keywordlist + "oga_description" "Tanzania Boundary" + "oga_title" "Tanzania Boundary" + "gml_include_items" "name,nr_id,name_hu" # also works with oga prefix + "oga_featureid" "ne_id" + END + VALIDATION + "ne_id" "^1159321337$" # only one acceptable value + END + PROJECTION "+init=epsg:4326" END + TEMPLATE VOID + END + + LAYER + NAME "tanzania2" + DATA "data/countries-tanzania" + TYPE POLYGON + STATUS OFF + ENCODING "ISO-8859-1" + METADATA + "oga_keywords" "boundary,Tanzania" # falls back to wfs_keywordlist + "oga_description" "Tanzania Boundary" + "oga_title" "Tanzania Boundary" + "gml_include_items" "name,nr_id,name_hu" # also works with oga prefix + "oga_featureid" "ne_id" + END + VALIDATION + "ne_id" "^1159321337$" # only one acceptable value + END + PROJECTION "+init=epsg:4326" END + TEMPLATE VOID + END + +END diff --git a/msautotest/api/7305_multipolygon.map b/msautotest/api/7305_multipolygon.map new file mode 100644 index 0000000000..c88fd1beb6 --- /dev/null +++ b/msautotest/api/7305_multipolygon.map @@ -0,0 +1,45 @@ +# RUN_PARMS: ogcapi_collections_multipolygon_items.json [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/multipolygon_layer/items" "QUERY_STRING=f=json" > [RESULT_DEMIME] +# RUN_PARMS: ogcapi_collections_multipolygon_items.html [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/multipolygon_layer/items" "QUERY_STRING=f=html" > [RESULT_DEMIME] + +MAP + EXTENT -23422614 -11650014 23758273 18540865 + SIZE 800 800 + + PROJECTION + "+init=epsg:4326" + END + UNITS METERS + + WEB + METADATA + "oga_html_template_directory" "../../share/ogcapi/templates/html-plain" + "oga_title" "Pull Request #7305" + "oga_description" "This is a test OGC API server description for pull request #7305." + "oga_onlineresource" "http://localhost/cgi-bin/mapserv/7305/ogcapi" + "oga_server_description" "Server description" + "oga_enable_request" "OGCAPI" + "oga_geometry_precision" "4" + END + END + + LAYER + NAME "multipolygon_layer" + DATA "data/7305-multipolygon" + TYPE POLYGON + STATUS OFF + METADATA + "oga_keywords" "multipolygon" + "oga_description" "Layer with multipolygon with holes" + "oga_title" "Multipolygon layer" + "oga_featureid" "ogc_fid" + END + VALIDATION + "ogc_fid" "^3$" # only one acceptable value + END + PROJECTION + "+init=epsg:4326" + END + TEMPLATE VOID + END +END + \ No newline at end of file diff --git a/mapscript/python/examples/__init__.py b/msautotest/api/__init__.py similarity index 100% rename from mapscript/python/examples/__init__.py rename to msautotest/api/__init__.py diff --git a/msautotest/api/data/7305-multipolygon.dbf b/msautotest/api/data/7305-multipolygon.dbf new file mode 100644 index 0000000000..555e8ebb42 Binary files /dev/null and b/msautotest/api/data/7305-multipolygon.dbf differ diff --git a/msautotest/api/data/7305-multipolygon.prj b/msautotest/api/data/7305-multipolygon.prj new file mode 100644 index 0000000000..f45cbadf00 --- /dev/null +++ b/msautotest/api/data/7305-multipolygon.prj @@ -0,0 +1 @@ +GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]] \ No newline at end of file diff --git a/msautotest/api/data/7305-multipolygon.shp b/msautotest/api/data/7305-multipolygon.shp new file mode 100644 index 0000000000..22e8af72bd Binary files /dev/null and b/msautotest/api/data/7305-multipolygon.shp differ diff --git a/msautotest/api/data/7305-multipolygon.shx b/msautotest/api/data/7305-multipolygon.shx new file mode 100644 index 0000000000..e348e6119f Binary files /dev/null and b/msautotest/api/data/7305-multipolygon.shx differ diff --git a/msautotest/api/data/countries-tanzania.dbf b/msautotest/api/data/countries-tanzania.dbf new file mode 100755 index 0000000000..4765712328 Binary files /dev/null and b/msautotest/api/data/countries-tanzania.dbf differ diff --git a/msautotest/api/data/countries-tanzania.prj b/msautotest/api/data/countries-tanzania.prj new file mode 100755 index 0000000000..f45cbadf00 --- /dev/null +++ b/msautotest/api/data/countries-tanzania.prj @@ -0,0 +1 @@ +GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]] \ No newline at end of file diff --git a/msautotest/api/data/countries-tanzania.shp b/msautotest/api/data/countries-tanzania.shp new file mode 100755 index 0000000000..4b9c123641 Binary files /dev/null and b/msautotest/api/data/countries-tanzania.shp differ diff --git a/msautotest/api/data/countries-tanzania.shx b/msautotest/api/data/countries-tanzania.shx new file mode 100755 index 0000000000..64df1f02c8 Binary files /dev/null and b/msautotest/api/data/countries-tanzania.shx differ diff --git a/msautotest/api/data/mn_counties.dbf b/msautotest/api/data/mn_counties.dbf new file mode 100644 index 0000000000..e75017c62f Binary files /dev/null and b/msautotest/api/data/mn_counties.dbf differ diff --git a/msautotest/api/data/mn_counties.prj b/msautotest/api/data/mn_counties.prj new file mode 100644 index 0000000000..e18e7e8513 --- /dev/null +++ b/msautotest/api/data/mn_counties.prj @@ -0,0 +1 @@ +PROJCS["NAD_1983_UTM_Zone_15N",GEOGCS["GCS_North_American_1983",DATUM["D_North_American_1983",SPHEROID["GRS_1980",6378137.0,298.257222101]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Transverse_Mercator"],PARAMETER["False_Easting",500000.0],PARAMETER["False_Northing",0.0],PARAMETER["Central_Meridian",-93.0],PARAMETER["Scale_Factor",0.9996],PARAMETER["Latitude_Of_Origin",0.0],UNIT["Meter",1.0]] \ No newline at end of file diff --git a/msautotest/api/data/mn_counties.shp b/msautotest/api/data/mn_counties.shp new file mode 100644 index 0000000000..28c5c6583b Binary files /dev/null and b/msautotest/api/data/mn_counties.shp differ diff --git a/msautotest/api/data/mn_counties.shx b/msautotest/api/data/mn_counties.shx new file mode 100644 index 0000000000..b4dba5148b Binary files /dev/null and b/msautotest/api/data/mn_counties.shx differ diff --git a/msautotest/api/data/mn_major_rivers.dbf b/msautotest/api/data/mn_major_rivers.dbf new file mode 100644 index 0000000000..d8904720e7 Binary files /dev/null and b/msautotest/api/data/mn_major_rivers.dbf differ diff --git a/msautotest/api/data/mn_major_rivers.prj b/msautotest/api/data/mn_major_rivers.prj new file mode 100644 index 0000000000..c4128b9271 --- /dev/null +++ b/msautotest/api/data/mn_major_rivers.prj @@ -0,0 +1 @@ +PROJCS["NAD_1983_UTM_Zone_15N",GEOGCS["GCS_North_American_1983",DATUM["D_North_American_1983",SPHEROID["GRS_1980",6378137.0,298.257222101]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Transverse_Mercator"],PARAMETER["False_Easting",500000.0],PARAMETER["False_Northing",0.0],PARAMETER["Central_Meridian",-93.0],PARAMETER["Scale_Factor",0.9996],PARAMETER["Latitude_Of_Origin",0.0],UNIT["Meter",1.0]],VERTCS["NAD_1983",DATUM["D_North_American_1983",SPHEROID["GRS_1980",6378137.0,298.257222101]],PARAMETER["Vertical_Shift",0.0],PARAMETER["Direction",1.0],UNIT["Meter",1.0]] \ No newline at end of file diff --git a/msautotest/api/data/mn_major_rivers.shp b/msautotest/api/data/mn_major_rivers.shp new file mode 100644 index 0000000000..a62b1fd173 Binary files /dev/null and b/msautotest/api/data/mn_major_rivers.shp differ diff --git a/msautotest/api/data/mn_major_rivers.shx b/msautotest/api/data/mn_major_rivers.shx new file mode 100644 index 0000000000..afdef07514 Binary files /dev/null and b/msautotest/api/data/mn_major_rivers.shx differ diff --git a/msautotest/api/data/mn_population_centers.dbf b/msautotest/api/data/mn_population_centers.dbf new file mode 100644 index 0000000000..f67b3852a7 Binary files /dev/null and b/msautotest/api/data/mn_population_centers.dbf differ diff --git a/msautotest/api/data/mn_population_centers.prj b/msautotest/api/data/mn_population_centers.prj new file mode 100644 index 0000000000..e18e7e8513 --- /dev/null +++ b/msautotest/api/data/mn_population_centers.prj @@ -0,0 +1 @@ +PROJCS["NAD_1983_UTM_Zone_15N",GEOGCS["GCS_North_American_1983",DATUM["D_North_American_1983",SPHEROID["GRS_1980",6378137.0,298.257222101]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Transverse_Mercator"],PARAMETER["False_Easting",500000.0],PARAMETER["False_Northing",0.0],PARAMETER["Central_Meridian",-93.0],PARAMETER["Scale_Factor",0.9996],PARAMETER["Latitude_Of_Origin",0.0],UNIT["Meter",1.0]] \ No newline at end of file diff --git a/msautotest/api/data/mn_population_centers.shp b/msautotest/api/data/mn_population_centers.shp new file mode 100644 index 0000000000..27ed064bd5 Binary files /dev/null and b/msautotest/api/data/mn_population_centers.shp differ diff --git a/msautotest/api/data/mn_population_centers.shx b/msautotest/api/data/mn_population_centers.shx new file mode 100644 index 0000000000..8ad26284e2 Binary files /dev/null and b/msautotest/api/data/mn_population_centers.shx differ diff --git a/msautotest/api/expected/conformance.html b/msautotest/api/expected/conformance.html new file mode 100644 index 0000000000..1c9c251828 --- /dev/null +++ b/msautotest/api/expected/conformance.html @@ -0,0 +1,84 @@ + + + + OGC API Test + + + + + +

OGC API Test - Conformance

+ +

This API implements the conformance classes from standards and community specifications that are listed below.

+ +

Links

+ + + + +

Template Data

+

+ API Root: http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi
+ Path: ["ogcapi.map","ogcapi","conformance"]
+ Params: {"f":"html"}
+ Extra Params:
+ Title: OGC API Test
+ Tags: {"debug":"true","sample":"sample tag"}
+

+ + + + + + + diff --git a/msautotest/api/expected/conformance.json b/msautotest/api/expected/conformance.json new file mode 100644 index 0000000000..9c55453698 --- /dev/null +++ b/msautotest/api/expected/conformance.json @@ -0,0 +1 @@ +{"conformsTo":["http://www.opengis.net/spec/ogcapi-common-1/1.0/conf/core","http://www.opengis.net/spec/ogcapi-common-2/1.0/conf/collections","http://www.opengis.net/spec/ogcapi-features-1/1.0/conf/core","http://www.opengis.net/spec/ogcapi-features-1/1.0/conf/oas30","http://www.opengis.net/spec/ogcapi-features-1/1.0/conf/html","http://www.opengis.net/spec/ogcapi-features-1/1.0/conf/geojson","http://www.opengis.net/spec/ogcapi-features-2/1.0/conf/crs","http://www.opengis.net/spec/ogcapi-features-3/1.0/conf/queryables","http://www.opengis.net/spec/ogcapi-features-3/1.0/conf/queryables-query-parameters","http://www.opengis.net/spec/ogcapi-features-3/1.0/conf/filter","http://www.opengis.net/spec/cql2/1.0/conf/cql2-text","http://www.opengis.net/spec/cql2/1.0/conf/cql2-json","http://www.opengis.net/spec/cql2/1.0/conf/basic-cql2","http://www.opengis.net/spec/cql2/1.0/conf/advanced-comparison-operators","http://www.opengis.net/spec/cql2/1.0/conf/case-insensitive-comparison","http://www.opengis.net/spec/cql2/1.0/conf/basic-spatial-functions","http://www.opengis.net/spec/cql2/1.0/conf/basic-spatial-functions-plus","http://www.opengis.net/spec/cql2/1.0/conf/spatial-functions","http://www.opengis.net/spec/cql2/1.0/conf/property-property","http://www.opengis.net/spec/cql2/1.0/conf/arithmetic","http://www.opengis.net/spec/ogcapi-features-5/1.0/conf/queryables","http://www.opengis.net/spec/ogcapi-features-5/1.0/conf/schemas","http://www.opengis.net/spec/ogcapi-features-5/1.0/conf/returnables-and-receivables","http://www.opengis.net/spec/ogcapi-features-5/1.0/conf/sortables"]} diff --git a/msautotest/api/expected/extents_collections.json b/msautotest/api/expected/extents_collections.json new file mode 100644 index 0000000000..93804db65d --- /dev/null +++ b/msautotest/api/expected/extents_collections.json @@ -0,0 +1 @@ +{"collections":[{"crs":["http://www.opengis.net/def/crs/OGC/1.3/CRS84","http://www.opengis.net/def/crs/EPSG/0/32615"],"description":"mn_counties","extent":{"spatial":{"bbox":[[-97.266614,43.438567,-89.388883,49.404536]],"crs":"http://www.opengis.net/def/crs/OGC/1.3/CRS84"}},"id":"mn_counties","itemType":"feature","links":[{"href":"http://localhost/cgi-bin/mapserv/extents/ogcapi/collections/mn_counties?f=json","rel":"self","title":"This collection as JSON","type":"application/json"},{"href":"http://localhost/cgi-bin/mapserv/extents/ogcapi/collections/mn_counties?f=html","rel":"alternate","title":"This collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/extents/ogcapi/collections/mn_counties/items?f=json","rel":"items","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/extents/ogcapi/collections/mn_counties/items?f=html","rel":"items","title":"Items for this collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/extents/ogcapi/collections/mn_counties/schema?f=json","rel":"http://www.opengis.net/def/rel/ogc/1.0/schema","title":"Schema for this collection as JSON schema","type":"application/schema+json"},{"href":"http://localhost/cgi-bin/mapserv/extents/ogcapi/collections/mn_counties/schema?f=html","rel":"http://www.opengis.net/def/rel/ogc/1.0/schema","title":"Schema for this collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/extents/ogcapi/collections/mn_counties/queryables?f=json","rel":"http://www.opengis.net/def/rel/ogc/1.0/queryables","title":"Queryables for this collection as JSON schema","type":"application/schema+json"},{"href":"http://localhost/cgi-bin/mapserv/extents/ogcapi/collections/mn_counties/queryables?f=html","rel":"http://www.opengis.net/def/rel/ogc/1.0/queryables","title":"Queryables for this collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/extents/ogcapi/collections/mn_counties/sortables?f=json","rel":"http://www.opengis.net/def/rel/ogc/1.0/sortables","title":"Sortables for this collection as JSON schema","type":"application/schema+json"},{"href":"http://localhost/cgi-bin/mapserv/extents/ogcapi/collections/mn_counties/sortables?f=html","rel":"http://www.opengis.net/def/rel/ogc/1.0/sortables","title":"Sortables for this collection as HTML","type":"text/html"}],"storageCrs":"http://www.opengis.net/def/crs/EPSG/0/32615","title":"mn_counties"},{"crs":["http://www.opengis.net/def/crs/OGC/1.3/CRS84","http://www.opengis.net/def/crs/EPSG/0/26915"],"description":"mn_major_rivers","extent":{"spatial":{"bbox":[[-97.266614,43.438567,-89.388883,49.404536]],"crs":"http://www.opengis.net/def/crs/OGC/1.3/CRS84"}},"id":"mn_major_rivers","itemType":"feature","links":[{"href":"http://localhost/cgi-bin/mapserv/extents/ogcapi/collections/mn_major_rivers?f=json","rel":"self","title":"This collection as JSON","type":"application/json"},{"href":"http://localhost/cgi-bin/mapserv/extents/ogcapi/collections/mn_major_rivers?f=html","rel":"alternate","title":"This collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/extents/ogcapi/collections/mn_major_rivers/items?f=json","rel":"items","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/extents/ogcapi/collections/mn_major_rivers/items?f=html","rel":"items","title":"Items for this collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/extents/ogcapi/collections/mn_major_rivers/schema?f=json","rel":"http://www.opengis.net/def/rel/ogc/1.0/schema","title":"Schema for this collection as JSON schema","type":"application/schema+json"},{"href":"http://localhost/cgi-bin/mapserv/extents/ogcapi/collections/mn_major_rivers/schema?f=html","rel":"http://www.opengis.net/def/rel/ogc/1.0/schema","title":"Schema for this collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/extents/ogcapi/collections/mn_major_rivers/queryables?f=json","rel":"http://www.opengis.net/def/rel/ogc/1.0/queryables","title":"Queryables for this collection as JSON schema","type":"application/schema+json"},{"href":"http://localhost/cgi-bin/mapserv/extents/ogcapi/collections/mn_major_rivers/queryables?f=html","rel":"http://www.opengis.net/def/rel/ogc/1.0/queryables","title":"Queryables for this collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/extents/ogcapi/collections/mn_major_rivers/sortables?f=json","rel":"http://www.opengis.net/def/rel/ogc/1.0/sortables","title":"Sortables for this collection as JSON schema","type":"application/schema+json"},{"href":"http://localhost/cgi-bin/mapserv/extents/ogcapi/collections/mn_major_rivers/sortables?f=html","rel":"http://www.opengis.net/def/rel/ogc/1.0/sortables","title":"Sortables for this collection as HTML","type":"text/html"}],"title":"mn_major_rivers"},{"crs":["http://www.opengis.net/def/crs/OGC/1.3/CRS84","http://www.opengis.net/def/crs/EPSG/0/26915"],"description":"mn_major_rivers2","extent":{"spatial":{"bbox":[[-97.24163,43.234009,-90.515182,49.077965]],"crs":"http://www.opengis.net/def/crs/OGC/1.3/CRS84"}},"id":"mn_major_rivers2","itemType":"feature","links":[{"href":"http://localhost/cgi-bin/mapserv/extents/ogcapi/collections/mn_major_rivers2?f=json","rel":"self","title":"This collection as JSON","type":"application/json"},{"href":"http://localhost/cgi-bin/mapserv/extents/ogcapi/collections/mn_major_rivers2?f=html","rel":"alternate","title":"This collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/extents/ogcapi/collections/mn_major_rivers2/items?f=json","rel":"items","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/extents/ogcapi/collections/mn_major_rivers2/items?f=html","rel":"items","title":"Items for this collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/extents/ogcapi/collections/mn_major_rivers2/schema?f=json","rel":"http://www.opengis.net/def/rel/ogc/1.0/schema","title":"Schema for this collection as JSON schema","type":"application/schema+json"},{"href":"http://localhost/cgi-bin/mapserv/extents/ogcapi/collections/mn_major_rivers2/schema?f=html","rel":"http://www.opengis.net/def/rel/ogc/1.0/schema","title":"Schema for this collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/extents/ogcapi/collections/mn_major_rivers2/queryables?f=json","rel":"http://www.opengis.net/def/rel/ogc/1.0/queryables","title":"Queryables for this collection as JSON schema","type":"application/schema+json"},{"href":"http://localhost/cgi-bin/mapserv/extents/ogcapi/collections/mn_major_rivers2/queryables?f=html","rel":"http://www.opengis.net/def/rel/ogc/1.0/queryables","title":"Queryables for this collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/extents/ogcapi/collections/mn_major_rivers2/sortables?f=json","rel":"http://www.opengis.net/def/rel/ogc/1.0/sortables","title":"Sortables for this collection as JSON schema","type":"application/schema+json"},{"href":"http://localhost/cgi-bin/mapserv/extents/ogcapi/collections/mn_major_rivers2/sortables?f=html","rel":"http://www.opengis.net/def/rel/ogc/1.0/sortables","title":"Sortables for this collection as HTML","type":"text/html"}],"title":"mn_major_rivers2"},{"crs":["http://www.opengis.net/def/crs/OGC/1.3/CRS84","http://www.opengis.net/def/crs/EPSG/0/26915"],"description":"mn_population_centers","extent":{"spatial":{"bbox":[[-97.251964,43.439119,-89.594878,49.365107]],"crs":"http://www.opengis.net/def/crs/OGC/1.3/CRS84"}},"id":"mn_population_centers","itemType":"feature","links":[{"href":"http://localhost/cgi-bin/mapserv/extents/ogcapi/collections/mn_population_centers?f=json","rel":"self","title":"This collection as JSON","type":"application/json"},{"href":"http://localhost/cgi-bin/mapserv/extents/ogcapi/collections/mn_population_centers?f=html","rel":"alternate","title":"This collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/extents/ogcapi/collections/mn_population_centers/items?f=json","rel":"items","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/extents/ogcapi/collections/mn_population_centers/items?f=html","rel":"items","title":"Items for this collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/extents/ogcapi/collections/mn_population_centers/schema?f=json","rel":"http://www.opengis.net/def/rel/ogc/1.0/schema","title":"Schema for this collection as JSON schema","type":"application/schema+json"},{"href":"http://localhost/cgi-bin/mapserv/extents/ogcapi/collections/mn_population_centers/schema?f=html","rel":"http://www.opengis.net/def/rel/ogc/1.0/schema","title":"Schema for this collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/extents/ogcapi/collections/mn_population_centers/queryables?f=json","rel":"http://www.opengis.net/def/rel/ogc/1.0/queryables","title":"Queryables for this collection as JSON schema","type":"application/schema+json"},{"href":"http://localhost/cgi-bin/mapserv/extents/ogcapi/collections/mn_population_centers/queryables?f=html","rel":"http://www.opengis.net/def/rel/ogc/1.0/queryables","title":"Queryables for this collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/extents/ogcapi/collections/mn_population_centers/sortables?f=json","rel":"http://www.opengis.net/def/rel/ogc/1.0/sortables","title":"Sortables for this collection as JSON schema","type":"application/schema+json"},{"href":"http://localhost/cgi-bin/mapserv/extents/ogcapi/collections/mn_population_centers/sortables?f=html","rel":"http://www.opengis.net/def/rel/ogc/1.0/sortables","title":"Sortables for this collection as HTML","type":"text/html"}],"storageCrs":"http://www.opengis.net/def/crs/EPSG/0/26915","title":"mn_population_centers"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/extents/ogcapi/collections?f=json","rel":"self","title":"This document as JSON","type":"application/json"},{"href":"http://localhost/cgi-bin/mapserv/extents/ogcapi/collections?f=html","rel":"alternate","title":"This document as HTML","type":"text/html"}]} diff --git a/msautotest/api/expected/ogcapi_api.json b/msautotest/api/expected/ogcapi_api.json new file mode 100644 index 0000000000..841c9ecf81 --- /dev/null +++ b/msautotest/api/expected/ogcapi_api.json @@ -0,0 +1 @@ +{"components":{"parameters":{"f":{"description":"The optional f parameter indicates the output format which the server shall provide as part of the response document. The default format is GeoJSON.","explode":false,"in":"query","name":"f","required":false,"schema":{"default":"json","enum":["json","html"],"type":"string"},"style":"form"},"offset":{"description":"The optional offset parameter indicates the index within the result set from which the server shall begin presenting results in the response document. The first element has an index of 0 (default).","explode":false,"in":"query","name":"offset","required":false,"schema":{"default":0,"minimum":0,"type":"integer"},"style":"form"},"vendorSpecificParameters":{"description":"Additional \"free-form\" parameters that are not explicitly defined","in":"query","name":"vendorSpecificParameters","schema":{"additionalProperties":true,"type":"object"},"style":"form"}},"responses":{"200":{"description":"successful operation"},"default":{"content":{"application/json":{"schema":{"$ref":"https://schemas.opengis.net/ogcapi/common/part1/1.0/openapi/schemas/exception.yaml"}}},"description":"unexpected error"}}},"info":{"contact":{"email":"email@example.com","name":"Contact person","url":"http://example.com/contact"},"description":"This is a test OGC API server description set via oga_description.","termsOfService":"Terms of Service","title":"OGC API Test","version":"1.0.0","x-keywords":"keyword1,keyword2"},"openapi":"3.0.2","paths":{"/":{"get":{"description":"Landing page","operationId":"getLandingPage","parameters":[{"$ref":"#/components/parameters/f"}],"responses":{"200":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/LandingPage"},"400":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/InvalidParameter"},"500":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/ServerError"}},"summary":"Landing page","tags":["server"]}},"/api":{"get":{"description":"API documentation","operationId":"getOpenapi","parameters":[{"$ref":"#/components/parameters/f"}],"responses":{"200":{"$ref":"#/components/responses/200"},"400":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/InvalidParameter"},"default":{"$ref":"#/components/responses/default"}},"summary":"API documentation","tags":["server"]}},"/collections":{"get":{"description":"Collections","operationId":"getCollections","parameters":[{"$ref":"#/components/parameters/f"}],"responses":{"200":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/Collections"},"400":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/InvalidParameter"},"500":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/ServerError"}},"summary":"Collections","tags":["server"]}},"/collections/mn_counties":{"get":{"description":"This is the standard Minnesota State County Boundary dataset.","operationId":"describemn_countiesCollection","parameters":[{"$ref":"#/components/parameters/f"}],"responses":{"200":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/Collection"},"400":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/InvalidParameter"},"500":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/ServerError"}},"summary":"Get State of Minnesota County Boundaries metadata","tags":["mn_counties"]}},"/collections/mn_counties/items":{"get":{"description":"This is the standard Minnesota State County Boundary dataset.","operationId":"getmn_countiesFeatures","parameters":[{"$ref":"#/components/parameters/f"},{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/parameters/bbox"},{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/parameters/datetime"},{"$ref":"http://schemas.opengis.net/ogcapi/features/part2/1.0/openapi/ogcapi-features-2.yaml#/components/parameters/bbox-crs"},{"$ref":"http://schemas.opengis.net/ogcapi/features/part2/1.0/openapi/ogcapi-features-2.yaml#/components/parameters/crs"},{"$ref":"#/components/parameters/offset"},{"$ref":"#/components/parameters/vendorSpecificParameters"},{"$ref":"http://schemas.opengis.net/ogcapi/features/part3/1.0/openapi/ogcapi-features-3.yaml#/components/parameters/filter"},{"$ref":"http://schemas.opengis.net/ogcapi/features/part3/1.0/openapi/ogcapi-features-3.yaml#/components/parameters/filter-lang"},{"$ref":"http://schemas.opengis.net/ogcapi/features/part3/1.0/openapi/ogcapi-features-3.yaml#/components/parameters/filter-crs"},{"description":"The optional limit parameter limits the number of items that are presented in the response document.","explode":false,"in":"query","name":"limit","required":false,"schema":{"default":9,"maximum":15,"minimum":1,"type":"integer"},"style":"form"},{"description":"Optional list of properties by which to sort the items.","explode":false,"in":"query","name":"sortby","required":false,"schema":{"items":{"pattern":"[+|-]?[A-Za-z_].*","type":"string"},"minItems":1,"type":"array"},"style":"form"},{"description":"Queryable item 'Name'","explode":false,"in":"query","name":"Name","required":false,"schema":{"type":"string"},"style":"form"},{"description":"Queryable item 'Area'","explode":false,"in":"query","name":"Area","required":false,"schema":{"type":"number"},"style":"form"},{"description":"Queryable item 'CTYONLY_'","explode":false,"in":"query","name":"CTYONLY_","required":false,"schema":{"type":"integer"},"style":"form"},{"description":"Queryable item 'LASTMOD'","explode":false,"in":"query","name":"LASTMOD","required":false,"schema":{"format":"date-time","type":"string"},"style":"form"}],"responses":{"200":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/Features"},"400":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/InvalidParameter"},"500":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/ServerError"}},"summary":"Get State of Minnesota County Boundaries items","tags":["mn_counties"]}},"/collections/mn_counties/items/{featureId}":{"get":{"description":"This is the standard Minnesota State County Boundary dataset.","operationId":"getmn_countiesFeature","parameters":[{"$ref":"#/components/parameters/f"},{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/parameters/featureId"}],"responses":{"200":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/Feature"},"400":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/InvalidParameter"},"404":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/NotFound"},"500":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/ServerError"}},"summary":"Get State of Minnesota County Boundaries item by id","tags":["mn_counties"]}},"/collections/mn_counties/queryables":{"get":{"description":"Get State of Minnesota County Boundaries queryables","operationId":"getmn_countiesQueryables","parameters":[{"$ref":"#/components/parameters/f"},{"$ref":"#/components/parameters/vendorSpecificParameters"}],"responses":{"200":{"content":{"application/schema+json":{"schema":{"type":"object"}}},"description":"The queryable properties of the collection."},"400":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/InvalidParameter"},"500":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/ServerError"}},"summary":"Get State of Minnesota County Boundaries queryables","tags":["mn_counties"]}},"/collections/mn_counties/schema":{"get":{"description":"Get State of Minnesota County Boundaries schema","operationId":"getmn_countiesSchema","parameters":[{"$ref":"#/components/parameters/f"},{"$ref":"#/components/parameters/vendorSpecificParameters"}],"responses":{"200":{"content":{"application/schema+json":{"schema":{"type":"object"}}},"description":"The returnable properties of the collection."},"400":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/InvalidParameter"},"500":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/ServerError"}},"summary":"Get State of Minnesota County Boundaries schema","tags":["mn_counties"]}},"/collections/mn_counties/sortables":{"get":{"description":"Get State of Minnesota County Boundaries sortables","operationId":"getmn_countiesSortables","parameters":[{"$ref":"#/components/parameters/f"},{"$ref":"#/components/parameters/vendorSpecificParameters"}],"responses":{"200":{"content":{"application/schema+json":{"schema":{"type":"object"}}},"description":"The sortable properties of the collection."},"400":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/InvalidParameter"},"500":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/ServerError"}},"summary":"Get State of Minnesota County Boundaries sortables","tags":["mn_counties"]}},"/collections/mn_counties_all_queryables_and_sortables":{"get":{"description":"This is the standard Minnesota State County Boundary dataset.","operationId":"describemn_counties_all_queryables_and_sortablesCollection","parameters":[{"$ref":"#/components/parameters/f"}],"responses":{"200":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/Collection"},"400":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/InvalidParameter"},"500":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/ServerError"}},"summary":"Get State of Minnesota County Boundaries metadata","tags":["mn_counties_all_queryables_and_sortables"]}},"/collections/mn_counties_all_queryables_and_sortables/items":{"get":{"description":"This is the standard Minnesota State County Boundary dataset.","operationId":"getmn_counties_all_queryables_and_sortablesFeatures","parameters":[{"$ref":"#/components/parameters/f"},{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/parameters/bbox"},{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/parameters/datetime"},{"$ref":"http://schemas.opengis.net/ogcapi/features/part2/1.0/openapi/ogcapi-features-2.yaml#/components/parameters/bbox-crs"},{"$ref":"http://schemas.opengis.net/ogcapi/features/part2/1.0/openapi/ogcapi-features-2.yaml#/components/parameters/crs"},{"$ref":"#/components/parameters/offset"},{"$ref":"#/components/parameters/vendorSpecificParameters"},{"$ref":"http://schemas.opengis.net/ogcapi/features/part3/1.0/openapi/ogcapi-features-3.yaml#/components/parameters/filter"},{"$ref":"http://schemas.opengis.net/ogcapi/features/part3/1.0/openapi/ogcapi-features-3.yaml#/components/parameters/filter-lang"},{"$ref":"http://schemas.opengis.net/ogcapi/features/part3/1.0/openapi/ogcapi-features-3.yaml#/components/parameters/filter-crs"},{"description":"The optional limit parameter limits the number of items that are presented in the response document.","explode":false,"in":"query","name":"limit","required":false,"schema":{"default":9,"maximum":15,"minimum":1,"type":"integer"},"style":"form"},{"description":"Optional list of properties by which to sort the items.","explode":false,"in":"query","name":"sortby","required":false,"schema":{"items":{"pattern":"[+|-]?[A-Za-z_].*","type":"string"},"minItems":1,"type":"array"},"style":"form"},{"description":"Queryable item 'Area'","explode":false,"in":"query","name":"Area","required":false,"schema":{"type":"number"},"style":"form"},{"description":"Queryable item 'Perimiter'","explode":false,"in":"query","name":"Perimiter","required":false,"schema":{"type":"number"},"style":"form"},{"description":"Queryable item 'CTYONLY_'","explode":false,"in":"query","name":"CTYONLY_","required":false,"schema":{"type":"integer"},"style":"form"},{"description":"Queryable item 'CTYONLY_ID'","explode":false,"in":"query","name":"CTYONLY_ID","required":false,"schema":{"type":"string"},"style":"form"},{"description":"Queryable item 'COUN'","explode":false,"in":"query","name":"COUN","required":false,"schema":{"type":"string"},"style":"form"},{"description":"Queryable item 'Name'","explode":false,"in":"query","name":"Name","required":false,"schema":{"type":"string"},"style":"form"},{"description":"Queryable item 'Code'","explode":false,"in":"query","name":"Code","required":false,"schema":{"type":"string"},"style":"form"},{"description":"Queryable item 'CTY_FIPS'","explode":false,"in":"query","name":"CTY_FIPS","required":false,"schema":{"type":"string"},"style":"form"},{"description":"Queryable item 'LASTMOD'","explode":false,"in":"query","name":"LASTMOD","required":false,"schema":{"format":"date-time","type":"string"},"style":"form"}],"responses":{"200":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/Features"},"400":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/InvalidParameter"},"500":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/ServerError"}},"summary":"Get State of Minnesota County Boundaries items","tags":["mn_counties_all_queryables_and_sortables"]}},"/collections/mn_counties_all_queryables_and_sortables/items/{featureId}":{"get":{"description":"This is the standard Minnesota State County Boundary dataset.","operationId":"getmn_counties_all_queryables_and_sortablesFeature","parameters":[{"$ref":"#/components/parameters/f"},{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/parameters/featureId"}],"responses":{"200":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/Feature"},"400":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/InvalidParameter"},"404":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/NotFound"},"500":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/ServerError"}},"summary":"Get State of Minnesota County Boundaries item by id","tags":["mn_counties_all_queryables_and_sortables"]}},"/collections/mn_counties_all_queryables_and_sortables/queryables":{"get":{"description":"Get State of Minnesota County Boundaries queryables","operationId":"getmn_counties_all_queryables_and_sortablesQueryables","parameters":[{"$ref":"#/components/parameters/f"},{"$ref":"#/components/parameters/vendorSpecificParameters"}],"responses":{"200":{"content":{"application/schema+json":{"schema":{"type":"object"}}},"description":"The queryable properties of the collection."},"400":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/InvalidParameter"},"500":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/ServerError"}},"summary":"Get State of Minnesota County Boundaries queryables","tags":["mn_counties_all_queryables_and_sortables"]}},"/collections/mn_counties_all_queryables_and_sortables/schema":{"get":{"description":"Get State of Minnesota County Boundaries schema","operationId":"getmn_counties_all_queryables_and_sortablesSchema","parameters":[{"$ref":"#/components/parameters/f"},{"$ref":"#/components/parameters/vendorSpecificParameters"}],"responses":{"200":{"content":{"application/schema+json":{"schema":{"type":"object"}}},"description":"The returnable properties of the collection."},"400":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/InvalidParameter"},"500":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/ServerError"}},"summary":"Get State of Minnesota County Boundaries schema","tags":["mn_counties_all_queryables_and_sortables"]}},"/collections/mn_counties_all_queryables_and_sortables/sortables":{"get":{"description":"Get State of Minnesota County Boundaries sortables","operationId":"getmn_counties_all_queryables_and_sortablesSortables","parameters":[{"$ref":"#/components/parameters/f"},{"$ref":"#/components/parameters/vendorSpecificParameters"}],"responses":{"200":{"content":{"application/schema+json":{"schema":{"type":"object"}}},"description":"The sortable properties of the collection."},"400":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/InvalidParameter"},"500":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/ServerError"}},"summary":"Get State of Minnesota County Boundaries sortables","tags":["mn_counties_all_queryables_and_sortables"]}},"/collections/mn_counties_no_queryables_and_sortables":{"get":{"description":"This is the standard Minnesota State County Boundary dataset.","operationId":"describemn_counties_no_queryables_and_sortablesCollection","parameters":[{"$ref":"#/components/parameters/f"}],"responses":{"200":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/Collection"},"400":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/InvalidParameter"},"500":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/ServerError"}},"summary":"Get State of Minnesota County Boundaries metadata","tags":["mn_counties_no_queryables_and_sortables"]}},"/collections/mn_counties_no_queryables_and_sortables/items":{"get":{"description":"This is the standard Minnesota State County Boundary dataset.","operationId":"getmn_counties_no_queryables_and_sortablesFeatures","parameters":[{"$ref":"#/components/parameters/f"},{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/parameters/bbox"},{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/parameters/datetime"},{"$ref":"http://schemas.opengis.net/ogcapi/features/part2/1.0/openapi/ogcapi-features-2.yaml#/components/parameters/bbox-crs"},{"$ref":"http://schemas.opengis.net/ogcapi/features/part2/1.0/openapi/ogcapi-features-2.yaml#/components/parameters/crs"},{"$ref":"#/components/parameters/offset"},{"$ref":"#/components/parameters/vendorSpecificParameters"},{"$ref":"http://schemas.opengis.net/ogcapi/features/part3/1.0/openapi/ogcapi-features-3.yaml#/components/parameters/filter"},{"$ref":"http://schemas.opengis.net/ogcapi/features/part3/1.0/openapi/ogcapi-features-3.yaml#/components/parameters/filter-lang"},{"$ref":"http://schemas.opengis.net/ogcapi/features/part3/1.0/openapi/ogcapi-features-3.yaml#/components/parameters/filter-crs"},{"description":"The optional limit parameter limits the number of items that are presented in the response document.","explode":false,"in":"query","name":"limit","required":false,"schema":{"default":9,"maximum":15,"minimum":1,"type":"integer"},"style":"form"},{"description":"Optional list of properties by which to sort the items.","explode":false,"in":"query","name":"sortby","required":false,"schema":{"items":{"pattern":"[+|-]?[A-Za-z_].*","type":"string"},"minItems":1,"type":"array"},"style":"form"}],"responses":{"200":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/Features"},"400":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/InvalidParameter"},"500":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/ServerError"}},"summary":"Get State of Minnesota County Boundaries items","tags":["mn_counties_no_queryables_and_sortables"]}},"/collections/mn_counties_no_queryables_and_sortables/items/{featureId}":{"get":{"description":"This is the standard Minnesota State County Boundary dataset.","operationId":"getmn_counties_no_queryables_and_sortablesFeature","parameters":[{"$ref":"#/components/parameters/f"},{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/parameters/featureId"}],"responses":{"200":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/Feature"},"400":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/InvalidParameter"},"404":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/NotFound"},"500":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/ServerError"}},"summary":"Get State of Minnesota County Boundaries item by id","tags":["mn_counties_no_queryables_and_sortables"]}},"/collections/mn_counties_no_queryables_and_sortables/queryables":{"get":{"description":"Get State of Minnesota County Boundaries queryables","operationId":"getmn_counties_no_queryables_and_sortablesQueryables","parameters":[{"$ref":"#/components/parameters/f"},{"$ref":"#/components/parameters/vendorSpecificParameters"}],"responses":{"200":{"content":{"application/schema+json":{"schema":{"type":"object"}}},"description":"The queryable properties of the collection."},"400":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/InvalidParameter"},"500":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/ServerError"}},"summary":"Get State of Minnesota County Boundaries queryables","tags":["mn_counties_no_queryables_and_sortables"]}},"/collections/mn_counties_no_queryables_and_sortables/schema":{"get":{"description":"Get State of Minnesota County Boundaries schema","operationId":"getmn_counties_no_queryables_and_sortablesSchema","parameters":[{"$ref":"#/components/parameters/f"},{"$ref":"#/components/parameters/vendorSpecificParameters"}],"responses":{"200":{"content":{"application/schema+json":{"schema":{"type":"object"}}},"description":"The returnable properties of the collection."},"400":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/InvalidParameter"},"500":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/ServerError"}},"summary":"Get State of Minnesota County Boundaries schema","tags":["mn_counties_no_queryables_and_sortables"]}},"/collections/mn_counties_no_queryables_and_sortables/sortables":{"get":{"description":"Get State of Minnesota County Boundaries sortables","operationId":"getmn_counties_no_queryables_and_sortablesSortables","parameters":[{"$ref":"#/components/parameters/f"},{"$ref":"#/components/parameters/vendorSpecificParameters"}],"responses":{"200":{"content":{"application/schema+json":{"schema":{"type":"object"}}},"description":"The sortable properties of the collection."},"400":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/InvalidParameter"},"500":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/ServerError"}},"summary":"Get State of Minnesota County Boundaries sortables","tags":["mn_counties_no_queryables_and_sortables"]}},"/collections/mn_major_rivers":{"get":{"description":"This dataset represents stream centerlines for major rivers in Minnesota.","operationId":"describemn_major_riversCollection","parameters":[{"$ref":"#/components/parameters/f"}],"responses":{"200":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/Collection"},"400":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/InvalidParameter"},"500":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/ServerError"}},"summary":"Get Minnesota Major River Centerlines metadata","tags":["mn_major_rivers"]}},"/collections/mn_major_rivers/items":{"get":{"description":"This dataset represents stream centerlines for major rivers in Minnesota.","operationId":"getmn_major_riversFeatures","parameters":[{"$ref":"#/components/parameters/f"},{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/parameters/bbox"},{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/parameters/datetime"},{"$ref":"http://schemas.opengis.net/ogcapi/features/part2/1.0/openapi/ogcapi-features-2.yaml#/components/parameters/bbox-crs"},{"$ref":"http://schemas.opengis.net/ogcapi/features/part2/1.0/openapi/ogcapi-features-2.yaml#/components/parameters/crs"},{"$ref":"#/components/parameters/offset"},{"$ref":"#/components/parameters/vendorSpecificParameters"},{"$ref":"http://schemas.opengis.net/ogcapi/features/part3/1.0/openapi/ogcapi-features-3.yaml#/components/parameters/filter"},{"$ref":"http://schemas.opengis.net/ogcapi/features/part3/1.0/openapi/ogcapi-features-3.yaml#/components/parameters/filter-lang"},{"$ref":"http://schemas.opengis.net/ogcapi/features/part3/1.0/openapi/ogcapi-features-3.yaml#/components/parameters/filter-crs"},{"description":"The optional limit parameter limits the number of items that are presented in the response document.","explode":false,"in":"query","name":"limit","required":false,"schema":{"default":9,"maximum":15,"minimum":1,"type":"integer"},"style":"form"},{"description":"Optional list of properties by which to sort the items.","explode":false,"in":"query","name":"sortby","required":false,"schema":{"items":{"pattern":"[+|-]?[A-Za-z_].*","type":"string"},"minItems":1,"type":"array"},"style":"form"}],"responses":{"200":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/Features"},"400":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/InvalidParameter"},"500":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/ServerError"}},"summary":"Get Minnesota Major River Centerlines items","tags":["mn_major_rivers"]}},"/collections/mn_major_rivers/items/{featureId}":{"get":{"description":"This dataset represents stream centerlines for major rivers in Minnesota.","operationId":"getmn_major_riversFeature","parameters":[{"$ref":"#/components/parameters/f"},{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/parameters/featureId"}],"responses":{"200":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/Feature"},"400":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/InvalidParameter"},"404":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/NotFound"},"500":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/ServerError"}},"summary":"Get Minnesota Major River Centerlines item by id","tags":["mn_major_rivers"]}},"/collections/mn_major_rivers/queryables":{"get":{"description":"Get Minnesota Major River Centerlines queryables","operationId":"getmn_major_riversQueryables","parameters":[{"$ref":"#/components/parameters/f"},{"$ref":"#/components/parameters/vendorSpecificParameters"}],"responses":{"200":{"content":{"application/schema+json":{"schema":{"type":"object"}}},"description":"The queryable properties of the collection."},"400":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/InvalidParameter"},"500":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/ServerError"}},"summary":"Get Minnesota Major River Centerlines queryables","tags":["mn_major_rivers"]}},"/collections/mn_major_rivers/schema":{"get":{"description":"Get Minnesota Major River Centerlines schema","operationId":"getmn_major_riversSchema","parameters":[{"$ref":"#/components/parameters/f"},{"$ref":"#/components/parameters/vendorSpecificParameters"}],"responses":{"200":{"content":{"application/schema+json":{"schema":{"type":"object"}}},"description":"The returnable properties of the collection."},"400":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/InvalidParameter"},"500":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/ServerError"}},"summary":"Get Minnesota Major River Centerlines schema","tags":["mn_major_rivers"]}},"/collections/mn_major_rivers/sortables":{"get":{"description":"Get Minnesota Major River Centerlines sortables","operationId":"getmn_major_riversSortables","parameters":[{"$ref":"#/components/parameters/f"},{"$ref":"#/components/parameters/vendorSpecificParameters"}],"responses":{"200":{"content":{"application/schema+json":{"schema":{"type":"object"}}},"description":"The sortable properties of the collection."},"400":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/InvalidParameter"},"500":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/ServerError"}},"summary":"Get Minnesota Major River Centerlines sortables","tags":["mn_major_rivers"]}},"/collections/mn_population_centers":{"get":{"description":"This dataset contains cities, townships, reservations, county seats and unorganized Territories in Minnesota, represented with point geometry for cartographic purposes.","operationId":"describemn_population_centersCollection","parameters":[{"$ref":"#/components/parameters/f"}],"responses":{"200":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/Collection"},"400":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/InvalidParameter"},"500":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/ServerError"}},"summary":"Get Minnesota Population Centers metadata","tags":["mn_population_centers"]}},"/collections/mn_population_centers/items":{"get":{"description":"This dataset contains cities, townships, reservations, county seats and unorganized Territories in Minnesota, represented with point geometry for cartographic purposes.","operationId":"getmn_population_centersFeatures","parameters":[{"$ref":"#/components/parameters/f"},{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/parameters/bbox"},{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/parameters/datetime"},{"$ref":"http://schemas.opengis.net/ogcapi/features/part2/1.0/openapi/ogcapi-features-2.yaml#/components/parameters/bbox-crs"},{"$ref":"http://schemas.opengis.net/ogcapi/features/part2/1.0/openapi/ogcapi-features-2.yaml#/components/parameters/crs"},{"$ref":"#/components/parameters/offset"},{"$ref":"#/components/parameters/vendorSpecificParameters"},{"$ref":"http://schemas.opengis.net/ogcapi/features/part3/1.0/openapi/ogcapi-features-3.yaml#/components/parameters/filter"},{"$ref":"http://schemas.opengis.net/ogcapi/features/part3/1.0/openapi/ogcapi-features-3.yaml#/components/parameters/filter-lang"},{"$ref":"http://schemas.opengis.net/ogcapi/features/part3/1.0/openapi/ogcapi-features-3.yaml#/components/parameters/filter-crs"},{"description":"The optional limit parameter limits the number of items that are presented in the response document.","explode":false,"in":"query","name":"limit","required":false,"schema":{"default":9,"maximum":15,"minimum":1,"type":"integer"},"style":"form"},{"description":"Optional list of properties by which to sort the items.","explode":false,"in":"query","name":"sortby","required":false,"schema":{"items":{"pattern":"[+|-]?[A-Za-z_].*","type":"string"},"minItems":1,"type":"array"},"style":"form"}],"responses":{"200":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/Features"},"400":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/InvalidParameter"},"500":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/ServerError"}},"summary":"Get Minnesota Population Centers items","tags":["mn_population_centers"]}},"/collections/mn_population_centers/items/{featureId}":{"get":{"description":"This dataset contains cities, townships, reservations, county seats and unorganized Territories in Minnesota, represented with point geometry for cartographic purposes.","operationId":"getmn_population_centersFeature","parameters":[{"$ref":"#/components/parameters/f"},{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/parameters/featureId"}],"responses":{"200":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/Feature"},"400":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/InvalidParameter"},"404":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/NotFound"},"500":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/ServerError"}},"summary":"Get Minnesota Population Centers item by id","tags":["mn_population_centers"]}},"/collections/mn_population_centers/queryables":{"get":{"description":"Get Minnesota Population Centers queryables","operationId":"getmn_population_centersQueryables","parameters":[{"$ref":"#/components/parameters/f"},{"$ref":"#/components/parameters/vendorSpecificParameters"}],"responses":{"200":{"content":{"application/schema+json":{"schema":{"type":"object"}}},"description":"The queryable properties of the collection."},"400":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/InvalidParameter"},"500":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/ServerError"}},"summary":"Get Minnesota Population Centers queryables","tags":["mn_population_centers"]}},"/collections/mn_population_centers/schema":{"get":{"description":"Get Minnesota Population Centers schema","operationId":"getmn_population_centersSchema","parameters":[{"$ref":"#/components/parameters/f"},{"$ref":"#/components/parameters/vendorSpecificParameters"}],"responses":{"200":{"content":{"application/schema+json":{"schema":{"type":"object"}}},"description":"The returnable properties of the collection."},"400":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/InvalidParameter"},"500":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/ServerError"}},"summary":"Get Minnesota Population Centers schema","tags":["mn_population_centers"]}},"/collections/mn_population_centers/sortables":{"get":{"description":"Get Minnesota Population Centers sortables","operationId":"getmn_population_centersSortables","parameters":[{"$ref":"#/components/parameters/f"},{"$ref":"#/components/parameters/vendorSpecificParameters"}],"responses":{"200":{"content":{"application/schema+json":{"schema":{"type":"object"}}},"description":"The sortable properties of the collection."},"400":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/InvalidParameter"},"500":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/ServerError"}},"summary":"Get Minnesota Population Centers sortables","tags":["mn_population_centers"]}},"/conformance":{"get":{"description":"API conformance definition","operationId":"getConformanceDeclaration","parameters":[{"$ref":"#/components/parameters/f"}],"responses":{"200":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/ConformanceDeclaration"},"400":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/InvalidParameter"},"500":{"$ref":"http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/ServerError"}},"summary":"API conformance definition","tags":["server"]}}},"servers":[{"description":"Server description","url":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi"}],"tags":[]} diff --git a/msautotest/api/expected/ogcapi_api_unknown_parameter.json.txt b/msautotest/api/expected/ogcapi_api_unknown_parameter.json.txt new file mode 100644 index 0000000000..237dff26d3 --- /dev/null +++ b/msautotest/api/expected/ogcapi_api_unknown_parameter.json.txt @@ -0,0 +1,4 @@ +Content-Type: application/json +Status: 400 + +{"code":"InvalidParameterValue","description":"Unknown query parameter: unknown"} diff --git a/msautotest/api/expected/ogcapi_collection_unknown_parameter.json.txt b/msautotest/api/expected/ogcapi_collection_unknown_parameter.json.txt new file mode 100644 index 0000000000..237dff26d3 --- /dev/null +++ b/msautotest/api/expected/ogcapi_collection_unknown_parameter.json.txt @@ -0,0 +1,4 @@ +Content-Type: application/json +Status: 400 + +{"code":"InvalidParameterValue","description":"Unknown query parameter: unknown"} diff --git a/msautotest/api/expected/ogcapi_collections.json b/msautotest/api/expected/ogcapi_collections.json new file mode 100644 index 0000000000..01f1334fa9 --- /dev/null +++ b/msautotest/api/expected/ogcapi_collections.json @@ -0,0 +1 @@ +{"collections":[{"crs":["http://www.opengis.net/def/crs/OGC/1.3/CRS84","http://www.opengis.net/def/crs/EPSG/0/32615","http://www.opengis.net/def/crs/EPSG/0/4326"],"description":"This is the standard Minnesota State County Boundary dataset.","extent":{"spatial":{"bbox":[[-97.2699,43.4353,-89.3971,49.4046]],"crs":"http://www.opengis.net/def/crs/OGC/1.3/CRS84"}},"id":"mn_counties","itemType":"feature","keywords":["boundary","Minnesota","counties"],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties?f=json","rel":"self","title":"This collection as JSON","type":"application/json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties?f=html","rel":"alternate","title":"This collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json","rel":"items","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html","rel":"items","title":"Items for this collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/schema?f=json","rel":"http://www.opengis.net/def/rel/ogc/1.0/schema","title":"Schema for this collection as JSON schema","type":"application/schema+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/schema?f=html","rel":"http://www.opengis.net/def/rel/ogc/1.0/schema","title":"Schema for this collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/queryables?f=json","rel":"http://www.opengis.net/def/rel/ogc/1.0/queryables","title":"Queryables for this collection as JSON schema","type":"application/schema+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/queryables?f=html","rel":"http://www.opengis.net/def/rel/ogc/1.0/queryables","title":"Queryables for this collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/sortables?f=json","rel":"http://www.opengis.net/def/rel/ogc/1.0/sortables","title":"Sortables for this collection as JSON schema","type":"application/schema+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/sortables?f=html","rel":"http://www.opengis.net/def/rel/ogc/1.0/sortables","title":"Sortables for this collection as HTML","type":"text/html"},{"href":"https://gisdata.mn.gov/dataset/bdry-counties-in-minnesota","title":"Layer in Minnesota Geocommons","type":"text/html"}],"storageCrs":"http://www.opengis.net/def/crs/EPSG/0/32615","title":"State of Minnesota County Boundaries"},{"crs":["http://www.opengis.net/def/crs/OGC/1.3/CRS84","http://www.opengis.net/def/crs/EPSG/0/32615","http://www.opengis.net/def/crs/EPSG/0/4326"],"description":"This is the standard Minnesota State County Boundary dataset.","extent":{"spatial":{"bbox":[[-97.2699,43.4353,-89.3971,49.4046]],"crs":"http://www.opengis.net/def/crs/OGC/1.3/CRS84"}},"id":"mn_counties_no_queryables_and_sortables","itemType":"feature","keywords":["boundary","Minnesota","counties"],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties_no_queryables_and_sortables?f=json","rel":"self","title":"This collection as JSON","type":"application/json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties_no_queryables_and_sortables?f=html","rel":"alternate","title":"This collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties_no_queryables_and_sortables/items?f=json","rel":"items","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties_no_queryables_and_sortables/items?f=html","rel":"items","title":"Items for this collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties_no_queryables_and_sortables/schema?f=json","rel":"http://www.opengis.net/def/rel/ogc/1.0/schema","title":"Schema for this collection as JSON schema","type":"application/schema+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties_no_queryables_and_sortables/schema?f=html","rel":"http://www.opengis.net/def/rel/ogc/1.0/schema","title":"Schema for this collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties_no_queryables_and_sortables/queryables?f=json","rel":"http://www.opengis.net/def/rel/ogc/1.0/queryables","title":"Queryables for this collection as JSON schema","type":"application/schema+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties_no_queryables_and_sortables/queryables?f=html","rel":"http://www.opengis.net/def/rel/ogc/1.0/queryables","title":"Queryables for this collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties_no_queryables_and_sortables/sortables?f=json","rel":"http://www.opengis.net/def/rel/ogc/1.0/sortables","title":"Sortables for this collection as JSON schema","type":"application/schema+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties_no_queryables_and_sortables/sortables?f=html","rel":"http://www.opengis.net/def/rel/ogc/1.0/sortables","title":"Sortables for this collection as HTML","type":"text/html"},{"href":"https://gisdata.mn.gov/dataset/bdry-counties-in-minnesota","title":"Layer in Minnesota Geocommons","type":"text/html"}],"storageCrs":"http://www.opengis.net/def/crs/EPSG/0/32615","title":"State of Minnesota County Boundaries"},{"crs":["http://www.opengis.net/def/crs/OGC/1.3/CRS84","http://www.opengis.net/def/crs/EPSG/0/32615","http://www.opengis.net/def/crs/EPSG/0/4326"],"description":"This is the standard Minnesota State County Boundary dataset.","extent":{"spatial":{"bbox":[[-97.2699,43.4353,-89.3971,49.4046]],"crs":"http://www.opengis.net/def/crs/OGC/1.3/CRS84"}},"id":"mn_counties_all_queryables_and_sortables","itemType":"feature","keywords":["boundary","Minnesota","counties"],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties_all_queryables_and_sortables?f=json","rel":"self","title":"This collection as JSON","type":"application/json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties_all_queryables_and_sortables?f=html","rel":"alternate","title":"This collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties_all_queryables_and_sortables/items?f=json","rel":"items","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties_all_queryables_and_sortables/items?f=html","rel":"items","title":"Items for this collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties_all_queryables_and_sortables/schema?f=json","rel":"http://www.opengis.net/def/rel/ogc/1.0/schema","title":"Schema for this collection as JSON schema","type":"application/schema+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties_all_queryables_and_sortables/schema?f=html","rel":"http://www.opengis.net/def/rel/ogc/1.0/schema","title":"Schema for this collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties_all_queryables_and_sortables/queryables?f=json","rel":"http://www.opengis.net/def/rel/ogc/1.0/queryables","title":"Queryables for this collection as JSON schema","type":"application/schema+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties_all_queryables_and_sortables/queryables?f=html","rel":"http://www.opengis.net/def/rel/ogc/1.0/queryables","title":"Queryables for this collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties_all_queryables_and_sortables/sortables?f=json","rel":"http://www.opengis.net/def/rel/ogc/1.0/sortables","title":"Sortables for this collection as JSON schema","type":"application/schema+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties_all_queryables_and_sortables/sortables?f=html","rel":"http://www.opengis.net/def/rel/ogc/1.0/sortables","title":"Sortables for this collection as HTML","type":"text/html"},{"href":"https://gisdata.mn.gov/dataset/bdry-counties-in-minnesota","title":"Layer in Minnesota Geocommons","type":"text/html"}],"storageCrs":"http://www.opengis.net/def/crs/EPSG/0/32615","title":"State of Minnesota County Boundaries"},{"crs":["http://www.opengis.net/def/crs/OGC/1.3/CRS84","http://www.opengis.net/def/crs/EPSG/0/26915"],"description":"This dataset represents stream centerlines for major rivers in Minnesota.","extent":{"spatial":{"bbox":[[-97.2417,43.234,-90.5151,49.078]],"crs":"http://www.opengis.net/def/crs/OGC/1.3/CRS84"}},"id":"mn_major_rivers","itemType":"feature","keywords":["Minnesota","river","hydrography","centerline"],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_major_rivers?f=json","rel":"self","title":"This collection as JSON","type":"application/json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_major_rivers?f=html","rel":"alternate","title":"This collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_major_rivers/items?f=json","rel":"items","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_major_rivers/items?f=html","rel":"items","title":"Items for this collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_major_rivers/schema?f=json","rel":"http://www.opengis.net/def/rel/ogc/1.0/schema","title":"Schema for this collection as JSON schema","type":"application/schema+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_major_rivers/schema?f=html","rel":"http://www.opengis.net/def/rel/ogc/1.0/schema","title":"Schema for this collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_major_rivers/queryables?f=json","rel":"http://www.opengis.net/def/rel/ogc/1.0/queryables","title":"Queryables for this collection as JSON schema","type":"application/schema+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_major_rivers/queryables?f=html","rel":"http://www.opengis.net/def/rel/ogc/1.0/queryables","title":"Queryables for this collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_major_rivers/sortables?f=json","rel":"http://www.opengis.net/def/rel/ogc/1.0/sortables","title":"Sortables for this collection as JSON schema","type":"application/schema+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_major_rivers/sortables?f=html","rel":"http://www.opengis.net/def/rel/ogc/1.0/sortables","title":"Sortables for this collection as HTML","type":"text/html"},{"href":"https://gisdata.mn.gov/dataset/water-major-river-centerlines","title":"Layer in Minnesota Geocommons","type":"text/html"}],"storageCrs":"http://www.opengis.net/def/crs/EPSG/0/26915","title":"Minnesota Major River Centerlines"},{"crs":["http://www.opengis.net/def/crs/OGC/1.3/CRS84","http://www.opengis.net/def/crs/EPSG/0/26915"],"description":"This dataset contains cities, townships, reservations, county seats and unorganized Territories in Minnesota, represented with point geometry for cartographic purposes.","extent":{"spatial":{"bbox":[[-97.252,43.4391,-89.5948,49.3652]],"crs":"http://www.opengis.net/def/crs/OGC/1.3/CRS84"}},"id":"mn_population_centers","itemType":"feature","keywords":["Minnesota","cities","townships","reservations","county seats","unorganized territories"],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_population_centers?f=json","rel":"self","title":"This collection as JSON","type":"application/json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_population_centers?f=html","rel":"alternate","title":"This collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_population_centers/items?f=json","rel":"items","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_population_centers/items?f=html","rel":"items","title":"Items for this collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_population_centers/schema?f=json","rel":"http://www.opengis.net/def/rel/ogc/1.0/schema","title":"Schema for this collection as JSON schema","type":"application/schema+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_population_centers/schema?f=html","rel":"http://www.opengis.net/def/rel/ogc/1.0/schema","title":"Schema for this collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_population_centers/queryables?f=json","rel":"http://www.opengis.net/def/rel/ogc/1.0/queryables","title":"Queryables for this collection as JSON schema","type":"application/schema+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_population_centers/queryables?f=html","rel":"http://www.opengis.net/def/rel/ogc/1.0/queryables","title":"Queryables for this collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_population_centers/sortables?f=json","rel":"http://www.opengis.net/def/rel/ogc/1.0/sortables","title":"Sortables for this collection as JSON schema","type":"application/schema+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_population_centers/sortables?f=html","rel":"http://www.opengis.net/def/rel/ogc/1.0/sortables","title":"Sortables for this collection as HTML","type":"text/html"},{"href":"https://gisdata.mn.gov/dataset/loc-pop-centers","title":"Layer in Minnesota Geocommons","type":"text/html"}],"storageCrs":"http://www.opengis.net/def/crs/EPSG/0/26915","title":"Minnesota Population Centers"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections?f=json","rel":"self","title":"This document as JSON","type":"application/json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections?f=html","rel":"alternate","title":"This document as HTML","type":"text/html"}]} diff --git a/msautotest/api/expected/ogcapi_collections_items_unknown_parameter.json.txt b/msautotest/api/expected/ogcapi_collections_items_unknown_parameter.json.txt new file mode 100644 index 0000000000..237dff26d3 --- /dev/null +++ b/msautotest/api/expected/ogcapi_collections_items_unknown_parameter.json.txt @@ -0,0 +1,4 @@ +Content-Type: application/json +Status: 400 + +{"code":"InvalidParameterValue","description":"Unknown query parameter: unknown"} diff --git a/msautotest/api/expected/ogcapi_collections_mn_counties.html b/msautotest/api/expected/ogcapi_collections_mn_counties.html new file mode 100644 index 0000000000..87ab146cbc --- /dev/null +++ b/msautotest/api/expected/ogcapi_collections_mn_counties.html @@ -0,0 +1,88 @@ + + + + OGC API Test + + + + + +

OGC API Test - Collection: State of Minnesota County Boundaries

+ +

This is the standard Minnesota State County Boundary dataset.

+ +

Keywords

+
    + +
  • boundary
  • + +
  • Minnesota
  • + +
  • counties
  • + +
+ + + +

Storage CRS

+http://www.opengis.net/def/crs/EPSG/0/32615 + + + +

Supported CRS

+ + + +

Links

+ + + + +

Template Data

+

+ API Root: http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi
+ Path: ["ogcapi.map","ogcapi","collections","mn_counties"]
+ Params: {"f":"html"}
+ Extra Params:
+ Title: OGC API Test
+ Tags: {"debug":"true","sample":"sample tag"}
+

+ + + + + + + diff --git a/msautotest/api/expected/ogcapi_collections_mn_counties.json b/msautotest/api/expected/ogcapi_collections_mn_counties.json new file mode 100644 index 0000000000..dfa4608e37 --- /dev/null +++ b/msautotest/api/expected/ogcapi_collections_mn_counties.json @@ -0,0 +1 @@ +{"crs":["http://www.opengis.net/def/crs/OGC/1.3/CRS84","http://www.opengis.net/def/crs/EPSG/0/32615","http://www.opengis.net/def/crs/EPSG/0/4326"],"description":"This is the standard Minnesota State County Boundary dataset.","extent":{"spatial":{"bbox":[[-97.2699,43.4353,-89.3971,49.4046]],"crs":"http://www.opengis.net/def/crs/OGC/1.3/CRS84"}},"id":"mn_counties","itemType":"feature","keywords":["boundary","Minnesota","counties"],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties?f=json","rel":"self","title":"This collection as JSON","type":"application/json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties?f=html","rel":"alternate","title":"This collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json","rel":"items","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html","rel":"items","title":"Items for this collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/schema?f=json","rel":"http://www.opengis.net/def/rel/ogc/1.0/schema","title":"Schema for this collection as JSON schema","type":"application/schema+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/schema?f=html","rel":"http://www.opengis.net/def/rel/ogc/1.0/schema","title":"Schema for this collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/queryables?f=json","rel":"http://www.opengis.net/def/rel/ogc/1.0/queryables","title":"Queryables for this collection as JSON schema","type":"application/schema+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/queryables?f=html","rel":"http://www.opengis.net/def/rel/ogc/1.0/queryables","title":"Queryables for this collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/sortables?f=json","rel":"http://www.opengis.net/def/rel/ogc/1.0/sortables","title":"Sortables for this collection as JSON schema","type":"application/schema+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/sortables?f=html","rel":"http://www.opengis.net/def/rel/ogc/1.0/sortables","title":"Sortables for this collection as HTML","type":"text/html"},{"href":"https://gisdata.mn.gov/dataset/bdry-counties-in-minnesota","title":"Layer in Minnesota Geocommons","type":"text/html"}],"storageCrs":"http://www.opengis.net/def/crs/EPSG/0/32615","title":"State of Minnesota County Boundaries"} diff --git a/msautotest/api/expected/ogcapi_collections_mn_counties_items_bad_bbox_crs.json b/msautotest/api/expected/ogcapi_collections_mn_counties_items_bad_bbox_crs.json new file mode 100644 index 0000000000..6d3cd302e9 --- /dev/null +++ b/msautotest/api/expected/ogcapi_collections_mn_counties_items_bad_bbox_crs.json @@ -0,0 +1 @@ +{"code":"InvalidParameterValue","description":"Bad value for bbox-crs."} diff --git a/msautotest/api/expected/ogcapi_collections_mn_counties_items_bad_crs.json b/msautotest/api/expected/ogcapi_collections_mn_counties_items_bad_crs.json new file mode 100644 index 0000000000..bfd08349ab --- /dev/null +++ b/msautotest/api/expected/ogcapi_collections_mn_counties_items_bad_crs.json @@ -0,0 +1 @@ +{"code":"InvalidParameterValue","description":"Bad value for crs."} diff --git a/msautotest/api/expected/ogcapi_collections_mn_counties_items_bbox_crs.json b/msautotest/api/expected/ogcapi_collections_mn_counties_items_bbox_crs.json new file mode 100644 index 0000000000..4b4fb2618b --- /dev/null +++ b/msautotest/api/expected/ogcapi_collections_mn_counties_items_bbox_crs.json @@ -0,0 +1 @@ +{"features":[{"geometry":{"coordinates":[[[-95.3231,48.999],[-95.3109,48.999],[-95.2889,48.9989],[-95.2852,48.9989],[-95.2669,48.9989],[-95.245,48.9989],[-95.2232,48.9989],[-95.2014,48.9989],[-95.1792,48.9989],[-95.1574,48.9989],[-95.1531,48.9989],[-95.1531,49.0031],[-95.1532,49.0179],[-95.1532,49.0325],[-95.1532,49.047],[-95.1532,49.0619],[-95.1532,49.0765],[-95.1532,49.0911],[-95.1532,49.1057],[-95.1532,49.1205],[-95.1532,49.1354],[-95.1532,49.1499],[-95.1532,49.1642],[-95.1532,49.1788],[-95.1532,49.1807],[-95.1532,49.1931],[-95.1532,49.1966],[-95.1532,49.2077],[-95.1533,49.2131],[-95.1533,49.2219],[-95.1533,49.2308],[-95.1533,49.2365],[-95.1533,49.2472],[-95.1533,49.2512],[-95.1533,49.2655],[-95.1533,49.2697],[-95.1533,49.2802],[-95.1533,49.2882],[-95.1533,49.2945],[-95.1533,49.3072],[-95.1533,49.309],[-95.1533,49.3234],[-95.1533,49.3237],[-95.1533,49.3381],[-95.1533,49.3476],[-95.1533,49.3525],[-95.1533,49.3636],[-95.1533,49.367],[-95.1533,49.3705],[-95.1533,49.3776],[-95.1533,49.3813],[-95.1533,49.3845],[-95.1503,49.383],[-95.1499,49.3813],[-95.1498,49.3807],[-95.1467,49.3802],[-95.145,49.3784],[-95.1418,49.3784],[-95.1397,49.3762],[-95.1367,49.3751],[-95.1324,49.3736],[-95.1287,49.3705],[-95.1171,49.367],[-95.1159,49.3666],[-95.1145,49.3666],[-95.1098,49.3664],[-95.1031,49.3652],[-95.1031,49.3636],[-95.0926,49.3617],[-95.0897,49.3612],[-95.0707,49.3564],[-95.0582,49.3533],[-95.0495,49.3532],[-95.0479,49.3533],[-95.0262,49.3554],[-95.0141,49.3565],[-95.0047,49.3612],[-94.993,49.367],[-94.9889,49.369],[-94.9818,49.3684],[-94.9742,49.3678],[-94.9597,49.3699],[-94.9573,49.3702],[-94.952,49.3688],[-94.948,49.367],[-94.9376,49.3625],[-94.9152,49.3529],[-94.9143,49.3524],[-94.909,49.3502],[-94.9065,49.3484],[-94.8933,49.3414],[-94.8865,49.3378],[-94.8782,49.3334],[-94.8712,49.3308],[-94.854,49.3244],[-94.8492,49.3244],[-94.8363,49.3243],[-94.8311,49.3236],[-94.8271,49.323],[-94.8162,49.3214],[-94.8243,49.309],[-94.8243,49.3088],[-94.8255,49.2944],[-94.8255,49.2943],[-94.8204,49.28],[-94.8152,49.2653],[-94.8103,49.2515],[-94.8059,49.2388],[-94.8051,49.2367],[-94.8001,49.2224],[-94.7973,49.2144],[-94.7975,49.2079],[-94.7979,49.1979],[-94.7965,49.1936],[-94.7918,49.1792],[-94.7871,49.1646],[-94.7833,49.153],[-94.7823,49.15],[-94.7776,49.1357],[-94.7727,49.1206],[-94.7727,49.1206],[-94.7611,49.1096],[-94.7571,49.1058],[-94.7496,49.0988],[-94.7474,49.0918],[-94.7429,49.0773],[-94.7394,49.0657],[-94.7385,49.063],[-94.7344,49.0497],[-94.7299,49.0351],[-94.7254,49.0205],[-94.7207,49.0052],[-94.7184,48.9979],[-94.7162,48.9907],[-94.7117,48.9761],[-94.7072,48.9615],[-94.7027,48.9468],[-94.6982,48.9322],[-94.6968,48.9276],[-94.6844,48.8875],[-94.6834,48.8842],[-94.6842,48.8724],[-94.6855,48.8719],[-94.6923,48.8691],[-94.6902,48.8636],[-94.6914,48.8591],[-94.693,48.8535],[-94.6881,48.8447],[-94.6855,48.8401],[-94.6963,48.836],[-94.6975,48.8355],[-94.702,48.8319],[-94.7025,48.8302],[-94.7042,48.8243],[-94.6991,48.8159],[-94.6962,48.8111],[-94.6951,48.8092],[-94.6958,48.8012],[-94.6959,48.7997],[-94.6944,48.7895],[-94.6934,48.7864],[-94.6909,48.7781],[-94.687,48.7752],[-94.6776,48.772],[-94.6768,48.7717],[-94.6746,48.7705],[-94.6671,48.7662],[-94.6603,48.7605],[-94.6557,48.7581],[-94.6525,48.7565],[-94.652,48.7562],[-94.6453,48.7491],[-94.6453,48.7441],[-94.6443,48.7434],[-94.6414,48.7413],[-94.631,48.7392],[-94.6301,48.739],[-94.6191,48.7373],[-94.6106,48.7318],[-94.6084,48.731],[-94.6028,48.7289],[-94.6011,48.7283],[-94.5962,48.7248],[-94.5913,48.7197],[-94.5876,48.7176],[-94.5867,48.7175],[-94.5685,48.7156],[-94.5622,48.7159],[-94.5558,48.7163],[-94.549,48.7148],[-94.5487,48.7146],[-94.5457,48.7124],[-94.5396,48.7036],[-94.539,48.7028],[-94.5329,48.7013],[-94.5247,48.7016],[-94.5178,48.7008],[-94.5173,48.7008],[-94.5093,48.7006],[-94.5066,48.6999],[-94.4996,48.698],[-94.4958,48.698],[-94.4863,48.698],[-94.4739,48.6969],[-94.4706,48.6966],[-94.4631,48.6953],[-94.4568,48.6933],[-94.4523,48.6925],[-94.4517,48.6925],[-94.4465,48.693],[-94.4388,48.6949],[-94.4319,48.6998],[-94.4299,48.7012],[-94.4299,48.6998],[-94.43,48.6852],[-94.4301,48.6708],[-94.43,48.6564],[-94.4297,48.642],[-94.4294,48.6276],[-94.4292,48.6133],[-94.4289,48.5988],[-94.4289,48.5844],[-94.4291,48.5698],[-94.4295,48.5554],[-94.43,48.5409],[-94.4303,48.5264],[-94.4303,48.512],[-94.4299,48.4977],[-94.4296,48.4832],[-94.4296,48.4688],[-94.4293,48.4543],[-94.4292,48.4399],[-94.4293,48.4254],[-94.4294,48.411],[-94.4293,48.3964],[-94.4289,48.3821],[-94.4288,48.3675],[-94.4471,48.3675],[-94.4505,48.3675],[-94.4688,48.3675],[-94.4722,48.3674],[-94.4906,48.3674],[-94.4924,48.3674],[-94.4941,48.3674],[-94.5118,48.3675],[-94.5157,48.3674],[-94.5335,48.3674],[-94.5378,48.3674],[-94.5536,48.3674],[-94.5593,48.3674],[-94.5754,48.3674],[-94.5812,48.3674],[-94.5971,48.3675],[-94.6029,48.3674],[-94.6188,48.3673],[-94.6245,48.3673],[-94.6405,48.3673],[-94.6465,48.3673],[-94.6505,48.3673],[-94.6622,48.3673],[-94.6679,48.3673],[-94.6694,48.3672],[-94.683,48.3671],[-94.6898,48.3671],[-94.7099,48.3669],[-94.7117,48.3668],[-94.7315,48.3669],[-94.7329,48.3669],[-94.7533,48.3669],[-94.7549,48.3669],[-94.7748,48.3669],[-94.7765,48.3669],[-94.7967,48.3669],[-94.7983,48.3669],[-94.8183,48.3669],[-94.8199,48.3669],[-94.8399,48.3669],[-94.8416,48.3669],[-94.8616,48.3667],[-94.8632,48.3667],[-94.8833,48.3667],[-94.8849,48.3666],[-94.9049,48.3666],[-94.9065,48.3666],[-94.9264,48.3667],[-94.9283,48.3667],[-94.9469,48.3666],[-94.95,48.3666],[-94.9684,48.3667],[-94.9716,48.3667],[-94.9901,48.3667],[-94.9932,48.3667],[-95.0119,48.3665],[-95.0153,48.3665],[-95.0337,48.3665],[-95.0369,48.3665],[-95.0555,48.3665],[-95.0586,48.3665],[-95.0773,48.3664],[-95.0801,48.3664],[-95.099,48.3663],[-95.1008,48.3663],[-95.1018,48.3663],[-95.1207,48.3663],[-95.1236,48.3663],[-95.1315,48.3662],[-95.1424,48.3662],[-95.1454,48.3662],[-95.164,48.3661],[-95.1669,48.3661],[-95.1861,48.3661],[-95.1887,48.3661],[-95.1983,48.3661],[-95.2066,48.3661],[-95.2106,48.3661],[-95.211,48.3797],[-95.211,48.3808],[-95.2111,48.3941],[-95.2111,48.3952],[-95.2112,48.4087],[-95.2112,48.4096],[-95.2113,48.4232],[-95.2113,48.4242],[-95.2113,48.4255],[-95.2113,48.4376],[-95.2113,48.4387],[-95.2113,48.4522],[-95.2112,48.4529],[-95.211,48.4666],[-95.211,48.4673],[-95.2111,48.4816],[-95.2112,48.4962],[-95.2111,48.5101],[-95.2111,48.5109],[-95.2115,48.5244],[-95.2115,48.5252],[-95.2119,48.54],[-95.2324,48.5399],[-95.2339,48.5399],[-95.2537,48.5398],[-95.2554,48.5398],[-95.2756,48.54],[-95.2773,48.54],[-95.2975,48.5401],[-95.2992,48.5402],[-95.3194,48.54],[-95.321,48.54],[-95.3412,48.5402],[-95.3425,48.5402],[-95.3424,48.5548],[-95.3423,48.5691],[-95.3423,48.5836],[-95.3426,48.5979],[-95.3424,48.6127],[-95.3426,48.6271],[-95.3425,48.6415],[-95.3424,48.6561],[-95.3423,48.6705],[-95.3424,48.6849],[-95.3425,48.6995],[-95.3425,48.7131],[-95.3302,48.713],[-95.3205,48.713],[-95.3084,48.713],[-95.3051,48.713],[-95.299,48.713],[-95.2866,48.713],[-95.2767,48.713],[-95.2656,48.713],[-95.2645,48.713],[-95.255,48.713],[-95.2427,48.713],[-95.2331,48.713],[-95.2206,48.713],[-95.2112,48.713],[-95.1991,48.713],[-95.1917,48.713],[-95.1773,48.713],[-95.1697,48.7129],[-95.1554,48.7129],[-95.1477,48.7129],[-95.1333,48.713],[-95.1297,48.713],[-95.1259,48.7129],[-95.1119,48.7129],[-95.1104,48.7129],[-95.1046,48.7129],[-95.0898,48.713],[-95.0899,48.7277],[-95.0901,48.7421],[-95.0901,48.7566],[-95.0903,48.7711],[-95.0903,48.7855],[-95.0903,48.8],[-95.0909,48.8147],[-95.0908,48.8291],[-95.0907,48.8436],[-95.0908,48.858],[-95.0908,48.8724],[-95.0911,48.8869],[-95.0912,48.9014],[-95.0914,48.916],[-95.0914,48.9208],[-95.0919,48.9207],[-95.0927,48.9204],[-95.0944,48.9193],[-95.0946,48.9191],[-95.0961,48.9181],[-95.097,48.9176],[-95.0971,48.9172],[-95.0975,48.9164],[-95.098,48.916],[-95.0981,48.9159],[-95.1008,48.9142],[-95.102,48.9132],[-95.1032,48.9127],[-95.1042,48.9121],[-95.1056,48.9113],[-95.108,48.9099],[-95.1096,48.9089],[-95.1107,48.9082],[-95.1126,48.9073],[-95.113,48.9072],[-95.1132,48.9071],[-95.1137,48.9069],[-95.1141,48.9064],[-95.114,48.9061],[-95.1144,48.9052],[-95.1151,48.9046],[-95.1163,48.9037],[-95.1182,48.9029],[-95.1204,48.9019],[-95.1205,48.9017],[-95.121,48.9016],[-95.1214,48.9013],[-95.1228,48.9006],[-95.1233,48.9004],[-95.1239,48.9001],[-95.1252,48.8998],[-95.1312,48.8975],[-95.1322,48.8973],[-95.1337,48.8969],[-95.1343,48.8963],[-95.1348,48.8963],[-95.1351,48.8963],[-95.1355,48.8959],[-95.1381,48.8949],[-95.1404,48.8943],[-95.1436,48.8937],[-95.1438,48.8934],[-95.1459,48.8929],[-95.1469,48.8927],[-95.1483,48.8923],[-95.1508,48.8922],[-95.1528,48.8921],[-95.1555,48.892],[-95.1564,48.8919],[-95.1579,48.8919],[-95.1602,48.892],[-95.1618,48.892],[-95.1641,48.8917],[-95.1648,48.8913],[-95.1674,48.8907],[-95.1701,48.8902],[-95.173,48.8897],[-95.1764,48.8893],[-95.1791,48.889],[-95.1797,48.889],[-95.1819,48.8888],[-95.1851,48.8882],[-95.1863,48.8877],[-95.1877,48.8874],[-95.1889,48.8873],[-95.1901,48.887],[-95.1913,48.8868],[-95.1919,48.8866],[-95.1924,48.8865],[-95.1956,48.8862],[-95.1986,48.8855],[-95.2005,48.8856],[-95.2009,48.8855],[-95.2024,48.8852],[-95.2059,48.8848],[-95.2085,48.8846],[-95.2112,48.8848],[-95.2115,48.8847],[-95.2117,48.8847],[-95.2122,48.8842],[-95.2144,48.8843],[-95.2151,48.884],[-95.2159,48.8839],[-95.217,48.8835],[-95.2188,48.8835],[-95.2193,48.8832],[-95.22,48.8831],[-95.2207,48.8831],[-95.2208,48.8831],[-95.2212,48.883],[-95.2252,48.8819],[-95.2265,48.8816],[-95.2287,48.8815],[-95.231,48.8814],[-95.2335,48.8814],[-95.2356,48.8815],[-95.2381,48.8817],[-95.2391,48.8819],[-95.2407,48.8821],[-95.2423,48.8821],[-95.2429,48.8822],[-95.2429,48.8822],[-95.2439,48.8823],[-95.2458,48.8829],[-95.2472,48.8835],[-95.248,48.8836],[-95.2485,48.8832],[-95.2496,48.8834],[-95.2502,48.8835],[-95.2507,48.8836],[-95.2517,48.8839],[-95.2548,48.8845],[-95.256,48.885],[-95.257,48.8858],[-95.2585,48.8867],[-95.2585,48.8867],[-95.2627,48.8877],[-95.2635,48.888],[-95.2639,48.8883],[-95.2646,48.8885],[-95.265,48.8886],[-95.2654,48.8888],[-95.2666,48.8894],[-95.2674,48.89],[-95.2677,48.8903],[-95.268,48.8905],[-95.2713,48.8915],[-95.2724,48.8921],[-95.2745,48.8931],[-95.2751,48.8938],[-95.2753,48.8943],[-95.2748,48.8951],[-95.2749,48.8956],[-95.2755,48.8959],[-95.2759,48.8962],[-95.2763,48.8963],[-95.2765,48.8962],[-95.277,48.8958],[-95.2773,48.8957],[-95.2782,48.8956],[-95.279,48.8957],[-95.2796,48.8962],[-95.2803,48.8965],[-95.2813,48.8967],[-95.2839,48.8975],[-95.2853,48.8977],[-95.2861,48.8976],[-95.2865,48.8975],[-95.287,48.8976],[-95.2872,48.8977],[-95.2879,48.8979],[-95.2882,48.8981],[-95.289,48.8994],[-95.2896,48.9],[-95.2901,48.9003],[-95.2911,48.9006],[-95.2911,48.9008],[-95.2906,48.9011],[-95.2907,48.9014],[-95.2908,48.9016],[-95.2909,48.9017],[-95.2914,48.9019],[-95.2927,48.9019],[-95.2935,48.902],[-95.2937,48.9023],[-95.2941,48.9027],[-95.2949,48.9028],[-95.2967,48.9027],[-95.2976,48.9026],[-95.298,48.9027],[-95.2983,48.9028],[-95.2993,48.9035],[-95.3005,48.904],[-95.3002,48.9045],[-95.3001,48.9046],[-95.3001,48.9047],[-95.3,48.9047],[-95.3,48.9047],[-95.2999,48.9048],[-95.2999,48.9048],[-95.2999,48.9048],[-95.2997,48.905],[-95.2996,48.9051],[-95.2994,48.9053],[-95.2992,48.9055],[-95.2991,48.9057],[-95.2989,48.906],[-95.2988,48.906],[-95.2986,48.9063],[-95.2985,48.9064],[-95.2985,48.9065],[-95.2983,48.9068],[-95.2982,48.9068],[-95.2981,48.907],[-95.298,48.9071],[-95.298,48.9071],[-95.298,48.9071],[-95.2979,48.9071],[-95.2979,48.9072],[-95.2979,48.9072],[-95.2978,48.9072],[-95.2978,48.9072],[-95.2978,48.9073],[-95.2977,48.9073],[-95.2976,48.9074],[-95.2973,48.9077],[-95.2973,48.908],[-95.2973,48.9081],[-95.2978,48.9083],[-95.2999,48.9086],[-95.3017,48.9093],[-95.3027,48.91],[-95.3038,48.9114],[-95.3043,48.9119],[-95.3059,48.9127],[-95.3061,48.9128],[-95.3064,48.9129],[-95.3074,48.9135],[-95.3078,48.9141],[-95.3085,48.9146],[-95.3092,48.9149],[-95.3093,48.9149],[-95.3102,48.9155],[-95.3109,48.9163],[-95.3115,48.9172],[-95.3119,48.9178],[-95.3126,48.919],[-95.3132,48.9198],[-95.3141,48.921],[-95.315,48.9222],[-95.3168,48.9245],[-95.3195,48.9285],[-95.3208,48.9305],[-95.3209,48.9307],[-95.3222,48.9327],[-95.3228,48.9344],[-95.3223,48.9355],[-95.3225,48.9358],[-95.3229,48.9373],[-95.3231,48.9389],[-95.3228,48.9403],[-95.3225,48.9409],[-95.3219,48.9412],[-95.3189,48.9419],[-95.3181,48.9421],[-95.3168,48.9431],[-95.3154,48.9448],[-95.3148,48.9452],[-95.3141,48.9457],[-95.3131,48.946],[-95.3114,48.9461],[-95.3102,48.9463],[-95.3095,48.9463],[-95.3088,48.9464],[-95.3086,48.9465],[-95.3086,48.9469],[-95.3085,48.947],[-95.3078,48.9466],[-95.3074,48.9465],[-95.3071,48.9466],[-95.3071,48.9469],[-95.3079,48.9474],[-95.3092,48.9477],[-95.3096,48.9478],[-95.3103,48.948],[-95.3104,48.9484],[-95.3103,48.9485],[-95.31,48.9485],[-95.3099,48.9484],[-95.3096,48.9482],[-95.3094,48.9481],[-95.3081,48.948],[-95.3071,48.9477],[-95.3062,48.9472],[-95.3062,48.9472],[-95.3061,48.9469],[-95.3062,48.9463],[-95.3063,48.9462],[-95.3069,48.9456],[-95.3069,48.9455],[-95.3068,48.9454],[-95.3061,48.9454],[-95.3053,48.9459],[-95.305,48.9462],[-95.3046,48.947],[-95.3046,48.9482],[-95.3052,48.9495],[-95.3061,48.9502],[-95.3079,48.9509],[-95.3089,48.9511],[-95.3097,48.951],[-95.3104,48.951],[-95.3108,48.9512],[-95.3115,48.952],[-95.312,48.9524],[-95.3126,48.9524],[-95.3129,48.9523],[-95.3129,48.9521],[-95.3119,48.9507],[-95.3119,48.9502],[-95.3123,48.9502],[-95.3125,48.9503],[-95.3131,48.9503],[-95.3141,48.9508],[-95.3151,48.951],[-95.3154,48.9513],[-95.3177,48.9525],[-95.3181,48.9531],[-95.3182,48.9535],[-95.3177,48.9545],[-95.3175,48.9552],[-95.3179,48.9559],[-95.3188,48.9562],[-95.3191,48.9569],[-95.3202,48.9581],[-95.3206,48.959],[-95.3206,48.9595],[-95.3206,48.9598],[-95.3202,48.9606],[-95.3193,48.9622],[-95.3193,48.964],[-95.3198,48.9643],[-95.3201,48.9648],[-95.3207,48.9669],[-95.3212,48.9672],[-95.3227,48.9685],[-95.3232,48.9692],[-95.3241,48.9703],[-95.3247,48.972],[-95.3248,48.9728],[-95.3249,48.9738],[-95.325,48.9743],[-95.3253,48.976],[-95.3257,48.9784],[-95.3255,48.9789],[-95.3256,48.98],[-95.3257,48.9814],[-95.3253,48.9832],[-95.3245,48.985],[-95.3242,48.9859],[-95.3227,48.9884],[-95.3224,48.9889],[-95.3206,48.9921],[-95.3204,48.9924],[-95.3191,48.9941],[-95.3181,48.995],[-95.3178,48.9958],[-95.3178,48.9961],[-95.3179,48.9961],[-95.3182,48.996],[-95.3187,48.9956],[-95.3191,48.9953],[-95.3197,48.9954],[-95.3201,48.9956],[-95.3206,48.9961],[-95.3204,48.9964],[-95.3202,48.9973],[-95.3204,48.9976],[-95.3224,48.9984],[-95.3231,48.999]]],"type":"Polygon"},"id":"39","properties":{"Area":4608320923.49768,"CTYONLY_":2,"Code":"LOTW","LASTMOD":"1976-07-04T12:00:00Z","Name":"Lake of the Woods","Perimiter":388250.14572},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=1&offset=0&bbox=190012.242200,4816648.737800,762254.477900,5472427.737000&bbox-crs=http://www.opengis.net/def/crs/EPSG/0/32615","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=1&offset=0&bbox=190012.242200,4816648.737800,762254.477900,5472427.737000&bbox-crs=http://www.opengis.net/def/crs/EPSG/0/32615","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=1&offset=1&bbox=190012.242200,4816648.737800,762254.477900,5472427.737000&bbox-crs=http://www.opengis.net/def/crs/EPSG/0/32615","rel":"next","title":"next page","type":"application/geo+json"}],"numberMatched":117,"numberReturned":1,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_collections_mn_counties_items_bbox_crs_epsg_4326.json b/msautotest/api/expected/ogcapi_collections_mn_counties_items_bbox_crs_epsg_4326.json new file mode 100644 index 0000000000..29b3f6de07 --- /dev/null +++ b/msautotest/api/expected/ogcapi_collections_mn_counties_items_bbox_crs_epsg_4326.json @@ -0,0 +1 @@ +{"features":[{"geometry":{"coordinates":[[[-95.3231,48.999],[-95.3109,48.999],[-95.2889,48.9989],[-95.2852,48.9989],[-95.2669,48.9989],[-95.245,48.9989],[-95.2232,48.9989],[-95.2014,48.9989],[-95.1792,48.9989],[-95.1574,48.9989],[-95.1531,48.9989],[-95.1531,49.0031],[-95.1532,49.0179],[-95.1532,49.0325],[-95.1532,49.047],[-95.1532,49.0619],[-95.1532,49.0765],[-95.1532,49.0911],[-95.1532,49.1057],[-95.1532,49.1205],[-95.1532,49.1354],[-95.1532,49.1499],[-95.1532,49.1642],[-95.1532,49.1788],[-95.1532,49.1807],[-95.1532,49.1931],[-95.1532,49.1966],[-95.1532,49.2077],[-95.1533,49.2131],[-95.1533,49.2219],[-95.1533,49.2308],[-95.1533,49.2365],[-95.1533,49.2472],[-95.1533,49.2512],[-95.1533,49.2655],[-95.1533,49.2697],[-95.1533,49.2802],[-95.1533,49.2882],[-95.1533,49.2945],[-95.1533,49.3072],[-95.1533,49.309],[-95.1533,49.3234],[-95.1533,49.3237],[-95.1533,49.3381],[-95.1533,49.3476],[-95.1533,49.3525],[-95.1533,49.3636],[-95.1533,49.367],[-95.1533,49.3705],[-95.1533,49.3776],[-95.1533,49.3813],[-95.1533,49.3845],[-95.1503,49.383],[-95.1499,49.3813],[-95.1498,49.3807],[-95.1467,49.3802],[-95.145,49.3784],[-95.1418,49.3784],[-95.1397,49.3762],[-95.1367,49.3751],[-95.1324,49.3736],[-95.1287,49.3705],[-95.1171,49.367],[-95.1159,49.3666],[-95.1145,49.3666],[-95.1098,49.3664],[-95.1031,49.3652],[-95.1031,49.3636],[-95.0926,49.3617],[-95.0897,49.3612],[-95.0707,49.3564],[-95.0582,49.3533],[-95.0495,49.3532],[-95.0479,49.3533],[-95.0262,49.3554],[-95.0141,49.3565],[-95.0047,49.3612],[-94.993,49.367],[-94.9889,49.369],[-94.9818,49.3684],[-94.9742,49.3678],[-94.9597,49.3699],[-94.9573,49.3702],[-94.952,49.3688],[-94.948,49.367],[-94.9376,49.3625],[-94.9152,49.3529],[-94.9143,49.3524],[-94.909,49.3502],[-94.9065,49.3484],[-94.8933,49.3414],[-94.8865,49.3378],[-94.8782,49.3334],[-94.8712,49.3308],[-94.854,49.3244],[-94.8492,49.3244],[-94.8363,49.3243],[-94.8311,49.3236],[-94.8271,49.323],[-94.8162,49.3214],[-94.8243,49.309],[-94.8243,49.3088],[-94.8255,49.2944],[-94.8255,49.2943],[-94.8204,49.28],[-94.8152,49.2653],[-94.8103,49.2515],[-94.8059,49.2388],[-94.8051,49.2367],[-94.8001,49.2224],[-94.7973,49.2144],[-94.7975,49.2079],[-94.7979,49.1979],[-94.7965,49.1936],[-94.7918,49.1792],[-94.7871,49.1646],[-94.7833,49.153],[-94.7823,49.15],[-94.7776,49.1357],[-94.7727,49.1206],[-94.7727,49.1206],[-94.7611,49.1096],[-94.7571,49.1058],[-94.7496,49.0988],[-94.7474,49.0918],[-94.7429,49.0773],[-94.7394,49.0657],[-94.7385,49.063],[-94.7344,49.0497],[-94.7299,49.0351],[-94.7254,49.0205],[-94.7207,49.0052],[-94.7184,48.9979],[-94.7162,48.9907],[-94.7117,48.9761],[-94.7072,48.9615],[-94.7027,48.9468],[-94.6982,48.9322],[-94.6968,48.9276],[-94.6844,48.8875],[-94.6834,48.8842],[-94.6842,48.8724],[-94.6855,48.8719],[-94.6923,48.8691],[-94.6902,48.8636],[-94.6914,48.8591],[-94.693,48.8535],[-94.6881,48.8447],[-94.6855,48.8401],[-94.6963,48.836],[-94.6975,48.8355],[-94.702,48.8319],[-94.7025,48.8302],[-94.7042,48.8243],[-94.6991,48.8159],[-94.6962,48.8111],[-94.6951,48.8092],[-94.6958,48.8012],[-94.6959,48.7997],[-94.6944,48.7895],[-94.6934,48.7864],[-94.6909,48.7781],[-94.687,48.7752],[-94.6776,48.772],[-94.6768,48.7717],[-94.6746,48.7705],[-94.6671,48.7662],[-94.6603,48.7605],[-94.6557,48.7581],[-94.6525,48.7565],[-94.652,48.7562],[-94.6453,48.7491],[-94.6453,48.7441],[-94.6443,48.7434],[-94.6414,48.7413],[-94.631,48.7392],[-94.6301,48.739],[-94.6191,48.7373],[-94.6106,48.7318],[-94.6084,48.731],[-94.6028,48.7289],[-94.6011,48.7283],[-94.5962,48.7248],[-94.5913,48.7197],[-94.5876,48.7176],[-94.5867,48.7175],[-94.5685,48.7156],[-94.5622,48.7159],[-94.5558,48.7163],[-94.549,48.7148],[-94.5487,48.7146],[-94.5457,48.7124],[-94.5396,48.7036],[-94.539,48.7028],[-94.5329,48.7013],[-94.5247,48.7016],[-94.5178,48.7008],[-94.5173,48.7008],[-94.5093,48.7006],[-94.5066,48.6999],[-94.4996,48.698],[-94.4958,48.698],[-94.4863,48.698],[-94.4739,48.6969],[-94.4706,48.6966],[-94.4631,48.6953],[-94.4568,48.6933],[-94.4523,48.6925],[-94.4517,48.6925],[-94.4465,48.693],[-94.4388,48.6949],[-94.4319,48.6998],[-94.4299,48.7012],[-94.4299,48.6998],[-94.43,48.6852],[-94.4301,48.6708],[-94.43,48.6564],[-94.4297,48.642],[-94.4294,48.6276],[-94.4292,48.6133],[-94.4289,48.5988],[-94.4289,48.5844],[-94.4291,48.5698],[-94.4295,48.5554],[-94.43,48.5409],[-94.4303,48.5264],[-94.4303,48.512],[-94.4299,48.4977],[-94.4296,48.4832],[-94.4296,48.4688],[-94.4293,48.4543],[-94.4292,48.4399],[-94.4293,48.4254],[-94.4294,48.411],[-94.4293,48.3964],[-94.4289,48.3821],[-94.4288,48.3675],[-94.4471,48.3675],[-94.4505,48.3675],[-94.4688,48.3675],[-94.4722,48.3674],[-94.4906,48.3674],[-94.4924,48.3674],[-94.4941,48.3674],[-94.5118,48.3675],[-94.5157,48.3674],[-94.5335,48.3674],[-94.5378,48.3674],[-94.5536,48.3674],[-94.5593,48.3674],[-94.5754,48.3674],[-94.5812,48.3674],[-94.5971,48.3675],[-94.6029,48.3674],[-94.6188,48.3673],[-94.6245,48.3673],[-94.6405,48.3673],[-94.6465,48.3673],[-94.6505,48.3673],[-94.6622,48.3673],[-94.6679,48.3673],[-94.6694,48.3672],[-94.683,48.3671],[-94.6898,48.3671],[-94.7099,48.3669],[-94.7117,48.3668],[-94.7315,48.3669],[-94.7329,48.3669],[-94.7533,48.3669],[-94.7549,48.3669],[-94.7748,48.3669],[-94.7765,48.3669],[-94.7967,48.3669],[-94.7983,48.3669],[-94.8183,48.3669],[-94.8199,48.3669],[-94.8399,48.3669],[-94.8416,48.3669],[-94.8616,48.3667],[-94.8632,48.3667],[-94.8833,48.3667],[-94.8849,48.3666],[-94.9049,48.3666],[-94.9065,48.3666],[-94.9264,48.3667],[-94.9283,48.3667],[-94.9469,48.3666],[-94.95,48.3666],[-94.9684,48.3667],[-94.9716,48.3667],[-94.9901,48.3667],[-94.9932,48.3667],[-95.0119,48.3665],[-95.0153,48.3665],[-95.0337,48.3665],[-95.0369,48.3665],[-95.0555,48.3665],[-95.0586,48.3665],[-95.0773,48.3664],[-95.0801,48.3664],[-95.099,48.3663],[-95.1008,48.3663],[-95.1018,48.3663],[-95.1207,48.3663],[-95.1236,48.3663],[-95.1315,48.3662],[-95.1424,48.3662],[-95.1454,48.3662],[-95.164,48.3661],[-95.1669,48.3661],[-95.1861,48.3661],[-95.1887,48.3661],[-95.1983,48.3661],[-95.2066,48.3661],[-95.2106,48.3661],[-95.211,48.3797],[-95.211,48.3808],[-95.2111,48.3941],[-95.2111,48.3952],[-95.2112,48.4087],[-95.2112,48.4096],[-95.2113,48.4232],[-95.2113,48.4242],[-95.2113,48.4255],[-95.2113,48.4376],[-95.2113,48.4387],[-95.2113,48.4522],[-95.2112,48.4529],[-95.211,48.4666],[-95.211,48.4673],[-95.2111,48.4816],[-95.2112,48.4962],[-95.2111,48.5101],[-95.2111,48.5109],[-95.2115,48.5244],[-95.2115,48.5252],[-95.2119,48.54],[-95.2324,48.5399],[-95.2339,48.5399],[-95.2537,48.5398],[-95.2554,48.5398],[-95.2756,48.54],[-95.2773,48.54],[-95.2975,48.5401],[-95.2992,48.5402],[-95.3194,48.54],[-95.321,48.54],[-95.3412,48.5402],[-95.3425,48.5402],[-95.3424,48.5548],[-95.3423,48.5691],[-95.3423,48.5836],[-95.3426,48.5979],[-95.3424,48.6127],[-95.3426,48.6271],[-95.3425,48.6415],[-95.3424,48.6561],[-95.3423,48.6705],[-95.3424,48.6849],[-95.3425,48.6995],[-95.3425,48.7131],[-95.3302,48.713],[-95.3205,48.713],[-95.3084,48.713],[-95.3051,48.713],[-95.299,48.713],[-95.2866,48.713],[-95.2767,48.713],[-95.2656,48.713],[-95.2645,48.713],[-95.255,48.713],[-95.2427,48.713],[-95.2331,48.713],[-95.2206,48.713],[-95.2112,48.713],[-95.1991,48.713],[-95.1917,48.713],[-95.1773,48.713],[-95.1697,48.7129],[-95.1554,48.7129],[-95.1477,48.7129],[-95.1333,48.713],[-95.1297,48.713],[-95.1259,48.7129],[-95.1119,48.7129],[-95.1104,48.7129],[-95.1046,48.7129],[-95.0898,48.713],[-95.0899,48.7277],[-95.0901,48.7421],[-95.0901,48.7566],[-95.0903,48.7711],[-95.0903,48.7855],[-95.0903,48.8],[-95.0909,48.8147],[-95.0908,48.8291],[-95.0907,48.8436],[-95.0908,48.858],[-95.0908,48.8724],[-95.0911,48.8869],[-95.0912,48.9014],[-95.0914,48.916],[-95.0914,48.9208],[-95.0919,48.9207],[-95.0927,48.9204],[-95.0944,48.9193],[-95.0946,48.9191],[-95.0961,48.9181],[-95.097,48.9176],[-95.0971,48.9172],[-95.0975,48.9164],[-95.098,48.916],[-95.0981,48.9159],[-95.1008,48.9142],[-95.102,48.9132],[-95.1032,48.9127],[-95.1042,48.9121],[-95.1056,48.9113],[-95.108,48.9099],[-95.1096,48.9089],[-95.1107,48.9082],[-95.1126,48.9073],[-95.113,48.9072],[-95.1132,48.9071],[-95.1137,48.9069],[-95.1141,48.9064],[-95.114,48.9061],[-95.1144,48.9052],[-95.1151,48.9046],[-95.1163,48.9037],[-95.1182,48.9029],[-95.1204,48.9019],[-95.1205,48.9017],[-95.121,48.9016],[-95.1214,48.9013],[-95.1228,48.9006],[-95.1233,48.9004],[-95.1239,48.9001],[-95.1252,48.8998],[-95.1312,48.8975],[-95.1322,48.8973],[-95.1337,48.8969],[-95.1343,48.8963],[-95.1348,48.8963],[-95.1351,48.8963],[-95.1355,48.8959],[-95.1381,48.8949],[-95.1404,48.8943],[-95.1436,48.8937],[-95.1438,48.8934],[-95.1459,48.8929],[-95.1469,48.8927],[-95.1483,48.8923],[-95.1508,48.8922],[-95.1528,48.8921],[-95.1555,48.892],[-95.1564,48.8919],[-95.1579,48.8919],[-95.1602,48.892],[-95.1618,48.892],[-95.1641,48.8917],[-95.1648,48.8913],[-95.1674,48.8907],[-95.1701,48.8902],[-95.173,48.8897],[-95.1764,48.8893],[-95.1791,48.889],[-95.1797,48.889],[-95.1819,48.8888],[-95.1851,48.8882],[-95.1863,48.8877],[-95.1877,48.8874],[-95.1889,48.8873],[-95.1901,48.887],[-95.1913,48.8868],[-95.1919,48.8866],[-95.1924,48.8865],[-95.1956,48.8862],[-95.1986,48.8855],[-95.2005,48.8856],[-95.2009,48.8855],[-95.2024,48.8852],[-95.2059,48.8848],[-95.2085,48.8846],[-95.2112,48.8848],[-95.2115,48.8847],[-95.2117,48.8847],[-95.2122,48.8842],[-95.2144,48.8843],[-95.2151,48.884],[-95.2159,48.8839],[-95.217,48.8835],[-95.2188,48.8835],[-95.2193,48.8832],[-95.22,48.8831],[-95.2207,48.8831],[-95.2208,48.8831],[-95.2212,48.883],[-95.2252,48.8819],[-95.2265,48.8816],[-95.2287,48.8815],[-95.231,48.8814],[-95.2335,48.8814],[-95.2356,48.8815],[-95.2381,48.8817],[-95.2391,48.8819],[-95.2407,48.8821],[-95.2423,48.8821],[-95.2429,48.8822],[-95.2429,48.8822],[-95.2439,48.8823],[-95.2458,48.8829],[-95.2472,48.8835],[-95.248,48.8836],[-95.2485,48.8832],[-95.2496,48.8834],[-95.2502,48.8835],[-95.2507,48.8836],[-95.2517,48.8839],[-95.2548,48.8845],[-95.256,48.885],[-95.257,48.8858],[-95.2585,48.8867],[-95.2585,48.8867],[-95.2627,48.8877],[-95.2635,48.888],[-95.2639,48.8883],[-95.2646,48.8885],[-95.265,48.8886],[-95.2654,48.8888],[-95.2666,48.8894],[-95.2674,48.89],[-95.2677,48.8903],[-95.268,48.8905],[-95.2713,48.8915],[-95.2724,48.8921],[-95.2745,48.8931],[-95.2751,48.8938],[-95.2753,48.8943],[-95.2748,48.8951],[-95.2749,48.8956],[-95.2755,48.8959],[-95.2759,48.8962],[-95.2763,48.8963],[-95.2765,48.8962],[-95.277,48.8958],[-95.2773,48.8957],[-95.2782,48.8956],[-95.279,48.8957],[-95.2796,48.8962],[-95.2803,48.8965],[-95.2813,48.8967],[-95.2839,48.8975],[-95.2853,48.8977],[-95.2861,48.8976],[-95.2865,48.8975],[-95.287,48.8976],[-95.2872,48.8977],[-95.2879,48.8979],[-95.2882,48.8981],[-95.289,48.8994],[-95.2896,48.9],[-95.2901,48.9003],[-95.2911,48.9006],[-95.2911,48.9008],[-95.2906,48.9011],[-95.2907,48.9014],[-95.2908,48.9016],[-95.2909,48.9017],[-95.2914,48.9019],[-95.2927,48.9019],[-95.2935,48.902],[-95.2937,48.9023],[-95.2941,48.9027],[-95.2949,48.9028],[-95.2967,48.9027],[-95.2976,48.9026],[-95.298,48.9027],[-95.2983,48.9028],[-95.2993,48.9035],[-95.3005,48.904],[-95.3002,48.9045],[-95.3001,48.9046],[-95.3001,48.9047],[-95.3,48.9047],[-95.3,48.9047],[-95.2999,48.9048],[-95.2999,48.9048],[-95.2999,48.9048],[-95.2997,48.905],[-95.2996,48.9051],[-95.2994,48.9053],[-95.2992,48.9055],[-95.2991,48.9057],[-95.2989,48.906],[-95.2988,48.906],[-95.2986,48.9063],[-95.2985,48.9064],[-95.2985,48.9065],[-95.2983,48.9068],[-95.2982,48.9068],[-95.2981,48.907],[-95.298,48.9071],[-95.298,48.9071],[-95.298,48.9071],[-95.2979,48.9071],[-95.2979,48.9072],[-95.2979,48.9072],[-95.2978,48.9072],[-95.2978,48.9072],[-95.2978,48.9073],[-95.2977,48.9073],[-95.2976,48.9074],[-95.2973,48.9077],[-95.2973,48.908],[-95.2973,48.9081],[-95.2978,48.9083],[-95.2999,48.9086],[-95.3017,48.9093],[-95.3027,48.91],[-95.3038,48.9114],[-95.3043,48.9119],[-95.3059,48.9127],[-95.3061,48.9128],[-95.3064,48.9129],[-95.3074,48.9135],[-95.3078,48.9141],[-95.3085,48.9146],[-95.3092,48.9149],[-95.3093,48.9149],[-95.3102,48.9155],[-95.3109,48.9163],[-95.3115,48.9172],[-95.3119,48.9178],[-95.3126,48.919],[-95.3132,48.9198],[-95.3141,48.921],[-95.315,48.9222],[-95.3168,48.9245],[-95.3195,48.9285],[-95.3208,48.9305],[-95.3209,48.9307],[-95.3222,48.9327],[-95.3228,48.9344],[-95.3223,48.9355],[-95.3225,48.9358],[-95.3229,48.9373],[-95.3231,48.9389],[-95.3228,48.9403],[-95.3225,48.9409],[-95.3219,48.9412],[-95.3189,48.9419],[-95.3181,48.9421],[-95.3168,48.9431],[-95.3154,48.9448],[-95.3148,48.9452],[-95.3141,48.9457],[-95.3131,48.946],[-95.3114,48.9461],[-95.3102,48.9463],[-95.3095,48.9463],[-95.3088,48.9464],[-95.3086,48.9465],[-95.3086,48.9469],[-95.3085,48.947],[-95.3078,48.9466],[-95.3074,48.9465],[-95.3071,48.9466],[-95.3071,48.9469],[-95.3079,48.9474],[-95.3092,48.9477],[-95.3096,48.9478],[-95.3103,48.948],[-95.3104,48.9484],[-95.3103,48.9485],[-95.31,48.9485],[-95.3099,48.9484],[-95.3096,48.9482],[-95.3094,48.9481],[-95.3081,48.948],[-95.3071,48.9477],[-95.3062,48.9472],[-95.3062,48.9472],[-95.3061,48.9469],[-95.3062,48.9463],[-95.3063,48.9462],[-95.3069,48.9456],[-95.3069,48.9455],[-95.3068,48.9454],[-95.3061,48.9454],[-95.3053,48.9459],[-95.305,48.9462],[-95.3046,48.947],[-95.3046,48.9482],[-95.3052,48.9495],[-95.3061,48.9502],[-95.3079,48.9509],[-95.3089,48.9511],[-95.3097,48.951],[-95.3104,48.951],[-95.3108,48.9512],[-95.3115,48.952],[-95.312,48.9524],[-95.3126,48.9524],[-95.3129,48.9523],[-95.3129,48.9521],[-95.3119,48.9507],[-95.3119,48.9502],[-95.3123,48.9502],[-95.3125,48.9503],[-95.3131,48.9503],[-95.3141,48.9508],[-95.3151,48.951],[-95.3154,48.9513],[-95.3177,48.9525],[-95.3181,48.9531],[-95.3182,48.9535],[-95.3177,48.9545],[-95.3175,48.9552],[-95.3179,48.9559],[-95.3188,48.9562],[-95.3191,48.9569],[-95.3202,48.9581],[-95.3206,48.959],[-95.3206,48.9595],[-95.3206,48.9598],[-95.3202,48.9606],[-95.3193,48.9622],[-95.3193,48.964],[-95.3198,48.9643],[-95.3201,48.9648],[-95.3207,48.9669],[-95.3212,48.9672],[-95.3227,48.9685],[-95.3232,48.9692],[-95.3241,48.9703],[-95.3247,48.972],[-95.3248,48.9728],[-95.3249,48.9738],[-95.325,48.9743],[-95.3253,48.976],[-95.3257,48.9784],[-95.3255,48.9789],[-95.3256,48.98],[-95.3257,48.9814],[-95.3253,48.9832],[-95.3245,48.985],[-95.3242,48.9859],[-95.3227,48.9884],[-95.3224,48.9889],[-95.3206,48.9921],[-95.3204,48.9924],[-95.3191,48.9941],[-95.3181,48.995],[-95.3178,48.9958],[-95.3178,48.9961],[-95.3179,48.9961],[-95.3182,48.996],[-95.3187,48.9956],[-95.3191,48.9953],[-95.3197,48.9954],[-95.3201,48.9956],[-95.3206,48.9961],[-95.3204,48.9964],[-95.3202,48.9973],[-95.3204,48.9976],[-95.3224,48.9984],[-95.3231,48.999]]],"type":"Polygon"},"id":"39","properties":{"Area":4608320923.49768,"CTYONLY_":2,"Code":"LOTW","LASTMOD":"1976-07-04T12:00:00Z","Name":"Lake of the Woods","Perimiter":388250.14572},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=1&offset=0&bbox=-90,-180,90,0&bbox-crs=http://www.opengis.net/def/crs/EPSG/0/4326","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=1&offset=0&bbox=-90,-180,90,0&bbox-crs=http://www.opengis.net/def/crs/EPSG/0/4326","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=1&offset=1&bbox=-90,-180,90,0&bbox-crs=http://www.opengis.net/def/crs/EPSG/0/4326","rel":"next","title":"next page","type":"application/geo+json"}],"numberMatched":117,"numberReturned":1,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_collections_mn_counties_items_by_id.json b/msautotest/api/expected/ogcapi_collections_mn_counties_items_by_id.json new file mode 100644 index 0000000000..f8ac3f3616 --- /dev/null +++ b/msautotest/api/expected/ogcapi_collections_mn_counties_items_by_id.json @@ -0,0 +1 @@ +{"geometry":{"coordinates":[[[-96.4054,49.0001],[-96.4054,48.9947],[-96.4054,48.994],[-96.4054,48.9803],[-96.4054,48.9793],[-96.4053,48.9705],[-96.4053,48.9658],[-96.4053,48.9648],[-96.4053,48.9515],[-96.4053,48.9504],[-96.4053,48.9371],[-96.4053,48.936],[-96.4054,48.9225],[-96.4054,48.9214],[-96.4053,48.9137],[-96.4053,48.9081],[-96.4053,48.9068],[-96.405,48.8926],[-96.405,48.878],[-96.4047,48.8635],[-96.4045,48.8491],[-96.4043,48.8343],[-96.4042,48.8198],[-96.4042,48.8048],[-96.4042,48.7903],[-96.4045,48.7758],[-96.4047,48.7607],[-96.4048,48.7465],[-96.4048,48.7318],[-96.4049,48.7172],[-96.388,48.7172],[-96.3873,48.7172],[-96.3866,48.703],[-96.3874,48.6887],[-96.3871,48.6741],[-96.3877,48.6599],[-96.3879,48.6454],[-96.388,48.6313],[-96.389,48.6165],[-96.3891,48.6024],[-96.3884,48.5877],[-96.3882,48.5733],[-96.3879,48.5588],[-96.3882,48.5442],[-96.4101,48.544],[-96.4318,48.5438],[-96.4535,48.5436],[-96.4754,48.5435],[-96.4973,48.5434],[-96.518,48.5434],[-96.54,48.5434],[-96.5621,48.5436],[-96.5839,48.5437],[-96.6058,48.5437],[-96.6278,48.5437],[-96.6493,48.5437],[-96.6713,48.5436],[-96.6931,48.5437],[-96.7151,48.5437],[-96.7368,48.5437],[-96.7585,48.5436],[-96.7803,48.5435],[-96.8023,48.5436],[-96.824,48.5436],[-96.8459,48.5434],[-96.8678,48.5433],[-96.8896,48.5433],[-96.9115,48.5432],[-96.9138,48.5433],[-96.9331,48.5435],[-96.9551,48.5437],[-96.9768,48.544],[-96.9985,48.5441],[-97.0194,48.5441],[-97.0416,48.5442],[-97.0635,48.5441],[-97.0852,48.5441],[-97.107,48.544],[-97.1287,48.5439],[-97.1509,48.5439],[-97.1631,48.544],[-97.1637,48.5445],[-97.1659,48.5483],[-97.1662,48.5509],[-97.1661,48.5527],[-97.1654,48.5536],[-97.1645,48.554],[-97.1628,48.5543],[-97.1613,48.5539],[-97.1592,48.5528],[-97.1577,48.5518],[-97.1557,48.5512],[-97.1538,48.5513],[-97.1513,48.5515],[-97.1507,48.5515],[-97.1493,48.5516],[-97.1474,48.5516],[-97.1444,48.5514],[-97.1407,48.5515],[-97.1387,48.5522],[-97.1379,48.553],[-97.1379,48.5542],[-97.1391,48.5554],[-97.141,48.5566],[-97.1426,48.5571],[-97.1464,48.5573],[-97.1505,48.5574],[-97.1515,48.5574],[-97.1551,48.5574],[-97.1578,48.5573],[-97.1606,48.5571],[-97.1631,48.5571],[-97.1646,48.5572],[-97.167,48.5575],[-97.1697,48.5584],[-97.1721,48.5591],[-97.1727,48.5593],[-97.174,48.5599],[-97.1749,48.5606],[-97.1753,48.5614],[-97.1754,48.5623],[-97.1749,48.5631],[-97.1744,48.5639],[-97.1723,48.5648],[-97.1721,48.5648],[-97.1706,48.5652],[-97.1687,48.5655],[-97.167,48.5658],[-97.1651,48.5659],[-97.1613,48.5661],[-97.1541,48.5669],[-97.153,48.5671],[-97.1516,48.5677],[-97.1503,48.5688],[-97.1496,48.5695],[-97.1487,48.5707],[-97.1477,48.5727],[-97.1477,48.5728],[-97.1476,48.5731],[-97.1483,48.5763],[-97.15,48.5775],[-97.1501,48.5775],[-97.1548,48.5779],[-97.1592,48.5785],[-97.1605,48.58],[-97.16,48.5816],[-97.1578,48.5826],[-97.1562,48.5828],[-97.1541,48.5826],[-97.1524,48.5823],[-97.15,48.5815],[-97.1494,48.5813],[-97.1484,48.5811],[-97.1449,48.5815],[-97.1436,48.5824],[-97.1431,48.5834],[-97.1429,48.5838],[-97.142,48.5876],[-97.1418,48.5886],[-97.1415,48.5909],[-97.1422,48.5926],[-97.1433,48.5936],[-97.1451,48.594],[-97.1471,48.594],[-97.1497,48.5937],[-97.1525,48.594],[-97.1536,48.5949],[-97.1535,48.5957],[-97.1527,48.5962],[-97.1524,48.5969],[-97.1516,48.598],[-97.1498,48.5981],[-97.1497,48.5981],[-97.1463,48.5977],[-97.1443,48.5981],[-97.143,48.5987],[-97.1416,48.6002],[-97.1403,48.6021],[-97.14,48.6025],[-97.138,48.6044],[-97.1359,48.6054],[-97.1345,48.6065],[-97.1341,48.6075],[-97.1349,48.6082],[-97.1358,48.6086],[-97.137,48.6088],[-97.1396,48.6086],[-97.1443,48.6078],[-97.1474,48.6081],[-97.1494,48.6089],[-97.1495,48.609],[-97.1505,48.6115],[-97.1501,48.6124],[-97.1493,48.6129],[-97.1478,48.6138],[-97.145,48.6146],[-97.1408,48.6149],[-97.137,48.6144],[-97.134,48.6136],[-97.1319,48.6133],[-97.1309,48.6137],[-97.1289,48.614],[-97.1286,48.6153],[-97.1293,48.6168],[-97.1295,48.617],[-97.1311,48.6184],[-97.1342,48.6199],[-97.1353,48.6212],[-97.1346,48.6224],[-97.133,48.6228],[-97.131,48.6227],[-97.1291,48.6222],[-97.1277,48.6212],[-97.1274,48.621],[-97.1259,48.6195],[-97.1253,48.619],[-97.1243,48.6183],[-97.1231,48.6178],[-97.1216,48.6176],[-97.12,48.6178],[-97.1193,48.6182],[-97.1186,48.6191],[-97.1183,48.6198],[-97.1186,48.6209],[-97.1198,48.6221],[-97.1209,48.6232],[-97.1212,48.6233],[-97.122,48.624],[-97.1228,48.6245],[-97.1236,48.625],[-97.1241,48.6254],[-97.1245,48.6257],[-97.1249,48.6259],[-97.1253,48.6261],[-97.126,48.6264],[-97.1266,48.6266],[-97.1272,48.627],[-97.1279,48.6273],[-97.1288,48.6278],[-97.1296,48.6282],[-97.1302,48.6288],[-97.1305,48.6292],[-97.1307,48.6297],[-97.131,48.6303],[-97.131,48.6304],[-97.131,48.6308],[-97.131,48.6315],[-97.1309,48.6317],[-97.1307,48.6321],[-97.1304,48.6325],[-97.1301,48.6326],[-97.1297,48.6328],[-97.1293,48.6329],[-97.129,48.633],[-97.1281,48.6332],[-97.128,48.6333],[-97.1275,48.6333],[-97.1253,48.6334],[-97.1235,48.6333],[-97.1216,48.6327],[-97.1181,48.6308],[-97.1176,48.6307],[-97.115,48.6299],[-97.1133,48.63],[-97.1115,48.6303],[-97.1107,48.6308],[-97.1104,48.6309],[-97.1095,48.6315],[-97.1084,48.6327],[-97.1082,48.6344],[-97.1086,48.6363],[-97.1096,48.6389],[-97.1109,48.6407],[-97.1119,48.6416],[-97.1144,48.6433],[-97.115,48.6438],[-97.115,48.6446],[-97.1149,48.6452],[-97.1123,48.6457],[-97.1112,48.6459],[-97.1093,48.6465],[-97.1078,48.6478],[-97.1069,48.6491],[-97.1066,48.6501],[-97.1061,48.6519],[-97.1059,48.6527],[-97.1045,48.6545],[-97.1017,48.6563],[-97.0987,48.6593],[-97.0986,48.6604],[-97.0985,48.6613],[-97.0992,48.6625],[-97.1019,48.6636],[-97.106,48.663],[-97.1062,48.663],[-97.1082,48.6634],[-97.1087,48.6645],[-97.1061,48.6654],[-97.1057,48.6655],[-97.102,48.6667],[-97.1,48.668],[-97.0998,48.6714],[-97.1002,48.675],[-97.1003,48.6757],[-97.1008,48.6787],[-97.1011,48.6808],[-97.1003,48.6828],[-97.0985,48.683],[-97.0946,48.6822],[-97.0926,48.6821],[-97.0904,48.6828],[-97.0898,48.6841],[-97.0899,48.6852],[-97.091,48.6861],[-97.093,48.687],[-97.0951,48.6876],[-97.099,48.6884],[-97.1024,48.6893],[-97.103,48.6894],[-97.1059,48.6903],[-97.1064,48.6905],[-97.1086,48.6915],[-97.111,48.6939],[-97.113,48.6964],[-97.1148,48.6981],[-97.1182,48.7005],[-97.1198,48.7018],[-97.1201,48.7039],[-97.1194,48.7041],[-97.1182,48.7046],[-97.1143,48.7052],[-97.1117,48.7056],[-97.11,48.7063],[-97.1098,48.7083],[-97.1113,48.7094],[-97.1134,48.7101],[-97.1157,48.7105],[-97.1174,48.7111],[-97.119,48.7119],[-97.1212,48.7136],[-97.1223,48.716],[-97.1229,48.7168],[-97.1231,48.7172],[-97.1243,48.7192],[-97.1253,48.7201],[-97.1253,48.7203],[-97.126,48.7207],[-97.1263,48.7212],[-97.1272,48.7215],[-97.128,48.722],[-97.1282,48.7221],[-97.1288,48.7225],[-97.1297,48.7229],[-97.131,48.7233],[-97.1321,48.7238],[-97.1331,48.7242],[-97.1345,48.7248],[-97.136,48.7257],[-97.1369,48.7263],[-97.1375,48.727],[-97.1376,48.7274],[-97.1376,48.7278],[-97.1373,48.7283],[-97.137,48.7284],[-97.1365,48.7285],[-97.136,48.7287],[-97.1352,48.7287],[-97.1341,48.7289],[-97.1333,48.7291],[-97.1328,48.7292],[-97.132,48.7294],[-97.1312,48.7295],[-97.1308,48.7296],[-97.1299,48.7299],[-97.1294,48.7304],[-97.1288,48.7308],[-97.1286,48.7312],[-97.1286,48.7315],[-97.1286,48.7316],[-97.1286,48.7318],[-97.1285,48.7322],[-97.1286,48.7326],[-97.1286,48.7328],[-97.1287,48.7331],[-97.129,48.7335],[-97.1295,48.7339],[-97.1298,48.7341],[-97.1316,48.7347],[-97.1322,48.7348],[-97.1334,48.7347],[-97.1351,48.7345],[-97.1369,48.7345],[-97.1383,48.7345],[-97.1396,48.7347],[-97.1402,48.7349],[-97.1412,48.7354],[-97.1419,48.7359],[-97.1422,48.7367],[-97.1423,48.7372],[-97.1421,48.7381],[-97.1414,48.7385],[-97.1408,48.7387],[-97.1404,48.7389],[-97.1399,48.7393],[-97.1392,48.7397],[-97.1381,48.7408],[-97.1372,48.742],[-97.1366,48.7435],[-97.1365,48.745],[-97.1365,48.7459],[-97.1366,48.7466],[-97.1369,48.748],[-97.1375,48.7492],[-97.1379,48.75],[-97.1385,48.7504],[-97.1391,48.7507],[-97.1396,48.7508],[-97.1401,48.7509],[-97.141,48.751],[-97.142,48.751],[-97.143,48.7509],[-97.1444,48.7507],[-97.1457,48.7506],[-97.1466,48.7505],[-97.1476,48.7505],[-97.1491,48.7506],[-97.1497,48.7508],[-97.1503,48.7509],[-97.1515,48.7515],[-97.1521,48.752],[-97.153,48.7529],[-97.1539,48.7542],[-97.1545,48.7553],[-97.1547,48.7558],[-97.1548,48.7562],[-97.1548,48.7569],[-97.1548,48.7576],[-97.1546,48.758],[-97.1542,48.7587],[-97.1535,48.7593],[-97.1528,48.7598],[-97.1519,48.7601],[-97.1508,48.7605],[-97.1503,48.7606],[-97.1501,48.7607],[-97.1475,48.7616],[-97.1473,48.7617],[-97.1469,48.762],[-97.1462,48.7626],[-97.1461,48.7628],[-97.1459,48.7633],[-97.1456,48.7643],[-97.1456,48.765],[-97.146,48.7658],[-97.1476,48.7673],[-97.1487,48.7681],[-97.15,48.7692],[-97.1501,48.7693],[-97.1506,48.77],[-97.1512,48.7712],[-97.1519,48.7721],[-97.1525,48.7727],[-97.1529,48.7728],[-97.1559,48.7731],[-97.1567,48.7732],[-97.1578,48.7735],[-97.1582,48.7737],[-97.1587,48.7742],[-97.1589,48.7746],[-97.159,48.7751],[-97.159,48.7751],[-97.159,48.7754],[-97.1589,48.776],[-97.1584,48.7766],[-97.1579,48.7769],[-97.1573,48.7772],[-97.1557,48.7776],[-97.1544,48.7778],[-97.1534,48.778],[-97.1522,48.7783],[-97.1509,48.7787],[-97.1501,48.7789],[-97.1497,48.779],[-97.1483,48.7797],[-97.1477,48.7801],[-97.1473,48.7807],[-97.1472,48.7811],[-97.1473,48.7816],[-97.1478,48.7821],[-97.1486,48.7824],[-97.1495,48.7826],[-97.1501,48.7826],[-97.1503,48.7826],[-97.1513,48.7825],[-97.1533,48.7824],[-97.1547,48.7824],[-97.1559,48.7825],[-97.1571,48.7827],[-97.1583,48.783],[-97.1591,48.7834],[-97.1595,48.7838],[-97.1597,48.7843],[-97.1598,48.7848],[-97.1596,48.7853],[-97.1593,48.786],[-97.1591,48.7863],[-97.1586,48.7869],[-97.1577,48.7877],[-97.1574,48.7882],[-97.1573,48.7884],[-97.1572,48.7887],[-97.1571,48.7894],[-97.157,48.7895],[-97.157,48.7901],[-97.1572,48.7906],[-97.1575,48.7909],[-97.1581,48.7912],[-97.1586,48.7913],[-97.1592,48.7915],[-97.1595,48.7915],[-97.1611,48.7915],[-97.1618,48.7914],[-97.1645,48.7911],[-97.1648,48.7911],[-97.1657,48.7911],[-97.1664,48.7912],[-97.1672,48.7913],[-97.1714,48.7921],[-97.1718,48.7923],[-97.1721,48.7924],[-97.1731,48.7929],[-97.1737,48.7933],[-97.174,48.7937],[-97.1741,48.7942],[-97.1742,48.7947],[-97.1742,48.7951],[-97.1739,48.7954],[-97.1734,48.7958],[-97.1726,48.7963],[-97.1717,48.7966],[-97.1716,48.7966],[-97.171,48.7967],[-97.1701,48.7967],[-97.1688,48.7966],[-97.1673,48.7964],[-97.1665,48.7962],[-97.1654,48.7962],[-97.1648,48.7962],[-97.1638,48.7963],[-97.1631,48.7966],[-97.1625,48.7969],[-97.162,48.7974],[-97.1617,48.7979],[-97.1617,48.7984],[-97.1619,48.7988],[-97.1621,48.7994],[-97.1626,48.8001],[-97.1633,48.8007],[-97.1642,48.8011],[-97.1652,48.8014],[-97.166,48.8015],[-97.1668,48.8016],[-97.1675,48.8016],[-97.1685,48.8016],[-97.1698,48.8013],[-97.1706,48.8011],[-97.1714,48.8008],[-97.1715,48.8008],[-97.1724,48.8004],[-97.1731,48.8],[-97.1742,48.7992],[-97.175,48.7986],[-97.1754,48.7983],[-97.1757,48.798],[-97.1761,48.7977],[-97.1768,48.7974],[-97.1773,48.7973],[-97.1779,48.7972],[-97.1787,48.7972],[-97.1795,48.7972],[-97.1801,48.7973],[-97.1807,48.7975],[-97.1811,48.7978],[-97.1815,48.7982],[-97.1816,48.7986],[-97.1817,48.7991],[-97.1815,48.7995],[-97.1813,48.8],[-97.1808,48.8004],[-97.1801,48.8008],[-97.1791,48.8012],[-97.1779,48.8015],[-97.1769,48.8017],[-97.1764,48.8018],[-97.1756,48.8021],[-97.1748,48.8023],[-97.1725,48.8032],[-97.1713,48.8036],[-97.171,48.8037],[-97.1706,48.8039],[-97.1694,48.8043],[-97.1682,48.8046],[-97.1675,48.8048],[-97.1666,48.805],[-97.1655,48.8052],[-97.1638,48.8055],[-97.161,48.8059],[-97.1605,48.8061],[-97.1597,48.8064],[-97.159,48.8067],[-97.1583,48.8072],[-97.1579,48.8077],[-97.1577,48.8082],[-97.1576,48.8089],[-97.1578,48.8098],[-97.158,48.8104],[-97.1586,48.811],[-97.159,48.8111],[-97.161,48.8117],[-97.1617,48.8119],[-97.1625,48.812],[-97.1636,48.8121],[-97.1644,48.8121],[-97.1651,48.812],[-97.1666,48.8118],[-97.168,48.8116],[-97.169,48.8114],[-97.17,48.8114],[-97.1713,48.8115],[-97.1715,48.8115],[-97.1726,48.8117],[-97.1731,48.8118],[-97.174,48.8122],[-97.1761,48.8132],[-97.1776,48.8141],[-97.1784,48.8145],[-97.1797,48.8149],[-97.1807,48.8151],[-97.1821,48.8153],[-97.1828,48.8153],[-97.184,48.8152],[-97.1848,48.8151],[-97.186,48.8147],[-97.1868,48.8145],[-97.1873,48.8143],[-97.1879,48.8143],[-97.1883,48.8143],[-97.1889,48.8143],[-97.1894,48.8144],[-97.1898,48.8146],[-97.1901,48.8148],[-97.1903,48.8153],[-97.1904,48.8156],[-97.1903,48.8159],[-97.19,48.8163],[-97.1893,48.8167],[-97.1885,48.8171],[-97.1879,48.8173],[-97.1866,48.8176],[-97.1857,48.8177],[-97.1847,48.8179],[-97.184,48.8181],[-97.1833,48.8184],[-97.1817,48.8189],[-97.1809,48.8193],[-97.1801,48.8199],[-97.1793,48.8207],[-97.1787,48.8216],[-97.178,48.8232],[-97.1777,48.824],[-97.1776,48.8245],[-97.1777,48.8249],[-97.178,48.8255],[-97.1782,48.8258],[-97.1786,48.8262],[-97.1794,48.8268],[-97.1822,48.8288],[-97.1837,48.8299],[-97.1841,48.8304],[-97.1847,48.8314],[-97.1848,48.8319],[-97.1849,48.8326],[-97.1849,48.8327],[-97.1848,48.833],[-97.1846,48.8336],[-97.1842,48.8341],[-97.1837,48.8345],[-97.183,48.8348],[-97.1822,48.835],[-97.1813,48.8351],[-97.1799,48.8352],[-97.1783,48.8353],[-97.1779,48.8354],[-97.1772,48.8356],[-97.1757,48.8362],[-97.1753,48.8364],[-97.1747,48.8369],[-97.1742,48.8373],[-97.1739,48.8378],[-97.1738,48.8384],[-97.1738,48.839],[-97.1739,48.8406],[-97.1743,48.8427],[-97.1747,48.8438],[-97.175,48.8442],[-97.1755,48.8447],[-97.1761,48.8452],[-97.1767,48.8455],[-97.1771,48.8456],[-97.1779,48.8458],[-97.1795,48.8459],[-97.1808,48.846],[-97.1817,48.8462],[-97.1823,48.8464],[-97.1827,48.8468],[-97.1829,48.847],[-97.1829,48.8471],[-97.1829,48.8473],[-97.1826,48.8476],[-97.1821,48.8479],[-97.1816,48.848],[-97.1809,48.8481],[-97.1793,48.8482],[-97.178,48.8483],[-97.1767,48.8484],[-97.1759,48.8486],[-97.1753,48.8487],[-97.1747,48.849],[-97.1742,48.8493],[-97.1737,48.8497],[-97.1733,48.8502],[-97.173,48.8506],[-97.173,48.8508],[-97.173,48.8511],[-97.173,48.8516],[-97.1732,48.8522],[-97.1737,48.8527],[-97.1746,48.8534],[-97.1771,48.855],[-97.1784,48.8561],[-97.1786,48.8563],[-97.179,48.8569],[-97.1793,48.8576],[-97.1794,48.8583],[-97.1794,48.859],[-97.1792,48.8606],[-97.179,48.8615],[-97.179,48.862],[-97.1791,48.8626],[-97.1794,48.863],[-97.1801,48.8636],[-97.1811,48.864],[-97.1818,48.8641],[-97.1827,48.8641],[-97.1839,48.864],[-97.1855,48.8637],[-97.1871,48.8633],[-97.1877,48.8631],[-97.1883,48.8631],[-97.1891,48.8631],[-97.1896,48.8633],[-97.19,48.8635],[-97.1903,48.8639],[-97.1905,48.8644],[-97.1905,48.8648],[-97.1904,48.8651],[-97.1901,48.8657],[-97.1899,48.8661],[-97.1895,48.8665],[-97.189,48.867],[-97.1884,48.8675],[-97.1851,48.8694],[-97.1813,48.8718],[-97.1788,48.8736],[-97.1785,48.8738],[-97.1782,48.8741],[-97.1781,48.8743],[-97.1779,48.8745],[-97.1778,48.8747],[-97.1777,48.8749],[-97.1777,48.875],[-97.1778,48.875],[-97.1778,48.8754],[-97.1779,48.8757],[-97.1782,48.8761],[-97.1786,48.8765],[-97.1792,48.8769],[-97.1798,48.8771],[-97.1808,48.8772],[-97.1823,48.8772],[-97.1852,48.8768],[-97.1869,48.8765],[-97.1881,48.8765],[-97.1891,48.8766],[-97.1904,48.8769],[-97.1933,48.8779],[-97.1944,48.8783],[-97.1957,48.8788],[-97.1972,48.8794],[-97.1981,48.8799],[-97.1988,48.8805],[-97.1995,48.8812],[-97.1999,48.8818],[-97.1999,48.8821],[-97.2,48.8827],[-97.1998,48.8832],[-97.1997,48.8836],[-97.199,48.8845],[-97.1978,48.8859],[-97.1975,48.8865],[-97.1974,48.8868],[-97.1973,48.8872],[-97.1973,48.8874],[-97.1974,48.8877],[-97.1975,48.8881],[-97.1983,48.8889],[-97.2002,48.8903],[-97.2004,48.8904],[-97.2009,48.8908],[-97.2014,48.8912],[-97.2017,48.8915],[-97.2017,48.8919],[-97.2016,48.8922],[-97.2013,48.8925],[-97.201,48.8926],[-97.2001,48.8926],[-97.1994,48.8926],[-97.1985,48.8925],[-97.198,48.8924],[-97.1973,48.892],[-97.1957,48.8916],[-97.1946,48.8915],[-97.1944,48.8914],[-97.1937,48.8914],[-97.1927,48.8915],[-97.1921,48.8917],[-97.1916,48.8919],[-97.1905,48.8926],[-97.1901,48.8932],[-97.1898,48.8938],[-97.1897,48.8944],[-97.1897,48.8947],[-97.1898,48.8951],[-97.1899,48.8954],[-97.1903,48.896],[-97.1911,48.8967],[-97.1919,48.8974],[-97.1925,48.8979],[-97.1935,48.8985],[-97.1941,48.8988],[-97.1945,48.8989],[-97.1966,48.8997],[-97.1992,48.9004],[-97.2009,48.9009],[-97.2022,48.9013],[-97.2048,48.9018],[-97.2055,48.902],[-97.207,48.9025],[-97.2076,48.9027],[-97.2082,48.9029],[-97.2088,48.9032],[-97.2093,48.9036],[-97.21,48.904],[-97.2105,48.9044],[-97.211,48.905],[-97.2114,48.9056],[-97.2122,48.9069],[-97.2125,48.9075],[-97.2127,48.9082],[-97.2127,48.909],[-97.2125,48.9099],[-97.212,48.911],[-97.2116,48.9121],[-97.2111,48.913],[-97.2108,48.914],[-97.2106,48.9148],[-97.2106,48.9153],[-97.2109,48.9162],[-97.2111,48.9167],[-97.2115,48.9172],[-97.2118,48.9175],[-97.2122,48.9177],[-97.2129,48.9181],[-97.2149,48.9187],[-97.2163,48.9191],[-97.2164,48.9191],[-97.2171,48.9194],[-97.2179,48.9198],[-97.2189,48.9205],[-97.2196,48.9215],[-97.2198,48.9222],[-97.2199,48.923],[-97.2197,48.9237],[-97.2191,48.9249],[-97.2183,48.9262],[-97.2172,48.9277],[-97.2163,48.9286],[-97.2159,48.9289],[-97.2149,48.9301],[-97.2146,48.9304],[-97.2145,48.9307],[-97.2144,48.931],[-97.2145,48.9314],[-97.2145,48.9316],[-97.2148,48.9319],[-97.2154,48.9325],[-97.2159,48.9327],[-97.2162,48.9328],[-97.217,48.9328],[-97.2181,48.9327],[-97.2198,48.9325],[-97.2208,48.9325],[-97.2214,48.9325],[-97.2218,48.9326],[-97.2237,48.9332],[-97.2245,48.9337],[-97.2249,48.9339],[-97.225,48.934],[-97.2252,48.9342],[-97.2254,48.9345],[-97.2257,48.9349],[-97.226,48.9353],[-97.2263,48.936],[-97.2267,48.9376],[-97.227,48.9389],[-97.2271,48.9398],[-97.2271,48.941],[-97.227,48.9418],[-97.2266,48.9432],[-97.2264,48.9441],[-97.2263,48.9445],[-97.2264,48.9452],[-97.2265,48.9456],[-97.227,48.9462],[-97.2273,48.9465],[-97.2276,48.9467],[-97.2279,48.9467],[-97.2284,48.9468],[-97.2304,48.9465],[-97.2309,48.9464],[-97.2313,48.9464],[-97.2326,48.9466],[-97.2331,48.9468],[-97.2338,48.9471],[-97.2342,48.9474],[-97.2343,48.948],[-97.2343,48.9485],[-97.2342,48.9488],[-97.2341,48.9491],[-97.2337,48.95],[-97.2332,48.951],[-97.2328,48.9524],[-97.2323,48.954],[-97.2317,48.9558],[-97.2313,48.9568],[-97.2309,48.9578],[-97.2305,48.9585],[-97.23,48.9591],[-97.2288,48.9603],[-97.2282,48.9609],[-97.2278,48.9613],[-97.2276,48.9619],[-97.2276,48.9624],[-97.2279,48.963],[-97.228,48.9631],[-97.2283,48.9634],[-97.2289,48.9639],[-97.2294,48.9641],[-97.23,48.9642],[-97.2323,48.9646],[-97.2355,48.965],[-97.2368,48.9652],[-97.2375,48.9654],[-97.2382,48.966],[-97.2383,48.9661],[-97.2388,48.9666],[-97.2391,48.9676],[-97.2392,48.9687],[-97.239,48.9696],[-97.2387,48.9706],[-97.2383,48.9715],[-97.2381,48.9723],[-97.238,48.9725],[-97.2379,48.9731],[-97.2378,48.9734],[-97.2378,48.9738],[-97.238,48.9752],[-97.238,48.9763],[-97.2381,48.9771],[-97.238,48.9771],[-97.238,48.9841],[-97.2377,48.9849],[-97.2372,48.9857],[-97.2365,48.9867],[-97.2359,48.9874],[-97.2351,48.9881],[-97.2342,48.989],[-97.2335,48.9895],[-97.2331,48.9898],[-97.2317,48.9904],[-97.2301,48.9911],[-97.2293,48.9914],[-97.229,48.9916],[-97.2279,48.9921],[-97.2274,48.9925],[-97.227,48.9929],[-97.2266,48.9933],[-97.2265,48.9938],[-97.2267,48.9941],[-97.227,48.9945],[-97.2273,48.9947],[-97.2287,48.9949],[-97.2304,48.995],[-97.2317,48.9951],[-97.2324,48.9952],[-97.2335,48.9956],[-97.2338,48.9959],[-97.2341,48.9966],[-97.2341,48.997],[-97.234,48.9975],[-97.2337,48.9981],[-97.2332,48.9985],[-97.2323,48.999],[-97.2305,49.0],[-97.2303,49.0001],[-97.2295,49.0005],[-97.2175,49.0005],[-97.2161,49.0005],[-97.2078,49.0005],[-97.2069,49.0005],[-97.1955,49.0005],[-97.1939,49.0005],[-97.1739,49.0005],[-97.1724,49.0005],[-97.1514,49.0005],[-97.1502,49.0005],[-97.1294,49.0004],[-97.1277,49.0004],[-97.1073,49.0004],[-97.1061,49.0004],[-97.0853,49.0004],[-97.084,49.0004],[-97.0633,49.0004],[-97.062,49.0004],[-97.0412,49.0004],[-97.0401,49.0004],[-97.0192,49.0004],[-97.0183,49.0004],[-96.9971,49.0004],[-96.9961,49.0004],[-96.9751,49.0003],[-96.9738,49.0003],[-96.953,49.0003],[-96.9518,49.0003],[-96.931,49.0003],[-96.9299,49.0003],[-96.909,49.0003],[-96.9078,49.0003],[-96.8869,49.0003],[-96.8856,49.0003],[-96.8649,49.0003],[-96.864,49.0003],[-96.8429,49.0003],[-96.8415,49.0003],[-96.8208,49.0003],[-96.8197,49.0003],[-96.8023,49.0002],[-96.8005,49.0002],[-96.8003,49.0002],[-96.7988,49.0002],[-96.7787,49.0002],[-96.7768,49.0002],[-96.7567,49.0002],[-96.7547,49.0002],[-96.7348,49.0002],[-96.7327,49.0002],[-96.7127,49.0002],[-96.7107,49.0002],[-96.6905,49.0002],[-96.6886,49.0002],[-96.6695,49.0002],[-96.6665,49.0002],[-96.6482,49.0002],[-96.6445,49.0002],[-96.6243,49.0002],[-96.6225,49.0002],[-96.6021,49.0002],[-96.6004,49.0002],[-96.58,49.0002],[-96.5784,49.0002],[-96.558,49.0002],[-96.5563,49.0002],[-96.536,49.0002],[-96.5342,49.0002],[-96.5154,49.0002],[-96.5123,49.0002],[-96.4933,49.0002],[-96.49,49.0002],[-96.471,49.0001],[-96.4664,49.0001],[-96.4496,49.0001],[-96.4492,49.0001],[-96.4491,49.0001],[-96.446,49.0001],[-96.4273,49.0001],[-96.4224,49.0001],[-96.4054,49.0001]]],"type":"Polygon"},"id":"35","links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items/35?f=json","rel":"self","title":"This document as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items/35?f=html","rel":"alternate","title":"This document as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties?f=json","rel":"collection","title":"This collection as JSON","type":"application/json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties?f=html","rel":"collection","title":"This collection as HTML","type":"text/html"}],"properties":{"Area":2862183702.23055,"CTYONLY_":3,"Code":"KITT","LASTMOD":"1999-12-31T23:59:59Z","Name":"Kittson","Perimiter":263017.48277},"type":"Feature"} diff --git a/msautotest/api/expected/ogcapi_collections_mn_counties_items_by_id_not_found.json.txt b/msautotest/api/expected/ogcapi_collections_mn_counties_items_by_id_not_found.json.txt new file mode 100644 index 0000000000..08f243c1bd --- /dev/null +++ b/msautotest/api/expected/ogcapi_collections_mn_counties_items_by_id_not_found.json.txt @@ -0,0 +1 @@ +{"code":"NotFound","description":"Invalid feature id."} diff --git a/msautotest/api/expected/ogcapi_collections_mn_counties_items_empty_bbox_crs.json b/msautotest/api/expected/ogcapi_collections_mn_counties_items_empty_bbox_crs.json new file mode 100644 index 0000000000..6d3cd302e9 --- /dev/null +++ b/msautotest/api/expected/ogcapi_collections_mn_counties_items_empty_bbox_crs.json @@ -0,0 +1 @@ +{"code":"InvalidParameterValue","description":"Bad value for bbox-crs."} diff --git a/msautotest/api/expected/ogcapi_collections_mn_counties_items_empty_crs.json b/msautotest/api/expected/ogcapi_collections_mn_counties_items_empty_crs.json new file mode 100644 index 0000000000..bfd08349ab --- /dev/null +++ b/msautotest/api/expected/ogcapi_collections_mn_counties_items_empty_crs.json @@ -0,0 +1 @@ +{"code":"InvalidParameterValue","description":"Bad value for crs."} diff --git a/msautotest/api/expected/ogcapi_collections_mn_counties_items_epsg_4326_with_headers.txt b/msautotest/api/expected/ogcapi_collections_mn_counties_items_epsg_4326_with_headers.txt new file mode 100644 index 0000000000..81f0c4b09a --- /dev/null +++ b/msautotest/api/expected/ogcapi_collections_mn_counties_items_epsg_4326_with_headers.txt @@ -0,0 +1,9 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +Link: ; rel="next"; title="next page"; type="application/geo+json" +OGC-NumberMatched: 117 +OGC-NumberReturned: 1 + +{"features":[{"geometry":{"coordinates":[[[48.999,-95.3231],[48.999,-95.3109],[48.9989,-95.2889],[48.9989,-95.2852],[48.9989,-95.2669],[48.9989,-95.245],[48.9989,-95.2232],[48.9989,-95.2014],[48.9989,-95.1792],[48.9989,-95.1574],[48.9989,-95.1531],[49.0031,-95.1531],[49.0179,-95.1532],[49.0325,-95.1532],[49.047,-95.1532],[49.0619,-95.1532],[49.0765,-95.1532],[49.0911,-95.1532],[49.1057,-95.1532],[49.1205,-95.1532],[49.1354,-95.1532],[49.1499,-95.1532],[49.1642,-95.1532],[49.1788,-95.1532],[49.1807,-95.1532],[49.1931,-95.1532],[49.1966,-95.1532],[49.2077,-95.1532],[49.2131,-95.1533],[49.2219,-95.1533],[49.2308,-95.1533],[49.2365,-95.1533],[49.2472,-95.1533],[49.2512,-95.1533],[49.2655,-95.1533],[49.2697,-95.1533],[49.2802,-95.1533],[49.2882,-95.1533],[49.2945,-95.1533],[49.3072,-95.1533],[49.309,-95.1533],[49.3234,-95.1533],[49.3237,-95.1533],[49.3381,-95.1533],[49.3476,-95.1533],[49.3525,-95.1533],[49.3636,-95.1533],[49.367,-95.1533],[49.3705,-95.1533],[49.3776,-95.1533],[49.3813,-95.1533],[49.3845,-95.1533],[49.383,-95.1503],[49.3813,-95.1499],[49.3807,-95.1498],[49.3802,-95.1467],[49.3784,-95.145],[49.3784,-95.1418],[49.3762,-95.1397],[49.3751,-95.1367],[49.3736,-95.1324],[49.3705,-95.1287],[49.367,-95.1171],[49.3666,-95.1159],[49.3666,-95.1145],[49.3664,-95.1098],[49.3652,-95.1031],[49.3636,-95.1031],[49.3617,-95.0926],[49.3612,-95.0897],[49.3564,-95.0707],[49.3533,-95.0582],[49.3532,-95.0495],[49.3533,-95.0479],[49.3554,-95.0262],[49.3565,-95.0141],[49.3612,-95.0047],[49.367,-94.993],[49.369,-94.9889],[49.3684,-94.9818],[49.3678,-94.9742],[49.3699,-94.9597],[49.3702,-94.9573],[49.3688,-94.952],[49.367,-94.948],[49.3625,-94.9376],[49.3529,-94.9152],[49.3524,-94.9143],[49.3502,-94.909],[49.3484,-94.9065],[49.3414,-94.8933],[49.3378,-94.8865],[49.3334,-94.8782],[49.3308,-94.8712],[49.3244,-94.854],[49.3244,-94.8492],[49.3243,-94.8363],[49.3236,-94.8311],[49.323,-94.8271],[49.3214,-94.8162],[49.309,-94.8243],[49.3088,-94.8243],[49.2944,-94.8255],[49.2943,-94.8255],[49.28,-94.8204],[49.2653,-94.8152],[49.2515,-94.8103],[49.2388,-94.8059],[49.2367,-94.8051],[49.2224,-94.8001],[49.2144,-94.7973],[49.2079,-94.7975],[49.1979,-94.7979],[49.1936,-94.7965],[49.1792,-94.7918],[49.1646,-94.7871],[49.153,-94.7833],[49.15,-94.7823],[49.1357,-94.7776],[49.1206,-94.7727],[49.1206,-94.7727],[49.1096,-94.7611],[49.1058,-94.7571],[49.0988,-94.7496],[49.0918,-94.7474],[49.0773,-94.7429],[49.0657,-94.7394],[49.063,-94.7385],[49.0497,-94.7344],[49.0351,-94.7299],[49.0205,-94.7254],[49.0052,-94.7207],[48.9979,-94.7184],[48.9907,-94.7162],[48.9761,-94.7117],[48.9615,-94.7072],[48.9468,-94.7027],[48.9322,-94.6982],[48.9276,-94.6968],[48.8875,-94.6844],[48.8842,-94.6834],[48.8724,-94.6842],[48.8719,-94.6855],[48.8691,-94.6923],[48.8636,-94.6902],[48.8591,-94.6914],[48.8535,-94.693],[48.8447,-94.6881],[48.8401,-94.6855],[48.836,-94.6963],[48.8355,-94.6975],[48.8319,-94.702],[48.8302,-94.7025],[48.8243,-94.7042],[48.8159,-94.6991],[48.8111,-94.6962],[48.8092,-94.6951],[48.8012,-94.6958],[48.7997,-94.6959],[48.7895,-94.6944],[48.7864,-94.6934],[48.7781,-94.6909],[48.7752,-94.687],[48.772,-94.6776],[48.7717,-94.6768],[48.7705,-94.6746],[48.7662,-94.6671],[48.7605,-94.6603],[48.7581,-94.6557],[48.7565,-94.6525],[48.7562,-94.652],[48.7491,-94.6453],[48.7441,-94.6453],[48.7434,-94.6443],[48.7413,-94.6414],[48.7392,-94.631],[48.739,-94.6301],[48.7373,-94.6191],[48.7318,-94.6106],[48.731,-94.6084],[48.7289,-94.6028],[48.7283,-94.6011],[48.7248,-94.5962],[48.7197,-94.5913],[48.7176,-94.5876],[48.7175,-94.5867],[48.7156,-94.5685],[48.7159,-94.5622],[48.7163,-94.5558],[48.7148,-94.549],[48.7146,-94.5487],[48.7124,-94.5457],[48.7036,-94.5396],[48.7028,-94.539],[48.7013,-94.5329],[48.7016,-94.5247],[48.7008,-94.5178],[48.7008,-94.5173],[48.7006,-94.5093],[48.6999,-94.5066],[48.698,-94.4996],[48.698,-94.4958],[48.698,-94.4863],[48.6969,-94.4739],[48.6966,-94.4706],[48.6953,-94.4631],[48.6933,-94.4568],[48.6925,-94.4523],[48.6925,-94.4517],[48.693,-94.4465],[48.6949,-94.4388],[48.6998,-94.4319],[48.7012,-94.4299],[48.6998,-94.4299],[48.6852,-94.43],[48.6708,-94.4301],[48.6564,-94.43],[48.642,-94.4297],[48.6276,-94.4294],[48.6133,-94.4292],[48.5988,-94.4289],[48.5844,-94.4289],[48.5698,-94.4291],[48.5554,-94.4295],[48.5409,-94.43],[48.5264,-94.4303],[48.512,-94.4303],[48.4977,-94.4299],[48.4832,-94.4296],[48.4688,-94.4296],[48.4543,-94.4293],[48.4399,-94.4292],[48.4254,-94.4293],[48.411,-94.4294],[48.3964,-94.4293],[48.3821,-94.4289],[48.3675,-94.4288],[48.3675,-94.4471],[48.3675,-94.4505],[48.3675,-94.4688],[48.3674,-94.4722],[48.3674,-94.4906],[48.3674,-94.4924],[48.3674,-94.4941],[48.3675,-94.5118],[48.3674,-94.5157],[48.3674,-94.5335],[48.3674,-94.5378],[48.3674,-94.5536],[48.3674,-94.5593],[48.3674,-94.5754],[48.3674,-94.5812],[48.3675,-94.5971],[48.3674,-94.6029],[48.3673,-94.6188],[48.3673,-94.6245],[48.3673,-94.6405],[48.3673,-94.6465],[48.3673,-94.6505],[48.3673,-94.6622],[48.3673,-94.6679],[48.3672,-94.6694],[48.3671,-94.683],[48.3671,-94.6898],[48.3669,-94.7099],[48.3668,-94.7117],[48.3669,-94.7315],[48.3669,-94.7329],[48.3669,-94.7533],[48.3669,-94.7549],[48.3669,-94.7748],[48.3669,-94.7765],[48.3669,-94.7967],[48.3669,-94.7983],[48.3669,-94.8183],[48.3669,-94.8199],[48.3669,-94.8399],[48.3669,-94.8416],[48.3667,-94.8616],[48.3667,-94.8632],[48.3667,-94.8833],[48.3666,-94.8849],[48.3666,-94.9049],[48.3666,-94.9065],[48.3667,-94.9264],[48.3667,-94.9283],[48.3666,-94.9469],[48.3666,-94.95],[48.3667,-94.9684],[48.3667,-94.9716],[48.3667,-94.9901],[48.3667,-94.9932],[48.3665,-95.0119],[48.3665,-95.0153],[48.3665,-95.0337],[48.3665,-95.0369],[48.3665,-95.0555],[48.3665,-95.0586],[48.3664,-95.0773],[48.3664,-95.0801],[48.3663,-95.099],[48.3663,-95.1008],[48.3663,-95.1018],[48.3663,-95.1207],[48.3663,-95.1236],[48.3662,-95.1315],[48.3662,-95.1424],[48.3662,-95.1454],[48.3661,-95.164],[48.3661,-95.1669],[48.3661,-95.1861],[48.3661,-95.1887],[48.3661,-95.1983],[48.3661,-95.2066],[48.3661,-95.2106],[48.3797,-95.211],[48.3808,-95.211],[48.3941,-95.2111],[48.3952,-95.2111],[48.4087,-95.2112],[48.4096,-95.2112],[48.4232,-95.2113],[48.4242,-95.2113],[48.4255,-95.2113],[48.4376,-95.2113],[48.4387,-95.2113],[48.4522,-95.2113],[48.4529,-95.2112],[48.4666,-95.211],[48.4673,-95.211],[48.4816,-95.2111],[48.4962,-95.2112],[48.5101,-95.2111],[48.5109,-95.2111],[48.5244,-95.2115],[48.5252,-95.2115],[48.54,-95.2119],[48.5399,-95.2324],[48.5399,-95.2339],[48.5398,-95.2537],[48.5398,-95.2554],[48.54,-95.2756],[48.54,-95.2773],[48.5401,-95.2975],[48.5402,-95.2992],[48.54,-95.3194],[48.54,-95.321],[48.5402,-95.3412],[48.5402,-95.3425],[48.5548,-95.3424],[48.5691,-95.3423],[48.5836,-95.3423],[48.5979,-95.3426],[48.6127,-95.3424],[48.6271,-95.3426],[48.6415,-95.3425],[48.6561,-95.3424],[48.6705,-95.3423],[48.6849,-95.3424],[48.6995,-95.3425],[48.7131,-95.3425],[48.713,-95.3302],[48.713,-95.3205],[48.713,-95.3084],[48.713,-95.3051],[48.713,-95.299],[48.713,-95.2866],[48.713,-95.2767],[48.713,-95.2656],[48.713,-95.2645],[48.713,-95.255],[48.713,-95.2427],[48.713,-95.2331],[48.713,-95.2206],[48.713,-95.2112],[48.713,-95.1991],[48.713,-95.1917],[48.713,-95.1773],[48.7129,-95.1697],[48.7129,-95.1554],[48.7129,-95.1477],[48.713,-95.1333],[48.713,-95.1297],[48.7129,-95.1259],[48.7129,-95.1119],[48.7129,-95.1104],[48.7129,-95.1046],[48.713,-95.0898],[48.7277,-95.0899],[48.7421,-95.0901],[48.7566,-95.0901],[48.7711,-95.0903],[48.7855,-95.0903],[48.8,-95.0903],[48.8147,-95.0909],[48.8291,-95.0908],[48.8436,-95.0907],[48.858,-95.0908],[48.8724,-95.0908],[48.8869,-95.0911],[48.9014,-95.0912],[48.916,-95.0914],[48.9208,-95.0914],[48.9207,-95.0919],[48.9204,-95.0927],[48.9193,-95.0944],[48.9191,-95.0946],[48.9181,-95.0961],[48.9176,-95.097],[48.9172,-95.0971],[48.9164,-95.0975],[48.916,-95.098],[48.9159,-95.0981],[48.9142,-95.1008],[48.9132,-95.102],[48.9127,-95.1032],[48.9121,-95.1042],[48.9113,-95.1056],[48.9099,-95.108],[48.9089,-95.1096],[48.9082,-95.1107],[48.9073,-95.1126],[48.9072,-95.113],[48.9071,-95.1132],[48.9069,-95.1137],[48.9064,-95.1141],[48.9061,-95.114],[48.9052,-95.1144],[48.9046,-95.1151],[48.9037,-95.1163],[48.9029,-95.1182],[48.9019,-95.1204],[48.9017,-95.1205],[48.9016,-95.121],[48.9013,-95.1214],[48.9006,-95.1228],[48.9004,-95.1233],[48.9001,-95.1239],[48.8998,-95.1252],[48.8975,-95.1312],[48.8973,-95.1322],[48.8969,-95.1337],[48.8963,-95.1343],[48.8963,-95.1348],[48.8963,-95.1351],[48.8959,-95.1355],[48.8949,-95.1381],[48.8943,-95.1404],[48.8937,-95.1436],[48.8934,-95.1438],[48.8929,-95.1459],[48.8927,-95.1469],[48.8923,-95.1483],[48.8922,-95.1508],[48.8921,-95.1528],[48.892,-95.1555],[48.8919,-95.1564],[48.8919,-95.1579],[48.892,-95.1602],[48.892,-95.1618],[48.8917,-95.1641],[48.8913,-95.1648],[48.8907,-95.1674],[48.8902,-95.1701],[48.8897,-95.173],[48.8893,-95.1764],[48.889,-95.1791],[48.889,-95.1797],[48.8888,-95.1819],[48.8882,-95.1851],[48.8877,-95.1863],[48.8874,-95.1877],[48.8873,-95.1889],[48.887,-95.1901],[48.8868,-95.1913],[48.8866,-95.1919],[48.8865,-95.1924],[48.8862,-95.1956],[48.8855,-95.1986],[48.8856,-95.2005],[48.8855,-95.2009],[48.8852,-95.2024],[48.8848,-95.2059],[48.8846,-95.2085],[48.8848,-95.2112],[48.8847,-95.2115],[48.8847,-95.2117],[48.8842,-95.2122],[48.8843,-95.2144],[48.884,-95.2151],[48.8839,-95.2159],[48.8835,-95.217],[48.8835,-95.2188],[48.8832,-95.2193],[48.8831,-95.22],[48.8831,-95.2207],[48.8831,-95.2208],[48.883,-95.2212],[48.8819,-95.2252],[48.8816,-95.2265],[48.8815,-95.2287],[48.8814,-95.231],[48.8814,-95.2335],[48.8815,-95.2356],[48.8817,-95.2381],[48.8819,-95.2391],[48.8821,-95.2407],[48.8821,-95.2423],[48.8822,-95.2429],[48.8822,-95.2429],[48.8823,-95.2439],[48.8829,-95.2458],[48.8835,-95.2472],[48.8836,-95.248],[48.8832,-95.2485],[48.8834,-95.2496],[48.8835,-95.2502],[48.8836,-95.2507],[48.8839,-95.2517],[48.8845,-95.2548],[48.885,-95.256],[48.8858,-95.257],[48.8867,-95.2585],[48.8867,-95.2585],[48.8877,-95.2627],[48.888,-95.2635],[48.8883,-95.2639],[48.8885,-95.2646],[48.8886,-95.265],[48.8888,-95.2654],[48.8894,-95.2666],[48.89,-95.2674],[48.8903,-95.2677],[48.8905,-95.268],[48.8915,-95.2713],[48.8921,-95.2724],[48.8931,-95.2745],[48.8938,-95.2751],[48.8943,-95.2753],[48.8951,-95.2748],[48.8956,-95.2749],[48.8959,-95.2755],[48.8962,-95.2759],[48.8963,-95.2763],[48.8962,-95.2765],[48.8958,-95.277],[48.8957,-95.2773],[48.8956,-95.2782],[48.8957,-95.279],[48.8962,-95.2796],[48.8965,-95.2803],[48.8967,-95.2813],[48.8975,-95.2839],[48.8977,-95.2853],[48.8976,-95.2861],[48.8975,-95.2865],[48.8976,-95.287],[48.8977,-95.2872],[48.8979,-95.2879],[48.8981,-95.2882],[48.8994,-95.289],[48.9,-95.2896],[48.9003,-95.2901],[48.9006,-95.2911],[48.9008,-95.2911],[48.9011,-95.2906],[48.9014,-95.2907],[48.9016,-95.2908],[48.9017,-95.2909],[48.9019,-95.2914],[48.9019,-95.2927],[48.902,-95.2935],[48.9023,-95.2937],[48.9027,-95.2941],[48.9028,-95.2949],[48.9027,-95.2967],[48.9026,-95.2976],[48.9027,-95.298],[48.9028,-95.2983],[48.9035,-95.2993],[48.904,-95.3005],[48.9045,-95.3002],[48.9046,-95.3001],[48.9047,-95.3001],[48.9047,-95.3],[48.9047,-95.3],[48.9048,-95.2999],[48.9048,-95.2999],[48.9048,-95.2999],[48.905,-95.2997],[48.9051,-95.2996],[48.9053,-95.2994],[48.9055,-95.2992],[48.9057,-95.2991],[48.906,-95.2989],[48.906,-95.2988],[48.9063,-95.2986],[48.9064,-95.2985],[48.9065,-95.2985],[48.9068,-95.2983],[48.9068,-95.2982],[48.907,-95.2981],[48.9071,-95.298],[48.9071,-95.298],[48.9071,-95.298],[48.9071,-95.2979],[48.9072,-95.2979],[48.9072,-95.2979],[48.9072,-95.2978],[48.9072,-95.2978],[48.9073,-95.2978],[48.9073,-95.2977],[48.9074,-95.2976],[48.9077,-95.2973],[48.908,-95.2973],[48.9081,-95.2973],[48.9083,-95.2978],[48.9086,-95.2999],[48.9093,-95.3017],[48.91,-95.3027],[48.9114,-95.3038],[48.9119,-95.3043],[48.9127,-95.3059],[48.9128,-95.3061],[48.9129,-95.3064],[48.9135,-95.3074],[48.9141,-95.3078],[48.9146,-95.3085],[48.9149,-95.3092],[48.9149,-95.3093],[48.9155,-95.3102],[48.9163,-95.3109],[48.9172,-95.3115],[48.9178,-95.3119],[48.919,-95.3126],[48.9198,-95.3132],[48.921,-95.3141],[48.9222,-95.315],[48.9245,-95.3168],[48.9285,-95.3195],[48.9305,-95.3208],[48.9307,-95.3209],[48.9327,-95.3222],[48.9344,-95.3228],[48.9355,-95.3223],[48.9358,-95.3225],[48.9373,-95.3229],[48.9389,-95.3231],[48.9403,-95.3228],[48.9409,-95.3225],[48.9412,-95.3219],[48.9419,-95.3189],[48.9421,-95.3181],[48.9431,-95.3168],[48.9448,-95.3154],[48.9452,-95.3148],[48.9457,-95.3141],[48.946,-95.3131],[48.9461,-95.3114],[48.9463,-95.3102],[48.9463,-95.3095],[48.9464,-95.3088],[48.9465,-95.3086],[48.9469,-95.3086],[48.947,-95.3085],[48.9466,-95.3078],[48.9465,-95.3074],[48.9466,-95.3071],[48.9469,-95.3071],[48.9474,-95.3079],[48.9477,-95.3092],[48.9478,-95.3096],[48.948,-95.3103],[48.9484,-95.3104],[48.9485,-95.3103],[48.9485,-95.31],[48.9484,-95.3099],[48.9482,-95.3096],[48.9481,-95.3094],[48.948,-95.3081],[48.9477,-95.3071],[48.9472,-95.3062],[48.9472,-95.3062],[48.9469,-95.3061],[48.9463,-95.3062],[48.9462,-95.3063],[48.9456,-95.3069],[48.9455,-95.3069],[48.9454,-95.3068],[48.9454,-95.3061],[48.9459,-95.3053],[48.9462,-95.305],[48.947,-95.3046],[48.9482,-95.3046],[48.9495,-95.3052],[48.9502,-95.3061],[48.9509,-95.3079],[48.9511,-95.3089],[48.951,-95.3097],[48.951,-95.3104],[48.9512,-95.3108],[48.952,-95.3115],[48.9524,-95.312],[48.9524,-95.3126],[48.9523,-95.3129],[48.9521,-95.3129],[48.9507,-95.3119],[48.9502,-95.3119],[48.9502,-95.3123],[48.9503,-95.3125],[48.9503,-95.3131],[48.9508,-95.3141],[48.951,-95.3151],[48.9513,-95.3154],[48.9525,-95.3177],[48.9531,-95.3181],[48.9535,-95.3182],[48.9545,-95.3177],[48.9552,-95.3175],[48.9559,-95.3179],[48.9562,-95.3188],[48.9569,-95.3191],[48.9581,-95.3202],[48.959,-95.3206],[48.9595,-95.3206],[48.9598,-95.3206],[48.9606,-95.3202],[48.9622,-95.3193],[48.964,-95.3193],[48.9643,-95.3198],[48.9648,-95.3201],[48.9669,-95.3207],[48.9672,-95.3212],[48.9685,-95.3227],[48.9692,-95.3232],[48.9703,-95.3241],[48.972,-95.3247],[48.9728,-95.3248],[48.9738,-95.3249],[48.9743,-95.325],[48.976,-95.3253],[48.9784,-95.3257],[48.9789,-95.3255],[48.98,-95.3256],[48.9814,-95.3257],[48.9832,-95.3253],[48.985,-95.3245],[48.9859,-95.3242],[48.9884,-95.3227],[48.9889,-95.3224],[48.9921,-95.3206],[48.9924,-95.3204],[48.9941,-95.3191],[48.995,-95.3181],[48.9958,-95.3178],[48.9961,-95.3178],[48.9961,-95.3179],[48.996,-95.3182],[48.9956,-95.3187],[48.9953,-95.3191],[48.9954,-95.3197],[48.9956,-95.3201],[48.9961,-95.3206],[48.9964,-95.3204],[48.9973,-95.3202],[48.9976,-95.3204],[48.9984,-95.3224],[48.999,-95.3231]]],"type":"Polygon"},"id":"39","properties":{"Area":4608320923.49768,"CTYONLY_":2,"Code":"LOTW","LASTMOD":"1976-07-04T12:00:00Z","Name":"Lake of the Woods","Perimiter":388250.14572},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=1&offset=0&crs=http://www.opengis.net/def/crs/EPSG/0/4326","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=1&offset=0&crs=http://www.opengis.net/def/crs/EPSG/0/4326","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=1&offset=1&crs=http://www.opengis.net/def/crs/EPSG/0/4326","rel":"next","title":"next page","type":"application/geo+json"}],"numberMatched":117,"numberReturned":1,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_collections_mn_counties_items_limit_1.json b/msautotest/api/expected/ogcapi_collections_mn_counties_items_limit_1.json new file mode 100644 index 0000000000..0b83f7dd7d --- /dev/null +++ b/msautotest/api/expected/ogcapi_collections_mn_counties_items_limit_1.json @@ -0,0 +1 @@ +{"features":[{"geometry":{"coordinates":[[[-95.3231,48.999],[-95.3109,48.999],[-95.2889,48.9989],[-95.2852,48.9989],[-95.2669,48.9989],[-95.245,48.9989],[-95.2232,48.9989],[-95.2014,48.9989],[-95.1792,48.9989],[-95.1574,48.9989],[-95.1531,48.9989],[-95.1531,49.0031],[-95.1532,49.0179],[-95.1532,49.0325],[-95.1532,49.047],[-95.1532,49.0619],[-95.1532,49.0765],[-95.1532,49.0911],[-95.1532,49.1057],[-95.1532,49.1205],[-95.1532,49.1354],[-95.1532,49.1499],[-95.1532,49.1642],[-95.1532,49.1788],[-95.1532,49.1807],[-95.1532,49.1931],[-95.1532,49.1966],[-95.1532,49.2077],[-95.1533,49.2131],[-95.1533,49.2219],[-95.1533,49.2308],[-95.1533,49.2365],[-95.1533,49.2472],[-95.1533,49.2512],[-95.1533,49.2655],[-95.1533,49.2697],[-95.1533,49.2802],[-95.1533,49.2882],[-95.1533,49.2945],[-95.1533,49.3072],[-95.1533,49.309],[-95.1533,49.3234],[-95.1533,49.3237],[-95.1533,49.3381],[-95.1533,49.3476],[-95.1533,49.3525],[-95.1533,49.3636],[-95.1533,49.367],[-95.1533,49.3705],[-95.1533,49.3776],[-95.1533,49.3813],[-95.1533,49.3845],[-95.1503,49.383],[-95.1499,49.3813],[-95.1498,49.3807],[-95.1467,49.3802],[-95.145,49.3784],[-95.1418,49.3784],[-95.1397,49.3762],[-95.1367,49.3751],[-95.1324,49.3736],[-95.1287,49.3705],[-95.1171,49.367],[-95.1159,49.3666],[-95.1145,49.3666],[-95.1098,49.3664],[-95.1031,49.3652],[-95.1031,49.3636],[-95.0926,49.3617],[-95.0897,49.3612],[-95.0707,49.3564],[-95.0582,49.3533],[-95.0495,49.3532],[-95.0479,49.3533],[-95.0262,49.3554],[-95.0141,49.3565],[-95.0047,49.3612],[-94.993,49.367],[-94.9889,49.369],[-94.9818,49.3684],[-94.9742,49.3678],[-94.9597,49.3699],[-94.9573,49.3702],[-94.952,49.3688],[-94.948,49.367],[-94.9376,49.3625],[-94.9152,49.3529],[-94.9143,49.3524],[-94.909,49.3502],[-94.9065,49.3484],[-94.8933,49.3414],[-94.8865,49.3378],[-94.8782,49.3334],[-94.8712,49.3308],[-94.854,49.3244],[-94.8492,49.3244],[-94.8363,49.3243],[-94.8311,49.3236],[-94.8271,49.323],[-94.8162,49.3214],[-94.8243,49.309],[-94.8243,49.3088],[-94.8255,49.2944],[-94.8255,49.2943],[-94.8204,49.28],[-94.8152,49.2653],[-94.8103,49.2515],[-94.8059,49.2388],[-94.8051,49.2367],[-94.8001,49.2224],[-94.7973,49.2144],[-94.7975,49.2079],[-94.7979,49.1979],[-94.7965,49.1936],[-94.7918,49.1792],[-94.7871,49.1646],[-94.7833,49.153],[-94.7823,49.15],[-94.7776,49.1357],[-94.7727,49.1206],[-94.7727,49.1206],[-94.7611,49.1096],[-94.7571,49.1058],[-94.7496,49.0988],[-94.7474,49.0918],[-94.7429,49.0773],[-94.7394,49.0657],[-94.7385,49.063],[-94.7344,49.0497],[-94.7299,49.0351],[-94.7254,49.0205],[-94.7207,49.0052],[-94.7184,48.9979],[-94.7162,48.9907],[-94.7117,48.9761],[-94.7072,48.9615],[-94.7027,48.9468],[-94.6982,48.9322],[-94.6968,48.9276],[-94.6844,48.8875],[-94.6834,48.8842],[-94.6842,48.8724],[-94.6855,48.8719],[-94.6923,48.8691],[-94.6902,48.8636],[-94.6914,48.8591],[-94.693,48.8535],[-94.6881,48.8447],[-94.6855,48.8401],[-94.6963,48.836],[-94.6975,48.8355],[-94.702,48.8319],[-94.7025,48.8302],[-94.7042,48.8243],[-94.6991,48.8159],[-94.6962,48.8111],[-94.6951,48.8092],[-94.6958,48.8012],[-94.6959,48.7997],[-94.6944,48.7895],[-94.6934,48.7864],[-94.6909,48.7781],[-94.687,48.7752],[-94.6776,48.772],[-94.6768,48.7717],[-94.6746,48.7705],[-94.6671,48.7662],[-94.6603,48.7605],[-94.6557,48.7581],[-94.6525,48.7565],[-94.652,48.7562],[-94.6453,48.7491],[-94.6453,48.7441],[-94.6443,48.7434],[-94.6414,48.7413],[-94.631,48.7392],[-94.6301,48.739],[-94.6191,48.7373],[-94.6106,48.7318],[-94.6084,48.731],[-94.6028,48.7289],[-94.6011,48.7283],[-94.5962,48.7248],[-94.5913,48.7197],[-94.5876,48.7176],[-94.5867,48.7175],[-94.5685,48.7156],[-94.5622,48.7159],[-94.5558,48.7163],[-94.549,48.7148],[-94.5487,48.7146],[-94.5457,48.7124],[-94.5396,48.7036],[-94.539,48.7028],[-94.5329,48.7013],[-94.5247,48.7016],[-94.5178,48.7008],[-94.5173,48.7008],[-94.5093,48.7006],[-94.5066,48.6999],[-94.4996,48.698],[-94.4958,48.698],[-94.4863,48.698],[-94.4739,48.6969],[-94.4706,48.6966],[-94.4631,48.6953],[-94.4568,48.6933],[-94.4523,48.6925],[-94.4517,48.6925],[-94.4465,48.693],[-94.4388,48.6949],[-94.4319,48.6998],[-94.4299,48.7012],[-94.4299,48.6998],[-94.43,48.6852],[-94.4301,48.6708],[-94.43,48.6564],[-94.4297,48.642],[-94.4294,48.6276],[-94.4292,48.6133],[-94.4289,48.5988],[-94.4289,48.5844],[-94.4291,48.5698],[-94.4295,48.5554],[-94.43,48.5409],[-94.4303,48.5264],[-94.4303,48.512],[-94.4299,48.4977],[-94.4296,48.4832],[-94.4296,48.4688],[-94.4293,48.4543],[-94.4292,48.4399],[-94.4293,48.4254],[-94.4294,48.411],[-94.4293,48.3964],[-94.4289,48.3821],[-94.4288,48.3675],[-94.4471,48.3675],[-94.4505,48.3675],[-94.4688,48.3675],[-94.4722,48.3674],[-94.4906,48.3674],[-94.4924,48.3674],[-94.4941,48.3674],[-94.5118,48.3675],[-94.5157,48.3674],[-94.5335,48.3674],[-94.5378,48.3674],[-94.5536,48.3674],[-94.5593,48.3674],[-94.5754,48.3674],[-94.5812,48.3674],[-94.5971,48.3675],[-94.6029,48.3674],[-94.6188,48.3673],[-94.6245,48.3673],[-94.6405,48.3673],[-94.6465,48.3673],[-94.6505,48.3673],[-94.6622,48.3673],[-94.6679,48.3673],[-94.6694,48.3672],[-94.683,48.3671],[-94.6898,48.3671],[-94.7099,48.3669],[-94.7117,48.3668],[-94.7315,48.3669],[-94.7329,48.3669],[-94.7533,48.3669],[-94.7549,48.3669],[-94.7748,48.3669],[-94.7765,48.3669],[-94.7967,48.3669],[-94.7983,48.3669],[-94.8183,48.3669],[-94.8199,48.3669],[-94.8399,48.3669],[-94.8416,48.3669],[-94.8616,48.3667],[-94.8632,48.3667],[-94.8833,48.3667],[-94.8849,48.3666],[-94.9049,48.3666],[-94.9065,48.3666],[-94.9264,48.3667],[-94.9283,48.3667],[-94.9469,48.3666],[-94.95,48.3666],[-94.9684,48.3667],[-94.9716,48.3667],[-94.9901,48.3667],[-94.9932,48.3667],[-95.0119,48.3665],[-95.0153,48.3665],[-95.0337,48.3665],[-95.0369,48.3665],[-95.0555,48.3665],[-95.0586,48.3665],[-95.0773,48.3664],[-95.0801,48.3664],[-95.099,48.3663],[-95.1008,48.3663],[-95.1018,48.3663],[-95.1207,48.3663],[-95.1236,48.3663],[-95.1315,48.3662],[-95.1424,48.3662],[-95.1454,48.3662],[-95.164,48.3661],[-95.1669,48.3661],[-95.1861,48.3661],[-95.1887,48.3661],[-95.1983,48.3661],[-95.2066,48.3661],[-95.2106,48.3661],[-95.211,48.3797],[-95.211,48.3808],[-95.2111,48.3941],[-95.2111,48.3952],[-95.2112,48.4087],[-95.2112,48.4096],[-95.2113,48.4232],[-95.2113,48.4242],[-95.2113,48.4255],[-95.2113,48.4376],[-95.2113,48.4387],[-95.2113,48.4522],[-95.2112,48.4529],[-95.211,48.4666],[-95.211,48.4673],[-95.2111,48.4816],[-95.2112,48.4962],[-95.2111,48.5101],[-95.2111,48.5109],[-95.2115,48.5244],[-95.2115,48.5252],[-95.2119,48.54],[-95.2324,48.5399],[-95.2339,48.5399],[-95.2537,48.5398],[-95.2554,48.5398],[-95.2756,48.54],[-95.2773,48.54],[-95.2975,48.5401],[-95.2992,48.5402],[-95.3194,48.54],[-95.321,48.54],[-95.3412,48.5402],[-95.3425,48.5402],[-95.3424,48.5548],[-95.3423,48.5691],[-95.3423,48.5836],[-95.3426,48.5979],[-95.3424,48.6127],[-95.3426,48.6271],[-95.3425,48.6415],[-95.3424,48.6561],[-95.3423,48.6705],[-95.3424,48.6849],[-95.3425,48.6995],[-95.3425,48.7131],[-95.3302,48.713],[-95.3205,48.713],[-95.3084,48.713],[-95.3051,48.713],[-95.299,48.713],[-95.2866,48.713],[-95.2767,48.713],[-95.2656,48.713],[-95.2645,48.713],[-95.255,48.713],[-95.2427,48.713],[-95.2331,48.713],[-95.2206,48.713],[-95.2112,48.713],[-95.1991,48.713],[-95.1917,48.713],[-95.1773,48.713],[-95.1697,48.7129],[-95.1554,48.7129],[-95.1477,48.7129],[-95.1333,48.713],[-95.1297,48.713],[-95.1259,48.7129],[-95.1119,48.7129],[-95.1104,48.7129],[-95.1046,48.7129],[-95.0898,48.713],[-95.0899,48.7277],[-95.0901,48.7421],[-95.0901,48.7566],[-95.0903,48.7711],[-95.0903,48.7855],[-95.0903,48.8],[-95.0909,48.8147],[-95.0908,48.8291],[-95.0907,48.8436],[-95.0908,48.858],[-95.0908,48.8724],[-95.0911,48.8869],[-95.0912,48.9014],[-95.0914,48.916],[-95.0914,48.9208],[-95.0919,48.9207],[-95.0927,48.9204],[-95.0944,48.9193],[-95.0946,48.9191],[-95.0961,48.9181],[-95.097,48.9176],[-95.0971,48.9172],[-95.0975,48.9164],[-95.098,48.916],[-95.0981,48.9159],[-95.1008,48.9142],[-95.102,48.9132],[-95.1032,48.9127],[-95.1042,48.9121],[-95.1056,48.9113],[-95.108,48.9099],[-95.1096,48.9089],[-95.1107,48.9082],[-95.1126,48.9073],[-95.113,48.9072],[-95.1132,48.9071],[-95.1137,48.9069],[-95.1141,48.9064],[-95.114,48.9061],[-95.1144,48.9052],[-95.1151,48.9046],[-95.1163,48.9037],[-95.1182,48.9029],[-95.1204,48.9019],[-95.1205,48.9017],[-95.121,48.9016],[-95.1214,48.9013],[-95.1228,48.9006],[-95.1233,48.9004],[-95.1239,48.9001],[-95.1252,48.8998],[-95.1312,48.8975],[-95.1322,48.8973],[-95.1337,48.8969],[-95.1343,48.8963],[-95.1348,48.8963],[-95.1351,48.8963],[-95.1355,48.8959],[-95.1381,48.8949],[-95.1404,48.8943],[-95.1436,48.8937],[-95.1438,48.8934],[-95.1459,48.8929],[-95.1469,48.8927],[-95.1483,48.8923],[-95.1508,48.8922],[-95.1528,48.8921],[-95.1555,48.892],[-95.1564,48.8919],[-95.1579,48.8919],[-95.1602,48.892],[-95.1618,48.892],[-95.1641,48.8917],[-95.1648,48.8913],[-95.1674,48.8907],[-95.1701,48.8902],[-95.173,48.8897],[-95.1764,48.8893],[-95.1791,48.889],[-95.1797,48.889],[-95.1819,48.8888],[-95.1851,48.8882],[-95.1863,48.8877],[-95.1877,48.8874],[-95.1889,48.8873],[-95.1901,48.887],[-95.1913,48.8868],[-95.1919,48.8866],[-95.1924,48.8865],[-95.1956,48.8862],[-95.1986,48.8855],[-95.2005,48.8856],[-95.2009,48.8855],[-95.2024,48.8852],[-95.2059,48.8848],[-95.2085,48.8846],[-95.2112,48.8848],[-95.2115,48.8847],[-95.2117,48.8847],[-95.2122,48.8842],[-95.2144,48.8843],[-95.2151,48.884],[-95.2159,48.8839],[-95.217,48.8835],[-95.2188,48.8835],[-95.2193,48.8832],[-95.22,48.8831],[-95.2207,48.8831],[-95.2208,48.8831],[-95.2212,48.883],[-95.2252,48.8819],[-95.2265,48.8816],[-95.2287,48.8815],[-95.231,48.8814],[-95.2335,48.8814],[-95.2356,48.8815],[-95.2381,48.8817],[-95.2391,48.8819],[-95.2407,48.8821],[-95.2423,48.8821],[-95.2429,48.8822],[-95.2429,48.8822],[-95.2439,48.8823],[-95.2458,48.8829],[-95.2472,48.8835],[-95.248,48.8836],[-95.2485,48.8832],[-95.2496,48.8834],[-95.2502,48.8835],[-95.2507,48.8836],[-95.2517,48.8839],[-95.2548,48.8845],[-95.256,48.885],[-95.257,48.8858],[-95.2585,48.8867],[-95.2585,48.8867],[-95.2627,48.8877],[-95.2635,48.888],[-95.2639,48.8883],[-95.2646,48.8885],[-95.265,48.8886],[-95.2654,48.8888],[-95.2666,48.8894],[-95.2674,48.89],[-95.2677,48.8903],[-95.268,48.8905],[-95.2713,48.8915],[-95.2724,48.8921],[-95.2745,48.8931],[-95.2751,48.8938],[-95.2753,48.8943],[-95.2748,48.8951],[-95.2749,48.8956],[-95.2755,48.8959],[-95.2759,48.8962],[-95.2763,48.8963],[-95.2765,48.8962],[-95.277,48.8958],[-95.2773,48.8957],[-95.2782,48.8956],[-95.279,48.8957],[-95.2796,48.8962],[-95.2803,48.8965],[-95.2813,48.8967],[-95.2839,48.8975],[-95.2853,48.8977],[-95.2861,48.8976],[-95.2865,48.8975],[-95.287,48.8976],[-95.2872,48.8977],[-95.2879,48.8979],[-95.2882,48.8981],[-95.289,48.8994],[-95.2896,48.9],[-95.2901,48.9003],[-95.2911,48.9006],[-95.2911,48.9008],[-95.2906,48.9011],[-95.2907,48.9014],[-95.2908,48.9016],[-95.2909,48.9017],[-95.2914,48.9019],[-95.2927,48.9019],[-95.2935,48.902],[-95.2937,48.9023],[-95.2941,48.9027],[-95.2949,48.9028],[-95.2967,48.9027],[-95.2976,48.9026],[-95.298,48.9027],[-95.2983,48.9028],[-95.2993,48.9035],[-95.3005,48.904],[-95.3002,48.9045],[-95.3001,48.9046],[-95.3001,48.9047],[-95.3,48.9047],[-95.3,48.9047],[-95.2999,48.9048],[-95.2999,48.9048],[-95.2999,48.9048],[-95.2997,48.905],[-95.2996,48.9051],[-95.2994,48.9053],[-95.2992,48.9055],[-95.2991,48.9057],[-95.2989,48.906],[-95.2988,48.906],[-95.2986,48.9063],[-95.2985,48.9064],[-95.2985,48.9065],[-95.2983,48.9068],[-95.2982,48.9068],[-95.2981,48.907],[-95.298,48.9071],[-95.298,48.9071],[-95.298,48.9071],[-95.2979,48.9071],[-95.2979,48.9072],[-95.2979,48.9072],[-95.2978,48.9072],[-95.2978,48.9072],[-95.2978,48.9073],[-95.2977,48.9073],[-95.2976,48.9074],[-95.2973,48.9077],[-95.2973,48.908],[-95.2973,48.9081],[-95.2978,48.9083],[-95.2999,48.9086],[-95.3017,48.9093],[-95.3027,48.91],[-95.3038,48.9114],[-95.3043,48.9119],[-95.3059,48.9127],[-95.3061,48.9128],[-95.3064,48.9129],[-95.3074,48.9135],[-95.3078,48.9141],[-95.3085,48.9146],[-95.3092,48.9149],[-95.3093,48.9149],[-95.3102,48.9155],[-95.3109,48.9163],[-95.3115,48.9172],[-95.3119,48.9178],[-95.3126,48.919],[-95.3132,48.9198],[-95.3141,48.921],[-95.315,48.9222],[-95.3168,48.9245],[-95.3195,48.9285],[-95.3208,48.9305],[-95.3209,48.9307],[-95.3222,48.9327],[-95.3228,48.9344],[-95.3223,48.9355],[-95.3225,48.9358],[-95.3229,48.9373],[-95.3231,48.9389],[-95.3228,48.9403],[-95.3225,48.9409],[-95.3219,48.9412],[-95.3189,48.9419],[-95.3181,48.9421],[-95.3168,48.9431],[-95.3154,48.9448],[-95.3148,48.9452],[-95.3141,48.9457],[-95.3131,48.946],[-95.3114,48.9461],[-95.3102,48.9463],[-95.3095,48.9463],[-95.3088,48.9464],[-95.3086,48.9465],[-95.3086,48.9469],[-95.3085,48.947],[-95.3078,48.9466],[-95.3074,48.9465],[-95.3071,48.9466],[-95.3071,48.9469],[-95.3079,48.9474],[-95.3092,48.9477],[-95.3096,48.9478],[-95.3103,48.948],[-95.3104,48.9484],[-95.3103,48.9485],[-95.31,48.9485],[-95.3099,48.9484],[-95.3096,48.9482],[-95.3094,48.9481],[-95.3081,48.948],[-95.3071,48.9477],[-95.3062,48.9472],[-95.3062,48.9472],[-95.3061,48.9469],[-95.3062,48.9463],[-95.3063,48.9462],[-95.3069,48.9456],[-95.3069,48.9455],[-95.3068,48.9454],[-95.3061,48.9454],[-95.3053,48.9459],[-95.305,48.9462],[-95.3046,48.947],[-95.3046,48.9482],[-95.3052,48.9495],[-95.3061,48.9502],[-95.3079,48.9509],[-95.3089,48.9511],[-95.3097,48.951],[-95.3104,48.951],[-95.3108,48.9512],[-95.3115,48.952],[-95.312,48.9524],[-95.3126,48.9524],[-95.3129,48.9523],[-95.3129,48.9521],[-95.3119,48.9507],[-95.3119,48.9502],[-95.3123,48.9502],[-95.3125,48.9503],[-95.3131,48.9503],[-95.3141,48.9508],[-95.3151,48.951],[-95.3154,48.9513],[-95.3177,48.9525],[-95.3181,48.9531],[-95.3182,48.9535],[-95.3177,48.9545],[-95.3175,48.9552],[-95.3179,48.9559],[-95.3188,48.9562],[-95.3191,48.9569],[-95.3202,48.9581],[-95.3206,48.959],[-95.3206,48.9595],[-95.3206,48.9598],[-95.3202,48.9606],[-95.3193,48.9622],[-95.3193,48.964],[-95.3198,48.9643],[-95.3201,48.9648],[-95.3207,48.9669],[-95.3212,48.9672],[-95.3227,48.9685],[-95.3232,48.9692],[-95.3241,48.9703],[-95.3247,48.972],[-95.3248,48.9728],[-95.3249,48.9738],[-95.325,48.9743],[-95.3253,48.976],[-95.3257,48.9784],[-95.3255,48.9789],[-95.3256,48.98],[-95.3257,48.9814],[-95.3253,48.9832],[-95.3245,48.985],[-95.3242,48.9859],[-95.3227,48.9884],[-95.3224,48.9889],[-95.3206,48.9921],[-95.3204,48.9924],[-95.3191,48.9941],[-95.3181,48.995],[-95.3178,48.9958],[-95.3178,48.9961],[-95.3179,48.9961],[-95.3182,48.996],[-95.3187,48.9956],[-95.3191,48.9953],[-95.3197,48.9954],[-95.3201,48.9956],[-95.3206,48.9961],[-95.3204,48.9964],[-95.3202,48.9973],[-95.3204,48.9976],[-95.3224,48.9984],[-95.3231,48.999]]],"type":"Polygon"},"id":"39","properties":{"Area":4608320923.49768,"CTYONLY_":2,"Code":"LOTW","LASTMOD":"1976-07-04T12:00:00Z","Name":"Lake of the Woods","Perimiter":388250.14572},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=1&offset=0","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=1&offset=0","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=1&offset=1","rel":"next","title":"next page","type":"application/geo+json"}],"numberMatched":117,"numberReturned":1,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_collections_mn_counties_items_limit_1_offset_2.json b/msautotest/api/expected/ogcapi_collections_mn_counties_items_limit_1_offset_2.json new file mode 100644 index 0000000000..8911f3ffa5 --- /dev/null +++ b/msautotest/api/expected/ogcapi_collections_mn_counties_items_limit_1_offset_2.json @@ -0,0 +1 @@ +{"features":[{"geometry":{"coordinates":[[[-96.4054,49.0001],[-96.4019,49.0001],[-96.3825,49.0001],[-96.3783,49.0001],[-96.3606,49.0001],[-96.3579,49.0001],[-96.3385,49.0001],[-96.3343,49.0001],[-96.3166,49.0001],[-96.3138,49.0001],[-96.2945,49.0001],[-96.2902,49.0001],[-96.2725,49.0001],[-96.2698,49.0001],[-96.2494,49.0001],[-96.2461,49.0001],[-96.2274,49.0001],[-96.2257,49.0001],[-96.2057,49.0001],[-96.2021,49.0001],[-96.1837,49.0],[-96.18,49.0],[-96.1617,49.0],[-96.1579,49.0],[-96.1401,49.0],[-96.1359,49.0],[-96.1176,49.0],[-96.1139,49.0],[-96.0957,49.0],[-96.0919,49.0],[-96.0738,49.0],[-96.07,49.0],[-96.0517,49.0],[-96.048,49.0],[-96.0298,49.0],[-96.026,49.0],[-96.0083,49.0],[-96.0045,49.0],[-95.9868,49.0],[-95.9784,49.0],[-95.9776,49.0],[-95.9755,49.0],[-95.9648,48.9999],[-95.9464,48.9999],[-95.943,48.9999],[-95.9225,48.9999],[-95.9211,48.9999],[-95.899,48.9998],[-95.883,48.9998],[-95.8771,48.9998],[-95.8564,48.9998],[-95.855,48.9998],[-95.8342,48.9998],[-95.8184,48.9997],[-95.8126,48.9997],[-95.7906,48.9997],[-95.7833,48.9997],[-95.7684,48.9997],[-95.7479,48.9996],[-95.7466,48.9996],[-95.7253,48.9996],[-95.7066,48.9996],[-95.7032,48.9996],[-95.681,48.9995],[-95.6654,48.9995],[-95.6596,48.9995],[-95.659,48.9995],[-95.6401,48.9995],[-95.6369,48.9995],[-95.6205,48.9994],[-95.615,48.9994],[-95.5948,48.9994],[-95.585,48.9994],[-95.573,48.9994],[-95.551,48.9993],[-95.5495,48.9993],[-95.5294,48.9993],[-95.5164,48.9993],[-95.5072,48.9993],[-95.4849,48.9992],[-95.4834,48.9992],[-95.4635,48.9992],[-95.4508,48.9992],[-95.4418,48.9992],[-95.4245,48.9991],[-95.4197,48.9991],[-95.3977,48.9991],[-95.3953,48.9991],[-95.3765,48.9991],[-95.3759,48.9991],[-95.3753,48.9991],[-95.3542,48.999],[-95.3513,48.999],[-95.3326,48.999],[-95.3286,48.999],[-95.3231,48.999],[-95.3224,48.9984],[-95.3204,48.9976],[-95.3202,48.9973],[-95.3204,48.9964],[-95.3206,48.9961],[-95.3201,48.9956],[-95.3197,48.9954],[-95.3191,48.9953],[-95.3187,48.9956],[-95.3182,48.996],[-95.3179,48.9961],[-95.3178,48.9961],[-95.3178,48.9958],[-95.3181,48.995],[-95.3191,48.9941],[-95.3204,48.9924],[-95.3206,48.9921],[-95.3224,48.9889],[-95.3227,48.9884],[-95.3242,48.9859],[-95.3245,48.985],[-95.3253,48.9832],[-95.3257,48.9814],[-95.3256,48.98],[-95.3255,48.9789],[-95.3257,48.9784],[-95.3253,48.976],[-95.325,48.9743],[-95.3249,48.9738],[-95.3248,48.9728],[-95.3247,48.972],[-95.3241,48.9703],[-95.3232,48.9692],[-95.3227,48.9685],[-95.3212,48.9672],[-95.3207,48.9669],[-95.3201,48.9648],[-95.3198,48.9643],[-95.3193,48.964],[-95.3193,48.9622],[-95.3202,48.9606],[-95.3206,48.9598],[-95.3206,48.9595],[-95.3206,48.959],[-95.3202,48.9581],[-95.3191,48.9569],[-95.3188,48.9562],[-95.3179,48.9559],[-95.3175,48.9552],[-95.3177,48.9545],[-95.3182,48.9535],[-95.3181,48.9531],[-95.3177,48.9525],[-95.3154,48.9513],[-95.3151,48.951],[-95.3141,48.9508],[-95.3131,48.9503],[-95.3125,48.9503],[-95.3123,48.9502],[-95.3119,48.9502],[-95.3119,48.9507],[-95.3129,48.9521],[-95.3129,48.9523],[-95.3126,48.9524],[-95.312,48.9524],[-95.3115,48.952],[-95.3108,48.9512],[-95.3104,48.951],[-95.3097,48.951],[-95.3089,48.9511],[-95.3079,48.9509],[-95.3061,48.9502],[-95.3052,48.9495],[-95.3046,48.9482],[-95.3046,48.947],[-95.305,48.9462],[-95.3053,48.9459],[-95.3061,48.9454],[-95.3068,48.9454],[-95.3069,48.9455],[-95.3069,48.9456],[-95.3063,48.9462],[-95.3062,48.9463],[-95.3061,48.9469],[-95.3062,48.9472],[-95.3062,48.9472],[-95.3071,48.9477],[-95.3081,48.948],[-95.3094,48.9481],[-95.3096,48.9482],[-95.3099,48.9484],[-95.31,48.9485],[-95.3103,48.9485],[-95.3104,48.9484],[-95.3103,48.948],[-95.3096,48.9478],[-95.3092,48.9477],[-95.3079,48.9474],[-95.3071,48.9469],[-95.3071,48.9466],[-95.3074,48.9465],[-95.3078,48.9466],[-95.3085,48.947],[-95.3086,48.9469],[-95.3086,48.9465],[-95.3088,48.9464],[-95.3095,48.9463],[-95.3102,48.9463],[-95.3114,48.9461],[-95.3131,48.946],[-95.3141,48.9457],[-95.3148,48.9452],[-95.3154,48.9448],[-95.3168,48.9431],[-95.3181,48.9421],[-95.3189,48.9419],[-95.3219,48.9412],[-95.3225,48.9409],[-95.3228,48.9403],[-95.3231,48.9389],[-95.3229,48.9373],[-95.3225,48.9358],[-95.3223,48.9355],[-95.3228,48.9344],[-95.3222,48.9327],[-95.3209,48.9307],[-95.3208,48.9305],[-95.3195,48.9285],[-95.3168,48.9245],[-95.315,48.9222],[-95.3141,48.921],[-95.3132,48.9198],[-95.3126,48.919],[-95.3119,48.9178],[-95.3115,48.9172],[-95.3109,48.9163],[-95.3102,48.9155],[-95.3093,48.9149],[-95.3092,48.9149],[-95.3085,48.9146],[-95.3078,48.9141],[-95.3074,48.9135],[-95.3064,48.9129],[-95.3061,48.9128],[-95.3059,48.9127],[-95.3043,48.9119],[-95.3038,48.9114],[-95.3027,48.91],[-95.3017,48.9093],[-95.2999,48.9086],[-95.2978,48.9083],[-95.2973,48.9081],[-95.2973,48.908],[-95.2973,48.9077],[-95.2976,48.9074],[-95.2977,48.9073],[-95.2978,48.9073],[-95.2978,48.9072],[-95.2978,48.9072],[-95.2979,48.9072],[-95.2979,48.9072],[-95.2979,48.9071],[-95.298,48.9071],[-95.298,48.9071],[-95.298,48.9071],[-95.2981,48.907],[-95.2982,48.9068],[-95.2983,48.9068],[-95.2985,48.9065],[-95.2985,48.9064],[-95.2986,48.9063],[-95.2988,48.906],[-95.2989,48.906],[-95.2991,48.9057],[-95.2992,48.9055],[-95.2994,48.9053],[-95.2996,48.9051],[-95.2997,48.905],[-95.2999,48.9048],[-95.2999,48.9048],[-95.2999,48.9048],[-95.3,48.9047],[-95.3,48.9047],[-95.3001,48.9047],[-95.3001,48.9046],[-95.3002,48.9045],[-95.3005,48.904],[-95.2993,48.9035],[-95.2983,48.9028],[-95.298,48.9027],[-95.2976,48.9026],[-95.2967,48.9027],[-95.2949,48.9028],[-95.2941,48.9027],[-95.2937,48.9023],[-95.2935,48.902],[-95.2927,48.9019],[-95.2914,48.9019],[-95.2909,48.9017],[-95.2908,48.9016],[-95.2907,48.9014],[-95.2906,48.9011],[-95.2911,48.9008],[-95.2911,48.9006],[-95.2901,48.9003],[-95.2896,48.9],[-95.289,48.8994],[-95.2882,48.8981],[-95.2879,48.8979],[-95.2872,48.8977],[-95.287,48.8976],[-95.2865,48.8975],[-95.2861,48.8976],[-95.2853,48.8977],[-95.2839,48.8975],[-95.2813,48.8967],[-95.2803,48.8965],[-95.2796,48.8962],[-95.279,48.8957],[-95.2782,48.8956],[-95.2773,48.8957],[-95.277,48.8958],[-95.2765,48.8962],[-95.2763,48.8963],[-95.2759,48.8962],[-95.2755,48.8959],[-95.2749,48.8956],[-95.2748,48.8951],[-95.2753,48.8943],[-95.2751,48.8938],[-95.2745,48.8931],[-95.2724,48.8921],[-95.2713,48.8915],[-95.268,48.8905],[-95.2677,48.8903],[-95.2674,48.89],[-95.2666,48.8894],[-95.2654,48.8888],[-95.265,48.8886],[-95.2646,48.8885],[-95.2639,48.8883],[-95.2635,48.888],[-95.2627,48.8877],[-95.2585,48.8867],[-95.2585,48.8867],[-95.257,48.8858],[-95.256,48.885],[-95.2548,48.8845],[-95.2517,48.8839],[-95.2507,48.8836],[-95.2502,48.8835],[-95.2496,48.8834],[-95.2485,48.8832],[-95.248,48.8836],[-95.2472,48.8835],[-95.2458,48.8829],[-95.2439,48.8823],[-95.2429,48.8822],[-95.2429,48.8822],[-95.2423,48.8821],[-95.2407,48.8821],[-95.2391,48.8819],[-95.2381,48.8817],[-95.2356,48.8815],[-95.2335,48.8814],[-95.231,48.8814],[-95.2287,48.8815],[-95.2265,48.8816],[-95.2252,48.8819],[-95.2212,48.883],[-95.2208,48.8831],[-95.2207,48.8831],[-95.22,48.8831],[-95.2193,48.8832],[-95.2188,48.8835],[-95.217,48.8835],[-95.2159,48.8839],[-95.2151,48.884],[-95.2144,48.8843],[-95.2122,48.8842],[-95.2117,48.8847],[-95.2115,48.8847],[-95.2112,48.8848],[-95.2085,48.8846],[-95.2059,48.8848],[-95.2024,48.8852],[-95.2009,48.8855],[-95.2005,48.8856],[-95.1986,48.8855],[-95.1956,48.8862],[-95.1924,48.8865],[-95.1919,48.8866],[-95.1913,48.8868],[-95.1901,48.887],[-95.1889,48.8873],[-95.1877,48.8874],[-95.1863,48.8877],[-95.1851,48.8882],[-95.1819,48.8888],[-95.1797,48.889],[-95.1791,48.889],[-95.1764,48.8893],[-95.173,48.8897],[-95.1701,48.8902],[-95.1674,48.8907],[-95.1648,48.8913],[-95.1641,48.8917],[-95.1618,48.892],[-95.1602,48.892],[-95.1579,48.8919],[-95.1564,48.8919],[-95.1555,48.892],[-95.1528,48.8921],[-95.1508,48.8922],[-95.1483,48.8923],[-95.1469,48.8927],[-95.1459,48.8929],[-95.1438,48.8934],[-95.1436,48.8937],[-95.1404,48.8943],[-95.1381,48.8949],[-95.1355,48.8959],[-95.1351,48.8963],[-95.1348,48.8963],[-95.1343,48.8963],[-95.1337,48.8969],[-95.1322,48.8973],[-95.1312,48.8975],[-95.1252,48.8998],[-95.1239,48.9001],[-95.1233,48.9004],[-95.1228,48.9006],[-95.1214,48.9013],[-95.121,48.9016],[-95.1205,48.9017],[-95.1204,48.9019],[-95.1182,48.9029],[-95.1163,48.9037],[-95.1151,48.9046],[-95.1144,48.9052],[-95.114,48.9061],[-95.1141,48.9064],[-95.1137,48.9069],[-95.1132,48.9071],[-95.113,48.9072],[-95.1126,48.9073],[-95.1107,48.9082],[-95.1096,48.9089],[-95.108,48.9099],[-95.1056,48.9113],[-95.1042,48.9121],[-95.1032,48.9127],[-95.102,48.9132],[-95.1008,48.9142],[-95.0981,48.9159],[-95.098,48.916],[-95.0975,48.9164],[-95.0971,48.9172],[-95.097,48.9176],[-95.0961,48.9181],[-95.0946,48.9191],[-95.0944,48.9193],[-95.0927,48.9204],[-95.0919,48.9207],[-95.0914,48.9208],[-95.0914,48.916],[-95.0912,48.9014],[-95.0911,48.8869],[-95.0908,48.8724],[-95.0908,48.858],[-95.0907,48.8436],[-95.0908,48.8291],[-95.0909,48.8147],[-95.0903,48.8],[-95.0903,48.7855],[-95.0903,48.7711],[-95.0901,48.7566],[-95.0901,48.7421],[-95.0899,48.7277],[-95.0898,48.713],[-95.1046,48.7129],[-95.1104,48.7129],[-95.1119,48.7129],[-95.1259,48.7129],[-95.1297,48.713],[-95.1333,48.713],[-95.1477,48.7129],[-95.1554,48.7129],[-95.1697,48.7129],[-95.1773,48.713],[-95.1917,48.713],[-95.1991,48.713],[-95.2112,48.713],[-95.2206,48.713],[-95.2331,48.713],[-95.2427,48.713],[-95.255,48.713],[-95.2645,48.713],[-95.2656,48.713],[-95.2767,48.713],[-95.2866,48.713],[-95.299,48.713],[-95.3051,48.713],[-95.3084,48.713],[-95.3205,48.713],[-95.3302,48.713],[-95.3425,48.7131],[-95.3425,48.6995],[-95.3424,48.6849],[-95.3423,48.6705],[-95.3424,48.6561],[-95.3425,48.6415],[-95.3426,48.6271],[-95.3424,48.6127],[-95.3426,48.5979],[-95.3423,48.5836],[-95.3423,48.5691],[-95.3424,48.5548],[-95.3425,48.5402],[-95.3628,48.5404],[-95.364,48.5403],[-95.3844,48.5402],[-95.386,48.5402],[-95.4061,48.5402],[-95.4078,48.5402],[-95.4279,48.54],[-95.4297,48.5399],[-95.4494,48.5399],[-95.4513,48.5399],[-95.4712,48.5396],[-95.4726,48.5396],[-95.493,48.5392],[-95.495,48.5392],[-95.5143,48.539],[-95.5163,48.539],[-95.5365,48.5389],[-95.5383,48.5389],[-95.558,48.5388],[-95.5603,48.5388],[-95.5801,48.5387],[-95.5821,48.5387],[-95.6023,48.5389],[-95.6232,48.5391],[-95.6447,48.5393],[-95.6666,48.5394],[-95.6886,48.5395],[-95.7102,48.5395],[-95.7322,48.54],[-95.7539,48.5404],[-95.7758,48.5406],[-95.7976,48.5405],[-95.8192,48.5404],[-95.8411,48.5406],[-95.8621,48.5414],[-95.8829,48.5419],[-95.8851,48.542],[-95.8986,48.5421],[-95.9046,48.5422],[-95.9064,48.5422],[-95.9269,48.5421],[-95.9486,48.5425],[-95.9498,48.5425],[-95.9704,48.543],[-95.9936,48.5435],[-96.0157,48.5437],[-96.0374,48.5438],[-96.0592,48.5437],[-96.0812,48.5436],[-96.1026,48.5438],[-96.1264,48.5439],[-96.1486,48.5442],[-96.1702,48.5445],[-96.1921,48.5446],[-96.2141,48.5449],[-96.2358,48.5452],[-96.2576,48.545],[-96.2794,48.5449],[-96.301,48.5448],[-96.3231,48.5446],[-96.3448,48.5444],[-96.3667,48.5443],[-96.3882,48.5442],[-96.3879,48.5588],[-96.3882,48.5733],[-96.3884,48.5877],[-96.3891,48.6024],[-96.389,48.6165],[-96.388,48.6313],[-96.3879,48.6454],[-96.3877,48.6599],[-96.3871,48.6741],[-96.3874,48.6887],[-96.3866,48.703],[-96.3873,48.7172],[-96.388,48.7172],[-96.4049,48.7172],[-96.4048,48.7318],[-96.4048,48.7465],[-96.4047,48.7607],[-96.4045,48.7758],[-96.4042,48.7903],[-96.4042,48.8048],[-96.4042,48.8198],[-96.4043,48.8343],[-96.4045,48.8491],[-96.4047,48.8635],[-96.405,48.878],[-96.405,48.8926],[-96.4053,48.9068],[-96.4053,48.9081],[-96.4053,48.9137],[-96.4054,48.9214],[-96.4054,48.9225],[-96.4053,48.936],[-96.4053,48.9371],[-96.4053,48.9504],[-96.4053,48.9515],[-96.4053,48.9648],[-96.4053,48.9658],[-96.4053,48.9705],[-96.4054,48.9793],[-96.4054,48.9803],[-96.4054,48.994],[-96.4054,48.9947],[-96.4054,49.0001]]],"type":"Polygon"},"id":"68","properties":{"Area":4347098503.12714,"CTYONLY_":4,"Code":"ROSE","LASTMOD":"2001-04-12T09:32:44Z","Name":"Roseau","Perimiter":302590.75293},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=1&offset=2","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=1&offset=2","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=1&offset=3","rel":"next","title":"next page","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=1&offset=1","rel":"prev","title":"previous page","type":"application/geo+json"}],"numberMatched":117,"numberReturned":1,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_collections_mn_counties_items_limit_bbox_empty_result.json b/msautotest/api/expected/ogcapi_collections_mn_counties_items_limit_bbox_empty_result.json new file mode 100644 index 0000000000..4e7a15b473 --- /dev/null +++ b/msautotest/api/expected/ogcapi_collections_mn_counties_items_limit_bbox_empty_result.json @@ -0,0 +1 @@ +{"features":[],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&bbox=2,49,3,50","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&bbox=2,49,3,50","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":0,"numberReturned":0,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_collections_mn_counties_items_storage_crs.json b/msautotest/api/expected/ogcapi_collections_mn_counties_items_storage_crs.json new file mode 100644 index 0000000000..3476983555 --- /dev/null +++ b/msautotest/api/expected/ogcapi_collections_mn_counties_items_storage_crs.json @@ -0,0 +1,9 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +Link: ; rel="next"; title="next page"; type="application/geo+json" +OGC-NumberMatched: 117 +OGC-NumberReturned: 1 + +{"features":[{"geometry":{"coordinates":[[[330081.6632,5429937.0852],[330973.8552,5429907.8707],[332581.0316,5429855.2443],[332852.32,5429846.361],[334194.5901,5429807.1188],[335796.4142,5429760.2882],[337389.1827,5429713.7224],[338981.2685,5429667.1765],[340605.3699,5429619.6947],[342198.2159,5429573.1266],[342511.687,5429563.962],[342524.6999,5430027.4046],[342570.9278,5431673.7806],[342616.3529,5433291.5638],[342661.6276,5434903.9867],[342708.3595,5436568.3111],[342753.8316,5438187.7688],[342799.5096,5439814.5568],[342844.8606,5441429.7021],[342891.2661,5443082.4014],[342937.5488,5444730.7277],[342982.8586,5446344.4017],[343027.6827,5447940.7829],[343073.2587,5449563.9378],[343078.978,5449767.629],[343117.8732,5451150.6239],[343128.642,5451533.53],[343163.4276,5452770.5168],[343180.203,5453367.059],[343207.9337,5454352.1209],[343235.609,5455335.219],[343253.6928,5455977.982],[343286.96,5457160.42],[343299.5229,5457606.6869],[343344.4291,5459201.8821],[343357.403,5459662.754],[343390.2374,5460827.5509],[343415.5031,5461723.847],[343435.1882,5462424.1872],[343474.799,5463833.428],[343480.289,5464028.3655],[343525.575,5465636.394],[343526.3585,5465664.1702],[343571.6312,5467269.1996],[343601.332,5468322.168],[343616.5435,5468862.0329],[343651.507,5470102.912],[343662.2853,5470484.3492],[343673.102,5470867.147],[343695.501,5471659.481],[343707.0891,5472073.3034],[343717.0141,5472427.737],[343936.2641,5472255.845],[343957.1513,5472067.0784],[343965.147,5471994.818],[344188.478,5471930.054],[344302.275,5471724.095],[344531.747,5471718.813],[344678.462,5471470.519],[344898.2187,5471345.0559],[345200.137,5471172.685],[345464.161,5470817.577],[346294.7483,5470405.3923],[346379.733,5470363.218],[346479.9179,5470355.0496],[346824.1391,5470326.984],[347299.966,5470172.483],[347299.281,5469995.742],[348056.4519,5469770.0044],[348262.75,5469708.5],[349632.0409,5469136.4513],[350523.2041,5468764.15],[351160.409,5468731.057],[351272.8408,5468744.37],[352856.2406,5468931.859],[353735.447,5469035.965],[354438.7108,5469539.7461],[355301.6538,5470157.9129],[355601.838,5470372.949],[356118.6003,5470292.7297],[356665.634,5470207.811],[357728.1066,5470418.7444],[357899.741,5470452.819],[358282.097,5470279.7641],[358568.2997,5470079.4765],[359313.554,5469557.9397],[360907.4733,5468442.4984],[360977.2589,5468393.6617],[361348.939,5468133.556],[361531.589,5467932.117],[362466.1701,5467132.4775],[362951.8979,5466716.8826],[363541.248,5466212.627],[364046.8372,5465907.4967],[365276.171,5465165.576],[365622.3332,5465155.1972],[366558.716,5465127.1221],[366937.9309,5465034.5635],[367230.1376,5464963.2419],[368014.398,5464771.82],[367393.186,5463402.329],[367391.4341,5463379.653],[367267.98,5461781.749],[367269.3258,5461775.2063],[367598.782,5460173.4366],[367936.4447,5458531.7683],[368255.2714,5456981.678],[368545.9098,5455568.6353],[368595.0437,5455329.7532],[368923.5926,5453732.3951],[369107.421,5452838.647],[369071.7769,5452120.1637],[369016.559,5451007.133],[369107.94,5450523.7745],[369411.9707,5448915.6061],[369720.2036,5447285.2107],[369965.4178,5445988.1524],[370028.5819,5445654.0462],[370331.379,5444052.4032],[370650.1664,5442366.1799],[370650.365,5442365.129],[371472.4199,5441126.6205],[371755.9254,5440699.4909],[372282.429,5439906.26],[372422.7587,5439124.5198],[372714.1737,5437501.122],[372944.9034,5436215.7861],[372999.4328,5435912.0169],[373265.5767,5434429.3982],[373559.9075,5432789.757],[373852.6344,5431159.0509],[374159.1437,5429451.5665],[374305.1022,5428638.4694],[374450.0366,5427831.0772],[374742.2898,5426203.0097],[375034.7177,5424573.9697],[375328.4555,5422937.6318],[375622.2821,5421300.7998],[375714.1927,5420788.7894],[376517.4923,5416313.8142],[376584.508,5415940.487],[376494.045,5414633.5311],[376402.2309,5414579.0054],[375891.834,5414275.896],[376038.462,5413665.258],[375933.8526,5413163.8157],[375804.374,5412543.164],[376141.5058,5411563.7081],[376320.015,5411045.092],[375520.579,5410605.3505],[375433.703,5410557.563],[375094.377,5410157.67],[375054.1728,5409976.1578],[374907.8781,5409315.6731],[375262.01,5408374.7152],[375464.5085,5407836.6598],[375543.641,5407626.398],[375470.7548,5406739.6124],[375456.884,5406570.851],[375547.938,5405434.414],[375610.4923,5405085.1001],[375776.781,5404156.515],[376050.3401,5403832.238],[376738.2056,5403457.944],[376793.05,5403428.101],[376948.6493,5403288.4788],[377489.375,5402803.275],[377981.034,5402151.805],[378310.5382,5401883.909],[378538.6724,5401698.4296],[378580.337,5401664.555],[379051.91,5400867.2],[379040.377,5400305.847],[379110.5351,5400226.6484],[379321.597,5399988.3891],[380084.5577,5399742.5458],[380145.434,5399722.93],[380950.928,5399513.897],[381564.463,5398892.9461],[381721.3865,5398798.5205],[382132.1715,5398551.3386],[382250.772,5398479.973],[382603.042,5398087.677],[382952.266,5397508.274],[383221.953,5397277.143],[383289.8692,5397264.637],[384622.751,5397019.2],[385083.3248,5397048.9605],[385558.774,5397079.682],[386055.792,5396903.666],[386079.6445,5396876.9065],[386293.027,5396637.517],[386721.9553,5395643.1239],[386761.869,5395550.591],[387209.0031,5395376.619],[387812.085,5395402.1901],[388320.6939,5395302.441],[388352.22,5395296.258],[388946.149,5395262.519],[389139.7782,5395181.5872],[389655.136,5394966.181],[389931.0962,5394959.2778],[390627.575,5394941.8551],[391539.1714,5394807.0315],[391781.625,5394771.1731],[392329.955,5394606.7811],[392789.235,5394382.371],[393117.957,5394280.336],[393164.2893,5394285.6831],[393545.273,5394329.651],[394120.036,5394531.266],[394639.071,5395068.8871],[394785.7823,5395220.852],[394781.5943,5395065.8629],[394748.5365,5393440.8328],[394707.4793,5391839.8035],[394689.4227,5390238.7733],[394677.3664,5388641.7429],[394669.31,5387040.7123],[394658.2539,5385450.6819],[394647.1972,5383842.6512],[394620.1401,5382236.621],[394570.0819,5380618.5914],[394511.0238,5379014.5623],[394444.965,5377400.5332],[394393.9069,5375792.5037],[394361.8496,5374192.4736],[394365.7925,5372600.4441],[394356.7275,5370993.424],[394324.6619,5369394.4048],[394316.5966,5367778.3846],[394297.5311,5366171.3647],[394260.4649,5364562.3454],[394222.3992,5362968.3263],[394199.3326,5361339.3062],[394194.2682,5359746.286],[394174.1398,5358130.7034],[392816.1457,5358158.6834],[392569.1041,5358162.0661],[391213.0785,5358180.4835],[390957.0365,5358183.7415],[389596.0419,5358201.5341],[389460.63,5358203.0383],[389337.0311,5358206.3547],[388028.9572,5358241.4597],[387741.0115,5358245.2816],[386422.9113,5358262.6373],[386104.9961,5358270.5852],[384931.8692,5358296.5613],[384508.8885,5358306.0128],[383317.8237,5358332.552],[382887.8429,5358343.8787],[381708.7785,5358374.6676],[381280.7974,5358377.8691],[380099.7321,5358386.7827],[379680.8454,5358397.9216],[378493.6868,5358422.3982],[378051.6745,5358434.2253],[377758.1661,5358439.1725],[376887.6414,5358453.8261],[376464.6292,5358458.465],[376358.0324,5358459.656],[375346.5971,5358469.4392],[374844.5202,5358474.2681],[373355.5398,5358484.3169],[373221.3796,5358484.1962],[371752.4946,5358519.7448],[371650.2417,5358521.7482],[370142.4527,5358562.4819],[370019.4823,5358566.0464],[368548.4615,5358601.9452],[368424.3972,5358604.1972],[366926.4381,5358632.3463],[366805.4051,5358634.5982],[365327.3532,5358676.0599],[365210.3203,5358679.3118],[363728.3614,5358706.9606],[363603.3284,5358709.0876],[362120.338,5358731.7988],[361998.2737,5358733.4882],[360513.3148,5358761.7621],[360395.2505,5358763.764],[358913.3231,5358795.6629],[358792.1338,5358797.9774],[357317.2696,5358843.4391],[357177.2363,5358846.3789],[355800.2791,5358876.4011],[355575.2446,5358881.2798],[354210.2256,5358923.3023],[353972.2535,5358929.3687],[352600.2028,5358964.3285],[352369.1994,5358967.7697],[350984.2215,5358990.3312],[350733.1272,5358994.4536],[349370.2502,5359027.5646],[349134.9685,5359032.7496],[347760.217,5359076.0484],[347527.1541,5359080.796],[346146.1829,5359108.8441],[345935.12,5359112.9043],[344534.211,5359137.1395],[344401.4919,5359139.1381],[344328.1793,5359141.3249],[342932.1775,5359182.2483],[342710.2396,5359186.6835],[342132.051,5359198.1774],[341324.1745,5359214.794],[341101.1428,5359219.3542],[339723.2029,5359251.2149],[339506.0463,5359255.9626],[338085.2003,5359293.5106],[337894.075,5359298.0087],[337181.3865,5359319.6265],[336569.073,5359335.4327],[336270.1662,5359343.1797],[336285.1588,5360859.2444],[336286.3218,5360978.3745],[336324.5002,5362464.3132],[336327.1946,5362585.3808],[336362.7176,5364088.3827],[336364.7228,5364179.4491],[336402.4964,5365693.4514],[336405.2219,5365811.4564],[336409.6987,5365953.4625],[336448.7435,5367290.5823],[336452.6261,5367423.5255],[336497.3988,5368922.6521],[336504.5907,5369000.468],[336560.9583,5370521.0956],[336562.7436,5370591.6611],[336602.8965,5372184.7291],[336645.989,5373813.7986],[336697.1519,5375350.5928],[336698.1555,5375437.8448],[336715.279,5376940.8799],[336716.2203,5377034.8821],[336735.1933,5378678.9205],[335222.1916,5378714.0408],[335105.004,5378716.728],[333650.2473,5378751.5936],[333521.2758,5378754.0282],[332029.1515,5378813.2455],[331903.0864,5378818.4303],[330416.9935,5378881.1479],[330286.2096,5378886.6451],[328801.1468,5378918.7995],[328680.988,5378921.7968],[327188.0511,5378984.0144],[327092.0491,5378987.8873],[327153.1089,5380605.8118],[327206.1679,5382204.8605],[327253.2269,5383809.9092],[327286.2851,5385402.9572],[327349.3458,5387048.0073],[327384.4043,5388651.0556],[327439.463,5390245.104],[327495.5228,5391870.1532],[327553.5817,5393471.2017],[327596.6402,5395070.2499],[327634.6995,5396699.2988],[327682.7545,5398200.3441],[328586.9652,5398170.7274],[329300.7959,5398147.3589],[330191.85,5398118.6796],[330435.325,5398110.8693],[330885.8991,5398098.811],[331798.7663,5398071.257],[332522.9099,5398050.3887],[333342.2434,5398026.8338],[333421.9017,5398024.3971],[334121.9198,5398005.4036],[335020.9368,5397974.5867],[335728.0724,5397955.3895],[336649.8987,5397928.5642],[337341.5341,5397908.4921],[338229.9222,5397878.6048],[338774.0553,5397862.2222],[339833.9773,5397829.3326],[340395.0481,5397811.8873],[341447.9386,5397774.9976],[342011.1972,5397763.6775],[343071.9633,5397738.4755],[343337.6236,5397732.1593],[343615.8463,5397721.5305],[344643.1113,5397684.6412],[344755.488,5397680.0146],[345183.2758,5397671.3213],[346269.1049,5397649.244],[346306.1814,5399284.2691],[346336.2563,5400889.2938],[346382.2881,5402503.3417],[346412.2673,5404110.4175],[346456.2467,5405712.4928],[346496.226,5407328.5688],[346501.9859,5408958.3957],[346553.4031,5410558.8457],[346605.1638,5412176.7965],[346638.1433,5413777.8716],[346683.123,5415377.9465],[346709.1024,5416991.0219],[346743.082,5418597.097],[346776.0614,5420222.1728],[346787.7099,5420753.01],[346751.4922,5420748.6347],[346689.4926,5420709.6326],[346566.9314,5420596.1268],[346551.0566,5420573.6257],[346438.964,5420467.3703],[346368.8708,5420413.43],[346362.3402,5420360.2401],[346329.6225,5420277.2986],[346289.7052,5420232.8438],[346285.0605,5420227.6711],[346076.6562,5420037.5991],[345987.4073,5419933.2815],[345899.4703,5419874.7785],[345821.4397,5419810.7128],[345717.7216,5419732.2714],[345538.1918,5419577.0763],[345421.0677,5419473.5087],[345332.4122,5419392.1298],[345190.1629,5419299.3752],[345164.2784,5419288.0512],[345146.4443,5419280.2492],[345112.6008,5419250.6228],[345080.8512,5419203.1831],[345084.9142,5419167.494],[345051.9151,5419071.8646],[344999.0096,5418997.1111],[344910.0729,5418902.9192],[344767.9172,5418815.3524],[344605.1991,5418715.5351],[344594.4492,5418695.4717],[344563.668,5418683.6586],[344526.9446,5418652.8127],[344425.8563,5418567.9032],[344384.7002,5418548.7148],[344340.5441,5418514.3382],[344248.3878,5418490.0869],[343800.7639,5418245.7629],[343722.7325,5418229.8246],[343616.7639,5418179.0723],[343569.7019,5418113.8819],[343529.5241,5418116.4922],[343507.1704,5418117.9444],[343477.7644,5418081.8803],[343286.5148,5417968.8752],[343114.3584,5417910.8725],[342879.6081,5417852.3697],[342864.4834,5417816.1182],[342710.7333,5417765.9284],[342635.5457,5417740.5522],[342528.2956,5417704.4256],[342343.9824,5417702.2378],[342203.0757,5417684.7369],[342004.3874,5417680.1115],[341934.1422,5417678.1595],[341824.4492,5417675.1112],[341658.4797,5417694.8618],[341537.8541,5417701.0495],[341370.8224,5417673.2982],[341318.6976,5417622.6086],[341127.041,5417569.4813],[340928.0093,5417512.0413],[340713.29,5417468.4769],[340459.2579,5417430.1002],[340265.3955,5417403.6474],[340216.9446,5417397.0362],[340060.069,5417380.723],[339819.7871,5417318.8455],[339730.1621,5417268.906],[339624.7556,5417236.3422],[339538.6615,5417226.5918],[339447.63,5417197.2781],[339363.2547,5417183.9651],[339315.2208,5417165.6031],[339276.5983,5417150.8388],[339045.1286,5417120.15],[338824.5655,5417055.21],[338685.2522,5417068.023],[338655.5859,5417060.0139],[338541.2518,5417029.1465],[338288.0008,5416986.3949],[338095.2187,5416974.7695],[337898.7488,5416997.2704],[337873.3738,5416990.5826],[337862.2175,5416987.645],[337820.0612,5416941.1433],[337657.4042,5416948.2686],[337604.7791,5416918.08],[337547.435,5416913.9548],[337463.3098,5416869.2032],[337337.1842,5416872.0158],[337295.4029,5416843.4523],[337244.9652,5416826.6392],[337192.1837,5416828.5143],[337183.2461,5416828.8893],[337157.2996,5416818.99],[336859.37,5416705.3224],[336767.5571,5416680.4466],[336600.1813,5416677.009],[336433.493,5416662.7586],[336252.8983,5416669.3839],[336099.3037,5416681.6969],[335913.0838,5416716.1983],[335839.3646,5416741.9492],[335722.5514,5416759.6374],[335609.2071,5416772.8879],[335565.7693,5416782.2632],[335564.0044,5416782.6473],[335489.9564,5416798.7638],[335350.9867,5416868.9538],[335251.2985,5416933.7686],[335195.1419,5416942.9564],[335153.2043,5416907.2677],[335074.0164,5416925.9558],[335034.1411,5416940.1438],[334997.5157,5416953.9568],[334927.4524,5416989.1455],[334698.481,5417064.7105],[334613.855,5417123.15],[334540.354,5417211.778],[334437.256,5417313.7847],[334434.2902,5417316.7191],[334130.3806,5417435.2857],[334075.5363,5417469.9119],[334043.3796,5417498.9129],[333991.0666,5417528.9764],[333968.6187,5417541.8877],[333935.9722,5417560.665],[333851.5963,5417626.6673],[333790.3143,5417699.7323],[333776.0329,5417733.171],[333748.9388,5417761.922],[333516.0301,5417873.2384],[333431.6855,5417941.8658],[333282.8715,5418060.7449],[333239.5585,5418140.8103],[333225.8396,5418192.0621],[333269.2461,5418282.2527],[333263.5273,5418343.5048],[333216.2768,5418377.9436],[333194.1829,5418404.007],[333158.9325,5418415.2574],[333146.0887,5418410.5072],[333109.1196,5418363.3806],[333088.3694,5418351.3177],[333022.3376,5418350.8177],[332959.087,5418360.318],[332922.6491,5418417.32],[332867.8674,5418454.5714],[332799.9605,5418477.0097],[332607.1462,5418571.7631],[332508.7704,5418595.0765],[332447.4886,5418584.2636],[332419.3946,5418580.076],[332381.5192,5418588.8263],[332368.3834,5418594.6606],[332313.8311,5418618.8899],[332294.3935,5418647.3909],[332242.893,5418793.7712],[332201.8614,5418863.6487],[332162.2049,5418897.8999],[332092.0168,5418927.9635],[332090.298,5418956.027],[332129.3921,5418987.7781],[332122.8608,5419023.5919],[332115.088,5419037.4962],[332108.3607,5419049.5303],[332076.0792,5419073.2812],[331977.0784,5419076.4064],[331921.7029,5419093.282],[331907.5466,5419129.3458],[331880.8276,5419170.7223],[331820.3271,5419187.7854],[331687.8885,5419176.5976],[331621.6379,5419171.035],[331590.794,5419184.4105],[331571.4813,5419192.9108],[331499.9808,5419266.226],[331415.5739,5419329.7908],[331437.4492,5419388.4179],[331446.793,5419399.9183],[331449.1055,5419402.7309],[331451.9493,5419406.231],[331454.8243,5419409.7937],[331457.6681,5419413.2938],[331459.8244,5419415.9189],[331464.2307,5419421.3566],[331475.6058,5419435.3571],[331485.7309,5419447.795],[331498.9497,5419471.4833],[331512.6999,5419496.1717],[331521.95,5419512.7973],[331539.3251,5419543.4859],[331542.8564,5419549.6736],[331560.2316,5419579.9872],[331567.1067,5419591.9876],[331573.138,5419604.3005],[331587.2319,5419633.1765],[331590.4506,5419639.7393],[331598.607,5419656.4274],[331606.3883,5419665.3027],[331607.8571,5419666.9902],[331610.5758,5419670.1153],[331613.6696,5419673.6155],[331617.1071,5419677.5531],[331619.2947,5419680.0532],[331621.1697,5419682.1783],[331623.451,5419684.8033],[331625.0447,5419686.6159],[331630.076,5419692.3661],[331640.3886,5419704.1165],[331661.7013,5419736.5552],[331662.4513,5419761.9936],[331662.8576,5419774.5565],[331630.5761,5419798.4324],[331474.1687,5419836.2464],[331347.2304,5419923.9372],[331270.9486,5420005.0652],[331194.3858,5420162.4459],[331163.1044,5420219.2605],[331045.4162,5420309.0764],[331033.6661,5420317.9517],[331014.1035,5420333.0148],[330942.6344,5420406.3926],[330913.853,5420463.1446],[330867.4153,5420525.647],[330812.5087,5420557.7732],[330810.3831,5420560.0338],[330746.0397,5420628.4634],[330697.0621,5420724.6663],[330650.1332,5420816.8453],[330627.1019,5420893.7231],[330577.6331,5421022.2904],[330538.2268,5421112.7312],[330477.8518,5421251.5489],[330410.7267,5421383.1788],[330291.6954,5421648.5011],[330104.633,5422099.018],[330017.4145,5422322.7763],[330008.5894,5422345.6491],[329923.196,5422566.973],[329885.7276,5422753.6674],[329925.1344,5422879.5469],[329908.2907,5422910.5481],[329882.8536,5423076.4292],[329878.2916,5423262.1236],[329900.5734,5423408.8789],[329930.73,5423481.6315],[329972.3865,5423513.3825],[330198.0438,5423580.2593],[330257.3253,5423608.9477],[330349.4509,5423712.8262],[330461.6393,5423892.3949],[330503.411,5423937.122],[330556.2024,5423993.6483],[330635.9839,5424026.8368],[330760.6093,5424030.7115],[330850.1097,5424048.3369],[330898.0359,5424053.1635],[330946.9225,5424058.0869],[330962.5476,5424070.3373],[330963.9852,5424115.964],[330977.1415,5424130.8395],[331026.329,5424078.5249],[331051.5791,5424072.7121],[331074.7354,5424082.1499],[331073.0167,5424107.5883],[331019.1417,5424175.2784],[330926.079,5424206.1548],[330899.3856,5424218.4133],[330843.3288,5424244.1565],[330837.0164,5424287.6581],[330844.9539,5424297.5334],[330870.329,5424296.7208],[330877.579,5424283.8453],[330899.753,5424263.3906],[330914.6415,5424249.6565],[331003.298,5424239.2808],[331080.7669,5424196.3415],[331140.2045,5424146.2145],[331142.0795,5424140.1518],[331151.7982,5424107.7131],[331137.2043,5424047.2109],[331129.2043,5424034.773],[331083.9227,5423964.9581],[331083.5165,5423952.2702],[331093.3915,5423944.3949],[331144.3604,5423947.8323],[331201.7044,5423994.3963],[331228.2671,5424034.3352],[331258.9236,5424122.2758],[331265.5801,5424256.7806],[331226.5489,5424395.1607],[331163.0489,5424478.4139],[331028.33,5424561.2923],[330955.2048,5424578.7932],[330902.3001,5424575.2462],[330850.7983,5424571.7933],[330818.4545,5424595.6068],[330768.0483,5424691.2354],[330733.6108,5424730.362],[330693.2045,5424739.2999],[330669.9857,5424727.1746],[330669.1418,5424699.2986],[330738.1417,5424544.7302],[330736.6103,5424493.9784],[330708.3915,5424487.1657],[330688.5789,5424502.9789],[330650.6726,5424509.2292],[330573.36,5424557.3562],[330503.2037,5424589.9826],[330486.3599,5424620.9838],[330320.2349,5424758.2394],[330289.235,5424825.2419],[330288.2351,5424876.1188],[330324.3293,5424976.6223],[330341.9858,5425054.8126],[330316.4234,5425134.3781],[330251.6109,5425174.5048],[330228.3923,5425246.32],[330153.9863,5425390.8881],[330131.4553,5425485.7041],[330133.0694,5425538.6576],[330134.3931,5425582.0826],[330162.2684,5425662.5855],[330231.0815,5425835.904],[330239.7071,5426036.3488],[330207.8634,5426075.5379],[330184.0198,5426126.9774],[330150.458,5426361.8611],[330116.2081,5426403.5503],[330006.3335,5426551.7436],[329973.1462,5426631.5592],[329908.1778,5426750.3764],[329870.6784,5426937.0709],[329868.335,5427028.5742],[329861.494,5427145.2662],[329858.3356,5427199.143],[329843.8987,5427392.7127],[329823.8996,5427655.16],[329835.9311,5427715.7246],[329836.869,5427830.1038],[329828.9633,5427987.8597],[329867.9639,5428184.9292],[329930.0583,5428388.8739],[329953.2773,5428482.1897],[330072.8441,5428762.6227],[330095.5282,5428815.8261],[330243.3102,5429162.0255],[330257.154,5429199.7143],[330354.4043,5429389.9082],[330433.3419,5429478.9735],[330461.5921,5429572.1017],[330462.4359,5429600.1027],[330449.936,5429605.5405],[330429.311,5429596.0403],[330394.8422,5429548.7887],[330360.9047,5429519.3504],[330315.6861,5429535.9762],[330290.9988,5429559.5397],[330251.7803,5429609.0418],[330273.0616,5429638.8552],[330291.3743,5429739.9838],[330277.3432,5429778.5478],[330132.7502,5429871.8646],[330081.6632,5429937.0852]]],"type":"Polygon"},"id":"39","properties":{"Area":4608320923.49768,"CTYONLY_":2,"Code":"LOTW","LASTMOD":"1976-07-04T12:00:00Z","Name":"Lake of the Woods","Perimiter":388250.14572},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=1&offset=0&crs=http://www.opengis.net/def/crs/EPSG/0/32615","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=1&offset=0&crs=http://www.opengis.net/def/crs/EPSG/0/32615","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=1&offset=1&crs=http://www.opengis.net/def/crs/EPSG/0/32615","rel":"next","title":"next page","type":"application/geo+json"}],"numberMatched":117,"numberReturned":1,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_collections_mn_counties_items_with_headers.txt b/msautotest/api/expected/ogcapi_collections_mn_counties_items_with_headers.txt new file mode 100644 index 0000000000..539cb12e36 --- /dev/null +++ b/msautotest/api/expected/ogcapi_collections_mn_counties_items_with_headers.txt @@ -0,0 +1,9 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +Link: ; rel="next"; title="next page"; type="application/geo+json" +OGC-NumberMatched: 117 +OGC-NumberReturned: 9 + +{"features":[{"geometry":{"coordinates":[[[-95.3231,48.999],[-95.3109,48.999],[-95.2889,48.9989],[-95.2852,48.9989],[-95.2669,48.9989],[-95.245,48.9989],[-95.2232,48.9989],[-95.2014,48.9989],[-95.1792,48.9989],[-95.1574,48.9989],[-95.1531,48.9989],[-95.1531,49.0031],[-95.1532,49.0179],[-95.1532,49.0325],[-95.1532,49.047],[-95.1532,49.0619],[-95.1532,49.0765],[-95.1532,49.0911],[-95.1532,49.1057],[-95.1532,49.1205],[-95.1532,49.1354],[-95.1532,49.1499],[-95.1532,49.1642],[-95.1532,49.1788],[-95.1532,49.1807],[-95.1532,49.1931],[-95.1532,49.1966],[-95.1532,49.2077],[-95.1533,49.2131],[-95.1533,49.2219],[-95.1533,49.2308],[-95.1533,49.2365],[-95.1533,49.2472],[-95.1533,49.2512],[-95.1533,49.2655],[-95.1533,49.2697],[-95.1533,49.2802],[-95.1533,49.2882],[-95.1533,49.2945],[-95.1533,49.3072],[-95.1533,49.309],[-95.1533,49.3234],[-95.1533,49.3237],[-95.1533,49.3381],[-95.1533,49.3476],[-95.1533,49.3525],[-95.1533,49.3636],[-95.1533,49.367],[-95.1533,49.3705],[-95.1533,49.3776],[-95.1533,49.3813],[-95.1533,49.3845],[-95.1503,49.383],[-95.1499,49.3813],[-95.1498,49.3807],[-95.1467,49.3802],[-95.145,49.3784],[-95.1418,49.3784],[-95.1397,49.3762],[-95.1367,49.3751],[-95.1324,49.3736],[-95.1287,49.3705],[-95.1171,49.367],[-95.1159,49.3666],[-95.1145,49.3666],[-95.1098,49.3664],[-95.1031,49.3652],[-95.1031,49.3636],[-95.0926,49.3617],[-95.0897,49.3612],[-95.0707,49.3564],[-95.0582,49.3533],[-95.0495,49.3532],[-95.0479,49.3533],[-95.0262,49.3554],[-95.0141,49.3565],[-95.0047,49.3612],[-94.993,49.367],[-94.9889,49.369],[-94.9818,49.3684],[-94.9742,49.3678],[-94.9597,49.3699],[-94.9573,49.3702],[-94.952,49.3688],[-94.948,49.367],[-94.9376,49.3625],[-94.9152,49.3529],[-94.9143,49.3524],[-94.909,49.3502],[-94.9065,49.3484],[-94.8933,49.3414],[-94.8865,49.3378],[-94.8782,49.3334],[-94.8712,49.3308],[-94.854,49.3244],[-94.8492,49.3244],[-94.8363,49.3243],[-94.8311,49.3236],[-94.8271,49.323],[-94.8162,49.3214],[-94.8243,49.309],[-94.8243,49.3088],[-94.8255,49.2944],[-94.8255,49.2943],[-94.8204,49.28],[-94.8152,49.2653],[-94.8103,49.2515],[-94.8059,49.2388],[-94.8051,49.2367],[-94.8001,49.2224],[-94.7973,49.2144],[-94.7975,49.2079],[-94.7979,49.1979],[-94.7965,49.1936],[-94.7918,49.1792],[-94.7871,49.1646],[-94.7833,49.153],[-94.7823,49.15],[-94.7776,49.1357],[-94.7727,49.1206],[-94.7727,49.1206],[-94.7611,49.1096],[-94.7571,49.1058],[-94.7496,49.0988],[-94.7474,49.0918],[-94.7429,49.0773],[-94.7394,49.0657],[-94.7385,49.063],[-94.7344,49.0497],[-94.7299,49.0351],[-94.7254,49.0205],[-94.7207,49.0052],[-94.7184,48.9979],[-94.7162,48.9907],[-94.7117,48.9761],[-94.7072,48.9615],[-94.7027,48.9468],[-94.6982,48.9322],[-94.6968,48.9276],[-94.6844,48.8875],[-94.6834,48.8842],[-94.6842,48.8724],[-94.6855,48.8719],[-94.6923,48.8691],[-94.6902,48.8636],[-94.6914,48.8591],[-94.693,48.8535],[-94.6881,48.8447],[-94.6855,48.8401],[-94.6963,48.836],[-94.6975,48.8355],[-94.702,48.8319],[-94.7025,48.8302],[-94.7042,48.8243],[-94.6991,48.8159],[-94.6962,48.8111],[-94.6951,48.8092],[-94.6958,48.8012],[-94.6959,48.7997],[-94.6944,48.7895],[-94.6934,48.7864],[-94.6909,48.7781],[-94.687,48.7752],[-94.6776,48.772],[-94.6768,48.7717],[-94.6746,48.7705],[-94.6671,48.7662],[-94.6603,48.7605],[-94.6557,48.7581],[-94.6525,48.7565],[-94.652,48.7562],[-94.6453,48.7491],[-94.6453,48.7441],[-94.6443,48.7434],[-94.6414,48.7413],[-94.631,48.7392],[-94.6301,48.739],[-94.6191,48.7373],[-94.6106,48.7318],[-94.6084,48.731],[-94.6028,48.7289],[-94.6011,48.7283],[-94.5962,48.7248],[-94.5913,48.7197],[-94.5876,48.7176],[-94.5867,48.7175],[-94.5685,48.7156],[-94.5622,48.7159],[-94.5558,48.7163],[-94.549,48.7148],[-94.5487,48.7146],[-94.5457,48.7124],[-94.5396,48.7036],[-94.539,48.7028],[-94.5329,48.7013],[-94.5247,48.7016],[-94.5178,48.7008],[-94.5173,48.7008],[-94.5093,48.7006],[-94.5066,48.6999],[-94.4996,48.698],[-94.4958,48.698],[-94.4863,48.698],[-94.4739,48.6969],[-94.4706,48.6966],[-94.4631,48.6953],[-94.4568,48.6933],[-94.4523,48.6925],[-94.4517,48.6925],[-94.4465,48.693],[-94.4388,48.6949],[-94.4319,48.6998],[-94.4299,48.7012],[-94.4299,48.6998],[-94.43,48.6852],[-94.4301,48.6708],[-94.43,48.6564],[-94.4297,48.642],[-94.4294,48.6276],[-94.4292,48.6133],[-94.4289,48.5988],[-94.4289,48.5844],[-94.4291,48.5698],[-94.4295,48.5554],[-94.43,48.5409],[-94.4303,48.5264],[-94.4303,48.512],[-94.4299,48.4977],[-94.4296,48.4832],[-94.4296,48.4688],[-94.4293,48.4543],[-94.4292,48.4399],[-94.4293,48.4254],[-94.4294,48.411],[-94.4293,48.3964],[-94.4289,48.3821],[-94.4288,48.3675],[-94.4471,48.3675],[-94.4505,48.3675],[-94.4688,48.3675],[-94.4722,48.3674],[-94.4906,48.3674],[-94.4924,48.3674],[-94.4941,48.3674],[-94.5118,48.3675],[-94.5157,48.3674],[-94.5335,48.3674],[-94.5378,48.3674],[-94.5536,48.3674],[-94.5593,48.3674],[-94.5754,48.3674],[-94.5812,48.3674],[-94.5971,48.3675],[-94.6029,48.3674],[-94.6188,48.3673],[-94.6245,48.3673],[-94.6405,48.3673],[-94.6465,48.3673],[-94.6505,48.3673],[-94.6622,48.3673],[-94.6679,48.3673],[-94.6694,48.3672],[-94.683,48.3671],[-94.6898,48.3671],[-94.7099,48.3669],[-94.7117,48.3668],[-94.7315,48.3669],[-94.7329,48.3669],[-94.7533,48.3669],[-94.7549,48.3669],[-94.7748,48.3669],[-94.7765,48.3669],[-94.7967,48.3669],[-94.7983,48.3669],[-94.8183,48.3669],[-94.8199,48.3669],[-94.8399,48.3669],[-94.8416,48.3669],[-94.8616,48.3667],[-94.8632,48.3667],[-94.8833,48.3667],[-94.8849,48.3666],[-94.9049,48.3666],[-94.9065,48.3666],[-94.9264,48.3667],[-94.9283,48.3667],[-94.9469,48.3666],[-94.95,48.3666],[-94.9684,48.3667],[-94.9716,48.3667],[-94.9901,48.3667],[-94.9932,48.3667],[-95.0119,48.3665],[-95.0153,48.3665],[-95.0337,48.3665],[-95.0369,48.3665],[-95.0555,48.3665],[-95.0586,48.3665],[-95.0773,48.3664],[-95.0801,48.3664],[-95.099,48.3663],[-95.1008,48.3663],[-95.1018,48.3663],[-95.1207,48.3663],[-95.1236,48.3663],[-95.1315,48.3662],[-95.1424,48.3662],[-95.1454,48.3662],[-95.164,48.3661],[-95.1669,48.3661],[-95.1861,48.3661],[-95.1887,48.3661],[-95.1983,48.3661],[-95.2066,48.3661],[-95.2106,48.3661],[-95.211,48.3797],[-95.211,48.3808],[-95.2111,48.3941],[-95.2111,48.3952],[-95.2112,48.4087],[-95.2112,48.4096],[-95.2113,48.4232],[-95.2113,48.4242],[-95.2113,48.4255],[-95.2113,48.4376],[-95.2113,48.4387],[-95.2113,48.4522],[-95.2112,48.4529],[-95.211,48.4666],[-95.211,48.4673],[-95.2111,48.4816],[-95.2112,48.4962],[-95.2111,48.5101],[-95.2111,48.5109],[-95.2115,48.5244],[-95.2115,48.5252],[-95.2119,48.54],[-95.2324,48.5399],[-95.2339,48.5399],[-95.2537,48.5398],[-95.2554,48.5398],[-95.2756,48.54],[-95.2773,48.54],[-95.2975,48.5401],[-95.2992,48.5402],[-95.3194,48.54],[-95.321,48.54],[-95.3412,48.5402],[-95.3425,48.5402],[-95.3424,48.5548],[-95.3423,48.5691],[-95.3423,48.5836],[-95.3426,48.5979],[-95.3424,48.6127],[-95.3426,48.6271],[-95.3425,48.6415],[-95.3424,48.6561],[-95.3423,48.6705],[-95.3424,48.6849],[-95.3425,48.6995],[-95.3425,48.7131],[-95.3302,48.713],[-95.3205,48.713],[-95.3084,48.713],[-95.3051,48.713],[-95.299,48.713],[-95.2866,48.713],[-95.2767,48.713],[-95.2656,48.713],[-95.2645,48.713],[-95.255,48.713],[-95.2427,48.713],[-95.2331,48.713],[-95.2206,48.713],[-95.2112,48.713],[-95.1991,48.713],[-95.1917,48.713],[-95.1773,48.713],[-95.1697,48.7129],[-95.1554,48.7129],[-95.1477,48.7129],[-95.1333,48.713],[-95.1297,48.713],[-95.1259,48.7129],[-95.1119,48.7129],[-95.1104,48.7129],[-95.1046,48.7129],[-95.0898,48.713],[-95.0899,48.7277],[-95.0901,48.7421],[-95.0901,48.7566],[-95.0903,48.7711],[-95.0903,48.7855],[-95.0903,48.8],[-95.0909,48.8147],[-95.0908,48.8291],[-95.0907,48.8436],[-95.0908,48.858],[-95.0908,48.8724],[-95.0911,48.8869],[-95.0912,48.9014],[-95.0914,48.916],[-95.0914,48.9208],[-95.0919,48.9207],[-95.0927,48.9204],[-95.0944,48.9193],[-95.0946,48.9191],[-95.0961,48.9181],[-95.097,48.9176],[-95.0971,48.9172],[-95.0975,48.9164],[-95.098,48.916],[-95.0981,48.9159],[-95.1008,48.9142],[-95.102,48.9132],[-95.1032,48.9127],[-95.1042,48.9121],[-95.1056,48.9113],[-95.108,48.9099],[-95.1096,48.9089],[-95.1107,48.9082],[-95.1126,48.9073],[-95.113,48.9072],[-95.1132,48.9071],[-95.1137,48.9069],[-95.1141,48.9064],[-95.114,48.9061],[-95.1144,48.9052],[-95.1151,48.9046],[-95.1163,48.9037],[-95.1182,48.9029],[-95.1204,48.9019],[-95.1205,48.9017],[-95.121,48.9016],[-95.1214,48.9013],[-95.1228,48.9006],[-95.1233,48.9004],[-95.1239,48.9001],[-95.1252,48.8998],[-95.1312,48.8975],[-95.1322,48.8973],[-95.1337,48.8969],[-95.1343,48.8963],[-95.1348,48.8963],[-95.1351,48.8963],[-95.1355,48.8959],[-95.1381,48.8949],[-95.1404,48.8943],[-95.1436,48.8937],[-95.1438,48.8934],[-95.1459,48.8929],[-95.1469,48.8927],[-95.1483,48.8923],[-95.1508,48.8922],[-95.1528,48.8921],[-95.1555,48.892],[-95.1564,48.8919],[-95.1579,48.8919],[-95.1602,48.892],[-95.1618,48.892],[-95.1641,48.8917],[-95.1648,48.8913],[-95.1674,48.8907],[-95.1701,48.8902],[-95.173,48.8897],[-95.1764,48.8893],[-95.1791,48.889],[-95.1797,48.889],[-95.1819,48.8888],[-95.1851,48.8882],[-95.1863,48.8877],[-95.1877,48.8874],[-95.1889,48.8873],[-95.1901,48.887],[-95.1913,48.8868],[-95.1919,48.8866],[-95.1924,48.8865],[-95.1956,48.8862],[-95.1986,48.8855],[-95.2005,48.8856],[-95.2009,48.8855],[-95.2024,48.8852],[-95.2059,48.8848],[-95.2085,48.8846],[-95.2112,48.8848],[-95.2115,48.8847],[-95.2117,48.8847],[-95.2122,48.8842],[-95.2144,48.8843],[-95.2151,48.884],[-95.2159,48.8839],[-95.217,48.8835],[-95.2188,48.8835],[-95.2193,48.8832],[-95.22,48.8831],[-95.2207,48.8831],[-95.2208,48.8831],[-95.2212,48.883],[-95.2252,48.8819],[-95.2265,48.8816],[-95.2287,48.8815],[-95.231,48.8814],[-95.2335,48.8814],[-95.2356,48.8815],[-95.2381,48.8817],[-95.2391,48.8819],[-95.2407,48.8821],[-95.2423,48.8821],[-95.2429,48.8822],[-95.2429,48.8822],[-95.2439,48.8823],[-95.2458,48.8829],[-95.2472,48.8835],[-95.248,48.8836],[-95.2485,48.8832],[-95.2496,48.8834],[-95.2502,48.8835],[-95.2507,48.8836],[-95.2517,48.8839],[-95.2548,48.8845],[-95.256,48.885],[-95.257,48.8858],[-95.2585,48.8867],[-95.2585,48.8867],[-95.2627,48.8877],[-95.2635,48.888],[-95.2639,48.8883],[-95.2646,48.8885],[-95.265,48.8886],[-95.2654,48.8888],[-95.2666,48.8894],[-95.2674,48.89],[-95.2677,48.8903],[-95.268,48.8905],[-95.2713,48.8915],[-95.2724,48.8921],[-95.2745,48.8931],[-95.2751,48.8938],[-95.2753,48.8943],[-95.2748,48.8951],[-95.2749,48.8956],[-95.2755,48.8959],[-95.2759,48.8962],[-95.2763,48.8963],[-95.2765,48.8962],[-95.277,48.8958],[-95.2773,48.8957],[-95.2782,48.8956],[-95.279,48.8957],[-95.2796,48.8962],[-95.2803,48.8965],[-95.2813,48.8967],[-95.2839,48.8975],[-95.2853,48.8977],[-95.2861,48.8976],[-95.2865,48.8975],[-95.287,48.8976],[-95.2872,48.8977],[-95.2879,48.8979],[-95.2882,48.8981],[-95.289,48.8994],[-95.2896,48.9],[-95.2901,48.9003],[-95.2911,48.9006],[-95.2911,48.9008],[-95.2906,48.9011],[-95.2907,48.9014],[-95.2908,48.9016],[-95.2909,48.9017],[-95.2914,48.9019],[-95.2927,48.9019],[-95.2935,48.902],[-95.2937,48.9023],[-95.2941,48.9027],[-95.2949,48.9028],[-95.2967,48.9027],[-95.2976,48.9026],[-95.298,48.9027],[-95.2983,48.9028],[-95.2993,48.9035],[-95.3005,48.904],[-95.3002,48.9045],[-95.3001,48.9046],[-95.3001,48.9047],[-95.3,48.9047],[-95.3,48.9047],[-95.2999,48.9048],[-95.2999,48.9048],[-95.2999,48.9048],[-95.2997,48.905],[-95.2996,48.9051],[-95.2994,48.9053],[-95.2992,48.9055],[-95.2991,48.9057],[-95.2989,48.906],[-95.2988,48.906],[-95.2986,48.9063],[-95.2985,48.9064],[-95.2985,48.9065],[-95.2983,48.9068],[-95.2982,48.9068],[-95.2981,48.907],[-95.298,48.9071],[-95.298,48.9071],[-95.298,48.9071],[-95.2979,48.9071],[-95.2979,48.9072],[-95.2979,48.9072],[-95.2978,48.9072],[-95.2978,48.9072],[-95.2978,48.9073],[-95.2977,48.9073],[-95.2976,48.9074],[-95.2973,48.9077],[-95.2973,48.908],[-95.2973,48.9081],[-95.2978,48.9083],[-95.2999,48.9086],[-95.3017,48.9093],[-95.3027,48.91],[-95.3038,48.9114],[-95.3043,48.9119],[-95.3059,48.9127],[-95.3061,48.9128],[-95.3064,48.9129],[-95.3074,48.9135],[-95.3078,48.9141],[-95.3085,48.9146],[-95.3092,48.9149],[-95.3093,48.9149],[-95.3102,48.9155],[-95.3109,48.9163],[-95.3115,48.9172],[-95.3119,48.9178],[-95.3126,48.919],[-95.3132,48.9198],[-95.3141,48.921],[-95.315,48.9222],[-95.3168,48.9245],[-95.3195,48.9285],[-95.3208,48.9305],[-95.3209,48.9307],[-95.3222,48.9327],[-95.3228,48.9344],[-95.3223,48.9355],[-95.3225,48.9358],[-95.3229,48.9373],[-95.3231,48.9389],[-95.3228,48.9403],[-95.3225,48.9409],[-95.3219,48.9412],[-95.3189,48.9419],[-95.3181,48.9421],[-95.3168,48.9431],[-95.3154,48.9448],[-95.3148,48.9452],[-95.3141,48.9457],[-95.3131,48.946],[-95.3114,48.9461],[-95.3102,48.9463],[-95.3095,48.9463],[-95.3088,48.9464],[-95.3086,48.9465],[-95.3086,48.9469],[-95.3085,48.947],[-95.3078,48.9466],[-95.3074,48.9465],[-95.3071,48.9466],[-95.3071,48.9469],[-95.3079,48.9474],[-95.3092,48.9477],[-95.3096,48.9478],[-95.3103,48.948],[-95.3104,48.9484],[-95.3103,48.9485],[-95.31,48.9485],[-95.3099,48.9484],[-95.3096,48.9482],[-95.3094,48.9481],[-95.3081,48.948],[-95.3071,48.9477],[-95.3062,48.9472],[-95.3062,48.9472],[-95.3061,48.9469],[-95.3062,48.9463],[-95.3063,48.9462],[-95.3069,48.9456],[-95.3069,48.9455],[-95.3068,48.9454],[-95.3061,48.9454],[-95.3053,48.9459],[-95.305,48.9462],[-95.3046,48.947],[-95.3046,48.9482],[-95.3052,48.9495],[-95.3061,48.9502],[-95.3079,48.9509],[-95.3089,48.9511],[-95.3097,48.951],[-95.3104,48.951],[-95.3108,48.9512],[-95.3115,48.952],[-95.312,48.9524],[-95.3126,48.9524],[-95.3129,48.9523],[-95.3129,48.9521],[-95.3119,48.9507],[-95.3119,48.9502],[-95.3123,48.9502],[-95.3125,48.9503],[-95.3131,48.9503],[-95.3141,48.9508],[-95.3151,48.951],[-95.3154,48.9513],[-95.3177,48.9525],[-95.3181,48.9531],[-95.3182,48.9535],[-95.3177,48.9545],[-95.3175,48.9552],[-95.3179,48.9559],[-95.3188,48.9562],[-95.3191,48.9569],[-95.3202,48.9581],[-95.3206,48.959],[-95.3206,48.9595],[-95.3206,48.9598],[-95.3202,48.9606],[-95.3193,48.9622],[-95.3193,48.964],[-95.3198,48.9643],[-95.3201,48.9648],[-95.3207,48.9669],[-95.3212,48.9672],[-95.3227,48.9685],[-95.3232,48.9692],[-95.3241,48.9703],[-95.3247,48.972],[-95.3248,48.9728],[-95.3249,48.9738],[-95.325,48.9743],[-95.3253,48.976],[-95.3257,48.9784],[-95.3255,48.9789],[-95.3256,48.98],[-95.3257,48.9814],[-95.3253,48.9832],[-95.3245,48.985],[-95.3242,48.9859],[-95.3227,48.9884],[-95.3224,48.9889],[-95.3206,48.9921],[-95.3204,48.9924],[-95.3191,48.9941],[-95.3181,48.995],[-95.3178,48.9958],[-95.3178,48.9961],[-95.3179,48.9961],[-95.3182,48.996],[-95.3187,48.9956],[-95.3191,48.9953],[-95.3197,48.9954],[-95.3201,48.9956],[-95.3206,48.9961],[-95.3204,48.9964],[-95.3202,48.9973],[-95.3204,48.9976],[-95.3224,48.9984],[-95.3231,48.999]]],"type":"Polygon"},"id":"39","properties":{"Area":4608320923.49768,"CTYONLY_":2,"Code":"LOTW","LASTMOD":"1976-07-04T12:00:00Z","Name":"Lake of the Woods","Perimiter":388250.14572},"type":"Feature"},{"geometry":{"coordinates":[[[-96.4054,49.0001],[-96.4054,48.9947],[-96.4054,48.994],[-96.4054,48.9803],[-96.4054,48.9793],[-96.4053,48.9705],[-96.4053,48.9658],[-96.4053,48.9648],[-96.4053,48.9515],[-96.4053,48.9504],[-96.4053,48.9371],[-96.4053,48.936],[-96.4054,48.9225],[-96.4054,48.9214],[-96.4053,48.9137],[-96.4053,48.9081],[-96.4053,48.9068],[-96.405,48.8926],[-96.405,48.878],[-96.4047,48.8635],[-96.4045,48.8491],[-96.4043,48.8343],[-96.4042,48.8198],[-96.4042,48.8048],[-96.4042,48.7903],[-96.4045,48.7758],[-96.4047,48.7607],[-96.4048,48.7465],[-96.4048,48.7318],[-96.4049,48.7172],[-96.388,48.7172],[-96.3873,48.7172],[-96.3866,48.703],[-96.3874,48.6887],[-96.3871,48.6741],[-96.3877,48.6599],[-96.3879,48.6454],[-96.388,48.6313],[-96.389,48.6165],[-96.3891,48.6024],[-96.3884,48.5877],[-96.3882,48.5733],[-96.3879,48.5588],[-96.3882,48.5442],[-96.4101,48.544],[-96.4318,48.5438],[-96.4535,48.5436],[-96.4754,48.5435],[-96.4973,48.5434],[-96.518,48.5434],[-96.54,48.5434],[-96.5621,48.5436],[-96.5839,48.5437],[-96.6058,48.5437],[-96.6278,48.5437],[-96.6493,48.5437],[-96.6713,48.5436],[-96.6931,48.5437],[-96.7151,48.5437],[-96.7368,48.5437],[-96.7585,48.5436],[-96.7803,48.5435],[-96.8023,48.5436],[-96.824,48.5436],[-96.8459,48.5434],[-96.8678,48.5433],[-96.8896,48.5433],[-96.9115,48.5432],[-96.9138,48.5433],[-96.9331,48.5435],[-96.9551,48.5437],[-96.9768,48.544],[-96.9985,48.5441],[-97.0194,48.5441],[-97.0416,48.5442],[-97.0635,48.5441],[-97.0852,48.5441],[-97.107,48.544],[-97.1287,48.5439],[-97.1509,48.5439],[-97.1631,48.544],[-97.1637,48.5445],[-97.1659,48.5483],[-97.1662,48.5509],[-97.1661,48.5527],[-97.1654,48.5536],[-97.1645,48.554],[-97.1628,48.5543],[-97.1613,48.5539],[-97.1592,48.5528],[-97.1577,48.5518],[-97.1557,48.5512],[-97.1538,48.5513],[-97.1513,48.5515],[-97.1507,48.5515],[-97.1493,48.5516],[-97.1474,48.5516],[-97.1444,48.5514],[-97.1407,48.5515],[-97.1387,48.5522],[-97.1379,48.553],[-97.1379,48.5542],[-97.1391,48.5554],[-97.141,48.5566],[-97.1426,48.5571],[-97.1464,48.5573],[-97.1505,48.5574],[-97.1515,48.5574],[-97.1551,48.5574],[-97.1578,48.5573],[-97.1606,48.5571],[-97.1631,48.5571],[-97.1646,48.5572],[-97.167,48.5575],[-97.1697,48.5584],[-97.1721,48.5591],[-97.1727,48.5593],[-97.174,48.5599],[-97.1749,48.5606],[-97.1753,48.5614],[-97.1754,48.5623],[-97.1749,48.5631],[-97.1744,48.5639],[-97.1723,48.5648],[-97.1721,48.5648],[-97.1706,48.5652],[-97.1687,48.5655],[-97.167,48.5658],[-97.1651,48.5659],[-97.1613,48.5661],[-97.1541,48.5669],[-97.153,48.5671],[-97.1516,48.5677],[-97.1503,48.5688],[-97.1496,48.5695],[-97.1487,48.5707],[-97.1477,48.5727],[-97.1477,48.5728],[-97.1476,48.5731],[-97.1483,48.5763],[-97.15,48.5775],[-97.1501,48.5775],[-97.1548,48.5779],[-97.1592,48.5785],[-97.1605,48.58],[-97.16,48.5816],[-97.1578,48.5826],[-97.1562,48.5828],[-97.1541,48.5826],[-97.1524,48.5823],[-97.15,48.5815],[-97.1494,48.5813],[-97.1484,48.5811],[-97.1449,48.5815],[-97.1436,48.5824],[-97.1431,48.5834],[-97.1429,48.5838],[-97.142,48.5876],[-97.1418,48.5886],[-97.1415,48.5909],[-97.1422,48.5926],[-97.1433,48.5936],[-97.1451,48.594],[-97.1471,48.594],[-97.1497,48.5937],[-97.1525,48.594],[-97.1536,48.5949],[-97.1535,48.5957],[-97.1527,48.5962],[-97.1524,48.5969],[-97.1516,48.598],[-97.1498,48.5981],[-97.1497,48.5981],[-97.1463,48.5977],[-97.1443,48.5981],[-97.143,48.5987],[-97.1416,48.6002],[-97.1403,48.6021],[-97.14,48.6025],[-97.138,48.6044],[-97.1359,48.6054],[-97.1345,48.6065],[-97.1341,48.6075],[-97.1349,48.6082],[-97.1358,48.6086],[-97.137,48.6088],[-97.1396,48.6086],[-97.1443,48.6078],[-97.1474,48.6081],[-97.1494,48.6089],[-97.1495,48.609],[-97.1505,48.6115],[-97.1501,48.6124],[-97.1493,48.6129],[-97.1478,48.6138],[-97.145,48.6146],[-97.1408,48.6149],[-97.137,48.6144],[-97.134,48.6136],[-97.1319,48.6133],[-97.1309,48.6137],[-97.1289,48.614],[-97.1286,48.6153],[-97.1293,48.6168],[-97.1295,48.617],[-97.1311,48.6184],[-97.1342,48.6199],[-97.1353,48.6212],[-97.1346,48.6224],[-97.133,48.6228],[-97.131,48.6227],[-97.1291,48.6222],[-97.1277,48.6212],[-97.1274,48.621],[-97.1259,48.6195],[-97.1253,48.619],[-97.1243,48.6183],[-97.1231,48.6178],[-97.1216,48.6176],[-97.12,48.6178],[-97.1193,48.6182],[-97.1186,48.6191],[-97.1183,48.6198],[-97.1186,48.6209],[-97.1198,48.6221],[-97.1209,48.6232],[-97.1212,48.6233],[-97.122,48.624],[-97.1228,48.6245],[-97.1236,48.625],[-97.1241,48.6254],[-97.1245,48.6257],[-97.1249,48.6259],[-97.1253,48.6261],[-97.126,48.6264],[-97.1266,48.6266],[-97.1272,48.627],[-97.1279,48.6273],[-97.1288,48.6278],[-97.1296,48.6282],[-97.1302,48.6288],[-97.1305,48.6292],[-97.1307,48.6297],[-97.131,48.6303],[-97.131,48.6304],[-97.131,48.6308],[-97.131,48.6315],[-97.1309,48.6317],[-97.1307,48.6321],[-97.1304,48.6325],[-97.1301,48.6326],[-97.1297,48.6328],[-97.1293,48.6329],[-97.129,48.633],[-97.1281,48.6332],[-97.128,48.6333],[-97.1275,48.6333],[-97.1253,48.6334],[-97.1235,48.6333],[-97.1216,48.6327],[-97.1181,48.6308],[-97.1176,48.6307],[-97.115,48.6299],[-97.1133,48.63],[-97.1115,48.6303],[-97.1107,48.6308],[-97.1104,48.6309],[-97.1095,48.6315],[-97.1084,48.6327],[-97.1082,48.6344],[-97.1086,48.6363],[-97.1096,48.6389],[-97.1109,48.6407],[-97.1119,48.6416],[-97.1144,48.6433],[-97.115,48.6438],[-97.115,48.6446],[-97.1149,48.6452],[-97.1123,48.6457],[-97.1112,48.6459],[-97.1093,48.6465],[-97.1078,48.6478],[-97.1069,48.6491],[-97.1066,48.6501],[-97.1061,48.6519],[-97.1059,48.6527],[-97.1045,48.6545],[-97.1017,48.6563],[-97.0987,48.6593],[-97.0986,48.6604],[-97.0985,48.6613],[-97.0992,48.6625],[-97.1019,48.6636],[-97.106,48.663],[-97.1062,48.663],[-97.1082,48.6634],[-97.1087,48.6645],[-97.1061,48.6654],[-97.1057,48.6655],[-97.102,48.6667],[-97.1,48.668],[-97.0998,48.6714],[-97.1002,48.675],[-97.1003,48.6757],[-97.1008,48.6787],[-97.1011,48.6808],[-97.1003,48.6828],[-97.0985,48.683],[-97.0946,48.6822],[-97.0926,48.6821],[-97.0904,48.6828],[-97.0898,48.6841],[-97.0899,48.6852],[-97.091,48.6861],[-97.093,48.687],[-97.0951,48.6876],[-97.099,48.6884],[-97.1024,48.6893],[-97.103,48.6894],[-97.1059,48.6903],[-97.1064,48.6905],[-97.1086,48.6915],[-97.111,48.6939],[-97.113,48.6964],[-97.1148,48.6981],[-97.1182,48.7005],[-97.1198,48.7018],[-97.1201,48.7039],[-97.1194,48.7041],[-97.1182,48.7046],[-97.1143,48.7052],[-97.1117,48.7056],[-97.11,48.7063],[-97.1098,48.7083],[-97.1113,48.7094],[-97.1134,48.7101],[-97.1157,48.7105],[-97.1174,48.7111],[-97.119,48.7119],[-97.1212,48.7136],[-97.1223,48.716],[-97.1229,48.7168],[-97.1231,48.7172],[-97.1243,48.7192],[-97.1253,48.7201],[-97.1253,48.7203],[-97.126,48.7207],[-97.1263,48.7212],[-97.1272,48.7215],[-97.128,48.722],[-97.1282,48.7221],[-97.1288,48.7225],[-97.1297,48.7229],[-97.131,48.7233],[-97.1321,48.7238],[-97.1331,48.7242],[-97.1345,48.7248],[-97.136,48.7257],[-97.1369,48.7263],[-97.1375,48.727],[-97.1376,48.7274],[-97.1376,48.7278],[-97.1373,48.7283],[-97.137,48.7284],[-97.1365,48.7285],[-97.136,48.7287],[-97.1352,48.7287],[-97.1341,48.7289],[-97.1333,48.7291],[-97.1328,48.7292],[-97.132,48.7294],[-97.1312,48.7295],[-97.1308,48.7296],[-97.1299,48.7299],[-97.1294,48.7304],[-97.1288,48.7308],[-97.1286,48.7312],[-97.1286,48.7315],[-97.1286,48.7316],[-97.1286,48.7318],[-97.1285,48.7322],[-97.1286,48.7326],[-97.1286,48.7328],[-97.1287,48.7331],[-97.129,48.7335],[-97.1295,48.7339],[-97.1298,48.7341],[-97.1316,48.7347],[-97.1322,48.7348],[-97.1334,48.7347],[-97.1351,48.7345],[-97.1369,48.7345],[-97.1383,48.7345],[-97.1396,48.7347],[-97.1402,48.7349],[-97.1412,48.7354],[-97.1419,48.7359],[-97.1422,48.7367],[-97.1423,48.7372],[-97.1421,48.7381],[-97.1414,48.7385],[-97.1408,48.7387],[-97.1404,48.7389],[-97.1399,48.7393],[-97.1392,48.7397],[-97.1381,48.7408],[-97.1372,48.742],[-97.1366,48.7435],[-97.1365,48.745],[-97.1365,48.7459],[-97.1366,48.7466],[-97.1369,48.748],[-97.1375,48.7492],[-97.1379,48.75],[-97.1385,48.7504],[-97.1391,48.7507],[-97.1396,48.7508],[-97.1401,48.7509],[-97.141,48.751],[-97.142,48.751],[-97.143,48.7509],[-97.1444,48.7507],[-97.1457,48.7506],[-97.1466,48.7505],[-97.1476,48.7505],[-97.1491,48.7506],[-97.1497,48.7508],[-97.1503,48.7509],[-97.1515,48.7515],[-97.1521,48.752],[-97.153,48.7529],[-97.1539,48.7542],[-97.1545,48.7553],[-97.1547,48.7558],[-97.1548,48.7562],[-97.1548,48.7569],[-97.1548,48.7576],[-97.1546,48.758],[-97.1542,48.7587],[-97.1535,48.7593],[-97.1528,48.7598],[-97.1519,48.7601],[-97.1508,48.7605],[-97.1503,48.7606],[-97.1501,48.7607],[-97.1475,48.7616],[-97.1473,48.7617],[-97.1469,48.762],[-97.1462,48.7626],[-97.1461,48.7628],[-97.1459,48.7633],[-97.1456,48.7643],[-97.1456,48.765],[-97.146,48.7658],[-97.1476,48.7673],[-97.1487,48.7681],[-97.15,48.7692],[-97.1501,48.7693],[-97.1506,48.77],[-97.1512,48.7712],[-97.1519,48.7721],[-97.1525,48.7727],[-97.1529,48.7728],[-97.1559,48.7731],[-97.1567,48.7732],[-97.1578,48.7735],[-97.1582,48.7737],[-97.1587,48.7742],[-97.1589,48.7746],[-97.159,48.7751],[-97.159,48.7751],[-97.159,48.7754],[-97.1589,48.776],[-97.1584,48.7766],[-97.1579,48.7769],[-97.1573,48.7772],[-97.1557,48.7776],[-97.1544,48.7778],[-97.1534,48.778],[-97.1522,48.7783],[-97.1509,48.7787],[-97.1501,48.7789],[-97.1497,48.779],[-97.1483,48.7797],[-97.1477,48.7801],[-97.1473,48.7807],[-97.1472,48.7811],[-97.1473,48.7816],[-97.1478,48.7821],[-97.1486,48.7824],[-97.1495,48.7826],[-97.1501,48.7826],[-97.1503,48.7826],[-97.1513,48.7825],[-97.1533,48.7824],[-97.1547,48.7824],[-97.1559,48.7825],[-97.1571,48.7827],[-97.1583,48.783],[-97.1591,48.7834],[-97.1595,48.7838],[-97.1597,48.7843],[-97.1598,48.7848],[-97.1596,48.7853],[-97.1593,48.786],[-97.1591,48.7863],[-97.1586,48.7869],[-97.1577,48.7877],[-97.1574,48.7882],[-97.1573,48.7884],[-97.1572,48.7887],[-97.1571,48.7894],[-97.157,48.7895],[-97.157,48.7901],[-97.1572,48.7906],[-97.1575,48.7909],[-97.1581,48.7912],[-97.1586,48.7913],[-97.1592,48.7915],[-97.1595,48.7915],[-97.1611,48.7915],[-97.1618,48.7914],[-97.1645,48.7911],[-97.1648,48.7911],[-97.1657,48.7911],[-97.1664,48.7912],[-97.1672,48.7913],[-97.1714,48.7921],[-97.1718,48.7923],[-97.1721,48.7924],[-97.1731,48.7929],[-97.1737,48.7933],[-97.174,48.7937],[-97.1741,48.7942],[-97.1742,48.7947],[-97.1742,48.7951],[-97.1739,48.7954],[-97.1734,48.7958],[-97.1726,48.7963],[-97.1717,48.7966],[-97.1716,48.7966],[-97.171,48.7967],[-97.1701,48.7967],[-97.1688,48.7966],[-97.1673,48.7964],[-97.1665,48.7962],[-97.1654,48.7962],[-97.1648,48.7962],[-97.1638,48.7963],[-97.1631,48.7966],[-97.1625,48.7969],[-97.162,48.7974],[-97.1617,48.7979],[-97.1617,48.7984],[-97.1619,48.7988],[-97.1621,48.7994],[-97.1626,48.8001],[-97.1633,48.8007],[-97.1642,48.8011],[-97.1652,48.8014],[-97.166,48.8015],[-97.1668,48.8016],[-97.1675,48.8016],[-97.1685,48.8016],[-97.1698,48.8013],[-97.1706,48.8011],[-97.1714,48.8008],[-97.1715,48.8008],[-97.1724,48.8004],[-97.1731,48.8],[-97.1742,48.7992],[-97.175,48.7986],[-97.1754,48.7983],[-97.1757,48.798],[-97.1761,48.7977],[-97.1768,48.7974],[-97.1773,48.7973],[-97.1779,48.7972],[-97.1787,48.7972],[-97.1795,48.7972],[-97.1801,48.7973],[-97.1807,48.7975],[-97.1811,48.7978],[-97.1815,48.7982],[-97.1816,48.7986],[-97.1817,48.7991],[-97.1815,48.7995],[-97.1813,48.8],[-97.1808,48.8004],[-97.1801,48.8008],[-97.1791,48.8012],[-97.1779,48.8015],[-97.1769,48.8017],[-97.1764,48.8018],[-97.1756,48.8021],[-97.1748,48.8023],[-97.1725,48.8032],[-97.1713,48.8036],[-97.171,48.8037],[-97.1706,48.8039],[-97.1694,48.8043],[-97.1682,48.8046],[-97.1675,48.8048],[-97.1666,48.805],[-97.1655,48.8052],[-97.1638,48.8055],[-97.161,48.8059],[-97.1605,48.8061],[-97.1597,48.8064],[-97.159,48.8067],[-97.1583,48.8072],[-97.1579,48.8077],[-97.1577,48.8082],[-97.1576,48.8089],[-97.1578,48.8098],[-97.158,48.8104],[-97.1586,48.811],[-97.159,48.8111],[-97.161,48.8117],[-97.1617,48.8119],[-97.1625,48.812],[-97.1636,48.8121],[-97.1644,48.8121],[-97.1651,48.812],[-97.1666,48.8118],[-97.168,48.8116],[-97.169,48.8114],[-97.17,48.8114],[-97.1713,48.8115],[-97.1715,48.8115],[-97.1726,48.8117],[-97.1731,48.8118],[-97.174,48.8122],[-97.1761,48.8132],[-97.1776,48.8141],[-97.1784,48.8145],[-97.1797,48.8149],[-97.1807,48.8151],[-97.1821,48.8153],[-97.1828,48.8153],[-97.184,48.8152],[-97.1848,48.8151],[-97.186,48.8147],[-97.1868,48.8145],[-97.1873,48.8143],[-97.1879,48.8143],[-97.1883,48.8143],[-97.1889,48.8143],[-97.1894,48.8144],[-97.1898,48.8146],[-97.1901,48.8148],[-97.1903,48.8153],[-97.1904,48.8156],[-97.1903,48.8159],[-97.19,48.8163],[-97.1893,48.8167],[-97.1885,48.8171],[-97.1879,48.8173],[-97.1866,48.8176],[-97.1857,48.8177],[-97.1847,48.8179],[-97.184,48.8181],[-97.1833,48.8184],[-97.1817,48.8189],[-97.1809,48.8193],[-97.1801,48.8199],[-97.1793,48.8207],[-97.1787,48.8216],[-97.178,48.8232],[-97.1777,48.824],[-97.1776,48.8245],[-97.1777,48.8249],[-97.178,48.8255],[-97.1782,48.8258],[-97.1786,48.8262],[-97.1794,48.8268],[-97.1822,48.8288],[-97.1837,48.8299],[-97.1841,48.8304],[-97.1847,48.8314],[-97.1848,48.8319],[-97.1849,48.8326],[-97.1849,48.8327],[-97.1848,48.833],[-97.1846,48.8336],[-97.1842,48.8341],[-97.1837,48.8345],[-97.183,48.8348],[-97.1822,48.835],[-97.1813,48.8351],[-97.1799,48.8352],[-97.1783,48.8353],[-97.1779,48.8354],[-97.1772,48.8356],[-97.1757,48.8362],[-97.1753,48.8364],[-97.1747,48.8369],[-97.1742,48.8373],[-97.1739,48.8378],[-97.1738,48.8384],[-97.1738,48.839],[-97.1739,48.8406],[-97.1743,48.8427],[-97.1747,48.8438],[-97.175,48.8442],[-97.1755,48.8447],[-97.1761,48.8452],[-97.1767,48.8455],[-97.1771,48.8456],[-97.1779,48.8458],[-97.1795,48.8459],[-97.1808,48.846],[-97.1817,48.8462],[-97.1823,48.8464],[-97.1827,48.8468],[-97.1829,48.847],[-97.1829,48.8471],[-97.1829,48.8473],[-97.1826,48.8476],[-97.1821,48.8479],[-97.1816,48.848],[-97.1809,48.8481],[-97.1793,48.8482],[-97.178,48.8483],[-97.1767,48.8484],[-97.1759,48.8486],[-97.1753,48.8487],[-97.1747,48.849],[-97.1742,48.8493],[-97.1737,48.8497],[-97.1733,48.8502],[-97.173,48.8506],[-97.173,48.8508],[-97.173,48.8511],[-97.173,48.8516],[-97.1732,48.8522],[-97.1737,48.8527],[-97.1746,48.8534],[-97.1771,48.855],[-97.1784,48.8561],[-97.1786,48.8563],[-97.179,48.8569],[-97.1793,48.8576],[-97.1794,48.8583],[-97.1794,48.859],[-97.1792,48.8606],[-97.179,48.8615],[-97.179,48.862],[-97.1791,48.8626],[-97.1794,48.863],[-97.1801,48.8636],[-97.1811,48.864],[-97.1818,48.8641],[-97.1827,48.8641],[-97.1839,48.864],[-97.1855,48.8637],[-97.1871,48.8633],[-97.1877,48.8631],[-97.1883,48.8631],[-97.1891,48.8631],[-97.1896,48.8633],[-97.19,48.8635],[-97.1903,48.8639],[-97.1905,48.8644],[-97.1905,48.8648],[-97.1904,48.8651],[-97.1901,48.8657],[-97.1899,48.8661],[-97.1895,48.8665],[-97.189,48.867],[-97.1884,48.8675],[-97.1851,48.8694],[-97.1813,48.8718],[-97.1788,48.8736],[-97.1785,48.8738],[-97.1782,48.8741],[-97.1781,48.8743],[-97.1779,48.8745],[-97.1778,48.8747],[-97.1777,48.8749],[-97.1777,48.875],[-97.1778,48.875],[-97.1778,48.8754],[-97.1779,48.8757],[-97.1782,48.8761],[-97.1786,48.8765],[-97.1792,48.8769],[-97.1798,48.8771],[-97.1808,48.8772],[-97.1823,48.8772],[-97.1852,48.8768],[-97.1869,48.8765],[-97.1881,48.8765],[-97.1891,48.8766],[-97.1904,48.8769],[-97.1933,48.8779],[-97.1944,48.8783],[-97.1957,48.8788],[-97.1972,48.8794],[-97.1981,48.8799],[-97.1988,48.8805],[-97.1995,48.8812],[-97.1999,48.8818],[-97.1999,48.8821],[-97.2,48.8827],[-97.1998,48.8832],[-97.1997,48.8836],[-97.199,48.8845],[-97.1978,48.8859],[-97.1975,48.8865],[-97.1974,48.8868],[-97.1973,48.8872],[-97.1973,48.8874],[-97.1974,48.8877],[-97.1975,48.8881],[-97.1983,48.8889],[-97.2002,48.8903],[-97.2004,48.8904],[-97.2009,48.8908],[-97.2014,48.8912],[-97.2017,48.8915],[-97.2017,48.8919],[-97.2016,48.8922],[-97.2013,48.8925],[-97.201,48.8926],[-97.2001,48.8926],[-97.1994,48.8926],[-97.1985,48.8925],[-97.198,48.8924],[-97.1973,48.892],[-97.1957,48.8916],[-97.1946,48.8915],[-97.1944,48.8914],[-97.1937,48.8914],[-97.1927,48.8915],[-97.1921,48.8917],[-97.1916,48.8919],[-97.1905,48.8926],[-97.1901,48.8932],[-97.1898,48.8938],[-97.1897,48.8944],[-97.1897,48.8947],[-97.1898,48.8951],[-97.1899,48.8954],[-97.1903,48.896],[-97.1911,48.8967],[-97.1919,48.8974],[-97.1925,48.8979],[-97.1935,48.8985],[-97.1941,48.8988],[-97.1945,48.8989],[-97.1966,48.8997],[-97.1992,48.9004],[-97.2009,48.9009],[-97.2022,48.9013],[-97.2048,48.9018],[-97.2055,48.902],[-97.207,48.9025],[-97.2076,48.9027],[-97.2082,48.9029],[-97.2088,48.9032],[-97.2093,48.9036],[-97.21,48.904],[-97.2105,48.9044],[-97.211,48.905],[-97.2114,48.9056],[-97.2122,48.9069],[-97.2125,48.9075],[-97.2127,48.9082],[-97.2127,48.909],[-97.2125,48.9099],[-97.212,48.911],[-97.2116,48.9121],[-97.2111,48.913],[-97.2108,48.914],[-97.2106,48.9148],[-97.2106,48.9153],[-97.2109,48.9162],[-97.2111,48.9167],[-97.2115,48.9172],[-97.2118,48.9175],[-97.2122,48.9177],[-97.2129,48.9181],[-97.2149,48.9187],[-97.2163,48.9191],[-97.2164,48.9191],[-97.2171,48.9194],[-97.2179,48.9198],[-97.2189,48.9205],[-97.2196,48.9215],[-97.2198,48.9222],[-97.2199,48.923],[-97.2197,48.9237],[-97.2191,48.9249],[-97.2183,48.9262],[-97.2172,48.9277],[-97.2163,48.9286],[-97.2159,48.9289],[-97.2149,48.9301],[-97.2146,48.9304],[-97.2145,48.9307],[-97.2144,48.931],[-97.2145,48.9314],[-97.2145,48.9316],[-97.2148,48.9319],[-97.2154,48.9325],[-97.2159,48.9327],[-97.2162,48.9328],[-97.217,48.9328],[-97.2181,48.9327],[-97.2198,48.9325],[-97.2208,48.9325],[-97.2214,48.9325],[-97.2218,48.9326],[-97.2237,48.9332],[-97.2245,48.9337],[-97.2249,48.9339],[-97.225,48.934],[-97.2252,48.9342],[-97.2254,48.9345],[-97.2257,48.9349],[-97.226,48.9353],[-97.2263,48.936],[-97.2267,48.9376],[-97.227,48.9389],[-97.2271,48.9398],[-97.2271,48.941],[-97.227,48.9418],[-97.2266,48.9432],[-97.2264,48.9441],[-97.2263,48.9445],[-97.2264,48.9452],[-97.2265,48.9456],[-97.227,48.9462],[-97.2273,48.9465],[-97.2276,48.9467],[-97.2279,48.9467],[-97.2284,48.9468],[-97.2304,48.9465],[-97.2309,48.9464],[-97.2313,48.9464],[-97.2326,48.9466],[-97.2331,48.9468],[-97.2338,48.9471],[-97.2342,48.9474],[-97.2343,48.948],[-97.2343,48.9485],[-97.2342,48.9488],[-97.2341,48.9491],[-97.2337,48.95],[-97.2332,48.951],[-97.2328,48.9524],[-97.2323,48.954],[-97.2317,48.9558],[-97.2313,48.9568],[-97.2309,48.9578],[-97.2305,48.9585],[-97.23,48.9591],[-97.2288,48.9603],[-97.2282,48.9609],[-97.2278,48.9613],[-97.2276,48.9619],[-97.2276,48.9624],[-97.2279,48.963],[-97.228,48.9631],[-97.2283,48.9634],[-97.2289,48.9639],[-97.2294,48.9641],[-97.23,48.9642],[-97.2323,48.9646],[-97.2355,48.965],[-97.2368,48.9652],[-97.2375,48.9654],[-97.2382,48.966],[-97.2383,48.9661],[-97.2388,48.9666],[-97.2391,48.9676],[-97.2392,48.9687],[-97.239,48.9696],[-97.2387,48.9706],[-97.2383,48.9715],[-97.2381,48.9723],[-97.238,48.9725],[-97.2379,48.9731],[-97.2378,48.9734],[-97.2378,48.9738],[-97.238,48.9752],[-97.238,48.9763],[-97.2381,48.9771],[-97.238,48.9771],[-97.238,48.9841],[-97.2377,48.9849],[-97.2372,48.9857],[-97.2365,48.9867],[-97.2359,48.9874],[-97.2351,48.9881],[-97.2342,48.989],[-97.2335,48.9895],[-97.2331,48.9898],[-97.2317,48.9904],[-97.2301,48.9911],[-97.2293,48.9914],[-97.229,48.9916],[-97.2279,48.9921],[-97.2274,48.9925],[-97.227,48.9929],[-97.2266,48.9933],[-97.2265,48.9938],[-97.2267,48.9941],[-97.227,48.9945],[-97.2273,48.9947],[-97.2287,48.9949],[-97.2304,48.995],[-97.2317,48.9951],[-97.2324,48.9952],[-97.2335,48.9956],[-97.2338,48.9959],[-97.2341,48.9966],[-97.2341,48.997],[-97.234,48.9975],[-97.2337,48.9981],[-97.2332,48.9985],[-97.2323,48.999],[-97.2305,49.0],[-97.2303,49.0001],[-97.2295,49.0005],[-97.2175,49.0005],[-97.2161,49.0005],[-97.2078,49.0005],[-97.2069,49.0005],[-97.1955,49.0005],[-97.1939,49.0005],[-97.1739,49.0005],[-97.1724,49.0005],[-97.1514,49.0005],[-97.1502,49.0005],[-97.1294,49.0004],[-97.1277,49.0004],[-97.1073,49.0004],[-97.1061,49.0004],[-97.0853,49.0004],[-97.084,49.0004],[-97.0633,49.0004],[-97.062,49.0004],[-97.0412,49.0004],[-97.0401,49.0004],[-97.0192,49.0004],[-97.0183,49.0004],[-96.9971,49.0004],[-96.9961,49.0004],[-96.9751,49.0003],[-96.9738,49.0003],[-96.953,49.0003],[-96.9518,49.0003],[-96.931,49.0003],[-96.9299,49.0003],[-96.909,49.0003],[-96.9078,49.0003],[-96.8869,49.0003],[-96.8856,49.0003],[-96.8649,49.0003],[-96.864,49.0003],[-96.8429,49.0003],[-96.8415,49.0003],[-96.8208,49.0003],[-96.8197,49.0003],[-96.8023,49.0002],[-96.8005,49.0002],[-96.8003,49.0002],[-96.7988,49.0002],[-96.7787,49.0002],[-96.7768,49.0002],[-96.7567,49.0002],[-96.7547,49.0002],[-96.7348,49.0002],[-96.7327,49.0002],[-96.7127,49.0002],[-96.7107,49.0002],[-96.6905,49.0002],[-96.6886,49.0002],[-96.6695,49.0002],[-96.6665,49.0002],[-96.6482,49.0002],[-96.6445,49.0002],[-96.6243,49.0002],[-96.6225,49.0002],[-96.6021,49.0002],[-96.6004,49.0002],[-96.58,49.0002],[-96.5784,49.0002],[-96.558,49.0002],[-96.5563,49.0002],[-96.536,49.0002],[-96.5342,49.0002],[-96.5154,49.0002],[-96.5123,49.0002],[-96.4933,49.0002],[-96.49,49.0002],[-96.471,49.0001],[-96.4664,49.0001],[-96.4496,49.0001],[-96.4492,49.0001],[-96.4491,49.0001],[-96.446,49.0001],[-96.4273,49.0001],[-96.4224,49.0001],[-96.4054,49.0001]]],"type":"Polygon"},"id":"35","properties":{"Area":2862183702.23055,"CTYONLY_":3,"Code":"KITT","LASTMOD":"1999-12-31T23:59:59Z","Name":"Kittson","Perimiter":263017.48277},"type":"Feature"},{"geometry":{"coordinates":[[[-96.4054,49.0001],[-96.4019,49.0001],[-96.3825,49.0001],[-96.3783,49.0001],[-96.3606,49.0001],[-96.3579,49.0001],[-96.3385,49.0001],[-96.3343,49.0001],[-96.3166,49.0001],[-96.3138,49.0001],[-96.2945,49.0001],[-96.2902,49.0001],[-96.2725,49.0001],[-96.2698,49.0001],[-96.2494,49.0001],[-96.2461,49.0001],[-96.2274,49.0001],[-96.2257,49.0001],[-96.2057,49.0001],[-96.2021,49.0001],[-96.1837,49.0],[-96.18,49.0],[-96.1617,49.0],[-96.1579,49.0],[-96.1401,49.0],[-96.1359,49.0],[-96.1176,49.0],[-96.1139,49.0],[-96.0957,49.0],[-96.0919,49.0],[-96.0738,49.0],[-96.07,49.0],[-96.0517,49.0],[-96.048,49.0],[-96.0298,49.0],[-96.026,49.0],[-96.0083,49.0],[-96.0045,49.0],[-95.9868,49.0],[-95.9784,49.0],[-95.9776,49.0],[-95.9755,49.0],[-95.9648,48.9999],[-95.9464,48.9999],[-95.943,48.9999],[-95.9225,48.9999],[-95.9211,48.9999],[-95.899,48.9998],[-95.883,48.9998],[-95.8771,48.9998],[-95.8564,48.9998],[-95.855,48.9998],[-95.8342,48.9998],[-95.8184,48.9997],[-95.8126,48.9997],[-95.7906,48.9997],[-95.7833,48.9997],[-95.7684,48.9997],[-95.7479,48.9996],[-95.7466,48.9996],[-95.7253,48.9996],[-95.7066,48.9996],[-95.7032,48.9996],[-95.681,48.9995],[-95.6654,48.9995],[-95.6596,48.9995],[-95.659,48.9995],[-95.6401,48.9995],[-95.6369,48.9995],[-95.6205,48.9994],[-95.615,48.9994],[-95.5948,48.9994],[-95.585,48.9994],[-95.573,48.9994],[-95.551,48.9993],[-95.5495,48.9993],[-95.5294,48.9993],[-95.5164,48.9993],[-95.5072,48.9993],[-95.4849,48.9992],[-95.4834,48.9992],[-95.4635,48.9992],[-95.4508,48.9992],[-95.4418,48.9992],[-95.4245,48.9991],[-95.4197,48.9991],[-95.3977,48.9991],[-95.3953,48.9991],[-95.3765,48.9991],[-95.3759,48.9991],[-95.3753,48.9991],[-95.3542,48.999],[-95.3513,48.999],[-95.3326,48.999],[-95.3286,48.999],[-95.3231,48.999],[-95.3224,48.9984],[-95.3204,48.9976],[-95.3202,48.9973],[-95.3204,48.9964],[-95.3206,48.9961],[-95.3201,48.9956],[-95.3197,48.9954],[-95.3191,48.9953],[-95.3187,48.9956],[-95.3182,48.996],[-95.3179,48.9961],[-95.3178,48.9961],[-95.3178,48.9958],[-95.3181,48.995],[-95.3191,48.9941],[-95.3204,48.9924],[-95.3206,48.9921],[-95.3224,48.9889],[-95.3227,48.9884],[-95.3242,48.9859],[-95.3245,48.985],[-95.3253,48.9832],[-95.3257,48.9814],[-95.3256,48.98],[-95.3255,48.9789],[-95.3257,48.9784],[-95.3253,48.976],[-95.325,48.9743],[-95.3249,48.9738],[-95.3248,48.9728],[-95.3247,48.972],[-95.3241,48.9703],[-95.3232,48.9692],[-95.3227,48.9685],[-95.3212,48.9672],[-95.3207,48.9669],[-95.3201,48.9648],[-95.3198,48.9643],[-95.3193,48.964],[-95.3193,48.9622],[-95.3202,48.9606],[-95.3206,48.9598],[-95.3206,48.9595],[-95.3206,48.959],[-95.3202,48.9581],[-95.3191,48.9569],[-95.3188,48.9562],[-95.3179,48.9559],[-95.3175,48.9552],[-95.3177,48.9545],[-95.3182,48.9535],[-95.3181,48.9531],[-95.3177,48.9525],[-95.3154,48.9513],[-95.3151,48.951],[-95.3141,48.9508],[-95.3131,48.9503],[-95.3125,48.9503],[-95.3123,48.9502],[-95.3119,48.9502],[-95.3119,48.9507],[-95.3129,48.9521],[-95.3129,48.9523],[-95.3126,48.9524],[-95.312,48.9524],[-95.3115,48.952],[-95.3108,48.9512],[-95.3104,48.951],[-95.3097,48.951],[-95.3089,48.9511],[-95.3079,48.9509],[-95.3061,48.9502],[-95.3052,48.9495],[-95.3046,48.9482],[-95.3046,48.947],[-95.305,48.9462],[-95.3053,48.9459],[-95.3061,48.9454],[-95.3068,48.9454],[-95.3069,48.9455],[-95.3069,48.9456],[-95.3063,48.9462],[-95.3062,48.9463],[-95.3061,48.9469],[-95.3062,48.9472],[-95.3062,48.9472],[-95.3071,48.9477],[-95.3081,48.948],[-95.3094,48.9481],[-95.3096,48.9482],[-95.3099,48.9484],[-95.31,48.9485],[-95.3103,48.9485],[-95.3104,48.9484],[-95.3103,48.948],[-95.3096,48.9478],[-95.3092,48.9477],[-95.3079,48.9474],[-95.3071,48.9469],[-95.3071,48.9466],[-95.3074,48.9465],[-95.3078,48.9466],[-95.3085,48.947],[-95.3086,48.9469],[-95.3086,48.9465],[-95.3088,48.9464],[-95.3095,48.9463],[-95.3102,48.9463],[-95.3114,48.9461],[-95.3131,48.946],[-95.3141,48.9457],[-95.3148,48.9452],[-95.3154,48.9448],[-95.3168,48.9431],[-95.3181,48.9421],[-95.3189,48.9419],[-95.3219,48.9412],[-95.3225,48.9409],[-95.3228,48.9403],[-95.3231,48.9389],[-95.3229,48.9373],[-95.3225,48.9358],[-95.3223,48.9355],[-95.3228,48.9344],[-95.3222,48.9327],[-95.3209,48.9307],[-95.3208,48.9305],[-95.3195,48.9285],[-95.3168,48.9245],[-95.315,48.9222],[-95.3141,48.921],[-95.3132,48.9198],[-95.3126,48.919],[-95.3119,48.9178],[-95.3115,48.9172],[-95.3109,48.9163],[-95.3102,48.9155],[-95.3093,48.9149],[-95.3092,48.9149],[-95.3085,48.9146],[-95.3078,48.9141],[-95.3074,48.9135],[-95.3064,48.9129],[-95.3061,48.9128],[-95.3059,48.9127],[-95.3043,48.9119],[-95.3038,48.9114],[-95.3027,48.91],[-95.3017,48.9093],[-95.2999,48.9086],[-95.2978,48.9083],[-95.2973,48.9081],[-95.2973,48.908],[-95.2973,48.9077],[-95.2976,48.9074],[-95.2977,48.9073],[-95.2978,48.9073],[-95.2978,48.9072],[-95.2978,48.9072],[-95.2979,48.9072],[-95.2979,48.9072],[-95.2979,48.9071],[-95.298,48.9071],[-95.298,48.9071],[-95.298,48.9071],[-95.2981,48.907],[-95.2982,48.9068],[-95.2983,48.9068],[-95.2985,48.9065],[-95.2985,48.9064],[-95.2986,48.9063],[-95.2988,48.906],[-95.2989,48.906],[-95.2991,48.9057],[-95.2992,48.9055],[-95.2994,48.9053],[-95.2996,48.9051],[-95.2997,48.905],[-95.2999,48.9048],[-95.2999,48.9048],[-95.2999,48.9048],[-95.3,48.9047],[-95.3,48.9047],[-95.3001,48.9047],[-95.3001,48.9046],[-95.3002,48.9045],[-95.3005,48.904],[-95.2993,48.9035],[-95.2983,48.9028],[-95.298,48.9027],[-95.2976,48.9026],[-95.2967,48.9027],[-95.2949,48.9028],[-95.2941,48.9027],[-95.2937,48.9023],[-95.2935,48.902],[-95.2927,48.9019],[-95.2914,48.9019],[-95.2909,48.9017],[-95.2908,48.9016],[-95.2907,48.9014],[-95.2906,48.9011],[-95.2911,48.9008],[-95.2911,48.9006],[-95.2901,48.9003],[-95.2896,48.9],[-95.289,48.8994],[-95.2882,48.8981],[-95.2879,48.8979],[-95.2872,48.8977],[-95.287,48.8976],[-95.2865,48.8975],[-95.2861,48.8976],[-95.2853,48.8977],[-95.2839,48.8975],[-95.2813,48.8967],[-95.2803,48.8965],[-95.2796,48.8962],[-95.279,48.8957],[-95.2782,48.8956],[-95.2773,48.8957],[-95.277,48.8958],[-95.2765,48.8962],[-95.2763,48.8963],[-95.2759,48.8962],[-95.2755,48.8959],[-95.2749,48.8956],[-95.2748,48.8951],[-95.2753,48.8943],[-95.2751,48.8938],[-95.2745,48.8931],[-95.2724,48.8921],[-95.2713,48.8915],[-95.268,48.8905],[-95.2677,48.8903],[-95.2674,48.89],[-95.2666,48.8894],[-95.2654,48.8888],[-95.265,48.8886],[-95.2646,48.8885],[-95.2639,48.8883],[-95.2635,48.888],[-95.2627,48.8877],[-95.2585,48.8867],[-95.2585,48.8867],[-95.257,48.8858],[-95.256,48.885],[-95.2548,48.8845],[-95.2517,48.8839],[-95.2507,48.8836],[-95.2502,48.8835],[-95.2496,48.8834],[-95.2485,48.8832],[-95.248,48.8836],[-95.2472,48.8835],[-95.2458,48.8829],[-95.2439,48.8823],[-95.2429,48.8822],[-95.2429,48.8822],[-95.2423,48.8821],[-95.2407,48.8821],[-95.2391,48.8819],[-95.2381,48.8817],[-95.2356,48.8815],[-95.2335,48.8814],[-95.231,48.8814],[-95.2287,48.8815],[-95.2265,48.8816],[-95.2252,48.8819],[-95.2212,48.883],[-95.2208,48.8831],[-95.2207,48.8831],[-95.22,48.8831],[-95.2193,48.8832],[-95.2188,48.8835],[-95.217,48.8835],[-95.2159,48.8839],[-95.2151,48.884],[-95.2144,48.8843],[-95.2122,48.8842],[-95.2117,48.8847],[-95.2115,48.8847],[-95.2112,48.8848],[-95.2085,48.8846],[-95.2059,48.8848],[-95.2024,48.8852],[-95.2009,48.8855],[-95.2005,48.8856],[-95.1986,48.8855],[-95.1956,48.8862],[-95.1924,48.8865],[-95.1919,48.8866],[-95.1913,48.8868],[-95.1901,48.887],[-95.1889,48.8873],[-95.1877,48.8874],[-95.1863,48.8877],[-95.1851,48.8882],[-95.1819,48.8888],[-95.1797,48.889],[-95.1791,48.889],[-95.1764,48.8893],[-95.173,48.8897],[-95.1701,48.8902],[-95.1674,48.8907],[-95.1648,48.8913],[-95.1641,48.8917],[-95.1618,48.892],[-95.1602,48.892],[-95.1579,48.8919],[-95.1564,48.8919],[-95.1555,48.892],[-95.1528,48.8921],[-95.1508,48.8922],[-95.1483,48.8923],[-95.1469,48.8927],[-95.1459,48.8929],[-95.1438,48.8934],[-95.1436,48.8937],[-95.1404,48.8943],[-95.1381,48.8949],[-95.1355,48.8959],[-95.1351,48.8963],[-95.1348,48.8963],[-95.1343,48.8963],[-95.1337,48.8969],[-95.1322,48.8973],[-95.1312,48.8975],[-95.1252,48.8998],[-95.1239,48.9001],[-95.1233,48.9004],[-95.1228,48.9006],[-95.1214,48.9013],[-95.121,48.9016],[-95.1205,48.9017],[-95.1204,48.9019],[-95.1182,48.9029],[-95.1163,48.9037],[-95.1151,48.9046],[-95.1144,48.9052],[-95.114,48.9061],[-95.1141,48.9064],[-95.1137,48.9069],[-95.1132,48.9071],[-95.113,48.9072],[-95.1126,48.9073],[-95.1107,48.9082],[-95.1096,48.9089],[-95.108,48.9099],[-95.1056,48.9113],[-95.1042,48.9121],[-95.1032,48.9127],[-95.102,48.9132],[-95.1008,48.9142],[-95.0981,48.9159],[-95.098,48.916],[-95.0975,48.9164],[-95.0971,48.9172],[-95.097,48.9176],[-95.0961,48.9181],[-95.0946,48.9191],[-95.0944,48.9193],[-95.0927,48.9204],[-95.0919,48.9207],[-95.0914,48.9208],[-95.0914,48.916],[-95.0912,48.9014],[-95.0911,48.8869],[-95.0908,48.8724],[-95.0908,48.858],[-95.0907,48.8436],[-95.0908,48.8291],[-95.0909,48.8147],[-95.0903,48.8],[-95.0903,48.7855],[-95.0903,48.7711],[-95.0901,48.7566],[-95.0901,48.7421],[-95.0899,48.7277],[-95.0898,48.713],[-95.1046,48.7129],[-95.1104,48.7129],[-95.1119,48.7129],[-95.1259,48.7129],[-95.1297,48.713],[-95.1333,48.713],[-95.1477,48.7129],[-95.1554,48.7129],[-95.1697,48.7129],[-95.1773,48.713],[-95.1917,48.713],[-95.1991,48.713],[-95.2112,48.713],[-95.2206,48.713],[-95.2331,48.713],[-95.2427,48.713],[-95.255,48.713],[-95.2645,48.713],[-95.2656,48.713],[-95.2767,48.713],[-95.2866,48.713],[-95.299,48.713],[-95.3051,48.713],[-95.3084,48.713],[-95.3205,48.713],[-95.3302,48.713],[-95.3425,48.7131],[-95.3425,48.6995],[-95.3424,48.6849],[-95.3423,48.6705],[-95.3424,48.6561],[-95.3425,48.6415],[-95.3426,48.6271],[-95.3424,48.6127],[-95.3426,48.5979],[-95.3423,48.5836],[-95.3423,48.5691],[-95.3424,48.5548],[-95.3425,48.5402],[-95.3628,48.5404],[-95.364,48.5403],[-95.3844,48.5402],[-95.386,48.5402],[-95.4061,48.5402],[-95.4078,48.5402],[-95.4279,48.54],[-95.4297,48.5399],[-95.4494,48.5399],[-95.4513,48.5399],[-95.4712,48.5396],[-95.4726,48.5396],[-95.493,48.5392],[-95.495,48.5392],[-95.5143,48.539],[-95.5163,48.539],[-95.5365,48.5389],[-95.5383,48.5389],[-95.558,48.5388],[-95.5603,48.5388],[-95.5801,48.5387],[-95.5821,48.5387],[-95.6023,48.5389],[-95.6232,48.5391],[-95.6447,48.5393],[-95.6666,48.5394],[-95.6886,48.5395],[-95.7102,48.5395],[-95.7322,48.54],[-95.7539,48.5404],[-95.7758,48.5406],[-95.7976,48.5405],[-95.8192,48.5404],[-95.8411,48.5406],[-95.8621,48.5414],[-95.8829,48.5419],[-95.8851,48.542],[-95.8986,48.5421],[-95.9046,48.5422],[-95.9064,48.5422],[-95.9269,48.5421],[-95.9486,48.5425],[-95.9498,48.5425],[-95.9704,48.543],[-95.9936,48.5435],[-96.0157,48.5437],[-96.0374,48.5438],[-96.0592,48.5437],[-96.0812,48.5436],[-96.1026,48.5438],[-96.1264,48.5439],[-96.1486,48.5442],[-96.1702,48.5445],[-96.1921,48.5446],[-96.2141,48.5449],[-96.2358,48.5452],[-96.2576,48.545],[-96.2794,48.5449],[-96.301,48.5448],[-96.3231,48.5446],[-96.3448,48.5444],[-96.3667,48.5443],[-96.3882,48.5442],[-96.3879,48.5588],[-96.3882,48.5733],[-96.3884,48.5877],[-96.3891,48.6024],[-96.389,48.6165],[-96.388,48.6313],[-96.3879,48.6454],[-96.3877,48.6599],[-96.3871,48.6741],[-96.3874,48.6887],[-96.3866,48.703],[-96.3873,48.7172],[-96.388,48.7172],[-96.4049,48.7172],[-96.4048,48.7318],[-96.4048,48.7465],[-96.4047,48.7607],[-96.4045,48.7758],[-96.4042,48.7903],[-96.4042,48.8048],[-96.4042,48.8198],[-96.4043,48.8343],[-96.4045,48.8491],[-96.4047,48.8635],[-96.405,48.878],[-96.405,48.8926],[-96.4053,48.9068],[-96.4053,48.9081],[-96.4053,48.9137],[-96.4054,48.9214],[-96.4054,48.9225],[-96.4053,48.936],[-96.4053,48.9371],[-96.4053,48.9504],[-96.4053,48.9515],[-96.4053,48.9648],[-96.4053,48.9658],[-96.4053,48.9705],[-96.4054,48.9793],[-96.4054,48.9803],[-96.4054,48.994],[-96.4054,48.9947],[-96.4054,49.0001]]],"type":"Polygon"},"id":"68","properties":{"Area":4347098503.12714,"CTYONLY_":4,"Code":"ROSE","LASTMOD":"2001-04-12T09:32:44Z","Name":"Roseau","Perimiter":302590.75293},"type":"Feature"},{"geometry":{"coordinates":[[[-94.4299,48.7012],[-94.4241,48.7053],[-94.4213,48.7086],[-94.4189,48.7103],[-94.4158,48.711],[-94.4081,48.7106],[-94.406,48.7105],[-94.3889,48.712],[-94.3859,48.7119],[-94.384,48.7119],[-94.3801,48.7111],[-94.3687,48.7065],[-94.3646,48.7059],[-94.3533,48.7042],[-94.3431,48.7035],[-94.3429,48.7035],[-94.3287,48.7045],[-94.3214,48.7067],[-94.3088,48.7103],[-94.2995,48.709],[-94.2911,48.7079],[-94.2829,48.7057],[-94.2781,48.7024],[-94.2745,48.6999],[-94.2694,48.6995],[-94.2644,48.699],[-94.261,48.6966],[-94.258,48.6918],[-94.2565,48.6901],[-94.2529,48.6864],[-94.2521,48.685],[-94.2514,48.6837],[-94.2507,48.6782],[-94.2527,48.6707],[-94.253,48.6693],[-94.2548,48.664],[-94.2546,48.6615],[-94.2509,48.657],[-94.2499,48.6563],[-94.2467,48.6542],[-94.2445,48.6535],[-94.2343,48.6524],[-94.2335,48.6524],[-94.2242,48.6495],[-94.2144,48.6494],[-94.2124,48.6496],[-94.1996,48.651],[-94.1915,48.6506],[-94.1886,48.6504],[-94.1689,48.6483],[-94.1678,48.6482],[-94.1574,48.6458],[-94.1522,48.6455],[-94.1458,48.6458],[-94.1391,48.646],[-94.126,48.6444],[-94.1235,48.6444],[-94.11,48.6443],[-94.1023,48.6455],[-94.0999,48.6459],[-94.0912,48.6437],[-94.0849,48.6441],[-94.0804,48.6442],[-94.0767,48.6442],[-94.0714,48.6459],[-94.0658,48.6462],[-94.0642,48.6438],[-94.0603,48.6431],[-94.0581,48.6434],[-94.0525,48.644],[-94.0432,48.6435],[-94.0393,48.6423],[-94.0364,48.6413],[-94.0356,48.6411],[-94.0295,48.6409],[-94.0153,48.6424],[-94.0069,48.6433],[-94.0007,48.6428],[-93.9931,48.6412],[-93.9897,48.6405],[-93.984,48.6401],[-93.9777,48.6385],[-93.9712,48.6385],[-93.968,48.6385],[-93.9596,48.6372],[-93.953,48.6341],[-93.9497,48.6339],[-93.934,48.6326],[-93.9272,48.6327],[-93.9169,48.6329],[-93.9134,48.6353],[-93.9057,48.6346],[-93.9054,48.6345],[-93.8948,48.6324],[-93.8853,48.6318],[-93.8844,48.6318],[-93.8757,48.6319],[-93.8698,48.6311],[-93.8624,48.631],[-93.848,48.6308],[-93.8443,48.6303],[-93.8404,48.6289],[-93.8393,48.6286],[-93.8365,48.6276],[-93.8334,48.6256],[-93.8292,48.6177],[-93.825,48.6136],[-93.8245,48.613],[-93.8214,48.6092],[-93.8182,48.5994],[-93.8175,48.597],[-93.8172,48.5964],[-93.813,48.588],[-93.8103,48.5846],[-93.8063,48.5796],[-93.8041,48.5703],[-93.8041,48.5702],[-93.8051,48.5644],[-93.808,48.5569],[-93.8088,48.5555],[-93.8119,48.5503],[-93.8102,48.5445],[-93.8109,48.5412],[-93.8109,48.541],[-93.818,48.535],[-93.818,48.5346],[-93.8184,48.5315],[-93.8178,48.5306],[-93.8161,48.5285],[-93.8145,48.5273],[-93.8111,48.5247],[-93.803,48.522],[-93.7964,48.5182],[-93.7933,48.5164],[-93.7879,48.5159],[-93.7745,48.5162],[-93.768,48.5164],[-93.7665,48.5164],[-93.7617,48.5166],[-93.7534,48.5158],[-93.7442,48.5175],[-93.739,48.5185],[-93.731,48.5185],[-93.7225,48.5178],[-93.7206,48.5176],[-93.7108,48.5186],[-93.7061,48.5182],[-93.7006,48.517],[-93.693,48.5152],[-93.6866,48.5154],[-93.6791,48.5167],[-93.6778,48.5169],[-93.6593,48.5165],[-93.657,48.5167],[-93.6473,48.5177],[-93.6433,48.519],[-93.6421,48.5199],[-93.6395,48.5218],[-93.6357,48.5285],[-93.6344,48.5293],[-93.6311,48.5313],[-93.6284,48.5319],[-93.6256,48.5315],[-93.6211,48.5264],[-93.6166,48.5238],[-93.6134,48.5228],[-93.6122,48.5225],[-93.6051,48.5231],[-93.5962,48.5287],[-93.5919,48.5299],[-93.5901,48.5305],[-93.581,48.5271],[-93.5761,48.527],[-93.5701,48.528],[-93.5602,48.5297],[-93.5484,48.5294],[-93.5476,48.5294],[-93.5425,48.53],[-93.5366,48.5319],[-93.5269,48.5341],[-93.5263,48.5341],[-93.5244,48.5343],[-93.5171,48.5348],[-93.5047,48.5399],[-93.501,48.5414],[-93.4952,48.5426],[-93.4854,48.5433],[-93.4833,48.5437],[-93.4673,48.5465],[-93.4655,48.5478],[-93.4625,48.5498],[-93.462,48.5505],[-93.4596,48.5537],[-93.4576,48.5598],[-93.4576,48.5621],[-93.4575,48.5672],[-93.4619,48.5731],[-93.4619,48.5734],[-93.4631,48.5767],[-93.4671,48.5885],[-93.4656,48.59],[-93.4654,48.5915],[-93.4654,48.5917],[-93.4627,48.5927],[-93.46,48.5927],[-93.4547,48.5927],[-93.4398,48.5937],[-93.4385,48.5942],[-93.4347,48.5954],[-93.4298,48.5997],[-93.4226,48.6032],[-93.4193,48.6036],[-93.416,48.605],[-93.4152,48.6053],[-93.415,48.6056],[-93.4144,48.6064],[-93.4056,48.6099],[-93.4034,48.61],[-93.4029,48.6077],[-93.4013,48.6079],[-93.3994,48.6055],[-93.3986,48.6045],[-93.3953,48.6038],[-93.3937,48.6041],[-93.3837,48.606],[-93.3724,48.6059],[-93.3714,48.6059],[-93.3672,48.6082],[-93.3619,48.6141],[-93.355,48.6114],[-93.3526,48.6135],[-93.3533,48.615],[-93.3513,48.62],[-93.3505,48.6219],[-93.3486,48.6265],[-93.3276,48.6302],[-93.3057,48.634],[-93.3048,48.6341],[-93.2838,48.6378],[-93.2634,48.6413],[-93.2546,48.6429],[-93.2422,48.6428],[-93.2193,48.6426],[-93.2075,48.6426],[-93.1975,48.6365],[-93.191,48.6325],[-93.184,48.6282],[-93.1783,48.6231],[-93.1754,48.6232],[-93.1531,48.6244],[-93.1319,48.6256],[-93.1104,48.6267],[-93.0903,48.6278],[-93.0884,48.6278],[-93.0886,48.6163],[-93.0895,48.6016],[-93.0898,48.5872],[-93.09,48.5727],[-93.0902,48.5583],[-93.0902,48.5441],[-93.0903,48.5296],[-93.0905,48.5151],[-93.0905,48.501],[-93.091,48.4884],[-93.0911,48.4867],[-93.0914,48.474],[-93.0915,48.4724],[-93.0918,48.4596],[-93.0919,48.458],[-93.092,48.4449],[-93.092,48.4436],[-93.0922,48.4303],[-93.0922,48.429],[-93.0923,48.4147],[-93.0935,48.4147],[-93.0938,48.4024],[-93.094,48.3879],[-93.094,48.3734],[-93.0945,48.3589],[-93.0948,48.3442],[-93.0948,48.3298],[-93.0953,48.3153],[-93.0952,48.3004],[-93.095,48.2862],[-93.0952,48.2716],[-93.0953,48.2576],[-93.0949,48.2426],[-93.0949,48.2425],[-93.0977,48.2426],[-93.0977,48.2271],[-93.0978,48.2126],[-93.0979,48.1981],[-93.0975,48.1836],[-93.097,48.1692],[-93.097,48.1546],[-93.097,48.1402],[-93.0969,48.1259],[-93.0972,48.1114],[-93.097,48.0969],[-93.0968,48.0823],[-93.0965,48.0679],[-93.0965,48.0678],[-93.0892,48.0679],[-93.0892,48.0509],[-93.089,48.0366],[-93.0886,48.022],[-93.0887,48.0075],[-93.0872,47.9932],[-93.088,47.9787],[-93.0809,47.9786],[-93.0809,47.967],[-93.0808,47.9647],[-93.0808,47.9525],[-93.0808,47.9504],[-93.0809,47.938],[-93.0809,47.9356],[-93.0809,47.9235],[-93.0809,47.9212],[-93.0809,47.9088],[-93.0809,47.9067],[-93.0808,47.8945],[-93.0808,47.8922],[-93.1015,47.8927],[-93.1232,47.893],[-93.1448,47.8928],[-93.1656,47.8931],[-93.1671,47.8932],[-93.1871,47.8931],[-93.1893,47.8931],[-93.2087,47.8933],[-93.2115,47.8934],[-93.2331,47.8937],[-93.2532,47.8936],[-93.2745,47.8938],[-93.2962,47.8939],[-93.3169,47.894],[-93.3392,47.8941],[-93.3603,47.8942],[-93.3809,47.8943],[-93.4024,47.8944],[-93.4235,47.8945],[-93.4442,47.8946],[-93.466,47.895],[-93.4874,47.8956],[-93.4892,47.8957],[-93.4933,47.8958],[-93.5085,47.8962],[-93.5105,47.8963],[-93.5297,47.8967],[-93.5303,47.8967],[-93.532,47.8968],[-93.5517,47.8973],[-93.5532,47.8974],[-93.5729,47.8981],[-93.5747,47.8982],[-93.5962,47.8978],[-93.5966,47.8978],[-93.6179,47.8977],[-93.6187,47.8977],[-93.6388,47.8977],[-93.6395,47.8976],[-93.6604,47.8976],[-93.6612,47.8976],[-93.6817,47.8976],[-93.6826,47.8976],[-93.7031,47.8976],[-93.7038,47.8976],[-93.7249,47.8975],[-93.7248,47.8989],[-93.7466,47.8989],[-93.768,47.8991],[-93.7758,47.8991],[-93.7758,47.899],[-93.776,47.8897],[-93.776,47.8842],[-93.7762,47.8753],[-93.7761,47.8697],[-93.7761,47.8607],[-93.7761,47.8553],[-93.7761,47.8464],[-93.7896,47.8465],[-93.7971,47.8466],[-93.8189,47.8467],[-93.8407,47.8468],[-93.8627,47.8469],[-93.8831,47.8471],[-93.9067,47.8471],[-93.9288,47.8475],[-93.9496,47.8475],[-93.9506,47.8475],[-93.971,47.8475],[-93.9725,47.8475],[-93.9927,47.8475],[-93.9942,47.8475],[-94.0141,47.8476],[-94.0161,47.8476],[-94.0375,47.8477],[-94.0591,47.8474],[-94.0807,47.8471],[-94.1022,47.8471],[-94.1239,47.8466],[-94.1448,47.8463],[-94.1657,47.8461],[-94.1822,47.8461],[-94.1871,47.846],[-94.2037,47.846],[-94.2086,47.846],[-94.2252,47.846],[-94.23,47.8461],[-94.2467,47.8462],[-94.2515,47.8462],[-94.2681,47.8462],[-94.2728,47.8462],[-94.2887,47.8462],[-94.3103,47.8458],[-94.3315,47.846],[-94.3532,47.8464],[-94.3747,47.8462],[-94.3964,47.8461],[-94.4185,47.8459],[-94.4186,47.86],[-94.4184,47.8744],[-94.418,47.8886],[-94.4177,47.9031],[-94.4176,47.9041],[-94.4175,47.9175],[-94.4174,47.9186],[-94.4175,47.9332],[-94.4174,47.9477],[-94.4172,47.9623],[-94.4173,47.9769],[-94.4176,47.9914],[-94.4177,48.006],[-94.4176,48.02],[-94.4236,48.0199],[-94.4241,48.0344],[-94.4246,48.0489],[-94.4247,48.0632],[-94.4234,48.0776],[-94.4231,48.092],[-94.4233,48.1059],[-94.4234,48.1204],[-94.4236,48.1348],[-94.4233,48.1491],[-94.4235,48.1637],[-94.4235,48.1781],[-94.4233,48.1923],[-94.4236,48.2067],[-94.4238,48.2212],[-94.4237,48.2356],[-94.4237,48.2504],[-94.424,48.2649],[-94.4243,48.2791],[-94.4244,48.2938],[-94.4246,48.3081],[-94.4248,48.3227],[-94.425,48.3372],[-94.4253,48.352],[-94.4252,48.3675],[-94.4288,48.3675],[-94.4289,48.3821],[-94.4293,48.3964],[-94.4294,48.411],[-94.4293,48.4254],[-94.4292,48.4399],[-94.4293,48.4543],[-94.4296,48.4688],[-94.4296,48.4832],[-94.4299,48.4977],[-94.4303,48.512],[-94.4303,48.5264],[-94.43,48.5409],[-94.4295,48.5554],[-94.4291,48.5698],[-94.4289,48.5844],[-94.4289,48.5988],[-94.4292,48.6133],[-94.4294,48.6276],[-94.4297,48.642],[-94.43,48.6564],[-94.4301,48.6708],[-94.43,48.6852],[-94.4299,48.6998],[-94.4299,48.7012]]],"type":"Polygon"},"id":"36","properties":{"Area":8167237870.91888,"CTYONLY_":5,"Code":"KOOC","LASTMOD":"1999-12-31T23:59:59Z","Name":"Koochiching","Perimiter":412897.43594},"type":"Feature"},{"geometry":{"coordinates":[[[-96.3882,48.5442],[-96.3667,48.5443],[-96.3448,48.5444],[-96.3231,48.5446],[-96.301,48.5448],[-96.2794,48.5449],[-96.2576,48.545],[-96.2358,48.5452],[-96.2141,48.5449],[-96.1921,48.5446],[-96.1702,48.5445],[-96.1486,48.5442],[-96.1264,48.5439],[-96.1026,48.5438],[-96.0812,48.5436],[-96.0592,48.5437],[-96.0374,48.5438],[-96.0157,48.5437],[-95.9936,48.5435],[-95.9704,48.543],[-95.9498,48.5425],[-95.9486,48.5425],[-95.9269,48.5421],[-95.9064,48.5422],[-95.9046,48.5422],[-95.8986,48.5421],[-95.8851,48.542],[-95.8829,48.5419],[-95.8621,48.5414],[-95.8411,48.5406],[-95.8192,48.5404],[-95.7976,48.5405],[-95.7758,48.5406],[-95.7539,48.5404],[-95.7322,48.54],[-95.7102,48.5395],[-95.6886,48.5395],[-95.6666,48.5394],[-95.6447,48.5393],[-95.6232,48.5391],[-95.6023,48.5389],[-95.6011,48.5251],[-95.6007,48.5107],[-95.6007,48.51],[-95.6008,48.4964],[-95.6008,48.4956],[-95.6011,48.4818],[-95.6011,48.4811],[-95.6016,48.4674],[-95.6016,48.4666],[-95.6016,48.453],[-95.6016,48.4522],[-95.602,48.4385],[-95.6021,48.4376],[-95.6023,48.424],[-95.6023,48.4232],[-95.6026,48.4095],[-95.6026,48.4088],[-95.6026,48.395],[-95.6026,48.3942],[-95.6021,48.3809],[-95.602,48.3798],[-95.6016,48.3655],[-95.5933,48.3656],[-95.5933,48.3656],[-95.5933,48.354],[-95.5932,48.3396],[-95.5932,48.325],[-95.5932,48.3105],[-95.5934,48.2961],[-95.5934,48.2815],[-95.5937,48.267],[-95.5941,48.2526],[-95.5941,48.2382],[-95.5939,48.2236],[-95.5939,48.2092],[-95.5938,48.1946],[-95.594,48.1802],[-95.5939,48.173],[-95.5941,48.173],[-95.6159,48.1731],[-95.6163,48.1731],[-95.6252,48.1731],[-95.6279,48.1731],[-95.6376,48.173],[-95.6376,48.173],[-95.6591,48.1729],[-95.662,48.1729],[-95.6802,48.1728],[-95.6803,48.1728],[-95.702,48.1729],[-95.7021,48.1729],[-95.7022,48.1729],[-95.7128,48.173],[-95.7157,48.1731],[-95.7226,48.1731],[-95.7227,48.1731],[-95.744,48.1727],[-95.7443,48.1727],[-95.7502,48.1727],[-95.7657,48.1728],[-95.7657,48.1728],[-95.7874,48.1725],[-95.8088,48.1722],[-95.809,48.1722],[-95.8091,48.1722],[-95.8305,48.1722],[-95.8308,48.1722],[-95.8308,48.1722],[-95.8499,48.1721],[-95.8525,48.1721],[-95.8527,48.1721],[-95.8744,48.172],[-95.8744,48.172],[-95.8752,48.172],[-95.8958,48.172],[-95.896,48.172],[-95.9176,48.1719],[-95.9178,48.1719],[-95.9178,48.1719],[-95.9392,48.1719],[-95.9394,48.1719],[-95.9608,48.1718],[-95.9609,48.1718],[-95.961,48.1718],[-95.9651,48.1718],[-95.9817,48.1717],[-95.9819,48.1717],[-95.9956,48.1717],[-96.0003,48.1717],[-96.0023,48.1718],[-96.0028,48.1718],[-96.0032,48.1718],[-96.0035,48.1718],[-96.0036,48.1718],[-96.0047,48.1717],[-96.0101,48.1718],[-96.0171,48.172],[-96.025,48.1721],[-96.0254,48.1721],[-96.0468,48.1722],[-96.0468,48.1722],[-96.0592,48.1721],[-96.0685,48.1721],[-96.0685,48.1721],[-96.079,48.1721],[-96.09,48.172],[-96.09,48.172],[-96.0979,48.172],[-96.1084,48.1718],[-96.1084,48.1718],[-96.1176,48.1722],[-96.1189,48.1722],[-96.1253,48.1727],[-96.1297,48.173],[-96.1298,48.173],[-96.1302,48.173],[-96.1388,48.1732],[-96.1516,48.1736],[-96.1518,48.1736],[-96.1625,48.1736],[-96.1641,48.1736],[-96.1736,48.1736],[-96.1737,48.1736],[-96.1741,48.1736],[-96.1813,48.1725],[-96.1827,48.1722],[-96.1834,48.172],[-96.1874,48.1721],[-96.191,48.1721],[-96.1948,48.1721],[-96.1954,48.1721],[-96.1959,48.1721],[-96.1963,48.1721],[-96.2023,48.1722],[-96.2038,48.1722],[-96.2072,48.1722],[-96.2076,48.1722],[-96.2177,48.1722],[-96.2179,48.1722],[-96.2188,48.1722],[-96.2251,48.1724],[-96.2275,48.1724],[-96.2287,48.1725],[-96.2307,48.1725],[-96.2329,48.1725],[-96.2391,48.1727],[-96.2397,48.1727],[-96.2397,48.1727],[-96.2398,48.1728],[-96.2476,48.1735],[-96.2491,48.1737],[-96.2503,48.1739],[-96.2511,48.174],[-96.252,48.174],[-96.2562,48.1744],[-96.2596,48.1749],[-96.2607,48.1749],[-96.2612,48.1749],[-96.2619,48.1749],[-96.2805,48.1747],[-96.2823,48.1747],[-96.2824,48.1747],[-96.2977,48.1747],[-96.3029,48.1747],[-96.3035,48.1747],[-96.3145,48.1747],[-96.3252,48.1746],[-96.3253,48.1746],[-96.3301,48.1745],[-96.3356,48.1745],[-96.3358,48.1744],[-96.338,48.1745],[-96.3402,48.1744],[-96.343,48.1744],[-96.3466,48.1743],[-96.347,48.1743],[-96.3473,48.1744],[-96.3477,48.1744],[-96.351,48.1745],[-96.3542,48.1746],[-96.3581,48.1747],[-96.361,48.1748],[-96.3642,48.1749],[-96.3656,48.175],[-96.3682,48.1751],[-96.3682,48.1751],[-96.3685,48.1751],[-96.3706,48.175],[-96.3728,48.1749],[-96.3753,48.1748],[-96.3781,48.1746],[-96.38,48.1745],[-96.3856,48.1747],[-96.3894,48.1748],[-96.3905,48.1748],[-96.3906,48.1748],[-96.3964,48.1748],[-96.4054,48.1748],[-96.4126,48.1749],[-96.4126,48.1749],[-96.4135,48.1749],[-96.4206,48.1749],[-96.4295,48.1749],[-96.4346,48.1749],[-96.4352,48.1749],[-96.4359,48.1749],[-96.438,48.1749],[-96.4402,48.1748],[-96.4436,48.1747],[-96.4454,48.1747],[-96.4561,48.1744],[-96.4563,48.1743],[-96.4564,48.1742],[-96.4569,48.1742],[-96.4592,48.1742],[-96.467,48.1741],[-96.4735,48.174],[-96.4773,48.1741],[-96.4789,48.1741],[-96.4791,48.1741],[-96.4841,48.174],[-96.4946,48.1741],[-96.4973,48.174],[-96.5003,48.1741],[-96.5006,48.1741],[-96.5008,48.1742],[-96.5008,48.1742],[-96.5038,48.174],[-96.5091,48.174],[-96.5164,48.1739],[-96.5204,48.1739],[-96.5223,48.1739],[-96.5251,48.1738],[-96.53,48.1738],[-96.5357,48.1738],[-96.5399,48.1738],[-96.5434,48.1738],[-96.5442,48.1738],[-96.5443,48.1738],[-96.5446,48.1738],[-96.5479,48.1738],[-96.5507,48.1738],[-96.5544,48.1738],[-96.557,48.1739],[-96.5616,48.1739],[-96.565,48.174],[-96.5654,48.174],[-96.5655,48.174],[-96.5678,48.174],[-96.5715,48.1739],[-96.5748,48.1739],[-96.5765,48.1739],[-96.5806,48.1739],[-96.5838,48.1738],[-96.5873,48.1737],[-96.5873,48.1737],[-96.5875,48.1737],[-96.5893,48.1737],[-96.5966,48.1737],[-96.6055,48.1737],[-96.609,48.1737],[-96.6092,48.1737],[-96.6106,48.1737],[-96.6253,48.1737],[-96.6307,48.1737],[-96.6307,48.1737],[-96.6309,48.1737],[-96.6338,48.1737],[-96.6378,48.1738],[-96.6407,48.1739],[-96.6525,48.1738],[-96.6525,48.1738],[-96.6742,48.1736],[-96.6742,48.1736],[-96.6826,48.1735],[-96.6958,48.1734],[-96.6959,48.1734],[-96.7176,48.1734],[-96.7177,48.1734],[-96.7393,48.1734],[-96.7393,48.1734],[-96.7503,48.1734],[-96.7573,48.1734],[-96.7581,48.1734],[-96.7605,48.1734],[-96.7606,48.1734],[-96.7613,48.1734],[-96.7819,48.1734],[-96.7821,48.1734],[-96.7821,48.1734],[-96.7932,48.1733],[-96.8038,48.1734],[-96.8039,48.1734],[-96.8111,48.1734],[-96.8255,48.1734],[-96.8255,48.1734],[-96.8473,48.1733],[-96.8474,48.1733],[-96.869,48.1733],[-96.869,48.1733],[-96.8753,48.1732],[-96.8907,48.1732],[-96.8907,48.1732],[-96.8932,48.1732],[-96.9122,48.1733],[-96.9123,48.1733],[-96.933,48.1733],[-96.9339,48.1733],[-96.934,48.1733],[-96.9387,48.1732],[-96.9448,48.1732],[-96.9554,48.1731],[-96.9703,48.1731],[-96.9705,48.1731],[-96.9749,48.173],[-96.9751,48.173],[-96.9773,48.173],[-96.9773,48.173],[-96.9775,48.1731],[-96.9812,48.1731],[-96.9844,48.1731],[-96.9889,48.1731],[-96.99,48.1731],[-96.9959,48.1732],[-96.9975,48.1732],[-96.998,48.1732],[-96.9987,48.1732],[-96.9989,48.1732],[-96.999,48.1732],[-97.0003,48.1732],[-97.0203,48.1733],[-97.0205,48.1733],[-97.042,48.1732],[-97.042,48.1732],[-97.0637,48.1732],[-97.0637,48.1732],[-97.0853,48.1734],[-97.0855,48.1734],[-97.1069,48.1735],[-97.1071,48.1735],[-97.1253,48.1733],[-97.1257,48.1733],[-97.1286,48.1733],[-97.1322,48.1733],[-97.1376,48.1733],[-97.1462,48.1733],[-97.1467,48.1733],[-97.1452,48.1741],[-97.1434,48.1744],[-97.1417,48.1746],[-97.1389,48.1747],[-97.1371,48.1754],[-97.1365,48.1758],[-97.136,48.1768],[-97.1359,48.1789],[-97.1362,48.1796],[-97.1366,48.1809],[-97.1383,48.1824],[-97.1406,48.183],[-97.1413,48.1831],[-97.1432,48.1828],[-97.1455,48.1824],[-97.1467,48.1821],[-97.1484,48.1825],[-97.1498,48.1835],[-97.1497,48.1859],[-97.1491,48.1864],[-97.1475,48.1879],[-97.1449,48.1895],[-97.1429,48.191],[-97.1426,48.1913],[-97.1415,48.1926],[-97.1413,48.1934],[-97.1412,48.1937],[-97.141,48.194],[-97.1409,48.1945],[-97.1404,48.1947],[-97.1397,48.1951],[-97.1391,48.1953],[-97.1383,48.1955],[-97.1365,48.1963],[-97.1356,48.1972],[-97.1359,48.1984],[-97.1368,48.1996],[-97.1383,48.2006],[-97.1401,48.2018],[-97.1409,48.2027],[-97.1412,48.203],[-97.1411,48.204],[-97.1409,48.2046],[-97.14,48.2052],[-97.139,48.2059],[-97.1375,48.2063],[-97.1341,48.2068],[-97.1316,48.2072],[-97.1301,48.2077],[-97.1296,48.208],[-97.1295,48.208],[-97.1292,48.2084],[-97.1292,48.2099],[-97.1291,48.21],[-97.1296,48.2105],[-97.1297,48.2106],[-97.1299,48.2108],[-97.1307,48.211],[-97.1318,48.2112],[-97.1354,48.2116],[-97.1364,48.2119],[-97.1382,48.2131],[-97.1394,48.2144],[-97.1392,48.2168],[-97.1389,48.2171],[-97.1383,48.2174],[-97.1373,48.2177],[-97.1354,48.2179],[-97.1344,48.2178],[-97.1328,48.2176],[-97.1313,48.2172],[-97.1302,48.2164],[-97.1297,48.2161],[-97.1292,48.2158],[-97.1278,48.2145],[-97.1274,48.2134],[-97.1265,48.2113],[-97.126,48.2101],[-97.1259,48.2099],[-97.1257,48.2097],[-97.1253,48.2093],[-97.1245,48.208],[-97.1236,48.2077],[-97.1229,48.2074],[-97.1216,48.2074],[-97.1204,48.2073],[-97.1197,48.2076],[-97.1189,48.2079],[-97.1183,48.2086],[-97.118,48.2092],[-97.1178,48.2098],[-97.1179,48.2107],[-97.1181,48.2115],[-97.1189,48.2129],[-97.1194,48.2136],[-97.1208,48.215],[-97.122,48.2159],[-97.1228,48.2165],[-97.1248,48.2175],[-97.1253,48.2178],[-97.1272,48.2185],[-97.1289,48.2188],[-97.1297,48.219],[-97.1321,48.2196],[-97.135,48.2207],[-97.139,48.222],[-97.1406,48.2222],[-97.1417,48.2221],[-97.1436,48.2216],[-97.1448,48.2209],[-97.1455,48.2204],[-97.1457,48.2202],[-97.1458,48.2202],[-97.1462,48.2198],[-97.1471,48.2189],[-97.1482,48.2184],[-97.1497,48.2181],[-97.1509,48.2184],[-97.151,48.2185],[-97.1517,48.219],[-97.1521,48.2197],[-97.1521,48.2205],[-97.1517,48.2214],[-97.151,48.2222],[-97.1496,48.2232],[-97.1483,48.2238],[-97.1476,48.224],[-97.1465,48.2243],[-97.1436,48.2253],[-97.1408,48.2263],[-97.1385,48.2268],[-97.1371,48.227],[-97.1357,48.2271],[-97.1332,48.227],[-97.1317,48.2265],[-97.1305,48.2259],[-97.1298,48.2255],[-97.129,48.2251],[-97.1276,48.2245],[-97.1273,48.2243],[-97.1266,48.2239],[-97.1259,48.2236],[-97.1253,48.2234],[-97.1245,48.2232],[-97.1233,48.2231],[-97.1222,48.2234],[-97.1216,48.2236],[-97.121,48.2242],[-97.121,48.2242],[-97.1206,48.2248],[-97.1206,48.2254],[-97.1207,48.2259],[-97.1216,48.227],[-97.1225,48.2275],[-97.1234,48.2281],[-97.1244,48.2284],[-97.1253,48.2287],[-97.1278,48.2293],[-97.1299,48.2297],[-97.1303,48.2297],[-97.1325,48.2298],[-97.1351,48.2298],[-97.1393,48.2302],[-97.1423,48.231],[-97.1435,48.2318],[-97.1446,48.2336],[-97.1445,48.2343],[-97.1443,48.2351],[-97.143,48.2361],[-97.1416,48.2365],[-97.1411,48.2366],[-97.1399,48.2367],[-97.1377,48.2368],[-97.1358,48.237],[-97.1343,48.2378],[-97.1339,48.2382],[-97.1338,48.2386],[-97.1337,48.2391],[-97.1341,48.2397],[-97.1346,48.2403],[-97.1357,48.2409],[-97.1375,48.2414],[-97.1385,48.2415],[-97.1405,48.2415],[-97.1422,48.2412],[-97.1444,48.2412],[-97.1459,48.2417],[-97.147,48.2423],[-97.1471,48.243],[-97.1467,48.2445],[-97.146,48.2452],[-97.1444,48.2462],[-97.1431,48.2468],[-97.1404,48.2473],[-97.1389,48.2479],[-97.1377,48.2485],[-97.1355,48.2495],[-97.1345,48.2498],[-97.1334,48.2499],[-97.1305,48.2498],[-97.1299,48.2498],[-97.1291,48.2495],[-97.1274,48.2495],[-97.1263,48.2498],[-97.1253,48.25],[-97.1251,48.25],[-97.1247,48.2504],[-97.1244,48.2508],[-97.1243,48.2513],[-97.1243,48.252],[-97.1245,48.2526],[-97.1248,48.2532],[-97.1248,48.2532],[-97.1253,48.2537],[-97.1256,48.254],[-97.1262,48.2546],[-97.1267,48.2551],[-97.1274,48.2555],[-97.1291,48.2566],[-97.13,48.2573],[-97.1304,48.2576],[-97.1306,48.2581],[-97.1306,48.2587],[-97.1306,48.259],[-97.1303,48.2595],[-97.1298,48.2598],[-97.1292,48.2599],[-97.1283,48.26],[-97.1272,48.2601],[-97.1253,48.2601],[-97.1248,48.2602],[-97.1242,48.2604],[-97.1236,48.2607],[-97.1231,48.2612],[-97.1229,48.2617],[-97.123,48.2623],[-97.1234,48.2628],[-97.1237,48.2633],[-97.1241,48.2636],[-97.1246,48.2639],[-97.1253,48.2641],[-97.1262,48.2644],[-97.1285,48.2649],[-97.1303,48.2651],[-97.1305,48.2652],[-97.1333,48.2656],[-97.135,48.2659],[-97.136,48.2659],[-97.1375,48.2657],[-97.1395,48.2655],[-97.1406,48.2654],[-97.142,48.2654],[-97.1427,48.2656],[-97.1438,48.2658],[-97.1444,48.2663],[-97.1448,48.2668],[-97.145,48.2675],[-97.1451,48.2678],[-97.145,48.2688],[-97.1443,48.2698],[-97.1431,48.2705],[-97.1421,48.2709],[-97.1403,48.2712],[-97.1391,48.2713],[-97.1377,48.2713],[-97.1361,48.2711],[-97.1343,48.2707],[-97.1313,48.2701],[-97.1305,48.27],[-97.1298,48.2699],[-97.1288,48.2698],[-97.1272,48.2699],[-97.1265,48.2701],[-97.1253,48.2705],[-97.125,48.2707],[-97.1247,48.2709],[-97.124,48.2713],[-97.1238,48.2716],[-97.1237,48.2721],[-97.1237,48.2725],[-97.1239,48.2728],[-97.124,48.2733],[-97.1242,48.2737],[-97.1247,48.2743],[-97.1253,48.2751],[-97.1254,48.2753],[-97.1255,48.2755],[-97.1256,48.2758],[-97.1255,48.2761],[-97.1254,48.2762],[-97.1253,48.2764],[-97.1251,48.2767],[-97.1246,48.2769],[-97.124,48.277],[-97.1232,48.277],[-97.1224,48.2769],[-97.1213,48.2768],[-97.1206,48.2768],[-97.12,48.2769],[-97.1187,48.2774],[-97.1175,48.2781],[-97.117,48.2788],[-97.1165,48.2797],[-97.1166,48.2805],[-97.1166,48.2807],[-97.1167,48.2813],[-97.117,48.2821],[-97.1171,48.2824],[-97.1172,48.2826],[-97.1177,48.2835],[-97.1221,48.2901],[-97.1231,48.2909],[-97.1239,48.2913],[-97.1244,48.2915],[-97.1247,48.2917],[-97.1253,48.2919],[-97.1256,48.292],[-97.126,48.292],[-97.1265,48.292],[-97.1272,48.2919],[-97.128,48.2916],[-97.1285,48.2913],[-97.1295,48.2908],[-97.1303,48.2902],[-97.1305,48.2901],[-97.1314,48.2891],[-97.1322,48.2884],[-97.133,48.2879],[-97.1342,48.2874],[-97.1349,48.2872],[-97.1355,48.2871],[-97.1367,48.2873],[-97.1374,48.2877],[-97.1378,48.2879],[-97.1383,48.2887],[-97.1384,48.2894],[-97.1384,48.2898],[-97.1383,48.2903],[-97.138,48.2909],[-97.1373,48.2918],[-97.1368,48.2922],[-97.1364,48.2925],[-97.1355,48.2929],[-97.1344,48.2935],[-97.1335,48.2941],[-97.133,48.2946],[-97.1323,48.2953],[-97.1318,48.2959],[-97.1314,48.2963],[-97.131,48.2969],[-97.1306,48.2973],[-97.1305,48.2974],[-97.13,48.2979],[-97.1293,48.2984],[-97.1286,48.2987],[-97.1282,48.2989],[-97.1276,48.299],[-97.1271,48.2991],[-97.127,48.2991],[-97.1263,48.2991],[-97.1253,48.2989],[-97.125,48.2988],[-97.1246,48.2987],[-97.1241,48.2984],[-97.1234,48.2975],[-97.1228,48.2968],[-97.1227,48.2967],[-97.1213,48.2955],[-97.1203,48.2949],[-97.1192,48.2943],[-97.1167,48.294],[-97.1153,48.2939],[-97.1138,48.2943],[-97.1129,48.2949],[-97.1123,48.2954],[-97.1122,48.296],[-97.1122,48.2965],[-97.1123,48.2968],[-97.1126,48.2973],[-97.113,48.2978],[-97.1138,48.2984],[-97.1148,48.299],[-97.118,48.3004],[-97.12,48.3012],[-97.1227,48.3019],[-97.1241,48.3022],[-97.1247,48.3025],[-97.1253,48.3029],[-97.1255,48.303],[-97.1259,48.3033],[-97.1262,48.3036],[-97.1266,48.3041],[-97.1267,48.3046],[-97.1265,48.3055],[-97.1263,48.3059],[-97.1257,48.3064],[-97.1253,48.3067],[-97.1241,48.3073],[-97.123,48.3081],[-97.1222,48.3088],[-97.1221,48.3095],[-97.1222,48.3099],[-97.123,48.3105],[-97.1241,48.3112],[-97.1247,48.3115],[-97.1253,48.3119],[-97.1258,48.3119],[-97.1263,48.312],[-97.1269,48.312],[-97.1276,48.312],[-97.1282,48.3118],[-97.1289,48.3116],[-97.1298,48.3111],[-97.1299,48.3111],[-97.1303,48.3108],[-97.1304,48.3108],[-97.1311,48.3103],[-97.1318,48.3099],[-97.1325,48.3094],[-97.1331,48.3092],[-97.1336,48.309],[-97.1343,48.3089],[-97.1351,48.3089],[-97.1358,48.3089],[-97.1365,48.3091],[-97.1372,48.3094],[-97.1377,48.3098],[-97.1379,48.3102],[-97.1381,48.3106],[-97.138,48.3111],[-97.138,48.3116],[-97.1379,48.312],[-97.1376,48.3125],[-97.1372,48.3129],[-97.1367,48.3134],[-97.1361,48.3141],[-97.1356,48.3148],[-97.1351,48.3155],[-97.1348,48.316],[-97.1346,48.3166],[-97.1345,48.3171],[-97.1343,48.3177],[-97.134,48.3181],[-97.1335,48.3185],[-97.1329,48.3189],[-97.1325,48.3192],[-97.132,48.3194],[-97.1312,48.3196],[-97.1306,48.3196],[-97.1303,48.3196],[-97.1291,48.3196],[-97.1282,48.3195],[-97.1274,48.3195],[-97.1267,48.3195],[-97.1253,48.3196],[-97.1229,48.3201],[-97.1197,48.3208],[-97.1173,48.3216],[-97.1164,48.3222],[-97.1157,48.323],[-97.1155,48.3236],[-97.1155,48.324],[-97.1162,48.3248],[-97.1168,48.3253],[-97.1173,48.3258],[-97.1175,48.326],[-97.1187,48.3266],[-97.1203,48.3271],[-97.1222,48.3274],[-97.123,48.3275],[-97.1253,48.3277],[-97.1257,48.3277],[-97.1262,48.3278],[-97.1275,48.328],[-97.1292,48.3282],[-97.1303,48.3282],[-97.1311,48.3283],[-97.1317,48.3282],[-97.1326,48.3281],[-97.1337,48.3279],[-97.1343,48.3277],[-97.1345,48.3277],[-97.1353,48.3273],[-97.1359,48.327],[-97.1368,48.3263],[-97.1376,48.3257],[-97.138,48.3255],[-97.1385,48.3253],[-97.139,48.3251],[-97.1397,48.3251],[-97.1404,48.3252],[-97.141,48.3254],[-97.1415,48.3257],[-97.1417,48.3258],[-97.142,48.3262],[-97.1422,48.3267],[-97.1423,48.327],[-97.1422,48.3276],[-97.142,48.3281],[-97.1416,48.3287],[-97.1408,48.3294],[-97.14,48.3299],[-97.139,48.3304],[-97.1378,48.3309],[-97.1371,48.331],[-97.1361,48.3312],[-97.1347,48.3315],[-97.1325,48.3318],[-97.1311,48.3321],[-97.1305,48.3323],[-97.1295,48.3326],[-97.129,48.3329],[-97.1284,48.3336],[-97.1275,48.3352],[-97.1263,48.3379],[-97.1258,48.3384],[-97.1258,48.3398],[-97.1258,48.3402],[-97.1259,48.3406],[-97.1263,48.3415],[-97.1267,48.3422],[-97.1276,48.3427],[-97.1283,48.343],[-97.1297,48.3435],[-97.1308,48.3438],[-97.1309,48.3438],[-97.132,48.344],[-97.1334,48.3439],[-97.1354,48.3439],[-97.1372,48.344],[-97.1383,48.3441],[-97.1388,48.3441],[-97.1396,48.3443],[-97.14,48.3446],[-97.1405,48.345],[-97.1407,48.3453],[-97.1409,48.3456],[-97.141,48.3459],[-97.1408,48.3468],[-97.1405,48.3471],[-97.1396,48.3478],[-97.1386,48.3485],[-97.1376,48.3491],[-97.1368,48.3496],[-97.1362,48.3501],[-97.1361,48.3503],[-97.136,48.3505],[-97.136,48.3506],[-97.1359,48.351],[-97.1359,48.3511],[-97.136,48.3518],[-97.1362,48.3522],[-97.1363,48.3524],[-97.1365,48.3526],[-97.1373,48.3529],[-97.1382,48.3532],[-97.1387,48.3533],[-97.1398,48.3535],[-97.1405,48.3536],[-97.1415,48.3538],[-97.1423,48.354],[-97.143,48.3542],[-97.1435,48.3543],[-97.1438,48.3546],[-97.1441,48.3549],[-97.1442,48.3551],[-97.1443,48.3554],[-97.1445,48.356],[-97.1447,48.3565],[-97.145,48.3571],[-97.1453,48.3576],[-97.1459,48.3586],[-97.1464,48.3592],[-97.1468,48.3596],[-97.1477,48.3603],[-97.1484,48.3608],[-97.1501,48.3613],[-97.1517,48.362],[-97.1525,48.3623],[-97.1534,48.3628],[-97.1545,48.3633],[-97.1554,48.3638],[-97.1559,48.3646],[-97.1562,48.3656],[-97.1562,48.3662],[-97.156,48.3671],[-97.1558,48.3681],[-97.1555,48.3686],[-97.1554,48.3689],[-97.1552,48.3691],[-97.1548,48.37],[-97.1539,48.3704],[-97.1536,48.3705],[-97.1524,48.371],[-97.1523,48.371],[-97.1512,48.3713],[-97.1498,48.3712],[-97.1476,48.371],[-97.1437,48.3703],[-97.1433,48.3703],[-97.141,48.3702],[-97.1407,48.3703],[-97.1404,48.3703],[-97.1403,48.3703],[-97.1402,48.3703],[-97.1401,48.3703],[-97.1392,48.3705],[-97.1386,48.3708],[-97.1378,48.3713],[-97.1373,48.3718],[-97.1372,48.3724],[-97.1373,48.373],[-97.1376,48.3736],[-97.1383,48.3744],[-97.1389,48.375],[-97.1398,48.3759],[-97.1406,48.3769],[-97.1412,48.3777],[-97.1413,48.3785],[-97.1409,48.3793],[-97.1403,48.3797],[-97.1395,48.3801],[-97.1379,48.3803],[-97.1366,48.3804],[-97.1355,48.3805],[-97.1344,48.3808],[-97.1339,48.3811],[-97.1334,48.3818],[-97.1333,48.3822],[-97.1338,48.3828],[-97.1344,48.3833],[-97.1354,48.3838],[-97.1362,48.384],[-97.1374,48.3839],[-97.1389,48.3837],[-97.1406,48.3833],[-97.1431,48.3824],[-97.1446,48.3819],[-97.1454,48.3815],[-97.1463,48.3815],[-97.147,48.3814],[-97.1479,48.3817],[-97.149,48.3819],[-97.1505,48.3824],[-97.1509,48.3825],[-97.1519,48.3829],[-97.1532,48.3834],[-97.1538,48.3839],[-97.1548,48.3844],[-97.155,48.3846],[-97.156,48.3851],[-97.1572,48.3858],[-97.1576,48.3865],[-97.1577,48.3874],[-97.1571,48.3884],[-97.1565,48.3896],[-97.1563,48.3904],[-97.1567,48.3909],[-97.1576,48.3912],[-97.1586,48.3913],[-97.1596,48.3912],[-97.1608,48.3913],[-97.1617,48.3915],[-97.1627,48.3918],[-97.1632,48.392],[-97.1633,48.3929],[-97.1631,48.3937],[-97.1621,48.3948],[-97.1607,48.3956],[-97.1593,48.3961],[-97.1586,48.3964],[-97.1574,48.3965],[-97.1551,48.3968],[-97.1534,48.397],[-97.1519,48.3969],[-97.1505,48.3968],[-97.1499,48.3968],[-97.1481,48.3968],[-97.1467,48.3971],[-97.1456,48.3975],[-97.1445,48.3981],[-97.1434,48.3989],[-97.1434,48.399],[-97.1427,48.3996],[-97.1421,48.4004],[-97.1414,48.4013],[-97.1406,48.4019],[-97.1399,48.4025],[-97.1392,48.4029],[-97.1383,48.4033],[-97.1369,48.4038],[-97.1349,48.4046],[-97.1334,48.4053],[-97.1323,48.4059],[-97.1314,48.4066],[-97.1311,48.4073],[-97.131,48.4079],[-97.1312,48.409],[-97.1316,48.4096],[-97.1322,48.4104],[-97.1334,48.4112],[-97.1348,48.412],[-97.1362,48.4126],[-97.1373,48.4134],[-97.1375,48.4137],[-97.1376,48.4137],[-97.1379,48.4141],[-97.1384,48.4146],[-97.1388,48.4163],[-97.1388,48.4172],[-97.1393,48.4181],[-97.1398,48.4185],[-97.1406,48.4187],[-97.142,48.4186],[-97.1434,48.4181],[-97.1445,48.4173],[-97.1453,48.4159],[-97.1467,48.414],[-97.1472,48.4137],[-97.1478,48.4133],[-97.1489,48.4129],[-97.1505,48.4128],[-97.1508,48.4128],[-97.1521,48.4129],[-97.1532,48.4131],[-97.1543,48.4136],[-97.1543,48.4136],[-97.155,48.4143],[-97.1554,48.415],[-97.1554,48.4161],[-97.1554,48.4168],[-97.1548,48.4175],[-97.1539,48.4182],[-97.1527,48.4188],[-97.1509,48.4195],[-97.1507,48.4196],[-97.1489,48.4201],[-97.1466,48.4206],[-97.1443,48.4211],[-97.1421,48.4215],[-97.1403,48.4216],[-97.1383,48.4217],[-97.1367,48.4216],[-97.135,48.4213],[-97.1335,48.421],[-97.1325,48.4205],[-97.1312,48.4197],[-97.1301,48.4191],[-97.129,48.4181],[-97.1285,48.4177],[-97.1274,48.4168],[-97.1264,48.4164],[-97.126,48.4162],[-97.1253,48.4162],[-97.1244,48.4164],[-97.1236,48.4167],[-97.1232,48.417],[-97.1227,48.4176],[-97.1225,48.418],[-97.1224,48.4183],[-97.1223,48.4191],[-97.1223,48.4195],[-97.1225,48.42],[-97.1227,48.4204],[-97.1228,48.4207],[-97.1231,48.421],[-97.1233,48.4213],[-97.1241,48.4219],[-97.1246,48.4223],[-97.1249,48.4224],[-97.1253,48.4226],[-97.1268,48.4234],[-97.1286,48.4242],[-97.129,48.4243],[-97.1312,48.4251],[-97.1332,48.4258],[-97.1346,48.4262],[-97.1375,48.4264],[-97.139,48.4265],[-97.1406,48.427],[-97.1412,48.4272],[-97.1425,48.4277],[-97.1438,48.4285],[-97.1446,48.4291],[-97.1451,48.4298],[-97.1457,48.4303],[-97.1458,48.4312],[-97.1455,48.4322],[-97.1451,48.4326],[-97.144,48.4332],[-97.142,48.4337],[-97.1412,48.4338],[-97.1398,48.4337],[-97.1384,48.4336],[-97.1366,48.433],[-97.1344,48.4321],[-97.1332,48.4316],[-97.1315,48.4312],[-97.1305,48.4311],[-97.129,48.4311],[-97.1278,48.4313],[-97.1267,48.4319],[-97.1259,48.4325],[-97.1253,48.4329],[-97.1246,48.4337],[-97.1245,48.4341],[-97.1238,48.4355],[-97.1236,48.4361],[-97.1234,48.4371],[-97.1233,48.4376],[-97.1233,48.4383],[-97.1235,48.4389],[-97.1238,48.4399],[-97.124,48.4407],[-97.1243,48.4413],[-97.1245,48.4416],[-97.1248,48.4419],[-97.125,48.4421],[-97.1251,48.4422],[-97.1253,48.4423],[-97.1258,48.4427],[-97.1265,48.4432],[-97.128,48.4438],[-97.129,48.444],[-97.1295,48.4441],[-97.1314,48.4441],[-97.1328,48.4439],[-97.1345,48.4434],[-97.1355,48.4427],[-97.1363,48.4421],[-97.1365,48.4419],[-97.138,48.4405],[-97.1398,48.4392],[-97.141,48.4386],[-97.1428,48.4383],[-97.1451,48.4381],[-97.1464,48.4381],[-97.1477,48.4383],[-97.149,48.4389],[-97.1498,48.4392],[-97.1503,48.4397],[-97.1505,48.4403],[-97.1506,48.4409],[-97.1505,48.4413],[-97.1502,48.4419],[-97.1501,48.4422],[-97.1492,48.4434],[-97.1481,48.4441],[-97.1462,48.4448],[-97.1426,48.4459],[-97.1401,48.4467],[-97.1377,48.4477],[-97.1353,48.4489],[-97.1306,48.4523],[-97.1293,48.4541],[-97.1292,48.4564],[-97.1292,48.4566],[-97.1292,48.4569],[-97.1291,48.4575],[-97.1288,48.4585],[-97.1286,48.4596],[-97.1285,48.4604],[-97.1288,48.4616],[-97.1292,48.4622],[-97.1293,48.4624],[-97.1298,48.463],[-97.1306,48.4635],[-97.1319,48.4638],[-97.1334,48.4639],[-97.1347,48.4638],[-97.136,48.4635],[-97.138,48.463],[-97.1395,48.463],[-97.1407,48.463],[-97.142,48.4634],[-97.143,48.4639],[-97.1444,48.4649],[-97.1455,48.466],[-97.1463,48.4669],[-97.147,48.4677],[-97.1474,48.4684],[-97.148,48.47],[-97.1482,48.4708],[-97.148,48.4713],[-97.1477,48.4721],[-97.1474,48.4728],[-97.1465,48.4737],[-97.1461,48.4741],[-97.1445,48.4746],[-97.1432,48.4748],[-97.1419,48.4748],[-97.1407,48.4747],[-97.1393,48.4743],[-97.1379,48.4737],[-97.1368,48.4732],[-97.1352,48.4724],[-97.134,48.4718],[-97.1331,48.4715],[-97.1326,48.4714],[-97.1324,48.4713],[-97.1315,48.4712],[-97.1306,48.4713],[-97.1301,48.4714],[-97.1294,48.4715],[-97.1293,48.4717],[-97.1289,48.472],[-97.1283,48.4729],[-97.1281,48.4736],[-97.1281,48.4744],[-97.1285,48.4751],[-97.1289,48.4758],[-97.1293,48.4761],[-97.1297,48.4764],[-97.1308,48.4769],[-97.1324,48.4773],[-97.1346,48.4776],[-97.1364,48.4777],[-97.1384,48.4776],[-97.1406,48.4775],[-97.1419,48.4773],[-97.1433,48.4769],[-97.1448,48.4765],[-97.1461,48.4761],[-97.1477,48.4758],[-97.1493,48.4755],[-97.1509,48.4753],[-97.1511,48.4752],[-97.153,48.475],[-97.1549,48.475],[-97.1569,48.475],[-97.1585,48.4752],[-97.1599,48.4756],[-97.1609,48.4759],[-97.1616,48.4763],[-97.1622,48.477],[-97.1626,48.4778],[-97.1624,48.4786],[-97.1623,48.4792],[-97.1616,48.4799],[-97.1602,48.4807],[-97.1592,48.4812],[-97.1574,48.4816],[-97.1562,48.4818],[-97.1546,48.4821],[-97.1529,48.4822],[-97.1509,48.4824],[-97.1507,48.4824],[-97.1482,48.4828],[-97.1455,48.483],[-97.1437,48.4835],[-97.1424,48.4838],[-97.1411,48.4843],[-97.1402,48.4848],[-97.1396,48.4854],[-97.1394,48.486],[-97.1392,48.4864],[-97.1393,48.4873],[-97.1396,48.4881],[-97.1401,48.4887],[-97.1408,48.4892],[-97.1417,48.49],[-97.1428,48.4909],[-97.1433,48.4914],[-97.1433,48.492],[-97.143,48.4924],[-97.1423,48.4926],[-97.1415,48.4926],[-97.1406,48.4924],[-97.1399,48.492],[-97.139,48.4912],[-97.1382,48.4904],[-97.138,48.4897],[-97.1373,48.4889],[-97.1367,48.4884],[-97.136,48.4881],[-97.1351,48.4878],[-97.1344,48.4878],[-97.1332,48.4881],[-97.1322,48.4885],[-97.1315,48.4891],[-97.1312,48.4897],[-97.1311,48.4903],[-97.1311,48.4907],[-97.1316,48.4916],[-97.1322,48.4924],[-97.1334,48.4935],[-97.1345,48.4943],[-97.1367,48.4954],[-97.1388,48.496],[-97.1408,48.4967],[-97.1425,48.4972],[-97.1444,48.4976],[-97.1453,48.4979],[-97.1478,48.4995],[-97.148,48.4997],[-97.1483,48.5],[-97.1487,48.5004],[-97.1491,48.5009],[-97.1497,48.502],[-97.1499,48.5034],[-97.1498,48.5047],[-97.1498,48.5061],[-97.1495,48.5075],[-97.1495,48.5086],[-97.1497,48.5096],[-97.1502,48.5106],[-97.1502,48.5117],[-97.1499,48.512],[-97.1491,48.5124],[-97.1477,48.5124],[-97.142,48.5116],[-97.139,48.5117],[-97.1366,48.5123],[-97.1338,48.5139],[-97.1328,48.5146],[-97.1326,48.5148],[-97.1289,48.5173],[-97.1281,48.5178],[-97.127,48.519],[-97.1267,48.5202],[-97.1276,48.5215],[-97.1288,48.5222],[-97.129,48.5223],[-97.1307,48.5227],[-97.1339,48.5227],[-97.1366,48.5221],[-97.1385,48.5215],[-97.1395,48.521],[-97.1411,48.5202],[-97.1426,48.5195],[-97.1442,48.5191],[-97.1454,48.5188],[-97.1473,48.5188],[-97.1488,48.5189],[-97.1503,48.5194],[-97.1506,48.5195],[-97.1524,48.5204],[-97.154,48.5217],[-97.1547,48.5242],[-97.1549,48.5266],[-97.1544,48.5285],[-97.1536,48.5295],[-97.1536,48.5295],[-97.1527,48.5303],[-97.1513,48.5309],[-97.1507,48.5311],[-97.1499,48.5313],[-97.1482,48.5315],[-97.1458,48.5316],[-97.1438,48.5316],[-97.1422,48.5323],[-97.1411,48.5333],[-97.141,48.5343],[-97.1413,48.5355],[-97.1424,48.5366],[-97.144,48.5375],[-97.1456,48.5382],[-97.1481,48.5388],[-97.1505,48.5395],[-97.1508,48.5395],[-97.1533,48.5399],[-97.1558,48.5403],[-97.1582,48.5409],[-97.1596,48.5414],[-97.161,48.542],[-97.1614,48.5424],[-97.1631,48.5439],[-97.1631,48.544],[-97.1509,48.5439],[-97.1287,48.5439],[-97.107,48.544],[-97.0852,48.5441],[-97.0635,48.5441],[-97.0416,48.5442],[-97.0194,48.5441],[-96.9985,48.5441],[-96.9768,48.544],[-96.9551,48.5437],[-96.9331,48.5435],[-96.9138,48.5433],[-96.9115,48.5432],[-96.8896,48.5433],[-96.8678,48.5433],[-96.8459,48.5434],[-96.824,48.5436],[-96.8023,48.5436],[-96.7803,48.5435],[-96.7585,48.5436],[-96.7368,48.5437],[-96.7151,48.5437],[-96.6931,48.5437],[-96.6713,48.5436],[-96.6493,48.5437],[-96.6278,48.5437],[-96.6058,48.5437],[-96.5839,48.5437],[-96.5621,48.5436],[-96.54,48.5434],[-96.518,48.5434],[-96.4973,48.5434],[-96.4754,48.5435],[-96.4535,48.5436],[-96.4318,48.5438],[-96.4101,48.544],[-96.3882,48.5442]]],"type":"Polygon"},"id":"45","properties":{"Area":4698732287.54973,"CTYONLY_":6,"Code":"MARS","LASTMOD":"1984-01-12T14:12:49Z","Name":"Marshall","Perimiter":374207.65129},"type":"Feature"},{"geometry":{"coordinates":[[[-93.0884,48.6278],[-93.067,48.627],[-93.0456,48.6262],[-93.0237,48.6253],[-93.0021,48.6245],[-92.9845,48.6239],[-92.98,48.625],[-92.9641,48.6291],[-92.9585,48.6306],[-92.9547,48.6316],[-92.9497,48.6304],[-92.9498,48.6291],[-92.9499,48.6147],[-92.95,48.6084],[-92.9369,48.6075],[-92.9295,48.607],[-92.9177,48.6006],[-92.9151,48.5992],[-92.91,48.5964],[-92.8945,48.595],[-92.8932,48.5946],[-92.8729,48.5878],[-92.8652,48.5853],[-92.8515,48.5807],[-92.8301,48.5735],[-92.8206,48.5703],[-92.8079,48.5661],[-92.7863,48.5589],[-92.7767,48.5557],[-92.7665,48.5522],[-92.7439,48.5446],[-92.7354,48.5418],[-92.7284,48.5394],[-92.7227,48.54],[-92.7007,48.5421],[-92.7003,48.5421],[-92.6789,48.5442],[-92.6578,48.5463],[-92.6576,48.5462],[-92.6369,48.5429],[-92.6357,48.5427],[-92.6348,48.5426],[-92.6302,48.5284],[-92.6282,48.5223],[-92.6255,48.5179],[-92.6269,48.5142],[-92.6268,48.514],[-92.6264,48.5135],[-92.625,48.513],[-92.628,48.5108],[-92.6287,48.5106],[-92.6308,48.5092],[-92.6312,48.5082],[-92.6319,48.5068],[-92.6296,48.5058],[-92.627,48.5033],[-92.6306,48.5008],[-92.6351,48.4998],[-92.637,48.4994],[-92.6386,48.4996],[-92.64,48.4999],[-92.647,48.4999],[-92.654,48.5017],[-92.6569,48.4996],[-92.6582,48.4987],[-92.6614,48.4964],[-92.6789,48.4971],[-92.6857,48.4974],[-92.6986,48.4949],[-92.7011,48.4847],[-92.7016,48.4841],[-92.7092,48.4729],[-92.7085,48.4704],[-92.7089,48.4696],[-92.7126,48.463],[-92.7025,48.4551],[-92.7015,48.4543],[-92.6881,48.4438],[-92.6799,48.4425],[-92.6694,48.441],[-92.6635,48.4401],[-92.6586,48.4377],[-92.6562,48.4365],[-92.6371,48.4375],[-92.6157,48.4386],[-92.5935,48.4398],[-92.5765,48.4406],[-92.5717,48.4415],[-92.5686,48.4421],[-92.5499,48.4454],[-92.5369,48.4478],[-92.5284,48.448],[-92.515,48.4484],[-92.5074,48.448],[-92.507,48.4476],[-92.501,48.4422],[-92.4942,48.436],[-92.4893,48.4303],[-92.4849,48.4294],[-92.4837,48.4292],[-92.482,48.4283],[-92.4819,48.4279],[-92.4819,48.4276],[-92.4807,48.4264],[-92.481,48.4253],[-92.4788,48.4233],[-92.4754,48.4187],[-92.4631,48.4157],[-92.4564,48.4141],[-92.4564,48.4135],[-92.4563,48.4012],[-92.4602,48.3956],[-92.47,48.3813],[-92.4765,48.372],[-92.4747,48.3667],[-92.4697,48.3522],[-92.4697,48.3521],[-92.4591,48.3374],[-92.4558,48.3329],[-92.4523,48.3281],[-92.4476,48.3229],[-92.4415,48.3161],[-92.4413,48.3159],[-92.4405,48.3154],[-92.4403,48.3149],[-92.4386,48.3112],[-92.4367,48.309],[-92.4361,48.3085],[-92.4347,48.3074],[-92.4318,48.3052],[-92.4289,48.306],[-92.4256,48.3047],[-92.4204,48.299],[-92.4156,48.2951],[-92.415,48.2941],[-92.4135,48.2915],[-92.4065,48.2795],[-92.4017,48.2714],[-92.3967,48.2648],[-92.3931,48.2601],[-92.3927,48.259],[-92.3934,48.2576],[-92.3921,48.2568],[-92.3913,48.256],[-92.3891,48.2537],[-92.3901,48.2528],[-92.3912,48.2529],[-92.3922,48.2531],[-92.3926,48.2519],[-92.3923,48.2512],[-92.3912,48.2509],[-92.3907,48.2507],[-92.3897,48.2508],[-92.3887,48.2512],[-92.3867,48.2518],[-92.3858,48.2514],[-92.3853,48.2504],[-92.3852,48.2502],[-92.3846,48.2492],[-92.3868,48.2492],[-92.3863,48.2475],[-92.3878,48.247],[-92.3881,48.2465],[-92.3872,48.2444],[-92.3866,48.2441],[-92.3846,48.2449],[-92.3838,48.2446],[-92.3844,48.2425],[-92.3844,48.2414],[-92.384,48.2404],[-92.3833,48.2393],[-92.3816,48.2377],[-92.3806,48.2365],[-92.3789,48.2359],[-92.3789,48.2359],[-92.3785,48.2353],[-92.3791,48.2343],[-92.3781,48.233],[-92.3784,48.2321],[-92.3785,48.2312],[-92.3783,48.2304],[-92.3774,48.2293],[-92.3758,48.2283],[-92.3754,48.2275],[-92.3756,48.2267],[-92.3751,48.226],[-92.3743,48.2256],[-92.3734,48.225],[-92.3726,48.2236],[-92.3714,48.2241],[-92.3708,48.2239],[-92.3707,48.2228],[-92.3699,48.2218],[-92.3699,48.2212],[-92.3699,48.2203],[-92.3695,48.2203],[-92.3691,48.2202],[-92.368,48.2212],[-92.368,48.2212],[-92.3672,48.2217],[-92.3668,48.2223],[-92.3676,48.2232],[-92.3687,48.2237],[-92.368,48.2241],[-92.3662,48.224],[-92.365,48.2236],[-92.3636,48.2229],[-92.3621,48.2227],[-92.3616,48.2232],[-92.3613,48.224],[-92.361,48.2248],[-92.3603,48.2256],[-92.3586,48.2265],[-92.3566,48.2275],[-92.3555,48.2281],[-92.3544,48.2286],[-92.3537,48.2296],[-92.3535,48.2301],[-92.3517,48.2306],[-92.3494,48.2313],[-92.3484,48.2314],[-92.3477,48.2315],[-92.347,48.2315],[-92.3439,48.2321],[-92.3419,48.2317],[-92.3414,48.2319],[-92.3408,48.2337],[-92.3404,48.2341],[-92.3392,48.2347],[-92.339,48.2349],[-92.3386,48.2351],[-92.338,48.2351],[-92.3377,48.235],[-92.3371,48.2351],[-92.3365,48.2357],[-92.3362,48.2357],[-92.3346,48.2348],[-92.3344,48.2346],[-92.3344,48.2344],[-92.3343,48.2342],[-92.3338,48.2339],[-92.3333,48.2338],[-92.332,48.234],[-92.3308,48.2348],[-92.3302,48.2349],[-92.3292,48.2351],[-92.3281,48.2359],[-92.3274,48.2366],[-92.327,48.2369],[-92.3268,48.2368],[-92.3262,48.2366],[-92.3261,48.2366],[-92.3259,48.2367],[-92.3256,48.2369],[-92.3253,48.2371],[-92.3223,48.2373],[-92.3221,48.2373],[-92.3148,48.2406],[-92.3006,48.2422],[-92.2803,48.2444],[-92.2783,48.2451],[-92.2695,48.2482],[-92.2713,48.2519],[-92.2736,48.2566],[-92.2794,48.2596],[-92.2901,48.2651],[-92.291,48.2664],[-92.2945,48.2713],[-92.2931,48.276],[-92.2937,48.2767],[-92.2942,48.2766],[-92.2945,48.2764],[-92.2951,48.2763],[-92.2952,48.2763],[-92.2953,48.2765],[-92.2953,48.2767],[-92.2954,48.2769],[-92.2953,48.2771],[-92.2952,48.2772],[-92.2953,48.2773],[-92.2956,48.2773],[-92.2955,48.2776],[-92.2955,48.2777],[-92.2956,48.278],[-92.2972,48.2809],[-92.3014,48.2883],[-92.2987,48.2954],[-92.2945,48.3063],[-92.2987,48.3099],[-92.3018,48.3125],[-92.3061,48.3163],[-92.3044,48.3229],[-92.302,48.3232],[-92.2954,48.3239],[-92.2952,48.3246],[-92.2901,48.3392],[-92.2888,48.3429],[-92.2803,48.3468],[-92.2625,48.355],[-92.2588,48.3544],[-92.2364,48.3511],[-92.2216,48.3489],[-92.2197,48.3481],[-92.2191,48.3475],[-92.2189,48.3469],[-92.2181,48.3463],[-92.2169,48.345],[-92.2147,48.3452],[-92.2067,48.3457],[-92.2065,48.3473],[-92.2077,48.3479],[-92.2038,48.3519],[-92.195,48.3505],[-92.1945,48.3488],[-92.193,48.3488],[-92.1928,48.3488],[-92.1785,48.3519],[-92.179,48.3549],[-92.1791,48.3549],[-92.1774,48.3572],[-92.1709,48.3598],[-92.162,48.3634],[-92.1488,48.3652],[-92.1448,48.3657],[-92.1437,48.3561],[-92.1274,48.3556],[-92.106,48.355],[-92.0942,48.3546],[-92.0908,48.3545],[-92.0842,48.3538],[-92.0835,48.3538],[-92.0823,48.3547],[-92.0781,48.3581],[-92.067,48.3595],[-92.0625,48.3595],[-92.0552,48.3594],[-92.0525,48.3549],[-92.0488,48.3486],[-92.0458,48.3479],[-92.0451,48.3458],[-92.0478,48.3436],[-92.0475,48.3404],[-92.0469,48.3348],[-92.0404,48.3336],[-92.0376,48.3331],[-92.031,48.3261],[-92.0307,48.3257],[-92.0185,48.324],[-92.0119,48.323],[-92.0001,48.3211],[-92.0051,48.3118],[-92.0129,48.2975],[-92.0129,48.297],[-92.012,48.287],[-92.0087,48.2826],[-92.0072,48.2806],[-92.0066,48.2677],[-92.0065,48.2655],[-91.9949,48.262],[-91.9891,48.2603],[-91.9841,48.2531],[-91.9805,48.248],[-91.979,48.2475],[-91.9783,48.2474],[-91.9778,48.2474],[-91.9773,48.2472],[-91.9769,48.2468],[-91.977,48.2465],[-91.9772,48.2463],[-91.9773,48.2462],[-91.9775,48.246],[-91.9774,48.2457],[-91.9774,48.2456],[-91.9772,48.2455],[-91.9765,48.245],[-91.9756,48.2444],[-91.9744,48.2453],[-91.9743,48.2454],[-91.9742,48.2455],[-91.9738,48.2459],[-91.9736,48.2464],[-91.9735,48.2467],[-91.9726,48.247],[-91.9704,48.2479],[-91.97,48.2488],[-91.9706,48.249],[-91.9708,48.2494],[-91.9714,48.2499],[-91.9719,48.25],[-91.9724,48.2503],[-91.9724,48.2506],[-91.9723,48.251],[-91.9722,48.2513],[-91.9722,48.2518],[-91.9718,48.252],[-91.9718,48.2529],[-91.9714,48.2531],[-91.9709,48.253],[-91.9705,48.2531],[-91.9704,48.2534],[-91.9699,48.2538],[-91.959,48.2537],[-91.957,48.2524],[-91.9541,48.2523],[-91.954,48.2518],[-91.9541,48.2517],[-91.9541,48.2515],[-91.954,48.2495],[-91.9512,48.2479],[-91.948,48.246],[-91.9496,48.2446],[-91.9511,48.2444],[-91.9582,48.2439],[-91.957,48.2389],[-91.9573,48.2387],[-91.9597,48.2369],[-91.9583,48.2332],[-91.9524,48.2331],[-91.9512,48.2334],[-91.9507,48.2332],[-91.9451,48.2304],[-91.942,48.2304],[-91.9375,48.2343],[-91.9288,48.2359],[-91.9282,48.236],[-91.9211,48.2368],[-91.9167,48.2386],[-91.9148,48.239],[-91.9134,48.2389],[-91.9131,48.2385],[-91.9106,48.2382],[-91.9097,48.2384],[-91.9076,48.2384],[-91.9073,48.2383],[-91.907,48.2382],[-91.9065,48.2378],[-91.9058,48.2373],[-91.9023,48.2372],[-91.8931,48.238],[-91.885,48.2283],[-91.8843,48.2275],[-91.8769,48.2239],[-91.8675,48.2192],[-91.865,48.2095],[-91.8643,48.207],[-91.8634,48.2071],[-91.8453,48.2088],[-91.8417,48.2094],[-91.8416,48.2094],[-91.8359,48.2103],[-91.8326,48.2095],[-91.8325,48.2094],[-91.8325,48.2094],[-91.8325,48.2094],[-91.8325,48.2094],[-91.8199,48.2112],[-91.8154,48.2119],[-91.8144,48.2094],[-91.8141,48.2084],[-91.8094,48.2063],[-91.7982,48.203],[-91.7983,48.1953],[-91.7982,48.1808],[-91.7984,48.1662],[-91.7983,48.1515],[-91.7981,48.1369],[-91.798,48.1224],[-91.7987,48.1079],[-91.7992,48.0936],[-91.7997,48.0788],[-91.8001,48.0643],[-91.8,48.0496],[-91.8,48.0353],[-91.8,48.0206],[-91.8001,48.0059],[-91.7996,47.9914],[-91.7992,47.977],[-91.7985,47.9625],[-91.7979,47.9481],[-91.7977,47.9334],[-91.7978,47.9189],[-91.7979,47.9045],[-91.7979,47.8899],[-91.7983,47.8771],[-91.7983,47.876],[-91.7988,47.8618],[-91.7992,47.8464],[-91.8,47.8319],[-91.8,47.8175],[-91.7999,47.8031],[-91.7997,47.7916],[-91.7997,47.7893],[-91.7997,47.7886],[-91.7995,47.7774],[-91.7995,47.776],[-91.7995,47.7742],[-91.7995,47.7723],[-91.7992,47.7626],[-91.7992,47.7598],[-91.7992,47.7538],[-91.7993,47.7482],[-91.7993,47.7454],[-91.7992,47.7388],[-91.7992,47.7339],[-91.799,47.731],[-91.7984,47.7201],[-91.7982,47.717],[-91.7981,47.7165],[-91.7977,47.7128],[-91.7971,47.707],[-91.7967,47.7024],[-91.7959,47.6925],[-91.7959,47.688],[-91.7955,47.678],[-91.7955,47.6778],[-91.7955,47.6733],[-91.7954,47.6729],[-91.795,47.663],[-91.7948,47.6586],[-91.7942,47.6486],[-91.794,47.6449],[-91.794,47.6442],[-91.7933,47.6345],[-91.793,47.6299],[-91.7923,47.6212],[-91.7922,47.6193],[-91.7919,47.6155],[-91.7915,47.6091],[-91.7913,47.6049],[-91.7912,47.6021],[-91.7911,47.6008],[-91.7908,47.5904],[-91.7905,47.5874],[-91.7904,47.5864],[-91.7893,47.576],[-91.7892,47.5749],[-91.789,47.5719],[-91.7888,47.5614],[-91.7887,47.5588],[-91.7886,47.5574],[-91.7878,47.5469],[-91.788,47.5431],[-91.788,47.5424],[-91.7886,47.533],[-91.7886,47.5322],[-91.7889,47.5187],[-91.7889,47.5176],[-91.789,47.5067],[-91.7891,47.5041],[-91.7891,47.503],[-91.7894,47.493],[-91.7894,47.4897],[-91.7894,47.4886],[-91.7895,47.4753],[-91.7895,47.4741],[-91.7895,47.4605],[-91.7895,47.4574],[-91.7893,47.4449],[-91.7894,47.4303],[-91.7895,47.416],[-91.7896,47.4017],[-91.7904,47.3872],[-91.7906,47.3726],[-91.792,47.3726],[-91.792,47.3576],[-91.792,47.3432],[-91.7918,47.3288],[-91.7918,47.3145],[-91.7919,47.3],[-91.792,47.2855],[-91.7921,47.271],[-91.7922,47.2565],[-91.7923,47.2422],[-91.7923,47.2276],[-91.7923,47.2128],[-91.7922,47.1985],[-91.7923,47.1843],[-91.7923,47.1698],[-91.7923,47.1556],[-91.7923,47.1411],[-91.7924,47.1265],[-91.7922,47.1119],[-91.7943,47.1119],[-91.7945,47.0976],[-91.7945,47.0831],[-91.7944,47.0688],[-91.7944,47.0541],[-91.7943,47.0399],[-91.7943,47.0255],[-91.7944,47.0109],[-91.7944,46.9965],[-91.7944,46.9818],[-91.7944,46.9675],[-91.7943,46.953],[-91.7944,46.9397],[-91.7945,46.9397],[-91.7947,46.9396],[-91.7948,46.9395],[-91.795,46.9394],[-91.7951,46.9394],[-91.7952,46.9394],[-91.7953,46.9393],[-91.7954,46.9391],[-91.7955,46.939],[-91.7957,46.9388],[-91.7957,46.9386],[-91.7958,46.9384],[-91.7958,46.9384],[-91.7959,46.9383],[-91.796,46.9382],[-91.7961,46.9381],[-91.7964,46.938],[-91.7966,46.9379],[-91.797,46.9379],[-91.7971,46.9378],[-91.7974,46.9378],[-91.7975,46.9378],[-91.7978,46.9378],[-91.798,46.9379],[-91.7981,46.938],[-91.7983,46.938],[-91.7986,46.9379],[-91.7989,46.9379],[-91.7991,46.9379],[-91.7993,46.9379],[-91.7995,46.9378],[-91.7996,46.9377],[-91.7998,46.9376],[-91.8004,46.9373],[-91.8007,46.9371],[-91.8011,46.9369],[-91.8013,46.9368],[-91.8016,46.9367],[-91.802,46.9366],[-91.8022,46.9365],[-91.8025,46.9364],[-91.8028,46.9363],[-91.8032,46.9361],[-91.8034,46.936],[-91.8036,46.9359],[-91.8037,46.9357],[-91.804,46.9356],[-91.8042,46.9354],[-91.8044,46.9352],[-91.8046,46.935],[-91.8048,46.9349],[-91.805,46.9347],[-91.8051,46.9346],[-91.8053,46.9345],[-91.8055,46.9345],[-91.8057,46.9344],[-91.8059,46.9343],[-91.806,46.9343],[-91.8062,46.9342],[-91.8064,46.9341],[-91.8066,46.9338],[-91.8067,46.9336],[-91.8069,46.9334],[-91.807,46.9332],[-91.8071,46.9331],[-91.8071,46.933],[-91.8072,46.9329],[-91.8073,46.9328],[-91.8075,46.9328],[-91.8076,46.9327],[-91.8078,46.9327],[-91.808,46.9327],[-91.8082,46.9325],[-91.8084,46.9324],[-91.8087,46.9322],[-91.8089,46.932],[-91.8091,46.9319],[-91.8094,46.9317],[-91.8097,46.9315],[-91.81,46.9314],[-91.8103,46.9312],[-91.8106,46.9311],[-91.8107,46.931],[-91.8109,46.9309],[-91.811,46.9309],[-91.8112,46.9309],[-91.8113,46.9308],[-91.8116,46.9306],[-91.8117,46.9305],[-91.8119,46.9303],[-91.812,46.9301],[-91.8121,46.9299],[-91.8122,46.9298],[-91.8123,46.9296],[-91.8123,46.9293],[-91.8124,46.9291],[-91.8124,46.929],[-91.8125,46.9288],[-91.8126,46.9287],[-91.813,46.9281],[-91.8133,46.9277],[-91.8135,46.9275],[-91.8137,46.9272],[-91.8138,46.9271],[-91.8139,46.927],[-91.8141,46.9268],[-91.8142,46.9267],[-91.8144,46.9267],[-91.8147,46.9266],[-91.8149,46.9265],[-91.815,46.9263],[-91.8151,46.9263],[-91.8152,46.9262],[-91.8153,46.926],[-91.8154,46.9259],[-91.8154,46.9258],[-91.8155,46.9258],[-91.8157,46.9256],[-91.8159,46.9252],[-91.8162,46.925],[-91.8163,46.9248],[-91.8165,46.9247],[-91.8166,46.9246],[-91.8168,46.9244],[-91.817,46.9243],[-91.8171,46.9243],[-91.8173,46.9242],[-91.8175,46.9241],[-91.8177,46.924],[-91.8179,46.924],[-91.8182,46.9241],[-91.8184,46.9242],[-91.8186,46.9244],[-91.8187,46.9245],[-91.8189,46.9246],[-91.819,46.9246],[-91.8192,46.9247],[-91.8194,46.9248],[-91.8196,46.9248],[-91.8198,46.9248],[-91.8202,46.9248],[-91.8204,46.9248],[-91.8206,46.9248],[-91.8208,46.9249],[-91.821,46.925],[-91.822,46.9252],[-91.8222,46.9253],[-91.8224,46.9253],[-91.8227,46.9254],[-91.8232,46.9256],[-91.8234,46.9257],[-91.8237,46.9259],[-91.8238,46.926],[-91.824,46.9261],[-91.8241,46.9262],[-91.8242,46.9262],[-91.8243,46.9263],[-91.8243,46.9264],[-91.8245,46.9265],[-91.8252,46.9267],[-91.8255,46.9269],[-91.8256,46.9269],[-91.8258,46.927],[-91.8259,46.9272],[-91.826,46.9272],[-91.826,46.9273],[-91.8265,46.9274],[-91.8267,46.9274],[-91.827,46.9275],[-91.8274,46.9275],[-91.8277,46.9275],[-91.828,46.9275],[-91.8283,46.9275],[-91.8286,46.9275],[-91.8289,46.9275],[-91.8292,46.9275],[-91.8295,46.9275],[-91.83,46.9275],[-91.8303,46.9275],[-91.8307,46.9275],[-91.831,46.9275],[-91.8314,46.9274],[-91.8318,46.9274],[-91.8321,46.9274],[-91.8325,46.9274],[-91.8327,46.9273],[-91.833,46.9273],[-91.8332,46.9273],[-91.8335,46.9272],[-91.8337,46.9272],[-91.8342,46.9269],[-91.8345,46.9268],[-91.8347,46.9267],[-91.8348,46.9267],[-91.8348,46.9266],[-91.8349,46.9266],[-91.835,46.9266],[-91.835,46.9267],[-91.8348,46.9268],[-91.8348,46.9269],[-91.8347,46.927],[-91.8347,46.9271],[-91.8346,46.9272],[-91.8348,46.9272],[-91.8351,46.9271],[-91.8352,46.927],[-91.8355,46.9269],[-91.8357,46.9269],[-91.8359,46.9268],[-91.8361,46.9268],[-91.8363,46.9268],[-91.8365,46.9267],[-91.8365,46.9267],[-91.8367,46.9266],[-91.8368,46.9266],[-91.8369,46.9265],[-91.8371,46.9265],[-91.8374,46.9265],[-91.8376,46.9265],[-91.8377,46.9265],[-91.8379,46.9264],[-91.8381,46.9263],[-91.8383,46.9262],[-91.8386,46.9261],[-91.8389,46.9261],[-91.8391,46.926],[-91.8393,46.9259],[-91.8396,46.9258],[-91.8398,46.9257],[-91.8401,46.9256],[-91.8405,46.9255],[-91.8407,46.9254],[-91.841,46.9253],[-91.8413,46.9253],[-91.8415,46.9252],[-91.8417,46.9251],[-91.8418,46.9251],[-91.8424,46.9248],[-91.8426,46.9246],[-91.8431,46.9244],[-91.8432,46.9243],[-91.8435,46.9242],[-91.8441,46.9239],[-91.8446,46.9238],[-91.8449,46.9236],[-91.8454,46.9234],[-91.8457,46.9233],[-91.8458,46.9232],[-91.8461,46.923],[-91.8464,46.9229],[-91.8466,46.9226],[-91.847,46.9224],[-91.8472,46.9223],[-91.8474,46.9221],[-91.8475,46.922],[-91.8476,46.9219],[-91.8477,46.9219],[-91.8478,46.9218],[-91.8481,46.9216],[-91.8484,46.9215],[-91.8486,46.9213],[-91.8488,46.9211],[-91.8491,46.9209],[-91.8493,46.9208],[-91.8495,46.9207],[-91.8497,46.9204],[-91.8499,46.9203],[-91.8501,46.9201],[-91.8502,46.9199],[-91.8504,46.9198],[-91.8505,46.9197],[-91.8506,46.9197],[-91.8511,46.9193],[-91.8512,46.9192],[-91.8513,46.919],[-91.8514,46.9188],[-91.8517,46.9185],[-91.8519,46.9182],[-91.8521,46.9179],[-91.8524,46.9175],[-91.8526,46.9171],[-91.8528,46.9168],[-91.8531,46.9165],[-91.8533,46.9162],[-91.8535,46.9158],[-91.8536,46.9156],[-91.8538,46.9155],[-91.854,46.9153],[-91.8542,46.9151],[-91.8544,46.915],[-91.8546,46.9148],[-91.8548,46.9146],[-91.855,46.9144],[-91.8551,46.9143],[-91.8552,46.9142],[-91.8553,46.9141],[-91.8555,46.9139],[-91.8557,46.9137],[-91.8559,46.9136],[-91.8562,46.9136],[-91.8565,46.9134],[-91.8568,46.9132],[-91.8569,46.9131],[-91.857,46.9131],[-91.8571,46.913],[-91.8572,46.9129],[-91.8576,46.9127],[-91.8579,46.9126],[-91.8581,46.9126],[-91.8583,46.9126],[-91.8584,46.9126],[-91.8585,46.9124],[-91.8588,46.9122],[-91.8591,46.912],[-91.8596,46.9116],[-91.8599,46.9115],[-91.8602,46.9114],[-91.8603,46.9113],[-91.8605,46.9112],[-91.8607,46.911],[-91.8609,46.9109],[-91.861,46.9108],[-91.8612,46.9107],[-91.8613,46.9106],[-91.8614,46.9105],[-91.8615,46.9104],[-91.8617,46.9103],[-91.8619,46.9102],[-91.8625,46.9101],[-91.863,46.91],[-91.8633,46.91],[-91.8635,46.9099],[-91.8637,46.9099],[-91.8639,46.9097],[-91.8642,46.9096],[-91.8644,46.9095],[-91.8644,46.9095],[-91.8646,46.9094],[-91.8648,46.9093],[-91.865,46.9092],[-91.8652,46.909],[-91.8654,46.9089],[-91.8656,46.9089],[-91.8659,46.9088],[-91.8662,46.9087],[-91.8664,46.9087],[-91.8666,46.9086],[-91.8668,46.9086],[-91.8675,46.9084],[-91.8679,46.9084],[-91.8681,46.9085],[-91.8684,46.9085],[-91.8686,46.9085],[-91.8688,46.9085],[-91.8691,46.9085],[-91.8693,46.9085],[-91.8705,46.9084],[-91.8709,46.9084],[-91.8711,46.9084],[-91.8714,46.9083],[-91.8717,46.9083],[-91.8724,46.9082],[-91.8734,46.9081],[-91.874,46.9081],[-91.8745,46.908],[-91.8749,46.908],[-91.8751,46.908],[-91.8755,46.9078],[-91.8758,46.9075],[-91.8761,46.9074],[-91.8764,46.9073],[-91.8766,46.9073],[-91.8768,46.9072],[-91.8772,46.9072],[-91.8775,46.9072],[-91.878,46.9071],[-91.8782,46.9071],[-91.879,46.9067],[-91.8797,46.9064],[-91.8802,46.9062],[-91.8807,46.906],[-91.8811,46.9058],[-91.8829,46.9047],[-91.885,46.9037],[-91.8854,46.9035],[-91.8856,46.9033],[-91.8858,46.9032],[-91.8859,46.903],[-91.8861,46.9029],[-91.8861,46.9028],[-91.8864,46.9027],[-91.8866,46.9026],[-91.8868,46.9025],[-91.8873,46.9021],[-91.8875,46.9019],[-91.8882,46.9015],[-91.8885,46.9015],[-91.8887,46.9015],[-91.8889,46.9015],[-91.8892,46.9014],[-91.8905,46.9005],[-91.891,46.9001],[-91.8912,46.8998],[-91.8915,46.8996],[-91.8918,46.8994],[-91.892,46.8994],[-91.8933,46.8987],[-91.8947,46.8979],[-91.895,46.8977],[-91.8953,46.8975],[-91.8955,46.8973],[-91.8956,46.8971],[-91.8957,46.8969],[-91.8961,46.8966],[-91.8971,46.8959],[-91.8976,46.8955],[-91.8981,46.8952],[-91.8986,46.895],[-91.8987,46.895],[-91.899,46.8949],[-91.8992,46.8948],[-91.8994,46.8947],[-91.9004,46.894],[-91.9009,46.8937],[-91.901,46.8935],[-91.9013,46.8933],[-91.9026,46.8928],[-91.9029,46.8926],[-91.9031,46.8925],[-91.9034,46.8923],[-91.9037,46.892],[-91.9038,46.892],[-91.904,46.892],[-91.9043,46.8917],[-91.9045,46.8915],[-91.9049,46.8912],[-91.9053,46.8909],[-91.9057,46.8906],[-91.9066,46.89],[-91.9069,46.8896],[-91.907,46.8894],[-91.9081,46.8887],[-91.9086,46.8881],[-91.9088,46.8879],[-91.909,46.8876],[-91.9093,46.8873],[-91.9098,46.8867],[-91.9102,46.8864],[-91.9106,46.8862],[-91.9108,46.8862],[-91.9109,46.886],[-91.911,46.8859],[-91.911,46.8858],[-91.9111,46.8857],[-91.9112,46.8856],[-91.9113,46.8855],[-91.9115,46.8852],[-91.9116,46.885],[-91.9118,46.8848],[-91.9122,46.8845],[-91.913,46.8839],[-91.9134,46.8837],[-91.9137,46.8836],[-91.9139,46.8836],[-91.9142,46.8836],[-91.9141,46.8835],[-91.9142,46.8834],[-91.9143,46.8833],[-91.9145,46.8832],[-91.9147,46.8831],[-91.915,46.883],[-91.9153,46.8829],[-91.9156,46.8827],[-91.9159,46.8826],[-91.9161,46.8824],[-91.9169,46.882],[-91.9173,46.8818],[-91.9178,46.8816],[-91.9191,46.8812],[-91.9194,46.8811],[-91.9197,46.881],[-91.9199,46.8808],[-91.9201,46.8807],[-91.9204,46.8805],[-91.9205,46.8805],[-91.9209,46.8804],[-91.9214,46.8803],[-91.9226,46.8799],[-91.923,46.8797],[-91.9235,46.8796],[-91.9244,46.8792],[-91.9256,46.8788],[-91.926,46.8786],[-91.9263,46.8786],[-91.9268,46.8784],[-91.9276,46.8781],[-91.928,46.878],[-91.9284,46.8777],[-91.9297,46.8771],[-91.9301,46.8769],[-91.9305,46.8767],[-91.9309,46.8764],[-91.9312,46.8762],[-91.9315,46.8761],[-91.9316,46.876],[-91.9317,46.8759],[-91.9318,46.8758],[-91.9319,46.8758],[-91.932,46.8757],[-91.9321,46.8755],[-91.9322,46.8755],[-91.9324,46.8754],[-91.9326,46.8753],[-91.9329,46.8752],[-91.9332,46.8752],[-91.9335,46.8751],[-91.9337,46.8751],[-91.9339,46.875],[-91.934,46.8749],[-91.9341,46.8748],[-91.9343,46.8746],[-91.9345,46.8744],[-91.9346,46.8743],[-91.9349,46.874],[-91.9353,46.8738],[-91.9358,46.8737],[-91.9362,46.8736],[-91.9368,46.8735],[-91.9374,46.8734],[-91.938,46.8734],[-91.9386,46.8732],[-91.9391,46.873],[-91.9397,46.8727],[-91.9403,46.8723],[-91.9408,46.8721],[-91.941,46.8719],[-91.9411,46.8717],[-91.9413,46.8717],[-91.9415,46.8718],[-91.9416,46.8717],[-91.9417,46.8717],[-91.9419,46.8715],[-91.942,46.8712],[-91.9422,46.871],[-91.9424,46.8709],[-91.9428,46.8708],[-91.943,46.8708],[-91.9432,46.8706],[-91.9435,46.8704],[-91.9438,46.8704],[-91.9444,46.8702],[-91.9449,46.8699],[-91.9456,46.8696],[-91.9465,46.8694],[-91.9475,46.8691],[-91.9484,46.8688],[-91.9492,46.8685],[-91.9496,46.8682],[-91.9499,46.8679],[-91.9502,46.8678],[-91.9507,46.8677],[-91.9513,46.8675],[-91.952,46.8671],[-91.9524,46.8668],[-91.9527,46.8665],[-91.953,46.8662],[-91.9535,46.8659],[-91.9536,46.8658],[-91.9545,46.8654],[-91.9552,46.8651],[-91.956,46.8645],[-91.9565,46.8641],[-91.9568,46.8638],[-91.957,46.8636],[-91.9574,46.8633],[-91.9577,46.8631],[-91.9581,46.8628],[-91.9587,46.8623],[-91.959,46.8619],[-91.9593,46.8617],[-91.9596,46.8616],[-91.96,46.8614],[-91.9604,46.8612],[-91.9608,46.8609],[-91.9611,46.8605],[-91.9615,46.8602],[-91.9621,46.86],[-91.9627,46.8597],[-91.963,46.8596],[-91.9633,46.8595],[-91.964,46.8592],[-91.9646,46.8589],[-91.965,46.8586],[-91.9654,46.8582],[-91.9657,46.858],[-91.966,46.8579],[-91.9663,46.8578],[-91.9667,46.8576],[-91.9669,46.8576],[-91.967,46.8575],[-91.9671,46.8574],[-91.9672,46.8573],[-91.9673,46.8571],[-91.9675,46.857],[-91.9677,46.857],[-91.9679,46.8571],[-91.9681,46.857],[-91.9683,46.8569],[-91.9686,46.8568],[-91.9688,46.8567],[-91.9692,46.8565],[-91.9695,46.8564],[-91.97,46.8563],[-91.9704,46.8563],[-91.9708,46.8562],[-91.9711,46.8561],[-91.9714,46.8562],[-91.9716,46.8561],[-91.972,46.8559],[-91.9724,46.8558],[-91.9728,46.8558],[-91.9731,46.8559],[-91.9732,46.8558],[-91.9734,46.8557],[-91.9736,46.8556],[-91.974,46.8555],[-91.9741,46.8554],[-91.9742,46.8553],[-91.9745,46.8552],[-91.9748,46.8551],[-91.9751,46.8549],[-91.9754,46.8547],[-91.9755,46.8548],[-91.9757,46.8548],[-91.9762,46.8546],[-91.9764,46.8545],[-91.9767,46.8542],[-91.977,46.8539],[-91.9772,46.8537],[-91.9773,46.8534],[-91.9775,46.8533],[-91.9777,46.8533],[-91.978,46.8532],[-91.9784,46.853],[-91.9787,46.8529],[-91.9791,46.8526],[-91.9792,46.8525],[-91.9795,46.8524],[-91.9797,46.8523],[-91.98,46.8521],[-91.9802,46.8519],[-91.9805,46.8517],[-91.9808,46.8516],[-91.9811,46.8515],[-91.9815,46.8515],[-91.9819,46.8513],[-91.982,46.8513],[-91.9827,46.851],[-91.983,46.8508],[-91.9833,46.8506],[-91.9836,46.8504],[-91.9838,46.8503],[-91.9841,46.8503],[-91.9842,46.8502],[-91.9845,46.8501],[-91.9849,46.8499],[-91.9854,46.8496],[-91.9856,46.8495],[-91.9857,46.8493],[-91.9858,46.8491],[-91.986,46.8489],[-91.9861,46.8487],[-91.9863,46.8484],[-91.9866,46.8482],[-91.9869,46.848],[-91.987,46.8478],[-91.9871,46.8476],[-91.9875,46.8476],[-91.9877,46.8474],[-91.9881,46.8471],[-91.9884,46.8469],[-91.9885,46.8467],[-91.9885,46.8465],[-91.9887,46.8462],[-91.9889,46.846],[-91.9892,46.8458],[-91.9895,46.8456],[-91.9898,46.8455],[-91.9901,46.8454],[-91.9903,46.8451],[-91.9906,46.845],[-91.9908,46.8448],[-91.991,46.8446],[-91.9913,46.8443],[-91.9915,46.844],[-91.9918,46.8437],[-91.992,46.8434],[-91.9923,46.8431],[-91.9926,46.8427],[-91.9928,46.8424],[-91.9931,46.8422],[-91.9934,46.8421],[-91.9938,46.842],[-91.9941,46.8419],[-91.9944,46.8417],[-91.9949,46.8414],[-91.9954,46.8411],[-91.9959,46.8409],[-91.9964,46.8407],[-91.9969,46.8405],[-91.9973,46.8403],[-91.9978,46.84],[-91.9981,46.8397],[-91.9983,46.8395],[-91.9983,46.8392],[-91.9985,46.839],[-91.9986,46.8389],[-91.999,46.8387],[-91.9992,46.8386],[-91.9997,46.8384],[-92.0001,46.8381],[-92.0002,46.8381],[-92.0003,46.8382],[-92.0005,46.8381],[-92.0007,46.838],[-92.0009,46.838],[-92.0012,46.8379],[-92.0014,46.8377],[-92.0016,46.8375],[-92.0019,46.8374],[-92.0022,46.8373],[-92.0025,46.8373],[-92.003,46.8372],[-92.0033,46.8372],[-92.0036,46.8372],[-92.0039,46.8372],[-92.0041,46.8371],[-92.0042,46.837],[-92.0044,46.8369],[-92.0045,46.8369],[-92.0048,46.8367],[-92.0051,46.8366],[-92.0055,46.8366],[-92.0055,46.8366],[-92.0058,46.8364],[-92.0059,46.8363],[-92.0059,46.8362],[-92.0059,46.8361],[-92.006,46.8361],[-92.0061,46.836],[-92.0062,46.8359],[-92.0064,46.8359],[-92.0068,46.8358],[-92.007,46.8358],[-92.0072,46.8358],[-92.0074,46.8358],[-92.0078,46.8357],[-92.008,46.8357],[-92.0083,46.8357],[-92.0086,46.8356],[-92.0088,46.8356],[-92.009,46.8356],[-92.0093,46.8356],[-92.0096,46.8356],[-92.0101,46.8355],[-92.0105,46.8354],[-92.0106,46.8354],[-92.0109,46.8353],[-92.0112,46.8352],[-92.0115,46.8351],[-92.0117,46.8351],[-92.0118,46.835],[-92.012,46.835],[-92.0125,46.8348],[-92.0126,46.8348],[-92.0128,46.8346],[-92.013,46.8345],[-92.0132,46.8344],[-92.0134,46.8343],[-92.0136,46.8342],[-92.0137,46.8342],[-92.0139,46.834],[-92.0141,46.8338],[-92.0143,46.8338],[-92.0143,46.8337],[-92.0145,46.8336],[-92.0147,46.8336],[-92.0149,46.8336],[-92.0152,46.8336],[-92.0156,46.8336],[-92.016,46.8335],[-92.0165,46.8334],[-92.0169,46.8334],[-92.0172,46.8333],[-92.0177,46.8331],[-92.018,46.833],[-92.0184,46.8327],[-92.0185,46.8326],[-92.0187,46.8324],[-92.0189,46.8322],[-92.019,46.8321],[-92.0192,46.8319],[-92.0193,46.8318],[-92.0193,46.8317],[-92.0194,46.8317],[-92.0196,46.8316],[-92.0198,46.8316],[-92.0201,46.8315],[-92.0206,46.8314],[-92.0209,46.8313],[-92.0213,46.8312],[-92.0214,46.8311],[-92.0218,46.8309],[-92.0221,46.8307],[-92.0225,46.8305],[-92.023,46.8302],[-92.0234,46.83],[-92.0236,46.8298],[-92.0238,46.8296],[-92.024,46.8295],[-92.0241,46.8294],[-92.0243,46.8293],[-92.0245,46.8292],[-92.0247,46.8291],[-92.0249,46.8291],[-92.025,46.829],[-92.0252,46.8289],[-92.0253,46.8288],[-92.0255,46.8286],[-92.0256,46.8284],[-92.0257,46.8283],[-92.0259,46.8282],[-92.0261,46.828],[-92.0263,46.8277],[-92.0264,46.8276],[-92.0266,46.8274],[-92.0267,46.8272],[-92.0267,46.8271],[-92.0268,46.827],[-92.0268,46.827],[-92.0268,46.8269],[-92.0269,46.8268],[-92.027,46.8267],[-92.0272,46.8266],[-92.0272,46.8266],[-92.0274,46.8265],[-92.0275,46.8265],[-92.0276,46.8264],[-92.0277,46.8263],[-92.0277,46.8262],[-92.0277,46.8261],[-92.0278,46.826],[-92.0278,46.826],[-92.0278,46.8259],[-92.0279,46.8259],[-92.0281,46.8258],[-92.0282,46.8256],[-92.0283,46.8255],[-92.0284,46.8254],[-92.0285,46.8252],[-92.0285,46.825],[-92.0287,46.8249],[-92.0287,46.8248],[-92.0289,46.8246],[-92.0291,46.8245],[-92.0294,46.8244],[-92.0295,46.8242],[-92.0297,46.8242],[-92.0299,46.8241],[-92.0301,46.824],[-92.0303,46.824],[-92.0307,46.824],[-92.0309,46.8239],[-92.0311,46.8238],[-92.0313,46.8237],[-92.0315,46.8236],[-92.0316,46.8234],[-92.0317,46.8233],[-92.0318,46.8231],[-92.0318,46.8231],[-92.0319,46.823],[-92.032,46.8229],[-92.0322,46.8228],[-92.0326,46.8226],[-92.0329,46.8224],[-92.0329,46.8224],[-92.0333,46.8222],[-92.0335,46.8222],[-92.0337,46.8221],[-92.0338,46.822],[-92.0339,46.8219],[-92.0343,46.8218],[-92.0347,46.8218],[-92.0352,46.8217],[-92.0358,46.8215],[-92.0364,46.8214],[-92.0369,46.8213],[-92.0372,46.8212],[-92.0376,46.8211],[-92.038,46.8209],[-92.0382,46.8207],[-92.0384,46.8205],[-92.0385,46.8204],[-92.0386,46.8203],[-92.0387,46.8203],[-92.0388,46.8202],[-92.0389,46.8202],[-92.0392,46.8202],[-92.0397,46.8201],[-92.04,46.8201],[-92.0401,46.8202],[-92.0405,46.8202],[-92.0408,46.8203],[-92.0411,46.8203],[-92.0414,46.8203],[-92.0417,46.8203],[-92.0419,46.8202],[-92.0421,46.8201],[-92.0423,46.8201],[-92.0425,46.82],[-92.0427,46.82],[-92.0429,46.82],[-92.0431,46.8199],[-92.0434,46.8197],[-92.0437,46.8196],[-92.044,46.8195],[-92.0441,46.8194],[-92.0443,46.8193],[-92.0445,46.8193],[-92.0447,46.8192],[-92.045,46.8191],[-92.0452,46.819],[-92.0454,46.8189],[-92.0456,46.8188],[-92.0457,46.8187],[-92.0459,46.8186],[-92.046,46.8185],[-92.0461,46.8183],[-92.0462,46.8182],[-92.0462,46.8181],[-92.0463,46.818],[-92.0463,46.8179],[-92.0464,46.8178],[-92.0465,46.8177],[-92.0466,46.8175],[-92.0467,46.8174],[-92.0468,46.8173],[-92.0469,46.8173],[-92.0469,46.8173],[-92.0471,46.8172],[-92.0473,46.8171],[-92.0474,46.8171],[-92.0476,46.8169],[-92.0478,46.8169],[-92.048,46.8167],[-92.0481,46.8166],[-92.0481,46.8165],[-92.0482,46.8164],[-92.0483,46.8164],[-92.0484,46.8163],[-92.0485,46.8162],[-92.0486,46.8161],[-92.0489,46.816],[-92.049,46.8158],[-92.0492,46.8157],[-92.0494,46.8156],[-92.0495,46.8155],[-92.0497,46.8154],[-92.0498,46.8151],[-92.0499,46.815],[-92.05,46.8148],[-92.0501,46.8146],[-92.0503,46.8144],[-92.0504,46.8144],[-92.0505,46.8144],[-92.0507,46.8144],[-92.0509,46.8143],[-92.0511,46.8143],[-92.0513,46.8143],[-92.0517,46.8142],[-92.0519,46.8142],[-92.0523,46.814],[-92.0525,46.8139],[-92.0527,46.8138],[-92.0529,46.8137],[-92.0531,46.8135],[-92.0533,46.8132],[-92.0535,46.8131],[-92.0537,46.8128],[-92.0539,46.8126],[-92.054,46.8124],[-92.054,46.8123],[-92.0542,46.812],[-92.0544,46.8118],[-92.0546,46.8117],[-92.0549,46.8115],[-92.0551,46.8115],[-92.0553,46.8113],[-92.0556,46.8112],[-92.0559,46.811],[-92.0563,46.8109],[-92.0566,46.8108],[-92.0569,46.8107],[-92.0573,46.8106],[-92.0575,46.8106],[-92.0581,46.8106],[-92.0583,46.8105],[-92.0587,46.8104],[-92.0588,46.8103],[-92.059,46.8101],[-92.0593,46.8099],[-92.0594,46.8097],[-92.0595,46.8095],[-92.0597,46.8092],[-92.0598,46.809],[-92.06,46.8087],[-92.06,46.8084],[-92.0602,46.808],[-92.0602,46.8078],[-92.0603,46.8074],[-92.0605,46.8071],[-92.0606,46.8069],[-92.0608,46.8066],[-92.061,46.8065],[-92.0611,46.8063],[-92.0612,46.8061],[-92.0612,46.8059],[-92.0613,46.8057],[-92.0616,46.8054],[-92.0617,46.8052],[-92.0619,46.8049],[-92.0621,46.8047],[-92.0622,46.8045],[-92.0625,46.8044],[-92.0627,46.8042],[-92.063,46.8041],[-92.0634,46.8039],[-92.0637,46.8038],[-92.064,46.8037],[-92.0642,46.8037],[-92.0646,46.8035],[-92.0649,46.8034],[-92.0652,46.8033],[-92.0656,46.8031],[-92.0659,46.803],[-92.0662,46.8028],[-92.0665,46.8026],[-92.0668,46.8024],[-92.067,46.8024],[-92.0674,46.8023],[-92.0677,46.8022],[-92.068,46.8022],[-92.0682,46.8023],[-92.0685,46.8023],[-92.0686,46.8023],[-92.0686,46.8023],[-92.0689,46.8024],[-92.0691,46.8023],[-92.0694,46.8023],[-92.0696,46.8022],[-92.0699,46.802],[-92.0702,46.8018],[-92.0705,46.8016],[-92.0707,46.8014],[-92.0708,46.8012],[-92.071,46.801],[-92.0712,46.8008],[-92.0713,46.8007],[-92.0715,46.8006],[-92.0716,46.8006],[-92.0718,46.8006],[-92.072,46.8007],[-92.0721,46.8007],[-92.0723,46.8006],[-92.0726,46.8006],[-92.0728,46.8005],[-92.0731,46.8004],[-92.0736,46.8002],[-92.0739,46.8],[-92.0741,46.7999],[-92.0743,46.7997],[-92.0746,46.7995],[-92.0749,46.7994],[-92.0752,46.7993],[-92.0755,46.7992],[-92.0758,46.7991],[-92.0762,46.7989],[-92.0764,46.7988],[-92.0765,46.7986],[-92.0766,46.7985],[-92.0767,46.7983],[-92.0769,46.7983],[-92.0771,46.7983],[-92.0774,46.7983],[-92.0775,46.7982],[-92.0777,46.7981],[-92.0778,46.798],[-92.0779,46.7979],[-92.078,46.7978],[-92.078,46.7977],[-92.0781,46.7975],[-92.0782,46.7974],[-92.0783,46.7973],[-92.0785,46.7973],[-92.0785,46.7973],[-92.0787,46.7974],[-92.0788,46.7974],[-92.0791,46.7974],[-92.0794,46.7973],[-92.0796,46.7973],[-92.0798,46.7973],[-92.0801,46.7973],[-92.0804,46.7973],[-92.0806,46.7973],[-92.0809,46.7972],[-92.0812,46.7971],[-92.0814,46.797],[-92.0815,46.7969],[-92.0817,46.7967],[-92.0819,46.7966],[-92.082,46.7965],[-92.0821,46.7963],[-92.0821,46.7962],[-92.0822,46.796],[-92.0823,46.7959],[-92.0825,46.7959],[-92.0828,46.7958],[-92.0831,46.7958],[-92.0835,46.7957],[-92.0838,46.7957],[-92.0841,46.7957],[-92.0844,46.7957],[-92.0847,46.7957],[-92.085,46.7957],[-92.0853,46.7956],[-92.0856,46.7955],[-92.0857,46.7954],[-92.0858,46.7953],[-92.0859,46.7952],[-92.0861,46.7951],[-92.0862,46.795],[-92.0863,46.7948],[-92.0864,46.7947],[-92.0867,46.7946],[-92.0869,46.7945],[-92.0872,46.7944],[-92.0875,46.7943],[-92.0878,46.7941],[-92.0881,46.794],[-92.0884,46.7938],[-92.0886,46.7937],[-92.0889,46.7935],[-92.0891,46.7933],[-92.0892,46.7931],[-92.0892,46.7931],[-92.0893,46.7929],[-92.0895,46.7926],[-92.0897,46.7924],[-92.0899,46.7923],[-92.0901,46.7921],[-92.0902,46.792],[-92.0903,46.7919],[-92.0904,46.7917],[-92.0903,46.7916],[-92.0903,46.7915],[-92.0903,46.7913],[-92.0904,46.7912],[-92.0905,46.791],[-92.0905,46.7908],[-92.0907,46.7905],[-92.0908,46.7902],[-92.091,46.7898],[-92.0912,46.7896],[-92.0913,46.7895],[-92.0915,46.7893],[-92.0918,46.7892],[-92.092,46.7892],[-92.0923,46.7892],[-92.0928,46.7889],[-92.0929,46.7888],[-92.0932,46.7887],[-92.0934,46.7885],[-92.0936,46.7883],[-92.0938,46.7881],[-92.0939,46.788],[-92.094,46.7877],[-92.0941,46.7875],[-92.0941,46.7874],[-92.094,46.7872],[-92.094,46.7871],[-92.094,46.7869],[-92.0939,46.7867],[-92.0938,46.7864],[-92.0936,46.786],[-92.0935,46.7857],[-92.0934,46.7854],[-92.0934,46.7852],[-92.0933,46.7849],[-92.0932,46.7848],[-92.0932,46.7845],[-92.0931,46.7842],[-92.093,46.7839],[-92.0929,46.7836],[-92.0926,46.7832],[-92.0925,46.783],[-92.0924,46.7828],[-92.0923,46.7826],[-92.0921,46.7825],[-92.092,46.7823],[-92.0919,46.7821],[-92.0918,46.7819],[-92.0917,46.7817],[-92.0916,46.7814],[-92.0915,46.7813],[-92.0913,46.781],[-92.0911,46.7807],[-92.091,46.7804],[-92.0912,46.7801],[-92.0914,46.7787],[-92.0914,46.7784],[-92.0909,46.7775],[-92.0908,46.7773],[-92.09,46.7762],[-92.0897,46.7757],[-92.0894,46.7754],[-92.0892,46.7751],[-92.0889,46.7747],[-92.0888,46.7743],[-92.0879,46.7731],[-92.0879,46.773],[-92.0878,46.773],[-92.0876,46.7727],[-92.0859,46.7704],[-92.0859,46.7702],[-92.0849,46.7691],[-92.0846,46.7687],[-92.0842,46.7682],[-92.0838,46.7676],[-92.0829,46.7665],[-92.0829,46.7664],[-92.0826,46.7659],[-92.0819,46.7651],[-92.0812,46.7644],[-92.0811,46.7642],[-92.0784,46.7609],[-92.0781,46.7606],[-92.0768,46.759],[-92.0767,46.7588],[-92.0765,46.7587],[-92.0764,46.7584],[-92.076,46.7581],[-92.0758,46.7578],[-92.0739,46.7555],[-92.0735,46.7552],[-92.0735,46.755],[-92.073,46.7546],[-92.0729,46.7544],[-92.0726,46.754],[-92.0724,46.754],[-92.0724,46.7538],[-92.0717,46.7532],[-92.0716,46.753],[-92.0707,46.7521],[-92.0706,46.7519],[-92.0703,46.7517],[-92.0694,46.7506],[-92.0693,46.7505],[-92.069,46.7502],[-92.0688,46.75],[-92.0686,46.7497],[-92.0684,46.7495],[-92.0681,46.7491],[-92.0679,46.7489],[-92.0677,46.7487],[-92.0676,46.7486],[-92.0672,46.7481],[-92.0668,46.7478],[-92.0658,46.7466],[-92.0633,46.7441],[-92.0629,46.7437],[-92.0628,46.7435],[-92.0625,46.7432],[-92.0623,46.743],[-92.062,46.7427],[-92.0618,46.7424],[-92.0614,46.7421],[-92.0613,46.7419],[-92.0607,46.7414],[-92.0597,46.7403],[-92.0592,46.7399],[-92.0588,46.7394],[-92.0575,46.7381],[-92.0568,46.7374],[-92.0563,46.737],[-92.0559,46.7366],[-92.0546,46.7353],[-92.0546,46.7352],[-92.0544,46.7352],[-92.0542,46.735],[-92.054,46.7347],[-92.0504,46.7315],[-92.0477,46.7291],[-92.0466,46.7282],[-92.0466,46.728],[-92.0463,46.7279],[-92.0459,46.7275],[-92.0448,46.7265],[-92.0376,46.7206],[-92.037,46.7201],[-92.0348,46.7183],[-92.0274,46.7118],[-92.0269,46.7114],[-92.0267,46.7113],[-92.0265,46.7112],[-92.0264,46.7112],[-92.0258,46.7114],[-92.0253,46.7111],[-92.0243,46.7109],[-92.0214,46.7108],[-92.0205,46.7107],[-92.0194,46.7106],[-92.0192,46.7102],[-92.0192,46.7099],[-92.0187,46.7088],[-92.0174,46.7072],[-92.0164,46.7062],[-92.0163,46.706],[-92.0202,46.7041],[-92.025,46.7058],[-92.0262,46.7062],[-92.0269,46.7065],[-92.0339,46.709],[-92.0428,46.7153],[-92.0479,46.719],[-92.0501,46.7206],[-92.0594,46.7274],[-92.0648,46.7312],[-92.0687,46.734],[-92.0701,46.735],[-92.0713,46.7359],[-92.0894,46.7493],[-92.0985,46.7491],[-92.1001,46.7491],[-92.1081,46.7492],[-92.1086,46.749],[-92.1102,46.749],[-92.1138,46.7489],[-92.1165,46.7487],[-92.1173,46.7484],[-92.1184,46.7479],[-92.1252,46.745],[-92.1317,46.7422],[-92.1378,46.7396],[-92.1428,46.7351],[-92.1429,46.735],[-92.1432,46.7347],[-92.1433,46.7306],[-92.1433,46.7282],[-92.1412,46.7253],[-92.1438,46.7205],[-92.1448,46.7184],[-92.1462,46.716],[-92.1467,46.7158],[-92.1486,46.7152],[-92.1534,46.7158],[-92.1551,46.716],[-92.1672,46.72],[-92.1708,46.7189],[-92.1719,46.7185],[-92.1742,46.7173],[-92.1747,46.7172],[-92.176,46.7171],[-92.1788,46.7168],[-92.189,46.7176],[-92.1914,46.7163],[-92.1916,46.7157],[-92.1917,46.7153],[-92.1932,46.7113],[-92.1959,46.7089],[-92.1973,46.7077],[-92.1997,46.7067],[-92.2003,46.7064],[-92.2004,46.7064],[-92.201,46.7062],[-92.2015,46.706],[-92.2019,46.7058],[-92.2026,46.7054],[-92.2046,46.7041],[-92.2056,46.7026],[-92.2051,46.6984],[-92.1984,46.6962],[-92.1956,46.696],[-92.1892,46.6956],[-92.183,46.6953],[-92.178,46.692],[-92.1778,46.6919],[-92.1764,46.6903],[-92.176,46.6864],[-92.1775,46.6835],[-92.1813,46.6803],[-92.1824,46.68],[-92.1875,46.679],[-92.1906,46.6776],[-92.1916,46.6772],[-92.1924,46.6768],[-92.1957,46.6741],[-92.1958,46.674],[-92.1994,46.6703],[-92.204,46.667],[-92.2054,46.6648],[-92.2046,46.6634],[-92.2021,46.659],[-92.2015,46.6567],[-92.2022,46.6551],[-92.2044,46.6537],[-92.207,46.652],[-92.2123,46.65],[-92.2163,46.6499],[-92.2166,46.65],[-92.2234,46.6527],[-92.2262,46.6529],[-92.2284,46.653],[-92.2355,46.6501],[-92.2376,46.6498],[-92.2424,46.6493],[-92.2486,46.6535],[-92.2509,46.655],[-92.2521,46.6558],[-92.2525,46.6561],[-92.2545,46.6574],[-92.2549,46.6577],[-92.2556,46.6581],[-92.2565,46.6588],[-92.2587,46.6577],[-92.2596,46.6572],[-92.2659,46.6511],[-92.2705,46.6508],[-92.2727,46.6529],[-92.2735,46.655],[-92.2743,46.6575],[-92.2784,46.6587],[-92.2799,46.6587],[-92.2836,46.6589],[-92.2842,46.6592],[-92.2844,46.6594],[-92.2861,46.6604],[-92.287,46.6629],[-92.2871,46.6631],[-92.2872,46.6647],[-92.2873,46.6669],[-92.2873,46.6674],[-92.2881,46.6676],[-92.2907,46.6681],[-92.2912,46.6682],[-92.2921,46.6661],[-92.2922,46.665],[-92.2921,46.6633],[-92.301,46.6636],[-92.3012,46.6773],[-92.3012,46.6919],[-92.3013,46.7063],[-92.3014,46.7208],[-92.3016,46.7353],[-92.3014,46.7498],[-92.3015,46.7643],[-92.3223,46.7652],[-92.3435,46.7651],[-92.3646,46.765],[-92.3856,46.765],[-92.4064,46.7649],[-92.4283,46.765],[-92.4495,46.7657],[-92.4705,46.7656],[-92.4924,46.7657],[-92.5125,46.7658],[-92.5336,46.7659],[-92.5548,46.7662],[-92.5759,46.7667],[-92.5967,46.7665],[-92.6177,46.7667],[-92.6385,46.767],[-92.6592,46.7692],[-92.6803,46.7692],[-92.7014,46.7687],[-92.7226,46.7682],[-92.7442,46.7677],[-92.7459,46.7677],[-92.7653,46.7674],[-92.7864,46.7666],[-92.8084,46.7661],[-92.8296,46.7661],[-92.8508,46.7662],[-92.8721,46.7664],[-92.8932,46.7666],[-92.9143,46.7661],[-92.9356,46.7662],[-92.9567,46.7662],[-92.9777,46.7665],[-92.9988,46.7669],[-93.0201,46.7668],[-93.0412,46.7667],[-93.0615,46.7667],[-93.0609,46.781],[-93.061,46.7956],[-93.0606,46.81],[-93.0606,46.8241],[-93.0603,46.8387],[-93.06,46.853],[-93.0597,46.8672],[-93.059,46.8817],[-93.0587,46.8964],[-93.0582,46.9108],[-93.0583,46.9251],[-93.0577,46.9398],[-93.0576,46.9541],[-93.0573,46.9685],[-93.0571,46.9832],[-93.0568,46.9976],[-93.0564,47.0121],[-93.0559,47.0265],[-93.0557,47.0407],[-93.0558,47.0551],[-93.0558,47.0698],[-93.0557,47.084],[-93.056,47.0984],[-93.0562,47.1093],[-93.0664,47.1094],[-93.0663,47.1239],[-93.0659,47.1382],[-93.0659,47.1526],[-93.0655,47.1671],[-93.0652,47.1814],[-93.0654,47.196],[-93.0654,47.2103],[-93.0655,47.2248],[-93.0657,47.2394],[-93.0658,47.2538],[-93.0657,47.2683],[-93.0658,47.2828],[-93.0658,47.2975],[-93.0652,47.3119],[-93.0647,47.3265],[-93.0645,47.3412],[-93.0644,47.3556],[-93.0644,47.3716],[-93.0666,47.3716],[-93.0689,47.386],[-93.0693,47.4003],[-93.0692,47.4148],[-93.0692,47.429],[-93.069,47.4434],[-93.0688,47.4578],[-93.0673,47.472],[-93.067,47.4859],[-93.0651,47.5003],[-93.0647,47.5147],[-93.0641,47.529],[-93.0637,47.5445],[-93.0637,47.559],[-93.0638,47.5734],[-93.0628,47.5875],[-93.0628,47.6026],[-93.0643,47.6172],[-93.0637,47.6333],[-93.0637,47.6476],[-93.0633,47.6621],[-93.0626,47.6774],[-93.0619,47.691],[-93.0612,47.7056],[-93.0613,47.7205],[-93.0821,47.7206],[-93.0823,47.7355],[-93.0823,47.7493],[-93.0826,47.7635],[-93.083,47.7779],[-93.0834,47.7917],[-93.0837,47.8064],[-93.0837,47.8209],[-93.0837,47.8223],[-93.0831,47.835],[-93.083,47.8368],[-93.0823,47.8494],[-93.0822,47.8513],[-93.0815,47.8637],[-93.0813,47.8656],[-93.0812,47.8676],[-93.0808,47.878],[-93.0807,47.88],[-93.0808,47.8922],[-93.0808,47.8945],[-93.0809,47.9067],[-93.0809,47.9088],[-93.0809,47.9212],[-93.0809,47.9235],[-93.0809,47.9356],[-93.0809,47.938],[-93.0808,47.9504],[-93.0808,47.9525],[-93.0808,47.9647],[-93.0809,47.967],[-93.0809,47.9786],[-93.088,47.9787],[-93.0872,47.9932],[-93.0887,48.0075],[-93.0886,48.022],[-93.089,48.0366],[-93.0892,48.0509],[-93.0892,48.0679],[-93.0965,48.0678],[-93.0965,48.0679],[-93.0968,48.0823],[-93.097,48.0969],[-93.0972,48.1114],[-93.0969,48.1259],[-93.097,48.1402],[-93.097,48.1546],[-93.097,48.1692],[-93.0975,48.1836],[-93.0979,48.1981],[-93.0978,48.2126],[-93.0977,48.2271],[-93.0977,48.2426],[-93.0949,48.2425],[-93.0949,48.2426],[-93.0953,48.2576],[-93.0952,48.2716],[-93.095,48.2862],[-93.0952,48.3004],[-93.0953,48.3153],[-93.0948,48.3298],[-93.0948,48.3442],[-93.0945,48.3589],[-93.094,48.3734],[-93.094,48.3879],[-93.0938,48.4024],[-93.0935,48.4147],[-93.0923,48.4147],[-93.0922,48.429],[-93.0922,48.4303],[-93.092,48.4436],[-93.092,48.4449],[-93.0919,48.458],[-93.0918,48.4596],[-93.0915,48.4724],[-93.0914,48.474],[-93.0911,48.4867],[-93.091,48.4884],[-93.0905,48.501],[-93.0905,48.5151],[-93.0903,48.5296],[-93.0902,48.5441],[-93.0902,48.5583],[-93.09,48.5727],[-93.0898,48.5872],[-93.0895,48.6016],[-93.0886,48.6163],[-93.0884,48.6278]]],"type":"Polygon"},"id":"69","properties":{"Area":17451037319.2417,"CTYONLY_":7,"Code":"STLO","LASTMOD":"2010-10-17T00:00:00Z","Name":"St. Louis","Perimiter":682518.436},"type":"Feature"},{"geometry":{"coordinates":[[[-95.3425,48.5402],[-95.3412,48.5402],[-95.321,48.54],[-95.3194,48.54],[-95.2992,48.5402],[-95.2975,48.5401],[-95.2773,48.54],[-95.2756,48.54],[-95.2554,48.5398],[-95.2537,48.5398],[-95.2339,48.5399],[-95.2324,48.5399],[-95.2119,48.54],[-95.2115,48.5252],[-95.2115,48.5244],[-95.2111,48.5109],[-95.2111,48.5101],[-95.2112,48.4962],[-95.2111,48.4816],[-95.211,48.4673],[-95.211,48.4666],[-95.2112,48.4529],[-95.2113,48.4522],[-95.2113,48.4387],[-95.2113,48.4376],[-95.2113,48.4255],[-95.2113,48.4242],[-95.2113,48.4232],[-95.2112,48.4096],[-95.2112,48.4087],[-95.2111,48.3952],[-95.2111,48.3941],[-95.211,48.3808],[-95.211,48.3797],[-95.2106,48.3661],[-95.2066,48.3661],[-95.1983,48.3661],[-95.1887,48.3661],[-95.1861,48.3661],[-95.1669,48.3661],[-95.164,48.3661],[-95.1454,48.3662],[-95.1424,48.3662],[-95.1315,48.3662],[-95.1236,48.3663],[-95.1207,48.3663],[-95.1018,48.3663],[-95.1008,48.3663],[-95.099,48.3663],[-95.0801,48.3664],[-95.0773,48.3664],[-95.0586,48.3665],[-95.0555,48.3665],[-95.0369,48.3665],[-95.0337,48.3665],[-95.0153,48.3665],[-95.0119,48.3665],[-94.9932,48.3667],[-94.9901,48.3667],[-94.9716,48.3667],[-94.9684,48.3667],[-94.95,48.3666],[-94.9469,48.3666],[-94.9283,48.3667],[-94.9264,48.3667],[-94.9065,48.3666],[-94.9049,48.3666],[-94.8849,48.3666],[-94.8833,48.3667],[-94.8632,48.3667],[-94.8616,48.3667],[-94.8416,48.3669],[-94.8399,48.3669],[-94.8199,48.3669],[-94.8183,48.3669],[-94.7983,48.3669],[-94.7967,48.3669],[-94.7765,48.3669],[-94.7748,48.3669],[-94.7549,48.3669],[-94.7533,48.3669],[-94.7329,48.3669],[-94.7315,48.3669],[-94.7117,48.3668],[-94.7099,48.3669],[-94.6898,48.3671],[-94.683,48.3671],[-94.6694,48.3672],[-94.6679,48.3673],[-94.6622,48.3673],[-94.6505,48.3673],[-94.6465,48.3673],[-94.6405,48.3673],[-94.6245,48.3673],[-94.6188,48.3673],[-94.6029,48.3674],[-94.5971,48.3675],[-94.5812,48.3674],[-94.5754,48.3674],[-94.5593,48.3674],[-94.5536,48.3674],[-94.5378,48.3674],[-94.5335,48.3674],[-94.5157,48.3674],[-94.5118,48.3675],[-94.4941,48.3674],[-94.4924,48.3674],[-94.4906,48.3674],[-94.4722,48.3674],[-94.4688,48.3675],[-94.4505,48.3675],[-94.4471,48.3675],[-94.4288,48.3675],[-94.4252,48.3675],[-94.4253,48.352],[-94.425,48.3372],[-94.4248,48.3227],[-94.4246,48.3081],[-94.4244,48.2938],[-94.4243,48.2791],[-94.424,48.2649],[-94.4237,48.2504],[-94.4237,48.2356],[-94.4238,48.2212],[-94.4236,48.2067],[-94.4233,48.1923],[-94.4235,48.1781],[-94.4235,48.1637],[-94.4233,48.1491],[-94.4236,48.1348],[-94.4234,48.1204],[-94.4233,48.1059],[-94.4231,48.092],[-94.4234,48.0776],[-94.4247,48.0632],[-94.4246,48.0489],[-94.4241,48.0344],[-94.4236,48.0199],[-94.4176,48.02],[-94.4177,48.006],[-94.4176,47.9914],[-94.4173,47.9769],[-94.4172,47.9623],[-94.4174,47.9477],[-94.4175,47.9332],[-94.4174,47.9186],[-94.4175,47.9175],[-94.4176,47.9041],[-94.4177,47.9031],[-94.418,47.8886],[-94.4184,47.8744],[-94.4186,47.86],[-94.4185,47.8459],[-94.4186,47.8316],[-94.4187,47.817],[-94.4188,47.8026],[-94.4189,47.7881],[-94.4189,47.7735],[-94.4191,47.759],[-94.4192,47.7445],[-94.4191,47.7302],[-94.419,47.7155],[-94.4187,47.7012],[-94.4185,47.6867],[-94.4184,47.6721],[-94.417,47.6722],[-94.417,47.6578],[-94.4167,47.6435],[-94.4165,47.6291],[-94.4163,47.615],[-94.4159,47.6009],[-94.4136,47.5866],[-94.4144,47.5723],[-94.414,47.5578],[-94.4148,47.5432],[-94.4146,47.5286],[-94.4149,47.5145],[-94.4151,47.5],[-94.4154,47.4861],[-94.4156,47.4717],[-94.416,47.4571],[-94.4161,47.4449],[-94.4161,47.443],[-94.4157,47.4287],[-94.4159,47.4119],[-94.4372,47.4118],[-94.4586,47.4118],[-94.4798,47.4119],[-94.5009,47.412],[-94.5243,47.4114],[-94.5458,47.4109],[-94.5636,47.411],[-94.585,47.411],[-94.6069,47.4101],[-94.6279,47.4103],[-94.6492,47.4102],[-94.6702,47.4102],[-94.6918,47.4098],[-94.7129,47.4095],[-94.7344,47.4098],[-94.7563,47.4105],[-94.7777,47.4102],[-94.7998,47.4098],[-94.8209,47.41],[-94.8423,47.4102],[-94.8636,47.4103],[-94.8849,47.4105],[-94.9063,47.4107],[-94.9274,47.4118],[-94.9487,47.4115],[-94.97,47.4114],[-94.9914,47.4114],[-95.0127,47.4114],[-95.0341,47.4117],[-95.0557,47.4119],[-95.0766,47.4123],[-95.098,47.4125],[-95.1193,47.4126],[-95.1406,47.4125],[-95.1619,47.4127],[-95.1829,47.4127],[-95.1828,47.4268],[-95.1828,47.4412],[-95.1829,47.4557],[-95.183,47.4703],[-95.1831,47.4845],[-95.1833,47.499],[-95.1837,47.5135],[-95.1839,47.528],[-95.1841,47.5424],[-95.1841,47.5566],[-95.1844,47.571],[-95.1847,47.5861],[-95.1849,47.6006],[-95.1849,47.6151],[-95.1849,47.6297],[-95.1849,47.6442],[-95.1847,47.6587],[-95.1849,47.6735],[-95.1904,47.6734],[-95.1941,47.6734],[-95.1944,47.688],[-95.1944,47.7024],[-95.1943,47.717],[-95.1942,47.7313],[-95.1941,47.746],[-95.1941,47.7606],[-95.1939,47.7752],[-95.1939,47.7896],[-95.1938,47.8033],[-95.1937,47.8044],[-95.1937,47.8188],[-95.1936,47.8334],[-95.1935,47.8479],[-95.1935,47.8624],[-95.1934,47.8726],[-95.2003,47.8732],[-95.2025,47.8735],[-95.205,47.874],[-95.2071,47.8742],[-95.2103,47.8744],[-95.2105,47.8745],[-95.2146,47.875],[-95.215,47.8751],[-95.2172,47.8755],[-95.2193,47.876],[-95.2218,47.8765],[-95.223,47.8768],[-95.2288,47.8781],[-95.2313,47.8788],[-95.2345,47.8798],[-95.2359,47.8803],[-95.2374,47.8807],[-95.2377,47.8807],[-95.238,47.8809],[-95.2397,47.8814],[-95.2415,47.882],[-95.2456,47.8829],[-95.2473,47.8837],[-95.2485,47.8844],[-95.2502,47.8852],[-95.2518,47.8861],[-95.2538,47.8876],[-95.2558,47.8891],[-95.2578,47.8903],[-95.258,47.8905],[-95.2585,47.8909],[-95.2592,47.8917],[-95.2592,47.8918],[-95.26,47.8925],[-95.2618,47.8944],[-95.2625,47.895],[-95.2635,47.896],[-95.2655,47.8979],[-95.2657,47.8981],[-95.266,47.8984],[-95.2661,47.8985],[-95.2663,47.8987],[-95.2664,47.8991],[-95.2665,47.8992],[-95.2665,47.8993],[-95.2666,47.8993],[-95.2668,47.8999],[-95.2671,47.9004],[-95.2677,47.901],[-95.2681,47.9016],[-95.2681,47.9017],[-95.2683,47.902],[-95.2688,47.9029],[-95.2689,47.9032],[-95.2699,47.9049],[-95.2701,47.9056],[-95.2702,47.9059],[-95.2703,47.9062],[-95.2704,47.9062],[-95.2704,47.9063],[-95.2705,47.9064],[-95.2705,47.9064],[-95.2706,47.9066],[-95.2709,47.9069],[-95.2709,47.907],[-95.2723,47.9089],[-95.2728,47.9097],[-95.2728,47.9098],[-95.2729,47.9099],[-95.2729,47.9101],[-95.2732,47.9107],[-95.2734,47.9114],[-95.2734,47.9116],[-95.2735,47.9116],[-95.2736,47.9121],[-95.2738,47.9125],[-95.2738,47.9128],[-95.2741,47.9135],[-95.2741,47.9139],[-95.2748,47.9154],[-95.275,47.9156],[-95.2753,47.9162],[-95.2754,47.9168],[-95.2756,47.9172],[-95.2756,47.9175],[-95.2761,47.92],[-95.2762,47.9206],[-95.2762,47.9206],[-95.2763,47.921],[-95.2764,47.9215],[-95.2765,47.922],[-95.2766,47.9227],[-95.2767,47.9231],[-95.2768,47.9236],[-95.2771,47.9247],[-95.2774,47.9254],[-95.2774,47.9257],[-95.2776,47.9263],[-95.2778,47.9281],[-95.278,47.9286],[-95.2781,47.9302],[-95.278,47.9321],[-95.2779,47.9328],[-95.2779,47.9351],[-95.2779,47.9351],[-95.2774,47.938],[-95.2772,47.9384],[-95.2772,47.9389],[-95.277,47.9414],[-95.2769,47.9416],[-95.2767,47.9438],[-95.2767,47.9449],[-95.2761,47.947],[-95.2759,47.9474],[-95.2756,47.9487],[-95.2755,47.9488],[-95.2753,47.9495],[-95.2751,47.9507],[-95.2749,47.9515],[-95.2743,47.9529],[-95.2743,47.9531],[-95.2742,47.9534],[-95.2742,47.9541],[-95.2741,47.9561],[-95.274,47.9568],[-95.2739,47.9574],[-95.2735,47.958],[-95.2731,47.9584],[-95.2729,47.9586],[-95.2728,47.9587],[-95.2726,47.959],[-95.2726,47.9593],[-95.2725,47.9605],[-95.2722,47.961],[-95.2712,47.9623],[-95.271,47.9628],[-95.2708,47.9632],[-95.2706,47.9636],[-95.2703,47.9637],[-95.2701,47.9639],[-95.2701,47.964],[-95.2698,47.9643],[-95.2694,47.9655],[-95.268,47.9688],[-95.267,47.9704],[-95.267,47.9707],[-95.2667,47.9708],[-95.2664,47.9714],[-95.2657,47.9727],[-95.2646,47.9748],[-95.2645,47.9752],[-95.2639,47.9765],[-95.2636,47.9771],[-95.2627,47.9786],[-95.2618,47.9803],[-95.259,47.9839],[-95.2585,47.9852],[-95.2583,47.9856],[-95.2582,47.9865],[-95.258,47.987],[-95.2579,47.9875],[-95.2576,47.9883],[-95.2571,47.9891],[-95.2554,47.9917],[-95.2551,47.992],[-95.2546,47.9926],[-95.2543,47.9932],[-95.253,47.9954],[-95.2526,47.9964],[-95.2523,47.9968],[-95.252,47.9971],[-95.2518,47.9973],[-95.2512,47.998],[-95.2508,47.9988],[-95.2507,47.999],[-95.2507,48.0],[-95.2504,48.0],[-95.2502,48.0],[-95.2495,48.0],[-95.2495,48.0009],[-95.2493,48.0015],[-95.249,48.002],[-95.2486,48.0025],[-95.2481,48.0029],[-95.2479,48.0031],[-95.2477,48.0041],[-95.2472,48.0046],[-95.247,48.0048],[-95.2464,48.0055],[-95.2459,48.0059],[-95.2455,48.0066],[-95.245,48.0071],[-95.2449,48.0072],[-95.2445,48.0076],[-95.2445,48.0076],[-95.2444,48.008],[-95.2442,48.0081],[-95.2441,48.0083],[-95.2439,48.0086],[-95.2439,48.0087],[-95.2438,48.0087],[-95.2433,48.009],[-95.2423,48.0097],[-95.2421,48.01],[-95.2418,48.0103],[-95.2417,48.0106],[-95.2414,48.0108],[-95.2414,48.0109],[-95.2409,48.0111],[-95.2407,48.0112],[-95.2404,48.0114],[-95.2401,48.0117],[-95.24,48.0119],[-95.24,48.0119],[-95.2396,48.0123],[-95.2394,48.0124],[-95.2387,48.0127],[-95.2377,48.0134],[-95.2376,48.0135],[-95.2372,48.0139],[-95.2371,48.0142],[-95.2371,48.0143],[-95.237,48.0144],[-95.2368,48.0145],[-95.2367,48.0145],[-95.2363,48.0148],[-95.2362,48.0148],[-95.2358,48.0149],[-95.2354,48.0152],[-95.2352,48.0155],[-95.2347,48.0158],[-95.2326,48.017],[-95.2323,48.0174],[-95.2306,48.0185],[-95.2304,48.0188],[-95.2303,48.0191],[-95.2297,48.0196],[-95.2293,48.0199],[-95.2289,48.0201],[-95.2378,48.0201],[-95.2473,48.0201],[-95.2493,48.0201],[-95.2594,48.0201],[-95.269,48.0201],[-95.281,48.0202],[-95.2887,48.0201],[-95.2906,48.0201],[-95.2933,48.0201],[-95.3025,48.0202],[-95.3122,48.0202],[-95.3224,48.0203],[-95.3338,48.0203],[-95.3401,48.0203],[-95.3439,48.0204],[-95.3554,48.0204],[-95.3654,48.0204],[-95.3661,48.0204],[-95.377,48.0205],[-95.3871,48.0206],[-95.3985,48.0206],[-95.4086,48.0207],[-95.4201,48.0206],[-95.4302,48.0206],[-95.4417,48.0206],[-95.4523,48.0206],[-95.4632,48.0207],[-95.4738,48.0207],[-95.485,48.0207],[-95.4954,48.0207],[-95.4959,48.0207],[-95.5065,48.0208],[-95.517,48.0208],[-95.5215,48.0209],[-95.5277,48.0209],[-95.5384,48.0209],[-95.5398,48.0209],[-95.5491,48.0209],[-95.5597,48.0208],[-95.5705,48.0208],[-95.5828,48.0207],[-95.5922,48.0207],[-95.5923,48.035],[-95.5925,48.0497],[-95.5925,48.0642],[-95.5926,48.0787],[-95.5928,48.0931],[-95.593,48.1078],[-95.5931,48.1223],[-95.5936,48.1368],[-95.5938,48.1512],[-95.5939,48.1658],[-95.5939,48.173],[-95.594,48.1802],[-95.5938,48.1946],[-95.5939,48.2092],[-95.5939,48.2236],[-95.5941,48.2382],[-95.5941,48.2526],[-95.5937,48.267],[-95.5934,48.2815],[-95.5934,48.2961],[-95.5932,48.3105],[-95.5932,48.325],[-95.5932,48.3396],[-95.5933,48.354],[-95.5933,48.3656],[-95.5933,48.3656],[-95.6016,48.3655],[-95.602,48.3798],[-95.6021,48.3809],[-95.6026,48.3942],[-95.6026,48.395],[-95.6026,48.4088],[-95.6026,48.4095],[-95.6023,48.4232],[-95.6023,48.424],[-95.6021,48.4376],[-95.602,48.4385],[-95.6016,48.4522],[-95.6016,48.453],[-95.6016,48.4666],[-95.6016,48.4674],[-95.6011,48.4811],[-95.6011,48.4818],[-95.6008,48.4956],[-95.6008,48.4964],[-95.6007,48.51],[-95.6007,48.5107],[-95.6011,48.5251],[-95.6023,48.5389],[-95.5821,48.5387],[-95.5801,48.5387],[-95.5603,48.5388],[-95.558,48.5388],[-95.5383,48.5389],[-95.5365,48.5389],[-95.5163,48.539],[-95.5143,48.539],[-95.495,48.5392],[-95.493,48.5392],[-95.4726,48.5396],[-95.4712,48.5396],[-95.4513,48.5399],[-95.4494,48.5399],[-95.4297,48.5399],[-95.4279,48.54],[-95.4078,48.5402],[-95.4061,48.5402],[-95.386,48.5402],[-95.3844,48.5402],[-95.364,48.5403],[-95.3628,48.5404],[-95.3425,48.5402]]],"type":"Polygon"},"id":"4","properties":{"Area":7911449532.86586,"CTYONLY_":8,"Code":"BELT","LASTMOD":"1999-12-31T23:59:59Z","Name":"Beltrami","Perimiter":429419.1705},"type":"Feature"},{"geometry":{"coordinates":[[[-97.1467,48.1733],[-97.1462,48.1733],[-97.1376,48.1733],[-97.1322,48.1733],[-97.1286,48.1733],[-97.1257,48.1733],[-97.1253,48.1733],[-97.1071,48.1735],[-97.1069,48.1735],[-97.0855,48.1734],[-97.0853,48.1734],[-97.0637,48.1732],[-97.0637,48.1732],[-97.042,48.1732],[-97.042,48.1732],[-97.0205,48.1733],[-97.0203,48.1733],[-97.0003,48.1732],[-96.999,48.1732],[-96.9989,48.1732],[-96.9987,48.1732],[-96.998,48.1732],[-96.9975,48.1732],[-96.9959,48.1732],[-96.99,48.1731],[-96.9889,48.1731],[-96.9844,48.1731],[-96.9812,48.1731],[-96.9775,48.1731],[-96.9773,48.173],[-96.9773,48.173],[-96.9751,48.173],[-96.9749,48.173],[-96.9705,48.1731],[-96.9703,48.1731],[-96.9554,48.1731],[-96.9448,48.1732],[-96.9387,48.1732],[-96.934,48.1733],[-96.9339,48.1733],[-96.933,48.1733],[-96.9123,48.1733],[-96.9122,48.1733],[-96.8932,48.1732],[-96.8907,48.1732],[-96.8907,48.1732],[-96.8753,48.1732],[-96.869,48.1733],[-96.869,48.1733],[-96.8474,48.1733],[-96.8473,48.1733],[-96.8255,48.1734],[-96.8255,48.1734],[-96.8111,48.1734],[-96.8039,48.1734],[-96.8038,48.1734],[-96.7932,48.1733],[-96.7821,48.1734],[-96.7821,48.1734],[-96.7819,48.1734],[-96.7613,48.1734],[-96.7606,48.1734],[-96.7605,48.1734],[-96.7581,48.1734],[-96.7573,48.1734],[-96.7503,48.1734],[-96.7393,48.1734],[-96.7393,48.1734],[-96.7177,48.1734],[-96.7176,48.1734],[-96.6959,48.1734],[-96.6958,48.1734],[-96.6826,48.1735],[-96.6742,48.1736],[-96.6742,48.1736],[-96.6525,48.1738],[-96.6525,48.1738],[-96.6407,48.1739],[-96.6378,48.1738],[-96.6338,48.1737],[-96.6309,48.1737],[-96.6307,48.1737],[-96.6307,48.1737],[-96.6253,48.1737],[-96.6106,48.1737],[-96.6092,48.1737],[-96.609,48.1737],[-96.6055,48.1737],[-96.5966,48.1737],[-96.5893,48.1737],[-96.5875,48.1737],[-96.5873,48.1737],[-96.5873,48.1737],[-96.5838,48.1738],[-96.5806,48.1739],[-96.5765,48.1739],[-96.5748,48.1739],[-96.5715,48.1739],[-96.5678,48.174],[-96.5655,48.174],[-96.5654,48.174],[-96.565,48.174],[-96.5616,48.1739],[-96.557,48.1739],[-96.5544,48.1738],[-96.5507,48.1738],[-96.5479,48.1738],[-96.5446,48.1738],[-96.5443,48.1738],[-96.5442,48.1738],[-96.5434,48.1738],[-96.5399,48.1738],[-96.5357,48.1738],[-96.53,48.1738],[-96.5251,48.1738],[-96.5223,48.1739],[-96.5204,48.1739],[-96.5164,48.1739],[-96.5091,48.174],[-96.5038,48.174],[-96.5008,48.1742],[-96.5008,48.1669],[-96.5008,48.1524],[-96.5006,48.1379],[-96.5007,48.1234],[-96.501,48.1089],[-96.5009,48.0943],[-96.5009,48.0798],[-96.5009,48.0654],[-96.5008,48.0506],[-96.5009,48.0362],[-96.5009,48.0217],[-96.4826,48.0217],[-96.4826,48.0072],[-96.4824,47.9924],[-96.4823,47.9782],[-96.4823,47.9636],[-96.4825,47.949],[-96.4826,47.9347],[-96.4825,47.9202],[-96.4825,47.9055],[-96.4825,47.9054],[-96.4824,47.8913],[-96.4827,47.8768],[-96.4821,47.862],[-96.482,47.8475],[-96.4601,47.8475],[-96.4386,47.8476],[-96.4172,47.8475],[-96.3958,47.8475],[-96.3742,47.8474],[-96.3527,47.8473],[-96.3524,47.8329],[-96.3523,47.8184],[-96.3521,47.8038],[-96.352,47.7893],[-96.3519,47.7748],[-96.3516,47.7604],[-96.3313,47.7603],[-96.3097,47.7601],[-96.2884,47.7601],[-96.2668,47.7599],[-96.2453,47.7598],[-96.2238,47.7598],[-96.2022,47.7597],[-96.1806,47.7598],[-96.159,47.7598],[-96.1388,47.7598],[-96.1175,47.7602],[-96.0957,47.76],[-96.0743,47.7601],[-96.053,47.7603],[-96.0315,47.7605],[-96.0097,47.7605],[-95.9883,47.7605],[-95.9671,47.7605],[-95.9452,47.7606],[-95.9233,47.7607],[-95.9017,47.7609],[-95.8801,47.7608],[-95.8588,47.7609],[-95.8372,47.7609],[-95.8371,47.7755],[-95.8365,47.79],[-95.8366,47.8043],[-95.8366,47.819],[-95.8367,47.8335],[-95.8366,47.8482],[-95.8153,47.8484],[-95.7952,47.8483],[-95.7737,47.8484],[-95.7525,47.8485],[-95.7307,47.8487],[-95.709,47.8486],[-95.7089,47.863],[-95.7094,47.8776],[-95.7095,47.8919],[-95.7094,47.9065],[-95.7098,47.9211],[-95.7096,47.9355],[-95.6898,47.9354],[-95.6683,47.9351],[-95.6466,47.9348],[-95.6252,47.9344],[-95.6034,47.9341],[-95.5824,47.9339],[-95.5817,47.9195],[-95.5816,47.9051],[-95.5814,47.8904],[-95.5813,47.876],[-95.5812,47.8617],[-95.5809,47.847],[-95.5805,47.8327],[-95.5804,47.8183],[-95.5801,47.8039],[-95.5796,47.7894],[-95.5796,47.775],[-95.5799,47.7605],[-95.5795,47.746],[-95.5793,47.7314],[-95.5789,47.7171],[-95.5789,47.7027],[-95.5787,47.6882],[-95.5785,47.6738],[-95.5785,47.6737],[-95.5755,47.6737],[-95.5595,47.6737],[-95.5535,47.6737],[-95.5537,47.6592],[-95.5536,47.6447],[-95.5535,47.6302],[-95.5538,47.6161],[-95.5536,47.6014],[-95.5537,47.5869],[-95.5538,47.5724],[-95.5538,47.5579],[-95.5539,47.5436],[-95.5539,47.5289],[-95.5539,47.5146],[-95.5513,47.5001],[-95.5516,47.5001],[-95.5729,47.5001],[-95.5942,47.4999],[-95.6158,47.4997],[-95.6366,47.4996],[-95.6393,47.4996],[-95.6411,47.4996],[-95.6584,47.4995],[-95.6605,47.4995],[-95.6782,47.4997],[-95.6818,47.4997],[-95.6908,47.4997],[-95.6996,47.4997],[-95.7033,47.4997],[-95.7211,47.4996],[-95.7247,47.4995],[-95.7424,47.4995],[-95.7459,47.4995],[-95.7537,47.4995],[-95.7634,47.4995],[-95.7675,47.4995],[-95.7851,47.4994],[-95.7888,47.4994],[-95.7965,47.4994],[-95.8053,47.4994],[-95.8103,47.4994],[-95.8266,47.4995],[-95.8272,47.4995],[-95.8316,47.4995],[-95.8371,47.4995],[-95.8482,47.4995],[-95.8529,47.4995],[-95.8696,47.4995],[-95.8746,47.4994],[-95.8908,47.4993],[-95.8954,47.4993],[-95.9123,47.4992],[-95.9169,47.4992],[-95.9332,47.4992],[-95.9383,47.4992],[-95.9549,47.4992],[-95.9603,47.4992],[-95.9761,47.4992],[-95.9818,47.4992],[-95.9977,47.4992],[-95.9991,47.4992],[-96.0032,47.4992],[-96.019,47.4993],[-96.0247,47.4993],[-96.0362,47.4992],[-96.0408,47.4992],[-96.0462,47.4992],[-96.0676,47.4992],[-96.0888,47.4993],[-96.1101,47.4993],[-96.1314,47.4996],[-96.1526,47.4997],[-96.1739,47.4999],[-96.1954,47.4999],[-96.2166,47.4999],[-96.238,47.4998],[-96.2594,47.4998],[-96.2808,47.4998],[-96.3022,47.4999],[-96.3232,47.4999],[-96.3448,47.4997],[-96.3659,47.4997],[-96.3873,47.4997],[-96.4088,47.4996],[-96.4301,47.4996],[-96.4517,47.4994],[-96.4731,47.4993],[-96.4944,47.4993],[-96.516,47.4991],[-96.5371,47.4991],[-96.5587,47.499],[-96.5801,47.499],[-96.6013,47.4989],[-96.6229,47.499],[-96.6442,47.4992],[-96.6653,47.499],[-96.6876,47.4987],[-96.7085,47.4989],[-96.73,47.4989],[-96.7515,47.4989],[-96.7732,47.4989],[-96.7945,47.499],[-96.8159,47.499],[-96.8361,47.4989],[-96.8487,47.4989],[-96.8488,47.499],[-96.8504,47.5],[-96.8506,47.5],[-96.8507,47.5],[-96.8514,47.5004],[-96.8524,47.5006],[-96.853,47.501],[-96.8533,47.5014],[-96.8534,47.5017],[-96.8535,47.5023],[-96.8535,47.5034],[-96.8532,47.5039],[-96.8532,47.5042],[-96.8531,47.5045],[-96.8528,47.5053],[-96.8528,47.5059],[-96.8529,47.506],[-96.853,47.5065],[-96.853,47.5069],[-96.8526,47.5073],[-96.8524,47.5075],[-96.8518,47.5076],[-96.8515,47.5076],[-96.8508,47.5074],[-96.8494,47.5068],[-96.8485,47.5066],[-96.8471,47.5066],[-96.846,47.5067],[-96.8443,47.5071],[-96.8436,47.5074],[-96.8424,47.5083],[-96.8422,47.5086],[-96.8421,47.5091],[-96.8424,47.5094],[-96.8431,47.51],[-96.8439,47.5103],[-96.8448,47.5105],[-96.8464,47.5105],[-96.849,47.5098],[-96.8504,47.5096],[-96.8512,47.5096],[-96.8519,47.5098],[-96.8526,47.5102],[-96.853,47.5106],[-96.8531,47.5107],[-96.8533,47.5112],[-96.8534,47.5112],[-96.8534,47.5113],[-96.8535,47.5113],[-96.8536,47.5119],[-96.8536,47.512],[-96.8532,47.5126],[-96.8531,47.5128],[-96.8525,47.5132],[-96.8517,47.5135],[-96.8514,47.5135],[-96.851,47.5136],[-96.8502,47.5135],[-96.8491,47.5134],[-96.8465,47.5124],[-96.846,47.5123],[-96.8448,47.5124],[-96.8442,47.5125],[-96.8435,47.5128],[-96.843,47.5132],[-96.8428,47.5134],[-96.8425,47.5137],[-96.8422,47.5141],[-96.842,47.5146],[-96.842,47.5155],[-96.842,47.5156],[-96.842,47.5157],[-96.8421,47.5158],[-96.8422,47.516],[-96.8427,47.5164],[-96.8433,47.5167],[-96.8442,47.517],[-96.8454,47.5172],[-96.8465,47.517],[-96.8475,47.5166],[-96.8481,47.5163],[-96.8501,47.5155],[-96.8519,47.515],[-96.8532,47.5146],[-96.8542,47.5144],[-96.8547,47.5144],[-96.8563,47.5146],[-96.8573,47.5147],[-96.8584,47.5149],[-96.8599,47.5153],[-96.8614,47.5159],[-96.8624,47.5164],[-96.8629,47.5169],[-96.8632,47.5173],[-96.8633,47.5177],[-96.8633,47.5198],[-96.8635,47.5204],[-96.8636,47.5206],[-96.8643,47.5213],[-96.8645,47.5216],[-96.8656,47.5225],[-96.8658,47.5229],[-96.866,47.523],[-96.8663,47.5238],[-96.8664,47.5249],[-96.8666,47.5254],[-96.8672,47.5259],[-96.8676,47.5261],[-96.8683,47.5262],[-96.8698,47.5264],[-96.8705,47.5266],[-96.8707,47.5268],[-96.8708,47.5269],[-96.8709,47.5272],[-96.8709,47.5273],[-96.8709,47.5279],[-96.8706,47.5283],[-96.8704,47.5284],[-96.87,47.5287],[-96.8691,47.529],[-96.868,47.5291],[-96.8665,47.5291],[-96.865,47.529],[-96.8623,47.5291],[-96.861,47.5294],[-96.8605,47.5296],[-96.8593,47.5304],[-96.8589,47.5308],[-96.8576,47.5328],[-96.8573,47.5333],[-96.8568,47.5337],[-96.8558,47.5346],[-96.8543,47.5354],[-96.854,47.5357],[-96.8535,47.5363],[-96.8534,47.5372],[-96.8536,47.5378],[-96.854,47.5382],[-96.8546,47.5383],[-96.8558,47.5382],[-96.8569,47.5379],[-96.8573,47.5377],[-96.8579,47.5375],[-96.8589,47.5371],[-96.8593,47.5371],[-96.8599,47.5371],[-96.8609,47.5374],[-96.8619,47.5379],[-96.8629,47.5387],[-96.8632,47.5391],[-96.8634,47.5395],[-96.8634,47.5402],[-96.8628,47.5409],[-96.8614,47.5414],[-96.858,47.542],[-96.8573,47.5421],[-96.8565,47.5422],[-96.8555,47.5421],[-96.8542,47.5418],[-96.8533,47.5413],[-96.8523,47.5407],[-96.8519,47.5401],[-96.8516,47.5397],[-96.8514,47.5393],[-96.8513,47.5393],[-96.8512,47.539],[-96.8511,47.5388],[-96.851,47.5386],[-96.8507,47.5383],[-96.8507,47.5382],[-96.8501,47.5377],[-96.8494,47.5374],[-96.8484,47.5372],[-96.8477,47.5371],[-96.8471,47.5372],[-96.8465,47.5374],[-96.8457,47.538],[-96.8452,47.5386],[-96.8452,47.5394],[-96.8452,47.5397],[-96.8454,47.5399],[-96.8455,47.5403],[-96.8456,47.5404],[-96.8456,47.5405],[-96.846,47.541],[-96.8467,47.5415],[-96.8484,47.5425],[-96.8501,47.5432],[-96.8525,47.5438],[-96.8571,47.5448],[-96.8572,47.5448],[-96.8586,47.5452],[-96.8597,47.5456],[-96.8602,47.5459],[-96.8603,47.5461],[-96.8603,47.5464],[-96.8602,47.5466],[-96.8599,47.5468],[-96.8596,47.547],[-96.8585,47.5472],[-96.8576,47.5477],[-96.8572,47.5479],[-96.8554,47.5485],[-96.8542,47.5488],[-96.8538,47.5491],[-96.8523,47.5504],[-96.8505,47.5517],[-96.8501,47.5521],[-96.8499,47.5526],[-96.8497,47.5532],[-96.85,47.5537],[-96.8501,47.5538],[-96.8501,47.5539],[-96.8506,47.5543],[-96.8513,47.5546],[-96.8526,47.5549],[-96.8546,47.5551],[-96.8558,47.5551],[-96.857,47.5553],[-96.8578,47.5556],[-96.8588,47.5562],[-96.8598,47.5571],[-96.8602,47.5576],[-96.8605,47.5578],[-96.8606,47.5581],[-96.8608,47.5582],[-96.8612,47.5588],[-96.8614,47.5592],[-96.8614,47.5599],[-96.8613,47.5602],[-96.8608,47.5604],[-96.8601,47.5607],[-96.8594,47.5607],[-96.8581,47.5605],[-96.8573,47.5602],[-96.8569,47.5601],[-96.8567,47.5601],[-96.8553,47.5602],[-96.8544,47.5603],[-96.8537,47.5606],[-96.8515,47.5621],[-96.8506,47.5626],[-96.8491,47.5636],[-96.8484,47.564],[-96.8476,47.5646],[-96.8474,47.565],[-96.8472,47.5656],[-96.8472,47.5661],[-96.8474,47.5663],[-96.8479,47.5666],[-96.8487,47.5667],[-96.8498,47.5665],[-96.8503,47.5664],[-96.8513,47.5658],[-96.852,47.5656],[-96.8541,47.5653],[-96.856,47.5649],[-96.8568,47.5646],[-96.8575,47.5643],[-96.8599,47.5632],[-96.8612,47.5628],[-96.8622,47.5626],[-96.8628,47.5626],[-96.864,47.5627],[-96.8652,47.5631],[-96.8661,47.5636],[-96.8666,47.564],[-96.8676,47.5651],[-96.8678,47.5654],[-96.868,47.5655],[-96.8685,47.5663],[-96.8685,47.5664],[-96.8686,47.5665],[-96.8687,47.5668],[-96.8688,47.5669],[-96.8687,47.5677],[-96.8684,47.5682],[-96.8675,47.5688],[-96.8661,47.5695],[-96.8656,47.5696],[-96.8647,47.5694],[-96.8639,47.569],[-96.8629,47.5687],[-96.8616,47.5684],[-96.861,47.5682],[-96.8607,47.568],[-96.8599,47.5676],[-96.8588,47.5672],[-96.8578,47.5671],[-96.8567,47.5671],[-96.8555,47.5671],[-96.8539,47.5675],[-96.8529,47.5678],[-96.8519,47.5684],[-96.8514,47.569],[-96.8515,47.5698],[-96.8517,47.5703],[-96.8521,47.5709],[-96.8529,47.5715],[-96.8531,47.5716],[-96.8537,47.5719],[-96.8549,47.5725],[-96.8566,47.5731],[-96.8571,47.5733],[-96.8595,47.574],[-96.8602,47.5744],[-96.8604,47.5746],[-96.8604,47.575],[-96.8599,47.5752],[-96.8589,47.5754],[-96.8585,47.5756],[-96.8573,47.5763],[-96.8565,47.5767],[-96.8553,47.5773],[-96.8543,47.578],[-96.8534,47.5792],[-96.8532,47.5795],[-96.853,47.5802],[-96.853,47.5805],[-96.8528,47.5809],[-96.8529,47.5822],[-96.853,47.5826],[-96.8532,47.5826],[-96.8532,47.5833],[-96.8531,47.5837],[-96.8526,47.5844],[-96.8527,47.5845],[-96.8525,47.5846],[-96.852,47.585],[-96.852,47.5851],[-96.8515,47.5859],[-96.8515,47.586],[-96.8513,47.5869],[-96.8512,47.5873],[-96.8511,47.5878],[-96.851,47.5881],[-96.8507,47.5888],[-96.8502,47.5898],[-96.85,47.5903],[-96.8499,47.591],[-96.8501,47.5916],[-96.8503,47.5919],[-96.8511,47.5925],[-96.8517,47.5927],[-96.8538,47.593],[-96.8549,47.5934],[-96.8562,47.5939],[-96.8575,47.5943],[-96.8582,47.5947],[-96.8586,47.5949],[-96.8588,47.5954],[-96.8588,47.5958],[-96.8584,47.5962],[-96.8575,47.5963],[-96.8562,47.5962],[-96.8542,47.596],[-96.853,47.5961],[-96.8521,47.5964],[-96.8515,47.5968],[-96.8511,47.5973],[-96.8509,47.5977],[-96.8509,47.5983],[-96.8511,47.5989],[-96.8515,47.5993],[-96.8521,47.5997],[-96.8528,47.6],[-96.8536,47.6003],[-96.8545,47.6004],[-96.8556,47.6009],[-96.8561,47.6014],[-96.8564,47.6016],[-96.8567,47.602],[-96.8569,47.6024],[-96.8568,47.6031],[-96.8565,47.6035],[-96.8562,47.6039],[-96.8553,47.6051],[-96.8549,47.6058],[-96.8548,47.6064],[-96.8548,47.6073],[-96.8549,47.6075],[-96.855,47.6079],[-96.855,47.608],[-96.8554,47.6088],[-96.8557,47.6093],[-96.8558,47.6094],[-96.8561,47.6098],[-96.8563,47.61],[-96.8571,47.6108],[-96.858,47.6115],[-96.8589,47.612],[-96.8602,47.6122],[-96.8612,47.6124],[-96.8646,47.6124],[-96.8655,47.6125],[-96.8664,47.6129],[-96.8672,47.6136],[-96.8673,47.6138],[-96.8675,47.6139],[-96.8676,47.6141],[-96.8679,47.6144],[-96.8686,47.6148],[-96.869,47.615],[-96.8694,47.615],[-96.8703,47.6147],[-96.871,47.6143],[-96.8714,47.6139],[-96.8719,47.6136],[-96.8723,47.6135],[-96.8729,47.6135],[-96.8736,47.6137],[-96.8739,47.614],[-96.874,47.6141],[-96.874,47.6148],[-96.8739,47.6149],[-96.8736,47.6154],[-96.8726,47.6159],[-96.8715,47.6165],[-96.871,47.6169],[-96.8706,47.6176],[-96.8708,47.6181],[-96.8712,47.6183],[-96.8717,47.6184],[-96.8727,47.6184],[-96.8753,47.6191],[-96.8763,47.6192],[-96.8778,47.6189],[-96.878,47.6189],[-96.879,47.6189],[-96.8796,47.6191],[-96.88,47.6195],[-96.88,47.62],[-96.8794,47.6206],[-96.8783,47.6213],[-96.8779,47.6215],[-96.8769,47.6219],[-96.8763,47.6223],[-96.876,47.6228],[-96.8758,47.623],[-96.876,47.6235],[-96.8761,47.6237],[-96.8768,47.6243],[-96.8775,47.6244],[-96.878,47.6245],[-96.8792,47.6246],[-96.88,47.6247],[-96.8803,47.625],[-96.8806,47.6254],[-96.8807,47.6255],[-96.8807,47.6259],[-96.8804,47.6262],[-96.8798,47.6266],[-96.8792,47.6267],[-96.8786,47.6267],[-96.878,47.6267],[-96.8767,47.6266],[-96.8753,47.6267],[-96.8748,47.6269],[-96.8745,47.6272],[-96.8745,47.6275],[-96.8745,47.628],[-96.8747,47.6283],[-96.8753,47.6287],[-96.8765,47.629],[-96.8774,47.6289],[-96.8781,47.6289],[-96.8787,47.6289],[-96.8795,47.6289],[-96.8801,47.6289],[-96.8806,47.6291],[-96.881,47.6294],[-96.8815,47.6299],[-96.8815,47.6299],[-96.8815,47.63],[-96.8816,47.6301],[-96.8818,47.6305],[-96.8818,47.631],[-96.8819,47.6311],[-96.882,47.6324],[-96.8822,47.6333],[-96.8823,47.6334],[-96.8823,47.6335],[-96.8827,47.6339],[-96.8852,47.6356],[-96.8876,47.6376],[-96.8878,47.6379],[-96.8885,47.6385],[-96.8885,47.6393],[-96.8884,47.6395],[-96.8881,47.6398],[-96.8874,47.6401],[-96.886,47.6405],[-96.8845,47.6408],[-96.8835,47.6412],[-96.8832,47.6414],[-96.8828,47.6418],[-96.8826,47.6422],[-96.8826,47.6429],[-96.8829,47.6439],[-96.8829,47.6441],[-96.8829,47.6447],[-96.8828,47.6451],[-96.8827,47.6462],[-96.8825,47.6471],[-96.8823,47.6491],[-96.8826,47.6498],[-96.8828,47.6502],[-96.8837,47.6509],[-96.8844,47.6513],[-96.8846,47.6513],[-96.8847,47.6515],[-96.8862,47.6523],[-96.8866,47.6526],[-96.8869,47.6531],[-96.887,47.6533],[-96.887,47.6543],[-96.8868,47.6548],[-96.8869,47.6556],[-96.887,47.656],[-96.8876,47.6577],[-96.8876,47.6585],[-96.8876,47.6589],[-96.8873,47.6596],[-96.8869,47.6601],[-96.8857,47.6616],[-96.8855,47.6624],[-96.8855,47.6635],[-96.8857,47.6643],[-96.8862,47.6652],[-96.8863,47.6653],[-96.8863,47.6654],[-96.8864,47.6656],[-96.8864,47.6656],[-96.8871,47.6664],[-96.8889,47.668],[-96.8896,47.6686],[-96.8897,47.669],[-96.8898,47.669],[-96.8899,47.6693],[-96.89,47.6694],[-96.8901,47.67],[-96.8899,47.6703],[-96.8897,47.6707],[-96.8883,47.6715],[-96.8871,47.6721],[-96.8868,47.6722],[-96.8863,47.6725],[-96.8859,47.6727],[-96.8856,47.6727],[-96.8855,47.6729],[-96.8853,47.6732],[-96.8851,47.6735],[-96.8852,47.6737],[-96.8852,47.6738],[-96.8853,47.6739],[-96.8857,47.6742],[-96.8863,47.6743],[-96.8867,47.6743],[-96.8874,47.6743],[-96.8886,47.674],[-96.8892,47.6738],[-96.8908,47.6734],[-96.8919,47.6732],[-96.8935,47.6732],[-96.8946,47.6734],[-96.8952,47.6736],[-96.8955,47.6738],[-96.8964,47.6745],[-96.8967,47.6748],[-96.8968,47.6751],[-96.8967,47.6759],[-96.8964,47.6768],[-96.8963,47.6772],[-96.8962,47.6775],[-96.8961,47.6776],[-96.8961,47.6785],[-96.8963,47.6792],[-96.8964,47.6793],[-96.8964,47.6794],[-96.8965,47.6796],[-96.8968,47.6802],[-96.8971,47.6804],[-96.8971,47.6806],[-96.8972,47.6806],[-96.8973,47.681],[-96.8974,47.6811],[-96.8974,47.6812],[-96.8975,47.6813],[-96.8977,47.6817],[-96.8978,47.6818],[-96.8978,47.682],[-96.8984,47.6834],[-96.8986,47.6837],[-96.8986,47.684],[-96.8987,47.6841],[-96.8989,47.6846],[-96.899,47.6847],[-96.899,47.685],[-96.8993,47.686],[-96.8992,47.6871],[-96.8992,47.688],[-96.8992,47.6883],[-96.8992,47.6887],[-96.8993,47.6895],[-96.8995,47.69],[-96.8996,47.6901],[-96.8997,47.6903],[-96.9002,47.6908],[-96.9011,47.6914],[-96.9017,47.6917],[-96.9022,47.6918],[-96.9029,47.6916],[-96.9035,47.6913],[-96.9039,47.6909],[-96.9047,47.6898],[-96.9052,47.6893],[-96.906,47.6889],[-96.9072,47.6885],[-96.9081,47.6885],[-96.9089,47.6888],[-96.9095,47.6892],[-96.9098,47.6896],[-96.9101,47.69],[-96.9101,47.6913],[-96.9099,47.6916],[-96.9098,47.692],[-96.9091,47.6926],[-96.9077,47.6934],[-96.9074,47.6937],[-96.9072,47.694],[-96.9072,47.6947],[-96.9076,47.6952],[-96.9077,47.6954],[-96.9083,47.6961],[-96.9092,47.6968],[-96.9097,47.6974],[-96.9101,47.698],[-96.9102,47.6982],[-96.9103,47.6985],[-96.9103,47.6986],[-96.9104,47.6986],[-96.9106,47.6989],[-96.9107,47.6991],[-96.9107,47.6993],[-96.9115,47.7006],[-96.912,47.7012],[-96.9125,47.7017],[-96.9128,47.7018],[-96.9132,47.7019],[-96.914,47.7018],[-96.9145,47.7016],[-96.9155,47.7009],[-96.9169,47.6998],[-96.9177,47.6994],[-96.9184,47.6991],[-96.9193,47.6991],[-96.9202,47.6993],[-96.9207,47.6996],[-96.9208,47.6998],[-96.9208,47.6999],[-96.921,47.7],[-96.9211,47.7003],[-96.9211,47.7008],[-96.9208,47.7013],[-96.9204,47.7017],[-96.9194,47.7026],[-96.919,47.7028],[-96.9187,47.703],[-96.9176,47.7034],[-96.9172,47.7035],[-96.9164,47.7034],[-96.9155,47.7035],[-96.9145,47.7038],[-96.9137,47.7042],[-96.9132,47.7047],[-96.9128,47.7052],[-96.9123,47.7058],[-96.9119,47.7066],[-96.912,47.7075],[-96.9122,47.7079],[-96.9129,47.7083],[-96.9134,47.7084],[-96.9146,47.7085],[-96.9163,47.7086],[-96.9175,47.7089],[-96.919,47.7095],[-96.9198,47.71],[-96.9201,47.7104],[-96.9201,47.7105],[-96.9202,47.7107],[-96.9204,47.7111],[-96.9204,47.712],[-96.9203,47.7124],[-96.9197,47.7137],[-96.9195,47.7139],[-96.9194,47.7142],[-96.9192,47.7146],[-96.9191,47.7149],[-96.9191,47.7156],[-96.9197,47.7166],[-96.9201,47.7171],[-96.9206,47.7174],[-96.9209,47.7176],[-96.9216,47.7178],[-96.9224,47.718],[-96.9232,47.7179],[-96.9238,47.7176],[-96.9241,47.7174],[-96.9245,47.7171],[-96.9247,47.7167],[-96.9248,47.7166],[-96.9248,47.7164],[-96.9251,47.7162],[-96.9252,47.716],[-96.926,47.7153],[-96.9266,47.7149],[-96.9277,47.7144],[-96.9284,47.7143],[-96.929,47.7143],[-96.93,47.7145],[-96.9305,47.7148],[-96.931,47.7153],[-96.931,47.7154],[-96.9311,47.7154],[-96.9312,47.716],[-96.9312,47.7166],[-96.9308,47.7174],[-96.9308,47.7175],[-96.9305,47.7179],[-96.93,47.7183],[-96.9287,47.7187],[-96.9271,47.719],[-96.9251,47.7197],[-96.9237,47.7202],[-96.9217,47.7211],[-96.9205,47.7218],[-96.9194,47.7226],[-96.9193,47.7227],[-96.9189,47.7231],[-96.9187,47.7234],[-96.9185,47.7239],[-96.9187,47.7243],[-96.9188,47.7244],[-96.9188,47.7245],[-96.9191,47.7248],[-96.9197,47.7251],[-96.9203,47.7253],[-96.9224,47.7256],[-96.9236,47.7259],[-96.9242,47.7262],[-96.9246,47.7267],[-96.9248,47.7272],[-96.925,47.7275],[-96.925,47.7291],[-96.9253,47.7299],[-96.9255,47.7302],[-96.9257,47.7304],[-96.9273,47.7316],[-96.9279,47.7321],[-96.9283,47.7325],[-96.9305,47.7344],[-96.9314,47.7353],[-96.9319,47.7359],[-96.9323,47.7365],[-96.9324,47.7366],[-96.9325,47.7368],[-96.9327,47.7371],[-96.9328,47.7372],[-96.9332,47.7383],[-96.9333,47.7388],[-96.9332,47.7395],[-96.933,47.74],[-96.9327,47.7403],[-96.9319,47.741],[-96.9318,47.7411],[-96.9308,47.7417],[-96.9302,47.7422],[-96.9293,47.743],[-96.929,47.7435],[-96.9287,47.7442],[-96.9285,47.7449],[-96.9284,47.7454],[-96.9284,47.7465],[-96.9285,47.7481],[-96.9286,47.7491],[-96.9288,47.7493],[-96.9289,47.7497],[-96.929,47.7497],[-96.9289,47.75],[-96.929,47.7504],[-96.9298,47.751],[-96.9308,47.7515],[-96.9322,47.7521],[-96.9332,47.7526],[-96.9351,47.7532],[-96.9387,47.754],[-96.9394,47.7544],[-96.9398,47.7549],[-96.9397,47.7555],[-96.9394,47.7559],[-96.9388,47.7562],[-96.9381,47.7563],[-96.9373,47.7563],[-96.9363,47.7562],[-96.9337,47.7551],[-96.9327,47.7548],[-96.9323,47.7548],[-96.9311,47.7547],[-96.9297,47.7549],[-96.9291,47.755],[-96.9289,47.7553],[-96.9288,47.7558],[-96.9291,47.7561],[-96.9298,47.7565],[-96.9309,47.7569],[-96.9324,47.7573],[-96.9335,47.7576],[-96.9355,47.7583],[-96.9368,47.759],[-96.9369,47.7592],[-96.9371,47.7594],[-96.9372,47.7595],[-96.9378,47.7602],[-96.9379,47.7604],[-96.9381,47.7607],[-96.9381,47.7609],[-96.9382,47.7609],[-96.9382,47.761],[-96.9384,47.7614],[-96.9384,47.7625],[-96.938,47.7632],[-96.9376,47.7639],[-96.9369,47.7646],[-96.9366,47.7649],[-96.9352,47.7658],[-96.9351,47.766],[-96.9349,47.7664],[-96.9348,47.7668],[-96.9349,47.7671],[-96.9357,47.7676],[-96.9365,47.7678],[-96.9382,47.7681],[-96.9391,47.7684],[-96.9404,47.7692],[-96.9423,47.7708],[-96.943,47.7712],[-96.9442,47.7717],[-96.9445,47.7717],[-96.9445,47.7719],[-96.9452,47.7722],[-96.9457,47.7727],[-96.9458,47.7729],[-96.9459,47.7734],[-96.9459,47.7743],[-96.946,47.7746],[-96.9466,47.775],[-96.9473,47.7753],[-96.9483,47.7755],[-96.9494,47.7753],[-96.9495,47.7753],[-96.9518,47.7747],[-96.9527,47.7746],[-96.9537,47.7746],[-96.9539,47.7747],[-96.955,47.7748],[-96.956,47.7751],[-96.9565,47.7753],[-96.9567,47.7757],[-96.9567,47.7761],[-96.9566,47.7762],[-96.9544,47.7777],[-96.9538,47.778],[-96.9527,47.7787],[-96.9523,47.779],[-96.9522,47.7793],[-96.9524,47.7796],[-96.9527,47.7799],[-96.9533,47.78],[-96.9538,47.78],[-96.9554,47.7798],[-96.9565,47.7798],[-96.9573,47.78],[-96.9584,47.7803],[-96.9589,47.7807],[-96.9593,47.7812],[-96.9593,47.7819],[-96.9592,47.7819],[-96.9578,47.7838],[-96.9576,47.7844],[-96.9575,47.7847],[-96.9575,47.7852],[-96.9578,47.7855],[-96.9581,47.7856],[-96.9584,47.7857],[-96.959,47.7855],[-96.9596,47.7849],[-96.9597,47.7847],[-96.9598,47.7847],[-96.9598,47.7846],[-96.9601,47.7843],[-96.961,47.7838],[-96.9619,47.7833],[-96.9631,47.783],[-96.9638,47.783],[-96.9644,47.783],[-96.9649,47.7833],[-96.9653,47.7835],[-96.9654,47.7839],[-96.9653,47.785],[-96.9651,47.7853],[-96.965,47.7855],[-96.9645,47.7862],[-96.9635,47.7873],[-96.9628,47.7879],[-96.9621,47.7884],[-96.9615,47.7888],[-96.9599,47.7893],[-96.9586,47.7896],[-96.958,47.7898],[-96.9576,47.79],[-96.9572,47.7902],[-96.9571,47.7904],[-96.9572,47.791],[-96.9573,47.7913],[-96.9574,47.7915],[-96.9578,47.7921],[-96.9584,47.7925],[-96.9597,47.7931],[-96.9627,47.7942],[-96.9635,47.7947],[-96.9642,47.7951],[-96.965,47.7959],[-96.9657,47.7968],[-96.966,47.7973],[-96.9661,47.7992],[-96.9662,47.7993],[-96.9663,47.7994],[-96.9669,47.7998],[-96.9674,47.7999],[-96.9681,47.7998],[-96.9687,47.7996],[-96.9689,47.7995],[-96.9702,47.7987],[-96.9716,47.7983],[-96.974,47.7978],[-96.9751,47.7978],[-96.9754,47.7978],[-96.9762,47.7979],[-96.9766,47.7981],[-96.9768,47.7983],[-96.977,47.7986],[-96.977,47.8],[-96.9764,47.8013],[-96.9761,47.8016],[-96.9759,47.8017],[-96.9754,47.8019],[-96.9751,47.8019],[-96.973,47.8019],[-96.9723,47.802],[-96.9721,47.8022],[-96.9719,47.8025],[-96.9721,47.8029],[-96.973,47.8034],[-96.974,47.8036],[-96.9749,47.8037],[-96.9751,47.8037],[-96.9769,47.8037],[-96.9789,47.804],[-96.9796,47.8042],[-96.981,47.8045],[-96.9818,47.8046],[-96.9826,47.805],[-96.9828,47.8051],[-96.9831,47.8051],[-96.9832,47.8053],[-96.9851,47.8065],[-96.9859,47.8069],[-96.9863,47.8071],[-96.9877,47.8072],[-96.9894,47.8072],[-96.9905,47.8076],[-96.991,47.8078],[-96.9914,47.8081],[-96.9916,47.8085],[-96.9916,47.8091],[-96.9912,47.8094],[-96.9903,47.8097],[-96.9891,47.8099],[-96.9882,47.8099],[-96.9864,47.8098],[-96.9818,47.8091],[-96.9805,47.8092],[-96.9796,47.8095],[-96.9788,47.8099],[-96.9782,47.8106],[-96.978,47.8112],[-96.9779,47.8117],[-96.9781,47.8122],[-96.9784,47.8128],[-96.9786,47.8129],[-96.9787,47.8131],[-96.9795,47.8138],[-96.9795,47.8139],[-96.9798,47.8143],[-96.9799,47.8145],[-96.9799,47.8146],[-96.9803,47.8157],[-96.9804,47.8187],[-96.9804,47.822],[-96.9802,47.8224],[-96.9797,47.8226],[-96.979,47.8226],[-96.9772,47.8222],[-96.9764,47.8221],[-96.9759,47.8221],[-96.9754,47.8222],[-96.9747,47.8224],[-96.9745,47.8224],[-96.9744,47.8225],[-96.9741,47.8228],[-96.9741,47.8234],[-96.9743,47.8239],[-96.9749,47.8244],[-96.9757,47.825],[-96.9759,47.825],[-96.9769,47.8254],[-96.9783,47.8256],[-96.9793,47.8257],[-96.982,47.8255],[-96.9845,47.8251],[-96.9857,47.8251],[-96.9865,47.8252],[-96.9869,47.8254],[-96.9872,47.8256],[-96.9871,47.8261],[-96.9867,47.8265],[-96.9858,47.8269],[-96.984,47.8275],[-96.9827,47.8281],[-96.9825,47.8283],[-96.9819,47.8287],[-96.9817,47.829],[-96.9815,47.8295],[-96.9816,47.8301],[-96.9817,47.8305],[-96.982,47.8309],[-96.9843,47.8325],[-96.9848,47.8331],[-96.9849,47.8332],[-96.9849,47.8333],[-96.985,47.8334],[-96.9852,47.8339],[-96.9853,47.8344],[-96.9854,47.8345],[-96.9857,47.8359],[-96.9859,47.8361],[-96.9859,47.8366],[-96.9863,47.8373],[-96.9866,47.8377],[-96.9873,47.8379],[-96.9881,47.838],[-96.9896,47.8381],[-96.9907,47.838],[-96.9915,47.8378],[-96.9924,47.8378],[-96.9929,47.838],[-96.9937,47.8383],[-96.9941,47.8388],[-96.9941,47.8396],[-96.994,47.8397],[-96.9935,47.8404],[-96.9929,47.8412],[-96.9925,47.8417],[-96.9924,47.8421],[-96.9924,47.8426],[-96.9927,47.8427],[-96.9931,47.8428],[-96.9938,47.8426],[-96.9956,47.842],[-96.9969,47.8416],[-96.9976,47.8416],[-96.9976,47.8435],[-96.9974,47.8437],[-96.9963,47.8444],[-96.9958,47.8447],[-96.9947,47.845],[-96.9943,47.8452],[-96.9941,47.8455],[-96.994,47.8458],[-96.9941,47.8461],[-96.9941,47.8462],[-96.9942,47.8463],[-96.9943,47.8464],[-96.9949,47.847],[-96.9956,47.8474],[-96.9967,47.848],[-96.9968,47.848],[-96.9968,47.8482],[-96.9969,47.8482],[-96.9971,47.8484],[-96.9973,47.8488],[-96.9975,47.8496],[-96.9973,47.8504],[-96.9969,47.8515],[-96.9967,47.8526],[-96.9968,47.8545],[-96.9969,47.8555],[-96.9971,47.8561],[-96.9971,47.8564],[-96.9972,47.8566],[-96.9973,47.8567],[-96.9974,47.8574],[-96.9976,47.8577],[-96.9978,47.8583],[-96.9978,47.8583],[-96.9981,47.8589],[-96.9982,47.859],[-96.9983,47.8592],[-96.9989,47.8599],[-96.9994,47.8603],[-96.9998,47.8607],[-97.0003,47.861],[-97.0017,47.8613],[-97.0031,47.8623],[-97.0055,47.864],[-97.0058,47.8653],[-97.0033,47.8659],[-97.0015,47.8674],[-97.0024,47.8687],[-97.0053,47.8702],[-97.0084,47.8708],[-97.0173,47.8716],[-97.0194,47.8722],[-97.0212,47.8726],[-97.0218,47.8731],[-97.0231,47.874],[-97.0231,47.875],[-97.0221,47.8755],[-97.0196,47.8766],[-97.0193,47.8768],[-97.0189,47.8769],[-97.0179,47.8785],[-97.0193,47.8803],[-97.022,47.8815],[-97.0233,47.8821],[-97.0253,47.8843],[-97.0253,47.8856],[-97.0249,47.8869],[-97.0222,47.8884],[-97.0194,47.8897],[-97.0191,47.8898],[-97.0189,47.8911],[-97.019,47.8912],[-97.0195,47.8915],[-97.0225,47.8933],[-97.0249,47.895],[-97.0239,47.8981],[-97.0201,47.9005],[-97.0202,47.9022],[-97.0241,47.9053],[-97.0242,47.9056],[-97.0249,47.9082],[-97.0245,47.9083],[-97.0235,47.9085],[-97.0203,47.9064],[-97.0198,47.9063],[-97.0184,47.906],[-97.0172,47.9057],[-97.015,47.9072],[-97.015,47.9073],[-97.0153,47.9103],[-97.0156,47.9108],[-97.0172,47.9131],[-97.0195,47.9141],[-97.0197,47.9142],[-97.0214,47.9147],[-97.0237,47.9159],[-97.0196,47.9175],[-97.018,47.9181],[-97.0177,47.9198],[-97.0183,47.9202],[-97.0196,47.9211],[-97.0213,47.9221],[-97.0219,47.9224],[-97.0235,47.9236],[-97.0247,47.9244],[-97.026,47.9253],[-97.0284,47.9269],[-97.0296,47.9276],[-97.0323,47.9285],[-97.0357,47.9302],[-97.0373,47.9333],[-97.0368,47.9343],[-97.0355,47.9366],[-97.036,47.9394],[-97.0374,47.9399],[-97.0391,47.9405],[-97.0394,47.9405],[-97.0416,47.9406],[-97.0417,47.9406],[-97.0449,47.9411],[-97.051,47.9434],[-97.0545,47.9463],[-97.0555,47.9491],[-97.0555,47.9491],[-97.0553,47.9502],[-97.0551,47.9508],[-97.0525,47.9548],[-97.0524,47.9572],[-97.054,47.9597],[-97.059,47.9621],[-97.0613,47.9636],[-97.0614,47.9636],[-97.0618,47.9645],[-97.0615,47.9659],[-97.06,47.9672],[-97.0578,47.969],[-97.0571,47.9705],[-97.0593,47.974],[-97.0591,47.9754],[-97.0589,47.976],[-97.0588,47.9762],[-97.0587,47.9766],[-97.0584,47.977],[-97.0582,47.9774],[-97.0579,47.9778],[-97.0577,47.9781],[-97.0577,47.9782],[-97.0574,47.9787],[-97.0571,47.9792],[-97.0567,47.9801],[-97.0564,47.9806],[-97.0563,47.9811],[-97.0561,47.9815],[-97.0559,47.9821],[-97.0556,47.9828],[-97.0554,47.9833],[-97.0553,47.9838],[-97.0552,47.9842],[-97.0549,47.9849],[-97.0546,47.9855],[-97.0544,47.986],[-97.0541,47.9866],[-97.0539,47.9871],[-97.0537,47.9877],[-97.0535,47.988],[-97.0534,47.9884],[-97.0533,47.9887],[-97.0532,47.989],[-97.053,47.9894],[-97.053,47.9898],[-97.053,47.9903],[-97.053,47.9905],[-97.0531,47.9907],[-97.0532,47.9909],[-97.0533,47.9912],[-97.0534,47.9915],[-97.0535,47.9917],[-97.0538,47.992],[-97.0541,47.9923],[-97.0543,47.9925],[-97.0545,47.9926],[-97.0549,47.993],[-97.0555,47.9933],[-97.0561,47.9936],[-97.0566,47.9938],[-97.0571,47.9939],[-97.0578,47.9941],[-97.0584,47.9943],[-97.0591,47.9945],[-97.0597,47.9948],[-97.0601,47.9949],[-97.0604,47.9951],[-97.0608,47.9953],[-97.0614,47.9956],[-97.0617,47.9957],[-97.0619,47.9959],[-97.0622,47.996],[-97.0625,47.9962],[-97.0628,47.9965],[-97.063,47.9967],[-97.0633,47.997],[-97.0637,47.9975],[-97.0639,47.9977],[-97.0641,47.9982],[-97.0642,47.9986],[-97.0644,47.9989],[-97.0644,47.9994],[-97.0645,48.0],[-97.0645,48.0004],[-97.0644,48.002],[-97.0644,48.0027],[-97.0645,48.0034],[-97.0648,48.0045],[-97.0656,48.0064],[-97.0659,48.0071],[-97.0662,48.0079],[-97.0667,48.0089],[-97.0667,48.0096],[-97.0666,48.0102],[-97.0654,48.0114],[-97.0638,48.0125],[-97.0636,48.0126],[-97.063,48.0132],[-97.0628,48.0138],[-97.0629,48.0145],[-97.0632,48.015],[-97.0638,48.0153],[-97.0649,48.0157],[-97.0685,48.016],[-97.0692,48.0162],[-97.0706,48.017],[-97.0717,48.0181],[-97.0722,48.0192],[-97.0723,48.0196],[-97.0723,48.0201],[-97.0721,48.0207],[-97.0721,48.0209],[-97.0719,48.0214],[-97.0713,48.0228],[-97.0699,48.0247],[-97.0689,48.0263],[-97.0687,48.0277],[-97.0688,48.029],[-97.0691,48.0313],[-97.0697,48.0334],[-97.07,48.0354],[-97.0701,48.0361],[-97.0699,48.0374],[-97.0704,48.0418],[-97.0712,48.0458],[-97.0719,48.0474],[-97.0722,48.0481],[-97.0732,48.0499],[-97.0732,48.05],[-97.074,48.0513],[-97.0747,48.0521],[-97.0756,48.0528],[-97.0767,48.0533],[-97.0782,48.054],[-97.0795,48.0545],[-97.0815,48.0553],[-97.0828,48.0558],[-97.084,48.0564],[-97.0845,48.0567],[-97.0859,48.0575],[-97.0869,48.0583],[-97.0881,48.0596],[-97.0892,48.0611],[-97.0905,48.0627],[-97.0905,48.0628],[-97.0908,48.0631],[-97.0919,48.0644],[-97.092,48.0644],[-97.0932,48.0653],[-97.0951,48.0669],[-97.0958,48.0677],[-97.0963,48.0688],[-97.0969,48.07],[-97.0972,48.0706],[-97.0977,48.0711],[-97.0982,48.0714],[-97.0988,48.0715],[-97.0997,48.0716],[-97.1012,48.0715],[-97.103,48.0717],[-97.1038,48.0719],[-97.1044,48.0725],[-97.1046,48.0731],[-97.1045,48.074],[-97.1041,48.0746],[-97.1007,48.0775],[-97.1005,48.078],[-97.1001,48.0788],[-97.0998,48.0799],[-97.0994,48.0822],[-97.0994,48.0838],[-97.0996,48.0849],[-97.0997,48.0859],[-97.1001,48.0869],[-97.1012,48.0884],[-97.1021,48.0892],[-97.1034,48.0898],[-97.1047,48.0902],[-97.1066,48.0904],[-97.108,48.0906],[-97.1094,48.091],[-97.1098,48.0914],[-97.1097,48.0917],[-97.1095,48.0922],[-97.1087,48.0928],[-97.1067,48.0934],[-97.1066,48.0934],[-97.104,48.0939],[-97.1031,48.0941],[-97.1025,48.0946],[-97.102,48.0953],[-97.1018,48.0959],[-97.1022,48.0967],[-97.1029,48.0973],[-97.1041,48.098],[-97.106,48.0987],[-97.1066,48.0989],[-97.1074,48.0992],[-97.108,48.0996],[-97.1084,48.0999],[-97.1086,48.1003],[-97.1088,48.1008],[-97.1089,48.1017],[-97.1088,48.1028],[-97.109,48.1038],[-97.1095,48.1048],[-97.1107,48.1056],[-97.1114,48.106],[-97.1124,48.1062],[-97.1131,48.1062],[-97.115,48.106],[-97.1169,48.1057],[-97.1181,48.1056],[-97.1197,48.1054],[-97.1208,48.1056],[-97.1218,48.1059],[-97.1225,48.1063],[-97.1232,48.1067],[-97.1234,48.1073],[-97.1235,48.1076],[-97.1236,48.1078],[-97.1236,48.1081],[-97.1231,48.1095],[-97.122,48.1109],[-97.121,48.1123],[-97.1205,48.1134],[-97.1207,48.115],[-97.121,48.1159],[-97.1215,48.117],[-97.1253,48.1223],[-97.1256,48.1224],[-97.1257,48.1226],[-97.1261,48.1233],[-97.1268,48.1243],[-97.127,48.1246],[-97.1271,48.125],[-97.1275,48.1258],[-97.1282,48.1272],[-97.1286,48.1284],[-97.1288,48.1291],[-97.129,48.1309],[-97.1294,48.1332],[-97.13,48.134],[-97.1314,48.135],[-97.1323,48.1358],[-97.1328,48.1362],[-97.1332,48.1366],[-97.1334,48.1372],[-97.133,48.1375],[-97.1325,48.1377],[-97.1319,48.1376],[-97.1303,48.1372],[-97.1293,48.1369],[-97.1289,48.1367],[-97.128,48.1364],[-97.1276,48.1362],[-97.1267,48.1361],[-97.1253,48.1361],[-97.1241,48.1364],[-97.124,48.1365],[-97.123,48.137],[-97.1227,48.1375],[-97.1224,48.1381],[-97.1223,48.1386],[-97.1223,48.1391],[-97.1228,48.1398],[-97.1234,48.1402],[-97.1239,48.1406],[-97.1248,48.1409],[-97.1253,48.1411],[-97.1266,48.1416],[-97.1277,48.1418],[-97.1294,48.1421],[-97.1297,48.1421],[-97.1319,48.1424],[-97.1347,48.143],[-97.1367,48.1433],[-97.1379,48.1433],[-97.1393,48.1429],[-97.1407,48.1423],[-97.1415,48.1417],[-97.1426,48.1413],[-97.1435,48.141],[-97.1444,48.1411],[-97.1454,48.1413],[-97.1461,48.1417],[-97.1465,48.1423],[-97.1466,48.1433],[-97.1465,48.1441],[-97.1458,48.1452],[-97.1447,48.1466],[-97.1435,48.1475],[-97.1425,48.1487],[-97.1413,48.1501],[-97.1405,48.1508],[-97.1402,48.1509],[-97.1391,48.1516],[-97.1371,48.1523],[-97.1328,48.1535],[-97.1307,48.1542],[-97.1305,48.1543],[-97.1281,48.1552],[-97.1263,48.156],[-97.1253,48.1563],[-97.1244,48.1566],[-97.1236,48.1571],[-97.1225,48.1577],[-97.1217,48.1583],[-97.1211,48.1588],[-97.121,48.1591],[-97.1209,48.1596],[-97.121,48.1608],[-97.1211,48.1612],[-97.1214,48.1615],[-97.1218,48.1617],[-97.1224,48.1621],[-97.1233,48.1625],[-97.1241,48.1627],[-97.1247,48.1628],[-97.1253,48.1629],[-97.1273,48.1628],[-97.1285,48.1626],[-97.1305,48.162],[-97.1313,48.1617],[-97.1322,48.1614],[-97.1345,48.1603],[-97.1363,48.1598],[-97.1385,48.1595],[-97.1403,48.1598],[-97.1419,48.1603],[-97.1431,48.1611],[-97.1442,48.1625],[-97.1443,48.1633],[-97.1445,48.1641],[-97.1447,48.165],[-97.1451,48.1668],[-97.1454,48.1675],[-97.1463,48.1686],[-97.1475,48.1706],[-97.1475,48.1725],[-97.1467,48.1733]]],"type":"Polygon"},"id":"60","properties":{"Area":5177876131.64875,"CTYONLY_":9,"Code":"POLK","LASTMOD":"1999-12-31T23:59:59Z","Name":"Polk","Perimiter":458889.41551},"type":"Feature"},{"geometry":{"coordinates":[[[-96.5008,48.1742],[-96.5008,48.1742],[-96.5006,48.1741],[-96.5003,48.1741],[-96.4973,48.174],[-96.4946,48.1741],[-96.4841,48.174],[-96.4791,48.1741],[-96.4789,48.1741],[-96.4773,48.1741],[-96.4735,48.174],[-96.467,48.1741],[-96.4592,48.1742],[-96.4569,48.1742],[-96.4564,48.1742],[-96.4563,48.1743],[-96.4561,48.1744],[-96.4454,48.1747],[-96.4436,48.1747],[-96.4402,48.1748],[-96.438,48.1749],[-96.4359,48.1749],[-96.4352,48.1749],[-96.4346,48.1749],[-96.4295,48.1749],[-96.4206,48.1749],[-96.4135,48.1749],[-96.4126,48.1749],[-96.4126,48.1749],[-96.4054,48.1748],[-96.3964,48.1748],[-96.3906,48.1748],[-96.3905,48.1748],[-96.3894,48.1748],[-96.3856,48.1747],[-96.38,48.1745],[-96.3781,48.1746],[-96.3753,48.1748],[-96.3728,48.1749],[-96.3706,48.175],[-96.3685,48.1751],[-96.3682,48.1751],[-96.3682,48.1751],[-96.3656,48.175],[-96.3642,48.1749],[-96.361,48.1748],[-96.3581,48.1747],[-96.3542,48.1746],[-96.351,48.1745],[-96.3477,48.1744],[-96.3473,48.1744],[-96.347,48.1743],[-96.3466,48.1743],[-96.343,48.1744],[-96.3402,48.1744],[-96.338,48.1745],[-96.3358,48.1744],[-96.3356,48.1745],[-96.3301,48.1745],[-96.3253,48.1746],[-96.3252,48.1746],[-96.3145,48.1747],[-96.3035,48.1747],[-96.3029,48.1747],[-96.2977,48.1747],[-96.2824,48.1747],[-96.2823,48.1747],[-96.2805,48.1747],[-96.2619,48.1749],[-96.2612,48.1749],[-96.2607,48.1749],[-96.2596,48.1749],[-96.2562,48.1744],[-96.252,48.174],[-96.2511,48.174],[-96.2503,48.1739],[-96.2491,48.1737],[-96.2476,48.1735],[-96.2398,48.1728],[-96.2397,48.1727],[-96.2397,48.1727],[-96.2391,48.1727],[-96.2329,48.1725],[-96.2307,48.1725],[-96.2287,48.1725],[-96.2275,48.1724],[-96.2251,48.1724],[-96.2188,48.1722],[-96.2179,48.1722],[-96.2177,48.1722],[-96.2076,48.1722],[-96.2072,48.1722],[-96.2038,48.1722],[-96.2023,48.1722],[-96.1963,48.1721],[-96.1959,48.1721],[-96.1954,48.1721],[-96.1948,48.1721],[-96.191,48.1721],[-96.1874,48.1721],[-96.1834,48.172],[-96.1827,48.1722],[-96.1813,48.1725],[-96.1741,48.1736],[-96.1737,48.1736],[-96.1736,48.1736],[-96.1641,48.1736],[-96.1625,48.1736],[-96.1518,48.1736],[-96.1516,48.1736],[-96.1388,48.1732],[-96.1302,48.173],[-96.1298,48.173],[-96.1297,48.173],[-96.1253,48.1727],[-96.1189,48.1722],[-96.1176,48.1722],[-96.1084,48.1718],[-96.1084,48.1718],[-96.0979,48.172],[-96.09,48.172],[-96.09,48.172],[-96.079,48.1721],[-96.0685,48.1721],[-96.0685,48.1721],[-96.0592,48.1721],[-96.0468,48.1722],[-96.0468,48.1722],[-96.0254,48.1721],[-96.025,48.1721],[-96.0171,48.172],[-96.0101,48.1718],[-96.0047,48.1717],[-96.0036,48.1718],[-96.0035,48.1718],[-96.0032,48.1718],[-96.0028,48.1718],[-96.0023,48.1718],[-96.0003,48.1717],[-95.9956,48.1717],[-95.9819,48.1717],[-95.9817,48.1717],[-95.9651,48.1718],[-95.961,48.1718],[-95.9609,48.1718],[-95.9608,48.1718],[-95.9394,48.1719],[-95.9392,48.1719],[-95.9178,48.1719],[-95.9178,48.1719],[-95.9176,48.1719],[-95.896,48.172],[-95.8958,48.172],[-95.8752,48.172],[-95.8744,48.172],[-95.8744,48.172],[-95.8527,48.1721],[-95.8525,48.1721],[-95.8499,48.1721],[-95.8308,48.1722],[-95.8308,48.1722],[-95.8305,48.1722],[-95.8091,48.1722],[-95.809,48.1722],[-95.8088,48.1722],[-95.7874,48.1725],[-95.7657,48.1728],[-95.7657,48.1728],[-95.7502,48.1727],[-95.7443,48.1727],[-95.744,48.1727],[-95.7227,48.1731],[-95.7226,48.1731],[-95.7157,48.1731],[-95.7128,48.173],[-95.7022,48.1729],[-95.7021,48.1729],[-95.702,48.1729],[-95.6803,48.1728],[-95.6802,48.1728],[-95.662,48.1729],[-95.6591,48.1729],[-95.6376,48.173],[-95.6376,48.173],[-95.6279,48.1731],[-95.6252,48.1731],[-95.6163,48.1731],[-95.6159,48.1731],[-95.5941,48.173],[-95.5939,48.173],[-95.5939,48.1658],[-95.5938,48.1512],[-95.5936,48.1368],[-95.5931,48.1223],[-95.593,48.1078],[-95.5928,48.0931],[-95.5926,48.0787],[-95.5925,48.0642],[-95.5925,48.0497],[-95.5923,48.035],[-95.5922,48.0207],[-95.5828,48.0207],[-95.5825,48.0063],[-95.5824,47.9917],[-95.5825,47.9771],[-95.5826,47.9629],[-95.5825,47.9482],[-95.5824,47.9339],[-95.6034,47.9341],[-95.6252,47.9344],[-95.6466,47.9348],[-95.6683,47.9351],[-95.6898,47.9354],[-95.7096,47.9355],[-95.7097,47.9499],[-95.7098,47.9644],[-95.7312,47.9644],[-95.7531,47.9645],[-95.7747,47.9646],[-95.7963,47.9647],[-95.8181,47.9647],[-95.8383,47.9648],[-95.86,47.9649],[-95.8814,47.9648],[-95.9031,47.9648],[-95.925,47.9647],[-95.9462,47.9646],[-95.9671,47.9646],[-95.9887,47.9642],[-96.0106,47.9641],[-96.0324,47.964],[-96.054,47.9638],[-96.0757,47.9637],[-96.096,47.9638],[-96.1173,47.9632],[-96.1389,47.9631],[-96.1606,47.9631],[-96.1826,47.9632],[-96.2044,47.963],[-96.2235,47.9629],[-96.2453,47.9629],[-96.2667,47.9629],[-96.2883,47.963],[-96.31,47.9633],[-96.3316,47.9634],[-96.3526,47.9634],[-96.3738,47.9636],[-96.3954,47.9636],[-96.4172,47.9637],[-96.439,47.9636],[-96.4603,47.9639],[-96.4823,47.9636],[-96.4823,47.9782],[-96.4824,47.9924],[-96.4826,48.0072],[-96.4826,48.0217],[-96.5009,48.0217],[-96.5009,48.0362],[-96.5008,48.0506],[-96.5009,48.0654],[-96.5009,48.0798],[-96.5009,48.0943],[-96.501,48.1089],[-96.5007,48.1234],[-96.5006,48.1379],[-96.5008,48.1524],[-96.5008,48.1669],[-96.5008,48.1742]]],"type":"Polygon"},"id":"57","properties":{"Area":1601102945.98836,"CTYONLY_":10,"Code":"PENN","LASTMOD":"2006-07-04T12:00:00Z","Name":"Pennington","Perimiter":190039.7415},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=9","rel":"next","title":"next page","type":"application/geo+json"}],"numberMatched":117,"numberReturned":9,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_collections_mn_population_centers_items_by_id_no_extent.json b/msautotest/api/expected/ogcapi_collections_mn_population_centers_items_by_id_no_extent.json new file mode 100644 index 0000000000..239d5a37f1 --- /dev/null +++ b/msautotest/api/expected/ogcapi_collections_mn_population_centers_items_by_id_no_extent.json @@ -0,0 +1 @@ +{"geometry":{"coordinates":[-96.5166,47.2991],"type":"Point"},"id":"2710700172","links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_population_centers/items/2710700172?f=json","rel":"self","title":"This document as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_population_centers/items/2710700172?f=html","rel":"alternate","title":"This document as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_population_centers?f=json","rel":"collection","title":"This collection as JSON","type":"application/json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_population_centers?f=html","rel":"collection","title":"This collection as HTML","type":"text/html"}],"properties":{"County":"Norman County","Name":"Ada","Population":"1681","Type":"City"},"type":"Feature"} diff --git a/msautotest/api/expected/ogcapi_collections_multipolygon_items.html b/msautotest/api/expected/ogcapi_collections_multipolygon_items.html new file mode 100644 index 0000000000..32de488d74 --- /dev/null +++ b/msautotest/api/expected/ogcapi_collections_multipolygon_items.html @@ -0,0 +1,41 @@ + + + + Pull Request #7305 + + + + + +

Pull Request #7305 - Collection Items: Multipolygon layer

+ +

+ Number of matching items: 1
+ Number of returned items: 1
+

+ + + + + + + + + + + + + + + + + + +
ID
3.000000000000000
+ + + + + + + diff --git a/msautotest/api/expected/ogcapi_collections_multipolygon_items.json b/msautotest/api/expected/ogcapi_collections_multipolygon_items.json new file mode 100644 index 0000000000..8fdc2ef557 --- /dev/null +++ b/msautotest/api/expected/ogcapi_collections_multipolygon_items.json @@ -0,0 +1 @@ +{"features":[{"geometry":{"coordinates":[[[[8.9216,45.5746],[8.8919,45.6027],[8.936,45.607],[8.9413,45.599],[8.9413,45.599],[8.9329,45.5924],[8.9216,45.5746],[8.9216,45.5746]],[[8.9112,45.6001],[8.9178,45.5871],[8.9308,45.5933],[8.9256,45.6004],[8.9112,45.6001]],[[8.9234,45.5865],[8.92,45.5851],[8.9208,45.5803],[8.9263,45.5832],[8.9234,45.5865]]],[[[8.9341,45.5868],[8.9337,45.5819],[8.9409,45.5836],[8.9387,45.5894],[8.9341,45.5868]]]],"type":"MultiPolygon"},"id":"3.000000000000000","properties":{},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/7305/ogcapi/collections/multipolygon_layer/items?f=json&limit=10&offset=0","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/7305/ogcapi/collections/multipolygon_layer/items?f=html&limit=10&offset=0","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":1,"numberReturned":1,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_collections_queryables_unknown_parameter.json.txt b/msautotest/api/expected/ogcapi_collections_queryables_unknown_parameter.json.txt new file mode 100644 index 0000000000..237dff26d3 --- /dev/null +++ b/msautotest/api/expected/ogcapi_collections_queryables_unknown_parameter.json.txt @@ -0,0 +1,4 @@ +Content-Type: application/json +Status: 400 + +{"code":"InvalidParameterValue","description":"Unknown query parameter: unknown"} diff --git a/msautotest/api/expected/ogcapi_collections_tanzania1_items.html.txt b/msautotest/api/expected/ogcapi_collections_tanzania1_items.html.txt new file mode 100644 index 0000000000..f1a7fdbd62 --- /dev/null +++ b/msautotest/api/expected/ogcapi_collections_tanzania1_items.html.txt @@ -0,0 +1 @@ +{"code":"ConfigError","description":"Invalid UTF-8 data, check encoding."} diff --git a/msautotest/api/expected/ogcapi_collections_tanzania1_items.json.txt b/msautotest/api/expected/ogcapi_collections_tanzania1_items.json.txt new file mode 100644 index 0000000000..f1a7fdbd62 --- /dev/null +++ b/msautotest/api/expected/ogcapi_collections_tanzania1_items.json.txt @@ -0,0 +1 @@ +{"code":"ConfigError","description":"Invalid UTF-8 data, check encoding."} diff --git a/msautotest/api/expected/ogcapi_collections_tanzania2_items.html b/msautotest/api/expected/ogcapi_collections_tanzania2_items.html new file mode 100644 index 0000000000..a4b2dea2b6 --- /dev/null +++ b/msautotest/api/expected/ogcapi_collections_tanzania2_items.html @@ -0,0 +1,49 @@ + + + + Issue #6631 + + + + + +

Issue #6631 - Collection Items: Tanzania Boundary

+ +

+ Number of matching items: 1
+ Number of returned items: 1
+

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
IDnamename_hu
1159321337TanzaniaTanzánia
+ + + + + + + diff --git a/msautotest/api/expected/ogcapi_collections_tanzania2_items.json b/msautotest/api/expected/ogcapi_collections_tanzania2_items.json new file mode 100644 index 0000000000..8564c39a71 --- /dev/null +++ b/msautotest/api/expected/ogcapi_collections_tanzania2_items.json @@ -0,0 +1 @@ +{"features":[{"geometry":{"coordinates":[[[33.9038,-0.95],[34.0727,-1.0598],[37.6987,-3.0969],[37.7669,-3.6771],[39.2023,-4.6767],[38.7406,-5.9089],[38.7998,-6.4756],[39.44,-6.8399],[39.4701,-7.0999],[39.1947,-7.7038],[39.2521,-8.0078],[39.1866,-8.4855],[39.5358,-9.1123],[39.9497,-10.0984],[40.3166,-10.317],[40.3166,-10.317],[39.521,-10.8968],[38.4276,-11.2852],[37.8277,-11.2687],[37.4713,-11.5687],[36.7752,-11.5945],[36.5141,-11.7209],[35.3124,-11.4391],[34.56,-11.52],[34.28,-10.16],[33.9409,-9.6936],[33.7398,-9.4171],[32.7594,-9.2305],[32.1919,-8.9303],[31.5564,-8.762],[31.1578,-8.5945],[30.7401,-8.34],[30.7401,-8.34],[30.2,-7.0799],[29.6201,-6.52],[29.42,-5.9399],[29.52,-5.4199],[29.34,-4.4999],[29.7536,-4.4523],[30.1164,-4.0901],[30.5056,-3.5685],[30.7523,-3.3593],[30.7431,-3.0343],[30.5277,-2.8076],[30.4697,-2.4138],[30.4697,-2.4138],[30.7584,-2.2872],[30.8162,-1.6989],[30.4192,-1.1346],[30.7699,-1.0145],[31.8662,-1.0273],[33.9038,-0.95]]],"type":"Polygon"},"id":"1159321337","properties":{"name":"Tanzania","name_hu":"Tanzánia"},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/6631/ogcapi/collections/tanzania2/items?f=json&limit=10&offset=0","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/6631/ogcapi/collections/tanzania2/items?f=html&limit=10&offset=0","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":1,"numberReturned":1,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_collections_unknown_parameter.json.txt b/msautotest/api/expected/ogcapi_collections_unknown_parameter.json.txt new file mode 100644 index 0000000000..237dff26d3 --- /dev/null +++ b/msautotest/api/expected/ogcapi_collections_unknown_parameter.json.txt @@ -0,0 +1,4 @@ +Content-Type: application/json +Status: 400 + +{"code":"InvalidParameterValue","description":"Unknown query parameter: unknown"} diff --git a/msautotest/api/expected/ogcapi_conformance_unknown_parameter.json.txt b/msautotest/api/expected/ogcapi_conformance_unknown_parameter.json.txt new file mode 100644 index 0000000000..237dff26d3 --- /dev/null +++ b/msautotest/api/expected/ogcapi_conformance_unknown_parameter.json.txt @@ -0,0 +1,4 @@ +Content-Type: application/json +Status: 400 + +{"code":"InvalidParameterValue","description":"Unknown query parameter: unknown"} diff --git a/msautotest/api/expected/ogcapi_cql2_json_add.json.txt b/msautotest/api/expected/ogcapi_cql2_json_add.json.txt new file mode 100644 index 0000000000..adb569a3dd --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_json_add.json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 1 +OGC-NumberReturned: 1 + +{"features":[{"geometry":{"coordinates":[[[-96.4054,49.0001],[-96.4019,49.0001],[-96.3825,49.0001],[-96.3783,49.0001],[-96.3606,49.0001],[-96.3579,49.0001],[-96.3385,49.0001],[-96.3343,49.0001],[-96.3166,49.0001],[-96.3138,49.0001],[-96.2945,49.0001],[-96.2902,49.0001],[-96.2725,49.0001],[-96.2698,49.0001],[-96.2494,49.0001],[-96.2461,49.0001],[-96.2274,49.0001],[-96.2257,49.0001],[-96.2057,49.0001],[-96.2021,49.0001],[-96.1837,49.0],[-96.18,49.0],[-96.1617,49.0],[-96.1579,49.0],[-96.1401,49.0],[-96.1359,49.0],[-96.1176,49.0],[-96.1139,49.0],[-96.0957,49.0],[-96.0919,49.0],[-96.0738,49.0],[-96.07,49.0],[-96.0517,49.0],[-96.048,49.0],[-96.0298,49.0],[-96.026,49.0],[-96.0083,49.0],[-96.0045,49.0],[-95.9868,49.0],[-95.9784,49.0],[-95.9776,49.0],[-95.9755,49.0],[-95.9648,48.9999],[-95.9464,48.9999],[-95.943,48.9999],[-95.9225,48.9999],[-95.9211,48.9999],[-95.899,48.9998],[-95.883,48.9998],[-95.8771,48.9998],[-95.8564,48.9998],[-95.855,48.9998],[-95.8342,48.9998],[-95.8184,48.9997],[-95.8126,48.9997],[-95.7906,48.9997],[-95.7833,48.9997],[-95.7684,48.9997],[-95.7479,48.9996],[-95.7466,48.9996],[-95.7253,48.9996],[-95.7066,48.9996],[-95.7032,48.9996],[-95.681,48.9995],[-95.6654,48.9995],[-95.6596,48.9995],[-95.659,48.9995],[-95.6401,48.9995],[-95.6369,48.9995],[-95.6205,48.9994],[-95.615,48.9994],[-95.5948,48.9994],[-95.585,48.9994],[-95.573,48.9994],[-95.551,48.9993],[-95.5495,48.9993],[-95.5294,48.9993],[-95.5164,48.9993],[-95.5072,48.9993],[-95.4849,48.9992],[-95.4834,48.9992],[-95.4635,48.9992],[-95.4508,48.9992],[-95.4418,48.9992],[-95.4245,48.9991],[-95.4197,48.9991],[-95.3977,48.9991],[-95.3953,48.9991],[-95.3765,48.9991],[-95.3759,48.9991],[-95.3753,48.9991],[-95.3542,48.999],[-95.3513,48.999],[-95.3326,48.999],[-95.3286,48.999],[-95.3231,48.999],[-95.3224,48.9984],[-95.3204,48.9976],[-95.3202,48.9973],[-95.3204,48.9964],[-95.3206,48.9961],[-95.3201,48.9956],[-95.3197,48.9954],[-95.3191,48.9953],[-95.3187,48.9956],[-95.3182,48.996],[-95.3179,48.9961],[-95.3178,48.9961],[-95.3178,48.9958],[-95.3181,48.995],[-95.3191,48.9941],[-95.3204,48.9924],[-95.3206,48.9921],[-95.3224,48.9889],[-95.3227,48.9884],[-95.3242,48.9859],[-95.3245,48.985],[-95.3253,48.9832],[-95.3257,48.9814],[-95.3256,48.98],[-95.3255,48.9789],[-95.3257,48.9784],[-95.3253,48.976],[-95.325,48.9743],[-95.3249,48.9738],[-95.3248,48.9728],[-95.3247,48.972],[-95.3241,48.9703],[-95.3232,48.9692],[-95.3227,48.9685],[-95.3212,48.9672],[-95.3207,48.9669],[-95.3201,48.9648],[-95.3198,48.9643],[-95.3193,48.964],[-95.3193,48.9622],[-95.3202,48.9606],[-95.3206,48.9598],[-95.3206,48.9595],[-95.3206,48.959],[-95.3202,48.9581],[-95.3191,48.9569],[-95.3188,48.9562],[-95.3179,48.9559],[-95.3175,48.9552],[-95.3177,48.9545],[-95.3182,48.9535],[-95.3181,48.9531],[-95.3177,48.9525],[-95.3154,48.9513],[-95.3151,48.951],[-95.3141,48.9508],[-95.3131,48.9503],[-95.3125,48.9503],[-95.3123,48.9502],[-95.3119,48.9502],[-95.3119,48.9507],[-95.3129,48.9521],[-95.3129,48.9523],[-95.3126,48.9524],[-95.312,48.9524],[-95.3115,48.952],[-95.3108,48.9512],[-95.3104,48.951],[-95.3097,48.951],[-95.3089,48.9511],[-95.3079,48.9509],[-95.3061,48.9502],[-95.3052,48.9495],[-95.3046,48.9482],[-95.3046,48.947],[-95.305,48.9462],[-95.3053,48.9459],[-95.3061,48.9454],[-95.3068,48.9454],[-95.3069,48.9455],[-95.3069,48.9456],[-95.3063,48.9462],[-95.3062,48.9463],[-95.3061,48.9469],[-95.3062,48.9472],[-95.3062,48.9472],[-95.3071,48.9477],[-95.3081,48.948],[-95.3094,48.9481],[-95.3096,48.9482],[-95.3099,48.9484],[-95.31,48.9485],[-95.3103,48.9485],[-95.3104,48.9484],[-95.3103,48.948],[-95.3096,48.9478],[-95.3092,48.9477],[-95.3079,48.9474],[-95.3071,48.9469],[-95.3071,48.9466],[-95.3074,48.9465],[-95.3078,48.9466],[-95.3085,48.947],[-95.3086,48.9469],[-95.3086,48.9465],[-95.3088,48.9464],[-95.3095,48.9463],[-95.3102,48.9463],[-95.3114,48.9461],[-95.3131,48.946],[-95.3141,48.9457],[-95.3148,48.9452],[-95.3154,48.9448],[-95.3168,48.9431],[-95.3181,48.9421],[-95.3189,48.9419],[-95.3219,48.9412],[-95.3225,48.9409],[-95.3228,48.9403],[-95.3231,48.9389],[-95.3229,48.9373],[-95.3225,48.9358],[-95.3223,48.9355],[-95.3228,48.9344],[-95.3222,48.9327],[-95.3209,48.9307],[-95.3208,48.9305],[-95.3195,48.9285],[-95.3168,48.9245],[-95.315,48.9222],[-95.3141,48.921],[-95.3132,48.9198],[-95.3126,48.919],[-95.3119,48.9178],[-95.3115,48.9172],[-95.3109,48.9163],[-95.3102,48.9155],[-95.3093,48.9149],[-95.3092,48.9149],[-95.3085,48.9146],[-95.3078,48.9141],[-95.3074,48.9135],[-95.3064,48.9129],[-95.3061,48.9128],[-95.3059,48.9127],[-95.3043,48.9119],[-95.3038,48.9114],[-95.3027,48.91],[-95.3017,48.9093],[-95.2999,48.9086],[-95.2978,48.9083],[-95.2973,48.9081],[-95.2973,48.908],[-95.2973,48.9077],[-95.2976,48.9074],[-95.2977,48.9073],[-95.2978,48.9073],[-95.2978,48.9072],[-95.2978,48.9072],[-95.2979,48.9072],[-95.2979,48.9072],[-95.2979,48.9071],[-95.298,48.9071],[-95.298,48.9071],[-95.298,48.9071],[-95.2981,48.907],[-95.2982,48.9068],[-95.2983,48.9068],[-95.2985,48.9065],[-95.2985,48.9064],[-95.2986,48.9063],[-95.2988,48.906],[-95.2989,48.906],[-95.2991,48.9057],[-95.2992,48.9055],[-95.2994,48.9053],[-95.2996,48.9051],[-95.2997,48.905],[-95.2999,48.9048],[-95.2999,48.9048],[-95.2999,48.9048],[-95.3,48.9047],[-95.3,48.9047],[-95.3001,48.9047],[-95.3001,48.9046],[-95.3002,48.9045],[-95.3005,48.904],[-95.2993,48.9035],[-95.2983,48.9028],[-95.298,48.9027],[-95.2976,48.9026],[-95.2967,48.9027],[-95.2949,48.9028],[-95.2941,48.9027],[-95.2937,48.9023],[-95.2935,48.902],[-95.2927,48.9019],[-95.2914,48.9019],[-95.2909,48.9017],[-95.2908,48.9016],[-95.2907,48.9014],[-95.2906,48.9011],[-95.2911,48.9008],[-95.2911,48.9006],[-95.2901,48.9003],[-95.2896,48.9],[-95.289,48.8994],[-95.2882,48.8981],[-95.2879,48.8979],[-95.2872,48.8977],[-95.287,48.8976],[-95.2865,48.8975],[-95.2861,48.8976],[-95.2853,48.8977],[-95.2839,48.8975],[-95.2813,48.8967],[-95.2803,48.8965],[-95.2796,48.8962],[-95.279,48.8957],[-95.2782,48.8956],[-95.2773,48.8957],[-95.277,48.8958],[-95.2765,48.8962],[-95.2763,48.8963],[-95.2759,48.8962],[-95.2755,48.8959],[-95.2749,48.8956],[-95.2748,48.8951],[-95.2753,48.8943],[-95.2751,48.8938],[-95.2745,48.8931],[-95.2724,48.8921],[-95.2713,48.8915],[-95.268,48.8905],[-95.2677,48.8903],[-95.2674,48.89],[-95.2666,48.8894],[-95.2654,48.8888],[-95.265,48.8886],[-95.2646,48.8885],[-95.2639,48.8883],[-95.2635,48.888],[-95.2627,48.8877],[-95.2585,48.8867],[-95.2585,48.8867],[-95.257,48.8858],[-95.256,48.885],[-95.2548,48.8845],[-95.2517,48.8839],[-95.2507,48.8836],[-95.2502,48.8835],[-95.2496,48.8834],[-95.2485,48.8832],[-95.248,48.8836],[-95.2472,48.8835],[-95.2458,48.8829],[-95.2439,48.8823],[-95.2429,48.8822],[-95.2429,48.8822],[-95.2423,48.8821],[-95.2407,48.8821],[-95.2391,48.8819],[-95.2381,48.8817],[-95.2356,48.8815],[-95.2335,48.8814],[-95.231,48.8814],[-95.2287,48.8815],[-95.2265,48.8816],[-95.2252,48.8819],[-95.2212,48.883],[-95.2208,48.8831],[-95.2207,48.8831],[-95.22,48.8831],[-95.2193,48.8832],[-95.2188,48.8835],[-95.217,48.8835],[-95.2159,48.8839],[-95.2151,48.884],[-95.2144,48.8843],[-95.2122,48.8842],[-95.2117,48.8847],[-95.2115,48.8847],[-95.2112,48.8848],[-95.2085,48.8846],[-95.2059,48.8848],[-95.2024,48.8852],[-95.2009,48.8855],[-95.2005,48.8856],[-95.1986,48.8855],[-95.1956,48.8862],[-95.1924,48.8865],[-95.1919,48.8866],[-95.1913,48.8868],[-95.1901,48.887],[-95.1889,48.8873],[-95.1877,48.8874],[-95.1863,48.8877],[-95.1851,48.8882],[-95.1819,48.8888],[-95.1797,48.889],[-95.1791,48.889],[-95.1764,48.8893],[-95.173,48.8897],[-95.1701,48.8902],[-95.1674,48.8907],[-95.1648,48.8913],[-95.1641,48.8917],[-95.1618,48.892],[-95.1602,48.892],[-95.1579,48.8919],[-95.1564,48.8919],[-95.1555,48.892],[-95.1528,48.8921],[-95.1508,48.8922],[-95.1483,48.8923],[-95.1469,48.8927],[-95.1459,48.8929],[-95.1438,48.8934],[-95.1436,48.8937],[-95.1404,48.8943],[-95.1381,48.8949],[-95.1355,48.8959],[-95.1351,48.8963],[-95.1348,48.8963],[-95.1343,48.8963],[-95.1337,48.8969],[-95.1322,48.8973],[-95.1312,48.8975],[-95.1252,48.8998],[-95.1239,48.9001],[-95.1233,48.9004],[-95.1228,48.9006],[-95.1214,48.9013],[-95.121,48.9016],[-95.1205,48.9017],[-95.1204,48.9019],[-95.1182,48.9029],[-95.1163,48.9037],[-95.1151,48.9046],[-95.1144,48.9052],[-95.114,48.9061],[-95.1141,48.9064],[-95.1137,48.9069],[-95.1132,48.9071],[-95.113,48.9072],[-95.1126,48.9073],[-95.1107,48.9082],[-95.1096,48.9089],[-95.108,48.9099],[-95.1056,48.9113],[-95.1042,48.9121],[-95.1032,48.9127],[-95.102,48.9132],[-95.1008,48.9142],[-95.0981,48.9159],[-95.098,48.916],[-95.0975,48.9164],[-95.0971,48.9172],[-95.097,48.9176],[-95.0961,48.9181],[-95.0946,48.9191],[-95.0944,48.9193],[-95.0927,48.9204],[-95.0919,48.9207],[-95.0914,48.9208],[-95.0914,48.916],[-95.0912,48.9014],[-95.0911,48.8869],[-95.0908,48.8724],[-95.0908,48.858],[-95.0907,48.8436],[-95.0908,48.8291],[-95.0909,48.8147],[-95.0903,48.8],[-95.0903,48.7855],[-95.0903,48.7711],[-95.0901,48.7566],[-95.0901,48.7421],[-95.0899,48.7277],[-95.0898,48.713],[-95.1046,48.7129],[-95.1104,48.7129],[-95.1119,48.7129],[-95.1259,48.7129],[-95.1297,48.713],[-95.1333,48.713],[-95.1477,48.7129],[-95.1554,48.7129],[-95.1697,48.7129],[-95.1773,48.713],[-95.1917,48.713],[-95.1991,48.713],[-95.2112,48.713],[-95.2206,48.713],[-95.2331,48.713],[-95.2427,48.713],[-95.255,48.713],[-95.2645,48.713],[-95.2656,48.713],[-95.2767,48.713],[-95.2866,48.713],[-95.299,48.713],[-95.3051,48.713],[-95.3084,48.713],[-95.3205,48.713],[-95.3302,48.713],[-95.3425,48.7131],[-95.3425,48.6995],[-95.3424,48.6849],[-95.3423,48.6705],[-95.3424,48.6561],[-95.3425,48.6415],[-95.3426,48.6271],[-95.3424,48.6127],[-95.3426,48.5979],[-95.3423,48.5836],[-95.3423,48.5691],[-95.3424,48.5548],[-95.3425,48.5402],[-95.3628,48.5404],[-95.364,48.5403],[-95.3844,48.5402],[-95.386,48.5402],[-95.4061,48.5402],[-95.4078,48.5402],[-95.4279,48.54],[-95.4297,48.5399],[-95.4494,48.5399],[-95.4513,48.5399],[-95.4712,48.5396],[-95.4726,48.5396],[-95.493,48.5392],[-95.495,48.5392],[-95.5143,48.539],[-95.5163,48.539],[-95.5365,48.5389],[-95.5383,48.5389],[-95.558,48.5388],[-95.5603,48.5388],[-95.5801,48.5387],[-95.5821,48.5387],[-95.6023,48.5389],[-95.6232,48.5391],[-95.6447,48.5393],[-95.6666,48.5394],[-95.6886,48.5395],[-95.7102,48.5395],[-95.7322,48.54],[-95.7539,48.5404],[-95.7758,48.5406],[-95.7976,48.5405],[-95.8192,48.5404],[-95.8411,48.5406],[-95.8621,48.5414],[-95.8829,48.5419],[-95.8851,48.542],[-95.8986,48.5421],[-95.9046,48.5422],[-95.9064,48.5422],[-95.9269,48.5421],[-95.9486,48.5425],[-95.9498,48.5425],[-95.9704,48.543],[-95.9936,48.5435],[-96.0157,48.5437],[-96.0374,48.5438],[-96.0592,48.5437],[-96.0812,48.5436],[-96.1026,48.5438],[-96.1264,48.5439],[-96.1486,48.5442],[-96.1702,48.5445],[-96.1921,48.5446],[-96.2141,48.5449],[-96.2358,48.5452],[-96.2576,48.545],[-96.2794,48.5449],[-96.301,48.5448],[-96.3231,48.5446],[-96.3448,48.5444],[-96.3667,48.5443],[-96.3882,48.5442],[-96.3879,48.5588],[-96.3882,48.5733],[-96.3884,48.5877],[-96.3891,48.6024],[-96.389,48.6165],[-96.388,48.6313],[-96.3879,48.6454],[-96.3877,48.6599],[-96.3871,48.6741],[-96.3874,48.6887],[-96.3866,48.703],[-96.3873,48.7172],[-96.388,48.7172],[-96.4049,48.7172],[-96.4048,48.7318],[-96.4048,48.7465],[-96.4047,48.7607],[-96.4045,48.7758],[-96.4042,48.7903],[-96.4042,48.8048],[-96.4042,48.8198],[-96.4043,48.8343],[-96.4045,48.8491],[-96.4047,48.8635],[-96.405,48.878],[-96.405,48.8926],[-96.4053,48.9068],[-96.4053,48.9081],[-96.4053,48.9137],[-96.4054,48.9214],[-96.4054,48.9225],[-96.4053,48.936],[-96.4053,48.9371],[-96.4053,48.9504],[-96.4053,48.9515],[-96.4053,48.9648],[-96.4053,48.9658],[-96.4053,48.9705],[-96.4054,48.9793],[-96.4054,48.9803],[-96.4054,48.994],[-96.4054,48.9947],[-96.4054,49.0001]]],"type":"Polygon"},"id":"68","properties":{"Area":4347098503.12714,"CTYONLY_":4,"Code":"ROSE","LASTMOD":"2001-04-12T09:32:44Z","Name":"Roseau","Perimiter":302590.75293},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&filter=%7B%22op%22%3A%22%3D%22%2C%22args%22%3A%5B%7B%22property%22%3A%22CTYONLY_%22%7D%2C%7B%22op%22%3A%22%2B%22%2C%22args%22%3A%5B1%2C3%5D%7D%5D%7D&filter-lang=cql2-json","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&filter=%7B%22op%22%3A%22%3D%22%2C%22args%22%3A%5B%7B%22property%22%3A%22CTYONLY_%22%7D%2C%7B%22op%22%3A%22%2B%22%2C%22args%22%3A%5B1%2C3%5D%7D%5D%7D&filter-lang=cql2-json","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":1,"numberReturned":1,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_json_and_false.json.txt b/msautotest/api/expected/ogcapi_cql2_json_and_false.json.txt new file mode 100644 index 0000000000..2064dedb8b --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_json_and_false.json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 0 +OGC-NumberReturned: 0 + +{"features":[],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&filter=%7B%22op%22%3A%22and%22%2C%22args%22%3A%5B%7B%22op%22%3A%22%3D%22%2C%22args%22%3A%5B%7B%22property%22%3A%22Name%22%7D%2C%22Rice%22%5D%7D%2Cfalse%5D%7D&filter-lang=cql2-json","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&filter=%7B%22op%22%3A%22and%22%2C%22args%22%3A%5B%7B%22op%22%3A%22%3D%22%2C%22args%22%3A%5B%7B%22property%22%3A%22Name%22%7D%2C%22Rice%22%5D%7D%2Cfalse%5D%7D&filter-lang=cql2-json","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":0,"numberReturned":0,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_json_and_true.json.txt b/msautotest/api/expected/ogcapi_cql2_json_and_true.json.txt new file mode 100644 index 0000000000..fe2e22b194 --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_json_and_true.json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 1 +OGC-NumberReturned: 1 + +{"features":[{"geometry":{"coordinates":[[[-93.5242,44.5436],[-93.5225,44.5436],[-93.504,44.5438],[-93.5018,44.5438],[-93.4835,44.5438],[-93.4817,44.5438],[-93.4734,44.5438],[-93.4632,44.5438],[-93.4609,44.5438],[-93.4429,44.5438],[-93.4408,44.5438],[-93.4326,44.5438],[-93.4226,44.5439],[-93.4206,44.5439],[-93.4024,44.5439],[-93.4003,44.5439],[-93.383,44.544],[-93.38,44.544],[-93.3627,44.5441],[-93.3596,44.5441],[-93.3556,44.5441],[-93.3424,44.5442],[-93.3395,44.5442],[-93.3221,44.544],[-93.3191,44.544],[-93.3128,44.544],[-93.3019,44.544],[-93.2988,44.544],[-93.2813,44.544],[-93.2814,44.5298],[-93.2815,44.5153],[-93.2815,44.501],[-93.2815,44.4865],[-93.2817,44.472],[-93.2618,44.4718],[-93.2415,44.4716],[-93.2213,44.4714],[-93.2008,44.4714],[-93.1808,44.4713],[-93.1605,44.4713],[-93.1408,44.4712],[-93.1206,44.4713],[-93.1002,44.4718],[-93.0799,44.4719],[-93.0597,44.4718],[-93.0393,44.4719],[-93.0394,44.4576],[-93.0396,44.4432],[-93.0397,44.4287],[-93.0399,44.4143],[-93.04,44.3999],[-93.0401,44.3855],[-93.0402,44.371],[-93.0403,44.3565],[-93.0403,44.3419],[-93.0405,44.3273],[-93.0405,44.3129],[-93.0405,44.2983],[-93.0406,44.2838],[-93.0407,44.2693],[-93.0409,44.2548],[-93.041,44.2402],[-93.0411,44.2257],[-93.0411,44.2113],[-93.0411,44.1968],[-93.0427,44.1968],[-93.0459,44.1968],[-93.0613,44.1967],[-93.0661,44.1967],[-93.0815,44.1967],[-93.0862,44.1967],[-93.1003,44.1967],[-93.1015,44.1967],[-93.1063,44.1967],[-93.1092,44.1967],[-93.1218,44.1967],[-93.1267,44.1967],[-93.1301,44.1967],[-93.1418,44.1967],[-93.1467,44.1967],[-93.1561,44.1966],[-93.1622,44.1966],[-93.1661,44.1966],[-93.1703,44.1966],[-93.1822,44.1966],[-93.1856,44.1966],[-93.1865,44.1966],[-93.2023,44.1966],[-93.2037,44.1966],[-93.2064,44.1966],[-93.2225,44.1966],[-93.2265,44.1966],[-93.2292,44.1966],[-93.2426,44.1966],[-93.2465,44.1966],[-93.255,44.1966],[-93.2629,44.1966],[-93.2664,44.1966],[-93.2767,44.1966],[-93.283,44.1966],[-93.2865,44.1965],[-93.2905,44.1965],[-93.3032,44.1965],[-93.3063,44.1965],[-93.3235,44.1965],[-93.3264,44.1965],[-93.3277,44.1965],[-93.3436,44.1965],[-93.3466,44.1965],[-93.3639,44.1965],[-93.3666,44.1965],[-93.3842,44.1965],[-93.3866,44.1965],[-93.4042,44.1965],[-93.4065,44.1965],[-93.4244,44.1964],[-93.4267,44.1964],[-93.4447,44.1964],[-93.4469,44.1964],[-93.4648,44.1963],[-93.467,44.1963],[-93.4852,44.1964],[-93.4872,44.1964],[-93.5053,44.1963],[-93.507,44.1963],[-93.5255,44.1962],[-93.5253,44.2107],[-93.5251,44.2251],[-93.5251,44.2388],[-93.5251,44.2533],[-93.5252,44.2685],[-93.5252,44.2829],[-93.5252,44.2975],[-93.5252,44.312],[-93.5249,44.3266],[-93.5249,44.3411],[-93.5245,44.3557],[-93.5245,44.3704],[-93.5246,44.3848],[-93.5245,44.3994],[-93.5245,44.4138],[-93.5245,44.4283],[-93.5245,44.4427],[-93.5245,44.4572],[-93.5244,44.4717],[-93.5245,44.4862],[-93.5244,44.5007],[-93.5243,44.5152],[-93.5244,44.5297],[-93.5242,44.5436]]],"type":"Polygon"},"id":"66","properties":{"Area":1335114621.00336,"CTYONLY_":66,"Code":"RICE","LASTMOD":"2010-10-17T00:00:00Z","Name":"Rice","Perimiter":154431.78788},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&filter=%7B%22op%22%3A%22and%22%2C%22args%22%3A%5B%7B%22op%22%3A%22%3D%22%2C%22args%22%3A%5B%7B%22property%22%3A%22Name%22%7D%2C%22Rice%22%5D%7D%2Ctrue%5D%7D&filter-lang=cql2-json","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&filter=%7B%22op%22%3A%22and%22%2C%22args%22%3A%5B%7B%22op%22%3A%22%3D%22%2C%22args%22%3A%5B%7B%22property%22%3A%22Name%22%7D%2C%22Rice%22%5D%7D%2Ctrue%5D%7D&filter-lang=cql2-json","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":1,"numberReturned":1,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_json_between.json.txt b/msautotest/api/expected/ogcapi_cql2_json_between.json.txt new file mode 100644 index 0000000000..26edee0b29 --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_json_between.json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 3 +OGC-NumberReturned: 3 + +{"features":[{"geometry":{"coordinates":[[[-96.4054,49.0001],[-96.4054,48.9947],[-96.4054,48.994],[-96.4054,48.9803],[-96.4054,48.9793],[-96.4053,48.9705],[-96.4053,48.9658],[-96.4053,48.9648],[-96.4053,48.9515],[-96.4053,48.9504],[-96.4053,48.9371],[-96.4053,48.936],[-96.4054,48.9225],[-96.4054,48.9214],[-96.4053,48.9137],[-96.4053,48.9081],[-96.4053,48.9068],[-96.405,48.8926],[-96.405,48.878],[-96.4047,48.8635],[-96.4045,48.8491],[-96.4043,48.8343],[-96.4042,48.8198],[-96.4042,48.8048],[-96.4042,48.7903],[-96.4045,48.7758],[-96.4047,48.7607],[-96.4048,48.7465],[-96.4048,48.7318],[-96.4049,48.7172],[-96.388,48.7172],[-96.3873,48.7172],[-96.3866,48.703],[-96.3874,48.6887],[-96.3871,48.6741],[-96.3877,48.6599],[-96.3879,48.6454],[-96.388,48.6313],[-96.389,48.6165],[-96.3891,48.6024],[-96.3884,48.5877],[-96.3882,48.5733],[-96.3879,48.5588],[-96.3882,48.5442],[-96.4101,48.544],[-96.4318,48.5438],[-96.4535,48.5436],[-96.4754,48.5435],[-96.4973,48.5434],[-96.518,48.5434],[-96.54,48.5434],[-96.5621,48.5436],[-96.5839,48.5437],[-96.6058,48.5437],[-96.6278,48.5437],[-96.6493,48.5437],[-96.6713,48.5436],[-96.6931,48.5437],[-96.7151,48.5437],[-96.7368,48.5437],[-96.7585,48.5436],[-96.7803,48.5435],[-96.8023,48.5436],[-96.824,48.5436],[-96.8459,48.5434],[-96.8678,48.5433],[-96.8896,48.5433],[-96.9115,48.5432],[-96.9138,48.5433],[-96.9331,48.5435],[-96.9551,48.5437],[-96.9768,48.544],[-96.9985,48.5441],[-97.0194,48.5441],[-97.0416,48.5442],[-97.0635,48.5441],[-97.0852,48.5441],[-97.107,48.544],[-97.1287,48.5439],[-97.1509,48.5439],[-97.1631,48.544],[-97.1637,48.5445],[-97.1659,48.5483],[-97.1662,48.5509],[-97.1661,48.5527],[-97.1654,48.5536],[-97.1645,48.554],[-97.1628,48.5543],[-97.1613,48.5539],[-97.1592,48.5528],[-97.1577,48.5518],[-97.1557,48.5512],[-97.1538,48.5513],[-97.1513,48.5515],[-97.1507,48.5515],[-97.1493,48.5516],[-97.1474,48.5516],[-97.1444,48.5514],[-97.1407,48.5515],[-97.1387,48.5522],[-97.1379,48.553],[-97.1379,48.5542],[-97.1391,48.5554],[-97.141,48.5566],[-97.1426,48.5571],[-97.1464,48.5573],[-97.1505,48.5574],[-97.1515,48.5574],[-97.1551,48.5574],[-97.1578,48.5573],[-97.1606,48.5571],[-97.1631,48.5571],[-97.1646,48.5572],[-97.167,48.5575],[-97.1697,48.5584],[-97.1721,48.5591],[-97.1727,48.5593],[-97.174,48.5599],[-97.1749,48.5606],[-97.1753,48.5614],[-97.1754,48.5623],[-97.1749,48.5631],[-97.1744,48.5639],[-97.1723,48.5648],[-97.1721,48.5648],[-97.1706,48.5652],[-97.1687,48.5655],[-97.167,48.5658],[-97.1651,48.5659],[-97.1613,48.5661],[-97.1541,48.5669],[-97.153,48.5671],[-97.1516,48.5677],[-97.1503,48.5688],[-97.1496,48.5695],[-97.1487,48.5707],[-97.1477,48.5727],[-97.1477,48.5728],[-97.1476,48.5731],[-97.1483,48.5763],[-97.15,48.5775],[-97.1501,48.5775],[-97.1548,48.5779],[-97.1592,48.5785],[-97.1605,48.58],[-97.16,48.5816],[-97.1578,48.5826],[-97.1562,48.5828],[-97.1541,48.5826],[-97.1524,48.5823],[-97.15,48.5815],[-97.1494,48.5813],[-97.1484,48.5811],[-97.1449,48.5815],[-97.1436,48.5824],[-97.1431,48.5834],[-97.1429,48.5838],[-97.142,48.5876],[-97.1418,48.5886],[-97.1415,48.5909],[-97.1422,48.5926],[-97.1433,48.5936],[-97.1451,48.594],[-97.1471,48.594],[-97.1497,48.5937],[-97.1525,48.594],[-97.1536,48.5949],[-97.1535,48.5957],[-97.1527,48.5962],[-97.1524,48.5969],[-97.1516,48.598],[-97.1498,48.5981],[-97.1497,48.5981],[-97.1463,48.5977],[-97.1443,48.5981],[-97.143,48.5987],[-97.1416,48.6002],[-97.1403,48.6021],[-97.14,48.6025],[-97.138,48.6044],[-97.1359,48.6054],[-97.1345,48.6065],[-97.1341,48.6075],[-97.1349,48.6082],[-97.1358,48.6086],[-97.137,48.6088],[-97.1396,48.6086],[-97.1443,48.6078],[-97.1474,48.6081],[-97.1494,48.6089],[-97.1495,48.609],[-97.1505,48.6115],[-97.1501,48.6124],[-97.1493,48.6129],[-97.1478,48.6138],[-97.145,48.6146],[-97.1408,48.6149],[-97.137,48.6144],[-97.134,48.6136],[-97.1319,48.6133],[-97.1309,48.6137],[-97.1289,48.614],[-97.1286,48.6153],[-97.1293,48.6168],[-97.1295,48.617],[-97.1311,48.6184],[-97.1342,48.6199],[-97.1353,48.6212],[-97.1346,48.6224],[-97.133,48.6228],[-97.131,48.6227],[-97.1291,48.6222],[-97.1277,48.6212],[-97.1274,48.621],[-97.1259,48.6195],[-97.1253,48.619],[-97.1243,48.6183],[-97.1231,48.6178],[-97.1216,48.6176],[-97.12,48.6178],[-97.1193,48.6182],[-97.1186,48.6191],[-97.1183,48.6198],[-97.1186,48.6209],[-97.1198,48.6221],[-97.1209,48.6232],[-97.1212,48.6233],[-97.122,48.624],[-97.1228,48.6245],[-97.1236,48.625],[-97.1241,48.6254],[-97.1245,48.6257],[-97.1249,48.6259],[-97.1253,48.6261],[-97.126,48.6264],[-97.1266,48.6266],[-97.1272,48.627],[-97.1279,48.6273],[-97.1288,48.6278],[-97.1296,48.6282],[-97.1302,48.6288],[-97.1305,48.6292],[-97.1307,48.6297],[-97.131,48.6303],[-97.131,48.6304],[-97.131,48.6308],[-97.131,48.6315],[-97.1309,48.6317],[-97.1307,48.6321],[-97.1304,48.6325],[-97.1301,48.6326],[-97.1297,48.6328],[-97.1293,48.6329],[-97.129,48.633],[-97.1281,48.6332],[-97.128,48.6333],[-97.1275,48.6333],[-97.1253,48.6334],[-97.1235,48.6333],[-97.1216,48.6327],[-97.1181,48.6308],[-97.1176,48.6307],[-97.115,48.6299],[-97.1133,48.63],[-97.1115,48.6303],[-97.1107,48.6308],[-97.1104,48.6309],[-97.1095,48.6315],[-97.1084,48.6327],[-97.1082,48.6344],[-97.1086,48.6363],[-97.1096,48.6389],[-97.1109,48.6407],[-97.1119,48.6416],[-97.1144,48.6433],[-97.115,48.6438],[-97.115,48.6446],[-97.1149,48.6452],[-97.1123,48.6457],[-97.1112,48.6459],[-97.1093,48.6465],[-97.1078,48.6478],[-97.1069,48.6491],[-97.1066,48.6501],[-97.1061,48.6519],[-97.1059,48.6527],[-97.1045,48.6545],[-97.1017,48.6563],[-97.0987,48.6593],[-97.0986,48.6604],[-97.0985,48.6613],[-97.0992,48.6625],[-97.1019,48.6636],[-97.106,48.663],[-97.1062,48.663],[-97.1082,48.6634],[-97.1087,48.6645],[-97.1061,48.6654],[-97.1057,48.6655],[-97.102,48.6667],[-97.1,48.668],[-97.0998,48.6714],[-97.1002,48.675],[-97.1003,48.6757],[-97.1008,48.6787],[-97.1011,48.6808],[-97.1003,48.6828],[-97.0985,48.683],[-97.0946,48.6822],[-97.0926,48.6821],[-97.0904,48.6828],[-97.0898,48.6841],[-97.0899,48.6852],[-97.091,48.6861],[-97.093,48.687],[-97.0951,48.6876],[-97.099,48.6884],[-97.1024,48.6893],[-97.103,48.6894],[-97.1059,48.6903],[-97.1064,48.6905],[-97.1086,48.6915],[-97.111,48.6939],[-97.113,48.6964],[-97.1148,48.6981],[-97.1182,48.7005],[-97.1198,48.7018],[-97.1201,48.7039],[-97.1194,48.7041],[-97.1182,48.7046],[-97.1143,48.7052],[-97.1117,48.7056],[-97.11,48.7063],[-97.1098,48.7083],[-97.1113,48.7094],[-97.1134,48.7101],[-97.1157,48.7105],[-97.1174,48.7111],[-97.119,48.7119],[-97.1212,48.7136],[-97.1223,48.716],[-97.1229,48.7168],[-97.1231,48.7172],[-97.1243,48.7192],[-97.1253,48.7201],[-97.1253,48.7203],[-97.126,48.7207],[-97.1263,48.7212],[-97.1272,48.7215],[-97.128,48.722],[-97.1282,48.7221],[-97.1288,48.7225],[-97.1297,48.7229],[-97.131,48.7233],[-97.1321,48.7238],[-97.1331,48.7242],[-97.1345,48.7248],[-97.136,48.7257],[-97.1369,48.7263],[-97.1375,48.727],[-97.1376,48.7274],[-97.1376,48.7278],[-97.1373,48.7283],[-97.137,48.7284],[-97.1365,48.7285],[-97.136,48.7287],[-97.1352,48.7287],[-97.1341,48.7289],[-97.1333,48.7291],[-97.1328,48.7292],[-97.132,48.7294],[-97.1312,48.7295],[-97.1308,48.7296],[-97.1299,48.7299],[-97.1294,48.7304],[-97.1288,48.7308],[-97.1286,48.7312],[-97.1286,48.7315],[-97.1286,48.7316],[-97.1286,48.7318],[-97.1285,48.7322],[-97.1286,48.7326],[-97.1286,48.7328],[-97.1287,48.7331],[-97.129,48.7335],[-97.1295,48.7339],[-97.1298,48.7341],[-97.1316,48.7347],[-97.1322,48.7348],[-97.1334,48.7347],[-97.1351,48.7345],[-97.1369,48.7345],[-97.1383,48.7345],[-97.1396,48.7347],[-97.1402,48.7349],[-97.1412,48.7354],[-97.1419,48.7359],[-97.1422,48.7367],[-97.1423,48.7372],[-97.1421,48.7381],[-97.1414,48.7385],[-97.1408,48.7387],[-97.1404,48.7389],[-97.1399,48.7393],[-97.1392,48.7397],[-97.1381,48.7408],[-97.1372,48.742],[-97.1366,48.7435],[-97.1365,48.745],[-97.1365,48.7459],[-97.1366,48.7466],[-97.1369,48.748],[-97.1375,48.7492],[-97.1379,48.75],[-97.1385,48.7504],[-97.1391,48.7507],[-97.1396,48.7508],[-97.1401,48.7509],[-97.141,48.751],[-97.142,48.751],[-97.143,48.7509],[-97.1444,48.7507],[-97.1457,48.7506],[-97.1466,48.7505],[-97.1476,48.7505],[-97.1491,48.7506],[-97.1497,48.7508],[-97.1503,48.7509],[-97.1515,48.7515],[-97.1521,48.752],[-97.153,48.7529],[-97.1539,48.7542],[-97.1545,48.7553],[-97.1547,48.7558],[-97.1548,48.7562],[-97.1548,48.7569],[-97.1548,48.7576],[-97.1546,48.758],[-97.1542,48.7587],[-97.1535,48.7593],[-97.1528,48.7598],[-97.1519,48.7601],[-97.1508,48.7605],[-97.1503,48.7606],[-97.1501,48.7607],[-97.1475,48.7616],[-97.1473,48.7617],[-97.1469,48.762],[-97.1462,48.7626],[-97.1461,48.7628],[-97.1459,48.7633],[-97.1456,48.7643],[-97.1456,48.765],[-97.146,48.7658],[-97.1476,48.7673],[-97.1487,48.7681],[-97.15,48.7692],[-97.1501,48.7693],[-97.1506,48.77],[-97.1512,48.7712],[-97.1519,48.7721],[-97.1525,48.7727],[-97.1529,48.7728],[-97.1559,48.7731],[-97.1567,48.7732],[-97.1578,48.7735],[-97.1582,48.7737],[-97.1587,48.7742],[-97.1589,48.7746],[-97.159,48.7751],[-97.159,48.7751],[-97.159,48.7754],[-97.1589,48.776],[-97.1584,48.7766],[-97.1579,48.7769],[-97.1573,48.7772],[-97.1557,48.7776],[-97.1544,48.7778],[-97.1534,48.778],[-97.1522,48.7783],[-97.1509,48.7787],[-97.1501,48.7789],[-97.1497,48.779],[-97.1483,48.7797],[-97.1477,48.7801],[-97.1473,48.7807],[-97.1472,48.7811],[-97.1473,48.7816],[-97.1478,48.7821],[-97.1486,48.7824],[-97.1495,48.7826],[-97.1501,48.7826],[-97.1503,48.7826],[-97.1513,48.7825],[-97.1533,48.7824],[-97.1547,48.7824],[-97.1559,48.7825],[-97.1571,48.7827],[-97.1583,48.783],[-97.1591,48.7834],[-97.1595,48.7838],[-97.1597,48.7843],[-97.1598,48.7848],[-97.1596,48.7853],[-97.1593,48.786],[-97.1591,48.7863],[-97.1586,48.7869],[-97.1577,48.7877],[-97.1574,48.7882],[-97.1573,48.7884],[-97.1572,48.7887],[-97.1571,48.7894],[-97.157,48.7895],[-97.157,48.7901],[-97.1572,48.7906],[-97.1575,48.7909],[-97.1581,48.7912],[-97.1586,48.7913],[-97.1592,48.7915],[-97.1595,48.7915],[-97.1611,48.7915],[-97.1618,48.7914],[-97.1645,48.7911],[-97.1648,48.7911],[-97.1657,48.7911],[-97.1664,48.7912],[-97.1672,48.7913],[-97.1714,48.7921],[-97.1718,48.7923],[-97.1721,48.7924],[-97.1731,48.7929],[-97.1737,48.7933],[-97.174,48.7937],[-97.1741,48.7942],[-97.1742,48.7947],[-97.1742,48.7951],[-97.1739,48.7954],[-97.1734,48.7958],[-97.1726,48.7963],[-97.1717,48.7966],[-97.1716,48.7966],[-97.171,48.7967],[-97.1701,48.7967],[-97.1688,48.7966],[-97.1673,48.7964],[-97.1665,48.7962],[-97.1654,48.7962],[-97.1648,48.7962],[-97.1638,48.7963],[-97.1631,48.7966],[-97.1625,48.7969],[-97.162,48.7974],[-97.1617,48.7979],[-97.1617,48.7984],[-97.1619,48.7988],[-97.1621,48.7994],[-97.1626,48.8001],[-97.1633,48.8007],[-97.1642,48.8011],[-97.1652,48.8014],[-97.166,48.8015],[-97.1668,48.8016],[-97.1675,48.8016],[-97.1685,48.8016],[-97.1698,48.8013],[-97.1706,48.8011],[-97.1714,48.8008],[-97.1715,48.8008],[-97.1724,48.8004],[-97.1731,48.8],[-97.1742,48.7992],[-97.175,48.7986],[-97.1754,48.7983],[-97.1757,48.798],[-97.1761,48.7977],[-97.1768,48.7974],[-97.1773,48.7973],[-97.1779,48.7972],[-97.1787,48.7972],[-97.1795,48.7972],[-97.1801,48.7973],[-97.1807,48.7975],[-97.1811,48.7978],[-97.1815,48.7982],[-97.1816,48.7986],[-97.1817,48.7991],[-97.1815,48.7995],[-97.1813,48.8],[-97.1808,48.8004],[-97.1801,48.8008],[-97.1791,48.8012],[-97.1779,48.8015],[-97.1769,48.8017],[-97.1764,48.8018],[-97.1756,48.8021],[-97.1748,48.8023],[-97.1725,48.8032],[-97.1713,48.8036],[-97.171,48.8037],[-97.1706,48.8039],[-97.1694,48.8043],[-97.1682,48.8046],[-97.1675,48.8048],[-97.1666,48.805],[-97.1655,48.8052],[-97.1638,48.8055],[-97.161,48.8059],[-97.1605,48.8061],[-97.1597,48.8064],[-97.159,48.8067],[-97.1583,48.8072],[-97.1579,48.8077],[-97.1577,48.8082],[-97.1576,48.8089],[-97.1578,48.8098],[-97.158,48.8104],[-97.1586,48.811],[-97.159,48.8111],[-97.161,48.8117],[-97.1617,48.8119],[-97.1625,48.812],[-97.1636,48.8121],[-97.1644,48.8121],[-97.1651,48.812],[-97.1666,48.8118],[-97.168,48.8116],[-97.169,48.8114],[-97.17,48.8114],[-97.1713,48.8115],[-97.1715,48.8115],[-97.1726,48.8117],[-97.1731,48.8118],[-97.174,48.8122],[-97.1761,48.8132],[-97.1776,48.8141],[-97.1784,48.8145],[-97.1797,48.8149],[-97.1807,48.8151],[-97.1821,48.8153],[-97.1828,48.8153],[-97.184,48.8152],[-97.1848,48.8151],[-97.186,48.8147],[-97.1868,48.8145],[-97.1873,48.8143],[-97.1879,48.8143],[-97.1883,48.8143],[-97.1889,48.8143],[-97.1894,48.8144],[-97.1898,48.8146],[-97.1901,48.8148],[-97.1903,48.8153],[-97.1904,48.8156],[-97.1903,48.8159],[-97.19,48.8163],[-97.1893,48.8167],[-97.1885,48.8171],[-97.1879,48.8173],[-97.1866,48.8176],[-97.1857,48.8177],[-97.1847,48.8179],[-97.184,48.8181],[-97.1833,48.8184],[-97.1817,48.8189],[-97.1809,48.8193],[-97.1801,48.8199],[-97.1793,48.8207],[-97.1787,48.8216],[-97.178,48.8232],[-97.1777,48.824],[-97.1776,48.8245],[-97.1777,48.8249],[-97.178,48.8255],[-97.1782,48.8258],[-97.1786,48.8262],[-97.1794,48.8268],[-97.1822,48.8288],[-97.1837,48.8299],[-97.1841,48.8304],[-97.1847,48.8314],[-97.1848,48.8319],[-97.1849,48.8326],[-97.1849,48.8327],[-97.1848,48.833],[-97.1846,48.8336],[-97.1842,48.8341],[-97.1837,48.8345],[-97.183,48.8348],[-97.1822,48.835],[-97.1813,48.8351],[-97.1799,48.8352],[-97.1783,48.8353],[-97.1779,48.8354],[-97.1772,48.8356],[-97.1757,48.8362],[-97.1753,48.8364],[-97.1747,48.8369],[-97.1742,48.8373],[-97.1739,48.8378],[-97.1738,48.8384],[-97.1738,48.839],[-97.1739,48.8406],[-97.1743,48.8427],[-97.1747,48.8438],[-97.175,48.8442],[-97.1755,48.8447],[-97.1761,48.8452],[-97.1767,48.8455],[-97.1771,48.8456],[-97.1779,48.8458],[-97.1795,48.8459],[-97.1808,48.846],[-97.1817,48.8462],[-97.1823,48.8464],[-97.1827,48.8468],[-97.1829,48.847],[-97.1829,48.8471],[-97.1829,48.8473],[-97.1826,48.8476],[-97.1821,48.8479],[-97.1816,48.848],[-97.1809,48.8481],[-97.1793,48.8482],[-97.178,48.8483],[-97.1767,48.8484],[-97.1759,48.8486],[-97.1753,48.8487],[-97.1747,48.849],[-97.1742,48.8493],[-97.1737,48.8497],[-97.1733,48.8502],[-97.173,48.8506],[-97.173,48.8508],[-97.173,48.8511],[-97.173,48.8516],[-97.1732,48.8522],[-97.1737,48.8527],[-97.1746,48.8534],[-97.1771,48.855],[-97.1784,48.8561],[-97.1786,48.8563],[-97.179,48.8569],[-97.1793,48.8576],[-97.1794,48.8583],[-97.1794,48.859],[-97.1792,48.8606],[-97.179,48.8615],[-97.179,48.862],[-97.1791,48.8626],[-97.1794,48.863],[-97.1801,48.8636],[-97.1811,48.864],[-97.1818,48.8641],[-97.1827,48.8641],[-97.1839,48.864],[-97.1855,48.8637],[-97.1871,48.8633],[-97.1877,48.8631],[-97.1883,48.8631],[-97.1891,48.8631],[-97.1896,48.8633],[-97.19,48.8635],[-97.1903,48.8639],[-97.1905,48.8644],[-97.1905,48.8648],[-97.1904,48.8651],[-97.1901,48.8657],[-97.1899,48.8661],[-97.1895,48.8665],[-97.189,48.867],[-97.1884,48.8675],[-97.1851,48.8694],[-97.1813,48.8718],[-97.1788,48.8736],[-97.1785,48.8738],[-97.1782,48.8741],[-97.1781,48.8743],[-97.1779,48.8745],[-97.1778,48.8747],[-97.1777,48.8749],[-97.1777,48.875],[-97.1778,48.875],[-97.1778,48.8754],[-97.1779,48.8757],[-97.1782,48.8761],[-97.1786,48.8765],[-97.1792,48.8769],[-97.1798,48.8771],[-97.1808,48.8772],[-97.1823,48.8772],[-97.1852,48.8768],[-97.1869,48.8765],[-97.1881,48.8765],[-97.1891,48.8766],[-97.1904,48.8769],[-97.1933,48.8779],[-97.1944,48.8783],[-97.1957,48.8788],[-97.1972,48.8794],[-97.1981,48.8799],[-97.1988,48.8805],[-97.1995,48.8812],[-97.1999,48.8818],[-97.1999,48.8821],[-97.2,48.8827],[-97.1998,48.8832],[-97.1997,48.8836],[-97.199,48.8845],[-97.1978,48.8859],[-97.1975,48.8865],[-97.1974,48.8868],[-97.1973,48.8872],[-97.1973,48.8874],[-97.1974,48.8877],[-97.1975,48.8881],[-97.1983,48.8889],[-97.2002,48.8903],[-97.2004,48.8904],[-97.2009,48.8908],[-97.2014,48.8912],[-97.2017,48.8915],[-97.2017,48.8919],[-97.2016,48.8922],[-97.2013,48.8925],[-97.201,48.8926],[-97.2001,48.8926],[-97.1994,48.8926],[-97.1985,48.8925],[-97.198,48.8924],[-97.1973,48.892],[-97.1957,48.8916],[-97.1946,48.8915],[-97.1944,48.8914],[-97.1937,48.8914],[-97.1927,48.8915],[-97.1921,48.8917],[-97.1916,48.8919],[-97.1905,48.8926],[-97.1901,48.8932],[-97.1898,48.8938],[-97.1897,48.8944],[-97.1897,48.8947],[-97.1898,48.8951],[-97.1899,48.8954],[-97.1903,48.896],[-97.1911,48.8967],[-97.1919,48.8974],[-97.1925,48.8979],[-97.1935,48.8985],[-97.1941,48.8988],[-97.1945,48.8989],[-97.1966,48.8997],[-97.1992,48.9004],[-97.2009,48.9009],[-97.2022,48.9013],[-97.2048,48.9018],[-97.2055,48.902],[-97.207,48.9025],[-97.2076,48.9027],[-97.2082,48.9029],[-97.2088,48.9032],[-97.2093,48.9036],[-97.21,48.904],[-97.2105,48.9044],[-97.211,48.905],[-97.2114,48.9056],[-97.2122,48.9069],[-97.2125,48.9075],[-97.2127,48.9082],[-97.2127,48.909],[-97.2125,48.9099],[-97.212,48.911],[-97.2116,48.9121],[-97.2111,48.913],[-97.2108,48.914],[-97.2106,48.9148],[-97.2106,48.9153],[-97.2109,48.9162],[-97.2111,48.9167],[-97.2115,48.9172],[-97.2118,48.9175],[-97.2122,48.9177],[-97.2129,48.9181],[-97.2149,48.9187],[-97.2163,48.9191],[-97.2164,48.9191],[-97.2171,48.9194],[-97.2179,48.9198],[-97.2189,48.9205],[-97.2196,48.9215],[-97.2198,48.9222],[-97.2199,48.923],[-97.2197,48.9237],[-97.2191,48.9249],[-97.2183,48.9262],[-97.2172,48.9277],[-97.2163,48.9286],[-97.2159,48.9289],[-97.2149,48.9301],[-97.2146,48.9304],[-97.2145,48.9307],[-97.2144,48.931],[-97.2145,48.9314],[-97.2145,48.9316],[-97.2148,48.9319],[-97.2154,48.9325],[-97.2159,48.9327],[-97.2162,48.9328],[-97.217,48.9328],[-97.2181,48.9327],[-97.2198,48.9325],[-97.2208,48.9325],[-97.2214,48.9325],[-97.2218,48.9326],[-97.2237,48.9332],[-97.2245,48.9337],[-97.2249,48.9339],[-97.225,48.934],[-97.2252,48.9342],[-97.2254,48.9345],[-97.2257,48.9349],[-97.226,48.9353],[-97.2263,48.936],[-97.2267,48.9376],[-97.227,48.9389],[-97.2271,48.9398],[-97.2271,48.941],[-97.227,48.9418],[-97.2266,48.9432],[-97.2264,48.9441],[-97.2263,48.9445],[-97.2264,48.9452],[-97.2265,48.9456],[-97.227,48.9462],[-97.2273,48.9465],[-97.2276,48.9467],[-97.2279,48.9467],[-97.2284,48.9468],[-97.2304,48.9465],[-97.2309,48.9464],[-97.2313,48.9464],[-97.2326,48.9466],[-97.2331,48.9468],[-97.2338,48.9471],[-97.2342,48.9474],[-97.2343,48.948],[-97.2343,48.9485],[-97.2342,48.9488],[-97.2341,48.9491],[-97.2337,48.95],[-97.2332,48.951],[-97.2328,48.9524],[-97.2323,48.954],[-97.2317,48.9558],[-97.2313,48.9568],[-97.2309,48.9578],[-97.2305,48.9585],[-97.23,48.9591],[-97.2288,48.9603],[-97.2282,48.9609],[-97.2278,48.9613],[-97.2276,48.9619],[-97.2276,48.9624],[-97.2279,48.963],[-97.228,48.9631],[-97.2283,48.9634],[-97.2289,48.9639],[-97.2294,48.9641],[-97.23,48.9642],[-97.2323,48.9646],[-97.2355,48.965],[-97.2368,48.9652],[-97.2375,48.9654],[-97.2382,48.966],[-97.2383,48.9661],[-97.2388,48.9666],[-97.2391,48.9676],[-97.2392,48.9687],[-97.239,48.9696],[-97.2387,48.9706],[-97.2383,48.9715],[-97.2381,48.9723],[-97.238,48.9725],[-97.2379,48.9731],[-97.2378,48.9734],[-97.2378,48.9738],[-97.238,48.9752],[-97.238,48.9763],[-97.2381,48.9771],[-97.238,48.9771],[-97.238,48.9841],[-97.2377,48.9849],[-97.2372,48.9857],[-97.2365,48.9867],[-97.2359,48.9874],[-97.2351,48.9881],[-97.2342,48.989],[-97.2335,48.9895],[-97.2331,48.9898],[-97.2317,48.9904],[-97.2301,48.9911],[-97.2293,48.9914],[-97.229,48.9916],[-97.2279,48.9921],[-97.2274,48.9925],[-97.227,48.9929],[-97.2266,48.9933],[-97.2265,48.9938],[-97.2267,48.9941],[-97.227,48.9945],[-97.2273,48.9947],[-97.2287,48.9949],[-97.2304,48.995],[-97.2317,48.9951],[-97.2324,48.9952],[-97.2335,48.9956],[-97.2338,48.9959],[-97.2341,48.9966],[-97.2341,48.997],[-97.234,48.9975],[-97.2337,48.9981],[-97.2332,48.9985],[-97.2323,48.999],[-97.2305,49.0],[-97.2303,49.0001],[-97.2295,49.0005],[-97.2175,49.0005],[-97.2161,49.0005],[-97.2078,49.0005],[-97.2069,49.0005],[-97.1955,49.0005],[-97.1939,49.0005],[-97.1739,49.0005],[-97.1724,49.0005],[-97.1514,49.0005],[-97.1502,49.0005],[-97.1294,49.0004],[-97.1277,49.0004],[-97.1073,49.0004],[-97.1061,49.0004],[-97.0853,49.0004],[-97.084,49.0004],[-97.0633,49.0004],[-97.062,49.0004],[-97.0412,49.0004],[-97.0401,49.0004],[-97.0192,49.0004],[-97.0183,49.0004],[-96.9971,49.0004],[-96.9961,49.0004],[-96.9751,49.0003],[-96.9738,49.0003],[-96.953,49.0003],[-96.9518,49.0003],[-96.931,49.0003],[-96.9299,49.0003],[-96.909,49.0003],[-96.9078,49.0003],[-96.8869,49.0003],[-96.8856,49.0003],[-96.8649,49.0003],[-96.864,49.0003],[-96.8429,49.0003],[-96.8415,49.0003],[-96.8208,49.0003],[-96.8197,49.0003],[-96.8023,49.0002],[-96.8005,49.0002],[-96.8003,49.0002],[-96.7988,49.0002],[-96.7787,49.0002],[-96.7768,49.0002],[-96.7567,49.0002],[-96.7547,49.0002],[-96.7348,49.0002],[-96.7327,49.0002],[-96.7127,49.0002],[-96.7107,49.0002],[-96.6905,49.0002],[-96.6886,49.0002],[-96.6695,49.0002],[-96.6665,49.0002],[-96.6482,49.0002],[-96.6445,49.0002],[-96.6243,49.0002],[-96.6225,49.0002],[-96.6021,49.0002],[-96.6004,49.0002],[-96.58,49.0002],[-96.5784,49.0002],[-96.558,49.0002],[-96.5563,49.0002],[-96.536,49.0002],[-96.5342,49.0002],[-96.5154,49.0002],[-96.5123,49.0002],[-96.4933,49.0002],[-96.49,49.0002],[-96.471,49.0001],[-96.4664,49.0001],[-96.4496,49.0001],[-96.4492,49.0001],[-96.4491,49.0001],[-96.446,49.0001],[-96.4273,49.0001],[-96.4224,49.0001],[-96.4054,49.0001]]],"type":"Polygon"},"id":"35","properties":{"Area":2862183702.23055,"CTYONLY_":3,"Code":"KITT","LASTMOD":"1999-12-31T23:59:59Z","Name":"Kittson","Perimiter":263017.48277},"type":"Feature"},{"geometry":{"coordinates":[[[-96.4054,49.0001],[-96.4019,49.0001],[-96.3825,49.0001],[-96.3783,49.0001],[-96.3606,49.0001],[-96.3579,49.0001],[-96.3385,49.0001],[-96.3343,49.0001],[-96.3166,49.0001],[-96.3138,49.0001],[-96.2945,49.0001],[-96.2902,49.0001],[-96.2725,49.0001],[-96.2698,49.0001],[-96.2494,49.0001],[-96.2461,49.0001],[-96.2274,49.0001],[-96.2257,49.0001],[-96.2057,49.0001],[-96.2021,49.0001],[-96.1837,49.0],[-96.18,49.0],[-96.1617,49.0],[-96.1579,49.0],[-96.1401,49.0],[-96.1359,49.0],[-96.1176,49.0],[-96.1139,49.0],[-96.0957,49.0],[-96.0919,49.0],[-96.0738,49.0],[-96.07,49.0],[-96.0517,49.0],[-96.048,49.0],[-96.0298,49.0],[-96.026,49.0],[-96.0083,49.0],[-96.0045,49.0],[-95.9868,49.0],[-95.9784,49.0],[-95.9776,49.0],[-95.9755,49.0],[-95.9648,48.9999],[-95.9464,48.9999],[-95.943,48.9999],[-95.9225,48.9999],[-95.9211,48.9999],[-95.899,48.9998],[-95.883,48.9998],[-95.8771,48.9998],[-95.8564,48.9998],[-95.855,48.9998],[-95.8342,48.9998],[-95.8184,48.9997],[-95.8126,48.9997],[-95.7906,48.9997],[-95.7833,48.9997],[-95.7684,48.9997],[-95.7479,48.9996],[-95.7466,48.9996],[-95.7253,48.9996],[-95.7066,48.9996],[-95.7032,48.9996],[-95.681,48.9995],[-95.6654,48.9995],[-95.6596,48.9995],[-95.659,48.9995],[-95.6401,48.9995],[-95.6369,48.9995],[-95.6205,48.9994],[-95.615,48.9994],[-95.5948,48.9994],[-95.585,48.9994],[-95.573,48.9994],[-95.551,48.9993],[-95.5495,48.9993],[-95.5294,48.9993],[-95.5164,48.9993],[-95.5072,48.9993],[-95.4849,48.9992],[-95.4834,48.9992],[-95.4635,48.9992],[-95.4508,48.9992],[-95.4418,48.9992],[-95.4245,48.9991],[-95.4197,48.9991],[-95.3977,48.9991],[-95.3953,48.9991],[-95.3765,48.9991],[-95.3759,48.9991],[-95.3753,48.9991],[-95.3542,48.999],[-95.3513,48.999],[-95.3326,48.999],[-95.3286,48.999],[-95.3231,48.999],[-95.3224,48.9984],[-95.3204,48.9976],[-95.3202,48.9973],[-95.3204,48.9964],[-95.3206,48.9961],[-95.3201,48.9956],[-95.3197,48.9954],[-95.3191,48.9953],[-95.3187,48.9956],[-95.3182,48.996],[-95.3179,48.9961],[-95.3178,48.9961],[-95.3178,48.9958],[-95.3181,48.995],[-95.3191,48.9941],[-95.3204,48.9924],[-95.3206,48.9921],[-95.3224,48.9889],[-95.3227,48.9884],[-95.3242,48.9859],[-95.3245,48.985],[-95.3253,48.9832],[-95.3257,48.9814],[-95.3256,48.98],[-95.3255,48.9789],[-95.3257,48.9784],[-95.3253,48.976],[-95.325,48.9743],[-95.3249,48.9738],[-95.3248,48.9728],[-95.3247,48.972],[-95.3241,48.9703],[-95.3232,48.9692],[-95.3227,48.9685],[-95.3212,48.9672],[-95.3207,48.9669],[-95.3201,48.9648],[-95.3198,48.9643],[-95.3193,48.964],[-95.3193,48.9622],[-95.3202,48.9606],[-95.3206,48.9598],[-95.3206,48.9595],[-95.3206,48.959],[-95.3202,48.9581],[-95.3191,48.9569],[-95.3188,48.9562],[-95.3179,48.9559],[-95.3175,48.9552],[-95.3177,48.9545],[-95.3182,48.9535],[-95.3181,48.9531],[-95.3177,48.9525],[-95.3154,48.9513],[-95.3151,48.951],[-95.3141,48.9508],[-95.3131,48.9503],[-95.3125,48.9503],[-95.3123,48.9502],[-95.3119,48.9502],[-95.3119,48.9507],[-95.3129,48.9521],[-95.3129,48.9523],[-95.3126,48.9524],[-95.312,48.9524],[-95.3115,48.952],[-95.3108,48.9512],[-95.3104,48.951],[-95.3097,48.951],[-95.3089,48.9511],[-95.3079,48.9509],[-95.3061,48.9502],[-95.3052,48.9495],[-95.3046,48.9482],[-95.3046,48.947],[-95.305,48.9462],[-95.3053,48.9459],[-95.3061,48.9454],[-95.3068,48.9454],[-95.3069,48.9455],[-95.3069,48.9456],[-95.3063,48.9462],[-95.3062,48.9463],[-95.3061,48.9469],[-95.3062,48.9472],[-95.3062,48.9472],[-95.3071,48.9477],[-95.3081,48.948],[-95.3094,48.9481],[-95.3096,48.9482],[-95.3099,48.9484],[-95.31,48.9485],[-95.3103,48.9485],[-95.3104,48.9484],[-95.3103,48.948],[-95.3096,48.9478],[-95.3092,48.9477],[-95.3079,48.9474],[-95.3071,48.9469],[-95.3071,48.9466],[-95.3074,48.9465],[-95.3078,48.9466],[-95.3085,48.947],[-95.3086,48.9469],[-95.3086,48.9465],[-95.3088,48.9464],[-95.3095,48.9463],[-95.3102,48.9463],[-95.3114,48.9461],[-95.3131,48.946],[-95.3141,48.9457],[-95.3148,48.9452],[-95.3154,48.9448],[-95.3168,48.9431],[-95.3181,48.9421],[-95.3189,48.9419],[-95.3219,48.9412],[-95.3225,48.9409],[-95.3228,48.9403],[-95.3231,48.9389],[-95.3229,48.9373],[-95.3225,48.9358],[-95.3223,48.9355],[-95.3228,48.9344],[-95.3222,48.9327],[-95.3209,48.9307],[-95.3208,48.9305],[-95.3195,48.9285],[-95.3168,48.9245],[-95.315,48.9222],[-95.3141,48.921],[-95.3132,48.9198],[-95.3126,48.919],[-95.3119,48.9178],[-95.3115,48.9172],[-95.3109,48.9163],[-95.3102,48.9155],[-95.3093,48.9149],[-95.3092,48.9149],[-95.3085,48.9146],[-95.3078,48.9141],[-95.3074,48.9135],[-95.3064,48.9129],[-95.3061,48.9128],[-95.3059,48.9127],[-95.3043,48.9119],[-95.3038,48.9114],[-95.3027,48.91],[-95.3017,48.9093],[-95.2999,48.9086],[-95.2978,48.9083],[-95.2973,48.9081],[-95.2973,48.908],[-95.2973,48.9077],[-95.2976,48.9074],[-95.2977,48.9073],[-95.2978,48.9073],[-95.2978,48.9072],[-95.2978,48.9072],[-95.2979,48.9072],[-95.2979,48.9072],[-95.2979,48.9071],[-95.298,48.9071],[-95.298,48.9071],[-95.298,48.9071],[-95.2981,48.907],[-95.2982,48.9068],[-95.2983,48.9068],[-95.2985,48.9065],[-95.2985,48.9064],[-95.2986,48.9063],[-95.2988,48.906],[-95.2989,48.906],[-95.2991,48.9057],[-95.2992,48.9055],[-95.2994,48.9053],[-95.2996,48.9051],[-95.2997,48.905],[-95.2999,48.9048],[-95.2999,48.9048],[-95.2999,48.9048],[-95.3,48.9047],[-95.3,48.9047],[-95.3001,48.9047],[-95.3001,48.9046],[-95.3002,48.9045],[-95.3005,48.904],[-95.2993,48.9035],[-95.2983,48.9028],[-95.298,48.9027],[-95.2976,48.9026],[-95.2967,48.9027],[-95.2949,48.9028],[-95.2941,48.9027],[-95.2937,48.9023],[-95.2935,48.902],[-95.2927,48.9019],[-95.2914,48.9019],[-95.2909,48.9017],[-95.2908,48.9016],[-95.2907,48.9014],[-95.2906,48.9011],[-95.2911,48.9008],[-95.2911,48.9006],[-95.2901,48.9003],[-95.2896,48.9],[-95.289,48.8994],[-95.2882,48.8981],[-95.2879,48.8979],[-95.2872,48.8977],[-95.287,48.8976],[-95.2865,48.8975],[-95.2861,48.8976],[-95.2853,48.8977],[-95.2839,48.8975],[-95.2813,48.8967],[-95.2803,48.8965],[-95.2796,48.8962],[-95.279,48.8957],[-95.2782,48.8956],[-95.2773,48.8957],[-95.277,48.8958],[-95.2765,48.8962],[-95.2763,48.8963],[-95.2759,48.8962],[-95.2755,48.8959],[-95.2749,48.8956],[-95.2748,48.8951],[-95.2753,48.8943],[-95.2751,48.8938],[-95.2745,48.8931],[-95.2724,48.8921],[-95.2713,48.8915],[-95.268,48.8905],[-95.2677,48.8903],[-95.2674,48.89],[-95.2666,48.8894],[-95.2654,48.8888],[-95.265,48.8886],[-95.2646,48.8885],[-95.2639,48.8883],[-95.2635,48.888],[-95.2627,48.8877],[-95.2585,48.8867],[-95.2585,48.8867],[-95.257,48.8858],[-95.256,48.885],[-95.2548,48.8845],[-95.2517,48.8839],[-95.2507,48.8836],[-95.2502,48.8835],[-95.2496,48.8834],[-95.2485,48.8832],[-95.248,48.8836],[-95.2472,48.8835],[-95.2458,48.8829],[-95.2439,48.8823],[-95.2429,48.8822],[-95.2429,48.8822],[-95.2423,48.8821],[-95.2407,48.8821],[-95.2391,48.8819],[-95.2381,48.8817],[-95.2356,48.8815],[-95.2335,48.8814],[-95.231,48.8814],[-95.2287,48.8815],[-95.2265,48.8816],[-95.2252,48.8819],[-95.2212,48.883],[-95.2208,48.8831],[-95.2207,48.8831],[-95.22,48.8831],[-95.2193,48.8832],[-95.2188,48.8835],[-95.217,48.8835],[-95.2159,48.8839],[-95.2151,48.884],[-95.2144,48.8843],[-95.2122,48.8842],[-95.2117,48.8847],[-95.2115,48.8847],[-95.2112,48.8848],[-95.2085,48.8846],[-95.2059,48.8848],[-95.2024,48.8852],[-95.2009,48.8855],[-95.2005,48.8856],[-95.1986,48.8855],[-95.1956,48.8862],[-95.1924,48.8865],[-95.1919,48.8866],[-95.1913,48.8868],[-95.1901,48.887],[-95.1889,48.8873],[-95.1877,48.8874],[-95.1863,48.8877],[-95.1851,48.8882],[-95.1819,48.8888],[-95.1797,48.889],[-95.1791,48.889],[-95.1764,48.8893],[-95.173,48.8897],[-95.1701,48.8902],[-95.1674,48.8907],[-95.1648,48.8913],[-95.1641,48.8917],[-95.1618,48.892],[-95.1602,48.892],[-95.1579,48.8919],[-95.1564,48.8919],[-95.1555,48.892],[-95.1528,48.8921],[-95.1508,48.8922],[-95.1483,48.8923],[-95.1469,48.8927],[-95.1459,48.8929],[-95.1438,48.8934],[-95.1436,48.8937],[-95.1404,48.8943],[-95.1381,48.8949],[-95.1355,48.8959],[-95.1351,48.8963],[-95.1348,48.8963],[-95.1343,48.8963],[-95.1337,48.8969],[-95.1322,48.8973],[-95.1312,48.8975],[-95.1252,48.8998],[-95.1239,48.9001],[-95.1233,48.9004],[-95.1228,48.9006],[-95.1214,48.9013],[-95.121,48.9016],[-95.1205,48.9017],[-95.1204,48.9019],[-95.1182,48.9029],[-95.1163,48.9037],[-95.1151,48.9046],[-95.1144,48.9052],[-95.114,48.9061],[-95.1141,48.9064],[-95.1137,48.9069],[-95.1132,48.9071],[-95.113,48.9072],[-95.1126,48.9073],[-95.1107,48.9082],[-95.1096,48.9089],[-95.108,48.9099],[-95.1056,48.9113],[-95.1042,48.9121],[-95.1032,48.9127],[-95.102,48.9132],[-95.1008,48.9142],[-95.0981,48.9159],[-95.098,48.916],[-95.0975,48.9164],[-95.0971,48.9172],[-95.097,48.9176],[-95.0961,48.9181],[-95.0946,48.9191],[-95.0944,48.9193],[-95.0927,48.9204],[-95.0919,48.9207],[-95.0914,48.9208],[-95.0914,48.916],[-95.0912,48.9014],[-95.0911,48.8869],[-95.0908,48.8724],[-95.0908,48.858],[-95.0907,48.8436],[-95.0908,48.8291],[-95.0909,48.8147],[-95.0903,48.8],[-95.0903,48.7855],[-95.0903,48.7711],[-95.0901,48.7566],[-95.0901,48.7421],[-95.0899,48.7277],[-95.0898,48.713],[-95.1046,48.7129],[-95.1104,48.7129],[-95.1119,48.7129],[-95.1259,48.7129],[-95.1297,48.713],[-95.1333,48.713],[-95.1477,48.7129],[-95.1554,48.7129],[-95.1697,48.7129],[-95.1773,48.713],[-95.1917,48.713],[-95.1991,48.713],[-95.2112,48.713],[-95.2206,48.713],[-95.2331,48.713],[-95.2427,48.713],[-95.255,48.713],[-95.2645,48.713],[-95.2656,48.713],[-95.2767,48.713],[-95.2866,48.713],[-95.299,48.713],[-95.3051,48.713],[-95.3084,48.713],[-95.3205,48.713],[-95.3302,48.713],[-95.3425,48.7131],[-95.3425,48.6995],[-95.3424,48.6849],[-95.3423,48.6705],[-95.3424,48.6561],[-95.3425,48.6415],[-95.3426,48.6271],[-95.3424,48.6127],[-95.3426,48.5979],[-95.3423,48.5836],[-95.3423,48.5691],[-95.3424,48.5548],[-95.3425,48.5402],[-95.3628,48.5404],[-95.364,48.5403],[-95.3844,48.5402],[-95.386,48.5402],[-95.4061,48.5402],[-95.4078,48.5402],[-95.4279,48.54],[-95.4297,48.5399],[-95.4494,48.5399],[-95.4513,48.5399],[-95.4712,48.5396],[-95.4726,48.5396],[-95.493,48.5392],[-95.495,48.5392],[-95.5143,48.539],[-95.5163,48.539],[-95.5365,48.5389],[-95.5383,48.5389],[-95.558,48.5388],[-95.5603,48.5388],[-95.5801,48.5387],[-95.5821,48.5387],[-95.6023,48.5389],[-95.6232,48.5391],[-95.6447,48.5393],[-95.6666,48.5394],[-95.6886,48.5395],[-95.7102,48.5395],[-95.7322,48.54],[-95.7539,48.5404],[-95.7758,48.5406],[-95.7976,48.5405],[-95.8192,48.5404],[-95.8411,48.5406],[-95.8621,48.5414],[-95.8829,48.5419],[-95.8851,48.542],[-95.8986,48.5421],[-95.9046,48.5422],[-95.9064,48.5422],[-95.9269,48.5421],[-95.9486,48.5425],[-95.9498,48.5425],[-95.9704,48.543],[-95.9936,48.5435],[-96.0157,48.5437],[-96.0374,48.5438],[-96.0592,48.5437],[-96.0812,48.5436],[-96.1026,48.5438],[-96.1264,48.5439],[-96.1486,48.5442],[-96.1702,48.5445],[-96.1921,48.5446],[-96.2141,48.5449],[-96.2358,48.5452],[-96.2576,48.545],[-96.2794,48.5449],[-96.301,48.5448],[-96.3231,48.5446],[-96.3448,48.5444],[-96.3667,48.5443],[-96.3882,48.5442],[-96.3879,48.5588],[-96.3882,48.5733],[-96.3884,48.5877],[-96.3891,48.6024],[-96.389,48.6165],[-96.388,48.6313],[-96.3879,48.6454],[-96.3877,48.6599],[-96.3871,48.6741],[-96.3874,48.6887],[-96.3866,48.703],[-96.3873,48.7172],[-96.388,48.7172],[-96.4049,48.7172],[-96.4048,48.7318],[-96.4048,48.7465],[-96.4047,48.7607],[-96.4045,48.7758],[-96.4042,48.7903],[-96.4042,48.8048],[-96.4042,48.8198],[-96.4043,48.8343],[-96.4045,48.8491],[-96.4047,48.8635],[-96.405,48.878],[-96.405,48.8926],[-96.4053,48.9068],[-96.4053,48.9081],[-96.4053,48.9137],[-96.4054,48.9214],[-96.4054,48.9225],[-96.4053,48.936],[-96.4053,48.9371],[-96.4053,48.9504],[-96.4053,48.9515],[-96.4053,48.9648],[-96.4053,48.9658],[-96.4053,48.9705],[-96.4054,48.9793],[-96.4054,48.9803],[-96.4054,48.994],[-96.4054,48.9947],[-96.4054,49.0001]]],"type":"Polygon"},"id":"68","properties":{"Area":4347098503.12714,"CTYONLY_":4,"Code":"ROSE","LASTMOD":"2001-04-12T09:32:44Z","Name":"Roseau","Perimiter":302590.75293},"type":"Feature"},{"geometry":{"coordinates":[[[-94.4299,48.7012],[-94.4241,48.7053],[-94.4213,48.7086],[-94.4189,48.7103],[-94.4158,48.711],[-94.4081,48.7106],[-94.406,48.7105],[-94.3889,48.712],[-94.3859,48.7119],[-94.384,48.7119],[-94.3801,48.7111],[-94.3687,48.7065],[-94.3646,48.7059],[-94.3533,48.7042],[-94.3431,48.7035],[-94.3429,48.7035],[-94.3287,48.7045],[-94.3214,48.7067],[-94.3088,48.7103],[-94.2995,48.709],[-94.2911,48.7079],[-94.2829,48.7057],[-94.2781,48.7024],[-94.2745,48.6999],[-94.2694,48.6995],[-94.2644,48.699],[-94.261,48.6966],[-94.258,48.6918],[-94.2565,48.6901],[-94.2529,48.6864],[-94.2521,48.685],[-94.2514,48.6837],[-94.2507,48.6782],[-94.2527,48.6707],[-94.253,48.6693],[-94.2548,48.664],[-94.2546,48.6615],[-94.2509,48.657],[-94.2499,48.6563],[-94.2467,48.6542],[-94.2445,48.6535],[-94.2343,48.6524],[-94.2335,48.6524],[-94.2242,48.6495],[-94.2144,48.6494],[-94.2124,48.6496],[-94.1996,48.651],[-94.1915,48.6506],[-94.1886,48.6504],[-94.1689,48.6483],[-94.1678,48.6482],[-94.1574,48.6458],[-94.1522,48.6455],[-94.1458,48.6458],[-94.1391,48.646],[-94.126,48.6444],[-94.1235,48.6444],[-94.11,48.6443],[-94.1023,48.6455],[-94.0999,48.6459],[-94.0912,48.6437],[-94.0849,48.6441],[-94.0804,48.6442],[-94.0767,48.6442],[-94.0714,48.6459],[-94.0658,48.6462],[-94.0642,48.6438],[-94.0603,48.6431],[-94.0581,48.6434],[-94.0525,48.644],[-94.0432,48.6435],[-94.0393,48.6423],[-94.0364,48.6413],[-94.0356,48.6411],[-94.0295,48.6409],[-94.0153,48.6424],[-94.0069,48.6433],[-94.0007,48.6428],[-93.9931,48.6412],[-93.9897,48.6405],[-93.984,48.6401],[-93.9777,48.6385],[-93.9712,48.6385],[-93.968,48.6385],[-93.9596,48.6372],[-93.953,48.6341],[-93.9497,48.6339],[-93.934,48.6326],[-93.9272,48.6327],[-93.9169,48.6329],[-93.9134,48.6353],[-93.9057,48.6346],[-93.9054,48.6345],[-93.8948,48.6324],[-93.8853,48.6318],[-93.8844,48.6318],[-93.8757,48.6319],[-93.8698,48.6311],[-93.8624,48.631],[-93.848,48.6308],[-93.8443,48.6303],[-93.8404,48.6289],[-93.8393,48.6286],[-93.8365,48.6276],[-93.8334,48.6256],[-93.8292,48.6177],[-93.825,48.6136],[-93.8245,48.613],[-93.8214,48.6092],[-93.8182,48.5994],[-93.8175,48.597],[-93.8172,48.5964],[-93.813,48.588],[-93.8103,48.5846],[-93.8063,48.5796],[-93.8041,48.5703],[-93.8041,48.5702],[-93.8051,48.5644],[-93.808,48.5569],[-93.8088,48.5555],[-93.8119,48.5503],[-93.8102,48.5445],[-93.8109,48.5412],[-93.8109,48.541],[-93.818,48.535],[-93.818,48.5346],[-93.8184,48.5315],[-93.8178,48.5306],[-93.8161,48.5285],[-93.8145,48.5273],[-93.8111,48.5247],[-93.803,48.522],[-93.7964,48.5182],[-93.7933,48.5164],[-93.7879,48.5159],[-93.7745,48.5162],[-93.768,48.5164],[-93.7665,48.5164],[-93.7617,48.5166],[-93.7534,48.5158],[-93.7442,48.5175],[-93.739,48.5185],[-93.731,48.5185],[-93.7225,48.5178],[-93.7206,48.5176],[-93.7108,48.5186],[-93.7061,48.5182],[-93.7006,48.517],[-93.693,48.5152],[-93.6866,48.5154],[-93.6791,48.5167],[-93.6778,48.5169],[-93.6593,48.5165],[-93.657,48.5167],[-93.6473,48.5177],[-93.6433,48.519],[-93.6421,48.5199],[-93.6395,48.5218],[-93.6357,48.5285],[-93.6344,48.5293],[-93.6311,48.5313],[-93.6284,48.5319],[-93.6256,48.5315],[-93.6211,48.5264],[-93.6166,48.5238],[-93.6134,48.5228],[-93.6122,48.5225],[-93.6051,48.5231],[-93.5962,48.5287],[-93.5919,48.5299],[-93.5901,48.5305],[-93.581,48.5271],[-93.5761,48.527],[-93.5701,48.528],[-93.5602,48.5297],[-93.5484,48.5294],[-93.5476,48.5294],[-93.5425,48.53],[-93.5366,48.5319],[-93.5269,48.5341],[-93.5263,48.5341],[-93.5244,48.5343],[-93.5171,48.5348],[-93.5047,48.5399],[-93.501,48.5414],[-93.4952,48.5426],[-93.4854,48.5433],[-93.4833,48.5437],[-93.4673,48.5465],[-93.4655,48.5478],[-93.4625,48.5498],[-93.462,48.5505],[-93.4596,48.5537],[-93.4576,48.5598],[-93.4576,48.5621],[-93.4575,48.5672],[-93.4619,48.5731],[-93.4619,48.5734],[-93.4631,48.5767],[-93.4671,48.5885],[-93.4656,48.59],[-93.4654,48.5915],[-93.4654,48.5917],[-93.4627,48.5927],[-93.46,48.5927],[-93.4547,48.5927],[-93.4398,48.5937],[-93.4385,48.5942],[-93.4347,48.5954],[-93.4298,48.5997],[-93.4226,48.6032],[-93.4193,48.6036],[-93.416,48.605],[-93.4152,48.6053],[-93.415,48.6056],[-93.4144,48.6064],[-93.4056,48.6099],[-93.4034,48.61],[-93.4029,48.6077],[-93.4013,48.6079],[-93.3994,48.6055],[-93.3986,48.6045],[-93.3953,48.6038],[-93.3937,48.6041],[-93.3837,48.606],[-93.3724,48.6059],[-93.3714,48.6059],[-93.3672,48.6082],[-93.3619,48.6141],[-93.355,48.6114],[-93.3526,48.6135],[-93.3533,48.615],[-93.3513,48.62],[-93.3505,48.6219],[-93.3486,48.6265],[-93.3276,48.6302],[-93.3057,48.634],[-93.3048,48.6341],[-93.2838,48.6378],[-93.2634,48.6413],[-93.2546,48.6429],[-93.2422,48.6428],[-93.2193,48.6426],[-93.2075,48.6426],[-93.1975,48.6365],[-93.191,48.6325],[-93.184,48.6282],[-93.1783,48.6231],[-93.1754,48.6232],[-93.1531,48.6244],[-93.1319,48.6256],[-93.1104,48.6267],[-93.0903,48.6278],[-93.0884,48.6278],[-93.0886,48.6163],[-93.0895,48.6016],[-93.0898,48.5872],[-93.09,48.5727],[-93.0902,48.5583],[-93.0902,48.5441],[-93.0903,48.5296],[-93.0905,48.5151],[-93.0905,48.501],[-93.091,48.4884],[-93.0911,48.4867],[-93.0914,48.474],[-93.0915,48.4724],[-93.0918,48.4596],[-93.0919,48.458],[-93.092,48.4449],[-93.092,48.4436],[-93.0922,48.4303],[-93.0922,48.429],[-93.0923,48.4147],[-93.0935,48.4147],[-93.0938,48.4024],[-93.094,48.3879],[-93.094,48.3734],[-93.0945,48.3589],[-93.0948,48.3442],[-93.0948,48.3298],[-93.0953,48.3153],[-93.0952,48.3004],[-93.095,48.2862],[-93.0952,48.2716],[-93.0953,48.2576],[-93.0949,48.2426],[-93.0949,48.2425],[-93.0977,48.2426],[-93.0977,48.2271],[-93.0978,48.2126],[-93.0979,48.1981],[-93.0975,48.1836],[-93.097,48.1692],[-93.097,48.1546],[-93.097,48.1402],[-93.0969,48.1259],[-93.0972,48.1114],[-93.097,48.0969],[-93.0968,48.0823],[-93.0965,48.0679],[-93.0965,48.0678],[-93.0892,48.0679],[-93.0892,48.0509],[-93.089,48.0366],[-93.0886,48.022],[-93.0887,48.0075],[-93.0872,47.9932],[-93.088,47.9787],[-93.0809,47.9786],[-93.0809,47.967],[-93.0808,47.9647],[-93.0808,47.9525],[-93.0808,47.9504],[-93.0809,47.938],[-93.0809,47.9356],[-93.0809,47.9235],[-93.0809,47.9212],[-93.0809,47.9088],[-93.0809,47.9067],[-93.0808,47.8945],[-93.0808,47.8922],[-93.1015,47.8927],[-93.1232,47.893],[-93.1448,47.8928],[-93.1656,47.8931],[-93.1671,47.8932],[-93.1871,47.8931],[-93.1893,47.8931],[-93.2087,47.8933],[-93.2115,47.8934],[-93.2331,47.8937],[-93.2532,47.8936],[-93.2745,47.8938],[-93.2962,47.8939],[-93.3169,47.894],[-93.3392,47.8941],[-93.3603,47.8942],[-93.3809,47.8943],[-93.4024,47.8944],[-93.4235,47.8945],[-93.4442,47.8946],[-93.466,47.895],[-93.4874,47.8956],[-93.4892,47.8957],[-93.4933,47.8958],[-93.5085,47.8962],[-93.5105,47.8963],[-93.5297,47.8967],[-93.5303,47.8967],[-93.532,47.8968],[-93.5517,47.8973],[-93.5532,47.8974],[-93.5729,47.8981],[-93.5747,47.8982],[-93.5962,47.8978],[-93.5966,47.8978],[-93.6179,47.8977],[-93.6187,47.8977],[-93.6388,47.8977],[-93.6395,47.8976],[-93.6604,47.8976],[-93.6612,47.8976],[-93.6817,47.8976],[-93.6826,47.8976],[-93.7031,47.8976],[-93.7038,47.8976],[-93.7249,47.8975],[-93.7248,47.8989],[-93.7466,47.8989],[-93.768,47.8991],[-93.7758,47.8991],[-93.7758,47.899],[-93.776,47.8897],[-93.776,47.8842],[-93.7762,47.8753],[-93.7761,47.8697],[-93.7761,47.8607],[-93.7761,47.8553],[-93.7761,47.8464],[-93.7896,47.8465],[-93.7971,47.8466],[-93.8189,47.8467],[-93.8407,47.8468],[-93.8627,47.8469],[-93.8831,47.8471],[-93.9067,47.8471],[-93.9288,47.8475],[-93.9496,47.8475],[-93.9506,47.8475],[-93.971,47.8475],[-93.9725,47.8475],[-93.9927,47.8475],[-93.9942,47.8475],[-94.0141,47.8476],[-94.0161,47.8476],[-94.0375,47.8477],[-94.0591,47.8474],[-94.0807,47.8471],[-94.1022,47.8471],[-94.1239,47.8466],[-94.1448,47.8463],[-94.1657,47.8461],[-94.1822,47.8461],[-94.1871,47.846],[-94.2037,47.846],[-94.2086,47.846],[-94.2252,47.846],[-94.23,47.8461],[-94.2467,47.8462],[-94.2515,47.8462],[-94.2681,47.8462],[-94.2728,47.8462],[-94.2887,47.8462],[-94.3103,47.8458],[-94.3315,47.846],[-94.3532,47.8464],[-94.3747,47.8462],[-94.3964,47.8461],[-94.4185,47.8459],[-94.4186,47.86],[-94.4184,47.8744],[-94.418,47.8886],[-94.4177,47.9031],[-94.4176,47.9041],[-94.4175,47.9175],[-94.4174,47.9186],[-94.4175,47.9332],[-94.4174,47.9477],[-94.4172,47.9623],[-94.4173,47.9769],[-94.4176,47.9914],[-94.4177,48.006],[-94.4176,48.02],[-94.4236,48.0199],[-94.4241,48.0344],[-94.4246,48.0489],[-94.4247,48.0632],[-94.4234,48.0776],[-94.4231,48.092],[-94.4233,48.1059],[-94.4234,48.1204],[-94.4236,48.1348],[-94.4233,48.1491],[-94.4235,48.1637],[-94.4235,48.1781],[-94.4233,48.1923],[-94.4236,48.2067],[-94.4238,48.2212],[-94.4237,48.2356],[-94.4237,48.2504],[-94.424,48.2649],[-94.4243,48.2791],[-94.4244,48.2938],[-94.4246,48.3081],[-94.4248,48.3227],[-94.425,48.3372],[-94.4253,48.352],[-94.4252,48.3675],[-94.4288,48.3675],[-94.4289,48.3821],[-94.4293,48.3964],[-94.4294,48.411],[-94.4293,48.4254],[-94.4292,48.4399],[-94.4293,48.4543],[-94.4296,48.4688],[-94.4296,48.4832],[-94.4299,48.4977],[-94.4303,48.512],[-94.4303,48.5264],[-94.43,48.5409],[-94.4295,48.5554],[-94.4291,48.5698],[-94.4289,48.5844],[-94.4289,48.5988],[-94.4292,48.6133],[-94.4294,48.6276],[-94.4297,48.642],[-94.43,48.6564],[-94.4301,48.6708],[-94.43,48.6852],[-94.4299,48.6998],[-94.4299,48.7012]]],"type":"Polygon"},"id":"36","properties":{"Area":8167237870.91888,"CTYONLY_":5,"Code":"KOOC","LASTMOD":"1999-12-31T23:59:59Z","Name":"Koochiching","Perimiter":412897.43594},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&filter=%7B%22op%22%3A%22between%22%2C%22args%22%3A%5B%7B%22property%22%3A%22CTYONLY_%22%7D%2C3%2C5%5D%7D&filter-lang=cql2-json","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&filter=%7B%22op%22%3A%22between%22%2C%22args%22%3A%5B%7B%22property%22%3A%22CTYONLY_%22%7D%2C3%2C5%5D%7D&filter-lang=cql2-json","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":3,"numberReturned":3,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_json_date.json.txt b/msautotest/api/expected/ogcapi_cql2_json_date.json.txt new file mode 100644 index 0000000000..3d3e8ae977 --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_json_date.json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 0 +OGC-NumberReturned: 0 + +{"features":[],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&filter=%7B%22op%22%3A%22%3D%22%2C%22args%22%3A%5B%7B%22property%22%3A%22LASTMOD%22%7D%2C%7B%22date%22%3A%222003-01-01%22%7D%5D%7D&filter-lang=cql2-json","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&filter=%7B%22op%22%3A%22%3D%22%2C%22args%22%3A%5B%7B%22property%22%3A%22LASTMOD%22%7D%2C%7B%22date%22%3A%222003-01-01%22%7D%5D%7D&filter-lang=cql2-json","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":0,"numberReturned":0,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_json_div.json.txt b/msautotest/api/expected/ogcapi_cql2_json_div.json.txt new file mode 100644 index 0000000000..804a07a49c --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_json_div.json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 1 +OGC-NumberReturned: 1 + +{"features":[{"geometry":{"coordinates":[[[-96.4054,49.0001],[-96.4019,49.0001],[-96.3825,49.0001],[-96.3783,49.0001],[-96.3606,49.0001],[-96.3579,49.0001],[-96.3385,49.0001],[-96.3343,49.0001],[-96.3166,49.0001],[-96.3138,49.0001],[-96.2945,49.0001],[-96.2902,49.0001],[-96.2725,49.0001],[-96.2698,49.0001],[-96.2494,49.0001],[-96.2461,49.0001],[-96.2274,49.0001],[-96.2257,49.0001],[-96.2057,49.0001],[-96.2021,49.0001],[-96.1837,49.0],[-96.18,49.0],[-96.1617,49.0],[-96.1579,49.0],[-96.1401,49.0],[-96.1359,49.0],[-96.1176,49.0],[-96.1139,49.0],[-96.0957,49.0],[-96.0919,49.0],[-96.0738,49.0],[-96.07,49.0],[-96.0517,49.0],[-96.048,49.0],[-96.0298,49.0],[-96.026,49.0],[-96.0083,49.0],[-96.0045,49.0],[-95.9868,49.0],[-95.9784,49.0],[-95.9776,49.0],[-95.9755,49.0],[-95.9648,48.9999],[-95.9464,48.9999],[-95.943,48.9999],[-95.9225,48.9999],[-95.9211,48.9999],[-95.899,48.9998],[-95.883,48.9998],[-95.8771,48.9998],[-95.8564,48.9998],[-95.855,48.9998],[-95.8342,48.9998],[-95.8184,48.9997],[-95.8126,48.9997],[-95.7906,48.9997],[-95.7833,48.9997],[-95.7684,48.9997],[-95.7479,48.9996],[-95.7466,48.9996],[-95.7253,48.9996],[-95.7066,48.9996],[-95.7032,48.9996],[-95.681,48.9995],[-95.6654,48.9995],[-95.6596,48.9995],[-95.659,48.9995],[-95.6401,48.9995],[-95.6369,48.9995],[-95.6205,48.9994],[-95.615,48.9994],[-95.5948,48.9994],[-95.585,48.9994],[-95.573,48.9994],[-95.551,48.9993],[-95.5495,48.9993],[-95.5294,48.9993],[-95.5164,48.9993],[-95.5072,48.9993],[-95.4849,48.9992],[-95.4834,48.9992],[-95.4635,48.9992],[-95.4508,48.9992],[-95.4418,48.9992],[-95.4245,48.9991],[-95.4197,48.9991],[-95.3977,48.9991],[-95.3953,48.9991],[-95.3765,48.9991],[-95.3759,48.9991],[-95.3753,48.9991],[-95.3542,48.999],[-95.3513,48.999],[-95.3326,48.999],[-95.3286,48.999],[-95.3231,48.999],[-95.3224,48.9984],[-95.3204,48.9976],[-95.3202,48.9973],[-95.3204,48.9964],[-95.3206,48.9961],[-95.3201,48.9956],[-95.3197,48.9954],[-95.3191,48.9953],[-95.3187,48.9956],[-95.3182,48.996],[-95.3179,48.9961],[-95.3178,48.9961],[-95.3178,48.9958],[-95.3181,48.995],[-95.3191,48.9941],[-95.3204,48.9924],[-95.3206,48.9921],[-95.3224,48.9889],[-95.3227,48.9884],[-95.3242,48.9859],[-95.3245,48.985],[-95.3253,48.9832],[-95.3257,48.9814],[-95.3256,48.98],[-95.3255,48.9789],[-95.3257,48.9784],[-95.3253,48.976],[-95.325,48.9743],[-95.3249,48.9738],[-95.3248,48.9728],[-95.3247,48.972],[-95.3241,48.9703],[-95.3232,48.9692],[-95.3227,48.9685],[-95.3212,48.9672],[-95.3207,48.9669],[-95.3201,48.9648],[-95.3198,48.9643],[-95.3193,48.964],[-95.3193,48.9622],[-95.3202,48.9606],[-95.3206,48.9598],[-95.3206,48.9595],[-95.3206,48.959],[-95.3202,48.9581],[-95.3191,48.9569],[-95.3188,48.9562],[-95.3179,48.9559],[-95.3175,48.9552],[-95.3177,48.9545],[-95.3182,48.9535],[-95.3181,48.9531],[-95.3177,48.9525],[-95.3154,48.9513],[-95.3151,48.951],[-95.3141,48.9508],[-95.3131,48.9503],[-95.3125,48.9503],[-95.3123,48.9502],[-95.3119,48.9502],[-95.3119,48.9507],[-95.3129,48.9521],[-95.3129,48.9523],[-95.3126,48.9524],[-95.312,48.9524],[-95.3115,48.952],[-95.3108,48.9512],[-95.3104,48.951],[-95.3097,48.951],[-95.3089,48.9511],[-95.3079,48.9509],[-95.3061,48.9502],[-95.3052,48.9495],[-95.3046,48.9482],[-95.3046,48.947],[-95.305,48.9462],[-95.3053,48.9459],[-95.3061,48.9454],[-95.3068,48.9454],[-95.3069,48.9455],[-95.3069,48.9456],[-95.3063,48.9462],[-95.3062,48.9463],[-95.3061,48.9469],[-95.3062,48.9472],[-95.3062,48.9472],[-95.3071,48.9477],[-95.3081,48.948],[-95.3094,48.9481],[-95.3096,48.9482],[-95.3099,48.9484],[-95.31,48.9485],[-95.3103,48.9485],[-95.3104,48.9484],[-95.3103,48.948],[-95.3096,48.9478],[-95.3092,48.9477],[-95.3079,48.9474],[-95.3071,48.9469],[-95.3071,48.9466],[-95.3074,48.9465],[-95.3078,48.9466],[-95.3085,48.947],[-95.3086,48.9469],[-95.3086,48.9465],[-95.3088,48.9464],[-95.3095,48.9463],[-95.3102,48.9463],[-95.3114,48.9461],[-95.3131,48.946],[-95.3141,48.9457],[-95.3148,48.9452],[-95.3154,48.9448],[-95.3168,48.9431],[-95.3181,48.9421],[-95.3189,48.9419],[-95.3219,48.9412],[-95.3225,48.9409],[-95.3228,48.9403],[-95.3231,48.9389],[-95.3229,48.9373],[-95.3225,48.9358],[-95.3223,48.9355],[-95.3228,48.9344],[-95.3222,48.9327],[-95.3209,48.9307],[-95.3208,48.9305],[-95.3195,48.9285],[-95.3168,48.9245],[-95.315,48.9222],[-95.3141,48.921],[-95.3132,48.9198],[-95.3126,48.919],[-95.3119,48.9178],[-95.3115,48.9172],[-95.3109,48.9163],[-95.3102,48.9155],[-95.3093,48.9149],[-95.3092,48.9149],[-95.3085,48.9146],[-95.3078,48.9141],[-95.3074,48.9135],[-95.3064,48.9129],[-95.3061,48.9128],[-95.3059,48.9127],[-95.3043,48.9119],[-95.3038,48.9114],[-95.3027,48.91],[-95.3017,48.9093],[-95.2999,48.9086],[-95.2978,48.9083],[-95.2973,48.9081],[-95.2973,48.908],[-95.2973,48.9077],[-95.2976,48.9074],[-95.2977,48.9073],[-95.2978,48.9073],[-95.2978,48.9072],[-95.2978,48.9072],[-95.2979,48.9072],[-95.2979,48.9072],[-95.2979,48.9071],[-95.298,48.9071],[-95.298,48.9071],[-95.298,48.9071],[-95.2981,48.907],[-95.2982,48.9068],[-95.2983,48.9068],[-95.2985,48.9065],[-95.2985,48.9064],[-95.2986,48.9063],[-95.2988,48.906],[-95.2989,48.906],[-95.2991,48.9057],[-95.2992,48.9055],[-95.2994,48.9053],[-95.2996,48.9051],[-95.2997,48.905],[-95.2999,48.9048],[-95.2999,48.9048],[-95.2999,48.9048],[-95.3,48.9047],[-95.3,48.9047],[-95.3001,48.9047],[-95.3001,48.9046],[-95.3002,48.9045],[-95.3005,48.904],[-95.2993,48.9035],[-95.2983,48.9028],[-95.298,48.9027],[-95.2976,48.9026],[-95.2967,48.9027],[-95.2949,48.9028],[-95.2941,48.9027],[-95.2937,48.9023],[-95.2935,48.902],[-95.2927,48.9019],[-95.2914,48.9019],[-95.2909,48.9017],[-95.2908,48.9016],[-95.2907,48.9014],[-95.2906,48.9011],[-95.2911,48.9008],[-95.2911,48.9006],[-95.2901,48.9003],[-95.2896,48.9],[-95.289,48.8994],[-95.2882,48.8981],[-95.2879,48.8979],[-95.2872,48.8977],[-95.287,48.8976],[-95.2865,48.8975],[-95.2861,48.8976],[-95.2853,48.8977],[-95.2839,48.8975],[-95.2813,48.8967],[-95.2803,48.8965],[-95.2796,48.8962],[-95.279,48.8957],[-95.2782,48.8956],[-95.2773,48.8957],[-95.277,48.8958],[-95.2765,48.8962],[-95.2763,48.8963],[-95.2759,48.8962],[-95.2755,48.8959],[-95.2749,48.8956],[-95.2748,48.8951],[-95.2753,48.8943],[-95.2751,48.8938],[-95.2745,48.8931],[-95.2724,48.8921],[-95.2713,48.8915],[-95.268,48.8905],[-95.2677,48.8903],[-95.2674,48.89],[-95.2666,48.8894],[-95.2654,48.8888],[-95.265,48.8886],[-95.2646,48.8885],[-95.2639,48.8883],[-95.2635,48.888],[-95.2627,48.8877],[-95.2585,48.8867],[-95.2585,48.8867],[-95.257,48.8858],[-95.256,48.885],[-95.2548,48.8845],[-95.2517,48.8839],[-95.2507,48.8836],[-95.2502,48.8835],[-95.2496,48.8834],[-95.2485,48.8832],[-95.248,48.8836],[-95.2472,48.8835],[-95.2458,48.8829],[-95.2439,48.8823],[-95.2429,48.8822],[-95.2429,48.8822],[-95.2423,48.8821],[-95.2407,48.8821],[-95.2391,48.8819],[-95.2381,48.8817],[-95.2356,48.8815],[-95.2335,48.8814],[-95.231,48.8814],[-95.2287,48.8815],[-95.2265,48.8816],[-95.2252,48.8819],[-95.2212,48.883],[-95.2208,48.8831],[-95.2207,48.8831],[-95.22,48.8831],[-95.2193,48.8832],[-95.2188,48.8835],[-95.217,48.8835],[-95.2159,48.8839],[-95.2151,48.884],[-95.2144,48.8843],[-95.2122,48.8842],[-95.2117,48.8847],[-95.2115,48.8847],[-95.2112,48.8848],[-95.2085,48.8846],[-95.2059,48.8848],[-95.2024,48.8852],[-95.2009,48.8855],[-95.2005,48.8856],[-95.1986,48.8855],[-95.1956,48.8862],[-95.1924,48.8865],[-95.1919,48.8866],[-95.1913,48.8868],[-95.1901,48.887],[-95.1889,48.8873],[-95.1877,48.8874],[-95.1863,48.8877],[-95.1851,48.8882],[-95.1819,48.8888],[-95.1797,48.889],[-95.1791,48.889],[-95.1764,48.8893],[-95.173,48.8897],[-95.1701,48.8902],[-95.1674,48.8907],[-95.1648,48.8913],[-95.1641,48.8917],[-95.1618,48.892],[-95.1602,48.892],[-95.1579,48.8919],[-95.1564,48.8919],[-95.1555,48.892],[-95.1528,48.8921],[-95.1508,48.8922],[-95.1483,48.8923],[-95.1469,48.8927],[-95.1459,48.8929],[-95.1438,48.8934],[-95.1436,48.8937],[-95.1404,48.8943],[-95.1381,48.8949],[-95.1355,48.8959],[-95.1351,48.8963],[-95.1348,48.8963],[-95.1343,48.8963],[-95.1337,48.8969],[-95.1322,48.8973],[-95.1312,48.8975],[-95.1252,48.8998],[-95.1239,48.9001],[-95.1233,48.9004],[-95.1228,48.9006],[-95.1214,48.9013],[-95.121,48.9016],[-95.1205,48.9017],[-95.1204,48.9019],[-95.1182,48.9029],[-95.1163,48.9037],[-95.1151,48.9046],[-95.1144,48.9052],[-95.114,48.9061],[-95.1141,48.9064],[-95.1137,48.9069],[-95.1132,48.9071],[-95.113,48.9072],[-95.1126,48.9073],[-95.1107,48.9082],[-95.1096,48.9089],[-95.108,48.9099],[-95.1056,48.9113],[-95.1042,48.9121],[-95.1032,48.9127],[-95.102,48.9132],[-95.1008,48.9142],[-95.0981,48.9159],[-95.098,48.916],[-95.0975,48.9164],[-95.0971,48.9172],[-95.097,48.9176],[-95.0961,48.9181],[-95.0946,48.9191],[-95.0944,48.9193],[-95.0927,48.9204],[-95.0919,48.9207],[-95.0914,48.9208],[-95.0914,48.916],[-95.0912,48.9014],[-95.0911,48.8869],[-95.0908,48.8724],[-95.0908,48.858],[-95.0907,48.8436],[-95.0908,48.8291],[-95.0909,48.8147],[-95.0903,48.8],[-95.0903,48.7855],[-95.0903,48.7711],[-95.0901,48.7566],[-95.0901,48.7421],[-95.0899,48.7277],[-95.0898,48.713],[-95.1046,48.7129],[-95.1104,48.7129],[-95.1119,48.7129],[-95.1259,48.7129],[-95.1297,48.713],[-95.1333,48.713],[-95.1477,48.7129],[-95.1554,48.7129],[-95.1697,48.7129],[-95.1773,48.713],[-95.1917,48.713],[-95.1991,48.713],[-95.2112,48.713],[-95.2206,48.713],[-95.2331,48.713],[-95.2427,48.713],[-95.255,48.713],[-95.2645,48.713],[-95.2656,48.713],[-95.2767,48.713],[-95.2866,48.713],[-95.299,48.713],[-95.3051,48.713],[-95.3084,48.713],[-95.3205,48.713],[-95.3302,48.713],[-95.3425,48.7131],[-95.3425,48.6995],[-95.3424,48.6849],[-95.3423,48.6705],[-95.3424,48.6561],[-95.3425,48.6415],[-95.3426,48.6271],[-95.3424,48.6127],[-95.3426,48.5979],[-95.3423,48.5836],[-95.3423,48.5691],[-95.3424,48.5548],[-95.3425,48.5402],[-95.3628,48.5404],[-95.364,48.5403],[-95.3844,48.5402],[-95.386,48.5402],[-95.4061,48.5402],[-95.4078,48.5402],[-95.4279,48.54],[-95.4297,48.5399],[-95.4494,48.5399],[-95.4513,48.5399],[-95.4712,48.5396],[-95.4726,48.5396],[-95.493,48.5392],[-95.495,48.5392],[-95.5143,48.539],[-95.5163,48.539],[-95.5365,48.5389],[-95.5383,48.5389],[-95.558,48.5388],[-95.5603,48.5388],[-95.5801,48.5387],[-95.5821,48.5387],[-95.6023,48.5389],[-95.6232,48.5391],[-95.6447,48.5393],[-95.6666,48.5394],[-95.6886,48.5395],[-95.7102,48.5395],[-95.7322,48.54],[-95.7539,48.5404],[-95.7758,48.5406],[-95.7976,48.5405],[-95.8192,48.5404],[-95.8411,48.5406],[-95.8621,48.5414],[-95.8829,48.5419],[-95.8851,48.542],[-95.8986,48.5421],[-95.9046,48.5422],[-95.9064,48.5422],[-95.9269,48.5421],[-95.9486,48.5425],[-95.9498,48.5425],[-95.9704,48.543],[-95.9936,48.5435],[-96.0157,48.5437],[-96.0374,48.5438],[-96.0592,48.5437],[-96.0812,48.5436],[-96.1026,48.5438],[-96.1264,48.5439],[-96.1486,48.5442],[-96.1702,48.5445],[-96.1921,48.5446],[-96.2141,48.5449],[-96.2358,48.5452],[-96.2576,48.545],[-96.2794,48.5449],[-96.301,48.5448],[-96.3231,48.5446],[-96.3448,48.5444],[-96.3667,48.5443],[-96.3882,48.5442],[-96.3879,48.5588],[-96.3882,48.5733],[-96.3884,48.5877],[-96.3891,48.6024],[-96.389,48.6165],[-96.388,48.6313],[-96.3879,48.6454],[-96.3877,48.6599],[-96.3871,48.6741],[-96.3874,48.6887],[-96.3866,48.703],[-96.3873,48.7172],[-96.388,48.7172],[-96.4049,48.7172],[-96.4048,48.7318],[-96.4048,48.7465],[-96.4047,48.7607],[-96.4045,48.7758],[-96.4042,48.7903],[-96.4042,48.8048],[-96.4042,48.8198],[-96.4043,48.8343],[-96.4045,48.8491],[-96.4047,48.8635],[-96.405,48.878],[-96.405,48.8926],[-96.4053,48.9068],[-96.4053,48.9081],[-96.4053,48.9137],[-96.4054,48.9214],[-96.4054,48.9225],[-96.4053,48.936],[-96.4053,48.9371],[-96.4053,48.9504],[-96.4053,48.9515],[-96.4053,48.9648],[-96.4053,48.9658],[-96.4053,48.9705],[-96.4054,48.9793],[-96.4054,48.9803],[-96.4054,48.994],[-96.4054,48.9947],[-96.4054,49.0001]]],"type":"Polygon"},"id":"68","properties":{"Area":4347098503.12714,"CTYONLY_":4,"Code":"ROSE","LASTMOD":"2001-04-12T09:32:44Z","Name":"Roseau","Perimiter":302590.75293},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&filter=%7B%22op%22%3A%22%3D%22%2C%22args%22%3A%5B%7B%22property%22%3A%22CTYONLY_%22%7D%2C%7B%22op%22%3A%22%2F%22%2C%22args%22%3A%5B12%2C3%5D%7D%5D%7D&filter-lang=cql2-json","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&filter=%7B%22op%22%3A%22%3D%22%2C%22args%22%3A%5B%7B%22property%22%3A%22CTYONLY_%22%7D%2C%7B%22op%22%3A%22%2F%22%2C%22args%22%3A%5B12%2C3%5D%7D%5D%7D&filter-lang=cql2-json","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":1,"numberReturned":1,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_json_div2.json.txt b/msautotest/api/expected/ogcapi_cql2_json_div2.json.txt new file mode 100644 index 0000000000..db6848cd2c --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_json_div2.json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 1 +OGC-NumberReturned: 1 + +{"features":[{"geometry":{"coordinates":[[[-96.4054,49.0001],[-96.4019,49.0001],[-96.3825,49.0001],[-96.3783,49.0001],[-96.3606,49.0001],[-96.3579,49.0001],[-96.3385,49.0001],[-96.3343,49.0001],[-96.3166,49.0001],[-96.3138,49.0001],[-96.2945,49.0001],[-96.2902,49.0001],[-96.2725,49.0001],[-96.2698,49.0001],[-96.2494,49.0001],[-96.2461,49.0001],[-96.2274,49.0001],[-96.2257,49.0001],[-96.2057,49.0001],[-96.2021,49.0001],[-96.1837,49.0],[-96.18,49.0],[-96.1617,49.0],[-96.1579,49.0],[-96.1401,49.0],[-96.1359,49.0],[-96.1176,49.0],[-96.1139,49.0],[-96.0957,49.0],[-96.0919,49.0],[-96.0738,49.0],[-96.07,49.0],[-96.0517,49.0],[-96.048,49.0],[-96.0298,49.0],[-96.026,49.0],[-96.0083,49.0],[-96.0045,49.0],[-95.9868,49.0],[-95.9784,49.0],[-95.9776,49.0],[-95.9755,49.0],[-95.9648,48.9999],[-95.9464,48.9999],[-95.943,48.9999],[-95.9225,48.9999],[-95.9211,48.9999],[-95.899,48.9998],[-95.883,48.9998],[-95.8771,48.9998],[-95.8564,48.9998],[-95.855,48.9998],[-95.8342,48.9998],[-95.8184,48.9997],[-95.8126,48.9997],[-95.7906,48.9997],[-95.7833,48.9997],[-95.7684,48.9997],[-95.7479,48.9996],[-95.7466,48.9996],[-95.7253,48.9996],[-95.7066,48.9996],[-95.7032,48.9996],[-95.681,48.9995],[-95.6654,48.9995],[-95.6596,48.9995],[-95.659,48.9995],[-95.6401,48.9995],[-95.6369,48.9995],[-95.6205,48.9994],[-95.615,48.9994],[-95.5948,48.9994],[-95.585,48.9994],[-95.573,48.9994],[-95.551,48.9993],[-95.5495,48.9993],[-95.5294,48.9993],[-95.5164,48.9993],[-95.5072,48.9993],[-95.4849,48.9992],[-95.4834,48.9992],[-95.4635,48.9992],[-95.4508,48.9992],[-95.4418,48.9992],[-95.4245,48.9991],[-95.4197,48.9991],[-95.3977,48.9991],[-95.3953,48.9991],[-95.3765,48.9991],[-95.3759,48.9991],[-95.3753,48.9991],[-95.3542,48.999],[-95.3513,48.999],[-95.3326,48.999],[-95.3286,48.999],[-95.3231,48.999],[-95.3224,48.9984],[-95.3204,48.9976],[-95.3202,48.9973],[-95.3204,48.9964],[-95.3206,48.9961],[-95.3201,48.9956],[-95.3197,48.9954],[-95.3191,48.9953],[-95.3187,48.9956],[-95.3182,48.996],[-95.3179,48.9961],[-95.3178,48.9961],[-95.3178,48.9958],[-95.3181,48.995],[-95.3191,48.9941],[-95.3204,48.9924],[-95.3206,48.9921],[-95.3224,48.9889],[-95.3227,48.9884],[-95.3242,48.9859],[-95.3245,48.985],[-95.3253,48.9832],[-95.3257,48.9814],[-95.3256,48.98],[-95.3255,48.9789],[-95.3257,48.9784],[-95.3253,48.976],[-95.325,48.9743],[-95.3249,48.9738],[-95.3248,48.9728],[-95.3247,48.972],[-95.3241,48.9703],[-95.3232,48.9692],[-95.3227,48.9685],[-95.3212,48.9672],[-95.3207,48.9669],[-95.3201,48.9648],[-95.3198,48.9643],[-95.3193,48.964],[-95.3193,48.9622],[-95.3202,48.9606],[-95.3206,48.9598],[-95.3206,48.9595],[-95.3206,48.959],[-95.3202,48.9581],[-95.3191,48.9569],[-95.3188,48.9562],[-95.3179,48.9559],[-95.3175,48.9552],[-95.3177,48.9545],[-95.3182,48.9535],[-95.3181,48.9531],[-95.3177,48.9525],[-95.3154,48.9513],[-95.3151,48.951],[-95.3141,48.9508],[-95.3131,48.9503],[-95.3125,48.9503],[-95.3123,48.9502],[-95.3119,48.9502],[-95.3119,48.9507],[-95.3129,48.9521],[-95.3129,48.9523],[-95.3126,48.9524],[-95.312,48.9524],[-95.3115,48.952],[-95.3108,48.9512],[-95.3104,48.951],[-95.3097,48.951],[-95.3089,48.9511],[-95.3079,48.9509],[-95.3061,48.9502],[-95.3052,48.9495],[-95.3046,48.9482],[-95.3046,48.947],[-95.305,48.9462],[-95.3053,48.9459],[-95.3061,48.9454],[-95.3068,48.9454],[-95.3069,48.9455],[-95.3069,48.9456],[-95.3063,48.9462],[-95.3062,48.9463],[-95.3061,48.9469],[-95.3062,48.9472],[-95.3062,48.9472],[-95.3071,48.9477],[-95.3081,48.948],[-95.3094,48.9481],[-95.3096,48.9482],[-95.3099,48.9484],[-95.31,48.9485],[-95.3103,48.9485],[-95.3104,48.9484],[-95.3103,48.948],[-95.3096,48.9478],[-95.3092,48.9477],[-95.3079,48.9474],[-95.3071,48.9469],[-95.3071,48.9466],[-95.3074,48.9465],[-95.3078,48.9466],[-95.3085,48.947],[-95.3086,48.9469],[-95.3086,48.9465],[-95.3088,48.9464],[-95.3095,48.9463],[-95.3102,48.9463],[-95.3114,48.9461],[-95.3131,48.946],[-95.3141,48.9457],[-95.3148,48.9452],[-95.3154,48.9448],[-95.3168,48.9431],[-95.3181,48.9421],[-95.3189,48.9419],[-95.3219,48.9412],[-95.3225,48.9409],[-95.3228,48.9403],[-95.3231,48.9389],[-95.3229,48.9373],[-95.3225,48.9358],[-95.3223,48.9355],[-95.3228,48.9344],[-95.3222,48.9327],[-95.3209,48.9307],[-95.3208,48.9305],[-95.3195,48.9285],[-95.3168,48.9245],[-95.315,48.9222],[-95.3141,48.921],[-95.3132,48.9198],[-95.3126,48.919],[-95.3119,48.9178],[-95.3115,48.9172],[-95.3109,48.9163],[-95.3102,48.9155],[-95.3093,48.9149],[-95.3092,48.9149],[-95.3085,48.9146],[-95.3078,48.9141],[-95.3074,48.9135],[-95.3064,48.9129],[-95.3061,48.9128],[-95.3059,48.9127],[-95.3043,48.9119],[-95.3038,48.9114],[-95.3027,48.91],[-95.3017,48.9093],[-95.2999,48.9086],[-95.2978,48.9083],[-95.2973,48.9081],[-95.2973,48.908],[-95.2973,48.9077],[-95.2976,48.9074],[-95.2977,48.9073],[-95.2978,48.9073],[-95.2978,48.9072],[-95.2978,48.9072],[-95.2979,48.9072],[-95.2979,48.9072],[-95.2979,48.9071],[-95.298,48.9071],[-95.298,48.9071],[-95.298,48.9071],[-95.2981,48.907],[-95.2982,48.9068],[-95.2983,48.9068],[-95.2985,48.9065],[-95.2985,48.9064],[-95.2986,48.9063],[-95.2988,48.906],[-95.2989,48.906],[-95.2991,48.9057],[-95.2992,48.9055],[-95.2994,48.9053],[-95.2996,48.9051],[-95.2997,48.905],[-95.2999,48.9048],[-95.2999,48.9048],[-95.2999,48.9048],[-95.3,48.9047],[-95.3,48.9047],[-95.3001,48.9047],[-95.3001,48.9046],[-95.3002,48.9045],[-95.3005,48.904],[-95.2993,48.9035],[-95.2983,48.9028],[-95.298,48.9027],[-95.2976,48.9026],[-95.2967,48.9027],[-95.2949,48.9028],[-95.2941,48.9027],[-95.2937,48.9023],[-95.2935,48.902],[-95.2927,48.9019],[-95.2914,48.9019],[-95.2909,48.9017],[-95.2908,48.9016],[-95.2907,48.9014],[-95.2906,48.9011],[-95.2911,48.9008],[-95.2911,48.9006],[-95.2901,48.9003],[-95.2896,48.9],[-95.289,48.8994],[-95.2882,48.8981],[-95.2879,48.8979],[-95.2872,48.8977],[-95.287,48.8976],[-95.2865,48.8975],[-95.2861,48.8976],[-95.2853,48.8977],[-95.2839,48.8975],[-95.2813,48.8967],[-95.2803,48.8965],[-95.2796,48.8962],[-95.279,48.8957],[-95.2782,48.8956],[-95.2773,48.8957],[-95.277,48.8958],[-95.2765,48.8962],[-95.2763,48.8963],[-95.2759,48.8962],[-95.2755,48.8959],[-95.2749,48.8956],[-95.2748,48.8951],[-95.2753,48.8943],[-95.2751,48.8938],[-95.2745,48.8931],[-95.2724,48.8921],[-95.2713,48.8915],[-95.268,48.8905],[-95.2677,48.8903],[-95.2674,48.89],[-95.2666,48.8894],[-95.2654,48.8888],[-95.265,48.8886],[-95.2646,48.8885],[-95.2639,48.8883],[-95.2635,48.888],[-95.2627,48.8877],[-95.2585,48.8867],[-95.2585,48.8867],[-95.257,48.8858],[-95.256,48.885],[-95.2548,48.8845],[-95.2517,48.8839],[-95.2507,48.8836],[-95.2502,48.8835],[-95.2496,48.8834],[-95.2485,48.8832],[-95.248,48.8836],[-95.2472,48.8835],[-95.2458,48.8829],[-95.2439,48.8823],[-95.2429,48.8822],[-95.2429,48.8822],[-95.2423,48.8821],[-95.2407,48.8821],[-95.2391,48.8819],[-95.2381,48.8817],[-95.2356,48.8815],[-95.2335,48.8814],[-95.231,48.8814],[-95.2287,48.8815],[-95.2265,48.8816],[-95.2252,48.8819],[-95.2212,48.883],[-95.2208,48.8831],[-95.2207,48.8831],[-95.22,48.8831],[-95.2193,48.8832],[-95.2188,48.8835],[-95.217,48.8835],[-95.2159,48.8839],[-95.2151,48.884],[-95.2144,48.8843],[-95.2122,48.8842],[-95.2117,48.8847],[-95.2115,48.8847],[-95.2112,48.8848],[-95.2085,48.8846],[-95.2059,48.8848],[-95.2024,48.8852],[-95.2009,48.8855],[-95.2005,48.8856],[-95.1986,48.8855],[-95.1956,48.8862],[-95.1924,48.8865],[-95.1919,48.8866],[-95.1913,48.8868],[-95.1901,48.887],[-95.1889,48.8873],[-95.1877,48.8874],[-95.1863,48.8877],[-95.1851,48.8882],[-95.1819,48.8888],[-95.1797,48.889],[-95.1791,48.889],[-95.1764,48.8893],[-95.173,48.8897],[-95.1701,48.8902],[-95.1674,48.8907],[-95.1648,48.8913],[-95.1641,48.8917],[-95.1618,48.892],[-95.1602,48.892],[-95.1579,48.8919],[-95.1564,48.8919],[-95.1555,48.892],[-95.1528,48.8921],[-95.1508,48.8922],[-95.1483,48.8923],[-95.1469,48.8927],[-95.1459,48.8929],[-95.1438,48.8934],[-95.1436,48.8937],[-95.1404,48.8943],[-95.1381,48.8949],[-95.1355,48.8959],[-95.1351,48.8963],[-95.1348,48.8963],[-95.1343,48.8963],[-95.1337,48.8969],[-95.1322,48.8973],[-95.1312,48.8975],[-95.1252,48.8998],[-95.1239,48.9001],[-95.1233,48.9004],[-95.1228,48.9006],[-95.1214,48.9013],[-95.121,48.9016],[-95.1205,48.9017],[-95.1204,48.9019],[-95.1182,48.9029],[-95.1163,48.9037],[-95.1151,48.9046],[-95.1144,48.9052],[-95.114,48.9061],[-95.1141,48.9064],[-95.1137,48.9069],[-95.1132,48.9071],[-95.113,48.9072],[-95.1126,48.9073],[-95.1107,48.9082],[-95.1096,48.9089],[-95.108,48.9099],[-95.1056,48.9113],[-95.1042,48.9121],[-95.1032,48.9127],[-95.102,48.9132],[-95.1008,48.9142],[-95.0981,48.9159],[-95.098,48.916],[-95.0975,48.9164],[-95.0971,48.9172],[-95.097,48.9176],[-95.0961,48.9181],[-95.0946,48.9191],[-95.0944,48.9193],[-95.0927,48.9204],[-95.0919,48.9207],[-95.0914,48.9208],[-95.0914,48.916],[-95.0912,48.9014],[-95.0911,48.8869],[-95.0908,48.8724],[-95.0908,48.858],[-95.0907,48.8436],[-95.0908,48.8291],[-95.0909,48.8147],[-95.0903,48.8],[-95.0903,48.7855],[-95.0903,48.7711],[-95.0901,48.7566],[-95.0901,48.7421],[-95.0899,48.7277],[-95.0898,48.713],[-95.1046,48.7129],[-95.1104,48.7129],[-95.1119,48.7129],[-95.1259,48.7129],[-95.1297,48.713],[-95.1333,48.713],[-95.1477,48.7129],[-95.1554,48.7129],[-95.1697,48.7129],[-95.1773,48.713],[-95.1917,48.713],[-95.1991,48.713],[-95.2112,48.713],[-95.2206,48.713],[-95.2331,48.713],[-95.2427,48.713],[-95.255,48.713],[-95.2645,48.713],[-95.2656,48.713],[-95.2767,48.713],[-95.2866,48.713],[-95.299,48.713],[-95.3051,48.713],[-95.3084,48.713],[-95.3205,48.713],[-95.3302,48.713],[-95.3425,48.7131],[-95.3425,48.6995],[-95.3424,48.6849],[-95.3423,48.6705],[-95.3424,48.6561],[-95.3425,48.6415],[-95.3426,48.6271],[-95.3424,48.6127],[-95.3426,48.5979],[-95.3423,48.5836],[-95.3423,48.5691],[-95.3424,48.5548],[-95.3425,48.5402],[-95.3628,48.5404],[-95.364,48.5403],[-95.3844,48.5402],[-95.386,48.5402],[-95.4061,48.5402],[-95.4078,48.5402],[-95.4279,48.54],[-95.4297,48.5399],[-95.4494,48.5399],[-95.4513,48.5399],[-95.4712,48.5396],[-95.4726,48.5396],[-95.493,48.5392],[-95.495,48.5392],[-95.5143,48.539],[-95.5163,48.539],[-95.5365,48.5389],[-95.5383,48.5389],[-95.558,48.5388],[-95.5603,48.5388],[-95.5801,48.5387],[-95.5821,48.5387],[-95.6023,48.5389],[-95.6232,48.5391],[-95.6447,48.5393],[-95.6666,48.5394],[-95.6886,48.5395],[-95.7102,48.5395],[-95.7322,48.54],[-95.7539,48.5404],[-95.7758,48.5406],[-95.7976,48.5405],[-95.8192,48.5404],[-95.8411,48.5406],[-95.8621,48.5414],[-95.8829,48.5419],[-95.8851,48.542],[-95.8986,48.5421],[-95.9046,48.5422],[-95.9064,48.5422],[-95.9269,48.5421],[-95.9486,48.5425],[-95.9498,48.5425],[-95.9704,48.543],[-95.9936,48.5435],[-96.0157,48.5437],[-96.0374,48.5438],[-96.0592,48.5437],[-96.0812,48.5436],[-96.1026,48.5438],[-96.1264,48.5439],[-96.1486,48.5442],[-96.1702,48.5445],[-96.1921,48.5446],[-96.2141,48.5449],[-96.2358,48.5452],[-96.2576,48.545],[-96.2794,48.5449],[-96.301,48.5448],[-96.3231,48.5446],[-96.3448,48.5444],[-96.3667,48.5443],[-96.3882,48.5442],[-96.3879,48.5588],[-96.3882,48.5733],[-96.3884,48.5877],[-96.3891,48.6024],[-96.389,48.6165],[-96.388,48.6313],[-96.3879,48.6454],[-96.3877,48.6599],[-96.3871,48.6741],[-96.3874,48.6887],[-96.3866,48.703],[-96.3873,48.7172],[-96.388,48.7172],[-96.4049,48.7172],[-96.4048,48.7318],[-96.4048,48.7465],[-96.4047,48.7607],[-96.4045,48.7758],[-96.4042,48.7903],[-96.4042,48.8048],[-96.4042,48.8198],[-96.4043,48.8343],[-96.4045,48.8491],[-96.4047,48.8635],[-96.405,48.878],[-96.405,48.8926],[-96.4053,48.9068],[-96.4053,48.9081],[-96.4053,48.9137],[-96.4054,48.9214],[-96.4054,48.9225],[-96.4053,48.936],[-96.4053,48.9371],[-96.4053,48.9504],[-96.4053,48.9515],[-96.4053,48.9648],[-96.4053,48.9658],[-96.4053,48.9705],[-96.4054,48.9793],[-96.4054,48.9803],[-96.4054,48.994],[-96.4054,48.9947],[-96.4054,49.0001]]],"type":"Polygon"},"id":"68","properties":{"Area":4347098503.12714,"CTYONLY_":4,"Code":"ROSE","LASTMOD":"2001-04-12T09:32:44Z","Name":"Roseau","Perimiter":302590.75293},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&filter=%7B%22op%22%3A%22%3D%22%2C%22args%22%3A%5B%7B%22property%22%3A%22CTYONLY_%22%7D%2C%7B%22op%22%3A%22div%22%2C%22args%22%3A%5B12%2C3%5D%7D%5D%7D&filter-lang=cql2-json","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&filter=%7B%22op%22%3A%22%3D%22%2C%22args%22%3A%5B%7B%22property%22%3A%22CTYONLY_%22%7D%2C%7B%22op%22%3A%22div%22%2C%22args%22%3A%5B12%2C3%5D%7D%5D%7D&filter-lang=cql2-json","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":1,"numberReturned":1,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_json_empty_dict.json.txt b/msautotest/api/expected/ogcapi_cql2_json_empty_dict.json.txt new file mode 100644 index 0000000000..023bdf1030 --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_json_empty_dict.json.txt @@ -0,0 +1,4 @@ +Content-Type: application/json +Status: 400 + +{"code":"InvalidParameterValue","description":"Cannot parse filter: Missing \"op\" member"} diff --git a/msautotest/api/expected/ogcapi_cql2_json_equal.json.txt b/msautotest/api/expected/ogcapi_cql2_json_equal.json.txt new file mode 100644 index 0000000000..7e89eebde3 --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_json_equal.json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 1 +OGC-NumberReturned: 1 + +{"features":[{"geometry":{"coordinates":[[[-93.5242,44.5436],[-93.5225,44.5436],[-93.504,44.5438],[-93.5018,44.5438],[-93.4835,44.5438],[-93.4817,44.5438],[-93.4734,44.5438],[-93.4632,44.5438],[-93.4609,44.5438],[-93.4429,44.5438],[-93.4408,44.5438],[-93.4326,44.5438],[-93.4226,44.5439],[-93.4206,44.5439],[-93.4024,44.5439],[-93.4003,44.5439],[-93.383,44.544],[-93.38,44.544],[-93.3627,44.5441],[-93.3596,44.5441],[-93.3556,44.5441],[-93.3424,44.5442],[-93.3395,44.5442],[-93.3221,44.544],[-93.3191,44.544],[-93.3128,44.544],[-93.3019,44.544],[-93.2988,44.544],[-93.2813,44.544],[-93.2814,44.5298],[-93.2815,44.5153],[-93.2815,44.501],[-93.2815,44.4865],[-93.2817,44.472],[-93.2618,44.4718],[-93.2415,44.4716],[-93.2213,44.4714],[-93.2008,44.4714],[-93.1808,44.4713],[-93.1605,44.4713],[-93.1408,44.4712],[-93.1206,44.4713],[-93.1002,44.4718],[-93.0799,44.4719],[-93.0597,44.4718],[-93.0393,44.4719],[-93.0394,44.4576],[-93.0396,44.4432],[-93.0397,44.4287],[-93.0399,44.4143],[-93.04,44.3999],[-93.0401,44.3855],[-93.0402,44.371],[-93.0403,44.3565],[-93.0403,44.3419],[-93.0405,44.3273],[-93.0405,44.3129],[-93.0405,44.2983],[-93.0406,44.2838],[-93.0407,44.2693],[-93.0409,44.2548],[-93.041,44.2402],[-93.0411,44.2257],[-93.0411,44.2113],[-93.0411,44.1968],[-93.0427,44.1968],[-93.0459,44.1968],[-93.0613,44.1967],[-93.0661,44.1967],[-93.0815,44.1967],[-93.0862,44.1967],[-93.1003,44.1967],[-93.1015,44.1967],[-93.1063,44.1967],[-93.1092,44.1967],[-93.1218,44.1967],[-93.1267,44.1967],[-93.1301,44.1967],[-93.1418,44.1967],[-93.1467,44.1967],[-93.1561,44.1966],[-93.1622,44.1966],[-93.1661,44.1966],[-93.1703,44.1966],[-93.1822,44.1966],[-93.1856,44.1966],[-93.1865,44.1966],[-93.2023,44.1966],[-93.2037,44.1966],[-93.2064,44.1966],[-93.2225,44.1966],[-93.2265,44.1966],[-93.2292,44.1966],[-93.2426,44.1966],[-93.2465,44.1966],[-93.255,44.1966],[-93.2629,44.1966],[-93.2664,44.1966],[-93.2767,44.1966],[-93.283,44.1966],[-93.2865,44.1965],[-93.2905,44.1965],[-93.3032,44.1965],[-93.3063,44.1965],[-93.3235,44.1965],[-93.3264,44.1965],[-93.3277,44.1965],[-93.3436,44.1965],[-93.3466,44.1965],[-93.3639,44.1965],[-93.3666,44.1965],[-93.3842,44.1965],[-93.3866,44.1965],[-93.4042,44.1965],[-93.4065,44.1965],[-93.4244,44.1964],[-93.4267,44.1964],[-93.4447,44.1964],[-93.4469,44.1964],[-93.4648,44.1963],[-93.467,44.1963],[-93.4852,44.1964],[-93.4872,44.1964],[-93.5053,44.1963],[-93.507,44.1963],[-93.5255,44.1962],[-93.5253,44.2107],[-93.5251,44.2251],[-93.5251,44.2388],[-93.5251,44.2533],[-93.5252,44.2685],[-93.5252,44.2829],[-93.5252,44.2975],[-93.5252,44.312],[-93.5249,44.3266],[-93.5249,44.3411],[-93.5245,44.3557],[-93.5245,44.3704],[-93.5246,44.3848],[-93.5245,44.3994],[-93.5245,44.4138],[-93.5245,44.4283],[-93.5245,44.4427],[-93.5245,44.4572],[-93.5244,44.4717],[-93.5245,44.4862],[-93.5244,44.5007],[-93.5243,44.5152],[-93.5244,44.5297],[-93.5242,44.5436]]],"type":"Polygon"},"id":"66","properties":{"Area":1335114621.00336,"CTYONLY_":66,"Code":"RICE","LASTMOD":"2010-10-17T00:00:00Z","Name":"Rice","Perimiter":154431.78788},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&filter=%7B%22op%22%3A%22%3D%22%2C%22args%22%3A%5B%7B%22property%22%3A%22Name%22%7D%2C%22Rice%22%5D%7D&filter-lang=cql2-json","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&filter=%7B%22op%22%3A%22%3D%22%2C%22args%22%3A%5B%7B%22property%22%3A%22Name%22%7D%2C%22Rice%22%5D%7D&filter-lang=cql2-json","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":1,"numberReturned":1,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_json_false_or_false.json.txt b/msautotest/api/expected/ogcapi_cql2_json_false_or_false.json.txt new file mode 100644 index 0000000000..72d43234dd --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_json_false_or_false.json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 0 +OGC-NumberReturned: 0 + +{"features":[],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&filter=%7B%22op%22%3A%22and%22%2C%22args%22%3A%5Bfalse%2Cfalse%5D%7D&filter-lang=cql2-json","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&filter=%7B%22op%22%3A%22and%22%2C%22args%22%3A%5Bfalse%2Cfalse%5D%7D&filter-lang=cql2-json","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":0,"numberReturned":0,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_json_false_or_true.json.txt b/msautotest/api/expected/ogcapi_cql2_json_false_or_true.json.txt new file mode 100644 index 0000000000..78fa85e8d1 --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_json_false_or_true.json.txt @@ -0,0 +1,9 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +Link: ; rel="next"; title="next page"; type="application/geo+json" +OGC-NumberMatched: 117 +OGC-NumberReturned: 1 + +{"features":[{"geometry":{"coordinates":[[[-95.3231,48.999],[-95.3109,48.999],[-95.2889,48.9989],[-95.2852,48.9989],[-95.2669,48.9989],[-95.245,48.9989],[-95.2232,48.9989],[-95.2014,48.9989],[-95.1792,48.9989],[-95.1574,48.9989],[-95.1531,48.9989],[-95.1531,49.0031],[-95.1532,49.0179],[-95.1532,49.0325],[-95.1532,49.047],[-95.1532,49.0619],[-95.1532,49.0765],[-95.1532,49.0911],[-95.1532,49.1057],[-95.1532,49.1205],[-95.1532,49.1354],[-95.1532,49.1499],[-95.1532,49.1642],[-95.1532,49.1788],[-95.1532,49.1807],[-95.1532,49.1931],[-95.1532,49.1966],[-95.1532,49.2077],[-95.1533,49.2131],[-95.1533,49.2219],[-95.1533,49.2308],[-95.1533,49.2365],[-95.1533,49.2472],[-95.1533,49.2512],[-95.1533,49.2655],[-95.1533,49.2697],[-95.1533,49.2802],[-95.1533,49.2882],[-95.1533,49.2945],[-95.1533,49.3072],[-95.1533,49.309],[-95.1533,49.3234],[-95.1533,49.3237],[-95.1533,49.3381],[-95.1533,49.3476],[-95.1533,49.3525],[-95.1533,49.3636],[-95.1533,49.367],[-95.1533,49.3705],[-95.1533,49.3776],[-95.1533,49.3813],[-95.1533,49.3845],[-95.1503,49.383],[-95.1499,49.3813],[-95.1498,49.3807],[-95.1467,49.3802],[-95.145,49.3784],[-95.1418,49.3784],[-95.1397,49.3762],[-95.1367,49.3751],[-95.1324,49.3736],[-95.1287,49.3705],[-95.1171,49.367],[-95.1159,49.3666],[-95.1145,49.3666],[-95.1098,49.3664],[-95.1031,49.3652],[-95.1031,49.3636],[-95.0926,49.3617],[-95.0897,49.3612],[-95.0707,49.3564],[-95.0582,49.3533],[-95.0495,49.3532],[-95.0479,49.3533],[-95.0262,49.3554],[-95.0141,49.3565],[-95.0047,49.3612],[-94.993,49.367],[-94.9889,49.369],[-94.9818,49.3684],[-94.9742,49.3678],[-94.9597,49.3699],[-94.9573,49.3702],[-94.952,49.3688],[-94.948,49.367],[-94.9376,49.3625],[-94.9152,49.3529],[-94.9143,49.3524],[-94.909,49.3502],[-94.9065,49.3484],[-94.8933,49.3414],[-94.8865,49.3378],[-94.8782,49.3334],[-94.8712,49.3308],[-94.854,49.3244],[-94.8492,49.3244],[-94.8363,49.3243],[-94.8311,49.3236],[-94.8271,49.323],[-94.8162,49.3214],[-94.8243,49.309],[-94.8243,49.3088],[-94.8255,49.2944],[-94.8255,49.2943],[-94.8204,49.28],[-94.8152,49.2653],[-94.8103,49.2515],[-94.8059,49.2388],[-94.8051,49.2367],[-94.8001,49.2224],[-94.7973,49.2144],[-94.7975,49.2079],[-94.7979,49.1979],[-94.7965,49.1936],[-94.7918,49.1792],[-94.7871,49.1646],[-94.7833,49.153],[-94.7823,49.15],[-94.7776,49.1357],[-94.7727,49.1206],[-94.7727,49.1206],[-94.7611,49.1096],[-94.7571,49.1058],[-94.7496,49.0988],[-94.7474,49.0918],[-94.7429,49.0773],[-94.7394,49.0657],[-94.7385,49.063],[-94.7344,49.0497],[-94.7299,49.0351],[-94.7254,49.0205],[-94.7207,49.0052],[-94.7184,48.9979],[-94.7162,48.9907],[-94.7117,48.9761],[-94.7072,48.9615],[-94.7027,48.9468],[-94.6982,48.9322],[-94.6968,48.9276],[-94.6844,48.8875],[-94.6834,48.8842],[-94.6842,48.8724],[-94.6855,48.8719],[-94.6923,48.8691],[-94.6902,48.8636],[-94.6914,48.8591],[-94.693,48.8535],[-94.6881,48.8447],[-94.6855,48.8401],[-94.6963,48.836],[-94.6975,48.8355],[-94.702,48.8319],[-94.7025,48.8302],[-94.7042,48.8243],[-94.6991,48.8159],[-94.6962,48.8111],[-94.6951,48.8092],[-94.6958,48.8012],[-94.6959,48.7997],[-94.6944,48.7895],[-94.6934,48.7864],[-94.6909,48.7781],[-94.687,48.7752],[-94.6776,48.772],[-94.6768,48.7717],[-94.6746,48.7705],[-94.6671,48.7662],[-94.6603,48.7605],[-94.6557,48.7581],[-94.6525,48.7565],[-94.652,48.7562],[-94.6453,48.7491],[-94.6453,48.7441],[-94.6443,48.7434],[-94.6414,48.7413],[-94.631,48.7392],[-94.6301,48.739],[-94.6191,48.7373],[-94.6106,48.7318],[-94.6084,48.731],[-94.6028,48.7289],[-94.6011,48.7283],[-94.5962,48.7248],[-94.5913,48.7197],[-94.5876,48.7176],[-94.5867,48.7175],[-94.5685,48.7156],[-94.5622,48.7159],[-94.5558,48.7163],[-94.549,48.7148],[-94.5487,48.7146],[-94.5457,48.7124],[-94.5396,48.7036],[-94.539,48.7028],[-94.5329,48.7013],[-94.5247,48.7016],[-94.5178,48.7008],[-94.5173,48.7008],[-94.5093,48.7006],[-94.5066,48.6999],[-94.4996,48.698],[-94.4958,48.698],[-94.4863,48.698],[-94.4739,48.6969],[-94.4706,48.6966],[-94.4631,48.6953],[-94.4568,48.6933],[-94.4523,48.6925],[-94.4517,48.6925],[-94.4465,48.693],[-94.4388,48.6949],[-94.4319,48.6998],[-94.4299,48.7012],[-94.4299,48.6998],[-94.43,48.6852],[-94.4301,48.6708],[-94.43,48.6564],[-94.4297,48.642],[-94.4294,48.6276],[-94.4292,48.6133],[-94.4289,48.5988],[-94.4289,48.5844],[-94.4291,48.5698],[-94.4295,48.5554],[-94.43,48.5409],[-94.4303,48.5264],[-94.4303,48.512],[-94.4299,48.4977],[-94.4296,48.4832],[-94.4296,48.4688],[-94.4293,48.4543],[-94.4292,48.4399],[-94.4293,48.4254],[-94.4294,48.411],[-94.4293,48.3964],[-94.4289,48.3821],[-94.4288,48.3675],[-94.4471,48.3675],[-94.4505,48.3675],[-94.4688,48.3675],[-94.4722,48.3674],[-94.4906,48.3674],[-94.4924,48.3674],[-94.4941,48.3674],[-94.5118,48.3675],[-94.5157,48.3674],[-94.5335,48.3674],[-94.5378,48.3674],[-94.5536,48.3674],[-94.5593,48.3674],[-94.5754,48.3674],[-94.5812,48.3674],[-94.5971,48.3675],[-94.6029,48.3674],[-94.6188,48.3673],[-94.6245,48.3673],[-94.6405,48.3673],[-94.6465,48.3673],[-94.6505,48.3673],[-94.6622,48.3673],[-94.6679,48.3673],[-94.6694,48.3672],[-94.683,48.3671],[-94.6898,48.3671],[-94.7099,48.3669],[-94.7117,48.3668],[-94.7315,48.3669],[-94.7329,48.3669],[-94.7533,48.3669],[-94.7549,48.3669],[-94.7748,48.3669],[-94.7765,48.3669],[-94.7967,48.3669],[-94.7983,48.3669],[-94.8183,48.3669],[-94.8199,48.3669],[-94.8399,48.3669],[-94.8416,48.3669],[-94.8616,48.3667],[-94.8632,48.3667],[-94.8833,48.3667],[-94.8849,48.3666],[-94.9049,48.3666],[-94.9065,48.3666],[-94.9264,48.3667],[-94.9283,48.3667],[-94.9469,48.3666],[-94.95,48.3666],[-94.9684,48.3667],[-94.9716,48.3667],[-94.9901,48.3667],[-94.9932,48.3667],[-95.0119,48.3665],[-95.0153,48.3665],[-95.0337,48.3665],[-95.0369,48.3665],[-95.0555,48.3665],[-95.0586,48.3665],[-95.0773,48.3664],[-95.0801,48.3664],[-95.099,48.3663],[-95.1008,48.3663],[-95.1018,48.3663],[-95.1207,48.3663],[-95.1236,48.3663],[-95.1315,48.3662],[-95.1424,48.3662],[-95.1454,48.3662],[-95.164,48.3661],[-95.1669,48.3661],[-95.1861,48.3661],[-95.1887,48.3661],[-95.1983,48.3661],[-95.2066,48.3661],[-95.2106,48.3661],[-95.211,48.3797],[-95.211,48.3808],[-95.2111,48.3941],[-95.2111,48.3952],[-95.2112,48.4087],[-95.2112,48.4096],[-95.2113,48.4232],[-95.2113,48.4242],[-95.2113,48.4255],[-95.2113,48.4376],[-95.2113,48.4387],[-95.2113,48.4522],[-95.2112,48.4529],[-95.211,48.4666],[-95.211,48.4673],[-95.2111,48.4816],[-95.2112,48.4962],[-95.2111,48.5101],[-95.2111,48.5109],[-95.2115,48.5244],[-95.2115,48.5252],[-95.2119,48.54],[-95.2324,48.5399],[-95.2339,48.5399],[-95.2537,48.5398],[-95.2554,48.5398],[-95.2756,48.54],[-95.2773,48.54],[-95.2975,48.5401],[-95.2992,48.5402],[-95.3194,48.54],[-95.321,48.54],[-95.3412,48.5402],[-95.3425,48.5402],[-95.3424,48.5548],[-95.3423,48.5691],[-95.3423,48.5836],[-95.3426,48.5979],[-95.3424,48.6127],[-95.3426,48.6271],[-95.3425,48.6415],[-95.3424,48.6561],[-95.3423,48.6705],[-95.3424,48.6849],[-95.3425,48.6995],[-95.3425,48.7131],[-95.3302,48.713],[-95.3205,48.713],[-95.3084,48.713],[-95.3051,48.713],[-95.299,48.713],[-95.2866,48.713],[-95.2767,48.713],[-95.2656,48.713],[-95.2645,48.713],[-95.255,48.713],[-95.2427,48.713],[-95.2331,48.713],[-95.2206,48.713],[-95.2112,48.713],[-95.1991,48.713],[-95.1917,48.713],[-95.1773,48.713],[-95.1697,48.7129],[-95.1554,48.7129],[-95.1477,48.7129],[-95.1333,48.713],[-95.1297,48.713],[-95.1259,48.7129],[-95.1119,48.7129],[-95.1104,48.7129],[-95.1046,48.7129],[-95.0898,48.713],[-95.0899,48.7277],[-95.0901,48.7421],[-95.0901,48.7566],[-95.0903,48.7711],[-95.0903,48.7855],[-95.0903,48.8],[-95.0909,48.8147],[-95.0908,48.8291],[-95.0907,48.8436],[-95.0908,48.858],[-95.0908,48.8724],[-95.0911,48.8869],[-95.0912,48.9014],[-95.0914,48.916],[-95.0914,48.9208],[-95.0919,48.9207],[-95.0927,48.9204],[-95.0944,48.9193],[-95.0946,48.9191],[-95.0961,48.9181],[-95.097,48.9176],[-95.0971,48.9172],[-95.0975,48.9164],[-95.098,48.916],[-95.0981,48.9159],[-95.1008,48.9142],[-95.102,48.9132],[-95.1032,48.9127],[-95.1042,48.9121],[-95.1056,48.9113],[-95.108,48.9099],[-95.1096,48.9089],[-95.1107,48.9082],[-95.1126,48.9073],[-95.113,48.9072],[-95.1132,48.9071],[-95.1137,48.9069],[-95.1141,48.9064],[-95.114,48.9061],[-95.1144,48.9052],[-95.1151,48.9046],[-95.1163,48.9037],[-95.1182,48.9029],[-95.1204,48.9019],[-95.1205,48.9017],[-95.121,48.9016],[-95.1214,48.9013],[-95.1228,48.9006],[-95.1233,48.9004],[-95.1239,48.9001],[-95.1252,48.8998],[-95.1312,48.8975],[-95.1322,48.8973],[-95.1337,48.8969],[-95.1343,48.8963],[-95.1348,48.8963],[-95.1351,48.8963],[-95.1355,48.8959],[-95.1381,48.8949],[-95.1404,48.8943],[-95.1436,48.8937],[-95.1438,48.8934],[-95.1459,48.8929],[-95.1469,48.8927],[-95.1483,48.8923],[-95.1508,48.8922],[-95.1528,48.8921],[-95.1555,48.892],[-95.1564,48.8919],[-95.1579,48.8919],[-95.1602,48.892],[-95.1618,48.892],[-95.1641,48.8917],[-95.1648,48.8913],[-95.1674,48.8907],[-95.1701,48.8902],[-95.173,48.8897],[-95.1764,48.8893],[-95.1791,48.889],[-95.1797,48.889],[-95.1819,48.8888],[-95.1851,48.8882],[-95.1863,48.8877],[-95.1877,48.8874],[-95.1889,48.8873],[-95.1901,48.887],[-95.1913,48.8868],[-95.1919,48.8866],[-95.1924,48.8865],[-95.1956,48.8862],[-95.1986,48.8855],[-95.2005,48.8856],[-95.2009,48.8855],[-95.2024,48.8852],[-95.2059,48.8848],[-95.2085,48.8846],[-95.2112,48.8848],[-95.2115,48.8847],[-95.2117,48.8847],[-95.2122,48.8842],[-95.2144,48.8843],[-95.2151,48.884],[-95.2159,48.8839],[-95.217,48.8835],[-95.2188,48.8835],[-95.2193,48.8832],[-95.22,48.8831],[-95.2207,48.8831],[-95.2208,48.8831],[-95.2212,48.883],[-95.2252,48.8819],[-95.2265,48.8816],[-95.2287,48.8815],[-95.231,48.8814],[-95.2335,48.8814],[-95.2356,48.8815],[-95.2381,48.8817],[-95.2391,48.8819],[-95.2407,48.8821],[-95.2423,48.8821],[-95.2429,48.8822],[-95.2429,48.8822],[-95.2439,48.8823],[-95.2458,48.8829],[-95.2472,48.8835],[-95.248,48.8836],[-95.2485,48.8832],[-95.2496,48.8834],[-95.2502,48.8835],[-95.2507,48.8836],[-95.2517,48.8839],[-95.2548,48.8845],[-95.256,48.885],[-95.257,48.8858],[-95.2585,48.8867],[-95.2585,48.8867],[-95.2627,48.8877],[-95.2635,48.888],[-95.2639,48.8883],[-95.2646,48.8885],[-95.265,48.8886],[-95.2654,48.8888],[-95.2666,48.8894],[-95.2674,48.89],[-95.2677,48.8903],[-95.268,48.8905],[-95.2713,48.8915],[-95.2724,48.8921],[-95.2745,48.8931],[-95.2751,48.8938],[-95.2753,48.8943],[-95.2748,48.8951],[-95.2749,48.8956],[-95.2755,48.8959],[-95.2759,48.8962],[-95.2763,48.8963],[-95.2765,48.8962],[-95.277,48.8958],[-95.2773,48.8957],[-95.2782,48.8956],[-95.279,48.8957],[-95.2796,48.8962],[-95.2803,48.8965],[-95.2813,48.8967],[-95.2839,48.8975],[-95.2853,48.8977],[-95.2861,48.8976],[-95.2865,48.8975],[-95.287,48.8976],[-95.2872,48.8977],[-95.2879,48.8979],[-95.2882,48.8981],[-95.289,48.8994],[-95.2896,48.9],[-95.2901,48.9003],[-95.2911,48.9006],[-95.2911,48.9008],[-95.2906,48.9011],[-95.2907,48.9014],[-95.2908,48.9016],[-95.2909,48.9017],[-95.2914,48.9019],[-95.2927,48.9019],[-95.2935,48.902],[-95.2937,48.9023],[-95.2941,48.9027],[-95.2949,48.9028],[-95.2967,48.9027],[-95.2976,48.9026],[-95.298,48.9027],[-95.2983,48.9028],[-95.2993,48.9035],[-95.3005,48.904],[-95.3002,48.9045],[-95.3001,48.9046],[-95.3001,48.9047],[-95.3,48.9047],[-95.3,48.9047],[-95.2999,48.9048],[-95.2999,48.9048],[-95.2999,48.9048],[-95.2997,48.905],[-95.2996,48.9051],[-95.2994,48.9053],[-95.2992,48.9055],[-95.2991,48.9057],[-95.2989,48.906],[-95.2988,48.906],[-95.2986,48.9063],[-95.2985,48.9064],[-95.2985,48.9065],[-95.2983,48.9068],[-95.2982,48.9068],[-95.2981,48.907],[-95.298,48.9071],[-95.298,48.9071],[-95.298,48.9071],[-95.2979,48.9071],[-95.2979,48.9072],[-95.2979,48.9072],[-95.2978,48.9072],[-95.2978,48.9072],[-95.2978,48.9073],[-95.2977,48.9073],[-95.2976,48.9074],[-95.2973,48.9077],[-95.2973,48.908],[-95.2973,48.9081],[-95.2978,48.9083],[-95.2999,48.9086],[-95.3017,48.9093],[-95.3027,48.91],[-95.3038,48.9114],[-95.3043,48.9119],[-95.3059,48.9127],[-95.3061,48.9128],[-95.3064,48.9129],[-95.3074,48.9135],[-95.3078,48.9141],[-95.3085,48.9146],[-95.3092,48.9149],[-95.3093,48.9149],[-95.3102,48.9155],[-95.3109,48.9163],[-95.3115,48.9172],[-95.3119,48.9178],[-95.3126,48.919],[-95.3132,48.9198],[-95.3141,48.921],[-95.315,48.9222],[-95.3168,48.9245],[-95.3195,48.9285],[-95.3208,48.9305],[-95.3209,48.9307],[-95.3222,48.9327],[-95.3228,48.9344],[-95.3223,48.9355],[-95.3225,48.9358],[-95.3229,48.9373],[-95.3231,48.9389],[-95.3228,48.9403],[-95.3225,48.9409],[-95.3219,48.9412],[-95.3189,48.9419],[-95.3181,48.9421],[-95.3168,48.9431],[-95.3154,48.9448],[-95.3148,48.9452],[-95.3141,48.9457],[-95.3131,48.946],[-95.3114,48.9461],[-95.3102,48.9463],[-95.3095,48.9463],[-95.3088,48.9464],[-95.3086,48.9465],[-95.3086,48.9469],[-95.3085,48.947],[-95.3078,48.9466],[-95.3074,48.9465],[-95.3071,48.9466],[-95.3071,48.9469],[-95.3079,48.9474],[-95.3092,48.9477],[-95.3096,48.9478],[-95.3103,48.948],[-95.3104,48.9484],[-95.3103,48.9485],[-95.31,48.9485],[-95.3099,48.9484],[-95.3096,48.9482],[-95.3094,48.9481],[-95.3081,48.948],[-95.3071,48.9477],[-95.3062,48.9472],[-95.3062,48.9472],[-95.3061,48.9469],[-95.3062,48.9463],[-95.3063,48.9462],[-95.3069,48.9456],[-95.3069,48.9455],[-95.3068,48.9454],[-95.3061,48.9454],[-95.3053,48.9459],[-95.305,48.9462],[-95.3046,48.947],[-95.3046,48.9482],[-95.3052,48.9495],[-95.3061,48.9502],[-95.3079,48.9509],[-95.3089,48.9511],[-95.3097,48.951],[-95.3104,48.951],[-95.3108,48.9512],[-95.3115,48.952],[-95.312,48.9524],[-95.3126,48.9524],[-95.3129,48.9523],[-95.3129,48.9521],[-95.3119,48.9507],[-95.3119,48.9502],[-95.3123,48.9502],[-95.3125,48.9503],[-95.3131,48.9503],[-95.3141,48.9508],[-95.3151,48.951],[-95.3154,48.9513],[-95.3177,48.9525],[-95.3181,48.9531],[-95.3182,48.9535],[-95.3177,48.9545],[-95.3175,48.9552],[-95.3179,48.9559],[-95.3188,48.9562],[-95.3191,48.9569],[-95.3202,48.9581],[-95.3206,48.959],[-95.3206,48.9595],[-95.3206,48.9598],[-95.3202,48.9606],[-95.3193,48.9622],[-95.3193,48.964],[-95.3198,48.9643],[-95.3201,48.9648],[-95.3207,48.9669],[-95.3212,48.9672],[-95.3227,48.9685],[-95.3232,48.9692],[-95.3241,48.9703],[-95.3247,48.972],[-95.3248,48.9728],[-95.3249,48.9738],[-95.325,48.9743],[-95.3253,48.976],[-95.3257,48.9784],[-95.3255,48.9789],[-95.3256,48.98],[-95.3257,48.9814],[-95.3253,48.9832],[-95.3245,48.985],[-95.3242,48.9859],[-95.3227,48.9884],[-95.3224,48.9889],[-95.3206,48.9921],[-95.3204,48.9924],[-95.3191,48.9941],[-95.3181,48.995],[-95.3178,48.9958],[-95.3178,48.9961],[-95.3179,48.9961],[-95.3182,48.996],[-95.3187,48.9956],[-95.3191,48.9953],[-95.3197,48.9954],[-95.3201,48.9956],[-95.3206,48.9961],[-95.3204,48.9964],[-95.3202,48.9973],[-95.3204,48.9976],[-95.3224,48.9984],[-95.3231,48.999]]],"type":"Polygon"},"id":"39","properties":{"Area":4608320923.49768,"CTYONLY_":2,"Code":"LOTW","LASTMOD":"1976-07-04T12:00:00Z","Name":"Lake of the Woods","Perimiter":388250.14572},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=1&offset=0&filter=%7B%22op%22%3A%22or%22%2C%22args%22%3A%5Bfalse%2Ctrue%5D%7D&filter-lang=cql2-json","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=1&offset=0&filter=%7B%22op%22%3A%22or%22%2C%22args%22%3A%5Bfalse%2Ctrue%5D%7D&filter-lang=cql2-json","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=1&offset=1&filter=%7B%22op%22%3A%22or%22%2C%22args%22%3A%5Bfalse%2Ctrue%5D%7D&filter-lang=cql2-json","rel":"next","title":"next page","type":"application/geo+json"}],"numberMatched":117,"numberReturned":1,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_json_ge.json.txt b/msautotest/api/expected/ogcapi_cql2_json_ge.json.txt new file mode 100644 index 0000000000..abf856da35 --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_json_ge.json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 2 +OGC-NumberReturned: 2 + +{"features":[{"geometry":{"coordinates":[[[-91.267,47.2703],[-91.267,47.2703],[-91.2669,47.2703],[-91.2668,47.2703],[-91.2666,47.2703],[-91.2665,47.2702],[-91.2666,47.2701],[-91.2666,47.2701],[-91.2668,47.2701],[-91.267,47.2702],[-91.267,47.2703]]],"type":"Polygon"},"id":"38","properties":{"Area":691.59892,"CTYONLY_":117,"Code":"LAKE","LASTMOD":"2003-01-01T01:10:00Z","Name":"Lake","Perimiter":103.08393},"type":"Feature"},{"geometry":{"coordinates":[[[-91.2824,47.2658],[-91.2823,47.2658],[-91.2822,47.2658],[-91.282,47.2659],[-91.2819,47.2659],[-91.2818,47.2659],[-91.2818,47.2658],[-91.2818,47.2658],[-91.2821,47.2657],[-91.2824,47.2655],[-91.2825,47.2654],[-91.2826,47.2654],[-91.2827,47.2654],[-91.2828,47.2655],[-91.2827,47.2657],[-91.2825,47.2658],[-91.2824,47.2658]]],"type":"Polygon"},"id":"38","properties":{"Area":2024.76285,"CTYONLY_":118,"Code":"LAKE","LASTMOD":"2003-01-01T01:10:00Z","Name":"Lake","Perimiter":206.26115},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&filter=%7B%22op%22%3A%22%3E%3D%22%2C%22args%22%3A%5B%7B%22property%22%3A%22CTYONLY_%22%7D%2C117%5D%7D&filter-lang=cql2-json","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&filter=%7B%22op%22%3A%22%3E%3D%22%2C%22args%22%3A%5B%7B%22property%22%3A%22CTYONLY_%22%7D%2C117%5D%7D&filter-lang=cql2-json","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":2,"numberReturned":2,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_json_gt.json.txt b/msautotest/api/expected/ogcapi_cql2_json_gt.json.txt new file mode 100644 index 0000000000..14cb788080 --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_json_gt.json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 1 +OGC-NumberReturned: 1 + +{"features":[{"geometry":{"coordinates":[[[-91.2824,47.2658],[-91.2823,47.2658],[-91.2822,47.2658],[-91.282,47.2659],[-91.2819,47.2659],[-91.2818,47.2659],[-91.2818,47.2658],[-91.2818,47.2658],[-91.2821,47.2657],[-91.2824,47.2655],[-91.2825,47.2654],[-91.2826,47.2654],[-91.2827,47.2654],[-91.2828,47.2655],[-91.2827,47.2657],[-91.2825,47.2658],[-91.2824,47.2658]]],"type":"Polygon"},"id":"38","properties":{"Area":2024.76285,"CTYONLY_":118,"Code":"LAKE","LASTMOD":"2003-01-01T01:10:00Z","Name":"Lake","Perimiter":206.26115},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&filter=%7B%22op%22%3A%22%3E%22%2C%22args%22%3A%5B%7B%22property%22%3A%22CTYONLY_%22%7D%2C117%5D%7D&filter-lang=cql2-json","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&filter=%7B%22op%22%3A%22%3E%22%2C%22args%22%3A%5B%7B%22property%22%3A%22CTYONLY_%22%7D%2C117%5D%7D&filter-lang=cql2-json","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":1,"numberReturned":1,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_json_iequal.json.txt b/msautotest/api/expected/ogcapi_cql2_json_iequal.json.txt new file mode 100644 index 0000000000..04095ec344 --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_json_iequal.json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 1 +OGC-NumberReturned: 1 + +{"features":[{"geometry":{"coordinates":[[[-93.5242,44.5436],[-93.5225,44.5436],[-93.504,44.5438],[-93.5018,44.5438],[-93.4835,44.5438],[-93.4817,44.5438],[-93.4734,44.5438],[-93.4632,44.5438],[-93.4609,44.5438],[-93.4429,44.5438],[-93.4408,44.5438],[-93.4326,44.5438],[-93.4226,44.5439],[-93.4206,44.5439],[-93.4024,44.5439],[-93.4003,44.5439],[-93.383,44.544],[-93.38,44.544],[-93.3627,44.5441],[-93.3596,44.5441],[-93.3556,44.5441],[-93.3424,44.5442],[-93.3395,44.5442],[-93.3221,44.544],[-93.3191,44.544],[-93.3128,44.544],[-93.3019,44.544],[-93.2988,44.544],[-93.2813,44.544],[-93.2814,44.5298],[-93.2815,44.5153],[-93.2815,44.501],[-93.2815,44.4865],[-93.2817,44.472],[-93.2618,44.4718],[-93.2415,44.4716],[-93.2213,44.4714],[-93.2008,44.4714],[-93.1808,44.4713],[-93.1605,44.4713],[-93.1408,44.4712],[-93.1206,44.4713],[-93.1002,44.4718],[-93.0799,44.4719],[-93.0597,44.4718],[-93.0393,44.4719],[-93.0394,44.4576],[-93.0396,44.4432],[-93.0397,44.4287],[-93.0399,44.4143],[-93.04,44.3999],[-93.0401,44.3855],[-93.0402,44.371],[-93.0403,44.3565],[-93.0403,44.3419],[-93.0405,44.3273],[-93.0405,44.3129],[-93.0405,44.2983],[-93.0406,44.2838],[-93.0407,44.2693],[-93.0409,44.2548],[-93.041,44.2402],[-93.0411,44.2257],[-93.0411,44.2113],[-93.0411,44.1968],[-93.0427,44.1968],[-93.0459,44.1968],[-93.0613,44.1967],[-93.0661,44.1967],[-93.0815,44.1967],[-93.0862,44.1967],[-93.1003,44.1967],[-93.1015,44.1967],[-93.1063,44.1967],[-93.1092,44.1967],[-93.1218,44.1967],[-93.1267,44.1967],[-93.1301,44.1967],[-93.1418,44.1967],[-93.1467,44.1967],[-93.1561,44.1966],[-93.1622,44.1966],[-93.1661,44.1966],[-93.1703,44.1966],[-93.1822,44.1966],[-93.1856,44.1966],[-93.1865,44.1966],[-93.2023,44.1966],[-93.2037,44.1966],[-93.2064,44.1966],[-93.2225,44.1966],[-93.2265,44.1966],[-93.2292,44.1966],[-93.2426,44.1966],[-93.2465,44.1966],[-93.255,44.1966],[-93.2629,44.1966],[-93.2664,44.1966],[-93.2767,44.1966],[-93.283,44.1966],[-93.2865,44.1965],[-93.2905,44.1965],[-93.3032,44.1965],[-93.3063,44.1965],[-93.3235,44.1965],[-93.3264,44.1965],[-93.3277,44.1965],[-93.3436,44.1965],[-93.3466,44.1965],[-93.3639,44.1965],[-93.3666,44.1965],[-93.3842,44.1965],[-93.3866,44.1965],[-93.4042,44.1965],[-93.4065,44.1965],[-93.4244,44.1964],[-93.4267,44.1964],[-93.4447,44.1964],[-93.4469,44.1964],[-93.4648,44.1963],[-93.467,44.1963],[-93.4852,44.1964],[-93.4872,44.1964],[-93.5053,44.1963],[-93.507,44.1963],[-93.5255,44.1962],[-93.5253,44.2107],[-93.5251,44.2251],[-93.5251,44.2388],[-93.5251,44.2533],[-93.5252,44.2685],[-93.5252,44.2829],[-93.5252,44.2975],[-93.5252,44.312],[-93.5249,44.3266],[-93.5249,44.3411],[-93.5245,44.3557],[-93.5245,44.3704],[-93.5246,44.3848],[-93.5245,44.3994],[-93.5245,44.4138],[-93.5245,44.4283],[-93.5245,44.4427],[-93.5245,44.4572],[-93.5244,44.4717],[-93.5245,44.4862],[-93.5244,44.5007],[-93.5243,44.5152],[-93.5244,44.5297],[-93.5242,44.5436]]],"type":"Polygon"},"id":"66","properties":{"Area":1335114621.00336,"CTYONLY_":66,"Code":"RICE","LASTMOD":"2010-10-17T00:00:00Z","Name":"Rice","Perimiter":154431.78788},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&filter=%7B%22op%22%3A%22%3D%22%2C%22args%22%3A%5B%7B%22op%22%3A%22casei%22%2C%22args%22%3A%5B%7B%22property%22%3A%22Name%22%7D%5D%7D%2C%7B%22op%22%3A%22casei%22%2C%22args%22%3A%5B%22rice%22%5D%7D%5D%7D&filter-lang=cql2-json","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&filter=%7B%22op%22%3A%22%3D%22%2C%22args%22%3A%5B%7B%22op%22%3A%22casei%22%2C%22args%22%3A%5B%7B%22property%22%3A%22Name%22%7D%5D%7D%2C%7B%22op%22%3A%22casei%22%2C%22args%22%3A%5B%22rice%22%5D%7D%5D%7D&filter-lang=cql2-json","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":1,"numberReturned":1,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_json_ilike.json.txt b/msautotest/api/expected/ogcapi_cql2_json_ilike.json.txt new file mode 100644 index 0000000000..4f6c986669 --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_json_ilike.json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 1 +OGC-NumberReturned: 1 + +{"features":[{"geometry":{"coordinates":[[[-93.5242,44.5436],[-93.5225,44.5436],[-93.504,44.5438],[-93.5018,44.5438],[-93.4835,44.5438],[-93.4817,44.5438],[-93.4734,44.5438],[-93.4632,44.5438],[-93.4609,44.5438],[-93.4429,44.5438],[-93.4408,44.5438],[-93.4326,44.5438],[-93.4226,44.5439],[-93.4206,44.5439],[-93.4024,44.5439],[-93.4003,44.5439],[-93.383,44.544],[-93.38,44.544],[-93.3627,44.5441],[-93.3596,44.5441],[-93.3556,44.5441],[-93.3424,44.5442],[-93.3395,44.5442],[-93.3221,44.544],[-93.3191,44.544],[-93.3128,44.544],[-93.3019,44.544],[-93.2988,44.544],[-93.2813,44.544],[-93.2814,44.5298],[-93.2815,44.5153],[-93.2815,44.501],[-93.2815,44.4865],[-93.2817,44.472],[-93.2618,44.4718],[-93.2415,44.4716],[-93.2213,44.4714],[-93.2008,44.4714],[-93.1808,44.4713],[-93.1605,44.4713],[-93.1408,44.4712],[-93.1206,44.4713],[-93.1002,44.4718],[-93.0799,44.4719],[-93.0597,44.4718],[-93.0393,44.4719],[-93.0394,44.4576],[-93.0396,44.4432],[-93.0397,44.4287],[-93.0399,44.4143],[-93.04,44.3999],[-93.0401,44.3855],[-93.0402,44.371],[-93.0403,44.3565],[-93.0403,44.3419],[-93.0405,44.3273],[-93.0405,44.3129],[-93.0405,44.2983],[-93.0406,44.2838],[-93.0407,44.2693],[-93.0409,44.2548],[-93.041,44.2402],[-93.0411,44.2257],[-93.0411,44.2113],[-93.0411,44.1968],[-93.0427,44.1968],[-93.0459,44.1968],[-93.0613,44.1967],[-93.0661,44.1967],[-93.0815,44.1967],[-93.0862,44.1967],[-93.1003,44.1967],[-93.1015,44.1967],[-93.1063,44.1967],[-93.1092,44.1967],[-93.1218,44.1967],[-93.1267,44.1967],[-93.1301,44.1967],[-93.1418,44.1967],[-93.1467,44.1967],[-93.1561,44.1966],[-93.1622,44.1966],[-93.1661,44.1966],[-93.1703,44.1966],[-93.1822,44.1966],[-93.1856,44.1966],[-93.1865,44.1966],[-93.2023,44.1966],[-93.2037,44.1966],[-93.2064,44.1966],[-93.2225,44.1966],[-93.2265,44.1966],[-93.2292,44.1966],[-93.2426,44.1966],[-93.2465,44.1966],[-93.255,44.1966],[-93.2629,44.1966],[-93.2664,44.1966],[-93.2767,44.1966],[-93.283,44.1966],[-93.2865,44.1965],[-93.2905,44.1965],[-93.3032,44.1965],[-93.3063,44.1965],[-93.3235,44.1965],[-93.3264,44.1965],[-93.3277,44.1965],[-93.3436,44.1965],[-93.3466,44.1965],[-93.3639,44.1965],[-93.3666,44.1965],[-93.3842,44.1965],[-93.3866,44.1965],[-93.4042,44.1965],[-93.4065,44.1965],[-93.4244,44.1964],[-93.4267,44.1964],[-93.4447,44.1964],[-93.4469,44.1964],[-93.4648,44.1963],[-93.467,44.1963],[-93.4852,44.1964],[-93.4872,44.1964],[-93.5053,44.1963],[-93.507,44.1963],[-93.5255,44.1962],[-93.5253,44.2107],[-93.5251,44.2251],[-93.5251,44.2388],[-93.5251,44.2533],[-93.5252,44.2685],[-93.5252,44.2829],[-93.5252,44.2975],[-93.5252,44.312],[-93.5249,44.3266],[-93.5249,44.3411],[-93.5245,44.3557],[-93.5245,44.3704],[-93.5246,44.3848],[-93.5245,44.3994],[-93.5245,44.4138],[-93.5245,44.4283],[-93.5245,44.4427],[-93.5245,44.4572],[-93.5244,44.4717],[-93.5245,44.4862],[-93.5244,44.5007],[-93.5243,44.5152],[-93.5244,44.5297],[-93.5242,44.5436]]],"type":"Polygon"},"id":"66","properties":{"Area":1335114621.00336,"CTYONLY_":66,"Code":"RICE","LASTMOD":"2010-10-17T00:00:00Z","Name":"Rice","Perimiter":154431.78788},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&filter=%7B%22op%22%3A%22like%22%2C%22args%22%3A%5B%7B%22op%22%3A%22casei%22%2C%22args%22%3A%5B%7B%22property%22%3A%22Name%22%7D%5D%7D%2C%7B%22op%22%3A%22casei%22%2C%22args%22%3A%5B%22r_ce%22%5D%7D%5D%7D&filter-lang=cql2-json","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&filter=%7B%22op%22%3A%22like%22%2C%22args%22%3A%5B%7B%22op%22%3A%22casei%22%2C%22args%22%3A%5B%7B%22property%22%3A%22Name%22%7D%5D%7D%2C%7B%22op%22%3A%22casei%22%2C%22args%22%3A%5B%22r_ce%22%5D%7D%5D%7D&filter-lang=cql2-json","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":1,"numberReturned":1,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_json_in.json.txt b/msautotest/api/expected/ogcapi_cql2_json_in.json.txt new file mode 100644 index 0000000000..2f90070f34 --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_json_in.json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 2 +OGC-NumberReturned: 2 + +{"features":[{"geometry":{"coordinates":[[[-96.4054,49.0001],[-96.4054,48.9947],[-96.4054,48.994],[-96.4054,48.9803],[-96.4054,48.9793],[-96.4053,48.9705],[-96.4053,48.9658],[-96.4053,48.9648],[-96.4053,48.9515],[-96.4053,48.9504],[-96.4053,48.9371],[-96.4053,48.936],[-96.4054,48.9225],[-96.4054,48.9214],[-96.4053,48.9137],[-96.4053,48.9081],[-96.4053,48.9068],[-96.405,48.8926],[-96.405,48.878],[-96.4047,48.8635],[-96.4045,48.8491],[-96.4043,48.8343],[-96.4042,48.8198],[-96.4042,48.8048],[-96.4042,48.7903],[-96.4045,48.7758],[-96.4047,48.7607],[-96.4048,48.7465],[-96.4048,48.7318],[-96.4049,48.7172],[-96.388,48.7172],[-96.3873,48.7172],[-96.3866,48.703],[-96.3874,48.6887],[-96.3871,48.6741],[-96.3877,48.6599],[-96.3879,48.6454],[-96.388,48.6313],[-96.389,48.6165],[-96.3891,48.6024],[-96.3884,48.5877],[-96.3882,48.5733],[-96.3879,48.5588],[-96.3882,48.5442],[-96.4101,48.544],[-96.4318,48.5438],[-96.4535,48.5436],[-96.4754,48.5435],[-96.4973,48.5434],[-96.518,48.5434],[-96.54,48.5434],[-96.5621,48.5436],[-96.5839,48.5437],[-96.6058,48.5437],[-96.6278,48.5437],[-96.6493,48.5437],[-96.6713,48.5436],[-96.6931,48.5437],[-96.7151,48.5437],[-96.7368,48.5437],[-96.7585,48.5436],[-96.7803,48.5435],[-96.8023,48.5436],[-96.824,48.5436],[-96.8459,48.5434],[-96.8678,48.5433],[-96.8896,48.5433],[-96.9115,48.5432],[-96.9138,48.5433],[-96.9331,48.5435],[-96.9551,48.5437],[-96.9768,48.544],[-96.9985,48.5441],[-97.0194,48.5441],[-97.0416,48.5442],[-97.0635,48.5441],[-97.0852,48.5441],[-97.107,48.544],[-97.1287,48.5439],[-97.1509,48.5439],[-97.1631,48.544],[-97.1637,48.5445],[-97.1659,48.5483],[-97.1662,48.5509],[-97.1661,48.5527],[-97.1654,48.5536],[-97.1645,48.554],[-97.1628,48.5543],[-97.1613,48.5539],[-97.1592,48.5528],[-97.1577,48.5518],[-97.1557,48.5512],[-97.1538,48.5513],[-97.1513,48.5515],[-97.1507,48.5515],[-97.1493,48.5516],[-97.1474,48.5516],[-97.1444,48.5514],[-97.1407,48.5515],[-97.1387,48.5522],[-97.1379,48.553],[-97.1379,48.5542],[-97.1391,48.5554],[-97.141,48.5566],[-97.1426,48.5571],[-97.1464,48.5573],[-97.1505,48.5574],[-97.1515,48.5574],[-97.1551,48.5574],[-97.1578,48.5573],[-97.1606,48.5571],[-97.1631,48.5571],[-97.1646,48.5572],[-97.167,48.5575],[-97.1697,48.5584],[-97.1721,48.5591],[-97.1727,48.5593],[-97.174,48.5599],[-97.1749,48.5606],[-97.1753,48.5614],[-97.1754,48.5623],[-97.1749,48.5631],[-97.1744,48.5639],[-97.1723,48.5648],[-97.1721,48.5648],[-97.1706,48.5652],[-97.1687,48.5655],[-97.167,48.5658],[-97.1651,48.5659],[-97.1613,48.5661],[-97.1541,48.5669],[-97.153,48.5671],[-97.1516,48.5677],[-97.1503,48.5688],[-97.1496,48.5695],[-97.1487,48.5707],[-97.1477,48.5727],[-97.1477,48.5728],[-97.1476,48.5731],[-97.1483,48.5763],[-97.15,48.5775],[-97.1501,48.5775],[-97.1548,48.5779],[-97.1592,48.5785],[-97.1605,48.58],[-97.16,48.5816],[-97.1578,48.5826],[-97.1562,48.5828],[-97.1541,48.5826],[-97.1524,48.5823],[-97.15,48.5815],[-97.1494,48.5813],[-97.1484,48.5811],[-97.1449,48.5815],[-97.1436,48.5824],[-97.1431,48.5834],[-97.1429,48.5838],[-97.142,48.5876],[-97.1418,48.5886],[-97.1415,48.5909],[-97.1422,48.5926],[-97.1433,48.5936],[-97.1451,48.594],[-97.1471,48.594],[-97.1497,48.5937],[-97.1525,48.594],[-97.1536,48.5949],[-97.1535,48.5957],[-97.1527,48.5962],[-97.1524,48.5969],[-97.1516,48.598],[-97.1498,48.5981],[-97.1497,48.5981],[-97.1463,48.5977],[-97.1443,48.5981],[-97.143,48.5987],[-97.1416,48.6002],[-97.1403,48.6021],[-97.14,48.6025],[-97.138,48.6044],[-97.1359,48.6054],[-97.1345,48.6065],[-97.1341,48.6075],[-97.1349,48.6082],[-97.1358,48.6086],[-97.137,48.6088],[-97.1396,48.6086],[-97.1443,48.6078],[-97.1474,48.6081],[-97.1494,48.6089],[-97.1495,48.609],[-97.1505,48.6115],[-97.1501,48.6124],[-97.1493,48.6129],[-97.1478,48.6138],[-97.145,48.6146],[-97.1408,48.6149],[-97.137,48.6144],[-97.134,48.6136],[-97.1319,48.6133],[-97.1309,48.6137],[-97.1289,48.614],[-97.1286,48.6153],[-97.1293,48.6168],[-97.1295,48.617],[-97.1311,48.6184],[-97.1342,48.6199],[-97.1353,48.6212],[-97.1346,48.6224],[-97.133,48.6228],[-97.131,48.6227],[-97.1291,48.6222],[-97.1277,48.6212],[-97.1274,48.621],[-97.1259,48.6195],[-97.1253,48.619],[-97.1243,48.6183],[-97.1231,48.6178],[-97.1216,48.6176],[-97.12,48.6178],[-97.1193,48.6182],[-97.1186,48.6191],[-97.1183,48.6198],[-97.1186,48.6209],[-97.1198,48.6221],[-97.1209,48.6232],[-97.1212,48.6233],[-97.122,48.624],[-97.1228,48.6245],[-97.1236,48.625],[-97.1241,48.6254],[-97.1245,48.6257],[-97.1249,48.6259],[-97.1253,48.6261],[-97.126,48.6264],[-97.1266,48.6266],[-97.1272,48.627],[-97.1279,48.6273],[-97.1288,48.6278],[-97.1296,48.6282],[-97.1302,48.6288],[-97.1305,48.6292],[-97.1307,48.6297],[-97.131,48.6303],[-97.131,48.6304],[-97.131,48.6308],[-97.131,48.6315],[-97.1309,48.6317],[-97.1307,48.6321],[-97.1304,48.6325],[-97.1301,48.6326],[-97.1297,48.6328],[-97.1293,48.6329],[-97.129,48.633],[-97.1281,48.6332],[-97.128,48.6333],[-97.1275,48.6333],[-97.1253,48.6334],[-97.1235,48.6333],[-97.1216,48.6327],[-97.1181,48.6308],[-97.1176,48.6307],[-97.115,48.6299],[-97.1133,48.63],[-97.1115,48.6303],[-97.1107,48.6308],[-97.1104,48.6309],[-97.1095,48.6315],[-97.1084,48.6327],[-97.1082,48.6344],[-97.1086,48.6363],[-97.1096,48.6389],[-97.1109,48.6407],[-97.1119,48.6416],[-97.1144,48.6433],[-97.115,48.6438],[-97.115,48.6446],[-97.1149,48.6452],[-97.1123,48.6457],[-97.1112,48.6459],[-97.1093,48.6465],[-97.1078,48.6478],[-97.1069,48.6491],[-97.1066,48.6501],[-97.1061,48.6519],[-97.1059,48.6527],[-97.1045,48.6545],[-97.1017,48.6563],[-97.0987,48.6593],[-97.0986,48.6604],[-97.0985,48.6613],[-97.0992,48.6625],[-97.1019,48.6636],[-97.106,48.663],[-97.1062,48.663],[-97.1082,48.6634],[-97.1087,48.6645],[-97.1061,48.6654],[-97.1057,48.6655],[-97.102,48.6667],[-97.1,48.668],[-97.0998,48.6714],[-97.1002,48.675],[-97.1003,48.6757],[-97.1008,48.6787],[-97.1011,48.6808],[-97.1003,48.6828],[-97.0985,48.683],[-97.0946,48.6822],[-97.0926,48.6821],[-97.0904,48.6828],[-97.0898,48.6841],[-97.0899,48.6852],[-97.091,48.6861],[-97.093,48.687],[-97.0951,48.6876],[-97.099,48.6884],[-97.1024,48.6893],[-97.103,48.6894],[-97.1059,48.6903],[-97.1064,48.6905],[-97.1086,48.6915],[-97.111,48.6939],[-97.113,48.6964],[-97.1148,48.6981],[-97.1182,48.7005],[-97.1198,48.7018],[-97.1201,48.7039],[-97.1194,48.7041],[-97.1182,48.7046],[-97.1143,48.7052],[-97.1117,48.7056],[-97.11,48.7063],[-97.1098,48.7083],[-97.1113,48.7094],[-97.1134,48.7101],[-97.1157,48.7105],[-97.1174,48.7111],[-97.119,48.7119],[-97.1212,48.7136],[-97.1223,48.716],[-97.1229,48.7168],[-97.1231,48.7172],[-97.1243,48.7192],[-97.1253,48.7201],[-97.1253,48.7203],[-97.126,48.7207],[-97.1263,48.7212],[-97.1272,48.7215],[-97.128,48.722],[-97.1282,48.7221],[-97.1288,48.7225],[-97.1297,48.7229],[-97.131,48.7233],[-97.1321,48.7238],[-97.1331,48.7242],[-97.1345,48.7248],[-97.136,48.7257],[-97.1369,48.7263],[-97.1375,48.727],[-97.1376,48.7274],[-97.1376,48.7278],[-97.1373,48.7283],[-97.137,48.7284],[-97.1365,48.7285],[-97.136,48.7287],[-97.1352,48.7287],[-97.1341,48.7289],[-97.1333,48.7291],[-97.1328,48.7292],[-97.132,48.7294],[-97.1312,48.7295],[-97.1308,48.7296],[-97.1299,48.7299],[-97.1294,48.7304],[-97.1288,48.7308],[-97.1286,48.7312],[-97.1286,48.7315],[-97.1286,48.7316],[-97.1286,48.7318],[-97.1285,48.7322],[-97.1286,48.7326],[-97.1286,48.7328],[-97.1287,48.7331],[-97.129,48.7335],[-97.1295,48.7339],[-97.1298,48.7341],[-97.1316,48.7347],[-97.1322,48.7348],[-97.1334,48.7347],[-97.1351,48.7345],[-97.1369,48.7345],[-97.1383,48.7345],[-97.1396,48.7347],[-97.1402,48.7349],[-97.1412,48.7354],[-97.1419,48.7359],[-97.1422,48.7367],[-97.1423,48.7372],[-97.1421,48.7381],[-97.1414,48.7385],[-97.1408,48.7387],[-97.1404,48.7389],[-97.1399,48.7393],[-97.1392,48.7397],[-97.1381,48.7408],[-97.1372,48.742],[-97.1366,48.7435],[-97.1365,48.745],[-97.1365,48.7459],[-97.1366,48.7466],[-97.1369,48.748],[-97.1375,48.7492],[-97.1379,48.75],[-97.1385,48.7504],[-97.1391,48.7507],[-97.1396,48.7508],[-97.1401,48.7509],[-97.141,48.751],[-97.142,48.751],[-97.143,48.7509],[-97.1444,48.7507],[-97.1457,48.7506],[-97.1466,48.7505],[-97.1476,48.7505],[-97.1491,48.7506],[-97.1497,48.7508],[-97.1503,48.7509],[-97.1515,48.7515],[-97.1521,48.752],[-97.153,48.7529],[-97.1539,48.7542],[-97.1545,48.7553],[-97.1547,48.7558],[-97.1548,48.7562],[-97.1548,48.7569],[-97.1548,48.7576],[-97.1546,48.758],[-97.1542,48.7587],[-97.1535,48.7593],[-97.1528,48.7598],[-97.1519,48.7601],[-97.1508,48.7605],[-97.1503,48.7606],[-97.1501,48.7607],[-97.1475,48.7616],[-97.1473,48.7617],[-97.1469,48.762],[-97.1462,48.7626],[-97.1461,48.7628],[-97.1459,48.7633],[-97.1456,48.7643],[-97.1456,48.765],[-97.146,48.7658],[-97.1476,48.7673],[-97.1487,48.7681],[-97.15,48.7692],[-97.1501,48.7693],[-97.1506,48.77],[-97.1512,48.7712],[-97.1519,48.7721],[-97.1525,48.7727],[-97.1529,48.7728],[-97.1559,48.7731],[-97.1567,48.7732],[-97.1578,48.7735],[-97.1582,48.7737],[-97.1587,48.7742],[-97.1589,48.7746],[-97.159,48.7751],[-97.159,48.7751],[-97.159,48.7754],[-97.1589,48.776],[-97.1584,48.7766],[-97.1579,48.7769],[-97.1573,48.7772],[-97.1557,48.7776],[-97.1544,48.7778],[-97.1534,48.778],[-97.1522,48.7783],[-97.1509,48.7787],[-97.1501,48.7789],[-97.1497,48.779],[-97.1483,48.7797],[-97.1477,48.7801],[-97.1473,48.7807],[-97.1472,48.7811],[-97.1473,48.7816],[-97.1478,48.7821],[-97.1486,48.7824],[-97.1495,48.7826],[-97.1501,48.7826],[-97.1503,48.7826],[-97.1513,48.7825],[-97.1533,48.7824],[-97.1547,48.7824],[-97.1559,48.7825],[-97.1571,48.7827],[-97.1583,48.783],[-97.1591,48.7834],[-97.1595,48.7838],[-97.1597,48.7843],[-97.1598,48.7848],[-97.1596,48.7853],[-97.1593,48.786],[-97.1591,48.7863],[-97.1586,48.7869],[-97.1577,48.7877],[-97.1574,48.7882],[-97.1573,48.7884],[-97.1572,48.7887],[-97.1571,48.7894],[-97.157,48.7895],[-97.157,48.7901],[-97.1572,48.7906],[-97.1575,48.7909],[-97.1581,48.7912],[-97.1586,48.7913],[-97.1592,48.7915],[-97.1595,48.7915],[-97.1611,48.7915],[-97.1618,48.7914],[-97.1645,48.7911],[-97.1648,48.7911],[-97.1657,48.7911],[-97.1664,48.7912],[-97.1672,48.7913],[-97.1714,48.7921],[-97.1718,48.7923],[-97.1721,48.7924],[-97.1731,48.7929],[-97.1737,48.7933],[-97.174,48.7937],[-97.1741,48.7942],[-97.1742,48.7947],[-97.1742,48.7951],[-97.1739,48.7954],[-97.1734,48.7958],[-97.1726,48.7963],[-97.1717,48.7966],[-97.1716,48.7966],[-97.171,48.7967],[-97.1701,48.7967],[-97.1688,48.7966],[-97.1673,48.7964],[-97.1665,48.7962],[-97.1654,48.7962],[-97.1648,48.7962],[-97.1638,48.7963],[-97.1631,48.7966],[-97.1625,48.7969],[-97.162,48.7974],[-97.1617,48.7979],[-97.1617,48.7984],[-97.1619,48.7988],[-97.1621,48.7994],[-97.1626,48.8001],[-97.1633,48.8007],[-97.1642,48.8011],[-97.1652,48.8014],[-97.166,48.8015],[-97.1668,48.8016],[-97.1675,48.8016],[-97.1685,48.8016],[-97.1698,48.8013],[-97.1706,48.8011],[-97.1714,48.8008],[-97.1715,48.8008],[-97.1724,48.8004],[-97.1731,48.8],[-97.1742,48.7992],[-97.175,48.7986],[-97.1754,48.7983],[-97.1757,48.798],[-97.1761,48.7977],[-97.1768,48.7974],[-97.1773,48.7973],[-97.1779,48.7972],[-97.1787,48.7972],[-97.1795,48.7972],[-97.1801,48.7973],[-97.1807,48.7975],[-97.1811,48.7978],[-97.1815,48.7982],[-97.1816,48.7986],[-97.1817,48.7991],[-97.1815,48.7995],[-97.1813,48.8],[-97.1808,48.8004],[-97.1801,48.8008],[-97.1791,48.8012],[-97.1779,48.8015],[-97.1769,48.8017],[-97.1764,48.8018],[-97.1756,48.8021],[-97.1748,48.8023],[-97.1725,48.8032],[-97.1713,48.8036],[-97.171,48.8037],[-97.1706,48.8039],[-97.1694,48.8043],[-97.1682,48.8046],[-97.1675,48.8048],[-97.1666,48.805],[-97.1655,48.8052],[-97.1638,48.8055],[-97.161,48.8059],[-97.1605,48.8061],[-97.1597,48.8064],[-97.159,48.8067],[-97.1583,48.8072],[-97.1579,48.8077],[-97.1577,48.8082],[-97.1576,48.8089],[-97.1578,48.8098],[-97.158,48.8104],[-97.1586,48.811],[-97.159,48.8111],[-97.161,48.8117],[-97.1617,48.8119],[-97.1625,48.812],[-97.1636,48.8121],[-97.1644,48.8121],[-97.1651,48.812],[-97.1666,48.8118],[-97.168,48.8116],[-97.169,48.8114],[-97.17,48.8114],[-97.1713,48.8115],[-97.1715,48.8115],[-97.1726,48.8117],[-97.1731,48.8118],[-97.174,48.8122],[-97.1761,48.8132],[-97.1776,48.8141],[-97.1784,48.8145],[-97.1797,48.8149],[-97.1807,48.8151],[-97.1821,48.8153],[-97.1828,48.8153],[-97.184,48.8152],[-97.1848,48.8151],[-97.186,48.8147],[-97.1868,48.8145],[-97.1873,48.8143],[-97.1879,48.8143],[-97.1883,48.8143],[-97.1889,48.8143],[-97.1894,48.8144],[-97.1898,48.8146],[-97.1901,48.8148],[-97.1903,48.8153],[-97.1904,48.8156],[-97.1903,48.8159],[-97.19,48.8163],[-97.1893,48.8167],[-97.1885,48.8171],[-97.1879,48.8173],[-97.1866,48.8176],[-97.1857,48.8177],[-97.1847,48.8179],[-97.184,48.8181],[-97.1833,48.8184],[-97.1817,48.8189],[-97.1809,48.8193],[-97.1801,48.8199],[-97.1793,48.8207],[-97.1787,48.8216],[-97.178,48.8232],[-97.1777,48.824],[-97.1776,48.8245],[-97.1777,48.8249],[-97.178,48.8255],[-97.1782,48.8258],[-97.1786,48.8262],[-97.1794,48.8268],[-97.1822,48.8288],[-97.1837,48.8299],[-97.1841,48.8304],[-97.1847,48.8314],[-97.1848,48.8319],[-97.1849,48.8326],[-97.1849,48.8327],[-97.1848,48.833],[-97.1846,48.8336],[-97.1842,48.8341],[-97.1837,48.8345],[-97.183,48.8348],[-97.1822,48.835],[-97.1813,48.8351],[-97.1799,48.8352],[-97.1783,48.8353],[-97.1779,48.8354],[-97.1772,48.8356],[-97.1757,48.8362],[-97.1753,48.8364],[-97.1747,48.8369],[-97.1742,48.8373],[-97.1739,48.8378],[-97.1738,48.8384],[-97.1738,48.839],[-97.1739,48.8406],[-97.1743,48.8427],[-97.1747,48.8438],[-97.175,48.8442],[-97.1755,48.8447],[-97.1761,48.8452],[-97.1767,48.8455],[-97.1771,48.8456],[-97.1779,48.8458],[-97.1795,48.8459],[-97.1808,48.846],[-97.1817,48.8462],[-97.1823,48.8464],[-97.1827,48.8468],[-97.1829,48.847],[-97.1829,48.8471],[-97.1829,48.8473],[-97.1826,48.8476],[-97.1821,48.8479],[-97.1816,48.848],[-97.1809,48.8481],[-97.1793,48.8482],[-97.178,48.8483],[-97.1767,48.8484],[-97.1759,48.8486],[-97.1753,48.8487],[-97.1747,48.849],[-97.1742,48.8493],[-97.1737,48.8497],[-97.1733,48.8502],[-97.173,48.8506],[-97.173,48.8508],[-97.173,48.8511],[-97.173,48.8516],[-97.1732,48.8522],[-97.1737,48.8527],[-97.1746,48.8534],[-97.1771,48.855],[-97.1784,48.8561],[-97.1786,48.8563],[-97.179,48.8569],[-97.1793,48.8576],[-97.1794,48.8583],[-97.1794,48.859],[-97.1792,48.8606],[-97.179,48.8615],[-97.179,48.862],[-97.1791,48.8626],[-97.1794,48.863],[-97.1801,48.8636],[-97.1811,48.864],[-97.1818,48.8641],[-97.1827,48.8641],[-97.1839,48.864],[-97.1855,48.8637],[-97.1871,48.8633],[-97.1877,48.8631],[-97.1883,48.8631],[-97.1891,48.8631],[-97.1896,48.8633],[-97.19,48.8635],[-97.1903,48.8639],[-97.1905,48.8644],[-97.1905,48.8648],[-97.1904,48.8651],[-97.1901,48.8657],[-97.1899,48.8661],[-97.1895,48.8665],[-97.189,48.867],[-97.1884,48.8675],[-97.1851,48.8694],[-97.1813,48.8718],[-97.1788,48.8736],[-97.1785,48.8738],[-97.1782,48.8741],[-97.1781,48.8743],[-97.1779,48.8745],[-97.1778,48.8747],[-97.1777,48.8749],[-97.1777,48.875],[-97.1778,48.875],[-97.1778,48.8754],[-97.1779,48.8757],[-97.1782,48.8761],[-97.1786,48.8765],[-97.1792,48.8769],[-97.1798,48.8771],[-97.1808,48.8772],[-97.1823,48.8772],[-97.1852,48.8768],[-97.1869,48.8765],[-97.1881,48.8765],[-97.1891,48.8766],[-97.1904,48.8769],[-97.1933,48.8779],[-97.1944,48.8783],[-97.1957,48.8788],[-97.1972,48.8794],[-97.1981,48.8799],[-97.1988,48.8805],[-97.1995,48.8812],[-97.1999,48.8818],[-97.1999,48.8821],[-97.2,48.8827],[-97.1998,48.8832],[-97.1997,48.8836],[-97.199,48.8845],[-97.1978,48.8859],[-97.1975,48.8865],[-97.1974,48.8868],[-97.1973,48.8872],[-97.1973,48.8874],[-97.1974,48.8877],[-97.1975,48.8881],[-97.1983,48.8889],[-97.2002,48.8903],[-97.2004,48.8904],[-97.2009,48.8908],[-97.2014,48.8912],[-97.2017,48.8915],[-97.2017,48.8919],[-97.2016,48.8922],[-97.2013,48.8925],[-97.201,48.8926],[-97.2001,48.8926],[-97.1994,48.8926],[-97.1985,48.8925],[-97.198,48.8924],[-97.1973,48.892],[-97.1957,48.8916],[-97.1946,48.8915],[-97.1944,48.8914],[-97.1937,48.8914],[-97.1927,48.8915],[-97.1921,48.8917],[-97.1916,48.8919],[-97.1905,48.8926],[-97.1901,48.8932],[-97.1898,48.8938],[-97.1897,48.8944],[-97.1897,48.8947],[-97.1898,48.8951],[-97.1899,48.8954],[-97.1903,48.896],[-97.1911,48.8967],[-97.1919,48.8974],[-97.1925,48.8979],[-97.1935,48.8985],[-97.1941,48.8988],[-97.1945,48.8989],[-97.1966,48.8997],[-97.1992,48.9004],[-97.2009,48.9009],[-97.2022,48.9013],[-97.2048,48.9018],[-97.2055,48.902],[-97.207,48.9025],[-97.2076,48.9027],[-97.2082,48.9029],[-97.2088,48.9032],[-97.2093,48.9036],[-97.21,48.904],[-97.2105,48.9044],[-97.211,48.905],[-97.2114,48.9056],[-97.2122,48.9069],[-97.2125,48.9075],[-97.2127,48.9082],[-97.2127,48.909],[-97.2125,48.9099],[-97.212,48.911],[-97.2116,48.9121],[-97.2111,48.913],[-97.2108,48.914],[-97.2106,48.9148],[-97.2106,48.9153],[-97.2109,48.9162],[-97.2111,48.9167],[-97.2115,48.9172],[-97.2118,48.9175],[-97.2122,48.9177],[-97.2129,48.9181],[-97.2149,48.9187],[-97.2163,48.9191],[-97.2164,48.9191],[-97.2171,48.9194],[-97.2179,48.9198],[-97.2189,48.9205],[-97.2196,48.9215],[-97.2198,48.9222],[-97.2199,48.923],[-97.2197,48.9237],[-97.2191,48.9249],[-97.2183,48.9262],[-97.2172,48.9277],[-97.2163,48.9286],[-97.2159,48.9289],[-97.2149,48.9301],[-97.2146,48.9304],[-97.2145,48.9307],[-97.2144,48.931],[-97.2145,48.9314],[-97.2145,48.9316],[-97.2148,48.9319],[-97.2154,48.9325],[-97.2159,48.9327],[-97.2162,48.9328],[-97.217,48.9328],[-97.2181,48.9327],[-97.2198,48.9325],[-97.2208,48.9325],[-97.2214,48.9325],[-97.2218,48.9326],[-97.2237,48.9332],[-97.2245,48.9337],[-97.2249,48.9339],[-97.225,48.934],[-97.2252,48.9342],[-97.2254,48.9345],[-97.2257,48.9349],[-97.226,48.9353],[-97.2263,48.936],[-97.2267,48.9376],[-97.227,48.9389],[-97.2271,48.9398],[-97.2271,48.941],[-97.227,48.9418],[-97.2266,48.9432],[-97.2264,48.9441],[-97.2263,48.9445],[-97.2264,48.9452],[-97.2265,48.9456],[-97.227,48.9462],[-97.2273,48.9465],[-97.2276,48.9467],[-97.2279,48.9467],[-97.2284,48.9468],[-97.2304,48.9465],[-97.2309,48.9464],[-97.2313,48.9464],[-97.2326,48.9466],[-97.2331,48.9468],[-97.2338,48.9471],[-97.2342,48.9474],[-97.2343,48.948],[-97.2343,48.9485],[-97.2342,48.9488],[-97.2341,48.9491],[-97.2337,48.95],[-97.2332,48.951],[-97.2328,48.9524],[-97.2323,48.954],[-97.2317,48.9558],[-97.2313,48.9568],[-97.2309,48.9578],[-97.2305,48.9585],[-97.23,48.9591],[-97.2288,48.9603],[-97.2282,48.9609],[-97.2278,48.9613],[-97.2276,48.9619],[-97.2276,48.9624],[-97.2279,48.963],[-97.228,48.9631],[-97.2283,48.9634],[-97.2289,48.9639],[-97.2294,48.9641],[-97.23,48.9642],[-97.2323,48.9646],[-97.2355,48.965],[-97.2368,48.9652],[-97.2375,48.9654],[-97.2382,48.966],[-97.2383,48.9661],[-97.2388,48.9666],[-97.2391,48.9676],[-97.2392,48.9687],[-97.239,48.9696],[-97.2387,48.9706],[-97.2383,48.9715],[-97.2381,48.9723],[-97.238,48.9725],[-97.2379,48.9731],[-97.2378,48.9734],[-97.2378,48.9738],[-97.238,48.9752],[-97.238,48.9763],[-97.2381,48.9771],[-97.238,48.9771],[-97.238,48.9841],[-97.2377,48.9849],[-97.2372,48.9857],[-97.2365,48.9867],[-97.2359,48.9874],[-97.2351,48.9881],[-97.2342,48.989],[-97.2335,48.9895],[-97.2331,48.9898],[-97.2317,48.9904],[-97.2301,48.9911],[-97.2293,48.9914],[-97.229,48.9916],[-97.2279,48.9921],[-97.2274,48.9925],[-97.227,48.9929],[-97.2266,48.9933],[-97.2265,48.9938],[-97.2267,48.9941],[-97.227,48.9945],[-97.2273,48.9947],[-97.2287,48.9949],[-97.2304,48.995],[-97.2317,48.9951],[-97.2324,48.9952],[-97.2335,48.9956],[-97.2338,48.9959],[-97.2341,48.9966],[-97.2341,48.997],[-97.234,48.9975],[-97.2337,48.9981],[-97.2332,48.9985],[-97.2323,48.999],[-97.2305,49.0],[-97.2303,49.0001],[-97.2295,49.0005],[-97.2175,49.0005],[-97.2161,49.0005],[-97.2078,49.0005],[-97.2069,49.0005],[-97.1955,49.0005],[-97.1939,49.0005],[-97.1739,49.0005],[-97.1724,49.0005],[-97.1514,49.0005],[-97.1502,49.0005],[-97.1294,49.0004],[-97.1277,49.0004],[-97.1073,49.0004],[-97.1061,49.0004],[-97.0853,49.0004],[-97.084,49.0004],[-97.0633,49.0004],[-97.062,49.0004],[-97.0412,49.0004],[-97.0401,49.0004],[-97.0192,49.0004],[-97.0183,49.0004],[-96.9971,49.0004],[-96.9961,49.0004],[-96.9751,49.0003],[-96.9738,49.0003],[-96.953,49.0003],[-96.9518,49.0003],[-96.931,49.0003],[-96.9299,49.0003],[-96.909,49.0003],[-96.9078,49.0003],[-96.8869,49.0003],[-96.8856,49.0003],[-96.8649,49.0003],[-96.864,49.0003],[-96.8429,49.0003],[-96.8415,49.0003],[-96.8208,49.0003],[-96.8197,49.0003],[-96.8023,49.0002],[-96.8005,49.0002],[-96.8003,49.0002],[-96.7988,49.0002],[-96.7787,49.0002],[-96.7768,49.0002],[-96.7567,49.0002],[-96.7547,49.0002],[-96.7348,49.0002],[-96.7327,49.0002],[-96.7127,49.0002],[-96.7107,49.0002],[-96.6905,49.0002],[-96.6886,49.0002],[-96.6695,49.0002],[-96.6665,49.0002],[-96.6482,49.0002],[-96.6445,49.0002],[-96.6243,49.0002],[-96.6225,49.0002],[-96.6021,49.0002],[-96.6004,49.0002],[-96.58,49.0002],[-96.5784,49.0002],[-96.558,49.0002],[-96.5563,49.0002],[-96.536,49.0002],[-96.5342,49.0002],[-96.5154,49.0002],[-96.5123,49.0002],[-96.4933,49.0002],[-96.49,49.0002],[-96.471,49.0001],[-96.4664,49.0001],[-96.4496,49.0001],[-96.4492,49.0001],[-96.4491,49.0001],[-96.446,49.0001],[-96.4273,49.0001],[-96.4224,49.0001],[-96.4054,49.0001]]],"type":"Polygon"},"id":"35","properties":{"Area":2862183702.23055,"CTYONLY_":3,"Code":"KITT","LASTMOD":"1999-12-31T23:59:59Z","Name":"Kittson","Perimiter":263017.48277},"type":"Feature"},{"geometry":{"coordinates":[[[-94.4299,48.7012],[-94.4241,48.7053],[-94.4213,48.7086],[-94.4189,48.7103],[-94.4158,48.711],[-94.4081,48.7106],[-94.406,48.7105],[-94.3889,48.712],[-94.3859,48.7119],[-94.384,48.7119],[-94.3801,48.7111],[-94.3687,48.7065],[-94.3646,48.7059],[-94.3533,48.7042],[-94.3431,48.7035],[-94.3429,48.7035],[-94.3287,48.7045],[-94.3214,48.7067],[-94.3088,48.7103],[-94.2995,48.709],[-94.2911,48.7079],[-94.2829,48.7057],[-94.2781,48.7024],[-94.2745,48.6999],[-94.2694,48.6995],[-94.2644,48.699],[-94.261,48.6966],[-94.258,48.6918],[-94.2565,48.6901],[-94.2529,48.6864],[-94.2521,48.685],[-94.2514,48.6837],[-94.2507,48.6782],[-94.2527,48.6707],[-94.253,48.6693],[-94.2548,48.664],[-94.2546,48.6615],[-94.2509,48.657],[-94.2499,48.6563],[-94.2467,48.6542],[-94.2445,48.6535],[-94.2343,48.6524],[-94.2335,48.6524],[-94.2242,48.6495],[-94.2144,48.6494],[-94.2124,48.6496],[-94.1996,48.651],[-94.1915,48.6506],[-94.1886,48.6504],[-94.1689,48.6483],[-94.1678,48.6482],[-94.1574,48.6458],[-94.1522,48.6455],[-94.1458,48.6458],[-94.1391,48.646],[-94.126,48.6444],[-94.1235,48.6444],[-94.11,48.6443],[-94.1023,48.6455],[-94.0999,48.6459],[-94.0912,48.6437],[-94.0849,48.6441],[-94.0804,48.6442],[-94.0767,48.6442],[-94.0714,48.6459],[-94.0658,48.6462],[-94.0642,48.6438],[-94.0603,48.6431],[-94.0581,48.6434],[-94.0525,48.644],[-94.0432,48.6435],[-94.0393,48.6423],[-94.0364,48.6413],[-94.0356,48.6411],[-94.0295,48.6409],[-94.0153,48.6424],[-94.0069,48.6433],[-94.0007,48.6428],[-93.9931,48.6412],[-93.9897,48.6405],[-93.984,48.6401],[-93.9777,48.6385],[-93.9712,48.6385],[-93.968,48.6385],[-93.9596,48.6372],[-93.953,48.6341],[-93.9497,48.6339],[-93.934,48.6326],[-93.9272,48.6327],[-93.9169,48.6329],[-93.9134,48.6353],[-93.9057,48.6346],[-93.9054,48.6345],[-93.8948,48.6324],[-93.8853,48.6318],[-93.8844,48.6318],[-93.8757,48.6319],[-93.8698,48.6311],[-93.8624,48.631],[-93.848,48.6308],[-93.8443,48.6303],[-93.8404,48.6289],[-93.8393,48.6286],[-93.8365,48.6276],[-93.8334,48.6256],[-93.8292,48.6177],[-93.825,48.6136],[-93.8245,48.613],[-93.8214,48.6092],[-93.8182,48.5994],[-93.8175,48.597],[-93.8172,48.5964],[-93.813,48.588],[-93.8103,48.5846],[-93.8063,48.5796],[-93.8041,48.5703],[-93.8041,48.5702],[-93.8051,48.5644],[-93.808,48.5569],[-93.8088,48.5555],[-93.8119,48.5503],[-93.8102,48.5445],[-93.8109,48.5412],[-93.8109,48.541],[-93.818,48.535],[-93.818,48.5346],[-93.8184,48.5315],[-93.8178,48.5306],[-93.8161,48.5285],[-93.8145,48.5273],[-93.8111,48.5247],[-93.803,48.522],[-93.7964,48.5182],[-93.7933,48.5164],[-93.7879,48.5159],[-93.7745,48.5162],[-93.768,48.5164],[-93.7665,48.5164],[-93.7617,48.5166],[-93.7534,48.5158],[-93.7442,48.5175],[-93.739,48.5185],[-93.731,48.5185],[-93.7225,48.5178],[-93.7206,48.5176],[-93.7108,48.5186],[-93.7061,48.5182],[-93.7006,48.517],[-93.693,48.5152],[-93.6866,48.5154],[-93.6791,48.5167],[-93.6778,48.5169],[-93.6593,48.5165],[-93.657,48.5167],[-93.6473,48.5177],[-93.6433,48.519],[-93.6421,48.5199],[-93.6395,48.5218],[-93.6357,48.5285],[-93.6344,48.5293],[-93.6311,48.5313],[-93.6284,48.5319],[-93.6256,48.5315],[-93.6211,48.5264],[-93.6166,48.5238],[-93.6134,48.5228],[-93.6122,48.5225],[-93.6051,48.5231],[-93.5962,48.5287],[-93.5919,48.5299],[-93.5901,48.5305],[-93.581,48.5271],[-93.5761,48.527],[-93.5701,48.528],[-93.5602,48.5297],[-93.5484,48.5294],[-93.5476,48.5294],[-93.5425,48.53],[-93.5366,48.5319],[-93.5269,48.5341],[-93.5263,48.5341],[-93.5244,48.5343],[-93.5171,48.5348],[-93.5047,48.5399],[-93.501,48.5414],[-93.4952,48.5426],[-93.4854,48.5433],[-93.4833,48.5437],[-93.4673,48.5465],[-93.4655,48.5478],[-93.4625,48.5498],[-93.462,48.5505],[-93.4596,48.5537],[-93.4576,48.5598],[-93.4576,48.5621],[-93.4575,48.5672],[-93.4619,48.5731],[-93.4619,48.5734],[-93.4631,48.5767],[-93.4671,48.5885],[-93.4656,48.59],[-93.4654,48.5915],[-93.4654,48.5917],[-93.4627,48.5927],[-93.46,48.5927],[-93.4547,48.5927],[-93.4398,48.5937],[-93.4385,48.5942],[-93.4347,48.5954],[-93.4298,48.5997],[-93.4226,48.6032],[-93.4193,48.6036],[-93.416,48.605],[-93.4152,48.6053],[-93.415,48.6056],[-93.4144,48.6064],[-93.4056,48.6099],[-93.4034,48.61],[-93.4029,48.6077],[-93.4013,48.6079],[-93.3994,48.6055],[-93.3986,48.6045],[-93.3953,48.6038],[-93.3937,48.6041],[-93.3837,48.606],[-93.3724,48.6059],[-93.3714,48.6059],[-93.3672,48.6082],[-93.3619,48.6141],[-93.355,48.6114],[-93.3526,48.6135],[-93.3533,48.615],[-93.3513,48.62],[-93.3505,48.6219],[-93.3486,48.6265],[-93.3276,48.6302],[-93.3057,48.634],[-93.3048,48.6341],[-93.2838,48.6378],[-93.2634,48.6413],[-93.2546,48.6429],[-93.2422,48.6428],[-93.2193,48.6426],[-93.2075,48.6426],[-93.1975,48.6365],[-93.191,48.6325],[-93.184,48.6282],[-93.1783,48.6231],[-93.1754,48.6232],[-93.1531,48.6244],[-93.1319,48.6256],[-93.1104,48.6267],[-93.0903,48.6278],[-93.0884,48.6278],[-93.0886,48.6163],[-93.0895,48.6016],[-93.0898,48.5872],[-93.09,48.5727],[-93.0902,48.5583],[-93.0902,48.5441],[-93.0903,48.5296],[-93.0905,48.5151],[-93.0905,48.501],[-93.091,48.4884],[-93.0911,48.4867],[-93.0914,48.474],[-93.0915,48.4724],[-93.0918,48.4596],[-93.0919,48.458],[-93.092,48.4449],[-93.092,48.4436],[-93.0922,48.4303],[-93.0922,48.429],[-93.0923,48.4147],[-93.0935,48.4147],[-93.0938,48.4024],[-93.094,48.3879],[-93.094,48.3734],[-93.0945,48.3589],[-93.0948,48.3442],[-93.0948,48.3298],[-93.0953,48.3153],[-93.0952,48.3004],[-93.095,48.2862],[-93.0952,48.2716],[-93.0953,48.2576],[-93.0949,48.2426],[-93.0949,48.2425],[-93.0977,48.2426],[-93.0977,48.2271],[-93.0978,48.2126],[-93.0979,48.1981],[-93.0975,48.1836],[-93.097,48.1692],[-93.097,48.1546],[-93.097,48.1402],[-93.0969,48.1259],[-93.0972,48.1114],[-93.097,48.0969],[-93.0968,48.0823],[-93.0965,48.0679],[-93.0965,48.0678],[-93.0892,48.0679],[-93.0892,48.0509],[-93.089,48.0366],[-93.0886,48.022],[-93.0887,48.0075],[-93.0872,47.9932],[-93.088,47.9787],[-93.0809,47.9786],[-93.0809,47.967],[-93.0808,47.9647],[-93.0808,47.9525],[-93.0808,47.9504],[-93.0809,47.938],[-93.0809,47.9356],[-93.0809,47.9235],[-93.0809,47.9212],[-93.0809,47.9088],[-93.0809,47.9067],[-93.0808,47.8945],[-93.0808,47.8922],[-93.1015,47.8927],[-93.1232,47.893],[-93.1448,47.8928],[-93.1656,47.8931],[-93.1671,47.8932],[-93.1871,47.8931],[-93.1893,47.8931],[-93.2087,47.8933],[-93.2115,47.8934],[-93.2331,47.8937],[-93.2532,47.8936],[-93.2745,47.8938],[-93.2962,47.8939],[-93.3169,47.894],[-93.3392,47.8941],[-93.3603,47.8942],[-93.3809,47.8943],[-93.4024,47.8944],[-93.4235,47.8945],[-93.4442,47.8946],[-93.466,47.895],[-93.4874,47.8956],[-93.4892,47.8957],[-93.4933,47.8958],[-93.5085,47.8962],[-93.5105,47.8963],[-93.5297,47.8967],[-93.5303,47.8967],[-93.532,47.8968],[-93.5517,47.8973],[-93.5532,47.8974],[-93.5729,47.8981],[-93.5747,47.8982],[-93.5962,47.8978],[-93.5966,47.8978],[-93.6179,47.8977],[-93.6187,47.8977],[-93.6388,47.8977],[-93.6395,47.8976],[-93.6604,47.8976],[-93.6612,47.8976],[-93.6817,47.8976],[-93.6826,47.8976],[-93.7031,47.8976],[-93.7038,47.8976],[-93.7249,47.8975],[-93.7248,47.8989],[-93.7466,47.8989],[-93.768,47.8991],[-93.7758,47.8991],[-93.7758,47.899],[-93.776,47.8897],[-93.776,47.8842],[-93.7762,47.8753],[-93.7761,47.8697],[-93.7761,47.8607],[-93.7761,47.8553],[-93.7761,47.8464],[-93.7896,47.8465],[-93.7971,47.8466],[-93.8189,47.8467],[-93.8407,47.8468],[-93.8627,47.8469],[-93.8831,47.8471],[-93.9067,47.8471],[-93.9288,47.8475],[-93.9496,47.8475],[-93.9506,47.8475],[-93.971,47.8475],[-93.9725,47.8475],[-93.9927,47.8475],[-93.9942,47.8475],[-94.0141,47.8476],[-94.0161,47.8476],[-94.0375,47.8477],[-94.0591,47.8474],[-94.0807,47.8471],[-94.1022,47.8471],[-94.1239,47.8466],[-94.1448,47.8463],[-94.1657,47.8461],[-94.1822,47.8461],[-94.1871,47.846],[-94.2037,47.846],[-94.2086,47.846],[-94.2252,47.846],[-94.23,47.8461],[-94.2467,47.8462],[-94.2515,47.8462],[-94.2681,47.8462],[-94.2728,47.8462],[-94.2887,47.8462],[-94.3103,47.8458],[-94.3315,47.846],[-94.3532,47.8464],[-94.3747,47.8462],[-94.3964,47.8461],[-94.4185,47.8459],[-94.4186,47.86],[-94.4184,47.8744],[-94.418,47.8886],[-94.4177,47.9031],[-94.4176,47.9041],[-94.4175,47.9175],[-94.4174,47.9186],[-94.4175,47.9332],[-94.4174,47.9477],[-94.4172,47.9623],[-94.4173,47.9769],[-94.4176,47.9914],[-94.4177,48.006],[-94.4176,48.02],[-94.4236,48.0199],[-94.4241,48.0344],[-94.4246,48.0489],[-94.4247,48.0632],[-94.4234,48.0776],[-94.4231,48.092],[-94.4233,48.1059],[-94.4234,48.1204],[-94.4236,48.1348],[-94.4233,48.1491],[-94.4235,48.1637],[-94.4235,48.1781],[-94.4233,48.1923],[-94.4236,48.2067],[-94.4238,48.2212],[-94.4237,48.2356],[-94.4237,48.2504],[-94.424,48.2649],[-94.4243,48.2791],[-94.4244,48.2938],[-94.4246,48.3081],[-94.4248,48.3227],[-94.425,48.3372],[-94.4253,48.352],[-94.4252,48.3675],[-94.4288,48.3675],[-94.4289,48.3821],[-94.4293,48.3964],[-94.4294,48.411],[-94.4293,48.4254],[-94.4292,48.4399],[-94.4293,48.4543],[-94.4296,48.4688],[-94.4296,48.4832],[-94.4299,48.4977],[-94.4303,48.512],[-94.4303,48.5264],[-94.43,48.5409],[-94.4295,48.5554],[-94.4291,48.5698],[-94.4289,48.5844],[-94.4289,48.5988],[-94.4292,48.6133],[-94.4294,48.6276],[-94.4297,48.642],[-94.43,48.6564],[-94.4301,48.6708],[-94.43,48.6852],[-94.4299,48.6998],[-94.4299,48.7012]]],"type":"Polygon"},"id":"36","properties":{"Area":8167237870.91888,"CTYONLY_":5,"Code":"KOOC","LASTMOD":"1999-12-31T23:59:59Z","Name":"Koochiching","Perimiter":412897.43594},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&filter=%7B%22op%22%3A%22in%22%2C%22args%22%3A%5B%7B%22property%22%3A%22CTYONLY_%22%7D%2C%5B3%2C5%5D%5D%7D&filter-lang=cql2-json","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&filter=%7B%22op%22%3A%22in%22%2C%22args%22%3A%5B%7B%22property%22%3A%22CTYONLY_%22%7D%2C%5B3%2C5%5D%5D%7D&filter-lang=cql2-json","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":2,"numberReturned":2,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_json_le.json.txt b/msautotest/api/expected/ogcapi_cql2_json_le.json.txt new file mode 100644 index 0000000000..43283d27dd --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_json_le.json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 2 +OGC-NumberReturned: 2 + +{"features":[{"geometry":{"coordinates":[[[-95.3231,48.999],[-95.3109,48.999],[-95.2889,48.9989],[-95.2852,48.9989],[-95.2669,48.9989],[-95.245,48.9989],[-95.2232,48.9989],[-95.2014,48.9989],[-95.1792,48.9989],[-95.1574,48.9989],[-95.1531,48.9989],[-95.1531,49.0031],[-95.1532,49.0179],[-95.1532,49.0325],[-95.1532,49.047],[-95.1532,49.0619],[-95.1532,49.0765],[-95.1532,49.0911],[-95.1532,49.1057],[-95.1532,49.1205],[-95.1532,49.1354],[-95.1532,49.1499],[-95.1532,49.1642],[-95.1532,49.1788],[-95.1532,49.1807],[-95.1532,49.1931],[-95.1532,49.1966],[-95.1532,49.2077],[-95.1533,49.2131],[-95.1533,49.2219],[-95.1533,49.2308],[-95.1533,49.2365],[-95.1533,49.2472],[-95.1533,49.2512],[-95.1533,49.2655],[-95.1533,49.2697],[-95.1533,49.2802],[-95.1533,49.2882],[-95.1533,49.2945],[-95.1533,49.3072],[-95.1533,49.309],[-95.1533,49.3234],[-95.1533,49.3237],[-95.1533,49.3381],[-95.1533,49.3476],[-95.1533,49.3525],[-95.1533,49.3636],[-95.1533,49.367],[-95.1533,49.3705],[-95.1533,49.3776],[-95.1533,49.3813],[-95.1533,49.3845],[-95.1503,49.383],[-95.1499,49.3813],[-95.1498,49.3807],[-95.1467,49.3802],[-95.145,49.3784],[-95.1418,49.3784],[-95.1397,49.3762],[-95.1367,49.3751],[-95.1324,49.3736],[-95.1287,49.3705],[-95.1171,49.367],[-95.1159,49.3666],[-95.1145,49.3666],[-95.1098,49.3664],[-95.1031,49.3652],[-95.1031,49.3636],[-95.0926,49.3617],[-95.0897,49.3612],[-95.0707,49.3564],[-95.0582,49.3533],[-95.0495,49.3532],[-95.0479,49.3533],[-95.0262,49.3554],[-95.0141,49.3565],[-95.0047,49.3612],[-94.993,49.367],[-94.9889,49.369],[-94.9818,49.3684],[-94.9742,49.3678],[-94.9597,49.3699],[-94.9573,49.3702],[-94.952,49.3688],[-94.948,49.367],[-94.9376,49.3625],[-94.9152,49.3529],[-94.9143,49.3524],[-94.909,49.3502],[-94.9065,49.3484],[-94.8933,49.3414],[-94.8865,49.3378],[-94.8782,49.3334],[-94.8712,49.3308],[-94.854,49.3244],[-94.8492,49.3244],[-94.8363,49.3243],[-94.8311,49.3236],[-94.8271,49.323],[-94.8162,49.3214],[-94.8243,49.309],[-94.8243,49.3088],[-94.8255,49.2944],[-94.8255,49.2943],[-94.8204,49.28],[-94.8152,49.2653],[-94.8103,49.2515],[-94.8059,49.2388],[-94.8051,49.2367],[-94.8001,49.2224],[-94.7973,49.2144],[-94.7975,49.2079],[-94.7979,49.1979],[-94.7965,49.1936],[-94.7918,49.1792],[-94.7871,49.1646],[-94.7833,49.153],[-94.7823,49.15],[-94.7776,49.1357],[-94.7727,49.1206],[-94.7727,49.1206],[-94.7611,49.1096],[-94.7571,49.1058],[-94.7496,49.0988],[-94.7474,49.0918],[-94.7429,49.0773],[-94.7394,49.0657],[-94.7385,49.063],[-94.7344,49.0497],[-94.7299,49.0351],[-94.7254,49.0205],[-94.7207,49.0052],[-94.7184,48.9979],[-94.7162,48.9907],[-94.7117,48.9761],[-94.7072,48.9615],[-94.7027,48.9468],[-94.6982,48.9322],[-94.6968,48.9276],[-94.6844,48.8875],[-94.6834,48.8842],[-94.6842,48.8724],[-94.6855,48.8719],[-94.6923,48.8691],[-94.6902,48.8636],[-94.6914,48.8591],[-94.693,48.8535],[-94.6881,48.8447],[-94.6855,48.8401],[-94.6963,48.836],[-94.6975,48.8355],[-94.702,48.8319],[-94.7025,48.8302],[-94.7042,48.8243],[-94.6991,48.8159],[-94.6962,48.8111],[-94.6951,48.8092],[-94.6958,48.8012],[-94.6959,48.7997],[-94.6944,48.7895],[-94.6934,48.7864],[-94.6909,48.7781],[-94.687,48.7752],[-94.6776,48.772],[-94.6768,48.7717],[-94.6746,48.7705],[-94.6671,48.7662],[-94.6603,48.7605],[-94.6557,48.7581],[-94.6525,48.7565],[-94.652,48.7562],[-94.6453,48.7491],[-94.6453,48.7441],[-94.6443,48.7434],[-94.6414,48.7413],[-94.631,48.7392],[-94.6301,48.739],[-94.6191,48.7373],[-94.6106,48.7318],[-94.6084,48.731],[-94.6028,48.7289],[-94.6011,48.7283],[-94.5962,48.7248],[-94.5913,48.7197],[-94.5876,48.7176],[-94.5867,48.7175],[-94.5685,48.7156],[-94.5622,48.7159],[-94.5558,48.7163],[-94.549,48.7148],[-94.5487,48.7146],[-94.5457,48.7124],[-94.5396,48.7036],[-94.539,48.7028],[-94.5329,48.7013],[-94.5247,48.7016],[-94.5178,48.7008],[-94.5173,48.7008],[-94.5093,48.7006],[-94.5066,48.6999],[-94.4996,48.698],[-94.4958,48.698],[-94.4863,48.698],[-94.4739,48.6969],[-94.4706,48.6966],[-94.4631,48.6953],[-94.4568,48.6933],[-94.4523,48.6925],[-94.4517,48.6925],[-94.4465,48.693],[-94.4388,48.6949],[-94.4319,48.6998],[-94.4299,48.7012],[-94.4299,48.6998],[-94.43,48.6852],[-94.4301,48.6708],[-94.43,48.6564],[-94.4297,48.642],[-94.4294,48.6276],[-94.4292,48.6133],[-94.4289,48.5988],[-94.4289,48.5844],[-94.4291,48.5698],[-94.4295,48.5554],[-94.43,48.5409],[-94.4303,48.5264],[-94.4303,48.512],[-94.4299,48.4977],[-94.4296,48.4832],[-94.4296,48.4688],[-94.4293,48.4543],[-94.4292,48.4399],[-94.4293,48.4254],[-94.4294,48.411],[-94.4293,48.3964],[-94.4289,48.3821],[-94.4288,48.3675],[-94.4471,48.3675],[-94.4505,48.3675],[-94.4688,48.3675],[-94.4722,48.3674],[-94.4906,48.3674],[-94.4924,48.3674],[-94.4941,48.3674],[-94.5118,48.3675],[-94.5157,48.3674],[-94.5335,48.3674],[-94.5378,48.3674],[-94.5536,48.3674],[-94.5593,48.3674],[-94.5754,48.3674],[-94.5812,48.3674],[-94.5971,48.3675],[-94.6029,48.3674],[-94.6188,48.3673],[-94.6245,48.3673],[-94.6405,48.3673],[-94.6465,48.3673],[-94.6505,48.3673],[-94.6622,48.3673],[-94.6679,48.3673],[-94.6694,48.3672],[-94.683,48.3671],[-94.6898,48.3671],[-94.7099,48.3669],[-94.7117,48.3668],[-94.7315,48.3669],[-94.7329,48.3669],[-94.7533,48.3669],[-94.7549,48.3669],[-94.7748,48.3669],[-94.7765,48.3669],[-94.7967,48.3669],[-94.7983,48.3669],[-94.8183,48.3669],[-94.8199,48.3669],[-94.8399,48.3669],[-94.8416,48.3669],[-94.8616,48.3667],[-94.8632,48.3667],[-94.8833,48.3667],[-94.8849,48.3666],[-94.9049,48.3666],[-94.9065,48.3666],[-94.9264,48.3667],[-94.9283,48.3667],[-94.9469,48.3666],[-94.95,48.3666],[-94.9684,48.3667],[-94.9716,48.3667],[-94.9901,48.3667],[-94.9932,48.3667],[-95.0119,48.3665],[-95.0153,48.3665],[-95.0337,48.3665],[-95.0369,48.3665],[-95.0555,48.3665],[-95.0586,48.3665],[-95.0773,48.3664],[-95.0801,48.3664],[-95.099,48.3663],[-95.1008,48.3663],[-95.1018,48.3663],[-95.1207,48.3663],[-95.1236,48.3663],[-95.1315,48.3662],[-95.1424,48.3662],[-95.1454,48.3662],[-95.164,48.3661],[-95.1669,48.3661],[-95.1861,48.3661],[-95.1887,48.3661],[-95.1983,48.3661],[-95.2066,48.3661],[-95.2106,48.3661],[-95.211,48.3797],[-95.211,48.3808],[-95.2111,48.3941],[-95.2111,48.3952],[-95.2112,48.4087],[-95.2112,48.4096],[-95.2113,48.4232],[-95.2113,48.4242],[-95.2113,48.4255],[-95.2113,48.4376],[-95.2113,48.4387],[-95.2113,48.4522],[-95.2112,48.4529],[-95.211,48.4666],[-95.211,48.4673],[-95.2111,48.4816],[-95.2112,48.4962],[-95.2111,48.5101],[-95.2111,48.5109],[-95.2115,48.5244],[-95.2115,48.5252],[-95.2119,48.54],[-95.2324,48.5399],[-95.2339,48.5399],[-95.2537,48.5398],[-95.2554,48.5398],[-95.2756,48.54],[-95.2773,48.54],[-95.2975,48.5401],[-95.2992,48.5402],[-95.3194,48.54],[-95.321,48.54],[-95.3412,48.5402],[-95.3425,48.5402],[-95.3424,48.5548],[-95.3423,48.5691],[-95.3423,48.5836],[-95.3426,48.5979],[-95.3424,48.6127],[-95.3426,48.6271],[-95.3425,48.6415],[-95.3424,48.6561],[-95.3423,48.6705],[-95.3424,48.6849],[-95.3425,48.6995],[-95.3425,48.7131],[-95.3302,48.713],[-95.3205,48.713],[-95.3084,48.713],[-95.3051,48.713],[-95.299,48.713],[-95.2866,48.713],[-95.2767,48.713],[-95.2656,48.713],[-95.2645,48.713],[-95.255,48.713],[-95.2427,48.713],[-95.2331,48.713],[-95.2206,48.713],[-95.2112,48.713],[-95.1991,48.713],[-95.1917,48.713],[-95.1773,48.713],[-95.1697,48.7129],[-95.1554,48.7129],[-95.1477,48.7129],[-95.1333,48.713],[-95.1297,48.713],[-95.1259,48.7129],[-95.1119,48.7129],[-95.1104,48.7129],[-95.1046,48.7129],[-95.0898,48.713],[-95.0899,48.7277],[-95.0901,48.7421],[-95.0901,48.7566],[-95.0903,48.7711],[-95.0903,48.7855],[-95.0903,48.8],[-95.0909,48.8147],[-95.0908,48.8291],[-95.0907,48.8436],[-95.0908,48.858],[-95.0908,48.8724],[-95.0911,48.8869],[-95.0912,48.9014],[-95.0914,48.916],[-95.0914,48.9208],[-95.0919,48.9207],[-95.0927,48.9204],[-95.0944,48.9193],[-95.0946,48.9191],[-95.0961,48.9181],[-95.097,48.9176],[-95.0971,48.9172],[-95.0975,48.9164],[-95.098,48.916],[-95.0981,48.9159],[-95.1008,48.9142],[-95.102,48.9132],[-95.1032,48.9127],[-95.1042,48.9121],[-95.1056,48.9113],[-95.108,48.9099],[-95.1096,48.9089],[-95.1107,48.9082],[-95.1126,48.9073],[-95.113,48.9072],[-95.1132,48.9071],[-95.1137,48.9069],[-95.1141,48.9064],[-95.114,48.9061],[-95.1144,48.9052],[-95.1151,48.9046],[-95.1163,48.9037],[-95.1182,48.9029],[-95.1204,48.9019],[-95.1205,48.9017],[-95.121,48.9016],[-95.1214,48.9013],[-95.1228,48.9006],[-95.1233,48.9004],[-95.1239,48.9001],[-95.1252,48.8998],[-95.1312,48.8975],[-95.1322,48.8973],[-95.1337,48.8969],[-95.1343,48.8963],[-95.1348,48.8963],[-95.1351,48.8963],[-95.1355,48.8959],[-95.1381,48.8949],[-95.1404,48.8943],[-95.1436,48.8937],[-95.1438,48.8934],[-95.1459,48.8929],[-95.1469,48.8927],[-95.1483,48.8923],[-95.1508,48.8922],[-95.1528,48.8921],[-95.1555,48.892],[-95.1564,48.8919],[-95.1579,48.8919],[-95.1602,48.892],[-95.1618,48.892],[-95.1641,48.8917],[-95.1648,48.8913],[-95.1674,48.8907],[-95.1701,48.8902],[-95.173,48.8897],[-95.1764,48.8893],[-95.1791,48.889],[-95.1797,48.889],[-95.1819,48.8888],[-95.1851,48.8882],[-95.1863,48.8877],[-95.1877,48.8874],[-95.1889,48.8873],[-95.1901,48.887],[-95.1913,48.8868],[-95.1919,48.8866],[-95.1924,48.8865],[-95.1956,48.8862],[-95.1986,48.8855],[-95.2005,48.8856],[-95.2009,48.8855],[-95.2024,48.8852],[-95.2059,48.8848],[-95.2085,48.8846],[-95.2112,48.8848],[-95.2115,48.8847],[-95.2117,48.8847],[-95.2122,48.8842],[-95.2144,48.8843],[-95.2151,48.884],[-95.2159,48.8839],[-95.217,48.8835],[-95.2188,48.8835],[-95.2193,48.8832],[-95.22,48.8831],[-95.2207,48.8831],[-95.2208,48.8831],[-95.2212,48.883],[-95.2252,48.8819],[-95.2265,48.8816],[-95.2287,48.8815],[-95.231,48.8814],[-95.2335,48.8814],[-95.2356,48.8815],[-95.2381,48.8817],[-95.2391,48.8819],[-95.2407,48.8821],[-95.2423,48.8821],[-95.2429,48.8822],[-95.2429,48.8822],[-95.2439,48.8823],[-95.2458,48.8829],[-95.2472,48.8835],[-95.248,48.8836],[-95.2485,48.8832],[-95.2496,48.8834],[-95.2502,48.8835],[-95.2507,48.8836],[-95.2517,48.8839],[-95.2548,48.8845],[-95.256,48.885],[-95.257,48.8858],[-95.2585,48.8867],[-95.2585,48.8867],[-95.2627,48.8877],[-95.2635,48.888],[-95.2639,48.8883],[-95.2646,48.8885],[-95.265,48.8886],[-95.2654,48.8888],[-95.2666,48.8894],[-95.2674,48.89],[-95.2677,48.8903],[-95.268,48.8905],[-95.2713,48.8915],[-95.2724,48.8921],[-95.2745,48.8931],[-95.2751,48.8938],[-95.2753,48.8943],[-95.2748,48.8951],[-95.2749,48.8956],[-95.2755,48.8959],[-95.2759,48.8962],[-95.2763,48.8963],[-95.2765,48.8962],[-95.277,48.8958],[-95.2773,48.8957],[-95.2782,48.8956],[-95.279,48.8957],[-95.2796,48.8962],[-95.2803,48.8965],[-95.2813,48.8967],[-95.2839,48.8975],[-95.2853,48.8977],[-95.2861,48.8976],[-95.2865,48.8975],[-95.287,48.8976],[-95.2872,48.8977],[-95.2879,48.8979],[-95.2882,48.8981],[-95.289,48.8994],[-95.2896,48.9],[-95.2901,48.9003],[-95.2911,48.9006],[-95.2911,48.9008],[-95.2906,48.9011],[-95.2907,48.9014],[-95.2908,48.9016],[-95.2909,48.9017],[-95.2914,48.9019],[-95.2927,48.9019],[-95.2935,48.902],[-95.2937,48.9023],[-95.2941,48.9027],[-95.2949,48.9028],[-95.2967,48.9027],[-95.2976,48.9026],[-95.298,48.9027],[-95.2983,48.9028],[-95.2993,48.9035],[-95.3005,48.904],[-95.3002,48.9045],[-95.3001,48.9046],[-95.3001,48.9047],[-95.3,48.9047],[-95.3,48.9047],[-95.2999,48.9048],[-95.2999,48.9048],[-95.2999,48.9048],[-95.2997,48.905],[-95.2996,48.9051],[-95.2994,48.9053],[-95.2992,48.9055],[-95.2991,48.9057],[-95.2989,48.906],[-95.2988,48.906],[-95.2986,48.9063],[-95.2985,48.9064],[-95.2985,48.9065],[-95.2983,48.9068],[-95.2982,48.9068],[-95.2981,48.907],[-95.298,48.9071],[-95.298,48.9071],[-95.298,48.9071],[-95.2979,48.9071],[-95.2979,48.9072],[-95.2979,48.9072],[-95.2978,48.9072],[-95.2978,48.9072],[-95.2978,48.9073],[-95.2977,48.9073],[-95.2976,48.9074],[-95.2973,48.9077],[-95.2973,48.908],[-95.2973,48.9081],[-95.2978,48.9083],[-95.2999,48.9086],[-95.3017,48.9093],[-95.3027,48.91],[-95.3038,48.9114],[-95.3043,48.9119],[-95.3059,48.9127],[-95.3061,48.9128],[-95.3064,48.9129],[-95.3074,48.9135],[-95.3078,48.9141],[-95.3085,48.9146],[-95.3092,48.9149],[-95.3093,48.9149],[-95.3102,48.9155],[-95.3109,48.9163],[-95.3115,48.9172],[-95.3119,48.9178],[-95.3126,48.919],[-95.3132,48.9198],[-95.3141,48.921],[-95.315,48.9222],[-95.3168,48.9245],[-95.3195,48.9285],[-95.3208,48.9305],[-95.3209,48.9307],[-95.3222,48.9327],[-95.3228,48.9344],[-95.3223,48.9355],[-95.3225,48.9358],[-95.3229,48.9373],[-95.3231,48.9389],[-95.3228,48.9403],[-95.3225,48.9409],[-95.3219,48.9412],[-95.3189,48.9419],[-95.3181,48.9421],[-95.3168,48.9431],[-95.3154,48.9448],[-95.3148,48.9452],[-95.3141,48.9457],[-95.3131,48.946],[-95.3114,48.9461],[-95.3102,48.9463],[-95.3095,48.9463],[-95.3088,48.9464],[-95.3086,48.9465],[-95.3086,48.9469],[-95.3085,48.947],[-95.3078,48.9466],[-95.3074,48.9465],[-95.3071,48.9466],[-95.3071,48.9469],[-95.3079,48.9474],[-95.3092,48.9477],[-95.3096,48.9478],[-95.3103,48.948],[-95.3104,48.9484],[-95.3103,48.9485],[-95.31,48.9485],[-95.3099,48.9484],[-95.3096,48.9482],[-95.3094,48.9481],[-95.3081,48.948],[-95.3071,48.9477],[-95.3062,48.9472],[-95.3062,48.9472],[-95.3061,48.9469],[-95.3062,48.9463],[-95.3063,48.9462],[-95.3069,48.9456],[-95.3069,48.9455],[-95.3068,48.9454],[-95.3061,48.9454],[-95.3053,48.9459],[-95.305,48.9462],[-95.3046,48.947],[-95.3046,48.9482],[-95.3052,48.9495],[-95.3061,48.9502],[-95.3079,48.9509],[-95.3089,48.9511],[-95.3097,48.951],[-95.3104,48.951],[-95.3108,48.9512],[-95.3115,48.952],[-95.312,48.9524],[-95.3126,48.9524],[-95.3129,48.9523],[-95.3129,48.9521],[-95.3119,48.9507],[-95.3119,48.9502],[-95.3123,48.9502],[-95.3125,48.9503],[-95.3131,48.9503],[-95.3141,48.9508],[-95.3151,48.951],[-95.3154,48.9513],[-95.3177,48.9525],[-95.3181,48.9531],[-95.3182,48.9535],[-95.3177,48.9545],[-95.3175,48.9552],[-95.3179,48.9559],[-95.3188,48.9562],[-95.3191,48.9569],[-95.3202,48.9581],[-95.3206,48.959],[-95.3206,48.9595],[-95.3206,48.9598],[-95.3202,48.9606],[-95.3193,48.9622],[-95.3193,48.964],[-95.3198,48.9643],[-95.3201,48.9648],[-95.3207,48.9669],[-95.3212,48.9672],[-95.3227,48.9685],[-95.3232,48.9692],[-95.3241,48.9703],[-95.3247,48.972],[-95.3248,48.9728],[-95.3249,48.9738],[-95.325,48.9743],[-95.3253,48.976],[-95.3257,48.9784],[-95.3255,48.9789],[-95.3256,48.98],[-95.3257,48.9814],[-95.3253,48.9832],[-95.3245,48.985],[-95.3242,48.9859],[-95.3227,48.9884],[-95.3224,48.9889],[-95.3206,48.9921],[-95.3204,48.9924],[-95.3191,48.9941],[-95.3181,48.995],[-95.3178,48.9958],[-95.3178,48.9961],[-95.3179,48.9961],[-95.3182,48.996],[-95.3187,48.9956],[-95.3191,48.9953],[-95.3197,48.9954],[-95.3201,48.9956],[-95.3206,48.9961],[-95.3204,48.9964],[-95.3202,48.9973],[-95.3204,48.9976],[-95.3224,48.9984],[-95.3231,48.999]]],"type":"Polygon"},"id":"39","properties":{"Area":4608320923.49768,"CTYONLY_":2,"Code":"LOTW","LASTMOD":"1976-07-04T12:00:00Z","Name":"Lake of the Woods","Perimiter":388250.14572},"type":"Feature"},{"geometry":{"coordinates":[[[-96.4054,49.0001],[-96.4054,48.9947],[-96.4054,48.994],[-96.4054,48.9803],[-96.4054,48.9793],[-96.4053,48.9705],[-96.4053,48.9658],[-96.4053,48.9648],[-96.4053,48.9515],[-96.4053,48.9504],[-96.4053,48.9371],[-96.4053,48.936],[-96.4054,48.9225],[-96.4054,48.9214],[-96.4053,48.9137],[-96.4053,48.9081],[-96.4053,48.9068],[-96.405,48.8926],[-96.405,48.878],[-96.4047,48.8635],[-96.4045,48.8491],[-96.4043,48.8343],[-96.4042,48.8198],[-96.4042,48.8048],[-96.4042,48.7903],[-96.4045,48.7758],[-96.4047,48.7607],[-96.4048,48.7465],[-96.4048,48.7318],[-96.4049,48.7172],[-96.388,48.7172],[-96.3873,48.7172],[-96.3866,48.703],[-96.3874,48.6887],[-96.3871,48.6741],[-96.3877,48.6599],[-96.3879,48.6454],[-96.388,48.6313],[-96.389,48.6165],[-96.3891,48.6024],[-96.3884,48.5877],[-96.3882,48.5733],[-96.3879,48.5588],[-96.3882,48.5442],[-96.4101,48.544],[-96.4318,48.5438],[-96.4535,48.5436],[-96.4754,48.5435],[-96.4973,48.5434],[-96.518,48.5434],[-96.54,48.5434],[-96.5621,48.5436],[-96.5839,48.5437],[-96.6058,48.5437],[-96.6278,48.5437],[-96.6493,48.5437],[-96.6713,48.5436],[-96.6931,48.5437],[-96.7151,48.5437],[-96.7368,48.5437],[-96.7585,48.5436],[-96.7803,48.5435],[-96.8023,48.5436],[-96.824,48.5436],[-96.8459,48.5434],[-96.8678,48.5433],[-96.8896,48.5433],[-96.9115,48.5432],[-96.9138,48.5433],[-96.9331,48.5435],[-96.9551,48.5437],[-96.9768,48.544],[-96.9985,48.5441],[-97.0194,48.5441],[-97.0416,48.5442],[-97.0635,48.5441],[-97.0852,48.5441],[-97.107,48.544],[-97.1287,48.5439],[-97.1509,48.5439],[-97.1631,48.544],[-97.1637,48.5445],[-97.1659,48.5483],[-97.1662,48.5509],[-97.1661,48.5527],[-97.1654,48.5536],[-97.1645,48.554],[-97.1628,48.5543],[-97.1613,48.5539],[-97.1592,48.5528],[-97.1577,48.5518],[-97.1557,48.5512],[-97.1538,48.5513],[-97.1513,48.5515],[-97.1507,48.5515],[-97.1493,48.5516],[-97.1474,48.5516],[-97.1444,48.5514],[-97.1407,48.5515],[-97.1387,48.5522],[-97.1379,48.553],[-97.1379,48.5542],[-97.1391,48.5554],[-97.141,48.5566],[-97.1426,48.5571],[-97.1464,48.5573],[-97.1505,48.5574],[-97.1515,48.5574],[-97.1551,48.5574],[-97.1578,48.5573],[-97.1606,48.5571],[-97.1631,48.5571],[-97.1646,48.5572],[-97.167,48.5575],[-97.1697,48.5584],[-97.1721,48.5591],[-97.1727,48.5593],[-97.174,48.5599],[-97.1749,48.5606],[-97.1753,48.5614],[-97.1754,48.5623],[-97.1749,48.5631],[-97.1744,48.5639],[-97.1723,48.5648],[-97.1721,48.5648],[-97.1706,48.5652],[-97.1687,48.5655],[-97.167,48.5658],[-97.1651,48.5659],[-97.1613,48.5661],[-97.1541,48.5669],[-97.153,48.5671],[-97.1516,48.5677],[-97.1503,48.5688],[-97.1496,48.5695],[-97.1487,48.5707],[-97.1477,48.5727],[-97.1477,48.5728],[-97.1476,48.5731],[-97.1483,48.5763],[-97.15,48.5775],[-97.1501,48.5775],[-97.1548,48.5779],[-97.1592,48.5785],[-97.1605,48.58],[-97.16,48.5816],[-97.1578,48.5826],[-97.1562,48.5828],[-97.1541,48.5826],[-97.1524,48.5823],[-97.15,48.5815],[-97.1494,48.5813],[-97.1484,48.5811],[-97.1449,48.5815],[-97.1436,48.5824],[-97.1431,48.5834],[-97.1429,48.5838],[-97.142,48.5876],[-97.1418,48.5886],[-97.1415,48.5909],[-97.1422,48.5926],[-97.1433,48.5936],[-97.1451,48.594],[-97.1471,48.594],[-97.1497,48.5937],[-97.1525,48.594],[-97.1536,48.5949],[-97.1535,48.5957],[-97.1527,48.5962],[-97.1524,48.5969],[-97.1516,48.598],[-97.1498,48.5981],[-97.1497,48.5981],[-97.1463,48.5977],[-97.1443,48.5981],[-97.143,48.5987],[-97.1416,48.6002],[-97.1403,48.6021],[-97.14,48.6025],[-97.138,48.6044],[-97.1359,48.6054],[-97.1345,48.6065],[-97.1341,48.6075],[-97.1349,48.6082],[-97.1358,48.6086],[-97.137,48.6088],[-97.1396,48.6086],[-97.1443,48.6078],[-97.1474,48.6081],[-97.1494,48.6089],[-97.1495,48.609],[-97.1505,48.6115],[-97.1501,48.6124],[-97.1493,48.6129],[-97.1478,48.6138],[-97.145,48.6146],[-97.1408,48.6149],[-97.137,48.6144],[-97.134,48.6136],[-97.1319,48.6133],[-97.1309,48.6137],[-97.1289,48.614],[-97.1286,48.6153],[-97.1293,48.6168],[-97.1295,48.617],[-97.1311,48.6184],[-97.1342,48.6199],[-97.1353,48.6212],[-97.1346,48.6224],[-97.133,48.6228],[-97.131,48.6227],[-97.1291,48.6222],[-97.1277,48.6212],[-97.1274,48.621],[-97.1259,48.6195],[-97.1253,48.619],[-97.1243,48.6183],[-97.1231,48.6178],[-97.1216,48.6176],[-97.12,48.6178],[-97.1193,48.6182],[-97.1186,48.6191],[-97.1183,48.6198],[-97.1186,48.6209],[-97.1198,48.6221],[-97.1209,48.6232],[-97.1212,48.6233],[-97.122,48.624],[-97.1228,48.6245],[-97.1236,48.625],[-97.1241,48.6254],[-97.1245,48.6257],[-97.1249,48.6259],[-97.1253,48.6261],[-97.126,48.6264],[-97.1266,48.6266],[-97.1272,48.627],[-97.1279,48.6273],[-97.1288,48.6278],[-97.1296,48.6282],[-97.1302,48.6288],[-97.1305,48.6292],[-97.1307,48.6297],[-97.131,48.6303],[-97.131,48.6304],[-97.131,48.6308],[-97.131,48.6315],[-97.1309,48.6317],[-97.1307,48.6321],[-97.1304,48.6325],[-97.1301,48.6326],[-97.1297,48.6328],[-97.1293,48.6329],[-97.129,48.633],[-97.1281,48.6332],[-97.128,48.6333],[-97.1275,48.6333],[-97.1253,48.6334],[-97.1235,48.6333],[-97.1216,48.6327],[-97.1181,48.6308],[-97.1176,48.6307],[-97.115,48.6299],[-97.1133,48.63],[-97.1115,48.6303],[-97.1107,48.6308],[-97.1104,48.6309],[-97.1095,48.6315],[-97.1084,48.6327],[-97.1082,48.6344],[-97.1086,48.6363],[-97.1096,48.6389],[-97.1109,48.6407],[-97.1119,48.6416],[-97.1144,48.6433],[-97.115,48.6438],[-97.115,48.6446],[-97.1149,48.6452],[-97.1123,48.6457],[-97.1112,48.6459],[-97.1093,48.6465],[-97.1078,48.6478],[-97.1069,48.6491],[-97.1066,48.6501],[-97.1061,48.6519],[-97.1059,48.6527],[-97.1045,48.6545],[-97.1017,48.6563],[-97.0987,48.6593],[-97.0986,48.6604],[-97.0985,48.6613],[-97.0992,48.6625],[-97.1019,48.6636],[-97.106,48.663],[-97.1062,48.663],[-97.1082,48.6634],[-97.1087,48.6645],[-97.1061,48.6654],[-97.1057,48.6655],[-97.102,48.6667],[-97.1,48.668],[-97.0998,48.6714],[-97.1002,48.675],[-97.1003,48.6757],[-97.1008,48.6787],[-97.1011,48.6808],[-97.1003,48.6828],[-97.0985,48.683],[-97.0946,48.6822],[-97.0926,48.6821],[-97.0904,48.6828],[-97.0898,48.6841],[-97.0899,48.6852],[-97.091,48.6861],[-97.093,48.687],[-97.0951,48.6876],[-97.099,48.6884],[-97.1024,48.6893],[-97.103,48.6894],[-97.1059,48.6903],[-97.1064,48.6905],[-97.1086,48.6915],[-97.111,48.6939],[-97.113,48.6964],[-97.1148,48.6981],[-97.1182,48.7005],[-97.1198,48.7018],[-97.1201,48.7039],[-97.1194,48.7041],[-97.1182,48.7046],[-97.1143,48.7052],[-97.1117,48.7056],[-97.11,48.7063],[-97.1098,48.7083],[-97.1113,48.7094],[-97.1134,48.7101],[-97.1157,48.7105],[-97.1174,48.7111],[-97.119,48.7119],[-97.1212,48.7136],[-97.1223,48.716],[-97.1229,48.7168],[-97.1231,48.7172],[-97.1243,48.7192],[-97.1253,48.7201],[-97.1253,48.7203],[-97.126,48.7207],[-97.1263,48.7212],[-97.1272,48.7215],[-97.128,48.722],[-97.1282,48.7221],[-97.1288,48.7225],[-97.1297,48.7229],[-97.131,48.7233],[-97.1321,48.7238],[-97.1331,48.7242],[-97.1345,48.7248],[-97.136,48.7257],[-97.1369,48.7263],[-97.1375,48.727],[-97.1376,48.7274],[-97.1376,48.7278],[-97.1373,48.7283],[-97.137,48.7284],[-97.1365,48.7285],[-97.136,48.7287],[-97.1352,48.7287],[-97.1341,48.7289],[-97.1333,48.7291],[-97.1328,48.7292],[-97.132,48.7294],[-97.1312,48.7295],[-97.1308,48.7296],[-97.1299,48.7299],[-97.1294,48.7304],[-97.1288,48.7308],[-97.1286,48.7312],[-97.1286,48.7315],[-97.1286,48.7316],[-97.1286,48.7318],[-97.1285,48.7322],[-97.1286,48.7326],[-97.1286,48.7328],[-97.1287,48.7331],[-97.129,48.7335],[-97.1295,48.7339],[-97.1298,48.7341],[-97.1316,48.7347],[-97.1322,48.7348],[-97.1334,48.7347],[-97.1351,48.7345],[-97.1369,48.7345],[-97.1383,48.7345],[-97.1396,48.7347],[-97.1402,48.7349],[-97.1412,48.7354],[-97.1419,48.7359],[-97.1422,48.7367],[-97.1423,48.7372],[-97.1421,48.7381],[-97.1414,48.7385],[-97.1408,48.7387],[-97.1404,48.7389],[-97.1399,48.7393],[-97.1392,48.7397],[-97.1381,48.7408],[-97.1372,48.742],[-97.1366,48.7435],[-97.1365,48.745],[-97.1365,48.7459],[-97.1366,48.7466],[-97.1369,48.748],[-97.1375,48.7492],[-97.1379,48.75],[-97.1385,48.7504],[-97.1391,48.7507],[-97.1396,48.7508],[-97.1401,48.7509],[-97.141,48.751],[-97.142,48.751],[-97.143,48.7509],[-97.1444,48.7507],[-97.1457,48.7506],[-97.1466,48.7505],[-97.1476,48.7505],[-97.1491,48.7506],[-97.1497,48.7508],[-97.1503,48.7509],[-97.1515,48.7515],[-97.1521,48.752],[-97.153,48.7529],[-97.1539,48.7542],[-97.1545,48.7553],[-97.1547,48.7558],[-97.1548,48.7562],[-97.1548,48.7569],[-97.1548,48.7576],[-97.1546,48.758],[-97.1542,48.7587],[-97.1535,48.7593],[-97.1528,48.7598],[-97.1519,48.7601],[-97.1508,48.7605],[-97.1503,48.7606],[-97.1501,48.7607],[-97.1475,48.7616],[-97.1473,48.7617],[-97.1469,48.762],[-97.1462,48.7626],[-97.1461,48.7628],[-97.1459,48.7633],[-97.1456,48.7643],[-97.1456,48.765],[-97.146,48.7658],[-97.1476,48.7673],[-97.1487,48.7681],[-97.15,48.7692],[-97.1501,48.7693],[-97.1506,48.77],[-97.1512,48.7712],[-97.1519,48.7721],[-97.1525,48.7727],[-97.1529,48.7728],[-97.1559,48.7731],[-97.1567,48.7732],[-97.1578,48.7735],[-97.1582,48.7737],[-97.1587,48.7742],[-97.1589,48.7746],[-97.159,48.7751],[-97.159,48.7751],[-97.159,48.7754],[-97.1589,48.776],[-97.1584,48.7766],[-97.1579,48.7769],[-97.1573,48.7772],[-97.1557,48.7776],[-97.1544,48.7778],[-97.1534,48.778],[-97.1522,48.7783],[-97.1509,48.7787],[-97.1501,48.7789],[-97.1497,48.779],[-97.1483,48.7797],[-97.1477,48.7801],[-97.1473,48.7807],[-97.1472,48.7811],[-97.1473,48.7816],[-97.1478,48.7821],[-97.1486,48.7824],[-97.1495,48.7826],[-97.1501,48.7826],[-97.1503,48.7826],[-97.1513,48.7825],[-97.1533,48.7824],[-97.1547,48.7824],[-97.1559,48.7825],[-97.1571,48.7827],[-97.1583,48.783],[-97.1591,48.7834],[-97.1595,48.7838],[-97.1597,48.7843],[-97.1598,48.7848],[-97.1596,48.7853],[-97.1593,48.786],[-97.1591,48.7863],[-97.1586,48.7869],[-97.1577,48.7877],[-97.1574,48.7882],[-97.1573,48.7884],[-97.1572,48.7887],[-97.1571,48.7894],[-97.157,48.7895],[-97.157,48.7901],[-97.1572,48.7906],[-97.1575,48.7909],[-97.1581,48.7912],[-97.1586,48.7913],[-97.1592,48.7915],[-97.1595,48.7915],[-97.1611,48.7915],[-97.1618,48.7914],[-97.1645,48.7911],[-97.1648,48.7911],[-97.1657,48.7911],[-97.1664,48.7912],[-97.1672,48.7913],[-97.1714,48.7921],[-97.1718,48.7923],[-97.1721,48.7924],[-97.1731,48.7929],[-97.1737,48.7933],[-97.174,48.7937],[-97.1741,48.7942],[-97.1742,48.7947],[-97.1742,48.7951],[-97.1739,48.7954],[-97.1734,48.7958],[-97.1726,48.7963],[-97.1717,48.7966],[-97.1716,48.7966],[-97.171,48.7967],[-97.1701,48.7967],[-97.1688,48.7966],[-97.1673,48.7964],[-97.1665,48.7962],[-97.1654,48.7962],[-97.1648,48.7962],[-97.1638,48.7963],[-97.1631,48.7966],[-97.1625,48.7969],[-97.162,48.7974],[-97.1617,48.7979],[-97.1617,48.7984],[-97.1619,48.7988],[-97.1621,48.7994],[-97.1626,48.8001],[-97.1633,48.8007],[-97.1642,48.8011],[-97.1652,48.8014],[-97.166,48.8015],[-97.1668,48.8016],[-97.1675,48.8016],[-97.1685,48.8016],[-97.1698,48.8013],[-97.1706,48.8011],[-97.1714,48.8008],[-97.1715,48.8008],[-97.1724,48.8004],[-97.1731,48.8],[-97.1742,48.7992],[-97.175,48.7986],[-97.1754,48.7983],[-97.1757,48.798],[-97.1761,48.7977],[-97.1768,48.7974],[-97.1773,48.7973],[-97.1779,48.7972],[-97.1787,48.7972],[-97.1795,48.7972],[-97.1801,48.7973],[-97.1807,48.7975],[-97.1811,48.7978],[-97.1815,48.7982],[-97.1816,48.7986],[-97.1817,48.7991],[-97.1815,48.7995],[-97.1813,48.8],[-97.1808,48.8004],[-97.1801,48.8008],[-97.1791,48.8012],[-97.1779,48.8015],[-97.1769,48.8017],[-97.1764,48.8018],[-97.1756,48.8021],[-97.1748,48.8023],[-97.1725,48.8032],[-97.1713,48.8036],[-97.171,48.8037],[-97.1706,48.8039],[-97.1694,48.8043],[-97.1682,48.8046],[-97.1675,48.8048],[-97.1666,48.805],[-97.1655,48.8052],[-97.1638,48.8055],[-97.161,48.8059],[-97.1605,48.8061],[-97.1597,48.8064],[-97.159,48.8067],[-97.1583,48.8072],[-97.1579,48.8077],[-97.1577,48.8082],[-97.1576,48.8089],[-97.1578,48.8098],[-97.158,48.8104],[-97.1586,48.811],[-97.159,48.8111],[-97.161,48.8117],[-97.1617,48.8119],[-97.1625,48.812],[-97.1636,48.8121],[-97.1644,48.8121],[-97.1651,48.812],[-97.1666,48.8118],[-97.168,48.8116],[-97.169,48.8114],[-97.17,48.8114],[-97.1713,48.8115],[-97.1715,48.8115],[-97.1726,48.8117],[-97.1731,48.8118],[-97.174,48.8122],[-97.1761,48.8132],[-97.1776,48.8141],[-97.1784,48.8145],[-97.1797,48.8149],[-97.1807,48.8151],[-97.1821,48.8153],[-97.1828,48.8153],[-97.184,48.8152],[-97.1848,48.8151],[-97.186,48.8147],[-97.1868,48.8145],[-97.1873,48.8143],[-97.1879,48.8143],[-97.1883,48.8143],[-97.1889,48.8143],[-97.1894,48.8144],[-97.1898,48.8146],[-97.1901,48.8148],[-97.1903,48.8153],[-97.1904,48.8156],[-97.1903,48.8159],[-97.19,48.8163],[-97.1893,48.8167],[-97.1885,48.8171],[-97.1879,48.8173],[-97.1866,48.8176],[-97.1857,48.8177],[-97.1847,48.8179],[-97.184,48.8181],[-97.1833,48.8184],[-97.1817,48.8189],[-97.1809,48.8193],[-97.1801,48.8199],[-97.1793,48.8207],[-97.1787,48.8216],[-97.178,48.8232],[-97.1777,48.824],[-97.1776,48.8245],[-97.1777,48.8249],[-97.178,48.8255],[-97.1782,48.8258],[-97.1786,48.8262],[-97.1794,48.8268],[-97.1822,48.8288],[-97.1837,48.8299],[-97.1841,48.8304],[-97.1847,48.8314],[-97.1848,48.8319],[-97.1849,48.8326],[-97.1849,48.8327],[-97.1848,48.833],[-97.1846,48.8336],[-97.1842,48.8341],[-97.1837,48.8345],[-97.183,48.8348],[-97.1822,48.835],[-97.1813,48.8351],[-97.1799,48.8352],[-97.1783,48.8353],[-97.1779,48.8354],[-97.1772,48.8356],[-97.1757,48.8362],[-97.1753,48.8364],[-97.1747,48.8369],[-97.1742,48.8373],[-97.1739,48.8378],[-97.1738,48.8384],[-97.1738,48.839],[-97.1739,48.8406],[-97.1743,48.8427],[-97.1747,48.8438],[-97.175,48.8442],[-97.1755,48.8447],[-97.1761,48.8452],[-97.1767,48.8455],[-97.1771,48.8456],[-97.1779,48.8458],[-97.1795,48.8459],[-97.1808,48.846],[-97.1817,48.8462],[-97.1823,48.8464],[-97.1827,48.8468],[-97.1829,48.847],[-97.1829,48.8471],[-97.1829,48.8473],[-97.1826,48.8476],[-97.1821,48.8479],[-97.1816,48.848],[-97.1809,48.8481],[-97.1793,48.8482],[-97.178,48.8483],[-97.1767,48.8484],[-97.1759,48.8486],[-97.1753,48.8487],[-97.1747,48.849],[-97.1742,48.8493],[-97.1737,48.8497],[-97.1733,48.8502],[-97.173,48.8506],[-97.173,48.8508],[-97.173,48.8511],[-97.173,48.8516],[-97.1732,48.8522],[-97.1737,48.8527],[-97.1746,48.8534],[-97.1771,48.855],[-97.1784,48.8561],[-97.1786,48.8563],[-97.179,48.8569],[-97.1793,48.8576],[-97.1794,48.8583],[-97.1794,48.859],[-97.1792,48.8606],[-97.179,48.8615],[-97.179,48.862],[-97.1791,48.8626],[-97.1794,48.863],[-97.1801,48.8636],[-97.1811,48.864],[-97.1818,48.8641],[-97.1827,48.8641],[-97.1839,48.864],[-97.1855,48.8637],[-97.1871,48.8633],[-97.1877,48.8631],[-97.1883,48.8631],[-97.1891,48.8631],[-97.1896,48.8633],[-97.19,48.8635],[-97.1903,48.8639],[-97.1905,48.8644],[-97.1905,48.8648],[-97.1904,48.8651],[-97.1901,48.8657],[-97.1899,48.8661],[-97.1895,48.8665],[-97.189,48.867],[-97.1884,48.8675],[-97.1851,48.8694],[-97.1813,48.8718],[-97.1788,48.8736],[-97.1785,48.8738],[-97.1782,48.8741],[-97.1781,48.8743],[-97.1779,48.8745],[-97.1778,48.8747],[-97.1777,48.8749],[-97.1777,48.875],[-97.1778,48.875],[-97.1778,48.8754],[-97.1779,48.8757],[-97.1782,48.8761],[-97.1786,48.8765],[-97.1792,48.8769],[-97.1798,48.8771],[-97.1808,48.8772],[-97.1823,48.8772],[-97.1852,48.8768],[-97.1869,48.8765],[-97.1881,48.8765],[-97.1891,48.8766],[-97.1904,48.8769],[-97.1933,48.8779],[-97.1944,48.8783],[-97.1957,48.8788],[-97.1972,48.8794],[-97.1981,48.8799],[-97.1988,48.8805],[-97.1995,48.8812],[-97.1999,48.8818],[-97.1999,48.8821],[-97.2,48.8827],[-97.1998,48.8832],[-97.1997,48.8836],[-97.199,48.8845],[-97.1978,48.8859],[-97.1975,48.8865],[-97.1974,48.8868],[-97.1973,48.8872],[-97.1973,48.8874],[-97.1974,48.8877],[-97.1975,48.8881],[-97.1983,48.8889],[-97.2002,48.8903],[-97.2004,48.8904],[-97.2009,48.8908],[-97.2014,48.8912],[-97.2017,48.8915],[-97.2017,48.8919],[-97.2016,48.8922],[-97.2013,48.8925],[-97.201,48.8926],[-97.2001,48.8926],[-97.1994,48.8926],[-97.1985,48.8925],[-97.198,48.8924],[-97.1973,48.892],[-97.1957,48.8916],[-97.1946,48.8915],[-97.1944,48.8914],[-97.1937,48.8914],[-97.1927,48.8915],[-97.1921,48.8917],[-97.1916,48.8919],[-97.1905,48.8926],[-97.1901,48.8932],[-97.1898,48.8938],[-97.1897,48.8944],[-97.1897,48.8947],[-97.1898,48.8951],[-97.1899,48.8954],[-97.1903,48.896],[-97.1911,48.8967],[-97.1919,48.8974],[-97.1925,48.8979],[-97.1935,48.8985],[-97.1941,48.8988],[-97.1945,48.8989],[-97.1966,48.8997],[-97.1992,48.9004],[-97.2009,48.9009],[-97.2022,48.9013],[-97.2048,48.9018],[-97.2055,48.902],[-97.207,48.9025],[-97.2076,48.9027],[-97.2082,48.9029],[-97.2088,48.9032],[-97.2093,48.9036],[-97.21,48.904],[-97.2105,48.9044],[-97.211,48.905],[-97.2114,48.9056],[-97.2122,48.9069],[-97.2125,48.9075],[-97.2127,48.9082],[-97.2127,48.909],[-97.2125,48.9099],[-97.212,48.911],[-97.2116,48.9121],[-97.2111,48.913],[-97.2108,48.914],[-97.2106,48.9148],[-97.2106,48.9153],[-97.2109,48.9162],[-97.2111,48.9167],[-97.2115,48.9172],[-97.2118,48.9175],[-97.2122,48.9177],[-97.2129,48.9181],[-97.2149,48.9187],[-97.2163,48.9191],[-97.2164,48.9191],[-97.2171,48.9194],[-97.2179,48.9198],[-97.2189,48.9205],[-97.2196,48.9215],[-97.2198,48.9222],[-97.2199,48.923],[-97.2197,48.9237],[-97.2191,48.9249],[-97.2183,48.9262],[-97.2172,48.9277],[-97.2163,48.9286],[-97.2159,48.9289],[-97.2149,48.9301],[-97.2146,48.9304],[-97.2145,48.9307],[-97.2144,48.931],[-97.2145,48.9314],[-97.2145,48.9316],[-97.2148,48.9319],[-97.2154,48.9325],[-97.2159,48.9327],[-97.2162,48.9328],[-97.217,48.9328],[-97.2181,48.9327],[-97.2198,48.9325],[-97.2208,48.9325],[-97.2214,48.9325],[-97.2218,48.9326],[-97.2237,48.9332],[-97.2245,48.9337],[-97.2249,48.9339],[-97.225,48.934],[-97.2252,48.9342],[-97.2254,48.9345],[-97.2257,48.9349],[-97.226,48.9353],[-97.2263,48.936],[-97.2267,48.9376],[-97.227,48.9389],[-97.2271,48.9398],[-97.2271,48.941],[-97.227,48.9418],[-97.2266,48.9432],[-97.2264,48.9441],[-97.2263,48.9445],[-97.2264,48.9452],[-97.2265,48.9456],[-97.227,48.9462],[-97.2273,48.9465],[-97.2276,48.9467],[-97.2279,48.9467],[-97.2284,48.9468],[-97.2304,48.9465],[-97.2309,48.9464],[-97.2313,48.9464],[-97.2326,48.9466],[-97.2331,48.9468],[-97.2338,48.9471],[-97.2342,48.9474],[-97.2343,48.948],[-97.2343,48.9485],[-97.2342,48.9488],[-97.2341,48.9491],[-97.2337,48.95],[-97.2332,48.951],[-97.2328,48.9524],[-97.2323,48.954],[-97.2317,48.9558],[-97.2313,48.9568],[-97.2309,48.9578],[-97.2305,48.9585],[-97.23,48.9591],[-97.2288,48.9603],[-97.2282,48.9609],[-97.2278,48.9613],[-97.2276,48.9619],[-97.2276,48.9624],[-97.2279,48.963],[-97.228,48.9631],[-97.2283,48.9634],[-97.2289,48.9639],[-97.2294,48.9641],[-97.23,48.9642],[-97.2323,48.9646],[-97.2355,48.965],[-97.2368,48.9652],[-97.2375,48.9654],[-97.2382,48.966],[-97.2383,48.9661],[-97.2388,48.9666],[-97.2391,48.9676],[-97.2392,48.9687],[-97.239,48.9696],[-97.2387,48.9706],[-97.2383,48.9715],[-97.2381,48.9723],[-97.238,48.9725],[-97.2379,48.9731],[-97.2378,48.9734],[-97.2378,48.9738],[-97.238,48.9752],[-97.238,48.9763],[-97.2381,48.9771],[-97.238,48.9771],[-97.238,48.9841],[-97.2377,48.9849],[-97.2372,48.9857],[-97.2365,48.9867],[-97.2359,48.9874],[-97.2351,48.9881],[-97.2342,48.989],[-97.2335,48.9895],[-97.2331,48.9898],[-97.2317,48.9904],[-97.2301,48.9911],[-97.2293,48.9914],[-97.229,48.9916],[-97.2279,48.9921],[-97.2274,48.9925],[-97.227,48.9929],[-97.2266,48.9933],[-97.2265,48.9938],[-97.2267,48.9941],[-97.227,48.9945],[-97.2273,48.9947],[-97.2287,48.9949],[-97.2304,48.995],[-97.2317,48.9951],[-97.2324,48.9952],[-97.2335,48.9956],[-97.2338,48.9959],[-97.2341,48.9966],[-97.2341,48.997],[-97.234,48.9975],[-97.2337,48.9981],[-97.2332,48.9985],[-97.2323,48.999],[-97.2305,49.0],[-97.2303,49.0001],[-97.2295,49.0005],[-97.2175,49.0005],[-97.2161,49.0005],[-97.2078,49.0005],[-97.2069,49.0005],[-97.1955,49.0005],[-97.1939,49.0005],[-97.1739,49.0005],[-97.1724,49.0005],[-97.1514,49.0005],[-97.1502,49.0005],[-97.1294,49.0004],[-97.1277,49.0004],[-97.1073,49.0004],[-97.1061,49.0004],[-97.0853,49.0004],[-97.084,49.0004],[-97.0633,49.0004],[-97.062,49.0004],[-97.0412,49.0004],[-97.0401,49.0004],[-97.0192,49.0004],[-97.0183,49.0004],[-96.9971,49.0004],[-96.9961,49.0004],[-96.9751,49.0003],[-96.9738,49.0003],[-96.953,49.0003],[-96.9518,49.0003],[-96.931,49.0003],[-96.9299,49.0003],[-96.909,49.0003],[-96.9078,49.0003],[-96.8869,49.0003],[-96.8856,49.0003],[-96.8649,49.0003],[-96.864,49.0003],[-96.8429,49.0003],[-96.8415,49.0003],[-96.8208,49.0003],[-96.8197,49.0003],[-96.8023,49.0002],[-96.8005,49.0002],[-96.8003,49.0002],[-96.7988,49.0002],[-96.7787,49.0002],[-96.7768,49.0002],[-96.7567,49.0002],[-96.7547,49.0002],[-96.7348,49.0002],[-96.7327,49.0002],[-96.7127,49.0002],[-96.7107,49.0002],[-96.6905,49.0002],[-96.6886,49.0002],[-96.6695,49.0002],[-96.6665,49.0002],[-96.6482,49.0002],[-96.6445,49.0002],[-96.6243,49.0002],[-96.6225,49.0002],[-96.6021,49.0002],[-96.6004,49.0002],[-96.58,49.0002],[-96.5784,49.0002],[-96.558,49.0002],[-96.5563,49.0002],[-96.536,49.0002],[-96.5342,49.0002],[-96.5154,49.0002],[-96.5123,49.0002],[-96.4933,49.0002],[-96.49,49.0002],[-96.471,49.0001],[-96.4664,49.0001],[-96.4496,49.0001],[-96.4492,49.0001],[-96.4491,49.0001],[-96.446,49.0001],[-96.4273,49.0001],[-96.4224,49.0001],[-96.4054,49.0001]]],"type":"Polygon"},"id":"35","properties":{"Area":2862183702.23055,"CTYONLY_":3,"Code":"KITT","LASTMOD":"1999-12-31T23:59:59Z","Name":"Kittson","Perimiter":263017.48277},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&filter=%7B%22op%22%3A%22%3C%3D%22%2C%22args%22%3A%5B%7B%22property%22%3A%22CTYONLY_%22%7D%2C3%5D%7D&filter-lang=cql2-json","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&filter=%7B%22op%22%3A%22%3C%3D%22%2C%22args%22%3A%5B%7B%22property%22%3A%22CTYONLY_%22%7D%2C3%5D%7D&filter-lang=cql2-json","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":2,"numberReturned":2,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_json_like.json.txt b/msautotest/api/expected/ogcapi_cql2_json_like.json.txt new file mode 100644 index 0000000000..aee718706c --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_json_like.json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 1 +OGC-NumberReturned: 1 + +{"features":[{"geometry":{"coordinates":[[[-93.5242,44.5436],[-93.5225,44.5436],[-93.504,44.5438],[-93.5018,44.5438],[-93.4835,44.5438],[-93.4817,44.5438],[-93.4734,44.5438],[-93.4632,44.5438],[-93.4609,44.5438],[-93.4429,44.5438],[-93.4408,44.5438],[-93.4326,44.5438],[-93.4226,44.5439],[-93.4206,44.5439],[-93.4024,44.5439],[-93.4003,44.5439],[-93.383,44.544],[-93.38,44.544],[-93.3627,44.5441],[-93.3596,44.5441],[-93.3556,44.5441],[-93.3424,44.5442],[-93.3395,44.5442],[-93.3221,44.544],[-93.3191,44.544],[-93.3128,44.544],[-93.3019,44.544],[-93.2988,44.544],[-93.2813,44.544],[-93.2814,44.5298],[-93.2815,44.5153],[-93.2815,44.501],[-93.2815,44.4865],[-93.2817,44.472],[-93.2618,44.4718],[-93.2415,44.4716],[-93.2213,44.4714],[-93.2008,44.4714],[-93.1808,44.4713],[-93.1605,44.4713],[-93.1408,44.4712],[-93.1206,44.4713],[-93.1002,44.4718],[-93.0799,44.4719],[-93.0597,44.4718],[-93.0393,44.4719],[-93.0394,44.4576],[-93.0396,44.4432],[-93.0397,44.4287],[-93.0399,44.4143],[-93.04,44.3999],[-93.0401,44.3855],[-93.0402,44.371],[-93.0403,44.3565],[-93.0403,44.3419],[-93.0405,44.3273],[-93.0405,44.3129],[-93.0405,44.2983],[-93.0406,44.2838],[-93.0407,44.2693],[-93.0409,44.2548],[-93.041,44.2402],[-93.0411,44.2257],[-93.0411,44.2113],[-93.0411,44.1968],[-93.0427,44.1968],[-93.0459,44.1968],[-93.0613,44.1967],[-93.0661,44.1967],[-93.0815,44.1967],[-93.0862,44.1967],[-93.1003,44.1967],[-93.1015,44.1967],[-93.1063,44.1967],[-93.1092,44.1967],[-93.1218,44.1967],[-93.1267,44.1967],[-93.1301,44.1967],[-93.1418,44.1967],[-93.1467,44.1967],[-93.1561,44.1966],[-93.1622,44.1966],[-93.1661,44.1966],[-93.1703,44.1966],[-93.1822,44.1966],[-93.1856,44.1966],[-93.1865,44.1966],[-93.2023,44.1966],[-93.2037,44.1966],[-93.2064,44.1966],[-93.2225,44.1966],[-93.2265,44.1966],[-93.2292,44.1966],[-93.2426,44.1966],[-93.2465,44.1966],[-93.255,44.1966],[-93.2629,44.1966],[-93.2664,44.1966],[-93.2767,44.1966],[-93.283,44.1966],[-93.2865,44.1965],[-93.2905,44.1965],[-93.3032,44.1965],[-93.3063,44.1965],[-93.3235,44.1965],[-93.3264,44.1965],[-93.3277,44.1965],[-93.3436,44.1965],[-93.3466,44.1965],[-93.3639,44.1965],[-93.3666,44.1965],[-93.3842,44.1965],[-93.3866,44.1965],[-93.4042,44.1965],[-93.4065,44.1965],[-93.4244,44.1964],[-93.4267,44.1964],[-93.4447,44.1964],[-93.4469,44.1964],[-93.4648,44.1963],[-93.467,44.1963],[-93.4852,44.1964],[-93.4872,44.1964],[-93.5053,44.1963],[-93.507,44.1963],[-93.5255,44.1962],[-93.5253,44.2107],[-93.5251,44.2251],[-93.5251,44.2388],[-93.5251,44.2533],[-93.5252,44.2685],[-93.5252,44.2829],[-93.5252,44.2975],[-93.5252,44.312],[-93.5249,44.3266],[-93.5249,44.3411],[-93.5245,44.3557],[-93.5245,44.3704],[-93.5246,44.3848],[-93.5245,44.3994],[-93.5245,44.4138],[-93.5245,44.4283],[-93.5245,44.4427],[-93.5245,44.4572],[-93.5244,44.4717],[-93.5245,44.4862],[-93.5244,44.5007],[-93.5243,44.5152],[-93.5244,44.5297],[-93.5242,44.5436]]],"type":"Polygon"},"id":"66","properties":{"Area":1335114621.00336,"CTYONLY_":66,"Code":"RICE","LASTMOD":"2010-10-17T00:00:00Z","Name":"Rice","Perimiter":154431.78788},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&filter=%7B%22op%22%3A%22like%22%2C%22args%22%3A%5B%7B%22property%22%3A%22Name%22%7D%2C%22R_ce%22%5D%7D&filter-lang=cql2-json","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&filter=%7B%22op%22%3A%22like%22%2C%22args%22%3A%5B%7B%22property%22%3A%22Name%22%7D%2C%22R_ce%22%5D%7D&filter-lang=cql2-json","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":1,"numberReturned":1,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_json_lt.json.txt b/msautotest/api/expected/ogcapi_cql2_json_lt.json.txt new file mode 100644 index 0000000000..b4a9b47a63 --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_json_lt.json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 1 +OGC-NumberReturned: 1 + +{"features":[{"geometry":{"coordinates":[[[-95.3231,48.999],[-95.3109,48.999],[-95.2889,48.9989],[-95.2852,48.9989],[-95.2669,48.9989],[-95.245,48.9989],[-95.2232,48.9989],[-95.2014,48.9989],[-95.1792,48.9989],[-95.1574,48.9989],[-95.1531,48.9989],[-95.1531,49.0031],[-95.1532,49.0179],[-95.1532,49.0325],[-95.1532,49.047],[-95.1532,49.0619],[-95.1532,49.0765],[-95.1532,49.0911],[-95.1532,49.1057],[-95.1532,49.1205],[-95.1532,49.1354],[-95.1532,49.1499],[-95.1532,49.1642],[-95.1532,49.1788],[-95.1532,49.1807],[-95.1532,49.1931],[-95.1532,49.1966],[-95.1532,49.2077],[-95.1533,49.2131],[-95.1533,49.2219],[-95.1533,49.2308],[-95.1533,49.2365],[-95.1533,49.2472],[-95.1533,49.2512],[-95.1533,49.2655],[-95.1533,49.2697],[-95.1533,49.2802],[-95.1533,49.2882],[-95.1533,49.2945],[-95.1533,49.3072],[-95.1533,49.309],[-95.1533,49.3234],[-95.1533,49.3237],[-95.1533,49.3381],[-95.1533,49.3476],[-95.1533,49.3525],[-95.1533,49.3636],[-95.1533,49.367],[-95.1533,49.3705],[-95.1533,49.3776],[-95.1533,49.3813],[-95.1533,49.3845],[-95.1503,49.383],[-95.1499,49.3813],[-95.1498,49.3807],[-95.1467,49.3802],[-95.145,49.3784],[-95.1418,49.3784],[-95.1397,49.3762],[-95.1367,49.3751],[-95.1324,49.3736],[-95.1287,49.3705],[-95.1171,49.367],[-95.1159,49.3666],[-95.1145,49.3666],[-95.1098,49.3664],[-95.1031,49.3652],[-95.1031,49.3636],[-95.0926,49.3617],[-95.0897,49.3612],[-95.0707,49.3564],[-95.0582,49.3533],[-95.0495,49.3532],[-95.0479,49.3533],[-95.0262,49.3554],[-95.0141,49.3565],[-95.0047,49.3612],[-94.993,49.367],[-94.9889,49.369],[-94.9818,49.3684],[-94.9742,49.3678],[-94.9597,49.3699],[-94.9573,49.3702],[-94.952,49.3688],[-94.948,49.367],[-94.9376,49.3625],[-94.9152,49.3529],[-94.9143,49.3524],[-94.909,49.3502],[-94.9065,49.3484],[-94.8933,49.3414],[-94.8865,49.3378],[-94.8782,49.3334],[-94.8712,49.3308],[-94.854,49.3244],[-94.8492,49.3244],[-94.8363,49.3243],[-94.8311,49.3236],[-94.8271,49.323],[-94.8162,49.3214],[-94.8243,49.309],[-94.8243,49.3088],[-94.8255,49.2944],[-94.8255,49.2943],[-94.8204,49.28],[-94.8152,49.2653],[-94.8103,49.2515],[-94.8059,49.2388],[-94.8051,49.2367],[-94.8001,49.2224],[-94.7973,49.2144],[-94.7975,49.2079],[-94.7979,49.1979],[-94.7965,49.1936],[-94.7918,49.1792],[-94.7871,49.1646],[-94.7833,49.153],[-94.7823,49.15],[-94.7776,49.1357],[-94.7727,49.1206],[-94.7727,49.1206],[-94.7611,49.1096],[-94.7571,49.1058],[-94.7496,49.0988],[-94.7474,49.0918],[-94.7429,49.0773],[-94.7394,49.0657],[-94.7385,49.063],[-94.7344,49.0497],[-94.7299,49.0351],[-94.7254,49.0205],[-94.7207,49.0052],[-94.7184,48.9979],[-94.7162,48.9907],[-94.7117,48.9761],[-94.7072,48.9615],[-94.7027,48.9468],[-94.6982,48.9322],[-94.6968,48.9276],[-94.6844,48.8875],[-94.6834,48.8842],[-94.6842,48.8724],[-94.6855,48.8719],[-94.6923,48.8691],[-94.6902,48.8636],[-94.6914,48.8591],[-94.693,48.8535],[-94.6881,48.8447],[-94.6855,48.8401],[-94.6963,48.836],[-94.6975,48.8355],[-94.702,48.8319],[-94.7025,48.8302],[-94.7042,48.8243],[-94.6991,48.8159],[-94.6962,48.8111],[-94.6951,48.8092],[-94.6958,48.8012],[-94.6959,48.7997],[-94.6944,48.7895],[-94.6934,48.7864],[-94.6909,48.7781],[-94.687,48.7752],[-94.6776,48.772],[-94.6768,48.7717],[-94.6746,48.7705],[-94.6671,48.7662],[-94.6603,48.7605],[-94.6557,48.7581],[-94.6525,48.7565],[-94.652,48.7562],[-94.6453,48.7491],[-94.6453,48.7441],[-94.6443,48.7434],[-94.6414,48.7413],[-94.631,48.7392],[-94.6301,48.739],[-94.6191,48.7373],[-94.6106,48.7318],[-94.6084,48.731],[-94.6028,48.7289],[-94.6011,48.7283],[-94.5962,48.7248],[-94.5913,48.7197],[-94.5876,48.7176],[-94.5867,48.7175],[-94.5685,48.7156],[-94.5622,48.7159],[-94.5558,48.7163],[-94.549,48.7148],[-94.5487,48.7146],[-94.5457,48.7124],[-94.5396,48.7036],[-94.539,48.7028],[-94.5329,48.7013],[-94.5247,48.7016],[-94.5178,48.7008],[-94.5173,48.7008],[-94.5093,48.7006],[-94.5066,48.6999],[-94.4996,48.698],[-94.4958,48.698],[-94.4863,48.698],[-94.4739,48.6969],[-94.4706,48.6966],[-94.4631,48.6953],[-94.4568,48.6933],[-94.4523,48.6925],[-94.4517,48.6925],[-94.4465,48.693],[-94.4388,48.6949],[-94.4319,48.6998],[-94.4299,48.7012],[-94.4299,48.6998],[-94.43,48.6852],[-94.4301,48.6708],[-94.43,48.6564],[-94.4297,48.642],[-94.4294,48.6276],[-94.4292,48.6133],[-94.4289,48.5988],[-94.4289,48.5844],[-94.4291,48.5698],[-94.4295,48.5554],[-94.43,48.5409],[-94.4303,48.5264],[-94.4303,48.512],[-94.4299,48.4977],[-94.4296,48.4832],[-94.4296,48.4688],[-94.4293,48.4543],[-94.4292,48.4399],[-94.4293,48.4254],[-94.4294,48.411],[-94.4293,48.3964],[-94.4289,48.3821],[-94.4288,48.3675],[-94.4471,48.3675],[-94.4505,48.3675],[-94.4688,48.3675],[-94.4722,48.3674],[-94.4906,48.3674],[-94.4924,48.3674],[-94.4941,48.3674],[-94.5118,48.3675],[-94.5157,48.3674],[-94.5335,48.3674],[-94.5378,48.3674],[-94.5536,48.3674],[-94.5593,48.3674],[-94.5754,48.3674],[-94.5812,48.3674],[-94.5971,48.3675],[-94.6029,48.3674],[-94.6188,48.3673],[-94.6245,48.3673],[-94.6405,48.3673],[-94.6465,48.3673],[-94.6505,48.3673],[-94.6622,48.3673],[-94.6679,48.3673],[-94.6694,48.3672],[-94.683,48.3671],[-94.6898,48.3671],[-94.7099,48.3669],[-94.7117,48.3668],[-94.7315,48.3669],[-94.7329,48.3669],[-94.7533,48.3669],[-94.7549,48.3669],[-94.7748,48.3669],[-94.7765,48.3669],[-94.7967,48.3669],[-94.7983,48.3669],[-94.8183,48.3669],[-94.8199,48.3669],[-94.8399,48.3669],[-94.8416,48.3669],[-94.8616,48.3667],[-94.8632,48.3667],[-94.8833,48.3667],[-94.8849,48.3666],[-94.9049,48.3666],[-94.9065,48.3666],[-94.9264,48.3667],[-94.9283,48.3667],[-94.9469,48.3666],[-94.95,48.3666],[-94.9684,48.3667],[-94.9716,48.3667],[-94.9901,48.3667],[-94.9932,48.3667],[-95.0119,48.3665],[-95.0153,48.3665],[-95.0337,48.3665],[-95.0369,48.3665],[-95.0555,48.3665],[-95.0586,48.3665],[-95.0773,48.3664],[-95.0801,48.3664],[-95.099,48.3663],[-95.1008,48.3663],[-95.1018,48.3663],[-95.1207,48.3663],[-95.1236,48.3663],[-95.1315,48.3662],[-95.1424,48.3662],[-95.1454,48.3662],[-95.164,48.3661],[-95.1669,48.3661],[-95.1861,48.3661],[-95.1887,48.3661],[-95.1983,48.3661],[-95.2066,48.3661],[-95.2106,48.3661],[-95.211,48.3797],[-95.211,48.3808],[-95.2111,48.3941],[-95.2111,48.3952],[-95.2112,48.4087],[-95.2112,48.4096],[-95.2113,48.4232],[-95.2113,48.4242],[-95.2113,48.4255],[-95.2113,48.4376],[-95.2113,48.4387],[-95.2113,48.4522],[-95.2112,48.4529],[-95.211,48.4666],[-95.211,48.4673],[-95.2111,48.4816],[-95.2112,48.4962],[-95.2111,48.5101],[-95.2111,48.5109],[-95.2115,48.5244],[-95.2115,48.5252],[-95.2119,48.54],[-95.2324,48.5399],[-95.2339,48.5399],[-95.2537,48.5398],[-95.2554,48.5398],[-95.2756,48.54],[-95.2773,48.54],[-95.2975,48.5401],[-95.2992,48.5402],[-95.3194,48.54],[-95.321,48.54],[-95.3412,48.5402],[-95.3425,48.5402],[-95.3424,48.5548],[-95.3423,48.5691],[-95.3423,48.5836],[-95.3426,48.5979],[-95.3424,48.6127],[-95.3426,48.6271],[-95.3425,48.6415],[-95.3424,48.6561],[-95.3423,48.6705],[-95.3424,48.6849],[-95.3425,48.6995],[-95.3425,48.7131],[-95.3302,48.713],[-95.3205,48.713],[-95.3084,48.713],[-95.3051,48.713],[-95.299,48.713],[-95.2866,48.713],[-95.2767,48.713],[-95.2656,48.713],[-95.2645,48.713],[-95.255,48.713],[-95.2427,48.713],[-95.2331,48.713],[-95.2206,48.713],[-95.2112,48.713],[-95.1991,48.713],[-95.1917,48.713],[-95.1773,48.713],[-95.1697,48.7129],[-95.1554,48.7129],[-95.1477,48.7129],[-95.1333,48.713],[-95.1297,48.713],[-95.1259,48.7129],[-95.1119,48.7129],[-95.1104,48.7129],[-95.1046,48.7129],[-95.0898,48.713],[-95.0899,48.7277],[-95.0901,48.7421],[-95.0901,48.7566],[-95.0903,48.7711],[-95.0903,48.7855],[-95.0903,48.8],[-95.0909,48.8147],[-95.0908,48.8291],[-95.0907,48.8436],[-95.0908,48.858],[-95.0908,48.8724],[-95.0911,48.8869],[-95.0912,48.9014],[-95.0914,48.916],[-95.0914,48.9208],[-95.0919,48.9207],[-95.0927,48.9204],[-95.0944,48.9193],[-95.0946,48.9191],[-95.0961,48.9181],[-95.097,48.9176],[-95.0971,48.9172],[-95.0975,48.9164],[-95.098,48.916],[-95.0981,48.9159],[-95.1008,48.9142],[-95.102,48.9132],[-95.1032,48.9127],[-95.1042,48.9121],[-95.1056,48.9113],[-95.108,48.9099],[-95.1096,48.9089],[-95.1107,48.9082],[-95.1126,48.9073],[-95.113,48.9072],[-95.1132,48.9071],[-95.1137,48.9069],[-95.1141,48.9064],[-95.114,48.9061],[-95.1144,48.9052],[-95.1151,48.9046],[-95.1163,48.9037],[-95.1182,48.9029],[-95.1204,48.9019],[-95.1205,48.9017],[-95.121,48.9016],[-95.1214,48.9013],[-95.1228,48.9006],[-95.1233,48.9004],[-95.1239,48.9001],[-95.1252,48.8998],[-95.1312,48.8975],[-95.1322,48.8973],[-95.1337,48.8969],[-95.1343,48.8963],[-95.1348,48.8963],[-95.1351,48.8963],[-95.1355,48.8959],[-95.1381,48.8949],[-95.1404,48.8943],[-95.1436,48.8937],[-95.1438,48.8934],[-95.1459,48.8929],[-95.1469,48.8927],[-95.1483,48.8923],[-95.1508,48.8922],[-95.1528,48.8921],[-95.1555,48.892],[-95.1564,48.8919],[-95.1579,48.8919],[-95.1602,48.892],[-95.1618,48.892],[-95.1641,48.8917],[-95.1648,48.8913],[-95.1674,48.8907],[-95.1701,48.8902],[-95.173,48.8897],[-95.1764,48.8893],[-95.1791,48.889],[-95.1797,48.889],[-95.1819,48.8888],[-95.1851,48.8882],[-95.1863,48.8877],[-95.1877,48.8874],[-95.1889,48.8873],[-95.1901,48.887],[-95.1913,48.8868],[-95.1919,48.8866],[-95.1924,48.8865],[-95.1956,48.8862],[-95.1986,48.8855],[-95.2005,48.8856],[-95.2009,48.8855],[-95.2024,48.8852],[-95.2059,48.8848],[-95.2085,48.8846],[-95.2112,48.8848],[-95.2115,48.8847],[-95.2117,48.8847],[-95.2122,48.8842],[-95.2144,48.8843],[-95.2151,48.884],[-95.2159,48.8839],[-95.217,48.8835],[-95.2188,48.8835],[-95.2193,48.8832],[-95.22,48.8831],[-95.2207,48.8831],[-95.2208,48.8831],[-95.2212,48.883],[-95.2252,48.8819],[-95.2265,48.8816],[-95.2287,48.8815],[-95.231,48.8814],[-95.2335,48.8814],[-95.2356,48.8815],[-95.2381,48.8817],[-95.2391,48.8819],[-95.2407,48.8821],[-95.2423,48.8821],[-95.2429,48.8822],[-95.2429,48.8822],[-95.2439,48.8823],[-95.2458,48.8829],[-95.2472,48.8835],[-95.248,48.8836],[-95.2485,48.8832],[-95.2496,48.8834],[-95.2502,48.8835],[-95.2507,48.8836],[-95.2517,48.8839],[-95.2548,48.8845],[-95.256,48.885],[-95.257,48.8858],[-95.2585,48.8867],[-95.2585,48.8867],[-95.2627,48.8877],[-95.2635,48.888],[-95.2639,48.8883],[-95.2646,48.8885],[-95.265,48.8886],[-95.2654,48.8888],[-95.2666,48.8894],[-95.2674,48.89],[-95.2677,48.8903],[-95.268,48.8905],[-95.2713,48.8915],[-95.2724,48.8921],[-95.2745,48.8931],[-95.2751,48.8938],[-95.2753,48.8943],[-95.2748,48.8951],[-95.2749,48.8956],[-95.2755,48.8959],[-95.2759,48.8962],[-95.2763,48.8963],[-95.2765,48.8962],[-95.277,48.8958],[-95.2773,48.8957],[-95.2782,48.8956],[-95.279,48.8957],[-95.2796,48.8962],[-95.2803,48.8965],[-95.2813,48.8967],[-95.2839,48.8975],[-95.2853,48.8977],[-95.2861,48.8976],[-95.2865,48.8975],[-95.287,48.8976],[-95.2872,48.8977],[-95.2879,48.8979],[-95.2882,48.8981],[-95.289,48.8994],[-95.2896,48.9],[-95.2901,48.9003],[-95.2911,48.9006],[-95.2911,48.9008],[-95.2906,48.9011],[-95.2907,48.9014],[-95.2908,48.9016],[-95.2909,48.9017],[-95.2914,48.9019],[-95.2927,48.9019],[-95.2935,48.902],[-95.2937,48.9023],[-95.2941,48.9027],[-95.2949,48.9028],[-95.2967,48.9027],[-95.2976,48.9026],[-95.298,48.9027],[-95.2983,48.9028],[-95.2993,48.9035],[-95.3005,48.904],[-95.3002,48.9045],[-95.3001,48.9046],[-95.3001,48.9047],[-95.3,48.9047],[-95.3,48.9047],[-95.2999,48.9048],[-95.2999,48.9048],[-95.2999,48.9048],[-95.2997,48.905],[-95.2996,48.9051],[-95.2994,48.9053],[-95.2992,48.9055],[-95.2991,48.9057],[-95.2989,48.906],[-95.2988,48.906],[-95.2986,48.9063],[-95.2985,48.9064],[-95.2985,48.9065],[-95.2983,48.9068],[-95.2982,48.9068],[-95.2981,48.907],[-95.298,48.9071],[-95.298,48.9071],[-95.298,48.9071],[-95.2979,48.9071],[-95.2979,48.9072],[-95.2979,48.9072],[-95.2978,48.9072],[-95.2978,48.9072],[-95.2978,48.9073],[-95.2977,48.9073],[-95.2976,48.9074],[-95.2973,48.9077],[-95.2973,48.908],[-95.2973,48.9081],[-95.2978,48.9083],[-95.2999,48.9086],[-95.3017,48.9093],[-95.3027,48.91],[-95.3038,48.9114],[-95.3043,48.9119],[-95.3059,48.9127],[-95.3061,48.9128],[-95.3064,48.9129],[-95.3074,48.9135],[-95.3078,48.9141],[-95.3085,48.9146],[-95.3092,48.9149],[-95.3093,48.9149],[-95.3102,48.9155],[-95.3109,48.9163],[-95.3115,48.9172],[-95.3119,48.9178],[-95.3126,48.919],[-95.3132,48.9198],[-95.3141,48.921],[-95.315,48.9222],[-95.3168,48.9245],[-95.3195,48.9285],[-95.3208,48.9305],[-95.3209,48.9307],[-95.3222,48.9327],[-95.3228,48.9344],[-95.3223,48.9355],[-95.3225,48.9358],[-95.3229,48.9373],[-95.3231,48.9389],[-95.3228,48.9403],[-95.3225,48.9409],[-95.3219,48.9412],[-95.3189,48.9419],[-95.3181,48.9421],[-95.3168,48.9431],[-95.3154,48.9448],[-95.3148,48.9452],[-95.3141,48.9457],[-95.3131,48.946],[-95.3114,48.9461],[-95.3102,48.9463],[-95.3095,48.9463],[-95.3088,48.9464],[-95.3086,48.9465],[-95.3086,48.9469],[-95.3085,48.947],[-95.3078,48.9466],[-95.3074,48.9465],[-95.3071,48.9466],[-95.3071,48.9469],[-95.3079,48.9474],[-95.3092,48.9477],[-95.3096,48.9478],[-95.3103,48.948],[-95.3104,48.9484],[-95.3103,48.9485],[-95.31,48.9485],[-95.3099,48.9484],[-95.3096,48.9482],[-95.3094,48.9481],[-95.3081,48.948],[-95.3071,48.9477],[-95.3062,48.9472],[-95.3062,48.9472],[-95.3061,48.9469],[-95.3062,48.9463],[-95.3063,48.9462],[-95.3069,48.9456],[-95.3069,48.9455],[-95.3068,48.9454],[-95.3061,48.9454],[-95.3053,48.9459],[-95.305,48.9462],[-95.3046,48.947],[-95.3046,48.9482],[-95.3052,48.9495],[-95.3061,48.9502],[-95.3079,48.9509],[-95.3089,48.9511],[-95.3097,48.951],[-95.3104,48.951],[-95.3108,48.9512],[-95.3115,48.952],[-95.312,48.9524],[-95.3126,48.9524],[-95.3129,48.9523],[-95.3129,48.9521],[-95.3119,48.9507],[-95.3119,48.9502],[-95.3123,48.9502],[-95.3125,48.9503],[-95.3131,48.9503],[-95.3141,48.9508],[-95.3151,48.951],[-95.3154,48.9513],[-95.3177,48.9525],[-95.3181,48.9531],[-95.3182,48.9535],[-95.3177,48.9545],[-95.3175,48.9552],[-95.3179,48.9559],[-95.3188,48.9562],[-95.3191,48.9569],[-95.3202,48.9581],[-95.3206,48.959],[-95.3206,48.9595],[-95.3206,48.9598],[-95.3202,48.9606],[-95.3193,48.9622],[-95.3193,48.964],[-95.3198,48.9643],[-95.3201,48.9648],[-95.3207,48.9669],[-95.3212,48.9672],[-95.3227,48.9685],[-95.3232,48.9692],[-95.3241,48.9703],[-95.3247,48.972],[-95.3248,48.9728],[-95.3249,48.9738],[-95.325,48.9743],[-95.3253,48.976],[-95.3257,48.9784],[-95.3255,48.9789],[-95.3256,48.98],[-95.3257,48.9814],[-95.3253,48.9832],[-95.3245,48.985],[-95.3242,48.9859],[-95.3227,48.9884],[-95.3224,48.9889],[-95.3206,48.9921],[-95.3204,48.9924],[-95.3191,48.9941],[-95.3181,48.995],[-95.3178,48.9958],[-95.3178,48.9961],[-95.3179,48.9961],[-95.3182,48.996],[-95.3187,48.9956],[-95.3191,48.9953],[-95.3197,48.9954],[-95.3201,48.9956],[-95.3206,48.9961],[-95.3204,48.9964],[-95.3202,48.9973],[-95.3204,48.9976],[-95.3224,48.9984],[-95.3231,48.999]]],"type":"Polygon"},"id":"39","properties":{"Area":4608320923.49768,"CTYONLY_":2,"Code":"LOTW","LASTMOD":"1976-07-04T12:00:00Z","Name":"Lake of the Woods","Perimiter":388250.14572},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&filter=%7B%22op%22%3A%22%3C%22%2C%22args%22%3A%5B%7B%22property%22%3A%22CTYONLY_%22%7D%2C3%5D%7D&filter-lang=cql2-json","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&filter=%7B%22op%22%3A%22%3C%22%2C%22args%22%3A%5B%7B%22property%22%3A%22CTYONLY_%22%7D%2C3%5D%7D&filter-lang=cql2-json","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":1,"numberReturned":1,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_json_mod.json.txt b/msautotest/api/expected/ogcapi_cql2_json_mod.json.txt new file mode 100644 index 0000000000..e953cf8599 --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_json_mod.json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 1 +OGC-NumberReturned: 1 + +{"features":[{"geometry":{"coordinates":[[[-96.4054,49.0001],[-96.4019,49.0001],[-96.3825,49.0001],[-96.3783,49.0001],[-96.3606,49.0001],[-96.3579,49.0001],[-96.3385,49.0001],[-96.3343,49.0001],[-96.3166,49.0001],[-96.3138,49.0001],[-96.2945,49.0001],[-96.2902,49.0001],[-96.2725,49.0001],[-96.2698,49.0001],[-96.2494,49.0001],[-96.2461,49.0001],[-96.2274,49.0001],[-96.2257,49.0001],[-96.2057,49.0001],[-96.2021,49.0001],[-96.1837,49.0],[-96.18,49.0],[-96.1617,49.0],[-96.1579,49.0],[-96.1401,49.0],[-96.1359,49.0],[-96.1176,49.0],[-96.1139,49.0],[-96.0957,49.0],[-96.0919,49.0],[-96.0738,49.0],[-96.07,49.0],[-96.0517,49.0],[-96.048,49.0],[-96.0298,49.0],[-96.026,49.0],[-96.0083,49.0],[-96.0045,49.0],[-95.9868,49.0],[-95.9784,49.0],[-95.9776,49.0],[-95.9755,49.0],[-95.9648,48.9999],[-95.9464,48.9999],[-95.943,48.9999],[-95.9225,48.9999],[-95.9211,48.9999],[-95.899,48.9998],[-95.883,48.9998],[-95.8771,48.9998],[-95.8564,48.9998],[-95.855,48.9998],[-95.8342,48.9998],[-95.8184,48.9997],[-95.8126,48.9997],[-95.7906,48.9997],[-95.7833,48.9997],[-95.7684,48.9997],[-95.7479,48.9996],[-95.7466,48.9996],[-95.7253,48.9996],[-95.7066,48.9996],[-95.7032,48.9996],[-95.681,48.9995],[-95.6654,48.9995],[-95.6596,48.9995],[-95.659,48.9995],[-95.6401,48.9995],[-95.6369,48.9995],[-95.6205,48.9994],[-95.615,48.9994],[-95.5948,48.9994],[-95.585,48.9994],[-95.573,48.9994],[-95.551,48.9993],[-95.5495,48.9993],[-95.5294,48.9993],[-95.5164,48.9993],[-95.5072,48.9993],[-95.4849,48.9992],[-95.4834,48.9992],[-95.4635,48.9992],[-95.4508,48.9992],[-95.4418,48.9992],[-95.4245,48.9991],[-95.4197,48.9991],[-95.3977,48.9991],[-95.3953,48.9991],[-95.3765,48.9991],[-95.3759,48.9991],[-95.3753,48.9991],[-95.3542,48.999],[-95.3513,48.999],[-95.3326,48.999],[-95.3286,48.999],[-95.3231,48.999],[-95.3224,48.9984],[-95.3204,48.9976],[-95.3202,48.9973],[-95.3204,48.9964],[-95.3206,48.9961],[-95.3201,48.9956],[-95.3197,48.9954],[-95.3191,48.9953],[-95.3187,48.9956],[-95.3182,48.996],[-95.3179,48.9961],[-95.3178,48.9961],[-95.3178,48.9958],[-95.3181,48.995],[-95.3191,48.9941],[-95.3204,48.9924],[-95.3206,48.9921],[-95.3224,48.9889],[-95.3227,48.9884],[-95.3242,48.9859],[-95.3245,48.985],[-95.3253,48.9832],[-95.3257,48.9814],[-95.3256,48.98],[-95.3255,48.9789],[-95.3257,48.9784],[-95.3253,48.976],[-95.325,48.9743],[-95.3249,48.9738],[-95.3248,48.9728],[-95.3247,48.972],[-95.3241,48.9703],[-95.3232,48.9692],[-95.3227,48.9685],[-95.3212,48.9672],[-95.3207,48.9669],[-95.3201,48.9648],[-95.3198,48.9643],[-95.3193,48.964],[-95.3193,48.9622],[-95.3202,48.9606],[-95.3206,48.9598],[-95.3206,48.9595],[-95.3206,48.959],[-95.3202,48.9581],[-95.3191,48.9569],[-95.3188,48.9562],[-95.3179,48.9559],[-95.3175,48.9552],[-95.3177,48.9545],[-95.3182,48.9535],[-95.3181,48.9531],[-95.3177,48.9525],[-95.3154,48.9513],[-95.3151,48.951],[-95.3141,48.9508],[-95.3131,48.9503],[-95.3125,48.9503],[-95.3123,48.9502],[-95.3119,48.9502],[-95.3119,48.9507],[-95.3129,48.9521],[-95.3129,48.9523],[-95.3126,48.9524],[-95.312,48.9524],[-95.3115,48.952],[-95.3108,48.9512],[-95.3104,48.951],[-95.3097,48.951],[-95.3089,48.9511],[-95.3079,48.9509],[-95.3061,48.9502],[-95.3052,48.9495],[-95.3046,48.9482],[-95.3046,48.947],[-95.305,48.9462],[-95.3053,48.9459],[-95.3061,48.9454],[-95.3068,48.9454],[-95.3069,48.9455],[-95.3069,48.9456],[-95.3063,48.9462],[-95.3062,48.9463],[-95.3061,48.9469],[-95.3062,48.9472],[-95.3062,48.9472],[-95.3071,48.9477],[-95.3081,48.948],[-95.3094,48.9481],[-95.3096,48.9482],[-95.3099,48.9484],[-95.31,48.9485],[-95.3103,48.9485],[-95.3104,48.9484],[-95.3103,48.948],[-95.3096,48.9478],[-95.3092,48.9477],[-95.3079,48.9474],[-95.3071,48.9469],[-95.3071,48.9466],[-95.3074,48.9465],[-95.3078,48.9466],[-95.3085,48.947],[-95.3086,48.9469],[-95.3086,48.9465],[-95.3088,48.9464],[-95.3095,48.9463],[-95.3102,48.9463],[-95.3114,48.9461],[-95.3131,48.946],[-95.3141,48.9457],[-95.3148,48.9452],[-95.3154,48.9448],[-95.3168,48.9431],[-95.3181,48.9421],[-95.3189,48.9419],[-95.3219,48.9412],[-95.3225,48.9409],[-95.3228,48.9403],[-95.3231,48.9389],[-95.3229,48.9373],[-95.3225,48.9358],[-95.3223,48.9355],[-95.3228,48.9344],[-95.3222,48.9327],[-95.3209,48.9307],[-95.3208,48.9305],[-95.3195,48.9285],[-95.3168,48.9245],[-95.315,48.9222],[-95.3141,48.921],[-95.3132,48.9198],[-95.3126,48.919],[-95.3119,48.9178],[-95.3115,48.9172],[-95.3109,48.9163],[-95.3102,48.9155],[-95.3093,48.9149],[-95.3092,48.9149],[-95.3085,48.9146],[-95.3078,48.9141],[-95.3074,48.9135],[-95.3064,48.9129],[-95.3061,48.9128],[-95.3059,48.9127],[-95.3043,48.9119],[-95.3038,48.9114],[-95.3027,48.91],[-95.3017,48.9093],[-95.2999,48.9086],[-95.2978,48.9083],[-95.2973,48.9081],[-95.2973,48.908],[-95.2973,48.9077],[-95.2976,48.9074],[-95.2977,48.9073],[-95.2978,48.9073],[-95.2978,48.9072],[-95.2978,48.9072],[-95.2979,48.9072],[-95.2979,48.9072],[-95.2979,48.9071],[-95.298,48.9071],[-95.298,48.9071],[-95.298,48.9071],[-95.2981,48.907],[-95.2982,48.9068],[-95.2983,48.9068],[-95.2985,48.9065],[-95.2985,48.9064],[-95.2986,48.9063],[-95.2988,48.906],[-95.2989,48.906],[-95.2991,48.9057],[-95.2992,48.9055],[-95.2994,48.9053],[-95.2996,48.9051],[-95.2997,48.905],[-95.2999,48.9048],[-95.2999,48.9048],[-95.2999,48.9048],[-95.3,48.9047],[-95.3,48.9047],[-95.3001,48.9047],[-95.3001,48.9046],[-95.3002,48.9045],[-95.3005,48.904],[-95.2993,48.9035],[-95.2983,48.9028],[-95.298,48.9027],[-95.2976,48.9026],[-95.2967,48.9027],[-95.2949,48.9028],[-95.2941,48.9027],[-95.2937,48.9023],[-95.2935,48.902],[-95.2927,48.9019],[-95.2914,48.9019],[-95.2909,48.9017],[-95.2908,48.9016],[-95.2907,48.9014],[-95.2906,48.9011],[-95.2911,48.9008],[-95.2911,48.9006],[-95.2901,48.9003],[-95.2896,48.9],[-95.289,48.8994],[-95.2882,48.8981],[-95.2879,48.8979],[-95.2872,48.8977],[-95.287,48.8976],[-95.2865,48.8975],[-95.2861,48.8976],[-95.2853,48.8977],[-95.2839,48.8975],[-95.2813,48.8967],[-95.2803,48.8965],[-95.2796,48.8962],[-95.279,48.8957],[-95.2782,48.8956],[-95.2773,48.8957],[-95.277,48.8958],[-95.2765,48.8962],[-95.2763,48.8963],[-95.2759,48.8962],[-95.2755,48.8959],[-95.2749,48.8956],[-95.2748,48.8951],[-95.2753,48.8943],[-95.2751,48.8938],[-95.2745,48.8931],[-95.2724,48.8921],[-95.2713,48.8915],[-95.268,48.8905],[-95.2677,48.8903],[-95.2674,48.89],[-95.2666,48.8894],[-95.2654,48.8888],[-95.265,48.8886],[-95.2646,48.8885],[-95.2639,48.8883],[-95.2635,48.888],[-95.2627,48.8877],[-95.2585,48.8867],[-95.2585,48.8867],[-95.257,48.8858],[-95.256,48.885],[-95.2548,48.8845],[-95.2517,48.8839],[-95.2507,48.8836],[-95.2502,48.8835],[-95.2496,48.8834],[-95.2485,48.8832],[-95.248,48.8836],[-95.2472,48.8835],[-95.2458,48.8829],[-95.2439,48.8823],[-95.2429,48.8822],[-95.2429,48.8822],[-95.2423,48.8821],[-95.2407,48.8821],[-95.2391,48.8819],[-95.2381,48.8817],[-95.2356,48.8815],[-95.2335,48.8814],[-95.231,48.8814],[-95.2287,48.8815],[-95.2265,48.8816],[-95.2252,48.8819],[-95.2212,48.883],[-95.2208,48.8831],[-95.2207,48.8831],[-95.22,48.8831],[-95.2193,48.8832],[-95.2188,48.8835],[-95.217,48.8835],[-95.2159,48.8839],[-95.2151,48.884],[-95.2144,48.8843],[-95.2122,48.8842],[-95.2117,48.8847],[-95.2115,48.8847],[-95.2112,48.8848],[-95.2085,48.8846],[-95.2059,48.8848],[-95.2024,48.8852],[-95.2009,48.8855],[-95.2005,48.8856],[-95.1986,48.8855],[-95.1956,48.8862],[-95.1924,48.8865],[-95.1919,48.8866],[-95.1913,48.8868],[-95.1901,48.887],[-95.1889,48.8873],[-95.1877,48.8874],[-95.1863,48.8877],[-95.1851,48.8882],[-95.1819,48.8888],[-95.1797,48.889],[-95.1791,48.889],[-95.1764,48.8893],[-95.173,48.8897],[-95.1701,48.8902],[-95.1674,48.8907],[-95.1648,48.8913],[-95.1641,48.8917],[-95.1618,48.892],[-95.1602,48.892],[-95.1579,48.8919],[-95.1564,48.8919],[-95.1555,48.892],[-95.1528,48.8921],[-95.1508,48.8922],[-95.1483,48.8923],[-95.1469,48.8927],[-95.1459,48.8929],[-95.1438,48.8934],[-95.1436,48.8937],[-95.1404,48.8943],[-95.1381,48.8949],[-95.1355,48.8959],[-95.1351,48.8963],[-95.1348,48.8963],[-95.1343,48.8963],[-95.1337,48.8969],[-95.1322,48.8973],[-95.1312,48.8975],[-95.1252,48.8998],[-95.1239,48.9001],[-95.1233,48.9004],[-95.1228,48.9006],[-95.1214,48.9013],[-95.121,48.9016],[-95.1205,48.9017],[-95.1204,48.9019],[-95.1182,48.9029],[-95.1163,48.9037],[-95.1151,48.9046],[-95.1144,48.9052],[-95.114,48.9061],[-95.1141,48.9064],[-95.1137,48.9069],[-95.1132,48.9071],[-95.113,48.9072],[-95.1126,48.9073],[-95.1107,48.9082],[-95.1096,48.9089],[-95.108,48.9099],[-95.1056,48.9113],[-95.1042,48.9121],[-95.1032,48.9127],[-95.102,48.9132],[-95.1008,48.9142],[-95.0981,48.9159],[-95.098,48.916],[-95.0975,48.9164],[-95.0971,48.9172],[-95.097,48.9176],[-95.0961,48.9181],[-95.0946,48.9191],[-95.0944,48.9193],[-95.0927,48.9204],[-95.0919,48.9207],[-95.0914,48.9208],[-95.0914,48.916],[-95.0912,48.9014],[-95.0911,48.8869],[-95.0908,48.8724],[-95.0908,48.858],[-95.0907,48.8436],[-95.0908,48.8291],[-95.0909,48.8147],[-95.0903,48.8],[-95.0903,48.7855],[-95.0903,48.7711],[-95.0901,48.7566],[-95.0901,48.7421],[-95.0899,48.7277],[-95.0898,48.713],[-95.1046,48.7129],[-95.1104,48.7129],[-95.1119,48.7129],[-95.1259,48.7129],[-95.1297,48.713],[-95.1333,48.713],[-95.1477,48.7129],[-95.1554,48.7129],[-95.1697,48.7129],[-95.1773,48.713],[-95.1917,48.713],[-95.1991,48.713],[-95.2112,48.713],[-95.2206,48.713],[-95.2331,48.713],[-95.2427,48.713],[-95.255,48.713],[-95.2645,48.713],[-95.2656,48.713],[-95.2767,48.713],[-95.2866,48.713],[-95.299,48.713],[-95.3051,48.713],[-95.3084,48.713],[-95.3205,48.713],[-95.3302,48.713],[-95.3425,48.7131],[-95.3425,48.6995],[-95.3424,48.6849],[-95.3423,48.6705],[-95.3424,48.6561],[-95.3425,48.6415],[-95.3426,48.6271],[-95.3424,48.6127],[-95.3426,48.5979],[-95.3423,48.5836],[-95.3423,48.5691],[-95.3424,48.5548],[-95.3425,48.5402],[-95.3628,48.5404],[-95.364,48.5403],[-95.3844,48.5402],[-95.386,48.5402],[-95.4061,48.5402],[-95.4078,48.5402],[-95.4279,48.54],[-95.4297,48.5399],[-95.4494,48.5399],[-95.4513,48.5399],[-95.4712,48.5396],[-95.4726,48.5396],[-95.493,48.5392],[-95.495,48.5392],[-95.5143,48.539],[-95.5163,48.539],[-95.5365,48.5389],[-95.5383,48.5389],[-95.558,48.5388],[-95.5603,48.5388],[-95.5801,48.5387],[-95.5821,48.5387],[-95.6023,48.5389],[-95.6232,48.5391],[-95.6447,48.5393],[-95.6666,48.5394],[-95.6886,48.5395],[-95.7102,48.5395],[-95.7322,48.54],[-95.7539,48.5404],[-95.7758,48.5406],[-95.7976,48.5405],[-95.8192,48.5404],[-95.8411,48.5406],[-95.8621,48.5414],[-95.8829,48.5419],[-95.8851,48.542],[-95.8986,48.5421],[-95.9046,48.5422],[-95.9064,48.5422],[-95.9269,48.5421],[-95.9486,48.5425],[-95.9498,48.5425],[-95.9704,48.543],[-95.9936,48.5435],[-96.0157,48.5437],[-96.0374,48.5438],[-96.0592,48.5437],[-96.0812,48.5436],[-96.1026,48.5438],[-96.1264,48.5439],[-96.1486,48.5442],[-96.1702,48.5445],[-96.1921,48.5446],[-96.2141,48.5449],[-96.2358,48.5452],[-96.2576,48.545],[-96.2794,48.5449],[-96.301,48.5448],[-96.3231,48.5446],[-96.3448,48.5444],[-96.3667,48.5443],[-96.3882,48.5442],[-96.3879,48.5588],[-96.3882,48.5733],[-96.3884,48.5877],[-96.3891,48.6024],[-96.389,48.6165],[-96.388,48.6313],[-96.3879,48.6454],[-96.3877,48.6599],[-96.3871,48.6741],[-96.3874,48.6887],[-96.3866,48.703],[-96.3873,48.7172],[-96.388,48.7172],[-96.4049,48.7172],[-96.4048,48.7318],[-96.4048,48.7465],[-96.4047,48.7607],[-96.4045,48.7758],[-96.4042,48.7903],[-96.4042,48.8048],[-96.4042,48.8198],[-96.4043,48.8343],[-96.4045,48.8491],[-96.4047,48.8635],[-96.405,48.878],[-96.405,48.8926],[-96.4053,48.9068],[-96.4053,48.9081],[-96.4053,48.9137],[-96.4054,48.9214],[-96.4054,48.9225],[-96.4053,48.936],[-96.4053,48.9371],[-96.4053,48.9504],[-96.4053,48.9515],[-96.4053,48.9648],[-96.4053,48.9658],[-96.4053,48.9705],[-96.4054,48.9793],[-96.4054,48.9803],[-96.4054,48.994],[-96.4054,48.9947],[-96.4054,49.0001]]],"type":"Polygon"},"id":"68","properties":{"Area":4347098503.12714,"CTYONLY_":4,"Code":"ROSE","LASTMOD":"2001-04-12T09:32:44Z","Name":"Roseau","Perimiter":302590.75293},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&filter=%7B%22op%22%3A%22%3D%22%2C%22args%22%3A%5B%7B%22property%22%3A%22CTYONLY_%22%7D%2C%7B%22op%22%3A%22%25%22%2C%22args%22%3A%5B9%2C5%5D%7D%5D%7D&filter-lang=cql2-json","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&filter=%7B%22op%22%3A%22%3D%22%2C%22args%22%3A%5B%7B%22property%22%3A%22CTYONLY_%22%7D%2C%7B%22op%22%3A%22%25%22%2C%22args%22%3A%5B9%2C5%5D%7D%5D%7D&filter-lang=cql2-json","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":1,"numberReturned":1,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_json_multiply.json.txt b/msautotest/api/expected/ogcapi_cql2_json_multiply.json.txt new file mode 100644 index 0000000000..d849417175 --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_json_multiply.json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 1 +OGC-NumberReturned: 1 + +{"features":[{"geometry":{"coordinates":[[[-96.4054,49.0001],[-96.4019,49.0001],[-96.3825,49.0001],[-96.3783,49.0001],[-96.3606,49.0001],[-96.3579,49.0001],[-96.3385,49.0001],[-96.3343,49.0001],[-96.3166,49.0001],[-96.3138,49.0001],[-96.2945,49.0001],[-96.2902,49.0001],[-96.2725,49.0001],[-96.2698,49.0001],[-96.2494,49.0001],[-96.2461,49.0001],[-96.2274,49.0001],[-96.2257,49.0001],[-96.2057,49.0001],[-96.2021,49.0001],[-96.1837,49.0],[-96.18,49.0],[-96.1617,49.0],[-96.1579,49.0],[-96.1401,49.0],[-96.1359,49.0],[-96.1176,49.0],[-96.1139,49.0],[-96.0957,49.0],[-96.0919,49.0],[-96.0738,49.0],[-96.07,49.0],[-96.0517,49.0],[-96.048,49.0],[-96.0298,49.0],[-96.026,49.0],[-96.0083,49.0],[-96.0045,49.0],[-95.9868,49.0],[-95.9784,49.0],[-95.9776,49.0],[-95.9755,49.0],[-95.9648,48.9999],[-95.9464,48.9999],[-95.943,48.9999],[-95.9225,48.9999],[-95.9211,48.9999],[-95.899,48.9998],[-95.883,48.9998],[-95.8771,48.9998],[-95.8564,48.9998],[-95.855,48.9998],[-95.8342,48.9998],[-95.8184,48.9997],[-95.8126,48.9997],[-95.7906,48.9997],[-95.7833,48.9997],[-95.7684,48.9997],[-95.7479,48.9996],[-95.7466,48.9996],[-95.7253,48.9996],[-95.7066,48.9996],[-95.7032,48.9996],[-95.681,48.9995],[-95.6654,48.9995],[-95.6596,48.9995],[-95.659,48.9995],[-95.6401,48.9995],[-95.6369,48.9995],[-95.6205,48.9994],[-95.615,48.9994],[-95.5948,48.9994],[-95.585,48.9994],[-95.573,48.9994],[-95.551,48.9993],[-95.5495,48.9993],[-95.5294,48.9993],[-95.5164,48.9993],[-95.5072,48.9993],[-95.4849,48.9992],[-95.4834,48.9992],[-95.4635,48.9992],[-95.4508,48.9992],[-95.4418,48.9992],[-95.4245,48.9991],[-95.4197,48.9991],[-95.3977,48.9991],[-95.3953,48.9991],[-95.3765,48.9991],[-95.3759,48.9991],[-95.3753,48.9991],[-95.3542,48.999],[-95.3513,48.999],[-95.3326,48.999],[-95.3286,48.999],[-95.3231,48.999],[-95.3224,48.9984],[-95.3204,48.9976],[-95.3202,48.9973],[-95.3204,48.9964],[-95.3206,48.9961],[-95.3201,48.9956],[-95.3197,48.9954],[-95.3191,48.9953],[-95.3187,48.9956],[-95.3182,48.996],[-95.3179,48.9961],[-95.3178,48.9961],[-95.3178,48.9958],[-95.3181,48.995],[-95.3191,48.9941],[-95.3204,48.9924],[-95.3206,48.9921],[-95.3224,48.9889],[-95.3227,48.9884],[-95.3242,48.9859],[-95.3245,48.985],[-95.3253,48.9832],[-95.3257,48.9814],[-95.3256,48.98],[-95.3255,48.9789],[-95.3257,48.9784],[-95.3253,48.976],[-95.325,48.9743],[-95.3249,48.9738],[-95.3248,48.9728],[-95.3247,48.972],[-95.3241,48.9703],[-95.3232,48.9692],[-95.3227,48.9685],[-95.3212,48.9672],[-95.3207,48.9669],[-95.3201,48.9648],[-95.3198,48.9643],[-95.3193,48.964],[-95.3193,48.9622],[-95.3202,48.9606],[-95.3206,48.9598],[-95.3206,48.9595],[-95.3206,48.959],[-95.3202,48.9581],[-95.3191,48.9569],[-95.3188,48.9562],[-95.3179,48.9559],[-95.3175,48.9552],[-95.3177,48.9545],[-95.3182,48.9535],[-95.3181,48.9531],[-95.3177,48.9525],[-95.3154,48.9513],[-95.3151,48.951],[-95.3141,48.9508],[-95.3131,48.9503],[-95.3125,48.9503],[-95.3123,48.9502],[-95.3119,48.9502],[-95.3119,48.9507],[-95.3129,48.9521],[-95.3129,48.9523],[-95.3126,48.9524],[-95.312,48.9524],[-95.3115,48.952],[-95.3108,48.9512],[-95.3104,48.951],[-95.3097,48.951],[-95.3089,48.9511],[-95.3079,48.9509],[-95.3061,48.9502],[-95.3052,48.9495],[-95.3046,48.9482],[-95.3046,48.947],[-95.305,48.9462],[-95.3053,48.9459],[-95.3061,48.9454],[-95.3068,48.9454],[-95.3069,48.9455],[-95.3069,48.9456],[-95.3063,48.9462],[-95.3062,48.9463],[-95.3061,48.9469],[-95.3062,48.9472],[-95.3062,48.9472],[-95.3071,48.9477],[-95.3081,48.948],[-95.3094,48.9481],[-95.3096,48.9482],[-95.3099,48.9484],[-95.31,48.9485],[-95.3103,48.9485],[-95.3104,48.9484],[-95.3103,48.948],[-95.3096,48.9478],[-95.3092,48.9477],[-95.3079,48.9474],[-95.3071,48.9469],[-95.3071,48.9466],[-95.3074,48.9465],[-95.3078,48.9466],[-95.3085,48.947],[-95.3086,48.9469],[-95.3086,48.9465],[-95.3088,48.9464],[-95.3095,48.9463],[-95.3102,48.9463],[-95.3114,48.9461],[-95.3131,48.946],[-95.3141,48.9457],[-95.3148,48.9452],[-95.3154,48.9448],[-95.3168,48.9431],[-95.3181,48.9421],[-95.3189,48.9419],[-95.3219,48.9412],[-95.3225,48.9409],[-95.3228,48.9403],[-95.3231,48.9389],[-95.3229,48.9373],[-95.3225,48.9358],[-95.3223,48.9355],[-95.3228,48.9344],[-95.3222,48.9327],[-95.3209,48.9307],[-95.3208,48.9305],[-95.3195,48.9285],[-95.3168,48.9245],[-95.315,48.9222],[-95.3141,48.921],[-95.3132,48.9198],[-95.3126,48.919],[-95.3119,48.9178],[-95.3115,48.9172],[-95.3109,48.9163],[-95.3102,48.9155],[-95.3093,48.9149],[-95.3092,48.9149],[-95.3085,48.9146],[-95.3078,48.9141],[-95.3074,48.9135],[-95.3064,48.9129],[-95.3061,48.9128],[-95.3059,48.9127],[-95.3043,48.9119],[-95.3038,48.9114],[-95.3027,48.91],[-95.3017,48.9093],[-95.2999,48.9086],[-95.2978,48.9083],[-95.2973,48.9081],[-95.2973,48.908],[-95.2973,48.9077],[-95.2976,48.9074],[-95.2977,48.9073],[-95.2978,48.9073],[-95.2978,48.9072],[-95.2978,48.9072],[-95.2979,48.9072],[-95.2979,48.9072],[-95.2979,48.9071],[-95.298,48.9071],[-95.298,48.9071],[-95.298,48.9071],[-95.2981,48.907],[-95.2982,48.9068],[-95.2983,48.9068],[-95.2985,48.9065],[-95.2985,48.9064],[-95.2986,48.9063],[-95.2988,48.906],[-95.2989,48.906],[-95.2991,48.9057],[-95.2992,48.9055],[-95.2994,48.9053],[-95.2996,48.9051],[-95.2997,48.905],[-95.2999,48.9048],[-95.2999,48.9048],[-95.2999,48.9048],[-95.3,48.9047],[-95.3,48.9047],[-95.3001,48.9047],[-95.3001,48.9046],[-95.3002,48.9045],[-95.3005,48.904],[-95.2993,48.9035],[-95.2983,48.9028],[-95.298,48.9027],[-95.2976,48.9026],[-95.2967,48.9027],[-95.2949,48.9028],[-95.2941,48.9027],[-95.2937,48.9023],[-95.2935,48.902],[-95.2927,48.9019],[-95.2914,48.9019],[-95.2909,48.9017],[-95.2908,48.9016],[-95.2907,48.9014],[-95.2906,48.9011],[-95.2911,48.9008],[-95.2911,48.9006],[-95.2901,48.9003],[-95.2896,48.9],[-95.289,48.8994],[-95.2882,48.8981],[-95.2879,48.8979],[-95.2872,48.8977],[-95.287,48.8976],[-95.2865,48.8975],[-95.2861,48.8976],[-95.2853,48.8977],[-95.2839,48.8975],[-95.2813,48.8967],[-95.2803,48.8965],[-95.2796,48.8962],[-95.279,48.8957],[-95.2782,48.8956],[-95.2773,48.8957],[-95.277,48.8958],[-95.2765,48.8962],[-95.2763,48.8963],[-95.2759,48.8962],[-95.2755,48.8959],[-95.2749,48.8956],[-95.2748,48.8951],[-95.2753,48.8943],[-95.2751,48.8938],[-95.2745,48.8931],[-95.2724,48.8921],[-95.2713,48.8915],[-95.268,48.8905],[-95.2677,48.8903],[-95.2674,48.89],[-95.2666,48.8894],[-95.2654,48.8888],[-95.265,48.8886],[-95.2646,48.8885],[-95.2639,48.8883],[-95.2635,48.888],[-95.2627,48.8877],[-95.2585,48.8867],[-95.2585,48.8867],[-95.257,48.8858],[-95.256,48.885],[-95.2548,48.8845],[-95.2517,48.8839],[-95.2507,48.8836],[-95.2502,48.8835],[-95.2496,48.8834],[-95.2485,48.8832],[-95.248,48.8836],[-95.2472,48.8835],[-95.2458,48.8829],[-95.2439,48.8823],[-95.2429,48.8822],[-95.2429,48.8822],[-95.2423,48.8821],[-95.2407,48.8821],[-95.2391,48.8819],[-95.2381,48.8817],[-95.2356,48.8815],[-95.2335,48.8814],[-95.231,48.8814],[-95.2287,48.8815],[-95.2265,48.8816],[-95.2252,48.8819],[-95.2212,48.883],[-95.2208,48.8831],[-95.2207,48.8831],[-95.22,48.8831],[-95.2193,48.8832],[-95.2188,48.8835],[-95.217,48.8835],[-95.2159,48.8839],[-95.2151,48.884],[-95.2144,48.8843],[-95.2122,48.8842],[-95.2117,48.8847],[-95.2115,48.8847],[-95.2112,48.8848],[-95.2085,48.8846],[-95.2059,48.8848],[-95.2024,48.8852],[-95.2009,48.8855],[-95.2005,48.8856],[-95.1986,48.8855],[-95.1956,48.8862],[-95.1924,48.8865],[-95.1919,48.8866],[-95.1913,48.8868],[-95.1901,48.887],[-95.1889,48.8873],[-95.1877,48.8874],[-95.1863,48.8877],[-95.1851,48.8882],[-95.1819,48.8888],[-95.1797,48.889],[-95.1791,48.889],[-95.1764,48.8893],[-95.173,48.8897],[-95.1701,48.8902],[-95.1674,48.8907],[-95.1648,48.8913],[-95.1641,48.8917],[-95.1618,48.892],[-95.1602,48.892],[-95.1579,48.8919],[-95.1564,48.8919],[-95.1555,48.892],[-95.1528,48.8921],[-95.1508,48.8922],[-95.1483,48.8923],[-95.1469,48.8927],[-95.1459,48.8929],[-95.1438,48.8934],[-95.1436,48.8937],[-95.1404,48.8943],[-95.1381,48.8949],[-95.1355,48.8959],[-95.1351,48.8963],[-95.1348,48.8963],[-95.1343,48.8963],[-95.1337,48.8969],[-95.1322,48.8973],[-95.1312,48.8975],[-95.1252,48.8998],[-95.1239,48.9001],[-95.1233,48.9004],[-95.1228,48.9006],[-95.1214,48.9013],[-95.121,48.9016],[-95.1205,48.9017],[-95.1204,48.9019],[-95.1182,48.9029],[-95.1163,48.9037],[-95.1151,48.9046],[-95.1144,48.9052],[-95.114,48.9061],[-95.1141,48.9064],[-95.1137,48.9069],[-95.1132,48.9071],[-95.113,48.9072],[-95.1126,48.9073],[-95.1107,48.9082],[-95.1096,48.9089],[-95.108,48.9099],[-95.1056,48.9113],[-95.1042,48.9121],[-95.1032,48.9127],[-95.102,48.9132],[-95.1008,48.9142],[-95.0981,48.9159],[-95.098,48.916],[-95.0975,48.9164],[-95.0971,48.9172],[-95.097,48.9176],[-95.0961,48.9181],[-95.0946,48.9191],[-95.0944,48.9193],[-95.0927,48.9204],[-95.0919,48.9207],[-95.0914,48.9208],[-95.0914,48.916],[-95.0912,48.9014],[-95.0911,48.8869],[-95.0908,48.8724],[-95.0908,48.858],[-95.0907,48.8436],[-95.0908,48.8291],[-95.0909,48.8147],[-95.0903,48.8],[-95.0903,48.7855],[-95.0903,48.7711],[-95.0901,48.7566],[-95.0901,48.7421],[-95.0899,48.7277],[-95.0898,48.713],[-95.1046,48.7129],[-95.1104,48.7129],[-95.1119,48.7129],[-95.1259,48.7129],[-95.1297,48.713],[-95.1333,48.713],[-95.1477,48.7129],[-95.1554,48.7129],[-95.1697,48.7129],[-95.1773,48.713],[-95.1917,48.713],[-95.1991,48.713],[-95.2112,48.713],[-95.2206,48.713],[-95.2331,48.713],[-95.2427,48.713],[-95.255,48.713],[-95.2645,48.713],[-95.2656,48.713],[-95.2767,48.713],[-95.2866,48.713],[-95.299,48.713],[-95.3051,48.713],[-95.3084,48.713],[-95.3205,48.713],[-95.3302,48.713],[-95.3425,48.7131],[-95.3425,48.6995],[-95.3424,48.6849],[-95.3423,48.6705],[-95.3424,48.6561],[-95.3425,48.6415],[-95.3426,48.6271],[-95.3424,48.6127],[-95.3426,48.5979],[-95.3423,48.5836],[-95.3423,48.5691],[-95.3424,48.5548],[-95.3425,48.5402],[-95.3628,48.5404],[-95.364,48.5403],[-95.3844,48.5402],[-95.386,48.5402],[-95.4061,48.5402],[-95.4078,48.5402],[-95.4279,48.54],[-95.4297,48.5399],[-95.4494,48.5399],[-95.4513,48.5399],[-95.4712,48.5396],[-95.4726,48.5396],[-95.493,48.5392],[-95.495,48.5392],[-95.5143,48.539],[-95.5163,48.539],[-95.5365,48.5389],[-95.5383,48.5389],[-95.558,48.5388],[-95.5603,48.5388],[-95.5801,48.5387],[-95.5821,48.5387],[-95.6023,48.5389],[-95.6232,48.5391],[-95.6447,48.5393],[-95.6666,48.5394],[-95.6886,48.5395],[-95.7102,48.5395],[-95.7322,48.54],[-95.7539,48.5404],[-95.7758,48.5406],[-95.7976,48.5405],[-95.8192,48.5404],[-95.8411,48.5406],[-95.8621,48.5414],[-95.8829,48.5419],[-95.8851,48.542],[-95.8986,48.5421],[-95.9046,48.5422],[-95.9064,48.5422],[-95.9269,48.5421],[-95.9486,48.5425],[-95.9498,48.5425],[-95.9704,48.543],[-95.9936,48.5435],[-96.0157,48.5437],[-96.0374,48.5438],[-96.0592,48.5437],[-96.0812,48.5436],[-96.1026,48.5438],[-96.1264,48.5439],[-96.1486,48.5442],[-96.1702,48.5445],[-96.1921,48.5446],[-96.2141,48.5449],[-96.2358,48.5452],[-96.2576,48.545],[-96.2794,48.5449],[-96.301,48.5448],[-96.3231,48.5446],[-96.3448,48.5444],[-96.3667,48.5443],[-96.3882,48.5442],[-96.3879,48.5588],[-96.3882,48.5733],[-96.3884,48.5877],[-96.3891,48.6024],[-96.389,48.6165],[-96.388,48.6313],[-96.3879,48.6454],[-96.3877,48.6599],[-96.3871,48.6741],[-96.3874,48.6887],[-96.3866,48.703],[-96.3873,48.7172],[-96.388,48.7172],[-96.4049,48.7172],[-96.4048,48.7318],[-96.4048,48.7465],[-96.4047,48.7607],[-96.4045,48.7758],[-96.4042,48.7903],[-96.4042,48.8048],[-96.4042,48.8198],[-96.4043,48.8343],[-96.4045,48.8491],[-96.4047,48.8635],[-96.405,48.878],[-96.405,48.8926],[-96.4053,48.9068],[-96.4053,48.9081],[-96.4053,48.9137],[-96.4054,48.9214],[-96.4054,48.9225],[-96.4053,48.936],[-96.4053,48.9371],[-96.4053,48.9504],[-96.4053,48.9515],[-96.4053,48.9648],[-96.4053,48.9658],[-96.4053,48.9705],[-96.4054,48.9793],[-96.4054,48.9803],[-96.4054,48.994],[-96.4054,48.9947],[-96.4054,49.0001]]],"type":"Polygon"},"id":"68","properties":{"Area":4347098503.12714,"CTYONLY_":4,"Code":"ROSE","LASTMOD":"2001-04-12T09:32:44Z","Name":"Roseau","Perimiter":302590.75293},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&filter=%7B%22op%22%3A%22%3D%22%2C%22args%22%3A%5B%7B%22property%22%3A%22CTYONLY_%22%7D%2C%7B%22op%22%3A%22*%22%2C%22args%22%3A%5B2%2C2%5D%7D%5D%7D&filter-lang=cql2-json","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&filter=%7B%22op%22%3A%22%3D%22%2C%22args%22%3A%5B%7B%22property%22%3A%22CTYONLY_%22%7D%2C%7B%22op%22%3A%22*%22%2C%22args%22%3A%5B2%2C2%5D%7D%5D%7D&filter-lang=cql2-json","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":1,"numberReturned":1,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_json_not_not_equal.json.txt b/msautotest/api/expected/ogcapi_cql2_json_not_not_equal.json.txt new file mode 100644 index 0000000000..485d2e1b9b --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_json_not_not_equal.json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 1 +OGC-NumberReturned: 1 + +{"features":[{"geometry":{"coordinates":[[[-93.5242,44.5436],[-93.5225,44.5436],[-93.504,44.5438],[-93.5018,44.5438],[-93.4835,44.5438],[-93.4817,44.5438],[-93.4734,44.5438],[-93.4632,44.5438],[-93.4609,44.5438],[-93.4429,44.5438],[-93.4408,44.5438],[-93.4326,44.5438],[-93.4226,44.5439],[-93.4206,44.5439],[-93.4024,44.5439],[-93.4003,44.5439],[-93.383,44.544],[-93.38,44.544],[-93.3627,44.5441],[-93.3596,44.5441],[-93.3556,44.5441],[-93.3424,44.5442],[-93.3395,44.5442],[-93.3221,44.544],[-93.3191,44.544],[-93.3128,44.544],[-93.3019,44.544],[-93.2988,44.544],[-93.2813,44.544],[-93.2814,44.5298],[-93.2815,44.5153],[-93.2815,44.501],[-93.2815,44.4865],[-93.2817,44.472],[-93.2618,44.4718],[-93.2415,44.4716],[-93.2213,44.4714],[-93.2008,44.4714],[-93.1808,44.4713],[-93.1605,44.4713],[-93.1408,44.4712],[-93.1206,44.4713],[-93.1002,44.4718],[-93.0799,44.4719],[-93.0597,44.4718],[-93.0393,44.4719],[-93.0394,44.4576],[-93.0396,44.4432],[-93.0397,44.4287],[-93.0399,44.4143],[-93.04,44.3999],[-93.0401,44.3855],[-93.0402,44.371],[-93.0403,44.3565],[-93.0403,44.3419],[-93.0405,44.3273],[-93.0405,44.3129],[-93.0405,44.2983],[-93.0406,44.2838],[-93.0407,44.2693],[-93.0409,44.2548],[-93.041,44.2402],[-93.0411,44.2257],[-93.0411,44.2113],[-93.0411,44.1968],[-93.0427,44.1968],[-93.0459,44.1968],[-93.0613,44.1967],[-93.0661,44.1967],[-93.0815,44.1967],[-93.0862,44.1967],[-93.1003,44.1967],[-93.1015,44.1967],[-93.1063,44.1967],[-93.1092,44.1967],[-93.1218,44.1967],[-93.1267,44.1967],[-93.1301,44.1967],[-93.1418,44.1967],[-93.1467,44.1967],[-93.1561,44.1966],[-93.1622,44.1966],[-93.1661,44.1966],[-93.1703,44.1966],[-93.1822,44.1966],[-93.1856,44.1966],[-93.1865,44.1966],[-93.2023,44.1966],[-93.2037,44.1966],[-93.2064,44.1966],[-93.2225,44.1966],[-93.2265,44.1966],[-93.2292,44.1966],[-93.2426,44.1966],[-93.2465,44.1966],[-93.255,44.1966],[-93.2629,44.1966],[-93.2664,44.1966],[-93.2767,44.1966],[-93.283,44.1966],[-93.2865,44.1965],[-93.2905,44.1965],[-93.3032,44.1965],[-93.3063,44.1965],[-93.3235,44.1965],[-93.3264,44.1965],[-93.3277,44.1965],[-93.3436,44.1965],[-93.3466,44.1965],[-93.3639,44.1965],[-93.3666,44.1965],[-93.3842,44.1965],[-93.3866,44.1965],[-93.4042,44.1965],[-93.4065,44.1965],[-93.4244,44.1964],[-93.4267,44.1964],[-93.4447,44.1964],[-93.4469,44.1964],[-93.4648,44.1963],[-93.467,44.1963],[-93.4852,44.1964],[-93.4872,44.1964],[-93.5053,44.1963],[-93.507,44.1963],[-93.5255,44.1962],[-93.5253,44.2107],[-93.5251,44.2251],[-93.5251,44.2388],[-93.5251,44.2533],[-93.5252,44.2685],[-93.5252,44.2829],[-93.5252,44.2975],[-93.5252,44.312],[-93.5249,44.3266],[-93.5249,44.3411],[-93.5245,44.3557],[-93.5245,44.3704],[-93.5246,44.3848],[-93.5245,44.3994],[-93.5245,44.4138],[-93.5245,44.4283],[-93.5245,44.4427],[-93.5245,44.4572],[-93.5244,44.4717],[-93.5245,44.4862],[-93.5244,44.5007],[-93.5243,44.5152],[-93.5244,44.5297],[-93.5242,44.5436]]],"type":"Polygon"},"id":"66","properties":{"Area":1335114621.00336,"CTYONLY_":66,"Code":"RICE","LASTMOD":"2010-10-17T00:00:00Z","Name":"Rice","Perimiter":154431.78788},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&filter=%7B%22op%22%3A%22not%22%2C%22args%22%3A%5B%7B%22op%22%3A%22%3C%3E%22%2C%22args%22%3A%5B%7B%22property%22%3A%22Name%22%7D%2C%22Rice%22%5D%7D%5D%7D&filter-lang=cql2-json","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&filter=%7B%22op%22%3A%22not%22%2C%22args%22%3A%5B%7B%22op%22%3A%22%3C%3E%22%2C%22args%22%3A%5B%7B%22property%22%3A%22Name%22%7D%2C%22Rice%22%5D%7D%5D%7D&filter-lang=cql2-json","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":1,"numberReturned":1,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_json_not_not_iequal.json.txt b/msautotest/api/expected/ogcapi_cql2_json_not_not_iequal.json.txt new file mode 100644 index 0000000000..e5c161692d --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_json_not_not_iequal.json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 1 +OGC-NumberReturned: 1 + +{"features":[{"geometry":{"coordinates":[[[-93.5242,44.5436],[-93.5225,44.5436],[-93.504,44.5438],[-93.5018,44.5438],[-93.4835,44.5438],[-93.4817,44.5438],[-93.4734,44.5438],[-93.4632,44.5438],[-93.4609,44.5438],[-93.4429,44.5438],[-93.4408,44.5438],[-93.4326,44.5438],[-93.4226,44.5439],[-93.4206,44.5439],[-93.4024,44.5439],[-93.4003,44.5439],[-93.383,44.544],[-93.38,44.544],[-93.3627,44.5441],[-93.3596,44.5441],[-93.3556,44.5441],[-93.3424,44.5442],[-93.3395,44.5442],[-93.3221,44.544],[-93.3191,44.544],[-93.3128,44.544],[-93.3019,44.544],[-93.2988,44.544],[-93.2813,44.544],[-93.2814,44.5298],[-93.2815,44.5153],[-93.2815,44.501],[-93.2815,44.4865],[-93.2817,44.472],[-93.2618,44.4718],[-93.2415,44.4716],[-93.2213,44.4714],[-93.2008,44.4714],[-93.1808,44.4713],[-93.1605,44.4713],[-93.1408,44.4712],[-93.1206,44.4713],[-93.1002,44.4718],[-93.0799,44.4719],[-93.0597,44.4718],[-93.0393,44.4719],[-93.0394,44.4576],[-93.0396,44.4432],[-93.0397,44.4287],[-93.0399,44.4143],[-93.04,44.3999],[-93.0401,44.3855],[-93.0402,44.371],[-93.0403,44.3565],[-93.0403,44.3419],[-93.0405,44.3273],[-93.0405,44.3129],[-93.0405,44.2983],[-93.0406,44.2838],[-93.0407,44.2693],[-93.0409,44.2548],[-93.041,44.2402],[-93.0411,44.2257],[-93.0411,44.2113],[-93.0411,44.1968],[-93.0427,44.1968],[-93.0459,44.1968],[-93.0613,44.1967],[-93.0661,44.1967],[-93.0815,44.1967],[-93.0862,44.1967],[-93.1003,44.1967],[-93.1015,44.1967],[-93.1063,44.1967],[-93.1092,44.1967],[-93.1218,44.1967],[-93.1267,44.1967],[-93.1301,44.1967],[-93.1418,44.1967],[-93.1467,44.1967],[-93.1561,44.1966],[-93.1622,44.1966],[-93.1661,44.1966],[-93.1703,44.1966],[-93.1822,44.1966],[-93.1856,44.1966],[-93.1865,44.1966],[-93.2023,44.1966],[-93.2037,44.1966],[-93.2064,44.1966],[-93.2225,44.1966],[-93.2265,44.1966],[-93.2292,44.1966],[-93.2426,44.1966],[-93.2465,44.1966],[-93.255,44.1966],[-93.2629,44.1966],[-93.2664,44.1966],[-93.2767,44.1966],[-93.283,44.1966],[-93.2865,44.1965],[-93.2905,44.1965],[-93.3032,44.1965],[-93.3063,44.1965],[-93.3235,44.1965],[-93.3264,44.1965],[-93.3277,44.1965],[-93.3436,44.1965],[-93.3466,44.1965],[-93.3639,44.1965],[-93.3666,44.1965],[-93.3842,44.1965],[-93.3866,44.1965],[-93.4042,44.1965],[-93.4065,44.1965],[-93.4244,44.1964],[-93.4267,44.1964],[-93.4447,44.1964],[-93.4469,44.1964],[-93.4648,44.1963],[-93.467,44.1963],[-93.4852,44.1964],[-93.4872,44.1964],[-93.5053,44.1963],[-93.507,44.1963],[-93.5255,44.1962],[-93.5253,44.2107],[-93.5251,44.2251],[-93.5251,44.2388],[-93.5251,44.2533],[-93.5252,44.2685],[-93.5252,44.2829],[-93.5252,44.2975],[-93.5252,44.312],[-93.5249,44.3266],[-93.5249,44.3411],[-93.5245,44.3557],[-93.5245,44.3704],[-93.5246,44.3848],[-93.5245,44.3994],[-93.5245,44.4138],[-93.5245,44.4283],[-93.5245,44.4427],[-93.5245,44.4572],[-93.5244,44.4717],[-93.5245,44.4862],[-93.5244,44.5007],[-93.5243,44.5152],[-93.5244,44.5297],[-93.5242,44.5436]]],"type":"Polygon"},"id":"66","properties":{"Area":1335114621.00336,"CTYONLY_":66,"Code":"RICE","LASTMOD":"2010-10-17T00:00:00Z","Name":"Rice","Perimiter":154431.78788},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&filter=%7B%22op%22%3A%22not%22%2C%22args%22%3A%5B%7B%22op%22%3A%22%3C%3E%22%2C%22args%22%3A%5B%7B%22op%22%3A%22casei%22%2C%22args%22%3A%5B%7B%22property%22%3A%22Name%22%7D%5D%7D%2C%7B%22op%22%3A%22casei%22%2C%22args%22%3A%5B%22rice%22%5D%7D%5D%7D%5D%7D&filter-lang=cql2-json","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&filter=%7B%22op%22%3A%22not%22%2C%22args%22%3A%5B%7B%22op%22%3A%22%3C%3E%22%2C%22args%22%3A%5B%7B%22op%22%3A%22casei%22%2C%22args%22%3A%5B%7B%22property%22%3A%22Name%22%7D%5D%7D%2C%7B%22op%22%3A%22casei%22%2C%22args%22%3A%5B%22rice%22%5D%7D%5D%7D%5D%7D&filter-lang=cql2-json","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":1,"numberReturned":1,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_json_s_intersects_bbox.json.txt b/msautotest/api/expected/ogcapi_cql2_json_s_intersects_bbox.json.txt new file mode 100644 index 0000000000..b0eae77fee --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_json_s_intersects_bbox.json.txt @@ -0,0 +1,9 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +Link: ; rel="next"; title="next page"; type="application/geo+json" +OGC-NumberMatched: 117 +OGC-NumberReturned: 1 + +{"features":[{"geometry":{"coordinates":[[[-95.3231,48.999],[-95.3109,48.999],[-95.2889,48.9989],[-95.2852,48.9989],[-95.2669,48.9989],[-95.245,48.9989],[-95.2232,48.9989],[-95.2014,48.9989],[-95.1792,48.9989],[-95.1574,48.9989],[-95.1531,48.9989],[-95.1531,49.0031],[-95.1532,49.0179],[-95.1532,49.0325],[-95.1532,49.047],[-95.1532,49.0619],[-95.1532,49.0765],[-95.1532,49.0911],[-95.1532,49.1057],[-95.1532,49.1205],[-95.1532,49.1354],[-95.1532,49.1499],[-95.1532,49.1642],[-95.1532,49.1788],[-95.1532,49.1807],[-95.1532,49.1931],[-95.1532,49.1966],[-95.1532,49.2077],[-95.1533,49.2131],[-95.1533,49.2219],[-95.1533,49.2308],[-95.1533,49.2365],[-95.1533,49.2472],[-95.1533,49.2512],[-95.1533,49.2655],[-95.1533,49.2697],[-95.1533,49.2802],[-95.1533,49.2882],[-95.1533,49.2945],[-95.1533,49.3072],[-95.1533,49.309],[-95.1533,49.3234],[-95.1533,49.3237],[-95.1533,49.3381],[-95.1533,49.3476],[-95.1533,49.3525],[-95.1533,49.3636],[-95.1533,49.367],[-95.1533,49.3705],[-95.1533,49.3776],[-95.1533,49.3813],[-95.1533,49.3845],[-95.1503,49.383],[-95.1499,49.3813],[-95.1498,49.3807],[-95.1467,49.3802],[-95.145,49.3784],[-95.1418,49.3784],[-95.1397,49.3762],[-95.1367,49.3751],[-95.1324,49.3736],[-95.1287,49.3705],[-95.1171,49.367],[-95.1159,49.3666],[-95.1145,49.3666],[-95.1098,49.3664],[-95.1031,49.3652],[-95.1031,49.3636],[-95.0926,49.3617],[-95.0897,49.3612],[-95.0707,49.3564],[-95.0582,49.3533],[-95.0495,49.3532],[-95.0479,49.3533],[-95.0262,49.3554],[-95.0141,49.3565],[-95.0047,49.3612],[-94.993,49.367],[-94.9889,49.369],[-94.9818,49.3684],[-94.9742,49.3678],[-94.9597,49.3699],[-94.9573,49.3702],[-94.952,49.3688],[-94.948,49.367],[-94.9376,49.3625],[-94.9152,49.3529],[-94.9143,49.3524],[-94.909,49.3502],[-94.9065,49.3484],[-94.8933,49.3414],[-94.8865,49.3378],[-94.8782,49.3334],[-94.8712,49.3308],[-94.854,49.3244],[-94.8492,49.3244],[-94.8363,49.3243],[-94.8311,49.3236],[-94.8271,49.323],[-94.8162,49.3214],[-94.8243,49.309],[-94.8243,49.3088],[-94.8255,49.2944],[-94.8255,49.2943],[-94.8204,49.28],[-94.8152,49.2653],[-94.8103,49.2515],[-94.8059,49.2388],[-94.8051,49.2367],[-94.8001,49.2224],[-94.7973,49.2144],[-94.7975,49.2079],[-94.7979,49.1979],[-94.7965,49.1936],[-94.7918,49.1792],[-94.7871,49.1646],[-94.7833,49.153],[-94.7823,49.15],[-94.7776,49.1357],[-94.7727,49.1206],[-94.7727,49.1206],[-94.7611,49.1096],[-94.7571,49.1058],[-94.7496,49.0988],[-94.7474,49.0918],[-94.7429,49.0773],[-94.7394,49.0657],[-94.7385,49.063],[-94.7344,49.0497],[-94.7299,49.0351],[-94.7254,49.0205],[-94.7207,49.0052],[-94.7184,48.9979],[-94.7162,48.9907],[-94.7117,48.9761],[-94.7072,48.9615],[-94.7027,48.9468],[-94.6982,48.9322],[-94.6968,48.9276],[-94.6844,48.8875],[-94.6834,48.8842],[-94.6842,48.8724],[-94.6855,48.8719],[-94.6923,48.8691],[-94.6902,48.8636],[-94.6914,48.8591],[-94.693,48.8535],[-94.6881,48.8447],[-94.6855,48.8401],[-94.6963,48.836],[-94.6975,48.8355],[-94.702,48.8319],[-94.7025,48.8302],[-94.7042,48.8243],[-94.6991,48.8159],[-94.6962,48.8111],[-94.6951,48.8092],[-94.6958,48.8012],[-94.6959,48.7997],[-94.6944,48.7895],[-94.6934,48.7864],[-94.6909,48.7781],[-94.687,48.7752],[-94.6776,48.772],[-94.6768,48.7717],[-94.6746,48.7705],[-94.6671,48.7662],[-94.6603,48.7605],[-94.6557,48.7581],[-94.6525,48.7565],[-94.652,48.7562],[-94.6453,48.7491],[-94.6453,48.7441],[-94.6443,48.7434],[-94.6414,48.7413],[-94.631,48.7392],[-94.6301,48.739],[-94.6191,48.7373],[-94.6106,48.7318],[-94.6084,48.731],[-94.6028,48.7289],[-94.6011,48.7283],[-94.5962,48.7248],[-94.5913,48.7197],[-94.5876,48.7176],[-94.5867,48.7175],[-94.5685,48.7156],[-94.5622,48.7159],[-94.5558,48.7163],[-94.549,48.7148],[-94.5487,48.7146],[-94.5457,48.7124],[-94.5396,48.7036],[-94.539,48.7028],[-94.5329,48.7013],[-94.5247,48.7016],[-94.5178,48.7008],[-94.5173,48.7008],[-94.5093,48.7006],[-94.5066,48.6999],[-94.4996,48.698],[-94.4958,48.698],[-94.4863,48.698],[-94.4739,48.6969],[-94.4706,48.6966],[-94.4631,48.6953],[-94.4568,48.6933],[-94.4523,48.6925],[-94.4517,48.6925],[-94.4465,48.693],[-94.4388,48.6949],[-94.4319,48.6998],[-94.4299,48.7012],[-94.4299,48.6998],[-94.43,48.6852],[-94.4301,48.6708],[-94.43,48.6564],[-94.4297,48.642],[-94.4294,48.6276],[-94.4292,48.6133],[-94.4289,48.5988],[-94.4289,48.5844],[-94.4291,48.5698],[-94.4295,48.5554],[-94.43,48.5409],[-94.4303,48.5264],[-94.4303,48.512],[-94.4299,48.4977],[-94.4296,48.4832],[-94.4296,48.4688],[-94.4293,48.4543],[-94.4292,48.4399],[-94.4293,48.4254],[-94.4294,48.411],[-94.4293,48.3964],[-94.4289,48.3821],[-94.4288,48.3675],[-94.4471,48.3675],[-94.4505,48.3675],[-94.4688,48.3675],[-94.4722,48.3674],[-94.4906,48.3674],[-94.4924,48.3674],[-94.4941,48.3674],[-94.5118,48.3675],[-94.5157,48.3674],[-94.5335,48.3674],[-94.5378,48.3674],[-94.5536,48.3674],[-94.5593,48.3674],[-94.5754,48.3674],[-94.5812,48.3674],[-94.5971,48.3675],[-94.6029,48.3674],[-94.6188,48.3673],[-94.6245,48.3673],[-94.6405,48.3673],[-94.6465,48.3673],[-94.6505,48.3673],[-94.6622,48.3673],[-94.6679,48.3673],[-94.6694,48.3672],[-94.683,48.3671],[-94.6898,48.3671],[-94.7099,48.3669],[-94.7117,48.3668],[-94.7315,48.3669],[-94.7329,48.3669],[-94.7533,48.3669],[-94.7549,48.3669],[-94.7748,48.3669],[-94.7765,48.3669],[-94.7967,48.3669],[-94.7983,48.3669],[-94.8183,48.3669],[-94.8199,48.3669],[-94.8399,48.3669],[-94.8416,48.3669],[-94.8616,48.3667],[-94.8632,48.3667],[-94.8833,48.3667],[-94.8849,48.3666],[-94.9049,48.3666],[-94.9065,48.3666],[-94.9264,48.3667],[-94.9283,48.3667],[-94.9469,48.3666],[-94.95,48.3666],[-94.9684,48.3667],[-94.9716,48.3667],[-94.9901,48.3667],[-94.9932,48.3667],[-95.0119,48.3665],[-95.0153,48.3665],[-95.0337,48.3665],[-95.0369,48.3665],[-95.0555,48.3665],[-95.0586,48.3665],[-95.0773,48.3664],[-95.0801,48.3664],[-95.099,48.3663],[-95.1008,48.3663],[-95.1018,48.3663],[-95.1207,48.3663],[-95.1236,48.3663],[-95.1315,48.3662],[-95.1424,48.3662],[-95.1454,48.3662],[-95.164,48.3661],[-95.1669,48.3661],[-95.1861,48.3661],[-95.1887,48.3661],[-95.1983,48.3661],[-95.2066,48.3661],[-95.2106,48.3661],[-95.211,48.3797],[-95.211,48.3808],[-95.2111,48.3941],[-95.2111,48.3952],[-95.2112,48.4087],[-95.2112,48.4096],[-95.2113,48.4232],[-95.2113,48.4242],[-95.2113,48.4255],[-95.2113,48.4376],[-95.2113,48.4387],[-95.2113,48.4522],[-95.2112,48.4529],[-95.211,48.4666],[-95.211,48.4673],[-95.2111,48.4816],[-95.2112,48.4962],[-95.2111,48.5101],[-95.2111,48.5109],[-95.2115,48.5244],[-95.2115,48.5252],[-95.2119,48.54],[-95.2324,48.5399],[-95.2339,48.5399],[-95.2537,48.5398],[-95.2554,48.5398],[-95.2756,48.54],[-95.2773,48.54],[-95.2975,48.5401],[-95.2992,48.5402],[-95.3194,48.54],[-95.321,48.54],[-95.3412,48.5402],[-95.3425,48.5402],[-95.3424,48.5548],[-95.3423,48.5691],[-95.3423,48.5836],[-95.3426,48.5979],[-95.3424,48.6127],[-95.3426,48.6271],[-95.3425,48.6415],[-95.3424,48.6561],[-95.3423,48.6705],[-95.3424,48.6849],[-95.3425,48.6995],[-95.3425,48.7131],[-95.3302,48.713],[-95.3205,48.713],[-95.3084,48.713],[-95.3051,48.713],[-95.299,48.713],[-95.2866,48.713],[-95.2767,48.713],[-95.2656,48.713],[-95.2645,48.713],[-95.255,48.713],[-95.2427,48.713],[-95.2331,48.713],[-95.2206,48.713],[-95.2112,48.713],[-95.1991,48.713],[-95.1917,48.713],[-95.1773,48.713],[-95.1697,48.7129],[-95.1554,48.7129],[-95.1477,48.7129],[-95.1333,48.713],[-95.1297,48.713],[-95.1259,48.7129],[-95.1119,48.7129],[-95.1104,48.7129],[-95.1046,48.7129],[-95.0898,48.713],[-95.0899,48.7277],[-95.0901,48.7421],[-95.0901,48.7566],[-95.0903,48.7711],[-95.0903,48.7855],[-95.0903,48.8],[-95.0909,48.8147],[-95.0908,48.8291],[-95.0907,48.8436],[-95.0908,48.858],[-95.0908,48.8724],[-95.0911,48.8869],[-95.0912,48.9014],[-95.0914,48.916],[-95.0914,48.9208],[-95.0919,48.9207],[-95.0927,48.9204],[-95.0944,48.9193],[-95.0946,48.9191],[-95.0961,48.9181],[-95.097,48.9176],[-95.0971,48.9172],[-95.0975,48.9164],[-95.098,48.916],[-95.0981,48.9159],[-95.1008,48.9142],[-95.102,48.9132],[-95.1032,48.9127],[-95.1042,48.9121],[-95.1056,48.9113],[-95.108,48.9099],[-95.1096,48.9089],[-95.1107,48.9082],[-95.1126,48.9073],[-95.113,48.9072],[-95.1132,48.9071],[-95.1137,48.9069],[-95.1141,48.9064],[-95.114,48.9061],[-95.1144,48.9052],[-95.1151,48.9046],[-95.1163,48.9037],[-95.1182,48.9029],[-95.1204,48.9019],[-95.1205,48.9017],[-95.121,48.9016],[-95.1214,48.9013],[-95.1228,48.9006],[-95.1233,48.9004],[-95.1239,48.9001],[-95.1252,48.8998],[-95.1312,48.8975],[-95.1322,48.8973],[-95.1337,48.8969],[-95.1343,48.8963],[-95.1348,48.8963],[-95.1351,48.8963],[-95.1355,48.8959],[-95.1381,48.8949],[-95.1404,48.8943],[-95.1436,48.8937],[-95.1438,48.8934],[-95.1459,48.8929],[-95.1469,48.8927],[-95.1483,48.8923],[-95.1508,48.8922],[-95.1528,48.8921],[-95.1555,48.892],[-95.1564,48.8919],[-95.1579,48.8919],[-95.1602,48.892],[-95.1618,48.892],[-95.1641,48.8917],[-95.1648,48.8913],[-95.1674,48.8907],[-95.1701,48.8902],[-95.173,48.8897],[-95.1764,48.8893],[-95.1791,48.889],[-95.1797,48.889],[-95.1819,48.8888],[-95.1851,48.8882],[-95.1863,48.8877],[-95.1877,48.8874],[-95.1889,48.8873],[-95.1901,48.887],[-95.1913,48.8868],[-95.1919,48.8866],[-95.1924,48.8865],[-95.1956,48.8862],[-95.1986,48.8855],[-95.2005,48.8856],[-95.2009,48.8855],[-95.2024,48.8852],[-95.2059,48.8848],[-95.2085,48.8846],[-95.2112,48.8848],[-95.2115,48.8847],[-95.2117,48.8847],[-95.2122,48.8842],[-95.2144,48.8843],[-95.2151,48.884],[-95.2159,48.8839],[-95.217,48.8835],[-95.2188,48.8835],[-95.2193,48.8832],[-95.22,48.8831],[-95.2207,48.8831],[-95.2208,48.8831],[-95.2212,48.883],[-95.2252,48.8819],[-95.2265,48.8816],[-95.2287,48.8815],[-95.231,48.8814],[-95.2335,48.8814],[-95.2356,48.8815],[-95.2381,48.8817],[-95.2391,48.8819],[-95.2407,48.8821],[-95.2423,48.8821],[-95.2429,48.8822],[-95.2429,48.8822],[-95.2439,48.8823],[-95.2458,48.8829],[-95.2472,48.8835],[-95.248,48.8836],[-95.2485,48.8832],[-95.2496,48.8834],[-95.2502,48.8835],[-95.2507,48.8836],[-95.2517,48.8839],[-95.2548,48.8845],[-95.256,48.885],[-95.257,48.8858],[-95.2585,48.8867],[-95.2585,48.8867],[-95.2627,48.8877],[-95.2635,48.888],[-95.2639,48.8883],[-95.2646,48.8885],[-95.265,48.8886],[-95.2654,48.8888],[-95.2666,48.8894],[-95.2674,48.89],[-95.2677,48.8903],[-95.268,48.8905],[-95.2713,48.8915],[-95.2724,48.8921],[-95.2745,48.8931],[-95.2751,48.8938],[-95.2753,48.8943],[-95.2748,48.8951],[-95.2749,48.8956],[-95.2755,48.8959],[-95.2759,48.8962],[-95.2763,48.8963],[-95.2765,48.8962],[-95.277,48.8958],[-95.2773,48.8957],[-95.2782,48.8956],[-95.279,48.8957],[-95.2796,48.8962],[-95.2803,48.8965],[-95.2813,48.8967],[-95.2839,48.8975],[-95.2853,48.8977],[-95.2861,48.8976],[-95.2865,48.8975],[-95.287,48.8976],[-95.2872,48.8977],[-95.2879,48.8979],[-95.2882,48.8981],[-95.289,48.8994],[-95.2896,48.9],[-95.2901,48.9003],[-95.2911,48.9006],[-95.2911,48.9008],[-95.2906,48.9011],[-95.2907,48.9014],[-95.2908,48.9016],[-95.2909,48.9017],[-95.2914,48.9019],[-95.2927,48.9019],[-95.2935,48.902],[-95.2937,48.9023],[-95.2941,48.9027],[-95.2949,48.9028],[-95.2967,48.9027],[-95.2976,48.9026],[-95.298,48.9027],[-95.2983,48.9028],[-95.2993,48.9035],[-95.3005,48.904],[-95.3002,48.9045],[-95.3001,48.9046],[-95.3001,48.9047],[-95.3,48.9047],[-95.3,48.9047],[-95.2999,48.9048],[-95.2999,48.9048],[-95.2999,48.9048],[-95.2997,48.905],[-95.2996,48.9051],[-95.2994,48.9053],[-95.2992,48.9055],[-95.2991,48.9057],[-95.2989,48.906],[-95.2988,48.906],[-95.2986,48.9063],[-95.2985,48.9064],[-95.2985,48.9065],[-95.2983,48.9068],[-95.2982,48.9068],[-95.2981,48.907],[-95.298,48.9071],[-95.298,48.9071],[-95.298,48.9071],[-95.2979,48.9071],[-95.2979,48.9072],[-95.2979,48.9072],[-95.2978,48.9072],[-95.2978,48.9072],[-95.2978,48.9073],[-95.2977,48.9073],[-95.2976,48.9074],[-95.2973,48.9077],[-95.2973,48.908],[-95.2973,48.9081],[-95.2978,48.9083],[-95.2999,48.9086],[-95.3017,48.9093],[-95.3027,48.91],[-95.3038,48.9114],[-95.3043,48.9119],[-95.3059,48.9127],[-95.3061,48.9128],[-95.3064,48.9129],[-95.3074,48.9135],[-95.3078,48.9141],[-95.3085,48.9146],[-95.3092,48.9149],[-95.3093,48.9149],[-95.3102,48.9155],[-95.3109,48.9163],[-95.3115,48.9172],[-95.3119,48.9178],[-95.3126,48.919],[-95.3132,48.9198],[-95.3141,48.921],[-95.315,48.9222],[-95.3168,48.9245],[-95.3195,48.9285],[-95.3208,48.9305],[-95.3209,48.9307],[-95.3222,48.9327],[-95.3228,48.9344],[-95.3223,48.9355],[-95.3225,48.9358],[-95.3229,48.9373],[-95.3231,48.9389],[-95.3228,48.9403],[-95.3225,48.9409],[-95.3219,48.9412],[-95.3189,48.9419],[-95.3181,48.9421],[-95.3168,48.9431],[-95.3154,48.9448],[-95.3148,48.9452],[-95.3141,48.9457],[-95.3131,48.946],[-95.3114,48.9461],[-95.3102,48.9463],[-95.3095,48.9463],[-95.3088,48.9464],[-95.3086,48.9465],[-95.3086,48.9469],[-95.3085,48.947],[-95.3078,48.9466],[-95.3074,48.9465],[-95.3071,48.9466],[-95.3071,48.9469],[-95.3079,48.9474],[-95.3092,48.9477],[-95.3096,48.9478],[-95.3103,48.948],[-95.3104,48.9484],[-95.3103,48.9485],[-95.31,48.9485],[-95.3099,48.9484],[-95.3096,48.9482],[-95.3094,48.9481],[-95.3081,48.948],[-95.3071,48.9477],[-95.3062,48.9472],[-95.3062,48.9472],[-95.3061,48.9469],[-95.3062,48.9463],[-95.3063,48.9462],[-95.3069,48.9456],[-95.3069,48.9455],[-95.3068,48.9454],[-95.3061,48.9454],[-95.3053,48.9459],[-95.305,48.9462],[-95.3046,48.947],[-95.3046,48.9482],[-95.3052,48.9495],[-95.3061,48.9502],[-95.3079,48.9509],[-95.3089,48.9511],[-95.3097,48.951],[-95.3104,48.951],[-95.3108,48.9512],[-95.3115,48.952],[-95.312,48.9524],[-95.3126,48.9524],[-95.3129,48.9523],[-95.3129,48.9521],[-95.3119,48.9507],[-95.3119,48.9502],[-95.3123,48.9502],[-95.3125,48.9503],[-95.3131,48.9503],[-95.3141,48.9508],[-95.3151,48.951],[-95.3154,48.9513],[-95.3177,48.9525],[-95.3181,48.9531],[-95.3182,48.9535],[-95.3177,48.9545],[-95.3175,48.9552],[-95.3179,48.9559],[-95.3188,48.9562],[-95.3191,48.9569],[-95.3202,48.9581],[-95.3206,48.959],[-95.3206,48.9595],[-95.3206,48.9598],[-95.3202,48.9606],[-95.3193,48.9622],[-95.3193,48.964],[-95.3198,48.9643],[-95.3201,48.9648],[-95.3207,48.9669],[-95.3212,48.9672],[-95.3227,48.9685],[-95.3232,48.9692],[-95.3241,48.9703],[-95.3247,48.972],[-95.3248,48.9728],[-95.3249,48.9738],[-95.325,48.9743],[-95.3253,48.976],[-95.3257,48.9784],[-95.3255,48.9789],[-95.3256,48.98],[-95.3257,48.9814],[-95.3253,48.9832],[-95.3245,48.985],[-95.3242,48.9859],[-95.3227,48.9884],[-95.3224,48.9889],[-95.3206,48.9921],[-95.3204,48.9924],[-95.3191,48.9941],[-95.3181,48.995],[-95.3178,48.9958],[-95.3178,48.9961],[-95.3179,48.9961],[-95.3182,48.996],[-95.3187,48.9956],[-95.3191,48.9953],[-95.3197,48.9954],[-95.3201,48.9956],[-95.3206,48.9961],[-95.3204,48.9964],[-95.3202,48.9973],[-95.3204,48.9976],[-95.3224,48.9984],[-95.3231,48.999]]],"type":"Polygon"},"id":"39","properties":{"Area":4608320923.49768,"CTYONLY_":2,"Code":"LOTW","LASTMOD":"1976-07-04T12:00:00Z","Name":"Lake of the Woods","Perimiter":388250.14572},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=1&offset=0&filter=%7B%22op%22%3A%22s_intersects%22%2C%22args%22%3A%5B%7B%22property%22%3A%22geom%22%7D%2C%7B%22bbox%22%3A%5B-180%2C-90%2C180%2C90%5D%7D%5D%7D&filter-lang=cql2-json","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=1&offset=0&filter=%7B%22op%22%3A%22s_intersects%22%2C%22args%22%3A%5B%7B%22property%22%3A%22geom%22%7D%2C%7B%22bbox%22%3A%5B-180%2C-90%2C180%2C90%5D%7D%5D%7D&filter-lang=cql2-json","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=1&offset=1&filter=%7B%22op%22%3A%22s_intersects%22%2C%22args%22%3A%5B%7B%22property%22%3A%22geom%22%7D%2C%7B%22bbox%22%3A%5B-180%2C-90%2C180%2C90%5D%7D%5D%7D&filter-lang=cql2-json","rel":"next","title":"next page","type":"application/geo+json"}],"numberMatched":117,"numberReturned":1,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_json_s_intersects_bbox_3D.json.txt b/msautotest/api/expected/ogcapi_cql2_json_s_intersects_bbox_3D.json.txt new file mode 100644 index 0000000000..2eb254ee3d --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_json_s_intersects_bbox_3D.json.txt @@ -0,0 +1,9 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +Link: ; rel="next"; title="next page"; type="application/geo+json" +OGC-NumberMatched: 117 +OGC-NumberReturned: 1 + +{"features":[{"geometry":{"coordinates":[[[-95.3231,48.999],[-95.3109,48.999],[-95.2889,48.9989],[-95.2852,48.9989],[-95.2669,48.9989],[-95.245,48.9989],[-95.2232,48.9989],[-95.2014,48.9989],[-95.1792,48.9989],[-95.1574,48.9989],[-95.1531,48.9989],[-95.1531,49.0031],[-95.1532,49.0179],[-95.1532,49.0325],[-95.1532,49.047],[-95.1532,49.0619],[-95.1532,49.0765],[-95.1532,49.0911],[-95.1532,49.1057],[-95.1532,49.1205],[-95.1532,49.1354],[-95.1532,49.1499],[-95.1532,49.1642],[-95.1532,49.1788],[-95.1532,49.1807],[-95.1532,49.1931],[-95.1532,49.1966],[-95.1532,49.2077],[-95.1533,49.2131],[-95.1533,49.2219],[-95.1533,49.2308],[-95.1533,49.2365],[-95.1533,49.2472],[-95.1533,49.2512],[-95.1533,49.2655],[-95.1533,49.2697],[-95.1533,49.2802],[-95.1533,49.2882],[-95.1533,49.2945],[-95.1533,49.3072],[-95.1533,49.309],[-95.1533,49.3234],[-95.1533,49.3237],[-95.1533,49.3381],[-95.1533,49.3476],[-95.1533,49.3525],[-95.1533,49.3636],[-95.1533,49.367],[-95.1533,49.3705],[-95.1533,49.3776],[-95.1533,49.3813],[-95.1533,49.3845],[-95.1503,49.383],[-95.1499,49.3813],[-95.1498,49.3807],[-95.1467,49.3802],[-95.145,49.3784],[-95.1418,49.3784],[-95.1397,49.3762],[-95.1367,49.3751],[-95.1324,49.3736],[-95.1287,49.3705],[-95.1171,49.367],[-95.1159,49.3666],[-95.1145,49.3666],[-95.1098,49.3664],[-95.1031,49.3652],[-95.1031,49.3636],[-95.0926,49.3617],[-95.0897,49.3612],[-95.0707,49.3564],[-95.0582,49.3533],[-95.0495,49.3532],[-95.0479,49.3533],[-95.0262,49.3554],[-95.0141,49.3565],[-95.0047,49.3612],[-94.993,49.367],[-94.9889,49.369],[-94.9818,49.3684],[-94.9742,49.3678],[-94.9597,49.3699],[-94.9573,49.3702],[-94.952,49.3688],[-94.948,49.367],[-94.9376,49.3625],[-94.9152,49.3529],[-94.9143,49.3524],[-94.909,49.3502],[-94.9065,49.3484],[-94.8933,49.3414],[-94.8865,49.3378],[-94.8782,49.3334],[-94.8712,49.3308],[-94.854,49.3244],[-94.8492,49.3244],[-94.8363,49.3243],[-94.8311,49.3236],[-94.8271,49.323],[-94.8162,49.3214],[-94.8243,49.309],[-94.8243,49.3088],[-94.8255,49.2944],[-94.8255,49.2943],[-94.8204,49.28],[-94.8152,49.2653],[-94.8103,49.2515],[-94.8059,49.2388],[-94.8051,49.2367],[-94.8001,49.2224],[-94.7973,49.2144],[-94.7975,49.2079],[-94.7979,49.1979],[-94.7965,49.1936],[-94.7918,49.1792],[-94.7871,49.1646],[-94.7833,49.153],[-94.7823,49.15],[-94.7776,49.1357],[-94.7727,49.1206],[-94.7727,49.1206],[-94.7611,49.1096],[-94.7571,49.1058],[-94.7496,49.0988],[-94.7474,49.0918],[-94.7429,49.0773],[-94.7394,49.0657],[-94.7385,49.063],[-94.7344,49.0497],[-94.7299,49.0351],[-94.7254,49.0205],[-94.7207,49.0052],[-94.7184,48.9979],[-94.7162,48.9907],[-94.7117,48.9761],[-94.7072,48.9615],[-94.7027,48.9468],[-94.6982,48.9322],[-94.6968,48.9276],[-94.6844,48.8875],[-94.6834,48.8842],[-94.6842,48.8724],[-94.6855,48.8719],[-94.6923,48.8691],[-94.6902,48.8636],[-94.6914,48.8591],[-94.693,48.8535],[-94.6881,48.8447],[-94.6855,48.8401],[-94.6963,48.836],[-94.6975,48.8355],[-94.702,48.8319],[-94.7025,48.8302],[-94.7042,48.8243],[-94.6991,48.8159],[-94.6962,48.8111],[-94.6951,48.8092],[-94.6958,48.8012],[-94.6959,48.7997],[-94.6944,48.7895],[-94.6934,48.7864],[-94.6909,48.7781],[-94.687,48.7752],[-94.6776,48.772],[-94.6768,48.7717],[-94.6746,48.7705],[-94.6671,48.7662],[-94.6603,48.7605],[-94.6557,48.7581],[-94.6525,48.7565],[-94.652,48.7562],[-94.6453,48.7491],[-94.6453,48.7441],[-94.6443,48.7434],[-94.6414,48.7413],[-94.631,48.7392],[-94.6301,48.739],[-94.6191,48.7373],[-94.6106,48.7318],[-94.6084,48.731],[-94.6028,48.7289],[-94.6011,48.7283],[-94.5962,48.7248],[-94.5913,48.7197],[-94.5876,48.7176],[-94.5867,48.7175],[-94.5685,48.7156],[-94.5622,48.7159],[-94.5558,48.7163],[-94.549,48.7148],[-94.5487,48.7146],[-94.5457,48.7124],[-94.5396,48.7036],[-94.539,48.7028],[-94.5329,48.7013],[-94.5247,48.7016],[-94.5178,48.7008],[-94.5173,48.7008],[-94.5093,48.7006],[-94.5066,48.6999],[-94.4996,48.698],[-94.4958,48.698],[-94.4863,48.698],[-94.4739,48.6969],[-94.4706,48.6966],[-94.4631,48.6953],[-94.4568,48.6933],[-94.4523,48.6925],[-94.4517,48.6925],[-94.4465,48.693],[-94.4388,48.6949],[-94.4319,48.6998],[-94.4299,48.7012],[-94.4299,48.6998],[-94.43,48.6852],[-94.4301,48.6708],[-94.43,48.6564],[-94.4297,48.642],[-94.4294,48.6276],[-94.4292,48.6133],[-94.4289,48.5988],[-94.4289,48.5844],[-94.4291,48.5698],[-94.4295,48.5554],[-94.43,48.5409],[-94.4303,48.5264],[-94.4303,48.512],[-94.4299,48.4977],[-94.4296,48.4832],[-94.4296,48.4688],[-94.4293,48.4543],[-94.4292,48.4399],[-94.4293,48.4254],[-94.4294,48.411],[-94.4293,48.3964],[-94.4289,48.3821],[-94.4288,48.3675],[-94.4471,48.3675],[-94.4505,48.3675],[-94.4688,48.3675],[-94.4722,48.3674],[-94.4906,48.3674],[-94.4924,48.3674],[-94.4941,48.3674],[-94.5118,48.3675],[-94.5157,48.3674],[-94.5335,48.3674],[-94.5378,48.3674],[-94.5536,48.3674],[-94.5593,48.3674],[-94.5754,48.3674],[-94.5812,48.3674],[-94.5971,48.3675],[-94.6029,48.3674],[-94.6188,48.3673],[-94.6245,48.3673],[-94.6405,48.3673],[-94.6465,48.3673],[-94.6505,48.3673],[-94.6622,48.3673],[-94.6679,48.3673],[-94.6694,48.3672],[-94.683,48.3671],[-94.6898,48.3671],[-94.7099,48.3669],[-94.7117,48.3668],[-94.7315,48.3669],[-94.7329,48.3669],[-94.7533,48.3669],[-94.7549,48.3669],[-94.7748,48.3669],[-94.7765,48.3669],[-94.7967,48.3669],[-94.7983,48.3669],[-94.8183,48.3669],[-94.8199,48.3669],[-94.8399,48.3669],[-94.8416,48.3669],[-94.8616,48.3667],[-94.8632,48.3667],[-94.8833,48.3667],[-94.8849,48.3666],[-94.9049,48.3666],[-94.9065,48.3666],[-94.9264,48.3667],[-94.9283,48.3667],[-94.9469,48.3666],[-94.95,48.3666],[-94.9684,48.3667],[-94.9716,48.3667],[-94.9901,48.3667],[-94.9932,48.3667],[-95.0119,48.3665],[-95.0153,48.3665],[-95.0337,48.3665],[-95.0369,48.3665],[-95.0555,48.3665],[-95.0586,48.3665],[-95.0773,48.3664],[-95.0801,48.3664],[-95.099,48.3663],[-95.1008,48.3663],[-95.1018,48.3663],[-95.1207,48.3663],[-95.1236,48.3663],[-95.1315,48.3662],[-95.1424,48.3662],[-95.1454,48.3662],[-95.164,48.3661],[-95.1669,48.3661],[-95.1861,48.3661],[-95.1887,48.3661],[-95.1983,48.3661],[-95.2066,48.3661],[-95.2106,48.3661],[-95.211,48.3797],[-95.211,48.3808],[-95.2111,48.3941],[-95.2111,48.3952],[-95.2112,48.4087],[-95.2112,48.4096],[-95.2113,48.4232],[-95.2113,48.4242],[-95.2113,48.4255],[-95.2113,48.4376],[-95.2113,48.4387],[-95.2113,48.4522],[-95.2112,48.4529],[-95.211,48.4666],[-95.211,48.4673],[-95.2111,48.4816],[-95.2112,48.4962],[-95.2111,48.5101],[-95.2111,48.5109],[-95.2115,48.5244],[-95.2115,48.5252],[-95.2119,48.54],[-95.2324,48.5399],[-95.2339,48.5399],[-95.2537,48.5398],[-95.2554,48.5398],[-95.2756,48.54],[-95.2773,48.54],[-95.2975,48.5401],[-95.2992,48.5402],[-95.3194,48.54],[-95.321,48.54],[-95.3412,48.5402],[-95.3425,48.5402],[-95.3424,48.5548],[-95.3423,48.5691],[-95.3423,48.5836],[-95.3426,48.5979],[-95.3424,48.6127],[-95.3426,48.6271],[-95.3425,48.6415],[-95.3424,48.6561],[-95.3423,48.6705],[-95.3424,48.6849],[-95.3425,48.6995],[-95.3425,48.7131],[-95.3302,48.713],[-95.3205,48.713],[-95.3084,48.713],[-95.3051,48.713],[-95.299,48.713],[-95.2866,48.713],[-95.2767,48.713],[-95.2656,48.713],[-95.2645,48.713],[-95.255,48.713],[-95.2427,48.713],[-95.2331,48.713],[-95.2206,48.713],[-95.2112,48.713],[-95.1991,48.713],[-95.1917,48.713],[-95.1773,48.713],[-95.1697,48.7129],[-95.1554,48.7129],[-95.1477,48.7129],[-95.1333,48.713],[-95.1297,48.713],[-95.1259,48.7129],[-95.1119,48.7129],[-95.1104,48.7129],[-95.1046,48.7129],[-95.0898,48.713],[-95.0899,48.7277],[-95.0901,48.7421],[-95.0901,48.7566],[-95.0903,48.7711],[-95.0903,48.7855],[-95.0903,48.8],[-95.0909,48.8147],[-95.0908,48.8291],[-95.0907,48.8436],[-95.0908,48.858],[-95.0908,48.8724],[-95.0911,48.8869],[-95.0912,48.9014],[-95.0914,48.916],[-95.0914,48.9208],[-95.0919,48.9207],[-95.0927,48.9204],[-95.0944,48.9193],[-95.0946,48.9191],[-95.0961,48.9181],[-95.097,48.9176],[-95.0971,48.9172],[-95.0975,48.9164],[-95.098,48.916],[-95.0981,48.9159],[-95.1008,48.9142],[-95.102,48.9132],[-95.1032,48.9127],[-95.1042,48.9121],[-95.1056,48.9113],[-95.108,48.9099],[-95.1096,48.9089],[-95.1107,48.9082],[-95.1126,48.9073],[-95.113,48.9072],[-95.1132,48.9071],[-95.1137,48.9069],[-95.1141,48.9064],[-95.114,48.9061],[-95.1144,48.9052],[-95.1151,48.9046],[-95.1163,48.9037],[-95.1182,48.9029],[-95.1204,48.9019],[-95.1205,48.9017],[-95.121,48.9016],[-95.1214,48.9013],[-95.1228,48.9006],[-95.1233,48.9004],[-95.1239,48.9001],[-95.1252,48.8998],[-95.1312,48.8975],[-95.1322,48.8973],[-95.1337,48.8969],[-95.1343,48.8963],[-95.1348,48.8963],[-95.1351,48.8963],[-95.1355,48.8959],[-95.1381,48.8949],[-95.1404,48.8943],[-95.1436,48.8937],[-95.1438,48.8934],[-95.1459,48.8929],[-95.1469,48.8927],[-95.1483,48.8923],[-95.1508,48.8922],[-95.1528,48.8921],[-95.1555,48.892],[-95.1564,48.8919],[-95.1579,48.8919],[-95.1602,48.892],[-95.1618,48.892],[-95.1641,48.8917],[-95.1648,48.8913],[-95.1674,48.8907],[-95.1701,48.8902],[-95.173,48.8897],[-95.1764,48.8893],[-95.1791,48.889],[-95.1797,48.889],[-95.1819,48.8888],[-95.1851,48.8882],[-95.1863,48.8877],[-95.1877,48.8874],[-95.1889,48.8873],[-95.1901,48.887],[-95.1913,48.8868],[-95.1919,48.8866],[-95.1924,48.8865],[-95.1956,48.8862],[-95.1986,48.8855],[-95.2005,48.8856],[-95.2009,48.8855],[-95.2024,48.8852],[-95.2059,48.8848],[-95.2085,48.8846],[-95.2112,48.8848],[-95.2115,48.8847],[-95.2117,48.8847],[-95.2122,48.8842],[-95.2144,48.8843],[-95.2151,48.884],[-95.2159,48.8839],[-95.217,48.8835],[-95.2188,48.8835],[-95.2193,48.8832],[-95.22,48.8831],[-95.2207,48.8831],[-95.2208,48.8831],[-95.2212,48.883],[-95.2252,48.8819],[-95.2265,48.8816],[-95.2287,48.8815],[-95.231,48.8814],[-95.2335,48.8814],[-95.2356,48.8815],[-95.2381,48.8817],[-95.2391,48.8819],[-95.2407,48.8821],[-95.2423,48.8821],[-95.2429,48.8822],[-95.2429,48.8822],[-95.2439,48.8823],[-95.2458,48.8829],[-95.2472,48.8835],[-95.248,48.8836],[-95.2485,48.8832],[-95.2496,48.8834],[-95.2502,48.8835],[-95.2507,48.8836],[-95.2517,48.8839],[-95.2548,48.8845],[-95.256,48.885],[-95.257,48.8858],[-95.2585,48.8867],[-95.2585,48.8867],[-95.2627,48.8877],[-95.2635,48.888],[-95.2639,48.8883],[-95.2646,48.8885],[-95.265,48.8886],[-95.2654,48.8888],[-95.2666,48.8894],[-95.2674,48.89],[-95.2677,48.8903],[-95.268,48.8905],[-95.2713,48.8915],[-95.2724,48.8921],[-95.2745,48.8931],[-95.2751,48.8938],[-95.2753,48.8943],[-95.2748,48.8951],[-95.2749,48.8956],[-95.2755,48.8959],[-95.2759,48.8962],[-95.2763,48.8963],[-95.2765,48.8962],[-95.277,48.8958],[-95.2773,48.8957],[-95.2782,48.8956],[-95.279,48.8957],[-95.2796,48.8962],[-95.2803,48.8965],[-95.2813,48.8967],[-95.2839,48.8975],[-95.2853,48.8977],[-95.2861,48.8976],[-95.2865,48.8975],[-95.287,48.8976],[-95.2872,48.8977],[-95.2879,48.8979],[-95.2882,48.8981],[-95.289,48.8994],[-95.2896,48.9],[-95.2901,48.9003],[-95.2911,48.9006],[-95.2911,48.9008],[-95.2906,48.9011],[-95.2907,48.9014],[-95.2908,48.9016],[-95.2909,48.9017],[-95.2914,48.9019],[-95.2927,48.9019],[-95.2935,48.902],[-95.2937,48.9023],[-95.2941,48.9027],[-95.2949,48.9028],[-95.2967,48.9027],[-95.2976,48.9026],[-95.298,48.9027],[-95.2983,48.9028],[-95.2993,48.9035],[-95.3005,48.904],[-95.3002,48.9045],[-95.3001,48.9046],[-95.3001,48.9047],[-95.3,48.9047],[-95.3,48.9047],[-95.2999,48.9048],[-95.2999,48.9048],[-95.2999,48.9048],[-95.2997,48.905],[-95.2996,48.9051],[-95.2994,48.9053],[-95.2992,48.9055],[-95.2991,48.9057],[-95.2989,48.906],[-95.2988,48.906],[-95.2986,48.9063],[-95.2985,48.9064],[-95.2985,48.9065],[-95.2983,48.9068],[-95.2982,48.9068],[-95.2981,48.907],[-95.298,48.9071],[-95.298,48.9071],[-95.298,48.9071],[-95.2979,48.9071],[-95.2979,48.9072],[-95.2979,48.9072],[-95.2978,48.9072],[-95.2978,48.9072],[-95.2978,48.9073],[-95.2977,48.9073],[-95.2976,48.9074],[-95.2973,48.9077],[-95.2973,48.908],[-95.2973,48.9081],[-95.2978,48.9083],[-95.2999,48.9086],[-95.3017,48.9093],[-95.3027,48.91],[-95.3038,48.9114],[-95.3043,48.9119],[-95.3059,48.9127],[-95.3061,48.9128],[-95.3064,48.9129],[-95.3074,48.9135],[-95.3078,48.9141],[-95.3085,48.9146],[-95.3092,48.9149],[-95.3093,48.9149],[-95.3102,48.9155],[-95.3109,48.9163],[-95.3115,48.9172],[-95.3119,48.9178],[-95.3126,48.919],[-95.3132,48.9198],[-95.3141,48.921],[-95.315,48.9222],[-95.3168,48.9245],[-95.3195,48.9285],[-95.3208,48.9305],[-95.3209,48.9307],[-95.3222,48.9327],[-95.3228,48.9344],[-95.3223,48.9355],[-95.3225,48.9358],[-95.3229,48.9373],[-95.3231,48.9389],[-95.3228,48.9403],[-95.3225,48.9409],[-95.3219,48.9412],[-95.3189,48.9419],[-95.3181,48.9421],[-95.3168,48.9431],[-95.3154,48.9448],[-95.3148,48.9452],[-95.3141,48.9457],[-95.3131,48.946],[-95.3114,48.9461],[-95.3102,48.9463],[-95.3095,48.9463],[-95.3088,48.9464],[-95.3086,48.9465],[-95.3086,48.9469],[-95.3085,48.947],[-95.3078,48.9466],[-95.3074,48.9465],[-95.3071,48.9466],[-95.3071,48.9469],[-95.3079,48.9474],[-95.3092,48.9477],[-95.3096,48.9478],[-95.3103,48.948],[-95.3104,48.9484],[-95.3103,48.9485],[-95.31,48.9485],[-95.3099,48.9484],[-95.3096,48.9482],[-95.3094,48.9481],[-95.3081,48.948],[-95.3071,48.9477],[-95.3062,48.9472],[-95.3062,48.9472],[-95.3061,48.9469],[-95.3062,48.9463],[-95.3063,48.9462],[-95.3069,48.9456],[-95.3069,48.9455],[-95.3068,48.9454],[-95.3061,48.9454],[-95.3053,48.9459],[-95.305,48.9462],[-95.3046,48.947],[-95.3046,48.9482],[-95.3052,48.9495],[-95.3061,48.9502],[-95.3079,48.9509],[-95.3089,48.9511],[-95.3097,48.951],[-95.3104,48.951],[-95.3108,48.9512],[-95.3115,48.952],[-95.312,48.9524],[-95.3126,48.9524],[-95.3129,48.9523],[-95.3129,48.9521],[-95.3119,48.9507],[-95.3119,48.9502],[-95.3123,48.9502],[-95.3125,48.9503],[-95.3131,48.9503],[-95.3141,48.9508],[-95.3151,48.951],[-95.3154,48.9513],[-95.3177,48.9525],[-95.3181,48.9531],[-95.3182,48.9535],[-95.3177,48.9545],[-95.3175,48.9552],[-95.3179,48.9559],[-95.3188,48.9562],[-95.3191,48.9569],[-95.3202,48.9581],[-95.3206,48.959],[-95.3206,48.9595],[-95.3206,48.9598],[-95.3202,48.9606],[-95.3193,48.9622],[-95.3193,48.964],[-95.3198,48.9643],[-95.3201,48.9648],[-95.3207,48.9669],[-95.3212,48.9672],[-95.3227,48.9685],[-95.3232,48.9692],[-95.3241,48.9703],[-95.3247,48.972],[-95.3248,48.9728],[-95.3249,48.9738],[-95.325,48.9743],[-95.3253,48.976],[-95.3257,48.9784],[-95.3255,48.9789],[-95.3256,48.98],[-95.3257,48.9814],[-95.3253,48.9832],[-95.3245,48.985],[-95.3242,48.9859],[-95.3227,48.9884],[-95.3224,48.9889],[-95.3206,48.9921],[-95.3204,48.9924],[-95.3191,48.9941],[-95.3181,48.995],[-95.3178,48.9958],[-95.3178,48.9961],[-95.3179,48.9961],[-95.3182,48.996],[-95.3187,48.9956],[-95.3191,48.9953],[-95.3197,48.9954],[-95.3201,48.9956],[-95.3206,48.9961],[-95.3204,48.9964],[-95.3202,48.9973],[-95.3204,48.9976],[-95.3224,48.9984],[-95.3231,48.999]]],"type":"Polygon"},"id":"39","properties":{"Area":4608320923.49768,"CTYONLY_":2,"Code":"LOTW","LASTMOD":"1976-07-04T12:00:00Z","Name":"Lake of the Woods","Perimiter":388250.14572},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=1&offset=0&filter=%7B%22op%22%3A%22s_intersects%22%2C%22args%22%3A%5B%7B%22property%22%3A%22geom%22%7D%2C%7B%22bbox%22%3A%5B-90%2C-180%2C-1000%2C90%2C180%2C1000%5D%7D%5D%7D&filter-lang=cql2-json&filter-crs=http%3A%2F%2Fwww.opengis.net%2Fdef%2Fcrs%2FEPSG%2F0%2F4326","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=1&offset=0&filter=%7B%22op%22%3A%22s_intersects%22%2C%22args%22%3A%5B%7B%22property%22%3A%22geom%22%7D%2C%7B%22bbox%22%3A%5B-90%2C-180%2C-1000%2C90%2C180%2C1000%5D%7D%5D%7D&filter-lang=cql2-json&filter-crs=http%3A%2F%2Fwww.opengis.net%2Fdef%2Fcrs%2FEPSG%2F0%2F4326","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=1&offset=1&filter=%7B%22op%22%3A%22s_intersects%22%2C%22args%22%3A%5B%7B%22property%22%3A%22geom%22%7D%2C%7B%22bbox%22%3A%5B-90%2C-180%2C-1000%2C90%2C180%2C1000%5D%7D%5D%7D&filter-lang=cql2-json&filter-crs=http%3A%2F%2Fwww.opengis.net%2Fdef%2Fcrs%2FEPSG%2F0%2F4326","rel":"next","title":"next page","type":"application/geo+json"}],"numberMatched":117,"numberReturned":1,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_json_s_intersects_point.json.txt b/msautotest/api/expected/ogcapi_cql2_json_s_intersects_point.json.txt new file mode 100644 index 0000000000..6f5505354a --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_json_s_intersects_point.json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 1 +OGC-NumberReturned: 1 + +{"features":[{"geometry":{"coordinates":[[[-94.4299,48.7012],[-94.4241,48.7053],[-94.4213,48.7086],[-94.4189,48.7103],[-94.4158,48.711],[-94.4081,48.7106],[-94.406,48.7105],[-94.3889,48.712],[-94.3859,48.7119],[-94.384,48.7119],[-94.3801,48.7111],[-94.3687,48.7065],[-94.3646,48.7059],[-94.3533,48.7042],[-94.3431,48.7035],[-94.3429,48.7035],[-94.3287,48.7045],[-94.3214,48.7067],[-94.3088,48.7103],[-94.2995,48.709],[-94.2911,48.7079],[-94.2829,48.7057],[-94.2781,48.7024],[-94.2745,48.6999],[-94.2694,48.6995],[-94.2644,48.699],[-94.261,48.6966],[-94.258,48.6918],[-94.2565,48.6901],[-94.2529,48.6864],[-94.2521,48.685],[-94.2514,48.6837],[-94.2507,48.6782],[-94.2527,48.6707],[-94.253,48.6693],[-94.2548,48.664],[-94.2546,48.6615],[-94.2509,48.657],[-94.2499,48.6563],[-94.2467,48.6542],[-94.2445,48.6535],[-94.2343,48.6524],[-94.2335,48.6524],[-94.2242,48.6495],[-94.2144,48.6494],[-94.2124,48.6496],[-94.1996,48.651],[-94.1915,48.6506],[-94.1886,48.6504],[-94.1689,48.6483],[-94.1678,48.6482],[-94.1574,48.6458],[-94.1522,48.6455],[-94.1458,48.6458],[-94.1391,48.646],[-94.126,48.6444],[-94.1235,48.6444],[-94.11,48.6443],[-94.1023,48.6455],[-94.0999,48.6459],[-94.0912,48.6437],[-94.0849,48.6441],[-94.0804,48.6442],[-94.0767,48.6442],[-94.0714,48.6459],[-94.0658,48.6462],[-94.0642,48.6438],[-94.0603,48.6431],[-94.0581,48.6434],[-94.0525,48.644],[-94.0432,48.6435],[-94.0393,48.6423],[-94.0364,48.6413],[-94.0356,48.6411],[-94.0295,48.6409],[-94.0153,48.6424],[-94.0069,48.6433],[-94.0007,48.6428],[-93.9931,48.6412],[-93.9897,48.6405],[-93.984,48.6401],[-93.9777,48.6385],[-93.9712,48.6385],[-93.968,48.6385],[-93.9596,48.6372],[-93.953,48.6341],[-93.9497,48.6339],[-93.934,48.6326],[-93.9272,48.6327],[-93.9169,48.6329],[-93.9134,48.6353],[-93.9057,48.6346],[-93.9054,48.6345],[-93.8948,48.6324],[-93.8853,48.6318],[-93.8844,48.6318],[-93.8757,48.6319],[-93.8698,48.6311],[-93.8624,48.631],[-93.848,48.6308],[-93.8443,48.6303],[-93.8404,48.6289],[-93.8393,48.6286],[-93.8365,48.6276],[-93.8334,48.6256],[-93.8292,48.6177],[-93.825,48.6136],[-93.8245,48.613],[-93.8214,48.6092],[-93.8182,48.5994],[-93.8175,48.597],[-93.8172,48.5964],[-93.813,48.588],[-93.8103,48.5846],[-93.8063,48.5796],[-93.8041,48.5703],[-93.8041,48.5702],[-93.8051,48.5644],[-93.808,48.5569],[-93.8088,48.5555],[-93.8119,48.5503],[-93.8102,48.5445],[-93.8109,48.5412],[-93.8109,48.541],[-93.818,48.535],[-93.818,48.5346],[-93.8184,48.5315],[-93.8178,48.5306],[-93.8161,48.5285],[-93.8145,48.5273],[-93.8111,48.5247],[-93.803,48.522],[-93.7964,48.5182],[-93.7933,48.5164],[-93.7879,48.5159],[-93.7745,48.5162],[-93.768,48.5164],[-93.7665,48.5164],[-93.7617,48.5166],[-93.7534,48.5158],[-93.7442,48.5175],[-93.739,48.5185],[-93.731,48.5185],[-93.7225,48.5178],[-93.7206,48.5176],[-93.7108,48.5186],[-93.7061,48.5182],[-93.7006,48.517],[-93.693,48.5152],[-93.6866,48.5154],[-93.6791,48.5167],[-93.6778,48.5169],[-93.6593,48.5165],[-93.657,48.5167],[-93.6473,48.5177],[-93.6433,48.519],[-93.6421,48.5199],[-93.6395,48.5218],[-93.6357,48.5285],[-93.6344,48.5293],[-93.6311,48.5313],[-93.6284,48.5319],[-93.6256,48.5315],[-93.6211,48.5264],[-93.6166,48.5238],[-93.6134,48.5228],[-93.6122,48.5225],[-93.6051,48.5231],[-93.5962,48.5287],[-93.5919,48.5299],[-93.5901,48.5305],[-93.581,48.5271],[-93.5761,48.527],[-93.5701,48.528],[-93.5602,48.5297],[-93.5484,48.5294],[-93.5476,48.5294],[-93.5425,48.53],[-93.5366,48.5319],[-93.5269,48.5341],[-93.5263,48.5341],[-93.5244,48.5343],[-93.5171,48.5348],[-93.5047,48.5399],[-93.501,48.5414],[-93.4952,48.5426],[-93.4854,48.5433],[-93.4833,48.5437],[-93.4673,48.5465],[-93.4655,48.5478],[-93.4625,48.5498],[-93.462,48.5505],[-93.4596,48.5537],[-93.4576,48.5598],[-93.4576,48.5621],[-93.4575,48.5672],[-93.4619,48.5731],[-93.4619,48.5734],[-93.4631,48.5767],[-93.4671,48.5885],[-93.4656,48.59],[-93.4654,48.5915],[-93.4654,48.5917],[-93.4627,48.5927],[-93.46,48.5927],[-93.4547,48.5927],[-93.4398,48.5937],[-93.4385,48.5942],[-93.4347,48.5954],[-93.4298,48.5997],[-93.4226,48.6032],[-93.4193,48.6036],[-93.416,48.605],[-93.4152,48.6053],[-93.415,48.6056],[-93.4144,48.6064],[-93.4056,48.6099],[-93.4034,48.61],[-93.4029,48.6077],[-93.4013,48.6079],[-93.3994,48.6055],[-93.3986,48.6045],[-93.3953,48.6038],[-93.3937,48.6041],[-93.3837,48.606],[-93.3724,48.6059],[-93.3714,48.6059],[-93.3672,48.6082],[-93.3619,48.6141],[-93.355,48.6114],[-93.3526,48.6135],[-93.3533,48.615],[-93.3513,48.62],[-93.3505,48.6219],[-93.3486,48.6265],[-93.3276,48.6302],[-93.3057,48.634],[-93.3048,48.6341],[-93.2838,48.6378],[-93.2634,48.6413],[-93.2546,48.6429],[-93.2422,48.6428],[-93.2193,48.6426],[-93.2075,48.6426],[-93.1975,48.6365],[-93.191,48.6325],[-93.184,48.6282],[-93.1783,48.6231],[-93.1754,48.6232],[-93.1531,48.6244],[-93.1319,48.6256],[-93.1104,48.6267],[-93.0903,48.6278],[-93.0884,48.6278],[-93.0886,48.6163],[-93.0895,48.6016],[-93.0898,48.5872],[-93.09,48.5727],[-93.0902,48.5583],[-93.0902,48.5441],[-93.0903,48.5296],[-93.0905,48.5151],[-93.0905,48.501],[-93.091,48.4884],[-93.0911,48.4867],[-93.0914,48.474],[-93.0915,48.4724],[-93.0918,48.4596],[-93.0919,48.458],[-93.092,48.4449],[-93.092,48.4436],[-93.0922,48.4303],[-93.0922,48.429],[-93.0923,48.4147],[-93.0935,48.4147],[-93.0938,48.4024],[-93.094,48.3879],[-93.094,48.3734],[-93.0945,48.3589],[-93.0948,48.3442],[-93.0948,48.3298],[-93.0953,48.3153],[-93.0952,48.3004],[-93.095,48.2862],[-93.0952,48.2716],[-93.0953,48.2576],[-93.0949,48.2426],[-93.0949,48.2425],[-93.0977,48.2426],[-93.0977,48.2271],[-93.0978,48.2126],[-93.0979,48.1981],[-93.0975,48.1836],[-93.097,48.1692],[-93.097,48.1546],[-93.097,48.1402],[-93.0969,48.1259],[-93.0972,48.1114],[-93.097,48.0969],[-93.0968,48.0823],[-93.0965,48.0679],[-93.0965,48.0678],[-93.0892,48.0679],[-93.0892,48.0509],[-93.089,48.0366],[-93.0886,48.022],[-93.0887,48.0075],[-93.0872,47.9932],[-93.088,47.9787],[-93.0809,47.9786],[-93.0809,47.967],[-93.0808,47.9647],[-93.0808,47.9525],[-93.0808,47.9504],[-93.0809,47.938],[-93.0809,47.9356],[-93.0809,47.9235],[-93.0809,47.9212],[-93.0809,47.9088],[-93.0809,47.9067],[-93.0808,47.8945],[-93.0808,47.8922],[-93.1015,47.8927],[-93.1232,47.893],[-93.1448,47.8928],[-93.1656,47.8931],[-93.1671,47.8932],[-93.1871,47.8931],[-93.1893,47.8931],[-93.2087,47.8933],[-93.2115,47.8934],[-93.2331,47.8937],[-93.2532,47.8936],[-93.2745,47.8938],[-93.2962,47.8939],[-93.3169,47.894],[-93.3392,47.8941],[-93.3603,47.8942],[-93.3809,47.8943],[-93.4024,47.8944],[-93.4235,47.8945],[-93.4442,47.8946],[-93.466,47.895],[-93.4874,47.8956],[-93.4892,47.8957],[-93.4933,47.8958],[-93.5085,47.8962],[-93.5105,47.8963],[-93.5297,47.8967],[-93.5303,47.8967],[-93.532,47.8968],[-93.5517,47.8973],[-93.5532,47.8974],[-93.5729,47.8981],[-93.5747,47.8982],[-93.5962,47.8978],[-93.5966,47.8978],[-93.6179,47.8977],[-93.6187,47.8977],[-93.6388,47.8977],[-93.6395,47.8976],[-93.6604,47.8976],[-93.6612,47.8976],[-93.6817,47.8976],[-93.6826,47.8976],[-93.7031,47.8976],[-93.7038,47.8976],[-93.7249,47.8975],[-93.7248,47.8989],[-93.7466,47.8989],[-93.768,47.8991],[-93.7758,47.8991],[-93.7758,47.899],[-93.776,47.8897],[-93.776,47.8842],[-93.7762,47.8753],[-93.7761,47.8697],[-93.7761,47.8607],[-93.7761,47.8553],[-93.7761,47.8464],[-93.7896,47.8465],[-93.7971,47.8466],[-93.8189,47.8467],[-93.8407,47.8468],[-93.8627,47.8469],[-93.8831,47.8471],[-93.9067,47.8471],[-93.9288,47.8475],[-93.9496,47.8475],[-93.9506,47.8475],[-93.971,47.8475],[-93.9725,47.8475],[-93.9927,47.8475],[-93.9942,47.8475],[-94.0141,47.8476],[-94.0161,47.8476],[-94.0375,47.8477],[-94.0591,47.8474],[-94.0807,47.8471],[-94.1022,47.8471],[-94.1239,47.8466],[-94.1448,47.8463],[-94.1657,47.8461],[-94.1822,47.8461],[-94.1871,47.846],[-94.2037,47.846],[-94.2086,47.846],[-94.2252,47.846],[-94.23,47.8461],[-94.2467,47.8462],[-94.2515,47.8462],[-94.2681,47.8462],[-94.2728,47.8462],[-94.2887,47.8462],[-94.3103,47.8458],[-94.3315,47.846],[-94.3532,47.8464],[-94.3747,47.8462],[-94.3964,47.8461],[-94.4185,47.8459],[-94.4186,47.86],[-94.4184,47.8744],[-94.418,47.8886],[-94.4177,47.9031],[-94.4176,47.9041],[-94.4175,47.9175],[-94.4174,47.9186],[-94.4175,47.9332],[-94.4174,47.9477],[-94.4172,47.9623],[-94.4173,47.9769],[-94.4176,47.9914],[-94.4177,48.006],[-94.4176,48.02],[-94.4236,48.0199],[-94.4241,48.0344],[-94.4246,48.0489],[-94.4247,48.0632],[-94.4234,48.0776],[-94.4231,48.092],[-94.4233,48.1059],[-94.4234,48.1204],[-94.4236,48.1348],[-94.4233,48.1491],[-94.4235,48.1637],[-94.4235,48.1781],[-94.4233,48.1923],[-94.4236,48.2067],[-94.4238,48.2212],[-94.4237,48.2356],[-94.4237,48.2504],[-94.424,48.2649],[-94.4243,48.2791],[-94.4244,48.2938],[-94.4246,48.3081],[-94.4248,48.3227],[-94.425,48.3372],[-94.4253,48.352],[-94.4252,48.3675],[-94.4288,48.3675],[-94.4289,48.3821],[-94.4293,48.3964],[-94.4294,48.411],[-94.4293,48.4254],[-94.4292,48.4399],[-94.4293,48.4543],[-94.4296,48.4688],[-94.4296,48.4832],[-94.4299,48.4977],[-94.4303,48.512],[-94.4303,48.5264],[-94.43,48.5409],[-94.4295,48.5554],[-94.4291,48.5698],[-94.4289,48.5844],[-94.4289,48.5988],[-94.4292,48.6133],[-94.4294,48.6276],[-94.4297,48.642],[-94.43,48.6564],[-94.4301,48.6708],[-94.43,48.6852],[-94.4299,48.6998],[-94.4299,48.7012]]],"type":"Polygon"},"id":"36","properties":{"Area":8167237870.91888,"CTYONLY_":5,"Code":"KOOC","LASTMOD":"1999-12-31T23:59:59Z","Name":"Koochiching","Perimiter":412897.43594},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=1&offset=0&filter=%7B%22op%22%3A%22s_intersects%22%2C%22args%22%3A%5B%7B%22property%22%3A%22geom%22%7D%2C%7B%22type%22%3A%22Point%22%2C%22coordinates%22%3A%5B-94.4297%2C48.642%5D%7D%5D%7D&filter-lang=cql2-json","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=1&offset=0&filter=%7B%22op%22%3A%22s_intersects%22%2C%22args%22%3A%5B%7B%22property%22%3A%22geom%22%7D%2C%7B%22type%22%3A%22Point%22%2C%22coordinates%22%3A%5B-94.4297%2C48.642%5D%7D%5D%7D&filter-lang=cql2-json","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":1,"numberReturned":1,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_json_subtract.json.txt b/msautotest/api/expected/ogcapi_cql2_json_subtract.json.txt new file mode 100644 index 0000000000..9b7930cf96 --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_json_subtract.json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 1 +OGC-NumberReturned: 1 + +{"features":[{"geometry":{"coordinates":[[[-96.4054,49.0001],[-96.4019,49.0001],[-96.3825,49.0001],[-96.3783,49.0001],[-96.3606,49.0001],[-96.3579,49.0001],[-96.3385,49.0001],[-96.3343,49.0001],[-96.3166,49.0001],[-96.3138,49.0001],[-96.2945,49.0001],[-96.2902,49.0001],[-96.2725,49.0001],[-96.2698,49.0001],[-96.2494,49.0001],[-96.2461,49.0001],[-96.2274,49.0001],[-96.2257,49.0001],[-96.2057,49.0001],[-96.2021,49.0001],[-96.1837,49.0],[-96.18,49.0],[-96.1617,49.0],[-96.1579,49.0],[-96.1401,49.0],[-96.1359,49.0],[-96.1176,49.0],[-96.1139,49.0],[-96.0957,49.0],[-96.0919,49.0],[-96.0738,49.0],[-96.07,49.0],[-96.0517,49.0],[-96.048,49.0],[-96.0298,49.0],[-96.026,49.0],[-96.0083,49.0],[-96.0045,49.0],[-95.9868,49.0],[-95.9784,49.0],[-95.9776,49.0],[-95.9755,49.0],[-95.9648,48.9999],[-95.9464,48.9999],[-95.943,48.9999],[-95.9225,48.9999],[-95.9211,48.9999],[-95.899,48.9998],[-95.883,48.9998],[-95.8771,48.9998],[-95.8564,48.9998],[-95.855,48.9998],[-95.8342,48.9998],[-95.8184,48.9997],[-95.8126,48.9997],[-95.7906,48.9997],[-95.7833,48.9997],[-95.7684,48.9997],[-95.7479,48.9996],[-95.7466,48.9996],[-95.7253,48.9996],[-95.7066,48.9996],[-95.7032,48.9996],[-95.681,48.9995],[-95.6654,48.9995],[-95.6596,48.9995],[-95.659,48.9995],[-95.6401,48.9995],[-95.6369,48.9995],[-95.6205,48.9994],[-95.615,48.9994],[-95.5948,48.9994],[-95.585,48.9994],[-95.573,48.9994],[-95.551,48.9993],[-95.5495,48.9993],[-95.5294,48.9993],[-95.5164,48.9993],[-95.5072,48.9993],[-95.4849,48.9992],[-95.4834,48.9992],[-95.4635,48.9992],[-95.4508,48.9992],[-95.4418,48.9992],[-95.4245,48.9991],[-95.4197,48.9991],[-95.3977,48.9991],[-95.3953,48.9991],[-95.3765,48.9991],[-95.3759,48.9991],[-95.3753,48.9991],[-95.3542,48.999],[-95.3513,48.999],[-95.3326,48.999],[-95.3286,48.999],[-95.3231,48.999],[-95.3224,48.9984],[-95.3204,48.9976],[-95.3202,48.9973],[-95.3204,48.9964],[-95.3206,48.9961],[-95.3201,48.9956],[-95.3197,48.9954],[-95.3191,48.9953],[-95.3187,48.9956],[-95.3182,48.996],[-95.3179,48.9961],[-95.3178,48.9961],[-95.3178,48.9958],[-95.3181,48.995],[-95.3191,48.9941],[-95.3204,48.9924],[-95.3206,48.9921],[-95.3224,48.9889],[-95.3227,48.9884],[-95.3242,48.9859],[-95.3245,48.985],[-95.3253,48.9832],[-95.3257,48.9814],[-95.3256,48.98],[-95.3255,48.9789],[-95.3257,48.9784],[-95.3253,48.976],[-95.325,48.9743],[-95.3249,48.9738],[-95.3248,48.9728],[-95.3247,48.972],[-95.3241,48.9703],[-95.3232,48.9692],[-95.3227,48.9685],[-95.3212,48.9672],[-95.3207,48.9669],[-95.3201,48.9648],[-95.3198,48.9643],[-95.3193,48.964],[-95.3193,48.9622],[-95.3202,48.9606],[-95.3206,48.9598],[-95.3206,48.9595],[-95.3206,48.959],[-95.3202,48.9581],[-95.3191,48.9569],[-95.3188,48.9562],[-95.3179,48.9559],[-95.3175,48.9552],[-95.3177,48.9545],[-95.3182,48.9535],[-95.3181,48.9531],[-95.3177,48.9525],[-95.3154,48.9513],[-95.3151,48.951],[-95.3141,48.9508],[-95.3131,48.9503],[-95.3125,48.9503],[-95.3123,48.9502],[-95.3119,48.9502],[-95.3119,48.9507],[-95.3129,48.9521],[-95.3129,48.9523],[-95.3126,48.9524],[-95.312,48.9524],[-95.3115,48.952],[-95.3108,48.9512],[-95.3104,48.951],[-95.3097,48.951],[-95.3089,48.9511],[-95.3079,48.9509],[-95.3061,48.9502],[-95.3052,48.9495],[-95.3046,48.9482],[-95.3046,48.947],[-95.305,48.9462],[-95.3053,48.9459],[-95.3061,48.9454],[-95.3068,48.9454],[-95.3069,48.9455],[-95.3069,48.9456],[-95.3063,48.9462],[-95.3062,48.9463],[-95.3061,48.9469],[-95.3062,48.9472],[-95.3062,48.9472],[-95.3071,48.9477],[-95.3081,48.948],[-95.3094,48.9481],[-95.3096,48.9482],[-95.3099,48.9484],[-95.31,48.9485],[-95.3103,48.9485],[-95.3104,48.9484],[-95.3103,48.948],[-95.3096,48.9478],[-95.3092,48.9477],[-95.3079,48.9474],[-95.3071,48.9469],[-95.3071,48.9466],[-95.3074,48.9465],[-95.3078,48.9466],[-95.3085,48.947],[-95.3086,48.9469],[-95.3086,48.9465],[-95.3088,48.9464],[-95.3095,48.9463],[-95.3102,48.9463],[-95.3114,48.9461],[-95.3131,48.946],[-95.3141,48.9457],[-95.3148,48.9452],[-95.3154,48.9448],[-95.3168,48.9431],[-95.3181,48.9421],[-95.3189,48.9419],[-95.3219,48.9412],[-95.3225,48.9409],[-95.3228,48.9403],[-95.3231,48.9389],[-95.3229,48.9373],[-95.3225,48.9358],[-95.3223,48.9355],[-95.3228,48.9344],[-95.3222,48.9327],[-95.3209,48.9307],[-95.3208,48.9305],[-95.3195,48.9285],[-95.3168,48.9245],[-95.315,48.9222],[-95.3141,48.921],[-95.3132,48.9198],[-95.3126,48.919],[-95.3119,48.9178],[-95.3115,48.9172],[-95.3109,48.9163],[-95.3102,48.9155],[-95.3093,48.9149],[-95.3092,48.9149],[-95.3085,48.9146],[-95.3078,48.9141],[-95.3074,48.9135],[-95.3064,48.9129],[-95.3061,48.9128],[-95.3059,48.9127],[-95.3043,48.9119],[-95.3038,48.9114],[-95.3027,48.91],[-95.3017,48.9093],[-95.2999,48.9086],[-95.2978,48.9083],[-95.2973,48.9081],[-95.2973,48.908],[-95.2973,48.9077],[-95.2976,48.9074],[-95.2977,48.9073],[-95.2978,48.9073],[-95.2978,48.9072],[-95.2978,48.9072],[-95.2979,48.9072],[-95.2979,48.9072],[-95.2979,48.9071],[-95.298,48.9071],[-95.298,48.9071],[-95.298,48.9071],[-95.2981,48.907],[-95.2982,48.9068],[-95.2983,48.9068],[-95.2985,48.9065],[-95.2985,48.9064],[-95.2986,48.9063],[-95.2988,48.906],[-95.2989,48.906],[-95.2991,48.9057],[-95.2992,48.9055],[-95.2994,48.9053],[-95.2996,48.9051],[-95.2997,48.905],[-95.2999,48.9048],[-95.2999,48.9048],[-95.2999,48.9048],[-95.3,48.9047],[-95.3,48.9047],[-95.3001,48.9047],[-95.3001,48.9046],[-95.3002,48.9045],[-95.3005,48.904],[-95.2993,48.9035],[-95.2983,48.9028],[-95.298,48.9027],[-95.2976,48.9026],[-95.2967,48.9027],[-95.2949,48.9028],[-95.2941,48.9027],[-95.2937,48.9023],[-95.2935,48.902],[-95.2927,48.9019],[-95.2914,48.9019],[-95.2909,48.9017],[-95.2908,48.9016],[-95.2907,48.9014],[-95.2906,48.9011],[-95.2911,48.9008],[-95.2911,48.9006],[-95.2901,48.9003],[-95.2896,48.9],[-95.289,48.8994],[-95.2882,48.8981],[-95.2879,48.8979],[-95.2872,48.8977],[-95.287,48.8976],[-95.2865,48.8975],[-95.2861,48.8976],[-95.2853,48.8977],[-95.2839,48.8975],[-95.2813,48.8967],[-95.2803,48.8965],[-95.2796,48.8962],[-95.279,48.8957],[-95.2782,48.8956],[-95.2773,48.8957],[-95.277,48.8958],[-95.2765,48.8962],[-95.2763,48.8963],[-95.2759,48.8962],[-95.2755,48.8959],[-95.2749,48.8956],[-95.2748,48.8951],[-95.2753,48.8943],[-95.2751,48.8938],[-95.2745,48.8931],[-95.2724,48.8921],[-95.2713,48.8915],[-95.268,48.8905],[-95.2677,48.8903],[-95.2674,48.89],[-95.2666,48.8894],[-95.2654,48.8888],[-95.265,48.8886],[-95.2646,48.8885],[-95.2639,48.8883],[-95.2635,48.888],[-95.2627,48.8877],[-95.2585,48.8867],[-95.2585,48.8867],[-95.257,48.8858],[-95.256,48.885],[-95.2548,48.8845],[-95.2517,48.8839],[-95.2507,48.8836],[-95.2502,48.8835],[-95.2496,48.8834],[-95.2485,48.8832],[-95.248,48.8836],[-95.2472,48.8835],[-95.2458,48.8829],[-95.2439,48.8823],[-95.2429,48.8822],[-95.2429,48.8822],[-95.2423,48.8821],[-95.2407,48.8821],[-95.2391,48.8819],[-95.2381,48.8817],[-95.2356,48.8815],[-95.2335,48.8814],[-95.231,48.8814],[-95.2287,48.8815],[-95.2265,48.8816],[-95.2252,48.8819],[-95.2212,48.883],[-95.2208,48.8831],[-95.2207,48.8831],[-95.22,48.8831],[-95.2193,48.8832],[-95.2188,48.8835],[-95.217,48.8835],[-95.2159,48.8839],[-95.2151,48.884],[-95.2144,48.8843],[-95.2122,48.8842],[-95.2117,48.8847],[-95.2115,48.8847],[-95.2112,48.8848],[-95.2085,48.8846],[-95.2059,48.8848],[-95.2024,48.8852],[-95.2009,48.8855],[-95.2005,48.8856],[-95.1986,48.8855],[-95.1956,48.8862],[-95.1924,48.8865],[-95.1919,48.8866],[-95.1913,48.8868],[-95.1901,48.887],[-95.1889,48.8873],[-95.1877,48.8874],[-95.1863,48.8877],[-95.1851,48.8882],[-95.1819,48.8888],[-95.1797,48.889],[-95.1791,48.889],[-95.1764,48.8893],[-95.173,48.8897],[-95.1701,48.8902],[-95.1674,48.8907],[-95.1648,48.8913],[-95.1641,48.8917],[-95.1618,48.892],[-95.1602,48.892],[-95.1579,48.8919],[-95.1564,48.8919],[-95.1555,48.892],[-95.1528,48.8921],[-95.1508,48.8922],[-95.1483,48.8923],[-95.1469,48.8927],[-95.1459,48.8929],[-95.1438,48.8934],[-95.1436,48.8937],[-95.1404,48.8943],[-95.1381,48.8949],[-95.1355,48.8959],[-95.1351,48.8963],[-95.1348,48.8963],[-95.1343,48.8963],[-95.1337,48.8969],[-95.1322,48.8973],[-95.1312,48.8975],[-95.1252,48.8998],[-95.1239,48.9001],[-95.1233,48.9004],[-95.1228,48.9006],[-95.1214,48.9013],[-95.121,48.9016],[-95.1205,48.9017],[-95.1204,48.9019],[-95.1182,48.9029],[-95.1163,48.9037],[-95.1151,48.9046],[-95.1144,48.9052],[-95.114,48.9061],[-95.1141,48.9064],[-95.1137,48.9069],[-95.1132,48.9071],[-95.113,48.9072],[-95.1126,48.9073],[-95.1107,48.9082],[-95.1096,48.9089],[-95.108,48.9099],[-95.1056,48.9113],[-95.1042,48.9121],[-95.1032,48.9127],[-95.102,48.9132],[-95.1008,48.9142],[-95.0981,48.9159],[-95.098,48.916],[-95.0975,48.9164],[-95.0971,48.9172],[-95.097,48.9176],[-95.0961,48.9181],[-95.0946,48.9191],[-95.0944,48.9193],[-95.0927,48.9204],[-95.0919,48.9207],[-95.0914,48.9208],[-95.0914,48.916],[-95.0912,48.9014],[-95.0911,48.8869],[-95.0908,48.8724],[-95.0908,48.858],[-95.0907,48.8436],[-95.0908,48.8291],[-95.0909,48.8147],[-95.0903,48.8],[-95.0903,48.7855],[-95.0903,48.7711],[-95.0901,48.7566],[-95.0901,48.7421],[-95.0899,48.7277],[-95.0898,48.713],[-95.1046,48.7129],[-95.1104,48.7129],[-95.1119,48.7129],[-95.1259,48.7129],[-95.1297,48.713],[-95.1333,48.713],[-95.1477,48.7129],[-95.1554,48.7129],[-95.1697,48.7129],[-95.1773,48.713],[-95.1917,48.713],[-95.1991,48.713],[-95.2112,48.713],[-95.2206,48.713],[-95.2331,48.713],[-95.2427,48.713],[-95.255,48.713],[-95.2645,48.713],[-95.2656,48.713],[-95.2767,48.713],[-95.2866,48.713],[-95.299,48.713],[-95.3051,48.713],[-95.3084,48.713],[-95.3205,48.713],[-95.3302,48.713],[-95.3425,48.7131],[-95.3425,48.6995],[-95.3424,48.6849],[-95.3423,48.6705],[-95.3424,48.6561],[-95.3425,48.6415],[-95.3426,48.6271],[-95.3424,48.6127],[-95.3426,48.5979],[-95.3423,48.5836],[-95.3423,48.5691],[-95.3424,48.5548],[-95.3425,48.5402],[-95.3628,48.5404],[-95.364,48.5403],[-95.3844,48.5402],[-95.386,48.5402],[-95.4061,48.5402],[-95.4078,48.5402],[-95.4279,48.54],[-95.4297,48.5399],[-95.4494,48.5399],[-95.4513,48.5399],[-95.4712,48.5396],[-95.4726,48.5396],[-95.493,48.5392],[-95.495,48.5392],[-95.5143,48.539],[-95.5163,48.539],[-95.5365,48.5389],[-95.5383,48.5389],[-95.558,48.5388],[-95.5603,48.5388],[-95.5801,48.5387],[-95.5821,48.5387],[-95.6023,48.5389],[-95.6232,48.5391],[-95.6447,48.5393],[-95.6666,48.5394],[-95.6886,48.5395],[-95.7102,48.5395],[-95.7322,48.54],[-95.7539,48.5404],[-95.7758,48.5406],[-95.7976,48.5405],[-95.8192,48.5404],[-95.8411,48.5406],[-95.8621,48.5414],[-95.8829,48.5419],[-95.8851,48.542],[-95.8986,48.5421],[-95.9046,48.5422],[-95.9064,48.5422],[-95.9269,48.5421],[-95.9486,48.5425],[-95.9498,48.5425],[-95.9704,48.543],[-95.9936,48.5435],[-96.0157,48.5437],[-96.0374,48.5438],[-96.0592,48.5437],[-96.0812,48.5436],[-96.1026,48.5438],[-96.1264,48.5439],[-96.1486,48.5442],[-96.1702,48.5445],[-96.1921,48.5446],[-96.2141,48.5449],[-96.2358,48.5452],[-96.2576,48.545],[-96.2794,48.5449],[-96.301,48.5448],[-96.3231,48.5446],[-96.3448,48.5444],[-96.3667,48.5443],[-96.3882,48.5442],[-96.3879,48.5588],[-96.3882,48.5733],[-96.3884,48.5877],[-96.3891,48.6024],[-96.389,48.6165],[-96.388,48.6313],[-96.3879,48.6454],[-96.3877,48.6599],[-96.3871,48.6741],[-96.3874,48.6887],[-96.3866,48.703],[-96.3873,48.7172],[-96.388,48.7172],[-96.4049,48.7172],[-96.4048,48.7318],[-96.4048,48.7465],[-96.4047,48.7607],[-96.4045,48.7758],[-96.4042,48.7903],[-96.4042,48.8048],[-96.4042,48.8198],[-96.4043,48.8343],[-96.4045,48.8491],[-96.4047,48.8635],[-96.405,48.878],[-96.405,48.8926],[-96.4053,48.9068],[-96.4053,48.9081],[-96.4053,48.9137],[-96.4054,48.9214],[-96.4054,48.9225],[-96.4053,48.936],[-96.4053,48.9371],[-96.4053,48.9504],[-96.4053,48.9515],[-96.4053,48.9648],[-96.4053,48.9658],[-96.4053,48.9705],[-96.4054,48.9793],[-96.4054,48.9803],[-96.4054,48.994],[-96.4054,48.9947],[-96.4054,49.0001]]],"type":"Polygon"},"id":"68","properties":{"Area":4347098503.12714,"CTYONLY_":4,"Code":"ROSE","LASTMOD":"2001-04-12T09:32:44Z","Name":"Roseau","Perimiter":302590.75293},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&filter=%7B%22op%22%3A%22%3D%22%2C%22args%22%3A%5B%7B%22property%22%3A%22CTYONLY_%22%7D%2C%7B%22op%22%3A%22-%22%2C%22args%22%3A%5B5%2C1%5D%7D%5D%7D&filter-lang=cql2-json","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&filter=%7B%22op%22%3A%22%3D%22%2C%22args%22%3A%5B%7B%22property%22%3A%22CTYONLY_%22%7D%2C%7B%22op%22%3A%22-%22%2C%22args%22%3A%5B5%2C1%5D%7D%5D%7D&filter-lang=cql2-json","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":1,"numberReturned":1,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_json_syntax_error.json.txt b/msautotest/api/expected/ogcapi_cql2_json_syntax_error.json.txt new file mode 100644 index 0000000000..7e5c67cc77 --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_json_syntax_error.json.txt @@ -0,0 +1,4 @@ +Content-Type: application/json +Status: 400 + +{"code":"InvalidParameterValue","description":"Cannot parse filter: Exception while parsing CQL2 JSON: [json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - invalid literal; last read: 'i'"} diff --git a/msautotest/api/expected/ogcapi_cql2_json_timestamp.json.txt b/msautotest/api/expected/ogcapi_cql2_json_timestamp.json.txt new file mode 100644 index 0000000000..e1db2f5434 --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_json_timestamp.json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 8 +OGC-NumberReturned: 8 + +{"features":[{"geometry":{"coordinates":[[[-91.0311,48.1889],[-91.0319,48.1804],[-91.0316,48.1652],[-91.0311,48.1507],[-91.0313,48.1362],[-91.0315,48.1222],[-91.0315,48.1075],[-91.0316,48.093],[-91.0316,48.0788],[-91.0314,48.0641],[-91.0243,48.0639],[-91.0236,48.0474],[-91.0243,48.0329],[-91.0241,48.0183],[-91.0245,48.0039],[-91.0246,47.9895],[-91.0252,47.9755],[-91.0256,47.9611],[-91.026,47.9465],[-91.0265,47.932],[-91.0265,47.9175],[-91.0266,47.9029],[-91.0266,47.8883],[-91.0207,47.8882],[-91.0212,47.8758],[-91.0213,47.875],[-91.0212,47.8616],[-91.0212,47.8605],[-91.0212,47.847],[-91.0212,47.846],[-91.0212,47.8327],[-91.0212,47.8316],[-91.0215,47.8182],[-91.0215,47.8171],[-91.0218,47.804],[-91.0218,47.8033],[-91.0217,47.7896],[-91.0217,47.7886],[-91.0217,47.7749],[-91.0217,47.7739],[-91.0216,47.7604],[-91.0216,47.7594],[-91.0214,47.7457],[-91.0217,47.7313],[-91.0217,47.7302],[-91.0216,47.7158],[-91.0222,47.7028],[-91.0225,47.6883],[-91.0226,47.6739],[-91.0222,47.6598],[-91.0222,47.6453],[-91.022,47.6308],[-91.0222,47.6163],[-91.0228,47.6019],[-91.0225,47.5874],[-91.0225,47.5729],[-91.0225,47.5587],[-91.0226,47.5443],[-91.0225,47.5299],[-91.0226,47.5154],[-91.0228,47.5009],[-91.0234,47.4865],[-91.0231,47.4725],[-91.023,47.4651],[-91.023,47.4651],[-91.0237,47.4647],[-91.0237,47.4646],[-91.0237,47.4646],[-91.0238,47.4645],[-91.0239,47.4644],[-91.024,47.4643],[-91.0241,47.4643],[-91.0242,47.4643],[-91.0243,47.4642],[-91.0244,47.4641],[-91.0246,47.464],[-91.0247,47.4639],[-91.0248,47.4638],[-91.0249,47.4637],[-91.0251,47.4636],[-91.0253,47.4635],[-91.0254,47.4634],[-91.0256,47.4633],[-91.0257,47.4632],[-91.0259,47.4631],[-91.0261,47.463],[-91.0262,47.4629],[-91.0264,47.4628],[-91.0265,47.4627],[-91.0267,47.4627],[-91.0267,47.4626],[-91.0268,47.4627],[-91.027,47.4626],[-91.0271,47.4626],[-91.0271,47.4626],[-91.0272,47.4624],[-91.0275,47.4623],[-91.0276,47.4623],[-91.0278,47.4623],[-91.028,47.4622],[-91.0281,47.4622],[-91.0281,47.4621],[-91.0281,47.462],[-91.0283,47.462],[-91.0284,47.462],[-91.0285,47.462],[-91.0285,47.462],[-91.0286,47.4619],[-91.0287,47.4617],[-91.0287,47.4616],[-91.0289,47.4616],[-91.029,47.4615],[-91.0292,47.4613],[-91.0292,47.4613],[-91.0292,47.4612],[-91.0293,47.4611],[-91.0293,47.461],[-91.0295,47.461],[-91.0296,47.4609],[-91.0296,47.4608],[-91.0297,47.4607],[-91.0298,47.4607],[-91.0299,47.4606],[-91.0302,47.4605],[-91.0303,47.4606],[-91.0303,47.4607],[-91.0304,47.4607],[-91.0306,47.4605],[-91.0308,47.4604],[-91.031,47.4601],[-91.0312,47.4599],[-91.0314,47.4598],[-91.0315,47.4597],[-91.0317,47.4596],[-91.0319,47.4595],[-91.032,47.4593],[-91.0321,47.4592],[-91.0322,47.4591],[-91.0323,47.459],[-91.0325,47.4589],[-91.0329,47.4587],[-91.033,47.4586],[-91.033,47.4585],[-91.033,47.4585],[-91.033,47.4584],[-91.033,47.4583],[-91.0333,47.4582],[-91.0337,47.458],[-91.034,47.4579],[-91.034,47.4578],[-91.0342,47.4578],[-91.0346,47.4577],[-91.035,47.4576],[-91.0355,47.4575],[-91.0359,47.4574],[-91.0362,47.4573],[-91.0364,47.4572],[-91.0367,47.4572],[-91.0369,47.4572],[-91.037,47.4572],[-91.0373,47.4571],[-91.0377,47.457],[-91.0381,47.4568],[-91.0385,47.4567],[-91.0389,47.4567],[-91.0394,47.4567],[-91.0395,47.4568],[-91.0398,47.4569],[-91.0405,47.457],[-91.0413,47.4572],[-91.0424,47.4573],[-91.0433,47.4573],[-91.0439,47.4574],[-91.044,47.4575],[-91.0441,47.4575],[-91.0443,47.4575],[-91.0448,47.4574],[-91.0453,47.4572],[-91.0458,47.457],[-91.0462,47.4567],[-91.0468,47.4564],[-91.0473,47.4559],[-91.0476,47.4557],[-91.0479,47.4555],[-91.048,47.4553],[-91.0486,47.4547],[-91.0489,47.4542],[-91.0492,47.4537],[-91.0496,47.4531],[-91.0496,47.4527],[-91.0496,47.4524],[-91.0495,47.4523],[-91.0493,47.452],[-91.0491,47.4519],[-91.049,47.4519],[-91.049,47.4519],[-91.049,47.4519],[-91.049,47.452],[-91.049,47.4521],[-91.0489,47.452],[-91.0488,47.4521],[-91.0487,47.452],[-91.0487,47.452],[-91.0486,47.452],[-91.0486,47.4518],[-91.0487,47.4517],[-91.0489,47.4516],[-91.0491,47.4514],[-91.0492,47.4513],[-91.0493,47.4513],[-91.0494,47.4514],[-91.0496,47.4514],[-91.05,47.4513],[-91.0507,47.4512],[-91.0512,47.4511],[-91.0517,47.4508],[-91.0518,47.4507],[-91.0518,47.4505],[-91.0518,47.4503],[-91.0519,47.4501],[-91.0521,47.45],[-91.0522,47.4499],[-91.0524,47.4498],[-91.0524,47.4497],[-91.0524,47.4496],[-91.0523,47.4495],[-91.0523,47.4494],[-91.0524,47.4493],[-91.0525,47.4493],[-91.0526,47.4493],[-91.0528,47.4494],[-91.0528,47.4494],[-91.053,47.4492],[-91.0533,47.4489],[-91.0535,47.4487],[-91.0536,47.4486],[-91.0538,47.4485],[-91.0538,47.4484],[-91.0538,47.4483],[-91.0537,47.4482],[-91.0538,47.448],[-91.054,47.4479],[-91.0543,47.4478],[-91.0544,47.4476],[-91.0546,47.4475],[-91.0548,47.4473],[-91.0551,47.4473],[-91.0554,47.4471],[-91.0557,47.4469],[-91.056,47.4466],[-91.0562,47.4464],[-91.0565,47.4462],[-91.0568,47.446],[-91.0571,47.4459],[-91.0573,47.4458],[-91.0574,47.4457],[-91.0577,47.4456],[-91.058,47.4455],[-91.0581,47.4454],[-91.0582,47.4452],[-91.0585,47.445],[-91.0587,47.4447],[-91.0589,47.4444],[-91.0591,47.4442],[-91.0595,47.4439],[-91.0598,47.4437],[-91.0598,47.4437],[-91.0599,47.4438],[-91.0601,47.4439],[-91.0604,47.4439],[-91.0608,47.4438],[-91.0611,47.4437],[-91.0613,47.4436],[-91.0615,47.4435],[-91.0617,47.4435],[-91.062,47.4435],[-91.0622,47.4435],[-91.0626,47.4433],[-91.0626,47.4433],[-91.0629,47.4432],[-91.0632,47.4431],[-91.0634,47.4431],[-91.0636,47.4432],[-91.0639,47.4433],[-91.0641,47.4433],[-91.0641,47.4433],[-91.0642,47.4431],[-91.0643,47.443],[-91.0643,47.4428],[-91.0641,47.4427],[-91.064,47.4427],[-91.0638,47.4428],[-91.0637,47.4427],[-91.0637,47.4427],[-91.0637,47.4424],[-91.0639,47.4423],[-91.0639,47.4422],[-91.0638,47.4419],[-91.0638,47.4418],[-91.0639,47.4417],[-91.0641,47.4417],[-91.0643,47.4417],[-91.0649,47.4416],[-91.0651,47.4415],[-91.0651,47.4413],[-91.0651,47.441],[-91.065,47.4409],[-91.0648,47.4407],[-91.0649,47.4406],[-91.065,47.4405],[-91.0652,47.4404],[-91.0653,47.4403],[-91.0653,47.4403],[-91.0655,47.4402],[-91.0656,47.4402],[-91.0656,47.4399],[-91.0657,47.4397],[-91.0661,47.4394],[-91.0662,47.4394],[-91.0664,47.4393],[-91.0665,47.4392],[-91.0664,47.4391],[-91.0663,47.4391],[-91.0662,47.439],[-91.0663,47.4389],[-91.0665,47.4389],[-91.0667,47.4387],[-91.0668,47.4386],[-91.067,47.4384],[-91.0671,47.4384],[-91.0671,47.4385],[-91.0671,47.4386],[-91.067,47.4387],[-91.0671,47.4388],[-91.0673,47.4388],[-91.0676,47.4388],[-91.0678,47.4386],[-91.0679,47.4385],[-91.0682,47.4384],[-91.0684,47.4383],[-91.0686,47.4381],[-91.0689,47.4378],[-91.0689,47.4374],[-91.0689,47.4373],[-91.0686,47.4373],[-91.0685,47.4373],[-91.0684,47.4372],[-91.0684,47.4371],[-91.0685,47.4369],[-91.0687,47.4368],[-91.069,47.4367],[-91.0694,47.4364],[-91.0696,47.4361],[-91.0698,47.436],[-91.07,47.4359],[-91.0701,47.4358],[-91.0704,47.4355],[-91.0706,47.4351],[-91.0706,47.435],[-91.0707,47.4347],[-91.0707,47.4345],[-91.0708,47.4343],[-91.0708,47.4341],[-91.0707,47.4339],[-91.0707,47.4338],[-91.0708,47.4337],[-91.071,47.4335],[-91.071,47.4334],[-91.0712,47.4332],[-91.0714,47.4331],[-91.0716,47.4331],[-91.0718,47.4332],[-91.0718,47.4332],[-91.0719,47.4333],[-91.0721,47.4333],[-91.0723,47.4333],[-91.0725,47.4332],[-91.0727,47.4332],[-91.0729,47.433],[-91.0729,47.433],[-91.0728,47.4329],[-91.0727,47.4328],[-91.0727,47.4327],[-91.0727,47.4325],[-91.0729,47.4323],[-91.0732,47.4322],[-91.0735,47.4321],[-91.0738,47.4319],[-91.0741,47.4317],[-91.0744,47.4315],[-91.0746,47.4313],[-91.0748,47.4311],[-91.0748,47.4309],[-91.0748,47.4307],[-91.0747,47.4306],[-91.0746,47.4305],[-91.0744,47.4305],[-91.0742,47.4305],[-91.0742,47.4304],[-91.0743,47.4303],[-91.0744,47.4301],[-91.0746,47.4299],[-91.0747,47.4298],[-91.0747,47.4298],[-91.0747,47.4297],[-91.0746,47.4296],[-91.0745,47.4295],[-91.0746,47.4294],[-91.0747,47.4294],[-91.0748,47.4294],[-91.0749,47.4294],[-91.0751,47.4294],[-91.0752,47.4293],[-91.0753,47.4292],[-91.0756,47.4291],[-91.0757,47.4291],[-91.0759,47.4292],[-91.0762,47.4292],[-91.0766,47.4291],[-91.0773,47.429],[-91.0779,47.4288],[-91.0784,47.4286],[-91.0787,47.4284],[-91.079,47.4283],[-91.0793,47.428],[-91.0797,47.4278],[-91.0801,47.4275],[-91.0806,47.4272],[-91.081,47.4269],[-91.0814,47.4266],[-91.0818,47.4263],[-91.0823,47.4261],[-91.0826,47.4258],[-91.083,47.4255],[-91.0834,47.4253],[-91.0837,47.4251],[-91.0841,47.4248],[-91.0843,47.4245],[-91.0845,47.4243],[-91.0847,47.4241],[-91.085,47.4241],[-91.0852,47.4241],[-91.0854,47.424],[-91.0855,47.424],[-91.0857,47.4238],[-91.086,47.4236],[-91.0862,47.4235],[-91.0863,47.4235],[-91.0864,47.4234],[-91.0867,47.4233],[-91.0869,47.4233],[-91.0871,47.4233],[-91.0872,47.4231],[-91.0873,47.4229],[-91.0874,47.4227],[-91.0875,47.4226],[-91.0876,47.4225],[-91.0879,47.4223],[-91.0882,47.4222],[-91.0883,47.4222],[-91.0884,47.4222],[-91.0887,47.4221],[-91.0888,47.4221],[-91.0889,47.422],[-91.089,47.4219],[-91.0889,47.4218],[-91.0888,47.4217],[-91.0887,47.4217],[-91.0886,47.4216],[-91.0886,47.4215],[-91.0887,47.4213],[-91.089,47.4211],[-91.0895,47.4208],[-91.0896,47.4207],[-91.0898,47.4207],[-91.0899,47.4206],[-91.0901,47.4206],[-91.0903,47.4206],[-91.0903,47.4205],[-91.0904,47.4203],[-91.0906,47.4201],[-91.0907,47.4199],[-91.0908,47.4196],[-91.0909,47.4193],[-91.091,47.4191],[-91.0911,47.4189],[-91.0913,47.4186],[-91.0915,47.4184],[-91.0918,47.4182],[-91.0921,47.4179],[-91.0923,47.4176],[-91.0925,47.4174],[-91.0929,47.4172],[-91.0935,47.4167],[-91.0939,47.4164],[-91.0944,47.4161],[-91.0947,47.4158],[-91.095,47.4156],[-91.0952,47.4153],[-91.0952,47.4153],[-91.0954,47.415],[-91.0956,47.4147],[-91.0957,47.4145],[-91.096,47.4143],[-91.0963,47.414],[-91.0967,47.4139],[-91.0971,47.4139],[-91.0974,47.414],[-91.0975,47.414],[-91.0977,47.4142],[-91.098,47.4144],[-91.0982,47.4145],[-91.0984,47.4146],[-91.0985,47.4147],[-91.0988,47.4146],[-91.0992,47.4145],[-91.0994,47.4145],[-91.0997,47.4143],[-91.0999,47.4142],[-91.1002,47.414],[-91.1006,47.4138],[-91.1007,47.4137],[-91.101,47.4134],[-91.1012,47.4132],[-91.1015,47.413],[-91.1019,47.4127],[-91.1023,47.4125],[-91.1027,47.4123],[-91.1032,47.4122],[-91.1036,47.4122],[-91.104,47.4121],[-91.1044,47.4121],[-91.1053,47.4121],[-91.1057,47.4121],[-91.106,47.412],[-91.1063,47.4119],[-91.1066,47.4117],[-91.1069,47.4115],[-91.1071,47.4112],[-91.1075,47.411],[-91.1076,47.411],[-91.1078,47.4108],[-91.1082,47.4107],[-91.1087,47.4105],[-91.1091,47.4103],[-91.1095,47.41],[-91.1099,47.4098],[-91.1103,47.4095],[-91.1107,47.4093],[-91.1113,47.409],[-91.1118,47.4087],[-91.1123,47.4084],[-91.1125,47.4083],[-91.1127,47.4081],[-91.1129,47.4079],[-91.1132,47.4077],[-91.1135,47.4074],[-91.1138,47.4071],[-91.114,47.4069],[-91.1144,47.4066],[-91.1149,47.4063],[-91.1154,47.406],[-91.1157,47.4058],[-91.116,47.4057],[-91.1163,47.4055],[-91.1165,47.4055],[-91.1168,47.4056],[-91.1171,47.4055],[-91.1174,47.4054],[-91.1178,47.4053],[-91.1181,47.4052],[-91.1185,47.405],[-91.1189,47.4048],[-91.1193,47.4046],[-91.1196,47.4046],[-91.12,47.4046],[-91.1202,47.4046],[-91.1204,47.4044],[-91.1207,47.4043],[-91.1209,47.4042],[-91.121,47.404],[-91.1211,47.4039],[-91.1214,47.4037],[-91.1218,47.4035],[-91.1221,47.4034],[-91.1225,47.4033],[-91.1228,47.4031],[-91.123,47.4029],[-91.1233,47.4028],[-91.1234,47.4026],[-91.1236,47.4025],[-91.1237,47.4024],[-91.124,47.4023],[-91.1242,47.4021],[-91.1244,47.4019],[-91.1247,47.4017],[-91.1249,47.4015],[-91.1251,47.4013],[-91.1254,47.401],[-91.1255,47.4009],[-91.1258,47.4007],[-91.1259,47.4006],[-91.126,47.4006],[-91.1262,47.4006],[-91.1263,47.4006],[-91.1264,47.4006],[-91.1266,47.4005],[-91.1267,47.4004],[-91.1267,47.4002],[-91.1268,47.4002],[-91.1271,47.4001],[-91.1275,47.4],[-91.1279,47.3997],[-91.1281,47.3996],[-91.1282,47.3996],[-91.1282,47.3995],[-91.1283,47.3994],[-91.1284,47.3994],[-91.1284,47.399],[-91.1285,47.3988],[-91.1285,47.3988],[-91.1287,47.3988],[-91.1288,47.3988],[-91.1289,47.3987],[-91.129,47.3984],[-91.1291,47.3983],[-91.1291,47.3982],[-91.1287,47.3979],[-91.1281,47.3977],[-91.128,47.3976],[-91.128,47.3976],[-91.128,47.3974],[-91.1281,47.3973],[-91.1281,47.3973],[-91.1282,47.3974],[-91.1282,47.3974],[-91.1283,47.3974],[-91.1283,47.3974],[-91.1284,47.3973],[-91.1286,47.397],[-91.1287,47.3969],[-91.1289,47.3967],[-91.1292,47.3965],[-91.1293,47.3964],[-91.1293,47.3964],[-91.1294,47.3962],[-91.1296,47.3959],[-91.1297,47.3957],[-91.1298,47.3956],[-91.1299,47.3956],[-91.1301,47.3956],[-91.1303,47.3957],[-91.1304,47.3956],[-91.1304,47.3953],[-91.1303,47.3949],[-91.1305,47.3948],[-91.1306,47.3947],[-91.1308,47.394],[-91.1308,47.3939],[-91.1306,47.3938],[-91.1305,47.3938],[-91.1303,47.3937],[-91.1303,47.3937],[-91.1303,47.3936],[-91.1304,47.3936],[-91.1305,47.3936],[-91.1308,47.3937],[-91.1309,47.3937],[-91.131,47.3936],[-91.1312,47.3935],[-91.1313,47.3934],[-91.1313,47.3934],[-91.1316,47.3934],[-91.1316,47.3934],[-91.1317,47.3934],[-91.1317,47.3934],[-91.1317,47.3935],[-91.1316,47.3935],[-91.1318,47.3936],[-91.1319,47.3938],[-91.1319,47.3938],[-91.1322,47.3939],[-91.1326,47.3939],[-91.1327,47.3939],[-91.1329,47.3938],[-91.1332,47.3939],[-91.1334,47.3938],[-91.1338,47.3936],[-91.1343,47.3933],[-91.1345,47.3932],[-91.1348,47.3931],[-91.1352,47.3928],[-91.1353,47.3927],[-91.1354,47.3926],[-91.1358,47.3926],[-91.1361,47.3924],[-91.1362,47.3923],[-91.1363,47.3922],[-91.1363,47.392],[-91.1361,47.3918],[-91.1362,47.3917],[-91.1363,47.3916],[-91.1367,47.3914],[-91.1371,47.3914],[-91.1375,47.3913],[-91.1378,47.3911],[-91.1381,47.391],[-91.1384,47.3909],[-91.1385,47.3907],[-91.1385,47.3906],[-91.1381,47.3902],[-91.1381,47.3901],[-91.1382,47.3899],[-91.1382,47.3898],[-91.1381,47.3897],[-91.1379,47.3895],[-91.1378,47.3894],[-91.1378,47.3894],[-91.1378,47.3894],[-91.1383,47.3893],[-91.1384,47.3892],[-91.1384,47.3891],[-91.1384,47.389],[-91.1384,47.389],[-91.1384,47.389],[-91.1385,47.389],[-91.1386,47.3891],[-91.1388,47.3891],[-91.1391,47.389],[-91.1398,47.389],[-91.1399,47.389],[-91.1403,47.3888],[-91.1407,47.3888],[-91.1409,47.3887],[-91.1412,47.3886],[-91.1414,47.3884],[-91.1416,47.3883],[-91.1416,47.388],[-91.1416,47.3879],[-91.1417,47.3879],[-91.1419,47.3879],[-91.1419,47.3879],[-91.142,47.388],[-91.142,47.388],[-91.1421,47.3879],[-91.1423,47.3878],[-91.1424,47.3878],[-91.1424,47.3876],[-91.1426,47.3875],[-91.1426,47.3874],[-91.1426,47.3874],[-91.1425,47.3873],[-91.1424,47.3872],[-91.1423,47.3871],[-91.1422,47.3868],[-91.1422,47.3865],[-91.1422,47.3865],[-91.1422,47.3864],[-91.1426,47.3859],[-91.1427,47.3857],[-91.1427,47.3854],[-91.1427,47.3854],[-91.1428,47.3853],[-91.143,47.3852],[-91.1433,47.3849],[-91.1435,47.3847],[-91.1437,47.3844],[-91.1438,47.3843],[-91.1438,47.3843],[-91.144,47.3843],[-91.1441,47.3842],[-91.1441,47.3841],[-91.1442,47.3839],[-91.1443,47.3837],[-91.1445,47.3835],[-91.1451,47.3831],[-91.1453,47.383],[-91.1456,47.3829],[-91.1458,47.3828],[-91.1461,47.3825],[-91.1463,47.3822],[-91.1466,47.3819],[-91.1466,47.3818],[-91.1466,47.3817],[-91.1466,47.3817],[-91.1466,47.3817],[-91.1466,47.3816],[-91.1468,47.3815],[-91.1469,47.3815],[-91.1473,47.3815],[-91.1474,47.3815],[-91.1475,47.3814],[-91.1477,47.3812],[-91.148,47.3812],[-91.1481,47.3811],[-91.1481,47.3811],[-91.1481,47.381],[-91.148,47.3809],[-91.1481,47.3807],[-91.1482,47.3806],[-91.1487,47.3806],[-91.1488,47.3806],[-91.15,47.3798],[-91.15,47.3798],[-91.15,47.3798],[-91.1504,47.3796],[-91.1507,47.3795],[-91.1508,47.3795],[-91.1508,47.3795],[-91.1509,47.3795],[-91.1514,47.3796],[-91.1518,47.3797],[-91.1524,47.3798],[-91.1529,47.38],[-91.1533,47.38],[-91.1535,47.3801],[-91.1537,47.3802],[-91.1541,47.3802],[-91.1546,47.3802],[-91.1551,47.3801],[-91.1552,47.3801],[-91.1556,47.3799],[-91.1558,47.3798],[-91.156,47.3796],[-91.1564,47.3792],[-91.1564,47.3791],[-91.1565,47.3789],[-91.1566,47.3788],[-91.1566,47.3784],[-91.1567,47.3783],[-91.1567,47.3783],[-91.1569,47.3783],[-91.157,47.3784],[-91.1571,47.3784],[-91.1572,47.3783],[-91.1574,47.378],[-91.1575,47.378],[-91.1577,47.3777],[-91.1581,47.3769],[-91.1581,47.3769],[-91.1581,47.3769],[-91.1582,47.3765],[-91.1582,47.3757],[-91.1581,47.3756],[-91.1578,47.3755],[-91.1577,47.3754],[-91.1575,47.3754],[-91.1572,47.3755],[-91.1571,47.3755],[-91.1571,47.3755],[-91.1571,47.3754],[-91.1571,47.375],[-91.1572,47.3749],[-91.1573,47.3748],[-91.1574,47.3747],[-91.1576,47.3747],[-91.1577,47.3747],[-91.1579,47.3747],[-91.158,47.3746],[-91.1581,47.3746],[-91.1583,47.3746],[-91.1585,47.3746],[-91.1588,47.3747],[-91.1592,47.3747],[-91.1595,47.3747],[-91.1596,47.3748],[-91.16,47.3748],[-91.1603,47.3747],[-91.1606,47.3747],[-91.1608,47.3746],[-91.161,47.3745],[-91.1612,47.3744],[-91.1613,47.3742],[-91.1614,47.3741],[-91.1614,47.374],[-91.1614,47.3738],[-91.1613,47.3737],[-91.1613,47.3737],[-91.1612,47.3736],[-91.1612,47.3736],[-91.1613,47.3735],[-91.1614,47.3736],[-91.1614,47.3736],[-91.1616,47.3736],[-91.1617,47.3736],[-91.1618,47.3736],[-91.162,47.3735],[-91.1622,47.3734],[-91.1624,47.3732],[-91.1626,47.3731],[-91.1628,47.373],[-91.1629,47.373],[-91.163,47.3729],[-91.1631,47.3728],[-91.163,47.3726],[-91.163,47.3724],[-91.163,47.3723],[-91.1629,47.3722],[-91.1628,47.3721],[-91.1627,47.372],[-91.1626,47.3719],[-91.1626,47.3718],[-91.1627,47.3717],[-91.1627,47.3717],[-91.1628,47.3716],[-91.1629,47.3715],[-91.163,47.3714],[-91.1631,47.3715],[-91.1632,47.3716],[-91.1634,47.3717],[-91.1634,47.3717],[-91.1636,47.3717],[-91.1637,47.3718],[-91.1639,47.3718],[-91.1641,47.3718],[-91.1642,47.3717],[-91.1642,47.3717],[-91.1643,47.3715],[-91.1645,47.3713],[-91.1646,47.3712],[-91.1648,47.371],[-91.1649,47.3709],[-91.165,47.3708],[-91.1649,47.3708],[-91.1648,47.3707],[-91.1647,47.3707],[-91.1645,47.3706],[-91.1644,47.3705],[-91.1645,47.3704],[-91.1645,47.3703],[-91.1644,47.3702],[-91.1643,47.3702],[-91.1642,47.3701],[-91.1642,47.37],[-91.1642,47.37],[-91.1643,47.3699],[-91.1644,47.3698],[-91.1645,47.3698],[-91.1646,47.3696],[-91.1647,47.3696],[-91.1647,47.3695],[-91.1647,47.3694],[-91.1647,47.3693],[-91.1649,47.3693],[-91.1651,47.3692],[-91.1653,47.3691],[-91.1654,47.3691],[-91.1655,47.369],[-91.1655,47.3688],[-91.1655,47.3687],[-91.1655,47.3686],[-91.1655,47.3685],[-91.1657,47.3684],[-91.1659,47.3683],[-91.1661,47.3683],[-91.1662,47.3682],[-91.1662,47.3682],[-91.1662,47.3681],[-91.1662,47.3681],[-91.1661,47.368],[-91.1662,47.3679],[-91.1662,47.3679],[-91.1663,47.3679],[-91.1665,47.3678],[-91.1665,47.3678],[-91.1664,47.3677],[-91.1663,47.3677],[-91.1663,47.3677],[-91.1663,47.3676],[-91.1663,47.3676],[-91.1664,47.3675],[-91.1665,47.3675],[-91.1665,47.3675],[-91.1667,47.3675],[-91.1668,47.3675],[-91.1668,47.3674],[-91.1669,47.3673],[-91.167,47.3673],[-91.1672,47.3672],[-91.1673,47.3672],[-91.1674,47.3672],[-91.1675,47.3671],[-91.1675,47.3671],[-91.1676,47.367],[-91.1679,47.367],[-91.168,47.367],[-91.1682,47.367],[-91.1685,47.367],[-91.1688,47.3669],[-91.1692,47.3668],[-91.1694,47.3667],[-91.1697,47.3665],[-91.1701,47.3662],[-91.1703,47.3659],[-91.1705,47.3656],[-91.1706,47.3654],[-91.1707,47.3652],[-91.1706,47.3651],[-91.1705,47.365],[-91.1704,47.3649],[-91.1703,47.3646],[-91.1704,47.3646],[-91.1706,47.3645],[-91.1707,47.3644],[-91.1706,47.3643],[-91.1707,47.3641],[-91.1707,47.364],[-91.1707,47.3639],[-91.1706,47.3638],[-91.1705,47.3636],[-91.1706,47.3636],[-91.1707,47.3636],[-91.1708,47.3636],[-91.1708,47.3635],[-91.1707,47.3634],[-91.1706,47.3633],[-91.1705,47.3633],[-91.1706,47.3632],[-91.1707,47.3631],[-91.1708,47.363],[-91.1709,47.3629],[-91.171,47.3628],[-91.171,47.3627],[-91.1711,47.3626],[-91.1713,47.3626],[-91.1715,47.3626],[-91.1717,47.3625],[-91.1719,47.3624],[-91.172,47.3623],[-91.1723,47.362],[-91.1724,47.362],[-91.1728,47.3619],[-91.173,47.362],[-91.1733,47.362],[-91.1735,47.3619],[-91.1737,47.3618],[-91.1737,47.3616],[-91.1737,47.3615],[-91.1736,47.3614],[-91.1735,47.3613],[-91.1734,47.3613],[-91.1733,47.3612],[-91.1734,47.3612],[-91.1735,47.3612],[-91.1736,47.3611],[-91.1735,47.3609],[-91.1735,47.3608],[-91.1735,47.3607],[-91.1736,47.3607],[-91.1738,47.3607],[-91.174,47.3607],[-91.1742,47.3606],[-91.1743,47.3605],[-91.1744,47.3604],[-91.1743,47.3603],[-91.1741,47.3602],[-91.1739,47.3602],[-91.1737,47.3602],[-91.1734,47.3602],[-91.1733,47.3601],[-91.1732,47.3601],[-91.1732,47.3601],[-91.1733,47.3601],[-91.1734,47.36],[-91.1736,47.36],[-91.1737,47.36],[-91.1737,47.3599],[-91.1737,47.3598],[-91.1739,47.3598],[-91.1741,47.3599],[-91.1743,47.3599],[-91.1746,47.3598],[-91.1747,47.3597],[-91.1746,47.3596],[-91.1746,47.3595],[-91.1747,47.3595],[-91.1748,47.3594],[-91.1747,47.3593],[-91.1747,47.3593],[-91.1746,47.3592],[-91.1747,47.3592],[-91.1748,47.3592],[-91.175,47.3592],[-91.1752,47.3592],[-91.1753,47.3592],[-91.1754,47.3592],[-91.1755,47.3592],[-91.1757,47.359],[-91.1758,47.3589],[-91.1759,47.3587],[-91.176,47.3584],[-91.176,47.3582],[-91.176,47.3581],[-91.176,47.358],[-91.1759,47.358],[-91.1759,47.3579],[-91.1758,47.3578],[-91.1758,47.3576],[-91.1758,47.3575],[-91.1758,47.3574],[-91.1757,47.3573],[-91.1755,47.3573],[-91.1754,47.3573],[-91.1752,47.3571],[-91.1751,47.357],[-91.175,47.3568],[-91.175,47.3567],[-91.175,47.3565],[-91.1751,47.3564],[-91.1754,47.3564],[-91.1756,47.3563],[-91.1758,47.3563],[-91.176,47.3563],[-91.1761,47.3562],[-91.1762,47.3561],[-91.1762,47.356],[-91.176,47.3559],[-91.1759,47.356],[-91.1758,47.356],[-91.1757,47.3559],[-91.1758,47.3558],[-91.1761,47.3557],[-91.1764,47.3555],[-91.1764,47.3555],[-91.1766,47.3554],[-91.1767,47.3554],[-91.1768,47.3555],[-91.1767,47.3556],[-91.1767,47.3557],[-91.1767,47.3558],[-91.1768,47.3559],[-91.1769,47.3558],[-91.177,47.3558],[-91.1771,47.3558],[-91.1773,47.3558],[-91.1775,47.3557],[-91.1777,47.3556],[-91.1779,47.3553],[-91.178,47.3551],[-91.1781,47.3548],[-91.1781,47.3545],[-91.178,47.3543],[-91.1779,47.3541],[-91.1779,47.354],[-91.1779,47.354],[-91.1779,47.3539],[-91.1779,47.3539],[-91.1779,47.3539],[-91.1778,47.3538],[-91.1777,47.3538],[-91.1777,47.3537],[-91.1778,47.3537],[-91.1778,47.3536],[-91.1778,47.3535],[-91.1778,47.3534],[-91.178,47.3534],[-91.1781,47.3533],[-91.1781,47.3531],[-91.1782,47.3529],[-91.1783,47.3528],[-91.1786,47.3527],[-91.1787,47.3526],[-91.1787,47.3524],[-91.1788,47.3522],[-91.1788,47.352],[-91.1787,47.3519],[-91.1786,47.3517],[-91.1785,47.3516],[-91.1784,47.3514],[-91.1783,47.3512],[-91.1782,47.351],[-91.1781,47.3509],[-91.1781,47.3507],[-91.178,47.3507],[-91.1783,47.3507],[-91.1786,47.3509],[-91.1791,47.351],[-91.1793,47.3511],[-91.1794,47.3511],[-91.1795,47.351],[-91.1795,47.3509],[-91.1797,47.3509],[-91.1799,47.3509],[-91.18,47.3509],[-91.1801,47.3509],[-91.1801,47.3508],[-91.1799,47.3507],[-91.1798,47.3506],[-91.1797,47.3505],[-91.1797,47.3504],[-91.1797,47.3503],[-91.1798,47.3504],[-91.18,47.3505],[-91.1801,47.3505],[-91.1802,47.3505],[-91.1803,47.3504],[-91.1804,47.3502],[-91.1805,47.35],[-91.1806,47.3498],[-91.1806,47.3497],[-91.1808,47.3498],[-91.181,47.3499],[-91.1811,47.35],[-91.1812,47.35],[-91.1813,47.3497],[-91.1814,47.3494],[-91.1814,47.3493],[-91.1813,47.3493],[-91.1812,47.3493],[-91.1812,47.3492],[-91.1812,47.349],[-91.1811,47.3487],[-91.1811,47.3485],[-91.181,47.3483],[-91.1808,47.3482],[-91.1807,47.348],[-91.1807,47.3479],[-91.1807,47.3478],[-91.1806,47.3477],[-91.1807,47.3476],[-91.1808,47.3475],[-91.1809,47.3475],[-91.1811,47.3476],[-91.1815,47.3477],[-91.1819,47.3478],[-91.1822,47.3479],[-91.1825,47.348],[-91.1828,47.348],[-91.1832,47.3479],[-91.1834,47.3479],[-91.1835,47.3478],[-91.1836,47.3478],[-91.1838,47.3478],[-91.184,47.3477],[-91.1843,47.3477],[-91.1845,47.3477],[-91.1847,47.3477],[-91.1848,47.3476],[-91.1849,47.3475],[-91.185,47.3474],[-91.1852,47.3473],[-91.1853,47.3471],[-91.1854,47.3469],[-91.1853,47.3468],[-91.1853,47.3467],[-91.1853,47.3465],[-91.1854,47.3462],[-91.1852,47.3459],[-91.1851,47.3457],[-91.1849,47.3454],[-91.1848,47.3451],[-91.1845,47.3448],[-91.1844,47.3447],[-91.1844,47.3445],[-91.1844,47.3443],[-91.1842,47.3441],[-91.184,47.344],[-91.184,47.3439],[-91.1839,47.3437],[-91.184,47.3436],[-91.1843,47.3436],[-91.1845,47.3435],[-91.1848,47.3435],[-91.1849,47.3434],[-91.185,47.3434],[-91.1851,47.3434],[-91.1851,47.3433],[-91.1851,47.3433],[-91.1848,47.3432],[-91.1844,47.3432],[-91.1842,47.3431],[-91.1842,47.343],[-91.1843,47.3428],[-91.1844,47.3426],[-91.1844,47.3425],[-91.1844,47.3424],[-91.1845,47.3422],[-91.1845,47.342],[-91.1845,47.3418],[-91.1846,47.3417],[-91.1848,47.3415],[-91.1851,47.3414],[-91.1852,47.3413],[-91.1853,47.3412],[-91.1855,47.3411],[-91.1856,47.3409],[-91.1856,47.3408],[-91.1856,47.3406],[-91.1856,47.3405],[-91.1856,47.3404],[-91.1855,47.3403],[-91.1853,47.3403],[-91.1851,47.3404],[-91.185,47.3404],[-91.1849,47.3403],[-91.185,47.3402],[-91.185,47.3401],[-91.1848,47.34],[-91.1845,47.34],[-91.1843,47.34],[-91.1842,47.3399],[-91.1842,47.3398],[-91.1843,47.3397],[-91.1843,47.3397],[-91.1843,47.3396],[-91.1843,47.3395],[-91.1844,47.3395],[-91.1846,47.3395],[-91.1848,47.3394],[-91.185,47.3393],[-91.1854,47.3393],[-91.1857,47.3393],[-91.186,47.3394],[-91.1863,47.3395],[-91.1867,47.3395],[-91.1871,47.3396],[-91.1874,47.3397],[-91.1879,47.3399],[-91.1882,47.34],[-91.1885,47.3402],[-91.1887,47.3402],[-91.1892,47.3401],[-91.1896,47.3399],[-91.19,47.3397],[-91.1904,47.3396],[-91.1906,47.3396],[-91.1905,47.3394],[-91.1906,47.3393],[-91.1907,47.3393],[-91.1908,47.3393],[-91.1909,47.3393],[-91.191,47.3393],[-91.1912,47.3393],[-91.1912,47.3393],[-91.1913,47.3391],[-91.1918,47.3389],[-91.1919,47.3388],[-91.1918,47.3387],[-91.1918,47.3386],[-91.1918,47.3385],[-91.1918,47.3384],[-91.192,47.3385],[-91.1921,47.3385],[-91.1922,47.3386],[-91.1924,47.3386],[-91.1926,47.3386],[-91.1927,47.3385],[-91.1928,47.3383],[-91.1929,47.3382],[-91.1928,47.338],[-91.1926,47.3378],[-91.1926,47.3377],[-91.1926,47.3375],[-91.1927,47.3375],[-91.1928,47.3375],[-91.193,47.3376],[-91.1932,47.3376],[-91.1934,47.3377],[-91.1937,47.3379],[-91.1938,47.338],[-91.1942,47.3381],[-91.1945,47.3381],[-91.1949,47.338],[-91.1953,47.3379],[-91.1957,47.3378],[-91.196,47.3376],[-91.1962,47.3374],[-91.1964,47.3372],[-91.1965,47.337],[-91.1967,47.3368],[-91.1968,47.3367],[-91.1969,47.3366],[-91.1969,47.3365],[-91.1972,47.3364],[-91.1973,47.3363],[-91.1974,47.3363],[-91.1975,47.3363],[-91.1974,47.3362],[-91.1975,47.3361],[-91.1973,47.3361],[-91.1972,47.3361],[-91.1972,47.3359],[-91.1973,47.3356],[-91.1973,47.3355],[-91.1973,47.3354],[-91.1973,47.3353],[-91.1973,47.3352],[-91.1974,47.335],[-91.1975,47.3348],[-91.1975,47.3348],[-91.1976,47.3348],[-91.1978,47.3348],[-91.1979,47.335],[-91.1981,47.335],[-91.1983,47.3349],[-91.1985,47.3347],[-91.1987,47.3347],[-91.199,47.3347],[-91.1991,47.3346],[-91.1992,47.3346],[-91.1993,47.3345],[-91.1995,47.3345],[-91.1997,47.3344],[-91.2,47.3342],[-91.2002,47.334],[-91.2003,47.3338],[-91.2003,47.3335],[-91.2004,47.3333],[-91.2006,47.3331],[-91.2007,47.3329],[-91.2008,47.3328],[-91.2009,47.3328],[-91.201,47.3329],[-91.2011,47.3329],[-91.2013,47.3329],[-91.2017,47.3328],[-91.202,47.3326],[-91.2022,47.3324],[-91.2026,47.3322],[-91.2029,47.3322],[-91.2029,47.3323],[-91.203,47.3323],[-91.2031,47.3323],[-91.2032,47.3322],[-91.2033,47.3321],[-91.2034,47.3321],[-91.2034,47.3321],[-91.2034,47.3322],[-91.2035,47.3322],[-91.2036,47.3322],[-91.2037,47.3322],[-91.2036,47.3321],[-91.2036,47.3321],[-91.2036,47.332],[-91.2036,47.3318],[-91.2037,47.3317],[-91.2037,47.3316],[-91.2035,47.3315],[-91.2035,47.3313],[-91.2037,47.3312],[-91.2039,47.3311],[-91.204,47.331],[-91.204,47.3309],[-91.2039,47.3308],[-91.2038,47.3308],[-91.2039,47.3307],[-91.2042,47.3307],[-91.2045,47.3306],[-91.2047,47.3306],[-91.205,47.3306],[-91.2051,47.3306],[-91.2052,47.3306],[-91.2053,47.3306],[-91.2054,47.3306],[-91.2054,47.3306],[-91.2055,47.3305],[-91.2057,47.3303],[-91.2058,47.3302],[-91.206,47.3301],[-91.2061,47.3301],[-91.2062,47.33],[-91.2064,47.3298],[-91.2064,47.3297],[-91.2064,47.3296],[-91.2064,47.3295],[-91.2064,47.3294],[-91.2063,47.3291],[-91.2062,47.3289],[-91.2062,47.3289],[-91.2062,47.3287],[-91.2061,47.3287],[-91.206,47.3287],[-91.2058,47.3288],[-91.2058,47.3285],[-91.2059,47.3283],[-91.2059,47.3282],[-91.206,47.328],[-91.2059,47.3278],[-91.2059,47.3277],[-91.2061,47.3275],[-91.2063,47.3273],[-91.2064,47.3272],[-91.2066,47.3272],[-91.2067,47.327],[-91.2068,47.3268],[-91.2068,47.3266],[-91.2068,47.3264],[-91.2068,47.3262],[-91.207,47.326],[-91.2072,47.3258],[-91.2074,47.3257],[-91.2075,47.3256],[-91.2077,47.3254],[-91.2079,47.3253],[-91.208,47.3252],[-91.2081,47.3251],[-91.2082,47.325],[-91.2083,47.3248],[-91.2083,47.3246],[-91.2082,47.3245],[-91.2081,47.3242],[-91.208,47.324],[-91.2079,47.3239],[-91.2079,47.3239],[-91.2079,47.3237],[-91.208,47.3235],[-91.208,47.3233],[-91.2079,47.3232],[-91.2081,47.323],[-91.2084,47.3228],[-91.2086,47.3227],[-91.2088,47.3226],[-91.209,47.3226],[-91.2092,47.3225],[-91.2094,47.3224],[-91.2096,47.3223],[-91.2097,47.3222],[-91.2097,47.322],[-91.2098,47.3218],[-91.2098,47.3216],[-91.2097,47.3214],[-91.2098,47.3211],[-91.2098,47.3209],[-91.21,47.3208],[-91.2102,47.3208],[-91.2103,47.3206],[-91.2103,47.3204],[-91.2102,47.3202],[-91.2104,47.32],[-91.2108,47.3198],[-91.2112,47.3195],[-91.2116,47.3193],[-91.212,47.319],[-91.2122,47.3188],[-91.2123,47.3187],[-91.2125,47.3186],[-91.2127,47.3184],[-91.2129,47.3182],[-91.2133,47.318],[-91.2137,47.3179],[-91.2139,47.3179],[-91.2139,47.3178],[-91.2138,47.3177],[-91.2137,47.3176],[-91.2136,47.3176],[-91.2136,47.3175],[-91.2137,47.3174],[-91.2138,47.3174],[-91.214,47.3174],[-91.2143,47.3175],[-91.2144,47.3174],[-91.2146,47.3173],[-91.2147,47.3172],[-91.2149,47.317],[-91.215,47.317],[-91.215,47.3171],[-91.215,47.3172],[-91.215,47.3173],[-91.2152,47.3175],[-91.2156,47.3175],[-91.216,47.3175],[-91.2164,47.3174],[-91.2168,47.3173],[-91.2172,47.3174],[-91.2176,47.3175],[-91.2178,47.3176],[-91.2181,47.3178],[-91.2185,47.3179],[-91.2185,47.3179],[-91.2188,47.318],[-91.219,47.3181],[-91.2192,47.3181],[-91.2194,47.3181],[-91.2196,47.3181],[-91.22,47.318],[-91.2205,47.3179],[-91.2209,47.3176],[-91.2214,47.3172],[-91.2217,47.3169],[-91.2219,47.3165],[-91.222,47.3163],[-91.2221,47.3161],[-91.2223,47.3159],[-91.2225,47.3158],[-91.2226,47.3158],[-91.2226,47.3158],[-91.2227,47.3158],[-91.2229,47.3157],[-91.223,47.3156],[-91.223,47.3155],[-91.223,47.3154],[-91.2228,47.3154],[-91.2227,47.3153],[-91.2226,47.3152],[-91.2227,47.315],[-91.2227,47.315],[-91.223,47.3146],[-91.2233,47.3143],[-91.2234,47.3141],[-91.2235,47.3139],[-91.2235,47.3138],[-91.2237,47.3137],[-91.2238,47.3136],[-91.2239,47.3135],[-91.2239,47.3133],[-91.224,47.3132],[-91.2241,47.313],[-91.2241,47.3129],[-91.2242,47.3128],[-91.2242,47.3128],[-91.2242,47.3128],[-91.2243,47.3126],[-91.2243,47.3125],[-91.2242,47.3123],[-91.2241,47.3123],[-91.2241,47.3122],[-91.2242,47.3121],[-91.2244,47.3122],[-91.2245,47.3123],[-91.2247,47.3123],[-91.225,47.3123],[-91.2252,47.3122],[-91.2253,47.3121],[-91.2257,47.3122],[-91.2261,47.3124],[-91.2265,47.3125],[-91.2268,47.3126],[-91.2274,47.3126],[-91.2278,47.3124],[-91.2283,47.3122],[-91.2285,47.312],[-91.2287,47.3119],[-91.2288,47.3117],[-91.2289,47.3114],[-91.2291,47.3111],[-91.2293,47.3107],[-91.2295,47.3103],[-91.2297,47.3101],[-91.2297,47.3099],[-91.2297,47.3096],[-91.2297,47.3093],[-91.2297,47.3093],[-91.2298,47.3092],[-91.2297,47.3091],[-91.2296,47.309],[-91.2296,47.3088],[-91.2297,47.3085],[-91.2297,47.3083],[-91.2297,47.3083],[-91.2296,47.3082],[-91.2294,47.3082],[-91.2293,47.3082],[-91.2291,47.3082],[-91.229,47.3082],[-91.2289,47.3082],[-91.229,47.308],[-91.2292,47.3078],[-91.2293,47.3077],[-91.2294,47.3075],[-91.2293,47.3074],[-91.2292,47.3073],[-91.2292,47.3073],[-91.2292,47.3072],[-91.2294,47.3072],[-91.2296,47.3071],[-91.2297,47.307],[-91.2298,47.3069],[-91.2299,47.3067],[-91.2301,47.3065],[-91.2304,47.3063],[-91.2307,47.3062],[-91.2309,47.3062],[-91.2312,47.3061],[-91.2314,47.3061],[-91.2316,47.3061],[-91.2317,47.3062],[-91.232,47.3062],[-91.2323,47.3063],[-91.2325,47.3063],[-91.2327,47.3064],[-91.2329,47.3064],[-91.2332,47.3064],[-91.2334,47.3065],[-91.2336,47.3065],[-91.2337,47.3064],[-91.2339,47.3062],[-91.234,47.306],[-91.2341,47.3059],[-91.2343,47.3059],[-91.2344,47.3059],[-91.2345,47.3059],[-91.2345,47.3058],[-91.2346,47.3058],[-91.2347,47.3058],[-91.2349,47.3058],[-91.2352,47.3058],[-91.2355,47.3058],[-91.2356,47.3057],[-91.2358,47.3056],[-91.2359,47.3056],[-91.2359,47.3055],[-91.2359,47.3054],[-91.236,47.3053],[-91.2361,47.3053],[-91.2362,47.3053],[-91.2365,47.3054],[-91.2366,47.3054],[-91.2368,47.3054],[-91.2369,47.3054],[-91.2371,47.3053],[-91.2372,47.3053],[-91.2374,47.3053],[-91.2376,47.3052],[-91.2377,47.3051],[-91.2378,47.305],[-91.238,47.3049],[-91.2381,47.3049],[-91.2383,47.3049],[-91.2385,47.3048],[-91.2386,47.3048],[-91.2386,47.3049],[-91.2387,47.305],[-91.2388,47.305],[-91.239,47.3049],[-91.239,47.3049],[-91.2391,47.3048],[-91.2393,47.3047],[-91.2395,47.3046],[-91.2395,47.3045],[-91.2395,47.3044],[-91.2396,47.3042],[-91.2395,47.304],[-91.2395,47.3039],[-91.2395,47.3036],[-91.2393,47.3034],[-91.2392,47.3032],[-91.2391,47.303],[-91.2392,47.3028],[-91.2392,47.3027],[-91.2395,47.3025],[-91.2398,47.3024],[-91.2402,47.3024],[-91.2402,47.3024],[-91.2404,47.3023],[-91.2405,47.3022],[-91.2406,47.3021],[-91.2407,47.3019],[-91.2407,47.3018],[-91.2406,47.3016],[-91.2405,47.3014],[-91.2404,47.3014],[-91.2403,47.3013],[-91.2402,47.3012],[-91.2401,47.3011],[-91.2403,47.301],[-91.2404,47.3008],[-91.2406,47.3007],[-91.2407,47.3005],[-91.2408,47.3003],[-91.2408,47.3003],[-91.2409,47.3001],[-91.241,47.2999],[-91.2412,47.2999],[-91.2415,47.2999],[-91.2417,47.2998],[-91.2418,47.2998],[-91.2419,47.2999],[-91.242,47.2999],[-91.2424,47.2998],[-91.2428,47.2997],[-91.2431,47.2996],[-91.2433,47.2994],[-91.2433,47.2993],[-91.2432,47.2992],[-91.2431,47.2991],[-91.243,47.299],[-91.243,47.2987],[-91.2431,47.2986],[-91.2432,47.2985],[-91.2436,47.2984],[-91.2439,47.2983],[-91.244,47.2981],[-91.244,47.298],[-91.2439,47.2978],[-91.244,47.2977],[-91.244,47.2976],[-91.2441,47.2975],[-91.2442,47.2974],[-91.2444,47.2973],[-91.2447,47.2972],[-91.2448,47.2971],[-91.2449,47.2969],[-91.245,47.2967],[-91.2452,47.2965],[-91.2453,47.2964],[-91.2452,47.2963],[-91.2449,47.2962],[-91.2448,47.2962],[-91.2448,47.296],[-91.2449,47.2958],[-91.2452,47.2957],[-91.2455,47.2957],[-91.2458,47.2957],[-91.246,47.2956],[-91.2462,47.2955],[-91.2462,47.2952],[-91.2462,47.295],[-91.2462,47.2948],[-91.2463,47.2948],[-91.2464,47.2948],[-91.2465,47.2948],[-91.2466,47.2948],[-91.2467,47.2947],[-91.2467,47.2946],[-91.2468,47.2945],[-91.2469,47.2944],[-91.247,47.2943],[-91.2472,47.2941],[-91.2473,47.294],[-91.2473,47.2938],[-91.2472,47.2937],[-91.247,47.2934],[-91.2468,47.293],[-91.2468,47.2927],[-91.2468,47.2924],[-91.247,47.2921],[-91.2471,47.2918],[-91.2472,47.2916],[-91.2472,47.2915],[-91.2472,47.2914],[-91.2471,47.2913],[-91.2471,47.2911],[-91.2469,47.2909],[-91.2467,47.2907],[-91.2464,47.2905],[-91.2462,47.2904],[-91.246,47.2904],[-91.2458,47.2904],[-91.2456,47.2905],[-91.2453,47.2904],[-91.2451,47.2903],[-91.2449,47.2902],[-91.2446,47.2901],[-91.2445,47.29],[-91.2444,47.29],[-91.2443,47.2899],[-91.2442,47.2897],[-91.2442,47.2895],[-91.2442,47.2894],[-91.2443,47.2892],[-91.2445,47.289],[-91.2447,47.2888],[-91.2448,47.2887],[-91.245,47.2886],[-91.245,47.2884],[-91.2451,47.2882],[-91.2451,47.288],[-91.2453,47.2877],[-91.2454,47.2876],[-91.2456,47.2873],[-91.2458,47.2872],[-91.246,47.287],[-91.2465,47.2868],[-91.2467,47.2867],[-91.247,47.2865],[-91.2472,47.2864],[-91.2475,47.2863],[-91.2477,47.2861],[-91.2479,47.286],[-91.2481,47.2859],[-91.2483,47.2858],[-91.2484,47.2857],[-91.2484,47.2855],[-91.2484,47.2854],[-91.2484,47.2853],[-91.2484,47.2852],[-91.2486,47.2852],[-91.249,47.2852],[-91.2494,47.2852],[-91.2498,47.2853],[-91.25,47.2854],[-91.2501,47.2854],[-91.2507,47.2853],[-91.2508,47.2853],[-91.2513,47.285],[-91.2514,47.2847],[-91.2514,47.2839],[-91.2513,47.2834],[-91.2505,47.2824],[-91.2506,47.2824],[-91.2508,47.2823],[-91.2518,47.2818],[-91.2519,47.2816],[-91.2522,47.2813],[-91.2524,47.2812],[-91.2525,47.2811],[-91.2527,47.281],[-91.2528,47.281],[-91.2529,47.281],[-91.2535,47.2809],[-91.2546,47.2808],[-91.2557,47.2806],[-91.2565,47.2804],[-91.2567,47.2804],[-91.2572,47.2802],[-91.2577,47.2801],[-91.2578,47.28],[-91.2584,47.28],[-91.2587,47.2799],[-91.2595,47.2793],[-91.2597,47.2792],[-91.2603,47.2789],[-91.2603,47.2789],[-91.2604,47.279],[-91.2602,47.2791],[-91.2598,47.2796],[-91.2596,47.2801],[-91.2596,47.2802],[-91.2592,47.2804],[-91.2588,47.2807],[-91.2584,47.281],[-91.2575,47.2817],[-91.2574,47.2818],[-91.2573,47.282],[-91.2573,47.2824],[-91.2573,47.2825],[-91.2588,47.2856],[-91.2589,47.2857],[-91.2589,47.2857],[-91.2591,47.2857],[-91.2595,47.2853],[-91.2608,47.284],[-91.2615,47.2834],[-91.262,47.2829],[-91.2621,47.2828],[-91.2624,47.2825],[-91.2625,47.2824],[-91.2643,47.2806],[-91.2649,47.2801],[-91.265,47.2801],[-91.2655,47.2801],[-91.268,47.2779],[-91.2683,47.2776],[-91.2685,47.2776],[-91.2696,47.2775],[-91.2699,47.2774],[-91.2701,47.2774],[-91.2706,47.2771],[-91.2709,47.2769],[-91.2709,47.2768],[-91.271,47.2767],[-91.2711,47.2764],[-91.2712,47.2763],[-91.2713,47.2763],[-91.2713,47.2762],[-91.2714,47.2761],[-91.2714,47.2761],[-91.2716,47.2758],[-91.2716,47.2758],[-91.2717,47.2756],[-91.2718,47.2756],[-91.272,47.2756],[-91.2728,47.2755],[-91.273,47.2755],[-91.2731,47.2755],[-91.2733,47.2756],[-91.2735,47.2755],[-91.2736,47.2755],[-91.2737,47.2753],[-91.2737,47.2752],[-91.2737,47.275],[-91.2738,47.2748],[-91.2736,47.2745],[-91.2735,47.2743],[-91.2736,47.2742],[-91.2737,47.274],[-91.274,47.2738],[-91.2741,47.2736],[-91.2742,47.2735],[-91.2743,47.2733],[-91.2743,47.273],[-91.2746,47.2726],[-91.2746,47.2726],[-91.2746,47.2724],[-91.2745,47.2723],[-91.2727,47.2716],[-91.2724,47.2715],[-91.2691,47.2702],[-91.2682,47.2699],[-91.2681,47.2699],[-91.2681,47.2699],[-91.268,47.2699],[-91.2675,47.2699],[-91.2673,47.2699],[-91.2672,47.2698],[-91.2673,47.2697],[-91.2673,47.2697],[-91.2673,47.2696],[-91.2672,47.2694],[-91.2672,47.2692],[-91.2674,47.2689],[-91.2674,47.2689],[-91.2675,47.2688],[-91.2675,47.2688],[-91.2676,47.2687],[-91.2677,47.2687],[-91.2678,47.2689],[-91.2678,47.269],[-91.2676,47.2692],[-91.2676,47.2694],[-91.2676,47.2694],[-91.2682,47.2695],[-91.2684,47.2696],[-91.2685,47.2696],[-91.2685,47.2698],[-91.2685,47.2698],[-91.2692,47.2701],[-91.2693,47.2701],[-91.2723,47.2712],[-91.2725,47.2713],[-91.2744,47.272],[-91.2747,47.2722],[-91.2751,47.2722],[-91.2754,47.2721],[-91.2755,47.272],[-91.2758,47.2719],[-91.276,47.2718],[-91.2761,47.2717],[-91.2762,47.2715],[-91.2762,47.2715],[-91.2762,47.2714],[-91.2761,47.2712],[-91.2762,47.2709],[-91.2762,47.2707],[-91.2762,47.2705],[-91.2761,47.2704],[-91.2756,47.2704],[-91.2754,47.2703],[-91.2753,47.2703],[-91.2753,47.2701],[-91.2755,47.2699],[-91.2756,47.2698],[-91.2759,47.2697],[-91.2759,47.2697],[-91.2759,47.2695],[-91.2757,47.2693],[-91.2757,47.2693],[-91.2755,47.2692],[-91.275,47.2692],[-91.2749,47.2691],[-91.2748,47.2691],[-91.2748,47.269],[-91.275,47.2688],[-91.2754,47.2683],[-91.2757,47.2681],[-91.2757,47.268],[-91.2759,47.2679],[-91.2773,47.2668],[-91.2778,47.2665],[-91.2779,47.2665],[-91.2798,47.2665],[-91.28,47.2666],[-91.2801,47.2666],[-91.2806,47.2669],[-91.2812,47.2671],[-91.2815,47.2671],[-91.282,47.267],[-91.282,47.267],[-91.2823,47.267],[-91.2823,47.267],[-91.2824,47.267],[-91.2833,47.267],[-91.2837,47.2672],[-91.2839,47.2672],[-91.2846,47.2673],[-91.2851,47.2673],[-91.2859,47.2672],[-91.2861,47.2672],[-91.2863,47.2672],[-91.2865,47.2671],[-91.287,47.2669],[-91.2876,47.2665],[-91.2876,47.2665],[-91.2878,47.2664],[-91.2881,47.2662],[-91.2882,47.2661],[-91.2882,47.2661],[-91.2884,47.266],[-91.2885,47.2659],[-91.2888,47.2658],[-91.2894,47.2653],[-91.2896,47.2651],[-91.2898,47.2647],[-91.2899,47.2645],[-91.2902,47.2643],[-91.2905,47.2641],[-91.2914,47.2633],[-91.2915,47.2631],[-91.2915,47.2631],[-91.2915,47.2631],[-91.2915,47.2629],[-91.2916,47.2627],[-91.2916,47.2626],[-91.2919,47.2624],[-91.2921,47.2621],[-91.2923,47.2619],[-91.2928,47.2619],[-91.2929,47.2618],[-91.2932,47.2616],[-91.2933,47.2614],[-91.2934,47.2611],[-91.2934,47.2608],[-91.2934,47.2607],[-91.2933,47.2601],[-91.2932,47.2599],[-91.2932,47.2598],[-91.2927,47.2593],[-91.2926,47.2592],[-91.2923,47.2593],[-91.2921,47.2593],[-91.2917,47.2591],[-91.2916,47.259],[-91.2913,47.259],[-91.291,47.259],[-91.2906,47.2591],[-91.2904,47.2591],[-91.2899,47.2591],[-91.2894,47.259],[-91.2889,47.2588],[-91.2887,47.2585],[-91.2887,47.2582],[-91.2888,47.2581],[-91.2891,47.2581],[-91.2891,47.2581],[-91.2894,47.2583],[-91.2896,47.2583],[-91.2898,47.2583],[-91.29,47.2582],[-91.2901,47.258],[-91.2901,47.258],[-91.2901,47.258],[-91.2899,47.2579],[-91.2898,47.2578],[-91.2896,47.2577],[-91.2895,47.2576],[-91.2896,47.2576],[-91.2897,47.2576],[-91.2906,47.2577],[-91.291,47.2577],[-91.2913,47.2576],[-91.2914,47.2575],[-91.292,47.2572],[-91.2925,47.257],[-91.2925,47.2569],[-91.2926,47.2569],[-91.2928,47.2569],[-91.2928,47.2569],[-91.2929,47.257],[-91.2931,47.2571],[-91.2933,47.2572],[-91.2934,47.2573],[-91.2936,47.2574],[-91.2939,47.2576],[-91.2941,47.2577],[-91.2943,47.2577],[-91.2947,47.2576],[-91.2949,47.2575],[-91.2953,47.2574],[-91.2954,47.2573],[-91.2959,47.2571],[-91.296,47.257],[-91.296,47.257],[-91.2961,47.2569],[-91.2961,47.2568],[-91.296,47.2567],[-91.296,47.2567],[-91.2961,47.2563],[-91.2962,47.2562],[-91.2965,47.2559],[-91.2966,47.2559],[-91.297,47.2559],[-91.2974,47.2559],[-91.2975,47.2559],[-91.2981,47.2559],[-91.2984,47.2559],[-91.2988,47.2559],[-91.2992,47.2558],[-91.2993,47.2558],[-91.2994,47.2557],[-91.2997,47.2553],[-91.3,47.2551],[-91.3,47.2551],[-91.3003,47.2551],[-91.3005,47.2553],[-91.3006,47.2556],[-91.3008,47.2557],[-91.301,47.2558],[-91.301,47.2558],[-91.3013,47.2558],[-91.3014,47.2557],[-91.3014,47.2556],[-91.3015,47.2555],[-91.3022,47.2553],[-91.3025,47.2552],[-91.3026,47.2551],[-91.3026,47.2549],[-91.3025,47.2548],[-91.3024,47.2546],[-91.3024,47.2546],[-91.3026,47.2544],[-91.3028,47.2544],[-91.3035,47.2544],[-91.3036,47.2544],[-91.3037,47.2544],[-91.3039,47.2543],[-91.3043,47.2543],[-91.3045,47.2543],[-91.3049,47.254],[-91.305,47.254],[-91.3055,47.2534],[-91.3058,47.2531],[-91.3059,47.2528],[-91.3061,47.2527],[-91.3062,47.2526],[-91.3062,47.2524],[-91.3061,47.2523],[-91.306,47.252],[-91.306,47.252],[-91.3061,47.2518],[-91.3064,47.2514],[-91.3065,47.2514],[-91.3066,47.2514],[-91.3067,47.2514],[-91.3069,47.2513],[-91.3071,47.2514],[-91.3077,47.2514],[-91.3079,47.2513],[-91.3081,47.2513],[-91.3082,47.2512],[-91.3083,47.2511],[-91.3087,47.2509],[-91.3089,47.2507],[-91.3091,47.2503],[-91.3092,47.2501],[-91.3092,47.25],[-91.3093,47.2499],[-91.3093,47.2498],[-91.3093,47.2495],[-91.3093,47.2494],[-91.3094,47.2493],[-91.3094,47.2491],[-91.3094,47.249],[-91.3095,47.2489],[-91.3096,47.2488],[-91.3102,47.2487],[-91.3105,47.2486],[-91.3106,47.2485],[-91.3107,47.2485],[-91.3107,47.2484],[-91.3106,47.2483],[-91.3107,47.2482],[-91.3109,47.2481],[-91.311,47.2481],[-91.3112,47.2477],[-91.3113,47.2475],[-91.3114,47.2474],[-91.3116,47.2474],[-91.3117,47.2474],[-91.3118,47.2472],[-91.3121,47.247],[-91.3125,47.2468],[-91.3127,47.2467],[-91.3129,47.2467],[-91.3131,47.2467],[-91.3132,47.2467],[-91.3133,47.2466],[-91.3134,47.2466],[-91.3134,47.2466],[-91.3135,47.2467],[-91.3137,47.2467],[-91.3138,47.2467],[-91.3139,47.2467],[-91.314,47.2465],[-91.3139,47.2465],[-91.3138,47.2464],[-91.3139,47.2463],[-91.3139,47.2462],[-91.3139,47.2462],[-91.3139,47.2461],[-91.3138,47.2461],[-91.3121,47.2461],[-91.312,47.2461],[-91.3118,47.2461],[-91.3119,47.246],[-91.312,47.246],[-91.3122,47.246],[-91.3122,47.2459],[-91.3122,47.2459],[-91.3121,47.2458],[-91.3121,47.2457],[-91.3123,47.2457],[-91.3124,47.2457],[-91.3125,47.2457],[-91.3126,47.2458],[-91.3127,47.2458],[-91.3128,47.2457],[-91.3129,47.2457],[-91.3132,47.2457],[-91.3134,47.2457],[-91.3136,47.2457],[-91.3138,47.2458],[-91.3138,47.2458],[-91.3138,47.2458],[-91.314,47.2458],[-91.3141,47.2458],[-91.3142,47.2458],[-91.3142,47.2459],[-91.3143,47.2459],[-91.3144,47.2459],[-91.3145,47.246],[-91.3146,47.246],[-91.3149,47.246],[-91.315,47.246],[-91.3152,47.2461],[-91.3153,47.2461],[-91.3155,47.246],[-91.3156,47.2459],[-91.3157,47.2458],[-91.3158,47.2457],[-91.3159,47.2455],[-91.316,47.2454],[-91.3161,47.2452],[-91.3164,47.245],[-91.317,47.2446],[-91.3171,47.2445],[-91.3172,47.2445],[-91.3173,47.2444],[-91.3173,47.2444],[-91.3172,47.2443],[-91.3173,47.2442],[-91.3174,47.2442],[-91.3174,47.2442],[-91.3176,47.244],[-91.3177,47.2439],[-91.3181,47.2438],[-91.3184,47.2437],[-91.3185,47.2436],[-91.3186,47.2434],[-91.3187,47.2432],[-91.3187,47.2429],[-91.3188,47.2427],[-91.3188,47.2426],[-91.319,47.2424],[-91.3192,47.2423],[-91.3192,47.2421],[-91.3192,47.2421],[-91.3193,47.242],[-91.3193,47.2418],[-91.3194,47.2417],[-91.3196,47.2416],[-91.3197,47.2415],[-91.3196,47.2414],[-91.3196,47.2413],[-91.3196,47.2413],[-91.3198,47.2412],[-91.3199,47.2413],[-91.32,47.2413],[-91.3202,47.2412],[-91.3209,47.2409],[-91.3212,47.2409],[-91.3216,47.2408],[-91.3218,47.2407],[-91.3218,47.2406],[-91.3219,47.2405],[-91.3222,47.2401],[-91.3223,47.24],[-91.3224,47.2399],[-91.3225,47.2397],[-91.3227,47.2396],[-91.3231,47.2396],[-91.3234,47.2396],[-91.3246,47.2394],[-91.3252,47.2393],[-91.3253,47.2393],[-91.3254,47.2392],[-91.3256,47.2391],[-91.3257,47.2389],[-91.3255,47.2383],[-91.3255,47.2381],[-91.3254,47.2379],[-91.3254,47.2378],[-91.3255,47.2376],[-91.3256,47.2375],[-91.3257,47.2374],[-91.3258,47.2371],[-91.3258,47.237],[-91.3257,47.2367],[-91.3258,47.2362],[-91.3258,47.236],[-91.326,47.2359],[-91.3262,47.236],[-91.3264,47.236],[-91.3267,47.2359],[-91.3271,47.2355],[-91.3277,47.2352],[-91.3278,47.2351],[-91.328,47.2351],[-91.3281,47.2351],[-91.3282,47.235],[-91.3284,47.2345],[-91.3285,47.2343],[-91.3287,47.2341],[-91.3286,47.234],[-91.3284,47.2339],[-91.3281,47.2338],[-91.3281,47.2337],[-91.328,47.2336],[-91.3279,47.2336],[-91.3278,47.2335],[-91.3278,47.2334],[-91.3279,47.2333],[-91.3282,47.233],[-91.3282,47.2329],[-91.3283,47.2328],[-91.3283,47.2327],[-91.3282,47.2326],[-91.3282,47.2324],[-91.3283,47.2323],[-91.3284,47.2322],[-91.3285,47.2322],[-91.3286,47.2322],[-91.3287,47.2322],[-91.3288,47.2321],[-91.329,47.232],[-91.3292,47.2319],[-91.3293,47.2319],[-91.3296,47.2318],[-91.3298,47.2318],[-91.3305,47.2315],[-91.3307,47.2314],[-91.3309,47.2314],[-91.3309,47.2313],[-91.3309,47.2312],[-91.331,47.2311],[-91.3311,47.2311],[-91.3313,47.2311],[-91.3313,47.2309],[-91.3314,47.2308],[-91.3317,47.2306],[-91.3339,47.23],[-91.3342,47.23],[-91.3343,47.2299],[-91.3343,47.2298],[-91.3338,47.2296],[-91.3336,47.2295],[-91.3335,47.2293],[-91.3336,47.2292],[-91.3342,47.229],[-91.3344,47.229],[-91.3346,47.229],[-91.3348,47.2291],[-91.335,47.2292],[-91.3352,47.2292],[-91.3363,47.229],[-91.3366,47.2289],[-91.3368,47.2287],[-91.337,47.2287],[-91.3372,47.2287],[-91.3374,47.2288],[-91.3377,47.2287],[-91.3377,47.2286],[-91.3377,47.2285],[-91.3376,47.2284],[-91.3376,47.2283],[-91.3375,47.2282],[-91.3375,47.2281],[-91.3377,47.2281],[-91.3379,47.228],[-91.3379,47.2279],[-91.3379,47.2278],[-91.3378,47.2276],[-91.3378,47.2275],[-91.3377,47.2273],[-91.3376,47.2272],[-91.3376,47.227],[-91.3377,47.2269],[-91.3378,47.2268],[-91.3379,47.2266],[-91.3378,47.2266],[-91.3378,47.2264],[-91.3378,47.2264],[-91.3378,47.2263],[-91.3379,47.2263],[-91.338,47.2264],[-91.3381,47.2264],[-91.3381,47.2265],[-91.3382,47.2264],[-91.3382,47.2263],[-91.3383,47.2262],[-91.3387,47.2261],[-91.3392,47.2261],[-91.3394,47.2261],[-91.3395,47.226],[-91.3396,47.2259],[-91.3396,47.2258],[-91.3396,47.2257],[-91.3396,47.2256],[-91.3398,47.2255],[-91.3406,47.2255],[-91.3408,47.2255],[-91.3409,47.2254],[-91.341,47.2252],[-91.3411,47.2251],[-91.3412,47.225],[-91.3414,47.225],[-91.3416,47.225],[-91.3419,47.2249],[-91.3421,47.2248],[-91.3423,47.2246],[-91.3425,47.2245],[-91.3427,47.2245],[-91.3429,47.2244],[-91.3433,47.2243],[-91.3435,47.2243],[-91.3437,47.2244],[-91.3438,47.2244],[-91.344,47.2245],[-91.3442,47.2245],[-91.3443,47.2243],[-91.3444,47.2242],[-91.3444,47.2241],[-91.3444,47.2239],[-91.3444,47.2237],[-91.3443,47.2236],[-91.3442,47.2235],[-91.3441,47.2233],[-91.344,47.2232],[-91.344,47.223],[-91.344,47.2228],[-91.3441,47.2223],[-91.3443,47.2221],[-91.3444,47.2219],[-91.3449,47.2216],[-91.3451,47.2216],[-91.3453,47.2216],[-91.3454,47.2217],[-91.3455,47.2216],[-91.3456,47.2215],[-91.3457,47.2214],[-91.346,47.2213],[-91.3462,47.2212],[-91.3465,47.2212],[-91.3466,47.2213],[-91.347,47.2213],[-91.3473,47.2214],[-91.3475,47.2214],[-91.3476,47.2214],[-91.3477,47.2213],[-91.3479,47.2211],[-91.3481,47.2207],[-91.3483,47.2206],[-91.3484,47.2205],[-91.3485,47.2203],[-91.3485,47.2202],[-91.3484,47.22],[-91.3484,47.2199],[-91.3485,47.2197],[-91.3486,47.2195],[-91.3487,47.2193],[-91.3489,47.2192],[-91.3499,47.2184],[-91.35,47.2183],[-91.3502,47.2182],[-91.3508,47.2176],[-91.351,47.2175],[-91.3511,47.2174],[-91.3513,47.2173],[-91.3523,47.217],[-91.3525,47.2169],[-91.3525,47.2169],[-91.3526,47.2167],[-91.3527,47.2163],[-91.3527,47.2162],[-91.3528,47.2161],[-91.3529,47.2161],[-91.3529,47.216],[-91.3529,47.2158],[-91.3529,47.2157],[-91.3531,47.2155],[-91.3531,47.2154],[-91.3532,47.2152],[-91.3533,47.2151],[-91.3534,47.2149],[-91.3535,47.2147],[-91.3535,47.2145],[-91.3535,47.2144],[-91.3535,47.2142],[-91.3536,47.214],[-91.3537,47.2138],[-91.3538,47.2137],[-91.3538,47.2136],[-91.3538,47.2132],[-91.3537,47.2131],[-91.3537,47.213],[-91.3537,47.2128],[-91.3536,47.2127],[-91.3535,47.2125],[-91.3534,47.2122],[-91.3532,47.212],[-91.3532,47.2118],[-91.3531,47.2116],[-91.3532,47.2113],[-91.3532,47.2111],[-91.3532,47.211],[-91.3533,47.2107],[-91.3533,47.2107],[-91.3533,47.2105],[-91.3533,47.2104],[-91.3532,47.2103],[-91.3532,47.2102],[-91.3533,47.2102],[-91.3534,47.2103],[-91.3544,47.2106],[-91.3547,47.2106],[-91.3548,47.2106],[-91.355,47.2104],[-91.3551,47.2103],[-91.3553,47.2103],[-91.3555,47.2103],[-91.3556,47.2103],[-91.3556,47.2102],[-91.3555,47.2099],[-91.3555,47.2098],[-91.3555,47.2097],[-91.3555,47.2097],[-91.3556,47.2097],[-91.3557,47.2097],[-91.3558,47.2095],[-91.3559,47.2094],[-91.3559,47.2093],[-91.356,47.2093],[-91.356,47.2092],[-91.3561,47.2091],[-91.3561,47.209],[-91.3562,47.2088],[-91.3562,47.2088],[-91.3562,47.2087],[-91.3561,47.2086],[-91.356,47.2086],[-91.3559,47.2085],[-91.3558,47.2085],[-91.3557,47.2084],[-91.3556,47.2084],[-91.3554,47.2084],[-91.3553,47.2083],[-91.3552,47.2082],[-91.3552,47.2081],[-91.3553,47.2079],[-91.3554,47.2078],[-91.3554,47.2077],[-91.3554,47.2076],[-91.3554,47.2075],[-91.3554,47.2072],[-91.3554,47.2071],[-91.3555,47.207],[-91.3556,47.2069],[-91.3557,47.2069],[-91.3557,47.207],[-91.3558,47.2071],[-91.356,47.207],[-91.3561,47.207],[-91.3563,47.2067],[-91.3566,47.2065],[-91.3567,47.2063],[-91.3568,47.2063],[-91.3569,47.2063],[-91.3572,47.2063],[-91.3574,47.2063],[-91.3575,47.2063],[-91.3576,47.2064],[-91.3577,47.2068],[-91.3578,47.2069],[-91.3579,47.207],[-91.358,47.207],[-91.3584,47.207],[-91.3585,47.207],[-91.3586,47.207],[-91.3587,47.2069],[-91.3588,47.2069],[-91.3593,47.2068],[-91.3595,47.2068],[-91.3596,47.2068],[-91.3598,47.2067],[-91.3599,47.2066],[-91.36,47.2066],[-91.3602,47.2066],[-91.3603,47.2066],[-91.3605,47.2066],[-91.3606,47.2066],[-91.3608,47.2065],[-91.3618,47.2062],[-91.362,47.2062],[-91.3622,47.2062],[-91.3624,47.2062],[-91.3624,47.2062],[-91.3626,47.2061],[-91.3627,47.2061],[-91.3629,47.206],[-91.3631,47.206],[-91.3634,47.2059],[-91.3642,47.2057],[-91.3644,47.2056],[-91.3646,47.2055],[-91.3647,47.2054],[-91.3649,47.2053],[-91.3651,47.2053],[-91.3651,47.2052],[-91.3651,47.2051],[-91.3651,47.205],[-91.3651,47.205],[-91.3649,47.2048],[-91.3649,47.2047],[-91.3649,47.2047],[-91.3649,47.2047],[-91.3649,47.2046],[-91.3649,47.2045],[-91.3649,47.2044],[-91.3648,47.2043],[-91.3648,47.2043],[-91.3648,47.2042],[-91.3649,47.2042],[-91.3652,47.2039],[-91.3653,47.2038],[-91.3654,47.2037],[-91.3655,47.2037],[-91.3655,47.2036],[-91.3654,47.2035],[-91.3653,47.2034],[-91.3653,47.2033],[-91.3654,47.2032],[-91.3654,47.2031],[-91.3653,47.203],[-91.3651,47.2029],[-91.3651,47.2027],[-91.3651,47.2026],[-91.3651,47.2026],[-91.3649,47.2025],[-91.3649,47.2025],[-91.3648,47.2024],[-91.3648,47.202],[-91.3648,47.2019],[-91.3649,47.2019],[-91.365,47.2018],[-91.365,47.2017],[-91.3649,47.2016],[-91.3648,47.2016],[-91.3647,47.2015],[-91.3647,47.2014],[-91.3648,47.2014],[-91.3652,47.2012],[-91.3653,47.2012],[-91.3654,47.2012],[-91.3655,47.2013],[-91.3656,47.2013],[-91.3657,47.2013],[-91.3657,47.2012],[-91.3658,47.2008],[-91.3658,47.2007],[-91.3657,47.2005],[-91.3658,47.2004],[-91.3658,47.2003],[-91.3659,47.2001],[-91.3661,47.2],[-91.3665,47.1999],[-91.3667,47.1998],[-91.3669,47.1998],[-91.3671,47.1998],[-91.3675,47.1998],[-91.3681,47.1999],[-91.3693,47.1999],[-91.3695,47.1999],[-91.3697,47.1998],[-91.3698,47.1997],[-91.3698,47.1996],[-91.37,47.1996],[-91.3702,47.1996],[-91.3704,47.1995],[-91.3706,47.1994],[-91.3707,47.1994],[-91.3708,47.1994],[-91.3709,47.1994],[-91.371,47.1993],[-91.3711,47.1992],[-91.3712,47.1992],[-91.3723,47.1991],[-91.3725,47.199],[-91.3726,47.199],[-91.3726,47.1989],[-91.3726,47.1988],[-91.3726,47.1988],[-91.3727,47.1987],[-91.3728,47.1987],[-91.3729,47.1986],[-91.3731,47.1985],[-91.3733,47.1984],[-91.3733,47.1983],[-91.3733,47.1982],[-91.3733,47.1981],[-91.3733,47.198],[-91.3735,47.198],[-91.3737,47.1978],[-91.3738,47.1977],[-91.374,47.1977],[-91.3741,47.1978],[-91.3745,47.1979],[-91.3748,47.1979],[-91.3751,47.198],[-91.3755,47.198],[-91.3758,47.1981],[-91.3761,47.1981],[-91.3766,47.1981],[-91.3769,47.198],[-91.3772,47.1978],[-91.3773,47.1976],[-91.3774,47.1975],[-91.3775,47.1973],[-91.3775,47.1972],[-91.3776,47.1969],[-91.3776,47.1967],[-91.3776,47.1966],[-91.3775,47.1964],[-91.3774,47.1961],[-91.3773,47.1958],[-91.3772,47.1957],[-91.3771,47.1957],[-91.377,47.1956],[-91.3771,47.1955],[-91.3774,47.1954],[-91.3778,47.1952],[-91.3783,47.1949],[-91.3787,47.1947],[-91.3789,47.1946],[-91.3791,47.1945],[-91.3794,47.1943],[-91.3795,47.1942],[-91.3797,47.194],[-91.3799,47.1937],[-91.3801,47.1935],[-91.3802,47.1933],[-91.3803,47.193],[-91.3804,47.1927],[-91.3804,47.1923],[-91.3805,47.1922],[-91.3805,47.1919],[-91.3806,47.1917],[-91.3806,47.1915],[-91.3807,47.1914],[-91.3807,47.1914],[-91.3811,47.1913],[-91.3814,47.1913],[-91.3817,47.1914],[-91.3819,47.1915],[-91.3822,47.1916],[-91.3824,47.1917],[-91.3825,47.1918],[-91.3828,47.1918],[-91.383,47.1918],[-91.3833,47.1918],[-91.3836,47.1918],[-91.3838,47.1918],[-91.3842,47.1916],[-91.3853,47.1909],[-91.3853,47.1908],[-91.3852,47.1907],[-91.3853,47.1906],[-91.3853,47.1905],[-91.3854,47.1904],[-91.3856,47.1903],[-91.3858,47.1902],[-91.3859,47.1902],[-91.3861,47.1901],[-91.3862,47.1901],[-91.3863,47.1901],[-91.3865,47.1901],[-91.3865,47.19],[-91.3863,47.1899],[-91.3862,47.1898],[-91.3861,47.1896],[-91.3859,47.1896],[-91.3856,47.1896],[-91.3853,47.1895],[-91.385,47.1893],[-91.3848,47.1891],[-91.3846,47.189],[-91.3843,47.1888],[-91.384,47.1888],[-91.3837,47.1887],[-91.3836,47.1886],[-91.3834,47.1885],[-91.3834,47.1884],[-91.3831,47.1884],[-91.383,47.1883],[-91.3831,47.188],[-91.3833,47.1879],[-91.3837,47.1879],[-91.3839,47.1878],[-91.384,47.1876],[-91.384,47.1875],[-91.3842,47.1873],[-91.3845,47.1872],[-91.3846,47.1872],[-91.3848,47.1872],[-91.385,47.1871],[-91.3853,47.1871],[-91.3855,47.1872],[-91.3858,47.1872],[-91.3861,47.1871],[-91.3864,47.187],[-91.3867,47.187],[-91.3869,47.1871],[-91.387,47.1872],[-91.3874,47.1873],[-91.3876,47.1873],[-91.3879,47.1873],[-91.3882,47.1873],[-91.3885,47.1873],[-91.3889,47.1873],[-91.3893,47.1873],[-91.3895,47.1873],[-91.3897,47.1873],[-91.3901,47.1873],[-91.3912,47.1873],[-91.3917,47.1873],[-91.3921,47.1872],[-91.3924,47.1872],[-91.3926,47.1872],[-91.393,47.187],[-91.3935,47.1869],[-91.3937,47.1868],[-91.3938,47.1868],[-91.394,47.1866],[-91.3942,47.1866],[-91.3944,47.1865],[-91.3946,47.1864],[-91.3948,47.1864],[-91.395,47.1864],[-91.3953,47.1864],[-91.3956,47.1864],[-91.3957,47.1863],[-91.3959,47.1862],[-91.3961,47.1862],[-91.3964,47.1861],[-91.3967,47.1861],[-91.3969,47.1861],[-91.3971,47.1861],[-91.3973,47.186],[-91.3976,47.1859],[-91.3978,47.1859],[-91.398,47.186],[-91.3982,47.1861],[-91.3985,47.1861],[-91.3988,47.186],[-91.3991,47.1858],[-91.3993,47.1856],[-91.3995,47.1853],[-91.3996,47.1851],[-91.3996,47.1849],[-91.3997,47.1848],[-91.3997,47.1848],[-91.3996,47.1846],[-91.3994,47.1844],[-91.3991,47.1843],[-91.3991,47.1843],[-91.399,47.1842],[-91.3987,47.1841],[-91.3985,47.184],[-91.3982,47.1839],[-91.3981,47.1838],[-91.3982,47.1836],[-91.3982,47.1834],[-91.3984,47.1833],[-91.3987,47.1834],[-91.3988,47.1833],[-91.3989,47.1832],[-91.3989,47.1831],[-91.399,47.183],[-91.3992,47.1829],[-91.3992,47.1827],[-91.3994,47.1823],[-91.3995,47.1822],[-91.3997,47.1821],[-91.3998,47.182],[-91.4,47.1819],[-91.4001,47.1818],[-91.4001,47.1817],[-91.4002,47.1815],[-91.4003,47.1815],[-91.4004,47.1814],[-91.4006,47.1813],[-91.4007,47.1812],[-91.4008,47.1812],[-91.4008,47.181],[-91.4009,47.1809],[-91.401,47.1808],[-91.4011,47.1808],[-91.4013,47.181],[-91.4013,47.1811],[-91.4014,47.1812],[-91.4016,47.1812],[-91.4017,47.1812],[-91.4019,47.1814],[-91.402,47.1816],[-91.4022,47.1818],[-91.4024,47.1819],[-91.4026,47.1819],[-91.4028,47.1819],[-91.4031,47.182],[-91.4034,47.182],[-91.4037,47.1819],[-91.404,47.1817],[-91.4041,47.1817],[-91.4042,47.1815],[-91.4042,47.1813],[-91.4042,47.1811],[-91.4043,47.1809],[-91.4044,47.1809],[-91.4045,47.181],[-91.4045,47.1812],[-91.4045,47.1814],[-91.4045,47.1814],[-91.4057,47.1815],[-91.4059,47.1817],[-91.406,47.1818],[-91.4061,47.182],[-91.4062,47.182],[-91.4064,47.1821],[-91.4065,47.1821],[-91.4066,47.1821],[-91.4071,47.182],[-91.4072,47.182],[-91.4073,47.1819],[-91.4075,47.1819],[-91.4077,47.1818],[-91.4079,47.1817],[-91.408,47.1816],[-91.4081,47.1815],[-91.4082,47.1814],[-91.4084,47.1813],[-91.4085,47.1812],[-91.4086,47.181],[-91.4087,47.1807],[-91.4087,47.1805],[-91.4088,47.1801],[-91.4089,47.1798],[-91.409,47.1796],[-91.4092,47.1794],[-91.4093,47.1793],[-91.4094,47.1792],[-91.4095,47.179],[-91.4096,47.1788],[-91.4096,47.1786],[-91.4097,47.1784],[-91.4098,47.1781],[-91.4098,47.1779],[-91.4098,47.1777],[-91.4098,47.1776],[-91.4096,47.1776],[-91.4094,47.1775],[-91.4094,47.1773],[-91.4096,47.1772],[-91.4097,47.1771],[-91.4097,47.177],[-91.4098,47.1765],[-91.4098,47.1762],[-91.4097,47.176],[-91.4097,47.1759],[-91.4098,47.1758],[-91.4099,47.1757],[-91.4102,47.1757],[-91.4102,47.1757],[-91.4105,47.1757],[-91.4108,47.1758],[-91.411,47.1758],[-91.4112,47.1757],[-91.4115,47.1757],[-91.4116,47.1756],[-91.4117,47.1754],[-91.4118,47.1753],[-91.4121,47.1753],[-91.4124,47.1752],[-91.4126,47.1752],[-91.4129,47.1752],[-91.413,47.175],[-91.4133,47.1748],[-91.4135,47.1747],[-91.4135,47.1746],[-91.4137,47.1745],[-91.4138,47.1744],[-91.4138,47.1742],[-91.414,47.174],[-91.4144,47.1737],[-91.4148,47.1735],[-91.4152,47.1733],[-91.4155,47.1732],[-91.4159,47.1731],[-91.4163,47.173],[-91.4166,47.1728],[-91.417,47.1726],[-91.4174,47.1724],[-91.4176,47.1724],[-91.4178,47.1724],[-91.4182,47.1724],[-91.4184,47.1723],[-91.4186,47.1723],[-91.4187,47.1722],[-91.4188,47.1721],[-91.419,47.1719],[-91.4191,47.1717],[-91.4192,47.1716],[-91.4195,47.1712],[-91.4197,47.171],[-91.42,47.1707],[-91.4202,47.1705],[-91.4204,47.1702],[-91.4206,47.1699],[-91.4207,47.1695],[-91.4209,47.1693],[-91.4209,47.1691],[-91.4209,47.1689],[-91.4209,47.1686],[-91.421,47.1682],[-91.4211,47.168],[-91.4212,47.1677],[-91.4212,47.1674],[-91.4213,47.1672],[-91.4213,47.167],[-91.4214,47.1668],[-91.4214,47.1667],[-91.4214,47.1666],[-91.4213,47.1666],[-91.4209,47.1666],[-91.4209,47.1664],[-91.421,47.1663],[-91.4212,47.1663],[-91.4213,47.1663],[-91.4214,47.1662],[-91.4214,47.1661],[-91.4215,47.1661],[-91.4217,47.1661],[-91.4218,47.1662],[-91.422,47.1663],[-91.4221,47.1663],[-91.4222,47.1662],[-91.4222,47.166],[-91.4222,47.1658],[-91.4221,47.1657],[-91.422,47.1655],[-91.4219,47.1655],[-91.422,47.1654],[-91.4222,47.1653],[-91.4223,47.1652],[-91.4225,47.165],[-91.4225,47.1649],[-91.4226,47.1648],[-91.4227,47.1648],[-91.4229,47.1648],[-91.423,47.1649],[-91.4231,47.165],[-91.4233,47.165],[-91.4235,47.165],[-91.4237,47.1651],[-91.4241,47.1652],[-91.4245,47.1653],[-91.4248,47.1654],[-91.4251,47.1656],[-91.4265,47.1652],[-91.4267,47.1651],[-91.427,47.165],[-91.4271,47.1649],[-91.4272,47.1647],[-91.4273,47.1645],[-91.4274,47.1644],[-91.4275,47.1643],[-91.4277,47.1643],[-91.4278,47.1642],[-91.4279,47.164],[-91.428,47.1638],[-91.4282,47.1636],[-91.4285,47.1635],[-91.4289,47.1634],[-91.429,47.1633],[-91.4291,47.1633],[-91.4291,47.1631],[-91.4293,47.1628],[-91.4295,47.1626],[-91.4296,47.1625],[-91.4299,47.1623],[-91.4302,47.1622],[-91.4307,47.162],[-91.4312,47.1619],[-91.4316,47.1618],[-91.4316,47.1618],[-91.4319,47.1617],[-91.4321,47.1616],[-91.4322,47.1615],[-91.4324,47.1614],[-91.4328,47.1608],[-91.4329,47.1606],[-91.4331,47.1602],[-91.4332,47.1601],[-91.4331,47.1599],[-91.433,47.1598],[-91.433,47.1597],[-91.4332,47.1596],[-91.4335,47.1596],[-91.4337,47.1596],[-91.434,47.1594],[-91.4341,47.1593],[-91.4342,47.1593],[-91.4345,47.1594],[-91.4351,47.1594],[-91.4354,47.1596],[-91.4358,47.1596],[-91.4361,47.1596],[-91.4365,47.1595],[-91.4367,47.1593],[-91.437,47.1591],[-91.4371,47.1589],[-91.4373,47.1587],[-91.4373,47.1585],[-91.4372,47.1583],[-91.4372,47.1581],[-91.4373,47.1579],[-91.4374,47.1578],[-91.4374,47.1577],[-91.4373,47.1576],[-91.4373,47.1576],[-91.4369,47.1576],[-91.4366,47.1575],[-91.4365,47.1575],[-91.4365,47.1573],[-91.4365,47.1572],[-91.4364,47.1571],[-91.4365,47.157],[-91.4366,47.1569],[-91.4368,47.1569],[-91.437,47.1568],[-91.437,47.1567],[-91.4372,47.1566],[-91.4374,47.1566],[-91.4378,47.1566],[-91.4382,47.1566],[-91.4385,47.1565],[-91.4388,47.1564],[-91.4391,47.1561],[-91.4391,47.1561],[-91.4393,47.1558],[-91.4396,47.1555],[-91.4398,47.1553],[-91.4399,47.1551],[-91.4399,47.1549],[-91.4399,47.1548],[-91.4401,47.1546],[-91.4404,47.1545],[-91.4406,47.1544],[-91.4406,47.1542],[-91.4407,47.1541],[-91.4407,47.154],[-91.4407,47.1539],[-91.4407,47.1537],[-91.4407,47.1537],[-91.4408,47.1535],[-91.4411,47.1534],[-91.4413,47.1533],[-91.4415,47.1532],[-91.4415,47.1529],[-91.4418,47.1526],[-91.4423,47.1523],[-91.4426,47.1521],[-91.4427,47.1519],[-91.4428,47.1517],[-91.4429,47.1515],[-91.4428,47.1514],[-91.4429,47.1512],[-91.443,47.151],[-91.4433,47.1508],[-91.4435,47.1506],[-91.4436,47.1504],[-91.4439,47.1501],[-91.444,47.15],[-91.4445,47.15],[-91.4447,47.1498],[-91.4447,47.1497],[-91.4449,47.1495],[-91.4451,47.1493],[-91.4452,47.1491],[-91.4453,47.149],[-91.4454,47.1489],[-91.4457,47.1488],[-91.4458,47.1488],[-91.4459,47.1487],[-91.446,47.1486],[-91.446,47.1485],[-91.4459,47.1485],[-91.4458,47.1485],[-91.4458,47.1484],[-91.4458,47.1484],[-91.4458,47.1483],[-91.4459,47.1483],[-91.446,47.1484],[-91.446,47.1484],[-91.4461,47.1485],[-91.4462,47.1486],[-91.4463,47.1487],[-91.4464,47.1487],[-91.4465,47.1487],[-91.4466,47.1487],[-91.4468,47.1486],[-91.4471,47.1485],[-91.4474,47.1483],[-91.4476,47.1482],[-91.4477,47.1482],[-91.4478,47.1482],[-91.4479,47.1481],[-91.4479,47.1479],[-91.4479,47.1478],[-91.4479,47.1477],[-91.4479,47.1475],[-91.448,47.1474],[-91.4482,47.1474],[-91.4483,47.1471],[-91.4485,47.1469],[-91.4486,47.1467],[-91.4489,47.1465],[-91.4492,47.1464],[-91.4494,47.1463],[-91.4497,47.1462],[-91.4499,47.1462],[-91.4501,47.1461],[-91.4503,47.1461],[-91.4505,47.1461],[-91.4507,47.1461],[-91.4508,47.146],[-91.4509,47.1459],[-91.4518,47.1458],[-91.4523,47.1458],[-91.4525,47.1458],[-91.4528,47.1458],[-91.4528,47.1458],[-91.4532,47.1457],[-91.4534,47.1456],[-91.4537,47.1456],[-91.4539,47.1455],[-91.4541,47.1455],[-91.4542,47.1454],[-91.4542,47.1452],[-91.4543,47.145],[-91.4544,47.145],[-91.4544,47.1448],[-91.4545,47.1447],[-91.4546,47.1446],[-91.4546,47.1444],[-91.4547,47.1441],[-91.4549,47.144],[-91.455,47.1439],[-91.4552,47.1437],[-91.4554,47.1436],[-91.4556,47.1436],[-91.4559,47.1435],[-91.4561,47.1434],[-91.4563,47.1433],[-91.4564,47.1433],[-91.4565,47.1432],[-91.4566,47.1432],[-91.457,47.1429],[-91.4569,47.1428],[-91.457,47.1427],[-91.4569,47.1426],[-91.4568,47.1424],[-91.4564,47.1421],[-91.4563,47.1421],[-91.4562,47.142],[-91.456,47.142],[-91.4558,47.1419],[-91.4557,47.1418],[-91.4557,47.1416],[-91.4557,47.1416],[-91.4558,47.1415],[-91.4558,47.1414],[-91.4557,47.1413],[-91.4556,47.1412],[-91.4557,47.1411],[-91.4557,47.1409],[-91.4557,47.1406],[-91.4555,47.1406],[-91.4549,47.1405],[-91.4546,47.1405],[-91.4544,47.1405],[-91.4542,47.1404],[-91.4543,47.1403],[-91.4545,47.1401],[-91.4547,47.14],[-91.4548,47.1397],[-91.455,47.1397],[-91.4551,47.1397],[-91.4553,47.1397],[-91.4553,47.1396],[-91.4554,47.1394],[-91.4558,47.1392],[-91.4562,47.1391],[-91.4565,47.1389],[-91.4569,47.1387],[-91.4573,47.1385],[-91.4576,47.1384],[-91.4579,47.1383],[-91.4581,47.1383],[-91.4582,47.1382],[-91.4583,47.1381],[-91.4585,47.138],[-91.4588,47.1379],[-91.4589,47.1379],[-91.459,47.1379],[-91.4591,47.1379],[-91.4592,47.1378],[-91.4592,47.1376],[-91.4592,47.1375],[-91.459,47.1374],[-91.459,47.1373],[-91.4591,47.1372],[-91.4594,47.1372],[-91.4595,47.1371],[-91.4596,47.1371],[-91.4597,47.1369],[-91.4599,47.1369],[-91.4599,47.1369],[-91.46,47.1368],[-91.4601,47.1366],[-91.4602,47.1366],[-91.4603,47.1365],[-91.4602,47.1364],[-91.4601,47.1363],[-91.4602,47.1361],[-91.4603,47.136],[-91.4605,47.1359],[-91.4606,47.1356],[-91.4607,47.1354],[-91.4608,47.1352],[-91.4609,47.135],[-91.461,47.1349],[-91.461,47.1347],[-91.461,47.1345],[-91.4612,47.1344],[-91.4614,47.1344],[-91.4617,47.1345],[-91.462,47.1344],[-91.4623,47.1344],[-91.4626,47.1344],[-91.4628,47.1344],[-91.463,47.1342],[-91.4632,47.134],[-91.4633,47.1339],[-91.4634,47.1338],[-91.4635,47.1338],[-91.4636,47.1337],[-91.464,47.1336],[-91.4643,47.1336],[-91.4646,47.1335],[-91.4647,47.1334],[-91.4648,47.1332],[-91.4649,47.1331],[-91.465,47.133],[-91.4649,47.1326],[-91.4649,47.1325],[-91.4649,47.1324],[-91.4648,47.1322],[-91.4648,47.1321],[-91.465,47.1319],[-91.4651,47.1319],[-91.4653,47.1318],[-91.4654,47.1317],[-91.4654,47.1315],[-91.4656,47.1313],[-91.4657,47.1312],[-91.466,47.1312],[-91.4663,47.1313],[-91.4665,47.1314],[-91.4667,47.1316],[-91.4668,47.1317],[-91.467,47.1318],[-91.4672,47.1318],[-91.4676,47.1317],[-91.468,47.1316],[-91.4682,47.1315],[-91.4684,47.1314],[-91.4685,47.1312],[-91.4688,47.131],[-91.4689,47.1308],[-91.4691,47.1307],[-91.4694,47.1306],[-91.4696,47.1305],[-91.4699,47.1305],[-91.4701,47.1304],[-91.4703,47.1304],[-91.4705,47.1304],[-91.4706,47.1302],[-91.4708,47.1301],[-91.4709,47.1301],[-91.471,47.13],[-91.4711,47.1299],[-91.4711,47.1298],[-91.4712,47.1297],[-91.4713,47.1296],[-91.4715,47.1295],[-91.4717,47.1295],[-91.4719,47.1295],[-91.4728,47.1294],[-91.4731,47.1294],[-91.4732,47.1293],[-91.4733,47.1292],[-91.4734,47.1292],[-91.4737,47.1289],[-91.4738,47.1288],[-91.4738,47.1287],[-91.4739,47.1286],[-91.474,47.1285],[-91.4741,47.1284],[-91.4743,47.1284],[-91.4745,47.1285],[-91.4746,47.1285],[-91.4748,47.1285],[-91.475,47.1284],[-91.475,47.1282],[-91.4751,47.1281],[-91.4752,47.1279],[-91.4752,47.1277],[-91.4753,47.1275],[-91.4754,47.1273],[-91.4754,47.1273],[-91.4756,47.1271],[-91.4759,47.1269],[-91.476,47.1269],[-91.4762,47.1266],[-91.4765,47.1263],[-91.4766,47.1262],[-91.4768,47.126],[-91.4769,47.1258],[-91.4771,47.1257],[-91.4773,47.1255],[-91.4775,47.1254],[-91.4778,47.1253],[-91.4782,47.1252],[-91.4786,47.1252],[-91.4789,47.1252],[-91.4791,47.1251],[-91.4793,47.125],[-91.4794,47.125],[-91.4794,47.1249],[-91.4795,47.1249],[-91.4797,47.1248],[-91.4799,47.1247],[-91.48,47.1246],[-91.4801,47.1246],[-91.4803,47.1245],[-91.4804,47.1244],[-91.4805,47.1243],[-91.4807,47.1243],[-91.4809,47.1243],[-91.481,47.1243],[-91.4812,47.1243],[-91.4815,47.1244],[-91.4816,47.1245],[-91.4817,47.1245],[-91.4819,47.1245],[-91.4821,47.1245],[-91.4823,47.1245],[-91.4826,47.1246],[-91.4829,47.1246],[-91.4831,47.1246],[-91.4833,47.1245],[-91.4836,47.1245],[-91.4838,47.1245],[-91.4841,47.1246],[-91.4842,47.1246],[-91.4844,47.1247],[-91.4845,47.1247],[-91.4847,47.1248],[-91.4849,47.1249],[-91.485,47.125],[-91.4867,47.125],[-91.4867,47.125],[-91.4869,47.1249],[-91.4871,47.1249],[-91.4874,47.1248],[-91.4876,47.1248],[-91.4877,47.1247],[-91.4879,47.1245],[-91.488,47.1243],[-91.4881,47.1242],[-91.4883,47.124],[-91.4884,47.1239],[-91.4886,47.1238],[-91.4887,47.1238],[-91.4888,47.1238],[-91.489,47.1237],[-91.4891,47.1237],[-91.4893,47.1237],[-91.4895,47.1237],[-91.4898,47.1236],[-91.4899,47.1236],[-91.4901,47.1234],[-91.4902,47.1233],[-91.4903,47.1232],[-91.4905,47.1231],[-91.4906,47.1231],[-91.4907,47.1231],[-91.4908,47.1232],[-91.491,47.1232],[-91.4911,47.1233],[-91.4913,47.1233],[-91.4915,47.1234],[-91.4918,47.1234],[-91.492,47.1233],[-91.4922,47.1233],[-91.4924,47.1232],[-91.4927,47.1232],[-91.4928,47.1231],[-91.4929,47.123],[-91.493,47.1229],[-91.4931,47.123],[-91.4932,47.123],[-91.4933,47.123],[-91.4933,47.1231],[-91.4935,47.1232],[-91.4937,47.1232],[-91.494,47.1233],[-91.4942,47.1233],[-91.4945,47.1233],[-91.4947,47.1232],[-91.4949,47.1232],[-91.4952,47.1231],[-91.4953,47.123],[-91.4955,47.1229],[-91.4958,47.1228],[-91.496,47.1226],[-91.4962,47.1225],[-91.4963,47.1225],[-91.4964,47.1225],[-91.4965,47.1225],[-91.4967,47.1226],[-91.4968,47.1227],[-91.497,47.1228],[-91.4972,47.1228],[-91.4973,47.1228],[-91.4975,47.1227],[-91.4977,47.1227],[-91.4979,47.1226],[-91.4981,47.1225],[-91.4983,47.1224],[-91.4985,47.1224],[-91.4986,47.1223],[-91.4987,47.1223],[-91.4988,47.1222],[-91.4989,47.1221],[-91.4991,47.1219],[-91.4993,47.1218],[-91.4997,47.1217],[-91.5,47.1216],[-91.5001,47.1215],[-91.5002,47.1214],[-91.5003,47.1213],[-91.5004,47.1212],[-91.5005,47.1211],[-91.5007,47.1209],[-91.5008,47.1207],[-91.5012,47.1205],[-91.5013,47.1203],[-91.5015,47.1201],[-91.5018,47.1199],[-91.502,47.1196],[-91.5024,47.1194],[-91.5026,47.1193],[-91.5029,47.1192],[-91.5031,47.1192],[-91.5033,47.1191],[-91.5034,47.1192],[-91.5035,47.1192],[-91.5035,47.1192],[-91.5036,47.1192],[-91.5038,47.1192],[-91.5041,47.1192],[-91.5045,47.1192],[-91.5049,47.1192],[-91.5051,47.1191],[-91.5054,47.1192],[-91.5057,47.1192],[-91.5061,47.1191],[-91.5064,47.119],[-91.5067,47.1189],[-91.5069,47.1187],[-91.507,47.1186],[-91.5072,47.1182],[-91.5073,47.1178],[-91.5073,47.1176],[-91.5074,47.1174],[-91.5076,47.1172],[-91.5077,47.1169],[-91.5078,47.1168],[-91.508,47.1167],[-91.5084,47.1164],[-91.5088,47.1162],[-91.5091,47.1161],[-91.5095,47.1161],[-91.5099,47.116],[-91.5101,47.1159],[-91.5104,47.1159],[-91.5106,47.1158],[-91.5109,47.1157],[-91.511,47.1156],[-91.5111,47.1155],[-91.5112,47.1154],[-91.5113,47.1153],[-91.5116,47.1151],[-91.5119,47.1149],[-91.5121,47.1146],[-91.5123,47.1143],[-91.5124,47.1142],[-91.5125,47.114],[-91.5127,47.1138],[-91.5128,47.1138],[-91.5129,47.1138],[-91.513,47.1138],[-91.5132,47.1136],[-91.5133,47.1135],[-91.5134,47.1134],[-91.5135,47.1133],[-91.5136,47.1132],[-91.5136,47.1132],[-91.5136,47.1131],[-91.5137,47.113],[-91.5137,47.1128],[-91.5138,47.1127],[-91.5138,47.1125],[-91.5139,47.1124],[-91.514,47.1123],[-91.5141,47.1122],[-91.5142,47.1121],[-91.5144,47.1121],[-91.5145,47.112],[-91.5146,47.1119],[-91.5146,47.1119],[-91.5147,47.1118],[-91.5148,47.1117],[-91.515,47.1116],[-91.5152,47.1114],[-91.5153,47.1113],[-91.5154,47.1113],[-91.5155,47.1112],[-91.5157,47.1109],[-91.516,47.1106],[-91.5164,47.1103],[-91.5169,47.1099],[-91.5171,47.1097],[-91.5173,47.1096],[-91.5174,47.1095],[-91.5175,47.1094],[-91.5175,47.1094],[-91.5176,47.1094],[-91.5176,47.1093],[-91.5176,47.1093],[-91.5177,47.1092],[-91.5178,47.1091],[-91.518,47.1087],[-91.5181,47.1085],[-91.5181,47.1084],[-91.5181,47.1083],[-91.5181,47.108],[-91.5181,47.1078],[-91.5181,47.1076],[-91.5181,47.1075],[-91.5181,47.1075],[-91.5181,47.1073],[-91.5181,47.1072],[-91.5181,47.1069],[-91.5181,47.1067],[-91.5182,47.1066],[-91.5184,47.1065],[-91.5184,47.1064],[-91.5183,47.1063],[-91.5185,47.1063],[-91.5185,47.1061],[-91.5186,47.106],[-91.5188,47.1059],[-91.5189,47.1058],[-91.519,47.1058],[-91.5193,47.1058],[-91.5194,47.1057],[-91.5195,47.1057],[-91.5196,47.1055],[-91.5199,47.1052],[-91.52,47.1049],[-91.5202,47.1048],[-91.5203,47.1047],[-91.5203,47.1046],[-91.5204,47.1046],[-91.5206,47.1046],[-91.5207,47.1045],[-91.5208,47.1044],[-91.5212,47.1041],[-91.5214,47.104],[-91.5215,47.104],[-91.5216,47.1039],[-91.5217,47.1039],[-91.5218,47.104],[-91.5219,47.104],[-91.5221,47.104],[-91.5222,47.1041],[-91.5223,47.1041],[-91.5224,47.1041],[-91.5226,47.1041],[-91.5229,47.1041],[-91.5229,47.1041],[-91.523,47.1041],[-91.523,47.1041],[-91.523,47.104],[-91.5231,47.104],[-91.5232,47.1039],[-91.5233,47.1039],[-91.5234,47.1039],[-91.5235,47.1039],[-91.5236,47.1039],[-91.5236,47.1039],[-91.5237,47.1039],[-91.5238,47.1039],[-91.5238,47.1039],[-91.5238,47.1039],[-91.5239,47.1038],[-91.5239,47.1037],[-91.5239,47.1037],[-91.5239,47.1036],[-91.5239,47.1036],[-91.5239,47.1035],[-91.5239,47.1034],[-91.524,47.1034],[-91.524,47.1034],[-91.5241,47.1034],[-91.5242,47.1034],[-91.5243,47.1034],[-91.5244,47.1035],[-91.5246,47.1035],[-91.525,47.1037],[-91.5251,47.1038],[-91.5252,47.1038],[-91.5254,47.1039],[-91.5255,47.1039],[-91.5256,47.1039],[-91.5257,47.104],[-91.5258,47.104],[-91.5262,47.104],[-91.5265,47.1039],[-91.5266,47.1039],[-91.5268,47.1038],[-91.5269,47.1038],[-91.527,47.1037],[-91.5271,47.1036],[-91.5271,47.1036],[-91.5272,47.1035],[-91.5273,47.1035],[-91.5277,47.1033],[-91.528,47.1031],[-91.5285,47.1029],[-91.5287,47.1028],[-91.5289,47.1027],[-91.5291,47.1026],[-91.5292,47.1025],[-91.5294,47.1024],[-91.5296,47.1024],[-91.5298,47.1024],[-91.5299,47.1024],[-91.5301,47.1024],[-91.5304,47.1024],[-91.5306,47.1025],[-91.5309,47.1025],[-91.5312,47.1025],[-91.5315,47.1025],[-91.5318,47.1024],[-91.532,47.1025],[-91.5322,47.1025],[-91.5323,47.1024],[-91.5323,47.1024],[-91.5326,47.1024],[-91.5327,47.1024],[-91.5329,47.1025],[-91.5332,47.1026],[-91.5334,47.1027],[-91.5336,47.1027],[-91.5337,47.1028],[-91.5339,47.1028],[-91.5343,47.1028],[-91.5348,47.1027],[-91.5352,47.1027],[-91.5354,47.1027],[-91.5358,47.1027],[-91.5361,47.1027],[-91.5364,47.1027],[-91.5368,47.1027],[-91.537,47.1027],[-91.5373,47.1026],[-91.5376,47.1024],[-91.538,47.1022],[-91.5383,47.102],[-91.5386,47.1019],[-91.5389,47.1018],[-91.5391,47.1018],[-91.5393,47.1018],[-91.5394,47.1018],[-91.5395,47.1018],[-91.5396,47.1017],[-91.5396,47.1017],[-91.5397,47.1017],[-91.5397,47.1016],[-91.5398,47.1015],[-91.5398,47.1015],[-91.5398,47.1014],[-91.5398,47.1013],[-91.5397,47.1011],[-91.5396,47.101],[-91.5396,47.1009],[-91.5395,47.1008],[-91.5395,47.1006],[-91.5395,47.1006],[-91.5396,47.1005],[-91.5397,47.1005],[-91.5398,47.1005],[-91.5399,47.1004],[-91.54,47.1004],[-91.54,47.1003],[-91.54,47.1002],[-91.54,47.1002],[-91.54,47.1001],[-91.54,47.1],[-91.54,47.0999],[-91.54,47.0999],[-91.5401,47.0999],[-91.5401,47.0998],[-91.5402,47.0998],[-91.5402,47.0998],[-91.5403,47.0999],[-91.5404,47.0999],[-91.5405,47.0999],[-91.5405,47.0999],[-91.5406,47.0998],[-91.5407,47.0998],[-91.5408,47.0997],[-91.5409,47.0995],[-91.5409,47.0993],[-91.541,47.0992],[-91.541,47.099],[-91.541,47.0989],[-91.541,47.0988],[-91.541,47.0988],[-91.5409,47.0987],[-91.5409,47.0987],[-91.5409,47.0986],[-91.5409,47.0986],[-91.5409,47.0986],[-91.5409,47.0985],[-91.541,47.0985],[-91.541,47.0985],[-91.5411,47.0985],[-91.5412,47.0986],[-91.5412,47.0986],[-91.5413,47.0987],[-91.5414,47.0987],[-91.5414,47.0988],[-91.5415,47.0988],[-91.5418,47.0989],[-91.542,47.099],[-91.5422,47.099],[-91.5425,47.099],[-91.5427,47.099],[-91.5428,47.0989],[-91.5429,47.0989],[-91.543,47.099],[-91.5431,47.099],[-91.5431,47.099],[-91.5432,47.0991],[-91.5433,47.0992],[-91.5434,47.0992],[-91.5435,47.0992],[-91.5437,47.0992],[-91.5438,47.0992],[-91.5439,47.0991],[-91.544,47.099],[-91.5441,47.099],[-91.5442,47.099],[-91.5443,47.099],[-91.5444,47.099],[-91.5444,47.099],[-91.5444,47.0991],[-91.5444,47.0991],[-91.5444,47.0992],[-91.5445,47.0993],[-91.5445,47.0993],[-91.5446,47.0994],[-91.5447,47.0994],[-91.5448,47.0994],[-91.5448,47.0994],[-91.5449,47.0995],[-91.545,47.0994],[-91.5453,47.0994],[-91.5457,47.0992],[-91.5461,47.099],[-91.5462,47.0989],[-91.5464,47.0988],[-91.5464,47.0988],[-91.5466,47.0986],[-91.5469,47.098],[-91.5471,47.0978],[-91.5472,47.0977],[-91.5474,47.0976],[-91.5476,47.0975],[-91.5477,47.0973],[-91.5477,47.0971],[-91.5478,47.097],[-91.5479,47.0969],[-91.5479,47.0969],[-91.5479,47.0968],[-91.5479,47.0966],[-91.5479,47.0965],[-91.548,47.0963],[-91.5482,47.0961],[-91.5485,47.0961],[-91.549,47.0961],[-91.5495,47.096],[-91.5497,47.0958],[-91.5499,47.0957],[-91.55,47.0956],[-91.55,47.0955],[-91.55,47.0954],[-91.5501,47.0954],[-91.5502,47.0954],[-91.5503,47.0955],[-91.5504,47.0955],[-91.5504,47.0953],[-91.5504,47.0953],[-91.5503,47.0952],[-91.5502,47.0951],[-91.5501,47.095],[-91.5502,47.0949],[-91.5502,47.0949],[-91.5503,47.0948],[-91.5503,47.0948],[-91.5501,47.0946],[-91.5499,47.0943],[-91.5498,47.0941],[-91.5497,47.094],[-91.5496,47.0939],[-91.5497,47.0937],[-91.5497,47.0936],[-91.5497,47.0935],[-91.5498,47.0935],[-91.5499,47.0935],[-91.5499,47.0935],[-91.55,47.0936],[-91.5501,47.0936],[-91.5502,47.0936],[-91.5503,47.0936],[-91.5505,47.0935],[-91.5506,47.0935],[-91.5507,47.0934],[-91.5509,47.0934],[-91.5511,47.0935],[-91.5512,47.0935],[-91.5513,47.0935],[-91.5514,47.0935],[-91.5516,47.0935],[-91.5518,47.0934],[-91.5521,47.0934],[-91.5523,47.0933],[-91.5525,47.0933],[-91.5526,47.0933],[-91.5528,47.0933],[-91.553,47.0934],[-91.5532,47.0934],[-91.5534,47.0936],[-91.5535,47.0937],[-91.5535,47.0938],[-91.5536,47.0939],[-91.5536,47.0939],[-91.5537,47.0939],[-91.5539,47.094],[-91.554,47.094],[-91.5542,47.0941],[-91.5546,47.0941],[-91.5557,47.0943],[-91.5563,47.0944],[-91.5568,47.0945],[-91.5575,47.0945],[-91.5581,47.0944],[-91.5586,47.0944],[-91.5593,47.0944],[-91.5598,47.0944],[-91.5602,47.0944],[-91.5608,47.0943],[-91.5612,47.0942],[-91.5612,47.0941],[-91.5614,47.0941],[-91.5616,47.0941],[-91.5619,47.0939],[-91.563,47.0936],[-91.5637,47.0933],[-91.5641,47.0931],[-91.5644,47.093],[-91.5645,47.0928],[-91.5649,47.0927],[-91.5651,47.0926],[-91.5653,47.0926],[-91.5658,47.0926],[-91.566,47.0926],[-91.5664,47.0926],[-91.5666,47.0926],[-91.5667,47.0926],[-91.5669,47.0925],[-91.567,47.0924],[-91.5674,47.0924],[-91.5677,47.0924],[-91.5681,47.0924],[-91.5684,47.0924],[-91.5686,47.0924],[-91.5688,47.0924],[-91.569,47.0923],[-91.5692,47.0922],[-91.5692,47.0921],[-91.5694,47.0921],[-91.5696,47.092],[-91.5698,47.0919],[-91.5703,47.0915],[-91.5708,47.0912],[-91.5712,47.091],[-91.5718,47.0909],[-91.572,47.0908],[-91.5724,47.0907],[-91.5728,47.0904],[-91.573,47.0903],[-91.5735,47.0901],[-91.5739,47.0898],[-91.5744,47.0895],[-91.5748,47.0892],[-91.5751,47.0889],[-91.5752,47.0886],[-91.5753,47.0885],[-91.5753,47.0884],[-91.5755,47.0881],[-91.5756,47.088],[-91.5758,47.0876],[-91.5761,47.0871],[-91.5761,47.0868],[-91.5763,47.0866],[-91.5764,47.0863],[-91.5767,47.0856],[-91.5768,47.0853],[-91.5769,47.0851],[-91.5771,47.085],[-91.5771,47.0848],[-91.5771,47.0847],[-91.5771,47.0846],[-91.5772,47.0845],[-91.5774,47.0845],[-91.5775,47.0845],[-91.5775,47.0846],[-91.5776,47.0847],[-91.578,47.0847],[-91.5784,47.0846],[-91.5786,47.0845],[-91.5787,47.0843],[-91.5788,47.0843],[-91.5788,47.0841],[-91.5789,47.0838],[-91.5789,47.0837],[-91.579,47.0837],[-91.5792,47.0836],[-91.5793,47.0834],[-91.5794,47.0833],[-91.5795,47.0832],[-91.5797,47.083],[-91.5799,47.0828],[-91.5799,47.0827],[-91.58,47.0824],[-91.5802,47.0821],[-91.5803,47.0819],[-91.5805,47.0818],[-91.5807,47.0818],[-91.5809,47.0816],[-91.5811,47.0814],[-91.5812,47.0813],[-91.5813,47.0813],[-91.5814,47.0813],[-91.5816,47.0812],[-91.5816,47.0812],[-91.5818,47.0811],[-91.5821,47.0809],[-91.5823,47.0807],[-91.5825,47.0806],[-91.5825,47.0806],[-91.5828,47.0801],[-91.5831,47.0799],[-91.5834,47.0797],[-91.5836,47.0794],[-91.5838,47.0793],[-91.5839,47.079],[-91.5841,47.0787],[-91.5842,47.0786],[-91.5843,47.0786],[-91.5843,47.0785],[-91.5844,47.0782],[-91.5845,47.078],[-91.5847,47.0776],[-91.5849,47.0772],[-91.5849,47.0769],[-91.5849,47.0766],[-91.585,47.0764],[-91.5851,47.0763],[-91.585,47.0762],[-91.585,47.0761],[-91.5849,47.076],[-91.5848,47.0759],[-91.5847,47.0759],[-91.5847,47.0758],[-91.5846,47.0758],[-91.5845,47.0758],[-91.5845,47.0758],[-91.5844,47.0758],[-91.5843,47.0758],[-91.5843,47.0758],[-91.5843,47.0757],[-91.5843,47.0757],[-91.5843,47.0755],[-91.5843,47.0755],[-91.5843,47.0753],[-91.5844,47.0752],[-91.5844,47.0751],[-91.5844,47.0751],[-91.5844,47.075],[-91.5844,47.0749],[-91.5845,47.0749],[-91.5846,47.0749],[-91.5846,47.0749],[-91.5846,47.075],[-91.5847,47.0751],[-91.5847,47.0751],[-91.5848,47.0751],[-91.5849,47.0751],[-91.5849,47.075],[-91.585,47.0748],[-91.5851,47.0747],[-91.5851,47.0746],[-91.5851,47.0744],[-91.5851,47.0743],[-91.585,47.0742],[-91.5849,47.0741],[-91.5847,47.074],[-91.5846,47.0739],[-91.5845,47.0738],[-91.5845,47.0736],[-91.5846,47.0734],[-91.5847,47.0733],[-91.5847,47.0733],[-91.5848,47.0732],[-91.585,47.0732],[-91.5851,47.0731],[-91.5852,47.073],[-91.5853,47.0729],[-91.5854,47.0729],[-91.5854,47.0728],[-91.5854,47.0728],[-91.5855,47.0727],[-91.5856,47.0727],[-91.5857,47.0728],[-91.5858,47.0727],[-91.5858,47.0726],[-91.5858,47.0725],[-91.586,47.0724],[-91.5861,47.0724],[-91.5864,47.0724],[-91.5865,47.0724],[-91.5865,47.0724],[-91.5866,47.0722],[-91.5867,47.072],[-91.5869,47.0719],[-91.5874,47.0718],[-91.5879,47.0717],[-91.5883,47.0716],[-91.5887,47.0715],[-91.5889,47.0714],[-91.5893,47.0712],[-91.5896,47.071],[-91.5899,47.0708],[-91.59,47.0706],[-91.5903,47.0703],[-91.5905,47.0702],[-91.5908,47.07],[-91.5909,47.0698],[-91.5911,47.0697],[-91.5913,47.0693],[-91.5914,47.069],[-91.5915,47.0687],[-91.5917,47.0685],[-91.5919,47.0682],[-91.5921,47.0678],[-91.5923,47.0675],[-91.5925,47.0673],[-91.5926,47.0671],[-91.5928,47.0668],[-91.5929,47.0665],[-91.5931,47.0663],[-91.5934,47.0661],[-91.5938,47.0659],[-91.5941,47.0657],[-91.5942,47.0656],[-91.5945,47.0654],[-91.5947,47.0652],[-91.5948,47.0649],[-91.5947,47.0646],[-91.5947,47.0642],[-91.5947,47.0639],[-91.5947,47.0637],[-91.5947,47.0636],[-91.5947,47.0635],[-91.5947,47.0634],[-91.5946,47.0633],[-91.5945,47.0633],[-91.5944,47.0632],[-91.5943,47.0631],[-91.5944,47.063],[-91.5944,47.0629],[-91.5944,47.0628],[-91.5945,47.0626],[-91.5946,47.0626],[-91.5949,47.0625],[-91.5954,47.0623],[-91.5956,47.0623],[-91.596,47.0623],[-91.5964,47.0623],[-91.5966,47.0624],[-91.5969,47.0624],[-91.5971,47.0623],[-91.5974,47.0622],[-91.5976,47.0621],[-91.5977,47.0622],[-91.5978,47.0623],[-91.598,47.0623],[-91.5981,47.0623],[-91.5985,47.0623],[-91.5989,47.0624],[-91.5992,47.0625],[-91.5995,47.0627],[-91.5998,47.0629],[-91.6,47.0632],[-91.6002,47.0634],[-91.6003,47.0635],[-91.6006,47.0636],[-91.601,47.0637],[-91.6014,47.0638],[-91.6016,47.0638],[-91.6019,47.0639],[-91.6022,47.0639],[-91.6024,47.064],[-91.6026,47.064],[-91.603,47.064],[-91.6031,47.064],[-91.6032,47.0639],[-91.6032,47.0639],[-91.6034,47.0638],[-91.6035,47.0637],[-91.6037,47.0637],[-91.6038,47.0636],[-91.604,47.0636],[-91.6041,47.0635],[-91.6043,47.0633],[-91.6045,47.0633],[-91.6046,47.0632],[-91.6048,47.0632],[-91.6051,47.0631],[-91.6053,47.063],[-91.6055,47.0629],[-91.6057,47.0628],[-91.6058,47.0627],[-91.6059,47.0626],[-91.606,47.0626],[-91.6061,47.0625],[-91.6062,47.0624],[-91.6062,47.0624],[-91.6064,47.0623],[-91.6066,47.0622],[-91.6072,47.0621],[-91.6078,47.062],[-91.6082,47.0619],[-91.6088,47.0617],[-91.6092,47.0615],[-91.6095,47.0613],[-91.6099,47.0611],[-91.6101,47.061],[-91.6103,47.0609],[-91.6104,47.0609],[-91.6104,47.0608],[-91.6105,47.0607],[-91.6105,47.0607],[-91.6112,47.0603],[-91.6117,47.0601],[-91.6121,47.0599],[-91.6126,47.0596],[-91.6129,47.0594],[-91.6131,47.0592],[-91.6132,47.0592],[-91.6134,47.0591],[-91.6136,47.059],[-91.6138,47.0589],[-91.6139,47.0588],[-91.6139,47.0588],[-91.6143,47.0585],[-91.6146,47.0583],[-91.6148,47.0581],[-91.615,47.0578],[-91.6154,47.0572],[-91.6157,47.0569],[-91.616,47.0568],[-91.6163,47.0566],[-91.6164,47.0565],[-91.6165,47.0565],[-91.6169,47.0564],[-91.6174,47.0563],[-91.6176,47.0562],[-91.6178,47.056],[-91.6181,47.0557],[-91.6183,47.0554],[-91.6186,47.0553],[-91.6187,47.0552],[-91.6188,47.055],[-91.6188,47.055],[-91.6189,47.0547],[-91.6191,47.0545],[-91.6192,47.0544],[-91.6192,47.0543],[-91.6192,47.0542],[-91.6192,47.0542],[-91.6192,47.0541],[-91.6192,47.054],[-91.6193,47.0539],[-91.6193,47.0538],[-91.6194,47.0537],[-91.6194,47.0535],[-91.6195,47.0533],[-91.6196,47.0532],[-91.6197,47.0532],[-91.6198,47.0531],[-91.6199,47.0531],[-91.6201,47.0529],[-91.6205,47.0526],[-91.6209,47.0522],[-91.6214,47.0516],[-91.6218,47.0512],[-91.6221,47.051],[-91.6226,47.0509],[-91.6231,47.0508],[-91.6236,47.0507],[-91.6242,47.0507],[-91.6243,47.0507],[-91.6246,47.0506],[-91.6247,47.0505],[-91.6248,47.0505],[-91.6249,47.0504],[-91.6251,47.0502],[-91.6254,47.0501],[-91.6255,47.0499],[-91.6257,47.0498],[-91.6259,47.0497],[-91.6261,47.0497],[-91.6267,47.0498],[-91.6269,47.0498],[-91.6271,47.0497],[-91.6273,47.0497],[-91.6275,47.0495],[-91.628,47.0492],[-91.6289,47.0484],[-91.6295,47.0478],[-91.6298,47.0477],[-91.6302,47.0475],[-91.6303,47.0475],[-91.6305,47.0473],[-91.6308,47.0469],[-91.6309,47.0467],[-91.6311,47.0464],[-91.6312,47.0463],[-91.6314,47.046],[-91.6315,47.046],[-91.6315,47.046],[-91.6316,47.0458],[-91.6317,47.0455],[-91.6318,47.045],[-91.6318,47.0448],[-91.6322,47.0446],[-91.6323,47.0445],[-91.6323,47.0445],[-91.6325,47.0442],[-91.6326,47.0441],[-91.6326,47.044],[-91.6326,47.044],[-91.6331,47.0436],[-91.6334,47.0435],[-91.6335,47.0435],[-91.6336,47.0435],[-91.6338,47.0434],[-91.6341,47.0434],[-91.6341,47.0433],[-91.6346,47.0432],[-91.6348,47.0431],[-91.6348,47.0431],[-91.6349,47.043],[-91.6349,47.043],[-91.6352,47.0427],[-91.6356,47.0421],[-91.6357,47.0418],[-91.6358,47.0414],[-91.6357,47.0412],[-91.6357,47.041],[-91.6356,47.0409],[-91.6357,47.0406],[-91.6358,47.0406],[-91.636,47.0405],[-91.6361,47.0405],[-91.6364,47.0405],[-91.6366,47.0405],[-91.6372,47.0403],[-91.6374,47.0403],[-91.638,47.0403],[-91.6388,47.0403],[-91.6396,47.04],[-91.6403,47.0397],[-91.6407,47.0394],[-91.6412,47.0389],[-91.6417,47.0385],[-91.6421,47.0378],[-91.6422,47.0376],[-91.6424,47.0369],[-91.6425,47.0363],[-91.6424,47.0355],[-91.6423,47.0351],[-91.642,47.0345],[-91.6418,47.0344],[-91.6415,47.0343],[-91.6413,47.0343],[-91.6412,47.0343],[-91.6406,47.0343],[-91.6405,47.0342],[-91.6399,47.0342],[-91.6396,47.0343],[-91.6395,47.0343],[-91.6391,47.0343],[-91.6385,47.0343],[-91.6384,47.0343],[-91.6382,47.0342],[-91.6381,47.034],[-91.638,47.0339],[-91.6376,47.0339],[-91.6373,47.0338],[-91.6372,47.0337],[-91.6371,47.0337],[-91.6372,47.0336],[-91.6374,47.0334],[-91.6375,47.0334],[-91.6376,47.0334],[-91.6378,47.0333],[-91.6382,47.0332],[-91.6385,47.0329],[-91.6385,47.0328],[-91.6385,47.0327],[-91.6385,47.0325],[-91.6386,47.0324],[-91.6387,47.0322],[-91.6388,47.0321],[-91.6388,47.0319],[-91.6387,47.0317],[-91.6386,47.0316],[-91.6385,47.0315],[-91.6384,47.0315],[-91.6383,47.0315],[-91.638,47.0315],[-91.6379,47.0315],[-91.6378,47.0315],[-91.6376,47.0315],[-91.6374,47.0313],[-91.6369,47.0313],[-91.6367,47.0312],[-91.6364,47.0313],[-91.6362,47.0313],[-91.6361,47.0313],[-91.636,47.0311],[-91.6358,47.0308],[-91.6357,47.0307],[-91.6357,47.0306],[-91.6357,47.0301],[-91.6358,47.0299],[-91.6361,47.0294],[-91.6363,47.0292],[-91.6364,47.0292],[-91.6365,47.0291],[-91.6366,47.029],[-91.6367,47.0289],[-91.6368,47.0287],[-91.6368,47.0287],[-91.637,47.0284],[-91.637,47.0281],[-91.6369,47.028],[-91.6369,47.028],[-91.6367,47.0279],[-91.6365,47.0278],[-91.6364,47.0278],[-91.6363,47.0277],[-91.6364,47.0276],[-91.6366,47.0274],[-91.6366,47.0274],[-91.6367,47.0273],[-91.6367,47.0273],[-91.6368,47.0272],[-91.637,47.027],[-91.6371,47.027],[-91.6379,47.0267],[-91.6381,47.0267],[-91.6385,47.0266],[-91.6388,47.0266],[-91.6389,47.0266],[-91.6391,47.0268],[-91.6396,47.0268],[-91.6401,47.0268],[-91.6406,47.0265],[-91.6411,47.0262],[-91.6415,47.026],[-91.6419,47.026],[-91.6422,47.0259],[-91.6425,47.0259],[-91.6427,47.026],[-91.643,47.0263],[-91.6432,47.0263],[-91.6436,47.0264],[-91.6442,47.0263],[-91.6452,47.0259],[-91.6453,47.0259],[-91.6458,47.0259],[-91.6459,47.0259],[-91.6461,47.0261],[-91.6461,47.0261],[-91.6465,47.0268],[-91.6466,47.0269],[-91.6468,47.0271],[-91.6469,47.0272],[-91.6472,47.0273],[-91.6476,47.0275],[-91.6477,47.0277],[-91.6479,47.0279],[-91.648,47.0279],[-91.6485,47.0284],[-91.6485,47.0285],[-91.6487,47.0287],[-91.6491,47.0289],[-91.6494,47.029],[-91.6497,47.0292],[-91.6502,47.0294],[-91.6512,47.0296],[-91.6526,47.0295],[-91.6531,47.0294],[-91.6531,47.0294],[-91.6543,47.0292],[-91.6545,47.0291],[-91.6546,47.0291],[-91.6549,47.029],[-91.6553,47.0289],[-91.6556,47.0288],[-91.6562,47.0286],[-91.6564,47.0285],[-91.6573,47.0281],[-91.6575,47.0279],[-91.6578,47.0277],[-91.6581,47.0276],[-91.6586,47.0272],[-91.6591,47.027],[-91.6594,47.0269],[-91.6596,47.0267],[-91.6605,47.0258],[-91.6606,47.0257],[-91.6608,47.0254],[-91.6609,47.0252],[-91.661,47.0251],[-91.661,47.0251],[-91.6611,47.0249],[-91.6611,47.0248],[-91.6612,47.0246],[-91.6611,47.0245],[-91.6611,47.0243],[-91.6611,47.0243],[-91.6611,47.0243],[-91.6609,47.0241],[-91.6607,47.024],[-91.6606,47.024],[-91.6599,47.024],[-91.6596,47.0239],[-91.6594,47.0237],[-91.6594,47.0237],[-91.6595,47.0236],[-91.6597,47.0235],[-91.6598,47.0234],[-91.6598,47.0232],[-91.6598,47.023],[-91.6598,47.023],[-91.6598,47.0229],[-91.6598,47.0229],[-91.6598,47.0224],[-91.6597,47.022],[-91.6597,47.0219],[-91.6598,47.0214],[-91.66,47.0212],[-91.6601,47.021],[-91.6601,47.0209],[-91.6601,47.0207],[-91.6601,47.0206],[-91.66,47.0205],[-91.6598,47.0204],[-91.6597,47.0203],[-91.6598,47.0201],[-91.6599,47.0201],[-91.6599,47.02],[-91.6599,47.02],[-91.66,47.0199],[-91.66,47.0198],[-91.6601,47.0196],[-91.6601,47.0194],[-91.6601,47.0193],[-91.6599,47.0192],[-91.6599,47.0191],[-91.6599,47.0191],[-91.6598,47.019],[-91.6595,47.0189],[-91.6595,47.0188],[-91.6597,47.0185],[-91.6599,47.0183],[-91.6602,47.0182],[-91.6605,47.0179],[-91.6606,47.0178],[-91.6607,47.0178],[-91.6607,47.0178],[-91.6609,47.0176],[-91.661,47.0175],[-91.661,47.0172],[-91.661,47.017],[-91.6607,47.0168],[-91.6606,47.0167],[-91.6603,47.0165],[-91.6603,47.0162],[-91.6604,47.016],[-91.6604,47.016],[-91.6605,47.016],[-91.6605,47.0159],[-91.6605,47.0157],[-91.6605,47.0155],[-91.6604,47.0153],[-91.6605,47.0153],[-91.6605,47.0152],[-91.6606,47.0152],[-91.661,47.0149],[-91.6612,47.0146],[-91.6613,47.0145],[-91.6613,47.0145],[-91.6616,47.0144],[-91.6616,47.0144],[-91.6619,47.0142],[-91.6622,47.014],[-91.6622,47.0139],[-91.6623,47.0138],[-91.6625,47.0135],[-91.6626,47.0134],[-91.663,47.0132],[-91.6632,47.0132],[-91.6633,47.0131],[-91.6635,47.013],[-91.6636,47.0129],[-91.6638,47.0129],[-91.664,47.013],[-91.6642,47.0132],[-91.6645,47.0135],[-91.6647,47.0136],[-91.6649,47.0137],[-91.6653,47.0137],[-91.6656,47.0138],[-91.6657,47.0141],[-91.6658,47.0142],[-91.6658,47.0144],[-91.6658,47.0146],[-91.6657,47.0155],[-91.6657,47.0157],[-91.6659,47.0159],[-91.666,47.0159],[-91.6665,47.0162],[-91.6669,47.0165],[-91.667,47.0165],[-91.6673,47.0166],[-91.6676,47.0166],[-91.6681,47.0166],[-91.6684,47.0165],[-91.6685,47.0164],[-91.6685,47.0163],[-91.6683,47.016],[-91.6682,47.0158],[-91.6682,47.0157],[-91.6683,47.0157],[-91.6683,47.0157],[-91.6684,47.0157],[-91.6684,47.0157],[-91.6687,47.016],[-91.6687,47.0161],[-91.6688,47.0163],[-91.6688,47.0164],[-91.6689,47.0165],[-91.6691,47.017],[-91.6693,47.0171],[-91.6693,47.0172],[-91.6695,47.0172],[-91.6696,47.0172],[-91.6696,47.0172],[-91.6695,47.017],[-91.6693,47.0166],[-91.6692,47.0163],[-91.6693,47.0163],[-91.6694,47.0163],[-91.6694,47.0164],[-91.6695,47.0165],[-91.6698,47.017],[-91.6699,47.0171],[-91.6701,47.0171],[-91.6704,47.0171],[-91.6708,47.0171],[-91.6715,47.0172],[-91.6732,47.0172],[-91.6736,47.0173],[-91.674,47.0174],[-91.6744,47.0175],[-91.6754,47.0176],[-91.6758,47.0175],[-91.6759,47.0175],[-91.6758,47.0174],[-91.6755,47.0173],[-91.6743,47.0169],[-91.6736,47.0166],[-91.671,47.0157],[-91.6709,47.0157],[-91.6709,47.0156],[-91.671,47.0155],[-91.6711,47.0155],[-91.673,47.0161],[-91.6762,47.0173],[-91.6762,47.0173],[-91.6765,47.0171],[-91.6766,47.017],[-91.6766,47.0169],[-91.6763,47.0168],[-91.6761,47.0167],[-91.6721,47.0153],[-91.6714,47.0151],[-91.6714,47.015],[-91.6714,47.015],[-91.6716,47.0148],[-91.6717,47.0149],[-91.6764,47.0166],[-91.6766,47.0166],[-91.6767,47.0167],[-91.6768,47.0167],[-91.6769,47.0166],[-91.6772,47.0163],[-91.6773,47.0162],[-91.6775,47.0158],[-91.6775,47.0157],[-91.6778,47.0153],[-91.6779,47.0151],[-91.6781,47.0148],[-91.6781,47.0148],[-91.6746,47.0137],[-91.6742,47.0136],[-91.6741,47.0136],[-91.6741,47.0136],[-91.674,47.0135],[-91.6741,47.0133],[-91.6742,47.0133],[-91.6743,47.0134],[-91.6782,47.0146],[-91.6784,47.0146],[-91.6785,47.0145],[-91.6785,47.0145],[-91.6785,47.0143],[-91.6783,47.014],[-91.6783,47.0139],[-91.6783,47.0137],[-91.6784,47.0135],[-91.6787,47.0131],[-91.6789,47.0127],[-91.679,47.0123],[-91.679,47.0121],[-91.679,47.0116],[-91.679,47.0112],[-91.679,47.0112],[-91.679,47.0112],[-91.6791,47.0111],[-91.6791,47.011],[-91.6791,47.011],[-91.6793,47.0108],[-91.6795,47.0106],[-91.6799,47.0103],[-91.6801,47.0102],[-91.6803,47.01],[-91.6805,47.0099],[-91.6807,47.0098],[-91.6808,47.0098],[-91.681,47.0097],[-91.6814,47.0093],[-91.682,47.0088],[-91.6821,47.0087],[-91.6822,47.0087],[-91.6827,47.0083],[-91.683,47.0081],[-91.683,47.0081],[-91.6836,47.0076],[-91.6839,47.0073],[-91.684,47.0073],[-91.684,47.0073],[-91.6842,47.0072],[-91.6843,47.0072],[-91.6845,47.0069],[-91.6848,47.0067],[-91.685,47.0066],[-91.6858,47.0066],[-91.686,47.0065],[-91.6861,47.0065],[-91.6862,47.0065],[-91.6863,47.0064],[-91.6865,47.0063],[-91.6868,47.0061],[-91.687,47.006],[-91.6873,47.006],[-91.6874,47.006],[-91.6878,47.0061],[-91.6879,47.0061],[-91.6881,47.0061],[-91.6881,47.0061],[-91.6883,47.0061],[-91.6886,47.0061],[-91.6888,47.0063],[-91.6889,47.0063],[-91.6892,47.0063],[-91.6897,47.0061],[-91.6901,47.0061],[-91.6904,47.0063],[-91.6914,47.0064],[-91.6914,47.0065],[-91.6917,47.0065],[-91.6918,47.0065],[-91.6925,47.0066],[-91.6926,47.0066],[-91.6934,47.0067],[-91.6936,47.0068],[-91.6945,47.007],[-91.6948,47.0071],[-91.6952,47.0072],[-91.6963,47.0073],[-91.6968,47.0073],[-91.6971,47.0073],[-91.6974,47.0073],[-91.698,47.0075],[-91.6986,47.0074],[-91.6993,47.0073],[-91.6995,47.0073],[-91.7002,47.007],[-91.7004,47.0069],[-91.7006,47.0069],[-91.701,47.0067],[-91.7012,47.0066],[-91.7013,47.0066],[-91.7021,47.0063],[-91.7027,47.0061],[-91.7028,47.0061],[-91.7028,47.006],[-91.7036,47.0057],[-91.7046,47.0053],[-91.7063,47.0041],[-91.7065,47.0039],[-91.7067,47.0038],[-91.7068,47.0037],[-91.7071,47.0033],[-91.7078,47.0027],[-91.708,47.0025],[-91.7081,47.0024],[-91.7082,47.0022],[-91.7084,47.0022],[-91.7087,47.0021],[-91.7088,47.0021],[-91.7093,47.0018],[-91.7094,47.0017],[-91.7097,47.0015],[-91.7098,47.0014],[-91.7098,47.0014],[-91.71,47.0013],[-91.7102,47.0012],[-91.7103,47.0011],[-91.7103,47.001],[-91.7103,47.001],[-91.7108,47.0003],[-91.7109,47.0003],[-91.7114,47.0002],[-91.7116,47.0],[-91.7116,46.9998],[-91.7117,46.9997],[-91.7117,46.9997],[-91.7117,46.9997],[-91.7117,46.9996],[-91.7117,46.9995],[-91.7118,46.9995],[-91.7118,46.9995],[-91.7119,46.9994],[-91.712,46.9994],[-91.7121,46.9994],[-91.7123,46.9994],[-91.7125,46.9994],[-91.7126,46.9994],[-91.7128,46.9993],[-91.713,46.9992],[-91.713,46.9991],[-91.7131,46.999],[-91.7132,46.9989],[-91.7133,46.9988],[-91.7134,46.9986],[-91.7136,46.9985],[-91.7138,46.9984],[-91.714,46.9983],[-91.7142,46.9982],[-91.7142,46.9982],[-91.7142,46.9981],[-91.7143,46.998],[-91.7143,46.998],[-91.7144,46.9979],[-91.7145,46.9978],[-91.7146,46.9978],[-91.7146,46.9978],[-91.7147,46.9977],[-91.7148,46.9976],[-91.7148,46.9976],[-91.7149,46.9975],[-91.715,46.9975],[-91.7151,46.9974],[-91.7152,46.9973],[-91.7153,46.9972],[-91.7155,46.997],[-91.7156,46.9969],[-91.7158,46.9968],[-91.716,46.9967],[-91.7161,46.9967],[-91.7164,46.9966],[-91.7166,46.9964],[-91.717,46.9962],[-91.7171,46.996],[-91.7172,46.9959],[-91.7174,46.9957],[-91.7175,46.9956],[-91.7176,46.9955],[-91.7179,46.9954],[-91.7181,46.9952],[-91.7183,46.9951],[-91.7184,46.995],[-91.7186,46.9949],[-91.7187,46.9948],[-91.7187,46.9947],[-91.7189,46.9946],[-91.7191,46.9944],[-91.7193,46.9942],[-91.7195,46.9942],[-91.7196,46.9941],[-91.7197,46.9941],[-91.7199,46.9941],[-91.7201,46.9941],[-91.7203,46.9941],[-91.7204,46.994],[-91.7205,46.994],[-91.7207,46.9939],[-91.7207,46.9939],[-91.7208,46.9938],[-91.7208,46.9938],[-91.7209,46.9937],[-91.7209,46.9937],[-91.721,46.9936],[-91.7211,46.9935],[-91.7212,46.9934],[-91.7214,46.9932],[-91.7216,46.993],[-91.7217,46.9929],[-91.7219,46.9928],[-91.722,46.9927],[-91.7223,46.9926],[-91.7225,46.9926],[-91.7227,46.9925],[-91.7228,46.9924],[-91.723,46.9924],[-91.723,46.9923],[-91.7231,46.9921],[-91.7232,46.9919],[-91.7234,46.9918],[-91.7235,46.9917],[-91.7237,46.9916],[-91.7238,46.9916],[-91.7239,46.9915],[-91.724,46.9914],[-91.7242,46.9913],[-91.7243,46.9912],[-91.7244,46.9911],[-91.7244,46.991],[-91.7245,46.9909],[-91.7247,46.9908],[-91.7248,46.9907],[-91.725,46.9906],[-91.7251,46.9905],[-91.7252,46.9905],[-91.7253,46.9904],[-91.7255,46.9904],[-91.7256,46.9904],[-91.7258,46.9903],[-91.726,46.9903],[-91.7262,46.9902],[-91.7263,46.9901],[-91.7265,46.99],[-91.7265,46.99],[-91.7267,46.9899],[-91.7268,46.9898],[-91.7269,46.9898],[-91.7269,46.9897],[-91.727,46.9896],[-91.7271,46.9895],[-91.7273,46.9894],[-91.7274,46.9893],[-91.7275,46.9892],[-91.7276,46.989],[-91.7277,46.9888],[-91.7278,46.9888],[-91.728,46.9887],[-91.7281,46.9887],[-91.7282,46.9886],[-91.7284,46.9886],[-91.7287,46.9884],[-91.7288,46.9884],[-91.729,46.9882],[-91.7291,46.9882],[-91.7292,46.9881],[-91.7294,46.9881],[-91.7295,46.988],[-91.7296,46.9879],[-91.7297,46.9879],[-91.7298,46.9878],[-91.7299,46.9877],[-91.73,46.9875],[-91.73,46.9874],[-91.7302,46.9874],[-91.7304,46.9873],[-91.7305,46.9873],[-91.7306,46.9872],[-91.7306,46.9872],[-91.7307,46.9872],[-91.7308,46.9871],[-91.7309,46.987],[-91.731,46.987],[-91.7312,46.9869],[-91.7312,46.9869],[-91.7313,46.9869],[-91.7313,46.9869],[-91.7314,46.9868],[-91.7315,46.9868],[-91.7316,46.9866],[-91.7317,46.9865],[-91.7319,46.9864],[-91.732,46.9863],[-91.7322,46.9861],[-91.7323,46.986],[-91.7325,46.9859],[-91.7326,46.9858],[-91.7327,46.9857],[-91.7329,46.9857],[-91.7331,46.9856],[-91.7332,46.9855],[-91.7333,46.9854],[-91.7334,46.9854],[-91.7335,46.9853],[-91.7336,46.9852],[-91.7337,46.9851],[-91.7339,46.985],[-91.734,46.9849],[-91.7342,46.9849],[-91.7344,46.9848],[-91.7345,46.9847],[-91.7347,46.9846],[-91.7349,46.9845],[-91.7349,46.9844],[-91.735,46.9843],[-91.735,46.9842],[-91.735,46.9841],[-91.7351,46.984],[-91.7352,46.9839],[-91.7353,46.9839],[-91.7354,46.9839],[-91.7356,46.9839],[-91.7357,46.9839],[-91.7358,46.9838],[-91.7359,46.9838],[-91.736,46.9837],[-91.7361,46.9836],[-91.7361,46.9835],[-91.7362,46.9835],[-91.7363,46.9834],[-91.7364,46.9834],[-91.7365,46.9833],[-91.7366,46.9832],[-91.7367,46.9832],[-91.7368,46.9831],[-91.7369,46.983],[-91.737,46.9829],[-91.7372,46.9828],[-91.7374,46.9826],[-91.7375,46.9825],[-91.7378,46.9824],[-91.7381,46.9822],[-91.7382,46.9821],[-91.7383,46.982],[-91.7384,46.9819],[-91.7384,46.9819],[-91.7385,46.9817],[-91.7387,46.9815],[-91.7388,46.9814],[-91.739,46.9813],[-91.7391,46.9812],[-91.7392,46.9811],[-91.7393,46.981],[-91.7394,46.9809],[-91.7396,46.9807],[-91.7397,46.9805],[-91.7398,46.9803],[-91.7399,46.9801],[-91.74,46.9799],[-91.74,46.9797],[-91.7401,46.9795],[-91.7402,46.9794],[-91.7404,46.9792],[-91.7406,46.9791],[-91.7407,46.979],[-91.7407,46.9789],[-91.7408,46.9788],[-91.7409,46.9787],[-91.7411,46.9786],[-91.7411,46.9786],[-91.7411,46.9786],[-91.7414,46.9784],[-91.7415,46.9782],[-91.7416,46.9781],[-91.7417,46.978],[-91.7417,46.9779],[-91.7417,46.9778],[-91.7418,46.9777],[-91.7418,46.9776],[-91.7418,46.9775],[-91.7418,46.9774],[-91.7419,46.9774],[-91.742,46.9773],[-91.7422,46.9773],[-91.7424,46.9773],[-91.7427,46.9772],[-91.7429,46.977],[-91.743,46.9769],[-91.7431,46.9768],[-91.7432,46.9766],[-91.7433,46.9765],[-91.7433,46.9764],[-91.7434,46.9764],[-91.7435,46.9764],[-91.7435,46.9764],[-91.7437,46.9763],[-91.7438,46.9763],[-91.7439,46.9762],[-91.744,46.9762],[-91.744,46.9761],[-91.7441,46.9761],[-91.7442,46.976],[-91.7443,46.976],[-91.7444,46.976],[-91.7445,46.976],[-91.7447,46.9759],[-91.7449,46.9759],[-91.7451,46.9759],[-91.7453,46.9759],[-91.7454,46.9758],[-91.7455,46.9757],[-91.7457,46.9756],[-91.7458,46.9755],[-91.7459,46.9754],[-91.7459,46.9753],[-91.746,46.9752],[-91.7461,46.9751],[-91.7462,46.9751],[-91.7462,46.9751],[-91.7463,46.975],[-91.7464,46.975],[-91.7465,46.9749],[-91.7467,46.9748],[-91.7469,46.9746],[-91.7471,46.9745],[-91.7473,46.9744],[-91.7474,46.9743],[-91.7477,46.9742],[-91.7479,46.9741],[-91.748,46.974],[-91.7482,46.9738],[-91.7482,46.9737],[-91.7483,46.9737],[-91.7484,46.9736],[-91.7485,46.9736],[-91.7487,46.9735],[-91.7488,46.9735],[-91.7489,46.9734],[-91.749,46.9733],[-91.7491,46.9732],[-91.7493,46.9731],[-91.7494,46.973],[-91.7495,46.973],[-91.7496,46.9729],[-91.7497,46.9728],[-91.7498,46.9728],[-91.7499,46.9727],[-91.75,46.9727],[-91.75,46.9727],[-91.7501,46.9726],[-91.7502,46.9725],[-91.7507,46.9721],[-91.7508,46.9721],[-91.7509,46.9721],[-91.751,46.9721],[-91.7511,46.972],[-91.7513,46.9718],[-91.7514,46.9717],[-91.7515,46.9716],[-91.7517,46.9715],[-91.7518,46.9715],[-91.7519,46.9714],[-91.752,46.9714],[-91.7521,46.9713],[-91.7523,46.9713],[-91.7524,46.9712],[-91.7526,46.971],[-91.7527,46.9708],[-91.7527,46.9707],[-91.7528,46.9707],[-91.7529,46.9707],[-91.753,46.9706],[-91.7536,46.9701],[-91.7537,46.97],[-91.7538,46.9698],[-91.7538,46.9697],[-91.7539,46.9695],[-91.7541,46.9694],[-91.7542,46.9692],[-91.7543,46.9691],[-91.7544,46.9691],[-91.7546,46.969],[-91.7548,46.969],[-91.755,46.9688],[-91.7552,46.9686],[-91.7553,46.9684],[-91.7556,46.9682],[-91.7559,46.9681],[-91.7559,46.968],[-91.7559,46.9678],[-91.756,46.9678],[-91.7562,46.9678],[-91.7563,46.9677],[-91.7564,46.9676],[-91.7565,46.9674],[-91.7565,46.9674],[-91.7568,46.9672],[-91.7571,46.967],[-91.7574,46.9668],[-91.7574,46.9667],[-91.7573,46.9667],[-91.7574,46.9666],[-91.7574,46.9666],[-91.7575,46.9665],[-91.7576,46.9666],[-91.7578,46.9666],[-91.7579,46.9665],[-91.758,46.9664],[-91.7581,46.9663],[-91.7582,46.9662],[-91.7583,46.966],[-91.7584,46.9658],[-91.7585,46.9657],[-91.7586,46.9655],[-91.7587,46.9654],[-91.7588,46.9652],[-91.7588,46.965],[-91.7589,46.965],[-91.7589,46.9649],[-91.759,46.9648],[-91.7591,46.9646],[-91.7592,46.9644],[-91.7592,46.9641],[-91.7592,46.9639],[-91.7592,46.9637],[-91.7592,46.9635],[-91.7594,46.9634],[-91.7595,46.9634],[-91.7597,46.9634],[-91.76,46.9634],[-91.7601,46.9634],[-91.7602,46.9632],[-91.7602,46.9632],[-91.7602,46.9631],[-91.7603,46.9629],[-91.7603,46.9628],[-91.7604,46.9626],[-91.7605,46.9624],[-91.7606,46.9623],[-91.7608,46.9622],[-91.7609,46.9622],[-91.7611,46.9623],[-91.7613,46.9623],[-91.7613,46.9623],[-91.7614,46.9622],[-91.7615,46.9621],[-91.7615,46.962],[-91.7616,46.9619],[-91.7618,46.962],[-91.7619,46.9619],[-91.7621,46.9619],[-91.7623,46.9617],[-91.7626,46.9616],[-91.7627,46.9616],[-91.7629,46.9615],[-91.763,46.9615],[-91.7632,46.9614],[-91.7633,46.9612],[-91.7634,46.961],[-91.7636,46.9609],[-91.7639,46.9606],[-91.7645,46.96],[-91.7649,46.9595],[-91.7652,46.9592],[-91.7654,46.9589],[-91.7657,46.9587],[-91.7659,46.9584],[-91.7663,46.9581],[-91.767,46.9576],[-91.7672,46.9574],[-91.7673,46.9572],[-91.7675,46.9571],[-91.7676,46.957],[-91.7677,46.957],[-91.7679,46.957],[-91.7681,46.9569],[-91.7683,46.9568],[-91.7684,46.9567],[-91.7687,46.9565],[-91.7688,46.9565],[-91.7689,46.9563],[-91.7692,46.9561],[-91.7693,46.9561],[-91.7695,46.9562],[-91.7697,46.9561],[-91.7699,46.956],[-91.7701,46.9559],[-91.7703,46.9558],[-91.7705,46.9557],[-91.7706,46.9557],[-91.7708,46.9558],[-91.7709,46.9558],[-91.771,46.9557],[-91.7712,46.9556],[-91.7717,46.9552],[-91.7718,46.9552],[-91.772,46.955],[-91.7723,46.9548],[-91.7726,46.9546],[-91.7731,46.9543],[-91.7732,46.9542],[-91.7733,46.954],[-91.7734,46.9539],[-91.7735,46.9537],[-91.7736,46.9536],[-91.7737,46.9536],[-91.7739,46.9536],[-91.774,46.9536],[-91.7742,46.9537],[-91.7744,46.9537],[-91.7745,46.9536],[-91.7746,46.9535],[-91.7747,46.9534],[-91.7748,46.9533],[-91.7749,46.9532],[-91.7752,46.9531],[-91.7755,46.953],[-91.7755,46.953],[-91.7756,46.9529],[-91.7757,46.9529],[-91.7759,46.9528],[-91.776,46.9527],[-91.7761,46.9526],[-91.7762,46.9524],[-91.7763,46.9524],[-91.7765,46.9524],[-91.7766,46.9523],[-91.7769,46.9521],[-91.7771,46.952],[-91.7774,46.9519],[-91.7776,46.9517],[-91.7777,46.9515],[-91.7778,46.9513],[-91.7779,46.9511],[-91.778,46.9509],[-91.7781,46.9508],[-91.7782,46.9507],[-91.7783,46.9505],[-91.7784,46.9504],[-91.7785,46.9502],[-91.7787,46.95],[-91.7785,46.9494],[-91.7784,46.9493],[-91.7784,46.9493],[-91.7783,46.9492],[-91.7783,46.9491],[-91.7782,46.949],[-91.7781,46.9489],[-91.778,46.9489],[-91.7778,46.9489],[-91.7776,46.9489],[-91.7773,46.9489],[-91.7772,46.9489],[-91.7772,46.9488],[-91.7772,46.9488],[-91.7774,46.9487],[-91.7776,46.9487],[-91.7778,46.9486],[-91.778,46.9484],[-91.7782,46.9483],[-91.7785,46.9482],[-91.7787,46.9481],[-91.7789,46.9479],[-91.7791,46.9478],[-91.7793,46.9477],[-91.7797,46.9475],[-91.78,46.9473],[-91.7801,46.9473],[-91.7803,46.9472],[-91.7804,46.947],[-91.7805,46.9469],[-91.7805,46.9467],[-91.7805,46.9465],[-91.7806,46.9463],[-91.7806,46.9461],[-91.7806,46.9459],[-91.7806,46.9457],[-91.7805,46.9456],[-91.7805,46.9454],[-91.7804,46.9452],[-91.7803,46.945],[-91.7802,46.9448],[-91.7801,46.9447],[-91.78,46.9445],[-91.78,46.9444],[-91.7801,46.9444],[-91.7804,46.9445],[-91.7806,46.9445],[-91.7808,46.9446],[-91.781,46.9447],[-91.7812,46.9449],[-91.7813,46.9449],[-91.7813,46.9451],[-91.7813,46.9453],[-91.7813,46.9454],[-91.7813,46.9455],[-91.7813,46.9456],[-91.7813,46.9457],[-91.7815,46.9457],[-91.7818,46.9458],[-91.7821,46.9457],[-91.7823,46.9457],[-91.7824,46.9457],[-91.7825,46.9457],[-91.7826,46.9455],[-91.7826,46.9453],[-91.7827,46.9452],[-91.7828,46.9451],[-91.7828,46.9449],[-91.783,46.9448],[-91.7831,46.9447],[-91.7832,46.9446],[-91.7833,46.9445],[-91.7832,46.9444],[-91.7831,46.9443],[-91.7829,46.9444],[-91.7825,46.9445],[-91.7823,46.9446],[-91.7821,46.9447],[-91.782,46.9447],[-91.7819,46.9447],[-91.7817,46.9446],[-91.7816,46.9446],[-91.7817,46.9445],[-91.7817,46.9443],[-91.7818,46.9442],[-91.7818,46.9441],[-91.7819,46.944],[-91.7816,46.9441],[-91.7815,46.9441],[-91.7813,46.9442],[-91.7811,46.9444],[-91.781,46.9443],[-91.7806,46.9442],[-91.7804,46.9441],[-91.7802,46.944],[-91.7801,46.944],[-91.7799,46.9439],[-91.7798,46.9438],[-91.7797,46.9437],[-91.7797,46.9436],[-91.7797,46.9436],[-91.7797,46.9435],[-91.7798,46.9435],[-91.7799,46.9434],[-91.7804,46.9433],[-91.7805,46.9433],[-91.7807,46.9431],[-91.7808,46.9431],[-91.781,46.943],[-91.7811,46.9429],[-91.7812,46.943],[-91.7814,46.943],[-91.7815,46.943],[-91.7816,46.9429],[-91.7818,46.9427],[-91.782,46.9427],[-91.7823,46.9426],[-91.7825,46.9425],[-91.7827,46.9425],[-91.7828,46.9425],[-91.783,46.9425],[-91.7831,46.9425],[-91.7834,46.9424],[-91.7836,46.9423],[-91.7838,46.9422],[-91.784,46.9421],[-91.7841,46.9421],[-91.7841,46.942],[-91.7848,46.9419],[-91.7852,46.9419],[-91.7855,46.942],[-91.7857,46.942],[-91.7859,46.9419],[-91.7862,46.9419],[-91.7864,46.9418],[-91.7866,46.9418],[-91.7869,46.9417],[-91.7872,46.9416],[-91.7875,46.9415],[-91.7878,46.9413],[-91.788,46.9412],[-91.7883,46.9411],[-91.7884,46.941],[-91.7885,46.9409],[-91.7887,46.9409],[-91.789,46.9408],[-91.7892,46.9409],[-91.7895,46.9409],[-91.7898,46.9409],[-91.7901,46.9409],[-91.7905,46.9409],[-91.7909,46.9408],[-91.7912,46.9408],[-91.7914,46.9407],[-91.7916,46.9406],[-91.7919,46.9408],[-91.7925,46.9407],[-91.7931,46.9406],[-91.7934,46.9405],[-91.7936,46.9403],[-91.7938,46.9402],[-91.7941,46.9401],[-91.7943,46.9399],[-91.7944,46.9398],[-91.7944,46.9397],[-91.7943,46.953],[-91.7944,46.9675],[-91.7944,46.9818],[-91.7944,46.9965],[-91.7944,47.0109],[-91.7943,47.0255],[-91.7943,47.0399],[-91.7944,47.0541],[-91.7944,47.0688],[-91.7945,47.0831],[-91.7945,47.0976],[-91.7943,47.1119],[-91.7922,47.1119],[-91.7924,47.1265],[-91.7923,47.1411],[-91.7923,47.1556],[-91.7923,47.1698],[-91.7923,47.1843],[-91.7922,47.1985],[-91.7923,47.2128],[-91.7923,47.2276],[-91.7923,47.2422],[-91.7922,47.2565],[-91.7921,47.271],[-91.792,47.2855],[-91.7919,47.3],[-91.7918,47.3145],[-91.7918,47.3288],[-91.792,47.3432],[-91.792,47.3576],[-91.792,47.3726],[-91.7906,47.3726],[-91.7904,47.3872],[-91.7896,47.4017],[-91.7895,47.416],[-91.7894,47.4303],[-91.7893,47.4449],[-91.7895,47.4574],[-91.7895,47.4605],[-91.7895,47.4741],[-91.7895,47.4753],[-91.7894,47.4886],[-91.7894,47.4897],[-91.7894,47.493],[-91.7891,47.503],[-91.7891,47.5041],[-91.789,47.5067],[-91.7889,47.5176],[-91.7889,47.5187],[-91.7886,47.5322],[-91.7886,47.533],[-91.788,47.5424],[-91.788,47.5431],[-91.7878,47.5469],[-91.7886,47.5574],[-91.7887,47.5588],[-91.7888,47.5614],[-91.789,47.5719],[-91.7892,47.5749],[-91.7893,47.576],[-91.7904,47.5864],[-91.7905,47.5874],[-91.7908,47.5904],[-91.7911,47.6008],[-91.7912,47.6021],[-91.7913,47.6049],[-91.7915,47.6091],[-91.7919,47.6155],[-91.7922,47.6193],[-91.7923,47.6212],[-91.793,47.6299],[-91.7933,47.6345],[-91.794,47.6442],[-91.794,47.6449],[-91.7942,47.6486],[-91.7948,47.6586],[-91.795,47.663],[-91.7954,47.6729],[-91.7955,47.6733],[-91.7955,47.6778],[-91.7955,47.678],[-91.7959,47.688],[-91.7959,47.6925],[-91.7967,47.7024],[-91.7971,47.707],[-91.7977,47.7128],[-91.7981,47.7165],[-91.7982,47.717],[-91.7984,47.7201],[-91.799,47.731],[-91.7992,47.7339],[-91.7992,47.7388],[-91.7993,47.7454],[-91.7993,47.7482],[-91.7992,47.7538],[-91.7992,47.7598],[-91.7992,47.7626],[-91.7995,47.7723],[-91.7995,47.7742],[-91.7995,47.776],[-91.7995,47.7774],[-91.7997,47.7886],[-91.7997,47.7893],[-91.7997,47.7916],[-91.7999,47.8031],[-91.8,47.8175],[-91.8,47.8319],[-91.7992,47.8464],[-91.7988,47.8618],[-91.7983,47.876],[-91.7983,47.8771],[-91.7979,47.8899],[-91.7979,47.9045],[-91.7978,47.9189],[-91.7977,47.9334],[-91.7979,47.9481],[-91.7985,47.9625],[-91.7992,47.977],[-91.7996,47.9914],[-91.8001,48.0059],[-91.8,48.0206],[-91.8,48.0353],[-91.8,48.0496],[-91.8001,48.0643],[-91.7997,48.0788],[-91.7992,48.0936],[-91.7987,48.1079],[-91.798,48.1224],[-91.7981,48.1369],[-91.7983,48.1515],[-91.7984,48.1662],[-91.7982,48.1808],[-91.7983,48.1953],[-91.7982,48.203],[-91.7972,48.2027],[-91.791,48.2026],[-91.7886,48.1964],[-91.7861,48.1962],[-91.7806,48.2008],[-91.7767,48.2008],[-91.7642,48.2007],[-91.7627,48.2018],[-91.7607,48.2049],[-91.7559,48.206],[-91.7553,48.2049],[-91.7535,48.2009],[-91.7484,48.1987],[-91.7438,48.1988],[-91.7415,48.1991],[-91.742,48.2047],[-91.7388,48.2043],[-91.7378,48.2043],[-91.7371,48.2042],[-91.7334,48.2033],[-91.7253,48.2014],[-91.7153,48.1996],[-91.7131,48.1981],[-91.7115,48.1958],[-91.7103,48.1939],[-91.7103,48.1926],[-91.7122,48.1876],[-91.72,48.1814],[-91.7213,48.1803],[-91.7223,48.1786],[-91.7229,48.1736],[-91.7243,48.1706],[-91.723,48.169],[-91.717,48.1719],[-91.711,48.1727],[-91.7093,48.173],[-91.7048,48.1708],[-91.705,48.1669],[-91.7051,48.1641],[-91.7049,48.1611],[-91.7046,48.1601],[-91.705,48.158],[-91.7069,48.1538],[-91.7081,48.1531],[-91.7077,48.1524],[-91.707,48.1511],[-91.7068,48.1504],[-91.7046,48.1472],[-91.7032,48.1452],[-91.7022,48.1448],[-91.7005,48.1448],[-91.6991,48.1451],[-91.6981,48.1441],[-91.6977,48.1416],[-91.6993,48.1379],[-91.6994,48.1375],[-91.6995,48.132],[-91.7005,48.1307],[-91.7037,48.1249],[-91.7078,48.1234],[-91.7078,48.1233],[-91.7093,48.1194],[-91.7117,48.1175],[-91.7125,48.1156],[-91.7117,48.1147],[-91.7103,48.1147],[-91.7099,48.1145],[-91.7033,48.1138],[-91.6967,48.1159],[-91.693,48.1166],[-91.6921,48.1169],[-91.6914,48.1179],[-91.6911,48.1182],[-91.6913,48.1185],[-91.6921,48.1198],[-91.6913,48.1201],[-91.6906,48.1203],[-91.6821,48.1226],[-91.6835,48.1178],[-91.6875,48.1119],[-91.6818,48.1099],[-91.6813,48.1091],[-91.6808,48.1084],[-91.6767,48.1075],[-91.671,48.1087],[-91.6703,48.1087],[-91.6673,48.1087],[-91.665,48.1072],[-91.6646,48.1074],[-91.6626,48.1092],[-91.6626,48.1092],[-91.6622,48.1117],[-91.6618,48.112],[-91.6551,48.1138],[-91.6532,48.1144],[-91.6518,48.114],[-91.6511,48.1131],[-91.6514,48.1122],[-91.653,48.1098],[-91.6519,48.1091],[-91.6496,48.1074],[-91.6486,48.1065],[-91.6484,48.1065],[-91.6481,48.1065],[-91.648,48.1064],[-91.6479,48.1064],[-91.648,48.1059],[-91.6469,48.1039],[-91.6399,48.0972],[-91.6267,48.0999],[-91.6148,48.1023],[-91.6073,48.1024],[-91.5888,48.1025],[-91.5846,48.1039],[-91.5755,48.107],[-91.5629,48.1082],[-91.5591,48.1086],[-91.5575,48.1073],[-91.5528,48.1033],[-91.5636,48.0971],[-91.5694,48.0937],[-91.5696,48.0928],[-91.5718,48.0828],[-91.5753,48.0668],[-91.5751,48.0658],[-91.5727,48.0574],[-91.5754,48.049],[-91.5675,48.0438],[-91.5674,48.0439],[-91.5468,48.0519],[-91.5422,48.0537],[-91.5416,48.0539],[-91.5266,48.058],[-91.5101,48.0625],[-91.4897,48.068],[-91.4881,48.0684],[-91.4659,48.067],[-91.4647,48.0669],[-91.45,48.0691],[-91.4462,48.0678],[-91.4466,48.0631],[-91.4445,48.0606],[-91.4435,48.0594],[-91.4377,48.0525],[-91.4381,48.0512],[-91.438,48.0509],[-91.4382,48.0507],[-91.4385,48.0506],[-91.4385,48.0504],[-91.4376,48.0499],[-91.4372,48.0495],[-91.4368,48.0495],[-91.4295,48.0487],[-91.4271,48.0501],[-91.4266,48.0499],[-91.4244,48.0508],[-91.4221,48.051],[-91.4151,48.0532],[-91.4135,48.0537],[-91.3921,48.057],[-91.3908,48.0572],[-91.3852,48.0612],[-91.3783,48.066],[-91.3777,48.0663],[-91.3708,48.0698],[-91.3649,48.0672],[-91.356,48.0701],[-91.3536,48.0709],[-91.3525,48.0712],[-91.352,48.0715],[-91.3508,48.0718],[-91.3503,48.072],[-91.3502,48.072],[-91.3497,48.0717],[-91.3485,48.0722],[-91.3399,48.0736],[-91.3363,48.0711],[-91.3363,48.0697],[-91.3347,48.0695],[-91.3346,48.0695],[-91.3334,48.07],[-91.332,48.0702],[-91.3312,48.0697],[-91.3293,48.07],[-91.3287,48.0706],[-91.3286,48.071],[-91.3284,48.0711],[-91.3261,48.0723],[-91.3244,48.073],[-91.3191,48.0733],[-91.3179,48.0731],[-91.3173,48.0733],[-91.316,48.0735],[-91.3153,48.0736],[-91.3147,48.0736],[-91.3129,48.0734],[-91.3117,48.0733],[-91.3112,48.0732],[-91.3108,48.0729],[-91.3101,48.0729],[-91.3088,48.0728],[-91.3078,48.0729],[-91.3068,48.0729],[-91.3063,48.0729],[-91.2915,48.0741],[-91.2897,48.0742],[-91.2796,48.0776],[-91.2759,48.0788],[-91.2714,48.0789],[-91.2667,48.0789],[-91.2499,48.0841],[-91.2496,48.0841],[-91.239,48.0928],[-91.2348,48.0962],[-91.2286,48.099],[-91.228,48.0993],[-91.2149,48.1029],[-91.2115,48.1059],[-91.2061,48.1107],[-91.1948,48.1208],[-91.19,48.1252],[-91.1846,48.1226],[-91.1842,48.1225],[-91.1833,48.1222],[-91.1828,48.1222],[-91.1812,48.1236],[-91.1766,48.1256],[-91.1635,48.1352],[-91.1618,48.1365],[-91.1562,48.1406],[-91.14,48.1481],[-91.1373,48.1493],[-91.1374,48.1496],[-91.138,48.152],[-91.1399,48.1518],[-91.1401,48.1517],[-91.1404,48.1523],[-91.1404,48.1529],[-91.1425,48.1547],[-91.1397,48.1555],[-91.1389,48.1558],[-91.1357,48.1567],[-91.1325,48.1573],[-91.1198,48.1607],[-91.1189,48.1615],[-91.118,48.1621],[-91.1169,48.1635],[-91.1147,48.1665],[-91.1088,48.1687],[-91.0977,48.1715],[-91.0971,48.1716],[-91.0919,48.1737],[-91.088,48.1784],[-91.0841,48.1804],[-91.0824,48.1812],[-91.0813,48.1809],[-91.0808,48.1804],[-91.0806,48.1801],[-91.0796,48.1799],[-91.0788,48.1796],[-91.076,48.1794],[-91.0758,48.1794],[-91.071,48.1804],[-91.0654,48.1815],[-91.0627,48.1856],[-91.0592,48.1854],[-91.0575,48.1871],[-91.056,48.1881],[-91.0554,48.1884],[-91.053,48.1882],[-91.0519,48.1881],[-91.0498,48.1888],[-91.0486,48.1888],[-91.0467,48.1892],[-91.0455,48.1895],[-91.0363,48.1902],[-91.0356,48.1899],[-91.0355,48.1899],[-91.0354,48.1898],[-91.0347,48.1893],[-91.0311,48.1889]]],"type":"Polygon"},"id":"38","properties":{"Area":5924884711.38128,"CTYONLY_":12,"Code":"LAKE","LASTMOD":"2003-01-01T01:10:00Z","Name":"Lake","Perimiter":433067.74708},"type":"Feature"},{"geometry":{"coordinates":[[[-91.2389,47.2968],[-91.2389,47.2968],[-91.2392,47.2968],[-91.2394,47.2968],[-91.2395,47.2969],[-91.2395,47.297],[-91.2394,47.2971],[-91.2392,47.2972],[-91.239,47.2972],[-91.2388,47.2971],[-91.2386,47.2972],[-91.2383,47.2973],[-91.238,47.2972],[-91.2379,47.297],[-91.238,47.2969],[-91.2381,47.2969],[-91.2382,47.297],[-91.2383,47.297],[-91.2383,47.2969],[-91.2385,47.2968],[-91.2387,47.2968],[-91.2389,47.2968]]],"type":"Polygon"},"id":"38","properties":{"Area":4148.06907,"CTYONLY_":96,"Code":"LAKE","LASTMOD":"2003-01-01T01:10:00Z","Name":"Lake","Perimiter":309.162},"type":"Feature"},{"geometry":{"coordinates":[[[-91.244,47.2934],[-91.2439,47.2934],[-91.2438,47.2934],[-91.2438,47.2932],[-91.2439,47.2931],[-91.2441,47.2931],[-91.2441,47.2931],[-91.2441,47.2933],[-91.244,47.2934]]],"type":"Polygon"},"id":"38","properties":{"Area":783.65339,"CTYONLY_":97,"Code":"LAKE","LASTMOD":"2003-01-01T01:10:00Z","Name":"Lake","Perimiter":109.61651},"type":"Feature"},{"geometry":{"coordinates":[[[-91.245,47.2935],[-91.2449,47.2935],[-91.2447,47.2935],[-91.2446,47.2934],[-91.2445,47.2932],[-91.2446,47.2931],[-91.2447,47.2931],[-91.2448,47.293],[-91.2449,47.2928],[-91.2449,47.2925],[-91.2449,47.2924],[-91.245,47.2923],[-91.2452,47.2922],[-91.2455,47.2922],[-91.2456,47.2922],[-91.2457,47.2924],[-91.2456,47.2926],[-91.2456,47.2928],[-91.2456,47.293],[-91.2457,47.2932],[-91.2456,47.2933],[-91.2454,47.2934],[-91.2452,47.2934],[-91.245,47.2935]]],"type":"Polygon"},"id":"38","properties":{"Area":8591.00636,"CTYONLY_":98,"Code":"LAKE","LASTMOD":"2003-01-01T01:10:00Z","Name":"Lake","Perimiter":398.31047},"type":"Feature"},{"geometry":{"coordinates":[[[-91.5535,47.0901],[-91.5534,47.0902],[-91.5532,47.0902],[-91.553,47.0902],[-91.5529,47.0903],[-91.5528,47.0903],[-91.5528,47.0904],[-91.5528,47.0905],[-91.5528,47.0905],[-91.5528,47.0905],[-91.5528,47.0906],[-91.5528,47.0906],[-91.5527,47.0906],[-91.5527,47.0906],[-91.5526,47.0906],[-91.5526,47.0907],[-91.5527,47.0907],[-91.5527,47.0908],[-91.5527,47.0908],[-91.5527,47.0908],[-91.5526,47.0908],[-91.5524,47.0909],[-91.5522,47.0908],[-91.5521,47.0908],[-91.552,47.0908],[-91.5519,47.0908],[-91.5519,47.0907],[-91.5519,47.0907],[-91.5517,47.0907],[-91.5517,47.0907],[-91.5515,47.0907],[-91.5515,47.0907],[-91.5514,47.0906],[-91.5514,47.0906],[-91.5515,47.0906],[-91.5517,47.0906],[-91.5519,47.0904],[-91.552,47.0903],[-91.552,47.0901],[-91.5521,47.0899],[-91.5522,47.0898],[-91.5523,47.0896],[-91.5524,47.0894],[-91.5524,47.0893],[-91.5524,47.0892],[-91.5523,47.0891],[-91.5523,47.089],[-91.5522,47.0889],[-91.552,47.0889],[-91.5518,47.0888],[-91.5516,47.0887],[-91.5515,47.0886],[-91.5514,47.0885],[-91.5514,47.0884],[-91.5513,47.0883],[-91.5513,47.0882],[-91.5513,47.0881],[-91.5513,47.0881],[-91.5513,47.0879],[-91.5514,47.0877],[-91.5514,47.0876],[-91.5515,47.0876],[-91.5516,47.0875],[-91.5517,47.0875],[-91.5518,47.0875],[-91.5519,47.0876],[-91.552,47.0877],[-91.5521,47.0877],[-91.5523,47.0878],[-91.5524,47.0878],[-91.5525,47.0878],[-91.5526,47.0878],[-91.5528,47.0877],[-91.5529,47.0877],[-91.5531,47.0877],[-91.5532,47.0878],[-91.5533,47.088],[-91.5534,47.0884],[-91.5535,47.0888],[-91.5536,47.0889],[-91.5536,47.0891],[-91.5536,47.0894],[-91.5536,47.0895],[-91.5536,47.0896],[-91.5536,47.0897],[-91.5536,47.0898],[-91.5536,47.0898],[-91.5537,47.0899],[-91.5537,47.0899],[-91.5538,47.09],[-91.5538,47.09],[-91.5539,47.0901],[-91.5538,47.0901],[-91.5537,47.0901],[-91.5536,47.0901],[-91.5535,47.0901]]],"type":"Polygon"},"id":"38","properties":{"Area":39764.53322,"CTYONLY_":99,"Code":"LAKE","LASTMOD":"2003-01-01T01:10:00Z","Name":"Lake","Perimiter":1105.41491},"type":"Feature"},{"geometry":{"coordinates":[[[-91.7743,46.9459],[-91.7742,46.946],[-91.7741,46.9461],[-91.774,46.9461],[-91.7737,46.9463],[-91.7735,46.9464],[-91.7734,46.9465],[-91.7732,46.9466],[-91.773,46.9466],[-91.7729,46.9466],[-91.7727,46.9466],[-91.7725,46.9467],[-91.7723,46.9467],[-91.7721,46.9468],[-91.772,46.9468],[-91.7719,46.9468],[-91.7719,46.9467],[-91.7719,46.9466],[-91.772,46.9464],[-91.7722,46.9463],[-91.7723,46.9462],[-91.7726,46.946],[-91.773,46.9459],[-91.773,46.9459],[-91.7733,46.9458],[-91.7734,46.9459],[-91.7735,46.9459],[-91.7736,46.946],[-91.7737,46.946],[-91.7739,46.9459],[-91.7741,46.9459],[-91.7743,46.9459]]],"type":"Polygon"},"id":"38","properties":{"Area":9667.10697,"CTYONLY_":100,"Code":"LAKE","LASTMOD":"2003-01-01T01:10:00Z","Name":"Lake","Perimiter":461.30255},"type":"Feature"},{"geometry":{"coordinates":[[[-91.267,47.2703],[-91.267,47.2703],[-91.2669,47.2703],[-91.2668,47.2703],[-91.2666,47.2703],[-91.2665,47.2702],[-91.2666,47.2701],[-91.2666,47.2701],[-91.2668,47.2701],[-91.267,47.2702],[-91.267,47.2703]]],"type":"Polygon"},"id":"38","properties":{"Area":691.59892,"CTYONLY_":117,"Code":"LAKE","LASTMOD":"2003-01-01T01:10:00Z","Name":"Lake","Perimiter":103.08393},"type":"Feature"},{"geometry":{"coordinates":[[[-91.2824,47.2658],[-91.2823,47.2658],[-91.2822,47.2658],[-91.282,47.2659],[-91.2819,47.2659],[-91.2818,47.2659],[-91.2818,47.2658],[-91.2818,47.2658],[-91.2821,47.2657],[-91.2824,47.2655],[-91.2825,47.2654],[-91.2826,47.2654],[-91.2827,47.2654],[-91.2828,47.2655],[-91.2827,47.2657],[-91.2825,47.2658],[-91.2824,47.2658]]],"type":"Polygon"},"id":"38","properties":{"Area":2024.76285,"CTYONLY_":118,"Code":"LAKE","LASTMOD":"2003-01-01T01:10:00Z","Name":"Lake","Perimiter":206.26115},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&filter=%7B%22op%22%3A%22%3D%22%2C%22args%22%3A%5B%7B%22property%22%3A%22LASTMOD%22%7D%2C%7B%22timestamp%22%3A%222003-01-01T01%3A10%3A00Z%22%7D%5D%7D&filter-lang=cql2-json","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&filter=%7B%22op%22%3A%22%3D%22%2C%22args%22%3A%5B%7B%22property%22%3A%22LASTMOD%22%7D%2C%7B%22timestamp%22%3A%222003-01-01T01%3A10%3A00Z%22%7D%5D%7D&filter-lang=cql2-json","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":8,"numberReturned":8,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_json_timestamp_with_backtick.json.txt b/msautotest/api/expected/ogcapi_cql2_json_timestamp_with_backtick.json.txt new file mode 100644 index 0000000000..30854ce3fa --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_json_timestamp_with_backtick.json.txt @@ -0,0 +1,4 @@ +Content-Type: application/json +Status: 400 + +{"code":"InvalidParameterValue","description":"Cannot translate CQL2 filter to MapServer expression: Invalid characters in TIMESTAMP() argument"} diff --git a/msautotest/api/expected/ogcapi_cql2_quoted_identifier.json.txt b/msautotest/api/expected/ogcapi_cql2_quoted_identifier.json.txt new file mode 100644 index 0000000000..665bf91451 --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_quoted_identifier.json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 1 +OGC-NumberReturned: 1 + +{"features":[{"geometry":{"coordinates":[[[-93.5242,44.5436],[-93.5225,44.5436],[-93.504,44.5438],[-93.5018,44.5438],[-93.4835,44.5438],[-93.4817,44.5438],[-93.4734,44.5438],[-93.4632,44.5438],[-93.4609,44.5438],[-93.4429,44.5438],[-93.4408,44.5438],[-93.4326,44.5438],[-93.4226,44.5439],[-93.4206,44.5439],[-93.4024,44.5439],[-93.4003,44.5439],[-93.383,44.544],[-93.38,44.544],[-93.3627,44.5441],[-93.3596,44.5441],[-93.3556,44.5441],[-93.3424,44.5442],[-93.3395,44.5442],[-93.3221,44.544],[-93.3191,44.544],[-93.3128,44.544],[-93.3019,44.544],[-93.2988,44.544],[-93.2813,44.544],[-93.2814,44.5298],[-93.2815,44.5153],[-93.2815,44.501],[-93.2815,44.4865],[-93.2817,44.472],[-93.2618,44.4718],[-93.2415,44.4716],[-93.2213,44.4714],[-93.2008,44.4714],[-93.1808,44.4713],[-93.1605,44.4713],[-93.1408,44.4712],[-93.1206,44.4713],[-93.1002,44.4718],[-93.0799,44.4719],[-93.0597,44.4718],[-93.0393,44.4719],[-93.0394,44.4576],[-93.0396,44.4432],[-93.0397,44.4287],[-93.0399,44.4143],[-93.04,44.3999],[-93.0401,44.3855],[-93.0402,44.371],[-93.0403,44.3565],[-93.0403,44.3419],[-93.0405,44.3273],[-93.0405,44.3129],[-93.0405,44.2983],[-93.0406,44.2838],[-93.0407,44.2693],[-93.0409,44.2548],[-93.041,44.2402],[-93.0411,44.2257],[-93.0411,44.2113],[-93.0411,44.1968],[-93.0427,44.1968],[-93.0459,44.1968],[-93.0613,44.1967],[-93.0661,44.1967],[-93.0815,44.1967],[-93.0862,44.1967],[-93.1003,44.1967],[-93.1015,44.1967],[-93.1063,44.1967],[-93.1092,44.1967],[-93.1218,44.1967],[-93.1267,44.1967],[-93.1301,44.1967],[-93.1418,44.1967],[-93.1467,44.1967],[-93.1561,44.1966],[-93.1622,44.1966],[-93.1661,44.1966],[-93.1703,44.1966],[-93.1822,44.1966],[-93.1856,44.1966],[-93.1865,44.1966],[-93.2023,44.1966],[-93.2037,44.1966],[-93.2064,44.1966],[-93.2225,44.1966],[-93.2265,44.1966],[-93.2292,44.1966],[-93.2426,44.1966],[-93.2465,44.1966],[-93.255,44.1966],[-93.2629,44.1966],[-93.2664,44.1966],[-93.2767,44.1966],[-93.283,44.1966],[-93.2865,44.1965],[-93.2905,44.1965],[-93.3032,44.1965],[-93.3063,44.1965],[-93.3235,44.1965],[-93.3264,44.1965],[-93.3277,44.1965],[-93.3436,44.1965],[-93.3466,44.1965],[-93.3639,44.1965],[-93.3666,44.1965],[-93.3842,44.1965],[-93.3866,44.1965],[-93.4042,44.1965],[-93.4065,44.1965],[-93.4244,44.1964],[-93.4267,44.1964],[-93.4447,44.1964],[-93.4469,44.1964],[-93.4648,44.1963],[-93.467,44.1963],[-93.4852,44.1964],[-93.4872,44.1964],[-93.5053,44.1963],[-93.507,44.1963],[-93.5255,44.1962],[-93.5253,44.2107],[-93.5251,44.2251],[-93.5251,44.2388],[-93.5251,44.2533],[-93.5252,44.2685],[-93.5252,44.2829],[-93.5252,44.2975],[-93.5252,44.312],[-93.5249,44.3266],[-93.5249,44.3411],[-93.5245,44.3557],[-93.5245,44.3704],[-93.5246,44.3848],[-93.5245,44.3994],[-93.5245,44.4138],[-93.5245,44.4283],[-93.5245,44.4427],[-93.5245,44.4572],[-93.5244,44.4717],[-93.5245,44.4862],[-93.5244,44.5007],[-93.5243,44.5152],[-93.5244,44.5297],[-93.5242,44.5436]]],"type":"Polygon"},"id":"66","properties":{"Area":1335114621.00336,"CTYONLY_":66,"Code":"RICE","LASTMOD":"2010-10-17T00:00:00Z","Name":"Rice","Perimiter":154431.78788},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&filter=%22Name%22%3D'Rice'","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&filter=%22Name%22%3D'Rice'","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":1,"numberReturned":1,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_text_add.json.txt b/msautotest/api/expected/ogcapi_cql2_text_add.json.txt new file mode 100644 index 0000000000..4a5c9777ff --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_text_add.json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 1 +OGC-NumberReturned: 1 + +{"features":[{"geometry":{"coordinates":[[[-96.4054,49.0001],[-96.4019,49.0001],[-96.3825,49.0001],[-96.3783,49.0001],[-96.3606,49.0001],[-96.3579,49.0001],[-96.3385,49.0001],[-96.3343,49.0001],[-96.3166,49.0001],[-96.3138,49.0001],[-96.2945,49.0001],[-96.2902,49.0001],[-96.2725,49.0001],[-96.2698,49.0001],[-96.2494,49.0001],[-96.2461,49.0001],[-96.2274,49.0001],[-96.2257,49.0001],[-96.2057,49.0001],[-96.2021,49.0001],[-96.1837,49.0],[-96.18,49.0],[-96.1617,49.0],[-96.1579,49.0],[-96.1401,49.0],[-96.1359,49.0],[-96.1176,49.0],[-96.1139,49.0],[-96.0957,49.0],[-96.0919,49.0],[-96.0738,49.0],[-96.07,49.0],[-96.0517,49.0],[-96.048,49.0],[-96.0298,49.0],[-96.026,49.0],[-96.0083,49.0],[-96.0045,49.0],[-95.9868,49.0],[-95.9784,49.0],[-95.9776,49.0],[-95.9755,49.0],[-95.9648,48.9999],[-95.9464,48.9999],[-95.943,48.9999],[-95.9225,48.9999],[-95.9211,48.9999],[-95.899,48.9998],[-95.883,48.9998],[-95.8771,48.9998],[-95.8564,48.9998],[-95.855,48.9998],[-95.8342,48.9998],[-95.8184,48.9997],[-95.8126,48.9997],[-95.7906,48.9997],[-95.7833,48.9997],[-95.7684,48.9997],[-95.7479,48.9996],[-95.7466,48.9996],[-95.7253,48.9996],[-95.7066,48.9996],[-95.7032,48.9996],[-95.681,48.9995],[-95.6654,48.9995],[-95.6596,48.9995],[-95.659,48.9995],[-95.6401,48.9995],[-95.6369,48.9995],[-95.6205,48.9994],[-95.615,48.9994],[-95.5948,48.9994],[-95.585,48.9994],[-95.573,48.9994],[-95.551,48.9993],[-95.5495,48.9993],[-95.5294,48.9993],[-95.5164,48.9993],[-95.5072,48.9993],[-95.4849,48.9992],[-95.4834,48.9992],[-95.4635,48.9992],[-95.4508,48.9992],[-95.4418,48.9992],[-95.4245,48.9991],[-95.4197,48.9991],[-95.3977,48.9991],[-95.3953,48.9991],[-95.3765,48.9991],[-95.3759,48.9991],[-95.3753,48.9991],[-95.3542,48.999],[-95.3513,48.999],[-95.3326,48.999],[-95.3286,48.999],[-95.3231,48.999],[-95.3224,48.9984],[-95.3204,48.9976],[-95.3202,48.9973],[-95.3204,48.9964],[-95.3206,48.9961],[-95.3201,48.9956],[-95.3197,48.9954],[-95.3191,48.9953],[-95.3187,48.9956],[-95.3182,48.996],[-95.3179,48.9961],[-95.3178,48.9961],[-95.3178,48.9958],[-95.3181,48.995],[-95.3191,48.9941],[-95.3204,48.9924],[-95.3206,48.9921],[-95.3224,48.9889],[-95.3227,48.9884],[-95.3242,48.9859],[-95.3245,48.985],[-95.3253,48.9832],[-95.3257,48.9814],[-95.3256,48.98],[-95.3255,48.9789],[-95.3257,48.9784],[-95.3253,48.976],[-95.325,48.9743],[-95.3249,48.9738],[-95.3248,48.9728],[-95.3247,48.972],[-95.3241,48.9703],[-95.3232,48.9692],[-95.3227,48.9685],[-95.3212,48.9672],[-95.3207,48.9669],[-95.3201,48.9648],[-95.3198,48.9643],[-95.3193,48.964],[-95.3193,48.9622],[-95.3202,48.9606],[-95.3206,48.9598],[-95.3206,48.9595],[-95.3206,48.959],[-95.3202,48.9581],[-95.3191,48.9569],[-95.3188,48.9562],[-95.3179,48.9559],[-95.3175,48.9552],[-95.3177,48.9545],[-95.3182,48.9535],[-95.3181,48.9531],[-95.3177,48.9525],[-95.3154,48.9513],[-95.3151,48.951],[-95.3141,48.9508],[-95.3131,48.9503],[-95.3125,48.9503],[-95.3123,48.9502],[-95.3119,48.9502],[-95.3119,48.9507],[-95.3129,48.9521],[-95.3129,48.9523],[-95.3126,48.9524],[-95.312,48.9524],[-95.3115,48.952],[-95.3108,48.9512],[-95.3104,48.951],[-95.3097,48.951],[-95.3089,48.9511],[-95.3079,48.9509],[-95.3061,48.9502],[-95.3052,48.9495],[-95.3046,48.9482],[-95.3046,48.947],[-95.305,48.9462],[-95.3053,48.9459],[-95.3061,48.9454],[-95.3068,48.9454],[-95.3069,48.9455],[-95.3069,48.9456],[-95.3063,48.9462],[-95.3062,48.9463],[-95.3061,48.9469],[-95.3062,48.9472],[-95.3062,48.9472],[-95.3071,48.9477],[-95.3081,48.948],[-95.3094,48.9481],[-95.3096,48.9482],[-95.3099,48.9484],[-95.31,48.9485],[-95.3103,48.9485],[-95.3104,48.9484],[-95.3103,48.948],[-95.3096,48.9478],[-95.3092,48.9477],[-95.3079,48.9474],[-95.3071,48.9469],[-95.3071,48.9466],[-95.3074,48.9465],[-95.3078,48.9466],[-95.3085,48.947],[-95.3086,48.9469],[-95.3086,48.9465],[-95.3088,48.9464],[-95.3095,48.9463],[-95.3102,48.9463],[-95.3114,48.9461],[-95.3131,48.946],[-95.3141,48.9457],[-95.3148,48.9452],[-95.3154,48.9448],[-95.3168,48.9431],[-95.3181,48.9421],[-95.3189,48.9419],[-95.3219,48.9412],[-95.3225,48.9409],[-95.3228,48.9403],[-95.3231,48.9389],[-95.3229,48.9373],[-95.3225,48.9358],[-95.3223,48.9355],[-95.3228,48.9344],[-95.3222,48.9327],[-95.3209,48.9307],[-95.3208,48.9305],[-95.3195,48.9285],[-95.3168,48.9245],[-95.315,48.9222],[-95.3141,48.921],[-95.3132,48.9198],[-95.3126,48.919],[-95.3119,48.9178],[-95.3115,48.9172],[-95.3109,48.9163],[-95.3102,48.9155],[-95.3093,48.9149],[-95.3092,48.9149],[-95.3085,48.9146],[-95.3078,48.9141],[-95.3074,48.9135],[-95.3064,48.9129],[-95.3061,48.9128],[-95.3059,48.9127],[-95.3043,48.9119],[-95.3038,48.9114],[-95.3027,48.91],[-95.3017,48.9093],[-95.2999,48.9086],[-95.2978,48.9083],[-95.2973,48.9081],[-95.2973,48.908],[-95.2973,48.9077],[-95.2976,48.9074],[-95.2977,48.9073],[-95.2978,48.9073],[-95.2978,48.9072],[-95.2978,48.9072],[-95.2979,48.9072],[-95.2979,48.9072],[-95.2979,48.9071],[-95.298,48.9071],[-95.298,48.9071],[-95.298,48.9071],[-95.2981,48.907],[-95.2982,48.9068],[-95.2983,48.9068],[-95.2985,48.9065],[-95.2985,48.9064],[-95.2986,48.9063],[-95.2988,48.906],[-95.2989,48.906],[-95.2991,48.9057],[-95.2992,48.9055],[-95.2994,48.9053],[-95.2996,48.9051],[-95.2997,48.905],[-95.2999,48.9048],[-95.2999,48.9048],[-95.2999,48.9048],[-95.3,48.9047],[-95.3,48.9047],[-95.3001,48.9047],[-95.3001,48.9046],[-95.3002,48.9045],[-95.3005,48.904],[-95.2993,48.9035],[-95.2983,48.9028],[-95.298,48.9027],[-95.2976,48.9026],[-95.2967,48.9027],[-95.2949,48.9028],[-95.2941,48.9027],[-95.2937,48.9023],[-95.2935,48.902],[-95.2927,48.9019],[-95.2914,48.9019],[-95.2909,48.9017],[-95.2908,48.9016],[-95.2907,48.9014],[-95.2906,48.9011],[-95.2911,48.9008],[-95.2911,48.9006],[-95.2901,48.9003],[-95.2896,48.9],[-95.289,48.8994],[-95.2882,48.8981],[-95.2879,48.8979],[-95.2872,48.8977],[-95.287,48.8976],[-95.2865,48.8975],[-95.2861,48.8976],[-95.2853,48.8977],[-95.2839,48.8975],[-95.2813,48.8967],[-95.2803,48.8965],[-95.2796,48.8962],[-95.279,48.8957],[-95.2782,48.8956],[-95.2773,48.8957],[-95.277,48.8958],[-95.2765,48.8962],[-95.2763,48.8963],[-95.2759,48.8962],[-95.2755,48.8959],[-95.2749,48.8956],[-95.2748,48.8951],[-95.2753,48.8943],[-95.2751,48.8938],[-95.2745,48.8931],[-95.2724,48.8921],[-95.2713,48.8915],[-95.268,48.8905],[-95.2677,48.8903],[-95.2674,48.89],[-95.2666,48.8894],[-95.2654,48.8888],[-95.265,48.8886],[-95.2646,48.8885],[-95.2639,48.8883],[-95.2635,48.888],[-95.2627,48.8877],[-95.2585,48.8867],[-95.2585,48.8867],[-95.257,48.8858],[-95.256,48.885],[-95.2548,48.8845],[-95.2517,48.8839],[-95.2507,48.8836],[-95.2502,48.8835],[-95.2496,48.8834],[-95.2485,48.8832],[-95.248,48.8836],[-95.2472,48.8835],[-95.2458,48.8829],[-95.2439,48.8823],[-95.2429,48.8822],[-95.2429,48.8822],[-95.2423,48.8821],[-95.2407,48.8821],[-95.2391,48.8819],[-95.2381,48.8817],[-95.2356,48.8815],[-95.2335,48.8814],[-95.231,48.8814],[-95.2287,48.8815],[-95.2265,48.8816],[-95.2252,48.8819],[-95.2212,48.883],[-95.2208,48.8831],[-95.2207,48.8831],[-95.22,48.8831],[-95.2193,48.8832],[-95.2188,48.8835],[-95.217,48.8835],[-95.2159,48.8839],[-95.2151,48.884],[-95.2144,48.8843],[-95.2122,48.8842],[-95.2117,48.8847],[-95.2115,48.8847],[-95.2112,48.8848],[-95.2085,48.8846],[-95.2059,48.8848],[-95.2024,48.8852],[-95.2009,48.8855],[-95.2005,48.8856],[-95.1986,48.8855],[-95.1956,48.8862],[-95.1924,48.8865],[-95.1919,48.8866],[-95.1913,48.8868],[-95.1901,48.887],[-95.1889,48.8873],[-95.1877,48.8874],[-95.1863,48.8877],[-95.1851,48.8882],[-95.1819,48.8888],[-95.1797,48.889],[-95.1791,48.889],[-95.1764,48.8893],[-95.173,48.8897],[-95.1701,48.8902],[-95.1674,48.8907],[-95.1648,48.8913],[-95.1641,48.8917],[-95.1618,48.892],[-95.1602,48.892],[-95.1579,48.8919],[-95.1564,48.8919],[-95.1555,48.892],[-95.1528,48.8921],[-95.1508,48.8922],[-95.1483,48.8923],[-95.1469,48.8927],[-95.1459,48.8929],[-95.1438,48.8934],[-95.1436,48.8937],[-95.1404,48.8943],[-95.1381,48.8949],[-95.1355,48.8959],[-95.1351,48.8963],[-95.1348,48.8963],[-95.1343,48.8963],[-95.1337,48.8969],[-95.1322,48.8973],[-95.1312,48.8975],[-95.1252,48.8998],[-95.1239,48.9001],[-95.1233,48.9004],[-95.1228,48.9006],[-95.1214,48.9013],[-95.121,48.9016],[-95.1205,48.9017],[-95.1204,48.9019],[-95.1182,48.9029],[-95.1163,48.9037],[-95.1151,48.9046],[-95.1144,48.9052],[-95.114,48.9061],[-95.1141,48.9064],[-95.1137,48.9069],[-95.1132,48.9071],[-95.113,48.9072],[-95.1126,48.9073],[-95.1107,48.9082],[-95.1096,48.9089],[-95.108,48.9099],[-95.1056,48.9113],[-95.1042,48.9121],[-95.1032,48.9127],[-95.102,48.9132],[-95.1008,48.9142],[-95.0981,48.9159],[-95.098,48.916],[-95.0975,48.9164],[-95.0971,48.9172],[-95.097,48.9176],[-95.0961,48.9181],[-95.0946,48.9191],[-95.0944,48.9193],[-95.0927,48.9204],[-95.0919,48.9207],[-95.0914,48.9208],[-95.0914,48.916],[-95.0912,48.9014],[-95.0911,48.8869],[-95.0908,48.8724],[-95.0908,48.858],[-95.0907,48.8436],[-95.0908,48.8291],[-95.0909,48.8147],[-95.0903,48.8],[-95.0903,48.7855],[-95.0903,48.7711],[-95.0901,48.7566],[-95.0901,48.7421],[-95.0899,48.7277],[-95.0898,48.713],[-95.1046,48.7129],[-95.1104,48.7129],[-95.1119,48.7129],[-95.1259,48.7129],[-95.1297,48.713],[-95.1333,48.713],[-95.1477,48.7129],[-95.1554,48.7129],[-95.1697,48.7129],[-95.1773,48.713],[-95.1917,48.713],[-95.1991,48.713],[-95.2112,48.713],[-95.2206,48.713],[-95.2331,48.713],[-95.2427,48.713],[-95.255,48.713],[-95.2645,48.713],[-95.2656,48.713],[-95.2767,48.713],[-95.2866,48.713],[-95.299,48.713],[-95.3051,48.713],[-95.3084,48.713],[-95.3205,48.713],[-95.3302,48.713],[-95.3425,48.7131],[-95.3425,48.6995],[-95.3424,48.6849],[-95.3423,48.6705],[-95.3424,48.6561],[-95.3425,48.6415],[-95.3426,48.6271],[-95.3424,48.6127],[-95.3426,48.5979],[-95.3423,48.5836],[-95.3423,48.5691],[-95.3424,48.5548],[-95.3425,48.5402],[-95.3628,48.5404],[-95.364,48.5403],[-95.3844,48.5402],[-95.386,48.5402],[-95.4061,48.5402],[-95.4078,48.5402],[-95.4279,48.54],[-95.4297,48.5399],[-95.4494,48.5399],[-95.4513,48.5399],[-95.4712,48.5396],[-95.4726,48.5396],[-95.493,48.5392],[-95.495,48.5392],[-95.5143,48.539],[-95.5163,48.539],[-95.5365,48.5389],[-95.5383,48.5389],[-95.558,48.5388],[-95.5603,48.5388],[-95.5801,48.5387],[-95.5821,48.5387],[-95.6023,48.5389],[-95.6232,48.5391],[-95.6447,48.5393],[-95.6666,48.5394],[-95.6886,48.5395],[-95.7102,48.5395],[-95.7322,48.54],[-95.7539,48.5404],[-95.7758,48.5406],[-95.7976,48.5405],[-95.8192,48.5404],[-95.8411,48.5406],[-95.8621,48.5414],[-95.8829,48.5419],[-95.8851,48.542],[-95.8986,48.5421],[-95.9046,48.5422],[-95.9064,48.5422],[-95.9269,48.5421],[-95.9486,48.5425],[-95.9498,48.5425],[-95.9704,48.543],[-95.9936,48.5435],[-96.0157,48.5437],[-96.0374,48.5438],[-96.0592,48.5437],[-96.0812,48.5436],[-96.1026,48.5438],[-96.1264,48.5439],[-96.1486,48.5442],[-96.1702,48.5445],[-96.1921,48.5446],[-96.2141,48.5449],[-96.2358,48.5452],[-96.2576,48.545],[-96.2794,48.5449],[-96.301,48.5448],[-96.3231,48.5446],[-96.3448,48.5444],[-96.3667,48.5443],[-96.3882,48.5442],[-96.3879,48.5588],[-96.3882,48.5733],[-96.3884,48.5877],[-96.3891,48.6024],[-96.389,48.6165],[-96.388,48.6313],[-96.3879,48.6454],[-96.3877,48.6599],[-96.3871,48.6741],[-96.3874,48.6887],[-96.3866,48.703],[-96.3873,48.7172],[-96.388,48.7172],[-96.4049,48.7172],[-96.4048,48.7318],[-96.4048,48.7465],[-96.4047,48.7607],[-96.4045,48.7758],[-96.4042,48.7903],[-96.4042,48.8048],[-96.4042,48.8198],[-96.4043,48.8343],[-96.4045,48.8491],[-96.4047,48.8635],[-96.405,48.878],[-96.405,48.8926],[-96.4053,48.9068],[-96.4053,48.9081],[-96.4053,48.9137],[-96.4054,48.9214],[-96.4054,48.9225],[-96.4053,48.936],[-96.4053,48.9371],[-96.4053,48.9504],[-96.4053,48.9515],[-96.4053,48.9648],[-96.4053,48.9658],[-96.4053,48.9705],[-96.4054,48.9793],[-96.4054,48.9803],[-96.4054,48.994],[-96.4054,48.9947],[-96.4054,49.0001]]],"type":"Polygon"},"id":"68","properties":{"Area":4347098503.12714,"CTYONLY_":4,"Code":"ROSE","LASTMOD":"2001-04-12T09:32:44Z","Name":"Roseau","Perimiter":302590.75293},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&filter=CTYONLY_%3D1%2B3","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&filter=CTYONLY_%3D1%2B3","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":1,"numberReturned":1,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_text_and_false.json.txt b/msautotest/api/expected/ogcapi_cql2_text_and_false.json.txt new file mode 100644 index 0000000000..1c2a0215d1 --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_text_and_false.json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 0 +OGC-NumberReturned: 0 + +{"features":[],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&filter=Name%3D'Rice'%20AND%201%3D0","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&filter=Name%3D'Rice'%20AND%201%3D0","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":0,"numberReturned":0,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_text_and_issue_GHSA_v4x2_j2g2_rxwp.json.txt b/msautotest/api/expected/ogcapi_cql2_text_and_issue_GHSA_v4x2_j2g2_rxwp.json.txt new file mode 100644 index 0000000000..f397f48b9a --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_text_and_issue_GHSA_v4x2_j2g2_rxwp.json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 0 +OGC-NumberReturned: 0 + +{"features":[],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&filter=1%3D1%20AND%20(1%3D1%20AND%201%3D0)","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&filter=1%3D1%20AND%20(1%3D1%20AND%201%3D0)","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":0,"numberReturned":0,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_text_and_query_param_filter.json.txt b/msautotest/api/expected/ogcapi_cql2_text_and_query_param_filter.json.txt new file mode 100644 index 0000000000..ede7c6860f --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_text_and_query_param_filter.json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 1 +OGC-NumberReturned: 1 + +{"features":[{"geometry":{"coordinates":[[[-93.5242,44.5436],[-93.5225,44.5436],[-93.504,44.5438],[-93.5018,44.5438],[-93.4835,44.5438],[-93.4817,44.5438],[-93.4734,44.5438],[-93.4632,44.5438],[-93.4609,44.5438],[-93.4429,44.5438],[-93.4408,44.5438],[-93.4326,44.5438],[-93.4226,44.5439],[-93.4206,44.5439],[-93.4024,44.5439],[-93.4003,44.5439],[-93.383,44.544],[-93.38,44.544],[-93.3627,44.5441],[-93.3596,44.5441],[-93.3556,44.5441],[-93.3424,44.5442],[-93.3395,44.5442],[-93.3221,44.544],[-93.3191,44.544],[-93.3128,44.544],[-93.3019,44.544],[-93.2988,44.544],[-93.2813,44.544],[-93.2814,44.5298],[-93.2815,44.5153],[-93.2815,44.501],[-93.2815,44.4865],[-93.2817,44.472],[-93.2618,44.4718],[-93.2415,44.4716],[-93.2213,44.4714],[-93.2008,44.4714],[-93.1808,44.4713],[-93.1605,44.4713],[-93.1408,44.4712],[-93.1206,44.4713],[-93.1002,44.4718],[-93.0799,44.4719],[-93.0597,44.4718],[-93.0393,44.4719],[-93.0394,44.4576],[-93.0396,44.4432],[-93.0397,44.4287],[-93.0399,44.4143],[-93.04,44.3999],[-93.0401,44.3855],[-93.0402,44.371],[-93.0403,44.3565],[-93.0403,44.3419],[-93.0405,44.3273],[-93.0405,44.3129],[-93.0405,44.2983],[-93.0406,44.2838],[-93.0407,44.2693],[-93.0409,44.2548],[-93.041,44.2402],[-93.0411,44.2257],[-93.0411,44.2113],[-93.0411,44.1968],[-93.0427,44.1968],[-93.0459,44.1968],[-93.0613,44.1967],[-93.0661,44.1967],[-93.0815,44.1967],[-93.0862,44.1967],[-93.1003,44.1967],[-93.1015,44.1967],[-93.1063,44.1967],[-93.1092,44.1967],[-93.1218,44.1967],[-93.1267,44.1967],[-93.1301,44.1967],[-93.1418,44.1967],[-93.1467,44.1967],[-93.1561,44.1966],[-93.1622,44.1966],[-93.1661,44.1966],[-93.1703,44.1966],[-93.1822,44.1966],[-93.1856,44.1966],[-93.1865,44.1966],[-93.2023,44.1966],[-93.2037,44.1966],[-93.2064,44.1966],[-93.2225,44.1966],[-93.2265,44.1966],[-93.2292,44.1966],[-93.2426,44.1966],[-93.2465,44.1966],[-93.255,44.1966],[-93.2629,44.1966],[-93.2664,44.1966],[-93.2767,44.1966],[-93.283,44.1966],[-93.2865,44.1965],[-93.2905,44.1965],[-93.3032,44.1965],[-93.3063,44.1965],[-93.3235,44.1965],[-93.3264,44.1965],[-93.3277,44.1965],[-93.3436,44.1965],[-93.3466,44.1965],[-93.3639,44.1965],[-93.3666,44.1965],[-93.3842,44.1965],[-93.3866,44.1965],[-93.4042,44.1965],[-93.4065,44.1965],[-93.4244,44.1964],[-93.4267,44.1964],[-93.4447,44.1964],[-93.4469,44.1964],[-93.4648,44.1963],[-93.467,44.1963],[-93.4852,44.1964],[-93.4872,44.1964],[-93.5053,44.1963],[-93.507,44.1963],[-93.5255,44.1962],[-93.5253,44.2107],[-93.5251,44.2251],[-93.5251,44.2388],[-93.5251,44.2533],[-93.5252,44.2685],[-93.5252,44.2829],[-93.5252,44.2975],[-93.5252,44.312],[-93.5249,44.3266],[-93.5249,44.3411],[-93.5245,44.3557],[-93.5245,44.3704],[-93.5246,44.3848],[-93.5245,44.3994],[-93.5245,44.4138],[-93.5245,44.4283],[-93.5245,44.4427],[-93.5245,44.4572],[-93.5244,44.4717],[-93.5245,44.4862],[-93.5244,44.5007],[-93.5243,44.5152],[-93.5244,44.5297],[-93.5242,44.5436]]],"type":"Polygon"},"id":"66","properties":{"Area":1335114621.00336,"CTYONLY_":66,"Code":"RICE","LASTMOD":"2010-10-17T00:00:00Z","Name":"Rice","Perimiter":154431.78788},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&Name=Rice&filter=true","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&Name=Rice&filter=true","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":1,"numberReturned":1,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_text_and_query_param_filter2.json.txt b/msautotest/api/expected/ogcapi_cql2_text_and_query_param_filter2.json.txt new file mode 100644 index 0000000000..1bdc1cb03c --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_text_and_query_param_filter2.json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 0 +OGC-NumberReturned: 0 + +{"features":[],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&Name=Rice&filter=false","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&Name=Rice&filter=false","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":0,"numberReturned":0,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_text_and_true.json.txt b/msautotest/api/expected/ogcapi_cql2_text_and_true.json.txt new file mode 100644 index 0000000000..460780eab6 --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_text_and_true.json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 1 +OGC-NumberReturned: 1 + +{"features":[{"geometry":{"coordinates":[[[-93.5242,44.5436],[-93.5225,44.5436],[-93.504,44.5438],[-93.5018,44.5438],[-93.4835,44.5438],[-93.4817,44.5438],[-93.4734,44.5438],[-93.4632,44.5438],[-93.4609,44.5438],[-93.4429,44.5438],[-93.4408,44.5438],[-93.4326,44.5438],[-93.4226,44.5439],[-93.4206,44.5439],[-93.4024,44.5439],[-93.4003,44.5439],[-93.383,44.544],[-93.38,44.544],[-93.3627,44.5441],[-93.3596,44.5441],[-93.3556,44.5441],[-93.3424,44.5442],[-93.3395,44.5442],[-93.3221,44.544],[-93.3191,44.544],[-93.3128,44.544],[-93.3019,44.544],[-93.2988,44.544],[-93.2813,44.544],[-93.2814,44.5298],[-93.2815,44.5153],[-93.2815,44.501],[-93.2815,44.4865],[-93.2817,44.472],[-93.2618,44.4718],[-93.2415,44.4716],[-93.2213,44.4714],[-93.2008,44.4714],[-93.1808,44.4713],[-93.1605,44.4713],[-93.1408,44.4712],[-93.1206,44.4713],[-93.1002,44.4718],[-93.0799,44.4719],[-93.0597,44.4718],[-93.0393,44.4719],[-93.0394,44.4576],[-93.0396,44.4432],[-93.0397,44.4287],[-93.0399,44.4143],[-93.04,44.3999],[-93.0401,44.3855],[-93.0402,44.371],[-93.0403,44.3565],[-93.0403,44.3419],[-93.0405,44.3273],[-93.0405,44.3129],[-93.0405,44.2983],[-93.0406,44.2838],[-93.0407,44.2693],[-93.0409,44.2548],[-93.041,44.2402],[-93.0411,44.2257],[-93.0411,44.2113],[-93.0411,44.1968],[-93.0427,44.1968],[-93.0459,44.1968],[-93.0613,44.1967],[-93.0661,44.1967],[-93.0815,44.1967],[-93.0862,44.1967],[-93.1003,44.1967],[-93.1015,44.1967],[-93.1063,44.1967],[-93.1092,44.1967],[-93.1218,44.1967],[-93.1267,44.1967],[-93.1301,44.1967],[-93.1418,44.1967],[-93.1467,44.1967],[-93.1561,44.1966],[-93.1622,44.1966],[-93.1661,44.1966],[-93.1703,44.1966],[-93.1822,44.1966],[-93.1856,44.1966],[-93.1865,44.1966],[-93.2023,44.1966],[-93.2037,44.1966],[-93.2064,44.1966],[-93.2225,44.1966],[-93.2265,44.1966],[-93.2292,44.1966],[-93.2426,44.1966],[-93.2465,44.1966],[-93.255,44.1966],[-93.2629,44.1966],[-93.2664,44.1966],[-93.2767,44.1966],[-93.283,44.1966],[-93.2865,44.1965],[-93.2905,44.1965],[-93.3032,44.1965],[-93.3063,44.1965],[-93.3235,44.1965],[-93.3264,44.1965],[-93.3277,44.1965],[-93.3436,44.1965],[-93.3466,44.1965],[-93.3639,44.1965],[-93.3666,44.1965],[-93.3842,44.1965],[-93.3866,44.1965],[-93.4042,44.1965],[-93.4065,44.1965],[-93.4244,44.1964],[-93.4267,44.1964],[-93.4447,44.1964],[-93.4469,44.1964],[-93.4648,44.1963],[-93.467,44.1963],[-93.4852,44.1964],[-93.4872,44.1964],[-93.5053,44.1963],[-93.507,44.1963],[-93.5255,44.1962],[-93.5253,44.2107],[-93.5251,44.2251],[-93.5251,44.2388],[-93.5251,44.2533],[-93.5252,44.2685],[-93.5252,44.2829],[-93.5252,44.2975],[-93.5252,44.312],[-93.5249,44.3266],[-93.5249,44.3411],[-93.5245,44.3557],[-93.5245,44.3704],[-93.5246,44.3848],[-93.5245,44.3994],[-93.5245,44.4138],[-93.5245,44.4283],[-93.5245,44.4427],[-93.5245,44.4572],[-93.5244,44.4717],[-93.5245,44.4862],[-93.5244,44.5007],[-93.5243,44.5152],[-93.5244,44.5297],[-93.5242,44.5436]]],"type":"Polygon"},"id":"66","properties":{"Area":1335114621.00336,"CTYONLY_":66,"Code":"RICE","LASTMOD":"2010-10-17T00:00:00Z","Name":"Rice","Perimiter":154431.78788},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&filter=Name%3D'Rice'%20AND%201%3D1","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&filter=Name%3D'Rice'%20AND%201%3D1","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":1,"numberReturned":1,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_text_between_json.txt b/msautotest/api/expected/ogcapi_cql2_text_between_json.txt new file mode 100644 index 0000000000..5d161beff2 --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_text_between_json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 3 +OGC-NumberReturned: 3 + +{"features":[{"geometry":{"coordinates":[[[-96.4054,49.0001],[-96.4054,48.9947],[-96.4054,48.994],[-96.4054,48.9803],[-96.4054,48.9793],[-96.4053,48.9705],[-96.4053,48.9658],[-96.4053,48.9648],[-96.4053,48.9515],[-96.4053,48.9504],[-96.4053,48.9371],[-96.4053,48.936],[-96.4054,48.9225],[-96.4054,48.9214],[-96.4053,48.9137],[-96.4053,48.9081],[-96.4053,48.9068],[-96.405,48.8926],[-96.405,48.878],[-96.4047,48.8635],[-96.4045,48.8491],[-96.4043,48.8343],[-96.4042,48.8198],[-96.4042,48.8048],[-96.4042,48.7903],[-96.4045,48.7758],[-96.4047,48.7607],[-96.4048,48.7465],[-96.4048,48.7318],[-96.4049,48.7172],[-96.388,48.7172],[-96.3873,48.7172],[-96.3866,48.703],[-96.3874,48.6887],[-96.3871,48.6741],[-96.3877,48.6599],[-96.3879,48.6454],[-96.388,48.6313],[-96.389,48.6165],[-96.3891,48.6024],[-96.3884,48.5877],[-96.3882,48.5733],[-96.3879,48.5588],[-96.3882,48.5442],[-96.4101,48.544],[-96.4318,48.5438],[-96.4535,48.5436],[-96.4754,48.5435],[-96.4973,48.5434],[-96.518,48.5434],[-96.54,48.5434],[-96.5621,48.5436],[-96.5839,48.5437],[-96.6058,48.5437],[-96.6278,48.5437],[-96.6493,48.5437],[-96.6713,48.5436],[-96.6931,48.5437],[-96.7151,48.5437],[-96.7368,48.5437],[-96.7585,48.5436],[-96.7803,48.5435],[-96.8023,48.5436],[-96.824,48.5436],[-96.8459,48.5434],[-96.8678,48.5433],[-96.8896,48.5433],[-96.9115,48.5432],[-96.9138,48.5433],[-96.9331,48.5435],[-96.9551,48.5437],[-96.9768,48.544],[-96.9985,48.5441],[-97.0194,48.5441],[-97.0416,48.5442],[-97.0635,48.5441],[-97.0852,48.5441],[-97.107,48.544],[-97.1287,48.5439],[-97.1509,48.5439],[-97.1631,48.544],[-97.1637,48.5445],[-97.1659,48.5483],[-97.1662,48.5509],[-97.1661,48.5527],[-97.1654,48.5536],[-97.1645,48.554],[-97.1628,48.5543],[-97.1613,48.5539],[-97.1592,48.5528],[-97.1577,48.5518],[-97.1557,48.5512],[-97.1538,48.5513],[-97.1513,48.5515],[-97.1507,48.5515],[-97.1493,48.5516],[-97.1474,48.5516],[-97.1444,48.5514],[-97.1407,48.5515],[-97.1387,48.5522],[-97.1379,48.553],[-97.1379,48.5542],[-97.1391,48.5554],[-97.141,48.5566],[-97.1426,48.5571],[-97.1464,48.5573],[-97.1505,48.5574],[-97.1515,48.5574],[-97.1551,48.5574],[-97.1578,48.5573],[-97.1606,48.5571],[-97.1631,48.5571],[-97.1646,48.5572],[-97.167,48.5575],[-97.1697,48.5584],[-97.1721,48.5591],[-97.1727,48.5593],[-97.174,48.5599],[-97.1749,48.5606],[-97.1753,48.5614],[-97.1754,48.5623],[-97.1749,48.5631],[-97.1744,48.5639],[-97.1723,48.5648],[-97.1721,48.5648],[-97.1706,48.5652],[-97.1687,48.5655],[-97.167,48.5658],[-97.1651,48.5659],[-97.1613,48.5661],[-97.1541,48.5669],[-97.153,48.5671],[-97.1516,48.5677],[-97.1503,48.5688],[-97.1496,48.5695],[-97.1487,48.5707],[-97.1477,48.5727],[-97.1477,48.5728],[-97.1476,48.5731],[-97.1483,48.5763],[-97.15,48.5775],[-97.1501,48.5775],[-97.1548,48.5779],[-97.1592,48.5785],[-97.1605,48.58],[-97.16,48.5816],[-97.1578,48.5826],[-97.1562,48.5828],[-97.1541,48.5826],[-97.1524,48.5823],[-97.15,48.5815],[-97.1494,48.5813],[-97.1484,48.5811],[-97.1449,48.5815],[-97.1436,48.5824],[-97.1431,48.5834],[-97.1429,48.5838],[-97.142,48.5876],[-97.1418,48.5886],[-97.1415,48.5909],[-97.1422,48.5926],[-97.1433,48.5936],[-97.1451,48.594],[-97.1471,48.594],[-97.1497,48.5937],[-97.1525,48.594],[-97.1536,48.5949],[-97.1535,48.5957],[-97.1527,48.5962],[-97.1524,48.5969],[-97.1516,48.598],[-97.1498,48.5981],[-97.1497,48.5981],[-97.1463,48.5977],[-97.1443,48.5981],[-97.143,48.5987],[-97.1416,48.6002],[-97.1403,48.6021],[-97.14,48.6025],[-97.138,48.6044],[-97.1359,48.6054],[-97.1345,48.6065],[-97.1341,48.6075],[-97.1349,48.6082],[-97.1358,48.6086],[-97.137,48.6088],[-97.1396,48.6086],[-97.1443,48.6078],[-97.1474,48.6081],[-97.1494,48.6089],[-97.1495,48.609],[-97.1505,48.6115],[-97.1501,48.6124],[-97.1493,48.6129],[-97.1478,48.6138],[-97.145,48.6146],[-97.1408,48.6149],[-97.137,48.6144],[-97.134,48.6136],[-97.1319,48.6133],[-97.1309,48.6137],[-97.1289,48.614],[-97.1286,48.6153],[-97.1293,48.6168],[-97.1295,48.617],[-97.1311,48.6184],[-97.1342,48.6199],[-97.1353,48.6212],[-97.1346,48.6224],[-97.133,48.6228],[-97.131,48.6227],[-97.1291,48.6222],[-97.1277,48.6212],[-97.1274,48.621],[-97.1259,48.6195],[-97.1253,48.619],[-97.1243,48.6183],[-97.1231,48.6178],[-97.1216,48.6176],[-97.12,48.6178],[-97.1193,48.6182],[-97.1186,48.6191],[-97.1183,48.6198],[-97.1186,48.6209],[-97.1198,48.6221],[-97.1209,48.6232],[-97.1212,48.6233],[-97.122,48.624],[-97.1228,48.6245],[-97.1236,48.625],[-97.1241,48.6254],[-97.1245,48.6257],[-97.1249,48.6259],[-97.1253,48.6261],[-97.126,48.6264],[-97.1266,48.6266],[-97.1272,48.627],[-97.1279,48.6273],[-97.1288,48.6278],[-97.1296,48.6282],[-97.1302,48.6288],[-97.1305,48.6292],[-97.1307,48.6297],[-97.131,48.6303],[-97.131,48.6304],[-97.131,48.6308],[-97.131,48.6315],[-97.1309,48.6317],[-97.1307,48.6321],[-97.1304,48.6325],[-97.1301,48.6326],[-97.1297,48.6328],[-97.1293,48.6329],[-97.129,48.633],[-97.1281,48.6332],[-97.128,48.6333],[-97.1275,48.6333],[-97.1253,48.6334],[-97.1235,48.6333],[-97.1216,48.6327],[-97.1181,48.6308],[-97.1176,48.6307],[-97.115,48.6299],[-97.1133,48.63],[-97.1115,48.6303],[-97.1107,48.6308],[-97.1104,48.6309],[-97.1095,48.6315],[-97.1084,48.6327],[-97.1082,48.6344],[-97.1086,48.6363],[-97.1096,48.6389],[-97.1109,48.6407],[-97.1119,48.6416],[-97.1144,48.6433],[-97.115,48.6438],[-97.115,48.6446],[-97.1149,48.6452],[-97.1123,48.6457],[-97.1112,48.6459],[-97.1093,48.6465],[-97.1078,48.6478],[-97.1069,48.6491],[-97.1066,48.6501],[-97.1061,48.6519],[-97.1059,48.6527],[-97.1045,48.6545],[-97.1017,48.6563],[-97.0987,48.6593],[-97.0986,48.6604],[-97.0985,48.6613],[-97.0992,48.6625],[-97.1019,48.6636],[-97.106,48.663],[-97.1062,48.663],[-97.1082,48.6634],[-97.1087,48.6645],[-97.1061,48.6654],[-97.1057,48.6655],[-97.102,48.6667],[-97.1,48.668],[-97.0998,48.6714],[-97.1002,48.675],[-97.1003,48.6757],[-97.1008,48.6787],[-97.1011,48.6808],[-97.1003,48.6828],[-97.0985,48.683],[-97.0946,48.6822],[-97.0926,48.6821],[-97.0904,48.6828],[-97.0898,48.6841],[-97.0899,48.6852],[-97.091,48.6861],[-97.093,48.687],[-97.0951,48.6876],[-97.099,48.6884],[-97.1024,48.6893],[-97.103,48.6894],[-97.1059,48.6903],[-97.1064,48.6905],[-97.1086,48.6915],[-97.111,48.6939],[-97.113,48.6964],[-97.1148,48.6981],[-97.1182,48.7005],[-97.1198,48.7018],[-97.1201,48.7039],[-97.1194,48.7041],[-97.1182,48.7046],[-97.1143,48.7052],[-97.1117,48.7056],[-97.11,48.7063],[-97.1098,48.7083],[-97.1113,48.7094],[-97.1134,48.7101],[-97.1157,48.7105],[-97.1174,48.7111],[-97.119,48.7119],[-97.1212,48.7136],[-97.1223,48.716],[-97.1229,48.7168],[-97.1231,48.7172],[-97.1243,48.7192],[-97.1253,48.7201],[-97.1253,48.7203],[-97.126,48.7207],[-97.1263,48.7212],[-97.1272,48.7215],[-97.128,48.722],[-97.1282,48.7221],[-97.1288,48.7225],[-97.1297,48.7229],[-97.131,48.7233],[-97.1321,48.7238],[-97.1331,48.7242],[-97.1345,48.7248],[-97.136,48.7257],[-97.1369,48.7263],[-97.1375,48.727],[-97.1376,48.7274],[-97.1376,48.7278],[-97.1373,48.7283],[-97.137,48.7284],[-97.1365,48.7285],[-97.136,48.7287],[-97.1352,48.7287],[-97.1341,48.7289],[-97.1333,48.7291],[-97.1328,48.7292],[-97.132,48.7294],[-97.1312,48.7295],[-97.1308,48.7296],[-97.1299,48.7299],[-97.1294,48.7304],[-97.1288,48.7308],[-97.1286,48.7312],[-97.1286,48.7315],[-97.1286,48.7316],[-97.1286,48.7318],[-97.1285,48.7322],[-97.1286,48.7326],[-97.1286,48.7328],[-97.1287,48.7331],[-97.129,48.7335],[-97.1295,48.7339],[-97.1298,48.7341],[-97.1316,48.7347],[-97.1322,48.7348],[-97.1334,48.7347],[-97.1351,48.7345],[-97.1369,48.7345],[-97.1383,48.7345],[-97.1396,48.7347],[-97.1402,48.7349],[-97.1412,48.7354],[-97.1419,48.7359],[-97.1422,48.7367],[-97.1423,48.7372],[-97.1421,48.7381],[-97.1414,48.7385],[-97.1408,48.7387],[-97.1404,48.7389],[-97.1399,48.7393],[-97.1392,48.7397],[-97.1381,48.7408],[-97.1372,48.742],[-97.1366,48.7435],[-97.1365,48.745],[-97.1365,48.7459],[-97.1366,48.7466],[-97.1369,48.748],[-97.1375,48.7492],[-97.1379,48.75],[-97.1385,48.7504],[-97.1391,48.7507],[-97.1396,48.7508],[-97.1401,48.7509],[-97.141,48.751],[-97.142,48.751],[-97.143,48.7509],[-97.1444,48.7507],[-97.1457,48.7506],[-97.1466,48.7505],[-97.1476,48.7505],[-97.1491,48.7506],[-97.1497,48.7508],[-97.1503,48.7509],[-97.1515,48.7515],[-97.1521,48.752],[-97.153,48.7529],[-97.1539,48.7542],[-97.1545,48.7553],[-97.1547,48.7558],[-97.1548,48.7562],[-97.1548,48.7569],[-97.1548,48.7576],[-97.1546,48.758],[-97.1542,48.7587],[-97.1535,48.7593],[-97.1528,48.7598],[-97.1519,48.7601],[-97.1508,48.7605],[-97.1503,48.7606],[-97.1501,48.7607],[-97.1475,48.7616],[-97.1473,48.7617],[-97.1469,48.762],[-97.1462,48.7626],[-97.1461,48.7628],[-97.1459,48.7633],[-97.1456,48.7643],[-97.1456,48.765],[-97.146,48.7658],[-97.1476,48.7673],[-97.1487,48.7681],[-97.15,48.7692],[-97.1501,48.7693],[-97.1506,48.77],[-97.1512,48.7712],[-97.1519,48.7721],[-97.1525,48.7727],[-97.1529,48.7728],[-97.1559,48.7731],[-97.1567,48.7732],[-97.1578,48.7735],[-97.1582,48.7737],[-97.1587,48.7742],[-97.1589,48.7746],[-97.159,48.7751],[-97.159,48.7751],[-97.159,48.7754],[-97.1589,48.776],[-97.1584,48.7766],[-97.1579,48.7769],[-97.1573,48.7772],[-97.1557,48.7776],[-97.1544,48.7778],[-97.1534,48.778],[-97.1522,48.7783],[-97.1509,48.7787],[-97.1501,48.7789],[-97.1497,48.779],[-97.1483,48.7797],[-97.1477,48.7801],[-97.1473,48.7807],[-97.1472,48.7811],[-97.1473,48.7816],[-97.1478,48.7821],[-97.1486,48.7824],[-97.1495,48.7826],[-97.1501,48.7826],[-97.1503,48.7826],[-97.1513,48.7825],[-97.1533,48.7824],[-97.1547,48.7824],[-97.1559,48.7825],[-97.1571,48.7827],[-97.1583,48.783],[-97.1591,48.7834],[-97.1595,48.7838],[-97.1597,48.7843],[-97.1598,48.7848],[-97.1596,48.7853],[-97.1593,48.786],[-97.1591,48.7863],[-97.1586,48.7869],[-97.1577,48.7877],[-97.1574,48.7882],[-97.1573,48.7884],[-97.1572,48.7887],[-97.1571,48.7894],[-97.157,48.7895],[-97.157,48.7901],[-97.1572,48.7906],[-97.1575,48.7909],[-97.1581,48.7912],[-97.1586,48.7913],[-97.1592,48.7915],[-97.1595,48.7915],[-97.1611,48.7915],[-97.1618,48.7914],[-97.1645,48.7911],[-97.1648,48.7911],[-97.1657,48.7911],[-97.1664,48.7912],[-97.1672,48.7913],[-97.1714,48.7921],[-97.1718,48.7923],[-97.1721,48.7924],[-97.1731,48.7929],[-97.1737,48.7933],[-97.174,48.7937],[-97.1741,48.7942],[-97.1742,48.7947],[-97.1742,48.7951],[-97.1739,48.7954],[-97.1734,48.7958],[-97.1726,48.7963],[-97.1717,48.7966],[-97.1716,48.7966],[-97.171,48.7967],[-97.1701,48.7967],[-97.1688,48.7966],[-97.1673,48.7964],[-97.1665,48.7962],[-97.1654,48.7962],[-97.1648,48.7962],[-97.1638,48.7963],[-97.1631,48.7966],[-97.1625,48.7969],[-97.162,48.7974],[-97.1617,48.7979],[-97.1617,48.7984],[-97.1619,48.7988],[-97.1621,48.7994],[-97.1626,48.8001],[-97.1633,48.8007],[-97.1642,48.8011],[-97.1652,48.8014],[-97.166,48.8015],[-97.1668,48.8016],[-97.1675,48.8016],[-97.1685,48.8016],[-97.1698,48.8013],[-97.1706,48.8011],[-97.1714,48.8008],[-97.1715,48.8008],[-97.1724,48.8004],[-97.1731,48.8],[-97.1742,48.7992],[-97.175,48.7986],[-97.1754,48.7983],[-97.1757,48.798],[-97.1761,48.7977],[-97.1768,48.7974],[-97.1773,48.7973],[-97.1779,48.7972],[-97.1787,48.7972],[-97.1795,48.7972],[-97.1801,48.7973],[-97.1807,48.7975],[-97.1811,48.7978],[-97.1815,48.7982],[-97.1816,48.7986],[-97.1817,48.7991],[-97.1815,48.7995],[-97.1813,48.8],[-97.1808,48.8004],[-97.1801,48.8008],[-97.1791,48.8012],[-97.1779,48.8015],[-97.1769,48.8017],[-97.1764,48.8018],[-97.1756,48.8021],[-97.1748,48.8023],[-97.1725,48.8032],[-97.1713,48.8036],[-97.171,48.8037],[-97.1706,48.8039],[-97.1694,48.8043],[-97.1682,48.8046],[-97.1675,48.8048],[-97.1666,48.805],[-97.1655,48.8052],[-97.1638,48.8055],[-97.161,48.8059],[-97.1605,48.8061],[-97.1597,48.8064],[-97.159,48.8067],[-97.1583,48.8072],[-97.1579,48.8077],[-97.1577,48.8082],[-97.1576,48.8089],[-97.1578,48.8098],[-97.158,48.8104],[-97.1586,48.811],[-97.159,48.8111],[-97.161,48.8117],[-97.1617,48.8119],[-97.1625,48.812],[-97.1636,48.8121],[-97.1644,48.8121],[-97.1651,48.812],[-97.1666,48.8118],[-97.168,48.8116],[-97.169,48.8114],[-97.17,48.8114],[-97.1713,48.8115],[-97.1715,48.8115],[-97.1726,48.8117],[-97.1731,48.8118],[-97.174,48.8122],[-97.1761,48.8132],[-97.1776,48.8141],[-97.1784,48.8145],[-97.1797,48.8149],[-97.1807,48.8151],[-97.1821,48.8153],[-97.1828,48.8153],[-97.184,48.8152],[-97.1848,48.8151],[-97.186,48.8147],[-97.1868,48.8145],[-97.1873,48.8143],[-97.1879,48.8143],[-97.1883,48.8143],[-97.1889,48.8143],[-97.1894,48.8144],[-97.1898,48.8146],[-97.1901,48.8148],[-97.1903,48.8153],[-97.1904,48.8156],[-97.1903,48.8159],[-97.19,48.8163],[-97.1893,48.8167],[-97.1885,48.8171],[-97.1879,48.8173],[-97.1866,48.8176],[-97.1857,48.8177],[-97.1847,48.8179],[-97.184,48.8181],[-97.1833,48.8184],[-97.1817,48.8189],[-97.1809,48.8193],[-97.1801,48.8199],[-97.1793,48.8207],[-97.1787,48.8216],[-97.178,48.8232],[-97.1777,48.824],[-97.1776,48.8245],[-97.1777,48.8249],[-97.178,48.8255],[-97.1782,48.8258],[-97.1786,48.8262],[-97.1794,48.8268],[-97.1822,48.8288],[-97.1837,48.8299],[-97.1841,48.8304],[-97.1847,48.8314],[-97.1848,48.8319],[-97.1849,48.8326],[-97.1849,48.8327],[-97.1848,48.833],[-97.1846,48.8336],[-97.1842,48.8341],[-97.1837,48.8345],[-97.183,48.8348],[-97.1822,48.835],[-97.1813,48.8351],[-97.1799,48.8352],[-97.1783,48.8353],[-97.1779,48.8354],[-97.1772,48.8356],[-97.1757,48.8362],[-97.1753,48.8364],[-97.1747,48.8369],[-97.1742,48.8373],[-97.1739,48.8378],[-97.1738,48.8384],[-97.1738,48.839],[-97.1739,48.8406],[-97.1743,48.8427],[-97.1747,48.8438],[-97.175,48.8442],[-97.1755,48.8447],[-97.1761,48.8452],[-97.1767,48.8455],[-97.1771,48.8456],[-97.1779,48.8458],[-97.1795,48.8459],[-97.1808,48.846],[-97.1817,48.8462],[-97.1823,48.8464],[-97.1827,48.8468],[-97.1829,48.847],[-97.1829,48.8471],[-97.1829,48.8473],[-97.1826,48.8476],[-97.1821,48.8479],[-97.1816,48.848],[-97.1809,48.8481],[-97.1793,48.8482],[-97.178,48.8483],[-97.1767,48.8484],[-97.1759,48.8486],[-97.1753,48.8487],[-97.1747,48.849],[-97.1742,48.8493],[-97.1737,48.8497],[-97.1733,48.8502],[-97.173,48.8506],[-97.173,48.8508],[-97.173,48.8511],[-97.173,48.8516],[-97.1732,48.8522],[-97.1737,48.8527],[-97.1746,48.8534],[-97.1771,48.855],[-97.1784,48.8561],[-97.1786,48.8563],[-97.179,48.8569],[-97.1793,48.8576],[-97.1794,48.8583],[-97.1794,48.859],[-97.1792,48.8606],[-97.179,48.8615],[-97.179,48.862],[-97.1791,48.8626],[-97.1794,48.863],[-97.1801,48.8636],[-97.1811,48.864],[-97.1818,48.8641],[-97.1827,48.8641],[-97.1839,48.864],[-97.1855,48.8637],[-97.1871,48.8633],[-97.1877,48.8631],[-97.1883,48.8631],[-97.1891,48.8631],[-97.1896,48.8633],[-97.19,48.8635],[-97.1903,48.8639],[-97.1905,48.8644],[-97.1905,48.8648],[-97.1904,48.8651],[-97.1901,48.8657],[-97.1899,48.8661],[-97.1895,48.8665],[-97.189,48.867],[-97.1884,48.8675],[-97.1851,48.8694],[-97.1813,48.8718],[-97.1788,48.8736],[-97.1785,48.8738],[-97.1782,48.8741],[-97.1781,48.8743],[-97.1779,48.8745],[-97.1778,48.8747],[-97.1777,48.8749],[-97.1777,48.875],[-97.1778,48.875],[-97.1778,48.8754],[-97.1779,48.8757],[-97.1782,48.8761],[-97.1786,48.8765],[-97.1792,48.8769],[-97.1798,48.8771],[-97.1808,48.8772],[-97.1823,48.8772],[-97.1852,48.8768],[-97.1869,48.8765],[-97.1881,48.8765],[-97.1891,48.8766],[-97.1904,48.8769],[-97.1933,48.8779],[-97.1944,48.8783],[-97.1957,48.8788],[-97.1972,48.8794],[-97.1981,48.8799],[-97.1988,48.8805],[-97.1995,48.8812],[-97.1999,48.8818],[-97.1999,48.8821],[-97.2,48.8827],[-97.1998,48.8832],[-97.1997,48.8836],[-97.199,48.8845],[-97.1978,48.8859],[-97.1975,48.8865],[-97.1974,48.8868],[-97.1973,48.8872],[-97.1973,48.8874],[-97.1974,48.8877],[-97.1975,48.8881],[-97.1983,48.8889],[-97.2002,48.8903],[-97.2004,48.8904],[-97.2009,48.8908],[-97.2014,48.8912],[-97.2017,48.8915],[-97.2017,48.8919],[-97.2016,48.8922],[-97.2013,48.8925],[-97.201,48.8926],[-97.2001,48.8926],[-97.1994,48.8926],[-97.1985,48.8925],[-97.198,48.8924],[-97.1973,48.892],[-97.1957,48.8916],[-97.1946,48.8915],[-97.1944,48.8914],[-97.1937,48.8914],[-97.1927,48.8915],[-97.1921,48.8917],[-97.1916,48.8919],[-97.1905,48.8926],[-97.1901,48.8932],[-97.1898,48.8938],[-97.1897,48.8944],[-97.1897,48.8947],[-97.1898,48.8951],[-97.1899,48.8954],[-97.1903,48.896],[-97.1911,48.8967],[-97.1919,48.8974],[-97.1925,48.8979],[-97.1935,48.8985],[-97.1941,48.8988],[-97.1945,48.8989],[-97.1966,48.8997],[-97.1992,48.9004],[-97.2009,48.9009],[-97.2022,48.9013],[-97.2048,48.9018],[-97.2055,48.902],[-97.207,48.9025],[-97.2076,48.9027],[-97.2082,48.9029],[-97.2088,48.9032],[-97.2093,48.9036],[-97.21,48.904],[-97.2105,48.9044],[-97.211,48.905],[-97.2114,48.9056],[-97.2122,48.9069],[-97.2125,48.9075],[-97.2127,48.9082],[-97.2127,48.909],[-97.2125,48.9099],[-97.212,48.911],[-97.2116,48.9121],[-97.2111,48.913],[-97.2108,48.914],[-97.2106,48.9148],[-97.2106,48.9153],[-97.2109,48.9162],[-97.2111,48.9167],[-97.2115,48.9172],[-97.2118,48.9175],[-97.2122,48.9177],[-97.2129,48.9181],[-97.2149,48.9187],[-97.2163,48.9191],[-97.2164,48.9191],[-97.2171,48.9194],[-97.2179,48.9198],[-97.2189,48.9205],[-97.2196,48.9215],[-97.2198,48.9222],[-97.2199,48.923],[-97.2197,48.9237],[-97.2191,48.9249],[-97.2183,48.9262],[-97.2172,48.9277],[-97.2163,48.9286],[-97.2159,48.9289],[-97.2149,48.9301],[-97.2146,48.9304],[-97.2145,48.9307],[-97.2144,48.931],[-97.2145,48.9314],[-97.2145,48.9316],[-97.2148,48.9319],[-97.2154,48.9325],[-97.2159,48.9327],[-97.2162,48.9328],[-97.217,48.9328],[-97.2181,48.9327],[-97.2198,48.9325],[-97.2208,48.9325],[-97.2214,48.9325],[-97.2218,48.9326],[-97.2237,48.9332],[-97.2245,48.9337],[-97.2249,48.9339],[-97.225,48.934],[-97.2252,48.9342],[-97.2254,48.9345],[-97.2257,48.9349],[-97.226,48.9353],[-97.2263,48.936],[-97.2267,48.9376],[-97.227,48.9389],[-97.2271,48.9398],[-97.2271,48.941],[-97.227,48.9418],[-97.2266,48.9432],[-97.2264,48.9441],[-97.2263,48.9445],[-97.2264,48.9452],[-97.2265,48.9456],[-97.227,48.9462],[-97.2273,48.9465],[-97.2276,48.9467],[-97.2279,48.9467],[-97.2284,48.9468],[-97.2304,48.9465],[-97.2309,48.9464],[-97.2313,48.9464],[-97.2326,48.9466],[-97.2331,48.9468],[-97.2338,48.9471],[-97.2342,48.9474],[-97.2343,48.948],[-97.2343,48.9485],[-97.2342,48.9488],[-97.2341,48.9491],[-97.2337,48.95],[-97.2332,48.951],[-97.2328,48.9524],[-97.2323,48.954],[-97.2317,48.9558],[-97.2313,48.9568],[-97.2309,48.9578],[-97.2305,48.9585],[-97.23,48.9591],[-97.2288,48.9603],[-97.2282,48.9609],[-97.2278,48.9613],[-97.2276,48.9619],[-97.2276,48.9624],[-97.2279,48.963],[-97.228,48.9631],[-97.2283,48.9634],[-97.2289,48.9639],[-97.2294,48.9641],[-97.23,48.9642],[-97.2323,48.9646],[-97.2355,48.965],[-97.2368,48.9652],[-97.2375,48.9654],[-97.2382,48.966],[-97.2383,48.9661],[-97.2388,48.9666],[-97.2391,48.9676],[-97.2392,48.9687],[-97.239,48.9696],[-97.2387,48.9706],[-97.2383,48.9715],[-97.2381,48.9723],[-97.238,48.9725],[-97.2379,48.9731],[-97.2378,48.9734],[-97.2378,48.9738],[-97.238,48.9752],[-97.238,48.9763],[-97.2381,48.9771],[-97.238,48.9771],[-97.238,48.9841],[-97.2377,48.9849],[-97.2372,48.9857],[-97.2365,48.9867],[-97.2359,48.9874],[-97.2351,48.9881],[-97.2342,48.989],[-97.2335,48.9895],[-97.2331,48.9898],[-97.2317,48.9904],[-97.2301,48.9911],[-97.2293,48.9914],[-97.229,48.9916],[-97.2279,48.9921],[-97.2274,48.9925],[-97.227,48.9929],[-97.2266,48.9933],[-97.2265,48.9938],[-97.2267,48.9941],[-97.227,48.9945],[-97.2273,48.9947],[-97.2287,48.9949],[-97.2304,48.995],[-97.2317,48.9951],[-97.2324,48.9952],[-97.2335,48.9956],[-97.2338,48.9959],[-97.2341,48.9966],[-97.2341,48.997],[-97.234,48.9975],[-97.2337,48.9981],[-97.2332,48.9985],[-97.2323,48.999],[-97.2305,49.0],[-97.2303,49.0001],[-97.2295,49.0005],[-97.2175,49.0005],[-97.2161,49.0005],[-97.2078,49.0005],[-97.2069,49.0005],[-97.1955,49.0005],[-97.1939,49.0005],[-97.1739,49.0005],[-97.1724,49.0005],[-97.1514,49.0005],[-97.1502,49.0005],[-97.1294,49.0004],[-97.1277,49.0004],[-97.1073,49.0004],[-97.1061,49.0004],[-97.0853,49.0004],[-97.084,49.0004],[-97.0633,49.0004],[-97.062,49.0004],[-97.0412,49.0004],[-97.0401,49.0004],[-97.0192,49.0004],[-97.0183,49.0004],[-96.9971,49.0004],[-96.9961,49.0004],[-96.9751,49.0003],[-96.9738,49.0003],[-96.953,49.0003],[-96.9518,49.0003],[-96.931,49.0003],[-96.9299,49.0003],[-96.909,49.0003],[-96.9078,49.0003],[-96.8869,49.0003],[-96.8856,49.0003],[-96.8649,49.0003],[-96.864,49.0003],[-96.8429,49.0003],[-96.8415,49.0003],[-96.8208,49.0003],[-96.8197,49.0003],[-96.8023,49.0002],[-96.8005,49.0002],[-96.8003,49.0002],[-96.7988,49.0002],[-96.7787,49.0002],[-96.7768,49.0002],[-96.7567,49.0002],[-96.7547,49.0002],[-96.7348,49.0002],[-96.7327,49.0002],[-96.7127,49.0002],[-96.7107,49.0002],[-96.6905,49.0002],[-96.6886,49.0002],[-96.6695,49.0002],[-96.6665,49.0002],[-96.6482,49.0002],[-96.6445,49.0002],[-96.6243,49.0002],[-96.6225,49.0002],[-96.6021,49.0002],[-96.6004,49.0002],[-96.58,49.0002],[-96.5784,49.0002],[-96.558,49.0002],[-96.5563,49.0002],[-96.536,49.0002],[-96.5342,49.0002],[-96.5154,49.0002],[-96.5123,49.0002],[-96.4933,49.0002],[-96.49,49.0002],[-96.471,49.0001],[-96.4664,49.0001],[-96.4496,49.0001],[-96.4492,49.0001],[-96.4491,49.0001],[-96.446,49.0001],[-96.4273,49.0001],[-96.4224,49.0001],[-96.4054,49.0001]]],"type":"Polygon"},"id":"35","properties":{"Area":2862183702.23055,"CTYONLY_":3,"Code":"KITT","LASTMOD":"1999-12-31T23:59:59Z","Name":"Kittson","Perimiter":263017.48277},"type":"Feature"},{"geometry":{"coordinates":[[[-96.4054,49.0001],[-96.4019,49.0001],[-96.3825,49.0001],[-96.3783,49.0001],[-96.3606,49.0001],[-96.3579,49.0001],[-96.3385,49.0001],[-96.3343,49.0001],[-96.3166,49.0001],[-96.3138,49.0001],[-96.2945,49.0001],[-96.2902,49.0001],[-96.2725,49.0001],[-96.2698,49.0001],[-96.2494,49.0001],[-96.2461,49.0001],[-96.2274,49.0001],[-96.2257,49.0001],[-96.2057,49.0001],[-96.2021,49.0001],[-96.1837,49.0],[-96.18,49.0],[-96.1617,49.0],[-96.1579,49.0],[-96.1401,49.0],[-96.1359,49.0],[-96.1176,49.0],[-96.1139,49.0],[-96.0957,49.0],[-96.0919,49.0],[-96.0738,49.0],[-96.07,49.0],[-96.0517,49.0],[-96.048,49.0],[-96.0298,49.0],[-96.026,49.0],[-96.0083,49.0],[-96.0045,49.0],[-95.9868,49.0],[-95.9784,49.0],[-95.9776,49.0],[-95.9755,49.0],[-95.9648,48.9999],[-95.9464,48.9999],[-95.943,48.9999],[-95.9225,48.9999],[-95.9211,48.9999],[-95.899,48.9998],[-95.883,48.9998],[-95.8771,48.9998],[-95.8564,48.9998],[-95.855,48.9998],[-95.8342,48.9998],[-95.8184,48.9997],[-95.8126,48.9997],[-95.7906,48.9997],[-95.7833,48.9997],[-95.7684,48.9997],[-95.7479,48.9996],[-95.7466,48.9996],[-95.7253,48.9996],[-95.7066,48.9996],[-95.7032,48.9996],[-95.681,48.9995],[-95.6654,48.9995],[-95.6596,48.9995],[-95.659,48.9995],[-95.6401,48.9995],[-95.6369,48.9995],[-95.6205,48.9994],[-95.615,48.9994],[-95.5948,48.9994],[-95.585,48.9994],[-95.573,48.9994],[-95.551,48.9993],[-95.5495,48.9993],[-95.5294,48.9993],[-95.5164,48.9993],[-95.5072,48.9993],[-95.4849,48.9992],[-95.4834,48.9992],[-95.4635,48.9992],[-95.4508,48.9992],[-95.4418,48.9992],[-95.4245,48.9991],[-95.4197,48.9991],[-95.3977,48.9991],[-95.3953,48.9991],[-95.3765,48.9991],[-95.3759,48.9991],[-95.3753,48.9991],[-95.3542,48.999],[-95.3513,48.999],[-95.3326,48.999],[-95.3286,48.999],[-95.3231,48.999],[-95.3224,48.9984],[-95.3204,48.9976],[-95.3202,48.9973],[-95.3204,48.9964],[-95.3206,48.9961],[-95.3201,48.9956],[-95.3197,48.9954],[-95.3191,48.9953],[-95.3187,48.9956],[-95.3182,48.996],[-95.3179,48.9961],[-95.3178,48.9961],[-95.3178,48.9958],[-95.3181,48.995],[-95.3191,48.9941],[-95.3204,48.9924],[-95.3206,48.9921],[-95.3224,48.9889],[-95.3227,48.9884],[-95.3242,48.9859],[-95.3245,48.985],[-95.3253,48.9832],[-95.3257,48.9814],[-95.3256,48.98],[-95.3255,48.9789],[-95.3257,48.9784],[-95.3253,48.976],[-95.325,48.9743],[-95.3249,48.9738],[-95.3248,48.9728],[-95.3247,48.972],[-95.3241,48.9703],[-95.3232,48.9692],[-95.3227,48.9685],[-95.3212,48.9672],[-95.3207,48.9669],[-95.3201,48.9648],[-95.3198,48.9643],[-95.3193,48.964],[-95.3193,48.9622],[-95.3202,48.9606],[-95.3206,48.9598],[-95.3206,48.9595],[-95.3206,48.959],[-95.3202,48.9581],[-95.3191,48.9569],[-95.3188,48.9562],[-95.3179,48.9559],[-95.3175,48.9552],[-95.3177,48.9545],[-95.3182,48.9535],[-95.3181,48.9531],[-95.3177,48.9525],[-95.3154,48.9513],[-95.3151,48.951],[-95.3141,48.9508],[-95.3131,48.9503],[-95.3125,48.9503],[-95.3123,48.9502],[-95.3119,48.9502],[-95.3119,48.9507],[-95.3129,48.9521],[-95.3129,48.9523],[-95.3126,48.9524],[-95.312,48.9524],[-95.3115,48.952],[-95.3108,48.9512],[-95.3104,48.951],[-95.3097,48.951],[-95.3089,48.9511],[-95.3079,48.9509],[-95.3061,48.9502],[-95.3052,48.9495],[-95.3046,48.9482],[-95.3046,48.947],[-95.305,48.9462],[-95.3053,48.9459],[-95.3061,48.9454],[-95.3068,48.9454],[-95.3069,48.9455],[-95.3069,48.9456],[-95.3063,48.9462],[-95.3062,48.9463],[-95.3061,48.9469],[-95.3062,48.9472],[-95.3062,48.9472],[-95.3071,48.9477],[-95.3081,48.948],[-95.3094,48.9481],[-95.3096,48.9482],[-95.3099,48.9484],[-95.31,48.9485],[-95.3103,48.9485],[-95.3104,48.9484],[-95.3103,48.948],[-95.3096,48.9478],[-95.3092,48.9477],[-95.3079,48.9474],[-95.3071,48.9469],[-95.3071,48.9466],[-95.3074,48.9465],[-95.3078,48.9466],[-95.3085,48.947],[-95.3086,48.9469],[-95.3086,48.9465],[-95.3088,48.9464],[-95.3095,48.9463],[-95.3102,48.9463],[-95.3114,48.9461],[-95.3131,48.946],[-95.3141,48.9457],[-95.3148,48.9452],[-95.3154,48.9448],[-95.3168,48.9431],[-95.3181,48.9421],[-95.3189,48.9419],[-95.3219,48.9412],[-95.3225,48.9409],[-95.3228,48.9403],[-95.3231,48.9389],[-95.3229,48.9373],[-95.3225,48.9358],[-95.3223,48.9355],[-95.3228,48.9344],[-95.3222,48.9327],[-95.3209,48.9307],[-95.3208,48.9305],[-95.3195,48.9285],[-95.3168,48.9245],[-95.315,48.9222],[-95.3141,48.921],[-95.3132,48.9198],[-95.3126,48.919],[-95.3119,48.9178],[-95.3115,48.9172],[-95.3109,48.9163],[-95.3102,48.9155],[-95.3093,48.9149],[-95.3092,48.9149],[-95.3085,48.9146],[-95.3078,48.9141],[-95.3074,48.9135],[-95.3064,48.9129],[-95.3061,48.9128],[-95.3059,48.9127],[-95.3043,48.9119],[-95.3038,48.9114],[-95.3027,48.91],[-95.3017,48.9093],[-95.2999,48.9086],[-95.2978,48.9083],[-95.2973,48.9081],[-95.2973,48.908],[-95.2973,48.9077],[-95.2976,48.9074],[-95.2977,48.9073],[-95.2978,48.9073],[-95.2978,48.9072],[-95.2978,48.9072],[-95.2979,48.9072],[-95.2979,48.9072],[-95.2979,48.9071],[-95.298,48.9071],[-95.298,48.9071],[-95.298,48.9071],[-95.2981,48.907],[-95.2982,48.9068],[-95.2983,48.9068],[-95.2985,48.9065],[-95.2985,48.9064],[-95.2986,48.9063],[-95.2988,48.906],[-95.2989,48.906],[-95.2991,48.9057],[-95.2992,48.9055],[-95.2994,48.9053],[-95.2996,48.9051],[-95.2997,48.905],[-95.2999,48.9048],[-95.2999,48.9048],[-95.2999,48.9048],[-95.3,48.9047],[-95.3,48.9047],[-95.3001,48.9047],[-95.3001,48.9046],[-95.3002,48.9045],[-95.3005,48.904],[-95.2993,48.9035],[-95.2983,48.9028],[-95.298,48.9027],[-95.2976,48.9026],[-95.2967,48.9027],[-95.2949,48.9028],[-95.2941,48.9027],[-95.2937,48.9023],[-95.2935,48.902],[-95.2927,48.9019],[-95.2914,48.9019],[-95.2909,48.9017],[-95.2908,48.9016],[-95.2907,48.9014],[-95.2906,48.9011],[-95.2911,48.9008],[-95.2911,48.9006],[-95.2901,48.9003],[-95.2896,48.9],[-95.289,48.8994],[-95.2882,48.8981],[-95.2879,48.8979],[-95.2872,48.8977],[-95.287,48.8976],[-95.2865,48.8975],[-95.2861,48.8976],[-95.2853,48.8977],[-95.2839,48.8975],[-95.2813,48.8967],[-95.2803,48.8965],[-95.2796,48.8962],[-95.279,48.8957],[-95.2782,48.8956],[-95.2773,48.8957],[-95.277,48.8958],[-95.2765,48.8962],[-95.2763,48.8963],[-95.2759,48.8962],[-95.2755,48.8959],[-95.2749,48.8956],[-95.2748,48.8951],[-95.2753,48.8943],[-95.2751,48.8938],[-95.2745,48.8931],[-95.2724,48.8921],[-95.2713,48.8915],[-95.268,48.8905],[-95.2677,48.8903],[-95.2674,48.89],[-95.2666,48.8894],[-95.2654,48.8888],[-95.265,48.8886],[-95.2646,48.8885],[-95.2639,48.8883],[-95.2635,48.888],[-95.2627,48.8877],[-95.2585,48.8867],[-95.2585,48.8867],[-95.257,48.8858],[-95.256,48.885],[-95.2548,48.8845],[-95.2517,48.8839],[-95.2507,48.8836],[-95.2502,48.8835],[-95.2496,48.8834],[-95.2485,48.8832],[-95.248,48.8836],[-95.2472,48.8835],[-95.2458,48.8829],[-95.2439,48.8823],[-95.2429,48.8822],[-95.2429,48.8822],[-95.2423,48.8821],[-95.2407,48.8821],[-95.2391,48.8819],[-95.2381,48.8817],[-95.2356,48.8815],[-95.2335,48.8814],[-95.231,48.8814],[-95.2287,48.8815],[-95.2265,48.8816],[-95.2252,48.8819],[-95.2212,48.883],[-95.2208,48.8831],[-95.2207,48.8831],[-95.22,48.8831],[-95.2193,48.8832],[-95.2188,48.8835],[-95.217,48.8835],[-95.2159,48.8839],[-95.2151,48.884],[-95.2144,48.8843],[-95.2122,48.8842],[-95.2117,48.8847],[-95.2115,48.8847],[-95.2112,48.8848],[-95.2085,48.8846],[-95.2059,48.8848],[-95.2024,48.8852],[-95.2009,48.8855],[-95.2005,48.8856],[-95.1986,48.8855],[-95.1956,48.8862],[-95.1924,48.8865],[-95.1919,48.8866],[-95.1913,48.8868],[-95.1901,48.887],[-95.1889,48.8873],[-95.1877,48.8874],[-95.1863,48.8877],[-95.1851,48.8882],[-95.1819,48.8888],[-95.1797,48.889],[-95.1791,48.889],[-95.1764,48.8893],[-95.173,48.8897],[-95.1701,48.8902],[-95.1674,48.8907],[-95.1648,48.8913],[-95.1641,48.8917],[-95.1618,48.892],[-95.1602,48.892],[-95.1579,48.8919],[-95.1564,48.8919],[-95.1555,48.892],[-95.1528,48.8921],[-95.1508,48.8922],[-95.1483,48.8923],[-95.1469,48.8927],[-95.1459,48.8929],[-95.1438,48.8934],[-95.1436,48.8937],[-95.1404,48.8943],[-95.1381,48.8949],[-95.1355,48.8959],[-95.1351,48.8963],[-95.1348,48.8963],[-95.1343,48.8963],[-95.1337,48.8969],[-95.1322,48.8973],[-95.1312,48.8975],[-95.1252,48.8998],[-95.1239,48.9001],[-95.1233,48.9004],[-95.1228,48.9006],[-95.1214,48.9013],[-95.121,48.9016],[-95.1205,48.9017],[-95.1204,48.9019],[-95.1182,48.9029],[-95.1163,48.9037],[-95.1151,48.9046],[-95.1144,48.9052],[-95.114,48.9061],[-95.1141,48.9064],[-95.1137,48.9069],[-95.1132,48.9071],[-95.113,48.9072],[-95.1126,48.9073],[-95.1107,48.9082],[-95.1096,48.9089],[-95.108,48.9099],[-95.1056,48.9113],[-95.1042,48.9121],[-95.1032,48.9127],[-95.102,48.9132],[-95.1008,48.9142],[-95.0981,48.9159],[-95.098,48.916],[-95.0975,48.9164],[-95.0971,48.9172],[-95.097,48.9176],[-95.0961,48.9181],[-95.0946,48.9191],[-95.0944,48.9193],[-95.0927,48.9204],[-95.0919,48.9207],[-95.0914,48.9208],[-95.0914,48.916],[-95.0912,48.9014],[-95.0911,48.8869],[-95.0908,48.8724],[-95.0908,48.858],[-95.0907,48.8436],[-95.0908,48.8291],[-95.0909,48.8147],[-95.0903,48.8],[-95.0903,48.7855],[-95.0903,48.7711],[-95.0901,48.7566],[-95.0901,48.7421],[-95.0899,48.7277],[-95.0898,48.713],[-95.1046,48.7129],[-95.1104,48.7129],[-95.1119,48.7129],[-95.1259,48.7129],[-95.1297,48.713],[-95.1333,48.713],[-95.1477,48.7129],[-95.1554,48.7129],[-95.1697,48.7129],[-95.1773,48.713],[-95.1917,48.713],[-95.1991,48.713],[-95.2112,48.713],[-95.2206,48.713],[-95.2331,48.713],[-95.2427,48.713],[-95.255,48.713],[-95.2645,48.713],[-95.2656,48.713],[-95.2767,48.713],[-95.2866,48.713],[-95.299,48.713],[-95.3051,48.713],[-95.3084,48.713],[-95.3205,48.713],[-95.3302,48.713],[-95.3425,48.7131],[-95.3425,48.6995],[-95.3424,48.6849],[-95.3423,48.6705],[-95.3424,48.6561],[-95.3425,48.6415],[-95.3426,48.6271],[-95.3424,48.6127],[-95.3426,48.5979],[-95.3423,48.5836],[-95.3423,48.5691],[-95.3424,48.5548],[-95.3425,48.5402],[-95.3628,48.5404],[-95.364,48.5403],[-95.3844,48.5402],[-95.386,48.5402],[-95.4061,48.5402],[-95.4078,48.5402],[-95.4279,48.54],[-95.4297,48.5399],[-95.4494,48.5399],[-95.4513,48.5399],[-95.4712,48.5396],[-95.4726,48.5396],[-95.493,48.5392],[-95.495,48.5392],[-95.5143,48.539],[-95.5163,48.539],[-95.5365,48.5389],[-95.5383,48.5389],[-95.558,48.5388],[-95.5603,48.5388],[-95.5801,48.5387],[-95.5821,48.5387],[-95.6023,48.5389],[-95.6232,48.5391],[-95.6447,48.5393],[-95.6666,48.5394],[-95.6886,48.5395],[-95.7102,48.5395],[-95.7322,48.54],[-95.7539,48.5404],[-95.7758,48.5406],[-95.7976,48.5405],[-95.8192,48.5404],[-95.8411,48.5406],[-95.8621,48.5414],[-95.8829,48.5419],[-95.8851,48.542],[-95.8986,48.5421],[-95.9046,48.5422],[-95.9064,48.5422],[-95.9269,48.5421],[-95.9486,48.5425],[-95.9498,48.5425],[-95.9704,48.543],[-95.9936,48.5435],[-96.0157,48.5437],[-96.0374,48.5438],[-96.0592,48.5437],[-96.0812,48.5436],[-96.1026,48.5438],[-96.1264,48.5439],[-96.1486,48.5442],[-96.1702,48.5445],[-96.1921,48.5446],[-96.2141,48.5449],[-96.2358,48.5452],[-96.2576,48.545],[-96.2794,48.5449],[-96.301,48.5448],[-96.3231,48.5446],[-96.3448,48.5444],[-96.3667,48.5443],[-96.3882,48.5442],[-96.3879,48.5588],[-96.3882,48.5733],[-96.3884,48.5877],[-96.3891,48.6024],[-96.389,48.6165],[-96.388,48.6313],[-96.3879,48.6454],[-96.3877,48.6599],[-96.3871,48.6741],[-96.3874,48.6887],[-96.3866,48.703],[-96.3873,48.7172],[-96.388,48.7172],[-96.4049,48.7172],[-96.4048,48.7318],[-96.4048,48.7465],[-96.4047,48.7607],[-96.4045,48.7758],[-96.4042,48.7903],[-96.4042,48.8048],[-96.4042,48.8198],[-96.4043,48.8343],[-96.4045,48.8491],[-96.4047,48.8635],[-96.405,48.878],[-96.405,48.8926],[-96.4053,48.9068],[-96.4053,48.9081],[-96.4053,48.9137],[-96.4054,48.9214],[-96.4054,48.9225],[-96.4053,48.936],[-96.4053,48.9371],[-96.4053,48.9504],[-96.4053,48.9515],[-96.4053,48.9648],[-96.4053,48.9658],[-96.4053,48.9705],[-96.4054,48.9793],[-96.4054,48.9803],[-96.4054,48.994],[-96.4054,48.9947],[-96.4054,49.0001]]],"type":"Polygon"},"id":"68","properties":{"Area":4347098503.12714,"CTYONLY_":4,"Code":"ROSE","LASTMOD":"2001-04-12T09:32:44Z","Name":"Roseau","Perimiter":302590.75293},"type":"Feature"},{"geometry":{"coordinates":[[[-94.4299,48.7012],[-94.4241,48.7053],[-94.4213,48.7086],[-94.4189,48.7103],[-94.4158,48.711],[-94.4081,48.7106],[-94.406,48.7105],[-94.3889,48.712],[-94.3859,48.7119],[-94.384,48.7119],[-94.3801,48.7111],[-94.3687,48.7065],[-94.3646,48.7059],[-94.3533,48.7042],[-94.3431,48.7035],[-94.3429,48.7035],[-94.3287,48.7045],[-94.3214,48.7067],[-94.3088,48.7103],[-94.2995,48.709],[-94.2911,48.7079],[-94.2829,48.7057],[-94.2781,48.7024],[-94.2745,48.6999],[-94.2694,48.6995],[-94.2644,48.699],[-94.261,48.6966],[-94.258,48.6918],[-94.2565,48.6901],[-94.2529,48.6864],[-94.2521,48.685],[-94.2514,48.6837],[-94.2507,48.6782],[-94.2527,48.6707],[-94.253,48.6693],[-94.2548,48.664],[-94.2546,48.6615],[-94.2509,48.657],[-94.2499,48.6563],[-94.2467,48.6542],[-94.2445,48.6535],[-94.2343,48.6524],[-94.2335,48.6524],[-94.2242,48.6495],[-94.2144,48.6494],[-94.2124,48.6496],[-94.1996,48.651],[-94.1915,48.6506],[-94.1886,48.6504],[-94.1689,48.6483],[-94.1678,48.6482],[-94.1574,48.6458],[-94.1522,48.6455],[-94.1458,48.6458],[-94.1391,48.646],[-94.126,48.6444],[-94.1235,48.6444],[-94.11,48.6443],[-94.1023,48.6455],[-94.0999,48.6459],[-94.0912,48.6437],[-94.0849,48.6441],[-94.0804,48.6442],[-94.0767,48.6442],[-94.0714,48.6459],[-94.0658,48.6462],[-94.0642,48.6438],[-94.0603,48.6431],[-94.0581,48.6434],[-94.0525,48.644],[-94.0432,48.6435],[-94.0393,48.6423],[-94.0364,48.6413],[-94.0356,48.6411],[-94.0295,48.6409],[-94.0153,48.6424],[-94.0069,48.6433],[-94.0007,48.6428],[-93.9931,48.6412],[-93.9897,48.6405],[-93.984,48.6401],[-93.9777,48.6385],[-93.9712,48.6385],[-93.968,48.6385],[-93.9596,48.6372],[-93.953,48.6341],[-93.9497,48.6339],[-93.934,48.6326],[-93.9272,48.6327],[-93.9169,48.6329],[-93.9134,48.6353],[-93.9057,48.6346],[-93.9054,48.6345],[-93.8948,48.6324],[-93.8853,48.6318],[-93.8844,48.6318],[-93.8757,48.6319],[-93.8698,48.6311],[-93.8624,48.631],[-93.848,48.6308],[-93.8443,48.6303],[-93.8404,48.6289],[-93.8393,48.6286],[-93.8365,48.6276],[-93.8334,48.6256],[-93.8292,48.6177],[-93.825,48.6136],[-93.8245,48.613],[-93.8214,48.6092],[-93.8182,48.5994],[-93.8175,48.597],[-93.8172,48.5964],[-93.813,48.588],[-93.8103,48.5846],[-93.8063,48.5796],[-93.8041,48.5703],[-93.8041,48.5702],[-93.8051,48.5644],[-93.808,48.5569],[-93.8088,48.5555],[-93.8119,48.5503],[-93.8102,48.5445],[-93.8109,48.5412],[-93.8109,48.541],[-93.818,48.535],[-93.818,48.5346],[-93.8184,48.5315],[-93.8178,48.5306],[-93.8161,48.5285],[-93.8145,48.5273],[-93.8111,48.5247],[-93.803,48.522],[-93.7964,48.5182],[-93.7933,48.5164],[-93.7879,48.5159],[-93.7745,48.5162],[-93.768,48.5164],[-93.7665,48.5164],[-93.7617,48.5166],[-93.7534,48.5158],[-93.7442,48.5175],[-93.739,48.5185],[-93.731,48.5185],[-93.7225,48.5178],[-93.7206,48.5176],[-93.7108,48.5186],[-93.7061,48.5182],[-93.7006,48.517],[-93.693,48.5152],[-93.6866,48.5154],[-93.6791,48.5167],[-93.6778,48.5169],[-93.6593,48.5165],[-93.657,48.5167],[-93.6473,48.5177],[-93.6433,48.519],[-93.6421,48.5199],[-93.6395,48.5218],[-93.6357,48.5285],[-93.6344,48.5293],[-93.6311,48.5313],[-93.6284,48.5319],[-93.6256,48.5315],[-93.6211,48.5264],[-93.6166,48.5238],[-93.6134,48.5228],[-93.6122,48.5225],[-93.6051,48.5231],[-93.5962,48.5287],[-93.5919,48.5299],[-93.5901,48.5305],[-93.581,48.5271],[-93.5761,48.527],[-93.5701,48.528],[-93.5602,48.5297],[-93.5484,48.5294],[-93.5476,48.5294],[-93.5425,48.53],[-93.5366,48.5319],[-93.5269,48.5341],[-93.5263,48.5341],[-93.5244,48.5343],[-93.5171,48.5348],[-93.5047,48.5399],[-93.501,48.5414],[-93.4952,48.5426],[-93.4854,48.5433],[-93.4833,48.5437],[-93.4673,48.5465],[-93.4655,48.5478],[-93.4625,48.5498],[-93.462,48.5505],[-93.4596,48.5537],[-93.4576,48.5598],[-93.4576,48.5621],[-93.4575,48.5672],[-93.4619,48.5731],[-93.4619,48.5734],[-93.4631,48.5767],[-93.4671,48.5885],[-93.4656,48.59],[-93.4654,48.5915],[-93.4654,48.5917],[-93.4627,48.5927],[-93.46,48.5927],[-93.4547,48.5927],[-93.4398,48.5937],[-93.4385,48.5942],[-93.4347,48.5954],[-93.4298,48.5997],[-93.4226,48.6032],[-93.4193,48.6036],[-93.416,48.605],[-93.4152,48.6053],[-93.415,48.6056],[-93.4144,48.6064],[-93.4056,48.6099],[-93.4034,48.61],[-93.4029,48.6077],[-93.4013,48.6079],[-93.3994,48.6055],[-93.3986,48.6045],[-93.3953,48.6038],[-93.3937,48.6041],[-93.3837,48.606],[-93.3724,48.6059],[-93.3714,48.6059],[-93.3672,48.6082],[-93.3619,48.6141],[-93.355,48.6114],[-93.3526,48.6135],[-93.3533,48.615],[-93.3513,48.62],[-93.3505,48.6219],[-93.3486,48.6265],[-93.3276,48.6302],[-93.3057,48.634],[-93.3048,48.6341],[-93.2838,48.6378],[-93.2634,48.6413],[-93.2546,48.6429],[-93.2422,48.6428],[-93.2193,48.6426],[-93.2075,48.6426],[-93.1975,48.6365],[-93.191,48.6325],[-93.184,48.6282],[-93.1783,48.6231],[-93.1754,48.6232],[-93.1531,48.6244],[-93.1319,48.6256],[-93.1104,48.6267],[-93.0903,48.6278],[-93.0884,48.6278],[-93.0886,48.6163],[-93.0895,48.6016],[-93.0898,48.5872],[-93.09,48.5727],[-93.0902,48.5583],[-93.0902,48.5441],[-93.0903,48.5296],[-93.0905,48.5151],[-93.0905,48.501],[-93.091,48.4884],[-93.0911,48.4867],[-93.0914,48.474],[-93.0915,48.4724],[-93.0918,48.4596],[-93.0919,48.458],[-93.092,48.4449],[-93.092,48.4436],[-93.0922,48.4303],[-93.0922,48.429],[-93.0923,48.4147],[-93.0935,48.4147],[-93.0938,48.4024],[-93.094,48.3879],[-93.094,48.3734],[-93.0945,48.3589],[-93.0948,48.3442],[-93.0948,48.3298],[-93.0953,48.3153],[-93.0952,48.3004],[-93.095,48.2862],[-93.0952,48.2716],[-93.0953,48.2576],[-93.0949,48.2426],[-93.0949,48.2425],[-93.0977,48.2426],[-93.0977,48.2271],[-93.0978,48.2126],[-93.0979,48.1981],[-93.0975,48.1836],[-93.097,48.1692],[-93.097,48.1546],[-93.097,48.1402],[-93.0969,48.1259],[-93.0972,48.1114],[-93.097,48.0969],[-93.0968,48.0823],[-93.0965,48.0679],[-93.0965,48.0678],[-93.0892,48.0679],[-93.0892,48.0509],[-93.089,48.0366],[-93.0886,48.022],[-93.0887,48.0075],[-93.0872,47.9932],[-93.088,47.9787],[-93.0809,47.9786],[-93.0809,47.967],[-93.0808,47.9647],[-93.0808,47.9525],[-93.0808,47.9504],[-93.0809,47.938],[-93.0809,47.9356],[-93.0809,47.9235],[-93.0809,47.9212],[-93.0809,47.9088],[-93.0809,47.9067],[-93.0808,47.8945],[-93.0808,47.8922],[-93.1015,47.8927],[-93.1232,47.893],[-93.1448,47.8928],[-93.1656,47.8931],[-93.1671,47.8932],[-93.1871,47.8931],[-93.1893,47.8931],[-93.2087,47.8933],[-93.2115,47.8934],[-93.2331,47.8937],[-93.2532,47.8936],[-93.2745,47.8938],[-93.2962,47.8939],[-93.3169,47.894],[-93.3392,47.8941],[-93.3603,47.8942],[-93.3809,47.8943],[-93.4024,47.8944],[-93.4235,47.8945],[-93.4442,47.8946],[-93.466,47.895],[-93.4874,47.8956],[-93.4892,47.8957],[-93.4933,47.8958],[-93.5085,47.8962],[-93.5105,47.8963],[-93.5297,47.8967],[-93.5303,47.8967],[-93.532,47.8968],[-93.5517,47.8973],[-93.5532,47.8974],[-93.5729,47.8981],[-93.5747,47.8982],[-93.5962,47.8978],[-93.5966,47.8978],[-93.6179,47.8977],[-93.6187,47.8977],[-93.6388,47.8977],[-93.6395,47.8976],[-93.6604,47.8976],[-93.6612,47.8976],[-93.6817,47.8976],[-93.6826,47.8976],[-93.7031,47.8976],[-93.7038,47.8976],[-93.7249,47.8975],[-93.7248,47.8989],[-93.7466,47.8989],[-93.768,47.8991],[-93.7758,47.8991],[-93.7758,47.899],[-93.776,47.8897],[-93.776,47.8842],[-93.7762,47.8753],[-93.7761,47.8697],[-93.7761,47.8607],[-93.7761,47.8553],[-93.7761,47.8464],[-93.7896,47.8465],[-93.7971,47.8466],[-93.8189,47.8467],[-93.8407,47.8468],[-93.8627,47.8469],[-93.8831,47.8471],[-93.9067,47.8471],[-93.9288,47.8475],[-93.9496,47.8475],[-93.9506,47.8475],[-93.971,47.8475],[-93.9725,47.8475],[-93.9927,47.8475],[-93.9942,47.8475],[-94.0141,47.8476],[-94.0161,47.8476],[-94.0375,47.8477],[-94.0591,47.8474],[-94.0807,47.8471],[-94.1022,47.8471],[-94.1239,47.8466],[-94.1448,47.8463],[-94.1657,47.8461],[-94.1822,47.8461],[-94.1871,47.846],[-94.2037,47.846],[-94.2086,47.846],[-94.2252,47.846],[-94.23,47.8461],[-94.2467,47.8462],[-94.2515,47.8462],[-94.2681,47.8462],[-94.2728,47.8462],[-94.2887,47.8462],[-94.3103,47.8458],[-94.3315,47.846],[-94.3532,47.8464],[-94.3747,47.8462],[-94.3964,47.8461],[-94.4185,47.8459],[-94.4186,47.86],[-94.4184,47.8744],[-94.418,47.8886],[-94.4177,47.9031],[-94.4176,47.9041],[-94.4175,47.9175],[-94.4174,47.9186],[-94.4175,47.9332],[-94.4174,47.9477],[-94.4172,47.9623],[-94.4173,47.9769],[-94.4176,47.9914],[-94.4177,48.006],[-94.4176,48.02],[-94.4236,48.0199],[-94.4241,48.0344],[-94.4246,48.0489],[-94.4247,48.0632],[-94.4234,48.0776],[-94.4231,48.092],[-94.4233,48.1059],[-94.4234,48.1204],[-94.4236,48.1348],[-94.4233,48.1491],[-94.4235,48.1637],[-94.4235,48.1781],[-94.4233,48.1923],[-94.4236,48.2067],[-94.4238,48.2212],[-94.4237,48.2356],[-94.4237,48.2504],[-94.424,48.2649],[-94.4243,48.2791],[-94.4244,48.2938],[-94.4246,48.3081],[-94.4248,48.3227],[-94.425,48.3372],[-94.4253,48.352],[-94.4252,48.3675],[-94.4288,48.3675],[-94.4289,48.3821],[-94.4293,48.3964],[-94.4294,48.411],[-94.4293,48.4254],[-94.4292,48.4399],[-94.4293,48.4543],[-94.4296,48.4688],[-94.4296,48.4832],[-94.4299,48.4977],[-94.4303,48.512],[-94.4303,48.5264],[-94.43,48.5409],[-94.4295,48.5554],[-94.4291,48.5698],[-94.4289,48.5844],[-94.4289,48.5988],[-94.4292,48.6133],[-94.4294,48.6276],[-94.4297,48.642],[-94.43,48.6564],[-94.4301,48.6708],[-94.43,48.6852],[-94.4299,48.6998],[-94.4299,48.7012]]],"type":"Polygon"},"id":"36","properties":{"Area":8167237870.91888,"CTYONLY_":5,"Code":"KOOC","LASTMOD":"1999-12-31T23:59:59Z","Name":"Koochiching","Perimiter":412897.43594},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&filter=CTYONLY_%20BETWEEN%203%20AND%205","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&filter=CTYONLY_%20BETWEEN%203%20AND%205","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":3,"numberReturned":3,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_text_casei_like.json.txt b/msautotest/api/expected/ogcapi_cql2_text_casei_like.json.txt new file mode 100644 index 0000000000..a053316c01 --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_text_casei_like.json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 1 +OGC-NumberReturned: 1 + +{"features":[{"geometry":{"coordinates":[[[-93.5242,44.5436],[-93.5225,44.5436],[-93.504,44.5438],[-93.5018,44.5438],[-93.4835,44.5438],[-93.4817,44.5438],[-93.4734,44.5438],[-93.4632,44.5438],[-93.4609,44.5438],[-93.4429,44.5438],[-93.4408,44.5438],[-93.4326,44.5438],[-93.4226,44.5439],[-93.4206,44.5439],[-93.4024,44.5439],[-93.4003,44.5439],[-93.383,44.544],[-93.38,44.544],[-93.3627,44.5441],[-93.3596,44.5441],[-93.3556,44.5441],[-93.3424,44.5442],[-93.3395,44.5442],[-93.3221,44.544],[-93.3191,44.544],[-93.3128,44.544],[-93.3019,44.544],[-93.2988,44.544],[-93.2813,44.544],[-93.2814,44.5298],[-93.2815,44.5153],[-93.2815,44.501],[-93.2815,44.4865],[-93.2817,44.472],[-93.2618,44.4718],[-93.2415,44.4716],[-93.2213,44.4714],[-93.2008,44.4714],[-93.1808,44.4713],[-93.1605,44.4713],[-93.1408,44.4712],[-93.1206,44.4713],[-93.1002,44.4718],[-93.0799,44.4719],[-93.0597,44.4718],[-93.0393,44.4719],[-93.0394,44.4576],[-93.0396,44.4432],[-93.0397,44.4287],[-93.0399,44.4143],[-93.04,44.3999],[-93.0401,44.3855],[-93.0402,44.371],[-93.0403,44.3565],[-93.0403,44.3419],[-93.0405,44.3273],[-93.0405,44.3129],[-93.0405,44.2983],[-93.0406,44.2838],[-93.0407,44.2693],[-93.0409,44.2548],[-93.041,44.2402],[-93.0411,44.2257],[-93.0411,44.2113],[-93.0411,44.1968],[-93.0427,44.1968],[-93.0459,44.1968],[-93.0613,44.1967],[-93.0661,44.1967],[-93.0815,44.1967],[-93.0862,44.1967],[-93.1003,44.1967],[-93.1015,44.1967],[-93.1063,44.1967],[-93.1092,44.1967],[-93.1218,44.1967],[-93.1267,44.1967],[-93.1301,44.1967],[-93.1418,44.1967],[-93.1467,44.1967],[-93.1561,44.1966],[-93.1622,44.1966],[-93.1661,44.1966],[-93.1703,44.1966],[-93.1822,44.1966],[-93.1856,44.1966],[-93.1865,44.1966],[-93.2023,44.1966],[-93.2037,44.1966],[-93.2064,44.1966],[-93.2225,44.1966],[-93.2265,44.1966],[-93.2292,44.1966],[-93.2426,44.1966],[-93.2465,44.1966],[-93.255,44.1966],[-93.2629,44.1966],[-93.2664,44.1966],[-93.2767,44.1966],[-93.283,44.1966],[-93.2865,44.1965],[-93.2905,44.1965],[-93.3032,44.1965],[-93.3063,44.1965],[-93.3235,44.1965],[-93.3264,44.1965],[-93.3277,44.1965],[-93.3436,44.1965],[-93.3466,44.1965],[-93.3639,44.1965],[-93.3666,44.1965],[-93.3842,44.1965],[-93.3866,44.1965],[-93.4042,44.1965],[-93.4065,44.1965],[-93.4244,44.1964],[-93.4267,44.1964],[-93.4447,44.1964],[-93.4469,44.1964],[-93.4648,44.1963],[-93.467,44.1963],[-93.4852,44.1964],[-93.4872,44.1964],[-93.5053,44.1963],[-93.507,44.1963],[-93.5255,44.1962],[-93.5253,44.2107],[-93.5251,44.2251],[-93.5251,44.2388],[-93.5251,44.2533],[-93.5252,44.2685],[-93.5252,44.2829],[-93.5252,44.2975],[-93.5252,44.312],[-93.5249,44.3266],[-93.5249,44.3411],[-93.5245,44.3557],[-93.5245,44.3704],[-93.5246,44.3848],[-93.5245,44.3994],[-93.5245,44.4138],[-93.5245,44.4283],[-93.5245,44.4427],[-93.5245,44.4572],[-93.5244,44.4717],[-93.5245,44.4862],[-93.5244,44.5007],[-93.5243,44.5152],[-93.5244,44.5297],[-93.5242,44.5436]]],"type":"Polygon"},"id":"66","properties":{"Area":1335114621.00336,"CTYONLY_":66,"Code":"RICE","LASTMOD":"2010-10-17T00:00:00Z","Name":"Rice","Perimiter":154431.78788},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&filter=casei(Name)%20LIKE%20CASEI('rice')","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&filter=casei(Name)%20LIKE%20CASEI('rice')","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":1,"numberReturned":1,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_text_div.json.txt b/msautotest/api/expected/ogcapi_cql2_text_div.json.txt new file mode 100644 index 0000000000..dd7a4cef50 --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_text_div.json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 1 +OGC-NumberReturned: 1 + +{"features":[{"geometry":{"coordinates":[[[-96.4054,49.0001],[-96.4019,49.0001],[-96.3825,49.0001],[-96.3783,49.0001],[-96.3606,49.0001],[-96.3579,49.0001],[-96.3385,49.0001],[-96.3343,49.0001],[-96.3166,49.0001],[-96.3138,49.0001],[-96.2945,49.0001],[-96.2902,49.0001],[-96.2725,49.0001],[-96.2698,49.0001],[-96.2494,49.0001],[-96.2461,49.0001],[-96.2274,49.0001],[-96.2257,49.0001],[-96.2057,49.0001],[-96.2021,49.0001],[-96.1837,49.0],[-96.18,49.0],[-96.1617,49.0],[-96.1579,49.0],[-96.1401,49.0],[-96.1359,49.0],[-96.1176,49.0],[-96.1139,49.0],[-96.0957,49.0],[-96.0919,49.0],[-96.0738,49.0],[-96.07,49.0],[-96.0517,49.0],[-96.048,49.0],[-96.0298,49.0],[-96.026,49.0],[-96.0083,49.0],[-96.0045,49.0],[-95.9868,49.0],[-95.9784,49.0],[-95.9776,49.0],[-95.9755,49.0],[-95.9648,48.9999],[-95.9464,48.9999],[-95.943,48.9999],[-95.9225,48.9999],[-95.9211,48.9999],[-95.899,48.9998],[-95.883,48.9998],[-95.8771,48.9998],[-95.8564,48.9998],[-95.855,48.9998],[-95.8342,48.9998],[-95.8184,48.9997],[-95.8126,48.9997],[-95.7906,48.9997],[-95.7833,48.9997],[-95.7684,48.9997],[-95.7479,48.9996],[-95.7466,48.9996],[-95.7253,48.9996],[-95.7066,48.9996],[-95.7032,48.9996],[-95.681,48.9995],[-95.6654,48.9995],[-95.6596,48.9995],[-95.659,48.9995],[-95.6401,48.9995],[-95.6369,48.9995],[-95.6205,48.9994],[-95.615,48.9994],[-95.5948,48.9994],[-95.585,48.9994],[-95.573,48.9994],[-95.551,48.9993],[-95.5495,48.9993],[-95.5294,48.9993],[-95.5164,48.9993],[-95.5072,48.9993],[-95.4849,48.9992],[-95.4834,48.9992],[-95.4635,48.9992],[-95.4508,48.9992],[-95.4418,48.9992],[-95.4245,48.9991],[-95.4197,48.9991],[-95.3977,48.9991],[-95.3953,48.9991],[-95.3765,48.9991],[-95.3759,48.9991],[-95.3753,48.9991],[-95.3542,48.999],[-95.3513,48.999],[-95.3326,48.999],[-95.3286,48.999],[-95.3231,48.999],[-95.3224,48.9984],[-95.3204,48.9976],[-95.3202,48.9973],[-95.3204,48.9964],[-95.3206,48.9961],[-95.3201,48.9956],[-95.3197,48.9954],[-95.3191,48.9953],[-95.3187,48.9956],[-95.3182,48.996],[-95.3179,48.9961],[-95.3178,48.9961],[-95.3178,48.9958],[-95.3181,48.995],[-95.3191,48.9941],[-95.3204,48.9924],[-95.3206,48.9921],[-95.3224,48.9889],[-95.3227,48.9884],[-95.3242,48.9859],[-95.3245,48.985],[-95.3253,48.9832],[-95.3257,48.9814],[-95.3256,48.98],[-95.3255,48.9789],[-95.3257,48.9784],[-95.3253,48.976],[-95.325,48.9743],[-95.3249,48.9738],[-95.3248,48.9728],[-95.3247,48.972],[-95.3241,48.9703],[-95.3232,48.9692],[-95.3227,48.9685],[-95.3212,48.9672],[-95.3207,48.9669],[-95.3201,48.9648],[-95.3198,48.9643],[-95.3193,48.964],[-95.3193,48.9622],[-95.3202,48.9606],[-95.3206,48.9598],[-95.3206,48.9595],[-95.3206,48.959],[-95.3202,48.9581],[-95.3191,48.9569],[-95.3188,48.9562],[-95.3179,48.9559],[-95.3175,48.9552],[-95.3177,48.9545],[-95.3182,48.9535],[-95.3181,48.9531],[-95.3177,48.9525],[-95.3154,48.9513],[-95.3151,48.951],[-95.3141,48.9508],[-95.3131,48.9503],[-95.3125,48.9503],[-95.3123,48.9502],[-95.3119,48.9502],[-95.3119,48.9507],[-95.3129,48.9521],[-95.3129,48.9523],[-95.3126,48.9524],[-95.312,48.9524],[-95.3115,48.952],[-95.3108,48.9512],[-95.3104,48.951],[-95.3097,48.951],[-95.3089,48.9511],[-95.3079,48.9509],[-95.3061,48.9502],[-95.3052,48.9495],[-95.3046,48.9482],[-95.3046,48.947],[-95.305,48.9462],[-95.3053,48.9459],[-95.3061,48.9454],[-95.3068,48.9454],[-95.3069,48.9455],[-95.3069,48.9456],[-95.3063,48.9462],[-95.3062,48.9463],[-95.3061,48.9469],[-95.3062,48.9472],[-95.3062,48.9472],[-95.3071,48.9477],[-95.3081,48.948],[-95.3094,48.9481],[-95.3096,48.9482],[-95.3099,48.9484],[-95.31,48.9485],[-95.3103,48.9485],[-95.3104,48.9484],[-95.3103,48.948],[-95.3096,48.9478],[-95.3092,48.9477],[-95.3079,48.9474],[-95.3071,48.9469],[-95.3071,48.9466],[-95.3074,48.9465],[-95.3078,48.9466],[-95.3085,48.947],[-95.3086,48.9469],[-95.3086,48.9465],[-95.3088,48.9464],[-95.3095,48.9463],[-95.3102,48.9463],[-95.3114,48.9461],[-95.3131,48.946],[-95.3141,48.9457],[-95.3148,48.9452],[-95.3154,48.9448],[-95.3168,48.9431],[-95.3181,48.9421],[-95.3189,48.9419],[-95.3219,48.9412],[-95.3225,48.9409],[-95.3228,48.9403],[-95.3231,48.9389],[-95.3229,48.9373],[-95.3225,48.9358],[-95.3223,48.9355],[-95.3228,48.9344],[-95.3222,48.9327],[-95.3209,48.9307],[-95.3208,48.9305],[-95.3195,48.9285],[-95.3168,48.9245],[-95.315,48.9222],[-95.3141,48.921],[-95.3132,48.9198],[-95.3126,48.919],[-95.3119,48.9178],[-95.3115,48.9172],[-95.3109,48.9163],[-95.3102,48.9155],[-95.3093,48.9149],[-95.3092,48.9149],[-95.3085,48.9146],[-95.3078,48.9141],[-95.3074,48.9135],[-95.3064,48.9129],[-95.3061,48.9128],[-95.3059,48.9127],[-95.3043,48.9119],[-95.3038,48.9114],[-95.3027,48.91],[-95.3017,48.9093],[-95.2999,48.9086],[-95.2978,48.9083],[-95.2973,48.9081],[-95.2973,48.908],[-95.2973,48.9077],[-95.2976,48.9074],[-95.2977,48.9073],[-95.2978,48.9073],[-95.2978,48.9072],[-95.2978,48.9072],[-95.2979,48.9072],[-95.2979,48.9072],[-95.2979,48.9071],[-95.298,48.9071],[-95.298,48.9071],[-95.298,48.9071],[-95.2981,48.907],[-95.2982,48.9068],[-95.2983,48.9068],[-95.2985,48.9065],[-95.2985,48.9064],[-95.2986,48.9063],[-95.2988,48.906],[-95.2989,48.906],[-95.2991,48.9057],[-95.2992,48.9055],[-95.2994,48.9053],[-95.2996,48.9051],[-95.2997,48.905],[-95.2999,48.9048],[-95.2999,48.9048],[-95.2999,48.9048],[-95.3,48.9047],[-95.3,48.9047],[-95.3001,48.9047],[-95.3001,48.9046],[-95.3002,48.9045],[-95.3005,48.904],[-95.2993,48.9035],[-95.2983,48.9028],[-95.298,48.9027],[-95.2976,48.9026],[-95.2967,48.9027],[-95.2949,48.9028],[-95.2941,48.9027],[-95.2937,48.9023],[-95.2935,48.902],[-95.2927,48.9019],[-95.2914,48.9019],[-95.2909,48.9017],[-95.2908,48.9016],[-95.2907,48.9014],[-95.2906,48.9011],[-95.2911,48.9008],[-95.2911,48.9006],[-95.2901,48.9003],[-95.2896,48.9],[-95.289,48.8994],[-95.2882,48.8981],[-95.2879,48.8979],[-95.2872,48.8977],[-95.287,48.8976],[-95.2865,48.8975],[-95.2861,48.8976],[-95.2853,48.8977],[-95.2839,48.8975],[-95.2813,48.8967],[-95.2803,48.8965],[-95.2796,48.8962],[-95.279,48.8957],[-95.2782,48.8956],[-95.2773,48.8957],[-95.277,48.8958],[-95.2765,48.8962],[-95.2763,48.8963],[-95.2759,48.8962],[-95.2755,48.8959],[-95.2749,48.8956],[-95.2748,48.8951],[-95.2753,48.8943],[-95.2751,48.8938],[-95.2745,48.8931],[-95.2724,48.8921],[-95.2713,48.8915],[-95.268,48.8905],[-95.2677,48.8903],[-95.2674,48.89],[-95.2666,48.8894],[-95.2654,48.8888],[-95.265,48.8886],[-95.2646,48.8885],[-95.2639,48.8883],[-95.2635,48.888],[-95.2627,48.8877],[-95.2585,48.8867],[-95.2585,48.8867],[-95.257,48.8858],[-95.256,48.885],[-95.2548,48.8845],[-95.2517,48.8839],[-95.2507,48.8836],[-95.2502,48.8835],[-95.2496,48.8834],[-95.2485,48.8832],[-95.248,48.8836],[-95.2472,48.8835],[-95.2458,48.8829],[-95.2439,48.8823],[-95.2429,48.8822],[-95.2429,48.8822],[-95.2423,48.8821],[-95.2407,48.8821],[-95.2391,48.8819],[-95.2381,48.8817],[-95.2356,48.8815],[-95.2335,48.8814],[-95.231,48.8814],[-95.2287,48.8815],[-95.2265,48.8816],[-95.2252,48.8819],[-95.2212,48.883],[-95.2208,48.8831],[-95.2207,48.8831],[-95.22,48.8831],[-95.2193,48.8832],[-95.2188,48.8835],[-95.217,48.8835],[-95.2159,48.8839],[-95.2151,48.884],[-95.2144,48.8843],[-95.2122,48.8842],[-95.2117,48.8847],[-95.2115,48.8847],[-95.2112,48.8848],[-95.2085,48.8846],[-95.2059,48.8848],[-95.2024,48.8852],[-95.2009,48.8855],[-95.2005,48.8856],[-95.1986,48.8855],[-95.1956,48.8862],[-95.1924,48.8865],[-95.1919,48.8866],[-95.1913,48.8868],[-95.1901,48.887],[-95.1889,48.8873],[-95.1877,48.8874],[-95.1863,48.8877],[-95.1851,48.8882],[-95.1819,48.8888],[-95.1797,48.889],[-95.1791,48.889],[-95.1764,48.8893],[-95.173,48.8897],[-95.1701,48.8902],[-95.1674,48.8907],[-95.1648,48.8913],[-95.1641,48.8917],[-95.1618,48.892],[-95.1602,48.892],[-95.1579,48.8919],[-95.1564,48.8919],[-95.1555,48.892],[-95.1528,48.8921],[-95.1508,48.8922],[-95.1483,48.8923],[-95.1469,48.8927],[-95.1459,48.8929],[-95.1438,48.8934],[-95.1436,48.8937],[-95.1404,48.8943],[-95.1381,48.8949],[-95.1355,48.8959],[-95.1351,48.8963],[-95.1348,48.8963],[-95.1343,48.8963],[-95.1337,48.8969],[-95.1322,48.8973],[-95.1312,48.8975],[-95.1252,48.8998],[-95.1239,48.9001],[-95.1233,48.9004],[-95.1228,48.9006],[-95.1214,48.9013],[-95.121,48.9016],[-95.1205,48.9017],[-95.1204,48.9019],[-95.1182,48.9029],[-95.1163,48.9037],[-95.1151,48.9046],[-95.1144,48.9052],[-95.114,48.9061],[-95.1141,48.9064],[-95.1137,48.9069],[-95.1132,48.9071],[-95.113,48.9072],[-95.1126,48.9073],[-95.1107,48.9082],[-95.1096,48.9089],[-95.108,48.9099],[-95.1056,48.9113],[-95.1042,48.9121],[-95.1032,48.9127],[-95.102,48.9132],[-95.1008,48.9142],[-95.0981,48.9159],[-95.098,48.916],[-95.0975,48.9164],[-95.0971,48.9172],[-95.097,48.9176],[-95.0961,48.9181],[-95.0946,48.9191],[-95.0944,48.9193],[-95.0927,48.9204],[-95.0919,48.9207],[-95.0914,48.9208],[-95.0914,48.916],[-95.0912,48.9014],[-95.0911,48.8869],[-95.0908,48.8724],[-95.0908,48.858],[-95.0907,48.8436],[-95.0908,48.8291],[-95.0909,48.8147],[-95.0903,48.8],[-95.0903,48.7855],[-95.0903,48.7711],[-95.0901,48.7566],[-95.0901,48.7421],[-95.0899,48.7277],[-95.0898,48.713],[-95.1046,48.7129],[-95.1104,48.7129],[-95.1119,48.7129],[-95.1259,48.7129],[-95.1297,48.713],[-95.1333,48.713],[-95.1477,48.7129],[-95.1554,48.7129],[-95.1697,48.7129],[-95.1773,48.713],[-95.1917,48.713],[-95.1991,48.713],[-95.2112,48.713],[-95.2206,48.713],[-95.2331,48.713],[-95.2427,48.713],[-95.255,48.713],[-95.2645,48.713],[-95.2656,48.713],[-95.2767,48.713],[-95.2866,48.713],[-95.299,48.713],[-95.3051,48.713],[-95.3084,48.713],[-95.3205,48.713],[-95.3302,48.713],[-95.3425,48.7131],[-95.3425,48.6995],[-95.3424,48.6849],[-95.3423,48.6705],[-95.3424,48.6561],[-95.3425,48.6415],[-95.3426,48.6271],[-95.3424,48.6127],[-95.3426,48.5979],[-95.3423,48.5836],[-95.3423,48.5691],[-95.3424,48.5548],[-95.3425,48.5402],[-95.3628,48.5404],[-95.364,48.5403],[-95.3844,48.5402],[-95.386,48.5402],[-95.4061,48.5402],[-95.4078,48.5402],[-95.4279,48.54],[-95.4297,48.5399],[-95.4494,48.5399],[-95.4513,48.5399],[-95.4712,48.5396],[-95.4726,48.5396],[-95.493,48.5392],[-95.495,48.5392],[-95.5143,48.539],[-95.5163,48.539],[-95.5365,48.5389],[-95.5383,48.5389],[-95.558,48.5388],[-95.5603,48.5388],[-95.5801,48.5387],[-95.5821,48.5387],[-95.6023,48.5389],[-95.6232,48.5391],[-95.6447,48.5393],[-95.6666,48.5394],[-95.6886,48.5395],[-95.7102,48.5395],[-95.7322,48.54],[-95.7539,48.5404],[-95.7758,48.5406],[-95.7976,48.5405],[-95.8192,48.5404],[-95.8411,48.5406],[-95.8621,48.5414],[-95.8829,48.5419],[-95.8851,48.542],[-95.8986,48.5421],[-95.9046,48.5422],[-95.9064,48.5422],[-95.9269,48.5421],[-95.9486,48.5425],[-95.9498,48.5425],[-95.9704,48.543],[-95.9936,48.5435],[-96.0157,48.5437],[-96.0374,48.5438],[-96.0592,48.5437],[-96.0812,48.5436],[-96.1026,48.5438],[-96.1264,48.5439],[-96.1486,48.5442],[-96.1702,48.5445],[-96.1921,48.5446],[-96.2141,48.5449],[-96.2358,48.5452],[-96.2576,48.545],[-96.2794,48.5449],[-96.301,48.5448],[-96.3231,48.5446],[-96.3448,48.5444],[-96.3667,48.5443],[-96.3882,48.5442],[-96.3879,48.5588],[-96.3882,48.5733],[-96.3884,48.5877],[-96.3891,48.6024],[-96.389,48.6165],[-96.388,48.6313],[-96.3879,48.6454],[-96.3877,48.6599],[-96.3871,48.6741],[-96.3874,48.6887],[-96.3866,48.703],[-96.3873,48.7172],[-96.388,48.7172],[-96.4049,48.7172],[-96.4048,48.7318],[-96.4048,48.7465],[-96.4047,48.7607],[-96.4045,48.7758],[-96.4042,48.7903],[-96.4042,48.8048],[-96.4042,48.8198],[-96.4043,48.8343],[-96.4045,48.8491],[-96.4047,48.8635],[-96.405,48.878],[-96.405,48.8926],[-96.4053,48.9068],[-96.4053,48.9081],[-96.4053,48.9137],[-96.4054,48.9214],[-96.4054,48.9225],[-96.4053,48.936],[-96.4053,48.9371],[-96.4053,48.9504],[-96.4053,48.9515],[-96.4053,48.9648],[-96.4053,48.9658],[-96.4053,48.9705],[-96.4054,48.9793],[-96.4054,48.9803],[-96.4054,48.994],[-96.4054,48.9947],[-96.4054,49.0001]]],"type":"Polygon"},"id":"68","properties":{"Area":4347098503.12714,"CTYONLY_":4,"Code":"ROSE","LASTMOD":"2001-04-12T09:32:44Z","Name":"Roseau","Perimiter":302590.75293},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&filter=CTYONLY_%3D12%2F3","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&filter=CTYONLY_%3D12%2F3","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":1,"numberReturned":1,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_text_div2.json.txt b/msautotest/api/expected/ogcapi_cql2_text_div2.json.txt new file mode 100644 index 0000000000..01b789c455 --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_text_div2.json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 1 +OGC-NumberReturned: 1 + +{"features":[{"geometry":{"coordinates":[[[-96.4054,49.0001],[-96.4019,49.0001],[-96.3825,49.0001],[-96.3783,49.0001],[-96.3606,49.0001],[-96.3579,49.0001],[-96.3385,49.0001],[-96.3343,49.0001],[-96.3166,49.0001],[-96.3138,49.0001],[-96.2945,49.0001],[-96.2902,49.0001],[-96.2725,49.0001],[-96.2698,49.0001],[-96.2494,49.0001],[-96.2461,49.0001],[-96.2274,49.0001],[-96.2257,49.0001],[-96.2057,49.0001],[-96.2021,49.0001],[-96.1837,49.0],[-96.18,49.0],[-96.1617,49.0],[-96.1579,49.0],[-96.1401,49.0],[-96.1359,49.0],[-96.1176,49.0],[-96.1139,49.0],[-96.0957,49.0],[-96.0919,49.0],[-96.0738,49.0],[-96.07,49.0],[-96.0517,49.0],[-96.048,49.0],[-96.0298,49.0],[-96.026,49.0],[-96.0083,49.0],[-96.0045,49.0],[-95.9868,49.0],[-95.9784,49.0],[-95.9776,49.0],[-95.9755,49.0],[-95.9648,48.9999],[-95.9464,48.9999],[-95.943,48.9999],[-95.9225,48.9999],[-95.9211,48.9999],[-95.899,48.9998],[-95.883,48.9998],[-95.8771,48.9998],[-95.8564,48.9998],[-95.855,48.9998],[-95.8342,48.9998],[-95.8184,48.9997],[-95.8126,48.9997],[-95.7906,48.9997],[-95.7833,48.9997],[-95.7684,48.9997],[-95.7479,48.9996],[-95.7466,48.9996],[-95.7253,48.9996],[-95.7066,48.9996],[-95.7032,48.9996],[-95.681,48.9995],[-95.6654,48.9995],[-95.6596,48.9995],[-95.659,48.9995],[-95.6401,48.9995],[-95.6369,48.9995],[-95.6205,48.9994],[-95.615,48.9994],[-95.5948,48.9994],[-95.585,48.9994],[-95.573,48.9994],[-95.551,48.9993],[-95.5495,48.9993],[-95.5294,48.9993],[-95.5164,48.9993],[-95.5072,48.9993],[-95.4849,48.9992],[-95.4834,48.9992],[-95.4635,48.9992],[-95.4508,48.9992],[-95.4418,48.9992],[-95.4245,48.9991],[-95.4197,48.9991],[-95.3977,48.9991],[-95.3953,48.9991],[-95.3765,48.9991],[-95.3759,48.9991],[-95.3753,48.9991],[-95.3542,48.999],[-95.3513,48.999],[-95.3326,48.999],[-95.3286,48.999],[-95.3231,48.999],[-95.3224,48.9984],[-95.3204,48.9976],[-95.3202,48.9973],[-95.3204,48.9964],[-95.3206,48.9961],[-95.3201,48.9956],[-95.3197,48.9954],[-95.3191,48.9953],[-95.3187,48.9956],[-95.3182,48.996],[-95.3179,48.9961],[-95.3178,48.9961],[-95.3178,48.9958],[-95.3181,48.995],[-95.3191,48.9941],[-95.3204,48.9924],[-95.3206,48.9921],[-95.3224,48.9889],[-95.3227,48.9884],[-95.3242,48.9859],[-95.3245,48.985],[-95.3253,48.9832],[-95.3257,48.9814],[-95.3256,48.98],[-95.3255,48.9789],[-95.3257,48.9784],[-95.3253,48.976],[-95.325,48.9743],[-95.3249,48.9738],[-95.3248,48.9728],[-95.3247,48.972],[-95.3241,48.9703],[-95.3232,48.9692],[-95.3227,48.9685],[-95.3212,48.9672],[-95.3207,48.9669],[-95.3201,48.9648],[-95.3198,48.9643],[-95.3193,48.964],[-95.3193,48.9622],[-95.3202,48.9606],[-95.3206,48.9598],[-95.3206,48.9595],[-95.3206,48.959],[-95.3202,48.9581],[-95.3191,48.9569],[-95.3188,48.9562],[-95.3179,48.9559],[-95.3175,48.9552],[-95.3177,48.9545],[-95.3182,48.9535],[-95.3181,48.9531],[-95.3177,48.9525],[-95.3154,48.9513],[-95.3151,48.951],[-95.3141,48.9508],[-95.3131,48.9503],[-95.3125,48.9503],[-95.3123,48.9502],[-95.3119,48.9502],[-95.3119,48.9507],[-95.3129,48.9521],[-95.3129,48.9523],[-95.3126,48.9524],[-95.312,48.9524],[-95.3115,48.952],[-95.3108,48.9512],[-95.3104,48.951],[-95.3097,48.951],[-95.3089,48.9511],[-95.3079,48.9509],[-95.3061,48.9502],[-95.3052,48.9495],[-95.3046,48.9482],[-95.3046,48.947],[-95.305,48.9462],[-95.3053,48.9459],[-95.3061,48.9454],[-95.3068,48.9454],[-95.3069,48.9455],[-95.3069,48.9456],[-95.3063,48.9462],[-95.3062,48.9463],[-95.3061,48.9469],[-95.3062,48.9472],[-95.3062,48.9472],[-95.3071,48.9477],[-95.3081,48.948],[-95.3094,48.9481],[-95.3096,48.9482],[-95.3099,48.9484],[-95.31,48.9485],[-95.3103,48.9485],[-95.3104,48.9484],[-95.3103,48.948],[-95.3096,48.9478],[-95.3092,48.9477],[-95.3079,48.9474],[-95.3071,48.9469],[-95.3071,48.9466],[-95.3074,48.9465],[-95.3078,48.9466],[-95.3085,48.947],[-95.3086,48.9469],[-95.3086,48.9465],[-95.3088,48.9464],[-95.3095,48.9463],[-95.3102,48.9463],[-95.3114,48.9461],[-95.3131,48.946],[-95.3141,48.9457],[-95.3148,48.9452],[-95.3154,48.9448],[-95.3168,48.9431],[-95.3181,48.9421],[-95.3189,48.9419],[-95.3219,48.9412],[-95.3225,48.9409],[-95.3228,48.9403],[-95.3231,48.9389],[-95.3229,48.9373],[-95.3225,48.9358],[-95.3223,48.9355],[-95.3228,48.9344],[-95.3222,48.9327],[-95.3209,48.9307],[-95.3208,48.9305],[-95.3195,48.9285],[-95.3168,48.9245],[-95.315,48.9222],[-95.3141,48.921],[-95.3132,48.9198],[-95.3126,48.919],[-95.3119,48.9178],[-95.3115,48.9172],[-95.3109,48.9163],[-95.3102,48.9155],[-95.3093,48.9149],[-95.3092,48.9149],[-95.3085,48.9146],[-95.3078,48.9141],[-95.3074,48.9135],[-95.3064,48.9129],[-95.3061,48.9128],[-95.3059,48.9127],[-95.3043,48.9119],[-95.3038,48.9114],[-95.3027,48.91],[-95.3017,48.9093],[-95.2999,48.9086],[-95.2978,48.9083],[-95.2973,48.9081],[-95.2973,48.908],[-95.2973,48.9077],[-95.2976,48.9074],[-95.2977,48.9073],[-95.2978,48.9073],[-95.2978,48.9072],[-95.2978,48.9072],[-95.2979,48.9072],[-95.2979,48.9072],[-95.2979,48.9071],[-95.298,48.9071],[-95.298,48.9071],[-95.298,48.9071],[-95.2981,48.907],[-95.2982,48.9068],[-95.2983,48.9068],[-95.2985,48.9065],[-95.2985,48.9064],[-95.2986,48.9063],[-95.2988,48.906],[-95.2989,48.906],[-95.2991,48.9057],[-95.2992,48.9055],[-95.2994,48.9053],[-95.2996,48.9051],[-95.2997,48.905],[-95.2999,48.9048],[-95.2999,48.9048],[-95.2999,48.9048],[-95.3,48.9047],[-95.3,48.9047],[-95.3001,48.9047],[-95.3001,48.9046],[-95.3002,48.9045],[-95.3005,48.904],[-95.2993,48.9035],[-95.2983,48.9028],[-95.298,48.9027],[-95.2976,48.9026],[-95.2967,48.9027],[-95.2949,48.9028],[-95.2941,48.9027],[-95.2937,48.9023],[-95.2935,48.902],[-95.2927,48.9019],[-95.2914,48.9019],[-95.2909,48.9017],[-95.2908,48.9016],[-95.2907,48.9014],[-95.2906,48.9011],[-95.2911,48.9008],[-95.2911,48.9006],[-95.2901,48.9003],[-95.2896,48.9],[-95.289,48.8994],[-95.2882,48.8981],[-95.2879,48.8979],[-95.2872,48.8977],[-95.287,48.8976],[-95.2865,48.8975],[-95.2861,48.8976],[-95.2853,48.8977],[-95.2839,48.8975],[-95.2813,48.8967],[-95.2803,48.8965],[-95.2796,48.8962],[-95.279,48.8957],[-95.2782,48.8956],[-95.2773,48.8957],[-95.277,48.8958],[-95.2765,48.8962],[-95.2763,48.8963],[-95.2759,48.8962],[-95.2755,48.8959],[-95.2749,48.8956],[-95.2748,48.8951],[-95.2753,48.8943],[-95.2751,48.8938],[-95.2745,48.8931],[-95.2724,48.8921],[-95.2713,48.8915],[-95.268,48.8905],[-95.2677,48.8903],[-95.2674,48.89],[-95.2666,48.8894],[-95.2654,48.8888],[-95.265,48.8886],[-95.2646,48.8885],[-95.2639,48.8883],[-95.2635,48.888],[-95.2627,48.8877],[-95.2585,48.8867],[-95.2585,48.8867],[-95.257,48.8858],[-95.256,48.885],[-95.2548,48.8845],[-95.2517,48.8839],[-95.2507,48.8836],[-95.2502,48.8835],[-95.2496,48.8834],[-95.2485,48.8832],[-95.248,48.8836],[-95.2472,48.8835],[-95.2458,48.8829],[-95.2439,48.8823],[-95.2429,48.8822],[-95.2429,48.8822],[-95.2423,48.8821],[-95.2407,48.8821],[-95.2391,48.8819],[-95.2381,48.8817],[-95.2356,48.8815],[-95.2335,48.8814],[-95.231,48.8814],[-95.2287,48.8815],[-95.2265,48.8816],[-95.2252,48.8819],[-95.2212,48.883],[-95.2208,48.8831],[-95.2207,48.8831],[-95.22,48.8831],[-95.2193,48.8832],[-95.2188,48.8835],[-95.217,48.8835],[-95.2159,48.8839],[-95.2151,48.884],[-95.2144,48.8843],[-95.2122,48.8842],[-95.2117,48.8847],[-95.2115,48.8847],[-95.2112,48.8848],[-95.2085,48.8846],[-95.2059,48.8848],[-95.2024,48.8852],[-95.2009,48.8855],[-95.2005,48.8856],[-95.1986,48.8855],[-95.1956,48.8862],[-95.1924,48.8865],[-95.1919,48.8866],[-95.1913,48.8868],[-95.1901,48.887],[-95.1889,48.8873],[-95.1877,48.8874],[-95.1863,48.8877],[-95.1851,48.8882],[-95.1819,48.8888],[-95.1797,48.889],[-95.1791,48.889],[-95.1764,48.8893],[-95.173,48.8897],[-95.1701,48.8902],[-95.1674,48.8907],[-95.1648,48.8913],[-95.1641,48.8917],[-95.1618,48.892],[-95.1602,48.892],[-95.1579,48.8919],[-95.1564,48.8919],[-95.1555,48.892],[-95.1528,48.8921],[-95.1508,48.8922],[-95.1483,48.8923],[-95.1469,48.8927],[-95.1459,48.8929],[-95.1438,48.8934],[-95.1436,48.8937],[-95.1404,48.8943],[-95.1381,48.8949],[-95.1355,48.8959],[-95.1351,48.8963],[-95.1348,48.8963],[-95.1343,48.8963],[-95.1337,48.8969],[-95.1322,48.8973],[-95.1312,48.8975],[-95.1252,48.8998],[-95.1239,48.9001],[-95.1233,48.9004],[-95.1228,48.9006],[-95.1214,48.9013],[-95.121,48.9016],[-95.1205,48.9017],[-95.1204,48.9019],[-95.1182,48.9029],[-95.1163,48.9037],[-95.1151,48.9046],[-95.1144,48.9052],[-95.114,48.9061],[-95.1141,48.9064],[-95.1137,48.9069],[-95.1132,48.9071],[-95.113,48.9072],[-95.1126,48.9073],[-95.1107,48.9082],[-95.1096,48.9089],[-95.108,48.9099],[-95.1056,48.9113],[-95.1042,48.9121],[-95.1032,48.9127],[-95.102,48.9132],[-95.1008,48.9142],[-95.0981,48.9159],[-95.098,48.916],[-95.0975,48.9164],[-95.0971,48.9172],[-95.097,48.9176],[-95.0961,48.9181],[-95.0946,48.9191],[-95.0944,48.9193],[-95.0927,48.9204],[-95.0919,48.9207],[-95.0914,48.9208],[-95.0914,48.916],[-95.0912,48.9014],[-95.0911,48.8869],[-95.0908,48.8724],[-95.0908,48.858],[-95.0907,48.8436],[-95.0908,48.8291],[-95.0909,48.8147],[-95.0903,48.8],[-95.0903,48.7855],[-95.0903,48.7711],[-95.0901,48.7566],[-95.0901,48.7421],[-95.0899,48.7277],[-95.0898,48.713],[-95.1046,48.7129],[-95.1104,48.7129],[-95.1119,48.7129],[-95.1259,48.7129],[-95.1297,48.713],[-95.1333,48.713],[-95.1477,48.7129],[-95.1554,48.7129],[-95.1697,48.7129],[-95.1773,48.713],[-95.1917,48.713],[-95.1991,48.713],[-95.2112,48.713],[-95.2206,48.713],[-95.2331,48.713],[-95.2427,48.713],[-95.255,48.713],[-95.2645,48.713],[-95.2656,48.713],[-95.2767,48.713],[-95.2866,48.713],[-95.299,48.713],[-95.3051,48.713],[-95.3084,48.713],[-95.3205,48.713],[-95.3302,48.713],[-95.3425,48.7131],[-95.3425,48.6995],[-95.3424,48.6849],[-95.3423,48.6705],[-95.3424,48.6561],[-95.3425,48.6415],[-95.3426,48.6271],[-95.3424,48.6127],[-95.3426,48.5979],[-95.3423,48.5836],[-95.3423,48.5691],[-95.3424,48.5548],[-95.3425,48.5402],[-95.3628,48.5404],[-95.364,48.5403],[-95.3844,48.5402],[-95.386,48.5402],[-95.4061,48.5402],[-95.4078,48.5402],[-95.4279,48.54],[-95.4297,48.5399],[-95.4494,48.5399],[-95.4513,48.5399],[-95.4712,48.5396],[-95.4726,48.5396],[-95.493,48.5392],[-95.495,48.5392],[-95.5143,48.539],[-95.5163,48.539],[-95.5365,48.5389],[-95.5383,48.5389],[-95.558,48.5388],[-95.5603,48.5388],[-95.5801,48.5387],[-95.5821,48.5387],[-95.6023,48.5389],[-95.6232,48.5391],[-95.6447,48.5393],[-95.6666,48.5394],[-95.6886,48.5395],[-95.7102,48.5395],[-95.7322,48.54],[-95.7539,48.5404],[-95.7758,48.5406],[-95.7976,48.5405],[-95.8192,48.5404],[-95.8411,48.5406],[-95.8621,48.5414],[-95.8829,48.5419],[-95.8851,48.542],[-95.8986,48.5421],[-95.9046,48.5422],[-95.9064,48.5422],[-95.9269,48.5421],[-95.9486,48.5425],[-95.9498,48.5425],[-95.9704,48.543],[-95.9936,48.5435],[-96.0157,48.5437],[-96.0374,48.5438],[-96.0592,48.5437],[-96.0812,48.5436],[-96.1026,48.5438],[-96.1264,48.5439],[-96.1486,48.5442],[-96.1702,48.5445],[-96.1921,48.5446],[-96.2141,48.5449],[-96.2358,48.5452],[-96.2576,48.545],[-96.2794,48.5449],[-96.301,48.5448],[-96.3231,48.5446],[-96.3448,48.5444],[-96.3667,48.5443],[-96.3882,48.5442],[-96.3879,48.5588],[-96.3882,48.5733],[-96.3884,48.5877],[-96.3891,48.6024],[-96.389,48.6165],[-96.388,48.6313],[-96.3879,48.6454],[-96.3877,48.6599],[-96.3871,48.6741],[-96.3874,48.6887],[-96.3866,48.703],[-96.3873,48.7172],[-96.388,48.7172],[-96.4049,48.7172],[-96.4048,48.7318],[-96.4048,48.7465],[-96.4047,48.7607],[-96.4045,48.7758],[-96.4042,48.7903],[-96.4042,48.8048],[-96.4042,48.8198],[-96.4043,48.8343],[-96.4045,48.8491],[-96.4047,48.8635],[-96.405,48.878],[-96.405,48.8926],[-96.4053,48.9068],[-96.4053,48.9081],[-96.4053,48.9137],[-96.4054,48.9214],[-96.4054,48.9225],[-96.4053,48.936],[-96.4053,48.9371],[-96.4053,48.9504],[-96.4053,48.9515],[-96.4053,48.9648],[-96.4053,48.9658],[-96.4053,48.9705],[-96.4054,48.9793],[-96.4054,48.9803],[-96.4054,48.994],[-96.4054,48.9947],[-96.4054,49.0001]]],"type":"Polygon"},"id":"68","properties":{"Area":4347098503.12714,"CTYONLY_":4,"Code":"ROSE","LASTMOD":"2001-04-12T09:32:44Z","Name":"Roseau","Perimiter":302590.75293},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&filter=CTYONLY_%3D12%20div%203","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&filter=CTYONLY_%3D12%20div%203","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":1,"numberReturned":1,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_text_double_constant.json.txt b/msautotest/api/expected/ogcapi_cql2_text_double_constant.json.txt new file mode 100644 index 0000000000..ae536b468b --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_text_double_constant.json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 1 +OGC-NumberReturned: 1 + +{"features":[{"geometry":{"coordinates":[[[-94.4299,48.7012],[-94.4241,48.7053],[-94.4213,48.7086],[-94.4189,48.7103],[-94.4158,48.711],[-94.4081,48.7106],[-94.406,48.7105],[-94.3889,48.712],[-94.3859,48.7119],[-94.384,48.7119],[-94.3801,48.7111],[-94.3687,48.7065],[-94.3646,48.7059],[-94.3533,48.7042],[-94.3431,48.7035],[-94.3429,48.7035],[-94.3287,48.7045],[-94.3214,48.7067],[-94.3088,48.7103],[-94.2995,48.709],[-94.2911,48.7079],[-94.2829,48.7057],[-94.2781,48.7024],[-94.2745,48.6999],[-94.2694,48.6995],[-94.2644,48.699],[-94.261,48.6966],[-94.258,48.6918],[-94.2565,48.6901],[-94.2529,48.6864],[-94.2521,48.685],[-94.2514,48.6837],[-94.2507,48.6782],[-94.2527,48.6707],[-94.253,48.6693],[-94.2548,48.664],[-94.2546,48.6615],[-94.2509,48.657],[-94.2499,48.6563],[-94.2467,48.6542],[-94.2445,48.6535],[-94.2343,48.6524],[-94.2335,48.6524],[-94.2242,48.6495],[-94.2144,48.6494],[-94.2124,48.6496],[-94.1996,48.651],[-94.1915,48.6506],[-94.1886,48.6504],[-94.1689,48.6483],[-94.1678,48.6482],[-94.1574,48.6458],[-94.1522,48.6455],[-94.1458,48.6458],[-94.1391,48.646],[-94.126,48.6444],[-94.1235,48.6444],[-94.11,48.6443],[-94.1023,48.6455],[-94.0999,48.6459],[-94.0912,48.6437],[-94.0849,48.6441],[-94.0804,48.6442],[-94.0767,48.6442],[-94.0714,48.6459],[-94.0658,48.6462],[-94.0642,48.6438],[-94.0603,48.6431],[-94.0581,48.6434],[-94.0525,48.644],[-94.0432,48.6435],[-94.0393,48.6423],[-94.0364,48.6413],[-94.0356,48.6411],[-94.0295,48.6409],[-94.0153,48.6424],[-94.0069,48.6433],[-94.0007,48.6428],[-93.9931,48.6412],[-93.9897,48.6405],[-93.984,48.6401],[-93.9777,48.6385],[-93.9712,48.6385],[-93.968,48.6385],[-93.9596,48.6372],[-93.953,48.6341],[-93.9497,48.6339],[-93.934,48.6326],[-93.9272,48.6327],[-93.9169,48.6329],[-93.9134,48.6353],[-93.9057,48.6346],[-93.9054,48.6345],[-93.8948,48.6324],[-93.8853,48.6318],[-93.8844,48.6318],[-93.8757,48.6319],[-93.8698,48.6311],[-93.8624,48.631],[-93.848,48.6308],[-93.8443,48.6303],[-93.8404,48.6289],[-93.8393,48.6286],[-93.8365,48.6276],[-93.8334,48.6256],[-93.8292,48.6177],[-93.825,48.6136],[-93.8245,48.613],[-93.8214,48.6092],[-93.8182,48.5994],[-93.8175,48.597],[-93.8172,48.5964],[-93.813,48.588],[-93.8103,48.5846],[-93.8063,48.5796],[-93.8041,48.5703],[-93.8041,48.5702],[-93.8051,48.5644],[-93.808,48.5569],[-93.8088,48.5555],[-93.8119,48.5503],[-93.8102,48.5445],[-93.8109,48.5412],[-93.8109,48.541],[-93.818,48.535],[-93.818,48.5346],[-93.8184,48.5315],[-93.8178,48.5306],[-93.8161,48.5285],[-93.8145,48.5273],[-93.8111,48.5247],[-93.803,48.522],[-93.7964,48.5182],[-93.7933,48.5164],[-93.7879,48.5159],[-93.7745,48.5162],[-93.768,48.5164],[-93.7665,48.5164],[-93.7617,48.5166],[-93.7534,48.5158],[-93.7442,48.5175],[-93.739,48.5185],[-93.731,48.5185],[-93.7225,48.5178],[-93.7206,48.5176],[-93.7108,48.5186],[-93.7061,48.5182],[-93.7006,48.517],[-93.693,48.5152],[-93.6866,48.5154],[-93.6791,48.5167],[-93.6778,48.5169],[-93.6593,48.5165],[-93.657,48.5167],[-93.6473,48.5177],[-93.6433,48.519],[-93.6421,48.5199],[-93.6395,48.5218],[-93.6357,48.5285],[-93.6344,48.5293],[-93.6311,48.5313],[-93.6284,48.5319],[-93.6256,48.5315],[-93.6211,48.5264],[-93.6166,48.5238],[-93.6134,48.5228],[-93.6122,48.5225],[-93.6051,48.5231],[-93.5962,48.5287],[-93.5919,48.5299],[-93.5901,48.5305],[-93.581,48.5271],[-93.5761,48.527],[-93.5701,48.528],[-93.5602,48.5297],[-93.5484,48.5294],[-93.5476,48.5294],[-93.5425,48.53],[-93.5366,48.5319],[-93.5269,48.5341],[-93.5263,48.5341],[-93.5244,48.5343],[-93.5171,48.5348],[-93.5047,48.5399],[-93.501,48.5414],[-93.4952,48.5426],[-93.4854,48.5433],[-93.4833,48.5437],[-93.4673,48.5465],[-93.4655,48.5478],[-93.4625,48.5498],[-93.462,48.5505],[-93.4596,48.5537],[-93.4576,48.5598],[-93.4576,48.5621],[-93.4575,48.5672],[-93.4619,48.5731],[-93.4619,48.5734],[-93.4631,48.5767],[-93.4671,48.5885],[-93.4656,48.59],[-93.4654,48.5915],[-93.4654,48.5917],[-93.4627,48.5927],[-93.46,48.5927],[-93.4547,48.5927],[-93.4398,48.5937],[-93.4385,48.5942],[-93.4347,48.5954],[-93.4298,48.5997],[-93.4226,48.6032],[-93.4193,48.6036],[-93.416,48.605],[-93.4152,48.6053],[-93.415,48.6056],[-93.4144,48.6064],[-93.4056,48.6099],[-93.4034,48.61],[-93.4029,48.6077],[-93.4013,48.6079],[-93.3994,48.6055],[-93.3986,48.6045],[-93.3953,48.6038],[-93.3937,48.6041],[-93.3837,48.606],[-93.3724,48.6059],[-93.3714,48.6059],[-93.3672,48.6082],[-93.3619,48.6141],[-93.355,48.6114],[-93.3526,48.6135],[-93.3533,48.615],[-93.3513,48.62],[-93.3505,48.6219],[-93.3486,48.6265],[-93.3276,48.6302],[-93.3057,48.634],[-93.3048,48.6341],[-93.2838,48.6378],[-93.2634,48.6413],[-93.2546,48.6429],[-93.2422,48.6428],[-93.2193,48.6426],[-93.2075,48.6426],[-93.1975,48.6365],[-93.191,48.6325],[-93.184,48.6282],[-93.1783,48.6231],[-93.1754,48.6232],[-93.1531,48.6244],[-93.1319,48.6256],[-93.1104,48.6267],[-93.0903,48.6278],[-93.0884,48.6278],[-93.0886,48.6163],[-93.0895,48.6016],[-93.0898,48.5872],[-93.09,48.5727],[-93.0902,48.5583],[-93.0902,48.5441],[-93.0903,48.5296],[-93.0905,48.5151],[-93.0905,48.501],[-93.091,48.4884],[-93.0911,48.4867],[-93.0914,48.474],[-93.0915,48.4724],[-93.0918,48.4596],[-93.0919,48.458],[-93.092,48.4449],[-93.092,48.4436],[-93.0922,48.4303],[-93.0922,48.429],[-93.0923,48.4147],[-93.0935,48.4147],[-93.0938,48.4024],[-93.094,48.3879],[-93.094,48.3734],[-93.0945,48.3589],[-93.0948,48.3442],[-93.0948,48.3298],[-93.0953,48.3153],[-93.0952,48.3004],[-93.095,48.2862],[-93.0952,48.2716],[-93.0953,48.2576],[-93.0949,48.2426],[-93.0949,48.2425],[-93.0977,48.2426],[-93.0977,48.2271],[-93.0978,48.2126],[-93.0979,48.1981],[-93.0975,48.1836],[-93.097,48.1692],[-93.097,48.1546],[-93.097,48.1402],[-93.0969,48.1259],[-93.0972,48.1114],[-93.097,48.0969],[-93.0968,48.0823],[-93.0965,48.0679],[-93.0965,48.0678],[-93.0892,48.0679],[-93.0892,48.0509],[-93.089,48.0366],[-93.0886,48.022],[-93.0887,48.0075],[-93.0872,47.9932],[-93.088,47.9787],[-93.0809,47.9786],[-93.0809,47.967],[-93.0808,47.9647],[-93.0808,47.9525],[-93.0808,47.9504],[-93.0809,47.938],[-93.0809,47.9356],[-93.0809,47.9235],[-93.0809,47.9212],[-93.0809,47.9088],[-93.0809,47.9067],[-93.0808,47.8945],[-93.0808,47.8922],[-93.1015,47.8927],[-93.1232,47.893],[-93.1448,47.8928],[-93.1656,47.8931],[-93.1671,47.8932],[-93.1871,47.8931],[-93.1893,47.8931],[-93.2087,47.8933],[-93.2115,47.8934],[-93.2331,47.8937],[-93.2532,47.8936],[-93.2745,47.8938],[-93.2962,47.8939],[-93.3169,47.894],[-93.3392,47.8941],[-93.3603,47.8942],[-93.3809,47.8943],[-93.4024,47.8944],[-93.4235,47.8945],[-93.4442,47.8946],[-93.466,47.895],[-93.4874,47.8956],[-93.4892,47.8957],[-93.4933,47.8958],[-93.5085,47.8962],[-93.5105,47.8963],[-93.5297,47.8967],[-93.5303,47.8967],[-93.532,47.8968],[-93.5517,47.8973],[-93.5532,47.8974],[-93.5729,47.8981],[-93.5747,47.8982],[-93.5962,47.8978],[-93.5966,47.8978],[-93.6179,47.8977],[-93.6187,47.8977],[-93.6388,47.8977],[-93.6395,47.8976],[-93.6604,47.8976],[-93.6612,47.8976],[-93.6817,47.8976],[-93.6826,47.8976],[-93.7031,47.8976],[-93.7038,47.8976],[-93.7249,47.8975],[-93.7248,47.8989],[-93.7466,47.8989],[-93.768,47.8991],[-93.7758,47.8991],[-93.7758,47.899],[-93.776,47.8897],[-93.776,47.8842],[-93.7762,47.8753],[-93.7761,47.8697],[-93.7761,47.8607],[-93.7761,47.8553],[-93.7761,47.8464],[-93.7896,47.8465],[-93.7971,47.8466],[-93.8189,47.8467],[-93.8407,47.8468],[-93.8627,47.8469],[-93.8831,47.8471],[-93.9067,47.8471],[-93.9288,47.8475],[-93.9496,47.8475],[-93.9506,47.8475],[-93.971,47.8475],[-93.9725,47.8475],[-93.9927,47.8475],[-93.9942,47.8475],[-94.0141,47.8476],[-94.0161,47.8476],[-94.0375,47.8477],[-94.0591,47.8474],[-94.0807,47.8471],[-94.1022,47.8471],[-94.1239,47.8466],[-94.1448,47.8463],[-94.1657,47.8461],[-94.1822,47.8461],[-94.1871,47.846],[-94.2037,47.846],[-94.2086,47.846],[-94.2252,47.846],[-94.23,47.8461],[-94.2467,47.8462],[-94.2515,47.8462],[-94.2681,47.8462],[-94.2728,47.8462],[-94.2887,47.8462],[-94.3103,47.8458],[-94.3315,47.846],[-94.3532,47.8464],[-94.3747,47.8462],[-94.3964,47.8461],[-94.4185,47.8459],[-94.4186,47.86],[-94.4184,47.8744],[-94.418,47.8886],[-94.4177,47.9031],[-94.4176,47.9041],[-94.4175,47.9175],[-94.4174,47.9186],[-94.4175,47.9332],[-94.4174,47.9477],[-94.4172,47.9623],[-94.4173,47.9769],[-94.4176,47.9914],[-94.4177,48.006],[-94.4176,48.02],[-94.4236,48.0199],[-94.4241,48.0344],[-94.4246,48.0489],[-94.4247,48.0632],[-94.4234,48.0776],[-94.4231,48.092],[-94.4233,48.1059],[-94.4234,48.1204],[-94.4236,48.1348],[-94.4233,48.1491],[-94.4235,48.1637],[-94.4235,48.1781],[-94.4233,48.1923],[-94.4236,48.2067],[-94.4238,48.2212],[-94.4237,48.2356],[-94.4237,48.2504],[-94.424,48.2649],[-94.4243,48.2791],[-94.4244,48.2938],[-94.4246,48.3081],[-94.4248,48.3227],[-94.425,48.3372],[-94.4253,48.352],[-94.4252,48.3675],[-94.4288,48.3675],[-94.4289,48.3821],[-94.4293,48.3964],[-94.4294,48.411],[-94.4293,48.4254],[-94.4292,48.4399],[-94.4293,48.4543],[-94.4296,48.4688],[-94.4296,48.4832],[-94.4299,48.4977],[-94.4303,48.512],[-94.4303,48.5264],[-94.43,48.5409],[-94.4295,48.5554],[-94.4291,48.5698],[-94.4289,48.5844],[-94.4289,48.5988],[-94.4292,48.6133],[-94.4294,48.6276],[-94.4297,48.642],[-94.43,48.6564],[-94.4301,48.6708],[-94.43,48.6852],[-94.4299,48.6998],[-94.4299,48.7012]]],"type":"Polygon"},"id":"36","properties":{"Area":8167237870.91888,"CTYONLY_":5,"Code":"KOOC","LASTMOD":"1999-12-31T23:59:59Z","Name":"Koochiching","Perimiter":412897.43594},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&filter=Area%3D8167237870.91888","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&filter=Area%3D8167237870.91888","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":1,"numberReturned":1,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_text_equal.json.txt b/msautotest/api/expected/ogcapi_cql2_text_equal.json.txt new file mode 100644 index 0000000000..4abc77168f --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_text_equal.json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 1 +OGC-NumberReturned: 1 + +{"features":[{"geometry":{"coordinates":[[[-93.5242,44.5436],[-93.5225,44.5436],[-93.504,44.5438],[-93.5018,44.5438],[-93.4835,44.5438],[-93.4817,44.5438],[-93.4734,44.5438],[-93.4632,44.5438],[-93.4609,44.5438],[-93.4429,44.5438],[-93.4408,44.5438],[-93.4326,44.5438],[-93.4226,44.5439],[-93.4206,44.5439],[-93.4024,44.5439],[-93.4003,44.5439],[-93.383,44.544],[-93.38,44.544],[-93.3627,44.5441],[-93.3596,44.5441],[-93.3556,44.5441],[-93.3424,44.5442],[-93.3395,44.5442],[-93.3221,44.544],[-93.3191,44.544],[-93.3128,44.544],[-93.3019,44.544],[-93.2988,44.544],[-93.2813,44.544],[-93.2814,44.5298],[-93.2815,44.5153],[-93.2815,44.501],[-93.2815,44.4865],[-93.2817,44.472],[-93.2618,44.4718],[-93.2415,44.4716],[-93.2213,44.4714],[-93.2008,44.4714],[-93.1808,44.4713],[-93.1605,44.4713],[-93.1408,44.4712],[-93.1206,44.4713],[-93.1002,44.4718],[-93.0799,44.4719],[-93.0597,44.4718],[-93.0393,44.4719],[-93.0394,44.4576],[-93.0396,44.4432],[-93.0397,44.4287],[-93.0399,44.4143],[-93.04,44.3999],[-93.0401,44.3855],[-93.0402,44.371],[-93.0403,44.3565],[-93.0403,44.3419],[-93.0405,44.3273],[-93.0405,44.3129],[-93.0405,44.2983],[-93.0406,44.2838],[-93.0407,44.2693],[-93.0409,44.2548],[-93.041,44.2402],[-93.0411,44.2257],[-93.0411,44.2113],[-93.0411,44.1968],[-93.0427,44.1968],[-93.0459,44.1968],[-93.0613,44.1967],[-93.0661,44.1967],[-93.0815,44.1967],[-93.0862,44.1967],[-93.1003,44.1967],[-93.1015,44.1967],[-93.1063,44.1967],[-93.1092,44.1967],[-93.1218,44.1967],[-93.1267,44.1967],[-93.1301,44.1967],[-93.1418,44.1967],[-93.1467,44.1967],[-93.1561,44.1966],[-93.1622,44.1966],[-93.1661,44.1966],[-93.1703,44.1966],[-93.1822,44.1966],[-93.1856,44.1966],[-93.1865,44.1966],[-93.2023,44.1966],[-93.2037,44.1966],[-93.2064,44.1966],[-93.2225,44.1966],[-93.2265,44.1966],[-93.2292,44.1966],[-93.2426,44.1966],[-93.2465,44.1966],[-93.255,44.1966],[-93.2629,44.1966],[-93.2664,44.1966],[-93.2767,44.1966],[-93.283,44.1966],[-93.2865,44.1965],[-93.2905,44.1965],[-93.3032,44.1965],[-93.3063,44.1965],[-93.3235,44.1965],[-93.3264,44.1965],[-93.3277,44.1965],[-93.3436,44.1965],[-93.3466,44.1965],[-93.3639,44.1965],[-93.3666,44.1965],[-93.3842,44.1965],[-93.3866,44.1965],[-93.4042,44.1965],[-93.4065,44.1965],[-93.4244,44.1964],[-93.4267,44.1964],[-93.4447,44.1964],[-93.4469,44.1964],[-93.4648,44.1963],[-93.467,44.1963],[-93.4852,44.1964],[-93.4872,44.1964],[-93.5053,44.1963],[-93.507,44.1963],[-93.5255,44.1962],[-93.5253,44.2107],[-93.5251,44.2251],[-93.5251,44.2388],[-93.5251,44.2533],[-93.5252,44.2685],[-93.5252,44.2829],[-93.5252,44.2975],[-93.5252,44.312],[-93.5249,44.3266],[-93.5249,44.3411],[-93.5245,44.3557],[-93.5245,44.3704],[-93.5246,44.3848],[-93.5245,44.3994],[-93.5245,44.4138],[-93.5245,44.4283],[-93.5245,44.4427],[-93.5245,44.4572],[-93.5244,44.4717],[-93.5245,44.4862],[-93.5244,44.5007],[-93.5243,44.5152],[-93.5244,44.5297],[-93.5242,44.5436]]],"type":"Polygon"},"id":"66","properties":{"Area":1335114621.00336,"CTYONLY_":66,"Code":"RICE","LASTMOD":"2010-10-17T00:00:00Z","Name":"Rice","Perimiter":154431.78788},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&filter=Name%3D'Rice'","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&filter=Name%3D'Rice'","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":1,"numberReturned":1,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_text_filter_crs.json.txt b/msautotest/api/expected/ogcapi_cql2_text_filter_crs.json.txt new file mode 100644 index 0000000000..9d01f297ea --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_text_filter_crs.json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 1 +OGC-NumberReturned: 1 + +{"features":[{"geometry":{"coordinates":[[[-94.4299,48.7012],[-94.4241,48.7053],[-94.4213,48.7086],[-94.4189,48.7103],[-94.4158,48.711],[-94.4081,48.7106],[-94.406,48.7105],[-94.3889,48.712],[-94.3859,48.7119],[-94.384,48.7119],[-94.3801,48.7111],[-94.3687,48.7065],[-94.3646,48.7059],[-94.3533,48.7042],[-94.3431,48.7035],[-94.3429,48.7035],[-94.3287,48.7045],[-94.3214,48.7067],[-94.3088,48.7103],[-94.2995,48.709],[-94.2911,48.7079],[-94.2829,48.7057],[-94.2781,48.7024],[-94.2745,48.6999],[-94.2694,48.6995],[-94.2644,48.699],[-94.261,48.6966],[-94.258,48.6918],[-94.2565,48.6901],[-94.2529,48.6864],[-94.2521,48.685],[-94.2514,48.6837],[-94.2507,48.6782],[-94.2527,48.6707],[-94.253,48.6693],[-94.2548,48.664],[-94.2546,48.6615],[-94.2509,48.657],[-94.2499,48.6563],[-94.2467,48.6542],[-94.2445,48.6535],[-94.2343,48.6524],[-94.2335,48.6524],[-94.2242,48.6495],[-94.2144,48.6494],[-94.2124,48.6496],[-94.1996,48.651],[-94.1915,48.6506],[-94.1886,48.6504],[-94.1689,48.6483],[-94.1678,48.6482],[-94.1574,48.6458],[-94.1522,48.6455],[-94.1458,48.6458],[-94.1391,48.646],[-94.126,48.6444],[-94.1235,48.6444],[-94.11,48.6443],[-94.1023,48.6455],[-94.0999,48.6459],[-94.0912,48.6437],[-94.0849,48.6441],[-94.0804,48.6442],[-94.0767,48.6442],[-94.0714,48.6459],[-94.0658,48.6462],[-94.0642,48.6438],[-94.0603,48.6431],[-94.0581,48.6434],[-94.0525,48.644],[-94.0432,48.6435],[-94.0393,48.6423],[-94.0364,48.6413],[-94.0356,48.6411],[-94.0295,48.6409],[-94.0153,48.6424],[-94.0069,48.6433],[-94.0007,48.6428],[-93.9931,48.6412],[-93.9897,48.6405],[-93.984,48.6401],[-93.9777,48.6385],[-93.9712,48.6385],[-93.968,48.6385],[-93.9596,48.6372],[-93.953,48.6341],[-93.9497,48.6339],[-93.934,48.6326],[-93.9272,48.6327],[-93.9169,48.6329],[-93.9134,48.6353],[-93.9057,48.6346],[-93.9054,48.6345],[-93.8948,48.6324],[-93.8853,48.6318],[-93.8844,48.6318],[-93.8757,48.6319],[-93.8698,48.6311],[-93.8624,48.631],[-93.848,48.6308],[-93.8443,48.6303],[-93.8404,48.6289],[-93.8393,48.6286],[-93.8365,48.6276],[-93.8334,48.6256],[-93.8292,48.6177],[-93.825,48.6136],[-93.8245,48.613],[-93.8214,48.6092],[-93.8182,48.5994],[-93.8175,48.597],[-93.8172,48.5964],[-93.813,48.588],[-93.8103,48.5846],[-93.8063,48.5796],[-93.8041,48.5703],[-93.8041,48.5702],[-93.8051,48.5644],[-93.808,48.5569],[-93.8088,48.5555],[-93.8119,48.5503],[-93.8102,48.5445],[-93.8109,48.5412],[-93.8109,48.541],[-93.818,48.535],[-93.818,48.5346],[-93.8184,48.5315],[-93.8178,48.5306],[-93.8161,48.5285],[-93.8145,48.5273],[-93.8111,48.5247],[-93.803,48.522],[-93.7964,48.5182],[-93.7933,48.5164],[-93.7879,48.5159],[-93.7745,48.5162],[-93.768,48.5164],[-93.7665,48.5164],[-93.7617,48.5166],[-93.7534,48.5158],[-93.7442,48.5175],[-93.739,48.5185],[-93.731,48.5185],[-93.7225,48.5178],[-93.7206,48.5176],[-93.7108,48.5186],[-93.7061,48.5182],[-93.7006,48.517],[-93.693,48.5152],[-93.6866,48.5154],[-93.6791,48.5167],[-93.6778,48.5169],[-93.6593,48.5165],[-93.657,48.5167],[-93.6473,48.5177],[-93.6433,48.519],[-93.6421,48.5199],[-93.6395,48.5218],[-93.6357,48.5285],[-93.6344,48.5293],[-93.6311,48.5313],[-93.6284,48.5319],[-93.6256,48.5315],[-93.6211,48.5264],[-93.6166,48.5238],[-93.6134,48.5228],[-93.6122,48.5225],[-93.6051,48.5231],[-93.5962,48.5287],[-93.5919,48.5299],[-93.5901,48.5305],[-93.581,48.5271],[-93.5761,48.527],[-93.5701,48.528],[-93.5602,48.5297],[-93.5484,48.5294],[-93.5476,48.5294],[-93.5425,48.53],[-93.5366,48.5319],[-93.5269,48.5341],[-93.5263,48.5341],[-93.5244,48.5343],[-93.5171,48.5348],[-93.5047,48.5399],[-93.501,48.5414],[-93.4952,48.5426],[-93.4854,48.5433],[-93.4833,48.5437],[-93.4673,48.5465],[-93.4655,48.5478],[-93.4625,48.5498],[-93.462,48.5505],[-93.4596,48.5537],[-93.4576,48.5598],[-93.4576,48.5621],[-93.4575,48.5672],[-93.4619,48.5731],[-93.4619,48.5734],[-93.4631,48.5767],[-93.4671,48.5885],[-93.4656,48.59],[-93.4654,48.5915],[-93.4654,48.5917],[-93.4627,48.5927],[-93.46,48.5927],[-93.4547,48.5927],[-93.4398,48.5937],[-93.4385,48.5942],[-93.4347,48.5954],[-93.4298,48.5997],[-93.4226,48.6032],[-93.4193,48.6036],[-93.416,48.605],[-93.4152,48.6053],[-93.415,48.6056],[-93.4144,48.6064],[-93.4056,48.6099],[-93.4034,48.61],[-93.4029,48.6077],[-93.4013,48.6079],[-93.3994,48.6055],[-93.3986,48.6045],[-93.3953,48.6038],[-93.3937,48.6041],[-93.3837,48.606],[-93.3724,48.6059],[-93.3714,48.6059],[-93.3672,48.6082],[-93.3619,48.6141],[-93.355,48.6114],[-93.3526,48.6135],[-93.3533,48.615],[-93.3513,48.62],[-93.3505,48.6219],[-93.3486,48.6265],[-93.3276,48.6302],[-93.3057,48.634],[-93.3048,48.6341],[-93.2838,48.6378],[-93.2634,48.6413],[-93.2546,48.6429],[-93.2422,48.6428],[-93.2193,48.6426],[-93.2075,48.6426],[-93.1975,48.6365],[-93.191,48.6325],[-93.184,48.6282],[-93.1783,48.6231],[-93.1754,48.6232],[-93.1531,48.6244],[-93.1319,48.6256],[-93.1104,48.6267],[-93.0903,48.6278],[-93.0884,48.6278],[-93.0886,48.6163],[-93.0895,48.6016],[-93.0898,48.5872],[-93.09,48.5727],[-93.0902,48.5583],[-93.0902,48.5441],[-93.0903,48.5296],[-93.0905,48.5151],[-93.0905,48.501],[-93.091,48.4884],[-93.0911,48.4867],[-93.0914,48.474],[-93.0915,48.4724],[-93.0918,48.4596],[-93.0919,48.458],[-93.092,48.4449],[-93.092,48.4436],[-93.0922,48.4303],[-93.0922,48.429],[-93.0923,48.4147],[-93.0935,48.4147],[-93.0938,48.4024],[-93.094,48.3879],[-93.094,48.3734],[-93.0945,48.3589],[-93.0948,48.3442],[-93.0948,48.3298],[-93.0953,48.3153],[-93.0952,48.3004],[-93.095,48.2862],[-93.0952,48.2716],[-93.0953,48.2576],[-93.0949,48.2426],[-93.0949,48.2425],[-93.0977,48.2426],[-93.0977,48.2271],[-93.0978,48.2126],[-93.0979,48.1981],[-93.0975,48.1836],[-93.097,48.1692],[-93.097,48.1546],[-93.097,48.1402],[-93.0969,48.1259],[-93.0972,48.1114],[-93.097,48.0969],[-93.0968,48.0823],[-93.0965,48.0679],[-93.0965,48.0678],[-93.0892,48.0679],[-93.0892,48.0509],[-93.089,48.0366],[-93.0886,48.022],[-93.0887,48.0075],[-93.0872,47.9932],[-93.088,47.9787],[-93.0809,47.9786],[-93.0809,47.967],[-93.0808,47.9647],[-93.0808,47.9525],[-93.0808,47.9504],[-93.0809,47.938],[-93.0809,47.9356],[-93.0809,47.9235],[-93.0809,47.9212],[-93.0809,47.9088],[-93.0809,47.9067],[-93.0808,47.8945],[-93.0808,47.8922],[-93.1015,47.8927],[-93.1232,47.893],[-93.1448,47.8928],[-93.1656,47.8931],[-93.1671,47.8932],[-93.1871,47.8931],[-93.1893,47.8931],[-93.2087,47.8933],[-93.2115,47.8934],[-93.2331,47.8937],[-93.2532,47.8936],[-93.2745,47.8938],[-93.2962,47.8939],[-93.3169,47.894],[-93.3392,47.8941],[-93.3603,47.8942],[-93.3809,47.8943],[-93.4024,47.8944],[-93.4235,47.8945],[-93.4442,47.8946],[-93.466,47.895],[-93.4874,47.8956],[-93.4892,47.8957],[-93.4933,47.8958],[-93.5085,47.8962],[-93.5105,47.8963],[-93.5297,47.8967],[-93.5303,47.8967],[-93.532,47.8968],[-93.5517,47.8973],[-93.5532,47.8974],[-93.5729,47.8981],[-93.5747,47.8982],[-93.5962,47.8978],[-93.5966,47.8978],[-93.6179,47.8977],[-93.6187,47.8977],[-93.6388,47.8977],[-93.6395,47.8976],[-93.6604,47.8976],[-93.6612,47.8976],[-93.6817,47.8976],[-93.6826,47.8976],[-93.7031,47.8976],[-93.7038,47.8976],[-93.7249,47.8975],[-93.7248,47.8989],[-93.7466,47.8989],[-93.768,47.8991],[-93.7758,47.8991],[-93.7758,47.899],[-93.776,47.8897],[-93.776,47.8842],[-93.7762,47.8753],[-93.7761,47.8697],[-93.7761,47.8607],[-93.7761,47.8553],[-93.7761,47.8464],[-93.7896,47.8465],[-93.7971,47.8466],[-93.8189,47.8467],[-93.8407,47.8468],[-93.8627,47.8469],[-93.8831,47.8471],[-93.9067,47.8471],[-93.9288,47.8475],[-93.9496,47.8475],[-93.9506,47.8475],[-93.971,47.8475],[-93.9725,47.8475],[-93.9927,47.8475],[-93.9942,47.8475],[-94.0141,47.8476],[-94.0161,47.8476],[-94.0375,47.8477],[-94.0591,47.8474],[-94.0807,47.8471],[-94.1022,47.8471],[-94.1239,47.8466],[-94.1448,47.8463],[-94.1657,47.8461],[-94.1822,47.8461],[-94.1871,47.846],[-94.2037,47.846],[-94.2086,47.846],[-94.2252,47.846],[-94.23,47.8461],[-94.2467,47.8462],[-94.2515,47.8462],[-94.2681,47.8462],[-94.2728,47.8462],[-94.2887,47.8462],[-94.3103,47.8458],[-94.3315,47.846],[-94.3532,47.8464],[-94.3747,47.8462],[-94.3964,47.8461],[-94.4185,47.8459],[-94.4186,47.86],[-94.4184,47.8744],[-94.418,47.8886],[-94.4177,47.9031],[-94.4176,47.9041],[-94.4175,47.9175],[-94.4174,47.9186],[-94.4175,47.9332],[-94.4174,47.9477],[-94.4172,47.9623],[-94.4173,47.9769],[-94.4176,47.9914],[-94.4177,48.006],[-94.4176,48.02],[-94.4236,48.0199],[-94.4241,48.0344],[-94.4246,48.0489],[-94.4247,48.0632],[-94.4234,48.0776],[-94.4231,48.092],[-94.4233,48.1059],[-94.4234,48.1204],[-94.4236,48.1348],[-94.4233,48.1491],[-94.4235,48.1637],[-94.4235,48.1781],[-94.4233,48.1923],[-94.4236,48.2067],[-94.4238,48.2212],[-94.4237,48.2356],[-94.4237,48.2504],[-94.424,48.2649],[-94.4243,48.2791],[-94.4244,48.2938],[-94.4246,48.3081],[-94.4248,48.3227],[-94.425,48.3372],[-94.4253,48.352],[-94.4252,48.3675],[-94.4288,48.3675],[-94.4289,48.3821],[-94.4293,48.3964],[-94.4294,48.411],[-94.4293,48.4254],[-94.4292,48.4399],[-94.4293,48.4543],[-94.4296,48.4688],[-94.4296,48.4832],[-94.4299,48.4977],[-94.4303,48.512],[-94.4303,48.5264],[-94.43,48.5409],[-94.4295,48.5554],[-94.4291,48.5698],[-94.4289,48.5844],[-94.4289,48.5988],[-94.4292,48.6133],[-94.4294,48.6276],[-94.4297,48.642],[-94.43,48.6564],[-94.4301,48.6708],[-94.43,48.6852],[-94.4299,48.6998],[-94.4299,48.7012]]],"type":"Polygon"},"id":"36","properties":{"Area":8167237870.91888,"CTYONLY_":5,"Code":"KOOC","LASTMOD":"1999-12-31T23:59:59Z","Name":"Koochiching","Perimiter":412897.43594},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=1&offset=0&filter=s_intersects(geom%2Cpoint(48.642%20-94.4297))&filter-crs=http%3A%2F%2Fwww.opengis.net%2Fdef%2Fcrs%2FEPSG%2F0%2F4326","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=1&offset=0&filter=s_intersects(geom%2Cpoint(48.642%20-94.4297))&filter-crs=http%3A%2F%2Fwww.opengis.net%2Fdef%2Fcrs%2FEPSG%2F0%2F4326","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":1,"numberReturned":1,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_text_filter_crs_invalid.json.txt b/msautotest/api/expected/ogcapi_cql2_text_filter_crs_invalid.json.txt new file mode 100644 index 0000000000..908e3bc625 --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_text_filter_crs_invalid.json.txt @@ -0,0 +1,4 @@ +Content-Type: application/json +Status: 400 + +{"code":"InvalidParameterValue","description":"Bad value for filter-crs."} diff --git a/msautotest/api/expected/ogcapi_cql2_text_filter_lang_invalid.json.txt b/msautotest/api/expected/ogcapi_cql2_text_filter_lang_invalid.json.txt new file mode 100644 index 0000000000..4d087dfbe8 --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_text_filter_lang_invalid.json.txt @@ -0,0 +1,4 @@ +Content-Type: application/json +Status: 400 + +{"code":"InvalidParameterValue","description":"Only filter-lang=cql2-text or filter-lang=cql2-json is handled"} diff --git a/msautotest/api/expected/ogcapi_cql2_text_four_and.json.txt b/msautotest/api/expected/ogcapi_cql2_text_four_and.json.txt new file mode 100644 index 0000000000..4d7f94cefc --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_text_four_and.json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 1 +OGC-NumberReturned: 1 + +{"features":[{"geometry":{"coordinates":[[[-93.5242,44.5436],[-93.5225,44.5436],[-93.504,44.5438],[-93.5018,44.5438],[-93.4835,44.5438],[-93.4817,44.5438],[-93.4734,44.5438],[-93.4632,44.5438],[-93.4609,44.5438],[-93.4429,44.5438],[-93.4408,44.5438],[-93.4326,44.5438],[-93.4226,44.5439],[-93.4206,44.5439],[-93.4024,44.5439],[-93.4003,44.5439],[-93.383,44.544],[-93.38,44.544],[-93.3627,44.5441],[-93.3596,44.5441],[-93.3556,44.5441],[-93.3424,44.5442],[-93.3395,44.5442],[-93.3221,44.544],[-93.3191,44.544],[-93.3128,44.544],[-93.3019,44.544],[-93.2988,44.544],[-93.2813,44.544],[-93.2814,44.5298],[-93.2815,44.5153],[-93.2815,44.501],[-93.2815,44.4865],[-93.2817,44.472],[-93.2618,44.4718],[-93.2415,44.4716],[-93.2213,44.4714],[-93.2008,44.4714],[-93.1808,44.4713],[-93.1605,44.4713],[-93.1408,44.4712],[-93.1206,44.4713],[-93.1002,44.4718],[-93.0799,44.4719],[-93.0597,44.4718],[-93.0393,44.4719],[-93.0394,44.4576],[-93.0396,44.4432],[-93.0397,44.4287],[-93.0399,44.4143],[-93.04,44.3999],[-93.0401,44.3855],[-93.0402,44.371],[-93.0403,44.3565],[-93.0403,44.3419],[-93.0405,44.3273],[-93.0405,44.3129],[-93.0405,44.2983],[-93.0406,44.2838],[-93.0407,44.2693],[-93.0409,44.2548],[-93.041,44.2402],[-93.0411,44.2257],[-93.0411,44.2113],[-93.0411,44.1968],[-93.0427,44.1968],[-93.0459,44.1968],[-93.0613,44.1967],[-93.0661,44.1967],[-93.0815,44.1967],[-93.0862,44.1967],[-93.1003,44.1967],[-93.1015,44.1967],[-93.1063,44.1967],[-93.1092,44.1967],[-93.1218,44.1967],[-93.1267,44.1967],[-93.1301,44.1967],[-93.1418,44.1967],[-93.1467,44.1967],[-93.1561,44.1966],[-93.1622,44.1966],[-93.1661,44.1966],[-93.1703,44.1966],[-93.1822,44.1966],[-93.1856,44.1966],[-93.1865,44.1966],[-93.2023,44.1966],[-93.2037,44.1966],[-93.2064,44.1966],[-93.2225,44.1966],[-93.2265,44.1966],[-93.2292,44.1966],[-93.2426,44.1966],[-93.2465,44.1966],[-93.255,44.1966],[-93.2629,44.1966],[-93.2664,44.1966],[-93.2767,44.1966],[-93.283,44.1966],[-93.2865,44.1965],[-93.2905,44.1965],[-93.3032,44.1965],[-93.3063,44.1965],[-93.3235,44.1965],[-93.3264,44.1965],[-93.3277,44.1965],[-93.3436,44.1965],[-93.3466,44.1965],[-93.3639,44.1965],[-93.3666,44.1965],[-93.3842,44.1965],[-93.3866,44.1965],[-93.4042,44.1965],[-93.4065,44.1965],[-93.4244,44.1964],[-93.4267,44.1964],[-93.4447,44.1964],[-93.4469,44.1964],[-93.4648,44.1963],[-93.467,44.1963],[-93.4852,44.1964],[-93.4872,44.1964],[-93.5053,44.1963],[-93.507,44.1963],[-93.5255,44.1962],[-93.5253,44.2107],[-93.5251,44.2251],[-93.5251,44.2388],[-93.5251,44.2533],[-93.5252,44.2685],[-93.5252,44.2829],[-93.5252,44.2975],[-93.5252,44.312],[-93.5249,44.3266],[-93.5249,44.3411],[-93.5245,44.3557],[-93.5245,44.3704],[-93.5246,44.3848],[-93.5245,44.3994],[-93.5245,44.4138],[-93.5245,44.4283],[-93.5245,44.4427],[-93.5245,44.4572],[-93.5244,44.4717],[-93.5245,44.4862],[-93.5244,44.5007],[-93.5243,44.5152],[-93.5244,44.5297],[-93.5242,44.5436]]],"type":"Polygon"},"id":"66","properties":{"Area":1335114621.00336,"CTYONLY_":66,"Code":"RICE","LASTMOD":"2010-10-17T00:00:00Z","Name":"Rice","Perimiter":154431.78788},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&filter=Name%3D'Rice'%20AND%201%3D1%20AND%201%3D1%20AND%201%3D1","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&filter=Name%3D'Rice'%20AND%201%3D1%20AND%201%3D1%20AND%201%3D1","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":1,"numberReturned":1,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_text_ge.json.txt b/msautotest/api/expected/ogcapi_cql2_text_ge.json.txt new file mode 100644 index 0000000000..885d7eaa36 --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_text_ge.json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 2 +OGC-NumberReturned: 2 + +{"features":[{"geometry":{"coordinates":[[[-91.267,47.2703],[-91.267,47.2703],[-91.2669,47.2703],[-91.2668,47.2703],[-91.2666,47.2703],[-91.2665,47.2702],[-91.2666,47.2701],[-91.2666,47.2701],[-91.2668,47.2701],[-91.267,47.2702],[-91.267,47.2703]]],"type":"Polygon"},"id":"38","properties":{"Area":691.59892,"CTYONLY_":117,"Code":"LAKE","LASTMOD":"2003-01-01T01:10:00Z","Name":"Lake","Perimiter":103.08393},"type":"Feature"},{"geometry":{"coordinates":[[[-91.2824,47.2658],[-91.2823,47.2658],[-91.2822,47.2658],[-91.282,47.2659],[-91.2819,47.2659],[-91.2818,47.2659],[-91.2818,47.2658],[-91.2818,47.2658],[-91.2821,47.2657],[-91.2824,47.2655],[-91.2825,47.2654],[-91.2826,47.2654],[-91.2827,47.2654],[-91.2828,47.2655],[-91.2827,47.2657],[-91.2825,47.2658],[-91.2824,47.2658]]],"type":"Polygon"},"id":"38","properties":{"Area":2024.76285,"CTYONLY_":118,"Code":"LAKE","LASTMOD":"2003-01-01T01:10:00Z","Name":"Lake","Perimiter":206.26115},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&filter=CTYONLY_%3E%3D117","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&filter=CTYONLY_%3E%3D117","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":2,"numberReturned":2,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_text_gt.json.txt b/msautotest/api/expected/ogcapi_cql2_text_gt.json.txt new file mode 100644 index 0000000000..f22a0baece --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_text_gt.json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 1 +OGC-NumberReturned: 1 + +{"features":[{"geometry":{"coordinates":[[[-91.2824,47.2658],[-91.2823,47.2658],[-91.2822,47.2658],[-91.282,47.2659],[-91.2819,47.2659],[-91.2818,47.2659],[-91.2818,47.2658],[-91.2818,47.2658],[-91.2821,47.2657],[-91.2824,47.2655],[-91.2825,47.2654],[-91.2826,47.2654],[-91.2827,47.2654],[-91.2828,47.2655],[-91.2827,47.2657],[-91.2825,47.2658],[-91.2824,47.2658]]],"type":"Polygon"},"id":"38","properties":{"Area":2024.76285,"CTYONLY_":118,"Code":"LAKE","LASTMOD":"2003-01-01T01:10:00Z","Name":"Lake","Perimiter":206.26115},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&filter=CTYONLY_%3E117","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&filter=CTYONLY_%3E117","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":1,"numberReturned":1,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_text_iequal.json.txt b/msautotest/api/expected/ogcapi_cql2_text_iequal.json.txt new file mode 100644 index 0000000000..b520e50ebb --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_text_iequal.json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 1 +OGC-NumberReturned: 1 + +{"features":[{"geometry":{"coordinates":[[[-93.5242,44.5436],[-93.5225,44.5436],[-93.504,44.5438],[-93.5018,44.5438],[-93.4835,44.5438],[-93.4817,44.5438],[-93.4734,44.5438],[-93.4632,44.5438],[-93.4609,44.5438],[-93.4429,44.5438],[-93.4408,44.5438],[-93.4326,44.5438],[-93.4226,44.5439],[-93.4206,44.5439],[-93.4024,44.5439],[-93.4003,44.5439],[-93.383,44.544],[-93.38,44.544],[-93.3627,44.5441],[-93.3596,44.5441],[-93.3556,44.5441],[-93.3424,44.5442],[-93.3395,44.5442],[-93.3221,44.544],[-93.3191,44.544],[-93.3128,44.544],[-93.3019,44.544],[-93.2988,44.544],[-93.2813,44.544],[-93.2814,44.5298],[-93.2815,44.5153],[-93.2815,44.501],[-93.2815,44.4865],[-93.2817,44.472],[-93.2618,44.4718],[-93.2415,44.4716],[-93.2213,44.4714],[-93.2008,44.4714],[-93.1808,44.4713],[-93.1605,44.4713],[-93.1408,44.4712],[-93.1206,44.4713],[-93.1002,44.4718],[-93.0799,44.4719],[-93.0597,44.4718],[-93.0393,44.4719],[-93.0394,44.4576],[-93.0396,44.4432],[-93.0397,44.4287],[-93.0399,44.4143],[-93.04,44.3999],[-93.0401,44.3855],[-93.0402,44.371],[-93.0403,44.3565],[-93.0403,44.3419],[-93.0405,44.3273],[-93.0405,44.3129],[-93.0405,44.2983],[-93.0406,44.2838],[-93.0407,44.2693],[-93.0409,44.2548],[-93.041,44.2402],[-93.0411,44.2257],[-93.0411,44.2113],[-93.0411,44.1968],[-93.0427,44.1968],[-93.0459,44.1968],[-93.0613,44.1967],[-93.0661,44.1967],[-93.0815,44.1967],[-93.0862,44.1967],[-93.1003,44.1967],[-93.1015,44.1967],[-93.1063,44.1967],[-93.1092,44.1967],[-93.1218,44.1967],[-93.1267,44.1967],[-93.1301,44.1967],[-93.1418,44.1967],[-93.1467,44.1967],[-93.1561,44.1966],[-93.1622,44.1966],[-93.1661,44.1966],[-93.1703,44.1966],[-93.1822,44.1966],[-93.1856,44.1966],[-93.1865,44.1966],[-93.2023,44.1966],[-93.2037,44.1966],[-93.2064,44.1966],[-93.2225,44.1966],[-93.2265,44.1966],[-93.2292,44.1966],[-93.2426,44.1966],[-93.2465,44.1966],[-93.255,44.1966],[-93.2629,44.1966],[-93.2664,44.1966],[-93.2767,44.1966],[-93.283,44.1966],[-93.2865,44.1965],[-93.2905,44.1965],[-93.3032,44.1965],[-93.3063,44.1965],[-93.3235,44.1965],[-93.3264,44.1965],[-93.3277,44.1965],[-93.3436,44.1965],[-93.3466,44.1965],[-93.3639,44.1965],[-93.3666,44.1965],[-93.3842,44.1965],[-93.3866,44.1965],[-93.4042,44.1965],[-93.4065,44.1965],[-93.4244,44.1964],[-93.4267,44.1964],[-93.4447,44.1964],[-93.4469,44.1964],[-93.4648,44.1963],[-93.467,44.1963],[-93.4852,44.1964],[-93.4872,44.1964],[-93.5053,44.1963],[-93.507,44.1963],[-93.5255,44.1962],[-93.5253,44.2107],[-93.5251,44.2251],[-93.5251,44.2388],[-93.5251,44.2533],[-93.5252,44.2685],[-93.5252,44.2829],[-93.5252,44.2975],[-93.5252,44.312],[-93.5249,44.3266],[-93.5249,44.3411],[-93.5245,44.3557],[-93.5245,44.3704],[-93.5246,44.3848],[-93.5245,44.3994],[-93.5245,44.4138],[-93.5245,44.4283],[-93.5245,44.4427],[-93.5245,44.4572],[-93.5244,44.4717],[-93.5245,44.4862],[-93.5244,44.5007],[-93.5243,44.5152],[-93.5244,44.5297],[-93.5242,44.5436]]],"type":"Polygon"},"id":"66","properties":{"Area":1335114621.00336,"CTYONLY_":66,"Code":"RICE","LASTMOD":"2010-10-17T00:00:00Z","Name":"Rice","Perimiter":154431.78788},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&filter=CASEI(Name)%3DCASEI('rice')","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&filter=CASEI(Name)%3DCASEI('rice')","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":1,"numberReturned":1,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_text_in_json.txt b/msautotest/api/expected/ogcapi_cql2_text_in_json.txt new file mode 100644 index 0000000000..e82f353929 --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_text_in_json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 2 +OGC-NumberReturned: 2 + +{"features":[{"geometry":{"coordinates":[[[-96.4054,49.0001],[-96.4054,48.9947],[-96.4054,48.994],[-96.4054,48.9803],[-96.4054,48.9793],[-96.4053,48.9705],[-96.4053,48.9658],[-96.4053,48.9648],[-96.4053,48.9515],[-96.4053,48.9504],[-96.4053,48.9371],[-96.4053,48.936],[-96.4054,48.9225],[-96.4054,48.9214],[-96.4053,48.9137],[-96.4053,48.9081],[-96.4053,48.9068],[-96.405,48.8926],[-96.405,48.878],[-96.4047,48.8635],[-96.4045,48.8491],[-96.4043,48.8343],[-96.4042,48.8198],[-96.4042,48.8048],[-96.4042,48.7903],[-96.4045,48.7758],[-96.4047,48.7607],[-96.4048,48.7465],[-96.4048,48.7318],[-96.4049,48.7172],[-96.388,48.7172],[-96.3873,48.7172],[-96.3866,48.703],[-96.3874,48.6887],[-96.3871,48.6741],[-96.3877,48.6599],[-96.3879,48.6454],[-96.388,48.6313],[-96.389,48.6165],[-96.3891,48.6024],[-96.3884,48.5877],[-96.3882,48.5733],[-96.3879,48.5588],[-96.3882,48.5442],[-96.4101,48.544],[-96.4318,48.5438],[-96.4535,48.5436],[-96.4754,48.5435],[-96.4973,48.5434],[-96.518,48.5434],[-96.54,48.5434],[-96.5621,48.5436],[-96.5839,48.5437],[-96.6058,48.5437],[-96.6278,48.5437],[-96.6493,48.5437],[-96.6713,48.5436],[-96.6931,48.5437],[-96.7151,48.5437],[-96.7368,48.5437],[-96.7585,48.5436],[-96.7803,48.5435],[-96.8023,48.5436],[-96.824,48.5436],[-96.8459,48.5434],[-96.8678,48.5433],[-96.8896,48.5433],[-96.9115,48.5432],[-96.9138,48.5433],[-96.9331,48.5435],[-96.9551,48.5437],[-96.9768,48.544],[-96.9985,48.5441],[-97.0194,48.5441],[-97.0416,48.5442],[-97.0635,48.5441],[-97.0852,48.5441],[-97.107,48.544],[-97.1287,48.5439],[-97.1509,48.5439],[-97.1631,48.544],[-97.1637,48.5445],[-97.1659,48.5483],[-97.1662,48.5509],[-97.1661,48.5527],[-97.1654,48.5536],[-97.1645,48.554],[-97.1628,48.5543],[-97.1613,48.5539],[-97.1592,48.5528],[-97.1577,48.5518],[-97.1557,48.5512],[-97.1538,48.5513],[-97.1513,48.5515],[-97.1507,48.5515],[-97.1493,48.5516],[-97.1474,48.5516],[-97.1444,48.5514],[-97.1407,48.5515],[-97.1387,48.5522],[-97.1379,48.553],[-97.1379,48.5542],[-97.1391,48.5554],[-97.141,48.5566],[-97.1426,48.5571],[-97.1464,48.5573],[-97.1505,48.5574],[-97.1515,48.5574],[-97.1551,48.5574],[-97.1578,48.5573],[-97.1606,48.5571],[-97.1631,48.5571],[-97.1646,48.5572],[-97.167,48.5575],[-97.1697,48.5584],[-97.1721,48.5591],[-97.1727,48.5593],[-97.174,48.5599],[-97.1749,48.5606],[-97.1753,48.5614],[-97.1754,48.5623],[-97.1749,48.5631],[-97.1744,48.5639],[-97.1723,48.5648],[-97.1721,48.5648],[-97.1706,48.5652],[-97.1687,48.5655],[-97.167,48.5658],[-97.1651,48.5659],[-97.1613,48.5661],[-97.1541,48.5669],[-97.153,48.5671],[-97.1516,48.5677],[-97.1503,48.5688],[-97.1496,48.5695],[-97.1487,48.5707],[-97.1477,48.5727],[-97.1477,48.5728],[-97.1476,48.5731],[-97.1483,48.5763],[-97.15,48.5775],[-97.1501,48.5775],[-97.1548,48.5779],[-97.1592,48.5785],[-97.1605,48.58],[-97.16,48.5816],[-97.1578,48.5826],[-97.1562,48.5828],[-97.1541,48.5826],[-97.1524,48.5823],[-97.15,48.5815],[-97.1494,48.5813],[-97.1484,48.5811],[-97.1449,48.5815],[-97.1436,48.5824],[-97.1431,48.5834],[-97.1429,48.5838],[-97.142,48.5876],[-97.1418,48.5886],[-97.1415,48.5909],[-97.1422,48.5926],[-97.1433,48.5936],[-97.1451,48.594],[-97.1471,48.594],[-97.1497,48.5937],[-97.1525,48.594],[-97.1536,48.5949],[-97.1535,48.5957],[-97.1527,48.5962],[-97.1524,48.5969],[-97.1516,48.598],[-97.1498,48.5981],[-97.1497,48.5981],[-97.1463,48.5977],[-97.1443,48.5981],[-97.143,48.5987],[-97.1416,48.6002],[-97.1403,48.6021],[-97.14,48.6025],[-97.138,48.6044],[-97.1359,48.6054],[-97.1345,48.6065],[-97.1341,48.6075],[-97.1349,48.6082],[-97.1358,48.6086],[-97.137,48.6088],[-97.1396,48.6086],[-97.1443,48.6078],[-97.1474,48.6081],[-97.1494,48.6089],[-97.1495,48.609],[-97.1505,48.6115],[-97.1501,48.6124],[-97.1493,48.6129],[-97.1478,48.6138],[-97.145,48.6146],[-97.1408,48.6149],[-97.137,48.6144],[-97.134,48.6136],[-97.1319,48.6133],[-97.1309,48.6137],[-97.1289,48.614],[-97.1286,48.6153],[-97.1293,48.6168],[-97.1295,48.617],[-97.1311,48.6184],[-97.1342,48.6199],[-97.1353,48.6212],[-97.1346,48.6224],[-97.133,48.6228],[-97.131,48.6227],[-97.1291,48.6222],[-97.1277,48.6212],[-97.1274,48.621],[-97.1259,48.6195],[-97.1253,48.619],[-97.1243,48.6183],[-97.1231,48.6178],[-97.1216,48.6176],[-97.12,48.6178],[-97.1193,48.6182],[-97.1186,48.6191],[-97.1183,48.6198],[-97.1186,48.6209],[-97.1198,48.6221],[-97.1209,48.6232],[-97.1212,48.6233],[-97.122,48.624],[-97.1228,48.6245],[-97.1236,48.625],[-97.1241,48.6254],[-97.1245,48.6257],[-97.1249,48.6259],[-97.1253,48.6261],[-97.126,48.6264],[-97.1266,48.6266],[-97.1272,48.627],[-97.1279,48.6273],[-97.1288,48.6278],[-97.1296,48.6282],[-97.1302,48.6288],[-97.1305,48.6292],[-97.1307,48.6297],[-97.131,48.6303],[-97.131,48.6304],[-97.131,48.6308],[-97.131,48.6315],[-97.1309,48.6317],[-97.1307,48.6321],[-97.1304,48.6325],[-97.1301,48.6326],[-97.1297,48.6328],[-97.1293,48.6329],[-97.129,48.633],[-97.1281,48.6332],[-97.128,48.6333],[-97.1275,48.6333],[-97.1253,48.6334],[-97.1235,48.6333],[-97.1216,48.6327],[-97.1181,48.6308],[-97.1176,48.6307],[-97.115,48.6299],[-97.1133,48.63],[-97.1115,48.6303],[-97.1107,48.6308],[-97.1104,48.6309],[-97.1095,48.6315],[-97.1084,48.6327],[-97.1082,48.6344],[-97.1086,48.6363],[-97.1096,48.6389],[-97.1109,48.6407],[-97.1119,48.6416],[-97.1144,48.6433],[-97.115,48.6438],[-97.115,48.6446],[-97.1149,48.6452],[-97.1123,48.6457],[-97.1112,48.6459],[-97.1093,48.6465],[-97.1078,48.6478],[-97.1069,48.6491],[-97.1066,48.6501],[-97.1061,48.6519],[-97.1059,48.6527],[-97.1045,48.6545],[-97.1017,48.6563],[-97.0987,48.6593],[-97.0986,48.6604],[-97.0985,48.6613],[-97.0992,48.6625],[-97.1019,48.6636],[-97.106,48.663],[-97.1062,48.663],[-97.1082,48.6634],[-97.1087,48.6645],[-97.1061,48.6654],[-97.1057,48.6655],[-97.102,48.6667],[-97.1,48.668],[-97.0998,48.6714],[-97.1002,48.675],[-97.1003,48.6757],[-97.1008,48.6787],[-97.1011,48.6808],[-97.1003,48.6828],[-97.0985,48.683],[-97.0946,48.6822],[-97.0926,48.6821],[-97.0904,48.6828],[-97.0898,48.6841],[-97.0899,48.6852],[-97.091,48.6861],[-97.093,48.687],[-97.0951,48.6876],[-97.099,48.6884],[-97.1024,48.6893],[-97.103,48.6894],[-97.1059,48.6903],[-97.1064,48.6905],[-97.1086,48.6915],[-97.111,48.6939],[-97.113,48.6964],[-97.1148,48.6981],[-97.1182,48.7005],[-97.1198,48.7018],[-97.1201,48.7039],[-97.1194,48.7041],[-97.1182,48.7046],[-97.1143,48.7052],[-97.1117,48.7056],[-97.11,48.7063],[-97.1098,48.7083],[-97.1113,48.7094],[-97.1134,48.7101],[-97.1157,48.7105],[-97.1174,48.7111],[-97.119,48.7119],[-97.1212,48.7136],[-97.1223,48.716],[-97.1229,48.7168],[-97.1231,48.7172],[-97.1243,48.7192],[-97.1253,48.7201],[-97.1253,48.7203],[-97.126,48.7207],[-97.1263,48.7212],[-97.1272,48.7215],[-97.128,48.722],[-97.1282,48.7221],[-97.1288,48.7225],[-97.1297,48.7229],[-97.131,48.7233],[-97.1321,48.7238],[-97.1331,48.7242],[-97.1345,48.7248],[-97.136,48.7257],[-97.1369,48.7263],[-97.1375,48.727],[-97.1376,48.7274],[-97.1376,48.7278],[-97.1373,48.7283],[-97.137,48.7284],[-97.1365,48.7285],[-97.136,48.7287],[-97.1352,48.7287],[-97.1341,48.7289],[-97.1333,48.7291],[-97.1328,48.7292],[-97.132,48.7294],[-97.1312,48.7295],[-97.1308,48.7296],[-97.1299,48.7299],[-97.1294,48.7304],[-97.1288,48.7308],[-97.1286,48.7312],[-97.1286,48.7315],[-97.1286,48.7316],[-97.1286,48.7318],[-97.1285,48.7322],[-97.1286,48.7326],[-97.1286,48.7328],[-97.1287,48.7331],[-97.129,48.7335],[-97.1295,48.7339],[-97.1298,48.7341],[-97.1316,48.7347],[-97.1322,48.7348],[-97.1334,48.7347],[-97.1351,48.7345],[-97.1369,48.7345],[-97.1383,48.7345],[-97.1396,48.7347],[-97.1402,48.7349],[-97.1412,48.7354],[-97.1419,48.7359],[-97.1422,48.7367],[-97.1423,48.7372],[-97.1421,48.7381],[-97.1414,48.7385],[-97.1408,48.7387],[-97.1404,48.7389],[-97.1399,48.7393],[-97.1392,48.7397],[-97.1381,48.7408],[-97.1372,48.742],[-97.1366,48.7435],[-97.1365,48.745],[-97.1365,48.7459],[-97.1366,48.7466],[-97.1369,48.748],[-97.1375,48.7492],[-97.1379,48.75],[-97.1385,48.7504],[-97.1391,48.7507],[-97.1396,48.7508],[-97.1401,48.7509],[-97.141,48.751],[-97.142,48.751],[-97.143,48.7509],[-97.1444,48.7507],[-97.1457,48.7506],[-97.1466,48.7505],[-97.1476,48.7505],[-97.1491,48.7506],[-97.1497,48.7508],[-97.1503,48.7509],[-97.1515,48.7515],[-97.1521,48.752],[-97.153,48.7529],[-97.1539,48.7542],[-97.1545,48.7553],[-97.1547,48.7558],[-97.1548,48.7562],[-97.1548,48.7569],[-97.1548,48.7576],[-97.1546,48.758],[-97.1542,48.7587],[-97.1535,48.7593],[-97.1528,48.7598],[-97.1519,48.7601],[-97.1508,48.7605],[-97.1503,48.7606],[-97.1501,48.7607],[-97.1475,48.7616],[-97.1473,48.7617],[-97.1469,48.762],[-97.1462,48.7626],[-97.1461,48.7628],[-97.1459,48.7633],[-97.1456,48.7643],[-97.1456,48.765],[-97.146,48.7658],[-97.1476,48.7673],[-97.1487,48.7681],[-97.15,48.7692],[-97.1501,48.7693],[-97.1506,48.77],[-97.1512,48.7712],[-97.1519,48.7721],[-97.1525,48.7727],[-97.1529,48.7728],[-97.1559,48.7731],[-97.1567,48.7732],[-97.1578,48.7735],[-97.1582,48.7737],[-97.1587,48.7742],[-97.1589,48.7746],[-97.159,48.7751],[-97.159,48.7751],[-97.159,48.7754],[-97.1589,48.776],[-97.1584,48.7766],[-97.1579,48.7769],[-97.1573,48.7772],[-97.1557,48.7776],[-97.1544,48.7778],[-97.1534,48.778],[-97.1522,48.7783],[-97.1509,48.7787],[-97.1501,48.7789],[-97.1497,48.779],[-97.1483,48.7797],[-97.1477,48.7801],[-97.1473,48.7807],[-97.1472,48.7811],[-97.1473,48.7816],[-97.1478,48.7821],[-97.1486,48.7824],[-97.1495,48.7826],[-97.1501,48.7826],[-97.1503,48.7826],[-97.1513,48.7825],[-97.1533,48.7824],[-97.1547,48.7824],[-97.1559,48.7825],[-97.1571,48.7827],[-97.1583,48.783],[-97.1591,48.7834],[-97.1595,48.7838],[-97.1597,48.7843],[-97.1598,48.7848],[-97.1596,48.7853],[-97.1593,48.786],[-97.1591,48.7863],[-97.1586,48.7869],[-97.1577,48.7877],[-97.1574,48.7882],[-97.1573,48.7884],[-97.1572,48.7887],[-97.1571,48.7894],[-97.157,48.7895],[-97.157,48.7901],[-97.1572,48.7906],[-97.1575,48.7909],[-97.1581,48.7912],[-97.1586,48.7913],[-97.1592,48.7915],[-97.1595,48.7915],[-97.1611,48.7915],[-97.1618,48.7914],[-97.1645,48.7911],[-97.1648,48.7911],[-97.1657,48.7911],[-97.1664,48.7912],[-97.1672,48.7913],[-97.1714,48.7921],[-97.1718,48.7923],[-97.1721,48.7924],[-97.1731,48.7929],[-97.1737,48.7933],[-97.174,48.7937],[-97.1741,48.7942],[-97.1742,48.7947],[-97.1742,48.7951],[-97.1739,48.7954],[-97.1734,48.7958],[-97.1726,48.7963],[-97.1717,48.7966],[-97.1716,48.7966],[-97.171,48.7967],[-97.1701,48.7967],[-97.1688,48.7966],[-97.1673,48.7964],[-97.1665,48.7962],[-97.1654,48.7962],[-97.1648,48.7962],[-97.1638,48.7963],[-97.1631,48.7966],[-97.1625,48.7969],[-97.162,48.7974],[-97.1617,48.7979],[-97.1617,48.7984],[-97.1619,48.7988],[-97.1621,48.7994],[-97.1626,48.8001],[-97.1633,48.8007],[-97.1642,48.8011],[-97.1652,48.8014],[-97.166,48.8015],[-97.1668,48.8016],[-97.1675,48.8016],[-97.1685,48.8016],[-97.1698,48.8013],[-97.1706,48.8011],[-97.1714,48.8008],[-97.1715,48.8008],[-97.1724,48.8004],[-97.1731,48.8],[-97.1742,48.7992],[-97.175,48.7986],[-97.1754,48.7983],[-97.1757,48.798],[-97.1761,48.7977],[-97.1768,48.7974],[-97.1773,48.7973],[-97.1779,48.7972],[-97.1787,48.7972],[-97.1795,48.7972],[-97.1801,48.7973],[-97.1807,48.7975],[-97.1811,48.7978],[-97.1815,48.7982],[-97.1816,48.7986],[-97.1817,48.7991],[-97.1815,48.7995],[-97.1813,48.8],[-97.1808,48.8004],[-97.1801,48.8008],[-97.1791,48.8012],[-97.1779,48.8015],[-97.1769,48.8017],[-97.1764,48.8018],[-97.1756,48.8021],[-97.1748,48.8023],[-97.1725,48.8032],[-97.1713,48.8036],[-97.171,48.8037],[-97.1706,48.8039],[-97.1694,48.8043],[-97.1682,48.8046],[-97.1675,48.8048],[-97.1666,48.805],[-97.1655,48.8052],[-97.1638,48.8055],[-97.161,48.8059],[-97.1605,48.8061],[-97.1597,48.8064],[-97.159,48.8067],[-97.1583,48.8072],[-97.1579,48.8077],[-97.1577,48.8082],[-97.1576,48.8089],[-97.1578,48.8098],[-97.158,48.8104],[-97.1586,48.811],[-97.159,48.8111],[-97.161,48.8117],[-97.1617,48.8119],[-97.1625,48.812],[-97.1636,48.8121],[-97.1644,48.8121],[-97.1651,48.812],[-97.1666,48.8118],[-97.168,48.8116],[-97.169,48.8114],[-97.17,48.8114],[-97.1713,48.8115],[-97.1715,48.8115],[-97.1726,48.8117],[-97.1731,48.8118],[-97.174,48.8122],[-97.1761,48.8132],[-97.1776,48.8141],[-97.1784,48.8145],[-97.1797,48.8149],[-97.1807,48.8151],[-97.1821,48.8153],[-97.1828,48.8153],[-97.184,48.8152],[-97.1848,48.8151],[-97.186,48.8147],[-97.1868,48.8145],[-97.1873,48.8143],[-97.1879,48.8143],[-97.1883,48.8143],[-97.1889,48.8143],[-97.1894,48.8144],[-97.1898,48.8146],[-97.1901,48.8148],[-97.1903,48.8153],[-97.1904,48.8156],[-97.1903,48.8159],[-97.19,48.8163],[-97.1893,48.8167],[-97.1885,48.8171],[-97.1879,48.8173],[-97.1866,48.8176],[-97.1857,48.8177],[-97.1847,48.8179],[-97.184,48.8181],[-97.1833,48.8184],[-97.1817,48.8189],[-97.1809,48.8193],[-97.1801,48.8199],[-97.1793,48.8207],[-97.1787,48.8216],[-97.178,48.8232],[-97.1777,48.824],[-97.1776,48.8245],[-97.1777,48.8249],[-97.178,48.8255],[-97.1782,48.8258],[-97.1786,48.8262],[-97.1794,48.8268],[-97.1822,48.8288],[-97.1837,48.8299],[-97.1841,48.8304],[-97.1847,48.8314],[-97.1848,48.8319],[-97.1849,48.8326],[-97.1849,48.8327],[-97.1848,48.833],[-97.1846,48.8336],[-97.1842,48.8341],[-97.1837,48.8345],[-97.183,48.8348],[-97.1822,48.835],[-97.1813,48.8351],[-97.1799,48.8352],[-97.1783,48.8353],[-97.1779,48.8354],[-97.1772,48.8356],[-97.1757,48.8362],[-97.1753,48.8364],[-97.1747,48.8369],[-97.1742,48.8373],[-97.1739,48.8378],[-97.1738,48.8384],[-97.1738,48.839],[-97.1739,48.8406],[-97.1743,48.8427],[-97.1747,48.8438],[-97.175,48.8442],[-97.1755,48.8447],[-97.1761,48.8452],[-97.1767,48.8455],[-97.1771,48.8456],[-97.1779,48.8458],[-97.1795,48.8459],[-97.1808,48.846],[-97.1817,48.8462],[-97.1823,48.8464],[-97.1827,48.8468],[-97.1829,48.847],[-97.1829,48.8471],[-97.1829,48.8473],[-97.1826,48.8476],[-97.1821,48.8479],[-97.1816,48.848],[-97.1809,48.8481],[-97.1793,48.8482],[-97.178,48.8483],[-97.1767,48.8484],[-97.1759,48.8486],[-97.1753,48.8487],[-97.1747,48.849],[-97.1742,48.8493],[-97.1737,48.8497],[-97.1733,48.8502],[-97.173,48.8506],[-97.173,48.8508],[-97.173,48.8511],[-97.173,48.8516],[-97.1732,48.8522],[-97.1737,48.8527],[-97.1746,48.8534],[-97.1771,48.855],[-97.1784,48.8561],[-97.1786,48.8563],[-97.179,48.8569],[-97.1793,48.8576],[-97.1794,48.8583],[-97.1794,48.859],[-97.1792,48.8606],[-97.179,48.8615],[-97.179,48.862],[-97.1791,48.8626],[-97.1794,48.863],[-97.1801,48.8636],[-97.1811,48.864],[-97.1818,48.8641],[-97.1827,48.8641],[-97.1839,48.864],[-97.1855,48.8637],[-97.1871,48.8633],[-97.1877,48.8631],[-97.1883,48.8631],[-97.1891,48.8631],[-97.1896,48.8633],[-97.19,48.8635],[-97.1903,48.8639],[-97.1905,48.8644],[-97.1905,48.8648],[-97.1904,48.8651],[-97.1901,48.8657],[-97.1899,48.8661],[-97.1895,48.8665],[-97.189,48.867],[-97.1884,48.8675],[-97.1851,48.8694],[-97.1813,48.8718],[-97.1788,48.8736],[-97.1785,48.8738],[-97.1782,48.8741],[-97.1781,48.8743],[-97.1779,48.8745],[-97.1778,48.8747],[-97.1777,48.8749],[-97.1777,48.875],[-97.1778,48.875],[-97.1778,48.8754],[-97.1779,48.8757],[-97.1782,48.8761],[-97.1786,48.8765],[-97.1792,48.8769],[-97.1798,48.8771],[-97.1808,48.8772],[-97.1823,48.8772],[-97.1852,48.8768],[-97.1869,48.8765],[-97.1881,48.8765],[-97.1891,48.8766],[-97.1904,48.8769],[-97.1933,48.8779],[-97.1944,48.8783],[-97.1957,48.8788],[-97.1972,48.8794],[-97.1981,48.8799],[-97.1988,48.8805],[-97.1995,48.8812],[-97.1999,48.8818],[-97.1999,48.8821],[-97.2,48.8827],[-97.1998,48.8832],[-97.1997,48.8836],[-97.199,48.8845],[-97.1978,48.8859],[-97.1975,48.8865],[-97.1974,48.8868],[-97.1973,48.8872],[-97.1973,48.8874],[-97.1974,48.8877],[-97.1975,48.8881],[-97.1983,48.8889],[-97.2002,48.8903],[-97.2004,48.8904],[-97.2009,48.8908],[-97.2014,48.8912],[-97.2017,48.8915],[-97.2017,48.8919],[-97.2016,48.8922],[-97.2013,48.8925],[-97.201,48.8926],[-97.2001,48.8926],[-97.1994,48.8926],[-97.1985,48.8925],[-97.198,48.8924],[-97.1973,48.892],[-97.1957,48.8916],[-97.1946,48.8915],[-97.1944,48.8914],[-97.1937,48.8914],[-97.1927,48.8915],[-97.1921,48.8917],[-97.1916,48.8919],[-97.1905,48.8926],[-97.1901,48.8932],[-97.1898,48.8938],[-97.1897,48.8944],[-97.1897,48.8947],[-97.1898,48.8951],[-97.1899,48.8954],[-97.1903,48.896],[-97.1911,48.8967],[-97.1919,48.8974],[-97.1925,48.8979],[-97.1935,48.8985],[-97.1941,48.8988],[-97.1945,48.8989],[-97.1966,48.8997],[-97.1992,48.9004],[-97.2009,48.9009],[-97.2022,48.9013],[-97.2048,48.9018],[-97.2055,48.902],[-97.207,48.9025],[-97.2076,48.9027],[-97.2082,48.9029],[-97.2088,48.9032],[-97.2093,48.9036],[-97.21,48.904],[-97.2105,48.9044],[-97.211,48.905],[-97.2114,48.9056],[-97.2122,48.9069],[-97.2125,48.9075],[-97.2127,48.9082],[-97.2127,48.909],[-97.2125,48.9099],[-97.212,48.911],[-97.2116,48.9121],[-97.2111,48.913],[-97.2108,48.914],[-97.2106,48.9148],[-97.2106,48.9153],[-97.2109,48.9162],[-97.2111,48.9167],[-97.2115,48.9172],[-97.2118,48.9175],[-97.2122,48.9177],[-97.2129,48.9181],[-97.2149,48.9187],[-97.2163,48.9191],[-97.2164,48.9191],[-97.2171,48.9194],[-97.2179,48.9198],[-97.2189,48.9205],[-97.2196,48.9215],[-97.2198,48.9222],[-97.2199,48.923],[-97.2197,48.9237],[-97.2191,48.9249],[-97.2183,48.9262],[-97.2172,48.9277],[-97.2163,48.9286],[-97.2159,48.9289],[-97.2149,48.9301],[-97.2146,48.9304],[-97.2145,48.9307],[-97.2144,48.931],[-97.2145,48.9314],[-97.2145,48.9316],[-97.2148,48.9319],[-97.2154,48.9325],[-97.2159,48.9327],[-97.2162,48.9328],[-97.217,48.9328],[-97.2181,48.9327],[-97.2198,48.9325],[-97.2208,48.9325],[-97.2214,48.9325],[-97.2218,48.9326],[-97.2237,48.9332],[-97.2245,48.9337],[-97.2249,48.9339],[-97.225,48.934],[-97.2252,48.9342],[-97.2254,48.9345],[-97.2257,48.9349],[-97.226,48.9353],[-97.2263,48.936],[-97.2267,48.9376],[-97.227,48.9389],[-97.2271,48.9398],[-97.2271,48.941],[-97.227,48.9418],[-97.2266,48.9432],[-97.2264,48.9441],[-97.2263,48.9445],[-97.2264,48.9452],[-97.2265,48.9456],[-97.227,48.9462],[-97.2273,48.9465],[-97.2276,48.9467],[-97.2279,48.9467],[-97.2284,48.9468],[-97.2304,48.9465],[-97.2309,48.9464],[-97.2313,48.9464],[-97.2326,48.9466],[-97.2331,48.9468],[-97.2338,48.9471],[-97.2342,48.9474],[-97.2343,48.948],[-97.2343,48.9485],[-97.2342,48.9488],[-97.2341,48.9491],[-97.2337,48.95],[-97.2332,48.951],[-97.2328,48.9524],[-97.2323,48.954],[-97.2317,48.9558],[-97.2313,48.9568],[-97.2309,48.9578],[-97.2305,48.9585],[-97.23,48.9591],[-97.2288,48.9603],[-97.2282,48.9609],[-97.2278,48.9613],[-97.2276,48.9619],[-97.2276,48.9624],[-97.2279,48.963],[-97.228,48.9631],[-97.2283,48.9634],[-97.2289,48.9639],[-97.2294,48.9641],[-97.23,48.9642],[-97.2323,48.9646],[-97.2355,48.965],[-97.2368,48.9652],[-97.2375,48.9654],[-97.2382,48.966],[-97.2383,48.9661],[-97.2388,48.9666],[-97.2391,48.9676],[-97.2392,48.9687],[-97.239,48.9696],[-97.2387,48.9706],[-97.2383,48.9715],[-97.2381,48.9723],[-97.238,48.9725],[-97.2379,48.9731],[-97.2378,48.9734],[-97.2378,48.9738],[-97.238,48.9752],[-97.238,48.9763],[-97.2381,48.9771],[-97.238,48.9771],[-97.238,48.9841],[-97.2377,48.9849],[-97.2372,48.9857],[-97.2365,48.9867],[-97.2359,48.9874],[-97.2351,48.9881],[-97.2342,48.989],[-97.2335,48.9895],[-97.2331,48.9898],[-97.2317,48.9904],[-97.2301,48.9911],[-97.2293,48.9914],[-97.229,48.9916],[-97.2279,48.9921],[-97.2274,48.9925],[-97.227,48.9929],[-97.2266,48.9933],[-97.2265,48.9938],[-97.2267,48.9941],[-97.227,48.9945],[-97.2273,48.9947],[-97.2287,48.9949],[-97.2304,48.995],[-97.2317,48.9951],[-97.2324,48.9952],[-97.2335,48.9956],[-97.2338,48.9959],[-97.2341,48.9966],[-97.2341,48.997],[-97.234,48.9975],[-97.2337,48.9981],[-97.2332,48.9985],[-97.2323,48.999],[-97.2305,49.0],[-97.2303,49.0001],[-97.2295,49.0005],[-97.2175,49.0005],[-97.2161,49.0005],[-97.2078,49.0005],[-97.2069,49.0005],[-97.1955,49.0005],[-97.1939,49.0005],[-97.1739,49.0005],[-97.1724,49.0005],[-97.1514,49.0005],[-97.1502,49.0005],[-97.1294,49.0004],[-97.1277,49.0004],[-97.1073,49.0004],[-97.1061,49.0004],[-97.0853,49.0004],[-97.084,49.0004],[-97.0633,49.0004],[-97.062,49.0004],[-97.0412,49.0004],[-97.0401,49.0004],[-97.0192,49.0004],[-97.0183,49.0004],[-96.9971,49.0004],[-96.9961,49.0004],[-96.9751,49.0003],[-96.9738,49.0003],[-96.953,49.0003],[-96.9518,49.0003],[-96.931,49.0003],[-96.9299,49.0003],[-96.909,49.0003],[-96.9078,49.0003],[-96.8869,49.0003],[-96.8856,49.0003],[-96.8649,49.0003],[-96.864,49.0003],[-96.8429,49.0003],[-96.8415,49.0003],[-96.8208,49.0003],[-96.8197,49.0003],[-96.8023,49.0002],[-96.8005,49.0002],[-96.8003,49.0002],[-96.7988,49.0002],[-96.7787,49.0002],[-96.7768,49.0002],[-96.7567,49.0002],[-96.7547,49.0002],[-96.7348,49.0002],[-96.7327,49.0002],[-96.7127,49.0002],[-96.7107,49.0002],[-96.6905,49.0002],[-96.6886,49.0002],[-96.6695,49.0002],[-96.6665,49.0002],[-96.6482,49.0002],[-96.6445,49.0002],[-96.6243,49.0002],[-96.6225,49.0002],[-96.6021,49.0002],[-96.6004,49.0002],[-96.58,49.0002],[-96.5784,49.0002],[-96.558,49.0002],[-96.5563,49.0002],[-96.536,49.0002],[-96.5342,49.0002],[-96.5154,49.0002],[-96.5123,49.0002],[-96.4933,49.0002],[-96.49,49.0002],[-96.471,49.0001],[-96.4664,49.0001],[-96.4496,49.0001],[-96.4492,49.0001],[-96.4491,49.0001],[-96.446,49.0001],[-96.4273,49.0001],[-96.4224,49.0001],[-96.4054,49.0001]]],"type":"Polygon"},"id":"35","properties":{"Area":2862183702.23055,"CTYONLY_":3,"Code":"KITT","LASTMOD":"1999-12-31T23:59:59Z","Name":"Kittson","Perimiter":263017.48277},"type":"Feature"},{"geometry":{"coordinates":[[[-94.4299,48.7012],[-94.4241,48.7053],[-94.4213,48.7086],[-94.4189,48.7103],[-94.4158,48.711],[-94.4081,48.7106],[-94.406,48.7105],[-94.3889,48.712],[-94.3859,48.7119],[-94.384,48.7119],[-94.3801,48.7111],[-94.3687,48.7065],[-94.3646,48.7059],[-94.3533,48.7042],[-94.3431,48.7035],[-94.3429,48.7035],[-94.3287,48.7045],[-94.3214,48.7067],[-94.3088,48.7103],[-94.2995,48.709],[-94.2911,48.7079],[-94.2829,48.7057],[-94.2781,48.7024],[-94.2745,48.6999],[-94.2694,48.6995],[-94.2644,48.699],[-94.261,48.6966],[-94.258,48.6918],[-94.2565,48.6901],[-94.2529,48.6864],[-94.2521,48.685],[-94.2514,48.6837],[-94.2507,48.6782],[-94.2527,48.6707],[-94.253,48.6693],[-94.2548,48.664],[-94.2546,48.6615],[-94.2509,48.657],[-94.2499,48.6563],[-94.2467,48.6542],[-94.2445,48.6535],[-94.2343,48.6524],[-94.2335,48.6524],[-94.2242,48.6495],[-94.2144,48.6494],[-94.2124,48.6496],[-94.1996,48.651],[-94.1915,48.6506],[-94.1886,48.6504],[-94.1689,48.6483],[-94.1678,48.6482],[-94.1574,48.6458],[-94.1522,48.6455],[-94.1458,48.6458],[-94.1391,48.646],[-94.126,48.6444],[-94.1235,48.6444],[-94.11,48.6443],[-94.1023,48.6455],[-94.0999,48.6459],[-94.0912,48.6437],[-94.0849,48.6441],[-94.0804,48.6442],[-94.0767,48.6442],[-94.0714,48.6459],[-94.0658,48.6462],[-94.0642,48.6438],[-94.0603,48.6431],[-94.0581,48.6434],[-94.0525,48.644],[-94.0432,48.6435],[-94.0393,48.6423],[-94.0364,48.6413],[-94.0356,48.6411],[-94.0295,48.6409],[-94.0153,48.6424],[-94.0069,48.6433],[-94.0007,48.6428],[-93.9931,48.6412],[-93.9897,48.6405],[-93.984,48.6401],[-93.9777,48.6385],[-93.9712,48.6385],[-93.968,48.6385],[-93.9596,48.6372],[-93.953,48.6341],[-93.9497,48.6339],[-93.934,48.6326],[-93.9272,48.6327],[-93.9169,48.6329],[-93.9134,48.6353],[-93.9057,48.6346],[-93.9054,48.6345],[-93.8948,48.6324],[-93.8853,48.6318],[-93.8844,48.6318],[-93.8757,48.6319],[-93.8698,48.6311],[-93.8624,48.631],[-93.848,48.6308],[-93.8443,48.6303],[-93.8404,48.6289],[-93.8393,48.6286],[-93.8365,48.6276],[-93.8334,48.6256],[-93.8292,48.6177],[-93.825,48.6136],[-93.8245,48.613],[-93.8214,48.6092],[-93.8182,48.5994],[-93.8175,48.597],[-93.8172,48.5964],[-93.813,48.588],[-93.8103,48.5846],[-93.8063,48.5796],[-93.8041,48.5703],[-93.8041,48.5702],[-93.8051,48.5644],[-93.808,48.5569],[-93.8088,48.5555],[-93.8119,48.5503],[-93.8102,48.5445],[-93.8109,48.5412],[-93.8109,48.541],[-93.818,48.535],[-93.818,48.5346],[-93.8184,48.5315],[-93.8178,48.5306],[-93.8161,48.5285],[-93.8145,48.5273],[-93.8111,48.5247],[-93.803,48.522],[-93.7964,48.5182],[-93.7933,48.5164],[-93.7879,48.5159],[-93.7745,48.5162],[-93.768,48.5164],[-93.7665,48.5164],[-93.7617,48.5166],[-93.7534,48.5158],[-93.7442,48.5175],[-93.739,48.5185],[-93.731,48.5185],[-93.7225,48.5178],[-93.7206,48.5176],[-93.7108,48.5186],[-93.7061,48.5182],[-93.7006,48.517],[-93.693,48.5152],[-93.6866,48.5154],[-93.6791,48.5167],[-93.6778,48.5169],[-93.6593,48.5165],[-93.657,48.5167],[-93.6473,48.5177],[-93.6433,48.519],[-93.6421,48.5199],[-93.6395,48.5218],[-93.6357,48.5285],[-93.6344,48.5293],[-93.6311,48.5313],[-93.6284,48.5319],[-93.6256,48.5315],[-93.6211,48.5264],[-93.6166,48.5238],[-93.6134,48.5228],[-93.6122,48.5225],[-93.6051,48.5231],[-93.5962,48.5287],[-93.5919,48.5299],[-93.5901,48.5305],[-93.581,48.5271],[-93.5761,48.527],[-93.5701,48.528],[-93.5602,48.5297],[-93.5484,48.5294],[-93.5476,48.5294],[-93.5425,48.53],[-93.5366,48.5319],[-93.5269,48.5341],[-93.5263,48.5341],[-93.5244,48.5343],[-93.5171,48.5348],[-93.5047,48.5399],[-93.501,48.5414],[-93.4952,48.5426],[-93.4854,48.5433],[-93.4833,48.5437],[-93.4673,48.5465],[-93.4655,48.5478],[-93.4625,48.5498],[-93.462,48.5505],[-93.4596,48.5537],[-93.4576,48.5598],[-93.4576,48.5621],[-93.4575,48.5672],[-93.4619,48.5731],[-93.4619,48.5734],[-93.4631,48.5767],[-93.4671,48.5885],[-93.4656,48.59],[-93.4654,48.5915],[-93.4654,48.5917],[-93.4627,48.5927],[-93.46,48.5927],[-93.4547,48.5927],[-93.4398,48.5937],[-93.4385,48.5942],[-93.4347,48.5954],[-93.4298,48.5997],[-93.4226,48.6032],[-93.4193,48.6036],[-93.416,48.605],[-93.4152,48.6053],[-93.415,48.6056],[-93.4144,48.6064],[-93.4056,48.6099],[-93.4034,48.61],[-93.4029,48.6077],[-93.4013,48.6079],[-93.3994,48.6055],[-93.3986,48.6045],[-93.3953,48.6038],[-93.3937,48.6041],[-93.3837,48.606],[-93.3724,48.6059],[-93.3714,48.6059],[-93.3672,48.6082],[-93.3619,48.6141],[-93.355,48.6114],[-93.3526,48.6135],[-93.3533,48.615],[-93.3513,48.62],[-93.3505,48.6219],[-93.3486,48.6265],[-93.3276,48.6302],[-93.3057,48.634],[-93.3048,48.6341],[-93.2838,48.6378],[-93.2634,48.6413],[-93.2546,48.6429],[-93.2422,48.6428],[-93.2193,48.6426],[-93.2075,48.6426],[-93.1975,48.6365],[-93.191,48.6325],[-93.184,48.6282],[-93.1783,48.6231],[-93.1754,48.6232],[-93.1531,48.6244],[-93.1319,48.6256],[-93.1104,48.6267],[-93.0903,48.6278],[-93.0884,48.6278],[-93.0886,48.6163],[-93.0895,48.6016],[-93.0898,48.5872],[-93.09,48.5727],[-93.0902,48.5583],[-93.0902,48.5441],[-93.0903,48.5296],[-93.0905,48.5151],[-93.0905,48.501],[-93.091,48.4884],[-93.0911,48.4867],[-93.0914,48.474],[-93.0915,48.4724],[-93.0918,48.4596],[-93.0919,48.458],[-93.092,48.4449],[-93.092,48.4436],[-93.0922,48.4303],[-93.0922,48.429],[-93.0923,48.4147],[-93.0935,48.4147],[-93.0938,48.4024],[-93.094,48.3879],[-93.094,48.3734],[-93.0945,48.3589],[-93.0948,48.3442],[-93.0948,48.3298],[-93.0953,48.3153],[-93.0952,48.3004],[-93.095,48.2862],[-93.0952,48.2716],[-93.0953,48.2576],[-93.0949,48.2426],[-93.0949,48.2425],[-93.0977,48.2426],[-93.0977,48.2271],[-93.0978,48.2126],[-93.0979,48.1981],[-93.0975,48.1836],[-93.097,48.1692],[-93.097,48.1546],[-93.097,48.1402],[-93.0969,48.1259],[-93.0972,48.1114],[-93.097,48.0969],[-93.0968,48.0823],[-93.0965,48.0679],[-93.0965,48.0678],[-93.0892,48.0679],[-93.0892,48.0509],[-93.089,48.0366],[-93.0886,48.022],[-93.0887,48.0075],[-93.0872,47.9932],[-93.088,47.9787],[-93.0809,47.9786],[-93.0809,47.967],[-93.0808,47.9647],[-93.0808,47.9525],[-93.0808,47.9504],[-93.0809,47.938],[-93.0809,47.9356],[-93.0809,47.9235],[-93.0809,47.9212],[-93.0809,47.9088],[-93.0809,47.9067],[-93.0808,47.8945],[-93.0808,47.8922],[-93.1015,47.8927],[-93.1232,47.893],[-93.1448,47.8928],[-93.1656,47.8931],[-93.1671,47.8932],[-93.1871,47.8931],[-93.1893,47.8931],[-93.2087,47.8933],[-93.2115,47.8934],[-93.2331,47.8937],[-93.2532,47.8936],[-93.2745,47.8938],[-93.2962,47.8939],[-93.3169,47.894],[-93.3392,47.8941],[-93.3603,47.8942],[-93.3809,47.8943],[-93.4024,47.8944],[-93.4235,47.8945],[-93.4442,47.8946],[-93.466,47.895],[-93.4874,47.8956],[-93.4892,47.8957],[-93.4933,47.8958],[-93.5085,47.8962],[-93.5105,47.8963],[-93.5297,47.8967],[-93.5303,47.8967],[-93.532,47.8968],[-93.5517,47.8973],[-93.5532,47.8974],[-93.5729,47.8981],[-93.5747,47.8982],[-93.5962,47.8978],[-93.5966,47.8978],[-93.6179,47.8977],[-93.6187,47.8977],[-93.6388,47.8977],[-93.6395,47.8976],[-93.6604,47.8976],[-93.6612,47.8976],[-93.6817,47.8976],[-93.6826,47.8976],[-93.7031,47.8976],[-93.7038,47.8976],[-93.7249,47.8975],[-93.7248,47.8989],[-93.7466,47.8989],[-93.768,47.8991],[-93.7758,47.8991],[-93.7758,47.899],[-93.776,47.8897],[-93.776,47.8842],[-93.7762,47.8753],[-93.7761,47.8697],[-93.7761,47.8607],[-93.7761,47.8553],[-93.7761,47.8464],[-93.7896,47.8465],[-93.7971,47.8466],[-93.8189,47.8467],[-93.8407,47.8468],[-93.8627,47.8469],[-93.8831,47.8471],[-93.9067,47.8471],[-93.9288,47.8475],[-93.9496,47.8475],[-93.9506,47.8475],[-93.971,47.8475],[-93.9725,47.8475],[-93.9927,47.8475],[-93.9942,47.8475],[-94.0141,47.8476],[-94.0161,47.8476],[-94.0375,47.8477],[-94.0591,47.8474],[-94.0807,47.8471],[-94.1022,47.8471],[-94.1239,47.8466],[-94.1448,47.8463],[-94.1657,47.8461],[-94.1822,47.8461],[-94.1871,47.846],[-94.2037,47.846],[-94.2086,47.846],[-94.2252,47.846],[-94.23,47.8461],[-94.2467,47.8462],[-94.2515,47.8462],[-94.2681,47.8462],[-94.2728,47.8462],[-94.2887,47.8462],[-94.3103,47.8458],[-94.3315,47.846],[-94.3532,47.8464],[-94.3747,47.8462],[-94.3964,47.8461],[-94.4185,47.8459],[-94.4186,47.86],[-94.4184,47.8744],[-94.418,47.8886],[-94.4177,47.9031],[-94.4176,47.9041],[-94.4175,47.9175],[-94.4174,47.9186],[-94.4175,47.9332],[-94.4174,47.9477],[-94.4172,47.9623],[-94.4173,47.9769],[-94.4176,47.9914],[-94.4177,48.006],[-94.4176,48.02],[-94.4236,48.0199],[-94.4241,48.0344],[-94.4246,48.0489],[-94.4247,48.0632],[-94.4234,48.0776],[-94.4231,48.092],[-94.4233,48.1059],[-94.4234,48.1204],[-94.4236,48.1348],[-94.4233,48.1491],[-94.4235,48.1637],[-94.4235,48.1781],[-94.4233,48.1923],[-94.4236,48.2067],[-94.4238,48.2212],[-94.4237,48.2356],[-94.4237,48.2504],[-94.424,48.2649],[-94.4243,48.2791],[-94.4244,48.2938],[-94.4246,48.3081],[-94.4248,48.3227],[-94.425,48.3372],[-94.4253,48.352],[-94.4252,48.3675],[-94.4288,48.3675],[-94.4289,48.3821],[-94.4293,48.3964],[-94.4294,48.411],[-94.4293,48.4254],[-94.4292,48.4399],[-94.4293,48.4543],[-94.4296,48.4688],[-94.4296,48.4832],[-94.4299,48.4977],[-94.4303,48.512],[-94.4303,48.5264],[-94.43,48.5409],[-94.4295,48.5554],[-94.4291,48.5698],[-94.4289,48.5844],[-94.4289,48.5988],[-94.4292,48.6133],[-94.4294,48.6276],[-94.4297,48.642],[-94.43,48.6564],[-94.4301,48.6708],[-94.43,48.6852],[-94.4299,48.6998],[-94.4299,48.7012]]],"type":"Polygon"},"id":"36","properties":{"Area":8167237870.91888,"CTYONLY_":5,"Code":"KOOC","LASTMOD":"1999-12-31T23:59:59Z","Name":"Koochiching","Perimiter":412897.43594},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&filter=CTYONLY_%20IN%20(3%2C%205)","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&filter=CTYONLY_%20IN%20(3%2C%205)","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":2,"numberReturned":2,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_text_is_not_null_not_supported.json.txt b/msautotest/api/expected/ogcapi_cql2_text_is_not_null_not_supported.json.txt new file mode 100644 index 0000000000..178902ca8a --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_text_is_not_null_not_supported.json.txt @@ -0,0 +1,4 @@ +Content-Type: application/json +Status: 400 + +{"code":"InvalidParameterValue","description":"Cannot translate CQL2 filter to MapServer expression: IS NULL not supported by MapServer"} diff --git a/msautotest/api/expected/ogcapi_cql2_text_is_null_not_supported.json.txt b/msautotest/api/expected/ogcapi_cql2_text_is_null_not_supported.json.txt new file mode 100644 index 0000000000..178902ca8a --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_text_is_null_not_supported.json.txt @@ -0,0 +1,4 @@ +Content-Type: application/json +Status: 400 + +{"code":"InvalidParameterValue","description":"Cannot translate CQL2 filter to MapServer expression: IS NULL not supported by MapServer"} diff --git a/msautotest/api/expected/ogcapi_cql2_text_le.json.txt b/msautotest/api/expected/ogcapi_cql2_text_le.json.txt new file mode 100644 index 0000000000..340f3f6de1 --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_text_le.json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 2 +OGC-NumberReturned: 2 + +{"features":[{"geometry":{"coordinates":[[[-95.3231,48.999],[-95.3109,48.999],[-95.2889,48.9989],[-95.2852,48.9989],[-95.2669,48.9989],[-95.245,48.9989],[-95.2232,48.9989],[-95.2014,48.9989],[-95.1792,48.9989],[-95.1574,48.9989],[-95.1531,48.9989],[-95.1531,49.0031],[-95.1532,49.0179],[-95.1532,49.0325],[-95.1532,49.047],[-95.1532,49.0619],[-95.1532,49.0765],[-95.1532,49.0911],[-95.1532,49.1057],[-95.1532,49.1205],[-95.1532,49.1354],[-95.1532,49.1499],[-95.1532,49.1642],[-95.1532,49.1788],[-95.1532,49.1807],[-95.1532,49.1931],[-95.1532,49.1966],[-95.1532,49.2077],[-95.1533,49.2131],[-95.1533,49.2219],[-95.1533,49.2308],[-95.1533,49.2365],[-95.1533,49.2472],[-95.1533,49.2512],[-95.1533,49.2655],[-95.1533,49.2697],[-95.1533,49.2802],[-95.1533,49.2882],[-95.1533,49.2945],[-95.1533,49.3072],[-95.1533,49.309],[-95.1533,49.3234],[-95.1533,49.3237],[-95.1533,49.3381],[-95.1533,49.3476],[-95.1533,49.3525],[-95.1533,49.3636],[-95.1533,49.367],[-95.1533,49.3705],[-95.1533,49.3776],[-95.1533,49.3813],[-95.1533,49.3845],[-95.1503,49.383],[-95.1499,49.3813],[-95.1498,49.3807],[-95.1467,49.3802],[-95.145,49.3784],[-95.1418,49.3784],[-95.1397,49.3762],[-95.1367,49.3751],[-95.1324,49.3736],[-95.1287,49.3705],[-95.1171,49.367],[-95.1159,49.3666],[-95.1145,49.3666],[-95.1098,49.3664],[-95.1031,49.3652],[-95.1031,49.3636],[-95.0926,49.3617],[-95.0897,49.3612],[-95.0707,49.3564],[-95.0582,49.3533],[-95.0495,49.3532],[-95.0479,49.3533],[-95.0262,49.3554],[-95.0141,49.3565],[-95.0047,49.3612],[-94.993,49.367],[-94.9889,49.369],[-94.9818,49.3684],[-94.9742,49.3678],[-94.9597,49.3699],[-94.9573,49.3702],[-94.952,49.3688],[-94.948,49.367],[-94.9376,49.3625],[-94.9152,49.3529],[-94.9143,49.3524],[-94.909,49.3502],[-94.9065,49.3484],[-94.8933,49.3414],[-94.8865,49.3378],[-94.8782,49.3334],[-94.8712,49.3308],[-94.854,49.3244],[-94.8492,49.3244],[-94.8363,49.3243],[-94.8311,49.3236],[-94.8271,49.323],[-94.8162,49.3214],[-94.8243,49.309],[-94.8243,49.3088],[-94.8255,49.2944],[-94.8255,49.2943],[-94.8204,49.28],[-94.8152,49.2653],[-94.8103,49.2515],[-94.8059,49.2388],[-94.8051,49.2367],[-94.8001,49.2224],[-94.7973,49.2144],[-94.7975,49.2079],[-94.7979,49.1979],[-94.7965,49.1936],[-94.7918,49.1792],[-94.7871,49.1646],[-94.7833,49.153],[-94.7823,49.15],[-94.7776,49.1357],[-94.7727,49.1206],[-94.7727,49.1206],[-94.7611,49.1096],[-94.7571,49.1058],[-94.7496,49.0988],[-94.7474,49.0918],[-94.7429,49.0773],[-94.7394,49.0657],[-94.7385,49.063],[-94.7344,49.0497],[-94.7299,49.0351],[-94.7254,49.0205],[-94.7207,49.0052],[-94.7184,48.9979],[-94.7162,48.9907],[-94.7117,48.9761],[-94.7072,48.9615],[-94.7027,48.9468],[-94.6982,48.9322],[-94.6968,48.9276],[-94.6844,48.8875],[-94.6834,48.8842],[-94.6842,48.8724],[-94.6855,48.8719],[-94.6923,48.8691],[-94.6902,48.8636],[-94.6914,48.8591],[-94.693,48.8535],[-94.6881,48.8447],[-94.6855,48.8401],[-94.6963,48.836],[-94.6975,48.8355],[-94.702,48.8319],[-94.7025,48.8302],[-94.7042,48.8243],[-94.6991,48.8159],[-94.6962,48.8111],[-94.6951,48.8092],[-94.6958,48.8012],[-94.6959,48.7997],[-94.6944,48.7895],[-94.6934,48.7864],[-94.6909,48.7781],[-94.687,48.7752],[-94.6776,48.772],[-94.6768,48.7717],[-94.6746,48.7705],[-94.6671,48.7662],[-94.6603,48.7605],[-94.6557,48.7581],[-94.6525,48.7565],[-94.652,48.7562],[-94.6453,48.7491],[-94.6453,48.7441],[-94.6443,48.7434],[-94.6414,48.7413],[-94.631,48.7392],[-94.6301,48.739],[-94.6191,48.7373],[-94.6106,48.7318],[-94.6084,48.731],[-94.6028,48.7289],[-94.6011,48.7283],[-94.5962,48.7248],[-94.5913,48.7197],[-94.5876,48.7176],[-94.5867,48.7175],[-94.5685,48.7156],[-94.5622,48.7159],[-94.5558,48.7163],[-94.549,48.7148],[-94.5487,48.7146],[-94.5457,48.7124],[-94.5396,48.7036],[-94.539,48.7028],[-94.5329,48.7013],[-94.5247,48.7016],[-94.5178,48.7008],[-94.5173,48.7008],[-94.5093,48.7006],[-94.5066,48.6999],[-94.4996,48.698],[-94.4958,48.698],[-94.4863,48.698],[-94.4739,48.6969],[-94.4706,48.6966],[-94.4631,48.6953],[-94.4568,48.6933],[-94.4523,48.6925],[-94.4517,48.6925],[-94.4465,48.693],[-94.4388,48.6949],[-94.4319,48.6998],[-94.4299,48.7012],[-94.4299,48.6998],[-94.43,48.6852],[-94.4301,48.6708],[-94.43,48.6564],[-94.4297,48.642],[-94.4294,48.6276],[-94.4292,48.6133],[-94.4289,48.5988],[-94.4289,48.5844],[-94.4291,48.5698],[-94.4295,48.5554],[-94.43,48.5409],[-94.4303,48.5264],[-94.4303,48.512],[-94.4299,48.4977],[-94.4296,48.4832],[-94.4296,48.4688],[-94.4293,48.4543],[-94.4292,48.4399],[-94.4293,48.4254],[-94.4294,48.411],[-94.4293,48.3964],[-94.4289,48.3821],[-94.4288,48.3675],[-94.4471,48.3675],[-94.4505,48.3675],[-94.4688,48.3675],[-94.4722,48.3674],[-94.4906,48.3674],[-94.4924,48.3674],[-94.4941,48.3674],[-94.5118,48.3675],[-94.5157,48.3674],[-94.5335,48.3674],[-94.5378,48.3674],[-94.5536,48.3674],[-94.5593,48.3674],[-94.5754,48.3674],[-94.5812,48.3674],[-94.5971,48.3675],[-94.6029,48.3674],[-94.6188,48.3673],[-94.6245,48.3673],[-94.6405,48.3673],[-94.6465,48.3673],[-94.6505,48.3673],[-94.6622,48.3673],[-94.6679,48.3673],[-94.6694,48.3672],[-94.683,48.3671],[-94.6898,48.3671],[-94.7099,48.3669],[-94.7117,48.3668],[-94.7315,48.3669],[-94.7329,48.3669],[-94.7533,48.3669],[-94.7549,48.3669],[-94.7748,48.3669],[-94.7765,48.3669],[-94.7967,48.3669],[-94.7983,48.3669],[-94.8183,48.3669],[-94.8199,48.3669],[-94.8399,48.3669],[-94.8416,48.3669],[-94.8616,48.3667],[-94.8632,48.3667],[-94.8833,48.3667],[-94.8849,48.3666],[-94.9049,48.3666],[-94.9065,48.3666],[-94.9264,48.3667],[-94.9283,48.3667],[-94.9469,48.3666],[-94.95,48.3666],[-94.9684,48.3667],[-94.9716,48.3667],[-94.9901,48.3667],[-94.9932,48.3667],[-95.0119,48.3665],[-95.0153,48.3665],[-95.0337,48.3665],[-95.0369,48.3665],[-95.0555,48.3665],[-95.0586,48.3665],[-95.0773,48.3664],[-95.0801,48.3664],[-95.099,48.3663],[-95.1008,48.3663],[-95.1018,48.3663],[-95.1207,48.3663],[-95.1236,48.3663],[-95.1315,48.3662],[-95.1424,48.3662],[-95.1454,48.3662],[-95.164,48.3661],[-95.1669,48.3661],[-95.1861,48.3661],[-95.1887,48.3661],[-95.1983,48.3661],[-95.2066,48.3661],[-95.2106,48.3661],[-95.211,48.3797],[-95.211,48.3808],[-95.2111,48.3941],[-95.2111,48.3952],[-95.2112,48.4087],[-95.2112,48.4096],[-95.2113,48.4232],[-95.2113,48.4242],[-95.2113,48.4255],[-95.2113,48.4376],[-95.2113,48.4387],[-95.2113,48.4522],[-95.2112,48.4529],[-95.211,48.4666],[-95.211,48.4673],[-95.2111,48.4816],[-95.2112,48.4962],[-95.2111,48.5101],[-95.2111,48.5109],[-95.2115,48.5244],[-95.2115,48.5252],[-95.2119,48.54],[-95.2324,48.5399],[-95.2339,48.5399],[-95.2537,48.5398],[-95.2554,48.5398],[-95.2756,48.54],[-95.2773,48.54],[-95.2975,48.5401],[-95.2992,48.5402],[-95.3194,48.54],[-95.321,48.54],[-95.3412,48.5402],[-95.3425,48.5402],[-95.3424,48.5548],[-95.3423,48.5691],[-95.3423,48.5836],[-95.3426,48.5979],[-95.3424,48.6127],[-95.3426,48.6271],[-95.3425,48.6415],[-95.3424,48.6561],[-95.3423,48.6705],[-95.3424,48.6849],[-95.3425,48.6995],[-95.3425,48.7131],[-95.3302,48.713],[-95.3205,48.713],[-95.3084,48.713],[-95.3051,48.713],[-95.299,48.713],[-95.2866,48.713],[-95.2767,48.713],[-95.2656,48.713],[-95.2645,48.713],[-95.255,48.713],[-95.2427,48.713],[-95.2331,48.713],[-95.2206,48.713],[-95.2112,48.713],[-95.1991,48.713],[-95.1917,48.713],[-95.1773,48.713],[-95.1697,48.7129],[-95.1554,48.7129],[-95.1477,48.7129],[-95.1333,48.713],[-95.1297,48.713],[-95.1259,48.7129],[-95.1119,48.7129],[-95.1104,48.7129],[-95.1046,48.7129],[-95.0898,48.713],[-95.0899,48.7277],[-95.0901,48.7421],[-95.0901,48.7566],[-95.0903,48.7711],[-95.0903,48.7855],[-95.0903,48.8],[-95.0909,48.8147],[-95.0908,48.8291],[-95.0907,48.8436],[-95.0908,48.858],[-95.0908,48.8724],[-95.0911,48.8869],[-95.0912,48.9014],[-95.0914,48.916],[-95.0914,48.9208],[-95.0919,48.9207],[-95.0927,48.9204],[-95.0944,48.9193],[-95.0946,48.9191],[-95.0961,48.9181],[-95.097,48.9176],[-95.0971,48.9172],[-95.0975,48.9164],[-95.098,48.916],[-95.0981,48.9159],[-95.1008,48.9142],[-95.102,48.9132],[-95.1032,48.9127],[-95.1042,48.9121],[-95.1056,48.9113],[-95.108,48.9099],[-95.1096,48.9089],[-95.1107,48.9082],[-95.1126,48.9073],[-95.113,48.9072],[-95.1132,48.9071],[-95.1137,48.9069],[-95.1141,48.9064],[-95.114,48.9061],[-95.1144,48.9052],[-95.1151,48.9046],[-95.1163,48.9037],[-95.1182,48.9029],[-95.1204,48.9019],[-95.1205,48.9017],[-95.121,48.9016],[-95.1214,48.9013],[-95.1228,48.9006],[-95.1233,48.9004],[-95.1239,48.9001],[-95.1252,48.8998],[-95.1312,48.8975],[-95.1322,48.8973],[-95.1337,48.8969],[-95.1343,48.8963],[-95.1348,48.8963],[-95.1351,48.8963],[-95.1355,48.8959],[-95.1381,48.8949],[-95.1404,48.8943],[-95.1436,48.8937],[-95.1438,48.8934],[-95.1459,48.8929],[-95.1469,48.8927],[-95.1483,48.8923],[-95.1508,48.8922],[-95.1528,48.8921],[-95.1555,48.892],[-95.1564,48.8919],[-95.1579,48.8919],[-95.1602,48.892],[-95.1618,48.892],[-95.1641,48.8917],[-95.1648,48.8913],[-95.1674,48.8907],[-95.1701,48.8902],[-95.173,48.8897],[-95.1764,48.8893],[-95.1791,48.889],[-95.1797,48.889],[-95.1819,48.8888],[-95.1851,48.8882],[-95.1863,48.8877],[-95.1877,48.8874],[-95.1889,48.8873],[-95.1901,48.887],[-95.1913,48.8868],[-95.1919,48.8866],[-95.1924,48.8865],[-95.1956,48.8862],[-95.1986,48.8855],[-95.2005,48.8856],[-95.2009,48.8855],[-95.2024,48.8852],[-95.2059,48.8848],[-95.2085,48.8846],[-95.2112,48.8848],[-95.2115,48.8847],[-95.2117,48.8847],[-95.2122,48.8842],[-95.2144,48.8843],[-95.2151,48.884],[-95.2159,48.8839],[-95.217,48.8835],[-95.2188,48.8835],[-95.2193,48.8832],[-95.22,48.8831],[-95.2207,48.8831],[-95.2208,48.8831],[-95.2212,48.883],[-95.2252,48.8819],[-95.2265,48.8816],[-95.2287,48.8815],[-95.231,48.8814],[-95.2335,48.8814],[-95.2356,48.8815],[-95.2381,48.8817],[-95.2391,48.8819],[-95.2407,48.8821],[-95.2423,48.8821],[-95.2429,48.8822],[-95.2429,48.8822],[-95.2439,48.8823],[-95.2458,48.8829],[-95.2472,48.8835],[-95.248,48.8836],[-95.2485,48.8832],[-95.2496,48.8834],[-95.2502,48.8835],[-95.2507,48.8836],[-95.2517,48.8839],[-95.2548,48.8845],[-95.256,48.885],[-95.257,48.8858],[-95.2585,48.8867],[-95.2585,48.8867],[-95.2627,48.8877],[-95.2635,48.888],[-95.2639,48.8883],[-95.2646,48.8885],[-95.265,48.8886],[-95.2654,48.8888],[-95.2666,48.8894],[-95.2674,48.89],[-95.2677,48.8903],[-95.268,48.8905],[-95.2713,48.8915],[-95.2724,48.8921],[-95.2745,48.8931],[-95.2751,48.8938],[-95.2753,48.8943],[-95.2748,48.8951],[-95.2749,48.8956],[-95.2755,48.8959],[-95.2759,48.8962],[-95.2763,48.8963],[-95.2765,48.8962],[-95.277,48.8958],[-95.2773,48.8957],[-95.2782,48.8956],[-95.279,48.8957],[-95.2796,48.8962],[-95.2803,48.8965],[-95.2813,48.8967],[-95.2839,48.8975],[-95.2853,48.8977],[-95.2861,48.8976],[-95.2865,48.8975],[-95.287,48.8976],[-95.2872,48.8977],[-95.2879,48.8979],[-95.2882,48.8981],[-95.289,48.8994],[-95.2896,48.9],[-95.2901,48.9003],[-95.2911,48.9006],[-95.2911,48.9008],[-95.2906,48.9011],[-95.2907,48.9014],[-95.2908,48.9016],[-95.2909,48.9017],[-95.2914,48.9019],[-95.2927,48.9019],[-95.2935,48.902],[-95.2937,48.9023],[-95.2941,48.9027],[-95.2949,48.9028],[-95.2967,48.9027],[-95.2976,48.9026],[-95.298,48.9027],[-95.2983,48.9028],[-95.2993,48.9035],[-95.3005,48.904],[-95.3002,48.9045],[-95.3001,48.9046],[-95.3001,48.9047],[-95.3,48.9047],[-95.3,48.9047],[-95.2999,48.9048],[-95.2999,48.9048],[-95.2999,48.9048],[-95.2997,48.905],[-95.2996,48.9051],[-95.2994,48.9053],[-95.2992,48.9055],[-95.2991,48.9057],[-95.2989,48.906],[-95.2988,48.906],[-95.2986,48.9063],[-95.2985,48.9064],[-95.2985,48.9065],[-95.2983,48.9068],[-95.2982,48.9068],[-95.2981,48.907],[-95.298,48.9071],[-95.298,48.9071],[-95.298,48.9071],[-95.2979,48.9071],[-95.2979,48.9072],[-95.2979,48.9072],[-95.2978,48.9072],[-95.2978,48.9072],[-95.2978,48.9073],[-95.2977,48.9073],[-95.2976,48.9074],[-95.2973,48.9077],[-95.2973,48.908],[-95.2973,48.9081],[-95.2978,48.9083],[-95.2999,48.9086],[-95.3017,48.9093],[-95.3027,48.91],[-95.3038,48.9114],[-95.3043,48.9119],[-95.3059,48.9127],[-95.3061,48.9128],[-95.3064,48.9129],[-95.3074,48.9135],[-95.3078,48.9141],[-95.3085,48.9146],[-95.3092,48.9149],[-95.3093,48.9149],[-95.3102,48.9155],[-95.3109,48.9163],[-95.3115,48.9172],[-95.3119,48.9178],[-95.3126,48.919],[-95.3132,48.9198],[-95.3141,48.921],[-95.315,48.9222],[-95.3168,48.9245],[-95.3195,48.9285],[-95.3208,48.9305],[-95.3209,48.9307],[-95.3222,48.9327],[-95.3228,48.9344],[-95.3223,48.9355],[-95.3225,48.9358],[-95.3229,48.9373],[-95.3231,48.9389],[-95.3228,48.9403],[-95.3225,48.9409],[-95.3219,48.9412],[-95.3189,48.9419],[-95.3181,48.9421],[-95.3168,48.9431],[-95.3154,48.9448],[-95.3148,48.9452],[-95.3141,48.9457],[-95.3131,48.946],[-95.3114,48.9461],[-95.3102,48.9463],[-95.3095,48.9463],[-95.3088,48.9464],[-95.3086,48.9465],[-95.3086,48.9469],[-95.3085,48.947],[-95.3078,48.9466],[-95.3074,48.9465],[-95.3071,48.9466],[-95.3071,48.9469],[-95.3079,48.9474],[-95.3092,48.9477],[-95.3096,48.9478],[-95.3103,48.948],[-95.3104,48.9484],[-95.3103,48.9485],[-95.31,48.9485],[-95.3099,48.9484],[-95.3096,48.9482],[-95.3094,48.9481],[-95.3081,48.948],[-95.3071,48.9477],[-95.3062,48.9472],[-95.3062,48.9472],[-95.3061,48.9469],[-95.3062,48.9463],[-95.3063,48.9462],[-95.3069,48.9456],[-95.3069,48.9455],[-95.3068,48.9454],[-95.3061,48.9454],[-95.3053,48.9459],[-95.305,48.9462],[-95.3046,48.947],[-95.3046,48.9482],[-95.3052,48.9495],[-95.3061,48.9502],[-95.3079,48.9509],[-95.3089,48.9511],[-95.3097,48.951],[-95.3104,48.951],[-95.3108,48.9512],[-95.3115,48.952],[-95.312,48.9524],[-95.3126,48.9524],[-95.3129,48.9523],[-95.3129,48.9521],[-95.3119,48.9507],[-95.3119,48.9502],[-95.3123,48.9502],[-95.3125,48.9503],[-95.3131,48.9503],[-95.3141,48.9508],[-95.3151,48.951],[-95.3154,48.9513],[-95.3177,48.9525],[-95.3181,48.9531],[-95.3182,48.9535],[-95.3177,48.9545],[-95.3175,48.9552],[-95.3179,48.9559],[-95.3188,48.9562],[-95.3191,48.9569],[-95.3202,48.9581],[-95.3206,48.959],[-95.3206,48.9595],[-95.3206,48.9598],[-95.3202,48.9606],[-95.3193,48.9622],[-95.3193,48.964],[-95.3198,48.9643],[-95.3201,48.9648],[-95.3207,48.9669],[-95.3212,48.9672],[-95.3227,48.9685],[-95.3232,48.9692],[-95.3241,48.9703],[-95.3247,48.972],[-95.3248,48.9728],[-95.3249,48.9738],[-95.325,48.9743],[-95.3253,48.976],[-95.3257,48.9784],[-95.3255,48.9789],[-95.3256,48.98],[-95.3257,48.9814],[-95.3253,48.9832],[-95.3245,48.985],[-95.3242,48.9859],[-95.3227,48.9884],[-95.3224,48.9889],[-95.3206,48.9921],[-95.3204,48.9924],[-95.3191,48.9941],[-95.3181,48.995],[-95.3178,48.9958],[-95.3178,48.9961],[-95.3179,48.9961],[-95.3182,48.996],[-95.3187,48.9956],[-95.3191,48.9953],[-95.3197,48.9954],[-95.3201,48.9956],[-95.3206,48.9961],[-95.3204,48.9964],[-95.3202,48.9973],[-95.3204,48.9976],[-95.3224,48.9984],[-95.3231,48.999]]],"type":"Polygon"},"id":"39","properties":{"Area":4608320923.49768,"CTYONLY_":2,"Code":"LOTW","LASTMOD":"1976-07-04T12:00:00Z","Name":"Lake of the Woods","Perimiter":388250.14572},"type":"Feature"},{"geometry":{"coordinates":[[[-96.4054,49.0001],[-96.4054,48.9947],[-96.4054,48.994],[-96.4054,48.9803],[-96.4054,48.9793],[-96.4053,48.9705],[-96.4053,48.9658],[-96.4053,48.9648],[-96.4053,48.9515],[-96.4053,48.9504],[-96.4053,48.9371],[-96.4053,48.936],[-96.4054,48.9225],[-96.4054,48.9214],[-96.4053,48.9137],[-96.4053,48.9081],[-96.4053,48.9068],[-96.405,48.8926],[-96.405,48.878],[-96.4047,48.8635],[-96.4045,48.8491],[-96.4043,48.8343],[-96.4042,48.8198],[-96.4042,48.8048],[-96.4042,48.7903],[-96.4045,48.7758],[-96.4047,48.7607],[-96.4048,48.7465],[-96.4048,48.7318],[-96.4049,48.7172],[-96.388,48.7172],[-96.3873,48.7172],[-96.3866,48.703],[-96.3874,48.6887],[-96.3871,48.6741],[-96.3877,48.6599],[-96.3879,48.6454],[-96.388,48.6313],[-96.389,48.6165],[-96.3891,48.6024],[-96.3884,48.5877],[-96.3882,48.5733],[-96.3879,48.5588],[-96.3882,48.5442],[-96.4101,48.544],[-96.4318,48.5438],[-96.4535,48.5436],[-96.4754,48.5435],[-96.4973,48.5434],[-96.518,48.5434],[-96.54,48.5434],[-96.5621,48.5436],[-96.5839,48.5437],[-96.6058,48.5437],[-96.6278,48.5437],[-96.6493,48.5437],[-96.6713,48.5436],[-96.6931,48.5437],[-96.7151,48.5437],[-96.7368,48.5437],[-96.7585,48.5436],[-96.7803,48.5435],[-96.8023,48.5436],[-96.824,48.5436],[-96.8459,48.5434],[-96.8678,48.5433],[-96.8896,48.5433],[-96.9115,48.5432],[-96.9138,48.5433],[-96.9331,48.5435],[-96.9551,48.5437],[-96.9768,48.544],[-96.9985,48.5441],[-97.0194,48.5441],[-97.0416,48.5442],[-97.0635,48.5441],[-97.0852,48.5441],[-97.107,48.544],[-97.1287,48.5439],[-97.1509,48.5439],[-97.1631,48.544],[-97.1637,48.5445],[-97.1659,48.5483],[-97.1662,48.5509],[-97.1661,48.5527],[-97.1654,48.5536],[-97.1645,48.554],[-97.1628,48.5543],[-97.1613,48.5539],[-97.1592,48.5528],[-97.1577,48.5518],[-97.1557,48.5512],[-97.1538,48.5513],[-97.1513,48.5515],[-97.1507,48.5515],[-97.1493,48.5516],[-97.1474,48.5516],[-97.1444,48.5514],[-97.1407,48.5515],[-97.1387,48.5522],[-97.1379,48.553],[-97.1379,48.5542],[-97.1391,48.5554],[-97.141,48.5566],[-97.1426,48.5571],[-97.1464,48.5573],[-97.1505,48.5574],[-97.1515,48.5574],[-97.1551,48.5574],[-97.1578,48.5573],[-97.1606,48.5571],[-97.1631,48.5571],[-97.1646,48.5572],[-97.167,48.5575],[-97.1697,48.5584],[-97.1721,48.5591],[-97.1727,48.5593],[-97.174,48.5599],[-97.1749,48.5606],[-97.1753,48.5614],[-97.1754,48.5623],[-97.1749,48.5631],[-97.1744,48.5639],[-97.1723,48.5648],[-97.1721,48.5648],[-97.1706,48.5652],[-97.1687,48.5655],[-97.167,48.5658],[-97.1651,48.5659],[-97.1613,48.5661],[-97.1541,48.5669],[-97.153,48.5671],[-97.1516,48.5677],[-97.1503,48.5688],[-97.1496,48.5695],[-97.1487,48.5707],[-97.1477,48.5727],[-97.1477,48.5728],[-97.1476,48.5731],[-97.1483,48.5763],[-97.15,48.5775],[-97.1501,48.5775],[-97.1548,48.5779],[-97.1592,48.5785],[-97.1605,48.58],[-97.16,48.5816],[-97.1578,48.5826],[-97.1562,48.5828],[-97.1541,48.5826],[-97.1524,48.5823],[-97.15,48.5815],[-97.1494,48.5813],[-97.1484,48.5811],[-97.1449,48.5815],[-97.1436,48.5824],[-97.1431,48.5834],[-97.1429,48.5838],[-97.142,48.5876],[-97.1418,48.5886],[-97.1415,48.5909],[-97.1422,48.5926],[-97.1433,48.5936],[-97.1451,48.594],[-97.1471,48.594],[-97.1497,48.5937],[-97.1525,48.594],[-97.1536,48.5949],[-97.1535,48.5957],[-97.1527,48.5962],[-97.1524,48.5969],[-97.1516,48.598],[-97.1498,48.5981],[-97.1497,48.5981],[-97.1463,48.5977],[-97.1443,48.5981],[-97.143,48.5987],[-97.1416,48.6002],[-97.1403,48.6021],[-97.14,48.6025],[-97.138,48.6044],[-97.1359,48.6054],[-97.1345,48.6065],[-97.1341,48.6075],[-97.1349,48.6082],[-97.1358,48.6086],[-97.137,48.6088],[-97.1396,48.6086],[-97.1443,48.6078],[-97.1474,48.6081],[-97.1494,48.6089],[-97.1495,48.609],[-97.1505,48.6115],[-97.1501,48.6124],[-97.1493,48.6129],[-97.1478,48.6138],[-97.145,48.6146],[-97.1408,48.6149],[-97.137,48.6144],[-97.134,48.6136],[-97.1319,48.6133],[-97.1309,48.6137],[-97.1289,48.614],[-97.1286,48.6153],[-97.1293,48.6168],[-97.1295,48.617],[-97.1311,48.6184],[-97.1342,48.6199],[-97.1353,48.6212],[-97.1346,48.6224],[-97.133,48.6228],[-97.131,48.6227],[-97.1291,48.6222],[-97.1277,48.6212],[-97.1274,48.621],[-97.1259,48.6195],[-97.1253,48.619],[-97.1243,48.6183],[-97.1231,48.6178],[-97.1216,48.6176],[-97.12,48.6178],[-97.1193,48.6182],[-97.1186,48.6191],[-97.1183,48.6198],[-97.1186,48.6209],[-97.1198,48.6221],[-97.1209,48.6232],[-97.1212,48.6233],[-97.122,48.624],[-97.1228,48.6245],[-97.1236,48.625],[-97.1241,48.6254],[-97.1245,48.6257],[-97.1249,48.6259],[-97.1253,48.6261],[-97.126,48.6264],[-97.1266,48.6266],[-97.1272,48.627],[-97.1279,48.6273],[-97.1288,48.6278],[-97.1296,48.6282],[-97.1302,48.6288],[-97.1305,48.6292],[-97.1307,48.6297],[-97.131,48.6303],[-97.131,48.6304],[-97.131,48.6308],[-97.131,48.6315],[-97.1309,48.6317],[-97.1307,48.6321],[-97.1304,48.6325],[-97.1301,48.6326],[-97.1297,48.6328],[-97.1293,48.6329],[-97.129,48.633],[-97.1281,48.6332],[-97.128,48.6333],[-97.1275,48.6333],[-97.1253,48.6334],[-97.1235,48.6333],[-97.1216,48.6327],[-97.1181,48.6308],[-97.1176,48.6307],[-97.115,48.6299],[-97.1133,48.63],[-97.1115,48.6303],[-97.1107,48.6308],[-97.1104,48.6309],[-97.1095,48.6315],[-97.1084,48.6327],[-97.1082,48.6344],[-97.1086,48.6363],[-97.1096,48.6389],[-97.1109,48.6407],[-97.1119,48.6416],[-97.1144,48.6433],[-97.115,48.6438],[-97.115,48.6446],[-97.1149,48.6452],[-97.1123,48.6457],[-97.1112,48.6459],[-97.1093,48.6465],[-97.1078,48.6478],[-97.1069,48.6491],[-97.1066,48.6501],[-97.1061,48.6519],[-97.1059,48.6527],[-97.1045,48.6545],[-97.1017,48.6563],[-97.0987,48.6593],[-97.0986,48.6604],[-97.0985,48.6613],[-97.0992,48.6625],[-97.1019,48.6636],[-97.106,48.663],[-97.1062,48.663],[-97.1082,48.6634],[-97.1087,48.6645],[-97.1061,48.6654],[-97.1057,48.6655],[-97.102,48.6667],[-97.1,48.668],[-97.0998,48.6714],[-97.1002,48.675],[-97.1003,48.6757],[-97.1008,48.6787],[-97.1011,48.6808],[-97.1003,48.6828],[-97.0985,48.683],[-97.0946,48.6822],[-97.0926,48.6821],[-97.0904,48.6828],[-97.0898,48.6841],[-97.0899,48.6852],[-97.091,48.6861],[-97.093,48.687],[-97.0951,48.6876],[-97.099,48.6884],[-97.1024,48.6893],[-97.103,48.6894],[-97.1059,48.6903],[-97.1064,48.6905],[-97.1086,48.6915],[-97.111,48.6939],[-97.113,48.6964],[-97.1148,48.6981],[-97.1182,48.7005],[-97.1198,48.7018],[-97.1201,48.7039],[-97.1194,48.7041],[-97.1182,48.7046],[-97.1143,48.7052],[-97.1117,48.7056],[-97.11,48.7063],[-97.1098,48.7083],[-97.1113,48.7094],[-97.1134,48.7101],[-97.1157,48.7105],[-97.1174,48.7111],[-97.119,48.7119],[-97.1212,48.7136],[-97.1223,48.716],[-97.1229,48.7168],[-97.1231,48.7172],[-97.1243,48.7192],[-97.1253,48.7201],[-97.1253,48.7203],[-97.126,48.7207],[-97.1263,48.7212],[-97.1272,48.7215],[-97.128,48.722],[-97.1282,48.7221],[-97.1288,48.7225],[-97.1297,48.7229],[-97.131,48.7233],[-97.1321,48.7238],[-97.1331,48.7242],[-97.1345,48.7248],[-97.136,48.7257],[-97.1369,48.7263],[-97.1375,48.727],[-97.1376,48.7274],[-97.1376,48.7278],[-97.1373,48.7283],[-97.137,48.7284],[-97.1365,48.7285],[-97.136,48.7287],[-97.1352,48.7287],[-97.1341,48.7289],[-97.1333,48.7291],[-97.1328,48.7292],[-97.132,48.7294],[-97.1312,48.7295],[-97.1308,48.7296],[-97.1299,48.7299],[-97.1294,48.7304],[-97.1288,48.7308],[-97.1286,48.7312],[-97.1286,48.7315],[-97.1286,48.7316],[-97.1286,48.7318],[-97.1285,48.7322],[-97.1286,48.7326],[-97.1286,48.7328],[-97.1287,48.7331],[-97.129,48.7335],[-97.1295,48.7339],[-97.1298,48.7341],[-97.1316,48.7347],[-97.1322,48.7348],[-97.1334,48.7347],[-97.1351,48.7345],[-97.1369,48.7345],[-97.1383,48.7345],[-97.1396,48.7347],[-97.1402,48.7349],[-97.1412,48.7354],[-97.1419,48.7359],[-97.1422,48.7367],[-97.1423,48.7372],[-97.1421,48.7381],[-97.1414,48.7385],[-97.1408,48.7387],[-97.1404,48.7389],[-97.1399,48.7393],[-97.1392,48.7397],[-97.1381,48.7408],[-97.1372,48.742],[-97.1366,48.7435],[-97.1365,48.745],[-97.1365,48.7459],[-97.1366,48.7466],[-97.1369,48.748],[-97.1375,48.7492],[-97.1379,48.75],[-97.1385,48.7504],[-97.1391,48.7507],[-97.1396,48.7508],[-97.1401,48.7509],[-97.141,48.751],[-97.142,48.751],[-97.143,48.7509],[-97.1444,48.7507],[-97.1457,48.7506],[-97.1466,48.7505],[-97.1476,48.7505],[-97.1491,48.7506],[-97.1497,48.7508],[-97.1503,48.7509],[-97.1515,48.7515],[-97.1521,48.752],[-97.153,48.7529],[-97.1539,48.7542],[-97.1545,48.7553],[-97.1547,48.7558],[-97.1548,48.7562],[-97.1548,48.7569],[-97.1548,48.7576],[-97.1546,48.758],[-97.1542,48.7587],[-97.1535,48.7593],[-97.1528,48.7598],[-97.1519,48.7601],[-97.1508,48.7605],[-97.1503,48.7606],[-97.1501,48.7607],[-97.1475,48.7616],[-97.1473,48.7617],[-97.1469,48.762],[-97.1462,48.7626],[-97.1461,48.7628],[-97.1459,48.7633],[-97.1456,48.7643],[-97.1456,48.765],[-97.146,48.7658],[-97.1476,48.7673],[-97.1487,48.7681],[-97.15,48.7692],[-97.1501,48.7693],[-97.1506,48.77],[-97.1512,48.7712],[-97.1519,48.7721],[-97.1525,48.7727],[-97.1529,48.7728],[-97.1559,48.7731],[-97.1567,48.7732],[-97.1578,48.7735],[-97.1582,48.7737],[-97.1587,48.7742],[-97.1589,48.7746],[-97.159,48.7751],[-97.159,48.7751],[-97.159,48.7754],[-97.1589,48.776],[-97.1584,48.7766],[-97.1579,48.7769],[-97.1573,48.7772],[-97.1557,48.7776],[-97.1544,48.7778],[-97.1534,48.778],[-97.1522,48.7783],[-97.1509,48.7787],[-97.1501,48.7789],[-97.1497,48.779],[-97.1483,48.7797],[-97.1477,48.7801],[-97.1473,48.7807],[-97.1472,48.7811],[-97.1473,48.7816],[-97.1478,48.7821],[-97.1486,48.7824],[-97.1495,48.7826],[-97.1501,48.7826],[-97.1503,48.7826],[-97.1513,48.7825],[-97.1533,48.7824],[-97.1547,48.7824],[-97.1559,48.7825],[-97.1571,48.7827],[-97.1583,48.783],[-97.1591,48.7834],[-97.1595,48.7838],[-97.1597,48.7843],[-97.1598,48.7848],[-97.1596,48.7853],[-97.1593,48.786],[-97.1591,48.7863],[-97.1586,48.7869],[-97.1577,48.7877],[-97.1574,48.7882],[-97.1573,48.7884],[-97.1572,48.7887],[-97.1571,48.7894],[-97.157,48.7895],[-97.157,48.7901],[-97.1572,48.7906],[-97.1575,48.7909],[-97.1581,48.7912],[-97.1586,48.7913],[-97.1592,48.7915],[-97.1595,48.7915],[-97.1611,48.7915],[-97.1618,48.7914],[-97.1645,48.7911],[-97.1648,48.7911],[-97.1657,48.7911],[-97.1664,48.7912],[-97.1672,48.7913],[-97.1714,48.7921],[-97.1718,48.7923],[-97.1721,48.7924],[-97.1731,48.7929],[-97.1737,48.7933],[-97.174,48.7937],[-97.1741,48.7942],[-97.1742,48.7947],[-97.1742,48.7951],[-97.1739,48.7954],[-97.1734,48.7958],[-97.1726,48.7963],[-97.1717,48.7966],[-97.1716,48.7966],[-97.171,48.7967],[-97.1701,48.7967],[-97.1688,48.7966],[-97.1673,48.7964],[-97.1665,48.7962],[-97.1654,48.7962],[-97.1648,48.7962],[-97.1638,48.7963],[-97.1631,48.7966],[-97.1625,48.7969],[-97.162,48.7974],[-97.1617,48.7979],[-97.1617,48.7984],[-97.1619,48.7988],[-97.1621,48.7994],[-97.1626,48.8001],[-97.1633,48.8007],[-97.1642,48.8011],[-97.1652,48.8014],[-97.166,48.8015],[-97.1668,48.8016],[-97.1675,48.8016],[-97.1685,48.8016],[-97.1698,48.8013],[-97.1706,48.8011],[-97.1714,48.8008],[-97.1715,48.8008],[-97.1724,48.8004],[-97.1731,48.8],[-97.1742,48.7992],[-97.175,48.7986],[-97.1754,48.7983],[-97.1757,48.798],[-97.1761,48.7977],[-97.1768,48.7974],[-97.1773,48.7973],[-97.1779,48.7972],[-97.1787,48.7972],[-97.1795,48.7972],[-97.1801,48.7973],[-97.1807,48.7975],[-97.1811,48.7978],[-97.1815,48.7982],[-97.1816,48.7986],[-97.1817,48.7991],[-97.1815,48.7995],[-97.1813,48.8],[-97.1808,48.8004],[-97.1801,48.8008],[-97.1791,48.8012],[-97.1779,48.8015],[-97.1769,48.8017],[-97.1764,48.8018],[-97.1756,48.8021],[-97.1748,48.8023],[-97.1725,48.8032],[-97.1713,48.8036],[-97.171,48.8037],[-97.1706,48.8039],[-97.1694,48.8043],[-97.1682,48.8046],[-97.1675,48.8048],[-97.1666,48.805],[-97.1655,48.8052],[-97.1638,48.8055],[-97.161,48.8059],[-97.1605,48.8061],[-97.1597,48.8064],[-97.159,48.8067],[-97.1583,48.8072],[-97.1579,48.8077],[-97.1577,48.8082],[-97.1576,48.8089],[-97.1578,48.8098],[-97.158,48.8104],[-97.1586,48.811],[-97.159,48.8111],[-97.161,48.8117],[-97.1617,48.8119],[-97.1625,48.812],[-97.1636,48.8121],[-97.1644,48.8121],[-97.1651,48.812],[-97.1666,48.8118],[-97.168,48.8116],[-97.169,48.8114],[-97.17,48.8114],[-97.1713,48.8115],[-97.1715,48.8115],[-97.1726,48.8117],[-97.1731,48.8118],[-97.174,48.8122],[-97.1761,48.8132],[-97.1776,48.8141],[-97.1784,48.8145],[-97.1797,48.8149],[-97.1807,48.8151],[-97.1821,48.8153],[-97.1828,48.8153],[-97.184,48.8152],[-97.1848,48.8151],[-97.186,48.8147],[-97.1868,48.8145],[-97.1873,48.8143],[-97.1879,48.8143],[-97.1883,48.8143],[-97.1889,48.8143],[-97.1894,48.8144],[-97.1898,48.8146],[-97.1901,48.8148],[-97.1903,48.8153],[-97.1904,48.8156],[-97.1903,48.8159],[-97.19,48.8163],[-97.1893,48.8167],[-97.1885,48.8171],[-97.1879,48.8173],[-97.1866,48.8176],[-97.1857,48.8177],[-97.1847,48.8179],[-97.184,48.8181],[-97.1833,48.8184],[-97.1817,48.8189],[-97.1809,48.8193],[-97.1801,48.8199],[-97.1793,48.8207],[-97.1787,48.8216],[-97.178,48.8232],[-97.1777,48.824],[-97.1776,48.8245],[-97.1777,48.8249],[-97.178,48.8255],[-97.1782,48.8258],[-97.1786,48.8262],[-97.1794,48.8268],[-97.1822,48.8288],[-97.1837,48.8299],[-97.1841,48.8304],[-97.1847,48.8314],[-97.1848,48.8319],[-97.1849,48.8326],[-97.1849,48.8327],[-97.1848,48.833],[-97.1846,48.8336],[-97.1842,48.8341],[-97.1837,48.8345],[-97.183,48.8348],[-97.1822,48.835],[-97.1813,48.8351],[-97.1799,48.8352],[-97.1783,48.8353],[-97.1779,48.8354],[-97.1772,48.8356],[-97.1757,48.8362],[-97.1753,48.8364],[-97.1747,48.8369],[-97.1742,48.8373],[-97.1739,48.8378],[-97.1738,48.8384],[-97.1738,48.839],[-97.1739,48.8406],[-97.1743,48.8427],[-97.1747,48.8438],[-97.175,48.8442],[-97.1755,48.8447],[-97.1761,48.8452],[-97.1767,48.8455],[-97.1771,48.8456],[-97.1779,48.8458],[-97.1795,48.8459],[-97.1808,48.846],[-97.1817,48.8462],[-97.1823,48.8464],[-97.1827,48.8468],[-97.1829,48.847],[-97.1829,48.8471],[-97.1829,48.8473],[-97.1826,48.8476],[-97.1821,48.8479],[-97.1816,48.848],[-97.1809,48.8481],[-97.1793,48.8482],[-97.178,48.8483],[-97.1767,48.8484],[-97.1759,48.8486],[-97.1753,48.8487],[-97.1747,48.849],[-97.1742,48.8493],[-97.1737,48.8497],[-97.1733,48.8502],[-97.173,48.8506],[-97.173,48.8508],[-97.173,48.8511],[-97.173,48.8516],[-97.1732,48.8522],[-97.1737,48.8527],[-97.1746,48.8534],[-97.1771,48.855],[-97.1784,48.8561],[-97.1786,48.8563],[-97.179,48.8569],[-97.1793,48.8576],[-97.1794,48.8583],[-97.1794,48.859],[-97.1792,48.8606],[-97.179,48.8615],[-97.179,48.862],[-97.1791,48.8626],[-97.1794,48.863],[-97.1801,48.8636],[-97.1811,48.864],[-97.1818,48.8641],[-97.1827,48.8641],[-97.1839,48.864],[-97.1855,48.8637],[-97.1871,48.8633],[-97.1877,48.8631],[-97.1883,48.8631],[-97.1891,48.8631],[-97.1896,48.8633],[-97.19,48.8635],[-97.1903,48.8639],[-97.1905,48.8644],[-97.1905,48.8648],[-97.1904,48.8651],[-97.1901,48.8657],[-97.1899,48.8661],[-97.1895,48.8665],[-97.189,48.867],[-97.1884,48.8675],[-97.1851,48.8694],[-97.1813,48.8718],[-97.1788,48.8736],[-97.1785,48.8738],[-97.1782,48.8741],[-97.1781,48.8743],[-97.1779,48.8745],[-97.1778,48.8747],[-97.1777,48.8749],[-97.1777,48.875],[-97.1778,48.875],[-97.1778,48.8754],[-97.1779,48.8757],[-97.1782,48.8761],[-97.1786,48.8765],[-97.1792,48.8769],[-97.1798,48.8771],[-97.1808,48.8772],[-97.1823,48.8772],[-97.1852,48.8768],[-97.1869,48.8765],[-97.1881,48.8765],[-97.1891,48.8766],[-97.1904,48.8769],[-97.1933,48.8779],[-97.1944,48.8783],[-97.1957,48.8788],[-97.1972,48.8794],[-97.1981,48.8799],[-97.1988,48.8805],[-97.1995,48.8812],[-97.1999,48.8818],[-97.1999,48.8821],[-97.2,48.8827],[-97.1998,48.8832],[-97.1997,48.8836],[-97.199,48.8845],[-97.1978,48.8859],[-97.1975,48.8865],[-97.1974,48.8868],[-97.1973,48.8872],[-97.1973,48.8874],[-97.1974,48.8877],[-97.1975,48.8881],[-97.1983,48.8889],[-97.2002,48.8903],[-97.2004,48.8904],[-97.2009,48.8908],[-97.2014,48.8912],[-97.2017,48.8915],[-97.2017,48.8919],[-97.2016,48.8922],[-97.2013,48.8925],[-97.201,48.8926],[-97.2001,48.8926],[-97.1994,48.8926],[-97.1985,48.8925],[-97.198,48.8924],[-97.1973,48.892],[-97.1957,48.8916],[-97.1946,48.8915],[-97.1944,48.8914],[-97.1937,48.8914],[-97.1927,48.8915],[-97.1921,48.8917],[-97.1916,48.8919],[-97.1905,48.8926],[-97.1901,48.8932],[-97.1898,48.8938],[-97.1897,48.8944],[-97.1897,48.8947],[-97.1898,48.8951],[-97.1899,48.8954],[-97.1903,48.896],[-97.1911,48.8967],[-97.1919,48.8974],[-97.1925,48.8979],[-97.1935,48.8985],[-97.1941,48.8988],[-97.1945,48.8989],[-97.1966,48.8997],[-97.1992,48.9004],[-97.2009,48.9009],[-97.2022,48.9013],[-97.2048,48.9018],[-97.2055,48.902],[-97.207,48.9025],[-97.2076,48.9027],[-97.2082,48.9029],[-97.2088,48.9032],[-97.2093,48.9036],[-97.21,48.904],[-97.2105,48.9044],[-97.211,48.905],[-97.2114,48.9056],[-97.2122,48.9069],[-97.2125,48.9075],[-97.2127,48.9082],[-97.2127,48.909],[-97.2125,48.9099],[-97.212,48.911],[-97.2116,48.9121],[-97.2111,48.913],[-97.2108,48.914],[-97.2106,48.9148],[-97.2106,48.9153],[-97.2109,48.9162],[-97.2111,48.9167],[-97.2115,48.9172],[-97.2118,48.9175],[-97.2122,48.9177],[-97.2129,48.9181],[-97.2149,48.9187],[-97.2163,48.9191],[-97.2164,48.9191],[-97.2171,48.9194],[-97.2179,48.9198],[-97.2189,48.9205],[-97.2196,48.9215],[-97.2198,48.9222],[-97.2199,48.923],[-97.2197,48.9237],[-97.2191,48.9249],[-97.2183,48.9262],[-97.2172,48.9277],[-97.2163,48.9286],[-97.2159,48.9289],[-97.2149,48.9301],[-97.2146,48.9304],[-97.2145,48.9307],[-97.2144,48.931],[-97.2145,48.9314],[-97.2145,48.9316],[-97.2148,48.9319],[-97.2154,48.9325],[-97.2159,48.9327],[-97.2162,48.9328],[-97.217,48.9328],[-97.2181,48.9327],[-97.2198,48.9325],[-97.2208,48.9325],[-97.2214,48.9325],[-97.2218,48.9326],[-97.2237,48.9332],[-97.2245,48.9337],[-97.2249,48.9339],[-97.225,48.934],[-97.2252,48.9342],[-97.2254,48.9345],[-97.2257,48.9349],[-97.226,48.9353],[-97.2263,48.936],[-97.2267,48.9376],[-97.227,48.9389],[-97.2271,48.9398],[-97.2271,48.941],[-97.227,48.9418],[-97.2266,48.9432],[-97.2264,48.9441],[-97.2263,48.9445],[-97.2264,48.9452],[-97.2265,48.9456],[-97.227,48.9462],[-97.2273,48.9465],[-97.2276,48.9467],[-97.2279,48.9467],[-97.2284,48.9468],[-97.2304,48.9465],[-97.2309,48.9464],[-97.2313,48.9464],[-97.2326,48.9466],[-97.2331,48.9468],[-97.2338,48.9471],[-97.2342,48.9474],[-97.2343,48.948],[-97.2343,48.9485],[-97.2342,48.9488],[-97.2341,48.9491],[-97.2337,48.95],[-97.2332,48.951],[-97.2328,48.9524],[-97.2323,48.954],[-97.2317,48.9558],[-97.2313,48.9568],[-97.2309,48.9578],[-97.2305,48.9585],[-97.23,48.9591],[-97.2288,48.9603],[-97.2282,48.9609],[-97.2278,48.9613],[-97.2276,48.9619],[-97.2276,48.9624],[-97.2279,48.963],[-97.228,48.9631],[-97.2283,48.9634],[-97.2289,48.9639],[-97.2294,48.9641],[-97.23,48.9642],[-97.2323,48.9646],[-97.2355,48.965],[-97.2368,48.9652],[-97.2375,48.9654],[-97.2382,48.966],[-97.2383,48.9661],[-97.2388,48.9666],[-97.2391,48.9676],[-97.2392,48.9687],[-97.239,48.9696],[-97.2387,48.9706],[-97.2383,48.9715],[-97.2381,48.9723],[-97.238,48.9725],[-97.2379,48.9731],[-97.2378,48.9734],[-97.2378,48.9738],[-97.238,48.9752],[-97.238,48.9763],[-97.2381,48.9771],[-97.238,48.9771],[-97.238,48.9841],[-97.2377,48.9849],[-97.2372,48.9857],[-97.2365,48.9867],[-97.2359,48.9874],[-97.2351,48.9881],[-97.2342,48.989],[-97.2335,48.9895],[-97.2331,48.9898],[-97.2317,48.9904],[-97.2301,48.9911],[-97.2293,48.9914],[-97.229,48.9916],[-97.2279,48.9921],[-97.2274,48.9925],[-97.227,48.9929],[-97.2266,48.9933],[-97.2265,48.9938],[-97.2267,48.9941],[-97.227,48.9945],[-97.2273,48.9947],[-97.2287,48.9949],[-97.2304,48.995],[-97.2317,48.9951],[-97.2324,48.9952],[-97.2335,48.9956],[-97.2338,48.9959],[-97.2341,48.9966],[-97.2341,48.997],[-97.234,48.9975],[-97.2337,48.9981],[-97.2332,48.9985],[-97.2323,48.999],[-97.2305,49.0],[-97.2303,49.0001],[-97.2295,49.0005],[-97.2175,49.0005],[-97.2161,49.0005],[-97.2078,49.0005],[-97.2069,49.0005],[-97.1955,49.0005],[-97.1939,49.0005],[-97.1739,49.0005],[-97.1724,49.0005],[-97.1514,49.0005],[-97.1502,49.0005],[-97.1294,49.0004],[-97.1277,49.0004],[-97.1073,49.0004],[-97.1061,49.0004],[-97.0853,49.0004],[-97.084,49.0004],[-97.0633,49.0004],[-97.062,49.0004],[-97.0412,49.0004],[-97.0401,49.0004],[-97.0192,49.0004],[-97.0183,49.0004],[-96.9971,49.0004],[-96.9961,49.0004],[-96.9751,49.0003],[-96.9738,49.0003],[-96.953,49.0003],[-96.9518,49.0003],[-96.931,49.0003],[-96.9299,49.0003],[-96.909,49.0003],[-96.9078,49.0003],[-96.8869,49.0003],[-96.8856,49.0003],[-96.8649,49.0003],[-96.864,49.0003],[-96.8429,49.0003],[-96.8415,49.0003],[-96.8208,49.0003],[-96.8197,49.0003],[-96.8023,49.0002],[-96.8005,49.0002],[-96.8003,49.0002],[-96.7988,49.0002],[-96.7787,49.0002],[-96.7768,49.0002],[-96.7567,49.0002],[-96.7547,49.0002],[-96.7348,49.0002],[-96.7327,49.0002],[-96.7127,49.0002],[-96.7107,49.0002],[-96.6905,49.0002],[-96.6886,49.0002],[-96.6695,49.0002],[-96.6665,49.0002],[-96.6482,49.0002],[-96.6445,49.0002],[-96.6243,49.0002],[-96.6225,49.0002],[-96.6021,49.0002],[-96.6004,49.0002],[-96.58,49.0002],[-96.5784,49.0002],[-96.558,49.0002],[-96.5563,49.0002],[-96.536,49.0002],[-96.5342,49.0002],[-96.5154,49.0002],[-96.5123,49.0002],[-96.4933,49.0002],[-96.49,49.0002],[-96.471,49.0001],[-96.4664,49.0001],[-96.4496,49.0001],[-96.4492,49.0001],[-96.4491,49.0001],[-96.446,49.0001],[-96.4273,49.0001],[-96.4224,49.0001],[-96.4054,49.0001]]],"type":"Polygon"},"id":"35","properties":{"Area":2862183702.23055,"CTYONLY_":3,"Code":"KITT","LASTMOD":"1999-12-31T23:59:59Z","Name":"Kittson","Perimiter":263017.48277},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&filter=CTYONLY_%3C%3D3","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&filter=CTYONLY_%3C%3D3","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":2,"numberReturned":2,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_text_like_no_match.json.txt b/msautotest/api/expected/ogcapi_cql2_text_like_no_match.json.txt new file mode 100644 index 0000000000..3b9c80b803 --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_text_like_no_match.json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 0 +OGC-NumberReturned: 0 + +{"features":[],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&filter=Name%20LIKE%20'rice'","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&filter=Name%20LIKE%20'rice'","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":0,"numberReturned":0,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_text_like_single_char.json.txt b/msautotest/api/expected/ogcapi_cql2_text_like_single_char.json.txt new file mode 100644 index 0000000000..f642038475 --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_text_like_single_char.json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 1 +OGC-NumberReturned: 1 + +{"features":[{"geometry":{"coordinates":[[[-93.5242,44.5436],[-93.5225,44.5436],[-93.504,44.5438],[-93.5018,44.5438],[-93.4835,44.5438],[-93.4817,44.5438],[-93.4734,44.5438],[-93.4632,44.5438],[-93.4609,44.5438],[-93.4429,44.5438],[-93.4408,44.5438],[-93.4326,44.5438],[-93.4226,44.5439],[-93.4206,44.5439],[-93.4024,44.5439],[-93.4003,44.5439],[-93.383,44.544],[-93.38,44.544],[-93.3627,44.5441],[-93.3596,44.5441],[-93.3556,44.5441],[-93.3424,44.5442],[-93.3395,44.5442],[-93.3221,44.544],[-93.3191,44.544],[-93.3128,44.544],[-93.3019,44.544],[-93.2988,44.544],[-93.2813,44.544],[-93.2814,44.5298],[-93.2815,44.5153],[-93.2815,44.501],[-93.2815,44.4865],[-93.2817,44.472],[-93.2618,44.4718],[-93.2415,44.4716],[-93.2213,44.4714],[-93.2008,44.4714],[-93.1808,44.4713],[-93.1605,44.4713],[-93.1408,44.4712],[-93.1206,44.4713],[-93.1002,44.4718],[-93.0799,44.4719],[-93.0597,44.4718],[-93.0393,44.4719],[-93.0394,44.4576],[-93.0396,44.4432],[-93.0397,44.4287],[-93.0399,44.4143],[-93.04,44.3999],[-93.0401,44.3855],[-93.0402,44.371],[-93.0403,44.3565],[-93.0403,44.3419],[-93.0405,44.3273],[-93.0405,44.3129],[-93.0405,44.2983],[-93.0406,44.2838],[-93.0407,44.2693],[-93.0409,44.2548],[-93.041,44.2402],[-93.0411,44.2257],[-93.0411,44.2113],[-93.0411,44.1968],[-93.0427,44.1968],[-93.0459,44.1968],[-93.0613,44.1967],[-93.0661,44.1967],[-93.0815,44.1967],[-93.0862,44.1967],[-93.1003,44.1967],[-93.1015,44.1967],[-93.1063,44.1967],[-93.1092,44.1967],[-93.1218,44.1967],[-93.1267,44.1967],[-93.1301,44.1967],[-93.1418,44.1967],[-93.1467,44.1967],[-93.1561,44.1966],[-93.1622,44.1966],[-93.1661,44.1966],[-93.1703,44.1966],[-93.1822,44.1966],[-93.1856,44.1966],[-93.1865,44.1966],[-93.2023,44.1966],[-93.2037,44.1966],[-93.2064,44.1966],[-93.2225,44.1966],[-93.2265,44.1966],[-93.2292,44.1966],[-93.2426,44.1966],[-93.2465,44.1966],[-93.255,44.1966],[-93.2629,44.1966],[-93.2664,44.1966],[-93.2767,44.1966],[-93.283,44.1966],[-93.2865,44.1965],[-93.2905,44.1965],[-93.3032,44.1965],[-93.3063,44.1965],[-93.3235,44.1965],[-93.3264,44.1965],[-93.3277,44.1965],[-93.3436,44.1965],[-93.3466,44.1965],[-93.3639,44.1965],[-93.3666,44.1965],[-93.3842,44.1965],[-93.3866,44.1965],[-93.4042,44.1965],[-93.4065,44.1965],[-93.4244,44.1964],[-93.4267,44.1964],[-93.4447,44.1964],[-93.4469,44.1964],[-93.4648,44.1963],[-93.467,44.1963],[-93.4852,44.1964],[-93.4872,44.1964],[-93.5053,44.1963],[-93.507,44.1963],[-93.5255,44.1962],[-93.5253,44.2107],[-93.5251,44.2251],[-93.5251,44.2388],[-93.5251,44.2533],[-93.5252,44.2685],[-93.5252,44.2829],[-93.5252,44.2975],[-93.5252,44.312],[-93.5249,44.3266],[-93.5249,44.3411],[-93.5245,44.3557],[-93.5245,44.3704],[-93.5246,44.3848],[-93.5245,44.3994],[-93.5245,44.4138],[-93.5245,44.4283],[-93.5245,44.4427],[-93.5245,44.4572],[-93.5244,44.4717],[-93.5245,44.4862],[-93.5244,44.5007],[-93.5243,44.5152],[-93.5244,44.5297],[-93.5242,44.5436]]],"type":"Polygon"},"id":"66","properties":{"Area":1335114621.00336,"CTYONLY_":66,"Code":"RICE","LASTMOD":"2010-10-17T00:00:00Z","Name":"Rice","Perimiter":154431.78788},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&filter=Name%20LIKE%20'Ri_e'","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&filter=Name%20LIKE%20'Ri_e'","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":1,"numberReturned":1,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_text_like_wildcard.json.txt b/msautotest/api/expected/ogcapi_cql2_text_like_wildcard.json.txt new file mode 100644 index 0000000000..c0a9fa829f --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_text_like_wildcard.json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 3 +OGC-NumberReturned: 3 + +{"features":[{"geometry":{"coordinates":[[[-95.7096,47.9355],[-95.7098,47.9211],[-95.7094,47.9065],[-95.7095,47.8919],[-95.7094,47.8776],[-95.7089,47.863],[-95.709,47.8486],[-95.7307,47.8487],[-95.7525,47.8485],[-95.7737,47.8484],[-95.7952,47.8483],[-95.8153,47.8484],[-95.8366,47.8482],[-95.8367,47.8335],[-95.8366,47.819],[-95.8366,47.8043],[-95.8365,47.79],[-95.8371,47.7755],[-95.8372,47.7609],[-95.8588,47.7609],[-95.8801,47.7608],[-95.9017,47.7609],[-95.9233,47.7607],[-95.9452,47.7606],[-95.9671,47.7605],[-95.9883,47.7605],[-96.0097,47.7605],[-96.0315,47.7605],[-96.053,47.7603],[-96.0743,47.7601],[-96.0957,47.76],[-96.1175,47.7602],[-96.1388,47.7598],[-96.159,47.7598],[-96.1806,47.7598],[-96.2022,47.7597],[-96.2238,47.7598],[-96.2453,47.7598],[-96.2668,47.7599],[-96.2884,47.7601],[-96.3097,47.7601],[-96.3313,47.7603],[-96.3516,47.7604],[-96.3519,47.7748],[-96.352,47.7893],[-96.3521,47.8038],[-96.3523,47.8184],[-96.3524,47.8329],[-96.3527,47.8473],[-96.3742,47.8474],[-96.3958,47.8475],[-96.4172,47.8475],[-96.4386,47.8476],[-96.4601,47.8475],[-96.482,47.8475],[-96.4821,47.862],[-96.4827,47.8768],[-96.4824,47.8913],[-96.4825,47.9054],[-96.4825,47.9055],[-96.4825,47.9202],[-96.4826,47.9347],[-96.4825,47.949],[-96.4823,47.9636],[-96.4603,47.9639],[-96.439,47.9636],[-96.4172,47.9637],[-96.3954,47.9636],[-96.3738,47.9636],[-96.3526,47.9634],[-96.3316,47.9634],[-96.31,47.9633],[-96.2883,47.963],[-96.2667,47.9629],[-96.2453,47.9629],[-96.2235,47.9629],[-96.2044,47.963],[-96.1826,47.9632],[-96.1606,47.9631],[-96.1389,47.9631],[-96.1173,47.9632],[-96.096,47.9638],[-96.0757,47.9637],[-96.054,47.9638],[-96.0324,47.964],[-96.0106,47.9641],[-95.9887,47.9642],[-95.9671,47.9646],[-95.9462,47.9646],[-95.925,47.9647],[-95.9031,47.9648],[-95.8814,47.9648],[-95.86,47.9649],[-95.8383,47.9648],[-95.8181,47.9647],[-95.7963,47.9647],[-95.7747,47.9646],[-95.7531,47.9645],[-95.7312,47.9644],[-95.7098,47.9644],[-95.7097,47.9499],[-95.7096,47.9355]]],"type":"Polygon"},"id":"63","properties":{"Area":1121769824.00964,"CTYONLY_":14,"Code":"REDL","LASTMOD":"2001-04-12T09:32:44Z","Name":"Red Lake","Perimiter":160699.14254},"type":"Feature"},{"geometry":{"coordinates":[[[-95.2485,44.8914],[-95.2398,44.8914],[-95.2313,44.8914],[-95.2279,44.8914],[-95.2202,44.8914],[-95.2074,44.8913],[-95.1993,44.8913],[-95.1867,44.8913],[-95.1792,44.8913],[-95.17,44.8913],[-95.1664,44.8914],[-95.1616,44.8914],[-95.1591,44.8914],[-95.1457,44.8914],[-95.1388,44.8915],[-95.1316,44.8915],[-95.1254,44.8915],[-95.1184,44.8915],[-95.105,44.8915],[-95.0975,44.8915],[-95.0845,44.8915],[-95.077,44.8915],[-95.064,44.8915],[-95.0575,44.8916],[-95.0566,44.8916],[-95.0437,44.8916],[-95.0365,44.8916],[-95.0235,44.8917],[-95.0162,44.8918],[-95.0032,44.8919],[-94.9958,44.8919],[-94.9827,44.8919],[-94.9756,44.892],[-94.9622,44.892],[-94.9552,44.8921],[-94.9413,44.8921],[-94.935,44.8922],[-94.921,44.8923],[-94.9144,44.8923],[-94.9007,44.8922],[-94.8971,44.8922],[-94.8941,44.8922],[-94.8802,44.8922],[-94.8756,44.8922],[-94.8742,44.8923],[-94.86,44.8922],[-94.8547,44.8922],[-94.8395,44.8922],[-94.8345,44.8922],[-94.8191,44.8922],[-94.814,44.8922],[-94.7989,44.8921],[-94.7935,44.8921],[-94.7865,44.8921],[-94.7787,44.8921],[-94.7731,44.8921],[-94.7675,44.8921],[-94.758,44.8921],[-94.7525,44.8921],[-94.7376,44.8921],[-94.7321,44.8921],[-94.7171,44.892],[-94.7118,44.8921],[-94.6966,44.8921],[-94.6916,44.892],[-94.6786,44.892],[-94.6761,44.892],[-94.6711,44.892],[-94.6557,44.892],[-94.6508,44.892],[-94.6354,44.892],[-94.6301,44.892],[-94.6049,44.892],[-94.6004,44.892],[-94.5942,44.892],[-94.5844,44.892],[-94.5802,44.892],[-94.5705,44.8921],[-94.564,44.8921],[-94.5594,44.8921],[-94.5434,44.8921],[-94.539,44.8921],[-94.5227,44.8922],[-94.5183,44.8922],[-94.5058,44.8923],[-94.5024,44.8923],[-94.4977,44.8923],[-94.498,44.8779],[-94.4979,44.8634],[-94.498,44.8488],[-94.4978,44.8343],[-94.4978,44.8198],[-94.4978,44.805],[-94.4977,44.7905],[-94.4979,44.7758],[-94.498,44.7611],[-94.4979,44.7465],[-94.498,44.7319],[-94.4978,44.7174],[-94.5182,44.7171],[-94.5385,44.7171],[-94.5589,44.717],[-94.5791,44.7169],[-94.5996,44.7168],[-94.6295,44.7167],[-94.6294,44.7022],[-94.6294,44.6876],[-94.6292,44.6731],[-94.6292,44.6585],[-94.6292,44.6438],[-94.6291,44.6293],[-94.6292,44.6149],[-94.6292,44.6004],[-94.6292,44.586],[-94.6292,44.5715],[-94.6292,44.5569],[-94.6292,44.5424],[-94.6242,44.5424],[-94.6242,44.5286],[-94.6241,44.5141],[-94.6241,44.4996],[-94.624,44.4851],[-94.6242,44.4706],[-94.6242,44.4561],[-94.6443,44.4561],[-94.6646,44.4562],[-94.6849,44.4563],[-94.7051,44.4563],[-94.7254,44.4564],[-94.7448,44.4564],[-94.7651,44.4562],[-94.7805,44.4561],[-94.7806,44.4562],[-94.7809,44.4566],[-94.7809,44.4567],[-94.7812,44.457],[-94.7812,44.4572],[-94.7815,44.4575],[-94.782,44.4576],[-94.7835,44.4573],[-94.7846,44.457],[-94.7851,44.457],[-94.7851,44.457],[-94.7852,44.4569],[-94.7868,44.4567],[-94.7889,44.4562],[-94.7895,44.4562],[-94.7901,44.4563],[-94.7909,44.4566],[-94.7914,44.4568],[-94.7927,44.4577],[-94.7937,44.4585],[-94.7942,44.459],[-94.7941,44.4593],[-94.7941,44.4595],[-94.7939,44.4599],[-94.7934,44.4604],[-94.7933,44.4607],[-94.7934,44.4608],[-94.7938,44.4611],[-94.7955,44.4616],[-94.7967,44.4621],[-94.7985,44.4631],[-94.7999,44.4642],[-94.8003,44.4645],[-94.8014,44.465],[-94.8022,44.4652],[-94.8033,44.4654],[-94.8048,44.4653],[-94.8055,44.4655],[-94.8055,44.4655],[-94.8058,44.4657],[-94.8061,44.4659],[-94.8063,44.4661],[-94.8065,44.4664],[-94.8065,44.4667],[-94.8061,44.4669],[-94.8058,44.467],[-94.8055,44.467],[-94.8051,44.467],[-94.8044,44.4668],[-94.8037,44.4665],[-94.803,44.4663],[-94.8019,44.4664],[-94.8012,44.4666],[-94.8001,44.467],[-94.7999,44.4671],[-94.799,44.4677],[-94.7984,44.4682],[-94.7984,44.4683],[-94.7983,44.4683],[-94.7982,44.4686],[-94.7982,44.4692],[-94.7984,44.4695],[-94.7987,44.4697],[-94.799,44.4696],[-94.7993,44.4694],[-94.7994,44.4692],[-94.7994,44.4687],[-94.7997,44.4683],[-94.8003,44.4679],[-94.8013,44.4678],[-94.8022,44.4678],[-94.8042,44.4682],[-94.8056,44.4687],[-94.8058,44.4688],[-94.8082,44.4699],[-94.809,44.4706],[-94.8094,44.471],[-94.8098,44.4712],[-94.8101,44.4715],[-94.8104,44.4721],[-94.8105,44.4722],[-94.8106,44.4724],[-94.8108,44.4727],[-94.8109,44.4731],[-94.811,44.4731],[-94.8111,44.4734],[-94.8112,44.4738],[-94.8112,44.4741],[-94.8107,44.4747],[-94.8104,44.4751],[-94.8104,44.4757],[-94.8104,44.4757],[-94.8105,44.4762],[-94.8106,44.4762],[-94.8106,44.4765],[-94.8106,44.4774],[-94.8107,44.4778],[-94.8108,44.4789],[-94.8109,44.4792],[-94.8109,44.4797],[-94.8111,44.4807],[-94.8113,44.481],[-94.8113,44.4811],[-94.8115,44.4814],[-94.812,44.4817],[-94.8127,44.4817],[-94.8133,44.4814],[-94.8138,44.481],[-94.8141,44.4806],[-94.8156,44.4795],[-94.8164,44.4792],[-94.817,44.4791],[-94.8173,44.4792],[-94.8176,44.4795],[-94.8179,44.4798],[-94.8181,44.4803],[-94.8181,44.4813],[-94.818,44.4816],[-94.8175,44.4819],[-94.8166,44.4822],[-94.8156,44.4825],[-94.8151,44.4828],[-94.8148,44.4831],[-94.8147,44.4835],[-94.8147,44.4839],[-94.8148,44.4841],[-94.8153,44.4845],[-94.8156,44.4846],[-94.8163,44.4845],[-94.8167,44.4841],[-94.8173,44.4836],[-94.8177,44.4833],[-94.8182,44.4832],[-94.8186,44.4832],[-94.8194,44.4834],[-94.8206,44.484],[-94.8233,44.4851],[-94.8233,44.4851],[-94.8236,44.4853],[-94.824,44.4854],[-94.8247,44.4853],[-94.825,44.4851],[-94.825,44.4851],[-94.825,44.4851],[-94.8257,44.4846],[-94.8257,44.4846],[-94.8259,44.4844],[-94.826,44.4843],[-94.8265,44.4838],[-94.8265,44.4836],[-94.8266,44.4836],[-94.8267,44.4833],[-94.8269,44.4831],[-94.8271,44.483],[-94.8276,44.483],[-94.8281,44.4832],[-94.8285,44.4836],[-94.8287,44.484],[-94.8288,44.4844],[-94.8289,44.4845],[-94.829,44.4848],[-94.829,44.4851],[-94.829,44.4851],[-94.8291,44.4858],[-94.8292,44.4862],[-94.8295,44.4866],[-94.8302,44.4873],[-94.831,44.488],[-94.8318,44.4888],[-94.8323,44.489],[-94.8323,44.4891],[-94.8329,44.4894],[-94.8334,44.4896],[-94.8349,44.4898],[-94.8361,44.4897],[-94.8366,44.4895],[-94.837,44.4893],[-94.8378,44.4888],[-94.838,44.4887],[-94.8384,44.4887],[-94.8387,44.4888],[-94.8388,44.4889],[-94.839,44.4892],[-94.8389,44.4902],[-94.839,44.4906],[-94.8394,44.4912],[-94.8402,44.4918],[-94.8414,44.4922],[-94.8434,44.4926],[-94.8461,44.4925],[-94.8461,44.4925],[-94.8463,44.4925],[-94.8491,44.4919],[-94.8496,44.4917],[-94.85,44.4912],[-94.85,44.491],[-94.8499,44.4909],[-94.8498,44.4905],[-94.8501,44.4902],[-94.8506,44.49],[-94.8511,44.4899],[-94.8513,44.4898],[-94.853,44.4898],[-94.8538,44.49],[-94.8545,44.4904],[-94.8552,44.4916],[-94.8553,44.4922],[-94.8552,44.4926],[-94.8548,44.4929],[-94.8533,44.4934],[-94.8525,44.4939],[-94.8521,44.4942],[-94.8518,44.4947],[-94.8518,44.4952],[-94.8524,44.4956],[-94.8533,44.4957],[-94.8538,44.4957],[-94.8546,44.4955],[-94.8562,44.495],[-94.8562,44.495],[-94.8574,44.4949],[-94.8585,44.4949],[-94.8625,44.4952],[-94.8633,44.4954],[-94.864,44.4957],[-94.8641,44.4959],[-94.8642,44.4962],[-94.8644,44.4963],[-94.8645,44.497],[-94.8648,44.4975],[-94.865,44.4979],[-94.8653,44.498],[-94.8655,44.4981],[-94.8655,44.4981],[-94.8658,44.4982],[-94.8659,44.4983],[-94.8673,44.4987],[-94.8679,44.499],[-94.8682,44.4991],[-94.8686,44.4993],[-94.8691,44.4995],[-94.8691,44.4996],[-94.8698,44.5],[-94.8697,44.5004],[-94.8699,44.5007],[-94.8699,44.5008],[-94.8701,44.501],[-94.8702,44.5011],[-94.871,44.5009],[-94.8712,44.5007],[-94.8717,44.5],[-94.8717,44.4997],[-94.8716,44.4997],[-94.8716,44.4996],[-94.8717,44.4993],[-94.8719,44.4991],[-94.8721,44.499],[-94.8728,44.4991],[-94.8731,44.4991],[-94.8736,44.4995],[-94.8736,44.4996],[-94.8736,44.4996],[-94.8736,44.4996],[-94.8736,44.4996],[-94.8738,44.5],[-94.8737,44.5019],[-94.8736,44.5021],[-94.8735,44.5025],[-94.8732,44.504],[-94.8732,44.5056],[-94.8739,44.5061],[-94.8747,44.5066],[-94.8752,44.5068],[-94.8758,44.5069],[-94.8767,44.5068],[-94.8788,44.5062],[-94.8791,44.5063],[-94.8796,44.5065],[-94.8796,44.5068],[-94.8795,44.507],[-94.8791,44.5072],[-94.8778,44.5082],[-94.8775,44.5086],[-94.8775,44.509],[-94.8783,44.5095],[-94.8797,44.51],[-94.8801,44.5103],[-94.88,44.5105],[-94.8797,44.5107],[-94.8784,44.5107],[-94.8781,44.5108],[-94.878,44.511],[-94.8778,44.5112],[-94.8778,44.5114],[-94.8778,44.5123],[-94.8779,44.5124],[-94.8779,44.5127],[-94.878,44.5132],[-94.8782,44.5136],[-94.8783,44.5138],[-94.8784,44.5141],[-94.8784,44.5141],[-94.8784,44.5141],[-94.8785,44.515],[-94.8786,44.515],[-94.8786,44.5152],[-94.8796,44.5161],[-94.8805,44.5168],[-94.8815,44.5173],[-94.8822,44.5174],[-94.884,44.5173],[-94.8846,44.517],[-94.8848,44.5169],[-94.8852,44.5166],[-94.8856,44.5163],[-94.8864,44.5155],[-94.887,44.5149],[-94.8871,44.5144],[-94.8872,44.5142],[-94.8872,44.5142],[-94.8873,44.5135],[-94.888,44.5129],[-94.8889,44.5125],[-94.8895,44.5123],[-94.8903,44.5123],[-94.8914,44.5125],[-94.8918,44.5127],[-94.8922,44.5131],[-94.8922,44.5136],[-94.8918,44.5142],[-94.8918,44.5142],[-94.8909,44.5152],[-94.8908,44.5155],[-94.8907,44.5162],[-94.8908,44.517],[-94.8912,44.5177],[-94.8919,44.5186],[-94.8929,44.5192],[-94.8937,44.5197],[-94.8947,44.5201],[-94.8969,44.5207],[-94.8977,44.5208],[-94.898,44.5208],[-94.8976,44.5203],[-94.8973,44.5196],[-94.8975,44.5193],[-94.8977,44.5191],[-94.8981,44.519],[-94.8983,44.519],[-94.8985,44.519],[-94.8987,44.5191],[-94.899,44.5194],[-94.8993,44.5197],[-94.8996,44.5201],[-94.8999,44.5203],[-94.9001,44.5205],[-94.9003,44.5207],[-94.9004,44.5207],[-94.9015,44.5208],[-94.9023,44.5206],[-94.9026,44.5205],[-94.9027,44.5202],[-94.9026,44.5195],[-94.9022,44.5184],[-94.9019,44.5181],[-94.9015,44.5179],[-94.9015,44.5177],[-94.902,44.5174],[-94.9036,44.5171],[-94.9044,44.5169],[-94.9058,44.517],[-94.9059,44.517],[-94.9073,44.5171],[-94.9091,44.5169],[-94.9116,44.5163],[-94.914,44.5158],[-94.9157,44.5158],[-94.9164,44.516],[-94.917,44.5166],[-94.9176,44.517],[-94.9178,44.517],[-94.9185,44.5169],[-94.9191,44.5166],[-94.9195,44.5165],[-94.9201,44.5165],[-94.9237,44.5176],[-94.9239,44.5178],[-94.9238,44.518],[-94.9237,44.5182],[-94.9231,44.5183],[-94.922,44.5185],[-94.9215,44.5188],[-94.9214,44.519],[-94.9214,44.5195],[-94.9216,44.5198],[-94.9222,44.5203],[-94.923,44.5206],[-94.9243,44.5211],[-94.9252,44.5216],[-94.9255,44.5219],[-94.9263,44.5225],[-94.9263,44.5225],[-94.9266,44.5227],[-94.9283,44.5237],[-94.9289,44.5243],[-94.9296,44.5246],[-94.9303,44.5246],[-94.9339,44.5242],[-94.934,44.5242],[-94.9342,44.5239],[-94.9344,44.523],[-94.9346,44.5228],[-94.935,44.5228],[-94.9355,44.5228],[-94.9375,44.5235],[-94.9379,44.5238],[-94.9383,44.5241],[-94.9383,44.5244],[-94.9374,44.5247],[-94.9365,44.5253],[-94.9363,44.5256],[-94.9352,44.5268],[-94.935,44.5271],[-94.935,44.5276],[-94.9353,44.528],[-94.9363,44.5289],[-94.9363,44.5289],[-94.9371,44.5297],[-94.9377,44.5304],[-94.9381,44.5306],[-94.9384,44.5306],[-94.939,44.5305],[-94.9391,44.5303],[-94.9392,44.5297],[-94.9391,44.5294],[-94.9389,44.5292],[-94.9388,44.529],[-94.9388,44.529],[-94.9388,44.5289],[-94.9383,44.5282],[-94.9383,44.5279],[-94.9382,44.5279],[-94.9382,44.5273],[-94.9384,44.527],[-94.9389,44.5266],[-94.9397,44.5264],[-94.9425,44.5258],[-94.9437,44.5258],[-94.9442,44.5259],[-94.9444,44.5262],[-94.9447,44.5262],[-94.9449,44.5263],[-94.945,44.5265],[-94.945,44.5269],[-94.9449,44.527],[-94.9448,44.5274],[-94.9447,44.5277],[-94.9447,44.5285],[-94.945,44.5289],[-94.9451,44.529],[-94.9451,44.529],[-94.9455,44.5293],[-94.9463,44.5294],[-94.9465,44.5294],[-94.9471,44.5294],[-94.9482,44.529],[-94.9482,44.529],[-94.9487,44.5288],[-94.95,44.5286],[-94.9511,44.5286],[-94.9526,44.5287],[-94.9533,44.5289],[-94.9535,44.529],[-94.9535,44.529],[-94.9537,44.5291],[-94.9542,44.5295],[-94.9545,44.5298],[-94.9548,44.53],[-94.9557,44.5312],[-94.9567,44.5321],[-94.9571,44.5324],[-94.958,44.5325],[-94.961,44.5326],[-94.963,44.5328],[-94.9646,44.5331],[-94.9669,44.5331],[-94.9669,44.5331],[-94.9669,44.5331],[-94.967,44.5331],[-94.9678,44.5332],[-94.9686,44.5335],[-94.969,44.5338],[-94.9692,44.5341],[-94.9692,44.5344],[-94.9691,44.5348],[-94.9689,44.535],[-94.9682,44.5356],[-94.9678,44.5361],[-94.9673,44.5369],[-94.9671,44.5376],[-94.9671,44.5386],[-94.9674,44.5391],[-94.9677,44.5394],[-94.9685,44.54],[-94.9693,44.5403],[-94.97,44.5403],[-94.9705,44.5402],[-94.9707,44.54],[-94.9708,44.5397],[-94.9704,44.539],[-94.9704,44.5385],[-94.9707,44.5382],[-94.9712,44.5379],[-94.9714,44.5379],[-94.9717,44.5379],[-94.9724,44.5381],[-94.9727,44.5381],[-94.973,44.5381],[-94.9732,44.5378],[-94.9734,44.5369],[-94.9737,44.5367],[-94.9737,44.5361],[-94.9745,44.5355],[-94.9757,44.5352],[-94.977,44.5354],[-94.9782,44.5359],[-94.979,44.5366],[-94.9791,44.5371],[-94.9789,44.5374],[-94.9785,44.5375],[-94.9776,44.5372],[-94.9767,44.5367],[-94.9757,44.5367],[-94.9751,44.5369],[-94.9752,44.5371],[-94.9752,44.5373],[-94.9753,44.5373],[-94.9754,44.5379],[-94.9755,44.5382],[-94.9756,44.539],[-94.9757,44.5392],[-94.9757,44.5397],[-94.9754,44.5403],[-94.9754,44.5405],[-94.9756,44.5406],[-94.9764,44.5405],[-94.9783,44.54],[-94.9793,44.5398],[-94.9822,44.5397],[-94.9834,44.5396],[-94.9838,44.5398],[-94.984,44.5399],[-94.9839,44.5402],[-94.9824,44.5414],[-94.9824,44.5415],[-94.9824,44.5415],[-94.9822,44.5416],[-94.982,44.5419],[-94.982,44.5424],[-94.9822,44.5425],[-94.9831,44.5425],[-94.9841,44.5422],[-94.9843,44.5421],[-94.9848,44.542],[-94.9856,44.5418],[-94.9862,44.5418],[-94.9871,44.5421],[-94.988,44.5426],[-94.9882,44.5428],[-94.9885,44.5433],[-94.9886,44.5436],[-94.9888,44.5442],[-94.9888,44.5445],[-94.9889,44.5445],[-94.9889,44.5452],[-94.9888,44.5455],[-94.9887,44.5455],[-94.9888,44.5459],[-94.9896,44.546],[-94.99,44.5459],[-94.9908,44.5454],[-94.9918,44.545],[-94.9919,44.545],[-94.9923,44.545],[-94.9936,44.545],[-94.9945,44.5452],[-94.9945,44.5452],[-94.995,44.5453],[-94.9958,44.5455],[-94.9963,44.5459],[-94.997,44.5462],[-94.9982,44.5469],[-94.9991,44.5472],[-94.9991,44.5473],[-95.0002,44.5476],[-95.0006,44.5476],[-95.0011,44.5474],[-95.0014,44.5472],[-95.0014,44.5469],[-95.0013,44.5465],[-95.0006,44.546],[-95.0002,44.546],[-94.9998,44.5458],[-94.9997,44.5457],[-94.9994,44.5454],[-94.9994,44.5449],[-94.9994,44.5447],[-94.9997,44.5441],[-95.0002,44.5436],[-95.0007,44.5435],[-95.0016,44.5428],[-95.0026,44.5427],[-95.0029,44.543],[-95.0037,44.5443],[-95.0037,44.5445],[-95.0035,44.5452],[-95.0037,44.5456],[-95.0048,44.5466],[-95.0057,44.5472],[-95.0061,44.5473],[-95.0065,44.5471],[-95.0065,44.5465],[-95.0061,44.5455],[-95.0062,44.545],[-95.0066,44.5442],[-95.0075,44.5441],[-95.0093,44.5441],[-95.0105,44.544],[-95.0123,44.5433],[-95.0144,44.5426],[-95.015,44.5426],[-95.015,44.5426],[-95.0152,44.5426],[-95.0158,44.5427],[-95.0162,44.5429],[-95.017,44.5435],[-95.0174,44.5439],[-95.0174,44.5443],[-95.0172,44.5451],[-95.0172,44.5454],[-95.0171,44.5455],[-95.0168,44.5463],[-95.0166,44.5466],[-95.0151,44.5476],[-95.015,44.5477],[-95.015,44.5477],[-95.0142,44.548],[-95.0121,44.5485],[-95.0118,44.5487],[-95.0117,44.5489],[-95.0117,44.5492],[-95.0119,44.5496],[-95.0124,44.5501],[-95.014,44.5507],[-95.015,44.5509],[-95.015,44.5509],[-95.0154,44.551],[-95.0162,44.5511],[-95.0173,44.551],[-95.0179,44.5508],[-95.0184,44.5505],[-95.0186,44.5502],[-95.0198,44.5493],[-95.0204,44.5491],[-95.0216,44.5487],[-95.0219,44.5484],[-95.0219,44.5483],[-95.022,44.5483],[-95.022,44.5478],[-95.0219,44.5476],[-95.0218,44.5475],[-95.0216,44.5473],[-95.0212,44.5467],[-95.0212,44.5462],[-95.0219,44.5457],[-95.0225,44.5455],[-95.0228,44.5454],[-95.0232,44.5454],[-95.0239,44.5456],[-95.0247,44.5459],[-95.0251,44.5462],[-95.0251,44.5464],[-95.0252,44.547],[-95.025,44.5475],[-95.0244,44.5485],[-95.0242,44.5489],[-95.0243,44.5498],[-95.0244,44.5502],[-95.0246,44.5505],[-95.0248,44.5509],[-95.0248,44.5519],[-95.0252,44.5524],[-95.0261,44.5532],[-95.0264,44.5534],[-95.0269,44.5534],[-95.0277,44.5532],[-95.0278,44.5531],[-95.0279,44.5511],[-95.0279,44.5511],[-95.0281,44.5507],[-95.0285,44.5505],[-95.0289,44.5503],[-95.0293,44.5503],[-95.0299,44.5505],[-95.0303,44.5508],[-95.0304,44.551],[-95.0305,44.5513],[-95.0306,44.5517],[-95.0306,44.5521],[-95.0308,44.5524],[-95.0308,44.5525],[-95.0311,44.5528],[-95.0315,44.5531],[-95.0322,44.5534],[-95.0331,44.5537],[-95.0336,44.5538],[-95.0339,44.5541],[-95.0339,44.5545],[-95.0335,44.5548],[-95.0328,44.5554],[-95.0325,44.5556],[-95.0324,44.556],[-95.0324,44.556],[-95.0325,44.5564],[-95.0327,44.5566],[-95.033,44.5569],[-95.0337,44.5571],[-95.0343,44.5571],[-95.0353,44.5569],[-95.0362,44.5568],[-95.0372,44.5568],[-95.0383,44.5571],[-95.0394,44.5574],[-95.0404,44.5579],[-95.0415,44.5581],[-95.0419,44.5581],[-95.0422,44.5581],[-95.0426,44.5578],[-95.0427,44.5566],[-95.0429,44.5565],[-95.0435,44.5565],[-95.0466,44.5571],[-95.0479,44.5574],[-95.0501,44.5583],[-95.0507,44.5587],[-95.0508,44.5589],[-95.0509,44.5593],[-95.0505,44.5606],[-95.0506,44.5607],[-95.0506,44.5608],[-95.0509,44.5613],[-95.0511,44.5617],[-95.0519,44.5622],[-95.0526,44.5625],[-95.0531,44.5625],[-95.0535,44.5623],[-95.0552,44.5616],[-95.0555,44.5616],[-95.0559,44.5616],[-95.0574,44.562],[-95.0587,44.5623],[-95.0592,44.5627],[-95.0593,44.5629],[-95.0593,44.5642],[-95.0592,44.5644],[-95.059,44.5649],[-95.058,44.5662],[-95.0579,44.5665],[-95.0579,44.5668],[-95.0583,44.5673],[-95.0589,44.5677],[-95.0595,44.568],[-95.0606,44.5679],[-95.0614,44.5676],[-95.0624,44.5676],[-95.0639,44.5679],[-95.0644,44.5682],[-95.0644,44.569],[-95.0645,44.5693],[-95.0647,44.5697],[-95.0651,44.5702],[-95.0657,44.5707],[-95.0657,44.5707],[-95.0662,44.5711],[-95.0676,44.5719],[-95.0684,44.5721],[-95.0709,44.5726],[-95.0742,44.5737],[-95.0755,44.5739],[-95.0758,44.5739],[-95.0763,44.5738],[-95.077,44.5735],[-95.0778,44.5728],[-95.078,44.5723],[-95.0781,44.5722],[-95.0783,44.5721],[-95.0783,44.5719],[-95.0784,44.5716],[-95.0786,44.5711],[-95.0788,44.5707],[-95.079,44.5706],[-95.079,44.5706],[-95.0794,44.5704],[-95.0808,44.5702],[-95.0811,44.57],[-95.0818,44.5693],[-95.0825,44.5692],[-95.0833,44.5691],[-95.0839,44.5694],[-95.0846,44.5698],[-95.0848,44.57],[-95.0852,44.5705],[-95.0852,44.5706],[-95.0852,44.5706],[-95.0857,44.5712],[-95.0861,44.5715],[-95.087,44.5718],[-95.088,44.5716],[-95.089,44.5711],[-95.0896,44.5712],[-95.0902,44.5713],[-95.0921,44.572],[-95.0927,44.572],[-95.0955,44.5716],[-95.0961,44.5716],[-95.0961,44.5716],[-95.0966,44.5716],[-95.0976,44.5718],[-95.098,44.5718],[-95.0987,44.5721],[-95.0991,44.5724],[-95.0991,44.5727],[-95.0991,44.5734],[-95.0988,44.5743],[-95.0984,44.5747],[-95.0972,44.5759],[-95.0967,44.5763],[-95.0961,44.5765],[-95.0961,44.5765],[-95.0957,44.5766],[-95.0942,44.5768],[-95.0929,44.577],[-95.0907,44.5774],[-95.0898,44.5777],[-95.0894,44.578],[-95.0892,44.578],[-95.089,44.5782],[-95.0888,44.5784],[-95.0886,44.5786],[-95.0886,44.579],[-95.0889,44.5793],[-95.0893,44.5795],[-95.0905,44.5797],[-95.0937,44.58],[-95.095,44.58],[-95.0958,44.5798],[-95.0961,44.5796],[-95.0961,44.5796],[-95.0965,44.5794],[-95.0969,44.579],[-95.0977,44.5785],[-95.0993,44.5782],[-95.0999,44.5782],[-95.1002,44.5783],[-95.1005,44.5786],[-95.1007,44.5789],[-95.1008,44.5793],[-95.1012,44.5798],[-95.1012,44.5799],[-95.1014,44.5801],[-95.1014,44.5803],[-95.1015,44.5803],[-95.1015,44.5805],[-95.1018,44.581],[-95.1018,44.5816],[-95.1017,44.5818],[-95.1016,44.5829],[-95.1017,44.5831],[-95.1017,44.5834],[-95.1019,44.5839],[-95.1021,44.5842],[-95.1021,44.5844],[-95.1023,44.5847],[-95.1024,44.5848],[-95.1024,44.5849],[-95.1025,44.5849],[-95.1026,44.5852],[-95.1026,44.5852],[-95.1031,44.5861],[-95.1038,44.5867],[-95.1043,44.5873],[-95.1046,44.5875],[-95.105,44.5877],[-95.1057,44.5877],[-95.1063,44.5875],[-95.1068,44.5869],[-95.1076,44.5865],[-95.1081,44.5863],[-95.1086,44.5863],[-95.1089,44.5864],[-95.1109,44.5879],[-95.1116,44.5883],[-95.1133,44.5888],[-95.1152,44.5892],[-95.1153,44.5894],[-95.1159,44.5899],[-95.1164,44.5907],[-95.1164,44.5907],[-95.1166,44.591],[-95.117,44.5921],[-95.1171,44.5923],[-95.1171,44.5925],[-95.1173,44.5929],[-95.1174,44.5934],[-95.1176,44.5936],[-95.1176,44.5937],[-95.1178,44.594],[-95.1182,44.5946],[-95.1183,44.5949],[-95.1187,44.5951],[-95.1191,44.5953],[-95.1205,44.5958],[-95.1252,44.5975],[-95.1261,44.5977],[-95.1268,44.5977],[-95.127,44.5977],[-95.1274,44.5975],[-95.1278,44.5969],[-95.128,44.5965],[-95.1285,44.5957],[-95.1292,44.5953],[-95.1296,44.5952],[-95.1305,44.5953],[-95.1314,44.5956],[-95.1325,44.5963],[-95.1327,44.5963],[-95.1327,44.5966],[-95.1329,44.5968],[-95.1331,44.5972],[-95.1332,44.5979],[-95.1331,44.5994],[-95.1332,44.5995],[-95.1333,44.6003],[-95.1335,44.6005],[-95.1336,44.6007],[-95.134,44.6014],[-95.1344,44.6016],[-95.1356,44.6021],[-95.1371,44.6023],[-95.1371,44.6023],[-95.1374,44.6024],[-95.1379,44.6026],[-95.1392,44.6038],[-95.1405,44.6044],[-95.1441,44.606],[-95.1451,44.6065],[-95.1455,44.6065],[-95.1456,44.6067],[-95.1463,44.6072],[-95.1472,44.6081],[-95.1476,44.6089],[-95.1476,44.6091],[-95.1477,44.6092],[-95.1478,44.6094],[-95.1479,44.6096],[-95.1479,44.6097],[-95.1481,44.6098],[-95.1483,44.6103],[-95.1485,44.6112],[-95.1486,44.6114],[-95.1486,44.6115],[-95.1489,44.6119],[-95.1497,44.6125],[-95.1506,44.6132],[-95.1508,44.6135],[-95.1507,44.6141],[-95.1507,44.6141],[-95.1506,44.6147],[-95.1507,44.6151],[-95.151,44.6153],[-95.1513,44.6154],[-95.1536,44.6153],[-95.1545,44.6153],[-95.1563,44.6156],[-95.1571,44.616],[-95.1575,44.6164],[-95.1577,44.6165],[-95.1592,44.6174],[-95.1593,44.6178],[-95.1593,44.6185],[-95.1594,44.6187],[-95.16,44.6192],[-95.1613,44.6198],[-95.1622,44.6201],[-95.1636,44.6202],[-95.1642,44.6202],[-95.1648,44.6202],[-95.1653,44.6203],[-95.1655,44.6208],[-95.1657,44.6212],[-95.1661,44.6214],[-95.1671,44.6217],[-95.168,44.6216],[-95.1687,44.6214],[-95.1702,44.6204],[-95.1717,44.6198],[-95.1742,44.6191],[-95.1751,44.6191],[-95.1759,44.6192],[-95.1772,44.6195],[-95.1778,44.6198],[-95.1778,44.6198],[-95.1779,44.6199],[-95.1787,44.6202],[-95.1789,44.6204],[-95.179,44.6207],[-95.1788,44.6212],[-95.1784,44.6216],[-95.178,44.6221],[-95.178,44.6225],[-95.1784,44.6228],[-95.1794,44.6233],[-95.1807,44.6236],[-95.1831,44.6238],[-95.1857,44.6239],[-95.1858,44.624],[-95.1863,44.6243],[-95.1867,44.6246],[-95.1868,44.625],[-95.1869,44.6253],[-95.187,44.6254],[-95.1872,44.626],[-95.1874,44.6274],[-95.1877,44.6278],[-95.188,44.6281],[-95.1885,44.6282],[-95.1907,44.6284],[-95.1916,44.6286],[-95.192,44.6288],[-95.192,44.6288],[-95.1925,44.6291],[-95.193,44.6294],[-95.1934,44.6298],[-95.1936,44.6303],[-95.1936,44.6306],[-95.1937,44.631],[-95.1941,44.6317],[-95.1941,44.6321],[-95.1944,44.6323],[-95.1945,44.6325],[-95.196,44.634],[-95.1968,44.6347],[-95.1971,44.635],[-95.198,44.6357],[-95.1982,44.6359],[-95.1987,44.6363],[-95.2002,44.637],[-95.2019,44.6375],[-95.2022,44.6378],[-95.2024,44.6381],[-95.2028,44.6385],[-95.2037,44.6391],[-95.2051,44.64],[-95.2062,44.6406],[-95.2073,44.641],[-95.2083,44.6413],[-95.2101,44.6415],[-95.2107,44.6417],[-95.2111,44.6421],[-95.2115,44.6427],[-95.2118,44.6431],[-95.2118,44.6434],[-95.2118,44.6434],[-95.212,44.6443],[-95.2123,44.6451],[-95.2124,44.6452],[-95.2124,44.6454],[-95.2127,44.6459],[-95.2133,44.6465],[-95.2136,44.6466],[-95.2144,44.6465],[-95.2148,44.6463],[-95.2149,44.6457],[-95.215,44.6452],[-95.2153,44.6449],[-95.2155,44.6448],[-95.2159,44.6449],[-95.2172,44.6453],[-95.218,44.6457],[-95.2184,44.646],[-95.2184,44.646],[-95.2189,44.6463],[-95.2192,44.6467],[-95.2206,44.6487],[-95.2212,44.6493],[-95.2214,44.6496],[-95.2228,44.6514],[-95.2231,44.6516],[-95.2242,44.6524],[-95.225,44.6526],[-95.2257,44.6525],[-95.2258,44.6525],[-95.2259,44.6524],[-95.2262,44.6523],[-95.2265,44.652],[-95.2271,44.6515],[-95.2272,44.6515],[-95.2276,44.6515],[-95.2278,44.6516],[-95.2292,44.6528],[-95.2302,44.6535],[-95.2304,44.6538],[-95.2328,44.6554],[-95.2333,44.6558],[-95.2336,44.6562],[-95.2336,44.6563],[-95.2337,44.6565],[-95.234,44.6569],[-95.2341,44.6576],[-95.2343,44.6578],[-95.2344,44.658],[-95.2344,44.658],[-95.2366,44.6597],[-95.2368,44.66],[-95.2372,44.6603],[-95.2381,44.6604],[-95.2385,44.6604],[-95.2385,44.6604],[-95.2386,44.6604],[-95.2395,44.6604],[-95.24,44.6607],[-95.2402,44.6609],[-95.2404,44.6614],[-95.2405,44.6623],[-95.2405,44.6637],[-95.2404,44.6639],[-95.2404,44.6645],[-95.2407,44.6648],[-95.2425,44.6659],[-95.2436,44.6667],[-95.2437,44.6668],[-95.2437,44.6668],[-95.2444,44.6671],[-95.2444,44.6671],[-95.2449,44.6671],[-95.2464,44.6674],[-95.2479,44.6674],[-95.2487,44.6671],[-95.2494,44.6668],[-95.2502,44.6661],[-95.2508,44.6652],[-95.2508,44.665],[-95.251,44.6648],[-95.2514,44.6645],[-95.2517,44.6644],[-95.2523,44.6644],[-95.2538,44.6646],[-95.2545,44.6644],[-95.2548,44.6641],[-95.2551,44.6636],[-95.2554,44.663],[-95.2555,44.6626],[-95.2556,44.6623],[-95.2561,44.6618],[-95.2567,44.6616],[-95.2578,44.6615],[-95.2585,44.6614],[-95.2585,44.6614],[-95.2598,44.6614],[-95.2605,44.6613],[-95.261,44.6611],[-95.2622,44.6609],[-95.2628,44.6607],[-95.2634,44.6604],[-95.2636,44.6601],[-95.2639,44.6601],[-95.2643,44.6599],[-95.2658,44.6596],[-95.2678,44.6593],[-95.2694,44.6593],[-95.2694,44.6594],[-95.2698,44.6594],[-95.2716,44.6598],[-95.2735,44.66],[-95.2758,44.6601],[-95.277,44.6603],[-95.2779,44.6604],[-95.278,44.6603],[-95.2792,44.6603],[-95.2798,44.6603],[-95.2821,44.6604],[-95.2834,44.6606],[-95.2841,44.6608],[-95.2842,44.6609],[-95.2855,44.661],[-95.2875,44.661],[-95.2889,44.6611],[-95.2903,44.6614],[-95.2911,44.6613],[-95.2926,44.6609],[-95.2929,44.6609],[-95.2935,44.6609],[-95.2939,44.6611],[-95.2942,44.6612],[-95.2943,44.6617],[-95.2939,44.663],[-95.2939,44.6638],[-95.2941,44.6643],[-95.2943,44.6646],[-95.2948,44.6649],[-95.2963,44.6654],[-95.2966,44.6654],[-95.2971,44.6656],[-95.2977,44.6658],[-95.2978,44.6658],[-95.2986,44.6664],[-95.2991,44.6665],[-95.2993,44.6669],[-95.2995,44.667],[-95.2995,44.667],[-95.3002,44.6673],[-95.3011,44.6678],[-95.3031,44.6685],[-95.3038,44.6689],[-95.3043,44.6697],[-95.3056,44.6707],[-95.3059,44.671],[-95.3061,44.6714],[-95.3062,44.6716],[-95.3063,44.6717],[-95.3063,44.6719],[-95.3067,44.6723],[-95.3069,44.6724],[-95.3074,44.6728],[-95.3078,44.6731],[-95.3089,44.6736],[-95.3105,44.6743],[-95.311,44.6747],[-95.3116,44.6752],[-95.3122,44.6758],[-95.3123,44.676],[-95.3125,44.6764],[-95.3129,44.6771],[-95.313,44.6777],[-95.3128,44.6786],[-95.3128,44.6789],[-95.3127,44.679],[-95.3126,44.6792],[-95.3124,44.6798],[-95.3123,44.6806],[-95.3124,44.6809],[-95.3124,44.6809],[-95.3125,44.681],[-95.3127,44.6814],[-95.3129,44.6817],[-95.3129,44.6818],[-95.3131,44.6825],[-95.313,44.6827],[-95.3129,44.6831],[-95.3124,44.6843],[-95.3122,44.6846],[-95.3113,44.6858],[-95.3109,44.6866],[-95.311,44.687],[-95.311,44.6873],[-95.3112,44.6878],[-95.3116,44.6883],[-95.3128,44.6894],[-95.3129,44.6895],[-95.313,44.6896],[-95.3132,44.6904],[-95.3133,44.6905],[-95.3133,44.6906],[-95.3135,44.691],[-95.3137,44.6913],[-95.3138,44.6914],[-95.3142,44.6919],[-95.3149,44.6925],[-95.3158,44.6928],[-95.318,44.6932],[-95.3195,44.6934],[-95.3199,44.6934],[-95.3203,44.6934],[-95.3211,44.6933],[-95.3237,44.6928],[-95.3249,44.6924],[-95.3256,44.6921],[-95.3261,44.692],[-95.3271,44.692],[-95.3282,44.6924],[-95.329,44.6927],[-95.3309,44.6934],[-95.3323,44.6937],[-95.3332,44.694],[-95.3347,44.6947],[-95.3355,44.6949],[-95.3364,44.6951],[-95.3378,44.695],[-95.3386,44.695],[-95.3401,44.6953],[-95.3403,44.6953],[-95.3403,44.6953],[-95.3405,44.6954],[-95.3437,44.6962],[-95.3445,44.6963],[-95.3457,44.6963],[-95.3466,44.6961],[-95.3474,44.6958],[-95.3481,44.6958],[-95.3487,44.696],[-95.3492,44.6964],[-95.35,44.697],[-95.3506,44.6973],[-95.3509,44.6973],[-95.3515,44.6973],[-95.3521,44.697],[-95.353,44.6964],[-95.3536,44.6962],[-95.3541,44.6963],[-95.3546,44.6964],[-95.3554,44.6968],[-95.3572,44.6974],[-95.3591,44.698],[-95.36,44.6984],[-95.3601,44.6985],[-95.3603,44.6986],[-95.3603,44.6986],[-95.3606,44.6989],[-95.3609,44.699],[-95.3614,44.6994],[-95.3618,44.6999],[-95.3618,44.7001],[-95.3621,44.7004],[-95.3621,44.7005],[-95.3629,44.7012],[-95.3634,44.7015],[-95.3641,44.7016],[-95.3641,44.7016],[-95.3642,44.7017],[-95.3647,44.7016],[-95.3651,44.7016],[-95.3659,44.7013],[-95.3666,44.7009],[-95.3673,44.7002],[-95.3678,44.6999],[-95.3682,44.6999],[-95.3688,44.7001],[-95.3696,44.7005],[-95.37,44.7008],[-95.3709,44.7011],[-95.3734,44.7016],[-95.3735,44.7017],[-95.3752,44.7022],[-95.3761,44.7025],[-95.377,44.7029],[-95.3775,44.7031],[-95.3786,44.7033],[-95.3786,44.7034],[-95.379,44.7036],[-95.3807,44.7047],[-95.3807,44.7047],[-95.382,44.7054],[-95.3825,44.7057],[-95.3825,44.706],[-95.3813,44.707],[-95.3807,44.7076],[-95.3804,44.7079],[-95.3799,44.7087],[-95.3799,44.71],[-95.3798,44.7104],[-95.3798,44.7111],[-95.3799,44.7113],[-95.3802,44.7115],[-95.3805,44.7116],[-95.3807,44.7116],[-95.3812,44.7116],[-95.3817,44.7113],[-95.3818,44.7111],[-95.3818,44.7111],[-95.3819,44.7109],[-95.3822,44.7106],[-95.383,44.7101],[-95.3845,44.7097],[-95.3856,44.7097],[-95.3864,44.7099],[-95.3885,44.7103],[-95.3899,44.7104],[-95.3917,44.7115],[-95.392,44.7118],[-95.392,44.7124],[-95.3919,44.7127],[-95.3919,44.7133],[-95.3919,44.7133],[-95.3919,44.7134],[-95.3922,44.7137],[-95.3931,44.7143],[-95.3938,44.7145],[-95.3946,44.7145],[-95.3947,44.7144],[-95.3956,44.7137],[-95.396,44.7135],[-95.3964,44.7133],[-95.3969,44.7134],[-95.3975,44.7135],[-95.3981,44.7138],[-95.3987,44.7142],[-95.399,44.7146],[-95.399,44.715],[-95.3987,44.7152],[-95.398,44.7155],[-95.3978,44.7156],[-95.3977,44.7159],[-95.3978,44.7162],[-95.3978,44.7163],[-95.3979,44.7164],[-95.3982,44.7166],[-95.3982,44.7168],[-95.3984,44.7169],[-95.3987,44.717],[-95.3995,44.7171],[-95.3998,44.7173],[-95.3998,44.7174],[-95.3999,44.7175],[-95.3999,44.7177],[-95.3995,44.7181],[-95.3992,44.7186],[-95.3992,44.719],[-95.3995,44.7191],[-95.3999,44.7192],[-95.4012,44.7194],[-95.4014,44.7194],[-95.4018,44.7196],[-95.4019,44.7197],[-95.4018,44.72],[-95.4015,44.7203],[-95.4012,44.7204],[-95.3987,44.7214],[-95.3982,44.7217],[-95.3974,44.7223],[-95.3971,44.7229],[-95.3972,44.7237],[-95.3975,44.7241],[-95.3983,44.7247],[-95.3994,44.7254],[-95.4012,44.7261],[-95.4027,44.7268],[-95.4035,44.7272],[-95.4049,44.7281],[-95.4057,44.7288],[-95.4064,44.7294],[-95.4073,44.7301],[-95.4075,44.7303],[-95.4077,44.7304],[-95.4082,44.7308],[-95.4085,44.731],[-95.4087,44.731],[-95.4102,44.7312],[-95.4112,44.7315],[-95.4117,44.7319],[-95.4121,44.7322],[-95.4125,44.7328],[-95.4131,44.7333],[-95.4147,44.7339],[-95.4151,44.7342],[-95.4163,44.7347],[-95.4169,44.7349],[-95.4177,44.7348],[-95.4185,44.7345],[-95.419,44.7342],[-95.4192,44.7339],[-95.4193,44.7335],[-95.419,44.7326],[-95.419,44.7319],[-95.4194,44.7316],[-95.4198,44.7315],[-95.4202,44.7315],[-95.421,44.7316],[-95.4212,44.7317],[-95.4214,44.7317],[-95.4217,44.7319],[-95.4221,44.732],[-95.4227,44.7325],[-95.4229,44.7328],[-95.423,44.733],[-95.4232,44.7335],[-95.4233,44.7337],[-95.4234,44.734],[-95.4235,44.7341],[-95.4236,44.7344],[-95.4237,44.7361],[-95.424,44.7363],[-95.4244,44.7367],[-95.4252,44.7371],[-95.4269,44.7385],[-95.4273,44.7388],[-95.4277,44.7391],[-95.4284,44.7395],[-95.4289,44.7395],[-95.4289,44.7396],[-95.4294,44.7397],[-95.431,44.7396],[-95.4321,44.7395],[-95.4328,44.7395],[-95.4332,44.7397],[-95.4343,44.7404],[-95.4374,44.7415],[-95.4381,44.742],[-95.4391,44.7427],[-95.4397,44.7431],[-95.4409,44.7435],[-95.4422,44.7438],[-95.4424,44.7438],[-95.4435,44.7437],[-95.4477,44.7426],[-95.4488,44.7422],[-95.4497,44.742],[-95.4516,44.7419],[-95.4535,44.7415],[-95.4558,44.7411],[-95.4577,44.7408],[-95.4584,44.741],[-95.4591,44.7413],[-95.4593,44.7415],[-95.4596,44.7418],[-95.4602,44.7429],[-95.4604,44.7432],[-95.4611,44.7436],[-95.462,44.744],[-95.4621,44.744],[-95.4629,44.7444],[-95.4634,44.7446],[-95.4638,44.7449],[-95.464,44.7452],[-95.464,44.7453],[-95.464,44.7462],[-95.4633,44.7476],[-95.4633,44.7483],[-95.4635,44.7486],[-95.4635,44.7488],[-95.4644,44.7489],[-95.4648,44.749],[-95.4665,44.7489],[-95.4679,44.749],[-95.4684,44.7491],[-95.4689,44.7493],[-95.4694,44.7496],[-95.4696,44.75],[-95.4698,44.7503],[-95.4698,44.7505],[-95.47,44.7505],[-95.47,44.7507],[-95.4706,44.7515],[-95.4709,44.7519],[-95.471,44.752],[-95.4714,44.7526],[-95.4716,44.7529],[-95.4723,44.7538],[-95.4729,44.7543],[-95.4739,44.7549],[-95.4762,44.756],[-95.4773,44.7564],[-95.4777,44.7564],[-95.4782,44.7563],[-95.4792,44.7559],[-95.4797,44.7555],[-95.4808,44.7546],[-95.4823,44.7535],[-95.4826,44.7533],[-95.4827,44.7532],[-95.483,44.7601],[-95.4829,44.7746],[-95.4829,44.789],[-95.483,44.8036],[-95.4831,44.8181],[-95.4832,44.8326],[-95.4832,44.8471],[-95.4831,44.8617],[-95.4832,44.8762],[-95.4833,44.8908],[-95.4729,44.8908],[-95.4642,44.8908],[-95.4533,44.8908],[-95.4526,44.8908],[-95.4432,44.8909],[-95.4322,44.8909],[-95.4226,44.891],[-95.4117,44.891],[-95.4091,44.891],[-95.4025,44.891],[-95.3913,44.8911],[-95.3895,44.8911],[-95.3819,44.8911],[-95.3705,44.8912],[-95.3611,44.8912],[-95.3502,44.8913],[-95.3464,44.8913],[-95.3422,44.8913],[-95.3382,44.8913],[-95.3301,44.8913],[-95.3216,44.8913],[-95.3099,44.8913],[-95.3012,44.8913],[-95.2895,44.8914],[-95.2853,44.8914],[-95.2809,44.8914],[-95.2752,44.8914],[-95.2692,44.8914],[-95.2603,44.8914],[-95.254,44.8914],[-95.2485,44.8914]]],"type":"Polygon"},"id":"65","properties":{"Area":2556556344.22304,"CTYONLY_":58,"Code":"RENV","LASTMOD":"2010-10-17T00:00:00Z","Name":"Renville","Perimiter":264508.74665},"type":"Feature"},{"geometry":{"coordinates":[[[-93.5242,44.5436],[-93.5225,44.5436],[-93.504,44.5438],[-93.5018,44.5438],[-93.4835,44.5438],[-93.4817,44.5438],[-93.4734,44.5438],[-93.4632,44.5438],[-93.4609,44.5438],[-93.4429,44.5438],[-93.4408,44.5438],[-93.4326,44.5438],[-93.4226,44.5439],[-93.4206,44.5439],[-93.4024,44.5439],[-93.4003,44.5439],[-93.383,44.544],[-93.38,44.544],[-93.3627,44.5441],[-93.3596,44.5441],[-93.3556,44.5441],[-93.3424,44.5442],[-93.3395,44.5442],[-93.3221,44.544],[-93.3191,44.544],[-93.3128,44.544],[-93.3019,44.544],[-93.2988,44.544],[-93.2813,44.544],[-93.2814,44.5298],[-93.2815,44.5153],[-93.2815,44.501],[-93.2815,44.4865],[-93.2817,44.472],[-93.2618,44.4718],[-93.2415,44.4716],[-93.2213,44.4714],[-93.2008,44.4714],[-93.1808,44.4713],[-93.1605,44.4713],[-93.1408,44.4712],[-93.1206,44.4713],[-93.1002,44.4718],[-93.0799,44.4719],[-93.0597,44.4718],[-93.0393,44.4719],[-93.0394,44.4576],[-93.0396,44.4432],[-93.0397,44.4287],[-93.0399,44.4143],[-93.04,44.3999],[-93.0401,44.3855],[-93.0402,44.371],[-93.0403,44.3565],[-93.0403,44.3419],[-93.0405,44.3273],[-93.0405,44.3129],[-93.0405,44.2983],[-93.0406,44.2838],[-93.0407,44.2693],[-93.0409,44.2548],[-93.041,44.2402],[-93.0411,44.2257],[-93.0411,44.2113],[-93.0411,44.1968],[-93.0427,44.1968],[-93.0459,44.1968],[-93.0613,44.1967],[-93.0661,44.1967],[-93.0815,44.1967],[-93.0862,44.1967],[-93.1003,44.1967],[-93.1015,44.1967],[-93.1063,44.1967],[-93.1092,44.1967],[-93.1218,44.1967],[-93.1267,44.1967],[-93.1301,44.1967],[-93.1418,44.1967],[-93.1467,44.1967],[-93.1561,44.1966],[-93.1622,44.1966],[-93.1661,44.1966],[-93.1703,44.1966],[-93.1822,44.1966],[-93.1856,44.1966],[-93.1865,44.1966],[-93.2023,44.1966],[-93.2037,44.1966],[-93.2064,44.1966],[-93.2225,44.1966],[-93.2265,44.1966],[-93.2292,44.1966],[-93.2426,44.1966],[-93.2465,44.1966],[-93.255,44.1966],[-93.2629,44.1966],[-93.2664,44.1966],[-93.2767,44.1966],[-93.283,44.1966],[-93.2865,44.1965],[-93.2905,44.1965],[-93.3032,44.1965],[-93.3063,44.1965],[-93.3235,44.1965],[-93.3264,44.1965],[-93.3277,44.1965],[-93.3436,44.1965],[-93.3466,44.1965],[-93.3639,44.1965],[-93.3666,44.1965],[-93.3842,44.1965],[-93.3866,44.1965],[-93.4042,44.1965],[-93.4065,44.1965],[-93.4244,44.1964],[-93.4267,44.1964],[-93.4447,44.1964],[-93.4469,44.1964],[-93.4648,44.1963],[-93.467,44.1963],[-93.4852,44.1964],[-93.4872,44.1964],[-93.5053,44.1963],[-93.507,44.1963],[-93.5255,44.1962],[-93.5253,44.2107],[-93.5251,44.2251],[-93.5251,44.2388],[-93.5251,44.2533],[-93.5252,44.2685],[-93.5252,44.2829],[-93.5252,44.2975],[-93.5252,44.312],[-93.5249,44.3266],[-93.5249,44.3411],[-93.5245,44.3557],[-93.5245,44.3704],[-93.5246,44.3848],[-93.5245,44.3994],[-93.5245,44.4138],[-93.5245,44.4283],[-93.5245,44.4427],[-93.5245,44.4572],[-93.5244,44.4717],[-93.5245,44.4862],[-93.5244,44.5007],[-93.5243,44.5152],[-93.5244,44.5297],[-93.5242,44.5436]]],"type":"Polygon"},"id":"66","properties":{"Area":1335114621.00336,"CTYONLY_":66,"Code":"RICE","LASTMOD":"2010-10-17T00:00:00Z","Name":"Rice","Perimiter":154431.78788},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&filter=Name%20LIKE%20'R%25e'","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&filter=Name%20LIKE%20'R%25e'","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":3,"numberReturned":3,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_text_lt.json.txt b/msautotest/api/expected/ogcapi_cql2_text_lt.json.txt new file mode 100644 index 0000000000..d9de6820fd --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_text_lt.json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 1 +OGC-NumberReturned: 1 + +{"features":[{"geometry":{"coordinates":[[[-95.3231,48.999],[-95.3109,48.999],[-95.2889,48.9989],[-95.2852,48.9989],[-95.2669,48.9989],[-95.245,48.9989],[-95.2232,48.9989],[-95.2014,48.9989],[-95.1792,48.9989],[-95.1574,48.9989],[-95.1531,48.9989],[-95.1531,49.0031],[-95.1532,49.0179],[-95.1532,49.0325],[-95.1532,49.047],[-95.1532,49.0619],[-95.1532,49.0765],[-95.1532,49.0911],[-95.1532,49.1057],[-95.1532,49.1205],[-95.1532,49.1354],[-95.1532,49.1499],[-95.1532,49.1642],[-95.1532,49.1788],[-95.1532,49.1807],[-95.1532,49.1931],[-95.1532,49.1966],[-95.1532,49.2077],[-95.1533,49.2131],[-95.1533,49.2219],[-95.1533,49.2308],[-95.1533,49.2365],[-95.1533,49.2472],[-95.1533,49.2512],[-95.1533,49.2655],[-95.1533,49.2697],[-95.1533,49.2802],[-95.1533,49.2882],[-95.1533,49.2945],[-95.1533,49.3072],[-95.1533,49.309],[-95.1533,49.3234],[-95.1533,49.3237],[-95.1533,49.3381],[-95.1533,49.3476],[-95.1533,49.3525],[-95.1533,49.3636],[-95.1533,49.367],[-95.1533,49.3705],[-95.1533,49.3776],[-95.1533,49.3813],[-95.1533,49.3845],[-95.1503,49.383],[-95.1499,49.3813],[-95.1498,49.3807],[-95.1467,49.3802],[-95.145,49.3784],[-95.1418,49.3784],[-95.1397,49.3762],[-95.1367,49.3751],[-95.1324,49.3736],[-95.1287,49.3705],[-95.1171,49.367],[-95.1159,49.3666],[-95.1145,49.3666],[-95.1098,49.3664],[-95.1031,49.3652],[-95.1031,49.3636],[-95.0926,49.3617],[-95.0897,49.3612],[-95.0707,49.3564],[-95.0582,49.3533],[-95.0495,49.3532],[-95.0479,49.3533],[-95.0262,49.3554],[-95.0141,49.3565],[-95.0047,49.3612],[-94.993,49.367],[-94.9889,49.369],[-94.9818,49.3684],[-94.9742,49.3678],[-94.9597,49.3699],[-94.9573,49.3702],[-94.952,49.3688],[-94.948,49.367],[-94.9376,49.3625],[-94.9152,49.3529],[-94.9143,49.3524],[-94.909,49.3502],[-94.9065,49.3484],[-94.8933,49.3414],[-94.8865,49.3378],[-94.8782,49.3334],[-94.8712,49.3308],[-94.854,49.3244],[-94.8492,49.3244],[-94.8363,49.3243],[-94.8311,49.3236],[-94.8271,49.323],[-94.8162,49.3214],[-94.8243,49.309],[-94.8243,49.3088],[-94.8255,49.2944],[-94.8255,49.2943],[-94.8204,49.28],[-94.8152,49.2653],[-94.8103,49.2515],[-94.8059,49.2388],[-94.8051,49.2367],[-94.8001,49.2224],[-94.7973,49.2144],[-94.7975,49.2079],[-94.7979,49.1979],[-94.7965,49.1936],[-94.7918,49.1792],[-94.7871,49.1646],[-94.7833,49.153],[-94.7823,49.15],[-94.7776,49.1357],[-94.7727,49.1206],[-94.7727,49.1206],[-94.7611,49.1096],[-94.7571,49.1058],[-94.7496,49.0988],[-94.7474,49.0918],[-94.7429,49.0773],[-94.7394,49.0657],[-94.7385,49.063],[-94.7344,49.0497],[-94.7299,49.0351],[-94.7254,49.0205],[-94.7207,49.0052],[-94.7184,48.9979],[-94.7162,48.9907],[-94.7117,48.9761],[-94.7072,48.9615],[-94.7027,48.9468],[-94.6982,48.9322],[-94.6968,48.9276],[-94.6844,48.8875],[-94.6834,48.8842],[-94.6842,48.8724],[-94.6855,48.8719],[-94.6923,48.8691],[-94.6902,48.8636],[-94.6914,48.8591],[-94.693,48.8535],[-94.6881,48.8447],[-94.6855,48.8401],[-94.6963,48.836],[-94.6975,48.8355],[-94.702,48.8319],[-94.7025,48.8302],[-94.7042,48.8243],[-94.6991,48.8159],[-94.6962,48.8111],[-94.6951,48.8092],[-94.6958,48.8012],[-94.6959,48.7997],[-94.6944,48.7895],[-94.6934,48.7864],[-94.6909,48.7781],[-94.687,48.7752],[-94.6776,48.772],[-94.6768,48.7717],[-94.6746,48.7705],[-94.6671,48.7662],[-94.6603,48.7605],[-94.6557,48.7581],[-94.6525,48.7565],[-94.652,48.7562],[-94.6453,48.7491],[-94.6453,48.7441],[-94.6443,48.7434],[-94.6414,48.7413],[-94.631,48.7392],[-94.6301,48.739],[-94.6191,48.7373],[-94.6106,48.7318],[-94.6084,48.731],[-94.6028,48.7289],[-94.6011,48.7283],[-94.5962,48.7248],[-94.5913,48.7197],[-94.5876,48.7176],[-94.5867,48.7175],[-94.5685,48.7156],[-94.5622,48.7159],[-94.5558,48.7163],[-94.549,48.7148],[-94.5487,48.7146],[-94.5457,48.7124],[-94.5396,48.7036],[-94.539,48.7028],[-94.5329,48.7013],[-94.5247,48.7016],[-94.5178,48.7008],[-94.5173,48.7008],[-94.5093,48.7006],[-94.5066,48.6999],[-94.4996,48.698],[-94.4958,48.698],[-94.4863,48.698],[-94.4739,48.6969],[-94.4706,48.6966],[-94.4631,48.6953],[-94.4568,48.6933],[-94.4523,48.6925],[-94.4517,48.6925],[-94.4465,48.693],[-94.4388,48.6949],[-94.4319,48.6998],[-94.4299,48.7012],[-94.4299,48.6998],[-94.43,48.6852],[-94.4301,48.6708],[-94.43,48.6564],[-94.4297,48.642],[-94.4294,48.6276],[-94.4292,48.6133],[-94.4289,48.5988],[-94.4289,48.5844],[-94.4291,48.5698],[-94.4295,48.5554],[-94.43,48.5409],[-94.4303,48.5264],[-94.4303,48.512],[-94.4299,48.4977],[-94.4296,48.4832],[-94.4296,48.4688],[-94.4293,48.4543],[-94.4292,48.4399],[-94.4293,48.4254],[-94.4294,48.411],[-94.4293,48.3964],[-94.4289,48.3821],[-94.4288,48.3675],[-94.4471,48.3675],[-94.4505,48.3675],[-94.4688,48.3675],[-94.4722,48.3674],[-94.4906,48.3674],[-94.4924,48.3674],[-94.4941,48.3674],[-94.5118,48.3675],[-94.5157,48.3674],[-94.5335,48.3674],[-94.5378,48.3674],[-94.5536,48.3674],[-94.5593,48.3674],[-94.5754,48.3674],[-94.5812,48.3674],[-94.5971,48.3675],[-94.6029,48.3674],[-94.6188,48.3673],[-94.6245,48.3673],[-94.6405,48.3673],[-94.6465,48.3673],[-94.6505,48.3673],[-94.6622,48.3673],[-94.6679,48.3673],[-94.6694,48.3672],[-94.683,48.3671],[-94.6898,48.3671],[-94.7099,48.3669],[-94.7117,48.3668],[-94.7315,48.3669],[-94.7329,48.3669],[-94.7533,48.3669],[-94.7549,48.3669],[-94.7748,48.3669],[-94.7765,48.3669],[-94.7967,48.3669],[-94.7983,48.3669],[-94.8183,48.3669],[-94.8199,48.3669],[-94.8399,48.3669],[-94.8416,48.3669],[-94.8616,48.3667],[-94.8632,48.3667],[-94.8833,48.3667],[-94.8849,48.3666],[-94.9049,48.3666],[-94.9065,48.3666],[-94.9264,48.3667],[-94.9283,48.3667],[-94.9469,48.3666],[-94.95,48.3666],[-94.9684,48.3667],[-94.9716,48.3667],[-94.9901,48.3667],[-94.9932,48.3667],[-95.0119,48.3665],[-95.0153,48.3665],[-95.0337,48.3665],[-95.0369,48.3665],[-95.0555,48.3665],[-95.0586,48.3665],[-95.0773,48.3664],[-95.0801,48.3664],[-95.099,48.3663],[-95.1008,48.3663],[-95.1018,48.3663],[-95.1207,48.3663],[-95.1236,48.3663],[-95.1315,48.3662],[-95.1424,48.3662],[-95.1454,48.3662],[-95.164,48.3661],[-95.1669,48.3661],[-95.1861,48.3661],[-95.1887,48.3661],[-95.1983,48.3661],[-95.2066,48.3661],[-95.2106,48.3661],[-95.211,48.3797],[-95.211,48.3808],[-95.2111,48.3941],[-95.2111,48.3952],[-95.2112,48.4087],[-95.2112,48.4096],[-95.2113,48.4232],[-95.2113,48.4242],[-95.2113,48.4255],[-95.2113,48.4376],[-95.2113,48.4387],[-95.2113,48.4522],[-95.2112,48.4529],[-95.211,48.4666],[-95.211,48.4673],[-95.2111,48.4816],[-95.2112,48.4962],[-95.2111,48.5101],[-95.2111,48.5109],[-95.2115,48.5244],[-95.2115,48.5252],[-95.2119,48.54],[-95.2324,48.5399],[-95.2339,48.5399],[-95.2537,48.5398],[-95.2554,48.5398],[-95.2756,48.54],[-95.2773,48.54],[-95.2975,48.5401],[-95.2992,48.5402],[-95.3194,48.54],[-95.321,48.54],[-95.3412,48.5402],[-95.3425,48.5402],[-95.3424,48.5548],[-95.3423,48.5691],[-95.3423,48.5836],[-95.3426,48.5979],[-95.3424,48.6127],[-95.3426,48.6271],[-95.3425,48.6415],[-95.3424,48.6561],[-95.3423,48.6705],[-95.3424,48.6849],[-95.3425,48.6995],[-95.3425,48.7131],[-95.3302,48.713],[-95.3205,48.713],[-95.3084,48.713],[-95.3051,48.713],[-95.299,48.713],[-95.2866,48.713],[-95.2767,48.713],[-95.2656,48.713],[-95.2645,48.713],[-95.255,48.713],[-95.2427,48.713],[-95.2331,48.713],[-95.2206,48.713],[-95.2112,48.713],[-95.1991,48.713],[-95.1917,48.713],[-95.1773,48.713],[-95.1697,48.7129],[-95.1554,48.7129],[-95.1477,48.7129],[-95.1333,48.713],[-95.1297,48.713],[-95.1259,48.7129],[-95.1119,48.7129],[-95.1104,48.7129],[-95.1046,48.7129],[-95.0898,48.713],[-95.0899,48.7277],[-95.0901,48.7421],[-95.0901,48.7566],[-95.0903,48.7711],[-95.0903,48.7855],[-95.0903,48.8],[-95.0909,48.8147],[-95.0908,48.8291],[-95.0907,48.8436],[-95.0908,48.858],[-95.0908,48.8724],[-95.0911,48.8869],[-95.0912,48.9014],[-95.0914,48.916],[-95.0914,48.9208],[-95.0919,48.9207],[-95.0927,48.9204],[-95.0944,48.9193],[-95.0946,48.9191],[-95.0961,48.9181],[-95.097,48.9176],[-95.0971,48.9172],[-95.0975,48.9164],[-95.098,48.916],[-95.0981,48.9159],[-95.1008,48.9142],[-95.102,48.9132],[-95.1032,48.9127],[-95.1042,48.9121],[-95.1056,48.9113],[-95.108,48.9099],[-95.1096,48.9089],[-95.1107,48.9082],[-95.1126,48.9073],[-95.113,48.9072],[-95.1132,48.9071],[-95.1137,48.9069],[-95.1141,48.9064],[-95.114,48.9061],[-95.1144,48.9052],[-95.1151,48.9046],[-95.1163,48.9037],[-95.1182,48.9029],[-95.1204,48.9019],[-95.1205,48.9017],[-95.121,48.9016],[-95.1214,48.9013],[-95.1228,48.9006],[-95.1233,48.9004],[-95.1239,48.9001],[-95.1252,48.8998],[-95.1312,48.8975],[-95.1322,48.8973],[-95.1337,48.8969],[-95.1343,48.8963],[-95.1348,48.8963],[-95.1351,48.8963],[-95.1355,48.8959],[-95.1381,48.8949],[-95.1404,48.8943],[-95.1436,48.8937],[-95.1438,48.8934],[-95.1459,48.8929],[-95.1469,48.8927],[-95.1483,48.8923],[-95.1508,48.8922],[-95.1528,48.8921],[-95.1555,48.892],[-95.1564,48.8919],[-95.1579,48.8919],[-95.1602,48.892],[-95.1618,48.892],[-95.1641,48.8917],[-95.1648,48.8913],[-95.1674,48.8907],[-95.1701,48.8902],[-95.173,48.8897],[-95.1764,48.8893],[-95.1791,48.889],[-95.1797,48.889],[-95.1819,48.8888],[-95.1851,48.8882],[-95.1863,48.8877],[-95.1877,48.8874],[-95.1889,48.8873],[-95.1901,48.887],[-95.1913,48.8868],[-95.1919,48.8866],[-95.1924,48.8865],[-95.1956,48.8862],[-95.1986,48.8855],[-95.2005,48.8856],[-95.2009,48.8855],[-95.2024,48.8852],[-95.2059,48.8848],[-95.2085,48.8846],[-95.2112,48.8848],[-95.2115,48.8847],[-95.2117,48.8847],[-95.2122,48.8842],[-95.2144,48.8843],[-95.2151,48.884],[-95.2159,48.8839],[-95.217,48.8835],[-95.2188,48.8835],[-95.2193,48.8832],[-95.22,48.8831],[-95.2207,48.8831],[-95.2208,48.8831],[-95.2212,48.883],[-95.2252,48.8819],[-95.2265,48.8816],[-95.2287,48.8815],[-95.231,48.8814],[-95.2335,48.8814],[-95.2356,48.8815],[-95.2381,48.8817],[-95.2391,48.8819],[-95.2407,48.8821],[-95.2423,48.8821],[-95.2429,48.8822],[-95.2429,48.8822],[-95.2439,48.8823],[-95.2458,48.8829],[-95.2472,48.8835],[-95.248,48.8836],[-95.2485,48.8832],[-95.2496,48.8834],[-95.2502,48.8835],[-95.2507,48.8836],[-95.2517,48.8839],[-95.2548,48.8845],[-95.256,48.885],[-95.257,48.8858],[-95.2585,48.8867],[-95.2585,48.8867],[-95.2627,48.8877],[-95.2635,48.888],[-95.2639,48.8883],[-95.2646,48.8885],[-95.265,48.8886],[-95.2654,48.8888],[-95.2666,48.8894],[-95.2674,48.89],[-95.2677,48.8903],[-95.268,48.8905],[-95.2713,48.8915],[-95.2724,48.8921],[-95.2745,48.8931],[-95.2751,48.8938],[-95.2753,48.8943],[-95.2748,48.8951],[-95.2749,48.8956],[-95.2755,48.8959],[-95.2759,48.8962],[-95.2763,48.8963],[-95.2765,48.8962],[-95.277,48.8958],[-95.2773,48.8957],[-95.2782,48.8956],[-95.279,48.8957],[-95.2796,48.8962],[-95.2803,48.8965],[-95.2813,48.8967],[-95.2839,48.8975],[-95.2853,48.8977],[-95.2861,48.8976],[-95.2865,48.8975],[-95.287,48.8976],[-95.2872,48.8977],[-95.2879,48.8979],[-95.2882,48.8981],[-95.289,48.8994],[-95.2896,48.9],[-95.2901,48.9003],[-95.2911,48.9006],[-95.2911,48.9008],[-95.2906,48.9011],[-95.2907,48.9014],[-95.2908,48.9016],[-95.2909,48.9017],[-95.2914,48.9019],[-95.2927,48.9019],[-95.2935,48.902],[-95.2937,48.9023],[-95.2941,48.9027],[-95.2949,48.9028],[-95.2967,48.9027],[-95.2976,48.9026],[-95.298,48.9027],[-95.2983,48.9028],[-95.2993,48.9035],[-95.3005,48.904],[-95.3002,48.9045],[-95.3001,48.9046],[-95.3001,48.9047],[-95.3,48.9047],[-95.3,48.9047],[-95.2999,48.9048],[-95.2999,48.9048],[-95.2999,48.9048],[-95.2997,48.905],[-95.2996,48.9051],[-95.2994,48.9053],[-95.2992,48.9055],[-95.2991,48.9057],[-95.2989,48.906],[-95.2988,48.906],[-95.2986,48.9063],[-95.2985,48.9064],[-95.2985,48.9065],[-95.2983,48.9068],[-95.2982,48.9068],[-95.2981,48.907],[-95.298,48.9071],[-95.298,48.9071],[-95.298,48.9071],[-95.2979,48.9071],[-95.2979,48.9072],[-95.2979,48.9072],[-95.2978,48.9072],[-95.2978,48.9072],[-95.2978,48.9073],[-95.2977,48.9073],[-95.2976,48.9074],[-95.2973,48.9077],[-95.2973,48.908],[-95.2973,48.9081],[-95.2978,48.9083],[-95.2999,48.9086],[-95.3017,48.9093],[-95.3027,48.91],[-95.3038,48.9114],[-95.3043,48.9119],[-95.3059,48.9127],[-95.3061,48.9128],[-95.3064,48.9129],[-95.3074,48.9135],[-95.3078,48.9141],[-95.3085,48.9146],[-95.3092,48.9149],[-95.3093,48.9149],[-95.3102,48.9155],[-95.3109,48.9163],[-95.3115,48.9172],[-95.3119,48.9178],[-95.3126,48.919],[-95.3132,48.9198],[-95.3141,48.921],[-95.315,48.9222],[-95.3168,48.9245],[-95.3195,48.9285],[-95.3208,48.9305],[-95.3209,48.9307],[-95.3222,48.9327],[-95.3228,48.9344],[-95.3223,48.9355],[-95.3225,48.9358],[-95.3229,48.9373],[-95.3231,48.9389],[-95.3228,48.9403],[-95.3225,48.9409],[-95.3219,48.9412],[-95.3189,48.9419],[-95.3181,48.9421],[-95.3168,48.9431],[-95.3154,48.9448],[-95.3148,48.9452],[-95.3141,48.9457],[-95.3131,48.946],[-95.3114,48.9461],[-95.3102,48.9463],[-95.3095,48.9463],[-95.3088,48.9464],[-95.3086,48.9465],[-95.3086,48.9469],[-95.3085,48.947],[-95.3078,48.9466],[-95.3074,48.9465],[-95.3071,48.9466],[-95.3071,48.9469],[-95.3079,48.9474],[-95.3092,48.9477],[-95.3096,48.9478],[-95.3103,48.948],[-95.3104,48.9484],[-95.3103,48.9485],[-95.31,48.9485],[-95.3099,48.9484],[-95.3096,48.9482],[-95.3094,48.9481],[-95.3081,48.948],[-95.3071,48.9477],[-95.3062,48.9472],[-95.3062,48.9472],[-95.3061,48.9469],[-95.3062,48.9463],[-95.3063,48.9462],[-95.3069,48.9456],[-95.3069,48.9455],[-95.3068,48.9454],[-95.3061,48.9454],[-95.3053,48.9459],[-95.305,48.9462],[-95.3046,48.947],[-95.3046,48.9482],[-95.3052,48.9495],[-95.3061,48.9502],[-95.3079,48.9509],[-95.3089,48.9511],[-95.3097,48.951],[-95.3104,48.951],[-95.3108,48.9512],[-95.3115,48.952],[-95.312,48.9524],[-95.3126,48.9524],[-95.3129,48.9523],[-95.3129,48.9521],[-95.3119,48.9507],[-95.3119,48.9502],[-95.3123,48.9502],[-95.3125,48.9503],[-95.3131,48.9503],[-95.3141,48.9508],[-95.3151,48.951],[-95.3154,48.9513],[-95.3177,48.9525],[-95.3181,48.9531],[-95.3182,48.9535],[-95.3177,48.9545],[-95.3175,48.9552],[-95.3179,48.9559],[-95.3188,48.9562],[-95.3191,48.9569],[-95.3202,48.9581],[-95.3206,48.959],[-95.3206,48.9595],[-95.3206,48.9598],[-95.3202,48.9606],[-95.3193,48.9622],[-95.3193,48.964],[-95.3198,48.9643],[-95.3201,48.9648],[-95.3207,48.9669],[-95.3212,48.9672],[-95.3227,48.9685],[-95.3232,48.9692],[-95.3241,48.9703],[-95.3247,48.972],[-95.3248,48.9728],[-95.3249,48.9738],[-95.325,48.9743],[-95.3253,48.976],[-95.3257,48.9784],[-95.3255,48.9789],[-95.3256,48.98],[-95.3257,48.9814],[-95.3253,48.9832],[-95.3245,48.985],[-95.3242,48.9859],[-95.3227,48.9884],[-95.3224,48.9889],[-95.3206,48.9921],[-95.3204,48.9924],[-95.3191,48.9941],[-95.3181,48.995],[-95.3178,48.9958],[-95.3178,48.9961],[-95.3179,48.9961],[-95.3182,48.996],[-95.3187,48.9956],[-95.3191,48.9953],[-95.3197,48.9954],[-95.3201,48.9956],[-95.3206,48.9961],[-95.3204,48.9964],[-95.3202,48.9973],[-95.3204,48.9976],[-95.3224,48.9984],[-95.3231,48.999]]],"type":"Polygon"},"id":"39","properties":{"Area":4608320923.49768,"CTYONLY_":2,"Code":"LOTW","LASTMOD":"1976-07-04T12:00:00Z","Name":"Lake of the Woods","Perimiter":388250.14572},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&filter=CTYONLY_%3C3","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&filter=CTYONLY_%3C3","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":1,"numberReturned":1,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_text_mod.json.txt b/msautotest/api/expected/ogcapi_cql2_text_mod.json.txt new file mode 100644 index 0000000000..e130c7e8be --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_text_mod.json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 1 +OGC-NumberReturned: 1 + +{"features":[{"geometry":{"coordinates":[[[-96.4054,49.0001],[-96.4019,49.0001],[-96.3825,49.0001],[-96.3783,49.0001],[-96.3606,49.0001],[-96.3579,49.0001],[-96.3385,49.0001],[-96.3343,49.0001],[-96.3166,49.0001],[-96.3138,49.0001],[-96.2945,49.0001],[-96.2902,49.0001],[-96.2725,49.0001],[-96.2698,49.0001],[-96.2494,49.0001],[-96.2461,49.0001],[-96.2274,49.0001],[-96.2257,49.0001],[-96.2057,49.0001],[-96.2021,49.0001],[-96.1837,49.0],[-96.18,49.0],[-96.1617,49.0],[-96.1579,49.0],[-96.1401,49.0],[-96.1359,49.0],[-96.1176,49.0],[-96.1139,49.0],[-96.0957,49.0],[-96.0919,49.0],[-96.0738,49.0],[-96.07,49.0],[-96.0517,49.0],[-96.048,49.0],[-96.0298,49.0],[-96.026,49.0],[-96.0083,49.0],[-96.0045,49.0],[-95.9868,49.0],[-95.9784,49.0],[-95.9776,49.0],[-95.9755,49.0],[-95.9648,48.9999],[-95.9464,48.9999],[-95.943,48.9999],[-95.9225,48.9999],[-95.9211,48.9999],[-95.899,48.9998],[-95.883,48.9998],[-95.8771,48.9998],[-95.8564,48.9998],[-95.855,48.9998],[-95.8342,48.9998],[-95.8184,48.9997],[-95.8126,48.9997],[-95.7906,48.9997],[-95.7833,48.9997],[-95.7684,48.9997],[-95.7479,48.9996],[-95.7466,48.9996],[-95.7253,48.9996],[-95.7066,48.9996],[-95.7032,48.9996],[-95.681,48.9995],[-95.6654,48.9995],[-95.6596,48.9995],[-95.659,48.9995],[-95.6401,48.9995],[-95.6369,48.9995],[-95.6205,48.9994],[-95.615,48.9994],[-95.5948,48.9994],[-95.585,48.9994],[-95.573,48.9994],[-95.551,48.9993],[-95.5495,48.9993],[-95.5294,48.9993],[-95.5164,48.9993],[-95.5072,48.9993],[-95.4849,48.9992],[-95.4834,48.9992],[-95.4635,48.9992],[-95.4508,48.9992],[-95.4418,48.9992],[-95.4245,48.9991],[-95.4197,48.9991],[-95.3977,48.9991],[-95.3953,48.9991],[-95.3765,48.9991],[-95.3759,48.9991],[-95.3753,48.9991],[-95.3542,48.999],[-95.3513,48.999],[-95.3326,48.999],[-95.3286,48.999],[-95.3231,48.999],[-95.3224,48.9984],[-95.3204,48.9976],[-95.3202,48.9973],[-95.3204,48.9964],[-95.3206,48.9961],[-95.3201,48.9956],[-95.3197,48.9954],[-95.3191,48.9953],[-95.3187,48.9956],[-95.3182,48.996],[-95.3179,48.9961],[-95.3178,48.9961],[-95.3178,48.9958],[-95.3181,48.995],[-95.3191,48.9941],[-95.3204,48.9924],[-95.3206,48.9921],[-95.3224,48.9889],[-95.3227,48.9884],[-95.3242,48.9859],[-95.3245,48.985],[-95.3253,48.9832],[-95.3257,48.9814],[-95.3256,48.98],[-95.3255,48.9789],[-95.3257,48.9784],[-95.3253,48.976],[-95.325,48.9743],[-95.3249,48.9738],[-95.3248,48.9728],[-95.3247,48.972],[-95.3241,48.9703],[-95.3232,48.9692],[-95.3227,48.9685],[-95.3212,48.9672],[-95.3207,48.9669],[-95.3201,48.9648],[-95.3198,48.9643],[-95.3193,48.964],[-95.3193,48.9622],[-95.3202,48.9606],[-95.3206,48.9598],[-95.3206,48.9595],[-95.3206,48.959],[-95.3202,48.9581],[-95.3191,48.9569],[-95.3188,48.9562],[-95.3179,48.9559],[-95.3175,48.9552],[-95.3177,48.9545],[-95.3182,48.9535],[-95.3181,48.9531],[-95.3177,48.9525],[-95.3154,48.9513],[-95.3151,48.951],[-95.3141,48.9508],[-95.3131,48.9503],[-95.3125,48.9503],[-95.3123,48.9502],[-95.3119,48.9502],[-95.3119,48.9507],[-95.3129,48.9521],[-95.3129,48.9523],[-95.3126,48.9524],[-95.312,48.9524],[-95.3115,48.952],[-95.3108,48.9512],[-95.3104,48.951],[-95.3097,48.951],[-95.3089,48.9511],[-95.3079,48.9509],[-95.3061,48.9502],[-95.3052,48.9495],[-95.3046,48.9482],[-95.3046,48.947],[-95.305,48.9462],[-95.3053,48.9459],[-95.3061,48.9454],[-95.3068,48.9454],[-95.3069,48.9455],[-95.3069,48.9456],[-95.3063,48.9462],[-95.3062,48.9463],[-95.3061,48.9469],[-95.3062,48.9472],[-95.3062,48.9472],[-95.3071,48.9477],[-95.3081,48.948],[-95.3094,48.9481],[-95.3096,48.9482],[-95.3099,48.9484],[-95.31,48.9485],[-95.3103,48.9485],[-95.3104,48.9484],[-95.3103,48.948],[-95.3096,48.9478],[-95.3092,48.9477],[-95.3079,48.9474],[-95.3071,48.9469],[-95.3071,48.9466],[-95.3074,48.9465],[-95.3078,48.9466],[-95.3085,48.947],[-95.3086,48.9469],[-95.3086,48.9465],[-95.3088,48.9464],[-95.3095,48.9463],[-95.3102,48.9463],[-95.3114,48.9461],[-95.3131,48.946],[-95.3141,48.9457],[-95.3148,48.9452],[-95.3154,48.9448],[-95.3168,48.9431],[-95.3181,48.9421],[-95.3189,48.9419],[-95.3219,48.9412],[-95.3225,48.9409],[-95.3228,48.9403],[-95.3231,48.9389],[-95.3229,48.9373],[-95.3225,48.9358],[-95.3223,48.9355],[-95.3228,48.9344],[-95.3222,48.9327],[-95.3209,48.9307],[-95.3208,48.9305],[-95.3195,48.9285],[-95.3168,48.9245],[-95.315,48.9222],[-95.3141,48.921],[-95.3132,48.9198],[-95.3126,48.919],[-95.3119,48.9178],[-95.3115,48.9172],[-95.3109,48.9163],[-95.3102,48.9155],[-95.3093,48.9149],[-95.3092,48.9149],[-95.3085,48.9146],[-95.3078,48.9141],[-95.3074,48.9135],[-95.3064,48.9129],[-95.3061,48.9128],[-95.3059,48.9127],[-95.3043,48.9119],[-95.3038,48.9114],[-95.3027,48.91],[-95.3017,48.9093],[-95.2999,48.9086],[-95.2978,48.9083],[-95.2973,48.9081],[-95.2973,48.908],[-95.2973,48.9077],[-95.2976,48.9074],[-95.2977,48.9073],[-95.2978,48.9073],[-95.2978,48.9072],[-95.2978,48.9072],[-95.2979,48.9072],[-95.2979,48.9072],[-95.2979,48.9071],[-95.298,48.9071],[-95.298,48.9071],[-95.298,48.9071],[-95.2981,48.907],[-95.2982,48.9068],[-95.2983,48.9068],[-95.2985,48.9065],[-95.2985,48.9064],[-95.2986,48.9063],[-95.2988,48.906],[-95.2989,48.906],[-95.2991,48.9057],[-95.2992,48.9055],[-95.2994,48.9053],[-95.2996,48.9051],[-95.2997,48.905],[-95.2999,48.9048],[-95.2999,48.9048],[-95.2999,48.9048],[-95.3,48.9047],[-95.3,48.9047],[-95.3001,48.9047],[-95.3001,48.9046],[-95.3002,48.9045],[-95.3005,48.904],[-95.2993,48.9035],[-95.2983,48.9028],[-95.298,48.9027],[-95.2976,48.9026],[-95.2967,48.9027],[-95.2949,48.9028],[-95.2941,48.9027],[-95.2937,48.9023],[-95.2935,48.902],[-95.2927,48.9019],[-95.2914,48.9019],[-95.2909,48.9017],[-95.2908,48.9016],[-95.2907,48.9014],[-95.2906,48.9011],[-95.2911,48.9008],[-95.2911,48.9006],[-95.2901,48.9003],[-95.2896,48.9],[-95.289,48.8994],[-95.2882,48.8981],[-95.2879,48.8979],[-95.2872,48.8977],[-95.287,48.8976],[-95.2865,48.8975],[-95.2861,48.8976],[-95.2853,48.8977],[-95.2839,48.8975],[-95.2813,48.8967],[-95.2803,48.8965],[-95.2796,48.8962],[-95.279,48.8957],[-95.2782,48.8956],[-95.2773,48.8957],[-95.277,48.8958],[-95.2765,48.8962],[-95.2763,48.8963],[-95.2759,48.8962],[-95.2755,48.8959],[-95.2749,48.8956],[-95.2748,48.8951],[-95.2753,48.8943],[-95.2751,48.8938],[-95.2745,48.8931],[-95.2724,48.8921],[-95.2713,48.8915],[-95.268,48.8905],[-95.2677,48.8903],[-95.2674,48.89],[-95.2666,48.8894],[-95.2654,48.8888],[-95.265,48.8886],[-95.2646,48.8885],[-95.2639,48.8883],[-95.2635,48.888],[-95.2627,48.8877],[-95.2585,48.8867],[-95.2585,48.8867],[-95.257,48.8858],[-95.256,48.885],[-95.2548,48.8845],[-95.2517,48.8839],[-95.2507,48.8836],[-95.2502,48.8835],[-95.2496,48.8834],[-95.2485,48.8832],[-95.248,48.8836],[-95.2472,48.8835],[-95.2458,48.8829],[-95.2439,48.8823],[-95.2429,48.8822],[-95.2429,48.8822],[-95.2423,48.8821],[-95.2407,48.8821],[-95.2391,48.8819],[-95.2381,48.8817],[-95.2356,48.8815],[-95.2335,48.8814],[-95.231,48.8814],[-95.2287,48.8815],[-95.2265,48.8816],[-95.2252,48.8819],[-95.2212,48.883],[-95.2208,48.8831],[-95.2207,48.8831],[-95.22,48.8831],[-95.2193,48.8832],[-95.2188,48.8835],[-95.217,48.8835],[-95.2159,48.8839],[-95.2151,48.884],[-95.2144,48.8843],[-95.2122,48.8842],[-95.2117,48.8847],[-95.2115,48.8847],[-95.2112,48.8848],[-95.2085,48.8846],[-95.2059,48.8848],[-95.2024,48.8852],[-95.2009,48.8855],[-95.2005,48.8856],[-95.1986,48.8855],[-95.1956,48.8862],[-95.1924,48.8865],[-95.1919,48.8866],[-95.1913,48.8868],[-95.1901,48.887],[-95.1889,48.8873],[-95.1877,48.8874],[-95.1863,48.8877],[-95.1851,48.8882],[-95.1819,48.8888],[-95.1797,48.889],[-95.1791,48.889],[-95.1764,48.8893],[-95.173,48.8897],[-95.1701,48.8902],[-95.1674,48.8907],[-95.1648,48.8913],[-95.1641,48.8917],[-95.1618,48.892],[-95.1602,48.892],[-95.1579,48.8919],[-95.1564,48.8919],[-95.1555,48.892],[-95.1528,48.8921],[-95.1508,48.8922],[-95.1483,48.8923],[-95.1469,48.8927],[-95.1459,48.8929],[-95.1438,48.8934],[-95.1436,48.8937],[-95.1404,48.8943],[-95.1381,48.8949],[-95.1355,48.8959],[-95.1351,48.8963],[-95.1348,48.8963],[-95.1343,48.8963],[-95.1337,48.8969],[-95.1322,48.8973],[-95.1312,48.8975],[-95.1252,48.8998],[-95.1239,48.9001],[-95.1233,48.9004],[-95.1228,48.9006],[-95.1214,48.9013],[-95.121,48.9016],[-95.1205,48.9017],[-95.1204,48.9019],[-95.1182,48.9029],[-95.1163,48.9037],[-95.1151,48.9046],[-95.1144,48.9052],[-95.114,48.9061],[-95.1141,48.9064],[-95.1137,48.9069],[-95.1132,48.9071],[-95.113,48.9072],[-95.1126,48.9073],[-95.1107,48.9082],[-95.1096,48.9089],[-95.108,48.9099],[-95.1056,48.9113],[-95.1042,48.9121],[-95.1032,48.9127],[-95.102,48.9132],[-95.1008,48.9142],[-95.0981,48.9159],[-95.098,48.916],[-95.0975,48.9164],[-95.0971,48.9172],[-95.097,48.9176],[-95.0961,48.9181],[-95.0946,48.9191],[-95.0944,48.9193],[-95.0927,48.9204],[-95.0919,48.9207],[-95.0914,48.9208],[-95.0914,48.916],[-95.0912,48.9014],[-95.0911,48.8869],[-95.0908,48.8724],[-95.0908,48.858],[-95.0907,48.8436],[-95.0908,48.8291],[-95.0909,48.8147],[-95.0903,48.8],[-95.0903,48.7855],[-95.0903,48.7711],[-95.0901,48.7566],[-95.0901,48.7421],[-95.0899,48.7277],[-95.0898,48.713],[-95.1046,48.7129],[-95.1104,48.7129],[-95.1119,48.7129],[-95.1259,48.7129],[-95.1297,48.713],[-95.1333,48.713],[-95.1477,48.7129],[-95.1554,48.7129],[-95.1697,48.7129],[-95.1773,48.713],[-95.1917,48.713],[-95.1991,48.713],[-95.2112,48.713],[-95.2206,48.713],[-95.2331,48.713],[-95.2427,48.713],[-95.255,48.713],[-95.2645,48.713],[-95.2656,48.713],[-95.2767,48.713],[-95.2866,48.713],[-95.299,48.713],[-95.3051,48.713],[-95.3084,48.713],[-95.3205,48.713],[-95.3302,48.713],[-95.3425,48.7131],[-95.3425,48.6995],[-95.3424,48.6849],[-95.3423,48.6705],[-95.3424,48.6561],[-95.3425,48.6415],[-95.3426,48.6271],[-95.3424,48.6127],[-95.3426,48.5979],[-95.3423,48.5836],[-95.3423,48.5691],[-95.3424,48.5548],[-95.3425,48.5402],[-95.3628,48.5404],[-95.364,48.5403],[-95.3844,48.5402],[-95.386,48.5402],[-95.4061,48.5402],[-95.4078,48.5402],[-95.4279,48.54],[-95.4297,48.5399],[-95.4494,48.5399],[-95.4513,48.5399],[-95.4712,48.5396],[-95.4726,48.5396],[-95.493,48.5392],[-95.495,48.5392],[-95.5143,48.539],[-95.5163,48.539],[-95.5365,48.5389],[-95.5383,48.5389],[-95.558,48.5388],[-95.5603,48.5388],[-95.5801,48.5387],[-95.5821,48.5387],[-95.6023,48.5389],[-95.6232,48.5391],[-95.6447,48.5393],[-95.6666,48.5394],[-95.6886,48.5395],[-95.7102,48.5395],[-95.7322,48.54],[-95.7539,48.5404],[-95.7758,48.5406],[-95.7976,48.5405],[-95.8192,48.5404],[-95.8411,48.5406],[-95.8621,48.5414],[-95.8829,48.5419],[-95.8851,48.542],[-95.8986,48.5421],[-95.9046,48.5422],[-95.9064,48.5422],[-95.9269,48.5421],[-95.9486,48.5425],[-95.9498,48.5425],[-95.9704,48.543],[-95.9936,48.5435],[-96.0157,48.5437],[-96.0374,48.5438],[-96.0592,48.5437],[-96.0812,48.5436],[-96.1026,48.5438],[-96.1264,48.5439],[-96.1486,48.5442],[-96.1702,48.5445],[-96.1921,48.5446],[-96.2141,48.5449],[-96.2358,48.5452],[-96.2576,48.545],[-96.2794,48.5449],[-96.301,48.5448],[-96.3231,48.5446],[-96.3448,48.5444],[-96.3667,48.5443],[-96.3882,48.5442],[-96.3879,48.5588],[-96.3882,48.5733],[-96.3884,48.5877],[-96.3891,48.6024],[-96.389,48.6165],[-96.388,48.6313],[-96.3879,48.6454],[-96.3877,48.6599],[-96.3871,48.6741],[-96.3874,48.6887],[-96.3866,48.703],[-96.3873,48.7172],[-96.388,48.7172],[-96.4049,48.7172],[-96.4048,48.7318],[-96.4048,48.7465],[-96.4047,48.7607],[-96.4045,48.7758],[-96.4042,48.7903],[-96.4042,48.8048],[-96.4042,48.8198],[-96.4043,48.8343],[-96.4045,48.8491],[-96.4047,48.8635],[-96.405,48.878],[-96.405,48.8926],[-96.4053,48.9068],[-96.4053,48.9081],[-96.4053,48.9137],[-96.4054,48.9214],[-96.4054,48.9225],[-96.4053,48.936],[-96.4053,48.9371],[-96.4053,48.9504],[-96.4053,48.9515],[-96.4053,48.9648],[-96.4053,48.9658],[-96.4053,48.9705],[-96.4054,48.9793],[-96.4054,48.9803],[-96.4054,48.994],[-96.4054,48.9947],[-96.4054,49.0001]]],"type":"Polygon"},"id":"68","properties":{"Area":4347098503.12714,"CTYONLY_":4,"Code":"ROSE","LASTMOD":"2001-04-12T09:32:44Z","Name":"Roseau","Perimiter":302590.75293},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&filter=CTYONLY_%3D9%255","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&filter=CTYONLY_%3D9%255","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":1,"numberReturned":1,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_text_multiply.json.txt b/msautotest/api/expected/ogcapi_cql2_text_multiply.json.txt new file mode 100644 index 0000000000..90513d530c --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_text_multiply.json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 1 +OGC-NumberReturned: 1 + +{"features":[{"geometry":{"coordinates":[[[-96.4054,49.0001],[-96.4019,49.0001],[-96.3825,49.0001],[-96.3783,49.0001],[-96.3606,49.0001],[-96.3579,49.0001],[-96.3385,49.0001],[-96.3343,49.0001],[-96.3166,49.0001],[-96.3138,49.0001],[-96.2945,49.0001],[-96.2902,49.0001],[-96.2725,49.0001],[-96.2698,49.0001],[-96.2494,49.0001],[-96.2461,49.0001],[-96.2274,49.0001],[-96.2257,49.0001],[-96.2057,49.0001],[-96.2021,49.0001],[-96.1837,49.0],[-96.18,49.0],[-96.1617,49.0],[-96.1579,49.0],[-96.1401,49.0],[-96.1359,49.0],[-96.1176,49.0],[-96.1139,49.0],[-96.0957,49.0],[-96.0919,49.0],[-96.0738,49.0],[-96.07,49.0],[-96.0517,49.0],[-96.048,49.0],[-96.0298,49.0],[-96.026,49.0],[-96.0083,49.0],[-96.0045,49.0],[-95.9868,49.0],[-95.9784,49.0],[-95.9776,49.0],[-95.9755,49.0],[-95.9648,48.9999],[-95.9464,48.9999],[-95.943,48.9999],[-95.9225,48.9999],[-95.9211,48.9999],[-95.899,48.9998],[-95.883,48.9998],[-95.8771,48.9998],[-95.8564,48.9998],[-95.855,48.9998],[-95.8342,48.9998],[-95.8184,48.9997],[-95.8126,48.9997],[-95.7906,48.9997],[-95.7833,48.9997],[-95.7684,48.9997],[-95.7479,48.9996],[-95.7466,48.9996],[-95.7253,48.9996],[-95.7066,48.9996],[-95.7032,48.9996],[-95.681,48.9995],[-95.6654,48.9995],[-95.6596,48.9995],[-95.659,48.9995],[-95.6401,48.9995],[-95.6369,48.9995],[-95.6205,48.9994],[-95.615,48.9994],[-95.5948,48.9994],[-95.585,48.9994],[-95.573,48.9994],[-95.551,48.9993],[-95.5495,48.9993],[-95.5294,48.9993],[-95.5164,48.9993],[-95.5072,48.9993],[-95.4849,48.9992],[-95.4834,48.9992],[-95.4635,48.9992],[-95.4508,48.9992],[-95.4418,48.9992],[-95.4245,48.9991],[-95.4197,48.9991],[-95.3977,48.9991],[-95.3953,48.9991],[-95.3765,48.9991],[-95.3759,48.9991],[-95.3753,48.9991],[-95.3542,48.999],[-95.3513,48.999],[-95.3326,48.999],[-95.3286,48.999],[-95.3231,48.999],[-95.3224,48.9984],[-95.3204,48.9976],[-95.3202,48.9973],[-95.3204,48.9964],[-95.3206,48.9961],[-95.3201,48.9956],[-95.3197,48.9954],[-95.3191,48.9953],[-95.3187,48.9956],[-95.3182,48.996],[-95.3179,48.9961],[-95.3178,48.9961],[-95.3178,48.9958],[-95.3181,48.995],[-95.3191,48.9941],[-95.3204,48.9924],[-95.3206,48.9921],[-95.3224,48.9889],[-95.3227,48.9884],[-95.3242,48.9859],[-95.3245,48.985],[-95.3253,48.9832],[-95.3257,48.9814],[-95.3256,48.98],[-95.3255,48.9789],[-95.3257,48.9784],[-95.3253,48.976],[-95.325,48.9743],[-95.3249,48.9738],[-95.3248,48.9728],[-95.3247,48.972],[-95.3241,48.9703],[-95.3232,48.9692],[-95.3227,48.9685],[-95.3212,48.9672],[-95.3207,48.9669],[-95.3201,48.9648],[-95.3198,48.9643],[-95.3193,48.964],[-95.3193,48.9622],[-95.3202,48.9606],[-95.3206,48.9598],[-95.3206,48.9595],[-95.3206,48.959],[-95.3202,48.9581],[-95.3191,48.9569],[-95.3188,48.9562],[-95.3179,48.9559],[-95.3175,48.9552],[-95.3177,48.9545],[-95.3182,48.9535],[-95.3181,48.9531],[-95.3177,48.9525],[-95.3154,48.9513],[-95.3151,48.951],[-95.3141,48.9508],[-95.3131,48.9503],[-95.3125,48.9503],[-95.3123,48.9502],[-95.3119,48.9502],[-95.3119,48.9507],[-95.3129,48.9521],[-95.3129,48.9523],[-95.3126,48.9524],[-95.312,48.9524],[-95.3115,48.952],[-95.3108,48.9512],[-95.3104,48.951],[-95.3097,48.951],[-95.3089,48.9511],[-95.3079,48.9509],[-95.3061,48.9502],[-95.3052,48.9495],[-95.3046,48.9482],[-95.3046,48.947],[-95.305,48.9462],[-95.3053,48.9459],[-95.3061,48.9454],[-95.3068,48.9454],[-95.3069,48.9455],[-95.3069,48.9456],[-95.3063,48.9462],[-95.3062,48.9463],[-95.3061,48.9469],[-95.3062,48.9472],[-95.3062,48.9472],[-95.3071,48.9477],[-95.3081,48.948],[-95.3094,48.9481],[-95.3096,48.9482],[-95.3099,48.9484],[-95.31,48.9485],[-95.3103,48.9485],[-95.3104,48.9484],[-95.3103,48.948],[-95.3096,48.9478],[-95.3092,48.9477],[-95.3079,48.9474],[-95.3071,48.9469],[-95.3071,48.9466],[-95.3074,48.9465],[-95.3078,48.9466],[-95.3085,48.947],[-95.3086,48.9469],[-95.3086,48.9465],[-95.3088,48.9464],[-95.3095,48.9463],[-95.3102,48.9463],[-95.3114,48.9461],[-95.3131,48.946],[-95.3141,48.9457],[-95.3148,48.9452],[-95.3154,48.9448],[-95.3168,48.9431],[-95.3181,48.9421],[-95.3189,48.9419],[-95.3219,48.9412],[-95.3225,48.9409],[-95.3228,48.9403],[-95.3231,48.9389],[-95.3229,48.9373],[-95.3225,48.9358],[-95.3223,48.9355],[-95.3228,48.9344],[-95.3222,48.9327],[-95.3209,48.9307],[-95.3208,48.9305],[-95.3195,48.9285],[-95.3168,48.9245],[-95.315,48.9222],[-95.3141,48.921],[-95.3132,48.9198],[-95.3126,48.919],[-95.3119,48.9178],[-95.3115,48.9172],[-95.3109,48.9163],[-95.3102,48.9155],[-95.3093,48.9149],[-95.3092,48.9149],[-95.3085,48.9146],[-95.3078,48.9141],[-95.3074,48.9135],[-95.3064,48.9129],[-95.3061,48.9128],[-95.3059,48.9127],[-95.3043,48.9119],[-95.3038,48.9114],[-95.3027,48.91],[-95.3017,48.9093],[-95.2999,48.9086],[-95.2978,48.9083],[-95.2973,48.9081],[-95.2973,48.908],[-95.2973,48.9077],[-95.2976,48.9074],[-95.2977,48.9073],[-95.2978,48.9073],[-95.2978,48.9072],[-95.2978,48.9072],[-95.2979,48.9072],[-95.2979,48.9072],[-95.2979,48.9071],[-95.298,48.9071],[-95.298,48.9071],[-95.298,48.9071],[-95.2981,48.907],[-95.2982,48.9068],[-95.2983,48.9068],[-95.2985,48.9065],[-95.2985,48.9064],[-95.2986,48.9063],[-95.2988,48.906],[-95.2989,48.906],[-95.2991,48.9057],[-95.2992,48.9055],[-95.2994,48.9053],[-95.2996,48.9051],[-95.2997,48.905],[-95.2999,48.9048],[-95.2999,48.9048],[-95.2999,48.9048],[-95.3,48.9047],[-95.3,48.9047],[-95.3001,48.9047],[-95.3001,48.9046],[-95.3002,48.9045],[-95.3005,48.904],[-95.2993,48.9035],[-95.2983,48.9028],[-95.298,48.9027],[-95.2976,48.9026],[-95.2967,48.9027],[-95.2949,48.9028],[-95.2941,48.9027],[-95.2937,48.9023],[-95.2935,48.902],[-95.2927,48.9019],[-95.2914,48.9019],[-95.2909,48.9017],[-95.2908,48.9016],[-95.2907,48.9014],[-95.2906,48.9011],[-95.2911,48.9008],[-95.2911,48.9006],[-95.2901,48.9003],[-95.2896,48.9],[-95.289,48.8994],[-95.2882,48.8981],[-95.2879,48.8979],[-95.2872,48.8977],[-95.287,48.8976],[-95.2865,48.8975],[-95.2861,48.8976],[-95.2853,48.8977],[-95.2839,48.8975],[-95.2813,48.8967],[-95.2803,48.8965],[-95.2796,48.8962],[-95.279,48.8957],[-95.2782,48.8956],[-95.2773,48.8957],[-95.277,48.8958],[-95.2765,48.8962],[-95.2763,48.8963],[-95.2759,48.8962],[-95.2755,48.8959],[-95.2749,48.8956],[-95.2748,48.8951],[-95.2753,48.8943],[-95.2751,48.8938],[-95.2745,48.8931],[-95.2724,48.8921],[-95.2713,48.8915],[-95.268,48.8905],[-95.2677,48.8903],[-95.2674,48.89],[-95.2666,48.8894],[-95.2654,48.8888],[-95.265,48.8886],[-95.2646,48.8885],[-95.2639,48.8883],[-95.2635,48.888],[-95.2627,48.8877],[-95.2585,48.8867],[-95.2585,48.8867],[-95.257,48.8858],[-95.256,48.885],[-95.2548,48.8845],[-95.2517,48.8839],[-95.2507,48.8836],[-95.2502,48.8835],[-95.2496,48.8834],[-95.2485,48.8832],[-95.248,48.8836],[-95.2472,48.8835],[-95.2458,48.8829],[-95.2439,48.8823],[-95.2429,48.8822],[-95.2429,48.8822],[-95.2423,48.8821],[-95.2407,48.8821],[-95.2391,48.8819],[-95.2381,48.8817],[-95.2356,48.8815],[-95.2335,48.8814],[-95.231,48.8814],[-95.2287,48.8815],[-95.2265,48.8816],[-95.2252,48.8819],[-95.2212,48.883],[-95.2208,48.8831],[-95.2207,48.8831],[-95.22,48.8831],[-95.2193,48.8832],[-95.2188,48.8835],[-95.217,48.8835],[-95.2159,48.8839],[-95.2151,48.884],[-95.2144,48.8843],[-95.2122,48.8842],[-95.2117,48.8847],[-95.2115,48.8847],[-95.2112,48.8848],[-95.2085,48.8846],[-95.2059,48.8848],[-95.2024,48.8852],[-95.2009,48.8855],[-95.2005,48.8856],[-95.1986,48.8855],[-95.1956,48.8862],[-95.1924,48.8865],[-95.1919,48.8866],[-95.1913,48.8868],[-95.1901,48.887],[-95.1889,48.8873],[-95.1877,48.8874],[-95.1863,48.8877],[-95.1851,48.8882],[-95.1819,48.8888],[-95.1797,48.889],[-95.1791,48.889],[-95.1764,48.8893],[-95.173,48.8897],[-95.1701,48.8902],[-95.1674,48.8907],[-95.1648,48.8913],[-95.1641,48.8917],[-95.1618,48.892],[-95.1602,48.892],[-95.1579,48.8919],[-95.1564,48.8919],[-95.1555,48.892],[-95.1528,48.8921],[-95.1508,48.8922],[-95.1483,48.8923],[-95.1469,48.8927],[-95.1459,48.8929],[-95.1438,48.8934],[-95.1436,48.8937],[-95.1404,48.8943],[-95.1381,48.8949],[-95.1355,48.8959],[-95.1351,48.8963],[-95.1348,48.8963],[-95.1343,48.8963],[-95.1337,48.8969],[-95.1322,48.8973],[-95.1312,48.8975],[-95.1252,48.8998],[-95.1239,48.9001],[-95.1233,48.9004],[-95.1228,48.9006],[-95.1214,48.9013],[-95.121,48.9016],[-95.1205,48.9017],[-95.1204,48.9019],[-95.1182,48.9029],[-95.1163,48.9037],[-95.1151,48.9046],[-95.1144,48.9052],[-95.114,48.9061],[-95.1141,48.9064],[-95.1137,48.9069],[-95.1132,48.9071],[-95.113,48.9072],[-95.1126,48.9073],[-95.1107,48.9082],[-95.1096,48.9089],[-95.108,48.9099],[-95.1056,48.9113],[-95.1042,48.9121],[-95.1032,48.9127],[-95.102,48.9132],[-95.1008,48.9142],[-95.0981,48.9159],[-95.098,48.916],[-95.0975,48.9164],[-95.0971,48.9172],[-95.097,48.9176],[-95.0961,48.9181],[-95.0946,48.9191],[-95.0944,48.9193],[-95.0927,48.9204],[-95.0919,48.9207],[-95.0914,48.9208],[-95.0914,48.916],[-95.0912,48.9014],[-95.0911,48.8869],[-95.0908,48.8724],[-95.0908,48.858],[-95.0907,48.8436],[-95.0908,48.8291],[-95.0909,48.8147],[-95.0903,48.8],[-95.0903,48.7855],[-95.0903,48.7711],[-95.0901,48.7566],[-95.0901,48.7421],[-95.0899,48.7277],[-95.0898,48.713],[-95.1046,48.7129],[-95.1104,48.7129],[-95.1119,48.7129],[-95.1259,48.7129],[-95.1297,48.713],[-95.1333,48.713],[-95.1477,48.7129],[-95.1554,48.7129],[-95.1697,48.7129],[-95.1773,48.713],[-95.1917,48.713],[-95.1991,48.713],[-95.2112,48.713],[-95.2206,48.713],[-95.2331,48.713],[-95.2427,48.713],[-95.255,48.713],[-95.2645,48.713],[-95.2656,48.713],[-95.2767,48.713],[-95.2866,48.713],[-95.299,48.713],[-95.3051,48.713],[-95.3084,48.713],[-95.3205,48.713],[-95.3302,48.713],[-95.3425,48.7131],[-95.3425,48.6995],[-95.3424,48.6849],[-95.3423,48.6705],[-95.3424,48.6561],[-95.3425,48.6415],[-95.3426,48.6271],[-95.3424,48.6127],[-95.3426,48.5979],[-95.3423,48.5836],[-95.3423,48.5691],[-95.3424,48.5548],[-95.3425,48.5402],[-95.3628,48.5404],[-95.364,48.5403],[-95.3844,48.5402],[-95.386,48.5402],[-95.4061,48.5402],[-95.4078,48.5402],[-95.4279,48.54],[-95.4297,48.5399],[-95.4494,48.5399],[-95.4513,48.5399],[-95.4712,48.5396],[-95.4726,48.5396],[-95.493,48.5392],[-95.495,48.5392],[-95.5143,48.539],[-95.5163,48.539],[-95.5365,48.5389],[-95.5383,48.5389],[-95.558,48.5388],[-95.5603,48.5388],[-95.5801,48.5387],[-95.5821,48.5387],[-95.6023,48.5389],[-95.6232,48.5391],[-95.6447,48.5393],[-95.6666,48.5394],[-95.6886,48.5395],[-95.7102,48.5395],[-95.7322,48.54],[-95.7539,48.5404],[-95.7758,48.5406],[-95.7976,48.5405],[-95.8192,48.5404],[-95.8411,48.5406],[-95.8621,48.5414],[-95.8829,48.5419],[-95.8851,48.542],[-95.8986,48.5421],[-95.9046,48.5422],[-95.9064,48.5422],[-95.9269,48.5421],[-95.9486,48.5425],[-95.9498,48.5425],[-95.9704,48.543],[-95.9936,48.5435],[-96.0157,48.5437],[-96.0374,48.5438],[-96.0592,48.5437],[-96.0812,48.5436],[-96.1026,48.5438],[-96.1264,48.5439],[-96.1486,48.5442],[-96.1702,48.5445],[-96.1921,48.5446],[-96.2141,48.5449],[-96.2358,48.5452],[-96.2576,48.545],[-96.2794,48.5449],[-96.301,48.5448],[-96.3231,48.5446],[-96.3448,48.5444],[-96.3667,48.5443],[-96.3882,48.5442],[-96.3879,48.5588],[-96.3882,48.5733],[-96.3884,48.5877],[-96.3891,48.6024],[-96.389,48.6165],[-96.388,48.6313],[-96.3879,48.6454],[-96.3877,48.6599],[-96.3871,48.6741],[-96.3874,48.6887],[-96.3866,48.703],[-96.3873,48.7172],[-96.388,48.7172],[-96.4049,48.7172],[-96.4048,48.7318],[-96.4048,48.7465],[-96.4047,48.7607],[-96.4045,48.7758],[-96.4042,48.7903],[-96.4042,48.8048],[-96.4042,48.8198],[-96.4043,48.8343],[-96.4045,48.8491],[-96.4047,48.8635],[-96.405,48.878],[-96.405,48.8926],[-96.4053,48.9068],[-96.4053,48.9081],[-96.4053,48.9137],[-96.4054,48.9214],[-96.4054,48.9225],[-96.4053,48.936],[-96.4053,48.9371],[-96.4053,48.9504],[-96.4053,48.9515],[-96.4053,48.9648],[-96.4053,48.9658],[-96.4053,48.9705],[-96.4054,48.9793],[-96.4054,48.9803],[-96.4054,48.994],[-96.4054,48.9947],[-96.4054,49.0001]]],"type":"Polygon"},"id":"68","properties":{"Area":4347098503.12714,"CTYONLY_":4,"Code":"ROSE","LASTMOD":"2001-04-12T09:32:44Z","Name":"Roseau","Perimiter":302590.75293},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&filter=CTYONLY_%3D2*2","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&filter=CTYONLY_%3D2*2","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":1,"numberReturned":1,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_text_not.json.txt b/msautotest/api/expected/ogcapi_cql2_text_not.json.txt new file mode 100644 index 0000000000..abf9cc853e --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_text_not.json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 1 +OGC-NumberReturned: 1 + +{"features":[{"geometry":{"coordinates":[[[-93.5242,44.5436],[-93.5225,44.5436],[-93.504,44.5438],[-93.5018,44.5438],[-93.4835,44.5438],[-93.4817,44.5438],[-93.4734,44.5438],[-93.4632,44.5438],[-93.4609,44.5438],[-93.4429,44.5438],[-93.4408,44.5438],[-93.4326,44.5438],[-93.4226,44.5439],[-93.4206,44.5439],[-93.4024,44.5439],[-93.4003,44.5439],[-93.383,44.544],[-93.38,44.544],[-93.3627,44.5441],[-93.3596,44.5441],[-93.3556,44.5441],[-93.3424,44.5442],[-93.3395,44.5442],[-93.3221,44.544],[-93.3191,44.544],[-93.3128,44.544],[-93.3019,44.544],[-93.2988,44.544],[-93.2813,44.544],[-93.2814,44.5298],[-93.2815,44.5153],[-93.2815,44.501],[-93.2815,44.4865],[-93.2817,44.472],[-93.2618,44.4718],[-93.2415,44.4716],[-93.2213,44.4714],[-93.2008,44.4714],[-93.1808,44.4713],[-93.1605,44.4713],[-93.1408,44.4712],[-93.1206,44.4713],[-93.1002,44.4718],[-93.0799,44.4719],[-93.0597,44.4718],[-93.0393,44.4719],[-93.0394,44.4576],[-93.0396,44.4432],[-93.0397,44.4287],[-93.0399,44.4143],[-93.04,44.3999],[-93.0401,44.3855],[-93.0402,44.371],[-93.0403,44.3565],[-93.0403,44.3419],[-93.0405,44.3273],[-93.0405,44.3129],[-93.0405,44.2983],[-93.0406,44.2838],[-93.0407,44.2693],[-93.0409,44.2548],[-93.041,44.2402],[-93.0411,44.2257],[-93.0411,44.2113],[-93.0411,44.1968],[-93.0427,44.1968],[-93.0459,44.1968],[-93.0613,44.1967],[-93.0661,44.1967],[-93.0815,44.1967],[-93.0862,44.1967],[-93.1003,44.1967],[-93.1015,44.1967],[-93.1063,44.1967],[-93.1092,44.1967],[-93.1218,44.1967],[-93.1267,44.1967],[-93.1301,44.1967],[-93.1418,44.1967],[-93.1467,44.1967],[-93.1561,44.1966],[-93.1622,44.1966],[-93.1661,44.1966],[-93.1703,44.1966],[-93.1822,44.1966],[-93.1856,44.1966],[-93.1865,44.1966],[-93.2023,44.1966],[-93.2037,44.1966],[-93.2064,44.1966],[-93.2225,44.1966],[-93.2265,44.1966],[-93.2292,44.1966],[-93.2426,44.1966],[-93.2465,44.1966],[-93.255,44.1966],[-93.2629,44.1966],[-93.2664,44.1966],[-93.2767,44.1966],[-93.283,44.1966],[-93.2865,44.1965],[-93.2905,44.1965],[-93.3032,44.1965],[-93.3063,44.1965],[-93.3235,44.1965],[-93.3264,44.1965],[-93.3277,44.1965],[-93.3436,44.1965],[-93.3466,44.1965],[-93.3639,44.1965],[-93.3666,44.1965],[-93.3842,44.1965],[-93.3866,44.1965],[-93.4042,44.1965],[-93.4065,44.1965],[-93.4244,44.1964],[-93.4267,44.1964],[-93.4447,44.1964],[-93.4469,44.1964],[-93.4648,44.1963],[-93.467,44.1963],[-93.4852,44.1964],[-93.4872,44.1964],[-93.5053,44.1963],[-93.507,44.1963],[-93.5255,44.1962],[-93.5253,44.2107],[-93.5251,44.2251],[-93.5251,44.2388],[-93.5251,44.2533],[-93.5252,44.2685],[-93.5252,44.2829],[-93.5252,44.2975],[-93.5252,44.312],[-93.5249,44.3266],[-93.5249,44.3411],[-93.5245,44.3557],[-93.5245,44.3704],[-93.5246,44.3848],[-93.5245,44.3994],[-93.5245,44.4138],[-93.5245,44.4283],[-93.5245,44.4427],[-93.5245,44.4572],[-93.5244,44.4717],[-93.5245,44.4862],[-93.5244,44.5007],[-93.5243,44.5152],[-93.5244,44.5297],[-93.5242,44.5436]]],"type":"Polygon"},"id":"66","properties":{"Area":1335114621.00336,"CTYONLY_":66,"Code":"RICE","LASTMOD":"2010-10-17T00:00:00Z","Name":"Rice","Perimiter":154431.78788},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&filter=NOT%20Name%3C%3E'Rice'","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&filter=NOT%20Name%3C%3E'Rice'","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":1,"numberReturned":1,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_text_not_a_queryable.json.txt b/msautotest/api/expected/ogcapi_cql2_text_not_a_queryable.json.txt new file mode 100644 index 0000000000..9566653e6b --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_text_not_a_queryable.json.txt @@ -0,0 +1,4 @@ +Content-Type: application/json +Status: 400 + +{"code":"InvalidParameterValue","description":"Cannot translate CQL2 filter to MapServer expression: unknown is not a queryable item"} diff --git a/msautotest/api/expected/ogcapi_cql2_text_not_casei_not_like.json.txt b/msautotest/api/expected/ogcapi_cql2_text_not_casei_not_like.json.txt new file mode 100644 index 0000000000..cac2075a1b --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_text_not_casei_not_like.json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 1 +OGC-NumberReturned: 1 + +{"features":[{"geometry":{"coordinates":[[[-93.5242,44.5436],[-93.5225,44.5436],[-93.504,44.5438],[-93.5018,44.5438],[-93.4835,44.5438],[-93.4817,44.5438],[-93.4734,44.5438],[-93.4632,44.5438],[-93.4609,44.5438],[-93.4429,44.5438],[-93.4408,44.5438],[-93.4326,44.5438],[-93.4226,44.5439],[-93.4206,44.5439],[-93.4024,44.5439],[-93.4003,44.5439],[-93.383,44.544],[-93.38,44.544],[-93.3627,44.5441],[-93.3596,44.5441],[-93.3556,44.5441],[-93.3424,44.5442],[-93.3395,44.5442],[-93.3221,44.544],[-93.3191,44.544],[-93.3128,44.544],[-93.3019,44.544],[-93.2988,44.544],[-93.2813,44.544],[-93.2814,44.5298],[-93.2815,44.5153],[-93.2815,44.501],[-93.2815,44.4865],[-93.2817,44.472],[-93.2618,44.4718],[-93.2415,44.4716],[-93.2213,44.4714],[-93.2008,44.4714],[-93.1808,44.4713],[-93.1605,44.4713],[-93.1408,44.4712],[-93.1206,44.4713],[-93.1002,44.4718],[-93.0799,44.4719],[-93.0597,44.4718],[-93.0393,44.4719],[-93.0394,44.4576],[-93.0396,44.4432],[-93.0397,44.4287],[-93.0399,44.4143],[-93.04,44.3999],[-93.0401,44.3855],[-93.0402,44.371],[-93.0403,44.3565],[-93.0403,44.3419],[-93.0405,44.3273],[-93.0405,44.3129],[-93.0405,44.2983],[-93.0406,44.2838],[-93.0407,44.2693],[-93.0409,44.2548],[-93.041,44.2402],[-93.0411,44.2257],[-93.0411,44.2113],[-93.0411,44.1968],[-93.0427,44.1968],[-93.0459,44.1968],[-93.0613,44.1967],[-93.0661,44.1967],[-93.0815,44.1967],[-93.0862,44.1967],[-93.1003,44.1967],[-93.1015,44.1967],[-93.1063,44.1967],[-93.1092,44.1967],[-93.1218,44.1967],[-93.1267,44.1967],[-93.1301,44.1967],[-93.1418,44.1967],[-93.1467,44.1967],[-93.1561,44.1966],[-93.1622,44.1966],[-93.1661,44.1966],[-93.1703,44.1966],[-93.1822,44.1966],[-93.1856,44.1966],[-93.1865,44.1966],[-93.2023,44.1966],[-93.2037,44.1966],[-93.2064,44.1966],[-93.2225,44.1966],[-93.2265,44.1966],[-93.2292,44.1966],[-93.2426,44.1966],[-93.2465,44.1966],[-93.255,44.1966],[-93.2629,44.1966],[-93.2664,44.1966],[-93.2767,44.1966],[-93.283,44.1966],[-93.2865,44.1965],[-93.2905,44.1965],[-93.3032,44.1965],[-93.3063,44.1965],[-93.3235,44.1965],[-93.3264,44.1965],[-93.3277,44.1965],[-93.3436,44.1965],[-93.3466,44.1965],[-93.3639,44.1965],[-93.3666,44.1965],[-93.3842,44.1965],[-93.3866,44.1965],[-93.4042,44.1965],[-93.4065,44.1965],[-93.4244,44.1964],[-93.4267,44.1964],[-93.4447,44.1964],[-93.4469,44.1964],[-93.4648,44.1963],[-93.467,44.1963],[-93.4852,44.1964],[-93.4872,44.1964],[-93.5053,44.1963],[-93.507,44.1963],[-93.5255,44.1962],[-93.5253,44.2107],[-93.5251,44.2251],[-93.5251,44.2388],[-93.5251,44.2533],[-93.5252,44.2685],[-93.5252,44.2829],[-93.5252,44.2975],[-93.5252,44.312],[-93.5249,44.3266],[-93.5249,44.3411],[-93.5245,44.3557],[-93.5245,44.3704],[-93.5246,44.3848],[-93.5245,44.3994],[-93.5245,44.4138],[-93.5245,44.4283],[-93.5245,44.4427],[-93.5245,44.4572],[-93.5244,44.4717],[-93.5245,44.4862],[-93.5244,44.5007],[-93.5243,44.5152],[-93.5244,44.5297],[-93.5242,44.5436]]],"type":"Polygon"},"id":"66","properties":{"Area":1335114621.00336,"CTYONLY_":66,"Code":"RICE","LASTMOD":"2010-10-17T00:00:00Z","Name":"Rice","Perimiter":154431.78788},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&filter=NOT%20casei(Name)%20NOT%20LIKE%20CASEI('rice')","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&filter=NOT%20casei(Name)%20NOT%20LIKE%20CASEI('rice')","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":1,"numberReturned":1,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_text_not_equal.json.txt b/msautotest/api/expected/ogcapi_cql2_text_not_equal.json.txt new file mode 100644 index 0000000000..295fab4c47 --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_text_not_equal.json.txt @@ -0,0 +1,9 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +Link: ; rel="next"; title="next page"; type="application/geo+json" +OGC-NumberMatched: 116 +OGC-NumberReturned: 9 + +{"features":[{"geometry":{"coordinates":[[[-95.3231,48.999],[-95.3109,48.999],[-95.2889,48.9989],[-95.2852,48.9989],[-95.2669,48.9989],[-95.245,48.9989],[-95.2232,48.9989],[-95.2014,48.9989],[-95.1792,48.9989],[-95.1574,48.9989],[-95.1531,48.9989],[-95.1531,49.0031],[-95.1532,49.0179],[-95.1532,49.0325],[-95.1532,49.047],[-95.1532,49.0619],[-95.1532,49.0765],[-95.1532,49.0911],[-95.1532,49.1057],[-95.1532,49.1205],[-95.1532,49.1354],[-95.1532,49.1499],[-95.1532,49.1642],[-95.1532,49.1788],[-95.1532,49.1807],[-95.1532,49.1931],[-95.1532,49.1966],[-95.1532,49.2077],[-95.1533,49.2131],[-95.1533,49.2219],[-95.1533,49.2308],[-95.1533,49.2365],[-95.1533,49.2472],[-95.1533,49.2512],[-95.1533,49.2655],[-95.1533,49.2697],[-95.1533,49.2802],[-95.1533,49.2882],[-95.1533,49.2945],[-95.1533,49.3072],[-95.1533,49.309],[-95.1533,49.3234],[-95.1533,49.3237],[-95.1533,49.3381],[-95.1533,49.3476],[-95.1533,49.3525],[-95.1533,49.3636],[-95.1533,49.367],[-95.1533,49.3705],[-95.1533,49.3776],[-95.1533,49.3813],[-95.1533,49.3845],[-95.1503,49.383],[-95.1499,49.3813],[-95.1498,49.3807],[-95.1467,49.3802],[-95.145,49.3784],[-95.1418,49.3784],[-95.1397,49.3762],[-95.1367,49.3751],[-95.1324,49.3736],[-95.1287,49.3705],[-95.1171,49.367],[-95.1159,49.3666],[-95.1145,49.3666],[-95.1098,49.3664],[-95.1031,49.3652],[-95.1031,49.3636],[-95.0926,49.3617],[-95.0897,49.3612],[-95.0707,49.3564],[-95.0582,49.3533],[-95.0495,49.3532],[-95.0479,49.3533],[-95.0262,49.3554],[-95.0141,49.3565],[-95.0047,49.3612],[-94.993,49.367],[-94.9889,49.369],[-94.9818,49.3684],[-94.9742,49.3678],[-94.9597,49.3699],[-94.9573,49.3702],[-94.952,49.3688],[-94.948,49.367],[-94.9376,49.3625],[-94.9152,49.3529],[-94.9143,49.3524],[-94.909,49.3502],[-94.9065,49.3484],[-94.8933,49.3414],[-94.8865,49.3378],[-94.8782,49.3334],[-94.8712,49.3308],[-94.854,49.3244],[-94.8492,49.3244],[-94.8363,49.3243],[-94.8311,49.3236],[-94.8271,49.323],[-94.8162,49.3214],[-94.8243,49.309],[-94.8243,49.3088],[-94.8255,49.2944],[-94.8255,49.2943],[-94.8204,49.28],[-94.8152,49.2653],[-94.8103,49.2515],[-94.8059,49.2388],[-94.8051,49.2367],[-94.8001,49.2224],[-94.7973,49.2144],[-94.7975,49.2079],[-94.7979,49.1979],[-94.7965,49.1936],[-94.7918,49.1792],[-94.7871,49.1646],[-94.7833,49.153],[-94.7823,49.15],[-94.7776,49.1357],[-94.7727,49.1206],[-94.7727,49.1206],[-94.7611,49.1096],[-94.7571,49.1058],[-94.7496,49.0988],[-94.7474,49.0918],[-94.7429,49.0773],[-94.7394,49.0657],[-94.7385,49.063],[-94.7344,49.0497],[-94.7299,49.0351],[-94.7254,49.0205],[-94.7207,49.0052],[-94.7184,48.9979],[-94.7162,48.9907],[-94.7117,48.9761],[-94.7072,48.9615],[-94.7027,48.9468],[-94.6982,48.9322],[-94.6968,48.9276],[-94.6844,48.8875],[-94.6834,48.8842],[-94.6842,48.8724],[-94.6855,48.8719],[-94.6923,48.8691],[-94.6902,48.8636],[-94.6914,48.8591],[-94.693,48.8535],[-94.6881,48.8447],[-94.6855,48.8401],[-94.6963,48.836],[-94.6975,48.8355],[-94.702,48.8319],[-94.7025,48.8302],[-94.7042,48.8243],[-94.6991,48.8159],[-94.6962,48.8111],[-94.6951,48.8092],[-94.6958,48.8012],[-94.6959,48.7997],[-94.6944,48.7895],[-94.6934,48.7864],[-94.6909,48.7781],[-94.687,48.7752],[-94.6776,48.772],[-94.6768,48.7717],[-94.6746,48.7705],[-94.6671,48.7662],[-94.6603,48.7605],[-94.6557,48.7581],[-94.6525,48.7565],[-94.652,48.7562],[-94.6453,48.7491],[-94.6453,48.7441],[-94.6443,48.7434],[-94.6414,48.7413],[-94.631,48.7392],[-94.6301,48.739],[-94.6191,48.7373],[-94.6106,48.7318],[-94.6084,48.731],[-94.6028,48.7289],[-94.6011,48.7283],[-94.5962,48.7248],[-94.5913,48.7197],[-94.5876,48.7176],[-94.5867,48.7175],[-94.5685,48.7156],[-94.5622,48.7159],[-94.5558,48.7163],[-94.549,48.7148],[-94.5487,48.7146],[-94.5457,48.7124],[-94.5396,48.7036],[-94.539,48.7028],[-94.5329,48.7013],[-94.5247,48.7016],[-94.5178,48.7008],[-94.5173,48.7008],[-94.5093,48.7006],[-94.5066,48.6999],[-94.4996,48.698],[-94.4958,48.698],[-94.4863,48.698],[-94.4739,48.6969],[-94.4706,48.6966],[-94.4631,48.6953],[-94.4568,48.6933],[-94.4523,48.6925],[-94.4517,48.6925],[-94.4465,48.693],[-94.4388,48.6949],[-94.4319,48.6998],[-94.4299,48.7012],[-94.4299,48.6998],[-94.43,48.6852],[-94.4301,48.6708],[-94.43,48.6564],[-94.4297,48.642],[-94.4294,48.6276],[-94.4292,48.6133],[-94.4289,48.5988],[-94.4289,48.5844],[-94.4291,48.5698],[-94.4295,48.5554],[-94.43,48.5409],[-94.4303,48.5264],[-94.4303,48.512],[-94.4299,48.4977],[-94.4296,48.4832],[-94.4296,48.4688],[-94.4293,48.4543],[-94.4292,48.4399],[-94.4293,48.4254],[-94.4294,48.411],[-94.4293,48.3964],[-94.4289,48.3821],[-94.4288,48.3675],[-94.4471,48.3675],[-94.4505,48.3675],[-94.4688,48.3675],[-94.4722,48.3674],[-94.4906,48.3674],[-94.4924,48.3674],[-94.4941,48.3674],[-94.5118,48.3675],[-94.5157,48.3674],[-94.5335,48.3674],[-94.5378,48.3674],[-94.5536,48.3674],[-94.5593,48.3674],[-94.5754,48.3674],[-94.5812,48.3674],[-94.5971,48.3675],[-94.6029,48.3674],[-94.6188,48.3673],[-94.6245,48.3673],[-94.6405,48.3673],[-94.6465,48.3673],[-94.6505,48.3673],[-94.6622,48.3673],[-94.6679,48.3673],[-94.6694,48.3672],[-94.683,48.3671],[-94.6898,48.3671],[-94.7099,48.3669],[-94.7117,48.3668],[-94.7315,48.3669],[-94.7329,48.3669],[-94.7533,48.3669],[-94.7549,48.3669],[-94.7748,48.3669],[-94.7765,48.3669],[-94.7967,48.3669],[-94.7983,48.3669],[-94.8183,48.3669],[-94.8199,48.3669],[-94.8399,48.3669],[-94.8416,48.3669],[-94.8616,48.3667],[-94.8632,48.3667],[-94.8833,48.3667],[-94.8849,48.3666],[-94.9049,48.3666],[-94.9065,48.3666],[-94.9264,48.3667],[-94.9283,48.3667],[-94.9469,48.3666],[-94.95,48.3666],[-94.9684,48.3667],[-94.9716,48.3667],[-94.9901,48.3667],[-94.9932,48.3667],[-95.0119,48.3665],[-95.0153,48.3665],[-95.0337,48.3665],[-95.0369,48.3665],[-95.0555,48.3665],[-95.0586,48.3665],[-95.0773,48.3664],[-95.0801,48.3664],[-95.099,48.3663],[-95.1008,48.3663],[-95.1018,48.3663],[-95.1207,48.3663],[-95.1236,48.3663],[-95.1315,48.3662],[-95.1424,48.3662],[-95.1454,48.3662],[-95.164,48.3661],[-95.1669,48.3661],[-95.1861,48.3661],[-95.1887,48.3661],[-95.1983,48.3661],[-95.2066,48.3661],[-95.2106,48.3661],[-95.211,48.3797],[-95.211,48.3808],[-95.2111,48.3941],[-95.2111,48.3952],[-95.2112,48.4087],[-95.2112,48.4096],[-95.2113,48.4232],[-95.2113,48.4242],[-95.2113,48.4255],[-95.2113,48.4376],[-95.2113,48.4387],[-95.2113,48.4522],[-95.2112,48.4529],[-95.211,48.4666],[-95.211,48.4673],[-95.2111,48.4816],[-95.2112,48.4962],[-95.2111,48.5101],[-95.2111,48.5109],[-95.2115,48.5244],[-95.2115,48.5252],[-95.2119,48.54],[-95.2324,48.5399],[-95.2339,48.5399],[-95.2537,48.5398],[-95.2554,48.5398],[-95.2756,48.54],[-95.2773,48.54],[-95.2975,48.5401],[-95.2992,48.5402],[-95.3194,48.54],[-95.321,48.54],[-95.3412,48.5402],[-95.3425,48.5402],[-95.3424,48.5548],[-95.3423,48.5691],[-95.3423,48.5836],[-95.3426,48.5979],[-95.3424,48.6127],[-95.3426,48.6271],[-95.3425,48.6415],[-95.3424,48.6561],[-95.3423,48.6705],[-95.3424,48.6849],[-95.3425,48.6995],[-95.3425,48.7131],[-95.3302,48.713],[-95.3205,48.713],[-95.3084,48.713],[-95.3051,48.713],[-95.299,48.713],[-95.2866,48.713],[-95.2767,48.713],[-95.2656,48.713],[-95.2645,48.713],[-95.255,48.713],[-95.2427,48.713],[-95.2331,48.713],[-95.2206,48.713],[-95.2112,48.713],[-95.1991,48.713],[-95.1917,48.713],[-95.1773,48.713],[-95.1697,48.7129],[-95.1554,48.7129],[-95.1477,48.7129],[-95.1333,48.713],[-95.1297,48.713],[-95.1259,48.7129],[-95.1119,48.7129],[-95.1104,48.7129],[-95.1046,48.7129],[-95.0898,48.713],[-95.0899,48.7277],[-95.0901,48.7421],[-95.0901,48.7566],[-95.0903,48.7711],[-95.0903,48.7855],[-95.0903,48.8],[-95.0909,48.8147],[-95.0908,48.8291],[-95.0907,48.8436],[-95.0908,48.858],[-95.0908,48.8724],[-95.0911,48.8869],[-95.0912,48.9014],[-95.0914,48.916],[-95.0914,48.9208],[-95.0919,48.9207],[-95.0927,48.9204],[-95.0944,48.9193],[-95.0946,48.9191],[-95.0961,48.9181],[-95.097,48.9176],[-95.0971,48.9172],[-95.0975,48.9164],[-95.098,48.916],[-95.0981,48.9159],[-95.1008,48.9142],[-95.102,48.9132],[-95.1032,48.9127],[-95.1042,48.9121],[-95.1056,48.9113],[-95.108,48.9099],[-95.1096,48.9089],[-95.1107,48.9082],[-95.1126,48.9073],[-95.113,48.9072],[-95.1132,48.9071],[-95.1137,48.9069],[-95.1141,48.9064],[-95.114,48.9061],[-95.1144,48.9052],[-95.1151,48.9046],[-95.1163,48.9037],[-95.1182,48.9029],[-95.1204,48.9019],[-95.1205,48.9017],[-95.121,48.9016],[-95.1214,48.9013],[-95.1228,48.9006],[-95.1233,48.9004],[-95.1239,48.9001],[-95.1252,48.8998],[-95.1312,48.8975],[-95.1322,48.8973],[-95.1337,48.8969],[-95.1343,48.8963],[-95.1348,48.8963],[-95.1351,48.8963],[-95.1355,48.8959],[-95.1381,48.8949],[-95.1404,48.8943],[-95.1436,48.8937],[-95.1438,48.8934],[-95.1459,48.8929],[-95.1469,48.8927],[-95.1483,48.8923],[-95.1508,48.8922],[-95.1528,48.8921],[-95.1555,48.892],[-95.1564,48.8919],[-95.1579,48.8919],[-95.1602,48.892],[-95.1618,48.892],[-95.1641,48.8917],[-95.1648,48.8913],[-95.1674,48.8907],[-95.1701,48.8902],[-95.173,48.8897],[-95.1764,48.8893],[-95.1791,48.889],[-95.1797,48.889],[-95.1819,48.8888],[-95.1851,48.8882],[-95.1863,48.8877],[-95.1877,48.8874],[-95.1889,48.8873],[-95.1901,48.887],[-95.1913,48.8868],[-95.1919,48.8866],[-95.1924,48.8865],[-95.1956,48.8862],[-95.1986,48.8855],[-95.2005,48.8856],[-95.2009,48.8855],[-95.2024,48.8852],[-95.2059,48.8848],[-95.2085,48.8846],[-95.2112,48.8848],[-95.2115,48.8847],[-95.2117,48.8847],[-95.2122,48.8842],[-95.2144,48.8843],[-95.2151,48.884],[-95.2159,48.8839],[-95.217,48.8835],[-95.2188,48.8835],[-95.2193,48.8832],[-95.22,48.8831],[-95.2207,48.8831],[-95.2208,48.8831],[-95.2212,48.883],[-95.2252,48.8819],[-95.2265,48.8816],[-95.2287,48.8815],[-95.231,48.8814],[-95.2335,48.8814],[-95.2356,48.8815],[-95.2381,48.8817],[-95.2391,48.8819],[-95.2407,48.8821],[-95.2423,48.8821],[-95.2429,48.8822],[-95.2429,48.8822],[-95.2439,48.8823],[-95.2458,48.8829],[-95.2472,48.8835],[-95.248,48.8836],[-95.2485,48.8832],[-95.2496,48.8834],[-95.2502,48.8835],[-95.2507,48.8836],[-95.2517,48.8839],[-95.2548,48.8845],[-95.256,48.885],[-95.257,48.8858],[-95.2585,48.8867],[-95.2585,48.8867],[-95.2627,48.8877],[-95.2635,48.888],[-95.2639,48.8883],[-95.2646,48.8885],[-95.265,48.8886],[-95.2654,48.8888],[-95.2666,48.8894],[-95.2674,48.89],[-95.2677,48.8903],[-95.268,48.8905],[-95.2713,48.8915],[-95.2724,48.8921],[-95.2745,48.8931],[-95.2751,48.8938],[-95.2753,48.8943],[-95.2748,48.8951],[-95.2749,48.8956],[-95.2755,48.8959],[-95.2759,48.8962],[-95.2763,48.8963],[-95.2765,48.8962],[-95.277,48.8958],[-95.2773,48.8957],[-95.2782,48.8956],[-95.279,48.8957],[-95.2796,48.8962],[-95.2803,48.8965],[-95.2813,48.8967],[-95.2839,48.8975],[-95.2853,48.8977],[-95.2861,48.8976],[-95.2865,48.8975],[-95.287,48.8976],[-95.2872,48.8977],[-95.2879,48.8979],[-95.2882,48.8981],[-95.289,48.8994],[-95.2896,48.9],[-95.2901,48.9003],[-95.2911,48.9006],[-95.2911,48.9008],[-95.2906,48.9011],[-95.2907,48.9014],[-95.2908,48.9016],[-95.2909,48.9017],[-95.2914,48.9019],[-95.2927,48.9019],[-95.2935,48.902],[-95.2937,48.9023],[-95.2941,48.9027],[-95.2949,48.9028],[-95.2967,48.9027],[-95.2976,48.9026],[-95.298,48.9027],[-95.2983,48.9028],[-95.2993,48.9035],[-95.3005,48.904],[-95.3002,48.9045],[-95.3001,48.9046],[-95.3001,48.9047],[-95.3,48.9047],[-95.3,48.9047],[-95.2999,48.9048],[-95.2999,48.9048],[-95.2999,48.9048],[-95.2997,48.905],[-95.2996,48.9051],[-95.2994,48.9053],[-95.2992,48.9055],[-95.2991,48.9057],[-95.2989,48.906],[-95.2988,48.906],[-95.2986,48.9063],[-95.2985,48.9064],[-95.2985,48.9065],[-95.2983,48.9068],[-95.2982,48.9068],[-95.2981,48.907],[-95.298,48.9071],[-95.298,48.9071],[-95.298,48.9071],[-95.2979,48.9071],[-95.2979,48.9072],[-95.2979,48.9072],[-95.2978,48.9072],[-95.2978,48.9072],[-95.2978,48.9073],[-95.2977,48.9073],[-95.2976,48.9074],[-95.2973,48.9077],[-95.2973,48.908],[-95.2973,48.9081],[-95.2978,48.9083],[-95.2999,48.9086],[-95.3017,48.9093],[-95.3027,48.91],[-95.3038,48.9114],[-95.3043,48.9119],[-95.3059,48.9127],[-95.3061,48.9128],[-95.3064,48.9129],[-95.3074,48.9135],[-95.3078,48.9141],[-95.3085,48.9146],[-95.3092,48.9149],[-95.3093,48.9149],[-95.3102,48.9155],[-95.3109,48.9163],[-95.3115,48.9172],[-95.3119,48.9178],[-95.3126,48.919],[-95.3132,48.9198],[-95.3141,48.921],[-95.315,48.9222],[-95.3168,48.9245],[-95.3195,48.9285],[-95.3208,48.9305],[-95.3209,48.9307],[-95.3222,48.9327],[-95.3228,48.9344],[-95.3223,48.9355],[-95.3225,48.9358],[-95.3229,48.9373],[-95.3231,48.9389],[-95.3228,48.9403],[-95.3225,48.9409],[-95.3219,48.9412],[-95.3189,48.9419],[-95.3181,48.9421],[-95.3168,48.9431],[-95.3154,48.9448],[-95.3148,48.9452],[-95.3141,48.9457],[-95.3131,48.946],[-95.3114,48.9461],[-95.3102,48.9463],[-95.3095,48.9463],[-95.3088,48.9464],[-95.3086,48.9465],[-95.3086,48.9469],[-95.3085,48.947],[-95.3078,48.9466],[-95.3074,48.9465],[-95.3071,48.9466],[-95.3071,48.9469],[-95.3079,48.9474],[-95.3092,48.9477],[-95.3096,48.9478],[-95.3103,48.948],[-95.3104,48.9484],[-95.3103,48.9485],[-95.31,48.9485],[-95.3099,48.9484],[-95.3096,48.9482],[-95.3094,48.9481],[-95.3081,48.948],[-95.3071,48.9477],[-95.3062,48.9472],[-95.3062,48.9472],[-95.3061,48.9469],[-95.3062,48.9463],[-95.3063,48.9462],[-95.3069,48.9456],[-95.3069,48.9455],[-95.3068,48.9454],[-95.3061,48.9454],[-95.3053,48.9459],[-95.305,48.9462],[-95.3046,48.947],[-95.3046,48.9482],[-95.3052,48.9495],[-95.3061,48.9502],[-95.3079,48.9509],[-95.3089,48.9511],[-95.3097,48.951],[-95.3104,48.951],[-95.3108,48.9512],[-95.3115,48.952],[-95.312,48.9524],[-95.3126,48.9524],[-95.3129,48.9523],[-95.3129,48.9521],[-95.3119,48.9507],[-95.3119,48.9502],[-95.3123,48.9502],[-95.3125,48.9503],[-95.3131,48.9503],[-95.3141,48.9508],[-95.3151,48.951],[-95.3154,48.9513],[-95.3177,48.9525],[-95.3181,48.9531],[-95.3182,48.9535],[-95.3177,48.9545],[-95.3175,48.9552],[-95.3179,48.9559],[-95.3188,48.9562],[-95.3191,48.9569],[-95.3202,48.9581],[-95.3206,48.959],[-95.3206,48.9595],[-95.3206,48.9598],[-95.3202,48.9606],[-95.3193,48.9622],[-95.3193,48.964],[-95.3198,48.9643],[-95.3201,48.9648],[-95.3207,48.9669],[-95.3212,48.9672],[-95.3227,48.9685],[-95.3232,48.9692],[-95.3241,48.9703],[-95.3247,48.972],[-95.3248,48.9728],[-95.3249,48.9738],[-95.325,48.9743],[-95.3253,48.976],[-95.3257,48.9784],[-95.3255,48.9789],[-95.3256,48.98],[-95.3257,48.9814],[-95.3253,48.9832],[-95.3245,48.985],[-95.3242,48.9859],[-95.3227,48.9884],[-95.3224,48.9889],[-95.3206,48.9921],[-95.3204,48.9924],[-95.3191,48.9941],[-95.3181,48.995],[-95.3178,48.9958],[-95.3178,48.9961],[-95.3179,48.9961],[-95.3182,48.996],[-95.3187,48.9956],[-95.3191,48.9953],[-95.3197,48.9954],[-95.3201,48.9956],[-95.3206,48.9961],[-95.3204,48.9964],[-95.3202,48.9973],[-95.3204,48.9976],[-95.3224,48.9984],[-95.3231,48.999]]],"type":"Polygon"},"id":"39","properties":{"Area":4608320923.49768,"CTYONLY_":2,"Code":"LOTW","LASTMOD":"1976-07-04T12:00:00Z","Name":"Lake of the Woods","Perimiter":388250.14572},"type":"Feature"},{"geometry":{"coordinates":[[[-96.4054,49.0001],[-96.4054,48.9947],[-96.4054,48.994],[-96.4054,48.9803],[-96.4054,48.9793],[-96.4053,48.9705],[-96.4053,48.9658],[-96.4053,48.9648],[-96.4053,48.9515],[-96.4053,48.9504],[-96.4053,48.9371],[-96.4053,48.936],[-96.4054,48.9225],[-96.4054,48.9214],[-96.4053,48.9137],[-96.4053,48.9081],[-96.4053,48.9068],[-96.405,48.8926],[-96.405,48.878],[-96.4047,48.8635],[-96.4045,48.8491],[-96.4043,48.8343],[-96.4042,48.8198],[-96.4042,48.8048],[-96.4042,48.7903],[-96.4045,48.7758],[-96.4047,48.7607],[-96.4048,48.7465],[-96.4048,48.7318],[-96.4049,48.7172],[-96.388,48.7172],[-96.3873,48.7172],[-96.3866,48.703],[-96.3874,48.6887],[-96.3871,48.6741],[-96.3877,48.6599],[-96.3879,48.6454],[-96.388,48.6313],[-96.389,48.6165],[-96.3891,48.6024],[-96.3884,48.5877],[-96.3882,48.5733],[-96.3879,48.5588],[-96.3882,48.5442],[-96.4101,48.544],[-96.4318,48.5438],[-96.4535,48.5436],[-96.4754,48.5435],[-96.4973,48.5434],[-96.518,48.5434],[-96.54,48.5434],[-96.5621,48.5436],[-96.5839,48.5437],[-96.6058,48.5437],[-96.6278,48.5437],[-96.6493,48.5437],[-96.6713,48.5436],[-96.6931,48.5437],[-96.7151,48.5437],[-96.7368,48.5437],[-96.7585,48.5436],[-96.7803,48.5435],[-96.8023,48.5436],[-96.824,48.5436],[-96.8459,48.5434],[-96.8678,48.5433],[-96.8896,48.5433],[-96.9115,48.5432],[-96.9138,48.5433],[-96.9331,48.5435],[-96.9551,48.5437],[-96.9768,48.544],[-96.9985,48.5441],[-97.0194,48.5441],[-97.0416,48.5442],[-97.0635,48.5441],[-97.0852,48.5441],[-97.107,48.544],[-97.1287,48.5439],[-97.1509,48.5439],[-97.1631,48.544],[-97.1637,48.5445],[-97.1659,48.5483],[-97.1662,48.5509],[-97.1661,48.5527],[-97.1654,48.5536],[-97.1645,48.554],[-97.1628,48.5543],[-97.1613,48.5539],[-97.1592,48.5528],[-97.1577,48.5518],[-97.1557,48.5512],[-97.1538,48.5513],[-97.1513,48.5515],[-97.1507,48.5515],[-97.1493,48.5516],[-97.1474,48.5516],[-97.1444,48.5514],[-97.1407,48.5515],[-97.1387,48.5522],[-97.1379,48.553],[-97.1379,48.5542],[-97.1391,48.5554],[-97.141,48.5566],[-97.1426,48.5571],[-97.1464,48.5573],[-97.1505,48.5574],[-97.1515,48.5574],[-97.1551,48.5574],[-97.1578,48.5573],[-97.1606,48.5571],[-97.1631,48.5571],[-97.1646,48.5572],[-97.167,48.5575],[-97.1697,48.5584],[-97.1721,48.5591],[-97.1727,48.5593],[-97.174,48.5599],[-97.1749,48.5606],[-97.1753,48.5614],[-97.1754,48.5623],[-97.1749,48.5631],[-97.1744,48.5639],[-97.1723,48.5648],[-97.1721,48.5648],[-97.1706,48.5652],[-97.1687,48.5655],[-97.167,48.5658],[-97.1651,48.5659],[-97.1613,48.5661],[-97.1541,48.5669],[-97.153,48.5671],[-97.1516,48.5677],[-97.1503,48.5688],[-97.1496,48.5695],[-97.1487,48.5707],[-97.1477,48.5727],[-97.1477,48.5728],[-97.1476,48.5731],[-97.1483,48.5763],[-97.15,48.5775],[-97.1501,48.5775],[-97.1548,48.5779],[-97.1592,48.5785],[-97.1605,48.58],[-97.16,48.5816],[-97.1578,48.5826],[-97.1562,48.5828],[-97.1541,48.5826],[-97.1524,48.5823],[-97.15,48.5815],[-97.1494,48.5813],[-97.1484,48.5811],[-97.1449,48.5815],[-97.1436,48.5824],[-97.1431,48.5834],[-97.1429,48.5838],[-97.142,48.5876],[-97.1418,48.5886],[-97.1415,48.5909],[-97.1422,48.5926],[-97.1433,48.5936],[-97.1451,48.594],[-97.1471,48.594],[-97.1497,48.5937],[-97.1525,48.594],[-97.1536,48.5949],[-97.1535,48.5957],[-97.1527,48.5962],[-97.1524,48.5969],[-97.1516,48.598],[-97.1498,48.5981],[-97.1497,48.5981],[-97.1463,48.5977],[-97.1443,48.5981],[-97.143,48.5987],[-97.1416,48.6002],[-97.1403,48.6021],[-97.14,48.6025],[-97.138,48.6044],[-97.1359,48.6054],[-97.1345,48.6065],[-97.1341,48.6075],[-97.1349,48.6082],[-97.1358,48.6086],[-97.137,48.6088],[-97.1396,48.6086],[-97.1443,48.6078],[-97.1474,48.6081],[-97.1494,48.6089],[-97.1495,48.609],[-97.1505,48.6115],[-97.1501,48.6124],[-97.1493,48.6129],[-97.1478,48.6138],[-97.145,48.6146],[-97.1408,48.6149],[-97.137,48.6144],[-97.134,48.6136],[-97.1319,48.6133],[-97.1309,48.6137],[-97.1289,48.614],[-97.1286,48.6153],[-97.1293,48.6168],[-97.1295,48.617],[-97.1311,48.6184],[-97.1342,48.6199],[-97.1353,48.6212],[-97.1346,48.6224],[-97.133,48.6228],[-97.131,48.6227],[-97.1291,48.6222],[-97.1277,48.6212],[-97.1274,48.621],[-97.1259,48.6195],[-97.1253,48.619],[-97.1243,48.6183],[-97.1231,48.6178],[-97.1216,48.6176],[-97.12,48.6178],[-97.1193,48.6182],[-97.1186,48.6191],[-97.1183,48.6198],[-97.1186,48.6209],[-97.1198,48.6221],[-97.1209,48.6232],[-97.1212,48.6233],[-97.122,48.624],[-97.1228,48.6245],[-97.1236,48.625],[-97.1241,48.6254],[-97.1245,48.6257],[-97.1249,48.6259],[-97.1253,48.6261],[-97.126,48.6264],[-97.1266,48.6266],[-97.1272,48.627],[-97.1279,48.6273],[-97.1288,48.6278],[-97.1296,48.6282],[-97.1302,48.6288],[-97.1305,48.6292],[-97.1307,48.6297],[-97.131,48.6303],[-97.131,48.6304],[-97.131,48.6308],[-97.131,48.6315],[-97.1309,48.6317],[-97.1307,48.6321],[-97.1304,48.6325],[-97.1301,48.6326],[-97.1297,48.6328],[-97.1293,48.6329],[-97.129,48.633],[-97.1281,48.6332],[-97.128,48.6333],[-97.1275,48.6333],[-97.1253,48.6334],[-97.1235,48.6333],[-97.1216,48.6327],[-97.1181,48.6308],[-97.1176,48.6307],[-97.115,48.6299],[-97.1133,48.63],[-97.1115,48.6303],[-97.1107,48.6308],[-97.1104,48.6309],[-97.1095,48.6315],[-97.1084,48.6327],[-97.1082,48.6344],[-97.1086,48.6363],[-97.1096,48.6389],[-97.1109,48.6407],[-97.1119,48.6416],[-97.1144,48.6433],[-97.115,48.6438],[-97.115,48.6446],[-97.1149,48.6452],[-97.1123,48.6457],[-97.1112,48.6459],[-97.1093,48.6465],[-97.1078,48.6478],[-97.1069,48.6491],[-97.1066,48.6501],[-97.1061,48.6519],[-97.1059,48.6527],[-97.1045,48.6545],[-97.1017,48.6563],[-97.0987,48.6593],[-97.0986,48.6604],[-97.0985,48.6613],[-97.0992,48.6625],[-97.1019,48.6636],[-97.106,48.663],[-97.1062,48.663],[-97.1082,48.6634],[-97.1087,48.6645],[-97.1061,48.6654],[-97.1057,48.6655],[-97.102,48.6667],[-97.1,48.668],[-97.0998,48.6714],[-97.1002,48.675],[-97.1003,48.6757],[-97.1008,48.6787],[-97.1011,48.6808],[-97.1003,48.6828],[-97.0985,48.683],[-97.0946,48.6822],[-97.0926,48.6821],[-97.0904,48.6828],[-97.0898,48.6841],[-97.0899,48.6852],[-97.091,48.6861],[-97.093,48.687],[-97.0951,48.6876],[-97.099,48.6884],[-97.1024,48.6893],[-97.103,48.6894],[-97.1059,48.6903],[-97.1064,48.6905],[-97.1086,48.6915],[-97.111,48.6939],[-97.113,48.6964],[-97.1148,48.6981],[-97.1182,48.7005],[-97.1198,48.7018],[-97.1201,48.7039],[-97.1194,48.7041],[-97.1182,48.7046],[-97.1143,48.7052],[-97.1117,48.7056],[-97.11,48.7063],[-97.1098,48.7083],[-97.1113,48.7094],[-97.1134,48.7101],[-97.1157,48.7105],[-97.1174,48.7111],[-97.119,48.7119],[-97.1212,48.7136],[-97.1223,48.716],[-97.1229,48.7168],[-97.1231,48.7172],[-97.1243,48.7192],[-97.1253,48.7201],[-97.1253,48.7203],[-97.126,48.7207],[-97.1263,48.7212],[-97.1272,48.7215],[-97.128,48.722],[-97.1282,48.7221],[-97.1288,48.7225],[-97.1297,48.7229],[-97.131,48.7233],[-97.1321,48.7238],[-97.1331,48.7242],[-97.1345,48.7248],[-97.136,48.7257],[-97.1369,48.7263],[-97.1375,48.727],[-97.1376,48.7274],[-97.1376,48.7278],[-97.1373,48.7283],[-97.137,48.7284],[-97.1365,48.7285],[-97.136,48.7287],[-97.1352,48.7287],[-97.1341,48.7289],[-97.1333,48.7291],[-97.1328,48.7292],[-97.132,48.7294],[-97.1312,48.7295],[-97.1308,48.7296],[-97.1299,48.7299],[-97.1294,48.7304],[-97.1288,48.7308],[-97.1286,48.7312],[-97.1286,48.7315],[-97.1286,48.7316],[-97.1286,48.7318],[-97.1285,48.7322],[-97.1286,48.7326],[-97.1286,48.7328],[-97.1287,48.7331],[-97.129,48.7335],[-97.1295,48.7339],[-97.1298,48.7341],[-97.1316,48.7347],[-97.1322,48.7348],[-97.1334,48.7347],[-97.1351,48.7345],[-97.1369,48.7345],[-97.1383,48.7345],[-97.1396,48.7347],[-97.1402,48.7349],[-97.1412,48.7354],[-97.1419,48.7359],[-97.1422,48.7367],[-97.1423,48.7372],[-97.1421,48.7381],[-97.1414,48.7385],[-97.1408,48.7387],[-97.1404,48.7389],[-97.1399,48.7393],[-97.1392,48.7397],[-97.1381,48.7408],[-97.1372,48.742],[-97.1366,48.7435],[-97.1365,48.745],[-97.1365,48.7459],[-97.1366,48.7466],[-97.1369,48.748],[-97.1375,48.7492],[-97.1379,48.75],[-97.1385,48.7504],[-97.1391,48.7507],[-97.1396,48.7508],[-97.1401,48.7509],[-97.141,48.751],[-97.142,48.751],[-97.143,48.7509],[-97.1444,48.7507],[-97.1457,48.7506],[-97.1466,48.7505],[-97.1476,48.7505],[-97.1491,48.7506],[-97.1497,48.7508],[-97.1503,48.7509],[-97.1515,48.7515],[-97.1521,48.752],[-97.153,48.7529],[-97.1539,48.7542],[-97.1545,48.7553],[-97.1547,48.7558],[-97.1548,48.7562],[-97.1548,48.7569],[-97.1548,48.7576],[-97.1546,48.758],[-97.1542,48.7587],[-97.1535,48.7593],[-97.1528,48.7598],[-97.1519,48.7601],[-97.1508,48.7605],[-97.1503,48.7606],[-97.1501,48.7607],[-97.1475,48.7616],[-97.1473,48.7617],[-97.1469,48.762],[-97.1462,48.7626],[-97.1461,48.7628],[-97.1459,48.7633],[-97.1456,48.7643],[-97.1456,48.765],[-97.146,48.7658],[-97.1476,48.7673],[-97.1487,48.7681],[-97.15,48.7692],[-97.1501,48.7693],[-97.1506,48.77],[-97.1512,48.7712],[-97.1519,48.7721],[-97.1525,48.7727],[-97.1529,48.7728],[-97.1559,48.7731],[-97.1567,48.7732],[-97.1578,48.7735],[-97.1582,48.7737],[-97.1587,48.7742],[-97.1589,48.7746],[-97.159,48.7751],[-97.159,48.7751],[-97.159,48.7754],[-97.1589,48.776],[-97.1584,48.7766],[-97.1579,48.7769],[-97.1573,48.7772],[-97.1557,48.7776],[-97.1544,48.7778],[-97.1534,48.778],[-97.1522,48.7783],[-97.1509,48.7787],[-97.1501,48.7789],[-97.1497,48.779],[-97.1483,48.7797],[-97.1477,48.7801],[-97.1473,48.7807],[-97.1472,48.7811],[-97.1473,48.7816],[-97.1478,48.7821],[-97.1486,48.7824],[-97.1495,48.7826],[-97.1501,48.7826],[-97.1503,48.7826],[-97.1513,48.7825],[-97.1533,48.7824],[-97.1547,48.7824],[-97.1559,48.7825],[-97.1571,48.7827],[-97.1583,48.783],[-97.1591,48.7834],[-97.1595,48.7838],[-97.1597,48.7843],[-97.1598,48.7848],[-97.1596,48.7853],[-97.1593,48.786],[-97.1591,48.7863],[-97.1586,48.7869],[-97.1577,48.7877],[-97.1574,48.7882],[-97.1573,48.7884],[-97.1572,48.7887],[-97.1571,48.7894],[-97.157,48.7895],[-97.157,48.7901],[-97.1572,48.7906],[-97.1575,48.7909],[-97.1581,48.7912],[-97.1586,48.7913],[-97.1592,48.7915],[-97.1595,48.7915],[-97.1611,48.7915],[-97.1618,48.7914],[-97.1645,48.7911],[-97.1648,48.7911],[-97.1657,48.7911],[-97.1664,48.7912],[-97.1672,48.7913],[-97.1714,48.7921],[-97.1718,48.7923],[-97.1721,48.7924],[-97.1731,48.7929],[-97.1737,48.7933],[-97.174,48.7937],[-97.1741,48.7942],[-97.1742,48.7947],[-97.1742,48.7951],[-97.1739,48.7954],[-97.1734,48.7958],[-97.1726,48.7963],[-97.1717,48.7966],[-97.1716,48.7966],[-97.171,48.7967],[-97.1701,48.7967],[-97.1688,48.7966],[-97.1673,48.7964],[-97.1665,48.7962],[-97.1654,48.7962],[-97.1648,48.7962],[-97.1638,48.7963],[-97.1631,48.7966],[-97.1625,48.7969],[-97.162,48.7974],[-97.1617,48.7979],[-97.1617,48.7984],[-97.1619,48.7988],[-97.1621,48.7994],[-97.1626,48.8001],[-97.1633,48.8007],[-97.1642,48.8011],[-97.1652,48.8014],[-97.166,48.8015],[-97.1668,48.8016],[-97.1675,48.8016],[-97.1685,48.8016],[-97.1698,48.8013],[-97.1706,48.8011],[-97.1714,48.8008],[-97.1715,48.8008],[-97.1724,48.8004],[-97.1731,48.8],[-97.1742,48.7992],[-97.175,48.7986],[-97.1754,48.7983],[-97.1757,48.798],[-97.1761,48.7977],[-97.1768,48.7974],[-97.1773,48.7973],[-97.1779,48.7972],[-97.1787,48.7972],[-97.1795,48.7972],[-97.1801,48.7973],[-97.1807,48.7975],[-97.1811,48.7978],[-97.1815,48.7982],[-97.1816,48.7986],[-97.1817,48.7991],[-97.1815,48.7995],[-97.1813,48.8],[-97.1808,48.8004],[-97.1801,48.8008],[-97.1791,48.8012],[-97.1779,48.8015],[-97.1769,48.8017],[-97.1764,48.8018],[-97.1756,48.8021],[-97.1748,48.8023],[-97.1725,48.8032],[-97.1713,48.8036],[-97.171,48.8037],[-97.1706,48.8039],[-97.1694,48.8043],[-97.1682,48.8046],[-97.1675,48.8048],[-97.1666,48.805],[-97.1655,48.8052],[-97.1638,48.8055],[-97.161,48.8059],[-97.1605,48.8061],[-97.1597,48.8064],[-97.159,48.8067],[-97.1583,48.8072],[-97.1579,48.8077],[-97.1577,48.8082],[-97.1576,48.8089],[-97.1578,48.8098],[-97.158,48.8104],[-97.1586,48.811],[-97.159,48.8111],[-97.161,48.8117],[-97.1617,48.8119],[-97.1625,48.812],[-97.1636,48.8121],[-97.1644,48.8121],[-97.1651,48.812],[-97.1666,48.8118],[-97.168,48.8116],[-97.169,48.8114],[-97.17,48.8114],[-97.1713,48.8115],[-97.1715,48.8115],[-97.1726,48.8117],[-97.1731,48.8118],[-97.174,48.8122],[-97.1761,48.8132],[-97.1776,48.8141],[-97.1784,48.8145],[-97.1797,48.8149],[-97.1807,48.8151],[-97.1821,48.8153],[-97.1828,48.8153],[-97.184,48.8152],[-97.1848,48.8151],[-97.186,48.8147],[-97.1868,48.8145],[-97.1873,48.8143],[-97.1879,48.8143],[-97.1883,48.8143],[-97.1889,48.8143],[-97.1894,48.8144],[-97.1898,48.8146],[-97.1901,48.8148],[-97.1903,48.8153],[-97.1904,48.8156],[-97.1903,48.8159],[-97.19,48.8163],[-97.1893,48.8167],[-97.1885,48.8171],[-97.1879,48.8173],[-97.1866,48.8176],[-97.1857,48.8177],[-97.1847,48.8179],[-97.184,48.8181],[-97.1833,48.8184],[-97.1817,48.8189],[-97.1809,48.8193],[-97.1801,48.8199],[-97.1793,48.8207],[-97.1787,48.8216],[-97.178,48.8232],[-97.1777,48.824],[-97.1776,48.8245],[-97.1777,48.8249],[-97.178,48.8255],[-97.1782,48.8258],[-97.1786,48.8262],[-97.1794,48.8268],[-97.1822,48.8288],[-97.1837,48.8299],[-97.1841,48.8304],[-97.1847,48.8314],[-97.1848,48.8319],[-97.1849,48.8326],[-97.1849,48.8327],[-97.1848,48.833],[-97.1846,48.8336],[-97.1842,48.8341],[-97.1837,48.8345],[-97.183,48.8348],[-97.1822,48.835],[-97.1813,48.8351],[-97.1799,48.8352],[-97.1783,48.8353],[-97.1779,48.8354],[-97.1772,48.8356],[-97.1757,48.8362],[-97.1753,48.8364],[-97.1747,48.8369],[-97.1742,48.8373],[-97.1739,48.8378],[-97.1738,48.8384],[-97.1738,48.839],[-97.1739,48.8406],[-97.1743,48.8427],[-97.1747,48.8438],[-97.175,48.8442],[-97.1755,48.8447],[-97.1761,48.8452],[-97.1767,48.8455],[-97.1771,48.8456],[-97.1779,48.8458],[-97.1795,48.8459],[-97.1808,48.846],[-97.1817,48.8462],[-97.1823,48.8464],[-97.1827,48.8468],[-97.1829,48.847],[-97.1829,48.8471],[-97.1829,48.8473],[-97.1826,48.8476],[-97.1821,48.8479],[-97.1816,48.848],[-97.1809,48.8481],[-97.1793,48.8482],[-97.178,48.8483],[-97.1767,48.8484],[-97.1759,48.8486],[-97.1753,48.8487],[-97.1747,48.849],[-97.1742,48.8493],[-97.1737,48.8497],[-97.1733,48.8502],[-97.173,48.8506],[-97.173,48.8508],[-97.173,48.8511],[-97.173,48.8516],[-97.1732,48.8522],[-97.1737,48.8527],[-97.1746,48.8534],[-97.1771,48.855],[-97.1784,48.8561],[-97.1786,48.8563],[-97.179,48.8569],[-97.1793,48.8576],[-97.1794,48.8583],[-97.1794,48.859],[-97.1792,48.8606],[-97.179,48.8615],[-97.179,48.862],[-97.1791,48.8626],[-97.1794,48.863],[-97.1801,48.8636],[-97.1811,48.864],[-97.1818,48.8641],[-97.1827,48.8641],[-97.1839,48.864],[-97.1855,48.8637],[-97.1871,48.8633],[-97.1877,48.8631],[-97.1883,48.8631],[-97.1891,48.8631],[-97.1896,48.8633],[-97.19,48.8635],[-97.1903,48.8639],[-97.1905,48.8644],[-97.1905,48.8648],[-97.1904,48.8651],[-97.1901,48.8657],[-97.1899,48.8661],[-97.1895,48.8665],[-97.189,48.867],[-97.1884,48.8675],[-97.1851,48.8694],[-97.1813,48.8718],[-97.1788,48.8736],[-97.1785,48.8738],[-97.1782,48.8741],[-97.1781,48.8743],[-97.1779,48.8745],[-97.1778,48.8747],[-97.1777,48.8749],[-97.1777,48.875],[-97.1778,48.875],[-97.1778,48.8754],[-97.1779,48.8757],[-97.1782,48.8761],[-97.1786,48.8765],[-97.1792,48.8769],[-97.1798,48.8771],[-97.1808,48.8772],[-97.1823,48.8772],[-97.1852,48.8768],[-97.1869,48.8765],[-97.1881,48.8765],[-97.1891,48.8766],[-97.1904,48.8769],[-97.1933,48.8779],[-97.1944,48.8783],[-97.1957,48.8788],[-97.1972,48.8794],[-97.1981,48.8799],[-97.1988,48.8805],[-97.1995,48.8812],[-97.1999,48.8818],[-97.1999,48.8821],[-97.2,48.8827],[-97.1998,48.8832],[-97.1997,48.8836],[-97.199,48.8845],[-97.1978,48.8859],[-97.1975,48.8865],[-97.1974,48.8868],[-97.1973,48.8872],[-97.1973,48.8874],[-97.1974,48.8877],[-97.1975,48.8881],[-97.1983,48.8889],[-97.2002,48.8903],[-97.2004,48.8904],[-97.2009,48.8908],[-97.2014,48.8912],[-97.2017,48.8915],[-97.2017,48.8919],[-97.2016,48.8922],[-97.2013,48.8925],[-97.201,48.8926],[-97.2001,48.8926],[-97.1994,48.8926],[-97.1985,48.8925],[-97.198,48.8924],[-97.1973,48.892],[-97.1957,48.8916],[-97.1946,48.8915],[-97.1944,48.8914],[-97.1937,48.8914],[-97.1927,48.8915],[-97.1921,48.8917],[-97.1916,48.8919],[-97.1905,48.8926],[-97.1901,48.8932],[-97.1898,48.8938],[-97.1897,48.8944],[-97.1897,48.8947],[-97.1898,48.8951],[-97.1899,48.8954],[-97.1903,48.896],[-97.1911,48.8967],[-97.1919,48.8974],[-97.1925,48.8979],[-97.1935,48.8985],[-97.1941,48.8988],[-97.1945,48.8989],[-97.1966,48.8997],[-97.1992,48.9004],[-97.2009,48.9009],[-97.2022,48.9013],[-97.2048,48.9018],[-97.2055,48.902],[-97.207,48.9025],[-97.2076,48.9027],[-97.2082,48.9029],[-97.2088,48.9032],[-97.2093,48.9036],[-97.21,48.904],[-97.2105,48.9044],[-97.211,48.905],[-97.2114,48.9056],[-97.2122,48.9069],[-97.2125,48.9075],[-97.2127,48.9082],[-97.2127,48.909],[-97.2125,48.9099],[-97.212,48.911],[-97.2116,48.9121],[-97.2111,48.913],[-97.2108,48.914],[-97.2106,48.9148],[-97.2106,48.9153],[-97.2109,48.9162],[-97.2111,48.9167],[-97.2115,48.9172],[-97.2118,48.9175],[-97.2122,48.9177],[-97.2129,48.9181],[-97.2149,48.9187],[-97.2163,48.9191],[-97.2164,48.9191],[-97.2171,48.9194],[-97.2179,48.9198],[-97.2189,48.9205],[-97.2196,48.9215],[-97.2198,48.9222],[-97.2199,48.923],[-97.2197,48.9237],[-97.2191,48.9249],[-97.2183,48.9262],[-97.2172,48.9277],[-97.2163,48.9286],[-97.2159,48.9289],[-97.2149,48.9301],[-97.2146,48.9304],[-97.2145,48.9307],[-97.2144,48.931],[-97.2145,48.9314],[-97.2145,48.9316],[-97.2148,48.9319],[-97.2154,48.9325],[-97.2159,48.9327],[-97.2162,48.9328],[-97.217,48.9328],[-97.2181,48.9327],[-97.2198,48.9325],[-97.2208,48.9325],[-97.2214,48.9325],[-97.2218,48.9326],[-97.2237,48.9332],[-97.2245,48.9337],[-97.2249,48.9339],[-97.225,48.934],[-97.2252,48.9342],[-97.2254,48.9345],[-97.2257,48.9349],[-97.226,48.9353],[-97.2263,48.936],[-97.2267,48.9376],[-97.227,48.9389],[-97.2271,48.9398],[-97.2271,48.941],[-97.227,48.9418],[-97.2266,48.9432],[-97.2264,48.9441],[-97.2263,48.9445],[-97.2264,48.9452],[-97.2265,48.9456],[-97.227,48.9462],[-97.2273,48.9465],[-97.2276,48.9467],[-97.2279,48.9467],[-97.2284,48.9468],[-97.2304,48.9465],[-97.2309,48.9464],[-97.2313,48.9464],[-97.2326,48.9466],[-97.2331,48.9468],[-97.2338,48.9471],[-97.2342,48.9474],[-97.2343,48.948],[-97.2343,48.9485],[-97.2342,48.9488],[-97.2341,48.9491],[-97.2337,48.95],[-97.2332,48.951],[-97.2328,48.9524],[-97.2323,48.954],[-97.2317,48.9558],[-97.2313,48.9568],[-97.2309,48.9578],[-97.2305,48.9585],[-97.23,48.9591],[-97.2288,48.9603],[-97.2282,48.9609],[-97.2278,48.9613],[-97.2276,48.9619],[-97.2276,48.9624],[-97.2279,48.963],[-97.228,48.9631],[-97.2283,48.9634],[-97.2289,48.9639],[-97.2294,48.9641],[-97.23,48.9642],[-97.2323,48.9646],[-97.2355,48.965],[-97.2368,48.9652],[-97.2375,48.9654],[-97.2382,48.966],[-97.2383,48.9661],[-97.2388,48.9666],[-97.2391,48.9676],[-97.2392,48.9687],[-97.239,48.9696],[-97.2387,48.9706],[-97.2383,48.9715],[-97.2381,48.9723],[-97.238,48.9725],[-97.2379,48.9731],[-97.2378,48.9734],[-97.2378,48.9738],[-97.238,48.9752],[-97.238,48.9763],[-97.2381,48.9771],[-97.238,48.9771],[-97.238,48.9841],[-97.2377,48.9849],[-97.2372,48.9857],[-97.2365,48.9867],[-97.2359,48.9874],[-97.2351,48.9881],[-97.2342,48.989],[-97.2335,48.9895],[-97.2331,48.9898],[-97.2317,48.9904],[-97.2301,48.9911],[-97.2293,48.9914],[-97.229,48.9916],[-97.2279,48.9921],[-97.2274,48.9925],[-97.227,48.9929],[-97.2266,48.9933],[-97.2265,48.9938],[-97.2267,48.9941],[-97.227,48.9945],[-97.2273,48.9947],[-97.2287,48.9949],[-97.2304,48.995],[-97.2317,48.9951],[-97.2324,48.9952],[-97.2335,48.9956],[-97.2338,48.9959],[-97.2341,48.9966],[-97.2341,48.997],[-97.234,48.9975],[-97.2337,48.9981],[-97.2332,48.9985],[-97.2323,48.999],[-97.2305,49.0],[-97.2303,49.0001],[-97.2295,49.0005],[-97.2175,49.0005],[-97.2161,49.0005],[-97.2078,49.0005],[-97.2069,49.0005],[-97.1955,49.0005],[-97.1939,49.0005],[-97.1739,49.0005],[-97.1724,49.0005],[-97.1514,49.0005],[-97.1502,49.0005],[-97.1294,49.0004],[-97.1277,49.0004],[-97.1073,49.0004],[-97.1061,49.0004],[-97.0853,49.0004],[-97.084,49.0004],[-97.0633,49.0004],[-97.062,49.0004],[-97.0412,49.0004],[-97.0401,49.0004],[-97.0192,49.0004],[-97.0183,49.0004],[-96.9971,49.0004],[-96.9961,49.0004],[-96.9751,49.0003],[-96.9738,49.0003],[-96.953,49.0003],[-96.9518,49.0003],[-96.931,49.0003],[-96.9299,49.0003],[-96.909,49.0003],[-96.9078,49.0003],[-96.8869,49.0003],[-96.8856,49.0003],[-96.8649,49.0003],[-96.864,49.0003],[-96.8429,49.0003],[-96.8415,49.0003],[-96.8208,49.0003],[-96.8197,49.0003],[-96.8023,49.0002],[-96.8005,49.0002],[-96.8003,49.0002],[-96.7988,49.0002],[-96.7787,49.0002],[-96.7768,49.0002],[-96.7567,49.0002],[-96.7547,49.0002],[-96.7348,49.0002],[-96.7327,49.0002],[-96.7127,49.0002],[-96.7107,49.0002],[-96.6905,49.0002],[-96.6886,49.0002],[-96.6695,49.0002],[-96.6665,49.0002],[-96.6482,49.0002],[-96.6445,49.0002],[-96.6243,49.0002],[-96.6225,49.0002],[-96.6021,49.0002],[-96.6004,49.0002],[-96.58,49.0002],[-96.5784,49.0002],[-96.558,49.0002],[-96.5563,49.0002],[-96.536,49.0002],[-96.5342,49.0002],[-96.5154,49.0002],[-96.5123,49.0002],[-96.4933,49.0002],[-96.49,49.0002],[-96.471,49.0001],[-96.4664,49.0001],[-96.4496,49.0001],[-96.4492,49.0001],[-96.4491,49.0001],[-96.446,49.0001],[-96.4273,49.0001],[-96.4224,49.0001],[-96.4054,49.0001]]],"type":"Polygon"},"id":"35","properties":{"Area":2862183702.23055,"CTYONLY_":3,"Code":"KITT","LASTMOD":"1999-12-31T23:59:59Z","Name":"Kittson","Perimiter":263017.48277},"type":"Feature"},{"geometry":{"coordinates":[[[-96.4054,49.0001],[-96.4019,49.0001],[-96.3825,49.0001],[-96.3783,49.0001],[-96.3606,49.0001],[-96.3579,49.0001],[-96.3385,49.0001],[-96.3343,49.0001],[-96.3166,49.0001],[-96.3138,49.0001],[-96.2945,49.0001],[-96.2902,49.0001],[-96.2725,49.0001],[-96.2698,49.0001],[-96.2494,49.0001],[-96.2461,49.0001],[-96.2274,49.0001],[-96.2257,49.0001],[-96.2057,49.0001],[-96.2021,49.0001],[-96.1837,49.0],[-96.18,49.0],[-96.1617,49.0],[-96.1579,49.0],[-96.1401,49.0],[-96.1359,49.0],[-96.1176,49.0],[-96.1139,49.0],[-96.0957,49.0],[-96.0919,49.0],[-96.0738,49.0],[-96.07,49.0],[-96.0517,49.0],[-96.048,49.0],[-96.0298,49.0],[-96.026,49.0],[-96.0083,49.0],[-96.0045,49.0],[-95.9868,49.0],[-95.9784,49.0],[-95.9776,49.0],[-95.9755,49.0],[-95.9648,48.9999],[-95.9464,48.9999],[-95.943,48.9999],[-95.9225,48.9999],[-95.9211,48.9999],[-95.899,48.9998],[-95.883,48.9998],[-95.8771,48.9998],[-95.8564,48.9998],[-95.855,48.9998],[-95.8342,48.9998],[-95.8184,48.9997],[-95.8126,48.9997],[-95.7906,48.9997],[-95.7833,48.9997],[-95.7684,48.9997],[-95.7479,48.9996],[-95.7466,48.9996],[-95.7253,48.9996],[-95.7066,48.9996],[-95.7032,48.9996],[-95.681,48.9995],[-95.6654,48.9995],[-95.6596,48.9995],[-95.659,48.9995],[-95.6401,48.9995],[-95.6369,48.9995],[-95.6205,48.9994],[-95.615,48.9994],[-95.5948,48.9994],[-95.585,48.9994],[-95.573,48.9994],[-95.551,48.9993],[-95.5495,48.9993],[-95.5294,48.9993],[-95.5164,48.9993],[-95.5072,48.9993],[-95.4849,48.9992],[-95.4834,48.9992],[-95.4635,48.9992],[-95.4508,48.9992],[-95.4418,48.9992],[-95.4245,48.9991],[-95.4197,48.9991],[-95.3977,48.9991],[-95.3953,48.9991],[-95.3765,48.9991],[-95.3759,48.9991],[-95.3753,48.9991],[-95.3542,48.999],[-95.3513,48.999],[-95.3326,48.999],[-95.3286,48.999],[-95.3231,48.999],[-95.3224,48.9984],[-95.3204,48.9976],[-95.3202,48.9973],[-95.3204,48.9964],[-95.3206,48.9961],[-95.3201,48.9956],[-95.3197,48.9954],[-95.3191,48.9953],[-95.3187,48.9956],[-95.3182,48.996],[-95.3179,48.9961],[-95.3178,48.9961],[-95.3178,48.9958],[-95.3181,48.995],[-95.3191,48.9941],[-95.3204,48.9924],[-95.3206,48.9921],[-95.3224,48.9889],[-95.3227,48.9884],[-95.3242,48.9859],[-95.3245,48.985],[-95.3253,48.9832],[-95.3257,48.9814],[-95.3256,48.98],[-95.3255,48.9789],[-95.3257,48.9784],[-95.3253,48.976],[-95.325,48.9743],[-95.3249,48.9738],[-95.3248,48.9728],[-95.3247,48.972],[-95.3241,48.9703],[-95.3232,48.9692],[-95.3227,48.9685],[-95.3212,48.9672],[-95.3207,48.9669],[-95.3201,48.9648],[-95.3198,48.9643],[-95.3193,48.964],[-95.3193,48.9622],[-95.3202,48.9606],[-95.3206,48.9598],[-95.3206,48.9595],[-95.3206,48.959],[-95.3202,48.9581],[-95.3191,48.9569],[-95.3188,48.9562],[-95.3179,48.9559],[-95.3175,48.9552],[-95.3177,48.9545],[-95.3182,48.9535],[-95.3181,48.9531],[-95.3177,48.9525],[-95.3154,48.9513],[-95.3151,48.951],[-95.3141,48.9508],[-95.3131,48.9503],[-95.3125,48.9503],[-95.3123,48.9502],[-95.3119,48.9502],[-95.3119,48.9507],[-95.3129,48.9521],[-95.3129,48.9523],[-95.3126,48.9524],[-95.312,48.9524],[-95.3115,48.952],[-95.3108,48.9512],[-95.3104,48.951],[-95.3097,48.951],[-95.3089,48.9511],[-95.3079,48.9509],[-95.3061,48.9502],[-95.3052,48.9495],[-95.3046,48.9482],[-95.3046,48.947],[-95.305,48.9462],[-95.3053,48.9459],[-95.3061,48.9454],[-95.3068,48.9454],[-95.3069,48.9455],[-95.3069,48.9456],[-95.3063,48.9462],[-95.3062,48.9463],[-95.3061,48.9469],[-95.3062,48.9472],[-95.3062,48.9472],[-95.3071,48.9477],[-95.3081,48.948],[-95.3094,48.9481],[-95.3096,48.9482],[-95.3099,48.9484],[-95.31,48.9485],[-95.3103,48.9485],[-95.3104,48.9484],[-95.3103,48.948],[-95.3096,48.9478],[-95.3092,48.9477],[-95.3079,48.9474],[-95.3071,48.9469],[-95.3071,48.9466],[-95.3074,48.9465],[-95.3078,48.9466],[-95.3085,48.947],[-95.3086,48.9469],[-95.3086,48.9465],[-95.3088,48.9464],[-95.3095,48.9463],[-95.3102,48.9463],[-95.3114,48.9461],[-95.3131,48.946],[-95.3141,48.9457],[-95.3148,48.9452],[-95.3154,48.9448],[-95.3168,48.9431],[-95.3181,48.9421],[-95.3189,48.9419],[-95.3219,48.9412],[-95.3225,48.9409],[-95.3228,48.9403],[-95.3231,48.9389],[-95.3229,48.9373],[-95.3225,48.9358],[-95.3223,48.9355],[-95.3228,48.9344],[-95.3222,48.9327],[-95.3209,48.9307],[-95.3208,48.9305],[-95.3195,48.9285],[-95.3168,48.9245],[-95.315,48.9222],[-95.3141,48.921],[-95.3132,48.9198],[-95.3126,48.919],[-95.3119,48.9178],[-95.3115,48.9172],[-95.3109,48.9163],[-95.3102,48.9155],[-95.3093,48.9149],[-95.3092,48.9149],[-95.3085,48.9146],[-95.3078,48.9141],[-95.3074,48.9135],[-95.3064,48.9129],[-95.3061,48.9128],[-95.3059,48.9127],[-95.3043,48.9119],[-95.3038,48.9114],[-95.3027,48.91],[-95.3017,48.9093],[-95.2999,48.9086],[-95.2978,48.9083],[-95.2973,48.9081],[-95.2973,48.908],[-95.2973,48.9077],[-95.2976,48.9074],[-95.2977,48.9073],[-95.2978,48.9073],[-95.2978,48.9072],[-95.2978,48.9072],[-95.2979,48.9072],[-95.2979,48.9072],[-95.2979,48.9071],[-95.298,48.9071],[-95.298,48.9071],[-95.298,48.9071],[-95.2981,48.907],[-95.2982,48.9068],[-95.2983,48.9068],[-95.2985,48.9065],[-95.2985,48.9064],[-95.2986,48.9063],[-95.2988,48.906],[-95.2989,48.906],[-95.2991,48.9057],[-95.2992,48.9055],[-95.2994,48.9053],[-95.2996,48.9051],[-95.2997,48.905],[-95.2999,48.9048],[-95.2999,48.9048],[-95.2999,48.9048],[-95.3,48.9047],[-95.3,48.9047],[-95.3001,48.9047],[-95.3001,48.9046],[-95.3002,48.9045],[-95.3005,48.904],[-95.2993,48.9035],[-95.2983,48.9028],[-95.298,48.9027],[-95.2976,48.9026],[-95.2967,48.9027],[-95.2949,48.9028],[-95.2941,48.9027],[-95.2937,48.9023],[-95.2935,48.902],[-95.2927,48.9019],[-95.2914,48.9019],[-95.2909,48.9017],[-95.2908,48.9016],[-95.2907,48.9014],[-95.2906,48.9011],[-95.2911,48.9008],[-95.2911,48.9006],[-95.2901,48.9003],[-95.2896,48.9],[-95.289,48.8994],[-95.2882,48.8981],[-95.2879,48.8979],[-95.2872,48.8977],[-95.287,48.8976],[-95.2865,48.8975],[-95.2861,48.8976],[-95.2853,48.8977],[-95.2839,48.8975],[-95.2813,48.8967],[-95.2803,48.8965],[-95.2796,48.8962],[-95.279,48.8957],[-95.2782,48.8956],[-95.2773,48.8957],[-95.277,48.8958],[-95.2765,48.8962],[-95.2763,48.8963],[-95.2759,48.8962],[-95.2755,48.8959],[-95.2749,48.8956],[-95.2748,48.8951],[-95.2753,48.8943],[-95.2751,48.8938],[-95.2745,48.8931],[-95.2724,48.8921],[-95.2713,48.8915],[-95.268,48.8905],[-95.2677,48.8903],[-95.2674,48.89],[-95.2666,48.8894],[-95.2654,48.8888],[-95.265,48.8886],[-95.2646,48.8885],[-95.2639,48.8883],[-95.2635,48.888],[-95.2627,48.8877],[-95.2585,48.8867],[-95.2585,48.8867],[-95.257,48.8858],[-95.256,48.885],[-95.2548,48.8845],[-95.2517,48.8839],[-95.2507,48.8836],[-95.2502,48.8835],[-95.2496,48.8834],[-95.2485,48.8832],[-95.248,48.8836],[-95.2472,48.8835],[-95.2458,48.8829],[-95.2439,48.8823],[-95.2429,48.8822],[-95.2429,48.8822],[-95.2423,48.8821],[-95.2407,48.8821],[-95.2391,48.8819],[-95.2381,48.8817],[-95.2356,48.8815],[-95.2335,48.8814],[-95.231,48.8814],[-95.2287,48.8815],[-95.2265,48.8816],[-95.2252,48.8819],[-95.2212,48.883],[-95.2208,48.8831],[-95.2207,48.8831],[-95.22,48.8831],[-95.2193,48.8832],[-95.2188,48.8835],[-95.217,48.8835],[-95.2159,48.8839],[-95.2151,48.884],[-95.2144,48.8843],[-95.2122,48.8842],[-95.2117,48.8847],[-95.2115,48.8847],[-95.2112,48.8848],[-95.2085,48.8846],[-95.2059,48.8848],[-95.2024,48.8852],[-95.2009,48.8855],[-95.2005,48.8856],[-95.1986,48.8855],[-95.1956,48.8862],[-95.1924,48.8865],[-95.1919,48.8866],[-95.1913,48.8868],[-95.1901,48.887],[-95.1889,48.8873],[-95.1877,48.8874],[-95.1863,48.8877],[-95.1851,48.8882],[-95.1819,48.8888],[-95.1797,48.889],[-95.1791,48.889],[-95.1764,48.8893],[-95.173,48.8897],[-95.1701,48.8902],[-95.1674,48.8907],[-95.1648,48.8913],[-95.1641,48.8917],[-95.1618,48.892],[-95.1602,48.892],[-95.1579,48.8919],[-95.1564,48.8919],[-95.1555,48.892],[-95.1528,48.8921],[-95.1508,48.8922],[-95.1483,48.8923],[-95.1469,48.8927],[-95.1459,48.8929],[-95.1438,48.8934],[-95.1436,48.8937],[-95.1404,48.8943],[-95.1381,48.8949],[-95.1355,48.8959],[-95.1351,48.8963],[-95.1348,48.8963],[-95.1343,48.8963],[-95.1337,48.8969],[-95.1322,48.8973],[-95.1312,48.8975],[-95.1252,48.8998],[-95.1239,48.9001],[-95.1233,48.9004],[-95.1228,48.9006],[-95.1214,48.9013],[-95.121,48.9016],[-95.1205,48.9017],[-95.1204,48.9019],[-95.1182,48.9029],[-95.1163,48.9037],[-95.1151,48.9046],[-95.1144,48.9052],[-95.114,48.9061],[-95.1141,48.9064],[-95.1137,48.9069],[-95.1132,48.9071],[-95.113,48.9072],[-95.1126,48.9073],[-95.1107,48.9082],[-95.1096,48.9089],[-95.108,48.9099],[-95.1056,48.9113],[-95.1042,48.9121],[-95.1032,48.9127],[-95.102,48.9132],[-95.1008,48.9142],[-95.0981,48.9159],[-95.098,48.916],[-95.0975,48.9164],[-95.0971,48.9172],[-95.097,48.9176],[-95.0961,48.9181],[-95.0946,48.9191],[-95.0944,48.9193],[-95.0927,48.9204],[-95.0919,48.9207],[-95.0914,48.9208],[-95.0914,48.916],[-95.0912,48.9014],[-95.0911,48.8869],[-95.0908,48.8724],[-95.0908,48.858],[-95.0907,48.8436],[-95.0908,48.8291],[-95.0909,48.8147],[-95.0903,48.8],[-95.0903,48.7855],[-95.0903,48.7711],[-95.0901,48.7566],[-95.0901,48.7421],[-95.0899,48.7277],[-95.0898,48.713],[-95.1046,48.7129],[-95.1104,48.7129],[-95.1119,48.7129],[-95.1259,48.7129],[-95.1297,48.713],[-95.1333,48.713],[-95.1477,48.7129],[-95.1554,48.7129],[-95.1697,48.7129],[-95.1773,48.713],[-95.1917,48.713],[-95.1991,48.713],[-95.2112,48.713],[-95.2206,48.713],[-95.2331,48.713],[-95.2427,48.713],[-95.255,48.713],[-95.2645,48.713],[-95.2656,48.713],[-95.2767,48.713],[-95.2866,48.713],[-95.299,48.713],[-95.3051,48.713],[-95.3084,48.713],[-95.3205,48.713],[-95.3302,48.713],[-95.3425,48.7131],[-95.3425,48.6995],[-95.3424,48.6849],[-95.3423,48.6705],[-95.3424,48.6561],[-95.3425,48.6415],[-95.3426,48.6271],[-95.3424,48.6127],[-95.3426,48.5979],[-95.3423,48.5836],[-95.3423,48.5691],[-95.3424,48.5548],[-95.3425,48.5402],[-95.3628,48.5404],[-95.364,48.5403],[-95.3844,48.5402],[-95.386,48.5402],[-95.4061,48.5402],[-95.4078,48.5402],[-95.4279,48.54],[-95.4297,48.5399],[-95.4494,48.5399],[-95.4513,48.5399],[-95.4712,48.5396],[-95.4726,48.5396],[-95.493,48.5392],[-95.495,48.5392],[-95.5143,48.539],[-95.5163,48.539],[-95.5365,48.5389],[-95.5383,48.5389],[-95.558,48.5388],[-95.5603,48.5388],[-95.5801,48.5387],[-95.5821,48.5387],[-95.6023,48.5389],[-95.6232,48.5391],[-95.6447,48.5393],[-95.6666,48.5394],[-95.6886,48.5395],[-95.7102,48.5395],[-95.7322,48.54],[-95.7539,48.5404],[-95.7758,48.5406],[-95.7976,48.5405],[-95.8192,48.5404],[-95.8411,48.5406],[-95.8621,48.5414],[-95.8829,48.5419],[-95.8851,48.542],[-95.8986,48.5421],[-95.9046,48.5422],[-95.9064,48.5422],[-95.9269,48.5421],[-95.9486,48.5425],[-95.9498,48.5425],[-95.9704,48.543],[-95.9936,48.5435],[-96.0157,48.5437],[-96.0374,48.5438],[-96.0592,48.5437],[-96.0812,48.5436],[-96.1026,48.5438],[-96.1264,48.5439],[-96.1486,48.5442],[-96.1702,48.5445],[-96.1921,48.5446],[-96.2141,48.5449],[-96.2358,48.5452],[-96.2576,48.545],[-96.2794,48.5449],[-96.301,48.5448],[-96.3231,48.5446],[-96.3448,48.5444],[-96.3667,48.5443],[-96.3882,48.5442],[-96.3879,48.5588],[-96.3882,48.5733],[-96.3884,48.5877],[-96.3891,48.6024],[-96.389,48.6165],[-96.388,48.6313],[-96.3879,48.6454],[-96.3877,48.6599],[-96.3871,48.6741],[-96.3874,48.6887],[-96.3866,48.703],[-96.3873,48.7172],[-96.388,48.7172],[-96.4049,48.7172],[-96.4048,48.7318],[-96.4048,48.7465],[-96.4047,48.7607],[-96.4045,48.7758],[-96.4042,48.7903],[-96.4042,48.8048],[-96.4042,48.8198],[-96.4043,48.8343],[-96.4045,48.8491],[-96.4047,48.8635],[-96.405,48.878],[-96.405,48.8926],[-96.4053,48.9068],[-96.4053,48.9081],[-96.4053,48.9137],[-96.4054,48.9214],[-96.4054,48.9225],[-96.4053,48.936],[-96.4053,48.9371],[-96.4053,48.9504],[-96.4053,48.9515],[-96.4053,48.9648],[-96.4053,48.9658],[-96.4053,48.9705],[-96.4054,48.9793],[-96.4054,48.9803],[-96.4054,48.994],[-96.4054,48.9947],[-96.4054,49.0001]]],"type":"Polygon"},"id":"68","properties":{"Area":4347098503.12714,"CTYONLY_":4,"Code":"ROSE","LASTMOD":"2001-04-12T09:32:44Z","Name":"Roseau","Perimiter":302590.75293},"type":"Feature"},{"geometry":{"coordinates":[[[-94.4299,48.7012],[-94.4241,48.7053],[-94.4213,48.7086],[-94.4189,48.7103],[-94.4158,48.711],[-94.4081,48.7106],[-94.406,48.7105],[-94.3889,48.712],[-94.3859,48.7119],[-94.384,48.7119],[-94.3801,48.7111],[-94.3687,48.7065],[-94.3646,48.7059],[-94.3533,48.7042],[-94.3431,48.7035],[-94.3429,48.7035],[-94.3287,48.7045],[-94.3214,48.7067],[-94.3088,48.7103],[-94.2995,48.709],[-94.2911,48.7079],[-94.2829,48.7057],[-94.2781,48.7024],[-94.2745,48.6999],[-94.2694,48.6995],[-94.2644,48.699],[-94.261,48.6966],[-94.258,48.6918],[-94.2565,48.6901],[-94.2529,48.6864],[-94.2521,48.685],[-94.2514,48.6837],[-94.2507,48.6782],[-94.2527,48.6707],[-94.253,48.6693],[-94.2548,48.664],[-94.2546,48.6615],[-94.2509,48.657],[-94.2499,48.6563],[-94.2467,48.6542],[-94.2445,48.6535],[-94.2343,48.6524],[-94.2335,48.6524],[-94.2242,48.6495],[-94.2144,48.6494],[-94.2124,48.6496],[-94.1996,48.651],[-94.1915,48.6506],[-94.1886,48.6504],[-94.1689,48.6483],[-94.1678,48.6482],[-94.1574,48.6458],[-94.1522,48.6455],[-94.1458,48.6458],[-94.1391,48.646],[-94.126,48.6444],[-94.1235,48.6444],[-94.11,48.6443],[-94.1023,48.6455],[-94.0999,48.6459],[-94.0912,48.6437],[-94.0849,48.6441],[-94.0804,48.6442],[-94.0767,48.6442],[-94.0714,48.6459],[-94.0658,48.6462],[-94.0642,48.6438],[-94.0603,48.6431],[-94.0581,48.6434],[-94.0525,48.644],[-94.0432,48.6435],[-94.0393,48.6423],[-94.0364,48.6413],[-94.0356,48.6411],[-94.0295,48.6409],[-94.0153,48.6424],[-94.0069,48.6433],[-94.0007,48.6428],[-93.9931,48.6412],[-93.9897,48.6405],[-93.984,48.6401],[-93.9777,48.6385],[-93.9712,48.6385],[-93.968,48.6385],[-93.9596,48.6372],[-93.953,48.6341],[-93.9497,48.6339],[-93.934,48.6326],[-93.9272,48.6327],[-93.9169,48.6329],[-93.9134,48.6353],[-93.9057,48.6346],[-93.9054,48.6345],[-93.8948,48.6324],[-93.8853,48.6318],[-93.8844,48.6318],[-93.8757,48.6319],[-93.8698,48.6311],[-93.8624,48.631],[-93.848,48.6308],[-93.8443,48.6303],[-93.8404,48.6289],[-93.8393,48.6286],[-93.8365,48.6276],[-93.8334,48.6256],[-93.8292,48.6177],[-93.825,48.6136],[-93.8245,48.613],[-93.8214,48.6092],[-93.8182,48.5994],[-93.8175,48.597],[-93.8172,48.5964],[-93.813,48.588],[-93.8103,48.5846],[-93.8063,48.5796],[-93.8041,48.5703],[-93.8041,48.5702],[-93.8051,48.5644],[-93.808,48.5569],[-93.8088,48.5555],[-93.8119,48.5503],[-93.8102,48.5445],[-93.8109,48.5412],[-93.8109,48.541],[-93.818,48.535],[-93.818,48.5346],[-93.8184,48.5315],[-93.8178,48.5306],[-93.8161,48.5285],[-93.8145,48.5273],[-93.8111,48.5247],[-93.803,48.522],[-93.7964,48.5182],[-93.7933,48.5164],[-93.7879,48.5159],[-93.7745,48.5162],[-93.768,48.5164],[-93.7665,48.5164],[-93.7617,48.5166],[-93.7534,48.5158],[-93.7442,48.5175],[-93.739,48.5185],[-93.731,48.5185],[-93.7225,48.5178],[-93.7206,48.5176],[-93.7108,48.5186],[-93.7061,48.5182],[-93.7006,48.517],[-93.693,48.5152],[-93.6866,48.5154],[-93.6791,48.5167],[-93.6778,48.5169],[-93.6593,48.5165],[-93.657,48.5167],[-93.6473,48.5177],[-93.6433,48.519],[-93.6421,48.5199],[-93.6395,48.5218],[-93.6357,48.5285],[-93.6344,48.5293],[-93.6311,48.5313],[-93.6284,48.5319],[-93.6256,48.5315],[-93.6211,48.5264],[-93.6166,48.5238],[-93.6134,48.5228],[-93.6122,48.5225],[-93.6051,48.5231],[-93.5962,48.5287],[-93.5919,48.5299],[-93.5901,48.5305],[-93.581,48.5271],[-93.5761,48.527],[-93.5701,48.528],[-93.5602,48.5297],[-93.5484,48.5294],[-93.5476,48.5294],[-93.5425,48.53],[-93.5366,48.5319],[-93.5269,48.5341],[-93.5263,48.5341],[-93.5244,48.5343],[-93.5171,48.5348],[-93.5047,48.5399],[-93.501,48.5414],[-93.4952,48.5426],[-93.4854,48.5433],[-93.4833,48.5437],[-93.4673,48.5465],[-93.4655,48.5478],[-93.4625,48.5498],[-93.462,48.5505],[-93.4596,48.5537],[-93.4576,48.5598],[-93.4576,48.5621],[-93.4575,48.5672],[-93.4619,48.5731],[-93.4619,48.5734],[-93.4631,48.5767],[-93.4671,48.5885],[-93.4656,48.59],[-93.4654,48.5915],[-93.4654,48.5917],[-93.4627,48.5927],[-93.46,48.5927],[-93.4547,48.5927],[-93.4398,48.5937],[-93.4385,48.5942],[-93.4347,48.5954],[-93.4298,48.5997],[-93.4226,48.6032],[-93.4193,48.6036],[-93.416,48.605],[-93.4152,48.6053],[-93.415,48.6056],[-93.4144,48.6064],[-93.4056,48.6099],[-93.4034,48.61],[-93.4029,48.6077],[-93.4013,48.6079],[-93.3994,48.6055],[-93.3986,48.6045],[-93.3953,48.6038],[-93.3937,48.6041],[-93.3837,48.606],[-93.3724,48.6059],[-93.3714,48.6059],[-93.3672,48.6082],[-93.3619,48.6141],[-93.355,48.6114],[-93.3526,48.6135],[-93.3533,48.615],[-93.3513,48.62],[-93.3505,48.6219],[-93.3486,48.6265],[-93.3276,48.6302],[-93.3057,48.634],[-93.3048,48.6341],[-93.2838,48.6378],[-93.2634,48.6413],[-93.2546,48.6429],[-93.2422,48.6428],[-93.2193,48.6426],[-93.2075,48.6426],[-93.1975,48.6365],[-93.191,48.6325],[-93.184,48.6282],[-93.1783,48.6231],[-93.1754,48.6232],[-93.1531,48.6244],[-93.1319,48.6256],[-93.1104,48.6267],[-93.0903,48.6278],[-93.0884,48.6278],[-93.0886,48.6163],[-93.0895,48.6016],[-93.0898,48.5872],[-93.09,48.5727],[-93.0902,48.5583],[-93.0902,48.5441],[-93.0903,48.5296],[-93.0905,48.5151],[-93.0905,48.501],[-93.091,48.4884],[-93.0911,48.4867],[-93.0914,48.474],[-93.0915,48.4724],[-93.0918,48.4596],[-93.0919,48.458],[-93.092,48.4449],[-93.092,48.4436],[-93.0922,48.4303],[-93.0922,48.429],[-93.0923,48.4147],[-93.0935,48.4147],[-93.0938,48.4024],[-93.094,48.3879],[-93.094,48.3734],[-93.0945,48.3589],[-93.0948,48.3442],[-93.0948,48.3298],[-93.0953,48.3153],[-93.0952,48.3004],[-93.095,48.2862],[-93.0952,48.2716],[-93.0953,48.2576],[-93.0949,48.2426],[-93.0949,48.2425],[-93.0977,48.2426],[-93.0977,48.2271],[-93.0978,48.2126],[-93.0979,48.1981],[-93.0975,48.1836],[-93.097,48.1692],[-93.097,48.1546],[-93.097,48.1402],[-93.0969,48.1259],[-93.0972,48.1114],[-93.097,48.0969],[-93.0968,48.0823],[-93.0965,48.0679],[-93.0965,48.0678],[-93.0892,48.0679],[-93.0892,48.0509],[-93.089,48.0366],[-93.0886,48.022],[-93.0887,48.0075],[-93.0872,47.9932],[-93.088,47.9787],[-93.0809,47.9786],[-93.0809,47.967],[-93.0808,47.9647],[-93.0808,47.9525],[-93.0808,47.9504],[-93.0809,47.938],[-93.0809,47.9356],[-93.0809,47.9235],[-93.0809,47.9212],[-93.0809,47.9088],[-93.0809,47.9067],[-93.0808,47.8945],[-93.0808,47.8922],[-93.1015,47.8927],[-93.1232,47.893],[-93.1448,47.8928],[-93.1656,47.8931],[-93.1671,47.8932],[-93.1871,47.8931],[-93.1893,47.8931],[-93.2087,47.8933],[-93.2115,47.8934],[-93.2331,47.8937],[-93.2532,47.8936],[-93.2745,47.8938],[-93.2962,47.8939],[-93.3169,47.894],[-93.3392,47.8941],[-93.3603,47.8942],[-93.3809,47.8943],[-93.4024,47.8944],[-93.4235,47.8945],[-93.4442,47.8946],[-93.466,47.895],[-93.4874,47.8956],[-93.4892,47.8957],[-93.4933,47.8958],[-93.5085,47.8962],[-93.5105,47.8963],[-93.5297,47.8967],[-93.5303,47.8967],[-93.532,47.8968],[-93.5517,47.8973],[-93.5532,47.8974],[-93.5729,47.8981],[-93.5747,47.8982],[-93.5962,47.8978],[-93.5966,47.8978],[-93.6179,47.8977],[-93.6187,47.8977],[-93.6388,47.8977],[-93.6395,47.8976],[-93.6604,47.8976],[-93.6612,47.8976],[-93.6817,47.8976],[-93.6826,47.8976],[-93.7031,47.8976],[-93.7038,47.8976],[-93.7249,47.8975],[-93.7248,47.8989],[-93.7466,47.8989],[-93.768,47.8991],[-93.7758,47.8991],[-93.7758,47.899],[-93.776,47.8897],[-93.776,47.8842],[-93.7762,47.8753],[-93.7761,47.8697],[-93.7761,47.8607],[-93.7761,47.8553],[-93.7761,47.8464],[-93.7896,47.8465],[-93.7971,47.8466],[-93.8189,47.8467],[-93.8407,47.8468],[-93.8627,47.8469],[-93.8831,47.8471],[-93.9067,47.8471],[-93.9288,47.8475],[-93.9496,47.8475],[-93.9506,47.8475],[-93.971,47.8475],[-93.9725,47.8475],[-93.9927,47.8475],[-93.9942,47.8475],[-94.0141,47.8476],[-94.0161,47.8476],[-94.0375,47.8477],[-94.0591,47.8474],[-94.0807,47.8471],[-94.1022,47.8471],[-94.1239,47.8466],[-94.1448,47.8463],[-94.1657,47.8461],[-94.1822,47.8461],[-94.1871,47.846],[-94.2037,47.846],[-94.2086,47.846],[-94.2252,47.846],[-94.23,47.8461],[-94.2467,47.8462],[-94.2515,47.8462],[-94.2681,47.8462],[-94.2728,47.8462],[-94.2887,47.8462],[-94.3103,47.8458],[-94.3315,47.846],[-94.3532,47.8464],[-94.3747,47.8462],[-94.3964,47.8461],[-94.4185,47.8459],[-94.4186,47.86],[-94.4184,47.8744],[-94.418,47.8886],[-94.4177,47.9031],[-94.4176,47.9041],[-94.4175,47.9175],[-94.4174,47.9186],[-94.4175,47.9332],[-94.4174,47.9477],[-94.4172,47.9623],[-94.4173,47.9769],[-94.4176,47.9914],[-94.4177,48.006],[-94.4176,48.02],[-94.4236,48.0199],[-94.4241,48.0344],[-94.4246,48.0489],[-94.4247,48.0632],[-94.4234,48.0776],[-94.4231,48.092],[-94.4233,48.1059],[-94.4234,48.1204],[-94.4236,48.1348],[-94.4233,48.1491],[-94.4235,48.1637],[-94.4235,48.1781],[-94.4233,48.1923],[-94.4236,48.2067],[-94.4238,48.2212],[-94.4237,48.2356],[-94.4237,48.2504],[-94.424,48.2649],[-94.4243,48.2791],[-94.4244,48.2938],[-94.4246,48.3081],[-94.4248,48.3227],[-94.425,48.3372],[-94.4253,48.352],[-94.4252,48.3675],[-94.4288,48.3675],[-94.4289,48.3821],[-94.4293,48.3964],[-94.4294,48.411],[-94.4293,48.4254],[-94.4292,48.4399],[-94.4293,48.4543],[-94.4296,48.4688],[-94.4296,48.4832],[-94.4299,48.4977],[-94.4303,48.512],[-94.4303,48.5264],[-94.43,48.5409],[-94.4295,48.5554],[-94.4291,48.5698],[-94.4289,48.5844],[-94.4289,48.5988],[-94.4292,48.6133],[-94.4294,48.6276],[-94.4297,48.642],[-94.43,48.6564],[-94.4301,48.6708],[-94.43,48.6852],[-94.4299,48.6998],[-94.4299,48.7012]]],"type":"Polygon"},"id":"36","properties":{"Area":8167237870.91888,"CTYONLY_":5,"Code":"KOOC","LASTMOD":"1999-12-31T23:59:59Z","Name":"Koochiching","Perimiter":412897.43594},"type":"Feature"},{"geometry":{"coordinates":[[[-96.3882,48.5442],[-96.3667,48.5443],[-96.3448,48.5444],[-96.3231,48.5446],[-96.301,48.5448],[-96.2794,48.5449],[-96.2576,48.545],[-96.2358,48.5452],[-96.2141,48.5449],[-96.1921,48.5446],[-96.1702,48.5445],[-96.1486,48.5442],[-96.1264,48.5439],[-96.1026,48.5438],[-96.0812,48.5436],[-96.0592,48.5437],[-96.0374,48.5438],[-96.0157,48.5437],[-95.9936,48.5435],[-95.9704,48.543],[-95.9498,48.5425],[-95.9486,48.5425],[-95.9269,48.5421],[-95.9064,48.5422],[-95.9046,48.5422],[-95.8986,48.5421],[-95.8851,48.542],[-95.8829,48.5419],[-95.8621,48.5414],[-95.8411,48.5406],[-95.8192,48.5404],[-95.7976,48.5405],[-95.7758,48.5406],[-95.7539,48.5404],[-95.7322,48.54],[-95.7102,48.5395],[-95.6886,48.5395],[-95.6666,48.5394],[-95.6447,48.5393],[-95.6232,48.5391],[-95.6023,48.5389],[-95.6011,48.5251],[-95.6007,48.5107],[-95.6007,48.51],[-95.6008,48.4964],[-95.6008,48.4956],[-95.6011,48.4818],[-95.6011,48.4811],[-95.6016,48.4674],[-95.6016,48.4666],[-95.6016,48.453],[-95.6016,48.4522],[-95.602,48.4385],[-95.6021,48.4376],[-95.6023,48.424],[-95.6023,48.4232],[-95.6026,48.4095],[-95.6026,48.4088],[-95.6026,48.395],[-95.6026,48.3942],[-95.6021,48.3809],[-95.602,48.3798],[-95.6016,48.3655],[-95.5933,48.3656],[-95.5933,48.3656],[-95.5933,48.354],[-95.5932,48.3396],[-95.5932,48.325],[-95.5932,48.3105],[-95.5934,48.2961],[-95.5934,48.2815],[-95.5937,48.267],[-95.5941,48.2526],[-95.5941,48.2382],[-95.5939,48.2236],[-95.5939,48.2092],[-95.5938,48.1946],[-95.594,48.1802],[-95.5939,48.173],[-95.5941,48.173],[-95.6159,48.1731],[-95.6163,48.1731],[-95.6252,48.1731],[-95.6279,48.1731],[-95.6376,48.173],[-95.6376,48.173],[-95.6591,48.1729],[-95.662,48.1729],[-95.6802,48.1728],[-95.6803,48.1728],[-95.702,48.1729],[-95.7021,48.1729],[-95.7022,48.1729],[-95.7128,48.173],[-95.7157,48.1731],[-95.7226,48.1731],[-95.7227,48.1731],[-95.744,48.1727],[-95.7443,48.1727],[-95.7502,48.1727],[-95.7657,48.1728],[-95.7657,48.1728],[-95.7874,48.1725],[-95.8088,48.1722],[-95.809,48.1722],[-95.8091,48.1722],[-95.8305,48.1722],[-95.8308,48.1722],[-95.8308,48.1722],[-95.8499,48.1721],[-95.8525,48.1721],[-95.8527,48.1721],[-95.8744,48.172],[-95.8744,48.172],[-95.8752,48.172],[-95.8958,48.172],[-95.896,48.172],[-95.9176,48.1719],[-95.9178,48.1719],[-95.9178,48.1719],[-95.9392,48.1719],[-95.9394,48.1719],[-95.9608,48.1718],[-95.9609,48.1718],[-95.961,48.1718],[-95.9651,48.1718],[-95.9817,48.1717],[-95.9819,48.1717],[-95.9956,48.1717],[-96.0003,48.1717],[-96.0023,48.1718],[-96.0028,48.1718],[-96.0032,48.1718],[-96.0035,48.1718],[-96.0036,48.1718],[-96.0047,48.1717],[-96.0101,48.1718],[-96.0171,48.172],[-96.025,48.1721],[-96.0254,48.1721],[-96.0468,48.1722],[-96.0468,48.1722],[-96.0592,48.1721],[-96.0685,48.1721],[-96.0685,48.1721],[-96.079,48.1721],[-96.09,48.172],[-96.09,48.172],[-96.0979,48.172],[-96.1084,48.1718],[-96.1084,48.1718],[-96.1176,48.1722],[-96.1189,48.1722],[-96.1253,48.1727],[-96.1297,48.173],[-96.1298,48.173],[-96.1302,48.173],[-96.1388,48.1732],[-96.1516,48.1736],[-96.1518,48.1736],[-96.1625,48.1736],[-96.1641,48.1736],[-96.1736,48.1736],[-96.1737,48.1736],[-96.1741,48.1736],[-96.1813,48.1725],[-96.1827,48.1722],[-96.1834,48.172],[-96.1874,48.1721],[-96.191,48.1721],[-96.1948,48.1721],[-96.1954,48.1721],[-96.1959,48.1721],[-96.1963,48.1721],[-96.2023,48.1722],[-96.2038,48.1722],[-96.2072,48.1722],[-96.2076,48.1722],[-96.2177,48.1722],[-96.2179,48.1722],[-96.2188,48.1722],[-96.2251,48.1724],[-96.2275,48.1724],[-96.2287,48.1725],[-96.2307,48.1725],[-96.2329,48.1725],[-96.2391,48.1727],[-96.2397,48.1727],[-96.2397,48.1727],[-96.2398,48.1728],[-96.2476,48.1735],[-96.2491,48.1737],[-96.2503,48.1739],[-96.2511,48.174],[-96.252,48.174],[-96.2562,48.1744],[-96.2596,48.1749],[-96.2607,48.1749],[-96.2612,48.1749],[-96.2619,48.1749],[-96.2805,48.1747],[-96.2823,48.1747],[-96.2824,48.1747],[-96.2977,48.1747],[-96.3029,48.1747],[-96.3035,48.1747],[-96.3145,48.1747],[-96.3252,48.1746],[-96.3253,48.1746],[-96.3301,48.1745],[-96.3356,48.1745],[-96.3358,48.1744],[-96.338,48.1745],[-96.3402,48.1744],[-96.343,48.1744],[-96.3466,48.1743],[-96.347,48.1743],[-96.3473,48.1744],[-96.3477,48.1744],[-96.351,48.1745],[-96.3542,48.1746],[-96.3581,48.1747],[-96.361,48.1748],[-96.3642,48.1749],[-96.3656,48.175],[-96.3682,48.1751],[-96.3682,48.1751],[-96.3685,48.1751],[-96.3706,48.175],[-96.3728,48.1749],[-96.3753,48.1748],[-96.3781,48.1746],[-96.38,48.1745],[-96.3856,48.1747],[-96.3894,48.1748],[-96.3905,48.1748],[-96.3906,48.1748],[-96.3964,48.1748],[-96.4054,48.1748],[-96.4126,48.1749],[-96.4126,48.1749],[-96.4135,48.1749],[-96.4206,48.1749],[-96.4295,48.1749],[-96.4346,48.1749],[-96.4352,48.1749],[-96.4359,48.1749],[-96.438,48.1749],[-96.4402,48.1748],[-96.4436,48.1747],[-96.4454,48.1747],[-96.4561,48.1744],[-96.4563,48.1743],[-96.4564,48.1742],[-96.4569,48.1742],[-96.4592,48.1742],[-96.467,48.1741],[-96.4735,48.174],[-96.4773,48.1741],[-96.4789,48.1741],[-96.4791,48.1741],[-96.4841,48.174],[-96.4946,48.1741],[-96.4973,48.174],[-96.5003,48.1741],[-96.5006,48.1741],[-96.5008,48.1742],[-96.5008,48.1742],[-96.5038,48.174],[-96.5091,48.174],[-96.5164,48.1739],[-96.5204,48.1739],[-96.5223,48.1739],[-96.5251,48.1738],[-96.53,48.1738],[-96.5357,48.1738],[-96.5399,48.1738],[-96.5434,48.1738],[-96.5442,48.1738],[-96.5443,48.1738],[-96.5446,48.1738],[-96.5479,48.1738],[-96.5507,48.1738],[-96.5544,48.1738],[-96.557,48.1739],[-96.5616,48.1739],[-96.565,48.174],[-96.5654,48.174],[-96.5655,48.174],[-96.5678,48.174],[-96.5715,48.1739],[-96.5748,48.1739],[-96.5765,48.1739],[-96.5806,48.1739],[-96.5838,48.1738],[-96.5873,48.1737],[-96.5873,48.1737],[-96.5875,48.1737],[-96.5893,48.1737],[-96.5966,48.1737],[-96.6055,48.1737],[-96.609,48.1737],[-96.6092,48.1737],[-96.6106,48.1737],[-96.6253,48.1737],[-96.6307,48.1737],[-96.6307,48.1737],[-96.6309,48.1737],[-96.6338,48.1737],[-96.6378,48.1738],[-96.6407,48.1739],[-96.6525,48.1738],[-96.6525,48.1738],[-96.6742,48.1736],[-96.6742,48.1736],[-96.6826,48.1735],[-96.6958,48.1734],[-96.6959,48.1734],[-96.7176,48.1734],[-96.7177,48.1734],[-96.7393,48.1734],[-96.7393,48.1734],[-96.7503,48.1734],[-96.7573,48.1734],[-96.7581,48.1734],[-96.7605,48.1734],[-96.7606,48.1734],[-96.7613,48.1734],[-96.7819,48.1734],[-96.7821,48.1734],[-96.7821,48.1734],[-96.7932,48.1733],[-96.8038,48.1734],[-96.8039,48.1734],[-96.8111,48.1734],[-96.8255,48.1734],[-96.8255,48.1734],[-96.8473,48.1733],[-96.8474,48.1733],[-96.869,48.1733],[-96.869,48.1733],[-96.8753,48.1732],[-96.8907,48.1732],[-96.8907,48.1732],[-96.8932,48.1732],[-96.9122,48.1733],[-96.9123,48.1733],[-96.933,48.1733],[-96.9339,48.1733],[-96.934,48.1733],[-96.9387,48.1732],[-96.9448,48.1732],[-96.9554,48.1731],[-96.9703,48.1731],[-96.9705,48.1731],[-96.9749,48.173],[-96.9751,48.173],[-96.9773,48.173],[-96.9773,48.173],[-96.9775,48.1731],[-96.9812,48.1731],[-96.9844,48.1731],[-96.9889,48.1731],[-96.99,48.1731],[-96.9959,48.1732],[-96.9975,48.1732],[-96.998,48.1732],[-96.9987,48.1732],[-96.9989,48.1732],[-96.999,48.1732],[-97.0003,48.1732],[-97.0203,48.1733],[-97.0205,48.1733],[-97.042,48.1732],[-97.042,48.1732],[-97.0637,48.1732],[-97.0637,48.1732],[-97.0853,48.1734],[-97.0855,48.1734],[-97.1069,48.1735],[-97.1071,48.1735],[-97.1253,48.1733],[-97.1257,48.1733],[-97.1286,48.1733],[-97.1322,48.1733],[-97.1376,48.1733],[-97.1462,48.1733],[-97.1467,48.1733],[-97.1452,48.1741],[-97.1434,48.1744],[-97.1417,48.1746],[-97.1389,48.1747],[-97.1371,48.1754],[-97.1365,48.1758],[-97.136,48.1768],[-97.1359,48.1789],[-97.1362,48.1796],[-97.1366,48.1809],[-97.1383,48.1824],[-97.1406,48.183],[-97.1413,48.1831],[-97.1432,48.1828],[-97.1455,48.1824],[-97.1467,48.1821],[-97.1484,48.1825],[-97.1498,48.1835],[-97.1497,48.1859],[-97.1491,48.1864],[-97.1475,48.1879],[-97.1449,48.1895],[-97.1429,48.191],[-97.1426,48.1913],[-97.1415,48.1926],[-97.1413,48.1934],[-97.1412,48.1937],[-97.141,48.194],[-97.1409,48.1945],[-97.1404,48.1947],[-97.1397,48.1951],[-97.1391,48.1953],[-97.1383,48.1955],[-97.1365,48.1963],[-97.1356,48.1972],[-97.1359,48.1984],[-97.1368,48.1996],[-97.1383,48.2006],[-97.1401,48.2018],[-97.1409,48.2027],[-97.1412,48.203],[-97.1411,48.204],[-97.1409,48.2046],[-97.14,48.2052],[-97.139,48.2059],[-97.1375,48.2063],[-97.1341,48.2068],[-97.1316,48.2072],[-97.1301,48.2077],[-97.1296,48.208],[-97.1295,48.208],[-97.1292,48.2084],[-97.1292,48.2099],[-97.1291,48.21],[-97.1296,48.2105],[-97.1297,48.2106],[-97.1299,48.2108],[-97.1307,48.211],[-97.1318,48.2112],[-97.1354,48.2116],[-97.1364,48.2119],[-97.1382,48.2131],[-97.1394,48.2144],[-97.1392,48.2168],[-97.1389,48.2171],[-97.1383,48.2174],[-97.1373,48.2177],[-97.1354,48.2179],[-97.1344,48.2178],[-97.1328,48.2176],[-97.1313,48.2172],[-97.1302,48.2164],[-97.1297,48.2161],[-97.1292,48.2158],[-97.1278,48.2145],[-97.1274,48.2134],[-97.1265,48.2113],[-97.126,48.2101],[-97.1259,48.2099],[-97.1257,48.2097],[-97.1253,48.2093],[-97.1245,48.208],[-97.1236,48.2077],[-97.1229,48.2074],[-97.1216,48.2074],[-97.1204,48.2073],[-97.1197,48.2076],[-97.1189,48.2079],[-97.1183,48.2086],[-97.118,48.2092],[-97.1178,48.2098],[-97.1179,48.2107],[-97.1181,48.2115],[-97.1189,48.2129],[-97.1194,48.2136],[-97.1208,48.215],[-97.122,48.2159],[-97.1228,48.2165],[-97.1248,48.2175],[-97.1253,48.2178],[-97.1272,48.2185],[-97.1289,48.2188],[-97.1297,48.219],[-97.1321,48.2196],[-97.135,48.2207],[-97.139,48.222],[-97.1406,48.2222],[-97.1417,48.2221],[-97.1436,48.2216],[-97.1448,48.2209],[-97.1455,48.2204],[-97.1457,48.2202],[-97.1458,48.2202],[-97.1462,48.2198],[-97.1471,48.2189],[-97.1482,48.2184],[-97.1497,48.2181],[-97.1509,48.2184],[-97.151,48.2185],[-97.1517,48.219],[-97.1521,48.2197],[-97.1521,48.2205],[-97.1517,48.2214],[-97.151,48.2222],[-97.1496,48.2232],[-97.1483,48.2238],[-97.1476,48.224],[-97.1465,48.2243],[-97.1436,48.2253],[-97.1408,48.2263],[-97.1385,48.2268],[-97.1371,48.227],[-97.1357,48.2271],[-97.1332,48.227],[-97.1317,48.2265],[-97.1305,48.2259],[-97.1298,48.2255],[-97.129,48.2251],[-97.1276,48.2245],[-97.1273,48.2243],[-97.1266,48.2239],[-97.1259,48.2236],[-97.1253,48.2234],[-97.1245,48.2232],[-97.1233,48.2231],[-97.1222,48.2234],[-97.1216,48.2236],[-97.121,48.2242],[-97.121,48.2242],[-97.1206,48.2248],[-97.1206,48.2254],[-97.1207,48.2259],[-97.1216,48.227],[-97.1225,48.2275],[-97.1234,48.2281],[-97.1244,48.2284],[-97.1253,48.2287],[-97.1278,48.2293],[-97.1299,48.2297],[-97.1303,48.2297],[-97.1325,48.2298],[-97.1351,48.2298],[-97.1393,48.2302],[-97.1423,48.231],[-97.1435,48.2318],[-97.1446,48.2336],[-97.1445,48.2343],[-97.1443,48.2351],[-97.143,48.2361],[-97.1416,48.2365],[-97.1411,48.2366],[-97.1399,48.2367],[-97.1377,48.2368],[-97.1358,48.237],[-97.1343,48.2378],[-97.1339,48.2382],[-97.1338,48.2386],[-97.1337,48.2391],[-97.1341,48.2397],[-97.1346,48.2403],[-97.1357,48.2409],[-97.1375,48.2414],[-97.1385,48.2415],[-97.1405,48.2415],[-97.1422,48.2412],[-97.1444,48.2412],[-97.1459,48.2417],[-97.147,48.2423],[-97.1471,48.243],[-97.1467,48.2445],[-97.146,48.2452],[-97.1444,48.2462],[-97.1431,48.2468],[-97.1404,48.2473],[-97.1389,48.2479],[-97.1377,48.2485],[-97.1355,48.2495],[-97.1345,48.2498],[-97.1334,48.2499],[-97.1305,48.2498],[-97.1299,48.2498],[-97.1291,48.2495],[-97.1274,48.2495],[-97.1263,48.2498],[-97.1253,48.25],[-97.1251,48.25],[-97.1247,48.2504],[-97.1244,48.2508],[-97.1243,48.2513],[-97.1243,48.252],[-97.1245,48.2526],[-97.1248,48.2532],[-97.1248,48.2532],[-97.1253,48.2537],[-97.1256,48.254],[-97.1262,48.2546],[-97.1267,48.2551],[-97.1274,48.2555],[-97.1291,48.2566],[-97.13,48.2573],[-97.1304,48.2576],[-97.1306,48.2581],[-97.1306,48.2587],[-97.1306,48.259],[-97.1303,48.2595],[-97.1298,48.2598],[-97.1292,48.2599],[-97.1283,48.26],[-97.1272,48.2601],[-97.1253,48.2601],[-97.1248,48.2602],[-97.1242,48.2604],[-97.1236,48.2607],[-97.1231,48.2612],[-97.1229,48.2617],[-97.123,48.2623],[-97.1234,48.2628],[-97.1237,48.2633],[-97.1241,48.2636],[-97.1246,48.2639],[-97.1253,48.2641],[-97.1262,48.2644],[-97.1285,48.2649],[-97.1303,48.2651],[-97.1305,48.2652],[-97.1333,48.2656],[-97.135,48.2659],[-97.136,48.2659],[-97.1375,48.2657],[-97.1395,48.2655],[-97.1406,48.2654],[-97.142,48.2654],[-97.1427,48.2656],[-97.1438,48.2658],[-97.1444,48.2663],[-97.1448,48.2668],[-97.145,48.2675],[-97.1451,48.2678],[-97.145,48.2688],[-97.1443,48.2698],[-97.1431,48.2705],[-97.1421,48.2709],[-97.1403,48.2712],[-97.1391,48.2713],[-97.1377,48.2713],[-97.1361,48.2711],[-97.1343,48.2707],[-97.1313,48.2701],[-97.1305,48.27],[-97.1298,48.2699],[-97.1288,48.2698],[-97.1272,48.2699],[-97.1265,48.2701],[-97.1253,48.2705],[-97.125,48.2707],[-97.1247,48.2709],[-97.124,48.2713],[-97.1238,48.2716],[-97.1237,48.2721],[-97.1237,48.2725],[-97.1239,48.2728],[-97.124,48.2733],[-97.1242,48.2737],[-97.1247,48.2743],[-97.1253,48.2751],[-97.1254,48.2753],[-97.1255,48.2755],[-97.1256,48.2758],[-97.1255,48.2761],[-97.1254,48.2762],[-97.1253,48.2764],[-97.1251,48.2767],[-97.1246,48.2769],[-97.124,48.277],[-97.1232,48.277],[-97.1224,48.2769],[-97.1213,48.2768],[-97.1206,48.2768],[-97.12,48.2769],[-97.1187,48.2774],[-97.1175,48.2781],[-97.117,48.2788],[-97.1165,48.2797],[-97.1166,48.2805],[-97.1166,48.2807],[-97.1167,48.2813],[-97.117,48.2821],[-97.1171,48.2824],[-97.1172,48.2826],[-97.1177,48.2835],[-97.1221,48.2901],[-97.1231,48.2909],[-97.1239,48.2913],[-97.1244,48.2915],[-97.1247,48.2917],[-97.1253,48.2919],[-97.1256,48.292],[-97.126,48.292],[-97.1265,48.292],[-97.1272,48.2919],[-97.128,48.2916],[-97.1285,48.2913],[-97.1295,48.2908],[-97.1303,48.2902],[-97.1305,48.2901],[-97.1314,48.2891],[-97.1322,48.2884],[-97.133,48.2879],[-97.1342,48.2874],[-97.1349,48.2872],[-97.1355,48.2871],[-97.1367,48.2873],[-97.1374,48.2877],[-97.1378,48.2879],[-97.1383,48.2887],[-97.1384,48.2894],[-97.1384,48.2898],[-97.1383,48.2903],[-97.138,48.2909],[-97.1373,48.2918],[-97.1368,48.2922],[-97.1364,48.2925],[-97.1355,48.2929],[-97.1344,48.2935],[-97.1335,48.2941],[-97.133,48.2946],[-97.1323,48.2953],[-97.1318,48.2959],[-97.1314,48.2963],[-97.131,48.2969],[-97.1306,48.2973],[-97.1305,48.2974],[-97.13,48.2979],[-97.1293,48.2984],[-97.1286,48.2987],[-97.1282,48.2989],[-97.1276,48.299],[-97.1271,48.2991],[-97.127,48.2991],[-97.1263,48.2991],[-97.1253,48.2989],[-97.125,48.2988],[-97.1246,48.2987],[-97.1241,48.2984],[-97.1234,48.2975],[-97.1228,48.2968],[-97.1227,48.2967],[-97.1213,48.2955],[-97.1203,48.2949],[-97.1192,48.2943],[-97.1167,48.294],[-97.1153,48.2939],[-97.1138,48.2943],[-97.1129,48.2949],[-97.1123,48.2954],[-97.1122,48.296],[-97.1122,48.2965],[-97.1123,48.2968],[-97.1126,48.2973],[-97.113,48.2978],[-97.1138,48.2984],[-97.1148,48.299],[-97.118,48.3004],[-97.12,48.3012],[-97.1227,48.3019],[-97.1241,48.3022],[-97.1247,48.3025],[-97.1253,48.3029],[-97.1255,48.303],[-97.1259,48.3033],[-97.1262,48.3036],[-97.1266,48.3041],[-97.1267,48.3046],[-97.1265,48.3055],[-97.1263,48.3059],[-97.1257,48.3064],[-97.1253,48.3067],[-97.1241,48.3073],[-97.123,48.3081],[-97.1222,48.3088],[-97.1221,48.3095],[-97.1222,48.3099],[-97.123,48.3105],[-97.1241,48.3112],[-97.1247,48.3115],[-97.1253,48.3119],[-97.1258,48.3119],[-97.1263,48.312],[-97.1269,48.312],[-97.1276,48.312],[-97.1282,48.3118],[-97.1289,48.3116],[-97.1298,48.3111],[-97.1299,48.3111],[-97.1303,48.3108],[-97.1304,48.3108],[-97.1311,48.3103],[-97.1318,48.3099],[-97.1325,48.3094],[-97.1331,48.3092],[-97.1336,48.309],[-97.1343,48.3089],[-97.1351,48.3089],[-97.1358,48.3089],[-97.1365,48.3091],[-97.1372,48.3094],[-97.1377,48.3098],[-97.1379,48.3102],[-97.1381,48.3106],[-97.138,48.3111],[-97.138,48.3116],[-97.1379,48.312],[-97.1376,48.3125],[-97.1372,48.3129],[-97.1367,48.3134],[-97.1361,48.3141],[-97.1356,48.3148],[-97.1351,48.3155],[-97.1348,48.316],[-97.1346,48.3166],[-97.1345,48.3171],[-97.1343,48.3177],[-97.134,48.3181],[-97.1335,48.3185],[-97.1329,48.3189],[-97.1325,48.3192],[-97.132,48.3194],[-97.1312,48.3196],[-97.1306,48.3196],[-97.1303,48.3196],[-97.1291,48.3196],[-97.1282,48.3195],[-97.1274,48.3195],[-97.1267,48.3195],[-97.1253,48.3196],[-97.1229,48.3201],[-97.1197,48.3208],[-97.1173,48.3216],[-97.1164,48.3222],[-97.1157,48.323],[-97.1155,48.3236],[-97.1155,48.324],[-97.1162,48.3248],[-97.1168,48.3253],[-97.1173,48.3258],[-97.1175,48.326],[-97.1187,48.3266],[-97.1203,48.3271],[-97.1222,48.3274],[-97.123,48.3275],[-97.1253,48.3277],[-97.1257,48.3277],[-97.1262,48.3278],[-97.1275,48.328],[-97.1292,48.3282],[-97.1303,48.3282],[-97.1311,48.3283],[-97.1317,48.3282],[-97.1326,48.3281],[-97.1337,48.3279],[-97.1343,48.3277],[-97.1345,48.3277],[-97.1353,48.3273],[-97.1359,48.327],[-97.1368,48.3263],[-97.1376,48.3257],[-97.138,48.3255],[-97.1385,48.3253],[-97.139,48.3251],[-97.1397,48.3251],[-97.1404,48.3252],[-97.141,48.3254],[-97.1415,48.3257],[-97.1417,48.3258],[-97.142,48.3262],[-97.1422,48.3267],[-97.1423,48.327],[-97.1422,48.3276],[-97.142,48.3281],[-97.1416,48.3287],[-97.1408,48.3294],[-97.14,48.3299],[-97.139,48.3304],[-97.1378,48.3309],[-97.1371,48.331],[-97.1361,48.3312],[-97.1347,48.3315],[-97.1325,48.3318],[-97.1311,48.3321],[-97.1305,48.3323],[-97.1295,48.3326],[-97.129,48.3329],[-97.1284,48.3336],[-97.1275,48.3352],[-97.1263,48.3379],[-97.1258,48.3384],[-97.1258,48.3398],[-97.1258,48.3402],[-97.1259,48.3406],[-97.1263,48.3415],[-97.1267,48.3422],[-97.1276,48.3427],[-97.1283,48.343],[-97.1297,48.3435],[-97.1308,48.3438],[-97.1309,48.3438],[-97.132,48.344],[-97.1334,48.3439],[-97.1354,48.3439],[-97.1372,48.344],[-97.1383,48.3441],[-97.1388,48.3441],[-97.1396,48.3443],[-97.14,48.3446],[-97.1405,48.345],[-97.1407,48.3453],[-97.1409,48.3456],[-97.141,48.3459],[-97.1408,48.3468],[-97.1405,48.3471],[-97.1396,48.3478],[-97.1386,48.3485],[-97.1376,48.3491],[-97.1368,48.3496],[-97.1362,48.3501],[-97.1361,48.3503],[-97.136,48.3505],[-97.136,48.3506],[-97.1359,48.351],[-97.1359,48.3511],[-97.136,48.3518],[-97.1362,48.3522],[-97.1363,48.3524],[-97.1365,48.3526],[-97.1373,48.3529],[-97.1382,48.3532],[-97.1387,48.3533],[-97.1398,48.3535],[-97.1405,48.3536],[-97.1415,48.3538],[-97.1423,48.354],[-97.143,48.3542],[-97.1435,48.3543],[-97.1438,48.3546],[-97.1441,48.3549],[-97.1442,48.3551],[-97.1443,48.3554],[-97.1445,48.356],[-97.1447,48.3565],[-97.145,48.3571],[-97.1453,48.3576],[-97.1459,48.3586],[-97.1464,48.3592],[-97.1468,48.3596],[-97.1477,48.3603],[-97.1484,48.3608],[-97.1501,48.3613],[-97.1517,48.362],[-97.1525,48.3623],[-97.1534,48.3628],[-97.1545,48.3633],[-97.1554,48.3638],[-97.1559,48.3646],[-97.1562,48.3656],[-97.1562,48.3662],[-97.156,48.3671],[-97.1558,48.3681],[-97.1555,48.3686],[-97.1554,48.3689],[-97.1552,48.3691],[-97.1548,48.37],[-97.1539,48.3704],[-97.1536,48.3705],[-97.1524,48.371],[-97.1523,48.371],[-97.1512,48.3713],[-97.1498,48.3712],[-97.1476,48.371],[-97.1437,48.3703],[-97.1433,48.3703],[-97.141,48.3702],[-97.1407,48.3703],[-97.1404,48.3703],[-97.1403,48.3703],[-97.1402,48.3703],[-97.1401,48.3703],[-97.1392,48.3705],[-97.1386,48.3708],[-97.1378,48.3713],[-97.1373,48.3718],[-97.1372,48.3724],[-97.1373,48.373],[-97.1376,48.3736],[-97.1383,48.3744],[-97.1389,48.375],[-97.1398,48.3759],[-97.1406,48.3769],[-97.1412,48.3777],[-97.1413,48.3785],[-97.1409,48.3793],[-97.1403,48.3797],[-97.1395,48.3801],[-97.1379,48.3803],[-97.1366,48.3804],[-97.1355,48.3805],[-97.1344,48.3808],[-97.1339,48.3811],[-97.1334,48.3818],[-97.1333,48.3822],[-97.1338,48.3828],[-97.1344,48.3833],[-97.1354,48.3838],[-97.1362,48.384],[-97.1374,48.3839],[-97.1389,48.3837],[-97.1406,48.3833],[-97.1431,48.3824],[-97.1446,48.3819],[-97.1454,48.3815],[-97.1463,48.3815],[-97.147,48.3814],[-97.1479,48.3817],[-97.149,48.3819],[-97.1505,48.3824],[-97.1509,48.3825],[-97.1519,48.3829],[-97.1532,48.3834],[-97.1538,48.3839],[-97.1548,48.3844],[-97.155,48.3846],[-97.156,48.3851],[-97.1572,48.3858],[-97.1576,48.3865],[-97.1577,48.3874],[-97.1571,48.3884],[-97.1565,48.3896],[-97.1563,48.3904],[-97.1567,48.3909],[-97.1576,48.3912],[-97.1586,48.3913],[-97.1596,48.3912],[-97.1608,48.3913],[-97.1617,48.3915],[-97.1627,48.3918],[-97.1632,48.392],[-97.1633,48.3929],[-97.1631,48.3937],[-97.1621,48.3948],[-97.1607,48.3956],[-97.1593,48.3961],[-97.1586,48.3964],[-97.1574,48.3965],[-97.1551,48.3968],[-97.1534,48.397],[-97.1519,48.3969],[-97.1505,48.3968],[-97.1499,48.3968],[-97.1481,48.3968],[-97.1467,48.3971],[-97.1456,48.3975],[-97.1445,48.3981],[-97.1434,48.3989],[-97.1434,48.399],[-97.1427,48.3996],[-97.1421,48.4004],[-97.1414,48.4013],[-97.1406,48.4019],[-97.1399,48.4025],[-97.1392,48.4029],[-97.1383,48.4033],[-97.1369,48.4038],[-97.1349,48.4046],[-97.1334,48.4053],[-97.1323,48.4059],[-97.1314,48.4066],[-97.1311,48.4073],[-97.131,48.4079],[-97.1312,48.409],[-97.1316,48.4096],[-97.1322,48.4104],[-97.1334,48.4112],[-97.1348,48.412],[-97.1362,48.4126],[-97.1373,48.4134],[-97.1375,48.4137],[-97.1376,48.4137],[-97.1379,48.4141],[-97.1384,48.4146],[-97.1388,48.4163],[-97.1388,48.4172],[-97.1393,48.4181],[-97.1398,48.4185],[-97.1406,48.4187],[-97.142,48.4186],[-97.1434,48.4181],[-97.1445,48.4173],[-97.1453,48.4159],[-97.1467,48.414],[-97.1472,48.4137],[-97.1478,48.4133],[-97.1489,48.4129],[-97.1505,48.4128],[-97.1508,48.4128],[-97.1521,48.4129],[-97.1532,48.4131],[-97.1543,48.4136],[-97.1543,48.4136],[-97.155,48.4143],[-97.1554,48.415],[-97.1554,48.4161],[-97.1554,48.4168],[-97.1548,48.4175],[-97.1539,48.4182],[-97.1527,48.4188],[-97.1509,48.4195],[-97.1507,48.4196],[-97.1489,48.4201],[-97.1466,48.4206],[-97.1443,48.4211],[-97.1421,48.4215],[-97.1403,48.4216],[-97.1383,48.4217],[-97.1367,48.4216],[-97.135,48.4213],[-97.1335,48.421],[-97.1325,48.4205],[-97.1312,48.4197],[-97.1301,48.4191],[-97.129,48.4181],[-97.1285,48.4177],[-97.1274,48.4168],[-97.1264,48.4164],[-97.126,48.4162],[-97.1253,48.4162],[-97.1244,48.4164],[-97.1236,48.4167],[-97.1232,48.417],[-97.1227,48.4176],[-97.1225,48.418],[-97.1224,48.4183],[-97.1223,48.4191],[-97.1223,48.4195],[-97.1225,48.42],[-97.1227,48.4204],[-97.1228,48.4207],[-97.1231,48.421],[-97.1233,48.4213],[-97.1241,48.4219],[-97.1246,48.4223],[-97.1249,48.4224],[-97.1253,48.4226],[-97.1268,48.4234],[-97.1286,48.4242],[-97.129,48.4243],[-97.1312,48.4251],[-97.1332,48.4258],[-97.1346,48.4262],[-97.1375,48.4264],[-97.139,48.4265],[-97.1406,48.427],[-97.1412,48.4272],[-97.1425,48.4277],[-97.1438,48.4285],[-97.1446,48.4291],[-97.1451,48.4298],[-97.1457,48.4303],[-97.1458,48.4312],[-97.1455,48.4322],[-97.1451,48.4326],[-97.144,48.4332],[-97.142,48.4337],[-97.1412,48.4338],[-97.1398,48.4337],[-97.1384,48.4336],[-97.1366,48.433],[-97.1344,48.4321],[-97.1332,48.4316],[-97.1315,48.4312],[-97.1305,48.4311],[-97.129,48.4311],[-97.1278,48.4313],[-97.1267,48.4319],[-97.1259,48.4325],[-97.1253,48.4329],[-97.1246,48.4337],[-97.1245,48.4341],[-97.1238,48.4355],[-97.1236,48.4361],[-97.1234,48.4371],[-97.1233,48.4376],[-97.1233,48.4383],[-97.1235,48.4389],[-97.1238,48.4399],[-97.124,48.4407],[-97.1243,48.4413],[-97.1245,48.4416],[-97.1248,48.4419],[-97.125,48.4421],[-97.1251,48.4422],[-97.1253,48.4423],[-97.1258,48.4427],[-97.1265,48.4432],[-97.128,48.4438],[-97.129,48.444],[-97.1295,48.4441],[-97.1314,48.4441],[-97.1328,48.4439],[-97.1345,48.4434],[-97.1355,48.4427],[-97.1363,48.4421],[-97.1365,48.4419],[-97.138,48.4405],[-97.1398,48.4392],[-97.141,48.4386],[-97.1428,48.4383],[-97.1451,48.4381],[-97.1464,48.4381],[-97.1477,48.4383],[-97.149,48.4389],[-97.1498,48.4392],[-97.1503,48.4397],[-97.1505,48.4403],[-97.1506,48.4409],[-97.1505,48.4413],[-97.1502,48.4419],[-97.1501,48.4422],[-97.1492,48.4434],[-97.1481,48.4441],[-97.1462,48.4448],[-97.1426,48.4459],[-97.1401,48.4467],[-97.1377,48.4477],[-97.1353,48.4489],[-97.1306,48.4523],[-97.1293,48.4541],[-97.1292,48.4564],[-97.1292,48.4566],[-97.1292,48.4569],[-97.1291,48.4575],[-97.1288,48.4585],[-97.1286,48.4596],[-97.1285,48.4604],[-97.1288,48.4616],[-97.1292,48.4622],[-97.1293,48.4624],[-97.1298,48.463],[-97.1306,48.4635],[-97.1319,48.4638],[-97.1334,48.4639],[-97.1347,48.4638],[-97.136,48.4635],[-97.138,48.463],[-97.1395,48.463],[-97.1407,48.463],[-97.142,48.4634],[-97.143,48.4639],[-97.1444,48.4649],[-97.1455,48.466],[-97.1463,48.4669],[-97.147,48.4677],[-97.1474,48.4684],[-97.148,48.47],[-97.1482,48.4708],[-97.148,48.4713],[-97.1477,48.4721],[-97.1474,48.4728],[-97.1465,48.4737],[-97.1461,48.4741],[-97.1445,48.4746],[-97.1432,48.4748],[-97.1419,48.4748],[-97.1407,48.4747],[-97.1393,48.4743],[-97.1379,48.4737],[-97.1368,48.4732],[-97.1352,48.4724],[-97.134,48.4718],[-97.1331,48.4715],[-97.1326,48.4714],[-97.1324,48.4713],[-97.1315,48.4712],[-97.1306,48.4713],[-97.1301,48.4714],[-97.1294,48.4715],[-97.1293,48.4717],[-97.1289,48.472],[-97.1283,48.4729],[-97.1281,48.4736],[-97.1281,48.4744],[-97.1285,48.4751],[-97.1289,48.4758],[-97.1293,48.4761],[-97.1297,48.4764],[-97.1308,48.4769],[-97.1324,48.4773],[-97.1346,48.4776],[-97.1364,48.4777],[-97.1384,48.4776],[-97.1406,48.4775],[-97.1419,48.4773],[-97.1433,48.4769],[-97.1448,48.4765],[-97.1461,48.4761],[-97.1477,48.4758],[-97.1493,48.4755],[-97.1509,48.4753],[-97.1511,48.4752],[-97.153,48.475],[-97.1549,48.475],[-97.1569,48.475],[-97.1585,48.4752],[-97.1599,48.4756],[-97.1609,48.4759],[-97.1616,48.4763],[-97.1622,48.477],[-97.1626,48.4778],[-97.1624,48.4786],[-97.1623,48.4792],[-97.1616,48.4799],[-97.1602,48.4807],[-97.1592,48.4812],[-97.1574,48.4816],[-97.1562,48.4818],[-97.1546,48.4821],[-97.1529,48.4822],[-97.1509,48.4824],[-97.1507,48.4824],[-97.1482,48.4828],[-97.1455,48.483],[-97.1437,48.4835],[-97.1424,48.4838],[-97.1411,48.4843],[-97.1402,48.4848],[-97.1396,48.4854],[-97.1394,48.486],[-97.1392,48.4864],[-97.1393,48.4873],[-97.1396,48.4881],[-97.1401,48.4887],[-97.1408,48.4892],[-97.1417,48.49],[-97.1428,48.4909],[-97.1433,48.4914],[-97.1433,48.492],[-97.143,48.4924],[-97.1423,48.4926],[-97.1415,48.4926],[-97.1406,48.4924],[-97.1399,48.492],[-97.139,48.4912],[-97.1382,48.4904],[-97.138,48.4897],[-97.1373,48.4889],[-97.1367,48.4884],[-97.136,48.4881],[-97.1351,48.4878],[-97.1344,48.4878],[-97.1332,48.4881],[-97.1322,48.4885],[-97.1315,48.4891],[-97.1312,48.4897],[-97.1311,48.4903],[-97.1311,48.4907],[-97.1316,48.4916],[-97.1322,48.4924],[-97.1334,48.4935],[-97.1345,48.4943],[-97.1367,48.4954],[-97.1388,48.496],[-97.1408,48.4967],[-97.1425,48.4972],[-97.1444,48.4976],[-97.1453,48.4979],[-97.1478,48.4995],[-97.148,48.4997],[-97.1483,48.5],[-97.1487,48.5004],[-97.1491,48.5009],[-97.1497,48.502],[-97.1499,48.5034],[-97.1498,48.5047],[-97.1498,48.5061],[-97.1495,48.5075],[-97.1495,48.5086],[-97.1497,48.5096],[-97.1502,48.5106],[-97.1502,48.5117],[-97.1499,48.512],[-97.1491,48.5124],[-97.1477,48.5124],[-97.142,48.5116],[-97.139,48.5117],[-97.1366,48.5123],[-97.1338,48.5139],[-97.1328,48.5146],[-97.1326,48.5148],[-97.1289,48.5173],[-97.1281,48.5178],[-97.127,48.519],[-97.1267,48.5202],[-97.1276,48.5215],[-97.1288,48.5222],[-97.129,48.5223],[-97.1307,48.5227],[-97.1339,48.5227],[-97.1366,48.5221],[-97.1385,48.5215],[-97.1395,48.521],[-97.1411,48.5202],[-97.1426,48.5195],[-97.1442,48.5191],[-97.1454,48.5188],[-97.1473,48.5188],[-97.1488,48.5189],[-97.1503,48.5194],[-97.1506,48.5195],[-97.1524,48.5204],[-97.154,48.5217],[-97.1547,48.5242],[-97.1549,48.5266],[-97.1544,48.5285],[-97.1536,48.5295],[-97.1536,48.5295],[-97.1527,48.5303],[-97.1513,48.5309],[-97.1507,48.5311],[-97.1499,48.5313],[-97.1482,48.5315],[-97.1458,48.5316],[-97.1438,48.5316],[-97.1422,48.5323],[-97.1411,48.5333],[-97.141,48.5343],[-97.1413,48.5355],[-97.1424,48.5366],[-97.144,48.5375],[-97.1456,48.5382],[-97.1481,48.5388],[-97.1505,48.5395],[-97.1508,48.5395],[-97.1533,48.5399],[-97.1558,48.5403],[-97.1582,48.5409],[-97.1596,48.5414],[-97.161,48.542],[-97.1614,48.5424],[-97.1631,48.5439],[-97.1631,48.544],[-97.1509,48.5439],[-97.1287,48.5439],[-97.107,48.544],[-97.0852,48.5441],[-97.0635,48.5441],[-97.0416,48.5442],[-97.0194,48.5441],[-96.9985,48.5441],[-96.9768,48.544],[-96.9551,48.5437],[-96.9331,48.5435],[-96.9138,48.5433],[-96.9115,48.5432],[-96.8896,48.5433],[-96.8678,48.5433],[-96.8459,48.5434],[-96.824,48.5436],[-96.8023,48.5436],[-96.7803,48.5435],[-96.7585,48.5436],[-96.7368,48.5437],[-96.7151,48.5437],[-96.6931,48.5437],[-96.6713,48.5436],[-96.6493,48.5437],[-96.6278,48.5437],[-96.6058,48.5437],[-96.5839,48.5437],[-96.5621,48.5436],[-96.54,48.5434],[-96.518,48.5434],[-96.4973,48.5434],[-96.4754,48.5435],[-96.4535,48.5436],[-96.4318,48.5438],[-96.4101,48.544],[-96.3882,48.5442]]],"type":"Polygon"},"id":"45","properties":{"Area":4698732287.54973,"CTYONLY_":6,"Code":"MARS","LASTMOD":"1984-01-12T14:12:49Z","Name":"Marshall","Perimiter":374207.65129},"type":"Feature"},{"geometry":{"coordinates":[[[-93.0884,48.6278],[-93.067,48.627],[-93.0456,48.6262],[-93.0237,48.6253],[-93.0021,48.6245],[-92.9845,48.6239],[-92.98,48.625],[-92.9641,48.6291],[-92.9585,48.6306],[-92.9547,48.6316],[-92.9497,48.6304],[-92.9498,48.6291],[-92.9499,48.6147],[-92.95,48.6084],[-92.9369,48.6075],[-92.9295,48.607],[-92.9177,48.6006],[-92.9151,48.5992],[-92.91,48.5964],[-92.8945,48.595],[-92.8932,48.5946],[-92.8729,48.5878],[-92.8652,48.5853],[-92.8515,48.5807],[-92.8301,48.5735],[-92.8206,48.5703],[-92.8079,48.5661],[-92.7863,48.5589],[-92.7767,48.5557],[-92.7665,48.5522],[-92.7439,48.5446],[-92.7354,48.5418],[-92.7284,48.5394],[-92.7227,48.54],[-92.7007,48.5421],[-92.7003,48.5421],[-92.6789,48.5442],[-92.6578,48.5463],[-92.6576,48.5462],[-92.6369,48.5429],[-92.6357,48.5427],[-92.6348,48.5426],[-92.6302,48.5284],[-92.6282,48.5223],[-92.6255,48.5179],[-92.6269,48.5142],[-92.6268,48.514],[-92.6264,48.5135],[-92.625,48.513],[-92.628,48.5108],[-92.6287,48.5106],[-92.6308,48.5092],[-92.6312,48.5082],[-92.6319,48.5068],[-92.6296,48.5058],[-92.627,48.5033],[-92.6306,48.5008],[-92.6351,48.4998],[-92.637,48.4994],[-92.6386,48.4996],[-92.64,48.4999],[-92.647,48.4999],[-92.654,48.5017],[-92.6569,48.4996],[-92.6582,48.4987],[-92.6614,48.4964],[-92.6789,48.4971],[-92.6857,48.4974],[-92.6986,48.4949],[-92.7011,48.4847],[-92.7016,48.4841],[-92.7092,48.4729],[-92.7085,48.4704],[-92.7089,48.4696],[-92.7126,48.463],[-92.7025,48.4551],[-92.7015,48.4543],[-92.6881,48.4438],[-92.6799,48.4425],[-92.6694,48.441],[-92.6635,48.4401],[-92.6586,48.4377],[-92.6562,48.4365],[-92.6371,48.4375],[-92.6157,48.4386],[-92.5935,48.4398],[-92.5765,48.4406],[-92.5717,48.4415],[-92.5686,48.4421],[-92.5499,48.4454],[-92.5369,48.4478],[-92.5284,48.448],[-92.515,48.4484],[-92.5074,48.448],[-92.507,48.4476],[-92.501,48.4422],[-92.4942,48.436],[-92.4893,48.4303],[-92.4849,48.4294],[-92.4837,48.4292],[-92.482,48.4283],[-92.4819,48.4279],[-92.4819,48.4276],[-92.4807,48.4264],[-92.481,48.4253],[-92.4788,48.4233],[-92.4754,48.4187],[-92.4631,48.4157],[-92.4564,48.4141],[-92.4564,48.4135],[-92.4563,48.4012],[-92.4602,48.3956],[-92.47,48.3813],[-92.4765,48.372],[-92.4747,48.3667],[-92.4697,48.3522],[-92.4697,48.3521],[-92.4591,48.3374],[-92.4558,48.3329],[-92.4523,48.3281],[-92.4476,48.3229],[-92.4415,48.3161],[-92.4413,48.3159],[-92.4405,48.3154],[-92.4403,48.3149],[-92.4386,48.3112],[-92.4367,48.309],[-92.4361,48.3085],[-92.4347,48.3074],[-92.4318,48.3052],[-92.4289,48.306],[-92.4256,48.3047],[-92.4204,48.299],[-92.4156,48.2951],[-92.415,48.2941],[-92.4135,48.2915],[-92.4065,48.2795],[-92.4017,48.2714],[-92.3967,48.2648],[-92.3931,48.2601],[-92.3927,48.259],[-92.3934,48.2576],[-92.3921,48.2568],[-92.3913,48.256],[-92.3891,48.2537],[-92.3901,48.2528],[-92.3912,48.2529],[-92.3922,48.2531],[-92.3926,48.2519],[-92.3923,48.2512],[-92.3912,48.2509],[-92.3907,48.2507],[-92.3897,48.2508],[-92.3887,48.2512],[-92.3867,48.2518],[-92.3858,48.2514],[-92.3853,48.2504],[-92.3852,48.2502],[-92.3846,48.2492],[-92.3868,48.2492],[-92.3863,48.2475],[-92.3878,48.247],[-92.3881,48.2465],[-92.3872,48.2444],[-92.3866,48.2441],[-92.3846,48.2449],[-92.3838,48.2446],[-92.3844,48.2425],[-92.3844,48.2414],[-92.384,48.2404],[-92.3833,48.2393],[-92.3816,48.2377],[-92.3806,48.2365],[-92.3789,48.2359],[-92.3789,48.2359],[-92.3785,48.2353],[-92.3791,48.2343],[-92.3781,48.233],[-92.3784,48.2321],[-92.3785,48.2312],[-92.3783,48.2304],[-92.3774,48.2293],[-92.3758,48.2283],[-92.3754,48.2275],[-92.3756,48.2267],[-92.3751,48.226],[-92.3743,48.2256],[-92.3734,48.225],[-92.3726,48.2236],[-92.3714,48.2241],[-92.3708,48.2239],[-92.3707,48.2228],[-92.3699,48.2218],[-92.3699,48.2212],[-92.3699,48.2203],[-92.3695,48.2203],[-92.3691,48.2202],[-92.368,48.2212],[-92.368,48.2212],[-92.3672,48.2217],[-92.3668,48.2223],[-92.3676,48.2232],[-92.3687,48.2237],[-92.368,48.2241],[-92.3662,48.224],[-92.365,48.2236],[-92.3636,48.2229],[-92.3621,48.2227],[-92.3616,48.2232],[-92.3613,48.224],[-92.361,48.2248],[-92.3603,48.2256],[-92.3586,48.2265],[-92.3566,48.2275],[-92.3555,48.2281],[-92.3544,48.2286],[-92.3537,48.2296],[-92.3535,48.2301],[-92.3517,48.2306],[-92.3494,48.2313],[-92.3484,48.2314],[-92.3477,48.2315],[-92.347,48.2315],[-92.3439,48.2321],[-92.3419,48.2317],[-92.3414,48.2319],[-92.3408,48.2337],[-92.3404,48.2341],[-92.3392,48.2347],[-92.339,48.2349],[-92.3386,48.2351],[-92.338,48.2351],[-92.3377,48.235],[-92.3371,48.2351],[-92.3365,48.2357],[-92.3362,48.2357],[-92.3346,48.2348],[-92.3344,48.2346],[-92.3344,48.2344],[-92.3343,48.2342],[-92.3338,48.2339],[-92.3333,48.2338],[-92.332,48.234],[-92.3308,48.2348],[-92.3302,48.2349],[-92.3292,48.2351],[-92.3281,48.2359],[-92.3274,48.2366],[-92.327,48.2369],[-92.3268,48.2368],[-92.3262,48.2366],[-92.3261,48.2366],[-92.3259,48.2367],[-92.3256,48.2369],[-92.3253,48.2371],[-92.3223,48.2373],[-92.3221,48.2373],[-92.3148,48.2406],[-92.3006,48.2422],[-92.2803,48.2444],[-92.2783,48.2451],[-92.2695,48.2482],[-92.2713,48.2519],[-92.2736,48.2566],[-92.2794,48.2596],[-92.2901,48.2651],[-92.291,48.2664],[-92.2945,48.2713],[-92.2931,48.276],[-92.2937,48.2767],[-92.2942,48.2766],[-92.2945,48.2764],[-92.2951,48.2763],[-92.2952,48.2763],[-92.2953,48.2765],[-92.2953,48.2767],[-92.2954,48.2769],[-92.2953,48.2771],[-92.2952,48.2772],[-92.2953,48.2773],[-92.2956,48.2773],[-92.2955,48.2776],[-92.2955,48.2777],[-92.2956,48.278],[-92.2972,48.2809],[-92.3014,48.2883],[-92.2987,48.2954],[-92.2945,48.3063],[-92.2987,48.3099],[-92.3018,48.3125],[-92.3061,48.3163],[-92.3044,48.3229],[-92.302,48.3232],[-92.2954,48.3239],[-92.2952,48.3246],[-92.2901,48.3392],[-92.2888,48.3429],[-92.2803,48.3468],[-92.2625,48.355],[-92.2588,48.3544],[-92.2364,48.3511],[-92.2216,48.3489],[-92.2197,48.3481],[-92.2191,48.3475],[-92.2189,48.3469],[-92.2181,48.3463],[-92.2169,48.345],[-92.2147,48.3452],[-92.2067,48.3457],[-92.2065,48.3473],[-92.2077,48.3479],[-92.2038,48.3519],[-92.195,48.3505],[-92.1945,48.3488],[-92.193,48.3488],[-92.1928,48.3488],[-92.1785,48.3519],[-92.179,48.3549],[-92.1791,48.3549],[-92.1774,48.3572],[-92.1709,48.3598],[-92.162,48.3634],[-92.1488,48.3652],[-92.1448,48.3657],[-92.1437,48.3561],[-92.1274,48.3556],[-92.106,48.355],[-92.0942,48.3546],[-92.0908,48.3545],[-92.0842,48.3538],[-92.0835,48.3538],[-92.0823,48.3547],[-92.0781,48.3581],[-92.067,48.3595],[-92.0625,48.3595],[-92.0552,48.3594],[-92.0525,48.3549],[-92.0488,48.3486],[-92.0458,48.3479],[-92.0451,48.3458],[-92.0478,48.3436],[-92.0475,48.3404],[-92.0469,48.3348],[-92.0404,48.3336],[-92.0376,48.3331],[-92.031,48.3261],[-92.0307,48.3257],[-92.0185,48.324],[-92.0119,48.323],[-92.0001,48.3211],[-92.0051,48.3118],[-92.0129,48.2975],[-92.0129,48.297],[-92.012,48.287],[-92.0087,48.2826],[-92.0072,48.2806],[-92.0066,48.2677],[-92.0065,48.2655],[-91.9949,48.262],[-91.9891,48.2603],[-91.9841,48.2531],[-91.9805,48.248],[-91.979,48.2475],[-91.9783,48.2474],[-91.9778,48.2474],[-91.9773,48.2472],[-91.9769,48.2468],[-91.977,48.2465],[-91.9772,48.2463],[-91.9773,48.2462],[-91.9775,48.246],[-91.9774,48.2457],[-91.9774,48.2456],[-91.9772,48.2455],[-91.9765,48.245],[-91.9756,48.2444],[-91.9744,48.2453],[-91.9743,48.2454],[-91.9742,48.2455],[-91.9738,48.2459],[-91.9736,48.2464],[-91.9735,48.2467],[-91.9726,48.247],[-91.9704,48.2479],[-91.97,48.2488],[-91.9706,48.249],[-91.9708,48.2494],[-91.9714,48.2499],[-91.9719,48.25],[-91.9724,48.2503],[-91.9724,48.2506],[-91.9723,48.251],[-91.9722,48.2513],[-91.9722,48.2518],[-91.9718,48.252],[-91.9718,48.2529],[-91.9714,48.2531],[-91.9709,48.253],[-91.9705,48.2531],[-91.9704,48.2534],[-91.9699,48.2538],[-91.959,48.2537],[-91.957,48.2524],[-91.9541,48.2523],[-91.954,48.2518],[-91.9541,48.2517],[-91.9541,48.2515],[-91.954,48.2495],[-91.9512,48.2479],[-91.948,48.246],[-91.9496,48.2446],[-91.9511,48.2444],[-91.9582,48.2439],[-91.957,48.2389],[-91.9573,48.2387],[-91.9597,48.2369],[-91.9583,48.2332],[-91.9524,48.2331],[-91.9512,48.2334],[-91.9507,48.2332],[-91.9451,48.2304],[-91.942,48.2304],[-91.9375,48.2343],[-91.9288,48.2359],[-91.9282,48.236],[-91.9211,48.2368],[-91.9167,48.2386],[-91.9148,48.239],[-91.9134,48.2389],[-91.9131,48.2385],[-91.9106,48.2382],[-91.9097,48.2384],[-91.9076,48.2384],[-91.9073,48.2383],[-91.907,48.2382],[-91.9065,48.2378],[-91.9058,48.2373],[-91.9023,48.2372],[-91.8931,48.238],[-91.885,48.2283],[-91.8843,48.2275],[-91.8769,48.2239],[-91.8675,48.2192],[-91.865,48.2095],[-91.8643,48.207],[-91.8634,48.2071],[-91.8453,48.2088],[-91.8417,48.2094],[-91.8416,48.2094],[-91.8359,48.2103],[-91.8326,48.2095],[-91.8325,48.2094],[-91.8325,48.2094],[-91.8325,48.2094],[-91.8325,48.2094],[-91.8199,48.2112],[-91.8154,48.2119],[-91.8144,48.2094],[-91.8141,48.2084],[-91.8094,48.2063],[-91.7982,48.203],[-91.7983,48.1953],[-91.7982,48.1808],[-91.7984,48.1662],[-91.7983,48.1515],[-91.7981,48.1369],[-91.798,48.1224],[-91.7987,48.1079],[-91.7992,48.0936],[-91.7997,48.0788],[-91.8001,48.0643],[-91.8,48.0496],[-91.8,48.0353],[-91.8,48.0206],[-91.8001,48.0059],[-91.7996,47.9914],[-91.7992,47.977],[-91.7985,47.9625],[-91.7979,47.9481],[-91.7977,47.9334],[-91.7978,47.9189],[-91.7979,47.9045],[-91.7979,47.8899],[-91.7983,47.8771],[-91.7983,47.876],[-91.7988,47.8618],[-91.7992,47.8464],[-91.8,47.8319],[-91.8,47.8175],[-91.7999,47.8031],[-91.7997,47.7916],[-91.7997,47.7893],[-91.7997,47.7886],[-91.7995,47.7774],[-91.7995,47.776],[-91.7995,47.7742],[-91.7995,47.7723],[-91.7992,47.7626],[-91.7992,47.7598],[-91.7992,47.7538],[-91.7993,47.7482],[-91.7993,47.7454],[-91.7992,47.7388],[-91.7992,47.7339],[-91.799,47.731],[-91.7984,47.7201],[-91.7982,47.717],[-91.7981,47.7165],[-91.7977,47.7128],[-91.7971,47.707],[-91.7967,47.7024],[-91.7959,47.6925],[-91.7959,47.688],[-91.7955,47.678],[-91.7955,47.6778],[-91.7955,47.6733],[-91.7954,47.6729],[-91.795,47.663],[-91.7948,47.6586],[-91.7942,47.6486],[-91.794,47.6449],[-91.794,47.6442],[-91.7933,47.6345],[-91.793,47.6299],[-91.7923,47.6212],[-91.7922,47.6193],[-91.7919,47.6155],[-91.7915,47.6091],[-91.7913,47.6049],[-91.7912,47.6021],[-91.7911,47.6008],[-91.7908,47.5904],[-91.7905,47.5874],[-91.7904,47.5864],[-91.7893,47.576],[-91.7892,47.5749],[-91.789,47.5719],[-91.7888,47.5614],[-91.7887,47.5588],[-91.7886,47.5574],[-91.7878,47.5469],[-91.788,47.5431],[-91.788,47.5424],[-91.7886,47.533],[-91.7886,47.5322],[-91.7889,47.5187],[-91.7889,47.5176],[-91.789,47.5067],[-91.7891,47.5041],[-91.7891,47.503],[-91.7894,47.493],[-91.7894,47.4897],[-91.7894,47.4886],[-91.7895,47.4753],[-91.7895,47.4741],[-91.7895,47.4605],[-91.7895,47.4574],[-91.7893,47.4449],[-91.7894,47.4303],[-91.7895,47.416],[-91.7896,47.4017],[-91.7904,47.3872],[-91.7906,47.3726],[-91.792,47.3726],[-91.792,47.3576],[-91.792,47.3432],[-91.7918,47.3288],[-91.7918,47.3145],[-91.7919,47.3],[-91.792,47.2855],[-91.7921,47.271],[-91.7922,47.2565],[-91.7923,47.2422],[-91.7923,47.2276],[-91.7923,47.2128],[-91.7922,47.1985],[-91.7923,47.1843],[-91.7923,47.1698],[-91.7923,47.1556],[-91.7923,47.1411],[-91.7924,47.1265],[-91.7922,47.1119],[-91.7943,47.1119],[-91.7945,47.0976],[-91.7945,47.0831],[-91.7944,47.0688],[-91.7944,47.0541],[-91.7943,47.0399],[-91.7943,47.0255],[-91.7944,47.0109],[-91.7944,46.9965],[-91.7944,46.9818],[-91.7944,46.9675],[-91.7943,46.953],[-91.7944,46.9397],[-91.7945,46.9397],[-91.7947,46.9396],[-91.7948,46.9395],[-91.795,46.9394],[-91.7951,46.9394],[-91.7952,46.9394],[-91.7953,46.9393],[-91.7954,46.9391],[-91.7955,46.939],[-91.7957,46.9388],[-91.7957,46.9386],[-91.7958,46.9384],[-91.7958,46.9384],[-91.7959,46.9383],[-91.796,46.9382],[-91.7961,46.9381],[-91.7964,46.938],[-91.7966,46.9379],[-91.797,46.9379],[-91.7971,46.9378],[-91.7974,46.9378],[-91.7975,46.9378],[-91.7978,46.9378],[-91.798,46.9379],[-91.7981,46.938],[-91.7983,46.938],[-91.7986,46.9379],[-91.7989,46.9379],[-91.7991,46.9379],[-91.7993,46.9379],[-91.7995,46.9378],[-91.7996,46.9377],[-91.7998,46.9376],[-91.8004,46.9373],[-91.8007,46.9371],[-91.8011,46.9369],[-91.8013,46.9368],[-91.8016,46.9367],[-91.802,46.9366],[-91.8022,46.9365],[-91.8025,46.9364],[-91.8028,46.9363],[-91.8032,46.9361],[-91.8034,46.936],[-91.8036,46.9359],[-91.8037,46.9357],[-91.804,46.9356],[-91.8042,46.9354],[-91.8044,46.9352],[-91.8046,46.935],[-91.8048,46.9349],[-91.805,46.9347],[-91.8051,46.9346],[-91.8053,46.9345],[-91.8055,46.9345],[-91.8057,46.9344],[-91.8059,46.9343],[-91.806,46.9343],[-91.8062,46.9342],[-91.8064,46.9341],[-91.8066,46.9338],[-91.8067,46.9336],[-91.8069,46.9334],[-91.807,46.9332],[-91.8071,46.9331],[-91.8071,46.933],[-91.8072,46.9329],[-91.8073,46.9328],[-91.8075,46.9328],[-91.8076,46.9327],[-91.8078,46.9327],[-91.808,46.9327],[-91.8082,46.9325],[-91.8084,46.9324],[-91.8087,46.9322],[-91.8089,46.932],[-91.8091,46.9319],[-91.8094,46.9317],[-91.8097,46.9315],[-91.81,46.9314],[-91.8103,46.9312],[-91.8106,46.9311],[-91.8107,46.931],[-91.8109,46.9309],[-91.811,46.9309],[-91.8112,46.9309],[-91.8113,46.9308],[-91.8116,46.9306],[-91.8117,46.9305],[-91.8119,46.9303],[-91.812,46.9301],[-91.8121,46.9299],[-91.8122,46.9298],[-91.8123,46.9296],[-91.8123,46.9293],[-91.8124,46.9291],[-91.8124,46.929],[-91.8125,46.9288],[-91.8126,46.9287],[-91.813,46.9281],[-91.8133,46.9277],[-91.8135,46.9275],[-91.8137,46.9272],[-91.8138,46.9271],[-91.8139,46.927],[-91.8141,46.9268],[-91.8142,46.9267],[-91.8144,46.9267],[-91.8147,46.9266],[-91.8149,46.9265],[-91.815,46.9263],[-91.8151,46.9263],[-91.8152,46.9262],[-91.8153,46.926],[-91.8154,46.9259],[-91.8154,46.9258],[-91.8155,46.9258],[-91.8157,46.9256],[-91.8159,46.9252],[-91.8162,46.925],[-91.8163,46.9248],[-91.8165,46.9247],[-91.8166,46.9246],[-91.8168,46.9244],[-91.817,46.9243],[-91.8171,46.9243],[-91.8173,46.9242],[-91.8175,46.9241],[-91.8177,46.924],[-91.8179,46.924],[-91.8182,46.9241],[-91.8184,46.9242],[-91.8186,46.9244],[-91.8187,46.9245],[-91.8189,46.9246],[-91.819,46.9246],[-91.8192,46.9247],[-91.8194,46.9248],[-91.8196,46.9248],[-91.8198,46.9248],[-91.8202,46.9248],[-91.8204,46.9248],[-91.8206,46.9248],[-91.8208,46.9249],[-91.821,46.925],[-91.822,46.9252],[-91.8222,46.9253],[-91.8224,46.9253],[-91.8227,46.9254],[-91.8232,46.9256],[-91.8234,46.9257],[-91.8237,46.9259],[-91.8238,46.926],[-91.824,46.9261],[-91.8241,46.9262],[-91.8242,46.9262],[-91.8243,46.9263],[-91.8243,46.9264],[-91.8245,46.9265],[-91.8252,46.9267],[-91.8255,46.9269],[-91.8256,46.9269],[-91.8258,46.927],[-91.8259,46.9272],[-91.826,46.9272],[-91.826,46.9273],[-91.8265,46.9274],[-91.8267,46.9274],[-91.827,46.9275],[-91.8274,46.9275],[-91.8277,46.9275],[-91.828,46.9275],[-91.8283,46.9275],[-91.8286,46.9275],[-91.8289,46.9275],[-91.8292,46.9275],[-91.8295,46.9275],[-91.83,46.9275],[-91.8303,46.9275],[-91.8307,46.9275],[-91.831,46.9275],[-91.8314,46.9274],[-91.8318,46.9274],[-91.8321,46.9274],[-91.8325,46.9274],[-91.8327,46.9273],[-91.833,46.9273],[-91.8332,46.9273],[-91.8335,46.9272],[-91.8337,46.9272],[-91.8342,46.9269],[-91.8345,46.9268],[-91.8347,46.9267],[-91.8348,46.9267],[-91.8348,46.9266],[-91.8349,46.9266],[-91.835,46.9266],[-91.835,46.9267],[-91.8348,46.9268],[-91.8348,46.9269],[-91.8347,46.927],[-91.8347,46.9271],[-91.8346,46.9272],[-91.8348,46.9272],[-91.8351,46.9271],[-91.8352,46.927],[-91.8355,46.9269],[-91.8357,46.9269],[-91.8359,46.9268],[-91.8361,46.9268],[-91.8363,46.9268],[-91.8365,46.9267],[-91.8365,46.9267],[-91.8367,46.9266],[-91.8368,46.9266],[-91.8369,46.9265],[-91.8371,46.9265],[-91.8374,46.9265],[-91.8376,46.9265],[-91.8377,46.9265],[-91.8379,46.9264],[-91.8381,46.9263],[-91.8383,46.9262],[-91.8386,46.9261],[-91.8389,46.9261],[-91.8391,46.926],[-91.8393,46.9259],[-91.8396,46.9258],[-91.8398,46.9257],[-91.8401,46.9256],[-91.8405,46.9255],[-91.8407,46.9254],[-91.841,46.9253],[-91.8413,46.9253],[-91.8415,46.9252],[-91.8417,46.9251],[-91.8418,46.9251],[-91.8424,46.9248],[-91.8426,46.9246],[-91.8431,46.9244],[-91.8432,46.9243],[-91.8435,46.9242],[-91.8441,46.9239],[-91.8446,46.9238],[-91.8449,46.9236],[-91.8454,46.9234],[-91.8457,46.9233],[-91.8458,46.9232],[-91.8461,46.923],[-91.8464,46.9229],[-91.8466,46.9226],[-91.847,46.9224],[-91.8472,46.9223],[-91.8474,46.9221],[-91.8475,46.922],[-91.8476,46.9219],[-91.8477,46.9219],[-91.8478,46.9218],[-91.8481,46.9216],[-91.8484,46.9215],[-91.8486,46.9213],[-91.8488,46.9211],[-91.8491,46.9209],[-91.8493,46.9208],[-91.8495,46.9207],[-91.8497,46.9204],[-91.8499,46.9203],[-91.8501,46.9201],[-91.8502,46.9199],[-91.8504,46.9198],[-91.8505,46.9197],[-91.8506,46.9197],[-91.8511,46.9193],[-91.8512,46.9192],[-91.8513,46.919],[-91.8514,46.9188],[-91.8517,46.9185],[-91.8519,46.9182],[-91.8521,46.9179],[-91.8524,46.9175],[-91.8526,46.9171],[-91.8528,46.9168],[-91.8531,46.9165],[-91.8533,46.9162],[-91.8535,46.9158],[-91.8536,46.9156],[-91.8538,46.9155],[-91.854,46.9153],[-91.8542,46.9151],[-91.8544,46.915],[-91.8546,46.9148],[-91.8548,46.9146],[-91.855,46.9144],[-91.8551,46.9143],[-91.8552,46.9142],[-91.8553,46.9141],[-91.8555,46.9139],[-91.8557,46.9137],[-91.8559,46.9136],[-91.8562,46.9136],[-91.8565,46.9134],[-91.8568,46.9132],[-91.8569,46.9131],[-91.857,46.9131],[-91.8571,46.913],[-91.8572,46.9129],[-91.8576,46.9127],[-91.8579,46.9126],[-91.8581,46.9126],[-91.8583,46.9126],[-91.8584,46.9126],[-91.8585,46.9124],[-91.8588,46.9122],[-91.8591,46.912],[-91.8596,46.9116],[-91.8599,46.9115],[-91.8602,46.9114],[-91.8603,46.9113],[-91.8605,46.9112],[-91.8607,46.911],[-91.8609,46.9109],[-91.861,46.9108],[-91.8612,46.9107],[-91.8613,46.9106],[-91.8614,46.9105],[-91.8615,46.9104],[-91.8617,46.9103],[-91.8619,46.9102],[-91.8625,46.9101],[-91.863,46.91],[-91.8633,46.91],[-91.8635,46.9099],[-91.8637,46.9099],[-91.8639,46.9097],[-91.8642,46.9096],[-91.8644,46.9095],[-91.8644,46.9095],[-91.8646,46.9094],[-91.8648,46.9093],[-91.865,46.9092],[-91.8652,46.909],[-91.8654,46.9089],[-91.8656,46.9089],[-91.8659,46.9088],[-91.8662,46.9087],[-91.8664,46.9087],[-91.8666,46.9086],[-91.8668,46.9086],[-91.8675,46.9084],[-91.8679,46.9084],[-91.8681,46.9085],[-91.8684,46.9085],[-91.8686,46.9085],[-91.8688,46.9085],[-91.8691,46.9085],[-91.8693,46.9085],[-91.8705,46.9084],[-91.8709,46.9084],[-91.8711,46.9084],[-91.8714,46.9083],[-91.8717,46.9083],[-91.8724,46.9082],[-91.8734,46.9081],[-91.874,46.9081],[-91.8745,46.908],[-91.8749,46.908],[-91.8751,46.908],[-91.8755,46.9078],[-91.8758,46.9075],[-91.8761,46.9074],[-91.8764,46.9073],[-91.8766,46.9073],[-91.8768,46.9072],[-91.8772,46.9072],[-91.8775,46.9072],[-91.878,46.9071],[-91.8782,46.9071],[-91.879,46.9067],[-91.8797,46.9064],[-91.8802,46.9062],[-91.8807,46.906],[-91.8811,46.9058],[-91.8829,46.9047],[-91.885,46.9037],[-91.8854,46.9035],[-91.8856,46.9033],[-91.8858,46.9032],[-91.8859,46.903],[-91.8861,46.9029],[-91.8861,46.9028],[-91.8864,46.9027],[-91.8866,46.9026],[-91.8868,46.9025],[-91.8873,46.9021],[-91.8875,46.9019],[-91.8882,46.9015],[-91.8885,46.9015],[-91.8887,46.9015],[-91.8889,46.9015],[-91.8892,46.9014],[-91.8905,46.9005],[-91.891,46.9001],[-91.8912,46.8998],[-91.8915,46.8996],[-91.8918,46.8994],[-91.892,46.8994],[-91.8933,46.8987],[-91.8947,46.8979],[-91.895,46.8977],[-91.8953,46.8975],[-91.8955,46.8973],[-91.8956,46.8971],[-91.8957,46.8969],[-91.8961,46.8966],[-91.8971,46.8959],[-91.8976,46.8955],[-91.8981,46.8952],[-91.8986,46.895],[-91.8987,46.895],[-91.899,46.8949],[-91.8992,46.8948],[-91.8994,46.8947],[-91.9004,46.894],[-91.9009,46.8937],[-91.901,46.8935],[-91.9013,46.8933],[-91.9026,46.8928],[-91.9029,46.8926],[-91.9031,46.8925],[-91.9034,46.8923],[-91.9037,46.892],[-91.9038,46.892],[-91.904,46.892],[-91.9043,46.8917],[-91.9045,46.8915],[-91.9049,46.8912],[-91.9053,46.8909],[-91.9057,46.8906],[-91.9066,46.89],[-91.9069,46.8896],[-91.907,46.8894],[-91.9081,46.8887],[-91.9086,46.8881],[-91.9088,46.8879],[-91.909,46.8876],[-91.9093,46.8873],[-91.9098,46.8867],[-91.9102,46.8864],[-91.9106,46.8862],[-91.9108,46.8862],[-91.9109,46.886],[-91.911,46.8859],[-91.911,46.8858],[-91.9111,46.8857],[-91.9112,46.8856],[-91.9113,46.8855],[-91.9115,46.8852],[-91.9116,46.885],[-91.9118,46.8848],[-91.9122,46.8845],[-91.913,46.8839],[-91.9134,46.8837],[-91.9137,46.8836],[-91.9139,46.8836],[-91.9142,46.8836],[-91.9141,46.8835],[-91.9142,46.8834],[-91.9143,46.8833],[-91.9145,46.8832],[-91.9147,46.8831],[-91.915,46.883],[-91.9153,46.8829],[-91.9156,46.8827],[-91.9159,46.8826],[-91.9161,46.8824],[-91.9169,46.882],[-91.9173,46.8818],[-91.9178,46.8816],[-91.9191,46.8812],[-91.9194,46.8811],[-91.9197,46.881],[-91.9199,46.8808],[-91.9201,46.8807],[-91.9204,46.8805],[-91.9205,46.8805],[-91.9209,46.8804],[-91.9214,46.8803],[-91.9226,46.8799],[-91.923,46.8797],[-91.9235,46.8796],[-91.9244,46.8792],[-91.9256,46.8788],[-91.926,46.8786],[-91.9263,46.8786],[-91.9268,46.8784],[-91.9276,46.8781],[-91.928,46.878],[-91.9284,46.8777],[-91.9297,46.8771],[-91.9301,46.8769],[-91.9305,46.8767],[-91.9309,46.8764],[-91.9312,46.8762],[-91.9315,46.8761],[-91.9316,46.876],[-91.9317,46.8759],[-91.9318,46.8758],[-91.9319,46.8758],[-91.932,46.8757],[-91.9321,46.8755],[-91.9322,46.8755],[-91.9324,46.8754],[-91.9326,46.8753],[-91.9329,46.8752],[-91.9332,46.8752],[-91.9335,46.8751],[-91.9337,46.8751],[-91.9339,46.875],[-91.934,46.8749],[-91.9341,46.8748],[-91.9343,46.8746],[-91.9345,46.8744],[-91.9346,46.8743],[-91.9349,46.874],[-91.9353,46.8738],[-91.9358,46.8737],[-91.9362,46.8736],[-91.9368,46.8735],[-91.9374,46.8734],[-91.938,46.8734],[-91.9386,46.8732],[-91.9391,46.873],[-91.9397,46.8727],[-91.9403,46.8723],[-91.9408,46.8721],[-91.941,46.8719],[-91.9411,46.8717],[-91.9413,46.8717],[-91.9415,46.8718],[-91.9416,46.8717],[-91.9417,46.8717],[-91.9419,46.8715],[-91.942,46.8712],[-91.9422,46.871],[-91.9424,46.8709],[-91.9428,46.8708],[-91.943,46.8708],[-91.9432,46.8706],[-91.9435,46.8704],[-91.9438,46.8704],[-91.9444,46.8702],[-91.9449,46.8699],[-91.9456,46.8696],[-91.9465,46.8694],[-91.9475,46.8691],[-91.9484,46.8688],[-91.9492,46.8685],[-91.9496,46.8682],[-91.9499,46.8679],[-91.9502,46.8678],[-91.9507,46.8677],[-91.9513,46.8675],[-91.952,46.8671],[-91.9524,46.8668],[-91.9527,46.8665],[-91.953,46.8662],[-91.9535,46.8659],[-91.9536,46.8658],[-91.9545,46.8654],[-91.9552,46.8651],[-91.956,46.8645],[-91.9565,46.8641],[-91.9568,46.8638],[-91.957,46.8636],[-91.9574,46.8633],[-91.9577,46.8631],[-91.9581,46.8628],[-91.9587,46.8623],[-91.959,46.8619],[-91.9593,46.8617],[-91.9596,46.8616],[-91.96,46.8614],[-91.9604,46.8612],[-91.9608,46.8609],[-91.9611,46.8605],[-91.9615,46.8602],[-91.9621,46.86],[-91.9627,46.8597],[-91.963,46.8596],[-91.9633,46.8595],[-91.964,46.8592],[-91.9646,46.8589],[-91.965,46.8586],[-91.9654,46.8582],[-91.9657,46.858],[-91.966,46.8579],[-91.9663,46.8578],[-91.9667,46.8576],[-91.9669,46.8576],[-91.967,46.8575],[-91.9671,46.8574],[-91.9672,46.8573],[-91.9673,46.8571],[-91.9675,46.857],[-91.9677,46.857],[-91.9679,46.8571],[-91.9681,46.857],[-91.9683,46.8569],[-91.9686,46.8568],[-91.9688,46.8567],[-91.9692,46.8565],[-91.9695,46.8564],[-91.97,46.8563],[-91.9704,46.8563],[-91.9708,46.8562],[-91.9711,46.8561],[-91.9714,46.8562],[-91.9716,46.8561],[-91.972,46.8559],[-91.9724,46.8558],[-91.9728,46.8558],[-91.9731,46.8559],[-91.9732,46.8558],[-91.9734,46.8557],[-91.9736,46.8556],[-91.974,46.8555],[-91.9741,46.8554],[-91.9742,46.8553],[-91.9745,46.8552],[-91.9748,46.8551],[-91.9751,46.8549],[-91.9754,46.8547],[-91.9755,46.8548],[-91.9757,46.8548],[-91.9762,46.8546],[-91.9764,46.8545],[-91.9767,46.8542],[-91.977,46.8539],[-91.9772,46.8537],[-91.9773,46.8534],[-91.9775,46.8533],[-91.9777,46.8533],[-91.978,46.8532],[-91.9784,46.853],[-91.9787,46.8529],[-91.9791,46.8526],[-91.9792,46.8525],[-91.9795,46.8524],[-91.9797,46.8523],[-91.98,46.8521],[-91.9802,46.8519],[-91.9805,46.8517],[-91.9808,46.8516],[-91.9811,46.8515],[-91.9815,46.8515],[-91.9819,46.8513],[-91.982,46.8513],[-91.9827,46.851],[-91.983,46.8508],[-91.9833,46.8506],[-91.9836,46.8504],[-91.9838,46.8503],[-91.9841,46.8503],[-91.9842,46.8502],[-91.9845,46.8501],[-91.9849,46.8499],[-91.9854,46.8496],[-91.9856,46.8495],[-91.9857,46.8493],[-91.9858,46.8491],[-91.986,46.8489],[-91.9861,46.8487],[-91.9863,46.8484],[-91.9866,46.8482],[-91.9869,46.848],[-91.987,46.8478],[-91.9871,46.8476],[-91.9875,46.8476],[-91.9877,46.8474],[-91.9881,46.8471],[-91.9884,46.8469],[-91.9885,46.8467],[-91.9885,46.8465],[-91.9887,46.8462],[-91.9889,46.846],[-91.9892,46.8458],[-91.9895,46.8456],[-91.9898,46.8455],[-91.9901,46.8454],[-91.9903,46.8451],[-91.9906,46.845],[-91.9908,46.8448],[-91.991,46.8446],[-91.9913,46.8443],[-91.9915,46.844],[-91.9918,46.8437],[-91.992,46.8434],[-91.9923,46.8431],[-91.9926,46.8427],[-91.9928,46.8424],[-91.9931,46.8422],[-91.9934,46.8421],[-91.9938,46.842],[-91.9941,46.8419],[-91.9944,46.8417],[-91.9949,46.8414],[-91.9954,46.8411],[-91.9959,46.8409],[-91.9964,46.8407],[-91.9969,46.8405],[-91.9973,46.8403],[-91.9978,46.84],[-91.9981,46.8397],[-91.9983,46.8395],[-91.9983,46.8392],[-91.9985,46.839],[-91.9986,46.8389],[-91.999,46.8387],[-91.9992,46.8386],[-91.9997,46.8384],[-92.0001,46.8381],[-92.0002,46.8381],[-92.0003,46.8382],[-92.0005,46.8381],[-92.0007,46.838],[-92.0009,46.838],[-92.0012,46.8379],[-92.0014,46.8377],[-92.0016,46.8375],[-92.0019,46.8374],[-92.0022,46.8373],[-92.0025,46.8373],[-92.003,46.8372],[-92.0033,46.8372],[-92.0036,46.8372],[-92.0039,46.8372],[-92.0041,46.8371],[-92.0042,46.837],[-92.0044,46.8369],[-92.0045,46.8369],[-92.0048,46.8367],[-92.0051,46.8366],[-92.0055,46.8366],[-92.0055,46.8366],[-92.0058,46.8364],[-92.0059,46.8363],[-92.0059,46.8362],[-92.0059,46.8361],[-92.006,46.8361],[-92.0061,46.836],[-92.0062,46.8359],[-92.0064,46.8359],[-92.0068,46.8358],[-92.007,46.8358],[-92.0072,46.8358],[-92.0074,46.8358],[-92.0078,46.8357],[-92.008,46.8357],[-92.0083,46.8357],[-92.0086,46.8356],[-92.0088,46.8356],[-92.009,46.8356],[-92.0093,46.8356],[-92.0096,46.8356],[-92.0101,46.8355],[-92.0105,46.8354],[-92.0106,46.8354],[-92.0109,46.8353],[-92.0112,46.8352],[-92.0115,46.8351],[-92.0117,46.8351],[-92.0118,46.835],[-92.012,46.835],[-92.0125,46.8348],[-92.0126,46.8348],[-92.0128,46.8346],[-92.013,46.8345],[-92.0132,46.8344],[-92.0134,46.8343],[-92.0136,46.8342],[-92.0137,46.8342],[-92.0139,46.834],[-92.0141,46.8338],[-92.0143,46.8338],[-92.0143,46.8337],[-92.0145,46.8336],[-92.0147,46.8336],[-92.0149,46.8336],[-92.0152,46.8336],[-92.0156,46.8336],[-92.016,46.8335],[-92.0165,46.8334],[-92.0169,46.8334],[-92.0172,46.8333],[-92.0177,46.8331],[-92.018,46.833],[-92.0184,46.8327],[-92.0185,46.8326],[-92.0187,46.8324],[-92.0189,46.8322],[-92.019,46.8321],[-92.0192,46.8319],[-92.0193,46.8318],[-92.0193,46.8317],[-92.0194,46.8317],[-92.0196,46.8316],[-92.0198,46.8316],[-92.0201,46.8315],[-92.0206,46.8314],[-92.0209,46.8313],[-92.0213,46.8312],[-92.0214,46.8311],[-92.0218,46.8309],[-92.0221,46.8307],[-92.0225,46.8305],[-92.023,46.8302],[-92.0234,46.83],[-92.0236,46.8298],[-92.0238,46.8296],[-92.024,46.8295],[-92.0241,46.8294],[-92.0243,46.8293],[-92.0245,46.8292],[-92.0247,46.8291],[-92.0249,46.8291],[-92.025,46.829],[-92.0252,46.8289],[-92.0253,46.8288],[-92.0255,46.8286],[-92.0256,46.8284],[-92.0257,46.8283],[-92.0259,46.8282],[-92.0261,46.828],[-92.0263,46.8277],[-92.0264,46.8276],[-92.0266,46.8274],[-92.0267,46.8272],[-92.0267,46.8271],[-92.0268,46.827],[-92.0268,46.827],[-92.0268,46.8269],[-92.0269,46.8268],[-92.027,46.8267],[-92.0272,46.8266],[-92.0272,46.8266],[-92.0274,46.8265],[-92.0275,46.8265],[-92.0276,46.8264],[-92.0277,46.8263],[-92.0277,46.8262],[-92.0277,46.8261],[-92.0278,46.826],[-92.0278,46.826],[-92.0278,46.8259],[-92.0279,46.8259],[-92.0281,46.8258],[-92.0282,46.8256],[-92.0283,46.8255],[-92.0284,46.8254],[-92.0285,46.8252],[-92.0285,46.825],[-92.0287,46.8249],[-92.0287,46.8248],[-92.0289,46.8246],[-92.0291,46.8245],[-92.0294,46.8244],[-92.0295,46.8242],[-92.0297,46.8242],[-92.0299,46.8241],[-92.0301,46.824],[-92.0303,46.824],[-92.0307,46.824],[-92.0309,46.8239],[-92.0311,46.8238],[-92.0313,46.8237],[-92.0315,46.8236],[-92.0316,46.8234],[-92.0317,46.8233],[-92.0318,46.8231],[-92.0318,46.8231],[-92.0319,46.823],[-92.032,46.8229],[-92.0322,46.8228],[-92.0326,46.8226],[-92.0329,46.8224],[-92.0329,46.8224],[-92.0333,46.8222],[-92.0335,46.8222],[-92.0337,46.8221],[-92.0338,46.822],[-92.0339,46.8219],[-92.0343,46.8218],[-92.0347,46.8218],[-92.0352,46.8217],[-92.0358,46.8215],[-92.0364,46.8214],[-92.0369,46.8213],[-92.0372,46.8212],[-92.0376,46.8211],[-92.038,46.8209],[-92.0382,46.8207],[-92.0384,46.8205],[-92.0385,46.8204],[-92.0386,46.8203],[-92.0387,46.8203],[-92.0388,46.8202],[-92.0389,46.8202],[-92.0392,46.8202],[-92.0397,46.8201],[-92.04,46.8201],[-92.0401,46.8202],[-92.0405,46.8202],[-92.0408,46.8203],[-92.0411,46.8203],[-92.0414,46.8203],[-92.0417,46.8203],[-92.0419,46.8202],[-92.0421,46.8201],[-92.0423,46.8201],[-92.0425,46.82],[-92.0427,46.82],[-92.0429,46.82],[-92.0431,46.8199],[-92.0434,46.8197],[-92.0437,46.8196],[-92.044,46.8195],[-92.0441,46.8194],[-92.0443,46.8193],[-92.0445,46.8193],[-92.0447,46.8192],[-92.045,46.8191],[-92.0452,46.819],[-92.0454,46.8189],[-92.0456,46.8188],[-92.0457,46.8187],[-92.0459,46.8186],[-92.046,46.8185],[-92.0461,46.8183],[-92.0462,46.8182],[-92.0462,46.8181],[-92.0463,46.818],[-92.0463,46.8179],[-92.0464,46.8178],[-92.0465,46.8177],[-92.0466,46.8175],[-92.0467,46.8174],[-92.0468,46.8173],[-92.0469,46.8173],[-92.0469,46.8173],[-92.0471,46.8172],[-92.0473,46.8171],[-92.0474,46.8171],[-92.0476,46.8169],[-92.0478,46.8169],[-92.048,46.8167],[-92.0481,46.8166],[-92.0481,46.8165],[-92.0482,46.8164],[-92.0483,46.8164],[-92.0484,46.8163],[-92.0485,46.8162],[-92.0486,46.8161],[-92.0489,46.816],[-92.049,46.8158],[-92.0492,46.8157],[-92.0494,46.8156],[-92.0495,46.8155],[-92.0497,46.8154],[-92.0498,46.8151],[-92.0499,46.815],[-92.05,46.8148],[-92.0501,46.8146],[-92.0503,46.8144],[-92.0504,46.8144],[-92.0505,46.8144],[-92.0507,46.8144],[-92.0509,46.8143],[-92.0511,46.8143],[-92.0513,46.8143],[-92.0517,46.8142],[-92.0519,46.8142],[-92.0523,46.814],[-92.0525,46.8139],[-92.0527,46.8138],[-92.0529,46.8137],[-92.0531,46.8135],[-92.0533,46.8132],[-92.0535,46.8131],[-92.0537,46.8128],[-92.0539,46.8126],[-92.054,46.8124],[-92.054,46.8123],[-92.0542,46.812],[-92.0544,46.8118],[-92.0546,46.8117],[-92.0549,46.8115],[-92.0551,46.8115],[-92.0553,46.8113],[-92.0556,46.8112],[-92.0559,46.811],[-92.0563,46.8109],[-92.0566,46.8108],[-92.0569,46.8107],[-92.0573,46.8106],[-92.0575,46.8106],[-92.0581,46.8106],[-92.0583,46.8105],[-92.0587,46.8104],[-92.0588,46.8103],[-92.059,46.8101],[-92.0593,46.8099],[-92.0594,46.8097],[-92.0595,46.8095],[-92.0597,46.8092],[-92.0598,46.809],[-92.06,46.8087],[-92.06,46.8084],[-92.0602,46.808],[-92.0602,46.8078],[-92.0603,46.8074],[-92.0605,46.8071],[-92.0606,46.8069],[-92.0608,46.8066],[-92.061,46.8065],[-92.0611,46.8063],[-92.0612,46.8061],[-92.0612,46.8059],[-92.0613,46.8057],[-92.0616,46.8054],[-92.0617,46.8052],[-92.0619,46.8049],[-92.0621,46.8047],[-92.0622,46.8045],[-92.0625,46.8044],[-92.0627,46.8042],[-92.063,46.8041],[-92.0634,46.8039],[-92.0637,46.8038],[-92.064,46.8037],[-92.0642,46.8037],[-92.0646,46.8035],[-92.0649,46.8034],[-92.0652,46.8033],[-92.0656,46.8031],[-92.0659,46.803],[-92.0662,46.8028],[-92.0665,46.8026],[-92.0668,46.8024],[-92.067,46.8024],[-92.0674,46.8023],[-92.0677,46.8022],[-92.068,46.8022],[-92.0682,46.8023],[-92.0685,46.8023],[-92.0686,46.8023],[-92.0686,46.8023],[-92.0689,46.8024],[-92.0691,46.8023],[-92.0694,46.8023],[-92.0696,46.8022],[-92.0699,46.802],[-92.0702,46.8018],[-92.0705,46.8016],[-92.0707,46.8014],[-92.0708,46.8012],[-92.071,46.801],[-92.0712,46.8008],[-92.0713,46.8007],[-92.0715,46.8006],[-92.0716,46.8006],[-92.0718,46.8006],[-92.072,46.8007],[-92.0721,46.8007],[-92.0723,46.8006],[-92.0726,46.8006],[-92.0728,46.8005],[-92.0731,46.8004],[-92.0736,46.8002],[-92.0739,46.8],[-92.0741,46.7999],[-92.0743,46.7997],[-92.0746,46.7995],[-92.0749,46.7994],[-92.0752,46.7993],[-92.0755,46.7992],[-92.0758,46.7991],[-92.0762,46.7989],[-92.0764,46.7988],[-92.0765,46.7986],[-92.0766,46.7985],[-92.0767,46.7983],[-92.0769,46.7983],[-92.0771,46.7983],[-92.0774,46.7983],[-92.0775,46.7982],[-92.0777,46.7981],[-92.0778,46.798],[-92.0779,46.7979],[-92.078,46.7978],[-92.078,46.7977],[-92.0781,46.7975],[-92.0782,46.7974],[-92.0783,46.7973],[-92.0785,46.7973],[-92.0785,46.7973],[-92.0787,46.7974],[-92.0788,46.7974],[-92.0791,46.7974],[-92.0794,46.7973],[-92.0796,46.7973],[-92.0798,46.7973],[-92.0801,46.7973],[-92.0804,46.7973],[-92.0806,46.7973],[-92.0809,46.7972],[-92.0812,46.7971],[-92.0814,46.797],[-92.0815,46.7969],[-92.0817,46.7967],[-92.0819,46.7966],[-92.082,46.7965],[-92.0821,46.7963],[-92.0821,46.7962],[-92.0822,46.796],[-92.0823,46.7959],[-92.0825,46.7959],[-92.0828,46.7958],[-92.0831,46.7958],[-92.0835,46.7957],[-92.0838,46.7957],[-92.0841,46.7957],[-92.0844,46.7957],[-92.0847,46.7957],[-92.085,46.7957],[-92.0853,46.7956],[-92.0856,46.7955],[-92.0857,46.7954],[-92.0858,46.7953],[-92.0859,46.7952],[-92.0861,46.7951],[-92.0862,46.795],[-92.0863,46.7948],[-92.0864,46.7947],[-92.0867,46.7946],[-92.0869,46.7945],[-92.0872,46.7944],[-92.0875,46.7943],[-92.0878,46.7941],[-92.0881,46.794],[-92.0884,46.7938],[-92.0886,46.7937],[-92.0889,46.7935],[-92.0891,46.7933],[-92.0892,46.7931],[-92.0892,46.7931],[-92.0893,46.7929],[-92.0895,46.7926],[-92.0897,46.7924],[-92.0899,46.7923],[-92.0901,46.7921],[-92.0902,46.792],[-92.0903,46.7919],[-92.0904,46.7917],[-92.0903,46.7916],[-92.0903,46.7915],[-92.0903,46.7913],[-92.0904,46.7912],[-92.0905,46.791],[-92.0905,46.7908],[-92.0907,46.7905],[-92.0908,46.7902],[-92.091,46.7898],[-92.0912,46.7896],[-92.0913,46.7895],[-92.0915,46.7893],[-92.0918,46.7892],[-92.092,46.7892],[-92.0923,46.7892],[-92.0928,46.7889],[-92.0929,46.7888],[-92.0932,46.7887],[-92.0934,46.7885],[-92.0936,46.7883],[-92.0938,46.7881],[-92.0939,46.788],[-92.094,46.7877],[-92.0941,46.7875],[-92.0941,46.7874],[-92.094,46.7872],[-92.094,46.7871],[-92.094,46.7869],[-92.0939,46.7867],[-92.0938,46.7864],[-92.0936,46.786],[-92.0935,46.7857],[-92.0934,46.7854],[-92.0934,46.7852],[-92.0933,46.7849],[-92.0932,46.7848],[-92.0932,46.7845],[-92.0931,46.7842],[-92.093,46.7839],[-92.0929,46.7836],[-92.0926,46.7832],[-92.0925,46.783],[-92.0924,46.7828],[-92.0923,46.7826],[-92.0921,46.7825],[-92.092,46.7823],[-92.0919,46.7821],[-92.0918,46.7819],[-92.0917,46.7817],[-92.0916,46.7814],[-92.0915,46.7813],[-92.0913,46.781],[-92.0911,46.7807],[-92.091,46.7804],[-92.0912,46.7801],[-92.0914,46.7787],[-92.0914,46.7784],[-92.0909,46.7775],[-92.0908,46.7773],[-92.09,46.7762],[-92.0897,46.7757],[-92.0894,46.7754],[-92.0892,46.7751],[-92.0889,46.7747],[-92.0888,46.7743],[-92.0879,46.7731],[-92.0879,46.773],[-92.0878,46.773],[-92.0876,46.7727],[-92.0859,46.7704],[-92.0859,46.7702],[-92.0849,46.7691],[-92.0846,46.7687],[-92.0842,46.7682],[-92.0838,46.7676],[-92.0829,46.7665],[-92.0829,46.7664],[-92.0826,46.7659],[-92.0819,46.7651],[-92.0812,46.7644],[-92.0811,46.7642],[-92.0784,46.7609],[-92.0781,46.7606],[-92.0768,46.759],[-92.0767,46.7588],[-92.0765,46.7587],[-92.0764,46.7584],[-92.076,46.7581],[-92.0758,46.7578],[-92.0739,46.7555],[-92.0735,46.7552],[-92.0735,46.755],[-92.073,46.7546],[-92.0729,46.7544],[-92.0726,46.754],[-92.0724,46.754],[-92.0724,46.7538],[-92.0717,46.7532],[-92.0716,46.753],[-92.0707,46.7521],[-92.0706,46.7519],[-92.0703,46.7517],[-92.0694,46.7506],[-92.0693,46.7505],[-92.069,46.7502],[-92.0688,46.75],[-92.0686,46.7497],[-92.0684,46.7495],[-92.0681,46.7491],[-92.0679,46.7489],[-92.0677,46.7487],[-92.0676,46.7486],[-92.0672,46.7481],[-92.0668,46.7478],[-92.0658,46.7466],[-92.0633,46.7441],[-92.0629,46.7437],[-92.0628,46.7435],[-92.0625,46.7432],[-92.0623,46.743],[-92.062,46.7427],[-92.0618,46.7424],[-92.0614,46.7421],[-92.0613,46.7419],[-92.0607,46.7414],[-92.0597,46.7403],[-92.0592,46.7399],[-92.0588,46.7394],[-92.0575,46.7381],[-92.0568,46.7374],[-92.0563,46.737],[-92.0559,46.7366],[-92.0546,46.7353],[-92.0546,46.7352],[-92.0544,46.7352],[-92.0542,46.735],[-92.054,46.7347],[-92.0504,46.7315],[-92.0477,46.7291],[-92.0466,46.7282],[-92.0466,46.728],[-92.0463,46.7279],[-92.0459,46.7275],[-92.0448,46.7265],[-92.0376,46.7206],[-92.037,46.7201],[-92.0348,46.7183],[-92.0274,46.7118],[-92.0269,46.7114],[-92.0267,46.7113],[-92.0265,46.7112],[-92.0264,46.7112],[-92.0258,46.7114],[-92.0253,46.7111],[-92.0243,46.7109],[-92.0214,46.7108],[-92.0205,46.7107],[-92.0194,46.7106],[-92.0192,46.7102],[-92.0192,46.7099],[-92.0187,46.7088],[-92.0174,46.7072],[-92.0164,46.7062],[-92.0163,46.706],[-92.0202,46.7041],[-92.025,46.7058],[-92.0262,46.7062],[-92.0269,46.7065],[-92.0339,46.709],[-92.0428,46.7153],[-92.0479,46.719],[-92.0501,46.7206],[-92.0594,46.7274],[-92.0648,46.7312],[-92.0687,46.734],[-92.0701,46.735],[-92.0713,46.7359],[-92.0894,46.7493],[-92.0985,46.7491],[-92.1001,46.7491],[-92.1081,46.7492],[-92.1086,46.749],[-92.1102,46.749],[-92.1138,46.7489],[-92.1165,46.7487],[-92.1173,46.7484],[-92.1184,46.7479],[-92.1252,46.745],[-92.1317,46.7422],[-92.1378,46.7396],[-92.1428,46.7351],[-92.1429,46.735],[-92.1432,46.7347],[-92.1433,46.7306],[-92.1433,46.7282],[-92.1412,46.7253],[-92.1438,46.7205],[-92.1448,46.7184],[-92.1462,46.716],[-92.1467,46.7158],[-92.1486,46.7152],[-92.1534,46.7158],[-92.1551,46.716],[-92.1672,46.72],[-92.1708,46.7189],[-92.1719,46.7185],[-92.1742,46.7173],[-92.1747,46.7172],[-92.176,46.7171],[-92.1788,46.7168],[-92.189,46.7176],[-92.1914,46.7163],[-92.1916,46.7157],[-92.1917,46.7153],[-92.1932,46.7113],[-92.1959,46.7089],[-92.1973,46.7077],[-92.1997,46.7067],[-92.2003,46.7064],[-92.2004,46.7064],[-92.201,46.7062],[-92.2015,46.706],[-92.2019,46.7058],[-92.2026,46.7054],[-92.2046,46.7041],[-92.2056,46.7026],[-92.2051,46.6984],[-92.1984,46.6962],[-92.1956,46.696],[-92.1892,46.6956],[-92.183,46.6953],[-92.178,46.692],[-92.1778,46.6919],[-92.1764,46.6903],[-92.176,46.6864],[-92.1775,46.6835],[-92.1813,46.6803],[-92.1824,46.68],[-92.1875,46.679],[-92.1906,46.6776],[-92.1916,46.6772],[-92.1924,46.6768],[-92.1957,46.6741],[-92.1958,46.674],[-92.1994,46.6703],[-92.204,46.667],[-92.2054,46.6648],[-92.2046,46.6634],[-92.2021,46.659],[-92.2015,46.6567],[-92.2022,46.6551],[-92.2044,46.6537],[-92.207,46.652],[-92.2123,46.65],[-92.2163,46.6499],[-92.2166,46.65],[-92.2234,46.6527],[-92.2262,46.6529],[-92.2284,46.653],[-92.2355,46.6501],[-92.2376,46.6498],[-92.2424,46.6493],[-92.2486,46.6535],[-92.2509,46.655],[-92.2521,46.6558],[-92.2525,46.6561],[-92.2545,46.6574],[-92.2549,46.6577],[-92.2556,46.6581],[-92.2565,46.6588],[-92.2587,46.6577],[-92.2596,46.6572],[-92.2659,46.6511],[-92.2705,46.6508],[-92.2727,46.6529],[-92.2735,46.655],[-92.2743,46.6575],[-92.2784,46.6587],[-92.2799,46.6587],[-92.2836,46.6589],[-92.2842,46.6592],[-92.2844,46.6594],[-92.2861,46.6604],[-92.287,46.6629],[-92.2871,46.6631],[-92.2872,46.6647],[-92.2873,46.6669],[-92.2873,46.6674],[-92.2881,46.6676],[-92.2907,46.6681],[-92.2912,46.6682],[-92.2921,46.6661],[-92.2922,46.665],[-92.2921,46.6633],[-92.301,46.6636],[-92.3012,46.6773],[-92.3012,46.6919],[-92.3013,46.7063],[-92.3014,46.7208],[-92.3016,46.7353],[-92.3014,46.7498],[-92.3015,46.7643],[-92.3223,46.7652],[-92.3435,46.7651],[-92.3646,46.765],[-92.3856,46.765],[-92.4064,46.7649],[-92.4283,46.765],[-92.4495,46.7657],[-92.4705,46.7656],[-92.4924,46.7657],[-92.5125,46.7658],[-92.5336,46.7659],[-92.5548,46.7662],[-92.5759,46.7667],[-92.5967,46.7665],[-92.6177,46.7667],[-92.6385,46.767],[-92.6592,46.7692],[-92.6803,46.7692],[-92.7014,46.7687],[-92.7226,46.7682],[-92.7442,46.7677],[-92.7459,46.7677],[-92.7653,46.7674],[-92.7864,46.7666],[-92.8084,46.7661],[-92.8296,46.7661],[-92.8508,46.7662],[-92.8721,46.7664],[-92.8932,46.7666],[-92.9143,46.7661],[-92.9356,46.7662],[-92.9567,46.7662],[-92.9777,46.7665],[-92.9988,46.7669],[-93.0201,46.7668],[-93.0412,46.7667],[-93.0615,46.7667],[-93.0609,46.781],[-93.061,46.7956],[-93.0606,46.81],[-93.0606,46.8241],[-93.0603,46.8387],[-93.06,46.853],[-93.0597,46.8672],[-93.059,46.8817],[-93.0587,46.8964],[-93.0582,46.9108],[-93.0583,46.9251],[-93.0577,46.9398],[-93.0576,46.9541],[-93.0573,46.9685],[-93.0571,46.9832],[-93.0568,46.9976],[-93.0564,47.0121],[-93.0559,47.0265],[-93.0557,47.0407],[-93.0558,47.0551],[-93.0558,47.0698],[-93.0557,47.084],[-93.056,47.0984],[-93.0562,47.1093],[-93.0664,47.1094],[-93.0663,47.1239],[-93.0659,47.1382],[-93.0659,47.1526],[-93.0655,47.1671],[-93.0652,47.1814],[-93.0654,47.196],[-93.0654,47.2103],[-93.0655,47.2248],[-93.0657,47.2394],[-93.0658,47.2538],[-93.0657,47.2683],[-93.0658,47.2828],[-93.0658,47.2975],[-93.0652,47.3119],[-93.0647,47.3265],[-93.0645,47.3412],[-93.0644,47.3556],[-93.0644,47.3716],[-93.0666,47.3716],[-93.0689,47.386],[-93.0693,47.4003],[-93.0692,47.4148],[-93.0692,47.429],[-93.069,47.4434],[-93.0688,47.4578],[-93.0673,47.472],[-93.067,47.4859],[-93.0651,47.5003],[-93.0647,47.5147],[-93.0641,47.529],[-93.0637,47.5445],[-93.0637,47.559],[-93.0638,47.5734],[-93.0628,47.5875],[-93.0628,47.6026],[-93.0643,47.6172],[-93.0637,47.6333],[-93.0637,47.6476],[-93.0633,47.6621],[-93.0626,47.6774],[-93.0619,47.691],[-93.0612,47.7056],[-93.0613,47.7205],[-93.0821,47.7206],[-93.0823,47.7355],[-93.0823,47.7493],[-93.0826,47.7635],[-93.083,47.7779],[-93.0834,47.7917],[-93.0837,47.8064],[-93.0837,47.8209],[-93.0837,47.8223],[-93.0831,47.835],[-93.083,47.8368],[-93.0823,47.8494],[-93.0822,47.8513],[-93.0815,47.8637],[-93.0813,47.8656],[-93.0812,47.8676],[-93.0808,47.878],[-93.0807,47.88],[-93.0808,47.8922],[-93.0808,47.8945],[-93.0809,47.9067],[-93.0809,47.9088],[-93.0809,47.9212],[-93.0809,47.9235],[-93.0809,47.9356],[-93.0809,47.938],[-93.0808,47.9504],[-93.0808,47.9525],[-93.0808,47.9647],[-93.0809,47.967],[-93.0809,47.9786],[-93.088,47.9787],[-93.0872,47.9932],[-93.0887,48.0075],[-93.0886,48.022],[-93.089,48.0366],[-93.0892,48.0509],[-93.0892,48.0679],[-93.0965,48.0678],[-93.0965,48.0679],[-93.0968,48.0823],[-93.097,48.0969],[-93.0972,48.1114],[-93.0969,48.1259],[-93.097,48.1402],[-93.097,48.1546],[-93.097,48.1692],[-93.0975,48.1836],[-93.0979,48.1981],[-93.0978,48.2126],[-93.0977,48.2271],[-93.0977,48.2426],[-93.0949,48.2425],[-93.0949,48.2426],[-93.0953,48.2576],[-93.0952,48.2716],[-93.095,48.2862],[-93.0952,48.3004],[-93.0953,48.3153],[-93.0948,48.3298],[-93.0948,48.3442],[-93.0945,48.3589],[-93.094,48.3734],[-93.094,48.3879],[-93.0938,48.4024],[-93.0935,48.4147],[-93.0923,48.4147],[-93.0922,48.429],[-93.0922,48.4303],[-93.092,48.4436],[-93.092,48.4449],[-93.0919,48.458],[-93.0918,48.4596],[-93.0915,48.4724],[-93.0914,48.474],[-93.0911,48.4867],[-93.091,48.4884],[-93.0905,48.501],[-93.0905,48.5151],[-93.0903,48.5296],[-93.0902,48.5441],[-93.0902,48.5583],[-93.09,48.5727],[-93.0898,48.5872],[-93.0895,48.6016],[-93.0886,48.6163],[-93.0884,48.6278]]],"type":"Polygon"},"id":"69","properties":{"Area":17451037319.2417,"CTYONLY_":7,"Code":"STLO","LASTMOD":"2010-10-17T00:00:00Z","Name":"St. Louis","Perimiter":682518.436},"type":"Feature"},{"geometry":{"coordinates":[[[-95.3425,48.5402],[-95.3412,48.5402],[-95.321,48.54],[-95.3194,48.54],[-95.2992,48.5402],[-95.2975,48.5401],[-95.2773,48.54],[-95.2756,48.54],[-95.2554,48.5398],[-95.2537,48.5398],[-95.2339,48.5399],[-95.2324,48.5399],[-95.2119,48.54],[-95.2115,48.5252],[-95.2115,48.5244],[-95.2111,48.5109],[-95.2111,48.5101],[-95.2112,48.4962],[-95.2111,48.4816],[-95.211,48.4673],[-95.211,48.4666],[-95.2112,48.4529],[-95.2113,48.4522],[-95.2113,48.4387],[-95.2113,48.4376],[-95.2113,48.4255],[-95.2113,48.4242],[-95.2113,48.4232],[-95.2112,48.4096],[-95.2112,48.4087],[-95.2111,48.3952],[-95.2111,48.3941],[-95.211,48.3808],[-95.211,48.3797],[-95.2106,48.3661],[-95.2066,48.3661],[-95.1983,48.3661],[-95.1887,48.3661],[-95.1861,48.3661],[-95.1669,48.3661],[-95.164,48.3661],[-95.1454,48.3662],[-95.1424,48.3662],[-95.1315,48.3662],[-95.1236,48.3663],[-95.1207,48.3663],[-95.1018,48.3663],[-95.1008,48.3663],[-95.099,48.3663],[-95.0801,48.3664],[-95.0773,48.3664],[-95.0586,48.3665],[-95.0555,48.3665],[-95.0369,48.3665],[-95.0337,48.3665],[-95.0153,48.3665],[-95.0119,48.3665],[-94.9932,48.3667],[-94.9901,48.3667],[-94.9716,48.3667],[-94.9684,48.3667],[-94.95,48.3666],[-94.9469,48.3666],[-94.9283,48.3667],[-94.9264,48.3667],[-94.9065,48.3666],[-94.9049,48.3666],[-94.8849,48.3666],[-94.8833,48.3667],[-94.8632,48.3667],[-94.8616,48.3667],[-94.8416,48.3669],[-94.8399,48.3669],[-94.8199,48.3669],[-94.8183,48.3669],[-94.7983,48.3669],[-94.7967,48.3669],[-94.7765,48.3669],[-94.7748,48.3669],[-94.7549,48.3669],[-94.7533,48.3669],[-94.7329,48.3669],[-94.7315,48.3669],[-94.7117,48.3668],[-94.7099,48.3669],[-94.6898,48.3671],[-94.683,48.3671],[-94.6694,48.3672],[-94.6679,48.3673],[-94.6622,48.3673],[-94.6505,48.3673],[-94.6465,48.3673],[-94.6405,48.3673],[-94.6245,48.3673],[-94.6188,48.3673],[-94.6029,48.3674],[-94.5971,48.3675],[-94.5812,48.3674],[-94.5754,48.3674],[-94.5593,48.3674],[-94.5536,48.3674],[-94.5378,48.3674],[-94.5335,48.3674],[-94.5157,48.3674],[-94.5118,48.3675],[-94.4941,48.3674],[-94.4924,48.3674],[-94.4906,48.3674],[-94.4722,48.3674],[-94.4688,48.3675],[-94.4505,48.3675],[-94.4471,48.3675],[-94.4288,48.3675],[-94.4252,48.3675],[-94.4253,48.352],[-94.425,48.3372],[-94.4248,48.3227],[-94.4246,48.3081],[-94.4244,48.2938],[-94.4243,48.2791],[-94.424,48.2649],[-94.4237,48.2504],[-94.4237,48.2356],[-94.4238,48.2212],[-94.4236,48.2067],[-94.4233,48.1923],[-94.4235,48.1781],[-94.4235,48.1637],[-94.4233,48.1491],[-94.4236,48.1348],[-94.4234,48.1204],[-94.4233,48.1059],[-94.4231,48.092],[-94.4234,48.0776],[-94.4247,48.0632],[-94.4246,48.0489],[-94.4241,48.0344],[-94.4236,48.0199],[-94.4176,48.02],[-94.4177,48.006],[-94.4176,47.9914],[-94.4173,47.9769],[-94.4172,47.9623],[-94.4174,47.9477],[-94.4175,47.9332],[-94.4174,47.9186],[-94.4175,47.9175],[-94.4176,47.9041],[-94.4177,47.9031],[-94.418,47.8886],[-94.4184,47.8744],[-94.4186,47.86],[-94.4185,47.8459],[-94.4186,47.8316],[-94.4187,47.817],[-94.4188,47.8026],[-94.4189,47.7881],[-94.4189,47.7735],[-94.4191,47.759],[-94.4192,47.7445],[-94.4191,47.7302],[-94.419,47.7155],[-94.4187,47.7012],[-94.4185,47.6867],[-94.4184,47.6721],[-94.417,47.6722],[-94.417,47.6578],[-94.4167,47.6435],[-94.4165,47.6291],[-94.4163,47.615],[-94.4159,47.6009],[-94.4136,47.5866],[-94.4144,47.5723],[-94.414,47.5578],[-94.4148,47.5432],[-94.4146,47.5286],[-94.4149,47.5145],[-94.4151,47.5],[-94.4154,47.4861],[-94.4156,47.4717],[-94.416,47.4571],[-94.4161,47.4449],[-94.4161,47.443],[-94.4157,47.4287],[-94.4159,47.4119],[-94.4372,47.4118],[-94.4586,47.4118],[-94.4798,47.4119],[-94.5009,47.412],[-94.5243,47.4114],[-94.5458,47.4109],[-94.5636,47.411],[-94.585,47.411],[-94.6069,47.4101],[-94.6279,47.4103],[-94.6492,47.4102],[-94.6702,47.4102],[-94.6918,47.4098],[-94.7129,47.4095],[-94.7344,47.4098],[-94.7563,47.4105],[-94.7777,47.4102],[-94.7998,47.4098],[-94.8209,47.41],[-94.8423,47.4102],[-94.8636,47.4103],[-94.8849,47.4105],[-94.9063,47.4107],[-94.9274,47.4118],[-94.9487,47.4115],[-94.97,47.4114],[-94.9914,47.4114],[-95.0127,47.4114],[-95.0341,47.4117],[-95.0557,47.4119],[-95.0766,47.4123],[-95.098,47.4125],[-95.1193,47.4126],[-95.1406,47.4125],[-95.1619,47.4127],[-95.1829,47.4127],[-95.1828,47.4268],[-95.1828,47.4412],[-95.1829,47.4557],[-95.183,47.4703],[-95.1831,47.4845],[-95.1833,47.499],[-95.1837,47.5135],[-95.1839,47.528],[-95.1841,47.5424],[-95.1841,47.5566],[-95.1844,47.571],[-95.1847,47.5861],[-95.1849,47.6006],[-95.1849,47.6151],[-95.1849,47.6297],[-95.1849,47.6442],[-95.1847,47.6587],[-95.1849,47.6735],[-95.1904,47.6734],[-95.1941,47.6734],[-95.1944,47.688],[-95.1944,47.7024],[-95.1943,47.717],[-95.1942,47.7313],[-95.1941,47.746],[-95.1941,47.7606],[-95.1939,47.7752],[-95.1939,47.7896],[-95.1938,47.8033],[-95.1937,47.8044],[-95.1937,47.8188],[-95.1936,47.8334],[-95.1935,47.8479],[-95.1935,47.8624],[-95.1934,47.8726],[-95.2003,47.8732],[-95.2025,47.8735],[-95.205,47.874],[-95.2071,47.8742],[-95.2103,47.8744],[-95.2105,47.8745],[-95.2146,47.875],[-95.215,47.8751],[-95.2172,47.8755],[-95.2193,47.876],[-95.2218,47.8765],[-95.223,47.8768],[-95.2288,47.8781],[-95.2313,47.8788],[-95.2345,47.8798],[-95.2359,47.8803],[-95.2374,47.8807],[-95.2377,47.8807],[-95.238,47.8809],[-95.2397,47.8814],[-95.2415,47.882],[-95.2456,47.8829],[-95.2473,47.8837],[-95.2485,47.8844],[-95.2502,47.8852],[-95.2518,47.8861],[-95.2538,47.8876],[-95.2558,47.8891],[-95.2578,47.8903],[-95.258,47.8905],[-95.2585,47.8909],[-95.2592,47.8917],[-95.2592,47.8918],[-95.26,47.8925],[-95.2618,47.8944],[-95.2625,47.895],[-95.2635,47.896],[-95.2655,47.8979],[-95.2657,47.8981],[-95.266,47.8984],[-95.2661,47.8985],[-95.2663,47.8987],[-95.2664,47.8991],[-95.2665,47.8992],[-95.2665,47.8993],[-95.2666,47.8993],[-95.2668,47.8999],[-95.2671,47.9004],[-95.2677,47.901],[-95.2681,47.9016],[-95.2681,47.9017],[-95.2683,47.902],[-95.2688,47.9029],[-95.2689,47.9032],[-95.2699,47.9049],[-95.2701,47.9056],[-95.2702,47.9059],[-95.2703,47.9062],[-95.2704,47.9062],[-95.2704,47.9063],[-95.2705,47.9064],[-95.2705,47.9064],[-95.2706,47.9066],[-95.2709,47.9069],[-95.2709,47.907],[-95.2723,47.9089],[-95.2728,47.9097],[-95.2728,47.9098],[-95.2729,47.9099],[-95.2729,47.9101],[-95.2732,47.9107],[-95.2734,47.9114],[-95.2734,47.9116],[-95.2735,47.9116],[-95.2736,47.9121],[-95.2738,47.9125],[-95.2738,47.9128],[-95.2741,47.9135],[-95.2741,47.9139],[-95.2748,47.9154],[-95.275,47.9156],[-95.2753,47.9162],[-95.2754,47.9168],[-95.2756,47.9172],[-95.2756,47.9175],[-95.2761,47.92],[-95.2762,47.9206],[-95.2762,47.9206],[-95.2763,47.921],[-95.2764,47.9215],[-95.2765,47.922],[-95.2766,47.9227],[-95.2767,47.9231],[-95.2768,47.9236],[-95.2771,47.9247],[-95.2774,47.9254],[-95.2774,47.9257],[-95.2776,47.9263],[-95.2778,47.9281],[-95.278,47.9286],[-95.2781,47.9302],[-95.278,47.9321],[-95.2779,47.9328],[-95.2779,47.9351],[-95.2779,47.9351],[-95.2774,47.938],[-95.2772,47.9384],[-95.2772,47.9389],[-95.277,47.9414],[-95.2769,47.9416],[-95.2767,47.9438],[-95.2767,47.9449],[-95.2761,47.947],[-95.2759,47.9474],[-95.2756,47.9487],[-95.2755,47.9488],[-95.2753,47.9495],[-95.2751,47.9507],[-95.2749,47.9515],[-95.2743,47.9529],[-95.2743,47.9531],[-95.2742,47.9534],[-95.2742,47.9541],[-95.2741,47.9561],[-95.274,47.9568],[-95.2739,47.9574],[-95.2735,47.958],[-95.2731,47.9584],[-95.2729,47.9586],[-95.2728,47.9587],[-95.2726,47.959],[-95.2726,47.9593],[-95.2725,47.9605],[-95.2722,47.961],[-95.2712,47.9623],[-95.271,47.9628],[-95.2708,47.9632],[-95.2706,47.9636],[-95.2703,47.9637],[-95.2701,47.9639],[-95.2701,47.964],[-95.2698,47.9643],[-95.2694,47.9655],[-95.268,47.9688],[-95.267,47.9704],[-95.267,47.9707],[-95.2667,47.9708],[-95.2664,47.9714],[-95.2657,47.9727],[-95.2646,47.9748],[-95.2645,47.9752],[-95.2639,47.9765],[-95.2636,47.9771],[-95.2627,47.9786],[-95.2618,47.9803],[-95.259,47.9839],[-95.2585,47.9852],[-95.2583,47.9856],[-95.2582,47.9865],[-95.258,47.987],[-95.2579,47.9875],[-95.2576,47.9883],[-95.2571,47.9891],[-95.2554,47.9917],[-95.2551,47.992],[-95.2546,47.9926],[-95.2543,47.9932],[-95.253,47.9954],[-95.2526,47.9964],[-95.2523,47.9968],[-95.252,47.9971],[-95.2518,47.9973],[-95.2512,47.998],[-95.2508,47.9988],[-95.2507,47.999],[-95.2507,48.0],[-95.2504,48.0],[-95.2502,48.0],[-95.2495,48.0],[-95.2495,48.0009],[-95.2493,48.0015],[-95.249,48.002],[-95.2486,48.0025],[-95.2481,48.0029],[-95.2479,48.0031],[-95.2477,48.0041],[-95.2472,48.0046],[-95.247,48.0048],[-95.2464,48.0055],[-95.2459,48.0059],[-95.2455,48.0066],[-95.245,48.0071],[-95.2449,48.0072],[-95.2445,48.0076],[-95.2445,48.0076],[-95.2444,48.008],[-95.2442,48.0081],[-95.2441,48.0083],[-95.2439,48.0086],[-95.2439,48.0087],[-95.2438,48.0087],[-95.2433,48.009],[-95.2423,48.0097],[-95.2421,48.01],[-95.2418,48.0103],[-95.2417,48.0106],[-95.2414,48.0108],[-95.2414,48.0109],[-95.2409,48.0111],[-95.2407,48.0112],[-95.2404,48.0114],[-95.2401,48.0117],[-95.24,48.0119],[-95.24,48.0119],[-95.2396,48.0123],[-95.2394,48.0124],[-95.2387,48.0127],[-95.2377,48.0134],[-95.2376,48.0135],[-95.2372,48.0139],[-95.2371,48.0142],[-95.2371,48.0143],[-95.237,48.0144],[-95.2368,48.0145],[-95.2367,48.0145],[-95.2363,48.0148],[-95.2362,48.0148],[-95.2358,48.0149],[-95.2354,48.0152],[-95.2352,48.0155],[-95.2347,48.0158],[-95.2326,48.017],[-95.2323,48.0174],[-95.2306,48.0185],[-95.2304,48.0188],[-95.2303,48.0191],[-95.2297,48.0196],[-95.2293,48.0199],[-95.2289,48.0201],[-95.2378,48.0201],[-95.2473,48.0201],[-95.2493,48.0201],[-95.2594,48.0201],[-95.269,48.0201],[-95.281,48.0202],[-95.2887,48.0201],[-95.2906,48.0201],[-95.2933,48.0201],[-95.3025,48.0202],[-95.3122,48.0202],[-95.3224,48.0203],[-95.3338,48.0203],[-95.3401,48.0203],[-95.3439,48.0204],[-95.3554,48.0204],[-95.3654,48.0204],[-95.3661,48.0204],[-95.377,48.0205],[-95.3871,48.0206],[-95.3985,48.0206],[-95.4086,48.0207],[-95.4201,48.0206],[-95.4302,48.0206],[-95.4417,48.0206],[-95.4523,48.0206],[-95.4632,48.0207],[-95.4738,48.0207],[-95.485,48.0207],[-95.4954,48.0207],[-95.4959,48.0207],[-95.5065,48.0208],[-95.517,48.0208],[-95.5215,48.0209],[-95.5277,48.0209],[-95.5384,48.0209],[-95.5398,48.0209],[-95.5491,48.0209],[-95.5597,48.0208],[-95.5705,48.0208],[-95.5828,48.0207],[-95.5922,48.0207],[-95.5923,48.035],[-95.5925,48.0497],[-95.5925,48.0642],[-95.5926,48.0787],[-95.5928,48.0931],[-95.593,48.1078],[-95.5931,48.1223],[-95.5936,48.1368],[-95.5938,48.1512],[-95.5939,48.1658],[-95.5939,48.173],[-95.594,48.1802],[-95.5938,48.1946],[-95.5939,48.2092],[-95.5939,48.2236],[-95.5941,48.2382],[-95.5941,48.2526],[-95.5937,48.267],[-95.5934,48.2815],[-95.5934,48.2961],[-95.5932,48.3105],[-95.5932,48.325],[-95.5932,48.3396],[-95.5933,48.354],[-95.5933,48.3656],[-95.5933,48.3656],[-95.6016,48.3655],[-95.602,48.3798],[-95.6021,48.3809],[-95.6026,48.3942],[-95.6026,48.395],[-95.6026,48.4088],[-95.6026,48.4095],[-95.6023,48.4232],[-95.6023,48.424],[-95.6021,48.4376],[-95.602,48.4385],[-95.6016,48.4522],[-95.6016,48.453],[-95.6016,48.4666],[-95.6016,48.4674],[-95.6011,48.4811],[-95.6011,48.4818],[-95.6008,48.4956],[-95.6008,48.4964],[-95.6007,48.51],[-95.6007,48.5107],[-95.6011,48.5251],[-95.6023,48.5389],[-95.5821,48.5387],[-95.5801,48.5387],[-95.5603,48.5388],[-95.558,48.5388],[-95.5383,48.5389],[-95.5365,48.5389],[-95.5163,48.539],[-95.5143,48.539],[-95.495,48.5392],[-95.493,48.5392],[-95.4726,48.5396],[-95.4712,48.5396],[-95.4513,48.5399],[-95.4494,48.5399],[-95.4297,48.5399],[-95.4279,48.54],[-95.4078,48.5402],[-95.4061,48.5402],[-95.386,48.5402],[-95.3844,48.5402],[-95.364,48.5403],[-95.3628,48.5404],[-95.3425,48.5402]]],"type":"Polygon"},"id":"4","properties":{"Area":7911449532.86586,"CTYONLY_":8,"Code":"BELT","LASTMOD":"1999-12-31T23:59:59Z","Name":"Beltrami","Perimiter":429419.1705},"type":"Feature"},{"geometry":{"coordinates":[[[-97.1467,48.1733],[-97.1462,48.1733],[-97.1376,48.1733],[-97.1322,48.1733],[-97.1286,48.1733],[-97.1257,48.1733],[-97.1253,48.1733],[-97.1071,48.1735],[-97.1069,48.1735],[-97.0855,48.1734],[-97.0853,48.1734],[-97.0637,48.1732],[-97.0637,48.1732],[-97.042,48.1732],[-97.042,48.1732],[-97.0205,48.1733],[-97.0203,48.1733],[-97.0003,48.1732],[-96.999,48.1732],[-96.9989,48.1732],[-96.9987,48.1732],[-96.998,48.1732],[-96.9975,48.1732],[-96.9959,48.1732],[-96.99,48.1731],[-96.9889,48.1731],[-96.9844,48.1731],[-96.9812,48.1731],[-96.9775,48.1731],[-96.9773,48.173],[-96.9773,48.173],[-96.9751,48.173],[-96.9749,48.173],[-96.9705,48.1731],[-96.9703,48.1731],[-96.9554,48.1731],[-96.9448,48.1732],[-96.9387,48.1732],[-96.934,48.1733],[-96.9339,48.1733],[-96.933,48.1733],[-96.9123,48.1733],[-96.9122,48.1733],[-96.8932,48.1732],[-96.8907,48.1732],[-96.8907,48.1732],[-96.8753,48.1732],[-96.869,48.1733],[-96.869,48.1733],[-96.8474,48.1733],[-96.8473,48.1733],[-96.8255,48.1734],[-96.8255,48.1734],[-96.8111,48.1734],[-96.8039,48.1734],[-96.8038,48.1734],[-96.7932,48.1733],[-96.7821,48.1734],[-96.7821,48.1734],[-96.7819,48.1734],[-96.7613,48.1734],[-96.7606,48.1734],[-96.7605,48.1734],[-96.7581,48.1734],[-96.7573,48.1734],[-96.7503,48.1734],[-96.7393,48.1734],[-96.7393,48.1734],[-96.7177,48.1734],[-96.7176,48.1734],[-96.6959,48.1734],[-96.6958,48.1734],[-96.6826,48.1735],[-96.6742,48.1736],[-96.6742,48.1736],[-96.6525,48.1738],[-96.6525,48.1738],[-96.6407,48.1739],[-96.6378,48.1738],[-96.6338,48.1737],[-96.6309,48.1737],[-96.6307,48.1737],[-96.6307,48.1737],[-96.6253,48.1737],[-96.6106,48.1737],[-96.6092,48.1737],[-96.609,48.1737],[-96.6055,48.1737],[-96.5966,48.1737],[-96.5893,48.1737],[-96.5875,48.1737],[-96.5873,48.1737],[-96.5873,48.1737],[-96.5838,48.1738],[-96.5806,48.1739],[-96.5765,48.1739],[-96.5748,48.1739],[-96.5715,48.1739],[-96.5678,48.174],[-96.5655,48.174],[-96.5654,48.174],[-96.565,48.174],[-96.5616,48.1739],[-96.557,48.1739],[-96.5544,48.1738],[-96.5507,48.1738],[-96.5479,48.1738],[-96.5446,48.1738],[-96.5443,48.1738],[-96.5442,48.1738],[-96.5434,48.1738],[-96.5399,48.1738],[-96.5357,48.1738],[-96.53,48.1738],[-96.5251,48.1738],[-96.5223,48.1739],[-96.5204,48.1739],[-96.5164,48.1739],[-96.5091,48.174],[-96.5038,48.174],[-96.5008,48.1742],[-96.5008,48.1669],[-96.5008,48.1524],[-96.5006,48.1379],[-96.5007,48.1234],[-96.501,48.1089],[-96.5009,48.0943],[-96.5009,48.0798],[-96.5009,48.0654],[-96.5008,48.0506],[-96.5009,48.0362],[-96.5009,48.0217],[-96.4826,48.0217],[-96.4826,48.0072],[-96.4824,47.9924],[-96.4823,47.9782],[-96.4823,47.9636],[-96.4825,47.949],[-96.4826,47.9347],[-96.4825,47.9202],[-96.4825,47.9055],[-96.4825,47.9054],[-96.4824,47.8913],[-96.4827,47.8768],[-96.4821,47.862],[-96.482,47.8475],[-96.4601,47.8475],[-96.4386,47.8476],[-96.4172,47.8475],[-96.3958,47.8475],[-96.3742,47.8474],[-96.3527,47.8473],[-96.3524,47.8329],[-96.3523,47.8184],[-96.3521,47.8038],[-96.352,47.7893],[-96.3519,47.7748],[-96.3516,47.7604],[-96.3313,47.7603],[-96.3097,47.7601],[-96.2884,47.7601],[-96.2668,47.7599],[-96.2453,47.7598],[-96.2238,47.7598],[-96.2022,47.7597],[-96.1806,47.7598],[-96.159,47.7598],[-96.1388,47.7598],[-96.1175,47.7602],[-96.0957,47.76],[-96.0743,47.7601],[-96.053,47.7603],[-96.0315,47.7605],[-96.0097,47.7605],[-95.9883,47.7605],[-95.9671,47.7605],[-95.9452,47.7606],[-95.9233,47.7607],[-95.9017,47.7609],[-95.8801,47.7608],[-95.8588,47.7609],[-95.8372,47.7609],[-95.8371,47.7755],[-95.8365,47.79],[-95.8366,47.8043],[-95.8366,47.819],[-95.8367,47.8335],[-95.8366,47.8482],[-95.8153,47.8484],[-95.7952,47.8483],[-95.7737,47.8484],[-95.7525,47.8485],[-95.7307,47.8487],[-95.709,47.8486],[-95.7089,47.863],[-95.7094,47.8776],[-95.7095,47.8919],[-95.7094,47.9065],[-95.7098,47.9211],[-95.7096,47.9355],[-95.6898,47.9354],[-95.6683,47.9351],[-95.6466,47.9348],[-95.6252,47.9344],[-95.6034,47.9341],[-95.5824,47.9339],[-95.5817,47.9195],[-95.5816,47.9051],[-95.5814,47.8904],[-95.5813,47.876],[-95.5812,47.8617],[-95.5809,47.847],[-95.5805,47.8327],[-95.5804,47.8183],[-95.5801,47.8039],[-95.5796,47.7894],[-95.5796,47.775],[-95.5799,47.7605],[-95.5795,47.746],[-95.5793,47.7314],[-95.5789,47.7171],[-95.5789,47.7027],[-95.5787,47.6882],[-95.5785,47.6738],[-95.5785,47.6737],[-95.5755,47.6737],[-95.5595,47.6737],[-95.5535,47.6737],[-95.5537,47.6592],[-95.5536,47.6447],[-95.5535,47.6302],[-95.5538,47.6161],[-95.5536,47.6014],[-95.5537,47.5869],[-95.5538,47.5724],[-95.5538,47.5579],[-95.5539,47.5436],[-95.5539,47.5289],[-95.5539,47.5146],[-95.5513,47.5001],[-95.5516,47.5001],[-95.5729,47.5001],[-95.5942,47.4999],[-95.6158,47.4997],[-95.6366,47.4996],[-95.6393,47.4996],[-95.6411,47.4996],[-95.6584,47.4995],[-95.6605,47.4995],[-95.6782,47.4997],[-95.6818,47.4997],[-95.6908,47.4997],[-95.6996,47.4997],[-95.7033,47.4997],[-95.7211,47.4996],[-95.7247,47.4995],[-95.7424,47.4995],[-95.7459,47.4995],[-95.7537,47.4995],[-95.7634,47.4995],[-95.7675,47.4995],[-95.7851,47.4994],[-95.7888,47.4994],[-95.7965,47.4994],[-95.8053,47.4994],[-95.8103,47.4994],[-95.8266,47.4995],[-95.8272,47.4995],[-95.8316,47.4995],[-95.8371,47.4995],[-95.8482,47.4995],[-95.8529,47.4995],[-95.8696,47.4995],[-95.8746,47.4994],[-95.8908,47.4993],[-95.8954,47.4993],[-95.9123,47.4992],[-95.9169,47.4992],[-95.9332,47.4992],[-95.9383,47.4992],[-95.9549,47.4992],[-95.9603,47.4992],[-95.9761,47.4992],[-95.9818,47.4992],[-95.9977,47.4992],[-95.9991,47.4992],[-96.0032,47.4992],[-96.019,47.4993],[-96.0247,47.4993],[-96.0362,47.4992],[-96.0408,47.4992],[-96.0462,47.4992],[-96.0676,47.4992],[-96.0888,47.4993],[-96.1101,47.4993],[-96.1314,47.4996],[-96.1526,47.4997],[-96.1739,47.4999],[-96.1954,47.4999],[-96.2166,47.4999],[-96.238,47.4998],[-96.2594,47.4998],[-96.2808,47.4998],[-96.3022,47.4999],[-96.3232,47.4999],[-96.3448,47.4997],[-96.3659,47.4997],[-96.3873,47.4997],[-96.4088,47.4996],[-96.4301,47.4996],[-96.4517,47.4994],[-96.4731,47.4993],[-96.4944,47.4993],[-96.516,47.4991],[-96.5371,47.4991],[-96.5587,47.499],[-96.5801,47.499],[-96.6013,47.4989],[-96.6229,47.499],[-96.6442,47.4992],[-96.6653,47.499],[-96.6876,47.4987],[-96.7085,47.4989],[-96.73,47.4989],[-96.7515,47.4989],[-96.7732,47.4989],[-96.7945,47.499],[-96.8159,47.499],[-96.8361,47.4989],[-96.8487,47.4989],[-96.8488,47.499],[-96.8504,47.5],[-96.8506,47.5],[-96.8507,47.5],[-96.8514,47.5004],[-96.8524,47.5006],[-96.853,47.501],[-96.8533,47.5014],[-96.8534,47.5017],[-96.8535,47.5023],[-96.8535,47.5034],[-96.8532,47.5039],[-96.8532,47.5042],[-96.8531,47.5045],[-96.8528,47.5053],[-96.8528,47.5059],[-96.8529,47.506],[-96.853,47.5065],[-96.853,47.5069],[-96.8526,47.5073],[-96.8524,47.5075],[-96.8518,47.5076],[-96.8515,47.5076],[-96.8508,47.5074],[-96.8494,47.5068],[-96.8485,47.5066],[-96.8471,47.5066],[-96.846,47.5067],[-96.8443,47.5071],[-96.8436,47.5074],[-96.8424,47.5083],[-96.8422,47.5086],[-96.8421,47.5091],[-96.8424,47.5094],[-96.8431,47.51],[-96.8439,47.5103],[-96.8448,47.5105],[-96.8464,47.5105],[-96.849,47.5098],[-96.8504,47.5096],[-96.8512,47.5096],[-96.8519,47.5098],[-96.8526,47.5102],[-96.853,47.5106],[-96.8531,47.5107],[-96.8533,47.5112],[-96.8534,47.5112],[-96.8534,47.5113],[-96.8535,47.5113],[-96.8536,47.5119],[-96.8536,47.512],[-96.8532,47.5126],[-96.8531,47.5128],[-96.8525,47.5132],[-96.8517,47.5135],[-96.8514,47.5135],[-96.851,47.5136],[-96.8502,47.5135],[-96.8491,47.5134],[-96.8465,47.5124],[-96.846,47.5123],[-96.8448,47.5124],[-96.8442,47.5125],[-96.8435,47.5128],[-96.843,47.5132],[-96.8428,47.5134],[-96.8425,47.5137],[-96.8422,47.5141],[-96.842,47.5146],[-96.842,47.5155],[-96.842,47.5156],[-96.842,47.5157],[-96.8421,47.5158],[-96.8422,47.516],[-96.8427,47.5164],[-96.8433,47.5167],[-96.8442,47.517],[-96.8454,47.5172],[-96.8465,47.517],[-96.8475,47.5166],[-96.8481,47.5163],[-96.8501,47.5155],[-96.8519,47.515],[-96.8532,47.5146],[-96.8542,47.5144],[-96.8547,47.5144],[-96.8563,47.5146],[-96.8573,47.5147],[-96.8584,47.5149],[-96.8599,47.5153],[-96.8614,47.5159],[-96.8624,47.5164],[-96.8629,47.5169],[-96.8632,47.5173],[-96.8633,47.5177],[-96.8633,47.5198],[-96.8635,47.5204],[-96.8636,47.5206],[-96.8643,47.5213],[-96.8645,47.5216],[-96.8656,47.5225],[-96.8658,47.5229],[-96.866,47.523],[-96.8663,47.5238],[-96.8664,47.5249],[-96.8666,47.5254],[-96.8672,47.5259],[-96.8676,47.5261],[-96.8683,47.5262],[-96.8698,47.5264],[-96.8705,47.5266],[-96.8707,47.5268],[-96.8708,47.5269],[-96.8709,47.5272],[-96.8709,47.5273],[-96.8709,47.5279],[-96.8706,47.5283],[-96.8704,47.5284],[-96.87,47.5287],[-96.8691,47.529],[-96.868,47.5291],[-96.8665,47.5291],[-96.865,47.529],[-96.8623,47.5291],[-96.861,47.5294],[-96.8605,47.5296],[-96.8593,47.5304],[-96.8589,47.5308],[-96.8576,47.5328],[-96.8573,47.5333],[-96.8568,47.5337],[-96.8558,47.5346],[-96.8543,47.5354],[-96.854,47.5357],[-96.8535,47.5363],[-96.8534,47.5372],[-96.8536,47.5378],[-96.854,47.5382],[-96.8546,47.5383],[-96.8558,47.5382],[-96.8569,47.5379],[-96.8573,47.5377],[-96.8579,47.5375],[-96.8589,47.5371],[-96.8593,47.5371],[-96.8599,47.5371],[-96.8609,47.5374],[-96.8619,47.5379],[-96.8629,47.5387],[-96.8632,47.5391],[-96.8634,47.5395],[-96.8634,47.5402],[-96.8628,47.5409],[-96.8614,47.5414],[-96.858,47.542],[-96.8573,47.5421],[-96.8565,47.5422],[-96.8555,47.5421],[-96.8542,47.5418],[-96.8533,47.5413],[-96.8523,47.5407],[-96.8519,47.5401],[-96.8516,47.5397],[-96.8514,47.5393],[-96.8513,47.5393],[-96.8512,47.539],[-96.8511,47.5388],[-96.851,47.5386],[-96.8507,47.5383],[-96.8507,47.5382],[-96.8501,47.5377],[-96.8494,47.5374],[-96.8484,47.5372],[-96.8477,47.5371],[-96.8471,47.5372],[-96.8465,47.5374],[-96.8457,47.538],[-96.8452,47.5386],[-96.8452,47.5394],[-96.8452,47.5397],[-96.8454,47.5399],[-96.8455,47.5403],[-96.8456,47.5404],[-96.8456,47.5405],[-96.846,47.541],[-96.8467,47.5415],[-96.8484,47.5425],[-96.8501,47.5432],[-96.8525,47.5438],[-96.8571,47.5448],[-96.8572,47.5448],[-96.8586,47.5452],[-96.8597,47.5456],[-96.8602,47.5459],[-96.8603,47.5461],[-96.8603,47.5464],[-96.8602,47.5466],[-96.8599,47.5468],[-96.8596,47.547],[-96.8585,47.5472],[-96.8576,47.5477],[-96.8572,47.5479],[-96.8554,47.5485],[-96.8542,47.5488],[-96.8538,47.5491],[-96.8523,47.5504],[-96.8505,47.5517],[-96.8501,47.5521],[-96.8499,47.5526],[-96.8497,47.5532],[-96.85,47.5537],[-96.8501,47.5538],[-96.8501,47.5539],[-96.8506,47.5543],[-96.8513,47.5546],[-96.8526,47.5549],[-96.8546,47.5551],[-96.8558,47.5551],[-96.857,47.5553],[-96.8578,47.5556],[-96.8588,47.5562],[-96.8598,47.5571],[-96.8602,47.5576],[-96.8605,47.5578],[-96.8606,47.5581],[-96.8608,47.5582],[-96.8612,47.5588],[-96.8614,47.5592],[-96.8614,47.5599],[-96.8613,47.5602],[-96.8608,47.5604],[-96.8601,47.5607],[-96.8594,47.5607],[-96.8581,47.5605],[-96.8573,47.5602],[-96.8569,47.5601],[-96.8567,47.5601],[-96.8553,47.5602],[-96.8544,47.5603],[-96.8537,47.5606],[-96.8515,47.5621],[-96.8506,47.5626],[-96.8491,47.5636],[-96.8484,47.564],[-96.8476,47.5646],[-96.8474,47.565],[-96.8472,47.5656],[-96.8472,47.5661],[-96.8474,47.5663],[-96.8479,47.5666],[-96.8487,47.5667],[-96.8498,47.5665],[-96.8503,47.5664],[-96.8513,47.5658],[-96.852,47.5656],[-96.8541,47.5653],[-96.856,47.5649],[-96.8568,47.5646],[-96.8575,47.5643],[-96.8599,47.5632],[-96.8612,47.5628],[-96.8622,47.5626],[-96.8628,47.5626],[-96.864,47.5627],[-96.8652,47.5631],[-96.8661,47.5636],[-96.8666,47.564],[-96.8676,47.5651],[-96.8678,47.5654],[-96.868,47.5655],[-96.8685,47.5663],[-96.8685,47.5664],[-96.8686,47.5665],[-96.8687,47.5668],[-96.8688,47.5669],[-96.8687,47.5677],[-96.8684,47.5682],[-96.8675,47.5688],[-96.8661,47.5695],[-96.8656,47.5696],[-96.8647,47.5694],[-96.8639,47.569],[-96.8629,47.5687],[-96.8616,47.5684],[-96.861,47.5682],[-96.8607,47.568],[-96.8599,47.5676],[-96.8588,47.5672],[-96.8578,47.5671],[-96.8567,47.5671],[-96.8555,47.5671],[-96.8539,47.5675],[-96.8529,47.5678],[-96.8519,47.5684],[-96.8514,47.569],[-96.8515,47.5698],[-96.8517,47.5703],[-96.8521,47.5709],[-96.8529,47.5715],[-96.8531,47.5716],[-96.8537,47.5719],[-96.8549,47.5725],[-96.8566,47.5731],[-96.8571,47.5733],[-96.8595,47.574],[-96.8602,47.5744],[-96.8604,47.5746],[-96.8604,47.575],[-96.8599,47.5752],[-96.8589,47.5754],[-96.8585,47.5756],[-96.8573,47.5763],[-96.8565,47.5767],[-96.8553,47.5773],[-96.8543,47.578],[-96.8534,47.5792],[-96.8532,47.5795],[-96.853,47.5802],[-96.853,47.5805],[-96.8528,47.5809],[-96.8529,47.5822],[-96.853,47.5826],[-96.8532,47.5826],[-96.8532,47.5833],[-96.8531,47.5837],[-96.8526,47.5844],[-96.8527,47.5845],[-96.8525,47.5846],[-96.852,47.585],[-96.852,47.5851],[-96.8515,47.5859],[-96.8515,47.586],[-96.8513,47.5869],[-96.8512,47.5873],[-96.8511,47.5878],[-96.851,47.5881],[-96.8507,47.5888],[-96.8502,47.5898],[-96.85,47.5903],[-96.8499,47.591],[-96.8501,47.5916],[-96.8503,47.5919],[-96.8511,47.5925],[-96.8517,47.5927],[-96.8538,47.593],[-96.8549,47.5934],[-96.8562,47.5939],[-96.8575,47.5943],[-96.8582,47.5947],[-96.8586,47.5949],[-96.8588,47.5954],[-96.8588,47.5958],[-96.8584,47.5962],[-96.8575,47.5963],[-96.8562,47.5962],[-96.8542,47.596],[-96.853,47.5961],[-96.8521,47.5964],[-96.8515,47.5968],[-96.8511,47.5973],[-96.8509,47.5977],[-96.8509,47.5983],[-96.8511,47.5989],[-96.8515,47.5993],[-96.8521,47.5997],[-96.8528,47.6],[-96.8536,47.6003],[-96.8545,47.6004],[-96.8556,47.6009],[-96.8561,47.6014],[-96.8564,47.6016],[-96.8567,47.602],[-96.8569,47.6024],[-96.8568,47.6031],[-96.8565,47.6035],[-96.8562,47.6039],[-96.8553,47.6051],[-96.8549,47.6058],[-96.8548,47.6064],[-96.8548,47.6073],[-96.8549,47.6075],[-96.855,47.6079],[-96.855,47.608],[-96.8554,47.6088],[-96.8557,47.6093],[-96.8558,47.6094],[-96.8561,47.6098],[-96.8563,47.61],[-96.8571,47.6108],[-96.858,47.6115],[-96.8589,47.612],[-96.8602,47.6122],[-96.8612,47.6124],[-96.8646,47.6124],[-96.8655,47.6125],[-96.8664,47.6129],[-96.8672,47.6136],[-96.8673,47.6138],[-96.8675,47.6139],[-96.8676,47.6141],[-96.8679,47.6144],[-96.8686,47.6148],[-96.869,47.615],[-96.8694,47.615],[-96.8703,47.6147],[-96.871,47.6143],[-96.8714,47.6139],[-96.8719,47.6136],[-96.8723,47.6135],[-96.8729,47.6135],[-96.8736,47.6137],[-96.8739,47.614],[-96.874,47.6141],[-96.874,47.6148],[-96.8739,47.6149],[-96.8736,47.6154],[-96.8726,47.6159],[-96.8715,47.6165],[-96.871,47.6169],[-96.8706,47.6176],[-96.8708,47.6181],[-96.8712,47.6183],[-96.8717,47.6184],[-96.8727,47.6184],[-96.8753,47.6191],[-96.8763,47.6192],[-96.8778,47.6189],[-96.878,47.6189],[-96.879,47.6189],[-96.8796,47.6191],[-96.88,47.6195],[-96.88,47.62],[-96.8794,47.6206],[-96.8783,47.6213],[-96.8779,47.6215],[-96.8769,47.6219],[-96.8763,47.6223],[-96.876,47.6228],[-96.8758,47.623],[-96.876,47.6235],[-96.8761,47.6237],[-96.8768,47.6243],[-96.8775,47.6244],[-96.878,47.6245],[-96.8792,47.6246],[-96.88,47.6247],[-96.8803,47.625],[-96.8806,47.6254],[-96.8807,47.6255],[-96.8807,47.6259],[-96.8804,47.6262],[-96.8798,47.6266],[-96.8792,47.6267],[-96.8786,47.6267],[-96.878,47.6267],[-96.8767,47.6266],[-96.8753,47.6267],[-96.8748,47.6269],[-96.8745,47.6272],[-96.8745,47.6275],[-96.8745,47.628],[-96.8747,47.6283],[-96.8753,47.6287],[-96.8765,47.629],[-96.8774,47.6289],[-96.8781,47.6289],[-96.8787,47.6289],[-96.8795,47.6289],[-96.8801,47.6289],[-96.8806,47.6291],[-96.881,47.6294],[-96.8815,47.6299],[-96.8815,47.6299],[-96.8815,47.63],[-96.8816,47.6301],[-96.8818,47.6305],[-96.8818,47.631],[-96.8819,47.6311],[-96.882,47.6324],[-96.8822,47.6333],[-96.8823,47.6334],[-96.8823,47.6335],[-96.8827,47.6339],[-96.8852,47.6356],[-96.8876,47.6376],[-96.8878,47.6379],[-96.8885,47.6385],[-96.8885,47.6393],[-96.8884,47.6395],[-96.8881,47.6398],[-96.8874,47.6401],[-96.886,47.6405],[-96.8845,47.6408],[-96.8835,47.6412],[-96.8832,47.6414],[-96.8828,47.6418],[-96.8826,47.6422],[-96.8826,47.6429],[-96.8829,47.6439],[-96.8829,47.6441],[-96.8829,47.6447],[-96.8828,47.6451],[-96.8827,47.6462],[-96.8825,47.6471],[-96.8823,47.6491],[-96.8826,47.6498],[-96.8828,47.6502],[-96.8837,47.6509],[-96.8844,47.6513],[-96.8846,47.6513],[-96.8847,47.6515],[-96.8862,47.6523],[-96.8866,47.6526],[-96.8869,47.6531],[-96.887,47.6533],[-96.887,47.6543],[-96.8868,47.6548],[-96.8869,47.6556],[-96.887,47.656],[-96.8876,47.6577],[-96.8876,47.6585],[-96.8876,47.6589],[-96.8873,47.6596],[-96.8869,47.6601],[-96.8857,47.6616],[-96.8855,47.6624],[-96.8855,47.6635],[-96.8857,47.6643],[-96.8862,47.6652],[-96.8863,47.6653],[-96.8863,47.6654],[-96.8864,47.6656],[-96.8864,47.6656],[-96.8871,47.6664],[-96.8889,47.668],[-96.8896,47.6686],[-96.8897,47.669],[-96.8898,47.669],[-96.8899,47.6693],[-96.89,47.6694],[-96.8901,47.67],[-96.8899,47.6703],[-96.8897,47.6707],[-96.8883,47.6715],[-96.8871,47.6721],[-96.8868,47.6722],[-96.8863,47.6725],[-96.8859,47.6727],[-96.8856,47.6727],[-96.8855,47.6729],[-96.8853,47.6732],[-96.8851,47.6735],[-96.8852,47.6737],[-96.8852,47.6738],[-96.8853,47.6739],[-96.8857,47.6742],[-96.8863,47.6743],[-96.8867,47.6743],[-96.8874,47.6743],[-96.8886,47.674],[-96.8892,47.6738],[-96.8908,47.6734],[-96.8919,47.6732],[-96.8935,47.6732],[-96.8946,47.6734],[-96.8952,47.6736],[-96.8955,47.6738],[-96.8964,47.6745],[-96.8967,47.6748],[-96.8968,47.6751],[-96.8967,47.6759],[-96.8964,47.6768],[-96.8963,47.6772],[-96.8962,47.6775],[-96.8961,47.6776],[-96.8961,47.6785],[-96.8963,47.6792],[-96.8964,47.6793],[-96.8964,47.6794],[-96.8965,47.6796],[-96.8968,47.6802],[-96.8971,47.6804],[-96.8971,47.6806],[-96.8972,47.6806],[-96.8973,47.681],[-96.8974,47.6811],[-96.8974,47.6812],[-96.8975,47.6813],[-96.8977,47.6817],[-96.8978,47.6818],[-96.8978,47.682],[-96.8984,47.6834],[-96.8986,47.6837],[-96.8986,47.684],[-96.8987,47.6841],[-96.8989,47.6846],[-96.899,47.6847],[-96.899,47.685],[-96.8993,47.686],[-96.8992,47.6871],[-96.8992,47.688],[-96.8992,47.6883],[-96.8992,47.6887],[-96.8993,47.6895],[-96.8995,47.69],[-96.8996,47.6901],[-96.8997,47.6903],[-96.9002,47.6908],[-96.9011,47.6914],[-96.9017,47.6917],[-96.9022,47.6918],[-96.9029,47.6916],[-96.9035,47.6913],[-96.9039,47.6909],[-96.9047,47.6898],[-96.9052,47.6893],[-96.906,47.6889],[-96.9072,47.6885],[-96.9081,47.6885],[-96.9089,47.6888],[-96.9095,47.6892],[-96.9098,47.6896],[-96.9101,47.69],[-96.9101,47.6913],[-96.9099,47.6916],[-96.9098,47.692],[-96.9091,47.6926],[-96.9077,47.6934],[-96.9074,47.6937],[-96.9072,47.694],[-96.9072,47.6947],[-96.9076,47.6952],[-96.9077,47.6954],[-96.9083,47.6961],[-96.9092,47.6968],[-96.9097,47.6974],[-96.9101,47.698],[-96.9102,47.6982],[-96.9103,47.6985],[-96.9103,47.6986],[-96.9104,47.6986],[-96.9106,47.6989],[-96.9107,47.6991],[-96.9107,47.6993],[-96.9115,47.7006],[-96.912,47.7012],[-96.9125,47.7017],[-96.9128,47.7018],[-96.9132,47.7019],[-96.914,47.7018],[-96.9145,47.7016],[-96.9155,47.7009],[-96.9169,47.6998],[-96.9177,47.6994],[-96.9184,47.6991],[-96.9193,47.6991],[-96.9202,47.6993],[-96.9207,47.6996],[-96.9208,47.6998],[-96.9208,47.6999],[-96.921,47.7],[-96.9211,47.7003],[-96.9211,47.7008],[-96.9208,47.7013],[-96.9204,47.7017],[-96.9194,47.7026],[-96.919,47.7028],[-96.9187,47.703],[-96.9176,47.7034],[-96.9172,47.7035],[-96.9164,47.7034],[-96.9155,47.7035],[-96.9145,47.7038],[-96.9137,47.7042],[-96.9132,47.7047],[-96.9128,47.7052],[-96.9123,47.7058],[-96.9119,47.7066],[-96.912,47.7075],[-96.9122,47.7079],[-96.9129,47.7083],[-96.9134,47.7084],[-96.9146,47.7085],[-96.9163,47.7086],[-96.9175,47.7089],[-96.919,47.7095],[-96.9198,47.71],[-96.9201,47.7104],[-96.9201,47.7105],[-96.9202,47.7107],[-96.9204,47.7111],[-96.9204,47.712],[-96.9203,47.7124],[-96.9197,47.7137],[-96.9195,47.7139],[-96.9194,47.7142],[-96.9192,47.7146],[-96.9191,47.7149],[-96.9191,47.7156],[-96.9197,47.7166],[-96.9201,47.7171],[-96.9206,47.7174],[-96.9209,47.7176],[-96.9216,47.7178],[-96.9224,47.718],[-96.9232,47.7179],[-96.9238,47.7176],[-96.9241,47.7174],[-96.9245,47.7171],[-96.9247,47.7167],[-96.9248,47.7166],[-96.9248,47.7164],[-96.9251,47.7162],[-96.9252,47.716],[-96.926,47.7153],[-96.9266,47.7149],[-96.9277,47.7144],[-96.9284,47.7143],[-96.929,47.7143],[-96.93,47.7145],[-96.9305,47.7148],[-96.931,47.7153],[-96.931,47.7154],[-96.9311,47.7154],[-96.9312,47.716],[-96.9312,47.7166],[-96.9308,47.7174],[-96.9308,47.7175],[-96.9305,47.7179],[-96.93,47.7183],[-96.9287,47.7187],[-96.9271,47.719],[-96.9251,47.7197],[-96.9237,47.7202],[-96.9217,47.7211],[-96.9205,47.7218],[-96.9194,47.7226],[-96.9193,47.7227],[-96.9189,47.7231],[-96.9187,47.7234],[-96.9185,47.7239],[-96.9187,47.7243],[-96.9188,47.7244],[-96.9188,47.7245],[-96.9191,47.7248],[-96.9197,47.7251],[-96.9203,47.7253],[-96.9224,47.7256],[-96.9236,47.7259],[-96.9242,47.7262],[-96.9246,47.7267],[-96.9248,47.7272],[-96.925,47.7275],[-96.925,47.7291],[-96.9253,47.7299],[-96.9255,47.7302],[-96.9257,47.7304],[-96.9273,47.7316],[-96.9279,47.7321],[-96.9283,47.7325],[-96.9305,47.7344],[-96.9314,47.7353],[-96.9319,47.7359],[-96.9323,47.7365],[-96.9324,47.7366],[-96.9325,47.7368],[-96.9327,47.7371],[-96.9328,47.7372],[-96.9332,47.7383],[-96.9333,47.7388],[-96.9332,47.7395],[-96.933,47.74],[-96.9327,47.7403],[-96.9319,47.741],[-96.9318,47.7411],[-96.9308,47.7417],[-96.9302,47.7422],[-96.9293,47.743],[-96.929,47.7435],[-96.9287,47.7442],[-96.9285,47.7449],[-96.9284,47.7454],[-96.9284,47.7465],[-96.9285,47.7481],[-96.9286,47.7491],[-96.9288,47.7493],[-96.9289,47.7497],[-96.929,47.7497],[-96.9289,47.75],[-96.929,47.7504],[-96.9298,47.751],[-96.9308,47.7515],[-96.9322,47.7521],[-96.9332,47.7526],[-96.9351,47.7532],[-96.9387,47.754],[-96.9394,47.7544],[-96.9398,47.7549],[-96.9397,47.7555],[-96.9394,47.7559],[-96.9388,47.7562],[-96.9381,47.7563],[-96.9373,47.7563],[-96.9363,47.7562],[-96.9337,47.7551],[-96.9327,47.7548],[-96.9323,47.7548],[-96.9311,47.7547],[-96.9297,47.7549],[-96.9291,47.755],[-96.9289,47.7553],[-96.9288,47.7558],[-96.9291,47.7561],[-96.9298,47.7565],[-96.9309,47.7569],[-96.9324,47.7573],[-96.9335,47.7576],[-96.9355,47.7583],[-96.9368,47.759],[-96.9369,47.7592],[-96.9371,47.7594],[-96.9372,47.7595],[-96.9378,47.7602],[-96.9379,47.7604],[-96.9381,47.7607],[-96.9381,47.7609],[-96.9382,47.7609],[-96.9382,47.761],[-96.9384,47.7614],[-96.9384,47.7625],[-96.938,47.7632],[-96.9376,47.7639],[-96.9369,47.7646],[-96.9366,47.7649],[-96.9352,47.7658],[-96.9351,47.766],[-96.9349,47.7664],[-96.9348,47.7668],[-96.9349,47.7671],[-96.9357,47.7676],[-96.9365,47.7678],[-96.9382,47.7681],[-96.9391,47.7684],[-96.9404,47.7692],[-96.9423,47.7708],[-96.943,47.7712],[-96.9442,47.7717],[-96.9445,47.7717],[-96.9445,47.7719],[-96.9452,47.7722],[-96.9457,47.7727],[-96.9458,47.7729],[-96.9459,47.7734],[-96.9459,47.7743],[-96.946,47.7746],[-96.9466,47.775],[-96.9473,47.7753],[-96.9483,47.7755],[-96.9494,47.7753],[-96.9495,47.7753],[-96.9518,47.7747],[-96.9527,47.7746],[-96.9537,47.7746],[-96.9539,47.7747],[-96.955,47.7748],[-96.956,47.7751],[-96.9565,47.7753],[-96.9567,47.7757],[-96.9567,47.7761],[-96.9566,47.7762],[-96.9544,47.7777],[-96.9538,47.778],[-96.9527,47.7787],[-96.9523,47.779],[-96.9522,47.7793],[-96.9524,47.7796],[-96.9527,47.7799],[-96.9533,47.78],[-96.9538,47.78],[-96.9554,47.7798],[-96.9565,47.7798],[-96.9573,47.78],[-96.9584,47.7803],[-96.9589,47.7807],[-96.9593,47.7812],[-96.9593,47.7819],[-96.9592,47.7819],[-96.9578,47.7838],[-96.9576,47.7844],[-96.9575,47.7847],[-96.9575,47.7852],[-96.9578,47.7855],[-96.9581,47.7856],[-96.9584,47.7857],[-96.959,47.7855],[-96.9596,47.7849],[-96.9597,47.7847],[-96.9598,47.7847],[-96.9598,47.7846],[-96.9601,47.7843],[-96.961,47.7838],[-96.9619,47.7833],[-96.9631,47.783],[-96.9638,47.783],[-96.9644,47.783],[-96.9649,47.7833],[-96.9653,47.7835],[-96.9654,47.7839],[-96.9653,47.785],[-96.9651,47.7853],[-96.965,47.7855],[-96.9645,47.7862],[-96.9635,47.7873],[-96.9628,47.7879],[-96.9621,47.7884],[-96.9615,47.7888],[-96.9599,47.7893],[-96.9586,47.7896],[-96.958,47.7898],[-96.9576,47.79],[-96.9572,47.7902],[-96.9571,47.7904],[-96.9572,47.791],[-96.9573,47.7913],[-96.9574,47.7915],[-96.9578,47.7921],[-96.9584,47.7925],[-96.9597,47.7931],[-96.9627,47.7942],[-96.9635,47.7947],[-96.9642,47.7951],[-96.965,47.7959],[-96.9657,47.7968],[-96.966,47.7973],[-96.9661,47.7992],[-96.9662,47.7993],[-96.9663,47.7994],[-96.9669,47.7998],[-96.9674,47.7999],[-96.9681,47.7998],[-96.9687,47.7996],[-96.9689,47.7995],[-96.9702,47.7987],[-96.9716,47.7983],[-96.974,47.7978],[-96.9751,47.7978],[-96.9754,47.7978],[-96.9762,47.7979],[-96.9766,47.7981],[-96.9768,47.7983],[-96.977,47.7986],[-96.977,47.8],[-96.9764,47.8013],[-96.9761,47.8016],[-96.9759,47.8017],[-96.9754,47.8019],[-96.9751,47.8019],[-96.973,47.8019],[-96.9723,47.802],[-96.9721,47.8022],[-96.9719,47.8025],[-96.9721,47.8029],[-96.973,47.8034],[-96.974,47.8036],[-96.9749,47.8037],[-96.9751,47.8037],[-96.9769,47.8037],[-96.9789,47.804],[-96.9796,47.8042],[-96.981,47.8045],[-96.9818,47.8046],[-96.9826,47.805],[-96.9828,47.8051],[-96.9831,47.8051],[-96.9832,47.8053],[-96.9851,47.8065],[-96.9859,47.8069],[-96.9863,47.8071],[-96.9877,47.8072],[-96.9894,47.8072],[-96.9905,47.8076],[-96.991,47.8078],[-96.9914,47.8081],[-96.9916,47.8085],[-96.9916,47.8091],[-96.9912,47.8094],[-96.9903,47.8097],[-96.9891,47.8099],[-96.9882,47.8099],[-96.9864,47.8098],[-96.9818,47.8091],[-96.9805,47.8092],[-96.9796,47.8095],[-96.9788,47.8099],[-96.9782,47.8106],[-96.978,47.8112],[-96.9779,47.8117],[-96.9781,47.8122],[-96.9784,47.8128],[-96.9786,47.8129],[-96.9787,47.8131],[-96.9795,47.8138],[-96.9795,47.8139],[-96.9798,47.8143],[-96.9799,47.8145],[-96.9799,47.8146],[-96.9803,47.8157],[-96.9804,47.8187],[-96.9804,47.822],[-96.9802,47.8224],[-96.9797,47.8226],[-96.979,47.8226],[-96.9772,47.8222],[-96.9764,47.8221],[-96.9759,47.8221],[-96.9754,47.8222],[-96.9747,47.8224],[-96.9745,47.8224],[-96.9744,47.8225],[-96.9741,47.8228],[-96.9741,47.8234],[-96.9743,47.8239],[-96.9749,47.8244],[-96.9757,47.825],[-96.9759,47.825],[-96.9769,47.8254],[-96.9783,47.8256],[-96.9793,47.8257],[-96.982,47.8255],[-96.9845,47.8251],[-96.9857,47.8251],[-96.9865,47.8252],[-96.9869,47.8254],[-96.9872,47.8256],[-96.9871,47.8261],[-96.9867,47.8265],[-96.9858,47.8269],[-96.984,47.8275],[-96.9827,47.8281],[-96.9825,47.8283],[-96.9819,47.8287],[-96.9817,47.829],[-96.9815,47.8295],[-96.9816,47.8301],[-96.9817,47.8305],[-96.982,47.8309],[-96.9843,47.8325],[-96.9848,47.8331],[-96.9849,47.8332],[-96.9849,47.8333],[-96.985,47.8334],[-96.9852,47.8339],[-96.9853,47.8344],[-96.9854,47.8345],[-96.9857,47.8359],[-96.9859,47.8361],[-96.9859,47.8366],[-96.9863,47.8373],[-96.9866,47.8377],[-96.9873,47.8379],[-96.9881,47.838],[-96.9896,47.8381],[-96.9907,47.838],[-96.9915,47.8378],[-96.9924,47.8378],[-96.9929,47.838],[-96.9937,47.8383],[-96.9941,47.8388],[-96.9941,47.8396],[-96.994,47.8397],[-96.9935,47.8404],[-96.9929,47.8412],[-96.9925,47.8417],[-96.9924,47.8421],[-96.9924,47.8426],[-96.9927,47.8427],[-96.9931,47.8428],[-96.9938,47.8426],[-96.9956,47.842],[-96.9969,47.8416],[-96.9976,47.8416],[-96.9976,47.8435],[-96.9974,47.8437],[-96.9963,47.8444],[-96.9958,47.8447],[-96.9947,47.845],[-96.9943,47.8452],[-96.9941,47.8455],[-96.994,47.8458],[-96.9941,47.8461],[-96.9941,47.8462],[-96.9942,47.8463],[-96.9943,47.8464],[-96.9949,47.847],[-96.9956,47.8474],[-96.9967,47.848],[-96.9968,47.848],[-96.9968,47.8482],[-96.9969,47.8482],[-96.9971,47.8484],[-96.9973,47.8488],[-96.9975,47.8496],[-96.9973,47.8504],[-96.9969,47.8515],[-96.9967,47.8526],[-96.9968,47.8545],[-96.9969,47.8555],[-96.9971,47.8561],[-96.9971,47.8564],[-96.9972,47.8566],[-96.9973,47.8567],[-96.9974,47.8574],[-96.9976,47.8577],[-96.9978,47.8583],[-96.9978,47.8583],[-96.9981,47.8589],[-96.9982,47.859],[-96.9983,47.8592],[-96.9989,47.8599],[-96.9994,47.8603],[-96.9998,47.8607],[-97.0003,47.861],[-97.0017,47.8613],[-97.0031,47.8623],[-97.0055,47.864],[-97.0058,47.8653],[-97.0033,47.8659],[-97.0015,47.8674],[-97.0024,47.8687],[-97.0053,47.8702],[-97.0084,47.8708],[-97.0173,47.8716],[-97.0194,47.8722],[-97.0212,47.8726],[-97.0218,47.8731],[-97.0231,47.874],[-97.0231,47.875],[-97.0221,47.8755],[-97.0196,47.8766],[-97.0193,47.8768],[-97.0189,47.8769],[-97.0179,47.8785],[-97.0193,47.8803],[-97.022,47.8815],[-97.0233,47.8821],[-97.0253,47.8843],[-97.0253,47.8856],[-97.0249,47.8869],[-97.0222,47.8884],[-97.0194,47.8897],[-97.0191,47.8898],[-97.0189,47.8911],[-97.019,47.8912],[-97.0195,47.8915],[-97.0225,47.8933],[-97.0249,47.895],[-97.0239,47.8981],[-97.0201,47.9005],[-97.0202,47.9022],[-97.0241,47.9053],[-97.0242,47.9056],[-97.0249,47.9082],[-97.0245,47.9083],[-97.0235,47.9085],[-97.0203,47.9064],[-97.0198,47.9063],[-97.0184,47.906],[-97.0172,47.9057],[-97.015,47.9072],[-97.015,47.9073],[-97.0153,47.9103],[-97.0156,47.9108],[-97.0172,47.9131],[-97.0195,47.9141],[-97.0197,47.9142],[-97.0214,47.9147],[-97.0237,47.9159],[-97.0196,47.9175],[-97.018,47.9181],[-97.0177,47.9198],[-97.0183,47.9202],[-97.0196,47.9211],[-97.0213,47.9221],[-97.0219,47.9224],[-97.0235,47.9236],[-97.0247,47.9244],[-97.026,47.9253],[-97.0284,47.9269],[-97.0296,47.9276],[-97.0323,47.9285],[-97.0357,47.9302],[-97.0373,47.9333],[-97.0368,47.9343],[-97.0355,47.9366],[-97.036,47.9394],[-97.0374,47.9399],[-97.0391,47.9405],[-97.0394,47.9405],[-97.0416,47.9406],[-97.0417,47.9406],[-97.0449,47.9411],[-97.051,47.9434],[-97.0545,47.9463],[-97.0555,47.9491],[-97.0555,47.9491],[-97.0553,47.9502],[-97.0551,47.9508],[-97.0525,47.9548],[-97.0524,47.9572],[-97.054,47.9597],[-97.059,47.9621],[-97.0613,47.9636],[-97.0614,47.9636],[-97.0618,47.9645],[-97.0615,47.9659],[-97.06,47.9672],[-97.0578,47.969],[-97.0571,47.9705],[-97.0593,47.974],[-97.0591,47.9754],[-97.0589,47.976],[-97.0588,47.9762],[-97.0587,47.9766],[-97.0584,47.977],[-97.0582,47.9774],[-97.0579,47.9778],[-97.0577,47.9781],[-97.0577,47.9782],[-97.0574,47.9787],[-97.0571,47.9792],[-97.0567,47.9801],[-97.0564,47.9806],[-97.0563,47.9811],[-97.0561,47.9815],[-97.0559,47.9821],[-97.0556,47.9828],[-97.0554,47.9833],[-97.0553,47.9838],[-97.0552,47.9842],[-97.0549,47.9849],[-97.0546,47.9855],[-97.0544,47.986],[-97.0541,47.9866],[-97.0539,47.9871],[-97.0537,47.9877],[-97.0535,47.988],[-97.0534,47.9884],[-97.0533,47.9887],[-97.0532,47.989],[-97.053,47.9894],[-97.053,47.9898],[-97.053,47.9903],[-97.053,47.9905],[-97.0531,47.9907],[-97.0532,47.9909],[-97.0533,47.9912],[-97.0534,47.9915],[-97.0535,47.9917],[-97.0538,47.992],[-97.0541,47.9923],[-97.0543,47.9925],[-97.0545,47.9926],[-97.0549,47.993],[-97.0555,47.9933],[-97.0561,47.9936],[-97.0566,47.9938],[-97.0571,47.9939],[-97.0578,47.9941],[-97.0584,47.9943],[-97.0591,47.9945],[-97.0597,47.9948],[-97.0601,47.9949],[-97.0604,47.9951],[-97.0608,47.9953],[-97.0614,47.9956],[-97.0617,47.9957],[-97.0619,47.9959],[-97.0622,47.996],[-97.0625,47.9962],[-97.0628,47.9965],[-97.063,47.9967],[-97.0633,47.997],[-97.0637,47.9975],[-97.0639,47.9977],[-97.0641,47.9982],[-97.0642,47.9986],[-97.0644,47.9989],[-97.0644,47.9994],[-97.0645,48.0],[-97.0645,48.0004],[-97.0644,48.002],[-97.0644,48.0027],[-97.0645,48.0034],[-97.0648,48.0045],[-97.0656,48.0064],[-97.0659,48.0071],[-97.0662,48.0079],[-97.0667,48.0089],[-97.0667,48.0096],[-97.0666,48.0102],[-97.0654,48.0114],[-97.0638,48.0125],[-97.0636,48.0126],[-97.063,48.0132],[-97.0628,48.0138],[-97.0629,48.0145],[-97.0632,48.015],[-97.0638,48.0153],[-97.0649,48.0157],[-97.0685,48.016],[-97.0692,48.0162],[-97.0706,48.017],[-97.0717,48.0181],[-97.0722,48.0192],[-97.0723,48.0196],[-97.0723,48.0201],[-97.0721,48.0207],[-97.0721,48.0209],[-97.0719,48.0214],[-97.0713,48.0228],[-97.0699,48.0247],[-97.0689,48.0263],[-97.0687,48.0277],[-97.0688,48.029],[-97.0691,48.0313],[-97.0697,48.0334],[-97.07,48.0354],[-97.0701,48.0361],[-97.0699,48.0374],[-97.0704,48.0418],[-97.0712,48.0458],[-97.0719,48.0474],[-97.0722,48.0481],[-97.0732,48.0499],[-97.0732,48.05],[-97.074,48.0513],[-97.0747,48.0521],[-97.0756,48.0528],[-97.0767,48.0533],[-97.0782,48.054],[-97.0795,48.0545],[-97.0815,48.0553],[-97.0828,48.0558],[-97.084,48.0564],[-97.0845,48.0567],[-97.0859,48.0575],[-97.0869,48.0583],[-97.0881,48.0596],[-97.0892,48.0611],[-97.0905,48.0627],[-97.0905,48.0628],[-97.0908,48.0631],[-97.0919,48.0644],[-97.092,48.0644],[-97.0932,48.0653],[-97.0951,48.0669],[-97.0958,48.0677],[-97.0963,48.0688],[-97.0969,48.07],[-97.0972,48.0706],[-97.0977,48.0711],[-97.0982,48.0714],[-97.0988,48.0715],[-97.0997,48.0716],[-97.1012,48.0715],[-97.103,48.0717],[-97.1038,48.0719],[-97.1044,48.0725],[-97.1046,48.0731],[-97.1045,48.074],[-97.1041,48.0746],[-97.1007,48.0775],[-97.1005,48.078],[-97.1001,48.0788],[-97.0998,48.0799],[-97.0994,48.0822],[-97.0994,48.0838],[-97.0996,48.0849],[-97.0997,48.0859],[-97.1001,48.0869],[-97.1012,48.0884],[-97.1021,48.0892],[-97.1034,48.0898],[-97.1047,48.0902],[-97.1066,48.0904],[-97.108,48.0906],[-97.1094,48.091],[-97.1098,48.0914],[-97.1097,48.0917],[-97.1095,48.0922],[-97.1087,48.0928],[-97.1067,48.0934],[-97.1066,48.0934],[-97.104,48.0939],[-97.1031,48.0941],[-97.1025,48.0946],[-97.102,48.0953],[-97.1018,48.0959],[-97.1022,48.0967],[-97.1029,48.0973],[-97.1041,48.098],[-97.106,48.0987],[-97.1066,48.0989],[-97.1074,48.0992],[-97.108,48.0996],[-97.1084,48.0999],[-97.1086,48.1003],[-97.1088,48.1008],[-97.1089,48.1017],[-97.1088,48.1028],[-97.109,48.1038],[-97.1095,48.1048],[-97.1107,48.1056],[-97.1114,48.106],[-97.1124,48.1062],[-97.1131,48.1062],[-97.115,48.106],[-97.1169,48.1057],[-97.1181,48.1056],[-97.1197,48.1054],[-97.1208,48.1056],[-97.1218,48.1059],[-97.1225,48.1063],[-97.1232,48.1067],[-97.1234,48.1073],[-97.1235,48.1076],[-97.1236,48.1078],[-97.1236,48.1081],[-97.1231,48.1095],[-97.122,48.1109],[-97.121,48.1123],[-97.1205,48.1134],[-97.1207,48.115],[-97.121,48.1159],[-97.1215,48.117],[-97.1253,48.1223],[-97.1256,48.1224],[-97.1257,48.1226],[-97.1261,48.1233],[-97.1268,48.1243],[-97.127,48.1246],[-97.1271,48.125],[-97.1275,48.1258],[-97.1282,48.1272],[-97.1286,48.1284],[-97.1288,48.1291],[-97.129,48.1309],[-97.1294,48.1332],[-97.13,48.134],[-97.1314,48.135],[-97.1323,48.1358],[-97.1328,48.1362],[-97.1332,48.1366],[-97.1334,48.1372],[-97.133,48.1375],[-97.1325,48.1377],[-97.1319,48.1376],[-97.1303,48.1372],[-97.1293,48.1369],[-97.1289,48.1367],[-97.128,48.1364],[-97.1276,48.1362],[-97.1267,48.1361],[-97.1253,48.1361],[-97.1241,48.1364],[-97.124,48.1365],[-97.123,48.137],[-97.1227,48.1375],[-97.1224,48.1381],[-97.1223,48.1386],[-97.1223,48.1391],[-97.1228,48.1398],[-97.1234,48.1402],[-97.1239,48.1406],[-97.1248,48.1409],[-97.1253,48.1411],[-97.1266,48.1416],[-97.1277,48.1418],[-97.1294,48.1421],[-97.1297,48.1421],[-97.1319,48.1424],[-97.1347,48.143],[-97.1367,48.1433],[-97.1379,48.1433],[-97.1393,48.1429],[-97.1407,48.1423],[-97.1415,48.1417],[-97.1426,48.1413],[-97.1435,48.141],[-97.1444,48.1411],[-97.1454,48.1413],[-97.1461,48.1417],[-97.1465,48.1423],[-97.1466,48.1433],[-97.1465,48.1441],[-97.1458,48.1452],[-97.1447,48.1466],[-97.1435,48.1475],[-97.1425,48.1487],[-97.1413,48.1501],[-97.1405,48.1508],[-97.1402,48.1509],[-97.1391,48.1516],[-97.1371,48.1523],[-97.1328,48.1535],[-97.1307,48.1542],[-97.1305,48.1543],[-97.1281,48.1552],[-97.1263,48.156],[-97.1253,48.1563],[-97.1244,48.1566],[-97.1236,48.1571],[-97.1225,48.1577],[-97.1217,48.1583],[-97.1211,48.1588],[-97.121,48.1591],[-97.1209,48.1596],[-97.121,48.1608],[-97.1211,48.1612],[-97.1214,48.1615],[-97.1218,48.1617],[-97.1224,48.1621],[-97.1233,48.1625],[-97.1241,48.1627],[-97.1247,48.1628],[-97.1253,48.1629],[-97.1273,48.1628],[-97.1285,48.1626],[-97.1305,48.162],[-97.1313,48.1617],[-97.1322,48.1614],[-97.1345,48.1603],[-97.1363,48.1598],[-97.1385,48.1595],[-97.1403,48.1598],[-97.1419,48.1603],[-97.1431,48.1611],[-97.1442,48.1625],[-97.1443,48.1633],[-97.1445,48.1641],[-97.1447,48.165],[-97.1451,48.1668],[-97.1454,48.1675],[-97.1463,48.1686],[-97.1475,48.1706],[-97.1475,48.1725],[-97.1467,48.1733]]],"type":"Polygon"},"id":"60","properties":{"Area":5177876131.64875,"CTYONLY_":9,"Code":"POLK","LASTMOD":"1999-12-31T23:59:59Z","Name":"Polk","Perimiter":458889.41551},"type":"Feature"},{"geometry":{"coordinates":[[[-96.5008,48.1742],[-96.5008,48.1742],[-96.5006,48.1741],[-96.5003,48.1741],[-96.4973,48.174],[-96.4946,48.1741],[-96.4841,48.174],[-96.4791,48.1741],[-96.4789,48.1741],[-96.4773,48.1741],[-96.4735,48.174],[-96.467,48.1741],[-96.4592,48.1742],[-96.4569,48.1742],[-96.4564,48.1742],[-96.4563,48.1743],[-96.4561,48.1744],[-96.4454,48.1747],[-96.4436,48.1747],[-96.4402,48.1748],[-96.438,48.1749],[-96.4359,48.1749],[-96.4352,48.1749],[-96.4346,48.1749],[-96.4295,48.1749],[-96.4206,48.1749],[-96.4135,48.1749],[-96.4126,48.1749],[-96.4126,48.1749],[-96.4054,48.1748],[-96.3964,48.1748],[-96.3906,48.1748],[-96.3905,48.1748],[-96.3894,48.1748],[-96.3856,48.1747],[-96.38,48.1745],[-96.3781,48.1746],[-96.3753,48.1748],[-96.3728,48.1749],[-96.3706,48.175],[-96.3685,48.1751],[-96.3682,48.1751],[-96.3682,48.1751],[-96.3656,48.175],[-96.3642,48.1749],[-96.361,48.1748],[-96.3581,48.1747],[-96.3542,48.1746],[-96.351,48.1745],[-96.3477,48.1744],[-96.3473,48.1744],[-96.347,48.1743],[-96.3466,48.1743],[-96.343,48.1744],[-96.3402,48.1744],[-96.338,48.1745],[-96.3358,48.1744],[-96.3356,48.1745],[-96.3301,48.1745],[-96.3253,48.1746],[-96.3252,48.1746],[-96.3145,48.1747],[-96.3035,48.1747],[-96.3029,48.1747],[-96.2977,48.1747],[-96.2824,48.1747],[-96.2823,48.1747],[-96.2805,48.1747],[-96.2619,48.1749],[-96.2612,48.1749],[-96.2607,48.1749],[-96.2596,48.1749],[-96.2562,48.1744],[-96.252,48.174],[-96.2511,48.174],[-96.2503,48.1739],[-96.2491,48.1737],[-96.2476,48.1735],[-96.2398,48.1728],[-96.2397,48.1727],[-96.2397,48.1727],[-96.2391,48.1727],[-96.2329,48.1725],[-96.2307,48.1725],[-96.2287,48.1725],[-96.2275,48.1724],[-96.2251,48.1724],[-96.2188,48.1722],[-96.2179,48.1722],[-96.2177,48.1722],[-96.2076,48.1722],[-96.2072,48.1722],[-96.2038,48.1722],[-96.2023,48.1722],[-96.1963,48.1721],[-96.1959,48.1721],[-96.1954,48.1721],[-96.1948,48.1721],[-96.191,48.1721],[-96.1874,48.1721],[-96.1834,48.172],[-96.1827,48.1722],[-96.1813,48.1725],[-96.1741,48.1736],[-96.1737,48.1736],[-96.1736,48.1736],[-96.1641,48.1736],[-96.1625,48.1736],[-96.1518,48.1736],[-96.1516,48.1736],[-96.1388,48.1732],[-96.1302,48.173],[-96.1298,48.173],[-96.1297,48.173],[-96.1253,48.1727],[-96.1189,48.1722],[-96.1176,48.1722],[-96.1084,48.1718],[-96.1084,48.1718],[-96.0979,48.172],[-96.09,48.172],[-96.09,48.172],[-96.079,48.1721],[-96.0685,48.1721],[-96.0685,48.1721],[-96.0592,48.1721],[-96.0468,48.1722],[-96.0468,48.1722],[-96.0254,48.1721],[-96.025,48.1721],[-96.0171,48.172],[-96.0101,48.1718],[-96.0047,48.1717],[-96.0036,48.1718],[-96.0035,48.1718],[-96.0032,48.1718],[-96.0028,48.1718],[-96.0023,48.1718],[-96.0003,48.1717],[-95.9956,48.1717],[-95.9819,48.1717],[-95.9817,48.1717],[-95.9651,48.1718],[-95.961,48.1718],[-95.9609,48.1718],[-95.9608,48.1718],[-95.9394,48.1719],[-95.9392,48.1719],[-95.9178,48.1719],[-95.9178,48.1719],[-95.9176,48.1719],[-95.896,48.172],[-95.8958,48.172],[-95.8752,48.172],[-95.8744,48.172],[-95.8744,48.172],[-95.8527,48.1721],[-95.8525,48.1721],[-95.8499,48.1721],[-95.8308,48.1722],[-95.8308,48.1722],[-95.8305,48.1722],[-95.8091,48.1722],[-95.809,48.1722],[-95.8088,48.1722],[-95.7874,48.1725],[-95.7657,48.1728],[-95.7657,48.1728],[-95.7502,48.1727],[-95.7443,48.1727],[-95.744,48.1727],[-95.7227,48.1731],[-95.7226,48.1731],[-95.7157,48.1731],[-95.7128,48.173],[-95.7022,48.1729],[-95.7021,48.1729],[-95.702,48.1729],[-95.6803,48.1728],[-95.6802,48.1728],[-95.662,48.1729],[-95.6591,48.1729],[-95.6376,48.173],[-95.6376,48.173],[-95.6279,48.1731],[-95.6252,48.1731],[-95.6163,48.1731],[-95.6159,48.1731],[-95.5941,48.173],[-95.5939,48.173],[-95.5939,48.1658],[-95.5938,48.1512],[-95.5936,48.1368],[-95.5931,48.1223],[-95.593,48.1078],[-95.5928,48.0931],[-95.5926,48.0787],[-95.5925,48.0642],[-95.5925,48.0497],[-95.5923,48.035],[-95.5922,48.0207],[-95.5828,48.0207],[-95.5825,48.0063],[-95.5824,47.9917],[-95.5825,47.9771],[-95.5826,47.9629],[-95.5825,47.9482],[-95.5824,47.9339],[-95.6034,47.9341],[-95.6252,47.9344],[-95.6466,47.9348],[-95.6683,47.9351],[-95.6898,47.9354],[-95.7096,47.9355],[-95.7097,47.9499],[-95.7098,47.9644],[-95.7312,47.9644],[-95.7531,47.9645],[-95.7747,47.9646],[-95.7963,47.9647],[-95.8181,47.9647],[-95.8383,47.9648],[-95.86,47.9649],[-95.8814,47.9648],[-95.9031,47.9648],[-95.925,47.9647],[-95.9462,47.9646],[-95.9671,47.9646],[-95.9887,47.9642],[-96.0106,47.9641],[-96.0324,47.964],[-96.054,47.9638],[-96.0757,47.9637],[-96.096,47.9638],[-96.1173,47.9632],[-96.1389,47.9631],[-96.1606,47.9631],[-96.1826,47.9632],[-96.2044,47.963],[-96.2235,47.9629],[-96.2453,47.9629],[-96.2667,47.9629],[-96.2883,47.963],[-96.31,47.9633],[-96.3316,47.9634],[-96.3526,47.9634],[-96.3738,47.9636],[-96.3954,47.9636],[-96.4172,47.9637],[-96.439,47.9636],[-96.4603,47.9639],[-96.4823,47.9636],[-96.4823,47.9782],[-96.4824,47.9924],[-96.4826,48.0072],[-96.4826,48.0217],[-96.5009,48.0217],[-96.5009,48.0362],[-96.5008,48.0506],[-96.5009,48.0654],[-96.5009,48.0798],[-96.5009,48.0943],[-96.501,48.1089],[-96.5007,48.1234],[-96.5006,48.1379],[-96.5008,48.1524],[-96.5008,48.1669],[-96.5008,48.1742]]],"type":"Polygon"},"id":"57","properties":{"Area":1601102945.98836,"CTYONLY_":10,"Code":"PENN","LASTMOD":"2006-07-04T12:00:00Z","Name":"Pennington","Perimiter":190039.7415},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&filter=Name%3C%3E'Rice'","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&filter=Name%3C%3E'Rice'","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=9&filter=Name%3C%3E'Rice'","rel":"next","title":"next page","type":"application/geo+json"}],"numberMatched":116,"numberReturned":9,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_text_not_not_between_json.txt b/msautotest/api/expected/ogcapi_cql2_text_not_not_between_json.txt new file mode 100644 index 0000000000..4e5b28905b --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_text_not_not_between_json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 3 +OGC-NumberReturned: 3 + +{"features":[{"geometry":{"coordinates":[[[-96.4054,49.0001],[-96.4054,48.9947],[-96.4054,48.994],[-96.4054,48.9803],[-96.4054,48.9793],[-96.4053,48.9705],[-96.4053,48.9658],[-96.4053,48.9648],[-96.4053,48.9515],[-96.4053,48.9504],[-96.4053,48.9371],[-96.4053,48.936],[-96.4054,48.9225],[-96.4054,48.9214],[-96.4053,48.9137],[-96.4053,48.9081],[-96.4053,48.9068],[-96.405,48.8926],[-96.405,48.878],[-96.4047,48.8635],[-96.4045,48.8491],[-96.4043,48.8343],[-96.4042,48.8198],[-96.4042,48.8048],[-96.4042,48.7903],[-96.4045,48.7758],[-96.4047,48.7607],[-96.4048,48.7465],[-96.4048,48.7318],[-96.4049,48.7172],[-96.388,48.7172],[-96.3873,48.7172],[-96.3866,48.703],[-96.3874,48.6887],[-96.3871,48.6741],[-96.3877,48.6599],[-96.3879,48.6454],[-96.388,48.6313],[-96.389,48.6165],[-96.3891,48.6024],[-96.3884,48.5877],[-96.3882,48.5733],[-96.3879,48.5588],[-96.3882,48.5442],[-96.4101,48.544],[-96.4318,48.5438],[-96.4535,48.5436],[-96.4754,48.5435],[-96.4973,48.5434],[-96.518,48.5434],[-96.54,48.5434],[-96.5621,48.5436],[-96.5839,48.5437],[-96.6058,48.5437],[-96.6278,48.5437],[-96.6493,48.5437],[-96.6713,48.5436],[-96.6931,48.5437],[-96.7151,48.5437],[-96.7368,48.5437],[-96.7585,48.5436],[-96.7803,48.5435],[-96.8023,48.5436],[-96.824,48.5436],[-96.8459,48.5434],[-96.8678,48.5433],[-96.8896,48.5433],[-96.9115,48.5432],[-96.9138,48.5433],[-96.9331,48.5435],[-96.9551,48.5437],[-96.9768,48.544],[-96.9985,48.5441],[-97.0194,48.5441],[-97.0416,48.5442],[-97.0635,48.5441],[-97.0852,48.5441],[-97.107,48.544],[-97.1287,48.5439],[-97.1509,48.5439],[-97.1631,48.544],[-97.1637,48.5445],[-97.1659,48.5483],[-97.1662,48.5509],[-97.1661,48.5527],[-97.1654,48.5536],[-97.1645,48.554],[-97.1628,48.5543],[-97.1613,48.5539],[-97.1592,48.5528],[-97.1577,48.5518],[-97.1557,48.5512],[-97.1538,48.5513],[-97.1513,48.5515],[-97.1507,48.5515],[-97.1493,48.5516],[-97.1474,48.5516],[-97.1444,48.5514],[-97.1407,48.5515],[-97.1387,48.5522],[-97.1379,48.553],[-97.1379,48.5542],[-97.1391,48.5554],[-97.141,48.5566],[-97.1426,48.5571],[-97.1464,48.5573],[-97.1505,48.5574],[-97.1515,48.5574],[-97.1551,48.5574],[-97.1578,48.5573],[-97.1606,48.5571],[-97.1631,48.5571],[-97.1646,48.5572],[-97.167,48.5575],[-97.1697,48.5584],[-97.1721,48.5591],[-97.1727,48.5593],[-97.174,48.5599],[-97.1749,48.5606],[-97.1753,48.5614],[-97.1754,48.5623],[-97.1749,48.5631],[-97.1744,48.5639],[-97.1723,48.5648],[-97.1721,48.5648],[-97.1706,48.5652],[-97.1687,48.5655],[-97.167,48.5658],[-97.1651,48.5659],[-97.1613,48.5661],[-97.1541,48.5669],[-97.153,48.5671],[-97.1516,48.5677],[-97.1503,48.5688],[-97.1496,48.5695],[-97.1487,48.5707],[-97.1477,48.5727],[-97.1477,48.5728],[-97.1476,48.5731],[-97.1483,48.5763],[-97.15,48.5775],[-97.1501,48.5775],[-97.1548,48.5779],[-97.1592,48.5785],[-97.1605,48.58],[-97.16,48.5816],[-97.1578,48.5826],[-97.1562,48.5828],[-97.1541,48.5826],[-97.1524,48.5823],[-97.15,48.5815],[-97.1494,48.5813],[-97.1484,48.5811],[-97.1449,48.5815],[-97.1436,48.5824],[-97.1431,48.5834],[-97.1429,48.5838],[-97.142,48.5876],[-97.1418,48.5886],[-97.1415,48.5909],[-97.1422,48.5926],[-97.1433,48.5936],[-97.1451,48.594],[-97.1471,48.594],[-97.1497,48.5937],[-97.1525,48.594],[-97.1536,48.5949],[-97.1535,48.5957],[-97.1527,48.5962],[-97.1524,48.5969],[-97.1516,48.598],[-97.1498,48.5981],[-97.1497,48.5981],[-97.1463,48.5977],[-97.1443,48.5981],[-97.143,48.5987],[-97.1416,48.6002],[-97.1403,48.6021],[-97.14,48.6025],[-97.138,48.6044],[-97.1359,48.6054],[-97.1345,48.6065],[-97.1341,48.6075],[-97.1349,48.6082],[-97.1358,48.6086],[-97.137,48.6088],[-97.1396,48.6086],[-97.1443,48.6078],[-97.1474,48.6081],[-97.1494,48.6089],[-97.1495,48.609],[-97.1505,48.6115],[-97.1501,48.6124],[-97.1493,48.6129],[-97.1478,48.6138],[-97.145,48.6146],[-97.1408,48.6149],[-97.137,48.6144],[-97.134,48.6136],[-97.1319,48.6133],[-97.1309,48.6137],[-97.1289,48.614],[-97.1286,48.6153],[-97.1293,48.6168],[-97.1295,48.617],[-97.1311,48.6184],[-97.1342,48.6199],[-97.1353,48.6212],[-97.1346,48.6224],[-97.133,48.6228],[-97.131,48.6227],[-97.1291,48.6222],[-97.1277,48.6212],[-97.1274,48.621],[-97.1259,48.6195],[-97.1253,48.619],[-97.1243,48.6183],[-97.1231,48.6178],[-97.1216,48.6176],[-97.12,48.6178],[-97.1193,48.6182],[-97.1186,48.6191],[-97.1183,48.6198],[-97.1186,48.6209],[-97.1198,48.6221],[-97.1209,48.6232],[-97.1212,48.6233],[-97.122,48.624],[-97.1228,48.6245],[-97.1236,48.625],[-97.1241,48.6254],[-97.1245,48.6257],[-97.1249,48.6259],[-97.1253,48.6261],[-97.126,48.6264],[-97.1266,48.6266],[-97.1272,48.627],[-97.1279,48.6273],[-97.1288,48.6278],[-97.1296,48.6282],[-97.1302,48.6288],[-97.1305,48.6292],[-97.1307,48.6297],[-97.131,48.6303],[-97.131,48.6304],[-97.131,48.6308],[-97.131,48.6315],[-97.1309,48.6317],[-97.1307,48.6321],[-97.1304,48.6325],[-97.1301,48.6326],[-97.1297,48.6328],[-97.1293,48.6329],[-97.129,48.633],[-97.1281,48.6332],[-97.128,48.6333],[-97.1275,48.6333],[-97.1253,48.6334],[-97.1235,48.6333],[-97.1216,48.6327],[-97.1181,48.6308],[-97.1176,48.6307],[-97.115,48.6299],[-97.1133,48.63],[-97.1115,48.6303],[-97.1107,48.6308],[-97.1104,48.6309],[-97.1095,48.6315],[-97.1084,48.6327],[-97.1082,48.6344],[-97.1086,48.6363],[-97.1096,48.6389],[-97.1109,48.6407],[-97.1119,48.6416],[-97.1144,48.6433],[-97.115,48.6438],[-97.115,48.6446],[-97.1149,48.6452],[-97.1123,48.6457],[-97.1112,48.6459],[-97.1093,48.6465],[-97.1078,48.6478],[-97.1069,48.6491],[-97.1066,48.6501],[-97.1061,48.6519],[-97.1059,48.6527],[-97.1045,48.6545],[-97.1017,48.6563],[-97.0987,48.6593],[-97.0986,48.6604],[-97.0985,48.6613],[-97.0992,48.6625],[-97.1019,48.6636],[-97.106,48.663],[-97.1062,48.663],[-97.1082,48.6634],[-97.1087,48.6645],[-97.1061,48.6654],[-97.1057,48.6655],[-97.102,48.6667],[-97.1,48.668],[-97.0998,48.6714],[-97.1002,48.675],[-97.1003,48.6757],[-97.1008,48.6787],[-97.1011,48.6808],[-97.1003,48.6828],[-97.0985,48.683],[-97.0946,48.6822],[-97.0926,48.6821],[-97.0904,48.6828],[-97.0898,48.6841],[-97.0899,48.6852],[-97.091,48.6861],[-97.093,48.687],[-97.0951,48.6876],[-97.099,48.6884],[-97.1024,48.6893],[-97.103,48.6894],[-97.1059,48.6903],[-97.1064,48.6905],[-97.1086,48.6915],[-97.111,48.6939],[-97.113,48.6964],[-97.1148,48.6981],[-97.1182,48.7005],[-97.1198,48.7018],[-97.1201,48.7039],[-97.1194,48.7041],[-97.1182,48.7046],[-97.1143,48.7052],[-97.1117,48.7056],[-97.11,48.7063],[-97.1098,48.7083],[-97.1113,48.7094],[-97.1134,48.7101],[-97.1157,48.7105],[-97.1174,48.7111],[-97.119,48.7119],[-97.1212,48.7136],[-97.1223,48.716],[-97.1229,48.7168],[-97.1231,48.7172],[-97.1243,48.7192],[-97.1253,48.7201],[-97.1253,48.7203],[-97.126,48.7207],[-97.1263,48.7212],[-97.1272,48.7215],[-97.128,48.722],[-97.1282,48.7221],[-97.1288,48.7225],[-97.1297,48.7229],[-97.131,48.7233],[-97.1321,48.7238],[-97.1331,48.7242],[-97.1345,48.7248],[-97.136,48.7257],[-97.1369,48.7263],[-97.1375,48.727],[-97.1376,48.7274],[-97.1376,48.7278],[-97.1373,48.7283],[-97.137,48.7284],[-97.1365,48.7285],[-97.136,48.7287],[-97.1352,48.7287],[-97.1341,48.7289],[-97.1333,48.7291],[-97.1328,48.7292],[-97.132,48.7294],[-97.1312,48.7295],[-97.1308,48.7296],[-97.1299,48.7299],[-97.1294,48.7304],[-97.1288,48.7308],[-97.1286,48.7312],[-97.1286,48.7315],[-97.1286,48.7316],[-97.1286,48.7318],[-97.1285,48.7322],[-97.1286,48.7326],[-97.1286,48.7328],[-97.1287,48.7331],[-97.129,48.7335],[-97.1295,48.7339],[-97.1298,48.7341],[-97.1316,48.7347],[-97.1322,48.7348],[-97.1334,48.7347],[-97.1351,48.7345],[-97.1369,48.7345],[-97.1383,48.7345],[-97.1396,48.7347],[-97.1402,48.7349],[-97.1412,48.7354],[-97.1419,48.7359],[-97.1422,48.7367],[-97.1423,48.7372],[-97.1421,48.7381],[-97.1414,48.7385],[-97.1408,48.7387],[-97.1404,48.7389],[-97.1399,48.7393],[-97.1392,48.7397],[-97.1381,48.7408],[-97.1372,48.742],[-97.1366,48.7435],[-97.1365,48.745],[-97.1365,48.7459],[-97.1366,48.7466],[-97.1369,48.748],[-97.1375,48.7492],[-97.1379,48.75],[-97.1385,48.7504],[-97.1391,48.7507],[-97.1396,48.7508],[-97.1401,48.7509],[-97.141,48.751],[-97.142,48.751],[-97.143,48.7509],[-97.1444,48.7507],[-97.1457,48.7506],[-97.1466,48.7505],[-97.1476,48.7505],[-97.1491,48.7506],[-97.1497,48.7508],[-97.1503,48.7509],[-97.1515,48.7515],[-97.1521,48.752],[-97.153,48.7529],[-97.1539,48.7542],[-97.1545,48.7553],[-97.1547,48.7558],[-97.1548,48.7562],[-97.1548,48.7569],[-97.1548,48.7576],[-97.1546,48.758],[-97.1542,48.7587],[-97.1535,48.7593],[-97.1528,48.7598],[-97.1519,48.7601],[-97.1508,48.7605],[-97.1503,48.7606],[-97.1501,48.7607],[-97.1475,48.7616],[-97.1473,48.7617],[-97.1469,48.762],[-97.1462,48.7626],[-97.1461,48.7628],[-97.1459,48.7633],[-97.1456,48.7643],[-97.1456,48.765],[-97.146,48.7658],[-97.1476,48.7673],[-97.1487,48.7681],[-97.15,48.7692],[-97.1501,48.7693],[-97.1506,48.77],[-97.1512,48.7712],[-97.1519,48.7721],[-97.1525,48.7727],[-97.1529,48.7728],[-97.1559,48.7731],[-97.1567,48.7732],[-97.1578,48.7735],[-97.1582,48.7737],[-97.1587,48.7742],[-97.1589,48.7746],[-97.159,48.7751],[-97.159,48.7751],[-97.159,48.7754],[-97.1589,48.776],[-97.1584,48.7766],[-97.1579,48.7769],[-97.1573,48.7772],[-97.1557,48.7776],[-97.1544,48.7778],[-97.1534,48.778],[-97.1522,48.7783],[-97.1509,48.7787],[-97.1501,48.7789],[-97.1497,48.779],[-97.1483,48.7797],[-97.1477,48.7801],[-97.1473,48.7807],[-97.1472,48.7811],[-97.1473,48.7816],[-97.1478,48.7821],[-97.1486,48.7824],[-97.1495,48.7826],[-97.1501,48.7826],[-97.1503,48.7826],[-97.1513,48.7825],[-97.1533,48.7824],[-97.1547,48.7824],[-97.1559,48.7825],[-97.1571,48.7827],[-97.1583,48.783],[-97.1591,48.7834],[-97.1595,48.7838],[-97.1597,48.7843],[-97.1598,48.7848],[-97.1596,48.7853],[-97.1593,48.786],[-97.1591,48.7863],[-97.1586,48.7869],[-97.1577,48.7877],[-97.1574,48.7882],[-97.1573,48.7884],[-97.1572,48.7887],[-97.1571,48.7894],[-97.157,48.7895],[-97.157,48.7901],[-97.1572,48.7906],[-97.1575,48.7909],[-97.1581,48.7912],[-97.1586,48.7913],[-97.1592,48.7915],[-97.1595,48.7915],[-97.1611,48.7915],[-97.1618,48.7914],[-97.1645,48.7911],[-97.1648,48.7911],[-97.1657,48.7911],[-97.1664,48.7912],[-97.1672,48.7913],[-97.1714,48.7921],[-97.1718,48.7923],[-97.1721,48.7924],[-97.1731,48.7929],[-97.1737,48.7933],[-97.174,48.7937],[-97.1741,48.7942],[-97.1742,48.7947],[-97.1742,48.7951],[-97.1739,48.7954],[-97.1734,48.7958],[-97.1726,48.7963],[-97.1717,48.7966],[-97.1716,48.7966],[-97.171,48.7967],[-97.1701,48.7967],[-97.1688,48.7966],[-97.1673,48.7964],[-97.1665,48.7962],[-97.1654,48.7962],[-97.1648,48.7962],[-97.1638,48.7963],[-97.1631,48.7966],[-97.1625,48.7969],[-97.162,48.7974],[-97.1617,48.7979],[-97.1617,48.7984],[-97.1619,48.7988],[-97.1621,48.7994],[-97.1626,48.8001],[-97.1633,48.8007],[-97.1642,48.8011],[-97.1652,48.8014],[-97.166,48.8015],[-97.1668,48.8016],[-97.1675,48.8016],[-97.1685,48.8016],[-97.1698,48.8013],[-97.1706,48.8011],[-97.1714,48.8008],[-97.1715,48.8008],[-97.1724,48.8004],[-97.1731,48.8],[-97.1742,48.7992],[-97.175,48.7986],[-97.1754,48.7983],[-97.1757,48.798],[-97.1761,48.7977],[-97.1768,48.7974],[-97.1773,48.7973],[-97.1779,48.7972],[-97.1787,48.7972],[-97.1795,48.7972],[-97.1801,48.7973],[-97.1807,48.7975],[-97.1811,48.7978],[-97.1815,48.7982],[-97.1816,48.7986],[-97.1817,48.7991],[-97.1815,48.7995],[-97.1813,48.8],[-97.1808,48.8004],[-97.1801,48.8008],[-97.1791,48.8012],[-97.1779,48.8015],[-97.1769,48.8017],[-97.1764,48.8018],[-97.1756,48.8021],[-97.1748,48.8023],[-97.1725,48.8032],[-97.1713,48.8036],[-97.171,48.8037],[-97.1706,48.8039],[-97.1694,48.8043],[-97.1682,48.8046],[-97.1675,48.8048],[-97.1666,48.805],[-97.1655,48.8052],[-97.1638,48.8055],[-97.161,48.8059],[-97.1605,48.8061],[-97.1597,48.8064],[-97.159,48.8067],[-97.1583,48.8072],[-97.1579,48.8077],[-97.1577,48.8082],[-97.1576,48.8089],[-97.1578,48.8098],[-97.158,48.8104],[-97.1586,48.811],[-97.159,48.8111],[-97.161,48.8117],[-97.1617,48.8119],[-97.1625,48.812],[-97.1636,48.8121],[-97.1644,48.8121],[-97.1651,48.812],[-97.1666,48.8118],[-97.168,48.8116],[-97.169,48.8114],[-97.17,48.8114],[-97.1713,48.8115],[-97.1715,48.8115],[-97.1726,48.8117],[-97.1731,48.8118],[-97.174,48.8122],[-97.1761,48.8132],[-97.1776,48.8141],[-97.1784,48.8145],[-97.1797,48.8149],[-97.1807,48.8151],[-97.1821,48.8153],[-97.1828,48.8153],[-97.184,48.8152],[-97.1848,48.8151],[-97.186,48.8147],[-97.1868,48.8145],[-97.1873,48.8143],[-97.1879,48.8143],[-97.1883,48.8143],[-97.1889,48.8143],[-97.1894,48.8144],[-97.1898,48.8146],[-97.1901,48.8148],[-97.1903,48.8153],[-97.1904,48.8156],[-97.1903,48.8159],[-97.19,48.8163],[-97.1893,48.8167],[-97.1885,48.8171],[-97.1879,48.8173],[-97.1866,48.8176],[-97.1857,48.8177],[-97.1847,48.8179],[-97.184,48.8181],[-97.1833,48.8184],[-97.1817,48.8189],[-97.1809,48.8193],[-97.1801,48.8199],[-97.1793,48.8207],[-97.1787,48.8216],[-97.178,48.8232],[-97.1777,48.824],[-97.1776,48.8245],[-97.1777,48.8249],[-97.178,48.8255],[-97.1782,48.8258],[-97.1786,48.8262],[-97.1794,48.8268],[-97.1822,48.8288],[-97.1837,48.8299],[-97.1841,48.8304],[-97.1847,48.8314],[-97.1848,48.8319],[-97.1849,48.8326],[-97.1849,48.8327],[-97.1848,48.833],[-97.1846,48.8336],[-97.1842,48.8341],[-97.1837,48.8345],[-97.183,48.8348],[-97.1822,48.835],[-97.1813,48.8351],[-97.1799,48.8352],[-97.1783,48.8353],[-97.1779,48.8354],[-97.1772,48.8356],[-97.1757,48.8362],[-97.1753,48.8364],[-97.1747,48.8369],[-97.1742,48.8373],[-97.1739,48.8378],[-97.1738,48.8384],[-97.1738,48.839],[-97.1739,48.8406],[-97.1743,48.8427],[-97.1747,48.8438],[-97.175,48.8442],[-97.1755,48.8447],[-97.1761,48.8452],[-97.1767,48.8455],[-97.1771,48.8456],[-97.1779,48.8458],[-97.1795,48.8459],[-97.1808,48.846],[-97.1817,48.8462],[-97.1823,48.8464],[-97.1827,48.8468],[-97.1829,48.847],[-97.1829,48.8471],[-97.1829,48.8473],[-97.1826,48.8476],[-97.1821,48.8479],[-97.1816,48.848],[-97.1809,48.8481],[-97.1793,48.8482],[-97.178,48.8483],[-97.1767,48.8484],[-97.1759,48.8486],[-97.1753,48.8487],[-97.1747,48.849],[-97.1742,48.8493],[-97.1737,48.8497],[-97.1733,48.8502],[-97.173,48.8506],[-97.173,48.8508],[-97.173,48.8511],[-97.173,48.8516],[-97.1732,48.8522],[-97.1737,48.8527],[-97.1746,48.8534],[-97.1771,48.855],[-97.1784,48.8561],[-97.1786,48.8563],[-97.179,48.8569],[-97.1793,48.8576],[-97.1794,48.8583],[-97.1794,48.859],[-97.1792,48.8606],[-97.179,48.8615],[-97.179,48.862],[-97.1791,48.8626],[-97.1794,48.863],[-97.1801,48.8636],[-97.1811,48.864],[-97.1818,48.8641],[-97.1827,48.8641],[-97.1839,48.864],[-97.1855,48.8637],[-97.1871,48.8633],[-97.1877,48.8631],[-97.1883,48.8631],[-97.1891,48.8631],[-97.1896,48.8633],[-97.19,48.8635],[-97.1903,48.8639],[-97.1905,48.8644],[-97.1905,48.8648],[-97.1904,48.8651],[-97.1901,48.8657],[-97.1899,48.8661],[-97.1895,48.8665],[-97.189,48.867],[-97.1884,48.8675],[-97.1851,48.8694],[-97.1813,48.8718],[-97.1788,48.8736],[-97.1785,48.8738],[-97.1782,48.8741],[-97.1781,48.8743],[-97.1779,48.8745],[-97.1778,48.8747],[-97.1777,48.8749],[-97.1777,48.875],[-97.1778,48.875],[-97.1778,48.8754],[-97.1779,48.8757],[-97.1782,48.8761],[-97.1786,48.8765],[-97.1792,48.8769],[-97.1798,48.8771],[-97.1808,48.8772],[-97.1823,48.8772],[-97.1852,48.8768],[-97.1869,48.8765],[-97.1881,48.8765],[-97.1891,48.8766],[-97.1904,48.8769],[-97.1933,48.8779],[-97.1944,48.8783],[-97.1957,48.8788],[-97.1972,48.8794],[-97.1981,48.8799],[-97.1988,48.8805],[-97.1995,48.8812],[-97.1999,48.8818],[-97.1999,48.8821],[-97.2,48.8827],[-97.1998,48.8832],[-97.1997,48.8836],[-97.199,48.8845],[-97.1978,48.8859],[-97.1975,48.8865],[-97.1974,48.8868],[-97.1973,48.8872],[-97.1973,48.8874],[-97.1974,48.8877],[-97.1975,48.8881],[-97.1983,48.8889],[-97.2002,48.8903],[-97.2004,48.8904],[-97.2009,48.8908],[-97.2014,48.8912],[-97.2017,48.8915],[-97.2017,48.8919],[-97.2016,48.8922],[-97.2013,48.8925],[-97.201,48.8926],[-97.2001,48.8926],[-97.1994,48.8926],[-97.1985,48.8925],[-97.198,48.8924],[-97.1973,48.892],[-97.1957,48.8916],[-97.1946,48.8915],[-97.1944,48.8914],[-97.1937,48.8914],[-97.1927,48.8915],[-97.1921,48.8917],[-97.1916,48.8919],[-97.1905,48.8926],[-97.1901,48.8932],[-97.1898,48.8938],[-97.1897,48.8944],[-97.1897,48.8947],[-97.1898,48.8951],[-97.1899,48.8954],[-97.1903,48.896],[-97.1911,48.8967],[-97.1919,48.8974],[-97.1925,48.8979],[-97.1935,48.8985],[-97.1941,48.8988],[-97.1945,48.8989],[-97.1966,48.8997],[-97.1992,48.9004],[-97.2009,48.9009],[-97.2022,48.9013],[-97.2048,48.9018],[-97.2055,48.902],[-97.207,48.9025],[-97.2076,48.9027],[-97.2082,48.9029],[-97.2088,48.9032],[-97.2093,48.9036],[-97.21,48.904],[-97.2105,48.9044],[-97.211,48.905],[-97.2114,48.9056],[-97.2122,48.9069],[-97.2125,48.9075],[-97.2127,48.9082],[-97.2127,48.909],[-97.2125,48.9099],[-97.212,48.911],[-97.2116,48.9121],[-97.2111,48.913],[-97.2108,48.914],[-97.2106,48.9148],[-97.2106,48.9153],[-97.2109,48.9162],[-97.2111,48.9167],[-97.2115,48.9172],[-97.2118,48.9175],[-97.2122,48.9177],[-97.2129,48.9181],[-97.2149,48.9187],[-97.2163,48.9191],[-97.2164,48.9191],[-97.2171,48.9194],[-97.2179,48.9198],[-97.2189,48.9205],[-97.2196,48.9215],[-97.2198,48.9222],[-97.2199,48.923],[-97.2197,48.9237],[-97.2191,48.9249],[-97.2183,48.9262],[-97.2172,48.9277],[-97.2163,48.9286],[-97.2159,48.9289],[-97.2149,48.9301],[-97.2146,48.9304],[-97.2145,48.9307],[-97.2144,48.931],[-97.2145,48.9314],[-97.2145,48.9316],[-97.2148,48.9319],[-97.2154,48.9325],[-97.2159,48.9327],[-97.2162,48.9328],[-97.217,48.9328],[-97.2181,48.9327],[-97.2198,48.9325],[-97.2208,48.9325],[-97.2214,48.9325],[-97.2218,48.9326],[-97.2237,48.9332],[-97.2245,48.9337],[-97.2249,48.9339],[-97.225,48.934],[-97.2252,48.9342],[-97.2254,48.9345],[-97.2257,48.9349],[-97.226,48.9353],[-97.2263,48.936],[-97.2267,48.9376],[-97.227,48.9389],[-97.2271,48.9398],[-97.2271,48.941],[-97.227,48.9418],[-97.2266,48.9432],[-97.2264,48.9441],[-97.2263,48.9445],[-97.2264,48.9452],[-97.2265,48.9456],[-97.227,48.9462],[-97.2273,48.9465],[-97.2276,48.9467],[-97.2279,48.9467],[-97.2284,48.9468],[-97.2304,48.9465],[-97.2309,48.9464],[-97.2313,48.9464],[-97.2326,48.9466],[-97.2331,48.9468],[-97.2338,48.9471],[-97.2342,48.9474],[-97.2343,48.948],[-97.2343,48.9485],[-97.2342,48.9488],[-97.2341,48.9491],[-97.2337,48.95],[-97.2332,48.951],[-97.2328,48.9524],[-97.2323,48.954],[-97.2317,48.9558],[-97.2313,48.9568],[-97.2309,48.9578],[-97.2305,48.9585],[-97.23,48.9591],[-97.2288,48.9603],[-97.2282,48.9609],[-97.2278,48.9613],[-97.2276,48.9619],[-97.2276,48.9624],[-97.2279,48.963],[-97.228,48.9631],[-97.2283,48.9634],[-97.2289,48.9639],[-97.2294,48.9641],[-97.23,48.9642],[-97.2323,48.9646],[-97.2355,48.965],[-97.2368,48.9652],[-97.2375,48.9654],[-97.2382,48.966],[-97.2383,48.9661],[-97.2388,48.9666],[-97.2391,48.9676],[-97.2392,48.9687],[-97.239,48.9696],[-97.2387,48.9706],[-97.2383,48.9715],[-97.2381,48.9723],[-97.238,48.9725],[-97.2379,48.9731],[-97.2378,48.9734],[-97.2378,48.9738],[-97.238,48.9752],[-97.238,48.9763],[-97.2381,48.9771],[-97.238,48.9771],[-97.238,48.9841],[-97.2377,48.9849],[-97.2372,48.9857],[-97.2365,48.9867],[-97.2359,48.9874],[-97.2351,48.9881],[-97.2342,48.989],[-97.2335,48.9895],[-97.2331,48.9898],[-97.2317,48.9904],[-97.2301,48.9911],[-97.2293,48.9914],[-97.229,48.9916],[-97.2279,48.9921],[-97.2274,48.9925],[-97.227,48.9929],[-97.2266,48.9933],[-97.2265,48.9938],[-97.2267,48.9941],[-97.227,48.9945],[-97.2273,48.9947],[-97.2287,48.9949],[-97.2304,48.995],[-97.2317,48.9951],[-97.2324,48.9952],[-97.2335,48.9956],[-97.2338,48.9959],[-97.2341,48.9966],[-97.2341,48.997],[-97.234,48.9975],[-97.2337,48.9981],[-97.2332,48.9985],[-97.2323,48.999],[-97.2305,49.0],[-97.2303,49.0001],[-97.2295,49.0005],[-97.2175,49.0005],[-97.2161,49.0005],[-97.2078,49.0005],[-97.2069,49.0005],[-97.1955,49.0005],[-97.1939,49.0005],[-97.1739,49.0005],[-97.1724,49.0005],[-97.1514,49.0005],[-97.1502,49.0005],[-97.1294,49.0004],[-97.1277,49.0004],[-97.1073,49.0004],[-97.1061,49.0004],[-97.0853,49.0004],[-97.084,49.0004],[-97.0633,49.0004],[-97.062,49.0004],[-97.0412,49.0004],[-97.0401,49.0004],[-97.0192,49.0004],[-97.0183,49.0004],[-96.9971,49.0004],[-96.9961,49.0004],[-96.9751,49.0003],[-96.9738,49.0003],[-96.953,49.0003],[-96.9518,49.0003],[-96.931,49.0003],[-96.9299,49.0003],[-96.909,49.0003],[-96.9078,49.0003],[-96.8869,49.0003],[-96.8856,49.0003],[-96.8649,49.0003],[-96.864,49.0003],[-96.8429,49.0003],[-96.8415,49.0003],[-96.8208,49.0003],[-96.8197,49.0003],[-96.8023,49.0002],[-96.8005,49.0002],[-96.8003,49.0002],[-96.7988,49.0002],[-96.7787,49.0002],[-96.7768,49.0002],[-96.7567,49.0002],[-96.7547,49.0002],[-96.7348,49.0002],[-96.7327,49.0002],[-96.7127,49.0002],[-96.7107,49.0002],[-96.6905,49.0002],[-96.6886,49.0002],[-96.6695,49.0002],[-96.6665,49.0002],[-96.6482,49.0002],[-96.6445,49.0002],[-96.6243,49.0002],[-96.6225,49.0002],[-96.6021,49.0002],[-96.6004,49.0002],[-96.58,49.0002],[-96.5784,49.0002],[-96.558,49.0002],[-96.5563,49.0002],[-96.536,49.0002],[-96.5342,49.0002],[-96.5154,49.0002],[-96.5123,49.0002],[-96.4933,49.0002],[-96.49,49.0002],[-96.471,49.0001],[-96.4664,49.0001],[-96.4496,49.0001],[-96.4492,49.0001],[-96.4491,49.0001],[-96.446,49.0001],[-96.4273,49.0001],[-96.4224,49.0001],[-96.4054,49.0001]]],"type":"Polygon"},"id":"35","properties":{"Area":2862183702.23055,"CTYONLY_":3,"Code":"KITT","LASTMOD":"1999-12-31T23:59:59Z","Name":"Kittson","Perimiter":263017.48277},"type":"Feature"},{"geometry":{"coordinates":[[[-96.4054,49.0001],[-96.4019,49.0001],[-96.3825,49.0001],[-96.3783,49.0001],[-96.3606,49.0001],[-96.3579,49.0001],[-96.3385,49.0001],[-96.3343,49.0001],[-96.3166,49.0001],[-96.3138,49.0001],[-96.2945,49.0001],[-96.2902,49.0001],[-96.2725,49.0001],[-96.2698,49.0001],[-96.2494,49.0001],[-96.2461,49.0001],[-96.2274,49.0001],[-96.2257,49.0001],[-96.2057,49.0001],[-96.2021,49.0001],[-96.1837,49.0],[-96.18,49.0],[-96.1617,49.0],[-96.1579,49.0],[-96.1401,49.0],[-96.1359,49.0],[-96.1176,49.0],[-96.1139,49.0],[-96.0957,49.0],[-96.0919,49.0],[-96.0738,49.0],[-96.07,49.0],[-96.0517,49.0],[-96.048,49.0],[-96.0298,49.0],[-96.026,49.0],[-96.0083,49.0],[-96.0045,49.0],[-95.9868,49.0],[-95.9784,49.0],[-95.9776,49.0],[-95.9755,49.0],[-95.9648,48.9999],[-95.9464,48.9999],[-95.943,48.9999],[-95.9225,48.9999],[-95.9211,48.9999],[-95.899,48.9998],[-95.883,48.9998],[-95.8771,48.9998],[-95.8564,48.9998],[-95.855,48.9998],[-95.8342,48.9998],[-95.8184,48.9997],[-95.8126,48.9997],[-95.7906,48.9997],[-95.7833,48.9997],[-95.7684,48.9997],[-95.7479,48.9996],[-95.7466,48.9996],[-95.7253,48.9996],[-95.7066,48.9996],[-95.7032,48.9996],[-95.681,48.9995],[-95.6654,48.9995],[-95.6596,48.9995],[-95.659,48.9995],[-95.6401,48.9995],[-95.6369,48.9995],[-95.6205,48.9994],[-95.615,48.9994],[-95.5948,48.9994],[-95.585,48.9994],[-95.573,48.9994],[-95.551,48.9993],[-95.5495,48.9993],[-95.5294,48.9993],[-95.5164,48.9993],[-95.5072,48.9993],[-95.4849,48.9992],[-95.4834,48.9992],[-95.4635,48.9992],[-95.4508,48.9992],[-95.4418,48.9992],[-95.4245,48.9991],[-95.4197,48.9991],[-95.3977,48.9991],[-95.3953,48.9991],[-95.3765,48.9991],[-95.3759,48.9991],[-95.3753,48.9991],[-95.3542,48.999],[-95.3513,48.999],[-95.3326,48.999],[-95.3286,48.999],[-95.3231,48.999],[-95.3224,48.9984],[-95.3204,48.9976],[-95.3202,48.9973],[-95.3204,48.9964],[-95.3206,48.9961],[-95.3201,48.9956],[-95.3197,48.9954],[-95.3191,48.9953],[-95.3187,48.9956],[-95.3182,48.996],[-95.3179,48.9961],[-95.3178,48.9961],[-95.3178,48.9958],[-95.3181,48.995],[-95.3191,48.9941],[-95.3204,48.9924],[-95.3206,48.9921],[-95.3224,48.9889],[-95.3227,48.9884],[-95.3242,48.9859],[-95.3245,48.985],[-95.3253,48.9832],[-95.3257,48.9814],[-95.3256,48.98],[-95.3255,48.9789],[-95.3257,48.9784],[-95.3253,48.976],[-95.325,48.9743],[-95.3249,48.9738],[-95.3248,48.9728],[-95.3247,48.972],[-95.3241,48.9703],[-95.3232,48.9692],[-95.3227,48.9685],[-95.3212,48.9672],[-95.3207,48.9669],[-95.3201,48.9648],[-95.3198,48.9643],[-95.3193,48.964],[-95.3193,48.9622],[-95.3202,48.9606],[-95.3206,48.9598],[-95.3206,48.9595],[-95.3206,48.959],[-95.3202,48.9581],[-95.3191,48.9569],[-95.3188,48.9562],[-95.3179,48.9559],[-95.3175,48.9552],[-95.3177,48.9545],[-95.3182,48.9535],[-95.3181,48.9531],[-95.3177,48.9525],[-95.3154,48.9513],[-95.3151,48.951],[-95.3141,48.9508],[-95.3131,48.9503],[-95.3125,48.9503],[-95.3123,48.9502],[-95.3119,48.9502],[-95.3119,48.9507],[-95.3129,48.9521],[-95.3129,48.9523],[-95.3126,48.9524],[-95.312,48.9524],[-95.3115,48.952],[-95.3108,48.9512],[-95.3104,48.951],[-95.3097,48.951],[-95.3089,48.9511],[-95.3079,48.9509],[-95.3061,48.9502],[-95.3052,48.9495],[-95.3046,48.9482],[-95.3046,48.947],[-95.305,48.9462],[-95.3053,48.9459],[-95.3061,48.9454],[-95.3068,48.9454],[-95.3069,48.9455],[-95.3069,48.9456],[-95.3063,48.9462],[-95.3062,48.9463],[-95.3061,48.9469],[-95.3062,48.9472],[-95.3062,48.9472],[-95.3071,48.9477],[-95.3081,48.948],[-95.3094,48.9481],[-95.3096,48.9482],[-95.3099,48.9484],[-95.31,48.9485],[-95.3103,48.9485],[-95.3104,48.9484],[-95.3103,48.948],[-95.3096,48.9478],[-95.3092,48.9477],[-95.3079,48.9474],[-95.3071,48.9469],[-95.3071,48.9466],[-95.3074,48.9465],[-95.3078,48.9466],[-95.3085,48.947],[-95.3086,48.9469],[-95.3086,48.9465],[-95.3088,48.9464],[-95.3095,48.9463],[-95.3102,48.9463],[-95.3114,48.9461],[-95.3131,48.946],[-95.3141,48.9457],[-95.3148,48.9452],[-95.3154,48.9448],[-95.3168,48.9431],[-95.3181,48.9421],[-95.3189,48.9419],[-95.3219,48.9412],[-95.3225,48.9409],[-95.3228,48.9403],[-95.3231,48.9389],[-95.3229,48.9373],[-95.3225,48.9358],[-95.3223,48.9355],[-95.3228,48.9344],[-95.3222,48.9327],[-95.3209,48.9307],[-95.3208,48.9305],[-95.3195,48.9285],[-95.3168,48.9245],[-95.315,48.9222],[-95.3141,48.921],[-95.3132,48.9198],[-95.3126,48.919],[-95.3119,48.9178],[-95.3115,48.9172],[-95.3109,48.9163],[-95.3102,48.9155],[-95.3093,48.9149],[-95.3092,48.9149],[-95.3085,48.9146],[-95.3078,48.9141],[-95.3074,48.9135],[-95.3064,48.9129],[-95.3061,48.9128],[-95.3059,48.9127],[-95.3043,48.9119],[-95.3038,48.9114],[-95.3027,48.91],[-95.3017,48.9093],[-95.2999,48.9086],[-95.2978,48.9083],[-95.2973,48.9081],[-95.2973,48.908],[-95.2973,48.9077],[-95.2976,48.9074],[-95.2977,48.9073],[-95.2978,48.9073],[-95.2978,48.9072],[-95.2978,48.9072],[-95.2979,48.9072],[-95.2979,48.9072],[-95.2979,48.9071],[-95.298,48.9071],[-95.298,48.9071],[-95.298,48.9071],[-95.2981,48.907],[-95.2982,48.9068],[-95.2983,48.9068],[-95.2985,48.9065],[-95.2985,48.9064],[-95.2986,48.9063],[-95.2988,48.906],[-95.2989,48.906],[-95.2991,48.9057],[-95.2992,48.9055],[-95.2994,48.9053],[-95.2996,48.9051],[-95.2997,48.905],[-95.2999,48.9048],[-95.2999,48.9048],[-95.2999,48.9048],[-95.3,48.9047],[-95.3,48.9047],[-95.3001,48.9047],[-95.3001,48.9046],[-95.3002,48.9045],[-95.3005,48.904],[-95.2993,48.9035],[-95.2983,48.9028],[-95.298,48.9027],[-95.2976,48.9026],[-95.2967,48.9027],[-95.2949,48.9028],[-95.2941,48.9027],[-95.2937,48.9023],[-95.2935,48.902],[-95.2927,48.9019],[-95.2914,48.9019],[-95.2909,48.9017],[-95.2908,48.9016],[-95.2907,48.9014],[-95.2906,48.9011],[-95.2911,48.9008],[-95.2911,48.9006],[-95.2901,48.9003],[-95.2896,48.9],[-95.289,48.8994],[-95.2882,48.8981],[-95.2879,48.8979],[-95.2872,48.8977],[-95.287,48.8976],[-95.2865,48.8975],[-95.2861,48.8976],[-95.2853,48.8977],[-95.2839,48.8975],[-95.2813,48.8967],[-95.2803,48.8965],[-95.2796,48.8962],[-95.279,48.8957],[-95.2782,48.8956],[-95.2773,48.8957],[-95.277,48.8958],[-95.2765,48.8962],[-95.2763,48.8963],[-95.2759,48.8962],[-95.2755,48.8959],[-95.2749,48.8956],[-95.2748,48.8951],[-95.2753,48.8943],[-95.2751,48.8938],[-95.2745,48.8931],[-95.2724,48.8921],[-95.2713,48.8915],[-95.268,48.8905],[-95.2677,48.8903],[-95.2674,48.89],[-95.2666,48.8894],[-95.2654,48.8888],[-95.265,48.8886],[-95.2646,48.8885],[-95.2639,48.8883],[-95.2635,48.888],[-95.2627,48.8877],[-95.2585,48.8867],[-95.2585,48.8867],[-95.257,48.8858],[-95.256,48.885],[-95.2548,48.8845],[-95.2517,48.8839],[-95.2507,48.8836],[-95.2502,48.8835],[-95.2496,48.8834],[-95.2485,48.8832],[-95.248,48.8836],[-95.2472,48.8835],[-95.2458,48.8829],[-95.2439,48.8823],[-95.2429,48.8822],[-95.2429,48.8822],[-95.2423,48.8821],[-95.2407,48.8821],[-95.2391,48.8819],[-95.2381,48.8817],[-95.2356,48.8815],[-95.2335,48.8814],[-95.231,48.8814],[-95.2287,48.8815],[-95.2265,48.8816],[-95.2252,48.8819],[-95.2212,48.883],[-95.2208,48.8831],[-95.2207,48.8831],[-95.22,48.8831],[-95.2193,48.8832],[-95.2188,48.8835],[-95.217,48.8835],[-95.2159,48.8839],[-95.2151,48.884],[-95.2144,48.8843],[-95.2122,48.8842],[-95.2117,48.8847],[-95.2115,48.8847],[-95.2112,48.8848],[-95.2085,48.8846],[-95.2059,48.8848],[-95.2024,48.8852],[-95.2009,48.8855],[-95.2005,48.8856],[-95.1986,48.8855],[-95.1956,48.8862],[-95.1924,48.8865],[-95.1919,48.8866],[-95.1913,48.8868],[-95.1901,48.887],[-95.1889,48.8873],[-95.1877,48.8874],[-95.1863,48.8877],[-95.1851,48.8882],[-95.1819,48.8888],[-95.1797,48.889],[-95.1791,48.889],[-95.1764,48.8893],[-95.173,48.8897],[-95.1701,48.8902],[-95.1674,48.8907],[-95.1648,48.8913],[-95.1641,48.8917],[-95.1618,48.892],[-95.1602,48.892],[-95.1579,48.8919],[-95.1564,48.8919],[-95.1555,48.892],[-95.1528,48.8921],[-95.1508,48.8922],[-95.1483,48.8923],[-95.1469,48.8927],[-95.1459,48.8929],[-95.1438,48.8934],[-95.1436,48.8937],[-95.1404,48.8943],[-95.1381,48.8949],[-95.1355,48.8959],[-95.1351,48.8963],[-95.1348,48.8963],[-95.1343,48.8963],[-95.1337,48.8969],[-95.1322,48.8973],[-95.1312,48.8975],[-95.1252,48.8998],[-95.1239,48.9001],[-95.1233,48.9004],[-95.1228,48.9006],[-95.1214,48.9013],[-95.121,48.9016],[-95.1205,48.9017],[-95.1204,48.9019],[-95.1182,48.9029],[-95.1163,48.9037],[-95.1151,48.9046],[-95.1144,48.9052],[-95.114,48.9061],[-95.1141,48.9064],[-95.1137,48.9069],[-95.1132,48.9071],[-95.113,48.9072],[-95.1126,48.9073],[-95.1107,48.9082],[-95.1096,48.9089],[-95.108,48.9099],[-95.1056,48.9113],[-95.1042,48.9121],[-95.1032,48.9127],[-95.102,48.9132],[-95.1008,48.9142],[-95.0981,48.9159],[-95.098,48.916],[-95.0975,48.9164],[-95.0971,48.9172],[-95.097,48.9176],[-95.0961,48.9181],[-95.0946,48.9191],[-95.0944,48.9193],[-95.0927,48.9204],[-95.0919,48.9207],[-95.0914,48.9208],[-95.0914,48.916],[-95.0912,48.9014],[-95.0911,48.8869],[-95.0908,48.8724],[-95.0908,48.858],[-95.0907,48.8436],[-95.0908,48.8291],[-95.0909,48.8147],[-95.0903,48.8],[-95.0903,48.7855],[-95.0903,48.7711],[-95.0901,48.7566],[-95.0901,48.7421],[-95.0899,48.7277],[-95.0898,48.713],[-95.1046,48.7129],[-95.1104,48.7129],[-95.1119,48.7129],[-95.1259,48.7129],[-95.1297,48.713],[-95.1333,48.713],[-95.1477,48.7129],[-95.1554,48.7129],[-95.1697,48.7129],[-95.1773,48.713],[-95.1917,48.713],[-95.1991,48.713],[-95.2112,48.713],[-95.2206,48.713],[-95.2331,48.713],[-95.2427,48.713],[-95.255,48.713],[-95.2645,48.713],[-95.2656,48.713],[-95.2767,48.713],[-95.2866,48.713],[-95.299,48.713],[-95.3051,48.713],[-95.3084,48.713],[-95.3205,48.713],[-95.3302,48.713],[-95.3425,48.7131],[-95.3425,48.6995],[-95.3424,48.6849],[-95.3423,48.6705],[-95.3424,48.6561],[-95.3425,48.6415],[-95.3426,48.6271],[-95.3424,48.6127],[-95.3426,48.5979],[-95.3423,48.5836],[-95.3423,48.5691],[-95.3424,48.5548],[-95.3425,48.5402],[-95.3628,48.5404],[-95.364,48.5403],[-95.3844,48.5402],[-95.386,48.5402],[-95.4061,48.5402],[-95.4078,48.5402],[-95.4279,48.54],[-95.4297,48.5399],[-95.4494,48.5399],[-95.4513,48.5399],[-95.4712,48.5396],[-95.4726,48.5396],[-95.493,48.5392],[-95.495,48.5392],[-95.5143,48.539],[-95.5163,48.539],[-95.5365,48.5389],[-95.5383,48.5389],[-95.558,48.5388],[-95.5603,48.5388],[-95.5801,48.5387],[-95.5821,48.5387],[-95.6023,48.5389],[-95.6232,48.5391],[-95.6447,48.5393],[-95.6666,48.5394],[-95.6886,48.5395],[-95.7102,48.5395],[-95.7322,48.54],[-95.7539,48.5404],[-95.7758,48.5406],[-95.7976,48.5405],[-95.8192,48.5404],[-95.8411,48.5406],[-95.8621,48.5414],[-95.8829,48.5419],[-95.8851,48.542],[-95.8986,48.5421],[-95.9046,48.5422],[-95.9064,48.5422],[-95.9269,48.5421],[-95.9486,48.5425],[-95.9498,48.5425],[-95.9704,48.543],[-95.9936,48.5435],[-96.0157,48.5437],[-96.0374,48.5438],[-96.0592,48.5437],[-96.0812,48.5436],[-96.1026,48.5438],[-96.1264,48.5439],[-96.1486,48.5442],[-96.1702,48.5445],[-96.1921,48.5446],[-96.2141,48.5449],[-96.2358,48.5452],[-96.2576,48.545],[-96.2794,48.5449],[-96.301,48.5448],[-96.3231,48.5446],[-96.3448,48.5444],[-96.3667,48.5443],[-96.3882,48.5442],[-96.3879,48.5588],[-96.3882,48.5733],[-96.3884,48.5877],[-96.3891,48.6024],[-96.389,48.6165],[-96.388,48.6313],[-96.3879,48.6454],[-96.3877,48.6599],[-96.3871,48.6741],[-96.3874,48.6887],[-96.3866,48.703],[-96.3873,48.7172],[-96.388,48.7172],[-96.4049,48.7172],[-96.4048,48.7318],[-96.4048,48.7465],[-96.4047,48.7607],[-96.4045,48.7758],[-96.4042,48.7903],[-96.4042,48.8048],[-96.4042,48.8198],[-96.4043,48.8343],[-96.4045,48.8491],[-96.4047,48.8635],[-96.405,48.878],[-96.405,48.8926],[-96.4053,48.9068],[-96.4053,48.9081],[-96.4053,48.9137],[-96.4054,48.9214],[-96.4054,48.9225],[-96.4053,48.936],[-96.4053,48.9371],[-96.4053,48.9504],[-96.4053,48.9515],[-96.4053,48.9648],[-96.4053,48.9658],[-96.4053,48.9705],[-96.4054,48.9793],[-96.4054,48.9803],[-96.4054,48.994],[-96.4054,48.9947],[-96.4054,49.0001]]],"type":"Polygon"},"id":"68","properties":{"Area":4347098503.12714,"CTYONLY_":4,"Code":"ROSE","LASTMOD":"2001-04-12T09:32:44Z","Name":"Roseau","Perimiter":302590.75293},"type":"Feature"},{"geometry":{"coordinates":[[[-94.4299,48.7012],[-94.4241,48.7053],[-94.4213,48.7086],[-94.4189,48.7103],[-94.4158,48.711],[-94.4081,48.7106],[-94.406,48.7105],[-94.3889,48.712],[-94.3859,48.7119],[-94.384,48.7119],[-94.3801,48.7111],[-94.3687,48.7065],[-94.3646,48.7059],[-94.3533,48.7042],[-94.3431,48.7035],[-94.3429,48.7035],[-94.3287,48.7045],[-94.3214,48.7067],[-94.3088,48.7103],[-94.2995,48.709],[-94.2911,48.7079],[-94.2829,48.7057],[-94.2781,48.7024],[-94.2745,48.6999],[-94.2694,48.6995],[-94.2644,48.699],[-94.261,48.6966],[-94.258,48.6918],[-94.2565,48.6901],[-94.2529,48.6864],[-94.2521,48.685],[-94.2514,48.6837],[-94.2507,48.6782],[-94.2527,48.6707],[-94.253,48.6693],[-94.2548,48.664],[-94.2546,48.6615],[-94.2509,48.657],[-94.2499,48.6563],[-94.2467,48.6542],[-94.2445,48.6535],[-94.2343,48.6524],[-94.2335,48.6524],[-94.2242,48.6495],[-94.2144,48.6494],[-94.2124,48.6496],[-94.1996,48.651],[-94.1915,48.6506],[-94.1886,48.6504],[-94.1689,48.6483],[-94.1678,48.6482],[-94.1574,48.6458],[-94.1522,48.6455],[-94.1458,48.6458],[-94.1391,48.646],[-94.126,48.6444],[-94.1235,48.6444],[-94.11,48.6443],[-94.1023,48.6455],[-94.0999,48.6459],[-94.0912,48.6437],[-94.0849,48.6441],[-94.0804,48.6442],[-94.0767,48.6442],[-94.0714,48.6459],[-94.0658,48.6462],[-94.0642,48.6438],[-94.0603,48.6431],[-94.0581,48.6434],[-94.0525,48.644],[-94.0432,48.6435],[-94.0393,48.6423],[-94.0364,48.6413],[-94.0356,48.6411],[-94.0295,48.6409],[-94.0153,48.6424],[-94.0069,48.6433],[-94.0007,48.6428],[-93.9931,48.6412],[-93.9897,48.6405],[-93.984,48.6401],[-93.9777,48.6385],[-93.9712,48.6385],[-93.968,48.6385],[-93.9596,48.6372],[-93.953,48.6341],[-93.9497,48.6339],[-93.934,48.6326],[-93.9272,48.6327],[-93.9169,48.6329],[-93.9134,48.6353],[-93.9057,48.6346],[-93.9054,48.6345],[-93.8948,48.6324],[-93.8853,48.6318],[-93.8844,48.6318],[-93.8757,48.6319],[-93.8698,48.6311],[-93.8624,48.631],[-93.848,48.6308],[-93.8443,48.6303],[-93.8404,48.6289],[-93.8393,48.6286],[-93.8365,48.6276],[-93.8334,48.6256],[-93.8292,48.6177],[-93.825,48.6136],[-93.8245,48.613],[-93.8214,48.6092],[-93.8182,48.5994],[-93.8175,48.597],[-93.8172,48.5964],[-93.813,48.588],[-93.8103,48.5846],[-93.8063,48.5796],[-93.8041,48.5703],[-93.8041,48.5702],[-93.8051,48.5644],[-93.808,48.5569],[-93.8088,48.5555],[-93.8119,48.5503],[-93.8102,48.5445],[-93.8109,48.5412],[-93.8109,48.541],[-93.818,48.535],[-93.818,48.5346],[-93.8184,48.5315],[-93.8178,48.5306],[-93.8161,48.5285],[-93.8145,48.5273],[-93.8111,48.5247],[-93.803,48.522],[-93.7964,48.5182],[-93.7933,48.5164],[-93.7879,48.5159],[-93.7745,48.5162],[-93.768,48.5164],[-93.7665,48.5164],[-93.7617,48.5166],[-93.7534,48.5158],[-93.7442,48.5175],[-93.739,48.5185],[-93.731,48.5185],[-93.7225,48.5178],[-93.7206,48.5176],[-93.7108,48.5186],[-93.7061,48.5182],[-93.7006,48.517],[-93.693,48.5152],[-93.6866,48.5154],[-93.6791,48.5167],[-93.6778,48.5169],[-93.6593,48.5165],[-93.657,48.5167],[-93.6473,48.5177],[-93.6433,48.519],[-93.6421,48.5199],[-93.6395,48.5218],[-93.6357,48.5285],[-93.6344,48.5293],[-93.6311,48.5313],[-93.6284,48.5319],[-93.6256,48.5315],[-93.6211,48.5264],[-93.6166,48.5238],[-93.6134,48.5228],[-93.6122,48.5225],[-93.6051,48.5231],[-93.5962,48.5287],[-93.5919,48.5299],[-93.5901,48.5305],[-93.581,48.5271],[-93.5761,48.527],[-93.5701,48.528],[-93.5602,48.5297],[-93.5484,48.5294],[-93.5476,48.5294],[-93.5425,48.53],[-93.5366,48.5319],[-93.5269,48.5341],[-93.5263,48.5341],[-93.5244,48.5343],[-93.5171,48.5348],[-93.5047,48.5399],[-93.501,48.5414],[-93.4952,48.5426],[-93.4854,48.5433],[-93.4833,48.5437],[-93.4673,48.5465],[-93.4655,48.5478],[-93.4625,48.5498],[-93.462,48.5505],[-93.4596,48.5537],[-93.4576,48.5598],[-93.4576,48.5621],[-93.4575,48.5672],[-93.4619,48.5731],[-93.4619,48.5734],[-93.4631,48.5767],[-93.4671,48.5885],[-93.4656,48.59],[-93.4654,48.5915],[-93.4654,48.5917],[-93.4627,48.5927],[-93.46,48.5927],[-93.4547,48.5927],[-93.4398,48.5937],[-93.4385,48.5942],[-93.4347,48.5954],[-93.4298,48.5997],[-93.4226,48.6032],[-93.4193,48.6036],[-93.416,48.605],[-93.4152,48.6053],[-93.415,48.6056],[-93.4144,48.6064],[-93.4056,48.6099],[-93.4034,48.61],[-93.4029,48.6077],[-93.4013,48.6079],[-93.3994,48.6055],[-93.3986,48.6045],[-93.3953,48.6038],[-93.3937,48.6041],[-93.3837,48.606],[-93.3724,48.6059],[-93.3714,48.6059],[-93.3672,48.6082],[-93.3619,48.6141],[-93.355,48.6114],[-93.3526,48.6135],[-93.3533,48.615],[-93.3513,48.62],[-93.3505,48.6219],[-93.3486,48.6265],[-93.3276,48.6302],[-93.3057,48.634],[-93.3048,48.6341],[-93.2838,48.6378],[-93.2634,48.6413],[-93.2546,48.6429],[-93.2422,48.6428],[-93.2193,48.6426],[-93.2075,48.6426],[-93.1975,48.6365],[-93.191,48.6325],[-93.184,48.6282],[-93.1783,48.6231],[-93.1754,48.6232],[-93.1531,48.6244],[-93.1319,48.6256],[-93.1104,48.6267],[-93.0903,48.6278],[-93.0884,48.6278],[-93.0886,48.6163],[-93.0895,48.6016],[-93.0898,48.5872],[-93.09,48.5727],[-93.0902,48.5583],[-93.0902,48.5441],[-93.0903,48.5296],[-93.0905,48.5151],[-93.0905,48.501],[-93.091,48.4884],[-93.0911,48.4867],[-93.0914,48.474],[-93.0915,48.4724],[-93.0918,48.4596],[-93.0919,48.458],[-93.092,48.4449],[-93.092,48.4436],[-93.0922,48.4303],[-93.0922,48.429],[-93.0923,48.4147],[-93.0935,48.4147],[-93.0938,48.4024],[-93.094,48.3879],[-93.094,48.3734],[-93.0945,48.3589],[-93.0948,48.3442],[-93.0948,48.3298],[-93.0953,48.3153],[-93.0952,48.3004],[-93.095,48.2862],[-93.0952,48.2716],[-93.0953,48.2576],[-93.0949,48.2426],[-93.0949,48.2425],[-93.0977,48.2426],[-93.0977,48.2271],[-93.0978,48.2126],[-93.0979,48.1981],[-93.0975,48.1836],[-93.097,48.1692],[-93.097,48.1546],[-93.097,48.1402],[-93.0969,48.1259],[-93.0972,48.1114],[-93.097,48.0969],[-93.0968,48.0823],[-93.0965,48.0679],[-93.0965,48.0678],[-93.0892,48.0679],[-93.0892,48.0509],[-93.089,48.0366],[-93.0886,48.022],[-93.0887,48.0075],[-93.0872,47.9932],[-93.088,47.9787],[-93.0809,47.9786],[-93.0809,47.967],[-93.0808,47.9647],[-93.0808,47.9525],[-93.0808,47.9504],[-93.0809,47.938],[-93.0809,47.9356],[-93.0809,47.9235],[-93.0809,47.9212],[-93.0809,47.9088],[-93.0809,47.9067],[-93.0808,47.8945],[-93.0808,47.8922],[-93.1015,47.8927],[-93.1232,47.893],[-93.1448,47.8928],[-93.1656,47.8931],[-93.1671,47.8932],[-93.1871,47.8931],[-93.1893,47.8931],[-93.2087,47.8933],[-93.2115,47.8934],[-93.2331,47.8937],[-93.2532,47.8936],[-93.2745,47.8938],[-93.2962,47.8939],[-93.3169,47.894],[-93.3392,47.8941],[-93.3603,47.8942],[-93.3809,47.8943],[-93.4024,47.8944],[-93.4235,47.8945],[-93.4442,47.8946],[-93.466,47.895],[-93.4874,47.8956],[-93.4892,47.8957],[-93.4933,47.8958],[-93.5085,47.8962],[-93.5105,47.8963],[-93.5297,47.8967],[-93.5303,47.8967],[-93.532,47.8968],[-93.5517,47.8973],[-93.5532,47.8974],[-93.5729,47.8981],[-93.5747,47.8982],[-93.5962,47.8978],[-93.5966,47.8978],[-93.6179,47.8977],[-93.6187,47.8977],[-93.6388,47.8977],[-93.6395,47.8976],[-93.6604,47.8976],[-93.6612,47.8976],[-93.6817,47.8976],[-93.6826,47.8976],[-93.7031,47.8976],[-93.7038,47.8976],[-93.7249,47.8975],[-93.7248,47.8989],[-93.7466,47.8989],[-93.768,47.8991],[-93.7758,47.8991],[-93.7758,47.899],[-93.776,47.8897],[-93.776,47.8842],[-93.7762,47.8753],[-93.7761,47.8697],[-93.7761,47.8607],[-93.7761,47.8553],[-93.7761,47.8464],[-93.7896,47.8465],[-93.7971,47.8466],[-93.8189,47.8467],[-93.8407,47.8468],[-93.8627,47.8469],[-93.8831,47.8471],[-93.9067,47.8471],[-93.9288,47.8475],[-93.9496,47.8475],[-93.9506,47.8475],[-93.971,47.8475],[-93.9725,47.8475],[-93.9927,47.8475],[-93.9942,47.8475],[-94.0141,47.8476],[-94.0161,47.8476],[-94.0375,47.8477],[-94.0591,47.8474],[-94.0807,47.8471],[-94.1022,47.8471],[-94.1239,47.8466],[-94.1448,47.8463],[-94.1657,47.8461],[-94.1822,47.8461],[-94.1871,47.846],[-94.2037,47.846],[-94.2086,47.846],[-94.2252,47.846],[-94.23,47.8461],[-94.2467,47.8462],[-94.2515,47.8462],[-94.2681,47.8462],[-94.2728,47.8462],[-94.2887,47.8462],[-94.3103,47.8458],[-94.3315,47.846],[-94.3532,47.8464],[-94.3747,47.8462],[-94.3964,47.8461],[-94.4185,47.8459],[-94.4186,47.86],[-94.4184,47.8744],[-94.418,47.8886],[-94.4177,47.9031],[-94.4176,47.9041],[-94.4175,47.9175],[-94.4174,47.9186],[-94.4175,47.9332],[-94.4174,47.9477],[-94.4172,47.9623],[-94.4173,47.9769],[-94.4176,47.9914],[-94.4177,48.006],[-94.4176,48.02],[-94.4236,48.0199],[-94.4241,48.0344],[-94.4246,48.0489],[-94.4247,48.0632],[-94.4234,48.0776],[-94.4231,48.092],[-94.4233,48.1059],[-94.4234,48.1204],[-94.4236,48.1348],[-94.4233,48.1491],[-94.4235,48.1637],[-94.4235,48.1781],[-94.4233,48.1923],[-94.4236,48.2067],[-94.4238,48.2212],[-94.4237,48.2356],[-94.4237,48.2504],[-94.424,48.2649],[-94.4243,48.2791],[-94.4244,48.2938],[-94.4246,48.3081],[-94.4248,48.3227],[-94.425,48.3372],[-94.4253,48.352],[-94.4252,48.3675],[-94.4288,48.3675],[-94.4289,48.3821],[-94.4293,48.3964],[-94.4294,48.411],[-94.4293,48.4254],[-94.4292,48.4399],[-94.4293,48.4543],[-94.4296,48.4688],[-94.4296,48.4832],[-94.4299,48.4977],[-94.4303,48.512],[-94.4303,48.5264],[-94.43,48.5409],[-94.4295,48.5554],[-94.4291,48.5698],[-94.4289,48.5844],[-94.4289,48.5988],[-94.4292,48.6133],[-94.4294,48.6276],[-94.4297,48.642],[-94.43,48.6564],[-94.4301,48.6708],[-94.43,48.6852],[-94.4299,48.6998],[-94.4299,48.7012]]],"type":"Polygon"},"id":"36","properties":{"Area":8167237870.91888,"CTYONLY_":5,"Code":"KOOC","LASTMOD":"1999-12-31T23:59:59Z","Name":"Koochiching","Perimiter":412897.43594},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&filter=NOT%20CTYONLY_%20NOT%20BETWEEN%203%20AND%205","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&filter=NOT%20CTYONLY_%20NOT%20BETWEEN%203%20AND%205","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":3,"numberReturned":3,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_text_not_not_iequal.json.txt b/msautotest/api/expected/ogcapi_cql2_text_not_not_iequal.json.txt new file mode 100644 index 0000000000..76e66df248 --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_text_not_not_iequal.json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 1 +OGC-NumberReturned: 1 + +{"features":[{"geometry":{"coordinates":[[[-93.5242,44.5436],[-93.5225,44.5436],[-93.504,44.5438],[-93.5018,44.5438],[-93.4835,44.5438],[-93.4817,44.5438],[-93.4734,44.5438],[-93.4632,44.5438],[-93.4609,44.5438],[-93.4429,44.5438],[-93.4408,44.5438],[-93.4326,44.5438],[-93.4226,44.5439],[-93.4206,44.5439],[-93.4024,44.5439],[-93.4003,44.5439],[-93.383,44.544],[-93.38,44.544],[-93.3627,44.5441],[-93.3596,44.5441],[-93.3556,44.5441],[-93.3424,44.5442],[-93.3395,44.5442],[-93.3221,44.544],[-93.3191,44.544],[-93.3128,44.544],[-93.3019,44.544],[-93.2988,44.544],[-93.2813,44.544],[-93.2814,44.5298],[-93.2815,44.5153],[-93.2815,44.501],[-93.2815,44.4865],[-93.2817,44.472],[-93.2618,44.4718],[-93.2415,44.4716],[-93.2213,44.4714],[-93.2008,44.4714],[-93.1808,44.4713],[-93.1605,44.4713],[-93.1408,44.4712],[-93.1206,44.4713],[-93.1002,44.4718],[-93.0799,44.4719],[-93.0597,44.4718],[-93.0393,44.4719],[-93.0394,44.4576],[-93.0396,44.4432],[-93.0397,44.4287],[-93.0399,44.4143],[-93.04,44.3999],[-93.0401,44.3855],[-93.0402,44.371],[-93.0403,44.3565],[-93.0403,44.3419],[-93.0405,44.3273],[-93.0405,44.3129],[-93.0405,44.2983],[-93.0406,44.2838],[-93.0407,44.2693],[-93.0409,44.2548],[-93.041,44.2402],[-93.0411,44.2257],[-93.0411,44.2113],[-93.0411,44.1968],[-93.0427,44.1968],[-93.0459,44.1968],[-93.0613,44.1967],[-93.0661,44.1967],[-93.0815,44.1967],[-93.0862,44.1967],[-93.1003,44.1967],[-93.1015,44.1967],[-93.1063,44.1967],[-93.1092,44.1967],[-93.1218,44.1967],[-93.1267,44.1967],[-93.1301,44.1967],[-93.1418,44.1967],[-93.1467,44.1967],[-93.1561,44.1966],[-93.1622,44.1966],[-93.1661,44.1966],[-93.1703,44.1966],[-93.1822,44.1966],[-93.1856,44.1966],[-93.1865,44.1966],[-93.2023,44.1966],[-93.2037,44.1966],[-93.2064,44.1966],[-93.2225,44.1966],[-93.2265,44.1966],[-93.2292,44.1966],[-93.2426,44.1966],[-93.2465,44.1966],[-93.255,44.1966],[-93.2629,44.1966],[-93.2664,44.1966],[-93.2767,44.1966],[-93.283,44.1966],[-93.2865,44.1965],[-93.2905,44.1965],[-93.3032,44.1965],[-93.3063,44.1965],[-93.3235,44.1965],[-93.3264,44.1965],[-93.3277,44.1965],[-93.3436,44.1965],[-93.3466,44.1965],[-93.3639,44.1965],[-93.3666,44.1965],[-93.3842,44.1965],[-93.3866,44.1965],[-93.4042,44.1965],[-93.4065,44.1965],[-93.4244,44.1964],[-93.4267,44.1964],[-93.4447,44.1964],[-93.4469,44.1964],[-93.4648,44.1963],[-93.467,44.1963],[-93.4852,44.1964],[-93.4872,44.1964],[-93.5053,44.1963],[-93.507,44.1963],[-93.5255,44.1962],[-93.5253,44.2107],[-93.5251,44.2251],[-93.5251,44.2388],[-93.5251,44.2533],[-93.5252,44.2685],[-93.5252,44.2829],[-93.5252,44.2975],[-93.5252,44.312],[-93.5249,44.3266],[-93.5249,44.3411],[-93.5245,44.3557],[-93.5245,44.3704],[-93.5246,44.3848],[-93.5245,44.3994],[-93.5245,44.4138],[-93.5245,44.4283],[-93.5245,44.4427],[-93.5245,44.4572],[-93.5244,44.4717],[-93.5245,44.4862],[-93.5244,44.5007],[-93.5243,44.5152],[-93.5244,44.5297],[-93.5242,44.5436]]],"type":"Polygon"},"id":"66","properties":{"Area":1335114621.00336,"CTYONLY_":66,"Code":"RICE","LASTMOD":"2010-10-17T00:00:00Z","Name":"Rice","Perimiter":154431.78788},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&filter=NOT%20CASEI(Name)%20%3C%3E%20CASEI('rice')","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&filter=NOT%20CASEI(Name)%20%3C%3E%20CASEI('rice')","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":1,"numberReturned":1,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_text_not_not_in_json.txt b/msautotest/api/expected/ogcapi_cql2_text_not_not_in_json.txt new file mode 100644 index 0000000000..311c4ca902 --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_text_not_not_in_json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 2 +OGC-NumberReturned: 2 + +{"features":[{"geometry":{"coordinates":[[[-96.4054,49.0001],[-96.4054,48.9947],[-96.4054,48.994],[-96.4054,48.9803],[-96.4054,48.9793],[-96.4053,48.9705],[-96.4053,48.9658],[-96.4053,48.9648],[-96.4053,48.9515],[-96.4053,48.9504],[-96.4053,48.9371],[-96.4053,48.936],[-96.4054,48.9225],[-96.4054,48.9214],[-96.4053,48.9137],[-96.4053,48.9081],[-96.4053,48.9068],[-96.405,48.8926],[-96.405,48.878],[-96.4047,48.8635],[-96.4045,48.8491],[-96.4043,48.8343],[-96.4042,48.8198],[-96.4042,48.8048],[-96.4042,48.7903],[-96.4045,48.7758],[-96.4047,48.7607],[-96.4048,48.7465],[-96.4048,48.7318],[-96.4049,48.7172],[-96.388,48.7172],[-96.3873,48.7172],[-96.3866,48.703],[-96.3874,48.6887],[-96.3871,48.6741],[-96.3877,48.6599],[-96.3879,48.6454],[-96.388,48.6313],[-96.389,48.6165],[-96.3891,48.6024],[-96.3884,48.5877],[-96.3882,48.5733],[-96.3879,48.5588],[-96.3882,48.5442],[-96.4101,48.544],[-96.4318,48.5438],[-96.4535,48.5436],[-96.4754,48.5435],[-96.4973,48.5434],[-96.518,48.5434],[-96.54,48.5434],[-96.5621,48.5436],[-96.5839,48.5437],[-96.6058,48.5437],[-96.6278,48.5437],[-96.6493,48.5437],[-96.6713,48.5436],[-96.6931,48.5437],[-96.7151,48.5437],[-96.7368,48.5437],[-96.7585,48.5436],[-96.7803,48.5435],[-96.8023,48.5436],[-96.824,48.5436],[-96.8459,48.5434],[-96.8678,48.5433],[-96.8896,48.5433],[-96.9115,48.5432],[-96.9138,48.5433],[-96.9331,48.5435],[-96.9551,48.5437],[-96.9768,48.544],[-96.9985,48.5441],[-97.0194,48.5441],[-97.0416,48.5442],[-97.0635,48.5441],[-97.0852,48.5441],[-97.107,48.544],[-97.1287,48.5439],[-97.1509,48.5439],[-97.1631,48.544],[-97.1637,48.5445],[-97.1659,48.5483],[-97.1662,48.5509],[-97.1661,48.5527],[-97.1654,48.5536],[-97.1645,48.554],[-97.1628,48.5543],[-97.1613,48.5539],[-97.1592,48.5528],[-97.1577,48.5518],[-97.1557,48.5512],[-97.1538,48.5513],[-97.1513,48.5515],[-97.1507,48.5515],[-97.1493,48.5516],[-97.1474,48.5516],[-97.1444,48.5514],[-97.1407,48.5515],[-97.1387,48.5522],[-97.1379,48.553],[-97.1379,48.5542],[-97.1391,48.5554],[-97.141,48.5566],[-97.1426,48.5571],[-97.1464,48.5573],[-97.1505,48.5574],[-97.1515,48.5574],[-97.1551,48.5574],[-97.1578,48.5573],[-97.1606,48.5571],[-97.1631,48.5571],[-97.1646,48.5572],[-97.167,48.5575],[-97.1697,48.5584],[-97.1721,48.5591],[-97.1727,48.5593],[-97.174,48.5599],[-97.1749,48.5606],[-97.1753,48.5614],[-97.1754,48.5623],[-97.1749,48.5631],[-97.1744,48.5639],[-97.1723,48.5648],[-97.1721,48.5648],[-97.1706,48.5652],[-97.1687,48.5655],[-97.167,48.5658],[-97.1651,48.5659],[-97.1613,48.5661],[-97.1541,48.5669],[-97.153,48.5671],[-97.1516,48.5677],[-97.1503,48.5688],[-97.1496,48.5695],[-97.1487,48.5707],[-97.1477,48.5727],[-97.1477,48.5728],[-97.1476,48.5731],[-97.1483,48.5763],[-97.15,48.5775],[-97.1501,48.5775],[-97.1548,48.5779],[-97.1592,48.5785],[-97.1605,48.58],[-97.16,48.5816],[-97.1578,48.5826],[-97.1562,48.5828],[-97.1541,48.5826],[-97.1524,48.5823],[-97.15,48.5815],[-97.1494,48.5813],[-97.1484,48.5811],[-97.1449,48.5815],[-97.1436,48.5824],[-97.1431,48.5834],[-97.1429,48.5838],[-97.142,48.5876],[-97.1418,48.5886],[-97.1415,48.5909],[-97.1422,48.5926],[-97.1433,48.5936],[-97.1451,48.594],[-97.1471,48.594],[-97.1497,48.5937],[-97.1525,48.594],[-97.1536,48.5949],[-97.1535,48.5957],[-97.1527,48.5962],[-97.1524,48.5969],[-97.1516,48.598],[-97.1498,48.5981],[-97.1497,48.5981],[-97.1463,48.5977],[-97.1443,48.5981],[-97.143,48.5987],[-97.1416,48.6002],[-97.1403,48.6021],[-97.14,48.6025],[-97.138,48.6044],[-97.1359,48.6054],[-97.1345,48.6065],[-97.1341,48.6075],[-97.1349,48.6082],[-97.1358,48.6086],[-97.137,48.6088],[-97.1396,48.6086],[-97.1443,48.6078],[-97.1474,48.6081],[-97.1494,48.6089],[-97.1495,48.609],[-97.1505,48.6115],[-97.1501,48.6124],[-97.1493,48.6129],[-97.1478,48.6138],[-97.145,48.6146],[-97.1408,48.6149],[-97.137,48.6144],[-97.134,48.6136],[-97.1319,48.6133],[-97.1309,48.6137],[-97.1289,48.614],[-97.1286,48.6153],[-97.1293,48.6168],[-97.1295,48.617],[-97.1311,48.6184],[-97.1342,48.6199],[-97.1353,48.6212],[-97.1346,48.6224],[-97.133,48.6228],[-97.131,48.6227],[-97.1291,48.6222],[-97.1277,48.6212],[-97.1274,48.621],[-97.1259,48.6195],[-97.1253,48.619],[-97.1243,48.6183],[-97.1231,48.6178],[-97.1216,48.6176],[-97.12,48.6178],[-97.1193,48.6182],[-97.1186,48.6191],[-97.1183,48.6198],[-97.1186,48.6209],[-97.1198,48.6221],[-97.1209,48.6232],[-97.1212,48.6233],[-97.122,48.624],[-97.1228,48.6245],[-97.1236,48.625],[-97.1241,48.6254],[-97.1245,48.6257],[-97.1249,48.6259],[-97.1253,48.6261],[-97.126,48.6264],[-97.1266,48.6266],[-97.1272,48.627],[-97.1279,48.6273],[-97.1288,48.6278],[-97.1296,48.6282],[-97.1302,48.6288],[-97.1305,48.6292],[-97.1307,48.6297],[-97.131,48.6303],[-97.131,48.6304],[-97.131,48.6308],[-97.131,48.6315],[-97.1309,48.6317],[-97.1307,48.6321],[-97.1304,48.6325],[-97.1301,48.6326],[-97.1297,48.6328],[-97.1293,48.6329],[-97.129,48.633],[-97.1281,48.6332],[-97.128,48.6333],[-97.1275,48.6333],[-97.1253,48.6334],[-97.1235,48.6333],[-97.1216,48.6327],[-97.1181,48.6308],[-97.1176,48.6307],[-97.115,48.6299],[-97.1133,48.63],[-97.1115,48.6303],[-97.1107,48.6308],[-97.1104,48.6309],[-97.1095,48.6315],[-97.1084,48.6327],[-97.1082,48.6344],[-97.1086,48.6363],[-97.1096,48.6389],[-97.1109,48.6407],[-97.1119,48.6416],[-97.1144,48.6433],[-97.115,48.6438],[-97.115,48.6446],[-97.1149,48.6452],[-97.1123,48.6457],[-97.1112,48.6459],[-97.1093,48.6465],[-97.1078,48.6478],[-97.1069,48.6491],[-97.1066,48.6501],[-97.1061,48.6519],[-97.1059,48.6527],[-97.1045,48.6545],[-97.1017,48.6563],[-97.0987,48.6593],[-97.0986,48.6604],[-97.0985,48.6613],[-97.0992,48.6625],[-97.1019,48.6636],[-97.106,48.663],[-97.1062,48.663],[-97.1082,48.6634],[-97.1087,48.6645],[-97.1061,48.6654],[-97.1057,48.6655],[-97.102,48.6667],[-97.1,48.668],[-97.0998,48.6714],[-97.1002,48.675],[-97.1003,48.6757],[-97.1008,48.6787],[-97.1011,48.6808],[-97.1003,48.6828],[-97.0985,48.683],[-97.0946,48.6822],[-97.0926,48.6821],[-97.0904,48.6828],[-97.0898,48.6841],[-97.0899,48.6852],[-97.091,48.6861],[-97.093,48.687],[-97.0951,48.6876],[-97.099,48.6884],[-97.1024,48.6893],[-97.103,48.6894],[-97.1059,48.6903],[-97.1064,48.6905],[-97.1086,48.6915],[-97.111,48.6939],[-97.113,48.6964],[-97.1148,48.6981],[-97.1182,48.7005],[-97.1198,48.7018],[-97.1201,48.7039],[-97.1194,48.7041],[-97.1182,48.7046],[-97.1143,48.7052],[-97.1117,48.7056],[-97.11,48.7063],[-97.1098,48.7083],[-97.1113,48.7094],[-97.1134,48.7101],[-97.1157,48.7105],[-97.1174,48.7111],[-97.119,48.7119],[-97.1212,48.7136],[-97.1223,48.716],[-97.1229,48.7168],[-97.1231,48.7172],[-97.1243,48.7192],[-97.1253,48.7201],[-97.1253,48.7203],[-97.126,48.7207],[-97.1263,48.7212],[-97.1272,48.7215],[-97.128,48.722],[-97.1282,48.7221],[-97.1288,48.7225],[-97.1297,48.7229],[-97.131,48.7233],[-97.1321,48.7238],[-97.1331,48.7242],[-97.1345,48.7248],[-97.136,48.7257],[-97.1369,48.7263],[-97.1375,48.727],[-97.1376,48.7274],[-97.1376,48.7278],[-97.1373,48.7283],[-97.137,48.7284],[-97.1365,48.7285],[-97.136,48.7287],[-97.1352,48.7287],[-97.1341,48.7289],[-97.1333,48.7291],[-97.1328,48.7292],[-97.132,48.7294],[-97.1312,48.7295],[-97.1308,48.7296],[-97.1299,48.7299],[-97.1294,48.7304],[-97.1288,48.7308],[-97.1286,48.7312],[-97.1286,48.7315],[-97.1286,48.7316],[-97.1286,48.7318],[-97.1285,48.7322],[-97.1286,48.7326],[-97.1286,48.7328],[-97.1287,48.7331],[-97.129,48.7335],[-97.1295,48.7339],[-97.1298,48.7341],[-97.1316,48.7347],[-97.1322,48.7348],[-97.1334,48.7347],[-97.1351,48.7345],[-97.1369,48.7345],[-97.1383,48.7345],[-97.1396,48.7347],[-97.1402,48.7349],[-97.1412,48.7354],[-97.1419,48.7359],[-97.1422,48.7367],[-97.1423,48.7372],[-97.1421,48.7381],[-97.1414,48.7385],[-97.1408,48.7387],[-97.1404,48.7389],[-97.1399,48.7393],[-97.1392,48.7397],[-97.1381,48.7408],[-97.1372,48.742],[-97.1366,48.7435],[-97.1365,48.745],[-97.1365,48.7459],[-97.1366,48.7466],[-97.1369,48.748],[-97.1375,48.7492],[-97.1379,48.75],[-97.1385,48.7504],[-97.1391,48.7507],[-97.1396,48.7508],[-97.1401,48.7509],[-97.141,48.751],[-97.142,48.751],[-97.143,48.7509],[-97.1444,48.7507],[-97.1457,48.7506],[-97.1466,48.7505],[-97.1476,48.7505],[-97.1491,48.7506],[-97.1497,48.7508],[-97.1503,48.7509],[-97.1515,48.7515],[-97.1521,48.752],[-97.153,48.7529],[-97.1539,48.7542],[-97.1545,48.7553],[-97.1547,48.7558],[-97.1548,48.7562],[-97.1548,48.7569],[-97.1548,48.7576],[-97.1546,48.758],[-97.1542,48.7587],[-97.1535,48.7593],[-97.1528,48.7598],[-97.1519,48.7601],[-97.1508,48.7605],[-97.1503,48.7606],[-97.1501,48.7607],[-97.1475,48.7616],[-97.1473,48.7617],[-97.1469,48.762],[-97.1462,48.7626],[-97.1461,48.7628],[-97.1459,48.7633],[-97.1456,48.7643],[-97.1456,48.765],[-97.146,48.7658],[-97.1476,48.7673],[-97.1487,48.7681],[-97.15,48.7692],[-97.1501,48.7693],[-97.1506,48.77],[-97.1512,48.7712],[-97.1519,48.7721],[-97.1525,48.7727],[-97.1529,48.7728],[-97.1559,48.7731],[-97.1567,48.7732],[-97.1578,48.7735],[-97.1582,48.7737],[-97.1587,48.7742],[-97.1589,48.7746],[-97.159,48.7751],[-97.159,48.7751],[-97.159,48.7754],[-97.1589,48.776],[-97.1584,48.7766],[-97.1579,48.7769],[-97.1573,48.7772],[-97.1557,48.7776],[-97.1544,48.7778],[-97.1534,48.778],[-97.1522,48.7783],[-97.1509,48.7787],[-97.1501,48.7789],[-97.1497,48.779],[-97.1483,48.7797],[-97.1477,48.7801],[-97.1473,48.7807],[-97.1472,48.7811],[-97.1473,48.7816],[-97.1478,48.7821],[-97.1486,48.7824],[-97.1495,48.7826],[-97.1501,48.7826],[-97.1503,48.7826],[-97.1513,48.7825],[-97.1533,48.7824],[-97.1547,48.7824],[-97.1559,48.7825],[-97.1571,48.7827],[-97.1583,48.783],[-97.1591,48.7834],[-97.1595,48.7838],[-97.1597,48.7843],[-97.1598,48.7848],[-97.1596,48.7853],[-97.1593,48.786],[-97.1591,48.7863],[-97.1586,48.7869],[-97.1577,48.7877],[-97.1574,48.7882],[-97.1573,48.7884],[-97.1572,48.7887],[-97.1571,48.7894],[-97.157,48.7895],[-97.157,48.7901],[-97.1572,48.7906],[-97.1575,48.7909],[-97.1581,48.7912],[-97.1586,48.7913],[-97.1592,48.7915],[-97.1595,48.7915],[-97.1611,48.7915],[-97.1618,48.7914],[-97.1645,48.7911],[-97.1648,48.7911],[-97.1657,48.7911],[-97.1664,48.7912],[-97.1672,48.7913],[-97.1714,48.7921],[-97.1718,48.7923],[-97.1721,48.7924],[-97.1731,48.7929],[-97.1737,48.7933],[-97.174,48.7937],[-97.1741,48.7942],[-97.1742,48.7947],[-97.1742,48.7951],[-97.1739,48.7954],[-97.1734,48.7958],[-97.1726,48.7963],[-97.1717,48.7966],[-97.1716,48.7966],[-97.171,48.7967],[-97.1701,48.7967],[-97.1688,48.7966],[-97.1673,48.7964],[-97.1665,48.7962],[-97.1654,48.7962],[-97.1648,48.7962],[-97.1638,48.7963],[-97.1631,48.7966],[-97.1625,48.7969],[-97.162,48.7974],[-97.1617,48.7979],[-97.1617,48.7984],[-97.1619,48.7988],[-97.1621,48.7994],[-97.1626,48.8001],[-97.1633,48.8007],[-97.1642,48.8011],[-97.1652,48.8014],[-97.166,48.8015],[-97.1668,48.8016],[-97.1675,48.8016],[-97.1685,48.8016],[-97.1698,48.8013],[-97.1706,48.8011],[-97.1714,48.8008],[-97.1715,48.8008],[-97.1724,48.8004],[-97.1731,48.8],[-97.1742,48.7992],[-97.175,48.7986],[-97.1754,48.7983],[-97.1757,48.798],[-97.1761,48.7977],[-97.1768,48.7974],[-97.1773,48.7973],[-97.1779,48.7972],[-97.1787,48.7972],[-97.1795,48.7972],[-97.1801,48.7973],[-97.1807,48.7975],[-97.1811,48.7978],[-97.1815,48.7982],[-97.1816,48.7986],[-97.1817,48.7991],[-97.1815,48.7995],[-97.1813,48.8],[-97.1808,48.8004],[-97.1801,48.8008],[-97.1791,48.8012],[-97.1779,48.8015],[-97.1769,48.8017],[-97.1764,48.8018],[-97.1756,48.8021],[-97.1748,48.8023],[-97.1725,48.8032],[-97.1713,48.8036],[-97.171,48.8037],[-97.1706,48.8039],[-97.1694,48.8043],[-97.1682,48.8046],[-97.1675,48.8048],[-97.1666,48.805],[-97.1655,48.8052],[-97.1638,48.8055],[-97.161,48.8059],[-97.1605,48.8061],[-97.1597,48.8064],[-97.159,48.8067],[-97.1583,48.8072],[-97.1579,48.8077],[-97.1577,48.8082],[-97.1576,48.8089],[-97.1578,48.8098],[-97.158,48.8104],[-97.1586,48.811],[-97.159,48.8111],[-97.161,48.8117],[-97.1617,48.8119],[-97.1625,48.812],[-97.1636,48.8121],[-97.1644,48.8121],[-97.1651,48.812],[-97.1666,48.8118],[-97.168,48.8116],[-97.169,48.8114],[-97.17,48.8114],[-97.1713,48.8115],[-97.1715,48.8115],[-97.1726,48.8117],[-97.1731,48.8118],[-97.174,48.8122],[-97.1761,48.8132],[-97.1776,48.8141],[-97.1784,48.8145],[-97.1797,48.8149],[-97.1807,48.8151],[-97.1821,48.8153],[-97.1828,48.8153],[-97.184,48.8152],[-97.1848,48.8151],[-97.186,48.8147],[-97.1868,48.8145],[-97.1873,48.8143],[-97.1879,48.8143],[-97.1883,48.8143],[-97.1889,48.8143],[-97.1894,48.8144],[-97.1898,48.8146],[-97.1901,48.8148],[-97.1903,48.8153],[-97.1904,48.8156],[-97.1903,48.8159],[-97.19,48.8163],[-97.1893,48.8167],[-97.1885,48.8171],[-97.1879,48.8173],[-97.1866,48.8176],[-97.1857,48.8177],[-97.1847,48.8179],[-97.184,48.8181],[-97.1833,48.8184],[-97.1817,48.8189],[-97.1809,48.8193],[-97.1801,48.8199],[-97.1793,48.8207],[-97.1787,48.8216],[-97.178,48.8232],[-97.1777,48.824],[-97.1776,48.8245],[-97.1777,48.8249],[-97.178,48.8255],[-97.1782,48.8258],[-97.1786,48.8262],[-97.1794,48.8268],[-97.1822,48.8288],[-97.1837,48.8299],[-97.1841,48.8304],[-97.1847,48.8314],[-97.1848,48.8319],[-97.1849,48.8326],[-97.1849,48.8327],[-97.1848,48.833],[-97.1846,48.8336],[-97.1842,48.8341],[-97.1837,48.8345],[-97.183,48.8348],[-97.1822,48.835],[-97.1813,48.8351],[-97.1799,48.8352],[-97.1783,48.8353],[-97.1779,48.8354],[-97.1772,48.8356],[-97.1757,48.8362],[-97.1753,48.8364],[-97.1747,48.8369],[-97.1742,48.8373],[-97.1739,48.8378],[-97.1738,48.8384],[-97.1738,48.839],[-97.1739,48.8406],[-97.1743,48.8427],[-97.1747,48.8438],[-97.175,48.8442],[-97.1755,48.8447],[-97.1761,48.8452],[-97.1767,48.8455],[-97.1771,48.8456],[-97.1779,48.8458],[-97.1795,48.8459],[-97.1808,48.846],[-97.1817,48.8462],[-97.1823,48.8464],[-97.1827,48.8468],[-97.1829,48.847],[-97.1829,48.8471],[-97.1829,48.8473],[-97.1826,48.8476],[-97.1821,48.8479],[-97.1816,48.848],[-97.1809,48.8481],[-97.1793,48.8482],[-97.178,48.8483],[-97.1767,48.8484],[-97.1759,48.8486],[-97.1753,48.8487],[-97.1747,48.849],[-97.1742,48.8493],[-97.1737,48.8497],[-97.1733,48.8502],[-97.173,48.8506],[-97.173,48.8508],[-97.173,48.8511],[-97.173,48.8516],[-97.1732,48.8522],[-97.1737,48.8527],[-97.1746,48.8534],[-97.1771,48.855],[-97.1784,48.8561],[-97.1786,48.8563],[-97.179,48.8569],[-97.1793,48.8576],[-97.1794,48.8583],[-97.1794,48.859],[-97.1792,48.8606],[-97.179,48.8615],[-97.179,48.862],[-97.1791,48.8626],[-97.1794,48.863],[-97.1801,48.8636],[-97.1811,48.864],[-97.1818,48.8641],[-97.1827,48.8641],[-97.1839,48.864],[-97.1855,48.8637],[-97.1871,48.8633],[-97.1877,48.8631],[-97.1883,48.8631],[-97.1891,48.8631],[-97.1896,48.8633],[-97.19,48.8635],[-97.1903,48.8639],[-97.1905,48.8644],[-97.1905,48.8648],[-97.1904,48.8651],[-97.1901,48.8657],[-97.1899,48.8661],[-97.1895,48.8665],[-97.189,48.867],[-97.1884,48.8675],[-97.1851,48.8694],[-97.1813,48.8718],[-97.1788,48.8736],[-97.1785,48.8738],[-97.1782,48.8741],[-97.1781,48.8743],[-97.1779,48.8745],[-97.1778,48.8747],[-97.1777,48.8749],[-97.1777,48.875],[-97.1778,48.875],[-97.1778,48.8754],[-97.1779,48.8757],[-97.1782,48.8761],[-97.1786,48.8765],[-97.1792,48.8769],[-97.1798,48.8771],[-97.1808,48.8772],[-97.1823,48.8772],[-97.1852,48.8768],[-97.1869,48.8765],[-97.1881,48.8765],[-97.1891,48.8766],[-97.1904,48.8769],[-97.1933,48.8779],[-97.1944,48.8783],[-97.1957,48.8788],[-97.1972,48.8794],[-97.1981,48.8799],[-97.1988,48.8805],[-97.1995,48.8812],[-97.1999,48.8818],[-97.1999,48.8821],[-97.2,48.8827],[-97.1998,48.8832],[-97.1997,48.8836],[-97.199,48.8845],[-97.1978,48.8859],[-97.1975,48.8865],[-97.1974,48.8868],[-97.1973,48.8872],[-97.1973,48.8874],[-97.1974,48.8877],[-97.1975,48.8881],[-97.1983,48.8889],[-97.2002,48.8903],[-97.2004,48.8904],[-97.2009,48.8908],[-97.2014,48.8912],[-97.2017,48.8915],[-97.2017,48.8919],[-97.2016,48.8922],[-97.2013,48.8925],[-97.201,48.8926],[-97.2001,48.8926],[-97.1994,48.8926],[-97.1985,48.8925],[-97.198,48.8924],[-97.1973,48.892],[-97.1957,48.8916],[-97.1946,48.8915],[-97.1944,48.8914],[-97.1937,48.8914],[-97.1927,48.8915],[-97.1921,48.8917],[-97.1916,48.8919],[-97.1905,48.8926],[-97.1901,48.8932],[-97.1898,48.8938],[-97.1897,48.8944],[-97.1897,48.8947],[-97.1898,48.8951],[-97.1899,48.8954],[-97.1903,48.896],[-97.1911,48.8967],[-97.1919,48.8974],[-97.1925,48.8979],[-97.1935,48.8985],[-97.1941,48.8988],[-97.1945,48.8989],[-97.1966,48.8997],[-97.1992,48.9004],[-97.2009,48.9009],[-97.2022,48.9013],[-97.2048,48.9018],[-97.2055,48.902],[-97.207,48.9025],[-97.2076,48.9027],[-97.2082,48.9029],[-97.2088,48.9032],[-97.2093,48.9036],[-97.21,48.904],[-97.2105,48.9044],[-97.211,48.905],[-97.2114,48.9056],[-97.2122,48.9069],[-97.2125,48.9075],[-97.2127,48.9082],[-97.2127,48.909],[-97.2125,48.9099],[-97.212,48.911],[-97.2116,48.9121],[-97.2111,48.913],[-97.2108,48.914],[-97.2106,48.9148],[-97.2106,48.9153],[-97.2109,48.9162],[-97.2111,48.9167],[-97.2115,48.9172],[-97.2118,48.9175],[-97.2122,48.9177],[-97.2129,48.9181],[-97.2149,48.9187],[-97.2163,48.9191],[-97.2164,48.9191],[-97.2171,48.9194],[-97.2179,48.9198],[-97.2189,48.9205],[-97.2196,48.9215],[-97.2198,48.9222],[-97.2199,48.923],[-97.2197,48.9237],[-97.2191,48.9249],[-97.2183,48.9262],[-97.2172,48.9277],[-97.2163,48.9286],[-97.2159,48.9289],[-97.2149,48.9301],[-97.2146,48.9304],[-97.2145,48.9307],[-97.2144,48.931],[-97.2145,48.9314],[-97.2145,48.9316],[-97.2148,48.9319],[-97.2154,48.9325],[-97.2159,48.9327],[-97.2162,48.9328],[-97.217,48.9328],[-97.2181,48.9327],[-97.2198,48.9325],[-97.2208,48.9325],[-97.2214,48.9325],[-97.2218,48.9326],[-97.2237,48.9332],[-97.2245,48.9337],[-97.2249,48.9339],[-97.225,48.934],[-97.2252,48.9342],[-97.2254,48.9345],[-97.2257,48.9349],[-97.226,48.9353],[-97.2263,48.936],[-97.2267,48.9376],[-97.227,48.9389],[-97.2271,48.9398],[-97.2271,48.941],[-97.227,48.9418],[-97.2266,48.9432],[-97.2264,48.9441],[-97.2263,48.9445],[-97.2264,48.9452],[-97.2265,48.9456],[-97.227,48.9462],[-97.2273,48.9465],[-97.2276,48.9467],[-97.2279,48.9467],[-97.2284,48.9468],[-97.2304,48.9465],[-97.2309,48.9464],[-97.2313,48.9464],[-97.2326,48.9466],[-97.2331,48.9468],[-97.2338,48.9471],[-97.2342,48.9474],[-97.2343,48.948],[-97.2343,48.9485],[-97.2342,48.9488],[-97.2341,48.9491],[-97.2337,48.95],[-97.2332,48.951],[-97.2328,48.9524],[-97.2323,48.954],[-97.2317,48.9558],[-97.2313,48.9568],[-97.2309,48.9578],[-97.2305,48.9585],[-97.23,48.9591],[-97.2288,48.9603],[-97.2282,48.9609],[-97.2278,48.9613],[-97.2276,48.9619],[-97.2276,48.9624],[-97.2279,48.963],[-97.228,48.9631],[-97.2283,48.9634],[-97.2289,48.9639],[-97.2294,48.9641],[-97.23,48.9642],[-97.2323,48.9646],[-97.2355,48.965],[-97.2368,48.9652],[-97.2375,48.9654],[-97.2382,48.966],[-97.2383,48.9661],[-97.2388,48.9666],[-97.2391,48.9676],[-97.2392,48.9687],[-97.239,48.9696],[-97.2387,48.9706],[-97.2383,48.9715],[-97.2381,48.9723],[-97.238,48.9725],[-97.2379,48.9731],[-97.2378,48.9734],[-97.2378,48.9738],[-97.238,48.9752],[-97.238,48.9763],[-97.2381,48.9771],[-97.238,48.9771],[-97.238,48.9841],[-97.2377,48.9849],[-97.2372,48.9857],[-97.2365,48.9867],[-97.2359,48.9874],[-97.2351,48.9881],[-97.2342,48.989],[-97.2335,48.9895],[-97.2331,48.9898],[-97.2317,48.9904],[-97.2301,48.9911],[-97.2293,48.9914],[-97.229,48.9916],[-97.2279,48.9921],[-97.2274,48.9925],[-97.227,48.9929],[-97.2266,48.9933],[-97.2265,48.9938],[-97.2267,48.9941],[-97.227,48.9945],[-97.2273,48.9947],[-97.2287,48.9949],[-97.2304,48.995],[-97.2317,48.9951],[-97.2324,48.9952],[-97.2335,48.9956],[-97.2338,48.9959],[-97.2341,48.9966],[-97.2341,48.997],[-97.234,48.9975],[-97.2337,48.9981],[-97.2332,48.9985],[-97.2323,48.999],[-97.2305,49.0],[-97.2303,49.0001],[-97.2295,49.0005],[-97.2175,49.0005],[-97.2161,49.0005],[-97.2078,49.0005],[-97.2069,49.0005],[-97.1955,49.0005],[-97.1939,49.0005],[-97.1739,49.0005],[-97.1724,49.0005],[-97.1514,49.0005],[-97.1502,49.0005],[-97.1294,49.0004],[-97.1277,49.0004],[-97.1073,49.0004],[-97.1061,49.0004],[-97.0853,49.0004],[-97.084,49.0004],[-97.0633,49.0004],[-97.062,49.0004],[-97.0412,49.0004],[-97.0401,49.0004],[-97.0192,49.0004],[-97.0183,49.0004],[-96.9971,49.0004],[-96.9961,49.0004],[-96.9751,49.0003],[-96.9738,49.0003],[-96.953,49.0003],[-96.9518,49.0003],[-96.931,49.0003],[-96.9299,49.0003],[-96.909,49.0003],[-96.9078,49.0003],[-96.8869,49.0003],[-96.8856,49.0003],[-96.8649,49.0003],[-96.864,49.0003],[-96.8429,49.0003],[-96.8415,49.0003],[-96.8208,49.0003],[-96.8197,49.0003],[-96.8023,49.0002],[-96.8005,49.0002],[-96.8003,49.0002],[-96.7988,49.0002],[-96.7787,49.0002],[-96.7768,49.0002],[-96.7567,49.0002],[-96.7547,49.0002],[-96.7348,49.0002],[-96.7327,49.0002],[-96.7127,49.0002],[-96.7107,49.0002],[-96.6905,49.0002],[-96.6886,49.0002],[-96.6695,49.0002],[-96.6665,49.0002],[-96.6482,49.0002],[-96.6445,49.0002],[-96.6243,49.0002],[-96.6225,49.0002],[-96.6021,49.0002],[-96.6004,49.0002],[-96.58,49.0002],[-96.5784,49.0002],[-96.558,49.0002],[-96.5563,49.0002],[-96.536,49.0002],[-96.5342,49.0002],[-96.5154,49.0002],[-96.5123,49.0002],[-96.4933,49.0002],[-96.49,49.0002],[-96.471,49.0001],[-96.4664,49.0001],[-96.4496,49.0001],[-96.4492,49.0001],[-96.4491,49.0001],[-96.446,49.0001],[-96.4273,49.0001],[-96.4224,49.0001],[-96.4054,49.0001]]],"type":"Polygon"},"id":"35","properties":{"Area":2862183702.23055,"CTYONLY_":3,"Code":"KITT","LASTMOD":"1999-12-31T23:59:59Z","Name":"Kittson","Perimiter":263017.48277},"type":"Feature"},{"geometry":{"coordinates":[[[-94.4299,48.7012],[-94.4241,48.7053],[-94.4213,48.7086],[-94.4189,48.7103],[-94.4158,48.711],[-94.4081,48.7106],[-94.406,48.7105],[-94.3889,48.712],[-94.3859,48.7119],[-94.384,48.7119],[-94.3801,48.7111],[-94.3687,48.7065],[-94.3646,48.7059],[-94.3533,48.7042],[-94.3431,48.7035],[-94.3429,48.7035],[-94.3287,48.7045],[-94.3214,48.7067],[-94.3088,48.7103],[-94.2995,48.709],[-94.2911,48.7079],[-94.2829,48.7057],[-94.2781,48.7024],[-94.2745,48.6999],[-94.2694,48.6995],[-94.2644,48.699],[-94.261,48.6966],[-94.258,48.6918],[-94.2565,48.6901],[-94.2529,48.6864],[-94.2521,48.685],[-94.2514,48.6837],[-94.2507,48.6782],[-94.2527,48.6707],[-94.253,48.6693],[-94.2548,48.664],[-94.2546,48.6615],[-94.2509,48.657],[-94.2499,48.6563],[-94.2467,48.6542],[-94.2445,48.6535],[-94.2343,48.6524],[-94.2335,48.6524],[-94.2242,48.6495],[-94.2144,48.6494],[-94.2124,48.6496],[-94.1996,48.651],[-94.1915,48.6506],[-94.1886,48.6504],[-94.1689,48.6483],[-94.1678,48.6482],[-94.1574,48.6458],[-94.1522,48.6455],[-94.1458,48.6458],[-94.1391,48.646],[-94.126,48.6444],[-94.1235,48.6444],[-94.11,48.6443],[-94.1023,48.6455],[-94.0999,48.6459],[-94.0912,48.6437],[-94.0849,48.6441],[-94.0804,48.6442],[-94.0767,48.6442],[-94.0714,48.6459],[-94.0658,48.6462],[-94.0642,48.6438],[-94.0603,48.6431],[-94.0581,48.6434],[-94.0525,48.644],[-94.0432,48.6435],[-94.0393,48.6423],[-94.0364,48.6413],[-94.0356,48.6411],[-94.0295,48.6409],[-94.0153,48.6424],[-94.0069,48.6433],[-94.0007,48.6428],[-93.9931,48.6412],[-93.9897,48.6405],[-93.984,48.6401],[-93.9777,48.6385],[-93.9712,48.6385],[-93.968,48.6385],[-93.9596,48.6372],[-93.953,48.6341],[-93.9497,48.6339],[-93.934,48.6326],[-93.9272,48.6327],[-93.9169,48.6329],[-93.9134,48.6353],[-93.9057,48.6346],[-93.9054,48.6345],[-93.8948,48.6324],[-93.8853,48.6318],[-93.8844,48.6318],[-93.8757,48.6319],[-93.8698,48.6311],[-93.8624,48.631],[-93.848,48.6308],[-93.8443,48.6303],[-93.8404,48.6289],[-93.8393,48.6286],[-93.8365,48.6276],[-93.8334,48.6256],[-93.8292,48.6177],[-93.825,48.6136],[-93.8245,48.613],[-93.8214,48.6092],[-93.8182,48.5994],[-93.8175,48.597],[-93.8172,48.5964],[-93.813,48.588],[-93.8103,48.5846],[-93.8063,48.5796],[-93.8041,48.5703],[-93.8041,48.5702],[-93.8051,48.5644],[-93.808,48.5569],[-93.8088,48.5555],[-93.8119,48.5503],[-93.8102,48.5445],[-93.8109,48.5412],[-93.8109,48.541],[-93.818,48.535],[-93.818,48.5346],[-93.8184,48.5315],[-93.8178,48.5306],[-93.8161,48.5285],[-93.8145,48.5273],[-93.8111,48.5247],[-93.803,48.522],[-93.7964,48.5182],[-93.7933,48.5164],[-93.7879,48.5159],[-93.7745,48.5162],[-93.768,48.5164],[-93.7665,48.5164],[-93.7617,48.5166],[-93.7534,48.5158],[-93.7442,48.5175],[-93.739,48.5185],[-93.731,48.5185],[-93.7225,48.5178],[-93.7206,48.5176],[-93.7108,48.5186],[-93.7061,48.5182],[-93.7006,48.517],[-93.693,48.5152],[-93.6866,48.5154],[-93.6791,48.5167],[-93.6778,48.5169],[-93.6593,48.5165],[-93.657,48.5167],[-93.6473,48.5177],[-93.6433,48.519],[-93.6421,48.5199],[-93.6395,48.5218],[-93.6357,48.5285],[-93.6344,48.5293],[-93.6311,48.5313],[-93.6284,48.5319],[-93.6256,48.5315],[-93.6211,48.5264],[-93.6166,48.5238],[-93.6134,48.5228],[-93.6122,48.5225],[-93.6051,48.5231],[-93.5962,48.5287],[-93.5919,48.5299],[-93.5901,48.5305],[-93.581,48.5271],[-93.5761,48.527],[-93.5701,48.528],[-93.5602,48.5297],[-93.5484,48.5294],[-93.5476,48.5294],[-93.5425,48.53],[-93.5366,48.5319],[-93.5269,48.5341],[-93.5263,48.5341],[-93.5244,48.5343],[-93.5171,48.5348],[-93.5047,48.5399],[-93.501,48.5414],[-93.4952,48.5426],[-93.4854,48.5433],[-93.4833,48.5437],[-93.4673,48.5465],[-93.4655,48.5478],[-93.4625,48.5498],[-93.462,48.5505],[-93.4596,48.5537],[-93.4576,48.5598],[-93.4576,48.5621],[-93.4575,48.5672],[-93.4619,48.5731],[-93.4619,48.5734],[-93.4631,48.5767],[-93.4671,48.5885],[-93.4656,48.59],[-93.4654,48.5915],[-93.4654,48.5917],[-93.4627,48.5927],[-93.46,48.5927],[-93.4547,48.5927],[-93.4398,48.5937],[-93.4385,48.5942],[-93.4347,48.5954],[-93.4298,48.5997],[-93.4226,48.6032],[-93.4193,48.6036],[-93.416,48.605],[-93.4152,48.6053],[-93.415,48.6056],[-93.4144,48.6064],[-93.4056,48.6099],[-93.4034,48.61],[-93.4029,48.6077],[-93.4013,48.6079],[-93.3994,48.6055],[-93.3986,48.6045],[-93.3953,48.6038],[-93.3937,48.6041],[-93.3837,48.606],[-93.3724,48.6059],[-93.3714,48.6059],[-93.3672,48.6082],[-93.3619,48.6141],[-93.355,48.6114],[-93.3526,48.6135],[-93.3533,48.615],[-93.3513,48.62],[-93.3505,48.6219],[-93.3486,48.6265],[-93.3276,48.6302],[-93.3057,48.634],[-93.3048,48.6341],[-93.2838,48.6378],[-93.2634,48.6413],[-93.2546,48.6429],[-93.2422,48.6428],[-93.2193,48.6426],[-93.2075,48.6426],[-93.1975,48.6365],[-93.191,48.6325],[-93.184,48.6282],[-93.1783,48.6231],[-93.1754,48.6232],[-93.1531,48.6244],[-93.1319,48.6256],[-93.1104,48.6267],[-93.0903,48.6278],[-93.0884,48.6278],[-93.0886,48.6163],[-93.0895,48.6016],[-93.0898,48.5872],[-93.09,48.5727],[-93.0902,48.5583],[-93.0902,48.5441],[-93.0903,48.5296],[-93.0905,48.5151],[-93.0905,48.501],[-93.091,48.4884],[-93.0911,48.4867],[-93.0914,48.474],[-93.0915,48.4724],[-93.0918,48.4596],[-93.0919,48.458],[-93.092,48.4449],[-93.092,48.4436],[-93.0922,48.4303],[-93.0922,48.429],[-93.0923,48.4147],[-93.0935,48.4147],[-93.0938,48.4024],[-93.094,48.3879],[-93.094,48.3734],[-93.0945,48.3589],[-93.0948,48.3442],[-93.0948,48.3298],[-93.0953,48.3153],[-93.0952,48.3004],[-93.095,48.2862],[-93.0952,48.2716],[-93.0953,48.2576],[-93.0949,48.2426],[-93.0949,48.2425],[-93.0977,48.2426],[-93.0977,48.2271],[-93.0978,48.2126],[-93.0979,48.1981],[-93.0975,48.1836],[-93.097,48.1692],[-93.097,48.1546],[-93.097,48.1402],[-93.0969,48.1259],[-93.0972,48.1114],[-93.097,48.0969],[-93.0968,48.0823],[-93.0965,48.0679],[-93.0965,48.0678],[-93.0892,48.0679],[-93.0892,48.0509],[-93.089,48.0366],[-93.0886,48.022],[-93.0887,48.0075],[-93.0872,47.9932],[-93.088,47.9787],[-93.0809,47.9786],[-93.0809,47.967],[-93.0808,47.9647],[-93.0808,47.9525],[-93.0808,47.9504],[-93.0809,47.938],[-93.0809,47.9356],[-93.0809,47.9235],[-93.0809,47.9212],[-93.0809,47.9088],[-93.0809,47.9067],[-93.0808,47.8945],[-93.0808,47.8922],[-93.1015,47.8927],[-93.1232,47.893],[-93.1448,47.8928],[-93.1656,47.8931],[-93.1671,47.8932],[-93.1871,47.8931],[-93.1893,47.8931],[-93.2087,47.8933],[-93.2115,47.8934],[-93.2331,47.8937],[-93.2532,47.8936],[-93.2745,47.8938],[-93.2962,47.8939],[-93.3169,47.894],[-93.3392,47.8941],[-93.3603,47.8942],[-93.3809,47.8943],[-93.4024,47.8944],[-93.4235,47.8945],[-93.4442,47.8946],[-93.466,47.895],[-93.4874,47.8956],[-93.4892,47.8957],[-93.4933,47.8958],[-93.5085,47.8962],[-93.5105,47.8963],[-93.5297,47.8967],[-93.5303,47.8967],[-93.532,47.8968],[-93.5517,47.8973],[-93.5532,47.8974],[-93.5729,47.8981],[-93.5747,47.8982],[-93.5962,47.8978],[-93.5966,47.8978],[-93.6179,47.8977],[-93.6187,47.8977],[-93.6388,47.8977],[-93.6395,47.8976],[-93.6604,47.8976],[-93.6612,47.8976],[-93.6817,47.8976],[-93.6826,47.8976],[-93.7031,47.8976],[-93.7038,47.8976],[-93.7249,47.8975],[-93.7248,47.8989],[-93.7466,47.8989],[-93.768,47.8991],[-93.7758,47.8991],[-93.7758,47.899],[-93.776,47.8897],[-93.776,47.8842],[-93.7762,47.8753],[-93.7761,47.8697],[-93.7761,47.8607],[-93.7761,47.8553],[-93.7761,47.8464],[-93.7896,47.8465],[-93.7971,47.8466],[-93.8189,47.8467],[-93.8407,47.8468],[-93.8627,47.8469],[-93.8831,47.8471],[-93.9067,47.8471],[-93.9288,47.8475],[-93.9496,47.8475],[-93.9506,47.8475],[-93.971,47.8475],[-93.9725,47.8475],[-93.9927,47.8475],[-93.9942,47.8475],[-94.0141,47.8476],[-94.0161,47.8476],[-94.0375,47.8477],[-94.0591,47.8474],[-94.0807,47.8471],[-94.1022,47.8471],[-94.1239,47.8466],[-94.1448,47.8463],[-94.1657,47.8461],[-94.1822,47.8461],[-94.1871,47.846],[-94.2037,47.846],[-94.2086,47.846],[-94.2252,47.846],[-94.23,47.8461],[-94.2467,47.8462],[-94.2515,47.8462],[-94.2681,47.8462],[-94.2728,47.8462],[-94.2887,47.8462],[-94.3103,47.8458],[-94.3315,47.846],[-94.3532,47.8464],[-94.3747,47.8462],[-94.3964,47.8461],[-94.4185,47.8459],[-94.4186,47.86],[-94.4184,47.8744],[-94.418,47.8886],[-94.4177,47.9031],[-94.4176,47.9041],[-94.4175,47.9175],[-94.4174,47.9186],[-94.4175,47.9332],[-94.4174,47.9477],[-94.4172,47.9623],[-94.4173,47.9769],[-94.4176,47.9914],[-94.4177,48.006],[-94.4176,48.02],[-94.4236,48.0199],[-94.4241,48.0344],[-94.4246,48.0489],[-94.4247,48.0632],[-94.4234,48.0776],[-94.4231,48.092],[-94.4233,48.1059],[-94.4234,48.1204],[-94.4236,48.1348],[-94.4233,48.1491],[-94.4235,48.1637],[-94.4235,48.1781],[-94.4233,48.1923],[-94.4236,48.2067],[-94.4238,48.2212],[-94.4237,48.2356],[-94.4237,48.2504],[-94.424,48.2649],[-94.4243,48.2791],[-94.4244,48.2938],[-94.4246,48.3081],[-94.4248,48.3227],[-94.425,48.3372],[-94.4253,48.352],[-94.4252,48.3675],[-94.4288,48.3675],[-94.4289,48.3821],[-94.4293,48.3964],[-94.4294,48.411],[-94.4293,48.4254],[-94.4292,48.4399],[-94.4293,48.4543],[-94.4296,48.4688],[-94.4296,48.4832],[-94.4299,48.4977],[-94.4303,48.512],[-94.4303,48.5264],[-94.43,48.5409],[-94.4295,48.5554],[-94.4291,48.5698],[-94.4289,48.5844],[-94.4289,48.5988],[-94.4292,48.6133],[-94.4294,48.6276],[-94.4297,48.642],[-94.43,48.6564],[-94.4301,48.6708],[-94.43,48.6852],[-94.4299,48.6998],[-94.4299,48.7012]]],"type":"Polygon"},"id":"36","properties":{"Area":8167237870.91888,"CTYONLY_":5,"Code":"KOOC","LASTMOD":"1999-12-31T23:59:59Z","Name":"Koochiching","Perimiter":412897.43594},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&filter=NOT%20CTYONLY_%20NOT%20IN%20(3%2C%205)","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&filter=NOT%20CTYONLY_%20NOT%20IN%20(3%2C%205)","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":2,"numberReturned":2,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_text_not_not_like.json.txt b/msautotest/api/expected/ogcapi_cql2_text_not_not_like.json.txt new file mode 100644 index 0000000000..9c5c1c1676 --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_text_not_not_like.json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 1 +OGC-NumberReturned: 1 + +{"features":[{"geometry":{"coordinates":[[[-93.5242,44.5436],[-93.5225,44.5436],[-93.504,44.5438],[-93.5018,44.5438],[-93.4835,44.5438],[-93.4817,44.5438],[-93.4734,44.5438],[-93.4632,44.5438],[-93.4609,44.5438],[-93.4429,44.5438],[-93.4408,44.5438],[-93.4326,44.5438],[-93.4226,44.5439],[-93.4206,44.5439],[-93.4024,44.5439],[-93.4003,44.5439],[-93.383,44.544],[-93.38,44.544],[-93.3627,44.5441],[-93.3596,44.5441],[-93.3556,44.5441],[-93.3424,44.5442],[-93.3395,44.5442],[-93.3221,44.544],[-93.3191,44.544],[-93.3128,44.544],[-93.3019,44.544],[-93.2988,44.544],[-93.2813,44.544],[-93.2814,44.5298],[-93.2815,44.5153],[-93.2815,44.501],[-93.2815,44.4865],[-93.2817,44.472],[-93.2618,44.4718],[-93.2415,44.4716],[-93.2213,44.4714],[-93.2008,44.4714],[-93.1808,44.4713],[-93.1605,44.4713],[-93.1408,44.4712],[-93.1206,44.4713],[-93.1002,44.4718],[-93.0799,44.4719],[-93.0597,44.4718],[-93.0393,44.4719],[-93.0394,44.4576],[-93.0396,44.4432],[-93.0397,44.4287],[-93.0399,44.4143],[-93.04,44.3999],[-93.0401,44.3855],[-93.0402,44.371],[-93.0403,44.3565],[-93.0403,44.3419],[-93.0405,44.3273],[-93.0405,44.3129],[-93.0405,44.2983],[-93.0406,44.2838],[-93.0407,44.2693],[-93.0409,44.2548],[-93.041,44.2402],[-93.0411,44.2257],[-93.0411,44.2113],[-93.0411,44.1968],[-93.0427,44.1968],[-93.0459,44.1968],[-93.0613,44.1967],[-93.0661,44.1967],[-93.0815,44.1967],[-93.0862,44.1967],[-93.1003,44.1967],[-93.1015,44.1967],[-93.1063,44.1967],[-93.1092,44.1967],[-93.1218,44.1967],[-93.1267,44.1967],[-93.1301,44.1967],[-93.1418,44.1967],[-93.1467,44.1967],[-93.1561,44.1966],[-93.1622,44.1966],[-93.1661,44.1966],[-93.1703,44.1966],[-93.1822,44.1966],[-93.1856,44.1966],[-93.1865,44.1966],[-93.2023,44.1966],[-93.2037,44.1966],[-93.2064,44.1966],[-93.2225,44.1966],[-93.2265,44.1966],[-93.2292,44.1966],[-93.2426,44.1966],[-93.2465,44.1966],[-93.255,44.1966],[-93.2629,44.1966],[-93.2664,44.1966],[-93.2767,44.1966],[-93.283,44.1966],[-93.2865,44.1965],[-93.2905,44.1965],[-93.3032,44.1965],[-93.3063,44.1965],[-93.3235,44.1965],[-93.3264,44.1965],[-93.3277,44.1965],[-93.3436,44.1965],[-93.3466,44.1965],[-93.3639,44.1965],[-93.3666,44.1965],[-93.3842,44.1965],[-93.3866,44.1965],[-93.4042,44.1965],[-93.4065,44.1965],[-93.4244,44.1964],[-93.4267,44.1964],[-93.4447,44.1964],[-93.4469,44.1964],[-93.4648,44.1963],[-93.467,44.1963],[-93.4852,44.1964],[-93.4872,44.1964],[-93.5053,44.1963],[-93.507,44.1963],[-93.5255,44.1962],[-93.5253,44.2107],[-93.5251,44.2251],[-93.5251,44.2388],[-93.5251,44.2533],[-93.5252,44.2685],[-93.5252,44.2829],[-93.5252,44.2975],[-93.5252,44.312],[-93.5249,44.3266],[-93.5249,44.3411],[-93.5245,44.3557],[-93.5245,44.3704],[-93.5246,44.3848],[-93.5245,44.3994],[-93.5245,44.4138],[-93.5245,44.4283],[-93.5245,44.4427],[-93.5245,44.4572],[-93.5244,44.4717],[-93.5245,44.4862],[-93.5244,44.5007],[-93.5243,44.5152],[-93.5244,44.5297],[-93.5242,44.5436]]],"type":"Polygon"},"id":"66","properties":{"Area":1335114621.00336,"CTYONLY_":66,"Code":"RICE","LASTMOD":"2010-10-17T00:00:00Z","Name":"Rice","Perimiter":154431.78788},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&filter=NOT%20Name%20NOT%20LIKE%20'Rice'","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&filter=NOT%20Name%20NOT%20LIKE%20'Rice'","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":1,"numberReturned":1,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_text_or_false.json.txt b/msautotest/api/expected/ogcapi_cql2_text_or_false.json.txt new file mode 100644 index 0000000000..319da5c930 --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_text_or_false.json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 0 +OGC-NumberReturned: 0 + +{"features":[],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&filter=0%3D1%20OR%201%3D0","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&filter=0%3D1%20OR%201%3D0","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":0,"numberReturned":0,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_text_or_true.json.txt b/msautotest/api/expected/ogcapi_cql2_text_or_true.json.txt new file mode 100644 index 0000000000..6bd94b23e7 --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_text_or_true.json.txt @@ -0,0 +1,9 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +Link: ; rel="next"; title="next page"; type="application/geo+json" +OGC-NumberMatched: 117 +OGC-NumberReturned: 9 + +{"features":[{"geometry":{"coordinates":[[[-95.3231,48.999],[-95.3109,48.999],[-95.2889,48.9989],[-95.2852,48.9989],[-95.2669,48.9989],[-95.245,48.9989],[-95.2232,48.9989],[-95.2014,48.9989],[-95.1792,48.9989],[-95.1574,48.9989],[-95.1531,48.9989],[-95.1531,49.0031],[-95.1532,49.0179],[-95.1532,49.0325],[-95.1532,49.047],[-95.1532,49.0619],[-95.1532,49.0765],[-95.1532,49.0911],[-95.1532,49.1057],[-95.1532,49.1205],[-95.1532,49.1354],[-95.1532,49.1499],[-95.1532,49.1642],[-95.1532,49.1788],[-95.1532,49.1807],[-95.1532,49.1931],[-95.1532,49.1966],[-95.1532,49.2077],[-95.1533,49.2131],[-95.1533,49.2219],[-95.1533,49.2308],[-95.1533,49.2365],[-95.1533,49.2472],[-95.1533,49.2512],[-95.1533,49.2655],[-95.1533,49.2697],[-95.1533,49.2802],[-95.1533,49.2882],[-95.1533,49.2945],[-95.1533,49.3072],[-95.1533,49.309],[-95.1533,49.3234],[-95.1533,49.3237],[-95.1533,49.3381],[-95.1533,49.3476],[-95.1533,49.3525],[-95.1533,49.3636],[-95.1533,49.367],[-95.1533,49.3705],[-95.1533,49.3776],[-95.1533,49.3813],[-95.1533,49.3845],[-95.1503,49.383],[-95.1499,49.3813],[-95.1498,49.3807],[-95.1467,49.3802],[-95.145,49.3784],[-95.1418,49.3784],[-95.1397,49.3762],[-95.1367,49.3751],[-95.1324,49.3736],[-95.1287,49.3705],[-95.1171,49.367],[-95.1159,49.3666],[-95.1145,49.3666],[-95.1098,49.3664],[-95.1031,49.3652],[-95.1031,49.3636],[-95.0926,49.3617],[-95.0897,49.3612],[-95.0707,49.3564],[-95.0582,49.3533],[-95.0495,49.3532],[-95.0479,49.3533],[-95.0262,49.3554],[-95.0141,49.3565],[-95.0047,49.3612],[-94.993,49.367],[-94.9889,49.369],[-94.9818,49.3684],[-94.9742,49.3678],[-94.9597,49.3699],[-94.9573,49.3702],[-94.952,49.3688],[-94.948,49.367],[-94.9376,49.3625],[-94.9152,49.3529],[-94.9143,49.3524],[-94.909,49.3502],[-94.9065,49.3484],[-94.8933,49.3414],[-94.8865,49.3378],[-94.8782,49.3334],[-94.8712,49.3308],[-94.854,49.3244],[-94.8492,49.3244],[-94.8363,49.3243],[-94.8311,49.3236],[-94.8271,49.323],[-94.8162,49.3214],[-94.8243,49.309],[-94.8243,49.3088],[-94.8255,49.2944],[-94.8255,49.2943],[-94.8204,49.28],[-94.8152,49.2653],[-94.8103,49.2515],[-94.8059,49.2388],[-94.8051,49.2367],[-94.8001,49.2224],[-94.7973,49.2144],[-94.7975,49.2079],[-94.7979,49.1979],[-94.7965,49.1936],[-94.7918,49.1792],[-94.7871,49.1646],[-94.7833,49.153],[-94.7823,49.15],[-94.7776,49.1357],[-94.7727,49.1206],[-94.7727,49.1206],[-94.7611,49.1096],[-94.7571,49.1058],[-94.7496,49.0988],[-94.7474,49.0918],[-94.7429,49.0773],[-94.7394,49.0657],[-94.7385,49.063],[-94.7344,49.0497],[-94.7299,49.0351],[-94.7254,49.0205],[-94.7207,49.0052],[-94.7184,48.9979],[-94.7162,48.9907],[-94.7117,48.9761],[-94.7072,48.9615],[-94.7027,48.9468],[-94.6982,48.9322],[-94.6968,48.9276],[-94.6844,48.8875],[-94.6834,48.8842],[-94.6842,48.8724],[-94.6855,48.8719],[-94.6923,48.8691],[-94.6902,48.8636],[-94.6914,48.8591],[-94.693,48.8535],[-94.6881,48.8447],[-94.6855,48.8401],[-94.6963,48.836],[-94.6975,48.8355],[-94.702,48.8319],[-94.7025,48.8302],[-94.7042,48.8243],[-94.6991,48.8159],[-94.6962,48.8111],[-94.6951,48.8092],[-94.6958,48.8012],[-94.6959,48.7997],[-94.6944,48.7895],[-94.6934,48.7864],[-94.6909,48.7781],[-94.687,48.7752],[-94.6776,48.772],[-94.6768,48.7717],[-94.6746,48.7705],[-94.6671,48.7662],[-94.6603,48.7605],[-94.6557,48.7581],[-94.6525,48.7565],[-94.652,48.7562],[-94.6453,48.7491],[-94.6453,48.7441],[-94.6443,48.7434],[-94.6414,48.7413],[-94.631,48.7392],[-94.6301,48.739],[-94.6191,48.7373],[-94.6106,48.7318],[-94.6084,48.731],[-94.6028,48.7289],[-94.6011,48.7283],[-94.5962,48.7248],[-94.5913,48.7197],[-94.5876,48.7176],[-94.5867,48.7175],[-94.5685,48.7156],[-94.5622,48.7159],[-94.5558,48.7163],[-94.549,48.7148],[-94.5487,48.7146],[-94.5457,48.7124],[-94.5396,48.7036],[-94.539,48.7028],[-94.5329,48.7013],[-94.5247,48.7016],[-94.5178,48.7008],[-94.5173,48.7008],[-94.5093,48.7006],[-94.5066,48.6999],[-94.4996,48.698],[-94.4958,48.698],[-94.4863,48.698],[-94.4739,48.6969],[-94.4706,48.6966],[-94.4631,48.6953],[-94.4568,48.6933],[-94.4523,48.6925],[-94.4517,48.6925],[-94.4465,48.693],[-94.4388,48.6949],[-94.4319,48.6998],[-94.4299,48.7012],[-94.4299,48.6998],[-94.43,48.6852],[-94.4301,48.6708],[-94.43,48.6564],[-94.4297,48.642],[-94.4294,48.6276],[-94.4292,48.6133],[-94.4289,48.5988],[-94.4289,48.5844],[-94.4291,48.5698],[-94.4295,48.5554],[-94.43,48.5409],[-94.4303,48.5264],[-94.4303,48.512],[-94.4299,48.4977],[-94.4296,48.4832],[-94.4296,48.4688],[-94.4293,48.4543],[-94.4292,48.4399],[-94.4293,48.4254],[-94.4294,48.411],[-94.4293,48.3964],[-94.4289,48.3821],[-94.4288,48.3675],[-94.4471,48.3675],[-94.4505,48.3675],[-94.4688,48.3675],[-94.4722,48.3674],[-94.4906,48.3674],[-94.4924,48.3674],[-94.4941,48.3674],[-94.5118,48.3675],[-94.5157,48.3674],[-94.5335,48.3674],[-94.5378,48.3674],[-94.5536,48.3674],[-94.5593,48.3674],[-94.5754,48.3674],[-94.5812,48.3674],[-94.5971,48.3675],[-94.6029,48.3674],[-94.6188,48.3673],[-94.6245,48.3673],[-94.6405,48.3673],[-94.6465,48.3673],[-94.6505,48.3673],[-94.6622,48.3673],[-94.6679,48.3673],[-94.6694,48.3672],[-94.683,48.3671],[-94.6898,48.3671],[-94.7099,48.3669],[-94.7117,48.3668],[-94.7315,48.3669],[-94.7329,48.3669],[-94.7533,48.3669],[-94.7549,48.3669],[-94.7748,48.3669],[-94.7765,48.3669],[-94.7967,48.3669],[-94.7983,48.3669],[-94.8183,48.3669],[-94.8199,48.3669],[-94.8399,48.3669],[-94.8416,48.3669],[-94.8616,48.3667],[-94.8632,48.3667],[-94.8833,48.3667],[-94.8849,48.3666],[-94.9049,48.3666],[-94.9065,48.3666],[-94.9264,48.3667],[-94.9283,48.3667],[-94.9469,48.3666],[-94.95,48.3666],[-94.9684,48.3667],[-94.9716,48.3667],[-94.9901,48.3667],[-94.9932,48.3667],[-95.0119,48.3665],[-95.0153,48.3665],[-95.0337,48.3665],[-95.0369,48.3665],[-95.0555,48.3665],[-95.0586,48.3665],[-95.0773,48.3664],[-95.0801,48.3664],[-95.099,48.3663],[-95.1008,48.3663],[-95.1018,48.3663],[-95.1207,48.3663],[-95.1236,48.3663],[-95.1315,48.3662],[-95.1424,48.3662],[-95.1454,48.3662],[-95.164,48.3661],[-95.1669,48.3661],[-95.1861,48.3661],[-95.1887,48.3661],[-95.1983,48.3661],[-95.2066,48.3661],[-95.2106,48.3661],[-95.211,48.3797],[-95.211,48.3808],[-95.2111,48.3941],[-95.2111,48.3952],[-95.2112,48.4087],[-95.2112,48.4096],[-95.2113,48.4232],[-95.2113,48.4242],[-95.2113,48.4255],[-95.2113,48.4376],[-95.2113,48.4387],[-95.2113,48.4522],[-95.2112,48.4529],[-95.211,48.4666],[-95.211,48.4673],[-95.2111,48.4816],[-95.2112,48.4962],[-95.2111,48.5101],[-95.2111,48.5109],[-95.2115,48.5244],[-95.2115,48.5252],[-95.2119,48.54],[-95.2324,48.5399],[-95.2339,48.5399],[-95.2537,48.5398],[-95.2554,48.5398],[-95.2756,48.54],[-95.2773,48.54],[-95.2975,48.5401],[-95.2992,48.5402],[-95.3194,48.54],[-95.321,48.54],[-95.3412,48.5402],[-95.3425,48.5402],[-95.3424,48.5548],[-95.3423,48.5691],[-95.3423,48.5836],[-95.3426,48.5979],[-95.3424,48.6127],[-95.3426,48.6271],[-95.3425,48.6415],[-95.3424,48.6561],[-95.3423,48.6705],[-95.3424,48.6849],[-95.3425,48.6995],[-95.3425,48.7131],[-95.3302,48.713],[-95.3205,48.713],[-95.3084,48.713],[-95.3051,48.713],[-95.299,48.713],[-95.2866,48.713],[-95.2767,48.713],[-95.2656,48.713],[-95.2645,48.713],[-95.255,48.713],[-95.2427,48.713],[-95.2331,48.713],[-95.2206,48.713],[-95.2112,48.713],[-95.1991,48.713],[-95.1917,48.713],[-95.1773,48.713],[-95.1697,48.7129],[-95.1554,48.7129],[-95.1477,48.7129],[-95.1333,48.713],[-95.1297,48.713],[-95.1259,48.7129],[-95.1119,48.7129],[-95.1104,48.7129],[-95.1046,48.7129],[-95.0898,48.713],[-95.0899,48.7277],[-95.0901,48.7421],[-95.0901,48.7566],[-95.0903,48.7711],[-95.0903,48.7855],[-95.0903,48.8],[-95.0909,48.8147],[-95.0908,48.8291],[-95.0907,48.8436],[-95.0908,48.858],[-95.0908,48.8724],[-95.0911,48.8869],[-95.0912,48.9014],[-95.0914,48.916],[-95.0914,48.9208],[-95.0919,48.9207],[-95.0927,48.9204],[-95.0944,48.9193],[-95.0946,48.9191],[-95.0961,48.9181],[-95.097,48.9176],[-95.0971,48.9172],[-95.0975,48.9164],[-95.098,48.916],[-95.0981,48.9159],[-95.1008,48.9142],[-95.102,48.9132],[-95.1032,48.9127],[-95.1042,48.9121],[-95.1056,48.9113],[-95.108,48.9099],[-95.1096,48.9089],[-95.1107,48.9082],[-95.1126,48.9073],[-95.113,48.9072],[-95.1132,48.9071],[-95.1137,48.9069],[-95.1141,48.9064],[-95.114,48.9061],[-95.1144,48.9052],[-95.1151,48.9046],[-95.1163,48.9037],[-95.1182,48.9029],[-95.1204,48.9019],[-95.1205,48.9017],[-95.121,48.9016],[-95.1214,48.9013],[-95.1228,48.9006],[-95.1233,48.9004],[-95.1239,48.9001],[-95.1252,48.8998],[-95.1312,48.8975],[-95.1322,48.8973],[-95.1337,48.8969],[-95.1343,48.8963],[-95.1348,48.8963],[-95.1351,48.8963],[-95.1355,48.8959],[-95.1381,48.8949],[-95.1404,48.8943],[-95.1436,48.8937],[-95.1438,48.8934],[-95.1459,48.8929],[-95.1469,48.8927],[-95.1483,48.8923],[-95.1508,48.8922],[-95.1528,48.8921],[-95.1555,48.892],[-95.1564,48.8919],[-95.1579,48.8919],[-95.1602,48.892],[-95.1618,48.892],[-95.1641,48.8917],[-95.1648,48.8913],[-95.1674,48.8907],[-95.1701,48.8902],[-95.173,48.8897],[-95.1764,48.8893],[-95.1791,48.889],[-95.1797,48.889],[-95.1819,48.8888],[-95.1851,48.8882],[-95.1863,48.8877],[-95.1877,48.8874],[-95.1889,48.8873],[-95.1901,48.887],[-95.1913,48.8868],[-95.1919,48.8866],[-95.1924,48.8865],[-95.1956,48.8862],[-95.1986,48.8855],[-95.2005,48.8856],[-95.2009,48.8855],[-95.2024,48.8852],[-95.2059,48.8848],[-95.2085,48.8846],[-95.2112,48.8848],[-95.2115,48.8847],[-95.2117,48.8847],[-95.2122,48.8842],[-95.2144,48.8843],[-95.2151,48.884],[-95.2159,48.8839],[-95.217,48.8835],[-95.2188,48.8835],[-95.2193,48.8832],[-95.22,48.8831],[-95.2207,48.8831],[-95.2208,48.8831],[-95.2212,48.883],[-95.2252,48.8819],[-95.2265,48.8816],[-95.2287,48.8815],[-95.231,48.8814],[-95.2335,48.8814],[-95.2356,48.8815],[-95.2381,48.8817],[-95.2391,48.8819],[-95.2407,48.8821],[-95.2423,48.8821],[-95.2429,48.8822],[-95.2429,48.8822],[-95.2439,48.8823],[-95.2458,48.8829],[-95.2472,48.8835],[-95.248,48.8836],[-95.2485,48.8832],[-95.2496,48.8834],[-95.2502,48.8835],[-95.2507,48.8836],[-95.2517,48.8839],[-95.2548,48.8845],[-95.256,48.885],[-95.257,48.8858],[-95.2585,48.8867],[-95.2585,48.8867],[-95.2627,48.8877],[-95.2635,48.888],[-95.2639,48.8883],[-95.2646,48.8885],[-95.265,48.8886],[-95.2654,48.8888],[-95.2666,48.8894],[-95.2674,48.89],[-95.2677,48.8903],[-95.268,48.8905],[-95.2713,48.8915],[-95.2724,48.8921],[-95.2745,48.8931],[-95.2751,48.8938],[-95.2753,48.8943],[-95.2748,48.8951],[-95.2749,48.8956],[-95.2755,48.8959],[-95.2759,48.8962],[-95.2763,48.8963],[-95.2765,48.8962],[-95.277,48.8958],[-95.2773,48.8957],[-95.2782,48.8956],[-95.279,48.8957],[-95.2796,48.8962],[-95.2803,48.8965],[-95.2813,48.8967],[-95.2839,48.8975],[-95.2853,48.8977],[-95.2861,48.8976],[-95.2865,48.8975],[-95.287,48.8976],[-95.2872,48.8977],[-95.2879,48.8979],[-95.2882,48.8981],[-95.289,48.8994],[-95.2896,48.9],[-95.2901,48.9003],[-95.2911,48.9006],[-95.2911,48.9008],[-95.2906,48.9011],[-95.2907,48.9014],[-95.2908,48.9016],[-95.2909,48.9017],[-95.2914,48.9019],[-95.2927,48.9019],[-95.2935,48.902],[-95.2937,48.9023],[-95.2941,48.9027],[-95.2949,48.9028],[-95.2967,48.9027],[-95.2976,48.9026],[-95.298,48.9027],[-95.2983,48.9028],[-95.2993,48.9035],[-95.3005,48.904],[-95.3002,48.9045],[-95.3001,48.9046],[-95.3001,48.9047],[-95.3,48.9047],[-95.3,48.9047],[-95.2999,48.9048],[-95.2999,48.9048],[-95.2999,48.9048],[-95.2997,48.905],[-95.2996,48.9051],[-95.2994,48.9053],[-95.2992,48.9055],[-95.2991,48.9057],[-95.2989,48.906],[-95.2988,48.906],[-95.2986,48.9063],[-95.2985,48.9064],[-95.2985,48.9065],[-95.2983,48.9068],[-95.2982,48.9068],[-95.2981,48.907],[-95.298,48.9071],[-95.298,48.9071],[-95.298,48.9071],[-95.2979,48.9071],[-95.2979,48.9072],[-95.2979,48.9072],[-95.2978,48.9072],[-95.2978,48.9072],[-95.2978,48.9073],[-95.2977,48.9073],[-95.2976,48.9074],[-95.2973,48.9077],[-95.2973,48.908],[-95.2973,48.9081],[-95.2978,48.9083],[-95.2999,48.9086],[-95.3017,48.9093],[-95.3027,48.91],[-95.3038,48.9114],[-95.3043,48.9119],[-95.3059,48.9127],[-95.3061,48.9128],[-95.3064,48.9129],[-95.3074,48.9135],[-95.3078,48.9141],[-95.3085,48.9146],[-95.3092,48.9149],[-95.3093,48.9149],[-95.3102,48.9155],[-95.3109,48.9163],[-95.3115,48.9172],[-95.3119,48.9178],[-95.3126,48.919],[-95.3132,48.9198],[-95.3141,48.921],[-95.315,48.9222],[-95.3168,48.9245],[-95.3195,48.9285],[-95.3208,48.9305],[-95.3209,48.9307],[-95.3222,48.9327],[-95.3228,48.9344],[-95.3223,48.9355],[-95.3225,48.9358],[-95.3229,48.9373],[-95.3231,48.9389],[-95.3228,48.9403],[-95.3225,48.9409],[-95.3219,48.9412],[-95.3189,48.9419],[-95.3181,48.9421],[-95.3168,48.9431],[-95.3154,48.9448],[-95.3148,48.9452],[-95.3141,48.9457],[-95.3131,48.946],[-95.3114,48.9461],[-95.3102,48.9463],[-95.3095,48.9463],[-95.3088,48.9464],[-95.3086,48.9465],[-95.3086,48.9469],[-95.3085,48.947],[-95.3078,48.9466],[-95.3074,48.9465],[-95.3071,48.9466],[-95.3071,48.9469],[-95.3079,48.9474],[-95.3092,48.9477],[-95.3096,48.9478],[-95.3103,48.948],[-95.3104,48.9484],[-95.3103,48.9485],[-95.31,48.9485],[-95.3099,48.9484],[-95.3096,48.9482],[-95.3094,48.9481],[-95.3081,48.948],[-95.3071,48.9477],[-95.3062,48.9472],[-95.3062,48.9472],[-95.3061,48.9469],[-95.3062,48.9463],[-95.3063,48.9462],[-95.3069,48.9456],[-95.3069,48.9455],[-95.3068,48.9454],[-95.3061,48.9454],[-95.3053,48.9459],[-95.305,48.9462],[-95.3046,48.947],[-95.3046,48.9482],[-95.3052,48.9495],[-95.3061,48.9502],[-95.3079,48.9509],[-95.3089,48.9511],[-95.3097,48.951],[-95.3104,48.951],[-95.3108,48.9512],[-95.3115,48.952],[-95.312,48.9524],[-95.3126,48.9524],[-95.3129,48.9523],[-95.3129,48.9521],[-95.3119,48.9507],[-95.3119,48.9502],[-95.3123,48.9502],[-95.3125,48.9503],[-95.3131,48.9503],[-95.3141,48.9508],[-95.3151,48.951],[-95.3154,48.9513],[-95.3177,48.9525],[-95.3181,48.9531],[-95.3182,48.9535],[-95.3177,48.9545],[-95.3175,48.9552],[-95.3179,48.9559],[-95.3188,48.9562],[-95.3191,48.9569],[-95.3202,48.9581],[-95.3206,48.959],[-95.3206,48.9595],[-95.3206,48.9598],[-95.3202,48.9606],[-95.3193,48.9622],[-95.3193,48.964],[-95.3198,48.9643],[-95.3201,48.9648],[-95.3207,48.9669],[-95.3212,48.9672],[-95.3227,48.9685],[-95.3232,48.9692],[-95.3241,48.9703],[-95.3247,48.972],[-95.3248,48.9728],[-95.3249,48.9738],[-95.325,48.9743],[-95.3253,48.976],[-95.3257,48.9784],[-95.3255,48.9789],[-95.3256,48.98],[-95.3257,48.9814],[-95.3253,48.9832],[-95.3245,48.985],[-95.3242,48.9859],[-95.3227,48.9884],[-95.3224,48.9889],[-95.3206,48.9921],[-95.3204,48.9924],[-95.3191,48.9941],[-95.3181,48.995],[-95.3178,48.9958],[-95.3178,48.9961],[-95.3179,48.9961],[-95.3182,48.996],[-95.3187,48.9956],[-95.3191,48.9953],[-95.3197,48.9954],[-95.3201,48.9956],[-95.3206,48.9961],[-95.3204,48.9964],[-95.3202,48.9973],[-95.3204,48.9976],[-95.3224,48.9984],[-95.3231,48.999]]],"type":"Polygon"},"id":"39","properties":{"Area":4608320923.49768,"CTYONLY_":2,"Code":"LOTW","LASTMOD":"1976-07-04T12:00:00Z","Name":"Lake of the Woods","Perimiter":388250.14572},"type":"Feature"},{"geometry":{"coordinates":[[[-96.4054,49.0001],[-96.4054,48.9947],[-96.4054,48.994],[-96.4054,48.9803],[-96.4054,48.9793],[-96.4053,48.9705],[-96.4053,48.9658],[-96.4053,48.9648],[-96.4053,48.9515],[-96.4053,48.9504],[-96.4053,48.9371],[-96.4053,48.936],[-96.4054,48.9225],[-96.4054,48.9214],[-96.4053,48.9137],[-96.4053,48.9081],[-96.4053,48.9068],[-96.405,48.8926],[-96.405,48.878],[-96.4047,48.8635],[-96.4045,48.8491],[-96.4043,48.8343],[-96.4042,48.8198],[-96.4042,48.8048],[-96.4042,48.7903],[-96.4045,48.7758],[-96.4047,48.7607],[-96.4048,48.7465],[-96.4048,48.7318],[-96.4049,48.7172],[-96.388,48.7172],[-96.3873,48.7172],[-96.3866,48.703],[-96.3874,48.6887],[-96.3871,48.6741],[-96.3877,48.6599],[-96.3879,48.6454],[-96.388,48.6313],[-96.389,48.6165],[-96.3891,48.6024],[-96.3884,48.5877],[-96.3882,48.5733],[-96.3879,48.5588],[-96.3882,48.5442],[-96.4101,48.544],[-96.4318,48.5438],[-96.4535,48.5436],[-96.4754,48.5435],[-96.4973,48.5434],[-96.518,48.5434],[-96.54,48.5434],[-96.5621,48.5436],[-96.5839,48.5437],[-96.6058,48.5437],[-96.6278,48.5437],[-96.6493,48.5437],[-96.6713,48.5436],[-96.6931,48.5437],[-96.7151,48.5437],[-96.7368,48.5437],[-96.7585,48.5436],[-96.7803,48.5435],[-96.8023,48.5436],[-96.824,48.5436],[-96.8459,48.5434],[-96.8678,48.5433],[-96.8896,48.5433],[-96.9115,48.5432],[-96.9138,48.5433],[-96.9331,48.5435],[-96.9551,48.5437],[-96.9768,48.544],[-96.9985,48.5441],[-97.0194,48.5441],[-97.0416,48.5442],[-97.0635,48.5441],[-97.0852,48.5441],[-97.107,48.544],[-97.1287,48.5439],[-97.1509,48.5439],[-97.1631,48.544],[-97.1637,48.5445],[-97.1659,48.5483],[-97.1662,48.5509],[-97.1661,48.5527],[-97.1654,48.5536],[-97.1645,48.554],[-97.1628,48.5543],[-97.1613,48.5539],[-97.1592,48.5528],[-97.1577,48.5518],[-97.1557,48.5512],[-97.1538,48.5513],[-97.1513,48.5515],[-97.1507,48.5515],[-97.1493,48.5516],[-97.1474,48.5516],[-97.1444,48.5514],[-97.1407,48.5515],[-97.1387,48.5522],[-97.1379,48.553],[-97.1379,48.5542],[-97.1391,48.5554],[-97.141,48.5566],[-97.1426,48.5571],[-97.1464,48.5573],[-97.1505,48.5574],[-97.1515,48.5574],[-97.1551,48.5574],[-97.1578,48.5573],[-97.1606,48.5571],[-97.1631,48.5571],[-97.1646,48.5572],[-97.167,48.5575],[-97.1697,48.5584],[-97.1721,48.5591],[-97.1727,48.5593],[-97.174,48.5599],[-97.1749,48.5606],[-97.1753,48.5614],[-97.1754,48.5623],[-97.1749,48.5631],[-97.1744,48.5639],[-97.1723,48.5648],[-97.1721,48.5648],[-97.1706,48.5652],[-97.1687,48.5655],[-97.167,48.5658],[-97.1651,48.5659],[-97.1613,48.5661],[-97.1541,48.5669],[-97.153,48.5671],[-97.1516,48.5677],[-97.1503,48.5688],[-97.1496,48.5695],[-97.1487,48.5707],[-97.1477,48.5727],[-97.1477,48.5728],[-97.1476,48.5731],[-97.1483,48.5763],[-97.15,48.5775],[-97.1501,48.5775],[-97.1548,48.5779],[-97.1592,48.5785],[-97.1605,48.58],[-97.16,48.5816],[-97.1578,48.5826],[-97.1562,48.5828],[-97.1541,48.5826],[-97.1524,48.5823],[-97.15,48.5815],[-97.1494,48.5813],[-97.1484,48.5811],[-97.1449,48.5815],[-97.1436,48.5824],[-97.1431,48.5834],[-97.1429,48.5838],[-97.142,48.5876],[-97.1418,48.5886],[-97.1415,48.5909],[-97.1422,48.5926],[-97.1433,48.5936],[-97.1451,48.594],[-97.1471,48.594],[-97.1497,48.5937],[-97.1525,48.594],[-97.1536,48.5949],[-97.1535,48.5957],[-97.1527,48.5962],[-97.1524,48.5969],[-97.1516,48.598],[-97.1498,48.5981],[-97.1497,48.5981],[-97.1463,48.5977],[-97.1443,48.5981],[-97.143,48.5987],[-97.1416,48.6002],[-97.1403,48.6021],[-97.14,48.6025],[-97.138,48.6044],[-97.1359,48.6054],[-97.1345,48.6065],[-97.1341,48.6075],[-97.1349,48.6082],[-97.1358,48.6086],[-97.137,48.6088],[-97.1396,48.6086],[-97.1443,48.6078],[-97.1474,48.6081],[-97.1494,48.6089],[-97.1495,48.609],[-97.1505,48.6115],[-97.1501,48.6124],[-97.1493,48.6129],[-97.1478,48.6138],[-97.145,48.6146],[-97.1408,48.6149],[-97.137,48.6144],[-97.134,48.6136],[-97.1319,48.6133],[-97.1309,48.6137],[-97.1289,48.614],[-97.1286,48.6153],[-97.1293,48.6168],[-97.1295,48.617],[-97.1311,48.6184],[-97.1342,48.6199],[-97.1353,48.6212],[-97.1346,48.6224],[-97.133,48.6228],[-97.131,48.6227],[-97.1291,48.6222],[-97.1277,48.6212],[-97.1274,48.621],[-97.1259,48.6195],[-97.1253,48.619],[-97.1243,48.6183],[-97.1231,48.6178],[-97.1216,48.6176],[-97.12,48.6178],[-97.1193,48.6182],[-97.1186,48.6191],[-97.1183,48.6198],[-97.1186,48.6209],[-97.1198,48.6221],[-97.1209,48.6232],[-97.1212,48.6233],[-97.122,48.624],[-97.1228,48.6245],[-97.1236,48.625],[-97.1241,48.6254],[-97.1245,48.6257],[-97.1249,48.6259],[-97.1253,48.6261],[-97.126,48.6264],[-97.1266,48.6266],[-97.1272,48.627],[-97.1279,48.6273],[-97.1288,48.6278],[-97.1296,48.6282],[-97.1302,48.6288],[-97.1305,48.6292],[-97.1307,48.6297],[-97.131,48.6303],[-97.131,48.6304],[-97.131,48.6308],[-97.131,48.6315],[-97.1309,48.6317],[-97.1307,48.6321],[-97.1304,48.6325],[-97.1301,48.6326],[-97.1297,48.6328],[-97.1293,48.6329],[-97.129,48.633],[-97.1281,48.6332],[-97.128,48.6333],[-97.1275,48.6333],[-97.1253,48.6334],[-97.1235,48.6333],[-97.1216,48.6327],[-97.1181,48.6308],[-97.1176,48.6307],[-97.115,48.6299],[-97.1133,48.63],[-97.1115,48.6303],[-97.1107,48.6308],[-97.1104,48.6309],[-97.1095,48.6315],[-97.1084,48.6327],[-97.1082,48.6344],[-97.1086,48.6363],[-97.1096,48.6389],[-97.1109,48.6407],[-97.1119,48.6416],[-97.1144,48.6433],[-97.115,48.6438],[-97.115,48.6446],[-97.1149,48.6452],[-97.1123,48.6457],[-97.1112,48.6459],[-97.1093,48.6465],[-97.1078,48.6478],[-97.1069,48.6491],[-97.1066,48.6501],[-97.1061,48.6519],[-97.1059,48.6527],[-97.1045,48.6545],[-97.1017,48.6563],[-97.0987,48.6593],[-97.0986,48.6604],[-97.0985,48.6613],[-97.0992,48.6625],[-97.1019,48.6636],[-97.106,48.663],[-97.1062,48.663],[-97.1082,48.6634],[-97.1087,48.6645],[-97.1061,48.6654],[-97.1057,48.6655],[-97.102,48.6667],[-97.1,48.668],[-97.0998,48.6714],[-97.1002,48.675],[-97.1003,48.6757],[-97.1008,48.6787],[-97.1011,48.6808],[-97.1003,48.6828],[-97.0985,48.683],[-97.0946,48.6822],[-97.0926,48.6821],[-97.0904,48.6828],[-97.0898,48.6841],[-97.0899,48.6852],[-97.091,48.6861],[-97.093,48.687],[-97.0951,48.6876],[-97.099,48.6884],[-97.1024,48.6893],[-97.103,48.6894],[-97.1059,48.6903],[-97.1064,48.6905],[-97.1086,48.6915],[-97.111,48.6939],[-97.113,48.6964],[-97.1148,48.6981],[-97.1182,48.7005],[-97.1198,48.7018],[-97.1201,48.7039],[-97.1194,48.7041],[-97.1182,48.7046],[-97.1143,48.7052],[-97.1117,48.7056],[-97.11,48.7063],[-97.1098,48.7083],[-97.1113,48.7094],[-97.1134,48.7101],[-97.1157,48.7105],[-97.1174,48.7111],[-97.119,48.7119],[-97.1212,48.7136],[-97.1223,48.716],[-97.1229,48.7168],[-97.1231,48.7172],[-97.1243,48.7192],[-97.1253,48.7201],[-97.1253,48.7203],[-97.126,48.7207],[-97.1263,48.7212],[-97.1272,48.7215],[-97.128,48.722],[-97.1282,48.7221],[-97.1288,48.7225],[-97.1297,48.7229],[-97.131,48.7233],[-97.1321,48.7238],[-97.1331,48.7242],[-97.1345,48.7248],[-97.136,48.7257],[-97.1369,48.7263],[-97.1375,48.727],[-97.1376,48.7274],[-97.1376,48.7278],[-97.1373,48.7283],[-97.137,48.7284],[-97.1365,48.7285],[-97.136,48.7287],[-97.1352,48.7287],[-97.1341,48.7289],[-97.1333,48.7291],[-97.1328,48.7292],[-97.132,48.7294],[-97.1312,48.7295],[-97.1308,48.7296],[-97.1299,48.7299],[-97.1294,48.7304],[-97.1288,48.7308],[-97.1286,48.7312],[-97.1286,48.7315],[-97.1286,48.7316],[-97.1286,48.7318],[-97.1285,48.7322],[-97.1286,48.7326],[-97.1286,48.7328],[-97.1287,48.7331],[-97.129,48.7335],[-97.1295,48.7339],[-97.1298,48.7341],[-97.1316,48.7347],[-97.1322,48.7348],[-97.1334,48.7347],[-97.1351,48.7345],[-97.1369,48.7345],[-97.1383,48.7345],[-97.1396,48.7347],[-97.1402,48.7349],[-97.1412,48.7354],[-97.1419,48.7359],[-97.1422,48.7367],[-97.1423,48.7372],[-97.1421,48.7381],[-97.1414,48.7385],[-97.1408,48.7387],[-97.1404,48.7389],[-97.1399,48.7393],[-97.1392,48.7397],[-97.1381,48.7408],[-97.1372,48.742],[-97.1366,48.7435],[-97.1365,48.745],[-97.1365,48.7459],[-97.1366,48.7466],[-97.1369,48.748],[-97.1375,48.7492],[-97.1379,48.75],[-97.1385,48.7504],[-97.1391,48.7507],[-97.1396,48.7508],[-97.1401,48.7509],[-97.141,48.751],[-97.142,48.751],[-97.143,48.7509],[-97.1444,48.7507],[-97.1457,48.7506],[-97.1466,48.7505],[-97.1476,48.7505],[-97.1491,48.7506],[-97.1497,48.7508],[-97.1503,48.7509],[-97.1515,48.7515],[-97.1521,48.752],[-97.153,48.7529],[-97.1539,48.7542],[-97.1545,48.7553],[-97.1547,48.7558],[-97.1548,48.7562],[-97.1548,48.7569],[-97.1548,48.7576],[-97.1546,48.758],[-97.1542,48.7587],[-97.1535,48.7593],[-97.1528,48.7598],[-97.1519,48.7601],[-97.1508,48.7605],[-97.1503,48.7606],[-97.1501,48.7607],[-97.1475,48.7616],[-97.1473,48.7617],[-97.1469,48.762],[-97.1462,48.7626],[-97.1461,48.7628],[-97.1459,48.7633],[-97.1456,48.7643],[-97.1456,48.765],[-97.146,48.7658],[-97.1476,48.7673],[-97.1487,48.7681],[-97.15,48.7692],[-97.1501,48.7693],[-97.1506,48.77],[-97.1512,48.7712],[-97.1519,48.7721],[-97.1525,48.7727],[-97.1529,48.7728],[-97.1559,48.7731],[-97.1567,48.7732],[-97.1578,48.7735],[-97.1582,48.7737],[-97.1587,48.7742],[-97.1589,48.7746],[-97.159,48.7751],[-97.159,48.7751],[-97.159,48.7754],[-97.1589,48.776],[-97.1584,48.7766],[-97.1579,48.7769],[-97.1573,48.7772],[-97.1557,48.7776],[-97.1544,48.7778],[-97.1534,48.778],[-97.1522,48.7783],[-97.1509,48.7787],[-97.1501,48.7789],[-97.1497,48.779],[-97.1483,48.7797],[-97.1477,48.7801],[-97.1473,48.7807],[-97.1472,48.7811],[-97.1473,48.7816],[-97.1478,48.7821],[-97.1486,48.7824],[-97.1495,48.7826],[-97.1501,48.7826],[-97.1503,48.7826],[-97.1513,48.7825],[-97.1533,48.7824],[-97.1547,48.7824],[-97.1559,48.7825],[-97.1571,48.7827],[-97.1583,48.783],[-97.1591,48.7834],[-97.1595,48.7838],[-97.1597,48.7843],[-97.1598,48.7848],[-97.1596,48.7853],[-97.1593,48.786],[-97.1591,48.7863],[-97.1586,48.7869],[-97.1577,48.7877],[-97.1574,48.7882],[-97.1573,48.7884],[-97.1572,48.7887],[-97.1571,48.7894],[-97.157,48.7895],[-97.157,48.7901],[-97.1572,48.7906],[-97.1575,48.7909],[-97.1581,48.7912],[-97.1586,48.7913],[-97.1592,48.7915],[-97.1595,48.7915],[-97.1611,48.7915],[-97.1618,48.7914],[-97.1645,48.7911],[-97.1648,48.7911],[-97.1657,48.7911],[-97.1664,48.7912],[-97.1672,48.7913],[-97.1714,48.7921],[-97.1718,48.7923],[-97.1721,48.7924],[-97.1731,48.7929],[-97.1737,48.7933],[-97.174,48.7937],[-97.1741,48.7942],[-97.1742,48.7947],[-97.1742,48.7951],[-97.1739,48.7954],[-97.1734,48.7958],[-97.1726,48.7963],[-97.1717,48.7966],[-97.1716,48.7966],[-97.171,48.7967],[-97.1701,48.7967],[-97.1688,48.7966],[-97.1673,48.7964],[-97.1665,48.7962],[-97.1654,48.7962],[-97.1648,48.7962],[-97.1638,48.7963],[-97.1631,48.7966],[-97.1625,48.7969],[-97.162,48.7974],[-97.1617,48.7979],[-97.1617,48.7984],[-97.1619,48.7988],[-97.1621,48.7994],[-97.1626,48.8001],[-97.1633,48.8007],[-97.1642,48.8011],[-97.1652,48.8014],[-97.166,48.8015],[-97.1668,48.8016],[-97.1675,48.8016],[-97.1685,48.8016],[-97.1698,48.8013],[-97.1706,48.8011],[-97.1714,48.8008],[-97.1715,48.8008],[-97.1724,48.8004],[-97.1731,48.8],[-97.1742,48.7992],[-97.175,48.7986],[-97.1754,48.7983],[-97.1757,48.798],[-97.1761,48.7977],[-97.1768,48.7974],[-97.1773,48.7973],[-97.1779,48.7972],[-97.1787,48.7972],[-97.1795,48.7972],[-97.1801,48.7973],[-97.1807,48.7975],[-97.1811,48.7978],[-97.1815,48.7982],[-97.1816,48.7986],[-97.1817,48.7991],[-97.1815,48.7995],[-97.1813,48.8],[-97.1808,48.8004],[-97.1801,48.8008],[-97.1791,48.8012],[-97.1779,48.8015],[-97.1769,48.8017],[-97.1764,48.8018],[-97.1756,48.8021],[-97.1748,48.8023],[-97.1725,48.8032],[-97.1713,48.8036],[-97.171,48.8037],[-97.1706,48.8039],[-97.1694,48.8043],[-97.1682,48.8046],[-97.1675,48.8048],[-97.1666,48.805],[-97.1655,48.8052],[-97.1638,48.8055],[-97.161,48.8059],[-97.1605,48.8061],[-97.1597,48.8064],[-97.159,48.8067],[-97.1583,48.8072],[-97.1579,48.8077],[-97.1577,48.8082],[-97.1576,48.8089],[-97.1578,48.8098],[-97.158,48.8104],[-97.1586,48.811],[-97.159,48.8111],[-97.161,48.8117],[-97.1617,48.8119],[-97.1625,48.812],[-97.1636,48.8121],[-97.1644,48.8121],[-97.1651,48.812],[-97.1666,48.8118],[-97.168,48.8116],[-97.169,48.8114],[-97.17,48.8114],[-97.1713,48.8115],[-97.1715,48.8115],[-97.1726,48.8117],[-97.1731,48.8118],[-97.174,48.8122],[-97.1761,48.8132],[-97.1776,48.8141],[-97.1784,48.8145],[-97.1797,48.8149],[-97.1807,48.8151],[-97.1821,48.8153],[-97.1828,48.8153],[-97.184,48.8152],[-97.1848,48.8151],[-97.186,48.8147],[-97.1868,48.8145],[-97.1873,48.8143],[-97.1879,48.8143],[-97.1883,48.8143],[-97.1889,48.8143],[-97.1894,48.8144],[-97.1898,48.8146],[-97.1901,48.8148],[-97.1903,48.8153],[-97.1904,48.8156],[-97.1903,48.8159],[-97.19,48.8163],[-97.1893,48.8167],[-97.1885,48.8171],[-97.1879,48.8173],[-97.1866,48.8176],[-97.1857,48.8177],[-97.1847,48.8179],[-97.184,48.8181],[-97.1833,48.8184],[-97.1817,48.8189],[-97.1809,48.8193],[-97.1801,48.8199],[-97.1793,48.8207],[-97.1787,48.8216],[-97.178,48.8232],[-97.1777,48.824],[-97.1776,48.8245],[-97.1777,48.8249],[-97.178,48.8255],[-97.1782,48.8258],[-97.1786,48.8262],[-97.1794,48.8268],[-97.1822,48.8288],[-97.1837,48.8299],[-97.1841,48.8304],[-97.1847,48.8314],[-97.1848,48.8319],[-97.1849,48.8326],[-97.1849,48.8327],[-97.1848,48.833],[-97.1846,48.8336],[-97.1842,48.8341],[-97.1837,48.8345],[-97.183,48.8348],[-97.1822,48.835],[-97.1813,48.8351],[-97.1799,48.8352],[-97.1783,48.8353],[-97.1779,48.8354],[-97.1772,48.8356],[-97.1757,48.8362],[-97.1753,48.8364],[-97.1747,48.8369],[-97.1742,48.8373],[-97.1739,48.8378],[-97.1738,48.8384],[-97.1738,48.839],[-97.1739,48.8406],[-97.1743,48.8427],[-97.1747,48.8438],[-97.175,48.8442],[-97.1755,48.8447],[-97.1761,48.8452],[-97.1767,48.8455],[-97.1771,48.8456],[-97.1779,48.8458],[-97.1795,48.8459],[-97.1808,48.846],[-97.1817,48.8462],[-97.1823,48.8464],[-97.1827,48.8468],[-97.1829,48.847],[-97.1829,48.8471],[-97.1829,48.8473],[-97.1826,48.8476],[-97.1821,48.8479],[-97.1816,48.848],[-97.1809,48.8481],[-97.1793,48.8482],[-97.178,48.8483],[-97.1767,48.8484],[-97.1759,48.8486],[-97.1753,48.8487],[-97.1747,48.849],[-97.1742,48.8493],[-97.1737,48.8497],[-97.1733,48.8502],[-97.173,48.8506],[-97.173,48.8508],[-97.173,48.8511],[-97.173,48.8516],[-97.1732,48.8522],[-97.1737,48.8527],[-97.1746,48.8534],[-97.1771,48.855],[-97.1784,48.8561],[-97.1786,48.8563],[-97.179,48.8569],[-97.1793,48.8576],[-97.1794,48.8583],[-97.1794,48.859],[-97.1792,48.8606],[-97.179,48.8615],[-97.179,48.862],[-97.1791,48.8626],[-97.1794,48.863],[-97.1801,48.8636],[-97.1811,48.864],[-97.1818,48.8641],[-97.1827,48.8641],[-97.1839,48.864],[-97.1855,48.8637],[-97.1871,48.8633],[-97.1877,48.8631],[-97.1883,48.8631],[-97.1891,48.8631],[-97.1896,48.8633],[-97.19,48.8635],[-97.1903,48.8639],[-97.1905,48.8644],[-97.1905,48.8648],[-97.1904,48.8651],[-97.1901,48.8657],[-97.1899,48.8661],[-97.1895,48.8665],[-97.189,48.867],[-97.1884,48.8675],[-97.1851,48.8694],[-97.1813,48.8718],[-97.1788,48.8736],[-97.1785,48.8738],[-97.1782,48.8741],[-97.1781,48.8743],[-97.1779,48.8745],[-97.1778,48.8747],[-97.1777,48.8749],[-97.1777,48.875],[-97.1778,48.875],[-97.1778,48.8754],[-97.1779,48.8757],[-97.1782,48.8761],[-97.1786,48.8765],[-97.1792,48.8769],[-97.1798,48.8771],[-97.1808,48.8772],[-97.1823,48.8772],[-97.1852,48.8768],[-97.1869,48.8765],[-97.1881,48.8765],[-97.1891,48.8766],[-97.1904,48.8769],[-97.1933,48.8779],[-97.1944,48.8783],[-97.1957,48.8788],[-97.1972,48.8794],[-97.1981,48.8799],[-97.1988,48.8805],[-97.1995,48.8812],[-97.1999,48.8818],[-97.1999,48.8821],[-97.2,48.8827],[-97.1998,48.8832],[-97.1997,48.8836],[-97.199,48.8845],[-97.1978,48.8859],[-97.1975,48.8865],[-97.1974,48.8868],[-97.1973,48.8872],[-97.1973,48.8874],[-97.1974,48.8877],[-97.1975,48.8881],[-97.1983,48.8889],[-97.2002,48.8903],[-97.2004,48.8904],[-97.2009,48.8908],[-97.2014,48.8912],[-97.2017,48.8915],[-97.2017,48.8919],[-97.2016,48.8922],[-97.2013,48.8925],[-97.201,48.8926],[-97.2001,48.8926],[-97.1994,48.8926],[-97.1985,48.8925],[-97.198,48.8924],[-97.1973,48.892],[-97.1957,48.8916],[-97.1946,48.8915],[-97.1944,48.8914],[-97.1937,48.8914],[-97.1927,48.8915],[-97.1921,48.8917],[-97.1916,48.8919],[-97.1905,48.8926],[-97.1901,48.8932],[-97.1898,48.8938],[-97.1897,48.8944],[-97.1897,48.8947],[-97.1898,48.8951],[-97.1899,48.8954],[-97.1903,48.896],[-97.1911,48.8967],[-97.1919,48.8974],[-97.1925,48.8979],[-97.1935,48.8985],[-97.1941,48.8988],[-97.1945,48.8989],[-97.1966,48.8997],[-97.1992,48.9004],[-97.2009,48.9009],[-97.2022,48.9013],[-97.2048,48.9018],[-97.2055,48.902],[-97.207,48.9025],[-97.2076,48.9027],[-97.2082,48.9029],[-97.2088,48.9032],[-97.2093,48.9036],[-97.21,48.904],[-97.2105,48.9044],[-97.211,48.905],[-97.2114,48.9056],[-97.2122,48.9069],[-97.2125,48.9075],[-97.2127,48.9082],[-97.2127,48.909],[-97.2125,48.9099],[-97.212,48.911],[-97.2116,48.9121],[-97.2111,48.913],[-97.2108,48.914],[-97.2106,48.9148],[-97.2106,48.9153],[-97.2109,48.9162],[-97.2111,48.9167],[-97.2115,48.9172],[-97.2118,48.9175],[-97.2122,48.9177],[-97.2129,48.9181],[-97.2149,48.9187],[-97.2163,48.9191],[-97.2164,48.9191],[-97.2171,48.9194],[-97.2179,48.9198],[-97.2189,48.9205],[-97.2196,48.9215],[-97.2198,48.9222],[-97.2199,48.923],[-97.2197,48.9237],[-97.2191,48.9249],[-97.2183,48.9262],[-97.2172,48.9277],[-97.2163,48.9286],[-97.2159,48.9289],[-97.2149,48.9301],[-97.2146,48.9304],[-97.2145,48.9307],[-97.2144,48.931],[-97.2145,48.9314],[-97.2145,48.9316],[-97.2148,48.9319],[-97.2154,48.9325],[-97.2159,48.9327],[-97.2162,48.9328],[-97.217,48.9328],[-97.2181,48.9327],[-97.2198,48.9325],[-97.2208,48.9325],[-97.2214,48.9325],[-97.2218,48.9326],[-97.2237,48.9332],[-97.2245,48.9337],[-97.2249,48.9339],[-97.225,48.934],[-97.2252,48.9342],[-97.2254,48.9345],[-97.2257,48.9349],[-97.226,48.9353],[-97.2263,48.936],[-97.2267,48.9376],[-97.227,48.9389],[-97.2271,48.9398],[-97.2271,48.941],[-97.227,48.9418],[-97.2266,48.9432],[-97.2264,48.9441],[-97.2263,48.9445],[-97.2264,48.9452],[-97.2265,48.9456],[-97.227,48.9462],[-97.2273,48.9465],[-97.2276,48.9467],[-97.2279,48.9467],[-97.2284,48.9468],[-97.2304,48.9465],[-97.2309,48.9464],[-97.2313,48.9464],[-97.2326,48.9466],[-97.2331,48.9468],[-97.2338,48.9471],[-97.2342,48.9474],[-97.2343,48.948],[-97.2343,48.9485],[-97.2342,48.9488],[-97.2341,48.9491],[-97.2337,48.95],[-97.2332,48.951],[-97.2328,48.9524],[-97.2323,48.954],[-97.2317,48.9558],[-97.2313,48.9568],[-97.2309,48.9578],[-97.2305,48.9585],[-97.23,48.9591],[-97.2288,48.9603],[-97.2282,48.9609],[-97.2278,48.9613],[-97.2276,48.9619],[-97.2276,48.9624],[-97.2279,48.963],[-97.228,48.9631],[-97.2283,48.9634],[-97.2289,48.9639],[-97.2294,48.9641],[-97.23,48.9642],[-97.2323,48.9646],[-97.2355,48.965],[-97.2368,48.9652],[-97.2375,48.9654],[-97.2382,48.966],[-97.2383,48.9661],[-97.2388,48.9666],[-97.2391,48.9676],[-97.2392,48.9687],[-97.239,48.9696],[-97.2387,48.9706],[-97.2383,48.9715],[-97.2381,48.9723],[-97.238,48.9725],[-97.2379,48.9731],[-97.2378,48.9734],[-97.2378,48.9738],[-97.238,48.9752],[-97.238,48.9763],[-97.2381,48.9771],[-97.238,48.9771],[-97.238,48.9841],[-97.2377,48.9849],[-97.2372,48.9857],[-97.2365,48.9867],[-97.2359,48.9874],[-97.2351,48.9881],[-97.2342,48.989],[-97.2335,48.9895],[-97.2331,48.9898],[-97.2317,48.9904],[-97.2301,48.9911],[-97.2293,48.9914],[-97.229,48.9916],[-97.2279,48.9921],[-97.2274,48.9925],[-97.227,48.9929],[-97.2266,48.9933],[-97.2265,48.9938],[-97.2267,48.9941],[-97.227,48.9945],[-97.2273,48.9947],[-97.2287,48.9949],[-97.2304,48.995],[-97.2317,48.9951],[-97.2324,48.9952],[-97.2335,48.9956],[-97.2338,48.9959],[-97.2341,48.9966],[-97.2341,48.997],[-97.234,48.9975],[-97.2337,48.9981],[-97.2332,48.9985],[-97.2323,48.999],[-97.2305,49.0],[-97.2303,49.0001],[-97.2295,49.0005],[-97.2175,49.0005],[-97.2161,49.0005],[-97.2078,49.0005],[-97.2069,49.0005],[-97.1955,49.0005],[-97.1939,49.0005],[-97.1739,49.0005],[-97.1724,49.0005],[-97.1514,49.0005],[-97.1502,49.0005],[-97.1294,49.0004],[-97.1277,49.0004],[-97.1073,49.0004],[-97.1061,49.0004],[-97.0853,49.0004],[-97.084,49.0004],[-97.0633,49.0004],[-97.062,49.0004],[-97.0412,49.0004],[-97.0401,49.0004],[-97.0192,49.0004],[-97.0183,49.0004],[-96.9971,49.0004],[-96.9961,49.0004],[-96.9751,49.0003],[-96.9738,49.0003],[-96.953,49.0003],[-96.9518,49.0003],[-96.931,49.0003],[-96.9299,49.0003],[-96.909,49.0003],[-96.9078,49.0003],[-96.8869,49.0003],[-96.8856,49.0003],[-96.8649,49.0003],[-96.864,49.0003],[-96.8429,49.0003],[-96.8415,49.0003],[-96.8208,49.0003],[-96.8197,49.0003],[-96.8023,49.0002],[-96.8005,49.0002],[-96.8003,49.0002],[-96.7988,49.0002],[-96.7787,49.0002],[-96.7768,49.0002],[-96.7567,49.0002],[-96.7547,49.0002],[-96.7348,49.0002],[-96.7327,49.0002],[-96.7127,49.0002],[-96.7107,49.0002],[-96.6905,49.0002],[-96.6886,49.0002],[-96.6695,49.0002],[-96.6665,49.0002],[-96.6482,49.0002],[-96.6445,49.0002],[-96.6243,49.0002],[-96.6225,49.0002],[-96.6021,49.0002],[-96.6004,49.0002],[-96.58,49.0002],[-96.5784,49.0002],[-96.558,49.0002],[-96.5563,49.0002],[-96.536,49.0002],[-96.5342,49.0002],[-96.5154,49.0002],[-96.5123,49.0002],[-96.4933,49.0002],[-96.49,49.0002],[-96.471,49.0001],[-96.4664,49.0001],[-96.4496,49.0001],[-96.4492,49.0001],[-96.4491,49.0001],[-96.446,49.0001],[-96.4273,49.0001],[-96.4224,49.0001],[-96.4054,49.0001]]],"type":"Polygon"},"id":"35","properties":{"Area":2862183702.23055,"CTYONLY_":3,"Code":"KITT","LASTMOD":"1999-12-31T23:59:59Z","Name":"Kittson","Perimiter":263017.48277},"type":"Feature"},{"geometry":{"coordinates":[[[-96.4054,49.0001],[-96.4019,49.0001],[-96.3825,49.0001],[-96.3783,49.0001],[-96.3606,49.0001],[-96.3579,49.0001],[-96.3385,49.0001],[-96.3343,49.0001],[-96.3166,49.0001],[-96.3138,49.0001],[-96.2945,49.0001],[-96.2902,49.0001],[-96.2725,49.0001],[-96.2698,49.0001],[-96.2494,49.0001],[-96.2461,49.0001],[-96.2274,49.0001],[-96.2257,49.0001],[-96.2057,49.0001],[-96.2021,49.0001],[-96.1837,49.0],[-96.18,49.0],[-96.1617,49.0],[-96.1579,49.0],[-96.1401,49.0],[-96.1359,49.0],[-96.1176,49.0],[-96.1139,49.0],[-96.0957,49.0],[-96.0919,49.0],[-96.0738,49.0],[-96.07,49.0],[-96.0517,49.0],[-96.048,49.0],[-96.0298,49.0],[-96.026,49.0],[-96.0083,49.0],[-96.0045,49.0],[-95.9868,49.0],[-95.9784,49.0],[-95.9776,49.0],[-95.9755,49.0],[-95.9648,48.9999],[-95.9464,48.9999],[-95.943,48.9999],[-95.9225,48.9999],[-95.9211,48.9999],[-95.899,48.9998],[-95.883,48.9998],[-95.8771,48.9998],[-95.8564,48.9998],[-95.855,48.9998],[-95.8342,48.9998],[-95.8184,48.9997],[-95.8126,48.9997],[-95.7906,48.9997],[-95.7833,48.9997],[-95.7684,48.9997],[-95.7479,48.9996],[-95.7466,48.9996],[-95.7253,48.9996],[-95.7066,48.9996],[-95.7032,48.9996],[-95.681,48.9995],[-95.6654,48.9995],[-95.6596,48.9995],[-95.659,48.9995],[-95.6401,48.9995],[-95.6369,48.9995],[-95.6205,48.9994],[-95.615,48.9994],[-95.5948,48.9994],[-95.585,48.9994],[-95.573,48.9994],[-95.551,48.9993],[-95.5495,48.9993],[-95.5294,48.9993],[-95.5164,48.9993],[-95.5072,48.9993],[-95.4849,48.9992],[-95.4834,48.9992],[-95.4635,48.9992],[-95.4508,48.9992],[-95.4418,48.9992],[-95.4245,48.9991],[-95.4197,48.9991],[-95.3977,48.9991],[-95.3953,48.9991],[-95.3765,48.9991],[-95.3759,48.9991],[-95.3753,48.9991],[-95.3542,48.999],[-95.3513,48.999],[-95.3326,48.999],[-95.3286,48.999],[-95.3231,48.999],[-95.3224,48.9984],[-95.3204,48.9976],[-95.3202,48.9973],[-95.3204,48.9964],[-95.3206,48.9961],[-95.3201,48.9956],[-95.3197,48.9954],[-95.3191,48.9953],[-95.3187,48.9956],[-95.3182,48.996],[-95.3179,48.9961],[-95.3178,48.9961],[-95.3178,48.9958],[-95.3181,48.995],[-95.3191,48.9941],[-95.3204,48.9924],[-95.3206,48.9921],[-95.3224,48.9889],[-95.3227,48.9884],[-95.3242,48.9859],[-95.3245,48.985],[-95.3253,48.9832],[-95.3257,48.9814],[-95.3256,48.98],[-95.3255,48.9789],[-95.3257,48.9784],[-95.3253,48.976],[-95.325,48.9743],[-95.3249,48.9738],[-95.3248,48.9728],[-95.3247,48.972],[-95.3241,48.9703],[-95.3232,48.9692],[-95.3227,48.9685],[-95.3212,48.9672],[-95.3207,48.9669],[-95.3201,48.9648],[-95.3198,48.9643],[-95.3193,48.964],[-95.3193,48.9622],[-95.3202,48.9606],[-95.3206,48.9598],[-95.3206,48.9595],[-95.3206,48.959],[-95.3202,48.9581],[-95.3191,48.9569],[-95.3188,48.9562],[-95.3179,48.9559],[-95.3175,48.9552],[-95.3177,48.9545],[-95.3182,48.9535],[-95.3181,48.9531],[-95.3177,48.9525],[-95.3154,48.9513],[-95.3151,48.951],[-95.3141,48.9508],[-95.3131,48.9503],[-95.3125,48.9503],[-95.3123,48.9502],[-95.3119,48.9502],[-95.3119,48.9507],[-95.3129,48.9521],[-95.3129,48.9523],[-95.3126,48.9524],[-95.312,48.9524],[-95.3115,48.952],[-95.3108,48.9512],[-95.3104,48.951],[-95.3097,48.951],[-95.3089,48.9511],[-95.3079,48.9509],[-95.3061,48.9502],[-95.3052,48.9495],[-95.3046,48.9482],[-95.3046,48.947],[-95.305,48.9462],[-95.3053,48.9459],[-95.3061,48.9454],[-95.3068,48.9454],[-95.3069,48.9455],[-95.3069,48.9456],[-95.3063,48.9462],[-95.3062,48.9463],[-95.3061,48.9469],[-95.3062,48.9472],[-95.3062,48.9472],[-95.3071,48.9477],[-95.3081,48.948],[-95.3094,48.9481],[-95.3096,48.9482],[-95.3099,48.9484],[-95.31,48.9485],[-95.3103,48.9485],[-95.3104,48.9484],[-95.3103,48.948],[-95.3096,48.9478],[-95.3092,48.9477],[-95.3079,48.9474],[-95.3071,48.9469],[-95.3071,48.9466],[-95.3074,48.9465],[-95.3078,48.9466],[-95.3085,48.947],[-95.3086,48.9469],[-95.3086,48.9465],[-95.3088,48.9464],[-95.3095,48.9463],[-95.3102,48.9463],[-95.3114,48.9461],[-95.3131,48.946],[-95.3141,48.9457],[-95.3148,48.9452],[-95.3154,48.9448],[-95.3168,48.9431],[-95.3181,48.9421],[-95.3189,48.9419],[-95.3219,48.9412],[-95.3225,48.9409],[-95.3228,48.9403],[-95.3231,48.9389],[-95.3229,48.9373],[-95.3225,48.9358],[-95.3223,48.9355],[-95.3228,48.9344],[-95.3222,48.9327],[-95.3209,48.9307],[-95.3208,48.9305],[-95.3195,48.9285],[-95.3168,48.9245],[-95.315,48.9222],[-95.3141,48.921],[-95.3132,48.9198],[-95.3126,48.919],[-95.3119,48.9178],[-95.3115,48.9172],[-95.3109,48.9163],[-95.3102,48.9155],[-95.3093,48.9149],[-95.3092,48.9149],[-95.3085,48.9146],[-95.3078,48.9141],[-95.3074,48.9135],[-95.3064,48.9129],[-95.3061,48.9128],[-95.3059,48.9127],[-95.3043,48.9119],[-95.3038,48.9114],[-95.3027,48.91],[-95.3017,48.9093],[-95.2999,48.9086],[-95.2978,48.9083],[-95.2973,48.9081],[-95.2973,48.908],[-95.2973,48.9077],[-95.2976,48.9074],[-95.2977,48.9073],[-95.2978,48.9073],[-95.2978,48.9072],[-95.2978,48.9072],[-95.2979,48.9072],[-95.2979,48.9072],[-95.2979,48.9071],[-95.298,48.9071],[-95.298,48.9071],[-95.298,48.9071],[-95.2981,48.907],[-95.2982,48.9068],[-95.2983,48.9068],[-95.2985,48.9065],[-95.2985,48.9064],[-95.2986,48.9063],[-95.2988,48.906],[-95.2989,48.906],[-95.2991,48.9057],[-95.2992,48.9055],[-95.2994,48.9053],[-95.2996,48.9051],[-95.2997,48.905],[-95.2999,48.9048],[-95.2999,48.9048],[-95.2999,48.9048],[-95.3,48.9047],[-95.3,48.9047],[-95.3001,48.9047],[-95.3001,48.9046],[-95.3002,48.9045],[-95.3005,48.904],[-95.2993,48.9035],[-95.2983,48.9028],[-95.298,48.9027],[-95.2976,48.9026],[-95.2967,48.9027],[-95.2949,48.9028],[-95.2941,48.9027],[-95.2937,48.9023],[-95.2935,48.902],[-95.2927,48.9019],[-95.2914,48.9019],[-95.2909,48.9017],[-95.2908,48.9016],[-95.2907,48.9014],[-95.2906,48.9011],[-95.2911,48.9008],[-95.2911,48.9006],[-95.2901,48.9003],[-95.2896,48.9],[-95.289,48.8994],[-95.2882,48.8981],[-95.2879,48.8979],[-95.2872,48.8977],[-95.287,48.8976],[-95.2865,48.8975],[-95.2861,48.8976],[-95.2853,48.8977],[-95.2839,48.8975],[-95.2813,48.8967],[-95.2803,48.8965],[-95.2796,48.8962],[-95.279,48.8957],[-95.2782,48.8956],[-95.2773,48.8957],[-95.277,48.8958],[-95.2765,48.8962],[-95.2763,48.8963],[-95.2759,48.8962],[-95.2755,48.8959],[-95.2749,48.8956],[-95.2748,48.8951],[-95.2753,48.8943],[-95.2751,48.8938],[-95.2745,48.8931],[-95.2724,48.8921],[-95.2713,48.8915],[-95.268,48.8905],[-95.2677,48.8903],[-95.2674,48.89],[-95.2666,48.8894],[-95.2654,48.8888],[-95.265,48.8886],[-95.2646,48.8885],[-95.2639,48.8883],[-95.2635,48.888],[-95.2627,48.8877],[-95.2585,48.8867],[-95.2585,48.8867],[-95.257,48.8858],[-95.256,48.885],[-95.2548,48.8845],[-95.2517,48.8839],[-95.2507,48.8836],[-95.2502,48.8835],[-95.2496,48.8834],[-95.2485,48.8832],[-95.248,48.8836],[-95.2472,48.8835],[-95.2458,48.8829],[-95.2439,48.8823],[-95.2429,48.8822],[-95.2429,48.8822],[-95.2423,48.8821],[-95.2407,48.8821],[-95.2391,48.8819],[-95.2381,48.8817],[-95.2356,48.8815],[-95.2335,48.8814],[-95.231,48.8814],[-95.2287,48.8815],[-95.2265,48.8816],[-95.2252,48.8819],[-95.2212,48.883],[-95.2208,48.8831],[-95.2207,48.8831],[-95.22,48.8831],[-95.2193,48.8832],[-95.2188,48.8835],[-95.217,48.8835],[-95.2159,48.8839],[-95.2151,48.884],[-95.2144,48.8843],[-95.2122,48.8842],[-95.2117,48.8847],[-95.2115,48.8847],[-95.2112,48.8848],[-95.2085,48.8846],[-95.2059,48.8848],[-95.2024,48.8852],[-95.2009,48.8855],[-95.2005,48.8856],[-95.1986,48.8855],[-95.1956,48.8862],[-95.1924,48.8865],[-95.1919,48.8866],[-95.1913,48.8868],[-95.1901,48.887],[-95.1889,48.8873],[-95.1877,48.8874],[-95.1863,48.8877],[-95.1851,48.8882],[-95.1819,48.8888],[-95.1797,48.889],[-95.1791,48.889],[-95.1764,48.8893],[-95.173,48.8897],[-95.1701,48.8902],[-95.1674,48.8907],[-95.1648,48.8913],[-95.1641,48.8917],[-95.1618,48.892],[-95.1602,48.892],[-95.1579,48.8919],[-95.1564,48.8919],[-95.1555,48.892],[-95.1528,48.8921],[-95.1508,48.8922],[-95.1483,48.8923],[-95.1469,48.8927],[-95.1459,48.8929],[-95.1438,48.8934],[-95.1436,48.8937],[-95.1404,48.8943],[-95.1381,48.8949],[-95.1355,48.8959],[-95.1351,48.8963],[-95.1348,48.8963],[-95.1343,48.8963],[-95.1337,48.8969],[-95.1322,48.8973],[-95.1312,48.8975],[-95.1252,48.8998],[-95.1239,48.9001],[-95.1233,48.9004],[-95.1228,48.9006],[-95.1214,48.9013],[-95.121,48.9016],[-95.1205,48.9017],[-95.1204,48.9019],[-95.1182,48.9029],[-95.1163,48.9037],[-95.1151,48.9046],[-95.1144,48.9052],[-95.114,48.9061],[-95.1141,48.9064],[-95.1137,48.9069],[-95.1132,48.9071],[-95.113,48.9072],[-95.1126,48.9073],[-95.1107,48.9082],[-95.1096,48.9089],[-95.108,48.9099],[-95.1056,48.9113],[-95.1042,48.9121],[-95.1032,48.9127],[-95.102,48.9132],[-95.1008,48.9142],[-95.0981,48.9159],[-95.098,48.916],[-95.0975,48.9164],[-95.0971,48.9172],[-95.097,48.9176],[-95.0961,48.9181],[-95.0946,48.9191],[-95.0944,48.9193],[-95.0927,48.9204],[-95.0919,48.9207],[-95.0914,48.9208],[-95.0914,48.916],[-95.0912,48.9014],[-95.0911,48.8869],[-95.0908,48.8724],[-95.0908,48.858],[-95.0907,48.8436],[-95.0908,48.8291],[-95.0909,48.8147],[-95.0903,48.8],[-95.0903,48.7855],[-95.0903,48.7711],[-95.0901,48.7566],[-95.0901,48.7421],[-95.0899,48.7277],[-95.0898,48.713],[-95.1046,48.7129],[-95.1104,48.7129],[-95.1119,48.7129],[-95.1259,48.7129],[-95.1297,48.713],[-95.1333,48.713],[-95.1477,48.7129],[-95.1554,48.7129],[-95.1697,48.7129],[-95.1773,48.713],[-95.1917,48.713],[-95.1991,48.713],[-95.2112,48.713],[-95.2206,48.713],[-95.2331,48.713],[-95.2427,48.713],[-95.255,48.713],[-95.2645,48.713],[-95.2656,48.713],[-95.2767,48.713],[-95.2866,48.713],[-95.299,48.713],[-95.3051,48.713],[-95.3084,48.713],[-95.3205,48.713],[-95.3302,48.713],[-95.3425,48.7131],[-95.3425,48.6995],[-95.3424,48.6849],[-95.3423,48.6705],[-95.3424,48.6561],[-95.3425,48.6415],[-95.3426,48.6271],[-95.3424,48.6127],[-95.3426,48.5979],[-95.3423,48.5836],[-95.3423,48.5691],[-95.3424,48.5548],[-95.3425,48.5402],[-95.3628,48.5404],[-95.364,48.5403],[-95.3844,48.5402],[-95.386,48.5402],[-95.4061,48.5402],[-95.4078,48.5402],[-95.4279,48.54],[-95.4297,48.5399],[-95.4494,48.5399],[-95.4513,48.5399],[-95.4712,48.5396],[-95.4726,48.5396],[-95.493,48.5392],[-95.495,48.5392],[-95.5143,48.539],[-95.5163,48.539],[-95.5365,48.5389],[-95.5383,48.5389],[-95.558,48.5388],[-95.5603,48.5388],[-95.5801,48.5387],[-95.5821,48.5387],[-95.6023,48.5389],[-95.6232,48.5391],[-95.6447,48.5393],[-95.6666,48.5394],[-95.6886,48.5395],[-95.7102,48.5395],[-95.7322,48.54],[-95.7539,48.5404],[-95.7758,48.5406],[-95.7976,48.5405],[-95.8192,48.5404],[-95.8411,48.5406],[-95.8621,48.5414],[-95.8829,48.5419],[-95.8851,48.542],[-95.8986,48.5421],[-95.9046,48.5422],[-95.9064,48.5422],[-95.9269,48.5421],[-95.9486,48.5425],[-95.9498,48.5425],[-95.9704,48.543],[-95.9936,48.5435],[-96.0157,48.5437],[-96.0374,48.5438],[-96.0592,48.5437],[-96.0812,48.5436],[-96.1026,48.5438],[-96.1264,48.5439],[-96.1486,48.5442],[-96.1702,48.5445],[-96.1921,48.5446],[-96.2141,48.5449],[-96.2358,48.5452],[-96.2576,48.545],[-96.2794,48.5449],[-96.301,48.5448],[-96.3231,48.5446],[-96.3448,48.5444],[-96.3667,48.5443],[-96.3882,48.5442],[-96.3879,48.5588],[-96.3882,48.5733],[-96.3884,48.5877],[-96.3891,48.6024],[-96.389,48.6165],[-96.388,48.6313],[-96.3879,48.6454],[-96.3877,48.6599],[-96.3871,48.6741],[-96.3874,48.6887],[-96.3866,48.703],[-96.3873,48.7172],[-96.388,48.7172],[-96.4049,48.7172],[-96.4048,48.7318],[-96.4048,48.7465],[-96.4047,48.7607],[-96.4045,48.7758],[-96.4042,48.7903],[-96.4042,48.8048],[-96.4042,48.8198],[-96.4043,48.8343],[-96.4045,48.8491],[-96.4047,48.8635],[-96.405,48.878],[-96.405,48.8926],[-96.4053,48.9068],[-96.4053,48.9081],[-96.4053,48.9137],[-96.4054,48.9214],[-96.4054,48.9225],[-96.4053,48.936],[-96.4053,48.9371],[-96.4053,48.9504],[-96.4053,48.9515],[-96.4053,48.9648],[-96.4053,48.9658],[-96.4053,48.9705],[-96.4054,48.9793],[-96.4054,48.9803],[-96.4054,48.994],[-96.4054,48.9947],[-96.4054,49.0001]]],"type":"Polygon"},"id":"68","properties":{"Area":4347098503.12714,"CTYONLY_":4,"Code":"ROSE","LASTMOD":"2001-04-12T09:32:44Z","Name":"Roseau","Perimiter":302590.75293},"type":"Feature"},{"geometry":{"coordinates":[[[-94.4299,48.7012],[-94.4241,48.7053],[-94.4213,48.7086],[-94.4189,48.7103],[-94.4158,48.711],[-94.4081,48.7106],[-94.406,48.7105],[-94.3889,48.712],[-94.3859,48.7119],[-94.384,48.7119],[-94.3801,48.7111],[-94.3687,48.7065],[-94.3646,48.7059],[-94.3533,48.7042],[-94.3431,48.7035],[-94.3429,48.7035],[-94.3287,48.7045],[-94.3214,48.7067],[-94.3088,48.7103],[-94.2995,48.709],[-94.2911,48.7079],[-94.2829,48.7057],[-94.2781,48.7024],[-94.2745,48.6999],[-94.2694,48.6995],[-94.2644,48.699],[-94.261,48.6966],[-94.258,48.6918],[-94.2565,48.6901],[-94.2529,48.6864],[-94.2521,48.685],[-94.2514,48.6837],[-94.2507,48.6782],[-94.2527,48.6707],[-94.253,48.6693],[-94.2548,48.664],[-94.2546,48.6615],[-94.2509,48.657],[-94.2499,48.6563],[-94.2467,48.6542],[-94.2445,48.6535],[-94.2343,48.6524],[-94.2335,48.6524],[-94.2242,48.6495],[-94.2144,48.6494],[-94.2124,48.6496],[-94.1996,48.651],[-94.1915,48.6506],[-94.1886,48.6504],[-94.1689,48.6483],[-94.1678,48.6482],[-94.1574,48.6458],[-94.1522,48.6455],[-94.1458,48.6458],[-94.1391,48.646],[-94.126,48.6444],[-94.1235,48.6444],[-94.11,48.6443],[-94.1023,48.6455],[-94.0999,48.6459],[-94.0912,48.6437],[-94.0849,48.6441],[-94.0804,48.6442],[-94.0767,48.6442],[-94.0714,48.6459],[-94.0658,48.6462],[-94.0642,48.6438],[-94.0603,48.6431],[-94.0581,48.6434],[-94.0525,48.644],[-94.0432,48.6435],[-94.0393,48.6423],[-94.0364,48.6413],[-94.0356,48.6411],[-94.0295,48.6409],[-94.0153,48.6424],[-94.0069,48.6433],[-94.0007,48.6428],[-93.9931,48.6412],[-93.9897,48.6405],[-93.984,48.6401],[-93.9777,48.6385],[-93.9712,48.6385],[-93.968,48.6385],[-93.9596,48.6372],[-93.953,48.6341],[-93.9497,48.6339],[-93.934,48.6326],[-93.9272,48.6327],[-93.9169,48.6329],[-93.9134,48.6353],[-93.9057,48.6346],[-93.9054,48.6345],[-93.8948,48.6324],[-93.8853,48.6318],[-93.8844,48.6318],[-93.8757,48.6319],[-93.8698,48.6311],[-93.8624,48.631],[-93.848,48.6308],[-93.8443,48.6303],[-93.8404,48.6289],[-93.8393,48.6286],[-93.8365,48.6276],[-93.8334,48.6256],[-93.8292,48.6177],[-93.825,48.6136],[-93.8245,48.613],[-93.8214,48.6092],[-93.8182,48.5994],[-93.8175,48.597],[-93.8172,48.5964],[-93.813,48.588],[-93.8103,48.5846],[-93.8063,48.5796],[-93.8041,48.5703],[-93.8041,48.5702],[-93.8051,48.5644],[-93.808,48.5569],[-93.8088,48.5555],[-93.8119,48.5503],[-93.8102,48.5445],[-93.8109,48.5412],[-93.8109,48.541],[-93.818,48.535],[-93.818,48.5346],[-93.8184,48.5315],[-93.8178,48.5306],[-93.8161,48.5285],[-93.8145,48.5273],[-93.8111,48.5247],[-93.803,48.522],[-93.7964,48.5182],[-93.7933,48.5164],[-93.7879,48.5159],[-93.7745,48.5162],[-93.768,48.5164],[-93.7665,48.5164],[-93.7617,48.5166],[-93.7534,48.5158],[-93.7442,48.5175],[-93.739,48.5185],[-93.731,48.5185],[-93.7225,48.5178],[-93.7206,48.5176],[-93.7108,48.5186],[-93.7061,48.5182],[-93.7006,48.517],[-93.693,48.5152],[-93.6866,48.5154],[-93.6791,48.5167],[-93.6778,48.5169],[-93.6593,48.5165],[-93.657,48.5167],[-93.6473,48.5177],[-93.6433,48.519],[-93.6421,48.5199],[-93.6395,48.5218],[-93.6357,48.5285],[-93.6344,48.5293],[-93.6311,48.5313],[-93.6284,48.5319],[-93.6256,48.5315],[-93.6211,48.5264],[-93.6166,48.5238],[-93.6134,48.5228],[-93.6122,48.5225],[-93.6051,48.5231],[-93.5962,48.5287],[-93.5919,48.5299],[-93.5901,48.5305],[-93.581,48.5271],[-93.5761,48.527],[-93.5701,48.528],[-93.5602,48.5297],[-93.5484,48.5294],[-93.5476,48.5294],[-93.5425,48.53],[-93.5366,48.5319],[-93.5269,48.5341],[-93.5263,48.5341],[-93.5244,48.5343],[-93.5171,48.5348],[-93.5047,48.5399],[-93.501,48.5414],[-93.4952,48.5426],[-93.4854,48.5433],[-93.4833,48.5437],[-93.4673,48.5465],[-93.4655,48.5478],[-93.4625,48.5498],[-93.462,48.5505],[-93.4596,48.5537],[-93.4576,48.5598],[-93.4576,48.5621],[-93.4575,48.5672],[-93.4619,48.5731],[-93.4619,48.5734],[-93.4631,48.5767],[-93.4671,48.5885],[-93.4656,48.59],[-93.4654,48.5915],[-93.4654,48.5917],[-93.4627,48.5927],[-93.46,48.5927],[-93.4547,48.5927],[-93.4398,48.5937],[-93.4385,48.5942],[-93.4347,48.5954],[-93.4298,48.5997],[-93.4226,48.6032],[-93.4193,48.6036],[-93.416,48.605],[-93.4152,48.6053],[-93.415,48.6056],[-93.4144,48.6064],[-93.4056,48.6099],[-93.4034,48.61],[-93.4029,48.6077],[-93.4013,48.6079],[-93.3994,48.6055],[-93.3986,48.6045],[-93.3953,48.6038],[-93.3937,48.6041],[-93.3837,48.606],[-93.3724,48.6059],[-93.3714,48.6059],[-93.3672,48.6082],[-93.3619,48.6141],[-93.355,48.6114],[-93.3526,48.6135],[-93.3533,48.615],[-93.3513,48.62],[-93.3505,48.6219],[-93.3486,48.6265],[-93.3276,48.6302],[-93.3057,48.634],[-93.3048,48.6341],[-93.2838,48.6378],[-93.2634,48.6413],[-93.2546,48.6429],[-93.2422,48.6428],[-93.2193,48.6426],[-93.2075,48.6426],[-93.1975,48.6365],[-93.191,48.6325],[-93.184,48.6282],[-93.1783,48.6231],[-93.1754,48.6232],[-93.1531,48.6244],[-93.1319,48.6256],[-93.1104,48.6267],[-93.0903,48.6278],[-93.0884,48.6278],[-93.0886,48.6163],[-93.0895,48.6016],[-93.0898,48.5872],[-93.09,48.5727],[-93.0902,48.5583],[-93.0902,48.5441],[-93.0903,48.5296],[-93.0905,48.5151],[-93.0905,48.501],[-93.091,48.4884],[-93.0911,48.4867],[-93.0914,48.474],[-93.0915,48.4724],[-93.0918,48.4596],[-93.0919,48.458],[-93.092,48.4449],[-93.092,48.4436],[-93.0922,48.4303],[-93.0922,48.429],[-93.0923,48.4147],[-93.0935,48.4147],[-93.0938,48.4024],[-93.094,48.3879],[-93.094,48.3734],[-93.0945,48.3589],[-93.0948,48.3442],[-93.0948,48.3298],[-93.0953,48.3153],[-93.0952,48.3004],[-93.095,48.2862],[-93.0952,48.2716],[-93.0953,48.2576],[-93.0949,48.2426],[-93.0949,48.2425],[-93.0977,48.2426],[-93.0977,48.2271],[-93.0978,48.2126],[-93.0979,48.1981],[-93.0975,48.1836],[-93.097,48.1692],[-93.097,48.1546],[-93.097,48.1402],[-93.0969,48.1259],[-93.0972,48.1114],[-93.097,48.0969],[-93.0968,48.0823],[-93.0965,48.0679],[-93.0965,48.0678],[-93.0892,48.0679],[-93.0892,48.0509],[-93.089,48.0366],[-93.0886,48.022],[-93.0887,48.0075],[-93.0872,47.9932],[-93.088,47.9787],[-93.0809,47.9786],[-93.0809,47.967],[-93.0808,47.9647],[-93.0808,47.9525],[-93.0808,47.9504],[-93.0809,47.938],[-93.0809,47.9356],[-93.0809,47.9235],[-93.0809,47.9212],[-93.0809,47.9088],[-93.0809,47.9067],[-93.0808,47.8945],[-93.0808,47.8922],[-93.1015,47.8927],[-93.1232,47.893],[-93.1448,47.8928],[-93.1656,47.8931],[-93.1671,47.8932],[-93.1871,47.8931],[-93.1893,47.8931],[-93.2087,47.8933],[-93.2115,47.8934],[-93.2331,47.8937],[-93.2532,47.8936],[-93.2745,47.8938],[-93.2962,47.8939],[-93.3169,47.894],[-93.3392,47.8941],[-93.3603,47.8942],[-93.3809,47.8943],[-93.4024,47.8944],[-93.4235,47.8945],[-93.4442,47.8946],[-93.466,47.895],[-93.4874,47.8956],[-93.4892,47.8957],[-93.4933,47.8958],[-93.5085,47.8962],[-93.5105,47.8963],[-93.5297,47.8967],[-93.5303,47.8967],[-93.532,47.8968],[-93.5517,47.8973],[-93.5532,47.8974],[-93.5729,47.8981],[-93.5747,47.8982],[-93.5962,47.8978],[-93.5966,47.8978],[-93.6179,47.8977],[-93.6187,47.8977],[-93.6388,47.8977],[-93.6395,47.8976],[-93.6604,47.8976],[-93.6612,47.8976],[-93.6817,47.8976],[-93.6826,47.8976],[-93.7031,47.8976],[-93.7038,47.8976],[-93.7249,47.8975],[-93.7248,47.8989],[-93.7466,47.8989],[-93.768,47.8991],[-93.7758,47.8991],[-93.7758,47.899],[-93.776,47.8897],[-93.776,47.8842],[-93.7762,47.8753],[-93.7761,47.8697],[-93.7761,47.8607],[-93.7761,47.8553],[-93.7761,47.8464],[-93.7896,47.8465],[-93.7971,47.8466],[-93.8189,47.8467],[-93.8407,47.8468],[-93.8627,47.8469],[-93.8831,47.8471],[-93.9067,47.8471],[-93.9288,47.8475],[-93.9496,47.8475],[-93.9506,47.8475],[-93.971,47.8475],[-93.9725,47.8475],[-93.9927,47.8475],[-93.9942,47.8475],[-94.0141,47.8476],[-94.0161,47.8476],[-94.0375,47.8477],[-94.0591,47.8474],[-94.0807,47.8471],[-94.1022,47.8471],[-94.1239,47.8466],[-94.1448,47.8463],[-94.1657,47.8461],[-94.1822,47.8461],[-94.1871,47.846],[-94.2037,47.846],[-94.2086,47.846],[-94.2252,47.846],[-94.23,47.8461],[-94.2467,47.8462],[-94.2515,47.8462],[-94.2681,47.8462],[-94.2728,47.8462],[-94.2887,47.8462],[-94.3103,47.8458],[-94.3315,47.846],[-94.3532,47.8464],[-94.3747,47.8462],[-94.3964,47.8461],[-94.4185,47.8459],[-94.4186,47.86],[-94.4184,47.8744],[-94.418,47.8886],[-94.4177,47.9031],[-94.4176,47.9041],[-94.4175,47.9175],[-94.4174,47.9186],[-94.4175,47.9332],[-94.4174,47.9477],[-94.4172,47.9623],[-94.4173,47.9769],[-94.4176,47.9914],[-94.4177,48.006],[-94.4176,48.02],[-94.4236,48.0199],[-94.4241,48.0344],[-94.4246,48.0489],[-94.4247,48.0632],[-94.4234,48.0776],[-94.4231,48.092],[-94.4233,48.1059],[-94.4234,48.1204],[-94.4236,48.1348],[-94.4233,48.1491],[-94.4235,48.1637],[-94.4235,48.1781],[-94.4233,48.1923],[-94.4236,48.2067],[-94.4238,48.2212],[-94.4237,48.2356],[-94.4237,48.2504],[-94.424,48.2649],[-94.4243,48.2791],[-94.4244,48.2938],[-94.4246,48.3081],[-94.4248,48.3227],[-94.425,48.3372],[-94.4253,48.352],[-94.4252,48.3675],[-94.4288,48.3675],[-94.4289,48.3821],[-94.4293,48.3964],[-94.4294,48.411],[-94.4293,48.4254],[-94.4292,48.4399],[-94.4293,48.4543],[-94.4296,48.4688],[-94.4296,48.4832],[-94.4299,48.4977],[-94.4303,48.512],[-94.4303,48.5264],[-94.43,48.5409],[-94.4295,48.5554],[-94.4291,48.5698],[-94.4289,48.5844],[-94.4289,48.5988],[-94.4292,48.6133],[-94.4294,48.6276],[-94.4297,48.642],[-94.43,48.6564],[-94.4301,48.6708],[-94.43,48.6852],[-94.4299,48.6998],[-94.4299,48.7012]]],"type":"Polygon"},"id":"36","properties":{"Area":8167237870.91888,"CTYONLY_":5,"Code":"KOOC","LASTMOD":"1999-12-31T23:59:59Z","Name":"Koochiching","Perimiter":412897.43594},"type":"Feature"},{"geometry":{"coordinates":[[[-96.3882,48.5442],[-96.3667,48.5443],[-96.3448,48.5444],[-96.3231,48.5446],[-96.301,48.5448],[-96.2794,48.5449],[-96.2576,48.545],[-96.2358,48.5452],[-96.2141,48.5449],[-96.1921,48.5446],[-96.1702,48.5445],[-96.1486,48.5442],[-96.1264,48.5439],[-96.1026,48.5438],[-96.0812,48.5436],[-96.0592,48.5437],[-96.0374,48.5438],[-96.0157,48.5437],[-95.9936,48.5435],[-95.9704,48.543],[-95.9498,48.5425],[-95.9486,48.5425],[-95.9269,48.5421],[-95.9064,48.5422],[-95.9046,48.5422],[-95.8986,48.5421],[-95.8851,48.542],[-95.8829,48.5419],[-95.8621,48.5414],[-95.8411,48.5406],[-95.8192,48.5404],[-95.7976,48.5405],[-95.7758,48.5406],[-95.7539,48.5404],[-95.7322,48.54],[-95.7102,48.5395],[-95.6886,48.5395],[-95.6666,48.5394],[-95.6447,48.5393],[-95.6232,48.5391],[-95.6023,48.5389],[-95.6011,48.5251],[-95.6007,48.5107],[-95.6007,48.51],[-95.6008,48.4964],[-95.6008,48.4956],[-95.6011,48.4818],[-95.6011,48.4811],[-95.6016,48.4674],[-95.6016,48.4666],[-95.6016,48.453],[-95.6016,48.4522],[-95.602,48.4385],[-95.6021,48.4376],[-95.6023,48.424],[-95.6023,48.4232],[-95.6026,48.4095],[-95.6026,48.4088],[-95.6026,48.395],[-95.6026,48.3942],[-95.6021,48.3809],[-95.602,48.3798],[-95.6016,48.3655],[-95.5933,48.3656],[-95.5933,48.3656],[-95.5933,48.354],[-95.5932,48.3396],[-95.5932,48.325],[-95.5932,48.3105],[-95.5934,48.2961],[-95.5934,48.2815],[-95.5937,48.267],[-95.5941,48.2526],[-95.5941,48.2382],[-95.5939,48.2236],[-95.5939,48.2092],[-95.5938,48.1946],[-95.594,48.1802],[-95.5939,48.173],[-95.5941,48.173],[-95.6159,48.1731],[-95.6163,48.1731],[-95.6252,48.1731],[-95.6279,48.1731],[-95.6376,48.173],[-95.6376,48.173],[-95.6591,48.1729],[-95.662,48.1729],[-95.6802,48.1728],[-95.6803,48.1728],[-95.702,48.1729],[-95.7021,48.1729],[-95.7022,48.1729],[-95.7128,48.173],[-95.7157,48.1731],[-95.7226,48.1731],[-95.7227,48.1731],[-95.744,48.1727],[-95.7443,48.1727],[-95.7502,48.1727],[-95.7657,48.1728],[-95.7657,48.1728],[-95.7874,48.1725],[-95.8088,48.1722],[-95.809,48.1722],[-95.8091,48.1722],[-95.8305,48.1722],[-95.8308,48.1722],[-95.8308,48.1722],[-95.8499,48.1721],[-95.8525,48.1721],[-95.8527,48.1721],[-95.8744,48.172],[-95.8744,48.172],[-95.8752,48.172],[-95.8958,48.172],[-95.896,48.172],[-95.9176,48.1719],[-95.9178,48.1719],[-95.9178,48.1719],[-95.9392,48.1719],[-95.9394,48.1719],[-95.9608,48.1718],[-95.9609,48.1718],[-95.961,48.1718],[-95.9651,48.1718],[-95.9817,48.1717],[-95.9819,48.1717],[-95.9956,48.1717],[-96.0003,48.1717],[-96.0023,48.1718],[-96.0028,48.1718],[-96.0032,48.1718],[-96.0035,48.1718],[-96.0036,48.1718],[-96.0047,48.1717],[-96.0101,48.1718],[-96.0171,48.172],[-96.025,48.1721],[-96.0254,48.1721],[-96.0468,48.1722],[-96.0468,48.1722],[-96.0592,48.1721],[-96.0685,48.1721],[-96.0685,48.1721],[-96.079,48.1721],[-96.09,48.172],[-96.09,48.172],[-96.0979,48.172],[-96.1084,48.1718],[-96.1084,48.1718],[-96.1176,48.1722],[-96.1189,48.1722],[-96.1253,48.1727],[-96.1297,48.173],[-96.1298,48.173],[-96.1302,48.173],[-96.1388,48.1732],[-96.1516,48.1736],[-96.1518,48.1736],[-96.1625,48.1736],[-96.1641,48.1736],[-96.1736,48.1736],[-96.1737,48.1736],[-96.1741,48.1736],[-96.1813,48.1725],[-96.1827,48.1722],[-96.1834,48.172],[-96.1874,48.1721],[-96.191,48.1721],[-96.1948,48.1721],[-96.1954,48.1721],[-96.1959,48.1721],[-96.1963,48.1721],[-96.2023,48.1722],[-96.2038,48.1722],[-96.2072,48.1722],[-96.2076,48.1722],[-96.2177,48.1722],[-96.2179,48.1722],[-96.2188,48.1722],[-96.2251,48.1724],[-96.2275,48.1724],[-96.2287,48.1725],[-96.2307,48.1725],[-96.2329,48.1725],[-96.2391,48.1727],[-96.2397,48.1727],[-96.2397,48.1727],[-96.2398,48.1728],[-96.2476,48.1735],[-96.2491,48.1737],[-96.2503,48.1739],[-96.2511,48.174],[-96.252,48.174],[-96.2562,48.1744],[-96.2596,48.1749],[-96.2607,48.1749],[-96.2612,48.1749],[-96.2619,48.1749],[-96.2805,48.1747],[-96.2823,48.1747],[-96.2824,48.1747],[-96.2977,48.1747],[-96.3029,48.1747],[-96.3035,48.1747],[-96.3145,48.1747],[-96.3252,48.1746],[-96.3253,48.1746],[-96.3301,48.1745],[-96.3356,48.1745],[-96.3358,48.1744],[-96.338,48.1745],[-96.3402,48.1744],[-96.343,48.1744],[-96.3466,48.1743],[-96.347,48.1743],[-96.3473,48.1744],[-96.3477,48.1744],[-96.351,48.1745],[-96.3542,48.1746],[-96.3581,48.1747],[-96.361,48.1748],[-96.3642,48.1749],[-96.3656,48.175],[-96.3682,48.1751],[-96.3682,48.1751],[-96.3685,48.1751],[-96.3706,48.175],[-96.3728,48.1749],[-96.3753,48.1748],[-96.3781,48.1746],[-96.38,48.1745],[-96.3856,48.1747],[-96.3894,48.1748],[-96.3905,48.1748],[-96.3906,48.1748],[-96.3964,48.1748],[-96.4054,48.1748],[-96.4126,48.1749],[-96.4126,48.1749],[-96.4135,48.1749],[-96.4206,48.1749],[-96.4295,48.1749],[-96.4346,48.1749],[-96.4352,48.1749],[-96.4359,48.1749],[-96.438,48.1749],[-96.4402,48.1748],[-96.4436,48.1747],[-96.4454,48.1747],[-96.4561,48.1744],[-96.4563,48.1743],[-96.4564,48.1742],[-96.4569,48.1742],[-96.4592,48.1742],[-96.467,48.1741],[-96.4735,48.174],[-96.4773,48.1741],[-96.4789,48.1741],[-96.4791,48.1741],[-96.4841,48.174],[-96.4946,48.1741],[-96.4973,48.174],[-96.5003,48.1741],[-96.5006,48.1741],[-96.5008,48.1742],[-96.5008,48.1742],[-96.5038,48.174],[-96.5091,48.174],[-96.5164,48.1739],[-96.5204,48.1739],[-96.5223,48.1739],[-96.5251,48.1738],[-96.53,48.1738],[-96.5357,48.1738],[-96.5399,48.1738],[-96.5434,48.1738],[-96.5442,48.1738],[-96.5443,48.1738],[-96.5446,48.1738],[-96.5479,48.1738],[-96.5507,48.1738],[-96.5544,48.1738],[-96.557,48.1739],[-96.5616,48.1739],[-96.565,48.174],[-96.5654,48.174],[-96.5655,48.174],[-96.5678,48.174],[-96.5715,48.1739],[-96.5748,48.1739],[-96.5765,48.1739],[-96.5806,48.1739],[-96.5838,48.1738],[-96.5873,48.1737],[-96.5873,48.1737],[-96.5875,48.1737],[-96.5893,48.1737],[-96.5966,48.1737],[-96.6055,48.1737],[-96.609,48.1737],[-96.6092,48.1737],[-96.6106,48.1737],[-96.6253,48.1737],[-96.6307,48.1737],[-96.6307,48.1737],[-96.6309,48.1737],[-96.6338,48.1737],[-96.6378,48.1738],[-96.6407,48.1739],[-96.6525,48.1738],[-96.6525,48.1738],[-96.6742,48.1736],[-96.6742,48.1736],[-96.6826,48.1735],[-96.6958,48.1734],[-96.6959,48.1734],[-96.7176,48.1734],[-96.7177,48.1734],[-96.7393,48.1734],[-96.7393,48.1734],[-96.7503,48.1734],[-96.7573,48.1734],[-96.7581,48.1734],[-96.7605,48.1734],[-96.7606,48.1734],[-96.7613,48.1734],[-96.7819,48.1734],[-96.7821,48.1734],[-96.7821,48.1734],[-96.7932,48.1733],[-96.8038,48.1734],[-96.8039,48.1734],[-96.8111,48.1734],[-96.8255,48.1734],[-96.8255,48.1734],[-96.8473,48.1733],[-96.8474,48.1733],[-96.869,48.1733],[-96.869,48.1733],[-96.8753,48.1732],[-96.8907,48.1732],[-96.8907,48.1732],[-96.8932,48.1732],[-96.9122,48.1733],[-96.9123,48.1733],[-96.933,48.1733],[-96.9339,48.1733],[-96.934,48.1733],[-96.9387,48.1732],[-96.9448,48.1732],[-96.9554,48.1731],[-96.9703,48.1731],[-96.9705,48.1731],[-96.9749,48.173],[-96.9751,48.173],[-96.9773,48.173],[-96.9773,48.173],[-96.9775,48.1731],[-96.9812,48.1731],[-96.9844,48.1731],[-96.9889,48.1731],[-96.99,48.1731],[-96.9959,48.1732],[-96.9975,48.1732],[-96.998,48.1732],[-96.9987,48.1732],[-96.9989,48.1732],[-96.999,48.1732],[-97.0003,48.1732],[-97.0203,48.1733],[-97.0205,48.1733],[-97.042,48.1732],[-97.042,48.1732],[-97.0637,48.1732],[-97.0637,48.1732],[-97.0853,48.1734],[-97.0855,48.1734],[-97.1069,48.1735],[-97.1071,48.1735],[-97.1253,48.1733],[-97.1257,48.1733],[-97.1286,48.1733],[-97.1322,48.1733],[-97.1376,48.1733],[-97.1462,48.1733],[-97.1467,48.1733],[-97.1452,48.1741],[-97.1434,48.1744],[-97.1417,48.1746],[-97.1389,48.1747],[-97.1371,48.1754],[-97.1365,48.1758],[-97.136,48.1768],[-97.1359,48.1789],[-97.1362,48.1796],[-97.1366,48.1809],[-97.1383,48.1824],[-97.1406,48.183],[-97.1413,48.1831],[-97.1432,48.1828],[-97.1455,48.1824],[-97.1467,48.1821],[-97.1484,48.1825],[-97.1498,48.1835],[-97.1497,48.1859],[-97.1491,48.1864],[-97.1475,48.1879],[-97.1449,48.1895],[-97.1429,48.191],[-97.1426,48.1913],[-97.1415,48.1926],[-97.1413,48.1934],[-97.1412,48.1937],[-97.141,48.194],[-97.1409,48.1945],[-97.1404,48.1947],[-97.1397,48.1951],[-97.1391,48.1953],[-97.1383,48.1955],[-97.1365,48.1963],[-97.1356,48.1972],[-97.1359,48.1984],[-97.1368,48.1996],[-97.1383,48.2006],[-97.1401,48.2018],[-97.1409,48.2027],[-97.1412,48.203],[-97.1411,48.204],[-97.1409,48.2046],[-97.14,48.2052],[-97.139,48.2059],[-97.1375,48.2063],[-97.1341,48.2068],[-97.1316,48.2072],[-97.1301,48.2077],[-97.1296,48.208],[-97.1295,48.208],[-97.1292,48.2084],[-97.1292,48.2099],[-97.1291,48.21],[-97.1296,48.2105],[-97.1297,48.2106],[-97.1299,48.2108],[-97.1307,48.211],[-97.1318,48.2112],[-97.1354,48.2116],[-97.1364,48.2119],[-97.1382,48.2131],[-97.1394,48.2144],[-97.1392,48.2168],[-97.1389,48.2171],[-97.1383,48.2174],[-97.1373,48.2177],[-97.1354,48.2179],[-97.1344,48.2178],[-97.1328,48.2176],[-97.1313,48.2172],[-97.1302,48.2164],[-97.1297,48.2161],[-97.1292,48.2158],[-97.1278,48.2145],[-97.1274,48.2134],[-97.1265,48.2113],[-97.126,48.2101],[-97.1259,48.2099],[-97.1257,48.2097],[-97.1253,48.2093],[-97.1245,48.208],[-97.1236,48.2077],[-97.1229,48.2074],[-97.1216,48.2074],[-97.1204,48.2073],[-97.1197,48.2076],[-97.1189,48.2079],[-97.1183,48.2086],[-97.118,48.2092],[-97.1178,48.2098],[-97.1179,48.2107],[-97.1181,48.2115],[-97.1189,48.2129],[-97.1194,48.2136],[-97.1208,48.215],[-97.122,48.2159],[-97.1228,48.2165],[-97.1248,48.2175],[-97.1253,48.2178],[-97.1272,48.2185],[-97.1289,48.2188],[-97.1297,48.219],[-97.1321,48.2196],[-97.135,48.2207],[-97.139,48.222],[-97.1406,48.2222],[-97.1417,48.2221],[-97.1436,48.2216],[-97.1448,48.2209],[-97.1455,48.2204],[-97.1457,48.2202],[-97.1458,48.2202],[-97.1462,48.2198],[-97.1471,48.2189],[-97.1482,48.2184],[-97.1497,48.2181],[-97.1509,48.2184],[-97.151,48.2185],[-97.1517,48.219],[-97.1521,48.2197],[-97.1521,48.2205],[-97.1517,48.2214],[-97.151,48.2222],[-97.1496,48.2232],[-97.1483,48.2238],[-97.1476,48.224],[-97.1465,48.2243],[-97.1436,48.2253],[-97.1408,48.2263],[-97.1385,48.2268],[-97.1371,48.227],[-97.1357,48.2271],[-97.1332,48.227],[-97.1317,48.2265],[-97.1305,48.2259],[-97.1298,48.2255],[-97.129,48.2251],[-97.1276,48.2245],[-97.1273,48.2243],[-97.1266,48.2239],[-97.1259,48.2236],[-97.1253,48.2234],[-97.1245,48.2232],[-97.1233,48.2231],[-97.1222,48.2234],[-97.1216,48.2236],[-97.121,48.2242],[-97.121,48.2242],[-97.1206,48.2248],[-97.1206,48.2254],[-97.1207,48.2259],[-97.1216,48.227],[-97.1225,48.2275],[-97.1234,48.2281],[-97.1244,48.2284],[-97.1253,48.2287],[-97.1278,48.2293],[-97.1299,48.2297],[-97.1303,48.2297],[-97.1325,48.2298],[-97.1351,48.2298],[-97.1393,48.2302],[-97.1423,48.231],[-97.1435,48.2318],[-97.1446,48.2336],[-97.1445,48.2343],[-97.1443,48.2351],[-97.143,48.2361],[-97.1416,48.2365],[-97.1411,48.2366],[-97.1399,48.2367],[-97.1377,48.2368],[-97.1358,48.237],[-97.1343,48.2378],[-97.1339,48.2382],[-97.1338,48.2386],[-97.1337,48.2391],[-97.1341,48.2397],[-97.1346,48.2403],[-97.1357,48.2409],[-97.1375,48.2414],[-97.1385,48.2415],[-97.1405,48.2415],[-97.1422,48.2412],[-97.1444,48.2412],[-97.1459,48.2417],[-97.147,48.2423],[-97.1471,48.243],[-97.1467,48.2445],[-97.146,48.2452],[-97.1444,48.2462],[-97.1431,48.2468],[-97.1404,48.2473],[-97.1389,48.2479],[-97.1377,48.2485],[-97.1355,48.2495],[-97.1345,48.2498],[-97.1334,48.2499],[-97.1305,48.2498],[-97.1299,48.2498],[-97.1291,48.2495],[-97.1274,48.2495],[-97.1263,48.2498],[-97.1253,48.25],[-97.1251,48.25],[-97.1247,48.2504],[-97.1244,48.2508],[-97.1243,48.2513],[-97.1243,48.252],[-97.1245,48.2526],[-97.1248,48.2532],[-97.1248,48.2532],[-97.1253,48.2537],[-97.1256,48.254],[-97.1262,48.2546],[-97.1267,48.2551],[-97.1274,48.2555],[-97.1291,48.2566],[-97.13,48.2573],[-97.1304,48.2576],[-97.1306,48.2581],[-97.1306,48.2587],[-97.1306,48.259],[-97.1303,48.2595],[-97.1298,48.2598],[-97.1292,48.2599],[-97.1283,48.26],[-97.1272,48.2601],[-97.1253,48.2601],[-97.1248,48.2602],[-97.1242,48.2604],[-97.1236,48.2607],[-97.1231,48.2612],[-97.1229,48.2617],[-97.123,48.2623],[-97.1234,48.2628],[-97.1237,48.2633],[-97.1241,48.2636],[-97.1246,48.2639],[-97.1253,48.2641],[-97.1262,48.2644],[-97.1285,48.2649],[-97.1303,48.2651],[-97.1305,48.2652],[-97.1333,48.2656],[-97.135,48.2659],[-97.136,48.2659],[-97.1375,48.2657],[-97.1395,48.2655],[-97.1406,48.2654],[-97.142,48.2654],[-97.1427,48.2656],[-97.1438,48.2658],[-97.1444,48.2663],[-97.1448,48.2668],[-97.145,48.2675],[-97.1451,48.2678],[-97.145,48.2688],[-97.1443,48.2698],[-97.1431,48.2705],[-97.1421,48.2709],[-97.1403,48.2712],[-97.1391,48.2713],[-97.1377,48.2713],[-97.1361,48.2711],[-97.1343,48.2707],[-97.1313,48.2701],[-97.1305,48.27],[-97.1298,48.2699],[-97.1288,48.2698],[-97.1272,48.2699],[-97.1265,48.2701],[-97.1253,48.2705],[-97.125,48.2707],[-97.1247,48.2709],[-97.124,48.2713],[-97.1238,48.2716],[-97.1237,48.2721],[-97.1237,48.2725],[-97.1239,48.2728],[-97.124,48.2733],[-97.1242,48.2737],[-97.1247,48.2743],[-97.1253,48.2751],[-97.1254,48.2753],[-97.1255,48.2755],[-97.1256,48.2758],[-97.1255,48.2761],[-97.1254,48.2762],[-97.1253,48.2764],[-97.1251,48.2767],[-97.1246,48.2769],[-97.124,48.277],[-97.1232,48.277],[-97.1224,48.2769],[-97.1213,48.2768],[-97.1206,48.2768],[-97.12,48.2769],[-97.1187,48.2774],[-97.1175,48.2781],[-97.117,48.2788],[-97.1165,48.2797],[-97.1166,48.2805],[-97.1166,48.2807],[-97.1167,48.2813],[-97.117,48.2821],[-97.1171,48.2824],[-97.1172,48.2826],[-97.1177,48.2835],[-97.1221,48.2901],[-97.1231,48.2909],[-97.1239,48.2913],[-97.1244,48.2915],[-97.1247,48.2917],[-97.1253,48.2919],[-97.1256,48.292],[-97.126,48.292],[-97.1265,48.292],[-97.1272,48.2919],[-97.128,48.2916],[-97.1285,48.2913],[-97.1295,48.2908],[-97.1303,48.2902],[-97.1305,48.2901],[-97.1314,48.2891],[-97.1322,48.2884],[-97.133,48.2879],[-97.1342,48.2874],[-97.1349,48.2872],[-97.1355,48.2871],[-97.1367,48.2873],[-97.1374,48.2877],[-97.1378,48.2879],[-97.1383,48.2887],[-97.1384,48.2894],[-97.1384,48.2898],[-97.1383,48.2903],[-97.138,48.2909],[-97.1373,48.2918],[-97.1368,48.2922],[-97.1364,48.2925],[-97.1355,48.2929],[-97.1344,48.2935],[-97.1335,48.2941],[-97.133,48.2946],[-97.1323,48.2953],[-97.1318,48.2959],[-97.1314,48.2963],[-97.131,48.2969],[-97.1306,48.2973],[-97.1305,48.2974],[-97.13,48.2979],[-97.1293,48.2984],[-97.1286,48.2987],[-97.1282,48.2989],[-97.1276,48.299],[-97.1271,48.2991],[-97.127,48.2991],[-97.1263,48.2991],[-97.1253,48.2989],[-97.125,48.2988],[-97.1246,48.2987],[-97.1241,48.2984],[-97.1234,48.2975],[-97.1228,48.2968],[-97.1227,48.2967],[-97.1213,48.2955],[-97.1203,48.2949],[-97.1192,48.2943],[-97.1167,48.294],[-97.1153,48.2939],[-97.1138,48.2943],[-97.1129,48.2949],[-97.1123,48.2954],[-97.1122,48.296],[-97.1122,48.2965],[-97.1123,48.2968],[-97.1126,48.2973],[-97.113,48.2978],[-97.1138,48.2984],[-97.1148,48.299],[-97.118,48.3004],[-97.12,48.3012],[-97.1227,48.3019],[-97.1241,48.3022],[-97.1247,48.3025],[-97.1253,48.3029],[-97.1255,48.303],[-97.1259,48.3033],[-97.1262,48.3036],[-97.1266,48.3041],[-97.1267,48.3046],[-97.1265,48.3055],[-97.1263,48.3059],[-97.1257,48.3064],[-97.1253,48.3067],[-97.1241,48.3073],[-97.123,48.3081],[-97.1222,48.3088],[-97.1221,48.3095],[-97.1222,48.3099],[-97.123,48.3105],[-97.1241,48.3112],[-97.1247,48.3115],[-97.1253,48.3119],[-97.1258,48.3119],[-97.1263,48.312],[-97.1269,48.312],[-97.1276,48.312],[-97.1282,48.3118],[-97.1289,48.3116],[-97.1298,48.3111],[-97.1299,48.3111],[-97.1303,48.3108],[-97.1304,48.3108],[-97.1311,48.3103],[-97.1318,48.3099],[-97.1325,48.3094],[-97.1331,48.3092],[-97.1336,48.309],[-97.1343,48.3089],[-97.1351,48.3089],[-97.1358,48.3089],[-97.1365,48.3091],[-97.1372,48.3094],[-97.1377,48.3098],[-97.1379,48.3102],[-97.1381,48.3106],[-97.138,48.3111],[-97.138,48.3116],[-97.1379,48.312],[-97.1376,48.3125],[-97.1372,48.3129],[-97.1367,48.3134],[-97.1361,48.3141],[-97.1356,48.3148],[-97.1351,48.3155],[-97.1348,48.316],[-97.1346,48.3166],[-97.1345,48.3171],[-97.1343,48.3177],[-97.134,48.3181],[-97.1335,48.3185],[-97.1329,48.3189],[-97.1325,48.3192],[-97.132,48.3194],[-97.1312,48.3196],[-97.1306,48.3196],[-97.1303,48.3196],[-97.1291,48.3196],[-97.1282,48.3195],[-97.1274,48.3195],[-97.1267,48.3195],[-97.1253,48.3196],[-97.1229,48.3201],[-97.1197,48.3208],[-97.1173,48.3216],[-97.1164,48.3222],[-97.1157,48.323],[-97.1155,48.3236],[-97.1155,48.324],[-97.1162,48.3248],[-97.1168,48.3253],[-97.1173,48.3258],[-97.1175,48.326],[-97.1187,48.3266],[-97.1203,48.3271],[-97.1222,48.3274],[-97.123,48.3275],[-97.1253,48.3277],[-97.1257,48.3277],[-97.1262,48.3278],[-97.1275,48.328],[-97.1292,48.3282],[-97.1303,48.3282],[-97.1311,48.3283],[-97.1317,48.3282],[-97.1326,48.3281],[-97.1337,48.3279],[-97.1343,48.3277],[-97.1345,48.3277],[-97.1353,48.3273],[-97.1359,48.327],[-97.1368,48.3263],[-97.1376,48.3257],[-97.138,48.3255],[-97.1385,48.3253],[-97.139,48.3251],[-97.1397,48.3251],[-97.1404,48.3252],[-97.141,48.3254],[-97.1415,48.3257],[-97.1417,48.3258],[-97.142,48.3262],[-97.1422,48.3267],[-97.1423,48.327],[-97.1422,48.3276],[-97.142,48.3281],[-97.1416,48.3287],[-97.1408,48.3294],[-97.14,48.3299],[-97.139,48.3304],[-97.1378,48.3309],[-97.1371,48.331],[-97.1361,48.3312],[-97.1347,48.3315],[-97.1325,48.3318],[-97.1311,48.3321],[-97.1305,48.3323],[-97.1295,48.3326],[-97.129,48.3329],[-97.1284,48.3336],[-97.1275,48.3352],[-97.1263,48.3379],[-97.1258,48.3384],[-97.1258,48.3398],[-97.1258,48.3402],[-97.1259,48.3406],[-97.1263,48.3415],[-97.1267,48.3422],[-97.1276,48.3427],[-97.1283,48.343],[-97.1297,48.3435],[-97.1308,48.3438],[-97.1309,48.3438],[-97.132,48.344],[-97.1334,48.3439],[-97.1354,48.3439],[-97.1372,48.344],[-97.1383,48.3441],[-97.1388,48.3441],[-97.1396,48.3443],[-97.14,48.3446],[-97.1405,48.345],[-97.1407,48.3453],[-97.1409,48.3456],[-97.141,48.3459],[-97.1408,48.3468],[-97.1405,48.3471],[-97.1396,48.3478],[-97.1386,48.3485],[-97.1376,48.3491],[-97.1368,48.3496],[-97.1362,48.3501],[-97.1361,48.3503],[-97.136,48.3505],[-97.136,48.3506],[-97.1359,48.351],[-97.1359,48.3511],[-97.136,48.3518],[-97.1362,48.3522],[-97.1363,48.3524],[-97.1365,48.3526],[-97.1373,48.3529],[-97.1382,48.3532],[-97.1387,48.3533],[-97.1398,48.3535],[-97.1405,48.3536],[-97.1415,48.3538],[-97.1423,48.354],[-97.143,48.3542],[-97.1435,48.3543],[-97.1438,48.3546],[-97.1441,48.3549],[-97.1442,48.3551],[-97.1443,48.3554],[-97.1445,48.356],[-97.1447,48.3565],[-97.145,48.3571],[-97.1453,48.3576],[-97.1459,48.3586],[-97.1464,48.3592],[-97.1468,48.3596],[-97.1477,48.3603],[-97.1484,48.3608],[-97.1501,48.3613],[-97.1517,48.362],[-97.1525,48.3623],[-97.1534,48.3628],[-97.1545,48.3633],[-97.1554,48.3638],[-97.1559,48.3646],[-97.1562,48.3656],[-97.1562,48.3662],[-97.156,48.3671],[-97.1558,48.3681],[-97.1555,48.3686],[-97.1554,48.3689],[-97.1552,48.3691],[-97.1548,48.37],[-97.1539,48.3704],[-97.1536,48.3705],[-97.1524,48.371],[-97.1523,48.371],[-97.1512,48.3713],[-97.1498,48.3712],[-97.1476,48.371],[-97.1437,48.3703],[-97.1433,48.3703],[-97.141,48.3702],[-97.1407,48.3703],[-97.1404,48.3703],[-97.1403,48.3703],[-97.1402,48.3703],[-97.1401,48.3703],[-97.1392,48.3705],[-97.1386,48.3708],[-97.1378,48.3713],[-97.1373,48.3718],[-97.1372,48.3724],[-97.1373,48.373],[-97.1376,48.3736],[-97.1383,48.3744],[-97.1389,48.375],[-97.1398,48.3759],[-97.1406,48.3769],[-97.1412,48.3777],[-97.1413,48.3785],[-97.1409,48.3793],[-97.1403,48.3797],[-97.1395,48.3801],[-97.1379,48.3803],[-97.1366,48.3804],[-97.1355,48.3805],[-97.1344,48.3808],[-97.1339,48.3811],[-97.1334,48.3818],[-97.1333,48.3822],[-97.1338,48.3828],[-97.1344,48.3833],[-97.1354,48.3838],[-97.1362,48.384],[-97.1374,48.3839],[-97.1389,48.3837],[-97.1406,48.3833],[-97.1431,48.3824],[-97.1446,48.3819],[-97.1454,48.3815],[-97.1463,48.3815],[-97.147,48.3814],[-97.1479,48.3817],[-97.149,48.3819],[-97.1505,48.3824],[-97.1509,48.3825],[-97.1519,48.3829],[-97.1532,48.3834],[-97.1538,48.3839],[-97.1548,48.3844],[-97.155,48.3846],[-97.156,48.3851],[-97.1572,48.3858],[-97.1576,48.3865],[-97.1577,48.3874],[-97.1571,48.3884],[-97.1565,48.3896],[-97.1563,48.3904],[-97.1567,48.3909],[-97.1576,48.3912],[-97.1586,48.3913],[-97.1596,48.3912],[-97.1608,48.3913],[-97.1617,48.3915],[-97.1627,48.3918],[-97.1632,48.392],[-97.1633,48.3929],[-97.1631,48.3937],[-97.1621,48.3948],[-97.1607,48.3956],[-97.1593,48.3961],[-97.1586,48.3964],[-97.1574,48.3965],[-97.1551,48.3968],[-97.1534,48.397],[-97.1519,48.3969],[-97.1505,48.3968],[-97.1499,48.3968],[-97.1481,48.3968],[-97.1467,48.3971],[-97.1456,48.3975],[-97.1445,48.3981],[-97.1434,48.3989],[-97.1434,48.399],[-97.1427,48.3996],[-97.1421,48.4004],[-97.1414,48.4013],[-97.1406,48.4019],[-97.1399,48.4025],[-97.1392,48.4029],[-97.1383,48.4033],[-97.1369,48.4038],[-97.1349,48.4046],[-97.1334,48.4053],[-97.1323,48.4059],[-97.1314,48.4066],[-97.1311,48.4073],[-97.131,48.4079],[-97.1312,48.409],[-97.1316,48.4096],[-97.1322,48.4104],[-97.1334,48.4112],[-97.1348,48.412],[-97.1362,48.4126],[-97.1373,48.4134],[-97.1375,48.4137],[-97.1376,48.4137],[-97.1379,48.4141],[-97.1384,48.4146],[-97.1388,48.4163],[-97.1388,48.4172],[-97.1393,48.4181],[-97.1398,48.4185],[-97.1406,48.4187],[-97.142,48.4186],[-97.1434,48.4181],[-97.1445,48.4173],[-97.1453,48.4159],[-97.1467,48.414],[-97.1472,48.4137],[-97.1478,48.4133],[-97.1489,48.4129],[-97.1505,48.4128],[-97.1508,48.4128],[-97.1521,48.4129],[-97.1532,48.4131],[-97.1543,48.4136],[-97.1543,48.4136],[-97.155,48.4143],[-97.1554,48.415],[-97.1554,48.4161],[-97.1554,48.4168],[-97.1548,48.4175],[-97.1539,48.4182],[-97.1527,48.4188],[-97.1509,48.4195],[-97.1507,48.4196],[-97.1489,48.4201],[-97.1466,48.4206],[-97.1443,48.4211],[-97.1421,48.4215],[-97.1403,48.4216],[-97.1383,48.4217],[-97.1367,48.4216],[-97.135,48.4213],[-97.1335,48.421],[-97.1325,48.4205],[-97.1312,48.4197],[-97.1301,48.4191],[-97.129,48.4181],[-97.1285,48.4177],[-97.1274,48.4168],[-97.1264,48.4164],[-97.126,48.4162],[-97.1253,48.4162],[-97.1244,48.4164],[-97.1236,48.4167],[-97.1232,48.417],[-97.1227,48.4176],[-97.1225,48.418],[-97.1224,48.4183],[-97.1223,48.4191],[-97.1223,48.4195],[-97.1225,48.42],[-97.1227,48.4204],[-97.1228,48.4207],[-97.1231,48.421],[-97.1233,48.4213],[-97.1241,48.4219],[-97.1246,48.4223],[-97.1249,48.4224],[-97.1253,48.4226],[-97.1268,48.4234],[-97.1286,48.4242],[-97.129,48.4243],[-97.1312,48.4251],[-97.1332,48.4258],[-97.1346,48.4262],[-97.1375,48.4264],[-97.139,48.4265],[-97.1406,48.427],[-97.1412,48.4272],[-97.1425,48.4277],[-97.1438,48.4285],[-97.1446,48.4291],[-97.1451,48.4298],[-97.1457,48.4303],[-97.1458,48.4312],[-97.1455,48.4322],[-97.1451,48.4326],[-97.144,48.4332],[-97.142,48.4337],[-97.1412,48.4338],[-97.1398,48.4337],[-97.1384,48.4336],[-97.1366,48.433],[-97.1344,48.4321],[-97.1332,48.4316],[-97.1315,48.4312],[-97.1305,48.4311],[-97.129,48.4311],[-97.1278,48.4313],[-97.1267,48.4319],[-97.1259,48.4325],[-97.1253,48.4329],[-97.1246,48.4337],[-97.1245,48.4341],[-97.1238,48.4355],[-97.1236,48.4361],[-97.1234,48.4371],[-97.1233,48.4376],[-97.1233,48.4383],[-97.1235,48.4389],[-97.1238,48.4399],[-97.124,48.4407],[-97.1243,48.4413],[-97.1245,48.4416],[-97.1248,48.4419],[-97.125,48.4421],[-97.1251,48.4422],[-97.1253,48.4423],[-97.1258,48.4427],[-97.1265,48.4432],[-97.128,48.4438],[-97.129,48.444],[-97.1295,48.4441],[-97.1314,48.4441],[-97.1328,48.4439],[-97.1345,48.4434],[-97.1355,48.4427],[-97.1363,48.4421],[-97.1365,48.4419],[-97.138,48.4405],[-97.1398,48.4392],[-97.141,48.4386],[-97.1428,48.4383],[-97.1451,48.4381],[-97.1464,48.4381],[-97.1477,48.4383],[-97.149,48.4389],[-97.1498,48.4392],[-97.1503,48.4397],[-97.1505,48.4403],[-97.1506,48.4409],[-97.1505,48.4413],[-97.1502,48.4419],[-97.1501,48.4422],[-97.1492,48.4434],[-97.1481,48.4441],[-97.1462,48.4448],[-97.1426,48.4459],[-97.1401,48.4467],[-97.1377,48.4477],[-97.1353,48.4489],[-97.1306,48.4523],[-97.1293,48.4541],[-97.1292,48.4564],[-97.1292,48.4566],[-97.1292,48.4569],[-97.1291,48.4575],[-97.1288,48.4585],[-97.1286,48.4596],[-97.1285,48.4604],[-97.1288,48.4616],[-97.1292,48.4622],[-97.1293,48.4624],[-97.1298,48.463],[-97.1306,48.4635],[-97.1319,48.4638],[-97.1334,48.4639],[-97.1347,48.4638],[-97.136,48.4635],[-97.138,48.463],[-97.1395,48.463],[-97.1407,48.463],[-97.142,48.4634],[-97.143,48.4639],[-97.1444,48.4649],[-97.1455,48.466],[-97.1463,48.4669],[-97.147,48.4677],[-97.1474,48.4684],[-97.148,48.47],[-97.1482,48.4708],[-97.148,48.4713],[-97.1477,48.4721],[-97.1474,48.4728],[-97.1465,48.4737],[-97.1461,48.4741],[-97.1445,48.4746],[-97.1432,48.4748],[-97.1419,48.4748],[-97.1407,48.4747],[-97.1393,48.4743],[-97.1379,48.4737],[-97.1368,48.4732],[-97.1352,48.4724],[-97.134,48.4718],[-97.1331,48.4715],[-97.1326,48.4714],[-97.1324,48.4713],[-97.1315,48.4712],[-97.1306,48.4713],[-97.1301,48.4714],[-97.1294,48.4715],[-97.1293,48.4717],[-97.1289,48.472],[-97.1283,48.4729],[-97.1281,48.4736],[-97.1281,48.4744],[-97.1285,48.4751],[-97.1289,48.4758],[-97.1293,48.4761],[-97.1297,48.4764],[-97.1308,48.4769],[-97.1324,48.4773],[-97.1346,48.4776],[-97.1364,48.4777],[-97.1384,48.4776],[-97.1406,48.4775],[-97.1419,48.4773],[-97.1433,48.4769],[-97.1448,48.4765],[-97.1461,48.4761],[-97.1477,48.4758],[-97.1493,48.4755],[-97.1509,48.4753],[-97.1511,48.4752],[-97.153,48.475],[-97.1549,48.475],[-97.1569,48.475],[-97.1585,48.4752],[-97.1599,48.4756],[-97.1609,48.4759],[-97.1616,48.4763],[-97.1622,48.477],[-97.1626,48.4778],[-97.1624,48.4786],[-97.1623,48.4792],[-97.1616,48.4799],[-97.1602,48.4807],[-97.1592,48.4812],[-97.1574,48.4816],[-97.1562,48.4818],[-97.1546,48.4821],[-97.1529,48.4822],[-97.1509,48.4824],[-97.1507,48.4824],[-97.1482,48.4828],[-97.1455,48.483],[-97.1437,48.4835],[-97.1424,48.4838],[-97.1411,48.4843],[-97.1402,48.4848],[-97.1396,48.4854],[-97.1394,48.486],[-97.1392,48.4864],[-97.1393,48.4873],[-97.1396,48.4881],[-97.1401,48.4887],[-97.1408,48.4892],[-97.1417,48.49],[-97.1428,48.4909],[-97.1433,48.4914],[-97.1433,48.492],[-97.143,48.4924],[-97.1423,48.4926],[-97.1415,48.4926],[-97.1406,48.4924],[-97.1399,48.492],[-97.139,48.4912],[-97.1382,48.4904],[-97.138,48.4897],[-97.1373,48.4889],[-97.1367,48.4884],[-97.136,48.4881],[-97.1351,48.4878],[-97.1344,48.4878],[-97.1332,48.4881],[-97.1322,48.4885],[-97.1315,48.4891],[-97.1312,48.4897],[-97.1311,48.4903],[-97.1311,48.4907],[-97.1316,48.4916],[-97.1322,48.4924],[-97.1334,48.4935],[-97.1345,48.4943],[-97.1367,48.4954],[-97.1388,48.496],[-97.1408,48.4967],[-97.1425,48.4972],[-97.1444,48.4976],[-97.1453,48.4979],[-97.1478,48.4995],[-97.148,48.4997],[-97.1483,48.5],[-97.1487,48.5004],[-97.1491,48.5009],[-97.1497,48.502],[-97.1499,48.5034],[-97.1498,48.5047],[-97.1498,48.5061],[-97.1495,48.5075],[-97.1495,48.5086],[-97.1497,48.5096],[-97.1502,48.5106],[-97.1502,48.5117],[-97.1499,48.512],[-97.1491,48.5124],[-97.1477,48.5124],[-97.142,48.5116],[-97.139,48.5117],[-97.1366,48.5123],[-97.1338,48.5139],[-97.1328,48.5146],[-97.1326,48.5148],[-97.1289,48.5173],[-97.1281,48.5178],[-97.127,48.519],[-97.1267,48.5202],[-97.1276,48.5215],[-97.1288,48.5222],[-97.129,48.5223],[-97.1307,48.5227],[-97.1339,48.5227],[-97.1366,48.5221],[-97.1385,48.5215],[-97.1395,48.521],[-97.1411,48.5202],[-97.1426,48.5195],[-97.1442,48.5191],[-97.1454,48.5188],[-97.1473,48.5188],[-97.1488,48.5189],[-97.1503,48.5194],[-97.1506,48.5195],[-97.1524,48.5204],[-97.154,48.5217],[-97.1547,48.5242],[-97.1549,48.5266],[-97.1544,48.5285],[-97.1536,48.5295],[-97.1536,48.5295],[-97.1527,48.5303],[-97.1513,48.5309],[-97.1507,48.5311],[-97.1499,48.5313],[-97.1482,48.5315],[-97.1458,48.5316],[-97.1438,48.5316],[-97.1422,48.5323],[-97.1411,48.5333],[-97.141,48.5343],[-97.1413,48.5355],[-97.1424,48.5366],[-97.144,48.5375],[-97.1456,48.5382],[-97.1481,48.5388],[-97.1505,48.5395],[-97.1508,48.5395],[-97.1533,48.5399],[-97.1558,48.5403],[-97.1582,48.5409],[-97.1596,48.5414],[-97.161,48.542],[-97.1614,48.5424],[-97.1631,48.5439],[-97.1631,48.544],[-97.1509,48.5439],[-97.1287,48.5439],[-97.107,48.544],[-97.0852,48.5441],[-97.0635,48.5441],[-97.0416,48.5442],[-97.0194,48.5441],[-96.9985,48.5441],[-96.9768,48.544],[-96.9551,48.5437],[-96.9331,48.5435],[-96.9138,48.5433],[-96.9115,48.5432],[-96.8896,48.5433],[-96.8678,48.5433],[-96.8459,48.5434],[-96.824,48.5436],[-96.8023,48.5436],[-96.7803,48.5435],[-96.7585,48.5436],[-96.7368,48.5437],[-96.7151,48.5437],[-96.6931,48.5437],[-96.6713,48.5436],[-96.6493,48.5437],[-96.6278,48.5437],[-96.6058,48.5437],[-96.5839,48.5437],[-96.5621,48.5436],[-96.54,48.5434],[-96.518,48.5434],[-96.4973,48.5434],[-96.4754,48.5435],[-96.4535,48.5436],[-96.4318,48.5438],[-96.4101,48.544],[-96.3882,48.5442]]],"type":"Polygon"},"id":"45","properties":{"Area":4698732287.54973,"CTYONLY_":6,"Code":"MARS","LASTMOD":"1984-01-12T14:12:49Z","Name":"Marshall","Perimiter":374207.65129},"type":"Feature"},{"geometry":{"coordinates":[[[-93.0884,48.6278],[-93.067,48.627],[-93.0456,48.6262],[-93.0237,48.6253],[-93.0021,48.6245],[-92.9845,48.6239],[-92.98,48.625],[-92.9641,48.6291],[-92.9585,48.6306],[-92.9547,48.6316],[-92.9497,48.6304],[-92.9498,48.6291],[-92.9499,48.6147],[-92.95,48.6084],[-92.9369,48.6075],[-92.9295,48.607],[-92.9177,48.6006],[-92.9151,48.5992],[-92.91,48.5964],[-92.8945,48.595],[-92.8932,48.5946],[-92.8729,48.5878],[-92.8652,48.5853],[-92.8515,48.5807],[-92.8301,48.5735],[-92.8206,48.5703],[-92.8079,48.5661],[-92.7863,48.5589],[-92.7767,48.5557],[-92.7665,48.5522],[-92.7439,48.5446],[-92.7354,48.5418],[-92.7284,48.5394],[-92.7227,48.54],[-92.7007,48.5421],[-92.7003,48.5421],[-92.6789,48.5442],[-92.6578,48.5463],[-92.6576,48.5462],[-92.6369,48.5429],[-92.6357,48.5427],[-92.6348,48.5426],[-92.6302,48.5284],[-92.6282,48.5223],[-92.6255,48.5179],[-92.6269,48.5142],[-92.6268,48.514],[-92.6264,48.5135],[-92.625,48.513],[-92.628,48.5108],[-92.6287,48.5106],[-92.6308,48.5092],[-92.6312,48.5082],[-92.6319,48.5068],[-92.6296,48.5058],[-92.627,48.5033],[-92.6306,48.5008],[-92.6351,48.4998],[-92.637,48.4994],[-92.6386,48.4996],[-92.64,48.4999],[-92.647,48.4999],[-92.654,48.5017],[-92.6569,48.4996],[-92.6582,48.4987],[-92.6614,48.4964],[-92.6789,48.4971],[-92.6857,48.4974],[-92.6986,48.4949],[-92.7011,48.4847],[-92.7016,48.4841],[-92.7092,48.4729],[-92.7085,48.4704],[-92.7089,48.4696],[-92.7126,48.463],[-92.7025,48.4551],[-92.7015,48.4543],[-92.6881,48.4438],[-92.6799,48.4425],[-92.6694,48.441],[-92.6635,48.4401],[-92.6586,48.4377],[-92.6562,48.4365],[-92.6371,48.4375],[-92.6157,48.4386],[-92.5935,48.4398],[-92.5765,48.4406],[-92.5717,48.4415],[-92.5686,48.4421],[-92.5499,48.4454],[-92.5369,48.4478],[-92.5284,48.448],[-92.515,48.4484],[-92.5074,48.448],[-92.507,48.4476],[-92.501,48.4422],[-92.4942,48.436],[-92.4893,48.4303],[-92.4849,48.4294],[-92.4837,48.4292],[-92.482,48.4283],[-92.4819,48.4279],[-92.4819,48.4276],[-92.4807,48.4264],[-92.481,48.4253],[-92.4788,48.4233],[-92.4754,48.4187],[-92.4631,48.4157],[-92.4564,48.4141],[-92.4564,48.4135],[-92.4563,48.4012],[-92.4602,48.3956],[-92.47,48.3813],[-92.4765,48.372],[-92.4747,48.3667],[-92.4697,48.3522],[-92.4697,48.3521],[-92.4591,48.3374],[-92.4558,48.3329],[-92.4523,48.3281],[-92.4476,48.3229],[-92.4415,48.3161],[-92.4413,48.3159],[-92.4405,48.3154],[-92.4403,48.3149],[-92.4386,48.3112],[-92.4367,48.309],[-92.4361,48.3085],[-92.4347,48.3074],[-92.4318,48.3052],[-92.4289,48.306],[-92.4256,48.3047],[-92.4204,48.299],[-92.4156,48.2951],[-92.415,48.2941],[-92.4135,48.2915],[-92.4065,48.2795],[-92.4017,48.2714],[-92.3967,48.2648],[-92.3931,48.2601],[-92.3927,48.259],[-92.3934,48.2576],[-92.3921,48.2568],[-92.3913,48.256],[-92.3891,48.2537],[-92.3901,48.2528],[-92.3912,48.2529],[-92.3922,48.2531],[-92.3926,48.2519],[-92.3923,48.2512],[-92.3912,48.2509],[-92.3907,48.2507],[-92.3897,48.2508],[-92.3887,48.2512],[-92.3867,48.2518],[-92.3858,48.2514],[-92.3853,48.2504],[-92.3852,48.2502],[-92.3846,48.2492],[-92.3868,48.2492],[-92.3863,48.2475],[-92.3878,48.247],[-92.3881,48.2465],[-92.3872,48.2444],[-92.3866,48.2441],[-92.3846,48.2449],[-92.3838,48.2446],[-92.3844,48.2425],[-92.3844,48.2414],[-92.384,48.2404],[-92.3833,48.2393],[-92.3816,48.2377],[-92.3806,48.2365],[-92.3789,48.2359],[-92.3789,48.2359],[-92.3785,48.2353],[-92.3791,48.2343],[-92.3781,48.233],[-92.3784,48.2321],[-92.3785,48.2312],[-92.3783,48.2304],[-92.3774,48.2293],[-92.3758,48.2283],[-92.3754,48.2275],[-92.3756,48.2267],[-92.3751,48.226],[-92.3743,48.2256],[-92.3734,48.225],[-92.3726,48.2236],[-92.3714,48.2241],[-92.3708,48.2239],[-92.3707,48.2228],[-92.3699,48.2218],[-92.3699,48.2212],[-92.3699,48.2203],[-92.3695,48.2203],[-92.3691,48.2202],[-92.368,48.2212],[-92.368,48.2212],[-92.3672,48.2217],[-92.3668,48.2223],[-92.3676,48.2232],[-92.3687,48.2237],[-92.368,48.2241],[-92.3662,48.224],[-92.365,48.2236],[-92.3636,48.2229],[-92.3621,48.2227],[-92.3616,48.2232],[-92.3613,48.224],[-92.361,48.2248],[-92.3603,48.2256],[-92.3586,48.2265],[-92.3566,48.2275],[-92.3555,48.2281],[-92.3544,48.2286],[-92.3537,48.2296],[-92.3535,48.2301],[-92.3517,48.2306],[-92.3494,48.2313],[-92.3484,48.2314],[-92.3477,48.2315],[-92.347,48.2315],[-92.3439,48.2321],[-92.3419,48.2317],[-92.3414,48.2319],[-92.3408,48.2337],[-92.3404,48.2341],[-92.3392,48.2347],[-92.339,48.2349],[-92.3386,48.2351],[-92.338,48.2351],[-92.3377,48.235],[-92.3371,48.2351],[-92.3365,48.2357],[-92.3362,48.2357],[-92.3346,48.2348],[-92.3344,48.2346],[-92.3344,48.2344],[-92.3343,48.2342],[-92.3338,48.2339],[-92.3333,48.2338],[-92.332,48.234],[-92.3308,48.2348],[-92.3302,48.2349],[-92.3292,48.2351],[-92.3281,48.2359],[-92.3274,48.2366],[-92.327,48.2369],[-92.3268,48.2368],[-92.3262,48.2366],[-92.3261,48.2366],[-92.3259,48.2367],[-92.3256,48.2369],[-92.3253,48.2371],[-92.3223,48.2373],[-92.3221,48.2373],[-92.3148,48.2406],[-92.3006,48.2422],[-92.2803,48.2444],[-92.2783,48.2451],[-92.2695,48.2482],[-92.2713,48.2519],[-92.2736,48.2566],[-92.2794,48.2596],[-92.2901,48.2651],[-92.291,48.2664],[-92.2945,48.2713],[-92.2931,48.276],[-92.2937,48.2767],[-92.2942,48.2766],[-92.2945,48.2764],[-92.2951,48.2763],[-92.2952,48.2763],[-92.2953,48.2765],[-92.2953,48.2767],[-92.2954,48.2769],[-92.2953,48.2771],[-92.2952,48.2772],[-92.2953,48.2773],[-92.2956,48.2773],[-92.2955,48.2776],[-92.2955,48.2777],[-92.2956,48.278],[-92.2972,48.2809],[-92.3014,48.2883],[-92.2987,48.2954],[-92.2945,48.3063],[-92.2987,48.3099],[-92.3018,48.3125],[-92.3061,48.3163],[-92.3044,48.3229],[-92.302,48.3232],[-92.2954,48.3239],[-92.2952,48.3246],[-92.2901,48.3392],[-92.2888,48.3429],[-92.2803,48.3468],[-92.2625,48.355],[-92.2588,48.3544],[-92.2364,48.3511],[-92.2216,48.3489],[-92.2197,48.3481],[-92.2191,48.3475],[-92.2189,48.3469],[-92.2181,48.3463],[-92.2169,48.345],[-92.2147,48.3452],[-92.2067,48.3457],[-92.2065,48.3473],[-92.2077,48.3479],[-92.2038,48.3519],[-92.195,48.3505],[-92.1945,48.3488],[-92.193,48.3488],[-92.1928,48.3488],[-92.1785,48.3519],[-92.179,48.3549],[-92.1791,48.3549],[-92.1774,48.3572],[-92.1709,48.3598],[-92.162,48.3634],[-92.1488,48.3652],[-92.1448,48.3657],[-92.1437,48.3561],[-92.1274,48.3556],[-92.106,48.355],[-92.0942,48.3546],[-92.0908,48.3545],[-92.0842,48.3538],[-92.0835,48.3538],[-92.0823,48.3547],[-92.0781,48.3581],[-92.067,48.3595],[-92.0625,48.3595],[-92.0552,48.3594],[-92.0525,48.3549],[-92.0488,48.3486],[-92.0458,48.3479],[-92.0451,48.3458],[-92.0478,48.3436],[-92.0475,48.3404],[-92.0469,48.3348],[-92.0404,48.3336],[-92.0376,48.3331],[-92.031,48.3261],[-92.0307,48.3257],[-92.0185,48.324],[-92.0119,48.323],[-92.0001,48.3211],[-92.0051,48.3118],[-92.0129,48.2975],[-92.0129,48.297],[-92.012,48.287],[-92.0087,48.2826],[-92.0072,48.2806],[-92.0066,48.2677],[-92.0065,48.2655],[-91.9949,48.262],[-91.9891,48.2603],[-91.9841,48.2531],[-91.9805,48.248],[-91.979,48.2475],[-91.9783,48.2474],[-91.9778,48.2474],[-91.9773,48.2472],[-91.9769,48.2468],[-91.977,48.2465],[-91.9772,48.2463],[-91.9773,48.2462],[-91.9775,48.246],[-91.9774,48.2457],[-91.9774,48.2456],[-91.9772,48.2455],[-91.9765,48.245],[-91.9756,48.2444],[-91.9744,48.2453],[-91.9743,48.2454],[-91.9742,48.2455],[-91.9738,48.2459],[-91.9736,48.2464],[-91.9735,48.2467],[-91.9726,48.247],[-91.9704,48.2479],[-91.97,48.2488],[-91.9706,48.249],[-91.9708,48.2494],[-91.9714,48.2499],[-91.9719,48.25],[-91.9724,48.2503],[-91.9724,48.2506],[-91.9723,48.251],[-91.9722,48.2513],[-91.9722,48.2518],[-91.9718,48.252],[-91.9718,48.2529],[-91.9714,48.2531],[-91.9709,48.253],[-91.9705,48.2531],[-91.9704,48.2534],[-91.9699,48.2538],[-91.959,48.2537],[-91.957,48.2524],[-91.9541,48.2523],[-91.954,48.2518],[-91.9541,48.2517],[-91.9541,48.2515],[-91.954,48.2495],[-91.9512,48.2479],[-91.948,48.246],[-91.9496,48.2446],[-91.9511,48.2444],[-91.9582,48.2439],[-91.957,48.2389],[-91.9573,48.2387],[-91.9597,48.2369],[-91.9583,48.2332],[-91.9524,48.2331],[-91.9512,48.2334],[-91.9507,48.2332],[-91.9451,48.2304],[-91.942,48.2304],[-91.9375,48.2343],[-91.9288,48.2359],[-91.9282,48.236],[-91.9211,48.2368],[-91.9167,48.2386],[-91.9148,48.239],[-91.9134,48.2389],[-91.9131,48.2385],[-91.9106,48.2382],[-91.9097,48.2384],[-91.9076,48.2384],[-91.9073,48.2383],[-91.907,48.2382],[-91.9065,48.2378],[-91.9058,48.2373],[-91.9023,48.2372],[-91.8931,48.238],[-91.885,48.2283],[-91.8843,48.2275],[-91.8769,48.2239],[-91.8675,48.2192],[-91.865,48.2095],[-91.8643,48.207],[-91.8634,48.2071],[-91.8453,48.2088],[-91.8417,48.2094],[-91.8416,48.2094],[-91.8359,48.2103],[-91.8326,48.2095],[-91.8325,48.2094],[-91.8325,48.2094],[-91.8325,48.2094],[-91.8325,48.2094],[-91.8199,48.2112],[-91.8154,48.2119],[-91.8144,48.2094],[-91.8141,48.2084],[-91.8094,48.2063],[-91.7982,48.203],[-91.7983,48.1953],[-91.7982,48.1808],[-91.7984,48.1662],[-91.7983,48.1515],[-91.7981,48.1369],[-91.798,48.1224],[-91.7987,48.1079],[-91.7992,48.0936],[-91.7997,48.0788],[-91.8001,48.0643],[-91.8,48.0496],[-91.8,48.0353],[-91.8,48.0206],[-91.8001,48.0059],[-91.7996,47.9914],[-91.7992,47.977],[-91.7985,47.9625],[-91.7979,47.9481],[-91.7977,47.9334],[-91.7978,47.9189],[-91.7979,47.9045],[-91.7979,47.8899],[-91.7983,47.8771],[-91.7983,47.876],[-91.7988,47.8618],[-91.7992,47.8464],[-91.8,47.8319],[-91.8,47.8175],[-91.7999,47.8031],[-91.7997,47.7916],[-91.7997,47.7893],[-91.7997,47.7886],[-91.7995,47.7774],[-91.7995,47.776],[-91.7995,47.7742],[-91.7995,47.7723],[-91.7992,47.7626],[-91.7992,47.7598],[-91.7992,47.7538],[-91.7993,47.7482],[-91.7993,47.7454],[-91.7992,47.7388],[-91.7992,47.7339],[-91.799,47.731],[-91.7984,47.7201],[-91.7982,47.717],[-91.7981,47.7165],[-91.7977,47.7128],[-91.7971,47.707],[-91.7967,47.7024],[-91.7959,47.6925],[-91.7959,47.688],[-91.7955,47.678],[-91.7955,47.6778],[-91.7955,47.6733],[-91.7954,47.6729],[-91.795,47.663],[-91.7948,47.6586],[-91.7942,47.6486],[-91.794,47.6449],[-91.794,47.6442],[-91.7933,47.6345],[-91.793,47.6299],[-91.7923,47.6212],[-91.7922,47.6193],[-91.7919,47.6155],[-91.7915,47.6091],[-91.7913,47.6049],[-91.7912,47.6021],[-91.7911,47.6008],[-91.7908,47.5904],[-91.7905,47.5874],[-91.7904,47.5864],[-91.7893,47.576],[-91.7892,47.5749],[-91.789,47.5719],[-91.7888,47.5614],[-91.7887,47.5588],[-91.7886,47.5574],[-91.7878,47.5469],[-91.788,47.5431],[-91.788,47.5424],[-91.7886,47.533],[-91.7886,47.5322],[-91.7889,47.5187],[-91.7889,47.5176],[-91.789,47.5067],[-91.7891,47.5041],[-91.7891,47.503],[-91.7894,47.493],[-91.7894,47.4897],[-91.7894,47.4886],[-91.7895,47.4753],[-91.7895,47.4741],[-91.7895,47.4605],[-91.7895,47.4574],[-91.7893,47.4449],[-91.7894,47.4303],[-91.7895,47.416],[-91.7896,47.4017],[-91.7904,47.3872],[-91.7906,47.3726],[-91.792,47.3726],[-91.792,47.3576],[-91.792,47.3432],[-91.7918,47.3288],[-91.7918,47.3145],[-91.7919,47.3],[-91.792,47.2855],[-91.7921,47.271],[-91.7922,47.2565],[-91.7923,47.2422],[-91.7923,47.2276],[-91.7923,47.2128],[-91.7922,47.1985],[-91.7923,47.1843],[-91.7923,47.1698],[-91.7923,47.1556],[-91.7923,47.1411],[-91.7924,47.1265],[-91.7922,47.1119],[-91.7943,47.1119],[-91.7945,47.0976],[-91.7945,47.0831],[-91.7944,47.0688],[-91.7944,47.0541],[-91.7943,47.0399],[-91.7943,47.0255],[-91.7944,47.0109],[-91.7944,46.9965],[-91.7944,46.9818],[-91.7944,46.9675],[-91.7943,46.953],[-91.7944,46.9397],[-91.7945,46.9397],[-91.7947,46.9396],[-91.7948,46.9395],[-91.795,46.9394],[-91.7951,46.9394],[-91.7952,46.9394],[-91.7953,46.9393],[-91.7954,46.9391],[-91.7955,46.939],[-91.7957,46.9388],[-91.7957,46.9386],[-91.7958,46.9384],[-91.7958,46.9384],[-91.7959,46.9383],[-91.796,46.9382],[-91.7961,46.9381],[-91.7964,46.938],[-91.7966,46.9379],[-91.797,46.9379],[-91.7971,46.9378],[-91.7974,46.9378],[-91.7975,46.9378],[-91.7978,46.9378],[-91.798,46.9379],[-91.7981,46.938],[-91.7983,46.938],[-91.7986,46.9379],[-91.7989,46.9379],[-91.7991,46.9379],[-91.7993,46.9379],[-91.7995,46.9378],[-91.7996,46.9377],[-91.7998,46.9376],[-91.8004,46.9373],[-91.8007,46.9371],[-91.8011,46.9369],[-91.8013,46.9368],[-91.8016,46.9367],[-91.802,46.9366],[-91.8022,46.9365],[-91.8025,46.9364],[-91.8028,46.9363],[-91.8032,46.9361],[-91.8034,46.936],[-91.8036,46.9359],[-91.8037,46.9357],[-91.804,46.9356],[-91.8042,46.9354],[-91.8044,46.9352],[-91.8046,46.935],[-91.8048,46.9349],[-91.805,46.9347],[-91.8051,46.9346],[-91.8053,46.9345],[-91.8055,46.9345],[-91.8057,46.9344],[-91.8059,46.9343],[-91.806,46.9343],[-91.8062,46.9342],[-91.8064,46.9341],[-91.8066,46.9338],[-91.8067,46.9336],[-91.8069,46.9334],[-91.807,46.9332],[-91.8071,46.9331],[-91.8071,46.933],[-91.8072,46.9329],[-91.8073,46.9328],[-91.8075,46.9328],[-91.8076,46.9327],[-91.8078,46.9327],[-91.808,46.9327],[-91.8082,46.9325],[-91.8084,46.9324],[-91.8087,46.9322],[-91.8089,46.932],[-91.8091,46.9319],[-91.8094,46.9317],[-91.8097,46.9315],[-91.81,46.9314],[-91.8103,46.9312],[-91.8106,46.9311],[-91.8107,46.931],[-91.8109,46.9309],[-91.811,46.9309],[-91.8112,46.9309],[-91.8113,46.9308],[-91.8116,46.9306],[-91.8117,46.9305],[-91.8119,46.9303],[-91.812,46.9301],[-91.8121,46.9299],[-91.8122,46.9298],[-91.8123,46.9296],[-91.8123,46.9293],[-91.8124,46.9291],[-91.8124,46.929],[-91.8125,46.9288],[-91.8126,46.9287],[-91.813,46.9281],[-91.8133,46.9277],[-91.8135,46.9275],[-91.8137,46.9272],[-91.8138,46.9271],[-91.8139,46.927],[-91.8141,46.9268],[-91.8142,46.9267],[-91.8144,46.9267],[-91.8147,46.9266],[-91.8149,46.9265],[-91.815,46.9263],[-91.8151,46.9263],[-91.8152,46.9262],[-91.8153,46.926],[-91.8154,46.9259],[-91.8154,46.9258],[-91.8155,46.9258],[-91.8157,46.9256],[-91.8159,46.9252],[-91.8162,46.925],[-91.8163,46.9248],[-91.8165,46.9247],[-91.8166,46.9246],[-91.8168,46.9244],[-91.817,46.9243],[-91.8171,46.9243],[-91.8173,46.9242],[-91.8175,46.9241],[-91.8177,46.924],[-91.8179,46.924],[-91.8182,46.9241],[-91.8184,46.9242],[-91.8186,46.9244],[-91.8187,46.9245],[-91.8189,46.9246],[-91.819,46.9246],[-91.8192,46.9247],[-91.8194,46.9248],[-91.8196,46.9248],[-91.8198,46.9248],[-91.8202,46.9248],[-91.8204,46.9248],[-91.8206,46.9248],[-91.8208,46.9249],[-91.821,46.925],[-91.822,46.9252],[-91.8222,46.9253],[-91.8224,46.9253],[-91.8227,46.9254],[-91.8232,46.9256],[-91.8234,46.9257],[-91.8237,46.9259],[-91.8238,46.926],[-91.824,46.9261],[-91.8241,46.9262],[-91.8242,46.9262],[-91.8243,46.9263],[-91.8243,46.9264],[-91.8245,46.9265],[-91.8252,46.9267],[-91.8255,46.9269],[-91.8256,46.9269],[-91.8258,46.927],[-91.8259,46.9272],[-91.826,46.9272],[-91.826,46.9273],[-91.8265,46.9274],[-91.8267,46.9274],[-91.827,46.9275],[-91.8274,46.9275],[-91.8277,46.9275],[-91.828,46.9275],[-91.8283,46.9275],[-91.8286,46.9275],[-91.8289,46.9275],[-91.8292,46.9275],[-91.8295,46.9275],[-91.83,46.9275],[-91.8303,46.9275],[-91.8307,46.9275],[-91.831,46.9275],[-91.8314,46.9274],[-91.8318,46.9274],[-91.8321,46.9274],[-91.8325,46.9274],[-91.8327,46.9273],[-91.833,46.9273],[-91.8332,46.9273],[-91.8335,46.9272],[-91.8337,46.9272],[-91.8342,46.9269],[-91.8345,46.9268],[-91.8347,46.9267],[-91.8348,46.9267],[-91.8348,46.9266],[-91.8349,46.9266],[-91.835,46.9266],[-91.835,46.9267],[-91.8348,46.9268],[-91.8348,46.9269],[-91.8347,46.927],[-91.8347,46.9271],[-91.8346,46.9272],[-91.8348,46.9272],[-91.8351,46.9271],[-91.8352,46.927],[-91.8355,46.9269],[-91.8357,46.9269],[-91.8359,46.9268],[-91.8361,46.9268],[-91.8363,46.9268],[-91.8365,46.9267],[-91.8365,46.9267],[-91.8367,46.9266],[-91.8368,46.9266],[-91.8369,46.9265],[-91.8371,46.9265],[-91.8374,46.9265],[-91.8376,46.9265],[-91.8377,46.9265],[-91.8379,46.9264],[-91.8381,46.9263],[-91.8383,46.9262],[-91.8386,46.9261],[-91.8389,46.9261],[-91.8391,46.926],[-91.8393,46.9259],[-91.8396,46.9258],[-91.8398,46.9257],[-91.8401,46.9256],[-91.8405,46.9255],[-91.8407,46.9254],[-91.841,46.9253],[-91.8413,46.9253],[-91.8415,46.9252],[-91.8417,46.9251],[-91.8418,46.9251],[-91.8424,46.9248],[-91.8426,46.9246],[-91.8431,46.9244],[-91.8432,46.9243],[-91.8435,46.9242],[-91.8441,46.9239],[-91.8446,46.9238],[-91.8449,46.9236],[-91.8454,46.9234],[-91.8457,46.9233],[-91.8458,46.9232],[-91.8461,46.923],[-91.8464,46.9229],[-91.8466,46.9226],[-91.847,46.9224],[-91.8472,46.9223],[-91.8474,46.9221],[-91.8475,46.922],[-91.8476,46.9219],[-91.8477,46.9219],[-91.8478,46.9218],[-91.8481,46.9216],[-91.8484,46.9215],[-91.8486,46.9213],[-91.8488,46.9211],[-91.8491,46.9209],[-91.8493,46.9208],[-91.8495,46.9207],[-91.8497,46.9204],[-91.8499,46.9203],[-91.8501,46.9201],[-91.8502,46.9199],[-91.8504,46.9198],[-91.8505,46.9197],[-91.8506,46.9197],[-91.8511,46.9193],[-91.8512,46.9192],[-91.8513,46.919],[-91.8514,46.9188],[-91.8517,46.9185],[-91.8519,46.9182],[-91.8521,46.9179],[-91.8524,46.9175],[-91.8526,46.9171],[-91.8528,46.9168],[-91.8531,46.9165],[-91.8533,46.9162],[-91.8535,46.9158],[-91.8536,46.9156],[-91.8538,46.9155],[-91.854,46.9153],[-91.8542,46.9151],[-91.8544,46.915],[-91.8546,46.9148],[-91.8548,46.9146],[-91.855,46.9144],[-91.8551,46.9143],[-91.8552,46.9142],[-91.8553,46.9141],[-91.8555,46.9139],[-91.8557,46.9137],[-91.8559,46.9136],[-91.8562,46.9136],[-91.8565,46.9134],[-91.8568,46.9132],[-91.8569,46.9131],[-91.857,46.9131],[-91.8571,46.913],[-91.8572,46.9129],[-91.8576,46.9127],[-91.8579,46.9126],[-91.8581,46.9126],[-91.8583,46.9126],[-91.8584,46.9126],[-91.8585,46.9124],[-91.8588,46.9122],[-91.8591,46.912],[-91.8596,46.9116],[-91.8599,46.9115],[-91.8602,46.9114],[-91.8603,46.9113],[-91.8605,46.9112],[-91.8607,46.911],[-91.8609,46.9109],[-91.861,46.9108],[-91.8612,46.9107],[-91.8613,46.9106],[-91.8614,46.9105],[-91.8615,46.9104],[-91.8617,46.9103],[-91.8619,46.9102],[-91.8625,46.9101],[-91.863,46.91],[-91.8633,46.91],[-91.8635,46.9099],[-91.8637,46.9099],[-91.8639,46.9097],[-91.8642,46.9096],[-91.8644,46.9095],[-91.8644,46.9095],[-91.8646,46.9094],[-91.8648,46.9093],[-91.865,46.9092],[-91.8652,46.909],[-91.8654,46.9089],[-91.8656,46.9089],[-91.8659,46.9088],[-91.8662,46.9087],[-91.8664,46.9087],[-91.8666,46.9086],[-91.8668,46.9086],[-91.8675,46.9084],[-91.8679,46.9084],[-91.8681,46.9085],[-91.8684,46.9085],[-91.8686,46.9085],[-91.8688,46.9085],[-91.8691,46.9085],[-91.8693,46.9085],[-91.8705,46.9084],[-91.8709,46.9084],[-91.8711,46.9084],[-91.8714,46.9083],[-91.8717,46.9083],[-91.8724,46.9082],[-91.8734,46.9081],[-91.874,46.9081],[-91.8745,46.908],[-91.8749,46.908],[-91.8751,46.908],[-91.8755,46.9078],[-91.8758,46.9075],[-91.8761,46.9074],[-91.8764,46.9073],[-91.8766,46.9073],[-91.8768,46.9072],[-91.8772,46.9072],[-91.8775,46.9072],[-91.878,46.9071],[-91.8782,46.9071],[-91.879,46.9067],[-91.8797,46.9064],[-91.8802,46.9062],[-91.8807,46.906],[-91.8811,46.9058],[-91.8829,46.9047],[-91.885,46.9037],[-91.8854,46.9035],[-91.8856,46.9033],[-91.8858,46.9032],[-91.8859,46.903],[-91.8861,46.9029],[-91.8861,46.9028],[-91.8864,46.9027],[-91.8866,46.9026],[-91.8868,46.9025],[-91.8873,46.9021],[-91.8875,46.9019],[-91.8882,46.9015],[-91.8885,46.9015],[-91.8887,46.9015],[-91.8889,46.9015],[-91.8892,46.9014],[-91.8905,46.9005],[-91.891,46.9001],[-91.8912,46.8998],[-91.8915,46.8996],[-91.8918,46.8994],[-91.892,46.8994],[-91.8933,46.8987],[-91.8947,46.8979],[-91.895,46.8977],[-91.8953,46.8975],[-91.8955,46.8973],[-91.8956,46.8971],[-91.8957,46.8969],[-91.8961,46.8966],[-91.8971,46.8959],[-91.8976,46.8955],[-91.8981,46.8952],[-91.8986,46.895],[-91.8987,46.895],[-91.899,46.8949],[-91.8992,46.8948],[-91.8994,46.8947],[-91.9004,46.894],[-91.9009,46.8937],[-91.901,46.8935],[-91.9013,46.8933],[-91.9026,46.8928],[-91.9029,46.8926],[-91.9031,46.8925],[-91.9034,46.8923],[-91.9037,46.892],[-91.9038,46.892],[-91.904,46.892],[-91.9043,46.8917],[-91.9045,46.8915],[-91.9049,46.8912],[-91.9053,46.8909],[-91.9057,46.8906],[-91.9066,46.89],[-91.9069,46.8896],[-91.907,46.8894],[-91.9081,46.8887],[-91.9086,46.8881],[-91.9088,46.8879],[-91.909,46.8876],[-91.9093,46.8873],[-91.9098,46.8867],[-91.9102,46.8864],[-91.9106,46.8862],[-91.9108,46.8862],[-91.9109,46.886],[-91.911,46.8859],[-91.911,46.8858],[-91.9111,46.8857],[-91.9112,46.8856],[-91.9113,46.8855],[-91.9115,46.8852],[-91.9116,46.885],[-91.9118,46.8848],[-91.9122,46.8845],[-91.913,46.8839],[-91.9134,46.8837],[-91.9137,46.8836],[-91.9139,46.8836],[-91.9142,46.8836],[-91.9141,46.8835],[-91.9142,46.8834],[-91.9143,46.8833],[-91.9145,46.8832],[-91.9147,46.8831],[-91.915,46.883],[-91.9153,46.8829],[-91.9156,46.8827],[-91.9159,46.8826],[-91.9161,46.8824],[-91.9169,46.882],[-91.9173,46.8818],[-91.9178,46.8816],[-91.9191,46.8812],[-91.9194,46.8811],[-91.9197,46.881],[-91.9199,46.8808],[-91.9201,46.8807],[-91.9204,46.8805],[-91.9205,46.8805],[-91.9209,46.8804],[-91.9214,46.8803],[-91.9226,46.8799],[-91.923,46.8797],[-91.9235,46.8796],[-91.9244,46.8792],[-91.9256,46.8788],[-91.926,46.8786],[-91.9263,46.8786],[-91.9268,46.8784],[-91.9276,46.8781],[-91.928,46.878],[-91.9284,46.8777],[-91.9297,46.8771],[-91.9301,46.8769],[-91.9305,46.8767],[-91.9309,46.8764],[-91.9312,46.8762],[-91.9315,46.8761],[-91.9316,46.876],[-91.9317,46.8759],[-91.9318,46.8758],[-91.9319,46.8758],[-91.932,46.8757],[-91.9321,46.8755],[-91.9322,46.8755],[-91.9324,46.8754],[-91.9326,46.8753],[-91.9329,46.8752],[-91.9332,46.8752],[-91.9335,46.8751],[-91.9337,46.8751],[-91.9339,46.875],[-91.934,46.8749],[-91.9341,46.8748],[-91.9343,46.8746],[-91.9345,46.8744],[-91.9346,46.8743],[-91.9349,46.874],[-91.9353,46.8738],[-91.9358,46.8737],[-91.9362,46.8736],[-91.9368,46.8735],[-91.9374,46.8734],[-91.938,46.8734],[-91.9386,46.8732],[-91.9391,46.873],[-91.9397,46.8727],[-91.9403,46.8723],[-91.9408,46.8721],[-91.941,46.8719],[-91.9411,46.8717],[-91.9413,46.8717],[-91.9415,46.8718],[-91.9416,46.8717],[-91.9417,46.8717],[-91.9419,46.8715],[-91.942,46.8712],[-91.9422,46.871],[-91.9424,46.8709],[-91.9428,46.8708],[-91.943,46.8708],[-91.9432,46.8706],[-91.9435,46.8704],[-91.9438,46.8704],[-91.9444,46.8702],[-91.9449,46.8699],[-91.9456,46.8696],[-91.9465,46.8694],[-91.9475,46.8691],[-91.9484,46.8688],[-91.9492,46.8685],[-91.9496,46.8682],[-91.9499,46.8679],[-91.9502,46.8678],[-91.9507,46.8677],[-91.9513,46.8675],[-91.952,46.8671],[-91.9524,46.8668],[-91.9527,46.8665],[-91.953,46.8662],[-91.9535,46.8659],[-91.9536,46.8658],[-91.9545,46.8654],[-91.9552,46.8651],[-91.956,46.8645],[-91.9565,46.8641],[-91.9568,46.8638],[-91.957,46.8636],[-91.9574,46.8633],[-91.9577,46.8631],[-91.9581,46.8628],[-91.9587,46.8623],[-91.959,46.8619],[-91.9593,46.8617],[-91.9596,46.8616],[-91.96,46.8614],[-91.9604,46.8612],[-91.9608,46.8609],[-91.9611,46.8605],[-91.9615,46.8602],[-91.9621,46.86],[-91.9627,46.8597],[-91.963,46.8596],[-91.9633,46.8595],[-91.964,46.8592],[-91.9646,46.8589],[-91.965,46.8586],[-91.9654,46.8582],[-91.9657,46.858],[-91.966,46.8579],[-91.9663,46.8578],[-91.9667,46.8576],[-91.9669,46.8576],[-91.967,46.8575],[-91.9671,46.8574],[-91.9672,46.8573],[-91.9673,46.8571],[-91.9675,46.857],[-91.9677,46.857],[-91.9679,46.8571],[-91.9681,46.857],[-91.9683,46.8569],[-91.9686,46.8568],[-91.9688,46.8567],[-91.9692,46.8565],[-91.9695,46.8564],[-91.97,46.8563],[-91.9704,46.8563],[-91.9708,46.8562],[-91.9711,46.8561],[-91.9714,46.8562],[-91.9716,46.8561],[-91.972,46.8559],[-91.9724,46.8558],[-91.9728,46.8558],[-91.9731,46.8559],[-91.9732,46.8558],[-91.9734,46.8557],[-91.9736,46.8556],[-91.974,46.8555],[-91.9741,46.8554],[-91.9742,46.8553],[-91.9745,46.8552],[-91.9748,46.8551],[-91.9751,46.8549],[-91.9754,46.8547],[-91.9755,46.8548],[-91.9757,46.8548],[-91.9762,46.8546],[-91.9764,46.8545],[-91.9767,46.8542],[-91.977,46.8539],[-91.9772,46.8537],[-91.9773,46.8534],[-91.9775,46.8533],[-91.9777,46.8533],[-91.978,46.8532],[-91.9784,46.853],[-91.9787,46.8529],[-91.9791,46.8526],[-91.9792,46.8525],[-91.9795,46.8524],[-91.9797,46.8523],[-91.98,46.8521],[-91.9802,46.8519],[-91.9805,46.8517],[-91.9808,46.8516],[-91.9811,46.8515],[-91.9815,46.8515],[-91.9819,46.8513],[-91.982,46.8513],[-91.9827,46.851],[-91.983,46.8508],[-91.9833,46.8506],[-91.9836,46.8504],[-91.9838,46.8503],[-91.9841,46.8503],[-91.9842,46.8502],[-91.9845,46.8501],[-91.9849,46.8499],[-91.9854,46.8496],[-91.9856,46.8495],[-91.9857,46.8493],[-91.9858,46.8491],[-91.986,46.8489],[-91.9861,46.8487],[-91.9863,46.8484],[-91.9866,46.8482],[-91.9869,46.848],[-91.987,46.8478],[-91.9871,46.8476],[-91.9875,46.8476],[-91.9877,46.8474],[-91.9881,46.8471],[-91.9884,46.8469],[-91.9885,46.8467],[-91.9885,46.8465],[-91.9887,46.8462],[-91.9889,46.846],[-91.9892,46.8458],[-91.9895,46.8456],[-91.9898,46.8455],[-91.9901,46.8454],[-91.9903,46.8451],[-91.9906,46.845],[-91.9908,46.8448],[-91.991,46.8446],[-91.9913,46.8443],[-91.9915,46.844],[-91.9918,46.8437],[-91.992,46.8434],[-91.9923,46.8431],[-91.9926,46.8427],[-91.9928,46.8424],[-91.9931,46.8422],[-91.9934,46.8421],[-91.9938,46.842],[-91.9941,46.8419],[-91.9944,46.8417],[-91.9949,46.8414],[-91.9954,46.8411],[-91.9959,46.8409],[-91.9964,46.8407],[-91.9969,46.8405],[-91.9973,46.8403],[-91.9978,46.84],[-91.9981,46.8397],[-91.9983,46.8395],[-91.9983,46.8392],[-91.9985,46.839],[-91.9986,46.8389],[-91.999,46.8387],[-91.9992,46.8386],[-91.9997,46.8384],[-92.0001,46.8381],[-92.0002,46.8381],[-92.0003,46.8382],[-92.0005,46.8381],[-92.0007,46.838],[-92.0009,46.838],[-92.0012,46.8379],[-92.0014,46.8377],[-92.0016,46.8375],[-92.0019,46.8374],[-92.0022,46.8373],[-92.0025,46.8373],[-92.003,46.8372],[-92.0033,46.8372],[-92.0036,46.8372],[-92.0039,46.8372],[-92.0041,46.8371],[-92.0042,46.837],[-92.0044,46.8369],[-92.0045,46.8369],[-92.0048,46.8367],[-92.0051,46.8366],[-92.0055,46.8366],[-92.0055,46.8366],[-92.0058,46.8364],[-92.0059,46.8363],[-92.0059,46.8362],[-92.0059,46.8361],[-92.006,46.8361],[-92.0061,46.836],[-92.0062,46.8359],[-92.0064,46.8359],[-92.0068,46.8358],[-92.007,46.8358],[-92.0072,46.8358],[-92.0074,46.8358],[-92.0078,46.8357],[-92.008,46.8357],[-92.0083,46.8357],[-92.0086,46.8356],[-92.0088,46.8356],[-92.009,46.8356],[-92.0093,46.8356],[-92.0096,46.8356],[-92.0101,46.8355],[-92.0105,46.8354],[-92.0106,46.8354],[-92.0109,46.8353],[-92.0112,46.8352],[-92.0115,46.8351],[-92.0117,46.8351],[-92.0118,46.835],[-92.012,46.835],[-92.0125,46.8348],[-92.0126,46.8348],[-92.0128,46.8346],[-92.013,46.8345],[-92.0132,46.8344],[-92.0134,46.8343],[-92.0136,46.8342],[-92.0137,46.8342],[-92.0139,46.834],[-92.0141,46.8338],[-92.0143,46.8338],[-92.0143,46.8337],[-92.0145,46.8336],[-92.0147,46.8336],[-92.0149,46.8336],[-92.0152,46.8336],[-92.0156,46.8336],[-92.016,46.8335],[-92.0165,46.8334],[-92.0169,46.8334],[-92.0172,46.8333],[-92.0177,46.8331],[-92.018,46.833],[-92.0184,46.8327],[-92.0185,46.8326],[-92.0187,46.8324],[-92.0189,46.8322],[-92.019,46.8321],[-92.0192,46.8319],[-92.0193,46.8318],[-92.0193,46.8317],[-92.0194,46.8317],[-92.0196,46.8316],[-92.0198,46.8316],[-92.0201,46.8315],[-92.0206,46.8314],[-92.0209,46.8313],[-92.0213,46.8312],[-92.0214,46.8311],[-92.0218,46.8309],[-92.0221,46.8307],[-92.0225,46.8305],[-92.023,46.8302],[-92.0234,46.83],[-92.0236,46.8298],[-92.0238,46.8296],[-92.024,46.8295],[-92.0241,46.8294],[-92.0243,46.8293],[-92.0245,46.8292],[-92.0247,46.8291],[-92.0249,46.8291],[-92.025,46.829],[-92.0252,46.8289],[-92.0253,46.8288],[-92.0255,46.8286],[-92.0256,46.8284],[-92.0257,46.8283],[-92.0259,46.8282],[-92.0261,46.828],[-92.0263,46.8277],[-92.0264,46.8276],[-92.0266,46.8274],[-92.0267,46.8272],[-92.0267,46.8271],[-92.0268,46.827],[-92.0268,46.827],[-92.0268,46.8269],[-92.0269,46.8268],[-92.027,46.8267],[-92.0272,46.8266],[-92.0272,46.8266],[-92.0274,46.8265],[-92.0275,46.8265],[-92.0276,46.8264],[-92.0277,46.8263],[-92.0277,46.8262],[-92.0277,46.8261],[-92.0278,46.826],[-92.0278,46.826],[-92.0278,46.8259],[-92.0279,46.8259],[-92.0281,46.8258],[-92.0282,46.8256],[-92.0283,46.8255],[-92.0284,46.8254],[-92.0285,46.8252],[-92.0285,46.825],[-92.0287,46.8249],[-92.0287,46.8248],[-92.0289,46.8246],[-92.0291,46.8245],[-92.0294,46.8244],[-92.0295,46.8242],[-92.0297,46.8242],[-92.0299,46.8241],[-92.0301,46.824],[-92.0303,46.824],[-92.0307,46.824],[-92.0309,46.8239],[-92.0311,46.8238],[-92.0313,46.8237],[-92.0315,46.8236],[-92.0316,46.8234],[-92.0317,46.8233],[-92.0318,46.8231],[-92.0318,46.8231],[-92.0319,46.823],[-92.032,46.8229],[-92.0322,46.8228],[-92.0326,46.8226],[-92.0329,46.8224],[-92.0329,46.8224],[-92.0333,46.8222],[-92.0335,46.8222],[-92.0337,46.8221],[-92.0338,46.822],[-92.0339,46.8219],[-92.0343,46.8218],[-92.0347,46.8218],[-92.0352,46.8217],[-92.0358,46.8215],[-92.0364,46.8214],[-92.0369,46.8213],[-92.0372,46.8212],[-92.0376,46.8211],[-92.038,46.8209],[-92.0382,46.8207],[-92.0384,46.8205],[-92.0385,46.8204],[-92.0386,46.8203],[-92.0387,46.8203],[-92.0388,46.8202],[-92.0389,46.8202],[-92.0392,46.8202],[-92.0397,46.8201],[-92.04,46.8201],[-92.0401,46.8202],[-92.0405,46.8202],[-92.0408,46.8203],[-92.0411,46.8203],[-92.0414,46.8203],[-92.0417,46.8203],[-92.0419,46.8202],[-92.0421,46.8201],[-92.0423,46.8201],[-92.0425,46.82],[-92.0427,46.82],[-92.0429,46.82],[-92.0431,46.8199],[-92.0434,46.8197],[-92.0437,46.8196],[-92.044,46.8195],[-92.0441,46.8194],[-92.0443,46.8193],[-92.0445,46.8193],[-92.0447,46.8192],[-92.045,46.8191],[-92.0452,46.819],[-92.0454,46.8189],[-92.0456,46.8188],[-92.0457,46.8187],[-92.0459,46.8186],[-92.046,46.8185],[-92.0461,46.8183],[-92.0462,46.8182],[-92.0462,46.8181],[-92.0463,46.818],[-92.0463,46.8179],[-92.0464,46.8178],[-92.0465,46.8177],[-92.0466,46.8175],[-92.0467,46.8174],[-92.0468,46.8173],[-92.0469,46.8173],[-92.0469,46.8173],[-92.0471,46.8172],[-92.0473,46.8171],[-92.0474,46.8171],[-92.0476,46.8169],[-92.0478,46.8169],[-92.048,46.8167],[-92.0481,46.8166],[-92.0481,46.8165],[-92.0482,46.8164],[-92.0483,46.8164],[-92.0484,46.8163],[-92.0485,46.8162],[-92.0486,46.8161],[-92.0489,46.816],[-92.049,46.8158],[-92.0492,46.8157],[-92.0494,46.8156],[-92.0495,46.8155],[-92.0497,46.8154],[-92.0498,46.8151],[-92.0499,46.815],[-92.05,46.8148],[-92.0501,46.8146],[-92.0503,46.8144],[-92.0504,46.8144],[-92.0505,46.8144],[-92.0507,46.8144],[-92.0509,46.8143],[-92.0511,46.8143],[-92.0513,46.8143],[-92.0517,46.8142],[-92.0519,46.8142],[-92.0523,46.814],[-92.0525,46.8139],[-92.0527,46.8138],[-92.0529,46.8137],[-92.0531,46.8135],[-92.0533,46.8132],[-92.0535,46.8131],[-92.0537,46.8128],[-92.0539,46.8126],[-92.054,46.8124],[-92.054,46.8123],[-92.0542,46.812],[-92.0544,46.8118],[-92.0546,46.8117],[-92.0549,46.8115],[-92.0551,46.8115],[-92.0553,46.8113],[-92.0556,46.8112],[-92.0559,46.811],[-92.0563,46.8109],[-92.0566,46.8108],[-92.0569,46.8107],[-92.0573,46.8106],[-92.0575,46.8106],[-92.0581,46.8106],[-92.0583,46.8105],[-92.0587,46.8104],[-92.0588,46.8103],[-92.059,46.8101],[-92.0593,46.8099],[-92.0594,46.8097],[-92.0595,46.8095],[-92.0597,46.8092],[-92.0598,46.809],[-92.06,46.8087],[-92.06,46.8084],[-92.0602,46.808],[-92.0602,46.8078],[-92.0603,46.8074],[-92.0605,46.8071],[-92.0606,46.8069],[-92.0608,46.8066],[-92.061,46.8065],[-92.0611,46.8063],[-92.0612,46.8061],[-92.0612,46.8059],[-92.0613,46.8057],[-92.0616,46.8054],[-92.0617,46.8052],[-92.0619,46.8049],[-92.0621,46.8047],[-92.0622,46.8045],[-92.0625,46.8044],[-92.0627,46.8042],[-92.063,46.8041],[-92.0634,46.8039],[-92.0637,46.8038],[-92.064,46.8037],[-92.0642,46.8037],[-92.0646,46.8035],[-92.0649,46.8034],[-92.0652,46.8033],[-92.0656,46.8031],[-92.0659,46.803],[-92.0662,46.8028],[-92.0665,46.8026],[-92.0668,46.8024],[-92.067,46.8024],[-92.0674,46.8023],[-92.0677,46.8022],[-92.068,46.8022],[-92.0682,46.8023],[-92.0685,46.8023],[-92.0686,46.8023],[-92.0686,46.8023],[-92.0689,46.8024],[-92.0691,46.8023],[-92.0694,46.8023],[-92.0696,46.8022],[-92.0699,46.802],[-92.0702,46.8018],[-92.0705,46.8016],[-92.0707,46.8014],[-92.0708,46.8012],[-92.071,46.801],[-92.0712,46.8008],[-92.0713,46.8007],[-92.0715,46.8006],[-92.0716,46.8006],[-92.0718,46.8006],[-92.072,46.8007],[-92.0721,46.8007],[-92.0723,46.8006],[-92.0726,46.8006],[-92.0728,46.8005],[-92.0731,46.8004],[-92.0736,46.8002],[-92.0739,46.8],[-92.0741,46.7999],[-92.0743,46.7997],[-92.0746,46.7995],[-92.0749,46.7994],[-92.0752,46.7993],[-92.0755,46.7992],[-92.0758,46.7991],[-92.0762,46.7989],[-92.0764,46.7988],[-92.0765,46.7986],[-92.0766,46.7985],[-92.0767,46.7983],[-92.0769,46.7983],[-92.0771,46.7983],[-92.0774,46.7983],[-92.0775,46.7982],[-92.0777,46.7981],[-92.0778,46.798],[-92.0779,46.7979],[-92.078,46.7978],[-92.078,46.7977],[-92.0781,46.7975],[-92.0782,46.7974],[-92.0783,46.7973],[-92.0785,46.7973],[-92.0785,46.7973],[-92.0787,46.7974],[-92.0788,46.7974],[-92.0791,46.7974],[-92.0794,46.7973],[-92.0796,46.7973],[-92.0798,46.7973],[-92.0801,46.7973],[-92.0804,46.7973],[-92.0806,46.7973],[-92.0809,46.7972],[-92.0812,46.7971],[-92.0814,46.797],[-92.0815,46.7969],[-92.0817,46.7967],[-92.0819,46.7966],[-92.082,46.7965],[-92.0821,46.7963],[-92.0821,46.7962],[-92.0822,46.796],[-92.0823,46.7959],[-92.0825,46.7959],[-92.0828,46.7958],[-92.0831,46.7958],[-92.0835,46.7957],[-92.0838,46.7957],[-92.0841,46.7957],[-92.0844,46.7957],[-92.0847,46.7957],[-92.085,46.7957],[-92.0853,46.7956],[-92.0856,46.7955],[-92.0857,46.7954],[-92.0858,46.7953],[-92.0859,46.7952],[-92.0861,46.7951],[-92.0862,46.795],[-92.0863,46.7948],[-92.0864,46.7947],[-92.0867,46.7946],[-92.0869,46.7945],[-92.0872,46.7944],[-92.0875,46.7943],[-92.0878,46.7941],[-92.0881,46.794],[-92.0884,46.7938],[-92.0886,46.7937],[-92.0889,46.7935],[-92.0891,46.7933],[-92.0892,46.7931],[-92.0892,46.7931],[-92.0893,46.7929],[-92.0895,46.7926],[-92.0897,46.7924],[-92.0899,46.7923],[-92.0901,46.7921],[-92.0902,46.792],[-92.0903,46.7919],[-92.0904,46.7917],[-92.0903,46.7916],[-92.0903,46.7915],[-92.0903,46.7913],[-92.0904,46.7912],[-92.0905,46.791],[-92.0905,46.7908],[-92.0907,46.7905],[-92.0908,46.7902],[-92.091,46.7898],[-92.0912,46.7896],[-92.0913,46.7895],[-92.0915,46.7893],[-92.0918,46.7892],[-92.092,46.7892],[-92.0923,46.7892],[-92.0928,46.7889],[-92.0929,46.7888],[-92.0932,46.7887],[-92.0934,46.7885],[-92.0936,46.7883],[-92.0938,46.7881],[-92.0939,46.788],[-92.094,46.7877],[-92.0941,46.7875],[-92.0941,46.7874],[-92.094,46.7872],[-92.094,46.7871],[-92.094,46.7869],[-92.0939,46.7867],[-92.0938,46.7864],[-92.0936,46.786],[-92.0935,46.7857],[-92.0934,46.7854],[-92.0934,46.7852],[-92.0933,46.7849],[-92.0932,46.7848],[-92.0932,46.7845],[-92.0931,46.7842],[-92.093,46.7839],[-92.0929,46.7836],[-92.0926,46.7832],[-92.0925,46.783],[-92.0924,46.7828],[-92.0923,46.7826],[-92.0921,46.7825],[-92.092,46.7823],[-92.0919,46.7821],[-92.0918,46.7819],[-92.0917,46.7817],[-92.0916,46.7814],[-92.0915,46.7813],[-92.0913,46.781],[-92.0911,46.7807],[-92.091,46.7804],[-92.0912,46.7801],[-92.0914,46.7787],[-92.0914,46.7784],[-92.0909,46.7775],[-92.0908,46.7773],[-92.09,46.7762],[-92.0897,46.7757],[-92.0894,46.7754],[-92.0892,46.7751],[-92.0889,46.7747],[-92.0888,46.7743],[-92.0879,46.7731],[-92.0879,46.773],[-92.0878,46.773],[-92.0876,46.7727],[-92.0859,46.7704],[-92.0859,46.7702],[-92.0849,46.7691],[-92.0846,46.7687],[-92.0842,46.7682],[-92.0838,46.7676],[-92.0829,46.7665],[-92.0829,46.7664],[-92.0826,46.7659],[-92.0819,46.7651],[-92.0812,46.7644],[-92.0811,46.7642],[-92.0784,46.7609],[-92.0781,46.7606],[-92.0768,46.759],[-92.0767,46.7588],[-92.0765,46.7587],[-92.0764,46.7584],[-92.076,46.7581],[-92.0758,46.7578],[-92.0739,46.7555],[-92.0735,46.7552],[-92.0735,46.755],[-92.073,46.7546],[-92.0729,46.7544],[-92.0726,46.754],[-92.0724,46.754],[-92.0724,46.7538],[-92.0717,46.7532],[-92.0716,46.753],[-92.0707,46.7521],[-92.0706,46.7519],[-92.0703,46.7517],[-92.0694,46.7506],[-92.0693,46.7505],[-92.069,46.7502],[-92.0688,46.75],[-92.0686,46.7497],[-92.0684,46.7495],[-92.0681,46.7491],[-92.0679,46.7489],[-92.0677,46.7487],[-92.0676,46.7486],[-92.0672,46.7481],[-92.0668,46.7478],[-92.0658,46.7466],[-92.0633,46.7441],[-92.0629,46.7437],[-92.0628,46.7435],[-92.0625,46.7432],[-92.0623,46.743],[-92.062,46.7427],[-92.0618,46.7424],[-92.0614,46.7421],[-92.0613,46.7419],[-92.0607,46.7414],[-92.0597,46.7403],[-92.0592,46.7399],[-92.0588,46.7394],[-92.0575,46.7381],[-92.0568,46.7374],[-92.0563,46.737],[-92.0559,46.7366],[-92.0546,46.7353],[-92.0546,46.7352],[-92.0544,46.7352],[-92.0542,46.735],[-92.054,46.7347],[-92.0504,46.7315],[-92.0477,46.7291],[-92.0466,46.7282],[-92.0466,46.728],[-92.0463,46.7279],[-92.0459,46.7275],[-92.0448,46.7265],[-92.0376,46.7206],[-92.037,46.7201],[-92.0348,46.7183],[-92.0274,46.7118],[-92.0269,46.7114],[-92.0267,46.7113],[-92.0265,46.7112],[-92.0264,46.7112],[-92.0258,46.7114],[-92.0253,46.7111],[-92.0243,46.7109],[-92.0214,46.7108],[-92.0205,46.7107],[-92.0194,46.7106],[-92.0192,46.7102],[-92.0192,46.7099],[-92.0187,46.7088],[-92.0174,46.7072],[-92.0164,46.7062],[-92.0163,46.706],[-92.0202,46.7041],[-92.025,46.7058],[-92.0262,46.7062],[-92.0269,46.7065],[-92.0339,46.709],[-92.0428,46.7153],[-92.0479,46.719],[-92.0501,46.7206],[-92.0594,46.7274],[-92.0648,46.7312],[-92.0687,46.734],[-92.0701,46.735],[-92.0713,46.7359],[-92.0894,46.7493],[-92.0985,46.7491],[-92.1001,46.7491],[-92.1081,46.7492],[-92.1086,46.749],[-92.1102,46.749],[-92.1138,46.7489],[-92.1165,46.7487],[-92.1173,46.7484],[-92.1184,46.7479],[-92.1252,46.745],[-92.1317,46.7422],[-92.1378,46.7396],[-92.1428,46.7351],[-92.1429,46.735],[-92.1432,46.7347],[-92.1433,46.7306],[-92.1433,46.7282],[-92.1412,46.7253],[-92.1438,46.7205],[-92.1448,46.7184],[-92.1462,46.716],[-92.1467,46.7158],[-92.1486,46.7152],[-92.1534,46.7158],[-92.1551,46.716],[-92.1672,46.72],[-92.1708,46.7189],[-92.1719,46.7185],[-92.1742,46.7173],[-92.1747,46.7172],[-92.176,46.7171],[-92.1788,46.7168],[-92.189,46.7176],[-92.1914,46.7163],[-92.1916,46.7157],[-92.1917,46.7153],[-92.1932,46.7113],[-92.1959,46.7089],[-92.1973,46.7077],[-92.1997,46.7067],[-92.2003,46.7064],[-92.2004,46.7064],[-92.201,46.7062],[-92.2015,46.706],[-92.2019,46.7058],[-92.2026,46.7054],[-92.2046,46.7041],[-92.2056,46.7026],[-92.2051,46.6984],[-92.1984,46.6962],[-92.1956,46.696],[-92.1892,46.6956],[-92.183,46.6953],[-92.178,46.692],[-92.1778,46.6919],[-92.1764,46.6903],[-92.176,46.6864],[-92.1775,46.6835],[-92.1813,46.6803],[-92.1824,46.68],[-92.1875,46.679],[-92.1906,46.6776],[-92.1916,46.6772],[-92.1924,46.6768],[-92.1957,46.6741],[-92.1958,46.674],[-92.1994,46.6703],[-92.204,46.667],[-92.2054,46.6648],[-92.2046,46.6634],[-92.2021,46.659],[-92.2015,46.6567],[-92.2022,46.6551],[-92.2044,46.6537],[-92.207,46.652],[-92.2123,46.65],[-92.2163,46.6499],[-92.2166,46.65],[-92.2234,46.6527],[-92.2262,46.6529],[-92.2284,46.653],[-92.2355,46.6501],[-92.2376,46.6498],[-92.2424,46.6493],[-92.2486,46.6535],[-92.2509,46.655],[-92.2521,46.6558],[-92.2525,46.6561],[-92.2545,46.6574],[-92.2549,46.6577],[-92.2556,46.6581],[-92.2565,46.6588],[-92.2587,46.6577],[-92.2596,46.6572],[-92.2659,46.6511],[-92.2705,46.6508],[-92.2727,46.6529],[-92.2735,46.655],[-92.2743,46.6575],[-92.2784,46.6587],[-92.2799,46.6587],[-92.2836,46.6589],[-92.2842,46.6592],[-92.2844,46.6594],[-92.2861,46.6604],[-92.287,46.6629],[-92.2871,46.6631],[-92.2872,46.6647],[-92.2873,46.6669],[-92.2873,46.6674],[-92.2881,46.6676],[-92.2907,46.6681],[-92.2912,46.6682],[-92.2921,46.6661],[-92.2922,46.665],[-92.2921,46.6633],[-92.301,46.6636],[-92.3012,46.6773],[-92.3012,46.6919],[-92.3013,46.7063],[-92.3014,46.7208],[-92.3016,46.7353],[-92.3014,46.7498],[-92.3015,46.7643],[-92.3223,46.7652],[-92.3435,46.7651],[-92.3646,46.765],[-92.3856,46.765],[-92.4064,46.7649],[-92.4283,46.765],[-92.4495,46.7657],[-92.4705,46.7656],[-92.4924,46.7657],[-92.5125,46.7658],[-92.5336,46.7659],[-92.5548,46.7662],[-92.5759,46.7667],[-92.5967,46.7665],[-92.6177,46.7667],[-92.6385,46.767],[-92.6592,46.7692],[-92.6803,46.7692],[-92.7014,46.7687],[-92.7226,46.7682],[-92.7442,46.7677],[-92.7459,46.7677],[-92.7653,46.7674],[-92.7864,46.7666],[-92.8084,46.7661],[-92.8296,46.7661],[-92.8508,46.7662],[-92.8721,46.7664],[-92.8932,46.7666],[-92.9143,46.7661],[-92.9356,46.7662],[-92.9567,46.7662],[-92.9777,46.7665],[-92.9988,46.7669],[-93.0201,46.7668],[-93.0412,46.7667],[-93.0615,46.7667],[-93.0609,46.781],[-93.061,46.7956],[-93.0606,46.81],[-93.0606,46.8241],[-93.0603,46.8387],[-93.06,46.853],[-93.0597,46.8672],[-93.059,46.8817],[-93.0587,46.8964],[-93.0582,46.9108],[-93.0583,46.9251],[-93.0577,46.9398],[-93.0576,46.9541],[-93.0573,46.9685],[-93.0571,46.9832],[-93.0568,46.9976],[-93.0564,47.0121],[-93.0559,47.0265],[-93.0557,47.0407],[-93.0558,47.0551],[-93.0558,47.0698],[-93.0557,47.084],[-93.056,47.0984],[-93.0562,47.1093],[-93.0664,47.1094],[-93.0663,47.1239],[-93.0659,47.1382],[-93.0659,47.1526],[-93.0655,47.1671],[-93.0652,47.1814],[-93.0654,47.196],[-93.0654,47.2103],[-93.0655,47.2248],[-93.0657,47.2394],[-93.0658,47.2538],[-93.0657,47.2683],[-93.0658,47.2828],[-93.0658,47.2975],[-93.0652,47.3119],[-93.0647,47.3265],[-93.0645,47.3412],[-93.0644,47.3556],[-93.0644,47.3716],[-93.0666,47.3716],[-93.0689,47.386],[-93.0693,47.4003],[-93.0692,47.4148],[-93.0692,47.429],[-93.069,47.4434],[-93.0688,47.4578],[-93.0673,47.472],[-93.067,47.4859],[-93.0651,47.5003],[-93.0647,47.5147],[-93.0641,47.529],[-93.0637,47.5445],[-93.0637,47.559],[-93.0638,47.5734],[-93.0628,47.5875],[-93.0628,47.6026],[-93.0643,47.6172],[-93.0637,47.6333],[-93.0637,47.6476],[-93.0633,47.6621],[-93.0626,47.6774],[-93.0619,47.691],[-93.0612,47.7056],[-93.0613,47.7205],[-93.0821,47.7206],[-93.0823,47.7355],[-93.0823,47.7493],[-93.0826,47.7635],[-93.083,47.7779],[-93.0834,47.7917],[-93.0837,47.8064],[-93.0837,47.8209],[-93.0837,47.8223],[-93.0831,47.835],[-93.083,47.8368],[-93.0823,47.8494],[-93.0822,47.8513],[-93.0815,47.8637],[-93.0813,47.8656],[-93.0812,47.8676],[-93.0808,47.878],[-93.0807,47.88],[-93.0808,47.8922],[-93.0808,47.8945],[-93.0809,47.9067],[-93.0809,47.9088],[-93.0809,47.9212],[-93.0809,47.9235],[-93.0809,47.9356],[-93.0809,47.938],[-93.0808,47.9504],[-93.0808,47.9525],[-93.0808,47.9647],[-93.0809,47.967],[-93.0809,47.9786],[-93.088,47.9787],[-93.0872,47.9932],[-93.0887,48.0075],[-93.0886,48.022],[-93.089,48.0366],[-93.0892,48.0509],[-93.0892,48.0679],[-93.0965,48.0678],[-93.0965,48.0679],[-93.0968,48.0823],[-93.097,48.0969],[-93.0972,48.1114],[-93.0969,48.1259],[-93.097,48.1402],[-93.097,48.1546],[-93.097,48.1692],[-93.0975,48.1836],[-93.0979,48.1981],[-93.0978,48.2126],[-93.0977,48.2271],[-93.0977,48.2426],[-93.0949,48.2425],[-93.0949,48.2426],[-93.0953,48.2576],[-93.0952,48.2716],[-93.095,48.2862],[-93.0952,48.3004],[-93.0953,48.3153],[-93.0948,48.3298],[-93.0948,48.3442],[-93.0945,48.3589],[-93.094,48.3734],[-93.094,48.3879],[-93.0938,48.4024],[-93.0935,48.4147],[-93.0923,48.4147],[-93.0922,48.429],[-93.0922,48.4303],[-93.092,48.4436],[-93.092,48.4449],[-93.0919,48.458],[-93.0918,48.4596],[-93.0915,48.4724],[-93.0914,48.474],[-93.0911,48.4867],[-93.091,48.4884],[-93.0905,48.501],[-93.0905,48.5151],[-93.0903,48.5296],[-93.0902,48.5441],[-93.0902,48.5583],[-93.09,48.5727],[-93.0898,48.5872],[-93.0895,48.6016],[-93.0886,48.6163],[-93.0884,48.6278]]],"type":"Polygon"},"id":"69","properties":{"Area":17451037319.2417,"CTYONLY_":7,"Code":"STLO","LASTMOD":"2010-10-17T00:00:00Z","Name":"St. Louis","Perimiter":682518.436},"type":"Feature"},{"geometry":{"coordinates":[[[-95.3425,48.5402],[-95.3412,48.5402],[-95.321,48.54],[-95.3194,48.54],[-95.2992,48.5402],[-95.2975,48.5401],[-95.2773,48.54],[-95.2756,48.54],[-95.2554,48.5398],[-95.2537,48.5398],[-95.2339,48.5399],[-95.2324,48.5399],[-95.2119,48.54],[-95.2115,48.5252],[-95.2115,48.5244],[-95.2111,48.5109],[-95.2111,48.5101],[-95.2112,48.4962],[-95.2111,48.4816],[-95.211,48.4673],[-95.211,48.4666],[-95.2112,48.4529],[-95.2113,48.4522],[-95.2113,48.4387],[-95.2113,48.4376],[-95.2113,48.4255],[-95.2113,48.4242],[-95.2113,48.4232],[-95.2112,48.4096],[-95.2112,48.4087],[-95.2111,48.3952],[-95.2111,48.3941],[-95.211,48.3808],[-95.211,48.3797],[-95.2106,48.3661],[-95.2066,48.3661],[-95.1983,48.3661],[-95.1887,48.3661],[-95.1861,48.3661],[-95.1669,48.3661],[-95.164,48.3661],[-95.1454,48.3662],[-95.1424,48.3662],[-95.1315,48.3662],[-95.1236,48.3663],[-95.1207,48.3663],[-95.1018,48.3663],[-95.1008,48.3663],[-95.099,48.3663],[-95.0801,48.3664],[-95.0773,48.3664],[-95.0586,48.3665],[-95.0555,48.3665],[-95.0369,48.3665],[-95.0337,48.3665],[-95.0153,48.3665],[-95.0119,48.3665],[-94.9932,48.3667],[-94.9901,48.3667],[-94.9716,48.3667],[-94.9684,48.3667],[-94.95,48.3666],[-94.9469,48.3666],[-94.9283,48.3667],[-94.9264,48.3667],[-94.9065,48.3666],[-94.9049,48.3666],[-94.8849,48.3666],[-94.8833,48.3667],[-94.8632,48.3667],[-94.8616,48.3667],[-94.8416,48.3669],[-94.8399,48.3669],[-94.8199,48.3669],[-94.8183,48.3669],[-94.7983,48.3669],[-94.7967,48.3669],[-94.7765,48.3669],[-94.7748,48.3669],[-94.7549,48.3669],[-94.7533,48.3669],[-94.7329,48.3669],[-94.7315,48.3669],[-94.7117,48.3668],[-94.7099,48.3669],[-94.6898,48.3671],[-94.683,48.3671],[-94.6694,48.3672],[-94.6679,48.3673],[-94.6622,48.3673],[-94.6505,48.3673],[-94.6465,48.3673],[-94.6405,48.3673],[-94.6245,48.3673],[-94.6188,48.3673],[-94.6029,48.3674],[-94.5971,48.3675],[-94.5812,48.3674],[-94.5754,48.3674],[-94.5593,48.3674],[-94.5536,48.3674],[-94.5378,48.3674],[-94.5335,48.3674],[-94.5157,48.3674],[-94.5118,48.3675],[-94.4941,48.3674],[-94.4924,48.3674],[-94.4906,48.3674],[-94.4722,48.3674],[-94.4688,48.3675],[-94.4505,48.3675],[-94.4471,48.3675],[-94.4288,48.3675],[-94.4252,48.3675],[-94.4253,48.352],[-94.425,48.3372],[-94.4248,48.3227],[-94.4246,48.3081],[-94.4244,48.2938],[-94.4243,48.2791],[-94.424,48.2649],[-94.4237,48.2504],[-94.4237,48.2356],[-94.4238,48.2212],[-94.4236,48.2067],[-94.4233,48.1923],[-94.4235,48.1781],[-94.4235,48.1637],[-94.4233,48.1491],[-94.4236,48.1348],[-94.4234,48.1204],[-94.4233,48.1059],[-94.4231,48.092],[-94.4234,48.0776],[-94.4247,48.0632],[-94.4246,48.0489],[-94.4241,48.0344],[-94.4236,48.0199],[-94.4176,48.02],[-94.4177,48.006],[-94.4176,47.9914],[-94.4173,47.9769],[-94.4172,47.9623],[-94.4174,47.9477],[-94.4175,47.9332],[-94.4174,47.9186],[-94.4175,47.9175],[-94.4176,47.9041],[-94.4177,47.9031],[-94.418,47.8886],[-94.4184,47.8744],[-94.4186,47.86],[-94.4185,47.8459],[-94.4186,47.8316],[-94.4187,47.817],[-94.4188,47.8026],[-94.4189,47.7881],[-94.4189,47.7735],[-94.4191,47.759],[-94.4192,47.7445],[-94.4191,47.7302],[-94.419,47.7155],[-94.4187,47.7012],[-94.4185,47.6867],[-94.4184,47.6721],[-94.417,47.6722],[-94.417,47.6578],[-94.4167,47.6435],[-94.4165,47.6291],[-94.4163,47.615],[-94.4159,47.6009],[-94.4136,47.5866],[-94.4144,47.5723],[-94.414,47.5578],[-94.4148,47.5432],[-94.4146,47.5286],[-94.4149,47.5145],[-94.4151,47.5],[-94.4154,47.4861],[-94.4156,47.4717],[-94.416,47.4571],[-94.4161,47.4449],[-94.4161,47.443],[-94.4157,47.4287],[-94.4159,47.4119],[-94.4372,47.4118],[-94.4586,47.4118],[-94.4798,47.4119],[-94.5009,47.412],[-94.5243,47.4114],[-94.5458,47.4109],[-94.5636,47.411],[-94.585,47.411],[-94.6069,47.4101],[-94.6279,47.4103],[-94.6492,47.4102],[-94.6702,47.4102],[-94.6918,47.4098],[-94.7129,47.4095],[-94.7344,47.4098],[-94.7563,47.4105],[-94.7777,47.4102],[-94.7998,47.4098],[-94.8209,47.41],[-94.8423,47.4102],[-94.8636,47.4103],[-94.8849,47.4105],[-94.9063,47.4107],[-94.9274,47.4118],[-94.9487,47.4115],[-94.97,47.4114],[-94.9914,47.4114],[-95.0127,47.4114],[-95.0341,47.4117],[-95.0557,47.4119],[-95.0766,47.4123],[-95.098,47.4125],[-95.1193,47.4126],[-95.1406,47.4125],[-95.1619,47.4127],[-95.1829,47.4127],[-95.1828,47.4268],[-95.1828,47.4412],[-95.1829,47.4557],[-95.183,47.4703],[-95.1831,47.4845],[-95.1833,47.499],[-95.1837,47.5135],[-95.1839,47.528],[-95.1841,47.5424],[-95.1841,47.5566],[-95.1844,47.571],[-95.1847,47.5861],[-95.1849,47.6006],[-95.1849,47.6151],[-95.1849,47.6297],[-95.1849,47.6442],[-95.1847,47.6587],[-95.1849,47.6735],[-95.1904,47.6734],[-95.1941,47.6734],[-95.1944,47.688],[-95.1944,47.7024],[-95.1943,47.717],[-95.1942,47.7313],[-95.1941,47.746],[-95.1941,47.7606],[-95.1939,47.7752],[-95.1939,47.7896],[-95.1938,47.8033],[-95.1937,47.8044],[-95.1937,47.8188],[-95.1936,47.8334],[-95.1935,47.8479],[-95.1935,47.8624],[-95.1934,47.8726],[-95.2003,47.8732],[-95.2025,47.8735],[-95.205,47.874],[-95.2071,47.8742],[-95.2103,47.8744],[-95.2105,47.8745],[-95.2146,47.875],[-95.215,47.8751],[-95.2172,47.8755],[-95.2193,47.876],[-95.2218,47.8765],[-95.223,47.8768],[-95.2288,47.8781],[-95.2313,47.8788],[-95.2345,47.8798],[-95.2359,47.8803],[-95.2374,47.8807],[-95.2377,47.8807],[-95.238,47.8809],[-95.2397,47.8814],[-95.2415,47.882],[-95.2456,47.8829],[-95.2473,47.8837],[-95.2485,47.8844],[-95.2502,47.8852],[-95.2518,47.8861],[-95.2538,47.8876],[-95.2558,47.8891],[-95.2578,47.8903],[-95.258,47.8905],[-95.2585,47.8909],[-95.2592,47.8917],[-95.2592,47.8918],[-95.26,47.8925],[-95.2618,47.8944],[-95.2625,47.895],[-95.2635,47.896],[-95.2655,47.8979],[-95.2657,47.8981],[-95.266,47.8984],[-95.2661,47.8985],[-95.2663,47.8987],[-95.2664,47.8991],[-95.2665,47.8992],[-95.2665,47.8993],[-95.2666,47.8993],[-95.2668,47.8999],[-95.2671,47.9004],[-95.2677,47.901],[-95.2681,47.9016],[-95.2681,47.9017],[-95.2683,47.902],[-95.2688,47.9029],[-95.2689,47.9032],[-95.2699,47.9049],[-95.2701,47.9056],[-95.2702,47.9059],[-95.2703,47.9062],[-95.2704,47.9062],[-95.2704,47.9063],[-95.2705,47.9064],[-95.2705,47.9064],[-95.2706,47.9066],[-95.2709,47.9069],[-95.2709,47.907],[-95.2723,47.9089],[-95.2728,47.9097],[-95.2728,47.9098],[-95.2729,47.9099],[-95.2729,47.9101],[-95.2732,47.9107],[-95.2734,47.9114],[-95.2734,47.9116],[-95.2735,47.9116],[-95.2736,47.9121],[-95.2738,47.9125],[-95.2738,47.9128],[-95.2741,47.9135],[-95.2741,47.9139],[-95.2748,47.9154],[-95.275,47.9156],[-95.2753,47.9162],[-95.2754,47.9168],[-95.2756,47.9172],[-95.2756,47.9175],[-95.2761,47.92],[-95.2762,47.9206],[-95.2762,47.9206],[-95.2763,47.921],[-95.2764,47.9215],[-95.2765,47.922],[-95.2766,47.9227],[-95.2767,47.9231],[-95.2768,47.9236],[-95.2771,47.9247],[-95.2774,47.9254],[-95.2774,47.9257],[-95.2776,47.9263],[-95.2778,47.9281],[-95.278,47.9286],[-95.2781,47.9302],[-95.278,47.9321],[-95.2779,47.9328],[-95.2779,47.9351],[-95.2779,47.9351],[-95.2774,47.938],[-95.2772,47.9384],[-95.2772,47.9389],[-95.277,47.9414],[-95.2769,47.9416],[-95.2767,47.9438],[-95.2767,47.9449],[-95.2761,47.947],[-95.2759,47.9474],[-95.2756,47.9487],[-95.2755,47.9488],[-95.2753,47.9495],[-95.2751,47.9507],[-95.2749,47.9515],[-95.2743,47.9529],[-95.2743,47.9531],[-95.2742,47.9534],[-95.2742,47.9541],[-95.2741,47.9561],[-95.274,47.9568],[-95.2739,47.9574],[-95.2735,47.958],[-95.2731,47.9584],[-95.2729,47.9586],[-95.2728,47.9587],[-95.2726,47.959],[-95.2726,47.9593],[-95.2725,47.9605],[-95.2722,47.961],[-95.2712,47.9623],[-95.271,47.9628],[-95.2708,47.9632],[-95.2706,47.9636],[-95.2703,47.9637],[-95.2701,47.9639],[-95.2701,47.964],[-95.2698,47.9643],[-95.2694,47.9655],[-95.268,47.9688],[-95.267,47.9704],[-95.267,47.9707],[-95.2667,47.9708],[-95.2664,47.9714],[-95.2657,47.9727],[-95.2646,47.9748],[-95.2645,47.9752],[-95.2639,47.9765],[-95.2636,47.9771],[-95.2627,47.9786],[-95.2618,47.9803],[-95.259,47.9839],[-95.2585,47.9852],[-95.2583,47.9856],[-95.2582,47.9865],[-95.258,47.987],[-95.2579,47.9875],[-95.2576,47.9883],[-95.2571,47.9891],[-95.2554,47.9917],[-95.2551,47.992],[-95.2546,47.9926],[-95.2543,47.9932],[-95.253,47.9954],[-95.2526,47.9964],[-95.2523,47.9968],[-95.252,47.9971],[-95.2518,47.9973],[-95.2512,47.998],[-95.2508,47.9988],[-95.2507,47.999],[-95.2507,48.0],[-95.2504,48.0],[-95.2502,48.0],[-95.2495,48.0],[-95.2495,48.0009],[-95.2493,48.0015],[-95.249,48.002],[-95.2486,48.0025],[-95.2481,48.0029],[-95.2479,48.0031],[-95.2477,48.0041],[-95.2472,48.0046],[-95.247,48.0048],[-95.2464,48.0055],[-95.2459,48.0059],[-95.2455,48.0066],[-95.245,48.0071],[-95.2449,48.0072],[-95.2445,48.0076],[-95.2445,48.0076],[-95.2444,48.008],[-95.2442,48.0081],[-95.2441,48.0083],[-95.2439,48.0086],[-95.2439,48.0087],[-95.2438,48.0087],[-95.2433,48.009],[-95.2423,48.0097],[-95.2421,48.01],[-95.2418,48.0103],[-95.2417,48.0106],[-95.2414,48.0108],[-95.2414,48.0109],[-95.2409,48.0111],[-95.2407,48.0112],[-95.2404,48.0114],[-95.2401,48.0117],[-95.24,48.0119],[-95.24,48.0119],[-95.2396,48.0123],[-95.2394,48.0124],[-95.2387,48.0127],[-95.2377,48.0134],[-95.2376,48.0135],[-95.2372,48.0139],[-95.2371,48.0142],[-95.2371,48.0143],[-95.237,48.0144],[-95.2368,48.0145],[-95.2367,48.0145],[-95.2363,48.0148],[-95.2362,48.0148],[-95.2358,48.0149],[-95.2354,48.0152],[-95.2352,48.0155],[-95.2347,48.0158],[-95.2326,48.017],[-95.2323,48.0174],[-95.2306,48.0185],[-95.2304,48.0188],[-95.2303,48.0191],[-95.2297,48.0196],[-95.2293,48.0199],[-95.2289,48.0201],[-95.2378,48.0201],[-95.2473,48.0201],[-95.2493,48.0201],[-95.2594,48.0201],[-95.269,48.0201],[-95.281,48.0202],[-95.2887,48.0201],[-95.2906,48.0201],[-95.2933,48.0201],[-95.3025,48.0202],[-95.3122,48.0202],[-95.3224,48.0203],[-95.3338,48.0203],[-95.3401,48.0203],[-95.3439,48.0204],[-95.3554,48.0204],[-95.3654,48.0204],[-95.3661,48.0204],[-95.377,48.0205],[-95.3871,48.0206],[-95.3985,48.0206],[-95.4086,48.0207],[-95.4201,48.0206],[-95.4302,48.0206],[-95.4417,48.0206],[-95.4523,48.0206],[-95.4632,48.0207],[-95.4738,48.0207],[-95.485,48.0207],[-95.4954,48.0207],[-95.4959,48.0207],[-95.5065,48.0208],[-95.517,48.0208],[-95.5215,48.0209],[-95.5277,48.0209],[-95.5384,48.0209],[-95.5398,48.0209],[-95.5491,48.0209],[-95.5597,48.0208],[-95.5705,48.0208],[-95.5828,48.0207],[-95.5922,48.0207],[-95.5923,48.035],[-95.5925,48.0497],[-95.5925,48.0642],[-95.5926,48.0787],[-95.5928,48.0931],[-95.593,48.1078],[-95.5931,48.1223],[-95.5936,48.1368],[-95.5938,48.1512],[-95.5939,48.1658],[-95.5939,48.173],[-95.594,48.1802],[-95.5938,48.1946],[-95.5939,48.2092],[-95.5939,48.2236],[-95.5941,48.2382],[-95.5941,48.2526],[-95.5937,48.267],[-95.5934,48.2815],[-95.5934,48.2961],[-95.5932,48.3105],[-95.5932,48.325],[-95.5932,48.3396],[-95.5933,48.354],[-95.5933,48.3656],[-95.5933,48.3656],[-95.6016,48.3655],[-95.602,48.3798],[-95.6021,48.3809],[-95.6026,48.3942],[-95.6026,48.395],[-95.6026,48.4088],[-95.6026,48.4095],[-95.6023,48.4232],[-95.6023,48.424],[-95.6021,48.4376],[-95.602,48.4385],[-95.6016,48.4522],[-95.6016,48.453],[-95.6016,48.4666],[-95.6016,48.4674],[-95.6011,48.4811],[-95.6011,48.4818],[-95.6008,48.4956],[-95.6008,48.4964],[-95.6007,48.51],[-95.6007,48.5107],[-95.6011,48.5251],[-95.6023,48.5389],[-95.5821,48.5387],[-95.5801,48.5387],[-95.5603,48.5388],[-95.558,48.5388],[-95.5383,48.5389],[-95.5365,48.5389],[-95.5163,48.539],[-95.5143,48.539],[-95.495,48.5392],[-95.493,48.5392],[-95.4726,48.5396],[-95.4712,48.5396],[-95.4513,48.5399],[-95.4494,48.5399],[-95.4297,48.5399],[-95.4279,48.54],[-95.4078,48.5402],[-95.4061,48.5402],[-95.386,48.5402],[-95.3844,48.5402],[-95.364,48.5403],[-95.3628,48.5404],[-95.3425,48.5402]]],"type":"Polygon"},"id":"4","properties":{"Area":7911449532.86586,"CTYONLY_":8,"Code":"BELT","LASTMOD":"1999-12-31T23:59:59Z","Name":"Beltrami","Perimiter":429419.1705},"type":"Feature"},{"geometry":{"coordinates":[[[-97.1467,48.1733],[-97.1462,48.1733],[-97.1376,48.1733],[-97.1322,48.1733],[-97.1286,48.1733],[-97.1257,48.1733],[-97.1253,48.1733],[-97.1071,48.1735],[-97.1069,48.1735],[-97.0855,48.1734],[-97.0853,48.1734],[-97.0637,48.1732],[-97.0637,48.1732],[-97.042,48.1732],[-97.042,48.1732],[-97.0205,48.1733],[-97.0203,48.1733],[-97.0003,48.1732],[-96.999,48.1732],[-96.9989,48.1732],[-96.9987,48.1732],[-96.998,48.1732],[-96.9975,48.1732],[-96.9959,48.1732],[-96.99,48.1731],[-96.9889,48.1731],[-96.9844,48.1731],[-96.9812,48.1731],[-96.9775,48.1731],[-96.9773,48.173],[-96.9773,48.173],[-96.9751,48.173],[-96.9749,48.173],[-96.9705,48.1731],[-96.9703,48.1731],[-96.9554,48.1731],[-96.9448,48.1732],[-96.9387,48.1732],[-96.934,48.1733],[-96.9339,48.1733],[-96.933,48.1733],[-96.9123,48.1733],[-96.9122,48.1733],[-96.8932,48.1732],[-96.8907,48.1732],[-96.8907,48.1732],[-96.8753,48.1732],[-96.869,48.1733],[-96.869,48.1733],[-96.8474,48.1733],[-96.8473,48.1733],[-96.8255,48.1734],[-96.8255,48.1734],[-96.8111,48.1734],[-96.8039,48.1734],[-96.8038,48.1734],[-96.7932,48.1733],[-96.7821,48.1734],[-96.7821,48.1734],[-96.7819,48.1734],[-96.7613,48.1734],[-96.7606,48.1734],[-96.7605,48.1734],[-96.7581,48.1734],[-96.7573,48.1734],[-96.7503,48.1734],[-96.7393,48.1734],[-96.7393,48.1734],[-96.7177,48.1734],[-96.7176,48.1734],[-96.6959,48.1734],[-96.6958,48.1734],[-96.6826,48.1735],[-96.6742,48.1736],[-96.6742,48.1736],[-96.6525,48.1738],[-96.6525,48.1738],[-96.6407,48.1739],[-96.6378,48.1738],[-96.6338,48.1737],[-96.6309,48.1737],[-96.6307,48.1737],[-96.6307,48.1737],[-96.6253,48.1737],[-96.6106,48.1737],[-96.6092,48.1737],[-96.609,48.1737],[-96.6055,48.1737],[-96.5966,48.1737],[-96.5893,48.1737],[-96.5875,48.1737],[-96.5873,48.1737],[-96.5873,48.1737],[-96.5838,48.1738],[-96.5806,48.1739],[-96.5765,48.1739],[-96.5748,48.1739],[-96.5715,48.1739],[-96.5678,48.174],[-96.5655,48.174],[-96.5654,48.174],[-96.565,48.174],[-96.5616,48.1739],[-96.557,48.1739],[-96.5544,48.1738],[-96.5507,48.1738],[-96.5479,48.1738],[-96.5446,48.1738],[-96.5443,48.1738],[-96.5442,48.1738],[-96.5434,48.1738],[-96.5399,48.1738],[-96.5357,48.1738],[-96.53,48.1738],[-96.5251,48.1738],[-96.5223,48.1739],[-96.5204,48.1739],[-96.5164,48.1739],[-96.5091,48.174],[-96.5038,48.174],[-96.5008,48.1742],[-96.5008,48.1669],[-96.5008,48.1524],[-96.5006,48.1379],[-96.5007,48.1234],[-96.501,48.1089],[-96.5009,48.0943],[-96.5009,48.0798],[-96.5009,48.0654],[-96.5008,48.0506],[-96.5009,48.0362],[-96.5009,48.0217],[-96.4826,48.0217],[-96.4826,48.0072],[-96.4824,47.9924],[-96.4823,47.9782],[-96.4823,47.9636],[-96.4825,47.949],[-96.4826,47.9347],[-96.4825,47.9202],[-96.4825,47.9055],[-96.4825,47.9054],[-96.4824,47.8913],[-96.4827,47.8768],[-96.4821,47.862],[-96.482,47.8475],[-96.4601,47.8475],[-96.4386,47.8476],[-96.4172,47.8475],[-96.3958,47.8475],[-96.3742,47.8474],[-96.3527,47.8473],[-96.3524,47.8329],[-96.3523,47.8184],[-96.3521,47.8038],[-96.352,47.7893],[-96.3519,47.7748],[-96.3516,47.7604],[-96.3313,47.7603],[-96.3097,47.7601],[-96.2884,47.7601],[-96.2668,47.7599],[-96.2453,47.7598],[-96.2238,47.7598],[-96.2022,47.7597],[-96.1806,47.7598],[-96.159,47.7598],[-96.1388,47.7598],[-96.1175,47.7602],[-96.0957,47.76],[-96.0743,47.7601],[-96.053,47.7603],[-96.0315,47.7605],[-96.0097,47.7605],[-95.9883,47.7605],[-95.9671,47.7605],[-95.9452,47.7606],[-95.9233,47.7607],[-95.9017,47.7609],[-95.8801,47.7608],[-95.8588,47.7609],[-95.8372,47.7609],[-95.8371,47.7755],[-95.8365,47.79],[-95.8366,47.8043],[-95.8366,47.819],[-95.8367,47.8335],[-95.8366,47.8482],[-95.8153,47.8484],[-95.7952,47.8483],[-95.7737,47.8484],[-95.7525,47.8485],[-95.7307,47.8487],[-95.709,47.8486],[-95.7089,47.863],[-95.7094,47.8776],[-95.7095,47.8919],[-95.7094,47.9065],[-95.7098,47.9211],[-95.7096,47.9355],[-95.6898,47.9354],[-95.6683,47.9351],[-95.6466,47.9348],[-95.6252,47.9344],[-95.6034,47.9341],[-95.5824,47.9339],[-95.5817,47.9195],[-95.5816,47.9051],[-95.5814,47.8904],[-95.5813,47.876],[-95.5812,47.8617],[-95.5809,47.847],[-95.5805,47.8327],[-95.5804,47.8183],[-95.5801,47.8039],[-95.5796,47.7894],[-95.5796,47.775],[-95.5799,47.7605],[-95.5795,47.746],[-95.5793,47.7314],[-95.5789,47.7171],[-95.5789,47.7027],[-95.5787,47.6882],[-95.5785,47.6738],[-95.5785,47.6737],[-95.5755,47.6737],[-95.5595,47.6737],[-95.5535,47.6737],[-95.5537,47.6592],[-95.5536,47.6447],[-95.5535,47.6302],[-95.5538,47.6161],[-95.5536,47.6014],[-95.5537,47.5869],[-95.5538,47.5724],[-95.5538,47.5579],[-95.5539,47.5436],[-95.5539,47.5289],[-95.5539,47.5146],[-95.5513,47.5001],[-95.5516,47.5001],[-95.5729,47.5001],[-95.5942,47.4999],[-95.6158,47.4997],[-95.6366,47.4996],[-95.6393,47.4996],[-95.6411,47.4996],[-95.6584,47.4995],[-95.6605,47.4995],[-95.6782,47.4997],[-95.6818,47.4997],[-95.6908,47.4997],[-95.6996,47.4997],[-95.7033,47.4997],[-95.7211,47.4996],[-95.7247,47.4995],[-95.7424,47.4995],[-95.7459,47.4995],[-95.7537,47.4995],[-95.7634,47.4995],[-95.7675,47.4995],[-95.7851,47.4994],[-95.7888,47.4994],[-95.7965,47.4994],[-95.8053,47.4994],[-95.8103,47.4994],[-95.8266,47.4995],[-95.8272,47.4995],[-95.8316,47.4995],[-95.8371,47.4995],[-95.8482,47.4995],[-95.8529,47.4995],[-95.8696,47.4995],[-95.8746,47.4994],[-95.8908,47.4993],[-95.8954,47.4993],[-95.9123,47.4992],[-95.9169,47.4992],[-95.9332,47.4992],[-95.9383,47.4992],[-95.9549,47.4992],[-95.9603,47.4992],[-95.9761,47.4992],[-95.9818,47.4992],[-95.9977,47.4992],[-95.9991,47.4992],[-96.0032,47.4992],[-96.019,47.4993],[-96.0247,47.4993],[-96.0362,47.4992],[-96.0408,47.4992],[-96.0462,47.4992],[-96.0676,47.4992],[-96.0888,47.4993],[-96.1101,47.4993],[-96.1314,47.4996],[-96.1526,47.4997],[-96.1739,47.4999],[-96.1954,47.4999],[-96.2166,47.4999],[-96.238,47.4998],[-96.2594,47.4998],[-96.2808,47.4998],[-96.3022,47.4999],[-96.3232,47.4999],[-96.3448,47.4997],[-96.3659,47.4997],[-96.3873,47.4997],[-96.4088,47.4996],[-96.4301,47.4996],[-96.4517,47.4994],[-96.4731,47.4993],[-96.4944,47.4993],[-96.516,47.4991],[-96.5371,47.4991],[-96.5587,47.499],[-96.5801,47.499],[-96.6013,47.4989],[-96.6229,47.499],[-96.6442,47.4992],[-96.6653,47.499],[-96.6876,47.4987],[-96.7085,47.4989],[-96.73,47.4989],[-96.7515,47.4989],[-96.7732,47.4989],[-96.7945,47.499],[-96.8159,47.499],[-96.8361,47.4989],[-96.8487,47.4989],[-96.8488,47.499],[-96.8504,47.5],[-96.8506,47.5],[-96.8507,47.5],[-96.8514,47.5004],[-96.8524,47.5006],[-96.853,47.501],[-96.8533,47.5014],[-96.8534,47.5017],[-96.8535,47.5023],[-96.8535,47.5034],[-96.8532,47.5039],[-96.8532,47.5042],[-96.8531,47.5045],[-96.8528,47.5053],[-96.8528,47.5059],[-96.8529,47.506],[-96.853,47.5065],[-96.853,47.5069],[-96.8526,47.5073],[-96.8524,47.5075],[-96.8518,47.5076],[-96.8515,47.5076],[-96.8508,47.5074],[-96.8494,47.5068],[-96.8485,47.5066],[-96.8471,47.5066],[-96.846,47.5067],[-96.8443,47.5071],[-96.8436,47.5074],[-96.8424,47.5083],[-96.8422,47.5086],[-96.8421,47.5091],[-96.8424,47.5094],[-96.8431,47.51],[-96.8439,47.5103],[-96.8448,47.5105],[-96.8464,47.5105],[-96.849,47.5098],[-96.8504,47.5096],[-96.8512,47.5096],[-96.8519,47.5098],[-96.8526,47.5102],[-96.853,47.5106],[-96.8531,47.5107],[-96.8533,47.5112],[-96.8534,47.5112],[-96.8534,47.5113],[-96.8535,47.5113],[-96.8536,47.5119],[-96.8536,47.512],[-96.8532,47.5126],[-96.8531,47.5128],[-96.8525,47.5132],[-96.8517,47.5135],[-96.8514,47.5135],[-96.851,47.5136],[-96.8502,47.5135],[-96.8491,47.5134],[-96.8465,47.5124],[-96.846,47.5123],[-96.8448,47.5124],[-96.8442,47.5125],[-96.8435,47.5128],[-96.843,47.5132],[-96.8428,47.5134],[-96.8425,47.5137],[-96.8422,47.5141],[-96.842,47.5146],[-96.842,47.5155],[-96.842,47.5156],[-96.842,47.5157],[-96.8421,47.5158],[-96.8422,47.516],[-96.8427,47.5164],[-96.8433,47.5167],[-96.8442,47.517],[-96.8454,47.5172],[-96.8465,47.517],[-96.8475,47.5166],[-96.8481,47.5163],[-96.8501,47.5155],[-96.8519,47.515],[-96.8532,47.5146],[-96.8542,47.5144],[-96.8547,47.5144],[-96.8563,47.5146],[-96.8573,47.5147],[-96.8584,47.5149],[-96.8599,47.5153],[-96.8614,47.5159],[-96.8624,47.5164],[-96.8629,47.5169],[-96.8632,47.5173],[-96.8633,47.5177],[-96.8633,47.5198],[-96.8635,47.5204],[-96.8636,47.5206],[-96.8643,47.5213],[-96.8645,47.5216],[-96.8656,47.5225],[-96.8658,47.5229],[-96.866,47.523],[-96.8663,47.5238],[-96.8664,47.5249],[-96.8666,47.5254],[-96.8672,47.5259],[-96.8676,47.5261],[-96.8683,47.5262],[-96.8698,47.5264],[-96.8705,47.5266],[-96.8707,47.5268],[-96.8708,47.5269],[-96.8709,47.5272],[-96.8709,47.5273],[-96.8709,47.5279],[-96.8706,47.5283],[-96.8704,47.5284],[-96.87,47.5287],[-96.8691,47.529],[-96.868,47.5291],[-96.8665,47.5291],[-96.865,47.529],[-96.8623,47.5291],[-96.861,47.5294],[-96.8605,47.5296],[-96.8593,47.5304],[-96.8589,47.5308],[-96.8576,47.5328],[-96.8573,47.5333],[-96.8568,47.5337],[-96.8558,47.5346],[-96.8543,47.5354],[-96.854,47.5357],[-96.8535,47.5363],[-96.8534,47.5372],[-96.8536,47.5378],[-96.854,47.5382],[-96.8546,47.5383],[-96.8558,47.5382],[-96.8569,47.5379],[-96.8573,47.5377],[-96.8579,47.5375],[-96.8589,47.5371],[-96.8593,47.5371],[-96.8599,47.5371],[-96.8609,47.5374],[-96.8619,47.5379],[-96.8629,47.5387],[-96.8632,47.5391],[-96.8634,47.5395],[-96.8634,47.5402],[-96.8628,47.5409],[-96.8614,47.5414],[-96.858,47.542],[-96.8573,47.5421],[-96.8565,47.5422],[-96.8555,47.5421],[-96.8542,47.5418],[-96.8533,47.5413],[-96.8523,47.5407],[-96.8519,47.5401],[-96.8516,47.5397],[-96.8514,47.5393],[-96.8513,47.5393],[-96.8512,47.539],[-96.8511,47.5388],[-96.851,47.5386],[-96.8507,47.5383],[-96.8507,47.5382],[-96.8501,47.5377],[-96.8494,47.5374],[-96.8484,47.5372],[-96.8477,47.5371],[-96.8471,47.5372],[-96.8465,47.5374],[-96.8457,47.538],[-96.8452,47.5386],[-96.8452,47.5394],[-96.8452,47.5397],[-96.8454,47.5399],[-96.8455,47.5403],[-96.8456,47.5404],[-96.8456,47.5405],[-96.846,47.541],[-96.8467,47.5415],[-96.8484,47.5425],[-96.8501,47.5432],[-96.8525,47.5438],[-96.8571,47.5448],[-96.8572,47.5448],[-96.8586,47.5452],[-96.8597,47.5456],[-96.8602,47.5459],[-96.8603,47.5461],[-96.8603,47.5464],[-96.8602,47.5466],[-96.8599,47.5468],[-96.8596,47.547],[-96.8585,47.5472],[-96.8576,47.5477],[-96.8572,47.5479],[-96.8554,47.5485],[-96.8542,47.5488],[-96.8538,47.5491],[-96.8523,47.5504],[-96.8505,47.5517],[-96.8501,47.5521],[-96.8499,47.5526],[-96.8497,47.5532],[-96.85,47.5537],[-96.8501,47.5538],[-96.8501,47.5539],[-96.8506,47.5543],[-96.8513,47.5546],[-96.8526,47.5549],[-96.8546,47.5551],[-96.8558,47.5551],[-96.857,47.5553],[-96.8578,47.5556],[-96.8588,47.5562],[-96.8598,47.5571],[-96.8602,47.5576],[-96.8605,47.5578],[-96.8606,47.5581],[-96.8608,47.5582],[-96.8612,47.5588],[-96.8614,47.5592],[-96.8614,47.5599],[-96.8613,47.5602],[-96.8608,47.5604],[-96.8601,47.5607],[-96.8594,47.5607],[-96.8581,47.5605],[-96.8573,47.5602],[-96.8569,47.5601],[-96.8567,47.5601],[-96.8553,47.5602],[-96.8544,47.5603],[-96.8537,47.5606],[-96.8515,47.5621],[-96.8506,47.5626],[-96.8491,47.5636],[-96.8484,47.564],[-96.8476,47.5646],[-96.8474,47.565],[-96.8472,47.5656],[-96.8472,47.5661],[-96.8474,47.5663],[-96.8479,47.5666],[-96.8487,47.5667],[-96.8498,47.5665],[-96.8503,47.5664],[-96.8513,47.5658],[-96.852,47.5656],[-96.8541,47.5653],[-96.856,47.5649],[-96.8568,47.5646],[-96.8575,47.5643],[-96.8599,47.5632],[-96.8612,47.5628],[-96.8622,47.5626],[-96.8628,47.5626],[-96.864,47.5627],[-96.8652,47.5631],[-96.8661,47.5636],[-96.8666,47.564],[-96.8676,47.5651],[-96.8678,47.5654],[-96.868,47.5655],[-96.8685,47.5663],[-96.8685,47.5664],[-96.8686,47.5665],[-96.8687,47.5668],[-96.8688,47.5669],[-96.8687,47.5677],[-96.8684,47.5682],[-96.8675,47.5688],[-96.8661,47.5695],[-96.8656,47.5696],[-96.8647,47.5694],[-96.8639,47.569],[-96.8629,47.5687],[-96.8616,47.5684],[-96.861,47.5682],[-96.8607,47.568],[-96.8599,47.5676],[-96.8588,47.5672],[-96.8578,47.5671],[-96.8567,47.5671],[-96.8555,47.5671],[-96.8539,47.5675],[-96.8529,47.5678],[-96.8519,47.5684],[-96.8514,47.569],[-96.8515,47.5698],[-96.8517,47.5703],[-96.8521,47.5709],[-96.8529,47.5715],[-96.8531,47.5716],[-96.8537,47.5719],[-96.8549,47.5725],[-96.8566,47.5731],[-96.8571,47.5733],[-96.8595,47.574],[-96.8602,47.5744],[-96.8604,47.5746],[-96.8604,47.575],[-96.8599,47.5752],[-96.8589,47.5754],[-96.8585,47.5756],[-96.8573,47.5763],[-96.8565,47.5767],[-96.8553,47.5773],[-96.8543,47.578],[-96.8534,47.5792],[-96.8532,47.5795],[-96.853,47.5802],[-96.853,47.5805],[-96.8528,47.5809],[-96.8529,47.5822],[-96.853,47.5826],[-96.8532,47.5826],[-96.8532,47.5833],[-96.8531,47.5837],[-96.8526,47.5844],[-96.8527,47.5845],[-96.8525,47.5846],[-96.852,47.585],[-96.852,47.5851],[-96.8515,47.5859],[-96.8515,47.586],[-96.8513,47.5869],[-96.8512,47.5873],[-96.8511,47.5878],[-96.851,47.5881],[-96.8507,47.5888],[-96.8502,47.5898],[-96.85,47.5903],[-96.8499,47.591],[-96.8501,47.5916],[-96.8503,47.5919],[-96.8511,47.5925],[-96.8517,47.5927],[-96.8538,47.593],[-96.8549,47.5934],[-96.8562,47.5939],[-96.8575,47.5943],[-96.8582,47.5947],[-96.8586,47.5949],[-96.8588,47.5954],[-96.8588,47.5958],[-96.8584,47.5962],[-96.8575,47.5963],[-96.8562,47.5962],[-96.8542,47.596],[-96.853,47.5961],[-96.8521,47.5964],[-96.8515,47.5968],[-96.8511,47.5973],[-96.8509,47.5977],[-96.8509,47.5983],[-96.8511,47.5989],[-96.8515,47.5993],[-96.8521,47.5997],[-96.8528,47.6],[-96.8536,47.6003],[-96.8545,47.6004],[-96.8556,47.6009],[-96.8561,47.6014],[-96.8564,47.6016],[-96.8567,47.602],[-96.8569,47.6024],[-96.8568,47.6031],[-96.8565,47.6035],[-96.8562,47.6039],[-96.8553,47.6051],[-96.8549,47.6058],[-96.8548,47.6064],[-96.8548,47.6073],[-96.8549,47.6075],[-96.855,47.6079],[-96.855,47.608],[-96.8554,47.6088],[-96.8557,47.6093],[-96.8558,47.6094],[-96.8561,47.6098],[-96.8563,47.61],[-96.8571,47.6108],[-96.858,47.6115],[-96.8589,47.612],[-96.8602,47.6122],[-96.8612,47.6124],[-96.8646,47.6124],[-96.8655,47.6125],[-96.8664,47.6129],[-96.8672,47.6136],[-96.8673,47.6138],[-96.8675,47.6139],[-96.8676,47.6141],[-96.8679,47.6144],[-96.8686,47.6148],[-96.869,47.615],[-96.8694,47.615],[-96.8703,47.6147],[-96.871,47.6143],[-96.8714,47.6139],[-96.8719,47.6136],[-96.8723,47.6135],[-96.8729,47.6135],[-96.8736,47.6137],[-96.8739,47.614],[-96.874,47.6141],[-96.874,47.6148],[-96.8739,47.6149],[-96.8736,47.6154],[-96.8726,47.6159],[-96.8715,47.6165],[-96.871,47.6169],[-96.8706,47.6176],[-96.8708,47.6181],[-96.8712,47.6183],[-96.8717,47.6184],[-96.8727,47.6184],[-96.8753,47.6191],[-96.8763,47.6192],[-96.8778,47.6189],[-96.878,47.6189],[-96.879,47.6189],[-96.8796,47.6191],[-96.88,47.6195],[-96.88,47.62],[-96.8794,47.6206],[-96.8783,47.6213],[-96.8779,47.6215],[-96.8769,47.6219],[-96.8763,47.6223],[-96.876,47.6228],[-96.8758,47.623],[-96.876,47.6235],[-96.8761,47.6237],[-96.8768,47.6243],[-96.8775,47.6244],[-96.878,47.6245],[-96.8792,47.6246],[-96.88,47.6247],[-96.8803,47.625],[-96.8806,47.6254],[-96.8807,47.6255],[-96.8807,47.6259],[-96.8804,47.6262],[-96.8798,47.6266],[-96.8792,47.6267],[-96.8786,47.6267],[-96.878,47.6267],[-96.8767,47.6266],[-96.8753,47.6267],[-96.8748,47.6269],[-96.8745,47.6272],[-96.8745,47.6275],[-96.8745,47.628],[-96.8747,47.6283],[-96.8753,47.6287],[-96.8765,47.629],[-96.8774,47.6289],[-96.8781,47.6289],[-96.8787,47.6289],[-96.8795,47.6289],[-96.8801,47.6289],[-96.8806,47.6291],[-96.881,47.6294],[-96.8815,47.6299],[-96.8815,47.6299],[-96.8815,47.63],[-96.8816,47.6301],[-96.8818,47.6305],[-96.8818,47.631],[-96.8819,47.6311],[-96.882,47.6324],[-96.8822,47.6333],[-96.8823,47.6334],[-96.8823,47.6335],[-96.8827,47.6339],[-96.8852,47.6356],[-96.8876,47.6376],[-96.8878,47.6379],[-96.8885,47.6385],[-96.8885,47.6393],[-96.8884,47.6395],[-96.8881,47.6398],[-96.8874,47.6401],[-96.886,47.6405],[-96.8845,47.6408],[-96.8835,47.6412],[-96.8832,47.6414],[-96.8828,47.6418],[-96.8826,47.6422],[-96.8826,47.6429],[-96.8829,47.6439],[-96.8829,47.6441],[-96.8829,47.6447],[-96.8828,47.6451],[-96.8827,47.6462],[-96.8825,47.6471],[-96.8823,47.6491],[-96.8826,47.6498],[-96.8828,47.6502],[-96.8837,47.6509],[-96.8844,47.6513],[-96.8846,47.6513],[-96.8847,47.6515],[-96.8862,47.6523],[-96.8866,47.6526],[-96.8869,47.6531],[-96.887,47.6533],[-96.887,47.6543],[-96.8868,47.6548],[-96.8869,47.6556],[-96.887,47.656],[-96.8876,47.6577],[-96.8876,47.6585],[-96.8876,47.6589],[-96.8873,47.6596],[-96.8869,47.6601],[-96.8857,47.6616],[-96.8855,47.6624],[-96.8855,47.6635],[-96.8857,47.6643],[-96.8862,47.6652],[-96.8863,47.6653],[-96.8863,47.6654],[-96.8864,47.6656],[-96.8864,47.6656],[-96.8871,47.6664],[-96.8889,47.668],[-96.8896,47.6686],[-96.8897,47.669],[-96.8898,47.669],[-96.8899,47.6693],[-96.89,47.6694],[-96.8901,47.67],[-96.8899,47.6703],[-96.8897,47.6707],[-96.8883,47.6715],[-96.8871,47.6721],[-96.8868,47.6722],[-96.8863,47.6725],[-96.8859,47.6727],[-96.8856,47.6727],[-96.8855,47.6729],[-96.8853,47.6732],[-96.8851,47.6735],[-96.8852,47.6737],[-96.8852,47.6738],[-96.8853,47.6739],[-96.8857,47.6742],[-96.8863,47.6743],[-96.8867,47.6743],[-96.8874,47.6743],[-96.8886,47.674],[-96.8892,47.6738],[-96.8908,47.6734],[-96.8919,47.6732],[-96.8935,47.6732],[-96.8946,47.6734],[-96.8952,47.6736],[-96.8955,47.6738],[-96.8964,47.6745],[-96.8967,47.6748],[-96.8968,47.6751],[-96.8967,47.6759],[-96.8964,47.6768],[-96.8963,47.6772],[-96.8962,47.6775],[-96.8961,47.6776],[-96.8961,47.6785],[-96.8963,47.6792],[-96.8964,47.6793],[-96.8964,47.6794],[-96.8965,47.6796],[-96.8968,47.6802],[-96.8971,47.6804],[-96.8971,47.6806],[-96.8972,47.6806],[-96.8973,47.681],[-96.8974,47.6811],[-96.8974,47.6812],[-96.8975,47.6813],[-96.8977,47.6817],[-96.8978,47.6818],[-96.8978,47.682],[-96.8984,47.6834],[-96.8986,47.6837],[-96.8986,47.684],[-96.8987,47.6841],[-96.8989,47.6846],[-96.899,47.6847],[-96.899,47.685],[-96.8993,47.686],[-96.8992,47.6871],[-96.8992,47.688],[-96.8992,47.6883],[-96.8992,47.6887],[-96.8993,47.6895],[-96.8995,47.69],[-96.8996,47.6901],[-96.8997,47.6903],[-96.9002,47.6908],[-96.9011,47.6914],[-96.9017,47.6917],[-96.9022,47.6918],[-96.9029,47.6916],[-96.9035,47.6913],[-96.9039,47.6909],[-96.9047,47.6898],[-96.9052,47.6893],[-96.906,47.6889],[-96.9072,47.6885],[-96.9081,47.6885],[-96.9089,47.6888],[-96.9095,47.6892],[-96.9098,47.6896],[-96.9101,47.69],[-96.9101,47.6913],[-96.9099,47.6916],[-96.9098,47.692],[-96.9091,47.6926],[-96.9077,47.6934],[-96.9074,47.6937],[-96.9072,47.694],[-96.9072,47.6947],[-96.9076,47.6952],[-96.9077,47.6954],[-96.9083,47.6961],[-96.9092,47.6968],[-96.9097,47.6974],[-96.9101,47.698],[-96.9102,47.6982],[-96.9103,47.6985],[-96.9103,47.6986],[-96.9104,47.6986],[-96.9106,47.6989],[-96.9107,47.6991],[-96.9107,47.6993],[-96.9115,47.7006],[-96.912,47.7012],[-96.9125,47.7017],[-96.9128,47.7018],[-96.9132,47.7019],[-96.914,47.7018],[-96.9145,47.7016],[-96.9155,47.7009],[-96.9169,47.6998],[-96.9177,47.6994],[-96.9184,47.6991],[-96.9193,47.6991],[-96.9202,47.6993],[-96.9207,47.6996],[-96.9208,47.6998],[-96.9208,47.6999],[-96.921,47.7],[-96.9211,47.7003],[-96.9211,47.7008],[-96.9208,47.7013],[-96.9204,47.7017],[-96.9194,47.7026],[-96.919,47.7028],[-96.9187,47.703],[-96.9176,47.7034],[-96.9172,47.7035],[-96.9164,47.7034],[-96.9155,47.7035],[-96.9145,47.7038],[-96.9137,47.7042],[-96.9132,47.7047],[-96.9128,47.7052],[-96.9123,47.7058],[-96.9119,47.7066],[-96.912,47.7075],[-96.9122,47.7079],[-96.9129,47.7083],[-96.9134,47.7084],[-96.9146,47.7085],[-96.9163,47.7086],[-96.9175,47.7089],[-96.919,47.7095],[-96.9198,47.71],[-96.9201,47.7104],[-96.9201,47.7105],[-96.9202,47.7107],[-96.9204,47.7111],[-96.9204,47.712],[-96.9203,47.7124],[-96.9197,47.7137],[-96.9195,47.7139],[-96.9194,47.7142],[-96.9192,47.7146],[-96.9191,47.7149],[-96.9191,47.7156],[-96.9197,47.7166],[-96.9201,47.7171],[-96.9206,47.7174],[-96.9209,47.7176],[-96.9216,47.7178],[-96.9224,47.718],[-96.9232,47.7179],[-96.9238,47.7176],[-96.9241,47.7174],[-96.9245,47.7171],[-96.9247,47.7167],[-96.9248,47.7166],[-96.9248,47.7164],[-96.9251,47.7162],[-96.9252,47.716],[-96.926,47.7153],[-96.9266,47.7149],[-96.9277,47.7144],[-96.9284,47.7143],[-96.929,47.7143],[-96.93,47.7145],[-96.9305,47.7148],[-96.931,47.7153],[-96.931,47.7154],[-96.9311,47.7154],[-96.9312,47.716],[-96.9312,47.7166],[-96.9308,47.7174],[-96.9308,47.7175],[-96.9305,47.7179],[-96.93,47.7183],[-96.9287,47.7187],[-96.9271,47.719],[-96.9251,47.7197],[-96.9237,47.7202],[-96.9217,47.7211],[-96.9205,47.7218],[-96.9194,47.7226],[-96.9193,47.7227],[-96.9189,47.7231],[-96.9187,47.7234],[-96.9185,47.7239],[-96.9187,47.7243],[-96.9188,47.7244],[-96.9188,47.7245],[-96.9191,47.7248],[-96.9197,47.7251],[-96.9203,47.7253],[-96.9224,47.7256],[-96.9236,47.7259],[-96.9242,47.7262],[-96.9246,47.7267],[-96.9248,47.7272],[-96.925,47.7275],[-96.925,47.7291],[-96.9253,47.7299],[-96.9255,47.7302],[-96.9257,47.7304],[-96.9273,47.7316],[-96.9279,47.7321],[-96.9283,47.7325],[-96.9305,47.7344],[-96.9314,47.7353],[-96.9319,47.7359],[-96.9323,47.7365],[-96.9324,47.7366],[-96.9325,47.7368],[-96.9327,47.7371],[-96.9328,47.7372],[-96.9332,47.7383],[-96.9333,47.7388],[-96.9332,47.7395],[-96.933,47.74],[-96.9327,47.7403],[-96.9319,47.741],[-96.9318,47.7411],[-96.9308,47.7417],[-96.9302,47.7422],[-96.9293,47.743],[-96.929,47.7435],[-96.9287,47.7442],[-96.9285,47.7449],[-96.9284,47.7454],[-96.9284,47.7465],[-96.9285,47.7481],[-96.9286,47.7491],[-96.9288,47.7493],[-96.9289,47.7497],[-96.929,47.7497],[-96.9289,47.75],[-96.929,47.7504],[-96.9298,47.751],[-96.9308,47.7515],[-96.9322,47.7521],[-96.9332,47.7526],[-96.9351,47.7532],[-96.9387,47.754],[-96.9394,47.7544],[-96.9398,47.7549],[-96.9397,47.7555],[-96.9394,47.7559],[-96.9388,47.7562],[-96.9381,47.7563],[-96.9373,47.7563],[-96.9363,47.7562],[-96.9337,47.7551],[-96.9327,47.7548],[-96.9323,47.7548],[-96.9311,47.7547],[-96.9297,47.7549],[-96.9291,47.755],[-96.9289,47.7553],[-96.9288,47.7558],[-96.9291,47.7561],[-96.9298,47.7565],[-96.9309,47.7569],[-96.9324,47.7573],[-96.9335,47.7576],[-96.9355,47.7583],[-96.9368,47.759],[-96.9369,47.7592],[-96.9371,47.7594],[-96.9372,47.7595],[-96.9378,47.7602],[-96.9379,47.7604],[-96.9381,47.7607],[-96.9381,47.7609],[-96.9382,47.7609],[-96.9382,47.761],[-96.9384,47.7614],[-96.9384,47.7625],[-96.938,47.7632],[-96.9376,47.7639],[-96.9369,47.7646],[-96.9366,47.7649],[-96.9352,47.7658],[-96.9351,47.766],[-96.9349,47.7664],[-96.9348,47.7668],[-96.9349,47.7671],[-96.9357,47.7676],[-96.9365,47.7678],[-96.9382,47.7681],[-96.9391,47.7684],[-96.9404,47.7692],[-96.9423,47.7708],[-96.943,47.7712],[-96.9442,47.7717],[-96.9445,47.7717],[-96.9445,47.7719],[-96.9452,47.7722],[-96.9457,47.7727],[-96.9458,47.7729],[-96.9459,47.7734],[-96.9459,47.7743],[-96.946,47.7746],[-96.9466,47.775],[-96.9473,47.7753],[-96.9483,47.7755],[-96.9494,47.7753],[-96.9495,47.7753],[-96.9518,47.7747],[-96.9527,47.7746],[-96.9537,47.7746],[-96.9539,47.7747],[-96.955,47.7748],[-96.956,47.7751],[-96.9565,47.7753],[-96.9567,47.7757],[-96.9567,47.7761],[-96.9566,47.7762],[-96.9544,47.7777],[-96.9538,47.778],[-96.9527,47.7787],[-96.9523,47.779],[-96.9522,47.7793],[-96.9524,47.7796],[-96.9527,47.7799],[-96.9533,47.78],[-96.9538,47.78],[-96.9554,47.7798],[-96.9565,47.7798],[-96.9573,47.78],[-96.9584,47.7803],[-96.9589,47.7807],[-96.9593,47.7812],[-96.9593,47.7819],[-96.9592,47.7819],[-96.9578,47.7838],[-96.9576,47.7844],[-96.9575,47.7847],[-96.9575,47.7852],[-96.9578,47.7855],[-96.9581,47.7856],[-96.9584,47.7857],[-96.959,47.7855],[-96.9596,47.7849],[-96.9597,47.7847],[-96.9598,47.7847],[-96.9598,47.7846],[-96.9601,47.7843],[-96.961,47.7838],[-96.9619,47.7833],[-96.9631,47.783],[-96.9638,47.783],[-96.9644,47.783],[-96.9649,47.7833],[-96.9653,47.7835],[-96.9654,47.7839],[-96.9653,47.785],[-96.9651,47.7853],[-96.965,47.7855],[-96.9645,47.7862],[-96.9635,47.7873],[-96.9628,47.7879],[-96.9621,47.7884],[-96.9615,47.7888],[-96.9599,47.7893],[-96.9586,47.7896],[-96.958,47.7898],[-96.9576,47.79],[-96.9572,47.7902],[-96.9571,47.7904],[-96.9572,47.791],[-96.9573,47.7913],[-96.9574,47.7915],[-96.9578,47.7921],[-96.9584,47.7925],[-96.9597,47.7931],[-96.9627,47.7942],[-96.9635,47.7947],[-96.9642,47.7951],[-96.965,47.7959],[-96.9657,47.7968],[-96.966,47.7973],[-96.9661,47.7992],[-96.9662,47.7993],[-96.9663,47.7994],[-96.9669,47.7998],[-96.9674,47.7999],[-96.9681,47.7998],[-96.9687,47.7996],[-96.9689,47.7995],[-96.9702,47.7987],[-96.9716,47.7983],[-96.974,47.7978],[-96.9751,47.7978],[-96.9754,47.7978],[-96.9762,47.7979],[-96.9766,47.7981],[-96.9768,47.7983],[-96.977,47.7986],[-96.977,47.8],[-96.9764,47.8013],[-96.9761,47.8016],[-96.9759,47.8017],[-96.9754,47.8019],[-96.9751,47.8019],[-96.973,47.8019],[-96.9723,47.802],[-96.9721,47.8022],[-96.9719,47.8025],[-96.9721,47.8029],[-96.973,47.8034],[-96.974,47.8036],[-96.9749,47.8037],[-96.9751,47.8037],[-96.9769,47.8037],[-96.9789,47.804],[-96.9796,47.8042],[-96.981,47.8045],[-96.9818,47.8046],[-96.9826,47.805],[-96.9828,47.8051],[-96.9831,47.8051],[-96.9832,47.8053],[-96.9851,47.8065],[-96.9859,47.8069],[-96.9863,47.8071],[-96.9877,47.8072],[-96.9894,47.8072],[-96.9905,47.8076],[-96.991,47.8078],[-96.9914,47.8081],[-96.9916,47.8085],[-96.9916,47.8091],[-96.9912,47.8094],[-96.9903,47.8097],[-96.9891,47.8099],[-96.9882,47.8099],[-96.9864,47.8098],[-96.9818,47.8091],[-96.9805,47.8092],[-96.9796,47.8095],[-96.9788,47.8099],[-96.9782,47.8106],[-96.978,47.8112],[-96.9779,47.8117],[-96.9781,47.8122],[-96.9784,47.8128],[-96.9786,47.8129],[-96.9787,47.8131],[-96.9795,47.8138],[-96.9795,47.8139],[-96.9798,47.8143],[-96.9799,47.8145],[-96.9799,47.8146],[-96.9803,47.8157],[-96.9804,47.8187],[-96.9804,47.822],[-96.9802,47.8224],[-96.9797,47.8226],[-96.979,47.8226],[-96.9772,47.8222],[-96.9764,47.8221],[-96.9759,47.8221],[-96.9754,47.8222],[-96.9747,47.8224],[-96.9745,47.8224],[-96.9744,47.8225],[-96.9741,47.8228],[-96.9741,47.8234],[-96.9743,47.8239],[-96.9749,47.8244],[-96.9757,47.825],[-96.9759,47.825],[-96.9769,47.8254],[-96.9783,47.8256],[-96.9793,47.8257],[-96.982,47.8255],[-96.9845,47.8251],[-96.9857,47.8251],[-96.9865,47.8252],[-96.9869,47.8254],[-96.9872,47.8256],[-96.9871,47.8261],[-96.9867,47.8265],[-96.9858,47.8269],[-96.984,47.8275],[-96.9827,47.8281],[-96.9825,47.8283],[-96.9819,47.8287],[-96.9817,47.829],[-96.9815,47.8295],[-96.9816,47.8301],[-96.9817,47.8305],[-96.982,47.8309],[-96.9843,47.8325],[-96.9848,47.8331],[-96.9849,47.8332],[-96.9849,47.8333],[-96.985,47.8334],[-96.9852,47.8339],[-96.9853,47.8344],[-96.9854,47.8345],[-96.9857,47.8359],[-96.9859,47.8361],[-96.9859,47.8366],[-96.9863,47.8373],[-96.9866,47.8377],[-96.9873,47.8379],[-96.9881,47.838],[-96.9896,47.8381],[-96.9907,47.838],[-96.9915,47.8378],[-96.9924,47.8378],[-96.9929,47.838],[-96.9937,47.8383],[-96.9941,47.8388],[-96.9941,47.8396],[-96.994,47.8397],[-96.9935,47.8404],[-96.9929,47.8412],[-96.9925,47.8417],[-96.9924,47.8421],[-96.9924,47.8426],[-96.9927,47.8427],[-96.9931,47.8428],[-96.9938,47.8426],[-96.9956,47.842],[-96.9969,47.8416],[-96.9976,47.8416],[-96.9976,47.8435],[-96.9974,47.8437],[-96.9963,47.8444],[-96.9958,47.8447],[-96.9947,47.845],[-96.9943,47.8452],[-96.9941,47.8455],[-96.994,47.8458],[-96.9941,47.8461],[-96.9941,47.8462],[-96.9942,47.8463],[-96.9943,47.8464],[-96.9949,47.847],[-96.9956,47.8474],[-96.9967,47.848],[-96.9968,47.848],[-96.9968,47.8482],[-96.9969,47.8482],[-96.9971,47.8484],[-96.9973,47.8488],[-96.9975,47.8496],[-96.9973,47.8504],[-96.9969,47.8515],[-96.9967,47.8526],[-96.9968,47.8545],[-96.9969,47.8555],[-96.9971,47.8561],[-96.9971,47.8564],[-96.9972,47.8566],[-96.9973,47.8567],[-96.9974,47.8574],[-96.9976,47.8577],[-96.9978,47.8583],[-96.9978,47.8583],[-96.9981,47.8589],[-96.9982,47.859],[-96.9983,47.8592],[-96.9989,47.8599],[-96.9994,47.8603],[-96.9998,47.8607],[-97.0003,47.861],[-97.0017,47.8613],[-97.0031,47.8623],[-97.0055,47.864],[-97.0058,47.8653],[-97.0033,47.8659],[-97.0015,47.8674],[-97.0024,47.8687],[-97.0053,47.8702],[-97.0084,47.8708],[-97.0173,47.8716],[-97.0194,47.8722],[-97.0212,47.8726],[-97.0218,47.8731],[-97.0231,47.874],[-97.0231,47.875],[-97.0221,47.8755],[-97.0196,47.8766],[-97.0193,47.8768],[-97.0189,47.8769],[-97.0179,47.8785],[-97.0193,47.8803],[-97.022,47.8815],[-97.0233,47.8821],[-97.0253,47.8843],[-97.0253,47.8856],[-97.0249,47.8869],[-97.0222,47.8884],[-97.0194,47.8897],[-97.0191,47.8898],[-97.0189,47.8911],[-97.019,47.8912],[-97.0195,47.8915],[-97.0225,47.8933],[-97.0249,47.895],[-97.0239,47.8981],[-97.0201,47.9005],[-97.0202,47.9022],[-97.0241,47.9053],[-97.0242,47.9056],[-97.0249,47.9082],[-97.0245,47.9083],[-97.0235,47.9085],[-97.0203,47.9064],[-97.0198,47.9063],[-97.0184,47.906],[-97.0172,47.9057],[-97.015,47.9072],[-97.015,47.9073],[-97.0153,47.9103],[-97.0156,47.9108],[-97.0172,47.9131],[-97.0195,47.9141],[-97.0197,47.9142],[-97.0214,47.9147],[-97.0237,47.9159],[-97.0196,47.9175],[-97.018,47.9181],[-97.0177,47.9198],[-97.0183,47.9202],[-97.0196,47.9211],[-97.0213,47.9221],[-97.0219,47.9224],[-97.0235,47.9236],[-97.0247,47.9244],[-97.026,47.9253],[-97.0284,47.9269],[-97.0296,47.9276],[-97.0323,47.9285],[-97.0357,47.9302],[-97.0373,47.9333],[-97.0368,47.9343],[-97.0355,47.9366],[-97.036,47.9394],[-97.0374,47.9399],[-97.0391,47.9405],[-97.0394,47.9405],[-97.0416,47.9406],[-97.0417,47.9406],[-97.0449,47.9411],[-97.051,47.9434],[-97.0545,47.9463],[-97.0555,47.9491],[-97.0555,47.9491],[-97.0553,47.9502],[-97.0551,47.9508],[-97.0525,47.9548],[-97.0524,47.9572],[-97.054,47.9597],[-97.059,47.9621],[-97.0613,47.9636],[-97.0614,47.9636],[-97.0618,47.9645],[-97.0615,47.9659],[-97.06,47.9672],[-97.0578,47.969],[-97.0571,47.9705],[-97.0593,47.974],[-97.0591,47.9754],[-97.0589,47.976],[-97.0588,47.9762],[-97.0587,47.9766],[-97.0584,47.977],[-97.0582,47.9774],[-97.0579,47.9778],[-97.0577,47.9781],[-97.0577,47.9782],[-97.0574,47.9787],[-97.0571,47.9792],[-97.0567,47.9801],[-97.0564,47.9806],[-97.0563,47.9811],[-97.0561,47.9815],[-97.0559,47.9821],[-97.0556,47.9828],[-97.0554,47.9833],[-97.0553,47.9838],[-97.0552,47.9842],[-97.0549,47.9849],[-97.0546,47.9855],[-97.0544,47.986],[-97.0541,47.9866],[-97.0539,47.9871],[-97.0537,47.9877],[-97.0535,47.988],[-97.0534,47.9884],[-97.0533,47.9887],[-97.0532,47.989],[-97.053,47.9894],[-97.053,47.9898],[-97.053,47.9903],[-97.053,47.9905],[-97.0531,47.9907],[-97.0532,47.9909],[-97.0533,47.9912],[-97.0534,47.9915],[-97.0535,47.9917],[-97.0538,47.992],[-97.0541,47.9923],[-97.0543,47.9925],[-97.0545,47.9926],[-97.0549,47.993],[-97.0555,47.9933],[-97.0561,47.9936],[-97.0566,47.9938],[-97.0571,47.9939],[-97.0578,47.9941],[-97.0584,47.9943],[-97.0591,47.9945],[-97.0597,47.9948],[-97.0601,47.9949],[-97.0604,47.9951],[-97.0608,47.9953],[-97.0614,47.9956],[-97.0617,47.9957],[-97.0619,47.9959],[-97.0622,47.996],[-97.0625,47.9962],[-97.0628,47.9965],[-97.063,47.9967],[-97.0633,47.997],[-97.0637,47.9975],[-97.0639,47.9977],[-97.0641,47.9982],[-97.0642,47.9986],[-97.0644,47.9989],[-97.0644,47.9994],[-97.0645,48.0],[-97.0645,48.0004],[-97.0644,48.002],[-97.0644,48.0027],[-97.0645,48.0034],[-97.0648,48.0045],[-97.0656,48.0064],[-97.0659,48.0071],[-97.0662,48.0079],[-97.0667,48.0089],[-97.0667,48.0096],[-97.0666,48.0102],[-97.0654,48.0114],[-97.0638,48.0125],[-97.0636,48.0126],[-97.063,48.0132],[-97.0628,48.0138],[-97.0629,48.0145],[-97.0632,48.015],[-97.0638,48.0153],[-97.0649,48.0157],[-97.0685,48.016],[-97.0692,48.0162],[-97.0706,48.017],[-97.0717,48.0181],[-97.0722,48.0192],[-97.0723,48.0196],[-97.0723,48.0201],[-97.0721,48.0207],[-97.0721,48.0209],[-97.0719,48.0214],[-97.0713,48.0228],[-97.0699,48.0247],[-97.0689,48.0263],[-97.0687,48.0277],[-97.0688,48.029],[-97.0691,48.0313],[-97.0697,48.0334],[-97.07,48.0354],[-97.0701,48.0361],[-97.0699,48.0374],[-97.0704,48.0418],[-97.0712,48.0458],[-97.0719,48.0474],[-97.0722,48.0481],[-97.0732,48.0499],[-97.0732,48.05],[-97.074,48.0513],[-97.0747,48.0521],[-97.0756,48.0528],[-97.0767,48.0533],[-97.0782,48.054],[-97.0795,48.0545],[-97.0815,48.0553],[-97.0828,48.0558],[-97.084,48.0564],[-97.0845,48.0567],[-97.0859,48.0575],[-97.0869,48.0583],[-97.0881,48.0596],[-97.0892,48.0611],[-97.0905,48.0627],[-97.0905,48.0628],[-97.0908,48.0631],[-97.0919,48.0644],[-97.092,48.0644],[-97.0932,48.0653],[-97.0951,48.0669],[-97.0958,48.0677],[-97.0963,48.0688],[-97.0969,48.07],[-97.0972,48.0706],[-97.0977,48.0711],[-97.0982,48.0714],[-97.0988,48.0715],[-97.0997,48.0716],[-97.1012,48.0715],[-97.103,48.0717],[-97.1038,48.0719],[-97.1044,48.0725],[-97.1046,48.0731],[-97.1045,48.074],[-97.1041,48.0746],[-97.1007,48.0775],[-97.1005,48.078],[-97.1001,48.0788],[-97.0998,48.0799],[-97.0994,48.0822],[-97.0994,48.0838],[-97.0996,48.0849],[-97.0997,48.0859],[-97.1001,48.0869],[-97.1012,48.0884],[-97.1021,48.0892],[-97.1034,48.0898],[-97.1047,48.0902],[-97.1066,48.0904],[-97.108,48.0906],[-97.1094,48.091],[-97.1098,48.0914],[-97.1097,48.0917],[-97.1095,48.0922],[-97.1087,48.0928],[-97.1067,48.0934],[-97.1066,48.0934],[-97.104,48.0939],[-97.1031,48.0941],[-97.1025,48.0946],[-97.102,48.0953],[-97.1018,48.0959],[-97.1022,48.0967],[-97.1029,48.0973],[-97.1041,48.098],[-97.106,48.0987],[-97.1066,48.0989],[-97.1074,48.0992],[-97.108,48.0996],[-97.1084,48.0999],[-97.1086,48.1003],[-97.1088,48.1008],[-97.1089,48.1017],[-97.1088,48.1028],[-97.109,48.1038],[-97.1095,48.1048],[-97.1107,48.1056],[-97.1114,48.106],[-97.1124,48.1062],[-97.1131,48.1062],[-97.115,48.106],[-97.1169,48.1057],[-97.1181,48.1056],[-97.1197,48.1054],[-97.1208,48.1056],[-97.1218,48.1059],[-97.1225,48.1063],[-97.1232,48.1067],[-97.1234,48.1073],[-97.1235,48.1076],[-97.1236,48.1078],[-97.1236,48.1081],[-97.1231,48.1095],[-97.122,48.1109],[-97.121,48.1123],[-97.1205,48.1134],[-97.1207,48.115],[-97.121,48.1159],[-97.1215,48.117],[-97.1253,48.1223],[-97.1256,48.1224],[-97.1257,48.1226],[-97.1261,48.1233],[-97.1268,48.1243],[-97.127,48.1246],[-97.1271,48.125],[-97.1275,48.1258],[-97.1282,48.1272],[-97.1286,48.1284],[-97.1288,48.1291],[-97.129,48.1309],[-97.1294,48.1332],[-97.13,48.134],[-97.1314,48.135],[-97.1323,48.1358],[-97.1328,48.1362],[-97.1332,48.1366],[-97.1334,48.1372],[-97.133,48.1375],[-97.1325,48.1377],[-97.1319,48.1376],[-97.1303,48.1372],[-97.1293,48.1369],[-97.1289,48.1367],[-97.128,48.1364],[-97.1276,48.1362],[-97.1267,48.1361],[-97.1253,48.1361],[-97.1241,48.1364],[-97.124,48.1365],[-97.123,48.137],[-97.1227,48.1375],[-97.1224,48.1381],[-97.1223,48.1386],[-97.1223,48.1391],[-97.1228,48.1398],[-97.1234,48.1402],[-97.1239,48.1406],[-97.1248,48.1409],[-97.1253,48.1411],[-97.1266,48.1416],[-97.1277,48.1418],[-97.1294,48.1421],[-97.1297,48.1421],[-97.1319,48.1424],[-97.1347,48.143],[-97.1367,48.1433],[-97.1379,48.1433],[-97.1393,48.1429],[-97.1407,48.1423],[-97.1415,48.1417],[-97.1426,48.1413],[-97.1435,48.141],[-97.1444,48.1411],[-97.1454,48.1413],[-97.1461,48.1417],[-97.1465,48.1423],[-97.1466,48.1433],[-97.1465,48.1441],[-97.1458,48.1452],[-97.1447,48.1466],[-97.1435,48.1475],[-97.1425,48.1487],[-97.1413,48.1501],[-97.1405,48.1508],[-97.1402,48.1509],[-97.1391,48.1516],[-97.1371,48.1523],[-97.1328,48.1535],[-97.1307,48.1542],[-97.1305,48.1543],[-97.1281,48.1552],[-97.1263,48.156],[-97.1253,48.1563],[-97.1244,48.1566],[-97.1236,48.1571],[-97.1225,48.1577],[-97.1217,48.1583],[-97.1211,48.1588],[-97.121,48.1591],[-97.1209,48.1596],[-97.121,48.1608],[-97.1211,48.1612],[-97.1214,48.1615],[-97.1218,48.1617],[-97.1224,48.1621],[-97.1233,48.1625],[-97.1241,48.1627],[-97.1247,48.1628],[-97.1253,48.1629],[-97.1273,48.1628],[-97.1285,48.1626],[-97.1305,48.162],[-97.1313,48.1617],[-97.1322,48.1614],[-97.1345,48.1603],[-97.1363,48.1598],[-97.1385,48.1595],[-97.1403,48.1598],[-97.1419,48.1603],[-97.1431,48.1611],[-97.1442,48.1625],[-97.1443,48.1633],[-97.1445,48.1641],[-97.1447,48.165],[-97.1451,48.1668],[-97.1454,48.1675],[-97.1463,48.1686],[-97.1475,48.1706],[-97.1475,48.1725],[-97.1467,48.1733]]],"type":"Polygon"},"id":"60","properties":{"Area":5177876131.64875,"CTYONLY_":9,"Code":"POLK","LASTMOD":"1999-12-31T23:59:59Z","Name":"Polk","Perimiter":458889.41551},"type":"Feature"},{"geometry":{"coordinates":[[[-96.5008,48.1742],[-96.5008,48.1742],[-96.5006,48.1741],[-96.5003,48.1741],[-96.4973,48.174],[-96.4946,48.1741],[-96.4841,48.174],[-96.4791,48.1741],[-96.4789,48.1741],[-96.4773,48.1741],[-96.4735,48.174],[-96.467,48.1741],[-96.4592,48.1742],[-96.4569,48.1742],[-96.4564,48.1742],[-96.4563,48.1743],[-96.4561,48.1744],[-96.4454,48.1747],[-96.4436,48.1747],[-96.4402,48.1748],[-96.438,48.1749],[-96.4359,48.1749],[-96.4352,48.1749],[-96.4346,48.1749],[-96.4295,48.1749],[-96.4206,48.1749],[-96.4135,48.1749],[-96.4126,48.1749],[-96.4126,48.1749],[-96.4054,48.1748],[-96.3964,48.1748],[-96.3906,48.1748],[-96.3905,48.1748],[-96.3894,48.1748],[-96.3856,48.1747],[-96.38,48.1745],[-96.3781,48.1746],[-96.3753,48.1748],[-96.3728,48.1749],[-96.3706,48.175],[-96.3685,48.1751],[-96.3682,48.1751],[-96.3682,48.1751],[-96.3656,48.175],[-96.3642,48.1749],[-96.361,48.1748],[-96.3581,48.1747],[-96.3542,48.1746],[-96.351,48.1745],[-96.3477,48.1744],[-96.3473,48.1744],[-96.347,48.1743],[-96.3466,48.1743],[-96.343,48.1744],[-96.3402,48.1744],[-96.338,48.1745],[-96.3358,48.1744],[-96.3356,48.1745],[-96.3301,48.1745],[-96.3253,48.1746],[-96.3252,48.1746],[-96.3145,48.1747],[-96.3035,48.1747],[-96.3029,48.1747],[-96.2977,48.1747],[-96.2824,48.1747],[-96.2823,48.1747],[-96.2805,48.1747],[-96.2619,48.1749],[-96.2612,48.1749],[-96.2607,48.1749],[-96.2596,48.1749],[-96.2562,48.1744],[-96.252,48.174],[-96.2511,48.174],[-96.2503,48.1739],[-96.2491,48.1737],[-96.2476,48.1735],[-96.2398,48.1728],[-96.2397,48.1727],[-96.2397,48.1727],[-96.2391,48.1727],[-96.2329,48.1725],[-96.2307,48.1725],[-96.2287,48.1725],[-96.2275,48.1724],[-96.2251,48.1724],[-96.2188,48.1722],[-96.2179,48.1722],[-96.2177,48.1722],[-96.2076,48.1722],[-96.2072,48.1722],[-96.2038,48.1722],[-96.2023,48.1722],[-96.1963,48.1721],[-96.1959,48.1721],[-96.1954,48.1721],[-96.1948,48.1721],[-96.191,48.1721],[-96.1874,48.1721],[-96.1834,48.172],[-96.1827,48.1722],[-96.1813,48.1725],[-96.1741,48.1736],[-96.1737,48.1736],[-96.1736,48.1736],[-96.1641,48.1736],[-96.1625,48.1736],[-96.1518,48.1736],[-96.1516,48.1736],[-96.1388,48.1732],[-96.1302,48.173],[-96.1298,48.173],[-96.1297,48.173],[-96.1253,48.1727],[-96.1189,48.1722],[-96.1176,48.1722],[-96.1084,48.1718],[-96.1084,48.1718],[-96.0979,48.172],[-96.09,48.172],[-96.09,48.172],[-96.079,48.1721],[-96.0685,48.1721],[-96.0685,48.1721],[-96.0592,48.1721],[-96.0468,48.1722],[-96.0468,48.1722],[-96.0254,48.1721],[-96.025,48.1721],[-96.0171,48.172],[-96.0101,48.1718],[-96.0047,48.1717],[-96.0036,48.1718],[-96.0035,48.1718],[-96.0032,48.1718],[-96.0028,48.1718],[-96.0023,48.1718],[-96.0003,48.1717],[-95.9956,48.1717],[-95.9819,48.1717],[-95.9817,48.1717],[-95.9651,48.1718],[-95.961,48.1718],[-95.9609,48.1718],[-95.9608,48.1718],[-95.9394,48.1719],[-95.9392,48.1719],[-95.9178,48.1719],[-95.9178,48.1719],[-95.9176,48.1719],[-95.896,48.172],[-95.8958,48.172],[-95.8752,48.172],[-95.8744,48.172],[-95.8744,48.172],[-95.8527,48.1721],[-95.8525,48.1721],[-95.8499,48.1721],[-95.8308,48.1722],[-95.8308,48.1722],[-95.8305,48.1722],[-95.8091,48.1722],[-95.809,48.1722],[-95.8088,48.1722],[-95.7874,48.1725],[-95.7657,48.1728],[-95.7657,48.1728],[-95.7502,48.1727],[-95.7443,48.1727],[-95.744,48.1727],[-95.7227,48.1731],[-95.7226,48.1731],[-95.7157,48.1731],[-95.7128,48.173],[-95.7022,48.1729],[-95.7021,48.1729],[-95.702,48.1729],[-95.6803,48.1728],[-95.6802,48.1728],[-95.662,48.1729],[-95.6591,48.1729],[-95.6376,48.173],[-95.6376,48.173],[-95.6279,48.1731],[-95.6252,48.1731],[-95.6163,48.1731],[-95.6159,48.1731],[-95.5941,48.173],[-95.5939,48.173],[-95.5939,48.1658],[-95.5938,48.1512],[-95.5936,48.1368],[-95.5931,48.1223],[-95.593,48.1078],[-95.5928,48.0931],[-95.5926,48.0787],[-95.5925,48.0642],[-95.5925,48.0497],[-95.5923,48.035],[-95.5922,48.0207],[-95.5828,48.0207],[-95.5825,48.0063],[-95.5824,47.9917],[-95.5825,47.9771],[-95.5826,47.9629],[-95.5825,47.9482],[-95.5824,47.9339],[-95.6034,47.9341],[-95.6252,47.9344],[-95.6466,47.9348],[-95.6683,47.9351],[-95.6898,47.9354],[-95.7096,47.9355],[-95.7097,47.9499],[-95.7098,47.9644],[-95.7312,47.9644],[-95.7531,47.9645],[-95.7747,47.9646],[-95.7963,47.9647],[-95.8181,47.9647],[-95.8383,47.9648],[-95.86,47.9649],[-95.8814,47.9648],[-95.9031,47.9648],[-95.925,47.9647],[-95.9462,47.9646],[-95.9671,47.9646],[-95.9887,47.9642],[-96.0106,47.9641],[-96.0324,47.964],[-96.054,47.9638],[-96.0757,47.9637],[-96.096,47.9638],[-96.1173,47.9632],[-96.1389,47.9631],[-96.1606,47.9631],[-96.1826,47.9632],[-96.2044,47.963],[-96.2235,47.9629],[-96.2453,47.9629],[-96.2667,47.9629],[-96.2883,47.963],[-96.31,47.9633],[-96.3316,47.9634],[-96.3526,47.9634],[-96.3738,47.9636],[-96.3954,47.9636],[-96.4172,47.9637],[-96.439,47.9636],[-96.4603,47.9639],[-96.4823,47.9636],[-96.4823,47.9782],[-96.4824,47.9924],[-96.4826,48.0072],[-96.4826,48.0217],[-96.5009,48.0217],[-96.5009,48.0362],[-96.5008,48.0506],[-96.5009,48.0654],[-96.5009,48.0798],[-96.5009,48.0943],[-96.501,48.1089],[-96.5007,48.1234],[-96.5006,48.1379],[-96.5008,48.1524],[-96.5008,48.1669],[-96.5008,48.1742]]],"type":"Polygon"},"id":"57","properties":{"Area":1601102945.98836,"CTYONLY_":10,"Code":"PENN","LASTMOD":"2006-07-04T12:00:00Z","Name":"Pennington","Perimiter":190039.7415},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&filter=Name%3D'Rice'%20OR%201%3D1","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&filter=Name%3D'Rice'%20OR%201%3D1","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=9&filter=Name%3D'Rice'%20OR%201%3D1","rel":"next","title":"next page","type":"application/geo+json"}],"numberMatched":117,"numberReturned":9,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_text_s_intersects_bbox.json.txt b/msautotest/api/expected/ogcapi_cql2_text_s_intersects_bbox.json.txt new file mode 100644 index 0000000000..d7dcea92d5 --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_text_s_intersects_bbox.json.txt @@ -0,0 +1,9 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +Link: ; rel="next"; title="next page"; type="application/geo+json" +OGC-NumberMatched: 117 +OGC-NumberReturned: 1 + +{"features":[{"geometry":{"coordinates":[[[-95.3231,48.999],[-95.3109,48.999],[-95.2889,48.9989],[-95.2852,48.9989],[-95.2669,48.9989],[-95.245,48.9989],[-95.2232,48.9989],[-95.2014,48.9989],[-95.1792,48.9989],[-95.1574,48.9989],[-95.1531,48.9989],[-95.1531,49.0031],[-95.1532,49.0179],[-95.1532,49.0325],[-95.1532,49.047],[-95.1532,49.0619],[-95.1532,49.0765],[-95.1532,49.0911],[-95.1532,49.1057],[-95.1532,49.1205],[-95.1532,49.1354],[-95.1532,49.1499],[-95.1532,49.1642],[-95.1532,49.1788],[-95.1532,49.1807],[-95.1532,49.1931],[-95.1532,49.1966],[-95.1532,49.2077],[-95.1533,49.2131],[-95.1533,49.2219],[-95.1533,49.2308],[-95.1533,49.2365],[-95.1533,49.2472],[-95.1533,49.2512],[-95.1533,49.2655],[-95.1533,49.2697],[-95.1533,49.2802],[-95.1533,49.2882],[-95.1533,49.2945],[-95.1533,49.3072],[-95.1533,49.309],[-95.1533,49.3234],[-95.1533,49.3237],[-95.1533,49.3381],[-95.1533,49.3476],[-95.1533,49.3525],[-95.1533,49.3636],[-95.1533,49.367],[-95.1533,49.3705],[-95.1533,49.3776],[-95.1533,49.3813],[-95.1533,49.3845],[-95.1503,49.383],[-95.1499,49.3813],[-95.1498,49.3807],[-95.1467,49.3802],[-95.145,49.3784],[-95.1418,49.3784],[-95.1397,49.3762],[-95.1367,49.3751],[-95.1324,49.3736],[-95.1287,49.3705],[-95.1171,49.367],[-95.1159,49.3666],[-95.1145,49.3666],[-95.1098,49.3664],[-95.1031,49.3652],[-95.1031,49.3636],[-95.0926,49.3617],[-95.0897,49.3612],[-95.0707,49.3564],[-95.0582,49.3533],[-95.0495,49.3532],[-95.0479,49.3533],[-95.0262,49.3554],[-95.0141,49.3565],[-95.0047,49.3612],[-94.993,49.367],[-94.9889,49.369],[-94.9818,49.3684],[-94.9742,49.3678],[-94.9597,49.3699],[-94.9573,49.3702],[-94.952,49.3688],[-94.948,49.367],[-94.9376,49.3625],[-94.9152,49.3529],[-94.9143,49.3524],[-94.909,49.3502],[-94.9065,49.3484],[-94.8933,49.3414],[-94.8865,49.3378],[-94.8782,49.3334],[-94.8712,49.3308],[-94.854,49.3244],[-94.8492,49.3244],[-94.8363,49.3243],[-94.8311,49.3236],[-94.8271,49.323],[-94.8162,49.3214],[-94.8243,49.309],[-94.8243,49.3088],[-94.8255,49.2944],[-94.8255,49.2943],[-94.8204,49.28],[-94.8152,49.2653],[-94.8103,49.2515],[-94.8059,49.2388],[-94.8051,49.2367],[-94.8001,49.2224],[-94.7973,49.2144],[-94.7975,49.2079],[-94.7979,49.1979],[-94.7965,49.1936],[-94.7918,49.1792],[-94.7871,49.1646],[-94.7833,49.153],[-94.7823,49.15],[-94.7776,49.1357],[-94.7727,49.1206],[-94.7727,49.1206],[-94.7611,49.1096],[-94.7571,49.1058],[-94.7496,49.0988],[-94.7474,49.0918],[-94.7429,49.0773],[-94.7394,49.0657],[-94.7385,49.063],[-94.7344,49.0497],[-94.7299,49.0351],[-94.7254,49.0205],[-94.7207,49.0052],[-94.7184,48.9979],[-94.7162,48.9907],[-94.7117,48.9761],[-94.7072,48.9615],[-94.7027,48.9468],[-94.6982,48.9322],[-94.6968,48.9276],[-94.6844,48.8875],[-94.6834,48.8842],[-94.6842,48.8724],[-94.6855,48.8719],[-94.6923,48.8691],[-94.6902,48.8636],[-94.6914,48.8591],[-94.693,48.8535],[-94.6881,48.8447],[-94.6855,48.8401],[-94.6963,48.836],[-94.6975,48.8355],[-94.702,48.8319],[-94.7025,48.8302],[-94.7042,48.8243],[-94.6991,48.8159],[-94.6962,48.8111],[-94.6951,48.8092],[-94.6958,48.8012],[-94.6959,48.7997],[-94.6944,48.7895],[-94.6934,48.7864],[-94.6909,48.7781],[-94.687,48.7752],[-94.6776,48.772],[-94.6768,48.7717],[-94.6746,48.7705],[-94.6671,48.7662],[-94.6603,48.7605],[-94.6557,48.7581],[-94.6525,48.7565],[-94.652,48.7562],[-94.6453,48.7491],[-94.6453,48.7441],[-94.6443,48.7434],[-94.6414,48.7413],[-94.631,48.7392],[-94.6301,48.739],[-94.6191,48.7373],[-94.6106,48.7318],[-94.6084,48.731],[-94.6028,48.7289],[-94.6011,48.7283],[-94.5962,48.7248],[-94.5913,48.7197],[-94.5876,48.7176],[-94.5867,48.7175],[-94.5685,48.7156],[-94.5622,48.7159],[-94.5558,48.7163],[-94.549,48.7148],[-94.5487,48.7146],[-94.5457,48.7124],[-94.5396,48.7036],[-94.539,48.7028],[-94.5329,48.7013],[-94.5247,48.7016],[-94.5178,48.7008],[-94.5173,48.7008],[-94.5093,48.7006],[-94.5066,48.6999],[-94.4996,48.698],[-94.4958,48.698],[-94.4863,48.698],[-94.4739,48.6969],[-94.4706,48.6966],[-94.4631,48.6953],[-94.4568,48.6933],[-94.4523,48.6925],[-94.4517,48.6925],[-94.4465,48.693],[-94.4388,48.6949],[-94.4319,48.6998],[-94.4299,48.7012],[-94.4299,48.6998],[-94.43,48.6852],[-94.4301,48.6708],[-94.43,48.6564],[-94.4297,48.642],[-94.4294,48.6276],[-94.4292,48.6133],[-94.4289,48.5988],[-94.4289,48.5844],[-94.4291,48.5698],[-94.4295,48.5554],[-94.43,48.5409],[-94.4303,48.5264],[-94.4303,48.512],[-94.4299,48.4977],[-94.4296,48.4832],[-94.4296,48.4688],[-94.4293,48.4543],[-94.4292,48.4399],[-94.4293,48.4254],[-94.4294,48.411],[-94.4293,48.3964],[-94.4289,48.3821],[-94.4288,48.3675],[-94.4471,48.3675],[-94.4505,48.3675],[-94.4688,48.3675],[-94.4722,48.3674],[-94.4906,48.3674],[-94.4924,48.3674],[-94.4941,48.3674],[-94.5118,48.3675],[-94.5157,48.3674],[-94.5335,48.3674],[-94.5378,48.3674],[-94.5536,48.3674],[-94.5593,48.3674],[-94.5754,48.3674],[-94.5812,48.3674],[-94.5971,48.3675],[-94.6029,48.3674],[-94.6188,48.3673],[-94.6245,48.3673],[-94.6405,48.3673],[-94.6465,48.3673],[-94.6505,48.3673],[-94.6622,48.3673],[-94.6679,48.3673],[-94.6694,48.3672],[-94.683,48.3671],[-94.6898,48.3671],[-94.7099,48.3669],[-94.7117,48.3668],[-94.7315,48.3669],[-94.7329,48.3669],[-94.7533,48.3669],[-94.7549,48.3669],[-94.7748,48.3669],[-94.7765,48.3669],[-94.7967,48.3669],[-94.7983,48.3669],[-94.8183,48.3669],[-94.8199,48.3669],[-94.8399,48.3669],[-94.8416,48.3669],[-94.8616,48.3667],[-94.8632,48.3667],[-94.8833,48.3667],[-94.8849,48.3666],[-94.9049,48.3666],[-94.9065,48.3666],[-94.9264,48.3667],[-94.9283,48.3667],[-94.9469,48.3666],[-94.95,48.3666],[-94.9684,48.3667],[-94.9716,48.3667],[-94.9901,48.3667],[-94.9932,48.3667],[-95.0119,48.3665],[-95.0153,48.3665],[-95.0337,48.3665],[-95.0369,48.3665],[-95.0555,48.3665],[-95.0586,48.3665],[-95.0773,48.3664],[-95.0801,48.3664],[-95.099,48.3663],[-95.1008,48.3663],[-95.1018,48.3663],[-95.1207,48.3663],[-95.1236,48.3663],[-95.1315,48.3662],[-95.1424,48.3662],[-95.1454,48.3662],[-95.164,48.3661],[-95.1669,48.3661],[-95.1861,48.3661],[-95.1887,48.3661],[-95.1983,48.3661],[-95.2066,48.3661],[-95.2106,48.3661],[-95.211,48.3797],[-95.211,48.3808],[-95.2111,48.3941],[-95.2111,48.3952],[-95.2112,48.4087],[-95.2112,48.4096],[-95.2113,48.4232],[-95.2113,48.4242],[-95.2113,48.4255],[-95.2113,48.4376],[-95.2113,48.4387],[-95.2113,48.4522],[-95.2112,48.4529],[-95.211,48.4666],[-95.211,48.4673],[-95.2111,48.4816],[-95.2112,48.4962],[-95.2111,48.5101],[-95.2111,48.5109],[-95.2115,48.5244],[-95.2115,48.5252],[-95.2119,48.54],[-95.2324,48.5399],[-95.2339,48.5399],[-95.2537,48.5398],[-95.2554,48.5398],[-95.2756,48.54],[-95.2773,48.54],[-95.2975,48.5401],[-95.2992,48.5402],[-95.3194,48.54],[-95.321,48.54],[-95.3412,48.5402],[-95.3425,48.5402],[-95.3424,48.5548],[-95.3423,48.5691],[-95.3423,48.5836],[-95.3426,48.5979],[-95.3424,48.6127],[-95.3426,48.6271],[-95.3425,48.6415],[-95.3424,48.6561],[-95.3423,48.6705],[-95.3424,48.6849],[-95.3425,48.6995],[-95.3425,48.7131],[-95.3302,48.713],[-95.3205,48.713],[-95.3084,48.713],[-95.3051,48.713],[-95.299,48.713],[-95.2866,48.713],[-95.2767,48.713],[-95.2656,48.713],[-95.2645,48.713],[-95.255,48.713],[-95.2427,48.713],[-95.2331,48.713],[-95.2206,48.713],[-95.2112,48.713],[-95.1991,48.713],[-95.1917,48.713],[-95.1773,48.713],[-95.1697,48.7129],[-95.1554,48.7129],[-95.1477,48.7129],[-95.1333,48.713],[-95.1297,48.713],[-95.1259,48.7129],[-95.1119,48.7129],[-95.1104,48.7129],[-95.1046,48.7129],[-95.0898,48.713],[-95.0899,48.7277],[-95.0901,48.7421],[-95.0901,48.7566],[-95.0903,48.7711],[-95.0903,48.7855],[-95.0903,48.8],[-95.0909,48.8147],[-95.0908,48.8291],[-95.0907,48.8436],[-95.0908,48.858],[-95.0908,48.8724],[-95.0911,48.8869],[-95.0912,48.9014],[-95.0914,48.916],[-95.0914,48.9208],[-95.0919,48.9207],[-95.0927,48.9204],[-95.0944,48.9193],[-95.0946,48.9191],[-95.0961,48.9181],[-95.097,48.9176],[-95.0971,48.9172],[-95.0975,48.9164],[-95.098,48.916],[-95.0981,48.9159],[-95.1008,48.9142],[-95.102,48.9132],[-95.1032,48.9127],[-95.1042,48.9121],[-95.1056,48.9113],[-95.108,48.9099],[-95.1096,48.9089],[-95.1107,48.9082],[-95.1126,48.9073],[-95.113,48.9072],[-95.1132,48.9071],[-95.1137,48.9069],[-95.1141,48.9064],[-95.114,48.9061],[-95.1144,48.9052],[-95.1151,48.9046],[-95.1163,48.9037],[-95.1182,48.9029],[-95.1204,48.9019],[-95.1205,48.9017],[-95.121,48.9016],[-95.1214,48.9013],[-95.1228,48.9006],[-95.1233,48.9004],[-95.1239,48.9001],[-95.1252,48.8998],[-95.1312,48.8975],[-95.1322,48.8973],[-95.1337,48.8969],[-95.1343,48.8963],[-95.1348,48.8963],[-95.1351,48.8963],[-95.1355,48.8959],[-95.1381,48.8949],[-95.1404,48.8943],[-95.1436,48.8937],[-95.1438,48.8934],[-95.1459,48.8929],[-95.1469,48.8927],[-95.1483,48.8923],[-95.1508,48.8922],[-95.1528,48.8921],[-95.1555,48.892],[-95.1564,48.8919],[-95.1579,48.8919],[-95.1602,48.892],[-95.1618,48.892],[-95.1641,48.8917],[-95.1648,48.8913],[-95.1674,48.8907],[-95.1701,48.8902],[-95.173,48.8897],[-95.1764,48.8893],[-95.1791,48.889],[-95.1797,48.889],[-95.1819,48.8888],[-95.1851,48.8882],[-95.1863,48.8877],[-95.1877,48.8874],[-95.1889,48.8873],[-95.1901,48.887],[-95.1913,48.8868],[-95.1919,48.8866],[-95.1924,48.8865],[-95.1956,48.8862],[-95.1986,48.8855],[-95.2005,48.8856],[-95.2009,48.8855],[-95.2024,48.8852],[-95.2059,48.8848],[-95.2085,48.8846],[-95.2112,48.8848],[-95.2115,48.8847],[-95.2117,48.8847],[-95.2122,48.8842],[-95.2144,48.8843],[-95.2151,48.884],[-95.2159,48.8839],[-95.217,48.8835],[-95.2188,48.8835],[-95.2193,48.8832],[-95.22,48.8831],[-95.2207,48.8831],[-95.2208,48.8831],[-95.2212,48.883],[-95.2252,48.8819],[-95.2265,48.8816],[-95.2287,48.8815],[-95.231,48.8814],[-95.2335,48.8814],[-95.2356,48.8815],[-95.2381,48.8817],[-95.2391,48.8819],[-95.2407,48.8821],[-95.2423,48.8821],[-95.2429,48.8822],[-95.2429,48.8822],[-95.2439,48.8823],[-95.2458,48.8829],[-95.2472,48.8835],[-95.248,48.8836],[-95.2485,48.8832],[-95.2496,48.8834],[-95.2502,48.8835],[-95.2507,48.8836],[-95.2517,48.8839],[-95.2548,48.8845],[-95.256,48.885],[-95.257,48.8858],[-95.2585,48.8867],[-95.2585,48.8867],[-95.2627,48.8877],[-95.2635,48.888],[-95.2639,48.8883],[-95.2646,48.8885],[-95.265,48.8886],[-95.2654,48.8888],[-95.2666,48.8894],[-95.2674,48.89],[-95.2677,48.8903],[-95.268,48.8905],[-95.2713,48.8915],[-95.2724,48.8921],[-95.2745,48.8931],[-95.2751,48.8938],[-95.2753,48.8943],[-95.2748,48.8951],[-95.2749,48.8956],[-95.2755,48.8959],[-95.2759,48.8962],[-95.2763,48.8963],[-95.2765,48.8962],[-95.277,48.8958],[-95.2773,48.8957],[-95.2782,48.8956],[-95.279,48.8957],[-95.2796,48.8962],[-95.2803,48.8965],[-95.2813,48.8967],[-95.2839,48.8975],[-95.2853,48.8977],[-95.2861,48.8976],[-95.2865,48.8975],[-95.287,48.8976],[-95.2872,48.8977],[-95.2879,48.8979],[-95.2882,48.8981],[-95.289,48.8994],[-95.2896,48.9],[-95.2901,48.9003],[-95.2911,48.9006],[-95.2911,48.9008],[-95.2906,48.9011],[-95.2907,48.9014],[-95.2908,48.9016],[-95.2909,48.9017],[-95.2914,48.9019],[-95.2927,48.9019],[-95.2935,48.902],[-95.2937,48.9023],[-95.2941,48.9027],[-95.2949,48.9028],[-95.2967,48.9027],[-95.2976,48.9026],[-95.298,48.9027],[-95.2983,48.9028],[-95.2993,48.9035],[-95.3005,48.904],[-95.3002,48.9045],[-95.3001,48.9046],[-95.3001,48.9047],[-95.3,48.9047],[-95.3,48.9047],[-95.2999,48.9048],[-95.2999,48.9048],[-95.2999,48.9048],[-95.2997,48.905],[-95.2996,48.9051],[-95.2994,48.9053],[-95.2992,48.9055],[-95.2991,48.9057],[-95.2989,48.906],[-95.2988,48.906],[-95.2986,48.9063],[-95.2985,48.9064],[-95.2985,48.9065],[-95.2983,48.9068],[-95.2982,48.9068],[-95.2981,48.907],[-95.298,48.9071],[-95.298,48.9071],[-95.298,48.9071],[-95.2979,48.9071],[-95.2979,48.9072],[-95.2979,48.9072],[-95.2978,48.9072],[-95.2978,48.9072],[-95.2978,48.9073],[-95.2977,48.9073],[-95.2976,48.9074],[-95.2973,48.9077],[-95.2973,48.908],[-95.2973,48.9081],[-95.2978,48.9083],[-95.2999,48.9086],[-95.3017,48.9093],[-95.3027,48.91],[-95.3038,48.9114],[-95.3043,48.9119],[-95.3059,48.9127],[-95.3061,48.9128],[-95.3064,48.9129],[-95.3074,48.9135],[-95.3078,48.9141],[-95.3085,48.9146],[-95.3092,48.9149],[-95.3093,48.9149],[-95.3102,48.9155],[-95.3109,48.9163],[-95.3115,48.9172],[-95.3119,48.9178],[-95.3126,48.919],[-95.3132,48.9198],[-95.3141,48.921],[-95.315,48.9222],[-95.3168,48.9245],[-95.3195,48.9285],[-95.3208,48.9305],[-95.3209,48.9307],[-95.3222,48.9327],[-95.3228,48.9344],[-95.3223,48.9355],[-95.3225,48.9358],[-95.3229,48.9373],[-95.3231,48.9389],[-95.3228,48.9403],[-95.3225,48.9409],[-95.3219,48.9412],[-95.3189,48.9419],[-95.3181,48.9421],[-95.3168,48.9431],[-95.3154,48.9448],[-95.3148,48.9452],[-95.3141,48.9457],[-95.3131,48.946],[-95.3114,48.9461],[-95.3102,48.9463],[-95.3095,48.9463],[-95.3088,48.9464],[-95.3086,48.9465],[-95.3086,48.9469],[-95.3085,48.947],[-95.3078,48.9466],[-95.3074,48.9465],[-95.3071,48.9466],[-95.3071,48.9469],[-95.3079,48.9474],[-95.3092,48.9477],[-95.3096,48.9478],[-95.3103,48.948],[-95.3104,48.9484],[-95.3103,48.9485],[-95.31,48.9485],[-95.3099,48.9484],[-95.3096,48.9482],[-95.3094,48.9481],[-95.3081,48.948],[-95.3071,48.9477],[-95.3062,48.9472],[-95.3062,48.9472],[-95.3061,48.9469],[-95.3062,48.9463],[-95.3063,48.9462],[-95.3069,48.9456],[-95.3069,48.9455],[-95.3068,48.9454],[-95.3061,48.9454],[-95.3053,48.9459],[-95.305,48.9462],[-95.3046,48.947],[-95.3046,48.9482],[-95.3052,48.9495],[-95.3061,48.9502],[-95.3079,48.9509],[-95.3089,48.9511],[-95.3097,48.951],[-95.3104,48.951],[-95.3108,48.9512],[-95.3115,48.952],[-95.312,48.9524],[-95.3126,48.9524],[-95.3129,48.9523],[-95.3129,48.9521],[-95.3119,48.9507],[-95.3119,48.9502],[-95.3123,48.9502],[-95.3125,48.9503],[-95.3131,48.9503],[-95.3141,48.9508],[-95.3151,48.951],[-95.3154,48.9513],[-95.3177,48.9525],[-95.3181,48.9531],[-95.3182,48.9535],[-95.3177,48.9545],[-95.3175,48.9552],[-95.3179,48.9559],[-95.3188,48.9562],[-95.3191,48.9569],[-95.3202,48.9581],[-95.3206,48.959],[-95.3206,48.9595],[-95.3206,48.9598],[-95.3202,48.9606],[-95.3193,48.9622],[-95.3193,48.964],[-95.3198,48.9643],[-95.3201,48.9648],[-95.3207,48.9669],[-95.3212,48.9672],[-95.3227,48.9685],[-95.3232,48.9692],[-95.3241,48.9703],[-95.3247,48.972],[-95.3248,48.9728],[-95.3249,48.9738],[-95.325,48.9743],[-95.3253,48.976],[-95.3257,48.9784],[-95.3255,48.9789],[-95.3256,48.98],[-95.3257,48.9814],[-95.3253,48.9832],[-95.3245,48.985],[-95.3242,48.9859],[-95.3227,48.9884],[-95.3224,48.9889],[-95.3206,48.9921],[-95.3204,48.9924],[-95.3191,48.9941],[-95.3181,48.995],[-95.3178,48.9958],[-95.3178,48.9961],[-95.3179,48.9961],[-95.3182,48.996],[-95.3187,48.9956],[-95.3191,48.9953],[-95.3197,48.9954],[-95.3201,48.9956],[-95.3206,48.9961],[-95.3204,48.9964],[-95.3202,48.9973],[-95.3204,48.9976],[-95.3224,48.9984],[-95.3231,48.999]]],"type":"Polygon"},"id":"39","properties":{"Area":4608320923.49768,"CTYONLY_":2,"Code":"LOTW","LASTMOD":"1976-07-04T12:00:00Z","Name":"Lake of the Woods","Perimiter":388250.14572},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=1&offset=0&filter=s_intersects(geom%2Cbbox(-180%2C-90%2C0%2C90))","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=1&offset=0&filter=s_intersects(geom%2Cbbox(-180%2C-90%2C0%2C90))","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=1&offset=1&filter=s_intersects(geom%2Cbbox(-180%2C-90%2C0%2C90))","rel":"next","title":"next page","type":"application/geo+json"}],"numberMatched":117,"numberReturned":1,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_text_s_intersects_point.json.txt b/msautotest/api/expected/ogcapi_cql2_text_s_intersects_point.json.txt new file mode 100644 index 0000000000..e89d81ffed --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_text_s_intersects_point.json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 1 +OGC-NumberReturned: 1 + +{"features":[{"geometry":{"coordinates":[[[-94.4299,48.7012],[-94.4241,48.7053],[-94.4213,48.7086],[-94.4189,48.7103],[-94.4158,48.711],[-94.4081,48.7106],[-94.406,48.7105],[-94.3889,48.712],[-94.3859,48.7119],[-94.384,48.7119],[-94.3801,48.7111],[-94.3687,48.7065],[-94.3646,48.7059],[-94.3533,48.7042],[-94.3431,48.7035],[-94.3429,48.7035],[-94.3287,48.7045],[-94.3214,48.7067],[-94.3088,48.7103],[-94.2995,48.709],[-94.2911,48.7079],[-94.2829,48.7057],[-94.2781,48.7024],[-94.2745,48.6999],[-94.2694,48.6995],[-94.2644,48.699],[-94.261,48.6966],[-94.258,48.6918],[-94.2565,48.6901],[-94.2529,48.6864],[-94.2521,48.685],[-94.2514,48.6837],[-94.2507,48.6782],[-94.2527,48.6707],[-94.253,48.6693],[-94.2548,48.664],[-94.2546,48.6615],[-94.2509,48.657],[-94.2499,48.6563],[-94.2467,48.6542],[-94.2445,48.6535],[-94.2343,48.6524],[-94.2335,48.6524],[-94.2242,48.6495],[-94.2144,48.6494],[-94.2124,48.6496],[-94.1996,48.651],[-94.1915,48.6506],[-94.1886,48.6504],[-94.1689,48.6483],[-94.1678,48.6482],[-94.1574,48.6458],[-94.1522,48.6455],[-94.1458,48.6458],[-94.1391,48.646],[-94.126,48.6444],[-94.1235,48.6444],[-94.11,48.6443],[-94.1023,48.6455],[-94.0999,48.6459],[-94.0912,48.6437],[-94.0849,48.6441],[-94.0804,48.6442],[-94.0767,48.6442],[-94.0714,48.6459],[-94.0658,48.6462],[-94.0642,48.6438],[-94.0603,48.6431],[-94.0581,48.6434],[-94.0525,48.644],[-94.0432,48.6435],[-94.0393,48.6423],[-94.0364,48.6413],[-94.0356,48.6411],[-94.0295,48.6409],[-94.0153,48.6424],[-94.0069,48.6433],[-94.0007,48.6428],[-93.9931,48.6412],[-93.9897,48.6405],[-93.984,48.6401],[-93.9777,48.6385],[-93.9712,48.6385],[-93.968,48.6385],[-93.9596,48.6372],[-93.953,48.6341],[-93.9497,48.6339],[-93.934,48.6326],[-93.9272,48.6327],[-93.9169,48.6329],[-93.9134,48.6353],[-93.9057,48.6346],[-93.9054,48.6345],[-93.8948,48.6324],[-93.8853,48.6318],[-93.8844,48.6318],[-93.8757,48.6319],[-93.8698,48.6311],[-93.8624,48.631],[-93.848,48.6308],[-93.8443,48.6303],[-93.8404,48.6289],[-93.8393,48.6286],[-93.8365,48.6276],[-93.8334,48.6256],[-93.8292,48.6177],[-93.825,48.6136],[-93.8245,48.613],[-93.8214,48.6092],[-93.8182,48.5994],[-93.8175,48.597],[-93.8172,48.5964],[-93.813,48.588],[-93.8103,48.5846],[-93.8063,48.5796],[-93.8041,48.5703],[-93.8041,48.5702],[-93.8051,48.5644],[-93.808,48.5569],[-93.8088,48.5555],[-93.8119,48.5503],[-93.8102,48.5445],[-93.8109,48.5412],[-93.8109,48.541],[-93.818,48.535],[-93.818,48.5346],[-93.8184,48.5315],[-93.8178,48.5306],[-93.8161,48.5285],[-93.8145,48.5273],[-93.8111,48.5247],[-93.803,48.522],[-93.7964,48.5182],[-93.7933,48.5164],[-93.7879,48.5159],[-93.7745,48.5162],[-93.768,48.5164],[-93.7665,48.5164],[-93.7617,48.5166],[-93.7534,48.5158],[-93.7442,48.5175],[-93.739,48.5185],[-93.731,48.5185],[-93.7225,48.5178],[-93.7206,48.5176],[-93.7108,48.5186],[-93.7061,48.5182],[-93.7006,48.517],[-93.693,48.5152],[-93.6866,48.5154],[-93.6791,48.5167],[-93.6778,48.5169],[-93.6593,48.5165],[-93.657,48.5167],[-93.6473,48.5177],[-93.6433,48.519],[-93.6421,48.5199],[-93.6395,48.5218],[-93.6357,48.5285],[-93.6344,48.5293],[-93.6311,48.5313],[-93.6284,48.5319],[-93.6256,48.5315],[-93.6211,48.5264],[-93.6166,48.5238],[-93.6134,48.5228],[-93.6122,48.5225],[-93.6051,48.5231],[-93.5962,48.5287],[-93.5919,48.5299],[-93.5901,48.5305],[-93.581,48.5271],[-93.5761,48.527],[-93.5701,48.528],[-93.5602,48.5297],[-93.5484,48.5294],[-93.5476,48.5294],[-93.5425,48.53],[-93.5366,48.5319],[-93.5269,48.5341],[-93.5263,48.5341],[-93.5244,48.5343],[-93.5171,48.5348],[-93.5047,48.5399],[-93.501,48.5414],[-93.4952,48.5426],[-93.4854,48.5433],[-93.4833,48.5437],[-93.4673,48.5465],[-93.4655,48.5478],[-93.4625,48.5498],[-93.462,48.5505],[-93.4596,48.5537],[-93.4576,48.5598],[-93.4576,48.5621],[-93.4575,48.5672],[-93.4619,48.5731],[-93.4619,48.5734],[-93.4631,48.5767],[-93.4671,48.5885],[-93.4656,48.59],[-93.4654,48.5915],[-93.4654,48.5917],[-93.4627,48.5927],[-93.46,48.5927],[-93.4547,48.5927],[-93.4398,48.5937],[-93.4385,48.5942],[-93.4347,48.5954],[-93.4298,48.5997],[-93.4226,48.6032],[-93.4193,48.6036],[-93.416,48.605],[-93.4152,48.6053],[-93.415,48.6056],[-93.4144,48.6064],[-93.4056,48.6099],[-93.4034,48.61],[-93.4029,48.6077],[-93.4013,48.6079],[-93.3994,48.6055],[-93.3986,48.6045],[-93.3953,48.6038],[-93.3937,48.6041],[-93.3837,48.606],[-93.3724,48.6059],[-93.3714,48.6059],[-93.3672,48.6082],[-93.3619,48.6141],[-93.355,48.6114],[-93.3526,48.6135],[-93.3533,48.615],[-93.3513,48.62],[-93.3505,48.6219],[-93.3486,48.6265],[-93.3276,48.6302],[-93.3057,48.634],[-93.3048,48.6341],[-93.2838,48.6378],[-93.2634,48.6413],[-93.2546,48.6429],[-93.2422,48.6428],[-93.2193,48.6426],[-93.2075,48.6426],[-93.1975,48.6365],[-93.191,48.6325],[-93.184,48.6282],[-93.1783,48.6231],[-93.1754,48.6232],[-93.1531,48.6244],[-93.1319,48.6256],[-93.1104,48.6267],[-93.0903,48.6278],[-93.0884,48.6278],[-93.0886,48.6163],[-93.0895,48.6016],[-93.0898,48.5872],[-93.09,48.5727],[-93.0902,48.5583],[-93.0902,48.5441],[-93.0903,48.5296],[-93.0905,48.5151],[-93.0905,48.501],[-93.091,48.4884],[-93.0911,48.4867],[-93.0914,48.474],[-93.0915,48.4724],[-93.0918,48.4596],[-93.0919,48.458],[-93.092,48.4449],[-93.092,48.4436],[-93.0922,48.4303],[-93.0922,48.429],[-93.0923,48.4147],[-93.0935,48.4147],[-93.0938,48.4024],[-93.094,48.3879],[-93.094,48.3734],[-93.0945,48.3589],[-93.0948,48.3442],[-93.0948,48.3298],[-93.0953,48.3153],[-93.0952,48.3004],[-93.095,48.2862],[-93.0952,48.2716],[-93.0953,48.2576],[-93.0949,48.2426],[-93.0949,48.2425],[-93.0977,48.2426],[-93.0977,48.2271],[-93.0978,48.2126],[-93.0979,48.1981],[-93.0975,48.1836],[-93.097,48.1692],[-93.097,48.1546],[-93.097,48.1402],[-93.0969,48.1259],[-93.0972,48.1114],[-93.097,48.0969],[-93.0968,48.0823],[-93.0965,48.0679],[-93.0965,48.0678],[-93.0892,48.0679],[-93.0892,48.0509],[-93.089,48.0366],[-93.0886,48.022],[-93.0887,48.0075],[-93.0872,47.9932],[-93.088,47.9787],[-93.0809,47.9786],[-93.0809,47.967],[-93.0808,47.9647],[-93.0808,47.9525],[-93.0808,47.9504],[-93.0809,47.938],[-93.0809,47.9356],[-93.0809,47.9235],[-93.0809,47.9212],[-93.0809,47.9088],[-93.0809,47.9067],[-93.0808,47.8945],[-93.0808,47.8922],[-93.1015,47.8927],[-93.1232,47.893],[-93.1448,47.8928],[-93.1656,47.8931],[-93.1671,47.8932],[-93.1871,47.8931],[-93.1893,47.8931],[-93.2087,47.8933],[-93.2115,47.8934],[-93.2331,47.8937],[-93.2532,47.8936],[-93.2745,47.8938],[-93.2962,47.8939],[-93.3169,47.894],[-93.3392,47.8941],[-93.3603,47.8942],[-93.3809,47.8943],[-93.4024,47.8944],[-93.4235,47.8945],[-93.4442,47.8946],[-93.466,47.895],[-93.4874,47.8956],[-93.4892,47.8957],[-93.4933,47.8958],[-93.5085,47.8962],[-93.5105,47.8963],[-93.5297,47.8967],[-93.5303,47.8967],[-93.532,47.8968],[-93.5517,47.8973],[-93.5532,47.8974],[-93.5729,47.8981],[-93.5747,47.8982],[-93.5962,47.8978],[-93.5966,47.8978],[-93.6179,47.8977],[-93.6187,47.8977],[-93.6388,47.8977],[-93.6395,47.8976],[-93.6604,47.8976],[-93.6612,47.8976],[-93.6817,47.8976],[-93.6826,47.8976],[-93.7031,47.8976],[-93.7038,47.8976],[-93.7249,47.8975],[-93.7248,47.8989],[-93.7466,47.8989],[-93.768,47.8991],[-93.7758,47.8991],[-93.7758,47.899],[-93.776,47.8897],[-93.776,47.8842],[-93.7762,47.8753],[-93.7761,47.8697],[-93.7761,47.8607],[-93.7761,47.8553],[-93.7761,47.8464],[-93.7896,47.8465],[-93.7971,47.8466],[-93.8189,47.8467],[-93.8407,47.8468],[-93.8627,47.8469],[-93.8831,47.8471],[-93.9067,47.8471],[-93.9288,47.8475],[-93.9496,47.8475],[-93.9506,47.8475],[-93.971,47.8475],[-93.9725,47.8475],[-93.9927,47.8475],[-93.9942,47.8475],[-94.0141,47.8476],[-94.0161,47.8476],[-94.0375,47.8477],[-94.0591,47.8474],[-94.0807,47.8471],[-94.1022,47.8471],[-94.1239,47.8466],[-94.1448,47.8463],[-94.1657,47.8461],[-94.1822,47.8461],[-94.1871,47.846],[-94.2037,47.846],[-94.2086,47.846],[-94.2252,47.846],[-94.23,47.8461],[-94.2467,47.8462],[-94.2515,47.8462],[-94.2681,47.8462],[-94.2728,47.8462],[-94.2887,47.8462],[-94.3103,47.8458],[-94.3315,47.846],[-94.3532,47.8464],[-94.3747,47.8462],[-94.3964,47.8461],[-94.4185,47.8459],[-94.4186,47.86],[-94.4184,47.8744],[-94.418,47.8886],[-94.4177,47.9031],[-94.4176,47.9041],[-94.4175,47.9175],[-94.4174,47.9186],[-94.4175,47.9332],[-94.4174,47.9477],[-94.4172,47.9623],[-94.4173,47.9769],[-94.4176,47.9914],[-94.4177,48.006],[-94.4176,48.02],[-94.4236,48.0199],[-94.4241,48.0344],[-94.4246,48.0489],[-94.4247,48.0632],[-94.4234,48.0776],[-94.4231,48.092],[-94.4233,48.1059],[-94.4234,48.1204],[-94.4236,48.1348],[-94.4233,48.1491],[-94.4235,48.1637],[-94.4235,48.1781],[-94.4233,48.1923],[-94.4236,48.2067],[-94.4238,48.2212],[-94.4237,48.2356],[-94.4237,48.2504],[-94.424,48.2649],[-94.4243,48.2791],[-94.4244,48.2938],[-94.4246,48.3081],[-94.4248,48.3227],[-94.425,48.3372],[-94.4253,48.352],[-94.4252,48.3675],[-94.4288,48.3675],[-94.4289,48.3821],[-94.4293,48.3964],[-94.4294,48.411],[-94.4293,48.4254],[-94.4292,48.4399],[-94.4293,48.4543],[-94.4296,48.4688],[-94.4296,48.4832],[-94.4299,48.4977],[-94.4303,48.512],[-94.4303,48.5264],[-94.43,48.5409],[-94.4295,48.5554],[-94.4291,48.5698],[-94.4289,48.5844],[-94.4289,48.5988],[-94.4292,48.6133],[-94.4294,48.6276],[-94.4297,48.642],[-94.43,48.6564],[-94.4301,48.6708],[-94.43,48.6852],[-94.4299,48.6998],[-94.4299,48.7012]]],"type":"Polygon"},"id":"36","properties":{"Area":8167237870.91888,"CTYONLY_":5,"Code":"KOOC","LASTMOD":"1999-12-31T23:59:59Z","Name":"Koochiching","Perimiter":412897.43594},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=1&offset=0&filter=s_intersects(geom%2Cpoint(-94.4297%2048.642))","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=1&offset=0&filter=s_intersects(geom%2Cpoint(-94.4297%2048.642))","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":1,"numberReturned":1,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_text_subtract.json.txt b/msautotest/api/expected/ogcapi_cql2_text_subtract.json.txt new file mode 100644 index 0000000000..80ec975cd9 --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_text_subtract.json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 1 +OGC-NumberReturned: 1 + +{"features":[{"geometry":{"coordinates":[[[-96.4054,49.0001],[-96.4019,49.0001],[-96.3825,49.0001],[-96.3783,49.0001],[-96.3606,49.0001],[-96.3579,49.0001],[-96.3385,49.0001],[-96.3343,49.0001],[-96.3166,49.0001],[-96.3138,49.0001],[-96.2945,49.0001],[-96.2902,49.0001],[-96.2725,49.0001],[-96.2698,49.0001],[-96.2494,49.0001],[-96.2461,49.0001],[-96.2274,49.0001],[-96.2257,49.0001],[-96.2057,49.0001],[-96.2021,49.0001],[-96.1837,49.0],[-96.18,49.0],[-96.1617,49.0],[-96.1579,49.0],[-96.1401,49.0],[-96.1359,49.0],[-96.1176,49.0],[-96.1139,49.0],[-96.0957,49.0],[-96.0919,49.0],[-96.0738,49.0],[-96.07,49.0],[-96.0517,49.0],[-96.048,49.0],[-96.0298,49.0],[-96.026,49.0],[-96.0083,49.0],[-96.0045,49.0],[-95.9868,49.0],[-95.9784,49.0],[-95.9776,49.0],[-95.9755,49.0],[-95.9648,48.9999],[-95.9464,48.9999],[-95.943,48.9999],[-95.9225,48.9999],[-95.9211,48.9999],[-95.899,48.9998],[-95.883,48.9998],[-95.8771,48.9998],[-95.8564,48.9998],[-95.855,48.9998],[-95.8342,48.9998],[-95.8184,48.9997],[-95.8126,48.9997],[-95.7906,48.9997],[-95.7833,48.9997],[-95.7684,48.9997],[-95.7479,48.9996],[-95.7466,48.9996],[-95.7253,48.9996],[-95.7066,48.9996],[-95.7032,48.9996],[-95.681,48.9995],[-95.6654,48.9995],[-95.6596,48.9995],[-95.659,48.9995],[-95.6401,48.9995],[-95.6369,48.9995],[-95.6205,48.9994],[-95.615,48.9994],[-95.5948,48.9994],[-95.585,48.9994],[-95.573,48.9994],[-95.551,48.9993],[-95.5495,48.9993],[-95.5294,48.9993],[-95.5164,48.9993],[-95.5072,48.9993],[-95.4849,48.9992],[-95.4834,48.9992],[-95.4635,48.9992],[-95.4508,48.9992],[-95.4418,48.9992],[-95.4245,48.9991],[-95.4197,48.9991],[-95.3977,48.9991],[-95.3953,48.9991],[-95.3765,48.9991],[-95.3759,48.9991],[-95.3753,48.9991],[-95.3542,48.999],[-95.3513,48.999],[-95.3326,48.999],[-95.3286,48.999],[-95.3231,48.999],[-95.3224,48.9984],[-95.3204,48.9976],[-95.3202,48.9973],[-95.3204,48.9964],[-95.3206,48.9961],[-95.3201,48.9956],[-95.3197,48.9954],[-95.3191,48.9953],[-95.3187,48.9956],[-95.3182,48.996],[-95.3179,48.9961],[-95.3178,48.9961],[-95.3178,48.9958],[-95.3181,48.995],[-95.3191,48.9941],[-95.3204,48.9924],[-95.3206,48.9921],[-95.3224,48.9889],[-95.3227,48.9884],[-95.3242,48.9859],[-95.3245,48.985],[-95.3253,48.9832],[-95.3257,48.9814],[-95.3256,48.98],[-95.3255,48.9789],[-95.3257,48.9784],[-95.3253,48.976],[-95.325,48.9743],[-95.3249,48.9738],[-95.3248,48.9728],[-95.3247,48.972],[-95.3241,48.9703],[-95.3232,48.9692],[-95.3227,48.9685],[-95.3212,48.9672],[-95.3207,48.9669],[-95.3201,48.9648],[-95.3198,48.9643],[-95.3193,48.964],[-95.3193,48.9622],[-95.3202,48.9606],[-95.3206,48.9598],[-95.3206,48.9595],[-95.3206,48.959],[-95.3202,48.9581],[-95.3191,48.9569],[-95.3188,48.9562],[-95.3179,48.9559],[-95.3175,48.9552],[-95.3177,48.9545],[-95.3182,48.9535],[-95.3181,48.9531],[-95.3177,48.9525],[-95.3154,48.9513],[-95.3151,48.951],[-95.3141,48.9508],[-95.3131,48.9503],[-95.3125,48.9503],[-95.3123,48.9502],[-95.3119,48.9502],[-95.3119,48.9507],[-95.3129,48.9521],[-95.3129,48.9523],[-95.3126,48.9524],[-95.312,48.9524],[-95.3115,48.952],[-95.3108,48.9512],[-95.3104,48.951],[-95.3097,48.951],[-95.3089,48.9511],[-95.3079,48.9509],[-95.3061,48.9502],[-95.3052,48.9495],[-95.3046,48.9482],[-95.3046,48.947],[-95.305,48.9462],[-95.3053,48.9459],[-95.3061,48.9454],[-95.3068,48.9454],[-95.3069,48.9455],[-95.3069,48.9456],[-95.3063,48.9462],[-95.3062,48.9463],[-95.3061,48.9469],[-95.3062,48.9472],[-95.3062,48.9472],[-95.3071,48.9477],[-95.3081,48.948],[-95.3094,48.9481],[-95.3096,48.9482],[-95.3099,48.9484],[-95.31,48.9485],[-95.3103,48.9485],[-95.3104,48.9484],[-95.3103,48.948],[-95.3096,48.9478],[-95.3092,48.9477],[-95.3079,48.9474],[-95.3071,48.9469],[-95.3071,48.9466],[-95.3074,48.9465],[-95.3078,48.9466],[-95.3085,48.947],[-95.3086,48.9469],[-95.3086,48.9465],[-95.3088,48.9464],[-95.3095,48.9463],[-95.3102,48.9463],[-95.3114,48.9461],[-95.3131,48.946],[-95.3141,48.9457],[-95.3148,48.9452],[-95.3154,48.9448],[-95.3168,48.9431],[-95.3181,48.9421],[-95.3189,48.9419],[-95.3219,48.9412],[-95.3225,48.9409],[-95.3228,48.9403],[-95.3231,48.9389],[-95.3229,48.9373],[-95.3225,48.9358],[-95.3223,48.9355],[-95.3228,48.9344],[-95.3222,48.9327],[-95.3209,48.9307],[-95.3208,48.9305],[-95.3195,48.9285],[-95.3168,48.9245],[-95.315,48.9222],[-95.3141,48.921],[-95.3132,48.9198],[-95.3126,48.919],[-95.3119,48.9178],[-95.3115,48.9172],[-95.3109,48.9163],[-95.3102,48.9155],[-95.3093,48.9149],[-95.3092,48.9149],[-95.3085,48.9146],[-95.3078,48.9141],[-95.3074,48.9135],[-95.3064,48.9129],[-95.3061,48.9128],[-95.3059,48.9127],[-95.3043,48.9119],[-95.3038,48.9114],[-95.3027,48.91],[-95.3017,48.9093],[-95.2999,48.9086],[-95.2978,48.9083],[-95.2973,48.9081],[-95.2973,48.908],[-95.2973,48.9077],[-95.2976,48.9074],[-95.2977,48.9073],[-95.2978,48.9073],[-95.2978,48.9072],[-95.2978,48.9072],[-95.2979,48.9072],[-95.2979,48.9072],[-95.2979,48.9071],[-95.298,48.9071],[-95.298,48.9071],[-95.298,48.9071],[-95.2981,48.907],[-95.2982,48.9068],[-95.2983,48.9068],[-95.2985,48.9065],[-95.2985,48.9064],[-95.2986,48.9063],[-95.2988,48.906],[-95.2989,48.906],[-95.2991,48.9057],[-95.2992,48.9055],[-95.2994,48.9053],[-95.2996,48.9051],[-95.2997,48.905],[-95.2999,48.9048],[-95.2999,48.9048],[-95.2999,48.9048],[-95.3,48.9047],[-95.3,48.9047],[-95.3001,48.9047],[-95.3001,48.9046],[-95.3002,48.9045],[-95.3005,48.904],[-95.2993,48.9035],[-95.2983,48.9028],[-95.298,48.9027],[-95.2976,48.9026],[-95.2967,48.9027],[-95.2949,48.9028],[-95.2941,48.9027],[-95.2937,48.9023],[-95.2935,48.902],[-95.2927,48.9019],[-95.2914,48.9019],[-95.2909,48.9017],[-95.2908,48.9016],[-95.2907,48.9014],[-95.2906,48.9011],[-95.2911,48.9008],[-95.2911,48.9006],[-95.2901,48.9003],[-95.2896,48.9],[-95.289,48.8994],[-95.2882,48.8981],[-95.2879,48.8979],[-95.2872,48.8977],[-95.287,48.8976],[-95.2865,48.8975],[-95.2861,48.8976],[-95.2853,48.8977],[-95.2839,48.8975],[-95.2813,48.8967],[-95.2803,48.8965],[-95.2796,48.8962],[-95.279,48.8957],[-95.2782,48.8956],[-95.2773,48.8957],[-95.277,48.8958],[-95.2765,48.8962],[-95.2763,48.8963],[-95.2759,48.8962],[-95.2755,48.8959],[-95.2749,48.8956],[-95.2748,48.8951],[-95.2753,48.8943],[-95.2751,48.8938],[-95.2745,48.8931],[-95.2724,48.8921],[-95.2713,48.8915],[-95.268,48.8905],[-95.2677,48.8903],[-95.2674,48.89],[-95.2666,48.8894],[-95.2654,48.8888],[-95.265,48.8886],[-95.2646,48.8885],[-95.2639,48.8883],[-95.2635,48.888],[-95.2627,48.8877],[-95.2585,48.8867],[-95.2585,48.8867],[-95.257,48.8858],[-95.256,48.885],[-95.2548,48.8845],[-95.2517,48.8839],[-95.2507,48.8836],[-95.2502,48.8835],[-95.2496,48.8834],[-95.2485,48.8832],[-95.248,48.8836],[-95.2472,48.8835],[-95.2458,48.8829],[-95.2439,48.8823],[-95.2429,48.8822],[-95.2429,48.8822],[-95.2423,48.8821],[-95.2407,48.8821],[-95.2391,48.8819],[-95.2381,48.8817],[-95.2356,48.8815],[-95.2335,48.8814],[-95.231,48.8814],[-95.2287,48.8815],[-95.2265,48.8816],[-95.2252,48.8819],[-95.2212,48.883],[-95.2208,48.8831],[-95.2207,48.8831],[-95.22,48.8831],[-95.2193,48.8832],[-95.2188,48.8835],[-95.217,48.8835],[-95.2159,48.8839],[-95.2151,48.884],[-95.2144,48.8843],[-95.2122,48.8842],[-95.2117,48.8847],[-95.2115,48.8847],[-95.2112,48.8848],[-95.2085,48.8846],[-95.2059,48.8848],[-95.2024,48.8852],[-95.2009,48.8855],[-95.2005,48.8856],[-95.1986,48.8855],[-95.1956,48.8862],[-95.1924,48.8865],[-95.1919,48.8866],[-95.1913,48.8868],[-95.1901,48.887],[-95.1889,48.8873],[-95.1877,48.8874],[-95.1863,48.8877],[-95.1851,48.8882],[-95.1819,48.8888],[-95.1797,48.889],[-95.1791,48.889],[-95.1764,48.8893],[-95.173,48.8897],[-95.1701,48.8902],[-95.1674,48.8907],[-95.1648,48.8913],[-95.1641,48.8917],[-95.1618,48.892],[-95.1602,48.892],[-95.1579,48.8919],[-95.1564,48.8919],[-95.1555,48.892],[-95.1528,48.8921],[-95.1508,48.8922],[-95.1483,48.8923],[-95.1469,48.8927],[-95.1459,48.8929],[-95.1438,48.8934],[-95.1436,48.8937],[-95.1404,48.8943],[-95.1381,48.8949],[-95.1355,48.8959],[-95.1351,48.8963],[-95.1348,48.8963],[-95.1343,48.8963],[-95.1337,48.8969],[-95.1322,48.8973],[-95.1312,48.8975],[-95.1252,48.8998],[-95.1239,48.9001],[-95.1233,48.9004],[-95.1228,48.9006],[-95.1214,48.9013],[-95.121,48.9016],[-95.1205,48.9017],[-95.1204,48.9019],[-95.1182,48.9029],[-95.1163,48.9037],[-95.1151,48.9046],[-95.1144,48.9052],[-95.114,48.9061],[-95.1141,48.9064],[-95.1137,48.9069],[-95.1132,48.9071],[-95.113,48.9072],[-95.1126,48.9073],[-95.1107,48.9082],[-95.1096,48.9089],[-95.108,48.9099],[-95.1056,48.9113],[-95.1042,48.9121],[-95.1032,48.9127],[-95.102,48.9132],[-95.1008,48.9142],[-95.0981,48.9159],[-95.098,48.916],[-95.0975,48.9164],[-95.0971,48.9172],[-95.097,48.9176],[-95.0961,48.9181],[-95.0946,48.9191],[-95.0944,48.9193],[-95.0927,48.9204],[-95.0919,48.9207],[-95.0914,48.9208],[-95.0914,48.916],[-95.0912,48.9014],[-95.0911,48.8869],[-95.0908,48.8724],[-95.0908,48.858],[-95.0907,48.8436],[-95.0908,48.8291],[-95.0909,48.8147],[-95.0903,48.8],[-95.0903,48.7855],[-95.0903,48.7711],[-95.0901,48.7566],[-95.0901,48.7421],[-95.0899,48.7277],[-95.0898,48.713],[-95.1046,48.7129],[-95.1104,48.7129],[-95.1119,48.7129],[-95.1259,48.7129],[-95.1297,48.713],[-95.1333,48.713],[-95.1477,48.7129],[-95.1554,48.7129],[-95.1697,48.7129],[-95.1773,48.713],[-95.1917,48.713],[-95.1991,48.713],[-95.2112,48.713],[-95.2206,48.713],[-95.2331,48.713],[-95.2427,48.713],[-95.255,48.713],[-95.2645,48.713],[-95.2656,48.713],[-95.2767,48.713],[-95.2866,48.713],[-95.299,48.713],[-95.3051,48.713],[-95.3084,48.713],[-95.3205,48.713],[-95.3302,48.713],[-95.3425,48.7131],[-95.3425,48.6995],[-95.3424,48.6849],[-95.3423,48.6705],[-95.3424,48.6561],[-95.3425,48.6415],[-95.3426,48.6271],[-95.3424,48.6127],[-95.3426,48.5979],[-95.3423,48.5836],[-95.3423,48.5691],[-95.3424,48.5548],[-95.3425,48.5402],[-95.3628,48.5404],[-95.364,48.5403],[-95.3844,48.5402],[-95.386,48.5402],[-95.4061,48.5402],[-95.4078,48.5402],[-95.4279,48.54],[-95.4297,48.5399],[-95.4494,48.5399],[-95.4513,48.5399],[-95.4712,48.5396],[-95.4726,48.5396],[-95.493,48.5392],[-95.495,48.5392],[-95.5143,48.539],[-95.5163,48.539],[-95.5365,48.5389],[-95.5383,48.5389],[-95.558,48.5388],[-95.5603,48.5388],[-95.5801,48.5387],[-95.5821,48.5387],[-95.6023,48.5389],[-95.6232,48.5391],[-95.6447,48.5393],[-95.6666,48.5394],[-95.6886,48.5395],[-95.7102,48.5395],[-95.7322,48.54],[-95.7539,48.5404],[-95.7758,48.5406],[-95.7976,48.5405],[-95.8192,48.5404],[-95.8411,48.5406],[-95.8621,48.5414],[-95.8829,48.5419],[-95.8851,48.542],[-95.8986,48.5421],[-95.9046,48.5422],[-95.9064,48.5422],[-95.9269,48.5421],[-95.9486,48.5425],[-95.9498,48.5425],[-95.9704,48.543],[-95.9936,48.5435],[-96.0157,48.5437],[-96.0374,48.5438],[-96.0592,48.5437],[-96.0812,48.5436],[-96.1026,48.5438],[-96.1264,48.5439],[-96.1486,48.5442],[-96.1702,48.5445],[-96.1921,48.5446],[-96.2141,48.5449],[-96.2358,48.5452],[-96.2576,48.545],[-96.2794,48.5449],[-96.301,48.5448],[-96.3231,48.5446],[-96.3448,48.5444],[-96.3667,48.5443],[-96.3882,48.5442],[-96.3879,48.5588],[-96.3882,48.5733],[-96.3884,48.5877],[-96.3891,48.6024],[-96.389,48.6165],[-96.388,48.6313],[-96.3879,48.6454],[-96.3877,48.6599],[-96.3871,48.6741],[-96.3874,48.6887],[-96.3866,48.703],[-96.3873,48.7172],[-96.388,48.7172],[-96.4049,48.7172],[-96.4048,48.7318],[-96.4048,48.7465],[-96.4047,48.7607],[-96.4045,48.7758],[-96.4042,48.7903],[-96.4042,48.8048],[-96.4042,48.8198],[-96.4043,48.8343],[-96.4045,48.8491],[-96.4047,48.8635],[-96.405,48.878],[-96.405,48.8926],[-96.4053,48.9068],[-96.4053,48.9081],[-96.4053,48.9137],[-96.4054,48.9214],[-96.4054,48.9225],[-96.4053,48.936],[-96.4053,48.9371],[-96.4053,48.9504],[-96.4053,48.9515],[-96.4053,48.9648],[-96.4053,48.9658],[-96.4053,48.9705],[-96.4054,48.9793],[-96.4054,48.9803],[-96.4054,48.994],[-96.4054,48.9947],[-96.4054,49.0001]]],"type":"Polygon"},"id":"68","properties":{"Area":4347098503.12714,"CTYONLY_":4,"Code":"ROSE","LASTMOD":"2001-04-12T09:32:44Z","Name":"Roseau","Perimiter":302590.75293},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&filter=CTYONLY_%3D5-1","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&filter=CTYONLY_%3D5-1","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":1,"numberReturned":1,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_text_syntax_error.json.txt b/msautotest/api/expected/ogcapi_cql2_text_syntax_error.json.txt new file mode 100644 index 0000000000..f9ac30a9b6 --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_text_syntax_error.json.txt @@ -0,0 +1,4 @@ +Content-Type: application/json +Status: 400 + +{"code":"InvalidParameterValue","description":"Cannot parse filter: CQL2Text Expression Parsing Error: syntax error, unexpected end of string. Occurred around :\nArea=\n ^"} diff --git a/msautotest/api/expected/ogcapi_cql2_text_timestamp.json.txt b/msautotest/api/expected/ogcapi_cql2_text_timestamp.json.txt new file mode 100644 index 0000000000..bdf641ccea --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_text_timestamp.json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 8 +OGC-NumberReturned: 8 + +{"features":[{"geometry":{"coordinates":[[[-91.0311,48.1889],[-91.0319,48.1804],[-91.0316,48.1652],[-91.0311,48.1507],[-91.0313,48.1362],[-91.0315,48.1222],[-91.0315,48.1075],[-91.0316,48.093],[-91.0316,48.0788],[-91.0314,48.0641],[-91.0243,48.0639],[-91.0236,48.0474],[-91.0243,48.0329],[-91.0241,48.0183],[-91.0245,48.0039],[-91.0246,47.9895],[-91.0252,47.9755],[-91.0256,47.9611],[-91.026,47.9465],[-91.0265,47.932],[-91.0265,47.9175],[-91.0266,47.9029],[-91.0266,47.8883],[-91.0207,47.8882],[-91.0212,47.8758],[-91.0213,47.875],[-91.0212,47.8616],[-91.0212,47.8605],[-91.0212,47.847],[-91.0212,47.846],[-91.0212,47.8327],[-91.0212,47.8316],[-91.0215,47.8182],[-91.0215,47.8171],[-91.0218,47.804],[-91.0218,47.8033],[-91.0217,47.7896],[-91.0217,47.7886],[-91.0217,47.7749],[-91.0217,47.7739],[-91.0216,47.7604],[-91.0216,47.7594],[-91.0214,47.7457],[-91.0217,47.7313],[-91.0217,47.7302],[-91.0216,47.7158],[-91.0222,47.7028],[-91.0225,47.6883],[-91.0226,47.6739],[-91.0222,47.6598],[-91.0222,47.6453],[-91.022,47.6308],[-91.0222,47.6163],[-91.0228,47.6019],[-91.0225,47.5874],[-91.0225,47.5729],[-91.0225,47.5587],[-91.0226,47.5443],[-91.0225,47.5299],[-91.0226,47.5154],[-91.0228,47.5009],[-91.0234,47.4865],[-91.0231,47.4725],[-91.023,47.4651],[-91.023,47.4651],[-91.0237,47.4647],[-91.0237,47.4646],[-91.0237,47.4646],[-91.0238,47.4645],[-91.0239,47.4644],[-91.024,47.4643],[-91.0241,47.4643],[-91.0242,47.4643],[-91.0243,47.4642],[-91.0244,47.4641],[-91.0246,47.464],[-91.0247,47.4639],[-91.0248,47.4638],[-91.0249,47.4637],[-91.0251,47.4636],[-91.0253,47.4635],[-91.0254,47.4634],[-91.0256,47.4633],[-91.0257,47.4632],[-91.0259,47.4631],[-91.0261,47.463],[-91.0262,47.4629],[-91.0264,47.4628],[-91.0265,47.4627],[-91.0267,47.4627],[-91.0267,47.4626],[-91.0268,47.4627],[-91.027,47.4626],[-91.0271,47.4626],[-91.0271,47.4626],[-91.0272,47.4624],[-91.0275,47.4623],[-91.0276,47.4623],[-91.0278,47.4623],[-91.028,47.4622],[-91.0281,47.4622],[-91.0281,47.4621],[-91.0281,47.462],[-91.0283,47.462],[-91.0284,47.462],[-91.0285,47.462],[-91.0285,47.462],[-91.0286,47.4619],[-91.0287,47.4617],[-91.0287,47.4616],[-91.0289,47.4616],[-91.029,47.4615],[-91.0292,47.4613],[-91.0292,47.4613],[-91.0292,47.4612],[-91.0293,47.4611],[-91.0293,47.461],[-91.0295,47.461],[-91.0296,47.4609],[-91.0296,47.4608],[-91.0297,47.4607],[-91.0298,47.4607],[-91.0299,47.4606],[-91.0302,47.4605],[-91.0303,47.4606],[-91.0303,47.4607],[-91.0304,47.4607],[-91.0306,47.4605],[-91.0308,47.4604],[-91.031,47.4601],[-91.0312,47.4599],[-91.0314,47.4598],[-91.0315,47.4597],[-91.0317,47.4596],[-91.0319,47.4595],[-91.032,47.4593],[-91.0321,47.4592],[-91.0322,47.4591],[-91.0323,47.459],[-91.0325,47.4589],[-91.0329,47.4587],[-91.033,47.4586],[-91.033,47.4585],[-91.033,47.4585],[-91.033,47.4584],[-91.033,47.4583],[-91.0333,47.4582],[-91.0337,47.458],[-91.034,47.4579],[-91.034,47.4578],[-91.0342,47.4578],[-91.0346,47.4577],[-91.035,47.4576],[-91.0355,47.4575],[-91.0359,47.4574],[-91.0362,47.4573],[-91.0364,47.4572],[-91.0367,47.4572],[-91.0369,47.4572],[-91.037,47.4572],[-91.0373,47.4571],[-91.0377,47.457],[-91.0381,47.4568],[-91.0385,47.4567],[-91.0389,47.4567],[-91.0394,47.4567],[-91.0395,47.4568],[-91.0398,47.4569],[-91.0405,47.457],[-91.0413,47.4572],[-91.0424,47.4573],[-91.0433,47.4573],[-91.0439,47.4574],[-91.044,47.4575],[-91.0441,47.4575],[-91.0443,47.4575],[-91.0448,47.4574],[-91.0453,47.4572],[-91.0458,47.457],[-91.0462,47.4567],[-91.0468,47.4564],[-91.0473,47.4559],[-91.0476,47.4557],[-91.0479,47.4555],[-91.048,47.4553],[-91.0486,47.4547],[-91.0489,47.4542],[-91.0492,47.4537],[-91.0496,47.4531],[-91.0496,47.4527],[-91.0496,47.4524],[-91.0495,47.4523],[-91.0493,47.452],[-91.0491,47.4519],[-91.049,47.4519],[-91.049,47.4519],[-91.049,47.4519],[-91.049,47.452],[-91.049,47.4521],[-91.0489,47.452],[-91.0488,47.4521],[-91.0487,47.452],[-91.0487,47.452],[-91.0486,47.452],[-91.0486,47.4518],[-91.0487,47.4517],[-91.0489,47.4516],[-91.0491,47.4514],[-91.0492,47.4513],[-91.0493,47.4513],[-91.0494,47.4514],[-91.0496,47.4514],[-91.05,47.4513],[-91.0507,47.4512],[-91.0512,47.4511],[-91.0517,47.4508],[-91.0518,47.4507],[-91.0518,47.4505],[-91.0518,47.4503],[-91.0519,47.4501],[-91.0521,47.45],[-91.0522,47.4499],[-91.0524,47.4498],[-91.0524,47.4497],[-91.0524,47.4496],[-91.0523,47.4495],[-91.0523,47.4494],[-91.0524,47.4493],[-91.0525,47.4493],[-91.0526,47.4493],[-91.0528,47.4494],[-91.0528,47.4494],[-91.053,47.4492],[-91.0533,47.4489],[-91.0535,47.4487],[-91.0536,47.4486],[-91.0538,47.4485],[-91.0538,47.4484],[-91.0538,47.4483],[-91.0537,47.4482],[-91.0538,47.448],[-91.054,47.4479],[-91.0543,47.4478],[-91.0544,47.4476],[-91.0546,47.4475],[-91.0548,47.4473],[-91.0551,47.4473],[-91.0554,47.4471],[-91.0557,47.4469],[-91.056,47.4466],[-91.0562,47.4464],[-91.0565,47.4462],[-91.0568,47.446],[-91.0571,47.4459],[-91.0573,47.4458],[-91.0574,47.4457],[-91.0577,47.4456],[-91.058,47.4455],[-91.0581,47.4454],[-91.0582,47.4452],[-91.0585,47.445],[-91.0587,47.4447],[-91.0589,47.4444],[-91.0591,47.4442],[-91.0595,47.4439],[-91.0598,47.4437],[-91.0598,47.4437],[-91.0599,47.4438],[-91.0601,47.4439],[-91.0604,47.4439],[-91.0608,47.4438],[-91.0611,47.4437],[-91.0613,47.4436],[-91.0615,47.4435],[-91.0617,47.4435],[-91.062,47.4435],[-91.0622,47.4435],[-91.0626,47.4433],[-91.0626,47.4433],[-91.0629,47.4432],[-91.0632,47.4431],[-91.0634,47.4431],[-91.0636,47.4432],[-91.0639,47.4433],[-91.0641,47.4433],[-91.0641,47.4433],[-91.0642,47.4431],[-91.0643,47.443],[-91.0643,47.4428],[-91.0641,47.4427],[-91.064,47.4427],[-91.0638,47.4428],[-91.0637,47.4427],[-91.0637,47.4427],[-91.0637,47.4424],[-91.0639,47.4423],[-91.0639,47.4422],[-91.0638,47.4419],[-91.0638,47.4418],[-91.0639,47.4417],[-91.0641,47.4417],[-91.0643,47.4417],[-91.0649,47.4416],[-91.0651,47.4415],[-91.0651,47.4413],[-91.0651,47.441],[-91.065,47.4409],[-91.0648,47.4407],[-91.0649,47.4406],[-91.065,47.4405],[-91.0652,47.4404],[-91.0653,47.4403],[-91.0653,47.4403],[-91.0655,47.4402],[-91.0656,47.4402],[-91.0656,47.4399],[-91.0657,47.4397],[-91.0661,47.4394],[-91.0662,47.4394],[-91.0664,47.4393],[-91.0665,47.4392],[-91.0664,47.4391],[-91.0663,47.4391],[-91.0662,47.439],[-91.0663,47.4389],[-91.0665,47.4389],[-91.0667,47.4387],[-91.0668,47.4386],[-91.067,47.4384],[-91.0671,47.4384],[-91.0671,47.4385],[-91.0671,47.4386],[-91.067,47.4387],[-91.0671,47.4388],[-91.0673,47.4388],[-91.0676,47.4388],[-91.0678,47.4386],[-91.0679,47.4385],[-91.0682,47.4384],[-91.0684,47.4383],[-91.0686,47.4381],[-91.0689,47.4378],[-91.0689,47.4374],[-91.0689,47.4373],[-91.0686,47.4373],[-91.0685,47.4373],[-91.0684,47.4372],[-91.0684,47.4371],[-91.0685,47.4369],[-91.0687,47.4368],[-91.069,47.4367],[-91.0694,47.4364],[-91.0696,47.4361],[-91.0698,47.436],[-91.07,47.4359],[-91.0701,47.4358],[-91.0704,47.4355],[-91.0706,47.4351],[-91.0706,47.435],[-91.0707,47.4347],[-91.0707,47.4345],[-91.0708,47.4343],[-91.0708,47.4341],[-91.0707,47.4339],[-91.0707,47.4338],[-91.0708,47.4337],[-91.071,47.4335],[-91.071,47.4334],[-91.0712,47.4332],[-91.0714,47.4331],[-91.0716,47.4331],[-91.0718,47.4332],[-91.0718,47.4332],[-91.0719,47.4333],[-91.0721,47.4333],[-91.0723,47.4333],[-91.0725,47.4332],[-91.0727,47.4332],[-91.0729,47.433],[-91.0729,47.433],[-91.0728,47.4329],[-91.0727,47.4328],[-91.0727,47.4327],[-91.0727,47.4325],[-91.0729,47.4323],[-91.0732,47.4322],[-91.0735,47.4321],[-91.0738,47.4319],[-91.0741,47.4317],[-91.0744,47.4315],[-91.0746,47.4313],[-91.0748,47.4311],[-91.0748,47.4309],[-91.0748,47.4307],[-91.0747,47.4306],[-91.0746,47.4305],[-91.0744,47.4305],[-91.0742,47.4305],[-91.0742,47.4304],[-91.0743,47.4303],[-91.0744,47.4301],[-91.0746,47.4299],[-91.0747,47.4298],[-91.0747,47.4298],[-91.0747,47.4297],[-91.0746,47.4296],[-91.0745,47.4295],[-91.0746,47.4294],[-91.0747,47.4294],[-91.0748,47.4294],[-91.0749,47.4294],[-91.0751,47.4294],[-91.0752,47.4293],[-91.0753,47.4292],[-91.0756,47.4291],[-91.0757,47.4291],[-91.0759,47.4292],[-91.0762,47.4292],[-91.0766,47.4291],[-91.0773,47.429],[-91.0779,47.4288],[-91.0784,47.4286],[-91.0787,47.4284],[-91.079,47.4283],[-91.0793,47.428],[-91.0797,47.4278],[-91.0801,47.4275],[-91.0806,47.4272],[-91.081,47.4269],[-91.0814,47.4266],[-91.0818,47.4263],[-91.0823,47.4261],[-91.0826,47.4258],[-91.083,47.4255],[-91.0834,47.4253],[-91.0837,47.4251],[-91.0841,47.4248],[-91.0843,47.4245],[-91.0845,47.4243],[-91.0847,47.4241],[-91.085,47.4241],[-91.0852,47.4241],[-91.0854,47.424],[-91.0855,47.424],[-91.0857,47.4238],[-91.086,47.4236],[-91.0862,47.4235],[-91.0863,47.4235],[-91.0864,47.4234],[-91.0867,47.4233],[-91.0869,47.4233],[-91.0871,47.4233],[-91.0872,47.4231],[-91.0873,47.4229],[-91.0874,47.4227],[-91.0875,47.4226],[-91.0876,47.4225],[-91.0879,47.4223],[-91.0882,47.4222],[-91.0883,47.4222],[-91.0884,47.4222],[-91.0887,47.4221],[-91.0888,47.4221],[-91.0889,47.422],[-91.089,47.4219],[-91.0889,47.4218],[-91.0888,47.4217],[-91.0887,47.4217],[-91.0886,47.4216],[-91.0886,47.4215],[-91.0887,47.4213],[-91.089,47.4211],[-91.0895,47.4208],[-91.0896,47.4207],[-91.0898,47.4207],[-91.0899,47.4206],[-91.0901,47.4206],[-91.0903,47.4206],[-91.0903,47.4205],[-91.0904,47.4203],[-91.0906,47.4201],[-91.0907,47.4199],[-91.0908,47.4196],[-91.0909,47.4193],[-91.091,47.4191],[-91.0911,47.4189],[-91.0913,47.4186],[-91.0915,47.4184],[-91.0918,47.4182],[-91.0921,47.4179],[-91.0923,47.4176],[-91.0925,47.4174],[-91.0929,47.4172],[-91.0935,47.4167],[-91.0939,47.4164],[-91.0944,47.4161],[-91.0947,47.4158],[-91.095,47.4156],[-91.0952,47.4153],[-91.0952,47.4153],[-91.0954,47.415],[-91.0956,47.4147],[-91.0957,47.4145],[-91.096,47.4143],[-91.0963,47.414],[-91.0967,47.4139],[-91.0971,47.4139],[-91.0974,47.414],[-91.0975,47.414],[-91.0977,47.4142],[-91.098,47.4144],[-91.0982,47.4145],[-91.0984,47.4146],[-91.0985,47.4147],[-91.0988,47.4146],[-91.0992,47.4145],[-91.0994,47.4145],[-91.0997,47.4143],[-91.0999,47.4142],[-91.1002,47.414],[-91.1006,47.4138],[-91.1007,47.4137],[-91.101,47.4134],[-91.1012,47.4132],[-91.1015,47.413],[-91.1019,47.4127],[-91.1023,47.4125],[-91.1027,47.4123],[-91.1032,47.4122],[-91.1036,47.4122],[-91.104,47.4121],[-91.1044,47.4121],[-91.1053,47.4121],[-91.1057,47.4121],[-91.106,47.412],[-91.1063,47.4119],[-91.1066,47.4117],[-91.1069,47.4115],[-91.1071,47.4112],[-91.1075,47.411],[-91.1076,47.411],[-91.1078,47.4108],[-91.1082,47.4107],[-91.1087,47.4105],[-91.1091,47.4103],[-91.1095,47.41],[-91.1099,47.4098],[-91.1103,47.4095],[-91.1107,47.4093],[-91.1113,47.409],[-91.1118,47.4087],[-91.1123,47.4084],[-91.1125,47.4083],[-91.1127,47.4081],[-91.1129,47.4079],[-91.1132,47.4077],[-91.1135,47.4074],[-91.1138,47.4071],[-91.114,47.4069],[-91.1144,47.4066],[-91.1149,47.4063],[-91.1154,47.406],[-91.1157,47.4058],[-91.116,47.4057],[-91.1163,47.4055],[-91.1165,47.4055],[-91.1168,47.4056],[-91.1171,47.4055],[-91.1174,47.4054],[-91.1178,47.4053],[-91.1181,47.4052],[-91.1185,47.405],[-91.1189,47.4048],[-91.1193,47.4046],[-91.1196,47.4046],[-91.12,47.4046],[-91.1202,47.4046],[-91.1204,47.4044],[-91.1207,47.4043],[-91.1209,47.4042],[-91.121,47.404],[-91.1211,47.4039],[-91.1214,47.4037],[-91.1218,47.4035],[-91.1221,47.4034],[-91.1225,47.4033],[-91.1228,47.4031],[-91.123,47.4029],[-91.1233,47.4028],[-91.1234,47.4026],[-91.1236,47.4025],[-91.1237,47.4024],[-91.124,47.4023],[-91.1242,47.4021],[-91.1244,47.4019],[-91.1247,47.4017],[-91.1249,47.4015],[-91.1251,47.4013],[-91.1254,47.401],[-91.1255,47.4009],[-91.1258,47.4007],[-91.1259,47.4006],[-91.126,47.4006],[-91.1262,47.4006],[-91.1263,47.4006],[-91.1264,47.4006],[-91.1266,47.4005],[-91.1267,47.4004],[-91.1267,47.4002],[-91.1268,47.4002],[-91.1271,47.4001],[-91.1275,47.4],[-91.1279,47.3997],[-91.1281,47.3996],[-91.1282,47.3996],[-91.1282,47.3995],[-91.1283,47.3994],[-91.1284,47.3994],[-91.1284,47.399],[-91.1285,47.3988],[-91.1285,47.3988],[-91.1287,47.3988],[-91.1288,47.3988],[-91.1289,47.3987],[-91.129,47.3984],[-91.1291,47.3983],[-91.1291,47.3982],[-91.1287,47.3979],[-91.1281,47.3977],[-91.128,47.3976],[-91.128,47.3976],[-91.128,47.3974],[-91.1281,47.3973],[-91.1281,47.3973],[-91.1282,47.3974],[-91.1282,47.3974],[-91.1283,47.3974],[-91.1283,47.3974],[-91.1284,47.3973],[-91.1286,47.397],[-91.1287,47.3969],[-91.1289,47.3967],[-91.1292,47.3965],[-91.1293,47.3964],[-91.1293,47.3964],[-91.1294,47.3962],[-91.1296,47.3959],[-91.1297,47.3957],[-91.1298,47.3956],[-91.1299,47.3956],[-91.1301,47.3956],[-91.1303,47.3957],[-91.1304,47.3956],[-91.1304,47.3953],[-91.1303,47.3949],[-91.1305,47.3948],[-91.1306,47.3947],[-91.1308,47.394],[-91.1308,47.3939],[-91.1306,47.3938],[-91.1305,47.3938],[-91.1303,47.3937],[-91.1303,47.3937],[-91.1303,47.3936],[-91.1304,47.3936],[-91.1305,47.3936],[-91.1308,47.3937],[-91.1309,47.3937],[-91.131,47.3936],[-91.1312,47.3935],[-91.1313,47.3934],[-91.1313,47.3934],[-91.1316,47.3934],[-91.1316,47.3934],[-91.1317,47.3934],[-91.1317,47.3934],[-91.1317,47.3935],[-91.1316,47.3935],[-91.1318,47.3936],[-91.1319,47.3938],[-91.1319,47.3938],[-91.1322,47.3939],[-91.1326,47.3939],[-91.1327,47.3939],[-91.1329,47.3938],[-91.1332,47.3939],[-91.1334,47.3938],[-91.1338,47.3936],[-91.1343,47.3933],[-91.1345,47.3932],[-91.1348,47.3931],[-91.1352,47.3928],[-91.1353,47.3927],[-91.1354,47.3926],[-91.1358,47.3926],[-91.1361,47.3924],[-91.1362,47.3923],[-91.1363,47.3922],[-91.1363,47.392],[-91.1361,47.3918],[-91.1362,47.3917],[-91.1363,47.3916],[-91.1367,47.3914],[-91.1371,47.3914],[-91.1375,47.3913],[-91.1378,47.3911],[-91.1381,47.391],[-91.1384,47.3909],[-91.1385,47.3907],[-91.1385,47.3906],[-91.1381,47.3902],[-91.1381,47.3901],[-91.1382,47.3899],[-91.1382,47.3898],[-91.1381,47.3897],[-91.1379,47.3895],[-91.1378,47.3894],[-91.1378,47.3894],[-91.1378,47.3894],[-91.1383,47.3893],[-91.1384,47.3892],[-91.1384,47.3891],[-91.1384,47.389],[-91.1384,47.389],[-91.1384,47.389],[-91.1385,47.389],[-91.1386,47.3891],[-91.1388,47.3891],[-91.1391,47.389],[-91.1398,47.389],[-91.1399,47.389],[-91.1403,47.3888],[-91.1407,47.3888],[-91.1409,47.3887],[-91.1412,47.3886],[-91.1414,47.3884],[-91.1416,47.3883],[-91.1416,47.388],[-91.1416,47.3879],[-91.1417,47.3879],[-91.1419,47.3879],[-91.1419,47.3879],[-91.142,47.388],[-91.142,47.388],[-91.1421,47.3879],[-91.1423,47.3878],[-91.1424,47.3878],[-91.1424,47.3876],[-91.1426,47.3875],[-91.1426,47.3874],[-91.1426,47.3874],[-91.1425,47.3873],[-91.1424,47.3872],[-91.1423,47.3871],[-91.1422,47.3868],[-91.1422,47.3865],[-91.1422,47.3865],[-91.1422,47.3864],[-91.1426,47.3859],[-91.1427,47.3857],[-91.1427,47.3854],[-91.1427,47.3854],[-91.1428,47.3853],[-91.143,47.3852],[-91.1433,47.3849],[-91.1435,47.3847],[-91.1437,47.3844],[-91.1438,47.3843],[-91.1438,47.3843],[-91.144,47.3843],[-91.1441,47.3842],[-91.1441,47.3841],[-91.1442,47.3839],[-91.1443,47.3837],[-91.1445,47.3835],[-91.1451,47.3831],[-91.1453,47.383],[-91.1456,47.3829],[-91.1458,47.3828],[-91.1461,47.3825],[-91.1463,47.3822],[-91.1466,47.3819],[-91.1466,47.3818],[-91.1466,47.3817],[-91.1466,47.3817],[-91.1466,47.3817],[-91.1466,47.3816],[-91.1468,47.3815],[-91.1469,47.3815],[-91.1473,47.3815],[-91.1474,47.3815],[-91.1475,47.3814],[-91.1477,47.3812],[-91.148,47.3812],[-91.1481,47.3811],[-91.1481,47.3811],[-91.1481,47.381],[-91.148,47.3809],[-91.1481,47.3807],[-91.1482,47.3806],[-91.1487,47.3806],[-91.1488,47.3806],[-91.15,47.3798],[-91.15,47.3798],[-91.15,47.3798],[-91.1504,47.3796],[-91.1507,47.3795],[-91.1508,47.3795],[-91.1508,47.3795],[-91.1509,47.3795],[-91.1514,47.3796],[-91.1518,47.3797],[-91.1524,47.3798],[-91.1529,47.38],[-91.1533,47.38],[-91.1535,47.3801],[-91.1537,47.3802],[-91.1541,47.3802],[-91.1546,47.3802],[-91.1551,47.3801],[-91.1552,47.3801],[-91.1556,47.3799],[-91.1558,47.3798],[-91.156,47.3796],[-91.1564,47.3792],[-91.1564,47.3791],[-91.1565,47.3789],[-91.1566,47.3788],[-91.1566,47.3784],[-91.1567,47.3783],[-91.1567,47.3783],[-91.1569,47.3783],[-91.157,47.3784],[-91.1571,47.3784],[-91.1572,47.3783],[-91.1574,47.378],[-91.1575,47.378],[-91.1577,47.3777],[-91.1581,47.3769],[-91.1581,47.3769],[-91.1581,47.3769],[-91.1582,47.3765],[-91.1582,47.3757],[-91.1581,47.3756],[-91.1578,47.3755],[-91.1577,47.3754],[-91.1575,47.3754],[-91.1572,47.3755],[-91.1571,47.3755],[-91.1571,47.3755],[-91.1571,47.3754],[-91.1571,47.375],[-91.1572,47.3749],[-91.1573,47.3748],[-91.1574,47.3747],[-91.1576,47.3747],[-91.1577,47.3747],[-91.1579,47.3747],[-91.158,47.3746],[-91.1581,47.3746],[-91.1583,47.3746],[-91.1585,47.3746],[-91.1588,47.3747],[-91.1592,47.3747],[-91.1595,47.3747],[-91.1596,47.3748],[-91.16,47.3748],[-91.1603,47.3747],[-91.1606,47.3747],[-91.1608,47.3746],[-91.161,47.3745],[-91.1612,47.3744],[-91.1613,47.3742],[-91.1614,47.3741],[-91.1614,47.374],[-91.1614,47.3738],[-91.1613,47.3737],[-91.1613,47.3737],[-91.1612,47.3736],[-91.1612,47.3736],[-91.1613,47.3735],[-91.1614,47.3736],[-91.1614,47.3736],[-91.1616,47.3736],[-91.1617,47.3736],[-91.1618,47.3736],[-91.162,47.3735],[-91.1622,47.3734],[-91.1624,47.3732],[-91.1626,47.3731],[-91.1628,47.373],[-91.1629,47.373],[-91.163,47.3729],[-91.1631,47.3728],[-91.163,47.3726],[-91.163,47.3724],[-91.163,47.3723],[-91.1629,47.3722],[-91.1628,47.3721],[-91.1627,47.372],[-91.1626,47.3719],[-91.1626,47.3718],[-91.1627,47.3717],[-91.1627,47.3717],[-91.1628,47.3716],[-91.1629,47.3715],[-91.163,47.3714],[-91.1631,47.3715],[-91.1632,47.3716],[-91.1634,47.3717],[-91.1634,47.3717],[-91.1636,47.3717],[-91.1637,47.3718],[-91.1639,47.3718],[-91.1641,47.3718],[-91.1642,47.3717],[-91.1642,47.3717],[-91.1643,47.3715],[-91.1645,47.3713],[-91.1646,47.3712],[-91.1648,47.371],[-91.1649,47.3709],[-91.165,47.3708],[-91.1649,47.3708],[-91.1648,47.3707],[-91.1647,47.3707],[-91.1645,47.3706],[-91.1644,47.3705],[-91.1645,47.3704],[-91.1645,47.3703],[-91.1644,47.3702],[-91.1643,47.3702],[-91.1642,47.3701],[-91.1642,47.37],[-91.1642,47.37],[-91.1643,47.3699],[-91.1644,47.3698],[-91.1645,47.3698],[-91.1646,47.3696],[-91.1647,47.3696],[-91.1647,47.3695],[-91.1647,47.3694],[-91.1647,47.3693],[-91.1649,47.3693],[-91.1651,47.3692],[-91.1653,47.3691],[-91.1654,47.3691],[-91.1655,47.369],[-91.1655,47.3688],[-91.1655,47.3687],[-91.1655,47.3686],[-91.1655,47.3685],[-91.1657,47.3684],[-91.1659,47.3683],[-91.1661,47.3683],[-91.1662,47.3682],[-91.1662,47.3682],[-91.1662,47.3681],[-91.1662,47.3681],[-91.1661,47.368],[-91.1662,47.3679],[-91.1662,47.3679],[-91.1663,47.3679],[-91.1665,47.3678],[-91.1665,47.3678],[-91.1664,47.3677],[-91.1663,47.3677],[-91.1663,47.3677],[-91.1663,47.3676],[-91.1663,47.3676],[-91.1664,47.3675],[-91.1665,47.3675],[-91.1665,47.3675],[-91.1667,47.3675],[-91.1668,47.3675],[-91.1668,47.3674],[-91.1669,47.3673],[-91.167,47.3673],[-91.1672,47.3672],[-91.1673,47.3672],[-91.1674,47.3672],[-91.1675,47.3671],[-91.1675,47.3671],[-91.1676,47.367],[-91.1679,47.367],[-91.168,47.367],[-91.1682,47.367],[-91.1685,47.367],[-91.1688,47.3669],[-91.1692,47.3668],[-91.1694,47.3667],[-91.1697,47.3665],[-91.1701,47.3662],[-91.1703,47.3659],[-91.1705,47.3656],[-91.1706,47.3654],[-91.1707,47.3652],[-91.1706,47.3651],[-91.1705,47.365],[-91.1704,47.3649],[-91.1703,47.3646],[-91.1704,47.3646],[-91.1706,47.3645],[-91.1707,47.3644],[-91.1706,47.3643],[-91.1707,47.3641],[-91.1707,47.364],[-91.1707,47.3639],[-91.1706,47.3638],[-91.1705,47.3636],[-91.1706,47.3636],[-91.1707,47.3636],[-91.1708,47.3636],[-91.1708,47.3635],[-91.1707,47.3634],[-91.1706,47.3633],[-91.1705,47.3633],[-91.1706,47.3632],[-91.1707,47.3631],[-91.1708,47.363],[-91.1709,47.3629],[-91.171,47.3628],[-91.171,47.3627],[-91.1711,47.3626],[-91.1713,47.3626],[-91.1715,47.3626],[-91.1717,47.3625],[-91.1719,47.3624],[-91.172,47.3623],[-91.1723,47.362],[-91.1724,47.362],[-91.1728,47.3619],[-91.173,47.362],[-91.1733,47.362],[-91.1735,47.3619],[-91.1737,47.3618],[-91.1737,47.3616],[-91.1737,47.3615],[-91.1736,47.3614],[-91.1735,47.3613],[-91.1734,47.3613],[-91.1733,47.3612],[-91.1734,47.3612],[-91.1735,47.3612],[-91.1736,47.3611],[-91.1735,47.3609],[-91.1735,47.3608],[-91.1735,47.3607],[-91.1736,47.3607],[-91.1738,47.3607],[-91.174,47.3607],[-91.1742,47.3606],[-91.1743,47.3605],[-91.1744,47.3604],[-91.1743,47.3603],[-91.1741,47.3602],[-91.1739,47.3602],[-91.1737,47.3602],[-91.1734,47.3602],[-91.1733,47.3601],[-91.1732,47.3601],[-91.1732,47.3601],[-91.1733,47.3601],[-91.1734,47.36],[-91.1736,47.36],[-91.1737,47.36],[-91.1737,47.3599],[-91.1737,47.3598],[-91.1739,47.3598],[-91.1741,47.3599],[-91.1743,47.3599],[-91.1746,47.3598],[-91.1747,47.3597],[-91.1746,47.3596],[-91.1746,47.3595],[-91.1747,47.3595],[-91.1748,47.3594],[-91.1747,47.3593],[-91.1747,47.3593],[-91.1746,47.3592],[-91.1747,47.3592],[-91.1748,47.3592],[-91.175,47.3592],[-91.1752,47.3592],[-91.1753,47.3592],[-91.1754,47.3592],[-91.1755,47.3592],[-91.1757,47.359],[-91.1758,47.3589],[-91.1759,47.3587],[-91.176,47.3584],[-91.176,47.3582],[-91.176,47.3581],[-91.176,47.358],[-91.1759,47.358],[-91.1759,47.3579],[-91.1758,47.3578],[-91.1758,47.3576],[-91.1758,47.3575],[-91.1758,47.3574],[-91.1757,47.3573],[-91.1755,47.3573],[-91.1754,47.3573],[-91.1752,47.3571],[-91.1751,47.357],[-91.175,47.3568],[-91.175,47.3567],[-91.175,47.3565],[-91.1751,47.3564],[-91.1754,47.3564],[-91.1756,47.3563],[-91.1758,47.3563],[-91.176,47.3563],[-91.1761,47.3562],[-91.1762,47.3561],[-91.1762,47.356],[-91.176,47.3559],[-91.1759,47.356],[-91.1758,47.356],[-91.1757,47.3559],[-91.1758,47.3558],[-91.1761,47.3557],[-91.1764,47.3555],[-91.1764,47.3555],[-91.1766,47.3554],[-91.1767,47.3554],[-91.1768,47.3555],[-91.1767,47.3556],[-91.1767,47.3557],[-91.1767,47.3558],[-91.1768,47.3559],[-91.1769,47.3558],[-91.177,47.3558],[-91.1771,47.3558],[-91.1773,47.3558],[-91.1775,47.3557],[-91.1777,47.3556],[-91.1779,47.3553],[-91.178,47.3551],[-91.1781,47.3548],[-91.1781,47.3545],[-91.178,47.3543],[-91.1779,47.3541],[-91.1779,47.354],[-91.1779,47.354],[-91.1779,47.3539],[-91.1779,47.3539],[-91.1779,47.3539],[-91.1778,47.3538],[-91.1777,47.3538],[-91.1777,47.3537],[-91.1778,47.3537],[-91.1778,47.3536],[-91.1778,47.3535],[-91.1778,47.3534],[-91.178,47.3534],[-91.1781,47.3533],[-91.1781,47.3531],[-91.1782,47.3529],[-91.1783,47.3528],[-91.1786,47.3527],[-91.1787,47.3526],[-91.1787,47.3524],[-91.1788,47.3522],[-91.1788,47.352],[-91.1787,47.3519],[-91.1786,47.3517],[-91.1785,47.3516],[-91.1784,47.3514],[-91.1783,47.3512],[-91.1782,47.351],[-91.1781,47.3509],[-91.1781,47.3507],[-91.178,47.3507],[-91.1783,47.3507],[-91.1786,47.3509],[-91.1791,47.351],[-91.1793,47.3511],[-91.1794,47.3511],[-91.1795,47.351],[-91.1795,47.3509],[-91.1797,47.3509],[-91.1799,47.3509],[-91.18,47.3509],[-91.1801,47.3509],[-91.1801,47.3508],[-91.1799,47.3507],[-91.1798,47.3506],[-91.1797,47.3505],[-91.1797,47.3504],[-91.1797,47.3503],[-91.1798,47.3504],[-91.18,47.3505],[-91.1801,47.3505],[-91.1802,47.3505],[-91.1803,47.3504],[-91.1804,47.3502],[-91.1805,47.35],[-91.1806,47.3498],[-91.1806,47.3497],[-91.1808,47.3498],[-91.181,47.3499],[-91.1811,47.35],[-91.1812,47.35],[-91.1813,47.3497],[-91.1814,47.3494],[-91.1814,47.3493],[-91.1813,47.3493],[-91.1812,47.3493],[-91.1812,47.3492],[-91.1812,47.349],[-91.1811,47.3487],[-91.1811,47.3485],[-91.181,47.3483],[-91.1808,47.3482],[-91.1807,47.348],[-91.1807,47.3479],[-91.1807,47.3478],[-91.1806,47.3477],[-91.1807,47.3476],[-91.1808,47.3475],[-91.1809,47.3475],[-91.1811,47.3476],[-91.1815,47.3477],[-91.1819,47.3478],[-91.1822,47.3479],[-91.1825,47.348],[-91.1828,47.348],[-91.1832,47.3479],[-91.1834,47.3479],[-91.1835,47.3478],[-91.1836,47.3478],[-91.1838,47.3478],[-91.184,47.3477],[-91.1843,47.3477],[-91.1845,47.3477],[-91.1847,47.3477],[-91.1848,47.3476],[-91.1849,47.3475],[-91.185,47.3474],[-91.1852,47.3473],[-91.1853,47.3471],[-91.1854,47.3469],[-91.1853,47.3468],[-91.1853,47.3467],[-91.1853,47.3465],[-91.1854,47.3462],[-91.1852,47.3459],[-91.1851,47.3457],[-91.1849,47.3454],[-91.1848,47.3451],[-91.1845,47.3448],[-91.1844,47.3447],[-91.1844,47.3445],[-91.1844,47.3443],[-91.1842,47.3441],[-91.184,47.344],[-91.184,47.3439],[-91.1839,47.3437],[-91.184,47.3436],[-91.1843,47.3436],[-91.1845,47.3435],[-91.1848,47.3435],[-91.1849,47.3434],[-91.185,47.3434],[-91.1851,47.3434],[-91.1851,47.3433],[-91.1851,47.3433],[-91.1848,47.3432],[-91.1844,47.3432],[-91.1842,47.3431],[-91.1842,47.343],[-91.1843,47.3428],[-91.1844,47.3426],[-91.1844,47.3425],[-91.1844,47.3424],[-91.1845,47.3422],[-91.1845,47.342],[-91.1845,47.3418],[-91.1846,47.3417],[-91.1848,47.3415],[-91.1851,47.3414],[-91.1852,47.3413],[-91.1853,47.3412],[-91.1855,47.3411],[-91.1856,47.3409],[-91.1856,47.3408],[-91.1856,47.3406],[-91.1856,47.3405],[-91.1856,47.3404],[-91.1855,47.3403],[-91.1853,47.3403],[-91.1851,47.3404],[-91.185,47.3404],[-91.1849,47.3403],[-91.185,47.3402],[-91.185,47.3401],[-91.1848,47.34],[-91.1845,47.34],[-91.1843,47.34],[-91.1842,47.3399],[-91.1842,47.3398],[-91.1843,47.3397],[-91.1843,47.3397],[-91.1843,47.3396],[-91.1843,47.3395],[-91.1844,47.3395],[-91.1846,47.3395],[-91.1848,47.3394],[-91.185,47.3393],[-91.1854,47.3393],[-91.1857,47.3393],[-91.186,47.3394],[-91.1863,47.3395],[-91.1867,47.3395],[-91.1871,47.3396],[-91.1874,47.3397],[-91.1879,47.3399],[-91.1882,47.34],[-91.1885,47.3402],[-91.1887,47.3402],[-91.1892,47.3401],[-91.1896,47.3399],[-91.19,47.3397],[-91.1904,47.3396],[-91.1906,47.3396],[-91.1905,47.3394],[-91.1906,47.3393],[-91.1907,47.3393],[-91.1908,47.3393],[-91.1909,47.3393],[-91.191,47.3393],[-91.1912,47.3393],[-91.1912,47.3393],[-91.1913,47.3391],[-91.1918,47.3389],[-91.1919,47.3388],[-91.1918,47.3387],[-91.1918,47.3386],[-91.1918,47.3385],[-91.1918,47.3384],[-91.192,47.3385],[-91.1921,47.3385],[-91.1922,47.3386],[-91.1924,47.3386],[-91.1926,47.3386],[-91.1927,47.3385],[-91.1928,47.3383],[-91.1929,47.3382],[-91.1928,47.338],[-91.1926,47.3378],[-91.1926,47.3377],[-91.1926,47.3375],[-91.1927,47.3375],[-91.1928,47.3375],[-91.193,47.3376],[-91.1932,47.3376],[-91.1934,47.3377],[-91.1937,47.3379],[-91.1938,47.338],[-91.1942,47.3381],[-91.1945,47.3381],[-91.1949,47.338],[-91.1953,47.3379],[-91.1957,47.3378],[-91.196,47.3376],[-91.1962,47.3374],[-91.1964,47.3372],[-91.1965,47.337],[-91.1967,47.3368],[-91.1968,47.3367],[-91.1969,47.3366],[-91.1969,47.3365],[-91.1972,47.3364],[-91.1973,47.3363],[-91.1974,47.3363],[-91.1975,47.3363],[-91.1974,47.3362],[-91.1975,47.3361],[-91.1973,47.3361],[-91.1972,47.3361],[-91.1972,47.3359],[-91.1973,47.3356],[-91.1973,47.3355],[-91.1973,47.3354],[-91.1973,47.3353],[-91.1973,47.3352],[-91.1974,47.335],[-91.1975,47.3348],[-91.1975,47.3348],[-91.1976,47.3348],[-91.1978,47.3348],[-91.1979,47.335],[-91.1981,47.335],[-91.1983,47.3349],[-91.1985,47.3347],[-91.1987,47.3347],[-91.199,47.3347],[-91.1991,47.3346],[-91.1992,47.3346],[-91.1993,47.3345],[-91.1995,47.3345],[-91.1997,47.3344],[-91.2,47.3342],[-91.2002,47.334],[-91.2003,47.3338],[-91.2003,47.3335],[-91.2004,47.3333],[-91.2006,47.3331],[-91.2007,47.3329],[-91.2008,47.3328],[-91.2009,47.3328],[-91.201,47.3329],[-91.2011,47.3329],[-91.2013,47.3329],[-91.2017,47.3328],[-91.202,47.3326],[-91.2022,47.3324],[-91.2026,47.3322],[-91.2029,47.3322],[-91.2029,47.3323],[-91.203,47.3323],[-91.2031,47.3323],[-91.2032,47.3322],[-91.2033,47.3321],[-91.2034,47.3321],[-91.2034,47.3321],[-91.2034,47.3322],[-91.2035,47.3322],[-91.2036,47.3322],[-91.2037,47.3322],[-91.2036,47.3321],[-91.2036,47.3321],[-91.2036,47.332],[-91.2036,47.3318],[-91.2037,47.3317],[-91.2037,47.3316],[-91.2035,47.3315],[-91.2035,47.3313],[-91.2037,47.3312],[-91.2039,47.3311],[-91.204,47.331],[-91.204,47.3309],[-91.2039,47.3308],[-91.2038,47.3308],[-91.2039,47.3307],[-91.2042,47.3307],[-91.2045,47.3306],[-91.2047,47.3306],[-91.205,47.3306],[-91.2051,47.3306],[-91.2052,47.3306],[-91.2053,47.3306],[-91.2054,47.3306],[-91.2054,47.3306],[-91.2055,47.3305],[-91.2057,47.3303],[-91.2058,47.3302],[-91.206,47.3301],[-91.2061,47.3301],[-91.2062,47.33],[-91.2064,47.3298],[-91.2064,47.3297],[-91.2064,47.3296],[-91.2064,47.3295],[-91.2064,47.3294],[-91.2063,47.3291],[-91.2062,47.3289],[-91.2062,47.3289],[-91.2062,47.3287],[-91.2061,47.3287],[-91.206,47.3287],[-91.2058,47.3288],[-91.2058,47.3285],[-91.2059,47.3283],[-91.2059,47.3282],[-91.206,47.328],[-91.2059,47.3278],[-91.2059,47.3277],[-91.2061,47.3275],[-91.2063,47.3273],[-91.2064,47.3272],[-91.2066,47.3272],[-91.2067,47.327],[-91.2068,47.3268],[-91.2068,47.3266],[-91.2068,47.3264],[-91.2068,47.3262],[-91.207,47.326],[-91.2072,47.3258],[-91.2074,47.3257],[-91.2075,47.3256],[-91.2077,47.3254],[-91.2079,47.3253],[-91.208,47.3252],[-91.2081,47.3251],[-91.2082,47.325],[-91.2083,47.3248],[-91.2083,47.3246],[-91.2082,47.3245],[-91.2081,47.3242],[-91.208,47.324],[-91.2079,47.3239],[-91.2079,47.3239],[-91.2079,47.3237],[-91.208,47.3235],[-91.208,47.3233],[-91.2079,47.3232],[-91.2081,47.323],[-91.2084,47.3228],[-91.2086,47.3227],[-91.2088,47.3226],[-91.209,47.3226],[-91.2092,47.3225],[-91.2094,47.3224],[-91.2096,47.3223],[-91.2097,47.3222],[-91.2097,47.322],[-91.2098,47.3218],[-91.2098,47.3216],[-91.2097,47.3214],[-91.2098,47.3211],[-91.2098,47.3209],[-91.21,47.3208],[-91.2102,47.3208],[-91.2103,47.3206],[-91.2103,47.3204],[-91.2102,47.3202],[-91.2104,47.32],[-91.2108,47.3198],[-91.2112,47.3195],[-91.2116,47.3193],[-91.212,47.319],[-91.2122,47.3188],[-91.2123,47.3187],[-91.2125,47.3186],[-91.2127,47.3184],[-91.2129,47.3182],[-91.2133,47.318],[-91.2137,47.3179],[-91.2139,47.3179],[-91.2139,47.3178],[-91.2138,47.3177],[-91.2137,47.3176],[-91.2136,47.3176],[-91.2136,47.3175],[-91.2137,47.3174],[-91.2138,47.3174],[-91.214,47.3174],[-91.2143,47.3175],[-91.2144,47.3174],[-91.2146,47.3173],[-91.2147,47.3172],[-91.2149,47.317],[-91.215,47.317],[-91.215,47.3171],[-91.215,47.3172],[-91.215,47.3173],[-91.2152,47.3175],[-91.2156,47.3175],[-91.216,47.3175],[-91.2164,47.3174],[-91.2168,47.3173],[-91.2172,47.3174],[-91.2176,47.3175],[-91.2178,47.3176],[-91.2181,47.3178],[-91.2185,47.3179],[-91.2185,47.3179],[-91.2188,47.318],[-91.219,47.3181],[-91.2192,47.3181],[-91.2194,47.3181],[-91.2196,47.3181],[-91.22,47.318],[-91.2205,47.3179],[-91.2209,47.3176],[-91.2214,47.3172],[-91.2217,47.3169],[-91.2219,47.3165],[-91.222,47.3163],[-91.2221,47.3161],[-91.2223,47.3159],[-91.2225,47.3158],[-91.2226,47.3158],[-91.2226,47.3158],[-91.2227,47.3158],[-91.2229,47.3157],[-91.223,47.3156],[-91.223,47.3155],[-91.223,47.3154],[-91.2228,47.3154],[-91.2227,47.3153],[-91.2226,47.3152],[-91.2227,47.315],[-91.2227,47.315],[-91.223,47.3146],[-91.2233,47.3143],[-91.2234,47.3141],[-91.2235,47.3139],[-91.2235,47.3138],[-91.2237,47.3137],[-91.2238,47.3136],[-91.2239,47.3135],[-91.2239,47.3133],[-91.224,47.3132],[-91.2241,47.313],[-91.2241,47.3129],[-91.2242,47.3128],[-91.2242,47.3128],[-91.2242,47.3128],[-91.2243,47.3126],[-91.2243,47.3125],[-91.2242,47.3123],[-91.2241,47.3123],[-91.2241,47.3122],[-91.2242,47.3121],[-91.2244,47.3122],[-91.2245,47.3123],[-91.2247,47.3123],[-91.225,47.3123],[-91.2252,47.3122],[-91.2253,47.3121],[-91.2257,47.3122],[-91.2261,47.3124],[-91.2265,47.3125],[-91.2268,47.3126],[-91.2274,47.3126],[-91.2278,47.3124],[-91.2283,47.3122],[-91.2285,47.312],[-91.2287,47.3119],[-91.2288,47.3117],[-91.2289,47.3114],[-91.2291,47.3111],[-91.2293,47.3107],[-91.2295,47.3103],[-91.2297,47.3101],[-91.2297,47.3099],[-91.2297,47.3096],[-91.2297,47.3093],[-91.2297,47.3093],[-91.2298,47.3092],[-91.2297,47.3091],[-91.2296,47.309],[-91.2296,47.3088],[-91.2297,47.3085],[-91.2297,47.3083],[-91.2297,47.3083],[-91.2296,47.3082],[-91.2294,47.3082],[-91.2293,47.3082],[-91.2291,47.3082],[-91.229,47.3082],[-91.2289,47.3082],[-91.229,47.308],[-91.2292,47.3078],[-91.2293,47.3077],[-91.2294,47.3075],[-91.2293,47.3074],[-91.2292,47.3073],[-91.2292,47.3073],[-91.2292,47.3072],[-91.2294,47.3072],[-91.2296,47.3071],[-91.2297,47.307],[-91.2298,47.3069],[-91.2299,47.3067],[-91.2301,47.3065],[-91.2304,47.3063],[-91.2307,47.3062],[-91.2309,47.3062],[-91.2312,47.3061],[-91.2314,47.3061],[-91.2316,47.3061],[-91.2317,47.3062],[-91.232,47.3062],[-91.2323,47.3063],[-91.2325,47.3063],[-91.2327,47.3064],[-91.2329,47.3064],[-91.2332,47.3064],[-91.2334,47.3065],[-91.2336,47.3065],[-91.2337,47.3064],[-91.2339,47.3062],[-91.234,47.306],[-91.2341,47.3059],[-91.2343,47.3059],[-91.2344,47.3059],[-91.2345,47.3059],[-91.2345,47.3058],[-91.2346,47.3058],[-91.2347,47.3058],[-91.2349,47.3058],[-91.2352,47.3058],[-91.2355,47.3058],[-91.2356,47.3057],[-91.2358,47.3056],[-91.2359,47.3056],[-91.2359,47.3055],[-91.2359,47.3054],[-91.236,47.3053],[-91.2361,47.3053],[-91.2362,47.3053],[-91.2365,47.3054],[-91.2366,47.3054],[-91.2368,47.3054],[-91.2369,47.3054],[-91.2371,47.3053],[-91.2372,47.3053],[-91.2374,47.3053],[-91.2376,47.3052],[-91.2377,47.3051],[-91.2378,47.305],[-91.238,47.3049],[-91.2381,47.3049],[-91.2383,47.3049],[-91.2385,47.3048],[-91.2386,47.3048],[-91.2386,47.3049],[-91.2387,47.305],[-91.2388,47.305],[-91.239,47.3049],[-91.239,47.3049],[-91.2391,47.3048],[-91.2393,47.3047],[-91.2395,47.3046],[-91.2395,47.3045],[-91.2395,47.3044],[-91.2396,47.3042],[-91.2395,47.304],[-91.2395,47.3039],[-91.2395,47.3036],[-91.2393,47.3034],[-91.2392,47.3032],[-91.2391,47.303],[-91.2392,47.3028],[-91.2392,47.3027],[-91.2395,47.3025],[-91.2398,47.3024],[-91.2402,47.3024],[-91.2402,47.3024],[-91.2404,47.3023],[-91.2405,47.3022],[-91.2406,47.3021],[-91.2407,47.3019],[-91.2407,47.3018],[-91.2406,47.3016],[-91.2405,47.3014],[-91.2404,47.3014],[-91.2403,47.3013],[-91.2402,47.3012],[-91.2401,47.3011],[-91.2403,47.301],[-91.2404,47.3008],[-91.2406,47.3007],[-91.2407,47.3005],[-91.2408,47.3003],[-91.2408,47.3003],[-91.2409,47.3001],[-91.241,47.2999],[-91.2412,47.2999],[-91.2415,47.2999],[-91.2417,47.2998],[-91.2418,47.2998],[-91.2419,47.2999],[-91.242,47.2999],[-91.2424,47.2998],[-91.2428,47.2997],[-91.2431,47.2996],[-91.2433,47.2994],[-91.2433,47.2993],[-91.2432,47.2992],[-91.2431,47.2991],[-91.243,47.299],[-91.243,47.2987],[-91.2431,47.2986],[-91.2432,47.2985],[-91.2436,47.2984],[-91.2439,47.2983],[-91.244,47.2981],[-91.244,47.298],[-91.2439,47.2978],[-91.244,47.2977],[-91.244,47.2976],[-91.2441,47.2975],[-91.2442,47.2974],[-91.2444,47.2973],[-91.2447,47.2972],[-91.2448,47.2971],[-91.2449,47.2969],[-91.245,47.2967],[-91.2452,47.2965],[-91.2453,47.2964],[-91.2452,47.2963],[-91.2449,47.2962],[-91.2448,47.2962],[-91.2448,47.296],[-91.2449,47.2958],[-91.2452,47.2957],[-91.2455,47.2957],[-91.2458,47.2957],[-91.246,47.2956],[-91.2462,47.2955],[-91.2462,47.2952],[-91.2462,47.295],[-91.2462,47.2948],[-91.2463,47.2948],[-91.2464,47.2948],[-91.2465,47.2948],[-91.2466,47.2948],[-91.2467,47.2947],[-91.2467,47.2946],[-91.2468,47.2945],[-91.2469,47.2944],[-91.247,47.2943],[-91.2472,47.2941],[-91.2473,47.294],[-91.2473,47.2938],[-91.2472,47.2937],[-91.247,47.2934],[-91.2468,47.293],[-91.2468,47.2927],[-91.2468,47.2924],[-91.247,47.2921],[-91.2471,47.2918],[-91.2472,47.2916],[-91.2472,47.2915],[-91.2472,47.2914],[-91.2471,47.2913],[-91.2471,47.2911],[-91.2469,47.2909],[-91.2467,47.2907],[-91.2464,47.2905],[-91.2462,47.2904],[-91.246,47.2904],[-91.2458,47.2904],[-91.2456,47.2905],[-91.2453,47.2904],[-91.2451,47.2903],[-91.2449,47.2902],[-91.2446,47.2901],[-91.2445,47.29],[-91.2444,47.29],[-91.2443,47.2899],[-91.2442,47.2897],[-91.2442,47.2895],[-91.2442,47.2894],[-91.2443,47.2892],[-91.2445,47.289],[-91.2447,47.2888],[-91.2448,47.2887],[-91.245,47.2886],[-91.245,47.2884],[-91.2451,47.2882],[-91.2451,47.288],[-91.2453,47.2877],[-91.2454,47.2876],[-91.2456,47.2873],[-91.2458,47.2872],[-91.246,47.287],[-91.2465,47.2868],[-91.2467,47.2867],[-91.247,47.2865],[-91.2472,47.2864],[-91.2475,47.2863],[-91.2477,47.2861],[-91.2479,47.286],[-91.2481,47.2859],[-91.2483,47.2858],[-91.2484,47.2857],[-91.2484,47.2855],[-91.2484,47.2854],[-91.2484,47.2853],[-91.2484,47.2852],[-91.2486,47.2852],[-91.249,47.2852],[-91.2494,47.2852],[-91.2498,47.2853],[-91.25,47.2854],[-91.2501,47.2854],[-91.2507,47.2853],[-91.2508,47.2853],[-91.2513,47.285],[-91.2514,47.2847],[-91.2514,47.2839],[-91.2513,47.2834],[-91.2505,47.2824],[-91.2506,47.2824],[-91.2508,47.2823],[-91.2518,47.2818],[-91.2519,47.2816],[-91.2522,47.2813],[-91.2524,47.2812],[-91.2525,47.2811],[-91.2527,47.281],[-91.2528,47.281],[-91.2529,47.281],[-91.2535,47.2809],[-91.2546,47.2808],[-91.2557,47.2806],[-91.2565,47.2804],[-91.2567,47.2804],[-91.2572,47.2802],[-91.2577,47.2801],[-91.2578,47.28],[-91.2584,47.28],[-91.2587,47.2799],[-91.2595,47.2793],[-91.2597,47.2792],[-91.2603,47.2789],[-91.2603,47.2789],[-91.2604,47.279],[-91.2602,47.2791],[-91.2598,47.2796],[-91.2596,47.2801],[-91.2596,47.2802],[-91.2592,47.2804],[-91.2588,47.2807],[-91.2584,47.281],[-91.2575,47.2817],[-91.2574,47.2818],[-91.2573,47.282],[-91.2573,47.2824],[-91.2573,47.2825],[-91.2588,47.2856],[-91.2589,47.2857],[-91.2589,47.2857],[-91.2591,47.2857],[-91.2595,47.2853],[-91.2608,47.284],[-91.2615,47.2834],[-91.262,47.2829],[-91.2621,47.2828],[-91.2624,47.2825],[-91.2625,47.2824],[-91.2643,47.2806],[-91.2649,47.2801],[-91.265,47.2801],[-91.2655,47.2801],[-91.268,47.2779],[-91.2683,47.2776],[-91.2685,47.2776],[-91.2696,47.2775],[-91.2699,47.2774],[-91.2701,47.2774],[-91.2706,47.2771],[-91.2709,47.2769],[-91.2709,47.2768],[-91.271,47.2767],[-91.2711,47.2764],[-91.2712,47.2763],[-91.2713,47.2763],[-91.2713,47.2762],[-91.2714,47.2761],[-91.2714,47.2761],[-91.2716,47.2758],[-91.2716,47.2758],[-91.2717,47.2756],[-91.2718,47.2756],[-91.272,47.2756],[-91.2728,47.2755],[-91.273,47.2755],[-91.2731,47.2755],[-91.2733,47.2756],[-91.2735,47.2755],[-91.2736,47.2755],[-91.2737,47.2753],[-91.2737,47.2752],[-91.2737,47.275],[-91.2738,47.2748],[-91.2736,47.2745],[-91.2735,47.2743],[-91.2736,47.2742],[-91.2737,47.274],[-91.274,47.2738],[-91.2741,47.2736],[-91.2742,47.2735],[-91.2743,47.2733],[-91.2743,47.273],[-91.2746,47.2726],[-91.2746,47.2726],[-91.2746,47.2724],[-91.2745,47.2723],[-91.2727,47.2716],[-91.2724,47.2715],[-91.2691,47.2702],[-91.2682,47.2699],[-91.2681,47.2699],[-91.2681,47.2699],[-91.268,47.2699],[-91.2675,47.2699],[-91.2673,47.2699],[-91.2672,47.2698],[-91.2673,47.2697],[-91.2673,47.2697],[-91.2673,47.2696],[-91.2672,47.2694],[-91.2672,47.2692],[-91.2674,47.2689],[-91.2674,47.2689],[-91.2675,47.2688],[-91.2675,47.2688],[-91.2676,47.2687],[-91.2677,47.2687],[-91.2678,47.2689],[-91.2678,47.269],[-91.2676,47.2692],[-91.2676,47.2694],[-91.2676,47.2694],[-91.2682,47.2695],[-91.2684,47.2696],[-91.2685,47.2696],[-91.2685,47.2698],[-91.2685,47.2698],[-91.2692,47.2701],[-91.2693,47.2701],[-91.2723,47.2712],[-91.2725,47.2713],[-91.2744,47.272],[-91.2747,47.2722],[-91.2751,47.2722],[-91.2754,47.2721],[-91.2755,47.272],[-91.2758,47.2719],[-91.276,47.2718],[-91.2761,47.2717],[-91.2762,47.2715],[-91.2762,47.2715],[-91.2762,47.2714],[-91.2761,47.2712],[-91.2762,47.2709],[-91.2762,47.2707],[-91.2762,47.2705],[-91.2761,47.2704],[-91.2756,47.2704],[-91.2754,47.2703],[-91.2753,47.2703],[-91.2753,47.2701],[-91.2755,47.2699],[-91.2756,47.2698],[-91.2759,47.2697],[-91.2759,47.2697],[-91.2759,47.2695],[-91.2757,47.2693],[-91.2757,47.2693],[-91.2755,47.2692],[-91.275,47.2692],[-91.2749,47.2691],[-91.2748,47.2691],[-91.2748,47.269],[-91.275,47.2688],[-91.2754,47.2683],[-91.2757,47.2681],[-91.2757,47.268],[-91.2759,47.2679],[-91.2773,47.2668],[-91.2778,47.2665],[-91.2779,47.2665],[-91.2798,47.2665],[-91.28,47.2666],[-91.2801,47.2666],[-91.2806,47.2669],[-91.2812,47.2671],[-91.2815,47.2671],[-91.282,47.267],[-91.282,47.267],[-91.2823,47.267],[-91.2823,47.267],[-91.2824,47.267],[-91.2833,47.267],[-91.2837,47.2672],[-91.2839,47.2672],[-91.2846,47.2673],[-91.2851,47.2673],[-91.2859,47.2672],[-91.2861,47.2672],[-91.2863,47.2672],[-91.2865,47.2671],[-91.287,47.2669],[-91.2876,47.2665],[-91.2876,47.2665],[-91.2878,47.2664],[-91.2881,47.2662],[-91.2882,47.2661],[-91.2882,47.2661],[-91.2884,47.266],[-91.2885,47.2659],[-91.2888,47.2658],[-91.2894,47.2653],[-91.2896,47.2651],[-91.2898,47.2647],[-91.2899,47.2645],[-91.2902,47.2643],[-91.2905,47.2641],[-91.2914,47.2633],[-91.2915,47.2631],[-91.2915,47.2631],[-91.2915,47.2631],[-91.2915,47.2629],[-91.2916,47.2627],[-91.2916,47.2626],[-91.2919,47.2624],[-91.2921,47.2621],[-91.2923,47.2619],[-91.2928,47.2619],[-91.2929,47.2618],[-91.2932,47.2616],[-91.2933,47.2614],[-91.2934,47.2611],[-91.2934,47.2608],[-91.2934,47.2607],[-91.2933,47.2601],[-91.2932,47.2599],[-91.2932,47.2598],[-91.2927,47.2593],[-91.2926,47.2592],[-91.2923,47.2593],[-91.2921,47.2593],[-91.2917,47.2591],[-91.2916,47.259],[-91.2913,47.259],[-91.291,47.259],[-91.2906,47.2591],[-91.2904,47.2591],[-91.2899,47.2591],[-91.2894,47.259],[-91.2889,47.2588],[-91.2887,47.2585],[-91.2887,47.2582],[-91.2888,47.2581],[-91.2891,47.2581],[-91.2891,47.2581],[-91.2894,47.2583],[-91.2896,47.2583],[-91.2898,47.2583],[-91.29,47.2582],[-91.2901,47.258],[-91.2901,47.258],[-91.2901,47.258],[-91.2899,47.2579],[-91.2898,47.2578],[-91.2896,47.2577],[-91.2895,47.2576],[-91.2896,47.2576],[-91.2897,47.2576],[-91.2906,47.2577],[-91.291,47.2577],[-91.2913,47.2576],[-91.2914,47.2575],[-91.292,47.2572],[-91.2925,47.257],[-91.2925,47.2569],[-91.2926,47.2569],[-91.2928,47.2569],[-91.2928,47.2569],[-91.2929,47.257],[-91.2931,47.2571],[-91.2933,47.2572],[-91.2934,47.2573],[-91.2936,47.2574],[-91.2939,47.2576],[-91.2941,47.2577],[-91.2943,47.2577],[-91.2947,47.2576],[-91.2949,47.2575],[-91.2953,47.2574],[-91.2954,47.2573],[-91.2959,47.2571],[-91.296,47.257],[-91.296,47.257],[-91.2961,47.2569],[-91.2961,47.2568],[-91.296,47.2567],[-91.296,47.2567],[-91.2961,47.2563],[-91.2962,47.2562],[-91.2965,47.2559],[-91.2966,47.2559],[-91.297,47.2559],[-91.2974,47.2559],[-91.2975,47.2559],[-91.2981,47.2559],[-91.2984,47.2559],[-91.2988,47.2559],[-91.2992,47.2558],[-91.2993,47.2558],[-91.2994,47.2557],[-91.2997,47.2553],[-91.3,47.2551],[-91.3,47.2551],[-91.3003,47.2551],[-91.3005,47.2553],[-91.3006,47.2556],[-91.3008,47.2557],[-91.301,47.2558],[-91.301,47.2558],[-91.3013,47.2558],[-91.3014,47.2557],[-91.3014,47.2556],[-91.3015,47.2555],[-91.3022,47.2553],[-91.3025,47.2552],[-91.3026,47.2551],[-91.3026,47.2549],[-91.3025,47.2548],[-91.3024,47.2546],[-91.3024,47.2546],[-91.3026,47.2544],[-91.3028,47.2544],[-91.3035,47.2544],[-91.3036,47.2544],[-91.3037,47.2544],[-91.3039,47.2543],[-91.3043,47.2543],[-91.3045,47.2543],[-91.3049,47.254],[-91.305,47.254],[-91.3055,47.2534],[-91.3058,47.2531],[-91.3059,47.2528],[-91.3061,47.2527],[-91.3062,47.2526],[-91.3062,47.2524],[-91.3061,47.2523],[-91.306,47.252],[-91.306,47.252],[-91.3061,47.2518],[-91.3064,47.2514],[-91.3065,47.2514],[-91.3066,47.2514],[-91.3067,47.2514],[-91.3069,47.2513],[-91.3071,47.2514],[-91.3077,47.2514],[-91.3079,47.2513],[-91.3081,47.2513],[-91.3082,47.2512],[-91.3083,47.2511],[-91.3087,47.2509],[-91.3089,47.2507],[-91.3091,47.2503],[-91.3092,47.2501],[-91.3092,47.25],[-91.3093,47.2499],[-91.3093,47.2498],[-91.3093,47.2495],[-91.3093,47.2494],[-91.3094,47.2493],[-91.3094,47.2491],[-91.3094,47.249],[-91.3095,47.2489],[-91.3096,47.2488],[-91.3102,47.2487],[-91.3105,47.2486],[-91.3106,47.2485],[-91.3107,47.2485],[-91.3107,47.2484],[-91.3106,47.2483],[-91.3107,47.2482],[-91.3109,47.2481],[-91.311,47.2481],[-91.3112,47.2477],[-91.3113,47.2475],[-91.3114,47.2474],[-91.3116,47.2474],[-91.3117,47.2474],[-91.3118,47.2472],[-91.3121,47.247],[-91.3125,47.2468],[-91.3127,47.2467],[-91.3129,47.2467],[-91.3131,47.2467],[-91.3132,47.2467],[-91.3133,47.2466],[-91.3134,47.2466],[-91.3134,47.2466],[-91.3135,47.2467],[-91.3137,47.2467],[-91.3138,47.2467],[-91.3139,47.2467],[-91.314,47.2465],[-91.3139,47.2465],[-91.3138,47.2464],[-91.3139,47.2463],[-91.3139,47.2462],[-91.3139,47.2462],[-91.3139,47.2461],[-91.3138,47.2461],[-91.3121,47.2461],[-91.312,47.2461],[-91.3118,47.2461],[-91.3119,47.246],[-91.312,47.246],[-91.3122,47.246],[-91.3122,47.2459],[-91.3122,47.2459],[-91.3121,47.2458],[-91.3121,47.2457],[-91.3123,47.2457],[-91.3124,47.2457],[-91.3125,47.2457],[-91.3126,47.2458],[-91.3127,47.2458],[-91.3128,47.2457],[-91.3129,47.2457],[-91.3132,47.2457],[-91.3134,47.2457],[-91.3136,47.2457],[-91.3138,47.2458],[-91.3138,47.2458],[-91.3138,47.2458],[-91.314,47.2458],[-91.3141,47.2458],[-91.3142,47.2458],[-91.3142,47.2459],[-91.3143,47.2459],[-91.3144,47.2459],[-91.3145,47.246],[-91.3146,47.246],[-91.3149,47.246],[-91.315,47.246],[-91.3152,47.2461],[-91.3153,47.2461],[-91.3155,47.246],[-91.3156,47.2459],[-91.3157,47.2458],[-91.3158,47.2457],[-91.3159,47.2455],[-91.316,47.2454],[-91.3161,47.2452],[-91.3164,47.245],[-91.317,47.2446],[-91.3171,47.2445],[-91.3172,47.2445],[-91.3173,47.2444],[-91.3173,47.2444],[-91.3172,47.2443],[-91.3173,47.2442],[-91.3174,47.2442],[-91.3174,47.2442],[-91.3176,47.244],[-91.3177,47.2439],[-91.3181,47.2438],[-91.3184,47.2437],[-91.3185,47.2436],[-91.3186,47.2434],[-91.3187,47.2432],[-91.3187,47.2429],[-91.3188,47.2427],[-91.3188,47.2426],[-91.319,47.2424],[-91.3192,47.2423],[-91.3192,47.2421],[-91.3192,47.2421],[-91.3193,47.242],[-91.3193,47.2418],[-91.3194,47.2417],[-91.3196,47.2416],[-91.3197,47.2415],[-91.3196,47.2414],[-91.3196,47.2413],[-91.3196,47.2413],[-91.3198,47.2412],[-91.3199,47.2413],[-91.32,47.2413],[-91.3202,47.2412],[-91.3209,47.2409],[-91.3212,47.2409],[-91.3216,47.2408],[-91.3218,47.2407],[-91.3218,47.2406],[-91.3219,47.2405],[-91.3222,47.2401],[-91.3223,47.24],[-91.3224,47.2399],[-91.3225,47.2397],[-91.3227,47.2396],[-91.3231,47.2396],[-91.3234,47.2396],[-91.3246,47.2394],[-91.3252,47.2393],[-91.3253,47.2393],[-91.3254,47.2392],[-91.3256,47.2391],[-91.3257,47.2389],[-91.3255,47.2383],[-91.3255,47.2381],[-91.3254,47.2379],[-91.3254,47.2378],[-91.3255,47.2376],[-91.3256,47.2375],[-91.3257,47.2374],[-91.3258,47.2371],[-91.3258,47.237],[-91.3257,47.2367],[-91.3258,47.2362],[-91.3258,47.236],[-91.326,47.2359],[-91.3262,47.236],[-91.3264,47.236],[-91.3267,47.2359],[-91.3271,47.2355],[-91.3277,47.2352],[-91.3278,47.2351],[-91.328,47.2351],[-91.3281,47.2351],[-91.3282,47.235],[-91.3284,47.2345],[-91.3285,47.2343],[-91.3287,47.2341],[-91.3286,47.234],[-91.3284,47.2339],[-91.3281,47.2338],[-91.3281,47.2337],[-91.328,47.2336],[-91.3279,47.2336],[-91.3278,47.2335],[-91.3278,47.2334],[-91.3279,47.2333],[-91.3282,47.233],[-91.3282,47.2329],[-91.3283,47.2328],[-91.3283,47.2327],[-91.3282,47.2326],[-91.3282,47.2324],[-91.3283,47.2323],[-91.3284,47.2322],[-91.3285,47.2322],[-91.3286,47.2322],[-91.3287,47.2322],[-91.3288,47.2321],[-91.329,47.232],[-91.3292,47.2319],[-91.3293,47.2319],[-91.3296,47.2318],[-91.3298,47.2318],[-91.3305,47.2315],[-91.3307,47.2314],[-91.3309,47.2314],[-91.3309,47.2313],[-91.3309,47.2312],[-91.331,47.2311],[-91.3311,47.2311],[-91.3313,47.2311],[-91.3313,47.2309],[-91.3314,47.2308],[-91.3317,47.2306],[-91.3339,47.23],[-91.3342,47.23],[-91.3343,47.2299],[-91.3343,47.2298],[-91.3338,47.2296],[-91.3336,47.2295],[-91.3335,47.2293],[-91.3336,47.2292],[-91.3342,47.229],[-91.3344,47.229],[-91.3346,47.229],[-91.3348,47.2291],[-91.335,47.2292],[-91.3352,47.2292],[-91.3363,47.229],[-91.3366,47.2289],[-91.3368,47.2287],[-91.337,47.2287],[-91.3372,47.2287],[-91.3374,47.2288],[-91.3377,47.2287],[-91.3377,47.2286],[-91.3377,47.2285],[-91.3376,47.2284],[-91.3376,47.2283],[-91.3375,47.2282],[-91.3375,47.2281],[-91.3377,47.2281],[-91.3379,47.228],[-91.3379,47.2279],[-91.3379,47.2278],[-91.3378,47.2276],[-91.3378,47.2275],[-91.3377,47.2273],[-91.3376,47.2272],[-91.3376,47.227],[-91.3377,47.2269],[-91.3378,47.2268],[-91.3379,47.2266],[-91.3378,47.2266],[-91.3378,47.2264],[-91.3378,47.2264],[-91.3378,47.2263],[-91.3379,47.2263],[-91.338,47.2264],[-91.3381,47.2264],[-91.3381,47.2265],[-91.3382,47.2264],[-91.3382,47.2263],[-91.3383,47.2262],[-91.3387,47.2261],[-91.3392,47.2261],[-91.3394,47.2261],[-91.3395,47.226],[-91.3396,47.2259],[-91.3396,47.2258],[-91.3396,47.2257],[-91.3396,47.2256],[-91.3398,47.2255],[-91.3406,47.2255],[-91.3408,47.2255],[-91.3409,47.2254],[-91.341,47.2252],[-91.3411,47.2251],[-91.3412,47.225],[-91.3414,47.225],[-91.3416,47.225],[-91.3419,47.2249],[-91.3421,47.2248],[-91.3423,47.2246],[-91.3425,47.2245],[-91.3427,47.2245],[-91.3429,47.2244],[-91.3433,47.2243],[-91.3435,47.2243],[-91.3437,47.2244],[-91.3438,47.2244],[-91.344,47.2245],[-91.3442,47.2245],[-91.3443,47.2243],[-91.3444,47.2242],[-91.3444,47.2241],[-91.3444,47.2239],[-91.3444,47.2237],[-91.3443,47.2236],[-91.3442,47.2235],[-91.3441,47.2233],[-91.344,47.2232],[-91.344,47.223],[-91.344,47.2228],[-91.3441,47.2223],[-91.3443,47.2221],[-91.3444,47.2219],[-91.3449,47.2216],[-91.3451,47.2216],[-91.3453,47.2216],[-91.3454,47.2217],[-91.3455,47.2216],[-91.3456,47.2215],[-91.3457,47.2214],[-91.346,47.2213],[-91.3462,47.2212],[-91.3465,47.2212],[-91.3466,47.2213],[-91.347,47.2213],[-91.3473,47.2214],[-91.3475,47.2214],[-91.3476,47.2214],[-91.3477,47.2213],[-91.3479,47.2211],[-91.3481,47.2207],[-91.3483,47.2206],[-91.3484,47.2205],[-91.3485,47.2203],[-91.3485,47.2202],[-91.3484,47.22],[-91.3484,47.2199],[-91.3485,47.2197],[-91.3486,47.2195],[-91.3487,47.2193],[-91.3489,47.2192],[-91.3499,47.2184],[-91.35,47.2183],[-91.3502,47.2182],[-91.3508,47.2176],[-91.351,47.2175],[-91.3511,47.2174],[-91.3513,47.2173],[-91.3523,47.217],[-91.3525,47.2169],[-91.3525,47.2169],[-91.3526,47.2167],[-91.3527,47.2163],[-91.3527,47.2162],[-91.3528,47.2161],[-91.3529,47.2161],[-91.3529,47.216],[-91.3529,47.2158],[-91.3529,47.2157],[-91.3531,47.2155],[-91.3531,47.2154],[-91.3532,47.2152],[-91.3533,47.2151],[-91.3534,47.2149],[-91.3535,47.2147],[-91.3535,47.2145],[-91.3535,47.2144],[-91.3535,47.2142],[-91.3536,47.214],[-91.3537,47.2138],[-91.3538,47.2137],[-91.3538,47.2136],[-91.3538,47.2132],[-91.3537,47.2131],[-91.3537,47.213],[-91.3537,47.2128],[-91.3536,47.2127],[-91.3535,47.2125],[-91.3534,47.2122],[-91.3532,47.212],[-91.3532,47.2118],[-91.3531,47.2116],[-91.3532,47.2113],[-91.3532,47.2111],[-91.3532,47.211],[-91.3533,47.2107],[-91.3533,47.2107],[-91.3533,47.2105],[-91.3533,47.2104],[-91.3532,47.2103],[-91.3532,47.2102],[-91.3533,47.2102],[-91.3534,47.2103],[-91.3544,47.2106],[-91.3547,47.2106],[-91.3548,47.2106],[-91.355,47.2104],[-91.3551,47.2103],[-91.3553,47.2103],[-91.3555,47.2103],[-91.3556,47.2103],[-91.3556,47.2102],[-91.3555,47.2099],[-91.3555,47.2098],[-91.3555,47.2097],[-91.3555,47.2097],[-91.3556,47.2097],[-91.3557,47.2097],[-91.3558,47.2095],[-91.3559,47.2094],[-91.3559,47.2093],[-91.356,47.2093],[-91.356,47.2092],[-91.3561,47.2091],[-91.3561,47.209],[-91.3562,47.2088],[-91.3562,47.2088],[-91.3562,47.2087],[-91.3561,47.2086],[-91.356,47.2086],[-91.3559,47.2085],[-91.3558,47.2085],[-91.3557,47.2084],[-91.3556,47.2084],[-91.3554,47.2084],[-91.3553,47.2083],[-91.3552,47.2082],[-91.3552,47.2081],[-91.3553,47.2079],[-91.3554,47.2078],[-91.3554,47.2077],[-91.3554,47.2076],[-91.3554,47.2075],[-91.3554,47.2072],[-91.3554,47.2071],[-91.3555,47.207],[-91.3556,47.2069],[-91.3557,47.2069],[-91.3557,47.207],[-91.3558,47.2071],[-91.356,47.207],[-91.3561,47.207],[-91.3563,47.2067],[-91.3566,47.2065],[-91.3567,47.2063],[-91.3568,47.2063],[-91.3569,47.2063],[-91.3572,47.2063],[-91.3574,47.2063],[-91.3575,47.2063],[-91.3576,47.2064],[-91.3577,47.2068],[-91.3578,47.2069],[-91.3579,47.207],[-91.358,47.207],[-91.3584,47.207],[-91.3585,47.207],[-91.3586,47.207],[-91.3587,47.2069],[-91.3588,47.2069],[-91.3593,47.2068],[-91.3595,47.2068],[-91.3596,47.2068],[-91.3598,47.2067],[-91.3599,47.2066],[-91.36,47.2066],[-91.3602,47.2066],[-91.3603,47.2066],[-91.3605,47.2066],[-91.3606,47.2066],[-91.3608,47.2065],[-91.3618,47.2062],[-91.362,47.2062],[-91.3622,47.2062],[-91.3624,47.2062],[-91.3624,47.2062],[-91.3626,47.2061],[-91.3627,47.2061],[-91.3629,47.206],[-91.3631,47.206],[-91.3634,47.2059],[-91.3642,47.2057],[-91.3644,47.2056],[-91.3646,47.2055],[-91.3647,47.2054],[-91.3649,47.2053],[-91.3651,47.2053],[-91.3651,47.2052],[-91.3651,47.2051],[-91.3651,47.205],[-91.3651,47.205],[-91.3649,47.2048],[-91.3649,47.2047],[-91.3649,47.2047],[-91.3649,47.2047],[-91.3649,47.2046],[-91.3649,47.2045],[-91.3649,47.2044],[-91.3648,47.2043],[-91.3648,47.2043],[-91.3648,47.2042],[-91.3649,47.2042],[-91.3652,47.2039],[-91.3653,47.2038],[-91.3654,47.2037],[-91.3655,47.2037],[-91.3655,47.2036],[-91.3654,47.2035],[-91.3653,47.2034],[-91.3653,47.2033],[-91.3654,47.2032],[-91.3654,47.2031],[-91.3653,47.203],[-91.3651,47.2029],[-91.3651,47.2027],[-91.3651,47.2026],[-91.3651,47.2026],[-91.3649,47.2025],[-91.3649,47.2025],[-91.3648,47.2024],[-91.3648,47.202],[-91.3648,47.2019],[-91.3649,47.2019],[-91.365,47.2018],[-91.365,47.2017],[-91.3649,47.2016],[-91.3648,47.2016],[-91.3647,47.2015],[-91.3647,47.2014],[-91.3648,47.2014],[-91.3652,47.2012],[-91.3653,47.2012],[-91.3654,47.2012],[-91.3655,47.2013],[-91.3656,47.2013],[-91.3657,47.2013],[-91.3657,47.2012],[-91.3658,47.2008],[-91.3658,47.2007],[-91.3657,47.2005],[-91.3658,47.2004],[-91.3658,47.2003],[-91.3659,47.2001],[-91.3661,47.2],[-91.3665,47.1999],[-91.3667,47.1998],[-91.3669,47.1998],[-91.3671,47.1998],[-91.3675,47.1998],[-91.3681,47.1999],[-91.3693,47.1999],[-91.3695,47.1999],[-91.3697,47.1998],[-91.3698,47.1997],[-91.3698,47.1996],[-91.37,47.1996],[-91.3702,47.1996],[-91.3704,47.1995],[-91.3706,47.1994],[-91.3707,47.1994],[-91.3708,47.1994],[-91.3709,47.1994],[-91.371,47.1993],[-91.3711,47.1992],[-91.3712,47.1992],[-91.3723,47.1991],[-91.3725,47.199],[-91.3726,47.199],[-91.3726,47.1989],[-91.3726,47.1988],[-91.3726,47.1988],[-91.3727,47.1987],[-91.3728,47.1987],[-91.3729,47.1986],[-91.3731,47.1985],[-91.3733,47.1984],[-91.3733,47.1983],[-91.3733,47.1982],[-91.3733,47.1981],[-91.3733,47.198],[-91.3735,47.198],[-91.3737,47.1978],[-91.3738,47.1977],[-91.374,47.1977],[-91.3741,47.1978],[-91.3745,47.1979],[-91.3748,47.1979],[-91.3751,47.198],[-91.3755,47.198],[-91.3758,47.1981],[-91.3761,47.1981],[-91.3766,47.1981],[-91.3769,47.198],[-91.3772,47.1978],[-91.3773,47.1976],[-91.3774,47.1975],[-91.3775,47.1973],[-91.3775,47.1972],[-91.3776,47.1969],[-91.3776,47.1967],[-91.3776,47.1966],[-91.3775,47.1964],[-91.3774,47.1961],[-91.3773,47.1958],[-91.3772,47.1957],[-91.3771,47.1957],[-91.377,47.1956],[-91.3771,47.1955],[-91.3774,47.1954],[-91.3778,47.1952],[-91.3783,47.1949],[-91.3787,47.1947],[-91.3789,47.1946],[-91.3791,47.1945],[-91.3794,47.1943],[-91.3795,47.1942],[-91.3797,47.194],[-91.3799,47.1937],[-91.3801,47.1935],[-91.3802,47.1933],[-91.3803,47.193],[-91.3804,47.1927],[-91.3804,47.1923],[-91.3805,47.1922],[-91.3805,47.1919],[-91.3806,47.1917],[-91.3806,47.1915],[-91.3807,47.1914],[-91.3807,47.1914],[-91.3811,47.1913],[-91.3814,47.1913],[-91.3817,47.1914],[-91.3819,47.1915],[-91.3822,47.1916],[-91.3824,47.1917],[-91.3825,47.1918],[-91.3828,47.1918],[-91.383,47.1918],[-91.3833,47.1918],[-91.3836,47.1918],[-91.3838,47.1918],[-91.3842,47.1916],[-91.3853,47.1909],[-91.3853,47.1908],[-91.3852,47.1907],[-91.3853,47.1906],[-91.3853,47.1905],[-91.3854,47.1904],[-91.3856,47.1903],[-91.3858,47.1902],[-91.3859,47.1902],[-91.3861,47.1901],[-91.3862,47.1901],[-91.3863,47.1901],[-91.3865,47.1901],[-91.3865,47.19],[-91.3863,47.1899],[-91.3862,47.1898],[-91.3861,47.1896],[-91.3859,47.1896],[-91.3856,47.1896],[-91.3853,47.1895],[-91.385,47.1893],[-91.3848,47.1891],[-91.3846,47.189],[-91.3843,47.1888],[-91.384,47.1888],[-91.3837,47.1887],[-91.3836,47.1886],[-91.3834,47.1885],[-91.3834,47.1884],[-91.3831,47.1884],[-91.383,47.1883],[-91.3831,47.188],[-91.3833,47.1879],[-91.3837,47.1879],[-91.3839,47.1878],[-91.384,47.1876],[-91.384,47.1875],[-91.3842,47.1873],[-91.3845,47.1872],[-91.3846,47.1872],[-91.3848,47.1872],[-91.385,47.1871],[-91.3853,47.1871],[-91.3855,47.1872],[-91.3858,47.1872],[-91.3861,47.1871],[-91.3864,47.187],[-91.3867,47.187],[-91.3869,47.1871],[-91.387,47.1872],[-91.3874,47.1873],[-91.3876,47.1873],[-91.3879,47.1873],[-91.3882,47.1873],[-91.3885,47.1873],[-91.3889,47.1873],[-91.3893,47.1873],[-91.3895,47.1873],[-91.3897,47.1873],[-91.3901,47.1873],[-91.3912,47.1873],[-91.3917,47.1873],[-91.3921,47.1872],[-91.3924,47.1872],[-91.3926,47.1872],[-91.393,47.187],[-91.3935,47.1869],[-91.3937,47.1868],[-91.3938,47.1868],[-91.394,47.1866],[-91.3942,47.1866],[-91.3944,47.1865],[-91.3946,47.1864],[-91.3948,47.1864],[-91.395,47.1864],[-91.3953,47.1864],[-91.3956,47.1864],[-91.3957,47.1863],[-91.3959,47.1862],[-91.3961,47.1862],[-91.3964,47.1861],[-91.3967,47.1861],[-91.3969,47.1861],[-91.3971,47.1861],[-91.3973,47.186],[-91.3976,47.1859],[-91.3978,47.1859],[-91.398,47.186],[-91.3982,47.1861],[-91.3985,47.1861],[-91.3988,47.186],[-91.3991,47.1858],[-91.3993,47.1856],[-91.3995,47.1853],[-91.3996,47.1851],[-91.3996,47.1849],[-91.3997,47.1848],[-91.3997,47.1848],[-91.3996,47.1846],[-91.3994,47.1844],[-91.3991,47.1843],[-91.3991,47.1843],[-91.399,47.1842],[-91.3987,47.1841],[-91.3985,47.184],[-91.3982,47.1839],[-91.3981,47.1838],[-91.3982,47.1836],[-91.3982,47.1834],[-91.3984,47.1833],[-91.3987,47.1834],[-91.3988,47.1833],[-91.3989,47.1832],[-91.3989,47.1831],[-91.399,47.183],[-91.3992,47.1829],[-91.3992,47.1827],[-91.3994,47.1823],[-91.3995,47.1822],[-91.3997,47.1821],[-91.3998,47.182],[-91.4,47.1819],[-91.4001,47.1818],[-91.4001,47.1817],[-91.4002,47.1815],[-91.4003,47.1815],[-91.4004,47.1814],[-91.4006,47.1813],[-91.4007,47.1812],[-91.4008,47.1812],[-91.4008,47.181],[-91.4009,47.1809],[-91.401,47.1808],[-91.4011,47.1808],[-91.4013,47.181],[-91.4013,47.1811],[-91.4014,47.1812],[-91.4016,47.1812],[-91.4017,47.1812],[-91.4019,47.1814],[-91.402,47.1816],[-91.4022,47.1818],[-91.4024,47.1819],[-91.4026,47.1819],[-91.4028,47.1819],[-91.4031,47.182],[-91.4034,47.182],[-91.4037,47.1819],[-91.404,47.1817],[-91.4041,47.1817],[-91.4042,47.1815],[-91.4042,47.1813],[-91.4042,47.1811],[-91.4043,47.1809],[-91.4044,47.1809],[-91.4045,47.181],[-91.4045,47.1812],[-91.4045,47.1814],[-91.4045,47.1814],[-91.4057,47.1815],[-91.4059,47.1817],[-91.406,47.1818],[-91.4061,47.182],[-91.4062,47.182],[-91.4064,47.1821],[-91.4065,47.1821],[-91.4066,47.1821],[-91.4071,47.182],[-91.4072,47.182],[-91.4073,47.1819],[-91.4075,47.1819],[-91.4077,47.1818],[-91.4079,47.1817],[-91.408,47.1816],[-91.4081,47.1815],[-91.4082,47.1814],[-91.4084,47.1813],[-91.4085,47.1812],[-91.4086,47.181],[-91.4087,47.1807],[-91.4087,47.1805],[-91.4088,47.1801],[-91.4089,47.1798],[-91.409,47.1796],[-91.4092,47.1794],[-91.4093,47.1793],[-91.4094,47.1792],[-91.4095,47.179],[-91.4096,47.1788],[-91.4096,47.1786],[-91.4097,47.1784],[-91.4098,47.1781],[-91.4098,47.1779],[-91.4098,47.1777],[-91.4098,47.1776],[-91.4096,47.1776],[-91.4094,47.1775],[-91.4094,47.1773],[-91.4096,47.1772],[-91.4097,47.1771],[-91.4097,47.177],[-91.4098,47.1765],[-91.4098,47.1762],[-91.4097,47.176],[-91.4097,47.1759],[-91.4098,47.1758],[-91.4099,47.1757],[-91.4102,47.1757],[-91.4102,47.1757],[-91.4105,47.1757],[-91.4108,47.1758],[-91.411,47.1758],[-91.4112,47.1757],[-91.4115,47.1757],[-91.4116,47.1756],[-91.4117,47.1754],[-91.4118,47.1753],[-91.4121,47.1753],[-91.4124,47.1752],[-91.4126,47.1752],[-91.4129,47.1752],[-91.413,47.175],[-91.4133,47.1748],[-91.4135,47.1747],[-91.4135,47.1746],[-91.4137,47.1745],[-91.4138,47.1744],[-91.4138,47.1742],[-91.414,47.174],[-91.4144,47.1737],[-91.4148,47.1735],[-91.4152,47.1733],[-91.4155,47.1732],[-91.4159,47.1731],[-91.4163,47.173],[-91.4166,47.1728],[-91.417,47.1726],[-91.4174,47.1724],[-91.4176,47.1724],[-91.4178,47.1724],[-91.4182,47.1724],[-91.4184,47.1723],[-91.4186,47.1723],[-91.4187,47.1722],[-91.4188,47.1721],[-91.419,47.1719],[-91.4191,47.1717],[-91.4192,47.1716],[-91.4195,47.1712],[-91.4197,47.171],[-91.42,47.1707],[-91.4202,47.1705],[-91.4204,47.1702],[-91.4206,47.1699],[-91.4207,47.1695],[-91.4209,47.1693],[-91.4209,47.1691],[-91.4209,47.1689],[-91.4209,47.1686],[-91.421,47.1682],[-91.4211,47.168],[-91.4212,47.1677],[-91.4212,47.1674],[-91.4213,47.1672],[-91.4213,47.167],[-91.4214,47.1668],[-91.4214,47.1667],[-91.4214,47.1666],[-91.4213,47.1666],[-91.4209,47.1666],[-91.4209,47.1664],[-91.421,47.1663],[-91.4212,47.1663],[-91.4213,47.1663],[-91.4214,47.1662],[-91.4214,47.1661],[-91.4215,47.1661],[-91.4217,47.1661],[-91.4218,47.1662],[-91.422,47.1663],[-91.4221,47.1663],[-91.4222,47.1662],[-91.4222,47.166],[-91.4222,47.1658],[-91.4221,47.1657],[-91.422,47.1655],[-91.4219,47.1655],[-91.422,47.1654],[-91.4222,47.1653],[-91.4223,47.1652],[-91.4225,47.165],[-91.4225,47.1649],[-91.4226,47.1648],[-91.4227,47.1648],[-91.4229,47.1648],[-91.423,47.1649],[-91.4231,47.165],[-91.4233,47.165],[-91.4235,47.165],[-91.4237,47.1651],[-91.4241,47.1652],[-91.4245,47.1653],[-91.4248,47.1654],[-91.4251,47.1656],[-91.4265,47.1652],[-91.4267,47.1651],[-91.427,47.165],[-91.4271,47.1649],[-91.4272,47.1647],[-91.4273,47.1645],[-91.4274,47.1644],[-91.4275,47.1643],[-91.4277,47.1643],[-91.4278,47.1642],[-91.4279,47.164],[-91.428,47.1638],[-91.4282,47.1636],[-91.4285,47.1635],[-91.4289,47.1634],[-91.429,47.1633],[-91.4291,47.1633],[-91.4291,47.1631],[-91.4293,47.1628],[-91.4295,47.1626],[-91.4296,47.1625],[-91.4299,47.1623],[-91.4302,47.1622],[-91.4307,47.162],[-91.4312,47.1619],[-91.4316,47.1618],[-91.4316,47.1618],[-91.4319,47.1617],[-91.4321,47.1616],[-91.4322,47.1615],[-91.4324,47.1614],[-91.4328,47.1608],[-91.4329,47.1606],[-91.4331,47.1602],[-91.4332,47.1601],[-91.4331,47.1599],[-91.433,47.1598],[-91.433,47.1597],[-91.4332,47.1596],[-91.4335,47.1596],[-91.4337,47.1596],[-91.434,47.1594],[-91.4341,47.1593],[-91.4342,47.1593],[-91.4345,47.1594],[-91.4351,47.1594],[-91.4354,47.1596],[-91.4358,47.1596],[-91.4361,47.1596],[-91.4365,47.1595],[-91.4367,47.1593],[-91.437,47.1591],[-91.4371,47.1589],[-91.4373,47.1587],[-91.4373,47.1585],[-91.4372,47.1583],[-91.4372,47.1581],[-91.4373,47.1579],[-91.4374,47.1578],[-91.4374,47.1577],[-91.4373,47.1576],[-91.4373,47.1576],[-91.4369,47.1576],[-91.4366,47.1575],[-91.4365,47.1575],[-91.4365,47.1573],[-91.4365,47.1572],[-91.4364,47.1571],[-91.4365,47.157],[-91.4366,47.1569],[-91.4368,47.1569],[-91.437,47.1568],[-91.437,47.1567],[-91.4372,47.1566],[-91.4374,47.1566],[-91.4378,47.1566],[-91.4382,47.1566],[-91.4385,47.1565],[-91.4388,47.1564],[-91.4391,47.1561],[-91.4391,47.1561],[-91.4393,47.1558],[-91.4396,47.1555],[-91.4398,47.1553],[-91.4399,47.1551],[-91.4399,47.1549],[-91.4399,47.1548],[-91.4401,47.1546],[-91.4404,47.1545],[-91.4406,47.1544],[-91.4406,47.1542],[-91.4407,47.1541],[-91.4407,47.154],[-91.4407,47.1539],[-91.4407,47.1537],[-91.4407,47.1537],[-91.4408,47.1535],[-91.4411,47.1534],[-91.4413,47.1533],[-91.4415,47.1532],[-91.4415,47.1529],[-91.4418,47.1526],[-91.4423,47.1523],[-91.4426,47.1521],[-91.4427,47.1519],[-91.4428,47.1517],[-91.4429,47.1515],[-91.4428,47.1514],[-91.4429,47.1512],[-91.443,47.151],[-91.4433,47.1508],[-91.4435,47.1506],[-91.4436,47.1504],[-91.4439,47.1501],[-91.444,47.15],[-91.4445,47.15],[-91.4447,47.1498],[-91.4447,47.1497],[-91.4449,47.1495],[-91.4451,47.1493],[-91.4452,47.1491],[-91.4453,47.149],[-91.4454,47.1489],[-91.4457,47.1488],[-91.4458,47.1488],[-91.4459,47.1487],[-91.446,47.1486],[-91.446,47.1485],[-91.4459,47.1485],[-91.4458,47.1485],[-91.4458,47.1484],[-91.4458,47.1484],[-91.4458,47.1483],[-91.4459,47.1483],[-91.446,47.1484],[-91.446,47.1484],[-91.4461,47.1485],[-91.4462,47.1486],[-91.4463,47.1487],[-91.4464,47.1487],[-91.4465,47.1487],[-91.4466,47.1487],[-91.4468,47.1486],[-91.4471,47.1485],[-91.4474,47.1483],[-91.4476,47.1482],[-91.4477,47.1482],[-91.4478,47.1482],[-91.4479,47.1481],[-91.4479,47.1479],[-91.4479,47.1478],[-91.4479,47.1477],[-91.4479,47.1475],[-91.448,47.1474],[-91.4482,47.1474],[-91.4483,47.1471],[-91.4485,47.1469],[-91.4486,47.1467],[-91.4489,47.1465],[-91.4492,47.1464],[-91.4494,47.1463],[-91.4497,47.1462],[-91.4499,47.1462],[-91.4501,47.1461],[-91.4503,47.1461],[-91.4505,47.1461],[-91.4507,47.1461],[-91.4508,47.146],[-91.4509,47.1459],[-91.4518,47.1458],[-91.4523,47.1458],[-91.4525,47.1458],[-91.4528,47.1458],[-91.4528,47.1458],[-91.4532,47.1457],[-91.4534,47.1456],[-91.4537,47.1456],[-91.4539,47.1455],[-91.4541,47.1455],[-91.4542,47.1454],[-91.4542,47.1452],[-91.4543,47.145],[-91.4544,47.145],[-91.4544,47.1448],[-91.4545,47.1447],[-91.4546,47.1446],[-91.4546,47.1444],[-91.4547,47.1441],[-91.4549,47.144],[-91.455,47.1439],[-91.4552,47.1437],[-91.4554,47.1436],[-91.4556,47.1436],[-91.4559,47.1435],[-91.4561,47.1434],[-91.4563,47.1433],[-91.4564,47.1433],[-91.4565,47.1432],[-91.4566,47.1432],[-91.457,47.1429],[-91.4569,47.1428],[-91.457,47.1427],[-91.4569,47.1426],[-91.4568,47.1424],[-91.4564,47.1421],[-91.4563,47.1421],[-91.4562,47.142],[-91.456,47.142],[-91.4558,47.1419],[-91.4557,47.1418],[-91.4557,47.1416],[-91.4557,47.1416],[-91.4558,47.1415],[-91.4558,47.1414],[-91.4557,47.1413],[-91.4556,47.1412],[-91.4557,47.1411],[-91.4557,47.1409],[-91.4557,47.1406],[-91.4555,47.1406],[-91.4549,47.1405],[-91.4546,47.1405],[-91.4544,47.1405],[-91.4542,47.1404],[-91.4543,47.1403],[-91.4545,47.1401],[-91.4547,47.14],[-91.4548,47.1397],[-91.455,47.1397],[-91.4551,47.1397],[-91.4553,47.1397],[-91.4553,47.1396],[-91.4554,47.1394],[-91.4558,47.1392],[-91.4562,47.1391],[-91.4565,47.1389],[-91.4569,47.1387],[-91.4573,47.1385],[-91.4576,47.1384],[-91.4579,47.1383],[-91.4581,47.1383],[-91.4582,47.1382],[-91.4583,47.1381],[-91.4585,47.138],[-91.4588,47.1379],[-91.4589,47.1379],[-91.459,47.1379],[-91.4591,47.1379],[-91.4592,47.1378],[-91.4592,47.1376],[-91.4592,47.1375],[-91.459,47.1374],[-91.459,47.1373],[-91.4591,47.1372],[-91.4594,47.1372],[-91.4595,47.1371],[-91.4596,47.1371],[-91.4597,47.1369],[-91.4599,47.1369],[-91.4599,47.1369],[-91.46,47.1368],[-91.4601,47.1366],[-91.4602,47.1366],[-91.4603,47.1365],[-91.4602,47.1364],[-91.4601,47.1363],[-91.4602,47.1361],[-91.4603,47.136],[-91.4605,47.1359],[-91.4606,47.1356],[-91.4607,47.1354],[-91.4608,47.1352],[-91.4609,47.135],[-91.461,47.1349],[-91.461,47.1347],[-91.461,47.1345],[-91.4612,47.1344],[-91.4614,47.1344],[-91.4617,47.1345],[-91.462,47.1344],[-91.4623,47.1344],[-91.4626,47.1344],[-91.4628,47.1344],[-91.463,47.1342],[-91.4632,47.134],[-91.4633,47.1339],[-91.4634,47.1338],[-91.4635,47.1338],[-91.4636,47.1337],[-91.464,47.1336],[-91.4643,47.1336],[-91.4646,47.1335],[-91.4647,47.1334],[-91.4648,47.1332],[-91.4649,47.1331],[-91.465,47.133],[-91.4649,47.1326],[-91.4649,47.1325],[-91.4649,47.1324],[-91.4648,47.1322],[-91.4648,47.1321],[-91.465,47.1319],[-91.4651,47.1319],[-91.4653,47.1318],[-91.4654,47.1317],[-91.4654,47.1315],[-91.4656,47.1313],[-91.4657,47.1312],[-91.466,47.1312],[-91.4663,47.1313],[-91.4665,47.1314],[-91.4667,47.1316],[-91.4668,47.1317],[-91.467,47.1318],[-91.4672,47.1318],[-91.4676,47.1317],[-91.468,47.1316],[-91.4682,47.1315],[-91.4684,47.1314],[-91.4685,47.1312],[-91.4688,47.131],[-91.4689,47.1308],[-91.4691,47.1307],[-91.4694,47.1306],[-91.4696,47.1305],[-91.4699,47.1305],[-91.4701,47.1304],[-91.4703,47.1304],[-91.4705,47.1304],[-91.4706,47.1302],[-91.4708,47.1301],[-91.4709,47.1301],[-91.471,47.13],[-91.4711,47.1299],[-91.4711,47.1298],[-91.4712,47.1297],[-91.4713,47.1296],[-91.4715,47.1295],[-91.4717,47.1295],[-91.4719,47.1295],[-91.4728,47.1294],[-91.4731,47.1294],[-91.4732,47.1293],[-91.4733,47.1292],[-91.4734,47.1292],[-91.4737,47.1289],[-91.4738,47.1288],[-91.4738,47.1287],[-91.4739,47.1286],[-91.474,47.1285],[-91.4741,47.1284],[-91.4743,47.1284],[-91.4745,47.1285],[-91.4746,47.1285],[-91.4748,47.1285],[-91.475,47.1284],[-91.475,47.1282],[-91.4751,47.1281],[-91.4752,47.1279],[-91.4752,47.1277],[-91.4753,47.1275],[-91.4754,47.1273],[-91.4754,47.1273],[-91.4756,47.1271],[-91.4759,47.1269],[-91.476,47.1269],[-91.4762,47.1266],[-91.4765,47.1263],[-91.4766,47.1262],[-91.4768,47.126],[-91.4769,47.1258],[-91.4771,47.1257],[-91.4773,47.1255],[-91.4775,47.1254],[-91.4778,47.1253],[-91.4782,47.1252],[-91.4786,47.1252],[-91.4789,47.1252],[-91.4791,47.1251],[-91.4793,47.125],[-91.4794,47.125],[-91.4794,47.1249],[-91.4795,47.1249],[-91.4797,47.1248],[-91.4799,47.1247],[-91.48,47.1246],[-91.4801,47.1246],[-91.4803,47.1245],[-91.4804,47.1244],[-91.4805,47.1243],[-91.4807,47.1243],[-91.4809,47.1243],[-91.481,47.1243],[-91.4812,47.1243],[-91.4815,47.1244],[-91.4816,47.1245],[-91.4817,47.1245],[-91.4819,47.1245],[-91.4821,47.1245],[-91.4823,47.1245],[-91.4826,47.1246],[-91.4829,47.1246],[-91.4831,47.1246],[-91.4833,47.1245],[-91.4836,47.1245],[-91.4838,47.1245],[-91.4841,47.1246],[-91.4842,47.1246],[-91.4844,47.1247],[-91.4845,47.1247],[-91.4847,47.1248],[-91.4849,47.1249],[-91.485,47.125],[-91.4867,47.125],[-91.4867,47.125],[-91.4869,47.1249],[-91.4871,47.1249],[-91.4874,47.1248],[-91.4876,47.1248],[-91.4877,47.1247],[-91.4879,47.1245],[-91.488,47.1243],[-91.4881,47.1242],[-91.4883,47.124],[-91.4884,47.1239],[-91.4886,47.1238],[-91.4887,47.1238],[-91.4888,47.1238],[-91.489,47.1237],[-91.4891,47.1237],[-91.4893,47.1237],[-91.4895,47.1237],[-91.4898,47.1236],[-91.4899,47.1236],[-91.4901,47.1234],[-91.4902,47.1233],[-91.4903,47.1232],[-91.4905,47.1231],[-91.4906,47.1231],[-91.4907,47.1231],[-91.4908,47.1232],[-91.491,47.1232],[-91.4911,47.1233],[-91.4913,47.1233],[-91.4915,47.1234],[-91.4918,47.1234],[-91.492,47.1233],[-91.4922,47.1233],[-91.4924,47.1232],[-91.4927,47.1232],[-91.4928,47.1231],[-91.4929,47.123],[-91.493,47.1229],[-91.4931,47.123],[-91.4932,47.123],[-91.4933,47.123],[-91.4933,47.1231],[-91.4935,47.1232],[-91.4937,47.1232],[-91.494,47.1233],[-91.4942,47.1233],[-91.4945,47.1233],[-91.4947,47.1232],[-91.4949,47.1232],[-91.4952,47.1231],[-91.4953,47.123],[-91.4955,47.1229],[-91.4958,47.1228],[-91.496,47.1226],[-91.4962,47.1225],[-91.4963,47.1225],[-91.4964,47.1225],[-91.4965,47.1225],[-91.4967,47.1226],[-91.4968,47.1227],[-91.497,47.1228],[-91.4972,47.1228],[-91.4973,47.1228],[-91.4975,47.1227],[-91.4977,47.1227],[-91.4979,47.1226],[-91.4981,47.1225],[-91.4983,47.1224],[-91.4985,47.1224],[-91.4986,47.1223],[-91.4987,47.1223],[-91.4988,47.1222],[-91.4989,47.1221],[-91.4991,47.1219],[-91.4993,47.1218],[-91.4997,47.1217],[-91.5,47.1216],[-91.5001,47.1215],[-91.5002,47.1214],[-91.5003,47.1213],[-91.5004,47.1212],[-91.5005,47.1211],[-91.5007,47.1209],[-91.5008,47.1207],[-91.5012,47.1205],[-91.5013,47.1203],[-91.5015,47.1201],[-91.5018,47.1199],[-91.502,47.1196],[-91.5024,47.1194],[-91.5026,47.1193],[-91.5029,47.1192],[-91.5031,47.1192],[-91.5033,47.1191],[-91.5034,47.1192],[-91.5035,47.1192],[-91.5035,47.1192],[-91.5036,47.1192],[-91.5038,47.1192],[-91.5041,47.1192],[-91.5045,47.1192],[-91.5049,47.1192],[-91.5051,47.1191],[-91.5054,47.1192],[-91.5057,47.1192],[-91.5061,47.1191],[-91.5064,47.119],[-91.5067,47.1189],[-91.5069,47.1187],[-91.507,47.1186],[-91.5072,47.1182],[-91.5073,47.1178],[-91.5073,47.1176],[-91.5074,47.1174],[-91.5076,47.1172],[-91.5077,47.1169],[-91.5078,47.1168],[-91.508,47.1167],[-91.5084,47.1164],[-91.5088,47.1162],[-91.5091,47.1161],[-91.5095,47.1161],[-91.5099,47.116],[-91.5101,47.1159],[-91.5104,47.1159],[-91.5106,47.1158],[-91.5109,47.1157],[-91.511,47.1156],[-91.5111,47.1155],[-91.5112,47.1154],[-91.5113,47.1153],[-91.5116,47.1151],[-91.5119,47.1149],[-91.5121,47.1146],[-91.5123,47.1143],[-91.5124,47.1142],[-91.5125,47.114],[-91.5127,47.1138],[-91.5128,47.1138],[-91.5129,47.1138],[-91.513,47.1138],[-91.5132,47.1136],[-91.5133,47.1135],[-91.5134,47.1134],[-91.5135,47.1133],[-91.5136,47.1132],[-91.5136,47.1132],[-91.5136,47.1131],[-91.5137,47.113],[-91.5137,47.1128],[-91.5138,47.1127],[-91.5138,47.1125],[-91.5139,47.1124],[-91.514,47.1123],[-91.5141,47.1122],[-91.5142,47.1121],[-91.5144,47.1121],[-91.5145,47.112],[-91.5146,47.1119],[-91.5146,47.1119],[-91.5147,47.1118],[-91.5148,47.1117],[-91.515,47.1116],[-91.5152,47.1114],[-91.5153,47.1113],[-91.5154,47.1113],[-91.5155,47.1112],[-91.5157,47.1109],[-91.516,47.1106],[-91.5164,47.1103],[-91.5169,47.1099],[-91.5171,47.1097],[-91.5173,47.1096],[-91.5174,47.1095],[-91.5175,47.1094],[-91.5175,47.1094],[-91.5176,47.1094],[-91.5176,47.1093],[-91.5176,47.1093],[-91.5177,47.1092],[-91.5178,47.1091],[-91.518,47.1087],[-91.5181,47.1085],[-91.5181,47.1084],[-91.5181,47.1083],[-91.5181,47.108],[-91.5181,47.1078],[-91.5181,47.1076],[-91.5181,47.1075],[-91.5181,47.1075],[-91.5181,47.1073],[-91.5181,47.1072],[-91.5181,47.1069],[-91.5181,47.1067],[-91.5182,47.1066],[-91.5184,47.1065],[-91.5184,47.1064],[-91.5183,47.1063],[-91.5185,47.1063],[-91.5185,47.1061],[-91.5186,47.106],[-91.5188,47.1059],[-91.5189,47.1058],[-91.519,47.1058],[-91.5193,47.1058],[-91.5194,47.1057],[-91.5195,47.1057],[-91.5196,47.1055],[-91.5199,47.1052],[-91.52,47.1049],[-91.5202,47.1048],[-91.5203,47.1047],[-91.5203,47.1046],[-91.5204,47.1046],[-91.5206,47.1046],[-91.5207,47.1045],[-91.5208,47.1044],[-91.5212,47.1041],[-91.5214,47.104],[-91.5215,47.104],[-91.5216,47.1039],[-91.5217,47.1039],[-91.5218,47.104],[-91.5219,47.104],[-91.5221,47.104],[-91.5222,47.1041],[-91.5223,47.1041],[-91.5224,47.1041],[-91.5226,47.1041],[-91.5229,47.1041],[-91.5229,47.1041],[-91.523,47.1041],[-91.523,47.1041],[-91.523,47.104],[-91.5231,47.104],[-91.5232,47.1039],[-91.5233,47.1039],[-91.5234,47.1039],[-91.5235,47.1039],[-91.5236,47.1039],[-91.5236,47.1039],[-91.5237,47.1039],[-91.5238,47.1039],[-91.5238,47.1039],[-91.5238,47.1039],[-91.5239,47.1038],[-91.5239,47.1037],[-91.5239,47.1037],[-91.5239,47.1036],[-91.5239,47.1036],[-91.5239,47.1035],[-91.5239,47.1034],[-91.524,47.1034],[-91.524,47.1034],[-91.5241,47.1034],[-91.5242,47.1034],[-91.5243,47.1034],[-91.5244,47.1035],[-91.5246,47.1035],[-91.525,47.1037],[-91.5251,47.1038],[-91.5252,47.1038],[-91.5254,47.1039],[-91.5255,47.1039],[-91.5256,47.1039],[-91.5257,47.104],[-91.5258,47.104],[-91.5262,47.104],[-91.5265,47.1039],[-91.5266,47.1039],[-91.5268,47.1038],[-91.5269,47.1038],[-91.527,47.1037],[-91.5271,47.1036],[-91.5271,47.1036],[-91.5272,47.1035],[-91.5273,47.1035],[-91.5277,47.1033],[-91.528,47.1031],[-91.5285,47.1029],[-91.5287,47.1028],[-91.5289,47.1027],[-91.5291,47.1026],[-91.5292,47.1025],[-91.5294,47.1024],[-91.5296,47.1024],[-91.5298,47.1024],[-91.5299,47.1024],[-91.5301,47.1024],[-91.5304,47.1024],[-91.5306,47.1025],[-91.5309,47.1025],[-91.5312,47.1025],[-91.5315,47.1025],[-91.5318,47.1024],[-91.532,47.1025],[-91.5322,47.1025],[-91.5323,47.1024],[-91.5323,47.1024],[-91.5326,47.1024],[-91.5327,47.1024],[-91.5329,47.1025],[-91.5332,47.1026],[-91.5334,47.1027],[-91.5336,47.1027],[-91.5337,47.1028],[-91.5339,47.1028],[-91.5343,47.1028],[-91.5348,47.1027],[-91.5352,47.1027],[-91.5354,47.1027],[-91.5358,47.1027],[-91.5361,47.1027],[-91.5364,47.1027],[-91.5368,47.1027],[-91.537,47.1027],[-91.5373,47.1026],[-91.5376,47.1024],[-91.538,47.1022],[-91.5383,47.102],[-91.5386,47.1019],[-91.5389,47.1018],[-91.5391,47.1018],[-91.5393,47.1018],[-91.5394,47.1018],[-91.5395,47.1018],[-91.5396,47.1017],[-91.5396,47.1017],[-91.5397,47.1017],[-91.5397,47.1016],[-91.5398,47.1015],[-91.5398,47.1015],[-91.5398,47.1014],[-91.5398,47.1013],[-91.5397,47.1011],[-91.5396,47.101],[-91.5396,47.1009],[-91.5395,47.1008],[-91.5395,47.1006],[-91.5395,47.1006],[-91.5396,47.1005],[-91.5397,47.1005],[-91.5398,47.1005],[-91.5399,47.1004],[-91.54,47.1004],[-91.54,47.1003],[-91.54,47.1002],[-91.54,47.1002],[-91.54,47.1001],[-91.54,47.1],[-91.54,47.0999],[-91.54,47.0999],[-91.5401,47.0999],[-91.5401,47.0998],[-91.5402,47.0998],[-91.5402,47.0998],[-91.5403,47.0999],[-91.5404,47.0999],[-91.5405,47.0999],[-91.5405,47.0999],[-91.5406,47.0998],[-91.5407,47.0998],[-91.5408,47.0997],[-91.5409,47.0995],[-91.5409,47.0993],[-91.541,47.0992],[-91.541,47.099],[-91.541,47.0989],[-91.541,47.0988],[-91.541,47.0988],[-91.5409,47.0987],[-91.5409,47.0987],[-91.5409,47.0986],[-91.5409,47.0986],[-91.5409,47.0986],[-91.5409,47.0985],[-91.541,47.0985],[-91.541,47.0985],[-91.5411,47.0985],[-91.5412,47.0986],[-91.5412,47.0986],[-91.5413,47.0987],[-91.5414,47.0987],[-91.5414,47.0988],[-91.5415,47.0988],[-91.5418,47.0989],[-91.542,47.099],[-91.5422,47.099],[-91.5425,47.099],[-91.5427,47.099],[-91.5428,47.0989],[-91.5429,47.0989],[-91.543,47.099],[-91.5431,47.099],[-91.5431,47.099],[-91.5432,47.0991],[-91.5433,47.0992],[-91.5434,47.0992],[-91.5435,47.0992],[-91.5437,47.0992],[-91.5438,47.0992],[-91.5439,47.0991],[-91.544,47.099],[-91.5441,47.099],[-91.5442,47.099],[-91.5443,47.099],[-91.5444,47.099],[-91.5444,47.099],[-91.5444,47.0991],[-91.5444,47.0991],[-91.5444,47.0992],[-91.5445,47.0993],[-91.5445,47.0993],[-91.5446,47.0994],[-91.5447,47.0994],[-91.5448,47.0994],[-91.5448,47.0994],[-91.5449,47.0995],[-91.545,47.0994],[-91.5453,47.0994],[-91.5457,47.0992],[-91.5461,47.099],[-91.5462,47.0989],[-91.5464,47.0988],[-91.5464,47.0988],[-91.5466,47.0986],[-91.5469,47.098],[-91.5471,47.0978],[-91.5472,47.0977],[-91.5474,47.0976],[-91.5476,47.0975],[-91.5477,47.0973],[-91.5477,47.0971],[-91.5478,47.097],[-91.5479,47.0969],[-91.5479,47.0969],[-91.5479,47.0968],[-91.5479,47.0966],[-91.5479,47.0965],[-91.548,47.0963],[-91.5482,47.0961],[-91.5485,47.0961],[-91.549,47.0961],[-91.5495,47.096],[-91.5497,47.0958],[-91.5499,47.0957],[-91.55,47.0956],[-91.55,47.0955],[-91.55,47.0954],[-91.5501,47.0954],[-91.5502,47.0954],[-91.5503,47.0955],[-91.5504,47.0955],[-91.5504,47.0953],[-91.5504,47.0953],[-91.5503,47.0952],[-91.5502,47.0951],[-91.5501,47.095],[-91.5502,47.0949],[-91.5502,47.0949],[-91.5503,47.0948],[-91.5503,47.0948],[-91.5501,47.0946],[-91.5499,47.0943],[-91.5498,47.0941],[-91.5497,47.094],[-91.5496,47.0939],[-91.5497,47.0937],[-91.5497,47.0936],[-91.5497,47.0935],[-91.5498,47.0935],[-91.5499,47.0935],[-91.5499,47.0935],[-91.55,47.0936],[-91.5501,47.0936],[-91.5502,47.0936],[-91.5503,47.0936],[-91.5505,47.0935],[-91.5506,47.0935],[-91.5507,47.0934],[-91.5509,47.0934],[-91.5511,47.0935],[-91.5512,47.0935],[-91.5513,47.0935],[-91.5514,47.0935],[-91.5516,47.0935],[-91.5518,47.0934],[-91.5521,47.0934],[-91.5523,47.0933],[-91.5525,47.0933],[-91.5526,47.0933],[-91.5528,47.0933],[-91.553,47.0934],[-91.5532,47.0934],[-91.5534,47.0936],[-91.5535,47.0937],[-91.5535,47.0938],[-91.5536,47.0939],[-91.5536,47.0939],[-91.5537,47.0939],[-91.5539,47.094],[-91.554,47.094],[-91.5542,47.0941],[-91.5546,47.0941],[-91.5557,47.0943],[-91.5563,47.0944],[-91.5568,47.0945],[-91.5575,47.0945],[-91.5581,47.0944],[-91.5586,47.0944],[-91.5593,47.0944],[-91.5598,47.0944],[-91.5602,47.0944],[-91.5608,47.0943],[-91.5612,47.0942],[-91.5612,47.0941],[-91.5614,47.0941],[-91.5616,47.0941],[-91.5619,47.0939],[-91.563,47.0936],[-91.5637,47.0933],[-91.5641,47.0931],[-91.5644,47.093],[-91.5645,47.0928],[-91.5649,47.0927],[-91.5651,47.0926],[-91.5653,47.0926],[-91.5658,47.0926],[-91.566,47.0926],[-91.5664,47.0926],[-91.5666,47.0926],[-91.5667,47.0926],[-91.5669,47.0925],[-91.567,47.0924],[-91.5674,47.0924],[-91.5677,47.0924],[-91.5681,47.0924],[-91.5684,47.0924],[-91.5686,47.0924],[-91.5688,47.0924],[-91.569,47.0923],[-91.5692,47.0922],[-91.5692,47.0921],[-91.5694,47.0921],[-91.5696,47.092],[-91.5698,47.0919],[-91.5703,47.0915],[-91.5708,47.0912],[-91.5712,47.091],[-91.5718,47.0909],[-91.572,47.0908],[-91.5724,47.0907],[-91.5728,47.0904],[-91.573,47.0903],[-91.5735,47.0901],[-91.5739,47.0898],[-91.5744,47.0895],[-91.5748,47.0892],[-91.5751,47.0889],[-91.5752,47.0886],[-91.5753,47.0885],[-91.5753,47.0884],[-91.5755,47.0881],[-91.5756,47.088],[-91.5758,47.0876],[-91.5761,47.0871],[-91.5761,47.0868],[-91.5763,47.0866],[-91.5764,47.0863],[-91.5767,47.0856],[-91.5768,47.0853],[-91.5769,47.0851],[-91.5771,47.085],[-91.5771,47.0848],[-91.5771,47.0847],[-91.5771,47.0846],[-91.5772,47.0845],[-91.5774,47.0845],[-91.5775,47.0845],[-91.5775,47.0846],[-91.5776,47.0847],[-91.578,47.0847],[-91.5784,47.0846],[-91.5786,47.0845],[-91.5787,47.0843],[-91.5788,47.0843],[-91.5788,47.0841],[-91.5789,47.0838],[-91.5789,47.0837],[-91.579,47.0837],[-91.5792,47.0836],[-91.5793,47.0834],[-91.5794,47.0833],[-91.5795,47.0832],[-91.5797,47.083],[-91.5799,47.0828],[-91.5799,47.0827],[-91.58,47.0824],[-91.5802,47.0821],[-91.5803,47.0819],[-91.5805,47.0818],[-91.5807,47.0818],[-91.5809,47.0816],[-91.5811,47.0814],[-91.5812,47.0813],[-91.5813,47.0813],[-91.5814,47.0813],[-91.5816,47.0812],[-91.5816,47.0812],[-91.5818,47.0811],[-91.5821,47.0809],[-91.5823,47.0807],[-91.5825,47.0806],[-91.5825,47.0806],[-91.5828,47.0801],[-91.5831,47.0799],[-91.5834,47.0797],[-91.5836,47.0794],[-91.5838,47.0793],[-91.5839,47.079],[-91.5841,47.0787],[-91.5842,47.0786],[-91.5843,47.0786],[-91.5843,47.0785],[-91.5844,47.0782],[-91.5845,47.078],[-91.5847,47.0776],[-91.5849,47.0772],[-91.5849,47.0769],[-91.5849,47.0766],[-91.585,47.0764],[-91.5851,47.0763],[-91.585,47.0762],[-91.585,47.0761],[-91.5849,47.076],[-91.5848,47.0759],[-91.5847,47.0759],[-91.5847,47.0758],[-91.5846,47.0758],[-91.5845,47.0758],[-91.5845,47.0758],[-91.5844,47.0758],[-91.5843,47.0758],[-91.5843,47.0758],[-91.5843,47.0757],[-91.5843,47.0757],[-91.5843,47.0755],[-91.5843,47.0755],[-91.5843,47.0753],[-91.5844,47.0752],[-91.5844,47.0751],[-91.5844,47.0751],[-91.5844,47.075],[-91.5844,47.0749],[-91.5845,47.0749],[-91.5846,47.0749],[-91.5846,47.0749],[-91.5846,47.075],[-91.5847,47.0751],[-91.5847,47.0751],[-91.5848,47.0751],[-91.5849,47.0751],[-91.5849,47.075],[-91.585,47.0748],[-91.5851,47.0747],[-91.5851,47.0746],[-91.5851,47.0744],[-91.5851,47.0743],[-91.585,47.0742],[-91.5849,47.0741],[-91.5847,47.074],[-91.5846,47.0739],[-91.5845,47.0738],[-91.5845,47.0736],[-91.5846,47.0734],[-91.5847,47.0733],[-91.5847,47.0733],[-91.5848,47.0732],[-91.585,47.0732],[-91.5851,47.0731],[-91.5852,47.073],[-91.5853,47.0729],[-91.5854,47.0729],[-91.5854,47.0728],[-91.5854,47.0728],[-91.5855,47.0727],[-91.5856,47.0727],[-91.5857,47.0728],[-91.5858,47.0727],[-91.5858,47.0726],[-91.5858,47.0725],[-91.586,47.0724],[-91.5861,47.0724],[-91.5864,47.0724],[-91.5865,47.0724],[-91.5865,47.0724],[-91.5866,47.0722],[-91.5867,47.072],[-91.5869,47.0719],[-91.5874,47.0718],[-91.5879,47.0717],[-91.5883,47.0716],[-91.5887,47.0715],[-91.5889,47.0714],[-91.5893,47.0712],[-91.5896,47.071],[-91.5899,47.0708],[-91.59,47.0706],[-91.5903,47.0703],[-91.5905,47.0702],[-91.5908,47.07],[-91.5909,47.0698],[-91.5911,47.0697],[-91.5913,47.0693],[-91.5914,47.069],[-91.5915,47.0687],[-91.5917,47.0685],[-91.5919,47.0682],[-91.5921,47.0678],[-91.5923,47.0675],[-91.5925,47.0673],[-91.5926,47.0671],[-91.5928,47.0668],[-91.5929,47.0665],[-91.5931,47.0663],[-91.5934,47.0661],[-91.5938,47.0659],[-91.5941,47.0657],[-91.5942,47.0656],[-91.5945,47.0654],[-91.5947,47.0652],[-91.5948,47.0649],[-91.5947,47.0646],[-91.5947,47.0642],[-91.5947,47.0639],[-91.5947,47.0637],[-91.5947,47.0636],[-91.5947,47.0635],[-91.5947,47.0634],[-91.5946,47.0633],[-91.5945,47.0633],[-91.5944,47.0632],[-91.5943,47.0631],[-91.5944,47.063],[-91.5944,47.0629],[-91.5944,47.0628],[-91.5945,47.0626],[-91.5946,47.0626],[-91.5949,47.0625],[-91.5954,47.0623],[-91.5956,47.0623],[-91.596,47.0623],[-91.5964,47.0623],[-91.5966,47.0624],[-91.5969,47.0624],[-91.5971,47.0623],[-91.5974,47.0622],[-91.5976,47.0621],[-91.5977,47.0622],[-91.5978,47.0623],[-91.598,47.0623],[-91.5981,47.0623],[-91.5985,47.0623],[-91.5989,47.0624],[-91.5992,47.0625],[-91.5995,47.0627],[-91.5998,47.0629],[-91.6,47.0632],[-91.6002,47.0634],[-91.6003,47.0635],[-91.6006,47.0636],[-91.601,47.0637],[-91.6014,47.0638],[-91.6016,47.0638],[-91.6019,47.0639],[-91.6022,47.0639],[-91.6024,47.064],[-91.6026,47.064],[-91.603,47.064],[-91.6031,47.064],[-91.6032,47.0639],[-91.6032,47.0639],[-91.6034,47.0638],[-91.6035,47.0637],[-91.6037,47.0637],[-91.6038,47.0636],[-91.604,47.0636],[-91.6041,47.0635],[-91.6043,47.0633],[-91.6045,47.0633],[-91.6046,47.0632],[-91.6048,47.0632],[-91.6051,47.0631],[-91.6053,47.063],[-91.6055,47.0629],[-91.6057,47.0628],[-91.6058,47.0627],[-91.6059,47.0626],[-91.606,47.0626],[-91.6061,47.0625],[-91.6062,47.0624],[-91.6062,47.0624],[-91.6064,47.0623],[-91.6066,47.0622],[-91.6072,47.0621],[-91.6078,47.062],[-91.6082,47.0619],[-91.6088,47.0617],[-91.6092,47.0615],[-91.6095,47.0613],[-91.6099,47.0611],[-91.6101,47.061],[-91.6103,47.0609],[-91.6104,47.0609],[-91.6104,47.0608],[-91.6105,47.0607],[-91.6105,47.0607],[-91.6112,47.0603],[-91.6117,47.0601],[-91.6121,47.0599],[-91.6126,47.0596],[-91.6129,47.0594],[-91.6131,47.0592],[-91.6132,47.0592],[-91.6134,47.0591],[-91.6136,47.059],[-91.6138,47.0589],[-91.6139,47.0588],[-91.6139,47.0588],[-91.6143,47.0585],[-91.6146,47.0583],[-91.6148,47.0581],[-91.615,47.0578],[-91.6154,47.0572],[-91.6157,47.0569],[-91.616,47.0568],[-91.6163,47.0566],[-91.6164,47.0565],[-91.6165,47.0565],[-91.6169,47.0564],[-91.6174,47.0563],[-91.6176,47.0562],[-91.6178,47.056],[-91.6181,47.0557],[-91.6183,47.0554],[-91.6186,47.0553],[-91.6187,47.0552],[-91.6188,47.055],[-91.6188,47.055],[-91.6189,47.0547],[-91.6191,47.0545],[-91.6192,47.0544],[-91.6192,47.0543],[-91.6192,47.0542],[-91.6192,47.0542],[-91.6192,47.0541],[-91.6192,47.054],[-91.6193,47.0539],[-91.6193,47.0538],[-91.6194,47.0537],[-91.6194,47.0535],[-91.6195,47.0533],[-91.6196,47.0532],[-91.6197,47.0532],[-91.6198,47.0531],[-91.6199,47.0531],[-91.6201,47.0529],[-91.6205,47.0526],[-91.6209,47.0522],[-91.6214,47.0516],[-91.6218,47.0512],[-91.6221,47.051],[-91.6226,47.0509],[-91.6231,47.0508],[-91.6236,47.0507],[-91.6242,47.0507],[-91.6243,47.0507],[-91.6246,47.0506],[-91.6247,47.0505],[-91.6248,47.0505],[-91.6249,47.0504],[-91.6251,47.0502],[-91.6254,47.0501],[-91.6255,47.0499],[-91.6257,47.0498],[-91.6259,47.0497],[-91.6261,47.0497],[-91.6267,47.0498],[-91.6269,47.0498],[-91.6271,47.0497],[-91.6273,47.0497],[-91.6275,47.0495],[-91.628,47.0492],[-91.6289,47.0484],[-91.6295,47.0478],[-91.6298,47.0477],[-91.6302,47.0475],[-91.6303,47.0475],[-91.6305,47.0473],[-91.6308,47.0469],[-91.6309,47.0467],[-91.6311,47.0464],[-91.6312,47.0463],[-91.6314,47.046],[-91.6315,47.046],[-91.6315,47.046],[-91.6316,47.0458],[-91.6317,47.0455],[-91.6318,47.045],[-91.6318,47.0448],[-91.6322,47.0446],[-91.6323,47.0445],[-91.6323,47.0445],[-91.6325,47.0442],[-91.6326,47.0441],[-91.6326,47.044],[-91.6326,47.044],[-91.6331,47.0436],[-91.6334,47.0435],[-91.6335,47.0435],[-91.6336,47.0435],[-91.6338,47.0434],[-91.6341,47.0434],[-91.6341,47.0433],[-91.6346,47.0432],[-91.6348,47.0431],[-91.6348,47.0431],[-91.6349,47.043],[-91.6349,47.043],[-91.6352,47.0427],[-91.6356,47.0421],[-91.6357,47.0418],[-91.6358,47.0414],[-91.6357,47.0412],[-91.6357,47.041],[-91.6356,47.0409],[-91.6357,47.0406],[-91.6358,47.0406],[-91.636,47.0405],[-91.6361,47.0405],[-91.6364,47.0405],[-91.6366,47.0405],[-91.6372,47.0403],[-91.6374,47.0403],[-91.638,47.0403],[-91.6388,47.0403],[-91.6396,47.04],[-91.6403,47.0397],[-91.6407,47.0394],[-91.6412,47.0389],[-91.6417,47.0385],[-91.6421,47.0378],[-91.6422,47.0376],[-91.6424,47.0369],[-91.6425,47.0363],[-91.6424,47.0355],[-91.6423,47.0351],[-91.642,47.0345],[-91.6418,47.0344],[-91.6415,47.0343],[-91.6413,47.0343],[-91.6412,47.0343],[-91.6406,47.0343],[-91.6405,47.0342],[-91.6399,47.0342],[-91.6396,47.0343],[-91.6395,47.0343],[-91.6391,47.0343],[-91.6385,47.0343],[-91.6384,47.0343],[-91.6382,47.0342],[-91.6381,47.034],[-91.638,47.0339],[-91.6376,47.0339],[-91.6373,47.0338],[-91.6372,47.0337],[-91.6371,47.0337],[-91.6372,47.0336],[-91.6374,47.0334],[-91.6375,47.0334],[-91.6376,47.0334],[-91.6378,47.0333],[-91.6382,47.0332],[-91.6385,47.0329],[-91.6385,47.0328],[-91.6385,47.0327],[-91.6385,47.0325],[-91.6386,47.0324],[-91.6387,47.0322],[-91.6388,47.0321],[-91.6388,47.0319],[-91.6387,47.0317],[-91.6386,47.0316],[-91.6385,47.0315],[-91.6384,47.0315],[-91.6383,47.0315],[-91.638,47.0315],[-91.6379,47.0315],[-91.6378,47.0315],[-91.6376,47.0315],[-91.6374,47.0313],[-91.6369,47.0313],[-91.6367,47.0312],[-91.6364,47.0313],[-91.6362,47.0313],[-91.6361,47.0313],[-91.636,47.0311],[-91.6358,47.0308],[-91.6357,47.0307],[-91.6357,47.0306],[-91.6357,47.0301],[-91.6358,47.0299],[-91.6361,47.0294],[-91.6363,47.0292],[-91.6364,47.0292],[-91.6365,47.0291],[-91.6366,47.029],[-91.6367,47.0289],[-91.6368,47.0287],[-91.6368,47.0287],[-91.637,47.0284],[-91.637,47.0281],[-91.6369,47.028],[-91.6369,47.028],[-91.6367,47.0279],[-91.6365,47.0278],[-91.6364,47.0278],[-91.6363,47.0277],[-91.6364,47.0276],[-91.6366,47.0274],[-91.6366,47.0274],[-91.6367,47.0273],[-91.6367,47.0273],[-91.6368,47.0272],[-91.637,47.027],[-91.6371,47.027],[-91.6379,47.0267],[-91.6381,47.0267],[-91.6385,47.0266],[-91.6388,47.0266],[-91.6389,47.0266],[-91.6391,47.0268],[-91.6396,47.0268],[-91.6401,47.0268],[-91.6406,47.0265],[-91.6411,47.0262],[-91.6415,47.026],[-91.6419,47.026],[-91.6422,47.0259],[-91.6425,47.0259],[-91.6427,47.026],[-91.643,47.0263],[-91.6432,47.0263],[-91.6436,47.0264],[-91.6442,47.0263],[-91.6452,47.0259],[-91.6453,47.0259],[-91.6458,47.0259],[-91.6459,47.0259],[-91.6461,47.0261],[-91.6461,47.0261],[-91.6465,47.0268],[-91.6466,47.0269],[-91.6468,47.0271],[-91.6469,47.0272],[-91.6472,47.0273],[-91.6476,47.0275],[-91.6477,47.0277],[-91.6479,47.0279],[-91.648,47.0279],[-91.6485,47.0284],[-91.6485,47.0285],[-91.6487,47.0287],[-91.6491,47.0289],[-91.6494,47.029],[-91.6497,47.0292],[-91.6502,47.0294],[-91.6512,47.0296],[-91.6526,47.0295],[-91.6531,47.0294],[-91.6531,47.0294],[-91.6543,47.0292],[-91.6545,47.0291],[-91.6546,47.0291],[-91.6549,47.029],[-91.6553,47.0289],[-91.6556,47.0288],[-91.6562,47.0286],[-91.6564,47.0285],[-91.6573,47.0281],[-91.6575,47.0279],[-91.6578,47.0277],[-91.6581,47.0276],[-91.6586,47.0272],[-91.6591,47.027],[-91.6594,47.0269],[-91.6596,47.0267],[-91.6605,47.0258],[-91.6606,47.0257],[-91.6608,47.0254],[-91.6609,47.0252],[-91.661,47.0251],[-91.661,47.0251],[-91.6611,47.0249],[-91.6611,47.0248],[-91.6612,47.0246],[-91.6611,47.0245],[-91.6611,47.0243],[-91.6611,47.0243],[-91.6611,47.0243],[-91.6609,47.0241],[-91.6607,47.024],[-91.6606,47.024],[-91.6599,47.024],[-91.6596,47.0239],[-91.6594,47.0237],[-91.6594,47.0237],[-91.6595,47.0236],[-91.6597,47.0235],[-91.6598,47.0234],[-91.6598,47.0232],[-91.6598,47.023],[-91.6598,47.023],[-91.6598,47.0229],[-91.6598,47.0229],[-91.6598,47.0224],[-91.6597,47.022],[-91.6597,47.0219],[-91.6598,47.0214],[-91.66,47.0212],[-91.6601,47.021],[-91.6601,47.0209],[-91.6601,47.0207],[-91.6601,47.0206],[-91.66,47.0205],[-91.6598,47.0204],[-91.6597,47.0203],[-91.6598,47.0201],[-91.6599,47.0201],[-91.6599,47.02],[-91.6599,47.02],[-91.66,47.0199],[-91.66,47.0198],[-91.6601,47.0196],[-91.6601,47.0194],[-91.6601,47.0193],[-91.6599,47.0192],[-91.6599,47.0191],[-91.6599,47.0191],[-91.6598,47.019],[-91.6595,47.0189],[-91.6595,47.0188],[-91.6597,47.0185],[-91.6599,47.0183],[-91.6602,47.0182],[-91.6605,47.0179],[-91.6606,47.0178],[-91.6607,47.0178],[-91.6607,47.0178],[-91.6609,47.0176],[-91.661,47.0175],[-91.661,47.0172],[-91.661,47.017],[-91.6607,47.0168],[-91.6606,47.0167],[-91.6603,47.0165],[-91.6603,47.0162],[-91.6604,47.016],[-91.6604,47.016],[-91.6605,47.016],[-91.6605,47.0159],[-91.6605,47.0157],[-91.6605,47.0155],[-91.6604,47.0153],[-91.6605,47.0153],[-91.6605,47.0152],[-91.6606,47.0152],[-91.661,47.0149],[-91.6612,47.0146],[-91.6613,47.0145],[-91.6613,47.0145],[-91.6616,47.0144],[-91.6616,47.0144],[-91.6619,47.0142],[-91.6622,47.014],[-91.6622,47.0139],[-91.6623,47.0138],[-91.6625,47.0135],[-91.6626,47.0134],[-91.663,47.0132],[-91.6632,47.0132],[-91.6633,47.0131],[-91.6635,47.013],[-91.6636,47.0129],[-91.6638,47.0129],[-91.664,47.013],[-91.6642,47.0132],[-91.6645,47.0135],[-91.6647,47.0136],[-91.6649,47.0137],[-91.6653,47.0137],[-91.6656,47.0138],[-91.6657,47.0141],[-91.6658,47.0142],[-91.6658,47.0144],[-91.6658,47.0146],[-91.6657,47.0155],[-91.6657,47.0157],[-91.6659,47.0159],[-91.666,47.0159],[-91.6665,47.0162],[-91.6669,47.0165],[-91.667,47.0165],[-91.6673,47.0166],[-91.6676,47.0166],[-91.6681,47.0166],[-91.6684,47.0165],[-91.6685,47.0164],[-91.6685,47.0163],[-91.6683,47.016],[-91.6682,47.0158],[-91.6682,47.0157],[-91.6683,47.0157],[-91.6683,47.0157],[-91.6684,47.0157],[-91.6684,47.0157],[-91.6687,47.016],[-91.6687,47.0161],[-91.6688,47.0163],[-91.6688,47.0164],[-91.6689,47.0165],[-91.6691,47.017],[-91.6693,47.0171],[-91.6693,47.0172],[-91.6695,47.0172],[-91.6696,47.0172],[-91.6696,47.0172],[-91.6695,47.017],[-91.6693,47.0166],[-91.6692,47.0163],[-91.6693,47.0163],[-91.6694,47.0163],[-91.6694,47.0164],[-91.6695,47.0165],[-91.6698,47.017],[-91.6699,47.0171],[-91.6701,47.0171],[-91.6704,47.0171],[-91.6708,47.0171],[-91.6715,47.0172],[-91.6732,47.0172],[-91.6736,47.0173],[-91.674,47.0174],[-91.6744,47.0175],[-91.6754,47.0176],[-91.6758,47.0175],[-91.6759,47.0175],[-91.6758,47.0174],[-91.6755,47.0173],[-91.6743,47.0169],[-91.6736,47.0166],[-91.671,47.0157],[-91.6709,47.0157],[-91.6709,47.0156],[-91.671,47.0155],[-91.6711,47.0155],[-91.673,47.0161],[-91.6762,47.0173],[-91.6762,47.0173],[-91.6765,47.0171],[-91.6766,47.017],[-91.6766,47.0169],[-91.6763,47.0168],[-91.6761,47.0167],[-91.6721,47.0153],[-91.6714,47.0151],[-91.6714,47.015],[-91.6714,47.015],[-91.6716,47.0148],[-91.6717,47.0149],[-91.6764,47.0166],[-91.6766,47.0166],[-91.6767,47.0167],[-91.6768,47.0167],[-91.6769,47.0166],[-91.6772,47.0163],[-91.6773,47.0162],[-91.6775,47.0158],[-91.6775,47.0157],[-91.6778,47.0153],[-91.6779,47.0151],[-91.6781,47.0148],[-91.6781,47.0148],[-91.6746,47.0137],[-91.6742,47.0136],[-91.6741,47.0136],[-91.6741,47.0136],[-91.674,47.0135],[-91.6741,47.0133],[-91.6742,47.0133],[-91.6743,47.0134],[-91.6782,47.0146],[-91.6784,47.0146],[-91.6785,47.0145],[-91.6785,47.0145],[-91.6785,47.0143],[-91.6783,47.014],[-91.6783,47.0139],[-91.6783,47.0137],[-91.6784,47.0135],[-91.6787,47.0131],[-91.6789,47.0127],[-91.679,47.0123],[-91.679,47.0121],[-91.679,47.0116],[-91.679,47.0112],[-91.679,47.0112],[-91.679,47.0112],[-91.6791,47.0111],[-91.6791,47.011],[-91.6791,47.011],[-91.6793,47.0108],[-91.6795,47.0106],[-91.6799,47.0103],[-91.6801,47.0102],[-91.6803,47.01],[-91.6805,47.0099],[-91.6807,47.0098],[-91.6808,47.0098],[-91.681,47.0097],[-91.6814,47.0093],[-91.682,47.0088],[-91.6821,47.0087],[-91.6822,47.0087],[-91.6827,47.0083],[-91.683,47.0081],[-91.683,47.0081],[-91.6836,47.0076],[-91.6839,47.0073],[-91.684,47.0073],[-91.684,47.0073],[-91.6842,47.0072],[-91.6843,47.0072],[-91.6845,47.0069],[-91.6848,47.0067],[-91.685,47.0066],[-91.6858,47.0066],[-91.686,47.0065],[-91.6861,47.0065],[-91.6862,47.0065],[-91.6863,47.0064],[-91.6865,47.0063],[-91.6868,47.0061],[-91.687,47.006],[-91.6873,47.006],[-91.6874,47.006],[-91.6878,47.0061],[-91.6879,47.0061],[-91.6881,47.0061],[-91.6881,47.0061],[-91.6883,47.0061],[-91.6886,47.0061],[-91.6888,47.0063],[-91.6889,47.0063],[-91.6892,47.0063],[-91.6897,47.0061],[-91.6901,47.0061],[-91.6904,47.0063],[-91.6914,47.0064],[-91.6914,47.0065],[-91.6917,47.0065],[-91.6918,47.0065],[-91.6925,47.0066],[-91.6926,47.0066],[-91.6934,47.0067],[-91.6936,47.0068],[-91.6945,47.007],[-91.6948,47.0071],[-91.6952,47.0072],[-91.6963,47.0073],[-91.6968,47.0073],[-91.6971,47.0073],[-91.6974,47.0073],[-91.698,47.0075],[-91.6986,47.0074],[-91.6993,47.0073],[-91.6995,47.0073],[-91.7002,47.007],[-91.7004,47.0069],[-91.7006,47.0069],[-91.701,47.0067],[-91.7012,47.0066],[-91.7013,47.0066],[-91.7021,47.0063],[-91.7027,47.0061],[-91.7028,47.0061],[-91.7028,47.006],[-91.7036,47.0057],[-91.7046,47.0053],[-91.7063,47.0041],[-91.7065,47.0039],[-91.7067,47.0038],[-91.7068,47.0037],[-91.7071,47.0033],[-91.7078,47.0027],[-91.708,47.0025],[-91.7081,47.0024],[-91.7082,47.0022],[-91.7084,47.0022],[-91.7087,47.0021],[-91.7088,47.0021],[-91.7093,47.0018],[-91.7094,47.0017],[-91.7097,47.0015],[-91.7098,47.0014],[-91.7098,47.0014],[-91.71,47.0013],[-91.7102,47.0012],[-91.7103,47.0011],[-91.7103,47.001],[-91.7103,47.001],[-91.7108,47.0003],[-91.7109,47.0003],[-91.7114,47.0002],[-91.7116,47.0],[-91.7116,46.9998],[-91.7117,46.9997],[-91.7117,46.9997],[-91.7117,46.9997],[-91.7117,46.9996],[-91.7117,46.9995],[-91.7118,46.9995],[-91.7118,46.9995],[-91.7119,46.9994],[-91.712,46.9994],[-91.7121,46.9994],[-91.7123,46.9994],[-91.7125,46.9994],[-91.7126,46.9994],[-91.7128,46.9993],[-91.713,46.9992],[-91.713,46.9991],[-91.7131,46.999],[-91.7132,46.9989],[-91.7133,46.9988],[-91.7134,46.9986],[-91.7136,46.9985],[-91.7138,46.9984],[-91.714,46.9983],[-91.7142,46.9982],[-91.7142,46.9982],[-91.7142,46.9981],[-91.7143,46.998],[-91.7143,46.998],[-91.7144,46.9979],[-91.7145,46.9978],[-91.7146,46.9978],[-91.7146,46.9978],[-91.7147,46.9977],[-91.7148,46.9976],[-91.7148,46.9976],[-91.7149,46.9975],[-91.715,46.9975],[-91.7151,46.9974],[-91.7152,46.9973],[-91.7153,46.9972],[-91.7155,46.997],[-91.7156,46.9969],[-91.7158,46.9968],[-91.716,46.9967],[-91.7161,46.9967],[-91.7164,46.9966],[-91.7166,46.9964],[-91.717,46.9962],[-91.7171,46.996],[-91.7172,46.9959],[-91.7174,46.9957],[-91.7175,46.9956],[-91.7176,46.9955],[-91.7179,46.9954],[-91.7181,46.9952],[-91.7183,46.9951],[-91.7184,46.995],[-91.7186,46.9949],[-91.7187,46.9948],[-91.7187,46.9947],[-91.7189,46.9946],[-91.7191,46.9944],[-91.7193,46.9942],[-91.7195,46.9942],[-91.7196,46.9941],[-91.7197,46.9941],[-91.7199,46.9941],[-91.7201,46.9941],[-91.7203,46.9941],[-91.7204,46.994],[-91.7205,46.994],[-91.7207,46.9939],[-91.7207,46.9939],[-91.7208,46.9938],[-91.7208,46.9938],[-91.7209,46.9937],[-91.7209,46.9937],[-91.721,46.9936],[-91.7211,46.9935],[-91.7212,46.9934],[-91.7214,46.9932],[-91.7216,46.993],[-91.7217,46.9929],[-91.7219,46.9928],[-91.722,46.9927],[-91.7223,46.9926],[-91.7225,46.9926],[-91.7227,46.9925],[-91.7228,46.9924],[-91.723,46.9924],[-91.723,46.9923],[-91.7231,46.9921],[-91.7232,46.9919],[-91.7234,46.9918],[-91.7235,46.9917],[-91.7237,46.9916],[-91.7238,46.9916],[-91.7239,46.9915],[-91.724,46.9914],[-91.7242,46.9913],[-91.7243,46.9912],[-91.7244,46.9911],[-91.7244,46.991],[-91.7245,46.9909],[-91.7247,46.9908],[-91.7248,46.9907],[-91.725,46.9906],[-91.7251,46.9905],[-91.7252,46.9905],[-91.7253,46.9904],[-91.7255,46.9904],[-91.7256,46.9904],[-91.7258,46.9903],[-91.726,46.9903],[-91.7262,46.9902],[-91.7263,46.9901],[-91.7265,46.99],[-91.7265,46.99],[-91.7267,46.9899],[-91.7268,46.9898],[-91.7269,46.9898],[-91.7269,46.9897],[-91.727,46.9896],[-91.7271,46.9895],[-91.7273,46.9894],[-91.7274,46.9893],[-91.7275,46.9892],[-91.7276,46.989],[-91.7277,46.9888],[-91.7278,46.9888],[-91.728,46.9887],[-91.7281,46.9887],[-91.7282,46.9886],[-91.7284,46.9886],[-91.7287,46.9884],[-91.7288,46.9884],[-91.729,46.9882],[-91.7291,46.9882],[-91.7292,46.9881],[-91.7294,46.9881],[-91.7295,46.988],[-91.7296,46.9879],[-91.7297,46.9879],[-91.7298,46.9878],[-91.7299,46.9877],[-91.73,46.9875],[-91.73,46.9874],[-91.7302,46.9874],[-91.7304,46.9873],[-91.7305,46.9873],[-91.7306,46.9872],[-91.7306,46.9872],[-91.7307,46.9872],[-91.7308,46.9871],[-91.7309,46.987],[-91.731,46.987],[-91.7312,46.9869],[-91.7312,46.9869],[-91.7313,46.9869],[-91.7313,46.9869],[-91.7314,46.9868],[-91.7315,46.9868],[-91.7316,46.9866],[-91.7317,46.9865],[-91.7319,46.9864],[-91.732,46.9863],[-91.7322,46.9861],[-91.7323,46.986],[-91.7325,46.9859],[-91.7326,46.9858],[-91.7327,46.9857],[-91.7329,46.9857],[-91.7331,46.9856],[-91.7332,46.9855],[-91.7333,46.9854],[-91.7334,46.9854],[-91.7335,46.9853],[-91.7336,46.9852],[-91.7337,46.9851],[-91.7339,46.985],[-91.734,46.9849],[-91.7342,46.9849],[-91.7344,46.9848],[-91.7345,46.9847],[-91.7347,46.9846],[-91.7349,46.9845],[-91.7349,46.9844],[-91.735,46.9843],[-91.735,46.9842],[-91.735,46.9841],[-91.7351,46.984],[-91.7352,46.9839],[-91.7353,46.9839],[-91.7354,46.9839],[-91.7356,46.9839],[-91.7357,46.9839],[-91.7358,46.9838],[-91.7359,46.9838],[-91.736,46.9837],[-91.7361,46.9836],[-91.7361,46.9835],[-91.7362,46.9835],[-91.7363,46.9834],[-91.7364,46.9834],[-91.7365,46.9833],[-91.7366,46.9832],[-91.7367,46.9832],[-91.7368,46.9831],[-91.7369,46.983],[-91.737,46.9829],[-91.7372,46.9828],[-91.7374,46.9826],[-91.7375,46.9825],[-91.7378,46.9824],[-91.7381,46.9822],[-91.7382,46.9821],[-91.7383,46.982],[-91.7384,46.9819],[-91.7384,46.9819],[-91.7385,46.9817],[-91.7387,46.9815],[-91.7388,46.9814],[-91.739,46.9813],[-91.7391,46.9812],[-91.7392,46.9811],[-91.7393,46.981],[-91.7394,46.9809],[-91.7396,46.9807],[-91.7397,46.9805],[-91.7398,46.9803],[-91.7399,46.9801],[-91.74,46.9799],[-91.74,46.9797],[-91.7401,46.9795],[-91.7402,46.9794],[-91.7404,46.9792],[-91.7406,46.9791],[-91.7407,46.979],[-91.7407,46.9789],[-91.7408,46.9788],[-91.7409,46.9787],[-91.7411,46.9786],[-91.7411,46.9786],[-91.7411,46.9786],[-91.7414,46.9784],[-91.7415,46.9782],[-91.7416,46.9781],[-91.7417,46.978],[-91.7417,46.9779],[-91.7417,46.9778],[-91.7418,46.9777],[-91.7418,46.9776],[-91.7418,46.9775],[-91.7418,46.9774],[-91.7419,46.9774],[-91.742,46.9773],[-91.7422,46.9773],[-91.7424,46.9773],[-91.7427,46.9772],[-91.7429,46.977],[-91.743,46.9769],[-91.7431,46.9768],[-91.7432,46.9766],[-91.7433,46.9765],[-91.7433,46.9764],[-91.7434,46.9764],[-91.7435,46.9764],[-91.7435,46.9764],[-91.7437,46.9763],[-91.7438,46.9763],[-91.7439,46.9762],[-91.744,46.9762],[-91.744,46.9761],[-91.7441,46.9761],[-91.7442,46.976],[-91.7443,46.976],[-91.7444,46.976],[-91.7445,46.976],[-91.7447,46.9759],[-91.7449,46.9759],[-91.7451,46.9759],[-91.7453,46.9759],[-91.7454,46.9758],[-91.7455,46.9757],[-91.7457,46.9756],[-91.7458,46.9755],[-91.7459,46.9754],[-91.7459,46.9753],[-91.746,46.9752],[-91.7461,46.9751],[-91.7462,46.9751],[-91.7462,46.9751],[-91.7463,46.975],[-91.7464,46.975],[-91.7465,46.9749],[-91.7467,46.9748],[-91.7469,46.9746],[-91.7471,46.9745],[-91.7473,46.9744],[-91.7474,46.9743],[-91.7477,46.9742],[-91.7479,46.9741],[-91.748,46.974],[-91.7482,46.9738],[-91.7482,46.9737],[-91.7483,46.9737],[-91.7484,46.9736],[-91.7485,46.9736],[-91.7487,46.9735],[-91.7488,46.9735],[-91.7489,46.9734],[-91.749,46.9733],[-91.7491,46.9732],[-91.7493,46.9731],[-91.7494,46.973],[-91.7495,46.973],[-91.7496,46.9729],[-91.7497,46.9728],[-91.7498,46.9728],[-91.7499,46.9727],[-91.75,46.9727],[-91.75,46.9727],[-91.7501,46.9726],[-91.7502,46.9725],[-91.7507,46.9721],[-91.7508,46.9721],[-91.7509,46.9721],[-91.751,46.9721],[-91.7511,46.972],[-91.7513,46.9718],[-91.7514,46.9717],[-91.7515,46.9716],[-91.7517,46.9715],[-91.7518,46.9715],[-91.7519,46.9714],[-91.752,46.9714],[-91.7521,46.9713],[-91.7523,46.9713],[-91.7524,46.9712],[-91.7526,46.971],[-91.7527,46.9708],[-91.7527,46.9707],[-91.7528,46.9707],[-91.7529,46.9707],[-91.753,46.9706],[-91.7536,46.9701],[-91.7537,46.97],[-91.7538,46.9698],[-91.7538,46.9697],[-91.7539,46.9695],[-91.7541,46.9694],[-91.7542,46.9692],[-91.7543,46.9691],[-91.7544,46.9691],[-91.7546,46.969],[-91.7548,46.969],[-91.755,46.9688],[-91.7552,46.9686],[-91.7553,46.9684],[-91.7556,46.9682],[-91.7559,46.9681],[-91.7559,46.968],[-91.7559,46.9678],[-91.756,46.9678],[-91.7562,46.9678],[-91.7563,46.9677],[-91.7564,46.9676],[-91.7565,46.9674],[-91.7565,46.9674],[-91.7568,46.9672],[-91.7571,46.967],[-91.7574,46.9668],[-91.7574,46.9667],[-91.7573,46.9667],[-91.7574,46.9666],[-91.7574,46.9666],[-91.7575,46.9665],[-91.7576,46.9666],[-91.7578,46.9666],[-91.7579,46.9665],[-91.758,46.9664],[-91.7581,46.9663],[-91.7582,46.9662],[-91.7583,46.966],[-91.7584,46.9658],[-91.7585,46.9657],[-91.7586,46.9655],[-91.7587,46.9654],[-91.7588,46.9652],[-91.7588,46.965],[-91.7589,46.965],[-91.7589,46.9649],[-91.759,46.9648],[-91.7591,46.9646],[-91.7592,46.9644],[-91.7592,46.9641],[-91.7592,46.9639],[-91.7592,46.9637],[-91.7592,46.9635],[-91.7594,46.9634],[-91.7595,46.9634],[-91.7597,46.9634],[-91.76,46.9634],[-91.7601,46.9634],[-91.7602,46.9632],[-91.7602,46.9632],[-91.7602,46.9631],[-91.7603,46.9629],[-91.7603,46.9628],[-91.7604,46.9626],[-91.7605,46.9624],[-91.7606,46.9623],[-91.7608,46.9622],[-91.7609,46.9622],[-91.7611,46.9623],[-91.7613,46.9623],[-91.7613,46.9623],[-91.7614,46.9622],[-91.7615,46.9621],[-91.7615,46.962],[-91.7616,46.9619],[-91.7618,46.962],[-91.7619,46.9619],[-91.7621,46.9619],[-91.7623,46.9617],[-91.7626,46.9616],[-91.7627,46.9616],[-91.7629,46.9615],[-91.763,46.9615],[-91.7632,46.9614],[-91.7633,46.9612],[-91.7634,46.961],[-91.7636,46.9609],[-91.7639,46.9606],[-91.7645,46.96],[-91.7649,46.9595],[-91.7652,46.9592],[-91.7654,46.9589],[-91.7657,46.9587],[-91.7659,46.9584],[-91.7663,46.9581],[-91.767,46.9576],[-91.7672,46.9574],[-91.7673,46.9572],[-91.7675,46.9571],[-91.7676,46.957],[-91.7677,46.957],[-91.7679,46.957],[-91.7681,46.9569],[-91.7683,46.9568],[-91.7684,46.9567],[-91.7687,46.9565],[-91.7688,46.9565],[-91.7689,46.9563],[-91.7692,46.9561],[-91.7693,46.9561],[-91.7695,46.9562],[-91.7697,46.9561],[-91.7699,46.956],[-91.7701,46.9559],[-91.7703,46.9558],[-91.7705,46.9557],[-91.7706,46.9557],[-91.7708,46.9558],[-91.7709,46.9558],[-91.771,46.9557],[-91.7712,46.9556],[-91.7717,46.9552],[-91.7718,46.9552],[-91.772,46.955],[-91.7723,46.9548],[-91.7726,46.9546],[-91.7731,46.9543],[-91.7732,46.9542],[-91.7733,46.954],[-91.7734,46.9539],[-91.7735,46.9537],[-91.7736,46.9536],[-91.7737,46.9536],[-91.7739,46.9536],[-91.774,46.9536],[-91.7742,46.9537],[-91.7744,46.9537],[-91.7745,46.9536],[-91.7746,46.9535],[-91.7747,46.9534],[-91.7748,46.9533],[-91.7749,46.9532],[-91.7752,46.9531],[-91.7755,46.953],[-91.7755,46.953],[-91.7756,46.9529],[-91.7757,46.9529],[-91.7759,46.9528],[-91.776,46.9527],[-91.7761,46.9526],[-91.7762,46.9524],[-91.7763,46.9524],[-91.7765,46.9524],[-91.7766,46.9523],[-91.7769,46.9521],[-91.7771,46.952],[-91.7774,46.9519],[-91.7776,46.9517],[-91.7777,46.9515],[-91.7778,46.9513],[-91.7779,46.9511],[-91.778,46.9509],[-91.7781,46.9508],[-91.7782,46.9507],[-91.7783,46.9505],[-91.7784,46.9504],[-91.7785,46.9502],[-91.7787,46.95],[-91.7785,46.9494],[-91.7784,46.9493],[-91.7784,46.9493],[-91.7783,46.9492],[-91.7783,46.9491],[-91.7782,46.949],[-91.7781,46.9489],[-91.778,46.9489],[-91.7778,46.9489],[-91.7776,46.9489],[-91.7773,46.9489],[-91.7772,46.9489],[-91.7772,46.9488],[-91.7772,46.9488],[-91.7774,46.9487],[-91.7776,46.9487],[-91.7778,46.9486],[-91.778,46.9484],[-91.7782,46.9483],[-91.7785,46.9482],[-91.7787,46.9481],[-91.7789,46.9479],[-91.7791,46.9478],[-91.7793,46.9477],[-91.7797,46.9475],[-91.78,46.9473],[-91.7801,46.9473],[-91.7803,46.9472],[-91.7804,46.947],[-91.7805,46.9469],[-91.7805,46.9467],[-91.7805,46.9465],[-91.7806,46.9463],[-91.7806,46.9461],[-91.7806,46.9459],[-91.7806,46.9457],[-91.7805,46.9456],[-91.7805,46.9454],[-91.7804,46.9452],[-91.7803,46.945],[-91.7802,46.9448],[-91.7801,46.9447],[-91.78,46.9445],[-91.78,46.9444],[-91.7801,46.9444],[-91.7804,46.9445],[-91.7806,46.9445],[-91.7808,46.9446],[-91.781,46.9447],[-91.7812,46.9449],[-91.7813,46.9449],[-91.7813,46.9451],[-91.7813,46.9453],[-91.7813,46.9454],[-91.7813,46.9455],[-91.7813,46.9456],[-91.7813,46.9457],[-91.7815,46.9457],[-91.7818,46.9458],[-91.7821,46.9457],[-91.7823,46.9457],[-91.7824,46.9457],[-91.7825,46.9457],[-91.7826,46.9455],[-91.7826,46.9453],[-91.7827,46.9452],[-91.7828,46.9451],[-91.7828,46.9449],[-91.783,46.9448],[-91.7831,46.9447],[-91.7832,46.9446],[-91.7833,46.9445],[-91.7832,46.9444],[-91.7831,46.9443],[-91.7829,46.9444],[-91.7825,46.9445],[-91.7823,46.9446],[-91.7821,46.9447],[-91.782,46.9447],[-91.7819,46.9447],[-91.7817,46.9446],[-91.7816,46.9446],[-91.7817,46.9445],[-91.7817,46.9443],[-91.7818,46.9442],[-91.7818,46.9441],[-91.7819,46.944],[-91.7816,46.9441],[-91.7815,46.9441],[-91.7813,46.9442],[-91.7811,46.9444],[-91.781,46.9443],[-91.7806,46.9442],[-91.7804,46.9441],[-91.7802,46.944],[-91.7801,46.944],[-91.7799,46.9439],[-91.7798,46.9438],[-91.7797,46.9437],[-91.7797,46.9436],[-91.7797,46.9436],[-91.7797,46.9435],[-91.7798,46.9435],[-91.7799,46.9434],[-91.7804,46.9433],[-91.7805,46.9433],[-91.7807,46.9431],[-91.7808,46.9431],[-91.781,46.943],[-91.7811,46.9429],[-91.7812,46.943],[-91.7814,46.943],[-91.7815,46.943],[-91.7816,46.9429],[-91.7818,46.9427],[-91.782,46.9427],[-91.7823,46.9426],[-91.7825,46.9425],[-91.7827,46.9425],[-91.7828,46.9425],[-91.783,46.9425],[-91.7831,46.9425],[-91.7834,46.9424],[-91.7836,46.9423],[-91.7838,46.9422],[-91.784,46.9421],[-91.7841,46.9421],[-91.7841,46.942],[-91.7848,46.9419],[-91.7852,46.9419],[-91.7855,46.942],[-91.7857,46.942],[-91.7859,46.9419],[-91.7862,46.9419],[-91.7864,46.9418],[-91.7866,46.9418],[-91.7869,46.9417],[-91.7872,46.9416],[-91.7875,46.9415],[-91.7878,46.9413],[-91.788,46.9412],[-91.7883,46.9411],[-91.7884,46.941],[-91.7885,46.9409],[-91.7887,46.9409],[-91.789,46.9408],[-91.7892,46.9409],[-91.7895,46.9409],[-91.7898,46.9409],[-91.7901,46.9409],[-91.7905,46.9409],[-91.7909,46.9408],[-91.7912,46.9408],[-91.7914,46.9407],[-91.7916,46.9406],[-91.7919,46.9408],[-91.7925,46.9407],[-91.7931,46.9406],[-91.7934,46.9405],[-91.7936,46.9403],[-91.7938,46.9402],[-91.7941,46.9401],[-91.7943,46.9399],[-91.7944,46.9398],[-91.7944,46.9397],[-91.7943,46.953],[-91.7944,46.9675],[-91.7944,46.9818],[-91.7944,46.9965],[-91.7944,47.0109],[-91.7943,47.0255],[-91.7943,47.0399],[-91.7944,47.0541],[-91.7944,47.0688],[-91.7945,47.0831],[-91.7945,47.0976],[-91.7943,47.1119],[-91.7922,47.1119],[-91.7924,47.1265],[-91.7923,47.1411],[-91.7923,47.1556],[-91.7923,47.1698],[-91.7923,47.1843],[-91.7922,47.1985],[-91.7923,47.2128],[-91.7923,47.2276],[-91.7923,47.2422],[-91.7922,47.2565],[-91.7921,47.271],[-91.792,47.2855],[-91.7919,47.3],[-91.7918,47.3145],[-91.7918,47.3288],[-91.792,47.3432],[-91.792,47.3576],[-91.792,47.3726],[-91.7906,47.3726],[-91.7904,47.3872],[-91.7896,47.4017],[-91.7895,47.416],[-91.7894,47.4303],[-91.7893,47.4449],[-91.7895,47.4574],[-91.7895,47.4605],[-91.7895,47.4741],[-91.7895,47.4753],[-91.7894,47.4886],[-91.7894,47.4897],[-91.7894,47.493],[-91.7891,47.503],[-91.7891,47.5041],[-91.789,47.5067],[-91.7889,47.5176],[-91.7889,47.5187],[-91.7886,47.5322],[-91.7886,47.533],[-91.788,47.5424],[-91.788,47.5431],[-91.7878,47.5469],[-91.7886,47.5574],[-91.7887,47.5588],[-91.7888,47.5614],[-91.789,47.5719],[-91.7892,47.5749],[-91.7893,47.576],[-91.7904,47.5864],[-91.7905,47.5874],[-91.7908,47.5904],[-91.7911,47.6008],[-91.7912,47.6021],[-91.7913,47.6049],[-91.7915,47.6091],[-91.7919,47.6155],[-91.7922,47.6193],[-91.7923,47.6212],[-91.793,47.6299],[-91.7933,47.6345],[-91.794,47.6442],[-91.794,47.6449],[-91.7942,47.6486],[-91.7948,47.6586],[-91.795,47.663],[-91.7954,47.6729],[-91.7955,47.6733],[-91.7955,47.6778],[-91.7955,47.678],[-91.7959,47.688],[-91.7959,47.6925],[-91.7967,47.7024],[-91.7971,47.707],[-91.7977,47.7128],[-91.7981,47.7165],[-91.7982,47.717],[-91.7984,47.7201],[-91.799,47.731],[-91.7992,47.7339],[-91.7992,47.7388],[-91.7993,47.7454],[-91.7993,47.7482],[-91.7992,47.7538],[-91.7992,47.7598],[-91.7992,47.7626],[-91.7995,47.7723],[-91.7995,47.7742],[-91.7995,47.776],[-91.7995,47.7774],[-91.7997,47.7886],[-91.7997,47.7893],[-91.7997,47.7916],[-91.7999,47.8031],[-91.8,47.8175],[-91.8,47.8319],[-91.7992,47.8464],[-91.7988,47.8618],[-91.7983,47.876],[-91.7983,47.8771],[-91.7979,47.8899],[-91.7979,47.9045],[-91.7978,47.9189],[-91.7977,47.9334],[-91.7979,47.9481],[-91.7985,47.9625],[-91.7992,47.977],[-91.7996,47.9914],[-91.8001,48.0059],[-91.8,48.0206],[-91.8,48.0353],[-91.8,48.0496],[-91.8001,48.0643],[-91.7997,48.0788],[-91.7992,48.0936],[-91.7987,48.1079],[-91.798,48.1224],[-91.7981,48.1369],[-91.7983,48.1515],[-91.7984,48.1662],[-91.7982,48.1808],[-91.7983,48.1953],[-91.7982,48.203],[-91.7972,48.2027],[-91.791,48.2026],[-91.7886,48.1964],[-91.7861,48.1962],[-91.7806,48.2008],[-91.7767,48.2008],[-91.7642,48.2007],[-91.7627,48.2018],[-91.7607,48.2049],[-91.7559,48.206],[-91.7553,48.2049],[-91.7535,48.2009],[-91.7484,48.1987],[-91.7438,48.1988],[-91.7415,48.1991],[-91.742,48.2047],[-91.7388,48.2043],[-91.7378,48.2043],[-91.7371,48.2042],[-91.7334,48.2033],[-91.7253,48.2014],[-91.7153,48.1996],[-91.7131,48.1981],[-91.7115,48.1958],[-91.7103,48.1939],[-91.7103,48.1926],[-91.7122,48.1876],[-91.72,48.1814],[-91.7213,48.1803],[-91.7223,48.1786],[-91.7229,48.1736],[-91.7243,48.1706],[-91.723,48.169],[-91.717,48.1719],[-91.711,48.1727],[-91.7093,48.173],[-91.7048,48.1708],[-91.705,48.1669],[-91.7051,48.1641],[-91.7049,48.1611],[-91.7046,48.1601],[-91.705,48.158],[-91.7069,48.1538],[-91.7081,48.1531],[-91.7077,48.1524],[-91.707,48.1511],[-91.7068,48.1504],[-91.7046,48.1472],[-91.7032,48.1452],[-91.7022,48.1448],[-91.7005,48.1448],[-91.6991,48.1451],[-91.6981,48.1441],[-91.6977,48.1416],[-91.6993,48.1379],[-91.6994,48.1375],[-91.6995,48.132],[-91.7005,48.1307],[-91.7037,48.1249],[-91.7078,48.1234],[-91.7078,48.1233],[-91.7093,48.1194],[-91.7117,48.1175],[-91.7125,48.1156],[-91.7117,48.1147],[-91.7103,48.1147],[-91.7099,48.1145],[-91.7033,48.1138],[-91.6967,48.1159],[-91.693,48.1166],[-91.6921,48.1169],[-91.6914,48.1179],[-91.6911,48.1182],[-91.6913,48.1185],[-91.6921,48.1198],[-91.6913,48.1201],[-91.6906,48.1203],[-91.6821,48.1226],[-91.6835,48.1178],[-91.6875,48.1119],[-91.6818,48.1099],[-91.6813,48.1091],[-91.6808,48.1084],[-91.6767,48.1075],[-91.671,48.1087],[-91.6703,48.1087],[-91.6673,48.1087],[-91.665,48.1072],[-91.6646,48.1074],[-91.6626,48.1092],[-91.6626,48.1092],[-91.6622,48.1117],[-91.6618,48.112],[-91.6551,48.1138],[-91.6532,48.1144],[-91.6518,48.114],[-91.6511,48.1131],[-91.6514,48.1122],[-91.653,48.1098],[-91.6519,48.1091],[-91.6496,48.1074],[-91.6486,48.1065],[-91.6484,48.1065],[-91.6481,48.1065],[-91.648,48.1064],[-91.6479,48.1064],[-91.648,48.1059],[-91.6469,48.1039],[-91.6399,48.0972],[-91.6267,48.0999],[-91.6148,48.1023],[-91.6073,48.1024],[-91.5888,48.1025],[-91.5846,48.1039],[-91.5755,48.107],[-91.5629,48.1082],[-91.5591,48.1086],[-91.5575,48.1073],[-91.5528,48.1033],[-91.5636,48.0971],[-91.5694,48.0937],[-91.5696,48.0928],[-91.5718,48.0828],[-91.5753,48.0668],[-91.5751,48.0658],[-91.5727,48.0574],[-91.5754,48.049],[-91.5675,48.0438],[-91.5674,48.0439],[-91.5468,48.0519],[-91.5422,48.0537],[-91.5416,48.0539],[-91.5266,48.058],[-91.5101,48.0625],[-91.4897,48.068],[-91.4881,48.0684],[-91.4659,48.067],[-91.4647,48.0669],[-91.45,48.0691],[-91.4462,48.0678],[-91.4466,48.0631],[-91.4445,48.0606],[-91.4435,48.0594],[-91.4377,48.0525],[-91.4381,48.0512],[-91.438,48.0509],[-91.4382,48.0507],[-91.4385,48.0506],[-91.4385,48.0504],[-91.4376,48.0499],[-91.4372,48.0495],[-91.4368,48.0495],[-91.4295,48.0487],[-91.4271,48.0501],[-91.4266,48.0499],[-91.4244,48.0508],[-91.4221,48.051],[-91.4151,48.0532],[-91.4135,48.0537],[-91.3921,48.057],[-91.3908,48.0572],[-91.3852,48.0612],[-91.3783,48.066],[-91.3777,48.0663],[-91.3708,48.0698],[-91.3649,48.0672],[-91.356,48.0701],[-91.3536,48.0709],[-91.3525,48.0712],[-91.352,48.0715],[-91.3508,48.0718],[-91.3503,48.072],[-91.3502,48.072],[-91.3497,48.0717],[-91.3485,48.0722],[-91.3399,48.0736],[-91.3363,48.0711],[-91.3363,48.0697],[-91.3347,48.0695],[-91.3346,48.0695],[-91.3334,48.07],[-91.332,48.0702],[-91.3312,48.0697],[-91.3293,48.07],[-91.3287,48.0706],[-91.3286,48.071],[-91.3284,48.0711],[-91.3261,48.0723],[-91.3244,48.073],[-91.3191,48.0733],[-91.3179,48.0731],[-91.3173,48.0733],[-91.316,48.0735],[-91.3153,48.0736],[-91.3147,48.0736],[-91.3129,48.0734],[-91.3117,48.0733],[-91.3112,48.0732],[-91.3108,48.0729],[-91.3101,48.0729],[-91.3088,48.0728],[-91.3078,48.0729],[-91.3068,48.0729],[-91.3063,48.0729],[-91.2915,48.0741],[-91.2897,48.0742],[-91.2796,48.0776],[-91.2759,48.0788],[-91.2714,48.0789],[-91.2667,48.0789],[-91.2499,48.0841],[-91.2496,48.0841],[-91.239,48.0928],[-91.2348,48.0962],[-91.2286,48.099],[-91.228,48.0993],[-91.2149,48.1029],[-91.2115,48.1059],[-91.2061,48.1107],[-91.1948,48.1208],[-91.19,48.1252],[-91.1846,48.1226],[-91.1842,48.1225],[-91.1833,48.1222],[-91.1828,48.1222],[-91.1812,48.1236],[-91.1766,48.1256],[-91.1635,48.1352],[-91.1618,48.1365],[-91.1562,48.1406],[-91.14,48.1481],[-91.1373,48.1493],[-91.1374,48.1496],[-91.138,48.152],[-91.1399,48.1518],[-91.1401,48.1517],[-91.1404,48.1523],[-91.1404,48.1529],[-91.1425,48.1547],[-91.1397,48.1555],[-91.1389,48.1558],[-91.1357,48.1567],[-91.1325,48.1573],[-91.1198,48.1607],[-91.1189,48.1615],[-91.118,48.1621],[-91.1169,48.1635],[-91.1147,48.1665],[-91.1088,48.1687],[-91.0977,48.1715],[-91.0971,48.1716],[-91.0919,48.1737],[-91.088,48.1784],[-91.0841,48.1804],[-91.0824,48.1812],[-91.0813,48.1809],[-91.0808,48.1804],[-91.0806,48.1801],[-91.0796,48.1799],[-91.0788,48.1796],[-91.076,48.1794],[-91.0758,48.1794],[-91.071,48.1804],[-91.0654,48.1815],[-91.0627,48.1856],[-91.0592,48.1854],[-91.0575,48.1871],[-91.056,48.1881],[-91.0554,48.1884],[-91.053,48.1882],[-91.0519,48.1881],[-91.0498,48.1888],[-91.0486,48.1888],[-91.0467,48.1892],[-91.0455,48.1895],[-91.0363,48.1902],[-91.0356,48.1899],[-91.0355,48.1899],[-91.0354,48.1898],[-91.0347,48.1893],[-91.0311,48.1889]]],"type":"Polygon"},"id":"38","properties":{"Area":5924884711.38128,"CTYONLY_":12,"Code":"LAKE","LASTMOD":"2003-01-01T01:10:00Z","Name":"Lake","Perimiter":433067.74708},"type":"Feature"},{"geometry":{"coordinates":[[[-91.2389,47.2968],[-91.2389,47.2968],[-91.2392,47.2968],[-91.2394,47.2968],[-91.2395,47.2969],[-91.2395,47.297],[-91.2394,47.2971],[-91.2392,47.2972],[-91.239,47.2972],[-91.2388,47.2971],[-91.2386,47.2972],[-91.2383,47.2973],[-91.238,47.2972],[-91.2379,47.297],[-91.238,47.2969],[-91.2381,47.2969],[-91.2382,47.297],[-91.2383,47.297],[-91.2383,47.2969],[-91.2385,47.2968],[-91.2387,47.2968],[-91.2389,47.2968]]],"type":"Polygon"},"id":"38","properties":{"Area":4148.06907,"CTYONLY_":96,"Code":"LAKE","LASTMOD":"2003-01-01T01:10:00Z","Name":"Lake","Perimiter":309.162},"type":"Feature"},{"geometry":{"coordinates":[[[-91.244,47.2934],[-91.2439,47.2934],[-91.2438,47.2934],[-91.2438,47.2932],[-91.2439,47.2931],[-91.2441,47.2931],[-91.2441,47.2931],[-91.2441,47.2933],[-91.244,47.2934]]],"type":"Polygon"},"id":"38","properties":{"Area":783.65339,"CTYONLY_":97,"Code":"LAKE","LASTMOD":"2003-01-01T01:10:00Z","Name":"Lake","Perimiter":109.61651},"type":"Feature"},{"geometry":{"coordinates":[[[-91.245,47.2935],[-91.2449,47.2935],[-91.2447,47.2935],[-91.2446,47.2934],[-91.2445,47.2932],[-91.2446,47.2931],[-91.2447,47.2931],[-91.2448,47.293],[-91.2449,47.2928],[-91.2449,47.2925],[-91.2449,47.2924],[-91.245,47.2923],[-91.2452,47.2922],[-91.2455,47.2922],[-91.2456,47.2922],[-91.2457,47.2924],[-91.2456,47.2926],[-91.2456,47.2928],[-91.2456,47.293],[-91.2457,47.2932],[-91.2456,47.2933],[-91.2454,47.2934],[-91.2452,47.2934],[-91.245,47.2935]]],"type":"Polygon"},"id":"38","properties":{"Area":8591.00636,"CTYONLY_":98,"Code":"LAKE","LASTMOD":"2003-01-01T01:10:00Z","Name":"Lake","Perimiter":398.31047},"type":"Feature"},{"geometry":{"coordinates":[[[-91.5535,47.0901],[-91.5534,47.0902],[-91.5532,47.0902],[-91.553,47.0902],[-91.5529,47.0903],[-91.5528,47.0903],[-91.5528,47.0904],[-91.5528,47.0905],[-91.5528,47.0905],[-91.5528,47.0905],[-91.5528,47.0906],[-91.5528,47.0906],[-91.5527,47.0906],[-91.5527,47.0906],[-91.5526,47.0906],[-91.5526,47.0907],[-91.5527,47.0907],[-91.5527,47.0908],[-91.5527,47.0908],[-91.5527,47.0908],[-91.5526,47.0908],[-91.5524,47.0909],[-91.5522,47.0908],[-91.5521,47.0908],[-91.552,47.0908],[-91.5519,47.0908],[-91.5519,47.0907],[-91.5519,47.0907],[-91.5517,47.0907],[-91.5517,47.0907],[-91.5515,47.0907],[-91.5515,47.0907],[-91.5514,47.0906],[-91.5514,47.0906],[-91.5515,47.0906],[-91.5517,47.0906],[-91.5519,47.0904],[-91.552,47.0903],[-91.552,47.0901],[-91.5521,47.0899],[-91.5522,47.0898],[-91.5523,47.0896],[-91.5524,47.0894],[-91.5524,47.0893],[-91.5524,47.0892],[-91.5523,47.0891],[-91.5523,47.089],[-91.5522,47.0889],[-91.552,47.0889],[-91.5518,47.0888],[-91.5516,47.0887],[-91.5515,47.0886],[-91.5514,47.0885],[-91.5514,47.0884],[-91.5513,47.0883],[-91.5513,47.0882],[-91.5513,47.0881],[-91.5513,47.0881],[-91.5513,47.0879],[-91.5514,47.0877],[-91.5514,47.0876],[-91.5515,47.0876],[-91.5516,47.0875],[-91.5517,47.0875],[-91.5518,47.0875],[-91.5519,47.0876],[-91.552,47.0877],[-91.5521,47.0877],[-91.5523,47.0878],[-91.5524,47.0878],[-91.5525,47.0878],[-91.5526,47.0878],[-91.5528,47.0877],[-91.5529,47.0877],[-91.5531,47.0877],[-91.5532,47.0878],[-91.5533,47.088],[-91.5534,47.0884],[-91.5535,47.0888],[-91.5536,47.0889],[-91.5536,47.0891],[-91.5536,47.0894],[-91.5536,47.0895],[-91.5536,47.0896],[-91.5536,47.0897],[-91.5536,47.0898],[-91.5536,47.0898],[-91.5537,47.0899],[-91.5537,47.0899],[-91.5538,47.09],[-91.5538,47.09],[-91.5539,47.0901],[-91.5538,47.0901],[-91.5537,47.0901],[-91.5536,47.0901],[-91.5535,47.0901]]],"type":"Polygon"},"id":"38","properties":{"Area":39764.53322,"CTYONLY_":99,"Code":"LAKE","LASTMOD":"2003-01-01T01:10:00Z","Name":"Lake","Perimiter":1105.41491},"type":"Feature"},{"geometry":{"coordinates":[[[-91.7743,46.9459],[-91.7742,46.946],[-91.7741,46.9461],[-91.774,46.9461],[-91.7737,46.9463],[-91.7735,46.9464],[-91.7734,46.9465],[-91.7732,46.9466],[-91.773,46.9466],[-91.7729,46.9466],[-91.7727,46.9466],[-91.7725,46.9467],[-91.7723,46.9467],[-91.7721,46.9468],[-91.772,46.9468],[-91.7719,46.9468],[-91.7719,46.9467],[-91.7719,46.9466],[-91.772,46.9464],[-91.7722,46.9463],[-91.7723,46.9462],[-91.7726,46.946],[-91.773,46.9459],[-91.773,46.9459],[-91.7733,46.9458],[-91.7734,46.9459],[-91.7735,46.9459],[-91.7736,46.946],[-91.7737,46.946],[-91.7739,46.9459],[-91.7741,46.9459],[-91.7743,46.9459]]],"type":"Polygon"},"id":"38","properties":{"Area":9667.10697,"CTYONLY_":100,"Code":"LAKE","LASTMOD":"2003-01-01T01:10:00Z","Name":"Lake","Perimiter":461.30255},"type":"Feature"},{"geometry":{"coordinates":[[[-91.267,47.2703],[-91.267,47.2703],[-91.2669,47.2703],[-91.2668,47.2703],[-91.2666,47.2703],[-91.2665,47.2702],[-91.2666,47.2701],[-91.2666,47.2701],[-91.2668,47.2701],[-91.267,47.2702],[-91.267,47.2703]]],"type":"Polygon"},"id":"38","properties":{"Area":691.59892,"CTYONLY_":117,"Code":"LAKE","LASTMOD":"2003-01-01T01:10:00Z","Name":"Lake","Perimiter":103.08393},"type":"Feature"},{"geometry":{"coordinates":[[[-91.2824,47.2658],[-91.2823,47.2658],[-91.2822,47.2658],[-91.282,47.2659],[-91.2819,47.2659],[-91.2818,47.2659],[-91.2818,47.2658],[-91.2818,47.2658],[-91.2821,47.2657],[-91.2824,47.2655],[-91.2825,47.2654],[-91.2826,47.2654],[-91.2827,47.2654],[-91.2828,47.2655],[-91.2827,47.2657],[-91.2825,47.2658],[-91.2824,47.2658]]],"type":"Polygon"},"id":"38","properties":{"Area":2024.76285,"CTYONLY_":118,"Code":"LAKE","LASTMOD":"2003-01-01T01:10:00Z","Name":"Lake","Perimiter":206.26115},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&filter=LASTMOD%3DTIMESTAMP('2003-01-01T01%3A10%3A00Z')","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&filter=LASTMOD%3DTIMESTAMP('2003-01-01T01%3A10%3A00Z')","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":8,"numberReturned":8,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_text_true_equal_true.json.txt b/msautotest/api/expected/ogcapi_cql2_text_true_equal_true.json.txt new file mode 100644 index 0000000000..6753b0f608 --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_text_true_equal_true.json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 1 +OGC-NumberReturned: 1 + +{"features":[{"geometry":{"coordinates":[[[-93.5242,44.5436],[-93.5225,44.5436],[-93.504,44.5438],[-93.5018,44.5438],[-93.4835,44.5438],[-93.4817,44.5438],[-93.4734,44.5438],[-93.4632,44.5438],[-93.4609,44.5438],[-93.4429,44.5438],[-93.4408,44.5438],[-93.4326,44.5438],[-93.4226,44.5439],[-93.4206,44.5439],[-93.4024,44.5439],[-93.4003,44.5439],[-93.383,44.544],[-93.38,44.544],[-93.3627,44.5441],[-93.3596,44.5441],[-93.3556,44.5441],[-93.3424,44.5442],[-93.3395,44.5442],[-93.3221,44.544],[-93.3191,44.544],[-93.3128,44.544],[-93.3019,44.544],[-93.2988,44.544],[-93.2813,44.544],[-93.2814,44.5298],[-93.2815,44.5153],[-93.2815,44.501],[-93.2815,44.4865],[-93.2817,44.472],[-93.2618,44.4718],[-93.2415,44.4716],[-93.2213,44.4714],[-93.2008,44.4714],[-93.1808,44.4713],[-93.1605,44.4713],[-93.1408,44.4712],[-93.1206,44.4713],[-93.1002,44.4718],[-93.0799,44.4719],[-93.0597,44.4718],[-93.0393,44.4719],[-93.0394,44.4576],[-93.0396,44.4432],[-93.0397,44.4287],[-93.0399,44.4143],[-93.04,44.3999],[-93.0401,44.3855],[-93.0402,44.371],[-93.0403,44.3565],[-93.0403,44.3419],[-93.0405,44.3273],[-93.0405,44.3129],[-93.0405,44.2983],[-93.0406,44.2838],[-93.0407,44.2693],[-93.0409,44.2548],[-93.041,44.2402],[-93.0411,44.2257],[-93.0411,44.2113],[-93.0411,44.1968],[-93.0427,44.1968],[-93.0459,44.1968],[-93.0613,44.1967],[-93.0661,44.1967],[-93.0815,44.1967],[-93.0862,44.1967],[-93.1003,44.1967],[-93.1015,44.1967],[-93.1063,44.1967],[-93.1092,44.1967],[-93.1218,44.1967],[-93.1267,44.1967],[-93.1301,44.1967],[-93.1418,44.1967],[-93.1467,44.1967],[-93.1561,44.1966],[-93.1622,44.1966],[-93.1661,44.1966],[-93.1703,44.1966],[-93.1822,44.1966],[-93.1856,44.1966],[-93.1865,44.1966],[-93.2023,44.1966],[-93.2037,44.1966],[-93.2064,44.1966],[-93.2225,44.1966],[-93.2265,44.1966],[-93.2292,44.1966],[-93.2426,44.1966],[-93.2465,44.1966],[-93.255,44.1966],[-93.2629,44.1966],[-93.2664,44.1966],[-93.2767,44.1966],[-93.283,44.1966],[-93.2865,44.1965],[-93.2905,44.1965],[-93.3032,44.1965],[-93.3063,44.1965],[-93.3235,44.1965],[-93.3264,44.1965],[-93.3277,44.1965],[-93.3436,44.1965],[-93.3466,44.1965],[-93.3639,44.1965],[-93.3666,44.1965],[-93.3842,44.1965],[-93.3866,44.1965],[-93.4042,44.1965],[-93.4065,44.1965],[-93.4244,44.1964],[-93.4267,44.1964],[-93.4447,44.1964],[-93.4469,44.1964],[-93.4648,44.1963],[-93.467,44.1963],[-93.4852,44.1964],[-93.4872,44.1964],[-93.5053,44.1963],[-93.507,44.1963],[-93.5255,44.1962],[-93.5253,44.2107],[-93.5251,44.2251],[-93.5251,44.2388],[-93.5251,44.2533],[-93.5252,44.2685],[-93.5252,44.2829],[-93.5252,44.2975],[-93.5252,44.312],[-93.5249,44.3266],[-93.5249,44.3411],[-93.5245,44.3557],[-93.5245,44.3704],[-93.5246,44.3848],[-93.5245,44.3994],[-93.5245,44.4138],[-93.5245,44.4283],[-93.5245,44.4427],[-93.5245,44.4572],[-93.5244,44.4717],[-93.5245,44.4862],[-93.5244,44.5007],[-93.5243,44.5152],[-93.5244,44.5297],[-93.5242,44.5436]]],"type":"Polygon"},"id":"66","properties":{"Area":1335114621.00336,"CTYONLY_":66,"Code":"RICE","LASTMOD":"2010-10-17T00:00:00Z","Name":"Rice","Perimiter":154431.78788},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=1&offset=0&Name=Rice&filter=true%3Dtrue","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=1&offset=0&Name=Rice&filter=true%3Dtrue","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":1,"numberReturned":1,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_text_true_or_true.json.txt b/msautotest/api/expected/ogcapi_cql2_text_true_or_true.json.txt new file mode 100644 index 0000000000..dc6a7ed3f8 --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_text_true_or_true.json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 1 +OGC-NumberReturned: 1 + +{"features":[{"geometry":{"coordinates":[[[-93.5242,44.5436],[-93.5225,44.5436],[-93.504,44.5438],[-93.5018,44.5438],[-93.4835,44.5438],[-93.4817,44.5438],[-93.4734,44.5438],[-93.4632,44.5438],[-93.4609,44.5438],[-93.4429,44.5438],[-93.4408,44.5438],[-93.4326,44.5438],[-93.4226,44.5439],[-93.4206,44.5439],[-93.4024,44.5439],[-93.4003,44.5439],[-93.383,44.544],[-93.38,44.544],[-93.3627,44.5441],[-93.3596,44.5441],[-93.3556,44.5441],[-93.3424,44.5442],[-93.3395,44.5442],[-93.3221,44.544],[-93.3191,44.544],[-93.3128,44.544],[-93.3019,44.544],[-93.2988,44.544],[-93.2813,44.544],[-93.2814,44.5298],[-93.2815,44.5153],[-93.2815,44.501],[-93.2815,44.4865],[-93.2817,44.472],[-93.2618,44.4718],[-93.2415,44.4716],[-93.2213,44.4714],[-93.2008,44.4714],[-93.1808,44.4713],[-93.1605,44.4713],[-93.1408,44.4712],[-93.1206,44.4713],[-93.1002,44.4718],[-93.0799,44.4719],[-93.0597,44.4718],[-93.0393,44.4719],[-93.0394,44.4576],[-93.0396,44.4432],[-93.0397,44.4287],[-93.0399,44.4143],[-93.04,44.3999],[-93.0401,44.3855],[-93.0402,44.371],[-93.0403,44.3565],[-93.0403,44.3419],[-93.0405,44.3273],[-93.0405,44.3129],[-93.0405,44.2983],[-93.0406,44.2838],[-93.0407,44.2693],[-93.0409,44.2548],[-93.041,44.2402],[-93.0411,44.2257],[-93.0411,44.2113],[-93.0411,44.1968],[-93.0427,44.1968],[-93.0459,44.1968],[-93.0613,44.1967],[-93.0661,44.1967],[-93.0815,44.1967],[-93.0862,44.1967],[-93.1003,44.1967],[-93.1015,44.1967],[-93.1063,44.1967],[-93.1092,44.1967],[-93.1218,44.1967],[-93.1267,44.1967],[-93.1301,44.1967],[-93.1418,44.1967],[-93.1467,44.1967],[-93.1561,44.1966],[-93.1622,44.1966],[-93.1661,44.1966],[-93.1703,44.1966],[-93.1822,44.1966],[-93.1856,44.1966],[-93.1865,44.1966],[-93.2023,44.1966],[-93.2037,44.1966],[-93.2064,44.1966],[-93.2225,44.1966],[-93.2265,44.1966],[-93.2292,44.1966],[-93.2426,44.1966],[-93.2465,44.1966],[-93.255,44.1966],[-93.2629,44.1966],[-93.2664,44.1966],[-93.2767,44.1966],[-93.283,44.1966],[-93.2865,44.1965],[-93.2905,44.1965],[-93.3032,44.1965],[-93.3063,44.1965],[-93.3235,44.1965],[-93.3264,44.1965],[-93.3277,44.1965],[-93.3436,44.1965],[-93.3466,44.1965],[-93.3639,44.1965],[-93.3666,44.1965],[-93.3842,44.1965],[-93.3866,44.1965],[-93.4042,44.1965],[-93.4065,44.1965],[-93.4244,44.1964],[-93.4267,44.1964],[-93.4447,44.1964],[-93.4469,44.1964],[-93.4648,44.1963],[-93.467,44.1963],[-93.4852,44.1964],[-93.4872,44.1964],[-93.5053,44.1963],[-93.507,44.1963],[-93.5255,44.1962],[-93.5253,44.2107],[-93.5251,44.2251],[-93.5251,44.2388],[-93.5251,44.2533],[-93.5252,44.2685],[-93.5252,44.2829],[-93.5252,44.2975],[-93.5252,44.312],[-93.5249,44.3266],[-93.5249,44.3411],[-93.5245,44.3557],[-93.5245,44.3704],[-93.5246,44.3848],[-93.5245,44.3994],[-93.5245,44.4138],[-93.5245,44.4283],[-93.5245,44.4427],[-93.5245,44.4572],[-93.5244,44.4717],[-93.5245,44.4862],[-93.5244,44.5007],[-93.5243,44.5152],[-93.5244,44.5297],[-93.5242,44.5436]]],"type":"Polygon"},"id":"66","properties":{"Area":1335114621.00336,"CTYONLY_":66,"Code":"RICE","LASTMOD":"2010-10-17T00:00:00Z","Name":"Rice","Perimiter":154431.78788},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=1&offset=0&Name=Rice&filter=true%20or%20true","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=1&offset=0&Name=Rice&filter=true%20or%20true","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":1,"numberReturned":1,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_text_unary_minus.json.txt b/msautotest/api/expected/ogcapi_cql2_text_unary_minus.json.txt new file mode 100644 index 0000000000..625c9115b2 --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_text_unary_minus.json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 1 +OGC-NumberReturned: 1 + +{"features":[{"geometry":{"coordinates":[[[-96.4054,49.0001],[-96.4019,49.0001],[-96.3825,49.0001],[-96.3783,49.0001],[-96.3606,49.0001],[-96.3579,49.0001],[-96.3385,49.0001],[-96.3343,49.0001],[-96.3166,49.0001],[-96.3138,49.0001],[-96.2945,49.0001],[-96.2902,49.0001],[-96.2725,49.0001],[-96.2698,49.0001],[-96.2494,49.0001],[-96.2461,49.0001],[-96.2274,49.0001],[-96.2257,49.0001],[-96.2057,49.0001],[-96.2021,49.0001],[-96.1837,49.0],[-96.18,49.0],[-96.1617,49.0],[-96.1579,49.0],[-96.1401,49.0],[-96.1359,49.0],[-96.1176,49.0],[-96.1139,49.0],[-96.0957,49.0],[-96.0919,49.0],[-96.0738,49.0],[-96.07,49.0],[-96.0517,49.0],[-96.048,49.0],[-96.0298,49.0],[-96.026,49.0],[-96.0083,49.0],[-96.0045,49.0],[-95.9868,49.0],[-95.9784,49.0],[-95.9776,49.0],[-95.9755,49.0],[-95.9648,48.9999],[-95.9464,48.9999],[-95.943,48.9999],[-95.9225,48.9999],[-95.9211,48.9999],[-95.899,48.9998],[-95.883,48.9998],[-95.8771,48.9998],[-95.8564,48.9998],[-95.855,48.9998],[-95.8342,48.9998],[-95.8184,48.9997],[-95.8126,48.9997],[-95.7906,48.9997],[-95.7833,48.9997],[-95.7684,48.9997],[-95.7479,48.9996],[-95.7466,48.9996],[-95.7253,48.9996],[-95.7066,48.9996],[-95.7032,48.9996],[-95.681,48.9995],[-95.6654,48.9995],[-95.6596,48.9995],[-95.659,48.9995],[-95.6401,48.9995],[-95.6369,48.9995],[-95.6205,48.9994],[-95.615,48.9994],[-95.5948,48.9994],[-95.585,48.9994],[-95.573,48.9994],[-95.551,48.9993],[-95.5495,48.9993],[-95.5294,48.9993],[-95.5164,48.9993],[-95.5072,48.9993],[-95.4849,48.9992],[-95.4834,48.9992],[-95.4635,48.9992],[-95.4508,48.9992],[-95.4418,48.9992],[-95.4245,48.9991],[-95.4197,48.9991],[-95.3977,48.9991],[-95.3953,48.9991],[-95.3765,48.9991],[-95.3759,48.9991],[-95.3753,48.9991],[-95.3542,48.999],[-95.3513,48.999],[-95.3326,48.999],[-95.3286,48.999],[-95.3231,48.999],[-95.3224,48.9984],[-95.3204,48.9976],[-95.3202,48.9973],[-95.3204,48.9964],[-95.3206,48.9961],[-95.3201,48.9956],[-95.3197,48.9954],[-95.3191,48.9953],[-95.3187,48.9956],[-95.3182,48.996],[-95.3179,48.9961],[-95.3178,48.9961],[-95.3178,48.9958],[-95.3181,48.995],[-95.3191,48.9941],[-95.3204,48.9924],[-95.3206,48.9921],[-95.3224,48.9889],[-95.3227,48.9884],[-95.3242,48.9859],[-95.3245,48.985],[-95.3253,48.9832],[-95.3257,48.9814],[-95.3256,48.98],[-95.3255,48.9789],[-95.3257,48.9784],[-95.3253,48.976],[-95.325,48.9743],[-95.3249,48.9738],[-95.3248,48.9728],[-95.3247,48.972],[-95.3241,48.9703],[-95.3232,48.9692],[-95.3227,48.9685],[-95.3212,48.9672],[-95.3207,48.9669],[-95.3201,48.9648],[-95.3198,48.9643],[-95.3193,48.964],[-95.3193,48.9622],[-95.3202,48.9606],[-95.3206,48.9598],[-95.3206,48.9595],[-95.3206,48.959],[-95.3202,48.9581],[-95.3191,48.9569],[-95.3188,48.9562],[-95.3179,48.9559],[-95.3175,48.9552],[-95.3177,48.9545],[-95.3182,48.9535],[-95.3181,48.9531],[-95.3177,48.9525],[-95.3154,48.9513],[-95.3151,48.951],[-95.3141,48.9508],[-95.3131,48.9503],[-95.3125,48.9503],[-95.3123,48.9502],[-95.3119,48.9502],[-95.3119,48.9507],[-95.3129,48.9521],[-95.3129,48.9523],[-95.3126,48.9524],[-95.312,48.9524],[-95.3115,48.952],[-95.3108,48.9512],[-95.3104,48.951],[-95.3097,48.951],[-95.3089,48.9511],[-95.3079,48.9509],[-95.3061,48.9502],[-95.3052,48.9495],[-95.3046,48.9482],[-95.3046,48.947],[-95.305,48.9462],[-95.3053,48.9459],[-95.3061,48.9454],[-95.3068,48.9454],[-95.3069,48.9455],[-95.3069,48.9456],[-95.3063,48.9462],[-95.3062,48.9463],[-95.3061,48.9469],[-95.3062,48.9472],[-95.3062,48.9472],[-95.3071,48.9477],[-95.3081,48.948],[-95.3094,48.9481],[-95.3096,48.9482],[-95.3099,48.9484],[-95.31,48.9485],[-95.3103,48.9485],[-95.3104,48.9484],[-95.3103,48.948],[-95.3096,48.9478],[-95.3092,48.9477],[-95.3079,48.9474],[-95.3071,48.9469],[-95.3071,48.9466],[-95.3074,48.9465],[-95.3078,48.9466],[-95.3085,48.947],[-95.3086,48.9469],[-95.3086,48.9465],[-95.3088,48.9464],[-95.3095,48.9463],[-95.3102,48.9463],[-95.3114,48.9461],[-95.3131,48.946],[-95.3141,48.9457],[-95.3148,48.9452],[-95.3154,48.9448],[-95.3168,48.9431],[-95.3181,48.9421],[-95.3189,48.9419],[-95.3219,48.9412],[-95.3225,48.9409],[-95.3228,48.9403],[-95.3231,48.9389],[-95.3229,48.9373],[-95.3225,48.9358],[-95.3223,48.9355],[-95.3228,48.9344],[-95.3222,48.9327],[-95.3209,48.9307],[-95.3208,48.9305],[-95.3195,48.9285],[-95.3168,48.9245],[-95.315,48.9222],[-95.3141,48.921],[-95.3132,48.9198],[-95.3126,48.919],[-95.3119,48.9178],[-95.3115,48.9172],[-95.3109,48.9163],[-95.3102,48.9155],[-95.3093,48.9149],[-95.3092,48.9149],[-95.3085,48.9146],[-95.3078,48.9141],[-95.3074,48.9135],[-95.3064,48.9129],[-95.3061,48.9128],[-95.3059,48.9127],[-95.3043,48.9119],[-95.3038,48.9114],[-95.3027,48.91],[-95.3017,48.9093],[-95.2999,48.9086],[-95.2978,48.9083],[-95.2973,48.9081],[-95.2973,48.908],[-95.2973,48.9077],[-95.2976,48.9074],[-95.2977,48.9073],[-95.2978,48.9073],[-95.2978,48.9072],[-95.2978,48.9072],[-95.2979,48.9072],[-95.2979,48.9072],[-95.2979,48.9071],[-95.298,48.9071],[-95.298,48.9071],[-95.298,48.9071],[-95.2981,48.907],[-95.2982,48.9068],[-95.2983,48.9068],[-95.2985,48.9065],[-95.2985,48.9064],[-95.2986,48.9063],[-95.2988,48.906],[-95.2989,48.906],[-95.2991,48.9057],[-95.2992,48.9055],[-95.2994,48.9053],[-95.2996,48.9051],[-95.2997,48.905],[-95.2999,48.9048],[-95.2999,48.9048],[-95.2999,48.9048],[-95.3,48.9047],[-95.3,48.9047],[-95.3001,48.9047],[-95.3001,48.9046],[-95.3002,48.9045],[-95.3005,48.904],[-95.2993,48.9035],[-95.2983,48.9028],[-95.298,48.9027],[-95.2976,48.9026],[-95.2967,48.9027],[-95.2949,48.9028],[-95.2941,48.9027],[-95.2937,48.9023],[-95.2935,48.902],[-95.2927,48.9019],[-95.2914,48.9019],[-95.2909,48.9017],[-95.2908,48.9016],[-95.2907,48.9014],[-95.2906,48.9011],[-95.2911,48.9008],[-95.2911,48.9006],[-95.2901,48.9003],[-95.2896,48.9],[-95.289,48.8994],[-95.2882,48.8981],[-95.2879,48.8979],[-95.2872,48.8977],[-95.287,48.8976],[-95.2865,48.8975],[-95.2861,48.8976],[-95.2853,48.8977],[-95.2839,48.8975],[-95.2813,48.8967],[-95.2803,48.8965],[-95.2796,48.8962],[-95.279,48.8957],[-95.2782,48.8956],[-95.2773,48.8957],[-95.277,48.8958],[-95.2765,48.8962],[-95.2763,48.8963],[-95.2759,48.8962],[-95.2755,48.8959],[-95.2749,48.8956],[-95.2748,48.8951],[-95.2753,48.8943],[-95.2751,48.8938],[-95.2745,48.8931],[-95.2724,48.8921],[-95.2713,48.8915],[-95.268,48.8905],[-95.2677,48.8903],[-95.2674,48.89],[-95.2666,48.8894],[-95.2654,48.8888],[-95.265,48.8886],[-95.2646,48.8885],[-95.2639,48.8883],[-95.2635,48.888],[-95.2627,48.8877],[-95.2585,48.8867],[-95.2585,48.8867],[-95.257,48.8858],[-95.256,48.885],[-95.2548,48.8845],[-95.2517,48.8839],[-95.2507,48.8836],[-95.2502,48.8835],[-95.2496,48.8834],[-95.2485,48.8832],[-95.248,48.8836],[-95.2472,48.8835],[-95.2458,48.8829],[-95.2439,48.8823],[-95.2429,48.8822],[-95.2429,48.8822],[-95.2423,48.8821],[-95.2407,48.8821],[-95.2391,48.8819],[-95.2381,48.8817],[-95.2356,48.8815],[-95.2335,48.8814],[-95.231,48.8814],[-95.2287,48.8815],[-95.2265,48.8816],[-95.2252,48.8819],[-95.2212,48.883],[-95.2208,48.8831],[-95.2207,48.8831],[-95.22,48.8831],[-95.2193,48.8832],[-95.2188,48.8835],[-95.217,48.8835],[-95.2159,48.8839],[-95.2151,48.884],[-95.2144,48.8843],[-95.2122,48.8842],[-95.2117,48.8847],[-95.2115,48.8847],[-95.2112,48.8848],[-95.2085,48.8846],[-95.2059,48.8848],[-95.2024,48.8852],[-95.2009,48.8855],[-95.2005,48.8856],[-95.1986,48.8855],[-95.1956,48.8862],[-95.1924,48.8865],[-95.1919,48.8866],[-95.1913,48.8868],[-95.1901,48.887],[-95.1889,48.8873],[-95.1877,48.8874],[-95.1863,48.8877],[-95.1851,48.8882],[-95.1819,48.8888],[-95.1797,48.889],[-95.1791,48.889],[-95.1764,48.8893],[-95.173,48.8897],[-95.1701,48.8902],[-95.1674,48.8907],[-95.1648,48.8913],[-95.1641,48.8917],[-95.1618,48.892],[-95.1602,48.892],[-95.1579,48.8919],[-95.1564,48.8919],[-95.1555,48.892],[-95.1528,48.8921],[-95.1508,48.8922],[-95.1483,48.8923],[-95.1469,48.8927],[-95.1459,48.8929],[-95.1438,48.8934],[-95.1436,48.8937],[-95.1404,48.8943],[-95.1381,48.8949],[-95.1355,48.8959],[-95.1351,48.8963],[-95.1348,48.8963],[-95.1343,48.8963],[-95.1337,48.8969],[-95.1322,48.8973],[-95.1312,48.8975],[-95.1252,48.8998],[-95.1239,48.9001],[-95.1233,48.9004],[-95.1228,48.9006],[-95.1214,48.9013],[-95.121,48.9016],[-95.1205,48.9017],[-95.1204,48.9019],[-95.1182,48.9029],[-95.1163,48.9037],[-95.1151,48.9046],[-95.1144,48.9052],[-95.114,48.9061],[-95.1141,48.9064],[-95.1137,48.9069],[-95.1132,48.9071],[-95.113,48.9072],[-95.1126,48.9073],[-95.1107,48.9082],[-95.1096,48.9089],[-95.108,48.9099],[-95.1056,48.9113],[-95.1042,48.9121],[-95.1032,48.9127],[-95.102,48.9132],[-95.1008,48.9142],[-95.0981,48.9159],[-95.098,48.916],[-95.0975,48.9164],[-95.0971,48.9172],[-95.097,48.9176],[-95.0961,48.9181],[-95.0946,48.9191],[-95.0944,48.9193],[-95.0927,48.9204],[-95.0919,48.9207],[-95.0914,48.9208],[-95.0914,48.916],[-95.0912,48.9014],[-95.0911,48.8869],[-95.0908,48.8724],[-95.0908,48.858],[-95.0907,48.8436],[-95.0908,48.8291],[-95.0909,48.8147],[-95.0903,48.8],[-95.0903,48.7855],[-95.0903,48.7711],[-95.0901,48.7566],[-95.0901,48.7421],[-95.0899,48.7277],[-95.0898,48.713],[-95.1046,48.7129],[-95.1104,48.7129],[-95.1119,48.7129],[-95.1259,48.7129],[-95.1297,48.713],[-95.1333,48.713],[-95.1477,48.7129],[-95.1554,48.7129],[-95.1697,48.7129],[-95.1773,48.713],[-95.1917,48.713],[-95.1991,48.713],[-95.2112,48.713],[-95.2206,48.713],[-95.2331,48.713],[-95.2427,48.713],[-95.255,48.713],[-95.2645,48.713],[-95.2656,48.713],[-95.2767,48.713],[-95.2866,48.713],[-95.299,48.713],[-95.3051,48.713],[-95.3084,48.713],[-95.3205,48.713],[-95.3302,48.713],[-95.3425,48.7131],[-95.3425,48.6995],[-95.3424,48.6849],[-95.3423,48.6705],[-95.3424,48.6561],[-95.3425,48.6415],[-95.3426,48.6271],[-95.3424,48.6127],[-95.3426,48.5979],[-95.3423,48.5836],[-95.3423,48.5691],[-95.3424,48.5548],[-95.3425,48.5402],[-95.3628,48.5404],[-95.364,48.5403],[-95.3844,48.5402],[-95.386,48.5402],[-95.4061,48.5402],[-95.4078,48.5402],[-95.4279,48.54],[-95.4297,48.5399],[-95.4494,48.5399],[-95.4513,48.5399],[-95.4712,48.5396],[-95.4726,48.5396],[-95.493,48.5392],[-95.495,48.5392],[-95.5143,48.539],[-95.5163,48.539],[-95.5365,48.5389],[-95.5383,48.5389],[-95.558,48.5388],[-95.5603,48.5388],[-95.5801,48.5387],[-95.5821,48.5387],[-95.6023,48.5389],[-95.6232,48.5391],[-95.6447,48.5393],[-95.6666,48.5394],[-95.6886,48.5395],[-95.7102,48.5395],[-95.7322,48.54],[-95.7539,48.5404],[-95.7758,48.5406],[-95.7976,48.5405],[-95.8192,48.5404],[-95.8411,48.5406],[-95.8621,48.5414],[-95.8829,48.5419],[-95.8851,48.542],[-95.8986,48.5421],[-95.9046,48.5422],[-95.9064,48.5422],[-95.9269,48.5421],[-95.9486,48.5425],[-95.9498,48.5425],[-95.9704,48.543],[-95.9936,48.5435],[-96.0157,48.5437],[-96.0374,48.5438],[-96.0592,48.5437],[-96.0812,48.5436],[-96.1026,48.5438],[-96.1264,48.5439],[-96.1486,48.5442],[-96.1702,48.5445],[-96.1921,48.5446],[-96.2141,48.5449],[-96.2358,48.5452],[-96.2576,48.545],[-96.2794,48.5449],[-96.301,48.5448],[-96.3231,48.5446],[-96.3448,48.5444],[-96.3667,48.5443],[-96.3882,48.5442],[-96.3879,48.5588],[-96.3882,48.5733],[-96.3884,48.5877],[-96.3891,48.6024],[-96.389,48.6165],[-96.388,48.6313],[-96.3879,48.6454],[-96.3877,48.6599],[-96.3871,48.6741],[-96.3874,48.6887],[-96.3866,48.703],[-96.3873,48.7172],[-96.388,48.7172],[-96.4049,48.7172],[-96.4048,48.7318],[-96.4048,48.7465],[-96.4047,48.7607],[-96.4045,48.7758],[-96.4042,48.7903],[-96.4042,48.8048],[-96.4042,48.8198],[-96.4043,48.8343],[-96.4045,48.8491],[-96.4047,48.8635],[-96.405,48.878],[-96.405,48.8926],[-96.4053,48.9068],[-96.4053,48.9081],[-96.4053,48.9137],[-96.4054,48.9214],[-96.4054,48.9225],[-96.4053,48.936],[-96.4053,48.9371],[-96.4053,48.9504],[-96.4053,48.9515],[-96.4053,48.9648],[-96.4053,48.9658],[-96.4053,48.9705],[-96.4054,48.9793],[-96.4054,48.9803],[-96.4054,48.994],[-96.4054,48.9947],[-96.4054,49.0001]]],"type":"Polygon"},"id":"68","properties":{"Area":4347098503.12714,"CTYONLY_":4,"Code":"ROSE","LASTMOD":"2001-04-12T09:32:44Z","Name":"Roseau","Perimiter":302590.75293},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&filter=CTYONLY_%3D-(-4)","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&filter=CTYONLY_%3D-(-4)","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":1,"numberReturned":1,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_cql2_text_unsupported_function.json.txt b/msautotest/api/expected/ogcapi_cql2_text_unsupported_function.json.txt new file mode 100644 index 0000000000..f5685902a8 --- /dev/null +++ b/msautotest/api/expected/ogcapi_cql2_text_unsupported_function.json.txt @@ -0,0 +1,4 @@ +Content-Type: application/json +Status: 400 + +{"code":"InvalidParameterValue","description":"Cannot translate CQL2 filter to MapServer expression: Unhandled function foo"} diff --git a/msautotest/api/expected/ogcapi_error_repeated_query_parameter.json b/msautotest/api/expected/ogcapi_error_repeated_query_parameter.json new file mode 100644 index 0000000000..6633c70993 --- /dev/null +++ b/msautotest/api/expected/ogcapi_error_repeated_query_parameter.json @@ -0,0 +1 @@ +{"code":"InvalidParameterValue","description":"Query parameter f is repeated"} diff --git a/msautotest/api/expected/ogcapi_extraparams_collection_items.html b/msautotest/api/expected/ogcapi_extraparams_collection_items.html new file mode 100644 index 0000000000..6aeae6763b --- /dev/null +++ b/msautotest/api/expected/ogcapi_extraparams_collection_items.html @@ -0,0 +1,174 @@ + + + + OGC API Test + + + + + +

OGC API Test - Collection Items: Minnesota Population Centers

+ +

+ Number of matching items: 1081
+ Number of returned items: 10
+

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IDCTU_TypeCountyNamePopulation
2710700172CityNorman CountyAda1681
2709900190CityMower CountyAdams742
2710500262CityNobles CountyAdrian1278
2716300316CityWashington CountyAfton2932
2700100460CityAitkin CountyAitkin2279
2705700496CityHubbard CountyAkeley397
2714500622CityStearns CountyAlbany2618
2704700694CityFreeborn CountyAlbert Lea17843
2714900676CityStevens CountyAlberta122
2717100730CityWright CountyAlbertville7226
+ + + + + + + diff --git a/msautotest/api/expected/ogcapi_extraparams_collection_items.json b/msautotest/api/expected/ogcapi_extraparams_collection_items.json new file mode 100644 index 0000000000..747ef48e0b --- /dev/null +++ b/msautotest/api/expected/ogcapi_extraparams_collection_items.json @@ -0,0 +1 @@ +{"features":[{"geometry":{"coordinates":[-96.516634,47.299074],"type":"Point"},"id":"2710700172","properties":{"CTU_Type":"City","County":"Norman County","Name":"Ada","Population":"1681"},"type":"Feature"},{"geometry":{"coordinates":[-92.71905,43.565193],"type":"Point"},"id":"2709900190","properties":{"CTU_Type":"City","County":"Mower County","Name":"Adams","Population":"742"},"type":"Feature"},{"geometry":{"coordinates":[-95.933254,43.633357],"type":"Point"},"id":"2710500262","properties":{"CTU_Type":"City","County":"Nobles County","Name":"Adrian","Population":"1278"},"type":"Feature"},{"geometry":{"coordinates":[-92.78333,44.902781],"type":"Point"},"id":"2716300316","properties":{"CTU_Type":"City","County":"Washington County","Name":"Afton","Population":"2932"},"type":"Feature"},{"geometry":{"coordinates":[-93.706073,46.529251],"type":"Point"},"id":"2700100460","properties":{"CTU_Type":"City","County":"Aitkin County","Name":"Aitkin","Population":"2279"},"type":"Feature"},{"geometry":{"coordinates":[-94.728005,47.000597],"type":"Point"},"id":"2705700496","properties":{"CTU_Type":"City","County":"Hubbard County","Name":"Akeley","Population":"397"},"type":"Feature"},{"geometry":{"coordinates":[-94.568321,45.628679],"type":"Point"},"id":"2714500622","properties":{"CTU_Type":"City","County":"Stearns County","Name":"Albany","Population":"2618"},"type":"Feature"},{"geometry":{"coordinates":[-93.363673,43.654728],"type":"Point"},"id":"2704700694","properties":{"CTU_Type":"City","County":"Freeborn County","Name":"Albert Lea","Population":"17843"},"type":"Feature"},{"geometry":{"coordinates":[-96.04722,45.57333],"type":"Point"},"id":"2714900676","properties":{"CTU_Type":"City","County":"Stevens County","Name":"Alberta","Population":"122"},"type":"Feature"},{"geometry":{"coordinates":[-93.65417,45.237781],"type":"Point"},"id":"2717100730","properties":{"CTU_Type":"City","County":"Wright County","Name":"Albertville","Population":"7226"},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_population_centers/items?f=json&limit=10&offset=0&token=eyJ9.e30.SflKxw&user_id=12345","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_population_centers/items?f=html&limit=10&offset=0&token=eyJ9.e30.SflKxw&user_id=12345","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_population_centers/items?f=json&limit=10&offset=10&token=eyJ9.e30.SflKxw&user_id=12345","rel":"next","title":"next page","type":"application/geo+json"}],"numberMatched":1081,"numberReturned":10,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_extraparams_collection_items_limit.json b/msautotest/api/expected/ogcapi_extraparams_collection_items_limit.json new file mode 100644 index 0000000000..ecf30c290b --- /dev/null +++ b/msautotest/api/expected/ogcapi_extraparams_collection_items_limit.json @@ -0,0 +1 @@ +{"features":[{"geometry":{"coordinates":[-96.516634,47.299074],"type":"Point"},"id":"2710700172","properties":{"CTU_Type":"City","County":"Norman County","Name":"Ada","Population":"1681"},"type":"Feature"},{"geometry":{"coordinates":[-92.71905,43.565193],"type":"Point"},"id":"2709900190","properties":{"CTU_Type":"City","County":"Mower County","Name":"Adams","Population":"742"},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_population_centers/items?f=json&limit=2&offset=0&token=MISSING&user_id=-1","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_population_centers/items?f=html&limit=2&offset=0&token=MISSING&user_id=-1","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_population_centers/items?f=json&limit=2&offset=2&token=MISSING&user_id=-1","rel":"next","title":"next page","type":"application/geo+json"}],"numberMatched":1081,"numberReturned":2,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_extraparams_collections.html b/msautotest/api/expected/ogcapi_extraparams_collections.html new file mode 100644 index 0000000000..9d1aa13038 --- /dev/null +++ b/msautotest/api/expected/ogcapi_extraparams_collections.html @@ -0,0 +1,42 @@ + + + + OGC API Test + + + + + +

OGC API Test - Collections

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
#TitleTypeDescription
1Minnesota Major River CenterlinesfeatureThis dataset represents stream centerlines for major rivers in Minnesota.
2Minnesota Population CentersfeatureThis dataset contains cities, townships, reservations, county seats and unorganized Territories in Minnesota, represented with point geometry for cartographic purposes.
+ + + + + diff --git a/msautotest/api/expected/ogcapi_extraparams_collections.json b/msautotest/api/expected/ogcapi_extraparams_collections.json new file mode 100644 index 0000000000..b29dd19b0c --- /dev/null +++ b/msautotest/api/expected/ogcapi_extraparams_collections.json @@ -0,0 +1 @@ +{"collections":[{"crs":["http://www.opengis.net/def/crs/OGC/1.3/CRS84","http://www.opengis.net/def/crs/EPSG/0/26915"],"description":"This dataset represents stream centerlines for major rivers in Minnesota.","extent":{"spatial":{"bbox":[[-97.24163,43.234009,-90.515182,49.077965]],"crs":"http://www.opengis.net/def/crs/OGC/1.3/CRS84"}},"id":"mn_major_rivers","itemType":"feature","links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_major_rivers?f=json&token=eyJ9.e30.SflKxw&user_id=12345&layer_param=rivers","rel":"self","title":"This collection as JSON","type":"application/json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_major_rivers?f=html&token=eyJ9.e30.SflKxw&user_id=12345&layer_param=rivers","rel":"alternate","title":"This collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_major_rivers/items?f=json&token=eyJ9.e30.SflKxw&user_id=12345&layer_param=rivers","rel":"items","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_major_rivers/items?f=html&token=eyJ9.e30.SflKxw&user_id=12345&layer_param=rivers","rel":"items","title":"Items for this collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_major_rivers/schema?f=json&token=eyJ9.e30.SflKxw&user_id=12345&layer_param=rivers","rel":"http://www.opengis.net/def/rel/ogc/1.0/schema","title":"Schema for this collection as JSON schema","type":"application/schema+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_major_rivers/schema?f=html&token=eyJ9.e30.SflKxw&user_id=12345&layer_param=rivers","rel":"http://www.opengis.net/def/rel/ogc/1.0/schema","title":"Schema for this collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_major_rivers/queryables?f=json&token=eyJ9.e30.SflKxw&user_id=12345&layer_param=rivers","rel":"http://www.opengis.net/def/rel/ogc/1.0/queryables","title":"Queryables for this collection as JSON schema","type":"application/schema+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_major_rivers/queryables?f=html&token=eyJ9.e30.SflKxw&user_id=12345&layer_param=rivers","rel":"http://www.opengis.net/def/rel/ogc/1.0/queryables","title":"Queryables for this collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_major_rivers/sortables?f=json&token=eyJ9.e30.SflKxw&user_id=12345&layer_param=rivers","rel":"http://www.opengis.net/def/rel/ogc/1.0/sortables","title":"Sortables for this collection as JSON schema","type":"application/schema+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_major_rivers/sortables?f=html&token=eyJ9.e30.SflKxw&user_id=12345&layer_param=rivers","rel":"http://www.opengis.net/def/rel/ogc/1.0/sortables","title":"Sortables for this collection as HTML","type":"text/html"}],"storageCrs":"http://www.opengis.net/def/crs/EPSG/0/26915","title":"Minnesota Major River Centerlines"},{"crs":["http://www.opengis.net/def/crs/OGC/1.3/CRS84","http://www.opengis.net/def/crs/EPSG/0/26915"],"description":"This dataset contains cities, townships, reservations, county seats and unorganized Territories in Minnesota, represented with point geometry for cartographic purposes.","extent":{"spatial":{"bbox":[[-97.251964,43.439119,-89.594878,49.365107]],"crs":"http://www.opengis.net/def/crs/OGC/1.3/CRS84"}},"id":"mn_population_centers","itemType":"feature","links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_population_centers?f=json&token=eyJ9.e30.SflKxw&user_id=12345","rel":"self","title":"This collection as JSON","type":"application/json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_population_centers?f=html&token=eyJ9.e30.SflKxw&user_id=12345","rel":"alternate","title":"This collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_population_centers/items?f=json&token=eyJ9.e30.SflKxw&user_id=12345","rel":"items","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_population_centers/items?f=html&token=eyJ9.e30.SflKxw&user_id=12345","rel":"items","title":"Items for this collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_population_centers/schema?f=json&token=eyJ9.e30.SflKxw&user_id=12345","rel":"http://www.opengis.net/def/rel/ogc/1.0/schema","title":"Schema for this collection as JSON schema","type":"application/schema+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_population_centers/schema?f=html&token=eyJ9.e30.SflKxw&user_id=12345","rel":"http://www.opengis.net/def/rel/ogc/1.0/schema","title":"Schema for this collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_population_centers/queryables?f=json&token=eyJ9.e30.SflKxw&user_id=12345","rel":"http://www.opengis.net/def/rel/ogc/1.0/queryables","title":"Queryables for this collection as JSON schema","type":"application/schema+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_population_centers/queryables?f=html&token=eyJ9.e30.SflKxw&user_id=12345","rel":"http://www.opengis.net/def/rel/ogc/1.0/queryables","title":"Queryables for this collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_population_centers/sortables?f=json&token=eyJ9.e30.SflKxw&user_id=12345","rel":"http://www.opengis.net/def/rel/ogc/1.0/sortables","title":"Sortables for this collection as JSON schema","type":"application/schema+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_population_centers/sortables?f=html&token=eyJ9.e30.SflKxw&user_id=12345","rel":"http://www.opengis.net/def/rel/ogc/1.0/sortables","title":"Sortables for this collection as HTML","type":"text/html"},{"href":"https://gisdata.mn.gov/dataset/loc-pop-centers","title":"Layer in Minnesota Geocommons","type":"text/html"}],"storageCrs":"http://www.opengis.net/def/crs/EPSG/0/26915","title":"Minnesota Population Centers"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections?f=json&token=eyJ9.e30.SflKxw&user_id=12345","rel":"self","title":"This document as JSON","type":"application/json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections?f=html&token=eyJ9.e30.SflKxw&user_id=12345","rel":"alternate","title":"This document as HTML","type":"text/html"}]} diff --git a/msautotest/api/expected/ogcapi_extraparams_collections_items_unknown_parameter.json.txt b/msautotest/api/expected/ogcapi_extraparams_collections_items_unknown_parameter.json.txt new file mode 100644 index 0000000000..237dff26d3 --- /dev/null +++ b/msautotest/api/expected/ogcapi_extraparams_collections_items_unknown_parameter.json.txt @@ -0,0 +1,4 @@ +Content-Type: application/json +Status: 400 + +{"code":"InvalidParameterValue","description":"Unknown query parameter: unknown"} diff --git a/msautotest/api/expected/ogcapi_extraparams_collections_mn_major_rivers.html b/msautotest/api/expected/ogcapi_extraparams_collections_mn_major_rivers.html new file mode 100644 index 0000000000..38c71d937e --- /dev/null +++ b/msautotest/api/expected/ogcapi_extraparams_collections_mn_major_rivers.html @@ -0,0 +1,61 @@ + + + + OGC API Test + + + + + +

OGC API Test - Collection: Minnesota Major River Centerlines

+ +

This dataset represents stream centerlines for major rivers in Minnesota.

+ + + +

Storage CRS

+http://www.opengis.net/def/crs/EPSG/0/26915 + + + +

Supported CRS

+ + + +

Links

+ + + + + + + + diff --git a/msautotest/api/expected/ogcapi_extraparams_collections_mn_major_rivers.json b/msautotest/api/expected/ogcapi_extraparams_collections_mn_major_rivers.json new file mode 100644 index 0000000000..f1e687bc53 --- /dev/null +++ b/msautotest/api/expected/ogcapi_extraparams_collections_mn_major_rivers.json @@ -0,0 +1 @@ +{"crs":["http://www.opengis.net/def/crs/OGC/1.3/CRS84","http://www.opengis.net/def/crs/EPSG/0/26915"],"description":"This dataset represents stream centerlines for major rivers in Minnesota.","extent":{"spatial":{"bbox":[[-97.24163,43.234009,-90.515182,49.077965]],"crs":"http://www.opengis.net/def/crs/OGC/1.3/CRS84"}},"id":"mn_major_rivers","itemType":"feature","links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_major_rivers?f=json&token=MISSING&user_id=BBB&layer_param=rivers","rel":"self","title":"This collection as JSON","type":"application/json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_major_rivers?f=html&token=MISSING&user_id=BBB&layer_param=rivers","rel":"alternate","title":"This collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_major_rivers/items?f=json&token=MISSING&user_id=BBB&layer_param=rivers","rel":"items","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_major_rivers/items?f=html&token=MISSING&user_id=BBB&layer_param=rivers","rel":"items","title":"Items for this collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_major_rivers/schema?f=json&token=MISSING&user_id=BBB&layer_param=rivers","rel":"http://www.opengis.net/def/rel/ogc/1.0/schema","title":"Schema for this collection as JSON schema","type":"application/schema+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_major_rivers/schema?f=html&token=MISSING&user_id=BBB&layer_param=rivers","rel":"http://www.opengis.net/def/rel/ogc/1.0/schema","title":"Schema for this collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_major_rivers/queryables?f=json&token=MISSING&user_id=BBB&layer_param=rivers","rel":"http://www.opengis.net/def/rel/ogc/1.0/queryables","title":"Queryables for this collection as JSON schema","type":"application/schema+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_major_rivers/queryables?f=html&token=MISSING&user_id=BBB&layer_param=rivers","rel":"http://www.opengis.net/def/rel/ogc/1.0/queryables","title":"Queryables for this collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_major_rivers/sortables?f=json&token=MISSING&user_id=BBB&layer_param=rivers","rel":"http://www.opengis.net/def/rel/ogc/1.0/sortables","title":"Sortables for this collection as JSON schema","type":"application/schema+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_major_rivers/sortables?f=html&token=MISSING&user_id=BBB&layer_param=rivers","rel":"http://www.opengis.net/def/rel/ogc/1.0/sortables","title":"Sortables for this collection as HTML","type":"text/html"}],"storageCrs":"http://www.opengis.net/def/crs/EPSG/0/26915","title":"Minnesota Major River Centerlines"} diff --git a/msautotest/api/expected/ogcapi_extraparams_collections_mn_population_centers.html b/msautotest/api/expected/ogcapi_extraparams_collections_mn_population_centers.html new file mode 100644 index 0000000000..00ab2208df --- /dev/null +++ b/msautotest/api/expected/ogcapi_extraparams_collections_mn_population_centers.html @@ -0,0 +1,63 @@ + + + + OGC API Test + + + + + +

OGC API Test - Collection: Minnesota Population Centers

+ +

This dataset contains cities, townships, reservations, county seats and unorganized Territories in Minnesota, represented with point geometry for cartographic purposes.

+ + + +

Storage CRS

+http://www.opengis.net/def/crs/EPSG/0/26915 + + + +

Supported CRS

+ + + +

Links

+ + + + + + + + diff --git a/msautotest/api/expected/ogcapi_extraparams_collections_mn_population_centers.json b/msautotest/api/expected/ogcapi_extraparams_collections_mn_population_centers.json new file mode 100644 index 0000000000..79926b6762 --- /dev/null +++ b/msautotest/api/expected/ogcapi_extraparams_collections_mn_population_centers.json @@ -0,0 +1 @@ +{"crs":["http://www.opengis.net/def/crs/OGC/1.3/CRS84","http://www.opengis.net/def/crs/EPSG/0/26915"],"description":"This dataset contains cities, townships, reservations, county seats and unorganized Territories in Minnesota, represented with point geometry for cartographic purposes.","extent":{"spatial":{"bbox":[[-97.251964,43.439119,-89.594878,49.365107]],"crs":"http://www.opengis.net/def/crs/OGC/1.3/CRS84"}},"id":"mn_population_centers","itemType":"feature","links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_population_centers?f=json&token=eyJ9.e30.SflKxw&user_id=12345","rel":"self","title":"This collection as JSON","type":"application/json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_population_centers?f=html&token=eyJ9.e30.SflKxw&user_id=12345","rel":"alternate","title":"This collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_population_centers/items?f=json&token=eyJ9.e30.SflKxw&user_id=12345","rel":"items","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_population_centers/items?f=html&token=eyJ9.e30.SflKxw&user_id=12345","rel":"items","title":"Items for this collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_population_centers/schema?f=json&token=eyJ9.e30.SflKxw&user_id=12345","rel":"http://www.opengis.net/def/rel/ogc/1.0/schema","title":"Schema for this collection as JSON schema","type":"application/schema+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_population_centers/schema?f=html&token=eyJ9.e30.SflKxw&user_id=12345","rel":"http://www.opengis.net/def/rel/ogc/1.0/schema","title":"Schema for this collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_population_centers/queryables?f=json&token=eyJ9.e30.SflKxw&user_id=12345","rel":"http://www.opengis.net/def/rel/ogc/1.0/queryables","title":"Queryables for this collection as JSON schema","type":"application/schema+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_population_centers/queryables?f=html&token=eyJ9.e30.SflKxw&user_id=12345","rel":"http://www.opengis.net/def/rel/ogc/1.0/queryables","title":"Queryables for this collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_population_centers/sortables?f=json&token=eyJ9.e30.SflKxw&user_id=12345","rel":"http://www.opengis.net/def/rel/ogc/1.0/sortables","title":"Sortables for this collection as JSON schema","type":"application/schema+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_population_centers/sortables?f=html&token=eyJ9.e30.SflKxw&user_id=12345","rel":"http://www.opengis.net/def/rel/ogc/1.0/sortables","title":"Sortables for this collection as HTML","type":"text/html"},{"href":"https://gisdata.mn.gov/dataset/loc-pop-centers","title":"Layer in Minnesota Geocommons","type":"text/html"}],"storageCrs":"http://www.opengis.net/def/crs/EPSG/0/26915","title":"Minnesota Population Centers"} diff --git a/msautotest/api/expected/ogcapi_extraparams_invalid_parameter.json b/msautotest/api/expected/ogcapi_extraparams_invalid_parameter.json new file mode 100644 index 0000000000..90f8c301f8 --- /dev/null +++ b/msautotest/api/expected/ogcapi_extraparams_invalid_parameter.json @@ -0,0 +1 @@ +{"description":"","links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi?f=json&token=MISSING&user_id=12345","rel":"self","title":"This document as JSON","type":"application/json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi?f=html&token=MISSING&user_id=12345","rel":"alternate","title":"This document as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/conformance?f=json&token=MISSING&user_id=12345","rel":"conformance","title":"OCG API conformance classes implemented by this server (JSON)","type":"application/json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/conformance?f=html&token=MISSING&user_id=12345","rel":"conformance","title":"OCG API conformance classes implemented by this server","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections?f=json&token=MISSING&user_id=12345","rel":"data","title":"Information about feature collections available from this server (JSON)","type":"application/json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections?f=html&token=MISSING&user_id=12345","rel":"data","title":"Information about feature collections available from this server","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/api?f=json&token=MISSING&user_id=12345","rel":"service-desc","title":"OpenAPI document","type":"application/vnd.oai.openapi+json;version=3.0"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/api?f=html&token=MISSING&user_id=12345","rel":"service-doc","title":"API documentation","type":"text/html"},{"href":"https://mapserver.org","title":"MapServer project website","type":"text/html"}],"title":"OGC API Test"} diff --git a/msautotest/api/expected/ogcapi_extraparams_no_parameters.json b/msautotest/api/expected/ogcapi_extraparams_no_parameters.json new file mode 100644 index 0000000000..44c9feb9be --- /dev/null +++ b/msautotest/api/expected/ogcapi_extraparams_no_parameters.json @@ -0,0 +1 @@ +{"description":"","links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi?f=json&token=MISSING&user_id=-1","rel":"self","title":"This document as JSON","type":"application/json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi?f=html&token=MISSING&user_id=-1","rel":"alternate","title":"This document as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/conformance?f=json&token=MISSING&user_id=-1","rel":"conformance","title":"OCG API conformance classes implemented by this server (JSON)","type":"application/json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/conformance?f=html&token=MISSING&user_id=-1","rel":"conformance","title":"OCG API conformance classes implemented by this server","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections?f=json&token=MISSING&user_id=-1","rel":"data","title":"Information about feature collections available from this server (JSON)","type":"application/json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections?f=html&token=MISSING&user_id=-1","rel":"data","title":"Information about feature collections available from this server","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/api?f=json&token=MISSING&user_id=-1","rel":"service-desc","title":"OpenAPI document","type":"application/vnd.oai.openapi+json;version=3.0"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/api?f=html&token=MISSING&user_id=-1","rel":"service-doc","title":"API documentation","type":"text/html"},{"href":"https://mapserver.org","title":"MapServer project website","type":"text/html"}],"title":"OGC API Test"} diff --git a/msautotest/api/expected/ogcapi_invalid_api_signature1.txt b/msautotest/api/expected/ogcapi_invalid_api_signature1.txt new file mode 100644 index 0000000000..522b9a1add --- /dev/null +++ b/msautotest/api/expected/ogcapi_invalid_api_signature1.txt @@ -0,0 +1,7 @@ +Content-Type: text/html + + +MapServer Message + +msCGIDispatchAPIRequest(): Web application error. Invalid API signature. + \ No newline at end of file diff --git a/msautotest/api/expected/ogcapi_invalid_api_signature2.txt b/msautotest/api/expected/ogcapi_invalid_api_signature2.txt new file mode 100644 index 0000000000..522b9a1add --- /dev/null +++ b/msautotest/api/expected/ogcapi_invalid_api_signature2.txt @@ -0,0 +1,7 @@ +Content-Type: text/html + + +MapServer Message + +msCGIDispatchAPIRequest(): Web application error. Invalid API signature. + \ No newline at end of file diff --git a/msautotest/api/expected/ogcapi_invalid_mapfile.txt b/msautotest/api/expected/ogcapi_invalid_mapfile.txt new file mode 100644 index 0000000000..b7bdadc017 --- /dev/null +++ b/msautotest/api/expected/ogcapi_invalid_mapfile.txt @@ -0,0 +1,7 @@ +Content-Type: text/html + + +MapServer Message + +msLoadMap(): Unable to access file. (invalid.map) + \ No newline at end of file diff --git a/msautotest/api/expected/ogcapi_landing_page_unknown_parameter.json.txt b/msautotest/api/expected/ogcapi_landing_page_unknown_parameter.json.txt new file mode 100644 index 0000000000..237dff26d3 --- /dev/null +++ b/msautotest/api/expected/ogcapi_landing_page_unknown_parameter.json.txt @@ -0,0 +1,4 @@ +Content-Type: application/json +Status: 400 + +{"code":"InvalidParameterValue","description":"Unknown query parameter: unknown"} diff --git a/msautotest/api/expected/ogcapi_missing_api_signature1.txt b/msautotest/api/expected/ogcapi_missing_api_signature1.txt new file mode 100644 index 0000000000..222e459d80 --- /dev/null +++ b/msautotest/api/expected/ogcapi_missing_api_signature1.txt @@ -0,0 +1,7 @@ +Content-Type: text/html + + +MapServer Message + +mapserv(): Web application error. Traditional BROWSE mode requires a TEMPLATE in the WEB section, but none was provided. + \ No newline at end of file diff --git a/msautotest/api/expected/ogcapi_missing_api_signature2.txt b/msautotest/api/expected/ogcapi_missing_api_signature2.txt new file mode 100644 index 0000000000..222e459d80 --- /dev/null +++ b/msautotest/api/expected/ogcapi_missing_api_signature2.txt @@ -0,0 +1,7 @@ +Content-Type: text/html + + +MapServer Message + +mapserv(): Web application error. Traditional BROWSE mode requires a TEMPLATE in the WEB section, but none was provided. + \ No newline at end of file diff --git a/msautotest/api/expected/ogcapi_postgis_numeric_id_invalid_id.json b/msautotest/api/expected/ogcapi_postgis_numeric_id_invalid_id.json new file mode 100644 index 0000000000..7e9c48f63e --- /dev/null +++ b/msautotest/api/expected/ogcapi_postgis_numeric_id_invalid_id.json @@ -0,0 +1 @@ +{"code":"NotFound","description":"Invalid API path."} diff --git a/msautotest/api/expected/ogcapi_queryable_in_query_parameters_match.json.txt b/msautotest/api/expected/ogcapi_queryable_in_query_parameters_match.json.txt new file mode 100644 index 0000000000..bde7406288 --- /dev/null +++ b/msautotest/api/expected/ogcapi_queryable_in_query_parameters_match.json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 1 +OGC-NumberReturned: 1 + +{"features":[{"geometry":{"coordinates":[[[-93.5242,44.5436],[-93.5225,44.5436],[-93.504,44.5438],[-93.5018,44.5438],[-93.4835,44.5438],[-93.4817,44.5438],[-93.4734,44.5438],[-93.4632,44.5438],[-93.4609,44.5438],[-93.4429,44.5438],[-93.4408,44.5438],[-93.4326,44.5438],[-93.4226,44.5439],[-93.4206,44.5439],[-93.4024,44.5439],[-93.4003,44.5439],[-93.383,44.544],[-93.38,44.544],[-93.3627,44.5441],[-93.3596,44.5441],[-93.3556,44.5441],[-93.3424,44.5442],[-93.3395,44.5442],[-93.3221,44.544],[-93.3191,44.544],[-93.3128,44.544],[-93.3019,44.544],[-93.2988,44.544],[-93.2813,44.544],[-93.2814,44.5298],[-93.2815,44.5153],[-93.2815,44.501],[-93.2815,44.4865],[-93.2817,44.472],[-93.2618,44.4718],[-93.2415,44.4716],[-93.2213,44.4714],[-93.2008,44.4714],[-93.1808,44.4713],[-93.1605,44.4713],[-93.1408,44.4712],[-93.1206,44.4713],[-93.1002,44.4718],[-93.0799,44.4719],[-93.0597,44.4718],[-93.0393,44.4719],[-93.0394,44.4576],[-93.0396,44.4432],[-93.0397,44.4287],[-93.0399,44.4143],[-93.04,44.3999],[-93.0401,44.3855],[-93.0402,44.371],[-93.0403,44.3565],[-93.0403,44.3419],[-93.0405,44.3273],[-93.0405,44.3129],[-93.0405,44.2983],[-93.0406,44.2838],[-93.0407,44.2693],[-93.0409,44.2548],[-93.041,44.2402],[-93.0411,44.2257],[-93.0411,44.2113],[-93.0411,44.1968],[-93.0427,44.1968],[-93.0459,44.1968],[-93.0613,44.1967],[-93.0661,44.1967],[-93.0815,44.1967],[-93.0862,44.1967],[-93.1003,44.1967],[-93.1015,44.1967],[-93.1063,44.1967],[-93.1092,44.1967],[-93.1218,44.1967],[-93.1267,44.1967],[-93.1301,44.1967],[-93.1418,44.1967],[-93.1467,44.1967],[-93.1561,44.1966],[-93.1622,44.1966],[-93.1661,44.1966],[-93.1703,44.1966],[-93.1822,44.1966],[-93.1856,44.1966],[-93.1865,44.1966],[-93.2023,44.1966],[-93.2037,44.1966],[-93.2064,44.1966],[-93.2225,44.1966],[-93.2265,44.1966],[-93.2292,44.1966],[-93.2426,44.1966],[-93.2465,44.1966],[-93.255,44.1966],[-93.2629,44.1966],[-93.2664,44.1966],[-93.2767,44.1966],[-93.283,44.1966],[-93.2865,44.1965],[-93.2905,44.1965],[-93.3032,44.1965],[-93.3063,44.1965],[-93.3235,44.1965],[-93.3264,44.1965],[-93.3277,44.1965],[-93.3436,44.1965],[-93.3466,44.1965],[-93.3639,44.1965],[-93.3666,44.1965],[-93.3842,44.1965],[-93.3866,44.1965],[-93.4042,44.1965],[-93.4065,44.1965],[-93.4244,44.1964],[-93.4267,44.1964],[-93.4447,44.1964],[-93.4469,44.1964],[-93.4648,44.1963],[-93.467,44.1963],[-93.4852,44.1964],[-93.4872,44.1964],[-93.5053,44.1963],[-93.507,44.1963],[-93.5255,44.1962],[-93.5253,44.2107],[-93.5251,44.2251],[-93.5251,44.2388],[-93.5251,44.2533],[-93.5252,44.2685],[-93.5252,44.2829],[-93.5252,44.2975],[-93.5252,44.312],[-93.5249,44.3266],[-93.5249,44.3411],[-93.5245,44.3557],[-93.5245,44.3704],[-93.5246,44.3848],[-93.5245,44.3994],[-93.5245,44.4138],[-93.5245,44.4283],[-93.5245,44.4427],[-93.5245,44.4572],[-93.5244,44.4717],[-93.5245,44.4862],[-93.5244,44.5007],[-93.5243,44.5152],[-93.5244,44.5297],[-93.5242,44.5436]]],"type":"Polygon"},"id":"66","properties":{"Area":1335114621.00336,"CTYONLY_":66,"Code":"RICE","LASTMOD":"2010-10-17T00:00:00Z","Name":"Rice","Perimiter":154431.78788},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&Name=Rice","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&Name=Rice","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":1,"numberReturned":1,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_queryable_in_query_parameters_match_with_bbox.json.txt b/msautotest/api/expected/ogcapi_queryable_in_query_parameters_match_with_bbox.json.txt new file mode 100644 index 0000000000..13f442a7a9 --- /dev/null +++ b/msautotest/api/expected/ogcapi_queryable_in_query_parameters_match_with_bbox.json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 1 +OGC-NumberReturned: 1 + +{"features":[{"geometry":{"coordinates":[[[-93.5242,44.5436],[-93.5225,44.5436],[-93.504,44.5438],[-93.5018,44.5438],[-93.4835,44.5438],[-93.4817,44.5438],[-93.4734,44.5438],[-93.4632,44.5438],[-93.4609,44.5438],[-93.4429,44.5438],[-93.4408,44.5438],[-93.4326,44.5438],[-93.4226,44.5439],[-93.4206,44.5439],[-93.4024,44.5439],[-93.4003,44.5439],[-93.383,44.544],[-93.38,44.544],[-93.3627,44.5441],[-93.3596,44.5441],[-93.3556,44.5441],[-93.3424,44.5442],[-93.3395,44.5442],[-93.3221,44.544],[-93.3191,44.544],[-93.3128,44.544],[-93.3019,44.544],[-93.2988,44.544],[-93.2813,44.544],[-93.2814,44.5298],[-93.2815,44.5153],[-93.2815,44.501],[-93.2815,44.4865],[-93.2817,44.472],[-93.2618,44.4718],[-93.2415,44.4716],[-93.2213,44.4714],[-93.2008,44.4714],[-93.1808,44.4713],[-93.1605,44.4713],[-93.1408,44.4712],[-93.1206,44.4713],[-93.1002,44.4718],[-93.0799,44.4719],[-93.0597,44.4718],[-93.0393,44.4719],[-93.0394,44.4576],[-93.0396,44.4432],[-93.0397,44.4287],[-93.0399,44.4143],[-93.04,44.3999],[-93.0401,44.3855],[-93.0402,44.371],[-93.0403,44.3565],[-93.0403,44.3419],[-93.0405,44.3273],[-93.0405,44.3129],[-93.0405,44.2983],[-93.0406,44.2838],[-93.0407,44.2693],[-93.0409,44.2548],[-93.041,44.2402],[-93.0411,44.2257],[-93.0411,44.2113],[-93.0411,44.1968],[-93.0427,44.1968],[-93.0459,44.1968],[-93.0613,44.1967],[-93.0661,44.1967],[-93.0815,44.1967],[-93.0862,44.1967],[-93.1003,44.1967],[-93.1015,44.1967],[-93.1063,44.1967],[-93.1092,44.1967],[-93.1218,44.1967],[-93.1267,44.1967],[-93.1301,44.1967],[-93.1418,44.1967],[-93.1467,44.1967],[-93.1561,44.1966],[-93.1622,44.1966],[-93.1661,44.1966],[-93.1703,44.1966],[-93.1822,44.1966],[-93.1856,44.1966],[-93.1865,44.1966],[-93.2023,44.1966],[-93.2037,44.1966],[-93.2064,44.1966],[-93.2225,44.1966],[-93.2265,44.1966],[-93.2292,44.1966],[-93.2426,44.1966],[-93.2465,44.1966],[-93.255,44.1966],[-93.2629,44.1966],[-93.2664,44.1966],[-93.2767,44.1966],[-93.283,44.1966],[-93.2865,44.1965],[-93.2905,44.1965],[-93.3032,44.1965],[-93.3063,44.1965],[-93.3235,44.1965],[-93.3264,44.1965],[-93.3277,44.1965],[-93.3436,44.1965],[-93.3466,44.1965],[-93.3639,44.1965],[-93.3666,44.1965],[-93.3842,44.1965],[-93.3866,44.1965],[-93.4042,44.1965],[-93.4065,44.1965],[-93.4244,44.1964],[-93.4267,44.1964],[-93.4447,44.1964],[-93.4469,44.1964],[-93.4648,44.1963],[-93.467,44.1963],[-93.4852,44.1964],[-93.4872,44.1964],[-93.5053,44.1963],[-93.507,44.1963],[-93.5255,44.1962],[-93.5253,44.2107],[-93.5251,44.2251],[-93.5251,44.2388],[-93.5251,44.2533],[-93.5252,44.2685],[-93.5252,44.2829],[-93.5252,44.2975],[-93.5252,44.312],[-93.5249,44.3266],[-93.5249,44.3411],[-93.5245,44.3557],[-93.5245,44.3704],[-93.5246,44.3848],[-93.5245,44.3994],[-93.5245,44.4138],[-93.5245,44.4283],[-93.5245,44.4427],[-93.5245,44.4572],[-93.5244,44.4717],[-93.5245,44.4862],[-93.5244,44.5007],[-93.5243,44.5152],[-93.5244,44.5297],[-93.5242,44.5436]]],"type":"Polygon"},"id":"66","properties":{"Area":1335114621.00336,"CTYONLY_":66,"Code":"RICE","LASTMOD":"2010-10-17T00:00:00Z","Name":"Rice","Perimiter":154431.78788},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&bbox=-100,0,-90,90&Name=Rice","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&bbox=-100,0,-90,90&Name=Rice","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":1,"numberReturned":1,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_queryable_in_query_parameters_no_match.json.txt b/msautotest/api/expected/ogcapi_queryable_in_query_parameters_no_match.json.txt new file mode 100644 index 0000000000..fc4bc54492 --- /dev/null +++ b/msautotest/api/expected/ogcapi_queryable_in_query_parameters_no_match.json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 0 +OGC-NumberReturned: 0 + +{"features":[],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&Name=no_match","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&Name=no_match","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":0,"numberReturned":0,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_queryable_in_query_parameters_no_match_with_bbox.json.txt b/msautotest/api/expected/ogcapi_queryable_in_query_parameters_no_match_with_bbox.json.txt new file mode 100644 index 0000000000..ff81fb755e --- /dev/null +++ b/msautotest/api/expected/ogcapi_queryable_in_query_parameters_no_match_with_bbox.json.txt @@ -0,0 +1,8 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +OGC-NumberMatched: 0 +OGC-NumberReturned: 0 + +{"features":[],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&bbox=0,0,1,1&Name=Rice","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&bbox=0,0,1,1&Name=Rice","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"}],"numberMatched":0,"numberReturned":0,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_queryable_in_query_parameters_not_queryable.json.txt b/msautotest/api/expected/ogcapi_queryable_in_query_parameters_not_queryable.json.txt new file mode 100644 index 0000000000..629b9506d0 --- /dev/null +++ b/msautotest/api/expected/ogcapi_queryable_in_query_parameters_not_queryable.json.txt @@ -0,0 +1,4 @@ +Content-Type: application/json +Status: 400 + +{"code":"InvalidParameterValue","description":"Unknown query parameter: AREA"} diff --git a/msautotest/api/expected/ogcapi_queryables.html b/msautotest/api/expected/ogcapi_queryables.html new file mode 100644 index 0000000000..91feeef870 --- /dev/null +++ b/msautotest/api/expected/ogcapi_queryables.html @@ -0,0 +1,78 @@ + + + + OGC API Test + + + + + +

OGC API Test - Collection Queryables: This is the standard Minnesota State County Boundary dataset.

+ +

Queryables:

+
    + +
  • Area: + + number + + + +
  • + +
  • CTYONLY_: + + integer + + + +
  • + +
  • LASTMOD: + + string + + + ,  + + + date-time + +
  • + +
  • Name: + + string + + + +
  • + +
  • geom: + + + + geometry-polygon-or-multipolygon + +
  • + +
+ + + +

Template Data

+

+ API Root: http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi
+ Path: ["ogcapi.map","ogcapi","collections","mn_counties","queryables"]
+ Params: {"f":"html"}
+ Extra Params:
+ Title: OGC API Test
+ Tags: {"debug":"true","sample":"sample tag"}
+

+ + + + + + + diff --git a/msautotest/api/expected/ogcapi_queryables.json.txt b/msautotest/api/expected/ogcapi_queryables.json.txt new file mode 100644 index 0000000000..f653691207 --- /dev/null +++ b/msautotest/api/expected/ogcapi_queryables.json.txt @@ -0,0 +1,3 @@ +Content-Type: application/schema+json + +{"$id":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/queryables","$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":false,"description":"This is the standard Minnesota State County Boundary dataset.","properties":{"Area":{"description":"Queryable item 'Area'","type":"number"},"CTYONLY_":{"description":"Queryable item 'CTYONLY_'","type":"integer"},"LASTMOD":{"description":"Queryable item 'LASTMOD'","format":"date-time","type":"string"},"Name":{"description":"Queryable item 'Name'","type":"string"},"geom":{"description":"The geometry of the collection.","format":"geometry-polygon-or-multipolygon","title":"geom","x-ogc-role":"primary-geometry"}},"title":"State of Minnesota County Boundaries","type":"object"} diff --git a/msautotest/api/expected/ogcapi_queryables_all.json.txt b/msautotest/api/expected/ogcapi_queryables_all.json.txt new file mode 100644 index 0000000000..4e768933cd --- /dev/null +++ b/msautotest/api/expected/ogcapi_queryables_all.json.txt @@ -0,0 +1,3 @@ +Content-Type: application/schema+json + +{"$id":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties_all_queryables_and_sortables/queryables","$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":false,"description":"This is the standard Minnesota State County Boundary dataset.","properties":{"Area":{"description":"Queryable item 'Area'","type":"number"},"COUN":{"description":"Queryable item 'COUN'","type":"string"},"CTYONLY_":{"description":"Queryable item 'CTYONLY_'","type":"integer"},"CTYONLY_ID":{"description":"Queryable item 'CTYONLY_ID'","type":"string"},"CTY_FIPS":{"description":"Queryable item 'CTY_FIPS'","type":"string"},"Code":{"description":"Queryable item 'Code'","type":"string"},"LASTMOD":{"description":"Queryable item 'LASTMOD'","format":"date-time","type":"string"},"Name":{"description":"Queryable item 'Name'","type":"string"},"Perimiter":{"description":"Queryable item 'Perimiter'","type":"number"},"geom":{"description":"The geometry of the collection.","format":"geometry-polygon-or-multipolygon","title":"geom","x-ogc-role":"primary-geometry"}},"title":"State of Minnesota County Boundaries","type":"object"} diff --git a/msautotest/api/expected/ogcapi_queryables_error_collection.json.txt b/msautotest/api/expected/ogcapi_queryables_error_collection.json.txt new file mode 100644 index 0000000000..4b88cd5cb0 --- /dev/null +++ b/msautotest/api/expected/ogcapi_queryables_error_collection.json.txt @@ -0,0 +1,4 @@ +Content-Type: application/json +Status: 404 + +{"code":"NotFound","description":"Invalid collection."} diff --git a/msautotest/api/expected/ogcapi_queryables_error_unexpected_kvp.json.txt b/msautotest/api/expected/ogcapi_queryables_error_unexpected_kvp.json.txt new file mode 100644 index 0000000000..e9702c8ccf --- /dev/null +++ b/msautotest/api/expected/ogcapi_queryables_error_unexpected_kvp.json.txt @@ -0,0 +1,4 @@ +Content-Type: application/json +Status: 400 + +{"code":"InvalidParameterValue","description":"Unknown query parameter: unexpected"} diff --git a/msautotest/api/expected/ogcapi_queryables_none.json.txt b/msautotest/api/expected/ogcapi_queryables_none.json.txt new file mode 100644 index 0000000000..f55f66f663 --- /dev/null +++ b/msautotest/api/expected/ogcapi_queryables_none.json.txt @@ -0,0 +1,3 @@ +Content-Type: application/schema+json + +{"$id":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties_no_queryables_and_sortables/queryables","$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":false,"description":"This is the standard Minnesota State County Boundary dataset.","properties":{"geom":{"description":"The geometry of the collection.","format":"geometry-polygon-or-multipolygon","title":"geom","x-ogc-role":"primary-geometry"}},"title":"State of Minnesota County Boundaries","type":"object"} diff --git a/msautotest/api/expected/ogcapi_root.html.txt b/msautotest/api/expected/ogcapi_root.html.txt new file mode 100644 index 0000000000..275368fd4f --- /dev/null +++ b/msautotest/api/expected/ogcapi_root.html.txt @@ -0,0 +1,59 @@ +Content-Type: text/html + + + + + OGC API Test + + + + + +

OGC API Test

+

+ This is a test OGC API server description set via oga_description. +

+ +

Links

+ + + + +

Template Data

+

+ API Root: http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi
+ Path: ["ogcapi.map","ogcapi"]
+ Params: {}
+ Extra Params:
+ Title: OGC API Test
+ Tags: {"debug":"true","sample":"sample tag"}
+

+ + + + + + + diff --git a/msautotest/api/expected/ogcapi_root.json b/msautotest/api/expected/ogcapi_root.json new file mode 100644 index 0000000000..c450a3aebe --- /dev/null +++ b/msautotest/api/expected/ogcapi_root.json @@ -0,0 +1 @@ +{"description":"This is a test OGC API server description set via oga_description.","links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi?f=json","rel":"self","title":"This document as JSON","type":"application/json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi?f=html","rel":"alternate","title":"This document as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/conformance?f=json","rel":"conformance","title":"OCG API conformance classes implemented by this server (JSON)","type":"application/json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/conformance?f=html","rel":"conformance","title":"OCG API conformance classes implemented by this server","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections?f=json","rel":"data","title":"Information about feature collections available from this server (JSON)","type":"application/json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections?f=html","rel":"data","title":"Information about feature collections available from this server","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/api?f=json","rel":"service-desc","title":"OpenAPI document","type":"application/vnd.oai.openapi+json;version=3.0"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/api?f=html","rel":"service-doc","title":"API documentation","type":"text/html"},{"href":"https://mapserver.org","title":"MapServer project website","type":"text/html"},{"href":"https://ogcapi.ogc.org","title":"OCG API website","type":"text/html"}],"title":"OGC API Test"} diff --git a/msautotest/api/expected/ogcapi_root.json.txt b/msautotest/api/expected/ogcapi_root.json.txt new file mode 100644 index 0000000000..34ac4b9aa6 --- /dev/null +++ b/msautotest/api/expected/ogcapi_root.json.txt @@ -0,0 +1,3 @@ +Content-Type: application/json + +{"description":"This is a test OGC API server description set via oga_description.","links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi?f=json","rel":"self","title":"This document as JSON","type":"application/json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi?f=html","rel":"alternate","title":"This document as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/conformance?f=json","rel":"conformance","title":"OCG API conformance classes implemented by this server (JSON)","type":"application/json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/conformance?f=html","rel":"conformance","title":"OCG API conformance classes implemented by this server","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections?f=json","rel":"data","title":"Information about feature collections available from this server (JSON)","type":"application/json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections?f=html","rel":"data","title":"Information about feature collections available from this server","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/api?f=json","rel":"service-desc","title":"OpenAPI document","type":"application/vnd.oai.openapi+json;version=3.0"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/api?f=html","rel":"service-doc","title":"API documentation","type":"text/html"},{"href":"https://mapserver.org","title":"MapServer project website","type":"text/html"},{"href":"https://ogcapi.ogc.org","title":"OCG API website","type":"text/html"}],"title":"OGC API Test"} diff --git a/msautotest/api/expected/ogcapi_schema.html b/msautotest/api/expected/ogcapi_schema.html new file mode 100644 index 0000000000..c3ef85a849 --- /dev/null +++ b/msautotest/api/expected/ogcapi_schema.html @@ -0,0 +1,118 @@ + + + + OGC API Test + + + + + +

OGC API Test - Collection schema: This is the standard Minnesota State County Boundary dataset.

+ +

Schema:

+
    + +
  • Area: + + number + + + +
  • + +
  • COUN: + + string + + + +
  • + +
  • CTYONLY_: + + integer + + + +
  • + +
  • CTYONLY_ID: + + string + + + +
  • + +
  • CTY_FIPS: + + string + + + +
  • + +
  • Code: + + string + + + +
  • + +
  • LASTMOD: + + string + + + ,  + + + date-time + +
  • + +
  • Name: + + string + + + +
  • + +
  • Perimiter: + + number + + + +
  • + +
  • geom: + + + + geometry-polygon-or-multipolygon + +
  • + +
+ + + +

Template Data

+

+ API Root: http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi
+ Path: ["ogcapi.map","ogcapi","collections","mn_counties","schema"]
+ Params: {"f":"html"}
+ Extra Params:
+ Title: OGC API Test
+ Tags: {"debug":"true","sample":"sample tag"}
+

+ + + + + + + diff --git a/msautotest/api/expected/ogcapi_schema.json.txt b/msautotest/api/expected/ogcapi_schema.json.txt new file mode 100644 index 0000000000..519f72db89 --- /dev/null +++ b/msautotest/api/expected/ogcapi_schema.json.txt @@ -0,0 +1,3 @@ +Content-Type: application/schema+json + +{"$id":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/schema","$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":false,"description":"This is the standard Minnesota State County Boundary dataset.","properties":{"Area":{"description":"Returnable item 'Area'","type":"number"},"COUN":{"description":"Returnable item 'COUN'","type":"string"},"CTYONLY_":{"description":"Returnable item 'CTYONLY_'","type":"integer"},"CTYONLY_ID":{"description":"Returnable item 'CTYONLY_ID'","type":"string"},"CTY_FIPS":{"description":"Returnable item 'CTY_FIPS'","type":"string"},"Code":{"description":"Returnable item 'Code'","type":"string"},"LASTMOD":{"description":"Returnable item 'LASTMOD'","format":"date-time","type":"string"},"Name":{"description":"Returnable item 'Name'","type":"string"},"Perimiter":{"description":"Returnable item 'Perimiter'","type":"number"},"geom":{"description":"The geometry of the collection.","format":"geometry-polygon-or-multipolygon","title":"geom","x-ogc-role":"primary-geometry"}},"title":"State of Minnesota County Boundaries","type":"object"} diff --git a/msautotest/api/expected/ogcapi_schema_error_collection.json.txt b/msautotest/api/expected/ogcapi_schema_error_collection.json.txt new file mode 100644 index 0000000000..4b88cd5cb0 --- /dev/null +++ b/msautotest/api/expected/ogcapi_schema_error_collection.json.txt @@ -0,0 +1,4 @@ +Content-Type: application/json +Status: 404 + +{"code":"NotFound","description":"Invalid collection."} diff --git a/msautotest/api/expected/ogcapi_schema_error_unexpected_kvp.json.txt b/msautotest/api/expected/ogcapi_schema_error_unexpected_kvp.json.txt new file mode 100644 index 0000000000..e9702c8ccf --- /dev/null +++ b/msautotest/api/expected/ogcapi_schema_error_unexpected_kvp.json.txt @@ -0,0 +1,4 @@ +Content-Type: application/json +Status: 400 + +{"code":"InvalidParameterValue","description":"Unknown query parameter: unexpected"} diff --git a/msautotest/api/expected/ogcapi_sortables.html b/msautotest/api/expected/ogcapi_sortables.html new file mode 100644 index 0000000000..be2872f60b --- /dev/null +++ b/msautotest/api/expected/ogcapi_sortables.html @@ -0,0 +1,46 @@ + + + + OGC API Test + + + + + +

OGC API Test - Collection Sortables: This is the standard Minnesota State County Boundary dataset.

+ +

Sortables:

+
    + +
  • lastmod: + + string + + + ,  + + + date-time + +
  • + +
+ + + +

Template Data

+

+ API Root: http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi
+ Path: ["ogcapi.map","ogcapi","collections","mn_counties","sortables"]
+ Params: {"f":"html"}
+ Extra Params:
+ Title: OGC API Test
+ Tags: {"debug":"true","sample":"sample tag"}
+

+ + + + + + + diff --git a/msautotest/api/expected/ogcapi_sortables.json.txt b/msautotest/api/expected/ogcapi_sortables.json.txt new file mode 100644 index 0000000000..40e62c9e07 --- /dev/null +++ b/msautotest/api/expected/ogcapi_sortables.json.txt @@ -0,0 +1,3 @@ +Content-Type: application/schema+json + +{"$id":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/sortables","$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":false,"description":"This is the standard Minnesota State County Boundary dataset.","properties":{"lastmod":{"description":"Sortable item 'lastmod'","format":"date-time","type":"string"}},"title":"State of Minnesota County Boundaries","type":"object"} diff --git a/msautotest/api/expected/ogcapi_sortables_all.json.txt b/msautotest/api/expected/ogcapi_sortables_all.json.txt new file mode 100644 index 0000000000..00e939d235 --- /dev/null +++ b/msautotest/api/expected/ogcapi_sortables_all.json.txt @@ -0,0 +1,3 @@ +Content-Type: application/schema+json + +{"$id":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties_all_queryables_and_sortables/sortables","$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":false,"description":"This is the standard Minnesota State County Boundary dataset.","properties":{"Area":{"description":"Sortable item 'Area'","type":"number"},"COUN":{"description":"Sortable item 'COUN'","type":"string"},"CTYONLY_":{"description":"Sortable item 'CTYONLY_'","type":"integer"},"CTYONLY_ID":{"description":"Sortable item 'CTYONLY_ID'","type":"string"},"CTY_FIPS":{"description":"Sortable item 'CTY_FIPS'","type":"string"},"Code":{"description":"Sortable item 'Code'","type":"string"},"LASTMOD":{"description":"Sortable item 'LASTMOD'","format":"date-time","type":"string"},"Name":{"description":"Sortable item 'Name'","type":"string"},"Perimiter":{"description":"Sortable item 'Perimiter'","type":"number"}},"title":"State of Minnesota County Boundaries","type":"object"} diff --git a/msautotest/api/expected/ogcapi_sortables_error_collection.json.txt b/msautotest/api/expected/ogcapi_sortables_error_collection.json.txt new file mode 100644 index 0000000000..4b88cd5cb0 --- /dev/null +++ b/msautotest/api/expected/ogcapi_sortables_error_collection.json.txt @@ -0,0 +1,4 @@ +Content-Type: application/json +Status: 404 + +{"code":"NotFound","description":"Invalid collection."} diff --git a/msautotest/api/expected/ogcapi_sortables_error_unexpected_kvp.json.txt b/msautotest/api/expected/ogcapi_sortables_error_unexpected_kvp.json.txt new file mode 100644 index 0000000000..e9702c8ccf --- /dev/null +++ b/msautotest/api/expected/ogcapi_sortables_error_unexpected_kvp.json.txt @@ -0,0 +1,4 @@ +Content-Type: application/json +Status: 400 + +{"code":"InvalidParameterValue","description":"Unknown query parameter: unexpected"} diff --git a/msautotest/api/expected/ogcapi_sortables_none.json.txt b/msautotest/api/expected/ogcapi_sortables_none.json.txt new file mode 100644 index 0000000000..93c3016dde --- /dev/null +++ b/msautotest/api/expected/ogcapi_sortables_none.json.txt @@ -0,0 +1,3 @@ +Content-Type: application/schema+json + +{"$id":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties_no_queryables_and_sortables/sortables","$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":false,"description":"This is the standard Minnesota State County Boundary dataset.","properties":{},"title":"State of Minnesota County Boundaries","type":"object"} diff --git a/msautotest/api/expected/ogcapi_sorted.json.txt b/msautotest/api/expected/ogcapi_sorted.json.txt new file mode 100644 index 0000000000..cddec8f350 --- /dev/null +++ b/msautotest/api/expected/ogcapi_sorted.json.txt @@ -0,0 +1,9 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +Link: ; rel="next"; title="next page"; type="application/geo+json" +OGC-NumberMatched: 117 +OGC-NumberReturned: 9 + +{"features":[{"geometry":{"coordinates":[[[-95.3231,48.999],[-95.3109,48.999],[-95.2889,48.9989],[-95.2852,48.9989],[-95.2669,48.9989],[-95.245,48.9989],[-95.2232,48.9989],[-95.2014,48.9989],[-95.1792,48.9989],[-95.1574,48.9989],[-95.1531,48.9989],[-95.1531,49.0031],[-95.1532,49.0179],[-95.1532,49.0325],[-95.1532,49.047],[-95.1532,49.0619],[-95.1532,49.0765],[-95.1532,49.0911],[-95.1532,49.1057],[-95.1532,49.1205],[-95.1532,49.1354],[-95.1532,49.1499],[-95.1532,49.1642],[-95.1532,49.1788],[-95.1532,49.1807],[-95.1532,49.1931],[-95.1532,49.1966],[-95.1532,49.2077],[-95.1533,49.2131],[-95.1533,49.2219],[-95.1533,49.2308],[-95.1533,49.2365],[-95.1533,49.2472],[-95.1533,49.2512],[-95.1533,49.2655],[-95.1533,49.2697],[-95.1533,49.2802],[-95.1533,49.2882],[-95.1533,49.2945],[-95.1533,49.3072],[-95.1533,49.309],[-95.1533,49.3234],[-95.1533,49.3237],[-95.1533,49.3381],[-95.1533,49.3476],[-95.1533,49.3525],[-95.1533,49.3636],[-95.1533,49.367],[-95.1533,49.3705],[-95.1533,49.3776],[-95.1533,49.3813],[-95.1533,49.3845],[-95.1503,49.383],[-95.1499,49.3813],[-95.1498,49.3807],[-95.1467,49.3802],[-95.145,49.3784],[-95.1418,49.3784],[-95.1397,49.3762],[-95.1367,49.3751],[-95.1324,49.3736],[-95.1287,49.3705],[-95.1171,49.367],[-95.1159,49.3666],[-95.1145,49.3666],[-95.1098,49.3664],[-95.1031,49.3652],[-95.1031,49.3636],[-95.0926,49.3617],[-95.0897,49.3612],[-95.0707,49.3564],[-95.0582,49.3533],[-95.0495,49.3532],[-95.0479,49.3533],[-95.0262,49.3554],[-95.0141,49.3565],[-95.0047,49.3612],[-94.993,49.367],[-94.9889,49.369],[-94.9818,49.3684],[-94.9742,49.3678],[-94.9597,49.3699],[-94.9573,49.3702],[-94.952,49.3688],[-94.948,49.367],[-94.9376,49.3625],[-94.9152,49.3529],[-94.9143,49.3524],[-94.909,49.3502],[-94.9065,49.3484],[-94.8933,49.3414],[-94.8865,49.3378],[-94.8782,49.3334],[-94.8712,49.3308],[-94.854,49.3244],[-94.8492,49.3244],[-94.8363,49.3243],[-94.8311,49.3236],[-94.8271,49.323],[-94.8162,49.3214],[-94.8243,49.309],[-94.8243,49.3088],[-94.8255,49.2944],[-94.8255,49.2943],[-94.8204,49.28],[-94.8152,49.2653],[-94.8103,49.2515],[-94.8059,49.2388],[-94.8051,49.2367],[-94.8001,49.2224],[-94.7973,49.2144],[-94.7975,49.2079],[-94.7979,49.1979],[-94.7965,49.1936],[-94.7918,49.1792],[-94.7871,49.1646],[-94.7833,49.153],[-94.7823,49.15],[-94.7776,49.1357],[-94.7727,49.1206],[-94.7727,49.1206],[-94.7611,49.1096],[-94.7571,49.1058],[-94.7496,49.0988],[-94.7474,49.0918],[-94.7429,49.0773],[-94.7394,49.0657],[-94.7385,49.063],[-94.7344,49.0497],[-94.7299,49.0351],[-94.7254,49.0205],[-94.7207,49.0052],[-94.7184,48.9979],[-94.7162,48.9907],[-94.7117,48.9761],[-94.7072,48.9615],[-94.7027,48.9468],[-94.6982,48.9322],[-94.6968,48.9276],[-94.6844,48.8875],[-94.6834,48.8842],[-94.6842,48.8724],[-94.6855,48.8719],[-94.6923,48.8691],[-94.6902,48.8636],[-94.6914,48.8591],[-94.693,48.8535],[-94.6881,48.8447],[-94.6855,48.8401],[-94.6963,48.836],[-94.6975,48.8355],[-94.702,48.8319],[-94.7025,48.8302],[-94.7042,48.8243],[-94.6991,48.8159],[-94.6962,48.8111],[-94.6951,48.8092],[-94.6958,48.8012],[-94.6959,48.7997],[-94.6944,48.7895],[-94.6934,48.7864],[-94.6909,48.7781],[-94.687,48.7752],[-94.6776,48.772],[-94.6768,48.7717],[-94.6746,48.7705],[-94.6671,48.7662],[-94.6603,48.7605],[-94.6557,48.7581],[-94.6525,48.7565],[-94.652,48.7562],[-94.6453,48.7491],[-94.6453,48.7441],[-94.6443,48.7434],[-94.6414,48.7413],[-94.631,48.7392],[-94.6301,48.739],[-94.6191,48.7373],[-94.6106,48.7318],[-94.6084,48.731],[-94.6028,48.7289],[-94.6011,48.7283],[-94.5962,48.7248],[-94.5913,48.7197],[-94.5876,48.7176],[-94.5867,48.7175],[-94.5685,48.7156],[-94.5622,48.7159],[-94.5558,48.7163],[-94.549,48.7148],[-94.5487,48.7146],[-94.5457,48.7124],[-94.5396,48.7036],[-94.539,48.7028],[-94.5329,48.7013],[-94.5247,48.7016],[-94.5178,48.7008],[-94.5173,48.7008],[-94.5093,48.7006],[-94.5066,48.6999],[-94.4996,48.698],[-94.4958,48.698],[-94.4863,48.698],[-94.4739,48.6969],[-94.4706,48.6966],[-94.4631,48.6953],[-94.4568,48.6933],[-94.4523,48.6925],[-94.4517,48.6925],[-94.4465,48.693],[-94.4388,48.6949],[-94.4319,48.6998],[-94.4299,48.7012],[-94.4299,48.6998],[-94.43,48.6852],[-94.4301,48.6708],[-94.43,48.6564],[-94.4297,48.642],[-94.4294,48.6276],[-94.4292,48.6133],[-94.4289,48.5988],[-94.4289,48.5844],[-94.4291,48.5698],[-94.4295,48.5554],[-94.43,48.5409],[-94.4303,48.5264],[-94.4303,48.512],[-94.4299,48.4977],[-94.4296,48.4832],[-94.4296,48.4688],[-94.4293,48.4543],[-94.4292,48.4399],[-94.4293,48.4254],[-94.4294,48.411],[-94.4293,48.3964],[-94.4289,48.3821],[-94.4288,48.3675],[-94.4471,48.3675],[-94.4505,48.3675],[-94.4688,48.3675],[-94.4722,48.3674],[-94.4906,48.3674],[-94.4924,48.3674],[-94.4941,48.3674],[-94.5118,48.3675],[-94.5157,48.3674],[-94.5335,48.3674],[-94.5378,48.3674],[-94.5536,48.3674],[-94.5593,48.3674],[-94.5754,48.3674],[-94.5812,48.3674],[-94.5971,48.3675],[-94.6029,48.3674],[-94.6188,48.3673],[-94.6245,48.3673],[-94.6405,48.3673],[-94.6465,48.3673],[-94.6505,48.3673],[-94.6622,48.3673],[-94.6679,48.3673],[-94.6694,48.3672],[-94.683,48.3671],[-94.6898,48.3671],[-94.7099,48.3669],[-94.7117,48.3668],[-94.7315,48.3669],[-94.7329,48.3669],[-94.7533,48.3669],[-94.7549,48.3669],[-94.7748,48.3669],[-94.7765,48.3669],[-94.7967,48.3669],[-94.7983,48.3669],[-94.8183,48.3669],[-94.8199,48.3669],[-94.8399,48.3669],[-94.8416,48.3669],[-94.8616,48.3667],[-94.8632,48.3667],[-94.8833,48.3667],[-94.8849,48.3666],[-94.9049,48.3666],[-94.9065,48.3666],[-94.9264,48.3667],[-94.9283,48.3667],[-94.9469,48.3666],[-94.95,48.3666],[-94.9684,48.3667],[-94.9716,48.3667],[-94.9901,48.3667],[-94.9932,48.3667],[-95.0119,48.3665],[-95.0153,48.3665],[-95.0337,48.3665],[-95.0369,48.3665],[-95.0555,48.3665],[-95.0586,48.3665],[-95.0773,48.3664],[-95.0801,48.3664],[-95.099,48.3663],[-95.1008,48.3663],[-95.1018,48.3663],[-95.1207,48.3663],[-95.1236,48.3663],[-95.1315,48.3662],[-95.1424,48.3662],[-95.1454,48.3662],[-95.164,48.3661],[-95.1669,48.3661],[-95.1861,48.3661],[-95.1887,48.3661],[-95.1983,48.3661],[-95.2066,48.3661],[-95.2106,48.3661],[-95.211,48.3797],[-95.211,48.3808],[-95.2111,48.3941],[-95.2111,48.3952],[-95.2112,48.4087],[-95.2112,48.4096],[-95.2113,48.4232],[-95.2113,48.4242],[-95.2113,48.4255],[-95.2113,48.4376],[-95.2113,48.4387],[-95.2113,48.4522],[-95.2112,48.4529],[-95.211,48.4666],[-95.211,48.4673],[-95.2111,48.4816],[-95.2112,48.4962],[-95.2111,48.5101],[-95.2111,48.5109],[-95.2115,48.5244],[-95.2115,48.5252],[-95.2119,48.54],[-95.2324,48.5399],[-95.2339,48.5399],[-95.2537,48.5398],[-95.2554,48.5398],[-95.2756,48.54],[-95.2773,48.54],[-95.2975,48.5401],[-95.2992,48.5402],[-95.3194,48.54],[-95.321,48.54],[-95.3412,48.5402],[-95.3425,48.5402],[-95.3424,48.5548],[-95.3423,48.5691],[-95.3423,48.5836],[-95.3426,48.5979],[-95.3424,48.6127],[-95.3426,48.6271],[-95.3425,48.6415],[-95.3424,48.6561],[-95.3423,48.6705],[-95.3424,48.6849],[-95.3425,48.6995],[-95.3425,48.7131],[-95.3302,48.713],[-95.3205,48.713],[-95.3084,48.713],[-95.3051,48.713],[-95.299,48.713],[-95.2866,48.713],[-95.2767,48.713],[-95.2656,48.713],[-95.2645,48.713],[-95.255,48.713],[-95.2427,48.713],[-95.2331,48.713],[-95.2206,48.713],[-95.2112,48.713],[-95.1991,48.713],[-95.1917,48.713],[-95.1773,48.713],[-95.1697,48.7129],[-95.1554,48.7129],[-95.1477,48.7129],[-95.1333,48.713],[-95.1297,48.713],[-95.1259,48.7129],[-95.1119,48.7129],[-95.1104,48.7129],[-95.1046,48.7129],[-95.0898,48.713],[-95.0899,48.7277],[-95.0901,48.7421],[-95.0901,48.7566],[-95.0903,48.7711],[-95.0903,48.7855],[-95.0903,48.8],[-95.0909,48.8147],[-95.0908,48.8291],[-95.0907,48.8436],[-95.0908,48.858],[-95.0908,48.8724],[-95.0911,48.8869],[-95.0912,48.9014],[-95.0914,48.916],[-95.0914,48.9208],[-95.0919,48.9207],[-95.0927,48.9204],[-95.0944,48.9193],[-95.0946,48.9191],[-95.0961,48.9181],[-95.097,48.9176],[-95.0971,48.9172],[-95.0975,48.9164],[-95.098,48.916],[-95.0981,48.9159],[-95.1008,48.9142],[-95.102,48.9132],[-95.1032,48.9127],[-95.1042,48.9121],[-95.1056,48.9113],[-95.108,48.9099],[-95.1096,48.9089],[-95.1107,48.9082],[-95.1126,48.9073],[-95.113,48.9072],[-95.1132,48.9071],[-95.1137,48.9069],[-95.1141,48.9064],[-95.114,48.9061],[-95.1144,48.9052],[-95.1151,48.9046],[-95.1163,48.9037],[-95.1182,48.9029],[-95.1204,48.9019],[-95.1205,48.9017],[-95.121,48.9016],[-95.1214,48.9013],[-95.1228,48.9006],[-95.1233,48.9004],[-95.1239,48.9001],[-95.1252,48.8998],[-95.1312,48.8975],[-95.1322,48.8973],[-95.1337,48.8969],[-95.1343,48.8963],[-95.1348,48.8963],[-95.1351,48.8963],[-95.1355,48.8959],[-95.1381,48.8949],[-95.1404,48.8943],[-95.1436,48.8937],[-95.1438,48.8934],[-95.1459,48.8929],[-95.1469,48.8927],[-95.1483,48.8923],[-95.1508,48.8922],[-95.1528,48.8921],[-95.1555,48.892],[-95.1564,48.8919],[-95.1579,48.8919],[-95.1602,48.892],[-95.1618,48.892],[-95.1641,48.8917],[-95.1648,48.8913],[-95.1674,48.8907],[-95.1701,48.8902],[-95.173,48.8897],[-95.1764,48.8893],[-95.1791,48.889],[-95.1797,48.889],[-95.1819,48.8888],[-95.1851,48.8882],[-95.1863,48.8877],[-95.1877,48.8874],[-95.1889,48.8873],[-95.1901,48.887],[-95.1913,48.8868],[-95.1919,48.8866],[-95.1924,48.8865],[-95.1956,48.8862],[-95.1986,48.8855],[-95.2005,48.8856],[-95.2009,48.8855],[-95.2024,48.8852],[-95.2059,48.8848],[-95.2085,48.8846],[-95.2112,48.8848],[-95.2115,48.8847],[-95.2117,48.8847],[-95.2122,48.8842],[-95.2144,48.8843],[-95.2151,48.884],[-95.2159,48.8839],[-95.217,48.8835],[-95.2188,48.8835],[-95.2193,48.8832],[-95.22,48.8831],[-95.2207,48.8831],[-95.2208,48.8831],[-95.2212,48.883],[-95.2252,48.8819],[-95.2265,48.8816],[-95.2287,48.8815],[-95.231,48.8814],[-95.2335,48.8814],[-95.2356,48.8815],[-95.2381,48.8817],[-95.2391,48.8819],[-95.2407,48.8821],[-95.2423,48.8821],[-95.2429,48.8822],[-95.2429,48.8822],[-95.2439,48.8823],[-95.2458,48.8829],[-95.2472,48.8835],[-95.248,48.8836],[-95.2485,48.8832],[-95.2496,48.8834],[-95.2502,48.8835],[-95.2507,48.8836],[-95.2517,48.8839],[-95.2548,48.8845],[-95.256,48.885],[-95.257,48.8858],[-95.2585,48.8867],[-95.2585,48.8867],[-95.2627,48.8877],[-95.2635,48.888],[-95.2639,48.8883],[-95.2646,48.8885],[-95.265,48.8886],[-95.2654,48.8888],[-95.2666,48.8894],[-95.2674,48.89],[-95.2677,48.8903],[-95.268,48.8905],[-95.2713,48.8915],[-95.2724,48.8921],[-95.2745,48.8931],[-95.2751,48.8938],[-95.2753,48.8943],[-95.2748,48.8951],[-95.2749,48.8956],[-95.2755,48.8959],[-95.2759,48.8962],[-95.2763,48.8963],[-95.2765,48.8962],[-95.277,48.8958],[-95.2773,48.8957],[-95.2782,48.8956],[-95.279,48.8957],[-95.2796,48.8962],[-95.2803,48.8965],[-95.2813,48.8967],[-95.2839,48.8975],[-95.2853,48.8977],[-95.2861,48.8976],[-95.2865,48.8975],[-95.287,48.8976],[-95.2872,48.8977],[-95.2879,48.8979],[-95.2882,48.8981],[-95.289,48.8994],[-95.2896,48.9],[-95.2901,48.9003],[-95.2911,48.9006],[-95.2911,48.9008],[-95.2906,48.9011],[-95.2907,48.9014],[-95.2908,48.9016],[-95.2909,48.9017],[-95.2914,48.9019],[-95.2927,48.9019],[-95.2935,48.902],[-95.2937,48.9023],[-95.2941,48.9027],[-95.2949,48.9028],[-95.2967,48.9027],[-95.2976,48.9026],[-95.298,48.9027],[-95.2983,48.9028],[-95.2993,48.9035],[-95.3005,48.904],[-95.3002,48.9045],[-95.3001,48.9046],[-95.3001,48.9047],[-95.3,48.9047],[-95.3,48.9047],[-95.2999,48.9048],[-95.2999,48.9048],[-95.2999,48.9048],[-95.2997,48.905],[-95.2996,48.9051],[-95.2994,48.9053],[-95.2992,48.9055],[-95.2991,48.9057],[-95.2989,48.906],[-95.2988,48.906],[-95.2986,48.9063],[-95.2985,48.9064],[-95.2985,48.9065],[-95.2983,48.9068],[-95.2982,48.9068],[-95.2981,48.907],[-95.298,48.9071],[-95.298,48.9071],[-95.298,48.9071],[-95.2979,48.9071],[-95.2979,48.9072],[-95.2979,48.9072],[-95.2978,48.9072],[-95.2978,48.9072],[-95.2978,48.9073],[-95.2977,48.9073],[-95.2976,48.9074],[-95.2973,48.9077],[-95.2973,48.908],[-95.2973,48.9081],[-95.2978,48.9083],[-95.2999,48.9086],[-95.3017,48.9093],[-95.3027,48.91],[-95.3038,48.9114],[-95.3043,48.9119],[-95.3059,48.9127],[-95.3061,48.9128],[-95.3064,48.9129],[-95.3074,48.9135],[-95.3078,48.9141],[-95.3085,48.9146],[-95.3092,48.9149],[-95.3093,48.9149],[-95.3102,48.9155],[-95.3109,48.9163],[-95.3115,48.9172],[-95.3119,48.9178],[-95.3126,48.919],[-95.3132,48.9198],[-95.3141,48.921],[-95.315,48.9222],[-95.3168,48.9245],[-95.3195,48.9285],[-95.3208,48.9305],[-95.3209,48.9307],[-95.3222,48.9327],[-95.3228,48.9344],[-95.3223,48.9355],[-95.3225,48.9358],[-95.3229,48.9373],[-95.3231,48.9389],[-95.3228,48.9403],[-95.3225,48.9409],[-95.3219,48.9412],[-95.3189,48.9419],[-95.3181,48.9421],[-95.3168,48.9431],[-95.3154,48.9448],[-95.3148,48.9452],[-95.3141,48.9457],[-95.3131,48.946],[-95.3114,48.9461],[-95.3102,48.9463],[-95.3095,48.9463],[-95.3088,48.9464],[-95.3086,48.9465],[-95.3086,48.9469],[-95.3085,48.947],[-95.3078,48.9466],[-95.3074,48.9465],[-95.3071,48.9466],[-95.3071,48.9469],[-95.3079,48.9474],[-95.3092,48.9477],[-95.3096,48.9478],[-95.3103,48.948],[-95.3104,48.9484],[-95.3103,48.9485],[-95.31,48.9485],[-95.3099,48.9484],[-95.3096,48.9482],[-95.3094,48.9481],[-95.3081,48.948],[-95.3071,48.9477],[-95.3062,48.9472],[-95.3062,48.9472],[-95.3061,48.9469],[-95.3062,48.9463],[-95.3063,48.9462],[-95.3069,48.9456],[-95.3069,48.9455],[-95.3068,48.9454],[-95.3061,48.9454],[-95.3053,48.9459],[-95.305,48.9462],[-95.3046,48.947],[-95.3046,48.9482],[-95.3052,48.9495],[-95.3061,48.9502],[-95.3079,48.9509],[-95.3089,48.9511],[-95.3097,48.951],[-95.3104,48.951],[-95.3108,48.9512],[-95.3115,48.952],[-95.312,48.9524],[-95.3126,48.9524],[-95.3129,48.9523],[-95.3129,48.9521],[-95.3119,48.9507],[-95.3119,48.9502],[-95.3123,48.9502],[-95.3125,48.9503],[-95.3131,48.9503],[-95.3141,48.9508],[-95.3151,48.951],[-95.3154,48.9513],[-95.3177,48.9525],[-95.3181,48.9531],[-95.3182,48.9535],[-95.3177,48.9545],[-95.3175,48.9552],[-95.3179,48.9559],[-95.3188,48.9562],[-95.3191,48.9569],[-95.3202,48.9581],[-95.3206,48.959],[-95.3206,48.9595],[-95.3206,48.9598],[-95.3202,48.9606],[-95.3193,48.9622],[-95.3193,48.964],[-95.3198,48.9643],[-95.3201,48.9648],[-95.3207,48.9669],[-95.3212,48.9672],[-95.3227,48.9685],[-95.3232,48.9692],[-95.3241,48.9703],[-95.3247,48.972],[-95.3248,48.9728],[-95.3249,48.9738],[-95.325,48.9743],[-95.3253,48.976],[-95.3257,48.9784],[-95.3255,48.9789],[-95.3256,48.98],[-95.3257,48.9814],[-95.3253,48.9832],[-95.3245,48.985],[-95.3242,48.9859],[-95.3227,48.9884],[-95.3224,48.9889],[-95.3206,48.9921],[-95.3204,48.9924],[-95.3191,48.9941],[-95.3181,48.995],[-95.3178,48.9958],[-95.3178,48.9961],[-95.3179,48.9961],[-95.3182,48.996],[-95.3187,48.9956],[-95.3191,48.9953],[-95.3197,48.9954],[-95.3201,48.9956],[-95.3206,48.9961],[-95.3204,48.9964],[-95.3202,48.9973],[-95.3204,48.9976],[-95.3224,48.9984],[-95.3231,48.999]]],"type":"Polygon"},"id":"39","properties":{"Area":4608320923.49768,"CTYONLY_":2,"Code":"LOTW","LASTMOD":"1976-07-04T12:00:00Z","Name":"Lake of the Woods","Perimiter":388250.14572},"type":"Feature"},{"geometry":{"coordinates":[[[-96.4054,49.0001],[-96.4054,48.9947],[-96.4054,48.994],[-96.4054,48.9803],[-96.4054,48.9793],[-96.4053,48.9705],[-96.4053,48.9658],[-96.4053,48.9648],[-96.4053,48.9515],[-96.4053,48.9504],[-96.4053,48.9371],[-96.4053,48.936],[-96.4054,48.9225],[-96.4054,48.9214],[-96.4053,48.9137],[-96.4053,48.9081],[-96.4053,48.9068],[-96.405,48.8926],[-96.405,48.878],[-96.4047,48.8635],[-96.4045,48.8491],[-96.4043,48.8343],[-96.4042,48.8198],[-96.4042,48.8048],[-96.4042,48.7903],[-96.4045,48.7758],[-96.4047,48.7607],[-96.4048,48.7465],[-96.4048,48.7318],[-96.4049,48.7172],[-96.388,48.7172],[-96.3873,48.7172],[-96.3866,48.703],[-96.3874,48.6887],[-96.3871,48.6741],[-96.3877,48.6599],[-96.3879,48.6454],[-96.388,48.6313],[-96.389,48.6165],[-96.3891,48.6024],[-96.3884,48.5877],[-96.3882,48.5733],[-96.3879,48.5588],[-96.3882,48.5442],[-96.4101,48.544],[-96.4318,48.5438],[-96.4535,48.5436],[-96.4754,48.5435],[-96.4973,48.5434],[-96.518,48.5434],[-96.54,48.5434],[-96.5621,48.5436],[-96.5839,48.5437],[-96.6058,48.5437],[-96.6278,48.5437],[-96.6493,48.5437],[-96.6713,48.5436],[-96.6931,48.5437],[-96.7151,48.5437],[-96.7368,48.5437],[-96.7585,48.5436],[-96.7803,48.5435],[-96.8023,48.5436],[-96.824,48.5436],[-96.8459,48.5434],[-96.8678,48.5433],[-96.8896,48.5433],[-96.9115,48.5432],[-96.9138,48.5433],[-96.9331,48.5435],[-96.9551,48.5437],[-96.9768,48.544],[-96.9985,48.5441],[-97.0194,48.5441],[-97.0416,48.5442],[-97.0635,48.5441],[-97.0852,48.5441],[-97.107,48.544],[-97.1287,48.5439],[-97.1509,48.5439],[-97.1631,48.544],[-97.1637,48.5445],[-97.1659,48.5483],[-97.1662,48.5509],[-97.1661,48.5527],[-97.1654,48.5536],[-97.1645,48.554],[-97.1628,48.5543],[-97.1613,48.5539],[-97.1592,48.5528],[-97.1577,48.5518],[-97.1557,48.5512],[-97.1538,48.5513],[-97.1513,48.5515],[-97.1507,48.5515],[-97.1493,48.5516],[-97.1474,48.5516],[-97.1444,48.5514],[-97.1407,48.5515],[-97.1387,48.5522],[-97.1379,48.553],[-97.1379,48.5542],[-97.1391,48.5554],[-97.141,48.5566],[-97.1426,48.5571],[-97.1464,48.5573],[-97.1505,48.5574],[-97.1515,48.5574],[-97.1551,48.5574],[-97.1578,48.5573],[-97.1606,48.5571],[-97.1631,48.5571],[-97.1646,48.5572],[-97.167,48.5575],[-97.1697,48.5584],[-97.1721,48.5591],[-97.1727,48.5593],[-97.174,48.5599],[-97.1749,48.5606],[-97.1753,48.5614],[-97.1754,48.5623],[-97.1749,48.5631],[-97.1744,48.5639],[-97.1723,48.5648],[-97.1721,48.5648],[-97.1706,48.5652],[-97.1687,48.5655],[-97.167,48.5658],[-97.1651,48.5659],[-97.1613,48.5661],[-97.1541,48.5669],[-97.153,48.5671],[-97.1516,48.5677],[-97.1503,48.5688],[-97.1496,48.5695],[-97.1487,48.5707],[-97.1477,48.5727],[-97.1477,48.5728],[-97.1476,48.5731],[-97.1483,48.5763],[-97.15,48.5775],[-97.1501,48.5775],[-97.1548,48.5779],[-97.1592,48.5785],[-97.1605,48.58],[-97.16,48.5816],[-97.1578,48.5826],[-97.1562,48.5828],[-97.1541,48.5826],[-97.1524,48.5823],[-97.15,48.5815],[-97.1494,48.5813],[-97.1484,48.5811],[-97.1449,48.5815],[-97.1436,48.5824],[-97.1431,48.5834],[-97.1429,48.5838],[-97.142,48.5876],[-97.1418,48.5886],[-97.1415,48.5909],[-97.1422,48.5926],[-97.1433,48.5936],[-97.1451,48.594],[-97.1471,48.594],[-97.1497,48.5937],[-97.1525,48.594],[-97.1536,48.5949],[-97.1535,48.5957],[-97.1527,48.5962],[-97.1524,48.5969],[-97.1516,48.598],[-97.1498,48.5981],[-97.1497,48.5981],[-97.1463,48.5977],[-97.1443,48.5981],[-97.143,48.5987],[-97.1416,48.6002],[-97.1403,48.6021],[-97.14,48.6025],[-97.138,48.6044],[-97.1359,48.6054],[-97.1345,48.6065],[-97.1341,48.6075],[-97.1349,48.6082],[-97.1358,48.6086],[-97.137,48.6088],[-97.1396,48.6086],[-97.1443,48.6078],[-97.1474,48.6081],[-97.1494,48.6089],[-97.1495,48.609],[-97.1505,48.6115],[-97.1501,48.6124],[-97.1493,48.6129],[-97.1478,48.6138],[-97.145,48.6146],[-97.1408,48.6149],[-97.137,48.6144],[-97.134,48.6136],[-97.1319,48.6133],[-97.1309,48.6137],[-97.1289,48.614],[-97.1286,48.6153],[-97.1293,48.6168],[-97.1295,48.617],[-97.1311,48.6184],[-97.1342,48.6199],[-97.1353,48.6212],[-97.1346,48.6224],[-97.133,48.6228],[-97.131,48.6227],[-97.1291,48.6222],[-97.1277,48.6212],[-97.1274,48.621],[-97.1259,48.6195],[-97.1253,48.619],[-97.1243,48.6183],[-97.1231,48.6178],[-97.1216,48.6176],[-97.12,48.6178],[-97.1193,48.6182],[-97.1186,48.6191],[-97.1183,48.6198],[-97.1186,48.6209],[-97.1198,48.6221],[-97.1209,48.6232],[-97.1212,48.6233],[-97.122,48.624],[-97.1228,48.6245],[-97.1236,48.625],[-97.1241,48.6254],[-97.1245,48.6257],[-97.1249,48.6259],[-97.1253,48.6261],[-97.126,48.6264],[-97.1266,48.6266],[-97.1272,48.627],[-97.1279,48.6273],[-97.1288,48.6278],[-97.1296,48.6282],[-97.1302,48.6288],[-97.1305,48.6292],[-97.1307,48.6297],[-97.131,48.6303],[-97.131,48.6304],[-97.131,48.6308],[-97.131,48.6315],[-97.1309,48.6317],[-97.1307,48.6321],[-97.1304,48.6325],[-97.1301,48.6326],[-97.1297,48.6328],[-97.1293,48.6329],[-97.129,48.633],[-97.1281,48.6332],[-97.128,48.6333],[-97.1275,48.6333],[-97.1253,48.6334],[-97.1235,48.6333],[-97.1216,48.6327],[-97.1181,48.6308],[-97.1176,48.6307],[-97.115,48.6299],[-97.1133,48.63],[-97.1115,48.6303],[-97.1107,48.6308],[-97.1104,48.6309],[-97.1095,48.6315],[-97.1084,48.6327],[-97.1082,48.6344],[-97.1086,48.6363],[-97.1096,48.6389],[-97.1109,48.6407],[-97.1119,48.6416],[-97.1144,48.6433],[-97.115,48.6438],[-97.115,48.6446],[-97.1149,48.6452],[-97.1123,48.6457],[-97.1112,48.6459],[-97.1093,48.6465],[-97.1078,48.6478],[-97.1069,48.6491],[-97.1066,48.6501],[-97.1061,48.6519],[-97.1059,48.6527],[-97.1045,48.6545],[-97.1017,48.6563],[-97.0987,48.6593],[-97.0986,48.6604],[-97.0985,48.6613],[-97.0992,48.6625],[-97.1019,48.6636],[-97.106,48.663],[-97.1062,48.663],[-97.1082,48.6634],[-97.1087,48.6645],[-97.1061,48.6654],[-97.1057,48.6655],[-97.102,48.6667],[-97.1,48.668],[-97.0998,48.6714],[-97.1002,48.675],[-97.1003,48.6757],[-97.1008,48.6787],[-97.1011,48.6808],[-97.1003,48.6828],[-97.0985,48.683],[-97.0946,48.6822],[-97.0926,48.6821],[-97.0904,48.6828],[-97.0898,48.6841],[-97.0899,48.6852],[-97.091,48.6861],[-97.093,48.687],[-97.0951,48.6876],[-97.099,48.6884],[-97.1024,48.6893],[-97.103,48.6894],[-97.1059,48.6903],[-97.1064,48.6905],[-97.1086,48.6915],[-97.111,48.6939],[-97.113,48.6964],[-97.1148,48.6981],[-97.1182,48.7005],[-97.1198,48.7018],[-97.1201,48.7039],[-97.1194,48.7041],[-97.1182,48.7046],[-97.1143,48.7052],[-97.1117,48.7056],[-97.11,48.7063],[-97.1098,48.7083],[-97.1113,48.7094],[-97.1134,48.7101],[-97.1157,48.7105],[-97.1174,48.7111],[-97.119,48.7119],[-97.1212,48.7136],[-97.1223,48.716],[-97.1229,48.7168],[-97.1231,48.7172],[-97.1243,48.7192],[-97.1253,48.7201],[-97.1253,48.7203],[-97.126,48.7207],[-97.1263,48.7212],[-97.1272,48.7215],[-97.128,48.722],[-97.1282,48.7221],[-97.1288,48.7225],[-97.1297,48.7229],[-97.131,48.7233],[-97.1321,48.7238],[-97.1331,48.7242],[-97.1345,48.7248],[-97.136,48.7257],[-97.1369,48.7263],[-97.1375,48.727],[-97.1376,48.7274],[-97.1376,48.7278],[-97.1373,48.7283],[-97.137,48.7284],[-97.1365,48.7285],[-97.136,48.7287],[-97.1352,48.7287],[-97.1341,48.7289],[-97.1333,48.7291],[-97.1328,48.7292],[-97.132,48.7294],[-97.1312,48.7295],[-97.1308,48.7296],[-97.1299,48.7299],[-97.1294,48.7304],[-97.1288,48.7308],[-97.1286,48.7312],[-97.1286,48.7315],[-97.1286,48.7316],[-97.1286,48.7318],[-97.1285,48.7322],[-97.1286,48.7326],[-97.1286,48.7328],[-97.1287,48.7331],[-97.129,48.7335],[-97.1295,48.7339],[-97.1298,48.7341],[-97.1316,48.7347],[-97.1322,48.7348],[-97.1334,48.7347],[-97.1351,48.7345],[-97.1369,48.7345],[-97.1383,48.7345],[-97.1396,48.7347],[-97.1402,48.7349],[-97.1412,48.7354],[-97.1419,48.7359],[-97.1422,48.7367],[-97.1423,48.7372],[-97.1421,48.7381],[-97.1414,48.7385],[-97.1408,48.7387],[-97.1404,48.7389],[-97.1399,48.7393],[-97.1392,48.7397],[-97.1381,48.7408],[-97.1372,48.742],[-97.1366,48.7435],[-97.1365,48.745],[-97.1365,48.7459],[-97.1366,48.7466],[-97.1369,48.748],[-97.1375,48.7492],[-97.1379,48.75],[-97.1385,48.7504],[-97.1391,48.7507],[-97.1396,48.7508],[-97.1401,48.7509],[-97.141,48.751],[-97.142,48.751],[-97.143,48.7509],[-97.1444,48.7507],[-97.1457,48.7506],[-97.1466,48.7505],[-97.1476,48.7505],[-97.1491,48.7506],[-97.1497,48.7508],[-97.1503,48.7509],[-97.1515,48.7515],[-97.1521,48.752],[-97.153,48.7529],[-97.1539,48.7542],[-97.1545,48.7553],[-97.1547,48.7558],[-97.1548,48.7562],[-97.1548,48.7569],[-97.1548,48.7576],[-97.1546,48.758],[-97.1542,48.7587],[-97.1535,48.7593],[-97.1528,48.7598],[-97.1519,48.7601],[-97.1508,48.7605],[-97.1503,48.7606],[-97.1501,48.7607],[-97.1475,48.7616],[-97.1473,48.7617],[-97.1469,48.762],[-97.1462,48.7626],[-97.1461,48.7628],[-97.1459,48.7633],[-97.1456,48.7643],[-97.1456,48.765],[-97.146,48.7658],[-97.1476,48.7673],[-97.1487,48.7681],[-97.15,48.7692],[-97.1501,48.7693],[-97.1506,48.77],[-97.1512,48.7712],[-97.1519,48.7721],[-97.1525,48.7727],[-97.1529,48.7728],[-97.1559,48.7731],[-97.1567,48.7732],[-97.1578,48.7735],[-97.1582,48.7737],[-97.1587,48.7742],[-97.1589,48.7746],[-97.159,48.7751],[-97.159,48.7751],[-97.159,48.7754],[-97.1589,48.776],[-97.1584,48.7766],[-97.1579,48.7769],[-97.1573,48.7772],[-97.1557,48.7776],[-97.1544,48.7778],[-97.1534,48.778],[-97.1522,48.7783],[-97.1509,48.7787],[-97.1501,48.7789],[-97.1497,48.779],[-97.1483,48.7797],[-97.1477,48.7801],[-97.1473,48.7807],[-97.1472,48.7811],[-97.1473,48.7816],[-97.1478,48.7821],[-97.1486,48.7824],[-97.1495,48.7826],[-97.1501,48.7826],[-97.1503,48.7826],[-97.1513,48.7825],[-97.1533,48.7824],[-97.1547,48.7824],[-97.1559,48.7825],[-97.1571,48.7827],[-97.1583,48.783],[-97.1591,48.7834],[-97.1595,48.7838],[-97.1597,48.7843],[-97.1598,48.7848],[-97.1596,48.7853],[-97.1593,48.786],[-97.1591,48.7863],[-97.1586,48.7869],[-97.1577,48.7877],[-97.1574,48.7882],[-97.1573,48.7884],[-97.1572,48.7887],[-97.1571,48.7894],[-97.157,48.7895],[-97.157,48.7901],[-97.1572,48.7906],[-97.1575,48.7909],[-97.1581,48.7912],[-97.1586,48.7913],[-97.1592,48.7915],[-97.1595,48.7915],[-97.1611,48.7915],[-97.1618,48.7914],[-97.1645,48.7911],[-97.1648,48.7911],[-97.1657,48.7911],[-97.1664,48.7912],[-97.1672,48.7913],[-97.1714,48.7921],[-97.1718,48.7923],[-97.1721,48.7924],[-97.1731,48.7929],[-97.1737,48.7933],[-97.174,48.7937],[-97.1741,48.7942],[-97.1742,48.7947],[-97.1742,48.7951],[-97.1739,48.7954],[-97.1734,48.7958],[-97.1726,48.7963],[-97.1717,48.7966],[-97.1716,48.7966],[-97.171,48.7967],[-97.1701,48.7967],[-97.1688,48.7966],[-97.1673,48.7964],[-97.1665,48.7962],[-97.1654,48.7962],[-97.1648,48.7962],[-97.1638,48.7963],[-97.1631,48.7966],[-97.1625,48.7969],[-97.162,48.7974],[-97.1617,48.7979],[-97.1617,48.7984],[-97.1619,48.7988],[-97.1621,48.7994],[-97.1626,48.8001],[-97.1633,48.8007],[-97.1642,48.8011],[-97.1652,48.8014],[-97.166,48.8015],[-97.1668,48.8016],[-97.1675,48.8016],[-97.1685,48.8016],[-97.1698,48.8013],[-97.1706,48.8011],[-97.1714,48.8008],[-97.1715,48.8008],[-97.1724,48.8004],[-97.1731,48.8],[-97.1742,48.7992],[-97.175,48.7986],[-97.1754,48.7983],[-97.1757,48.798],[-97.1761,48.7977],[-97.1768,48.7974],[-97.1773,48.7973],[-97.1779,48.7972],[-97.1787,48.7972],[-97.1795,48.7972],[-97.1801,48.7973],[-97.1807,48.7975],[-97.1811,48.7978],[-97.1815,48.7982],[-97.1816,48.7986],[-97.1817,48.7991],[-97.1815,48.7995],[-97.1813,48.8],[-97.1808,48.8004],[-97.1801,48.8008],[-97.1791,48.8012],[-97.1779,48.8015],[-97.1769,48.8017],[-97.1764,48.8018],[-97.1756,48.8021],[-97.1748,48.8023],[-97.1725,48.8032],[-97.1713,48.8036],[-97.171,48.8037],[-97.1706,48.8039],[-97.1694,48.8043],[-97.1682,48.8046],[-97.1675,48.8048],[-97.1666,48.805],[-97.1655,48.8052],[-97.1638,48.8055],[-97.161,48.8059],[-97.1605,48.8061],[-97.1597,48.8064],[-97.159,48.8067],[-97.1583,48.8072],[-97.1579,48.8077],[-97.1577,48.8082],[-97.1576,48.8089],[-97.1578,48.8098],[-97.158,48.8104],[-97.1586,48.811],[-97.159,48.8111],[-97.161,48.8117],[-97.1617,48.8119],[-97.1625,48.812],[-97.1636,48.8121],[-97.1644,48.8121],[-97.1651,48.812],[-97.1666,48.8118],[-97.168,48.8116],[-97.169,48.8114],[-97.17,48.8114],[-97.1713,48.8115],[-97.1715,48.8115],[-97.1726,48.8117],[-97.1731,48.8118],[-97.174,48.8122],[-97.1761,48.8132],[-97.1776,48.8141],[-97.1784,48.8145],[-97.1797,48.8149],[-97.1807,48.8151],[-97.1821,48.8153],[-97.1828,48.8153],[-97.184,48.8152],[-97.1848,48.8151],[-97.186,48.8147],[-97.1868,48.8145],[-97.1873,48.8143],[-97.1879,48.8143],[-97.1883,48.8143],[-97.1889,48.8143],[-97.1894,48.8144],[-97.1898,48.8146],[-97.1901,48.8148],[-97.1903,48.8153],[-97.1904,48.8156],[-97.1903,48.8159],[-97.19,48.8163],[-97.1893,48.8167],[-97.1885,48.8171],[-97.1879,48.8173],[-97.1866,48.8176],[-97.1857,48.8177],[-97.1847,48.8179],[-97.184,48.8181],[-97.1833,48.8184],[-97.1817,48.8189],[-97.1809,48.8193],[-97.1801,48.8199],[-97.1793,48.8207],[-97.1787,48.8216],[-97.178,48.8232],[-97.1777,48.824],[-97.1776,48.8245],[-97.1777,48.8249],[-97.178,48.8255],[-97.1782,48.8258],[-97.1786,48.8262],[-97.1794,48.8268],[-97.1822,48.8288],[-97.1837,48.8299],[-97.1841,48.8304],[-97.1847,48.8314],[-97.1848,48.8319],[-97.1849,48.8326],[-97.1849,48.8327],[-97.1848,48.833],[-97.1846,48.8336],[-97.1842,48.8341],[-97.1837,48.8345],[-97.183,48.8348],[-97.1822,48.835],[-97.1813,48.8351],[-97.1799,48.8352],[-97.1783,48.8353],[-97.1779,48.8354],[-97.1772,48.8356],[-97.1757,48.8362],[-97.1753,48.8364],[-97.1747,48.8369],[-97.1742,48.8373],[-97.1739,48.8378],[-97.1738,48.8384],[-97.1738,48.839],[-97.1739,48.8406],[-97.1743,48.8427],[-97.1747,48.8438],[-97.175,48.8442],[-97.1755,48.8447],[-97.1761,48.8452],[-97.1767,48.8455],[-97.1771,48.8456],[-97.1779,48.8458],[-97.1795,48.8459],[-97.1808,48.846],[-97.1817,48.8462],[-97.1823,48.8464],[-97.1827,48.8468],[-97.1829,48.847],[-97.1829,48.8471],[-97.1829,48.8473],[-97.1826,48.8476],[-97.1821,48.8479],[-97.1816,48.848],[-97.1809,48.8481],[-97.1793,48.8482],[-97.178,48.8483],[-97.1767,48.8484],[-97.1759,48.8486],[-97.1753,48.8487],[-97.1747,48.849],[-97.1742,48.8493],[-97.1737,48.8497],[-97.1733,48.8502],[-97.173,48.8506],[-97.173,48.8508],[-97.173,48.8511],[-97.173,48.8516],[-97.1732,48.8522],[-97.1737,48.8527],[-97.1746,48.8534],[-97.1771,48.855],[-97.1784,48.8561],[-97.1786,48.8563],[-97.179,48.8569],[-97.1793,48.8576],[-97.1794,48.8583],[-97.1794,48.859],[-97.1792,48.8606],[-97.179,48.8615],[-97.179,48.862],[-97.1791,48.8626],[-97.1794,48.863],[-97.1801,48.8636],[-97.1811,48.864],[-97.1818,48.8641],[-97.1827,48.8641],[-97.1839,48.864],[-97.1855,48.8637],[-97.1871,48.8633],[-97.1877,48.8631],[-97.1883,48.8631],[-97.1891,48.8631],[-97.1896,48.8633],[-97.19,48.8635],[-97.1903,48.8639],[-97.1905,48.8644],[-97.1905,48.8648],[-97.1904,48.8651],[-97.1901,48.8657],[-97.1899,48.8661],[-97.1895,48.8665],[-97.189,48.867],[-97.1884,48.8675],[-97.1851,48.8694],[-97.1813,48.8718],[-97.1788,48.8736],[-97.1785,48.8738],[-97.1782,48.8741],[-97.1781,48.8743],[-97.1779,48.8745],[-97.1778,48.8747],[-97.1777,48.8749],[-97.1777,48.875],[-97.1778,48.875],[-97.1778,48.8754],[-97.1779,48.8757],[-97.1782,48.8761],[-97.1786,48.8765],[-97.1792,48.8769],[-97.1798,48.8771],[-97.1808,48.8772],[-97.1823,48.8772],[-97.1852,48.8768],[-97.1869,48.8765],[-97.1881,48.8765],[-97.1891,48.8766],[-97.1904,48.8769],[-97.1933,48.8779],[-97.1944,48.8783],[-97.1957,48.8788],[-97.1972,48.8794],[-97.1981,48.8799],[-97.1988,48.8805],[-97.1995,48.8812],[-97.1999,48.8818],[-97.1999,48.8821],[-97.2,48.8827],[-97.1998,48.8832],[-97.1997,48.8836],[-97.199,48.8845],[-97.1978,48.8859],[-97.1975,48.8865],[-97.1974,48.8868],[-97.1973,48.8872],[-97.1973,48.8874],[-97.1974,48.8877],[-97.1975,48.8881],[-97.1983,48.8889],[-97.2002,48.8903],[-97.2004,48.8904],[-97.2009,48.8908],[-97.2014,48.8912],[-97.2017,48.8915],[-97.2017,48.8919],[-97.2016,48.8922],[-97.2013,48.8925],[-97.201,48.8926],[-97.2001,48.8926],[-97.1994,48.8926],[-97.1985,48.8925],[-97.198,48.8924],[-97.1973,48.892],[-97.1957,48.8916],[-97.1946,48.8915],[-97.1944,48.8914],[-97.1937,48.8914],[-97.1927,48.8915],[-97.1921,48.8917],[-97.1916,48.8919],[-97.1905,48.8926],[-97.1901,48.8932],[-97.1898,48.8938],[-97.1897,48.8944],[-97.1897,48.8947],[-97.1898,48.8951],[-97.1899,48.8954],[-97.1903,48.896],[-97.1911,48.8967],[-97.1919,48.8974],[-97.1925,48.8979],[-97.1935,48.8985],[-97.1941,48.8988],[-97.1945,48.8989],[-97.1966,48.8997],[-97.1992,48.9004],[-97.2009,48.9009],[-97.2022,48.9013],[-97.2048,48.9018],[-97.2055,48.902],[-97.207,48.9025],[-97.2076,48.9027],[-97.2082,48.9029],[-97.2088,48.9032],[-97.2093,48.9036],[-97.21,48.904],[-97.2105,48.9044],[-97.211,48.905],[-97.2114,48.9056],[-97.2122,48.9069],[-97.2125,48.9075],[-97.2127,48.9082],[-97.2127,48.909],[-97.2125,48.9099],[-97.212,48.911],[-97.2116,48.9121],[-97.2111,48.913],[-97.2108,48.914],[-97.2106,48.9148],[-97.2106,48.9153],[-97.2109,48.9162],[-97.2111,48.9167],[-97.2115,48.9172],[-97.2118,48.9175],[-97.2122,48.9177],[-97.2129,48.9181],[-97.2149,48.9187],[-97.2163,48.9191],[-97.2164,48.9191],[-97.2171,48.9194],[-97.2179,48.9198],[-97.2189,48.9205],[-97.2196,48.9215],[-97.2198,48.9222],[-97.2199,48.923],[-97.2197,48.9237],[-97.2191,48.9249],[-97.2183,48.9262],[-97.2172,48.9277],[-97.2163,48.9286],[-97.2159,48.9289],[-97.2149,48.9301],[-97.2146,48.9304],[-97.2145,48.9307],[-97.2144,48.931],[-97.2145,48.9314],[-97.2145,48.9316],[-97.2148,48.9319],[-97.2154,48.9325],[-97.2159,48.9327],[-97.2162,48.9328],[-97.217,48.9328],[-97.2181,48.9327],[-97.2198,48.9325],[-97.2208,48.9325],[-97.2214,48.9325],[-97.2218,48.9326],[-97.2237,48.9332],[-97.2245,48.9337],[-97.2249,48.9339],[-97.225,48.934],[-97.2252,48.9342],[-97.2254,48.9345],[-97.2257,48.9349],[-97.226,48.9353],[-97.2263,48.936],[-97.2267,48.9376],[-97.227,48.9389],[-97.2271,48.9398],[-97.2271,48.941],[-97.227,48.9418],[-97.2266,48.9432],[-97.2264,48.9441],[-97.2263,48.9445],[-97.2264,48.9452],[-97.2265,48.9456],[-97.227,48.9462],[-97.2273,48.9465],[-97.2276,48.9467],[-97.2279,48.9467],[-97.2284,48.9468],[-97.2304,48.9465],[-97.2309,48.9464],[-97.2313,48.9464],[-97.2326,48.9466],[-97.2331,48.9468],[-97.2338,48.9471],[-97.2342,48.9474],[-97.2343,48.948],[-97.2343,48.9485],[-97.2342,48.9488],[-97.2341,48.9491],[-97.2337,48.95],[-97.2332,48.951],[-97.2328,48.9524],[-97.2323,48.954],[-97.2317,48.9558],[-97.2313,48.9568],[-97.2309,48.9578],[-97.2305,48.9585],[-97.23,48.9591],[-97.2288,48.9603],[-97.2282,48.9609],[-97.2278,48.9613],[-97.2276,48.9619],[-97.2276,48.9624],[-97.2279,48.963],[-97.228,48.9631],[-97.2283,48.9634],[-97.2289,48.9639],[-97.2294,48.9641],[-97.23,48.9642],[-97.2323,48.9646],[-97.2355,48.965],[-97.2368,48.9652],[-97.2375,48.9654],[-97.2382,48.966],[-97.2383,48.9661],[-97.2388,48.9666],[-97.2391,48.9676],[-97.2392,48.9687],[-97.239,48.9696],[-97.2387,48.9706],[-97.2383,48.9715],[-97.2381,48.9723],[-97.238,48.9725],[-97.2379,48.9731],[-97.2378,48.9734],[-97.2378,48.9738],[-97.238,48.9752],[-97.238,48.9763],[-97.2381,48.9771],[-97.238,48.9771],[-97.238,48.9841],[-97.2377,48.9849],[-97.2372,48.9857],[-97.2365,48.9867],[-97.2359,48.9874],[-97.2351,48.9881],[-97.2342,48.989],[-97.2335,48.9895],[-97.2331,48.9898],[-97.2317,48.9904],[-97.2301,48.9911],[-97.2293,48.9914],[-97.229,48.9916],[-97.2279,48.9921],[-97.2274,48.9925],[-97.227,48.9929],[-97.2266,48.9933],[-97.2265,48.9938],[-97.2267,48.9941],[-97.227,48.9945],[-97.2273,48.9947],[-97.2287,48.9949],[-97.2304,48.995],[-97.2317,48.9951],[-97.2324,48.9952],[-97.2335,48.9956],[-97.2338,48.9959],[-97.2341,48.9966],[-97.2341,48.997],[-97.234,48.9975],[-97.2337,48.9981],[-97.2332,48.9985],[-97.2323,48.999],[-97.2305,49.0],[-97.2303,49.0001],[-97.2295,49.0005],[-97.2175,49.0005],[-97.2161,49.0005],[-97.2078,49.0005],[-97.2069,49.0005],[-97.1955,49.0005],[-97.1939,49.0005],[-97.1739,49.0005],[-97.1724,49.0005],[-97.1514,49.0005],[-97.1502,49.0005],[-97.1294,49.0004],[-97.1277,49.0004],[-97.1073,49.0004],[-97.1061,49.0004],[-97.0853,49.0004],[-97.084,49.0004],[-97.0633,49.0004],[-97.062,49.0004],[-97.0412,49.0004],[-97.0401,49.0004],[-97.0192,49.0004],[-97.0183,49.0004],[-96.9971,49.0004],[-96.9961,49.0004],[-96.9751,49.0003],[-96.9738,49.0003],[-96.953,49.0003],[-96.9518,49.0003],[-96.931,49.0003],[-96.9299,49.0003],[-96.909,49.0003],[-96.9078,49.0003],[-96.8869,49.0003],[-96.8856,49.0003],[-96.8649,49.0003],[-96.864,49.0003],[-96.8429,49.0003],[-96.8415,49.0003],[-96.8208,49.0003],[-96.8197,49.0003],[-96.8023,49.0002],[-96.8005,49.0002],[-96.8003,49.0002],[-96.7988,49.0002],[-96.7787,49.0002],[-96.7768,49.0002],[-96.7567,49.0002],[-96.7547,49.0002],[-96.7348,49.0002],[-96.7327,49.0002],[-96.7127,49.0002],[-96.7107,49.0002],[-96.6905,49.0002],[-96.6886,49.0002],[-96.6695,49.0002],[-96.6665,49.0002],[-96.6482,49.0002],[-96.6445,49.0002],[-96.6243,49.0002],[-96.6225,49.0002],[-96.6021,49.0002],[-96.6004,49.0002],[-96.58,49.0002],[-96.5784,49.0002],[-96.558,49.0002],[-96.5563,49.0002],[-96.536,49.0002],[-96.5342,49.0002],[-96.5154,49.0002],[-96.5123,49.0002],[-96.4933,49.0002],[-96.49,49.0002],[-96.471,49.0001],[-96.4664,49.0001],[-96.4496,49.0001],[-96.4492,49.0001],[-96.4491,49.0001],[-96.446,49.0001],[-96.4273,49.0001],[-96.4224,49.0001],[-96.4054,49.0001]]],"type":"Polygon"},"id":"35","properties":{"Area":2862183702.23055,"CTYONLY_":3,"Code":"KITT","LASTMOD":"1999-12-31T23:59:59Z","Name":"Kittson","Perimiter":263017.48277},"type":"Feature"},{"geometry":{"coordinates":[[[-96.4054,49.0001],[-96.4019,49.0001],[-96.3825,49.0001],[-96.3783,49.0001],[-96.3606,49.0001],[-96.3579,49.0001],[-96.3385,49.0001],[-96.3343,49.0001],[-96.3166,49.0001],[-96.3138,49.0001],[-96.2945,49.0001],[-96.2902,49.0001],[-96.2725,49.0001],[-96.2698,49.0001],[-96.2494,49.0001],[-96.2461,49.0001],[-96.2274,49.0001],[-96.2257,49.0001],[-96.2057,49.0001],[-96.2021,49.0001],[-96.1837,49.0],[-96.18,49.0],[-96.1617,49.0],[-96.1579,49.0],[-96.1401,49.0],[-96.1359,49.0],[-96.1176,49.0],[-96.1139,49.0],[-96.0957,49.0],[-96.0919,49.0],[-96.0738,49.0],[-96.07,49.0],[-96.0517,49.0],[-96.048,49.0],[-96.0298,49.0],[-96.026,49.0],[-96.0083,49.0],[-96.0045,49.0],[-95.9868,49.0],[-95.9784,49.0],[-95.9776,49.0],[-95.9755,49.0],[-95.9648,48.9999],[-95.9464,48.9999],[-95.943,48.9999],[-95.9225,48.9999],[-95.9211,48.9999],[-95.899,48.9998],[-95.883,48.9998],[-95.8771,48.9998],[-95.8564,48.9998],[-95.855,48.9998],[-95.8342,48.9998],[-95.8184,48.9997],[-95.8126,48.9997],[-95.7906,48.9997],[-95.7833,48.9997],[-95.7684,48.9997],[-95.7479,48.9996],[-95.7466,48.9996],[-95.7253,48.9996],[-95.7066,48.9996],[-95.7032,48.9996],[-95.681,48.9995],[-95.6654,48.9995],[-95.6596,48.9995],[-95.659,48.9995],[-95.6401,48.9995],[-95.6369,48.9995],[-95.6205,48.9994],[-95.615,48.9994],[-95.5948,48.9994],[-95.585,48.9994],[-95.573,48.9994],[-95.551,48.9993],[-95.5495,48.9993],[-95.5294,48.9993],[-95.5164,48.9993],[-95.5072,48.9993],[-95.4849,48.9992],[-95.4834,48.9992],[-95.4635,48.9992],[-95.4508,48.9992],[-95.4418,48.9992],[-95.4245,48.9991],[-95.4197,48.9991],[-95.3977,48.9991],[-95.3953,48.9991],[-95.3765,48.9991],[-95.3759,48.9991],[-95.3753,48.9991],[-95.3542,48.999],[-95.3513,48.999],[-95.3326,48.999],[-95.3286,48.999],[-95.3231,48.999],[-95.3224,48.9984],[-95.3204,48.9976],[-95.3202,48.9973],[-95.3204,48.9964],[-95.3206,48.9961],[-95.3201,48.9956],[-95.3197,48.9954],[-95.3191,48.9953],[-95.3187,48.9956],[-95.3182,48.996],[-95.3179,48.9961],[-95.3178,48.9961],[-95.3178,48.9958],[-95.3181,48.995],[-95.3191,48.9941],[-95.3204,48.9924],[-95.3206,48.9921],[-95.3224,48.9889],[-95.3227,48.9884],[-95.3242,48.9859],[-95.3245,48.985],[-95.3253,48.9832],[-95.3257,48.9814],[-95.3256,48.98],[-95.3255,48.9789],[-95.3257,48.9784],[-95.3253,48.976],[-95.325,48.9743],[-95.3249,48.9738],[-95.3248,48.9728],[-95.3247,48.972],[-95.3241,48.9703],[-95.3232,48.9692],[-95.3227,48.9685],[-95.3212,48.9672],[-95.3207,48.9669],[-95.3201,48.9648],[-95.3198,48.9643],[-95.3193,48.964],[-95.3193,48.9622],[-95.3202,48.9606],[-95.3206,48.9598],[-95.3206,48.9595],[-95.3206,48.959],[-95.3202,48.9581],[-95.3191,48.9569],[-95.3188,48.9562],[-95.3179,48.9559],[-95.3175,48.9552],[-95.3177,48.9545],[-95.3182,48.9535],[-95.3181,48.9531],[-95.3177,48.9525],[-95.3154,48.9513],[-95.3151,48.951],[-95.3141,48.9508],[-95.3131,48.9503],[-95.3125,48.9503],[-95.3123,48.9502],[-95.3119,48.9502],[-95.3119,48.9507],[-95.3129,48.9521],[-95.3129,48.9523],[-95.3126,48.9524],[-95.312,48.9524],[-95.3115,48.952],[-95.3108,48.9512],[-95.3104,48.951],[-95.3097,48.951],[-95.3089,48.9511],[-95.3079,48.9509],[-95.3061,48.9502],[-95.3052,48.9495],[-95.3046,48.9482],[-95.3046,48.947],[-95.305,48.9462],[-95.3053,48.9459],[-95.3061,48.9454],[-95.3068,48.9454],[-95.3069,48.9455],[-95.3069,48.9456],[-95.3063,48.9462],[-95.3062,48.9463],[-95.3061,48.9469],[-95.3062,48.9472],[-95.3062,48.9472],[-95.3071,48.9477],[-95.3081,48.948],[-95.3094,48.9481],[-95.3096,48.9482],[-95.3099,48.9484],[-95.31,48.9485],[-95.3103,48.9485],[-95.3104,48.9484],[-95.3103,48.948],[-95.3096,48.9478],[-95.3092,48.9477],[-95.3079,48.9474],[-95.3071,48.9469],[-95.3071,48.9466],[-95.3074,48.9465],[-95.3078,48.9466],[-95.3085,48.947],[-95.3086,48.9469],[-95.3086,48.9465],[-95.3088,48.9464],[-95.3095,48.9463],[-95.3102,48.9463],[-95.3114,48.9461],[-95.3131,48.946],[-95.3141,48.9457],[-95.3148,48.9452],[-95.3154,48.9448],[-95.3168,48.9431],[-95.3181,48.9421],[-95.3189,48.9419],[-95.3219,48.9412],[-95.3225,48.9409],[-95.3228,48.9403],[-95.3231,48.9389],[-95.3229,48.9373],[-95.3225,48.9358],[-95.3223,48.9355],[-95.3228,48.9344],[-95.3222,48.9327],[-95.3209,48.9307],[-95.3208,48.9305],[-95.3195,48.9285],[-95.3168,48.9245],[-95.315,48.9222],[-95.3141,48.921],[-95.3132,48.9198],[-95.3126,48.919],[-95.3119,48.9178],[-95.3115,48.9172],[-95.3109,48.9163],[-95.3102,48.9155],[-95.3093,48.9149],[-95.3092,48.9149],[-95.3085,48.9146],[-95.3078,48.9141],[-95.3074,48.9135],[-95.3064,48.9129],[-95.3061,48.9128],[-95.3059,48.9127],[-95.3043,48.9119],[-95.3038,48.9114],[-95.3027,48.91],[-95.3017,48.9093],[-95.2999,48.9086],[-95.2978,48.9083],[-95.2973,48.9081],[-95.2973,48.908],[-95.2973,48.9077],[-95.2976,48.9074],[-95.2977,48.9073],[-95.2978,48.9073],[-95.2978,48.9072],[-95.2978,48.9072],[-95.2979,48.9072],[-95.2979,48.9072],[-95.2979,48.9071],[-95.298,48.9071],[-95.298,48.9071],[-95.298,48.9071],[-95.2981,48.907],[-95.2982,48.9068],[-95.2983,48.9068],[-95.2985,48.9065],[-95.2985,48.9064],[-95.2986,48.9063],[-95.2988,48.906],[-95.2989,48.906],[-95.2991,48.9057],[-95.2992,48.9055],[-95.2994,48.9053],[-95.2996,48.9051],[-95.2997,48.905],[-95.2999,48.9048],[-95.2999,48.9048],[-95.2999,48.9048],[-95.3,48.9047],[-95.3,48.9047],[-95.3001,48.9047],[-95.3001,48.9046],[-95.3002,48.9045],[-95.3005,48.904],[-95.2993,48.9035],[-95.2983,48.9028],[-95.298,48.9027],[-95.2976,48.9026],[-95.2967,48.9027],[-95.2949,48.9028],[-95.2941,48.9027],[-95.2937,48.9023],[-95.2935,48.902],[-95.2927,48.9019],[-95.2914,48.9019],[-95.2909,48.9017],[-95.2908,48.9016],[-95.2907,48.9014],[-95.2906,48.9011],[-95.2911,48.9008],[-95.2911,48.9006],[-95.2901,48.9003],[-95.2896,48.9],[-95.289,48.8994],[-95.2882,48.8981],[-95.2879,48.8979],[-95.2872,48.8977],[-95.287,48.8976],[-95.2865,48.8975],[-95.2861,48.8976],[-95.2853,48.8977],[-95.2839,48.8975],[-95.2813,48.8967],[-95.2803,48.8965],[-95.2796,48.8962],[-95.279,48.8957],[-95.2782,48.8956],[-95.2773,48.8957],[-95.277,48.8958],[-95.2765,48.8962],[-95.2763,48.8963],[-95.2759,48.8962],[-95.2755,48.8959],[-95.2749,48.8956],[-95.2748,48.8951],[-95.2753,48.8943],[-95.2751,48.8938],[-95.2745,48.8931],[-95.2724,48.8921],[-95.2713,48.8915],[-95.268,48.8905],[-95.2677,48.8903],[-95.2674,48.89],[-95.2666,48.8894],[-95.2654,48.8888],[-95.265,48.8886],[-95.2646,48.8885],[-95.2639,48.8883],[-95.2635,48.888],[-95.2627,48.8877],[-95.2585,48.8867],[-95.2585,48.8867],[-95.257,48.8858],[-95.256,48.885],[-95.2548,48.8845],[-95.2517,48.8839],[-95.2507,48.8836],[-95.2502,48.8835],[-95.2496,48.8834],[-95.2485,48.8832],[-95.248,48.8836],[-95.2472,48.8835],[-95.2458,48.8829],[-95.2439,48.8823],[-95.2429,48.8822],[-95.2429,48.8822],[-95.2423,48.8821],[-95.2407,48.8821],[-95.2391,48.8819],[-95.2381,48.8817],[-95.2356,48.8815],[-95.2335,48.8814],[-95.231,48.8814],[-95.2287,48.8815],[-95.2265,48.8816],[-95.2252,48.8819],[-95.2212,48.883],[-95.2208,48.8831],[-95.2207,48.8831],[-95.22,48.8831],[-95.2193,48.8832],[-95.2188,48.8835],[-95.217,48.8835],[-95.2159,48.8839],[-95.2151,48.884],[-95.2144,48.8843],[-95.2122,48.8842],[-95.2117,48.8847],[-95.2115,48.8847],[-95.2112,48.8848],[-95.2085,48.8846],[-95.2059,48.8848],[-95.2024,48.8852],[-95.2009,48.8855],[-95.2005,48.8856],[-95.1986,48.8855],[-95.1956,48.8862],[-95.1924,48.8865],[-95.1919,48.8866],[-95.1913,48.8868],[-95.1901,48.887],[-95.1889,48.8873],[-95.1877,48.8874],[-95.1863,48.8877],[-95.1851,48.8882],[-95.1819,48.8888],[-95.1797,48.889],[-95.1791,48.889],[-95.1764,48.8893],[-95.173,48.8897],[-95.1701,48.8902],[-95.1674,48.8907],[-95.1648,48.8913],[-95.1641,48.8917],[-95.1618,48.892],[-95.1602,48.892],[-95.1579,48.8919],[-95.1564,48.8919],[-95.1555,48.892],[-95.1528,48.8921],[-95.1508,48.8922],[-95.1483,48.8923],[-95.1469,48.8927],[-95.1459,48.8929],[-95.1438,48.8934],[-95.1436,48.8937],[-95.1404,48.8943],[-95.1381,48.8949],[-95.1355,48.8959],[-95.1351,48.8963],[-95.1348,48.8963],[-95.1343,48.8963],[-95.1337,48.8969],[-95.1322,48.8973],[-95.1312,48.8975],[-95.1252,48.8998],[-95.1239,48.9001],[-95.1233,48.9004],[-95.1228,48.9006],[-95.1214,48.9013],[-95.121,48.9016],[-95.1205,48.9017],[-95.1204,48.9019],[-95.1182,48.9029],[-95.1163,48.9037],[-95.1151,48.9046],[-95.1144,48.9052],[-95.114,48.9061],[-95.1141,48.9064],[-95.1137,48.9069],[-95.1132,48.9071],[-95.113,48.9072],[-95.1126,48.9073],[-95.1107,48.9082],[-95.1096,48.9089],[-95.108,48.9099],[-95.1056,48.9113],[-95.1042,48.9121],[-95.1032,48.9127],[-95.102,48.9132],[-95.1008,48.9142],[-95.0981,48.9159],[-95.098,48.916],[-95.0975,48.9164],[-95.0971,48.9172],[-95.097,48.9176],[-95.0961,48.9181],[-95.0946,48.9191],[-95.0944,48.9193],[-95.0927,48.9204],[-95.0919,48.9207],[-95.0914,48.9208],[-95.0914,48.916],[-95.0912,48.9014],[-95.0911,48.8869],[-95.0908,48.8724],[-95.0908,48.858],[-95.0907,48.8436],[-95.0908,48.8291],[-95.0909,48.8147],[-95.0903,48.8],[-95.0903,48.7855],[-95.0903,48.7711],[-95.0901,48.7566],[-95.0901,48.7421],[-95.0899,48.7277],[-95.0898,48.713],[-95.1046,48.7129],[-95.1104,48.7129],[-95.1119,48.7129],[-95.1259,48.7129],[-95.1297,48.713],[-95.1333,48.713],[-95.1477,48.7129],[-95.1554,48.7129],[-95.1697,48.7129],[-95.1773,48.713],[-95.1917,48.713],[-95.1991,48.713],[-95.2112,48.713],[-95.2206,48.713],[-95.2331,48.713],[-95.2427,48.713],[-95.255,48.713],[-95.2645,48.713],[-95.2656,48.713],[-95.2767,48.713],[-95.2866,48.713],[-95.299,48.713],[-95.3051,48.713],[-95.3084,48.713],[-95.3205,48.713],[-95.3302,48.713],[-95.3425,48.7131],[-95.3425,48.6995],[-95.3424,48.6849],[-95.3423,48.6705],[-95.3424,48.6561],[-95.3425,48.6415],[-95.3426,48.6271],[-95.3424,48.6127],[-95.3426,48.5979],[-95.3423,48.5836],[-95.3423,48.5691],[-95.3424,48.5548],[-95.3425,48.5402],[-95.3628,48.5404],[-95.364,48.5403],[-95.3844,48.5402],[-95.386,48.5402],[-95.4061,48.5402],[-95.4078,48.5402],[-95.4279,48.54],[-95.4297,48.5399],[-95.4494,48.5399],[-95.4513,48.5399],[-95.4712,48.5396],[-95.4726,48.5396],[-95.493,48.5392],[-95.495,48.5392],[-95.5143,48.539],[-95.5163,48.539],[-95.5365,48.5389],[-95.5383,48.5389],[-95.558,48.5388],[-95.5603,48.5388],[-95.5801,48.5387],[-95.5821,48.5387],[-95.6023,48.5389],[-95.6232,48.5391],[-95.6447,48.5393],[-95.6666,48.5394],[-95.6886,48.5395],[-95.7102,48.5395],[-95.7322,48.54],[-95.7539,48.5404],[-95.7758,48.5406],[-95.7976,48.5405],[-95.8192,48.5404],[-95.8411,48.5406],[-95.8621,48.5414],[-95.8829,48.5419],[-95.8851,48.542],[-95.8986,48.5421],[-95.9046,48.5422],[-95.9064,48.5422],[-95.9269,48.5421],[-95.9486,48.5425],[-95.9498,48.5425],[-95.9704,48.543],[-95.9936,48.5435],[-96.0157,48.5437],[-96.0374,48.5438],[-96.0592,48.5437],[-96.0812,48.5436],[-96.1026,48.5438],[-96.1264,48.5439],[-96.1486,48.5442],[-96.1702,48.5445],[-96.1921,48.5446],[-96.2141,48.5449],[-96.2358,48.5452],[-96.2576,48.545],[-96.2794,48.5449],[-96.301,48.5448],[-96.3231,48.5446],[-96.3448,48.5444],[-96.3667,48.5443],[-96.3882,48.5442],[-96.3879,48.5588],[-96.3882,48.5733],[-96.3884,48.5877],[-96.3891,48.6024],[-96.389,48.6165],[-96.388,48.6313],[-96.3879,48.6454],[-96.3877,48.6599],[-96.3871,48.6741],[-96.3874,48.6887],[-96.3866,48.703],[-96.3873,48.7172],[-96.388,48.7172],[-96.4049,48.7172],[-96.4048,48.7318],[-96.4048,48.7465],[-96.4047,48.7607],[-96.4045,48.7758],[-96.4042,48.7903],[-96.4042,48.8048],[-96.4042,48.8198],[-96.4043,48.8343],[-96.4045,48.8491],[-96.4047,48.8635],[-96.405,48.878],[-96.405,48.8926],[-96.4053,48.9068],[-96.4053,48.9081],[-96.4053,48.9137],[-96.4054,48.9214],[-96.4054,48.9225],[-96.4053,48.936],[-96.4053,48.9371],[-96.4053,48.9504],[-96.4053,48.9515],[-96.4053,48.9648],[-96.4053,48.9658],[-96.4053,48.9705],[-96.4054,48.9793],[-96.4054,48.9803],[-96.4054,48.994],[-96.4054,48.9947],[-96.4054,49.0001]]],"type":"Polygon"},"id":"68","properties":{"Area":4347098503.12714,"CTYONLY_":4,"Code":"ROSE","LASTMOD":"2001-04-12T09:32:44Z","Name":"Roseau","Perimiter":302590.75293},"type":"Feature"},{"geometry":{"coordinates":[[[-94.4299,48.7012],[-94.4241,48.7053],[-94.4213,48.7086],[-94.4189,48.7103],[-94.4158,48.711],[-94.4081,48.7106],[-94.406,48.7105],[-94.3889,48.712],[-94.3859,48.7119],[-94.384,48.7119],[-94.3801,48.7111],[-94.3687,48.7065],[-94.3646,48.7059],[-94.3533,48.7042],[-94.3431,48.7035],[-94.3429,48.7035],[-94.3287,48.7045],[-94.3214,48.7067],[-94.3088,48.7103],[-94.2995,48.709],[-94.2911,48.7079],[-94.2829,48.7057],[-94.2781,48.7024],[-94.2745,48.6999],[-94.2694,48.6995],[-94.2644,48.699],[-94.261,48.6966],[-94.258,48.6918],[-94.2565,48.6901],[-94.2529,48.6864],[-94.2521,48.685],[-94.2514,48.6837],[-94.2507,48.6782],[-94.2527,48.6707],[-94.253,48.6693],[-94.2548,48.664],[-94.2546,48.6615],[-94.2509,48.657],[-94.2499,48.6563],[-94.2467,48.6542],[-94.2445,48.6535],[-94.2343,48.6524],[-94.2335,48.6524],[-94.2242,48.6495],[-94.2144,48.6494],[-94.2124,48.6496],[-94.1996,48.651],[-94.1915,48.6506],[-94.1886,48.6504],[-94.1689,48.6483],[-94.1678,48.6482],[-94.1574,48.6458],[-94.1522,48.6455],[-94.1458,48.6458],[-94.1391,48.646],[-94.126,48.6444],[-94.1235,48.6444],[-94.11,48.6443],[-94.1023,48.6455],[-94.0999,48.6459],[-94.0912,48.6437],[-94.0849,48.6441],[-94.0804,48.6442],[-94.0767,48.6442],[-94.0714,48.6459],[-94.0658,48.6462],[-94.0642,48.6438],[-94.0603,48.6431],[-94.0581,48.6434],[-94.0525,48.644],[-94.0432,48.6435],[-94.0393,48.6423],[-94.0364,48.6413],[-94.0356,48.6411],[-94.0295,48.6409],[-94.0153,48.6424],[-94.0069,48.6433],[-94.0007,48.6428],[-93.9931,48.6412],[-93.9897,48.6405],[-93.984,48.6401],[-93.9777,48.6385],[-93.9712,48.6385],[-93.968,48.6385],[-93.9596,48.6372],[-93.953,48.6341],[-93.9497,48.6339],[-93.934,48.6326],[-93.9272,48.6327],[-93.9169,48.6329],[-93.9134,48.6353],[-93.9057,48.6346],[-93.9054,48.6345],[-93.8948,48.6324],[-93.8853,48.6318],[-93.8844,48.6318],[-93.8757,48.6319],[-93.8698,48.6311],[-93.8624,48.631],[-93.848,48.6308],[-93.8443,48.6303],[-93.8404,48.6289],[-93.8393,48.6286],[-93.8365,48.6276],[-93.8334,48.6256],[-93.8292,48.6177],[-93.825,48.6136],[-93.8245,48.613],[-93.8214,48.6092],[-93.8182,48.5994],[-93.8175,48.597],[-93.8172,48.5964],[-93.813,48.588],[-93.8103,48.5846],[-93.8063,48.5796],[-93.8041,48.5703],[-93.8041,48.5702],[-93.8051,48.5644],[-93.808,48.5569],[-93.8088,48.5555],[-93.8119,48.5503],[-93.8102,48.5445],[-93.8109,48.5412],[-93.8109,48.541],[-93.818,48.535],[-93.818,48.5346],[-93.8184,48.5315],[-93.8178,48.5306],[-93.8161,48.5285],[-93.8145,48.5273],[-93.8111,48.5247],[-93.803,48.522],[-93.7964,48.5182],[-93.7933,48.5164],[-93.7879,48.5159],[-93.7745,48.5162],[-93.768,48.5164],[-93.7665,48.5164],[-93.7617,48.5166],[-93.7534,48.5158],[-93.7442,48.5175],[-93.739,48.5185],[-93.731,48.5185],[-93.7225,48.5178],[-93.7206,48.5176],[-93.7108,48.5186],[-93.7061,48.5182],[-93.7006,48.517],[-93.693,48.5152],[-93.6866,48.5154],[-93.6791,48.5167],[-93.6778,48.5169],[-93.6593,48.5165],[-93.657,48.5167],[-93.6473,48.5177],[-93.6433,48.519],[-93.6421,48.5199],[-93.6395,48.5218],[-93.6357,48.5285],[-93.6344,48.5293],[-93.6311,48.5313],[-93.6284,48.5319],[-93.6256,48.5315],[-93.6211,48.5264],[-93.6166,48.5238],[-93.6134,48.5228],[-93.6122,48.5225],[-93.6051,48.5231],[-93.5962,48.5287],[-93.5919,48.5299],[-93.5901,48.5305],[-93.581,48.5271],[-93.5761,48.527],[-93.5701,48.528],[-93.5602,48.5297],[-93.5484,48.5294],[-93.5476,48.5294],[-93.5425,48.53],[-93.5366,48.5319],[-93.5269,48.5341],[-93.5263,48.5341],[-93.5244,48.5343],[-93.5171,48.5348],[-93.5047,48.5399],[-93.501,48.5414],[-93.4952,48.5426],[-93.4854,48.5433],[-93.4833,48.5437],[-93.4673,48.5465],[-93.4655,48.5478],[-93.4625,48.5498],[-93.462,48.5505],[-93.4596,48.5537],[-93.4576,48.5598],[-93.4576,48.5621],[-93.4575,48.5672],[-93.4619,48.5731],[-93.4619,48.5734],[-93.4631,48.5767],[-93.4671,48.5885],[-93.4656,48.59],[-93.4654,48.5915],[-93.4654,48.5917],[-93.4627,48.5927],[-93.46,48.5927],[-93.4547,48.5927],[-93.4398,48.5937],[-93.4385,48.5942],[-93.4347,48.5954],[-93.4298,48.5997],[-93.4226,48.6032],[-93.4193,48.6036],[-93.416,48.605],[-93.4152,48.6053],[-93.415,48.6056],[-93.4144,48.6064],[-93.4056,48.6099],[-93.4034,48.61],[-93.4029,48.6077],[-93.4013,48.6079],[-93.3994,48.6055],[-93.3986,48.6045],[-93.3953,48.6038],[-93.3937,48.6041],[-93.3837,48.606],[-93.3724,48.6059],[-93.3714,48.6059],[-93.3672,48.6082],[-93.3619,48.6141],[-93.355,48.6114],[-93.3526,48.6135],[-93.3533,48.615],[-93.3513,48.62],[-93.3505,48.6219],[-93.3486,48.6265],[-93.3276,48.6302],[-93.3057,48.634],[-93.3048,48.6341],[-93.2838,48.6378],[-93.2634,48.6413],[-93.2546,48.6429],[-93.2422,48.6428],[-93.2193,48.6426],[-93.2075,48.6426],[-93.1975,48.6365],[-93.191,48.6325],[-93.184,48.6282],[-93.1783,48.6231],[-93.1754,48.6232],[-93.1531,48.6244],[-93.1319,48.6256],[-93.1104,48.6267],[-93.0903,48.6278],[-93.0884,48.6278],[-93.0886,48.6163],[-93.0895,48.6016],[-93.0898,48.5872],[-93.09,48.5727],[-93.0902,48.5583],[-93.0902,48.5441],[-93.0903,48.5296],[-93.0905,48.5151],[-93.0905,48.501],[-93.091,48.4884],[-93.0911,48.4867],[-93.0914,48.474],[-93.0915,48.4724],[-93.0918,48.4596],[-93.0919,48.458],[-93.092,48.4449],[-93.092,48.4436],[-93.0922,48.4303],[-93.0922,48.429],[-93.0923,48.4147],[-93.0935,48.4147],[-93.0938,48.4024],[-93.094,48.3879],[-93.094,48.3734],[-93.0945,48.3589],[-93.0948,48.3442],[-93.0948,48.3298],[-93.0953,48.3153],[-93.0952,48.3004],[-93.095,48.2862],[-93.0952,48.2716],[-93.0953,48.2576],[-93.0949,48.2426],[-93.0949,48.2425],[-93.0977,48.2426],[-93.0977,48.2271],[-93.0978,48.2126],[-93.0979,48.1981],[-93.0975,48.1836],[-93.097,48.1692],[-93.097,48.1546],[-93.097,48.1402],[-93.0969,48.1259],[-93.0972,48.1114],[-93.097,48.0969],[-93.0968,48.0823],[-93.0965,48.0679],[-93.0965,48.0678],[-93.0892,48.0679],[-93.0892,48.0509],[-93.089,48.0366],[-93.0886,48.022],[-93.0887,48.0075],[-93.0872,47.9932],[-93.088,47.9787],[-93.0809,47.9786],[-93.0809,47.967],[-93.0808,47.9647],[-93.0808,47.9525],[-93.0808,47.9504],[-93.0809,47.938],[-93.0809,47.9356],[-93.0809,47.9235],[-93.0809,47.9212],[-93.0809,47.9088],[-93.0809,47.9067],[-93.0808,47.8945],[-93.0808,47.8922],[-93.1015,47.8927],[-93.1232,47.893],[-93.1448,47.8928],[-93.1656,47.8931],[-93.1671,47.8932],[-93.1871,47.8931],[-93.1893,47.8931],[-93.2087,47.8933],[-93.2115,47.8934],[-93.2331,47.8937],[-93.2532,47.8936],[-93.2745,47.8938],[-93.2962,47.8939],[-93.3169,47.894],[-93.3392,47.8941],[-93.3603,47.8942],[-93.3809,47.8943],[-93.4024,47.8944],[-93.4235,47.8945],[-93.4442,47.8946],[-93.466,47.895],[-93.4874,47.8956],[-93.4892,47.8957],[-93.4933,47.8958],[-93.5085,47.8962],[-93.5105,47.8963],[-93.5297,47.8967],[-93.5303,47.8967],[-93.532,47.8968],[-93.5517,47.8973],[-93.5532,47.8974],[-93.5729,47.8981],[-93.5747,47.8982],[-93.5962,47.8978],[-93.5966,47.8978],[-93.6179,47.8977],[-93.6187,47.8977],[-93.6388,47.8977],[-93.6395,47.8976],[-93.6604,47.8976],[-93.6612,47.8976],[-93.6817,47.8976],[-93.6826,47.8976],[-93.7031,47.8976],[-93.7038,47.8976],[-93.7249,47.8975],[-93.7248,47.8989],[-93.7466,47.8989],[-93.768,47.8991],[-93.7758,47.8991],[-93.7758,47.899],[-93.776,47.8897],[-93.776,47.8842],[-93.7762,47.8753],[-93.7761,47.8697],[-93.7761,47.8607],[-93.7761,47.8553],[-93.7761,47.8464],[-93.7896,47.8465],[-93.7971,47.8466],[-93.8189,47.8467],[-93.8407,47.8468],[-93.8627,47.8469],[-93.8831,47.8471],[-93.9067,47.8471],[-93.9288,47.8475],[-93.9496,47.8475],[-93.9506,47.8475],[-93.971,47.8475],[-93.9725,47.8475],[-93.9927,47.8475],[-93.9942,47.8475],[-94.0141,47.8476],[-94.0161,47.8476],[-94.0375,47.8477],[-94.0591,47.8474],[-94.0807,47.8471],[-94.1022,47.8471],[-94.1239,47.8466],[-94.1448,47.8463],[-94.1657,47.8461],[-94.1822,47.8461],[-94.1871,47.846],[-94.2037,47.846],[-94.2086,47.846],[-94.2252,47.846],[-94.23,47.8461],[-94.2467,47.8462],[-94.2515,47.8462],[-94.2681,47.8462],[-94.2728,47.8462],[-94.2887,47.8462],[-94.3103,47.8458],[-94.3315,47.846],[-94.3532,47.8464],[-94.3747,47.8462],[-94.3964,47.8461],[-94.4185,47.8459],[-94.4186,47.86],[-94.4184,47.8744],[-94.418,47.8886],[-94.4177,47.9031],[-94.4176,47.9041],[-94.4175,47.9175],[-94.4174,47.9186],[-94.4175,47.9332],[-94.4174,47.9477],[-94.4172,47.9623],[-94.4173,47.9769],[-94.4176,47.9914],[-94.4177,48.006],[-94.4176,48.02],[-94.4236,48.0199],[-94.4241,48.0344],[-94.4246,48.0489],[-94.4247,48.0632],[-94.4234,48.0776],[-94.4231,48.092],[-94.4233,48.1059],[-94.4234,48.1204],[-94.4236,48.1348],[-94.4233,48.1491],[-94.4235,48.1637],[-94.4235,48.1781],[-94.4233,48.1923],[-94.4236,48.2067],[-94.4238,48.2212],[-94.4237,48.2356],[-94.4237,48.2504],[-94.424,48.2649],[-94.4243,48.2791],[-94.4244,48.2938],[-94.4246,48.3081],[-94.4248,48.3227],[-94.425,48.3372],[-94.4253,48.352],[-94.4252,48.3675],[-94.4288,48.3675],[-94.4289,48.3821],[-94.4293,48.3964],[-94.4294,48.411],[-94.4293,48.4254],[-94.4292,48.4399],[-94.4293,48.4543],[-94.4296,48.4688],[-94.4296,48.4832],[-94.4299,48.4977],[-94.4303,48.512],[-94.4303,48.5264],[-94.43,48.5409],[-94.4295,48.5554],[-94.4291,48.5698],[-94.4289,48.5844],[-94.4289,48.5988],[-94.4292,48.6133],[-94.4294,48.6276],[-94.4297,48.642],[-94.43,48.6564],[-94.4301,48.6708],[-94.43,48.6852],[-94.4299,48.6998],[-94.4299,48.7012]]],"type":"Polygon"},"id":"36","properties":{"Area":8167237870.91888,"CTYONLY_":5,"Code":"KOOC","LASTMOD":"1999-12-31T23:59:59Z","Name":"Koochiching","Perimiter":412897.43594},"type":"Feature"},{"geometry":{"coordinates":[[[-96.3882,48.5442],[-96.3667,48.5443],[-96.3448,48.5444],[-96.3231,48.5446],[-96.301,48.5448],[-96.2794,48.5449],[-96.2576,48.545],[-96.2358,48.5452],[-96.2141,48.5449],[-96.1921,48.5446],[-96.1702,48.5445],[-96.1486,48.5442],[-96.1264,48.5439],[-96.1026,48.5438],[-96.0812,48.5436],[-96.0592,48.5437],[-96.0374,48.5438],[-96.0157,48.5437],[-95.9936,48.5435],[-95.9704,48.543],[-95.9498,48.5425],[-95.9486,48.5425],[-95.9269,48.5421],[-95.9064,48.5422],[-95.9046,48.5422],[-95.8986,48.5421],[-95.8851,48.542],[-95.8829,48.5419],[-95.8621,48.5414],[-95.8411,48.5406],[-95.8192,48.5404],[-95.7976,48.5405],[-95.7758,48.5406],[-95.7539,48.5404],[-95.7322,48.54],[-95.7102,48.5395],[-95.6886,48.5395],[-95.6666,48.5394],[-95.6447,48.5393],[-95.6232,48.5391],[-95.6023,48.5389],[-95.6011,48.5251],[-95.6007,48.5107],[-95.6007,48.51],[-95.6008,48.4964],[-95.6008,48.4956],[-95.6011,48.4818],[-95.6011,48.4811],[-95.6016,48.4674],[-95.6016,48.4666],[-95.6016,48.453],[-95.6016,48.4522],[-95.602,48.4385],[-95.6021,48.4376],[-95.6023,48.424],[-95.6023,48.4232],[-95.6026,48.4095],[-95.6026,48.4088],[-95.6026,48.395],[-95.6026,48.3942],[-95.6021,48.3809],[-95.602,48.3798],[-95.6016,48.3655],[-95.5933,48.3656],[-95.5933,48.3656],[-95.5933,48.354],[-95.5932,48.3396],[-95.5932,48.325],[-95.5932,48.3105],[-95.5934,48.2961],[-95.5934,48.2815],[-95.5937,48.267],[-95.5941,48.2526],[-95.5941,48.2382],[-95.5939,48.2236],[-95.5939,48.2092],[-95.5938,48.1946],[-95.594,48.1802],[-95.5939,48.173],[-95.5941,48.173],[-95.6159,48.1731],[-95.6163,48.1731],[-95.6252,48.1731],[-95.6279,48.1731],[-95.6376,48.173],[-95.6376,48.173],[-95.6591,48.1729],[-95.662,48.1729],[-95.6802,48.1728],[-95.6803,48.1728],[-95.702,48.1729],[-95.7021,48.1729],[-95.7022,48.1729],[-95.7128,48.173],[-95.7157,48.1731],[-95.7226,48.1731],[-95.7227,48.1731],[-95.744,48.1727],[-95.7443,48.1727],[-95.7502,48.1727],[-95.7657,48.1728],[-95.7657,48.1728],[-95.7874,48.1725],[-95.8088,48.1722],[-95.809,48.1722],[-95.8091,48.1722],[-95.8305,48.1722],[-95.8308,48.1722],[-95.8308,48.1722],[-95.8499,48.1721],[-95.8525,48.1721],[-95.8527,48.1721],[-95.8744,48.172],[-95.8744,48.172],[-95.8752,48.172],[-95.8958,48.172],[-95.896,48.172],[-95.9176,48.1719],[-95.9178,48.1719],[-95.9178,48.1719],[-95.9392,48.1719],[-95.9394,48.1719],[-95.9608,48.1718],[-95.9609,48.1718],[-95.961,48.1718],[-95.9651,48.1718],[-95.9817,48.1717],[-95.9819,48.1717],[-95.9956,48.1717],[-96.0003,48.1717],[-96.0023,48.1718],[-96.0028,48.1718],[-96.0032,48.1718],[-96.0035,48.1718],[-96.0036,48.1718],[-96.0047,48.1717],[-96.0101,48.1718],[-96.0171,48.172],[-96.025,48.1721],[-96.0254,48.1721],[-96.0468,48.1722],[-96.0468,48.1722],[-96.0592,48.1721],[-96.0685,48.1721],[-96.0685,48.1721],[-96.079,48.1721],[-96.09,48.172],[-96.09,48.172],[-96.0979,48.172],[-96.1084,48.1718],[-96.1084,48.1718],[-96.1176,48.1722],[-96.1189,48.1722],[-96.1253,48.1727],[-96.1297,48.173],[-96.1298,48.173],[-96.1302,48.173],[-96.1388,48.1732],[-96.1516,48.1736],[-96.1518,48.1736],[-96.1625,48.1736],[-96.1641,48.1736],[-96.1736,48.1736],[-96.1737,48.1736],[-96.1741,48.1736],[-96.1813,48.1725],[-96.1827,48.1722],[-96.1834,48.172],[-96.1874,48.1721],[-96.191,48.1721],[-96.1948,48.1721],[-96.1954,48.1721],[-96.1959,48.1721],[-96.1963,48.1721],[-96.2023,48.1722],[-96.2038,48.1722],[-96.2072,48.1722],[-96.2076,48.1722],[-96.2177,48.1722],[-96.2179,48.1722],[-96.2188,48.1722],[-96.2251,48.1724],[-96.2275,48.1724],[-96.2287,48.1725],[-96.2307,48.1725],[-96.2329,48.1725],[-96.2391,48.1727],[-96.2397,48.1727],[-96.2397,48.1727],[-96.2398,48.1728],[-96.2476,48.1735],[-96.2491,48.1737],[-96.2503,48.1739],[-96.2511,48.174],[-96.252,48.174],[-96.2562,48.1744],[-96.2596,48.1749],[-96.2607,48.1749],[-96.2612,48.1749],[-96.2619,48.1749],[-96.2805,48.1747],[-96.2823,48.1747],[-96.2824,48.1747],[-96.2977,48.1747],[-96.3029,48.1747],[-96.3035,48.1747],[-96.3145,48.1747],[-96.3252,48.1746],[-96.3253,48.1746],[-96.3301,48.1745],[-96.3356,48.1745],[-96.3358,48.1744],[-96.338,48.1745],[-96.3402,48.1744],[-96.343,48.1744],[-96.3466,48.1743],[-96.347,48.1743],[-96.3473,48.1744],[-96.3477,48.1744],[-96.351,48.1745],[-96.3542,48.1746],[-96.3581,48.1747],[-96.361,48.1748],[-96.3642,48.1749],[-96.3656,48.175],[-96.3682,48.1751],[-96.3682,48.1751],[-96.3685,48.1751],[-96.3706,48.175],[-96.3728,48.1749],[-96.3753,48.1748],[-96.3781,48.1746],[-96.38,48.1745],[-96.3856,48.1747],[-96.3894,48.1748],[-96.3905,48.1748],[-96.3906,48.1748],[-96.3964,48.1748],[-96.4054,48.1748],[-96.4126,48.1749],[-96.4126,48.1749],[-96.4135,48.1749],[-96.4206,48.1749],[-96.4295,48.1749],[-96.4346,48.1749],[-96.4352,48.1749],[-96.4359,48.1749],[-96.438,48.1749],[-96.4402,48.1748],[-96.4436,48.1747],[-96.4454,48.1747],[-96.4561,48.1744],[-96.4563,48.1743],[-96.4564,48.1742],[-96.4569,48.1742],[-96.4592,48.1742],[-96.467,48.1741],[-96.4735,48.174],[-96.4773,48.1741],[-96.4789,48.1741],[-96.4791,48.1741],[-96.4841,48.174],[-96.4946,48.1741],[-96.4973,48.174],[-96.5003,48.1741],[-96.5006,48.1741],[-96.5008,48.1742],[-96.5008,48.1742],[-96.5038,48.174],[-96.5091,48.174],[-96.5164,48.1739],[-96.5204,48.1739],[-96.5223,48.1739],[-96.5251,48.1738],[-96.53,48.1738],[-96.5357,48.1738],[-96.5399,48.1738],[-96.5434,48.1738],[-96.5442,48.1738],[-96.5443,48.1738],[-96.5446,48.1738],[-96.5479,48.1738],[-96.5507,48.1738],[-96.5544,48.1738],[-96.557,48.1739],[-96.5616,48.1739],[-96.565,48.174],[-96.5654,48.174],[-96.5655,48.174],[-96.5678,48.174],[-96.5715,48.1739],[-96.5748,48.1739],[-96.5765,48.1739],[-96.5806,48.1739],[-96.5838,48.1738],[-96.5873,48.1737],[-96.5873,48.1737],[-96.5875,48.1737],[-96.5893,48.1737],[-96.5966,48.1737],[-96.6055,48.1737],[-96.609,48.1737],[-96.6092,48.1737],[-96.6106,48.1737],[-96.6253,48.1737],[-96.6307,48.1737],[-96.6307,48.1737],[-96.6309,48.1737],[-96.6338,48.1737],[-96.6378,48.1738],[-96.6407,48.1739],[-96.6525,48.1738],[-96.6525,48.1738],[-96.6742,48.1736],[-96.6742,48.1736],[-96.6826,48.1735],[-96.6958,48.1734],[-96.6959,48.1734],[-96.7176,48.1734],[-96.7177,48.1734],[-96.7393,48.1734],[-96.7393,48.1734],[-96.7503,48.1734],[-96.7573,48.1734],[-96.7581,48.1734],[-96.7605,48.1734],[-96.7606,48.1734],[-96.7613,48.1734],[-96.7819,48.1734],[-96.7821,48.1734],[-96.7821,48.1734],[-96.7932,48.1733],[-96.8038,48.1734],[-96.8039,48.1734],[-96.8111,48.1734],[-96.8255,48.1734],[-96.8255,48.1734],[-96.8473,48.1733],[-96.8474,48.1733],[-96.869,48.1733],[-96.869,48.1733],[-96.8753,48.1732],[-96.8907,48.1732],[-96.8907,48.1732],[-96.8932,48.1732],[-96.9122,48.1733],[-96.9123,48.1733],[-96.933,48.1733],[-96.9339,48.1733],[-96.934,48.1733],[-96.9387,48.1732],[-96.9448,48.1732],[-96.9554,48.1731],[-96.9703,48.1731],[-96.9705,48.1731],[-96.9749,48.173],[-96.9751,48.173],[-96.9773,48.173],[-96.9773,48.173],[-96.9775,48.1731],[-96.9812,48.1731],[-96.9844,48.1731],[-96.9889,48.1731],[-96.99,48.1731],[-96.9959,48.1732],[-96.9975,48.1732],[-96.998,48.1732],[-96.9987,48.1732],[-96.9989,48.1732],[-96.999,48.1732],[-97.0003,48.1732],[-97.0203,48.1733],[-97.0205,48.1733],[-97.042,48.1732],[-97.042,48.1732],[-97.0637,48.1732],[-97.0637,48.1732],[-97.0853,48.1734],[-97.0855,48.1734],[-97.1069,48.1735],[-97.1071,48.1735],[-97.1253,48.1733],[-97.1257,48.1733],[-97.1286,48.1733],[-97.1322,48.1733],[-97.1376,48.1733],[-97.1462,48.1733],[-97.1467,48.1733],[-97.1452,48.1741],[-97.1434,48.1744],[-97.1417,48.1746],[-97.1389,48.1747],[-97.1371,48.1754],[-97.1365,48.1758],[-97.136,48.1768],[-97.1359,48.1789],[-97.1362,48.1796],[-97.1366,48.1809],[-97.1383,48.1824],[-97.1406,48.183],[-97.1413,48.1831],[-97.1432,48.1828],[-97.1455,48.1824],[-97.1467,48.1821],[-97.1484,48.1825],[-97.1498,48.1835],[-97.1497,48.1859],[-97.1491,48.1864],[-97.1475,48.1879],[-97.1449,48.1895],[-97.1429,48.191],[-97.1426,48.1913],[-97.1415,48.1926],[-97.1413,48.1934],[-97.1412,48.1937],[-97.141,48.194],[-97.1409,48.1945],[-97.1404,48.1947],[-97.1397,48.1951],[-97.1391,48.1953],[-97.1383,48.1955],[-97.1365,48.1963],[-97.1356,48.1972],[-97.1359,48.1984],[-97.1368,48.1996],[-97.1383,48.2006],[-97.1401,48.2018],[-97.1409,48.2027],[-97.1412,48.203],[-97.1411,48.204],[-97.1409,48.2046],[-97.14,48.2052],[-97.139,48.2059],[-97.1375,48.2063],[-97.1341,48.2068],[-97.1316,48.2072],[-97.1301,48.2077],[-97.1296,48.208],[-97.1295,48.208],[-97.1292,48.2084],[-97.1292,48.2099],[-97.1291,48.21],[-97.1296,48.2105],[-97.1297,48.2106],[-97.1299,48.2108],[-97.1307,48.211],[-97.1318,48.2112],[-97.1354,48.2116],[-97.1364,48.2119],[-97.1382,48.2131],[-97.1394,48.2144],[-97.1392,48.2168],[-97.1389,48.2171],[-97.1383,48.2174],[-97.1373,48.2177],[-97.1354,48.2179],[-97.1344,48.2178],[-97.1328,48.2176],[-97.1313,48.2172],[-97.1302,48.2164],[-97.1297,48.2161],[-97.1292,48.2158],[-97.1278,48.2145],[-97.1274,48.2134],[-97.1265,48.2113],[-97.126,48.2101],[-97.1259,48.2099],[-97.1257,48.2097],[-97.1253,48.2093],[-97.1245,48.208],[-97.1236,48.2077],[-97.1229,48.2074],[-97.1216,48.2074],[-97.1204,48.2073],[-97.1197,48.2076],[-97.1189,48.2079],[-97.1183,48.2086],[-97.118,48.2092],[-97.1178,48.2098],[-97.1179,48.2107],[-97.1181,48.2115],[-97.1189,48.2129],[-97.1194,48.2136],[-97.1208,48.215],[-97.122,48.2159],[-97.1228,48.2165],[-97.1248,48.2175],[-97.1253,48.2178],[-97.1272,48.2185],[-97.1289,48.2188],[-97.1297,48.219],[-97.1321,48.2196],[-97.135,48.2207],[-97.139,48.222],[-97.1406,48.2222],[-97.1417,48.2221],[-97.1436,48.2216],[-97.1448,48.2209],[-97.1455,48.2204],[-97.1457,48.2202],[-97.1458,48.2202],[-97.1462,48.2198],[-97.1471,48.2189],[-97.1482,48.2184],[-97.1497,48.2181],[-97.1509,48.2184],[-97.151,48.2185],[-97.1517,48.219],[-97.1521,48.2197],[-97.1521,48.2205],[-97.1517,48.2214],[-97.151,48.2222],[-97.1496,48.2232],[-97.1483,48.2238],[-97.1476,48.224],[-97.1465,48.2243],[-97.1436,48.2253],[-97.1408,48.2263],[-97.1385,48.2268],[-97.1371,48.227],[-97.1357,48.2271],[-97.1332,48.227],[-97.1317,48.2265],[-97.1305,48.2259],[-97.1298,48.2255],[-97.129,48.2251],[-97.1276,48.2245],[-97.1273,48.2243],[-97.1266,48.2239],[-97.1259,48.2236],[-97.1253,48.2234],[-97.1245,48.2232],[-97.1233,48.2231],[-97.1222,48.2234],[-97.1216,48.2236],[-97.121,48.2242],[-97.121,48.2242],[-97.1206,48.2248],[-97.1206,48.2254],[-97.1207,48.2259],[-97.1216,48.227],[-97.1225,48.2275],[-97.1234,48.2281],[-97.1244,48.2284],[-97.1253,48.2287],[-97.1278,48.2293],[-97.1299,48.2297],[-97.1303,48.2297],[-97.1325,48.2298],[-97.1351,48.2298],[-97.1393,48.2302],[-97.1423,48.231],[-97.1435,48.2318],[-97.1446,48.2336],[-97.1445,48.2343],[-97.1443,48.2351],[-97.143,48.2361],[-97.1416,48.2365],[-97.1411,48.2366],[-97.1399,48.2367],[-97.1377,48.2368],[-97.1358,48.237],[-97.1343,48.2378],[-97.1339,48.2382],[-97.1338,48.2386],[-97.1337,48.2391],[-97.1341,48.2397],[-97.1346,48.2403],[-97.1357,48.2409],[-97.1375,48.2414],[-97.1385,48.2415],[-97.1405,48.2415],[-97.1422,48.2412],[-97.1444,48.2412],[-97.1459,48.2417],[-97.147,48.2423],[-97.1471,48.243],[-97.1467,48.2445],[-97.146,48.2452],[-97.1444,48.2462],[-97.1431,48.2468],[-97.1404,48.2473],[-97.1389,48.2479],[-97.1377,48.2485],[-97.1355,48.2495],[-97.1345,48.2498],[-97.1334,48.2499],[-97.1305,48.2498],[-97.1299,48.2498],[-97.1291,48.2495],[-97.1274,48.2495],[-97.1263,48.2498],[-97.1253,48.25],[-97.1251,48.25],[-97.1247,48.2504],[-97.1244,48.2508],[-97.1243,48.2513],[-97.1243,48.252],[-97.1245,48.2526],[-97.1248,48.2532],[-97.1248,48.2532],[-97.1253,48.2537],[-97.1256,48.254],[-97.1262,48.2546],[-97.1267,48.2551],[-97.1274,48.2555],[-97.1291,48.2566],[-97.13,48.2573],[-97.1304,48.2576],[-97.1306,48.2581],[-97.1306,48.2587],[-97.1306,48.259],[-97.1303,48.2595],[-97.1298,48.2598],[-97.1292,48.2599],[-97.1283,48.26],[-97.1272,48.2601],[-97.1253,48.2601],[-97.1248,48.2602],[-97.1242,48.2604],[-97.1236,48.2607],[-97.1231,48.2612],[-97.1229,48.2617],[-97.123,48.2623],[-97.1234,48.2628],[-97.1237,48.2633],[-97.1241,48.2636],[-97.1246,48.2639],[-97.1253,48.2641],[-97.1262,48.2644],[-97.1285,48.2649],[-97.1303,48.2651],[-97.1305,48.2652],[-97.1333,48.2656],[-97.135,48.2659],[-97.136,48.2659],[-97.1375,48.2657],[-97.1395,48.2655],[-97.1406,48.2654],[-97.142,48.2654],[-97.1427,48.2656],[-97.1438,48.2658],[-97.1444,48.2663],[-97.1448,48.2668],[-97.145,48.2675],[-97.1451,48.2678],[-97.145,48.2688],[-97.1443,48.2698],[-97.1431,48.2705],[-97.1421,48.2709],[-97.1403,48.2712],[-97.1391,48.2713],[-97.1377,48.2713],[-97.1361,48.2711],[-97.1343,48.2707],[-97.1313,48.2701],[-97.1305,48.27],[-97.1298,48.2699],[-97.1288,48.2698],[-97.1272,48.2699],[-97.1265,48.2701],[-97.1253,48.2705],[-97.125,48.2707],[-97.1247,48.2709],[-97.124,48.2713],[-97.1238,48.2716],[-97.1237,48.2721],[-97.1237,48.2725],[-97.1239,48.2728],[-97.124,48.2733],[-97.1242,48.2737],[-97.1247,48.2743],[-97.1253,48.2751],[-97.1254,48.2753],[-97.1255,48.2755],[-97.1256,48.2758],[-97.1255,48.2761],[-97.1254,48.2762],[-97.1253,48.2764],[-97.1251,48.2767],[-97.1246,48.2769],[-97.124,48.277],[-97.1232,48.277],[-97.1224,48.2769],[-97.1213,48.2768],[-97.1206,48.2768],[-97.12,48.2769],[-97.1187,48.2774],[-97.1175,48.2781],[-97.117,48.2788],[-97.1165,48.2797],[-97.1166,48.2805],[-97.1166,48.2807],[-97.1167,48.2813],[-97.117,48.2821],[-97.1171,48.2824],[-97.1172,48.2826],[-97.1177,48.2835],[-97.1221,48.2901],[-97.1231,48.2909],[-97.1239,48.2913],[-97.1244,48.2915],[-97.1247,48.2917],[-97.1253,48.2919],[-97.1256,48.292],[-97.126,48.292],[-97.1265,48.292],[-97.1272,48.2919],[-97.128,48.2916],[-97.1285,48.2913],[-97.1295,48.2908],[-97.1303,48.2902],[-97.1305,48.2901],[-97.1314,48.2891],[-97.1322,48.2884],[-97.133,48.2879],[-97.1342,48.2874],[-97.1349,48.2872],[-97.1355,48.2871],[-97.1367,48.2873],[-97.1374,48.2877],[-97.1378,48.2879],[-97.1383,48.2887],[-97.1384,48.2894],[-97.1384,48.2898],[-97.1383,48.2903],[-97.138,48.2909],[-97.1373,48.2918],[-97.1368,48.2922],[-97.1364,48.2925],[-97.1355,48.2929],[-97.1344,48.2935],[-97.1335,48.2941],[-97.133,48.2946],[-97.1323,48.2953],[-97.1318,48.2959],[-97.1314,48.2963],[-97.131,48.2969],[-97.1306,48.2973],[-97.1305,48.2974],[-97.13,48.2979],[-97.1293,48.2984],[-97.1286,48.2987],[-97.1282,48.2989],[-97.1276,48.299],[-97.1271,48.2991],[-97.127,48.2991],[-97.1263,48.2991],[-97.1253,48.2989],[-97.125,48.2988],[-97.1246,48.2987],[-97.1241,48.2984],[-97.1234,48.2975],[-97.1228,48.2968],[-97.1227,48.2967],[-97.1213,48.2955],[-97.1203,48.2949],[-97.1192,48.2943],[-97.1167,48.294],[-97.1153,48.2939],[-97.1138,48.2943],[-97.1129,48.2949],[-97.1123,48.2954],[-97.1122,48.296],[-97.1122,48.2965],[-97.1123,48.2968],[-97.1126,48.2973],[-97.113,48.2978],[-97.1138,48.2984],[-97.1148,48.299],[-97.118,48.3004],[-97.12,48.3012],[-97.1227,48.3019],[-97.1241,48.3022],[-97.1247,48.3025],[-97.1253,48.3029],[-97.1255,48.303],[-97.1259,48.3033],[-97.1262,48.3036],[-97.1266,48.3041],[-97.1267,48.3046],[-97.1265,48.3055],[-97.1263,48.3059],[-97.1257,48.3064],[-97.1253,48.3067],[-97.1241,48.3073],[-97.123,48.3081],[-97.1222,48.3088],[-97.1221,48.3095],[-97.1222,48.3099],[-97.123,48.3105],[-97.1241,48.3112],[-97.1247,48.3115],[-97.1253,48.3119],[-97.1258,48.3119],[-97.1263,48.312],[-97.1269,48.312],[-97.1276,48.312],[-97.1282,48.3118],[-97.1289,48.3116],[-97.1298,48.3111],[-97.1299,48.3111],[-97.1303,48.3108],[-97.1304,48.3108],[-97.1311,48.3103],[-97.1318,48.3099],[-97.1325,48.3094],[-97.1331,48.3092],[-97.1336,48.309],[-97.1343,48.3089],[-97.1351,48.3089],[-97.1358,48.3089],[-97.1365,48.3091],[-97.1372,48.3094],[-97.1377,48.3098],[-97.1379,48.3102],[-97.1381,48.3106],[-97.138,48.3111],[-97.138,48.3116],[-97.1379,48.312],[-97.1376,48.3125],[-97.1372,48.3129],[-97.1367,48.3134],[-97.1361,48.3141],[-97.1356,48.3148],[-97.1351,48.3155],[-97.1348,48.316],[-97.1346,48.3166],[-97.1345,48.3171],[-97.1343,48.3177],[-97.134,48.3181],[-97.1335,48.3185],[-97.1329,48.3189],[-97.1325,48.3192],[-97.132,48.3194],[-97.1312,48.3196],[-97.1306,48.3196],[-97.1303,48.3196],[-97.1291,48.3196],[-97.1282,48.3195],[-97.1274,48.3195],[-97.1267,48.3195],[-97.1253,48.3196],[-97.1229,48.3201],[-97.1197,48.3208],[-97.1173,48.3216],[-97.1164,48.3222],[-97.1157,48.323],[-97.1155,48.3236],[-97.1155,48.324],[-97.1162,48.3248],[-97.1168,48.3253],[-97.1173,48.3258],[-97.1175,48.326],[-97.1187,48.3266],[-97.1203,48.3271],[-97.1222,48.3274],[-97.123,48.3275],[-97.1253,48.3277],[-97.1257,48.3277],[-97.1262,48.3278],[-97.1275,48.328],[-97.1292,48.3282],[-97.1303,48.3282],[-97.1311,48.3283],[-97.1317,48.3282],[-97.1326,48.3281],[-97.1337,48.3279],[-97.1343,48.3277],[-97.1345,48.3277],[-97.1353,48.3273],[-97.1359,48.327],[-97.1368,48.3263],[-97.1376,48.3257],[-97.138,48.3255],[-97.1385,48.3253],[-97.139,48.3251],[-97.1397,48.3251],[-97.1404,48.3252],[-97.141,48.3254],[-97.1415,48.3257],[-97.1417,48.3258],[-97.142,48.3262],[-97.1422,48.3267],[-97.1423,48.327],[-97.1422,48.3276],[-97.142,48.3281],[-97.1416,48.3287],[-97.1408,48.3294],[-97.14,48.3299],[-97.139,48.3304],[-97.1378,48.3309],[-97.1371,48.331],[-97.1361,48.3312],[-97.1347,48.3315],[-97.1325,48.3318],[-97.1311,48.3321],[-97.1305,48.3323],[-97.1295,48.3326],[-97.129,48.3329],[-97.1284,48.3336],[-97.1275,48.3352],[-97.1263,48.3379],[-97.1258,48.3384],[-97.1258,48.3398],[-97.1258,48.3402],[-97.1259,48.3406],[-97.1263,48.3415],[-97.1267,48.3422],[-97.1276,48.3427],[-97.1283,48.343],[-97.1297,48.3435],[-97.1308,48.3438],[-97.1309,48.3438],[-97.132,48.344],[-97.1334,48.3439],[-97.1354,48.3439],[-97.1372,48.344],[-97.1383,48.3441],[-97.1388,48.3441],[-97.1396,48.3443],[-97.14,48.3446],[-97.1405,48.345],[-97.1407,48.3453],[-97.1409,48.3456],[-97.141,48.3459],[-97.1408,48.3468],[-97.1405,48.3471],[-97.1396,48.3478],[-97.1386,48.3485],[-97.1376,48.3491],[-97.1368,48.3496],[-97.1362,48.3501],[-97.1361,48.3503],[-97.136,48.3505],[-97.136,48.3506],[-97.1359,48.351],[-97.1359,48.3511],[-97.136,48.3518],[-97.1362,48.3522],[-97.1363,48.3524],[-97.1365,48.3526],[-97.1373,48.3529],[-97.1382,48.3532],[-97.1387,48.3533],[-97.1398,48.3535],[-97.1405,48.3536],[-97.1415,48.3538],[-97.1423,48.354],[-97.143,48.3542],[-97.1435,48.3543],[-97.1438,48.3546],[-97.1441,48.3549],[-97.1442,48.3551],[-97.1443,48.3554],[-97.1445,48.356],[-97.1447,48.3565],[-97.145,48.3571],[-97.1453,48.3576],[-97.1459,48.3586],[-97.1464,48.3592],[-97.1468,48.3596],[-97.1477,48.3603],[-97.1484,48.3608],[-97.1501,48.3613],[-97.1517,48.362],[-97.1525,48.3623],[-97.1534,48.3628],[-97.1545,48.3633],[-97.1554,48.3638],[-97.1559,48.3646],[-97.1562,48.3656],[-97.1562,48.3662],[-97.156,48.3671],[-97.1558,48.3681],[-97.1555,48.3686],[-97.1554,48.3689],[-97.1552,48.3691],[-97.1548,48.37],[-97.1539,48.3704],[-97.1536,48.3705],[-97.1524,48.371],[-97.1523,48.371],[-97.1512,48.3713],[-97.1498,48.3712],[-97.1476,48.371],[-97.1437,48.3703],[-97.1433,48.3703],[-97.141,48.3702],[-97.1407,48.3703],[-97.1404,48.3703],[-97.1403,48.3703],[-97.1402,48.3703],[-97.1401,48.3703],[-97.1392,48.3705],[-97.1386,48.3708],[-97.1378,48.3713],[-97.1373,48.3718],[-97.1372,48.3724],[-97.1373,48.373],[-97.1376,48.3736],[-97.1383,48.3744],[-97.1389,48.375],[-97.1398,48.3759],[-97.1406,48.3769],[-97.1412,48.3777],[-97.1413,48.3785],[-97.1409,48.3793],[-97.1403,48.3797],[-97.1395,48.3801],[-97.1379,48.3803],[-97.1366,48.3804],[-97.1355,48.3805],[-97.1344,48.3808],[-97.1339,48.3811],[-97.1334,48.3818],[-97.1333,48.3822],[-97.1338,48.3828],[-97.1344,48.3833],[-97.1354,48.3838],[-97.1362,48.384],[-97.1374,48.3839],[-97.1389,48.3837],[-97.1406,48.3833],[-97.1431,48.3824],[-97.1446,48.3819],[-97.1454,48.3815],[-97.1463,48.3815],[-97.147,48.3814],[-97.1479,48.3817],[-97.149,48.3819],[-97.1505,48.3824],[-97.1509,48.3825],[-97.1519,48.3829],[-97.1532,48.3834],[-97.1538,48.3839],[-97.1548,48.3844],[-97.155,48.3846],[-97.156,48.3851],[-97.1572,48.3858],[-97.1576,48.3865],[-97.1577,48.3874],[-97.1571,48.3884],[-97.1565,48.3896],[-97.1563,48.3904],[-97.1567,48.3909],[-97.1576,48.3912],[-97.1586,48.3913],[-97.1596,48.3912],[-97.1608,48.3913],[-97.1617,48.3915],[-97.1627,48.3918],[-97.1632,48.392],[-97.1633,48.3929],[-97.1631,48.3937],[-97.1621,48.3948],[-97.1607,48.3956],[-97.1593,48.3961],[-97.1586,48.3964],[-97.1574,48.3965],[-97.1551,48.3968],[-97.1534,48.397],[-97.1519,48.3969],[-97.1505,48.3968],[-97.1499,48.3968],[-97.1481,48.3968],[-97.1467,48.3971],[-97.1456,48.3975],[-97.1445,48.3981],[-97.1434,48.3989],[-97.1434,48.399],[-97.1427,48.3996],[-97.1421,48.4004],[-97.1414,48.4013],[-97.1406,48.4019],[-97.1399,48.4025],[-97.1392,48.4029],[-97.1383,48.4033],[-97.1369,48.4038],[-97.1349,48.4046],[-97.1334,48.4053],[-97.1323,48.4059],[-97.1314,48.4066],[-97.1311,48.4073],[-97.131,48.4079],[-97.1312,48.409],[-97.1316,48.4096],[-97.1322,48.4104],[-97.1334,48.4112],[-97.1348,48.412],[-97.1362,48.4126],[-97.1373,48.4134],[-97.1375,48.4137],[-97.1376,48.4137],[-97.1379,48.4141],[-97.1384,48.4146],[-97.1388,48.4163],[-97.1388,48.4172],[-97.1393,48.4181],[-97.1398,48.4185],[-97.1406,48.4187],[-97.142,48.4186],[-97.1434,48.4181],[-97.1445,48.4173],[-97.1453,48.4159],[-97.1467,48.414],[-97.1472,48.4137],[-97.1478,48.4133],[-97.1489,48.4129],[-97.1505,48.4128],[-97.1508,48.4128],[-97.1521,48.4129],[-97.1532,48.4131],[-97.1543,48.4136],[-97.1543,48.4136],[-97.155,48.4143],[-97.1554,48.415],[-97.1554,48.4161],[-97.1554,48.4168],[-97.1548,48.4175],[-97.1539,48.4182],[-97.1527,48.4188],[-97.1509,48.4195],[-97.1507,48.4196],[-97.1489,48.4201],[-97.1466,48.4206],[-97.1443,48.4211],[-97.1421,48.4215],[-97.1403,48.4216],[-97.1383,48.4217],[-97.1367,48.4216],[-97.135,48.4213],[-97.1335,48.421],[-97.1325,48.4205],[-97.1312,48.4197],[-97.1301,48.4191],[-97.129,48.4181],[-97.1285,48.4177],[-97.1274,48.4168],[-97.1264,48.4164],[-97.126,48.4162],[-97.1253,48.4162],[-97.1244,48.4164],[-97.1236,48.4167],[-97.1232,48.417],[-97.1227,48.4176],[-97.1225,48.418],[-97.1224,48.4183],[-97.1223,48.4191],[-97.1223,48.4195],[-97.1225,48.42],[-97.1227,48.4204],[-97.1228,48.4207],[-97.1231,48.421],[-97.1233,48.4213],[-97.1241,48.4219],[-97.1246,48.4223],[-97.1249,48.4224],[-97.1253,48.4226],[-97.1268,48.4234],[-97.1286,48.4242],[-97.129,48.4243],[-97.1312,48.4251],[-97.1332,48.4258],[-97.1346,48.4262],[-97.1375,48.4264],[-97.139,48.4265],[-97.1406,48.427],[-97.1412,48.4272],[-97.1425,48.4277],[-97.1438,48.4285],[-97.1446,48.4291],[-97.1451,48.4298],[-97.1457,48.4303],[-97.1458,48.4312],[-97.1455,48.4322],[-97.1451,48.4326],[-97.144,48.4332],[-97.142,48.4337],[-97.1412,48.4338],[-97.1398,48.4337],[-97.1384,48.4336],[-97.1366,48.433],[-97.1344,48.4321],[-97.1332,48.4316],[-97.1315,48.4312],[-97.1305,48.4311],[-97.129,48.4311],[-97.1278,48.4313],[-97.1267,48.4319],[-97.1259,48.4325],[-97.1253,48.4329],[-97.1246,48.4337],[-97.1245,48.4341],[-97.1238,48.4355],[-97.1236,48.4361],[-97.1234,48.4371],[-97.1233,48.4376],[-97.1233,48.4383],[-97.1235,48.4389],[-97.1238,48.4399],[-97.124,48.4407],[-97.1243,48.4413],[-97.1245,48.4416],[-97.1248,48.4419],[-97.125,48.4421],[-97.1251,48.4422],[-97.1253,48.4423],[-97.1258,48.4427],[-97.1265,48.4432],[-97.128,48.4438],[-97.129,48.444],[-97.1295,48.4441],[-97.1314,48.4441],[-97.1328,48.4439],[-97.1345,48.4434],[-97.1355,48.4427],[-97.1363,48.4421],[-97.1365,48.4419],[-97.138,48.4405],[-97.1398,48.4392],[-97.141,48.4386],[-97.1428,48.4383],[-97.1451,48.4381],[-97.1464,48.4381],[-97.1477,48.4383],[-97.149,48.4389],[-97.1498,48.4392],[-97.1503,48.4397],[-97.1505,48.4403],[-97.1506,48.4409],[-97.1505,48.4413],[-97.1502,48.4419],[-97.1501,48.4422],[-97.1492,48.4434],[-97.1481,48.4441],[-97.1462,48.4448],[-97.1426,48.4459],[-97.1401,48.4467],[-97.1377,48.4477],[-97.1353,48.4489],[-97.1306,48.4523],[-97.1293,48.4541],[-97.1292,48.4564],[-97.1292,48.4566],[-97.1292,48.4569],[-97.1291,48.4575],[-97.1288,48.4585],[-97.1286,48.4596],[-97.1285,48.4604],[-97.1288,48.4616],[-97.1292,48.4622],[-97.1293,48.4624],[-97.1298,48.463],[-97.1306,48.4635],[-97.1319,48.4638],[-97.1334,48.4639],[-97.1347,48.4638],[-97.136,48.4635],[-97.138,48.463],[-97.1395,48.463],[-97.1407,48.463],[-97.142,48.4634],[-97.143,48.4639],[-97.1444,48.4649],[-97.1455,48.466],[-97.1463,48.4669],[-97.147,48.4677],[-97.1474,48.4684],[-97.148,48.47],[-97.1482,48.4708],[-97.148,48.4713],[-97.1477,48.4721],[-97.1474,48.4728],[-97.1465,48.4737],[-97.1461,48.4741],[-97.1445,48.4746],[-97.1432,48.4748],[-97.1419,48.4748],[-97.1407,48.4747],[-97.1393,48.4743],[-97.1379,48.4737],[-97.1368,48.4732],[-97.1352,48.4724],[-97.134,48.4718],[-97.1331,48.4715],[-97.1326,48.4714],[-97.1324,48.4713],[-97.1315,48.4712],[-97.1306,48.4713],[-97.1301,48.4714],[-97.1294,48.4715],[-97.1293,48.4717],[-97.1289,48.472],[-97.1283,48.4729],[-97.1281,48.4736],[-97.1281,48.4744],[-97.1285,48.4751],[-97.1289,48.4758],[-97.1293,48.4761],[-97.1297,48.4764],[-97.1308,48.4769],[-97.1324,48.4773],[-97.1346,48.4776],[-97.1364,48.4777],[-97.1384,48.4776],[-97.1406,48.4775],[-97.1419,48.4773],[-97.1433,48.4769],[-97.1448,48.4765],[-97.1461,48.4761],[-97.1477,48.4758],[-97.1493,48.4755],[-97.1509,48.4753],[-97.1511,48.4752],[-97.153,48.475],[-97.1549,48.475],[-97.1569,48.475],[-97.1585,48.4752],[-97.1599,48.4756],[-97.1609,48.4759],[-97.1616,48.4763],[-97.1622,48.477],[-97.1626,48.4778],[-97.1624,48.4786],[-97.1623,48.4792],[-97.1616,48.4799],[-97.1602,48.4807],[-97.1592,48.4812],[-97.1574,48.4816],[-97.1562,48.4818],[-97.1546,48.4821],[-97.1529,48.4822],[-97.1509,48.4824],[-97.1507,48.4824],[-97.1482,48.4828],[-97.1455,48.483],[-97.1437,48.4835],[-97.1424,48.4838],[-97.1411,48.4843],[-97.1402,48.4848],[-97.1396,48.4854],[-97.1394,48.486],[-97.1392,48.4864],[-97.1393,48.4873],[-97.1396,48.4881],[-97.1401,48.4887],[-97.1408,48.4892],[-97.1417,48.49],[-97.1428,48.4909],[-97.1433,48.4914],[-97.1433,48.492],[-97.143,48.4924],[-97.1423,48.4926],[-97.1415,48.4926],[-97.1406,48.4924],[-97.1399,48.492],[-97.139,48.4912],[-97.1382,48.4904],[-97.138,48.4897],[-97.1373,48.4889],[-97.1367,48.4884],[-97.136,48.4881],[-97.1351,48.4878],[-97.1344,48.4878],[-97.1332,48.4881],[-97.1322,48.4885],[-97.1315,48.4891],[-97.1312,48.4897],[-97.1311,48.4903],[-97.1311,48.4907],[-97.1316,48.4916],[-97.1322,48.4924],[-97.1334,48.4935],[-97.1345,48.4943],[-97.1367,48.4954],[-97.1388,48.496],[-97.1408,48.4967],[-97.1425,48.4972],[-97.1444,48.4976],[-97.1453,48.4979],[-97.1478,48.4995],[-97.148,48.4997],[-97.1483,48.5],[-97.1487,48.5004],[-97.1491,48.5009],[-97.1497,48.502],[-97.1499,48.5034],[-97.1498,48.5047],[-97.1498,48.5061],[-97.1495,48.5075],[-97.1495,48.5086],[-97.1497,48.5096],[-97.1502,48.5106],[-97.1502,48.5117],[-97.1499,48.512],[-97.1491,48.5124],[-97.1477,48.5124],[-97.142,48.5116],[-97.139,48.5117],[-97.1366,48.5123],[-97.1338,48.5139],[-97.1328,48.5146],[-97.1326,48.5148],[-97.1289,48.5173],[-97.1281,48.5178],[-97.127,48.519],[-97.1267,48.5202],[-97.1276,48.5215],[-97.1288,48.5222],[-97.129,48.5223],[-97.1307,48.5227],[-97.1339,48.5227],[-97.1366,48.5221],[-97.1385,48.5215],[-97.1395,48.521],[-97.1411,48.5202],[-97.1426,48.5195],[-97.1442,48.5191],[-97.1454,48.5188],[-97.1473,48.5188],[-97.1488,48.5189],[-97.1503,48.5194],[-97.1506,48.5195],[-97.1524,48.5204],[-97.154,48.5217],[-97.1547,48.5242],[-97.1549,48.5266],[-97.1544,48.5285],[-97.1536,48.5295],[-97.1536,48.5295],[-97.1527,48.5303],[-97.1513,48.5309],[-97.1507,48.5311],[-97.1499,48.5313],[-97.1482,48.5315],[-97.1458,48.5316],[-97.1438,48.5316],[-97.1422,48.5323],[-97.1411,48.5333],[-97.141,48.5343],[-97.1413,48.5355],[-97.1424,48.5366],[-97.144,48.5375],[-97.1456,48.5382],[-97.1481,48.5388],[-97.1505,48.5395],[-97.1508,48.5395],[-97.1533,48.5399],[-97.1558,48.5403],[-97.1582,48.5409],[-97.1596,48.5414],[-97.161,48.542],[-97.1614,48.5424],[-97.1631,48.5439],[-97.1631,48.544],[-97.1509,48.5439],[-97.1287,48.5439],[-97.107,48.544],[-97.0852,48.5441],[-97.0635,48.5441],[-97.0416,48.5442],[-97.0194,48.5441],[-96.9985,48.5441],[-96.9768,48.544],[-96.9551,48.5437],[-96.9331,48.5435],[-96.9138,48.5433],[-96.9115,48.5432],[-96.8896,48.5433],[-96.8678,48.5433],[-96.8459,48.5434],[-96.824,48.5436],[-96.8023,48.5436],[-96.7803,48.5435],[-96.7585,48.5436],[-96.7368,48.5437],[-96.7151,48.5437],[-96.6931,48.5437],[-96.6713,48.5436],[-96.6493,48.5437],[-96.6278,48.5437],[-96.6058,48.5437],[-96.5839,48.5437],[-96.5621,48.5436],[-96.54,48.5434],[-96.518,48.5434],[-96.4973,48.5434],[-96.4754,48.5435],[-96.4535,48.5436],[-96.4318,48.5438],[-96.4101,48.544],[-96.3882,48.5442]]],"type":"Polygon"},"id":"45","properties":{"Area":4698732287.54973,"CTYONLY_":6,"Code":"MARS","LASTMOD":"1984-01-12T14:12:49Z","Name":"Marshall","Perimiter":374207.65129},"type":"Feature"},{"geometry":{"coordinates":[[[-93.0884,48.6278],[-93.067,48.627],[-93.0456,48.6262],[-93.0237,48.6253],[-93.0021,48.6245],[-92.9845,48.6239],[-92.98,48.625],[-92.9641,48.6291],[-92.9585,48.6306],[-92.9547,48.6316],[-92.9497,48.6304],[-92.9498,48.6291],[-92.9499,48.6147],[-92.95,48.6084],[-92.9369,48.6075],[-92.9295,48.607],[-92.9177,48.6006],[-92.9151,48.5992],[-92.91,48.5964],[-92.8945,48.595],[-92.8932,48.5946],[-92.8729,48.5878],[-92.8652,48.5853],[-92.8515,48.5807],[-92.8301,48.5735],[-92.8206,48.5703],[-92.8079,48.5661],[-92.7863,48.5589],[-92.7767,48.5557],[-92.7665,48.5522],[-92.7439,48.5446],[-92.7354,48.5418],[-92.7284,48.5394],[-92.7227,48.54],[-92.7007,48.5421],[-92.7003,48.5421],[-92.6789,48.5442],[-92.6578,48.5463],[-92.6576,48.5462],[-92.6369,48.5429],[-92.6357,48.5427],[-92.6348,48.5426],[-92.6302,48.5284],[-92.6282,48.5223],[-92.6255,48.5179],[-92.6269,48.5142],[-92.6268,48.514],[-92.6264,48.5135],[-92.625,48.513],[-92.628,48.5108],[-92.6287,48.5106],[-92.6308,48.5092],[-92.6312,48.5082],[-92.6319,48.5068],[-92.6296,48.5058],[-92.627,48.5033],[-92.6306,48.5008],[-92.6351,48.4998],[-92.637,48.4994],[-92.6386,48.4996],[-92.64,48.4999],[-92.647,48.4999],[-92.654,48.5017],[-92.6569,48.4996],[-92.6582,48.4987],[-92.6614,48.4964],[-92.6789,48.4971],[-92.6857,48.4974],[-92.6986,48.4949],[-92.7011,48.4847],[-92.7016,48.4841],[-92.7092,48.4729],[-92.7085,48.4704],[-92.7089,48.4696],[-92.7126,48.463],[-92.7025,48.4551],[-92.7015,48.4543],[-92.6881,48.4438],[-92.6799,48.4425],[-92.6694,48.441],[-92.6635,48.4401],[-92.6586,48.4377],[-92.6562,48.4365],[-92.6371,48.4375],[-92.6157,48.4386],[-92.5935,48.4398],[-92.5765,48.4406],[-92.5717,48.4415],[-92.5686,48.4421],[-92.5499,48.4454],[-92.5369,48.4478],[-92.5284,48.448],[-92.515,48.4484],[-92.5074,48.448],[-92.507,48.4476],[-92.501,48.4422],[-92.4942,48.436],[-92.4893,48.4303],[-92.4849,48.4294],[-92.4837,48.4292],[-92.482,48.4283],[-92.4819,48.4279],[-92.4819,48.4276],[-92.4807,48.4264],[-92.481,48.4253],[-92.4788,48.4233],[-92.4754,48.4187],[-92.4631,48.4157],[-92.4564,48.4141],[-92.4564,48.4135],[-92.4563,48.4012],[-92.4602,48.3956],[-92.47,48.3813],[-92.4765,48.372],[-92.4747,48.3667],[-92.4697,48.3522],[-92.4697,48.3521],[-92.4591,48.3374],[-92.4558,48.3329],[-92.4523,48.3281],[-92.4476,48.3229],[-92.4415,48.3161],[-92.4413,48.3159],[-92.4405,48.3154],[-92.4403,48.3149],[-92.4386,48.3112],[-92.4367,48.309],[-92.4361,48.3085],[-92.4347,48.3074],[-92.4318,48.3052],[-92.4289,48.306],[-92.4256,48.3047],[-92.4204,48.299],[-92.4156,48.2951],[-92.415,48.2941],[-92.4135,48.2915],[-92.4065,48.2795],[-92.4017,48.2714],[-92.3967,48.2648],[-92.3931,48.2601],[-92.3927,48.259],[-92.3934,48.2576],[-92.3921,48.2568],[-92.3913,48.256],[-92.3891,48.2537],[-92.3901,48.2528],[-92.3912,48.2529],[-92.3922,48.2531],[-92.3926,48.2519],[-92.3923,48.2512],[-92.3912,48.2509],[-92.3907,48.2507],[-92.3897,48.2508],[-92.3887,48.2512],[-92.3867,48.2518],[-92.3858,48.2514],[-92.3853,48.2504],[-92.3852,48.2502],[-92.3846,48.2492],[-92.3868,48.2492],[-92.3863,48.2475],[-92.3878,48.247],[-92.3881,48.2465],[-92.3872,48.2444],[-92.3866,48.2441],[-92.3846,48.2449],[-92.3838,48.2446],[-92.3844,48.2425],[-92.3844,48.2414],[-92.384,48.2404],[-92.3833,48.2393],[-92.3816,48.2377],[-92.3806,48.2365],[-92.3789,48.2359],[-92.3789,48.2359],[-92.3785,48.2353],[-92.3791,48.2343],[-92.3781,48.233],[-92.3784,48.2321],[-92.3785,48.2312],[-92.3783,48.2304],[-92.3774,48.2293],[-92.3758,48.2283],[-92.3754,48.2275],[-92.3756,48.2267],[-92.3751,48.226],[-92.3743,48.2256],[-92.3734,48.225],[-92.3726,48.2236],[-92.3714,48.2241],[-92.3708,48.2239],[-92.3707,48.2228],[-92.3699,48.2218],[-92.3699,48.2212],[-92.3699,48.2203],[-92.3695,48.2203],[-92.3691,48.2202],[-92.368,48.2212],[-92.368,48.2212],[-92.3672,48.2217],[-92.3668,48.2223],[-92.3676,48.2232],[-92.3687,48.2237],[-92.368,48.2241],[-92.3662,48.224],[-92.365,48.2236],[-92.3636,48.2229],[-92.3621,48.2227],[-92.3616,48.2232],[-92.3613,48.224],[-92.361,48.2248],[-92.3603,48.2256],[-92.3586,48.2265],[-92.3566,48.2275],[-92.3555,48.2281],[-92.3544,48.2286],[-92.3537,48.2296],[-92.3535,48.2301],[-92.3517,48.2306],[-92.3494,48.2313],[-92.3484,48.2314],[-92.3477,48.2315],[-92.347,48.2315],[-92.3439,48.2321],[-92.3419,48.2317],[-92.3414,48.2319],[-92.3408,48.2337],[-92.3404,48.2341],[-92.3392,48.2347],[-92.339,48.2349],[-92.3386,48.2351],[-92.338,48.2351],[-92.3377,48.235],[-92.3371,48.2351],[-92.3365,48.2357],[-92.3362,48.2357],[-92.3346,48.2348],[-92.3344,48.2346],[-92.3344,48.2344],[-92.3343,48.2342],[-92.3338,48.2339],[-92.3333,48.2338],[-92.332,48.234],[-92.3308,48.2348],[-92.3302,48.2349],[-92.3292,48.2351],[-92.3281,48.2359],[-92.3274,48.2366],[-92.327,48.2369],[-92.3268,48.2368],[-92.3262,48.2366],[-92.3261,48.2366],[-92.3259,48.2367],[-92.3256,48.2369],[-92.3253,48.2371],[-92.3223,48.2373],[-92.3221,48.2373],[-92.3148,48.2406],[-92.3006,48.2422],[-92.2803,48.2444],[-92.2783,48.2451],[-92.2695,48.2482],[-92.2713,48.2519],[-92.2736,48.2566],[-92.2794,48.2596],[-92.2901,48.2651],[-92.291,48.2664],[-92.2945,48.2713],[-92.2931,48.276],[-92.2937,48.2767],[-92.2942,48.2766],[-92.2945,48.2764],[-92.2951,48.2763],[-92.2952,48.2763],[-92.2953,48.2765],[-92.2953,48.2767],[-92.2954,48.2769],[-92.2953,48.2771],[-92.2952,48.2772],[-92.2953,48.2773],[-92.2956,48.2773],[-92.2955,48.2776],[-92.2955,48.2777],[-92.2956,48.278],[-92.2972,48.2809],[-92.3014,48.2883],[-92.2987,48.2954],[-92.2945,48.3063],[-92.2987,48.3099],[-92.3018,48.3125],[-92.3061,48.3163],[-92.3044,48.3229],[-92.302,48.3232],[-92.2954,48.3239],[-92.2952,48.3246],[-92.2901,48.3392],[-92.2888,48.3429],[-92.2803,48.3468],[-92.2625,48.355],[-92.2588,48.3544],[-92.2364,48.3511],[-92.2216,48.3489],[-92.2197,48.3481],[-92.2191,48.3475],[-92.2189,48.3469],[-92.2181,48.3463],[-92.2169,48.345],[-92.2147,48.3452],[-92.2067,48.3457],[-92.2065,48.3473],[-92.2077,48.3479],[-92.2038,48.3519],[-92.195,48.3505],[-92.1945,48.3488],[-92.193,48.3488],[-92.1928,48.3488],[-92.1785,48.3519],[-92.179,48.3549],[-92.1791,48.3549],[-92.1774,48.3572],[-92.1709,48.3598],[-92.162,48.3634],[-92.1488,48.3652],[-92.1448,48.3657],[-92.1437,48.3561],[-92.1274,48.3556],[-92.106,48.355],[-92.0942,48.3546],[-92.0908,48.3545],[-92.0842,48.3538],[-92.0835,48.3538],[-92.0823,48.3547],[-92.0781,48.3581],[-92.067,48.3595],[-92.0625,48.3595],[-92.0552,48.3594],[-92.0525,48.3549],[-92.0488,48.3486],[-92.0458,48.3479],[-92.0451,48.3458],[-92.0478,48.3436],[-92.0475,48.3404],[-92.0469,48.3348],[-92.0404,48.3336],[-92.0376,48.3331],[-92.031,48.3261],[-92.0307,48.3257],[-92.0185,48.324],[-92.0119,48.323],[-92.0001,48.3211],[-92.0051,48.3118],[-92.0129,48.2975],[-92.0129,48.297],[-92.012,48.287],[-92.0087,48.2826],[-92.0072,48.2806],[-92.0066,48.2677],[-92.0065,48.2655],[-91.9949,48.262],[-91.9891,48.2603],[-91.9841,48.2531],[-91.9805,48.248],[-91.979,48.2475],[-91.9783,48.2474],[-91.9778,48.2474],[-91.9773,48.2472],[-91.9769,48.2468],[-91.977,48.2465],[-91.9772,48.2463],[-91.9773,48.2462],[-91.9775,48.246],[-91.9774,48.2457],[-91.9774,48.2456],[-91.9772,48.2455],[-91.9765,48.245],[-91.9756,48.2444],[-91.9744,48.2453],[-91.9743,48.2454],[-91.9742,48.2455],[-91.9738,48.2459],[-91.9736,48.2464],[-91.9735,48.2467],[-91.9726,48.247],[-91.9704,48.2479],[-91.97,48.2488],[-91.9706,48.249],[-91.9708,48.2494],[-91.9714,48.2499],[-91.9719,48.25],[-91.9724,48.2503],[-91.9724,48.2506],[-91.9723,48.251],[-91.9722,48.2513],[-91.9722,48.2518],[-91.9718,48.252],[-91.9718,48.2529],[-91.9714,48.2531],[-91.9709,48.253],[-91.9705,48.2531],[-91.9704,48.2534],[-91.9699,48.2538],[-91.959,48.2537],[-91.957,48.2524],[-91.9541,48.2523],[-91.954,48.2518],[-91.9541,48.2517],[-91.9541,48.2515],[-91.954,48.2495],[-91.9512,48.2479],[-91.948,48.246],[-91.9496,48.2446],[-91.9511,48.2444],[-91.9582,48.2439],[-91.957,48.2389],[-91.9573,48.2387],[-91.9597,48.2369],[-91.9583,48.2332],[-91.9524,48.2331],[-91.9512,48.2334],[-91.9507,48.2332],[-91.9451,48.2304],[-91.942,48.2304],[-91.9375,48.2343],[-91.9288,48.2359],[-91.9282,48.236],[-91.9211,48.2368],[-91.9167,48.2386],[-91.9148,48.239],[-91.9134,48.2389],[-91.9131,48.2385],[-91.9106,48.2382],[-91.9097,48.2384],[-91.9076,48.2384],[-91.9073,48.2383],[-91.907,48.2382],[-91.9065,48.2378],[-91.9058,48.2373],[-91.9023,48.2372],[-91.8931,48.238],[-91.885,48.2283],[-91.8843,48.2275],[-91.8769,48.2239],[-91.8675,48.2192],[-91.865,48.2095],[-91.8643,48.207],[-91.8634,48.2071],[-91.8453,48.2088],[-91.8417,48.2094],[-91.8416,48.2094],[-91.8359,48.2103],[-91.8326,48.2095],[-91.8325,48.2094],[-91.8325,48.2094],[-91.8325,48.2094],[-91.8325,48.2094],[-91.8199,48.2112],[-91.8154,48.2119],[-91.8144,48.2094],[-91.8141,48.2084],[-91.8094,48.2063],[-91.7982,48.203],[-91.7983,48.1953],[-91.7982,48.1808],[-91.7984,48.1662],[-91.7983,48.1515],[-91.7981,48.1369],[-91.798,48.1224],[-91.7987,48.1079],[-91.7992,48.0936],[-91.7997,48.0788],[-91.8001,48.0643],[-91.8,48.0496],[-91.8,48.0353],[-91.8,48.0206],[-91.8001,48.0059],[-91.7996,47.9914],[-91.7992,47.977],[-91.7985,47.9625],[-91.7979,47.9481],[-91.7977,47.9334],[-91.7978,47.9189],[-91.7979,47.9045],[-91.7979,47.8899],[-91.7983,47.8771],[-91.7983,47.876],[-91.7988,47.8618],[-91.7992,47.8464],[-91.8,47.8319],[-91.8,47.8175],[-91.7999,47.8031],[-91.7997,47.7916],[-91.7997,47.7893],[-91.7997,47.7886],[-91.7995,47.7774],[-91.7995,47.776],[-91.7995,47.7742],[-91.7995,47.7723],[-91.7992,47.7626],[-91.7992,47.7598],[-91.7992,47.7538],[-91.7993,47.7482],[-91.7993,47.7454],[-91.7992,47.7388],[-91.7992,47.7339],[-91.799,47.731],[-91.7984,47.7201],[-91.7982,47.717],[-91.7981,47.7165],[-91.7977,47.7128],[-91.7971,47.707],[-91.7967,47.7024],[-91.7959,47.6925],[-91.7959,47.688],[-91.7955,47.678],[-91.7955,47.6778],[-91.7955,47.6733],[-91.7954,47.6729],[-91.795,47.663],[-91.7948,47.6586],[-91.7942,47.6486],[-91.794,47.6449],[-91.794,47.6442],[-91.7933,47.6345],[-91.793,47.6299],[-91.7923,47.6212],[-91.7922,47.6193],[-91.7919,47.6155],[-91.7915,47.6091],[-91.7913,47.6049],[-91.7912,47.6021],[-91.7911,47.6008],[-91.7908,47.5904],[-91.7905,47.5874],[-91.7904,47.5864],[-91.7893,47.576],[-91.7892,47.5749],[-91.789,47.5719],[-91.7888,47.5614],[-91.7887,47.5588],[-91.7886,47.5574],[-91.7878,47.5469],[-91.788,47.5431],[-91.788,47.5424],[-91.7886,47.533],[-91.7886,47.5322],[-91.7889,47.5187],[-91.7889,47.5176],[-91.789,47.5067],[-91.7891,47.5041],[-91.7891,47.503],[-91.7894,47.493],[-91.7894,47.4897],[-91.7894,47.4886],[-91.7895,47.4753],[-91.7895,47.4741],[-91.7895,47.4605],[-91.7895,47.4574],[-91.7893,47.4449],[-91.7894,47.4303],[-91.7895,47.416],[-91.7896,47.4017],[-91.7904,47.3872],[-91.7906,47.3726],[-91.792,47.3726],[-91.792,47.3576],[-91.792,47.3432],[-91.7918,47.3288],[-91.7918,47.3145],[-91.7919,47.3],[-91.792,47.2855],[-91.7921,47.271],[-91.7922,47.2565],[-91.7923,47.2422],[-91.7923,47.2276],[-91.7923,47.2128],[-91.7922,47.1985],[-91.7923,47.1843],[-91.7923,47.1698],[-91.7923,47.1556],[-91.7923,47.1411],[-91.7924,47.1265],[-91.7922,47.1119],[-91.7943,47.1119],[-91.7945,47.0976],[-91.7945,47.0831],[-91.7944,47.0688],[-91.7944,47.0541],[-91.7943,47.0399],[-91.7943,47.0255],[-91.7944,47.0109],[-91.7944,46.9965],[-91.7944,46.9818],[-91.7944,46.9675],[-91.7943,46.953],[-91.7944,46.9397],[-91.7945,46.9397],[-91.7947,46.9396],[-91.7948,46.9395],[-91.795,46.9394],[-91.7951,46.9394],[-91.7952,46.9394],[-91.7953,46.9393],[-91.7954,46.9391],[-91.7955,46.939],[-91.7957,46.9388],[-91.7957,46.9386],[-91.7958,46.9384],[-91.7958,46.9384],[-91.7959,46.9383],[-91.796,46.9382],[-91.7961,46.9381],[-91.7964,46.938],[-91.7966,46.9379],[-91.797,46.9379],[-91.7971,46.9378],[-91.7974,46.9378],[-91.7975,46.9378],[-91.7978,46.9378],[-91.798,46.9379],[-91.7981,46.938],[-91.7983,46.938],[-91.7986,46.9379],[-91.7989,46.9379],[-91.7991,46.9379],[-91.7993,46.9379],[-91.7995,46.9378],[-91.7996,46.9377],[-91.7998,46.9376],[-91.8004,46.9373],[-91.8007,46.9371],[-91.8011,46.9369],[-91.8013,46.9368],[-91.8016,46.9367],[-91.802,46.9366],[-91.8022,46.9365],[-91.8025,46.9364],[-91.8028,46.9363],[-91.8032,46.9361],[-91.8034,46.936],[-91.8036,46.9359],[-91.8037,46.9357],[-91.804,46.9356],[-91.8042,46.9354],[-91.8044,46.9352],[-91.8046,46.935],[-91.8048,46.9349],[-91.805,46.9347],[-91.8051,46.9346],[-91.8053,46.9345],[-91.8055,46.9345],[-91.8057,46.9344],[-91.8059,46.9343],[-91.806,46.9343],[-91.8062,46.9342],[-91.8064,46.9341],[-91.8066,46.9338],[-91.8067,46.9336],[-91.8069,46.9334],[-91.807,46.9332],[-91.8071,46.9331],[-91.8071,46.933],[-91.8072,46.9329],[-91.8073,46.9328],[-91.8075,46.9328],[-91.8076,46.9327],[-91.8078,46.9327],[-91.808,46.9327],[-91.8082,46.9325],[-91.8084,46.9324],[-91.8087,46.9322],[-91.8089,46.932],[-91.8091,46.9319],[-91.8094,46.9317],[-91.8097,46.9315],[-91.81,46.9314],[-91.8103,46.9312],[-91.8106,46.9311],[-91.8107,46.931],[-91.8109,46.9309],[-91.811,46.9309],[-91.8112,46.9309],[-91.8113,46.9308],[-91.8116,46.9306],[-91.8117,46.9305],[-91.8119,46.9303],[-91.812,46.9301],[-91.8121,46.9299],[-91.8122,46.9298],[-91.8123,46.9296],[-91.8123,46.9293],[-91.8124,46.9291],[-91.8124,46.929],[-91.8125,46.9288],[-91.8126,46.9287],[-91.813,46.9281],[-91.8133,46.9277],[-91.8135,46.9275],[-91.8137,46.9272],[-91.8138,46.9271],[-91.8139,46.927],[-91.8141,46.9268],[-91.8142,46.9267],[-91.8144,46.9267],[-91.8147,46.9266],[-91.8149,46.9265],[-91.815,46.9263],[-91.8151,46.9263],[-91.8152,46.9262],[-91.8153,46.926],[-91.8154,46.9259],[-91.8154,46.9258],[-91.8155,46.9258],[-91.8157,46.9256],[-91.8159,46.9252],[-91.8162,46.925],[-91.8163,46.9248],[-91.8165,46.9247],[-91.8166,46.9246],[-91.8168,46.9244],[-91.817,46.9243],[-91.8171,46.9243],[-91.8173,46.9242],[-91.8175,46.9241],[-91.8177,46.924],[-91.8179,46.924],[-91.8182,46.9241],[-91.8184,46.9242],[-91.8186,46.9244],[-91.8187,46.9245],[-91.8189,46.9246],[-91.819,46.9246],[-91.8192,46.9247],[-91.8194,46.9248],[-91.8196,46.9248],[-91.8198,46.9248],[-91.8202,46.9248],[-91.8204,46.9248],[-91.8206,46.9248],[-91.8208,46.9249],[-91.821,46.925],[-91.822,46.9252],[-91.8222,46.9253],[-91.8224,46.9253],[-91.8227,46.9254],[-91.8232,46.9256],[-91.8234,46.9257],[-91.8237,46.9259],[-91.8238,46.926],[-91.824,46.9261],[-91.8241,46.9262],[-91.8242,46.9262],[-91.8243,46.9263],[-91.8243,46.9264],[-91.8245,46.9265],[-91.8252,46.9267],[-91.8255,46.9269],[-91.8256,46.9269],[-91.8258,46.927],[-91.8259,46.9272],[-91.826,46.9272],[-91.826,46.9273],[-91.8265,46.9274],[-91.8267,46.9274],[-91.827,46.9275],[-91.8274,46.9275],[-91.8277,46.9275],[-91.828,46.9275],[-91.8283,46.9275],[-91.8286,46.9275],[-91.8289,46.9275],[-91.8292,46.9275],[-91.8295,46.9275],[-91.83,46.9275],[-91.8303,46.9275],[-91.8307,46.9275],[-91.831,46.9275],[-91.8314,46.9274],[-91.8318,46.9274],[-91.8321,46.9274],[-91.8325,46.9274],[-91.8327,46.9273],[-91.833,46.9273],[-91.8332,46.9273],[-91.8335,46.9272],[-91.8337,46.9272],[-91.8342,46.9269],[-91.8345,46.9268],[-91.8347,46.9267],[-91.8348,46.9267],[-91.8348,46.9266],[-91.8349,46.9266],[-91.835,46.9266],[-91.835,46.9267],[-91.8348,46.9268],[-91.8348,46.9269],[-91.8347,46.927],[-91.8347,46.9271],[-91.8346,46.9272],[-91.8348,46.9272],[-91.8351,46.9271],[-91.8352,46.927],[-91.8355,46.9269],[-91.8357,46.9269],[-91.8359,46.9268],[-91.8361,46.9268],[-91.8363,46.9268],[-91.8365,46.9267],[-91.8365,46.9267],[-91.8367,46.9266],[-91.8368,46.9266],[-91.8369,46.9265],[-91.8371,46.9265],[-91.8374,46.9265],[-91.8376,46.9265],[-91.8377,46.9265],[-91.8379,46.9264],[-91.8381,46.9263],[-91.8383,46.9262],[-91.8386,46.9261],[-91.8389,46.9261],[-91.8391,46.926],[-91.8393,46.9259],[-91.8396,46.9258],[-91.8398,46.9257],[-91.8401,46.9256],[-91.8405,46.9255],[-91.8407,46.9254],[-91.841,46.9253],[-91.8413,46.9253],[-91.8415,46.9252],[-91.8417,46.9251],[-91.8418,46.9251],[-91.8424,46.9248],[-91.8426,46.9246],[-91.8431,46.9244],[-91.8432,46.9243],[-91.8435,46.9242],[-91.8441,46.9239],[-91.8446,46.9238],[-91.8449,46.9236],[-91.8454,46.9234],[-91.8457,46.9233],[-91.8458,46.9232],[-91.8461,46.923],[-91.8464,46.9229],[-91.8466,46.9226],[-91.847,46.9224],[-91.8472,46.9223],[-91.8474,46.9221],[-91.8475,46.922],[-91.8476,46.9219],[-91.8477,46.9219],[-91.8478,46.9218],[-91.8481,46.9216],[-91.8484,46.9215],[-91.8486,46.9213],[-91.8488,46.9211],[-91.8491,46.9209],[-91.8493,46.9208],[-91.8495,46.9207],[-91.8497,46.9204],[-91.8499,46.9203],[-91.8501,46.9201],[-91.8502,46.9199],[-91.8504,46.9198],[-91.8505,46.9197],[-91.8506,46.9197],[-91.8511,46.9193],[-91.8512,46.9192],[-91.8513,46.919],[-91.8514,46.9188],[-91.8517,46.9185],[-91.8519,46.9182],[-91.8521,46.9179],[-91.8524,46.9175],[-91.8526,46.9171],[-91.8528,46.9168],[-91.8531,46.9165],[-91.8533,46.9162],[-91.8535,46.9158],[-91.8536,46.9156],[-91.8538,46.9155],[-91.854,46.9153],[-91.8542,46.9151],[-91.8544,46.915],[-91.8546,46.9148],[-91.8548,46.9146],[-91.855,46.9144],[-91.8551,46.9143],[-91.8552,46.9142],[-91.8553,46.9141],[-91.8555,46.9139],[-91.8557,46.9137],[-91.8559,46.9136],[-91.8562,46.9136],[-91.8565,46.9134],[-91.8568,46.9132],[-91.8569,46.9131],[-91.857,46.9131],[-91.8571,46.913],[-91.8572,46.9129],[-91.8576,46.9127],[-91.8579,46.9126],[-91.8581,46.9126],[-91.8583,46.9126],[-91.8584,46.9126],[-91.8585,46.9124],[-91.8588,46.9122],[-91.8591,46.912],[-91.8596,46.9116],[-91.8599,46.9115],[-91.8602,46.9114],[-91.8603,46.9113],[-91.8605,46.9112],[-91.8607,46.911],[-91.8609,46.9109],[-91.861,46.9108],[-91.8612,46.9107],[-91.8613,46.9106],[-91.8614,46.9105],[-91.8615,46.9104],[-91.8617,46.9103],[-91.8619,46.9102],[-91.8625,46.9101],[-91.863,46.91],[-91.8633,46.91],[-91.8635,46.9099],[-91.8637,46.9099],[-91.8639,46.9097],[-91.8642,46.9096],[-91.8644,46.9095],[-91.8644,46.9095],[-91.8646,46.9094],[-91.8648,46.9093],[-91.865,46.9092],[-91.8652,46.909],[-91.8654,46.9089],[-91.8656,46.9089],[-91.8659,46.9088],[-91.8662,46.9087],[-91.8664,46.9087],[-91.8666,46.9086],[-91.8668,46.9086],[-91.8675,46.9084],[-91.8679,46.9084],[-91.8681,46.9085],[-91.8684,46.9085],[-91.8686,46.9085],[-91.8688,46.9085],[-91.8691,46.9085],[-91.8693,46.9085],[-91.8705,46.9084],[-91.8709,46.9084],[-91.8711,46.9084],[-91.8714,46.9083],[-91.8717,46.9083],[-91.8724,46.9082],[-91.8734,46.9081],[-91.874,46.9081],[-91.8745,46.908],[-91.8749,46.908],[-91.8751,46.908],[-91.8755,46.9078],[-91.8758,46.9075],[-91.8761,46.9074],[-91.8764,46.9073],[-91.8766,46.9073],[-91.8768,46.9072],[-91.8772,46.9072],[-91.8775,46.9072],[-91.878,46.9071],[-91.8782,46.9071],[-91.879,46.9067],[-91.8797,46.9064],[-91.8802,46.9062],[-91.8807,46.906],[-91.8811,46.9058],[-91.8829,46.9047],[-91.885,46.9037],[-91.8854,46.9035],[-91.8856,46.9033],[-91.8858,46.9032],[-91.8859,46.903],[-91.8861,46.9029],[-91.8861,46.9028],[-91.8864,46.9027],[-91.8866,46.9026],[-91.8868,46.9025],[-91.8873,46.9021],[-91.8875,46.9019],[-91.8882,46.9015],[-91.8885,46.9015],[-91.8887,46.9015],[-91.8889,46.9015],[-91.8892,46.9014],[-91.8905,46.9005],[-91.891,46.9001],[-91.8912,46.8998],[-91.8915,46.8996],[-91.8918,46.8994],[-91.892,46.8994],[-91.8933,46.8987],[-91.8947,46.8979],[-91.895,46.8977],[-91.8953,46.8975],[-91.8955,46.8973],[-91.8956,46.8971],[-91.8957,46.8969],[-91.8961,46.8966],[-91.8971,46.8959],[-91.8976,46.8955],[-91.8981,46.8952],[-91.8986,46.895],[-91.8987,46.895],[-91.899,46.8949],[-91.8992,46.8948],[-91.8994,46.8947],[-91.9004,46.894],[-91.9009,46.8937],[-91.901,46.8935],[-91.9013,46.8933],[-91.9026,46.8928],[-91.9029,46.8926],[-91.9031,46.8925],[-91.9034,46.8923],[-91.9037,46.892],[-91.9038,46.892],[-91.904,46.892],[-91.9043,46.8917],[-91.9045,46.8915],[-91.9049,46.8912],[-91.9053,46.8909],[-91.9057,46.8906],[-91.9066,46.89],[-91.9069,46.8896],[-91.907,46.8894],[-91.9081,46.8887],[-91.9086,46.8881],[-91.9088,46.8879],[-91.909,46.8876],[-91.9093,46.8873],[-91.9098,46.8867],[-91.9102,46.8864],[-91.9106,46.8862],[-91.9108,46.8862],[-91.9109,46.886],[-91.911,46.8859],[-91.911,46.8858],[-91.9111,46.8857],[-91.9112,46.8856],[-91.9113,46.8855],[-91.9115,46.8852],[-91.9116,46.885],[-91.9118,46.8848],[-91.9122,46.8845],[-91.913,46.8839],[-91.9134,46.8837],[-91.9137,46.8836],[-91.9139,46.8836],[-91.9142,46.8836],[-91.9141,46.8835],[-91.9142,46.8834],[-91.9143,46.8833],[-91.9145,46.8832],[-91.9147,46.8831],[-91.915,46.883],[-91.9153,46.8829],[-91.9156,46.8827],[-91.9159,46.8826],[-91.9161,46.8824],[-91.9169,46.882],[-91.9173,46.8818],[-91.9178,46.8816],[-91.9191,46.8812],[-91.9194,46.8811],[-91.9197,46.881],[-91.9199,46.8808],[-91.9201,46.8807],[-91.9204,46.8805],[-91.9205,46.8805],[-91.9209,46.8804],[-91.9214,46.8803],[-91.9226,46.8799],[-91.923,46.8797],[-91.9235,46.8796],[-91.9244,46.8792],[-91.9256,46.8788],[-91.926,46.8786],[-91.9263,46.8786],[-91.9268,46.8784],[-91.9276,46.8781],[-91.928,46.878],[-91.9284,46.8777],[-91.9297,46.8771],[-91.9301,46.8769],[-91.9305,46.8767],[-91.9309,46.8764],[-91.9312,46.8762],[-91.9315,46.8761],[-91.9316,46.876],[-91.9317,46.8759],[-91.9318,46.8758],[-91.9319,46.8758],[-91.932,46.8757],[-91.9321,46.8755],[-91.9322,46.8755],[-91.9324,46.8754],[-91.9326,46.8753],[-91.9329,46.8752],[-91.9332,46.8752],[-91.9335,46.8751],[-91.9337,46.8751],[-91.9339,46.875],[-91.934,46.8749],[-91.9341,46.8748],[-91.9343,46.8746],[-91.9345,46.8744],[-91.9346,46.8743],[-91.9349,46.874],[-91.9353,46.8738],[-91.9358,46.8737],[-91.9362,46.8736],[-91.9368,46.8735],[-91.9374,46.8734],[-91.938,46.8734],[-91.9386,46.8732],[-91.9391,46.873],[-91.9397,46.8727],[-91.9403,46.8723],[-91.9408,46.8721],[-91.941,46.8719],[-91.9411,46.8717],[-91.9413,46.8717],[-91.9415,46.8718],[-91.9416,46.8717],[-91.9417,46.8717],[-91.9419,46.8715],[-91.942,46.8712],[-91.9422,46.871],[-91.9424,46.8709],[-91.9428,46.8708],[-91.943,46.8708],[-91.9432,46.8706],[-91.9435,46.8704],[-91.9438,46.8704],[-91.9444,46.8702],[-91.9449,46.8699],[-91.9456,46.8696],[-91.9465,46.8694],[-91.9475,46.8691],[-91.9484,46.8688],[-91.9492,46.8685],[-91.9496,46.8682],[-91.9499,46.8679],[-91.9502,46.8678],[-91.9507,46.8677],[-91.9513,46.8675],[-91.952,46.8671],[-91.9524,46.8668],[-91.9527,46.8665],[-91.953,46.8662],[-91.9535,46.8659],[-91.9536,46.8658],[-91.9545,46.8654],[-91.9552,46.8651],[-91.956,46.8645],[-91.9565,46.8641],[-91.9568,46.8638],[-91.957,46.8636],[-91.9574,46.8633],[-91.9577,46.8631],[-91.9581,46.8628],[-91.9587,46.8623],[-91.959,46.8619],[-91.9593,46.8617],[-91.9596,46.8616],[-91.96,46.8614],[-91.9604,46.8612],[-91.9608,46.8609],[-91.9611,46.8605],[-91.9615,46.8602],[-91.9621,46.86],[-91.9627,46.8597],[-91.963,46.8596],[-91.9633,46.8595],[-91.964,46.8592],[-91.9646,46.8589],[-91.965,46.8586],[-91.9654,46.8582],[-91.9657,46.858],[-91.966,46.8579],[-91.9663,46.8578],[-91.9667,46.8576],[-91.9669,46.8576],[-91.967,46.8575],[-91.9671,46.8574],[-91.9672,46.8573],[-91.9673,46.8571],[-91.9675,46.857],[-91.9677,46.857],[-91.9679,46.8571],[-91.9681,46.857],[-91.9683,46.8569],[-91.9686,46.8568],[-91.9688,46.8567],[-91.9692,46.8565],[-91.9695,46.8564],[-91.97,46.8563],[-91.9704,46.8563],[-91.9708,46.8562],[-91.9711,46.8561],[-91.9714,46.8562],[-91.9716,46.8561],[-91.972,46.8559],[-91.9724,46.8558],[-91.9728,46.8558],[-91.9731,46.8559],[-91.9732,46.8558],[-91.9734,46.8557],[-91.9736,46.8556],[-91.974,46.8555],[-91.9741,46.8554],[-91.9742,46.8553],[-91.9745,46.8552],[-91.9748,46.8551],[-91.9751,46.8549],[-91.9754,46.8547],[-91.9755,46.8548],[-91.9757,46.8548],[-91.9762,46.8546],[-91.9764,46.8545],[-91.9767,46.8542],[-91.977,46.8539],[-91.9772,46.8537],[-91.9773,46.8534],[-91.9775,46.8533],[-91.9777,46.8533],[-91.978,46.8532],[-91.9784,46.853],[-91.9787,46.8529],[-91.9791,46.8526],[-91.9792,46.8525],[-91.9795,46.8524],[-91.9797,46.8523],[-91.98,46.8521],[-91.9802,46.8519],[-91.9805,46.8517],[-91.9808,46.8516],[-91.9811,46.8515],[-91.9815,46.8515],[-91.9819,46.8513],[-91.982,46.8513],[-91.9827,46.851],[-91.983,46.8508],[-91.9833,46.8506],[-91.9836,46.8504],[-91.9838,46.8503],[-91.9841,46.8503],[-91.9842,46.8502],[-91.9845,46.8501],[-91.9849,46.8499],[-91.9854,46.8496],[-91.9856,46.8495],[-91.9857,46.8493],[-91.9858,46.8491],[-91.986,46.8489],[-91.9861,46.8487],[-91.9863,46.8484],[-91.9866,46.8482],[-91.9869,46.848],[-91.987,46.8478],[-91.9871,46.8476],[-91.9875,46.8476],[-91.9877,46.8474],[-91.9881,46.8471],[-91.9884,46.8469],[-91.9885,46.8467],[-91.9885,46.8465],[-91.9887,46.8462],[-91.9889,46.846],[-91.9892,46.8458],[-91.9895,46.8456],[-91.9898,46.8455],[-91.9901,46.8454],[-91.9903,46.8451],[-91.9906,46.845],[-91.9908,46.8448],[-91.991,46.8446],[-91.9913,46.8443],[-91.9915,46.844],[-91.9918,46.8437],[-91.992,46.8434],[-91.9923,46.8431],[-91.9926,46.8427],[-91.9928,46.8424],[-91.9931,46.8422],[-91.9934,46.8421],[-91.9938,46.842],[-91.9941,46.8419],[-91.9944,46.8417],[-91.9949,46.8414],[-91.9954,46.8411],[-91.9959,46.8409],[-91.9964,46.8407],[-91.9969,46.8405],[-91.9973,46.8403],[-91.9978,46.84],[-91.9981,46.8397],[-91.9983,46.8395],[-91.9983,46.8392],[-91.9985,46.839],[-91.9986,46.8389],[-91.999,46.8387],[-91.9992,46.8386],[-91.9997,46.8384],[-92.0001,46.8381],[-92.0002,46.8381],[-92.0003,46.8382],[-92.0005,46.8381],[-92.0007,46.838],[-92.0009,46.838],[-92.0012,46.8379],[-92.0014,46.8377],[-92.0016,46.8375],[-92.0019,46.8374],[-92.0022,46.8373],[-92.0025,46.8373],[-92.003,46.8372],[-92.0033,46.8372],[-92.0036,46.8372],[-92.0039,46.8372],[-92.0041,46.8371],[-92.0042,46.837],[-92.0044,46.8369],[-92.0045,46.8369],[-92.0048,46.8367],[-92.0051,46.8366],[-92.0055,46.8366],[-92.0055,46.8366],[-92.0058,46.8364],[-92.0059,46.8363],[-92.0059,46.8362],[-92.0059,46.8361],[-92.006,46.8361],[-92.0061,46.836],[-92.0062,46.8359],[-92.0064,46.8359],[-92.0068,46.8358],[-92.007,46.8358],[-92.0072,46.8358],[-92.0074,46.8358],[-92.0078,46.8357],[-92.008,46.8357],[-92.0083,46.8357],[-92.0086,46.8356],[-92.0088,46.8356],[-92.009,46.8356],[-92.0093,46.8356],[-92.0096,46.8356],[-92.0101,46.8355],[-92.0105,46.8354],[-92.0106,46.8354],[-92.0109,46.8353],[-92.0112,46.8352],[-92.0115,46.8351],[-92.0117,46.8351],[-92.0118,46.835],[-92.012,46.835],[-92.0125,46.8348],[-92.0126,46.8348],[-92.0128,46.8346],[-92.013,46.8345],[-92.0132,46.8344],[-92.0134,46.8343],[-92.0136,46.8342],[-92.0137,46.8342],[-92.0139,46.834],[-92.0141,46.8338],[-92.0143,46.8338],[-92.0143,46.8337],[-92.0145,46.8336],[-92.0147,46.8336],[-92.0149,46.8336],[-92.0152,46.8336],[-92.0156,46.8336],[-92.016,46.8335],[-92.0165,46.8334],[-92.0169,46.8334],[-92.0172,46.8333],[-92.0177,46.8331],[-92.018,46.833],[-92.0184,46.8327],[-92.0185,46.8326],[-92.0187,46.8324],[-92.0189,46.8322],[-92.019,46.8321],[-92.0192,46.8319],[-92.0193,46.8318],[-92.0193,46.8317],[-92.0194,46.8317],[-92.0196,46.8316],[-92.0198,46.8316],[-92.0201,46.8315],[-92.0206,46.8314],[-92.0209,46.8313],[-92.0213,46.8312],[-92.0214,46.8311],[-92.0218,46.8309],[-92.0221,46.8307],[-92.0225,46.8305],[-92.023,46.8302],[-92.0234,46.83],[-92.0236,46.8298],[-92.0238,46.8296],[-92.024,46.8295],[-92.0241,46.8294],[-92.0243,46.8293],[-92.0245,46.8292],[-92.0247,46.8291],[-92.0249,46.8291],[-92.025,46.829],[-92.0252,46.8289],[-92.0253,46.8288],[-92.0255,46.8286],[-92.0256,46.8284],[-92.0257,46.8283],[-92.0259,46.8282],[-92.0261,46.828],[-92.0263,46.8277],[-92.0264,46.8276],[-92.0266,46.8274],[-92.0267,46.8272],[-92.0267,46.8271],[-92.0268,46.827],[-92.0268,46.827],[-92.0268,46.8269],[-92.0269,46.8268],[-92.027,46.8267],[-92.0272,46.8266],[-92.0272,46.8266],[-92.0274,46.8265],[-92.0275,46.8265],[-92.0276,46.8264],[-92.0277,46.8263],[-92.0277,46.8262],[-92.0277,46.8261],[-92.0278,46.826],[-92.0278,46.826],[-92.0278,46.8259],[-92.0279,46.8259],[-92.0281,46.8258],[-92.0282,46.8256],[-92.0283,46.8255],[-92.0284,46.8254],[-92.0285,46.8252],[-92.0285,46.825],[-92.0287,46.8249],[-92.0287,46.8248],[-92.0289,46.8246],[-92.0291,46.8245],[-92.0294,46.8244],[-92.0295,46.8242],[-92.0297,46.8242],[-92.0299,46.8241],[-92.0301,46.824],[-92.0303,46.824],[-92.0307,46.824],[-92.0309,46.8239],[-92.0311,46.8238],[-92.0313,46.8237],[-92.0315,46.8236],[-92.0316,46.8234],[-92.0317,46.8233],[-92.0318,46.8231],[-92.0318,46.8231],[-92.0319,46.823],[-92.032,46.8229],[-92.0322,46.8228],[-92.0326,46.8226],[-92.0329,46.8224],[-92.0329,46.8224],[-92.0333,46.8222],[-92.0335,46.8222],[-92.0337,46.8221],[-92.0338,46.822],[-92.0339,46.8219],[-92.0343,46.8218],[-92.0347,46.8218],[-92.0352,46.8217],[-92.0358,46.8215],[-92.0364,46.8214],[-92.0369,46.8213],[-92.0372,46.8212],[-92.0376,46.8211],[-92.038,46.8209],[-92.0382,46.8207],[-92.0384,46.8205],[-92.0385,46.8204],[-92.0386,46.8203],[-92.0387,46.8203],[-92.0388,46.8202],[-92.0389,46.8202],[-92.0392,46.8202],[-92.0397,46.8201],[-92.04,46.8201],[-92.0401,46.8202],[-92.0405,46.8202],[-92.0408,46.8203],[-92.0411,46.8203],[-92.0414,46.8203],[-92.0417,46.8203],[-92.0419,46.8202],[-92.0421,46.8201],[-92.0423,46.8201],[-92.0425,46.82],[-92.0427,46.82],[-92.0429,46.82],[-92.0431,46.8199],[-92.0434,46.8197],[-92.0437,46.8196],[-92.044,46.8195],[-92.0441,46.8194],[-92.0443,46.8193],[-92.0445,46.8193],[-92.0447,46.8192],[-92.045,46.8191],[-92.0452,46.819],[-92.0454,46.8189],[-92.0456,46.8188],[-92.0457,46.8187],[-92.0459,46.8186],[-92.046,46.8185],[-92.0461,46.8183],[-92.0462,46.8182],[-92.0462,46.8181],[-92.0463,46.818],[-92.0463,46.8179],[-92.0464,46.8178],[-92.0465,46.8177],[-92.0466,46.8175],[-92.0467,46.8174],[-92.0468,46.8173],[-92.0469,46.8173],[-92.0469,46.8173],[-92.0471,46.8172],[-92.0473,46.8171],[-92.0474,46.8171],[-92.0476,46.8169],[-92.0478,46.8169],[-92.048,46.8167],[-92.0481,46.8166],[-92.0481,46.8165],[-92.0482,46.8164],[-92.0483,46.8164],[-92.0484,46.8163],[-92.0485,46.8162],[-92.0486,46.8161],[-92.0489,46.816],[-92.049,46.8158],[-92.0492,46.8157],[-92.0494,46.8156],[-92.0495,46.8155],[-92.0497,46.8154],[-92.0498,46.8151],[-92.0499,46.815],[-92.05,46.8148],[-92.0501,46.8146],[-92.0503,46.8144],[-92.0504,46.8144],[-92.0505,46.8144],[-92.0507,46.8144],[-92.0509,46.8143],[-92.0511,46.8143],[-92.0513,46.8143],[-92.0517,46.8142],[-92.0519,46.8142],[-92.0523,46.814],[-92.0525,46.8139],[-92.0527,46.8138],[-92.0529,46.8137],[-92.0531,46.8135],[-92.0533,46.8132],[-92.0535,46.8131],[-92.0537,46.8128],[-92.0539,46.8126],[-92.054,46.8124],[-92.054,46.8123],[-92.0542,46.812],[-92.0544,46.8118],[-92.0546,46.8117],[-92.0549,46.8115],[-92.0551,46.8115],[-92.0553,46.8113],[-92.0556,46.8112],[-92.0559,46.811],[-92.0563,46.8109],[-92.0566,46.8108],[-92.0569,46.8107],[-92.0573,46.8106],[-92.0575,46.8106],[-92.0581,46.8106],[-92.0583,46.8105],[-92.0587,46.8104],[-92.0588,46.8103],[-92.059,46.8101],[-92.0593,46.8099],[-92.0594,46.8097],[-92.0595,46.8095],[-92.0597,46.8092],[-92.0598,46.809],[-92.06,46.8087],[-92.06,46.8084],[-92.0602,46.808],[-92.0602,46.8078],[-92.0603,46.8074],[-92.0605,46.8071],[-92.0606,46.8069],[-92.0608,46.8066],[-92.061,46.8065],[-92.0611,46.8063],[-92.0612,46.8061],[-92.0612,46.8059],[-92.0613,46.8057],[-92.0616,46.8054],[-92.0617,46.8052],[-92.0619,46.8049],[-92.0621,46.8047],[-92.0622,46.8045],[-92.0625,46.8044],[-92.0627,46.8042],[-92.063,46.8041],[-92.0634,46.8039],[-92.0637,46.8038],[-92.064,46.8037],[-92.0642,46.8037],[-92.0646,46.8035],[-92.0649,46.8034],[-92.0652,46.8033],[-92.0656,46.8031],[-92.0659,46.803],[-92.0662,46.8028],[-92.0665,46.8026],[-92.0668,46.8024],[-92.067,46.8024],[-92.0674,46.8023],[-92.0677,46.8022],[-92.068,46.8022],[-92.0682,46.8023],[-92.0685,46.8023],[-92.0686,46.8023],[-92.0686,46.8023],[-92.0689,46.8024],[-92.0691,46.8023],[-92.0694,46.8023],[-92.0696,46.8022],[-92.0699,46.802],[-92.0702,46.8018],[-92.0705,46.8016],[-92.0707,46.8014],[-92.0708,46.8012],[-92.071,46.801],[-92.0712,46.8008],[-92.0713,46.8007],[-92.0715,46.8006],[-92.0716,46.8006],[-92.0718,46.8006],[-92.072,46.8007],[-92.0721,46.8007],[-92.0723,46.8006],[-92.0726,46.8006],[-92.0728,46.8005],[-92.0731,46.8004],[-92.0736,46.8002],[-92.0739,46.8],[-92.0741,46.7999],[-92.0743,46.7997],[-92.0746,46.7995],[-92.0749,46.7994],[-92.0752,46.7993],[-92.0755,46.7992],[-92.0758,46.7991],[-92.0762,46.7989],[-92.0764,46.7988],[-92.0765,46.7986],[-92.0766,46.7985],[-92.0767,46.7983],[-92.0769,46.7983],[-92.0771,46.7983],[-92.0774,46.7983],[-92.0775,46.7982],[-92.0777,46.7981],[-92.0778,46.798],[-92.0779,46.7979],[-92.078,46.7978],[-92.078,46.7977],[-92.0781,46.7975],[-92.0782,46.7974],[-92.0783,46.7973],[-92.0785,46.7973],[-92.0785,46.7973],[-92.0787,46.7974],[-92.0788,46.7974],[-92.0791,46.7974],[-92.0794,46.7973],[-92.0796,46.7973],[-92.0798,46.7973],[-92.0801,46.7973],[-92.0804,46.7973],[-92.0806,46.7973],[-92.0809,46.7972],[-92.0812,46.7971],[-92.0814,46.797],[-92.0815,46.7969],[-92.0817,46.7967],[-92.0819,46.7966],[-92.082,46.7965],[-92.0821,46.7963],[-92.0821,46.7962],[-92.0822,46.796],[-92.0823,46.7959],[-92.0825,46.7959],[-92.0828,46.7958],[-92.0831,46.7958],[-92.0835,46.7957],[-92.0838,46.7957],[-92.0841,46.7957],[-92.0844,46.7957],[-92.0847,46.7957],[-92.085,46.7957],[-92.0853,46.7956],[-92.0856,46.7955],[-92.0857,46.7954],[-92.0858,46.7953],[-92.0859,46.7952],[-92.0861,46.7951],[-92.0862,46.795],[-92.0863,46.7948],[-92.0864,46.7947],[-92.0867,46.7946],[-92.0869,46.7945],[-92.0872,46.7944],[-92.0875,46.7943],[-92.0878,46.7941],[-92.0881,46.794],[-92.0884,46.7938],[-92.0886,46.7937],[-92.0889,46.7935],[-92.0891,46.7933],[-92.0892,46.7931],[-92.0892,46.7931],[-92.0893,46.7929],[-92.0895,46.7926],[-92.0897,46.7924],[-92.0899,46.7923],[-92.0901,46.7921],[-92.0902,46.792],[-92.0903,46.7919],[-92.0904,46.7917],[-92.0903,46.7916],[-92.0903,46.7915],[-92.0903,46.7913],[-92.0904,46.7912],[-92.0905,46.791],[-92.0905,46.7908],[-92.0907,46.7905],[-92.0908,46.7902],[-92.091,46.7898],[-92.0912,46.7896],[-92.0913,46.7895],[-92.0915,46.7893],[-92.0918,46.7892],[-92.092,46.7892],[-92.0923,46.7892],[-92.0928,46.7889],[-92.0929,46.7888],[-92.0932,46.7887],[-92.0934,46.7885],[-92.0936,46.7883],[-92.0938,46.7881],[-92.0939,46.788],[-92.094,46.7877],[-92.0941,46.7875],[-92.0941,46.7874],[-92.094,46.7872],[-92.094,46.7871],[-92.094,46.7869],[-92.0939,46.7867],[-92.0938,46.7864],[-92.0936,46.786],[-92.0935,46.7857],[-92.0934,46.7854],[-92.0934,46.7852],[-92.0933,46.7849],[-92.0932,46.7848],[-92.0932,46.7845],[-92.0931,46.7842],[-92.093,46.7839],[-92.0929,46.7836],[-92.0926,46.7832],[-92.0925,46.783],[-92.0924,46.7828],[-92.0923,46.7826],[-92.0921,46.7825],[-92.092,46.7823],[-92.0919,46.7821],[-92.0918,46.7819],[-92.0917,46.7817],[-92.0916,46.7814],[-92.0915,46.7813],[-92.0913,46.781],[-92.0911,46.7807],[-92.091,46.7804],[-92.0912,46.7801],[-92.0914,46.7787],[-92.0914,46.7784],[-92.0909,46.7775],[-92.0908,46.7773],[-92.09,46.7762],[-92.0897,46.7757],[-92.0894,46.7754],[-92.0892,46.7751],[-92.0889,46.7747],[-92.0888,46.7743],[-92.0879,46.7731],[-92.0879,46.773],[-92.0878,46.773],[-92.0876,46.7727],[-92.0859,46.7704],[-92.0859,46.7702],[-92.0849,46.7691],[-92.0846,46.7687],[-92.0842,46.7682],[-92.0838,46.7676],[-92.0829,46.7665],[-92.0829,46.7664],[-92.0826,46.7659],[-92.0819,46.7651],[-92.0812,46.7644],[-92.0811,46.7642],[-92.0784,46.7609],[-92.0781,46.7606],[-92.0768,46.759],[-92.0767,46.7588],[-92.0765,46.7587],[-92.0764,46.7584],[-92.076,46.7581],[-92.0758,46.7578],[-92.0739,46.7555],[-92.0735,46.7552],[-92.0735,46.755],[-92.073,46.7546],[-92.0729,46.7544],[-92.0726,46.754],[-92.0724,46.754],[-92.0724,46.7538],[-92.0717,46.7532],[-92.0716,46.753],[-92.0707,46.7521],[-92.0706,46.7519],[-92.0703,46.7517],[-92.0694,46.7506],[-92.0693,46.7505],[-92.069,46.7502],[-92.0688,46.75],[-92.0686,46.7497],[-92.0684,46.7495],[-92.0681,46.7491],[-92.0679,46.7489],[-92.0677,46.7487],[-92.0676,46.7486],[-92.0672,46.7481],[-92.0668,46.7478],[-92.0658,46.7466],[-92.0633,46.7441],[-92.0629,46.7437],[-92.0628,46.7435],[-92.0625,46.7432],[-92.0623,46.743],[-92.062,46.7427],[-92.0618,46.7424],[-92.0614,46.7421],[-92.0613,46.7419],[-92.0607,46.7414],[-92.0597,46.7403],[-92.0592,46.7399],[-92.0588,46.7394],[-92.0575,46.7381],[-92.0568,46.7374],[-92.0563,46.737],[-92.0559,46.7366],[-92.0546,46.7353],[-92.0546,46.7352],[-92.0544,46.7352],[-92.0542,46.735],[-92.054,46.7347],[-92.0504,46.7315],[-92.0477,46.7291],[-92.0466,46.7282],[-92.0466,46.728],[-92.0463,46.7279],[-92.0459,46.7275],[-92.0448,46.7265],[-92.0376,46.7206],[-92.037,46.7201],[-92.0348,46.7183],[-92.0274,46.7118],[-92.0269,46.7114],[-92.0267,46.7113],[-92.0265,46.7112],[-92.0264,46.7112],[-92.0258,46.7114],[-92.0253,46.7111],[-92.0243,46.7109],[-92.0214,46.7108],[-92.0205,46.7107],[-92.0194,46.7106],[-92.0192,46.7102],[-92.0192,46.7099],[-92.0187,46.7088],[-92.0174,46.7072],[-92.0164,46.7062],[-92.0163,46.706],[-92.0202,46.7041],[-92.025,46.7058],[-92.0262,46.7062],[-92.0269,46.7065],[-92.0339,46.709],[-92.0428,46.7153],[-92.0479,46.719],[-92.0501,46.7206],[-92.0594,46.7274],[-92.0648,46.7312],[-92.0687,46.734],[-92.0701,46.735],[-92.0713,46.7359],[-92.0894,46.7493],[-92.0985,46.7491],[-92.1001,46.7491],[-92.1081,46.7492],[-92.1086,46.749],[-92.1102,46.749],[-92.1138,46.7489],[-92.1165,46.7487],[-92.1173,46.7484],[-92.1184,46.7479],[-92.1252,46.745],[-92.1317,46.7422],[-92.1378,46.7396],[-92.1428,46.7351],[-92.1429,46.735],[-92.1432,46.7347],[-92.1433,46.7306],[-92.1433,46.7282],[-92.1412,46.7253],[-92.1438,46.7205],[-92.1448,46.7184],[-92.1462,46.716],[-92.1467,46.7158],[-92.1486,46.7152],[-92.1534,46.7158],[-92.1551,46.716],[-92.1672,46.72],[-92.1708,46.7189],[-92.1719,46.7185],[-92.1742,46.7173],[-92.1747,46.7172],[-92.176,46.7171],[-92.1788,46.7168],[-92.189,46.7176],[-92.1914,46.7163],[-92.1916,46.7157],[-92.1917,46.7153],[-92.1932,46.7113],[-92.1959,46.7089],[-92.1973,46.7077],[-92.1997,46.7067],[-92.2003,46.7064],[-92.2004,46.7064],[-92.201,46.7062],[-92.2015,46.706],[-92.2019,46.7058],[-92.2026,46.7054],[-92.2046,46.7041],[-92.2056,46.7026],[-92.2051,46.6984],[-92.1984,46.6962],[-92.1956,46.696],[-92.1892,46.6956],[-92.183,46.6953],[-92.178,46.692],[-92.1778,46.6919],[-92.1764,46.6903],[-92.176,46.6864],[-92.1775,46.6835],[-92.1813,46.6803],[-92.1824,46.68],[-92.1875,46.679],[-92.1906,46.6776],[-92.1916,46.6772],[-92.1924,46.6768],[-92.1957,46.6741],[-92.1958,46.674],[-92.1994,46.6703],[-92.204,46.667],[-92.2054,46.6648],[-92.2046,46.6634],[-92.2021,46.659],[-92.2015,46.6567],[-92.2022,46.6551],[-92.2044,46.6537],[-92.207,46.652],[-92.2123,46.65],[-92.2163,46.6499],[-92.2166,46.65],[-92.2234,46.6527],[-92.2262,46.6529],[-92.2284,46.653],[-92.2355,46.6501],[-92.2376,46.6498],[-92.2424,46.6493],[-92.2486,46.6535],[-92.2509,46.655],[-92.2521,46.6558],[-92.2525,46.6561],[-92.2545,46.6574],[-92.2549,46.6577],[-92.2556,46.6581],[-92.2565,46.6588],[-92.2587,46.6577],[-92.2596,46.6572],[-92.2659,46.6511],[-92.2705,46.6508],[-92.2727,46.6529],[-92.2735,46.655],[-92.2743,46.6575],[-92.2784,46.6587],[-92.2799,46.6587],[-92.2836,46.6589],[-92.2842,46.6592],[-92.2844,46.6594],[-92.2861,46.6604],[-92.287,46.6629],[-92.2871,46.6631],[-92.2872,46.6647],[-92.2873,46.6669],[-92.2873,46.6674],[-92.2881,46.6676],[-92.2907,46.6681],[-92.2912,46.6682],[-92.2921,46.6661],[-92.2922,46.665],[-92.2921,46.6633],[-92.301,46.6636],[-92.3012,46.6773],[-92.3012,46.6919],[-92.3013,46.7063],[-92.3014,46.7208],[-92.3016,46.7353],[-92.3014,46.7498],[-92.3015,46.7643],[-92.3223,46.7652],[-92.3435,46.7651],[-92.3646,46.765],[-92.3856,46.765],[-92.4064,46.7649],[-92.4283,46.765],[-92.4495,46.7657],[-92.4705,46.7656],[-92.4924,46.7657],[-92.5125,46.7658],[-92.5336,46.7659],[-92.5548,46.7662],[-92.5759,46.7667],[-92.5967,46.7665],[-92.6177,46.7667],[-92.6385,46.767],[-92.6592,46.7692],[-92.6803,46.7692],[-92.7014,46.7687],[-92.7226,46.7682],[-92.7442,46.7677],[-92.7459,46.7677],[-92.7653,46.7674],[-92.7864,46.7666],[-92.8084,46.7661],[-92.8296,46.7661],[-92.8508,46.7662],[-92.8721,46.7664],[-92.8932,46.7666],[-92.9143,46.7661],[-92.9356,46.7662],[-92.9567,46.7662],[-92.9777,46.7665],[-92.9988,46.7669],[-93.0201,46.7668],[-93.0412,46.7667],[-93.0615,46.7667],[-93.0609,46.781],[-93.061,46.7956],[-93.0606,46.81],[-93.0606,46.8241],[-93.0603,46.8387],[-93.06,46.853],[-93.0597,46.8672],[-93.059,46.8817],[-93.0587,46.8964],[-93.0582,46.9108],[-93.0583,46.9251],[-93.0577,46.9398],[-93.0576,46.9541],[-93.0573,46.9685],[-93.0571,46.9832],[-93.0568,46.9976],[-93.0564,47.0121],[-93.0559,47.0265],[-93.0557,47.0407],[-93.0558,47.0551],[-93.0558,47.0698],[-93.0557,47.084],[-93.056,47.0984],[-93.0562,47.1093],[-93.0664,47.1094],[-93.0663,47.1239],[-93.0659,47.1382],[-93.0659,47.1526],[-93.0655,47.1671],[-93.0652,47.1814],[-93.0654,47.196],[-93.0654,47.2103],[-93.0655,47.2248],[-93.0657,47.2394],[-93.0658,47.2538],[-93.0657,47.2683],[-93.0658,47.2828],[-93.0658,47.2975],[-93.0652,47.3119],[-93.0647,47.3265],[-93.0645,47.3412],[-93.0644,47.3556],[-93.0644,47.3716],[-93.0666,47.3716],[-93.0689,47.386],[-93.0693,47.4003],[-93.0692,47.4148],[-93.0692,47.429],[-93.069,47.4434],[-93.0688,47.4578],[-93.0673,47.472],[-93.067,47.4859],[-93.0651,47.5003],[-93.0647,47.5147],[-93.0641,47.529],[-93.0637,47.5445],[-93.0637,47.559],[-93.0638,47.5734],[-93.0628,47.5875],[-93.0628,47.6026],[-93.0643,47.6172],[-93.0637,47.6333],[-93.0637,47.6476],[-93.0633,47.6621],[-93.0626,47.6774],[-93.0619,47.691],[-93.0612,47.7056],[-93.0613,47.7205],[-93.0821,47.7206],[-93.0823,47.7355],[-93.0823,47.7493],[-93.0826,47.7635],[-93.083,47.7779],[-93.0834,47.7917],[-93.0837,47.8064],[-93.0837,47.8209],[-93.0837,47.8223],[-93.0831,47.835],[-93.083,47.8368],[-93.0823,47.8494],[-93.0822,47.8513],[-93.0815,47.8637],[-93.0813,47.8656],[-93.0812,47.8676],[-93.0808,47.878],[-93.0807,47.88],[-93.0808,47.8922],[-93.0808,47.8945],[-93.0809,47.9067],[-93.0809,47.9088],[-93.0809,47.9212],[-93.0809,47.9235],[-93.0809,47.9356],[-93.0809,47.938],[-93.0808,47.9504],[-93.0808,47.9525],[-93.0808,47.9647],[-93.0809,47.967],[-93.0809,47.9786],[-93.088,47.9787],[-93.0872,47.9932],[-93.0887,48.0075],[-93.0886,48.022],[-93.089,48.0366],[-93.0892,48.0509],[-93.0892,48.0679],[-93.0965,48.0678],[-93.0965,48.0679],[-93.0968,48.0823],[-93.097,48.0969],[-93.0972,48.1114],[-93.0969,48.1259],[-93.097,48.1402],[-93.097,48.1546],[-93.097,48.1692],[-93.0975,48.1836],[-93.0979,48.1981],[-93.0978,48.2126],[-93.0977,48.2271],[-93.0977,48.2426],[-93.0949,48.2425],[-93.0949,48.2426],[-93.0953,48.2576],[-93.0952,48.2716],[-93.095,48.2862],[-93.0952,48.3004],[-93.0953,48.3153],[-93.0948,48.3298],[-93.0948,48.3442],[-93.0945,48.3589],[-93.094,48.3734],[-93.094,48.3879],[-93.0938,48.4024],[-93.0935,48.4147],[-93.0923,48.4147],[-93.0922,48.429],[-93.0922,48.4303],[-93.092,48.4436],[-93.092,48.4449],[-93.0919,48.458],[-93.0918,48.4596],[-93.0915,48.4724],[-93.0914,48.474],[-93.0911,48.4867],[-93.091,48.4884],[-93.0905,48.501],[-93.0905,48.5151],[-93.0903,48.5296],[-93.0902,48.5441],[-93.0902,48.5583],[-93.09,48.5727],[-93.0898,48.5872],[-93.0895,48.6016],[-93.0886,48.6163],[-93.0884,48.6278]]],"type":"Polygon"},"id":"69","properties":{"Area":17451037319.2417,"CTYONLY_":7,"Code":"STLO","LASTMOD":"2010-10-17T00:00:00Z","Name":"St. Louis","Perimiter":682518.436},"type":"Feature"},{"geometry":{"coordinates":[[[-95.3425,48.5402],[-95.3412,48.5402],[-95.321,48.54],[-95.3194,48.54],[-95.2992,48.5402],[-95.2975,48.5401],[-95.2773,48.54],[-95.2756,48.54],[-95.2554,48.5398],[-95.2537,48.5398],[-95.2339,48.5399],[-95.2324,48.5399],[-95.2119,48.54],[-95.2115,48.5252],[-95.2115,48.5244],[-95.2111,48.5109],[-95.2111,48.5101],[-95.2112,48.4962],[-95.2111,48.4816],[-95.211,48.4673],[-95.211,48.4666],[-95.2112,48.4529],[-95.2113,48.4522],[-95.2113,48.4387],[-95.2113,48.4376],[-95.2113,48.4255],[-95.2113,48.4242],[-95.2113,48.4232],[-95.2112,48.4096],[-95.2112,48.4087],[-95.2111,48.3952],[-95.2111,48.3941],[-95.211,48.3808],[-95.211,48.3797],[-95.2106,48.3661],[-95.2066,48.3661],[-95.1983,48.3661],[-95.1887,48.3661],[-95.1861,48.3661],[-95.1669,48.3661],[-95.164,48.3661],[-95.1454,48.3662],[-95.1424,48.3662],[-95.1315,48.3662],[-95.1236,48.3663],[-95.1207,48.3663],[-95.1018,48.3663],[-95.1008,48.3663],[-95.099,48.3663],[-95.0801,48.3664],[-95.0773,48.3664],[-95.0586,48.3665],[-95.0555,48.3665],[-95.0369,48.3665],[-95.0337,48.3665],[-95.0153,48.3665],[-95.0119,48.3665],[-94.9932,48.3667],[-94.9901,48.3667],[-94.9716,48.3667],[-94.9684,48.3667],[-94.95,48.3666],[-94.9469,48.3666],[-94.9283,48.3667],[-94.9264,48.3667],[-94.9065,48.3666],[-94.9049,48.3666],[-94.8849,48.3666],[-94.8833,48.3667],[-94.8632,48.3667],[-94.8616,48.3667],[-94.8416,48.3669],[-94.8399,48.3669],[-94.8199,48.3669],[-94.8183,48.3669],[-94.7983,48.3669],[-94.7967,48.3669],[-94.7765,48.3669],[-94.7748,48.3669],[-94.7549,48.3669],[-94.7533,48.3669],[-94.7329,48.3669],[-94.7315,48.3669],[-94.7117,48.3668],[-94.7099,48.3669],[-94.6898,48.3671],[-94.683,48.3671],[-94.6694,48.3672],[-94.6679,48.3673],[-94.6622,48.3673],[-94.6505,48.3673],[-94.6465,48.3673],[-94.6405,48.3673],[-94.6245,48.3673],[-94.6188,48.3673],[-94.6029,48.3674],[-94.5971,48.3675],[-94.5812,48.3674],[-94.5754,48.3674],[-94.5593,48.3674],[-94.5536,48.3674],[-94.5378,48.3674],[-94.5335,48.3674],[-94.5157,48.3674],[-94.5118,48.3675],[-94.4941,48.3674],[-94.4924,48.3674],[-94.4906,48.3674],[-94.4722,48.3674],[-94.4688,48.3675],[-94.4505,48.3675],[-94.4471,48.3675],[-94.4288,48.3675],[-94.4252,48.3675],[-94.4253,48.352],[-94.425,48.3372],[-94.4248,48.3227],[-94.4246,48.3081],[-94.4244,48.2938],[-94.4243,48.2791],[-94.424,48.2649],[-94.4237,48.2504],[-94.4237,48.2356],[-94.4238,48.2212],[-94.4236,48.2067],[-94.4233,48.1923],[-94.4235,48.1781],[-94.4235,48.1637],[-94.4233,48.1491],[-94.4236,48.1348],[-94.4234,48.1204],[-94.4233,48.1059],[-94.4231,48.092],[-94.4234,48.0776],[-94.4247,48.0632],[-94.4246,48.0489],[-94.4241,48.0344],[-94.4236,48.0199],[-94.4176,48.02],[-94.4177,48.006],[-94.4176,47.9914],[-94.4173,47.9769],[-94.4172,47.9623],[-94.4174,47.9477],[-94.4175,47.9332],[-94.4174,47.9186],[-94.4175,47.9175],[-94.4176,47.9041],[-94.4177,47.9031],[-94.418,47.8886],[-94.4184,47.8744],[-94.4186,47.86],[-94.4185,47.8459],[-94.4186,47.8316],[-94.4187,47.817],[-94.4188,47.8026],[-94.4189,47.7881],[-94.4189,47.7735],[-94.4191,47.759],[-94.4192,47.7445],[-94.4191,47.7302],[-94.419,47.7155],[-94.4187,47.7012],[-94.4185,47.6867],[-94.4184,47.6721],[-94.417,47.6722],[-94.417,47.6578],[-94.4167,47.6435],[-94.4165,47.6291],[-94.4163,47.615],[-94.4159,47.6009],[-94.4136,47.5866],[-94.4144,47.5723],[-94.414,47.5578],[-94.4148,47.5432],[-94.4146,47.5286],[-94.4149,47.5145],[-94.4151,47.5],[-94.4154,47.4861],[-94.4156,47.4717],[-94.416,47.4571],[-94.4161,47.4449],[-94.4161,47.443],[-94.4157,47.4287],[-94.4159,47.4119],[-94.4372,47.4118],[-94.4586,47.4118],[-94.4798,47.4119],[-94.5009,47.412],[-94.5243,47.4114],[-94.5458,47.4109],[-94.5636,47.411],[-94.585,47.411],[-94.6069,47.4101],[-94.6279,47.4103],[-94.6492,47.4102],[-94.6702,47.4102],[-94.6918,47.4098],[-94.7129,47.4095],[-94.7344,47.4098],[-94.7563,47.4105],[-94.7777,47.4102],[-94.7998,47.4098],[-94.8209,47.41],[-94.8423,47.4102],[-94.8636,47.4103],[-94.8849,47.4105],[-94.9063,47.4107],[-94.9274,47.4118],[-94.9487,47.4115],[-94.97,47.4114],[-94.9914,47.4114],[-95.0127,47.4114],[-95.0341,47.4117],[-95.0557,47.4119],[-95.0766,47.4123],[-95.098,47.4125],[-95.1193,47.4126],[-95.1406,47.4125],[-95.1619,47.4127],[-95.1829,47.4127],[-95.1828,47.4268],[-95.1828,47.4412],[-95.1829,47.4557],[-95.183,47.4703],[-95.1831,47.4845],[-95.1833,47.499],[-95.1837,47.5135],[-95.1839,47.528],[-95.1841,47.5424],[-95.1841,47.5566],[-95.1844,47.571],[-95.1847,47.5861],[-95.1849,47.6006],[-95.1849,47.6151],[-95.1849,47.6297],[-95.1849,47.6442],[-95.1847,47.6587],[-95.1849,47.6735],[-95.1904,47.6734],[-95.1941,47.6734],[-95.1944,47.688],[-95.1944,47.7024],[-95.1943,47.717],[-95.1942,47.7313],[-95.1941,47.746],[-95.1941,47.7606],[-95.1939,47.7752],[-95.1939,47.7896],[-95.1938,47.8033],[-95.1937,47.8044],[-95.1937,47.8188],[-95.1936,47.8334],[-95.1935,47.8479],[-95.1935,47.8624],[-95.1934,47.8726],[-95.2003,47.8732],[-95.2025,47.8735],[-95.205,47.874],[-95.2071,47.8742],[-95.2103,47.8744],[-95.2105,47.8745],[-95.2146,47.875],[-95.215,47.8751],[-95.2172,47.8755],[-95.2193,47.876],[-95.2218,47.8765],[-95.223,47.8768],[-95.2288,47.8781],[-95.2313,47.8788],[-95.2345,47.8798],[-95.2359,47.8803],[-95.2374,47.8807],[-95.2377,47.8807],[-95.238,47.8809],[-95.2397,47.8814],[-95.2415,47.882],[-95.2456,47.8829],[-95.2473,47.8837],[-95.2485,47.8844],[-95.2502,47.8852],[-95.2518,47.8861],[-95.2538,47.8876],[-95.2558,47.8891],[-95.2578,47.8903],[-95.258,47.8905],[-95.2585,47.8909],[-95.2592,47.8917],[-95.2592,47.8918],[-95.26,47.8925],[-95.2618,47.8944],[-95.2625,47.895],[-95.2635,47.896],[-95.2655,47.8979],[-95.2657,47.8981],[-95.266,47.8984],[-95.2661,47.8985],[-95.2663,47.8987],[-95.2664,47.8991],[-95.2665,47.8992],[-95.2665,47.8993],[-95.2666,47.8993],[-95.2668,47.8999],[-95.2671,47.9004],[-95.2677,47.901],[-95.2681,47.9016],[-95.2681,47.9017],[-95.2683,47.902],[-95.2688,47.9029],[-95.2689,47.9032],[-95.2699,47.9049],[-95.2701,47.9056],[-95.2702,47.9059],[-95.2703,47.9062],[-95.2704,47.9062],[-95.2704,47.9063],[-95.2705,47.9064],[-95.2705,47.9064],[-95.2706,47.9066],[-95.2709,47.9069],[-95.2709,47.907],[-95.2723,47.9089],[-95.2728,47.9097],[-95.2728,47.9098],[-95.2729,47.9099],[-95.2729,47.9101],[-95.2732,47.9107],[-95.2734,47.9114],[-95.2734,47.9116],[-95.2735,47.9116],[-95.2736,47.9121],[-95.2738,47.9125],[-95.2738,47.9128],[-95.2741,47.9135],[-95.2741,47.9139],[-95.2748,47.9154],[-95.275,47.9156],[-95.2753,47.9162],[-95.2754,47.9168],[-95.2756,47.9172],[-95.2756,47.9175],[-95.2761,47.92],[-95.2762,47.9206],[-95.2762,47.9206],[-95.2763,47.921],[-95.2764,47.9215],[-95.2765,47.922],[-95.2766,47.9227],[-95.2767,47.9231],[-95.2768,47.9236],[-95.2771,47.9247],[-95.2774,47.9254],[-95.2774,47.9257],[-95.2776,47.9263],[-95.2778,47.9281],[-95.278,47.9286],[-95.2781,47.9302],[-95.278,47.9321],[-95.2779,47.9328],[-95.2779,47.9351],[-95.2779,47.9351],[-95.2774,47.938],[-95.2772,47.9384],[-95.2772,47.9389],[-95.277,47.9414],[-95.2769,47.9416],[-95.2767,47.9438],[-95.2767,47.9449],[-95.2761,47.947],[-95.2759,47.9474],[-95.2756,47.9487],[-95.2755,47.9488],[-95.2753,47.9495],[-95.2751,47.9507],[-95.2749,47.9515],[-95.2743,47.9529],[-95.2743,47.9531],[-95.2742,47.9534],[-95.2742,47.9541],[-95.2741,47.9561],[-95.274,47.9568],[-95.2739,47.9574],[-95.2735,47.958],[-95.2731,47.9584],[-95.2729,47.9586],[-95.2728,47.9587],[-95.2726,47.959],[-95.2726,47.9593],[-95.2725,47.9605],[-95.2722,47.961],[-95.2712,47.9623],[-95.271,47.9628],[-95.2708,47.9632],[-95.2706,47.9636],[-95.2703,47.9637],[-95.2701,47.9639],[-95.2701,47.964],[-95.2698,47.9643],[-95.2694,47.9655],[-95.268,47.9688],[-95.267,47.9704],[-95.267,47.9707],[-95.2667,47.9708],[-95.2664,47.9714],[-95.2657,47.9727],[-95.2646,47.9748],[-95.2645,47.9752],[-95.2639,47.9765],[-95.2636,47.9771],[-95.2627,47.9786],[-95.2618,47.9803],[-95.259,47.9839],[-95.2585,47.9852],[-95.2583,47.9856],[-95.2582,47.9865],[-95.258,47.987],[-95.2579,47.9875],[-95.2576,47.9883],[-95.2571,47.9891],[-95.2554,47.9917],[-95.2551,47.992],[-95.2546,47.9926],[-95.2543,47.9932],[-95.253,47.9954],[-95.2526,47.9964],[-95.2523,47.9968],[-95.252,47.9971],[-95.2518,47.9973],[-95.2512,47.998],[-95.2508,47.9988],[-95.2507,47.999],[-95.2507,48.0],[-95.2504,48.0],[-95.2502,48.0],[-95.2495,48.0],[-95.2495,48.0009],[-95.2493,48.0015],[-95.249,48.002],[-95.2486,48.0025],[-95.2481,48.0029],[-95.2479,48.0031],[-95.2477,48.0041],[-95.2472,48.0046],[-95.247,48.0048],[-95.2464,48.0055],[-95.2459,48.0059],[-95.2455,48.0066],[-95.245,48.0071],[-95.2449,48.0072],[-95.2445,48.0076],[-95.2445,48.0076],[-95.2444,48.008],[-95.2442,48.0081],[-95.2441,48.0083],[-95.2439,48.0086],[-95.2439,48.0087],[-95.2438,48.0087],[-95.2433,48.009],[-95.2423,48.0097],[-95.2421,48.01],[-95.2418,48.0103],[-95.2417,48.0106],[-95.2414,48.0108],[-95.2414,48.0109],[-95.2409,48.0111],[-95.2407,48.0112],[-95.2404,48.0114],[-95.2401,48.0117],[-95.24,48.0119],[-95.24,48.0119],[-95.2396,48.0123],[-95.2394,48.0124],[-95.2387,48.0127],[-95.2377,48.0134],[-95.2376,48.0135],[-95.2372,48.0139],[-95.2371,48.0142],[-95.2371,48.0143],[-95.237,48.0144],[-95.2368,48.0145],[-95.2367,48.0145],[-95.2363,48.0148],[-95.2362,48.0148],[-95.2358,48.0149],[-95.2354,48.0152],[-95.2352,48.0155],[-95.2347,48.0158],[-95.2326,48.017],[-95.2323,48.0174],[-95.2306,48.0185],[-95.2304,48.0188],[-95.2303,48.0191],[-95.2297,48.0196],[-95.2293,48.0199],[-95.2289,48.0201],[-95.2378,48.0201],[-95.2473,48.0201],[-95.2493,48.0201],[-95.2594,48.0201],[-95.269,48.0201],[-95.281,48.0202],[-95.2887,48.0201],[-95.2906,48.0201],[-95.2933,48.0201],[-95.3025,48.0202],[-95.3122,48.0202],[-95.3224,48.0203],[-95.3338,48.0203],[-95.3401,48.0203],[-95.3439,48.0204],[-95.3554,48.0204],[-95.3654,48.0204],[-95.3661,48.0204],[-95.377,48.0205],[-95.3871,48.0206],[-95.3985,48.0206],[-95.4086,48.0207],[-95.4201,48.0206],[-95.4302,48.0206],[-95.4417,48.0206],[-95.4523,48.0206],[-95.4632,48.0207],[-95.4738,48.0207],[-95.485,48.0207],[-95.4954,48.0207],[-95.4959,48.0207],[-95.5065,48.0208],[-95.517,48.0208],[-95.5215,48.0209],[-95.5277,48.0209],[-95.5384,48.0209],[-95.5398,48.0209],[-95.5491,48.0209],[-95.5597,48.0208],[-95.5705,48.0208],[-95.5828,48.0207],[-95.5922,48.0207],[-95.5923,48.035],[-95.5925,48.0497],[-95.5925,48.0642],[-95.5926,48.0787],[-95.5928,48.0931],[-95.593,48.1078],[-95.5931,48.1223],[-95.5936,48.1368],[-95.5938,48.1512],[-95.5939,48.1658],[-95.5939,48.173],[-95.594,48.1802],[-95.5938,48.1946],[-95.5939,48.2092],[-95.5939,48.2236],[-95.5941,48.2382],[-95.5941,48.2526],[-95.5937,48.267],[-95.5934,48.2815],[-95.5934,48.2961],[-95.5932,48.3105],[-95.5932,48.325],[-95.5932,48.3396],[-95.5933,48.354],[-95.5933,48.3656],[-95.5933,48.3656],[-95.6016,48.3655],[-95.602,48.3798],[-95.6021,48.3809],[-95.6026,48.3942],[-95.6026,48.395],[-95.6026,48.4088],[-95.6026,48.4095],[-95.6023,48.4232],[-95.6023,48.424],[-95.6021,48.4376],[-95.602,48.4385],[-95.6016,48.4522],[-95.6016,48.453],[-95.6016,48.4666],[-95.6016,48.4674],[-95.6011,48.4811],[-95.6011,48.4818],[-95.6008,48.4956],[-95.6008,48.4964],[-95.6007,48.51],[-95.6007,48.5107],[-95.6011,48.5251],[-95.6023,48.5389],[-95.5821,48.5387],[-95.5801,48.5387],[-95.5603,48.5388],[-95.558,48.5388],[-95.5383,48.5389],[-95.5365,48.5389],[-95.5163,48.539],[-95.5143,48.539],[-95.495,48.5392],[-95.493,48.5392],[-95.4726,48.5396],[-95.4712,48.5396],[-95.4513,48.5399],[-95.4494,48.5399],[-95.4297,48.5399],[-95.4279,48.54],[-95.4078,48.5402],[-95.4061,48.5402],[-95.386,48.5402],[-95.3844,48.5402],[-95.364,48.5403],[-95.3628,48.5404],[-95.3425,48.5402]]],"type":"Polygon"},"id":"4","properties":{"Area":7911449532.86586,"CTYONLY_":8,"Code":"BELT","LASTMOD":"1999-12-31T23:59:59Z","Name":"Beltrami","Perimiter":429419.1705},"type":"Feature"},{"geometry":{"coordinates":[[[-97.1467,48.1733],[-97.1462,48.1733],[-97.1376,48.1733],[-97.1322,48.1733],[-97.1286,48.1733],[-97.1257,48.1733],[-97.1253,48.1733],[-97.1071,48.1735],[-97.1069,48.1735],[-97.0855,48.1734],[-97.0853,48.1734],[-97.0637,48.1732],[-97.0637,48.1732],[-97.042,48.1732],[-97.042,48.1732],[-97.0205,48.1733],[-97.0203,48.1733],[-97.0003,48.1732],[-96.999,48.1732],[-96.9989,48.1732],[-96.9987,48.1732],[-96.998,48.1732],[-96.9975,48.1732],[-96.9959,48.1732],[-96.99,48.1731],[-96.9889,48.1731],[-96.9844,48.1731],[-96.9812,48.1731],[-96.9775,48.1731],[-96.9773,48.173],[-96.9773,48.173],[-96.9751,48.173],[-96.9749,48.173],[-96.9705,48.1731],[-96.9703,48.1731],[-96.9554,48.1731],[-96.9448,48.1732],[-96.9387,48.1732],[-96.934,48.1733],[-96.9339,48.1733],[-96.933,48.1733],[-96.9123,48.1733],[-96.9122,48.1733],[-96.8932,48.1732],[-96.8907,48.1732],[-96.8907,48.1732],[-96.8753,48.1732],[-96.869,48.1733],[-96.869,48.1733],[-96.8474,48.1733],[-96.8473,48.1733],[-96.8255,48.1734],[-96.8255,48.1734],[-96.8111,48.1734],[-96.8039,48.1734],[-96.8038,48.1734],[-96.7932,48.1733],[-96.7821,48.1734],[-96.7821,48.1734],[-96.7819,48.1734],[-96.7613,48.1734],[-96.7606,48.1734],[-96.7605,48.1734],[-96.7581,48.1734],[-96.7573,48.1734],[-96.7503,48.1734],[-96.7393,48.1734],[-96.7393,48.1734],[-96.7177,48.1734],[-96.7176,48.1734],[-96.6959,48.1734],[-96.6958,48.1734],[-96.6826,48.1735],[-96.6742,48.1736],[-96.6742,48.1736],[-96.6525,48.1738],[-96.6525,48.1738],[-96.6407,48.1739],[-96.6378,48.1738],[-96.6338,48.1737],[-96.6309,48.1737],[-96.6307,48.1737],[-96.6307,48.1737],[-96.6253,48.1737],[-96.6106,48.1737],[-96.6092,48.1737],[-96.609,48.1737],[-96.6055,48.1737],[-96.5966,48.1737],[-96.5893,48.1737],[-96.5875,48.1737],[-96.5873,48.1737],[-96.5873,48.1737],[-96.5838,48.1738],[-96.5806,48.1739],[-96.5765,48.1739],[-96.5748,48.1739],[-96.5715,48.1739],[-96.5678,48.174],[-96.5655,48.174],[-96.5654,48.174],[-96.565,48.174],[-96.5616,48.1739],[-96.557,48.1739],[-96.5544,48.1738],[-96.5507,48.1738],[-96.5479,48.1738],[-96.5446,48.1738],[-96.5443,48.1738],[-96.5442,48.1738],[-96.5434,48.1738],[-96.5399,48.1738],[-96.5357,48.1738],[-96.53,48.1738],[-96.5251,48.1738],[-96.5223,48.1739],[-96.5204,48.1739],[-96.5164,48.1739],[-96.5091,48.174],[-96.5038,48.174],[-96.5008,48.1742],[-96.5008,48.1669],[-96.5008,48.1524],[-96.5006,48.1379],[-96.5007,48.1234],[-96.501,48.1089],[-96.5009,48.0943],[-96.5009,48.0798],[-96.5009,48.0654],[-96.5008,48.0506],[-96.5009,48.0362],[-96.5009,48.0217],[-96.4826,48.0217],[-96.4826,48.0072],[-96.4824,47.9924],[-96.4823,47.9782],[-96.4823,47.9636],[-96.4825,47.949],[-96.4826,47.9347],[-96.4825,47.9202],[-96.4825,47.9055],[-96.4825,47.9054],[-96.4824,47.8913],[-96.4827,47.8768],[-96.4821,47.862],[-96.482,47.8475],[-96.4601,47.8475],[-96.4386,47.8476],[-96.4172,47.8475],[-96.3958,47.8475],[-96.3742,47.8474],[-96.3527,47.8473],[-96.3524,47.8329],[-96.3523,47.8184],[-96.3521,47.8038],[-96.352,47.7893],[-96.3519,47.7748],[-96.3516,47.7604],[-96.3313,47.7603],[-96.3097,47.7601],[-96.2884,47.7601],[-96.2668,47.7599],[-96.2453,47.7598],[-96.2238,47.7598],[-96.2022,47.7597],[-96.1806,47.7598],[-96.159,47.7598],[-96.1388,47.7598],[-96.1175,47.7602],[-96.0957,47.76],[-96.0743,47.7601],[-96.053,47.7603],[-96.0315,47.7605],[-96.0097,47.7605],[-95.9883,47.7605],[-95.9671,47.7605],[-95.9452,47.7606],[-95.9233,47.7607],[-95.9017,47.7609],[-95.8801,47.7608],[-95.8588,47.7609],[-95.8372,47.7609],[-95.8371,47.7755],[-95.8365,47.79],[-95.8366,47.8043],[-95.8366,47.819],[-95.8367,47.8335],[-95.8366,47.8482],[-95.8153,47.8484],[-95.7952,47.8483],[-95.7737,47.8484],[-95.7525,47.8485],[-95.7307,47.8487],[-95.709,47.8486],[-95.7089,47.863],[-95.7094,47.8776],[-95.7095,47.8919],[-95.7094,47.9065],[-95.7098,47.9211],[-95.7096,47.9355],[-95.6898,47.9354],[-95.6683,47.9351],[-95.6466,47.9348],[-95.6252,47.9344],[-95.6034,47.9341],[-95.5824,47.9339],[-95.5817,47.9195],[-95.5816,47.9051],[-95.5814,47.8904],[-95.5813,47.876],[-95.5812,47.8617],[-95.5809,47.847],[-95.5805,47.8327],[-95.5804,47.8183],[-95.5801,47.8039],[-95.5796,47.7894],[-95.5796,47.775],[-95.5799,47.7605],[-95.5795,47.746],[-95.5793,47.7314],[-95.5789,47.7171],[-95.5789,47.7027],[-95.5787,47.6882],[-95.5785,47.6738],[-95.5785,47.6737],[-95.5755,47.6737],[-95.5595,47.6737],[-95.5535,47.6737],[-95.5537,47.6592],[-95.5536,47.6447],[-95.5535,47.6302],[-95.5538,47.6161],[-95.5536,47.6014],[-95.5537,47.5869],[-95.5538,47.5724],[-95.5538,47.5579],[-95.5539,47.5436],[-95.5539,47.5289],[-95.5539,47.5146],[-95.5513,47.5001],[-95.5516,47.5001],[-95.5729,47.5001],[-95.5942,47.4999],[-95.6158,47.4997],[-95.6366,47.4996],[-95.6393,47.4996],[-95.6411,47.4996],[-95.6584,47.4995],[-95.6605,47.4995],[-95.6782,47.4997],[-95.6818,47.4997],[-95.6908,47.4997],[-95.6996,47.4997],[-95.7033,47.4997],[-95.7211,47.4996],[-95.7247,47.4995],[-95.7424,47.4995],[-95.7459,47.4995],[-95.7537,47.4995],[-95.7634,47.4995],[-95.7675,47.4995],[-95.7851,47.4994],[-95.7888,47.4994],[-95.7965,47.4994],[-95.8053,47.4994],[-95.8103,47.4994],[-95.8266,47.4995],[-95.8272,47.4995],[-95.8316,47.4995],[-95.8371,47.4995],[-95.8482,47.4995],[-95.8529,47.4995],[-95.8696,47.4995],[-95.8746,47.4994],[-95.8908,47.4993],[-95.8954,47.4993],[-95.9123,47.4992],[-95.9169,47.4992],[-95.9332,47.4992],[-95.9383,47.4992],[-95.9549,47.4992],[-95.9603,47.4992],[-95.9761,47.4992],[-95.9818,47.4992],[-95.9977,47.4992],[-95.9991,47.4992],[-96.0032,47.4992],[-96.019,47.4993],[-96.0247,47.4993],[-96.0362,47.4992],[-96.0408,47.4992],[-96.0462,47.4992],[-96.0676,47.4992],[-96.0888,47.4993],[-96.1101,47.4993],[-96.1314,47.4996],[-96.1526,47.4997],[-96.1739,47.4999],[-96.1954,47.4999],[-96.2166,47.4999],[-96.238,47.4998],[-96.2594,47.4998],[-96.2808,47.4998],[-96.3022,47.4999],[-96.3232,47.4999],[-96.3448,47.4997],[-96.3659,47.4997],[-96.3873,47.4997],[-96.4088,47.4996],[-96.4301,47.4996],[-96.4517,47.4994],[-96.4731,47.4993],[-96.4944,47.4993],[-96.516,47.4991],[-96.5371,47.4991],[-96.5587,47.499],[-96.5801,47.499],[-96.6013,47.4989],[-96.6229,47.499],[-96.6442,47.4992],[-96.6653,47.499],[-96.6876,47.4987],[-96.7085,47.4989],[-96.73,47.4989],[-96.7515,47.4989],[-96.7732,47.4989],[-96.7945,47.499],[-96.8159,47.499],[-96.8361,47.4989],[-96.8487,47.4989],[-96.8488,47.499],[-96.8504,47.5],[-96.8506,47.5],[-96.8507,47.5],[-96.8514,47.5004],[-96.8524,47.5006],[-96.853,47.501],[-96.8533,47.5014],[-96.8534,47.5017],[-96.8535,47.5023],[-96.8535,47.5034],[-96.8532,47.5039],[-96.8532,47.5042],[-96.8531,47.5045],[-96.8528,47.5053],[-96.8528,47.5059],[-96.8529,47.506],[-96.853,47.5065],[-96.853,47.5069],[-96.8526,47.5073],[-96.8524,47.5075],[-96.8518,47.5076],[-96.8515,47.5076],[-96.8508,47.5074],[-96.8494,47.5068],[-96.8485,47.5066],[-96.8471,47.5066],[-96.846,47.5067],[-96.8443,47.5071],[-96.8436,47.5074],[-96.8424,47.5083],[-96.8422,47.5086],[-96.8421,47.5091],[-96.8424,47.5094],[-96.8431,47.51],[-96.8439,47.5103],[-96.8448,47.5105],[-96.8464,47.5105],[-96.849,47.5098],[-96.8504,47.5096],[-96.8512,47.5096],[-96.8519,47.5098],[-96.8526,47.5102],[-96.853,47.5106],[-96.8531,47.5107],[-96.8533,47.5112],[-96.8534,47.5112],[-96.8534,47.5113],[-96.8535,47.5113],[-96.8536,47.5119],[-96.8536,47.512],[-96.8532,47.5126],[-96.8531,47.5128],[-96.8525,47.5132],[-96.8517,47.5135],[-96.8514,47.5135],[-96.851,47.5136],[-96.8502,47.5135],[-96.8491,47.5134],[-96.8465,47.5124],[-96.846,47.5123],[-96.8448,47.5124],[-96.8442,47.5125],[-96.8435,47.5128],[-96.843,47.5132],[-96.8428,47.5134],[-96.8425,47.5137],[-96.8422,47.5141],[-96.842,47.5146],[-96.842,47.5155],[-96.842,47.5156],[-96.842,47.5157],[-96.8421,47.5158],[-96.8422,47.516],[-96.8427,47.5164],[-96.8433,47.5167],[-96.8442,47.517],[-96.8454,47.5172],[-96.8465,47.517],[-96.8475,47.5166],[-96.8481,47.5163],[-96.8501,47.5155],[-96.8519,47.515],[-96.8532,47.5146],[-96.8542,47.5144],[-96.8547,47.5144],[-96.8563,47.5146],[-96.8573,47.5147],[-96.8584,47.5149],[-96.8599,47.5153],[-96.8614,47.5159],[-96.8624,47.5164],[-96.8629,47.5169],[-96.8632,47.5173],[-96.8633,47.5177],[-96.8633,47.5198],[-96.8635,47.5204],[-96.8636,47.5206],[-96.8643,47.5213],[-96.8645,47.5216],[-96.8656,47.5225],[-96.8658,47.5229],[-96.866,47.523],[-96.8663,47.5238],[-96.8664,47.5249],[-96.8666,47.5254],[-96.8672,47.5259],[-96.8676,47.5261],[-96.8683,47.5262],[-96.8698,47.5264],[-96.8705,47.5266],[-96.8707,47.5268],[-96.8708,47.5269],[-96.8709,47.5272],[-96.8709,47.5273],[-96.8709,47.5279],[-96.8706,47.5283],[-96.8704,47.5284],[-96.87,47.5287],[-96.8691,47.529],[-96.868,47.5291],[-96.8665,47.5291],[-96.865,47.529],[-96.8623,47.5291],[-96.861,47.5294],[-96.8605,47.5296],[-96.8593,47.5304],[-96.8589,47.5308],[-96.8576,47.5328],[-96.8573,47.5333],[-96.8568,47.5337],[-96.8558,47.5346],[-96.8543,47.5354],[-96.854,47.5357],[-96.8535,47.5363],[-96.8534,47.5372],[-96.8536,47.5378],[-96.854,47.5382],[-96.8546,47.5383],[-96.8558,47.5382],[-96.8569,47.5379],[-96.8573,47.5377],[-96.8579,47.5375],[-96.8589,47.5371],[-96.8593,47.5371],[-96.8599,47.5371],[-96.8609,47.5374],[-96.8619,47.5379],[-96.8629,47.5387],[-96.8632,47.5391],[-96.8634,47.5395],[-96.8634,47.5402],[-96.8628,47.5409],[-96.8614,47.5414],[-96.858,47.542],[-96.8573,47.5421],[-96.8565,47.5422],[-96.8555,47.5421],[-96.8542,47.5418],[-96.8533,47.5413],[-96.8523,47.5407],[-96.8519,47.5401],[-96.8516,47.5397],[-96.8514,47.5393],[-96.8513,47.5393],[-96.8512,47.539],[-96.8511,47.5388],[-96.851,47.5386],[-96.8507,47.5383],[-96.8507,47.5382],[-96.8501,47.5377],[-96.8494,47.5374],[-96.8484,47.5372],[-96.8477,47.5371],[-96.8471,47.5372],[-96.8465,47.5374],[-96.8457,47.538],[-96.8452,47.5386],[-96.8452,47.5394],[-96.8452,47.5397],[-96.8454,47.5399],[-96.8455,47.5403],[-96.8456,47.5404],[-96.8456,47.5405],[-96.846,47.541],[-96.8467,47.5415],[-96.8484,47.5425],[-96.8501,47.5432],[-96.8525,47.5438],[-96.8571,47.5448],[-96.8572,47.5448],[-96.8586,47.5452],[-96.8597,47.5456],[-96.8602,47.5459],[-96.8603,47.5461],[-96.8603,47.5464],[-96.8602,47.5466],[-96.8599,47.5468],[-96.8596,47.547],[-96.8585,47.5472],[-96.8576,47.5477],[-96.8572,47.5479],[-96.8554,47.5485],[-96.8542,47.5488],[-96.8538,47.5491],[-96.8523,47.5504],[-96.8505,47.5517],[-96.8501,47.5521],[-96.8499,47.5526],[-96.8497,47.5532],[-96.85,47.5537],[-96.8501,47.5538],[-96.8501,47.5539],[-96.8506,47.5543],[-96.8513,47.5546],[-96.8526,47.5549],[-96.8546,47.5551],[-96.8558,47.5551],[-96.857,47.5553],[-96.8578,47.5556],[-96.8588,47.5562],[-96.8598,47.5571],[-96.8602,47.5576],[-96.8605,47.5578],[-96.8606,47.5581],[-96.8608,47.5582],[-96.8612,47.5588],[-96.8614,47.5592],[-96.8614,47.5599],[-96.8613,47.5602],[-96.8608,47.5604],[-96.8601,47.5607],[-96.8594,47.5607],[-96.8581,47.5605],[-96.8573,47.5602],[-96.8569,47.5601],[-96.8567,47.5601],[-96.8553,47.5602],[-96.8544,47.5603],[-96.8537,47.5606],[-96.8515,47.5621],[-96.8506,47.5626],[-96.8491,47.5636],[-96.8484,47.564],[-96.8476,47.5646],[-96.8474,47.565],[-96.8472,47.5656],[-96.8472,47.5661],[-96.8474,47.5663],[-96.8479,47.5666],[-96.8487,47.5667],[-96.8498,47.5665],[-96.8503,47.5664],[-96.8513,47.5658],[-96.852,47.5656],[-96.8541,47.5653],[-96.856,47.5649],[-96.8568,47.5646],[-96.8575,47.5643],[-96.8599,47.5632],[-96.8612,47.5628],[-96.8622,47.5626],[-96.8628,47.5626],[-96.864,47.5627],[-96.8652,47.5631],[-96.8661,47.5636],[-96.8666,47.564],[-96.8676,47.5651],[-96.8678,47.5654],[-96.868,47.5655],[-96.8685,47.5663],[-96.8685,47.5664],[-96.8686,47.5665],[-96.8687,47.5668],[-96.8688,47.5669],[-96.8687,47.5677],[-96.8684,47.5682],[-96.8675,47.5688],[-96.8661,47.5695],[-96.8656,47.5696],[-96.8647,47.5694],[-96.8639,47.569],[-96.8629,47.5687],[-96.8616,47.5684],[-96.861,47.5682],[-96.8607,47.568],[-96.8599,47.5676],[-96.8588,47.5672],[-96.8578,47.5671],[-96.8567,47.5671],[-96.8555,47.5671],[-96.8539,47.5675],[-96.8529,47.5678],[-96.8519,47.5684],[-96.8514,47.569],[-96.8515,47.5698],[-96.8517,47.5703],[-96.8521,47.5709],[-96.8529,47.5715],[-96.8531,47.5716],[-96.8537,47.5719],[-96.8549,47.5725],[-96.8566,47.5731],[-96.8571,47.5733],[-96.8595,47.574],[-96.8602,47.5744],[-96.8604,47.5746],[-96.8604,47.575],[-96.8599,47.5752],[-96.8589,47.5754],[-96.8585,47.5756],[-96.8573,47.5763],[-96.8565,47.5767],[-96.8553,47.5773],[-96.8543,47.578],[-96.8534,47.5792],[-96.8532,47.5795],[-96.853,47.5802],[-96.853,47.5805],[-96.8528,47.5809],[-96.8529,47.5822],[-96.853,47.5826],[-96.8532,47.5826],[-96.8532,47.5833],[-96.8531,47.5837],[-96.8526,47.5844],[-96.8527,47.5845],[-96.8525,47.5846],[-96.852,47.585],[-96.852,47.5851],[-96.8515,47.5859],[-96.8515,47.586],[-96.8513,47.5869],[-96.8512,47.5873],[-96.8511,47.5878],[-96.851,47.5881],[-96.8507,47.5888],[-96.8502,47.5898],[-96.85,47.5903],[-96.8499,47.591],[-96.8501,47.5916],[-96.8503,47.5919],[-96.8511,47.5925],[-96.8517,47.5927],[-96.8538,47.593],[-96.8549,47.5934],[-96.8562,47.5939],[-96.8575,47.5943],[-96.8582,47.5947],[-96.8586,47.5949],[-96.8588,47.5954],[-96.8588,47.5958],[-96.8584,47.5962],[-96.8575,47.5963],[-96.8562,47.5962],[-96.8542,47.596],[-96.853,47.5961],[-96.8521,47.5964],[-96.8515,47.5968],[-96.8511,47.5973],[-96.8509,47.5977],[-96.8509,47.5983],[-96.8511,47.5989],[-96.8515,47.5993],[-96.8521,47.5997],[-96.8528,47.6],[-96.8536,47.6003],[-96.8545,47.6004],[-96.8556,47.6009],[-96.8561,47.6014],[-96.8564,47.6016],[-96.8567,47.602],[-96.8569,47.6024],[-96.8568,47.6031],[-96.8565,47.6035],[-96.8562,47.6039],[-96.8553,47.6051],[-96.8549,47.6058],[-96.8548,47.6064],[-96.8548,47.6073],[-96.8549,47.6075],[-96.855,47.6079],[-96.855,47.608],[-96.8554,47.6088],[-96.8557,47.6093],[-96.8558,47.6094],[-96.8561,47.6098],[-96.8563,47.61],[-96.8571,47.6108],[-96.858,47.6115],[-96.8589,47.612],[-96.8602,47.6122],[-96.8612,47.6124],[-96.8646,47.6124],[-96.8655,47.6125],[-96.8664,47.6129],[-96.8672,47.6136],[-96.8673,47.6138],[-96.8675,47.6139],[-96.8676,47.6141],[-96.8679,47.6144],[-96.8686,47.6148],[-96.869,47.615],[-96.8694,47.615],[-96.8703,47.6147],[-96.871,47.6143],[-96.8714,47.6139],[-96.8719,47.6136],[-96.8723,47.6135],[-96.8729,47.6135],[-96.8736,47.6137],[-96.8739,47.614],[-96.874,47.6141],[-96.874,47.6148],[-96.8739,47.6149],[-96.8736,47.6154],[-96.8726,47.6159],[-96.8715,47.6165],[-96.871,47.6169],[-96.8706,47.6176],[-96.8708,47.6181],[-96.8712,47.6183],[-96.8717,47.6184],[-96.8727,47.6184],[-96.8753,47.6191],[-96.8763,47.6192],[-96.8778,47.6189],[-96.878,47.6189],[-96.879,47.6189],[-96.8796,47.6191],[-96.88,47.6195],[-96.88,47.62],[-96.8794,47.6206],[-96.8783,47.6213],[-96.8779,47.6215],[-96.8769,47.6219],[-96.8763,47.6223],[-96.876,47.6228],[-96.8758,47.623],[-96.876,47.6235],[-96.8761,47.6237],[-96.8768,47.6243],[-96.8775,47.6244],[-96.878,47.6245],[-96.8792,47.6246],[-96.88,47.6247],[-96.8803,47.625],[-96.8806,47.6254],[-96.8807,47.6255],[-96.8807,47.6259],[-96.8804,47.6262],[-96.8798,47.6266],[-96.8792,47.6267],[-96.8786,47.6267],[-96.878,47.6267],[-96.8767,47.6266],[-96.8753,47.6267],[-96.8748,47.6269],[-96.8745,47.6272],[-96.8745,47.6275],[-96.8745,47.628],[-96.8747,47.6283],[-96.8753,47.6287],[-96.8765,47.629],[-96.8774,47.6289],[-96.8781,47.6289],[-96.8787,47.6289],[-96.8795,47.6289],[-96.8801,47.6289],[-96.8806,47.6291],[-96.881,47.6294],[-96.8815,47.6299],[-96.8815,47.6299],[-96.8815,47.63],[-96.8816,47.6301],[-96.8818,47.6305],[-96.8818,47.631],[-96.8819,47.6311],[-96.882,47.6324],[-96.8822,47.6333],[-96.8823,47.6334],[-96.8823,47.6335],[-96.8827,47.6339],[-96.8852,47.6356],[-96.8876,47.6376],[-96.8878,47.6379],[-96.8885,47.6385],[-96.8885,47.6393],[-96.8884,47.6395],[-96.8881,47.6398],[-96.8874,47.6401],[-96.886,47.6405],[-96.8845,47.6408],[-96.8835,47.6412],[-96.8832,47.6414],[-96.8828,47.6418],[-96.8826,47.6422],[-96.8826,47.6429],[-96.8829,47.6439],[-96.8829,47.6441],[-96.8829,47.6447],[-96.8828,47.6451],[-96.8827,47.6462],[-96.8825,47.6471],[-96.8823,47.6491],[-96.8826,47.6498],[-96.8828,47.6502],[-96.8837,47.6509],[-96.8844,47.6513],[-96.8846,47.6513],[-96.8847,47.6515],[-96.8862,47.6523],[-96.8866,47.6526],[-96.8869,47.6531],[-96.887,47.6533],[-96.887,47.6543],[-96.8868,47.6548],[-96.8869,47.6556],[-96.887,47.656],[-96.8876,47.6577],[-96.8876,47.6585],[-96.8876,47.6589],[-96.8873,47.6596],[-96.8869,47.6601],[-96.8857,47.6616],[-96.8855,47.6624],[-96.8855,47.6635],[-96.8857,47.6643],[-96.8862,47.6652],[-96.8863,47.6653],[-96.8863,47.6654],[-96.8864,47.6656],[-96.8864,47.6656],[-96.8871,47.6664],[-96.8889,47.668],[-96.8896,47.6686],[-96.8897,47.669],[-96.8898,47.669],[-96.8899,47.6693],[-96.89,47.6694],[-96.8901,47.67],[-96.8899,47.6703],[-96.8897,47.6707],[-96.8883,47.6715],[-96.8871,47.6721],[-96.8868,47.6722],[-96.8863,47.6725],[-96.8859,47.6727],[-96.8856,47.6727],[-96.8855,47.6729],[-96.8853,47.6732],[-96.8851,47.6735],[-96.8852,47.6737],[-96.8852,47.6738],[-96.8853,47.6739],[-96.8857,47.6742],[-96.8863,47.6743],[-96.8867,47.6743],[-96.8874,47.6743],[-96.8886,47.674],[-96.8892,47.6738],[-96.8908,47.6734],[-96.8919,47.6732],[-96.8935,47.6732],[-96.8946,47.6734],[-96.8952,47.6736],[-96.8955,47.6738],[-96.8964,47.6745],[-96.8967,47.6748],[-96.8968,47.6751],[-96.8967,47.6759],[-96.8964,47.6768],[-96.8963,47.6772],[-96.8962,47.6775],[-96.8961,47.6776],[-96.8961,47.6785],[-96.8963,47.6792],[-96.8964,47.6793],[-96.8964,47.6794],[-96.8965,47.6796],[-96.8968,47.6802],[-96.8971,47.6804],[-96.8971,47.6806],[-96.8972,47.6806],[-96.8973,47.681],[-96.8974,47.6811],[-96.8974,47.6812],[-96.8975,47.6813],[-96.8977,47.6817],[-96.8978,47.6818],[-96.8978,47.682],[-96.8984,47.6834],[-96.8986,47.6837],[-96.8986,47.684],[-96.8987,47.6841],[-96.8989,47.6846],[-96.899,47.6847],[-96.899,47.685],[-96.8993,47.686],[-96.8992,47.6871],[-96.8992,47.688],[-96.8992,47.6883],[-96.8992,47.6887],[-96.8993,47.6895],[-96.8995,47.69],[-96.8996,47.6901],[-96.8997,47.6903],[-96.9002,47.6908],[-96.9011,47.6914],[-96.9017,47.6917],[-96.9022,47.6918],[-96.9029,47.6916],[-96.9035,47.6913],[-96.9039,47.6909],[-96.9047,47.6898],[-96.9052,47.6893],[-96.906,47.6889],[-96.9072,47.6885],[-96.9081,47.6885],[-96.9089,47.6888],[-96.9095,47.6892],[-96.9098,47.6896],[-96.9101,47.69],[-96.9101,47.6913],[-96.9099,47.6916],[-96.9098,47.692],[-96.9091,47.6926],[-96.9077,47.6934],[-96.9074,47.6937],[-96.9072,47.694],[-96.9072,47.6947],[-96.9076,47.6952],[-96.9077,47.6954],[-96.9083,47.6961],[-96.9092,47.6968],[-96.9097,47.6974],[-96.9101,47.698],[-96.9102,47.6982],[-96.9103,47.6985],[-96.9103,47.6986],[-96.9104,47.6986],[-96.9106,47.6989],[-96.9107,47.6991],[-96.9107,47.6993],[-96.9115,47.7006],[-96.912,47.7012],[-96.9125,47.7017],[-96.9128,47.7018],[-96.9132,47.7019],[-96.914,47.7018],[-96.9145,47.7016],[-96.9155,47.7009],[-96.9169,47.6998],[-96.9177,47.6994],[-96.9184,47.6991],[-96.9193,47.6991],[-96.9202,47.6993],[-96.9207,47.6996],[-96.9208,47.6998],[-96.9208,47.6999],[-96.921,47.7],[-96.9211,47.7003],[-96.9211,47.7008],[-96.9208,47.7013],[-96.9204,47.7017],[-96.9194,47.7026],[-96.919,47.7028],[-96.9187,47.703],[-96.9176,47.7034],[-96.9172,47.7035],[-96.9164,47.7034],[-96.9155,47.7035],[-96.9145,47.7038],[-96.9137,47.7042],[-96.9132,47.7047],[-96.9128,47.7052],[-96.9123,47.7058],[-96.9119,47.7066],[-96.912,47.7075],[-96.9122,47.7079],[-96.9129,47.7083],[-96.9134,47.7084],[-96.9146,47.7085],[-96.9163,47.7086],[-96.9175,47.7089],[-96.919,47.7095],[-96.9198,47.71],[-96.9201,47.7104],[-96.9201,47.7105],[-96.9202,47.7107],[-96.9204,47.7111],[-96.9204,47.712],[-96.9203,47.7124],[-96.9197,47.7137],[-96.9195,47.7139],[-96.9194,47.7142],[-96.9192,47.7146],[-96.9191,47.7149],[-96.9191,47.7156],[-96.9197,47.7166],[-96.9201,47.7171],[-96.9206,47.7174],[-96.9209,47.7176],[-96.9216,47.7178],[-96.9224,47.718],[-96.9232,47.7179],[-96.9238,47.7176],[-96.9241,47.7174],[-96.9245,47.7171],[-96.9247,47.7167],[-96.9248,47.7166],[-96.9248,47.7164],[-96.9251,47.7162],[-96.9252,47.716],[-96.926,47.7153],[-96.9266,47.7149],[-96.9277,47.7144],[-96.9284,47.7143],[-96.929,47.7143],[-96.93,47.7145],[-96.9305,47.7148],[-96.931,47.7153],[-96.931,47.7154],[-96.9311,47.7154],[-96.9312,47.716],[-96.9312,47.7166],[-96.9308,47.7174],[-96.9308,47.7175],[-96.9305,47.7179],[-96.93,47.7183],[-96.9287,47.7187],[-96.9271,47.719],[-96.9251,47.7197],[-96.9237,47.7202],[-96.9217,47.7211],[-96.9205,47.7218],[-96.9194,47.7226],[-96.9193,47.7227],[-96.9189,47.7231],[-96.9187,47.7234],[-96.9185,47.7239],[-96.9187,47.7243],[-96.9188,47.7244],[-96.9188,47.7245],[-96.9191,47.7248],[-96.9197,47.7251],[-96.9203,47.7253],[-96.9224,47.7256],[-96.9236,47.7259],[-96.9242,47.7262],[-96.9246,47.7267],[-96.9248,47.7272],[-96.925,47.7275],[-96.925,47.7291],[-96.9253,47.7299],[-96.9255,47.7302],[-96.9257,47.7304],[-96.9273,47.7316],[-96.9279,47.7321],[-96.9283,47.7325],[-96.9305,47.7344],[-96.9314,47.7353],[-96.9319,47.7359],[-96.9323,47.7365],[-96.9324,47.7366],[-96.9325,47.7368],[-96.9327,47.7371],[-96.9328,47.7372],[-96.9332,47.7383],[-96.9333,47.7388],[-96.9332,47.7395],[-96.933,47.74],[-96.9327,47.7403],[-96.9319,47.741],[-96.9318,47.7411],[-96.9308,47.7417],[-96.9302,47.7422],[-96.9293,47.743],[-96.929,47.7435],[-96.9287,47.7442],[-96.9285,47.7449],[-96.9284,47.7454],[-96.9284,47.7465],[-96.9285,47.7481],[-96.9286,47.7491],[-96.9288,47.7493],[-96.9289,47.7497],[-96.929,47.7497],[-96.9289,47.75],[-96.929,47.7504],[-96.9298,47.751],[-96.9308,47.7515],[-96.9322,47.7521],[-96.9332,47.7526],[-96.9351,47.7532],[-96.9387,47.754],[-96.9394,47.7544],[-96.9398,47.7549],[-96.9397,47.7555],[-96.9394,47.7559],[-96.9388,47.7562],[-96.9381,47.7563],[-96.9373,47.7563],[-96.9363,47.7562],[-96.9337,47.7551],[-96.9327,47.7548],[-96.9323,47.7548],[-96.9311,47.7547],[-96.9297,47.7549],[-96.9291,47.755],[-96.9289,47.7553],[-96.9288,47.7558],[-96.9291,47.7561],[-96.9298,47.7565],[-96.9309,47.7569],[-96.9324,47.7573],[-96.9335,47.7576],[-96.9355,47.7583],[-96.9368,47.759],[-96.9369,47.7592],[-96.9371,47.7594],[-96.9372,47.7595],[-96.9378,47.7602],[-96.9379,47.7604],[-96.9381,47.7607],[-96.9381,47.7609],[-96.9382,47.7609],[-96.9382,47.761],[-96.9384,47.7614],[-96.9384,47.7625],[-96.938,47.7632],[-96.9376,47.7639],[-96.9369,47.7646],[-96.9366,47.7649],[-96.9352,47.7658],[-96.9351,47.766],[-96.9349,47.7664],[-96.9348,47.7668],[-96.9349,47.7671],[-96.9357,47.7676],[-96.9365,47.7678],[-96.9382,47.7681],[-96.9391,47.7684],[-96.9404,47.7692],[-96.9423,47.7708],[-96.943,47.7712],[-96.9442,47.7717],[-96.9445,47.7717],[-96.9445,47.7719],[-96.9452,47.7722],[-96.9457,47.7727],[-96.9458,47.7729],[-96.9459,47.7734],[-96.9459,47.7743],[-96.946,47.7746],[-96.9466,47.775],[-96.9473,47.7753],[-96.9483,47.7755],[-96.9494,47.7753],[-96.9495,47.7753],[-96.9518,47.7747],[-96.9527,47.7746],[-96.9537,47.7746],[-96.9539,47.7747],[-96.955,47.7748],[-96.956,47.7751],[-96.9565,47.7753],[-96.9567,47.7757],[-96.9567,47.7761],[-96.9566,47.7762],[-96.9544,47.7777],[-96.9538,47.778],[-96.9527,47.7787],[-96.9523,47.779],[-96.9522,47.7793],[-96.9524,47.7796],[-96.9527,47.7799],[-96.9533,47.78],[-96.9538,47.78],[-96.9554,47.7798],[-96.9565,47.7798],[-96.9573,47.78],[-96.9584,47.7803],[-96.9589,47.7807],[-96.9593,47.7812],[-96.9593,47.7819],[-96.9592,47.7819],[-96.9578,47.7838],[-96.9576,47.7844],[-96.9575,47.7847],[-96.9575,47.7852],[-96.9578,47.7855],[-96.9581,47.7856],[-96.9584,47.7857],[-96.959,47.7855],[-96.9596,47.7849],[-96.9597,47.7847],[-96.9598,47.7847],[-96.9598,47.7846],[-96.9601,47.7843],[-96.961,47.7838],[-96.9619,47.7833],[-96.9631,47.783],[-96.9638,47.783],[-96.9644,47.783],[-96.9649,47.7833],[-96.9653,47.7835],[-96.9654,47.7839],[-96.9653,47.785],[-96.9651,47.7853],[-96.965,47.7855],[-96.9645,47.7862],[-96.9635,47.7873],[-96.9628,47.7879],[-96.9621,47.7884],[-96.9615,47.7888],[-96.9599,47.7893],[-96.9586,47.7896],[-96.958,47.7898],[-96.9576,47.79],[-96.9572,47.7902],[-96.9571,47.7904],[-96.9572,47.791],[-96.9573,47.7913],[-96.9574,47.7915],[-96.9578,47.7921],[-96.9584,47.7925],[-96.9597,47.7931],[-96.9627,47.7942],[-96.9635,47.7947],[-96.9642,47.7951],[-96.965,47.7959],[-96.9657,47.7968],[-96.966,47.7973],[-96.9661,47.7992],[-96.9662,47.7993],[-96.9663,47.7994],[-96.9669,47.7998],[-96.9674,47.7999],[-96.9681,47.7998],[-96.9687,47.7996],[-96.9689,47.7995],[-96.9702,47.7987],[-96.9716,47.7983],[-96.974,47.7978],[-96.9751,47.7978],[-96.9754,47.7978],[-96.9762,47.7979],[-96.9766,47.7981],[-96.9768,47.7983],[-96.977,47.7986],[-96.977,47.8],[-96.9764,47.8013],[-96.9761,47.8016],[-96.9759,47.8017],[-96.9754,47.8019],[-96.9751,47.8019],[-96.973,47.8019],[-96.9723,47.802],[-96.9721,47.8022],[-96.9719,47.8025],[-96.9721,47.8029],[-96.973,47.8034],[-96.974,47.8036],[-96.9749,47.8037],[-96.9751,47.8037],[-96.9769,47.8037],[-96.9789,47.804],[-96.9796,47.8042],[-96.981,47.8045],[-96.9818,47.8046],[-96.9826,47.805],[-96.9828,47.8051],[-96.9831,47.8051],[-96.9832,47.8053],[-96.9851,47.8065],[-96.9859,47.8069],[-96.9863,47.8071],[-96.9877,47.8072],[-96.9894,47.8072],[-96.9905,47.8076],[-96.991,47.8078],[-96.9914,47.8081],[-96.9916,47.8085],[-96.9916,47.8091],[-96.9912,47.8094],[-96.9903,47.8097],[-96.9891,47.8099],[-96.9882,47.8099],[-96.9864,47.8098],[-96.9818,47.8091],[-96.9805,47.8092],[-96.9796,47.8095],[-96.9788,47.8099],[-96.9782,47.8106],[-96.978,47.8112],[-96.9779,47.8117],[-96.9781,47.8122],[-96.9784,47.8128],[-96.9786,47.8129],[-96.9787,47.8131],[-96.9795,47.8138],[-96.9795,47.8139],[-96.9798,47.8143],[-96.9799,47.8145],[-96.9799,47.8146],[-96.9803,47.8157],[-96.9804,47.8187],[-96.9804,47.822],[-96.9802,47.8224],[-96.9797,47.8226],[-96.979,47.8226],[-96.9772,47.8222],[-96.9764,47.8221],[-96.9759,47.8221],[-96.9754,47.8222],[-96.9747,47.8224],[-96.9745,47.8224],[-96.9744,47.8225],[-96.9741,47.8228],[-96.9741,47.8234],[-96.9743,47.8239],[-96.9749,47.8244],[-96.9757,47.825],[-96.9759,47.825],[-96.9769,47.8254],[-96.9783,47.8256],[-96.9793,47.8257],[-96.982,47.8255],[-96.9845,47.8251],[-96.9857,47.8251],[-96.9865,47.8252],[-96.9869,47.8254],[-96.9872,47.8256],[-96.9871,47.8261],[-96.9867,47.8265],[-96.9858,47.8269],[-96.984,47.8275],[-96.9827,47.8281],[-96.9825,47.8283],[-96.9819,47.8287],[-96.9817,47.829],[-96.9815,47.8295],[-96.9816,47.8301],[-96.9817,47.8305],[-96.982,47.8309],[-96.9843,47.8325],[-96.9848,47.8331],[-96.9849,47.8332],[-96.9849,47.8333],[-96.985,47.8334],[-96.9852,47.8339],[-96.9853,47.8344],[-96.9854,47.8345],[-96.9857,47.8359],[-96.9859,47.8361],[-96.9859,47.8366],[-96.9863,47.8373],[-96.9866,47.8377],[-96.9873,47.8379],[-96.9881,47.838],[-96.9896,47.8381],[-96.9907,47.838],[-96.9915,47.8378],[-96.9924,47.8378],[-96.9929,47.838],[-96.9937,47.8383],[-96.9941,47.8388],[-96.9941,47.8396],[-96.994,47.8397],[-96.9935,47.8404],[-96.9929,47.8412],[-96.9925,47.8417],[-96.9924,47.8421],[-96.9924,47.8426],[-96.9927,47.8427],[-96.9931,47.8428],[-96.9938,47.8426],[-96.9956,47.842],[-96.9969,47.8416],[-96.9976,47.8416],[-96.9976,47.8435],[-96.9974,47.8437],[-96.9963,47.8444],[-96.9958,47.8447],[-96.9947,47.845],[-96.9943,47.8452],[-96.9941,47.8455],[-96.994,47.8458],[-96.9941,47.8461],[-96.9941,47.8462],[-96.9942,47.8463],[-96.9943,47.8464],[-96.9949,47.847],[-96.9956,47.8474],[-96.9967,47.848],[-96.9968,47.848],[-96.9968,47.8482],[-96.9969,47.8482],[-96.9971,47.8484],[-96.9973,47.8488],[-96.9975,47.8496],[-96.9973,47.8504],[-96.9969,47.8515],[-96.9967,47.8526],[-96.9968,47.8545],[-96.9969,47.8555],[-96.9971,47.8561],[-96.9971,47.8564],[-96.9972,47.8566],[-96.9973,47.8567],[-96.9974,47.8574],[-96.9976,47.8577],[-96.9978,47.8583],[-96.9978,47.8583],[-96.9981,47.8589],[-96.9982,47.859],[-96.9983,47.8592],[-96.9989,47.8599],[-96.9994,47.8603],[-96.9998,47.8607],[-97.0003,47.861],[-97.0017,47.8613],[-97.0031,47.8623],[-97.0055,47.864],[-97.0058,47.8653],[-97.0033,47.8659],[-97.0015,47.8674],[-97.0024,47.8687],[-97.0053,47.8702],[-97.0084,47.8708],[-97.0173,47.8716],[-97.0194,47.8722],[-97.0212,47.8726],[-97.0218,47.8731],[-97.0231,47.874],[-97.0231,47.875],[-97.0221,47.8755],[-97.0196,47.8766],[-97.0193,47.8768],[-97.0189,47.8769],[-97.0179,47.8785],[-97.0193,47.8803],[-97.022,47.8815],[-97.0233,47.8821],[-97.0253,47.8843],[-97.0253,47.8856],[-97.0249,47.8869],[-97.0222,47.8884],[-97.0194,47.8897],[-97.0191,47.8898],[-97.0189,47.8911],[-97.019,47.8912],[-97.0195,47.8915],[-97.0225,47.8933],[-97.0249,47.895],[-97.0239,47.8981],[-97.0201,47.9005],[-97.0202,47.9022],[-97.0241,47.9053],[-97.0242,47.9056],[-97.0249,47.9082],[-97.0245,47.9083],[-97.0235,47.9085],[-97.0203,47.9064],[-97.0198,47.9063],[-97.0184,47.906],[-97.0172,47.9057],[-97.015,47.9072],[-97.015,47.9073],[-97.0153,47.9103],[-97.0156,47.9108],[-97.0172,47.9131],[-97.0195,47.9141],[-97.0197,47.9142],[-97.0214,47.9147],[-97.0237,47.9159],[-97.0196,47.9175],[-97.018,47.9181],[-97.0177,47.9198],[-97.0183,47.9202],[-97.0196,47.9211],[-97.0213,47.9221],[-97.0219,47.9224],[-97.0235,47.9236],[-97.0247,47.9244],[-97.026,47.9253],[-97.0284,47.9269],[-97.0296,47.9276],[-97.0323,47.9285],[-97.0357,47.9302],[-97.0373,47.9333],[-97.0368,47.9343],[-97.0355,47.9366],[-97.036,47.9394],[-97.0374,47.9399],[-97.0391,47.9405],[-97.0394,47.9405],[-97.0416,47.9406],[-97.0417,47.9406],[-97.0449,47.9411],[-97.051,47.9434],[-97.0545,47.9463],[-97.0555,47.9491],[-97.0555,47.9491],[-97.0553,47.9502],[-97.0551,47.9508],[-97.0525,47.9548],[-97.0524,47.9572],[-97.054,47.9597],[-97.059,47.9621],[-97.0613,47.9636],[-97.0614,47.9636],[-97.0618,47.9645],[-97.0615,47.9659],[-97.06,47.9672],[-97.0578,47.969],[-97.0571,47.9705],[-97.0593,47.974],[-97.0591,47.9754],[-97.0589,47.976],[-97.0588,47.9762],[-97.0587,47.9766],[-97.0584,47.977],[-97.0582,47.9774],[-97.0579,47.9778],[-97.0577,47.9781],[-97.0577,47.9782],[-97.0574,47.9787],[-97.0571,47.9792],[-97.0567,47.9801],[-97.0564,47.9806],[-97.0563,47.9811],[-97.0561,47.9815],[-97.0559,47.9821],[-97.0556,47.9828],[-97.0554,47.9833],[-97.0553,47.9838],[-97.0552,47.9842],[-97.0549,47.9849],[-97.0546,47.9855],[-97.0544,47.986],[-97.0541,47.9866],[-97.0539,47.9871],[-97.0537,47.9877],[-97.0535,47.988],[-97.0534,47.9884],[-97.0533,47.9887],[-97.0532,47.989],[-97.053,47.9894],[-97.053,47.9898],[-97.053,47.9903],[-97.053,47.9905],[-97.0531,47.9907],[-97.0532,47.9909],[-97.0533,47.9912],[-97.0534,47.9915],[-97.0535,47.9917],[-97.0538,47.992],[-97.0541,47.9923],[-97.0543,47.9925],[-97.0545,47.9926],[-97.0549,47.993],[-97.0555,47.9933],[-97.0561,47.9936],[-97.0566,47.9938],[-97.0571,47.9939],[-97.0578,47.9941],[-97.0584,47.9943],[-97.0591,47.9945],[-97.0597,47.9948],[-97.0601,47.9949],[-97.0604,47.9951],[-97.0608,47.9953],[-97.0614,47.9956],[-97.0617,47.9957],[-97.0619,47.9959],[-97.0622,47.996],[-97.0625,47.9962],[-97.0628,47.9965],[-97.063,47.9967],[-97.0633,47.997],[-97.0637,47.9975],[-97.0639,47.9977],[-97.0641,47.9982],[-97.0642,47.9986],[-97.0644,47.9989],[-97.0644,47.9994],[-97.0645,48.0],[-97.0645,48.0004],[-97.0644,48.002],[-97.0644,48.0027],[-97.0645,48.0034],[-97.0648,48.0045],[-97.0656,48.0064],[-97.0659,48.0071],[-97.0662,48.0079],[-97.0667,48.0089],[-97.0667,48.0096],[-97.0666,48.0102],[-97.0654,48.0114],[-97.0638,48.0125],[-97.0636,48.0126],[-97.063,48.0132],[-97.0628,48.0138],[-97.0629,48.0145],[-97.0632,48.015],[-97.0638,48.0153],[-97.0649,48.0157],[-97.0685,48.016],[-97.0692,48.0162],[-97.0706,48.017],[-97.0717,48.0181],[-97.0722,48.0192],[-97.0723,48.0196],[-97.0723,48.0201],[-97.0721,48.0207],[-97.0721,48.0209],[-97.0719,48.0214],[-97.0713,48.0228],[-97.0699,48.0247],[-97.0689,48.0263],[-97.0687,48.0277],[-97.0688,48.029],[-97.0691,48.0313],[-97.0697,48.0334],[-97.07,48.0354],[-97.0701,48.0361],[-97.0699,48.0374],[-97.0704,48.0418],[-97.0712,48.0458],[-97.0719,48.0474],[-97.0722,48.0481],[-97.0732,48.0499],[-97.0732,48.05],[-97.074,48.0513],[-97.0747,48.0521],[-97.0756,48.0528],[-97.0767,48.0533],[-97.0782,48.054],[-97.0795,48.0545],[-97.0815,48.0553],[-97.0828,48.0558],[-97.084,48.0564],[-97.0845,48.0567],[-97.0859,48.0575],[-97.0869,48.0583],[-97.0881,48.0596],[-97.0892,48.0611],[-97.0905,48.0627],[-97.0905,48.0628],[-97.0908,48.0631],[-97.0919,48.0644],[-97.092,48.0644],[-97.0932,48.0653],[-97.0951,48.0669],[-97.0958,48.0677],[-97.0963,48.0688],[-97.0969,48.07],[-97.0972,48.0706],[-97.0977,48.0711],[-97.0982,48.0714],[-97.0988,48.0715],[-97.0997,48.0716],[-97.1012,48.0715],[-97.103,48.0717],[-97.1038,48.0719],[-97.1044,48.0725],[-97.1046,48.0731],[-97.1045,48.074],[-97.1041,48.0746],[-97.1007,48.0775],[-97.1005,48.078],[-97.1001,48.0788],[-97.0998,48.0799],[-97.0994,48.0822],[-97.0994,48.0838],[-97.0996,48.0849],[-97.0997,48.0859],[-97.1001,48.0869],[-97.1012,48.0884],[-97.1021,48.0892],[-97.1034,48.0898],[-97.1047,48.0902],[-97.1066,48.0904],[-97.108,48.0906],[-97.1094,48.091],[-97.1098,48.0914],[-97.1097,48.0917],[-97.1095,48.0922],[-97.1087,48.0928],[-97.1067,48.0934],[-97.1066,48.0934],[-97.104,48.0939],[-97.1031,48.0941],[-97.1025,48.0946],[-97.102,48.0953],[-97.1018,48.0959],[-97.1022,48.0967],[-97.1029,48.0973],[-97.1041,48.098],[-97.106,48.0987],[-97.1066,48.0989],[-97.1074,48.0992],[-97.108,48.0996],[-97.1084,48.0999],[-97.1086,48.1003],[-97.1088,48.1008],[-97.1089,48.1017],[-97.1088,48.1028],[-97.109,48.1038],[-97.1095,48.1048],[-97.1107,48.1056],[-97.1114,48.106],[-97.1124,48.1062],[-97.1131,48.1062],[-97.115,48.106],[-97.1169,48.1057],[-97.1181,48.1056],[-97.1197,48.1054],[-97.1208,48.1056],[-97.1218,48.1059],[-97.1225,48.1063],[-97.1232,48.1067],[-97.1234,48.1073],[-97.1235,48.1076],[-97.1236,48.1078],[-97.1236,48.1081],[-97.1231,48.1095],[-97.122,48.1109],[-97.121,48.1123],[-97.1205,48.1134],[-97.1207,48.115],[-97.121,48.1159],[-97.1215,48.117],[-97.1253,48.1223],[-97.1256,48.1224],[-97.1257,48.1226],[-97.1261,48.1233],[-97.1268,48.1243],[-97.127,48.1246],[-97.1271,48.125],[-97.1275,48.1258],[-97.1282,48.1272],[-97.1286,48.1284],[-97.1288,48.1291],[-97.129,48.1309],[-97.1294,48.1332],[-97.13,48.134],[-97.1314,48.135],[-97.1323,48.1358],[-97.1328,48.1362],[-97.1332,48.1366],[-97.1334,48.1372],[-97.133,48.1375],[-97.1325,48.1377],[-97.1319,48.1376],[-97.1303,48.1372],[-97.1293,48.1369],[-97.1289,48.1367],[-97.128,48.1364],[-97.1276,48.1362],[-97.1267,48.1361],[-97.1253,48.1361],[-97.1241,48.1364],[-97.124,48.1365],[-97.123,48.137],[-97.1227,48.1375],[-97.1224,48.1381],[-97.1223,48.1386],[-97.1223,48.1391],[-97.1228,48.1398],[-97.1234,48.1402],[-97.1239,48.1406],[-97.1248,48.1409],[-97.1253,48.1411],[-97.1266,48.1416],[-97.1277,48.1418],[-97.1294,48.1421],[-97.1297,48.1421],[-97.1319,48.1424],[-97.1347,48.143],[-97.1367,48.1433],[-97.1379,48.1433],[-97.1393,48.1429],[-97.1407,48.1423],[-97.1415,48.1417],[-97.1426,48.1413],[-97.1435,48.141],[-97.1444,48.1411],[-97.1454,48.1413],[-97.1461,48.1417],[-97.1465,48.1423],[-97.1466,48.1433],[-97.1465,48.1441],[-97.1458,48.1452],[-97.1447,48.1466],[-97.1435,48.1475],[-97.1425,48.1487],[-97.1413,48.1501],[-97.1405,48.1508],[-97.1402,48.1509],[-97.1391,48.1516],[-97.1371,48.1523],[-97.1328,48.1535],[-97.1307,48.1542],[-97.1305,48.1543],[-97.1281,48.1552],[-97.1263,48.156],[-97.1253,48.1563],[-97.1244,48.1566],[-97.1236,48.1571],[-97.1225,48.1577],[-97.1217,48.1583],[-97.1211,48.1588],[-97.121,48.1591],[-97.1209,48.1596],[-97.121,48.1608],[-97.1211,48.1612],[-97.1214,48.1615],[-97.1218,48.1617],[-97.1224,48.1621],[-97.1233,48.1625],[-97.1241,48.1627],[-97.1247,48.1628],[-97.1253,48.1629],[-97.1273,48.1628],[-97.1285,48.1626],[-97.1305,48.162],[-97.1313,48.1617],[-97.1322,48.1614],[-97.1345,48.1603],[-97.1363,48.1598],[-97.1385,48.1595],[-97.1403,48.1598],[-97.1419,48.1603],[-97.1431,48.1611],[-97.1442,48.1625],[-97.1443,48.1633],[-97.1445,48.1641],[-97.1447,48.165],[-97.1451,48.1668],[-97.1454,48.1675],[-97.1463,48.1686],[-97.1475,48.1706],[-97.1475,48.1725],[-97.1467,48.1733]]],"type":"Polygon"},"id":"60","properties":{"Area":5177876131.64875,"CTYONLY_":9,"Code":"POLK","LASTMOD":"1999-12-31T23:59:59Z","Name":"Polk","Perimiter":458889.41551},"type":"Feature"},{"geometry":{"coordinates":[[[-96.5008,48.1742],[-96.5008,48.1742],[-96.5006,48.1741],[-96.5003,48.1741],[-96.4973,48.174],[-96.4946,48.1741],[-96.4841,48.174],[-96.4791,48.1741],[-96.4789,48.1741],[-96.4773,48.1741],[-96.4735,48.174],[-96.467,48.1741],[-96.4592,48.1742],[-96.4569,48.1742],[-96.4564,48.1742],[-96.4563,48.1743],[-96.4561,48.1744],[-96.4454,48.1747],[-96.4436,48.1747],[-96.4402,48.1748],[-96.438,48.1749],[-96.4359,48.1749],[-96.4352,48.1749],[-96.4346,48.1749],[-96.4295,48.1749],[-96.4206,48.1749],[-96.4135,48.1749],[-96.4126,48.1749],[-96.4126,48.1749],[-96.4054,48.1748],[-96.3964,48.1748],[-96.3906,48.1748],[-96.3905,48.1748],[-96.3894,48.1748],[-96.3856,48.1747],[-96.38,48.1745],[-96.3781,48.1746],[-96.3753,48.1748],[-96.3728,48.1749],[-96.3706,48.175],[-96.3685,48.1751],[-96.3682,48.1751],[-96.3682,48.1751],[-96.3656,48.175],[-96.3642,48.1749],[-96.361,48.1748],[-96.3581,48.1747],[-96.3542,48.1746],[-96.351,48.1745],[-96.3477,48.1744],[-96.3473,48.1744],[-96.347,48.1743],[-96.3466,48.1743],[-96.343,48.1744],[-96.3402,48.1744],[-96.338,48.1745],[-96.3358,48.1744],[-96.3356,48.1745],[-96.3301,48.1745],[-96.3253,48.1746],[-96.3252,48.1746],[-96.3145,48.1747],[-96.3035,48.1747],[-96.3029,48.1747],[-96.2977,48.1747],[-96.2824,48.1747],[-96.2823,48.1747],[-96.2805,48.1747],[-96.2619,48.1749],[-96.2612,48.1749],[-96.2607,48.1749],[-96.2596,48.1749],[-96.2562,48.1744],[-96.252,48.174],[-96.2511,48.174],[-96.2503,48.1739],[-96.2491,48.1737],[-96.2476,48.1735],[-96.2398,48.1728],[-96.2397,48.1727],[-96.2397,48.1727],[-96.2391,48.1727],[-96.2329,48.1725],[-96.2307,48.1725],[-96.2287,48.1725],[-96.2275,48.1724],[-96.2251,48.1724],[-96.2188,48.1722],[-96.2179,48.1722],[-96.2177,48.1722],[-96.2076,48.1722],[-96.2072,48.1722],[-96.2038,48.1722],[-96.2023,48.1722],[-96.1963,48.1721],[-96.1959,48.1721],[-96.1954,48.1721],[-96.1948,48.1721],[-96.191,48.1721],[-96.1874,48.1721],[-96.1834,48.172],[-96.1827,48.1722],[-96.1813,48.1725],[-96.1741,48.1736],[-96.1737,48.1736],[-96.1736,48.1736],[-96.1641,48.1736],[-96.1625,48.1736],[-96.1518,48.1736],[-96.1516,48.1736],[-96.1388,48.1732],[-96.1302,48.173],[-96.1298,48.173],[-96.1297,48.173],[-96.1253,48.1727],[-96.1189,48.1722],[-96.1176,48.1722],[-96.1084,48.1718],[-96.1084,48.1718],[-96.0979,48.172],[-96.09,48.172],[-96.09,48.172],[-96.079,48.1721],[-96.0685,48.1721],[-96.0685,48.1721],[-96.0592,48.1721],[-96.0468,48.1722],[-96.0468,48.1722],[-96.0254,48.1721],[-96.025,48.1721],[-96.0171,48.172],[-96.0101,48.1718],[-96.0047,48.1717],[-96.0036,48.1718],[-96.0035,48.1718],[-96.0032,48.1718],[-96.0028,48.1718],[-96.0023,48.1718],[-96.0003,48.1717],[-95.9956,48.1717],[-95.9819,48.1717],[-95.9817,48.1717],[-95.9651,48.1718],[-95.961,48.1718],[-95.9609,48.1718],[-95.9608,48.1718],[-95.9394,48.1719],[-95.9392,48.1719],[-95.9178,48.1719],[-95.9178,48.1719],[-95.9176,48.1719],[-95.896,48.172],[-95.8958,48.172],[-95.8752,48.172],[-95.8744,48.172],[-95.8744,48.172],[-95.8527,48.1721],[-95.8525,48.1721],[-95.8499,48.1721],[-95.8308,48.1722],[-95.8308,48.1722],[-95.8305,48.1722],[-95.8091,48.1722],[-95.809,48.1722],[-95.8088,48.1722],[-95.7874,48.1725],[-95.7657,48.1728],[-95.7657,48.1728],[-95.7502,48.1727],[-95.7443,48.1727],[-95.744,48.1727],[-95.7227,48.1731],[-95.7226,48.1731],[-95.7157,48.1731],[-95.7128,48.173],[-95.7022,48.1729],[-95.7021,48.1729],[-95.702,48.1729],[-95.6803,48.1728],[-95.6802,48.1728],[-95.662,48.1729],[-95.6591,48.1729],[-95.6376,48.173],[-95.6376,48.173],[-95.6279,48.1731],[-95.6252,48.1731],[-95.6163,48.1731],[-95.6159,48.1731],[-95.5941,48.173],[-95.5939,48.173],[-95.5939,48.1658],[-95.5938,48.1512],[-95.5936,48.1368],[-95.5931,48.1223],[-95.593,48.1078],[-95.5928,48.0931],[-95.5926,48.0787],[-95.5925,48.0642],[-95.5925,48.0497],[-95.5923,48.035],[-95.5922,48.0207],[-95.5828,48.0207],[-95.5825,48.0063],[-95.5824,47.9917],[-95.5825,47.9771],[-95.5826,47.9629],[-95.5825,47.9482],[-95.5824,47.9339],[-95.6034,47.9341],[-95.6252,47.9344],[-95.6466,47.9348],[-95.6683,47.9351],[-95.6898,47.9354],[-95.7096,47.9355],[-95.7097,47.9499],[-95.7098,47.9644],[-95.7312,47.9644],[-95.7531,47.9645],[-95.7747,47.9646],[-95.7963,47.9647],[-95.8181,47.9647],[-95.8383,47.9648],[-95.86,47.9649],[-95.8814,47.9648],[-95.9031,47.9648],[-95.925,47.9647],[-95.9462,47.9646],[-95.9671,47.9646],[-95.9887,47.9642],[-96.0106,47.9641],[-96.0324,47.964],[-96.054,47.9638],[-96.0757,47.9637],[-96.096,47.9638],[-96.1173,47.9632],[-96.1389,47.9631],[-96.1606,47.9631],[-96.1826,47.9632],[-96.2044,47.963],[-96.2235,47.9629],[-96.2453,47.9629],[-96.2667,47.9629],[-96.2883,47.963],[-96.31,47.9633],[-96.3316,47.9634],[-96.3526,47.9634],[-96.3738,47.9636],[-96.3954,47.9636],[-96.4172,47.9637],[-96.439,47.9636],[-96.4603,47.9639],[-96.4823,47.9636],[-96.4823,47.9782],[-96.4824,47.9924],[-96.4826,48.0072],[-96.4826,48.0217],[-96.5009,48.0217],[-96.5009,48.0362],[-96.5008,48.0506],[-96.5009,48.0654],[-96.5009,48.0798],[-96.5009,48.0943],[-96.501,48.1089],[-96.5007,48.1234],[-96.5006,48.1379],[-96.5008,48.1524],[-96.5008,48.1669],[-96.5008,48.1742]]],"type":"Polygon"},"id":"57","properties":{"Area":1601102945.98836,"CTYONLY_":10,"Code":"PENN","LASTMOD":"2006-07-04T12:00:00Z","Name":"Pennington","Perimiter":190039.7415},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&sortby=LASTMOD","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&sortby=LASTMOD","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=9&sortby=LASTMOD","rel":"next","title":"next page","type":"application/geo+json"}],"numberMatched":117,"numberReturned":9,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_sorted_error.json.txt b/msautotest/api/expected/ogcapi_sorted_error.json.txt new file mode 100644 index 0000000000..63faeba844 --- /dev/null +++ b/msautotest/api/expected/ogcapi_sorted_error.json.txt @@ -0,0 +1,4 @@ +Content-Type: application/json +Status: 400 + +{"code":"InvalidParameterValue","description":"'illegal' is not a sortable item"} diff --git a/msautotest/api/expected/ogcapi_sorted_minus.json.txt b/msautotest/api/expected/ogcapi_sorted_minus.json.txt new file mode 100644 index 0000000000..a5c550adf6 --- /dev/null +++ b/msautotest/api/expected/ogcapi_sorted_minus.json.txt @@ -0,0 +1,9 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +Link: ; rel="next"; title="next page"; type="application/geo+json" +OGC-NumberMatched: 117 +OGC-NumberReturned: 9 + +{"features":[{"geometry":{"coordinates":[[[-95.3231,48.999],[-95.3109,48.999],[-95.2889,48.9989],[-95.2852,48.9989],[-95.2669,48.9989],[-95.245,48.9989],[-95.2232,48.9989],[-95.2014,48.9989],[-95.1792,48.9989],[-95.1574,48.9989],[-95.1531,48.9989],[-95.1531,49.0031],[-95.1532,49.0179],[-95.1532,49.0325],[-95.1532,49.047],[-95.1532,49.0619],[-95.1532,49.0765],[-95.1532,49.0911],[-95.1532,49.1057],[-95.1532,49.1205],[-95.1532,49.1354],[-95.1532,49.1499],[-95.1532,49.1642],[-95.1532,49.1788],[-95.1532,49.1807],[-95.1532,49.1931],[-95.1532,49.1966],[-95.1532,49.2077],[-95.1533,49.2131],[-95.1533,49.2219],[-95.1533,49.2308],[-95.1533,49.2365],[-95.1533,49.2472],[-95.1533,49.2512],[-95.1533,49.2655],[-95.1533,49.2697],[-95.1533,49.2802],[-95.1533,49.2882],[-95.1533,49.2945],[-95.1533,49.3072],[-95.1533,49.309],[-95.1533,49.3234],[-95.1533,49.3237],[-95.1533,49.3381],[-95.1533,49.3476],[-95.1533,49.3525],[-95.1533,49.3636],[-95.1533,49.367],[-95.1533,49.3705],[-95.1533,49.3776],[-95.1533,49.3813],[-95.1533,49.3845],[-95.1503,49.383],[-95.1499,49.3813],[-95.1498,49.3807],[-95.1467,49.3802],[-95.145,49.3784],[-95.1418,49.3784],[-95.1397,49.3762],[-95.1367,49.3751],[-95.1324,49.3736],[-95.1287,49.3705],[-95.1171,49.367],[-95.1159,49.3666],[-95.1145,49.3666],[-95.1098,49.3664],[-95.1031,49.3652],[-95.1031,49.3636],[-95.0926,49.3617],[-95.0897,49.3612],[-95.0707,49.3564],[-95.0582,49.3533],[-95.0495,49.3532],[-95.0479,49.3533],[-95.0262,49.3554],[-95.0141,49.3565],[-95.0047,49.3612],[-94.993,49.367],[-94.9889,49.369],[-94.9818,49.3684],[-94.9742,49.3678],[-94.9597,49.3699],[-94.9573,49.3702],[-94.952,49.3688],[-94.948,49.367],[-94.9376,49.3625],[-94.9152,49.3529],[-94.9143,49.3524],[-94.909,49.3502],[-94.9065,49.3484],[-94.8933,49.3414],[-94.8865,49.3378],[-94.8782,49.3334],[-94.8712,49.3308],[-94.854,49.3244],[-94.8492,49.3244],[-94.8363,49.3243],[-94.8311,49.3236],[-94.8271,49.323],[-94.8162,49.3214],[-94.8243,49.309],[-94.8243,49.3088],[-94.8255,49.2944],[-94.8255,49.2943],[-94.8204,49.28],[-94.8152,49.2653],[-94.8103,49.2515],[-94.8059,49.2388],[-94.8051,49.2367],[-94.8001,49.2224],[-94.7973,49.2144],[-94.7975,49.2079],[-94.7979,49.1979],[-94.7965,49.1936],[-94.7918,49.1792],[-94.7871,49.1646],[-94.7833,49.153],[-94.7823,49.15],[-94.7776,49.1357],[-94.7727,49.1206],[-94.7727,49.1206],[-94.7611,49.1096],[-94.7571,49.1058],[-94.7496,49.0988],[-94.7474,49.0918],[-94.7429,49.0773],[-94.7394,49.0657],[-94.7385,49.063],[-94.7344,49.0497],[-94.7299,49.0351],[-94.7254,49.0205],[-94.7207,49.0052],[-94.7184,48.9979],[-94.7162,48.9907],[-94.7117,48.9761],[-94.7072,48.9615],[-94.7027,48.9468],[-94.6982,48.9322],[-94.6968,48.9276],[-94.6844,48.8875],[-94.6834,48.8842],[-94.6842,48.8724],[-94.6855,48.8719],[-94.6923,48.8691],[-94.6902,48.8636],[-94.6914,48.8591],[-94.693,48.8535],[-94.6881,48.8447],[-94.6855,48.8401],[-94.6963,48.836],[-94.6975,48.8355],[-94.702,48.8319],[-94.7025,48.8302],[-94.7042,48.8243],[-94.6991,48.8159],[-94.6962,48.8111],[-94.6951,48.8092],[-94.6958,48.8012],[-94.6959,48.7997],[-94.6944,48.7895],[-94.6934,48.7864],[-94.6909,48.7781],[-94.687,48.7752],[-94.6776,48.772],[-94.6768,48.7717],[-94.6746,48.7705],[-94.6671,48.7662],[-94.6603,48.7605],[-94.6557,48.7581],[-94.6525,48.7565],[-94.652,48.7562],[-94.6453,48.7491],[-94.6453,48.7441],[-94.6443,48.7434],[-94.6414,48.7413],[-94.631,48.7392],[-94.6301,48.739],[-94.6191,48.7373],[-94.6106,48.7318],[-94.6084,48.731],[-94.6028,48.7289],[-94.6011,48.7283],[-94.5962,48.7248],[-94.5913,48.7197],[-94.5876,48.7176],[-94.5867,48.7175],[-94.5685,48.7156],[-94.5622,48.7159],[-94.5558,48.7163],[-94.549,48.7148],[-94.5487,48.7146],[-94.5457,48.7124],[-94.5396,48.7036],[-94.539,48.7028],[-94.5329,48.7013],[-94.5247,48.7016],[-94.5178,48.7008],[-94.5173,48.7008],[-94.5093,48.7006],[-94.5066,48.6999],[-94.4996,48.698],[-94.4958,48.698],[-94.4863,48.698],[-94.4739,48.6969],[-94.4706,48.6966],[-94.4631,48.6953],[-94.4568,48.6933],[-94.4523,48.6925],[-94.4517,48.6925],[-94.4465,48.693],[-94.4388,48.6949],[-94.4319,48.6998],[-94.4299,48.7012],[-94.4299,48.6998],[-94.43,48.6852],[-94.4301,48.6708],[-94.43,48.6564],[-94.4297,48.642],[-94.4294,48.6276],[-94.4292,48.6133],[-94.4289,48.5988],[-94.4289,48.5844],[-94.4291,48.5698],[-94.4295,48.5554],[-94.43,48.5409],[-94.4303,48.5264],[-94.4303,48.512],[-94.4299,48.4977],[-94.4296,48.4832],[-94.4296,48.4688],[-94.4293,48.4543],[-94.4292,48.4399],[-94.4293,48.4254],[-94.4294,48.411],[-94.4293,48.3964],[-94.4289,48.3821],[-94.4288,48.3675],[-94.4471,48.3675],[-94.4505,48.3675],[-94.4688,48.3675],[-94.4722,48.3674],[-94.4906,48.3674],[-94.4924,48.3674],[-94.4941,48.3674],[-94.5118,48.3675],[-94.5157,48.3674],[-94.5335,48.3674],[-94.5378,48.3674],[-94.5536,48.3674],[-94.5593,48.3674],[-94.5754,48.3674],[-94.5812,48.3674],[-94.5971,48.3675],[-94.6029,48.3674],[-94.6188,48.3673],[-94.6245,48.3673],[-94.6405,48.3673],[-94.6465,48.3673],[-94.6505,48.3673],[-94.6622,48.3673],[-94.6679,48.3673],[-94.6694,48.3672],[-94.683,48.3671],[-94.6898,48.3671],[-94.7099,48.3669],[-94.7117,48.3668],[-94.7315,48.3669],[-94.7329,48.3669],[-94.7533,48.3669],[-94.7549,48.3669],[-94.7748,48.3669],[-94.7765,48.3669],[-94.7967,48.3669],[-94.7983,48.3669],[-94.8183,48.3669],[-94.8199,48.3669],[-94.8399,48.3669],[-94.8416,48.3669],[-94.8616,48.3667],[-94.8632,48.3667],[-94.8833,48.3667],[-94.8849,48.3666],[-94.9049,48.3666],[-94.9065,48.3666],[-94.9264,48.3667],[-94.9283,48.3667],[-94.9469,48.3666],[-94.95,48.3666],[-94.9684,48.3667],[-94.9716,48.3667],[-94.9901,48.3667],[-94.9932,48.3667],[-95.0119,48.3665],[-95.0153,48.3665],[-95.0337,48.3665],[-95.0369,48.3665],[-95.0555,48.3665],[-95.0586,48.3665],[-95.0773,48.3664],[-95.0801,48.3664],[-95.099,48.3663],[-95.1008,48.3663],[-95.1018,48.3663],[-95.1207,48.3663],[-95.1236,48.3663],[-95.1315,48.3662],[-95.1424,48.3662],[-95.1454,48.3662],[-95.164,48.3661],[-95.1669,48.3661],[-95.1861,48.3661],[-95.1887,48.3661],[-95.1983,48.3661],[-95.2066,48.3661],[-95.2106,48.3661],[-95.211,48.3797],[-95.211,48.3808],[-95.2111,48.3941],[-95.2111,48.3952],[-95.2112,48.4087],[-95.2112,48.4096],[-95.2113,48.4232],[-95.2113,48.4242],[-95.2113,48.4255],[-95.2113,48.4376],[-95.2113,48.4387],[-95.2113,48.4522],[-95.2112,48.4529],[-95.211,48.4666],[-95.211,48.4673],[-95.2111,48.4816],[-95.2112,48.4962],[-95.2111,48.5101],[-95.2111,48.5109],[-95.2115,48.5244],[-95.2115,48.5252],[-95.2119,48.54],[-95.2324,48.5399],[-95.2339,48.5399],[-95.2537,48.5398],[-95.2554,48.5398],[-95.2756,48.54],[-95.2773,48.54],[-95.2975,48.5401],[-95.2992,48.5402],[-95.3194,48.54],[-95.321,48.54],[-95.3412,48.5402],[-95.3425,48.5402],[-95.3424,48.5548],[-95.3423,48.5691],[-95.3423,48.5836],[-95.3426,48.5979],[-95.3424,48.6127],[-95.3426,48.6271],[-95.3425,48.6415],[-95.3424,48.6561],[-95.3423,48.6705],[-95.3424,48.6849],[-95.3425,48.6995],[-95.3425,48.7131],[-95.3302,48.713],[-95.3205,48.713],[-95.3084,48.713],[-95.3051,48.713],[-95.299,48.713],[-95.2866,48.713],[-95.2767,48.713],[-95.2656,48.713],[-95.2645,48.713],[-95.255,48.713],[-95.2427,48.713],[-95.2331,48.713],[-95.2206,48.713],[-95.2112,48.713],[-95.1991,48.713],[-95.1917,48.713],[-95.1773,48.713],[-95.1697,48.7129],[-95.1554,48.7129],[-95.1477,48.7129],[-95.1333,48.713],[-95.1297,48.713],[-95.1259,48.7129],[-95.1119,48.7129],[-95.1104,48.7129],[-95.1046,48.7129],[-95.0898,48.713],[-95.0899,48.7277],[-95.0901,48.7421],[-95.0901,48.7566],[-95.0903,48.7711],[-95.0903,48.7855],[-95.0903,48.8],[-95.0909,48.8147],[-95.0908,48.8291],[-95.0907,48.8436],[-95.0908,48.858],[-95.0908,48.8724],[-95.0911,48.8869],[-95.0912,48.9014],[-95.0914,48.916],[-95.0914,48.9208],[-95.0919,48.9207],[-95.0927,48.9204],[-95.0944,48.9193],[-95.0946,48.9191],[-95.0961,48.9181],[-95.097,48.9176],[-95.0971,48.9172],[-95.0975,48.9164],[-95.098,48.916],[-95.0981,48.9159],[-95.1008,48.9142],[-95.102,48.9132],[-95.1032,48.9127],[-95.1042,48.9121],[-95.1056,48.9113],[-95.108,48.9099],[-95.1096,48.9089],[-95.1107,48.9082],[-95.1126,48.9073],[-95.113,48.9072],[-95.1132,48.9071],[-95.1137,48.9069],[-95.1141,48.9064],[-95.114,48.9061],[-95.1144,48.9052],[-95.1151,48.9046],[-95.1163,48.9037],[-95.1182,48.9029],[-95.1204,48.9019],[-95.1205,48.9017],[-95.121,48.9016],[-95.1214,48.9013],[-95.1228,48.9006],[-95.1233,48.9004],[-95.1239,48.9001],[-95.1252,48.8998],[-95.1312,48.8975],[-95.1322,48.8973],[-95.1337,48.8969],[-95.1343,48.8963],[-95.1348,48.8963],[-95.1351,48.8963],[-95.1355,48.8959],[-95.1381,48.8949],[-95.1404,48.8943],[-95.1436,48.8937],[-95.1438,48.8934],[-95.1459,48.8929],[-95.1469,48.8927],[-95.1483,48.8923],[-95.1508,48.8922],[-95.1528,48.8921],[-95.1555,48.892],[-95.1564,48.8919],[-95.1579,48.8919],[-95.1602,48.892],[-95.1618,48.892],[-95.1641,48.8917],[-95.1648,48.8913],[-95.1674,48.8907],[-95.1701,48.8902],[-95.173,48.8897],[-95.1764,48.8893],[-95.1791,48.889],[-95.1797,48.889],[-95.1819,48.8888],[-95.1851,48.8882],[-95.1863,48.8877],[-95.1877,48.8874],[-95.1889,48.8873],[-95.1901,48.887],[-95.1913,48.8868],[-95.1919,48.8866],[-95.1924,48.8865],[-95.1956,48.8862],[-95.1986,48.8855],[-95.2005,48.8856],[-95.2009,48.8855],[-95.2024,48.8852],[-95.2059,48.8848],[-95.2085,48.8846],[-95.2112,48.8848],[-95.2115,48.8847],[-95.2117,48.8847],[-95.2122,48.8842],[-95.2144,48.8843],[-95.2151,48.884],[-95.2159,48.8839],[-95.217,48.8835],[-95.2188,48.8835],[-95.2193,48.8832],[-95.22,48.8831],[-95.2207,48.8831],[-95.2208,48.8831],[-95.2212,48.883],[-95.2252,48.8819],[-95.2265,48.8816],[-95.2287,48.8815],[-95.231,48.8814],[-95.2335,48.8814],[-95.2356,48.8815],[-95.2381,48.8817],[-95.2391,48.8819],[-95.2407,48.8821],[-95.2423,48.8821],[-95.2429,48.8822],[-95.2429,48.8822],[-95.2439,48.8823],[-95.2458,48.8829],[-95.2472,48.8835],[-95.248,48.8836],[-95.2485,48.8832],[-95.2496,48.8834],[-95.2502,48.8835],[-95.2507,48.8836],[-95.2517,48.8839],[-95.2548,48.8845],[-95.256,48.885],[-95.257,48.8858],[-95.2585,48.8867],[-95.2585,48.8867],[-95.2627,48.8877],[-95.2635,48.888],[-95.2639,48.8883],[-95.2646,48.8885],[-95.265,48.8886],[-95.2654,48.8888],[-95.2666,48.8894],[-95.2674,48.89],[-95.2677,48.8903],[-95.268,48.8905],[-95.2713,48.8915],[-95.2724,48.8921],[-95.2745,48.8931],[-95.2751,48.8938],[-95.2753,48.8943],[-95.2748,48.8951],[-95.2749,48.8956],[-95.2755,48.8959],[-95.2759,48.8962],[-95.2763,48.8963],[-95.2765,48.8962],[-95.277,48.8958],[-95.2773,48.8957],[-95.2782,48.8956],[-95.279,48.8957],[-95.2796,48.8962],[-95.2803,48.8965],[-95.2813,48.8967],[-95.2839,48.8975],[-95.2853,48.8977],[-95.2861,48.8976],[-95.2865,48.8975],[-95.287,48.8976],[-95.2872,48.8977],[-95.2879,48.8979],[-95.2882,48.8981],[-95.289,48.8994],[-95.2896,48.9],[-95.2901,48.9003],[-95.2911,48.9006],[-95.2911,48.9008],[-95.2906,48.9011],[-95.2907,48.9014],[-95.2908,48.9016],[-95.2909,48.9017],[-95.2914,48.9019],[-95.2927,48.9019],[-95.2935,48.902],[-95.2937,48.9023],[-95.2941,48.9027],[-95.2949,48.9028],[-95.2967,48.9027],[-95.2976,48.9026],[-95.298,48.9027],[-95.2983,48.9028],[-95.2993,48.9035],[-95.3005,48.904],[-95.3002,48.9045],[-95.3001,48.9046],[-95.3001,48.9047],[-95.3,48.9047],[-95.3,48.9047],[-95.2999,48.9048],[-95.2999,48.9048],[-95.2999,48.9048],[-95.2997,48.905],[-95.2996,48.9051],[-95.2994,48.9053],[-95.2992,48.9055],[-95.2991,48.9057],[-95.2989,48.906],[-95.2988,48.906],[-95.2986,48.9063],[-95.2985,48.9064],[-95.2985,48.9065],[-95.2983,48.9068],[-95.2982,48.9068],[-95.2981,48.907],[-95.298,48.9071],[-95.298,48.9071],[-95.298,48.9071],[-95.2979,48.9071],[-95.2979,48.9072],[-95.2979,48.9072],[-95.2978,48.9072],[-95.2978,48.9072],[-95.2978,48.9073],[-95.2977,48.9073],[-95.2976,48.9074],[-95.2973,48.9077],[-95.2973,48.908],[-95.2973,48.9081],[-95.2978,48.9083],[-95.2999,48.9086],[-95.3017,48.9093],[-95.3027,48.91],[-95.3038,48.9114],[-95.3043,48.9119],[-95.3059,48.9127],[-95.3061,48.9128],[-95.3064,48.9129],[-95.3074,48.9135],[-95.3078,48.9141],[-95.3085,48.9146],[-95.3092,48.9149],[-95.3093,48.9149],[-95.3102,48.9155],[-95.3109,48.9163],[-95.3115,48.9172],[-95.3119,48.9178],[-95.3126,48.919],[-95.3132,48.9198],[-95.3141,48.921],[-95.315,48.9222],[-95.3168,48.9245],[-95.3195,48.9285],[-95.3208,48.9305],[-95.3209,48.9307],[-95.3222,48.9327],[-95.3228,48.9344],[-95.3223,48.9355],[-95.3225,48.9358],[-95.3229,48.9373],[-95.3231,48.9389],[-95.3228,48.9403],[-95.3225,48.9409],[-95.3219,48.9412],[-95.3189,48.9419],[-95.3181,48.9421],[-95.3168,48.9431],[-95.3154,48.9448],[-95.3148,48.9452],[-95.3141,48.9457],[-95.3131,48.946],[-95.3114,48.9461],[-95.3102,48.9463],[-95.3095,48.9463],[-95.3088,48.9464],[-95.3086,48.9465],[-95.3086,48.9469],[-95.3085,48.947],[-95.3078,48.9466],[-95.3074,48.9465],[-95.3071,48.9466],[-95.3071,48.9469],[-95.3079,48.9474],[-95.3092,48.9477],[-95.3096,48.9478],[-95.3103,48.948],[-95.3104,48.9484],[-95.3103,48.9485],[-95.31,48.9485],[-95.3099,48.9484],[-95.3096,48.9482],[-95.3094,48.9481],[-95.3081,48.948],[-95.3071,48.9477],[-95.3062,48.9472],[-95.3062,48.9472],[-95.3061,48.9469],[-95.3062,48.9463],[-95.3063,48.9462],[-95.3069,48.9456],[-95.3069,48.9455],[-95.3068,48.9454],[-95.3061,48.9454],[-95.3053,48.9459],[-95.305,48.9462],[-95.3046,48.947],[-95.3046,48.9482],[-95.3052,48.9495],[-95.3061,48.9502],[-95.3079,48.9509],[-95.3089,48.9511],[-95.3097,48.951],[-95.3104,48.951],[-95.3108,48.9512],[-95.3115,48.952],[-95.312,48.9524],[-95.3126,48.9524],[-95.3129,48.9523],[-95.3129,48.9521],[-95.3119,48.9507],[-95.3119,48.9502],[-95.3123,48.9502],[-95.3125,48.9503],[-95.3131,48.9503],[-95.3141,48.9508],[-95.3151,48.951],[-95.3154,48.9513],[-95.3177,48.9525],[-95.3181,48.9531],[-95.3182,48.9535],[-95.3177,48.9545],[-95.3175,48.9552],[-95.3179,48.9559],[-95.3188,48.9562],[-95.3191,48.9569],[-95.3202,48.9581],[-95.3206,48.959],[-95.3206,48.9595],[-95.3206,48.9598],[-95.3202,48.9606],[-95.3193,48.9622],[-95.3193,48.964],[-95.3198,48.9643],[-95.3201,48.9648],[-95.3207,48.9669],[-95.3212,48.9672],[-95.3227,48.9685],[-95.3232,48.9692],[-95.3241,48.9703],[-95.3247,48.972],[-95.3248,48.9728],[-95.3249,48.9738],[-95.325,48.9743],[-95.3253,48.976],[-95.3257,48.9784],[-95.3255,48.9789],[-95.3256,48.98],[-95.3257,48.9814],[-95.3253,48.9832],[-95.3245,48.985],[-95.3242,48.9859],[-95.3227,48.9884],[-95.3224,48.9889],[-95.3206,48.9921],[-95.3204,48.9924],[-95.3191,48.9941],[-95.3181,48.995],[-95.3178,48.9958],[-95.3178,48.9961],[-95.3179,48.9961],[-95.3182,48.996],[-95.3187,48.9956],[-95.3191,48.9953],[-95.3197,48.9954],[-95.3201,48.9956],[-95.3206,48.9961],[-95.3204,48.9964],[-95.3202,48.9973],[-95.3204,48.9976],[-95.3224,48.9984],[-95.3231,48.999]]],"type":"Polygon"},"id":"39","properties":{"Area":4608320923.49768,"CTYONLY_":2,"Code":"LOTW","LASTMOD":"1976-07-04T12:00:00Z","Name":"Lake of the Woods","Perimiter":388250.14572},"type":"Feature"},{"geometry":{"coordinates":[[[-96.4054,49.0001],[-96.4054,48.9947],[-96.4054,48.994],[-96.4054,48.9803],[-96.4054,48.9793],[-96.4053,48.9705],[-96.4053,48.9658],[-96.4053,48.9648],[-96.4053,48.9515],[-96.4053,48.9504],[-96.4053,48.9371],[-96.4053,48.936],[-96.4054,48.9225],[-96.4054,48.9214],[-96.4053,48.9137],[-96.4053,48.9081],[-96.4053,48.9068],[-96.405,48.8926],[-96.405,48.878],[-96.4047,48.8635],[-96.4045,48.8491],[-96.4043,48.8343],[-96.4042,48.8198],[-96.4042,48.8048],[-96.4042,48.7903],[-96.4045,48.7758],[-96.4047,48.7607],[-96.4048,48.7465],[-96.4048,48.7318],[-96.4049,48.7172],[-96.388,48.7172],[-96.3873,48.7172],[-96.3866,48.703],[-96.3874,48.6887],[-96.3871,48.6741],[-96.3877,48.6599],[-96.3879,48.6454],[-96.388,48.6313],[-96.389,48.6165],[-96.3891,48.6024],[-96.3884,48.5877],[-96.3882,48.5733],[-96.3879,48.5588],[-96.3882,48.5442],[-96.4101,48.544],[-96.4318,48.5438],[-96.4535,48.5436],[-96.4754,48.5435],[-96.4973,48.5434],[-96.518,48.5434],[-96.54,48.5434],[-96.5621,48.5436],[-96.5839,48.5437],[-96.6058,48.5437],[-96.6278,48.5437],[-96.6493,48.5437],[-96.6713,48.5436],[-96.6931,48.5437],[-96.7151,48.5437],[-96.7368,48.5437],[-96.7585,48.5436],[-96.7803,48.5435],[-96.8023,48.5436],[-96.824,48.5436],[-96.8459,48.5434],[-96.8678,48.5433],[-96.8896,48.5433],[-96.9115,48.5432],[-96.9138,48.5433],[-96.9331,48.5435],[-96.9551,48.5437],[-96.9768,48.544],[-96.9985,48.5441],[-97.0194,48.5441],[-97.0416,48.5442],[-97.0635,48.5441],[-97.0852,48.5441],[-97.107,48.544],[-97.1287,48.5439],[-97.1509,48.5439],[-97.1631,48.544],[-97.1637,48.5445],[-97.1659,48.5483],[-97.1662,48.5509],[-97.1661,48.5527],[-97.1654,48.5536],[-97.1645,48.554],[-97.1628,48.5543],[-97.1613,48.5539],[-97.1592,48.5528],[-97.1577,48.5518],[-97.1557,48.5512],[-97.1538,48.5513],[-97.1513,48.5515],[-97.1507,48.5515],[-97.1493,48.5516],[-97.1474,48.5516],[-97.1444,48.5514],[-97.1407,48.5515],[-97.1387,48.5522],[-97.1379,48.553],[-97.1379,48.5542],[-97.1391,48.5554],[-97.141,48.5566],[-97.1426,48.5571],[-97.1464,48.5573],[-97.1505,48.5574],[-97.1515,48.5574],[-97.1551,48.5574],[-97.1578,48.5573],[-97.1606,48.5571],[-97.1631,48.5571],[-97.1646,48.5572],[-97.167,48.5575],[-97.1697,48.5584],[-97.1721,48.5591],[-97.1727,48.5593],[-97.174,48.5599],[-97.1749,48.5606],[-97.1753,48.5614],[-97.1754,48.5623],[-97.1749,48.5631],[-97.1744,48.5639],[-97.1723,48.5648],[-97.1721,48.5648],[-97.1706,48.5652],[-97.1687,48.5655],[-97.167,48.5658],[-97.1651,48.5659],[-97.1613,48.5661],[-97.1541,48.5669],[-97.153,48.5671],[-97.1516,48.5677],[-97.1503,48.5688],[-97.1496,48.5695],[-97.1487,48.5707],[-97.1477,48.5727],[-97.1477,48.5728],[-97.1476,48.5731],[-97.1483,48.5763],[-97.15,48.5775],[-97.1501,48.5775],[-97.1548,48.5779],[-97.1592,48.5785],[-97.1605,48.58],[-97.16,48.5816],[-97.1578,48.5826],[-97.1562,48.5828],[-97.1541,48.5826],[-97.1524,48.5823],[-97.15,48.5815],[-97.1494,48.5813],[-97.1484,48.5811],[-97.1449,48.5815],[-97.1436,48.5824],[-97.1431,48.5834],[-97.1429,48.5838],[-97.142,48.5876],[-97.1418,48.5886],[-97.1415,48.5909],[-97.1422,48.5926],[-97.1433,48.5936],[-97.1451,48.594],[-97.1471,48.594],[-97.1497,48.5937],[-97.1525,48.594],[-97.1536,48.5949],[-97.1535,48.5957],[-97.1527,48.5962],[-97.1524,48.5969],[-97.1516,48.598],[-97.1498,48.5981],[-97.1497,48.5981],[-97.1463,48.5977],[-97.1443,48.5981],[-97.143,48.5987],[-97.1416,48.6002],[-97.1403,48.6021],[-97.14,48.6025],[-97.138,48.6044],[-97.1359,48.6054],[-97.1345,48.6065],[-97.1341,48.6075],[-97.1349,48.6082],[-97.1358,48.6086],[-97.137,48.6088],[-97.1396,48.6086],[-97.1443,48.6078],[-97.1474,48.6081],[-97.1494,48.6089],[-97.1495,48.609],[-97.1505,48.6115],[-97.1501,48.6124],[-97.1493,48.6129],[-97.1478,48.6138],[-97.145,48.6146],[-97.1408,48.6149],[-97.137,48.6144],[-97.134,48.6136],[-97.1319,48.6133],[-97.1309,48.6137],[-97.1289,48.614],[-97.1286,48.6153],[-97.1293,48.6168],[-97.1295,48.617],[-97.1311,48.6184],[-97.1342,48.6199],[-97.1353,48.6212],[-97.1346,48.6224],[-97.133,48.6228],[-97.131,48.6227],[-97.1291,48.6222],[-97.1277,48.6212],[-97.1274,48.621],[-97.1259,48.6195],[-97.1253,48.619],[-97.1243,48.6183],[-97.1231,48.6178],[-97.1216,48.6176],[-97.12,48.6178],[-97.1193,48.6182],[-97.1186,48.6191],[-97.1183,48.6198],[-97.1186,48.6209],[-97.1198,48.6221],[-97.1209,48.6232],[-97.1212,48.6233],[-97.122,48.624],[-97.1228,48.6245],[-97.1236,48.625],[-97.1241,48.6254],[-97.1245,48.6257],[-97.1249,48.6259],[-97.1253,48.6261],[-97.126,48.6264],[-97.1266,48.6266],[-97.1272,48.627],[-97.1279,48.6273],[-97.1288,48.6278],[-97.1296,48.6282],[-97.1302,48.6288],[-97.1305,48.6292],[-97.1307,48.6297],[-97.131,48.6303],[-97.131,48.6304],[-97.131,48.6308],[-97.131,48.6315],[-97.1309,48.6317],[-97.1307,48.6321],[-97.1304,48.6325],[-97.1301,48.6326],[-97.1297,48.6328],[-97.1293,48.6329],[-97.129,48.633],[-97.1281,48.6332],[-97.128,48.6333],[-97.1275,48.6333],[-97.1253,48.6334],[-97.1235,48.6333],[-97.1216,48.6327],[-97.1181,48.6308],[-97.1176,48.6307],[-97.115,48.6299],[-97.1133,48.63],[-97.1115,48.6303],[-97.1107,48.6308],[-97.1104,48.6309],[-97.1095,48.6315],[-97.1084,48.6327],[-97.1082,48.6344],[-97.1086,48.6363],[-97.1096,48.6389],[-97.1109,48.6407],[-97.1119,48.6416],[-97.1144,48.6433],[-97.115,48.6438],[-97.115,48.6446],[-97.1149,48.6452],[-97.1123,48.6457],[-97.1112,48.6459],[-97.1093,48.6465],[-97.1078,48.6478],[-97.1069,48.6491],[-97.1066,48.6501],[-97.1061,48.6519],[-97.1059,48.6527],[-97.1045,48.6545],[-97.1017,48.6563],[-97.0987,48.6593],[-97.0986,48.6604],[-97.0985,48.6613],[-97.0992,48.6625],[-97.1019,48.6636],[-97.106,48.663],[-97.1062,48.663],[-97.1082,48.6634],[-97.1087,48.6645],[-97.1061,48.6654],[-97.1057,48.6655],[-97.102,48.6667],[-97.1,48.668],[-97.0998,48.6714],[-97.1002,48.675],[-97.1003,48.6757],[-97.1008,48.6787],[-97.1011,48.6808],[-97.1003,48.6828],[-97.0985,48.683],[-97.0946,48.6822],[-97.0926,48.6821],[-97.0904,48.6828],[-97.0898,48.6841],[-97.0899,48.6852],[-97.091,48.6861],[-97.093,48.687],[-97.0951,48.6876],[-97.099,48.6884],[-97.1024,48.6893],[-97.103,48.6894],[-97.1059,48.6903],[-97.1064,48.6905],[-97.1086,48.6915],[-97.111,48.6939],[-97.113,48.6964],[-97.1148,48.6981],[-97.1182,48.7005],[-97.1198,48.7018],[-97.1201,48.7039],[-97.1194,48.7041],[-97.1182,48.7046],[-97.1143,48.7052],[-97.1117,48.7056],[-97.11,48.7063],[-97.1098,48.7083],[-97.1113,48.7094],[-97.1134,48.7101],[-97.1157,48.7105],[-97.1174,48.7111],[-97.119,48.7119],[-97.1212,48.7136],[-97.1223,48.716],[-97.1229,48.7168],[-97.1231,48.7172],[-97.1243,48.7192],[-97.1253,48.7201],[-97.1253,48.7203],[-97.126,48.7207],[-97.1263,48.7212],[-97.1272,48.7215],[-97.128,48.722],[-97.1282,48.7221],[-97.1288,48.7225],[-97.1297,48.7229],[-97.131,48.7233],[-97.1321,48.7238],[-97.1331,48.7242],[-97.1345,48.7248],[-97.136,48.7257],[-97.1369,48.7263],[-97.1375,48.727],[-97.1376,48.7274],[-97.1376,48.7278],[-97.1373,48.7283],[-97.137,48.7284],[-97.1365,48.7285],[-97.136,48.7287],[-97.1352,48.7287],[-97.1341,48.7289],[-97.1333,48.7291],[-97.1328,48.7292],[-97.132,48.7294],[-97.1312,48.7295],[-97.1308,48.7296],[-97.1299,48.7299],[-97.1294,48.7304],[-97.1288,48.7308],[-97.1286,48.7312],[-97.1286,48.7315],[-97.1286,48.7316],[-97.1286,48.7318],[-97.1285,48.7322],[-97.1286,48.7326],[-97.1286,48.7328],[-97.1287,48.7331],[-97.129,48.7335],[-97.1295,48.7339],[-97.1298,48.7341],[-97.1316,48.7347],[-97.1322,48.7348],[-97.1334,48.7347],[-97.1351,48.7345],[-97.1369,48.7345],[-97.1383,48.7345],[-97.1396,48.7347],[-97.1402,48.7349],[-97.1412,48.7354],[-97.1419,48.7359],[-97.1422,48.7367],[-97.1423,48.7372],[-97.1421,48.7381],[-97.1414,48.7385],[-97.1408,48.7387],[-97.1404,48.7389],[-97.1399,48.7393],[-97.1392,48.7397],[-97.1381,48.7408],[-97.1372,48.742],[-97.1366,48.7435],[-97.1365,48.745],[-97.1365,48.7459],[-97.1366,48.7466],[-97.1369,48.748],[-97.1375,48.7492],[-97.1379,48.75],[-97.1385,48.7504],[-97.1391,48.7507],[-97.1396,48.7508],[-97.1401,48.7509],[-97.141,48.751],[-97.142,48.751],[-97.143,48.7509],[-97.1444,48.7507],[-97.1457,48.7506],[-97.1466,48.7505],[-97.1476,48.7505],[-97.1491,48.7506],[-97.1497,48.7508],[-97.1503,48.7509],[-97.1515,48.7515],[-97.1521,48.752],[-97.153,48.7529],[-97.1539,48.7542],[-97.1545,48.7553],[-97.1547,48.7558],[-97.1548,48.7562],[-97.1548,48.7569],[-97.1548,48.7576],[-97.1546,48.758],[-97.1542,48.7587],[-97.1535,48.7593],[-97.1528,48.7598],[-97.1519,48.7601],[-97.1508,48.7605],[-97.1503,48.7606],[-97.1501,48.7607],[-97.1475,48.7616],[-97.1473,48.7617],[-97.1469,48.762],[-97.1462,48.7626],[-97.1461,48.7628],[-97.1459,48.7633],[-97.1456,48.7643],[-97.1456,48.765],[-97.146,48.7658],[-97.1476,48.7673],[-97.1487,48.7681],[-97.15,48.7692],[-97.1501,48.7693],[-97.1506,48.77],[-97.1512,48.7712],[-97.1519,48.7721],[-97.1525,48.7727],[-97.1529,48.7728],[-97.1559,48.7731],[-97.1567,48.7732],[-97.1578,48.7735],[-97.1582,48.7737],[-97.1587,48.7742],[-97.1589,48.7746],[-97.159,48.7751],[-97.159,48.7751],[-97.159,48.7754],[-97.1589,48.776],[-97.1584,48.7766],[-97.1579,48.7769],[-97.1573,48.7772],[-97.1557,48.7776],[-97.1544,48.7778],[-97.1534,48.778],[-97.1522,48.7783],[-97.1509,48.7787],[-97.1501,48.7789],[-97.1497,48.779],[-97.1483,48.7797],[-97.1477,48.7801],[-97.1473,48.7807],[-97.1472,48.7811],[-97.1473,48.7816],[-97.1478,48.7821],[-97.1486,48.7824],[-97.1495,48.7826],[-97.1501,48.7826],[-97.1503,48.7826],[-97.1513,48.7825],[-97.1533,48.7824],[-97.1547,48.7824],[-97.1559,48.7825],[-97.1571,48.7827],[-97.1583,48.783],[-97.1591,48.7834],[-97.1595,48.7838],[-97.1597,48.7843],[-97.1598,48.7848],[-97.1596,48.7853],[-97.1593,48.786],[-97.1591,48.7863],[-97.1586,48.7869],[-97.1577,48.7877],[-97.1574,48.7882],[-97.1573,48.7884],[-97.1572,48.7887],[-97.1571,48.7894],[-97.157,48.7895],[-97.157,48.7901],[-97.1572,48.7906],[-97.1575,48.7909],[-97.1581,48.7912],[-97.1586,48.7913],[-97.1592,48.7915],[-97.1595,48.7915],[-97.1611,48.7915],[-97.1618,48.7914],[-97.1645,48.7911],[-97.1648,48.7911],[-97.1657,48.7911],[-97.1664,48.7912],[-97.1672,48.7913],[-97.1714,48.7921],[-97.1718,48.7923],[-97.1721,48.7924],[-97.1731,48.7929],[-97.1737,48.7933],[-97.174,48.7937],[-97.1741,48.7942],[-97.1742,48.7947],[-97.1742,48.7951],[-97.1739,48.7954],[-97.1734,48.7958],[-97.1726,48.7963],[-97.1717,48.7966],[-97.1716,48.7966],[-97.171,48.7967],[-97.1701,48.7967],[-97.1688,48.7966],[-97.1673,48.7964],[-97.1665,48.7962],[-97.1654,48.7962],[-97.1648,48.7962],[-97.1638,48.7963],[-97.1631,48.7966],[-97.1625,48.7969],[-97.162,48.7974],[-97.1617,48.7979],[-97.1617,48.7984],[-97.1619,48.7988],[-97.1621,48.7994],[-97.1626,48.8001],[-97.1633,48.8007],[-97.1642,48.8011],[-97.1652,48.8014],[-97.166,48.8015],[-97.1668,48.8016],[-97.1675,48.8016],[-97.1685,48.8016],[-97.1698,48.8013],[-97.1706,48.8011],[-97.1714,48.8008],[-97.1715,48.8008],[-97.1724,48.8004],[-97.1731,48.8],[-97.1742,48.7992],[-97.175,48.7986],[-97.1754,48.7983],[-97.1757,48.798],[-97.1761,48.7977],[-97.1768,48.7974],[-97.1773,48.7973],[-97.1779,48.7972],[-97.1787,48.7972],[-97.1795,48.7972],[-97.1801,48.7973],[-97.1807,48.7975],[-97.1811,48.7978],[-97.1815,48.7982],[-97.1816,48.7986],[-97.1817,48.7991],[-97.1815,48.7995],[-97.1813,48.8],[-97.1808,48.8004],[-97.1801,48.8008],[-97.1791,48.8012],[-97.1779,48.8015],[-97.1769,48.8017],[-97.1764,48.8018],[-97.1756,48.8021],[-97.1748,48.8023],[-97.1725,48.8032],[-97.1713,48.8036],[-97.171,48.8037],[-97.1706,48.8039],[-97.1694,48.8043],[-97.1682,48.8046],[-97.1675,48.8048],[-97.1666,48.805],[-97.1655,48.8052],[-97.1638,48.8055],[-97.161,48.8059],[-97.1605,48.8061],[-97.1597,48.8064],[-97.159,48.8067],[-97.1583,48.8072],[-97.1579,48.8077],[-97.1577,48.8082],[-97.1576,48.8089],[-97.1578,48.8098],[-97.158,48.8104],[-97.1586,48.811],[-97.159,48.8111],[-97.161,48.8117],[-97.1617,48.8119],[-97.1625,48.812],[-97.1636,48.8121],[-97.1644,48.8121],[-97.1651,48.812],[-97.1666,48.8118],[-97.168,48.8116],[-97.169,48.8114],[-97.17,48.8114],[-97.1713,48.8115],[-97.1715,48.8115],[-97.1726,48.8117],[-97.1731,48.8118],[-97.174,48.8122],[-97.1761,48.8132],[-97.1776,48.8141],[-97.1784,48.8145],[-97.1797,48.8149],[-97.1807,48.8151],[-97.1821,48.8153],[-97.1828,48.8153],[-97.184,48.8152],[-97.1848,48.8151],[-97.186,48.8147],[-97.1868,48.8145],[-97.1873,48.8143],[-97.1879,48.8143],[-97.1883,48.8143],[-97.1889,48.8143],[-97.1894,48.8144],[-97.1898,48.8146],[-97.1901,48.8148],[-97.1903,48.8153],[-97.1904,48.8156],[-97.1903,48.8159],[-97.19,48.8163],[-97.1893,48.8167],[-97.1885,48.8171],[-97.1879,48.8173],[-97.1866,48.8176],[-97.1857,48.8177],[-97.1847,48.8179],[-97.184,48.8181],[-97.1833,48.8184],[-97.1817,48.8189],[-97.1809,48.8193],[-97.1801,48.8199],[-97.1793,48.8207],[-97.1787,48.8216],[-97.178,48.8232],[-97.1777,48.824],[-97.1776,48.8245],[-97.1777,48.8249],[-97.178,48.8255],[-97.1782,48.8258],[-97.1786,48.8262],[-97.1794,48.8268],[-97.1822,48.8288],[-97.1837,48.8299],[-97.1841,48.8304],[-97.1847,48.8314],[-97.1848,48.8319],[-97.1849,48.8326],[-97.1849,48.8327],[-97.1848,48.833],[-97.1846,48.8336],[-97.1842,48.8341],[-97.1837,48.8345],[-97.183,48.8348],[-97.1822,48.835],[-97.1813,48.8351],[-97.1799,48.8352],[-97.1783,48.8353],[-97.1779,48.8354],[-97.1772,48.8356],[-97.1757,48.8362],[-97.1753,48.8364],[-97.1747,48.8369],[-97.1742,48.8373],[-97.1739,48.8378],[-97.1738,48.8384],[-97.1738,48.839],[-97.1739,48.8406],[-97.1743,48.8427],[-97.1747,48.8438],[-97.175,48.8442],[-97.1755,48.8447],[-97.1761,48.8452],[-97.1767,48.8455],[-97.1771,48.8456],[-97.1779,48.8458],[-97.1795,48.8459],[-97.1808,48.846],[-97.1817,48.8462],[-97.1823,48.8464],[-97.1827,48.8468],[-97.1829,48.847],[-97.1829,48.8471],[-97.1829,48.8473],[-97.1826,48.8476],[-97.1821,48.8479],[-97.1816,48.848],[-97.1809,48.8481],[-97.1793,48.8482],[-97.178,48.8483],[-97.1767,48.8484],[-97.1759,48.8486],[-97.1753,48.8487],[-97.1747,48.849],[-97.1742,48.8493],[-97.1737,48.8497],[-97.1733,48.8502],[-97.173,48.8506],[-97.173,48.8508],[-97.173,48.8511],[-97.173,48.8516],[-97.1732,48.8522],[-97.1737,48.8527],[-97.1746,48.8534],[-97.1771,48.855],[-97.1784,48.8561],[-97.1786,48.8563],[-97.179,48.8569],[-97.1793,48.8576],[-97.1794,48.8583],[-97.1794,48.859],[-97.1792,48.8606],[-97.179,48.8615],[-97.179,48.862],[-97.1791,48.8626],[-97.1794,48.863],[-97.1801,48.8636],[-97.1811,48.864],[-97.1818,48.8641],[-97.1827,48.8641],[-97.1839,48.864],[-97.1855,48.8637],[-97.1871,48.8633],[-97.1877,48.8631],[-97.1883,48.8631],[-97.1891,48.8631],[-97.1896,48.8633],[-97.19,48.8635],[-97.1903,48.8639],[-97.1905,48.8644],[-97.1905,48.8648],[-97.1904,48.8651],[-97.1901,48.8657],[-97.1899,48.8661],[-97.1895,48.8665],[-97.189,48.867],[-97.1884,48.8675],[-97.1851,48.8694],[-97.1813,48.8718],[-97.1788,48.8736],[-97.1785,48.8738],[-97.1782,48.8741],[-97.1781,48.8743],[-97.1779,48.8745],[-97.1778,48.8747],[-97.1777,48.8749],[-97.1777,48.875],[-97.1778,48.875],[-97.1778,48.8754],[-97.1779,48.8757],[-97.1782,48.8761],[-97.1786,48.8765],[-97.1792,48.8769],[-97.1798,48.8771],[-97.1808,48.8772],[-97.1823,48.8772],[-97.1852,48.8768],[-97.1869,48.8765],[-97.1881,48.8765],[-97.1891,48.8766],[-97.1904,48.8769],[-97.1933,48.8779],[-97.1944,48.8783],[-97.1957,48.8788],[-97.1972,48.8794],[-97.1981,48.8799],[-97.1988,48.8805],[-97.1995,48.8812],[-97.1999,48.8818],[-97.1999,48.8821],[-97.2,48.8827],[-97.1998,48.8832],[-97.1997,48.8836],[-97.199,48.8845],[-97.1978,48.8859],[-97.1975,48.8865],[-97.1974,48.8868],[-97.1973,48.8872],[-97.1973,48.8874],[-97.1974,48.8877],[-97.1975,48.8881],[-97.1983,48.8889],[-97.2002,48.8903],[-97.2004,48.8904],[-97.2009,48.8908],[-97.2014,48.8912],[-97.2017,48.8915],[-97.2017,48.8919],[-97.2016,48.8922],[-97.2013,48.8925],[-97.201,48.8926],[-97.2001,48.8926],[-97.1994,48.8926],[-97.1985,48.8925],[-97.198,48.8924],[-97.1973,48.892],[-97.1957,48.8916],[-97.1946,48.8915],[-97.1944,48.8914],[-97.1937,48.8914],[-97.1927,48.8915],[-97.1921,48.8917],[-97.1916,48.8919],[-97.1905,48.8926],[-97.1901,48.8932],[-97.1898,48.8938],[-97.1897,48.8944],[-97.1897,48.8947],[-97.1898,48.8951],[-97.1899,48.8954],[-97.1903,48.896],[-97.1911,48.8967],[-97.1919,48.8974],[-97.1925,48.8979],[-97.1935,48.8985],[-97.1941,48.8988],[-97.1945,48.8989],[-97.1966,48.8997],[-97.1992,48.9004],[-97.2009,48.9009],[-97.2022,48.9013],[-97.2048,48.9018],[-97.2055,48.902],[-97.207,48.9025],[-97.2076,48.9027],[-97.2082,48.9029],[-97.2088,48.9032],[-97.2093,48.9036],[-97.21,48.904],[-97.2105,48.9044],[-97.211,48.905],[-97.2114,48.9056],[-97.2122,48.9069],[-97.2125,48.9075],[-97.2127,48.9082],[-97.2127,48.909],[-97.2125,48.9099],[-97.212,48.911],[-97.2116,48.9121],[-97.2111,48.913],[-97.2108,48.914],[-97.2106,48.9148],[-97.2106,48.9153],[-97.2109,48.9162],[-97.2111,48.9167],[-97.2115,48.9172],[-97.2118,48.9175],[-97.2122,48.9177],[-97.2129,48.9181],[-97.2149,48.9187],[-97.2163,48.9191],[-97.2164,48.9191],[-97.2171,48.9194],[-97.2179,48.9198],[-97.2189,48.9205],[-97.2196,48.9215],[-97.2198,48.9222],[-97.2199,48.923],[-97.2197,48.9237],[-97.2191,48.9249],[-97.2183,48.9262],[-97.2172,48.9277],[-97.2163,48.9286],[-97.2159,48.9289],[-97.2149,48.9301],[-97.2146,48.9304],[-97.2145,48.9307],[-97.2144,48.931],[-97.2145,48.9314],[-97.2145,48.9316],[-97.2148,48.9319],[-97.2154,48.9325],[-97.2159,48.9327],[-97.2162,48.9328],[-97.217,48.9328],[-97.2181,48.9327],[-97.2198,48.9325],[-97.2208,48.9325],[-97.2214,48.9325],[-97.2218,48.9326],[-97.2237,48.9332],[-97.2245,48.9337],[-97.2249,48.9339],[-97.225,48.934],[-97.2252,48.9342],[-97.2254,48.9345],[-97.2257,48.9349],[-97.226,48.9353],[-97.2263,48.936],[-97.2267,48.9376],[-97.227,48.9389],[-97.2271,48.9398],[-97.2271,48.941],[-97.227,48.9418],[-97.2266,48.9432],[-97.2264,48.9441],[-97.2263,48.9445],[-97.2264,48.9452],[-97.2265,48.9456],[-97.227,48.9462],[-97.2273,48.9465],[-97.2276,48.9467],[-97.2279,48.9467],[-97.2284,48.9468],[-97.2304,48.9465],[-97.2309,48.9464],[-97.2313,48.9464],[-97.2326,48.9466],[-97.2331,48.9468],[-97.2338,48.9471],[-97.2342,48.9474],[-97.2343,48.948],[-97.2343,48.9485],[-97.2342,48.9488],[-97.2341,48.9491],[-97.2337,48.95],[-97.2332,48.951],[-97.2328,48.9524],[-97.2323,48.954],[-97.2317,48.9558],[-97.2313,48.9568],[-97.2309,48.9578],[-97.2305,48.9585],[-97.23,48.9591],[-97.2288,48.9603],[-97.2282,48.9609],[-97.2278,48.9613],[-97.2276,48.9619],[-97.2276,48.9624],[-97.2279,48.963],[-97.228,48.9631],[-97.2283,48.9634],[-97.2289,48.9639],[-97.2294,48.9641],[-97.23,48.9642],[-97.2323,48.9646],[-97.2355,48.965],[-97.2368,48.9652],[-97.2375,48.9654],[-97.2382,48.966],[-97.2383,48.9661],[-97.2388,48.9666],[-97.2391,48.9676],[-97.2392,48.9687],[-97.239,48.9696],[-97.2387,48.9706],[-97.2383,48.9715],[-97.2381,48.9723],[-97.238,48.9725],[-97.2379,48.9731],[-97.2378,48.9734],[-97.2378,48.9738],[-97.238,48.9752],[-97.238,48.9763],[-97.2381,48.9771],[-97.238,48.9771],[-97.238,48.9841],[-97.2377,48.9849],[-97.2372,48.9857],[-97.2365,48.9867],[-97.2359,48.9874],[-97.2351,48.9881],[-97.2342,48.989],[-97.2335,48.9895],[-97.2331,48.9898],[-97.2317,48.9904],[-97.2301,48.9911],[-97.2293,48.9914],[-97.229,48.9916],[-97.2279,48.9921],[-97.2274,48.9925],[-97.227,48.9929],[-97.2266,48.9933],[-97.2265,48.9938],[-97.2267,48.9941],[-97.227,48.9945],[-97.2273,48.9947],[-97.2287,48.9949],[-97.2304,48.995],[-97.2317,48.9951],[-97.2324,48.9952],[-97.2335,48.9956],[-97.2338,48.9959],[-97.2341,48.9966],[-97.2341,48.997],[-97.234,48.9975],[-97.2337,48.9981],[-97.2332,48.9985],[-97.2323,48.999],[-97.2305,49.0],[-97.2303,49.0001],[-97.2295,49.0005],[-97.2175,49.0005],[-97.2161,49.0005],[-97.2078,49.0005],[-97.2069,49.0005],[-97.1955,49.0005],[-97.1939,49.0005],[-97.1739,49.0005],[-97.1724,49.0005],[-97.1514,49.0005],[-97.1502,49.0005],[-97.1294,49.0004],[-97.1277,49.0004],[-97.1073,49.0004],[-97.1061,49.0004],[-97.0853,49.0004],[-97.084,49.0004],[-97.0633,49.0004],[-97.062,49.0004],[-97.0412,49.0004],[-97.0401,49.0004],[-97.0192,49.0004],[-97.0183,49.0004],[-96.9971,49.0004],[-96.9961,49.0004],[-96.9751,49.0003],[-96.9738,49.0003],[-96.953,49.0003],[-96.9518,49.0003],[-96.931,49.0003],[-96.9299,49.0003],[-96.909,49.0003],[-96.9078,49.0003],[-96.8869,49.0003],[-96.8856,49.0003],[-96.8649,49.0003],[-96.864,49.0003],[-96.8429,49.0003],[-96.8415,49.0003],[-96.8208,49.0003],[-96.8197,49.0003],[-96.8023,49.0002],[-96.8005,49.0002],[-96.8003,49.0002],[-96.7988,49.0002],[-96.7787,49.0002],[-96.7768,49.0002],[-96.7567,49.0002],[-96.7547,49.0002],[-96.7348,49.0002],[-96.7327,49.0002],[-96.7127,49.0002],[-96.7107,49.0002],[-96.6905,49.0002],[-96.6886,49.0002],[-96.6695,49.0002],[-96.6665,49.0002],[-96.6482,49.0002],[-96.6445,49.0002],[-96.6243,49.0002],[-96.6225,49.0002],[-96.6021,49.0002],[-96.6004,49.0002],[-96.58,49.0002],[-96.5784,49.0002],[-96.558,49.0002],[-96.5563,49.0002],[-96.536,49.0002],[-96.5342,49.0002],[-96.5154,49.0002],[-96.5123,49.0002],[-96.4933,49.0002],[-96.49,49.0002],[-96.471,49.0001],[-96.4664,49.0001],[-96.4496,49.0001],[-96.4492,49.0001],[-96.4491,49.0001],[-96.446,49.0001],[-96.4273,49.0001],[-96.4224,49.0001],[-96.4054,49.0001]]],"type":"Polygon"},"id":"35","properties":{"Area":2862183702.23055,"CTYONLY_":3,"Code":"KITT","LASTMOD":"1999-12-31T23:59:59Z","Name":"Kittson","Perimiter":263017.48277},"type":"Feature"},{"geometry":{"coordinates":[[[-96.4054,49.0001],[-96.4019,49.0001],[-96.3825,49.0001],[-96.3783,49.0001],[-96.3606,49.0001],[-96.3579,49.0001],[-96.3385,49.0001],[-96.3343,49.0001],[-96.3166,49.0001],[-96.3138,49.0001],[-96.2945,49.0001],[-96.2902,49.0001],[-96.2725,49.0001],[-96.2698,49.0001],[-96.2494,49.0001],[-96.2461,49.0001],[-96.2274,49.0001],[-96.2257,49.0001],[-96.2057,49.0001],[-96.2021,49.0001],[-96.1837,49.0],[-96.18,49.0],[-96.1617,49.0],[-96.1579,49.0],[-96.1401,49.0],[-96.1359,49.0],[-96.1176,49.0],[-96.1139,49.0],[-96.0957,49.0],[-96.0919,49.0],[-96.0738,49.0],[-96.07,49.0],[-96.0517,49.0],[-96.048,49.0],[-96.0298,49.0],[-96.026,49.0],[-96.0083,49.0],[-96.0045,49.0],[-95.9868,49.0],[-95.9784,49.0],[-95.9776,49.0],[-95.9755,49.0],[-95.9648,48.9999],[-95.9464,48.9999],[-95.943,48.9999],[-95.9225,48.9999],[-95.9211,48.9999],[-95.899,48.9998],[-95.883,48.9998],[-95.8771,48.9998],[-95.8564,48.9998],[-95.855,48.9998],[-95.8342,48.9998],[-95.8184,48.9997],[-95.8126,48.9997],[-95.7906,48.9997],[-95.7833,48.9997],[-95.7684,48.9997],[-95.7479,48.9996],[-95.7466,48.9996],[-95.7253,48.9996],[-95.7066,48.9996],[-95.7032,48.9996],[-95.681,48.9995],[-95.6654,48.9995],[-95.6596,48.9995],[-95.659,48.9995],[-95.6401,48.9995],[-95.6369,48.9995],[-95.6205,48.9994],[-95.615,48.9994],[-95.5948,48.9994],[-95.585,48.9994],[-95.573,48.9994],[-95.551,48.9993],[-95.5495,48.9993],[-95.5294,48.9993],[-95.5164,48.9993],[-95.5072,48.9993],[-95.4849,48.9992],[-95.4834,48.9992],[-95.4635,48.9992],[-95.4508,48.9992],[-95.4418,48.9992],[-95.4245,48.9991],[-95.4197,48.9991],[-95.3977,48.9991],[-95.3953,48.9991],[-95.3765,48.9991],[-95.3759,48.9991],[-95.3753,48.9991],[-95.3542,48.999],[-95.3513,48.999],[-95.3326,48.999],[-95.3286,48.999],[-95.3231,48.999],[-95.3224,48.9984],[-95.3204,48.9976],[-95.3202,48.9973],[-95.3204,48.9964],[-95.3206,48.9961],[-95.3201,48.9956],[-95.3197,48.9954],[-95.3191,48.9953],[-95.3187,48.9956],[-95.3182,48.996],[-95.3179,48.9961],[-95.3178,48.9961],[-95.3178,48.9958],[-95.3181,48.995],[-95.3191,48.9941],[-95.3204,48.9924],[-95.3206,48.9921],[-95.3224,48.9889],[-95.3227,48.9884],[-95.3242,48.9859],[-95.3245,48.985],[-95.3253,48.9832],[-95.3257,48.9814],[-95.3256,48.98],[-95.3255,48.9789],[-95.3257,48.9784],[-95.3253,48.976],[-95.325,48.9743],[-95.3249,48.9738],[-95.3248,48.9728],[-95.3247,48.972],[-95.3241,48.9703],[-95.3232,48.9692],[-95.3227,48.9685],[-95.3212,48.9672],[-95.3207,48.9669],[-95.3201,48.9648],[-95.3198,48.9643],[-95.3193,48.964],[-95.3193,48.9622],[-95.3202,48.9606],[-95.3206,48.9598],[-95.3206,48.9595],[-95.3206,48.959],[-95.3202,48.9581],[-95.3191,48.9569],[-95.3188,48.9562],[-95.3179,48.9559],[-95.3175,48.9552],[-95.3177,48.9545],[-95.3182,48.9535],[-95.3181,48.9531],[-95.3177,48.9525],[-95.3154,48.9513],[-95.3151,48.951],[-95.3141,48.9508],[-95.3131,48.9503],[-95.3125,48.9503],[-95.3123,48.9502],[-95.3119,48.9502],[-95.3119,48.9507],[-95.3129,48.9521],[-95.3129,48.9523],[-95.3126,48.9524],[-95.312,48.9524],[-95.3115,48.952],[-95.3108,48.9512],[-95.3104,48.951],[-95.3097,48.951],[-95.3089,48.9511],[-95.3079,48.9509],[-95.3061,48.9502],[-95.3052,48.9495],[-95.3046,48.9482],[-95.3046,48.947],[-95.305,48.9462],[-95.3053,48.9459],[-95.3061,48.9454],[-95.3068,48.9454],[-95.3069,48.9455],[-95.3069,48.9456],[-95.3063,48.9462],[-95.3062,48.9463],[-95.3061,48.9469],[-95.3062,48.9472],[-95.3062,48.9472],[-95.3071,48.9477],[-95.3081,48.948],[-95.3094,48.9481],[-95.3096,48.9482],[-95.3099,48.9484],[-95.31,48.9485],[-95.3103,48.9485],[-95.3104,48.9484],[-95.3103,48.948],[-95.3096,48.9478],[-95.3092,48.9477],[-95.3079,48.9474],[-95.3071,48.9469],[-95.3071,48.9466],[-95.3074,48.9465],[-95.3078,48.9466],[-95.3085,48.947],[-95.3086,48.9469],[-95.3086,48.9465],[-95.3088,48.9464],[-95.3095,48.9463],[-95.3102,48.9463],[-95.3114,48.9461],[-95.3131,48.946],[-95.3141,48.9457],[-95.3148,48.9452],[-95.3154,48.9448],[-95.3168,48.9431],[-95.3181,48.9421],[-95.3189,48.9419],[-95.3219,48.9412],[-95.3225,48.9409],[-95.3228,48.9403],[-95.3231,48.9389],[-95.3229,48.9373],[-95.3225,48.9358],[-95.3223,48.9355],[-95.3228,48.9344],[-95.3222,48.9327],[-95.3209,48.9307],[-95.3208,48.9305],[-95.3195,48.9285],[-95.3168,48.9245],[-95.315,48.9222],[-95.3141,48.921],[-95.3132,48.9198],[-95.3126,48.919],[-95.3119,48.9178],[-95.3115,48.9172],[-95.3109,48.9163],[-95.3102,48.9155],[-95.3093,48.9149],[-95.3092,48.9149],[-95.3085,48.9146],[-95.3078,48.9141],[-95.3074,48.9135],[-95.3064,48.9129],[-95.3061,48.9128],[-95.3059,48.9127],[-95.3043,48.9119],[-95.3038,48.9114],[-95.3027,48.91],[-95.3017,48.9093],[-95.2999,48.9086],[-95.2978,48.9083],[-95.2973,48.9081],[-95.2973,48.908],[-95.2973,48.9077],[-95.2976,48.9074],[-95.2977,48.9073],[-95.2978,48.9073],[-95.2978,48.9072],[-95.2978,48.9072],[-95.2979,48.9072],[-95.2979,48.9072],[-95.2979,48.9071],[-95.298,48.9071],[-95.298,48.9071],[-95.298,48.9071],[-95.2981,48.907],[-95.2982,48.9068],[-95.2983,48.9068],[-95.2985,48.9065],[-95.2985,48.9064],[-95.2986,48.9063],[-95.2988,48.906],[-95.2989,48.906],[-95.2991,48.9057],[-95.2992,48.9055],[-95.2994,48.9053],[-95.2996,48.9051],[-95.2997,48.905],[-95.2999,48.9048],[-95.2999,48.9048],[-95.2999,48.9048],[-95.3,48.9047],[-95.3,48.9047],[-95.3001,48.9047],[-95.3001,48.9046],[-95.3002,48.9045],[-95.3005,48.904],[-95.2993,48.9035],[-95.2983,48.9028],[-95.298,48.9027],[-95.2976,48.9026],[-95.2967,48.9027],[-95.2949,48.9028],[-95.2941,48.9027],[-95.2937,48.9023],[-95.2935,48.902],[-95.2927,48.9019],[-95.2914,48.9019],[-95.2909,48.9017],[-95.2908,48.9016],[-95.2907,48.9014],[-95.2906,48.9011],[-95.2911,48.9008],[-95.2911,48.9006],[-95.2901,48.9003],[-95.2896,48.9],[-95.289,48.8994],[-95.2882,48.8981],[-95.2879,48.8979],[-95.2872,48.8977],[-95.287,48.8976],[-95.2865,48.8975],[-95.2861,48.8976],[-95.2853,48.8977],[-95.2839,48.8975],[-95.2813,48.8967],[-95.2803,48.8965],[-95.2796,48.8962],[-95.279,48.8957],[-95.2782,48.8956],[-95.2773,48.8957],[-95.277,48.8958],[-95.2765,48.8962],[-95.2763,48.8963],[-95.2759,48.8962],[-95.2755,48.8959],[-95.2749,48.8956],[-95.2748,48.8951],[-95.2753,48.8943],[-95.2751,48.8938],[-95.2745,48.8931],[-95.2724,48.8921],[-95.2713,48.8915],[-95.268,48.8905],[-95.2677,48.8903],[-95.2674,48.89],[-95.2666,48.8894],[-95.2654,48.8888],[-95.265,48.8886],[-95.2646,48.8885],[-95.2639,48.8883],[-95.2635,48.888],[-95.2627,48.8877],[-95.2585,48.8867],[-95.2585,48.8867],[-95.257,48.8858],[-95.256,48.885],[-95.2548,48.8845],[-95.2517,48.8839],[-95.2507,48.8836],[-95.2502,48.8835],[-95.2496,48.8834],[-95.2485,48.8832],[-95.248,48.8836],[-95.2472,48.8835],[-95.2458,48.8829],[-95.2439,48.8823],[-95.2429,48.8822],[-95.2429,48.8822],[-95.2423,48.8821],[-95.2407,48.8821],[-95.2391,48.8819],[-95.2381,48.8817],[-95.2356,48.8815],[-95.2335,48.8814],[-95.231,48.8814],[-95.2287,48.8815],[-95.2265,48.8816],[-95.2252,48.8819],[-95.2212,48.883],[-95.2208,48.8831],[-95.2207,48.8831],[-95.22,48.8831],[-95.2193,48.8832],[-95.2188,48.8835],[-95.217,48.8835],[-95.2159,48.8839],[-95.2151,48.884],[-95.2144,48.8843],[-95.2122,48.8842],[-95.2117,48.8847],[-95.2115,48.8847],[-95.2112,48.8848],[-95.2085,48.8846],[-95.2059,48.8848],[-95.2024,48.8852],[-95.2009,48.8855],[-95.2005,48.8856],[-95.1986,48.8855],[-95.1956,48.8862],[-95.1924,48.8865],[-95.1919,48.8866],[-95.1913,48.8868],[-95.1901,48.887],[-95.1889,48.8873],[-95.1877,48.8874],[-95.1863,48.8877],[-95.1851,48.8882],[-95.1819,48.8888],[-95.1797,48.889],[-95.1791,48.889],[-95.1764,48.8893],[-95.173,48.8897],[-95.1701,48.8902],[-95.1674,48.8907],[-95.1648,48.8913],[-95.1641,48.8917],[-95.1618,48.892],[-95.1602,48.892],[-95.1579,48.8919],[-95.1564,48.8919],[-95.1555,48.892],[-95.1528,48.8921],[-95.1508,48.8922],[-95.1483,48.8923],[-95.1469,48.8927],[-95.1459,48.8929],[-95.1438,48.8934],[-95.1436,48.8937],[-95.1404,48.8943],[-95.1381,48.8949],[-95.1355,48.8959],[-95.1351,48.8963],[-95.1348,48.8963],[-95.1343,48.8963],[-95.1337,48.8969],[-95.1322,48.8973],[-95.1312,48.8975],[-95.1252,48.8998],[-95.1239,48.9001],[-95.1233,48.9004],[-95.1228,48.9006],[-95.1214,48.9013],[-95.121,48.9016],[-95.1205,48.9017],[-95.1204,48.9019],[-95.1182,48.9029],[-95.1163,48.9037],[-95.1151,48.9046],[-95.1144,48.9052],[-95.114,48.9061],[-95.1141,48.9064],[-95.1137,48.9069],[-95.1132,48.9071],[-95.113,48.9072],[-95.1126,48.9073],[-95.1107,48.9082],[-95.1096,48.9089],[-95.108,48.9099],[-95.1056,48.9113],[-95.1042,48.9121],[-95.1032,48.9127],[-95.102,48.9132],[-95.1008,48.9142],[-95.0981,48.9159],[-95.098,48.916],[-95.0975,48.9164],[-95.0971,48.9172],[-95.097,48.9176],[-95.0961,48.9181],[-95.0946,48.9191],[-95.0944,48.9193],[-95.0927,48.9204],[-95.0919,48.9207],[-95.0914,48.9208],[-95.0914,48.916],[-95.0912,48.9014],[-95.0911,48.8869],[-95.0908,48.8724],[-95.0908,48.858],[-95.0907,48.8436],[-95.0908,48.8291],[-95.0909,48.8147],[-95.0903,48.8],[-95.0903,48.7855],[-95.0903,48.7711],[-95.0901,48.7566],[-95.0901,48.7421],[-95.0899,48.7277],[-95.0898,48.713],[-95.1046,48.7129],[-95.1104,48.7129],[-95.1119,48.7129],[-95.1259,48.7129],[-95.1297,48.713],[-95.1333,48.713],[-95.1477,48.7129],[-95.1554,48.7129],[-95.1697,48.7129],[-95.1773,48.713],[-95.1917,48.713],[-95.1991,48.713],[-95.2112,48.713],[-95.2206,48.713],[-95.2331,48.713],[-95.2427,48.713],[-95.255,48.713],[-95.2645,48.713],[-95.2656,48.713],[-95.2767,48.713],[-95.2866,48.713],[-95.299,48.713],[-95.3051,48.713],[-95.3084,48.713],[-95.3205,48.713],[-95.3302,48.713],[-95.3425,48.7131],[-95.3425,48.6995],[-95.3424,48.6849],[-95.3423,48.6705],[-95.3424,48.6561],[-95.3425,48.6415],[-95.3426,48.6271],[-95.3424,48.6127],[-95.3426,48.5979],[-95.3423,48.5836],[-95.3423,48.5691],[-95.3424,48.5548],[-95.3425,48.5402],[-95.3628,48.5404],[-95.364,48.5403],[-95.3844,48.5402],[-95.386,48.5402],[-95.4061,48.5402],[-95.4078,48.5402],[-95.4279,48.54],[-95.4297,48.5399],[-95.4494,48.5399],[-95.4513,48.5399],[-95.4712,48.5396],[-95.4726,48.5396],[-95.493,48.5392],[-95.495,48.5392],[-95.5143,48.539],[-95.5163,48.539],[-95.5365,48.5389],[-95.5383,48.5389],[-95.558,48.5388],[-95.5603,48.5388],[-95.5801,48.5387],[-95.5821,48.5387],[-95.6023,48.5389],[-95.6232,48.5391],[-95.6447,48.5393],[-95.6666,48.5394],[-95.6886,48.5395],[-95.7102,48.5395],[-95.7322,48.54],[-95.7539,48.5404],[-95.7758,48.5406],[-95.7976,48.5405],[-95.8192,48.5404],[-95.8411,48.5406],[-95.8621,48.5414],[-95.8829,48.5419],[-95.8851,48.542],[-95.8986,48.5421],[-95.9046,48.5422],[-95.9064,48.5422],[-95.9269,48.5421],[-95.9486,48.5425],[-95.9498,48.5425],[-95.9704,48.543],[-95.9936,48.5435],[-96.0157,48.5437],[-96.0374,48.5438],[-96.0592,48.5437],[-96.0812,48.5436],[-96.1026,48.5438],[-96.1264,48.5439],[-96.1486,48.5442],[-96.1702,48.5445],[-96.1921,48.5446],[-96.2141,48.5449],[-96.2358,48.5452],[-96.2576,48.545],[-96.2794,48.5449],[-96.301,48.5448],[-96.3231,48.5446],[-96.3448,48.5444],[-96.3667,48.5443],[-96.3882,48.5442],[-96.3879,48.5588],[-96.3882,48.5733],[-96.3884,48.5877],[-96.3891,48.6024],[-96.389,48.6165],[-96.388,48.6313],[-96.3879,48.6454],[-96.3877,48.6599],[-96.3871,48.6741],[-96.3874,48.6887],[-96.3866,48.703],[-96.3873,48.7172],[-96.388,48.7172],[-96.4049,48.7172],[-96.4048,48.7318],[-96.4048,48.7465],[-96.4047,48.7607],[-96.4045,48.7758],[-96.4042,48.7903],[-96.4042,48.8048],[-96.4042,48.8198],[-96.4043,48.8343],[-96.4045,48.8491],[-96.4047,48.8635],[-96.405,48.878],[-96.405,48.8926],[-96.4053,48.9068],[-96.4053,48.9081],[-96.4053,48.9137],[-96.4054,48.9214],[-96.4054,48.9225],[-96.4053,48.936],[-96.4053,48.9371],[-96.4053,48.9504],[-96.4053,48.9515],[-96.4053,48.9648],[-96.4053,48.9658],[-96.4053,48.9705],[-96.4054,48.9793],[-96.4054,48.9803],[-96.4054,48.994],[-96.4054,48.9947],[-96.4054,49.0001]]],"type":"Polygon"},"id":"68","properties":{"Area":4347098503.12714,"CTYONLY_":4,"Code":"ROSE","LASTMOD":"2001-04-12T09:32:44Z","Name":"Roseau","Perimiter":302590.75293},"type":"Feature"},{"geometry":{"coordinates":[[[-94.4299,48.7012],[-94.4241,48.7053],[-94.4213,48.7086],[-94.4189,48.7103],[-94.4158,48.711],[-94.4081,48.7106],[-94.406,48.7105],[-94.3889,48.712],[-94.3859,48.7119],[-94.384,48.7119],[-94.3801,48.7111],[-94.3687,48.7065],[-94.3646,48.7059],[-94.3533,48.7042],[-94.3431,48.7035],[-94.3429,48.7035],[-94.3287,48.7045],[-94.3214,48.7067],[-94.3088,48.7103],[-94.2995,48.709],[-94.2911,48.7079],[-94.2829,48.7057],[-94.2781,48.7024],[-94.2745,48.6999],[-94.2694,48.6995],[-94.2644,48.699],[-94.261,48.6966],[-94.258,48.6918],[-94.2565,48.6901],[-94.2529,48.6864],[-94.2521,48.685],[-94.2514,48.6837],[-94.2507,48.6782],[-94.2527,48.6707],[-94.253,48.6693],[-94.2548,48.664],[-94.2546,48.6615],[-94.2509,48.657],[-94.2499,48.6563],[-94.2467,48.6542],[-94.2445,48.6535],[-94.2343,48.6524],[-94.2335,48.6524],[-94.2242,48.6495],[-94.2144,48.6494],[-94.2124,48.6496],[-94.1996,48.651],[-94.1915,48.6506],[-94.1886,48.6504],[-94.1689,48.6483],[-94.1678,48.6482],[-94.1574,48.6458],[-94.1522,48.6455],[-94.1458,48.6458],[-94.1391,48.646],[-94.126,48.6444],[-94.1235,48.6444],[-94.11,48.6443],[-94.1023,48.6455],[-94.0999,48.6459],[-94.0912,48.6437],[-94.0849,48.6441],[-94.0804,48.6442],[-94.0767,48.6442],[-94.0714,48.6459],[-94.0658,48.6462],[-94.0642,48.6438],[-94.0603,48.6431],[-94.0581,48.6434],[-94.0525,48.644],[-94.0432,48.6435],[-94.0393,48.6423],[-94.0364,48.6413],[-94.0356,48.6411],[-94.0295,48.6409],[-94.0153,48.6424],[-94.0069,48.6433],[-94.0007,48.6428],[-93.9931,48.6412],[-93.9897,48.6405],[-93.984,48.6401],[-93.9777,48.6385],[-93.9712,48.6385],[-93.968,48.6385],[-93.9596,48.6372],[-93.953,48.6341],[-93.9497,48.6339],[-93.934,48.6326],[-93.9272,48.6327],[-93.9169,48.6329],[-93.9134,48.6353],[-93.9057,48.6346],[-93.9054,48.6345],[-93.8948,48.6324],[-93.8853,48.6318],[-93.8844,48.6318],[-93.8757,48.6319],[-93.8698,48.6311],[-93.8624,48.631],[-93.848,48.6308],[-93.8443,48.6303],[-93.8404,48.6289],[-93.8393,48.6286],[-93.8365,48.6276],[-93.8334,48.6256],[-93.8292,48.6177],[-93.825,48.6136],[-93.8245,48.613],[-93.8214,48.6092],[-93.8182,48.5994],[-93.8175,48.597],[-93.8172,48.5964],[-93.813,48.588],[-93.8103,48.5846],[-93.8063,48.5796],[-93.8041,48.5703],[-93.8041,48.5702],[-93.8051,48.5644],[-93.808,48.5569],[-93.8088,48.5555],[-93.8119,48.5503],[-93.8102,48.5445],[-93.8109,48.5412],[-93.8109,48.541],[-93.818,48.535],[-93.818,48.5346],[-93.8184,48.5315],[-93.8178,48.5306],[-93.8161,48.5285],[-93.8145,48.5273],[-93.8111,48.5247],[-93.803,48.522],[-93.7964,48.5182],[-93.7933,48.5164],[-93.7879,48.5159],[-93.7745,48.5162],[-93.768,48.5164],[-93.7665,48.5164],[-93.7617,48.5166],[-93.7534,48.5158],[-93.7442,48.5175],[-93.739,48.5185],[-93.731,48.5185],[-93.7225,48.5178],[-93.7206,48.5176],[-93.7108,48.5186],[-93.7061,48.5182],[-93.7006,48.517],[-93.693,48.5152],[-93.6866,48.5154],[-93.6791,48.5167],[-93.6778,48.5169],[-93.6593,48.5165],[-93.657,48.5167],[-93.6473,48.5177],[-93.6433,48.519],[-93.6421,48.5199],[-93.6395,48.5218],[-93.6357,48.5285],[-93.6344,48.5293],[-93.6311,48.5313],[-93.6284,48.5319],[-93.6256,48.5315],[-93.6211,48.5264],[-93.6166,48.5238],[-93.6134,48.5228],[-93.6122,48.5225],[-93.6051,48.5231],[-93.5962,48.5287],[-93.5919,48.5299],[-93.5901,48.5305],[-93.581,48.5271],[-93.5761,48.527],[-93.5701,48.528],[-93.5602,48.5297],[-93.5484,48.5294],[-93.5476,48.5294],[-93.5425,48.53],[-93.5366,48.5319],[-93.5269,48.5341],[-93.5263,48.5341],[-93.5244,48.5343],[-93.5171,48.5348],[-93.5047,48.5399],[-93.501,48.5414],[-93.4952,48.5426],[-93.4854,48.5433],[-93.4833,48.5437],[-93.4673,48.5465],[-93.4655,48.5478],[-93.4625,48.5498],[-93.462,48.5505],[-93.4596,48.5537],[-93.4576,48.5598],[-93.4576,48.5621],[-93.4575,48.5672],[-93.4619,48.5731],[-93.4619,48.5734],[-93.4631,48.5767],[-93.4671,48.5885],[-93.4656,48.59],[-93.4654,48.5915],[-93.4654,48.5917],[-93.4627,48.5927],[-93.46,48.5927],[-93.4547,48.5927],[-93.4398,48.5937],[-93.4385,48.5942],[-93.4347,48.5954],[-93.4298,48.5997],[-93.4226,48.6032],[-93.4193,48.6036],[-93.416,48.605],[-93.4152,48.6053],[-93.415,48.6056],[-93.4144,48.6064],[-93.4056,48.6099],[-93.4034,48.61],[-93.4029,48.6077],[-93.4013,48.6079],[-93.3994,48.6055],[-93.3986,48.6045],[-93.3953,48.6038],[-93.3937,48.6041],[-93.3837,48.606],[-93.3724,48.6059],[-93.3714,48.6059],[-93.3672,48.6082],[-93.3619,48.6141],[-93.355,48.6114],[-93.3526,48.6135],[-93.3533,48.615],[-93.3513,48.62],[-93.3505,48.6219],[-93.3486,48.6265],[-93.3276,48.6302],[-93.3057,48.634],[-93.3048,48.6341],[-93.2838,48.6378],[-93.2634,48.6413],[-93.2546,48.6429],[-93.2422,48.6428],[-93.2193,48.6426],[-93.2075,48.6426],[-93.1975,48.6365],[-93.191,48.6325],[-93.184,48.6282],[-93.1783,48.6231],[-93.1754,48.6232],[-93.1531,48.6244],[-93.1319,48.6256],[-93.1104,48.6267],[-93.0903,48.6278],[-93.0884,48.6278],[-93.0886,48.6163],[-93.0895,48.6016],[-93.0898,48.5872],[-93.09,48.5727],[-93.0902,48.5583],[-93.0902,48.5441],[-93.0903,48.5296],[-93.0905,48.5151],[-93.0905,48.501],[-93.091,48.4884],[-93.0911,48.4867],[-93.0914,48.474],[-93.0915,48.4724],[-93.0918,48.4596],[-93.0919,48.458],[-93.092,48.4449],[-93.092,48.4436],[-93.0922,48.4303],[-93.0922,48.429],[-93.0923,48.4147],[-93.0935,48.4147],[-93.0938,48.4024],[-93.094,48.3879],[-93.094,48.3734],[-93.0945,48.3589],[-93.0948,48.3442],[-93.0948,48.3298],[-93.0953,48.3153],[-93.0952,48.3004],[-93.095,48.2862],[-93.0952,48.2716],[-93.0953,48.2576],[-93.0949,48.2426],[-93.0949,48.2425],[-93.0977,48.2426],[-93.0977,48.2271],[-93.0978,48.2126],[-93.0979,48.1981],[-93.0975,48.1836],[-93.097,48.1692],[-93.097,48.1546],[-93.097,48.1402],[-93.0969,48.1259],[-93.0972,48.1114],[-93.097,48.0969],[-93.0968,48.0823],[-93.0965,48.0679],[-93.0965,48.0678],[-93.0892,48.0679],[-93.0892,48.0509],[-93.089,48.0366],[-93.0886,48.022],[-93.0887,48.0075],[-93.0872,47.9932],[-93.088,47.9787],[-93.0809,47.9786],[-93.0809,47.967],[-93.0808,47.9647],[-93.0808,47.9525],[-93.0808,47.9504],[-93.0809,47.938],[-93.0809,47.9356],[-93.0809,47.9235],[-93.0809,47.9212],[-93.0809,47.9088],[-93.0809,47.9067],[-93.0808,47.8945],[-93.0808,47.8922],[-93.1015,47.8927],[-93.1232,47.893],[-93.1448,47.8928],[-93.1656,47.8931],[-93.1671,47.8932],[-93.1871,47.8931],[-93.1893,47.8931],[-93.2087,47.8933],[-93.2115,47.8934],[-93.2331,47.8937],[-93.2532,47.8936],[-93.2745,47.8938],[-93.2962,47.8939],[-93.3169,47.894],[-93.3392,47.8941],[-93.3603,47.8942],[-93.3809,47.8943],[-93.4024,47.8944],[-93.4235,47.8945],[-93.4442,47.8946],[-93.466,47.895],[-93.4874,47.8956],[-93.4892,47.8957],[-93.4933,47.8958],[-93.5085,47.8962],[-93.5105,47.8963],[-93.5297,47.8967],[-93.5303,47.8967],[-93.532,47.8968],[-93.5517,47.8973],[-93.5532,47.8974],[-93.5729,47.8981],[-93.5747,47.8982],[-93.5962,47.8978],[-93.5966,47.8978],[-93.6179,47.8977],[-93.6187,47.8977],[-93.6388,47.8977],[-93.6395,47.8976],[-93.6604,47.8976],[-93.6612,47.8976],[-93.6817,47.8976],[-93.6826,47.8976],[-93.7031,47.8976],[-93.7038,47.8976],[-93.7249,47.8975],[-93.7248,47.8989],[-93.7466,47.8989],[-93.768,47.8991],[-93.7758,47.8991],[-93.7758,47.899],[-93.776,47.8897],[-93.776,47.8842],[-93.7762,47.8753],[-93.7761,47.8697],[-93.7761,47.8607],[-93.7761,47.8553],[-93.7761,47.8464],[-93.7896,47.8465],[-93.7971,47.8466],[-93.8189,47.8467],[-93.8407,47.8468],[-93.8627,47.8469],[-93.8831,47.8471],[-93.9067,47.8471],[-93.9288,47.8475],[-93.9496,47.8475],[-93.9506,47.8475],[-93.971,47.8475],[-93.9725,47.8475],[-93.9927,47.8475],[-93.9942,47.8475],[-94.0141,47.8476],[-94.0161,47.8476],[-94.0375,47.8477],[-94.0591,47.8474],[-94.0807,47.8471],[-94.1022,47.8471],[-94.1239,47.8466],[-94.1448,47.8463],[-94.1657,47.8461],[-94.1822,47.8461],[-94.1871,47.846],[-94.2037,47.846],[-94.2086,47.846],[-94.2252,47.846],[-94.23,47.8461],[-94.2467,47.8462],[-94.2515,47.8462],[-94.2681,47.8462],[-94.2728,47.8462],[-94.2887,47.8462],[-94.3103,47.8458],[-94.3315,47.846],[-94.3532,47.8464],[-94.3747,47.8462],[-94.3964,47.8461],[-94.4185,47.8459],[-94.4186,47.86],[-94.4184,47.8744],[-94.418,47.8886],[-94.4177,47.9031],[-94.4176,47.9041],[-94.4175,47.9175],[-94.4174,47.9186],[-94.4175,47.9332],[-94.4174,47.9477],[-94.4172,47.9623],[-94.4173,47.9769],[-94.4176,47.9914],[-94.4177,48.006],[-94.4176,48.02],[-94.4236,48.0199],[-94.4241,48.0344],[-94.4246,48.0489],[-94.4247,48.0632],[-94.4234,48.0776],[-94.4231,48.092],[-94.4233,48.1059],[-94.4234,48.1204],[-94.4236,48.1348],[-94.4233,48.1491],[-94.4235,48.1637],[-94.4235,48.1781],[-94.4233,48.1923],[-94.4236,48.2067],[-94.4238,48.2212],[-94.4237,48.2356],[-94.4237,48.2504],[-94.424,48.2649],[-94.4243,48.2791],[-94.4244,48.2938],[-94.4246,48.3081],[-94.4248,48.3227],[-94.425,48.3372],[-94.4253,48.352],[-94.4252,48.3675],[-94.4288,48.3675],[-94.4289,48.3821],[-94.4293,48.3964],[-94.4294,48.411],[-94.4293,48.4254],[-94.4292,48.4399],[-94.4293,48.4543],[-94.4296,48.4688],[-94.4296,48.4832],[-94.4299,48.4977],[-94.4303,48.512],[-94.4303,48.5264],[-94.43,48.5409],[-94.4295,48.5554],[-94.4291,48.5698],[-94.4289,48.5844],[-94.4289,48.5988],[-94.4292,48.6133],[-94.4294,48.6276],[-94.4297,48.642],[-94.43,48.6564],[-94.4301,48.6708],[-94.43,48.6852],[-94.4299,48.6998],[-94.4299,48.7012]]],"type":"Polygon"},"id":"36","properties":{"Area":8167237870.91888,"CTYONLY_":5,"Code":"KOOC","LASTMOD":"1999-12-31T23:59:59Z","Name":"Koochiching","Perimiter":412897.43594},"type":"Feature"},{"geometry":{"coordinates":[[[-96.3882,48.5442],[-96.3667,48.5443],[-96.3448,48.5444],[-96.3231,48.5446],[-96.301,48.5448],[-96.2794,48.5449],[-96.2576,48.545],[-96.2358,48.5452],[-96.2141,48.5449],[-96.1921,48.5446],[-96.1702,48.5445],[-96.1486,48.5442],[-96.1264,48.5439],[-96.1026,48.5438],[-96.0812,48.5436],[-96.0592,48.5437],[-96.0374,48.5438],[-96.0157,48.5437],[-95.9936,48.5435],[-95.9704,48.543],[-95.9498,48.5425],[-95.9486,48.5425],[-95.9269,48.5421],[-95.9064,48.5422],[-95.9046,48.5422],[-95.8986,48.5421],[-95.8851,48.542],[-95.8829,48.5419],[-95.8621,48.5414],[-95.8411,48.5406],[-95.8192,48.5404],[-95.7976,48.5405],[-95.7758,48.5406],[-95.7539,48.5404],[-95.7322,48.54],[-95.7102,48.5395],[-95.6886,48.5395],[-95.6666,48.5394],[-95.6447,48.5393],[-95.6232,48.5391],[-95.6023,48.5389],[-95.6011,48.5251],[-95.6007,48.5107],[-95.6007,48.51],[-95.6008,48.4964],[-95.6008,48.4956],[-95.6011,48.4818],[-95.6011,48.4811],[-95.6016,48.4674],[-95.6016,48.4666],[-95.6016,48.453],[-95.6016,48.4522],[-95.602,48.4385],[-95.6021,48.4376],[-95.6023,48.424],[-95.6023,48.4232],[-95.6026,48.4095],[-95.6026,48.4088],[-95.6026,48.395],[-95.6026,48.3942],[-95.6021,48.3809],[-95.602,48.3798],[-95.6016,48.3655],[-95.5933,48.3656],[-95.5933,48.3656],[-95.5933,48.354],[-95.5932,48.3396],[-95.5932,48.325],[-95.5932,48.3105],[-95.5934,48.2961],[-95.5934,48.2815],[-95.5937,48.267],[-95.5941,48.2526],[-95.5941,48.2382],[-95.5939,48.2236],[-95.5939,48.2092],[-95.5938,48.1946],[-95.594,48.1802],[-95.5939,48.173],[-95.5941,48.173],[-95.6159,48.1731],[-95.6163,48.1731],[-95.6252,48.1731],[-95.6279,48.1731],[-95.6376,48.173],[-95.6376,48.173],[-95.6591,48.1729],[-95.662,48.1729],[-95.6802,48.1728],[-95.6803,48.1728],[-95.702,48.1729],[-95.7021,48.1729],[-95.7022,48.1729],[-95.7128,48.173],[-95.7157,48.1731],[-95.7226,48.1731],[-95.7227,48.1731],[-95.744,48.1727],[-95.7443,48.1727],[-95.7502,48.1727],[-95.7657,48.1728],[-95.7657,48.1728],[-95.7874,48.1725],[-95.8088,48.1722],[-95.809,48.1722],[-95.8091,48.1722],[-95.8305,48.1722],[-95.8308,48.1722],[-95.8308,48.1722],[-95.8499,48.1721],[-95.8525,48.1721],[-95.8527,48.1721],[-95.8744,48.172],[-95.8744,48.172],[-95.8752,48.172],[-95.8958,48.172],[-95.896,48.172],[-95.9176,48.1719],[-95.9178,48.1719],[-95.9178,48.1719],[-95.9392,48.1719],[-95.9394,48.1719],[-95.9608,48.1718],[-95.9609,48.1718],[-95.961,48.1718],[-95.9651,48.1718],[-95.9817,48.1717],[-95.9819,48.1717],[-95.9956,48.1717],[-96.0003,48.1717],[-96.0023,48.1718],[-96.0028,48.1718],[-96.0032,48.1718],[-96.0035,48.1718],[-96.0036,48.1718],[-96.0047,48.1717],[-96.0101,48.1718],[-96.0171,48.172],[-96.025,48.1721],[-96.0254,48.1721],[-96.0468,48.1722],[-96.0468,48.1722],[-96.0592,48.1721],[-96.0685,48.1721],[-96.0685,48.1721],[-96.079,48.1721],[-96.09,48.172],[-96.09,48.172],[-96.0979,48.172],[-96.1084,48.1718],[-96.1084,48.1718],[-96.1176,48.1722],[-96.1189,48.1722],[-96.1253,48.1727],[-96.1297,48.173],[-96.1298,48.173],[-96.1302,48.173],[-96.1388,48.1732],[-96.1516,48.1736],[-96.1518,48.1736],[-96.1625,48.1736],[-96.1641,48.1736],[-96.1736,48.1736],[-96.1737,48.1736],[-96.1741,48.1736],[-96.1813,48.1725],[-96.1827,48.1722],[-96.1834,48.172],[-96.1874,48.1721],[-96.191,48.1721],[-96.1948,48.1721],[-96.1954,48.1721],[-96.1959,48.1721],[-96.1963,48.1721],[-96.2023,48.1722],[-96.2038,48.1722],[-96.2072,48.1722],[-96.2076,48.1722],[-96.2177,48.1722],[-96.2179,48.1722],[-96.2188,48.1722],[-96.2251,48.1724],[-96.2275,48.1724],[-96.2287,48.1725],[-96.2307,48.1725],[-96.2329,48.1725],[-96.2391,48.1727],[-96.2397,48.1727],[-96.2397,48.1727],[-96.2398,48.1728],[-96.2476,48.1735],[-96.2491,48.1737],[-96.2503,48.1739],[-96.2511,48.174],[-96.252,48.174],[-96.2562,48.1744],[-96.2596,48.1749],[-96.2607,48.1749],[-96.2612,48.1749],[-96.2619,48.1749],[-96.2805,48.1747],[-96.2823,48.1747],[-96.2824,48.1747],[-96.2977,48.1747],[-96.3029,48.1747],[-96.3035,48.1747],[-96.3145,48.1747],[-96.3252,48.1746],[-96.3253,48.1746],[-96.3301,48.1745],[-96.3356,48.1745],[-96.3358,48.1744],[-96.338,48.1745],[-96.3402,48.1744],[-96.343,48.1744],[-96.3466,48.1743],[-96.347,48.1743],[-96.3473,48.1744],[-96.3477,48.1744],[-96.351,48.1745],[-96.3542,48.1746],[-96.3581,48.1747],[-96.361,48.1748],[-96.3642,48.1749],[-96.3656,48.175],[-96.3682,48.1751],[-96.3682,48.1751],[-96.3685,48.1751],[-96.3706,48.175],[-96.3728,48.1749],[-96.3753,48.1748],[-96.3781,48.1746],[-96.38,48.1745],[-96.3856,48.1747],[-96.3894,48.1748],[-96.3905,48.1748],[-96.3906,48.1748],[-96.3964,48.1748],[-96.4054,48.1748],[-96.4126,48.1749],[-96.4126,48.1749],[-96.4135,48.1749],[-96.4206,48.1749],[-96.4295,48.1749],[-96.4346,48.1749],[-96.4352,48.1749],[-96.4359,48.1749],[-96.438,48.1749],[-96.4402,48.1748],[-96.4436,48.1747],[-96.4454,48.1747],[-96.4561,48.1744],[-96.4563,48.1743],[-96.4564,48.1742],[-96.4569,48.1742],[-96.4592,48.1742],[-96.467,48.1741],[-96.4735,48.174],[-96.4773,48.1741],[-96.4789,48.1741],[-96.4791,48.1741],[-96.4841,48.174],[-96.4946,48.1741],[-96.4973,48.174],[-96.5003,48.1741],[-96.5006,48.1741],[-96.5008,48.1742],[-96.5008,48.1742],[-96.5038,48.174],[-96.5091,48.174],[-96.5164,48.1739],[-96.5204,48.1739],[-96.5223,48.1739],[-96.5251,48.1738],[-96.53,48.1738],[-96.5357,48.1738],[-96.5399,48.1738],[-96.5434,48.1738],[-96.5442,48.1738],[-96.5443,48.1738],[-96.5446,48.1738],[-96.5479,48.1738],[-96.5507,48.1738],[-96.5544,48.1738],[-96.557,48.1739],[-96.5616,48.1739],[-96.565,48.174],[-96.5654,48.174],[-96.5655,48.174],[-96.5678,48.174],[-96.5715,48.1739],[-96.5748,48.1739],[-96.5765,48.1739],[-96.5806,48.1739],[-96.5838,48.1738],[-96.5873,48.1737],[-96.5873,48.1737],[-96.5875,48.1737],[-96.5893,48.1737],[-96.5966,48.1737],[-96.6055,48.1737],[-96.609,48.1737],[-96.6092,48.1737],[-96.6106,48.1737],[-96.6253,48.1737],[-96.6307,48.1737],[-96.6307,48.1737],[-96.6309,48.1737],[-96.6338,48.1737],[-96.6378,48.1738],[-96.6407,48.1739],[-96.6525,48.1738],[-96.6525,48.1738],[-96.6742,48.1736],[-96.6742,48.1736],[-96.6826,48.1735],[-96.6958,48.1734],[-96.6959,48.1734],[-96.7176,48.1734],[-96.7177,48.1734],[-96.7393,48.1734],[-96.7393,48.1734],[-96.7503,48.1734],[-96.7573,48.1734],[-96.7581,48.1734],[-96.7605,48.1734],[-96.7606,48.1734],[-96.7613,48.1734],[-96.7819,48.1734],[-96.7821,48.1734],[-96.7821,48.1734],[-96.7932,48.1733],[-96.8038,48.1734],[-96.8039,48.1734],[-96.8111,48.1734],[-96.8255,48.1734],[-96.8255,48.1734],[-96.8473,48.1733],[-96.8474,48.1733],[-96.869,48.1733],[-96.869,48.1733],[-96.8753,48.1732],[-96.8907,48.1732],[-96.8907,48.1732],[-96.8932,48.1732],[-96.9122,48.1733],[-96.9123,48.1733],[-96.933,48.1733],[-96.9339,48.1733],[-96.934,48.1733],[-96.9387,48.1732],[-96.9448,48.1732],[-96.9554,48.1731],[-96.9703,48.1731],[-96.9705,48.1731],[-96.9749,48.173],[-96.9751,48.173],[-96.9773,48.173],[-96.9773,48.173],[-96.9775,48.1731],[-96.9812,48.1731],[-96.9844,48.1731],[-96.9889,48.1731],[-96.99,48.1731],[-96.9959,48.1732],[-96.9975,48.1732],[-96.998,48.1732],[-96.9987,48.1732],[-96.9989,48.1732],[-96.999,48.1732],[-97.0003,48.1732],[-97.0203,48.1733],[-97.0205,48.1733],[-97.042,48.1732],[-97.042,48.1732],[-97.0637,48.1732],[-97.0637,48.1732],[-97.0853,48.1734],[-97.0855,48.1734],[-97.1069,48.1735],[-97.1071,48.1735],[-97.1253,48.1733],[-97.1257,48.1733],[-97.1286,48.1733],[-97.1322,48.1733],[-97.1376,48.1733],[-97.1462,48.1733],[-97.1467,48.1733],[-97.1452,48.1741],[-97.1434,48.1744],[-97.1417,48.1746],[-97.1389,48.1747],[-97.1371,48.1754],[-97.1365,48.1758],[-97.136,48.1768],[-97.1359,48.1789],[-97.1362,48.1796],[-97.1366,48.1809],[-97.1383,48.1824],[-97.1406,48.183],[-97.1413,48.1831],[-97.1432,48.1828],[-97.1455,48.1824],[-97.1467,48.1821],[-97.1484,48.1825],[-97.1498,48.1835],[-97.1497,48.1859],[-97.1491,48.1864],[-97.1475,48.1879],[-97.1449,48.1895],[-97.1429,48.191],[-97.1426,48.1913],[-97.1415,48.1926],[-97.1413,48.1934],[-97.1412,48.1937],[-97.141,48.194],[-97.1409,48.1945],[-97.1404,48.1947],[-97.1397,48.1951],[-97.1391,48.1953],[-97.1383,48.1955],[-97.1365,48.1963],[-97.1356,48.1972],[-97.1359,48.1984],[-97.1368,48.1996],[-97.1383,48.2006],[-97.1401,48.2018],[-97.1409,48.2027],[-97.1412,48.203],[-97.1411,48.204],[-97.1409,48.2046],[-97.14,48.2052],[-97.139,48.2059],[-97.1375,48.2063],[-97.1341,48.2068],[-97.1316,48.2072],[-97.1301,48.2077],[-97.1296,48.208],[-97.1295,48.208],[-97.1292,48.2084],[-97.1292,48.2099],[-97.1291,48.21],[-97.1296,48.2105],[-97.1297,48.2106],[-97.1299,48.2108],[-97.1307,48.211],[-97.1318,48.2112],[-97.1354,48.2116],[-97.1364,48.2119],[-97.1382,48.2131],[-97.1394,48.2144],[-97.1392,48.2168],[-97.1389,48.2171],[-97.1383,48.2174],[-97.1373,48.2177],[-97.1354,48.2179],[-97.1344,48.2178],[-97.1328,48.2176],[-97.1313,48.2172],[-97.1302,48.2164],[-97.1297,48.2161],[-97.1292,48.2158],[-97.1278,48.2145],[-97.1274,48.2134],[-97.1265,48.2113],[-97.126,48.2101],[-97.1259,48.2099],[-97.1257,48.2097],[-97.1253,48.2093],[-97.1245,48.208],[-97.1236,48.2077],[-97.1229,48.2074],[-97.1216,48.2074],[-97.1204,48.2073],[-97.1197,48.2076],[-97.1189,48.2079],[-97.1183,48.2086],[-97.118,48.2092],[-97.1178,48.2098],[-97.1179,48.2107],[-97.1181,48.2115],[-97.1189,48.2129],[-97.1194,48.2136],[-97.1208,48.215],[-97.122,48.2159],[-97.1228,48.2165],[-97.1248,48.2175],[-97.1253,48.2178],[-97.1272,48.2185],[-97.1289,48.2188],[-97.1297,48.219],[-97.1321,48.2196],[-97.135,48.2207],[-97.139,48.222],[-97.1406,48.2222],[-97.1417,48.2221],[-97.1436,48.2216],[-97.1448,48.2209],[-97.1455,48.2204],[-97.1457,48.2202],[-97.1458,48.2202],[-97.1462,48.2198],[-97.1471,48.2189],[-97.1482,48.2184],[-97.1497,48.2181],[-97.1509,48.2184],[-97.151,48.2185],[-97.1517,48.219],[-97.1521,48.2197],[-97.1521,48.2205],[-97.1517,48.2214],[-97.151,48.2222],[-97.1496,48.2232],[-97.1483,48.2238],[-97.1476,48.224],[-97.1465,48.2243],[-97.1436,48.2253],[-97.1408,48.2263],[-97.1385,48.2268],[-97.1371,48.227],[-97.1357,48.2271],[-97.1332,48.227],[-97.1317,48.2265],[-97.1305,48.2259],[-97.1298,48.2255],[-97.129,48.2251],[-97.1276,48.2245],[-97.1273,48.2243],[-97.1266,48.2239],[-97.1259,48.2236],[-97.1253,48.2234],[-97.1245,48.2232],[-97.1233,48.2231],[-97.1222,48.2234],[-97.1216,48.2236],[-97.121,48.2242],[-97.121,48.2242],[-97.1206,48.2248],[-97.1206,48.2254],[-97.1207,48.2259],[-97.1216,48.227],[-97.1225,48.2275],[-97.1234,48.2281],[-97.1244,48.2284],[-97.1253,48.2287],[-97.1278,48.2293],[-97.1299,48.2297],[-97.1303,48.2297],[-97.1325,48.2298],[-97.1351,48.2298],[-97.1393,48.2302],[-97.1423,48.231],[-97.1435,48.2318],[-97.1446,48.2336],[-97.1445,48.2343],[-97.1443,48.2351],[-97.143,48.2361],[-97.1416,48.2365],[-97.1411,48.2366],[-97.1399,48.2367],[-97.1377,48.2368],[-97.1358,48.237],[-97.1343,48.2378],[-97.1339,48.2382],[-97.1338,48.2386],[-97.1337,48.2391],[-97.1341,48.2397],[-97.1346,48.2403],[-97.1357,48.2409],[-97.1375,48.2414],[-97.1385,48.2415],[-97.1405,48.2415],[-97.1422,48.2412],[-97.1444,48.2412],[-97.1459,48.2417],[-97.147,48.2423],[-97.1471,48.243],[-97.1467,48.2445],[-97.146,48.2452],[-97.1444,48.2462],[-97.1431,48.2468],[-97.1404,48.2473],[-97.1389,48.2479],[-97.1377,48.2485],[-97.1355,48.2495],[-97.1345,48.2498],[-97.1334,48.2499],[-97.1305,48.2498],[-97.1299,48.2498],[-97.1291,48.2495],[-97.1274,48.2495],[-97.1263,48.2498],[-97.1253,48.25],[-97.1251,48.25],[-97.1247,48.2504],[-97.1244,48.2508],[-97.1243,48.2513],[-97.1243,48.252],[-97.1245,48.2526],[-97.1248,48.2532],[-97.1248,48.2532],[-97.1253,48.2537],[-97.1256,48.254],[-97.1262,48.2546],[-97.1267,48.2551],[-97.1274,48.2555],[-97.1291,48.2566],[-97.13,48.2573],[-97.1304,48.2576],[-97.1306,48.2581],[-97.1306,48.2587],[-97.1306,48.259],[-97.1303,48.2595],[-97.1298,48.2598],[-97.1292,48.2599],[-97.1283,48.26],[-97.1272,48.2601],[-97.1253,48.2601],[-97.1248,48.2602],[-97.1242,48.2604],[-97.1236,48.2607],[-97.1231,48.2612],[-97.1229,48.2617],[-97.123,48.2623],[-97.1234,48.2628],[-97.1237,48.2633],[-97.1241,48.2636],[-97.1246,48.2639],[-97.1253,48.2641],[-97.1262,48.2644],[-97.1285,48.2649],[-97.1303,48.2651],[-97.1305,48.2652],[-97.1333,48.2656],[-97.135,48.2659],[-97.136,48.2659],[-97.1375,48.2657],[-97.1395,48.2655],[-97.1406,48.2654],[-97.142,48.2654],[-97.1427,48.2656],[-97.1438,48.2658],[-97.1444,48.2663],[-97.1448,48.2668],[-97.145,48.2675],[-97.1451,48.2678],[-97.145,48.2688],[-97.1443,48.2698],[-97.1431,48.2705],[-97.1421,48.2709],[-97.1403,48.2712],[-97.1391,48.2713],[-97.1377,48.2713],[-97.1361,48.2711],[-97.1343,48.2707],[-97.1313,48.2701],[-97.1305,48.27],[-97.1298,48.2699],[-97.1288,48.2698],[-97.1272,48.2699],[-97.1265,48.2701],[-97.1253,48.2705],[-97.125,48.2707],[-97.1247,48.2709],[-97.124,48.2713],[-97.1238,48.2716],[-97.1237,48.2721],[-97.1237,48.2725],[-97.1239,48.2728],[-97.124,48.2733],[-97.1242,48.2737],[-97.1247,48.2743],[-97.1253,48.2751],[-97.1254,48.2753],[-97.1255,48.2755],[-97.1256,48.2758],[-97.1255,48.2761],[-97.1254,48.2762],[-97.1253,48.2764],[-97.1251,48.2767],[-97.1246,48.2769],[-97.124,48.277],[-97.1232,48.277],[-97.1224,48.2769],[-97.1213,48.2768],[-97.1206,48.2768],[-97.12,48.2769],[-97.1187,48.2774],[-97.1175,48.2781],[-97.117,48.2788],[-97.1165,48.2797],[-97.1166,48.2805],[-97.1166,48.2807],[-97.1167,48.2813],[-97.117,48.2821],[-97.1171,48.2824],[-97.1172,48.2826],[-97.1177,48.2835],[-97.1221,48.2901],[-97.1231,48.2909],[-97.1239,48.2913],[-97.1244,48.2915],[-97.1247,48.2917],[-97.1253,48.2919],[-97.1256,48.292],[-97.126,48.292],[-97.1265,48.292],[-97.1272,48.2919],[-97.128,48.2916],[-97.1285,48.2913],[-97.1295,48.2908],[-97.1303,48.2902],[-97.1305,48.2901],[-97.1314,48.2891],[-97.1322,48.2884],[-97.133,48.2879],[-97.1342,48.2874],[-97.1349,48.2872],[-97.1355,48.2871],[-97.1367,48.2873],[-97.1374,48.2877],[-97.1378,48.2879],[-97.1383,48.2887],[-97.1384,48.2894],[-97.1384,48.2898],[-97.1383,48.2903],[-97.138,48.2909],[-97.1373,48.2918],[-97.1368,48.2922],[-97.1364,48.2925],[-97.1355,48.2929],[-97.1344,48.2935],[-97.1335,48.2941],[-97.133,48.2946],[-97.1323,48.2953],[-97.1318,48.2959],[-97.1314,48.2963],[-97.131,48.2969],[-97.1306,48.2973],[-97.1305,48.2974],[-97.13,48.2979],[-97.1293,48.2984],[-97.1286,48.2987],[-97.1282,48.2989],[-97.1276,48.299],[-97.1271,48.2991],[-97.127,48.2991],[-97.1263,48.2991],[-97.1253,48.2989],[-97.125,48.2988],[-97.1246,48.2987],[-97.1241,48.2984],[-97.1234,48.2975],[-97.1228,48.2968],[-97.1227,48.2967],[-97.1213,48.2955],[-97.1203,48.2949],[-97.1192,48.2943],[-97.1167,48.294],[-97.1153,48.2939],[-97.1138,48.2943],[-97.1129,48.2949],[-97.1123,48.2954],[-97.1122,48.296],[-97.1122,48.2965],[-97.1123,48.2968],[-97.1126,48.2973],[-97.113,48.2978],[-97.1138,48.2984],[-97.1148,48.299],[-97.118,48.3004],[-97.12,48.3012],[-97.1227,48.3019],[-97.1241,48.3022],[-97.1247,48.3025],[-97.1253,48.3029],[-97.1255,48.303],[-97.1259,48.3033],[-97.1262,48.3036],[-97.1266,48.3041],[-97.1267,48.3046],[-97.1265,48.3055],[-97.1263,48.3059],[-97.1257,48.3064],[-97.1253,48.3067],[-97.1241,48.3073],[-97.123,48.3081],[-97.1222,48.3088],[-97.1221,48.3095],[-97.1222,48.3099],[-97.123,48.3105],[-97.1241,48.3112],[-97.1247,48.3115],[-97.1253,48.3119],[-97.1258,48.3119],[-97.1263,48.312],[-97.1269,48.312],[-97.1276,48.312],[-97.1282,48.3118],[-97.1289,48.3116],[-97.1298,48.3111],[-97.1299,48.3111],[-97.1303,48.3108],[-97.1304,48.3108],[-97.1311,48.3103],[-97.1318,48.3099],[-97.1325,48.3094],[-97.1331,48.3092],[-97.1336,48.309],[-97.1343,48.3089],[-97.1351,48.3089],[-97.1358,48.3089],[-97.1365,48.3091],[-97.1372,48.3094],[-97.1377,48.3098],[-97.1379,48.3102],[-97.1381,48.3106],[-97.138,48.3111],[-97.138,48.3116],[-97.1379,48.312],[-97.1376,48.3125],[-97.1372,48.3129],[-97.1367,48.3134],[-97.1361,48.3141],[-97.1356,48.3148],[-97.1351,48.3155],[-97.1348,48.316],[-97.1346,48.3166],[-97.1345,48.3171],[-97.1343,48.3177],[-97.134,48.3181],[-97.1335,48.3185],[-97.1329,48.3189],[-97.1325,48.3192],[-97.132,48.3194],[-97.1312,48.3196],[-97.1306,48.3196],[-97.1303,48.3196],[-97.1291,48.3196],[-97.1282,48.3195],[-97.1274,48.3195],[-97.1267,48.3195],[-97.1253,48.3196],[-97.1229,48.3201],[-97.1197,48.3208],[-97.1173,48.3216],[-97.1164,48.3222],[-97.1157,48.323],[-97.1155,48.3236],[-97.1155,48.324],[-97.1162,48.3248],[-97.1168,48.3253],[-97.1173,48.3258],[-97.1175,48.326],[-97.1187,48.3266],[-97.1203,48.3271],[-97.1222,48.3274],[-97.123,48.3275],[-97.1253,48.3277],[-97.1257,48.3277],[-97.1262,48.3278],[-97.1275,48.328],[-97.1292,48.3282],[-97.1303,48.3282],[-97.1311,48.3283],[-97.1317,48.3282],[-97.1326,48.3281],[-97.1337,48.3279],[-97.1343,48.3277],[-97.1345,48.3277],[-97.1353,48.3273],[-97.1359,48.327],[-97.1368,48.3263],[-97.1376,48.3257],[-97.138,48.3255],[-97.1385,48.3253],[-97.139,48.3251],[-97.1397,48.3251],[-97.1404,48.3252],[-97.141,48.3254],[-97.1415,48.3257],[-97.1417,48.3258],[-97.142,48.3262],[-97.1422,48.3267],[-97.1423,48.327],[-97.1422,48.3276],[-97.142,48.3281],[-97.1416,48.3287],[-97.1408,48.3294],[-97.14,48.3299],[-97.139,48.3304],[-97.1378,48.3309],[-97.1371,48.331],[-97.1361,48.3312],[-97.1347,48.3315],[-97.1325,48.3318],[-97.1311,48.3321],[-97.1305,48.3323],[-97.1295,48.3326],[-97.129,48.3329],[-97.1284,48.3336],[-97.1275,48.3352],[-97.1263,48.3379],[-97.1258,48.3384],[-97.1258,48.3398],[-97.1258,48.3402],[-97.1259,48.3406],[-97.1263,48.3415],[-97.1267,48.3422],[-97.1276,48.3427],[-97.1283,48.343],[-97.1297,48.3435],[-97.1308,48.3438],[-97.1309,48.3438],[-97.132,48.344],[-97.1334,48.3439],[-97.1354,48.3439],[-97.1372,48.344],[-97.1383,48.3441],[-97.1388,48.3441],[-97.1396,48.3443],[-97.14,48.3446],[-97.1405,48.345],[-97.1407,48.3453],[-97.1409,48.3456],[-97.141,48.3459],[-97.1408,48.3468],[-97.1405,48.3471],[-97.1396,48.3478],[-97.1386,48.3485],[-97.1376,48.3491],[-97.1368,48.3496],[-97.1362,48.3501],[-97.1361,48.3503],[-97.136,48.3505],[-97.136,48.3506],[-97.1359,48.351],[-97.1359,48.3511],[-97.136,48.3518],[-97.1362,48.3522],[-97.1363,48.3524],[-97.1365,48.3526],[-97.1373,48.3529],[-97.1382,48.3532],[-97.1387,48.3533],[-97.1398,48.3535],[-97.1405,48.3536],[-97.1415,48.3538],[-97.1423,48.354],[-97.143,48.3542],[-97.1435,48.3543],[-97.1438,48.3546],[-97.1441,48.3549],[-97.1442,48.3551],[-97.1443,48.3554],[-97.1445,48.356],[-97.1447,48.3565],[-97.145,48.3571],[-97.1453,48.3576],[-97.1459,48.3586],[-97.1464,48.3592],[-97.1468,48.3596],[-97.1477,48.3603],[-97.1484,48.3608],[-97.1501,48.3613],[-97.1517,48.362],[-97.1525,48.3623],[-97.1534,48.3628],[-97.1545,48.3633],[-97.1554,48.3638],[-97.1559,48.3646],[-97.1562,48.3656],[-97.1562,48.3662],[-97.156,48.3671],[-97.1558,48.3681],[-97.1555,48.3686],[-97.1554,48.3689],[-97.1552,48.3691],[-97.1548,48.37],[-97.1539,48.3704],[-97.1536,48.3705],[-97.1524,48.371],[-97.1523,48.371],[-97.1512,48.3713],[-97.1498,48.3712],[-97.1476,48.371],[-97.1437,48.3703],[-97.1433,48.3703],[-97.141,48.3702],[-97.1407,48.3703],[-97.1404,48.3703],[-97.1403,48.3703],[-97.1402,48.3703],[-97.1401,48.3703],[-97.1392,48.3705],[-97.1386,48.3708],[-97.1378,48.3713],[-97.1373,48.3718],[-97.1372,48.3724],[-97.1373,48.373],[-97.1376,48.3736],[-97.1383,48.3744],[-97.1389,48.375],[-97.1398,48.3759],[-97.1406,48.3769],[-97.1412,48.3777],[-97.1413,48.3785],[-97.1409,48.3793],[-97.1403,48.3797],[-97.1395,48.3801],[-97.1379,48.3803],[-97.1366,48.3804],[-97.1355,48.3805],[-97.1344,48.3808],[-97.1339,48.3811],[-97.1334,48.3818],[-97.1333,48.3822],[-97.1338,48.3828],[-97.1344,48.3833],[-97.1354,48.3838],[-97.1362,48.384],[-97.1374,48.3839],[-97.1389,48.3837],[-97.1406,48.3833],[-97.1431,48.3824],[-97.1446,48.3819],[-97.1454,48.3815],[-97.1463,48.3815],[-97.147,48.3814],[-97.1479,48.3817],[-97.149,48.3819],[-97.1505,48.3824],[-97.1509,48.3825],[-97.1519,48.3829],[-97.1532,48.3834],[-97.1538,48.3839],[-97.1548,48.3844],[-97.155,48.3846],[-97.156,48.3851],[-97.1572,48.3858],[-97.1576,48.3865],[-97.1577,48.3874],[-97.1571,48.3884],[-97.1565,48.3896],[-97.1563,48.3904],[-97.1567,48.3909],[-97.1576,48.3912],[-97.1586,48.3913],[-97.1596,48.3912],[-97.1608,48.3913],[-97.1617,48.3915],[-97.1627,48.3918],[-97.1632,48.392],[-97.1633,48.3929],[-97.1631,48.3937],[-97.1621,48.3948],[-97.1607,48.3956],[-97.1593,48.3961],[-97.1586,48.3964],[-97.1574,48.3965],[-97.1551,48.3968],[-97.1534,48.397],[-97.1519,48.3969],[-97.1505,48.3968],[-97.1499,48.3968],[-97.1481,48.3968],[-97.1467,48.3971],[-97.1456,48.3975],[-97.1445,48.3981],[-97.1434,48.3989],[-97.1434,48.399],[-97.1427,48.3996],[-97.1421,48.4004],[-97.1414,48.4013],[-97.1406,48.4019],[-97.1399,48.4025],[-97.1392,48.4029],[-97.1383,48.4033],[-97.1369,48.4038],[-97.1349,48.4046],[-97.1334,48.4053],[-97.1323,48.4059],[-97.1314,48.4066],[-97.1311,48.4073],[-97.131,48.4079],[-97.1312,48.409],[-97.1316,48.4096],[-97.1322,48.4104],[-97.1334,48.4112],[-97.1348,48.412],[-97.1362,48.4126],[-97.1373,48.4134],[-97.1375,48.4137],[-97.1376,48.4137],[-97.1379,48.4141],[-97.1384,48.4146],[-97.1388,48.4163],[-97.1388,48.4172],[-97.1393,48.4181],[-97.1398,48.4185],[-97.1406,48.4187],[-97.142,48.4186],[-97.1434,48.4181],[-97.1445,48.4173],[-97.1453,48.4159],[-97.1467,48.414],[-97.1472,48.4137],[-97.1478,48.4133],[-97.1489,48.4129],[-97.1505,48.4128],[-97.1508,48.4128],[-97.1521,48.4129],[-97.1532,48.4131],[-97.1543,48.4136],[-97.1543,48.4136],[-97.155,48.4143],[-97.1554,48.415],[-97.1554,48.4161],[-97.1554,48.4168],[-97.1548,48.4175],[-97.1539,48.4182],[-97.1527,48.4188],[-97.1509,48.4195],[-97.1507,48.4196],[-97.1489,48.4201],[-97.1466,48.4206],[-97.1443,48.4211],[-97.1421,48.4215],[-97.1403,48.4216],[-97.1383,48.4217],[-97.1367,48.4216],[-97.135,48.4213],[-97.1335,48.421],[-97.1325,48.4205],[-97.1312,48.4197],[-97.1301,48.4191],[-97.129,48.4181],[-97.1285,48.4177],[-97.1274,48.4168],[-97.1264,48.4164],[-97.126,48.4162],[-97.1253,48.4162],[-97.1244,48.4164],[-97.1236,48.4167],[-97.1232,48.417],[-97.1227,48.4176],[-97.1225,48.418],[-97.1224,48.4183],[-97.1223,48.4191],[-97.1223,48.4195],[-97.1225,48.42],[-97.1227,48.4204],[-97.1228,48.4207],[-97.1231,48.421],[-97.1233,48.4213],[-97.1241,48.4219],[-97.1246,48.4223],[-97.1249,48.4224],[-97.1253,48.4226],[-97.1268,48.4234],[-97.1286,48.4242],[-97.129,48.4243],[-97.1312,48.4251],[-97.1332,48.4258],[-97.1346,48.4262],[-97.1375,48.4264],[-97.139,48.4265],[-97.1406,48.427],[-97.1412,48.4272],[-97.1425,48.4277],[-97.1438,48.4285],[-97.1446,48.4291],[-97.1451,48.4298],[-97.1457,48.4303],[-97.1458,48.4312],[-97.1455,48.4322],[-97.1451,48.4326],[-97.144,48.4332],[-97.142,48.4337],[-97.1412,48.4338],[-97.1398,48.4337],[-97.1384,48.4336],[-97.1366,48.433],[-97.1344,48.4321],[-97.1332,48.4316],[-97.1315,48.4312],[-97.1305,48.4311],[-97.129,48.4311],[-97.1278,48.4313],[-97.1267,48.4319],[-97.1259,48.4325],[-97.1253,48.4329],[-97.1246,48.4337],[-97.1245,48.4341],[-97.1238,48.4355],[-97.1236,48.4361],[-97.1234,48.4371],[-97.1233,48.4376],[-97.1233,48.4383],[-97.1235,48.4389],[-97.1238,48.4399],[-97.124,48.4407],[-97.1243,48.4413],[-97.1245,48.4416],[-97.1248,48.4419],[-97.125,48.4421],[-97.1251,48.4422],[-97.1253,48.4423],[-97.1258,48.4427],[-97.1265,48.4432],[-97.128,48.4438],[-97.129,48.444],[-97.1295,48.4441],[-97.1314,48.4441],[-97.1328,48.4439],[-97.1345,48.4434],[-97.1355,48.4427],[-97.1363,48.4421],[-97.1365,48.4419],[-97.138,48.4405],[-97.1398,48.4392],[-97.141,48.4386],[-97.1428,48.4383],[-97.1451,48.4381],[-97.1464,48.4381],[-97.1477,48.4383],[-97.149,48.4389],[-97.1498,48.4392],[-97.1503,48.4397],[-97.1505,48.4403],[-97.1506,48.4409],[-97.1505,48.4413],[-97.1502,48.4419],[-97.1501,48.4422],[-97.1492,48.4434],[-97.1481,48.4441],[-97.1462,48.4448],[-97.1426,48.4459],[-97.1401,48.4467],[-97.1377,48.4477],[-97.1353,48.4489],[-97.1306,48.4523],[-97.1293,48.4541],[-97.1292,48.4564],[-97.1292,48.4566],[-97.1292,48.4569],[-97.1291,48.4575],[-97.1288,48.4585],[-97.1286,48.4596],[-97.1285,48.4604],[-97.1288,48.4616],[-97.1292,48.4622],[-97.1293,48.4624],[-97.1298,48.463],[-97.1306,48.4635],[-97.1319,48.4638],[-97.1334,48.4639],[-97.1347,48.4638],[-97.136,48.4635],[-97.138,48.463],[-97.1395,48.463],[-97.1407,48.463],[-97.142,48.4634],[-97.143,48.4639],[-97.1444,48.4649],[-97.1455,48.466],[-97.1463,48.4669],[-97.147,48.4677],[-97.1474,48.4684],[-97.148,48.47],[-97.1482,48.4708],[-97.148,48.4713],[-97.1477,48.4721],[-97.1474,48.4728],[-97.1465,48.4737],[-97.1461,48.4741],[-97.1445,48.4746],[-97.1432,48.4748],[-97.1419,48.4748],[-97.1407,48.4747],[-97.1393,48.4743],[-97.1379,48.4737],[-97.1368,48.4732],[-97.1352,48.4724],[-97.134,48.4718],[-97.1331,48.4715],[-97.1326,48.4714],[-97.1324,48.4713],[-97.1315,48.4712],[-97.1306,48.4713],[-97.1301,48.4714],[-97.1294,48.4715],[-97.1293,48.4717],[-97.1289,48.472],[-97.1283,48.4729],[-97.1281,48.4736],[-97.1281,48.4744],[-97.1285,48.4751],[-97.1289,48.4758],[-97.1293,48.4761],[-97.1297,48.4764],[-97.1308,48.4769],[-97.1324,48.4773],[-97.1346,48.4776],[-97.1364,48.4777],[-97.1384,48.4776],[-97.1406,48.4775],[-97.1419,48.4773],[-97.1433,48.4769],[-97.1448,48.4765],[-97.1461,48.4761],[-97.1477,48.4758],[-97.1493,48.4755],[-97.1509,48.4753],[-97.1511,48.4752],[-97.153,48.475],[-97.1549,48.475],[-97.1569,48.475],[-97.1585,48.4752],[-97.1599,48.4756],[-97.1609,48.4759],[-97.1616,48.4763],[-97.1622,48.477],[-97.1626,48.4778],[-97.1624,48.4786],[-97.1623,48.4792],[-97.1616,48.4799],[-97.1602,48.4807],[-97.1592,48.4812],[-97.1574,48.4816],[-97.1562,48.4818],[-97.1546,48.4821],[-97.1529,48.4822],[-97.1509,48.4824],[-97.1507,48.4824],[-97.1482,48.4828],[-97.1455,48.483],[-97.1437,48.4835],[-97.1424,48.4838],[-97.1411,48.4843],[-97.1402,48.4848],[-97.1396,48.4854],[-97.1394,48.486],[-97.1392,48.4864],[-97.1393,48.4873],[-97.1396,48.4881],[-97.1401,48.4887],[-97.1408,48.4892],[-97.1417,48.49],[-97.1428,48.4909],[-97.1433,48.4914],[-97.1433,48.492],[-97.143,48.4924],[-97.1423,48.4926],[-97.1415,48.4926],[-97.1406,48.4924],[-97.1399,48.492],[-97.139,48.4912],[-97.1382,48.4904],[-97.138,48.4897],[-97.1373,48.4889],[-97.1367,48.4884],[-97.136,48.4881],[-97.1351,48.4878],[-97.1344,48.4878],[-97.1332,48.4881],[-97.1322,48.4885],[-97.1315,48.4891],[-97.1312,48.4897],[-97.1311,48.4903],[-97.1311,48.4907],[-97.1316,48.4916],[-97.1322,48.4924],[-97.1334,48.4935],[-97.1345,48.4943],[-97.1367,48.4954],[-97.1388,48.496],[-97.1408,48.4967],[-97.1425,48.4972],[-97.1444,48.4976],[-97.1453,48.4979],[-97.1478,48.4995],[-97.148,48.4997],[-97.1483,48.5],[-97.1487,48.5004],[-97.1491,48.5009],[-97.1497,48.502],[-97.1499,48.5034],[-97.1498,48.5047],[-97.1498,48.5061],[-97.1495,48.5075],[-97.1495,48.5086],[-97.1497,48.5096],[-97.1502,48.5106],[-97.1502,48.5117],[-97.1499,48.512],[-97.1491,48.5124],[-97.1477,48.5124],[-97.142,48.5116],[-97.139,48.5117],[-97.1366,48.5123],[-97.1338,48.5139],[-97.1328,48.5146],[-97.1326,48.5148],[-97.1289,48.5173],[-97.1281,48.5178],[-97.127,48.519],[-97.1267,48.5202],[-97.1276,48.5215],[-97.1288,48.5222],[-97.129,48.5223],[-97.1307,48.5227],[-97.1339,48.5227],[-97.1366,48.5221],[-97.1385,48.5215],[-97.1395,48.521],[-97.1411,48.5202],[-97.1426,48.5195],[-97.1442,48.5191],[-97.1454,48.5188],[-97.1473,48.5188],[-97.1488,48.5189],[-97.1503,48.5194],[-97.1506,48.5195],[-97.1524,48.5204],[-97.154,48.5217],[-97.1547,48.5242],[-97.1549,48.5266],[-97.1544,48.5285],[-97.1536,48.5295],[-97.1536,48.5295],[-97.1527,48.5303],[-97.1513,48.5309],[-97.1507,48.5311],[-97.1499,48.5313],[-97.1482,48.5315],[-97.1458,48.5316],[-97.1438,48.5316],[-97.1422,48.5323],[-97.1411,48.5333],[-97.141,48.5343],[-97.1413,48.5355],[-97.1424,48.5366],[-97.144,48.5375],[-97.1456,48.5382],[-97.1481,48.5388],[-97.1505,48.5395],[-97.1508,48.5395],[-97.1533,48.5399],[-97.1558,48.5403],[-97.1582,48.5409],[-97.1596,48.5414],[-97.161,48.542],[-97.1614,48.5424],[-97.1631,48.5439],[-97.1631,48.544],[-97.1509,48.5439],[-97.1287,48.5439],[-97.107,48.544],[-97.0852,48.5441],[-97.0635,48.5441],[-97.0416,48.5442],[-97.0194,48.5441],[-96.9985,48.5441],[-96.9768,48.544],[-96.9551,48.5437],[-96.9331,48.5435],[-96.9138,48.5433],[-96.9115,48.5432],[-96.8896,48.5433],[-96.8678,48.5433],[-96.8459,48.5434],[-96.824,48.5436],[-96.8023,48.5436],[-96.7803,48.5435],[-96.7585,48.5436],[-96.7368,48.5437],[-96.7151,48.5437],[-96.6931,48.5437],[-96.6713,48.5436],[-96.6493,48.5437],[-96.6278,48.5437],[-96.6058,48.5437],[-96.5839,48.5437],[-96.5621,48.5436],[-96.54,48.5434],[-96.518,48.5434],[-96.4973,48.5434],[-96.4754,48.5435],[-96.4535,48.5436],[-96.4318,48.5438],[-96.4101,48.544],[-96.3882,48.5442]]],"type":"Polygon"},"id":"45","properties":{"Area":4698732287.54973,"CTYONLY_":6,"Code":"MARS","LASTMOD":"1984-01-12T14:12:49Z","Name":"Marshall","Perimiter":374207.65129},"type":"Feature"},{"geometry":{"coordinates":[[[-93.0884,48.6278],[-93.067,48.627],[-93.0456,48.6262],[-93.0237,48.6253],[-93.0021,48.6245],[-92.9845,48.6239],[-92.98,48.625],[-92.9641,48.6291],[-92.9585,48.6306],[-92.9547,48.6316],[-92.9497,48.6304],[-92.9498,48.6291],[-92.9499,48.6147],[-92.95,48.6084],[-92.9369,48.6075],[-92.9295,48.607],[-92.9177,48.6006],[-92.9151,48.5992],[-92.91,48.5964],[-92.8945,48.595],[-92.8932,48.5946],[-92.8729,48.5878],[-92.8652,48.5853],[-92.8515,48.5807],[-92.8301,48.5735],[-92.8206,48.5703],[-92.8079,48.5661],[-92.7863,48.5589],[-92.7767,48.5557],[-92.7665,48.5522],[-92.7439,48.5446],[-92.7354,48.5418],[-92.7284,48.5394],[-92.7227,48.54],[-92.7007,48.5421],[-92.7003,48.5421],[-92.6789,48.5442],[-92.6578,48.5463],[-92.6576,48.5462],[-92.6369,48.5429],[-92.6357,48.5427],[-92.6348,48.5426],[-92.6302,48.5284],[-92.6282,48.5223],[-92.6255,48.5179],[-92.6269,48.5142],[-92.6268,48.514],[-92.6264,48.5135],[-92.625,48.513],[-92.628,48.5108],[-92.6287,48.5106],[-92.6308,48.5092],[-92.6312,48.5082],[-92.6319,48.5068],[-92.6296,48.5058],[-92.627,48.5033],[-92.6306,48.5008],[-92.6351,48.4998],[-92.637,48.4994],[-92.6386,48.4996],[-92.64,48.4999],[-92.647,48.4999],[-92.654,48.5017],[-92.6569,48.4996],[-92.6582,48.4987],[-92.6614,48.4964],[-92.6789,48.4971],[-92.6857,48.4974],[-92.6986,48.4949],[-92.7011,48.4847],[-92.7016,48.4841],[-92.7092,48.4729],[-92.7085,48.4704],[-92.7089,48.4696],[-92.7126,48.463],[-92.7025,48.4551],[-92.7015,48.4543],[-92.6881,48.4438],[-92.6799,48.4425],[-92.6694,48.441],[-92.6635,48.4401],[-92.6586,48.4377],[-92.6562,48.4365],[-92.6371,48.4375],[-92.6157,48.4386],[-92.5935,48.4398],[-92.5765,48.4406],[-92.5717,48.4415],[-92.5686,48.4421],[-92.5499,48.4454],[-92.5369,48.4478],[-92.5284,48.448],[-92.515,48.4484],[-92.5074,48.448],[-92.507,48.4476],[-92.501,48.4422],[-92.4942,48.436],[-92.4893,48.4303],[-92.4849,48.4294],[-92.4837,48.4292],[-92.482,48.4283],[-92.4819,48.4279],[-92.4819,48.4276],[-92.4807,48.4264],[-92.481,48.4253],[-92.4788,48.4233],[-92.4754,48.4187],[-92.4631,48.4157],[-92.4564,48.4141],[-92.4564,48.4135],[-92.4563,48.4012],[-92.4602,48.3956],[-92.47,48.3813],[-92.4765,48.372],[-92.4747,48.3667],[-92.4697,48.3522],[-92.4697,48.3521],[-92.4591,48.3374],[-92.4558,48.3329],[-92.4523,48.3281],[-92.4476,48.3229],[-92.4415,48.3161],[-92.4413,48.3159],[-92.4405,48.3154],[-92.4403,48.3149],[-92.4386,48.3112],[-92.4367,48.309],[-92.4361,48.3085],[-92.4347,48.3074],[-92.4318,48.3052],[-92.4289,48.306],[-92.4256,48.3047],[-92.4204,48.299],[-92.4156,48.2951],[-92.415,48.2941],[-92.4135,48.2915],[-92.4065,48.2795],[-92.4017,48.2714],[-92.3967,48.2648],[-92.3931,48.2601],[-92.3927,48.259],[-92.3934,48.2576],[-92.3921,48.2568],[-92.3913,48.256],[-92.3891,48.2537],[-92.3901,48.2528],[-92.3912,48.2529],[-92.3922,48.2531],[-92.3926,48.2519],[-92.3923,48.2512],[-92.3912,48.2509],[-92.3907,48.2507],[-92.3897,48.2508],[-92.3887,48.2512],[-92.3867,48.2518],[-92.3858,48.2514],[-92.3853,48.2504],[-92.3852,48.2502],[-92.3846,48.2492],[-92.3868,48.2492],[-92.3863,48.2475],[-92.3878,48.247],[-92.3881,48.2465],[-92.3872,48.2444],[-92.3866,48.2441],[-92.3846,48.2449],[-92.3838,48.2446],[-92.3844,48.2425],[-92.3844,48.2414],[-92.384,48.2404],[-92.3833,48.2393],[-92.3816,48.2377],[-92.3806,48.2365],[-92.3789,48.2359],[-92.3789,48.2359],[-92.3785,48.2353],[-92.3791,48.2343],[-92.3781,48.233],[-92.3784,48.2321],[-92.3785,48.2312],[-92.3783,48.2304],[-92.3774,48.2293],[-92.3758,48.2283],[-92.3754,48.2275],[-92.3756,48.2267],[-92.3751,48.226],[-92.3743,48.2256],[-92.3734,48.225],[-92.3726,48.2236],[-92.3714,48.2241],[-92.3708,48.2239],[-92.3707,48.2228],[-92.3699,48.2218],[-92.3699,48.2212],[-92.3699,48.2203],[-92.3695,48.2203],[-92.3691,48.2202],[-92.368,48.2212],[-92.368,48.2212],[-92.3672,48.2217],[-92.3668,48.2223],[-92.3676,48.2232],[-92.3687,48.2237],[-92.368,48.2241],[-92.3662,48.224],[-92.365,48.2236],[-92.3636,48.2229],[-92.3621,48.2227],[-92.3616,48.2232],[-92.3613,48.224],[-92.361,48.2248],[-92.3603,48.2256],[-92.3586,48.2265],[-92.3566,48.2275],[-92.3555,48.2281],[-92.3544,48.2286],[-92.3537,48.2296],[-92.3535,48.2301],[-92.3517,48.2306],[-92.3494,48.2313],[-92.3484,48.2314],[-92.3477,48.2315],[-92.347,48.2315],[-92.3439,48.2321],[-92.3419,48.2317],[-92.3414,48.2319],[-92.3408,48.2337],[-92.3404,48.2341],[-92.3392,48.2347],[-92.339,48.2349],[-92.3386,48.2351],[-92.338,48.2351],[-92.3377,48.235],[-92.3371,48.2351],[-92.3365,48.2357],[-92.3362,48.2357],[-92.3346,48.2348],[-92.3344,48.2346],[-92.3344,48.2344],[-92.3343,48.2342],[-92.3338,48.2339],[-92.3333,48.2338],[-92.332,48.234],[-92.3308,48.2348],[-92.3302,48.2349],[-92.3292,48.2351],[-92.3281,48.2359],[-92.3274,48.2366],[-92.327,48.2369],[-92.3268,48.2368],[-92.3262,48.2366],[-92.3261,48.2366],[-92.3259,48.2367],[-92.3256,48.2369],[-92.3253,48.2371],[-92.3223,48.2373],[-92.3221,48.2373],[-92.3148,48.2406],[-92.3006,48.2422],[-92.2803,48.2444],[-92.2783,48.2451],[-92.2695,48.2482],[-92.2713,48.2519],[-92.2736,48.2566],[-92.2794,48.2596],[-92.2901,48.2651],[-92.291,48.2664],[-92.2945,48.2713],[-92.2931,48.276],[-92.2937,48.2767],[-92.2942,48.2766],[-92.2945,48.2764],[-92.2951,48.2763],[-92.2952,48.2763],[-92.2953,48.2765],[-92.2953,48.2767],[-92.2954,48.2769],[-92.2953,48.2771],[-92.2952,48.2772],[-92.2953,48.2773],[-92.2956,48.2773],[-92.2955,48.2776],[-92.2955,48.2777],[-92.2956,48.278],[-92.2972,48.2809],[-92.3014,48.2883],[-92.2987,48.2954],[-92.2945,48.3063],[-92.2987,48.3099],[-92.3018,48.3125],[-92.3061,48.3163],[-92.3044,48.3229],[-92.302,48.3232],[-92.2954,48.3239],[-92.2952,48.3246],[-92.2901,48.3392],[-92.2888,48.3429],[-92.2803,48.3468],[-92.2625,48.355],[-92.2588,48.3544],[-92.2364,48.3511],[-92.2216,48.3489],[-92.2197,48.3481],[-92.2191,48.3475],[-92.2189,48.3469],[-92.2181,48.3463],[-92.2169,48.345],[-92.2147,48.3452],[-92.2067,48.3457],[-92.2065,48.3473],[-92.2077,48.3479],[-92.2038,48.3519],[-92.195,48.3505],[-92.1945,48.3488],[-92.193,48.3488],[-92.1928,48.3488],[-92.1785,48.3519],[-92.179,48.3549],[-92.1791,48.3549],[-92.1774,48.3572],[-92.1709,48.3598],[-92.162,48.3634],[-92.1488,48.3652],[-92.1448,48.3657],[-92.1437,48.3561],[-92.1274,48.3556],[-92.106,48.355],[-92.0942,48.3546],[-92.0908,48.3545],[-92.0842,48.3538],[-92.0835,48.3538],[-92.0823,48.3547],[-92.0781,48.3581],[-92.067,48.3595],[-92.0625,48.3595],[-92.0552,48.3594],[-92.0525,48.3549],[-92.0488,48.3486],[-92.0458,48.3479],[-92.0451,48.3458],[-92.0478,48.3436],[-92.0475,48.3404],[-92.0469,48.3348],[-92.0404,48.3336],[-92.0376,48.3331],[-92.031,48.3261],[-92.0307,48.3257],[-92.0185,48.324],[-92.0119,48.323],[-92.0001,48.3211],[-92.0051,48.3118],[-92.0129,48.2975],[-92.0129,48.297],[-92.012,48.287],[-92.0087,48.2826],[-92.0072,48.2806],[-92.0066,48.2677],[-92.0065,48.2655],[-91.9949,48.262],[-91.9891,48.2603],[-91.9841,48.2531],[-91.9805,48.248],[-91.979,48.2475],[-91.9783,48.2474],[-91.9778,48.2474],[-91.9773,48.2472],[-91.9769,48.2468],[-91.977,48.2465],[-91.9772,48.2463],[-91.9773,48.2462],[-91.9775,48.246],[-91.9774,48.2457],[-91.9774,48.2456],[-91.9772,48.2455],[-91.9765,48.245],[-91.9756,48.2444],[-91.9744,48.2453],[-91.9743,48.2454],[-91.9742,48.2455],[-91.9738,48.2459],[-91.9736,48.2464],[-91.9735,48.2467],[-91.9726,48.247],[-91.9704,48.2479],[-91.97,48.2488],[-91.9706,48.249],[-91.9708,48.2494],[-91.9714,48.2499],[-91.9719,48.25],[-91.9724,48.2503],[-91.9724,48.2506],[-91.9723,48.251],[-91.9722,48.2513],[-91.9722,48.2518],[-91.9718,48.252],[-91.9718,48.2529],[-91.9714,48.2531],[-91.9709,48.253],[-91.9705,48.2531],[-91.9704,48.2534],[-91.9699,48.2538],[-91.959,48.2537],[-91.957,48.2524],[-91.9541,48.2523],[-91.954,48.2518],[-91.9541,48.2517],[-91.9541,48.2515],[-91.954,48.2495],[-91.9512,48.2479],[-91.948,48.246],[-91.9496,48.2446],[-91.9511,48.2444],[-91.9582,48.2439],[-91.957,48.2389],[-91.9573,48.2387],[-91.9597,48.2369],[-91.9583,48.2332],[-91.9524,48.2331],[-91.9512,48.2334],[-91.9507,48.2332],[-91.9451,48.2304],[-91.942,48.2304],[-91.9375,48.2343],[-91.9288,48.2359],[-91.9282,48.236],[-91.9211,48.2368],[-91.9167,48.2386],[-91.9148,48.239],[-91.9134,48.2389],[-91.9131,48.2385],[-91.9106,48.2382],[-91.9097,48.2384],[-91.9076,48.2384],[-91.9073,48.2383],[-91.907,48.2382],[-91.9065,48.2378],[-91.9058,48.2373],[-91.9023,48.2372],[-91.8931,48.238],[-91.885,48.2283],[-91.8843,48.2275],[-91.8769,48.2239],[-91.8675,48.2192],[-91.865,48.2095],[-91.8643,48.207],[-91.8634,48.2071],[-91.8453,48.2088],[-91.8417,48.2094],[-91.8416,48.2094],[-91.8359,48.2103],[-91.8326,48.2095],[-91.8325,48.2094],[-91.8325,48.2094],[-91.8325,48.2094],[-91.8325,48.2094],[-91.8199,48.2112],[-91.8154,48.2119],[-91.8144,48.2094],[-91.8141,48.2084],[-91.8094,48.2063],[-91.7982,48.203],[-91.7983,48.1953],[-91.7982,48.1808],[-91.7984,48.1662],[-91.7983,48.1515],[-91.7981,48.1369],[-91.798,48.1224],[-91.7987,48.1079],[-91.7992,48.0936],[-91.7997,48.0788],[-91.8001,48.0643],[-91.8,48.0496],[-91.8,48.0353],[-91.8,48.0206],[-91.8001,48.0059],[-91.7996,47.9914],[-91.7992,47.977],[-91.7985,47.9625],[-91.7979,47.9481],[-91.7977,47.9334],[-91.7978,47.9189],[-91.7979,47.9045],[-91.7979,47.8899],[-91.7983,47.8771],[-91.7983,47.876],[-91.7988,47.8618],[-91.7992,47.8464],[-91.8,47.8319],[-91.8,47.8175],[-91.7999,47.8031],[-91.7997,47.7916],[-91.7997,47.7893],[-91.7997,47.7886],[-91.7995,47.7774],[-91.7995,47.776],[-91.7995,47.7742],[-91.7995,47.7723],[-91.7992,47.7626],[-91.7992,47.7598],[-91.7992,47.7538],[-91.7993,47.7482],[-91.7993,47.7454],[-91.7992,47.7388],[-91.7992,47.7339],[-91.799,47.731],[-91.7984,47.7201],[-91.7982,47.717],[-91.7981,47.7165],[-91.7977,47.7128],[-91.7971,47.707],[-91.7967,47.7024],[-91.7959,47.6925],[-91.7959,47.688],[-91.7955,47.678],[-91.7955,47.6778],[-91.7955,47.6733],[-91.7954,47.6729],[-91.795,47.663],[-91.7948,47.6586],[-91.7942,47.6486],[-91.794,47.6449],[-91.794,47.6442],[-91.7933,47.6345],[-91.793,47.6299],[-91.7923,47.6212],[-91.7922,47.6193],[-91.7919,47.6155],[-91.7915,47.6091],[-91.7913,47.6049],[-91.7912,47.6021],[-91.7911,47.6008],[-91.7908,47.5904],[-91.7905,47.5874],[-91.7904,47.5864],[-91.7893,47.576],[-91.7892,47.5749],[-91.789,47.5719],[-91.7888,47.5614],[-91.7887,47.5588],[-91.7886,47.5574],[-91.7878,47.5469],[-91.788,47.5431],[-91.788,47.5424],[-91.7886,47.533],[-91.7886,47.5322],[-91.7889,47.5187],[-91.7889,47.5176],[-91.789,47.5067],[-91.7891,47.5041],[-91.7891,47.503],[-91.7894,47.493],[-91.7894,47.4897],[-91.7894,47.4886],[-91.7895,47.4753],[-91.7895,47.4741],[-91.7895,47.4605],[-91.7895,47.4574],[-91.7893,47.4449],[-91.7894,47.4303],[-91.7895,47.416],[-91.7896,47.4017],[-91.7904,47.3872],[-91.7906,47.3726],[-91.792,47.3726],[-91.792,47.3576],[-91.792,47.3432],[-91.7918,47.3288],[-91.7918,47.3145],[-91.7919,47.3],[-91.792,47.2855],[-91.7921,47.271],[-91.7922,47.2565],[-91.7923,47.2422],[-91.7923,47.2276],[-91.7923,47.2128],[-91.7922,47.1985],[-91.7923,47.1843],[-91.7923,47.1698],[-91.7923,47.1556],[-91.7923,47.1411],[-91.7924,47.1265],[-91.7922,47.1119],[-91.7943,47.1119],[-91.7945,47.0976],[-91.7945,47.0831],[-91.7944,47.0688],[-91.7944,47.0541],[-91.7943,47.0399],[-91.7943,47.0255],[-91.7944,47.0109],[-91.7944,46.9965],[-91.7944,46.9818],[-91.7944,46.9675],[-91.7943,46.953],[-91.7944,46.9397],[-91.7945,46.9397],[-91.7947,46.9396],[-91.7948,46.9395],[-91.795,46.9394],[-91.7951,46.9394],[-91.7952,46.9394],[-91.7953,46.9393],[-91.7954,46.9391],[-91.7955,46.939],[-91.7957,46.9388],[-91.7957,46.9386],[-91.7958,46.9384],[-91.7958,46.9384],[-91.7959,46.9383],[-91.796,46.9382],[-91.7961,46.9381],[-91.7964,46.938],[-91.7966,46.9379],[-91.797,46.9379],[-91.7971,46.9378],[-91.7974,46.9378],[-91.7975,46.9378],[-91.7978,46.9378],[-91.798,46.9379],[-91.7981,46.938],[-91.7983,46.938],[-91.7986,46.9379],[-91.7989,46.9379],[-91.7991,46.9379],[-91.7993,46.9379],[-91.7995,46.9378],[-91.7996,46.9377],[-91.7998,46.9376],[-91.8004,46.9373],[-91.8007,46.9371],[-91.8011,46.9369],[-91.8013,46.9368],[-91.8016,46.9367],[-91.802,46.9366],[-91.8022,46.9365],[-91.8025,46.9364],[-91.8028,46.9363],[-91.8032,46.9361],[-91.8034,46.936],[-91.8036,46.9359],[-91.8037,46.9357],[-91.804,46.9356],[-91.8042,46.9354],[-91.8044,46.9352],[-91.8046,46.935],[-91.8048,46.9349],[-91.805,46.9347],[-91.8051,46.9346],[-91.8053,46.9345],[-91.8055,46.9345],[-91.8057,46.9344],[-91.8059,46.9343],[-91.806,46.9343],[-91.8062,46.9342],[-91.8064,46.9341],[-91.8066,46.9338],[-91.8067,46.9336],[-91.8069,46.9334],[-91.807,46.9332],[-91.8071,46.9331],[-91.8071,46.933],[-91.8072,46.9329],[-91.8073,46.9328],[-91.8075,46.9328],[-91.8076,46.9327],[-91.8078,46.9327],[-91.808,46.9327],[-91.8082,46.9325],[-91.8084,46.9324],[-91.8087,46.9322],[-91.8089,46.932],[-91.8091,46.9319],[-91.8094,46.9317],[-91.8097,46.9315],[-91.81,46.9314],[-91.8103,46.9312],[-91.8106,46.9311],[-91.8107,46.931],[-91.8109,46.9309],[-91.811,46.9309],[-91.8112,46.9309],[-91.8113,46.9308],[-91.8116,46.9306],[-91.8117,46.9305],[-91.8119,46.9303],[-91.812,46.9301],[-91.8121,46.9299],[-91.8122,46.9298],[-91.8123,46.9296],[-91.8123,46.9293],[-91.8124,46.9291],[-91.8124,46.929],[-91.8125,46.9288],[-91.8126,46.9287],[-91.813,46.9281],[-91.8133,46.9277],[-91.8135,46.9275],[-91.8137,46.9272],[-91.8138,46.9271],[-91.8139,46.927],[-91.8141,46.9268],[-91.8142,46.9267],[-91.8144,46.9267],[-91.8147,46.9266],[-91.8149,46.9265],[-91.815,46.9263],[-91.8151,46.9263],[-91.8152,46.9262],[-91.8153,46.926],[-91.8154,46.9259],[-91.8154,46.9258],[-91.8155,46.9258],[-91.8157,46.9256],[-91.8159,46.9252],[-91.8162,46.925],[-91.8163,46.9248],[-91.8165,46.9247],[-91.8166,46.9246],[-91.8168,46.9244],[-91.817,46.9243],[-91.8171,46.9243],[-91.8173,46.9242],[-91.8175,46.9241],[-91.8177,46.924],[-91.8179,46.924],[-91.8182,46.9241],[-91.8184,46.9242],[-91.8186,46.9244],[-91.8187,46.9245],[-91.8189,46.9246],[-91.819,46.9246],[-91.8192,46.9247],[-91.8194,46.9248],[-91.8196,46.9248],[-91.8198,46.9248],[-91.8202,46.9248],[-91.8204,46.9248],[-91.8206,46.9248],[-91.8208,46.9249],[-91.821,46.925],[-91.822,46.9252],[-91.8222,46.9253],[-91.8224,46.9253],[-91.8227,46.9254],[-91.8232,46.9256],[-91.8234,46.9257],[-91.8237,46.9259],[-91.8238,46.926],[-91.824,46.9261],[-91.8241,46.9262],[-91.8242,46.9262],[-91.8243,46.9263],[-91.8243,46.9264],[-91.8245,46.9265],[-91.8252,46.9267],[-91.8255,46.9269],[-91.8256,46.9269],[-91.8258,46.927],[-91.8259,46.9272],[-91.826,46.9272],[-91.826,46.9273],[-91.8265,46.9274],[-91.8267,46.9274],[-91.827,46.9275],[-91.8274,46.9275],[-91.8277,46.9275],[-91.828,46.9275],[-91.8283,46.9275],[-91.8286,46.9275],[-91.8289,46.9275],[-91.8292,46.9275],[-91.8295,46.9275],[-91.83,46.9275],[-91.8303,46.9275],[-91.8307,46.9275],[-91.831,46.9275],[-91.8314,46.9274],[-91.8318,46.9274],[-91.8321,46.9274],[-91.8325,46.9274],[-91.8327,46.9273],[-91.833,46.9273],[-91.8332,46.9273],[-91.8335,46.9272],[-91.8337,46.9272],[-91.8342,46.9269],[-91.8345,46.9268],[-91.8347,46.9267],[-91.8348,46.9267],[-91.8348,46.9266],[-91.8349,46.9266],[-91.835,46.9266],[-91.835,46.9267],[-91.8348,46.9268],[-91.8348,46.9269],[-91.8347,46.927],[-91.8347,46.9271],[-91.8346,46.9272],[-91.8348,46.9272],[-91.8351,46.9271],[-91.8352,46.927],[-91.8355,46.9269],[-91.8357,46.9269],[-91.8359,46.9268],[-91.8361,46.9268],[-91.8363,46.9268],[-91.8365,46.9267],[-91.8365,46.9267],[-91.8367,46.9266],[-91.8368,46.9266],[-91.8369,46.9265],[-91.8371,46.9265],[-91.8374,46.9265],[-91.8376,46.9265],[-91.8377,46.9265],[-91.8379,46.9264],[-91.8381,46.9263],[-91.8383,46.9262],[-91.8386,46.9261],[-91.8389,46.9261],[-91.8391,46.926],[-91.8393,46.9259],[-91.8396,46.9258],[-91.8398,46.9257],[-91.8401,46.9256],[-91.8405,46.9255],[-91.8407,46.9254],[-91.841,46.9253],[-91.8413,46.9253],[-91.8415,46.9252],[-91.8417,46.9251],[-91.8418,46.9251],[-91.8424,46.9248],[-91.8426,46.9246],[-91.8431,46.9244],[-91.8432,46.9243],[-91.8435,46.9242],[-91.8441,46.9239],[-91.8446,46.9238],[-91.8449,46.9236],[-91.8454,46.9234],[-91.8457,46.9233],[-91.8458,46.9232],[-91.8461,46.923],[-91.8464,46.9229],[-91.8466,46.9226],[-91.847,46.9224],[-91.8472,46.9223],[-91.8474,46.9221],[-91.8475,46.922],[-91.8476,46.9219],[-91.8477,46.9219],[-91.8478,46.9218],[-91.8481,46.9216],[-91.8484,46.9215],[-91.8486,46.9213],[-91.8488,46.9211],[-91.8491,46.9209],[-91.8493,46.9208],[-91.8495,46.9207],[-91.8497,46.9204],[-91.8499,46.9203],[-91.8501,46.9201],[-91.8502,46.9199],[-91.8504,46.9198],[-91.8505,46.9197],[-91.8506,46.9197],[-91.8511,46.9193],[-91.8512,46.9192],[-91.8513,46.919],[-91.8514,46.9188],[-91.8517,46.9185],[-91.8519,46.9182],[-91.8521,46.9179],[-91.8524,46.9175],[-91.8526,46.9171],[-91.8528,46.9168],[-91.8531,46.9165],[-91.8533,46.9162],[-91.8535,46.9158],[-91.8536,46.9156],[-91.8538,46.9155],[-91.854,46.9153],[-91.8542,46.9151],[-91.8544,46.915],[-91.8546,46.9148],[-91.8548,46.9146],[-91.855,46.9144],[-91.8551,46.9143],[-91.8552,46.9142],[-91.8553,46.9141],[-91.8555,46.9139],[-91.8557,46.9137],[-91.8559,46.9136],[-91.8562,46.9136],[-91.8565,46.9134],[-91.8568,46.9132],[-91.8569,46.9131],[-91.857,46.9131],[-91.8571,46.913],[-91.8572,46.9129],[-91.8576,46.9127],[-91.8579,46.9126],[-91.8581,46.9126],[-91.8583,46.9126],[-91.8584,46.9126],[-91.8585,46.9124],[-91.8588,46.9122],[-91.8591,46.912],[-91.8596,46.9116],[-91.8599,46.9115],[-91.8602,46.9114],[-91.8603,46.9113],[-91.8605,46.9112],[-91.8607,46.911],[-91.8609,46.9109],[-91.861,46.9108],[-91.8612,46.9107],[-91.8613,46.9106],[-91.8614,46.9105],[-91.8615,46.9104],[-91.8617,46.9103],[-91.8619,46.9102],[-91.8625,46.9101],[-91.863,46.91],[-91.8633,46.91],[-91.8635,46.9099],[-91.8637,46.9099],[-91.8639,46.9097],[-91.8642,46.9096],[-91.8644,46.9095],[-91.8644,46.9095],[-91.8646,46.9094],[-91.8648,46.9093],[-91.865,46.9092],[-91.8652,46.909],[-91.8654,46.9089],[-91.8656,46.9089],[-91.8659,46.9088],[-91.8662,46.9087],[-91.8664,46.9087],[-91.8666,46.9086],[-91.8668,46.9086],[-91.8675,46.9084],[-91.8679,46.9084],[-91.8681,46.9085],[-91.8684,46.9085],[-91.8686,46.9085],[-91.8688,46.9085],[-91.8691,46.9085],[-91.8693,46.9085],[-91.8705,46.9084],[-91.8709,46.9084],[-91.8711,46.9084],[-91.8714,46.9083],[-91.8717,46.9083],[-91.8724,46.9082],[-91.8734,46.9081],[-91.874,46.9081],[-91.8745,46.908],[-91.8749,46.908],[-91.8751,46.908],[-91.8755,46.9078],[-91.8758,46.9075],[-91.8761,46.9074],[-91.8764,46.9073],[-91.8766,46.9073],[-91.8768,46.9072],[-91.8772,46.9072],[-91.8775,46.9072],[-91.878,46.9071],[-91.8782,46.9071],[-91.879,46.9067],[-91.8797,46.9064],[-91.8802,46.9062],[-91.8807,46.906],[-91.8811,46.9058],[-91.8829,46.9047],[-91.885,46.9037],[-91.8854,46.9035],[-91.8856,46.9033],[-91.8858,46.9032],[-91.8859,46.903],[-91.8861,46.9029],[-91.8861,46.9028],[-91.8864,46.9027],[-91.8866,46.9026],[-91.8868,46.9025],[-91.8873,46.9021],[-91.8875,46.9019],[-91.8882,46.9015],[-91.8885,46.9015],[-91.8887,46.9015],[-91.8889,46.9015],[-91.8892,46.9014],[-91.8905,46.9005],[-91.891,46.9001],[-91.8912,46.8998],[-91.8915,46.8996],[-91.8918,46.8994],[-91.892,46.8994],[-91.8933,46.8987],[-91.8947,46.8979],[-91.895,46.8977],[-91.8953,46.8975],[-91.8955,46.8973],[-91.8956,46.8971],[-91.8957,46.8969],[-91.8961,46.8966],[-91.8971,46.8959],[-91.8976,46.8955],[-91.8981,46.8952],[-91.8986,46.895],[-91.8987,46.895],[-91.899,46.8949],[-91.8992,46.8948],[-91.8994,46.8947],[-91.9004,46.894],[-91.9009,46.8937],[-91.901,46.8935],[-91.9013,46.8933],[-91.9026,46.8928],[-91.9029,46.8926],[-91.9031,46.8925],[-91.9034,46.8923],[-91.9037,46.892],[-91.9038,46.892],[-91.904,46.892],[-91.9043,46.8917],[-91.9045,46.8915],[-91.9049,46.8912],[-91.9053,46.8909],[-91.9057,46.8906],[-91.9066,46.89],[-91.9069,46.8896],[-91.907,46.8894],[-91.9081,46.8887],[-91.9086,46.8881],[-91.9088,46.8879],[-91.909,46.8876],[-91.9093,46.8873],[-91.9098,46.8867],[-91.9102,46.8864],[-91.9106,46.8862],[-91.9108,46.8862],[-91.9109,46.886],[-91.911,46.8859],[-91.911,46.8858],[-91.9111,46.8857],[-91.9112,46.8856],[-91.9113,46.8855],[-91.9115,46.8852],[-91.9116,46.885],[-91.9118,46.8848],[-91.9122,46.8845],[-91.913,46.8839],[-91.9134,46.8837],[-91.9137,46.8836],[-91.9139,46.8836],[-91.9142,46.8836],[-91.9141,46.8835],[-91.9142,46.8834],[-91.9143,46.8833],[-91.9145,46.8832],[-91.9147,46.8831],[-91.915,46.883],[-91.9153,46.8829],[-91.9156,46.8827],[-91.9159,46.8826],[-91.9161,46.8824],[-91.9169,46.882],[-91.9173,46.8818],[-91.9178,46.8816],[-91.9191,46.8812],[-91.9194,46.8811],[-91.9197,46.881],[-91.9199,46.8808],[-91.9201,46.8807],[-91.9204,46.8805],[-91.9205,46.8805],[-91.9209,46.8804],[-91.9214,46.8803],[-91.9226,46.8799],[-91.923,46.8797],[-91.9235,46.8796],[-91.9244,46.8792],[-91.9256,46.8788],[-91.926,46.8786],[-91.9263,46.8786],[-91.9268,46.8784],[-91.9276,46.8781],[-91.928,46.878],[-91.9284,46.8777],[-91.9297,46.8771],[-91.9301,46.8769],[-91.9305,46.8767],[-91.9309,46.8764],[-91.9312,46.8762],[-91.9315,46.8761],[-91.9316,46.876],[-91.9317,46.8759],[-91.9318,46.8758],[-91.9319,46.8758],[-91.932,46.8757],[-91.9321,46.8755],[-91.9322,46.8755],[-91.9324,46.8754],[-91.9326,46.8753],[-91.9329,46.8752],[-91.9332,46.8752],[-91.9335,46.8751],[-91.9337,46.8751],[-91.9339,46.875],[-91.934,46.8749],[-91.9341,46.8748],[-91.9343,46.8746],[-91.9345,46.8744],[-91.9346,46.8743],[-91.9349,46.874],[-91.9353,46.8738],[-91.9358,46.8737],[-91.9362,46.8736],[-91.9368,46.8735],[-91.9374,46.8734],[-91.938,46.8734],[-91.9386,46.8732],[-91.9391,46.873],[-91.9397,46.8727],[-91.9403,46.8723],[-91.9408,46.8721],[-91.941,46.8719],[-91.9411,46.8717],[-91.9413,46.8717],[-91.9415,46.8718],[-91.9416,46.8717],[-91.9417,46.8717],[-91.9419,46.8715],[-91.942,46.8712],[-91.9422,46.871],[-91.9424,46.8709],[-91.9428,46.8708],[-91.943,46.8708],[-91.9432,46.8706],[-91.9435,46.8704],[-91.9438,46.8704],[-91.9444,46.8702],[-91.9449,46.8699],[-91.9456,46.8696],[-91.9465,46.8694],[-91.9475,46.8691],[-91.9484,46.8688],[-91.9492,46.8685],[-91.9496,46.8682],[-91.9499,46.8679],[-91.9502,46.8678],[-91.9507,46.8677],[-91.9513,46.8675],[-91.952,46.8671],[-91.9524,46.8668],[-91.9527,46.8665],[-91.953,46.8662],[-91.9535,46.8659],[-91.9536,46.8658],[-91.9545,46.8654],[-91.9552,46.8651],[-91.956,46.8645],[-91.9565,46.8641],[-91.9568,46.8638],[-91.957,46.8636],[-91.9574,46.8633],[-91.9577,46.8631],[-91.9581,46.8628],[-91.9587,46.8623],[-91.959,46.8619],[-91.9593,46.8617],[-91.9596,46.8616],[-91.96,46.8614],[-91.9604,46.8612],[-91.9608,46.8609],[-91.9611,46.8605],[-91.9615,46.8602],[-91.9621,46.86],[-91.9627,46.8597],[-91.963,46.8596],[-91.9633,46.8595],[-91.964,46.8592],[-91.9646,46.8589],[-91.965,46.8586],[-91.9654,46.8582],[-91.9657,46.858],[-91.966,46.8579],[-91.9663,46.8578],[-91.9667,46.8576],[-91.9669,46.8576],[-91.967,46.8575],[-91.9671,46.8574],[-91.9672,46.8573],[-91.9673,46.8571],[-91.9675,46.857],[-91.9677,46.857],[-91.9679,46.8571],[-91.9681,46.857],[-91.9683,46.8569],[-91.9686,46.8568],[-91.9688,46.8567],[-91.9692,46.8565],[-91.9695,46.8564],[-91.97,46.8563],[-91.9704,46.8563],[-91.9708,46.8562],[-91.9711,46.8561],[-91.9714,46.8562],[-91.9716,46.8561],[-91.972,46.8559],[-91.9724,46.8558],[-91.9728,46.8558],[-91.9731,46.8559],[-91.9732,46.8558],[-91.9734,46.8557],[-91.9736,46.8556],[-91.974,46.8555],[-91.9741,46.8554],[-91.9742,46.8553],[-91.9745,46.8552],[-91.9748,46.8551],[-91.9751,46.8549],[-91.9754,46.8547],[-91.9755,46.8548],[-91.9757,46.8548],[-91.9762,46.8546],[-91.9764,46.8545],[-91.9767,46.8542],[-91.977,46.8539],[-91.9772,46.8537],[-91.9773,46.8534],[-91.9775,46.8533],[-91.9777,46.8533],[-91.978,46.8532],[-91.9784,46.853],[-91.9787,46.8529],[-91.9791,46.8526],[-91.9792,46.8525],[-91.9795,46.8524],[-91.9797,46.8523],[-91.98,46.8521],[-91.9802,46.8519],[-91.9805,46.8517],[-91.9808,46.8516],[-91.9811,46.8515],[-91.9815,46.8515],[-91.9819,46.8513],[-91.982,46.8513],[-91.9827,46.851],[-91.983,46.8508],[-91.9833,46.8506],[-91.9836,46.8504],[-91.9838,46.8503],[-91.9841,46.8503],[-91.9842,46.8502],[-91.9845,46.8501],[-91.9849,46.8499],[-91.9854,46.8496],[-91.9856,46.8495],[-91.9857,46.8493],[-91.9858,46.8491],[-91.986,46.8489],[-91.9861,46.8487],[-91.9863,46.8484],[-91.9866,46.8482],[-91.9869,46.848],[-91.987,46.8478],[-91.9871,46.8476],[-91.9875,46.8476],[-91.9877,46.8474],[-91.9881,46.8471],[-91.9884,46.8469],[-91.9885,46.8467],[-91.9885,46.8465],[-91.9887,46.8462],[-91.9889,46.846],[-91.9892,46.8458],[-91.9895,46.8456],[-91.9898,46.8455],[-91.9901,46.8454],[-91.9903,46.8451],[-91.9906,46.845],[-91.9908,46.8448],[-91.991,46.8446],[-91.9913,46.8443],[-91.9915,46.844],[-91.9918,46.8437],[-91.992,46.8434],[-91.9923,46.8431],[-91.9926,46.8427],[-91.9928,46.8424],[-91.9931,46.8422],[-91.9934,46.8421],[-91.9938,46.842],[-91.9941,46.8419],[-91.9944,46.8417],[-91.9949,46.8414],[-91.9954,46.8411],[-91.9959,46.8409],[-91.9964,46.8407],[-91.9969,46.8405],[-91.9973,46.8403],[-91.9978,46.84],[-91.9981,46.8397],[-91.9983,46.8395],[-91.9983,46.8392],[-91.9985,46.839],[-91.9986,46.8389],[-91.999,46.8387],[-91.9992,46.8386],[-91.9997,46.8384],[-92.0001,46.8381],[-92.0002,46.8381],[-92.0003,46.8382],[-92.0005,46.8381],[-92.0007,46.838],[-92.0009,46.838],[-92.0012,46.8379],[-92.0014,46.8377],[-92.0016,46.8375],[-92.0019,46.8374],[-92.0022,46.8373],[-92.0025,46.8373],[-92.003,46.8372],[-92.0033,46.8372],[-92.0036,46.8372],[-92.0039,46.8372],[-92.0041,46.8371],[-92.0042,46.837],[-92.0044,46.8369],[-92.0045,46.8369],[-92.0048,46.8367],[-92.0051,46.8366],[-92.0055,46.8366],[-92.0055,46.8366],[-92.0058,46.8364],[-92.0059,46.8363],[-92.0059,46.8362],[-92.0059,46.8361],[-92.006,46.8361],[-92.0061,46.836],[-92.0062,46.8359],[-92.0064,46.8359],[-92.0068,46.8358],[-92.007,46.8358],[-92.0072,46.8358],[-92.0074,46.8358],[-92.0078,46.8357],[-92.008,46.8357],[-92.0083,46.8357],[-92.0086,46.8356],[-92.0088,46.8356],[-92.009,46.8356],[-92.0093,46.8356],[-92.0096,46.8356],[-92.0101,46.8355],[-92.0105,46.8354],[-92.0106,46.8354],[-92.0109,46.8353],[-92.0112,46.8352],[-92.0115,46.8351],[-92.0117,46.8351],[-92.0118,46.835],[-92.012,46.835],[-92.0125,46.8348],[-92.0126,46.8348],[-92.0128,46.8346],[-92.013,46.8345],[-92.0132,46.8344],[-92.0134,46.8343],[-92.0136,46.8342],[-92.0137,46.8342],[-92.0139,46.834],[-92.0141,46.8338],[-92.0143,46.8338],[-92.0143,46.8337],[-92.0145,46.8336],[-92.0147,46.8336],[-92.0149,46.8336],[-92.0152,46.8336],[-92.0156,46.8336],[-92.016,46.8335],[-92.0165,46.8334],[-92.0169,46.8334],[-92.0172,46.8333],[-92.0177,46.8331],[-92.018,46.833],[-92.0184,46.8327],[-92.0185,46.8326],[-92.0187,46.8324],[-92.0189,46.8322],[-92.019,46.8321],[-92.0192,46.8319],[-92.0193,46.8318],[-92.0193,46.8317],[-92.0194,46.8317],[-92.0196,46.8316],[-92.0198,46.8316],[-92.0201,46.8315],[-92.0206,46.8314],[-92.0209,46.8313],[-92.0213,46.8312],[-92.0214,46.8311],[-92.0218,46.8309],[-92.0221,46.8307],[-92.0225,46.8305],[-92.023,46.8302],[-92.0234,46.83],[-92.0236,46.8298],[-92.0238,46.8296],[-92.024,46.8295],[-92.0241,46.8294],[-92.0243,46.8293],[-92.0245,46.8292],[-92.0247,46.8291],[-92.0249,46.8291],[-92.025,46.829],[-92.0252,46.8289],[-92.0253,46.8288],[-92.0255,46.8286],[-92.0256,46.8284],[-92.0257,46.8283],[-92.0259,46.8282],[-92.0261,46.828],[-92.0263,46.8277],[-92.0264,46.8276],[-92.0266,46.8274],[-92.0267,46.8272],[-92.0267,46.8271],[-92.0268,46.827],[-92.0268,46.827],[-92.0268,46.8269],[-92.0269,46.8268],[-92.027,46.8267],[-92.0272,46.8266],[-92.0272,46.8266],[-92.0274,46.8265],[-92.0275,46.8265],[-92.0276,46.8264],[-92.0277,46.8263],[-92.0277,46.8262],[-92.0277,46.8261],[-92.0278,46.826],[-92.0278,46.826],[-92.0278,46.8259],[-92.0279,46.8259],[-92.0281,46.8258],[-92.0282,46.8256],[-92.0283,46.8255],[-92.0284,46.8254],[-92.0285,46.8252],[-92.0285,46.825],[-92.0287,46.8249],[-92.0287,46.8248],[-92.0289,46.8246],[-92.0291,46.8245],[-92.0294,46.8244],[-92.0295,46.8242],[-92.0297,46.8242],[-92.0299,46.8241],[-92.0301,46.824],[-92.0303,46.824],[-92.0307,46.824],[-92.0309,46.8239],[-92.0311,46.8238],[-92.0313,46.8237],[-92.0315,46.8236],[-92.0316,46.8234],[-92.0317,46.8233],[-92.0318,46.8231],[-92.0318,46.8231],[-92.0319,46.823],[-92.032,46.8229],[-92.0322,46.8228],[-92.0326,46.8226],[-92.0329,46.8224],[-92.0329,46.8224],[-92.0333,46.8222],[-92.0335,46.8222],[-92.0337,46.8221],[-92.0338,46.822],[-92.0339,46.8219],[-92.0343,46.8218],[-92.0347,46.8218],[-92.0352,46.8217],[-92.0358,46.8215],[-92.0364,46.8214],[-92.0369,46.8213],[-92.0372,46.8212],[-92.0376,46.8211],[-92.038,46.8209],[-92.0382,46.8207],[-92.0384,46.8205],[-92.0385,46.8204],[-92.0386,46.8203],[-92.0387,46.8203],[-92.0388,46.8202],[-92.0389,46.8202],[-92.0392,46.8202],[-92.0397,46.8201],[-92.04,46.8201],[-92.0401,46.8202],[-92.0405,46.8202],[-92.0408,46.8203],[-92.0411,46.8203],[-92.0414,46.8203],[-92.0417,46.8203],[-92.0419,46.8202],[-92.0421,46.8201],[-92.0423,46.8201],[-92.0425,46.82],[-92.0427,46.82],[-92.0429,46.82],[-92.0431,46.8199],[-92.0434,46.8197],[-92.0437,46.8196],[-92.044,46.8195],[-92.0441,46.8194],[-92.0443,46.8193],[-92.0445,46.8193],[-92.0447,46.8192],[-92.045,46.8191],[-92.0452,46.819],[-92.0454,46.8189],[-92.0456,46.8188],[-92.0457,46.8187],[-92.0459,46.8186],[-92.046,46.8185],[-92.0461,46.8183],[-92.0462,46.8182],[-92.0462,46.8181],[-92.0463,46.818],[-92.0463,46.8179],[-92.0464,46.8178],[-92.0465,46.8177],[-92.0466,46.8175],[-92.0467,46.8174],[-92.0468,46.8173],[-92.0469,46.8173],[-92.0469,46.8173],[-92.0471,46.8172],[-92.0473,46.8171],[-92.0474,46.8171],[-92.0476,46.8169],[-92.0478,46.8169],[-92.048,46.8167],[-92.0481,46.8166],[-92.0481,46.8165],[-92.0482,46.8164],[-92.0483,46.8164],[-92.0484,46.8163],[-92.0485,46.8162],[-92.0486,46.8161],[-92.0489,46.816],[-92.049,46.8158],[-92.0492,46.8157],[-92.0494,46.8156],[-92.0495,46.8155],[-92.0497,46.8154],[-92.0498,46.8151],[-92.0499,46.815],[-92.05,46.8148],[-92.0501,46.8146],[-92.0503,46.8144],[-92.0504,46.8144],[-92.0505,46.8144],[-92.0507,46.8144],[-92.0509,46.8143],[-92.0511,46.8143],[-92.0513,46.8143],[-92.0517,46.8142],[-92.0519,46.8142],[-92.0523,46.814],[-92.0525,46.8139],[-92.0527,46.8138],[-92.0529,46.8137],[-92.0531,46.8135],[-92.0533,46.8132],[-92.0535,46.8131],[-92.0537,46.8128],[-92.0539,46.8126],[-92.054,46.8124],[-92.054,46.8123],[-92.0542,46.812],[-92.0544,46.8118],[-92.0546,46.8117],[-92.0549,46.8115],[-92.0551,46.8115],[-92.0553,46.8113],[-92.0556,46.8112],[-92.0559,46.811],[-92.0563,46.8109],[-92.0566,46.8108],[-92.0569,46.8107],[-92.0573,46.8106],[-92.0575,46.8106],[-92.0581,46.8106],[-92.0583,46.8105],[-92.0587,46.8104],[-92.0588,46.8103],[-92.059,46.8101],[-92.0593,46.8099],[-92.0594,46.8097],[-92.0595,46.8095],[-92.0597,46.8092],[-92.0598,46.809],[-92.06,46.8087],[-92.06,46.8084],[-92.0602,46.808],[-92.0602,46.8078],[-92.0603,46.8074],[-92.0605,46.8071],[-92.0606,46.8069],[-92.0608,46.8066],[-92.061,46.8065],[-92.0611,46.8063],[-92.0612,46.8061],[-92.0612,46.8059],[-92.0613,46.8057],[-92.0616,46.8054],[-92.0617,46.8052],[-92.0619,46.8049],[-92.0621,46.8047],[-92.0622,46.8045],[-92.0625,46.8044],[-92.0627,46.8042],[-92.063,46.8041],[-92.0634,46.8039],[-92.0637,46.8038],[-92.064,46.8037],[-92.0642,46.8037],[-92.0646,46.8035],[-92.0649,46.8034],[-92.0652,46.8033],[-92.0656,46.8031],[-92.0659,46.803],[-92.0662,46.8028],[-92.0665,46.8026],[-92.0668,46.8024],[-92.067,46.8024],[-92.0674,46.8023],[-92.0677,46.8022],[-92.068,46.8022],[-92.0682,46.8023],[-92.0685,46.8023],[-92.0686,46.8023],[-92.0686,46.8023],[-92.0689,46.8024],[-92.0691,46.8023],[-92.0694,46.8023],[-92.0696,46.8022],[-92.0699,46.802],[-92.0702,46.8018],[-92.0705,46.8016],[-92.0707,46.8014],[-92.0708,46.8012],[-92.071,46.801],[-92.0712,46.8008],[-92.0713,46.8007],[-92.0715,46.8006],[-92.0716,46.8006],[-92.0718,46.8006],[-92.072,46.8007],[-92.0721,46.8007],[-92.0723,46.8006],[-92.0726,46.8006],[-92.0728,46.8005],[-92.0731,46.8004],[-92.0736,46.8002],[-92.0739,46.8],[-92.0741,46.7999],[-92.0743,46.7997],[-92.0746,46.7995],[-92.0749,46.7994],[-92.0752,46.7993],[-92.0755,46.7992],[-92.0758,46.7991],[-92.0762,46.7989],[-92.0764,46.7988],[-92.0765,46.7986],[-92.0766,46.7985],[-92.0767,46.7983],[-92.0769,46.7983],[-92.0771,46.7983],[-92.0774,46.7983],[-92.0775,46.7982],[-92.0777,46.7981],[-92.0778,46.798],[-92.0779,46.7979],[-92.078,46.7978],[-92.078,46.7977],[-92.0781,46.7975],[-92.0782,46.7974],[-92.0783,46.7973],[-92.0785,46.7973],[-92.0785,46.7973],[-92.0787,46.7974],[-92.0788,46.7974],[-92.0791,46.7974],[-92.0794,46.7973],[-92.0796,46.7973],[-92.0798,46.7973],[-92.0801,46.7973],[-92.0804,46.7973],[-92.0806,46.7973],[-92.0809,46.7972],[-92.0812,46.7971],[-92.0814,46.797],[-92.0815,46.7969],[-92.0817,46.7967],[-92.0819,46.7966],[-92.082,46.7965],[-92.0821,46.7963],[-92.0821,46.7962],[-92.0822,46.796],[-92.0823,46.7959],[-92.0825,46.7959],[-92.0828,46.7958],[-92.0831,46.7958],[-92.0835,46.7957],[-92.0838,46.7957],[-92.0841,46.7957],[-92.0844,46.7957],[-92.0847,46.7957],[-92.085,46.7957],[-92.0853,46.7956],[-92.0856,46.7955],[-92.0857,46.7954],[-92.0858,46.7953],[-92.0859,46.7952],[-92.0861,46.7951],[-92.0862,46.795],[-92.0863,46.7948],[-92.0864,46.7947],[-92.0867,46.7946],[-92.0869,46.7945],[-92.0872,46.7944],[-92.0875,46.7943],[-92.0878,46.7941],[-92.0881,46.794],[-92.0884,46.7938],[-92.0886,46.7937],[-92.0889,46.7935],[-92.0891,46.7933],[-92.0892,46.7931],[-92.0892,46.7931],[-92.0893,46.7929],[-92.0895,46.7926],[-92.0897,46.7924],[-92.0899,46.7923],[-92.0901,46.7921],[-92.0902,46.792],[-92.0903,46.7919],[-92.0904,46.7917],[-92.0903,46.7916],[-92.0903,46.7915],[-92.0903,46.7913],[-92.0904,46.7912],[-92.0905,46.791],[-92.0905,46.7908],[-92.0907,46.7905],[-92.0908,46.7902],[-92.091,46.7898],[-92.0912,46.7896],[-92.0913,46.7895],[-92.0915,46.7893],[-92.0918,46.7892],[-92.092,46.7892],[-92.0923,46.7892],[-92.0928,46.7889],[-92.0929,46.7888],[-92.0932,46.7887],[-92.0934,46.7885],[-92.0936,46.7883],[-92.0938,46.7881],[-92.0939,46.788],[-92.094,46.7877],[-92.0941,46.7875],[-92.0941,46.7874],[-92.094,46.7872],[-92.094,46.7871],[-92.094,46.7869],[-92.0939,46.7867],[-92.0938,46.7864],[-92.0936,46.786],[-92.0935,46.7857],[-92.0934,46.7854],[-92.0934,46.7852],[-92.0933,46.7849],[-92.0932,46.7848],[-92.0932,46.7845],[-92.0931,46.7842],[-92.093,46.7839],[-92.0929,46.7836],[-92.0926,46.7832],[-92.0925,46.783],[-92.0924,46.7828],[-92.0923,46.7826],[-92.0921,46.7825],[-92.092,46.7823],[-92.0919,46.7821],[-92.0918,46.7819],[-92.0917,46.7817],[-92.0916,46.7814],[-92.0915,46.7813],[-92.0913,46.781],[-92.0911,46.7807],[-92.091,46.7804],[-92.0912,46.7801],[-92.0914,46.7787],[-92.0914,46.7784],[-92.0909,46.7775],[-92.0908,46.7773],[-92.09,46.7762],[-92.0897,46.7757],[-92.0894,46.7754],[-92.0892,46.7751],[-92.0889,46.7747],[-92.0888,46.7743],[-92.0879,46.7731],[-92.0879,46.773],[-92.0878,46.773],[-92.0876,46.7727],[-92.0859,46.7704],[-92.0859,46.7702],[-92.0849,46.7691],[-92.0846,46.7687],[-92.0842,46.7682],[-92.0838,46.7676],[-92.0829,46.7665],[-92.0829,46.7664],[-92.0826,46.7659],[-92.0819,46.7651],[-92.0812,46.7644],[-92.0811,46.7642],[-92.0784,46.7609],[-92.0781,46.7606],[-92.0768,46.759],[-92.0767,46.7588],[-92.0765,46.7587],[-92.0764,46.7584],[-92.076,46.7581],[-92.0758,46.7578],[-92.0739,46.7555],[-92.0735,46.7552],[-92.0735,46.755],[-92.073,46.7546],[-92.0729,46.7544],[-92.0726,46.754],[-92.0724,46.754],[-92.0724,46.7538],[-92.0717,46.7532],[-92.0716,46.753],[-92.0707,46.7521],[-92.0706,46.7519],[-92.0703,46.7517],[-92.0694,46.7506],[-92.0693,46.7505],[-92.069,46.7502],[-92.0688,46.75],[-92.0686,46.7497],[-92.0684,46.7495],[-92.0681,46.7491],[-92.0679,46.7489],[-92.0677,46.7487],[-92.0676,46.7486],[-92.0672,46.7481],[-92.0668,46.7478],[-92.0658,46.7466],[-92.0633,46.7441],[-92.0629,46.7437],[-92.0628,46.7435],[-92.0625,46.7432],[-92.0623,46.743],[-92.062,46.7427],[-92.0618,46.7424],[-92.0614,46.7421],[-92.0613,46.7419],[-92.0607,46.7414],[-92.0597,46.7403],[-92.0592,46.7399],[-92.0588,46.7394],[-92.0575,46.7381],[-92.0568,46.7374],[-92.0563,46.737],[-92.0559,46.7366],[-92.0546,46.7353],[-92.0546,46.7352],[-92.0544,46.7352],[-92.0542,46.735],[-92.054,46.7347],[-92.0504,46.7315],[-92.0477,46.7291],[-92.0466,46.7282],[-92.0466,46.728],[-92.0463,46.7279],[-92.0459,46.7275],[-92.0448,46.7265],[-92.0376,46.7206],[-92.037,46.7201],[-92.0348,46.7183],[-92.0274,46.7118],[-92.0269,46.7114],[-92.0267,46.7113],[-92.0265,46.7112],[-92.0264,46.7112],[-92.0258,46.7114],[-92.0253,46.7111],[-92.0243,46.7109],[-92.0214,46.7108],[-92.0205,46.7107],[-92.0194,46.7106],[-92.0192,46.7102],[-92.0192,46.7099],[-92.0187,46.7088],[-92.0174,46.7072],[-92.0164,46.7062],[-92.0163,46.706],[-92.0202,46.7041],[-92.025,46.7058],[-92.0262,46.7062],[-92.0269,46.7065],[-92.0339,46.709],[-92.0428,46.7153],[-92.0479,46.719],[-92.0501,46.7206],[-92.0594,46.7274],[-92.0648,46.7312],[-92.0687,46.734],[-92.0701,46.735],[-92.0713,46.7359],[-92.0894,46.7493],[-92.0985,46.7491],[-92.1001,46.7491],[-92.1081,46.7492],[-92.1086,46.749],[-92.1102,46.749],[-92.1138,46.7489],[-92.1165,46.7487],[-92.1173,46.7484],[-92.1184,46.7479],[-92.1252,46.745],[-92.1317,46.7422],[-92.1378,46.7396],[-92.1428,46.7351],[-92.1429,46.735],[-92.1432,46.7347],[-92.1433,46.7306],[-92.1433,46.7282],[-92.1412,46.7253],[-92.1438,46.7205],[-92.1448,46.7184],[-92.1462,46.716],[-92.1467,46.7158],[-92.1486,46.7152],[-92.1534,46.7158],[-92.1551,46.716],[-92.1672,46.72],[-92.1708,46.7189],[-92.1719,46.7185],[-92.1742,46.7173],[-92.1747,46.7172],[-92.176,46.7171],[-92.1788,46.7168],[-92.189,46.7176],[-92.1914,46.7163],[-92.1916,46.7157],[-92.1917,46.7153],[-92.1932,46.7113],[-92.1959,46.7089],[-92.1973,46.7077],[-92.1997,46.7067],[-92.2003,46.7064],[-92.2004,46.7064],[-92.201,46.7062],[-92.2015,46.706],[-92.2019,46.7058],[-92.2026,46.7054],[-92.2046,46.7041],[-92.2056,46.7026],[-92.2051,46.6984],[-92.1984,46.6962],[-92.1956,46.696],[-92.1892,46.6956],[-92.183,46.6953],[-92.178,46.692],[-92.1778,46.6919],[-92.1764,46.6903],[-92.176,46.6864],[-92.1775,46.6835],[-92.1813,46.6803],[-92.1824,46.68],[-92.1875,46.679],[-92.1906,46.6776],[-92.1916,46.6772],[-92.1924,46.6768],[-92.1957,46.6741],[-92.1958,46.674],[-92.1994,46.6703],[-92.204,46.667],[-92.2054,46.6648],[-92.2046,46.6634],[-92.2021,46.659],[-92.2015,46.6567],[-92.2022,46.6551],[-92.2044,46.6537],[-92.207,46.652],[-92.2123,46.65],[-92.2163,46.6499],[-92.2166,46.65],[-92.2234,46.6527],[-92.2262,46.6529],[-92.2284,46.653],[-92.2355,46.6501],[-92.2376,46.6498],[-92.2424,46.6493],[-92.2486,46.6535],[-92.2509,46.655],[-92.2521,46.6558],[-92.2525,46.6561],[-92.2545,46.6574],[-92.2549,46.6577],[-92.2556,46.6581],[-92.2565,46.6588],[-92.2587,46.6577],[-92.2596,46.6572],[-92.2659,46.6511],[-92.2705,46.6508],[-92.2727,46.6529],[-92.2735,46.655],[-92.2743,46.6575],[-92.2784,46.6587],[-92.2799,46.6587],[-92.2836,46.6589],[-92.2842,46.6592],[-92.2844,46.6594],[-92.2861,46.6604],[-92.287,46.6629],[-92.2871,46.6631],[-92.2872,46.6647],[-92.2873,46.6669],[-92.2873,46.6674],[-92.2881,46.6676],[-92.2907,46.6681],[-92.2912,46.6682],[-92.2921,46.6661],[-92.2922,46.665],[-92.2921,46.6633],[-92.301,46.6636],[-92.3012,46.6773],[-92.3012,46.6919],[-92.3013,46.7063],[-92.3014,46.7208],[-92.3016,46.7353],[-92.3014,46.7498],[-92.3015,46.7643],[-92.3223,46.7652],[-92.3435,46.7651],[-92.3646,46.765],[-92.3856,46.765],[-92.4064,46.7649],[-92.4283,46.765],[-92.4495,46.7657],[-92.4705,46.7656],[-92.4924,46.7657],[-92.5125,46.7658],[-92.5336,46.7659],[-92.5548,46.7662],[-92.5759,46.7667],[-92.5967,46.7665],[-92.6177,46.7667],[-92.6385,46.767],[-92.6592,46.7692],[-92.6803,46.7692],[-92.7014,46.7687],[-92.7226,46.7682],[-92.7442,46.7677],[-92.7459,46.7677],[-92.7653,46.7674],[-92.7864,46.7666],[-92.8084,46.7661],[-92.8296,46.7661],[-92.8508,46.7662],[-92.8721,46.7664],[-92.8932,46.7666],[-92.9143,46.7661],[-92.9356,46.7662],[-92.9567,46.7662],[-92.9777,46.7665],[-92.9988,46.7669],[-93.0201,46.7668],[-93.0412,46.7667],[-93.0615,46.7667],[-93.0609,46.781],[-93.061,46.7956],[-93.0606,46.81],[-93.0606,46.8241],[-93.0603,46.8387],[-93.06,46.853],[-93.0597,46.8672],[-93.059,46.8817],[-93.0587,46.8964],[-93.0582,46.9108],[-93.0583,46.9251],[-93.0577,46.9398],[-93.0576,46.9541],[-93.0573,46.9685],[-93.0571,46.9832],[-93.0568,46.9976],[-93.0564,47.0121],[-93.0559,47.0265],[-93.0557,47.0407],[-93.0558,47.0551],[-93.0558,47.0698],[-93.0557,47.084],[-93.056,47.0984],[-93.0562,47.1093],[-93.0664,47.1094],[-93.0663,47.1239],[-93.0659,47.1382],[-93.0659,47.1526],[-93.0655,47.1671],[-93.0652,47.1814],[-93.0654,47.196],[-93.0654,47.2103],[-93.0655,47.2248],[-93.0657,47.2394],[-93.0658,47.2538],[-93.0657,47.2683],[-93.0658,47.2828],[-93.0658,47.2975],[-93.0652,47.3119],[-93.0647,47.3265],[-93.0645,47.3412],[-93.0644,47.3556],[-93.0644,47.3716],[-93.0666,47.3716],[-93.0689,47.386],[-93.0693,47.4003],[-93.0692,47.4148],[-93.0692,47.429],[-93.069,47.4434],[-93.0688,47.4578],[-93.0673,47.472],[-93.067,47.4859],[-93.0651,47.5003],[-93.0647,47.5147],[-93.0641,47.529],[-93.0637,47.5445],[-93.0637,47.559],[-93.0638,47.5734],[-93.0628,47.5875],[-93.0628,47.6026],[-93.0643,47.6172],[-93.0637,47.6333],[-93.0637,47.6476],[-93.0633,47.6621],[-93.0626,47.6774],[-93.0619,47.691],[-93.0612,47.7056],[-93.0613,47.7205],[-93.0821,47.7206],[-93.0823,47.7355],[-93.0823,47.7493],[-93.0826,47.7635],[-93.083,47.7779],[-93.0834,47.7917],[-93.0837,47.8064],[-93.0837,47.8209],[-93.0837,47.8223],[-93.0831,47.835],[-93.083,47.8368],[-93.0823,47.8494],[-93.0822,47.8513],[-93.0815,47.8637],[-93.0813,47.8656],[-93.0812,47.8676],[-93.0808,47.878],[-93.0807,47.88],[-93.0808,47.8922],[-93.0808,47.8945],[-93.0809,47.9067],[-93.0809,47.9088],[-93.0809,47.9212],[-93.0809,47.9235],[-93.0809,47.9356],[-93.0809,47.938],[-93.0808,47.9504],[-93.0808,47.9525],[-93.0808,47.9647],[-93.0809,47.967],[-93.0809,47.9786],[-93.088,47.9787],[-93.0872,47.9932],[-93.0887,48.0075],[-93.0886,48.022],[-93.089,48.0366],[-93.0892,48.0509],[-93.0892,48.0679],[-93.0965,48.0678],[-93.0965,48.0679],[-93.0968,48.0823],[-93.097,48.0969],[-93.0972,48.1114],[-93.0969,48.1259],[-93.097,48.1402],[-93.097,48.1546],[-93.097,48.1692],[-93.0975,48.1836],[-93.0979,48.1981],[-93.0978,48.2126],[-93.0977,48.2271],[-93.0977,48.2426],[-93.0949,48.2425],[-93.0949,48.2426],[-93.0953,48.2576],[-93.0952,48.2716],[-93.095,48.2862],[-93.0952,48.3004],[-93.0953,48.3153],[-93.0948,48.3298],[-93.0948,48.3442],[-93.0945,48.3589],[-93.094,48.3734],[-93.094,48.3879],[-93.0938,48.4024],[-93.0935,48.4147],[-93.0923,48.4147],[-93.0922,48.429],[-93.0922,48.4303],[-93.092,48.4436],[-93.092,48.4449],[-93.0919,48.458],[-93.0918,48.4596],[-93.0915,48.4724],[-93.0914,48.474],[-93.0911,48.4867],[-93.091,48.4884],[-93.0905,48.501],[-93.0905,48.5151],[-93.0903,48.5296],[-93.0902,48.5441],[-93.0902,48.5583],[-93.09,48.5727],[-93.0898,48.5872],[-93.0895,48.6016],[-93.0886,48.6163],[-93.0884,48.6278]]],"type":"Polygon"},"id":"69","properties":{"Area":17451037319.2417,"CTYONLY_":7,"Code":"STLO","LASTMOD":"2010-10-17T00:00:00Z","Name":"St. Louis","Perimiter":682518.436},"type":"Feature"},{"geometry":{"coordinates":[[[-95.3425,48.5402],[-95.3412,48.5402],[-95.321,48.54],[-95.3194,48.54],[-95.2992,48.5402],[-95.2975,48.5401],[-95.2773,48.54],[-95.2756,48.54],[-95.2554,48.5398],[-95.2537,48.5398],[-95.2339,48.5399],[-95.2324,48.5399],[-95.2119,48.54],[-95.2115,48.5252],[-95.2115,48.5244],[-95.2111,48.5109],[-95.2111,48.5101],[-95.2112,48.4962],[-95.2111,48.4816],[-95.211,48.4673],[-95.211,48.4666],[-95.2112,48.4529],[-95.2113,48.4522],[-95.2113,48.4387],[-95.2113,48.4376],[-95.2113,48.4255],[-95.2113,48.4242],[-95.2113,48.4232],[-95.2112,48.4096],[-95.2112,48.4087],[-95.2111,48.3952],[-95.2111,48.3941],[-95.211,48.3808],[-95.211,48.3797],[-95.2106,48.3661],[-95.2066,48.3661],[-95.1983,48.3661],[-95.1887,48.3661],[-95.1861,48.3661],[-95.1669,48.3661],[-95.164,48.3661],[-95.1454,48.3662],[-95.1424,48.3662],[-95.1315,48.3662],[-95.1236,48.3663],[-95.1207,48.3663],[-95.1018,48.3663],[-95.1008,48.3663],[-95.099,48.3663],[-95.0801,48.3664],[-95.0773,48.3664],[-95.0586,48.3665],[-95.0555,48.3665],[-95.0369,48.3665],[-95.0337,48.3665],[-95.0153,48.3665],[-95.0119,48.3665],[-94.9932,48.3667],[-94.9901,48.3667],[-94.9716,48.3667],[-94.9684,48.3667],[-94.95,48.3666],[-94.9469,48.3666],[-94.9283,48.3667],[-94.9264,48.3667],[-94.9065,48.3666],[-94.9049,48.3666],[-94.8849,48.3666],[-94.8833,48.3667],[-94.8632,48.3667],[-94.8616,48.3667],[-94.8416,48.3669],[-94.8399,48.3669],[-94.8199,48.3669],[-94.8183,48.3669],[-94.7983,48.3669],[-94.7967,48.3669],[-94.7765,48.3669],[-94.7748,48.3669],[-94.7549,48.3669],[-94.7533,48.3669],[-94.7329,48.3669],[-94.7315,48.3669],[-94.7117,48.3668],[-94.7099,48.3669],[-94.6898,48.3671],[-94.683,48.3671],[-94.6694,48.3672],[-94.6679,48.3673],[-94.6622,48.3673],[-94.6505,48.3673],[-94.6465,48.3673],[-94.6405,48.3673],[-94.6245,48.3673],[-94.6188,48.3673],[-94.6029,48.3674],[-94.5971,48.3675],[-94.5812,48.3674],[-94.5754,48.3674],[-94.5593,48.3674],[-94.5536,48.3674],[-94.5378,48.3674],[-94.5335,48.3674],[-94.5157,48.3674],[-94.5118,48.3675],[-94.4941,48.3674],[-94.4924,48.3674],[-94.4906,48.3674],[-94.4722,48.3674],[-94.4688,48.3675],[-94.4505,48.3675],[-94.4471,48.3675],[-94.4288,48.3675],[-94.4252,48.3675],[-94.4253,48.352],[-94.425,48.3372],[-94.4248,48.3227],[-94.4246,48.3081],[-94.4244,48.2938],[-94.4243,48.2791],[-94.424,48.2649],[-94.4237,48.2504],[-94.4237,48.2356],[-94.4238,48.2212],[-94.4236,48.2067],[-94.4233,48.1923],[-94.4235,48.1781],[-94.4235,48.1637],[-94.4233,48.1491],[-94.4236,48.1348],[-94.4234,48.1204],[-94.4233,48.1059],[-94.4231,48.092],[-94.4234,48.0776],[-94.4247,48.0632],[-94.4246,48.0489],[-94.4241,48.0344],[-94.4236,48.0199],[-94.4176,48.02],[-94.4177,48.006],[-94.4176,47.9914],[-94.4173,47.9769],[-94.4172,47.9623],[-94.4174,47.9477],[-94.4175,47.9332],[-94.4174,47.9186],[-94.4175,47.9175],[-94.4176,47.9041],[-94.4177,47.9031],[-94.418,47.8886],[-94.4184,47.8744],[-94.4186,47.86],[-94.4185,47.8459],[-94.4186,47.8316],[-94.4187,47.817],[-94.4188,47.8026],[-94.4189,47.7881],[-94.4189,47.7735],[-94.4191,47.759],[-94.4192,47.7445],[-94.4191,47.7302],[-94.419,47.7155],[-94.4187,47.7012],[-94.4185,47.6867],[-94.4184,47.6721],[-94.417,47.6722],[-94.417,47.6578],[-94.4167,47.6435],[-94.4165,47.6291],[-94.4163,47.615],[-94.4159,47.6009],[-94.4136,47.5866],[-94.4144,47.5723],[-94.414,47.5578],[-94.4148,47.5432],[-94.4146,47.5286],[-94.4149,47.5145],[-94.4151,47.5],[-94.4154,47.4861],[-94.4156,47.4717],[-94.416,47.4571],[-94.4161,47.4449],[-94.4161,47.443],[-94.4157,47.4287],[-94.4159,47.4119],[-94.4372,47.4118],[-94.4586,47.4118],[-94.4798,47.4119],[-94.5009,47.412],[-94.5243,47.4114],[-94.5458,47.4109],[-94.5636,47.411],[-94.585,47.411],[-94.6069,47.4101],[-94.6279,47.4103],[-94.6492,47.4102],[-94.6702,47.4102],[-94.6918,47.4098],[-94.7129,47.4095],[-94.7344,47.4098],[-94.7563,47.4105],[-94.7777,47.4102],[-94.7998,47.4098],[-94.8209,47.41],[-94.8423,47.4102],[-94.8636,47.4103],[-94.8849,47.4105],[-94.9063,47.4107],[-94.9274,47.4118],[-94.9487,47.4115],[-94.97,47.4114],[-94.9914,47.4114],[-95.0127,47.4114],[-95.0341,47.4117],[-95.0557,47.4119],[-95.0766,47.4123],[-95.098,47.4125],[-95.1193,47.4126],[-95.1406,47.4125],[-95.1619,47.4127],[-95.1829,47.4127],[-95.1828,47.4268],[-95.1828,47.4412],[-95.1829,47.4557],[-95.183,47.4703],[-95.1831,47.4845],[-95.1833,47.499],[-95.1837,47.5135],[-95.1839,47.528],[-95.1841,47.5424],[-95.1841,47.5566],[-95.1844,47.571],[-95.1847,47.5861],[-95.1849,47.6006],[-95.1849,47.6151],[-95.1849,47.6297],[-95.1849,47.6442],[-95.1847,47.6587],[-95.1849,47.6735],[-95.1904,47.6734],[-95.1941,47.6734],[-95.1944,47.688],[-95.1944,47.7024],[-95.1943,47.717],[-95.1942,47.7313],[-95.1941,47.746],[-95.1941,47.7606],[-95.1939,47.7752],[-95.1939,47.7896],[-95.1938,47.8033],[-95.1937,47.8044],[-95.1937,47.8188],[-95.1936,47.8334],[-95.1935,47.8479],[-95.1935,47.8624],[-95.1934,47.8726],[-95.2003,47.8732],[-95.2025,47.8735],[-95.205,47.874],[-95.2071,47.8742],[-95.2103,47.8744],[-95.2105,47.8745],[-95.2146,47.875],[-95.215,47.8751],[-95.2172,47.8755],[-95.2193,47.876],[-95.2218,47.8765],[-95.223,47.8768],[-95.2288,47.8781],[-95.2313,47.8788],[-95.2345,47.8798],[-95.2359,47.8803],[-95.2374,47.8807],[-95.2377,47.8807],[-95.238,47.8809],[-95.2397,47.8814],[-95.2415,47.882],[-95.2456,47.8829],[-95.2473,47.8837],[-95.2485,47.8844],[-95.2502,47.8852],[-95.2518,47.8861],[-95.2538,47.8876],[-95.2558,47.8891],[-95.2578,47.8903],[-95.258,47.8905],[-95.2585,47.8909],[-95.2592,47.8917],[-95.2592,47.8918],[-95.26,47.8925],[-95.2618,47.8944],[-95.2625,47.895],[-95.2635,47.896],[-95.2655,47.8979],[-95.2657,47.8981],[-95.266,47.8984],[-95.2661,47.8985],[-95.2663,47.8987],[-95.2664,47.8991],[-95.2665,47.8992],[-95.2665,47.8993],[-95.2666,47.8993],[-95.2668,47.8999],[-95.2671,47.9004],[-95.2677,47.901],[-95.2681,47.9016],[-95.2681,47.9017],[-95.2683,47.902],[-95.2688,47.9029],[-95.2689,47.9032],[-95.2699,47.9049],[-95.2701,47.9056],[-95.2702,47.9059],[-95.2703,47.9062],[-95.2704,47.9062],[-95.2704,47.9063],[-95.2705,47.9064],[-95.2705,47.9064],[-95.2706,47.9066],[-95.2709,47.9069],[-95.2709,47.907],[-95.2723,47.9089],[-95.2728,47.9097],[-95.2728,47.9098],[-95.2729,47.9099],[-95.2729,47.9101],[-95.2732,47.9107],[-95.2734,47.9114],[-95.2734,47.9116],[-95.2735,47.9116],[-95.2736,47.9121],[-95.2738,47.9125],[-95.2738,47.9128],[-95.2741,47.9135],[-95.2741,47.9139],[-95.2748,47.9154],[-95.275,47.9156],[-95.2753,47.9162],[-95.2754,47.9168],[-95.2756,47.9172],[-95.2756,47.9175],[-95.2761,47.92],[-95.2762,47.9206],[-95.2762,47.9206],[-95.2763,47.921],[-95.2764,47.9215],[-95.2765,47.922],[-95.2766,47.9227],[-95.2767,47.9231],[-95.2768,47.9236],[-95.2771,47.9247],[-95.2774,47.9254],[-95.2774,47.9257],[-95.2776,47.9263],[-95.2778,47.9281],[-95.278,47.9286],[-95.2781,47.9302],[-95.278,47.9321],[-95.2779,47.9328],[-95.2779,47.9351],[-95.2779,47.9351],[-95.2774,47.938],[-95.2772,47.9384],[-95.2772,47.9389],[-95.277,47.9414],[-95.2769,47.9416],[-95.2767,47.9438],[-95.2767,47.9449],[-95.2761,47.947],[-95.2759,47.9474],[-95.2756,47.9487],[-95.2755,47.9488],[-95.2753,47.9495],[-95.2751,47.9507],[-95.2749,47.9515],[-95.2743,47.9529],[-95.2743,47.9531],[-95.2742,47.9534],[-95.2742,47.9541],[-95.2741,47.9561],[-95.274,47.9568],[-95.2739,47.9574],[-95.2735,47.958],[-95.2731,47.9584],[-95.2729,47.9586],[-95.2728,47.9587],[-95.2726,47.959],[-95.2726,47.9593],[-95.2725,47.9605],[-95.2722,47.961],[-95.2712,47.9623],[-95.271,47.9628],[-95.2708,47.9632],[-95.2706,47.9636],[-95.2703,47.9637],[-95.2701,47.9639],[-95.2701,47.964],[-95.2698,47.9643],[-95.2694,47.9655],[-95.268,47.9688],[-95.267,47.9704],[-95.267,47.9707],[-95.2667,47.9708],[-95.2664,47.9714],[-95.2657,47.9727],[-95.2646,47.9748],[-95.2645,47.9752],[-95.2639,47.9765],[-95.2636,47.9771],[-95.2627,47.9786],[-95.2618,47.9803],[-95.259,47.9839],[-95.2585,47.9852],[-95.2583,47.9856],[-95.2582,47.9865],[-95.258,47.987],[-95.2579,47.9875],[-95.2576,47.9883],[-95.2571,47.9891],[-95.2554,47.9917],[-95.2551,47.992],[-95.2546,47.9926],[-95.2543,47.9932],[-95.253,47.9954],[-95.2526,47.9964],[-95.2523,47.9968],[-95.252,47.9971],[-95.2518,47.9973],[-95.2512,47.998],[-95.2508,47.9988],[-95.2507,47.999],[-95.2507,48.0],[-95.2504,48.0],[-95.2502,48.0],[-95.2495,48.0],[-95.2495,48.0009],[-95.2493,48.0015],[-95.249,48.002],[-95.2486,48.0025],[-95.2481,48.0029],[-95.2479,48.0031],[-95.2477,48.0041],[-95.2472,48.0046],[-95.247,48.0048],[-95.2464,48.0055],[-95.2459,48.0059],[-95.2455,48.0066],[-95.245,48.0071],[-95.2449,48.0072],[-95.2445,48.0076],[-95.2445,48.0076],[-95.2444,48.008],[-95.2442,48.0081],[-95.2441,48.0083],[-95.2439,48.0086],[-95.2439,48.0087],[-95.2438,48.0087],[-95.2433,48.009],[-95.2423,48.0097],[-95.2421,48.01],[-95.2418,48.0103],[-95.2417,48.0106],[-95.2414,48.0108],[-95.2414,48.0109],[-95.2409,48.0111],[-95.2407,48.0112],[-95.2404,48.0114],[-95.2401,48.0117],[-95.24,48.0119],[-95.24,48.0119],[-95.2396,48.0123],[-95.2394,48.0124],[-95.2387,48.0127],[-95.2377,48.0134],[-95.2376,48.0135],[-95.2372,48.0139],[-95.2371,48.0142],[-95.2371,48.0143],[-95.237,48.0144],[-95.2368,48.0145],[-95.2367,48.0145],[-95.2363,48.0148],[-95.2362,48.0148],[-95.2358,48.0149],[-95.2354,48.0152],[-95.2352,48.0155],[-95.2347,48.0158],[-95.2326,48.017],[-95.2323,48.0174],[-95.2306,48.0185],[-95.2304,48.0188],[-95.2303,48.0191],[-95.2297,48.0196],[-95.2293,48.0199],[-95.2289,48.0201],[-95.2378,48.0201],[-95.2473,48.0201],[-95.2493,48.0201],[-95.2594,48.0201],[-95.269,48.0201],[-95.281,48.0202],[-95.2887,48.0201],[-95.2906,48.0201],[-95.2933,48.0201],[-95.3025,48.0202],[-95.3122,48.0202],[-95.3224,48.0203],[-95.3338,48.0203],[-95.3401,48.0203],[-95.3439,48.0204],[-95.3554,48.0204],[-95.3654,48.0204],[-95.3661,48.0204],[-95.377,48.0205],[-95.3871,48.0206],[-95.3985,48.0206],[-95.4086,48.0207],[-95.4201,48.0206],[-95.4302,48.0206],[-95.4417,48.0206],[-95.4523,48.0206],[-95.4632,48.0207],[-95.4738,48.0207],[-95.485,48.0207],[-95.4954,48.0207],[-95.4959,48.0207],[-95.5065,48.0208],[-95.517,48.0208],[-95.5215,48.0209],[-95.5277,48.0209],[-95.5384,48.0209],[-95.5398,48.0209],[-95.5491,48.0209],[-95.5597,48.0208],[-95.5705,48.0208],[-95.5828,48.0207],[-95.5922,48.0207],[-95.5923,48.035],[-95.5925,48.0497],[-95.5925,48.0642],[-95.5926,48.0787],[-95.5928,48.0931],[-95.593,48.1078],[-95.5931,48.1223],[-95.5936,48.1368],[-95.5938,48.1512],[-95.5939,48.1658],[-95.5939,48.173],[-95.594,48.1802],[-95.5938,48.1946],[-95.5939,48.2092],[-95.5939,48.2236],[-95.5941,48.2382],[-95.5941,48.2526],[-95.5937,48.267],[-95.5934,48.2815],[-95.5934,48.2961],[-95.5932,48.3105],[-95.5932,48.325],[-95.5932,48.3396],[-95.5933,48.354],[-95.5933,48.3656],[-95.5933,48.3656],[-95.6016,48.3655],[-95.602,48.3798],[-95.6021,48.3809],[-95.6026,48.3942],[-95.6026,48.395],[-95.6026,48.4088],[-95.6026,48.4095],[-95.6023,48.4232],[-95.6023,48.424],[-95.6021,48.4376],[-95.602,48.4385],[-95.6016,48.4522],[-95.6016,48.453],[-95.6016,48.4666],[-95.6016,48.4674],[-95.6011,48.4811],[-95.6011,48.4818],[-95.6008,48.4956],[-95.6008,48.4964],[-95.6007,48.51],[-95.6007,48.5107],[-95.6011,48.5251],[-95.6023,48.5389],[-95.5821,48.5387],[-95.5801,48.5387],[-95.5603,48.5388],[-95.558,48.5388],[-95.5383,48.5389],[-95.5365,48.5389],[-95.5163,48.539],[-95.5143,48.539],[-95.495,48.5392],[-95.493,48.5392],[-95.4726,48.5396],[-95.4712,48.5396],[-95.4513,48.5399],[-95.4494,48.5399],[-95.4297,48.5399],[-95.4279,48.54],[-95.4078,48.5402],[-95.4061,48.5402],[-95.386,48.5402],[-95.3844,48.5402],[-95.364,48.5403],[-95.3628,48.5404],[-95.3425,48.5402]]],"type":"Polygon"},"id":"4","properties":{"Area":7911449532.86586,"CTYONLY_":8,"Code":"BELT","LASTMOD":"1999-12-31T23:59:59Z","Name":"Beltrami","Perimiter":429419.1705},"type":"Feature"},{"geometry":{"coordinates":[[[-97.1467,48.1733],[-97.1462,48.1733],[-97.1376,48.1733],[-97.1322,48.1733],[-97.1286,48.1733],[-97.1257,48.1733],[-97.1253,48.1733],[-97.1071,48.1735],[-97.1069,48.1735],[-97.0855,48.1734],[-97.0853,48.1734],[-97.0637,48.1732],[-97.0637,48.1732],[-97.042,48.1732],[-97.042,48.1732],[-97.0205,48.1733],[-97.0203,48.1733],[-97.0003,48.1732],[-96.999,48.1732],[-96.9989,48.1732],[-96.9987,48.1732],[-96.998,48.1732],[-96.9975,48.1732],[-96.9959,48.1732],[-96.99,48.1731],[-96.9889,48.1731],[-96.9844,48.1731],[-96.9812,48.1731],[-96.9775,48.1731],[-96.9773,48.173],[-96.9773,48.173],[-96.9751,48.173],[-96.9749,48.173],[-96.9705,48.1731],[-96.9703,48.1731],[-96.9554,48.1731],[-96.9448,48.1732],[-96.9387,48.1732],[-96.934,48.1733],[-96.9339,48.1733],[-96.933,48.1733],[-96.9123,48.1733],[-96.9122,48.1733],[-96.8932,48.1732],[-96.8907,48.1732],[-96.8907,48.1732],[-96.8753,48.1732],[-96.869,48.1733],[-96.869,48.1733],[-96.8474,48.1733],[-96.8473,48.1733],[-96.8255,48.1734],[-96.8255,48.1734],[-96.8111,48.1734],[-96.8039,48.1734],[-96.8038,48.1734],[-96.7932,48.1733],[-96.7821,48.1734],[-96.7821,48.1734],[-96.7819,48.1734],[-96.7613,48.1734],[-96.7606,48.1734],[-96.7605,48.1734],[-96.7581,48.1734],[-96.7573,48.1734],[-96.7503,48.1734],[-96.7393,48.1734],[-96.7393,48.1734],[-96.7177,48.1734],[-96.7176,48.1734],[-96.6959,48.1734],[-96.6958,48.1734],[-96.6826,48.1735],[-96.6742,48.1736],[-96.6742,48.1736],[-96.6525,48.1738],[-96.6525,48.1738],[-96.6407,48.1739],[-96.6378,48.1738],[-96.6338,48.1737],[-96.6309,48.1737],[-96.6307,48.1737],[-96.6307,48.1737],[-96.6253,48.1737],[-96.6106,48.1737],[-96.6092,48.1737],[-96.609,48.1737],[-96.6055,48.1737],[-96.5966,48.1737],[-96.5893,48.1737],[-96.5875,48.1737],[-96.5873,48.1737],[-96.5873,48.1737],[-96.5838,48.1738],[-96.5806,48.1739],[-96.5765,48.1739],[-96.5748,48.1739],[-96.5715,48.1739],[-96.5678,48.174],[-96.5655,48.174],[-96.5654,48.174],[-96.565,48.174],[-96.5616,48.1739],[-96.557,48.1739],[-96.5544,48.1738],[-96.5507,48.1738],[-96.5479,48.1738],[-96.5446,48.1738],[-96.5443,48.1738],[-96.5442,48.1738],[-96.5434,48.1738],[-96.5399,48.1738],[-96.5357,48.1738],[-96.53,48.1738],[-96.5251,48.1738],[-96.5223,48.1739],[-96.5204,48.1739],[-96.5164,48.1739],[-96.5091,48.174],[-96.5038,48.174],[-96.5008,48.1742],[-96.5008,48.1669],[-96.5008,48.1524],[-96.5006,48.1379],[-96.5007,48.1234],[-96.501,48.1089],[-96.5009,48.0943],[-96.5009,48.0798],[-96.5009,48.0654],[-96.5008,48.0506],[-96.5009,48.0362],[-96.5009,48.0217],[-96.4826,48.0217],[-96.4826,48.0072],[-96.4824,47.9924],[-96.4823,47.9782],[-96.4823,47.9636],[-96.4825,47.949],[-96.4826,47.9347],[-96.4825,47.9202],[-96.4825,47.9055],[-96.4825,47.9054],[-96.4824,47.8913],[-96.4827,47.8768],[-96.4821,47.862],[-96.482,47.8475],[-96.4601,47.8475],[-96.4386,47.8476],[-96.4172,47.8475],[-96.3958,47.8475],[-96.3742,47.8474],[-96.3527,47.8473],[-96.3524,47.8329],[-96.3523,47.8184],[-96.3521,47.8038],[-96.352,47.7893],[-96.3519,47.7748],[-96.3516,47.7604],[-96.3313,47.7603],[-96.3097,47.7601],[-96.2884,47.7601],[-96.2668,47.7599],[-96.2453,47.7598],[-96.2238,47.7598],[-96.2022,47.7597],[-96.1806,47.7598],[-96.159,47.7598],[-96.1388,47.7598],[-96.1175,47.7602],[-96.0957,47.76],[-96.0743,47.7601],[-96.053,47.7603],[-96.0315,47.7605],[-96.0097,47.7605],[-95.9883,47.7605],[-95.9671,47.7605],[-95.9452,47.7606],[-95.9233,47.7607],[-95.9017,47.7609],[-95.8801,47.7608],[-95.8588,47.7609],[-95.8372,47.7609],[-95.8371,47.7755],[-95.8365,47.79],[-95.8366,47.8043],[-95.8366,47.819],[-95.8367,47.8335],[-95.8366,47.8482],[-95.8153,47.8484],[-95.7952,47.8483],[-95.7737,47.8484],[-95.7525,47.8485],[-95.7307,47.8487],[-95.709,47.8486],[-95.7089,47.863],[-95.7094,47.8776],[-95.7095,47.8919],[-95.7094,47.9065],[-95.7098,47.9211],[-95.7096,47.9355],[-95.6898,47.9354],[-95.6683,47.9351],[-95.6466,47.9348],[-95.6252,47.9344],[-95.6034,47.9341],[-95.5824,47.9339],[-95.5817,47.9195],[-95.5816,47.9051],[-95.5814,47.8904],[-95.5813,47.876],[-95.5812,47.8617],[-95.5809,47.847],[-95.5805,47.8327],[-95.5804,47.8183],[-95.5801,47.8039],[-95.5796,47.7894],[-95.5796,47.775],[-95.5799,47.7605],[-95.5795,47.746],[-95.5793,47.7314],[-95.5789,47.7171],[-95.5789,47.7027],[-95.5787,47.6882],[-95.5785,47.6738],[-95.5785,47.6737],[-95.5755,47.6737],[-95.5595,47.6737],[-95.5535,47.6737],[-95.5537,47.6592],[-95.5536,47.6447],[-95.5535,47.6302],[-95.5538,47.6161],[-95.5536,47.6014],[-95.5537,47.5869],[-95.5538,47.5724],[-95.5538,47.5579],[-95.5539,47.5436],[-95.5539,47.5289],[-95.5539,47.5146],[-95.5513,47.5001],[-95.5516,47.5001],[-95.5729,47.5001],[-95.5942,47.4999],[-95.6158,47.4997],[-95.6366,47.4996],[-95.6393,47.4996],[-95.6411,47.4996],[-95.6584,47.4995],[-95.6605,47.4995],[-95.6782,47.4997],[-95.6818,47.4997],[-95.6908,47.4997],[-95.6996,47.4997],[-95.7033,47.4997],[-95.7211,47.4996],[-95.7247,47.4995],[-95.7424,47.4995],[-95.7459,47.4995],[-95.7537,47.4995],[-95.7634,47.4995],[-95.7675,47.4995],[-95.7851,47.4994],[-95.7888,47.4994],[-95.7965,47.4994],[-95.8053,47.4994],[-95.8103,47.4994],[-95.8266,47.4995],[-95.8272,47.4995],[-95.8316,47.4995],[-95.8371,47.4995],[-95.8482,47.4995],[-95.8529,47.4995],[-95.8696,47.4995],[-95.8746,47.4994],[-95.8908,47.4993],[-95.8954,47.4993],[-95.9123,47.4992],[-95.9169,47.4992],[-95.9332,47.4992],[-95.9383,47.4992],[-95.9549,47.4992],[-95.9603,47.4992],[-95.9761,47.4992],[-95.9818,47.4992],[-95.9977,47.4992],[-95.9991,47.4992],[-96.0032,47.4992],[-96.019,47.4993],[-96.0247,47.4993],[-96.0362,47.4992],[-96.0408,47.4992],[-96.0462,47.4992],[-96.0676,47.4992],[-96.0888,47.4993],[-96.1101,47.4993],[-96.1314,47.4996],[-96.1526,47.4997],[-96.1739,47.4999],[-96.1954,47.4999],[-96.2166,47.4999],[-96.238,47.4998],[-96.2594,47.4998],[-96.2808,47.4998],[-96.3022,47.4999],[-96.3232,47.4999],[-96.3448,47.4997],[-96.3659,47.4997],[-96.3873,47.4997],[-96.4088,47.4996],[-96.4301,47.4996],[-96.4517,47.4994],[-96.4731,47.4993],[-96.4944,47.4993],[-96.516,47.4991],[-96.5371,47.4991],[-96.5587,47.499],[-96.5801,47.499],[-96.6013,47.4989],[-96.6229,47.499],[-96.6442,47.4992],[-96.6653,47.499],[-96.6876,47.4987],[-96.7085,47.4989],[-96.73,47.4989],[-96.7515,47.4989],[-96.7732,47.4989],[-96.7945,47.499],[-96.8159,47.499],[-96.8361,47.4989],[-96.8487,47.4989],[-96.8488,47.499],[-96.8504,47.5],[-96.8506,47.5],[-96.8507,47.5],[-96.8514,47.5004],[-96.8524,47.5006],[-96.853,47.501],[-96.8533,47.5014],[-96.8534,47.5017],[-96.8535,47.5023],[-96.8535,47.5034],[-96.8532,47.5039],[-96.8532,47.5042],[-96.8531,47.5045],[-96.8528,47.5053],[-96.8528,47.5059],[-96.8529,47.506],[-96.853,47.5065],[-96.853,47.5069],[-96.8526,47.5073],[-96.8524,47.5075],[-96.8518,47.5076],[-96.8515,47.5076],[-96.8508,47.5074],[-96.8494,47.5068],[-96.8485,47.5066],[-96.8471,47.5066],[-96.846,47.5067],[-96.8443,47.5071],[-96.8436,47.5074],[-96.8424,47.5083],[-96.8422,47.5086],[-96.8421,47.5091],[-96.8424,47.5094],[-96.8431,47.51],[-96.8439,47.5103],[-96.8448,47.5105],[-96.8464,47.5105],[-96.849,47.5098],[-96.8504,47.5096],[-96.8512,47.5096],[-96.8519,47.5098],[-96.8526,47.5102],[-96.853,47.5106],[-96.8531,47.5107],[-96.8533,47.5112],[-96.8534,47.5112],[-96.8534,47.5113],[-96.8535,47.5113],[-96.8536,47.5119],[-96.8536,47.512],[-96.8532,47.5126],[-96.8531,47.5128],[-96.8525,47.5132],[-96.8517,47.5135],[-96.8514,47.5135],[-96.851,47.5136],[-96.8502,47.5135],[-96.8491,47.5134],[-96.8465,47.5124],[-96.846,47.5123],[-96.8448,47.5124],[-96.8442,47.5125],[-96.8435,47.5128],[-96.843,47.5132],[-96.8428,47.5134],[-96.8425,47.5137],[-96.8422,47.5141],[-96.842,47.5146],[-96.842,47.5155],[-96.842,47.5156],[-96.842,47.5157],[-96.8421,47.5158],[-96.8422,47.516],[-96.8427,47.5164],[-96.8433,47.5167],[-96.8442,47.517],[-96.8454,47.5172],[-96.8465,47.517],[-96.8475,47.5166],[-96.8481,47.5163],[-96.8501,47.5155],[-96.8519,47.515],[-96.8532,47.5146],[-96.8542,47.5144],[-96.8547,47.5144],[-96.8563,47.5146],[-96.8573,47.5147],[-96.8584,47.5149],[-96.8599,47.5153],[-96.8614,47.5159],[-96.8624,47.5164],[-96.8629,47.5169],[-96.8632,47.5173],[-96.8633,47.5177],[-96.8633,47.5198],[-96.8635,47.5204],[-96.8636,47.5206],[-96.8643,47.5213],[-96.8645,47.5216],[-96.8656,47.5225],[-96.8658,47.5229],[-96.866,47.523],[-96.8663,47.5238],[-96.8664,47.5249],[-96.8666,47.5254],[-96.8672,47.5259],[-96.8676,47.5261],[-96.8683,47.5262],[-96.8698,47.5264],[-96.8705,47.5266],[-96.8707,47.5268],[-96.8708,47.5269],[-96.8709,47.5272],[-96.8709,47.5273],[-96.8709,47.5279],[-96.8706,47.5283],[-96.8704,47.5284],[-96.87,47.5287],[-96.8691,47.529],[-96.868,47.5291],[-96.8665,47.5291],[-96.865,47.529],[-96.8623,47.5291],[-96.861,47.5294],[-96.8605,47.5296],[-96.8593,47.5304],[-96.8589,47.5308],[-96.8576,47.5328],[-96.8573,47.5333],[-96.8568,47.5337],[-96.8558,47.5346],[-96.8543,47.5354],[-96.854,47.5357],[-96.8535,47.5363],[-96.8534,47.5372],[-96.8536,47.5378],[-96.854,47.5382],[-96.8546,47.5383],[-96.8558,47.5382],[-96.8569,47.5379],[-96.8573,47.5377],[-96.8579,47.5375],[-96.8589,47.5371],[-96.8593,47.5371],[-96.8599,47.5371],[-96.8609,47.5374],[-96.8619,47.5379],[-96.8629,47.5387],[-96.8632,47.5391],[-96.8634,47.5395],[-96.8634,47.5402],[-96.8628,47.5409],[-96.8614,47.5414],[-96.858,47.542],[-96.8573,47.5421],[-96.8565,47.5422],[-96.8555,47.5421],[-96.8542,47.5418],[-96.8533,47.5413],[-96.8523,47.5407],[-96.8519,47.5401],[-96.8516,47.5397],[-96.8514,47.5393],[-96.8513,47.5393],[-96.8512,47.539],[-96.8511,47.5388],[-96.851,47.5386],[-96.8507,47.5383],[-96.8507,47.5382],[-96.8501,47.5377],[-96.8494,47.5374],[-96.8484,47.5372],[-96.8477,47.5371],[-96.8471,47.5372],[-96.8465,47.5374],[-96.8457,47.538],[-96.8452,47.5386],[-96.8452,47.5394],[-96.8452,47.5397],[-96.8454,47.5399],[-96.8455,47.5403],[-96.8456,47.5404],[-96.8456,47.5405],[-96.846,47.541],[-96.8467,47.5415],[-96.8484,47.5425],[-96.8501,47.5432],[-96.8525,47.5438],[-96.8571,47.5448],[-96.8572,47.5448],[-96.8586,47.5452],[-96.8597,47.5456],[-96.8602,47.5459],[-96.8603,47.5461],[-96.8603,47.5464],[-96.8602,47.5466],[-96.8599,47.5468],[-96.8596,47.547],[-96.8585,47.5472],[-96.8576,47.5477],[-96.8572,47.5479],[-96.8554,47.5485],[-96.8542,47.5488],[-96.8538,47.5491],[-96.8523,47.5504],[-96.8505,47.5517],[-96.8501,47.5521],[-96.8499,47.5526],[-96.8497,47.5532],[-96.85,47.5537],[-96.8501,47.5538],[-96.8501,47.5539],[-96.8506,47.5543],[-96.8513,47.5546],[-96.8526,47.5549],[-96.8546,47.5551],[-96.8558,47.5551],[-96.857,47.5553],[-96.8578,47.5556],[-96.8588,47.5562],[-96.8598,47.5571],[-96.8602,47.5576],[-96.8605,47.5578],[-96.8606,47.5581],[-96.8608,47.5582],[-96.8612,47.5588],[-96.8614,47.5592],[-96.8614,47.5599],[-96.8613,47.5602],[-96.8608,47.5604],[-96.8601,47.5607],[-96.8594,47.5607],[-96.8581,47.5605],[-96.8573,47.5602],[-96.8569,47.5601],[-96.8567,47.5601],[-96.8553,47.5602],[-96.8544,47.5603],[-96.8537,47.5606],[-96.8515,47.5621],[-96.8506,47.5626],[-96.8491,47.5636],[-96.8484,47.564],[-96.8476,47.5646],[-96.8474,47.565],[-96.8472,47.5656],[-96.8472,47.5661],[-96.8474,47.5663],[-96.8479,47.5666],[-96.8487,47.5667],[-96.8498,47.5665],[-96.8503,47.5664],[-96.8513,47.5658],[-96.852,47.5656],[-96.8541,47.5653],[-96.856,47.5649],[-96.8568,47.5646],[-96.8575,47.5643],[-96.8599,47.5632],[-96.8612,47.5628],[-96.8622,47.5626],[-96.8628,47.5626],[-96.864,47.5627],[-96.8652,47.5631],[-96.8661,47.5636],[-96.8666,47.564],[-96.8676,47.5651],[-96.8678,47.5654],[-96.868,47.5655],[-96.8685,47.5663],[-96.8685,47.5664],[-96.8686,47.5665],[-96.8687,47.5668],[-96.8688,47.5669],[-96.8687,47.5677],[-96.8684,47.5682],[-96.8675,47.5688],[-96.8661,47.5695],[-96.8656,47.5696],[-96.8647,47.5694],[-96.8639,47.569],[-96.8629,47.5687],[-96.8616,47.5684],[-96.861,47.5682],[-96.8607,47.568],[-96.8599,47.5676],[-96.8588,47.5672],[-96.8578,47.5671],[-96.8567,47.5671],[-96.8555,47.5671],[-96.8539,47.5675],[-96.8529,47.5678],[-96.8519,47.5684],[-96.8514,47.569],[-96.8515,47.5698],[-96.8517,47.5703],[-96.8521,47.5709],[-96.8529,47.5715],[-96.8531,47.5716],[-96.8537,47.5719],[-96.8549,47.5725],[-96.8566,47.5731],[-96.8571,47.5733],[-96.8595,47.574],[-96.8602,47.5744],[-96.8604,47.5746],[-96.8604,47.575],[-96.8599,47.5752],[-96.8589,47.5754],[-96.8585,47.5756],[-96.8573,47.5763],[-96.8565,47.5767],[-96.8553,47.5773],[-96.8543,47.578],[-96.8534,47.5792],[-96.8532,47.5795],[-96.853,47.5802],[-96.853,47.5805],[-96.8528,47.5809],[-96.8529,47.5822],[-96.853,47.5826],[-96.8532,47.5826],[-96.8532,47.5833],[-96.8531,47.5837],[-96.8526,47.5844],[-96.8527,47.5845],[-96.8525,47.5846],[-96.852,47.585],[-96.852,47.5851],[-96.8515,47.5859],[-96.8515,47.586],[-96.8513,47.5869],[-96.8512,47.5873],[-96.8511,47.5878],[-96.851,47.5881],[-96.8507,47.5888],[-96.8502,47.5898],[-96.85,47.5903],[-96.8499,47.591],[-96.8501,47.5916],[-96.8503,47.5919],[-96.8511,47.5925],[-96.8517,47.5927],[-96.8538,47.593],[-96.8549,47.5934],[-96.8562,47.5939],[-96.8575,47.5943],[-96.8582,47.5947],[-96.8586,47.5949],[-96.8588,47.5954],[-96.8588,47.5958],[-96.8584,47.5962],[-96.8575,47.5963],[-96.8562,47.5962],[-96.8542,47.596],[-96.853,47.5961],[-96.8521,47.5964],[-96.8515,47.5968],[-96.8511,47.5973],[-96.8509,47.5977],[-96.8509,47.5983],[-96.8511,47.5989],[-96.8515,47.5993],[-96.8521,47.5997],[-96.8528,47.6],[-96.8536,47.6003],[-96.8545,47.6004],[-96.8556,47.6009],[-96.8561,47.6014],[-96.8564,47.6016],[-96.8567,47.602],[-96.8569,47.6024],[-96.8568,47.6031],[-96.8565,47.6035],[-96.8562,47.6039],[-96.8553,47.6051],[-96.8549,47.6058],[-96.8548,47.6064],[-96.8548,47.6073],[-96.8549,47.6075],[-96.855,47.6079],[-96.855,47.608],[-96.8554,47.6088],[-96.8557,47.6093],[-96.8558,47.6094],[-96.8561,47.6098],[-96.8563,47.61],[-96.8571,47.6108],[-96.858,47.6115],[-96.8589,47.612],[-96.8602,47.6122],[-96.8612,47.6124],[-96.8646,47.6124],[-96.8655,47.6125],[-96.8664,47.6129],[-96.8672,47.6136],[-96.8673,47.6138],[-96.8675,47.6139],[-96.8676,47.6141],[-96.8679,47.6144],[-96.8686,47.6148],[-96.869,47.615],[-96.8694,47.615],[-96.8703,47.6147],[-96.871,47.6143],[-96.8714,47.6139],[-96.8719,47.6136],[-96.8723,47.6135],[-96.8729,47.6135],[-96.8736,47.6137],[-96.8739,47.614],[-96.874,47.6141],[-96.874,47.6148],[-96.8739,47.6149],[-96.8736,47.6154],[-96.8726,47.6159],[-96.8715,47.6165],[-96.871,47.6169],[-96.8706,47.6176],[-96.8708,47.6181],[-96.8712,47.6183],[-96.8717,47.6184],[-96.8727,47.6184],[-96.8753,47.6191],[-96.8763,47.6192],[-96.8778,47.6189],[-96.878,47.6189],[-96.879,47.6189],[-96.8796,47.6191],[-96.88,47.6195],[-96.88,47.62],[-96.8794,47.6206],[-96.8783,47.6213],[-96.8779,47.6215],[-96.8769,47.6219],[-96.8763,47.6223],[-96.876,47.6228],[-96.8758,47.623],[-96.876,47.6235],[-96.8761,47.6237],[-96.8768,47.6243],[-96.8775,47.6244],[-96.878,47.6245],[-96.8792,47.6246],[-96.88,47.6247],[-96.8803,47.625],[-96.8806,47.6254],[-96.8807,47.6255],[-96.8807,47.6259],[-96.8804,47.6262],[-96.8798,47.6266],[-96.8792,47.6267],[-96.8786,47.6267],[-96.878,47.6267],[-96.8767,47.6266],[-96.8753,47.6267],[-96.8748,47.6269],[-96.8745,47.6272],[-96.8745,47.6275],[-96.8745,47.628],[-96.8747,47.6283],[-96.8753,47.6287],[-96.8765,47.629],[-96.8774,47.6289],[-96.8781,47.6289],[-96.8787,47.6289],[-96.8795,47.6289],[-96.8801,47.6289],[-96.8806,47.6291],[-96.881,47.6294],[-96.8815,47.6299],[-96.8815,47.6299],[-96.8815,47.63],[-96.8816,47.6301],[-96.8818,47.6305],[-96.8818,47.631],[-96.8819,47.6311],[-96.882,47.6324],[-96.8822,47.6333],[-96.8823,47.6334],[-96.8823,47.6335],[-96.8827,47.6339],[-96.8852,47.6356],[-96.8876,47.6376],[-96.8878,47.6379],[-96.8885,47.6385],[-96.8885,47.6393],[-96.8884,47.6395],[-96.8881,47.6398],[-96.8874,47.6401],[-96.886,47.6405],[-96.8845,47.6408],[-96.8835,47.6412],[-96.8832,47.6414],[-96.8828,47.6418],[-96.8826,47.6422],[-96.8826,47.6429],[-96.8829,47.6439],[-96.8829,47.6441],[-96.8829,47.6447],[-96.8828,47.6451],[-96.8827,47.6462],[-96.8825,47.6471],[-96.8823,47.6491],[-96.8826,47.6498],[-96.8828,47.6502],[-96.8837,47.6509],[-96.8844,47.6513],[-96.8846,47.6513],[-96.8847,47.6515],[-96.8862,47.6523],[-96.8866,47.6526],[-96.8869,47.6531],[-96.887,47.6533],[-96.887,47.6543],[-96.8868,47.6548],[-96.8869,47.6556],[-96.887,47.656],[-96.8876,47.6577],[-96.8876,47.6585],[-96.8876,47.6589],[-96.8873,47.6596],[-96.8869,47.6601],[-96.8857,47.6616],[-96.8855,47.6624],[-96.8855,47.6635],[-96.8857,47.6643],[-96.8862,47.6652],[-96.8863,47.6653],[-96.8863,47.6654],[-96.8864,47.6656],[-96.8864,47.6656],[-96.8871,47.6664],[-96.8889,47.668],[-96.8896,47.6686],[-96.8897,47.669],[-96.8898,47.669],[-96.8899,47.6693],[-96.89,47.6694],[-96.8901,47.67],[-96.8899,47.6703],[-96.8897,47.6707],[-96.8883,47.6715],[-96.8871,47.6721],[-96.8868,47.6722],[-96.8863,47.6725],[-96.8859,47.6727],[-96.8856,47.6727],[-96.8855,47.6729],[-96.8853,47.6732],[-96.8851,47.6735],[-96.8852,47.6737],[-96.8852,47.6738],[-96.8853,47.6739],[-96.8857,47.6742],[-96.8863,47.6743],[-96.8867,47.6743],[-96.8874,47.6743],[-96.8886,47.674],[-96.8892,47.6738],[-96.8908,47.6734],[-96.8919,47.6732],[-96.8935,47.6732],[-96.8946,47.6734],[-96.8952,47.6736],[-96.8955,47.6738],[-96.8964,47.6745],[-96.8967,47.6748],[-96.8968,47.6751],[-96.8967,47.6759],[-96.8964,47.6768],[-96.8963,47.6772],[-96.8962,47.6775],[-96.8961,47.6776],[-96.8961,47.6785],[-96.8963,47.6792],[-96.8964,47.6793],[-96.8964,47.6794],[-96.8965,47.6796],[-96.8968,47.6802],[-96.8971,47.6804],[-96.8971,47.6806],[-96.8972,47.6806],[-96.8973,47.681],[-96.8974,47.6811],[-96.8974,47.6812],[-96.8975,47.6813],[-96.8977,47.6817],[-96.8978,47.6818],[-96.8978,47.682],[-96.8984,47.6834],[-96.8986,47.6837],[-96.8986,47.684],[-96.8987,47.6841],[-96.8989,47.6846],[-96.899,47.6847],[-96.899,47.685],[-96.8993,47.686],[-96.8992,47.6871],[-96.8992,47.688],[-96.8992,47.6883],[-96.8992,47.6887],[-96.8993,47.6895],[-96.8995,47.69],[-96.8996,47.6901],[-96.8997,47.6903],[-96.9002,47.6908],[-96.9011,47.6914],[-96.9017,47.6917],[-96.9022,47.6918],[-96.9029,47.6916],[-96.9035,47.6913],[-96.9039,47.6909],[-96.9047,47.6898],[-96.9052,47.6893],[-96.906,47.6889],[-96.9072,47.6885],[-96.9081,47.6885],[-96.9089,47.6888],[-96.9095,47.6892],[-96.9098,47.6896],[-96.9101,47.69],[-96.9101,47.6913],[-96.9099,47.6916],[-96.9098,47.692],[-96.9091,47.6926],[-96.9077,47.6934],[-96.9074,47.6937],[-96.9072,47.694],[-96.9072,47.6947],[-96.9076,47.6952],[-96.9077,47.6954],[-96.9083,47.6961],[-96.9092,47.6968],[-96.9097,47.6974],[-96.9101,47.698],[-96.9102,47.6982],[-96.9103,47.6985],[-96.9103,47.6986],[-96.9104,47.6986],[-96.9106,47.6989],[-96.9107,47.6991],[-96.9107,47.6993],[-96.9115,47.7006],[-96.912,47.7012],[-96.9125,47.7017],[-96.9128,47.7018],[-96.9132,47.7019],[-96.914,47.7018],[-96.9145,47.7016],[-96.9155,47.7009],[-96.9169,47.6998],[-96.9177,47.6994],[-96.9184,47.6991],[-96.9193,47.6991],[-96.9202,47.6993],[-96.9207,47.6996],[-96.9208,47.6998],[-96.9208,47.6999],[-96.921,47.7],[-96.9211,47.7003],[-96.9211,47.7008],[-96.9208,47.7013],[-96.9204,47.7017],[-96.9194,47.7026],[-96.919,47.7028],[-96.9187,47.703],[-96.9176,47.7034],[-96.9172,47.7035],[-96.9164,47.7034],[-96.9155,47.7035],[-96.9145,47.7038],[-96.9137,47.7042],[-96.9132,47.7047],[-96.9128,47.7052],[-96.9123,47.7058],[-96.9119,47.7066],[-96.912,47.7075],[-96.9122,47.7079],[-96.9129,47.7083],[-96.9134,47.7084],[-96.9146,47.7085],[-96.9163,47.7086],[-96.9175,47.7089],[-96.919,47.7095],[-96.9198,47.71],[-96.9201,47.7104],[-96.9201,47.7105],[-96.9202,47.7107],[-96.9204,47.7111],[-96.9204,47.712],[-96.9203,47.7124],[-96.9197,47.7137],[-96.9195,47.7139],[-96.9194,47.7142],[-96.9192,47.7146],[-96.9191,47.7149],[-96.9191,47.7156],[-96.9197,47.7166],[-96.9201,47.7171],[-96.9206,47.7174],[-96.9209,47.7176],[-96.9216,47.7178],[-96.9224,47.718],[-96.9232,47.7179],[-96.9238,47.7176],[-96.9241,47.7174],[-96.9245,47.7171],[-96.9247,47.7167],[-96.9248,47.7166],[-96.9248,47.7164],[-96.9251,47.7162],[-96.9252,47.716],[-96.926,47.7153],[-96.9266,47.7149],[-96.9277,47.7144],[-96.9284,47.7143],[-96.929,47.7143],[-96.93,47.7145],[-96.9305,47.7148],[-96.931,47.7153],[-96.931,47.7154],[-96.9311,47.7154],[-96.9312,47.716],[-96.9312,47.7166],[-96.9308,47.7174],[-96.9308,47.7175],[-96.9305,47.7179],[-96.93,47.7183],[-96.9287,47.7187],[-96.9271,47.719],[-96.9251,47.7197],[-96.9237,47.7202],[-96.9217,47.7211],[-96.9205,47.7218],[-96.9194,47.7226],[-96.9193,47.7227],[-96.9189,47.7231],[-96.9187,47.7234],[-96.9185,47.7239],[-96.9187,47.7243],[-96.9188,47.7244],[-96.9188,47.7245],[-96.9191,47.7248],[-96.9197,47.7251],[-96.9203,47.7253],[-96.9224,47.7256],[-96.9236,47.7259],[-96.9242,47.7262],[-96.9246,47.7267],[-96.9248,47.7272],[-96.925,47.7275],[-96.925,47.7291],[-96.9253,47.7299],[-96.9255,47.7302],[-96.9257,47.7304],[-96.9273,47.7316],[-96.9279,47.7321],[-96.9283,47.7325],[-96.9305,47.7344],[-96.9314,47.7353],[-96.9319,47.7359],[-96.9323,47.7365],[-96.9324,47.7366],[-96.9325,47.7368],[-96.9327,47.7371],[-96.9328,47.7372],[-96.9332,47.7383],[-96.9333,47.7388],[-96.9332,47.7395],[-96.933,47.74],[-96.9327,47.7403],[-96.9319,47.741],[-96.9318,47.7411],[-96.9308,47.7417],[-96.9302,47.7422],[-96.9293,47.743],[-96.929,47.7435],[-96.9287,47.7442],[-96.9285,47.7449],[-96.9284,47.7454],[-96.9284,47.7465],[-96.9285,47.7481],[-96.9286,47.7491],[-96.9288,47.7493],[-96.9289,47.7497],[-96.929,47.7497],[-96.9289,47.75],[-96.929,47.7504],[-96.9298,47.751],[-96.9308,47.7515],[-96.9322,47.7521],[-96.9332,47.7526],[-96.9351,47.7532],[-96.9387,47.754],[-96.9394,47.7544],[-96.9398,47.7549],[-96.9397,47.7555],[-96.9394,47.7559],[-96.9388,47.7562],[-96.9381,47.7563],[-96.9373,47.7563],[-96.9363,47.7562],[-96.9337,47.7551],[-96.9327,47.7548],[-96.9323,47.7548],[-96.9311,47.7547],[-96.9297,47.7549],[-96.9291,47.755],[-96.9289,47.7553],[-96.9288,47.7558],[-96.9291,47.7561],[-96.9298,47.7565],[-96.9309,47.7569],[-96.9324,47.7573],[-96.9335,47.7576],[-96.9355,47.7583],[-96.9368,47.759],[-96.9369,47.7592],[-96.9371,47.7594],[-96.9372,47.7595],[-96.9378,47.7602],[-96.9379,47.7604],[-96.9381,47.7607],[-96.9381,47.7609],[-96.9382,47.7609],[-96.9382,47.761],[-96.9384,47.7614],[-96.9384,47.7625],[-96.938,47.7632],[-96.9376,47.7639],[-96.9369,47.7646],[-96.9366,47.7649],[-96.9352,47.7658],[-96.9351,47.766],[-96.9349,47.7664],[-96.9348,47.7668],[-96.9349,47.7671],[-96.9357,47.7676],[-96.9365,47.7678],[-96.9382,47.7681],[-96.9391,47.7684],[-96.9404,47.7692],[-96.9423,47.7708],[-96.943,47.7712],[-96.9442,47.7717],[-96.9445,47.7717],[-96.9445,47.7719],[-96.9452,47.7722],[-96.9457,47.7727],[-96.9458,47.7729],[-96.9459,47.7734],[-96.9459,47.7743],[-96.946,47.7746],[-96.9466,47.775],[-96.9473,47.7753],[-96.9483,47.7755],[-96.9494,47.7753],[-96.9495,47.7753],[-96.9518,47.7747],[-96.9527,47.7746],[-96.9537,47.7746],[-96.9539,47.7747],[-96.955,47.7748],[-96.956,47.7751],[-96.9565,47.7753],[-96.9567,47.7757],[-96.9567,47.7761],[-96.9566,47.7762],[-96.9544,47.7777],[-96.9538,47.778],[-96.9527,47.7787],[-96.9523,47.779],[-96.9522,47.7793],[-96.9524,47.7796],[-96.9527,47.7799],[-96.9533,47.78],[-96.9538,47.78],[-96.9554,47.7798],[-96.9565,47.7798],[-96.9573,47.78],[-96.9584,47.7803],[-96.9589,47.7807],[-96.9593,47.7812],[-96.9593,47.7819],[-96.9592,47.7819],[-96.9578,47.7838],[-96.9576,47.7844],[-96.9575,47.7847],[-96.9575,47.7852],[-96.9578,47.7855],[-96.9581,47.7856],[-96.9584,47.7857],[-96.959,47.7855],[-96.9596,47.7849],[-96.9597,47.7847],[-96.9598,47.7847],[-96.9598,47.7846],[-96.9601,47.7843],[-96.961,47.7838],[-96.9619,47.7833],[-96.9631,47.783],[-96.9638,47.783],[-96.9644,47.783],[-96.9649,47.7833],[-96.9653,47.7835],[-96.9654,47.7839],[-96.9653,47.785],[-96.9651,47.7853],[-96.965,47.7855],[-96.9645,47.7862],[-96.9635,47.7873],[-96.9628,47.7879],[-96.9621,47.7884],[-96.9615,47.7888],[-96.9599,47.7893],[-96.9586,47.7896],[-96.958,47.7898],[-96.9576,47.79],[-96.9572,47.7902],[-96.9571,47.7904],[-96.9572,47.791],[-96.9573,47.7913],[-96.9574,47.7915],[-96.9578,47.7921],[-96.9584,47.7925],[-96.9597,47.7931],[-96.9627,47.7942],[-96.9635,47.7947],[-96.9642,47.7951],[-96.965,47.7959],[-96.9657,47.7968],[-96.966,47.7973],[-96.9661,47.7992],[-96.9662,47.7993],[-96.9663,47.7994],[-96.9669,47.7998],[-96.9674,47.7999],[-96.9681,47.7998],[-96.9687,47.7996],[-96.9689,47.7995],[-96.9702,47.7987],[-96.9716,47.7983],[-96.974,47.7978],[-96.9751,47.7978],[-96.9754,47.7978],[-96.9762,47.7979],[-96.9766,47.7981],[-96.9768,47.7983],[-96.977,47.7986],[-96.977,47.8],[-96.9764,47.8013],[-96.9761,47.8016],[-96.9759,47.8017],[-96.9754,47.8019],[-96.9751,47.8019],[-96.973,47.8019],[-96.9723,47.802],[-96.9721,47.8022],[-96.9719,47.8025],[-96.9721,47.8029],[-96.973,47.8034],[-96.974,47.8036],[-96.9749,47.8037],[-96.9751,47.8037],[-96.9769,47.8037],[-96.9789,47.804],[-96.9796,47.8042],[-96.981,47.8045],[-96.9818,47.8046],[-96.9826,47.805],[-96.9828,47.8051],[-96.9831,47.8051],[-96.9832,47.8053],[-96.9851,47.8065],[-96.9859,47.8069],[-96.9863,47.8071],[-96.9877,47.8072],[-96.9894,47.8072],[-96.9905,47.8076],[-96.991,47.8078],[-96.9914,47.8081],[-96.9916,47.8085],[-96.9916,47.8091],[-96.9912,47.8094],[-96.9903,47.8097],[-96.9891,47.8099],[-96.9882,47.8099],[-96.9864,47.8098],[-96.9818,47.8091],[-96.9805,47.8092],[-96.9796,47.8095],[-96.9788,47.8099],[-96.9782,47.8106],[-96.978,47.8112],[-96.9779,47.8117],[-96.9781,47.8122],[-96.9784,47.8128],[-96.9786,47.8129],[-96.9787,47.8131],[-96.9795,47.8138],[-96.9795,47.8139],[-96.9798,47.8143],[-96.9799,47.8145],[-96.9799,47.8146],[-96.9803,47.8157],[-96.9804,47.8187],[-96.9804,47.822],[-96.9802,47.8224],[-96.9797,47.8226],[-96.979,47.8226],[-96.9772,47.8222],[-96.9764,47.8221],[-96.9759,47.8221],[-96.9754,47.8222],[-96.9747,47.8224],[-96.9745,47.8224],[-96.9744,47.8225],[-96.9741,47.8228],[-96.9741,47.8234],[-96.9743,47.8239],[-96.9749,47.8244],[-96.9757,47.825],[-96.9759,47.825],[-96.9769,47.8254],[-96.9783,47.8256],[-96.9793,47.8257],[-96.982,47.8255],[-96.9845,47.8251],[-96.9857,47.8251],[-96.9865,47.8252],[-96.9869,47.8254],[-96.9872,47.8256],[-96.9871,47.8261],[-96.9867,47.8265],[-96.9858,47.8269],[-96.984,47.8275],[-96.9827,47.8281],[-96.9825,47.8283],[-96.9819,47.8287],[-96.9817,47.829],[-96.9815,47.8295],[-96.9816,47.8301],[-96.9817,47.8305],[-96.982,47.8309],[-96.9843,47.8325],[-96.9848,47.8331],[-96.9849,47.8332],[-96.9849,47.8333],[-96.985,47.8334],[-96.9852,47.8339],[-96.9853,47.8344],[-96.9854,47.8345],[-96.9857,47.8359],[-96.9859,47.8361],[-96.9859,47.8366],[-96.9863,47.8373],[-96.9866,47.8377],[-96.9873,47.8379],[-96.9881,47.838],[-96.9896,47.8381],[-96.9907,47.838],[-96.9915,47.8378],[-96.9924,47.8378],[-96.9929,47.838],[-96.9937,47.8383],[-96.9941,47.8388],[-96.9941,47.8396],[-96.994,47.8397],[-96.9935,47.8404],[-96.9929,47.8412],[-96.9925,47.8417],[-96.9924,47.8421],[-96.9924,47.8426],[-96.9927,47.8427],[-96.9931,47.8428],[-96.9938,47.8426],[-96.9956,47.842],[-96.9969,47.8416],[-96.9976,47.8416],[-96.9976,47.8435],[-96.9974,47.8437],[-96.9963,47.8444],[-96.9958,47.8447],[-96.9947,47.845],[-96.9943,47.8452],[-96.9941,47.8455],[-96.994,47.8458],[-96.9941,47.8461],[-96.9941,47.8462],[-96.9942,47.8463],[-96.9943,47.8464],[-96.9949,47.847],[-96.9956,47.8474],[-96.9967,47.848],[-96.9968,47.848],[-96.9968,47.8482],[-96.9969,47.8482],[-96.9971,47.8484],[-96.9973,47.8488],[-96.9975,47.8496],[-96.9973,47.8504],[-96.9969,47.8515],[-96.9967,47.8526],[-96.9968,47.8545],[-96.9969,47.8555],[-96.9971,47.8561],[-96.9971,47.8564],[-96.9972,47.8566],[-96.9973,47.8567],[-96.9974,47.8574],[-96.9976,47.8577],[-96.9978,47.8583],[-96.9978,47.8583],[-96.9981,47.8589],[-96.9982,47.859],[-96.9983,47.8592],[-96.9989,47.8599],[-96.9994,47.8603],[-96.9998,47.8607],[-97.0003,47.861],[-97.0017,47.8613],[-97.0031,47.8623],[-97.0055,47.864],[-97.0058,47.8653],[-97.0033,47.8659],[-97.0015,47.8674],[-97.0024,47.8687],[-97.0053,47.8702],[-97.0084,47.8708],[-97.0173,47.8716],[-97.0194,47.8722],[-97.0212,47.8726],[-97.0218,47.8731],[-97.0231,47.874],[-97.0231,47.875],[-97.0221,47.8755],[-97.0196,47.8766],[-97.0193,47.8768],[-97.0189,47.8769],[-97.0179,47.8785],[-97.0193,47.8803],[-97.022,47.8815],[-97.0233,47.8821],[-97.0253,47.8843],[-97.0253,47.8856],[-97.0249,47.8869],[-97.0222,47.8884],[-97.0194,47.8897],[-97.0191,47.8898],[-97.0189,47.8911],[-97.019,47.8912],[-97.0195,47.8915],[-97.0225,47.8933],[-97.0249,47.895],[-97.0239,47.8981],[-97.0201,47.9005],[-97.0202,47.9022],[-97.0241,47.9053],[-97.0242,47.9056],[-97.0249,47.9082],[-97.0245,47.9083],[-97.0235,47.9085],[-97.0203,47.9064],[-97.0198,47.9063],[-97.0184,47.906],[-97.0172,47.9057],[-97.015,47.9072],[-97.015,47.9073],[-97.0153,47.9103],[-97.0156,47.9108],[-97.0172,47.9131],[-97.0195,47.9141],[-97.0197,47.9142],[-97.0214,47.9147],[-97.0237,47.9159],[-97.0196,47.9175],[-97.018,47.9181],[-97.0177,47.9198],[-97.0183,47.9202],[-97.0196,47.9211],[-97.0213,47.9221],[-97.0219,47.9224],[-97.0235,47.9236],[-97.0247,47.9244],[-97.026,47.9253],[-97.0284,47.9269],[-97.0296,47.9276],[-97.0323,47.9285],[-97.0357,47.9302],[-97.0373,47.9333],[-97.0368,47.9343],[-97.0355,47.9366],[-97.036,47.9394],[-97.0374,47.9399],[-97.0391,47.9405],[-97.0394,47.9405],[-97.0416,47.9406],[-97.0417,47.9406],[-97.0449,47.9411],[-97.051,47.9434],[-97.0545,47.9463],[-97.0555,47.9491],[-97.0555,47.9491],[-97.0553,47.9502],[-97.0551,47.9508],[-97.0525,47.9548],[-97.0524,47.9572],[-97.054,47.9597],[-97.059,47.9621],[-97.0613,47.9636],[-97.0614,47.9636],[-97.0618,47.9645],[-97.0615,47.9659],[-97.06,47.9672],[-97.0578,47.969],[-97.0571,47.9705],[-97.0593,47.974],[-97.0591,47.9754],[-97.0589,47.976],[-97.0588,47.9762],[-97.0587,47.9766],[-97.0584,47.977],[-97.0582,47.9774],[-97.0579,47.9778],[-97.0577,47.9781],[-97.0577,47.9782],[-97.0574,47.9787],[-97.0571,47.9792],[-97.0567,47.9801],[-97.0564,47.9806],[-97.0563,47.9811],[-97.0561,47.9815],[-97.0559,47.9821],[-97.0556,47.9828],[-97.0554,47.9833],[-97.0553,47.9838],[-97.0552,47.9842],[-97.0549,47.9849],[-97.0546,47.9855],[-97.0544,47.986],[-97.0541,47.9866],[-97.0539,47.9871],[-97.0537,47.9877],[-97.0535,47.988],[-97.0534,47.9884],[-97.0533,47.9887],[-97.0532,47.989],[-97.053,47.9894],[-97.053,47.9898],[-97.053,47.9903],[-97.053,47.9905],[-97.0531,47.9907],[-97.0532,47.9909],[-97.0533,47.9912],[-97.0534,47.9915],[-97.0535,47.9917],[-97.0538,47.992],[-97.0541,47.9923],[-97.0543,47.9925],[-97.0545,47.9926],[-97.0549,47.993],[-97.0555,47.9933],[-97.0561,47.9936],[-97.0566,47.9938],[-97.0571,47.9939],[-97.0578,47.9941],[-97.0584,47.9943],[-97.0591,47.9945],[-97.0597,47.9948],[-97.0601,47.9949],[-97.0604,47.9951],[-97.0608,47.9953],[-97.0614,47.9956],[-97.0617,47.9957],[-97.0619,47.9959],[-97.0622,47.996],[-97.0625,47.9962],[-97.0628,47.9965],[-97.063,47.9967],[-97.0633,47.997],[-97.0637,47.9975],[-97.0639,47.9977],[-97.0641,47.9982],[-97.0642,47.9986],[-97.0644,47.9989],[-97.0644,47.9994],[-97.0645,48.0],[-97.0645,48.0004],[-97.0644,48.002],[-97.0644,48.0027],[-97.0645,48.0034],[-97.0648,48.0045],[-97.0656,48.0064],[-97.0659,48.0071],[-97.0662,48.0079],[-97.0667,48.0089],[-97.0667,48.0096],[-97.0666,48.0102],[-97.0654,48.0114],[-97.0638,48.0125],[-97.0636,48.0126],[-97.063,48.0132],[-97.0628,48.0138],[-97.0629,48.0145],[-97.0632,48.015],[-97.0638,48.0153],[-97.0649,48.0157],[-97.0685,48.016],[-97.0692,48.0162],[-97.0706,48.017],[-97.0717,48.0181],[-97.0722,48.0192],[-97.0723,48.0196],[-97.0723,48.0201],[-97.0721,48.0207],[-97.0721,48.0209],[-97.0719,48.0214],[-97.0713,48.0228],[-97.0699,48.0247],[-97.0689,48.0263],[-97.0687,48.0277],[-97.0688,48.029],[-97.0691,48.0313],[-97.0697,48.0334],[-97.07,48.0354],[-97.0701,48.0361],[-97.0699,48.0374],[-97.0704,48.0418],[-97.0712,48.0458],[-97.0719,48.0474],[-97.0722,48.0481],[-97.0732,48.0499],[-97.0732,48.05],[-97.074,48.0513],[-97.0747,48.0521],[-97.0756,48.0528],[-97.0767,48.0533],[-97.0782,48.054],[-97.0795,48.0545],[-97.0815,48.0553],[-97.0828,48.0558],[-97.084,48.0564],[-97.0845,48.0567],[-97.0859,48.0575],[-97.0869,48.0583],[-97.0881,48.0596],[-97.0892,48.0611],[-97.0905,48.0627],[-97.0905,48.0628],[-97.0908,48.0631],[-97.0919,48.0644],[-97.092,48.0644],[-97.0932,48.0653],[-97.0951,48.0669],[-97.0958,48.0677],[-97.0963,48.0688],[-97.0969,48.07],[-97.0972,48.0706],[-97.0977,48.0711],[-97.0982,48.0714],[-97.0988,48.0715],[-97.0997,48.0716],[-97.1012,48.0715],[-97.103,48.0717],[-97.1038,48.0719],[-97.1044,48.0725],[-97.1046,48.0731],[-97.1045,48.074],[-97.1041,48.0746],[-97.1007,48.0775],[-97.1005,48.078],[-97.1001,48.0788],[-97.0998,48.0799],[-97.0994,48.0822],[-97.0994,48.0838],[-97.0996,48.0849],[-97.0997,48.0859],[-97.1001,48.0869],[-97.1012,48.0884],[-97.1021,48.0892],[-97.1034,48.0898],[-97.1047,48.0902],[-97.1066,48.0904],[-97.108,48.0906],[-97.1094,48.091],[-97.1098,48.0914],[-97.1097,48.0917],[-97.1095,48.0922],[-97.1087,48.0928],[-97.1067,48.0934],[-97.1066,48.0934],[-97.104,48.0939],[-97.1031,48.0941],[-97.1025,48.0946],[-97.102,48.0953],[-97.1018,48.0959],[-97.1022,48.0967],[-97.1029,48.0973],[-97.1041,48.098],[-97.106,48.0987],[-97.1066,48.0989],[-97.1074,48.0992],[-97.108,48.0996],[-97.1084,48.0999],[-97.1086,48.1003],[-97.1088,48.1008],[-97.1089,48.1017],[-97.1088,48.1028],[-97.109,48.1038],[-97.1095,48.1048],[-97.1107,48.1056],[-97.1114,48.106],[-97.1124,48.1062],[-97.1131,48.1062],[-97.115,48.106],[-97.1169,48.1057],[-97.1181,48.1056],[-97.1197,48.1054],[-97.1208,48.1056],[-97.1218,48.1059],[-97.1225,48.1063],[-97.1232,48.1067],[-97.1234,48.1073],[-97.1235,48.1076],[-97.1236,48.1078],[-97.1236,48.1081],[-97.1231,48.1095],[-97.122,48.1109],[-97.121,48.1123],[-97.1205,48.1134],[-97.1207,48.115],[-97.121,48.1159],[-97.1215,48.117],[-97.1253,48.1223],[-97.1256,48.1224],[-97.1257,48.1226],[-97.1261,48.1233],[-97.1268,48.1243],[-97.127,48.1246],[-97.1271,48.125],[-97.1275,48.1258],[-97.1282,48.1272],[-97.1286,48.1284],[-97.1288,48.1291],[-97.129,48.1309],[-97.1294,48.1332],[-97.13,48.134],[-97.1314,48.135],[-97.1323,48.1358],[-97.1328,48.1362],[-97.1332,48.1366],[-97.1334,48.1372],[-97.133,48.1375],[-97.1325,48.1377],[-97.1319,48.1376],[-97.1303,48.1372],[-97.1293,48.1369],[-97.1289,48.1367],[-97.128,48.1364],[-97.1276,48.1362],[-97.1267,48.1361],[-97.1253,48.1361],[-97.1241,48.1364],[-97.124,48.1365],[-97.123,48.137],[-97.1227,48.1375],[-97.1224,48.1381],[-97.1223,48.1386],[-97.1223,48.1391],[-97.1228,48.1398],[-97.1234,48.1402],[-97.1239,48.1406],[-97.1248,48.1409],[-97.1253,48.1411],[-97.1266,48.1416],[-97.1277,48.1418],[-97.1294,48.1421],[-97.1297,48.1421],[-97.1319,48.1424],[-97.1347,48.143],[-97.1367,48.1433],[-97.1379,48.1433],[-97.1393,48.1429],[-97.1407,48.1423],[-97.1415,48.1417],[-97.1426,48.1413],[-97.1435,48.141],[-97.1444,48.1411],[-97.1454,48.1413],[-97.1461,48.1417],[-97.1465,48.1423],[-97.1466,48.1433],[-97.1465,48.1441],[-97.1458,48.1452],[-97.1447,48.1466],[-97.1435,48.1475],[-97.1425,48.1487],[-97.1413,48.1501],[-97.1405,48.1508],[-97.1402,48.1509],[-97.1391,48.1516],[-97.1371,48.1523],[-97.1328,48.1535],[-97.1307,48.1542],[-97.1305,48.1543],[-97.1281,48.1552],[-97.1263,48.156],[-97.1253,48.1563],[-97.1244,48.1566],[-97.1236,48.1571],[-97.1225,48.1577],[-97.1217,48.1583],[-97.1211,48.1588],[-97.121,48.1591],[-97.1209,48.1596],[-97.121,48.1608],[-97.1211,48.1612],[-97.1214,48.1615],[-97.1218,48.1617],[-97.1224,48.1621],[-97.1233,48.1625],[-97.1241,48.1627],[-97.1247,48.1628],[-97.1253,48.1629],[-97.1273,48.1628],[-97.1285,48.1626],[-97.1305,48.162],[-97.1313,48.1617],[-97.1322,48.1614],[-97.1345,48.1603],[-97.1363,48.1598],[-97.1385,48.1595],[-97.1403,48.1598],[-97.1419,48.1603],[-97.1431,48.1611],[-97.1442,48.1625],[-97.1443,48.1633],[-97.1445,48.1641],[-97.1447,48.165],[-97.1451,48.1668],[-97.1454,48.1675],[-97.1463,48.1686],[-97.1475,48.1706],[-97.1475,48.1725],[-97.1467,48.1733]]],"type":"Polygon"},"id":"60","properties":{"Area":5177876131.64875,"CTYONLY_":9,"Code":"POLK","LASTMOD":"1999-12-31T23:59:59Z","Name":"Polk","Perimiter":458889.41551},"type":"Feature"},{"geometry":{"coordinates":[[[-96.5008,48.1742],[-96.5008,48.1742],[-96.5006,48.1741],[-96.5003,48.1741],[-96.4973,48.174],[-96.4946,48.1741],[-96.4841,48.174],[-96.4791,48.1741],[-96.4789,48.1741],[-96.4773,48.1741],[-96.4735,48.174],[-96.467,48.1741],[-96.4592,48.1742],[-96.4569,48.1742],[-96.4564,48.1742],[-96.4563,48.1743],[-96.4561,48.1744],[-96.4454,48.1747],[-96.4436,48.1747],[-96.4402,48.1748],[-96.438,48.1749],[-96.4359,48.1749],[-96.4352,48.1749],[-96.4346,48.1749],[-96.4295,48.1749],[-96.4206,48.1749],[-96.4135,48.1749],[-96.4126,48.1749],[-96.4126,48.1749],[-96.4054,48.1748],[-96.3964,48.1748],[-96.3906,48.1748],[-96.3905,48.1748],[-96.3894,48.1748],[-96.3856,48.1747],[-96.38,48.1745],[-96.3781,48.1746],[-96.3753,48.1748],[-96.3728,48.1749],[-96.3706,48.175],[-96.3685,48.1751],[-96.3682,48.1751],[-96.3682,48.1751],[-96.3656,48.175],[-96.3642,48.1749],[-96.361,48.1748],[-96.3581,48.1747],[-96.3542,48.1746],[-96.351,48.1745],[-96.3477,48.1744],[-96.3473,48.1744],[-96.347,48.1743],[-96.3466,48.1743],[-96.343,48.1744],[-96.3402,48.1744],[-96.338,48.1745],[-96.3358,48.1744],[-96.3356,48.1745],[-96.3301,48.1745],[-96.3253,48.1746],[-96.3252,48.1746],[-96.3145,48.1747],[-96.3035,48.1747],[-96.3029,48.1747],[-96.2977,48.1747],[-96.2824,48.1747],[-96.2823,48.1747],[-96.2805,48.1747],[-96.2619,48.1749],[-96.2612,48.1749],[-96.2607,48.1749],[-96.2596,48.1749],[-96.2562,48.1744],[-96.252,48.174],[-96.2511,48.174],[-96.2503,48.1739],[-96.2491,48.1737],[-96.2476,48.1735],[-96.2398,48.1728],[-96.2397,48.1727],[-96.2397,48.1727],[-96.2391,48.1727],[-96.2329,48.1725],[-96.2307,48.1725],[-96.2287,48.1725],[-96.2275,48.1724],[-96.2251,48.1724],[-96.2188,48.1722],[-96.2179,48.1722],[-96.2177,48.1722],[-96.2076,48.1722],[-96.2072,48.1722],[-96.2038,48.1722],[-96.2023,48.1722],[-96.1963,48.1721],[-96.1959,48.1721],[-96.1954,48.1721],[-96.1948,48.1721],[-96.191,48.1721],[-96.1874,48.1721],[-96.1834,48.172],[-96.1827,48.1722],[-96.1813,48.1725],[-96.1741,48.1736],[-96.1737,48.1736],[-96.1736,48.1736],[-96.1641,48.1736],[-96.1625,48.1736],[-96.1518,48.1736],[-96.1516,48.1736],[-96.1388,48.1732],[-96.1302,48.173],[-96.1298,48.173],[-96.1297,48.173],[-96.1253,48.1727],[-96.1189,48.1722],[-96.1176,48.1722],[-96.1084,48.1718],[-96.1084,48.1718],[-96.0979,48.172],[-96.09,48.172],[-96.09,48.172],[-96.079,48.1721],[-96.0685,48.1721],[-96.0685,48.1721],[-96.0592,48.1721],[-96.0468,48.1722],[-96.0468,48.1722],[-96.0254,48.1721],[-96.025,48.1721],[-96.0171,48.172],[-96.0101,48.1718],[-96.0047,48.1717],[-96.0036,48.1718],[-96.0035,48.1718],[-96.0032,48.1718],[-96.0028,48.1718],[-96.0023,48.1718],[-96.0003,48.1717],[-95.9956,48.1717],[-95.9819,48.1717],[-95.9817,48.1717],[-95.9651,48.1718],[-95.961,48.1718],[-95.9609,48.1718],[-95.9608,48.1718],[-95.9394,48.1719],[-95.9392,48.1719],[-95.9178,48.1719],[-95.9178,48.1719],[-95.9176,48.1719],[-95.896,48.172],[-95.8958,48.172],[-95.8752,48.172],[-95.8744,48.172],[-95.8744,48.172],[-95.8527,48.1721],[-95.8525,48.1721],[-95.8499,48.1721],[-95.8308,48.1722],[-95.8308,48.1722],[-95.8305,48.1722],[-95.8091,48.1722],[-95.809,48.1722],[-95.8088,48.1722],[-95.7874,48.1725],[-95.7657,48.1728],[-95.7657,48.1728],[-95.7502,48.1727],[-95.7443,48.1727],[-95.744,48.1727],[-95.7227,48.1731],[-95.7226,48.1731],[-95.7157,48.1731],[-95.7128,48.173],[-95.7022,48.1729],[-95.7021,48.1729],[-95.702,48.1729],[-95.6803,48.1728],[-95.6802,48.1728],[-95.662,48.1729],[-95.6591,48.1729],[-95.6376,48.173],[-95.6376,48.173],[-95.6279,48.1731],[-95.6252,48.1731],[-95.6163,48.1731],[-95.6159,48.1731],[-95.5941,48.173],[-95.5939,48.173],[-95.5939,48.1658],[-95.5938,48.1512],[-95.5936,48.1368],[-95.5931,48.1223],[-95.593,48.1078],[-95.5928,48.0931],[-95.5926,48.0787],[-95.5925,48.0642],[-95.5925,48.0497],[-95.5923,48.035],[-95.5922,48.0207],[-95.5828,48.0207],[-95.5825,48.0063],[-95.5824,47.9917],[-95.5825,47.9771],[-95.5826,47.9629],[-95.5825,47.9482],[-95.5824,47.9339],[-95.6034,47.9341],[-95.6252,47.9344],[-95.6466,47.9348],[-95.6683,47.9351],[-95.6898,47.9354],[-95.7096,47.9355],[-95.7097,47.9499],[-95.7098,47.9644],[-95.7312,47.9644],[-95.7531,47.9645],[-95.7747,47.9646],[-95.7963,47.9647],[-95.8181,47.9647],[-95.8383,47.9648],[-95.86,47.9649],[-95.8814,47.9648],[-95.9031,47.9648],[-95.925,47.9647],[-95.9462,47.9646],[-95.9671,47.9646],[-95.9887,47.9642],[-96.0106,47.9641],[-96.0324,47.964],[-96.054,47.9638],[-96.0757,47.9637],[-96.096,47.9638],[-96.1173,47.9632],[-96.1389,47.9631],[-96.1606,47.9631],[-96.1826,47.9632],[-96.2044,47.963],[-96.2235,47.9629],[-96.2453,47.9629],[-96.2667,47.9629],[-96.2883,47.963],[-96.31,47.9633],[-96.3316,47.9634],[-96.3526,47.9634],[-96.3738,47.9636],[-96.3954,47.9636],[-96.4172,47.9637],[-96.439,47.9636],[-96.4603,47.9639],[-96.4823,47.9636],[-96.4823,47.9782],[-96.4824,47.9924],[-96.4826,48.0072],[-96.4826,48.0217],[-96.5009,48.0217],[-96.5009,48.0362],[-96.5008,48.0506],[-96.5009,48.0654],[-96.5009,48.0798],[-96.5009,48.0943],[-96.501,48.1089],[-96.5007,48.1234],[-96.5006,48.1379],[-96.5008,48.1524],[-96.5008,48.1669],[-96.5008,48.1742]]],"type":"Polygon"},"id":"57","properties":{"Area":1601102945.98836,"CTYONLY_":10,"Code":"PENN","LASTMOD":"2006-07-04T12:00:00Z","Name":"Pennington","Perimiter":190039.7415},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&sortby=-LASTMOD","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&sortby=-LASTMOD","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=9&sortby=-LASTMOD","rel":"next","title":"next page","type":"application/geo+json"}],"numberMatched":117,"numberReturned":9,"type":"FeatureCollection"} diff --git a/msautotest/api/expected/ogcapi_sorted_plus.json.txt b/msautotest/api/expected/ogcapi_sorted_plus.json.txt new file mode 100644 index 0000000000..9d12144745 --- /dev/null +++ b/msautotest/api/expected/ogcapi_sorted_plus.json.txt @@ -0,0 +1,9 @@ +Content-Type: application/geo+json +Content-Crs: +Link: ; rel="self"; title="Items for this collection as GeoJSON"; type="application/geo+json" +Link: ; rel="alternate"; title="Items for this collection as HTML"; type="text/html" +Link: ; rel="next"; title="next page"; type="application/geo+json" +OGC-NumberMatched: 117 +OGC-NumberReturned: 9 + +{"features":[{"geometry":{"coordinates":[[[-95.3231,48.999],[-95.3109,48.999],[-95.2889,48.9989],[-95.2852,48.9989],[-95.2669,48.9989],[-95.245,48.9989],[-95.2232,48.9989],[-95.2014,48.9989],[-95.1792,48.9989],[-95.1574,48.9989],[-95.1531,48.9989],[-95.1531,49.0031],[-95.1532,49.0179],[-95.1532,49.0325],[-95.1532,49.047],[-95.1532,49.0619],[-95.1532,49.0765],[-95.1532,49.0911],[-95.1532,49.1057],[-95.1532,49.1205],[-95.1532,49.1354],[-95.1532,49.1499],[-95.1532,49.1642],[-95.1532,49.1788],[-95.1532,49.1807],[-95.1532,49.1931],[-95.1532,49.1966],[-95.1532,49.2077],[-95.1533,49.2131],[-95.1533,49.2219],[-95.1533,49.2308],[-95.1533,49.2365],[-95.1533,49.2472],[-95.1533,49.2512],[-95.1533,49.2655],[-95.1533,49.2697],[-95.1533,49.2802],[-95.1533,49.2882],[-95.1533,49.2945],[-95.1533,49.3072],[-95.1533,49.309],[-95.1533,49.3234],[-95.1533,49.3237],[-95.1533,49.3381],[-95.1533,49.3476],[-95.1533,49.3525],[-95.1533,49.3636],[-95.1533,49.367],[-95.1533,49.3705],[-95.1533,49.3776],[-95.1533,49.3813],[-95.1533,49.3845],[-95.1503,49.383],[-95.1499,49.3813],[-95.1498,49.3807],[-95.1467,49.3802],[-95.145,49.3784],[-95.1418,49.3784],[-95.1397,49.3762],[-95.1367,49.3751],[-95.1324,49.3736],[-95.1287,49.3705],[-95.1171,49.367],[-95.1159,49.3666],[-95.1145,49.3666],[-95.1098,49.3664],[-95.1031,49.3652],[-95.1031,49.3636],[-95.0926,49.3617],[-95.0897,49.3612],[-95.0707,49.3564],[-95.0582,49.3533],[-95.0495,49.3532],[-95.0479,49.3533],[-95.0262,49.3554],[-95.0141,49.3565],[-95.0047,49.3612],[-94.993,49.367],[-94.9889,49.369],[-94.9818,49.3684],[-94.9742,49.3678],[-94.9597,49.3699],[-94.9573,49.3702],[-94.952,49.3688],[-94.948,49.367],[-94.9376,49.3625],[-94.9152,49.3529],[-94.9143,49.3524],[-94.909,49.3502],[-94.9065,49.3484],[-94.8933,49.3414],[-94.8865,49.3378],[-94.8782,49.3334],[-94.8712,49.3308],[-94.854,49.3244],[-94.8492,49.3244],[-94.8363,49.3243],[-94.8311,49.3236],[-94.8271,49.323],[-94.8162,49.3214],[-94.8243,49.309],[-94.8243,49.3088],[-94.8255,49.2944],[-94.8255,49.2943],[-94.8204,49.28],[-94.8152,49.2653],[-94.8103,49.2515],[-94.8059,49.2388],[-94.8051,49.2367],[-94.8001,49.2224],[-94.7973,49.2144],[-94.7975,49.2079],[-94.7979,49.1979],[-94.7965,49.1936],[-94.7918,49.1792],[-94.7871,49.1646],[-94.7833,49.153],[-94.7823,49.15],[-94.7776,49.1357],[-94.7727,49.1206],[-94.7727,49.1206],[-94.7611,49.1096],[-94.7571,49.1058],[-94.7496,49.0988],[-94.7474,49.0918],[-94.7429,49.0773],[-94.7394,49.0657],[-94.7385,49.063],[-94.7344,49.0497],[-94.7299,49.0351],[-94.7254,49.0205],[-94.7207,49.0052],[-94.7184,48.9979],[-94.7162,48.9907],[-94.7117,48.9761],[-94.7072,48.9615],[-94.7027,48.9468],[-94.6982,48.9322],[-94.6968,48.9276],[-94.6844,48.8875],[-94.6834,48.8842],[-94.6842,48.8724],[-94.6855,48.8719],[-94.6923,48.8691],[-94.6902,48.8636],[-94.6914,48.8591],[-94.693,48.8535],[-94.6881,48.8447],[-94.6855,48.8401],[-94.6963,48.836],[-94.6975,48.8355],[-94.702,48.8319],[-94.7025,48.8302],[-94.7042,48.8243],[-94.6991,48.8159],[-94.6962,48.8111],[-94.6951,48.8092],[-94.6958,48.8012],[-94.6959,48.7997],[-94.6944,48.7895],[-94.6934,48.7864],[-94.6909,48.7781],[-94.687,48.7752],[-94.6776,48.772],[-94.6768,48.7717],[-94.6746,48.7705],[-94.6671,48.7662],[-94.6603,48.7605],[-94.6557,48.7581],[-94.6525,48.7565],[-94.652,48.7562],[-94.6453,48.7491],[-94.6453,48.7441],[-94.6443,48.7434],[-94.6414,48.7413],[-94.631,48.7392],[-94.6301,48.739],[-94.6191,48.7373],[-94.6106,48.7318],[-94.6084,48.731],[-94.6028,48.7289],[-94.6011,48.7283],[-94.5962,48.7248],[-94.5913,48.7197],[-94.5876,48.7176],[-94.5867,48.7175],[-94.5685,48.7156],[-94.5622,48.7159],[-94.5558,48.7163],[-94.549,48.7148],[-94.5487,48.7146],[-94.5457,48.7124],[-94.5396,48.7036],[-94.539,48.7028],[-94.5329,48.7013],[-94.5247,48.7016],[-94.5178,48.7008],[-94.5173,48.7008],[-94.5093,48.7006],[-94.5066,48.6999],[-94.4996,48.698],[-94.4958,48.698],[-94.4863,48.698],[-94.4739,48.6969],[-94.4706,48.6966],[-94.4631,48.6953],[-94.4568,48.6933],[-94.4523,48.6925],[-94.4517,48.6925],[-94.4465,48.693],[-94.4388,48.6949],[-94.4319,48.6998],[-94.4299,48.7012],[-94.4299,48.6998],[-94.43,48.6852],[-94.4301,48.6708],[-94.43,48.6564],[-94.4297,48.642],[-94.4294,48.6276],[-94.4292,48.6133],[-94.4289,48.5988],[-94.4289,48.5844],[-94.4291,48.5698],[-94.4295,48.5554],[-94.43,48.5409],[-94.4303,48.5264],[-94.4303,48.512],[-94.4299,48.4977],[-94.4296,48.4832],[-94.4296,48.4688],[-94.4293,48.4543],[-94.4292,48.4399],[-94.4293,48.4254],[-94.4294,48.411],[-94.4293,48.3964],[-94.4289,48.3821],[-94.4288,48.3675],[-94.4471,48.3675],[-94.4505,48.3675],[-94.4688,48.3675],[-94.4722,48.3674],[-94.4906,48.3674],[-94.4924,48.3674],[-94.4941,48.3674],[-94.5118,48.3675],[-94.5157,48.3674],[-94.5335,48.3674],[-94.5378,48.3674],[-94.5536,48.3674],[-94.5593,48.3674],[-94.5754,48.3674],[-94.5812,48.3674],[-94.5971,48.3675],[-94.6029,48.3674],[-94.6188,48.3673],[-94.6245,48.3673],[-94.6405,48.3673],[-94.6465,48.3673],[-94.6505,48.3673],[-94.6622,48.3673],[-94.6679,48.3673],[-94.6694,48.3672],[-94.683,48.3671],[-94.6898,48.3671],[-94.7099,48.3669],[-94.7117,48.3668],[-94.7315,48.3669],[-94.7329,48.3669],[-94.7533,48.3669],[-94.7549,48.3669],[-94.7748,48.3669],[-94.7765,48.3669],[-94.7967,48.3669],[-94.7983,48.3669],[-94.8183,48.3669],[-94.8199,48.3669],[-94.8399,48.3669],[-94.8416,48.3669],[-94.8616,48.3667],[-94.8632,48.3667],[-94.8833,48.3667],[-94.8849,48.3666],[-94.9049,48.3666],[-94.9065,48.3666],[-94.9264,48.3667],[-94.9283,48.3667],[-94.9469,48.3666],[-94.95,48.3666],[-94.9684,48.3667],[-94.9716,48.3667],[-94.9901,48.3667],[-94.9932,48.3667],[-95.0119,48.3665],[-95.0153,48.3665],[-95.0337,48.3665],[-95.0369,48.3665],[-95.0555,48.3665],[-95.0586,48.3665],[-95.0773,48.3664],[-95.0801,48.3664],[-95.099,48.3663],[-95.1008,48.3663],[-95.1018,48.3663],[-95.1207,48.3663],[-95.1236,48.3663],[-95.1315,48.3662],[-95.1424,48.3662],[-95.1454,48.3662],[-95.164,48.3661],[-95.1669,48.3661],[-95.1861,48.3661],[-95.1887,48.3661],[-95.1983,48.3661],[-95.2066,48.3661],[-95.2106,48.3661],[-95.211,48.3797],[-95.211,48.3808],[-95.2111,48.3941],[-95.2111,48.3952],[-95.2112,48.4087],[-95.2112,48.4096],[-95.2113,48.4232],[-95.2113,48.4242],[-95.2113,48.4255],[-95.2113,48.4376],[-95.2113,48.4387],[-95.2113,48.4522],[-95.2112,48.4529],[-95.211,48.4666],[-95.211,48.4673],[-95.2111,48.4816],[-95.2112,48.4962],[-95.2111,48.5101],[-95.2111,48.5109],[-95.2115,48.5244],[-95.2115,48.5252],[-95.2119,48.54],[-95.2324,48.5399],[-95.2339,48.5399],[-95.2537,48.5398],[-95.2554,48.5398],[-95.2756,48.54],[-95.2773,48.54],[-95.2975,48.5401],[-95.2992,48.5402],[-95.3194,48.54],[-95.321,48.54],[-95.3412,48.5402],[-95.3425,48.5402],[-95.3424,48.5548],[-95.3423,48.5691],[-95.3423,48.5836],[-95.3426,48.5979],[-95.3424,48.6127],[-95.3426,48.6271],[-95.3425,48.6415],[-95.3424,48.6561],[-95.3423,48.6705],[-95.3424,48.6849],[-95.3425,48.6995],[-95.3425,48.7131],[-95.3302,48.713],[-95.3205,48.713],[-95.3084,48.713],[-95.3051,48.713],[-95.299,48.713],[-95.2866,48.713],[-95.2767,48.713],[-95.2656,48.713],[-95.2645,48.713],[-95.255,48.713],[-95.2427,48.713],[-95.2331,48.713],[-95.2206,48.713],[-95.2112,48.713],[-95.1991,48.713],[-95.1917,48.713],[-95.1773,48.713],[-95.1697,48.7129],[-95.1554,48.7129],[-95.1477,48.7129],[-95.1333,48.713],[-95.1297,48.713],[-95.1259,48.7129],[-95.1119,48.7129],[-95.1104,48.7129],[-95.1046,48.7129],[-95.0898,48.713],[-95.0899,48.7277],[-95.0901,48.7421],[-95.0901,48.7566],[-95.0903,48.7711],[-95.0903,48.7855],[-95.0903,48.8],[-95.0909,48.8147],[-95.0908,48.8291],[-95.0907,48.8436],[-95.0908,48.858],[-95.0908,48.8724],[-95.0911,48.8869],[-95.0912,48.9014],[-95.0914,48.916],[-95.0914,48.9208],[-95.0919,48.9207],[-95.0927,48.9204],[-95.0944,48.9193],[-95.0946,48.9191],[-95.0961,48.9181],[-95.097,48.9176],[-95.0971,48.9172],[-95.0975,48.9164],[-95.098,48.916],[-95.0981,48.9159],[-95.1008,48.9142],[-95.102,48.9132],[-95.1032,48.9127],[-95.1042,48.9121],[-95.1056,48.9113],[-95.108,48.9099],[-95.1096,48.9089],[-95.1107,48.9082],[-95.1126,48.9073],[-95.113,48.9072],[-95.1132,48.9071],[-95.1137,48.9069],[-95.1141,48.9064],[-95.114,48.9061],[-95.1144,48.9052],[-95.1151,48.9046],[-95.1163,48.9037],[-95.1182,48.9029],[-95.1204,48.9019],[-95.1205,48.9017],[-95.121,48.9016],[-95.1214,48.9013],[-95.1228,48.9006],[-95.1233,48.9004],[-95.1239,48.9001],[-95.1252,48.8998],[-95.1312,48.8975],[-95.1322,48.8973],[-95.1337,48.8969],[-95.1343,48.8963],[-95.1348,48.8963],[-95.1351,48.8963],[-95.1355,48.8959],[-95.1381,48.8949],[-95.1404,48.8943],[-95.1436,48.8937],[-95.1438,48.8934],[-95.1459,48.8929],[-95.1469,48.8927],[-95.1483,48.8923],[-95.1508,48.8922],[-95.1528,48.8921],[-95.1555,48.892],[-95.1564,48.8919],[-95.1579,48.8919],[-95.1602,48.892],[-95.1618,48.892],[-95.1641,48.8917],[-95.1648,48.8913],[-95.1674,48.8907],[-95.1701,48.8902],[-95.173,48.8897],[-95.1764,48.8893],[-95.1791,48.889],[-95.1797,48.889],[-95.1819,48.8888],[-95.1851,48.8882],[-95.1863,48.8877],[-95.1877,48.8874],[-95.1889,48.8873],[-95.1901,48.887],[-95.1913,48.8868],[-95.1919,48.8866],[-95.1924,48.8865],[-95.1956,48.8862],[-95.1986,48.8855],[-95.2005,48.8856],[-95.2009,48.8855],[-95.2024,48.8852],[-95.2059,48.8848],[-95.2085,48.8846],[-95.2112,48.8848],[-95.2115,48.8847],[-95.2117,48.8847],[-95.2122,48.8842],[-95.2144,48.8843],[-95.2151,48.884],[-95.2159,48.8839],[-95.217,48.8835],[-95.2188,48.8835],[-95.2193,48.8832],[-95.22,48.8831],[-95.2207,48.8831],[-95.2208,48.8831],[-95.2212,48.883],[-95.2252,48.8819],[-95.2265,48.8816],[-95.2287,48.8815],[-95.231,48.8814],[-95.2335,48.8814],[-95.2356,48.8815],[-95.2381,48.8817],[-95.2391,48.8819],[-95.2407,48.8821],[-95.2423,48.8821],[-95.2429,48.8822],[-95.2429,48.8822],[-95.2439,48.8823],[-95.2458,48.8829],[-95.2472,48.8835],[-95.248,48.8836],[-95.2485,48.8832],[-95.2496,48.8834],[-95.2502,48.8835],[-95.2507,48.8836],[-95.2517,48.8839],[-95.2548,48.8845],[-95.256,48.885],[-95.257,48.8858],[-95.2585,48.8867],[-95.2585,48.8867],[-95.2627,48.8877],[-95.2635,48.888],[-95.2639,48.8883],[-95.2646,48.8885],[-95.265,48.8886],[-95.2654,48.8888],[-95.2666,48.8894],[-95.2674,48.89],[-95.2677,48.8903],[-95.268,48.8905],[-95.2713,48.8915],[-95.2724,48.8921],[-95.2745,48.8931],[-95.2751,48.8938],[-95.2753,48.8943],[-95.2748,48.8951],[-95.2749,48.8956],[-95.2755,48.8959],[-95.2759,48.8962],[-95.2763,48.8963],[-95.2765,48.8962],[-95.277,48.8958],[-95.2773,48.8957],[-95.2782,48.8956],[-95.279,48.8957],[-95.2796,48.8962],[-95.2803,48.8965],[-95.2813,48.8967],[-95.2839,48.8975],[-95.2853,48.8977],[-95.2861,48.8976],[-95.2865,48.8975],[-95.287,48.8976],[-95.2872,48.8977],[-95.2879,48.8979],[-95.2882,48.8981],[-95.289,48.8994],[-95.2896,48.9],[-95.2901,48.9003],[-95.2911,48.9006],[-95.2911,48.9008],[-95.2906,48.9011],[-95.2907,48.9014],[-95.2908,48.9016],[-95.2909,48.9017],[-95.2914,48.9019],[-95.2927,48.9019],[-95.2935,48.902],[-95.2937,48.9023],[-95.2941,48.9027],[-95.2949,48.9028],[-95.2967,48.9027],[-95.2976,48.9026],[-95.298,48.9027],[-95.2983,48.9028],[-95.2993,48.9035],[-95.3005,48.904],[-95.3002,48.9045],[-95.3001,48.9046],[-95.3001,48.9047],[-95.3,48.9047],[-95.3,48.9047],[-95.2999,48.9048],[-95.2999,48.9048],[-95.2999,48.9048],[-95.2997,48.905],[-95.2996,48.9051],[-95.2994,48.9053],[-95.2992,48.9055],[-95.2991,48.9057],[-95.2989,48.906],[-95.2988,48.906],[-95.2986,48.9063],[-95.2985,48.9064],[-95.2985,48.9065],[-95.2983,48.9068],[-95.2982,48.9068],[-95.2981,48.907],[-95.298,48.9071],[-95.298,48.9071],[-95.298,48.9071],[-95.2979,48.9071],[-95.2979,48.9072],[-95.2979,48.9072],[-95.2978,48.9072],[-95.2978,48.9072],[-95.2978,48.9073],[-95.2977,48.9073],[-95.2976,48.9074],[-95.2973,48.9077],[-95.2973,48.908],[-95.2973,48.9081],[-95.2978,48.9083],[-95.2999,48.9086],[-95.3017,48.9093],[-95.3027,48.91],[-95.3038,48.9114],[-95.3043,48.9119],[-95.3059,48.9127],[-95.3061,48.9128],[-95.3064,48.9129],[-95.3074,48.9135],[-95.3078,48.9141],[-95.3085,48.9146],[-95.3092,48.9149],[-95.3093,48.9149],[-95.3102,48.9155],[-95.3109,48.9163],[-95.3115,48.9172],[-95.3119,48.9178],[-95.3126,48.919],[-95.3132,48.9198],[-95.3141,48.921],[-95.315,48.9222],[-95.3168,48.9245],[-95.3195,48.9285],[-95.3208,48.9305],[-95.3209,48.9307],[-95.3222,48.9327],[-95.3228,48.9344],[-95.3223,48.9355],[-95.3225,48.9358],[-95.3229,48.9373],[-95.3231,48.9389],[-95.3228,48.9403],[-95.3225,48.9409],[-95.3219,48.9412],[-95.3189,48.9419],[-95.3181,48.9421],[-95.3168,48.9431],[-95.3154,48.9448],[-95.3148,48.9452],[-95.3141,48.9457],[-95.3131,48.946],[-95.3114,48.9461],[-95.3102,48.9463],[-95.3095,48.9463],[-95.3088,48.9464],[-95.3086,48.9465],[-95.3086,48.9469],[-95.3085,48.947],[-95.3078,48.9466],[-95.3074,48.9465],[-95.3071,48.9466],[-95.3071,48.9469],[-95.3079,48.9474],[-95.3092,48.9477],[-95.3096,48.9478],[-95.3103,48.948],[-95.3104,48.9484],[-95.3103,48.9485],[-95.31,48.9485],[-95.3099,48.9484],[-95.3096,48.9482],[-95.3094,48.9481],[-95.3081,48.948],[-95.3071,48.9477],[-95.3062,48.9472],[-95.3062,48.9472],[-95.3061,48.9469],[-95.3062,48.9463],[-95.3063,48.9462],[-95.3069,48.9456],[-95.3069,48.9455],[-95.3068,48.9454],[-95.3061,48.9454],[-95.3053,48.9459],[-95.305,48.9462],[-95.3046,48.947],[-95.3046,48.9482],[-95.3052,48.9495],[-95.3061,48.9502],[-95.3079,48.9509],[-95.3089,48.9511],[-95.3097,48.951],[-95.3104,48.951],[-95.3108,48.9512],[-95.3115,48.952],[-95.312,48.9524],[-95.3126,48.9524],[-95.3129,48.9523],[-95.3129,48.9521],[-95.3119,48.9507],[-95.3119,48.9502],[-95.3123,48.9502],[-95.3125,48.9503],[-95.3131,48.9503],[-95.3141,48.9508],[-95.3151,48.951],[-95.3154,48.9513],[-95.3177,48.9525],[-95.3181,48.9531],[-95.3182,48.9535],[-95.3177,48.9545],[-95.3175,48.9552],[-95.3179,48.9559],[-95.3188,48.9562],[-95.3191,48.9569],[-95.3202,48.9581],[-95.3206,48.959],[-95.3206,48.9595],[-95.3206,48.9598],[-95.3202,48.9606],[-95.3193,48.9622],[-95.3193,48.964],[-95.3198,48.9643],[-95.3201,48.9648],[-95.3207,48.9669],[-95.3212,48.9672],[-95.3227,48.9685],[-95.3232,48.9692],[-95.3241,48.9703],[-95.3247,48.972],[-95.3248,48.9728],[-95.3249,48.9738],[-95.325,48.9743],[-95.3253,48.976],[-95.3257,48.9784],[-95.3255,48.9789],[-95.3256,48.98],[-95.3257,48.9814],[-95.3253,48.9832],[-95.3245,48.985],[-95.3242,48.9859],[-95.3227,48.9884],[-95.3224,48.9889],[-95.3206,48.9921],[-95.3204,48.9924],[-95.3191,48.9941],[-95.3181,48.995],[-95.3178,48.9958],[-95.3178,48.9961],[-95.3179,48.9961],[-95.3182,48.996],[-95.3187,48.9956],[-95.3191,48.9953],[-95.3197,48.9954],[-95.3201,48.9956],[-95.3206,48.9961],[-95.3204,48.9964],[-95.3202,48.9973],[-95.3204,48.9976],[-95.3224,48.9984],[-95.3231,48.999]]],"type":"Polygon"},"id":"39","properties":{"Area":4608320923.49768,"CTYONLY_":2,"Code":"LOTW","LASTMOD":"1976-07-04T12:00:00Z","Name":"Lake of the Woods","Perimiter":388250.14572},"type":"Feature"},{"geometry":{"coordinates":[[[-96.4054,49.0001],[-96.4054,48.9947],[-96.4054,48.994],[-96.4054,48.9803],[-96.4054,48.9793],[-96.4053,48.9705],[-96.4053,48.9658],[-96.4053,48.9648],[-96.4053,48.9515],[-96.4053,48.9504],[-96.4053,48.9371],[-96.4053,48.936],[-96.4054,48.9225],[-96.4054,48.9214],[-96.4053,48.9137],[-96.4053,48.9081],[-96.4053,48.9068],[-96.405,48.8926],[-96.405,48.878],[-96.4047,48.8635],[-96.4045,48.8491],[-96.4043,48.8343],[-96.4042,48.8198],[-96.4042,48.8048],[-96.4042,48.7903],[-96.4045,48.7758],[-96.4047,48.7607],[-96.4048,48.7465],[-96.4048,48.7318],[-96.4049,48.7172],[-96.388,48.7172],[-96.3873,48.7172],[-96.3866,48.703],[-96.3874,48.6887],[-96.3871,48.6741],[-96.3877,48.6599],[-96.3879,48.6454],[-96.388,48.6313],[-96.389,48.6165],[-96.3891,48.6024],[-96.3884,48.5877],[-96.3882,48.5733],[-96.3879,48.5588],[-96.3882,48.5442],[-96.4101,48.544],[-96.4318,48.5438],[-96.4535,48.5436],[-96.4754,48.5435],[-96.4973,48.5434],[-96.518,48.5434],[-96.54,48.5434],[-96.5621,48.5436],[-96.5839,48.5437],[-96.6058,48.5437],[-96.6278,48.5437],[-96.6493,48.5437],[-96.6713,48.5436],[-96.6931,48.5437],[-96.7151,48.5437],[-96.7368,48.5437],[-96.7585,48.5436],[-96.7803,48.5435],[-96.8023,48.5436],[-96.824,48.5436],[-96.8459,48.5434],[-96.8678,48.5433],[-96.8896,48.5433],[-96.9115,48.5432],[-96.9138,48.5433],[-96.9331,48.5435],[-96.9551,48.5437],[-96.9768,48.544],[-96.9985,48.5441],[-97.0194,48.5441],[-97.0416,48.5442],[-97.0635,48.5441],[-97.0852,48.5441],[-97.107,48.544],[-97.1287,48.5439],[-97.1509,48.5439],[-97.1631,48.544],[-97.1637,48.5445],[-97.1659,48.5483],[-97.1662,48.5509],[-97.1661,48.5527],[-97.1654,48.5536],[-97.1645,48.554],[-97.1628,48.5543],[-97.1613,48.5539],[-97.1592,48.5528],[-97.1577,48.5518],[-97.1557,48.5512],[-97.1538,48.5513],[-97.1513,48.5515],[-97.1507,48.5515],[-97.1493,48.5516],[-97.1474,48.5516],[-97.1444,48.5514],[-97.1407,48.5515],[-97.1387,48.5522],[-97.1379,48.553],[-97.1379,48.5542],[-97.1391,48.5554],[-97.141,48.5566],[-97.1426,48.5571],[-97.1464,48.5573],[-97.1505,48.5574],[-97.1515,48.5574],[-97.1551,48.5574],[-97.1578,48.5573],[-97.1606,48.5571],[-97.1631,48.5571],[-97.1646,48.5572],[-97.167,48.5575],[-97.1697,48.5584],[-97.1721,48.5591],[-97.1727,48.5593],[-97.174,48.5599],[-97.1749,48.5606],[-97.1753,48.5614],[-97.1754,48.5623],[-97.1749,48.5631],[-97.1744,48.5639],[-97.1723,48.5648],[-97.1721,48.5648],[-97.1706,48.5652],[-97.1687,48.5655],[-97.167,48.5658],[-97.1651,48.5659],[-97.1613,48.5661],[-97.1541,48.5669],[-97.153,48.5671],[-97.1516,48.5677],[-97.1503,48.5688],[-97.1496,48.5695],[-97.1487,48.5707],[-97.1477,48.5727],[-97.1477,48.5728],[-97.1476,48.5731],[-97.1483,48.5763],[-97.15,48.5775],[-97.1501,48.5775],[-97.1548,48.5779],[-97.1592,48.5785],[-97.1605,48.58],[-97.16,48.5816],[-97.1578,48.5826],[-97.1562,48.5828],[-97.1541,48.5826],[-97.1524,48.5823],[-97.15,48.5815],[-97.1494,48.5813],[-97.1484,48.5811],[-97.1449,48.5815],[-97.1436,48.5824],[-97.1431,48.5834],[-97.1429,48.5838],[-97.142,48.5876],[-97.1418,48.5886],[-97.1415,48.5909],[-97.1422,48.5926],[-97.1433,48.5936],[-97.1451,48.594],[-97.1471,48.594],[-97.1497,48.5937],[-97.1525,48.594],[-97.1536,48.5949],[-97.1535,48.5957],[-97.1527,48.5962],[-97.1524,48.5969],[-97.1516,48.598],[-97.1498,48.5981],[-97.1497,48.5981],[-97.1463,48.5977],[-97.1443,48.5981],[-97.143,48.5987],[-97.1416,48.6002],[-97.1403,48.6021],[-97.14,48.6025],[-97.138,48.6044],[-97.1359,48.6054],[-97.1345,48.6065],[-97.1341,48.6075],[-97.1349,48.6082],[-97.1358,48.6086],[-97.137,48.6088],[-97.1396,48.6086],[-97.1443,48.6078],[-97.1474,48.6081],[-97.1494,48.6089],[-97.1495,48.609],[-97.1505,48.6115],[-97.1501,48.6124],[-97.1493,48.6129],[-97.1478,48.6138],[-97.145,48.6146],[-97.1408,48.6149],[-97.137,48.6144],[-97.134,48.6136],[-97.1319,48.6133],[-97.1309,48.6137],[-97.1289,48.614],[-97.1286,48.6153],[-97.1293,48.6168],[-97.1295,48.617],[-97.1311,48.6184],[-97.1342,48.6199],[-97.1353,48.6212],[-97.1346,48.6224],[-97.133,48.6228],[-97.131,48.6227],[-97.1291,48.6222],[-97.1277,48.6212],[-97.1274,48.621],[-97.1259,48.6195],[-97.1253,48.619],[-97.1243,48.6183],[-97.1231,48.6178],[-97.1216,48.6176],[-97.12,48.6178],[-97.1193,48.6182],[-97.1186,48.6191],[-97.1183,48.6198],[-97.1186,48.6209],[-97.1198,48.6221],[-97.1209,48.6232],[-97.1212,48.6233],[-97.122,48.624],[-97.1228,48.6245],[-97.1236,48.625],[-97.1241,48.6254],[-97.1245,48.6257],[-97.1249,48.6259],[-97.1253,48.6261],[-97.126,48.6264],[-97.1266,48.6266],[-97.1272,48.627],[-97.1279,48.6273],[-97.1288,48.6278],[-97.1296,48.6282],[-97.1302,48.6288],[-97.1305,48.6292],[-97.1307,48.6297],[-97.131,48.6303],[-97.131,48.6304],[-97.131,48.6308],[-97.131,48.6315],[-97.1309,48.6317],[-97.1307,48.6321],[-97.1304,48.6325],[-97.1301,48.6326],[-97.1297,48.6328],[-97.1293,48.6329],[-97.129,48.633],[-97.1281,48.6332],[-97.128,48.6333],[-97.1275,48.6333],[-97.1253,48.6334],[-97.1235,48.6333],[-97.1216,48.6327],[-97.1181,48.6308],[-97.1176,48.6307],[-97.115,48.6299],[-97.1133,48.63],[-97.1115,48.6303],[-97.1107,48.6308],[-97.1104,48.6309],[-97.1095,48.6315],[-97.1084,48.6327],[-97.1082,48.6344],[-97.1086,48.6363],[-97.1096,48.6389],[-97.1109,48.6407],[-97.1119,48.6416],[-97.1144,48.6433],[-97.115,48.6438],[-97.115,48.6446],[-97.1149,48.6452],[-97.1123,48.6457],[-97.1112,48.6459],[-97.1093,48.6465],[-97.1078,48.6478],[-97.1069,48.6491],[-97.1066,48.6501],[-97.1061,48.6519],[-97.1059,48.6527],[-97.1045,48.6545],[-97.1017,48.6563],[-97.0987,48.6593],[-97.0986,48.6604],[-97.0985,48.6613],[-97.0992,48.6625],[-97.1019,48.6636],[-97.106,48.663],[-97.1062,48.663],[-97.1082,48.6634],[-97.1087,48.6645],[-97.1061,48.6654],[-97.1057,48.6655],[-97.102,48.6667],[-97.1,48.668],[-97.0998,48.6714],[-97.1002,48.675],[-97.1003,48.6757],[-97.1008,48.6787],[-97.1011,48.6808],[-97.1003,48.6828],[-97.0985,48.683],[-97.0946,48.6822],[-97.0926,48.6821],[-97.0904,48.6828],[-97.0898,48.6841],[-97.0899,48.6852],[-97.091,48.6861],[-97.093,48.687],[-97.0951,48.6876],[-97.099,48.6884],[-97.1024,48.6893],[-97.103,48.6894],[-97.1059,48.6903],[-97.1064,48.6905],[-97.1086,48.6915],[-97.111,48.6939],[-97.113,48.6964],[-97.1148,48.6981],[-97.1182,48.7005],[-97.1198,48.7018],[-97.1201,48.7039],[-97.1194,48.7041],[-97.1182,48.7046],[-97.1143,48.7052],[-97.1117,48.7056],[-97.11,48.7063],[-97.1098,48.7083],[-97.1113,48.7094],[-97.1134,48.7101],[-97.1157,48.7105],[-97.1174,48.7111],[-97.119,48.7119],[-97.1212,48.7136],[-97.1223,48.716],[-97.1229,48.7168],[-97.1231,48.7172],[-97.1243,48.7192],[-97.1253,48.7201],[-97.1253,48.7203],[-97.126,48.7207],[-97.1263,48.7212],[-97.1272,48.7215],[-97.128,48.722],[-97.1282,48.7221],[-97.1288,48.7225],[-97.1297,48.7229],[-97.131,48.7233],[-97.1321,48.7238],[-97.1331,48.7242],[-97.1345,48.7248],[-97.136,48.7257],[-97.1369,48.7263],[-97.1375,48.727],[-97.1376,48.7274],[-97.1376,48.7278],[-97.1373,48.7283],[-97.137,48.7284],[-97.1365,48.7285],[-97.136,48.7287],[-97.1352,48.7287],[-97.1341,48.7289],[-97.1333,48.7291],[-97.1328,48.7292],[-97.132,48.7294],[-97.1312,48.7295],[-97.1308,48.7296],[-97.1299,48.7299],[-97.1294,48.7304],[-97.1288,48.7308],[-97.1286,48.7312],[-97.1286,48.7315],[-97.1286,48.7316],[-97.1286,48.7318],[-97.1285,48.7322],[-97.1286,48.7326],[-97.1286,48.7328],[-97.1287,48.7331],[-97.129,48.7335],[-97.1295,48.7339],[-97.1298,48.7341],[-97.1316,48.7347],[-97.1322,48.7348],[-97.1334,48.7347],[-97.1351,48.7345],[-97.1369,48.7345],[-97.1383,48.7345],[-97.1396,48.7347],[-97.1402,48.7349],[-97.1412,48.7354],[-97.1419,48.7359],[-97.1422,48.7367],[-97.1423,48.7372],[-97.1421,48.7381],[-97.1414,48.7385],[-97.1408,48.7387],[-97.1404,48.7389],[-97.1399,48.7393],[-97.1392,48.7397],[-97.1381,48.7408],[-97.1372,48.742],[-97.1366,48.7435],[-97.1365,48.745],[-97.1365,48.7459],[-97.1366,48.7466],[-97.1369,48.748],[-97.1375,48.7492],[-97.1379,48.75],[-97.1385,48.7504],[-97.1391,48.7507],[-97.1396,48.7508],[-97.1401,48.7509],[-97.141,48.751],[-97.142,48.751],[-97.143,48.7509],[-97.1444,48.7507],[-97.1457,48.7506],[-97.1466,48.7505],[-97.1476,48.7505],[-97.1491,48.7506],[-97.1497,48.7508],[-97.1503,48.7509],[-97.1515,48.7515],[-97.1521,48.752],[-97.153,48.7529],[-97.1539,48.7542],[-97.1545,48.7553],[-97.1547,48.7558],[-97.1548,48.7562],[-97.1548,48.7569],[-97.1548,48.7576],[-97.1546,48.758],[-97.1542,48.7587],[-97.1535,48.7593],[-97.1528,48.7598],[-97.1519,48.7601],[-97.1508,48.7605],[-97.1503,48.7606],[-97.1501,48.7607],[-97.1475,48.7616],[-97.1473,48.7617],[-97.1469,48.762],[-97.1462,48.7626],[-97.1461,48.7628],[-97.1459,48.7633],[-97.1456,48.7643],[-97.1456,48.765],[-97.146,48.7658],[-97.1476,48.7673],[-97.1487,48.7681],[-97.15,48.7692],[-97.1501,48.7693],[-97.1506,48.77],[-97.1512,48.7712],[-97.1519,48.7721],[-97.1525,48.7727],[-97.1529,48.7728],[-97.1559,48.7731],[-97.1567,48.7732],[-97.1578,48.7735],[-97.1582,48.7737],[-97.1587,48.7742],[-97.1589,48.7746],[-97.159,48.7751],[-97.159,48.7751],[-97.159,48.7754],[-97.1589,48.776],[-97.1584,48.7766],[-97.1579,48.7769],[-97.1573,48.7772],[-97.1557,48.7776],[-97.1544,48.7778],[-97.1534,48.778],[-97.1522,48.7783],[-97.1509,48.7787],[-97.1501,48.7789],[-97.1497,48.779],[-97.1483,48.7797],[-97.1477,48.7801],[-97.1473,48.7807],[-97.1472,48.7811],[-97.1473,48.7816],[-97.1478,48.7821],[-97.1486,48.7824],[-97.1495,48.7826],[-97.1501,48.7826],[-97.1503,48.7826],[-97.1513,48.7825],[-97.1533,48.7824],[-97.1547,48.7824],[-97.1559,48.7825],[-97.1571,48.7827],[-97.1583,48.783],[-97.1591,48.7834],[-97.1595,48.7838],[-97.1597,48.7843],[-97.1598,48.7848],[-97.1596,48.7853],[-97.1593,48.786],[-97.1591,48.7863],[-97.1586,48.7869],[-97.1577,48.7877],[-97.1574,48.7882],[-97.1573,48.7884],[-97.1572,48.7887],[-97.1571,48.7894],[-97.157,48.7895],[-97.157,48.7901],[-97.1572,48.7906],[-97.1575,48.7909],[-97.1581,48.7912],[-97.1586,48.7913],[-97.1592,48.7915],[-97.1595,48.7915],[-97.1611,48.7915],[-97.1618,48.7914],[-97.1645,48.7911],[-97.1648,48.7911],[-97.1657,48.7911],[-97.1664,48.7912],[-97.1672,48.7913],[-97.1714,48.7921],[-97.1718,48.7923],[-97.1721,48.7924],[-97.1731,48.7929],[-97.1737,48.7933],[-97.174,48.7937],[-97.1741,48.7942],[-97.1742,48.7947],[-97.1742,48.7951],[-97.1739,48.7954],[-97.1734,48.7958],[-97.1726,48.7963],[-97.1717,48.7966],[-97.1716,48.7966],[-97.171,48.7967],[-97.1701,48.7967],[-97.1688,48.7966],[-97.1673,48.7964],[-97.1665,48.7962],[-97.1654,48.7962],[-97.1648,48.7962],[-97.1638,48.7963],[-97.1631,48.7966],[-97.1625,48.7969],[-97.162,48.7974],[-97.1617,48.7979],[-97.1617,48.7984],[-97.1619,48.7988],[-97.1621,48.7994],[-97.1626,48.8001],[-97.1633,48.8007],[-97.1642,48.8011],[-97.1652,48.8014],[-97.166,48.8015],[-97.1668,48.8016],[-97.1675,48.8016],[-97.1685,48.8016],[-97.1698,48.8013],[-97.1706,48.8011],[-97.1714,48.8008],[-97.1715,48.8008],[-97.1724,48.8004],[-97.1731,48.8],[-97.1742,48.7992],[-97.175,48.7986],[-97.1754,48.7983],[-97.1757,48.798],[-97.1761,48.7977],[-97.1768,48.7974],[-97.1773,48.7973],[-97.1779,48.7972],[-97.1787,48.7972],[-97.1795,48.7972],[-97.1801,48.7973],[-97.1807,48.7975],[-97.1811,48.7978],[-97.1815,48.7982],[-97.1816,48.7986],[-97.1817,48.7991],[-97.1815,48.7995],[-97.1813,48.8],[-97.1808,48.8004],[-97.1801,48.8008],[-97.1791,48.8012],[-97.1779,48.8015],[-97.1769,48.8017],[-97.1764,48.8018],[-97.1756,48.8021],[-97.1748,48.8023],[-97.1725,48.8032],[-97.1713,48.8036],[-97.171,48.8037],[-97.1706,48.8039],[-97.1694,48.8043],[-97.1682,48.8046],[-97.1675,48.8048],[-97.1666,48.805],[-97.1655,48.8052],[-97.1638,48.8055],[-97.161,48.8059],[-97.1605,48.8061],[-97.1597,48.8064],[-97.159,48.8067],[-97.1583,48.8072],[-97.1579,48.8077],[-97.1577,48.8082],[-97.1576,48.8089],[-97.1578,48.8098],[-97.158,48.8104],[-97.1586,48.811],[-97.159,48.8111],[-97.161,48.8117],[-97.1617,48.8119],[-97.1625,48.812],[-97.1636,48.8121],[-97.1644,48.8121],[-97.1651,48.812],[-97.1666,48.8118],[-97.168,48.8116],[-97.169,48.8114],[-97.17,48.8114],[-97.1713,48.8115],[-97.1715,48.8115],[-97.1726,48.8117],[-97.1731,48.8118],[-97.174,48.8122],[-97.1761,48.8132],[-97.1776,48.8141],[-97.1784,48.8145],[-97.1797,48.8149],[-97.1807,48.8151],[-97.1821,48.8153],[-97.1828,48.8153],[-97.184,48.8152],[-97.1848,48.8151],[-97.186,48.8147],[-97.1868,48.8145],[-97.1873,48.8143],[-97.1879,48.8143],[-97.1883,48.8143],[-97.1889,48.8143],[-97.1894,48.8144],[-97.1898,48.8146],[-97.1901,48.8148],[-97.1903,48.8153],[-97.1904,48.8156],[-97.1903,48.8159],[-97.19,48.8163],[-97.1893,48.8167],[-97.1885,48.8171],[-97.1879,48.8173],[-97.1866,48.8176],[-97.1857,48.8177],[-97.1847,48.8179],[-97.184,48.8181],[-97.1833,48.8184],[-97.1817,48.8189],[-97.1809,48.8193],[-97.1801,48.8199],[-97.1793,48.8207],[-97.1787,48.8216],[-97.178,48.8232],[-97.1777,48.824],[-97.1776,48.8245],[-97.1777,48.8249],[-97.178,48.8255],[-97.1782,48.8258],[-97.1786,48.8262],[-97.1794,48.8268],[-97.1822,48.8288],[-97.1837,48.8299],[-97.1841,48.8304],[-97.1847,48.8314],[-97.1848,48.8319],[-97.1849,48.8326],[-97.1849,48.8327],[-97.1848,48.833],[-97.1846,48.8336],[-97.1842,48.8341],[-97.1837,48.8345],[-97.183,48.8348],[-97.1822,48.835],[-97.1813,48.8351],[-97.1799,48.8352],[-97.1783,48.8353],[-97.1779,48.8354],[-97.1772,48.8356],[-97.1757,48.8362],[-97.1753,48.8364],[-97.1747,48.8369],[-97.1742,48.8373],[-97.1739,48.8378],[-97.1738,48.8384],[-97.1738,48.839],[-97.1739,48.8406],[-97.1743,48.8427],[-97.1747,48.8438],[-97.175,48.8442],[-97.1755,48.8447],[-97.1761,48.8452],[-97.1767,48.8455],[-97.1771,48.8456],[-97.1779,48.8458],[-97.1795,48.8459],[-97.1808,48.846],[-97.1817,48.8462],[-97.1823,48.8464],[-97.1827,48.8468],[-97.1829,48.847],[-97.1829,48.8471],[-97.1829,48.8473],[-97.1826,48.8476],[-97.1821,48.8479],[-97.1816,48.848],[-97.1809,48.8481],[-97.1793,48.8482],[-97.178,48.8483],[-97.1767,48.8484],[-97.1759,48.8486],[-97.1753,48.8487],[-97.1747,48.849],[-97.1742,48.8493],[-97.1737,48.8497],[-97.1733,48.8502],[-97.173,48.8506],[-97.173,48.8508],[-97.173,48.8511],[-97.173,48.8516],[-97.1732,48.8522],[-97.1737,48.8527],[-97.1746,48.8534],[-97.1771,48.855],[-97.1784,48.8561],[-97.1786,48.8563],[-97.179,48.8569],[-97.1793,48.8576],[-97.1794,48.8583],[-97.1794,48.859],[-97.1792,48.8606],[-97.179,48.8615],[-97.179,48.862],[-97.1791,48.8626],[-97.1794,48.863],[-97.1801,48.8636],[-97.1811,48.864],[-97.1818,48.8641],[-97.1827,48.8641],[-97.1839,48.864],[-97.1855,48.8637],[-97.1871,48.8633],[-97.1877,48.8631],[-97.1883,48.8631],[-97.1891,48.8631],[-97.1896,48.8633],[-97.19,48.8635],[-97.1903,48.8639],[-97.1905,48.8644],[-97.1905,48.8648],[-97.1904,48.8651],[-97.1901,48.8657],[-97.1899,48.8661],[-97.1895,48.8665],[-97.189,48.867],[-97.1884,48.8675],[-97.1851,48.8694],[-97.1813,48.8718],[-97.1788,48.8736],[-97.1785,48.8738],[-97.1782,48.8741],[-97.1781,48.8743],[-97.1779,48.8745],[-97.1778,48.8747],[-97.1777,48.8749],[-97.1777,48.875],[-97.1778,48.875],[-97.1778,48.8754],[-97.1779,48.8757],[-97.1782,48.8761],[-97.1786,48.8765],[-97.1792,48.8769],[-97.1798,48.8771],[-97.1808,48.8772],[-97.1823,48.8772],[-97.1852,48.8768],[-97.1869,48.8765],[-97.1881,48.8765],[-97.1891,48.8766],[-97.1904,48.8769],[-97.1933,48.8779],[-97.1944,48.8783],[-97.1957,48.8788],[-97.1972,48.8794],[-97.1981,48.8799],[-97.1988,48.8805],[-97.1995,48.8812],[-97.1999,48.8818],[-97.1999,48.8821],[-97.2,48.8827],[-97.1998,48.8832],[-97.1997,48.8836],[-97.199,48.8845],[-97.1978,48.8859],[-97.1975,48.8865],[-97.1974,48.8868],[-97.1973,48.8872],[-97.1973,48.8874],[-97.1974,48.8877],[-97.1975,48.8881],[-97.1983,48.8889],[-97.2002,48.8903],[-97.2004,48.8904],[-97.2009,48.8908],[-97.2014,48.8912],[-97.2017,48.8915],[-97.2017,48.8919],[-97.2016,48.8922],[-97.2013,48.8925],[-97.201,48.8926],[-97.2001,48.8926],[-97.1994,48.8926],[-97.1985,48.8925],[-97.198,48.8924],[-97.1973,48.892],[-97.1957,48.8916],[-97.1946,48.8915],[-97.1944,48.8914],[-97.1937,48.8914],[-97.1927,48.8915],[-97.1921,48.8917],[-97.1916,48.8919],[-97.1905,48.8926],[-97.1901,48.8932],[-97.1898,48.8938],[-97.1897,48.8944],[-97.1897,48.8947],[-97.1898,48.8951],[-97.1899,48.8954],[-97.1903,48.896],[-97.1911,48.8967],[-97.1919,48.8974],[-97.1925,48.8979],[-97.1935,48.8985],[-97.1941,48.8988],[-97.1945,48.8989],[-97.1966,48.8997],[-97.1992,48.9004],[-97.2009,48.9009],[-97.2022,48.9013],[-97.2048,48.9018],[-97.2055,48.902],[-97.207,48.9025],[-97.2076,48.9027],[-97.2082,48.9029],[-97.2088,48.9032],[-97.2093,48.9036],[-97.21,48.904],[-97.2105,48.9044],[-97.211,48.905],[-97.2114,48.9056],[-97.2122,48.9069],[-97.2125,48.9075],[-97.2127,48.9082],[-97.2127,48.909],[-97.2125,48.9099],[-97.212,48.911],[-97.2116,48.9121],[-97.2111,48.913],[-97.2108,48.914],[-97.2106,48.9148],[-97.2106,48.9153],[-97.2109,48.9162],[-97.2111,48.9167],[-97.2115,48.9172],[-97.2118,48.9175],[-97.2122,48.9177],[-97.2129,48.9181],[-97.2149,48.9187],[-97.2163,48.9191],[-97.2164,48.9191],[-97.2171,48.9194],[-97.2179,48.9198],[-97.2189,48.9205],[-97.2196,48.9215],[-97.2198,48.9222],[-97.2199,48.923],[-97.2197,48.9237],[-97.2191,48.9249],[-97.2183,48.9262],[-97.2172,48.9277],[-97.2163,48.9286],[-97.2159,48.9289],[-97.2149,48.9301],[-97.2146,48.9304],[-97.2145,48.9307],[-97.2144,48.931],[-97.2145,48.9314],[-97.2145,48.9316],[-97.2148,48.9319],[-97.2154,48.9325],[-97.2159,48.9327],[-97.2162,48.9328],[-97.217,48.9328],[-97.2181,48.9327],[-97.2198,48.9325],[-97.2208,48.9325],[-97.2214,48.9325],[-97.2218,48.9326],[-97.2237,48.9332],[-97.2245,48.9337],[-97.2249,48.9339],[-97.225,48.934],[-97.2252,48.9342],[-97.2254,48.9345],[-97.2257,48.9349],[-97.226,48.9353],[-97.2263,48.936],[-97.2267,48.9376],[-97.227,48.9389],[-97.2271,48.9398],[-97.2271,48.941],[-97.227,48.9418],[-97.2266,48.9432],[-97.2264,48.9441],[-97.2263,48.9445],[-97.2264,48.9452],[-97.2265,48.9456],[-97.227,48.9462],[-97.2273,48.9465],[-97.2276,48.9467],[-97.2279,48.9467],[-97.2284,48.9468],[-97.2304,48.9465],[-97.2309,48.9464],[-97.2313,48.9464],[-97.2326,48.9466],[-97.2331,48.9468],[-97.2338,48.9471],[-97.2342,48.9474],[-97.2343,48.948],[-97.2343,48.9485],[-97.2342,48.9488],[-97.2341,48.9491],[-97.2337,48.95],[-97.2332,48.951],[-97.2328,48.9524],[-97.2323,48.954],[-97.2317,48.9558],[-97.2313,48.9568],[-97.2309,48.9578],[-97.2305,48.9585],[-97.23,48.9591],[-97.2288,48.9603],[-97.2282,48.9609],[-97.2278,48.9613],[-97.2276,48.9619],[-97.2276,48.9624],[-97.2279,48.963],[-97.228,48.9631],[-97.2283,48.9634],[-97.2289,48.9639],[-97.2294,48.9641],[-97.23,48.9642],[-97.2323,48.9646],[-97.2355,48.965],[-97.2368,48.9652],[-97.2375,48.9654],[-97.2382,48.966],[-97.2383,48.9661],[-97.2388,48.9666],[-97.2391,48.9676],[-97.2392,48.9687],[-97.239,48.9696],[-97.2387,48.9706],[-97.2383,48.9715],[-97.2381,48.9723],[-97.238,48.9725],[-97.2379,48.9731],[-97.2378,48.9734],[-97.2378,48.9738],[-97.238,48.9752],[-97.238,48.9763],[-97.2381,48.9771],[-97.238,48.9771],[-97.238,48.9841],[-97.2377,48.9849],[-97.2372,48.9857],[-97.2365,48.9867],[-97.2359,48.9874],[-97.2351,48.9881],[-97.2342,48.989],[-97.2335,48.9895],[-97.2331,48.9898],[-97.2317,48.9904],[-97.2301,48.9911],[-97.2293,48.9914],[-97.229,48.9916],[-97.2279,48.9921],[-97.2274,48.9925],[-97.227,48.9929],[-97.2266,48.9933],[-97.2265,48.9938],[-97.2267,48.9941],[-97.227,48.9945],[-97.2273,48.9947],[-97.2287,48.9949],[-97.2304,48.995],[-97.2317,48.9951],[-97.2324,48.9952],[-97.2335,48.9956],[-97.2338,48.9959],[-97.2341,48.9966],[-97.2341,48.997],[-97.234,48.9975],[-97.2337,48.9981],[-97.2332,48.9985],[-97.2323,48.999],[-97.2305,49.0],[-97.2303,49.0001],[-97.2295,49.0005],[-97.2175,49.0005],[-97.2161,49.0005],[-97.2078,49.0005],[-97.2069,49.0005],[-97.1955,49.0005],[-97.1939,49.0005],[-97.1739,49.0005],[-97.1724,49.0005],[-97.1514,49.0005],[-97.1502,49.0005],[-97.1294,49.0004],[-97.1277,49.0004],[-97.1073,49.0004],[-97.1061,49.0004],[-97.0853,49.0004],[-97.084,49.0004],[-97.0633,49.0004],[-97.062,49.0004],[-97.0412,49.0004],[-97.0401,49.0004],[-97.0192,49.0004],[-97.0183,49.0004],[-96.9971,49.0004],[-96.9961,49.0004],[-96.9751,49.0003],[-96.9738,49.0003],[-96.953,49.0003],[-96.9518,49.0003],[-96.931,49.0003],[-96.9299,49.0003],[-96.909,49.0003],[-96.9078,49.0003],[-96.8869,49.0003],[-96.8856,49.0003],[-96.8649,49.0003],[-96.864,49.0003],[-96.8429,49.0003],[-96.8415,49.0003],[-96.8208,49.0003],[-96.8197,49.0003],[-96.8023,49.0002],[-96.8005,49.0002],[-96.8003,49.0002],[-96.7988,49.0002],[-96.7787,49.0002],[-96.7768,49.0002],[-96.7567,49.0002],[-96.7547,49.0002],[-96.7348,49.0002],[-96.7327,49.0002],[-96.7127,49.0002],[-96.7107,49.0002],[-96.6905,49.0002],[-96.6886,49.0002],[-96.6695,49.0002],[-96.6665,49.0002],[-96.6482,49.0002],[-96.6445,49.0002],[-96.6243,49.0002],[-96.6225,49.0002],[-96.6021,49.0002],[-96.6004,49.0002],[-96.58,49.0002],[-96.5784,49.0002],[-96.558,49.0002],[-96.5563,49.0002],[-96.536,49.0002],[-96.5342,49.0002],[-96.5154,49.0002],[-96.5123,49.0002],[-96.4933,49.0002],[-96.49,49.0002],[-96.471,49.0001],[-96.4664,49.0001],[-96.4496,49.0001],[-96.4492,49.0001],[-96.4491,49.0001],[-96.446,49.0001],[-96.4273,49.0001],[-96.4224,49.0001],[-96.4054,49.0001]]],"type":"Polygon"},"id":"35","properties":{"Area":2862183702.23055,"CTYONLY_":3,"Code":"KITT","LASTMOD":"1999-12-31T23:59:59Z","Name":"Kittson","Perimiter":263017.48277},"type":"Feature"},{"geometry":{"coordinates":[[[-96.4054,49.0001],[-96.4019,49.0001],[-96.3825,49.0001],[-96.3783,49.0001],[-96.3606,49.0001],[-96.3579,49.0001],[-96.3385,49.0001],[-96.3343,49.0001],[-96.3166,49.0001],[-96.3138,49.0001],[-96.2945,49.0001],[-96.2902,49.0001],[-96.2725,49.0001],[-96.2698,49.0001],[-96.2494,49.0001],[-96.2461,49.0001],[-96.2274,49.0001],[-96.2257,49.0001],[-96.2057,49.0001],[-96.2021,49.0001],[-96.1837,49.0],[-96.18,49.0],[-96.1617,49.0],[-96.1579,49.0],[-96.1401,49.0],[-96.1359,49.0],[-96.1176,49.0],[-96.1139,49.0],[-96.0957,49.0],[-96.0919,49.0],[-96.0738,49.0],[-96.07,49.0],[-96.0517,49.0],[-96.048,49.0],[-96.0298,49.0],[-96.026,49.0],[-96.0083,49.0],[-96.0045,49.0],[-95.9868,49.0],[-95.9784,49.0],[-95.9776,49.0],[-95.9755,49.0],[-95.9648,48.9999],[-95.9464,48.9999],[-95.943,48.9999],[-95.9225,48.9999],[-95.9211,48.9999],[-95.899,48.9998],[-95.883,48.9998],[-95.8771,48.9998],[-95.8564,48.9998],[-95.855,48.9998],[-95.8342,48.9998],[-95.8184,48.9997],[-95.8126,48.9997],[-95.7906,48.9997],[-95.7833,48.9997],[-95.7684,48.9997],[-95.7479,48.9996],[-95.7466,48.9996],[-95.7253,48.9996],[-95.7066,48.9996],[-95.7032,48.9996],[-95.681,48.9995],[-95.6654,48.9995],[-95.6596,48.9995],[-95.659,48.9995],[-95.6401,48.9995],[-95.6369,48.9995],[-95.6205,48.9994],[-95.615,48.9994],[-95.5948,48.9994],[-95.585,48.9994],[-95.573,48.9994],[-95.551,48.9993],[-95.5495,48.9993],[-95.5294,48.9993],[-95.5164,48.9993],[-95.5072,48.9993],[-95.4849,48.9992],[-95.4834,48.9992],[-95.4635,48.9992],[-95.4508,48.9992],[-95.4418,48.9992],[-95.4245,48.9991],[-95.4197,48.9991],[-95.3977,48.9991],[-95.3953,48.9991],[-95.3765,48.9991],[-95.3759,48.9991],[-95.3753,48.9991],[-95.3542,48.999],[-95.3513,48.999],[-95.3326,48.999],[-95.3286,48.999],[-95.3231,48.999],[-95.3224,48.9984],[-95.3204,48.9976],[-95.3202,48.9973],[-95.3204,48.9964],[-95.3206,48.9961],[-95.3201,48.9956],[-95.3197,48.9954],[-95.3191,48.9953],[-95.3187,48.9956],[-95.3182,48.996],[-95.3179,48.9961],[-95.3178,48.9961],[-95.3178,48.9958],[-95.3181,48.995],[-95.3191,48.9941],[-95.3204,48.9924],[-95.3206,48.9921],[-95.3224,48.9889],[-95.3227,48.9884],[-95.3242,48.9859],[-95.3245,48.985],[-95.3253,48.9832],[-95.3257,48.9814],[-95.3256,48.98],[-95.3255,48.9789],[-95.3257,48.9784],[-95.3253,48.976],[-95.325,48.9743],[-95.3249,48.9738],[-95.3248,48.9728],[-95.3247,48.972],[-95.3241,48.9703],[-95.3232,48.9692],[-95.3227,48.9685],[-95.3212,48.9672],[-95.3207,48.9669],[-95.3201,48.9648],[-95.3198,48.9643],[-95.3193,48.964],[-95.3193,48.9622],[-95.3202,48.9606],[-95.3206,48.9598],[-95.3206,48.9595],[-95.3206,48.959],[-95.3202,48.9581],[-95.3191,48.9569],[-95.3188,48.9562],[-95.3179,48.9559],[-95.3175,48.9552],[-95.3177,48.9545],[-95.3182,48.9535],[-95.3181,48.9531],[-95.3177,48.9525],[-95.3154,48.9513],[-95.3151,48.951],[-95.3141,48.9508],[-95.3131,48.9503],[-95.3125,48.9503],[-95.3123,48.9502],[-95.3119,48.9502],[-95.3119,48.9507],[-95.3129,48.9521],[-95.3129,48.9523],[-95.3126,48.9524],[-95.312,48.9524],[-95.3115,48.952],[-95.3108,48.9512],[-95.3104,48.951],[-95.3097,48.951],[-95.3089,48.9511],[-95.3079,48.9509],[-95.3061,48.9502],[-95.3052,48.9495],[-95.3046,48.9482],[-95.3046,48.947],[-95.305,48.9462],[-95.3053,48.9459],[-95.3061,48.9454],[-95.3068,48.9454],[-95.3069,48.9455],[-95.3069,48.9456],[-95.3063,48.9462],[-95.3062,48.9463],[-95.3061,48.9469],[-95.3062,48.9472],[-95.3062,48.9472],[-95.3071,48.9477],[-95.3081,48.948],[-95.3094,48.9481],[-95.3096,48.9482],[-95.3099,48.9484],[-95.31,48.9485],[-95.3103,48.9485],[-95.3104,48.9484],[-95.3103,48.948],[-95.3096,48.9478],[-95.3092,48.9477],[-95.3079,48.9474],[-95.3071,48.9469],[-95.3071,48.9466],[-95.3074,48.9465],[-95.3078,48.9466],[-95.3085,48.947],[-95.3086,48.9469],[-95.3086,48.9465],[-95.3088,48.9464],[-95.3095,48.9463],[-95.3102,48.9463],[-95.3114,48.9461],[-95.3131,48.946],[-95.3141,48.9457],[-95.3148,48.9452],[-95.3154,48.9448],[-95.3168,48.9431],[-95.3181,48.9421],[-95.3189,48.9419],[-95.3219,48.9412],[-95.3225,48.9409],[-95.3228,48.9403],[-95.3231,48.9389],[-95.3229,48.9373],[-95.3225,48.9358],[-95.3223,48.9355],[-95.3228,48.9344],[-95.3222,48.9327],[-95.3209,48.9307],[-95.3208,48.9305],[-95.3195,48.9285],[-95.3168,48.9245],[-95.315,48.9222],[-95.3141,48.921],[-95.3132,48.9198],[-95.3126,48.919],[-95.3119,48.9178],[-95.3115,48.9172],[-95.3109,48.9163],[-95.3102,48.9155],[-95.3093,48.9149],[-95.3092,48.9149],[-95.3085,48.9146],[-95.3078,48.9141],[-95.3074,48.9135],[-95.3064,48.9129],[-95.3061,48.9128],[-95.3059,48.9127],[-95.3043,48.9119],[-95.3038,48.9114],[-95.3027,48.91],[-95.3017,48.9093],[-95.2999,48.9086],[-95.2978,48.9083],[-95.2973,48.9081],[-95.2973,48.908],[-95.2973,48.9077],[-95.2976,48.9074],[-95.2977,48.9073],[-95.2978,48.9073],[-95.2978,48.9072],[-95.2978,48.9072],[-95.2979,48.9072],[-95.2979,48.9072],[-95.2979,48.9071],[-95.298,48.9071],[-95.298,48.9071],[-95.298,48.9071],[-95.2981,48.907],[-95.2982,48.9068],[-95.2983,48.9068],[-95.2985,48.9065],[-95.2985,48.9064],[-95.2986,48.9063],[-95.2988,48.906],[-95.2989,48.906],[-95.2991,48.9057],[-95.2992,48.9055],[-95.2994,48.9053],[-95.2996,48.9051],[-95.2997,48.905],[-95.2999,48.9048],[-95.2999,48.9048],[-95.2999,48.9048],[-95.3,48.9047],[-95.3,48.9047],[-95.3001,48.9047],[-95.3001,48.9046],[-95.3002,48.9045],[-95.3005,48.904],[-95.2993,48.9035],[-95.2983,48.9028],[-95.298,48.9027],[-95.2976,48.9026],[-95.2967,48.9027],[-95.2949,48.9028],[-95.2941,48.9027],[-95.2937,48.9023],[-95.2935,48.902],[-95.2927,48.9019],[-95.2914,48.9019],[-95.2909,48.9017],[-95.2908,48.9016],[-95.2907,48.9014],[-95.2906,48.9011],[-95.2911,48.9008],[-95.2911,48.9006],[-95.2901,48.9003],[-95.2896,48.9],[-95.289,48.8994],[-95.2882,48.8981],[-95.2879,48.8979],[-95.2872,48.8977],[-95.287,48.8976],[-95.2865,48.8975],[-95.2861,48.8976],[-95.2853,48.8977],[-95.2839,48.8975],[-95.2813,48.8967],[-95.2803,48.8965],[-95.2796,48.8962],[-95.279,48.8957],[-95.2782,48.8956],[-95.2773,48.8957],[-95.277,48.8958],[-95.2765,48.8962],[-95.2763,48.8963],[-95.2759,48.8962],[-95.2755,48.8959],[-95.2749,48.8956],[-95.2748,48.8951],[-95.2753,48.8943],[-95.2751,48.8938],[-95.2745,48.8931],[-95.2724,48.8921],[-95.2713,48.8915],[-95.268,48.8905],[-95.2677,48.8903],[-95.2674,48.89],[-95.2666,48.8894],[-95.2654,48.8888],[-95.265,48.8886],[-95.2646,48.8885],[-95.2639,48.8883],[-95.2635,48.888],[-95.2627,48.8877],[-95.2585,48.8867],[-95.2585,48.8867],[-95.257,48.8858],[-95.256,48.885],[-95.2548,48.8845],[-95.2517,48.8839],[-95.2507,48.8836],[-95.2502,48.8835],[-95.2496,48.8834],[-95.2485,48.8832],[-95.248,48.8836],[-95.2472,48.8835],[-95.2458,48.8829],[-95.2439,48.8823],[-95.2429,48.8822],[-95.2429,48.8822],[-95.2423,48.8821],[-95.2407,48.8821],[-95.2391,48.8819],[-95.2381,48.8817],[-95.2356,48.8815],[-95.2335,48.8814],[-95.231,48.8814],[-95.2287,48.8815],[-95.2265,48.8816],[-95.2252,48.8819],[-95.2212,48.883],[-95.2208,48.8831],[-95.2207,48.8831],[-95.22,48.8831],[-95.2193,48.8832],[-95.2188,48.8835],[-95.217,48.8835],[-95.2159,48.8839],[-95.2151,48.884],[-95.2144,48.8843],[-95.2122,48.8842],[-95.2117,48.8847],[-95.2115,48.8847],[-95.2112,48.8848],[-95.2085,48.8846],[-95.2059,48.8848],[-95.2024,48.8852],[-95.2009,48.8855],[-95.2005,48.8856],[-95.1986,48.8855],[-95.1956,48.8862],[-95.1924,48.8865],[-95.1919,48.8866],[-95.1913,48.8868],[-95.1901,48.887],[-95.1889,48.8873],[-95.1877,48.8874],[-95.1863,48.8877],[-95.1851,48.8882],[-95.1819,48.8888],[-95.1797,48.889],[-95.1791,48.889],[-95.1764,48.8893],[-95.173,48.8897],[-95.1701,48.8902],[-95.1674,48.8907],[-95.1648,48.8913],[-95.1641,48.8917],[-95.1618,48.892],[-95.1602,48.892],[-95.1579,48.8919],[-95.1564,48.8919],[-95.1555,48.892],[-95.1528,48.8921],[-95.1508,48.8922],[-95.1483,48.8923],[-95.1469,48.8927],[-95.1459,48.8929],[-95.1438,48.8934],[-95.1436,48.8937],[-95.1404,48.8943],[-95.1381,48.8949],[-95.1355,48.8959],[-95.1351,48.8963],[-95.1348,48.8963],[-95.1343,48.8963],[-95.1337,48.8969],[-95.1322,48.8973],[-95.1312,48.8975],[-95.1252,48.8998],[-95.1239,48.9001],[-95.1233,48.9004],[-95.1228,48.9006],[-95.1214,48.9013],[-95.121,48.9016],[-95.1205,48.9017],[-95.1204,48.9019],[-95.1182,48.9029],[-95.1163,48.9037],[-95.1151,48.9046],[-95.1144,48.9052],[-95.114,48.9061],[-95.1141,48.9064],[-95.1137,48.9069],[-95.1132,48.9071],[-95.113,48.9072],[-95.1126,48.9073],[-95.1107,48.9082],[-95.1096,48.9089],[-95.108,48.9099],[-95.1056,48.9113],[-95.1042,48.9121],[-95.1032,48.9127],[-95.102,48.9132],[-95.1008,48.9142],[-95.0981,48.9159],[-95.098,48.916],[-95.0975,48.9164],[-95.0971,48.9172],[-95.097,48.9176],[-95.0961,48.9181],[-95.0946,48.9191],[-95.0944,48.9193],[-95.0927,48.9204],[-95.0919,48.9207],[-95.0914,48.9208],[-95.0914,48.916],[-95.0912,48.9014],[-95.0911,48.8869],[-95.0908,48.8724],[-95.0908,48.858],[-95.0907,48.8436],[-95.0908,48.8291],[-95.0909,48.8147],[-95.0903,48.8],[-95.0903,48.7855],[-95.0903,48.7711],[-95.0901,48.7566],[-95.0901,48.7421],[-95.0899,48.7277],[-95.0898,48.713],[-95.1046,48.7129],[-95.1104,48.7129],[-95.1119,48.7129],[-95.1259,48.7129],[-95.1297,48.713],[-95.1333,48.713],[-95.1477,48.7129],[-95.1554,48.7129],[-95.1697,48.7129],[-95.1773,48.713],[-95.1917,48.713],[-95.1991,48.713],[-95.2112,48.713],[-95.2206,48.713],[-95.2331,48.713],[-95.2427,48.713],[-95.255,48.713],[-95.2645,48.713],[-95.2656,48.713],[-95.2767,48.713],[-95.2866,48.713],[-95.299,48.713],[-95.3051,48.713],[-95.3084,48.713],[-95.3205,48.713],[-95.3302,48.713],[-95.3425,48.7131],[-95.3425,48.6995],[-95.3424,48.6849],[-95.3423,48.6705],[-95.3424,48.6561],[-95.3425,48.6415],[-95.3426,48.6271],[-95.3424,48.6127],[-95.3426,48.5979],[-95.3423,48.5836],[-95.3423,48.5691],[-95.3424,48.5548],[-95.3425,48.5402],[-95.3628,48.5404],[-95.364,48.5403],[-95.3844,48.5402],[-95.386,48.5402],[-95.4061,48.5402],[-95.4078,48.5402],[-95.4279,48.54],[-95.4297,48.5399],[-95.4494,48.5399],[-95.4513,48.5399],[-95.4712,48.5396],[-95.4726,48.5396],[-95.493,48.5392],[-95.495,48.5392],[-95.5143,48.539],[-95.5163,48.539],[-95.5365,48.5389],[-95.5383,48.5389],[-95.558,48.5388],[-95.5603,48.5388],[-95.5801,48.5387],[-95.5821,48.5387],[-95.6023,48.5389],[-95.6232,48.5391],[-95.6447,48.5393],[-95.6666,48.5394],[-95.6886,48.5395],[-95.7102,48.5395],[-95.7322,48.54],[-95.7539,48.5404],[-95.7758,48.5406],[-95.7976,48.5405],[-95.8192,48.5404],[-95.8411,48.5406],[-95.8621,48.5414],[-95.8829,48.5419],[-95.8851,48.542],[-95.8986,48.5421],[-95.9046,48.5422],[-95.9064,48.5422],[-95.9269,48.5421],[-95.9486,48.5425],[-95.9498,48.5425],[-95.9704,48.543],[-95.9936,48.5435],[-96.0157,48.5437],[-96.0374,48.5438],[-96.0592,48.5437],[-96.0812,48.5436],[-96.1026,48.5438],[-96.1264,48.5439],[-96.1486,48.5442],[-96.1702,48.5445],[-96.1921,48.5446],[-96.2141,48.5449],[-96.2358,48.5452],[-96.2576,48.545],[-96.2794,48.5449],[-96.301,48.5448],[-96.3231,48.5446],[-96.3448,48.5444],[-96.3667,48.5443],[-96.3882,48.5442],[-96.3879,48.5588],[-96.3882,48.5733],[-96.3884,48.5877],[-96.3891,48.6024],[-96.389,48.6165],[-96.388,48.6313],[-96.3879,48.6454],[-96.3877,48.6599],[-96.3871,48.6741],[-96.3874,48.6887],[-96.3866,48.703],[-96.3873,48.7172],[-96.388,48.7172],[-96.4049,48.7172],[-96.4048,48.7318],[-96.4048,48.7465],[-96.4047,48.7607],[-96.4045,48.7758],[-96.4042,48.7903],[-96.4042,48.8048],[-96.4042,48.8198],[-96.4043,48.8343],[-96.4045,48.8491],[-96.4047,48.8635],[-96.405,48.878],[-96.405,48.8926],[-96.4053,48.9068],[-96.4053,48.9081],[-96.4053,48.9137],[-96.4054,48.9214],[-96.4054,48.9225],[-96.4053,48.936],[-96.4053,48.9371],[-96.4053,48.9504],[-96.4053,48.9515],[-96.4053,48.9648],[-96.4053,48.9658],[-96.4053,48.9705],[-96.4054,48.9793],[-96.4054,48.9803],[-96.4054,48.994],[-96.4054,48.9947],[-96.4054,49.0001]]],"type":"Polygon"},"id":"68","properties":{"Area":4347098503.12714,"CTYONLY_":4,"Code":"ROSE","LASTMOD":"2001-04-12T09:32:44Z","Name":"Roseau","Perimiter":302590.75293},"type":"Feature"},{"geometry":{"coordinates":[[[-94.4299,48.7012],[-94.4241,48.7053],[-94.4213,48.7086],[-94.4189,48.7103],[-94.4158,48.711],[-94.4081,48.7106],[-94.406,48.7105],[-94.3889,48.712],[-94.3859,48.7119],[-94.384,48.7119],[-94.3801,48.7111],[-94.3687,48.7065],[-94.3646,48.7059],[-94.3533,48.7042],[-94.3431,48.7035],[-94.3429,48.7035],[-94.3287,48.7045],[-94.3214,48.7067],[-94.3088,48.7103],[-94.2995,48.709],[-94.2911,48.7079],[-94.2829,48.7057],[-94.2781,48.7024],[-94.2745,48.6999],[-94.2694,48.6995],[-94.2644,48.699],[-94.261,48.6966],[-94.258,48.6918],[-94.2565,48.6901],[-94.2529,48.6864],[-94.2521,48.685],[-94.2514,48.6837],[-94.2507,48.6782],[-94.2527,48.6707],[-94.253,48.6693],[-94.2548,48.664],[-94.2546,48.6615],[-94.2509,48.657],[-94.2499,48.6563],[-94.2467,48.6542],[-94.2445,48.6535],[-94.2343,48.6524],[-94.2335,48.6524],[-94.2242,48.6495],[-94.2144,48.6494],[-94.2124,48.6496],[-94.1996,48.651],[-94.1915,48.6506],[-94.1886,48.6504],[-94.1689,48.6483],[-94.1678,48.6482],[-94.1574,48.6458],[-94.1522,48.6455],[-94.1458,48.6458],[-94.1391,48.646],[-94.126,48.6444],[-94.1235,48.6444],[-94.11,48.6443],[-94.1023,48.6455],[-94.0999,48.6459],[-94.0912,48.6437],[-94.0849,48.6441],[-94.0804,48.6442],[-94.0767,48.6442],[-94.0714,48.6459],[-94.0658,48.6462],[-94.0642,48.6438],[-94.0603,48.6431],[-94.0581,48.6434],[-94.0525,48.644],[-94.0432,48.6435],[-94.0393,48.6423],[-94.0364,48.6413],[-94.0356,48.6411],[-94.0295,48.6409],[-94.0153,48.6424],[-94.0069,48.6433],[-94.0007,48.6428],[-93.9931,48.6412],[-93.9897,48.6405],[-93.984,48.6401],[-93.9777,48.6385],[-93.9712,48.6385],[-93.968,48.6385],[-93.9596,48.6372],[-93.953,48.6341],[-93.9497,48.6339],[-93.934,48.6326],[-93.9272,48.6327],[-93.9169,48.6329],[-93.9134,48.6353],[-93.9057,48.6346],[-93.9054,48.6345],[-93.8948,48.6324],[-93.8853,48.6318],[-93.8844,48.6318],[-93.8757,48.6319],[-93.8698,48.6311],[-93.8624,48.631],[-93.848,48.6308],[-93.8443,48.6303],[-93.8404,48.6289],[-93.8393,48.6286],[-93.8365,48.6276],[-93.8334,48.6256],[-93.8292,48.6177],[-93.825,48.6136],[-93.8245,48.613],[-93.8214,48.6092],[-93.8182,48.5994],[-93.8175,48.597],[-93.8172,48.5964],[-93.813,48.588],[-93.8103,48.5846],[-93.8063,48.5796],[-93.8041,48.5703],[-93.8041,48.5702],[-93.8051,48.5644],[-93.808,48.5569],[-93.8088,48.5555],[-93.8119,48.5503],[-93.8102,48.5445],[-93.8109,48.5412],[-93.8109,48.541],[-93.818,48.535],[-93.818,48.5346],[-93.8184,48.5315],[-93.8178,48.5306],[-93.8161,48.5285],[-93.8145,48.5273],[-93.8111,48.5247],[-93.803,48.522],[-93.7964,48.5182],[-93.7933,48.5164],[-93.7879,48.5159],[-93.7745,48.5162],[-93.768,48.5164],[-93.7665,48.5164],[-93.7617,48.5166],[-93.7534,48.5158],[-93.7442,48.5175],[-93.739,48.5185],[-93.731,48.5185],[-93.7225,48.5178],[-93.7206,48.5176],[-93.7108,48.5186],[-93.7061,48.5182],[-93.7006,48.517],[-93.693,48.5152],[-93.6866,48.5154],[-93.6791,48.5167],[-93.6778,48.5169],[-93.6593,48.5165],[-93.657,48.5167],[-93.6473,48.5177],[-93.6433,48.519],[-93.6421,48.5199],[-93.6395,48.5218],[-93.6357,48.5285],[-93.6344,48.5293],[-93.6311,48.5313],[-93.6284,48.5319],[-93.6256,48.5315],[-93.6211,48.5264],[-93.6166,48.5238],[-93.6134,48.5228],[-93.6122,48.5225],[-93.6051,48.5231],[-93.5962,48.5287],[-93.5919,48.5299],[-93.5901,48.5305],[-93.581,48.5271],[-93.5761,48.527],[-93.5701,48.528],[-93.5602,48.5297],[-93.5484,48.5294],[-93.5476,48.5294],[-93.5425,48.53],[-93.5366,48.5319],[-93.5269,48.5341],[-93.5263,48.5341],[-93.5244,48.5343],[-93.5171,48.5348],[-93.5047,48.5399],[-93.501,48.5414],[-93.4952,48.5426],[-93.4854,48.5433],[-93.4833,48.5437],[-93.4673,48.5465],[-93.4655,48.5478],[-93.4625,48.5498],[-93.462,48.5505],[-93.4596,48.5537],[-93.4576,48.5598],[-93.4576,48.5621],[-93.4575,48.5672],[-93.4619,48.5731],[-93.4619,48.5734],[-93.4631,48.5767],[-93.4671,48.5885],[-93.4656,48.59],[-93.4654,48.5915],[-93.4654,48.5917],[-93.4627,48.5927],[-93.46,48.5927],[-93.4547,48.5927],[-93.4398,48.5937],[-93.4385,48.5942],[-93.4347,48.5954],[-93.4298,48.5997],[-93.4226,48.6032],[-93.4193,48.6036],[-93.416,48.605],[-93.4152,48.6053],[-93.415,48.6056],[-93.4144,48.6064],[-93.4056,48.6099],[-93.4034,48.61],[-93.4029,48.6077],[-93.4013,48.6079],[-93.3994,48.6055],[-93.3986,48.6045],[-93.3953,48.6038],[-93.3937,48.6041],[-93.3837,48.606],[-93.3724,48.6059],[-93.3714,48.6059],[-93.3672,48.6082],[-93.3619,48.6141],[-93.355,48.6114],[-93.3526,48.6135],[-93.3533,48.615],[-93.3513,48.62],[-93.3505,48.6219],[-93.3486,48.6265],[-93.3276,48.6302],[-93.3057,48.634],[-93.3048,48.6341],[-93.2838,48.6378],[-93.2634,48.6413],[-93.2546,48.6429],[-93.2422,48.6428],[-93.2193,48.6426],[-93.2075,48.6426],[-93.1975,48.6365],[-93.191,48.6325],[-93.184,48.6282],[-93.1783,48.6231],[-93.1754,48.6232],[-93.1531,48.6244],[-93.1319,48.6256],[-93.1104,48.6267],[-93.0903,48.6278],[-93.0884,48.6278],[-93.0886,48.6163],[-93.0895,48.6016],[-93.0898,48.5872],[-93.09,48.5727],[-93.0902,48.5583],[-93.0902,48.5441],[-93.0903,48.5296],[-93.0905,48.5151],[-93.0905,48.501],[-93.091,48.4884],[-93.0911,48.4867],[-93.0914,48.474],[-93.0915,48.4724],[-93.0918,48.4596],[-93.0919,48.458],[-93.092,48.4449],[-93.092,48.4436],[-93.0922,48.4303],[-93.0922,48.429],[-93.0923,48.4147],[-93.0935,48.4147],[-93.0938,48.4024],[-93.094,48.3879],[-93.094,48.3734],[-93.0945,48.3589],[-93.0948,48.3442],[-93.0948,48.3298],[-93.0953,48.3153],[-93.0952,48.3004],[-93.095,48.2862],[-93.0952,48.2716],[-93.0953,48.2576],[-93.0949,48.2426],[-93.0949,48.2425],[-93.0977,48.2426],[-93.0977,48.2271],[-93.0978,48.2126],[-93.0979,48.1981],[-93.0975,48.1836],[-93.097,48.1692],[-93.097,48.1546],[-93.097,48.1402],[-93.0969,48.1259],[-93.0972,48.1114],[-93.097,48.0969],[-93.0968,48.0823],[-93.0965,48.0679],[-93.0965,48.0678],[-93.0892,48.0679],[-93.0892,48.0509],[-93.089,48.0366],[-93.0886,48.022],[-93.0887,48.0075],[-93.0872,47.9932],[-93.088,47.9787],[-93.0809,47.9786],[-93.0809,47.967],[-93.0808,47.9647],[-93.0808,47.9525],[-93.0808,47.9504],[-93.0809,47.938],[-93.0809,47.9356],[-93.0809,47.9235],[-93.0809,47.9212],[-93.0809,47.9088],[-93.0809,47.9067],[-93.0808,47.8945],[-93.0808,47.8922],[-93.1015,47.8927],[-93.1232,47.893],[-93.1448,47.8928],[-93.1656,47.8931],[-93.1671,47.8932],[-93.1871,47.8931],[-93.1893,47.8931],[-93.2087,47.8933],[-93.2115,47.8934],[-93.2331,47.8937],[-93.2532,47.8936],[-93.2745,47.8938],[-93.2962,47.8939],[-93.3169,47.894],[-93.3392,47.8941],[-93.3603,47.8942],[-93.3809,47.8943],[-93.4024,47.8944],[-93.4235,47.8945],[-93.4442,47.8946],[-93.466,47.895],[-93.4874,47.8956],[-93.4892,47.8957],[-93.4933,47.8958],[-93.5085,47.8962],[-93.5105,47.8963],[-93.5297,47.8967],[-93.5303,47.8967],[-93.532,47.8968],[-93.5517,47.8973],[-93.5532,47.8974],[-93.5729,47.8981],[-93.5747,47.8982],[-93.5962,47.8978],[-93.5966,47.8978],[-93.6179,47.8977],[-93.6187,47.8977],[-93.6388,47.8977],[-93.6395,47.8976],[-93.6604,47.8976],[-93.6612,47.8976],[-93.6817,47.8976],[-93.6826,47.8976],[-93.7031,47.8976],[-93.7038,47.8976],[-93.7249,47.8975],[-93.7248,47.8989],[-93.7466,47.8989],[-93.768,47.8991],[-93.7758,47.8991],[-93.7758,47.899],[-93.776,47.8897],[-93.776,47.8842],[-93.7762,47.8753],[-93.7761,47.8697],[-93.7761,47.8607],[-93.7761,47.8553],[-93.7761,47.8464],[-93.7896,47.8465],[-93.7971,47.8466],[-93.8189,47.8467],[-93.8407,47.8468],[-93.8627,47.8469],[-93.8831,47.8471],[-93.9067,47.8471],[-93.9288,47.8475],[-93.9496,47.8475],[-93.9506,47.8475],[-93.971,47.8475],[-93.9725,47.8475],[-93.9927,47.8475],[-93.9942,47.8475],[-94.0141,47.8476],[-94.0161,47.8476],[-94.0375,47.8477],[-94.0591,47.8474],[-94.0807,47.8471],[-94.1022,47.8471],[-94.1239,47.8466],[-94.1448,47.8463],[-94.1657,47.8461],[-94.1822,47.8461],[-94.1871,47.846],[-94.2037,47.846],[-94.2086,47.846],[-94.2252,47.846],[-94.23,47.8461],[-94.2467,47.8462],[-94.2515,47.8462],[-94.2681,47.8462],[-94.2728,47.8462],[-94.2887,47.8462],[-94.3103,47.8458],[-94.3315,47.846],[-94.3532,47.8464],[-94.3747,47.8462],[-94.3964,47.8461],[-94.4185,47.8459],[-94.4186,47.86],[-94.4184,47.8744],[-94.418,47.8886],[-94.4177,47.9031],[-94.4176,47.9041],[-94.4175,47.9175],[-94.4174,47.9186],[-94.4175,47.9332],[-94.4174,47.9477],[-94.4172,47.9623],[-94.4173,47.9769],[-94.4176,47.9914],[-94.4177,48.006],[-94.4176,48.02],[-94.4236,48.0199],[-94.4241,48.0344],[-94.4246,48.0489],[-94.4247,48.0632],[-94.4234,48.0776],[-94.4231,48.092],[-94.4233,48.1059],[-94.4234,48.1204],[-94.4236,48.1348],[-94.4233,48.1491],[-94.4235,48.1637],[-94.4235,48.1781],[-94.4233,48.1923],[-94.4236,48.2067],[-94.4238,48.2212],[-94.4237,48.2356],[-94.4237,48.2504],[-94.424,48.2649],[-94.4243,48.2791],[-94.4244,48.2938],[-94.4246,48.3081],[-94.4248,48.3227],[-94.425,48.3372],[-94.4253,48.352],[-94.4252,48.3675],[-94.4288,48.3675],[-94.4289,48.3821],[-94.4293,48.3964],[-94.4294,48.411],[-94.4293,48.4254],[-94.4292,48.4399],[-94.4293,48.4543],[-94.4296,48.4688],[-94.4296,48.4832],[-94.4299,48.4977],[-94.4303,48.512],[-94.4303,48.5264],[-94.43,48.5409],[-94.4295,48.5554],[-94.4291,48.5698],[-94.4289,48.5844],[-94.4289,48.5988],[-94.4292,48.6133],[-94.4294,48.6276],[-94.4297,48.642],[-94.43,48.6564],[-94.4301,48.6708],[-94.43,48.6852],[-94.4299,48.6998],[-94.4299,48.7012]]],"type":"Polygon"},"id":"36","properties":{"Area":8167237870.91888,"CTYONLY_":5,"Code":"KOOC","LASTMOD":"1999-12-31T23:59:59Z","Name":"Koochiching","Perimiter":412897.43594},"type":"Feature"},{"geometry":{"coordinates":[[[-96.3882,48.5442],[-96.3667,48.5443],[-96.3448,48.5444],[-96.3231,48.5446],[-96.301,48.5448],[-96.2794,48.5449],[-96.2576,48.545],[-96.2358,48.5452],[-96.2141,48.5449],[-96.1921,48.5446],[-96.1702,48.5445],[-96.1486,48.5442],[-96.1264,48.5439],[-96.1026,48.5438],[-96.0812,48.5436],[-96.0592,48.5437],[-96.0374,48.5438],[-96.0157,48.5437],[-95.9936,48.5435],[-95.9704,48.543],[-95.9498,48.5425],[-95.9486,48.5425],[-95.9269,48.5421],[-95.9064,48.5422],[-95.9046,48.5422],[-95.8986,48.5421],[-95.8851,48.542],[-95.8829,48.5419],[-95.8621,48.5414],[-95.8411,48.5406],[-95.8192,48.5404],[-95.7976,48.5405],[-95.7758,48.5406],[-95.7539,48.5404],[-95.7322,48.54],[-95.7102,48.5395],[-95.6886,48.5395],[-95.6666,48.5394],[-95.6447,48.5393],[-95.6232,48.5391],[-95.6023,48.5389],[-95.6011,48.5251],[-95.6007,48.5107],[-95.6007,48.51],[-95.6008,48.4964],[-95.6008,48.4956],[-95.6011,48.4818],[-95.6011,48.4811],[-95.6016,48.4674],[-95.6016,48.4666],[-95.6016,48.453],[-95.6016,48.4522],[-95.602,48.4385],[-95.6021,48.4376],[-95.6023,48.424],[-95.6023,48.4232],[-95.6026,48.4095],[-95.6026,48.4088],[-95.6026,48.395],[-95.6026,48.3942],[-95.6021,48.3809],[-95.602,48.3798],[-95.6016,48.3655],[-95.5933,48.3656],[-95.5933,48.3656],[-95.5933,48.354],[-95.5932,48.3396],[-95.5932,48.325],[-95.5932,48.3105],[-95.5934,48.2961],[-95.5934,48.2815],[-95.5937,48.267],[-95.5941,48.2526],[-95.5941,48.2382],[-95.5939,48.2236],[-95.5939,48.2092],[-95.5938,48.1946],[-95.594,48.1802],[-95.5939,48.173],[-95.5941,48.173],[-95.6159,48.1731],[-95.6163,48.1731],[-95.6252,48.1731],[-95.6279,48.1731],[-95.6376,48.173],[-95.6376,48.173],[-95.6591,48.1729],[-95.662,48.1729],[-95.6802,48.1728],[-95.6803,48.1728],[-95.702,48.1729],[-95.7021,48.1729],[-95.7022,48.1729],[-95.7128,48.173],[-95.7157,48.1731],[-95.7226,48.1731],[-95.7227,48.1731],[-95.744,48.1727],[-95.7443,48.1727],[-95.7502,48.1727],[-95.7657,48.1728],[-95.7657,48.1728],[-95.7874,48.1725],[-95.8088,48.1722],[-95.809,48.1722],[-95.8091,48.1722],[-95.8305,48.1722],[-95.8308,48.1722],[-95.8308,48.1722],[-95.8499,48.1721],[-95.8525,48.1721],[-95.8527,48.1721],[-95.8744,48.172],[-95.8744,48.172],[-95.8752,48.172],[-95.8958,48.172],[-95.896,48.172],[-95.9176,48.1719],[-95.9178,48.1719],[-95.9178,48.1719],[-95.9392,48.1719],[-95.9394,48.1719],[-95.9608,48.1718],[-95.9609,48.1718],[-95.961,48.1718],[-95.9651,48.1718],[-95.9817,48.1717],[-95.9819,48.1717],[-95.9956,48.1717],[-96.0003,48.1717],[-96.0023,48.1718],[-96.0028,48.1718],[-96.0032,48.1718],[-96.0035,48.1718],[-96.0036,48.1718],[-96.0047,48.1717],[-96.0101,48.1718],[-96.0171,48.172],[-96.025,48.1721],[-96.0254,48.1721],[-96.0468,48.1722],[-96.0468,48.1722],[-96.0592,48.1721],[-96.0685,48.1721],[-96.0685,48.1721],[-96.079,48.1721],[-96.09,48.172],[-96.09,48.172],[-96.0979,48.172],[-96.1084,48.1718],[-96.1084,48.1718],[-96.1176,48.1722],[-96.1189,48.1722],[-96.1253,48.1727],[-96.1297,48.173],[-96.1298,48.173],[-96.1302,48.173],[-96.1388,48.1732],[-96.1516,48.1736],[-96.1518,48.1736],[-96.1625,48.1736],[-96.1641,48.1736],[-96.1736,48.1736],[-96.1737,48.1736],[-96.1741,48.1736],[-96.1813,48.1725],[-96.1827,48.1722],[-96.1834,48.172],[-96.1874,48.1721],[-96.191,48.1721],[-96.1948,48.1721],[-96.1954,48.1721],[-96.1959,48.1721],[-96.1963,48.1721],[-96.2023,48.1722],[-96.2038,48.1722],[-96.2072,48.1722],[-96.2076,48.1722],[-96.2177,48.1722],[-96.2179,48.1722],[-96.2188,48.1722],[-96.2251,48.1724],[-96.2275,48.1724],[-96.2287,48.1725],[-96.2307,48.1725],[-96.2329,48.1725],[-96.2391,48.1727],[-96.2397,48.1727],[-96.2397,48.1727],[-96.2398,48.1728],[-96.2476,48.1735],[-96.2491,48.1737],[-96.2503,48.1739],[-96.2511,48.174],[-96.252,48.174],[-96.2562,48.1744],[-96.2596,48.1749],[-96.2607,48.1749],[-96.2612,48.1749],[-96.2619,48.1749],[-96.2805,48.1747],[-96.2823,48.1747],[-96.2824,48.1747],[-96.2977,48.1747],[-96.3029,48.1747],[-96.3035,48.1747],[-96.3145,48.1747],[-96.3252,48.1746],[-96.3253,48.1746],[-96.3301,48.1745],[-96.3356,48.1745],[-96.3358,48.1744],[-96.338,48.1745],[-96.3402,48.1744],[-96.343,48.1744],[-96.3466,48.1743],[-96.347,48.1743],[-96.3473,48.1744],[-96.3477,48.1744],[-96.351,48.1745],[-96.3542,48.1746],[-96.3581,48.1747],[-96.361,48.1748],[-96.3642,48.1749],[-96.3656,48.175],[-96.3682,48.1751],[-96.3682,48.1751],[-96.3685,48.1751],[-96.3706,48.175],[-96.3728,48.1749],[-96.3753,48.1748],[-96.3781,48.1746],[-96.38,48.1745],[-96.3856,48.1747],[-96.3894,48.1748],[-96.3905,48.1748],[-96.3906,48.1748],[-96.3964,48.1748],[-96.4054,48.1748],[-96.4126,48.1749],[-96.4126,48.1749],[-96.4135,48.1749],[-96.4206,48.1749],[-96.4295,48.1749],[-96.4346,48.1749],[-96.4352,48.1749],[-96.4359,48.1749],[-96.438,48.1749],[-96.4402,48.1748],[-96.4436,48.1747],[-96.4454,48.1747],[-96.4561,48.1744],[-96.4563,48.1743],[-96.4564,48.1742],[-96.4569,48.1742],[-96.4592,48.1742],[-96.467,48.1741],[-96.4735,48.174],[-96.4773,48.1741],[-96.4789,48.1741],[-96.4791,48.1741],[-96.4841,48.174],[-96.4946,48.1741],[-96.4973,48.174],[-96.5003,48.1741],[-96.5006,48.1741],[-96.5008,48.1742],[-96.5008,48.1742],[-96.5038,48.174],[-96.5091,48.174],[-96.5164,48.1739],[-96.5204,48.1739],[-96.5223,48.1739],[-96.5251,48.1738],[-96.53,48.1738],[-96.5357,48.1738],[-96.5399,48.1738],[-96.5434,48.1738],[-96.5442,48.1738],[-96.5443,48.1738],[-96.5446,48.1738],[-96.5479,48.1738],[-96.5507,48.1738],[-96.5544,48.1738],[-96.557,48.1739],[-96.5616,48.1739],[-96.565,48.174],[-96.5654,48.174],[-96.5655,48.174],[-96.5678,48.174],[-96.5715,48.1739],[-96.5748,48.1739],[-96.5765,48.1739],[-96.5806,48.1739],[-96.5838,48.1738],[-96.5873,48.1737],[-96.5873,48.1737],[-96.5875,48.1737],[-96.5893,48.1737],[-96.5966,48.1737],[-96.6055,48.1737],[-96.609,48.1737],[-96.6092,48.1737],[-96.6106,48.1737],[-96.6253,48.1737],[-96.6307,48.1737],[-96.6307,48.1737],[-96.6309,48.1737],[-96.6338,48.1737],[-96.6378,48.1738],[-96.6407,48.1739],[-96.6525,48.1738],[-96.6525,48.1738],[-96.6742,48.1736],[-96.6742,48.1736],[-96.6826,48.1735],[-96.6958,48.1734],[-96.6959,48.1734],[-96.7176,48.1734],[-96.7177,48.1734],[-96.7393,48.1734],[-96.7393,48.1734],[-96.7503,48.1734],[-96.7573,48.1734],[-96.7581,48.1734],[-96.7605,48.1734],[-96.7606,48.1734],[-96.7613,48.1734],[-96.7819,48.1734],[-96.7821,48.1734],[-96.7821,48.1734],[-96.7932,48.1733],[-96.8038,48.1734],[-96.8039,48.1734],[-96.8111,48.1734],[-96.8255,48.1734],[-96.8255,48.1734],[-96.8473,48.1733],[-96.8474,48.1733],[-96.869,48.1733],[-96.869,48.1733],[-96.8753,48.1732],[-96.8907,48.1732],[-96.8907,48.1732],[-96.8932,48.1732],[-96.9122,48.1733],[-96.9123,48.1733],[-96.933,48.1733],[-96.9339,48.1733],[-96.934,48.1733],[-96.9387,48.1732],[-96.9448,48.1732],[-96.9554,48.1731],[-96.9703,48.1731],[-96.9705,48.1731],[-96.9749,48.173],[-96.9751,48.173],[-96.9773,48.173],[-96.9773,48.173],[-96.9775,48.1731],[-96.9812,48.1731],[-96.9844,48.1731],[-96.9889,48.1731],[-96.99,48.1731],[-96.9959,48.1732],[-96.9975,48.1732],[-96.998,48.1732],[-96.9987,48.1732],[-96.9989,48.1732],[-96.999,48.1732],[-97.0003,48.1732],[-97.0203,48.1733],[-97.0205,48.1733],[-97.042,48.1732],[-97.042,48.1732],[-97.0637,48.1732],[-97.0637,48.1732],[-97.0853,48.1734],[-97.0855,48.1734],[-97.1069,48.1735],[-97.1071,48.1735],[-97.1253,48.1733],[-97.1257,48.1733],[-97.1286,48.1733],[-97.1322,48.1733],[-97.1376,48.1733],[-97.1462,48.1733],[-97.1467,48.1733],[-97.1452,48.1741],[-97.1434,48.1744],[-97.1417,48.1746],[-97.1389,48.1747],[-97.1371,48.1754],[-97.1365,48.1758],[-97.136,48.1768],[-97.1359,48.1789],[-97.1362,48.1796],[-97.1366,48.1809],[-97.1383,48.1824],[-97.1406,48.183],[-97.1413,48.1831],[-97.1432,48.1828],[-97.1455,48.1824],[-97.1467,48.1821],[-97.1484,48.1825],[-97.1498,48.1835],[-97.1497,48.1859],[-97.1491,48.1864],[-97.1475,48.1879],[-97.1449,48.1895],[-97.1429,48.191],[-97.1426,48.1913],[-97.1415,48.1926],[-97.1413,48.1934],[-97.1412,48.1937],[-97.141,48.194],[-97.1409,48.1945],[-97.1404,48.1947],[-97.1397,48.1951],[-97.1391,48.1953],[-97.1383,48.1955],[-97.1365,48.1963],[-97.1356,48.1972],[-97.1359,48.1984],[-97.1368,48.1996],[-97.1383,48.2006],[-97.1401,48.2018],[-97.1409,48.2027],[-97.1412,48.203],[-97.1411,48.204],[-97.1409,48.2046],[-97.14,48.2052],[-97.139,48.2059],[-97.1375,48.2063],[-97.1341,48.2068],[-97.1316,48.2072],[-97.1301,48.2077],[-97.1296,48.208],[-97.1295,48.208],[-97.1292,48.2084],[-97.1292,48.2099],[-97.1291,48.21],[-97.1296,48.2105],[-97.1297,48.2106],[-97.1299,48.2108],[-97.1307,48.211],[-97.1318,48.2112],[-97.1354,48.2116],[-97.1364,48.2119],[-97.1382,48.2131],[-97.1394,48.2144],[-97.1392,48.2168],[-97.1389,48.2171],[-97.1383,48.2174],[-97.1373,48.2177],[-97.1354,48.2179],[-97.1344,48.2178],[-97.1328,48.2176],[-97.1313,48.2172],[-97.1302,48.2164],[-97.1297,48.2161],[-97.1292,48.2158],[-97.1278,48.2145],[-97.1274,48.2134],[-97.1265,48.2113],[-97.126,48.2101],[-97.1259,48.2099],[-97.1257,48.2097],[-97.1253,48.2093],[-97.1245,48.208],[-97.1236,48.2077],[-97.1229,48.2074],[-97.1216,48.2074],[-97.1204,48.2073],[-97.1197,48.2076],[-97.1189,48.2079],[-97.1183,48.2086],[-97.118,48.2092],[-97.1178,48.2098],[-97.1179,48.2107],[-97.1181,48.2115],[-97.1189,48.2129],[-97.1194,48.2136],[-97.1208,48.215],[-97.122,48.2159],[-97.1228,48.2165],[-97.1248,48.2175],[-97.1253,48.2178],[-97.1272,48.2185],[-97.1289,48.2188],[-97.1297,48.219],[-97.1321,48.2196],[-97.135,48.2207],[-97.139,48.222],[-97.1406,48.2222],[-97.1417,48.2221],[-97.1436,48.2216],[-97.1448,48.2209],[-97.1455,48.2204],[-97.1457,48.2202],[-97.1458,48.2202],[-97.1462,48.2198],[-97.1471,48.2189],[-97.1482,48.2184],[-97.1497,48.2181],[-97.1509,48.2184],[-97.151,48.2185],[-97.1517,48.219],[-97.1521,48.2197],[-97.1521,48.2205],[-97.1517,48.2214],[-97.151,48.2222],[-97.1496,48.2232],[-97.1483,48.2238],[-97.1476,48.224],[-97.1465,48.2243],[-97.1436,48.2253],[-97.1408,48.2263],[-97.1385,48.2268],[-97.1371,48.227],[-97.1357,48.2271],[-97.1332,48.227],[-97.1317,48.2265],[-97.1305,48.2259],[-97.1298,48.2255],[-97.129,48.2251],[-97.1276,48.2245],[-97.1273,48.2243],[-97.1266,48.2239],[-97.1259,48.2236],[-97.1253,48.2234],[-97.1245,48.2232],[-97.1233,48.2231],[-97.1222,48.2234],[-97.1216,48.2236],[-97.121,48.2242],[-97.121,48.2242],[-97.1206,48.2248],[-97.1206,48.2254],[-97.1207,48.2259],[-97.1216,48.227],[-97.1225,48.2275],[-97.1234,48.2281],[-97.1244,48.2284],[-97.1253,48.2287],[-97.1278,48.2293],[-97.1299,48.2297],[-97.1303,48.2297],[-97.1325,48.2298],[-97.1351,48.2298],[-97.1393,48.2302],[-97.1423,48.231],[-97.1435,48.2318],[-97.1446,48.2336],[-97.1445,48.2343],[-97.1443,48.2351],[-97.143,48.2361],[-97.1416,48.2365],[-97.1411,48.2366],[-97.1399,48.2367],[-97.1377,48.2368],[-97.1358,48.237],[-97.1343,48.2378],[-97.1339,48.2382],[-97.1338,48.2386],[-97.1337,48.2391],[-97.1341,48.2397],[-97.1346,48.2403],[-97.1357,48.2409],[-97.1375,48.2414],[-97.1385,48.2415],[-97.1405,48.2415],[-97.1422,48.2412],[-97.1444,48.2412],[-97.1459,48.2417],[-97.147,48.2423],[-97.1471,48.243],[-97.1467,48.2445],[-97.146,48.2452],[-97.1444,48.2462],[-97.1431,48.2468],[-97.1404,48.2473],[-97.1389,48.2479],[-97.1377,48.2485],[-97.1355,48.2495],[-97.1345,48.2498],[-97.1334,48.2499],[-97.1305,48.2498],[-97.1299,48.2498],[-97.1291,48.2495],[-97.1274,48.2495],[-97.1263,48.2498],[-97.1253,48.25],[-97.1251,48.25],[-97.1247,48.2504],[-97.1244,48.2508],[-97.1243,48.2513],[-97.1243,48.252],[-97.1245,48.2526],[-97.1248,48.2532],[-97.1248,48.2532],[-97.1253,48.2537],[-97.1256,48.254],[-97.1262,48.2546],[-97.1267,48.2551],[-97.1274,48.2555],[-97.1291,48.2566],[-97.13,48.2573],[-97.1304,48.2576],[-97.1306,48.2581],[-97.1306,48.2587],[-97.1306,48.259],[-97.1303,48.2595],[-97.1298,48.2598],[-97.1292,48.2599],[-97.1283,48.26],[-97.1272,48.2601],[-97.1253,48.2601],[-97.1248,48.2602],[-97.1242,48.2604],[-97.1236,48.2607],[-97.1231,48.2612],[-97.1229,48.2617],[-97.123,48.2623],[-97.1234,48.2628],[-97.1237,48.2633],[-97.1241,48.2636],[-97.1246,48.2639],[-97.1253,48.2641],[-97.1262,48.2644],[-97.1285,48.2649],[-97.1303,48.2651],[-97.1305,48.2652],[-97.1333,48.2656],[-97.135,48.2659],[-97.136,48.2659],[-97.1375,48.2657],[-97.1395,48.2655],[-97.1406,48.2654],[-97.142,48.2654],[-97.1427,48.2656],[-97.1438,48.2658],[-97.1444,48.2663],[-97.1448,48.2668],[-97.145,48.2675],[-97.1451,48.2678],[-97.145,48.2688],[-97.1443,48.2698],[-97.1431,48.2705],[-97.1421,48.2709],[-97.1403,48.2712],[-97.1391,48.2713],[-97.1377,48.2713],[-97.1361,48.2711],[-97.1343,48.2707],[-97.1313,48.2701],[-97.1305,48.27],[-97.1298,48.2699],[-97.1288,48.2698],[-97.1272,48.2699],[-97.1265,48.2701],[-97.1253,48.2705],[-97.125,48.2707],[-97.1247,48.2709],[-97.124,48.2713],[-97.1238,48.2716],[-97.1237,48.2721],[-97.1237,48.2725],[-97.1239,48.2728],[-97.124,48.2733],[-97.1242,48.2737],[-97.1247,48.2743],[-97.1253,48.2751],[-97.1254,48.2753],[-97.1255,48.2755],[-97.1256,48.2758],[-97.1255,48.2761],[-97.1254,48.2762],[-97.1253,48.2764],[-97.1251,48.2767],[-97.1246,48.2769],[-97.124,48.277],[-97.1232,48.277],[-97.1224,48.2769],[-97.1213,48.2768],[-97.1206,48.2768],[-97.12,48.2769],[-97.1187,48.2774],[-97.1175,48.2781],[-97.117,48.2788],[-97.1165,48.2797],[-97.1166,48.2805],[-97.1166,48.2807],[-97.1167,48.2813],[-97.117,48.2821],[-97.1171,48.2824],[-97.1172,48.2826],[-97.1177,48.2835],[-97.1221,48.2901],[-97.1231,48.2909],[-97.1239,48.2913],[-97.1244,48.2915],[-97.1247,48.2917],[-97.1253,48.2919],[-97.1256,48.292],[-97.126,48.292],[-97.1265,48.292],[-97.1272,48.2919],[-97.128,48.2916],[-97.1285,48.2913],[-97.1295,48.2908],[-97.1303,48.2902],[-97.1305,48.2901],[-97.1314,48.2891],[-97.1322,48.2884],[-97.133,48.2879],[-97.1342,48.2874],[-97.1349,48.2872],[-97.1355,48.2871],[-97.1367,48.2873],[-97.1374,48.2877],[-97.1378,48.2879],[-97.1383,48.2887],[-97.1384,48.2894],[-97.1384,48.2898],[-97.1383,48.2903],[-97.138,48.2909],[-97.1373,48.2918],[-97.1368,48.2922],[-97.1364,48.2925],[-97.1355,48.2929],[-97.1344,48.2935],[-97.1335,48.2941],[-97.133,48.2946],[-97.1323,48.2953],[-97.1318,48.2959],[-97.1314,48.2963],[-97.131,48.2969],[-97.1306,48.2973],[-97.1305,48.2974],[-97.13,48.2979],[-97.1293,48.2984],[-97.1286,48.2987],[-97.1282,48.2989],[-97.1276,48.299],[-97.1271,48.2991],[-97.127,48.2991],[-97.1263,48.2991],[-97.1253,48.2989],[-97.125,48.2988],[-97.1246,48.2987],[-97.1241,48.2984],[-97.1234,48.2975],[-97.1228,48.2968],[-97.1227,48.2967],[-97.1213,48.2955],[-97.1203,48.2949],[-97.1192,48.2943],[-97.1167,48.294],[-97.1153,48.2939],[-97.1138,48.2943],[-97.1129,48.2949],[-97.1123,48.2954],[-97.1122,48.296],[-97.1122,48.2965],[-97.1123,48.2968],[-97.1126,48.2973],[-97.113,48.2978],[-97.1138,48.2984],[-97.1148,48.299],[-97.118,48.3004],[-97.12,48.3012],[-97.1227,48.3019],[-97.1241,48.3022],[-97.1247,48.3025],[-97.1253,48.3029],[-97.1255,48.303],[-97.1259,48.3033],[-97.1262,48.3036],[-97.1266,48.3041],[-97.1267,48.3046],[-97.1265,48.3055],[-97.1263,48.3059],[-97.1257,48.3064],[-97.1253,48.3067],[-97.1241,48.3073],[-97.123,48.3081],[-97.1222,48.3088],[-97.1221,48.3095],[-97.1222,48.3099],[-97.123,48.3105],[-97.1241,48.3112],[-97.1247,48.3115],[-97.1253,48.3119],[-97.1258,48.3119],[-97.1263,48.312],[-97.1269,48.312],[-97.1276,48.312],[-97.1282,48.3118],[-97.1289,48.3116],[-97.1298,48.3111],[-97.1299,48.3111],[-97.1303,48.3108],[-97.1304,48.3108],[-97.1311,48.3103],[-97.1318,48.3099],[-97.1325,48.3094],[-97.1331,48.3092],[-97.1336,48.309],[-97.1343,48.3089],[-97.1351,48.3089],[-97.1358,48.3089],[-97.1365,48.3091],[-97.1372,48.3094],[-97.1377,48.3098],[-97.1379,48.3102],[-97.1381,48.3106],[-97.138,48.3111],[-97.138,48.3116],[-97.1379,48.312],[-97.1376,48.3125],[-97.1372,48.3129],[-97.1367,48.3134],[-97.1361,48.3141],[-97.1356,48.3148],[-97.1351,48.3155],[-97.1348,48.316],[-97.1346,48.3166],[-97.1345,48.3171],[-97.1343,48.3177],[-97.134,48.3181],[-97.1335,48.3185],[-97.1329,48.3189],[-97.1325,48.3192],[-97.132,48.3194],[-97.1312,48.3196],[-97.1306,48.3196],[-97.1303,48.3196],[-97.1291,48.3196],[-97.1282,48.3195],[-97.1274,48.3195],[-97.1267,48.3195],[-97.1253,48.3196],[-97.1229,48.3201],[-97.1197,48.3208],[-97.1173,48.3216],[-97.1164,48.3222],[-97.1157,48.323],[-97.1155,48.3236],[-97.1155,48.324],[-97.1162,48.3248],[-97.1168,48.3253],[-97.1173,48.3258],[-97.1175,48.326],[-97.1187,48.3266],[-97.1203,48.3271],[-97.1222,48.3274],[-97.123,48.3275],[-97.1253,48.3277],[-97.1257,48.3277],[-97.1262,48.3278],[-97.1275,48.328],[-97.1292,48.3282],[-97.1303,48.3282],[-97.1311,48.3283],[-97.1317,48.3282],[-97.1326,48.3281],[-97.1337,48.3279],[-97.1343,48.3277],[-97.1345,48.3277],[-97.1353,48.3273],[-97.1359,48.327],[-97.1368,48.3263],[-97.1376,48.3257],[-97.138,48.3255],[-97.1385,48.3253],[-97.139,48.3251],[-97.1397,48.3251],[-97.1404,48.3252],[-97.141,48.3254],[-97.1415,48.3257],[-97.1417,48.3258],[-97.142,48.3262],[-97.1422,48.3267],[-97.1423,48.327],[-97.1422,48.3276],[-97.142,48.3281],[-97.1416,48.3287],[-97.1408,48.3294],[-97.14,48.3299],[-97.139,48.3304],[-97.1378,48.3309],[-97.1371,48.331],[-97.1361,48.3312],[-97.1347,48.3315],[-97.1325,48.3318],[-97.1311,48.3321],[-97.1305,48.3323],[-97.1295,48.3326],[-97.129,48.3329],[-97.1284,48.3336],[-97.1275,48.3352],[-97.1263,48.3379],[-97.1258,48.3384],[-97.1258,48.3398],[-97.1258,48.3402],[-97.1259,48.3406],[-97.1263,48.3415],[-97.1267,48.3422],[-97.1276,48.3427],[-97.1283,48.343],[-97.1297,48.3435],[-97.1308,48.3438],[-97.1309,48.3438],[-97.132,48.344],[-97.1334,48.3439],[-97.1354,48.3439],[-97.1372,48.344],[-97.1383,48.3441],[-97.1388,48.3441],[-97.1396,48.3443],[-97.14,48.3446],[-97.1405,48.345],[-97.1407,48.3453],[-97.1409,48.3456],[-97.141,48.3459],[-97.1408,48.3468],[-97.1405,48.3471],[-97.1396,48.3478],[-97.1386,48.3485],[-97.1376,48.3491],[-97.1368,48.3496],[-97.1362,48.3501],[-97.1361,48.3503],[-97.136,48.3505],[-97.136,48.3506],[-97.1359,48.351],[-97.1359,48.3511],[-97.136,48.3518],[-97.1362,48.3522],[-97.1363,48.3524],[-97.1365,48.3526],[-97.1373,48.3529],[-97.1382,48.3532],[-97.1387,48.3533],[-97.1398,48.3535],[-97.1405,48.3536],[-97.1415,48.3538],[-97.1423,48.354],[-97.143,48.3542],[-97.1435,48.3543],[-97.1438,48.3546],[-97.1441,48.3549],[-97.1442,48.3551],[-97.1443,48.3554],[-97.1445,48.356],[-97.1447,48.3565],[-97.145,48.3571],[-97.1453,48.3576],[-97.1459,48.3586],[-97.1464,48.3592],[-97.1468,48.3596],[-97.1477,48.3603],[-97.1484,48.3608],[-97.1501,48.3613],[-97.1517,48.362],[-97.1525,48.3623],[-97.1534,48.3628],[-97.1545,48.3633],[-97.1554,48.3638],[-97.1559,48.3646],[-97.1562,48.3656],[-97.1562,48.3662],[-97.156,48.3671],[-97.1558,48.3681],[-97.1555,48.3686],[-97.1554,48.3689],[-97.1552,48.3691],[-97.1548,48.37],[-97.1539,48.3704],[-97.1536,48.3705],[-97.1524,48.371],[-97.1523,48.371],[-97.1512,48.3713],[-97.1498,48.3712],[-97.1476,48.371],[-97.1437,48.3703],[-97.1433,48.3703],[-97.141,48.3702],[-97.1407,48.3703],[-97.1404,48.3703],[-97.1403,48.3703],[-97.1402,48.3703],[-97.1401,48.3703],[-97.1392,48.3705],[-97.1386,48.3708],[-97.1378,48.3713],[-97.1373,48.3718],[-97.1372,48.3724],[-97.1373,48.373],[-97.1376,48.3736],[-97.1383,48.3744],[-97.1389,48.375],[-97.1398,48.3759],[-97.1406,48.3769],[-97.1412,48.3777],[-97.1413,48.3785],[-97.1409,48.3793],[-97.1403,48.3797],[-97.1395,48.3801],[-97.1379,48.3803],[-97.1366,48.3804],[-97.1355,48.3805],[-97.1344,48.3808],[-97.1339,48.3811],[-97.1334,48.3818],[-97.1333,48.3822],[-97.1338,48.3828],[-97.1344,48.3833],[-97.1354,48.3838],[-97.1362,48.384],[-97.1374,48.3839],[-97.1389,48.3837],[-97.1406,48.3833],[-97.1431,48.3824],[-97.1446,48.3819],[-97.1454,48.3815],[-97.1463,48.3815],[-97.147,48.3814],[-97.1479,48.3817],[-97.149,48.3819],[-97.1505,48.3824],[-97.1509,48.3825],[-97.1519,48.3829],[-97.1532,48.3834],[-97.1538,48.3839],[-97.1548,48.3844],[-97.155,48.3846],[-97.156,48.3851],[-97.1572,48.3858],[-97.1576,48.3865],[-97.1577,48.3874],[-97.1571,48.3884],[-97.1565,48.3896],[-97.1563,48.3904],[-97.1567,48.3909],[-97.1576,48.3912],[-97.1586,48.3913],[-97.1596,48.3912],[-97.1608,48.3913],[-97.1617,48.3915],[-97.1627,48.3918],[-97.1632,48.392],[-97.1633,48.3929],[-97.1631,48.3937],[-97.1621,48.3948],[-97.1607,48.3956],[-97.1593,48.3961],[-97.1586,48.3964],[-97.1574,48.3965],[-97.1551,48.3968],[-97.1534,48.397],[-97.1519,48.3969],[-97.1505,48.3968],[-97.1499,48.3968],[-97.1481,48.3968],[-97.1467,48.3971],[-97.1456,48.3975],[-97.1445,48.3981],[-97.1434,48.3989],[-97.1434,48.399],[-97.1427,48.3996],[-97.1421,48.4004],[-97.1414,48.4013],[-97.1406,48.4019],[-97.1399,48.4025],[-97.1392,48.4029],[-97.1383,48.4033],[-97.1369,48.4038],[-97.1349,48.4046],[-97.1334,48.4053],[-97.1323,48.4059],[-97.1314,48.4066],[-97.1311,48.4073],[-97.131,48.4079],[-97.1312,48.409],[-97.1316,48.4096],[-97.1322,48.4104],[-97.1334,48.4112],[-97.1348,48.412],[-97.1362,48.4126],[-97.1373,48.4134],[-97.1375,48.4137],[-97.1376,48.4137],[-97.1379,48.4141],[-97.1384,48.4146],[-97.1388,48.4163],[-97.1388,48.4172],[-97.1393,48.4181],[-97.1398,48.4185],[-97.1406,48.4187],[-97.142,48.4186],[-97.1434,48.4181],[-97.1445,48.4173],[-97.1453,48.4159],[-97.1467,48.414],[-97.1472,48.4137],[-97.1478,48.4133],[-97.1489,48.4129],[-97.1505,48.4128],[-97.1508,48.4128],[-97.1521,48.4129],[-97.1532,48.4131],[-97.1543,48.4136],[-97.1543,48.4136],[-97.155,48.4143],[-97.1554,48.415],[-97.1554,48.4161],[-97.1554,48.4168],[-97.1548,48.4175],[-97.1539,48.4182],[-97.1527,48.4188],[-97.1509,48.4195],[-97.1507,48.4196],[-97.1489,48.4201],[-97.1466,48.4206],[-97.1443,48.4211],[-97.1421,48.4215],[-97.1403,48.4216],[-97.1383,48.4217],[-97.1367,48.4216],[-97.135,48.4213],[-97.1335,48.421],[-97.1325,48.4205],[-97.1312,48.4197],[-97.1301,48.4191],[-97.129,48.4181],[-97.1285,48.4177],[-97.1274,48.4168],[-97.1264,48.4164],[-97.126,48.4162],[-97.1253,48.4162],[-97.1244,48.4164],[-97.1236,48.4167],[-97.1232,48.417],[-97.1227,48.4176],[-97.1225,48.418],[-97.1224,48.4183],[-97.1223,48.4191],[-97.1223,48.4195],[-97.1225,48.42],[-97.1227,48.4204],[-97.1228,48.4207],[-97.1231,48.421],[-97.1233,48.4213],[-97.1241,48.4219],[-97.1246,48.4223],[-97.1249,48.4224],[-97.1253,48.4226],[-97.1268,48.4234],[-97.1286,48.4242],[-97.129,48.4243],[-97.1312,48.4251],[-97.1332,48.4258],[-97.1346,48.4262],[-97.1375,48.4264],[-97.139,48.4265],[-97.1406,48.427],[-97.1412,48.4272],[-97.1425,48.4277],[-97.1438,48.4285],[-97.1446,48.4291],[-97.1451,48.4298],[-97.1457,48.4303],[-97.1458,48.4312],[-97.1455,48.4322],[-97.1451,48.4326],[-97.144,48.4332],[-97.142,48.4337],[-97.1412,48.4338],[-97.1398,48.4337],[-97.1384,48.4336],[-97.1366,48.433],[-97.1344,48.4321],[-97.1332,48.4316],[-97.1315,48.4312],[-97.1305,48.4311],[-97.129,48.4311],[-97.1278,48.4313],[-97.1267,48.4319],[-97.1259,48.4325],[-97.1253,48.4329],[-97.1246,48.4337],[-97.1245,48.4341],[-97.1238,48.4355],[-97.1236,48.4361],[-97.1234,48.4371],[-97.1233,48.4376],[-97.1233,48.4383],[-97.1235,48.4389],[-97.1238,48.4399],[-97.124,48.4407],[-97.1243,48.4413],[-97.1245,48.4416],[-97.1248,48.4419],[-97.125,48.4421],[-97.1251,48.4422],[-97.1253,48.4423],[-97.1258,48.4427],[-97.1265,48.4432],[-97.128,48.4438],[-97.129,48.444],[-97.1295,48.4441],[-97.1314,48.4441],[-97.1328,48.4439],[-97.1345,48.4434],[-97.1355,48.4427],[-97.1363,48.4421],[-97.1365,48.4419],[-97.138,48.4405],[-97.1398,48.4392],[-97.141,48.4386],[-97.1428,48.4383],[-97.1451,48.4381],[-97.1464,48.4381],[-97.1477,48.4383],[-97.149,48.4389],[-97.1498,48.4392],[-97.1503,48.4397],[-97.1505,48.4403],[-97.1506,48.4409],[-97.1505,48.4413],[-97.1502,48.4419],[-97.1501,48.4422],[-97.1492,48.4434],[-97.1481,48.4441],[-97.1462,48.4448],[-97.1426,48.4459],[-97.1401,48.4467],[-97.1377,48.4477],[-97.1353,48.4489],[-97.1306,48.4523],[-97.1293,48.4541],[-97.1292,48.4564],[-97.1292,48.4566],[-97.1292,48.4569],[-97.1291,48.4575],[-97.1288,48.4585],[-97.1286,48.4596],[-97.1285,48.4604],[-97.1288,48.4616],[-97.1292,48.4622],[-97.1293,48.4624],[-97.1298,48.463],[-97.1306,48.4635],[-97.1319,48.4638],[-97.1334,48.4639],[-97.1347,48.4638],[-97.136,48.4635],[-97.138,48.463],[-97.1395,48.463],[-97.1407,48.463],[-97.142,48.4634],[-97.143,48.4639],[-97.1444,48.4649],[-97.1455,48.466],[-97.1463,48.4669],[-97.147,48.4677],[-97.1474,48.4684],[-97.148,48.47],[-97.1482,48.4708],[-97.148,48.4713],[-97.1477,48.4721],[-97.1474,48.4728],[-97.1465,48.4737],[-97.1461,48.4741],[-97.1445,48.4746],[-97.1432,48.4748],[-97.1419,48.4748],[-97.1407,48.4747],[-97.1393,48.4743],[-97.1379,48.4737],[-97.1368,48.4732],[-97.1352,48.4724],[-97.134,48.4718],[-97.1331,48.4715],[-97.1326,48.4714],[-97.1324,48.4713],[-97.1315,48.4712],[-97.1306,48.4713],[-97.1301,48.4714],[-97.1294,48.4715],[-97.1293,48.4717],[-97.1289,48.472],[-97.1283,48.4729],[-97.1281,48.4736],[-97.1281,48.4744],[-97.1285,48.4751],[-97.1289,48.4758],[-97.1293,48.4761],[-97.1297,48.4764],[-97.1308,48.4769],[-97.1324,48.4773],[-97.1346,48.4776],[-97.1364,48.4777],[-97.1384,48.4776],[-97.1406,48.4775],[-97.1419,48.4773],[-97.1433,48.4769],[-97.1448,48.4765],[-97.1461,48.4761],[-97.1477,48.4758],[-97.1493,48.4755],[-97.1509,48.4753],[-97.1511,48.4752],[-97.153,48.475],[-97.1549,48.475],[-97.1569,48.475],[-97.1585,48.4752],[-97.1599,48.4756],[-97.1609,48.4759],[-97.1616,48.4763],[-97.1622,48.477],[-97.1626,48.4778],[-97.1624,48.4786],[-97.1623,48.4792],[-97.1616,48.4799],[-97.1602,48.4807],[-97.1592,48.4812],[-97.1574,48.4816],[-97.1562,48.4818],[-97.1546,48.4821],[-97.1529,48.4822],[-97.1509,48.4824],[-97.1507,48.4824],[-97.1482,48.4828],[-97.1455,48.483],[-97.1437,48.4835],[-97.1424,48.4838],[-97.1411,48.4843],[-97.1402,48.4848],[-97.1396,48.4854],[-97.1394,48.486],[-97.1392,48.4864],[-97.1393,48.4873],[-97.1396,48.4881],[-97.1401,48.4887],[-97.1408,48.4892],[-97.1417,48.49],[-97.1428,48.4909],[-97.1433,48.4914],[-97.1433,48.492],[-97.143,48.4924],[-97.1423,48.4926],[-97.1415,48.4926],[-97.1406,48.4924],[-97.1399,48.492],[-97.139,48.4912],[-97.1382,48.4904],[-97.138,48.4897],[-97.1373,48.4889],[-97.1367,48.4884],[-97.136,48.4881],[-97.1351,48.4878],[-97.1344,48.4878],[-97.1332,48.4881],[-97.1322,48.4885],[-97.1315,48.4891],[-97.1312,48.4897],[-97.1311,48.4903],[-97.1311,48.4907],[-97.1316,48.4916],[-97.1322,48.4924],[-97.1334,48.4935],[-97.1345,48.4943],[-97.1367,48.4954],[-97.1388,48.496],[-97.1408,48.4967],[-97.1425,48.4972],[-97.1444,48.4976],[-97.1453,48.4979],[-97.1478,48.4995],[-97.148,48.4997],[-97.1483,48.5],[-97.1487,48.5004],[-97.1491,48.5009],[-97.1497,48.502],[-97.1499,48.5034],[-97.1498,48.5047],[-97.1498,48.5061],[-97.1495,48.5075],[-97.1495,48.5086],[-97.1497,48.5096],[-97.1502,48.5106],[-97.1502,48.5117],[-97.1499,48.512],[-97.1491,48.5124],[-97.1477,48.5124],[-97.142,48.5116],[-97.139,48.5117],[-97.1366,48.5123],[-97.1338,48.5139],[-97.1328,48.5146],[-97.1326,48.5148],[-97.1289,48.5173],[-97.1281,48.5178],[-97.127,48.519],[-97.1267,48.5202],[-97.1276,48.5215],[-97.1288,48.5222],[-97.129,48.5223],[-97.1307,48.5227],[-97.1339,48.5227],[-97.1366,48.5221],[-97.1385,48.5215],[-97.1395,48.521],[-97.1411,48.5202],[-97.1426,48.5195],[-97.1442,48.5191],[-97.1454,48.5188],[-97.1473,48.5188],[-97.1488,48.5189],[-97.1503,48.5194],[-97.1506,48.5195],[-97.1524,48.5204],[-97.154,48.5217],[-97.1547,48.5242],[-97.1549,48.5266],[-97.1544,48.5285],[-97.1536,48.5295],[-97.1536,48.5295],[-97.1527,48.5303],[-97.1513,48.5309],[-97.1507,48.5311],[-97.1499,48.5313],[-97.1482,48.5315],[-97.1458,48.5316],[-97.1438,48.5316],[-97.1422,48.5323],[-97.1411,48.5333],[-97.141,48.5343],[-97.1413,48.5355],[-97.1424,48.5366],[-97.144,48.5375],[-97.1456,48.5382],[-97.1481,48.5388],[-97.1505,48.5395],[-97.1508,48.5395],[-97.1533,48.5399],[-97.1558,48.5403],[-97.1582,48.5409],[-97.1596,48.5414],[-97.161,48.542],[-97.1614,48.5424],[-97.1631,48.5439],[-97.1631,48.544],[-97.1509,48.5439],[-97.1287,48.5439],[-97.107,48.544],[-97.0852,48.5441],[-97.0635,48.5441],[-97.0416,48.5442],[-97.0194,48.5441],[-96.9985,48.5441],[-96.9768,48.544],[-96.9551,48.5437],[-96.9331,48.5435],[-96.9138,48.5433],[-96.9115,48.5432],[-96.8896,48.5433],[-96.8678,48.5433],[-96.8459,48.5434],[-96.824,48.5436],[-96.8023,48.5436],[-96.7803,48.5435],[-96.7585,48.5436],[-96.7368,48.5437],[-96.7151,48.5437],[-96.6931,48.5437],[-96.6713,48.5436],[-96.6493,48.5437],[-96.6278,48.5437],[-96.6058,48.5437],[-96.5839,48.5437],[-96.5621,48.5436],[-96.54,48.5434],[-96.518,48.5434],[-96.4973,48.5434],[-96.4754,48.5435],[-96.4535,48.5436],[-96.4318,48.5438],[-96.4101,48.544],[-96.3882,48.5442]]],"type":"Polygon"},"id":"45","properties":{"Area":4698732287.54973,"CTYONLY_":6,"Code":"MARS","LASTMOD":"1984-01-12T14:12:49Z","Name":"Marshall","Perimiter":374207.65129},"type":"Feature"},{"geometry":{"coordinates":[[[-93.0884,48.6278],[-93.067,48.627],[-93.0456,48.6262],[-93.0237,48.6253],[-93.0021,48.6245],[-92.9845,48.6239],[-92.98,48.625],[-92.9641,48.6291],[-92.9585,48.6306],[-92.9547,48.6316],[-92.9497,48.6304],[-92.9498,48.6291],[-92.9499,48.6147],[-92.95,48.6084],[-92.9369,48.6075],[-92.9295,48.607],[-92.9177,48.6006],[-92.9151,48.5992],[-92.91,48.5964],[-92.8945,48.595],[-92.8932,48.5946],[-92.8729,48.5878],[-92.8652,48.5853],[-92.8515,48.5807],[-92.8301,48.5735],[-92.8206,48.5703],[-92.8079,48.5661],[-92.7863,48.5589],[-92.7767,48.5557],[-92.7665,48.5522],[-92.7439,48.5446],[-92.7354,48.5418],[-92.7284,48.5394],[-92.7227,48.54],[-92.7007,48.5421],[-92.7003,48.5421],[-92.6789,48.5442],[-92.6578,48.5463],[-92.6576,48.5462],[-92.6369,48.5429],[-92.6357,48.5427],[-92.6348,48.5426],[-92.6302,48.5284],[-92.6282,48.5223],[-92.6255,48.5179],[-92.6269,48.5142],[-92.6268,48.514],[-92.6264,48.5135],[-92.625,48.513],[-92.628,48.5108],[-92.6287,48.5106],[-92.6308,48.5092],[-92.6312,48.5082],[-92.6319,48.5068],[-92.6296,48.5058],[-92.627,48.5033],[-92.6306,48.5008],[-92.6351,48.4998],[-92.637,48.4994],[-92.6386,48.4996],[-92.64,48.4999],[-92.647,48.4999],[-92.654,48.5017],[-92.6569,48.4996],[-92.6582,48.4987],[-92.6614,48.4964],[-92.6789,48.4971],[-92.6857,48.4974],[-92.6986,48.4949],[-92.7011,48.4847],[-92.7016,48.4841],[-92.7092,48.4729],[-92.7085,48.4704],[-92.7089,48.4696],[-92.7126,48.463],[-92.7025,48.4551],[-92.7015,48.4543],[-92.6881,48.4438],[-92.6799,48.4425],[-92.6694,48.441],[-92.6635,48.4401],[-92.6586,48.4377],[-92.6562,48.4365],[-92.6371,48.4375],[-92.6157,48.4386],[-92.5935,48.4398],[-92.5765,48.4406],[-92.5717,48.4415],[-92.5686,48.4421],[-92.5499,48.4454],[-92.5369,48.4478],[-92.5284,48.448],[-92.515,48.4484],[-92.5074,48.448],[-92.507,48.4476],[-92.501,48.4422],[-92.4942,48.436],[-92.4893,48.4303],[-92.4849,48.4294],[-92.4837,48.4292],[-92.482,48.4283],[-92.4819,48.4279],[-92.4819,48.4276],[-92.4807,48.4264],[-92.481,48.4253],[-92.4788,48.4233],[-92.4754,48.4187],[-92.4631,48.4157],[-92.4564,48.4141],[-92.4564,48.4135],[-92.4563,48.4012],[-92.4602,48.3956],[-92.47,48.3813],[-92.4765,48.372],[-92.4747,48.3667],[-92.4697,48.3522],[-92.4697,48.3521],[-92.4591,48.3374],[-92.4558,48.3329],[-92.4523,48.3281],[-92.4476,48.3229],[-92.4415,48.3161],[-92.4413,48.3159],[-92.4405,48.3154],[-92.4403,48.3149],[-92.4386,48.3112],[-92.4367,48.309],[-92.4361,48.3085],[-92.4347,48.3074],[-92.4318,48.3052],[-92.4289,48.306],[-92.4256,48.3047],[-92.4204,48.299],[-92.4156,48.2951],[-92.415,48.2941],[-92.4135,48.2915],[-92.4065,48.2795],[-92.4017,48.2714],[-92.3967,48.2648],[-92.3931,48.2601],[-92.3927,48.259],[-92.3934,48.2576],[-92.3921,48.2568],[-92.3913,48.256],[-92.3891,48.2537],[-92.3901,48.2528],[-92.3912,48.2529],[-92.3922,48.2531],[-92.3926,48.2519],[-92.3923,48.2512],[-92.3912,48.2509],[-92.3907,48.2507],[-92.3897,48.2508],[-92.3887,48.2512],[-92.3867,48.2518],[-92.3858,48.2514],[-92.3853,48.2504],[-92.3852,48.2502],[-92.3846,48.2492],[-92.3868,48.2492],[-92.3863,48.2475],[-92.3878,48.247],[-92.3881,48.2465],[-92.3872,48.2444],[-92.3866,48.2441],[-92.3846,48.2449],[-92.3838,48.2446],[-92.3844,48.2425],[-92.3844,48.2414],[-92.384,48.2404],[-92.3833,48.2393],[-92.3816,48.2377],[-92.3806,48.2365],[-92.3789,48.2359],[-92.3789,48.2359],[-92.3785,48.2353],[-92.3791,48.2343],[-92.3781,48.233],[-92.3784,48.2321],[-92.3785,48.2312],[-92.3783,48.2304],[-92.3774,48.2293],[-92.3758,48.2283],[-92.3754,48.2275],[-92.3756,48.2267],[-92.3751,48.226],[-92.3743,48.2256],[-92.3734,48.225],[-92.3726,48.2236],[-92.3714,48.2241],[-92.3708,48.2239],[-92.3707,48.2228],[-92.3699,48.2218],[-92.3699,48.2212],[-92.3699,48.2203],[-92.3695,48.2203],[-92.3691,48.2202],[-92.368,48.2212],[-92.368,48.2212],[-92.3672,48.2217],[-92.3668,48.2223],[-92.3676,48.2232],[-92.3687,48.2237],[-92.368,48.2241],[-92.3662,48.224],[-92.365,48.2236],[-92.3636,48.2229],[-92.3621,48.2227],[-92.3616,48.2232],[-92.3613,48.224],[-92.361,48.2248],[-92.3603,48.2256],[-92.3586,48.2265],[-92.3566,48.2275],[-92.3555,48.2281],[-92.3544,48.2286],[-92.3537,48.2296],[-92.3535,48.2301],[-92.3517,48.2306],[-92.3494,48.2313],[-92.3484,48.2314],[-92.3477,48.2315],[-92.347,48.2315],[-92.3439,48.2321],[-92.3419,48.2317],[-92.3414,48.2319],[-92.3408,48.2337],[-92.3404,48.2341],[-92.3392,48.2347],[-92.339,48.2349],[-92.3386,48.2351],[-92.338,48.2351],[-92.3377,48.235],[-92.3371,48.2351],[-92.3365,48.2357],[-92.3362,48.2357],[-92.3346,48.2348],[-92.3344,48.2346],[-92.3344,48.2344],[-92.3343,48.2342],[-92.3338,48.2339],[-92.3333,48.2338],[-92.332,48.234],[-92.3308,48.2348],[-92.3302,48.2349],[-92.3292,48.2351],[-92.3281,48.2359],[-92.3274,48.2366],[-92.327,48.2369],[-92.3268,48.2368],[-92.3262,48.2366],[-92.3261,48.2366],[-92.3259,48.2367],[-92.3256,48.2369],[-92.3253,48.2371],[-92.3223,48.2373],[-92.3221,48.2373],[-92.3148,48.2406],[-92.3006,48.2422],[-92.2803,48.2444],[-92.2783,48.2451],[-92.2695,48.2482],[-92.2713,48.2519],[-92.2736,48.2566],[-92.2794,48.2596],[-92.2901,48.2651],[-92.291,48.2664],[-92.2945,48.2713],[-92.2931,48.276],[-92.2937,48.2767],[-92.2942,48.2766],[-92.2945,48.2764],[-92.2951,48.2763],[-92.2952,48.2763],[-92.2953,48.2765],[-92.2953,48.2767],[-92.2954,48.2769],[-92.2953,48.2771],[-92.2952,48.2772],[-92.2953,48.2773],[-92.2956,48.2773],[-92.2955,48.2776],[-92.2955,48.2777],[-92.2956,48.278],[-92.2972,48.2809],[-92.3014,48.2883],[-92.2987,48.2954],[-92.2945,48.3063],[-92.2987,48.3099],[-92.3018,48.3125],[-92.3061,48.3163],[-92.3044,48.3229],[-92.302,48.3232],[-92.2954,48.3239],[-92.2952,48.3246],[-92.2901,48.3392],[-92.2888,48.3429],[-92.2803,48.3468],[-92.2625,48.355],[-92.2588,48.3544],[-92.2364,48.3511],[-92.2216,48.3489],[-92.2197,48.3481],[-92.2191,48.3475],[-92.2189,48.3469],[-92.2181,48.3463],[-92.2169,48.345],[-92.2147,48.3452],[-92.2067,48.3457],[-92.2065,48.3473],[-92.2077,48.3479],[-92.2038,48.3519],[-92.195,48.3505],[-92.1945,48.3488],[-92.193,48.3488],[-92.1928,48.3488],[-92.1785,48.3519],[-92.179,48.3549],[-92.1791,48.3549],[-92.1774,48.3572],[-92.1709,48.3598],[-92.162,48.3634],[-92.1488,48.3652],[-92.1448,48.3657],[-92.1437,48.3561],[-92.1274,48.3556],[-92.106,48.355],[-92.0942,48.3546],[-92.0908,48.3545],[-92.0842,48.3538],[-92.0835,48.3538],[-92.0823,48.3547],[-92.0781,48.3581],[-92.067,48.3595],[-92.0625,48.3595],[-92.0552,48.3594],[-92.0525,48.3549],[-92.0488,48.3486],[-92.0458,48.3479],[-92.0451,48.3458],[-92.0478,48.3436],[-92.0475,48.3404],[-92.0469,48.3348],[-92.0404,48.3336],[-92.0376,48.3331],[-92.031,48.3261],[-92.0307,48.3257],[-92.0185,48.324],[-92.0119,48.323],[-92.0001,48.3211],[-92.0051,48.3118],[-92.0129,48.2975],[-92.0129,48.297],[-92.012,48.287],[-92.0087,48.2826],[-92.0072,48.2806],[-92.0066,48.2677],[-92.0065,48.2655],[-91.9949,48.262],[-91.9891,48.2603],[-91.9841,48.2531],[-91.9805,48.248],[-91.979,48.2475],[-91.9783,48.2474],[-91.9778,48.2474],[-91.9773,48.2472],[-91.9769,48.2468],[-91.977,48.2465],[-91.9772,48.2463],[-91.9773,48.2462],[-91.9775,48.246],[-91.9774,48.2457],[-91.9774,48.2456],[-91.9772,48.2455],[-91.9765,48.245],[-91.9756,48.2444],[-91.9744,48.2453],[-91.9743,48.2454],[-91.9742,48.2455],[-91.9738,48.2459],[-91.9736,48.2464],[-91.9735,48.2467],[-91.9726,48.247],[-91.9704,48.2479],[-91.97,48.2488],[-91.9706,48.249],[-91.9708,48.2494],[-91.9714,48.2499],[-91.9719,48.25],[-91.9724,48.2503],[-91.9724,48.2506],[-91.9723,48.251],[-91.9722,48.2513],[-91.9722,48.2518],[-91.9718,48.252],[-91.9718,48.2529],[-91.9714,48.2531],[-91.9709,48.253],[-91.9705,48.2531],[-91.9704,48.2534],[-91.9699,48.2538],[-91.959,48.2537],[-91.957,48.2524],[-91.9541,48.2523],[-91.954,48.2518],[-91.9541,48.2517],[-91.9541,48.2515],[-91.954,48.2495],[-91.9512,48.2479],[-91.948,48.246],[-91.9496,48.2446],[-91.9511,48.2444],[-91.9582,48.2439],[-91.957,48.2389],[-91.9573,48.2387],[-91.9597,48.2369],[-91.9583,48.2332],[-91.9524,48.2331],[-91.9512,48.2334],[-91.9507,48.2332],[-91.9451,48.2304],[-91.942,48.2304],[-91.9375,48.2343],[-91.9288,48.2359],[-91.9282,48.236],[-91.9211,48.2368],[-91.9167,48.2386],[-91.9148,48.239],[-91.9134,48.2389],[-91.9131,48.2385],[-91.9106,48.2382],[-91.9097,48.2384],[-91.9076,48.2384],[-91.9073,48.2383],[-91.907,48.2382],[-91.9065,48.2378],[-91.9058,48.2373],[-91.9023,48.2372],[-91.8931,48.238],[-91.885,48.2283],[-91.8843,48.2275],[-91.8769,48.2239],[-91.8675,48.2192],[-91.865,48.2095],[-91.8643,48.207],[-91.8634,48.2071],[-91.8453,48.2088],[-91.8417,48.2094],[-91.8416,48.2094],[-91.8359,48.2103],[-91.8326,48.2095],[-91.8325,48.2094],[-91.8325,48.2094],[-91.8325,48.2094],[-91.8325,48.2094],[-91.8199,48.2112],[-91.8154,48.2119],[-91.8144,48.2094],[-91.8141,48.2084],[-91.8094,48.2063],[-91.7982,48.203],[-91.7983,48.1953],[-91.7982,48.1808],[-91.7984,48.1662],[-91.7983,48.1515],[-91.7981,48.1369],[-91.798,48.1224],[-91.7987,48.1079],[-91.7992,48.0936],[-91.7997,48.0788],[-91.8001,48.0643],[-91.8,48.0496],[-91.8,48.0353],[-91.8,48.0206],[-91.8001,48.0059],[-91.7996,47.9914],[-91.7992,47.977],[-91.7985,47.9625],[-91.7979,47.9481],[-91.7977,47.9334],[-91.7978,47.9189],[-91.7979,47.9045],[-91.7979,47.8899],[-91.7983,47.8771],[-91.7983,47.876],[-91.7988,47.8618],[-91.7992,47.8464],[-91.8,47.8319],[-91.8,47.8175],[-91.7999,47.8031],[-91.7997,47.7916],[-91.7997,47.7893],[-91.7997,47.7886],[-91.7995,47.7774],[-91.7995,47.776],[-91.7995,47.7742],[-91.7995,47.7723],[-91.7992,47.7626],[-91.7992,47.7598],[-91.7992,47.7538],[-91.7993,47.7482],[-91.7993,47.7454],[-91.7992,47.7388],[-91.7992,47.7339],[-91.799,47.731],[-91.7984,47.7201],[-91.7982,47.717],[-91.7981,47.7165],[-91.7977,47.7128],[-91.7971,47.707],[-91.7967,47.7024],[-91.7959,47.6925],[-91.7959,47.688],[-91.7955,47.678],[-91.7955,47.6778],[-91.7955,47.6733],[-91.7954,47.6729],[-91.795,47.663],[-91.7948,47.6586],[-91.7942,47.6486],[-91.794,47.6449],[-91.794,47.6442],[-91.7933,47.6345],[-91.793,47.6299],[-91.7923,47.6212],[-91.7922,47.6193],[-91.7919,47.6155],[-91.7915,47.6091],[-91.7913,47.6049],[-91.7912,47.6021],[-91.7911,47.6008],[-91.7908,47.5904],[-91.7905,47.5874],[-91.7904,47.5864],[-91.7893,47.576],[-91.7892,47.5749],[-91.789,47.5719],[-91.7888,47.5614],[-91.7887,47.5588],[-91.7886,47.5574],[-91.7878,47.5469],[-91.788,47.5431],[-91.788,47.5424],[-91.7886,47.533],[-91.7886,47.5322],[-91.7889,47.5187],[-91.7889,47.5176],[-91.789,47.5067],[-91.7891,47.5041],[-91.7891,47.503],[-91.7894,47.493],[-91.7894,47.4897],[-91.7894,47.4886],[-91.7895,47.4753],[-91.7895,47.4741],[-91.7895,47.4605],[-91.7895,47.4574],[-91.7893,47.4449],[-91.7894,47.4303],[-91.7895,47.416],[-91.7896,47.4017],[-91.7904,47.3872],[-91.7906,47.3726],[-91.792,47.3726],[-91.792,47.3576],[-91.792,47.3432],[-91.7918,47.3288],[-91.7918,47.3145],[-91.7919,47.3],[-91.792,47.2855],[-91.7921,47.271],[-91.7922,47.2565],[-91.7923,47.2422],[-91.7923,47.2276],[-91.7923,47.2128],[-91.7922,47.1985],[-91.7923,47.1843],[-91.7923,47.1698],[-91.7923,47.1556],[-91.7923,47.1411],[-91.7924,47.1265],[-91.7922,47.1119],[-91.7943,47.1119],[-91.7945,47.0976],[-91.7945,47.0831],[-91.7944,47.0688],[-91.7944,47.0541],[-91.7943,47.0399],[-91.7943,47.0255],[-91.7944,47.0109],[-91.7944,46.9965],[-91.7944,46.9818],[-91.7944,46.9675],[-91.7943,46.953],[-91.7944,46.9397],[-91.7945,46.9397],[-91.7947,46.9396],[-91.7948,46.9395],[-91.795,46.9394],[-91.7951,46.9394],[-91.7952,46.9394],[-91.7953,46.9393],[-91.7954,46.9391],[-91.7955,46.939],[-91.7957,46.9388],[-91.7957,46.9386],[-91.7958,46.9384],[-91.7958,46.9384],[-91.7959,46.9383],[-91.796,46.9382],[-91.7961,46.9381],[-91.7964,46.938],[-91.7966,46.9379],[-91.797,46.9379],[-91.7971,46.9378],[-91.7974,46.9378],[-91.7975,46.9378],[-91.7978,46.9378],[-91.798,46.9379],[-91.7981,46.938],[-91.7983,46.938],[-91.7986,46.9379],[-91.7989,46.9379],[-91.7991,46.9379],[-91.7993,46.9379],[-91.7995,46.9378],[-91.7996,46.9377],[-91.7998,46.9376],[-91.8004,46.9373],[-91.8007,46.9371],[-91.8011,46.9369],[-91.8013,46.9368],[-91.8016,46.9367],[-91.802,46.9366],[-91.8022,46.9365],[-91.8025,46.9364],[-91.8028,46.9363],[-91.8032,46.9361],[-91.8034,46.936],[-91.8036,46.9359],[-91.8037,46.9357],[-91.804,46.9356],[-91.8042,46.9354],[-91.8044,46.9352],[-91.8046,46.935],[-91.8048,46.9349],[-91.805,46.9347],[-91.8051,46.9346],[-91.8053,46.9345],[-91.8055,46.9345],[-91.8057,46.9344],[-91.8059,46.9343],[-91.806,46.9343],[-91.8062,46.9342],[-91.8064,46.9341],[-91.8066,46.9338],[-91.8067,46.9336],[-91.8069,46.9334],[-91.807,46.9332],[-91.8071,46.9331],[-91.8071,46.933],[-91.8072,46.9329],[-91.8073,46.9328],[-91.8075,46.9328],[-91.8076,46.9327],[-91.8078,46.9327],[-91.808,46.9327],[-91.8082,46.9325],[-91.8084,46.9324],[-91.8087,46.9322],[-91.8089,46.932],[-91.8091,46.9319],[-91.8094,46.9317],[-91.8097,46.9315],[-91.81,46.9314],[-91.8103,46.9312],[-91.8106,46.9311],[-91.8107,46.931],[-91.8109,46.9309],[-91.811,46.9309],[-91.8112,46.9309],[-91.8113,46.9308],[-91.8116,46.9306],[-91.8117,46.9305],[-91.8119,46.9303],[-91.812,46.9301],[-91.8121,46.9299],[-91.8122,46.9298],[-91.8123,46.9296],[-91.8123,46.9293],[-91.8124,46.9291],[-91.8124,46.929],[-91.8125,46.9288],[-91.8126,46.9287],[-91.813,46.9281],[-91.8133,46.9277],[-91.8135,46.9275],[-91.8137,46.9272],[-91.8138,46.9271],[-91.8139,46.927],[-91.8141,46.9268],[-91.8142,46.9267],[-91.8144,46.9267],[-91.8147,46.9266],[-91.8149,46.9265],[-91.815,46.9263],[-91.8151,46.9263],[-91.8152,46.9262],[-91.8153,46.926],[-91.8154,46.9259],[-91.8154,46.9258],[-91.8155,46.9258],[-91.8157,46.9256],[-91.8159,46.9252],[-91.8162,46.925],[-91.8163,46.9248],[-91.8165,46.9247],[-91.8166,46.9246],[-91.8168,46.9244],[-91.817,46.9243],[-91.8171,46.9243],[-91.8173,46.9242],[-91.8175,46.9241],[-91.8177,46.924],[-91.8179,46.924],[-91.8182,46.9241],[-91.8184,46.9242],[-91.8186,46.9244],[-91.8187,46.9245],[-91.8189,46.9246],[-91.819,46.9246],[-91.8192,46.9247],[-91.8194,46.9248],[-91.8196,46.9248],[-91.8198,46.9248],[-91.8202,46.9248],[-91.8204,46.9248],[-91.8206,46.9248],[-91.8208,46.9249],[-91.821,46.925],[-91.822,46.9252],[-91.8222,46.9253],[-91.8224,46.9253],[-91.8227,46.9254],[-91.8232,46.9256],[-91.8234,46.9257],[-91.8237,46.9259],[-91.8238,46.926],[-91.824,46.9261],[-91.8241,46.9262],[-91.8242,46.9262],[-91.8243,46.9263],[-91.8243,46.9264],[-91.8245,46.9265],[-91.8252,46.9267],[-91.8255,46.9269],[-91.8256,46.9269],[-91.8258,46.927],[-91.8259,46.9272],[-91.826,46.9272],[-91.826,46.9273],[-91.8265,46.9274],[-91.8267,46.9274],[-91.827,46.9275],[-91.8274,46.9275],[-91.8277,46.9275],[-91.828,46.9275],[-91.8283,46.9275],[-91.8286,46.9275],[-91.8289,46.9275],[-91.8292,46.9275],[-91.8295,46.9275],[-91.83,46.9275],[-91.8303,46.9275],[-91.8307,46.9275],[-91.831,46.9275],[-91.8314,46.9274],[-91.8318,46.9274],[-91.8321,46.9274],[-91.8325,46.9274],[-91.8327,46.9273],[-91.833,46.9273],[-91.8332,46.9273],[-91.8335,46.9272],[-91.8337,46.9272],[-91.8342,46.9269],[-91.8345,46.9268],[-91.8347,46.9267],[-91.8348,46.9267],[-91.8348,46.9266],[-91.8349,46.9266],[-91.835,46.9266],[-91.835,46.9267],[-91.8348,46.9268],[-91.8348,46.9269],[-91.8347,46.927],[-91.8347,46.9271],[-91.8346,46.9272],[-91.8348,46.9272],[-91.8351,46.9271],[-91.8352,46.927],[-91.8355,46.9269],[-91.8357,46.9269],[-91.8359,46.9268],[-91.8361,46.9268],[-91.8363,46.9268],[-91.8365,46.9267],[-91.8365,46.9267],[-91.8367,46.9266],[-91.8368,46.9266],[-91.8369,46.9265],[-91.8371,46.9265],[-91.8374,46.9265],[-91.8376,46.9265],[-91.8377,46.9265],[-91.8379,46.9264],[-91.8381,46.9263],[-91.8383,46.9262],[-91.8386,46.9261],[-91.8389,46.9261],[-91.8391,46.926],[-91.8393,46.9259],[-91.8396,46.9258],[-91.8398,46.9257],[-91.8401,46.9256],[-91.8405,46.9255],[-91.8407,46.9254],[-91.841,46.9253],[-91.8413,46.9253],[-91.8415,46.9252],[-91.8417,46.9251],[-91.8418,46.9251],[-91.8424,46.9248],[-91.8426,46.9246],[-91.8431,46.9244],[-91.8432,46.9243],[-91.8435,46.9242],[-91.8441,46.9239],[-91.8446,46.9238],[-91.8449,46.9236],[-91.8454,46.9234],[-91.8457,46.9233],[-91.8458,46.9232],[-91.8461,46.923],[-91.8464,46.9229],[-91.8466,46.9226],[-91.847,46.9224],[-91.8472,46.9223],[-91.8474,46.9221],[-91.8475,46.922],[-91.8476,46.9219],[-91.8477,46.9219],[-91.8478,46.9218],[-91.8481,46.9216],[-91.8484,46.9215],[-91.8486,46.9213],[-91.8488,46.9211],[-91.8491,46.9209],[-91.8493,46.9208],[-91.8495,46.9207],[-91.8497,46.9204],[-91.8499,46.9203],[-91.8501,46.9201],[-91.8502,46.9199],[-91.8504,46.9198],[-91.8505,46.9197],[-91.8506,46.9197],[-91.8511,46.9193],[-91.8512,46.9192],[-91.8513,46.919],[-91.8514,46.9188],[-91.8517,46.9185],[-91.8519,46.9182],[-91.8521,46.9179],[-91.8524,46.9175],[-91.8526,46.9171],[-91.8528,46.9168],[-91.8531,46.9165],[-91.8533,46.9162],[-91.8535,46.9158],[-91.8536,46.9156],[-91.8538,46.9155],[-91.854,46.9153],[-91.8542,46.9151],[-91.8544,46.915],[-91.8546,46.9148],[-91.8548,46.9146],[-91.855,46.9144],[-91.8551,46.9143],[-91.8552,46.9142],[-91.8553,46.9141],[-91.8555,46.9139],[-91.8557,46.9137],[-91.8559,46.9136],[-91.8562,46.9136],[-91.8565,46.9134],[-91.8568,46.9132],[-91.8569,46.9131],[-91.857,46.9131],[-91.8571,46.913],[-91.8572,46.9129],[-91.8576,46.9127],[-91.8579,46.9126],[-91.8581,46.9126],[-91.8583,46.9126],[-91.8584,46.9126],[-91.8585,46.9124],[-91.8588,46.9122],[-91.8591,46.912],[-91.8596,46.9116],[-91.8599,46.9115],[-91.8602,46.9114],[-91.8603,46.9113],[-91.8605,46.9112],[-91.8607,46.911],[-91.8609,46.9109],[-91.861,46.9108],[-91.8612,46.9107],[-91.8613,46.9106],[-91.8614,46.9105],[-91.8615,46.9104],[-91.8617,46.9103],[-91.8619,46.9102],[-91.8625,46.9101],[-91.863,46.91],[-91.8633,46.91],[-91.8635,46.9099],[-91.8637,46.9099],[-91.8639,46.9097],[-91.8642,46.9096],[-91.8644,46.9095],[-91.8644,46.9095],[-91.8646,46.9094],[-91.8648,46.9093],[-91.865,46.9092],[-91.8652,46.909],[-91.8654,46.9089],[-91.8656,46.9089],[-91.8659,46.9088],[-91.8662,46.9087],[-91.8664,46.9087],[-91.8666,46.9086],[-91.8668,46.9086],[-91.8675,46.9084],[-91.8679,46.9084],[-91.8681,46.9085],[-91.8684,46.9085],[-91.8686,46.9085],[-91.8688,46.9085],[-91.8691,46.9085],[-91.8693,46.9085],[-91.8705,46.9084],[-91.8709,46.9084],[-91.8711,46.9084],[-91.8714,46.9083],[-91.8717,46.9083],[-91.8724,46.9082],[-91.8734,46.9081],[-91.874,46.9081],[-91.8745,46.908],[-91.8749,46.908],[-91.8751,46.908],[-91.8755,46.9078],[-91.8758,46.9075],[-91.8761,46.9074],[-91.8764,46.9073],[-91.8766,46.9073],[-91.8768,46.9072],[-91.8772,46.9072],[-91.8775,46.9072],[-91.878,46.9071],[-91.8782,46.9071],[-91.879,46.9067],[-91.8797,46.9064],[-91.8802,46.9062],[-91.8807,46.906],[-91.8811,46.9058],[-91.8829,46.9047],[-91.885,46.9037],[-91.8854,46.9035],[-91.8856,46.9033],[-91.8858,46.9032],[-91.8859,46.903],[-91.8861,46.9029],[-91.8861,46.9028],[-91.8864,46.9027],[-91.8866,46.9026],[-91.8868,46.9025],[-91.8873,46.9021],[-91.8875,46.9019],[-91.8882,46.9015],[-91.8885,46.9015],[-91.8887,46.9015],[-91.8889,46.9015],[-91.8892,46.9014],[-91.8905,46.9005],[-91.891,46.9001],[-91.8912,46.8998],[-91.8915,46.8996],[-91.8918,46.8994],[-91.892,46.8994],[-91.8933,46.8987],[-91.8947,46.8979],[-91.895,46.8977],[-91.8953,46.8975],[-91.8955,46.8973],[-91.8956,46.8971],[-91.8957,46.8969],[-91.8961,46.8966],[-91.8971,46.8959],[-91.8976,46.8955],[-91.8981,46.8952],[-91.8986,46.895],[-91.8987,46.895],[-91.899,46.8949],[-91.8992,46.8948],[-91.8994,46.8947],[-91.9004,46.894],[-91.9009,46.8937],[-91.901,46.8935],[-91.9013,46.8933],[-91.9026,46.8928],[-91.9029,46.8926],[-91.9031,46.8925],[-91.9034,46.8923],[-91.9037,46.892],[-91.9038,46.892],[-91.904,46.892],[-91.9043,46.8917],[-91.9045,46.8915],[-91.9049,46.8912],[-91.9053,46.8909],[-91.9057,46.8906],[-91.9066,46.89],[-91.9069,46.8896],[-91.907,46.8894],[-91.9081,46.8887],[-91.9086,46.8881],[-91.9088,46.8879],[-91.909,46.8876],[-91.9093,46.8873],[-91.9098,46.8867],[-91.9102,46.8864],[-91.9106,46.8862],[-91.9108,46.8862],[-91.9109,46.886],[-91.911,46.8859],[-91.911,46.8858],[-91.9111,46.8857],[-91.9112,46.8856],[-91.9113,46.8855],[-91.9115,46.8852],[-91.9116,46.885],[-91.9118,46.8848],[-91.9122,46.8845],[-91.913,46.8839],[-91.9134,46.8837],[-91.9137,46.8836],[-91.9139,46.8836],[-91.9142,46.8836],[-91.9141,46.8835],[-91.9142,46.8834],[-91.9143,46.8833],[-91.9145,46.8832],[-91.9147,46.8831],[-91.915,46.883],[-91.9153,46.8829],[-91.9156,46.8827],[-91.9159,46.8826],[-91.9161,46.8824],[-91.9169,46.882],[-91.9173,46.8818],[-91.9178,46.8816],[-91.9191,46.8812],[-91.9194,46.8811],[-91.9197,46.881],[-91.9199,46.8808],[-91.9201,46.8807],[-91.9204,46.8805],[-91.9205,46.8805],[-91.9209,46.8804],[-91.9214,46.8803],[-91.9226,46.8799],[-91.923,46.8797],[-91.9235,46.8796],[-91.9244,46.8792],[-91.9256,46.8788],[-91.926,46.8786],[-91.9263,46.8786],[-91.9268,46.8784],[-91.9276,46.8781],[-91.928,46.878],[-91.9284,46.8777],[-91.9297,46.8771],[-91.9301,46.8769],[-91.9305,46.8767],[-91.9309,46.8764],[-91.9312,46.8762],[-91.9315,46.8761],[-91.9316,46.876],[-91.9317,46.8759],[-91.9318,46.8758],[-91.9319,46.8758],[-91.932,46.8757],[-91.9321,46.8755],[-91.9322,46.8755],[-91.9324,46.8754],[-91.9326,46.8753],[-91.9329,46.8752],[-91.9332,46.8752],[-91.9335,46.8751],[-91.9337,46.8751],[-91.9339,46.875],[-91.934,46.8749],[-91.9341,46.8748],[-91.9343,46.8746],[-91.9345,46.8744],[-91.9346,46.8743],[-91.9349,46.874],[-91.9353,46.8738],[-91.9358,46.8737],[-91.9362,46.8736],[-91.9368,46.8735],[-91.9374,46.8734],[-91.938,46.8734],[-91.9386,46.8732],[-91.9391,46.873],[-91.9397,46.8727],[-91.9403,46.8723],[-91.9408,46.8721],[-91.941,46.8719],[-91.9411,46.8717],[-91.9413,46.8717],[-91.9415,46.8718],[-91.9416,46.8717],[-91.9417,46.8717],[-91.9419,46.8715],[-91.942,46.8712],[-91.9422,46.871],[-91.9424,46.8709],[-91.9428,46.8708],[-91.943,46.8708],[-91.9432,46.8706],[-91.9435,46.8704],[-91.9438,46.8704],[-91.9444,46.8702],[-91.9449,46.8699],[-91.9456,46.8696],[-91.9465,46.8694],[-91.9475,46.8691],[-91.9484,46.8688],[-91.9492,46.8685],[-91.9496,46.8682],[-91.9499,46.8679],[-91.9502,46.8678],[-91.9507,46.8677],[-91.9513,46.8675],[-91.952,46.8671],[-91.9524,46.8668],[-91.9527,46.8665],[-91.953,46.8662],[-91.9535,46.8659],[-91.9536,46.8658],[-91.9545,46.8654],[-91.9552,46.8651],[-91.956,46.8645],[-91.9565,46.8641],[-91.9568,46.8638],[-91.957,46.8636],[-91.9574,46.8633],[-91.9577,46.8631],[-91.9581,46.8628],[-91.9587,46.8623],[-91.959,46.8619],[-91.9593,46.8617],[-91.9596,46.8616],[-91.96,46.8614],[-91.9604,46.8612],[-91.9608,46.8609],[-91.9611,46.8605],[-91.9615,46.8602],[-91.9621,46.86],[-91.9627,46.8597],[-91.963,46.8596],[-91.9633,46.8595],[-91.964,46.8592],[-91.9646,46.8589],[-91.965,46.8586],[-91.9654,46.8582],[-91.9657,46.858],[-91.966,46.8579],[-91.9663,46.8578],[-91.9667,46.8576],[-91.9669,46.8576],[-91.967,46.8575],[-91.9671,46.8574],[-91.9672,46.8573],[-91.9673,46.8571],[-91.9675,46.857],[-91.9677,46.857],[-91.9679,46.8571],[-91.9681,46.857],[-91.9683,46.8569],[-91.9686,46.8568],[-91.9688,46.8567],[-91.9692,46.8565],[-91.9695,46.8564],[-91.97,46.8563],[-91.9704,46.8563],[-91.9708,46.8562],[-91.9711,46.8561],[-91.9714,46.8562],[-91.9716,46.8561],[-91.972,46.8559],[-91.9724,46.8558],[-91.9728,46.8558],[-91.9731,46.8559],[-91.9732,46.8558],[-91.9734,46.8557],[-91.9736,46.8556],[-91.974,46.8555],[-91.9741,46.8554],[-91.9742,46.8553],[-91.9745,46.8552],[-91.9748,46.8551],[-91.9751,46.8549],[-91.9754,46.8547],[-91.9755,46.8548],[-91.9757,46.8548],[-91.9762,46.8546],[-91.9764,46.8545],[-91.9767,46.8542],[-91.977,46.8539],[-91.9772,46.8537],[-91.9773,46.8534],[-91.9775,46.8533],[-91.9777,46.8533],[-91.978,46.8532],[-91.9784,46.853],[-91.9787,46.8529],[-91.9791,46.8526],[-91.9792,46.8525],[-91.9795,46.8524],[-91.9797,46.8523],[-91.98,46.8521],[-91.9802,46.8519],[-91.9805,46.8517],[-91.9808,46.8516],[-91.9811,46.8515],[-91.9815,46.8515],[-91.9819,46.8513],[-91.982,46.8513],[-91.9827,46.851],[-91.983,46.8508],[-91.9833,46.8506],[-91.9836,46.8504],[-91.9838,46.8503],[-91.9841,46.8503],[-91.9842,46.8502],[-91.9845,46.8501],[-91.9849,46.8499],[-91.9854,46.8496],[-91.9856,46.8495],[-91.9857,46.8493],[-91.9858,46.8491],[-91.986,46.8489],[-91.9861,46.8487],[-91.9863,46.8484],[-91.9866,46.8482],[-91.9869,46.848],[-91.987,46.8478],[-91.9871,46.8476],[-91.9875,46.8476],[-91.9877,46.8474],[-91.9881,46.8471],[-91.9884,46.8469],[-91.9885,46.8467],[-91.9885,46.8465],[-91.9887,46.8462],[-91.9889,46.846],[-91.9892,46.8458],[-91.9895,46.8456],[-91.9898,46.8455],[-91.9901,46.8454],[-91.9903,46.8451],[-91.9906,46.845],[-91.9908,46.8448],[-91.991,46.8446],[-91.9913,46.8443],[-91.9915,46.844],[-91.9918,46.8437],[-91.992,46.8434],[-91.9923,46.8431],[-91.9926,46.8427],[-91.9928,46.8424],[-91.9931,46.8422],[-91.9934,46.8421],[-91.9938,46.842],[-91.9941,46.8419],[-91.9944,46.8417],[-91.9949,46.8414],[-91.9954,46.8411],[-91.9959,46.8409],[-91.9964,46.8407],[-91.9969,46.8405],[-91.9973,46.8403],[-91.9978,46.84],[-91.9981,46.8397],[-91.9983,46.8395],[-91.9983,46.8392],[-91.9985,46.839],[-91.9986,46.8389],[-91.999,46.8387],[-91.9992,46.8386],[-91.9997,46.8384],[-92.0001,46.8381],[-92.0002,46.8381],[-92.0003,46.8382],[-92.0005,46.8381],[-92.0007,46.838],[-92.0009,46.838],[-92.0012,46.8379],[-92.0014,46.8377],[-92.0016,46.8375],[-92.0019,46.8374],[-92.0022,46.8373],[-92.0025,46.8373],[-92.003,46.8372],[-92.0033,46.8372],[-92.0036,46.8372],[-92.0039,46.8372],[-92.0041,46.8371],[-92.0042,46.837],[-92.0044,46.8369],[-92.0045,46.8369],[-92.0048,46.8367],[-92.0051,46.8366],[-92.0055,46.8366],[-92.0055,46.8366],[-92.0058,46.8364],[-92.0059,46.8363],[-92.0059,46.8362],[-92.0059,46.8361],[-92.006,46.8361],[-92.0061,46.836],[-92.0062,46.8359],[-92.0064,46.8359],[-92.0068,46.8358],[-92.007,46.8358],[-92.0072,46.8358],[-92.0074,46.8358],[-92.0078,46.8357],[-92.008,46.8357],[-92.0083,46.8357],[-92.0086,46.8356],[-92.0088,46.8356],[-92.009,46.8356],[-92.0093,46.8356],[-92.0096,46.8356],[-92.0101,46.8355],[-92.0105,46.8354],[-92.0106,46.8354],[-92.0109,46.8353],[-92.0112,46.8352],[-92.0115,46.8351],[-92.0117,46.8351],[-92.0118,46.835],[-92.012,46.835],[-92.0125,46.8348],[-92.0126,46.8348],[-92.0128,46.8346],[-92.013,46.8345],[-92.0132,46.8344],[-92.0134,46.8343],[-92.0136,46.8342],[-92.0137,46.8342],[-92.0139,46.834],[-92.0141,46.8338],[-92.0143,46.8338],[-92.0143,46.8337],[-92.0145,46.8336],[-92.0147,46.8336],[-92.0149,46.8336],[-92.0152,46.8336],[-92.0156,46.8336],[-92.016,46.8335],[-92.0165,46.8334],[-92.0169,46.8334],[-92.0172,46.8333],[-92.0177,46.8331],[-92.018,46.833],[-92.0184,46.8327],[-92.0185,46.8326],[-92.0187,46.8324],[-92.0189,46.8322],[-92.019,46.8321],[-92.0192,46.8319],[-92.0193,46.8318],[-92.0193,46.8317],[-92.0194,46.8317],[-92.0196,46.8316],[-92.0198,46.8316],[-92.0201,46.8315],[-92.0206,46.8314],[-92.0209,46.8313],[-92.0213,46.8312],[-92.0214,46.8311],[-92.0218,46.8309],[-92.0221,46.8307],[-92.0225,46.8305],[-92.023,46.8302],[-92.0234,46.83],[-92.0236,46.8298],[-92.0238,46.8296],[-92.024,46.8295],[-92.0241,46.8294],[-92.0243,46.8293],[-92.0245,46.8292],[-92.0247,46.8291],[-92.0249,46.8291],[-92.025,46.829],[-92.0252,46.8289],[-92.0253,46.8288],[-92.0255,46.8286],[-92.0256,46.8284],[-92.0257,46.8283],[-92.0259,46.8282],[-92.0261,46.828],[-92.0263,46.8277],[-92.0264,46.8276],[-92.0266,46.8274],[-92.0267,46.8272],[-92.0267,46.8271],[-92.0268,46.827],[-92.0268,46.827],[-92.0268,46.8269],[-92.0269,46.8268],[-92.027,46.8267],[-92.0272,46.8266],[-92.0272,46.8266],[-92.0274,46.8265],[-92.0275,46.8265],[-92.0276,46.8264],[-92.0277,46.8263],[-92.0277,46.8262],[-92.0277,46.8261],[-92.0278,46.826],[-92.0278,46.826],[-92.0278,46.8259],[-92.0279,46.8259],[-92.0281,46.8258],[-92.0282,46.8256],[-92.0283,46.8255],[-92.0284,46.8254],[-92.0285,46.8252],[-92.0285,46.825],[-92.0287,46.8249],[-92.0287,46.8248],[-92.0289,46.8246],[-92.0291,46.8245],[-92.0294,46.8244],[-92.0295,46.8242],[-92.0297,46.8242],[-92.0299,46.8241],[-92.0301,46.824],[-92.0303,46.824],[-92.0307,46.824],[-92.0309,46.8239],[-92.0311,46.8238],[-92.0313,46.8237],[-92.0315,46.8236],[-92.0316,46.8234],[-92.0317,46.8233],[-92.0318,46.8231],[-92.0318,46.8231],[-92.0319,46.823],[-92.032,46.8229],[-92.0322,46.8228],[-92.0326,46.8226],[-92.0329,46.8224],[-92.0329,46.8224],[-92.0333,46.8222],[-92.0335,46.8222],[-92.0337,46.8221],[-92.0338,46.822],[-92.0339,46.8219],[-92.0343,46.8218],[-92.0347,46.8218],[-92.0352,46.8217],[-92.0358,46.8215],[-92.0364,46.8214],[-92.0369,46.8213],[-92.0372,46.8212],[-92.0376,46.8211],[-92.038,46.8209],[-92.0382,46.8207],[-92.0384,46.8205],[-92.0385,46.8204],[-92.0386,46.8203],[-92.0387,46.8203],[-92.0388,46.8202],[-92.0389,46.8202],[-92.0392,46.8202],[-92.0397,46.8201],[-92.04,46.8201],[-92.0401,46.8202],[-92.0405,46.8202],[-92.0408,46.8203],[-92.0411,46.8203],[-92.0414,46.8203],[-92.0417,46.8203],[-92.0419,46.8202],[-92.0421,46.8201],[-92.0423,46.8201],[-92.0425,46.82],[-92.0427,46.82],[-92.0429,46.82],[-92.0431,46.8199],[-92.0434,46.8197],[-92.0437,46.8196],[-92.044,46.8195],[-92.0441,46.8194],[-92.0443,46.8193],[-92.0445,46.8193],[-92.0447,46.8192],[-92.045,46.8191],[-92.0452,46.819],[-92.0454,46.8189],[-92.0456,46.8188],[-92.0457,46.8187],[-92.0459,46.8186],[-92.046,46.8185],[-92.0461,46.8183],[-92.0462,46.8182],[-92.0462,46.8181],[-92.0463,46.818],[-92.0463,46.8179],[-92.0464,46.8178],[-92.0465,46.8177],[-92.0466,46.8175],[-92.0467,46.8174],[-92.0468,46.8173],[-92.0469,46.8173],[-92.0469,46.8173],[-92.0471,46.8172],[-92.0473,46.8171],[-92.0474,46.8171],[-92.0476,46.8169],[-92.0478,46.8169],[-92.048,46.8167],[-92.0481,46.8166],[-92.0481,46.8165],[-92.0482,46.8164],[-92.0483,46.8164],[-92.0484,46.8163],[-92.0485,46.8162],[-92.0486,46.8161],[-92.0489,46.816],[-92.049,46.8158],[-92.0492,46.8157],[-92.0494,46.8156],[-92.0495,46.8155],[-92.0497,46.8154],[-92.0498,46.8151],[-92.0499,46.815],[-92.05,46.8148],[-92.0501,46.8146],[-92.0503,46.8144],[-92.0504,46.8144],[-92.0505,46.8144],[-92.0507,46.8144],[-92.0509,46.8143],[-92.0511,46.8143],[-92.0513,46.8143],[-92.0517,46.8142],[-92.0519,46.8142],[-92.0523,46.814],[-92.0525,46.8139],[-92.0527,46.8138],[-92.0529,46.8137],[-92.0531,46.8135],[-92.0533,46.8132],[-92.0535,46.8131],[-92.0537,46.8128],[-92.0539,46.8126],[-92.054,46.8124],[-92.054,46.8123],[-92.0542,46.812],[-92.0544,46.8118],[-92.0546,46.8117],[-92.0549,46.8115],[-92.0551,46.8115],[-92.0553,46.8113],[-92.0556,46.8112],[-92.0559,46.811],[-92.0563,46.8109],[-92.0566,46.8108],[-92.0569,46.8107],[-92.0573,46.8106],[-92.0575,46.8106],[-92.0581,46.8106],[-92.0583,46.8105],[-92.0587,46.8104],[-92.0588,46.8103],[-92.059,46.8101],[-92.0593,46.8099],[-92.0594,46.8097],[-92.0595,46.8095],[-92.0597,46.8092],[-92.0598,46.809],[-92.06,46.8087],[-92.06,46.8084],[-92.0602,46.808],[-92.0602,46.8078],[-92.0603,46.8074],[-92.0605,46.8071],[-92.0606,46.8069],[-92.0608,46.8066],[-92.061,46.8065],[-92.0611,46.8063],[-92.0612,46.8061],[-92.0612,46.8059],[-92.0613,46.8057],[-92.0616,46.8054],[-92.0617,46.8052],[-92.0619,46.8049],[-92.0621,46.8047],[-92.0622,46.8045],[-92.0625,46.8044],[-92.0627,46.8042],[-92.063,46.8041],[-92.0634,46.8039],[-92.0637,46.8038],[-92.064,46.8037],[-92.0642,46.8037],[-92.0646,46.8035],[-92.0649,46.8034],[-92.0652,46.8033],[-92.0656,46.8031],[-92.0659,46.803],[-92.0662,46.8028],[-92.0665,46.8026],[-92.0668,46.8024],[-92.067,46.8024],[-92.0674,46.8023],[-92.0677,46.8022],[-92.068,46.8022],[-92.0682,46.8023],[-92.0685,46.8023],[-92.0686,46.8023],[-92.0686,46.8023],[-92.0689,46.8024],[-92.0691,46.8023],[-92.0694,46.8023],[-92.0696,46.8022],[-92.0699,46.802],[-92.0702,46.8018],[-92.0705,46.8016],[-92.0707,46.8014],[-92.0708,46.8012],[-92.071,46.801],[-92.0712,46.8008],[-92.0713,46.8007],[-92.0715,46.8006],[-92.0716,46.8006],[-92.0718,46.8006],[-92.072,46.8007],[-92.0721,46.8007],[-92.0723,46.8006],[-92.0726,46.8006],[-92.0728,46.8005],[-92.0731,46.8004],[-92.0736,46.8002],[-92.0739,46.8],[-92.0741,46.7999],[-92.0743,46.7997],[-92.0746,46.7995],[-92.0749,46.7994],[-92.0752,46.7993],[-92.0755,46.7992],[-92.0758,46.7991],[-92.0762,46.7989],[-92.0764,46.7988],[-92.0765,46.7986],[-92.0766,46.7985],[-92.0767,46.7983],[-92.0769,46.7983],[-92.0771,46.7983],[-92.0774,46.7983],[-92.0775,46.7982],[-92.0777,46.7981],[-92.0778,46.798],[-92.0779,46.7979],[-92.078,46.7978],[-92.078,46.7977],[-92.0781,46.7975],[-92.0782,46.7974],[-92.0783,46.7973],[-92.0785,46.7973],[-92.0785,46.7973],[-92.0787,46.7974],[-92.0788,46.7974],[-92.0791,46.7974],[-92.0794,46.7973],[-92.0796,46.7973],[-92.0798,46.7973],[-92.0801,46.7973],[-92.0804,46.7973],[-92.0806,46.7973],[-92.0809,46.7972],[-92.0812,46.7971],[-92.0814,46.797],[-92.0815,46.7969],[-92.0817,46.7967],[-92.0819,46.7966],[-92.082,46.7965],[-92.0821,46.7963],[-92.0821,46.7962],[-92.0822,46.796],[-92.0823,46.7959],[-92.0825,46.7959],[-92.0828,46.7958],[-92.0831,46.7958],[-92.0835,46.7957],[-92.0838,46.7957],[-92.0841,46.7957],[-92.0844,46.7957],[-92.0847,46.7957],[-92.085,46.7957],[-92.0853,46.7956],[-92.0856,46.7955],[-92.0857,46.7954],[-92.0858,46.7953],[-92.0859,46.7952],[-92.0861,46.7951],[-92.0862,46.795],[-92.0863,46.7948],[-92.0864,46.7947],[-92.0867,46.7946],[-92.0869,46.7945],[-92.0872,46.7944],[-92.0875,46.7943],[-92.0878,46.7941],[-92.0881,46.794],[-92.0884,46.7938],[-92.0886,46.7937],[-92.0889,46.7935],[-92.0891,46.7933],[-92.0892,46.7931],[-92.0892,46.7931],[-92.0893,46.7929],[-92.0895,46.7926],[-92.0897,46.7924],[-92.0899,46.7923],[-92.0901,46.7921],[-92.0902,46.792],[-92.0903,46.7919],[-92.0904,46.7917],[-92.0903,46.7916],[-92.0903,46.7915],[-92.0903,46.7913],[-92.0904,46.7912],[-92.0905,46.791],[-92.0905,46.7908],[-92.0907,46.7905],[-92.0908,46.7902],[-92.091,46.7898],[-92.0912,46.7896],[-92.0913,46.7895],[-92.0915,46.7893],[-92.0918,46.7892],[-92.092,46.7892],[-92.0923,46.7892],[-92.0928,46.7889],[-92.0929,46.7888],[-92.0932,46.7887],[-92.0934,46.7885],[-92.0936,46.7883],[-92.0938,46.7881],[-92.0939,46.788],[-92.094,46.7877],[-92.0941,46.7875],[-92.0941,46.7874],[-92.094,46.7872],[-92.094,46.7871],[-92.094,46.7869],[-92.0939,46.7867],[-92.0938,46.7864],[-92.0936,46.786],[-92.0935,46.7857],[-92.0934,46.7854],[-92.0934,46.7852],[-92.0933,46.7849],[-92.0932,46.7848],[-92.0932,46.7845],[-92.0931,46.7842],[-92.093,46.7839],[-92.0929,46.7836],[-92.0926,46.7832],[-92.0925,46.783],[-92.0924,46.7828],[-92.0923,46.7826],[-92.0921,46.7825],[-92.092,46.7823],[-92.0919,46.7821],[-92.0918,46.7819],[-92.0917,46.7817],[-92.0916,46.7814],[-92.0915,46.7813],[-92.0913,46.781],[-92.0911,46.7807],[-92.091,46.7804],[-92.0912,46.7801],[-92.0914,46.7787],[-92.0914,46.7784],[-92.0909,46.7775],[-92.0908,46.7773],[-92.09,46.7762],[-92.0897,46.7757],[-92.0894,46.7754],[-92.0892,46.7751],[-92.0889,46.7747],[-92.0888,46.7743],[-92.0879,46.7731],[-92.0879,46.773],[-92.0878,46.773],[-92.0876,46.7727],[-92.0859,46.7704],[-92.0859,46.7702],[-92.0849,46.7691],[-92.0846,46.7687],[-92.0842,46.7682],[-92.0838,46.7676],[-92.0829,46.7665],[-92.0829,46.7664],[-92.0826,46.7659],[-92.0819,46.7651],[-92.0812,46.7644],[-92.0811,46.7642],[-92.0784,46.7609],[-92.0781,46.7606],[-92.0768,46.759],[-92.0767,46.7588],[-92.0765,46.7587],[-92.0764,46.7584],[-92.076,46.7581],[-92.0758,46.7578],[-92.0739,46.7555],[-92.0735,46.7552],[-92.0735,46.755],[-92.073,46.7546],[-92.0729,46.7544],[-92.0726,46.754],[-92.0724,46.754],[-92.0724,46.7538],[-92.0717,46.7532],[-92.0716,46.753],[-92.0707,46.7521],[-92.0706,46.7519],[-92.0703,46.7517],[-92.0694,46.7506],[-92.0693,46.7505],[-92.069,46.7502],[-92.0688,46.75],[-92.0686,46.7497],[-92.0684,46.7495],[-92.0681,46.7491],[-92.0679,46.7489],[-92.0677,46.7487],[-92.0676,46.7486],[-92.0672,46.7481],[-92.0668,46.7478],[-92.0658,46.7466],[-92.0633,46.7441],[-92.0629,46.7437],[-92.0628,46.7435],[-92.0625,46.7432],[-92.0623,46.743],[-92.062,46.7427],[-92.0618,46.7424],[-92.0614,46.7421],[-92.0613,46.7419],[-92.0607,46.7414],[-92.0597,46.7403],[-92.0592,46.7399],[-92.0588,46.7394],[-92.0575,46.7381],[-92.0568,46.7374],[-92.0563,46.737],[-92.0559,46.7366],[-92.0546,46.7353],[-92.0546,46.7352],[-92.0544,46.7352],[-92.0542,46.735],[-92.054,46.7347],[-92.0504,46.7315],[-92.0477,46.7291],[-92.0466,46.7282],[-92.0466,46.728],[-92.0463,46.7279],[-92.0459,46.7275],[-92.0448,46.7265],[-92.0376,46.7206],[-92.037,46.7201],[-92.0348,46.7183],[-92.0274,46.7118],[-92.0269,46.7114],[-92.0267,46.7113],[-92.0265,46.7112],[-92.0264,46.7112],[-92.0258,46.7114],[-92.0253,46.7111],[-92.0243,46.7109],[-92.0214,46.7108],[-92.0205,46.7107],[-92.0194,46.7106],[-92.0192,46.7102],[-92.0192,46.7099],[-92.0187,46.7088],[-92.0174,46.7072],[-92.0164,46.7062],[-92.0163,46.706],[-92.0202,46.7041],[-92.025,46.7058],[-92.0262,46.7062],[-92.0269,46.7065],[-92.0339,46.709],[-92.0428,46.7153],[-92.0479,46.719],[-92.0501,46.7206],[-92.0594,46.7274],[-92.0648,46.7312],[-92.0687,46.734],[-92.0701,46.735],[-92.0713,46.7359],[-92.0894,46.7493],[-92.0985,46.7491],[-92.1001,46.7491],[-92.1081,46.7492],[-92.1086,46.749],[-92.1102,46.749],[-92.1138,46.7489],[-92.1165,46.7487],[-92.1173,46.7484],[-92.1184,46.7479],[-92.1252,46.745],[-92.1317,46.7422],[-92.1378,46.7396],[-92.1428,46.7351],[-92.1429,46.735],[-92.1432,46.7347],[-92.1433,46.7306],[-92.1433,46.7282],[-92.1412,46.7253],[-92.1438,46.7205],[-92.1448,46.7184],[-92.1462,46.716],[-92.1467,46.7158],[-92.1486,46.7152],[-92.1534,46.7158],[-92.1551,46.716],[-92.1672,46.72],[-92.1708,46.7189],[-92.1719,46.7185],[-92.1742,46.7173],[-92.1747,46.7172],[-92.176,46.7171],[-92.1788,46.7168],[-92.189,46.7176],[-92.1914,46.7163],[-92.1916,46.7157],[-92.1917,46.7153],[-92.1932,46.7113],[-92.1959,46.7089],[-92.1973,46.7077],[-92.1997,46.7067],[-92.2003,46.7064],[-92.2004,46.7064],[-92.201,46.7062],[-92.2015,46.706],[-92.2019,46.7058],[-92.2026,46.7054],[-92.2046,46.7041],[-92.2056,46.7026],[-92.2051,46.6984],[-92.1984,46.6962],[-92.1956,46.696],[-92.1892,46.6956],[-92.183,46.6953],[-92.178,46.692],[-92.1778,46.6919],[-92.1764,46.6903],[-92.176,46.6864],[-92.1775,46.6835],[-92.1813,46.6803],[-92.1824,46.68],[-92.1875,46.679],[-92.1906,46.6776],[-92.1916,46.6772],[-92.1924,46.6768],[-92.1957,46.6741],[-92.1958,46.674],[-92.1994,46.6703],[-92.204,46.667],[-92.2054,46.6648],[-92.2046,46.6634],[-92.2021,46.659],[-92.2015,46.6567],[-92.2022,46.6551],[-92.2044,46.6537],[-92.207,46.652],[-92.2123,46.65],[-92.2163,46.6499],[-92.2166,46.65],[-92.2234,46.6527],[-92.2262,46.6529],[-92.2284,46.653],[-92.2355,46.6501],[-92.2376,46.6498],[-92.2424,46.6493],[-92.2486,46.6535],[-92.2509,46.655],[-92.2521,46.6558],[-92.2525,46.6561],[-92.2545,46.6574],[-92.2549,46.6577],[-92.2556,46.6581],[-92.2565,46.6588],[-92.2587,46.6577],[-92.2596,46.6572],[-92.2659,46.6511],[-92.2705,46.6508],[-92.2727,46.6529],[-92.2735,46.655],[-92.2743,46.6575],[-92.2784,46.6587],[-92.2799,46.6587],[-92.2836,46.6589],[-92.2842,46.6592],[-92.2844,46.6594],[-92.2861,46.6604],[-92.287,46.6629],[-92.2871,46.6631],[-92.2872,46.6647],[-92.2873,46.6669],[-92.2873,46.6674],[-92.2881,46.6676],[-92.2907,46.6681],[-92.2912,46.6682],[-92.2921,46.6661],[-92.2922,46.665],[-92.2921,46.6633],[-92.301,46.6636],[-92.3012,46.6773],[-92.3012,46.6919],[-92.3013,46.7063],[-92.3014,46.7208],[-92.3016,46.7353],[-92.3014,46.7498],[-92.3015,46.7643],[-92.3223,46.7652],[-92.3435,46.7651],[-92.3646,46.765],[-92.3856,46.765],[-92.4064,46.7649],[-92.4283,46.765],[-92.4495,46.7657],[-92.4705,46.7656],[-92.4924,46.7657],[-92.5125,46.7658],[-92.5336,46.7659],[-92.5548,46.7662],[-92.5759,46.7667],[-92.5967,46.7665],[-92.6177,46.7667],[-92.6385,46.767],[-92.6592,46.7692],[-92.6803,46.7692],[-92.7014,46.7687],[-92.7226,46.7682],[-92.7442,46.7677],[-92.7459,46.7677],[-92.7653,46.7674],[-92.7864,46.7666],[-92.8084,46.7661],[-92.8296,46.7661],[-92.8508,46.7662],[-92.8721,46.7664],[-92.8932,46.7666],[-92.9143,46.7661],[-92.9356,46.7662],[-92.9567,46.7662],[-92.9777,46.7665],[-92.9988,46.7669],[-93.0201,46.7668],[-93.0412,46.7667],[-93.0615,46.7667],[-93.0609,46.781],[-93.061,46.7956],[-93.0606,46.81],[-93.0606,46.8241],[-93.0603,46.8387],[-93.06,46.853],[-93.0597,46.8672],[-93.059,46.8817],[-93.0587,46.8964],[-93.0582,46.9108],[-93.0583,46.9251],[-93.0577,46.9398],[-93.0576,46.9541],[-93.0573,46.9685],[-93.0571,46.9832],[-93.0568,46.9976],[-93.0564,47.0121],[-93.0559,47.0265],[-93.0557,47.0407],[-93.0558,47.0551],[-93.0558,47.0698],[-93.0557,47.084],[-93.056,47.0984],[-93.0562,47.1093],[-93.0664,47.1094],[-93.0663,47.1239],[-93.0659,47.1382],[-93.0659,47.1526],[-93.0655,47.1671],[-93.0652,47.1814],[-93.0654,47.196],[-93.0654,47.2103],[-93.0655,47.2248],[-93.0657,47.2394],[-93.0658,47.2538],[-93.0657,47.2683],[-93.0658,47.2828],[-93.0658,47.2975],[-93.0652,47.3119],[-93.0647,47.3265],[-93.0645,47.3412],[-93.0644,47.3556],[-93.0644,47.3716],[-93.0666,47.3716],[-93.0689,47.386],[-93.0693,47.4003],[-93.0692,47.4148],[-93.0692,47.429],[-93.069,47.4434],[-93.0688,47.4578],[-93.0673,47.472],[-93.067,47.4859],[-93.0651,47.5003],[-93.0647,47.5147],[-93.0641,47.529],[-93.0637,47.5445],[-93.0637,47.559],[-93.0638,47.5734],[-93.0628,47.5875],[-93.0628,47.6026],[-93.0643,47.6172],[-93.0637,47.6333],[-93.0637,47.6476],[-93.0633,47.6621],[-93.0626,47.6774],[-93.0619,47.691],[-93.0612,47.7056],[-93.0613,47.7205],[-93.0821,47.7206],[-93.0823,47.7355],[-93.0823,47.7493],[-93.0826,47.7635],[-93.083,47.7779],[-93.0834,47.7917],[-93.0837,47.8064],[-93.0837,47.8209],[-93.0837,47.8223],[-93.0831,47.835],[-93.083,47.8368],[-93.0823,47.8494],[-93.0822,47.8513],[-93.0815,47.8637],[-93.0813,47.8656],[-93.0812,47.8676],[-93.0808,47.878],[-93.0807,47.88],[-93.0808,47.8922],[-93.0808,47.8945],[-93.0809,47.9067],[-93.0809,47.9088],[-93.0809,47.9212],[-93.0809,47.9235],[-93.0809,47.9356],[-93.0809,47.938],[-93.0808,47.9504],[-93.0808,47.9525],[-93.0808,47.9647],[-93.0809,47.967],[-93.0809,47.9786],[-93.088,47.9787],[-93.0872,47.9932],[-93.0887,48.0075],[-93.0886,48.022],[-93.089,48.0366],[-93.0892,48.0509],[-93.0892,48.0679],[-93.0965,48.0678],[-93.0965,48.0679],[-93.0968,48.0823],[-93.097,48.0969],[-93.0972,48.1114],[-93.0969,48.1259],[-93.097,48.1402],[-93.097,48.1546],[-93.097,48.1692],[-93.0975,48.1836],[-93.0979,48.1981],[-93.0978,48.2126],[-93.0977,48.2271],[-93.0977,48.2426],[-93.0949,48.2425],[-93.0949,48.2426],[-93.0953,48.2576],[-93.0952,48.2716],[-93.095,48.2862],[-93.0952,48.3004],[-93.0953,48.3153],[-93.0948,48.3298],[-93.0948,48.3442],[-93.0945,48.3589],[-93.094,48.3734],[-93.094,48.3879],[-93.0938,48.4024],[-93.0935,48.4147],[-93.0923,48.4147],[-93.0922,48.429],[-93.0922,48.4303],[-93.092,48.4436],[-93.092,48.4449],[-93.0919,48.458],[-93.0918,48.4596],[-93.0915,48.4724],[-93.0914,48.474],[-93.0911,48.4867],[-93.091,48.4884],[-93.0905,48.501],[-93.0905,48.5151],[-93.0903,48.5296],[-93.0902,48.5441],[-93.0902,48.5583],[-93.09,48.5727],[-93.0898,48.5872],[-93.0895,48.6016],[-93.0886,48.6163],[-93.0884,48.6278]]],"type":"Polygon"},"id":"69","properties":{"Area":17451037319.2417,"CTYONLY_":7,"Code":"STLO","LASTMOD":"2010-10-17T00:00:00Z","Name":"St. Louis","Perimiter":682518.436},"type":"Feature"},{"geometry":{"coordinates":[[[-95.3425,48.5402],[-95.3412,48.5402],[-95.321,48.54],[-95.3194,48.54],[-95.2992,48.5402],[-95.2975,48.5401],[-95.2773,48.54],[-95.2756,48.54],[-95.2554,48.5398],[-95.2537,48.5398],[-95.2339,48.5399],[-95.2324,48.5399],[-95.2119,48.54],[-95.2115,48.5252],[-95.2115,48.5244],[-95.2111,48.5109],[-95.2111,48.5101],[-95.2112,48.4962],[-95.2111,48.4816],[-95.211,48.4673],[-95.211,48.4666],[-95.2112,48.4529],[-95.2113,48.4522],[-95.2113,48.4387],[-95.2113,48.4376],[-95.2113,48.4255],[-95.2113,48.4242],[-95.2113,48.4232],[-95.2112,48.4096],[-95.2112,48.4087],[-95.2111,48.3952],[-95.2111,48.3941],[-95.211,48.3808],[-95.211,48.3797],[-95.2106,48.3661],[-95.2066,48.3661],[-95.1983,48.3661],[-95.1887,48.3661],[-95.1861,48.3661],[-95.1669,48.3661],[-95.164,48.3661],[-95.1454,48.3662],[-95.1424,48.3662],[-95.1315,48.3662],[-95.1236,48.3663],[-95.1207,48.3663],[-95.1018,48.3663],[-95.1008,48.3663],[-95.099,48.3663],[-95.0801,48.3664],[-95.0773,48.3664],[-95.0586,48.3665],[-95.0555,48.3665],[-95.0369,48.3665],[-95.0337,48.3665],[-95.0153,48.3665],[-95.0119,48.3665],[-94.9932,48.3667],[-94.9901,48.3667],[-94.9716,48.3667],[-94.9684,48.3667],[-94.95,48.3666],[-94.9469,48.3666],[-94.9283,48.3667],[-94.9264,48.3667],[-94.9065,48.3666],[-94.9049,48.3666],[-94.8849,48.3666],[-94.8833,48.3667],[-94.8632,48.3667],[-94.8616,48.3667],[-94.8416,48.3669],[-94.8399,48.3669],[-94.8199,48.3669],[-94.8183,48.3669],[-94.7983,48.3669],[-94.7967,48.3669],[-94.7765,48.3669],[-94.7748,48.3669],[-94.7549,48.3669],[-94.7533,48.3669],[-94.7329,48.3669],[-94.7315,48.3669],[-94.7117,48.3668],[-94.7099,48.3669],[-94.6898,48.3671],[-94.683,48.3671],[-94.6694,48.3672],[-94.6679,48.3673],[-94.6622,48.3673],[-94.6505,48.3673],[-94.6465,48.3673],[-94.6405,48.3673],[-94.6245,48.3673],[-94.6188,48.3673],[-94.6029,48.3674],[-94.5971,48.3675],[-94.5812,48.3674],[-94.5754,48.3674],[-94.5593,48.3674],[-94.5536,48.3674],[-94.5378,48.3674],[-94.5335,48.3674],[-94.5157,48.3674],[-94.5118,48.3675],[-94.4941,48.3674],[-94.4924,48.3674],[-94.4906,48.3674],[-94.4722,48.3674],[-94.4688,48.3675],[-94.4505,48.3675],[-94.4471,48.3675],[-94.4288,48.3675],[-94.4252,48.3675],[-94.4253,48.352],[-94.425,48.3372],[-94.4248,48.3227],[-94.4246,48.3081],[-94.4244,48.2938],[-94.4243,48.2791],[-94.424,48.2649],[-94.4237,48.2504],[-94.4237,48.2356],[-94.4238,48.2212],[-94.4236,48.2067],[-94.4233,48.1923],[-94.4235,48.1781],[-94.4235,48.1637],[-94.4233,48.1491],[-94.4236,48.1348],[-94.4234,48.1204],[-94.4233,48.1059],[-94.4231,48.092],[-94.4234,48.0776],[-94.4247,48.0632],[-94.4246,48.0489],[-94.4241,48.0344],[-94.4236,48.0199],[-94.4176,48.02],[-94.4177,48.006],[-94.4176,47.9914],[-94.4173,47.9769],[-94.4172,47.9623],[-94.4174,47.9477],[-94.4175,47.9332],[-94.4174,47.9186],[-94.4175,47.9175],[-94.4176,47.9041],[-94.4177,47.9031],[-94.418,47.8886],[-94.4184,47.8744],[-94.4186,47.86],[-94.4185,47.8459],[-94.4186,47.8316],[-94.4187,47.817],[-94.4188,47.8026],[-94.4189,47.7881],[-94.4189,47.7735],[-94.4191,47.759],[-94.4192,47.7445],[-94.4191,47.7302],[-94.419,47.7155],[-94.4187,47.7012],[-94.4185,47.6867],[-94.4184,47.6721],[-94.417,47.6722],[-94.417,47.6578],[-94.4167,47.6435],[-94.4165,47.6291],[-94.4163,47.615],[-94.4159,47.6009],[-94.4136,47.5866],[-94.4144,47.5723],[-94.414,47.5578],[-94.4148,47.5432],[-94.4146,47.5286],[-94.4149,47.5145],[-94.4151,47.5],[-94.4154,47.4861],[-94.4156,47.4717],[-94.416,47.4571],[-94.4161,47.4449],[-94.4161,47.443],[-94.4157,47.4287],[-94.4159,47.4119],[-94.4372,47.4118],[-94.4586,47.4118],[-94.4798,47.4119],[-94.5009,47.412],[-94.5243,47.4114],[-94.5458,47.4109],[-94.5636,47.411],[-94.585,47.411],[-94.6069,47.4101],[-94.6279,47.4103],[-94.6492,47.4102],[-94.6702,47.4102],[-94.6918,47.4098],[-94.7129,47.4095],[-94.7344,47.4098],[-94.7563,47.4105],[-94.7777,47.4102],[-94.7998,47.4098],[-94.8209,47.41],[-94.8423,47.4102],[-94.8636,47.4103],[-94.8849,47.4105],[-94.9063,47.4107],[-94.9274,47.4118],[-94.9487,47.4115],[-94.97,47.4114],[-94.9914,47.4114],[-95.0127,47.4114],[-95.0341,47.4117],[-95.0557,47.4119],[-95.0766,47.4123],[-95.098,47.4125],[-95.1193,47.4126],[-95.1406,47.4125],[-95.1619,47.4127],[-95.1829,47.4127],[-95.1828,47.4268],[-95.1828,47.4412],[-95.1829,47.4557],[-95.183,47.4703],[-95.1831,47.4845],[-95.1833,47.499],[-95.1837,47.5135],[-95.1839,47.528],[-95.1841,47.5424],[-95.1841,47.5566],[-95.1844,47.571],[-95.1847,47.5861],[-95.1849,47.6006],[-95.1849,47.6151],[-95.1849,47.6297],[-95.1849,47.6442],[-95.1847,47.6587],[-95.1849,47.6735],[-95.1904,47.6734],[-95.1941,47.6734],[-95.1944,47.688],[-95.1944,47.7024],[-95.1943,47.717],[-95.1942,47.7313],[-95.1941,47.746],[-95.1941,47.7606],[-95.1939,47.7752],[-95.1939,47.7896],[-95.1938,47.8033],[-95.1937,47.8044],[-95.1937,47.8188],[-95.1936,47.8334],[-95.1935,47.8479],[-95.1935,47.8624],[-95.1934,47.8726],[-95.2003,47.8732],[-95.2025,47.8735],[-95.205,47.874],[-95.2071,47.8742],[-95.2103,47.8744],[-95.2105,47.8745],[-95.2146,47.875],[-95.215,47.8751],[-95.2172,47.8755],[-95.2193,47.876],[-95.2218,47.8765],[-95.223,47.8768],[-95.2288,47.8781],[-95.2313,47.8788],[-95.2345,47.8798],[-95.2359,47.8803],[-95.2374,47.8807],[-95.2377,47.8807],[-95.238,47.8809],[-95.2397,47.8814],[-95.2415,47.882],[-95.2456,47.8829],[-95.2473,47.8837],[-95.2485,47.8844],[-95.2502,47.8852],[-95.2518,47.8861],[-95.2538,47.8876],[-95.2558,47.8891],[-95.2578,47.8903],[-95.258,47.8905],[-95.2585,47.8909],[-95.2592,47.8917],[-95.2592,47.8918],[-95.26,47.8925],[-95.2618,47.8944],[-95.2625,47.895],[-95.2635,47.896],[-95.2655,47.8979],[-95.2657,47.8981],[-95.266,47.8984],[-95.2661,47.8985],[-95.2663,47.8987],[-95.2664,47.8991],[-95.2665,47.8992],[-95.2665,47.8993],[-95.2666,47.8993],[-95.2668,47.8999],[-95.2671,47.9004],[-95.2677,47.901],[-95.2681,47.9016],[-95.2681,47.9017],[-95.2683,47.902],[-95.2688,47.9029],[-95.2689,47.9032],[-95.2699,47.9049],[-95.2701,47.9056],[-95.2702,47.9059],[-95.2703,47.9062],[-95.2704,47.9062],[-95.2704,47.9063],[-95.2705,47.9064],[-95.2705,47.9064],[-95.2706,47.9066],[-95.2709,47.9069],[-95.2709,47.907],[-95.2723,47.9089],[-95.2728,47.9097],[-95.2728,47.9098],[-95.2729,47.9099],[-95.2729,47.9101],[-95.2732,47.9107],[-95.2734,47.9114],[-95.2734,47.9116],[-95.2735,47.9116],[-95.2736,47.9121],[-95.2738,47.9125],[-95.2738,47.9128],[-95.2741,47.9135],[-95.2741,47.9139],[-95.2748,47.9154],[-95.275,47.9156],[-95.2753,47.9162],[-95.2754,47.9168],[-95.2756,47.9172],[-95.2756,47.9175],[-95.2761,47.92],[-95.2762,47.9206],[-95.2762,47.9206],[-95.2763,47.921],[-95.2764,47.9215],[-95.2765,47.922],[-95.2766,47.9227],[-95.2767,47.9231],[-95.2768,47.9236],[-95.2771,47.9247],[-95.2774,47.9254],[-95.2774,47.9257],[-95.2776,47.9263],[-95.2778,47.9281],[-95.278,47.9286],[-95.2781,47.9302],[-95.278,47.9321],[-95.2779,47.9328],[-95.2779,47.9351],[-95.2779,47.9351],[-95.2774,47.938],[-95.2772,47.9384],[-95.2772,47.9389],[-95.277,47.9414],[-95.2769,47.9416],[-95.2767,47.9438],[-95.2767,47.9449],[-95.2761,47.947],[-95.2759,47.9474],[-95.2756,47.9487],[-95.2755,47.9488],[-95.2753,47.9495],[-95.2751,47.9507],[-95.2749,47.9515],[-95.2743,47.9529],[-95.2743,47.9531],[-95.2742,47.9534],[-95.2742,47.9541],[-95.2741,47.9561],[-95.274,47.9568],[-95.2739,47.9574],[-95.2735,47.958],[-95.2731,47.9584],[-95.2729,47.9586],[-95.2728,47.9587],[-95.2726,47.959],[-95.2726,47.9593],[-95.2725,47.9605],[-95.2722,47.961],[-95.2712,47.9623],[-95.271,47.9628],[-95.2708,47.9632],[-95.2706,47.9636],[-95.2703,47.9637],[-95.2701,47.9639],[-95.2701,47.964],[-95.2698,47.9643],[-95.2694,47.9655],[-95.268,47.9688],[-95.267,47.9704],[-95.267,47.9707],[-95.2667,47.9708],[-95.2664,47.9714],[-95.2657,47.9727],[-95.2646,47.9748],[-95.2645,47.9752],[-95.2639,47.9765],[-95.2636,47.9771],[-95.2627,47.9786],[-95.2618,47.9803],[-95.259,47.9839],[-95.2585,47.9852],[-95.2583,47.9856],[-95.2582,47.9865],[-95.258,47.987],[-95.2579,47.9875],[-95.2576,47.9883],[-95.2571,47.9891],[-95.2554,47.9917],[-95.2551,47.992],[-95.2546,47.9926],[-95.2543,47.9932],[-95.253,47.9954],[-95.2526,47.9964],[-95.2523,47.9968],[-95.252,47.9971],[-95.2518,47.9973],[-95.2512,47.998],[-95.2508,47.9988],[-95.2507,47.999],[-95.2507,48.0],[-95.2504,48.0],[-95.2502,48.0],[-95.2495,48.0],[-95.2495,48.0009],[-95.2493,48.0015],[-95.249,48.002],[-95.2486,48.0025],[-95.2481,48.0029],[-95.2479,48.0031],[-95.2477,48.0041],[-95.2472,48.0046],[-95.247,48.0048],[-95.2464,48.0055],[-95.2459,48.0059],[-95.2455,48.0066],[-95.245,48.0071],[-95.2449,48.0072],[-95.2445,48.0076],[-95.2445,48.0076],[-95.2444,48.008],[-95.2442,48.0081],[-95.2441,48.0083],[-95.2439,48.0086],[-95.2439,48.0087],[-95.2438,48.0087],[-95.2433,48.009],[-95.2423,48.0097],[-95.2421,48.01],[-95.2418,48.0103],[-95.2417,48.0106],[-95.2414,48.0108],[-95.2414,48.0109],[-95.2409,48.0111],[-95.2407,48.0112],[-95.2404,48.0114],[-95.2401,48.0117],[-95.24,48.0119],[-95.24,48.0119],[-95.2396,48.0123],[-95.2394,48.0124],[-95.2387,48.0127],[-95.2377,48.0134],[-95.2376,48.0135],[-95.2372,48.0139],[-95.2371,48.0142],[-95.2371,48.0143],[-95.237,48.0144],[-95.2368,48.0145],[-95.2367,48.0145],[-95.2363,48.0148],[-95.2362,48.0148],[-95.2358,48.0149],[-95.2354,48.0152],[-95.2352,48.0155],[-95.2347,48.0158],[-95.2326,48.017],[-95.2323,48.0174],[-95.2306,48.0185],[-95.2304,48.0188],[-95.2303,48.0191],[-95.2297,48.0196],[-95.2293,48.0199],[-95.2289,48.0201],[-95.2378,48.0201],[-95.2473,48.0201],[-95.2493,48.0201],[-95.2594,48.0201],[-95.269,48.0201],[-95.281,48.0202],[-95.2887,48.0201],[-95.2906,48.0201],[-95.2933,48.0201],[-95.3025,48.0202],[-95.3122,48.0202],[-95.3224,48.0203],[-95.3338,48.0203],[-95.3401,48.0203],[-95.3439,48.0204],[-95.3554,48.0204],[-95.3654,48.0204],[-95.3661,48.0204],[-95.377,48.0205],[-95.3871,48.0206],[-95.3985,48.0206],[-95.4086,48.0207],[-95.4201,48.0206],[-95.4302,48.0206],[-95.4417,48.0206],[-95.4523,48.0206],[-95.4632,48.0207],[-95.4738,48.0207],[-95.485,48.0207],[-95.4954,48.0207],[-95.4959,48.0207],[-95.5065,48.0208],[-95.517,48.0208],[-95.5215,48.0209],[-95.5277,48.0209],[-95.5384,48.0209],[-95.5398,48.0209],[-95.5491,48.0209],[-95.5597,48.0208],[-95.5705,48.0208],[-95.5828,48.0207],[-95.5922,48.0207],[-95.5923,48.035],[-95.5925,48.0497],[-95.5925,48.0642],[-95.5926,48.0787],[-95.5928,48.0931],[-95.593,48.1078],[-95.5931,48.1223],[-95.5936,48.1368],[-95.5938,48.1512],[-95.5939,48.1658],[-95.5939,48.173],[-95.594,48.1802],[-95.5938,48.1946],[-95.5939,48.2092],[-95.5939,48.2236],[-95.5941,48.2382],[-95.5941,48.2526],[-95.5937,48.267],[-95.5934,48.2815],[-95.5934,48.2961],[-95.5932,48.3105],[-95.5932,48.325],[-95.5932,48.3396],[-95.5933,48.354],[-95.5933,48.3656],[-95.5933,48.3656],[-95.6016,48.3655],[-95.602,48.3798],[-95.6021,48.3809],[-95.6026,48.3942],[-95.6026,48.395],[-95.6026,48.4088],[-95.6026,48.4095],[-95.6023,48.4232],[-95.6023,48.424],[-95.6021,48.4376],[-95.602,48.4385],[-95.6016,48.4522],[-95.6016,48.453],[-95.6016,48.4666],[-95.6016,48.4674],[-95.6011,48.4811],[-95.6011,48.4818],[-95.6008,48.4956],[-95.6008,48.4964],[-95.6007,48.51],[-95.6007,48.5107],[-95.6011,48.5251],[-95.6023,48.5389],[-95.5821,48.5387],[-95.5801,48.5387],[-95.5603,48.5388],[-95.558,48.5388],[-95.5383,48.5389],[-95.5365,48.5389],[-95.5163,48.539],[-95.5143,48.539],[-95.495,48.5392],[-95.493,48.5392],[-95.4726,48.5396],[-95.4712,48.5396],[-95.4513,48.5399],[-95.4494,48.5399],[-95.4297,48.5399],[-95.4279,48.54],[-95.4078,48.5402],[-95.4061,48.5402],[-95.386,48.5402],[-95.3844,48.5402],[-95.364,48.5403],[-95.3628,48.5404],[-95.3425,48.5402]]],"type":"Polygon"},"id":"4","properties":{"Area":7911449532.86586,"CTYONLY_":8,"Code":"BELT","LASTMOD":"1999-12-31T23:59:59Z","Name":"Beltrami","Perimiter":429419.1705},"type":"Feature"},{"geometry":{"coordinates":[[[-97.1467,48.1733],[-97.1462,48.1733],[-97.1376,48.1733],[-97.1322,48.1733],[-97.1286,48.1733],[-97.1257,48.1733],[-97.1253,48.1733],[-97.1071,48.1735],[-97.1069,48.1735],[-97.0855,48.1734],[-97.0853,48.1734],[-97.0637,48.1732],[-97.0637,48.1732],[-97.042,48.1732],[-97.042,48.1732],[-97.0205,48.1733],[-97.0203,48.1733],[-97.0003,48.1732],[-96.999,48.1732],[-96.9989,48.1732],[-96.9987,48.1732],[-96.998,48.1732],[-96.9975,48.1732],[-96.9959,48.1732],[-96.99,48.1731],[-96.9889,48.1731],[-96.9844,48.1731],[-96.9812,48.1731],[-96.9775,48.1731],[-96.9773,48.173],[-96.9773,48.173],[-96.9751,48.173],[-96.9749,48.173],[-96.9705,48.1731],[-96.9703,48.1731],[-96.9554,48.1731],[-96.9448,48.1732],[-96.9387,48.1732],[-96.934,48.1733],[-96.9339,48.1733],[-96.933,48.1733],[-96.9123,48.1733],[-96.9122,48.1733],[-96.8932,48.1732],[-96.8907,48.1732],[-96.8907,48.1732],[-96.8753,48.1732],[-96.869,48.1733],[-96.869,48.1733],[-96.8474,48.1733],[-96.8473,48.1733],[-96.8255,48.1734],[-96.8255,48.1734],[-96.8111,48.1734],[-96.8039,48.1734],[-96.8038,48.1734],[-96.7932,48.1733],[-96.7821,48.1734],[-96.7821,48.1734],[-96.7819,48.1734],[-96.7613,48.1734],[-96.7606,48.1734],[-96.7605,48.1734],[-96.7581,48.1734],[-96.7573,48.1734],[-96.7503,48.1734],[-96.7393,48.1734],[-96.7393,48.1734],[-96.7177,48.1734],[-96.7176,48.1734],[-96.6959,48.1734],[-96.6958,48.1734],[-96.6826,48.1735],[-96.6742,48.1736],[-96.6742,48.1736],[-96.6525,48.1738],[-96.6525,48.1738],[-96.6407,48.1739],[-96.6378,48.1738],[-96.6338,48.1737],[-96.6309,48.1737],[-96.6307,48.1737],[-96.6307,48.1737],[-96.6253,48.1737],[-96.6106,48.1737],[-96.6092,48.1737],[-96.609,48.1737],[-96.6055,48.1737],[-96.5966,48.1737],[-96.5893,48.1737],[-96.5875,48.1737],[-96.5873,48.1737],[-96.5873,48.1737],[-96.5838,48.1738],[-96.5806,48.1739],[-96.5765,48.1739],[-96.5748,48.1739],[-96.5715,48.1739],[-96.5678,48.174],[-96.5655,48.174],[-96.5654,48.174],[-96.565,48.174],[-96.5616,48.1739],[-96.557,48.1739],[-96.5544,48.1738],[-96.5507,48.1738],[-96.5479,48.1738],[-96.5446,48.1738],[-96.5443,48.1738],[-96.5442,48.1738],[-96.5434,48.1738],[-96.5399,48.1738],[-96.5357,48.1738],[-96.53,48.1738],[-96.5251,48.1738],[-96.5223,48.1739],[-96.5204,48.1739],[-96.5164,48.1739],[-96.5091,48.174],[-96.5038,48.174],[-96.5008,48.1742],[-96.5008,48.1669],[-96.5008,48.1524],[-96.5006,48.1379],[-96.5007,48.1234],[-96.501,48.1089],[-96.5009,48.0943],[-96.5009,48.0798],[-96.5009,48.0654],[-96.5008,48.0506],[-96.5009,48.0362],[-96.5009,48.0217],[-96.4826,48.0217],[-96.4826,48.0072],[-96.4824,47.9924],[-96.4823,47.9782],[-96.4823,47.9636],[-96.4825,47.949],[-96.4826,47.9347],[-96.4825,47.9202],[-96.4825,47.9055],[-96.4825,47.9054],[-96.4824,47.8913],[-96.4827,47.8768],[-96.4821,47.862],[-96.482,47.8475],[-96.4601,47.8475],[-96.4386,47.8476],[-96.4172,47.8475],[-96.3958,47.8475],[-96.3742,47.8474],[-96.3527,47.8473],[-96.3524,47.8329],[-96.3523,47.8184],[-96.3521,47.8038],[-96.352,47.7893],[-96.3519,47.7748],[-96.3516,47.7604],[-96.3313,47.7603],[-96.3097,47.7601],[-96.2884,47.7601],[-96.2668,47.7599],[-96.2453,47.7598],[-96.2238,47.7598],[-96.2022,47.7597],[-96.1806,47.7598],[-96.159,47.7598],[-96.1388,47.7598],[-96.1175,47.7602],[-96.0957,47.76],[-96.0743,47.7601],[-96.053,47.7603],[-96.0315,47.7605],[-96.0097,47.7605],[-95.9883,47.7605],[-95.9671,47.7605],[-95.9452,47.7606],[-95.9233,47.7607],[-95.9017,47.7609],[-95.8801,47.7608],[-95.8588,47.7609],[-95.8372,47.7609],[-95.8371,47.7755],[-95.8365,47.79],[-95.8366,47.8043],[-95.8366,47.819],[-95.8367,47.8335],[-95.8366,47.8482],[-95.8153,47.8484],[-95.7952,47.8483],[-95.7737,47.8484],[-95.7525,47.8485],[-95.7307,47.8487],[-95.709,47.8486],[-95.7089,47.863],[-95.7094,47.8776],[-95.7095,47.8919],[-95.7094,47.9065],[-95.7098,47.9211],[-95.7096,47.9355],[-95.6898,47.9354],[-95.6683,47.9351],[-95.6466,47.9348],[-95.6252,47.9344],[-95.6034,47.9341],[-95.5824,47.9339],[-95.5817,47.9195],[-95.5816,47.9051],[-95.5814,47.8904],[-95.5813,47.876],[-95.5812,47.8617],[-95.5809,47.847],[-95.5805,47.8327],[-95.5804,47.8183],[-95.5801,47.8039],[-95.5796,47.7894],[-95.5796,47.775],[-95.5799,47.7605],[-95.5795,47.746],[-95.5793,47.7314],[-95.5789,47.7171],[-95.5789,47.7027],[-95.5787,47.6882],[-95.5785,47.6738],[-95.5785,47.6737],[-95.5755,47.6737],[-95.5595,47.6737],[-95.5535,47.6737],[-95.5537,47.6592],[-95.5536,47.6447],[-95.5535,47.6302],[-95.5538,47.6161],[-95.5536,47.6014],[-95.5537,47.5869],[-95.5538,47.5724],[-95.5538,47.5579],[-95.5539,47.5436],[-95.5539,47.5289],[-95.5539,47.5146],[-95.5513,47.5001],[-95.5516,47.5001],[-95.5729,47.5001],[-95.5942,47.4999],[-95.6158,47.4997],[-95.6366,47.4996],[-95.6393,47.4996],[-95.6411,47.4996],[-95.6584,47.4995],[-95.6605,47.4995],[-95.6782,47.4997],[-95.6818,47.4997],[-95.6908,47.4997],[-95.6996,47.4997],[-95.7033,47.4997],[-95.7211,47.4996],[-95.7247,47.4995],[-95.7424,47.4995],[-95.7459,47.4995],[-95.7537,47.4995],[-95.7634,47.4995],[-95.7675,47.4995],[-95.7851,47.4994],[-95.7888,47.4994],[-95.7965,47.4994],[-95.8053,47.4994],[-95.8103,47.4994],[-95.8266,47.4995],[-95.8272,47.4995],[-95.8316,47.4995],[-95.8371,47.4995],[-95.8482,47.4995],[-95.8529,47.4995],[-95.8696,47.4995],[-95.8746,47.4994],[-95.8908,47.4993],[-95.8954,47.4993],[-95.9123,47.4992],[-95.9169,47.4992],[-95.9332,47.4992],[-95.9383,47.4992],[-95.9549,47.4992],[-95.9603,47.4992],[-95.9761,47.4992],[-95.9818,47.4992],[-95.9977,47.4992],[-95.9991,47.4992],[-96.0032,47.4992],[-96.019,47.4993],[-96.0247,47.4993],[-96.0362,47.4992],[-96.0408,47.4992],[-96.0462,47.4992],[-96.0676,47.4992],[-96.0888,47.4993],[-96.1101,47.4993],[-96.1314,47.4996],[-96.1526,47.4997],[-96.1739,47.4999],[-96.1954,47.4999],[-96.2166,47.4999],[-96.238,47.4998],[-96.2594,47.4998],[-96.2808,47.4998],[-96.3022,47.4999],[-96.3232,47.4999],[-96.3448,47.4997],[-96.3659,47.4997],[-96.3873,47.4997],[-96.4088,47.4996],[-96.4301,47.4996],[-96.4517,47.4994],[-96.4731,47.4993],[-96.4944,47.4993],[-96.516,47.4991],[-96.5371,47.4991],[-96.5587,47.499],[-96.5801,47.499],[-96.6013,47.4989],[-96.6229,47.499],[-96.6442,47.4992],[-96.6653,47.499],[-96.6876,47.4987],[-96.7085,47.4989],[-96.73,47.4989],[-96.7515,47.4989],[-96.7732,47.4989],[-96.7945,47.499],[-96.8159,47.499],[-96.8361,47.4989],[-96.8487,47.4989],[-96.8488,47.499],[-96.8504,47.5],[-96.8506,47.5],[-96.8507,47.5],[-96.8514,47.5004],[-96.8524,47.5006],[-96.853,47.501],[-96.8533,47.5014],[-96.8534,47.5017],[-96.8535,47.5023],[-96.8535,47.5034],[-96.8532,47.5039],[-96.8532,47.5042],[-96.8531,47.5045],[-96.8528,47.5053],[-96.8528,47.5059],[-96.8529,47.506],[-96.853,47.5065],[-96.853,47.5069],[-96.8526,47.5073],[-96.8524,47.5075],[-96.8518,47.5076],[-96.8515,47.5076],[-96.8508,47.5074],[-96.8494,47.5068],[-96.8485,47.5066],[-96.8471,47.5066],[-96.846,47.5067],[-96.8443,47.5071],[-96.8436,47.5074],[-96.8424,47.5083],[-96.8422,47.5086],[-96.8421,47.5091],[-96.8424,47.5094],[-96.8431,47.51],[-96.8439,47.5103],[-96.8448,47.5105],[-96.8464,47.5105],[-96.849,47.5098],[-96.8504,47.5096],[-96.8512,47.5096],[-96.8519,47.5098],[-96.8526,47.5102],[-96.853,47.5106],[-96.8531,47.5107],[-96.8533,47.5112],[-96.8534,47.5112],[-96.8534,47.5113],[-96.8535,47.5113],[-96.8536,47.5119],[-96.8536,47.512],[-96.8532,47.5126],[-96.8531,47.5128],[-96.8525,47.5132],[-96.8517,47.5135],[-96.8514,47.5135],[-96.851,47.5136],[-96.8502,47.5135],[-96.8491,47.5134],[-96.8465,47.5124],[-96.846,47.5123],[-96.8448,47.5124],[-96.8442,47.5125],[-96.8435,47.5128],[-96.843,47.5132],[-96.8428,47.5134],[-96.8425,47.5137],[-96.8422,47.5141],[-96.842,47.5146],[-96.842,47.5155],[-96.842,47.5156],[-96.842,47.5157],[-96.8421,47.5158],[-96.8422,47.516],[-96.8427,47.5164],[-96.8433,47.5167],[-96.8442,47.517],[-96.8454,47.5172],[-96.8465,47.517],[-96.8475,47.5166],[-96.8481,47.5163],[-96.8501,47.5155],[-96.8519,47.515],[-96.8532,47.5146],[-96.8542,47.5144],[-96.8547,47.5144],[-96.8563,47.5146],[-96.8573,47.5147],[-96.8584,47.5149],[-96.8599,47.5153],[-96.8614,47.5159],[-96.8624,47.5164],[-96.8629,47.5169],[-96.8632,47.5173],[-96.8633,47.5177],[-96.8633,47.5198],[-96.8635,47.5204],[-96.8636,47.5206],[-96.8643,47.5213],[-96.8645,47.5216],[-96.8656,47.5225],[-96.8658,47.5229],[-96.866,47.523],[-96.8663,47.5238],[-96.8664,47.5249],[-96.8666,47.5254],[-96.8672,47.5259],[-96.8676,47.5261],[-96.8683,47.5262],[-96.8698,47.5264],[-96.8705,47.5266],[-96.8707,47.5268],[-96.8708,47.5269],[-96.8709,47.5272],[-96.8709,47.5273],[-96.8709,47.5279],[-96.8706,47.5283],[-96.8704,47.5284],[-96.87,47.5287],[-96.8691,47.529],[-96.868,47.5291],[-96.8665,47.5291],[-96.865,47.529],[-96.8623,47.5291],[-96.861,47.5294],[-96.8605,47.5296],[-96.8593,47.5304],[-96.8589,47.5308],[-96.8576,47.5328],[-96.8573,47.5333],[-96.8568,47.5337],[-96.8558,47.5346],[-96.8543,47.5354],[-96.854,47.5357],[-96.8535,47.5363],[-96.8534,47.5372],[-96.8536,47.5378],[-96.854,47.5382],[-96.8546,47.5383],[-96.8558,47.5382],[-96.8569,47.5379],[-96.8573,47.5377],[-96.8579,47.5375],[-96.8589,47.5371],[-96.8593,47.5371],[-96.8599,47.5371],[-96.8609,47.5374],[-96.8619,47.5379],[-96.8629,47.5387],[-96.8632,47.5391],[-96.8634,47.5395],[-96.8634,47.5402],[-96.8628,47.5409],[-96.8614,47.5414],[-96.858,47.542],[-96.8573,47.5421],[-96.8565,47.5422],[-96.8555,47.5421],[-96.8542,47.5418],[-96.8533,47.5413],[-96.8523,47.5407],[-96.8519,47.5401],[-96.8516,47.5397],[-96.8514,47.5393],[-96.8513,47.5393],[-96.8512,47.539],[-96.8511,47.5388],[-96.851,47.5386],[-96.8507,47.5383],[-96.8507,47.5382],[-96.8501,47.5377],[-96.8494,47.5374],[-96.8484,47.5372],[-96.8477,47.5371],[-96.8471,47.5372],[-96.8465,47.5374],[-96.8457,47.538],[-96.8452,47.5386],[-96.8452,47.5394],[-96.8452,47.5397],[-96.8454,47.5399],[-96.8455,47.5403],[-96.8456,47.5404],[-96.8456,47.5405],[-96.846,47.541],[-96.8467,47.5415],[-96.8484,47.5425],[-96.8501,47.5432],[-96.8525,47.5438],[-96.8571,47.5448],[-96.8572,47.5448],[-96.8586,47.5452],[-96.8597,47.5456],[-96.8602,47.5459],[-96.8603,47.5461],[-96.8603,47.5464],[-96.8602,47.5466],[-96.8599,47.5468],[-96.8596,47.547],[-96.8585,47.5472],[-96.8576,47.5477],[-96.8572,47.5479],[-96.8554,47.5485],[-96.8542,47.5488],[-96.8538,47.5491],[-96.8523,47.5504],[-96.8505,47.5517],[-96.8501,47.5521],[-96.8499,47.5526],[-96.8497,47.5532],[-96.85,47.5537],[-96.8501,47.5538],[-96.8501,47.5539],[-96.8506,47.5543],[-96.8513,47.5546],[-96.8526,47.5549],[-96.8546,47.5551],[-96.8558,47.5551],[-96.857,47.5553],[-96.8578,47.5556],[-96.8588,47.5562],[-96.8598,47.5571],[-96.8602,47.5576],[-96.8605,47.5578],[-96.8606,47.5581],[-96.8608,47.5582],[-96.8612,47.5588],[-96.8614,47.5592],[-96.8614,47.5599],[-96.8613,47.5602],[-96.8608,47.5604],[-96.8601,47.5607],[-96.8594,47.5607],[-96.8581,47.5605],[-96.8573,47.5602],[-96.8569,47.5601],[-96.8567,47.5601],[-96.8553,47.5602],[-96.8544,47.5603],[-96.8537,47.5606],[-96.8515,47.5621],[-96.8506,47.5626],[-96.8491,47.5636],[-96.8484,47.564],[-96.8476,47.5646],[-96.8474,47.565],[-96.8472,47.5656],[-96.8472,47.5661],[-96.8474,47.5663],[-96.8479,47.5666],[-96.8487,47.5667],[-96.8498,47.5665],[-96.8503,47.5664],[-96.8513,47.5658],[-96.852,47.5656],[-96.8541,47.5653],[-96.856,47.5649],[-96.8568,47.5646],[-96.8575,47.5643],[-96.8599,47.5632],[-96.8612,47.5628],[-96.8622,47.5626],[-96.8628,47.5626],[-96.864,47.5627],[-96.8652,47.5631],[-96.8661,47.5636],[-96.8666,47.564],[-96.8676,47.5651],[-96.8678,47.5654],[-96.868,47.5655],[-96.8685,47.5663],[-96.8685,47.5664],[-96.8686,47.5665],[-96.8687,47.5668],[-96.8688,47.5669],[-96.8687,47.5677],[-96.8684,47.5682],[-96.8675,47.5688],[-96.8661,47.5695],[-96.8656,47.5696],[-96.8647,47.5694],[-96.8639,47.569],[-96.8629,47.5687],[-96.8616,47.5684],[-96.861,47.5682],[-96.8607,47.568],[-96.8599,47.5676],[-96.8588,47.5672],[-96.8578,47.5671],[-96.8567,47.5671],[-96.8555,47.5671],[-96.8539,47.5675],[-96.8529,47.5678],[-96.8519,47.5684],[-96.8514,47.569],[-96.8515,47.5698],[-96.8517,47.5703],[-96.8521,47.5709],[-96.8529,47.5715],[-96.8531,47.5716],[-96.8537,47.5719],[-96.8549,47.5725],[-96.8566,47.5731],[-96.8571,47.5733],[-96.8595,47.574],[-96.8602,47.5744],[-96.8604,47.5746],[-96.8604,47.575],[-96.8599,47.5752],[-96.8589,47.5754],[-96.8585,47.5756],[-96.8573,47.5763],[-96.8565,47.5767],[-96.8553,47.5773],[-96.8543,47.578],[-96.8534,47.5792],[-96.8532,47.5795],[-96.853,47.5802],[-96.853,47.5805],[-96.8528,47.5809],[-96.8529,47.5822],[-96.853,47.5826],[-96.8532,47.5826],[-96.8532,47.5833],[-96.8531,47.5837],[-96.8526,47.5844],[-96.8527,47.5845],[-96.8525,47.5846],[-96.852,47.585],[-96.852,47.5851],[-96.8515,47.5859],[-96.8515,47.586],[-96.8513,47.5869],[-96.8512,47.5873],[-96.8511,47.5878],[-96.851,47.5881],[-96.8507,47.5888],[-96.8502,47.5898],[-96.85,47.5903],[-96.8499,47.591],[-96.8501,47.5916],[-96.8503,47.5919],[-96.8511,47.5925],[-96.8517,47.5927],[-96.8538,47.593],[-96.8549,47.5934],[-96.8562,47.5939],[-96.8575,47.5943],[-96.8582,47.5947],[-96.8586,47.5949],[-96.8588,47.5954],[-96.8588,47.5958],[-96.8584,47.5962],[-96.8575,47.5963],[-96.8562,47.5962],[-96.8542,47.596],[-96.853,47.5961],[-96.8521,47.5964],[-96.8515,47.5968],[-96.8511,47.5973],[-96.8509,47.5977],[-96.8509,47.5983],[-96.8511,47.5989],[-96.8515,47.5993],[-96.8521,47.5997],[-96.8528,47.6],[-96.8536,47.6003],[-96.8545,47.6004],[-96.8556,47.6009],[-96.8561,47.6014],[-96.8564,47.6016],[-96.8567,47.602],[-96.8569,47.6024],[-96.8568,47.6031],[-96.8565,47.6035],[-96.8562,47.6039],[-96.8553,47.6051],[-96.8549,47.6058],[-96.8548,47.6064],[-96.8548,47.6073],[-96.8549,47.6075],[-96.855,47.6079],[-96.855,47.608],[-96.8554,47.6088],[-96.8557,47.6093],[-96.8558,47.6094],[-96.8561,47.6098],[-96.8563,47.61],[-96.8571,47.6108],[-96.858,47.6115],[-96.8589,47.612],[-96.8602,47.6122],[-96.8612,47.6124],[-96.8646,47.6124],[-96.8655,47.6125],[-96.8664,47.6129],[-96.8672,47.6136],[-96.8673,47.6138],[-96.8675,47.6139],[-96.8676,47.6141],[-96.8679,47.6144],[-96.8686,47.6148],[-96.869,47.615],[-96.8694,47.615],[-96.8703,47.6147],[-96.871,47.6143],[-96.8714,47.6139],[-96.8719,47.6136],[-96.8723,47.6135],[-96.8729,47.6135],[-96.8736,47.6137],[-96.8739,47.614],[-96.874,47.6141],[-96.874,47.6148],[-96.8739,47.6149],[-96.8736,47.6154],[-96.8726,47.6159],[-96.8715,47.6165],[-96.871,47.6169],[-96.8706,47.6176],[-96.8708,47.6181],[-96.8712,47.6183],[-96.8717,47.6184],[-96.8727,47.6184],[-96.8753,47.6191],[-96.8763,47.6192],[-96.8778,47.6189],[-96.878,47.6189],[-96.879,47.6189],[-96.8796,47.6191],[-96.88,47.6195],[-96.88,47.62],[-96.8794,47.6206],[-96.8783,47.6213],[-96.8779,47.6215],[-96.8769,47.6219],[-96.8763,47.6223],[-96.876,47.6228],[-96.8758,47.623],[-96.876,47.6235],[-96.8761,47.6237],[-96.8768,47.6243],[-96.8775,47.6244],[-96.878,47.6245],[-96.8792,47.6246],[-96.88,47.6247],[-96.8803,47.625],[-96.8806,47.6254],[-96.8807,47.6255],[-96.8807,47.6259],[-96.8804,47.6262],[-96.8798,47.6266],[-96.8792,47.6267],[-96.8786,47.6267],[-96.878,47.6267],[-96.8767,47.6266],[-96.8753,47.6267],[-96.8748,47.6269],[-96.8745,47.6272],[-96.8745,47.6275],[-96.8745,47.628],[-96.8747,47.6283],[-96.8753,47.6287],[-96.8765,47.629],[-96.8774,47.6289],[-96.8781,47.6289],[-96.8787,47.6289],[-96.8795,47.6289],[-96.8801,47.6289],[-96.8806,47.6291],[-96.881,47.6294],[-96.8815,47.6299],[-96.8815,47.6299],[-96.8815,47.63],[-96.8816,47.6301],[-96.8818,47.6305],[-96.8818,47.631],[-96.8819,47.6311],[-96.882,47.6324],[-96.8822,47.6333],[-96.8823,47.6334],[-96.8823,47.6335],[-96.8827,47.6339],[-96.8852,47.6356],[-96.8876,47.6376],[-96.8878,47.6379],[-96.8885,47.6385],[-96.8885,47.6393],[-96.8884,47.6395],[-96.8881,47.6398],[-96.8874,47.6401],[-96.886,47.6405],[-96.8845,47.6408],[-96.8835,47.6412],[-96.8832,47.6414],[-96.8828,47.6418],[-96.8826,47.6422],[-96.8826,47.6429],[-96.8829,47.6439],[-96.8829,47.6441],[-96.8829,47.6447],[-96.8828,47.6451],[-96.8827,47.6462],[-96.8825,47.6471],[-96.8823,47.6491],[-96.8826,47.6498],[-96.8828,47.6502],[-96.8837,47.6509],[-96.8844,47.6513],[-96.8846,47.6513],[-96.8847,47.6515],[-96.8862,47.6523],[-96.8866,47.6526],[-96.8869,47.6531],[-96.887,47.6533],[-96.887,47.6543],[-96.8868,47.6548],[-96.8869,47.6556],[-96.887,47.656],[-96.8876,47.6577],[-96.8876,47.6585],[-96.8876,47.6589],[-96.8873,47.6596],[-96.8869,47.6601],[-96.8857,47.6616],[-96.8855,47.6624],[-96.8855,47.6635],[-96.8857,47.6643],[-96.8862,47.6652],[-96.8863,47.6653],[-96.8863,47.6654],[-96.8864,47.6656],[-96.8864,47.6656],[-96.8871,47.6664],[-96.8889,47.668],[-96.8896,47.6686],[-96.8897,47.669],[-96.8898,47.669],[-96.8899,47.6693],[-96.89,47.6694],[-96.8901,47.67],[-96.8899,47.6703],[-96.8897,47.6707],[-96.8883,47.6715],[-96.8871,47.6721],[-96.8868,47.6722],[-96.8863,47.6725],[-96.8859,47.6727],[-96.8856,47.6727],[-96.8855,47.6729],[-96.8853,47.6732],[-96.8851,47.6735],[-96.8852,47.6737],[-96.8852,47.6738],[-96.8853,47.6739],[-96.8857,47.6742],[-96.8863,47.6743],[-96.8867,47.6743],[-96.8874,47.6743],[-96.8886,47.674],[-96.8892,47.6738],[-96.8908,47.6734],[-96.8919,47.6732],[-96.8935,47.6732],[-96.8946,47.6734],[-96.8952,47.6736],[-96.8955,47.6738],[-96.8964,47.6745],[-96.8967,47.6748],[-96.8968,47.6751],[-96.8967,47.6759],[-96.8964,47.6768],[-96.8963,47.6772],[-96.8962,47.6775],[-96.8961,47.6776],[-96.8961,47.6785],[-96.8963,47.6792],[-96.8964,47.6793],[-96.8964,47.6794],[-96.8965,47.6796],[-96.8968,47.6802],[-96.8971,47.6804],[-96.8971,47.6806],[-96.8972,47.6806],[-96.8973,47.681],[-96.8974,47.6811],[-96.8974,47.6812],[-96.8975,47.6813],[-96.8977,47.6817],[-96.8978,47.6818],[-96.8978,47.682],[-96.8984,47.6834],[-96.8986,47.6837],[-96.8986,47.684],[-96.8987,47.6841],[-96.8989,47.6846],[-96.899,47.6847],[-96.899,47.685],[-96.8993,47.686],[-96.8992,47.6871],[-96.8992,47.688],[-96.8992,47.6883],[-96.8992,47.6887],[-96.8993,47.6895],[-96.8995,47.69],[-96.8996,47.6901],[-96.8997,47.6903],[-96.9002,47.6908],[-96.9011,47.6914],[-96.9017,47.6917],[-96.9022,47.6918],[-96.9029,47.6916],[-96.9035,47.6913],[-96.9039,47.6909],[-96.9047,47.6898],[-96.9052,47.6893],[-96.906,47.6889],[-96.9072,47.6885],[-96.9081,47.6885],[-96.9089,47.6888],[-96.9095,47.6892],[-96.9098,47.6896],[-96.9101,47.69],[-96.9101,47.6913],[-96.9099,47.6916],[-96.9098,47.692],[-96.9091,47.6926],[-96.9077,47.6934],[-96.9074,47.6937],[-96.9072,47.694],[-96.9072,47.6947],[-96.9076,47.6952],[-96.9077,47.6954],[-96.9083,47.6961],[-96.9092,47.6968],[-96.9097,47.6974],[-96.9101,47.698],[-96.9102,47.6982],[-96.9103,47.6985],[-96.9103,47.6986],[-96.9104,47.6986],[-96.9106,47.6989],[-96.9107,47.6991],[-96.9107,47.6993],[-96.9115,47.7006],[-96.912,47.7012],[-96.9125,47.7017],[-96.9128,47.7018],[-96.9132,47.7019],[-96.914,47.7018],[-96.9145,47.7016],[-96.9155,47.7009],[-96.9169,47.6998],[-96.9177,47.6994],[-96.9184,47.6991],[-96.9193,47.6991],[-96.9202,47.6993],[-96.9207,47.6996],[-96.9208,47.6998],[-96.9208,47.6999],[-96.921,47.7],[-96.9211,47.7003],[-96.9211,47.7008],[-96.9208,47.7013],[-96.9204,47.7017],[-96.9194,47.7026],[-96.919,47.7028],[-96.9187,47.703],[-96.9176,47.7034],[-96.9172,47.7035],[-96.9164,47.7034],[-96.9155,47.7035],[-96.9145,47.7038],[-96.9137,47.7042],[-96.9132,47.7047],[-96.9128,47.7052],[-96.9123,47.7058],[-96.9119,47.7066],[-96.912,47.7075],[-96.9122,47.7079],[-96.9129,47.7083],[-96.9134,47.7084],[-96.9146,47.7085],[-96.9163,47.7086],[-96.9175,47.7089],[-96.919,47.7095],[-96.9198,47.71],[-96.9201,47.7104],[-96.9201,47.7105],[-96.9202,47.7107],[-96.9204,47.7111],[-96.9204,47.712],[-96.9203,47.7124],[-96.9197,47.7137],[-96.9195,47.7139],[-96.9194,47.7142],[-96.9192,47.7146],[-96.9191,47.7149],[-96.9191,47.7156],[-96.9197,47.7166],[-96.9201,47.7171],[-96.9206,47.7174],[-96.9209,47.7176],[-96.9216,47.7178],[-96.9224,47.718],[-96.9232,47.7179],[-96.9238,47.7176],[-96.9241,47.7174],[-96.9245,47.7171],[-96.9247,47.7167],[-96.9248,47.7166],[-96.9248,47.7164],[-96.9251,47.7162],[-96.9252,47.716],[-96.926,47.7153],[-96.9266,47.7149],[-96.9277,47.7144],[-96.9284,47.7143],[-96.929,47.7143],[-96.93,47.7145],[-96.9305,47.7148],[-96.931,47.7153],[-96.931,47.7154],[-96.9311,47.7154],[-96.9312,47.716],[-96.9312,47.7166],[-96.9308,47.7174],[-96.9308,47.7175],[-96.9305,47.7179],[-96.93,47.7183],[-96.9287,47.7187],[-96.9271,47.719],[-96.9251,47.7197],[-96.9237,47.7202],[-96.9217,47.7211],[-96.9205,47.7218],[-96.9194,47.7226],[-96.9193,47.7227],[-96.9189,47.7231],[-96.9187,47.7234],[-96.9185,47.7239],[-96.9187,47.7243],[-96.9188,47.7244],[-96.9188,47.7245],[-96.9191,47.7248],[-96.9197,47.7251],[-96.9203,47.7253],[-96.9224,47.7256],[-96.9236,47.7259],[-96.9242,47.7262],[-96.9246,47.7267],[-96.9248,47.7272],[-96.925,47.7275],[-96.925,47.7291],[-96.9253,47.7299],[-96.9255,47.7302],[-96.9257,47.7304],[-96.9273,47.7316],[-96.9279,47.7321],[-96.9283,47.7325],[-96.9305,47.7344],[-96.9314,47.7353],[-96.9319,47.7359],[-96.9323,47.7365],[-96.9324,47.7366],[-96.9325,47.7368],[-96.9327,47.7371],[-96.9328,47.7372],[-96.9332,47.7383],[-96.9333,47.7388],[-96.9332,47.7395],[-96.933,47.74],[-96.9327,47.7403],[-96.9319,47.741],[-96.9318,47.7411],[-96.9308,47.7417],[-96.9302,47.7422],[-96.9293,47.743],[-96.929,47.7435],[-96.9287,47.7442],[-96.9285,47.7449],[-96.9284,47.7454],[-96.9284,47.7465],[-96.9285,47.7481],[-96.9286,47.7491],[-96.9288,47.7493],[-96.9289,47.7497],[-96.929,47.7497],[-96.9289,47.75],[-96.929,47.7504],[-96.9298,47.751],[-96.9308,47.7515],[-96.9322,47.7521],[-96.9332,47.7526],[-96.9351,47.7532],[-96.9387,47.754],[-96.9394,47.7544],[-96.9398,47.7549],[-96.9397,47.7555],[-96.9394,47.7559],[-96.9388,47.7562],[-96.9381,47.7563],[-96.9373,47.7563],[-96.9363,47.7562],[-96.9337,47.7551],[-96.9327,47.7548],[-96.9323,47.7548],[-96.9311,47.7547],[-96.9297,47.7549],[-96.9291,47.755],[-96.9289,47.7553],[-96.9288,47.7558],[-96.9291,47.7561],[-96.9298,47.7565],[-96.9309,47.7569],[-96.9324,47.7573],[-96.9335,47.7576],[-96.9355,47.7583],[-96.9368,47.759],[-96.9369,47.7592],[-96.9371,47.7594],[-96.9372,47.7595],[-96.9378,47.7602],[-96.9379,47.7604],[-96.9381,47.7607],[-96.9381,47.7609],[-96.9382,47.7609],[-96.9382,47.761],[-96.9384,47.7614],[-96.9384,47.7625],[-96.938,47.7632],[-96.9376,47.7639],[-96.9369,47.7646],[-96.9366,47.7649],[-96.9352,47.7658],[-96.9351,47.766],[-96.9349,47.7664],[-96.9348,47.7668],[-96.9349,47.7671],[-96.9357,47.7676],[-96.9365,47.7678],[-96.9382,47.7681],[-96.9391,47.7684],[-96.9404,47.7692],[-96.9423,47.7708],[-96.943,47.7712],[-96.9442,47.7717],[-96.9445,47.7717],[-96.9445,47.7719],[-96.9452,47.7722],[-96.9457,47.7727],[-96.9458,47.7729],[-96.9459,47.7734],[-96.9459,47.7743],[-96.946,47.7746],[-96.9466,47.775],[-96.9473,47.7753],[-96.9483,47.7755],[-96.9494,47.7753],[-96.9495,47.7753],[-96.9518,47.7747],[-96.9527,47.7746],[-96.9537,47.7746],[-96.9539,47.7747],[-96.955,47.7748],[-96.956,47.7751],[-96.9565,47.7753],[-96.9567,47.7757],[-96.9567,47.7761],[-96.9566,47.7762],[-96.9544,47.7777],[-96.9538,47.778],[-96.9527,47.7787],[-96.9523,47.779],[-96.9522,47.7793],[-96.9524,47.7796],[-96.9527,47.7799],[-96.9533,47.78],[-96.9538,47.78],[-96.9554,47.7798],[-96.9565,47.7798],[-96.9573,47.78],[-96.9584,47.7803],[-96.9589,47.7807],[-96.9593,47.7812],[-96.9593,47.7819],[-96.9592,47.7819],[-96.9578,47.7838],[-96.9576,47.7844],[-96.9575,47.7847],[-96.9575,47.7852],[-96.9578,47.7855],[-96.9581,47.7856],[-96.9584,47.7857],[-96.959,47.7855],[-96.9596,47.7849],[-96.9597,47.7847],[-96.9598,47.7847],[-96.9598,47.7846],[-96.9601,47.7843],[-96.961,47.7838],[-96.9619,47.7833],[-96.9631,47.783],[-96.9638,47.783],[-96.9644,47.783],[-96.9649,47.7833],[-96.9653,47.7835],[-96.9654,47.7839],[-96.9653,47.785],[-96.9651,47.7853],[-96.965,47.7855],[-96.9645,47.7862],[-96.9635,47.7873],[-96.9628,47.7879],[-96.9621,47.7884],[-96.9615,47.7888],[-96.9599,47.7893],[-96.9586,47.7896],[-96.958,47.7898],[-96.9576,47.79],[-96.9572,47.7902],[-96.9571,47.7904],[-96.9572,47.791],[-96.9573,47.7913],[-96.9574,47.7915],[-96.9578,47.7921],[-96.9584,47.7925],[-96.9597,47.7931],[-96.9627,47.7942],[-96.9635,47.7947],[-96.9642,47.7951],[-96.965,47.7959],[-96.9657,47.7968],[-96.966,47.7973],[-96.9661,47.7992],[-96.9662,47.7993],[-96.9663,47.7994],[-96.9669,47.7998],[-96.9674,47.7999],[-96.9681,47.7998],[-96.9687,47.7996],[-96.9689,47.7995],[-96.9702,47.7987],[-96.9716,47.7983],[-96.974,47.7978],[-96.9751,47.7978],[-96.9754,47.7978],[-96.9762,47.7979],[-96.9766,47.7981],[-96.9768,47.7983],[-96.977,47.7986],[-96.977,47.8],[-96.9764,47.8013],[-96.9761,47.8016],[-96.9759,47.8017],[-96.9754,47.8019],[-96.9751,47.8019],[-96.973,47.8019],[-96.9723,47.802],[-96.9721,47.8022],[-96.9719,47.8025],[-96.9721,47.8029],[-96.973,47.8034],[-96.974,47.8036],[-96.9749,47.8037],[-96.9751,47.8037],[-96.9769,47.8037],[-96.9789,47.804],[-96.9796,47.8042],[-96.981,47.8045],[-96.9818,47.8046],[-96.9826,47.805],[-96.9828,47.8051],[-96.9831,47.8051],[-96.9832,47.8053],[-96.9851,47.8065],[-96.9859,47.8069],[-96.9863,47.8071],[-96.9877,47.8072],[-96.9894,47.8072],[-96.9905,47.8076],[-96.991,47.8078],[-96.9914,47.8081],[-96.9916,47.8085],[-96.9916,47.8091],[-96.9912,47.8094],[-96.9903,47.8097],[-96.9891,47.8099],[-96.9882,47.8099],[-96.9864,47.8098],[-96.9818,47.8091],[-96.9805,47.8092],[-96.9796,47.8095],[-96.9788,47.8099],[-96.9782,47.8106],[-96.978,47.8112],[-96.9779,47.8117],[-96.9781,47.8122],[-96.9784,47.8128],[-96.9786,47.8129],[-96.9787,47.8131],[-96.9795,47.8138],[-96.9795,47.8139],[-96.9798,47.8143],[-96.9799,47.8145],[-96.9799,47.8146],[-96.9803,47.8157],[-96.9804,47.8187],[-96.9804,47.822],[-96.9802,47.8224],[-96.9797,47.8226],[-96.979,47.8226],[-96.9772,47.8222],[-96.9764,47.8221],[-96.9759,47.8221],[-96.9754,47.8222],[-96.9747,47.8224],[-96.9745,47.8224],[-96.9744,47.8225],[-96.9741,47.8228],[-96.9741,47.8234],[-96.9743,47.8239],[-96.9749,47.8244],[-96.9757,47.825],[-96.9759,47.825],[-96.9769,47.8254],[-96.9783,47.8256],[-96.9793,47.8257],[-96.982,47.8255],[-96.9845,47.8251],[-96.9857,47.8251],[-96.9865,47.8252],[-96.9869,47.8254],[-96.9872,47.8256],[-96.9871,47.8261],[-96.9867,47.8265],[-96.9858,47.8269],[-96.984,47.8275],[-96.9827,47.8281],[-96.9825,47.8283],[-96.9819,47.8287],[-96.9817,47.829],[-96.9815,47.8295],[-96.9816,47.8301],[-96.9817,47.8305],[-96.982,47.8309],[-96.9843,47.8325],[-96.9848,47.8331],[-96.9849,47.8332],[-96.9849,47.8333],[-96.985,47.8334],[-96.9852,47.8339],[-96.9853,47.8344],[-96.9854,47.8345],[-96.9857,47.8359],[-96.9859,47.8361],[-96.9859,47.8366],[-96.9863,47.8373],[-96.9866,47.8377],[-96.9873,47.8379],[-96.9881,47.838],[-96.9896,47.8381],[-96.9907,47.838],[-96.9915,47.8378],[-96.9924,47.8378],[-96.9929,47.838],[-96.9937,47.8383],[-96.9941,47.8388],[-96.9941,47.8396],[-96.994,47.8397],[-96.9935,47.8404],[-96.9929,47.8412],[-96.9925,47.8417],[-96.9924,47.8421],[-96.9924,47.8426],[-96.9927,47.8427],[-96.9931,47.8428],[-96.9938,47.8426],[-96.9956,47.842],[-96.9969,47.8416],[-96.9976,47.8416],[-96.9976,47.8435],[-96.9974,47.8437],[-96.9963,47.8444],[-96.9958,47.8447],[-96.9947,47.845],[-96.9943,47.8452],[-96.9941,47.8455],[-96.994,47.8458],[-96.9941,47.8461],[-96.9941,47.8462],[-96.9942,47.8463],[-96.9943,47.8464],[-96.9949,47.847],[-96.9956,47.8474],[-96.9967,47.848],[-96.9968,47.848],[-96.9968,47.8482],[-96.9969,47.8482],[-96.9971,47.8484],[-96.9973,47.8488],[-96.9975,47.8496],[-96.9973,47.8504],[-96.9969,47.8515],[-96.9967,47.8526],[-96.9968,47.8545],[-96.9969,47.8555],[-96.9971,47.8561],[-96.9971,47.8564],[-96.9972,47.8566],[-96.9973,47.8567],[-96.9974,47.8574],[-96.9976,47.8577],[-96.9978,47.8583],[-96.9978,47.8583],[-96.9981,47.8589],[-96.9982,47.859],[-96.9983,47.8592],[-96.9989,47.8599],[-96.9994,47.8603],[-96.9998,47.8607],[-97.0003,47.861],[-97.0017,47.8613],[-97.0031,47.8623],[-97.0055,47.864],[-97.0058,47.8653],[-97.0033,47.8659],[-97.0015,47.8674],[-97.0024,47.8687],[-97.0053,47.8702],[-97.0084,47.8708],[-97.0173,47.8716],[-97.0194,47.8722],[-97.0212,47.8726],[-97.0218,47.8731],[-97.0231,47.874],[-97.0231,47.875],[-97.0221,47.8755],[-97.0196,47.8766],[-97.0193,47.8768],[-97.0189,47.8769],[-97.0179,47.8785],[-97.0193,47.8803],[-97.022,47.8815],[-97.0233,47.8821],[-97.0253,47.8843],[-97.0253,47.8856],[-97.0249,47.8869],[-97.0222,47.8884],[-97.0194,47.8897],[-97.0191,47.8898],[-97.0189,47.8911],[-97.019,47.8912],[-97.0195,47.8915],[-97.0225,47.8933],[-97.0249,47.895],[-97.0239,47.8981],[-97.0201,47.9005],[-97.0202,47.9022],[-97.0241,47.9053],[-97.0242,47.9056],[-97.0249,47.9082],[-97.0245,47.9083],[-97.0235,47.9085],[-97.0203,47.9064],[-97.0198,47.9063],[-97.0184,47.906],[-97.0172,47.9057],[-97.015,47.9072],[-97.015,47.9073],[-97.0153,47.9103],[-97.0156,47.9108],[-97.0172,47.9131],[-97.0195,47.9141],[-97.0197,47.9142],[-97.0214,47.9147],[-97.0237,47.9159],[-97.0196,47.9175],[-97.018,47.9181],[-97.0177,47.9198],[-97.0183,47.9202],[-97.0196,47.9211],[-97.0213,47.9221],[-97.0219,47.9224],[-97.0235,47.9236],[-97.0247,47.9244],[-97.026,47.9253],[-97.0284,47.9269],[-97.0296,47.9276],[-97.0323,47.9285],[-97.0357,47.9302],[-97.0373,47.9333],[-97.0368,47.9343],[-97.0355,47.9366],[-97.036,47.9394],[-97.0374,47.9399],[-97.0391,47.9405],[-97.0394,47.9405],[-97.0416,47.9406],[-97.0417,47.9406],[-97.0449,47.9411],[-97.051,47.9434],[-97.0545,47.9463],[-97.0555,47.9491],[-97.0555,47.9491],[-97.0553,47.9502],[-97.0551,47.9508],[-97.0525,47.9548],[-97.0524,47.9572],[-97.054,47.9597],[-97.059,47.9621],[-97.0613,47.9636],[-97.0614,47.9636],[-97.0618,47.9645],[-97.0615,47.9659],[-97.06,47.9672],[-97.0578,47.969],[-97.0571,47.9705],[-97.0593,47.974],[-97.0591,47.9754],[-97.0589,47.976],[-97.0588,47.9762],[-97.0587,47.9766],[-97.0584,47.977],[-97.0582,47.9774],[-97.0579,47.9778],[-97.0577,47.9781],[-97.0577,47.9782],[-97.0574,47.9787],[-97.0571,47.9792],[-97.0567,47.9801],[-97.0564,47.9806],[-97.0563,47.9811],[-97.0561,47.9815],[-97.0559,47.9821],[-97.0556,47.9828],[-97.0554,47.9833],[-97.0553,47.9838],[-97.0552,47.9842],[-97.0549,47.9849],[-97.0546,47.9855],[-97.0544,47.986],[-97.0541,47.9866],[-97.0539,47.9871],[-97.0537,47.9877],[-97.0535,47.988],[-97.0534,47.9884],[-97.0533,47.9887],[-97.0532,47.989],[-97.053,47.9894],[-97.053,47.9898],[-97.053,47.9903],[-97.053,47.9905],[-97.0531,47.9907],[-97.0532,47.9909],[-97.0533,47.9912],[-97.0534,47.9915],[-97.0535,47.9917],[-97.0538,47.992],[-97.0541,47.9923],[-97.0543,47.9925],[-97.0545,47.9926],[-97.0549,47.993],[-97.0555,47.9933],[-97.0561,47.9936],[-97.0566,47.9938],[-97.0571,47.9939],[-97.0578,47.9941],[-97.0584,47.9943],[-97.0591,47.9945],[-97.0597,47.9948],[-97.0601,47.9949],[-97.0604,47.9951],[-97.0608,47.9953],[-97.0614,47.9956],[-97.0617,47.9957],[-97.0619,47.9959],[-97.0622,47.996],[-97.0625,47.9962],[-97.0628,47.9965],[-97.063,47.9967],[-97.0633,47.997],[-97.0637,47.9975],[-97.0639,47.9977],[-97.0641,47.9982],[-97.0642,47.9986],[-97.0644,47.9989],[-97.0644,47.9994],[-97.0645,48.0],[-97.0645,48.0004],[-97.0644,48.002],[-97.0644,48.0027],[-97.0645,48.0034],[-97.0648,48.0045],[-97.0656,48.0064],[-97.0659,48.0071],[-97.0662,48.0079],[-97.0667,48.0089],[-97.0667,48.0096],[-97.0666,48.0102],[-97.0654,48.0114],[-97.0638,48.0125],[-97.0636,48.0126],[-97.063,48.0132],[-97.0628,48.0138],[-97.0629,48.0145],[-97.0632,48.015],[-97.0638,48.0153],[-97.0649,48.0157],[-97.0685,48.016],[-97.0692,48.0162],[-97.0706,48.017],[-97.0717,48.0181],[-97.0722,48.0192],[-97.0723,48.0196],[-97.0723,48.0201],[-97.0721,48.0207],[-97.0721,48.0209],[-97.0719,48.0214],[-97.0713,48.0228],[-97.0699,48.0247],[-97.0689,48.0263],[-97.0687,48.0277],[-97.0688,48.029],[-97.0691,48.0313],[-97.0697,48.0334],[-97.07,48.0354],[-97.0701,48.0361],[-97.0699,48.0374],[-97.0704,48.0418],[-97.0712,48.0458],[-97.0719,48.0474],[-97.0722,48.0481],[-97.0732,48.0499],[-97.0732,48.05],[-97.074,48.0513],[-97.0747,48.0521],[-97.0756,48.0528],[-97.0767,48.0533],[-97.0782,48.054],[-97.0795,48.0545],[-97.0815,48.0553],[-97.0828,48.0558],[-97.084,48.0564],[-97.0845,48.0567],[-97.0859,48.0575],[-97.0869,48.0583],[-97.0881,48.0596],[-97.0892,48.0611],[-97.0905,48.0627],[-97.0905,48.0628],[-97.0908,48.0631],[-97.0919,48.0644],[-97.092,48.0644],[-97.0932,48.0653],[-97.0951,48.0669],[-97.0958,48.0677],[-97.0963,48.0688],[-97.0969,48.07],[-97.0972,48.0706],[-97.0977,48.0711],[-97.0982,48.0714],[-97.0988,48.0715],[-97.0997,48.0716],[-97.1012,48.0715],[-97.103,48.0717],[-97.1038,48.0719],[-97.1044,48.0725],[-97.1046,48.0731],[-97.1045,48.074],[-97.1041,48.0746],[-97.1007,48.0775],[-97.1005,48.078],[-97.1001,48.0788],[-97.0998,48.0799],[-97.0994,48.0822],[-97.0994,48.0838],[-97.0996,48.0849],[-97.0997,48.0859],[-97.1001,48.0869],[-97.1012,48.0884],[-97.1021,48.0892],[-97.1034,48.0898],[-97.1047,48.0902],[-97.1066,48.0904],[-97.108,48.0906],[-97.1094,48.091],[-97.1098,48.0914],[-97.1097,48.0917],[-97.1095,48.0922],[-97.1087,48.0928],[-97.1067,48.0934],[-97.1066,48.0934],[-97.104,48.0939],[-97.1031,48.0941],[-97.1025,48.0946],[-97.102,48.0953],[-97.1018,48.0959],[-97.1022,48.0967],[-97.1029,48.0973],[-97.1041,48.098],[-97.106,48.0987],[-97.1066,48.0989],[-97.1074,48.0992],[-97.108,48.0996],[-97.1084,48.0999],[-97.1086,48.1003],[-97.1088,48.1008],[-97.1089,48.1017],[-97.1088,48.1028],[-97.109,48.1038],[-97.1095,48.1048],[-97.1107,48.1056],[-97.1114,48.106],[-97.1124,48.1062],[-97.1131,48.1062],[-97.115,48.106],[-97.1169,48.1057],[-97.1181,48.1056],[-97.1197,48.1054],[-97.1208,48.1056],[-97.1218,48.1059],[-97.1225,48.1063],[-97.1232,48.1067],[-97.1234,48.1073],[-97.1235,48.1076],[-97.1236,48.1078],[-97.1236,48.1081],[-97.1231,48.1095],[-97.122,48.1109],[-97.121,48.1123],[-97.1205,48.1134],[-97.1207,48.115],[-97.121,48.1159],[-97.1215,48.117],[-97.1253,48.1223],[-97.1256,48.1224],[-97.1257,48.1226],[-97.1261,48.1233],[-97.1268,48.1243],[-97.127,48.1246],[-97.1271,48.125],[-97.1275,48.1258],[-97.1282,48.1272],[-97.1286,48.1284],[-97.1288,48.1291],[-97.129,48.1309],[-97.1294,48.1332],[-97.13,48.134],[-97.1314,48.135],[-97.1323,48.1358],[-97.1328,48.1362],[-97.1332,48.1366],[-97.1334,48.1372],[-97.133,48.1375],[-97.1325,48.1377],[-97.1319,48.1376],[-97.1303,48.1372],[-97.1293,48.1369],[-97.1289,48.1367],[-97.128,48.1364],[-97.1276,48.1362],[-97.1267,48.1361],[-97.1253,48.1361],[-97.1241,48.1364],[-97.124,48.1365],[-97.123,48.137],[-97.1227,48.1375],[-97.1224,48.1381],[-97.1223,48.1386],[-97.1223,48.1391],[-97.1228,48.1398],[-97.1234,48.1402],[-97.1239,48.1406],[-97.1248,48.1409],[-97.1253,48.1411],[-97.1266,48.1416],[-97.1277,48.1418],[-97.1294,48.1421],[-97.1297,48.1421],[-97.1319,48.1424],[-97.1347,48.143],[-97.1367,48.1433],[-97.1379,48.1433],[-97.1393,48.1429],[-97.1407,48.1423],[-97.1415,48.1417],[-97.1426,48.1413],[-97.1435,48.141],[-97.1444,48.1411],[-97.1454,48.1413],[-97.1461,48.1417],[-97.1465,48.1423],[-97.1466,48.1433],[-97.1465,48.1441],[-97.1458,48.1452],[-97.1447,48.1466],[-97.1435,48.1475],[-97.1425,48.1487],[-97.1413,48.1501],[-97.1405,48.1508],[-97.1402,48.1509],[-97.1391,48.1516],[-97.1371,48.1523],[-97.1328,48.1535],[-97.1307,48.1542],[-97.1305,48.1543],[-97.1281,48.1552],[-97.1263,48.156],[-97.1253,48.1563],[-97.1244,48.1566],[-97.1236,48.1571],[-97.1225,48.1577],[-97.1217,48.1583],[-97.1211,48.1588],[-97.121,48.1591],[-97.1209,48.1596],[-97.121,48.1608],[-97.1211,48.1612],[-97.1214,48.1615],[-97.1218,48.1617],[-97.1224,48.1621],[-97.1233,48.1625],[-97.1241,48.1627],[-97.1247,48.1628],[-97.1253,48.1629],[-97.1273,48.1628],[-97.1285,48.1626],[-97.1305,48.162],[-97.1313,48.1617],[-97.1322,48.1614],[-97.1345,48.1603],[-97.1363,48.1598],[-97.1385,48.1595],[-97.1403,48.1598],[-97.1419,48.1603],[-97.1431,48.1611],[-97.1442,48.1625],[-97.1443,48.1633],[-97.1445,48.1641],[-97.1447,48.165],[-97.1451,48.1668],[-97.1454,48.1675],[-97.1463,48.1686],[-97.1475,48.1706],[-97.1475,48.1725],[-97.1467,48.1733]]],"type":"Polygon"},"id":"60","properties":{"Area":5177876131.64875,"CTYONLY_":9,"Code":"POLK","LASTMOD":"1999-12-31T23:59:59Z","Name":"Polk","Perimiter":458889.41551},"type":"Feature"},{"geometry":{"coordinates":[[[-96.5008,48.1742],[-96.5008,48.1742],[-96.5006,48.1741],[-96.5003,48.1741],[-96.4973,48.174],[-96.4946,48.1741],[-96.4841,48.174],[-96.4791,48.1741],[-96.4789,48.1741],[-96.4773,48.1741],[-96.4735,48.174],[-96.467,48.1741],[-96.4592,48.1742],[-96.4569,48.1742],[-96.4564,48.1742],[-96.4563,48.1743],[-96.4561,48.1744],[-96.4454,48.1747],[-96.4436,48.1747],[-96.4402,48.1748],[-96.438,48.1749],[-96.4359,48.1749],[-96.4352,48.1749],[-96.4346,48.1749],[-96.4295,48.1749],[-96.4206,48.1749],[-96.4135,48.1749],[-96.4126,48.1749],[-96.4126,48.1749],[-96.4054,48.1748],[-96.3964,48.1748],[-96.3906,48.1748],[-96.3905,48.1748],[-96.3894,48.1748],[-96.3856,48.1747],[-96.38,48.1745],[-96.3781,48.1746],[-96.3753,48.1748],[-96.3728,48.1749],[-96.3706,48.175],[-96.3685,48.1751],[-96.3682,48.1751],[-96.3682,48.1751],[-96.3656,48.175],[-96.3642,48.1749],[-96.361,48.1748],[-96.3581,48.1747],[-96.3542,48.1746],[-96.351,48.1745],[-96.3477,48.1744],[-96.3473,48.1744],[-96.347,48.1743],[-96.3466,48.1743],[-96.343,48.1744],[-96.3402,48.1744],[-96.338,48.1745],[-96.3358,48.1744],[-96.3356,48.1745],[-96.3301,48.1745],[-96.3253,48.1746],[-96.3252,48.1746],[-96.3145,48.1747],[-96.3035,48.1747],[-96.3029,48.1747],[-96.2977,48.1747],[-96.2824,48.1747],[-96.2823,48.1747],[-96.2805,48.1747],[-96.2619,48.1749],[-96.2612,48.1749],[-96.2607,48.1749],[-96.2596,48.1749],[-96.2562,48.1744],[-96.252,48.174],[-96.2511,48.174],[-96.2503,48.1739],[-96.2491,48.1737],[-96.2476,48.1735],[-96.2398,48.1728],[-96.2397,48.1727],[-96.2397,48.1727],[-96.2391,48.1727],[-96.2329,48.1725],[-96.2307,48.1725],[-96.2287,48.1725],[-96.2275,48.1724],[-96.2251,48.1724],[-96.2188,48.1722],[-96.2179,48.1722],[-96.2177,48.1722],[-96.2076,48.1722],[-96.2072,48.1722],[-96.2038,48.1722],[-96.2023,48.1722],[-96.1963,48.1721],[-96.1959,48.1721],[-96.1954,48.1721],[-96.1948,48.1721],[-96.191,48.1721],[-96.1874,48.1721],[-96.1834,48.172],[-96.1827,48.1722],[-96.1813,48.1725],[-96.1741,48.1736],[-96.1737,48.1736],[-96.1736,48.1736],[-96.1641,48.1736],[-96.1625,48.1736],[-96.1518,48.1736],[-96.1516,48.1736],[-96.1388,48.1732],[-96.1302,48.173],[-96.1298,48.173],[-96.1297,48.173],[-96.1253,48.1727],[-96.1189,48.1722],[-96.1176,48.1722],[-96.1084,48.1718],[-96.1084,48.1718],[-96.0979,48.172],[-96.09,48.172],[-96.09,48.172],[-96.079,48.1721],[-96.0685,48.1721],[-96.0685,48.1721],[-96.0592,48.1721],[-96.0468,48.1722],[-96.0468,48.1722],[-96.0254,48.1721],[-96.025,48.1721],[-96.0171,48.172],[-96.0101,48.1718],[-96.0047,48.1717],[-96.0036,48.1718],[-96.0035,48.1718],[-96.0032,48.1718],[-96.0028,48.1718],[-96.0023,48.1718],[-96.0003,48.1717],[-95.9956,48.1717],[-95.9819,48.1717],[-95.9817,48.1717],[-95.9651,48.1718],[-95.961,48.1718],[-95.9609,48.1718],[-95.9608,48.1718],[-95.9394,48.1719],[-95.9392,48.1719],[-95.9178,48.1719],[-95.9178,48.1719],[-95.9176,48.1719],[-95.896,48.172],[-95.8958,48.172],[-95.8752,48.172],[-95.8744,48.172],[-95.8744,48.172],[-95.8527,48.1721],[-95.8525,48.1721],[-95.8499,48.1721],[-95.8308,48.1722],[-95.8308,48.1722],[-95.8305,48.1722],[-95.8091,48.1722],[-95.809,48.1722],[-95.8088,48.1722],[-95.7874,48.1725],[-95.7657,48.1728],[-95.7657,48.1728],[-95.7502,48.1727],[-95.7443,48.1727],[-95.744,48.1727],[-95.7227,48.1731],[-95.7226,48.1731],[-95.7157,48.1731],[-95.7128,48.173],[-95.7022,48.1729],[-95.7021,48.1729],[-95.702,48.1729],[-95.6803,48.1728],[-95.6802,48.1728],[-95.662,48.1729],[-95.6591,48.1729],[-95.6376,48.173],[-95.6376,48.173],[-95.6279,48.1731],[-95.6252,48.1731],[-95.6163,48.1731],[-95.6159,48.1731],[-95.5941,48.173],[-95.5939,48.173],[-95.5939,48.1658],[-95.5938,48.1512],[-95.5936,48.1368],[-95.5931,48.1223],[-95.593,48.1078],[-95.5928,48.0931],[-95.5926,48.0787],[-95.5925,48.0642],[-95.5925,48.0497],[-95.5923,48.035],[-95.5922,48.0207],[-95.5828,48.0207],[-95.5825,48.0063],[-95.5824,47.9917],[-95.5825,47.9771],[-95.5826,47.9629],[-95.5825,47.9482],[-95.5824,47.9339],[-95.6034,47.9341],[-95.6252,47.9344],[-95.6466,47.9348],[-95.6683,47.9351],[-95.6898,47.9354],[-95.7096,47.9355],[-95.7097,47.9499],[-95.7098,47.9644],[-95.7312,47.9644],[-95.7531,47.9645],[-95.7747,47.9646],[-95.7963,47.9647],[-95.8181,47.9647],[-95.8383,47.9648],[-95.86,47.9649],[-95.8814,47.9648],[-95.9031,47.9648],[-95.925,47.9647],[-95.9462,47.9646],[-95.9671,47.9646],[-95.9887,47.9642],[-96.0106,47.9641],[-96.0324,47.964],[-96.054,47.9638],[-96.0757,47.9637],[-96.096,47.9638],[-96.1173,47.9632],[-96.1389,47.9631],[-96.1606,47.9631],[-96.1826,47.9632],[-96.2044,47.963],[-96.2235,47.9629],[-96.2453,47.9629],[-96.2667,47.9629],[-96.2883,47.963],[-96.31,47.9633],[-96.3316,47.9634],[-96.3526,47.9634],[-96.3738,47.9636],[-96.3954,47.9636],[-96.4172,47.9637],[-96.439,47.9636],[-96.4603,47.9639],[-96.4823,47.9636],[-96.4823,47.9782],[-96.4824,47.9924],[-96.4826,48.0072],[-96.4826,48.0217],[-96.5009,48.0217],[-96.5009,48.0362],[-96.5008,48.0506],[-96.5009,48.0654],[-96.5009,48.0798],[-96.5009,48.0943],[-96.501,48.1089],[-96.5007,48.1234],[-96.5006,48.1379],[-96.5008,48.1524],[-96.5008,48.1669],[-96.5008,48.1742]]],"type":"Polygon"},"id":"57","properties":{"Area":1601102945.98836,"CTYONLY_":10,"Code":"PENN","LASTMOD":"2006-07-04T12:00:00Z","Name":"Pennington","Perimiter":190039.7415},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=0&sortby=%2BLASTMOD","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=html&limit=9&offset=0&sortby=%2BLASTMOD","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/mn_counties/items?f=json&limit=9&offset=9&sortby=%2BLASTMOD","rel":"next","title":"next page","type":"application/geo+json"}],"numberMatched":117,"numberReturned":9,"type":"FeatureCollection"} diff --git a/msautotest/api/extents.map b/msautotest/api/extents.map new file mode 100644 index 0000000000..a5fd81f09a --- /dev/null +++ b/msautotest/api/extents.map @@ -0,0 +1,73 @@ +# RUN_PARMS: extents_collections.json [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections" "QUERY_STRING=f=json" > [RESULT_DEMIME] + +MAP + EXTENT 190012.242200 4816648.737800 762254.477900 5472427.737000 + SIZE 800 800 + PROJECTION "+init=epsg:26915" END + UNITS METERS + + WEB + METADATA + "oga_enable_request" "OGCAPI" + "oga_title" "OGC API Extent Test" + "oga_onlineresource" "http://localhost/cgi-bin/mapserv/extents/ogcapi" + "oga_fallback_to_map_extent" "true" + END + END + + # layer with no extent and a PROJECTION different from the MAP + # will use the (reprojected) MAP projection for its extent + LAYER + NAME "mn_counties" + DATA "data/mn_counties" + TYPE POLYGON + STATUS OFF + METADATA + "oga_description" "mn_counties" + END + PROJECTION "+init=epsg:32615" END + TEMPLATE VOID + END + + # layer with no extent and no PROJECTION + # will use the MAP projection for its extent + LAYER + NAME "mn_major_rivers" + DATA "data/mn_major_rivers" + TYPE LINE + STATUS OFF + METADATA + "oga_description" "mn_major_rivers" + END + TEMPLATE VOID + END + + # fallback_to_map_extent can be overidden at the + # LAYER level, so in this case it will be calculated from source + LAYER + NAME "mn_major_rivers2" + DATA "data/mn_major_rivers" + TYPE LINE + STATUS OFF + METADATA + "oga_description" "mn_major_rivers2" + "oga_fallback_to_map_extent" "false" + END + TEMPLATE VOID + END + + # LAYER EXTENT will be used when available + LAYER + NAME "mn_population_centers" + EXTENT 190832.625000 4816672.500000 747463.375000 5468044.853100 + DATA "data/mn_population_centers" + TYPE POINT + STATUS OFF + METADATA + "oga_description" "mn_population_centers" + END + PROJECTION "+init=epsg:26915" END + TEMPLATE VOID + END + +END diff --git a/msautotest/api/ogcapi.map b/msautotest/api/ogcapi.map new file mode 100644 index 0000000000..a80e0355f0 --- /dev/null +++ b/msautotest/api/ogcapi.map @@ -0,0 +1,357 @@ +# RUN_PARMS: ogcapi_root.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi" "QUERY_STRING=f=json" > [RESULT] +# RUN_PARMS: ogcapi_root.html.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi" QUERY_STRING= > [RESULT] +# RUN_PARMS: ogcapi_root.json [ENV HTTP_ACCEPT=application/json] [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi" "QUERY_STRING=" > [RESULT_DEMIME] +# RUN_PARMS: ogcapi_error_repeated_query_parameter.json [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi" "QUERY_STRING=f=json&f=bar" > [RESULT_DEMIME] +# RUN_PARMS: ogcapi_collections.json [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections" "QUERY_STRING=f=json" > [RESULT_DEMIME] +# RUN_PARMS: ogcapi_collections_mn_counties.json [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties" "QUERY_STRING=f=json" > [RESULT_DEMIME] +# RUN_PARMS: ogcapi_collections_mn_counties.html [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties" "QUERY_STRING=f=html" > [RESULT_DEMIME] +# RUN_PARMS: ogcapi_collections_mn_counties_items_with_headers.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json" > [RESULT] +# RUN_PARMS: ogcapi_collections_mn_counties_items_storage_crs.json [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&crs=http://www.opengis.net/def/crs/EPSG/0/32615&limit=1" > [RESULT] +# RUN_PARMS: ogcapi_collections_mn_counties_items_epsg_4326_with_headers.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&crs=http://www.opengis.net/def/crs/EPSG/0/4326&limit=1" > [RESULT] +# RUN_PARMS: ogcapi_collections_mn_counties_items_bad_crs.json [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&crs=http://www.opengis.net/def/crs/EPSG/0/12345&limit=1" > [RESULT_DEMIME] +# RUN_PARMS: ogcapi_collections_mn_counties_items_empty_crs.json [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&crs=&limit=1" > [RESULT_DEMIME] +# RUN_PARMS: ogcapi_collections_mn_counties_items_bbox_crs.json [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&bbox=190012.242200,4816648.737800,762254.477900,5472427.737000&bbox-crs=http://www.opengis.net/def/crs/EPSG/0/32615&limit=1" > [RESULT_DEMIME] +# RUN_PARMS: ogcapi_collections_mn_counties_items_bbox_crs_epsg_4326.json [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&bbox=-90,-180,90,0&bbox-crs=http://www.opengis.net/def/crs/EPSG/0/4326&limit=1" > [RESULT_DEMIME] +# RUN_PARMS: ogcapi_collections_mn_counties_items_bad_bbox_crs.json [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&bbox=-90,-180,90,0&bbox-crs=http://www.opengis.net/def/crs/EPSG/0/12345&limit=1" > [RESULT_DEMIME] +# RUN_PARMS: ogcapi_collections_mn_counties_items_empty_bbox_crs.json [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&bbox=-90,-180,90,0&bbox-crs=&limit=1" > [RESULT_DEMIME] +# RUN_PARMS: ogcapi_collections_mn_counties_items_limit_1.json [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&limit=1" > [RESULT_DEMIME] +# RUN_PARMS: ogcapi_collections_mn_counties_items_limit_1_offset_2.json [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&limit=1&offset=2" > [RESULT_DEMIME] +# RUN_PARMS: ogcapi_collections_mn_counties_items_limit_bbox_empty_result.json [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&bbox=2,49,3,50" > [RESULT_DEMIME] +# RUN_PARMS: ogcapi_collections_mn_counties_items_by_id.json [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items/35" "QUERY_STRING=f=json" > [RESULT_DEMIME] +# RUN_PARMS: ogcapi_collections_mn_counties_items_by_id_not_found.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items/12345678" "QUERY_STRING=f=json" > [RESULT_DEMIME] +# RUN_PARMS: ogcapi_collections_mn_population_centers_items_by_id_no_extent.json [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_population_centers/items/2710700172" "QUERY_STRING=f=json" > [RESULT_DEMIME] +# RUN_PARMS: ogcapi_api.json [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/api" "QUERY_STRING=f=json" > [RESULT_DEMIME] +# RUN_PARMS: conformance.json [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/conformance" "QUERY_STRING=f=json" > [RESULT_DEMIME] +# RUN_PARMS: conformance.html [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/conformance" "QUERY_STRING=f=html" > [RESULT_DEMIME] +# RUN_PARMS: ogcapi_invalid_mapfile.txt [MAPSERV] "PATH_INFO=/invalid.map/ogcapi" "QUERY_STRING=f=json" > [RESULT_DEVERSION] +# RUN_PARMS: ogcapi_missing_api_signature1.txt [MAPSERV] "PATH_INFO=/[MAPFILE]" "QUERY_STRING=f=json" > [RESULT_DEVERSION] +# RUN_PARMS: ogcapi_missing_api_signature2.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/" "QUERY_STRING=f=json" > [RESULT_DEVERSION] +# RUN_PARMS: ogcapi_invalid_api_signature1.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/invalid" "QUERY_STRING=f=json" > [RESULT_DEVERSION] +# RUN_PARMS: ogcapi_invalid_api_signature2.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/invalid/" "QUERY_STRING=f=json" > [RESULT_DEVERSION] + +# RUN_PARMS: ogcapi_landing_page_unknown_parameter.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi" "QUERY_STRING=f=json&unknown=parameter" > [RESULT] +# RUN_PARMS: ogcapi_api_unknown_parameter.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/api" "QUERY_STRING=f=json&unknown=parameter" > [RESULT] +# RUN_PARMS: ogcapi_conformance_unknown_parameter.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/conformance" "QUERY_STRING=f=json&unknown=parameter" > [RESULT] +# RUN_PARMS: ogcapi_collections_unknown_parameter.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections" "QUERY_STRING=f=json&unknown=parameter" > [RESULT] +# RUN_PARMS: ogcapi_collection_unknown_parameter.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties" "QUERY_STRING=f=json&unknown=parameter" > [RESULT] +# RUN_PARMS: ogcapi_collections_items_unknown_parameter.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&unknown=parameter" > [RESULT] +# RUN_PARMS: ogcapi_collections_queryables_unknown_parameter.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/queryables" "QUERY_STRING=f=json&unknown=parameter" > [RESULT] + +# RUN_PARMS: ogcapi_queryable_in_query_parameters_match.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&Name=Rice" > [RESULT] +# RUN_PARMS: ogcapi_queryable_in_query_parameters_match_with_bbox.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&Name=Rice&bbox=-100,0,-90,90" > [RESULT] +# RUN_PARMS: ogcapi_queryable_in_query_parameters_no_match_with_bbox.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&Name=Rice&bbox=0,0,1,1" > [RESULT] +# RUN_PARMS: ogcapi_queryable_in_query_parameters_no_match.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&Name=no_match" > [RESULT] +# RUN_PARMS: ogcapi_queryable_in_query_parameters_not_queryable.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&AREA=0" > [RESULT] + +# RUN_PARMS: ogcapi_queryables.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/queryables" "QUERY_STRING=f=json" > [RESULT] +# RUN_PARMS: ogcapi_queryables.html [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/queryables" "QUERY_STRING=f=html" > [RESULT_DEMIME] +# RUN_PARMS: ogcapi_queryables_error_collection.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/error/queryables" "QUERY_STRING=f=json" > [RESULT] +# RUN_PARMS: ogcapi_queryables_error_unexpected_kvp.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/queryables" "QUERY_STRING=f=json&unexpected=true" > [RESULT] +# RUN_PARMS: ogcapi_queryables_none.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties_no_queryables_and_sortables/queryables" "QUERY_STRING=f=json" > [RESULT] +# RUN_PARMS: ogcapi_queryables_all.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties_all_queryables_and_sortables/queryables" "QUERY_STRING=f=json" > [RESULT] + +# RUN_PARMS: ogcapi_schema.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/schema" "QUERY_STRING=f=json" > [RESULT] +# RUN_PARMS: ogcapi_schema.html [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/schema" "QUERY_STRING=f=html" > [RESULT_DEMIME] +# RUN_PARMS: ogcapi_schema_error_collection.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/error/schema" "QUERY_STRING=f=json" > [RESULT] +# RUN_PARMS: ogcapi_schema_error_unexpected_kvp.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/schema" "QUERY_STRING=f=json&unexpected=true" > [RESULT] + +# RUN_PARMS: ogcapi_sortables.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/sortables" "QUERY_STRING=f=json" > [RESULT] +# RUN_PARMS: ogcapi_sortables.html [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/sortables" "QUERY_STRING=f=html" > [RESULT_DEMIME] +# RUN_PARMS: ogcapi_sortables_error_collection.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/error/sortables" "QUERY_STRING=f=json" > [RESULT] +# RUN_PARMS: ogcapi_sortables_error_unexpected_kvp.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/sortables" "QUERY_STRING=f=json&unexpected=true" > [RESULT] +# RUN_PARMS: ogcapi_sortables_none.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties_no_queryables_and_sortables/sortables" "QUERY_STRING=f=json" > [RESULT] +# RUN_PARMS: ogcapi_sortables_all.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties_all_queryables_and_sortables/sortables" "QUERY_STRING=f=json" > [RESULT] + +# RUN_PARMS: ogcapi_sorted.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&sortby=LASTMOD" > [RESULT] +# RUN_PARMS: ogcapi_sorted_plus.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&sortby=%2BLASTMOD" > [RESULT] +# RUN_PARMS: ogcapi_sorted_minus.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&sortby=-LASTMOD" > [RESULT] +# RUN_PARMS: ogcapi_sorted_error.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&sortby=illegal" > [RESULT] + +# CQL2-text testing + +# RUN_PARMS: ogcapi_cql2_text_equal.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&filter=Name='Rice'" > [RESULT] +# RUN_PARMS: ogcapi_cql2_quoted_identifier.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&filter=%22Name%22='Rice'" > [RESULT] +# RUN_PARMS: ogcapi_cql2_text_iequal.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&filter=CASEI(Name)=CASEI('rice')" > [RESULT] +# RUN_PARMS: ogcapi_cql2_text_like_wildcard.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&filter=Name LIKE 'R%25e'" > [RESULT] +# RUN_PARMS: ogcapi_cql2_text_like_no_match.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&filter=Name LIKE 'rice'" > [RESULT] +# RUN_PARMS: ogcapi_cql2_text_casei_like.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&filter=casei(Name) LIKE CASEI('rice')" > [RESULT] +# RUN_PARMS: ogcapi_cql2_text_not_casei_not_like.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&filter=NOT casei(Name) NOT LIKE CASEI('rice')" > [RESULT] +# RUN_PARMS: ogcapi_cql2_text_like_single_char.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&filter=Name LIKE 'Ri_e'" > [RESULT] +# RUN_PARMS: ogcapi_cql2_text_not_not_like.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&filter=NOT Name NOT LIKE 'Rice'" > [RESULT] +# RUN_PARMS: ogcapi_cql2_text_not_equal.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&filter=Name<>'Rice'" > [RESULT] +# RUN_PARMS: ogcapi_cql2_text_not_not_iequal.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&filter=NOT CASEI(Name) <> CASEI('rice')" > [RESULT] +# RUN_PARMS: ogcapi_cql2_text_lt.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&filter=CTYONLY_<3" > [RESULT] +# RUN_PARMS: ogcapi_cql2_text_le.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&filter=CTYONLY_<=3" > [RESULT] +# RUN_PARMS: ogcapi_cql2_text_gt.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&filter=CTYONLY_>117" > [RESULT] +# RUN_PARMS: ogcapi_cql2_text_ge.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&filter=CTYONLY_>=117" > [RESULT] +# RUN_PARMS: ogcapi_cql2_text_not.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&filter=NOT Name<>'Rice'" > [RESULT] +# RUN_PARMS: ogcapi_cql2_text_and_true.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&filter=Name='Rice' AND 1=1" > [RESULT] +# RUN_PARMS: ogcapi_cql2_text_and_issue_GHSA_v4x2_j2g2_rxwp.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&filter=1=1 AND (1=1 AND 1=0)" > [RESULT] +# RUN_PARMS: ogcapi_cql2_text_four_and.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&filter=Name='Rice' AND 1=1 AND 1=1 AND 1=1" > [RESULT] +# RUN_PARMS: ogcapi_cql2_text_and_false.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&filter=Name='Rice' AND 1=0" > [RESULT] +# RUN_PARMS: ogcapi_cql2_text_or_true.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&filter=Name='Rice' OR 1=1" > [RESULT] +# RUN_PARMS: ogcapi_cql2_text_or_false.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&filter=0=1 OR 1=0" > [RESULT] +# RUN_PARMS: ogcapi_cql2_text_in_json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&filter=CTYONLY_ IN (3, 5)" > [RESULT] +# RUN_PARMS: ogcapi_cql2_text_not_not_in_json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&filter=NOT CTYONLY_ NOT IN (3, 5)" > [RESULT] +# RUN_PARMS: ogcapi_cql2_text_between_json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&filter=CTYONLY_ BETWEEN 3 AND 5" > [RESULT] +# RUN_PARMS: ogcapi_cql2_text_not_not_between_json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&filter=NOT CTYONLY_ NOT BETWEEN 3 AND 5" > [RESULT] +# RUN_PARMS: ogcapi_cql2_text_is_null_not_supported.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&filter=Name IS NULL" > [RESULT] +# RUN_PARMS: ogcapi_cql2_text_is_not_null_not_supported.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&filter=Name IS NOT NULL" > [RESULT] +# RUN_PARMS: ogcapi_cql2_text_not_a_queryable.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&filter=unknown=0" > [RESULT] +# RUN_PARMS: ogcapi_cql2_text_timestamp.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&filter=LASTMOD=TIMESTAMP('2003-01-01T01:10:00Z')" > [RESULT] +# RUN_PARMS: ogcapi_cql2_text_double_constant.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&filter=Area=8167237870.91888" > [RESULT] +# RUN_PARMS: ogcapi_cql2_text_true_or_true.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&Name=Rice&filter=true or true&limit=1" > [RESULT] +# RUN_PARMS: ogcapi_cql2_text_true_equal_true.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&Name=Rice&filter=true=true&limit=1" > [RESULT] + +# RUN_PARMS: ogcapi_cql2_text_and_query_param_filter.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&Name=Rice&filter=true" > [RESULT] +# RUN_PARMS: ogcapi_cql2_text_and_query_param_filter2.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&Name=Rice&filter=false" > [RESULT] + +# RUN_PARMS: ogcapi_cql2_text_add.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&filter=CTYONLY_=1%2B3" > [RESULT] +# RUN_PARMS: ogcapi_cql2_text_subtract.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&filter=CTYONLY_=5-1" > [RESULT] +# RUN_PARMS: ogcapi_cql2_text_multiply.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&filter=CTYONLY_=2*2" > [RESULT] +# RUN_PARMS: ogcapi_cql2_text_div.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&filter=CTYONLY_=12/3" > [RESULT] +# RUN_PARMS: ogcapi_cql2_text_div2.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&filter=CTYONLY_=12 div 3" > [RESULT] +# RUN_PARMS: ogcapi_cql2_text_mod.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&filter=CTYONLY_=9%255" > [RESULT] +# RUN_PARMS: ogcapi_cql2_text_unary_minus.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&filter=CTYONLY_=-(-4)" > [RESULT] + +# RUN_PARMS: ogcapi_cql2_text_s_intersects_bbox.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&filter=s_intersects(geom,bbox(-180,-90,0,90))&limit=1" > [RESULT] +# RUN_PARMS: ogcapi_cql2_text_s_intersects_point.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&filter=s_intersects(geom,point(-94.4297 48.642))&limit=1" > [RESULT] +# RUN_PARMS: ogcapi_cql2_text_filter_crs.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&filter=s_intersects(geom,point(48.642 -94.4297))&filter-crs=http://www.opengis.net/def/crs/EPSG/0/4326&limit=1" > [RESULT] +# RUN_PARMS: ogcapi_cql2_text_filter_crs_invalid.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&filter=s_intersects(geom,point(48.642 -94.4297))&filter-crs=invalid&limit=1" > [RESULT] + +# RUN_PARMS: ogcapi_cql2_text_syntax_error.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&filter=Area=" > [RESULT] +# RUN_PARMS: ogcapi_cql2_text_unsupported_function.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&filter=1=foo('bar')" > [RESULT] +# RUN_PARMS: ogcapi_cql2_text_filter_lang_invalid.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&filter=1=1&filter-lang=invalid&limit=1" > [RESULT] + +# CQL2-JSON testing + +# RUN_PARMS: ogcapi_cql2_json_equal.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" 'QUERY_STRING=f=json&filter={"op":"=","args":[{"property":"Name"},"Rice"]}&filter-lang=cql2-json' > [RESULT] +# RUN_PARMS: ogcapi_cql2_json_not_not_equal.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" 'QUERY_STRING=f=json&filter={"op":"not","args":[{"op":"<>","args":[{"property":"Name"},"Rice"]}]}&filter-lang=cql2-json' > [RESULT] +# RUN_PARMS: ogcapi_cql2_json_like.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" 'QUERY_STRING=f=json&filter={"op":"like","args":[{"property":"Name"},"R_ce"]}&filter-lang=cql2-json' > [RESULT] +# RUN_PARMS: ogcapi_cql2_json_lt.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" 'QUERY_STRING=f=json&filter={"op":"<","args":[{"property":"CTYONLY_"},3]}&filter-lang=cql2-json' > [RESULT] +# RUN_PARMS: ogcapi_cql2_json_le.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" 'QUERY_STRING=f=json&filter={"op":"<=","args":[{"property":"CTYONLY_"},3]}&filter-lang=cql2-json' > [RESULT] +# RUN_PARMS: ogcapi_cql2_json_gt.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" 'QUERY_STRING=f=json&filter={"op":">","args":[{"property":"CTYONLY_"},117]}&filter-lang=cql2-json' > [RESULT] +# RUN_PARMS: ogcapi_cql2_json_ge.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" 'QUERY_STRING=f=json&filter={"op":">=","args":[{"property":"CTYONLY_"},117]}&filter-lang=cql2-json' > [RESULT] +# RUN_PARMS: ogcapi_cql2_json_and_true.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" 'QUERY_STRING=f=json&filter={"op":"and","args":[{"op":"=","args":[{"property":"Name"},"Rice"]},true]}&filter-lang=cql2-json' > [RESULT] +# RUN_PARMS: ogcapi_cql2_json_and_false.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" 'QUERY_STRING=f=json&filter={"op":"and","args":[{"op":"=","args":[{"property":"Name"},"Rice"]},false]}&filter-lang=cql2-json' > [RESULT] +# RUN_PARMS: ogcapi_cql2_json_false_or_true.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" 'QUERY_STRING=f=json&filter={"op":"or","args":[false,true]}&filter-lang=cql2-json&limit=1' > [RESULT] +# RUN_PARMS: ogcapi_cql2_json_false_or_false.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" 'QUERY_STRING=f=json&filter={"op":"and","args":[false,false]}&filter-lang=cql2-json' > [RESULT] +# RUN_PARMS: ogcapi_cql2_json_in.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" 'QUERY_STRING=f=json&filter={"op":"in","args":[{"property":"CTYONLY_"},[3,5]]}&filter-lang=cql2-json' > [RESULT] +# RUN_PARMS: ogcapi_cql2_json_between.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" 'QUERY_STRING=f=json&filter={"op":"between","args":[{"property":"CTYONLY_"},3,5]}&filter-lang=cql2-json' > [RESULT] + +# RUN_PARMS: ogcapi_cql2_json_add.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" 'QUERY_STRING=f=json&filter={"op":"=","args":[{"property":"CTYONLY_"},{"op":"%2B","args":[1,3]}]}&filter-lang=cql2-json' > [RESULT] +# RUN_PARMS: ogcapi_cql2_json_subtract.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" 'QUERY_STRING=f=json&filter={"op":"=","args":[{"property":"CTYONLY_"},{"op":"-","args":[5,1]}]}&filter-lang=cql2-json' > [RESULT] +# RUN_PARMS: ogcapi_cql2_json_multiply.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" 'QUERY_STRING=f=json&filter={"op":"=","args":[{"property":"CTYONLY_"},{"op":"*","args":[2,2]}]}&filter-lang=cql2-json' > [RESULT] +# RUN_PARMS: ogcapi_cql2_json_div.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" 'QUERY_STRING=f=json&filter={"op":"=","args":[{"property":"CTYONLY_"},{"op":"/","args":[12,3]}]}&filter-lang=cql2-json' > [RESULT] +# RUN_PARMS: ogcapi_cql2_json_div2.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" 'QUERY_STRING=f=json&filter={"op":"=","args":[{"property":"CTYONLY_"},{"op":"div","args":[12,3]}]}&filter-lang=cql2-json' > [RESULT] +# RUN_PARMS: ogcapi_cql2_json_mod.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" 'QUERY_STRING=f=json&filter={"op":"=","args":[{"property":"CTYONLY_"},{"op":"%25","args":[9,5]}]}&filter-lang=cql2-json' > [RESULT] + +# RUN_PARMS: ogcapi_cql2_json_iequal.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" 'QUERY_STRING=f=json&filter={"op":"=","args":[{"op":"casei","args":[{"property":"Name"}]},{"op":"casei","args":["rice"]}]}&filter-lang=cql2-json' > [RESULT] +# RUN_PARMS: ogcapi_cql2_json_not_not_iequal.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" 'QUERY_STRING=f=json&filter={"op":"not","args":[{"op":"<>","args":[{"op":"casei","args":[{"property":"Name"}]},{"op":"casei","args":["rice"]}]}]}&filter-lang=cql2-json' > [RESULT] +# RUN_PARMS: ogcapi_cql2_json_ilike.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" 'QUERY_STRING=f=json&filter={"op":"like","args":[{"op":"casei","args":[{"property":"Name"}]},{"op":"casei","args":["r_ce"]}]}&filter-lang=cql2-json' > [RESULT] + +# RUN_PARMS: ogcapi_cql2_json_timestamp.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" 'QUERY_STRING=f=json&filter={"op":"=","args":[{"property":"LASTMOD"},{"timestamp":"2003-01-01T01:10:00Z"}]}&filter-lang=cql2-json' > [RESULT] +# RUN_PARMS: ogcapi_cql2_json_date.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" 'QUERY_STRING=f=json&filter={"op":"=","args":[{"property":"LASTMOD"},{"date":"2003-01-01"}]}&filter-lang=cql2-json' > [RESULT] +# RUN_PARMS: ogcapi_cql2_json_timestamp_with_backtick.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" 'QUERY_STRING=f=json&filter={"op":"=","args":[{"property":"LASTMOD"},{"timestamp":"with`backtick"}]}&filter-lang=cql2-json' > [RESULT] + +# RUN_PARMS: ogcapi_cql2_json_s_intersects_bbox.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" 'QUERY_STRING=f=json&filter={"op":"s_intersects","args":[{"property":"geom"},{"bbox":[-180,-90,180,90]}]}&filter-lang=cql2-json&limit=1' > [RESULT] +# RUN_PARMS: ogcapi_cql2_json_s_intersects_bbox_3D.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" 'QUERY_STRING=f=json&filter={"op":"s_intersects","args":[{"property":"geom"},{"bbox":[-90,-180,-1000,90,180,1000]}]}&filter-lang=cql2-json&filter-crs=http://www.opengis.net/def/crs/EPSG/0/4326&limit=1' > [RESULT] +# RUN_PARMS: ogcapi_cql2_json_s_intersects_point.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" 'QUERY_STRING=f=json&filter={"op":"s_intersects","args":[{"property":"geom"},{"type":"Point","coordinates":[-94.4297,48.642]}]}&filter-lang=cql2-json&limit=1' > [RESULT] + +# RUN_PARMS: ogcapi_cql2_json_syntax_error.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&filter=invalid&filter-lang=cql2-json" > [RESULT] +# RUN_PARMS: ogcapi_cql2_json_empty_dict.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_counties/items" "QUERY_STRING=f=json&filter={}&filter-lang=cql2-json" > [RESULT] + +MAP + EXTENT 190012.242200 4816648.737800 762254.477900 5472427.737000 + SIZE 800 800 + + PROJECTION "+init=epsg:26915" END + UNITS METERS + + WEB + METADATA + "oga_html_template_directory" "../../share/ogcapi/templates/html-plain/" + "oga_title" "OGC API Test" ## REQUIRED (or just recommended?) + "oga_description" "This is a test OGC API server description set via oga_description." + "oga_contactperson" "Contact person" + "oga_contacturl" "http://example.com/contact" + "oga_contactelectronicmailaddress" "email@example.com" + "oga_termsofservice" "Terms of Service" + "oga_keywords" "keyword1,keyword2" + "oga_html_tags" "debug,sample" + "oga_tag_debug" "true" + "oga_tag_sample" "sample tag" + "oga_onlineresource" "http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi" ## REQUIRED + #"oga_onlineresource" "http://192.168.0.17/ogcapi/MY_MAP/ogcapi" + "oga_server_description" "Server description" + "oga_links" "link1,link2" + "oga_link1_href" "https://mapserver.org" + "oga_link1_title" "MapServer project website" + "oga_link2_href" "https://ogcapi.ogc.org" + "oga_link2_title" "OCG API website" + "oga_enable_request" "OGCAPI" ## REQUIRED + "oga_max_limit" "15" + "oga_default_limit" "9" + "oga_geometry_precision" "4" + END + END + + LAYER + NAME "mn_counties" + DATA "data/mn_counties" + TYPE POLYGON + STATUS OFF + METADATA + "oga_keywords" "boundary,Minnesota,counties" # falls back to wfs_keywordlist + "oga_description" "This is the standard Minnesota State County Boundary dataset." + "oga_title" "State of Minnesota County Boundaries" + "oga_srs" "EPSG:32615 EPSG:4326" # storageCrs is first in the list + + "oga_links" "link1" + "oga_link1_href" "https://gisdata.mn.gov/dataset/bdry-counties-in-minnesota" + "oga_link1_title" "Layer in Minnesota Geocommons" + + "gml_include_items" "CTY_NAME,AREA,PERIMETER,CTY_ABBR,CTYONLY_,LASTMOD" # also works with oga prefix + "gml_AREA_alias" "Area" + "gml_AREA_type" "Real" + "gml_perimeter_alias" "Perimiter" + "gml_perimeter_type" "Real" + "gml_CTY_NAME_alias" "Name" + "gml_CTY_ABBR_alias" "Code" + "gml_CTYONLY__type" "Integer" + "gml_LASTMOD_type" "DateTime" + "oga_featureid" "coun" + "oga_queryable_items" "cty_name,AREA,CTYONLY_,LASTMOD" + "oga_sortable_items" "lastmod" + END + VALIDATION + "coun" "^[0-9]{1,2}$" # 1 or 2-digit number + END + PROJECTION "+init=epsg:32615" END + TEMPLATE VOID + END + + LAYER + NAME "mn_counties_no_queryables_and_sortables" + DATA "data/mn_counties" + TYPE POLYGON + STATUS OFF + METADATA + "oga_keywords" "boundary,Minnesota,counties" # falls back to wfs_keywordlist + "oga_description" "This is the standard Minnesota State County Boundary dataset." + "oga_title" "State of Minnesota County Boundaries" + "oga_srs" "EPSG:32615 EPSG:4326" # storageCrs is first in the list + + "oga_links" "link1" + "oga_link1_href" "https://gisdata.mn.gov/dataset/bdry-counties-in-minnesota" + "oga_link1_title" "Layer in Minnesota Geocommons" + + "gml_include_items" "CTY_NAME,AREA,PERIMETER,CTY_ABBR,CTYONLY_,LASTMOD" # also works with oga prefix + "gml_AREA_alias" "Area" + "gml_AREA_type" "Real" + "gml_perimeter_alias" "Perimiter" + "gml_perimeter_type" "Real" + "gml_CTY_NAME_alias" "Name" + "gml_CTY_ABBR_alias" "Code" + "gml_CTYONLY__type" "Integer" + "gml_LASTMOD_type" "DateTime" + "oga_featureid" "coun" + END + VALIDATION + "coun" "^[0-9]{1,2}$" # 1 or 2-digit number + END + PROJECTION "+init=epsg:32615" END + TEMPLATE VOID + END + + LAYER + NAME "mn_counties_all_queryables_and_sortables" + DATA "data/mn_counties" + TYPE POLYGON + STATUS OFF + METADATA + "oga_keywords" "boundary,Minnesota,counties" # falls back to wfs_keywordlist + "oga_description" "This is the standard Minnesota State County Boundary dataset." + "oga_title" "State of Minnesota County Boundaries" + "oga_srs" "EPSG:32615 EPSG:4326" # storageCrs is first in the list + + "oga_links" "link1" + "oga_link1_href" "https://gisdata.mn.gov/dataset/bdry-counties-in-minnesota" + "oga_link1_title" "Layer in Minnesota Geocommons" + + "gml_include_items" "CTY_NAME,AREA,PERIMETER,CTY_ABBR,CTYONLY_,LASTMOD" # also works with oga prefix + "gml_AREA_alias" "Area" + "gml_AREA_type" "Real" + "gml_perimeter_alias" "Perimiter" + "gml_perimeter_type" "Real" + "gml_CTY_NAME_alias" "Name" + "gml_CTY_ABBR_alias" "Code" + "gml_CTYONLY__type" "Integer" + "gml_LASTMOD_type" "DateTime" + "oga_featureid" "coun" + "oga_queryable_items" "all" + "oga_sortable_items" "all" + END + VALIDATION + "coun" "^[0-9]{1,2}$" # 1 or 2-digit number + END + PROJECTION "+init=epsg:32615" END + TEMPLATE VOID + END + + LAYER + NAME "mn_major_rivers" + DATA "data/mn_major_rivers" + TYPE LINE + STATUS OFF + METADATA + "oga_keywords" "Minnesota,river,hydrography,centerline" # falls back to wfs_keywordlist + "oga_description" "This dataset represents stream centerlines for major rivers in Minnesota." + "oga_title" "Minnesota Major River Centerlines" + + "oga_links" "link1" + "oga_link1_href" "https://gisdata.mn.gov/dataset/water-major-river-centerlines" + "oga_link1_title" "Layer in Minnesota Geocommons" + + "gml_include_items" "kittle_name,kittle_nbr,length_mi" # also works with oga prefix + "gml_length_mi_alias" "Length" + "gml_kittle_name_alias" "Name" + "gml_kittle_nbr_alias" "Kittle #" + "gml_featureid" "fw_id" + END + VALIDATION + "fw_id" "^[0-9]{6}$" # 6-digit number + END + PROJECTION "+init=epsg:26915" END + TEMPLATE VOID + END + + LAYER + NAME "mn_population_centers" + DATA "data/mn_population_centers" + TYPE POINT + STATUS OFF + METADATA + "oga_keywords" "Minnesota,cities,townships,reservations,county seats,unorganized territories" # falls back to wfs_keywordlist + "oga_description" "This dataset contains cities, townships, reservations, county seats and unorganized Territories in Minnesota, represented with point geometry for cartographic purposes." + "oga_title" "Minnesota Population Centers" + + "oga_links" "link1" + "oga_link1_href" "https://gisdata.mn.gov/dataset/loc-pop-centers" + "oga_link1_title" "Layer in Minnesota Geocommons" + + "gml_include_items" "name,ctu_type,county,population" # also works with oga prefix + "gml_name_alias" "Name" + "gml_ctu_type_alias" "Type" + "gml_county_alias" "County" + "gml_population_alias" "Population" + "gml_featureid" "fips_code" + END + VALIDATION + "fips_code" "^[0-9]{6,10}$" # 6 to 10-character string, digits only + END + PROJECTION "+init=epsg:26915" END + TEMPLATE VOID + END + +END diff --git a/msautotest/api/ogcapi_extraparams.map b/msautotest/api/ogcapi_extraparams.map new file mode 100644 index 0000000000..8d563b9f33 --- /dev/null +++ b/msautotest/api/ogcapi_extraparams.map @@ -0,0 +1,96 @@ +# RUN_PARMS: ogcapi_extraparams_collections.html [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections" "QUERY_STRING=f=html&token=eyJ9.e30.SflKxw&user_id=12345" > [RESULT_DEMIME] +# RUN_PARMS: ogcapi_extraparams_collections.json [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections" "QUERY_STRING=f=json&token=eyJ9.e30.SflKxw&user_id=12345" > [RESULT_DEMIME] +# RUN_PARMS: ogcapi_extraparams_collections_mn_population_centers.html [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_population_centers" "QUERY_STRING=f=html&token=eyJ9.e30.SflKxw&user_id=12345" > [RESULT_DEMIME] +# RUN_PARMS: ogcapi_extraparams_collections_mn_population_centers.json [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_population_centers" "QUERY_STRING=f=json&token=eyJ9.e30.SflKxw&user_id=12345" > [RESULT_DEMIME] + +# RUN_PARMS: ogcapi_extraparams_collection_items.html [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_population_centers/items" "QUERY_STRING=f=html&token=eyJ9.e30.SflKxw&user_id=12345" > [RESULT_DEMIME] +# RUN_PARMS: ogcapi_extraparams_collection_items.json [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_population_centers/items" "QUERY_STRING=f=json&token=eyJ9.e30.SflKxw&user_id=12345" > [RESULT_DEMIME] + +# test with invalid parameter +# RUN_PARMS: ogcapi_extraparams_invalid_parameter.json [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi" "QUERY_STRING=f=json&token=@@@@@&user_id=12345" > [RESULT_DEMIME] +# test with missing parameters (defaults will be used) +# RUN_PARMS: ogcapi_extraparams_no_parameters.json [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi" "QUERY_STRING=f=json" > [RESULT_DEMIME] + +# test with layer level parameters, and an empty token +# RUN_PARMS: ogcapi_extraparams_collections_mn_major_rivers.html [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_major_rivers" "QUERY_STRING=f=html&token=&user_id=" > [RESULT_DEMIME] +# RUN_PARMS: ogcapi_extraparams_collections_mn_major_rivers.json [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_major_rivers" "QUERY_STRING=f=json&token=&user_id=BBB" > [RESULT_DEMIME] + +# test with limit parameter and empty token +# RUN_PARMS: ogcapi_extraparams_collection_items_limit.json [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_population_centers/items" "QUERY_STRING=f=json&limit=2" > [RESULT_DEMIME] + +# RUN_PARMS: ogcapi_extraparams_collections_items_unknown_parameter.json.txt [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/mn_population_centers/items" "QUERY_STRING=f=json&unknown=parameter" > [RESULT] + + +MAP + EXTENT 190012.242200 4816648.737800 762254.477900 5472427.737000 + SIZE 800 800 + + PROJECTION "+init=epsg:26915" END + UNITS METERS + + WEB + + VALIDATION + 'token' '^[A-Za-z0-9\-_]+\.[A-Za-z0-9\-_]+\.[A-Za-z0-9\-_]+$' + 'user_id' '^[0-9]+$' # only allow integers + 'default_token' 'MISSING' + 'default_user_id' '-1' + END + + METADATA + "oga_onlineresource" "http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi" ## REQUIRED + "oga_html_template_directory" "../../share/ogcapi/templates/html-plain/" + "ows_extra_params" "token=%TOKEN%&user_id=%USER_ID%" + "oga_title" "OGC API Test" + "oga_tag_debug" "true" + "oga_server_description" "Server description" + "oga_links" "link1" + "oga_link1_href" "https://mapserver.org" + "oga_link1_title" "MapServer project website" + "oga_enable_request" "OGCAPI" ## REQUIRED + END + END + + LAYER + NAME "mn_major_rivers" + DATA "data/mn_major_rivers" + TYPE LINE + STATUS OFF + METADATA + "oga_description" "This dataset represents stream centerlines for major rivers in Minnesota." + "oga_title" "Minnesota Major River Centerlines" + "gml_include_items" "kittle_name,kittle_nbr,length_mi" + "gml_featureid" "fw_id" + "ows_extra_params" "token=%TOKEN%&user_id=%USER_ID%&layer_param=%LAYER_PARAM%" + END + VALIDATION + 'user_id' '.' # allow any value + 'default_user_id' 'AAA' + 'layer_param' '.' + 'default_layer_param' 'rivers' + END + PROJECTION "+init=epsg:26915" END + TEMPLATE VOID + END + + LAYER + NAME "mn_population_centers" + DATA "data/mn_population_centers" + TYPE POINT + STATUS OFF + METADATA + "oga_title" "Minnesota Population Centers" + "oga_description" "This dataset contains cities, townships, reservations, county seats and unorganized Territories in Minnesota, represented with point geometry for cartographic purposes." + + "oga_links" "link1" + "oga_link1_href" "https://gisdata.mn.gov/dataset/loc-pop-centers" + "oga_link1_title" "Layer in Minnesota Geocommons" + + "oga_include_items" "name,ctu_type,county,population" + "oga_featureid" "fips_code" + END + PROJECTION "+init=epsg:26915" END + TEMPLATE VOID + END + +END diff --git a/msautotest/api/ogcapi_postgis_numeric_id.map b/msautotest/api/ogcapi_postgis_numeric_id.map new file mode 100644 index 0000000000..891299fbe1 --- /dev/null +++ b/msautotest/api/ogcapi_postgis_numeric_id.map @@ -0,0 +1,55 @@ +# REQUIRES: POSTGIS +# +# RUN_PARMS: ogcapi_postgis_numeric_id_invalid_id.json [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/test/invalid_id" "QUERY_STRING=f=json" > [RESULT_DEMIME] + +MAP + EXTENT -67.5725 42 -58.9275 48.5 + + WEB + METADATA + "oga_html_template_directory" "../../share/ogcapi/templates/html-plain/" + "oga_title" "OGC API Test" ## REQUIRED (or just recommended?) + "oga_description" "This is a test OGC API server description set via oga_description." + "oga_contactperson" "Contact person" + "oga_contacturl" "http://example.com/contact" + "oga_contactelectronicmailaddress" "email@example.com" + "oga_termsofservice" "Terms of Service" + "oga_keywords" "keyword1,keyword2" + "oga_html_tags" "debug,sample" + "oga_tag_debug" "true" + "oga_tag_sample" "sample tag" + "oga_onlineresource" "http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi" ## REQUIRED + "oga_server_description" "Server description" + "oga_links" "link1,link2" + "oga_link1_href" "https://mapserver.org" + "oga_link1_title" "MapServer project website" + "oga_link2_href" "https://ogcapi.ogc.org" + "oga_link2_title" "OCG API website" + "oga_enable_request" "OGCAPI" ## REQUIRED + "oga_max_limit" "15" + "oga_default_limit" "9" + "oga_geometry_precision" "4" + END + END + +LAYER + NAME test + INCLUDE "../wxs/postgis.include" + DATA "the_geom from (select * from province order by gid) as foo using srid=3978 using unique gid" + METADATA + "oga_title" "test" + "oga_description" "province" + "oga_srs" "EPSG:3978 EPSG:4326" # storageCrs is first in the list + "oga_featureid" "gid" + "gml_include_items" "all" + "gml_gid_type" "Integer" + END + TYPE LINE + STATUS ON + PROJECTION + "init=epsg:3978" + END + TEMPLATE VOID +END # Layer + +END diff --git a/msautotest/api/run_test.py b/msautotest/api/run_test.py new file mode 100755 index 0000000000..0933d7fde9 --- /dev/null +++ b/msautotest/api/run_test.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python +############################################################################### +# $Id$ +# +# Project: MapServer +# Purpose: Test harnass script for MapServer autotest. +# Author: Frank Warmerdam, warmerdam@pobox.com +# +############################################################################### +# Copyright (c) 2002, Frank Warmerdam +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +############################################################################### + +import os +import sys + +import pytest + +sys.path.append("../pymod") + +import mstestlib + + +@pytest.mark.parametrize( + "map,out_file,command", + mstestlib.get_pytests(os.path.dirname(os.path.abspath(__file__))), +) +def test(map, out_file, command, extra_args): + mstestlib.run_pytest(map, out_file, command, extra_args) + + +############################################################################### +# main() + +if __name__ == "__main__": + sys.exit(mstestlib.pytest_main()) diff --git a/msautotest/config/6968.conf b/msautotest/config/6968.conf new file mode 100644 index 0000000000..8ee013c469 --- /dev/null +++ b/msautotest/config/6968.conf @@ -0,0 +1,6 @@ +CONFIG + ENV + MS_MAP_PATTERN "." + MS_ERROR_URL "http://localhost/6968.html" + END +END diff --git a/msautotest/config/6968.map b/msautotest/config/6968.map new file mode 100644 index 0000000000..1c338fbeda --- /dev/null +++ b/msautotest/config/6968.map @@ -0,0 +1,6 @@ +# Test 1: malformed mapfile +# RUN_PARMS: 6968_test001.txt [MAPSERV] QUERY_STRING='map=[MAPFILE]&mode=map' > [RESULT] +# +# Test 2: mapformed mapfile, MS_ERROR_URL in config +# RUN_PARMS: 6968_test002.txt [MAPSERV] -conf 6968.conf QUERY_STRING='map=[MAPFILE]&mode=MAP' > [RESULT] +BADTOKEN diff --git a/mapscript/python/tests/cases/__init__.py b/msautotest/config/__init__.py similarity index 100% rename from mapscript/python/tests/cases/__init__.py rename to msautotest/config/__init__.py diff --git a/msautotest/config/data/ne_110m_land.fgb b/msautotest/config/data/ne_110m_land.fgb new file mode 100644 index 0000000000..d1ce7beb05 Binary files /dev/null and b/msautotest/config/data/ne_110m_land.fgb differ diff --git a/msautotest/config/data/toronto.tfw b/msautotest/config/data/toronto.tfw new file mode 100644 index 0000000000..42d22f62fa --- /dev/null +++ b/msautotest/config/data/toronto.tfw @@ -0,0 +1,6 @@ + 100.0000000000 + 0.0000000000 + 0.0000000000 + -100.0000000000 + 456850.0 + 4957100.0 diff --git a/msautotest/config/data/toronto.tif b/msautotest/config/data/toronto.tif new file mode 100644 index 0000000000..a7c9854cb3 Binary files /dev/null and b/msautotest/config/data/toronto.tif differ diff --git a/msautotest/config/data/toronto.tif.aux.xml b/msautotest/config/data/toronto.tif.aux.xml new file mode 100644 index 0000000000..e5e80e233d --- /dev/null +++ b/msautotest/config/data/toronto.tif.aux.xml @@ -0,0 +1,29 @@ + + + + 0 + 255 + 53.209428571429 + 63.012990698874 + 100 + + + + + 0 + 255 + 60.913857142857 + 64.294548820095 + 100 + + + + + 0 + 255 + 49.359857142857 + 53.788496539498 + 100 + + + diff --git a/msautotest/config/empty1.conf b/msautotest/config/empty1.conf new file mode 100644 index 0000000000..e69de29bb2 diff --git a/msautotest/config/empty2.conf b/msautotest/config/empty2.conf new file mode 100644 index 0000000000..d408dd770c --- /dev/null +++ b/msautotest/config/empty2.conf @@ -0,0 +1,2 @@ +CONFIG +END diff --git a/msautotest/config/expected/6968_test001.txt b/msautotest/config/expected/6968_test001.txt new file mode 100644 index 0000000000..e425b10ee4 --- /dev/null +++ b/msautotest/config/expected/6968_test001.txt @@ -0,0 +1,7 @@ +Content-Type: text/html + + +MapServer Message + +msLoadMap(): Unknown identifier. First token must be MAP, this doesn't look like a mapfile. + \ No newline at end of file diff --git a/msautotest/config/expected/6968_test002.txt b/msautotest/config/expected/6968_test002.txt new file mode 100644 index 0000000000..edd58a224a --- /dev/null +++ b/msautotest/config/expected/6968_test002.txt @@ -0,0 +1,5 @@ +Status: 302 Found +Uri: http://localhost/6968.html +Location: http://localhost/6968.html +Content-Type: text/html + diff --git a/msautotest/config/expected/empty1_conf.txt b/msautotest/config/expected/empty1_conf.txt new file mode 100644 index 0000000000..30f8a4d206 --- /dev/null +++ b/msautotest/config/expected/empty1_conf.txt @@ -0,0 +1,7 @@ +Content-Type: text/html + + +MapServer Message + +msLoadConfig(): Unknown identifier. First token must be CONFIG, this doesn't look like a mapserver config file. + \ No newline at end of file diff --git a/msautotest/config/expected/empty2_conf.txt b/msautotest/config/expected/empty2_conf.txt new file mode 100644 index 0000000000..58c7039c1d --- /dev/null +++ b/msautotest/config/expected/empty2_conf.txt @@ -0,0 +1,7 @@ +Content-Type: text/html + + +MapServer Message + +msCGILoadMap(): Web application error. Required configuration value MS_MAP_PATTERN not set. + \ No newline at end of file diff --git a/msautotest/config/expected/hello_world_mapfile_key.png b/msautotest/config/expected/hello_world_mapfile_key.png new file mode 100644 index 0000000000..6a9a4764af Binary files /dev/null and b/msautotest/config/expected/hello_world_mapfile_key.png differ diff --git a/msautotest/config/expected/hello_world_mapfile_url.png b/msautotest/config/expected/hello_world_mapfile_url.png new file mode 100644 index 0000000000..6a9a4764af Binary files /dev/null and b/msautotest/config/expected/hello_world_mapfile_url.png differ diff --git a/msautotest/config/expected/hello_world_mapfile_url_slash.png b/msautotest/config/expected/hello_world_mapfile_url_slash.png new file mode 100644 index 0000000000..6a9a4764af Binary files /dev/null and b/msautotest/config/expected/hello_world_mapfile_url_slash.png differ diff --git a/msautotest/config/expected/hello_world_post.png b/msautotest/config/expected/hello_world_post.png new file mode 100644 index 0000000000..6a9a4764af Binary files /dev/null and b/msautotest/config/expected/hello_world_post.png differ diff --git a/msautotest/config/expected/index.json b/msautotest/config/expected/index.json new file mode 100644 index 0000000000..0b4ba402c0 --- /dev/null +++ b/msautotest/config/expected/index.json @@ -0,0 +1 @@ +{"description":"List of Mapfiles","linkset":[{"name":"hello_world","service-desc":[{"href":"https://demo.mapserver.org/cgi-bin/msautotest?SERVICE=WMS&VERSION=1.3.0&REQUEST=GetCapabilities","title":"World WMS service","type":"text/xml"}],"title":"title"}],"title":"Index Page"} diff --git a/msautotest/config/expected/index_kitchensink.json b/msautotest/config/expected/index_kitchensink.json new file mode 100644 index 0000000000..e4d99f408f --- /dev/null +++ b/msautotest/config/expected/index_kitchensink.json @@ -0,0 +1 @@ +{"has-error":false,"key":"KITCHENSINK_MAP","layer-count":2,"linkset":[{"service-doc":[{"href":"./?template=openlayers&mode=browse&layers=all","service":"CGI","title":"OpenLayers Viewer","type":"text/html"}],"title":"Kitchensink Demo Mapfile"},{"service-desc":[{"href":"/ogcapi/?f=json","service":"OGC API","title":"OGC API Root Service","type":"application/json"}],"service-doc":[{"href":"/ogcapi/?f=html","service":"OGC API","title":"OGC API Landing Page","type":"text/html"}],"title":"MapServer Kitchensink Demo Map"},{"service-desc":[{"href":"./?version=1.0.0&request=GetCapabilities&service=WMS","service":"WMS","title":"WMS GetCapabilities URL (version 1.0.0)","type":"text/xml"},{"href":"./?version=1.1.0&request=GetCapabilities&service=WMS","service":"WMS","title":"WMS GetCapabilities URL (version 1.1.0)","type":"text/xml"},{"href":"./?version=1.1.1&request=GetCapabilities&service=WMS","service":"WMS","title":"WMS GetCapabilities URL (version 1.1.1)","type":"text/xml"},{"href":"./?version=1.3.0&request=GetCapabilities&service=WMS","service":"WMS","title":"WMS GetCapabilities URL (version 1.3.0)","type":"text/xml"}],"title":"MapServer Kitchensink Demo Map"},{"service-desc":[{"href":"./?version=1.0.0&request=GetCapabilities&service=WFS","service":"WFS","title":"WFS GetCapabilities URL (version 1.0.0)","type":"text/xml"},{"href":"./?version=1.1.0&request=GetCapabilities&service=WFS","service":"WFS","title":"WFS GetCapabilities URL (version 1.1.0)","type":"text/xml"},{"href":"./?version=2.0.0&request=GetCapabilities&service=WFS","service":"WFS","title":"WFS GetCapabilities URL (version 2.0.0)","type":"text/xml"}],"title":"MapServer Kitchensink Demo Map"},{"service-desc":[{"href":"./?version=1.0.0&request=GetCapabilities&service=WCS","service":"WCS","title":"WCS GetCapabilities URL (version 1.0.0)","type":"text/xml"},{"href":"./?version=1.1.0&request=GetCapabilities&service=WCS","service":"WCS","title":"WCS GetCapabilities URL (version 1.1.0)","type":"text/xml"},{"href":"./?version=2.0.0&request=GetCapabilities&service=WCS","service":"WCS","title":"WCS GetCapabilities URL (version 2.0.0)","type":"text/xml"},{"href":"./?version=2.0.1&request=GetCapabilities&service=WCS","service":"WCS","title":"WCS GetCapabilities URL (version 2.0.1)","type":"text/xml"}],"title":"MapServer Kitchensink Demo Map"}],"name":"Kitchensink Demo Mapfile","title":"MapServer Kitchensink Demo Map"} diff --git a/msautotest/config/expected/index_kitchensink.png b/msautotest/config/expected/index_kitchensink.png new file mode 100644 index 0000000000..bf44bbe679 Binary files /dev/null and b/msautotest/config/expected/index_kitchensink.png differ diff --git a/msautotest/config/expected/index_map.html b/msautotest/config/expected/index_map.html new file mode 100644 index 0000000000..96bcddec94 --- /dev/null +++ b/msautotest/config/expected/index_map.html @@ -0,0 +1,36 @@ + + + + MapServer Landing Page + + + +

MapServer Mapfile Landing Page

+
    +
  • Title: hello_world
  • +
  • Layer Count: 1
  • +
  • Map Name: hello_world
  • +
+

+ Below are all the services available for this Mapfile. +

+ + + + + + + + + + + + + + + + + +
#TypeServiceTitle
1CGIOpenLayers Viewerhello_world
+ + diff --git a/msautotest/config/expected/index_map_landing.json b/msautotest/config/expected/index_map_landing.json new file mode 100644 index 0000000000..03bb808d88 --- /dev/null +++ b/msautotest/config/expected/index_map_landing.json @@ -0,0 +1 @@ +{"has-error":false,"key":"INDEX","layer-count":1,"linkset":[{"service-doc":[{"href":"./?template=openlayers&mode=browse&layers=all","service":"CGI","title":"OpenLayers Viewer","type":"text/html"}],"title":"hello_world"}],"name":"hello_world","title":"hello_world"} diff --git a/msautotest/config/expected/index_map_landing_missing.txt b/msautotest/config/expected/index_map_landing_missing.txt new file mode 100644 index 0000000000..82fa5d11a4 --- /dev/null +++ b/msautotest/config/expected/index_map_landing_missing.txt @@ -0,0 +1,5 @@ + +MapServer Message + +msLoadMap(): Unable to access file. (./missing.map) + \ No newline at end of file diff --git a/msautotest/config/expected/index_map_landing_missing_html.txt b/msautotest/config/expected/index_map_landing_missing_html.txt new file mode 100644 index 0000000000..82fa5d11a4 --- /dev/null +++ b/msautotest/config/expected/index_map_landing_missing_html.txt @@ -0,0 +1,5 @@ + +MapServer Message + +msLoadMap(): Unable to access file. (./missing.map) + \ No newline at end of file diff --git a/msautotest/config/expected/index_map_landing_no_slash.json b/msautotest/config/expected/index_map_landing_no_slash.json new file mode 100644 index 0000000000..03bb808d88 --- /dev/null +++ b/msautotest/config/expected/index_map_landing_no_slash.json @@ -0,0 +1 @@ +{"has-error":false,"key":"INDEX","layer-count":1,"linkset":[{"service-doc":[{"href":"./?template=openlayers&mode=browse&layers=all","service":"CGI","title":"OpenLayers Viewer","type":"text/html"}],"title":"hello_world"}],"name":"hello_world","title":"hello_world"} diff --git a/msautotest/config/expected/index_map_mapfile_key.png b/msautotest/config/expected/index_map_mapfile_key.png new file mode 100644 index 0000000000..6a9a4764af Binary files /dev/null and b/msautotest/config/expected/index_map_mapfile_key.png differ diff --git a/msautotest/config/expected/index_map_mapfile_missing.txt b/msautotest/config/expected/index_map_mapfile_missing.txt new file mode 100644 index 0000000000..d8aa4b8ee1 --- /dev/null +++ b/msautotest/config/expected/index_map_mapfile_missing.txt @@ -0,0 +1,7 @@ +Content-Type: text/html + + +MapServer Message + +msLoadMap(): Unable to access file. (i_do_not_exist.map) + \ No newline at end of file diff --git a/msautotest/config/expected/index_map_mapfile_url.png b/msautotest/config/expected/index_map_mapfile_url.png new file mode 100644 index 0000000000..6a9a4764af Binary files /dev/null and b/msautotest/config/expected/index_map_mapfile_url.png differ diff --git a/msautotest/config/expected/index_map_mapfile_url_slash.png b/msautotest/config/expected/index_map_mapfile_url_slash.png new file mode 100644 index 0000000000..6a9a4764af Binary files /dev/null and b/msautotest/config/expected/index_map_mapfile_url_slash.png differ diff --git a/msautotest/config/expected/index_map_post.png b/msautotest/config/expected/index_map_post.png new file mode 100644 index 0000000000..6a9a4764af Binary files /dev/null and b/msautotest/config/expected/index_map_post.png differ diff --git a/msautotest/config/expected/index_ogcapi.json b/msautotest/config/expected/index_ogcapi.json new file mode 100644 index 0000000000..71c42f0b38 --- /dev/null +++ b/msautotest/config/expected/index_ogcapi.json @@ -0,0 +1 @@ +{"has-error":false,"key":"OGCAPI_MAP","layer-count":1,"linkset":[{"service-doc":[{"href":"./?template=openlayers&mode=browse&layers=all","service":"CGI","title":"OpenLayers Viewer","type":"text/html"}],"title":"OAPIF Demo Mapfile"},{"service-desc":[{"href":"/ogcapi/?f=json","service":"OGC API","title":"OGC API Root Service","type":"application/json"}],"service-doc":[{"href":"/ogcapi/?f=html","service":"OGC API","title":"OGC API Landing Page","type":"text/html"}],"title":"MapServer OGC Features API Demo Map"}],"name":"OAPIF Demo Mapfile","title":"MapServer OGC Features API Demo Map"} diff --git a/msautotest/config/expected/index_ogcapi.png b/msautotest/config/expected/index_ogcapi.png new file mode 100644 index 0000000000..bf44bbe679 Binary files /dev/null and b/msautotest/config/expected/index_ogcapi.png differ diff --git a/msautotest/config/expected/index_wcs.json b/msautotest/config/expected/index_wcs.json new file mode 100644 index 0000000000..19b6ccdbb6 --- /dev/null +++ b/msautotest/config/expected/index_wcs.json @@ -0,0 +1 @@ +{"has-error":false,"key":"WCS_MAP","layer-count":1,"linkset":[{"service-doc":[{"href":"./?template=openlayers&mode=browse&layers=all","service":"CGI","title":"OpenLayers Viewer","type":"text/html"}],"title":"WCS Demo Mapfile"},{"service-desc":[{"href":"./?version=1.0.0&request=GetCapabilities&service=WCS","service":"WCS","title":"WCS GetCapabilities URL (version 1.0.0)","type":"text/xml"},{"href":"./?version=1.1.0&request=GetCapabilities&service=WCS","service":"WCS","title":"WCS GetCapabilities URL (version 1.1.0)","type":"text/xml"},{"href":"./?version=2.0.0&request=GetCapabilities&service=WCS","service":"WCS","title":"WCS GetCapabilities URL (version 2.0.0)","type":"text/xml"},{"href":"./?version=2.0.1&request=GetCapabilities&service=WCS","service":"WCS","title":"WCS GetCapabilities URL (version 2.0.1)","type":"text/xml"}],"title":"WCS Demo Mapfile"}],"name":"WCS Demo Mapfile","title":"WCS Demo Mapfile"} diff --git a/msautotest/config/expected/index_wcs.png b/msautotest/config/expected/index_wcs.png new file mode 100644 index 0000000000..960c45dffa Binary files /dev/null and b/msautotest/config/expected/index_wcs.png differ diff --git a/msautotest/config/expected/index_wfs.json b/msautotest/config/expected/index_wfs.json new file mode 100644 index 0000000000..2f58803631 --- /dev/null +++ b/msautotest/config/expected/index_wfs.json @@ -0,0 +1 @@ +{"has-error":false,"key":"WFS_MAP","layer-count":1,"linkset":[{"service-doc":[{"href":"./?template=openlayers&mode=browse&layers=all","service":"CGI","title":"OpenLayers Viewer","type":"text/html"}],"title":"WFSMAP"},{"service-desc":[{"href":"./?version=1.0.0&request=GetCapabilities&service=WFS","service":"WFS","title":"WFS GetCapabilities URL (version 1.0.0)","type":"text/xml"},{"href":"./?version=1.1.0&request=GetCapabilities&service=WFS","service":"WFS","title":"WFS GetCapabilities URL (version 1.1.0)","type":"text/xml"},{"href":"./?version=2.0.0&request=GetCapabilities&service=WFS","service":"WFS","title":"WFS GetCapabilities URL (version 2.0.0)","type":"text/xml"}],"title":"MapServer WFS Demo Map"}],"name":"WFSMAP","title":"MapServer WFS Demo Map"} diff --git a/msautotest/config/expected/index_wfs.png b/msautotest/config/expected/index_wfs.png new file mode 100644 index 0000000000..bf44bbe679 Binary files /dev/null and b/msautotest/config/expected/index_wfs.png differ diff --git a/msautotest/config/expected/index_wms.html b/msautotest/config/expected/index_wms.html new file mode 100644 index 0000000000..321a907840 --- /dev/null +++ b/msautotest/config/expected/index_wms.html @@ -0,0 +1,60 @@ + + + + MapServer Landing Page + + + +

MapServer Mapfile Landing Page

+
    +
  • Title: MapServer WMS Demo Map
  • +
  • Layer Count: 1
  • +
  • Map Name: WMSMAP
  • +
+

+ Below are all the services available for this Mapfile. +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#TypeServiceTitle
1CGIOpenLayers ViewerWMSMAP
2WMSWMS GetCapabilities URL (version 1.0.0)MapServer WMS Demo Map
3WMSWMS GetCapabilities URL (version 1.1.0)MapServer WMS Demo Map
4WMSWMS GetCapabilities URL (version 1.1.1)MapServer WMS Demo Map
5WMSWMS GetCapabilities URL (version 1.3.0)MapServer WMS Demo Map
+ + diff --git a/msautotest/config/expected/index_wms.json b/msautotest/config/expected/index_wms.json new file mode 100644 index 0000000000..ff24339759 --- /dev/null +++ b/msautotest/config/expected/index_wms.json @@ -0,0 +1 @@ +{"has-error":false,"key":"WMS_MAP","layer-count":1,"linkset":[{"service-doc":[{"href":"./?template=openlayers&mode=browse&layers=all","service":"CGI","title":"OpenLayers Viewer","type":"text/html"}],"title":"WMSMAP"},{"service-desc":[{"href":"./?version=1.0.0&request=GetCapabilities&service=WMS","service":"WMS","title":"WMS GetCapabilities URL (version 1.0.0)","type":"text/xml"},{"href":"./?version=1.1.0&request=GetCapabilities&service=WMS","service":"WMS","title":"WMS GetCapabilities URL (version 1.1.0)","type":"text/xml"},{"href":"./?version=1.1.1&request=GetCapabilities&service=WMS","service":"WMS","title":"WMS GetCapabilities URL (version 1.1.1)","type":"text/xml"},{"href":"./?version=1.3.0&request=GetCapabilities&service=WMS","service":"WMS","title":"WMS GetCapabilities URL (version 1.3.0)","type":"text/xml"}],"title":"MapServer WMS Demo Map"}],"name":"WMSMAP","title":"MapServer WMS Demo Map"} diff --git a/msautotest/config/expected/index_wms_error.txt b/msautotest/config/expected/index_wms_error.txt new file mode 100644 index 0000000000..59d6a6aae7 --- /dev/null +++ b/msautotest/config/expected/index_wms_error.txt @@ -0,0 +1,6 @@ + + + +msWMSLoadGetMapParams(): WMS server error. Invalid layer(s) given in the LAYERS parameter. A layer might be disabled for this request. Check wms/ows_enable_request settings. + + diff --git a/msautotest/config/expected/index_wms_nocgi.json b/msautotest/config/expected/index_wms_nocgi.json new file mode 100644 index 0000000000..057e87c25f --- /dev/null +++ b/msautotest/config/expected/index_wms_nocgi.json @@ -0,0 +1 @@ +{"has-error":false,"key":"WMS_MAP_NOCGI","layer-count":1,"linkset":[{"service-desc":[{"href":"./?version=1.0.0&request=GetCapabilities&service=WMS","service":"WMS","title":"WMS GetCapabilities URL (version 1.0.0)","type":"text/xml"},{"href":"./?version=1.1.0&request=GetCapabilities&service=WMS","service":"WMS","title":"WMS GetCapabilities URL (version 1.1.0)","type":"text/xml"},{"href":"./?version=1.1.1&request=GetCapabilities&service=WMS","service":"WMS","title":"WMS GetCapabilities URL (version 1.1.1)","type":"text/xml"},{"href":"./?version=1.3.0&request=GetCapabilities&service=WMS","service":"WMS","title":"WMS GetCapabilities URL (version 1.3.0)","type":"text/xml"}],"title":"MapServer WMS Demo Map with CGI Disabled"}],"name":"WMSMAPNOCGI","title":"MapServer WMS Demo Map with CGI Disabled"} diff --git a/msautotest/config/expected/index_wms_nocgi.png b/msautotest/config/expected/index_wms_nocgi.png new file mode 100644 index 0000000000..bf44bbe679 Binary files /dev/null and b/msautotest/config/expected/index_wms_nocgi.png differ diff --git a/msautotest/config/expected/index_wms_onlineresource.json b/msautotest/config/expected/index_wms_onlineresource.json new file mode 100644 index 0000000000..4b9cc2a88a --- /dev/null +++ b/msautotest/config/expected/index_wms_onlineresource.json @@ -0,0 +1 @@ +{"has-error":false,"key":"WMS_MAP_ONLINERESOURCE","layer-count":1,"linkset":[{"service-doc":[{"href":"http://127.0.0.1/cgi-bin/mapserv.exe?map=/my/path/index_wms_onlineresource.map&template=openlayers&mode=browse&layers=all","service":"CGI","title":"OpenLayers Viewer","type":"text/html"}],"title":"WMSMAP"},{"service-desc":[{"href":"http://127.0.0.1/cgi-bin/mapserv.exe?map=/my/path/index_wms_onlineresource.map&version=1.0.0&request=GetCapabilities&service=WMS","service":"WMS","title":"WMS GetCapabilities URL (version 1.0.0)","type":"text/xml"},{"href":"http://127.0.0.1/cgi-bin/mapserv.exe?map=/my/path/index_wms_onlineresource.map&version=1.1.0&request=GetCapabilities&service=WMS","service":"WMS","title":"WMS GetCapabilities URL (version 1.1.0)","type":"text/xml"},{"href":"http://127.0.0.1/cgi-bin/mapserv.exe?map=/my/path/index_wms_onlineresource.map&version=1.1.1&request=GetCapabilities&service=WMS","service":"WMS","title":"WMS GetCapabilities URL (version 1.1.1)","type":"text/xml"},{"href":"http://127.0.0.1/cgi-bin/mapserv.exe?map=/my/path/index_wms_onlineresource.map&version=1.3.0&request=GetCapabilities&service=WMS","service":"WMS","title":"WMS GetCapabilities URL (version 1.3.0)","type":"text/xml"}],"title":"MapServer WMS Demo Map"}],"name":"WMSMAP","title":"MapServer WMS Demo Map"} diff --git a/msautotest/config/expected/index_wms_onlineresource2.json b/msautotest/config/expected/index_wms_onlineresource2.json new file mode 100644 index 0000000000..4b9cc2a88a --- /dev/null +++ b/msautotest/config/expected/index_wms_onlineresource2.json @@ -0,0 +1 @@ +{"has-error":false,"key":"WMS_MAP_ONLINERESOURCE","layer-count":1,"linkset":[{"service-doc":[{"href":"http://127.0.0.1/cgi-bin/mapserv.exe?map=/my/path/index_wms_onlineresource.map&template=openlayers&mode=browse&layers=all","service":"CGI","title":"OpenLayers Viewer","type":"text/html"}],"title":"WMSMAP"},{"service-desc":[{"href":"http://127.0.0.1/cgi-bin/mapserv.exe?map=/my/path/index_wms_onlineresource.map&version=1.0.0&request=GetCapabilities&service=WMS","service":"WMS","title":"WMS GetCapabilities URL (version 1.0.0)","type":"text/xml"},{"href":"http://127.0.0.1/cgi-bin/mapserv.exe?map=/my/path/index_wms_onlineresource.map&version=1.1.0&request=GetCapabilities&service=WMS","service":"WMS","title":"WMS GetCapabilities URL (version 1.1.0)","type":"text/xml"},{"href":"http://127.0.0.1/cgi-bin/mapserv.exe?map=/my/path/index_wms_onlineresource.map&version=1.1.1&request=GetCapabilities&service=WMS","service":"WMS","title":"WMS GetCapabilities URL (version 1.1.1)","type":"text/xml"},{"href":"http://127.0.0.1/cgi-bin/mapserv.exe?map=/my/path/index_wms_onlineresource.map&version=1.3.0&request=GetCapabilities&service=WMS","service":"WMS","title":"WMS GetCapabilities URL (version 1.3.0)","type":"text/xml"}],"title":"MapServer WMS Demo Map"}],"name":"WMSMAP","title":"MapServer WMS Demo Map"} diff --git a/msautotest/config/expected/invalid1_conf.txt b/msautotest/config/expected/invalid1_conf.txt new file mode 100644 index 0000000000..4e4990e767 --- /dev/null +++ b/msautotest/config/expected/invalid1_conf.txt @@ -0,0 +1,7 @@ +Content-Type: text/html + + +MapServer Message + +msLoadConfig(): Unknown identifier. Parsing error near (INVALID):(line 2) + \ No newline at end of file diff --git a/msautotest/config/expected/invalid2_conf.txt b/msautotest/config/expected/invalid2_conf.txt new file mode 100644 index 0000000000..9dadb8b3c7 --- /dev/null +++ b/msautotest/config/expected/invalid2_conf.txt @@ -0,0 +1,7 @@ +Content-Type: text/html + + +MapServer Message + +msLoadConfig(): Premature End-of-File. + \ No newline at end of file diff --git a/msautotest/config/expected/landing-missing-format.json b/msautotest/config/expected/landing-missing-format.json new file mode 100644 index 0000000000..3ff0f468aa --- /dev/null +++ b/msautotest/config/expected/landing-missing-format.json @@ -0,0 +1,4 @@ +Content-Type: application/json +Status: 400 + +{"code":"InvalidParameterValue","description":"Unsupported format requested."} diff --git a/msautotest/config/expected/landing.html b/msautotest/config/expected/landing.html new file mode 100644 index 0000000000..11968a5fa9 --- /dev/null +++ b/msautotest/config/expected/landing.html @@ -0,0 +1,100 @@ + + + + MapServer Landing Page + + + +

MapServer Homepage

+

+ This page lists all available Mapfiles hosted by MapServer. +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#KeyNameLayer CountHTML DocumentationJSON
1INDEXhello_world1INDEXINDEX
2KITCHENSINK_MAPMapServer Kitchensink Demo Map2KITCHENSINK_MAPKITCHENSINK_MAP
3MISSING_MAP Error loading the map0MISSING_MAPMISSING_MAP
4OGCAPI_MAPMapServer OGC Features API Demo Map1OGCAPI_MAPOGCAPI_MAP
5WCS_MAPWCS Demo Mapfile1WCS_MAPWCS_MAP
6WFS_MAPMapServer WFS Demo Map1WFS_MAPWFS_MAP
7WMS_MAPMapServer WMS Demo Map1WMS_MAPWMS_MAP
8WMS_MAP_NOCGIMapServer WMS Demo Map with CGI Disabled1WMS_MAP_NOCGIWMS_MAP_NOCGI
9WMS_MAP_ONLINERESOURCEMapServer WMS Demo Map1WMS_MAP_ONLINERESOURCEWMS_MAP_ONLINERESOURCE
+ + diff --git a/msautotest/config/expected/landing.json b/msautotest/config/expected/landing.json new file mode 100644 index 0000000000..ce8841ef2a --- /dev/null +++ b/msautotest/config/expected/landing.json @@ -0,0 +1 @@ +{"linkset":[{"has-error":false,"key":"INDEX","layer-count":1,"name":"hello_world","service-desc":[{"href":"./INDEX/?f=json","title":"INDEX","type":"application/vnd.oai.openapi+json"}],"service-doc":[{"href":"./INDEX/","title":"INDEX","type":"text/html"}],"title":"hello_world"},{"has-error":false,"key":"KITCHENSINK_MAP","layer-count":2,"name":"Kitchensink Demo Mapfile","service-desc":[{"href":"./KITCHENSINK_MAP/?f=json","title":"KITCHENSINK_MAP","type":"application/vnd.oai.openapi+json"}],"service-doc":[{"href":"./KITCHENSINK_MAP/","title":"KITCHENSINK_MAP","type":"text/html"}],"title":"MapServer Kitchensink Demo Map"},{"has-error":true,"key":"MISSING_MAP","layer-count":0,"name":"MISSING_MAP","service-desc":[{"href":"./MISSING_MAP/?f=json","title":"MISSING_MAP","type":"application/vnd.oai.openapi+json"}],"service-doc":[{"href":"./MISSING_MAP/","title":"MISSING_MAP","type":"text/html"}],"title":" Error loading the map"},{"has-error":false,"key":"OGCAPI_MAP","layer-count":1,"name":"OAPIF Demo Mapfile","service-desc":[{"href":"./OGCAPI_MAP/?f=json","title":"OGCAPI_MAP","type":"application/vnd.oai.openapi+json"}],"service-doc":[{"href":"./OGCAPI_MAP/","title":"OGCAPI_MAP","type":"text/html"}],"title":"MapServer OGC Features API Demo Map"},{"has-error":false,"key":"WCS_MAP","layer-count":1,"name":"WCS Demo Mapfile","service-desc":[{"href":"./WCS_MAP/?f=json","title":"WCS_MAP","type":"application/vnd.oai.openapi+json"}],"service-doc":[{"href":"./WCS_MAP/","title":"WCS_MAP","type":"text/html"}],"title":"WCS Demo Mapfile"},{"has-error":false,"key":"WFS_MAP","layer-count":1,"name":"WFSMAP","service-desc":[{"href":"./WFS_MAP/?f=json","title":"WFS_MAP","type":"application/vnd.oai.openapi+json"}],"service-doc":[{"href":"./WFS_MAP/","title":"WFS_MAP","type":"text/html"}],"title":"MapServer WFS Demo Map"},{"has-error":false,"key":"WMS_MAP","layer-count":1,"name":"WMSMAP","service-desc":[{"href":"./WMS_MAP/?f=json","title":"WMS_MAP","type":"application/vnd.oai.openapi+json"}],"service-doc":[{"href":"./WMS_MAP/","title":"WMS_MAP","type":"text/html"}],"title":"MapServer WMS Demo Map"},{"has-error":false,"key":"WMS_MAP_NOCGI","layer-count":1,"name":"WMSMAPNOCGI","service-desc":[{"href":"./WMS_MAP_NOCGI/?f=json","title":"WMS_MAP_NOCGI","type":"application/vnd.oai.openapi+json"}],"service-doc":[{"href":"./WMS_MAP_NOCGI/","title":"WMS_MAP_NOCGI","type":"text/html"}],"title":"MapServer WMS Demo Map with CGI Disabled"},{"has-error":false,"key":"WMS_MAP_ONLINERESOURCE","layer-count":1,"name":"WMSMAP","service-desc":[{"href":"./WMS_MAP_ONLINERESOURCE/?f=json","title":"WMS_MAP_ONLINERESOURCE","type":"application/vnd.oai.openapi+json"}],"service-doc":[{"href":"./WMS_MAP_ONLINERESOURCE/","title":"WMS_MAP_ONLINERESOURCE","type":"text/html"}],"title":"MapServer WMS Demo Map"}]} diff --git a/msautotest/config/expected/missing_conf.txt b/msautotest/config/expected/missing_conf.txt new file mode 100644 index 0000000000..6035f2ea26 --- /dev/null +++ b/msautotest/config/expected/missing_conf.txt @@ -0,0 +1,7 @@ +Content-Type: text/html + + +MapServer Message + +msLoadConfig(): Unable to access file. See mapserver.org/mapfile/config.html for more information. + \ No newline at end of file diff --git a/msautotest/config/expected/ms_index_no_path_info.txt b/msautotest/config/expected/ms_index_no_path_info.txt new file mode 100644 index 0000000000..4fd0e6db37 --- /dev/null +++ b/msautotest/config/expected/ms_index_no_path_info.txt @@ -0,0 +1,7 @@ +Content-Type: text/html + + +MapServer Message + +msCGILoadMap(): Web application error. CGI variable "map" is not set. + \ No newline at end of file diff --git a/msautotest/config/expected/ms_map_no_path1_conf.txt b/msautotest/config/expected/ms_map_no_path1_conf.txt new file mode 100644 index 0000000000..e663685aea --- /dev/null +++ b/msautotest/config/expected/ms_map_no_path1_conf.txt @@ -0,0 +1,7 @@ +Content-Type: text/html + + +MapServer Message + +msCGILoadMap(): Web application error. CGI variable "map" not found in configuration and this server is not configured for full paths. + \ No newline at end of file diff --git a/msautotest/config/expected/ms_map_no_path2_conf_failure1.txt b/msautotest/config/expected/ms_map_no_path2_conf_failure1.txt new file mode 100644 index 0000000000..e663685aea --- /dev/null +++ b/msautotest/config/expected/ms_map_no_path2_conf_failure1.txt @@ -0,0 +1,7 @@ +Content-Type: text/html + + +MapServer Message + +msCGILoadMap(): Web application error. CGI variable "map" not found in configuration and this server is not configured for full paths. + \ No newline at end of file diff --git a/msautotest/config/expected/ms_map_no_path2_conf_failure2.txt b/msautotest/config/expected/ms_map_no_path2_conf_failure2.txt new file mode 100644 index 0000000000..e663685aea --- /dev/null +++ b/msautotest/config/expected/ms_map_no_path2_conf_failure2.txt @@ -0,0 +1,7 @@ +Content-Type: text/html + + +MapServer Message + +msCGILoadMap(): Web application error. CGI variable "map" not found in configuration and this server is not configured for full paths. + \ No newline at end of file diff --git a/msautotest/config/expected/ms_map_no_path2_conf_success.png b/msautotest/config/expected/ms_map_no_path2_conf_success.png new file mode 100644 index 0000000000..6a9a4764af Binary files /dev/null and b/msautotest/config/expected/ms_map_no_path2_conf_success.png differ diff --git a/msautotest/config/expected/ms_map_pattern_conf.txt b/msautotest/config/expected/ms_map_pattern_conf.txt new file mode 100644 index 0000000000..155cbf945f --- /dev/null +++ b/msautotest/config/expected/ms_map_pattern_conf.txt @@ -0,0 +1,7 @@ +Content-Type: text/html + + +MapServer Message + +msCGILoadMap(): Web application error. CGI variable "map" fails to validate. + \ No newline at end of file diff --git a/msautotest/config/expected/ms_map_pattern_conf_bad_regex.txt b/msautotest/config/expected/ms_map_pattern_conf_bad_regex.txt new file mode 100644 index 0000000000..515a266e44 --- /dev/null +++ b/msautotest/config/expected/ms_map_pattern_conf_bad_regex.txt @@ -0,0 +1,8 @@ +Content-Type: text/html + + +MapServer Message + +msCGILoadMap(): Web application error. CGI variable "map" fails to validate. +msEvalRegex(): Regular expression error. Failed to compile expression ([A-Z*): Unmatched [, [^, [:, [., or [=. + \ No newline at end of file diff --git a/msautotest/config/expected/ms_map_pattern_conf_bad_regex.txt.alternative b/msautotest/config/expected/ms_map_pattern_conf_bad_regex.txt.alternative new file mode 100644 index 0000000000..ea1f7cc547 --- /dev/null +++ b/msautotest/config/expected/ms_map_pattern_conf_bad_regex.txt.alternative @@ -0,0 +1,8 @@ +Content-Type: text/html + + +MapServer Message + +msCGILoadMap(): Web application error. CGI variable "map" fails to validate. +msEvalRegex(): Regular expression error. Failed to compile expression ([A-Z*): unbalanced []. + \ No newline at end of file diff --git a/msautotest/config/expected/ms_no_post_conf_failure.txt b/msautotest/config/expected/ms_no_post_conf_failure.txt new file mode 100644 index 0000000000..4f378e9900 --- /dev/null +++ b/msautotest/config/expected/ms_no_post_conf_failure.txt @@ -0,0 +1,7 @@ +Content-Type: text/html + + +MapServer Message + +loadParams(): Web application error. This script should be referenced with a METHOD of GET or METHOD of POST. + \ No newline at end of file diff --git a/msautotest/config/expected/ms_no_post_conf_success.png b/msautotest/config/expected/ms_no_post_conf_success.png new file mode 100644 index 0000000000..6a9a4764af Binary files /dev/null and b/msautotest/config/expected/ms_no_post_conf_success.png differ diff --git a/msautotest/config/expected/onlineresource_index.json b/msautotest/config/expected/onlineresource_index.json new file mode 100644 index 0000000000..ee692f25ad --- /dev/null +++ b/msautotest/config/expected/onlineresource_index.json @@ -0,0 +1 @@ +{"has-error":false,"key":"ONLINERESOURCE","layer-count":1,"linkset":[{"service-doc":[{"href":"https://maps.example.com/mapserver/ONLINERESOURCE/?template=openlayers&mode=browse&layers=all","service":"CGI","title":"OpenLayers Viewer","type":"text/html"}],"title":"TEST"},{"service-desc":[{"href":"https://maps.example.com/mapserver/ONLINERESOURCE/ogcapi/?f=json","service":"OGC API","title":"OGC API Root Service","type":"application/json"}],"service-doc":[{"href":"https://maps.example.com/mapserver/ONLINERESOURCE/ogcapi/?f=html","service":"OGC API","title":"OGC API Landing Page","type":"text/html"}],"title":"Example Map"},{"service-desc":[{"href":"https://maps.example.com/mapserver/ONLINERESOURCE/?version=1.0.0&request=GetCapabilities&service=WMS","service":"WMS","title":"WMS GetCapabilities URL (version 1.0.0)","type":"text/xml"},{"href":"https://maps.example.com/mapserver/ONLINERESOURCE/?version=1.1.0&request=GetCapabilities&service=WMS","service":"WMS","title":"WMS GetCapabilities URL (version 1.1.0)","type":"text/xml"},{"href":"https://maps.example.com/mapserver/ONLINERESOURCE/?version=1.1.1&request=GetCapabilities&service=WMS","service":"WMS","title":"WMS GetCapabilities URL (version 1.1.1)","type":"text/xml"},{"href":"https://maps.example.com/mapserver/ONLINERESOURCE/?version=1.3.0&request=GetCapabilities&service=WMS","service":"WMS","title":"WMS GetCapabilities URL (version 1.3.0)","type":"text/xml"}],"title":"Example Map"},{"service-desc":[{"href":"https://maps.example.com/mapserver/ONLINERESOURCE/?version=1.0.0&request=GetCapabilities&service=WFS","service":"WFS","title":"WFS GetCapabilities URL (version 1.0.0)","type":"text/xml"},{"href":"https://maps.example.com/mapserver/ONLINERESOURCE/?version=1.1.0&request=GetCapabilities&service=WFS","service":"WFS","title":"WFS GetCapabilities URL (version 1.1.0)","type":"text/xml"},{"href":"https://maps.example.com/mapserver/ONLINERESOURCE/?version=2.0.0&request=GetCapabilities&service=WFS","service":"WFS","title":"WFS GetCapabilities URL (version 2.0.0)","type":"text/xml"}],"title":"Example Map"},{"service-desc":[{"href":"https://maps.example.com/mapserver/ONLINERESOURCE/?version=1.0.0&request=GetCapabilities&service=WCS","service":"WCS","title":"WCS GetCapabilities URL (version 1.0.0)","type":"text/xml"},{"href":"https://maps.example.com/mapserver/ONLINERESOURCE/?version=1.1.0&request=GetCapabilities&service=WCS","service":"WCS","title":"WCS GetCapabilities URL (version 1.1.0)","type":"text/xml"},{"href":"https://maps.example.com/mapserver/ONLINERESOURCE/?version=2.0.0&request=GetCapabilities&service=WCS","service":"WCS","title":"WCS GetCapabilities URL (version 2.0.0)","type":"text/xml"},{"href":"https://maps.example.com/mapserver/ONLINERESOURCE/?version=2.0.1&request=GetCapabilities&service=WCS","service":"WCS","title":"WCS GetCapabilities URL (version 2.0.1)","type":"text/xml"}],"title":"Example Map"}],"name":"TEST","title":"Example Map"} diff --git a/msautotest/config/expected/onlineresource_index_empty.json b/msautotest/config/expected/onlineresource_index_empty.json new file mode 100644 index 0000000000..97c1a57c91 --- /dev/null +++ b/msautotest/config/expected/onlineresource_index_empty.json @@ -0,0 +1 @@ +{"has-error":false,"key":"ONLINERESOURCE","layer-count":1,"linkset":[{"service-doc":[{"href":"/ONLINERESOURCE/?template=openlayers&mode=browse&layers=all","service":"CGI","title":"OpenLayers Viewer","type":"text/html"}],"title":"TEST"},{"service-desc":[{"href":"/ONLINERESOURCE/ogcapi/?f=json","service":"OGC API","title":"OGC API Root Service","type":"application/json"}],"service-doc":[{"href":"/ONLINERESOURCE/ogcapi/?f=html","service":"OGC API","title":"OGC API Landing Page","type":"text/html"}],"title":"Example Map"},{"service-desc":[{"href":"/ONLINERESOURCE/?version=1.0.0&request=GetCapabilities&service=WMS","service":"WMS","title":"WMS GetCapabilities URL (version 1.0.0)","type":"text/xml"},{"href":"/ONLINERESOURCE/?version=1.1.0&request=GetCapabilities&service=WMS","service":"WMS","title":"WMS GetCapabilities URL (version 1.1.0)","type":"text/xml"},{"href":"/ONLINERESOURCE/?version=1.1.1&request=GetCapabilities&service=WMS","service":"WMS","title":"WMS GetCapabilities URL (version 1.1.1)","type":"text/xml"},{"href":"/ONLINERESOURCE/?version=1.3.0&request=GetCapabilities&service=WMS","service":"WMS","title":"WMS GetCapabilities URL (version 1.3.0)","type":"text/xml"}],"title":"Example Map"},{"service-desc":[{"href":"/ONLINERESOURCE/?version=1.0.0&request=GetCapabilities&service=WFS","service":"WFS","title":"WFS GetCapabilities URL (version 1.0.0)","type":"text/xml"},{"href":"/ONLINERESOURCE/?version=1.1.0&request=GetCapabilities&service=WFS","service":"WFS","title":"WFS GetCapabilities URL (version 1.1.0)","type":"text/xml"},{"href":"/ONLINERESOURCE/?version=2.0.0&request=GetCapabilities&service=WFS","service":"WFS","title":"WFS GetCapabilities URL (version 2.0.0)","type":"text/xml"}],"title":"Example Map"},{"service-desc":[{"href":"/ONLINERESOURCE/?version=1.0.0&request=GetCapabilities&service=WCS","service":"WCS","title":"WCS GetCapabilities URL (version 1.0.0)","type":"text/xml"},{"href":"/ONLINERESOURCE/?version=1.1.0&request=GetCapabilities&service=WCS","service":"WCS","title":"WCS GetCapabilities URL (version 1.1.0)","type":"text/xml"},{"href":"/ONLINERESOURCE/?version=2.0.0&request=GetCapabilities&service=WCS","service":"WCS","title":"WCS GetCapabilities URL (version 2.0.0)","type":"text/xml"},{"href":"/ONLINERESOURCE/?version=2.0.1&request=GetCapabilities&service=WCS","service":"WCS","title":"WCS GetCapabilities URL (version 2.0.1)","type":"text/xml"}],"title":"Example Map"}],"name":"TEST","title":"Example Map"} diff --git a/msautotest/config/expected/onlineresource_ogcapi.json b/msautotest/config/expected/onlineresource_ogcapi.json new file mode 100644 index 0000000000..f4cf2e19ad --- /dev/null +++ b/msautotest/config/expected/onlineresource_ogcapi.json @@ -0,0 +1 @@ +{"description":"","links":[{"href":"https://maps.example.com/mapserver/onlineresource/ogcapi?f=json","rel":"self","title":"This document as JSON","type":"application/json"},{"href":"https://maps.example.com/mapserver/onlineresource/ogcapi?f=html","rel":"alternate","title":"This document as HTML","type":"text/html"},{"href":"https://maps.example.com/mapserver/onlineresource/ogcapi/conformance?f=json","rel":"conformance","title":"OCG API conformance classes implemented by this server (JSON)","type":"application/json"},{"href":"https://maps.example.com/mapserver/onlineresource/ogcapi/conformance?f=html","rel":"conformance","title":"OCG API conformance classes implemented by this server","type":"text/html"},{"href":"https://maps.example.com/mapserver/onlineresource/ogcapi/collections?f=json","rel":"data","title":"Information about feature collections available from this server (JSON)","type":"application/json"},{"href":"https://maps.example.com/mapserver/onlineresource/ogcapi/collections?f=html","rel":"data","title":"Information about feature collections available from this server","type":"text/html"},{"href":"https://maps.example.com/mapserver/onlineresource/ogcapi/api?f=json","rel":"service-desc","title":"OpenAPI document","type":"application/vnd.oai.openapi+json;version=3.0"},{"href":"https://maps.example.com/mapserver/onlineresource/ogcapi/api?f=html","rel":"service-doc","title":"API documentation","type":"text/html"}],"title":"Example Map"} diff --git a/msautotest/config/expected/onlineresource_ogcapi_collections.json b/msautotest/config/expected/onlineresource_ogcapi_collections.json new file mode 100644 index 0000000000..ca87e31eaf --- /dev/null +++ b/msautotest/config/expected/onlineresource_ogcapi_collections.json @@ -0,0 +1 @@ +{"collections":[{"crs":["http://www.opengis.net/def/crs/OGC/1.3/CRS84","http://www.opengis.net/def/crs/EPSG/0/4326"],"description":"","extent":{"spatial":{"bbox":[[-180.0,-90.000001,180.000001,83.645131]],"crs":"http://www.opengis.net/def/crs/OGC/1.3/CRS84"}},"id":"ne_110m_land","itemType":"feature","links":[{"href":"https://maps.example.com/mapserver/onlineresource/ogcapi/collections/ne_110m_land?f=json","rel":"self","title":"This collection as JSON","type":"application/json"},{"href":"https://maps.example.com/mapserver/onlineresource/ogcapi/collections/ne_110m_land?f=html","rel":"alternate","title":"This collection as HTML","type":"text/html"},{"href":"https://maps.example.com/mapserver/onlineresource/ogcapi/collections/ne_110m_land/items?f=json","rel":"items","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"https://maps.example.com/mapserver/onlineresource/ogcapi/collections/ne_110m_land/items?f=html","rel":"items","title":"Items for this collection as HTML","type":"text/html"},{"href":"https://maps.example.com/mapserver/onlineresource/ogcapi/collections/ne_110m_land/schema?f=json","rel":"http://www.opengis.net/def/rel/ogc/1.0/schema","title":"Schema for this collection as JSON schema","type":"application/schema+json"},{"href":"https://maps.example.com/mapserver/onlineresource/ogcapi/collections/ne_110m_land/schema?f=html","rel":"http://www.opengis.net/def/rel/ogc/1.0/schema","title":"Schema for this collection as HTML","type":"text/html"},{"href":"https://maps.example.com/mapserver/onlineresource/ogcapi/collections/ne_110m_land/queryables?f=json","rel":"http://www.opengis.net/def/rel/ogc/1.0/queryables","title":"Queryables for this collection as JSON schema","type":"application/schema+json"},{"href":"https://maps.example.com/mapserver/onlineresource/ogcapi/collections/ne_110m_land/queryables?f=html","rel":"http://www.opengis.net/def/rel/ogc/1.0/queryables","title":"Queryables for this collection as HTML","type":"text/html"},{"href":"https://maps.example.com/mapserver/onlineresource/ogcapi/collections/ne_110m_land/sortables?f=json","rel":"http://www.opengis.net/def/rel/ogc/1.0/sortables","title":"Sortables for this collection as JSON schema","type":"application/schema+json"},{"href":"https://maps.example.com/mapserver/onlineresource/ogcapi/collections/ne_110m_land/sortables?f=html","rel":"http://www.opengis.net/def/rel/ogc/1.0/sortables","title":"Sortables for this collection as HTML","type":"text/html"}],"title":"ne_110m_land"}],"links":[{"href":"https://maps.example.com/mapserver/onlineresource/ogcapi/collections?f=json","rel":"self","title":"This document as JSON","type":"application/json"},{"href":"https://maps.example.com/mapserver/onlineresource/ogcapi/collections?f=html","rel":"alternate","title":"This document as HTML","type":"text/html"}]} diff --git a/msautotest/config/expected/onlineresource_wfs_getcapabiltities.xml b/msautotest/config/expected/onlineresource_wfs_getcapabiltities.xml new file mode 100644 index 0000000000..87033c9a3b --- /dev/null +++ b/msautotest/config/expected/onlineresource_wfs_getcapabiltities.xml @@ -0,0 +1,361 @@ + + + + Example Map + + + + WFS + 2.0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 2.0.0 + 1.1.0 + 1.0.0 + + + + + text/xml + + + + + ServiceIdentification + ServiceProvider + OperationsMetadata + FeatureTypeList + Filter_Capabilities + + + + + + + + + + + + + application/gml+xml; version=3.2 + text/xml; subtype=gml/3.2.1 + text/xml; subtype=gml/3.1.1 + text/xml; subtype=gml/2.1.2 + + + + + + + + + + + + + application/gml+xml; version=3.2 + text/xml; subtype=gml/3.2.1 + text/xml; subtype=gml/3.1.1 + text/xml; subtype=gml/2.1.2 + + + + + + + + + + + + + application/gml+xml; version=3.2 + text/xml; subtype=gml/3.2.1 + text/xml; subtype=gml/3.1.1 + text/xml; subtype=gml/2.1.2 + + + + + + + + + + + + + + + + + + + + + + 2.0.0 + 1.1.0 + 1.0.0 + + + + + TRUE + + + + FALSE + + + + FALSE + + + + TRUE + + + + TRUE + + + + FALSE + + + + FALSE + + + + FALSE + + + + TRUE + + + + FALSE + + + + FALSE + + + + FALSE + + + + FALSE + + + + FALSE + + + + FALSE + + + + wfs:Query + wfs:StoredQuery + + + + + + ms:ne_110m_land + ne_110m_land + urn:ogc:def:crs:EPSG::4326 + + application/gml+xml; version=3.2 + text/xml; subtype=gml/3.2.1 + text/xml; subtype=gml/3.1.1 + text/xml; subtype=gml/2.1.2 + + + -180.000000 -90.000000 + 180.000000 83.645130 + + + + + + + + + TRUE + + + + TRUE + + + + FALSE + + + + TRUE + + + + TRUE + + + + TRUE + + + + TRUE + + + + FALSE + + + + TRUE + + + + FALSE + + + + FALSE + + + + TRUE + + + + FALSE + + + + TRUE + + + + FALSE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msautotest/config/expected/onlineresource_wms_getcapabiltities.xml b/msautotest/config/expected/onlineresource_wms_getcapabiltities.xml new file mode 100644 index 0000000000..6d518c4cc6 --- /dev/null +++ b/msautotest/config/expected/onlineresource_wms_getcapabiltities.xml @@ -0,0 +1,132 @@ + + + + WMS + Example Map + + + + 4096 + 4096 + + + + + + text/xml + + + + + + + + + image/png + image/jpeg + image/png; mode=8bit + image/vnd.jpeg-png + image/vnd.jpeg-png8 + application/x-pdf + image/svg+xml + image/tiff + application/vnd.google-earth.kml+xml + application/vnd.google-earth.kmz + application/vnd.mapbox-vector-tile + application/x-protobuf + application/json + + + + + + + + + text/plain + application/vnd.ogc.gml + + + + + + + + + text/xml + + + + + + + + + image/png + image/jpeg + image/png; mode=8bit + image/vnd.jpeg-png + image/vnd.jpeg-png8 + + + + + + + + + text/xml + + + + + + + + + + XML + INIMAGE + BLANK + + + + TEST + Example Map + TEST + EPSG:4326 + + -180.000000 + 180.000000 + -90.000000 + 90.000000 + + + + ne_110m_land + ne_110m_land + + -180.000000 + 180.000000 + -90.000000 + 83.645130 + + + + text/xml + + + + + + + diff --git a/msautotest/config/expected/onlineresource_wms_getcapabiltities_mapfile.xml b/msautotest/config/expected/onlineresource_wms_getcapabiltities_mapfile.xml new file mode 100644 index 0000000000..4b6f2a2670 --- /dev/null +++ b/msautotest/config/expected/onlineresource_wms_getcapabiltities_mapfile.xml @@ -0,0 +1,132 @@ + + + + WMS + Example Map + + + + 4096 + 4096 + + + + + + text/xml + + + + + + + + + image/png + image/jpeg + image/png; mode=8bit + image/vnd.jpeg-png + image/vnd.jpeg-png8 + application/x-pdf + image/svg+xml + image/tiff + application/vnd.google-earth.kml+xml + application/vnd.google-earth.kmz + application/vnd.mapbox-vector-tile + application/x-protobuf + application/json + + + + + + + + + text/plain + application/vnd.ogc.gml + + + + + + + + + text/xml + + + + + + + + + image/png + image/jpeg + image/png; mode=8bit + image/vnd.jpeg-png + image/vnd.jpeg-png8 + + + + + + + + + text/xml + + + + + + + + + + XML + INIMAGE + BLANK + + + + TEST + Example Map + TEST + EPSG:4326 + + -180.000000 + 180.000000 + -90.000000 + 90.000000 + + + + ne_110m_land + ne_110m_land + + -180.000000 + 180.000000 + -90.000000 + 83.645130 + + + + text/xml + + + + + + + diff --git a/msautotest/config/hello_world.map b/msautotest/config/hello_world.map new file mode 100644 index 0000000000..0a10dbfb8e --- /dev/null +++ b/msautotest/config/hello_world.map @@ -0,0 +1,43 @@ +# RUN_PARMS: hello_world_mapfile_key.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&mode=map" > [RESULT_DEMIME] +# RUN_PARMS: hello_world_mapfile_url.png [MAPSERV] "PATH_INFO=/[MAPFILE]" QUERY_STRING="mode=map" > [RESULT_DEMIME] +# RUN_PARMS: hello_world_mapfile_url_slash.png [MAPSERV] "PATH_INFO=/[MAPFILE]/" QUERY_STRING="mode=map" > [RESULT_DEMIME] +# RUN_PARMS: hello_world_post.png [MAPSERV] [POST]map=[MAPFILE]&mode=map[/POST] > [RESULT_DEMIME] +# RUN_PARMS: missing_conf.txt [MAPSERV] -conf missing.conf QUERY_STRING="map=[MAPFILE]&mode=map" > [RESULT_DEVERSION] +# RUN_PARMS: empty1_conf.txt [MAPSERV] -conf empty1.conf QUERY_STRING="map=[MAPFILE]&mode=map" > [RESULT_DEVERSION] +# RUN_PARMS: empty2_conf.txt [MAPSERV] -conf empty2.conf QUERY_STRING="map=[MAPFILE]&mode=map" > [RESULT_DEVERSION] +# RUN_PARMS: invalid1_conf.txt [MAPSERV] -conf invalid1.conf QUERY_STRING="map=[MAPFILE]&mode=map" > [RESULT_DEVERSION] +# RUN_PARMS: invalid2_conf.txt [MAPSERV] -conf invalid2.conf QUERY_STRING="map=[MAPFILE]&mode=map" > [RESULT_DEVERSION] +# RUN_PARMS: ms_map_no_path1_conf.txt [MAPSERV] -conf ms_map_no_path1.conf QUERY_STRING="map=[MAPFILE]&mode=map" > [RESULT_DEVERSION] +# RUN_PARMS: ms_map_no_path2_conf_success.png [MAPSERV] -conf ms_map_no_path2.conf QUERY_STRING="map=HELLO_WORLD&mode=map" > [RESULT_DEMIME] +# RUN_PARMS: ms_map_no_path2_conf_failure1.txt [MAPSERV] -conf ms_map_no_path2.conf QUERY_STRING="map=invalid&mode=map" > [RESULT_DEVERSION] +# RUN_PARMS: ms_map_no_path2_conf_failure2.txt [MAPSERV] -conf ms_map_no_path2.conf QUERY_STRING="map=[MAPFILE]&mode=map" > [RESULT_DEVERSION] +# RUN_PARMS: ms_map_pattern_conf.txt [MAPSERV] -conf ms_map_pattern.conf QUERY_STRING="map=[MAPFILE]&mode=map" > [RESULT_DEVERSION] +# RUN_PARMS: ms_map_pattern_conf_bad_regex.txt [MAPSERV] -conf ms_map_pattern_bad_regex.conf QUERY_STRING="map=[MAPFILE]&mode=map" > [RESULT_DEVERSION] +# RUN_PARMS: ms_no_post_conf_success.png [MAPSERV] -conf ms_no_post.conf QUERY_STRING="map=HELLO_WORLD&mode=map" > [RESULT_DEMIME] +# RUN_PARMS: ms_no_post_conf_failure.txt [MAPSERV] -conf ms_no_post.conf [POST]map=HELLO_WORLD&mode=map[/POST] > [RESULT_DEVERSION] + +MAP + NAME 'hello_world' + EXTENT 1 1 100 100 + SIZE 300 300 + + WEB + IMAGEPATH "/tmp/" + END + + LAYER + NAME 'hello_world' + STATUS DEFAULT + TYPE POINT + FEATURE + POINTS 50 50 END + END + CLASS + TEXT 'Hello World!' + LABEL + SIZE MEDIUM + COLOR 0 0 0 + END + END + END +END diff --git a/msautotest/config/index.conf b/msautotest/config/index.conf new file mode 100644 index 0000000000..fc0676c7b1 --- /dev/null +++ b/msautotest/config/index.conf @@ -0,0 +1,17 @@ +CONFIG + ENV + MS_MAP_PATTERN "." + MS_INDEX_TEMPLATE_DIRECTORY "../../share/ogcapi/templates/html-index-plain/" + END + MAPS + INDEX "index.map" + WMS_MAP "index_wms.map" + WMS_MAP_NOCGI "index_wms_nocgi.map" + WMS_MAP_ONLINERESOURCE "index_wms_onlineresource.map" + WFS_MAP "index_wfs.map" + WCS_MAP "index_wcs.map" + OGCAPI_MAP "index_ogcapi.map" + MISSING_MAP "missing.map" + KITCHENSINK_MAP "index_kitchensink.map" + END +END diff --git a/msautotest/config/index.map b/msautotest/config/index.map new file mode 100644 index 0000000000..595c056f4a --- /dev/null +++ b/msautotest/config/index.map @@ -0,0 +1,48 @@ +# test root URLs +# RUN_PARMS: landing.json [MAPSERV] -conf index.conf "PATH_INFO=/" "QUERY_STRING=f=json" > [RESULT_DEMIME] +# RUN_PARMS: landing.html [MAPSERV] -conf index.conf "PATH_INFO=/" "QUERY_STRING=f=html" > [RESULT_DEMIME] +# test with a missing PATH_INFO +# RUN_PARMS: ms_index_no_path_info.txt [MAPSERV] -conf index.conf "QUERY_STRING=f=json" > [RESULT_DEVERSION] + +# test with an invalid format +# RUN_PARMS: landing-missing-format.json [MAPSERV] -conf index.conf "PATH_INFO=/" "QUERY_STRING=f=missing" > [RESULT] + +# check querystrings and POST requests with Mapfiles are still processed +# RUN_PARMS: index_map_mapfile_key.png [MAPSERV] -conf index.conf QUERY_STRING="map=[MAPFILE]&mode=map" > [RESULT_DEMIME] +# RUN_PARMS: index_map_mapfile_url.png [MAPSERV] -conf index.conf "PATH_INFO=/[MAPFILE]" QUERY_STRING="mode=map" > [RESULT_DEMIME] +# RUN_PARMS: index_map_mapfile_url_slash.png [MAPSERV] -conf index.conf "PATH_INFO=/[MAPFILE]/" QUERY_STRING="mode=map" > [RESULT_DEMIME] +# RUN_PARMS: index_map_post.png [MAPSERV] -conf index.conf [POST]map=[MAPFILE]&mode=map[/POST] > [RESULT_DEMIME] +# RUN_PARMS: index_map_mapfile_missing.txt [MAPSERV] -conf index.conf QUERY_STRING="map=i_do_not_exist.map&mode=map" > [RESULT] + +# map URLs +# RUN_PARMS: index_map_landing.json [MAPSERV] -conf index.conf "PATH_INFO=/INDEX/" QUERY_STRING="f=json" > [RESULT_DEMIME] +# RUN_PARMS: index_map_landing_no_slash.json [MAPSERV] -conf index.conf "PATH_INFO=/INDEX" QUERY_STRING="f=json" > [RESULT_DEMIME] +# RUN_PARMS: index_map.html [MAPSERV] -conf index.conf "PATH_INFO=/INDEX/" QUERY_STRING="f=html" > [RESULT_DEMIME] +# RUN_PARMS: index_map_landing_missing.txt [MAPSERV] -conf index.conf "PATH_INFO=/MISSING_MAP/" QUERY_STRING="f=json" > [RESULT_DEMIME] +# RUN_PARMS: index_map_landing_missing_html.txt [MAPSERV] -conf index.conf "PATH_INFO=/MISSING_MAP/" QUERY_STRING="f=html" > [RESULT_DEMIME] + +MAP + NAME 'hello_world' + EXTENT 1 1 100 100 + SIZE 300 300 + + WEB + IMAGEPATH "/tmp/" + END + + LAYER + NAME 'hello_world' + STATUS DEFAULT + TYPE POINT + FEATURE + POINTS 50 50 END + END + CLASS + TEXT 'Hello World!' + LABEL + SIZE MEDIUM + COLOR 0 0 0 + END + END + END +END diff --git a/msautotest/config/index_kitchensink.map b/msautotest/config/index_kitchensink.map new file mode 100644 index 0000000000..130a555dbc --- /dev/null +++ b/msautotest/config/index_kitchensink.map @@ -0,0 +1,49 @@ +# RUN_PARMS: index_kitchensink.json [MAPSERV] -conf index.conf "PATH_INFO=/KITCHENSINK_MAP/" QUERY_STRING="f=json" > [RESULT_DEMIME] + +MAP + NAME "Kitchensink Demo Mapfile" + IMAGETYPE "png" + SIZE 800 800 + EXTENT -120 30 -80 70 + PROJECTION + "EPSG:4326" + END + WEB + IMAGEPATH "/tmp/" + METADATA + "ows_enable_request" "*" + "oga_enable_request" "*" + "ows_srs" "EPSG:4326" + "ows_title" "MapServer Kitchensink Demo Map" + END + END + LAYER + NAME "ne_110m_land" + STATUS OFF + CONNECTION "./data/ne_110m_land.fgb" + TYPE POLYGON + CONNECTIONTYPE OGR + TEMPLATE "ttt" + METADATA + "ows_title" "ne_110m_land" + "gml_include_items" "all" + "gml_featureid" "fid" + END + CLASS + NAME "land" + STYLE + COLOR "#556b2f" + END + END + END + + LAYER + STATUS OFF + NAME toronto + DATA "data/toronto.tif" + TYPE RASTER + PROJECTION + "init=epsg:32611" + END + END +END \ No newline at end of file diff --git a/msautotest/config/index_ogcapi.map b/msautotest/config/index_ogcapi.map new file mode 100644 index 0000000000..cb59eb2c60 --- /dev/null +++ b/msautotest/config/index_ogcapi.map @@ -0,0 +1,37 @@ +# RUN_PARMS: index_ogcapi.json [MAPSERV] -conf index.conf "PATH_INFO=/OGCAPI_MAP/" QUERY_STRING="f=json" > [RESULT_DEMIME] + +MAP + NAME "OAPIF Demo Mapfile" + SIZE 800 800 + EXTENT -180.0 -90 180 90 + PROJECTION + "EPSG:4326" + END + WEB + IMAGEPATH "/tmp/" + METADATA + "oga_title" "MapServer OGC Features API Demo Map" + "oga_enable_request" "*" #REQUIRED + END + END + + LAYER + NAME "ne_110m_land" + STATUS OFF + CONNECTION "./data/ne_110m_land.fgb" + TYPE POLYGON + CONNECTIONTYPE OGR + TEMPLATE "ttt" + METADATA + "ows_title" "ne_110m_land" + "gml_include_items" "all" + "gml_featureid" "fid" + END + CLASS + NAME "land" + STYLE + COLOR "#556b2f" + END + END + END +END \ No newline at end of file diff --git a/msautotest/config/index_wcs.map b/msautotest/config/index_wcs.map new file mode 100644 index 0000000000..9a752bdd84 --- /dev/null +++ b/msautotest/config/index_wcs.map @@ -0,0 +1,34 @@ +# RUN_PARMS: index_wcs.json [MAPSERV] -conf index.conf "PATH_INFO=/WCS_MAP/" QUERY_STRING="f=json" > [RESULT_DEMIME] + +MAP + NAME "WCS Demo Mapfile" + SIZE 1200 1200 + IMAGETYPE "png" + EXTENT -117.5459036 44.6653607 -117.3871721 44.7670830 + PROJECTION + "EPSG:4326" + END + WEB + IMAGEPATH "/tmp/" + METADATA + "wcs_srs" "EPSG:4326" + "wcs_enable_request" "*" + END + END + LAYER + STATUS OFF + NAME toronto + DATA "data/toronto.tif" + METADATA + "ows_title" "Toronto" + "wcs_label" "Toronto" + "ows_abstract" "Toronto" + "wcs_rangeset_name" "range 1" + "wcs_rangeset_label" "label" + END + TYPE RASTER + PROJECTION + "init=epsg:32611" + END + END +END \ No newline at end of file diff --git a/msautotest/config/index_wfs.map b/msautotest/config/index_wfs.map new file mode 100644 index 0000000000..0f50632904 --- /dev/null +++ b/msautotest/config/index_wfs.map @@ -0,0 +1,33 @@ +# RUN_PARMS: index_wfs.json [MAPSERV] -conf index.conf "PATH_INFO=/WFS_MAP/" QUERY_STRING="f=json" > [RESULT_DEMIME] + +MAP + NAME "WFSMAP" + SIZE 800 800 + EXTENT -180.0 -90 180 90 + PROJECTION + "EPSG:4326" + END + WEB + IMAGEPATH "/tmp/" + METADATA + "wfs_enable_request" "GetCapabilities GetMap" + "wfs_srs" "EPSG:4326" + "wfs_title" "MapServer WFS Demo Map" + END + END + + LAYER + NAME "ne_110m_land" + STATUS OFF + CONNECTION "./data/ne_110m_land.fgb" + TYPE POLYGON + CONNECTIONTYPE OGR + TEMPLATE "ttt" + CLASS + NAME "land" + STYLE + COLOR "#b5651d" + END + END + END +END \ No newline at end of file diff --git a/msautotest/config/index_wms.map b/msautotest/config/index_wms.map new file mode 100644 index 0000000000..c254be57d5 --- /dev/null +++ b/msautotest/config/index_wms.map @@ -0,0 +1,41 @@ +# RUN_PARMS: index_wms.json [MAPSERV] -conf index.conf "PATH_INFO=/WMS_MAP/" QUERY_STRING="f=json" > [RESULT_DEMIME] + +# a request with a querystring that returns empty requests errors will default to returning the index JSON +# RUN_PARMS: index_wms.json [MAPSERV] -conf index.conf "PATH_INFO=/WMS_MAP/" QUERY_STRING="param1=val1¶m2=val2&f=json" > [RESULT_DEMIME] + +# reutrn index page (in HTML) when previously Web application error. Traditional BROWSE mode requires a TEMPLATE in the WEB section, but none was provided would be returned +# RUN_PARMS: index_wms.html [MAPSERV] -conf index.conf "PATH_INFO=/WMS_MAP/" QUERY_STRING="?version=1.3.0&request=GetCapabilities&service=" > [RESULT_DEMIME] + +# any requests that throw a different error should return the error +# RUN_PARAMS: index_wms_error.txt [MAPSERV] -conf index.conf "PATH_INFO=/WMS_MAP/" QUERY_STRING="?SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMap&BBOX=-90,0,90,180&CRS=EPSG:4326&WIDTH=372&HEIGHT=372&LAYERS=missing&STYLES=&FORMAT=image/png" > [RESULT_DEMIME] + +MAP + NAME "WMSMAP" + IMAGETYPE "png" + SIZE 800 800 + EXTENT -180.0 -90 180 90 + PROJECTION + "EPSG:4326" + END + WEB + METADATA + "wms_enable_request" "GetCapabilities GetMap" + "wms_srs" "EPSG:4326" + "ows_title" "MapServer WMS Demo Map" + END + END + + LAYER + NAME "ne_110m_land" + STATUS OFF + CONNECTION "./data/ne_110m_land.fgb" + TYPE POLYGON + CONNECTIONTYPE OGR + CLASS + NAME "land" + STYLE + COLOR "#556b2f" + END + END + END +END \ No newline at end of file diff --git a/msautotest/config/index_wms_nocgi.map b/msautotest/config/index_wms_nocgi.map new file mode 100644 index 0000000000..a9d6bccfcd --- /dev/null +++ b/msautotest/config/index_wms_nocgi.map @@ -0,0 +1,33 @@ +# RUN_PARMS: index_wms_nocgi.json [MAPSERV] -conf index.conf "PATH_INFO=/WMS_MAP_NOCGI/" QUERY_STRING="f=json" > [RESULT_DEMIME] + +MAP + NAME "WMSMAPNOCGI" + IMAGETYPE "png" + SIZE 800 800 + EXTENT -180.0 -90 180 90 + PROJECTION + "EPSG:4326" + END + WEB + METADATA + "wms_enable_request" "GetCapabilities GetMap" + "wms_srs" "EPSG:4326" + "ows_title" "MapServer WMS Demo Map with CGI Disabled" + "ms_enable_modes" "!*" # disable CGI modes + END + END + + LAYER + NAME "ne_110m_land" + STATUS OFF + CONNECTION "./data/ne_110m_land.fgb" + TYPE POLYGON + CONNECTIONTYPE OGR + CLASS + NAME "land" + STYLE + COLOR "#556b2f" + END + END + END +END \ No newline at end of file diff --git a/msautotest/config/index_wms_onlineresource.map b/msautotest/config/index_wms_onlineresource.map new file mode 100644 index 0000000000..85a956075b --- /dev/null +++ b/msautotest/config/index_wms_onlineresource.map @@ -0,0 +1,36 @@ +# RUN_PARMS: index_wms_onlineresource.json [MAPSERV] -conf index.conf "PATH_INFO=/WMS_MAP_ONLINERESOURCE/" QUERY_STRING="f=json" > [RESULT_DEMIME] +# RUN_PARMS: index_wms_onlineresource2.json [MAPSERV] -conf onlineresource.conf "PATH_INFO=/WMS_MAP_ONLINERESOURCE/" QUERY_STRING="f=json" > [RESULT_DEMIME] + +MAP + NAME "WMSMAP" + IMAGETYPE "png" + SIZE 800 800 + EXTENT -180.0 -90 180 90 + PROJECTION + "EPSG:4326" + END + WEB + METADATA + "wms_enable_request" "GetCapabilities GetMap" + "wms_srs" "EPSG:4326" + "ows_title" "MapServer WMS Demo Map" + "ows_onlineresource" "http://127.0.0.1/cgi-bin/mapserv.exe?map=/my/path/index_wms_onlineresource.map&" + END + # required if using &mode=browse&template=openlayers + IMAGEPATH "/tmp/" + END + + LAYER + NAME "ne_110m_land" + STATUS OFF + CONNECTION "./data/ne_110m_land.fgb" + TYPE POLYGON + CONNECTIONTYPE OGR + CLASS + NAME "land" + STYLE + COLOR "#556b2f" + END + END + END +END \ No newline at end of file diff --git a/msautotest/config/invalid1.conf b/msautotest/config/invalid1.conf new file mode 100644 index 0000000000..5ecd22034a --- /dev/null +++ b/msautotest/config/invalid1.conf @@ -0,0 +1,4 @@ +CONFIG + INVALID + END +END diff --git a/msautotest/config/invalid2.conf b/msautotest/config/invalid2.conf new file mode 100644 index 0000000000..76a674079f --- /dev/null +++ b/msautotest/config/invalid2.conf @@ -0,0 +1,3 @@ +CONFIG + ENV +END diff --git a/msautotest/config/ms_map_no_path1.conf b/msautotest/config/ms_map_no_path1.conf new file mode 100644 index 0000000000..720035941e --- /dev/null +++ b/msautotest/config/ms_map_no_path1.conf @@ -0,0 +1,5 @@ +CONFIG + ENV + MS_MAP_NO_PATH "1" + END +END diff --git a/msautotest/config/ms_map_no_path2.conf b/msautotest/config/ms_map_no_path2.conf new file mode 100644 index 0000000000..27904d8c00 --- /dev/null +++ b/msautotest/config/ms_map_no_path2.conf @@ -0,0 +1,8 @@ +CONFIG + ENV + MS_MAP_NO_PATH "1" + END + MAPS + "HELLO_WORLD" "hello_world.map" + END +END diff --git a/msautotest/config/ms_map_pattern.conf b/msautotest/config/ms_map_pattern.conf new file mode 100644 index 0000000000..cff6373cc1 --- /dev/null +++ b/msautotest/config/ms_map_pattern.conf @@ -0,0 +1,5 @@ +CONFIG + ENV + MS_MAP_PATTERN "^/opt/mapserver" + END +END diff --git a/msautotest/config/ms_map_pattern_bad_regex.conf b/msautotest/config/ms_map_pattern_bad_regex.conf new file mode 100644 index 0000000000..acf8172162 --- /dev/null +++ b/msautotest/config/ms_map_pattern_bad_regex.conf @@ -0,0 +1,5 @@ +CONFIG + ENV + MS_MAP_PATTERN "[A-Z*" + END +END diff --git a/msautotest/config/ms_no_post.conf b/msautotest/config/ms_no_post.conf new file mode 100644 index 0000000000..0961d01654 --- /dev/null +++ b/msautotest/config/ms_no_post.conf @@ -0,0 +1,9 @@ +CONFIG + ENV + MS_NO_POST "1" + MS_MAP_NO_PATH "1" + END + MAPS + HELLO_WORLD "hello_world.map" + END +END diff --git a/msautotest/config/onlineresource.conf b/msautotest/config/onlineresource.conf new file mode 100644 index 0000000000..6f49857b4b --- /dev/null +++ b/msautotest/config/onlineresource.conf @@ -0,0 +1,13 @@ +CONFIG + ENV + MS_MAP_PATTERN "." + MS_INDEX_TEMPLATE_DIRECTORY "../../share/ogcapi/templates/html-index-plain/" + MS_ONLINERESOURCE "https://maps.example.com/mapserver/" + END + MAPS + # this map includes ows_onlineresource so MS_ONLINERESOURCE will be ignored + WMS_MAP_ONLINERESOURCE "index_wms_onlineresource.map" + # this will use MS_ONLINERESOURCE to construct all URLs + ONLINERESOURCE "onlineresource.map" + END +END diff --git a/msautotest/config/onlineresource.map b/msautotest/config/onlineresource.map new file mode 100644 index 0000000000..b68c8f2b15 --- /dev/null +++ b/msautotest/config/onlineresource.map @@ -0,0 +1,43 @@ +# RUN_PARMS: onlineresource_index.json [MAPSERV] -conf onlineresource.conf PATH_INFO="/ONLINERESOURCE/" QUERY_STRING="f=json" > [RESULT_DEMIME] +# RUN_PARMS: onlineresource_index_empty.json [MAPSERV] -conf onlineresource_empty.conf PATH_INFO="/ONLINERESOURCE/" QUERY_STRING="f=json" > [RESULT_DEMIME] +# RUN_PARMS: onlineresource_ogcapi.json [MAPSERV] -conf onlineresource.conf PATH_INFO="/onlineresource/ogcapi/" QUERY_STRING="f=json" > [RESULT_DEMIME] +# RUN_PARMS: onlineresource_ogcapi_collections.json [MAPSERV] -conf onlineresource.conf PATH_INFO="/onlineresource/ogcapi/collections/" QUERY_STRING="f=json" > [RESULT_DEMIME] +# RUN_PARMS: onlineresource_wms_getcapabiltities.xml [MAPSERV] -conf onlineresource.conf PATH_INFO="/onlineresource/" QUERY_STRING="SERVICE=WMS&VERSION=1.3.0&REQUEST=GetCapabilities" > [RESULT_DEMIME] +# RUN_PARMS: onlineresource_wfs_getcapabiltities.xml [MAPSERV] -conf onlineresource.conf PATH_INFO="/onlineresource/" QUERY_STRING="SERVICE=WFS&VERSION=2.0.0&REQUEST=GetCapabilities" > [RESULT_DEMIME] +# RUN_PARMS: onlineresource_wms_getcapabiltities_mapfile.xml [MAPSERV] -conf onlineresource.conf QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetCapabilities" > [RESULT_DEMIME] + +MAP + NAME "TEST" + SIZE 800 800 + EXTENT -180.0 -90 180 90 + PROJECTION + "EPSG:4326" + END + WEB + METADATA + "ows_title" "Example Map" + "oga_enable_request" "*" + "ows_enable_request" "*" + END + END + + LAYER + NAME "ne_110m_land" + STATUS OFF + CONNECTION "./data/ne_110m_land.fgb" + TYPE POLYGON + CONNECTIONTYPE OGR + TEMPLATE "ttt" + METADATA + "ows_title" "ne_110m_land" + "gml_include_items" "all" + "gml_featureid" "fid" + END + CLASS + NAME "land" + STYLE + COLOR "#556b2f" + END + END + END +END \ No newline at end of file diff --git a/msautotest/config/onlineresource_empty.conf b/msautotest/config/onlineresource_empty.conf new file mode 100644 index 0000000000..13bcd2f6f0 --- /dev/null +++ b/msautotest/config/onlineresource_empty.conf @@ -0,0 +1,10 @@ +CONFIG + ENV + MS_INDEX_TEMPLATE_DIRECTORY "../../share/ogcapi/templates/html-index-plain/" + # test the empty string case for onlineresource + MS_ONLINERESOURCE "" + END + MAPS + ONLINERESOURCE "onlineresource.map" + END +END diff --git a/msautotest/config/run_test.py b/msautotest/config/run_test.py new file mode 100755 index 0000000000..0933d7fde9 --- /dev/null +++ b/msautotest/config/run_test.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python +############################################################################### +# $Id$ +# +# Project: MapServer +# Purpose: Test harnass script for MapServer autotest. +# Author: Frank Warmerdam, warmerdam@pobox.com +# +############################################################################### +# Copyright (c) 2002, Frank Warmerdam +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +############################################################################### + +import os +import sys + +import pytest + +sys.path.append("../pymod") + +import mstestlib + + +@pytest.mark.parametrize( + "map,out_file,command", + mstestlib.get_pytests(os.path.dirname(os.path.abspath(__file__))), +) +def test(map, out_file, command, extra_args): + mstestlib.run_pytest(map, out_file, command, extra_args) + + +############################################################################### +# main() + +if __name__ == "__main__": + sys.exit(mstestlib.pytest_main()) diff --git a/msautotest/conftest.py b/msautotest/conftest.py index 6e926bbcd2..f1d09b8948 100644 --- a/msautotest/conftest.py +++ b/msautotest/conftest.py @@ -1,14 +1,15 @@ # coding: utf-8 import os -import pytest import sys +import pytest + # Put the pymod dir on the path, so modules can `import pmstestlib` sys.path.insert(0, os.path.join(os.path.dirname(__file__), "pymod")) # These files may be non-importable, and don't contain tests anyway. # So we skip searching them during test collection. -collect_ignore = [ 'pymod/msautotest_viewer.py' ] +collect_ignore = ["pymod/msautotest_viewer.py"] def pytest_addoption(parser): @@ -33,10 +34,8 @@ def pytest_addoption(parser): help="Run under ASAN", ) - parser.addoption( - "--renderer", - default=None - ) + parser.addoption("--renderer", default=None) + @pytest.fixture def extra_args(request): diff --git a/msautotest/create_postgis_test_data.sh b/msautotest/create_postgis_test_data.sh index bc81b7f038..8edf0a6ac7 100755 --- a/msautotest/create_postgis_test_data.sh +++ b/msautotest/create_postgis_test_data.sh @@ -99,33 +99,57 @@ alter TABLE pattern15 ADD COLUMN time timestamp without time zone; update pattern15 set time = to_timestamp(time_str,'YYYY-MM-DDZ'); " psql -U postgres -d msautotest -c " -CREATE TABLE point3d (ID SERIAL); +CREATE TABLE point3d (ID SERIAL PRIMARY KEY); SELECT AddGeometryColumn('public', 'point3d', 'the_geom', 27700, 'POINT', 3); INSERT INTO point3d (the_geom) VALUES (GeomFromEWKT('SRID=27700;POINT(1 2 3)')); " psql -U postgres -d msautotest -c " -CREATE TABLE multipoint3d (ID SERIAL); +CREATE TABLE multipoint3d (ID SERIAL PRIMARY KEY); SELECT AddGeometryColumn('public', 'multipoint3d', 'the_geom', 27700, 'MULTIPOINT', 3); INSERT INTO multipoint3d (the_geom) VALUES (GeomFromEWKT('SRID=27700;MULTIPOINT(1 2 3,4 5 6)')); " psql -U postgres -d msautotest -c " -CREATE TABLE linestring3d (ID SERIAL); +CREATE TABLE linestring3d (ID SERIAL PRIMARY KEY); SELECT AddGeometryColumn('public', 'linestring3d', 'the_geom', 27700, 'LINESTRING', 3); INSERT INTO linestring3d (the_geom) VALUES (GeomFromEWKT('SRID=27700;LINESTRING(1 2 3,4 5 6)')); " psql -U postgres -d msautotest -c " -CREATE TABLE multilinestring3d (ID SERIAL); +CREATE TABLE multilinestring3d (ID SERIAL PRIMARY KEY); SELECT AddGeometryColumn('public', 'multilinestring3d', 'the_geom', 27700, 'MULTILINESTRING', 3); INSERT INTO multilinestring3d (the_geom) VALUES (GeomFromEWKT('SRID=27700;MULTILINESTRING((1 2 3,4 5 6),(7 8 9,10 11 12))')); " psql -U postgres -d msautotest -c " -CREATE TABLE polygon3d (ID SERIAL); +CREATE TABLE polygon3d (ID SERIAL PRIMARY KEY); SELECT AddGeometryColumn('public', 'polygon3d', 'the_geom', 27700, 'POLYGON', 3); INSERT INTO polygon3d (the_geom) VALUES (GeomFromEWKT('SRID=27700;POLYGON((0 0 1,10 0 2,10 10 3,0 10 4,0 0 1))')); INSERT INTO polygon3d (the_geom) VALUES (GeomFromEWKT('SRID=27700;POLYGON((0 0 1,10 0 2,10 10 3,0 10 4,0 0 1),(1 1 2,1 9 3,9 9 4,9 1 5,1 1 2))')); " psql -U postgres -d msautotest -c " -CREATE TABLE multipolygon3d (ID SERIAL); +CREATE TABLE multipolygon3d (ID SERIAL PRIMARY KEY); SELECT AddGeometryColumn('public', 'multipolygon3d', 'the_geom', 27700, 'MULTIPOLYGON', 3); INSERT INTO multipolygon3d (the_geom) VALUES (GeomFromEWKT('SRID=27700;MULTIPOLYGON(((0 0 1,10 0 2,10 10 3,0 10 4,0 0 1),(1 1 2,1 9 3,9 9 4,9 1 5,1 1 2)),((10 10 0,10 20 1,20 20 2,20 10 3,10 10 0)))')); " + +psql -U postgres -d msautotest -c " +CREATE TABLE test_wfs_paging (ID SERIAL PRIMARY KEY); +SELECT AddGeometryColumn('public', 'test_wfs_paging', 'the_geom', 27700, 'LINESTRING', 2); +INSERT INTO test_wfs_paging (the_geom) VALUES (GeomFromEWKT('SRID=27700;LINESTRING (1 0,0 1)')); +INSERT INTO test_wfs_paging (the_geom) VALUES (GeomFromEWKT('SRID=27700;LINESTRING(0 0,10 10)')); +INSERT INTO test_wfs_paging (the_geom) VALUES (GeomFromEWKT('SRID=27700;LINESTRING(5 2,5 8)')); +" + +psql -U postgres -d msautotest -c " +CREATE TABLE text_datatypes (id SERIAL PRIMARY KEY, mychar5 CHAR(5), myvarchar5 VARCHAR(5), mytext TEXT); +SELECT AddGeometryColumn('public', 'text_datatypes', 'the_geom', 27700, 'POINT', 2); +INSERT INTO text_datatypes (the_geom, mychar5, myvarchar5, mytext) VALUES (GeomFromEWKT('SRID=27700;POINT(1 2)'), 'abc ', 'def ', 'ghi '); +" + +psql -U postgres -d msautotest -c " +CREATE TABLE autotypes (id SERIAL PRIMARY KEY, mychar CHAR(5), myvarchar VARCHAR(5), mytext TEXT, mybool BOOL, myint2 INT2, myint4 INT4, myint8 INT8, +myfloat4 FLOAT4, myfloat8 FLOAT8, mynumeric NUMERIC(4,2), mydate DATE, mytime TIME, mytimez TIMETZ, mytimestamp TIMESTAMP, mytimestampz TIMESTAMPTZ); +SELECT AddGeometryColumn('public', 'autotypes', 'the_geom', 4326, 'POINT', 2); +INSERT INTO autotypes (the_geom, mychar, myvarchar, mytext, mybool, myint2, myint4, myint8, +myfloat4, myfloat8, mynumeric, mydate, mytime, mytimez, mytimestamp, mytimestampz) +VALUES (GeomFromEWKT('SRID=4326;POINT(1 2)'), 'abc', 'def', 'ghi', True, 10, 100, 1000, +1.5, 2.5, 3.33, '2023-01-01', '00:00:00', '00:00:00', '2023-01-01 00:00:00', '2023-01-01 00:00:00'); +" diff --git a/msautotest/etc/mapserv.conf b/msautotest/etc/mapserv.conf new file mode 100644 index 0000000000..641595f1d2 --- /dev/null +++ b/msautotest/etc/mapserv.conf @@ -0,0 +1,14 @@ +CONFIG + ENV + MS_MAP_PATTERN "." + MS_CONTEXT_PATTERN "ows_context.*\.xml" + + # Workaround current issues with demo.mapserver.org with HTTP/2 + CURL_HTTP_VERSION "1.1" + + END + # following used by the mssql tests on Appveyor + PLUGINS + "mssql" "C:\projects\mapserver\build\Release\msplugin_mssql2008.dll" + END +END diff --git a/msautotest/gdal/256_overlay_res.map b/msautotest/gdal/256_overlay_res.map index 9b94455d3e..c6b09009b3 100644 --- a/msautotest/gdal/256_overlay_res.map +++ b/msautotest/gdal/256_overlay_res.map @@ -21,14 +21,7 @@ PROJECTION "datum=WGS84" END -IMAGETYPE png8_t - -OUTPUTFORMAT - NAME png8_t - DRIVER "GD/PNG" - IMAGEMODE PC256 - TRANSPARENT OFF -END +IMAGETYPE PNG8 LAYER NAME grey diff --git a/msautotest/gdal/256color_overdose.map b/msautotest/gdal/256color_overdose.map index 1e87f8e9dc..6df36d2b09 100644 --- a/msautotest/gdal/256color_overdose.map +++ b/msautotest/gdal/256color_overdose.map @@ -1,7 +1,7 @@ # # Tests layering a layer with transparency on a layer with 256 colors already. -# This is intended to address case where colors are exausted before a +# This is intended to address case where colors are exhausted before a # transparent color can be allocated. # # NOTE: without resampling. @@ -23,16 +23,7 @@ SIZE 400 300 EXTENT 0.5 0.5 399.5 299.5 IMAGECOLOR 255 255 0 -IMAGETYPE png8_t - -OUTPUTFORMAT - NAME png8_t - DRIVER "GD/PNG" - EXTENSION "png" - MIMETYPE "image/png" - IMAGEMODE PC256 - TRANSPARENT OFF -END +IMAGETYPE PNG8 LAYER NAME grey diff --git a/msautotest/gdal/256color_overdose_cmt.map b/msautotest/gdal/256color_overdose_cmt.map index 8ac426fe08..e5ef433212 100644 --- a/msautotest/gdal/256color_overdose_cmt.map +++ b/msautotest/gdal/256color_overdose_cmt.map @@ -1,7 +1,7 @@ # # Tests layering a layer with transparency on a layer with 256 colors already. -# This is intended to address case where colors are exausted before a +# This is intended to address case where colors are exhausted before a # transparent color can be allocated. # # NOTE: without resampling. @@ -19,16 +19,7 @@ SIZE 400 300 EXTENT 0.5 0.5 399.5 299.5 IMAGECOLOR 255 255 0 -IMAGETYPE png8_t - -OUTPUTFORMAT - NAME png8_t - DRIVER "GD/PNG" - EXTENSION "png" - MIMETYPE "image/png" - IMAGEMODE PC256 - TRANSPARENT OFF -END +IMAGETYPE PNG8 LAYER NAME grey diff --git a/msautotest/gdal/256color_overdose_res.map b/msautotest/gdal/256color_overdose_res.map index 76ec78fd44..8a21274d01 100644 --- a/msautotest/gdal/256color_overdose_res.map +++ b/msautotest/gdal/256color_overdose_res.map @@ -1,7 +1,7 @@ # # Tests layering a layer with transparency on a layer with 256 colors already. -# This is intended to address case where colors are exausted before a +# This is intended to address case where colors are exhausted before a # transparent color can be allocated. # # NOTE: with resampling. @@ -32,14 +32,7 @@ PROJECTION "datum=WGS84" END -IMAGETYPE png8_t - -OUTPUTFORMAT - NAME png8_t - DRIVER "GD/PNG" - IMAGEMODE PC256 - TRANSPARENT OFF -END +IMAGETYPE PNG8 LAYER NAME grey diff --git a/msautotest/gdal/bilinear_left_right.map b/msautotest/gdal/bilinear_left_right.map new file mode 100644 index 0000000000..fcb70e5219 --- /dev/null +++ b/msautotest/gdal/bilinear_left_right.map @@ -0,0 +1,37 @@ +# Test assembling two rasters and bilinear resampling +MAP + + NAME TEST + PROJECTION + "init=epsg:4326" + END + + EXTENT -3.515625 -35.15625 3.515625 35.15625 + SIZE 32 320 + IMAGETYPE png + + LAYER + NAME "east-bilinear" + TYPE RASTER + STATUS default + + PROJECTION + "init=epsg:4326" + END + PROCESSING "RESAMPLE=BILINEAR" + DATA "data/east.tif" + END + + LAYER + NAME "west-bilinear" + TYPE RASTER + STATUS default + + PROJECTION + "init=epsg:4326" + END + PROCESSING "RESAMPLE=BILINEAR" + DATA "data/west.tif" + END + +END diff --git a/msautotest/gdal/bilinear_src_transp.map b/msautotest/gdal/bilinear_src_transp.map index cda421a2b7..57f04fbdc5 100644 --- a/msautotest/gdal/bilinear_src_transp.map +++ b/msautotest/gdal/bilinear_src_transp.map @@ -6,7 +6,7 @@ MAP NAME TEST STATUS ON SIZE 400 40 -EXTENT 0.5 0.5 39.5 1.5 +EXTENT 0.5 1.5 39.5 2.5 IMAGECOLOR 0 0 0 OUTPUTFORMAT diff --git a/msautotest/gdal/class16.map b/msautotest/gdal/class16.map index 3712fb028c..50a9968f85 100644 --- a/msautotest/gdal/class16.map +++ b/msautotest/gdal/class16.map @@ -13,8 +13,8 @@ IMAGETYPE png8_t OUTPUTFORMAT NAME png8_t - DRIVER "GD/PNG" - IMAGEMODE PC256 + DRIVER "AGG/PNG8" + IMAGEMODE RGB TRANSPARENT ON END @@ -26,17 +26,23 @@ LAYER CLASS NAME "red" EXPRESSION ([pixel] < -3) - COLOR 255 0 0 + STYLE + COLOR 255 0 0 + END END CLASS NAME "green" EXPRESSION ([pixel] >= -3 and [pixel] < 3) - COLOR 0 255 0 + STYLE + COLOR 0 255 0 + END END CLASS NAME "blue" EXPRESSION ([pixel] >= 3) - COLOR 0 0 255 + STYLE + COLOR 0 0 255 + END END END diff --git a/msautotest/gdal/class16_classify_scaled.map b/msautotest/gdal/class16_classify_scaled.map index 791d933bda..2ca44c92e1 100644 --- a/msautotest/gdal/class16_classify_scaled.map +++ b/msautotest/gdal/class16_classify_scaled.map @@ -13,8 +13,8 @@ IMAGETYPE png8_t OUTPUTFORMAT NAME png8_t - DRIVER "GD/PNG" - IMAGEMODE PC256 + DRIVER "AGG/PNG8" + IMAGEMODE RGB TRANSPARENT ON END @@ -31,17 +31,23 @@ LAYER CLASS NAME "red" EXPRESSION ([pixel] < 50) - COLOR 255 0 0 + STYLE + COLOR 255 0 0 + END END CLASS NAME "green" EXPRESSION ([pixel] >=50 and [pixel] < 150) - COLOR 0 255 0 + STYLE + COLOR 0 255 0 + END END CLASS NAME "blue" EXPRESSION ([pixel] > 150) - COLOR 0 0 255 + STYLE + COLOR 0 0 255 + END END END diff --git a/msautotest/gdal/class16_intoddscale.map b/msautotest/gdal/class16_intoddscale.map index ce50f2c08c..210e71144a 100644 --- a/msautotest/gdal/class16_intoddscale.map +++ b/msautotest/gdal/class16_intoddscale.map @@ -14,8 +14,8 @@ IMAGETYPE png8_t OUTPUTFORMAT NAME png8_t - DRIVER "GD/PNG" - IMAGEMODE PC256 + DRIVER "AGG/PNG8" + IMAGEMODE RGB TRANSPARENT ON END @@ -29,17 +29,23 @@ LAYER CLASS NAME "red" EXPRESSION ([pixel] < -3) - COLOR 255 0 0 + STYLE + COLOR 255 0 0 + END END CLASS NAME "green" EXPRESSION ([pixel] >= -3 and [pixel] < 3) - COLOR 0 255 0 + STYLE + COLOR 0 255 0 + END END CLASS NAME "blue" EXPRESSION ([pixel] >= 3) - COLOR 0 0 255 + STYLE + COLOR 0 0 255 + END END END diff --git a/msautotest/gdal/class16_ndmap.map b/msautotest/gdal/class16_ndmap.map index 7d1c943c83..1d334402e6 100644 --- a/msautotest/gdal/class16_ndmap.map +++ b/msautotest/gdal/class16_ndmap.map @@ -14,8 +14,8 @@ IMAGETYPE png8_t OUTPUTFORMAT NAME png8_t - DRIVER "GD/PNG" - IMAGEMODE PC256 + DRIVER "AGG/PNG8" + IMAGEMODE RGB TRANSPARENT ON END @@ -30,17 +30,23 @@ LAYER CLASS NAME "red" EXPRESSION ([pixel] < -3) - COLOR 255 0 0 + STYLE + COLOR 255 0 0 + END END CLASS NAME "green" EXPRESSION ([pixel] >= -3 and [pixel] < 3) - COLOR 0 255 0 + STYLE + COLOR 0 255 0 + END END CLASS NAME "blue" EXPRESSION ([pixel] >= 3) - COLOR 0 0 255 + STYLE + COLOR 0 0 255 + END END END diff --git a/msautotest/gdal/class16_oddscale.map b/msautotest/gdal/class16_oddscale.map index e845b6b7e9..47c545ab6d 100644 --- a/msautotest/gdal/class16_oddscale.map +++ b/msautotest/gdal/class16_oddscale.map @@ -18,8 +18,8 @@ IMAGETYPE png8_t OUTPUTFORMAT NAME png8_t - DRIVER "GD/PNG" - IMAGEMODE PC256 + DRIVER "AGG/PNG8" + IMAGEMODE RGB TRANSPARENT ON END @@ -38,12 +38,12 @@ LAYER CLASS NAME "green" EXPRESSION ([pixel] >= -3 and [pixel] < 3) - COLOR 0 255 0 + STYLE COLOR 0 255 0 END END CLASS NAME "blue" EXPRESSION ([pixel] >= 3) - COLOR 0 0 255 + STYLE COLOR 0 0 255 END END END diff --git a/msautotest/gdal/class16_range.map b/msautotest/gdal/class16_range.map index 600d12a8d8..87fff6f912 100644 --- a/msautotest/gdal/class16_range.map +++ b/msautotest/gdal/class16_range.map @@ -13,8 +13,8 @@ IMAGETYPE png8_t OUTPUTFORMAT NAME png8_t - DRIVER "GD/PNG" - IMAGEMODE PC256 + DRIVER "AGG/PNG8" + IMAGEMODE RGB TRANSPARENT ON END @@ -26,8 +26,12 @@ LAYER PROCESSING "SCALE=-10.001,28.001" CLASS STYLE - COLORRANGE 0 0 0 255 0 0 - DATARANGE -10 28 + COLORRANGE 0 0 0 255 0 0 + DATARANGE -10 14 + END + STYLE + COLORRANGE 255 0 0 255 255 0 + DATARANGE 14 28 END END END diff --git a/msautotest/gdal/class8_range.map b/msautotest/gdal/class8_range.map index dfb375e898..aee8193da2 100644 --- a/msautotest/gdal/class8_range.map +++ b/msautotest/gdal/class8_range.map @@ -1,6 +1,6 @@ -#RUN_PARMS: class8_range.png [SHP2IMG] -m [MAPFILE] -i png8_t -o [RESULT] -l grid1 -#RUN_PARMS: double_range_rgb.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -l grid2 -#RUN_PARMS: double_range_hsl.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -l grid3 +#RUN_PARMS: class8_range.png [MAP2IMG] -m [MAPFILE] -i png8_t -o [RESULT] -l grid1 +#RUN_PARMS: double_range_rgb.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] -l grid2 +#RUN_PARMS: double_range_hsl.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] -l grid3 # # Simple test of classification methods on a floating point input. # @@ -16,8 +16,8 @@ IMAGETYPE png8_t OUTPUTFORMAT NAME png8_t - DRIVER "GD/PNG" - IMAGEMODE PC256 + DRIVER "AGG/PNG8" + IMAGEMODE RGB TRANSPARENT ON END @@ -29,7 +29,7 @@ LAYER CLASS STYLE COLORRANGE 255 0 0 0 0 255 - DATARANGE 0 255 + DATARANGE 100 255 END END END diff --git a/msautotest/gdal/classtest1.map b/msautotest/gdal/classtest1.map index 99649e09ba..6aee8734ae 100644 --- a/msautotest/gdal/classtest1.map +++ b/msautotest/gdal/classtest1.map @@ -16,8 +16,8 @@ IMAGETYPE png8_t OUTPUTFORMAT NAME png8_t - DRIVER "GD/PNG" - IMAGEMODE PC256 + DRIVER "AGG/PNG8" + IMAGEMODE RGB TRANSPARENT ON END @@ -30,17 +30,17 @@ LAYER CLASS NAME "Text" EXPRESSION ([pixel] == 0) - COLOR -255 -255 -255 + STYLE COLOR -255 -255 -255 END END CLASS NAME "TextBackground" EXPRESSION ([pixel] == 2) - COLOR 0 255 0 + STYLE COLOR 0 255 0 END END CLASS NAME "Grid" EXPRESSION ([red] == 96 and [green] == 32 and [blue] == 32) - COLOR 255 0 0 + STYLE COLOR 255 0 0 END END END diff --git a/msautotest/gdal/classtest2.map b/msautotest/gdal/classtest2.map index 6597d18a36..8d806b3ffc 100644 --- a/msautotest/gdal/classtest2.map +++ b/msautotest/gdal/classtest2.map @@ -13,9 +13,9 @@ EXTENT 0.5 0.5 399.5 299.5 IMAGECOLOR 255 255 0 OUTPUTFORMAT - NAME png8_t + NAME gdal_png DRIVER "GDAL/PNG" - IMAGEMODE PC256 + IMAGEMODE RGB END LAYER @@ -26,7 +26,7 @@ LAYER CLASS NAME "Hole" EXPRESSION ([pixel] == 111) - COLOR 255 0 0 + STYLE COLOR 255 0 0 END END END diff --git a/msautotest/gdal/connectionoptions.map b/msautotest/gdal/connectionoptions.map index d0b66700c8..87d9a395e7 100644 --- a/msautotest/gdal/connectionoptions.map +++ b/msautotest/gdal/connectionoptions.map @@ -15,7 +15,6 @@ LAYER NAME "TEST" STATUS DEFAULT TYPE RASTER - DUMP TRUE # At full resolution red_square.tif is a red square indeed # but we created an overview which is yellow. diff --git a/msautotest/gdal/data/east.tif b/msautotest/gdal/data/east.tif new file mode 100644 index 0000000000..e0bee966cb Binary files /dev/null and b/msautotest/gdal/data/east.tif differ diff --git a/msautotest/gdal/data/rgba_alpha_all_255.tif b/msautotest/gdal/data/rgba_alpha_all_255.tif new file mode 100644 index 0000000000..19af70b6d0 Binary files /dev/null and b/msautotest/gdal/data/rgba_alpha_all_255.tif differ diff --git a/msautotest/gdal/data/tile_index_paths_special_chars.cpg b/msautotest/gdal/data/tile_index_paths_special_chars.cpg new file mode 100644 index 0000000000..cd89cb9758 --- /dev/null +++ b/msautotest/gdal/data/tile_index_paths_special_chars.cpg @@ -0,0 +1 @@ +ISO-8859-1 \ No newline at end of file diff --git a/msautotest/gdal/data/tile_index_paths_special_chars.dbf b/msautotest/gdal/data/tile_index_paths_special_chars.dbf new file mode 100644 index 0000000000..3e2b1ae75d Binary files /dev/null and b/msautotest/gdal/data/tile_index_paths_special_chars.dbf differ diff --git a/msautotest/gdal/data/tile_index_paths_special_chars.prj b/msautotest/gdal/data/tile_index_paths_special_chars.prj new file mode 100644 index 0000000000..f45cbadf00 --- /dev/null +++ b/msautotest/gdal/data/tile_index_paths_special_chars.prj @@ -0,0 +1 @@ +GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]] \ No newline at end of file diff --git a/msautotest/gdal/data/tile_index_paths_special_chars.shp b/msautotest/gdal/data/tile_index_paths_special_chars.shp new file mode 100644 index 0000000000..446004ecdc Binary files /dev/null and b/msautotest/gdal/data/tile_index_paths_special_chars.shp differ diff --git a/msautotest/gdal/data/tile_index_paths_special_chars.shx b/msautotest/gdal/data/tile_index_paths_special_chars.shx new file mode 100644 index 0000000000..3812591d93 Binary files /dev/null and b/msautotest/gdal/data/tile_index_paths_special_chars.shx differ diff --git "a/msautotest/gdal/data/utm_4326_spec_char_\303\270\303\246\303\266\303\274\303\247.tif" "b/msautotest/gdal/data/utm_4326_spec_char_\303\270\303\246\303\266\303\274\303\247.tif" new file mode 100644 index 0000000000..48faeb6a1f Binary files /dev/null and "b/msautotest/gdal/data/utm_4326_spec_char_\303\270\303\246\303\266\303\274\303\247.tif" differ diff --git a/msautotest/gdal/data/west.tif b/msautotest/gdal/data/west.tif new file mode 100644 index 0000000000..3f68c90423 Binary files /dev/null and b/msautotest/gdal/data/west.tif differ diff --git a/msautotest/gdal/expected/bilinear_float.png b/msautotest/gdal/expected/bilinear_float.png index 006753dd90..8c6681c3a0 100644 Binary files a/msautotest/gdal/expected/bilinear_float.png and b/msautotest/gdal/expected/bilinear_float.png differ diff --git a/msautotest/gdal/expected/bilinear_left_right.png b/msautotest/gdal/expected/bilinear_left_right.png new file mode 100644 index 0000000000..9b092fa5d0 Binary files /dev/null and b/msautotest/gdal/expected/bilinear_left_right.png differ diff --git a/msautotest/gdal/expected/bilinear_src_transp.png b/msautotest/gdal/expected/bilinear_src_transp.png index b6b7672012..70b0eaeac3 100644 Binary files a/msautotest/gdal/expected/bilinear_src_transp.png and b/msautotest/gdal/expected/bilinear_src_transp.png differ diff --git a/msautotest/gdal/expected/bilinear_src_transp2.png b/msautotest/gdal/expected/bilinear_src_transp2.png index 25605f5f34..9e50dcd503 100644 Binary files a/msautotest/gdal/expected/bilinear_src_transp2.png and b/msautotest/gdal/expected/bilinear_src_transp2.png differ diff --git a/msautotest/gdal/expected/class16_range.png b/msautotest/gdal/expected/class16_range.png index 33e02073e9..393a1d9f40 100644 Binary files a/msautotest/gdal/expected/class16_range.png and b/msautotest/gdal/expected/class16_range.png differ diff --git a/msautotest/gdal/expected/class8_range.png b/msautotest/gdal/expected/class8_range.png index 2776adeb0f..3a15767c95 100644 Binary files a/msautotest/gdal/expected/class8_range.png and b/msautotest/gdal/expected/class8_range.png differ diff --git a/msautotest/gdal/expected/gamma_grayalpha.png b/msautotest/gdal/expected/gamma_grayalpha.png new file mode 100644 index 0000000000..18704866fa Binary files /dev/null and b/msautotest/gdal/expected/gamma_grayalpha.png differ diff --git a/msautotest/gdal/expected/gamma_pct.png b/msautotest/gdal/expected/gamma_pct.png new file mode 100644 index 0000000000..ee538f333d Binary files /dev/null and b/msautotest/gdal/expected/gamma_pct.png differ diff --git a/msautotest/gdal/expected/gamma_rgb.png b/msautotest/gdal/expected/gamma_rgb.png new file mode 100644 index 0000000000..946cf2460d Binary files /dev/null and b/msautotest/gdal/expected/gamma_rgb.png differ diff --git a/msautotest/gdal/expected/gamma_rgba.png b/msautotest/gdal/expected/gamma_rgba.png new file mode 100644 index 0000000000..d3026da68d Binary files /dev/null and b/msautotest/gdal/expected/gamma_rgba.png differ diff --git a/msautotest/gdal/expected/heatmap-getfeatureinfo.html b/msautotest/gdal/expected/heatmap-getfeatureinfo.html new file mode 100644 index 0000000000..034fcdbd96 --- /dev/null +++ b/msautotest/gdal/expected/heatmap-getfeatureinfo.html @@ -0,0 +1,3 @@ +value_0: 5 +x: 0.412722 +y: -0.412722 diff --git a/msautotest/gdal/expected/idw.png b/msautotest/gdal/expected/idw.png new file mode 100644 index 0000000000..4908d8f65f Binary files /dev/null and b/msautotest/gdal/expected/idw.png differ diff --git a/msautotest/gdal/expected/nodata_scaled.png b/msautotest/gdal/expected/nodata_scaled.png index dd855e901f..e919bdd04d 100644 Binary files a/msautotest/gdal/expected/nodata_scaled.png and b/msautotest/gdal/expected/nodata_scaled.png differ diff --git a/msautotest/gdal/expected/nonsquare.png b/msautotest/gdal/expected/nonsquare.png index 94bec3a2ca..d11c9acb21 100644 Binary files a/msautotest/gdal/expected/nonsquare.png and b/msautotest/gdal/expected/nonsquare.png differ diff --git a/msautotest/gdal/expected/processing_scale_auto_alpha_255.png b/msautotest/gdal/expected/processing_scale_auto_alpha_255.png new file mode 100644 index 0000000000..0aa15b84e6 Binary files /dev/null and b/msautotest/gdal/expected/processing_scale_auto_alpha_255.png differ diff --git a/msautotest/gdal/expected/rawmode_multiband.png b/msautotest/gdal/expected/rawmode_multiband.png index acff2bed8d..310dab159d 100644 Binary files a/msautotest/gdal/expected/rawmode_multiband.png and b/msautotest/gdal/expected/rawmode_multiband.png differ diff --git a/msautotest/gdal/expected/rawmode_nodata.png b/msautotest/gdal/expected/rawmode_nodata.png index 99ae5b8686..d932487b4a 100644 --- a/msautotest/gdal/expected/rawmode_nodata.png +++ b/msautotest/gdal/expected/rawmode_nodata.png @@ -4,33 +4,33 @@ xllcorner -6.206896551724 yllcorner -4.655172413793 cellsize 10.310344827586 NODATA_value -99 - -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -99 - -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -99 - -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -99 - -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -99 - -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -99 - -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -99 - -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -99 - 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -99 - 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -99 - 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -99 - 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 -99 - 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 -99 - 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 -99 - 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 -99 - 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 -99 - 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 -99 - 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 -99 - 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 -99 - 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 -99 - 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 -99 - 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 -99 - 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 -99 - 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 -99 - 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 -99 - 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 -99 - 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 -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 -99 -99 -99 -99 -99 -99 -99 -99 -99 - 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 -99 - 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 -99 - 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 -99 +-10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -99 +-8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -99 +-7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -99 +-6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -99 +-4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -99 +-3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -99 +-2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -99 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -99 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -99 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -99 +3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 -99 +4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 -99 +5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 -99 +7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 -99 +8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 -99 +9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 -99 +11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 -99 +12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 -99 +13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 -99 +15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 -99 +16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 -99 +17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 -99 +19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 -99 +20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 -99 +21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 -99 +23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 -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 -99 -99 -99 -99 -99 -99 -99 -99 -99 +25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 -99 +27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 -99 +28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 -99 diff --git a/msautotest/gdal/expected/rawmode_nodata_resample.png b/msautotest/gdal/expected/rawmode_nodata_resample.png index 4e8b4e741e..128b3615d8 100644 --- a/msautotest/gdal/expected/rawmode_nodata_resample.png +++ b/msautotest/gdal/expected/rawmode_nodata_resample.png @@ -3,33 +3,33 @@ nrows 30 xllcorner -6.206896551724 yllcorner -4.655172413793 cellsize 10.310344827586 - -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -9 -10 -10 -10 -10 -10 -10 -10 -9 -10 -10 -10 -10 -10 -10 -10 -10 - -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 - -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 - -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 - -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 - -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 - -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 - 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 - 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 - 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 - 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 - 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 - 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 - 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 - 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 - 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 - 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 - 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 - 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 - 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 - 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 - 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 - 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 - 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 - 23 23 23 23 23 23 23 23 23 23 23 23 22 23 23 23 23 23 23 23 23 23 23 23 23 23 23 22 23 23 23 23 23 23 23 23 23 23 23 23 - 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 - 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 - 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 - 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 +0 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -9 -10 -10 -10 -10 -10 -10 -10 -9 -10 -10 -10 -10 -10 -10 -10 0 +0 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 0 +0 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 -7 0 +0 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 0 +0 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 0 +0 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 0 +0 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 0 +0 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 0 +0 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 0 +0 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 0 +0 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 0 +0 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 0 +0 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 0 +0 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 0 +0 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 0 +0 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 0 +0 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 0 +0 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 0 +0 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 0 +0 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 0 +0 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 0 +0 23 23 23 23 23 23 23 23 23 23 23 22 23 23 23 23 23 23 23 23 23 23 23 23 23 23 22 23 23 23 23 23 23 23 23 23 23 23 0 +0 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 0 +0 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 0 +0 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 0 +0 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 0 diff --git a/msautotest/gdal/expected/rot_out.png b/msautotest/gdal/expected/rot_out.png index 52c22c1e94..fc77c5668b 100644 Binary files a/msautotest/gdal/expected/rot_out.png and b/msautotest/gdal/expected/rot_out.png differ diff --git a/msautotest/gdal/expected/tileindex_special_chars.png b/msautotest/gdal/expected/tileindex_special_chars.png new file mode 100644 index 0000000000..1f7d3c2be1 Binary files /dev/null and b/msautotest/gdal/expected/tileindex_special_chars.png differ diff --git a/msautotest/gdal/expected/tileindexmixedsrs.png b/msautotest/gdal/expected/tileindexmixedsrs.png index 2229782e01..806d92a8ff 100644 Binary files a/msautotest/gdal/expected/tileindexmixedsrs.png and b/msautotest/gdal/expected/tileindexmixedsrs.png differ diff --git a/msautotest/gdal/expected/tileindexmixedsrs2.png b/msautotest/gdal/expected/tileindexmixedsrs2.png index 2229782e01..806d92a8ff 100644 Binary files a/msautotest/gdal/expected/tileindexmixedsrs2.png and b/msautotest/gdal/expected/tileindexmixedsrs2.png differ diff --git a/msautotest/gdal/expected/tileindexmixedsrs3.png b/msautotest/gdal/expected/tileindexmixedsrs3.png index 2229782e01..806d92a8ff 100644 Binary files a/msautotest/gdal/expected/tileindexmixedsrs3.png and b/msautotest/gdal/expected/tileindexmixedsrs3.png differ diff --git a/msautotest/gdal/expected/tileindexmixedsrs4.png b/msautotest/gdal/expected/tileindexmixedsrs4.png index 2229782e01..806d92a8ff 100644 Binary files a/msautotest/gdal/expected/tileindexmixedsrs4.png and b/msautotest/gdal/expected/tileindexmixedsrs4.png differ diff --git a/msautotest/gdal/expected/wmsclient_3543.png b/msautotest/gdal/expected/wmsclient_3543.png index 407f15a590..299c3f659d 100644 Binary files a/msautotest/gdal/expected/wmsclient_3543.png and b/msautotest/gdal/expected/wmsclient_3543.png differ diff --git a/msautotest/gdal/gamma_grayalpha.map b/msautotest/gdal/gamma_grayalpha.map new file mode 100644 index 0000000000..a8a1eb52f7 --- /dev/null +++ b/msautotest/gdal/gamma_grayalpha.map @@ -0,0 +1,28 @@ +# +# Test GAMMA correction on a greyscale image with an alpha band +# +MAP + +NAME TEST +STATUS ON +SIZE 400 300 +EXTENT 0.5 0.5 399.5 299.5 +IMAGECOLOR 255 255 0 + +IMAGETYPE png24_t + +OUTPUTFORMAT + NAME png24_t + DRIVER "GDAL/PNG" + IMAGEMODE RGBA +END + +LAYER + NAME test + TYPE raster + STATUS default + DATA data/greyalpha.vrt + PROCESSING "GAMMA=0.75" +END + +END # of map file diff --git a/msautotest/gdal/gamma_pct.map b/msautotest/gdal/gamma_pct.map new file mode 100644 index 0000000000..9308d0fbd5 --- /dev/null +++ b/msautotest/gdal/gamma_pct.map @@ -0,0 +1,22 @@ +# +# Test GAMMA correction on a image with a color table +# +MAP + +NAME TEST +STATUS ON +SIZE 200 150 +EXTENT 0.5 0.5 399.5 299.5 +IMAGECOLOR 255 255 0 + +IMAGETYPE png24 + +LAYER + NAME test + TYPE raster + STATUS default + DATA data/pct22.tif + PROCESSING "GAMMA=0.75" +END + +END # of map file diff --git a/msautotest/gdal/gamma_rgb.map b/msautotest/gdal/gamma_rgb.map new file mode 100644 index 0000000000..46f8566595 --- /dev/null +++ b/msautotest/gdal/gamma_rgb.map @@ -0,0 +1,26 @@ +# +# Test GAMMA correction on a RGB dataset +# +MAP + +NAME TEST +STATUS ON +SIZE 400 300 +EXTENT 0.5 0.5 399.5 299.5 +IMAGECOLOR 255 255 0 + +IMAGETYPE png24 + +# +# Start of layer definitions +# + +LAYER + NAME test + TYPE raster + STATUS default + DATA data/rgb.tif + PROCESSING "GAMMA=0.75" +END + +END # of map file diff --git a/msautotest/gdal/gamma_rgba.map b/msautotest/gdal/gamma_rgba.map new file mode 100644 index 0000000000..eb01c6839c --- /dev/null +++ b/msautotest/gdal/gamma_rgba.map @@ -0,0 +1,33 @@ +# +# Test GAMMA correction on a RGBA dataset +# +MAP + +NAME TEST +STATUS ON +SIZE 400 300 +EXTENT 0.5 0.5 399.5 299.5 +IMAGECOLOR 255 255 0 + +IMAGETYPE png24_t + +OUTPUTFORMAT + NAME png24_t + DRIVER "GDAL/PNG" + IMAGEMODE RGBA + TRANSPARENT ON +END + +# +# Start of layer definitions +# + +LAYER + NAME test + TYPE raster + STATUS default + DATA data/rgba.tif + PROCESSING "GAMMA=0.75" +END + +END # of map file diff --git a/msautotest/gdal/gd_png_256_res.map b/msautotest/gdal/gd_png_256_res.map index a4b8acdb8f..d0c9649331 100644 --- a/msautotest/gdal/gd_png_256_res.map +++ b/msautotest/gdal/gd_png_256_res.map @@ -21,14 +21,7 @@ PROJECTION "datum=WGS84" END -IMAGETYPE png8_t - -OUTPUTFORMAT - NAME png8_t - DRIVER "GD/PNG" - IMAGEMODE PC256 - TRANSPARENT OFF -END +IMAGETYPE PNG8 # # Start of layer definitions diff --git a/msautotest/gdal/gd_png_tr_256.map b/msautotest/gdal/gd_png_tr_256.map index 4f92263b9b..35dc37aac6 100644 --- a/msautotest/gdal/gd_png_tr_256.map +++ b/msautotest/gdal/gd_png_tr_256.map @@ -8,14 +8,13 @@ STATUS ON SIZE 500 500 EXTENT 0.5 0.5 399.5 299.5 IMAGECOLOR 255 255 0 -TRANSPARENT ON IMAGETYPE png8_t OUTPUTFORMAT NAME png8_t - DRIVER "GD/PNG" - IMAGEMODE PC256 + DRIVER "AGG/PNG8" + IMAGEMODE RGB TRANSPARENT ON END diff --git a/msautotest/gdal/gd_png_tr_256_res.map b/msautotest/gdal/gd_png_tr_256_res.map index 584361914f..331f664f91 100644 --- a/msautotest/gdal/gd_png_tr_256_res.map +++ b/msautotest/gdal/gd_png_tr_256_res.map @@ -10,7 +10,6 @@ STATUS ON SIZE 500 500 EXTENT 0.5 0.5 399.5 299.5 IMAGECOLOR 255 255 0 -TRANSPARENT ON PROJECTION "proj=utm" @@ -19,9 +18,10 @@ PROJECTION END OUTPUTFORMAT - NAME png8_t + NAME gdal_png DRIVER "GDAL/PNG" - IMAGEMODE PC256 + IMAGEMODE RGB + TRANSPARENT ON END # diff --git a/msautotest/gdal/gdal_png_256_res.map b/msautotest/gdal/gdal_png_256_res.map index 2464f2f509..06bfcccd47 100644 --- a/msautotest/gdal/gdal_png_256_res.map +++ b/msautotest/gdal/gdal_png_256_res.map @@ -1,6 +1,7 @@ # # Tests non-transparent 8bit output via GDAL with resampling. +# FIXME/REMOVE_ME?: this used to be the case at the GD era, but now it is actually RGBA # # NOTE: Input is transparent, but we see through to the opaque background # set via IMAGECOLOR directive. This file also tests all-in-one projection @@ -22,13 +23,10 @@ PROJECTION "datum=WGS84" END -IMAGETYPE png8_t - OUTPUTFORMAT - NAME png8_t + NAME gdal_png DRIVER "GDAL/PNG" - IMAGEMODE PC256 - TRANSPARENT OFF + IMAGEMODE RGB END # diff --git a/msautotest/gdal/gdal_png_tr_256.map b/msautotest/gdal/gdal_png_tr_256.map index e52f127400..e5150cdb1d 100644 --- a/msautotest/gdal/gdal_png_tr_256.map +++ b/msautotest/gdal/gdal_png_tr_256.map @@ -1,6 +1,7 @@ # # Tests transparent 8bit output via GDAL without resampling. +# FIXME/REMOVE_ME?: this used to be the case at the GD era, but now it is actually RGBA # MAP @@ -10,13 +11,10 @@ SIZE 500 500 EXTENT 0.5 0.5 399.5 299.5 IMAGECOLOR 255 255 0 -IMAGETYPE png8_t - OUTPUTFORMAT - NAME png8_t + NAME gdal_png DRIVER "GDAL/PNG" - IMAGEMODE PC256 - TRANSPARENT ON + IMAGEMODE RGBA END # diff --git a/msautotest/gdal/gdal_png_tr_256_res.map b/msautotest/gdal/gdal_png_tr_256_res.map index ce51892407..0b362f660e 100644 --- a/msautotest/gdal/gdal_png_tr_256_res.map +++ b/msautotest/gdal/gdal_png_tr_256_res.map @@ -1,6 +1,7 @@ # # Tests transparent 8bit output via GDAL with resampling. +# FIXME/REMOVE_ME?: this used to be the case at the GD era, but now it is actually RGBA # # REQUIRES: SUPPORTS=PROJ # @@ -18,13 +19,10 @@ PROJECTION "datum=WGS84" END -IMAGETYPE png8_t - OUTPUTFORMAT - NAME png8_t + NAME gdal_png DRIVER "GDAL/PNG" - IMAGEMODE PC256 - TRANSPARENT ON + IMAGEMODE RGBA END # diff --git a/msautotest/gdal/grayalpha_8bit.map b/msautotest/gdal/grayalpha_8bit.map index e56ccbe0d3..3c4d3650c4 100644 --- a/msautotest/gdal/grayalpha_8bit.map +++ b/msautotest/gdal/grayalpha_8bit.map @@ -14,10 +14,9 @@ EXTENT 0.5 0.5 399.5 299.5 IMAGECOLOR 255 255 0 OUTPUTFORMAT - NAME png8 + NAME gdal_png DRIVER "GDAL/PNG" - IMAGEMODE PC256 - TRANSPARENT ON + IMAGEMODE RGBA END LAYER diff --git a/msautotest/gdal/grayalpha_plug.map b/msautotest/gdal/grayalpha_plug.map index 9a7d660a21..e5c7bf62d4 100644 --- a/msautotest/gdal/grayalpha_plug.map +++ b/msautotest/gdal/grayalpha_plug.map @@ -1,6 +1,6 @@ # # Tests overlaying a greyscale image with an alpha band on a greyscale image -# into an RGBA output via the AGG2 plugable renderer. +# into an RGBA output via the AGG2 pluggable renderer. # # REQUIRES: SUPPORTS=AGG # diff --git a/msautotest/gdal/heat.map b/msautotest/gdal/heat.map index b29280a59f..8dca7d4f37 100644 --- a/msautotest/gdal/heat.map +++ b/msautotest/gdal/heat.map @@ -3,6 +3,8 @@ #RUN_PARMS: heatmap-r20-noborder-fixednorm-rgb-expression.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&LAYERS=heatmap&BBOX=-85.719105577136,-42.859552788568,85.719105577136,42.859552788568&WIDTH=200&HEIGHT=100&VERSION=1.1.1&FORMAT=image%2Fpng&SERVICE=WMS&REQUEST=GetMap&STYLES=&EXCEPTIONS=application%2Fvnd.ogc.se_inimage&SRS=EPSG%3A4326" > [RESULT_DEMIME] #RUN_PARMS: heatmap-reproj.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&LAYERS=heatmap&BBOX=-7760000,-600000,240000,3400000&WIDTH=200&HEIGHT=100&VERSION=1.1.1&FORMAT=image%2Fpng&SERVICE=WMS&REQUEST=GetMap&STYLES=&EXCEPTIONS=application%2Fvnd.ogc.se_inimage&SRS=EPSG%3A3857" > [RESULT_DEMIME] +#RUN_PARMS: heatmap-getfeatureinfo.html [MAPSERV] QUERY_STRING="map=[MAPFILE]&LAYERS=heatmap&BBOX=-82.544323889094,-41.272161944547,82.544323889094,41.272161944547&WIDTH=200&HEIGHT=100&VERSION=1.1.1&FORMAT=image%2Fpng&SERVICE=WMS&REQUEST=GetFeatureInfo&STYLES=&EXCEPTIONS=application%2Fvnd.ogc.se_inimage&SRS=EPSG%3A4326&QUERY_LAYERS=heatmap&INFO_FORMAT=text/html&X=100&Y=50" > [RESULT_DEMIME] + #no overlap because outside of shape extents #RUN_PARMS: heatmap-no-overlap.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&LAYERS=heatmap&BBOX=200,200,201,201&WIDTH=10&HEIGHT=10&VERSION=1.1.1&FORMAT=image%2Fpng&SERVICE=WMS&REQUEST=GetMap&STYLES=&EXCEPTIONS=application%2Fvnd.ogc.se_inimage&SRS=EPSG%3A4326" > [RESULT_DEMIME] @@ -21,6 +23,7 @@ map metadata "ows_srs" "epsg:4326 epsg:3857 epsg:900913" "ows_enable_request" "*" + "wms_getfeatureinfo_formatlist" "text/html" end end @@ -68,6 +71,7 @@ map "255000000" "RGB" END END + TEMPLATE "heatmap_query.html" class style COLORRANGE "#0000ff00" "#0000ffff" diff --git a/msautotest/gdal/heatmap_query.html b/msautotest/gdal/heatmap_query.html new file mode 100644 index 0000000000..e9c7fd0718 --- /dev/null +++ b/msautotest/gdal/heatmap_query.html @@ -0,0 +1,4 @@ + +value_0: [value_0] +x: [item name="x" precision=6] +y: [item name="y" precision=6] diff --git a/msautotest/gdal/idw.map b/msautotest/gdal/idw.map new file mode 100644 index 0000000000..4d728bf6e5 --- /dev/null +++ b/msautotest/gdal/idw.map @@ -0,0 +1,77 @@ +#RUN_PARMS: idw.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&LAYERS=idw&BBOX=-79.369542201052,-39.684771100526,79.369542201052,39.684771100526&WIDTH=200&HEIGHT=100&VERSION=1.1.1&FORMAT=image%2Fpng&SERVICE=WMS&REQUEST=GetMap&STYLES=&EXCEPTIONS=application%2Fvnd.ogc.se_inimage&SRS=EPSG%3A4326" > [RESULT_DEMIME] + +map + + size 1000 500 + extent -180 -90 180 90 + name "test idw" + imagetype "png" + units dd + + web + metadata + "ows_srs" "epsg:4326 epsg:3857 epsg:900913" + "ows_enable_request" "*" + end + end + + projection + "+init=epsg:4326" + end + CONFIG "MS_ERRORFILE" "stderr" + layer + name "idw" + type raster + connectiontype idw #interpolation method + connection "points" #layer that contain data + status on + processing "RANGE_COLORSPACE=HSL" + processing "IDW_RADIUS=200" #optional param for interpolation + processing "IDW_POWER=1" #optional param for interpolation + processing "IDW_COMPUTE_BORDERS=OFF" #optional param for interpolation + offsite 0 0 0 + class + style + COLORRANGE "#00ff0000" "#00ff00ff" + DATARANGE 0 3 + end + style + COLORRANGE "#00ff00ff" "#ff0000ff" + DATARANGE 3 30 + end + end + end + + layer + name "points" + status on + type POINT + data "data/pnts.shp" + CLASS + MAXSCALEDENOM 255000000 + STYLE + SIZE [VAL] + END + END + CLASS + MAXSCALEDENOM 265000000 + STYLE + SIZE 0.1 + END + END + CLASS + MAXSCALEDENOM 275000000 + EXPRESSION ([VAL]>1) + STYLE + SIZE 1 + END + END + CLASS + MAXSCALEDENOM 275000000 + STYLE + SIZE 2 + END + END + end + +end diff --git a/msautotest/gdal/lon_wrap_180.map b/msautotest/gdal/lon_wrap_180.map index c09e6fb4b4..05ac67a211 100644 --- a/msautotest/gdal/lon_wrap_180.map +++ b/msautotest/gdal/lon_wrap_180.map @@ -1,4 +1,4 @@ -# Test behaviour with a projection with lon_wrap=180 +# Test behavior with a projection with lon_wrap=180 MAP diff --git a/msautotest/gdal/lon_wrap_180_covering_more_than_360deg.map b/msautotest/gdal/lon_wrap_180_covering_more_than_360deg.map index de04f2930b..6744c9f1c0 100644 --- a/msautotest/gdal/lon_wrap_180_covering_more_than_360deg.map +++ b/msautotest/gdal/lon_wrap_180_covering_more_than_360deg.map @@ -1,4 +1,4 @@ -# Test behaviour with a projection with lon_wrap=180 +# Test behavior with a projection with lon_wrap=180 MAP diff --git a/msautotest/gdal/lut_1_crv.map b/msautotest/gdal/lut_1_crv.map index 5a21273fc3..626a3cd12f 100644 --- a/msautotest/gdal/lut_1_crv.map +++ b/msautotest/gdal/lut_1_crv.map @@ -10,9 +10,9 @@ EXTENT 0.5 0.5 399.5 299.5 IMAGECOLOR 255 255 0 OUTPUTFORMAT - NAME png8_t + NAME gdal_png DRIVER "GDAL/PNG" - IMAGEMODE PC256 + IMAGEMODE RGB END LAYER diff --git a/msautotest/gdal/lut_float.map b/msautotest/gdal/lut_float.map index 0b70adf794..859d5d792c 100644 --- a/msautotest/gdal/lut_float.map +++ b/msautotest/gdal/lut_float.map @@ -12,9 +12,9 @@ EXTENT 0.5 0.5 399.5 299.5 IMAGECOLOR 255 255 0 OUTPUTFORMAT - NAME png8_t + NAME gdal_png DRIVER "GDAL/PNG" - IMAGEMODE PC256 + IMAGEMODE RGB END LAYER diff --git a/msautotest/gdal/mask_1.map b/msautotest/gdal/mask_1.map index 5ac4f4c990..0eba947505 100644 --- a/msautotest/gdal/mask_1.map +++ b/msautotest/gdal/mask_1.map @@ -12,7 +12,6 @@ MAP GROUP "TEST" STATUS DEFAULT TYPE RASTER - DUMP TRUE # A RGB image with a transparency mask #DATA "test3_with_1mask_1bit.tif" diff --git a/msautotest/gdal/mask_3.map b/msautotest/gdal/mask_3.map index e55707482d..d3f95bc77c 100644 --- a/msautotest/gdal/mask_3.map +++ b/msautotest/gdal/mask_3.map @@ -12,7 +12,6 @@ MAP GROUP "TEST" STATUS DEFAULT TYPE RASTER - DUMP TRUE # A RGB image with a transparency mask DATA "data/test3_with_1mask_1bit.tif" diff --git a/msautotest/gdal/nodata_8bit.map b/msautotest/gdal/nodata_8bit.map index 1bbbfaf96d..9b65485cb1 100644 --- a/msautotest/gdal/nodata_8bit.map +++ b/msautotest/gdal/nodata_8bit.map @@ -12,9 +12,9 @@ EXTENT 0.5 0.5 399.5 299.5 IMAGECOLOR 255 255 0 OUTPUTFORMAT - NAME png8_t + NAME gdal_png DRIVER "GDAL/PNG" - IMAGEMODE PC256 + IMAGEMODE RGB END LAYER diff --git a/msautotest/gdal/nodata_rgb.map b/msautotest/gdal/nodata_rgb.map index a3d0444437..5897a0b0da 100644 --- a/msautotest/gdal/nodata_rgb.map +++ b/msautotest/gdal/nodata_rgb.map @@ -1,6 +1,6 @@ # # Test rendering of an RGB image with nodata values that should give -# equivelent processing to "OFFSET 0 0 0". +# equivalent processing to "OFFSET 0 0 0". # MAP IMAGETYPE PNG24 @@ -16,7 +16,6 @@ LAYER NAME "TEST" STATUS DEFAULT TYPE RASTER - DUMP TRUE DATA "data/red_square.tif" PROJECTION "init=epsg:4326" diff --git a/msautotest/gdal/nodata_scaled.map b/msautotest/gdal/nodata_scaled.map index 96cf371a71..b87c6d008b 100644 --- a/msautotest/gdal/nodata_scaled.map +++ b/msautotest/gdal/nodata_scaled.map @@ -2,11 +2,6 @@ # # Test unclassified scaled raster with NODATA. # -# Currently (Jan/2011) the NODATA value is excluded from the auto -# scaling min/max computation, but is not shown as transparent. Eventualy -# if this is fixed, a new proper result should occur and this tests results -# will need to be updated. -# MAP @@ -16,14 +11,7 @@ SIZE 200 150 EXTENT 0.5 0.5 399.5 299.5 IMAGECOLOR 255 255 0 -IMAGETYPE png24_t - -OUTPUTFORMAT - NAME png24_t - DRIVER "GD/PNG" - IMAGEMODE PC256 - TRANSPARENT OFF -END +IMAGETYPE PNG8 LAYER NAME rgb diff --git a/msautotest/gdal/nonsquare.map b/msautotest/gdal/nonsquare.map index 2a600e023c..43319bdcc4 100644 --- a/msautotest/gdal/nonsquare.map +++ b/msautotest/gdal/nonsquare.map @@ -12,9 +12,9 @@ EXTENT 0.2 0.6 99.8 299.4 IMAGECOLOR 255 255 0 OUTPUTFORMAT - NAME png8_t + NAME gdal_png DRIVER "GDAL/PNG" - IMAGEMODE PC256 + IMAGEMODE RGB END CONFIG MS_NONSQUARE YES diff --git a/msautotest/gdal/offsite_8bitgrey.map b/msautotest/gdal/offsite_8bitgrey.map index 7ba586c652..d230b5818a 100644 --- a/msautotest/gdal/offsite_8bitgrey.map +++ b/msautotest/gdal/offsite_8bitgrey.map @@ -12,9 +12,9 @@ EXTENT 0.5 0.5 399.5 299.5 IMAGECOLOR 255 255 0 OUTPUTFORMAT - NAME png8_t + NAME gdal_png DRIVER "GDAL/PNG" - IMAGEMODE PC256 + IMAGEMODE RGB END LAYER diff --git a/msautotest/gdal/offsite_pct_rgb.map b/msautotest/gdal/offsite_pct_rgb.map index f19711f549..8f05727715 100644 --- a/msautotest/gdal/offsite_pct_rgb.map +++ b/msautotest/gdal/offsite_pct_rgb.map @@ -12,9 +12,9 @@ EXTENT 0.5 0.5 399.5 299.5 IMAGECOLOR 255 255 0 OUTPUTFORMAT - NAME png8_t + NAME gdal_png DRIVER "GDAL/PNG" - IMAGEMODE PC256 + IMAGEMODE RGB END LAYER diff --git a/msautotest/gdal/processing_scale_auto.map b/msautotest/gdal/processing_scale_auto.map index 888fd7c069..36380019fd 100644 --- a/msautotest/gdal/processing_scale_auto.map +++ b/msautotest/gdal/processing_scale_auto.map @@ -9,14 +9,7 @@ SIZE 400 300 EXTENT 0.5 0.5 399.5 299.5 IMAGECOLOR 255 255 0 -IMAGETYPE png24_t - -OUTPUTFORMAT - NAME png24_t - DRIVER "GD/PNG" - IMAGEMODE PC256 - TRANSPARENT OFF -END +IMAGETYPE PNG8 LAYER NAME rgb diff --git a/msautotest/gdal/processing_scale_auto_alpha_255.map b/msautotest/gdal/processing_scale_auto_alpha_255.map new file mode 100644 index 0000000000..8cebd899f6 --- /dev/null +++ b/msautotest/gdal/processing_scale_auto_alpha_255.map @@ -0,0 +1,37 @@ +# +# REQUIRES: SUPPORTS=PROJ +# +MAP + +NAME TEST +STATUS ON +SIZE 50 50 +EXTENT 440720.000 3748320.000 443720.000 3751320.000 +IMAGECOLOR 0 0 0 + +PROJECTION + "+init=epsg:26711" +END + +IMAGETYPE png24_t + +OUTPUTFORMAT + NAME png24_t + DRIVER "GDAL/PNG" + IMAGEMODE RGBA + TRANSPARENT ON +END + +LAYER + NAME test + TYPE raster + STATUS default + DATA "data/rgba_alpha_all_255.tif" + EXTENT 440720.000 3748320.000 443720.000 3751320.000 + PROJECTION + "+init=epsg:26711" + END + PROCESSING "SCALE=AUTO" +END + +END # of map file diff --git a/msautotest/gdal/reproj.map b/msautotest/gdal/reproj.map index e37828a35d..fb25c9d71b 100644 --- a/msautotest/gdal/reproj.map +++ b/msautotest/gdal/reproj.map @@ -21,14 +21,7 @@ PROJECTION "datum=WGS84" END -IMAGETYPE png8_t - -OUTPUTFORMAT - NAME png8_t - DRIVER "GD/PNG" - IMAGEMODE PC256 - TRANSPARENT OFF -END +IMAGETYPE PNG8 LAYER NAME grey diff --git a/msautotest/gdal/rgb_overlay_plug.map b/msautotest/gdal/rgb_overlay_plug.map index beda048ce4..a0bab64b5f 100644 --- a/msautotest/gdal/rgb_overlay_plug.map +++ b/msautotest/gdal/rgb_overlay_plug.map @@ -1,6 +1,6 @@ # # Tests overlaying an RGB image with a transparent value on a greyscale image -# into an RGB output via the AGG/plugable rendering mechanism. +# into an RGB output via the AGG/pluggable rendering mechanism. # # NOTE: without resampling. # diff --git a/msautotest/gdal/rgb_overlay_res_to8bit.map b/msautotest/gdal/rgb_overlay_res_to8bit.map index 659698b548..bbb3a90d27 100644 --- a/msautotest/gdal/rgb_overlay_res_to8bit.map +++ b/msautotest/gdal/rgb_overlay_res_to8bit.map @@ -22,14 +22,7 @@ PROJECTION "datum=WGS84" END -IMAGETYPE png8_local - -OUTPUTFORMAT - NAME png8_local - DRIVER "GD/PNG" - IMAGEMODE PC256 - TRANSPARENT OFF -END +IMAGETYPE PNG8 LAYER NAME grey diff --git a/msautotest/gdal/rgb_overlay_res_to8bit_dithered.map b/msautotest/gdal/rgb_overlay_res_to8bit_dithered.map index 8c1299dfb2..ed4c429d96 100644 --- a/msautotest/gdal/rgb_overlay_res_to8bit_dithered.map +++ b/msautotest/gdal/rgb_overlay_res_to8bit_dithered.map @@ -20,14 +20,7 @@ PROJECTION "datum=WGS84" END -IMAGETYPE png8_t - -OUTPUTFORMAT - NAME png8_t - DRIVER "GD/PNG" - IMAGEMODE PC256 - TRANSPARENT OFF -END +IMAGETYPE PNG8 LAYER NAME grey diff --git a/msautotest/gdal/run_test.py b/msautotest/gdal/run_test.py index ee65170a60..0933d7fde9 100755 --- a/msautotest/gdal/run_test.py +++ b/msautotest/gdal/run_test.py @@ -8,17 +8,17 @@ # ############################################################################### # Copyright (c) 2002, Frank Warmerdam -# +# # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: -# +# # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. -# +# # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL @@ -29,14 +29,19 @@ ############################################################################### import os -import pytest import sys -sys.path.append( '../pymod' ) +import pytest + +sys.path.append("../pymod") import mstestlib -@pytest.mark.parametrize('map,out_file,command', mstestlib.get_pytests(os.path.dirname(os.path.abspath(__file__)))) + +@pytest.mark.parametrize( + "map,out_file,command", + mstestlib.get_pytests(os.path.dirname(os.path.abspath(__file__))), +) def test(map, out_file, command, extra_args): mstestlib.run_pytest(map, out_file, command, extra_args) @@ -44,5 +49,5 @@ def test(map, out_file, command, extra_args): ############################################################################### # main() -if __name__ == '__main__': +if __name__ == "__main__": sys.exit(mstestlib.pytest_main()) diff --git a/msautotest/gdal/tileindex.map b/msautotest/gdal/tileindex.map index 979d65b7bd..0da97543ad 100644 --- a/msautotest/gdal/tileindex.map +++ b/msautotest/gdal/tileindex.map @@ -15,22 +15,12 @@ PROJECTION "+proj=latlong +datum=WGS84" END -IMAGETYPE png8_t - -OUTPUTFORMAT - NAME png8_t - DRIVER "GD/PNG" - EXTENSION "png" - MIMETYPE "image/png" - IMAGEMODE PC256 - TRANSPARENT OFF -END +IMAGETYPE PNG8 LAYER NAME grey TYPE raster STATUS default - DUMP TRUE TEMPLATE "fake.html" TILEINDEX "data/tile_index.shp" TILEITEM "location" diff --git a/msautotest/gdal/tileindex_mi.map b/msautotest/gdal/tileindex_mi.map index 07c77638a4..b9a2ef7476 100644 --- a/msautotest/gdal/tileindex_mi.map +++ b/msautotest/gdal/tileindex_mi.map @@ -16,22 +16,12 @@ PROJECTION "+proj=latlong +datum=WGS84" END -IMAGETYPE png8_t - -OUTPUTFORMAT - NAME png8_t - DRIVER "GD/PNG" - EXTENSION "png" - MIMETYPE "image/png" - IMAGEMODE PC256 - TRANSPARENT OFF -END +IMAGETYPE PNG8 LAYER NAME grey TYPE raster STATUS default - DUMP TRUE TEMPLATE "fake.html" TILEINDEX tindex TILEITEM "location" diff --git a/msautotest/gdal/tileindex_special_characters.map b/msautotest/gdal/tileindex_special_characters.map new file mode 100644 index 0000000000..f40f97707a --- /dev/null +++ b/msautotest/gdal/tileindex_special_characters.map @@ -0,0 +1,35 @@ +# +# REQUIRES: INPUT=SHAPE OUTPUT=PNG +# +# RUN_PARMS: tileindex_special_chars.png [MAP2IMG] -m [MAPFILE] -l special_character_path -o [RESULT] +# +# Test tileindex with special characters in location value + +MAP + +NAME TEST +STATUS ON +SIZE 100 100 +EXTENT -117.6409662 33.8479548 -117.6080786 33.8754608 +IMAGECOLOR 0 0 0 + +PROJECTION + "+init=epsg:4326" +END + +IMAGETYPE png + +LAYER + NAME special_character_path + TYPE raster + STATUS default + TEMPLATE "fake.html" + TILEINDEX "./data/tile_index_paths_special_chars.shp" + TILEITEM "location" + TILESRS "src_srs" + PROJECTION + "+proj=latlong +datum=WGS84" + END +END + +END # of map file diff --git a/msautotest/gdal/tileindexmixedsrs.map b/msautotest/gdal/tileindexmixedsrs.map index de2770a814..53a8d00c08 100644 --- a/msautotest/gdal/tileindexmixedsrs.map +++ b/msautotest/gdal/tileindexmixedsrs.map @@ -32,7 +32,6 @@ LAYER NAME grey TYPE raster STATUS default - DUMP TRUE TEMPLATE "fake.html" TILEINDEX "data/tile_index_mixed_srs.shp" TILEITEM "location" diff --git a/msautotest/gdal/tileindexmixedsrs2.map b/msautotest/gdal/tileindexmixedsrs2.map index 90bbbbd072..fe9eb68220 100644 --- a/msautotest/gdal/tileindexmixedsrs2.map +++ b/msautotest/gdal/tileindexmixedsrs2.map @@ -20,7 +20,6 @@ LAYER NAME grey TYPE raster STATUS default - DUMP TRUE TEMPLATE "fake.html" TILEINDEX "data/tile_index_mixed_srs.shp" TILEITEM "location" diff --git a/msautotest/gdal/tileindexmixedsrs3.map b/msautotest/gdal/tileindexmixedsrs3.map index 4f2c10f479..32ce604a2e 100644 --- a/msautotest/gdal/tileindexmixedsrs3.map +++ b/msautotest/gdal/tileindexmixedsrs3.map @@ -20,7 +20,6 @@ LAYER NAME mytileindex TYPE POLYGON STATUS OFF - DUMP OFF DATA "data/tile_index_mixed_srs_with_data_dir.shp" PROJECTION AUTO @@ -31,7 +30,6 @@ LAYER NAME grey TYPE raster STATUS default - DUMP TRUE TEMPLATE "fake.html" TILEINDEX "mytileindex" TILEITEM "location" diff --git a/msautotest/gdal/tileindexmixedsrs4.map b/msautotest/gdal/tileindexmixedsrs4.map index 796dda882a..f79760fdc3 100644 --- a/msautotest/gdal/tileindexmixedsrs4.map +++ b/msautotest/gdal/tileindexmixedsrs4.map @@ -20,7 +20,6 @@ LAYER NAME mytileindex TYPE POLYGON STATUS OFF - DUMP OFF CONNECTION "data/tile_index_mixed_srs_with_data_dir.shp" CONNECTIONTYPE OGR PROJECTION @@ -32,7 +31,6 @@ LAYER NAME grey TYPE raster STATUS default - DUMP TRUE TEMPLATE "fake.html" TILEINDEX "mytileindex" TILEITEM "location" diff --git a/msautotest/gdal/trlay1.map b/msautotest/gdal/trlay1.map index e144079bb5..17f09503a6 100644 --- a/msautotest/gdal/trlay1.map +++ b/msautotest/gdal/trlay1.map @@ -2,7 +2,8 @@ # Test TRANSPARENCY flag on layer for overlaying 24bit image(s). # # In this case the final output image is RGB but the temporary results include -# alpha values. +# alpha values. +# FIXME/REMOVE_ME?: this used to be the case at the GD era, but now it goes through AGG/PNG8 # MAP @@ -12,14 +13,7 @@ SIZE 400 300 EXTENT 0.5 0.5 399.5 299.5 IMAGECOLOR 255 255 0 -IMAGETYPE png_24 - -OUTPUTFORMAT - NAME png_24 - DRIVER "GD/PNG" - IMAGEMODE RGB - TRANSPARENT OFF -END +IMAGETYPE PNG8 # # Start of layer definitions @@ -36,7 +30,9 @@ LAYER TYPE raster STATUS ON DATA data/grid.gif - TRANSPARENCY 33 + COMPOSITE + OPACITY 33 + END END END # of map file diff --git a/msautotest/gdal/trlay2.map b/msautotest/gdal/trlay2.map index 55ce0b4186..6356198cd3 100644 --- a/msautotest/gdal/trlay2.map +++ b/msautotest/gdal/trlay2.map @@ -3,6 +3,7 @@ # # Final result is RGBA and transparency from both input images, and the # layer TRANSPARENCY flag all have an influence. +# FIXME/REMOVE_ME?: this used to be the case at the GD era, but now it goes through AGG/PNG8 # MAP @@ -12,12 +13,12 @@ SIZE 400 300 EXTENT 0.5 0.5 399.5 299.5 IMAGECOLOR 255 255 0 -IMAGETYPE png_24 +IMAGETYPE png8_t OUTPUTFORMAT - NAME png_24 - DRIVER "GD/PNG" - IMAGEMODE RGBA + NAME png8_t + DRIVER "AGG/PNG8" + IMAGEMODE RGB TRANSPARENT ON END @@ -36,7 +37,9 @@ LAYER TYPE raster STATUS ON DATA data/grid.gif - TRANSPARENCY 33 + COMPOSITE + OPACITY 33 + END END END # of map file diff --git a/msautotest/gdal/trlay3.map b/msautotest/gdal/trlay3.map index d508bcdb5b..e0bd524a8f 100644 --- a/msautotest/gdal/trlay3.map +++ b/msautotest/gdal/trlay3.map @@ -9,12 +9,12 @@ SIZE 400 300 EXTENT 0.5 0.5 399.5 299.5 IMAGECOLOR 255 255 0 -IMAGETYPE png_8 +IMAGETYPE png8_t OUTPUTFORMAT - NAME png_8 - DRIVER "GD/PNG" - IMAGEMODE PC256 + NAME png8_t + DRIVER "AGG/PNG8" + IMAGEMODE RGB TRANSPARENT ON END @@ -33,7 +33,9 @@ LAYER TYPE raster STATUS ON DATA data/grid.gif - TRANSPARENCY 33 + COMPOSITE + OPACITY 33 + END END END # of map file diff --git a/msautotest/gdal/unclassified.map b/msautotest/gdal/unclassified.map index ed3114e854..2f76191df8 100644 --- a/msautotest/gdal/unclassified.map +++ b/msautotest/gdal/unclassified.map @@ -26,6 +26,7 @@ LAYER STATUS default DATA data/rgba.tif PROCESSING "BANDS=1,2,3" + PROCESSING "USE_MASK_BAND=NO" CLASS KEYIMAGE "data/grid.gif" END diff --git a/msautotest/gdal/wld_override.map b/msautotest/gdal/wld_override.map index bc8040d014..5044ba3fc6 100644 --- a/msautotest/gdal/wld_override.map +++ b/msautotest/gdal/wld_override.map @@ -18,14 +18,7 @@ PROJECTION "datum=WGS84" END -IMAGETYPE png8_t - -OUTPUTFORMAT - NAME png8_t - DRIVER "GD/PNG" - IMAGEMODE PC256 - TRANSPARENT OFF -END +IMAGETYPE PNG8 LAYER NAME grey diff --git a/msautotest/gdal/wld_rotate.map b/msautotest/gdal/wld_rotate.map index 27d65cd176..4b9b35d6e6 100644 --- a/msautotest/gdal/wld_rotate.map +++ b/msautotest/gdal/wld_rotate.map @@ -18,14 +18,7 @@ PROJECTION "datum=WGS84" END -IMAGETYPE png8_t - -OUTPUTFORMAT - NAME png8_t - DRIVER "GD/PNG" - IMAGEMODE PC256 - TRANSPARENT OFF -END +IMAGETYPE PNG8 LAYER NAME grey diff --git a/msautotest/gdal/wld_upsidedown.map b/msautotest/gdal/wld_upsidedown.map index 9756386349..a170b99eb6 100644 --- a/msautotest/gdal/wld_upsidedown.map +++ b/msautotest/gdal/wld_upsidedown.map @@ -11,14 +11,7 @@ SIZE 200 150 EXTENT 1 1 399 299 IMAGECOLOR 255 255 0 -IMAGETYPE png8_t - -OUTPUTFORMAT - NAME png8_t - DRIVER "GD/PNG" - IMAGEMODE PC256 - TRANSPARENT OFF -END +IMAGETYPE PNG8 LAYER NAME grey diff --git a/msautotest/gdal/wmsclient.map b/msautotest/gdal/wmsclient.map index a2e076926e..ef870fc269 100644 --- a/msautotest/gdal/wmsclient.map +++ b/msautotest/gdal/wmsclient.map @@ -12,9 +12,9 @@ EXTENT -180 -60 180 85 IMAGECOLOR 255 255 0 OUTPUTFORMAT - NAME png8_t + NAME gdal_png DRIVER "GDAL/PNG" - IMAGEMODE PC256 + IMAGEMODE RGB END WEB @@ -27,7 +27,7 @@ LAYER STATUS DEFAULT DEBUG 1 #CONNECTION "http://mstest.tiles.osgeo.org/wms/vmap0?" - CONNECTION "http://demo.mapserver.org/cgi-bin/mapserv?map=/osgeo/mapserver/msautotest/world/world.map&" + CONNECTION "https://demo.mapserver.org/cgi-bin/msautotest?" CONNECTIONTYPE WMS METADATA "wms_srs" "EPSG:4326" diff --git a/msautotest/gdal/wmsclient_3543.map b/msautotest/gdal/wmsclient_3543.map index 5b5b44a2c7..28a03ad30d 100644 --- a/msautotest/gdal/wmsclient_3543.map +++ b/msautotest/gdal/wmsclient_3543.map @@ -22,7 +22,7 @@ END LAYER NAME "X" - CONNECTION "http://demo.mapserver.org/cgi-bin/mapserv?map=/osgeo/mapserver/msautotest/world/world.map&" + CONNECTION "https://demo.mapserver.org/cgi-bin/msautotest?" CONNECTIONTYPE WMS TYPE RASTER STATUS DEFAULT diff --git a/msautotest/misc/attrbind.map b/msautotest/misc/attrbind.map index 0c15dc8425..536ab26d51 100644 --- a/msautotest/misc/attrbind.map +++ b/msautotest/misc/attrbind.map @@ -3,7 +3,9 @@ # # REQUIRES: INPUT=SHAPE OUTPUT=PNG # -# RUN_PARMS: attrbind_test001.png [SHP2IMG] -m [MAPFILE] -l test001 -o [RESULT] +# RUN_PARMS: attrbind_test001.png [MAP2IMG] -m [MAPFILE] -l test001 -o [RESULT] +# RUN_PARMS: attrbind_test002.png [MAP2IMG] -m [MAPFILE] -l test002 -o [RESULT] + MAP NAME 'attrbind' EXTENT -1.5 0.1 -0.6 1.0 @@ -71,5 +73,25 @@ MAP END END END + + # test with an alpha channel in bound colour + LAYER + NAME 'test002' + TYPE POINT + STATUS OFF + CONNECTIONTYPE OGR + CONNECTION "data/attrbind.shp" + DATA "SELECT *, '#006D2C14' AS hex FROM attrbind" + CLASS + STYLE + OPACITY 20 + COLOR [hex] + SYMBOL [symbol] + OFFSET 2 2 + SIZE 30 + END + END + END + END diff --git a/msautotest/misc/bug1526.map b/msautotest/misc/bug1526.map index fcf699ded2..594dd2a4eb 100644 --- a/msautotest/misc/bug1526.map +++ b/msautotest/misc/bug1526.map @@ -3,7 +3,7 @@ # processing very very small rectangles in msProjectRect() due to the # increment size rounding to zero against the base values. The output # image is not intended to be interesting. The important thing is that -# shp2img complete, not hang. +# map2img complete, not hang. # # REQUIRES: INPUT=SHAPE OUTPUT=PNG SUPPORTS=PROJ # @@ -26,8 +26,10 @@ MAP "+proj=latlong +datum=WGS84" END CLASS - OUTLINECOLOR 255 0 0 - COLOR 0 255 0 + STYLE + OUTLINECOLOR 255 0 0 + COLOR 0 255 0 + END END END END diff --git a/msautotest/misc/centerline.map b/msautotest/misc/centerline.map new file mode 100644 index 0000000000..5c5ffe8775 --- /dev/null +++ b/msautotest/misc/centerline.map @@ -0,0 +1,231 @@ +# +# Tests the centerline, inner and outer GEOMTRANSFORM functions. +# +# REQUIRES: INPUT=SHAPE OUTPUT=PNG +# +# RUN_PARMS: centerline1.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&mode=map&layer=centerline1" > [RESULT_DEMIME] +# RUN_PARMS: centerline2.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&mode=map&layer=centerline2" > [RESULT_DEMIME] +# RUN_PARMS: centerline3_exception.txt [MAPSERV] QUERY_STRING="map=[MAPFILE]&mode=map&layer=centerline3" > [RESULT_DEVERSION] +# RUN_PARMS: centerline4_exception.txt [MAPSERV] QUERY_STRING="map=[MAPFILE]&mode=map&layer=centerline4" > [RESULT_DEVERSION] +# RUN_PARMS: centerline5_exception.txt [MAPSERV] QUERY_STRING="map=[MAPFILE]&mode=map&layer=centerline5" > [RESULT_DEVERSION] +# +MAP + NAME "centerline" + STATUS ON + # EXTENT -125.549477 -69.508628 101.670954 15.840339 + # EXTENT -131.343925 -41.285156 170.097978 115.727752 + EXTENT -135.620276 -69.508628 173.802333 104.769497 + SIZE 400 300 + FONTSET "fonts.lst" + IMAGETYPE png24 + + SHAPEPATH "../renderers/data" + + # CONFIG MS_ERRORFILE "stderr" + + SYMBOL NAME 'vertex' TYPE ELLIPSE POINTS 1 1 END FILLED TRUE END + + LAYER + NAME 'base' + TYPE POLYGON + STATUS DEFAULT + DATA 'world_testpoly' + CLASS + STYLE + COLOR 181 181 181 + OUTLINECOLOR 51 51 51 + END + END + END + + LAYER + NAME 'outer' + TYPE LINE + STATUS DEFAULT + DATA 'world_testpoly' + GEOMTRANSFORM (outer([shape])) + CLASS + STYLE + COLOR 0 0 0 + WIDTH 2 + END + END + END + + LAYER + NAME 'inner' + TYPE LINE + STATUS DEFAULT + DATA 'world_testpoly' + GEOMTRANSFORM (inner([shape])) + CLASS + STYLE + COLOR 255 0 0 + WIDTH 2 + END + END + END + + LAYER + NAME 'centerline1' + TYPE LINE + STATUS OFF + DATA 'world_testpoly' + GEOMTRANSFORM (centerline(densify([shape], 5))) + CLASS + LABEL + TEXT 'sample label' + TYPE TRUETYPE + FONT 'lucida' + COLOR 0 0 0 + OUTLINECOLOR 255 255 255 + SIZE 8 + MAXOVERLAPANGLE 50 + ANGLE FOLLOW + END + STYLE + COLOR 0 0 0 + WIDTH 1 + PATTERN 5 5 END + END + STYLE + GEOMTRANSFORM VERTICES + SYMBOL 'vertex' + COLOR 0 0 255 + SIZE 3 + END + STYLE + GEOMTRANSFORM START + SYMBOL 'vertex' + COLOR 255 0 0 + SIZE 5 + END + STYLE + GEOMTRANSFORM "END" + SYMBOL 'vertex' + COLOR 0 255 0 + SIZE 5 + END + END + END + + LAYER + NAME 'centerline2' + TYPE LINE + STATUS OFF + DATA 'world_testpoly' + GEOMTRANSFORM (smoothsia(centerline(densify([shape], 5)))) + CLASS + LABEL + TEXT 'sample label' + TYPE TRUETYPE + FONT 'lucida' + COLOR 0 0 0 + OUTLINECOLOR 255 255 255 + SIZE 8 + MAXOVERLAPANGLE 50 + ANGLE FOLLOW + END + STYLE + COLOR 0 0 0 + WIDTH 1 + PATTERN 5 5 END + END + STYLE + GEOMTRANSFORM VERTICES + SYMBOL 'vertex' + COLOR 0 0 255 + SIZE 3 + END + STYLE + GEOMTRANSFORM START + SYMBOL 'vertex' + COLOR 255 0 0 + SIZE 5 + END + STYLE + GEOMTRANSFORM "END" + SYMBOL 'vertex' + COLOR 0 255 0 + SIZE 5 + END + END + END + + # should error, shapes are too simple and need to be densified + LAYER + NAME 'centerline3' + TYPE LINE + STATUS OFF + DATA 'world_testpoly' + GEOMTRANSFORM (centerline([shape])) + CLASS + LABEL + TEXT 'sample label' + TYPE TRUETYPE + FONT 'lucida' + COLOR 0 0 0 + OUTLINECOLOR 255 255 255 + SIZE 8 + MAXOVERLAPANGLE 50 + ANGLE FOLLOW + END + STYLE + COLOR 0 0 0 + WIDTH 1 + PATTERN 5 5 END + END + STYLE + GEOMTRANSFORM VERTICES + SYMBOL 'vertex' + COLOR 0 0 255 + SIZE 3 + END + STYLE + GEOMTRANSFORM START + SYMBOL 'vertex' + COLOR 255 0 0 + SIZE 5 + END + STYLE + GEOMTRANSFORM "END" + SYMBOL 'vertex' + COLOR 0 255 0 + SIZE 5 + END + END + END + + # should error, centerline() requires polygon input + LAYER + NAME 'centerline4' + TYPE LINE + STATUS OFF + DATA 'world_testlines' + GEOMTRANSFORM (centerline([shape])) + CLASS + STYLE + COLOR 0 0 0 + WIDTH 2 + PATTERN 5 5 END + END + END + END + + # should error, densify needs a positive tolerance + LAYER + NAME 'centerline5' + TYPE LINE + STATUS OFF + DATA 'world_testpoly' + GEOMTRANSFORM (centerline(densify([shape],-5))) + CLASS + STYLE + COLOR 0 0 0 + WIDTH 2 + PATTERN 5 5 END + END + END + END + +END diff --git a/msautotest/misc/cluster.map b/msautotest/misc/cluster.map new file mode 100644 index 0000000000..7796f826dd --- /dev/null +++ b/msautotest/misc/cluster.map @@ -0,0 +1,89 @@ +# +# Test a layer with clustering +# +# REQUIRES: INPUT=GDAL INPUT=POSTGIS OUTPUT=PNG SUPPORTS=WMS +# +# RUN_PARMS: cluster.png [MAP2IMG] -m [MAPFILE] -l popplace -o [RESULT] +# +# Capabilities (return latest supported version by default) +# +# RUN_PARMS: wms_cluster_cap_latestversion.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&REQUEST=GetCapabilities" > [RESULT_DEVERSION] +# RUN_PARMS: wms_cluster_cap.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetCapabilities" > [RESULT_DEVERSION] +# +# Draw a map +# RUN_PARMS: wms_get_map_cluster.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMap&CRS=EPSG:3978&BBOX=2279399,-55345,2600377,461587&FORMAT=image/png&WIDTH=400&HEIGHT=400&STYLES=&LAYERS=popplace" > [RESULT_DEMIME] +# +MAP + +NAME "clusters" +EXTENT 2279399 -55345 2600377 461587 +SIZE 400 400 + +PROJECTION + "epsg:3978" +END + +IMAGETYPE png + +SYMBOL + NAME 'circle' + TYPE ELLIPSE + POINTS 1 1 END + FILLED TRUE +END + +WEB + METADATA + "ows_enable_request" "*" + "ows_srs" "EPSG:3978" + "ows_onlineresource" "http://foo" + END +END + +LAYER + NAME popplace + TYPE POINT + CONNECTIONTYPE POSTGIS + CONNECTION "user=postgres dbname=msautotest" + DATA "the_geom FROM popplace USING UNIQUE gid USING srid=3978" + PROCESSING "CLOSE_CONNECTION=DEFER" + STATUS OFF + CLUSTER + MAXDISTANCE 50 + REGION "ellipse" + END + LABELITEM "Cluster_FeatureCount" + CLASSITEM "Cluster_FeatureCount" + + CLASS + NAME "single" + EXPRESSION "1" + STYLE + COLOR 50 50 50 + SIZE 5 + SYMBOL 'circle' + END + END + + CLASS + NAME "cluster" + EXPRESSION ("[Cluster_FeatureCount]" != "1") + LABEL + SIZE 8 + COLOR 0 0 0 + ALIGN CENTER + PRIORITY 10 + BUFFER 1 + PARTIALS TRUE + POSITION cc + FORCE TRUE + END + STYLE + COLOR 0 255 0 + SIZE 20 + SYMBOL 'circle' + END + END +END + +END diff --git a/msautotest/misc/data/Road_Works.svg b/msautotest/misc/data/Road_Works.svg index 09f1f1c657..8d5c89c47b 100644 --- a/msautotest/misc/data/Road_Works.svg +++ b/msautotest/misc/data/Road_Works.svg @@ -1,21 +1,21 @@ + + sodipodi:docname="Road_Works.svg" + version="1.0" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:dc="http://purl.org/dc/elements/1.1/"> @@ -30,8 +30,8 @@ + inkscape:cx="355.32115" + inkscape:cy="216.02112" + inkscape:window-x="1272" + inkscape:window-y="-8" + inkscape:current-layer="svg1353" + inkscape:showpageshadow="2" + inkscape:pagecheckerboard="0" + inkscape:deskcolor="#d1d1d1" + showgrid="false" + inkscape:window-maximized="1" /> + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/msautotest/misc/data/africa.fgb b/msautotest/misc/data/africa.fgb new file mode 100644 index 0000000000..b334827c8e Binary files /dev/null and b/msautotest/misc/data/africa.fgb differ diff --git a/msautotest/misc/data/mykey.txt b/msautotest/misc/data/mykey.txt new file mode 100644 index 0000000000..a721cd6533 --- /dev/null +++ b/msautotest/misc/data/mykey.txt @@ -0,0 +1 @@ +C41C71C7725D0E126C191683BB8AEDC4 diff --git a/msautotest/misc/data/shp_encoding/encoding_1250.cpg b/msautotest/misc/data/shp_encoding/encoding_1250.cpg new file mode 100644 index 0000000000..746faa2a85 --- /dev/null +++ b/msautotest/misc/data/shp_encoding/encoding_1250.cpg @@ -0,0 +1 @@ +1250 \ No newline at end of file diff --git a/msautotest/misc/data/shp_encoding/encoding_1250.dbf b/msautotest/misc/data/shp_encoding/encoding_1250.dbf new file mode 100644 index 0000000000..ce313b02de Binary files /dev/null and b/msautotest/misc/data/shp_encoding/encoding_1250.dbf differ diff --git a/msautotest/misc/data/shp_encoding/encoding_1250.prj b/msautotest/misc/data/shp_encoding/encoding_1250.prj new file mode 100644 index 0000000000..f45cbadf00 --- /dev/null +++ b/msautotest/misc/data/shp_encoding/encoding_1250.prj @@ -0,0 +1 @@ +GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]] \ No newline at end of file diff --git a/msautotest/misc/data/shp_encoding/encoding_1250.shp b/msautotest/misc/data/shp_encoding/encoding_1250.shp new file mode 100644 index 0000000000..eeb7144dbc Binary files /dev/null and b/msautotest/misc/data/shp_encoding/encoding_1250.shp differ diff --git a/msautotest/misc/data/shp_encoding/encoding_1250.shx b/msautotest/misc/data/shp_encoding/encoding_1250.shx new file mode 100644 index 0000000000..d4436d5bef Binary files /dev/null and b/msautotest/misc/data/shp_encoding/encoding_1250.shx differ diff --git a/msautotest/misc/data/shp_encoding/encoding_1251.cpg b/msautotest/misc/data/shp_encoding/encoding_1251.cpg new file mode 100644 index 0000000000..f0acbc2e3f --- /dev/null +++ b/msautotest/misc/data/shp_encoding/encoding_1251.cpg @@ -0,0 +1 @@ +1251 \ No newline at end of file diff --git a/msautotest/misc/data/shp_encoding/encoding_1251.dbf b/msautotest/misc/data/shp_encoding/encoding_1251.dbf new file mode 100644 index 0000000000..911b826cd0 Binary files /dev/null and b/msautotest/misc/data/shp_encoding/encoding_1251.dbf differ diff --git a/msautotest/misc/data/shp_encoding/encoding_1251.prj b/msautotest/misc/data/shp_encoding/encoding_1251.prj new file mode 100644 index 0000000000..f45cbadf00 --- /dev/null +++ b/msautotest/misc/data/shp_encoding/encoding_1251.prj @@ -0,0 +1 @@ +GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]] \ No newline at end of file diff --git a/msautotest/misc/data/shp_encoding/encoding_1251.shp b/msautotest/misc/data/shp_encoding/encoding_1251.shp new file mode 100644 index 0000000000..eeb7144dbc Binary files /dev/null and b/msautotest/misc/data/shp_encoding/encoding_1251.shp differ diff --git a/msautotest/misc/data/shp_encoding/encoding_1251.shx b/msautotest/misc/data/shp_encoding/encoding_1251.shx new file mode 100644 index 0000000000..d4436d5bef Binary files /dev/null and b/msautotest/misc/data/shp_encoding/encoding_1251.shx differ diff --git a/msautotest/misc/data/shp_encoding/encoding_1253.cpg b/msautotest/misc/data/shp_encoding/encoding_1253.cpg new file mode 100644 index 0000000000..b0a0271f9c --- /dev/null +++ b/msautotest/misc/data/shp_encoding/encoding_1253.cpg @@ -0,0 +1 @@ +1253 \ No newline at end of file diff --git a/msautotest/misc/data/shp_encoding/encoding_1253.dbf b/msautotest/misc/data/shp_encoding/encoding_1253.dbf new file mode 100644 index 0000000000..58c1e1e45b Binary files /dev/null and b/msautotest/misc/data/shp_encoding/encoding_1253.dbf differ diff --git a/msautotest/misc/data/shp_encoding/encoding_1253.prj b/msautotest/misc/data/shp_encoding/encoding_1253.prj new file mode 100644 index 0000000000..f45cbadf00 --- /dev/null +++ b/msautotest/misc/data/shp_encoding/encoding_1253.prj @@ -0,0 +1 @@ +GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]] \ No newline at end of file diff --git a/msautotest/misc/data/shp_encoding/encoding_1253.shp b/msautotest/misc/data/shp_encoding/encoding_1253.shp new file mode 100644 index 0000000000..eeb7144dbc Binary files /dev/null and b/msautotest/misc/data/shp_encoding/encoding_1253.shp differ diff --git a/msautotest/misc/data/shp_encoding/encoding_1253.shx b/msautotest/misc/data/shp_encoding/encoding_1253.shx new file mode 100644 index 0000000000..d4436d5bef Binary files /dev/null and b/msautotest/misc/data/shp_encoding/encoding_1253.shx differ diff --git a/msautotest/misc/data/shp_encoding/encoding_1254.cpg b/msautotest/misc/data/shp_encoding/encoding_1254.cpg new file mode 100644 index 0000000000..c789257680 --- /dev/null +++ b/msautotest/misc/data/shp_encoding/encoding_1254.cpg @@ -0,0 +1 @@ +1254 \ No newline at end of file diff --git a/msautotest/misc/data/shp_encoding/encoding_1254.dbf b/msautotest/misc/data/shp_encoding/encoding_1254.dbf new file mode 100644 index 0000000000..d1fce52db5 Binary files /dev/null and b/msautotest/misc/data/shp_encoding/encoding_1254.dbf differ diff --git a/msautotest/misc/data/shp_encoding/encoding_1254.prj b/msautotest/misc/data/shp_encoding/encoding_1254.prj new file mode 100644 index 0000000000..f45cbadf00 --- /dev/null +++ b/msautotest/misc/data/shp_encoding/encoding_1254.prj @@ -0,0 +1 @@ +GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]] \ No newline at end of file diff --git a/msautotest/misc/data/shp_encoding/encoding_1254.shp b/msautotest/misc/data/shp_encoding/encoding_1254.shp new file mode 100644 index 0000000000..eeb7144dbc Binary files /dev/null and b/msautotest/misc/data/shp_encoding/encoding_1254.shp differ diff --git a/msautotest/misc/data/shp_encoding/encoding_1254.shx b/msautotest/misc/data/shp_encoding/encoding_1254.shx new file mode 100644 index 0000000000..d4436d5bef Binary files /dev/null and b/msautotest/misc/data/shp_encoding/encoding_1254.shx differ diff --git a/msautotest/misc/data/shp_encoding/encoding_437.cpg b/msautotest/misc/data/shp_encoding/encoding_437.cpg new file mode 100644 index 0000000000..3fa694f245 --- /dev/null +++ b/msautotest/misc/data/shp_encoding/encoding_437.cpg @@ -0,0 +1 @@ +437 \ No newline at end of file diff --git a/msautotest/misc/data/shp_encoding/encoding_437.dbf b/msautotest/misc/data/shp_encoding/encoding_437.dbf new file mode 100644 index 0000000000..570d91df95 Binary files /dev/null and b/msautotest/misc/data/shp_encoding/encoding_437.dbf differ diff --git a/msautotest/misc/data/shp_encoding/encoding_437.prj b/msautotest/misc/data/shp_encoding/encoding_437.prj new file mode 100644 index 0000000000..f45cbadf00 --- /dev/null +++ b/msautotest/misc/data/shp_encoding/encoding_437.prj @@ -0,0 +1 @@ +GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]] \ No newline at end of file diff --git a/msautotest/misc/data/shp_encoding/encoding_437.shp b/msautotest/misc/data/shp_encoding/encoding_437.shp new file mode 100644 index 0000000000..eeb7144dbc Binary files /dev/null and b/msautotest/misc/data/shp_encoding/encoding_437.shp differ diff --git a/msautotest/misc/data/shp_encoding/encoding_437.shx b/msautotest/misc/data/shp_encoding/encoding_437.shx new file mode 100644 index 0000000000..d4436d5bef Binary files /dev/null and b/msautotest/misc/data/shp_encoding/encoding_437.shx differ diff --git a/msautotest/misc/data/shp_encoding/encoding_88591.cpg b/msautotest/misc/data/shp_encoding/encoding_88591.cpg new file mode 100644 index 0000000000..0968566aaf --- /dev/null +++ b/msautotest/misc/data/shp_encoding/encoding_88591.cpg @@ -0,0 +1 @@ +88591 \ No newline at end of file diff --git a/msautotest/misc/data/shp_encoding/encoding_88591.dbf b/msautotest/misc/data/shp_encoding/encoding_88591.dbf new file mode 100644 index 0000000000..1beb2035e6 Binary files /dev/null and b/msautotest/misc/data/shp_encoding/encoding_88591.dbf differ diff --git a/msautotest/misc/data/shp_encoding/encoding_88591.prj b/msautotest/misc/data/shp_encoding/encoding_88591.prj new file mode 100644 index 0000000000..f45cbadf00 --- /dev/null +++ b/msautotest/misc/data/shp_encoding/encoding_88591.prj @@ -0,0 +1 @@ +GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]] \ No newline at end of file diff --git a/msautotest/misc/data/shp_encoding/encoding_88591.shp b/msautotest/misc/data/shp_encoding/encoding_88591.shp new file mode 100644 index 0000000000..eeb7144dbc Binary files /dev/null and b/msautotest/misc/data/shp_encoding/encoding_88591.shp differ diff --git a/msautotest/misc/data/shp_encoding/encoding_88591.shx b/msautotest/misc/data/shp_encoding/encoding_88591.shx new file mode 100644 index 0000000000..d4436d5bef Binary files /dev/null and b/msautotest/misc/data/shp_encoding/encoding_88591.shx differ diff --git a/msautotest/misc/data/shp_encoding/encoding_885910.cpg b/msautotest/misc/data/shp_encoding/encoding_885910.cpg new file mode 100644 index 0000000000..9378e6a30d --- /dev/null +++ b/msautotest/misc/data/shp_encoding/encoding_885910.cpg @@ -0,0 +1 @@ +885910 \ No newline at end of file diff --git a/msautotest/misc/data/shp_encoding/encoding_885910.dbf b/msautotest/misc/data/shp_encoding/encoding_885910.dbf new file mode 100644 index 0000000000..8c1fde3277 Binary files /dev/null and b/msautotest/misc/data/shp_encoding/encoding_885910.dbf differ diff --git a/msautotest/misc/data/shp_encoding/encoding_885910.prj b/msautotest/misc/data/shp_encoding/encoding_885910.prj new file mode 100644 index 0000000000..f45cbadf00 --- /dev/null +++ b/msautotest/misc/data/shp_encoding/encoding_885910.prj @@ -0,0 +1 @@ +GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]] \ No newline at end of file diff --git a/msautotest/misc/data/shp_encoding/encoding_885910.shp b/msautotest/misc/data/shp_encoding/encoding_885910.shp new file mode 100644 index 0000000000..eeb7144dbc Binary files /dev/null and b/msautotest/misc/data/shp_encoding/encoding_885910.shp differ diff --git a/msautotest/misc/data/shp_encoding/encoding_885910.shx b/msautotest/misc/data/shp_encoding/encoding_885910.shx new file mode 100644 index 0000000000..d4436d5bef Binary files /dev/null and b/msautotest/misc/data/shp_encoding/encoding_885910.shx differ diff --git a/msautotest/misc/data/shp_encoding/encoding_885911.cpg b/msautotest/misc/data/shp_encoding/encoding_885911.cpg new file mode 100644 index 0000000000..8915cc18e4 --- /dev/null +++ b/msautotest/misc/data/shp_encoding/encoding_885911.cpg @@ -0,0 +1 @@ +885911 \ No newline at end of file diff --git a/msautotest/misc/data/shp_encoding/encoding_885911.dbf b/msautotest/misc/data/shp_encoding/encoding_885911.dbf new file mode 100644 index 0000000000..759c303989 Binary files /dev/null and b/msautotest/misc/data/shp_encoding/encoding_885911.dbf differ diff --git a/msautotest/misc/data/shp_encoding/encoding_885911.prj b/msautotest/misc/data/shp_encoding/encoding_885911.prj new file mode 100644 index 0000000000..f45cbadf00 --- /dev/null +++ b/msautotest/misc/data/shp_encoding/encoding_885911.prj @@ -0,0 +1 @@ +GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]] \ No newline at end of file diff --git a/msautotest/misc/data/shp_encoding/encoding_885911.shp b/msautotest/misc/data/shp_encoding/encoding_885911.shp new file mode 100644 index 0000000000..eeb7144dbc Binary files /dev/null and b/msautotest/misc/data/shp_encoding/encoding_885911.shp differ diff --git a/msautotest/misc/data/shp_encoding/encoding_885911.shx b/msautotest/misc/data/shp_encoding/encoding_885911.shx new file mode 100644 index 0000000000..d4436d5bef Binary files /dev/null and b/msautotest/misc/data/shp_encoding/encoding_885911.shx differ diff --git a/msautotest/misc/data/shp_encoding/encoding_885913.cpg b/msautotest/misc/data/shp_encoding/encoding_885913.cpg new file mode 100644 index 0000000000..0d8ed6ba29 --- /dev/null +++ b/msautotest/misc/data/shp_encoding/encoding_885913.cpg @@ -0,0 +1 @@ +885913 \ No newline at end of file diff --git a/msautotest/misc/data/shp_encoding/encoding_885913.dbf b/msautotest/misc/data/shp_encoding/encoding_885913.dbf new file mode 100644 index 0000000000..08d8ebb089 Binary files /dev/null and b/msautotest/misc/data/shp_encoding/encoding_885913.dbf differ diff --git a/msautotest/misc/data/shp_encoding/encoding_885913.prj b/msautotest/misc/data/shp_encoding/encoding_885913.prj new file mode 100644 index 0000000000..f45cbadf00 --- /dev/null +++ b/msautotest/misc/data/shp_encoding/encoding_885913.prj @@ -0,0 +1 @@ +GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]] \ No newline at end of file diff --git a/msautotest/misc/data/shp_encoding/encoding_885913.shp b/msautotest/misc/data/shp_encoding/encoding_885913.shp new file mode 100644 index 0000000000..eeb7144dbc Binary files /dev/null and b/msautotest/misc/data/shp_encoding/encoding_885913.shp differ diff --git a/msautotest/misc/data/shp_encoding/encoding_885913.shx b/msautotest/misc/data/shp_encoding/encoding_885913.shx new file mode 100644 index 0000000000..d4436d5bef Binary files /dev/null and b/msautotest/misc/data/shp_encoding/encoding_885913.shx differ diff --git a/msautotest/misc/data/shp_encoding/encoding_885915.cpg b/msautotest/misc/data/shp_encoding/encoding_885915.cpg new file mode 100644 index 0000000000..ccdb223253 --- /dev/null +++ b/msautotest/misc/data/shp_encoding/encoding_885915.cpg @@ -0,0 +1 @@ +885915 \ No newline at end of file diff --git a/msautotest/misc/data/shp_encoding/encoding_885915.dbf b/msautotest/misc/data/shp_encoding/encoding_885915.dbf new file mode 100644 index 0000000000..3372c76dda Binary files /dev/null and b/msautotest/misc/data/shp_encoding/encoding_885915.dbf differ diff --git a/msautotest/misc/data/shp_encoding/encoding_885915.prj b/msautotest/misc/data/shp_encoding/encoding_885915.prj new file mode 100644 index 0000000000..f45cbadf00 --- /dev/null +++ b/msautotest/misc/data/shp_encoding/encoding_885915.prj @@ -0,0 +1 @@ +GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]] \ No newline at end of file diff --git a/msautotest/misc/data/shp_encoding/encoding_885915.shp b/msautotest/misc/data/shp_encoding/encoding_885915.shp new file mode 100644 index 0000000000..eeb7144dbc Binary files /dev/null and b/msautotest/misc/data/shp_encoding/encoding_885915.shp differ diff --git a/msautotest/misc/data/shp_encoding/encoding_885915.shx b/msautotest/misc/data/shp_encoding/encoding_885915.shx new file mode 100644 index 0000000000..d4436d5bef Binary files /dev/null and b/msautotest/misc/data/shp_encoding/encoding_885915.shx differ diff --git a/msautotest/misc/data/shp_encoding/encoding_88592.cpg b/msautotest/misc/data/shp_encoding/encoding_88592.cpg new file mode 100644 index 0000000000..bda94ad63f --- /dev/null +++ b/msautotest/misc/data/shp_encoding/encoding_88592.cpg @@ -0,0 +1 @@ +88592 \ No newline at end of file diff --git a/msautotest/misc/data/shp_encoding/encoding_88592.dbf b/msautotest/misc/data/shp_encoding/encoding_88592.dbf new file mode 100644 index 0000000000..daeba2a73f Binary files /dev/null and b/msautotest/misc/data/shp_encoding/encoding_88592.dbf differ diff --git a/msautotest/misc/data/shp_encoding/encoding_88592.prj b/msautotest/misc/data/shp_encoding/encoding_88592.prj new file mode 100644 index 0000000000..f45cbadf00 --- /dev/null +++ b/msautotest/misc/data/shp_encoding/encoding_88592.prj @@ -0,0 +1 @@ +GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]] \ No newline at end of file diff --git a/msautotest/misc/data/shp_encoding/encoding_88592.shp b/msautotest/misc/data/shp_encoding/encoding_88592.shp new file mode 100644 index 0000000000..eeb7144dbc Binary files /dev/null and b/msautotest/misc/data/shp_encoding/encoding_88592.shp differ diff --git a/msautotest/misc/data/shp_encoding/encoding_88592.shx b/msautotest/misc/data/shp_encoding/encoding_88592.shx new file mode 100644 index 0000000000..d4436d5bef Binary files /dev/null and b/msautotest/misc/data/shp_encoding/encoding_88592.shx differ diff --git a/msautotest/misc/data/shp_encoding/encoding_88593.cpg b/msautotest/misc/data/shp_encoding/encoding_88593.cpg new file mode 100644 index 0000000000..c5d61bb5db --- /dev/null +++ b/msautotest/misc/data/shp_encoding/encoding_88593.cpg @@ -0,0 +1 @@ +88593 \ No newline at end of file diff --git a/msautotest/misc/data/shp_encoding/encoding_88593.dbf b/msautotest/misc/data/shp_encoding/encoding_88593.dbf new file mode 100644 index 0000000000..34ae9522ff Binary files /dev/null and b/msautotest/misc/data/shp_encoding/encoding_88593.dbf differ diff --git a/msautotest/misc/data/shp_encoding/encoding_88593.prj b/msautotest/misc/data/shp_encoding/encoding_88593.prj new file mode 100644 index 0000000000..f45cbadf00 --- /dev/null +++ b/msautotest/misc/data/shp_encoding/encoding_88593.prj @@ -0,0 +1 @@ +GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]] \ No newline at end of file diff --git a/msautotest/misc/data/shp_encoding/encoding_88593.shp b/msautotest/misc/data/shp_encoding/encoding_88593.shp new file mode 100644 index 0000000000..eeb7144dbc Binary files /dev/null and b/msautotest/misc/data/shp_encoding/encoding_88593.shp differ diff --git a/msautotest/misc/data/shp_encoding/encoding_88593.shx b/msautotest/misc/data/shp_encoding/encoding_88593.shx new file mode 100644 index 0000000000..d4436d5bef Binary files /dev/null and b/msautotest/misc/data/shp_encoding/encoding_88593.shx differ diff --git a/msautotest/misc/data/shp_encoding/encoding_88594.cpg b/msautotest/misc/data/shp_encoding/encoding_88594.cpg new file mode 100644 index 0000000000..355a1b7313 --- /dev/null +++ b/msautotest/misc/data/shp_encoding/encoding_88594.cpg @@ -0,0 +1 @@ +88594 \ No newline at end of file diff --git a/msautotest/misc/data/shp_encoding/encoding_88594.dbf b/msautotest/misc/data/shp_encoding/encoding_88594.dbf new file mode 100644 index 0000000000..a4d4d8410f Binary files /dev/null and b/msautotest/misc/data/shp_encoding/encoding_88594.dbf differ diff --git a/msautotest/misc/data/shp_encoding/encoding_88594.prj b/msautotest/misc/data/shp_encoding/encoding_88594.prj new file mode 100644 index 0000000000..f45cbadf00 --- /dev/null +++ b/msautotest/misc/data/shp_encoding/encoding_88594.prj @@ -0,0 +1 @@ +GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]] \ No newline at end of file diff --git a/msautotest/misc/data/shp_encoding/encoding_88594.shp b/msautotest/misc/data/shp_encoding/encoding_88594.shp new file mode 100644 index 0000000000..eeb7144dbc Binary files /dev/null and b/msautotest/misc/data/shp_encoding/encoding_88594.shp differ diff --git a/msautotest/misc/data/shp_encoding/encoding_88594.shx b/msautotest/misc/data/shp_encoding/encoding_88594.shx new file mode 100644 index 0000000000..d4436d5bef Binary files /dev/null and b/msautotest/misc/data/shp_encoding/encoding_88594.shx differ diff --git a/msautotest/misc/data/shp_encoding/encoding_88595.cpg b/msautotest/misc/data/shp_encoding/encoding_88595.cpg new file mode 100644 index 0000000000..505ed08eb8 --- /dev/null +++ b/msautotest/misc/data/shp_encoding/encoding_88595.cpg @@ -0,0 +1 @@ +88595 \ No newline at end of file diff --git a/msautotest/misc/data/shp_encoding/encoding_88595.dbf b/msautotest/misc/data/shp_encoding/encoding_88595.dbf new file mode 100644 index 0000000000..803ebe61f9 Binary files /dev/null and b/msautotest/misc/data/shp_encoding/encoding_88595.dbf differ diff --git a/msautotest/misc/data/shp_encoding/encoding_88595.prj b/msautotest/misc/data/shp_encoding/encoding_88595.prj new file mode 100644 index 0000000000..f45cbadf00 --- /dev/null +++ b/msautotest/misc/data/shp_encoding/encoding_88595.prj @@ -0,0 +1 @@ +GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]] \ No newline at end of file diff --git a/msautotest/misc/data/shp_encoding/encoding_88595.shp b/msautotest/misc/data/shp_encoding/encoding_88595.shp new file mode 100644 index 0000000000..eeb7144dbc Binary files /dev/null and b/msautotest/misc/data/shp_encoding/encoding_88595.shp differ diff --git a/msautotest/misc/data/shp_encoding/encoding_88595.shx b/msautotest/misc/data/shp_encoding/encoding_88595.shx new file mode 100644 index 0000000000..d4436d5bef Binary files /dev/null and b/msautotest/misc/data/shp_encoding/encoding_88595.shx differ diff --git a/msautotest/misc/data/shp_encoding/encoding_88596.cpg b/msautotest/misc/data/shp_encoding/encoding_88596.cpg new file mode 100644 index 0000000000..4ee2725f57 --- /dev/null +++ b/msautotest/misc/data/shp_encoding/encoding_88596.cpg @@ -0,0 +1 @@ +88596 \ No newline at end of file diff --git a/msautotest/misc/data/shp_encoding/encoding_88596.dbf b/msautotest/misc/data/shp_encoding/encoding_88596.dbf new file mode 100644 index 0000000000..d4ffa1c4fb Binary files /dev/null and b/msautotest/misc/data/shp_encoding/encoding_88596.dbf differ diff --git a/msautotest/misc/data/shp_encoding/encoding_88596.prj b/msautotest/misc/data/shp_encoding/encoding_88596.prj new file mode 100644 index 0000000000..f45cbadf00 --- /dev/null +++ b/msautotest/misc/data/shp_encoding/encoding_88596.prj @@ -0,0 +1 @@ +GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]] \ No newline at end of file diff --git a/msautotest/misc/data/shp_encoding/encoding_88596.shp b/msautotest/misc/data/shp_encoding/encoding_88596.shp new file mode 100644 index 0000000000..eeb7144dbc Binary files /dev/null and b/msautotest/misc/data/shp_encoding/encoding_88596.shp differ diff --git a/msautotest/misc/data/shp_encoding/encoding_88596.shx b/msautotest/misc/data/shp_encoding/encoding_88596.shx new file mode 100644 index 0000000000..d4436d5bef Binary files /dev/null and b/msautotest/misc/data/shp_encoding/encoding_88596.shx differ diff --git a/msautotest/misc/data/shp_encoding/encoding_88597.cpg b/msautotest/misc/data/shp_encoding/encoding_88597.cpg new file mode 100644 index 0000000000..ca3fcf9135 --- /dev/null +++ b/msautotest/misc/data/shp_encoding/encoding_88597.cpg @@ -0,0 +1 @@ +88597 \ No newline at end of file diff --git a/msautotest/misc/data/shp_encoding/encoding_88597.dbf b/msautotest/misc/data/shp_encoding/encoding_88597.dbf new file mode 100644 index 0000000000..165da9f5f2 Binary files /dev/null and b/msautotest/misc/data/shp_encoding/encoding_88597.dbf differ diff --git a/msautotest/misc/data/shp_encoding/encoding_88597.prj b/msautotest/misc/data/shp_encoding/encoding_88597.prj new file mode 100644 index 0000000000..f45cbadf00 --- /dev/null +++ b/msautotest/misc/data/shp_encoding/encoding_88597.prj @@ -0,0 +1 @@ +GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]] \ No newline at end of file diff --git a/msautotest/misc/data/shp_encoding/encoding_88597.shp b/msautotest/misc/data/shp_encoding/encoding_88597.shp new file mode 100644 index 0000000000..eeb7144dbc Binary files /dev/null and b/msautotest/misc/data/shp_encoding/encoding_88597.shp differ diff --git a/msautotest/misc/data/shp_encoding/encoding_88597.shx b/msautotest/misc/data/shp_encoding/encoding_88597.shx new file mode 100644 index 0000000000..d4436d5bef Binary files /dev/null and b/msautotest/misc/data/shp_encoding/encoding_88597.shx differ diff --git a/msautotest/misc/data/shp_encoding/encoding_88598.cpg b/msautotest/misc/data/shp_encoding/encoding_88598.cpg new file mode 100644 index 0000000000..231eb307c1 --- /dev/null +++ b/msautotest/misc/data/shp_encoding/encoding_88598.cpg @@ -0,0 +1 @@ +88598 \ No newline at end of file diff --git a/msautotest/misc/data/shp_encoding/encoding_88598.dbf b/msautotest/misc/data/shp_encoding/encoding_88598.dbf new file mode 100644 index 0000000000..fd4d9360f5 Binary files /dev/null and b/msautotest/misc/data/shp_encoding/encoding_88598.dbf differ diff --git a/msautotest/misc/data/shp_encoding/encoding_88598.prj b/msautotest/misc/data/shp_encoding/encoding_88598.prj new file mode 100644 index 0000000000..f45cbadf00 --- /dev/null +++ b/msautotest/misc/data/shp_encoding/encoding_88598.prj @@ -0,0 +1 @@ +GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]] \ No newline at end of file diff --git a/msautotest/misc/data/shp_encoding/encoding_88598.shp b/msautotest/misc/data/shp_encoding/encoding_88598.shp new file mode 100644 index 0000000000..eeb7144dbc Binary files /dev/null and b/msautotest/misc/data/shp_encoding/encoding_88598.shp differ diff --git a/msautotest/misc/data/shp_encoding/encoding_88598.shx b/msautotest/misc/data/shp_encoding/encoding_88598.shx new file mode 100644 index 0000000000..d4436d5bef Binary files /dev/null and b/msautotest/misc/data/shp_encoding/encoding_88598.shx differ diff --git a/msautotest/misc/data/shp_encoding/encoding_88599.cpg b/msautotest/misc/data/shp_encoding/encoding_88599.cpg new file mode 100644 index 0000000000..85bd649b33 --- /dev/null +++ b/msautotest/misc/data/shp_encoding/encoding_88599.cpg @@ -0,0 +1 @@ +88599 \ No newline at end of file diff --git a/msautotest/misc/data/shp_encoding/encoding_88599.dbf b/msautotest/misc/data/shp_encoding/encoding_88599.dbf new file mode 100644 index 0000000000..cfa42521cc Binary files /dev/null and b/msautotest/misc/data/shp_encoding/encoding_88599.dbf differ diff --git a/msautotest/misc/data/shp_encoding/encoding_88599.prj b/msautotest/misc/data/shp_encoding/encoding_88599.prj new file mode 100644 index 0000000000..f45cbadf00 --- /dev/null +++ b/msautotest/misc/data/shp_encoding/encoding_88599.prj @@ -0,0 +1 @@ +GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]] \ No newline at end of file diff --git a/msautotest/misc/data/shp_encoding/encoding_88599.shp b/msautotest/misc/data/shp_encoding/encoding_88599.shp new file mode 100644 index 0000000000..eeb7144dbc Binary files /dev/null and b/msautotest/misc/data/shp_encoding/encoding_88599.shp differ diff --git a/msautotest/misc/data/shp_encoding/encoding_88599.shx b/msautotest/misc/data/shp_encoding/encoding_88599.shx new file mode 100644 index 0000000000..d4436d5bef Binary files /dev/null and b/msautotest/misc/data/shp_encoding/encoding_88599.shx differ diff --git a/msautotest/misc/data/shp_encoding/encodings_utf-8.cpg b/msautotest/misc/data/shp_encoding/encodings_utf-8.cpg new file mode 100644 index 0000000000..3ad133c048 --- /dev/null +++ b/msautotest/misc/data/shp_encoding/encodings_utf-8.cpg @@ -0,0 +1 @@ +UTF-8 \ No newline at end of file diff --git a/msautotest/misc/data/shp_encoding/encodings_utf-8.dbf b/msautotest/misc/data/shp_encoding/encodings_utf-8.dbf new file mode 100644 index 0000000000..cc401e2433 Binary files /dev/null and b/msautotest/misc/data/shp_encoding/encodings_utf-8.dbf differ diff --git a/msautotest/misc/data/shp_encoding/encodings_utf-8.prj b/msautotest/misc/data/shp_encoding/encodings_utf-8.prj new file mode 100644 index 0000000000..f45cbadf00 --- /dev/null +++ b/msautotest/misc/data/shp_encoding/encodings_utf-8.prj @@ -0,0 +1 @@ +GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]] \ No newline at end of file diff --git a/msautotest/misc/data/shp_encoding/encodings_utf-8.shp b/msautotest/misc/data/shp_encoding/encodings_utf-8.shp new file mode 100644 index 0000000000..eeb7144dbc Binary files /dev/null and b/msautotest/misc/data/shp_encoding/encodings_utf-8.shp differ diff --git a/msautotest/misc/data/shp_encoding/encodings_utf-8.shx b/msautotest/misc/data/shp_encoding/encodings_utf-8.shx new file mode 100644 index 0000000000..d4436d5bef Binary files /dev/null and b/msautotest/misc/data/shp_encoding/encodings_utf-8.shx differ diff --git a/msautotest/misc/data/styleitem_style.csv b/msautotest/misc/data/styleitem_style.csv new file mode 100644 index 0000000000..fd9963a5a4 --- /dev/null +++ b/msautotest/misc/data/styleitem_style.csv @@ -0,0 +1,2 @@ +WKT,STYLE,comment +"LINESTRING(0.1 0.9,0.9 0.9)","STYLE WIDTH 1 COLOR 0 0 255 END","" diff --git a/msautotest/misc/data/union/layer1.dbf b/msautotest/misc/data/union/layer1.dbf new file mode 100644 index 0000000000..6076a2abab Binary files /dev/null and b/msautotest/misc/data/union/layer1.dbf differ diff --git a/msautotest/misc/data/union/layer1.shp b/msautotest/misc/data/union/layer1.shp new file mode 100644 index 0000000000..aec5a87608 Binary files /dev/null and b/msautotest/misc/data/union/layer1.shp differ diff --git a/msautotest/misc/data/union/layer1.shx b/msautotest/misc/data/union/layer1.shx new file mode 100644 index 0000000000..98b0d5ff60 Binary files /dev/null and b/msautotest/misc/data/union/layer1.shx differ diff --git a/msautotest/misc/data/union/layer2.dbf b/msautotest/misc/data/union/layer2.dbf new file mode 100644 index 0000000000..34e534d3f9 Binary files /dev/null and b/msautotest/misc/data/union/layer2.dbf differ diff --git a/msautotest/misc/data/union/layer2.shp b/msautotest/misc/data/union/layer2.shp new file mode 100644 index 0000000000..9b8c267370 Binary files /dev/null and b/msautotest/misc/data/union/layer2.shp differ diff --git a/msautotest/misc/data/union/layer2.shx b/msautotest/misc/data/union/layer2.shx new file mode 100644 index 0000000000..3866ae926e Binary files /dev/null and b/msautotest/misc/data/union/layer2.shx differ diff --git a/msautotest/misc/dateline.map b/msautotest/misc/dateline.map index c3c66fb6ba..a92b24214c 100644 --- a/msautotest/misc/dateline.map +++ b/msautotest/misc/dateline.map @@ -25,8 +25,10 @@ MAP "+proj=merc +datum=WGS84 +over" END CLASS - OUTLINECOLOR 0 0 0 - COLOR 255 255 0 + STYLE + OUTLINECOLOR 0 0 0 + COLOR 255 255 0 + END END END END diff --git a/msautotest/misc/encoding.map b/msautotest/misc/encoding.map index 33c3132a0f..e184f9cf84 100644 --- a/msautotest/misc/encoding.map +++ b/msautotest/misc/encoding.map @@ -1,6 +1,6 @@ # Test support for handling datasource encoding -# RUN_PARMS: encodings.png [SHP2IMG] -m [MAPFILE] -o [RESULT] +# RUN_PARMS: encodings.png [MAP2IMG] -m [MAPFILE] -o [RESULT] # RUN_PARMS: encodings.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=getFeature&TYPENAME=encoded&Filter=nameéà toto" > [RESULT_DEVERSION] map diff --git a/msautotest/misc/encoding_from_cpg.map b/msautotest/misc/encoding_from_cpg.map new file mode 100644 index 0000000000..7ba954461f --- /dev/null +++ b/msautotest/misc/encoding_from_cpg.map @@ -0,0 +1,478 @@ +# Test reading encodings from cpg. +# http://www.madore.org/~david/computers/unicode/cstab.HTML +# +# RUN_PARMS: shp_encodings.png [MAP2IMG] -m [MAPFILE] -o [RESULT] +# +# Recipe to generate the files from the 'encodings_utf-8.shp': +# +# encodings=(88591 88592 88593 88594 88595 88596 88597 88598 88599 885910 885911 885913 885915 437 1250 1251 1253 1254) +# +# for ENC in "${encodings[@]}"; do +# ogr2ogr -f "ESRI Shapefile" "encoding_${ENC}.shp" "encodings_utf-8.shp" -lco ENCODING="$ENC" +# done +# +map + name "test encoding" + size 300 300 + extent -30 -30 40 40 + web + metadata + "ows_enable_request" "*" + "ows_srs" "epsg:4326" + "ows_onlineresource" "http://foo" + end + end + projection + "+init=epsg:4326" + end + + imagetype png + + symbol + type ellipse + name "circle" + points 1 1 end + filled true + end + + LAYER + NAME "latin-1" + DATA "data/shp_encoding/encoding_88591.shp" + TYPE point + CLASSITEM "data" + LABELITEM "encoding" + STATUS on + CLASS + EXPRESSION "ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ" + STYLE + SYMBOL "circle" + SIZE 8 + COLOR 255 0 0 + END # STYLE + LABEL + SIZE 6 + COLOR 0 0 0 + POSITION AUTO + PARTIALS TRUE + MAXLENGTH 10 + END # LABEL + END # CLASS + END # LAYER + + LAYER + NAME "latin-2" + DATA "data/shp_encoding/encoding_88592.shp" + TYPE point + CLASSITEM "data" + LABELITEM "encoding" + STATUS on + CLASS + EXPRESSION "Ą˘Ł¤ĽŚ§¨ŠŞŤŹŽŻ°ą˛ł´ľśˇ¸šşťź˝žżŔÁÂĂÄĹĆÇČÉĘËĚÍÎĎĐŃŇÓÔŐÖ×ŘŮÚŰÜÝŢßŕáâăäĺćçčéęëěíîďđńňóôőö÷řůúűüýţ˙" + STYLE + SYMBOL "circle" + SIZE 8 + COLOR 255 0 0 + END # STYLE + LABEL + SIZE 6 + COLOR 0 0 0 + POSITION AUTO + PARTIALS TRUE + MAXLENGTH 10 + END # LABEL + END # CLASS + END # LAYER + + + LAYER + NAME "latin-3" + DATA "data/shp_encoding/encoding_88593.shp" + TYPE point + CLASSITEM "data" + LABELITEM "encoding" + STATUS on + CLASS + EXPRESSION "ÄĊĈÇÈÉÊËÌÍÎÏÑÒÓÔĠÖ×ĜÙÚÛÜŬŜßàáâäċĉçèéêëìíîïñòóôġö÷ĝùúûüŭŝ" + STYLE + SYMBOL "circle" + SIZE 8 + COLOR 255 0 0 + END # STYLE + LABEL + SIZE 6 + COLOR 0 0 0 + POSITION AUTO + PARTIALS TRUE + MAXLENGTH 10 + END # LABEL + END # CLASS + END # LAYER + + + LAYER + NAME "latin-4" + DATA "data/shp_encoding/encoding_88594.shp" + TYPE point + CLASSITEM "data" + LABELITEM "encoding" + STATUS on + CLASS + EXPRESSION "šēģŧŊžŋĀÁÂÃÄÅÆĮČÉĘËĖÍÎĪĐŅŌĶÔÕÖרŲÚÛÜŨŪßāáâãäåæįčéęëėíîīđņōķôõö÷øųúûüũū" + STYLE + SYMBOL "circle" + SIZE 8 + COLOR 255 0 0 + END # STYLE + LABEL + SIZE 6 + COLOR 0 0 0 + POSITION AUTO + PARTIALS TRUE + MAXLENGTH 10 + END # LABEL + END # CLASS + END # LAYER + + + LAYER + NAME "latin-5" + DATA "data/shp_encoding/encoding_88595.shp" + TYPE point + CLASSITEM "data" + LABELITEM "encoding" + STATUS on + CLASS + EXPRESSION "ЎЏАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдеежзийклмнопрстуфхцчшщъыьэюя№ёђѓєѕіїјљњћќ§ўџ" + STYLE + SYMBOL "circle" + SIZE 8 + COLOR 255 0 0 + END # STYLE + LABEL + SIZE 6 + COLOR 0 0 0 + POSITION AUTO + PARTIALS TRUE + MAXLENGTH 10 + END # LABEL + END # CLASS + END # LAYER + + + LAYER + NAME "latin-6" + DATA "data/shp_encoding/encoding_88596.shp" + TYPE point + CLASSITEM "data" + LABELITEM "encoding" + STATUS on + CLASS + EXPRESSION "ءآأؤإئابةتثجحخدذرزسشصضطظعغـفقكلمنهوى" + STYLE + SYMBOL "circle" + SIZE 8 + COLOR 255 0 0 + END # STYLE + LABEL + SIZE 6 + COLOR 0 0 0 + POSITION AUTO + PARTIALS TRUE + MAXLENGTH 10 + END # LABEL + END # CLASS + END # LAYER + + + LAYER + NAME "latin-7" + DATA "data/shp_encoding/encoding_88597.shp" + TYPE point + CLASSITEM "data" + LABELITEM "encoding" + STATUS on + CLASS + EXPRESSION "ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩΪΫάέήίΰαβγδεζηθικλμνξοπρςστυφχψωϊϋόύώ" + STYLE + SYMBOL "circle" + SIZE 8 + COLOR 255 0 0 + END # STYLE + LABEL + SIZE 6 + COLOR 0 0 0 + POSITION AUTO + PARTIALS TRUE + MAXLENGTH 10 + END # LABEL + END # CLASS + END # LAYER + + + LAYER + NAME "latin-8" + DATA "data/shp_encoding/encoding_88598.shp" + TYPE point + CLASSITEM "data" + LABELITEM "encoding" + STATUS on + CLASS + EXPRESSION "אבגדהוזחטיךכלםמןנסעףפץצקרשת" + STYLE + SYMBOL "circle" + SIZE 8 + COLOR 255 0 0 + END # STYLE + LABEL + SIZE 6 + COLOR 0 0 0 + POSITION AUTO + PARTIALS TRUE + MAXLENGTH 10 + END # LABEL + END # CLASS + END # LAYER + + + LAYER + NAME "latin-9" + DATA "data/shp_encoding/encoding_88599.shp" + TYPE point + CLASSITEM "data" + LABELITEM "encoding" + STATUS on + CLASS + EXPRESSION "ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏĞÑÒÓÔÕÖרÙÚÛÜİŞßàáâãäåæçèéêëìíîïğñòóôõö÷øùúûüışÿ" + STYLE + SYMBOL "circle" + SIZE 8 + COLOR 255 0 0 + END # STYLE + LABEL + SIZE 6 + COLOR 0 0 0 + POSITION AUTO + PARTIALS TRUE + MAXLENGTH 10 + END # LABEL + END # CLASS + END # LAYER + + + LAYER + NAME "latin-10" + DATA "data/shp_encoding/encoding_885910.shp" + TYPE point + CLASSITEM "data" + LABELITEM "encoding" + STATUS on + CLASS + EXPRESSION "ĄĒĢĪĨͧĻĐŠŦŽ­ŪŊ°ąēģīĩķ·ļđšŧž―ūŋĀÁÂÃÄÅÆĮČÉĘËĖÍÎÏÐŅŌÓÔÕÖŨØŲÚÛÜÝÞßāáâãäåæįčéęëėíîïðņōóôõöũøųúûüýþĸ" + STYLE + SYMBOL "circle" + SIZE 8 + COLOR 255 0 0 + END # STYLE + LABEL + SIZE 6 + COLOR 0 0 0 + POSITION AUTO + PARTIALS TRUE + MAXLENGTH 10 + END # LABEL + END # CLASS + END # LAYER + + + LAYER + NAME "latin-11" + DATA "data/shp_encoding/encoding_885911.shp" + TYPE point + CLASSITEM "data" + LABELITEM "encoding" + STATUS on + CLASS + EXPRESSION "กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรฤลฦวศษสหฬอฮฯะัำิีึืฺุู" + STYLE + SYMBOL "circle" + SIZE 8 + COLOR 255 0 0 + END # STYLE + LABEL + SIZE 6 + COLOR 0 0 0 + POSITION AUTO + PARTIALS TRUE + MAXLENGTH 10 + END # LABEL + END # CLASS + END # LAYER + + LAYER + NAME "latin-13" + DATA "data/shp_encoding/encoding_885913.shp" + TYPE point + CLASSITEM "data" + LABELITEM "encoding" + STATUS on + CLASS + EXPRESSION "ĄĮĀĆÄÅĘĒČÉŹĖĢĶĪĻŠŃŅÓŌÕÖ×ŲŁŚŪÜŻŽßąįāćäåęēčéźėģķīļšńņóōõö÷ųłśūüżž’" + STYLE + SYMBOL "circle" + SIZE 8 + COLOR 255 0 0 + END # STYLE + LABEL + SIZE 6 + COLOR 0 0 0 + POSITION AUTO + PARTIALS TRUE + MAXLENGTH 10 + END # LABEL + END # CLASS + END # LAYER + + LAYER + NAME "latin-15" + DATA "data/shp_encoding/encoding_885915.shp" + TYPE point + CLASSITEM "data" + LABELITEM "encoding" + STATUS on + CLASS + EXPRESSION "ŒœŸ¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ" + STYLE + SYMBOL "circle" + SIZE 8 + COLOR 255 0 0 + END # STYLE + LABEL + SIZE 6 + COLOR 0 0 0 + POSITION AUTO + PARTIALS TRUE + MAXLENGTH 10 + END # LABEL + END # CLASS + END # LAYER + + LAYER + NAME "ANSI 1250" + DATA "data/shp_encoding/encoding_1250.shp" + TYPE point + CLASSITEM "data" + LABELITEM "encoding" + STATUS on + CLASS + EXPRESSION "ŔÁÂĂÄĹĆÇČÉĘËĚÍÎĎĐŃŇÓÔŐÖ×ŘŮÚŰÜÝŢßŕáâăäĺćçčéęëěíîďđńňóôőö÷řůúűüý" + STYLE + SYMBOL "circle" + SIZE 8 + COLOR 255 0 0 + END # STYLE + LABEL + SIZE 6 + COLOR 0 0 0 + POSITION AUTO + PARTIALS TRUE + MAXLENGTH 10 + END # LABEL + END # CLASS + END # LAYER + LAYER + NAME "ANSI 1251" + DATA "data/shp_encoding/encoding_1251.shp" + TYPE point + CLASSITEM "data" + LABELITEM "encoding" + STATUS on + CLASS + EXPRESSION "АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзиклмнопрстуфхцчшщъыьэюя" + STYLE + SYMBOL "circle" + SIZE 8 + COLOR 255 0 0 + END # STYLE + LABEL + SIZE 6 + COLOR 0 0 0 + POSITION AUTO + PARTIALS TRUE + MAXLENGTH 10 + END # LABEL + END # CLASS + END # LAYER + + LAYER + NAME "ANSI 1253" + DATA "data/shp_encoding/encoding_1253.shp" + TYPE point + CLASSITEM "data" + LABELITEM "encoding" + STATUS on + CLASS + EXPRESSION "ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩΪΫάέήίΰαβγδεζηθικλμνξοπρςστυφχψωϊϋόύώ" + STYLE + SYMBOL "circle" + SIZE 8 + COLOR 255 0 0 + END # STYLE + LABEL + SIZE 6 + COLOR 0 0 0 + POSITION AUTO + PARTIALS TRUE + MAXLENGTH 10 + END # LABEL + END # CLASS + END # LAYER + + LAYER + NAME "ANSI 1254" + DATA "data/shp_encoding/encoding_1254.shp" + TYPE point + CLASSITEM "data" + LABELITEM "encoding" + STATUS on + CLASS + EXPRESSION "ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏĞÑÒÓÔÕÖØÙÚÛÜİŞß" + STYLE + SYMBOL "circle" + SIZE 8 + COLOR 255 0 0 + END # STYLE + LABEL + SIZE 6 + COLOR 0 0 0 + POSITION AUTO + PARTIALS TRUE + MAXLENGTH 10 + END # LABEL + END # CLASS + END # LAYER + + LAYER + NAME "OEM Codepage 437" + DATA "data/shp_encoding/encoding_437.shp" + TYPE point + CLASSITEM "data" + LABELITEM "encoding" + STATUS on + CLASS + EXPRESSION "ÉæÆôöòûùÿÖÜ¢£¥₧ƒ" + STYLE + SYMBOL "circle" + SIZE 8 + COLOR 255 0 0 + END # STYLE + LABEL + SIZE 6 + COLOR 0 0 0 + POSITION AUTO + PARTIALS TRUE + MAXLENGTH 10 + END # LABEL + END # CLASS + END # LAYER + +END # MAP diff --git a/msautotest/misc/encrypted_connection.map b/msautotest/misc/encrypted_connection.map new file mode 100644 index 0000000000..68474187dd --- /dev/null +++ b/msautotest/misc/encrypted_connection.map @@ -0,0 +1,55 @@ +# +# Test encrypted connection strings +# +# REQUIRES: INPUT=OGR SUPPORTS=WFS +# +# RUN_PARMS: encrypted_connection_postgis_hits.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&service=WFS&version=2.0.0&request=GetFeature&resultType=hits&typenames=road" > [RESULT_DEVERSION] + +MAP + +NAME ENCRYPTED_TEST +STATUS ON +SIZE 400 300 +EXTENT 2018000 -73300 3410396 647400 +UNITS METERS +UNITS DD +IMAGECOLOR 255 255 255 +IMAGETYPE png + +PROJECTION + "init=epsg:4326" +END + +# use a relative path to an encryption key +CONFIG "MS_ENCRYPTION_KEY" "data/mykey.txt" + +WEB + METADATA + "wfs_onlineresource" "http://localhost/path/to/wfs_simple?" + "ows_enable_request" "*" + END +END + +LAYER + NAME road + CONNECTIONTYPE postgis + # encrypted connection string details + CONNECTION "dbname={11BB7FB1E993759CD0E8761CA1DEC7B3} user={35B83E9A93BF72F0}" + DATA "the_geom from (select * from road order by gid) as foo using unique gid using srid=3978" + TYPE LINE + STATUS ON + + PROJECTION + "init=epsg:3978" + END + + CLASS + NAME "Roads" + STYLE + WIDTH 1 + COLOR 220 0 0 + END + END +END # Layer + +END # Map File diff --git a/msautotest/misc/expected/attrbind_test001.png b/msautotest/misc/expected/attrbind_test001.png index 61928f5d0a..395f82b7d3 100644 Binary files a/msautotest/misc/expected/attrbind_test001.png and b/msautotest/misc/expected/attrbind_test001.png differ diff --git a/msautotest/misc/expected/attrbind_test002.png b/msautotest/misc/expected/attrbind_test002.png new file mode 100644 index 0000000000..909ae2d84e Binary files /dev/null and b/msautotest/misc/expected/attrbind_test002.png differ diff --git a/msautotest/misc/expected/autostyle_quoted.png b/msautotest/misc/expected/autostyle_quoted.png index f0d43dd840..f811e7c93c 100644 Binary files a/msautotest/misc/expected/autostyle_quoted.png and b/msautotest/misc/expected/autostyle_quoted.png differ diff --git a/msautotest/misc/expected/browse.html b/msautotest/misc/expected/browse.html new file mode 100644 index 0000000000..1d554debdd --- /dev/null +++ b/msautotest/misc/expected/browse.html @@ -0,0 +1,49 @@ + + + + + + MapServer Simple Viewer + + + + + +
+ + + + \ No newline at end of file diff --git a/msautotest/misc/expected/browse_all.html b/msautotest/misc/expected/browse_all.html new file mode 100644 index 0000000000..3769abcfda --- /dev/null +++ b/msautotest/misc/expected/browse_all.html @@ -0,0 +1,49 @@ + + + + + + MapServer Simple Viewer + + + + + +
+ + + + \ No newline at end of file diff --git a/msautotest/misc/expected/browse_invalid.html b/msautotest/misc/expected/browse_invalid.html new file mode 100644 index 0000000000..43b058c543 --- /dev/null +++ b/msautotest/misc/expected/browse_invalid.html @@ -0,0 +1,49 @@ + + + + + + MapServer Simple Viewer + + + + + +
+ + + + \ No newline at end of file diff --git a/msautotest/misc/expected/centerline1.png b/msautotest/misc/expected/centerline1.png new file mode 100644 index 0000000000..85793e48f1 Binary files /dev/null and b/msautotest/misc/expected/centerline1.png differ diff --git a/msautotest/misc/expected/centerline2.png b/msautotest/misc/expected/centerline2.png new file mode 100644 index 0000000000..910c78f203 Binary files /dev/null and b/msautotest/misc/expected/centerline2.png differ diff --git a/msautotest/misc/expected/centerline3_exception.txt b/msautotest/misc/expected/centerline3_exception.txt new file mode 100644 index 0000000000..a06ec1f353 --- /dev/null +++ b/msautotest/misc/expected/centerline3_exception.txt @@ -0,0 +1,10 @@ +Content-Type: text/html + + +MapServer Message + +msDrawMap(): Image handling error. Failed to draw layer named 'centerline3'. +msGeomTransformShape(): Expression parser error. Failed to process shape expression: centerline([shape]) +yyparse(): Expression parser error. Executing centerline failed. +msGEOSCenterline(): GEOS library error. Centerline generation failed, try densifying the shapes. + \ No newline at end of file diff --git a/msautotest/misc/expected/centerline4_exception.txt b/msautotest/misc/expected/centerline4_exception.txt new file mode 100644 index 0000000000..50d6997c22 --- /dev/null +++ b/msautotest/misc/expected/centerline4_exception.txt @@ -0,0 +1,10 @@ +Content-Type: text/html + + +MapServer Message + +msDrawMap(): Image handling error. Failed to draw layer named 'centerline4'. +msGeomTransformShape(): Expression parser error. Failed to process shape expression: centerline([shape]) +yyparse(): Expression parser error. Executing centerline failed. +msGEOSCenterline(): GEOS library error. Centerlines can only be computed for polygon shapes. + \ No newline at end of file diff --git a/msautotest/misc/expected/centerline5_exception.txt b/msautotest/misc/expected/centerline5_exception.txt new file mode 100644 index 0000000000..a8e8a1fcca --- /dev/null +++ b/msautotest/misc/expected/centerline5_exception.txt @@ -0,0 +1,9 @@ +Content-Type: text/html + + +MapServer Message + +msDrawMap(): Image handling error. Failed to draw layer named 'centerline5'. +msGeomTransformShape(): Expression parser error. Failed to process shape expression: centerline(densify([shape],-5)) +yyparse(): Expression parser error. Executing densify failed. + \ No newline at end of file diff --git a/msautotest/misc/expected/cluster.png b/msautotest/misc/expected/cluster.png new file mode 100644 index 0000000000..486bf1620f Binary files /dev/null and b/msautotest/misc/expected/cluster.png differ diff --git a/msautotest/misc/expected/encodings.xml b/msautotest/misc/expected/encodings.xml index 9413c26a2c..581d33b0e6 100644 --- a/msautotest/misc/expected/encodings.xml +++ b/msautotest/misc/expected/encodings.xml @@ -11,19 +11,19 @@ Content-Type: text/xml; charset=UTF-8 http://mapserver.gis.umn.edu/mapserver http://foo?SERVICE=WFS&VERSION=1.0.0&REQUEST=DescribeFeatureType&TYPENAME=encoded&OUTPUTFORMAT=XMLSCHEMA"> - -0.95118,0.39958 -0.95118,0.39958 + -0.951189,0.399582 -0.951189,0.399582 - -0.95118,0.39958 -0.95118,0.39958 + -0.951189,0.399582 -0.951189,0.399582 - -0.95118,0.39958 + -0.951189,0.399582 diff --git a/msautotest/misc/expected/encrypted_connection_postgis_hits.xml b/msautotest/misc/expected/encrypted_connection_postgis_hits.xml new file mode 100644 index 0000000000..5d489519ee --- /dev/null +++ b/msautotest/misc/expected/encrypted_connection_postgis_hits.xml @@ -0,0 +1,12 @@ +Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 + + + + + diff --git a/msautotest/misc/expected/flatgeobuf-classes.png b/msautotest/misc/expected/flatgeobuf-classes.png new file mode 100644 index 0000000000..d03cea3d8a Binary files /dev/null and b/msautotest/misc/expected/flatgeobuf-classes.png differ diff --git a/msautotest/misc/expected/flatgeobuf-continent.png b/msautotest/misc/expected/flatgeobuf-continent.png new file mode 100644 index 0000000000..988f207c28 Binary files /dev/null and b/msautotest/misc/expected/flatgeobuf-continent.png differ diff --git a/msautotest/misc/expected/flatgeobuf-ocean.png b/msautotest/misc/expected/flatgeobuf-ocean.png new file mode 100644 index 0000000000..172c885d62 Binary files /dev/null and b/msautotest/misc/expected/flatgeobuf-ocean.png differ diff --git a/msautotest/misc/expected/flatgeobuf-shapepath-classes.png b/msautotest/misc/expected/flatgeobuf-shapepath-classes.png new file mode 100644 index 0000000000..d03cea3d8a Binary files /dev/null and b/msautotest/misc/expected/flatgeobuf-shapepath-classes.png differ diff --git a/msautotest/misc/expected/flatgeobuf-shapepath-continent.png b/msautotest/misc/expected/flatgeobuf-shapepath-continent.png new file mode 100644 index 0000000000..988f207c28 Binary files /dev/null and b/msautotest/misc/expected/flatgeobuf-shapepath-continent.png differ diff --git a/msautotest/misc/expected/flatgeobuf-wfs-cap.xml b/msautotest/misc/expected/flatgeobuf-wfs-cap.xml new file mode 100644 index 0000000000..283a6b4f92 --- /dev/null +++ b/msautotest/misc/expected/flatgeobuf-wfs-cap.xml @@ -0,0 +1,110 @@ +Content-Type: text/xml; charset=UTF-8 + + + + + MapServer WFS + Test FlatGeobuf WFS output + Longer text describing the FlatGeobuf WFS service. + http://localhost/path/to/flatgeobuf? + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + africa-continent + Africa Continent + EPSG:4326 + + http://localhost/path/to/flatgeobuf?request=GetMetadata&layer=africa-continent + + + africa-classes + Africa Classes + EPSG:4326 + + http://localhost/path/to/flatgeobuf?request=GetMetadata&layer=africa-classes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msautotest/misc/expected/flatgeobuf-wfs-describe.xml b/msautotest/misc/expected/flatgeobuf-wfs-describe.xml new file mode 100644 index 0000000000..712fbf1c10 --- /dev/null +++ b/msautotest/misc/expected/flatgeobuf-wfs-describe.xml @@ -0,0 +1,50 @@ +Content-Type: text/xml; charset=UTF-8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msautotest/misc/expected/flatgeobuf-wfs-get-feature-id.xml b/msautotest/misc/expected/flatgeobuf-wfs-get-feature-id.xml new file mode 100644 index 0000000000..8aa57ca584 --- /dev/null +++ b/msautotest/misc/expected/flatgeobuf-wfs-get-feature-id.xml @@ -0,0 +1,39 @@ +Content-Type: text/xml; charset=UTF-8 + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 0.023803,11.018682 -0.049785,10.706918 0.367580,10.191213 0.365901,9.465004 0.461192,8.677223 0.712029,8.312465 0.490957,7.411744 0.570384,6.914359 0.836931,6.279979 1.060122,5.928837 -0.507638,5.343473 -1.063625,5.000548 -1.964707,4.710462 -2.856125,4.994476 -2.810701,5.389051 -3.244370,6.250472 -2.983585,7.379705 -2.562190,8.219628 -2.827496,9.642461 -2.963896,10.395335 -2.940409,10.962690 -1.203358,11.009819 -0.761576,10.936930 -0.438702,11.098341 0.023803,11.018682 + + + + + 27499924 + Ghana + 46 + + + + diff --git a/msautotest/misc/expected/flatgeobuf-wfs-get-feature-propertyname-geometry.xml b/msautotest/misc/expected/flatgeobuf-wfs-get-feature-propertyname-geometry.xml new file mode 100644 index 0000000000..f271e5cb24 --- /dev/null +++ b/msautotest/misc/expected/flatgeobuf-wfs-get-feature-propertyname-geometry.xml @@ -0,0 +1,1005 @@ +Content-Type: text/xml; charset=UTF-8 + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 49.543519,-12.469833 49.808981,-12.895285 50.056511,-13.555761 50.217431,-14.758789 50.476537,-15.226512 50.377111,-15.706069 50.200275,-16.000263 49.860606,-15.414253 49.672607,-15.710204 49.863344,-16.451037 49.774564,-16.875042 49.498612,-17.106036 49.435619,-17.953064 49.041792,-19.118781 48.548541,-20.496888 47.930749,-22.391501 47.547723,-23.781959 47.095761,-24.941630 46.282478,-25.178463 45.409508,-25.601434 44.833574,-25.346101 44.039720,-24.988345 43.763768,-24.460677 43.697778,-23.574116 43.345654,-22.776904 43.254187,-22.057413 43.433298,-21.336475 43.893683,-21.163307 43.896370,-20.830459 44.374325,-20.072366 44.464397,-19.435454 44.232422,-18.961995 44.042976,-18.331387 43.963084,-17.409945 44.312469,-16.850496 44.446517,-16.216219 44.944937,-16.179374 45.502732,-15.974373 45.872994,-15.793454 46.312243,-15.780018 46.882183,-15.210182 47.705130,-14.594303 48.005215,-14.091233 47.869047,-13.663869 48.293828,-13.784068 48.845060,-13.089175 48.863509,-12.487868 49.194651,-12.040557 49.543519,-12.469833 + + + + + Madagascar + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 34.559989,-11.520020 35.312398,-11.439146 36.514082,-11.720938 36.775151,-11.594537 37.471290,-11.568760 37.827640,-11.268790 38.427557,-11.285202 39.521000,-10.896880 40.316590,-10.317100 40.316586,-10.317098 40.316589,-10.317096 40.478387,-10.765441 40.437253,-11.761711 40.560811,-12.639177 40.599620,-14.201975 40.775475,-14.691764 40.477251,-15.406294 40.089264,-16.100774 39.452559,-16.720891 38.538351,-17.101023 37.411133,-17.586368 36.281279,-18.659688 35.896497,-18.842260 35.198400,-19.552811 34.786383,-19.784012 34.701893,-20.497043 35.176127,-21.254361 35.373428,-21.840837 35.385848,-22.140000 35.562546,-22.090000 35.533935,-23.070788 35.371774,-23.535359 35.607470,-23.706563 35.458746,-24.122610 35.040735,-24.478351 34.215824,-24.816314 33.013210,-25.357573 32.574632,-25.727318 32.660363,-26.148584 32.915955,-26.215867 32.830120,-26.742192 32.071665,-26.733820 31.985779,-26.291780 31.837778,-25.843332 31.752408,-25.484284 31.930589,-24.369417 31.670398,-23.658969 31.191409,-22.251510 32.244988,-21.116489 32.508693,-20.395292 32.659743,-20.304290 32.772708,-19.715592 32.611994,-19.419383 32.654886,-18.672090 32.849861,-17.979057 32.847639,-16.713398 32.328239,-16.392074 31.852041,-16.319417 31.636498,-16.071990 31.173064,-15.860944 30.338955,-15.880839 30.274256,-15.507787 30.179481,-14.796099 33.214025,-13.971860 33.789700,-14.451831 34.064825,-14.359950 34.459633,-14.613010 34.517666,-15.013709 34.307291,-15.478641 34.381292,-16.183560 35.033810,-16.801300 35.339063,-16.107440 35.771905,-15.896859 35.686845,-14.611046 35.267956,-13.887834 34.907151,-13.565425 34.559989,-13.579998 34.280006,-12.280025 34.559989,-11.520020 + + + + + Mozambique + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 32.071665,-26.733820 31.868060,-27.177927 31.282773,-27.285879 30.685962,-26.743845 30.676609,-26.398078 30.949667,-26.022649 31.044080,-25.731452 31.333158,-25.660191 31.837778,-25.843332 31.985779,-26.291780 32.071665,-26.733820 + + + + + eSwatini + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 28.978263,-28.955597 29.325166,-29.257387 29.018415,-29.743766 28.848400,-30.070051 28.291069,-30.226217 28.107205,-30.545732 27.749397,-30.645106 26.999262,-29.875954 27.532511,-29.242711 28.074338,-28.851469 28.541700,-28.647502 28.978263,-28.955597 + + + + + Lesotho + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 16.344977,-28.576705 16.824017,-28.082162 17.218929,-28.355943 17.387497,-28.783514 17.836152,-28.856378 18.464899,-29.045462 19.002127,-28.972443 19.894734,-28.461105 19.895768,-24.767790 20.165726,-24.917962 20.758609,-25.868136 20.666470,-26.477453 20.889609,-26.828543 21.605896,-26.726534 22.105969,-26.280256 22.579532,-25.979448 22.824271,-25.500459 23.312097,-25.268690 23.733570,-25.390129 24.211267,-25.670216 25.025171,-25.719670 25.664666,-25.486816 25.765849,-25.174845 25.941652,-24.696373 26.485753,-24.616327 26.786407,-24.240691 27.119410,-23.574323 28.017236,-22.827754 29.432188,-22.091313 29.839037,-22.102216 30.322883,-22.271612 30.659865,-22.151567 31.191409,-22.251510 31.670398,-23.658969 31.930589,-24.369417 31.752408,-25.484284 31.837778,-25.843332 31.333158,-25.660191 31.044080,-25.731452 30.949667,-26.022649 30.676609,-26.398078 30.685962,-26.743845 31.282773,-27.285879 31.868060,-27.177927 32.071665,-26.733820 32.830120,-26.742192 32.580265,-27.470158 32.462133,-28.301011 32.203389,-28.752405 31.521001,-29.257387 31.325561,-29.401978 30.901763,-29.909957 30.622813,-30.423776 30.055716,-31.140269 28.925553,-32.172041 28.219756,-32.771953 27.464608,-33.226964 26.419452,-33.614950 25.909664,-33.667040 25.780628,-33.944646 25.172862,-33.796851 24.677853,-33.987176 23.594043,-33.794474 22.988189,-33.916431 22.574157,-33.864083 21.542799,-34.258839 20.689053,-34.417175 20.071261,-34.795137 19.616405,-34.819166 19.193278,-34.462599 18.855315,-34.444306 18.424643,-33.997873 18.377411,-34.136521 18.244499,-33.867752 18.250080,-33.281431 17.925190,-32.611291 18.247910,-32.429131 18.221762,-31.661633 17.566918,-30.725721 17.064416,-29.878641 17.062918,-29.875954 16.344977,-28.576705 + + + + + 28.978263,-28.955597 28.541700,-28.647502 28.074338,-28.851469 27.532511,-29.242711 26.999262,-29.875954 27.749397,-30.645106 28.107205,-30.545732 28.291069,-30.226217 28.848400,-30.070051 29.018415,-29.743766 29.325166,-29.257387 28.978263,-28.955597 + + + + + South Africa + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 29.432188,-22.091313 28.017236,-22.827754 27.119410,-23.574323 26.786407,-24.240691 26.485753,-24.616327 25.941652,-24.696373 25.765849,-25.174845 25.664666,-25.486816 25.025171,-25.719670 24.211267,-25.670216 23.733570,-25.390129 23.312097,-25.268690 22.824271,-25.500459 22.579532,-25.979448 22.105969,-26.280256 21.605896,-26.726534 20.889609,-26.828543 20.666470,-26.477453 20.758609,-25.868136 20.165726,-24.917962 19.895768,-24.767790 19.895458,-21.849157 20.881134,-21.814327 20.910641,-18.252219 21.655040,-18.219146 23.196858,-17.869038 23.579006,-18.281261 24.217365,-17.889347 24.520705,-17.887125 25.084443,-17.661816 25.264226,-17.736540 25.649163,-18.536026 25.850391,-18.714413 26.164791,-19.293086 27.296505,-20.391520 27.724747,-20.499059 27.727228,-20.851802 28.021370,-21.485975 28.794656,-21.639454 29.432188,-22.091313 + + + + + Botswana + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 19.895768,-24.767790 19.894734,-28.461105 19.002127,-28.972443 18.464899,-29.045462 17.836152,-28.856378 17.387497,-28.783514 17.218929,-28.355943 16.824017,-28.082162 16.344977,-28.576705 15.601818,-27.821247 15.210472,-27.090956 14.989711,-26.117372 14.743214,-25.392920 14.408144,-23.853014 14.385717,-22.656653 14.257714,-22.111208 13.868642,-21.699037 13.352498,-20.872834 12.826845,-19.673166 12.608564,-19.045349 11.794919,-18.069129 11.734199,-17.301889 12.215461,-17.111668 12.814081,-16.941343 13.462362,-16.971212 14.058501,-17.423381 14.209707,-17.353101 18.263309,-17.309951 18.956187,-17.789095 21.377176,-17.930636 23.215048,-17.523116 24.033862,-17.295843 24.682349,-17.353411 25.076950,-17.578823 25.084443,-17.661816 24.520705,-17.887125 24.217365,-17.889347 23.579006,-18.281261 23.196858,-17.869038 21.655040,-18.219146 20.910641,-18.252219 20.881134,-21.814327 19.895458,-21.849157 19.895768,-24.767790 + + + + + Namibia + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 31.191409,-22.251510 30.659865,-22.151567 30.322883,-22.271612 29.839037,-22.102216 29.432188,-22.091313 28.794656,-21.639454 28.021370,-21.485975 27.727228,-20.851802 27.724747,-20.499059 27.296505,-20.391520 26.164791,-19.293086 25.850391,-18.714413 25.649163,-18.536026 25.264226,-17.736540 26.381935,-17.846042 26.706773,-17.961229 27.044427,-17.938026 27.598243,-17.290831 28.467906,-16.468400 28.825869,-16.389749 28.947463,-16.043051 29.516834,-15.644678 30.274256,-15.507787 30.338955,-15.880839 31.173064,-15.860944 31.636498,-16.071990 31.852041,-16.319417 32.328239,-16.392074 32.847639,-16.713398 32.849861,-17.979057 32.654886,-18.672090 32.611994,-19.419383 32.772708,-19.715592 32.659743,-20.304290 32.508693,-20.395292 32.244988,-21.116489 31.191409,-22.251510 + + + + + Zimbabwe + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 30.740010,-8.340006 31.157751,-8.594579 31.556348,-8.762049 32.191865,-8.930359 32.759375,-9.230599 33.231388,-9.676722 33.485688,-10.525559 33.315310,-10.796550 33.114289,-11.607198 33.306422,-12.435778 32.991764,-12.783871 32.688165,-13.712858 33.214025,-13.971860 30.179481,-14.796099 30.274256,-15.507787 29.516834,-15.644678 28.947463,-16.043051 28.825869,-16.389749 28.467906,-16.468400 27.598243,-17.290831 27.044427,-17.938026 26.706773,-17.961229 26.381935,-17.846042 25.264226,-17.736540 25.084443,-17.661816 25.076950,-17.578823 24.682349,-17.353411 24.033862,-17.295843 23.215048,-17.523116 22.562478,-16.898451 21.887843,-16.080310 21.933886,-12.898437 24.016137,-12.911046 23.930922,-12.565848 24.079905,-12.191297 23.904154,-11.722282 24.017894,-11.237298 23.912215,-10.926826 24.257155,-10.951993 24.314516,-11.262826 24.783170,-11.238694 25.418118,-11.330936 25.752310,-11.784965 26.553088,-11.924440 27.164420,-11.608748 27.388799,-12.132747 28.155109,-12.272481 28.523562,-12.698604 28.934286,-13.248958 29.699614,-13.257227 29.616001,-12.178895 29.341548,-12.360744 28.642417,-11.971569 28.372253,-11.793647 28.496070,-10.789884 28.673682,-9.605925 28.449871,-9.164918 28.734867,-8.526559 29.002912,-8.407032 30.346086,-8.238257 30.740010,-8.340006 + + + + + Zambia + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + + + 12.995517,-4.781103 12.631612,-4.991271 12.468004,-5.248362 12.436688,-5.684304 12.182337,-5.789931 11.914963,-5.037987 12.318608,-4.606230 12.620760,-4.438023 12.995517,-4.781103 + + + + + + + + + 12.322432,-6.100092 12.735171,-5.965682 13.024869,-5.984389 13.375597,-5.864241 16.326528,-5.877470 16.573180,-6.622645 16.860191,-7.222298 17.089996,-7.545689 17.472970,-8.068551 18.134222,-7.987678 18.464176,-7.847014 19.016752,-7.988246 19.166613,-7.738184 19.417502,-7.155429 20.037723,-7.116361 20.091622,-6.943090 20.601823,-6.939318 20.514748,-7.299606 21.728111,-7.290872 21.746456,-7.920085 21.949131,-8.305901 21.801801,-8.908707 21.875182,-9.523708 22.208753,-9.894796 22.155268,-11.084801 22.402798,-10.993075 22.837345,-11.017622 23.456791,-10.867863 23.912215,-10.926826 24.017894,-11.237298 23.904154,-11.722282 24.079905,-12.191297 23.930922,-12.565848 24.016137,-12.911046 21.933886,-12.898437 21.887843,-16.080310 22.562478,-16.898451 23.215048,-17.523116 21.377176,-17.930636 18.956187,-17.789095 18.263309,-17.309951 14.209707,-17.353101 14.058501,-17.423381 13.462362,-16.971212 12.814081,-16.941343 12.215461,-17.111668 11.734199,-17.301889 11.640096,-16.673142 11.778537,-15.793816 12.123581,-14.878316 12.175619,-14.449144 12.500095,-13.547700 12.738479,-13.137906 13.312914,-12.483630 13.633721,-12.038645 13.738728,-11.297863 13.686379,-10.731076 13.387328,-10.373578 13.120988,-9.766897 12.875370,-9.166934 12.929061,-8.959091 13.236433,-8.562629 12.933040,-7.596539 12.728298,-6.927122 12.227347,-6.294448 12.322432,-6.100092 + + + + + + + Angola + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 29.339998,-4.499983 29.519987,-5.419979 29.419993,-5.939999 29.620032,-6.520015 30.199997,-7.079981 30.740015,-8.340007 30.740010,-8.340006 30.346086,-8.238257 29.002912,-8.407032 28.734867,-8.526559 28.449871,-9.164918 28.673682,-9.605925 28.496070,-10.789884 28.372253,-11.793647 28.642417,-11.971569 29.341548,-12.360744 29.616001,-12.178895 29.699614,-13.257227 28.934286,-13.248958 28.523562,-12.698604 28.155109,-12.272481 27.388799,-12.132747 27.164420,-11.608748 26.553088,-11.924440 25.752310,-11.784965 25.418118,-11.330936 24.783170,-11.238694 24.314516,-11.262826 24.257155,-10.951993 23.912215,-10.926826 23.456791,-10.867863 22.837345,-11.017622 22.402798,-10.993075 22.155268,-11.084801 22.208753,-9.894796 21.875182,-9.523708 21.801801,-8.908707 21.949131,-8.305901 21.746456,-7.920085 21.728111,-7.290872 20.514748,-7.299606 20.601823,-6.939318 20.091622,-6.943090 20.037723,-7.116361 19.417502,-7.155429 19.166613,-7.738184 19.016752,-7.988246 18.464176,-7.847014 18.134222,-7.987678 17.472970,-8.068551 17.089996,-7.545689 16.860191,-7.222298 16.573180,-6.622645 16.326528,-5.877470 13.375597,-5.864241 13.024869,-5.984389 12.735171,-5.965682 12.322432,-6.100092 12.182337,-5.789931 12.436688,-5.684304 12.468004,-5.248362 12.631612,-4.991271 12.995517,-4.781103 13.258240,-4.882957 13.600235,-4.500138 14.144956,-4.510009 14.209035,-4.793092 14.582604,-4.970239 15.170992,-4.343507 15.753540,-3.855165 16.006290,-3.535133 15.972803,-2.712392 16.407092,-1.740927 16.865307,-1.225816 17.523716,-0.743830 17.638645,-0.424832 17.663553,-0.058084 17.826540,0.288923 17.774192,0.855659 17.898835,1.741832 18.094276,2.365722 18.393792,2.900443 18.453065,3.504386 18.542982,4.201785 18.932312,4.709506 19.467784,5.031528 20.290679,4.691678 20.927591,4.322786 21.659123,4.224342 22.405124,4.029160 22.704124,4.633051 22.841480,4.710126 23.297214,4.609693 24.410531,5.108784 24.805029,4.897247 25.128833,4.927245 25.278798,5.170408 25.650455,5.256088 26.402761,5.150875 27.044065,5.127853 27.374226,5.233944 27.979977,4.408413 28.428994,4.287155 28.696678,4.455077 29.159078,4.389267 29.715995,4.600805 29.953500,4.173699 30.833852,3.509172 30.833860,3.509166 30.773347,2.339883 31.174149,2.204465 30.852670,1.849396 30.468508,1.583805 30.086154,1.062313 29.875779,0.597380 29.819503,-0.205310 29.587838,-0.587406 29.579466,-1.341313 29.291887,-1.620056 29.254835,-2.215110 29.117479,-2.292211 29.024926,-2.839258 29.276384,-3.293907 29.339998,-4.499983 + + + + + Democratic Republic of the Congo + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 30.469674,-2.413855 30.527660,-2.807620 30.743010,-3.034310 30.752240,-3.359310 30.505540,-3.568580 30.116320,-4.090120 29.753512,-4.452389 29.339998,-4.499983 29.276384,-3.293907 29.024926,-2.839258 29.632176,-2.917858 29.938359,-2.348487 30.469674,-2.413855 + + + + + Burundi + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 30.419105,-1.134659 30.816135,-1.698914 30.758309,-2.287250 30.469670,-2.413830 30.469674,-2.413855 29.938359,-2.348487 29.632176,-2.917858 29.024926,-2.839258 29.117479,-2.292211 29.254835,-2.215110 29.291887,-1.620056 29.579466,-1.341313 29.821519,-1.443322 30.419105,-1.134659 + + + + + Rwanda + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 39.202220,-4.676770 37.766900,-3.677120 37.698690,-3.096990 34.072620,-1.059820 33.903711,-0.950000 33.893569,0.109814 34.180000,0.515000 34.672100,1.176940 35.035990,1.905840 34.596070,3.053740 34.479130,3.555600 34.005000,4.249885 34.620196,4.847123 35.298007,5.506000 35.817448,5.338232 35.817448,4.776966 36.159079,4.447864 36.855093,4.447864 38.120915,3.598605 38.436970,3.588510 38.671140,3.616070 38.892510,3.500740 39.559384,3.422060 39.854940,3.838790 40.768480,4.257020 41.171800,3.919090 41.855083,3.918912 40.981050,2.784520 40.993000,-0.858290 41.585130,-1.683250 40.884770,-2.082550 40.637850,-2.499790 40.263040,-2.573090 40.121190,-3.277680 39.800060,-3.681160 39.604890,-4.346530 39.202220,-4.676770 + + + + + Kenya + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 33.903711,-0.950000 34.072620,-1.059820 37.698690,-3.096990 37.766900,-3.677120 39.202220,-4.676770 38.740540,-5.908950 38.799770,-6.475660 39.440000,-6.840000 39.470000,-7.100000 39.194690,-7.703900 39.252030,-8.007810 39.186520,-8.485510 39.535740,-9.112370 39.949600,-10.098400 40.316586,-10.317098 40.316590,-10.317100 39.521000,-10.896880 38.427557,-11.285202 37.827640,-11.268790 37.471290,-11.568760 36.775151,-11.594537 36.514082,-11.720938 35.312398,-11.439146 34.559989,-11.520020 34.280000,-10.160000 33.940838,-9.693674 33.739720,-9.417150 32.759375,-9.230599 32.191865,-8.930359 31.556348,-8.762049 31.157751,-8.594579 30.740010,-8.340006 30.740015,-8.340007 30.199997,-7.079981 29.620032,-6.520015 29.419993,-5.939999 29.519987,-5.419979 29.339998,-4.499983 29.753512,-4.452389 30.116320,-4.090120 30.505540,-3.568580 30.752240,-3.359310 30.743010,-3.034310 30.527660,-2.807620 30.469674,-2.413855 30.469670,-2.413830 30.758309,-2.287250 30.816135,-1.698914 30.419105,-1.134659 30.769860,-1.014550 31.866170,-1.027360 33.903711,-0.950000 + + + + + Tanzania + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 32.759375,-9.230599 33.739720,-9.417150 33.940838,-9.693674 34.280000,-10.160000 34.559989,-11.520020 34.280006,-12.280025 34.559989,-13.579998 34.907151,-13.565425 35.267956,-13.887834 35.686845,-14.611046 35.771905,-15.896859 35.339063,-16.107440 35.033810,-16.801300 34.381292,-16.183560 34.307291,-15.478641 34.517666,-15.013709 34.459633,-14.613010 34.064825,-14.359950 33.789700,-14.451831 33.214025,-13.971860 32.688165,-13.712858 32.991764,-12.783871 33.306422,-12.435778 33.114289,-11.607198 33.315310,-10.796550 33.485688,-10.525559 33.231388,-9.676722 32.759375,-9.230599 + + + + + Malawi + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 48.948205,11.410617 48.948205,11.410617 48.942005,11.394266 48.938491,10.982327 48.938233,9.973500 48.938130,9.451749 48.486736,8.837626 47.789420,8.003000 46.948340,7.996880 43.678750,9.183580 43.296990,9.540480 42.928120,10.021940 42.558760,10.572580 42.776852,10.926879 43.145305,11.462040 43.470660,11.277710 43.666668,10.864169 44.117804,10.445538 44.614259,10.442205 45.556941,10.698029 46.645401,10.816549 47.525658,11.127228 48.021596,11.193064 48.378784,11.375482 48.948206,11.410622 48.948205,11.410617 + + + + + Somaliland + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 41.585130,-1.683250 40.993000,-0.858290 40.981050,2.784520 41.855083,3.918912 42.128610,4.234130 42.769670,4.252590 43.660870,4.957550 44.963600,5.001620 47.789420,8.003000 48.486736,8.837626 48.938130,9.451749 48.938233,9.973500 48.938491,10.982327 48.942005,11.394266 48.948205,11.410617 48.948205,11.410617 49.267760,11.430330 49.728620,11.578900 50.258780,11.679570 50.732020,12.021900 51.111200,12.024640 51.133870,11.748150 51.041530,11.166510 51.045310,10.640900 50.834180,10.279720 50.552390,9.198740 50.070920,8.081730 49.452700,6.804660 48.594550,5.339110 47.740790,4.219400 46.564760,2.855290 45.563990,2.045760 44.068150,1.052830 43.135970,0.292200 42.041570,-0.919160 41.810950,-1.446470 41.585130,-1.683250 + + + + + Somalia + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 47.789420,8.003000 44.963600,5.001620 43.660870,4.957550 42.769670,4.252590 42.128610,4.234130 41.855083,3.918912 41.171800,3.919090 40.768480,4.257020 39.854940,3.838790 39.559384,3.422060 38.892510,3.500740 38.671140,3.616070 38.436970,3.588510 38.120915,3.598605 36.855093,4.447864 36.159079,4.447864 35.817448,4.776966 35.817448,5.338232 35.298007,5.506000 34.707020,6.594220 34.250320,6.826070 34.075100,7.225950 33.568290,7.713340 32.954180,7.784970 33.294800,8.354580 33.825500,8.379160 33.974980,8.684560 33.961620,9.583580 34.257450,10.630090 34.731150,10.910170 34.831630,11.318960 35.260490,12.082860 35.863630,12.578280 36.270220,13.563330 36.429510,14.422110 37.593770,14.213100 37.906070,14.959430 38.512950,14.505470 39.099400,14.740640 39.340610,14.531550 40.026250,14.519590 40.896600,14.118640 41.155200,13.773330 41.598560,13.452090 42.009750,12.865820 42.351560,12.542230 42.000000,12.100000 41.661760,11.631200 41.739590,11.355110 41.755570,11.050910 42.314140,11.034200 42.554930,11.105110 42.776852,10.926879 42.558760,10.572580 42.928120,10.021940 43.296990,9.540480 43.678750,9.183580 46.948340,7.996880 47.789420,8.003000 + + + + + Ethiopia + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 42.351560,12.542230 42.779642,12.455416 43.081226,12.699639 43.317852,12.390148 43.286381,11.974928 42.715874,11.735641 43.145305,11.462040 42.776852,10.926879 42.554930,11.105110 42.314140,11.034200 41.755570,11.050910 41.739590,11.355110 41.661760,11.631200 42.000000,12.100000 42.351560,12.542230 + + + + + Djibouti + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 36.429510,14.422110 36.323220,14.822490 36.753890,16.291860 36.852530,16.956550 37.167470,17.263140 37.904000,17.427540 38.410090,17.998307 38.990623,16.840626 39.266110,15.922723 39.814294,15.435647 41.179275,14.491080 41.734952,13.921037 42.276831,13.343992 42.589576,13.000421 43.081226,12.699639 42.779642,12.455416 42.351560,12.542230 42.009750,12.865820 41.598560,13.452090 41.155200,13.773330 40.896600,14.118640 40.026250,14.519590 39.340610,14.531550 39.099400,14.740640 38.512950,14.505470 37.906070,14.959430 37.593770,14.213100 36.429510,14.422110 + + + + + Eritrea + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 36.866230,22.000000 32.900000,22.000000 29.020000,22.000000 25.000000,22.000000 25.000000,25.682500 25.000000,29.238655 24.700070,30.044190 24.957620,30.661600 24.802870,31.089290 25.164820,31.569150 26.495330,31.585680 27.457620,31.321260 28.450480,31.025770 28.913530,30.870050 29.683420,31.186860 30.095030,31.473400 30.976930,31.555860 31.687960,31.429600 31.960410,30.933600 32.192470,31.260340 32.993920,31.024070 33.773400,30.967460 34.265435,31.219357 34.265440,31.219360 34.823243,29.761081 34.922600,29.501330 34.641740,29.099420 34.426550,28.343990 34.154510,27.823300 33.921360,27.648700 33.588110,27.971360 33.136760,28.417650 32.423230,29.851080 32.320460,29.760430 32.734820,28.705230 33.348760,27.699890 34.104550,26.142270 34.473870,25.598560 34.795070,25.033750 35.692410,23.926710 35.493720,23.752370 35.525980,23.102440 36.690690,22.204850 36.866230,22.000000 + + + + + Egypt + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 25.000000,22.000000 25.000000,20.003040 23.850000,20.000000 23.837660,19.580470 19.849260,21.495090 15.860850,23.409720 14.851300,22.862950 14.143871,22.491289 13.581425,23.040506 11.999506,23.471668 11.560669,24.097909 10.771364,24.562532 10.303847,24.379313 9.948261,24.936954 9.910693,25.365455 9.319411,26.094325 9.716286,26.512206 9.629056,27.140953 9.756128,27.688259 9.683885,28.144174 9.859998,28.959990 9.805634,29.424638 9.482140,30.307556 9.970017,30.539325 10.056575,30.961831 9.950225,31.376070 10.636901,31.761421 10.944790,32.081815 11.432253,32.368903 11.488787,33.136996 12.663310,32.792780 13.083260,32.878820 13.918680,32.711960 15.245630,32.265080 15.713940,31.376260 16.611620,31.182180 18.021090,30.763570 19.086410,30.266390 19.574040,30.525820 20.053350,30.985760 19.820330,31.751790 20.133970,32.238200 20.854520,32.706800 21.542980,32.843200 22.895760,32.638580 23.236800,32.191490 23.609130,32.187260 23.927500,32.016670 24.921140,31.899360 25.164820,31.569150 24.802870,31.089290 24.957620,30.661600 24.700070,30.044190 25.000000,29.238655 25.000000,25.682500 25.000000,22.000000 + + + + + Libya + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 23.837660,19.580470 23.886890,15.610840 23.024590,15.680720 22.567950,14.944290 22.303510,14.326820 22.512020,14.093180 22.183290,13.786480 22.296580,13.372320 22.037590,12.955460 21.936810,12.588180 22.288010,12.646050 22.497620,12.260240 22.508690,11.679360 22.876220,11.384610 22.864165,11.142395 22.231129,10.971889 21.723822,10.567056 21.000868,9.475985 20.059685,9.012706 19.094008,9.074847 18.812010,8.982915 18.911022,8.630895 18.389555,8.281304 17.964930,7.890914 16.705988,7.508328 16.456185,7.734774 16.290562,7.754307 16.106232,7.497088 15.279460,7.421925 15.436092,7.692812 15.120866,8.382150 14.979996,8.796104 14.544467,8.965861 13.954218,9.549495 14.171466,10.021378 14.627201,9.920919 14.909354,9.992129 15.467873,9.982337 14.923565,10.891325 14.960152,11.555574 14.893360,12.219050 14.495787,12.859396 14.595781,13.330427 13.954477,13.353449 13.956699,13.996691 13.540394,14.367134 13.972170,15.684370 15.247731,16.627306 15.300441,17.927950 15.685741,19.957180 15.903247,20.387619 15.487148,20.730415 15.471060,21.048450 15.096888,21.308519 14.851300,22.862950 15.860850,23.409720 19.849260,21.495090 23.837660,19.580470 + + + + + Chad + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 24.567369,8.229188 23.805813,8.666319 23.459013,8.954286 23.394779,9.265068 23.557250,9.681218 23.554304,10.089255 22.977544,10.714463 22.864165,11.142395 22.876220,11.384610 22.508690,11.679360 22.497620,12.260240 22.288010,12.646050 21.936810,12.588180 22.037590,12.955460 22.296580,13.372320 22.183290,13.786480 22.512020,14.093180 22.303510,14.326820 22.567950,14.944290 23.024590,15.680720 23.886890,15.610840 23.837660,19.580470 23.850000,20.000000 25.000000,20.003040 25.000000,22.000000 29.020000,22.000000 32.900000,22.000000 36.866230,22.000000 37.188720,21.018850 36.969410,20.837440 37.114700,19.807960 37.481790,18.614090 37.862760,18.367860 38.410090,17.998307 37.904000,17.427540 37.167470,17.263140 36.852530,16.956550 36.753890,16.291860 36.323220,14.822490 36.429510,14.422110 36.270220,13.563330 35.863630,12.578280 35.260490,12.082860 34.831630,11.318960 34.731150,10.910170 34.257450,10.630090 33.961620,9.583580 33.974980,8.684560 33.963393,9.464285 33.824963,9.484061 33.842131,9.981915 33.721959,10.325262 33.206938,10.720112 33.086766,11.441141 33.206938,12.179338 32.743419,12.248008 32.674750,12.024832 32.073892,11.973330 32.314235,11.681484 32.400072,11.080626 31.850716,10.531271 31.352862,9.810241 30.837841,9.707237 29.996639,10.290927 29.618957,10.084919 29.515953,9.793074 29.000932,9.604232 28.966597,9.398224 27.970890,9.398224 27.833551,9.604232 27.112521,9.638567 26.752006,9.466893 26.477328,9.552730 25.962307,10.136421 25.790633,10.411099 25.069604,10.273760 24.794926,9.810241 24.537415,8.917538 24.194068,8.728696 23.886980,8.619730 24.567369,8.229188 + + + + + Sudan + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 30.833852,3.509172 29.953500,4.173699 29.715995,4.600805 29.159078,4.389267 28.696678,4.455077 28.428994,4.287155 27.979977,4.408413 27.374226,5.233944 27.213409,5.550953 26.465909,5.946717 26.213418,6.546603 25.796648,6.979316 25.124131,7.500085 25.114932,7.825104 24.567369,8.229188 23.886980,8.619730 24.194068,8.728696 24.537415,8.917538 24.794926,9.810241 25.069604,10.273760 25.790633,10.411099 25.962307,10.136421 26.477328,9.552730 26.752006,9.466893 27.112521,9.638567 27.833551,9.604232 27.970890,9.398224 28.966597,9.398224 29.000932,9.604232 29.515953,9.793074 29.618957,10.084919 29.996639,10.290927 30.837841,9.707237 31.352862,9.810241 31.850716,10.531271 32.400072,11.080626 32.314235,11.681484 32.073892,11.973330 32.674750,12.024832 32.743419,12.248008 33.206938,12.179338 33.086766,11.441141 33.206938,10.720112 33.721959,10.325262 33.842131,9.981915 33.824963,9.484061 33.963393,9.464285 33.974980,8.684560 33.825500,8.379160 33.294800,8.354580 32.954180,7.784970 33.568290,7.713340 34.075100,7.225950 34.250320,6.826070 34.707020,6.594220 35.298007,5.506000 34.620196,4.847123 34.005000,4.249885 33.390000,3.790000 32.686420,3.792320 31.881450,3.558270 31.245560,3.781900 30.833852,3.509172 + + + + + South Sudan + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 33.903711,-0.950000 31.866170,-1.027360 30.769860,-1.014550 30.419105,-1.134659 29.821519,-1.443322 29.579466,-1.341313 29.587838,-0.587406 29.819503,-0.205310 29.875779,0.597380 30.086154,1.062313 30.468508,1.583805 30.852670,1.849396 31.174149,2.204465 30.773347,2.339883 30.833860,3.509166 30.833852,3.509172 31.245560,3.781900 31.881450,3.558270 32.686420,3.792320 33.390000,3.790000 34.005000,4.249885 34.479130,3.555600 34.596070,3.053740 35.035990,1.905840 34.672100,1.176940 34.180000,0.515000 33.893569,0.109814 33.903711,-0.950000 + + + + + Uganda + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 27.374226,5.233944 27.044065,5.127853 26.402761,5.150875 25.650455,5.256088 25.278798,5.170408 25.128833,4.927245 24.805029,4.897247 24.410531,5.108784 23.297214,4.609693 22.841480,4.710126 22.704124,4.633051 22.405124,4.029160 21.659123,4.224342 20.927591,4.322786 20.290679,4.691678 19.467784,5.031528 18.932312,4.709506 18.542982,4.201785 18.453065,3.504386 17.809900,3.560196 17.133042,3.728197 16.537058,3.198255 16.012852,2.267640 15.907381,2.557389 15.862732,3.013537 15.405396,3.335301 15.036220,3.851367 14.950953,4.210389 14.478372,4.732605 14.558936,5.030598 14.459407,5.451761 14.536560,6.226959 14.776545,6.408498 15.279460,7.421925 16.106232,7.497088 16.290562,7.754307 16.456185,7.734774 16.705988,7.508328 17.964930,7.890914 18.389555,8.281304 18.911022,8.630895 18.812010,8.982915 19.094008,9.074847 20.059685,9.012706 21.000868,9.475985 21.723822,10.567056 22.231129,10.971889 22.864165,11.142395 22.977544,10.714463 23.554304,10.089255 23.557250,9.681218 23.394779,9.265068 23.459013,8.954286 23.805813,8.666319 24.567369,8.229188 25.114932,7.825104 25.124131,7.500085 25.796648,6.979316 26.213418,6.546603 26.465909,5.946717 27.213409,5.550953 27.374226,5.233944 + + + + + Central African Republic + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 14.495787,12.859396 14.893360,12.219050 14.960152,11.555574 14.923565,10.891325 15.467873,9.982337 14.909354,9.992129 14.627201,9.920919 14.171466,10.021378 13.954218,9.549495 14.544467,8.965861 14.979996,8.796104 15.120866,8.382150 15.436092,7.692812 15.279460,7.421925 14.776545,6.408498 14.536560,6.226959 14.459407,5.451761 14.558936,5.030598 14.478372,4.732605 14.950953,4.210389 15.036220,3.851367 15.405396,3.335301 15.862732,3.013537 15.907381,2.557389 16.012852,2.267640 15.940919,1.727673 15.146342,1.964015 14.337813,2.227875 13.075822,2.267097 12.951334,2.321616 12.359380,2.192812 11.751665,2.326758 11.276449,2.261051 9.649158,2.283866 9.795196,3.073404 9.404367,3.734527 8.948116,3.904129 8.744924,4.352215 8.488816,4.495617 8.500288,4.771983 8.757533,5.479666 9.233163,6.444491 9.522706,6.453482 10.118277,7.038770 10.497375,7.055358 11.058788,6.644427 11.745774,6.981383 11.839309,7.397042 12.063946,7.799808 12.218872,8.305824 12.753672,8.717763 12.955468,9.417772 13.167600,9.640626 13.308676,10.160362 13.572950,10.798566 14.415379,11.572369 14.468192,11.904752 14.577178,12.085361 14.181336,12.483657 14.213531,12.802035 14.495787,12.859396 + + + + + Cameroon + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 2.691702,6.258817 2.749063,7.870734 2.723793,8.506845 2.912308,9.137608 3.220352,9.444153 3.705438,10.063210 3.600070,10.332186 3.797112,10.734746 3.572216,11.327939 3.611180,11.660167 3.680634,12.552903 3.967283,12.956109 4.107946,13.531216 4.368344,13.747482 5.443058,13.865924 6.445426,13.492768 6.820442,13.115091 7.330747,13.098038 7.804671,13.343527 9.014933,12.826659 9.524928,12.851102 10.114814,13.277252 10.701032,13.246918 10.989593,13.387323 11.527803,13.328980 12.302071,13.037189 13.083987,13.596147 13.318702,13.556356 13.995353,12.461565 14.181336,12.483657 14.577178,12.085361 14.468192,11.904752 14.415379,11.572369 13.572950,10.798566 13.308676,10.160362 13.167600,9.640626 12.955468,9.417772 12.753672,8.717763 12.218872,8.305824 12.063946,7.799808 11.839309,7.397042 11.745774,6.981383 11.058788,6.644427 10.497375,7.055358 10.118277,7.038770 9.522706,6.453482 9.233163,6.444491 8.757533,5.479666 8.500288,4.771983 7.462108,4.412108 7.082596,4.464689 6.698072,4.240594 5.898173,4.262453 5.362805,4.887971 5.033574,5.611802 4.325607,6.270651 3.574180,6.258300 2.691702,6.258817 + + + + + Nigeria + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 9.649158,2.283866 11.276449,2.261051 11.285079,1.057662 9.830284,1.067894 9.492889,1.010120 9.305613,1.160911 9.649158,2.283866 + + + + + Equatorial Guinea + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 0.899563,10.997339 0.772336,10.470808 1.077795,10.175607 1.425061,9.825395 1.463043,9.334624 1.664478,9.128590 1.618951,6.832038 1.865241,6.142158 1.060122,5.928837 0.836931,6.279979 0.570384,6.914359 0.490957,7.411744 0.712029,8.312465 0.461192,8.677223 0.365901,9.465004 0.367580,10.191213 -0.049785,10.706918 0.023803,11.018682 0.899563,10.997339 + + + + + Togo + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 2.691702,6.258817 1.865241,6.142158 1.618951,6.832038 1.664478,9.128590 1.463043,9.334624 1.425061,9.825395 1.077795,10.175607 0.772336,10.470808 0.899563,10.997339 1.243470,11.110511 1.447178,11.547719 1.935986,11.641150 2.154474,11.940150 2.490164,12.233052 2.848643,12.235636 3.611180,11.660167 3.572216,11.327939 3.797112,10.734746 3.600070,10.332186 3.705438,10.063210 3.220352,9.444153 2.912308,9.137608 2.723793,8.506845 2.749063,7.870734 2.691702,6.258817 + + + + + Benin + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 14.851300,22.862950 15.096888,21.308519 15.471060,21.048450 15.487148,20.730415 15.903247,20.387619 15.685741,19.957180 15.300441,17.927950 15.247731,16.627306 13.972170,15.684370 13.540394,14.367134 13.956699,13.996691 13.954477,13.353449 14.595781,13.330427 14.495787,12.859396 14.213531,12.802035 14.181336,12.483657 13.995353,12.461565 13.318702,13.556356 13.083987,13.596147 12.302071,13.037189 11.527803,13.328980 10.989593,13.387323 10.701032,13.246918 10.114814,13.277252 9.524928,12.851102 9.014933,12.826659 7.804671,13.343527 7.330747,13.098038 6.820442,13.115091 6.445426,13.492768 5.443058,13.865924 4.368344,13.747482 4.107946,13.531216 3.967283,12.956109 3.680634,12.552903 3.611180,11.660167 2.848643,12.235636 2.490164,12.233052 2.154474,11.940150 2.177108,12.625018 1.024103,12.851826 0.993046,13.335750 0.429928,13.988733 0.295646,14.444235 0.374892,14.928908 1.015783,14.968182 1.385528,15.323561 2.749993,15.409525 3.638259,15.568120 3.723422,16.184284 4.270210,16.852227 4.267419,19.155265 5.677566,19.601207 8.572893,21.565661 11.999506,23.471668 13.581425,23.040506 14.143871,22.491289 14.851300,22.862950 + + + + + Niger + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 9.482140,30.307556 9.055603,32.102692 8.439103,32.506285 8.430473,32.748337 7.612642,33.344115 7.524482,34.097376 8.140981,34.655146 8.376368,35.479876 8.217824,36.433177 8.420964,36.946427 9.509994,37.349994 10.210002,37.230002 10.180650,36.724038 11.028867,37.092103 11.100026,36.899996 10.600005,36.410000 10.593287,35.947444 10.939519,35.698984 10.807847,34.833507 10.149593,34.330773 10.339659,33.785742 10.856836,33.768740 11.108501,33.293343 11.488787,33.136996 11.432253,32.368903 10.944790,32.081815 10.636901,31.761421 9.950225,31.376070 10.056575,30.961831 9.970017,30.539325 9.482140,30.307556 + + + + + Tunisia + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + -8.684400,27.395744 -8.665124,27.589479 -8.665590,27.656426 -8.674116,28.841289 -7.059228,29.579228 -6.060632,29.731700 -5.242129,30.000443 -4.859646,30.501188 -3.690441,30.896952 -3.647498,31.637294 -3.068980,31.724498 -2.616605,32.094346 -1.307899,32.262889 -1.124551,32.651522 -1.388049,32.864015 -1.733455,33.919713 -1.792986,34.527919 -2.169914,35.168396 -1.208603,35.714849 -0.127454,35.888662 0.503877,36.301273 1.466919,36.605647 3.161699,36.783905 4.815758,36.865037 5.320120,36.716519 6.261820,37.110655 7.330385,37.118381 7.737078,36.885708 8.420964,36.946427 8.217824,36.433177 8.376368,35.479876 8.140981,34.655146 7.524482,34.097376 7.612642,33.344115 8.430473,32.748337 8.439103,32.506285 9.055603,32.102692 9.482140,30.307556 9.805634,29.424638 9.859998,28.959990 9.683885,28.144174 9.756128,27.688259 9.629056,27.140953 9.716286,26.512206 9.319411,26.094325 9.910693,25.365455 9.948261,24.936954 10.303847,24.379313 10.771364,24.562532 11.560669,24.097909 11.999506,23.471668 8.572893,21.565661 5.677566,19.601207 4.267419,19.155265 3.158133,19.057364 3.146661,19.693579 2.683588,19.856230 2.060991,20.142233 1.823228,20.610809 -1.550055,22.792666 -4.923337,24.974574 -8.684400,27.395744 + + + + + Algeria + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + -2.169914,35.168396 -1.792986,34.527919 -1.733455,33.919713 -1.388049,32.864015 -1.124551,32.651522 -1.307899,32.262889 -2.616605,32.094346 -3.068980,31.724498 -3.647498,31.637294 -3.690441,30.896952 -4.859646,30.501188 -5.242129,30.000443 -6.060632,29.731700 -7.059228,29.579228 -8.674116,28.841289 -8.665590,27.656426 -8.817828,27.656426 -8.794884,27.120696 -9.413037,27.088476 -9.735343,26.860945 -10.189424,26.860945 -10.551263,26.990808 -11.392555,26.883424 -11.718220,26.104092 -12.030759,26.030866 -12.500963,24.770116 -13.891110,23.691009 -14.221168,22.310163 -14.630833,21.860940 -14.750955,21.500600 -17.002962,21.420734 -17.020428,21.422310 -16.973248,21.885745 -16.589137,22.158234 -16.261922,22.679340 -16.326414,23.017768 -15.982611,23.723358 -15.426004,24.359134 -15.089332,24.520261 -14.824645,25.103533 -14.800926,25.636265 -14.439940,26.254418 -13.773805,26.618892 -13.139942,27.640148 -13.121613,27.654148 -12.618837,28.038186 -11.688919,28.148644 -10.900957,28.832142 -10.399592,29.098586 -9.564811,29.933574 -9.814718,31.177736 -9.434793,32.038096 -9.300693,32.564679 -8.657476,33.240245 -7.654178,33.697065 -6.912544,34.110476 -6.244342,35.145865 -5.929994,35.759988 -5.193863,35.755182 -4.591006,35.330712 -3.640057,35.399855 -2.604306,35.179093 -2.169914,35.168396 + + + + + Morocco + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + -8.665590,27.656426 -8.665124,27.589479 -8.684400,27.395744 -8.687294,25.881056 -11.969419,25.933353 -11.937224,23.374594 -12.874222,23.284832 -13.118754,22.771220 -12.929102,21.327071 -16.845194,21.333323 -17.063423,20.999752 -17.020428,21.422310 -17.002962,21.420734 -14.750955,21.500600 -14.630833,21.860940 -14.221168,22.310163 -13.891110,23.691009 -12.500963,24.770116 -12.030759,26.030866 -11.718220,26.104092 -11.392555,26.883424 -10.551263,26.990808 -10.189424,26.860945 -9.735343,26.860945 -9.413037,27.088476 -8.794884,27.120696 -8.817828,27.656426 -8.665590,27.656426 + + + + + Western Sahara + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + -17.063423,20.999752 -16.845194,21.333323 -12.929102,21.327071 -13.118754,22.771220 -12.874222,23.284832 -11.937224,23.374594 -11.969419,25.933353 -8.687294,25.881056 -8.684400,27.395744 -4.923337,24.974574 -6.453787,24.956591 -5.971129,20.640833 -5.488523,16.325102 -5.315277,16.201854 -5.537744,15.501690 -9.550238,15.486497 -9.700255,15.264107 -10.086846,15.330486 -10.650791,15.132746 -11.349095,15.411256 -11.666078,15.388208 -11.834208,14.799097 -12.170750,14.616834 -12.830658,15.303692 -13.435738,16.039383 -14.099521,16.304302 -14.577348,16.598264 -15.135737,16.587282 -15.623666,16.369337 -16.120690,16.455663 -16.463098,16.135036 -16.549708,16.673892 -16.270552,17.166963 -16.146347,18.108482 -16.256883,19.096716 -16.377651,19.593817 -16.277838,20.092521 -16.536324,20.567866 -17.063423,20.999752 + + + + + Mauritania + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + -16.677452,12.384852 -16.147717,12.547762 -15.816574,12.515567 -15.548477,12.628170 -13.700476,12.586183 -13.718744,12.247186 -13.828272,12.142644 -13.743161,11.811269 -13.900800,11.678719 -14.121406,11.677117 -14.382192,11.509272 -14.685687,11.527824 -15.130311,11.040412 -15.664180,11.458474 -16.085214,11.524594 -16.314787,11.806515 -16.308947,11.958702 -16.613838,12.170911 -16.677452,12.384852 + + + + + Guinea-Bissau + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + -16.713729,13.594959 -15.624596,13.623587 -15.398770,13.860369 -15.081735,13.876492 -14.687031,13.630357 -14.376714,13.625680 -14.046992,13.794068 -13.844963,13.505042 -14.277702,13.280585 -14.712197,13.298207 -15.141163,13.509512 -15.511813,13.278570 -15.691001,13.270353 -15.931296,13.130284 -16.841525,13.151394 -16.713729,13.594959 + + + + + The Gambia + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + -16.713729,13.594959 -17.126107,14.373516 -17.625043,14.729541 -17.185173,14.919477 -16.700706,15.621527 -16.463098,16.135036 -16.120690,16.455663 -15.623666,16.369337 -15.135737,16.587282 -14.577348,16.598264 -14.099521,16.304302 -13.435738,16.039383 -12.830658,15.303692 -12.170750,14.616834 -12.124887,13.994727 -11.927716,13.422075 -11.553398,13.141214 -11.467899,12.754519 -11.513943,12.442988 -11.658301,12.386583 -12.203565,12.465648 -12.278599,12.354440 -12.499051,12.332090 -13.217818,12.575874 -13.700476,12.586183 -15.548477,12.628170 -15.816574,12.515567 -16.147717,12.547762 -16.677452,12.384852 -16.841525,13.151394 -15.931296,13.130284 -15.691001,13.270353 -15.511813,13.278570 -15.141163,13.509512 -14.712197,13.298207 -14.277702,13.280585 -13.844963,13.505042 -14.046992,13.794068 -14.376714,13.625680 -14.687031,13.630357 -15.081735,13.876492 -15.398770,13.860369 -15.624596,13.623587 -16.713729,13.594959 + + + + + Senegal + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + -11.513943,12.442988 -11.467899,12.754519 -11.553398,13.141214 -11.927716,13.422075 -12.124887,13.994727 -12.170750,14.616834 -11.834208,14.799097 -11.666078,15.388208 -11.349095,15.411256 -10.650791,15.132746 -10.086846,15.330486 -9.700255,15.264107 -9.550238,15.486497 -5.537744,15.501690 -5.315277,16.201854 -5.488523,16.325102 -5.971129,20.640833 -6.453787,24.956591 -4.923337,24.974574 -1.550055,22.792666 1.823228,20.610809 2.060991,20.142233 2.683588,19.856230 3.146661,19.693579 3.158133,19.057364 4.267419,19.155265 4.270210,16.852227 3.723422,16.184284 3.638259,15.568120 2.749993,15.409525 1.385528,15.323561 1.015783,14.968182 0.374892,14.928908 -0.266257,14.924309 -0.515854,15.116158 -1.066363,14.973815 -2.001035,14.559008 -2.191825,14.246418 -2.967694,13.798150 -3.103707,13.541267 -3.522803,13.337662 -4.006391,13.472485 -4.280405,13.228444 -4.427166,12.542646 -5.220942,11.713859 -5.197843,11.375146 -5.470565,10.951270 -5.404342,10.370737 -5.816926,10.222555 -6.050452,10.096361 -6.205223,10.524061 -6.493965,10.411303 -6.666461,10.430811 -6.850507,10.138994 -7.622759,10.147236 -7.899590,10.297382 -8.029944,10.206535 -8.335377,10.494812 -8.282357,10.792597 -8.407311,10.909257 -8.620321,10.810891 -8.581305,11.136246 -8.376305,11.393646 -8.786099,11.812561 -8.905265,12.088358 -9.127474,12.308060 -9.327616,12.334286 -9.567912,12.194243 -9.890993,12.060479 -10.165214,11.844084 -10.593224,11.923975 -10.870830,12.177887 -11.036556,12.211245 -11.297574,12.077971 -11.456169,12.076834 -11.513943,12.442988 + + + + + Mali + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + -5.404342,10.370737 -5.470565,10.951270 -5.197843,11.375146 -5.220942,11.713859 -4.427166,12.542646 -4.280405,13.228444 -4.006391,13.472485 -3.522803,13.337662 -3.103707,13.541267 -2.967694,13.798150 -2.191825,14.246418 -2.001035,14.559008 -1.066363,14.973815 -0.515854,15.116158 -0.266257,14.924309 0.374892,14.928908 0.295646,14.444235 0.429928,13.988733 0.993046,13.335750 1.024103,12.851826 2.177108,12.625018 2.154474,11.940150 1.935986,11.641150 1.447178,11.547719 1.243470,11.110511 0.899563,10.997339 0.023803,11.018682 -0.438702,11.098341 -0.761576,10.936930 -1.203358,11.009819 -2.940409,10.962690 -2.963896,10.395335 -2.827496,9.642461 -3.511899,9.900326 -3.980449,9.862344 -4.330247,9.610835 -4.779884,9.821985 -4.954653,10.152714 -5.404342,10.370737 + + + + + Burkina Faso + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + -8.029944,10.206535 -7.899590,10.297382 -7.622759,10.147236 -6.850507,10.138994 -6.666461,10.430811 -6.493965,10.411303 -6.205223,10.524061 -6.050452,10.096361 -5.816926,10.222555 -5.404342,10.370737 -4.954653,10.152714 -4.779884,9.821985 -4.330247,9.610835 -3.980449,9.862344 -3.511899,9.900326 -2.827496,9.642461 -2.562190,8.219628 -2.983585,7.379705 -3.244370,6.250472 -2.810701,5.389051 -2.856125,4.994476 -3.311084,4.984296 -4.008820,5.179813 -4.649917,5.168264 -5.834496,4.993701 -6.528769,4.705088 -7.518941,4.338288 -7.712159,4.364566 -7.635368,5.188159 -7.539715,5.313345 -7.570153,5.707352 -7.993693,6.126190 -8.311348,6.193033 -8.602880,6.467564 -8.385452,6.911801 -8.485446,7.395208 -8.439298,7.686043 -8.280703,7.687180 -8.221792,8.123329 -8.299049,8.316444 -8.203499,8.455453 -7.832100,8.575704 -8.079114,9.376224 -8.309616,9.789532 -8.229337,10.129020 -8.029944,10.206535 + + + + + Ivory Coast + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 0.023803,11.018682 -0.049785,10.706918 0.367580,10.191213 0.365901,9.465004 0.461192,8.677223 0.712029,8.312465 0.490957,7.411744 0.570384,6.914359 0.836931,6.279979 1.060122,5.928837 -0.507638,5.343473 -1.063625,5.000548 -1.964707,4.710462 -2.856125,4.994476 -2.810701,5.389051 -3.244370,6.250472 -2.983585,7.379705 -2.562190,8.219628 -2.827496,9.642461 -2.963896,10.395335 -2.940409,10.962690 -1.203358,11.009819 -0.761576,10.936930 -0.438702,11.098341 0.023803,11.018682 + + + + + Ghana + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + -8.439298,7.686043 -8.485446,7.395208 -8.385452,6.911801 -8.602880,6.467564 -8.311348,6.193033 -7.993693,6.126190 -7.570153,5.707352 -7.539715,5.313345 -7.635368,5.188159 -7.712159,4.364566 -7.974107,4.355755 -9.004794,4.832419 -9.913420,5.593561 -10.765384,6.140711 -11.438779,6.785917 -11.199802,7.105846 -11.146704,7.396706 -10.695595,7.939464 -10.230094,8.406206 -10.016567,8.428504 -9.755342,8.541055 -9.337280,7.928534 -9.403348,7.526905 -9.208786,7.313921 -8.926065,7.309037 -8.722124,7.711674 -8.439298,7.686043 + + + + + Liberia + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + -13.246550,8.903049 -12.711958,9.342712 -12.596719,9.620188 -12.425929,9.835834 -12.150338,9.858572 -11.917277,10.046984 -11.117481,10.045873 -10.839152,9.688246 -10.622395,9.267910 -10.654770,8.977178 -10.494315,8.715541 -10.505477,8.348896 -10.230094,8.406206 -10.695595,7.939464 -11.146704,7.396706 -11.199802,7.105846 -11.438779,6.785917 -11.708195,6.860098 -12.428099,7.262942 -12.949049,7.798646 -13.124025,8.163946 -13.246550,8.903049 + + + + + Sierra Leone + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + -13.700476,12.586183 -13.217818,12.575874 -12.499051,12.332090 -12.278599,12.354440 -12.203565,12.465648 -11.658301,12.386583 -11.513943,12.442988 -11.456169,12.076834 -11.297574,12.077971 -11.036556,12.211245 -10.870830,12.177887 -10.593224,11.923975 -10.165214,11.844084 -9.890993,12.060479 -9.567912,12.194243 -9.327616,12.334286 -9.127474,12.308060 -8.905265,12.088358 -8.786099,11.812561 -8.376305,11.393646 -8.581305,11.136246 -8.620321,10.810891 -8.407311,10.909257 -8.282357,10.792597 -8.335377,10.494812 -8.029944,10.206535 -8.229337,10.129020 -8.309616,9.789532 -8.079114,9.376224 -7.832100,8.575704 -8.203499,8.455453 -8.299049,8.316444 -8.221792,8.123329 -8.280703,7.687180 -8.439298,7.686043 -8.722124,7.711674 -8.926065,7.309037 -9.208786,7.313921 -9.403348,7.526905 -9.337280,7.928534 -9.755342,8.541055 -10.016567,8.428504 -10.230094,8.406206 -10.505477,8.348896 -10.494315,8.715541 -10.654770,8.977178 -10.622395,9.267910 -10.839152,9.688246 -11.117481,10.045873 -11.917277,10.046984 -12.150338,9.858572 -12.425929,9.835834 -12.596719,9.620188 -12.711958,9.342712 -13.246550,8.903049 -13.685154,9.494744 -14.074045,9.886167 -14.330076,10.015720 -14.579699,10.214467 -14.693232,10.656301 -14.839554,10.876572 -15.130311,11.040412 -14.685687,11.527824 -14.382192,11.509272 -14.121406,11.677117 -13.900800,11.678719 -13.743161,11.811269 -13.828272,12.142644 -13.718744,12.247186 -13.700476,12.586183 + + + + + Guinea + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 11.276449,2.261051 11.751665,2.326758 12.359380,2.192812 12.951334,2.321616 13.075822,2.267097 13.003114,1.830896 13.282631,1.314184 14.026669,1.395677 14.276266,1.196930 13.843321,0.038758 14.316418,-0.552627 14.425456,-1.333407 14.299210,-1.998276 13.992407,-2.470805 13.109619,-2.428740 12.575284,-1.948511 12.495703,-2.391688 11.820964,-2.514161 11.478039,-2.765619 11.855122,-3.426871 11.093773,-3.978827 10.066135,-2.969483 9.405245,-2.144313 8.797996,-1.111301 8.830087,-0.779074 9.048420,-0.459351 9.291351,0.268666 9.492889,1.010120 9.830284,1.067894 11.285079,1.057662 11.276449,2.261051 + + + + + Gabon + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 18.453065,3.504386 18.393792,2.900443 18.094276,2.365722 17.898835,1.741832 17.774192,0.855659 17.826540,0.288923 17.663553,-0.058084 17.638645,-0.424832 17.523716,-0.743830 16.865307,-1.225816 16.407092,-1.740927 15.972803,-2.712392 16.006290,-3.535133 15.753540,-3.855165 15.170992,-4.343507 14.582604,-4.970239 14.209035,-4.793092 14.144956,-4.510009 13.600235,-4.500138 13.258240,-4.882957 12.995517,-4.781103 12.620760,-4.438023 12.318608,-4.606230 11.914963,-5.037987 11.093773,-3.978827 11.855122,-3.426871 11.478039,-2.765619 11.820964,-2.514161 12.495703,-2.391688 12.575284,-1.948511 13.109619,-2.428740 13.992407,-2.470805 14.299210,-1.998276 14.425456,-1.333407 14.316418,-0.552627 13.843321,0.038758 14.276266,1.196930 14.026669,1.395677 13.282631,1.314184 13.003114,1.830896 13.075822,2.267097 14.337813,2.227875 15.146342,1.964015 15.940919,1.727673 16.012852,2.267640 16.537058,3.198255 17.133042,3.728197 17.809900,3.560196 18.453065,3.504386 + + + + + Republic of the Congo + + + + diff --git a/msautotest/misc/expected/flatgeobuf-wfs-get-feature-propertyname.xml b/msautotest/misc/expected/flatgeobuf-wfs-get-feature-propertyname.xml new file mode 100644 index 0000000000..5c3f08daeb --- /dev/null +++ b/msautotest/misc/expected/flatgeobuf-wfs-get-feature-propertyname.xml @@ -0,0 +1,273 @@ +Content-Type: text/xml; charset=UTF-8 + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + Madagascar + + + + + Mozambique + + + + + eSwatini + + + + + Lesotho + + + + + South Africa + + + + + Botswana + + + + + Namibia + + + + + Zimbabwe + + + + + Zambia + + + + + Angola + + + + + Democratic Republic of the Congo + + + + + Burundi + + + + + Rwanda + + + + + Kenya + + + + + Tanzania + + + + + Malawi + + + + + Somaliland + + + + + Somalia + + + + + Ethiopia + + + + + Djibouti + + + + + Eritrea + + + + + Egypt + + + + + Libya + + + + + Chad + + + + + Sudan + + + + + South Sudan + + + + + Uganda + + + + + Central African Republic + + + + + Cameroon + + + + + Nigeria + + + + + Equatorial Guinea + + + + + Togo + + + + + Benin + + + + + Niger + + + + + Tunisia + + + + + Algeria + + + + + Morocco + + + + + Western Sahara + + + + + Mauritania + + + + + Guinea-Bissau + + + + + The Gambia + + + + + Senegal + + + + + Mali + + + + + Burkina Faso + + + + + Ivory Coast + + + + + Ghana + + + + + Liberia + + + + + Sierra Leone + + + + + Guinea + + + + + Gabon + + + + + Republic of the Congo + + + + diff --git a/msautotest/misc/expected/flatgeobuf-wfs-get-feature.xml b/msautotest/misc/expected/flatgeobuf-wfs-get-feature.xml new file mode 100644 index 0000000000..94ad259ce2 --- /dev/null +++ b/msautotest/misc/expected/flatgeobuf-wfs-get-feature.xml @@ -0,0 +1,1111 @@ +Content-Type: text/xml; charset=UTF-8 + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 49.543519,-12.469833 49.808981,-12.895285 50.056511,-13.555761 50.217431,-14.758789 50.476537,-15.226512 50.377111,-15.706069 50.200275,-16.000263 49.860606,-15.414253 49.672607,-15.710204 49.863344,-16.451037 49.774564,-16.875042 49.498612,-17.106036 49.435619,-17.953064 49.041792,-19.118781 48.548541,-20.496888 47.930749,-22.391501 47.547723,-23.781959 47.095761,-24.941630 46.282478,-25.178463 45.409508,-25.601434 44.833574,-25.346101 44.039720,-24.988345 43.763768,-24.460677 43.697778,-23.574116 43.345654,-22.776904 43.254187,-22.057413 43.433298,-21.336475 43.893683,-21.163307 43.896370,-20.830459 44.374325,-20.072366 44.464397,-19.435454 44.232422,-18.961995 44.042976,-18.331387 43.963084,-17.409945 44.312469,-16.850496 44.446517,-16.216219 44.944937,-16.179374 45.502732,-15.974373 45.872994,-15.793454 46.312243,-15.780018 46.882183,-15.210182 47.705130,-14.594303 48.005215,-14.091233 47.869047,-13.663869 48.293828,-13.784068 48.845060,-13.089175 48.863509,-12.487868 49.194651,-12.040557 49.543519,-12.469833 + + + + + 25054161 + Madagascar + 1 + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 34.559989,-11.520020 35.312398,-11.439146 36.514082,-11.720938 36.775151,-11.594537 37.471290,-11.568760 37.827640,-11.268790 38.427557,-11.285202 39.521000,-10.896880 40.316590,-10.317100 40.316586,-10.317098 40.316589,-10.317096 40.478387,-10.765441 40.437253,-11.761711 40.560811,-12.639177 40.599620,-14.201975 40.775475,-14.691764 40.477251,-15.406294 40.089264,-16.100774 39.452559,-16.720891 38.538351,-17.101023 37.411133,-17.586368 36.281279,-18.659688 35.896497,-18.842260 35.198400,-19.552811 34.786383,-19.784012 34.701893,-20.497043 35.176127,-21.254361 35.373428,-21.840837 35.385848,-22.140000 35.562546,-22.090000 35.533935,-23.070788 35.371774,-23.535359 35.607470,-23.706563 35.458746,-24.122610 35.040735,-24.478351 34.215824,-24.816314 33.013210,-25.357573 32.574632,-25.727318 32.660363,-26.148584 32.915955,-26.215867 32.830120,-26.742192 32.071665,-26.733820 31.985779,-26.291780 31.837778,-25.843332 31.752408,-25.484284 31.930589,-24.369417 31.670398,-23.658969 31.191409,-22.251510 32.244988,-21.116489 32.508693,-20.395292 32.659743,-20.304290 32.772708,-19.715592 32.611994,-19.419383 32.654886,-18.672090 32.849861,-17.979057 32.847639,-16.713398 32.328239,-16.392074 31.852041,-16.319417 31.636498,-16.071990 31.173064,-15.860944 30.338955,-15.880839 30.274256,-15.507787 30.179481,-14.796099 33.214025,-13.971860 33.789700,-14.451831 34.064825,-14.359950 34.459633,-14.613010 34.517666,-15.013709 34.307291,-15.478641 34.381292,-16.183560 35.033810,-16.801300 35.339063,-16.107440 35.771905,-15.896859 35.686845,-14.611046 35.267956,-13.887834 34.907151,-13.565425 34.559989,-13.579998 34.280006,-12.280025 34.559989,-11.520020 + + + + + 26573706 + Mozambique + 2 + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 32.071665,-26.733820 31.868060,-27.177927 31.282773,-27.285879 30.685962,-26.743845 30.676609,-26.398078 30.949667,-26.022649 31.044080,-25.731452 31.333158,-25.660191 31.837778,-25.843332 31.985779,-26.291780 32.071665,-26.733820 + + + + + 1467152 + eSwatini + 3 + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 28.978263,-28.955597 29.325166,-29.257387 29.018415,-29.743766 28.848400,-30.070051 28.291069,-30.226217 28.107205,-30.545732 27.749397,-30.645106 26.999262,-29.875954 27.532511,-29.242711 28.074338,-28.851469 28.541700,-28.647502 28.978263,-28.955597 + + + + + 1958042 + Lesotho + 4 + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + + + 16.344977,-28.576705 16.824017,-28.082162 17.218929,-28.355943 17.387497,-28.783514 17.836152,-28.856378 18.464899,-29.045462 19.002127,-28.972443 19.894734,-28.461105 19.895768,-24.767790 20.165726,-24.917962 20.758609,-25.868136 20.666470,-26.477453 20.889609,-26.828543 21.605896,-26.726534 22.105969,-26.280256 22.579532,-25.979448 22.824271,-25.500459 23.312097,-25.268690 23.733570,-25.390129 24.211267,-25.670216 25.025171,-25.719670 25.664666,-25.486816 25.765849,-25.174845 25.941652,-24.696373 26.485753,-24.616327 26.786407,-24.240691 27.119410,-23.574323 28.017236,-22.827754 29.432188,-22.091313 29.839037,-22.102216 30.322883,-22.271612 30.659865,-22.151567 31.191409,-22.251510 31.670398,-23.658969 31.930589,-24.369417 31.752408,-25.484284 31.837778,-25.843332 31.333158,-25.660191 31.044080,-25.731452 30.949667,-26.022649 30.676609,-26.398078 30.685962,-26.743845 31.282773,-27.285879 31.868060,-27.177927 32.071665,-26.733820 32.830120,-26.742192 32.580265,-27.470158 32.462133,-28.301011 32.203389,-28.752405 31.521001,-29.257387 31.325561,-29.401978 30.901763,-29.909957 30.622813,-30.423776 30.055716,-31.140269 28.925553,-32.172041 28.219756,-32.771953 27.464608,-33.226964 26.419452,-33.614950 25.909664,-33.667040 25.780628,-33.944646 25.172862,-33.796851 24.677853,-33.987176 23.594043,-33.794474 22.988189,-33.916431 22.574157,-33.864083 21.542799,-34.258839 20.689053,-34.417175 20.071261,-34.795137 19.616405,-34.819166 19.193278,-34.462599 18.855315,-34.444306 18.424643,-33.997873 18.377411,-34.136521 18.244499,-33.867752 18.250080,-33.281431 17.925190,-32.611291 18.247910,-32.429131 18.221762,-31.661633 17.566918,-30.725721 17.064416,-29.878641 17.062918,-29.875954 16.344977,-28.576705 + + + + + 28.978263,-28.955597 28.541700,-28.647502 28.074338,-28.851469 27.532511,-29.242711 26.999262,-29.875954 27.749397,-30.645106 28.107205,-30.545732 28.291069,-30.226217 28.848400,-30.070051 29.018415,-29.743766 29.325166,-29.257387 28.978263,-28.955597 + + + + + + + 54841552 + South Africa + 5 + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 29.432188,-22.091313 28.017236,-22.827754 27.119410,-23.574323 26.786407,-24.240691 26.485753,-24.616327 25.941652,-24.696373 25.765849,-25.174845 25.664666,-25.486816 25.025171,-25.719670 24.211267,-25.670216 23.733570,-25.390129 23.312097,-25.268690 22.824271,-25.500459 22.579532,-25.979448 22.105969,-26.280256 21.605896,-26.726534 20.889609,-26.828543 20.666470,-26.477453 20.758609,-25.868136 20.165726,-24.917962 19.895768,-24.767790 19.895458,-21.849157 20.881134,-21.814327 20.910641,-18.252219 21.655040,-18.219146 23.196858,-17.869038 23.579006,-18.281261 24.217365,-17.889347 24.520705,-17.887125 25.084443,-17.661816 25.264226,-17.736540 25.649163,-18.536026 25.850391,-18.714413 26.164791,-19.293086 27.296505,-20.391520 27.724747,-20.499059 27.727228,-20.851802 28.021370,-21.485975 28.794656,-21.639454 29.432188,-22.091313 + + + + + 2214858 + Botswana + 6 + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 19.895768,-24.767790 19.894734,-28.461105 19.002127,-28.972443 18.464899,-29.045462 17.836152,-28.856378 17.387497,-28.783514 17.218929,-28.355943 16.824017,-28.082162 16.344977,-28.576705 15.601818,-27.821247 15.210472,-27.090956 14.989711,-26.117372 14.743214,-25.392920 14.408144,-23.853014 14.385717,-22.656653 14.257714,-22.111208 13.868642,-21.699037 13.352498,-20.872834 12.826845,-19.673166 12.608564,-19.045349 11.794919,-18.069129 11.734199,-17.301889 12.215461,-17.111668 12.814081,-16.941343 13.462362,-16.971212 14.058501,-17.423381 14.209707,-17.353101 18.263309,-17.309951 18.956187,-17.789095 21.377176,-17.930636 23.215048,-17.523116 24.033862,-17.295843 24.682349,-17.353411 25.076950,-17.578823 25.084443,-17.661816 24.520705,-17.887125 24.217365,-17.889347 23.579006,-18.281261 23.196858,-17.869038 21.655040,-18.219146 20.910641,-18.252219 20.881134,-21.814327 19.895458,-21.849157 19.895768,-24.767790 + + + + + 2484780 + Namibia + 7 + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 31.191409,-22.251510 30.659865,-22.151567 30.322883,-22.271612 29.839037,-22.102216 29.432188,-22.091313 28.794656,-21.639454 28.021370,-21.485975 27.727228,-20.851802 27.724747,-20.499059 27.296505,-20.391520 26.164791,-19.293086 25.850391,-18.714413 25.649163,-18.536026 25.264226,-17.736540 26.381935,-17.846042 26.706773,-17.961229 27.044427,-17.938026 27.598243,-17.290831 28.467906,-16.468400 28.825869,-16.389749 28.947463,-16.043051 29.516834,-15.644678 30.274256,-15.507787 30.338955,-15.880839 31.173064,-15.860944 31.636498,-16.071990 31.852041,-16.319417 32.328239,-16.392074 32.847639,-16.713398 32.849861,-17.979057 32.654886,-18.672090 32.611994,-19.419383 32.772708,-19.715592 32.659743,-20.304290 32.508693,-20.395292 32.244988,-21.116489 31.191409,-22.251510 + + + + + 13805084 + Zimbabwe + 8 + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 30.740010,-8.340006 31.157751,-8.594579 31.556348,-8.762049 32.191865,-8.930359 32.759375,-9.230599 33.231388,-9.676722 33.485688,-10.525559 33.315310,-10.796550 33.114289,-11.607198 33.306422,-12.435778 32.991764,-12.783871 32.688165,-13.712858 33.214025,-13.971860 30.179481,-14.796099 30.274256,-15.507787 29.516834,-15.644678 28.947463,-16.043051 28.825869,-16.389749 28.467906,-16.468400 27.598243,-17.290831 27.044427,-17.938026 26.706773,-17.961229 26.381935,-17.846042 25.264226,-17.736540 25.084443,-17.661816 25.076950,-17.578823 24.682349,-17.353411 24.033862,-17.295843 23.215048,-17.523116 22.562478,-16.898451 21.887843,-16.080310 21.933886,-12.898437 24.016137,-12.911046 23.930922,-12.565848 24.079905,-12.191297 23.904154,-11.722282 24.017894,-11.237298 23.912215,-10.926826 24.257155,-10.951993 24.314516,-11.262826 24.783170,-11.238694 25.418118,-11.330936 25.752310,-11.784965 26.553088,-11.924440 27.164420,-11.608748 27.388799,-12.132747 28.155109,-12.272481 28.523562,-12.698604 28.934286,-13.248958 29.699614,-13.257227 29.616001,-12.178895 29.341548,-12.360744 28.642417,-11.971569 28.372253,-11.793647 28.496070,-10.789884 28.673682,-9.605925 28.449871,-9.164918 28.734867,-8.526559 29.002912,-8.407032 30.346086,-8.238257 30.740010,-8.340006 + + + + + 15972000 + Zambia + 9 + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + + + 12.995517,-4.781103 12.631612,-4.991271 12.468004,-5.248362 12.436688,-5.684304 12.182337,-5.789931 11.914963,-5.037987 12.318608,-4.606230 12.620760,-4.438023 12.995517,-4.781103 + + + + + + + + + 12.322432,-6.100092 12.735171,-5.965682 13.024869,-5.984389 13.375597,-5.864241 16.326528,-5.877470 16.573180,-6.622645 16.860191,-7.222298 17.089996,-7.545689 17.472970,-8.068551 18.134222,-7.987678 18.464176,-7.847014 19.016752,-7.988246 19.166613,-7.738184 19.417502,-7.155429 20.037723,-7.116361 20.091622,-6.943090 20.601823,-6.939318 20.514748,-7.299606 21.728111,-7.290872 21.746456,-7.920085 21.949131,-8.305901 21.801801,-8.908707 21.875182,-9.523708 22.208753,-9.894796 22.155268,-11.084801 22.402798,-10.993075 22.837345,-11.017622 23.456791,-10.867863 23.912215,-10.926826 24.017894,-11.237298 23.904154,-11.722282 24.079905,-12.191297 23.930922,-12.565848 24.016137,-12.911046 21.933886,-12.898437 21.887843,-16.080310 22.562478,-16.898451 23.215048,-17.523116 21.377176,-17.930636 18.956187,-17.789095 18.263309,-17.309951 14.209707,-17.353101 14.058501,-17.423381 13.462362,-16.971212 12.814081,-16.941343 12.215461,-17.111668 11.734199,-17.301889 11.640096,-16.673142 11.778537,-15.793816 12.123581,-14.878316 12.175619,-14.449144 12.500095,-13.547700 12.738479,-13.137906 13.312914,-12.483630 13.633721,-12.038645 13.738728,-11.297863 13.686379,-10.731076 13.387328,-10.373578 13.120988,-9.766897 12.875370,-9.166934 12.929061,-8.959091 13.236433,-8.562629 12.933040,-7.596539 12.728298,-6.927122 12.227347,-6.294448 12.322432,-6.100092 + + + + + + + 29310273 + Angola + 10 + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 29.339998,-4.499983 29.519987,-5.419979 29.419993,-5.939999 29.620032,-6.520015 30.199997,-7.079981 30.740015,-8.340007 30.740010,-8.340006 30.346086,-8.238257 29.002912,-8.407032 28.734867,-8.526559 28.449871,-9.164918 28.673682,-9.605925 28.496070,-10.789884 28.372253,-11.793647 28.642417,-11.971569 29.341548,-12.360744 29.616001,-12.178895 29.699614,-13.257227 28.934286,-13.248958 28.523562,-12.698604 28.155109,-12.272481 27.388799,-12.132747 27.164420,-11.608748 26.553088,-11.924440 25.752310,-11.784965 25.418118,-11.330936 24.783170,-11.238694 24.314516,-11.262826 24.257155,-10.951993 23.912215,-10.926826 23.456791,-10.867863 22.837345,-11.017622 22.402798,-10.993075 22.155268,-11.084801 22.208753,-9.894796 21.875182,-9.523708 21.801801,-8.908707 21.949131,-8.305901 21.746456,-7.920085 21.728111,-7.290872 20.514748,-7.299606 20.601823,-6.939318 20.091622,-6.943090 20.037723,-7.116361 19.417502,-7.155429 19.166613,-7.738184 19.016752,-7.988246 18.464176,-7.847014 18.134222,-7.987678 17.472970,-8.068551 17.089996,-7.545689 16.860191,-7.222298 16.573180,-6.622645 16.326528,-5.877470 13.375597,-5.864241 13.024869,-5.984389 12.735171,-5.965682 12.322432,-6.100092 12.182337,-5.789931 12.436688,-5.684304 12.468004,-5.248362 12.631612,-4.991271 12.995517,-4.781103 13.258240,-4.882957 13.600235,-4.500138 14.144956,-4.510009 14.209035,-4.793092 14.582604,-4.970239 15.170992,-4.343507 15.753540,-3.855165 16.006290,-3.535133 15.972803,-2.712392 16.407092,-1.740927 16.865307,-1.225816 17.523716,-0.743830 17.638645,-0.424832 17.663553,-0.058084 17.826540,0.288923 17.774192,0.855659 17.898835,1.741832 18.094276,2.365722 18.393792,2.900443 18.453065,3.504386 18.542982,4.201785 18.932312,4.709506 19.467784,5.031528 20.290679,4.691678 20.927591,4.322786 21.659123,4.224342 22.405124,4.029160 22.704124,4.633051 22.841480,4.710126 23.297214,4.609693 24.410531,5.108784 24.805029,4.897247 25.128833,4.927245 25.278798,5.170408 25.650455,5.256088 26.402761,5.150875 27.044065,5.127853 27.374226,5.233944 27.979977,4.408413 28.428994,4.287155 28.696678,4.455077 29.159078,4.389267 29.715995,4.600805 29.953500,4.173699 30.833852,3.509172 30.833860,3.509166 30.773347,2.339883 31.174149,2.204465 30.852670,1.849396 30.468508,1.583805 30.086154,1.062313 29.875779,0.597380 29.819503,-0.205310 29.587838,-0.587406 29.579466,-1.341313 29.291887,-1.620056 29.254835,-2.215110 29.117479,-2.292211 29.024926,-2.839258 29.276384,-3.293907 29.339998,-4.499983 + + + + + 83301151 + Democratic Republic of the Congo + 11 + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 30.469674,-2.413855 30.527660,-2.807620 30.743010,-3.034310 30.752240,-3.359310 30.505540,-3.568580 30.116320,-4.090120 29.753512,-4.452389 29.339998,-4.499983 29.276384,-3.293907 29.024926,-2.839258 29.632176,-2.917858 29.938359,-2.348487 30.469674,-2.413855 + + + + + 11466756 + Burundi + 12 + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 30.419105,-1.134659 30.816135,-1.698914 30.758309,-2.287250 30.469670,-2.413830 30.469674,-2.413855 29.938359,-2.348487 29.632176,-2.917858 29.024926,-2.839258 29.117479,-2.292211 29.254835,-2.215110 29.291887,-1.620056 29.579466,-1.341313 29.821519,-1.443322 30.419105,-1.134659 + + + + + 11901484 + Rwanda + 13 + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 39.202220,-4.676770 37.766900,-3.677120 37.698690,-3.096990 34.072620,-1.059820 33.903711,-0.950000 33.893569,0.109814 34.180000,0.515000 34.672100,1.176940 35.035990,1.905840 34.596070,3.053740 34.479130,3.555600 34.005000,4.249885 34.620196,4.847123 35.298007,5.506000 35.817448,5.338232 35.817448,4.776966 36.159079,4.447864 36.855093,4.447864 38.120915,3.598605 38.436970,3.588510 38.671140,3.616070 38.892510,3.500740 39.559384,3.422060 39.854940,3.838790 40.768480,4.257020 41.171800,3.919090 41.855083,3.918912 40.981050,2.784520 40.993000,-0.858290 41.585130,-1.683250 40.884770,-2.082550 40.637850,-2.499790 40.263040,-2.573090 40.121190,-3.277680 39.800060,-3.681160 39.604890,-4.346530 39.202220,-4.676770 + + + + + 47615739 + Kenya + 14 + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 33.903711,-0.950000 34.072620,-1.059820 37.698690,-3.096990 37.766900,-3.677120 39.202220,-4.676770 38.740540,-5.908950 38.799770,-6.475660 39.440000,-6.840000 39.470000,-7.100000 39.194690,-7.703900 39.252030,-8.007810 39.186520,-8.485510 39.535740,-9.112370 39.949600,-10.098400 40.316586,-10.317098 40.316590,-10.317100 39.521000,-10.896880 38.427557,-11.285202 37.827640,-11.268790 37.471290,-11.568760 36.775151,-11.594537 36.514082,-11.720938 35.312398,-11.439146 34.559989,-11.520020 34.280000,-10.160000 33.940838,-9.693674 33.739720,-9.417150 32.759375,-9.230599 32.191865,-8.930359 31.556348,-8.762049 31.157751,-8.594579 30.740010,-8.340006 30.740015,-8.340007 30.199997,-7.079981 29.620032,-6.520015 29.419993,-5.939999 29.519987,-5.419979 29.339998,-4.499983 29.753512,-4.452389 30.116320,-4.090120 30.505540,-3.568580 30.752240,-3.359310 30.743010,-3.034310 30.527660,-2.807620 30.469674,-2.413855 30.469670,-2.413830 30.758309,-2.287250 30.816135,-1.698914 30.419105,-1.134659 30.769860,-1.014550 31.866170,-1.027360 33.903711,-0.950000 + + + + + 53950935 + Tanzania + 15 + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 32.759375,-9.230599 33.739720,-9.417150 33.940838,-9.693674 34.280000,-10.160000 34.559989,-11.520020 34.280006,-12.280025 34.559989,-13.579998 34.907151,-13.565425 35.267956,-13.887834 35.686845,-14.611046 35.771905,-15.896859 35.339063,-16.107440 35.033810,-16.801300 34.381292,-16.183560 34.307291,-15.478641 34.517666,-15.013709 34.459633,-14.613010 34.064825,-14.359950 33.789700,-14.451831 33.214025,-13.971860 32.688165,-13.712858 32.991764,-12.783871 33.306422,-12.435778 33.114289,-11.607198 33.315310,-10.796550 33.485688,-10.525559 33.231388,-9.676722 32.759375,-9.230599 + + + + + 19196246 + Malawi + 16 + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 48.948205,11.410617 48.948205,11.410617 48.942005,11.394266 48.938491,10.982327 48.938233,9.973500 48.938130,9.451749 48.486736,8.837626 47.789420,8.003000 46.948340,7.996880 43.678750,9.183580 43.296990,9.540480 42.928120,10.021940 42.558760,10.572580 42.776852,10.926879 43.145305,11.462040 43.470660,11.277710 43.666668,10.864169 44.117804,10.445538 44.614259,10.442205 45.556941,10.698029 46.645401,10.816549 47.525658,11.127228 48.021596,11.193064 48.378784,11.375482 48.948206,11.410622 48.948205,11.410617 + + + + + 3500000 + Somaliland + 17 + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 41.585130,-1.683250 40.993000,-0.858290 40.981050,2.784520 41.855083,3.918912 42.128610,4.234130 42.769670,4.252590 43.660870,4.957550 44.963600,5.001620 47.789420,8.003000 48.486736,8.837626 48.938130,9.451749 48.938233,9.973500 48.938491,10.982327 48.942005,11.394266 48.948205,11.410617 48.948205,11.410617 49.267760,11.430330 49.728620,11.578900 50.258780,11.679570 50.732020,12.021900 51.111200,12.024640 51.133870,11.748150 51.041530,11.166510 51.045310,10.640900 50.834180,10.279720 50.552390,9.198740 50.070920,8.081730 49.452700,6.804660 48.594550,5.339110 47.740790,4.219400 46.564760,2.855290 45.563990,2.045760 44.068150,1.052830 43.135970,0.292200 42.041570,-0.919160 41.810950,-1.446470 41.585130,-1.683250 + + + + + 7531386 + Somalia + 18 + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 47.789420,8.003000 44.963600,5.001620 43.660870,4.957550 42.769670,4.252590 42.128610,4.234130 41.855083,3.918912 41.171800,3.919090 40.768480,4.257020 39.854940,3.838790 39.559384,3.422060 38.892510,3.500740 38.671140,3.616070 38.436970,3.588510 38.120915,3.598605 36.855093,4.447864 36.159079,4.447864 35.817448,4.776966 35.817448,5.338232 35.298007,5.506000 34.707020,6.594220 34.250320,6.826070 34.075100,7.225950 33.568290,7.713340 32.954180,7.784970 33.294800,8.354580 33.825500,8.379160 33.974980,8.684560 33.961620,9.583580 34.257450,10.630090 34.731150,10.910170 34.831630,11.318960 35.260490,12.082860 35.863630,12.578280 36.270220,13.563330 36.429510,14.422110 37.593770,14.213100 37.906070,14.959430 38.512950,14.505470 39.099400,14.740640 39.340610,14.531550 40.026250,14.519590 40.896600,14.118640 41.155200,13.773330 41.598560,13.452090 42.009750,12.865820 42.351560,12.542230 42.000000,12.100000 41.661760,11.631200 41.739590,11.355110 41.755570,11.050910 42.314140,11.034200 42.554930,11.105110 42.776852,10.926879 42.558760,10.572580 42.928120,10.021940 43.296990,9.540480 43.678750,9.183580 46.948340,7.996880 47.789420,8.003000 + + + + + 105350020 + Ethiopia + 19 + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 42.351560,12.542230 42.779642,12.455416 43.081226,12.699639 43.317852,12.390148 43.286381,11.974928 42.715874,11.735641 43.145305,11.462040 42.776852,10.926879 42.554930,11.105110 42.314140,11.034200 41.755570,11.050910 41.739590,11.355110 41.661760,11.631200 42.000000,12.100000 42.351560,12.542230 + + + + + 865267 + Djibouti + 20 + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 36.429510,14.422110 36.323220,14.822490 36.753890,16.291860 36.852530,16.956550 37.167470,17.263140 37.904000,17.427540 38.410090,17.998307 38.990623,16.840626 39.266110,15.922723 39.814294,15.435647 41.179275,14.491080 41.734952,13.921037 42.276831,13.343992 42.589576,13.000421 43.081226,12.699639 42.779642,12.455416 42.351560,12.542230 42.009750,12.865820 41.598560,13.452090 41.155200,13.773330 40.896600,14.118640 40.026250,14.519590 39.340610,14.531550 39.099400,14.740640 38.512950,14.505470 37.906070,14.959430 37.593770,14.213100 36.429510,14.422110 + + + + + 5918919 + Eritrea + 21 + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 36.866230,22.000000 32.900000,22.000000 29.020000,22.000000 25.000000,22.000000 25.000000,25.682500 25.000000,29.238655 24.700070,30.044190 24.957620,30.661600 24.802870,31.089290 25.164820,31.569150 26.495330,31.585680 27.457620,31.321260 28.450480,31.025770 28.913530,30.870050 29.683420,31.186860 30.095030,31.473400 30.976930,31.555860 31.687960,31.429600 31.960410,30.933600 32.192470,31.260340 32.993920,31.024070 33.773400,30.967460 34.265435,31.219357 34.265440,31.219360 34.823243,29.761081 34.922600,29.501330 34.641740,29.099420 34.426550,28.343990 34.154510,27.823300 33.921360,27.648700 33.588110,27.971360 33.136760,28.417650 32.423230,29.851080 32.320460,29.760430 32.734820,28.705230 33.348760,27.699890 34.104550,26.142270 34.473870,25.598560 34.795070,25.033750 35.692410,23.926710 35.493720,23.752370 35.525980,23.102440 36.690690,22.204850 36.866230,22.000000 + + + + + 97041072 + Egypt + 22 + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 25.000000,22.000000 25.000000,20.003040 23.850000,20.000000 23.837660,19.580470 19.849260,21.495090 15.860850,23.409720 14.851300,22.862950 14.143871,22.491289 13.581425,23.040506 11.999506,23.471668 11.560669,24.097909 10.771364,24.562532 10.303847,24.379313 9.948261,24.936954 9.910693,25.365455 9.319411,26.094325 9.716286,26.512206 9.629056,27.140953 9.756128,27.688259 9.683885,28.144174 9.859998,28.959990 9.805634,29.424638 9.482140,30.307556 9.970017,30.539325 10.056575,30.961831 9.950225,31.376070 10.636901,31.761421 10.944790,32.081815 11.432253,32.368903 11.488787,33.136996 12.663310,32.792780 13.083260,32.878820 13.918680,32.711960 15.245630,32.265080 15.713940,31.376260 16.611620,31.182180 18.021090,30.763570 19.086410,30.266390 19.574040,30.525820 20.053350,30.985760 19.820330,31.751790 20.133970,32.238200 20.854520,32.706800 21.542980,32.843200 22.895760,32.638580 23.236800,32.191490 23.609130,32.187260 23.927500,32.016670 24.921140,31.899360 25.164820,31.569150 24.802870,31.089290 24.957620,30.661600 24.700070,30.044190 25.000000,29.238655 25.000000,25.682500 25.000000,22.000000 + + + + + 6653210 + Libya + 23 + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 23.837660,19.580470 23.886890,15.610840 23.024590,15.680720 22.567950,14.944290 22.303510,14.326820 22.512020,14.093180 22.183290,13.786480 22.296580,13.372320 22.037590,12.955460 21.936810,12.588180 22.288010,12.646050 22.497620,12.260240 22.508690,11.679360 22.876220,11.384610 22.864165,11.142395 22.231129,10.971889 21.723822,10.567056 21.000868,9.475985 20.059685,9.012706 19.094008,9.074847 18.812010,8.982915 18.911022,8.630895 18.389555,8.281304 17.964930,7.890914 16.705988,7.508328 16.456185,7.734774 16.290562,7.754307 16.106232,7.497088 15.279460,7.421925 15.436092,7.692812 15.120866,8.382150 14.979996,8.796104 14.544467,8.965861 13.954218,9.549495 14.171466,10.021378 14.627201,9.920919 14.909354,9.992129 15.467873,9.982337 14.923565,10.891325 14.960152,11.555574 14.893360,12.219050 14.495787,12.859396 14.595781,13.330427 13.954477,13.353449 13.956699,13.996691 13.540394,14.367134 13.972170,15.684370 15.247731,16.627306 15.300441,17.927950 15.685741,19.957180 15.903247,20.387619 15.487148,20.730415 15.471060,21.048450 15.096888,21.308519 14.851300,22.862950 15.860850,23.409720 19.849260,21.495090 23.837660,19.580470 + + + + + 12075985 + Chad + 24 + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 24.567369,8.229188 23.805813,8.666319 23.459013,8.954286 23.394779,9.265068 23.557250,9.681218 23.554304,10.089255 22.977544,10.714463 22.864165,11.142395 22.876220,11.384610 22.508690,11.679360 22.497620,12.260240 22.288010,12.646050 21.936810,12.588180 22.037590,12.955460 22.296580,13.372320 22.183290,13.786480 22.512020,14.093180 22.303510,14.326820 22.567950,14.944290 23.024590,15.680720 23.886890,15.610840 23.837660,19.580470 23.850000,20.000000 25.000000,20.003040 25.000000,22.000000 29.020000,22.000000 32.900000,22.000000 36.866230,22.000000 37.188720,21.018850 36.969410,20.837440 37.114700,19.807960 37.481790,18.614090 37.862760,18.367860 38.410090,17.998307 37.904000,17.427540 37.167470,17.263140 36.852530,16.956550 36.753890,16.291860 36.323220,14.822490 36.429510,14.422110 36.270220,13.563330 35.863630,12.578280 35.260490,12.082860 34.831630,11.318960 34.731150,10.910170 34.257450,10.630090 33.961620,9.583580 33.974980,8.684560 33.963393,9.464285 33.824963,9.484061 33.842131,9.981915 33.721959,10.325262 33.206938,10.720112 33.086766,11.441141 33.206938,12.179338 32.743419,12.248008 32.674750,12.024832 32.073892,11.973330 32.314235,11.681484 32.400072,11.080626 31.850716,10.531271 31.352862,9.810241 30.837841,9.707237 29.996639,10.290927 29.618957,10.084919 29.515953,9.793074 29.000932,9.604232 28.966597,9.398224 27.970890,9.398224 27.833551,9.604232 27.112521,9.638567 26.752006,9.466893 26.477328,9.552730 25.962307,10.136421 25.790633,10.411099 25.069604,10.273760 24.794926,9.810241 24.537415,8.917538 24.194068,8.728696 23.886980,8.619730 24.567369,8.229188 + + + + + 37345935 + Sudan + 25 + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 30.833852,3.509172 29.953500,4.173699 29.715995,4.600805 29.159078,4.389267 28.696678,4.455077 28.428994,4.287155 27.979977,4.408413 27.374226,5.233944 27.213409,5.550953 26.465909,5.946717 26.213418,6.546603 25.796648,6.979316 25.124131,7.500085 25.114932,7.825104 24.567369,8.229188 23.886980,8.619730 24.194068,8.728696 24.537415,8.917538 24.794926,9.810241 25.069604,10.273760 25.790633,10.411099 25.962307,10.136421 26.477328,9.552730 26.752006,9.466893 27.112521,9.638567 27.833551,9.604232 27.970890,9.398224 28.966597,9.398224 29.000932,9.604232 29.515953,9.793074 29.618957,10.084919 29.996639,10.290927 30.837841,9.707237 31.352862,9.810241 31.850716,10.531271 32.400072,11.080626 32.314235,11.681484 32.073892,11.973330 32.674750,12.024832 32.743419,12.248008 33.206938,12.179338 33.086766,11.441141 33.206938,10.720112 33.721959,10.325262 33.842131,9.981915 33.824963,9.484061 33.963393,9.464285 33.974980,8.684560 33.825500,8.379160 33.294800,8.354580 32.954180,7.784970 33.568290,7.713340 34.075100,7.225950 34.250320,6.826070 34.707020,6.594220 35.298007,5.506000 34.620196,4.847123 34.005000,4.249885 33.390000,3.790000 32.686420,3.792320 31.881450,3.558270 31.245560,3.781900 30.833852,3.509172 + + + + + 13026129 + South Sudan + 26 + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 33.903711,-0.950000 31.866170,-1.027360 30.769860,-1.014550 30.419105,-1.134659 29.821519,-1.443322 29.579466,-1.341313 29.587838,-0.587406 29.819503,-0.205310 29.875779,0.597380 30.086154,1.062313 30.468508,1.583805 30.852670,1.849396 31.174149,2.204465 30.773347,2.339883 30.833860,3.509166 30.833852,3.509172 31.245560,3.781900 31.881450,3.558270 32.686420,3.792320 33.390000,3.790000 34.005000,4.249885 34.479130,3.555600 34.596070,3.053740 35.035990,1.905840 34.672100,1.176940 34.180000,0.515000 33.893569,0.109814 33.903711,-0.950000 + + + + + 39570125 + Uganda + 27 + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 27.374226,5.233944 27.044065,5.127853 26.402761,5.150875 25.650455,5.256088 25.278798,5.170408 25.128833,4.927245 24.805029,4.897247 24.410531,5.108784 23.297214,4.609693 22.841480,4.710126 22.704124,4.633051 22.405124,4.029160 21.659123,4.224342 20.927591,4.322786 20.290679,4.691678 19.467784,5.031528 18.932312,4.709506 18.542982,4.201785 18.453065,3.504386 17.809900,3.560196 17.133042,3.728197 16.537058,3.198255 16.012852,2.267640 15.907381,2.557389 15.862732,3.013537 15.405396,3.335301 15.036220,3.851367 14.950953,4.210389 14.478372,4.732605 14.558936,5.030598 14.459407,5.451761 14.536560,6.226959 14.776545,6.408498 15.279460,7.421925 16.106232,7.497088 16.290562,7.754307 16.456185,7.734774 16.705988,7.508328 17.964930,7.890914 18.389555,8.281304 18.911022,8.630895 18.812010,8.982915 19.094008,9.074847 20.059685,9.012706 21.000868,9.475985 21.723822,10.567056 22.231129,10.971889 22.864165,11.142395 22.977544,10.714463 23.554304,10.089255 23.557250,9.681218 23.394779,9.265068 23.459013,8.954286 23.805813,8.666319 24.567369,8.229188 25.114932,7.825104 25.124131,7.500085 25.796648,6.979316 26.213418,6.546603 26.465909,5.946717 27.213409,5.550953 27.374226,5.233944 + + + + + 5625118 + Central African Republic + 28 + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 14.495787,12.859396 14.893360,12.219050 14.960152,11.555574 14.923565,10.891325 15.467873,9.982337 14.909354,9.992129 14.627201,9.920919 14.171466,10.021378 13.954218,9.549495 14.544467,8.965861 14.979996,8.796104 15.120866,8.382150 15.436092,7.692812 15.279460,7.421925 14.776545,6.408498 14.536560,6.226959 14.459407,5.451761 14.558936,5.030598 14.478372,4.732605 14.950953,4.210389 15.036220,3.851367 15.405396,3.335301 15.862732,3.013537 15.907381,2.557389 16.012852,2.267640 15.940919,1.727673 15.146342,1.964015 14.337813,2.227875 13.075822,2.267097 12.951334,2.321616 12.359380,2.192812 11.751665,2.326758 11.276449,2.261051 9.649158,2.283866 9.795196,3.073404 9.404367,3.734527 8.948116,3.904129 8.744924,4.352215 8.488816,4.495617 8.500288,4.771983 8.757533,5.479666 9.233163,6.444491 9.522706,6.453482 10.118277,7.038770 10.497375,7.055358 11.058788,6.644427 11.745774,6.981383 11.839309,7.397042 12.063946,7.799808 12.218872,8.305824 12.753672,8.717763 12.955468,9.417772 13.167600,9.640626 13.308676,10.160362 13.572950,10.798566 14.415379,11.572369 14.468192,11.904752 14.577178,12.085361 14.181336,12.483657 14.213531,12.802035 14.495787,12.859396 + + + + + 24994885 + Cameroon + 29 + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 2.691702,6.258817 2.749063,7.870734 2.723793,8.506845 2.912308,9.137608 3.220352,9.444153 3.705438,10.063210 3.600070,10.332186 3.797112,10.734746 3.572216,11.327939 3.611180,11.660167 3.680634,12.552903 3.967283,12.956109 4.107946,13.531216 4.368344,13.747482 5.443058,13.865924 6.445426,13.492768 6.820442,13.115091 7.330747,13.098038 7.804671,13.343527 9.014933,12.826659 9.524928,12.851102 10.114814,13.277252 10.701032,13.246918 10.989593,13.387323 11.527803,13.328980 12.302071,13.037189 13.083987,13.596147 13.318702,13.556356 13.995353,12.461565 14.181336,12.483657 14.577178,12.085361 14.468192,11.904752 14.415379,11.572369 13.572950,10.798566 13.308676,10.160362 13.167600,9.640626 12.955468,9.417772 12.753672,8.717763 12.218872,8.305824 12.063946,7.799808 11.839309,7.397042 11.745774,6.981383 11.058788,6.644427 10.497375,7.055358 10.118277,7.038770 9.522706,6.453482 9.233163,6.444491 8.757533,5.479666 8.500288,4.771983 7.462108,4.412108 7.082596,4.464689 6.698072,4.240594 5.898173,4.262453 5.362805,4.887971 5.033574,5.611802 4.325607,6.270651 3.574180,6.258300 2.691702,6.258817 + + + + + 190632261 + Nigeria + 30 + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 9.649158,2.283866 11.276449,2.261051 11.285079,1.057662 9.830284,1.067894 9.492889,1.010120 9.305613,1.160911 9.649158,2.283866 + + + + + 778358 + Equatorial Guinea + 31 + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 0.899563,10.997339 0.772336,10.470808 1.077795,10.175607 1.425061,9.825395 1.463043,9.334624 1.664478,9.128590 1.618951,6.832038 1.865241,6.142158 1.060122,5.928837 0.836931,6.279979 0.570384,6.914359 0.490957,7.411744 0.712029,8.312465 0.461192,8.677223 0.365901,9.465004 0.367580,10.191213 -0.049785,10.706918 0.023803,11.018682 0.899563,10.997339 + + + + + 7965055 + Togo + 32 + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 2.691702,6.258817 1.865241,6.142158 1.618951,6.832038 1.664478,9.128590 1.463043,9.334624 1.425061,9.825395 1.077795,10.175607 0.772336,10.470808 0.899563,10.997339 1.243470,11.110511 1.447178,11.547719 1.935986,11.641150 2.154474,11.940150 2.490164,12.233052 2.848643,12.235636 3.611180,11.660167 3.572216,11.327939 3.797112,10.734746 3.600070,10.332186 3.705438,10.063210 3.220352,9.444153 2.912308,9.137608 2.723793,8.506845 2.749063,7.870734 2.691702,6.258817 + + + + + 11038805 + Benin + 33 + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 14.851300,22.862950 15.096888,21.308519 15.471060,21.048450 15.487148,20.730415 15.903247,20.387619 15.685741,19.957180 15.300441,17.927950 15.247731,16.627306 13.972170,15.684370 13.540394,14.367134 13.956699,13.996691 13.954477,13.353449 14.595781,13.330427 14.495787,12.859396 14.213531,12.802035 14.181336,12.483657 13.995353,12.461565 13.318702,13.556356 13.083987,13.596147 12.302071,13.037189 11.527803,13.328980 10.989593,13.387323 10.701032,13.246918 10.114814,13.277252 9.524928,12.851102 9.014933,12.826659 7.804671,13.343527 7.330747,13.098038 6.820442,13.115091 6.445426,13.492768 5.443058,13.865924 4.368344,13.747482 4.107946,13.531216 3.967283,12.956109 3.680634,12.552903 3.611180,11.660167 2.848643,12.235636 2.490164,12.233052 2.154474,11.940150 2.177108,12.625018 1.024103,12.851826 0.993046,13.335750 0.429928,13.988733 0.295646,14.444235 0.374892,14.928908 1.015783,14.968182 1.385528,15.323561 2.749993,15.409525 3.638259,15.568120 3.723422,16.184284 4.270210,16.852227 4.267419,19.155265 5.677566,19.601207 8.572893,21.565661 11.999506,23.471668 13.581425,23.040506 14.143871,22.491289 14.851300,22.862950 + + + + + 19245344 + Niger + 34 + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 9.482140,30.307556 9.055603,32.102692 8.439103,32.506285 8.430473,32.748337 7.612642,33.344115 7.524482,34.097376 8.140981,34.655146 8.376368,35.479876 8.217824,36.433177 8.420964,36.946427 9.509994,37.349994 10.210002,37.230002 10.180650,36.724038 11.028867,37.092103 11.100026,36.899996 10.600005,36.410000 10.593287,35.947444 10.939519,35.698984 10.807847,34.833507 10.149593,34.330773 10.339659,33.785742 10.856836,33.768740 11.108501,33.293343 11.488787,33.136996 11.432253,32.368903 10.944790,32.081815 10.636901,31.761421 9.950225,31.376070 10.056575,30.961831 9.970017,30.539325 9.482140,30.307556 + + + + + 11403800 + Tunisia + 35 + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + -8.684400,27.395744 -8.665124,27.589479 -8.665590,27.656426 -8.674116,28.841289 -7.059228,29.579228 -6.060632,29.731700 -5.242129,30.000443 -4.859646,30.501188 -3.690441,30.896952 -3.647498,31.637294 -3.068980,31.724498 -2.616605,32.094346 -1.307899,32.262889 -1.124551,32.651522 -1.388049,32.864015 -1.733455,33.919713 -1.792986,34.527919 -2.169914,35.168396 -1.208603,35.714849 -0.127454,35.888662 0.503877,36.301273 1.466919,36.605647 3.161699,36.783905 4.815758,36.865037 5.320120,36.716519 6.261820,37.110655 7.330385,37.118381 7.737078,36.885708 8.420964,36.946427 8.217824,36.433177 8.376368,35.479876 8.140981,34.655146 7.524482,34.097376 7.612642,33.344115 8.430473,32.748337 8.439103,32.506285 9.055603,32.102692 9.482140,30.307556 9.805634,29.424638 9.859998,28.959990 9.683885,28.144174 9.756128,27.688259 9.629056,27.140953 9.716286,26.512206 9.319411,26.094325 9.910693,25.365455 9.948261,24.936954 10.303847,24.379313 10.771364,24.562532 11.560669,24.097909 11.999506,23.471668 8.572893,21.565661 5.677566,19.601207 4.267419,19.155265 3.158133,19.057364 3.146661,19.693579 2.683588,19.856230 2.060991,20.142233 1.823228,20.610809 -1.550055,22.792666 -4.923337,24.974574 -8.684400,27.395744 + + + + + 40969443 + Algeria + 36 + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + -2.169914,35.168396 -1.792986,34.527919 -1.733455,33.919713 -1.388049,32.864015 -1.124551,32.651522 -1.307899,32.262889 -2.616605,32.094346 -3.068980,31.724498 -3.647498,31.637294 -3.690441,30.896952 -4.859646,30.501188 -5.242129,30.000443 -6.060632,29.731700 -7.059228,29.579228 -8.674116,28.841289 -8.665590,27.656426 -8.817828,27.656426 -8.794884,27.120696 -9.413037,27.088476 -9.735343,26.860945 -10.189424,26.860945 -10.551263,26.990808 -11.392555,26.883424 -11.718220,26.104092 -12.030759,26.030866 -12.500963,24.770116 -13.891110,23.691009 -14.221168,22.310163 -14.630833,21.860940 -14.750955,21.500600 -17.002962,21.420734 -17.020428,21.422310 -16.973248,21.885745 -16.589137,22.158234 -16.261922,22.679340 -16.326414,23.017768 -15.982611,23.723358 -15.426004,24.359134 -15.089332,24.520261 -14.824645,25.103533 -14.800926,25.636265 -14.439940,26.254418 -13.773805,26.618892 -13.139942,27.640148 -13.121613,27.654148 -12.618837,28.038186 -11.688919,28.148644 -10.900957,28.832142 -10.399592,29.098586 -9.564811,29.933574 -9.814718,31.177736 -9.434793,32.038096 -9.300693,32.564679 -8.657476,33.240245 -7.654178,33.697065 -6.912544,34.110476 -6.244342,35.145865 -5.929994,35.759988 -5.193863,35.755182 -4.591006,35.330712 -3.640057,35.399855 -2.604306,35.179093 -2.169914,35.168396 + + + + + 33986655 + Morocco + 37 + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + -8.665590,27.656426 -8.665124,27.589479 -8.684400,27.395744 -8.687294,25.881056 -11.969419,25.933353 -11.937224,23.374594 -12.874222,23.284832 -13.118754,22.771220 -12.929102,21.327071 -16.845194,21.333323 -17.063423,20.999752 -17.020428,21.422310 -17.002962,21.420734 -14.750955,21.500600 -14.630833,21.860940 -14.221168,22.310163 -13.891110,23.691009 -12.500963,24.770116 -12.030759,26.030866 -11.718220,26.104092 -11.392555,26.883424 -10.551263,26.990808 -10.189424,26.860945 -9.735343,26.860945 -9.413037,27.088476 -8.794884,27.120696 -8.817828,27.656426 -8.665590,27.656426 + + + + + 603253 + Western Sahara + 38 + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + -17.063423,20.999752 -16.845194,21.333323 -12.929102,21.327071 -13.118754,22.771220 -12.874222,23.284832 -11.937224,23.374594 -11.969419,25.933353 -8.687294,25.881056 -8.684400,27.395744 -4.923337,24.974574 -6.453787,24.956591 -5.971129,20.640833 -5.488523,16.325102 -5.315277,16.201854 -5.537744,15.501690 -9.550238,15.486497 -9.700255,15.264107 -10.086846,15.330486 -10.650791,15.132746 -11.349095,15.411256 -11.666078,15.388208 -11.834208,14.799097 -12.170750,14.616834 -12.830658,15.303692 -13.435738,16.039383 -14.099521,16.304302 -14.577348,16.598264 -15.135737,16.587282 -15.623666,16.369337 -16.120690,16.455663 -16.463098,16.135036 -16.549708,16.673892 -16.270552,17.166963 -16.146347,18.108482 -16.256883,19.096716 -16.377651,19.593817 -16.277838,20.092521 -16.536324,20.567866 -17.063423,20.999752 + + + + + 3758571 + Mauritania + 39 + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + -16.677452,12.384852 -16.147717,12.547762 -15.816574,12.515567 -15.548477,12.628170 -13.700476,12.586183 -13.718744,12.247186 -13.828272,12.142644 -13.743161,11.811269 -13.900800,11.678719 -14.121406,11.677117 -14.382192,11.509272 -14.685687,11.527824 -15.130311,11.040412 -15.664180,11.458474 -16.085214,11.524594 -16.314787,11.806515 -16.308947,11.958702 -16.613838,12.170911 -16.677452,12.384852 + + + + + 1792338 + Guinea-Bissau + 40 + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + -16.713729,13.594959 -15.624596,13.623587 -15.398770,13.860369 -15.081735,13.876492 -14.687031,13.630357 -14.376714,13.625680 -14.046992,13.794068 -13.844963,13.505042 -14.277702,13.280585 -14.712197,13.298207 -15.141163,13.509512 -15.511813,13.278570 -15.691001,13.270353 -15.931296,13.130284 -16.841525,13.151394 -16.713729,13.594959 + + + + + 2051363 + The Gambia + 41 + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + -16.713729,13.594959 -17.126107,14.373516 -17.625043,14.729541 -17.185173,14.919477 -16.700706,15.621527 -16.463098,16.135036 -16.120690,16.455663 -15.623666,16.369337 -15.135737,16.587282 -14.577348,16.598264 -14.099521,16.304302 -13.435738,16.039383 -12.830658,15.303692 -12.170750,14.616834 -12.124887,13.994727 -11.927716,13.422075 -11.553398,13.141214 -11.467899,12.754519 -11.513943,12.442988 -11.658301,12.386583 -12.203565,12.465648 -12.278599,12.354440 -12.499051,12.332090 -13.217818,12.575874 -13.700476,12.586183 -15.548477,12.628170 -15.816574,12.515567 -16.147717,12.547762 -16.677452,12.384852 -16.841525,13.151394 -15.931296,13.130284 -15.691001,13.270353 -15.511813,13.278570 -15.141163,13.509512 -14.712197,13.298207 -14.277702,13.280585 -13.844963,13.505042 -14.046992,13.794068 -14.376714,13.625680 -14.687031,13.630357 -15.081735,13.876492 -15.398770,13.860369 -15.624596,13.623587 -16.713729,13.594959 + + + + + 14668522 + Senegal + 42 + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + -11.513943,12.442988 -11.467899,12.754519 -11.553398,13.141214 -11.927716,13.422075 -12.124887,13.994727 -12.170750,14.616834 -11.834208,14.799097 -11.666078,15.388208 -11.349095,15.411256 -10.650791,15.132746 -10.086846,15.330486 -9.700255,15.264107 -9.550238,15.486497 -5.537744,15.501690 -5.315277,16.201854 -5.488523,16.325102 -5.971129,20.640833 -6.453787,24.956591 -4.923337,24.974574 -1.550055,22.792666 1.823228,20.610809 2.060991,20.142233 2.683588,19.856230 3.146661,19.693579 3.158133,19.057364 4.267419,19.155265 4.270210,16.852227 3.723422,16.184284 3.638259,15.568120 2.749993,15.409525 1.385528,15.323561 1.015783,14.968182 0.374892,14.928908 -0.266257,14.924309 -0.515854,15.116158 -1.066363,14.973815 -2.001035,14.559008 -2.191825,14.246418 -2.967694,13.798150 -3.103707,13.541267 -3.522803,13.337662 -4.006391,13.472485 -4.280405,13.228444 -4.427166,12.542646 -5.220942,11.713859 -5.197843,11.375146 -5.470565,10.951270 -5.404342,10.370737 -5.816926,10.222555 -6.050452,10.096361 -6.205223,10.524061 -6.493965,10.411303 -6.666461,10.430811 -6.850507,10.138994 -7.622759,10.147236 -7.899590,10.297382 -8.029944,10.206535 -8.335377,10.494812 -8.282357,10.792597 -8.407311,10.909257 -8.620321,10.810891 -8.581305,11.136246 -8.376305,11.393646 -8.786099,11.812561 -8.905265,12.088358 -9.127474,12.308060 -9.327616,12.334286 -9.567912,12.194243 -9.890993,12.060479 -10.165214,11.844084 -10.593224,11.923975 -10.870830,12.177887 -11.036556,12.211245 -11.297574,12.077971 -11.456169,12.076834 -11.513943,12.442988 + + + + + 17885245 + Mali + 43 + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + -5.404342,10.370737 -5.470565,10.951270 -5.197843,11.375146 -5.220942,11.713859 -4.427166,12.542646 -4.280405,13.228444 -4.006391,13.472485 -3.522803,13.337662 -3.103707,13.541267 -2.967694,13.798150 -2.191825,14.246418 -2.001035,14.559008 -1.066363,14.973815 -0.515854,15.116158 -0.266257,14.924309 0.374892,14.928908 0.295646,14.444235 0.429928,13.988733 0.993046,13.335750 1.024103,12.851826 2.177108,12.625018 2.154474,11.940150 1.935986,11.641150 1.447178,11.547719 1.243470,11.110511 0.899563,10.997339 0.023803,11.018682 -0.438702,11.098341 -0.761576,10.936930 -1.203358,11.009819 -2.940409,10.962690 -2.963896,10.395335 -2.827496,9.642461 -3.511899,9.900326 -3.980449,9.862344 -4.330247,9.610835 -4.779884,9.821985 -4.954653,10.152714 -5.404342,10.370737 + + + + + 20107509 + Burkina Faso + 44 + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + -8.029944,10.206535 -7.899590,10.297382 -7.622759,10.147236 -6.850507,10.138994 -6.666461,10.430811 -6.493965,10.411303 -6.205223,10.524061 -6.050452,10.096361 -5.816926,10.222555 -5.404342,10.370737 -4.954653,10.152714 -4.779884,9.821985 -4.330247,9.610835 -3.980449,9.862344 -3.511899,9.900326 -2.827496,9.642461 -2.562190,8.219628 -2.983585,7.379705 -3.244370,6.250472 -2.810701,5.389051 -2.856125,4.994476 -3.311084,4.984296 -4.008820,5.179813 -4.649917,5.168264 -5.834496,4.993701 -6.528769,4.705088 -7.518941,4.338288 -7.712159,4.364566 -7.635368,5.188159 -7.539715,5.313345 -7.570153,5.707352 -7.993693,6.126190 -8.311348,6.193033 -8.602880,6.467564 -8.385452,6.911801 -8.485446,7.395208 -8.439298,7.686043 -8.280703,7.687180 -8.221792,8.123329 -8.299049,8.316444 -8.203499,8.455453 -7.832100,8.575704 -8.079114,9.376224 -8.309616,9.789532 -8.229337,10.129020 -8.029944,10.206535 + + + + + 24184810 + Ivory Coast + 45 + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 0.023803,11.018682 -0.049785,10.706918 0.367580,10.191213 0.365901,9.465004 0.461192,8.677223 0.712029,8.312465 0.490957,7.411744 0.570384,6.914359 0.836931,6.279979 1.060122,5.928837 -0.507638,5.343473 -1.063625,5.000548 -1.964707,4.710462 -2.856125,4.994476 -2.810701,5.389051 -3.244370,6.250472 -2.983585,7.379705 -2.562190,8.219628 -2.827496,9.642461 -2.963896,10.395335 -2.940409,10.962690 -1.203358,11.009819 -0.761576,10.936930 -0.438702,11.098341 0.023803,11.018682 + + + + + 27499924 + Ghana + 46 + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + -8.439298,7.686043 -8.485446,7.395208 -8.385452,6.911801 -8.602880,6.467564 -8.311348,6.193033 -7.993693,6.126190 -7.570153,5.707352 -7.539715,5.313345 -7.635368,5.188159 -7.712159,4.364566 -7.974107,4.355755 -9.004794,4.832419 -9.913420,5.593561 -10.765384,6.140711 -11.438779,6.785917 -11.199802,7.105846 -11.146704,7.396706 -10.695595,7.939464 -10.230094,8.406206 -10.016567,8.428504 -9.755342,8.541055 -9.337280,7.928534 -9.403348,7.526905 -9.208786,7.313921 -8.926065,7.309037 -8.722124,7.711674 -8.439298,7.686043 + + + + + 4689021 + Liberia + 47 + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + -13.246550,8.903049 -12.711958,9.342712 -12.596719,9.620188 -12.425929,9.835834 -12.150338,9.858572 -11.917277,10.046984 -11.117481,10.045873 -10.839152,9.688246 -10.622395,9.267910 -10.654770,8.977178 -10.494315,8.715541 -10.505477,8.348896 -10.230094,8.406206 -10.695595,7.939464 -11.146704,7.396706 -11.199802,7.105846 -11.438779,6.785917 -11.708195,6.860098 -12.428099,7.262942 -12.949049,7.798646 -13.124025,8.163946 -13.246550,8.903049 + + + + + 6163195 + Sierra Leone + 48 + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + -13.700476,12.586183 -13.217818,12.575874 -12.499051,12.332090 -12.278599,12.354440 -12.203565,12.465648 -11.658301,12.386583 -11.513943,12.442988 -11.456169,12.076834 -11.297574,12.077971 -11.036556,12.211245 -10.870830,12.177887 -10.593224,11.923975 -10.165214,11.844084 -9.890993,12.060479 -9.567912,12.194243 -9.327616,12.334286 -9.127474,12.308060 -8.905265,12.088358 -8.786099,11.812561 -8.376305,11.393646 -8.581305,11.136246 -8.620321,10.810891 -8.407311,10.909257 -8.282357,10.792597 -8.335377,10.494812 -8.029944,10.206535 -8.229337,10.129020 -8.309616,9.789532 -8.079114,9.376224 -7.832100,8.575704 -8.203499,8.455453 -8.299049,8.316444 -8.221792,8.123329 -8.280703,7.687180 -8.439298,7.686043 -8.722124,7.711674 -8.926065,7.309037 -9.208786,7.313921 -9.403348,7.526905 -9.337280,7.928534 -9.755342,8.541055 -10.016567,8.428504 -10.230094,8.406206 -10.505477,8.348896 -10.494315,8.715541 -10.654770,8.977178 -10.622395,9.267910 -10.839152,9.688246 -11.117481,10.045873 -11.917277,10.046984 -12.150338,9.858572 -12.425929,9.835834 -12.596719,9.620188 -12.711958,9.342712 -13.246550,8.903049 -13.685154,9.494744 -14.074045,9.886167 -14.330076,10.015720 -14.579699,10.214467 -14.693232,10.656301 -14.839554,10.876572 -15.130311,11.040412 -14.685687,11.527824 -14.382192,11.509272 -14.121406,11.677117 -13.900800,11.678719 -13.743161,11.811269 -13.828272,12.142644 -13.718744,12.247186 -13.700476,12.586183 + + + + + 12413867 + Guinea + 49 + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 11.276449,2.261051 11.751665,2.326758 12.359380,2.192812 12.951334,2.321616 13.075822,2.267097 13.003114,1.830896 13.282631,1.314184 14.026669,1.395677 14.276266,1.196930 13.843321,0.038758 14.316418,-0.552627 14.425456,-1.333407 14.299210,-1.998276 13.992407,-2.470805 13.109619,-2.428740 12.575284,-1.948511 12.495703,-2.391688 11.820964,-2.514161 11.478039,-2.765619 11.855122,-3.426871 11.093773,-3.978827 10.066135,-2.969483 9.405245,-2.144313 8.797996,-1.111301 8.830087,-0.779074 9.048420,-0.459351 9.291351,0.268666 9.492889,1.010120 9.830284,1.067894 11.285079,1.057662 11.276449,2.261051 + + + + + 1772255 + Gabon + 50 + + + + + + + -1.000000,-1.000000 -1.000000,-1.000000 + + + + + + + 18.453065,3.504386 18.393792,2.900443 18.094276,2.365722 17.898835,1.741832 17.774192,0.855659 17.826540,0.288923 17.663553,-0.058084 17.638645,-0.424832 17.523716,-0.743830 16.865307,-1.225816 16.407092,-1.740927 15.972803,-2.712392 16.006290,-3.535133 15.753540,-3.855165 15.170992,-4.343507 14.582604,-4.970239 14.209035,-4.793092 14.144956,-4.510009 13.600235,-4.500138 13.258240,-4.882957 12.995517,-4.781103 12.620760,-4.438023 12.318608,-4.606230 11.914963,-5.037987 11.093773,-3.978827 11.855122,-3.426871 11.478039,-2.765619 11.820964,-2.514161 12.495703,-2.391688 12.575284,-1.948511 13.109619,-2.428740 13.992407,-2.470805 14.299210,-1.998276 14.425456,-1.333407 14.316418,-0.552627 13.843321,0.038758 14.276266,1.196930 14.026669,1.395677 13.282631,1.314184 13.003114,1.830896 13.075822,2.267097 14.337813,2.227875 15.146342,1.964015 15.940919,1.727673 16.012852,2.267640 16.537058,3.198255 17.133042,3.728197 17.809900,3.560196 18.453065,3.504386 + + + + + 4954674 + Republic of the Congo + 51 + + + + diff --git a/msautotest/misc/expected/geopdf-iso.pdf b/msautotest/misc/expected/geopdf-iso.pdf index 20d51ce44a..05c6273b4b 100644 Binary files a/msautotest/misc/expected/geopdf-iso.pdf and b/msautotest/misc/expected/geopdf-iso.pdf differ diff --git a/msautotest/misc/expected/geopdf-ogc.pdf b/msautotest/misc/expected/geopdf-ogc.pdf index aa6afebf44..05c6273b4b 100644 Binary files a/msautotest/misc/expected/geopdf-ogc.pdf and b/msautotest/misc/expected/geopdf-ogc.pdf differ diff --git a/msautotest/misc/expected/line_offset_clipped_to_multiline.png b/msautotest/misc/expected/line_offset_clipped_to_multiline.png new file mode 100644 index 0000000000..783e3ff8d1 Binary files /dev/null and b/msautotest/misc/expected/line_offset_clipped_to_multiline.png differ diff --git a/msautotest/misc/expected/listexpression.png b/msautotest/misc/expected/listexpression.png index 310b2f84f6..4b6a339e9f 100644 Binary files a/msautotest/misc/expected/listexpression.png and b/msautotest/misc/expected/listexpression.png differ diff --git a/msautotest/misc/expected/map2img-argparse-c.txt b/msautotest/misc/expected/map2img-argparse-c.txt new file mode 100644 index 0000000000..b7c3b5ec67 --- /dev/null +++ b/msautotest/misc/expected/map2img-argparse-c.txt @@ -0,0 +1 @@ +Argument -c requires an additional argument. diff --git a/msautotest/misc/expected/map2img-argparse-d.txt b/msautotest/misc/expected/map2img-argparse-d.txt new file mode 100644 index 0000000000..2cb0e88e59 --- /dev/null +++ b/msautotest/misc/expected/map2img-argparse-d.txt @@ -0,0 +1 @@ +Argument -d needs 2 space separated arguments. diff --git a/msautotest/misc/expected/map2img-argparse-e.txt b/msautotest/misc/expected/map2img-argparse-e.txt new file mode 100644 index 0000000000..40b141cedb --- /dev/null +++ b/msautotest/misc/expected/map2img-argparse-e.txt @@ -0,0 +1 @@ +Argument -e needs 4 space separated arguments. diff --git a/msautotest/misc/expected/map2img-argparse-layer_debug.txt b/msautotest/misc/expected/map2img-argparse-layer_debug.txt new file mode 100644 index 0000000000..4885c1050a --- /dev/null +++ b/msautotest/misc/expected/map2img-argparse-layer_debug.txt @@ -0,0 +1 @@ +Argument -layer_debug needs 2 space separated arguments. diff --git a/msautotest/misc/expected/map2img-argparse-o.txt b/msautotest/misc/expected/map2img-argparse-o.txt new file mode 100644 index 0000000000..ae4c9b6859 --- /dev/null +++ b/msautotest/misc/expected/map2img-argparse-o.txt @@ -0,0 +1 @@ +Argument -o requires an additional argument. diff --git a/msautotest/misc/expected/map2img-argparse-s.txt b/msautotest/misc/expected/map2img-argparse-s.txt new file mode 100644 index 0000000000..06c1624b44 --- /dev/null +++ b/msautotest/misc/expected/map2img-argparse-s.txt @@ -0,0 +1 @@ +Argument -s needs 2 space separated arguments. diff --git a/msautotest/misc/expected/shp2img-size.gif b/msautotest/misc/expected/map2img-size.gif similarity index 100% rename from msautotest/misc/expected/shp2img-size.gif rename to msautotest/misc/expected/map2img-size.gif diff --git a/msautotest/misc/expected/map2img-size.png b/msautotest/misc/expected/map2img-size.png new file mode 100644 index 0000000000..26d1ea3ea9 Binary files /dev/null and b/msautotest/misc/expected/map2img-size.png differ diff --git a/msautotest/misc/expected/mode_tile_output.png b/msautotest/misc/expected/mode_tile_output.png new file mode 100644 index 0000000000..82c5c1e887 Binary files /dev/null and b/msautotest/misc/expected/mode_tile_output.png differ diff --git a/msautotest/misc/expected/mode_tile_output_512.png b/msautotest/misc/expected/mode_tile_output_512.png new file mode 100644 index 0000000000..31c17419ba Binary files /dev/null and b/msautotest/misc/expected/mode_tile_output_512.png differ diff --git a/msautotest/misc/expected/ogr_empty_geojson.json b/msautotest/misc/expected/ogr_empty_geojson.json index e3282c4f37..b7be8c4225 100644 --- a/msautotest/misc/expected/ogr_empty_geojson.json +++ b/msautotest/misc/expected/ogr_empty_geojson.json @@ -2,6 +2,7 @@ "type": "FeatureCollection", "name": "geojson", "crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:EPSG::3857" } }, +"xy_coordinate_resolution": 1e-05, "features": [ ] diff --git a/msautotest/misc/expected/ortho.png b/msautotest/misc/expected/ortho.png index 47fe80f574..0cc67fbe1f 100644 Binary files a/msautotest/misc/expected/ortho.png and b/msautotest/misc/expected/ortho.png differ diff --git a/msautotest/misc/expected/quoting.png b/msautotest/misc/expected/quoting.png index c987c3ed61..47cc8e04d1 100644 Binary files a/msautotest/misc/expected/quoting.png and b/msautotest/misc/expected/quoting.png differ diff --git a/msautotest/misc/expected/rfc14.png b/msautotest/misc/expected/rfc14.png index 3dce20f0a6..4a62f0aa1f 100644 Binary files a/msautotest/misc/expected/rfc14.png and b/msautotest/misc/expected/rfc14.png differ diff --git a/msautotest/misc/expected/runtime_sub_test001.txt b/msautotest/misc/expected/runtime_sub_test001.txt index 0b62d5b3ac..2f8a698ee5 100644 --- a/msautotest/misc/expected/runtime_sub_test001.txt +++ b/msautotest/misc/expected/runtime_sub_test001.txt @@ -1,7 +1,8 @@ Content-Type: text/html -MapServer Message +MapServer Message + msDrawMap(): Image handling error. Failed to draw layer named 'layer1'. [stripped line matching "ShapefileOpen"] [stripped line matching "ShapefileOpen"] diff --git a/msautotest/misc/expected/runtime_sub_test003.txt b/msautotest/misc/expected/runtime_sub_test003.txt index 223849a53c..7733e5bc26 100644 --- a/msautotest/misc/expected/runtime_sub_test003.txt +++ b/msautotest/misc/expected/runtime_sub_test003.txt @@ -1,7 +1,8 @@ Content-Type: text/html -MapServer Message +MapServer Message + msDrawMap(): Image handling error. Failed to draw layer named 'layer2'. [stripped line matching "ShapefileOpen"] [stripped line matching "ShapefileOpen"] diff --git a/msautotest/misc/expected/runtime_sub_test005.txt b/msautotest/misc/expected/runtime_sub_test005.txt index 3e473cc41b..1938752748 100644 --- a/msautotest/misc/expected/runtime_sub_test005.txt +++ b/msautotest/misc/expected/runtime_sub_test005.txt @@ -1,7 +1,8 @@ Content-Type: text/html -MapServer Message +MapServer Message + msDrawMap(): Image handling error. Failed to draw layer named 'layer3'. [stripped line matching "ShapefileOpen"] [stripped line matching "ShapefileOpen"] diff --git a/msautotest/misc/expected/runtime_sub_test_caps.xml b/msautotest/misc/expected/runtime_sub_test_caps.xml index b6a7fa7c49..35338fceee 100644 --- a/msautotest/misc/expected/runtime_sub_test_caps.xml +++ b/msautotest/misc/expected/runtime_sub_test_caps.xml @@ -2,10 +2,9 @@ Content-Type: text/xml; charset=UTF-8 - WMS - + runtime_sub @@ -34,132 +33,132 @@ Content-Type: text/xml; charset=UTF-8 runtime_sub - + runtime_sub runtime_sub EPSG:3857 - 1.12289 - 7.08771 - 39.4407 - 44.152 + 1.122894 + 7.087708 + 39.440727 + 44.152034 - layer1 - - layer1 - - - text/xml - - + layer1 + + layer1 + + + text/xml + + - layer2 - - layer2 - - - text/xml - - + layer2 + + layer2 + + + text/xml + + - layer3 - - layer3 - - - text/xml - - + layer3 + + layer3 + + + text/xml + + - layer5 - - layer5 - - 1.10894 - 7.19753 - 39.2727 - 44.1415 - - - - text/xml - - + layer5 + + layer5 + + 1.108938 + 7.197525 + 39.272716 + 44.141505 + + + + text/xml + + - layer5b - - layer5b - - 1.10894 - 7.19753 - 39.2727 - 44.1415 - - - - text/xml - - + layer5b + + layer5b + + 1.108938 + 7.197525 + 39.272716 + 44.141505 + + + + text/xml + + - layer6 - - layer6 - - 1.10894 - 7.19753 - 39.2727 - 44.1415 - - - - text/xml - - + layer6 + + layer6 + + 1.108938 + 7.197525 + 39.272716 + 44.141505 + + + + text/xml + + - layer7 - - layer7 - - 1.10894 - 7.19753 - 39.2727 - 44.1415 - - - - text/xml - - + layer7 + + layer7 + + 1.108938 + 7.197525 + 39.272716 + 44.141505 + + + + text/xml + + - layer8 - - layer8 - - 1.10894 - 7.19753 - 39.2727 - 44.1415 - - - - text/xml - - + layer8 + + layer8 + + 1.108938 + 7.197525 + 39.272716 + 44.141505 + + + + text/xml + + diff --git a/msautotest/misc/expected/scale_factor_inheritance.png b/msautotest/misc/expected/scale_factor_inheritance.png new file mode 100644 index 0000000000..5aa2d66910 Binary files /dev/null and b/msautotest/misc/expected/scale_factor_inheritance.png differ diff --git a/msautotest/misc/expected/scaletoken_filterexpression_192k.png b/msautotest/misc/expected/scaletoken_filterexpression_192k.png new file mode 100644 index 0000000000..5ec2916013 Binary files /dev/null and b/msautotest/misc/expected/scaletoken_filterexpression_192k.png differ diff --git a/msautotest/misc/expected/scaletoken_filterexpression_424k.png b/msautotest/misc/expected/scaletoken_filterexpression_424k.png new file mode 100644 index 0000000000..72dbbe9bf2 Binary files /dev/null and b/msautotest/misc/expected/scaletoken_filterexpression_424k.png differ diff --git a/msautotest/misc/expected/shp2img-size.png b/msautotest/misc/expected/shp2img-size.png deleted file mode 100644 index 3e6bfcaae9..0000000000 Binary files a/msautotest/misc/expected/shp2img-size.png and /dev/null differ diff --git a/msautotest/misc/expected/shp_encodings.png b/msautotest/misc/expected/shp_encodings.png new file mode 100644 index 0000000000..364283169f Binary files /dev/null and b/msautotest/misc/expected/shp_encodings.png differ diff --git a/msautotest/misc/expected/tile_scale_z2.png b/msautotest/misc/expected/tile_scale_z2.png new file mode 100644 index 0000000000..dd1e62af39 Binary files /dev/null and b/msautotest/misc/expected/tile_scale_z2.png differ diff --git a/msautotest/misc/expected/tile_scale_z3.png b/msautotest/misc/expected/tile_scale_z3.png new file mode 100644 index 0000000000..e21212f28d Binary files /dev/null and b/msautotest/misc/expected/tile_scale_z3.png differ diff --git a/msautotest/misc/expected/tile_scale_z4.png b/msautotest/misc/expected/tile_scale_z4.png new file mode 100644 index 0000000000..dd1e62af39 Binary files /dev/null and b/msautotest/misc/expected/tile_scale_z4.png differ diff --git a/msautotest/misc/expected/union.png b/msautotest/misc/expected/union.png new file mode 100644 index 0000000000..7cb9408719 Binary files /dev/null and b/msautotest/misc/expected/union.png differ diff --git a/msautotest/misc/expected/wms.html b/msautotest/misc/expected/wms.html new file mode 100644 index 0000000000..ab74b4db8c --- /dev/null +++ b/msautotest/misc/expected/wms.html @@ -0,0 +1,52 @@ + + + + + + MapServer Simple Viewer + + + + + +
+ + + + \ No newline at end of file diff --git a/msautotest/misc/expected/wms_cluster_cap.xml b/msautotest/misc/expected/wms_cluster_cap.xml new file mode 100644 index 0000000000..846b4336ed --- /dev/null +++ b/msautotest/misc/expected/wms_cluster_cap.xml @@ -0,0 +1,131 @@ +Content-Type: application/vnd.ogc.wms_xml; charset=UTF-8 + + + + ]> + + + + OGC:WMS + + clusters + + + + + + + + + application/vnd.ogc.wms_xml + + + + + + + + + image/png + image/jpeg + image/png; mode=8bit + image/vnd.jpeg-png + image/vnd.jpeg-png8 + application/x-pdf + image/svg+xml + image/tiff + application/vnd.google-earth.kml+xml + application/vnd.google-earth.kmz + application/vnd.mapbox-vector-tile + application/x-protobuf + application/json + + + + + + + + + text/plain + application/vnd.ogc.gml + + + + + + + + + text/xml + + + + + + + + + image/png + image/jpeg + image/png; mode=8bit + image/vnd.jpeg-png + image/vnd.jpeg-png8 + + + + + + + + + text/xml + + + + + + + + + + application/vnd.ogc.se_xml + application/vnd.ogc.se_inimage + application/vnd.ogc.se_blank + + + + + clusters + + clusters + clusters + EPSG:3978 + + + + popplace + + popplace + + + + text/xml + + + + + + + diff --git a/msautotest/misc/expected/wms_cluster_cap_latestversion.xml b/msautotest/misc/expected/wms_cluster_cap_latestversion.xml new file mode 100644 index 0000000000..c374eac134 --- /dev/null +++ b/msautotest/misc/expected/wms_cluster_cap_latestversion.xml @@ -0,0 +1,137 @@ +Content-Type: text/xml; charset=UTF-8 + + + + + WMS + + clusters + + + + 4096 + 4096 + + + + + + text/xml + + + + + + + + + image/png + image/jpeg + image/png; mode=8bit + image/vnd.jpeg-png + image/vnd.jpeg-png8 + application/x-pdf + image/svg+xml + image/tiff + application/vnd.google-earth.kml+xml + application/vnd.google-earth.kmz + application/vnd.mapbox-vector-tile + application/x-protobuf + application/json + + + + + + + + + text/plain + application/vnd.ogc.gml + + + + + + + + + text/xml + + + + + + + + + image/png + image/jpeg + image/png; mode=8bit + image/vnd.jpeg-png + image/vnd.jpeg-png8 + + + + + + + + + text/xml + + + + + + + + + + XML + INIMAGE + BLANK + + + + clusters + + clusters + clusters + EPSG:3978 + + -66.328620 + -59.688211 + 42.563121 + 47.941252 + + + + popplace + + popplace + + -66.328617 + -59.688212 + 42.563125 + 47.941251 + + + + text/xml + + + + + + + diff --git a/msautotest/misc/expected/wms_get_map_cluster.png b/msautotest/misc/expected/wms_get_map_cluster.png new file mode 100644 index 0000000000..391bf3125c Binary files /dev/null and b/msautotest/misc/expected/wms_get_map_cluster.png differ diff --git a/msautotest/misc/expected/wms_invalid_parameter1.html b/msautotest/misc/expected/wms_invalid_parameter1.html new file mode 100644 index 0000000000..4d55628225 --- /dev/null +++ b/msautotest/misc/expected/wms_invalid_parameter1.html @@ -0,0 +1,7 @@ + + + + +msWMSLoadGetMapParams(): WMS server error. Missing required parameter SRS + + diff --git a/msautotest/misc/expected/wms_invalid_parameter2.html b/msautotest/misc/expected/wms_invalid_parameter2.html new file mode 100644 index 0000000000..e1ed37e67f --- /dev/null +++ b/msautotest/misc/expected/wms_invalid_parameter2.html @@ -0,0 +1,52 @@ + + + + + + MapServer Simple Viewer + + + + + +
+ + + + \ No newline at end of file diff --git a/msautotest/misc/expected/wms_invalid_parameter3.html b/msautotest/misc/expected/wms_invalid_parameter3.html new file mode 100644 index 0000000000..e47a30a266 --- /dev/null +++ b/msautotest/misc/expected/wms_invalid_parameter3.html @@ -0,0 +1,6 @@ + + + +msWMSLoadGetMapParams(): WMS server error. Unsupported CRS namespace (CRS must be in the format AUTH:XXXX). + + diff --git a/msautotest/misc/expected/wms_projected.html b/msautotest/misc/expected/wms_projected.html new file mode 100644 index 0000000000..6e349fac74 --- /dev/null +++ b/msautotest/misc/expected/wms_projected.html @@ -0,0 +1,52 @@ + + + + + + MapServer Simple Viewer + + + + + +
+ + + + \ No newline at end of file diff --git a/msautotest/misc/expected/wms_projected_extra.html b/msautotest/misc/expected/wms_projected_extra.html new file mode 100644 index 0000000000..e1ed37e67f --- /dev/null +++ b/msautotest/misc/expected/wms_projected_extra.html @@ -0,0 +1,52 @@ + + + + + + MapServer Simple Viewer + + + + + +
+ + + + \ No newline at end of file diff --git a/msautotest/misc/flatgeobuf-shapepath.map b/msautotest/misc/flatgeobuf-shapepath.map new file mode 100644 index 0000000000..a7c4b60d5c --- /dev/null +++ b/msautotest/misc/flatgeobuf-shapepath.map @@ -0,0 +1,71 @@ +# +# Test FlatGeobuf native access (RFC 137), but using SHAPEPATH +# +# REQUIRES: INPUT=FLATGEOBUF +# +#RUN_PARMS: flatgeobuf-shapepath-continent.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] -l africa-continent +#RUN_PARMS: flatgeobuf-shapepath-classes.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] -l africa-classes + +MAP + NAME "fgb-test" + STATUS ON + SIZE 400 300 + EXTENT -17.625043 -34.819166 51.133870 37.349994 + UNITS DD + IMAGECOLOR 255 255 255 + SHAPEPATH "./data" + IMAGETYPE png + + /* Africa Continent */ + LAYER + NAME "africa-continent" + TYPE POLYGON + STATUS ON + CONNECTIONTYPE flatgeobuf + DATA "africa.fgb" + CLASS + NAME "Africa Continent" + STYLE + COLOR 50 50 50 + OUTLINECOLOR 120 120 120 + END #style + END #class + END # layer + + /* Africa classes */ + LAYER + NAME "africa-classes" + TYPE POLYGON + STATUS ON + CONNECTIONTYPE flatgeobuf + DATA "africa.fgb" + CLASSITEM "name_en" + CLASS + NAME "Tanzania" + EXPRESSION "Tanzania" + STYLE + COLOR 100 223 69 + OUTLINECOLOR 120 120 120 + END #style + END #class + CLASS + NAME "Kenya" + EXPRESSION "Kenya" + STYLE + COLOR 120 220 123 + OUTLINECOLOR 120 120 120 + END #style + END #class + TEMPLATE "ttt.html" + CLASS + NAME "Zambia" + EXPRESSION "Zambia" + STYLE + COLOR 37 234 224 + OUTLINECOLOR 120 120 120 + END #style + END #class + TEMPLATE "ttt.html" + END # layer + +END # map diff --git a/msautotest/misc/flatgeobuf.map b/msautotest/misc/flatgeobuf.map new file mode 100644 index 0000000000..02dca6afb9 --- /dev/null +++ b/msautotest/misc/flatgeobuf.map @@ -0,0 +1,130 @@ +# +# Test FlatGeobuf native access (RFC 137) +# +# REQUIRES: INPUT=FLATGEOBUF SUPPORTS=WFS +# +#RUN_PARMS: flatgeobuf-continent.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] -l africa-continent +#RUN_PARMS: flatgeobuf-classes.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] -l africa-classes +# Given extent is fully in the Atlantic Ocean therefore no feature is selected and the result empty +#RUN_PARMS: flatgeobuf-ocean.png [MAP2IMG] -m [MAPFILE] -i png -e -7 -17 -4 -14 -s 50 50 -o [RESULT] -l africa-continent +# +# WFS 1.0.0 +# +# Capabilities +# RUN_PARMS: flatgeobuf-wfs-cap.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetCapabilities" > [RESULT_DEVERSION] +# +# Feature types description +# RUN_PARMS: flatgeobuf-wfs-describe.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=DescribeFeatureType" > [RESULT] +# +# Generate simple layer info. +# RUN_PARMS: flatgeobuf-wfs-get-feature.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=africa-continent" > [RESULT] +# +# Generate layer info using property name. +# RUN_PARMS: flatgeobuf-wfs-get-feature-propertyname.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=africa-continent&propertyname=(name_en)" > [RESULT] +# +# Generate layer info using property name and a geometry property. +# RUN_PARMS: flatgeobuf-wfs-get-feature-propertyname-geometry.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=africa-continent&propertyname=(name_en,msGeometry)" > [RESULT] +# +# Get Feature by id +# RUN_PARMS: flatgeobuf-wfs-get-feature-id.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=africa-continent&featureid=africa-continent.46" > [RESULT] +# +MAP + NAME "fgb-test" + STATUS ON + SIZE 400 300 + EXTENT -17.625043 -34.819166 51.133870 37.349994 + UNITS DD + IMAGECOLOR 255 255 255 + IMAGETYPE png + + WEB + METADATA + "wfs_title" "Test FlatGeobuf WFS output" + "wfs_abstract" "Longer text describing the FlatGeobuf WFS service." + "wfs_onlineresource" "http://localhost/path/to/flatgeobuf?" + "wfs_srs" "EPSG:4326 EPSG:4269 EPSG:3978 EPSG:3857" + "wfs_enable_request" "*" + END + END + + PROJECTION + "init=epsg:4326" + END + + /* Africa Continent */ + LAYER + NAME "africa-continent" + METADATA + "wfs_title" "Africa Continent" + "wfs_srs" "EPSG:4326" + "gml_include_items" "all" + "gml_featureid" "id" + "gml_types" "auto" + "wfs_enable_request" "*" + "wfs_use_default_extent_for_getfeature" "false" + END + TYPE POLYGON + STATUS ON + CONNECTIONTYPE flatgeobuf + DATA "data/africa.fgb" + CLASS + NAME "Africa Continent" + STYLE + COLOR 50 50 50 + OUTLINECOLOR 120 120 120 + END #style + END #class + PROJECTION + "init=epsg:4326" + END + END # layer + + /* Africa classes */ + LAYER + NAME "africa-classes" + METADATA + "wfs_title" "Africa Classes" + "wfs_srs" "EPSG:4326" + "gml_include_items" "all" + "gml_featureid" "id" + "gml_types" "auto" + "wfs_enable_request" "*" + "wfs_use_default_extent_for_getfeature" "false" + END + TYPE POLYGON + STATUS ON + CONNECTIONTYPE flatgeobuf + DATA "data/africa.fgb" + CLASSITEM "name_en" + CLASS + NAME "Tanzania" + EXPRESSION "Tanzania" + STYLE + COLOR 100 223 69 + OUTLINECOLOR 120 120 120 + END #style + END #class + CLASS + NAME "Kenya" + EXPRESSION "Kenya" + STYLE + COLOR 120 220 123 + OUTLINECOLOR 120 120 120 + END #style + END #class + TEMPLATE "ttt.html" + CLASS + NAME "Zambia" + EXPRESSION "Zambia" + STYLE + COLOR 37 234 224 + OUTLINECOLOR 120 120 120 + END #style + END #class + TEMPLATE "ttt.html" + PROJECTION + AUTO + END + END # layer + +END # map diff --git a/msautotest/misc/fonts.lst b/msautotest/misc/fonts.lst index 6f6ca8f290..0498f3c9cc 100644 --- a/msautotest/misc/fonts.lst +++ b/msautotest/misc/fonts.lst @@ -3,4 +3,4 @@ sans data/DejaVuSans.ttf lucida data/LucidaBrightRegular.ttf arabic data/DroidNaskh-Regular.ttf hindi data/DroidSansDevanagari-Regular.ttf -bogus /path/to/inexistant/file.ttf +bogus /path/to/inexistent/file.ttf diff --git a/msautotest/misc/geopdf.map b/msautotest/misc/geopdf.map index 28999b8827..dd7311915b 100644 --- a/msautotest/misc/geopdf.map +++ b/msautotest/misc/geopdf.map @@ -1,5 +1,5 @@ -# RUN_PARMS: geopdf-iso.pdf [SHP2IMG] -m [MAPFILE] -i geopdfiso -o [RESULT] -# RUN_PARMS: geopdf-ogc.pdf [SHP2IMG] -m [MAPFILE] -i geopdfogc -o [RESULT] +# RUN_PARMS: geopdf-iso.pdf [MAP2IMG] -m [MAPFILE] -i geopdfiso -o [RESULT] +# RUN_PARMS: geopdf-ogc.pdf [MAP2IMG] -m [MAPFILE] -i geopdfogc -o [RESULT] MAP IMAGECOLOR 255 255 255 diff --git a/msautotest/misc/issue5558.map b/msautotest/misc/issue5558.map index f990e6056a..6407895075 100644 --- a/msautotest/misc/issue5558.map +++ b/msautotest/misc/issue5558.map @@ -1,9 +1,9 @@ # # Tests bugfix for https://github.com/mapserver/mapserver/issues/5558 -# "Missing LABEL TEXT attribute bind causes crash in shp2img" +# "Missing LABEL TEXT attribute bind causes crash in map2img" # -# RUN_PARMS: issue5581-1.png [SHP2IMG] -m [MAPFILE] -o [RESULT] -# RUN_PARMS: issue5581-2.png [SHP2IMG] -c 2 -m [MAPFILE] -o [RESULT] +# RUN_PARMS: issue5581-1.png [MAP2IMG] -m [MAPFILE] -o [RESULT] +# RUN_PARMS: issue5581-2.png [MAP2IMG] -c 2 -m [MAPFILE] -o [RESULT] MAP EXTENT 0 0 100 100 diff --git a/msautotest/misc/line_offset_clipped_to_multiline.map b/msautotest/misc/line_offset_clipped_to_multiline.map new file mode 100644 index 0000000000..947d96428c --- /dev/null +++ b/msautotest/misc/line_offset_clipped_to_multiline.map @@ -0,0 +1,34 @@ +# REQUIRES: INPUT=SHAPE OUTPUT=PNG +# +# Test shifted offset when line is being clipped to a multi-line containing multi-lines. +# + +MAP + EXTENT 387200 6544755 388224 6545779 + SIZE 128 128 + IMAGETYPE png + + LAYER + NAME "Test" + STATUS ON + TYPE LINE + FEATURE + POINTS + 387184.7628 6544765.9766500005 + 387189.844 6544759.04235 + 387215.864 6544756.3572 + 387212.7508 6544765.81515 + 387183.058 6544782.9486 + 387186.706 6544811.9778 + 389248 6546803 + END + END + + CLASS + STYLE + COLOR 255 0 0 + OFFSET -1 -99 + END + END + END +END \ No newline at end of file diff --git a/msautotest/misc/map2img-argparse.map b/msautotest/misc/map2img-argparse.map new file mode 100644 index 0000000000..a269e132c1 --- /dev/null +++ b/msautotest/misc/map2img-argparse.map @@ -0,0 +1,38 @@ +# +# Tests map2img incomplete arguments +# +# RUN_PARMS: map2img-argparse-s.txt [MAP2IMG] -m [MAPFILE] -s 640 > [RESULT] 2>&1 [ASAN_SKIP_LOG] +# RUN_PARMS: map2img-argparse-e.txt [MAP2IMG] -m [MAPFILE] -e 0 1 > [RESULT] 2>&1 [ASAN_SKIP_LOG] +# RUN_PARMS: map2img-argparse-o.txt [MAP2IMG] -m [MAPFILE] -o > [RESULT] 2>&1 [ASAN_SKIP_LOG] +# RUN_PARMS: map2img-argparse-c.txt [MAP2IMG] -m [MAPFILE] -c > [RESULT] 2>&1 [ASAN_SKIP_LOG] +# RUN_PARMS: map2img-argparse-d.txt [MAP2IMG] -m [MAPFILE] -d otherlayer > [RESULT] 2>&1 [ASAN_SKIP_LOG] +# RUN_PARMS: map2img-argparse-layer_debug.txt [MAP2IMG] -m [MAPFILE] -layer_debug 3 > [RESULT] 2>&1 [ASAN_SKIP_LOG] + +MAP + NAME HELLO + STATUS ON + EXTENT 59 10 60 11 + SIZE 400 300 + IMAGECOLOR 200 255 255 + + IMAGETYPE png + + LAYER + NAME "credits" + STATUS DEFAULT + TRANSFORM FALSE + TYPE POINT + FEATURE + POINTS + 200 250 + END + TEXT 'Hello world' + END + CLASS + LABEL + TYPE BITMAP + COLOR 0 0 0 + END + END + END +END diff --git a/msautotest/misc/map2img-size.map b/msautotest/misc/map2img-size.map new file mode 100644 index 0000000000..b23520c0eb --- /dev/null +++ b/msautotest/misc/map2img-size.map @@ -0,0 +1,33 @@ +# +# Tests map2img binary to ensure size option is respected. +# +# RUN_PARMS: map2img-size.png [MAP2IMG] -s 640 480 -m [MAPFILE] -o [RESULT] + +MAP + NAME HELLO + STATUS ON + EXTENT 59 10 60 11 + SIZE 400 300 + IMAGECOLOR 200 255 255 + + IMAGETYPE png + + LAYER + NAME "credits" + STATUS DEFAULT + TRANSFORM FALSE + TYPE POINT + FEATURE + POINTS + 200 250 + END + TEXT 'Hello world' + END + CLASS + LABEL + TYPE BITMAP + COLOR 0 0 0 + END + END + END +END diff --git a/msautotest/misc/maxfeatures.map b/msautotest/misc/maxfeatures.map index 5778c0c0d5..7f65ac55a2 100644 --- a/msautotest/misc/maxfeatures.map +++ b/msautotest/misc/maxfeatures.map @@ -1,5 +1,5 @@ -# RUN_PARMS: maxfeatures.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: maxfeatures-of.png [SHP2IMG] -m [MAPFILE] -i pngmf -o [RESULT] +# RUN_PARMS: maxfeatures.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: maxfeatures-of.png [MAP2IMG] -m [MAPFILE] -i pngmf -o [RESULT] MAP IMAGECOLOR 255 255 255 diff --git a/msautotest/misc/mode_tile.map b/msautotest/misc/mode_tile.map new file mode 100644 index 0000000000..a2b50b7b18 --- /dev/null +++ b/msautotest/misc/mode_tile.map @@ -0,0 +1,39 @@ +# +# Test of mode=tile (CGI "tile mode"). A 256x256 tile should be generated +# in the "gmap" tilemode, reprojected to the Google Mercator (EPSG:3857) +# and displayed at the global extent. +# +# REQUIRES: INPUT=OGR OUTPUT=PNG SUPPORTS=PROJ +# +# RUN_PARMS: mode_tile_output.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&MODE=tile&TILEMODE=gmap&TILE=0+0+0&LAYERS=canada-poly" > [RESULT_DEMIME] +# RUN_PARMS: mode_tile_output_512.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&MODE=tile&TILEMODE=gmap&TILE=0+0+0&TILESIZE=512+512&LAYERS=canada-poly" > [RESULT_DEMIME] +# +MAP + NAME "MODE_TILE_TEST" + IMAGETYPE PNG + EXTENT -140.992892 41.976786 -55.630945 71.990315 + SIZE 400 400 + + PROJECTION + "init=epsg:4326" + END #projection + + LAYER + NAME "canada-poly" + TYPE POLYGON + STATUS DEFAULT + CONNECTIONTYPE OGR + CONNECTION "data/canada.dgn" + DATA "elements" + PROJECTION + "init=epsg:4326" + END #projection + CLASS + STYLE + OUTLINECOLOR 0 0 0 + COLOR 120 120 120 + END + END #class + END #layer + +END #map diff --git a/msautotest/misc/multipoint.map b/msautotest/misc/multipoint.map index c2d40dc241..a37560ebc5 100644 --- a/msautotest/misc/multipoint.map +++ b/msautotest/misc/multipoint.map @@ -33,9 +33,11 @@ LAYER CLASSITEM "FID" CLASS NAME "test1" - COLOR 0 255 0 - SYMBOL 'cross' - SIZE 5 + STYLE + COLOR 0 255 0 + SYMBOL 'cross' + SIZE 5 + END END END diff --git a/msautotest/misc/ogr_attrfilter.map b/msautotest/misc/ogr_attrfilter.map index bad933b55b..69f83e346a 100644 --- a/msautotest/misc/ogr_attrfilter.map +++ b/msautotest/misc/ogr_attrfilter.map @@ -22,8 +22,10 @@ LAYER CLASSITEM "AREA" CLASS NAME "test1" - COLOR 0 255 0 - OUTLINECOLOR 255 0 0 + STYLE + COLOR 0 255 0 + OUTLINECOLOR 255 0 0 + END END END diff --git a/msautotest/misc/ogr_direct.map b/msautotest/misc/ogr_direct.map index f07b817da4..24dbfe9762 100644 --- a/msautotest/misc/ogr_direct.map +++ b/msautotest/misc/ogr_direct.map @@ -1,29 +1,31 @@ -# -# Simple OGR Render. -# -# REQUIRES: INPUT=OGR OUTPUT=PNG -# -MAP - -STATUS ON -EXTENT 478300 4762880 481650 4765610 -SIZE 400 300 - -IMAGETYPE png - -LAYER - NAME shppoly - TYPE polygon - CONNECTIONTYPE OGR - CONNECTION "data/shppoly/poly.shp" - DATA "poly" - STATUS default - CLASSITEM "AREA" - CLASS - NAME "test1" - COLOR 0 255 0 - OUTLINECOLOR 255 0 0 - END -END - -END +# +# Simple OGR Render. +# +# REQUIRES: INPUT=OGR OUTPUT=PNG +# +MAP + +STATUS ON +EXTENT 478300 4762880 481650 4765610 +SIZE 400 300 + +IMAGETYPE png + +LAYER + NAME shppoly + TYPE polygon + CONNECTIONTYPE OGR + CONNECTION "data/shppoly/poly.shp" + DATA "poly" + STATUS default + CLASSITEM "AREA" + CLASS + NAME "test1" + STYLE + COLOR 0 255 0 + OUTLINECOLOR 255 0 0 + END + END +END + +END diff --git a/msautotest/misc/ogr_join.map b/msautotest/misc/ogr_join.map index 6527e6767d..7f9454ab13 100644 --- a/msautotest/misc/ogr_join.map +++ b/msautotest/misc/ogr_join.map @@ -24,14 +24,18 @@ LAYER CLASSITEM "idlink.Name" CLASS NAME "selected" - COLOR 0 0 255 - OUTLINECOLOR 255 0 0 + STYLE + COLOR 0 0 255 + OUTLINECOLOR 255 0 0 + END EXPRESSION "_158_" END CLASS NAME "normal" - COLOR 0 255 0 - OUTLINECOLOR 255 0 0 + STYLE + COLOR 0 255 0 + OUTLINECOLOR 255 0 0 + END END END diff --git a/msautotest/misc/ogr_multi_defer.map b/msautotest/misc/ogr_multi_defer.map index af577088fb..d2513e49ca 100644 --- a/msautotest/misc/ogr_multi_defer.map +++ b/msautotest/misc/ogr_multi_defer.map @@ -23,8 +23,10 @@ LAYER CLASSITEM "AREA" CLASS NAME "test1" - COLOR 0 0 255 - OUTLINECOLOR 255 128 0 + STYLE + COLOR 0 0 255 + OUTLINECOLOR 255 128 0 + END END END @@ -40,8 +42,10 @@ LAYER CLASSITEM "AREA" CLASS NAME "test1" - COLOR 0 255 0 - OUTLINECOLOR 255 0 0 + STYLE + COLOR 0 255 0 + OUTLINECOLOR 255 0 0 + END END END diff --git a/msautotest/misc/ogr_select.map b/msautotest/misc/ogr_select.map index 899c9b4ce8..5945205c9f 100644 --- a/msautotest/misc/ogr_select.map +++ b/msautotest/misc/ogr_select.map @@ -21,8 +21,10 @@ LAYER CLASSITEM "AREA" CLASS NAME "test1" - COLOR 0 255 0 - OUTLINECOLOR 255 0 0 + STYLE + COLOR 0 255 0 + OUTLINECOLOR 255 0 0 + END END END diff --git a/msautotest/misc/ogr_vrtconnect.map b/msautotest/misc/ogr_vrtconnect.map index e6af9a367c..f62f42f131 100644 --- a/msautotest/misc/ogr_vrtconnect.map +++ b/msautotest/misc/ogr_vrtconnect.map @@ -21,8 +21,10 @@ LAYER CLASSITEM "AREA" CLASS NAME "test1" - COLOR 0 255 0 - OUTLINECOLOR 255 0 0 + STYLE + COLOR 0 255 0 + OUTLINECOLOR 255 0 0 + END END END diff --git a/msautotest/misc/ogr_wkt.map b/msautotest/misc/ogr_wkt.map index 36d92d2d9b..c4aa62e1fd 100644 --- a/msautotest/misc/ogr_wkt.map +++ b/msautotest/misc/ogr_wkt.map @@ -9,8 +9,6 @@ MAP IMAGETYPE png - TRANSPARENT OFF - SIZE 400 300 EXTENT 0 0 4000 3000 UNITS meters @@ -38,7 +36,7 @@ MAP WKT "MULTIPOLYGON(((50 50, 350 50, 350 250, 50 250, 50 50)),((250 150, 550 150, 550 350, 250 350, 250 150)))" END CLASS - COLOR 0 255 0 + STYLE COLOR 0 255 0 END END # CLASS END @@ -53,9 +51,11 @@ MAP WKT "MULTIPOINT(2000 2000, 2000 1900)" END CLASS - COLOR 0 0 255 - SYMBOL 'cross' - SIZE 5 + STYLE + COLOR 0 0 255 + SYMBOL 'cross' + SIZE 5 + END END # CLASS END @@ -70,7 +70,7 @@ MAP WKT "MULTILINESTRING((600 1500, 1600 2500),(700 1500,1700 2500))" END CLASS - COLOR 255 0 0 + STYLE COLOR 255 0 0 END END # CLASS END END diff --git a/msautotest/misc/ogrpen.map b/msautotest/misc/ogrpen.map index a9dbdff1f6..b35c38dff2 100644 --- a/msautotest/misc/ogrpen.map +++ b/msautotest/misc/ogrpen.map @@ -1,5 +1,7 @@ # Test OGR feature style PEN parameters +# RUN_PARMS: ogrpen.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&layer=test&mode=map" > [RESULT_DEMIME] + MAP EXTENT 0 -1 1 1 SIZE 200 400 diff --git a/msautotest/misc/openlayers.map b/msautotest/misc/openlayers.map new file mode 100644 index 0000000000..ce0d21043a --- /dev/null +++ b/msautotest/misc/openlayers.map @@ -0,0 +1,80 @@ +# Test OpenLayers HTML template output through CGI and WMS + +# RUN_PARMS: browse.html [MAPSERV] QUERY_STRING="map=[MAPFILE]&layers=world-polys world-lines&mode=browse&template=openlayers" > [RESULT_DEMIME] +# RUN_PARMS: browse_all.html [MAPSERV] QUERY_STRING="map=[MAPFILE]&layers=all&mode=browse&template=openlayers" > [RESULT_DEMIME] +# RUN_PARMS: browse_invalid.html [MAPSERV] QUERY_STRING="map=[MAPFILE]&layers=x%3C/script%3E%3Cimg%20src%3Dx%20onerror%3Dalert(document.domain)%3E%3Cscript%3E&mode=browse&template=openlayers&SRS=x%3C/script%3E%3Cimg%20src%3Dx%20onerror%3Dalert(document.domain)%3E%3Cscript%3E" > [RESULT_DEMIME] +# RUN_PARMS: wms.html [MAPSERV] QUERY_STRING="map=[MAPFILE]&REQUEST=GetMap&SERVICE=WMS&VERSION=1.3.0&FORMAT=application/openlayers&STYLES=&TRANSPARENT=false&LAYERS=world-polys,world-lines,quotes%27&WIDTH=956&HEIGHT=705&CRS=EPSG:4326&BBOX=-180,-90,180,90" > [RESULT_DEMIME] +# RUN_PARMS: wms_projected.html [MAPSERV] QUERY_STRING="map=[MAPFILE]&REQUEST=GetMap&SERVICE=WMS&VERSION=1.3.0&FORMAT=application/openlayers&STYLES=&TRANSPARENT=false&LAYERS=world-polys,world-lines&WIDTH=956&HEIGHT=705&CRS=EPSG:3857&BBOX=-20037508.34,-20048966.1,20037508.34,20048966.1" > [RESULT_DEMIME] +# RUN_PARMS: wms_projected_extra.html [MAPSERV] QUERY_STRING="map=[MAPFILE]&REQUEST=GetMap&SERVICE=WMS&VERSION=1.3.0&FORMAT=application/openlayers&STYLES=&TRANSPARENT=false&LAYERS=world-polys,world-lines&WIDTH=956&HEIGHT=705&CRS=EPSG:3395&BBOX=-20037508.34,-15496570.74,20037508.34,18764656.23" > [RESULT_DEMIME] +# RUN_PARMS: wms_invalid_parameter1.html [MAPSERV] QUERY_STRING="map=[MAPFILE]&REQUEST=GetMap&SERVICE=WMS&VERSION=1.1.1&FORMAT=application/openlayers&STYLES=&TRANSPARENT=false&LAYERS=world-polys,world-lines&WIDTH=956&HEIGHT=705&CRS=x%3C/script%3E%3Cimg%20src%3Dx%20onerror%3Dalert(document.domain)%3E%3Cscript%3E&BBOX=-20037508.34,-15496570.74,20037508.34,18764656.23" > [RESULT_DEMIME] +# RUN_PARMS: wms_invalid_parameter2.html [MAPSERV] QUERY_STRING="map=[MAPFILE]&REQUEST=GetMap&SERVICE=WMS&VERSION=1.3.0&FORMAT=application/openlayers&STYLES=&TRANSPARENT=false&LAYERS=world-polys,world-lines&WIDTH=956&HEIGHT=705&CRS=EPSG:3395&SRS=x%3C/script%3E%3Cimg%20src%3Dx%20onerror%3Dalert(document.domain)%3E%3Cscript%3E&BBOX=-20037508.34,-15496570.74,20037508.34,18764656.23" > [RESULT_DEMIME] +# RUN_PARMS: wms_invalid_parameter3.html [MAPSERV] QUERY_STRING="map=[MAPFILE]&REQUEST=GetMap&SERVICE=WMS&VERSION=1.3.0&FORMAT=application/openlayers&STYLES=&TRANSPARENT=false&LAYERS=world-polys,world-lines&WIDTH=956&HEIGHT=705&CRS=x%3C/script%3E%3Cimg%20src%3Dx%20onerror%3Dalert(document.domain)%3E%3Cscript%3E&BBOX=-20037508.34,-15496570.74,20037508.34,18764656.23" > [RESULT_DEMIME] + +# REQUIRES: INPUT=SHAPE OUTPUT=PNG SUPPORTS=PROJ SUPPORTS=WMS +# + +MAP + NAME 'OpenLayersTest' + IMAGETYPE PNG + EXTENT -180 -90 180 90 + SIZE 400 400 + + # can also test with OpenLayers hosted on a CDN + # CONFIG "MS_OPENLAYERS_JS_URL" "//cdn.jsdelivr.net/npm/ol@v10.5.0/dist/ol.js" + # CONFIG "MS_OPENLAYERS_CSS_URL" "//cdn.jsdelivr.net/npm/ol@v10.5.0/ol.css" + + WEB + METADATA + # for testing output locally change the following to point to a MapServer URL and location of this Mapfile + "ows_onlineresource" "http://localhost/?map=msautotest/misc/openlayers.map&" + # required for both CGI and WMS + "wms_enable_request" "GetMap" # required for WMS testing + # following required for WMS + "wms_srs" "EPSG:4326 EPSG:3857 EPSG:3395" + END + END + + PROJECTION + "+init=epsg:4326" + END + + LAYER + NAME "world-polys" + TYPE POLYGON + STATUS OFF + DATA "data/world_testpoly.shp" + CLASS + STYLE + OUTLINECOLOR 255 0 0 + COLOR 0 255 0 + END + END + END + + LAYER + NAME "world-lines" + TYPE LINE + STATUS OFF + DATA "data/testlines.shp" + CLASS + STYLE + WIDTH 0.5 + COLOR 0 0 0 + END + END + END + + LAYER + NAME "quotes'" + TYPE LINE + STATUS OFF + DATA "data/testlines.shp" + CLASS + STYLE + WIDTH 0.5 + COLOR 255 0 0 + END + END + END + +END diff --git a/msautotest/misc/ortho.map b/msautotest/misc/ortho.map index 426bc37746..9d6a531068 100644 --- a/msautotest/misc/ortho.map +++ b/msautotest/misc/ortho.map @@ -24,8 +24,10 @@ MAP "+proj=latlong +datum=WGS84" END CLASS - OUTLINECOLOR 255 0 0 - COLOR 0 255 0 + STYLE + OUTLINECOLOR 255 0 0 + COLOR 0 255 0 + END END END LAYER @@ -37,7 +39,7 @@ MAP "+proj=latlong +datum=WGS84" END CLASS - COLOR 255 255 0 + STYLE COLOR 255 255 0 END END END END diff --git a/msautotest/misc/quoting.map b/msautotest/misc/quoting.map index 55e3ae9a2b..7ad9f99dc4 100644 --- a/msautotest/misc/quoting.map +++ b/msautotest/misc/quoting.map @@ -31,14 +31,16 @@ LAYER "init=epsg:3978" END - DUMP TRUE LabelItem "Name" CLASSITEM "Name" CLASS EXPRESSION "\"Tignish" - SYMBOL 2 - SIZE 8 + STYLE + SYMBOL 2 + SIZE 8 + COLOR 0 0 0 + END LABEL FORCE true COLOR 0 255 0 @@ -49,12 +51,14 @@ LAYER PARTIALS FALSE OUTLINECOLOR 255 255 255 END - COLOR 0 0 0 END CLASS EXPRESSION '\'Souris\'' - SYMBOL 2 - SIZE 8 + STYLE + SYMBOL 2 + SIZE 8 + COLOR 0 0 0 + END LABEL FORCE true COLOR 0 0 255 @@ -65,12 +69,14 @@ LAYER PARTIALS FALSE OUTLINECOLOR 255 255 255 END - COLOR 0 0 0 END CLASS EXPRESSION ("[NAME]" = "Tr\"uro") - SYMBOL 2 - SIZE 8 + STYLE + SYMBOL 2 + SIZE 8 + COLOR 0 0 0 + END LABEL FORCE true COLOR 255 0 0 @@ -81,12 +87,14 @@ LAYER PARTIALS FALSE OUTLINECOLOR 255 255 255 END - COLOR 0 0 0 END CLASS EXPRESSION ("[NAME]" = '\'Cheticamp') - SYMBOL 2 - SIZE 8 + STYLE + SYMBOL 2 + SIZE 8 + COLOR 0 0 0 + END LABEL FORCE true COLOR 255 0 0 @@ -97,11 +105,13 @@ LAYER PARTIALS FALSE OUTLINECOLOR 255 255 255 END - COLOR 0 0 0 END CLASS - SYMBOL 2 - SIZE 8 + STYLE + SYMBOL 2 + SIZE 8 + COLOR 0 0 0 + END LABEL PRIORITY 10 COLOR 0 0 0 @@ -112,7 +122,6 @@ LAYER PARTIALS FALSE OUTLINECOLOR 255 255 255 END - COLOR 0 0 0 END END # Layer diff --git a/msautotest/misc/rfc36.map b/msautotest/misc/rfc36.map index 8278ed5033..eb12dcda31 100644 --- a/msautotest/misc/rfc36.map +++ b/msautotest/misc/rfc36.map @@ -20,8 +20,6 @@ MAP DEBUG ON - TRANSPARENT ON - OUTPUTFORMAT NAME "geojson" DRIVER "TEMPLATE" @@ -95,7 +93,6 @@ MAP DEBUG ON DATA "../wxs/data/popplace.shp" TYPE POINT - DUMP TRUE TEMPLATE "dummy" TOLERANCE 30 PROJECTION @@ -103,9 +100,11 @@ MAP END CLASS NAME " " - SIZE 10 - SYMBOL 2 - COLOR 255 0 0 + STYLE + SIZE 10 + SYMBOL 2 + COLOR 255 0 0 + END END END END diff --git a/msautotest/misc/rfc36_ogr.map b/msautotest/misc/rfc36_ogr.map index f7f7fbe5db..8be89d042a 100644 --- a/msautotest/misc/rfc36_ogr.map +++ b/msautotest/misc/rfc36_ogr.map @@ -21,8 +21,6 @@ MAP DEBUG ON - TRANSPARENT ON - OUTPUTFORMAT NAME "geojson" DRIVER "TEMPLATE" @@ -97,7 +95,6 @@ MAP CONNECTIONTYPE OGR CONNECTION "../wxs/data/popplace.shp" TYPE POINT - DUMP TRUE TEMPLATE "dummy" TOLERANCE 30 PROJECTION @@ -105,9 +102,11 @@ MAP END CLASS NAME " " - SIZE 10 - SYMBOL 2 - COLOR 255 0 0 + STYLE + SIZE 10 + SYMBOL 2 + COLOR 255 0 0 + END END END END diff --git a/msautotest/misc/rot_out.map b/msautotest/misc/rot_out.map index f12429e632..07c57e7da3 100644 --- a/msautotest/misc/rot_out.map +++ b/msautotest/misc/rot_out.map @@ -24,8 +24,10 @@ LAYER CLASSITEM "AREA" CLASS NAME "test1" - COLOR 0 255 0 - OUTLINECOLOR 255 0 0 + STYLE + COLOR 0 255 0 + OUTLINECOLOR 255 0 0 + END END PROJECTION diff --git a/msautotest/misc/run_test.py b/msautotest/misc/run_test.py index ee65170a60..0933d7fde9 100755 --- a/msautotest/misc/run_test.py +++ b/msautotest/misc/run_test.py @@ -8,17 +8,17 @@ # ############################################################################### # Copyright (c) 2002, Frank Warmerdam -# +# # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: -# +# # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. -# +# # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL @@ -29,14 +29,19 @@ ############################################################################### import os -import pytest import sys -sys.path.append( '../pymod' ) +import pytest + +sys.path.append("../pymod") import mstestlib -@pytest.mark.parametrize('map,out_file,command', mstestlib.get_pytests(os.path.dirname(os.path.abspath(__file__)))) + +@pytest.mark.parametrize( + "map,out_file,command", + mstestlib.get_pytests(os.path.dirname(os.path.abspath(__file__))), +) def test(map, out_file, command, extra_args): mstestlib.run_pytest(map, out_file, command, extra_args) @@ -44,5 +49,5 @@ def test(map, out_file, command, extra_args): ############################################################################### # main() -if __name__ == '__main__': +if __name__ == "__main__": sys.exit(mstestlib.pytest_main()) diff --git a/msautotest/misc/runtime_sub.map b/msautotest/misc/runtime_sub.map index 70d3162f64..33e6c9b5da 100644 --- a/msautotest/misc/runtime_sub.map +++ b/msautotest/misc/runtime_sub.map @@ -15,7 +15,7 @@ # RUN_PARMS: runtime_sub_test012.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&mode=map&layer=layer9&mapext=0 0 300 300&mapsize=30 30&resample=average" > [RESULT_DEMIME] # RUN_PARMS: runtime_sub_test013.png [ENV resample=nearest] [MAPSERV] QUERY_STRING="map=[MAPFILE]&mode=map&layer=layer9&mapext=0 0 300 300&mapsize=30 30&resample=average" > [RESULT_DEMIME] -#override alloed request types by url. if we do not pass "enable=capabilities" in the url, then "layer2" would not appear in the resulting xml doc +#override allowed request types by url. if we do not pass "enable=capabilities" in the url, then "layer2" would not appear in the resulting xml doc # RUN_PARMS: runtime_sub_test_caps.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&service=wms&request=getcapabilities&enable=getcapabilities" > [RESULT_DEVERSION] # MAP diff --git a/msautotest/misc/scale_factor_inheritance.map b/msautotest/misc/scale_factor_inheritance.map new file mode 100644 index 0000000000..c7baa7fde1 --- /dev/null +++ b/msautotest/misc/scale_factor_inheritance.map @@ -0,0 +1,25 @@ +# +# Test style scale factor inheritance with STYLEITEM +# +# REQUIRES: INPUT=GDAL OUTPUT=PNG +# + +# RUN_PARMS: scale_factor_inheritance.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&layer=test&mode=map" > [RESULT_DEMIME] + +MAP + EXTENT 0 -1 1 1 + SIZE 100 100 + LAYER + NAME "test" + EXTENT 0 -1 1 1 + CONNECTIONTYPE OGR + CONNECTION "data/styleitem_style.csv" + DATA "styleitem_style" + TYPE LINE + STATUS ON + SYMBOLSCALEDENOM 500 + STYLEITEM "STYLE" + CLASS + END + END +END diff --git a/msautotest/misc/scaletoken.map b/msautotest/misc/scaletoken.map index 60296620ec..380a9780f1 100644 --- a/msautotest/misc/scaletoken.map +++ b/msautotest/misc/scaletoken.map @@ -1,13 +1,15 @@ # Test Runtime Substitutions # -# RUN_PARMS: scaletoken_data_200k.png [SHP2IMG] -l layer1 -m [MAPFILE] -o [RESULT] -e 478315 4762880 481645 4765610 -# RUN_PARMS: scaletoken_data_29m.png [SHP2IMG] -l layer1 -m [MAPFILE] -o [RESULT] -e 425000 4685000 489000 5189000 -# RUN_PARMS: scaletoken_data_40m.png [SHP2IMG] -l layer1 -m [MAPFILE] -o [RESULT] -# RUN_PARMS: scaletoken_filter_192k.png [SHP2IMG] -l layer2 -m [MAPFILE] -o [RESULT] -e 478315 4762880 481645 4765610 -# RUN_PARMS: scaletoken_filter_424k.png [SHP2IMG] -l layer2 -m [MAPFILE] -o [RESULT] -e 476315 4762880 483645 4765610 -# RUN_PARMS: scaletoken_filter_655k.png [SHP2IMG] -l layer2 -m [MAPFILE] -o [RESULT] -e 474315 4762880 485645 4765610 -# RUN_PARMS: scaletoken_filteritem_192k.png [SHP2IMG] -l layer3 -m [MAPFILE] -o [RESULT] -e 478315 4762880 481645 4765610 -# RUN_PARMS: scaletoken_filteritem_424k.png [SHP2IMG] -l layer3 -m [MAPFILE] -o [RESULT] -e 476315 4762880 483645 4765610 +# RUN_PARMS: scaletoken_data_200k.png [MAP2IMG] -l layer1 -m [MAPFILE] -o [RESULT] -e 478315 4762880 481645 4765610 +# RUN_PARMS: scaletoken_data_29m.png [MAP2IMG] -l layer1 -m [MAPFILE] -o [RESULT] -e 425000 4685000 489000 5189000 +# RUN_PARMS: scaletoken_data_40m.png [MAP2IMG] -l layer1 -m [MAPFILE] -o [RESULT] +# RUN_PARMS: scaletoken_filter_192k.png [MAP2IMG] -l layer2 -m [MAPFILE] -o [RESULT] -e 478315 4762880 481645 4765610 +# RUN_PARMS: scaletoken_filter_424k.png [MAP2IMG] -l layer2 -m [MAPFILE] -o [RESULT] -e 476315 4762880 483645 4765610 +# RUN_PARMS: scaletoken_filter_655k.png [MAP2IMG] -l layer2 -m [MAPFILE] -o [RESULT] -e 474315 4762880 485645 4765610 +# RUN_PARMS: scaletoken_filteritem_192k.png [MAP2IMG] -l layer3 -m [MAPFILE] -o [RESULT] -e 478315 4762880 481645 4765610 +# RUN_PARMS: scaletoken_filteritem_424k.png [MAP2IMG] -l layer3 -m [MAPFILE] -o [RESULT] -e 476315 4762880 483645 4765610 +# RUN_PARMS: scaletoken_filterexpression_192k.png [MAP2IMG] -l layer4 -m [MAPFILE] -o [RESULT] -e 478315 4762880 481645 4765610 +# RUN_PARMS: scaletoken_filterexpression_424k.png [MAP2IMG] -l layer4 -m [MAPFILE] -o [RESULT] -e 476315 4762880 483645 4765610 # MAP NAME 'scaletoken' @@ -83,5 +85,24 @@ MAP STYLE COLOR 51 51 51 END END END + LAYER + NAME 'layer4' + STATUS ON + DEBUG 1 + DATA "data/shppoly/poly.shp" + SCALETOKEN + NAME "%filter%" + VALUES + "0" "158" + "200000" "166" + END + END + # FILTER using an expression + FILTER ([EAS_ID] = %filter% ) + TYPE POLYGON + CLASS + STYLE COLOR 51 51 51 END + END + END END diff --git a/msautotest/misc/sde_bug2072.map b/msautotest/misc/sde_bug2072.map deleted file mode 100644 index bc2caefaec..0000000000 --- a/msautotest/misc/sde_bug2072.map +++ /dev/null @@ -1,52 +0,0 @@ -# -# Test of OGR SQL JOIN support via MapServer. -# -# A joined field is used for the EXPRESSION used to classify the returned -# polygons. -# -# REQUIRES: INPUT=OGR OUTPUT=PNG INPUT=SDE -# -MAP - -STATUS ON -EXTENT 113.157997 -35.132000 129.003204 -13.735800 -SIZE 400 300 - -IMAGETYPE png - -DEBUG ON -PROJECTION -'init=epsg:4283' -END #PROJECTION - -LAYER - NAME shppoly - TYPE polygon - CONNECTIONTYPE SDE - CONNECTION "smoke.hobu.net,5151,sde,sde,osgeo" - DATA "SDE.BUG_2072,SHAPE,SDE.DEFAULT" - STATUS default - DEBUG 3 - PROCESSING "CLOSE_CONNECTION=DEFER" - DUMP TRUE - UNITS DD - -METADATA -"wms_title" "CALM - CALM_REGIONS (SDE)" -"wms_name" "shppoly" -"wms_srs" "epsg:4283 epsg:4326 epsg:28349 epsg:28350 epsg:28351" -"ows_include_items" "all" -END - -PROJECTION -'init=epsg:4283' -END #PROJECTION - - CLASS - NAME "selected" - COLOR 0 0 255 - OUTLINECOLOR 255 0 0 - END -END - -END diff --git a/msautotest/misc/sde_join.map b/msautotest/misc/sde_join.map deleted file mode 100644 index 95faf2a4d2..0000000000 --- a/msautotest/misc/sde_join.map +++ /dev/null @@ -1,72 +0,0 @@ -# -# Test of OGR SQL JOIN support via MapServer. -# -# A joined field is used for the EXPRESSION used to classify the returned -# polygons. -# -# REQUIRES: INPUT=OGR OUTPUT=PNG INPUT=SDE -# -# RUN_PARMS: sde_join_getinfo.xml [MAPSERV] QUERY_STRING="service=WMS&request=GetFeatureInfo&layers=shppoly&version=1.1.1&styles=&map=[MAPFILE]&query_layers=shppoly&x=300&y=300&info_format=application/vnd.ogc.gml&srs=EPSG:4326&bbox=1283364.000001,457670.968990,1330430.374999,495313.843989&format=image/png&width=600&height=600&STYLES=" > [RESULT_DEVERSION] -# -# -MAP - -STATUS ON -#EXTENT 478300 4762880 481650 4765610 -EXTENT 1283364.000001 457670.968990 1330430.374999 495313.843989 - -SIZE 600 600 -PROJECTION - "init=epsg:4326" -END -IMAGETYPE png - -DEBUG ON - WEB - IMAGEPATH "/tmp" - METADATA - "ows_title" "ArcSDE MapServer Test" - "ows_onlineresource" "http://127.0.0.1:8888/cgi-bin/mapserv.fcgi" - "wfs_srs" "EPSG:4326" - END - END - -LAYER - NAME shppoly - TYPE polygon - CONNECTIONTYPE SDE - CONNECTION "smoke.hobu.net,5151,sde,sde,osgeo" - DATA "SDE.JOINTESTLAYER,SHAPE,SDE.DEFAULT" - STATUS on - TEMPLATE "default.html" - DEBUG 3 - PROCESSING "JOINTABLE=SDE.JOINTESTTABLE" - PROCESSING "JOINFROMFIELD=AQ_TAG" - PROCESSING "JOINTOFIELD=AQ_TAG" - FILTER "WHERE JOINTESTTABLE.AQ_TAG=JOINTESTLAYER.AQ_TAG" - CLASSITEM "SDE.JOINTESTTABLE.VAL" - DUMP TRUE - METADATA -# "ows_srs" "EPSG:4326" - "wfs_title" "shppoly" -# "wfs_name" "polys" - "gml_include_items" "all" -# "wfs_include_items" "OBJECTID,FCODE,AQNAME" - "gml_featureid" "OBJECTID" -# "ows_feature_id" "OBJECTID" -# "wms_feature_info_mime_type" "text/plain" - END - CLASS - NAME "selected" - COLOR 0 0 255 - OUTLINECOLOR 255 0 0 - EXPRESSION "val1" - END - CLASS - NAME "normal" - COLOR 0 255 0 - OUTLINECOLOR 255 0 0 - END -END - -END diff --git a/msautotest/misc/sde_utf.map b/msautotest/misc/sde_utf.map deleted file mode 100644 index 35f43ae9d6..0000000000 --- a/msautotest/misc/sde_utf.map +++ /dev/null @@ -1,69 +0,0 @@ -# -# Test of OGR SQL JOIN support via MapServer. -# -# A joined field is used for the EXPRESSION used to classify the returned -# polygons. -# -# REQUIRES: INPUT=OGR OUTPUT=PNG INPUT=SDE -# -MAP - -FONTSET "/home/hobu/mapserver/tests/fonts.txt" -SYMBOL - NAME "circle" - TYPE ellipse - FILLED true - POINTS - 1 1 - END -END - - -STATUS ON -EXTENT -169.000000 -89.000000 177.000000 87.000000 - -SIZE 800 800 - -IMAGETYPE png - -DEBUG ON - -LAYER - NAME shppoly - TYPE POINT - CONNECTIONTYPE SDE - CONNECTION "smoke.hobu.net,5151,sde,sde,osgeo" - DATA "SDE.UTF,SHAPE,SDE.DEFAULT" - STATUS default - DEBUG 3 - LABELITEM "COLB" - #LABELITEM "aCOLA" - CLASS - NAME "selected" - STYLE - COLOR 0 0 255 - SYMBOL 'circle' - SIZE 8 - END - LABEL - - ANTIALIAS TRUE - FONT "Vera" - - SIZE 12 - TYPE TRUETYPE - - COLOR 0 0 0 - FORCE FALSE - MINDISTANCE 200 - MINFEATURESIZE -1 - - PARTIALS TRUE - POSITION AUTO - END - # EXPRESSION "val1" - END - -END - -END diff --git a/msautotest/misc/sde_utf2.map b/msautotest/misc/sde_utf2.map deleted file mode 100644 index 15feabb411..0000000000 --- a/msautotest/misc/sde_utf2.map +++ /dev/null @@ -1,71 +0,0 @@ -# -# Test of OGR SQL JOIN support via MapServer. -# -# A joined field is used for the EXPRESSION used to classify the returned -# polygons. -# -# REQUIRES: INPUT=OGR OUTPUT=PNG INPUT=SDE -# -MAP - -FONTSET "/home/hobu/mapserver/tests/fonts.txt" -SYMBOL - NAME "circle" - TYPE ellipse - FILLED true - POINTS - 1 1 - END -END - - -STATUS ON -EXTENT 1712843.567492 647232.344265 1740646.171659 663501.938015 - -SIZE 800 800 - -IMAGETYPE png - -DEBUG ON - -LAYER - - NAME 'ROADNAMES' - METADATA - "wms_title" "roadnames" - END - - CONNECTIONTYPE SDE - CONNECTION 'smoke.hobu.net,port:5151,sde,sde,osgeo' - DATA 'SDE.CENTERLINES,SHAPE,SDE.DEFAULT' - PROCESSING "CLOSE_CONNECTION=DEFER" - DUMP TRUE - PROJECTION - "init=epsg:2274" - END - TYPE ANNOTATION - STATUS ON - LABELITEM 'STREET_NAME' - CLASS - STYLE - COLOR 212 207 199 - END - LABEL - ANGLE FOLLOW - MINDISTANCE 800 - FONT "Vera" -# ENCODING UTF-16 - TYPE TRUETYPE - SIZE 6 - BUFFER 15 - COLOR 0 0 0 - BACKGROUNDCOLOR -1 -1 -1 - OUTLINECOLOR 255 255 255 - #FORCE TRUE - END - END - -END - - -END diff --git a/msautotest/misc/sde_view.map b/msautotest/misc/sde_view.map deleted file mode 100644 index 2089e98bbe..0000000000 --- a/msautotest/misc/sde_view.map +++ /dev/null @@ -1,44 +0,0 @@ -# -# Test of OGR SQL JOIN support via MapServer. -# -# A joined field is used for the EXPRESSION used to classify the returned -# polygons. -# -# REQUIRES: INPUT=OGR OUTPUT=PNG INPUT=SDE -# -MAP - -STATUS ON -#EXTENT 478300 4762880 481650 4765610 -EXTENT 1731113.786242 660217.823431 1731605.958117 661097.125515 -#EXTENT 1283364.000001 457670.968990 1330430.374999 495313.843989 - -SIZE 400 300 - -IMAGETYPE png - -DEBUG ON - -LAYER - NAME shppoly - TYPE polygon - CONNECTIONTYPE SDE - CONNECTION "smoke.hobu.net,5151,sde,sde,osgeo" - DATA "SDE.FACILITIES_VIEW,SHAPE,SDE.DEFAULT" - STATUS default - DEBUG 3 - #CLASSITEM "SDE.JOINTESTTABLE.VAL" - CLASS - NAME "selected" - COLOR 0 0 255 - OUTLINECOLOR 255 0 0 - # EXPRESSION "val1" - END - CLASS - NAME "normal" - COLOR 0 255 0 - OUTLINECOLOR 255 0 0 - END -END - -END diff --git a/msautotest/misc/sde_wms.map b/msautotest/misc/sde_wms.map deleted file mode 100644 index c56db3618e..0000000000 --- a/msautotest/misc/sde_wms.map +++ /dev/null @@ -1,70 +0,0 @@ -# -# Test of OGR SQL JOIN support via MapServer. -# -# A joined field is used for the EXPRESSION used to classify the returned -# polygons. -# -# REQUIRES: INPUT=OGR OUTPUT=PNG INPUT=SDE -# - -# Capabilities -# RUN_PARMS: sde_wms_cap.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.1.0&REQUEST=GetCapabilities" > [RESULT_DEVERSION] -# -# Layer description -# RUN_PARMS: sde_wms_describe.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.1.0&REQUEST=DescribeLayer&LAYERS=shppoly" > [RESULT] -# -# Draw a map with a single polygon layer. -# RUN_PARMS: sde_wms_get_map_polygon.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.1.0&REQUEST=GetMap&SRS=EPSG:4326&BBOX=2018000,-73300,3410396,647400&FORMAT=image/png&WIDTH=400&HEIGHT=300&STYLES=&LAYERS=shppoly" > [RESULT_DEMIME] -# -# -MAP - -WEB - METADATA - "wms_title" "Test simple wms" - "wms_onlineresource" "http://localhost/path/to/wms_simple?" - "wms_srs" "EPSG:42304 EPSG:42101 EPSG:4269 EPSG:4326" - "ows_schemas_location" "http://ogc.dmsolutions.ca" - END -END - -PROJECTION -"init=epsg:4326" -END - -STATUS ON -EXTENT 1283364.000001 457670.968990 1330430.374999 495313.843989 - -SIZE 400 300 - -IMAGETYPE png - -DEBUG ON - -LAYER - NAME shppoly - TYPE polygon - CONNECTIONTYPE SDE - CONNECTION "smoke.hobu.net,5151,sde,sde,osgeo" - DATA "SDE.JOINTESTLAYER,SHAPE,SDE.DEFAULT" - STATUS default - DEBUG 3 - PROCESSING "JOINTABLE=SDE.JOINTESTTABLE" - PROCESSING "JOINFROMFIELD=AQ_TAG" - PROCESSING "JOINTOFIELD=AQ_TAG" - FILTER "WHERE JOINTESTTABLE.AQ_TAG=JOINTESTLAYER.AQ_TAG" - CLASSITEM "SDE.JOINTESTTABLE.VAL" - CLASS - NAME "selected" - COLOR 0 0 255 - OUTLINECOLOR 255 0 0 - EXPRESSION "val1" - END - CLASS - NAME "normal" - COLOR 0 255 0 - OUTLINECOLOR 255 0 0 - END -END - -END diff --git a/msautotest/misc/shp2img-size.map b/msautotest/misc/shp2img-size.map deleted file mode 100644 index c0d34bab73..0000000000 --- a/msautotest/misc/shp2img-size.map +++ /dev/null @@ -1,33 +0,0 @@ -# -# Tests shp2img binary to ensure size option is respected. -# -# RUN_PARMS: shp2img-size.png [SHP2IMG] -s 640 480 -m [MAPFILE] -o [RESULT] - -MAP - NAME HELLO - STATUS ON - EXTENT 59 10 60 11 - SIZE 400 300 - IMAGECOLOR 200 255 255 - - IMAGETYPE png - - LAYER - NAME "credits" - STATUS DEFAULT - TRANSFORM FALSE - TYPE POINT - FEATURE - POINTS - 200 250 - END - TEXT 'Hello world' - END - CLASS - LABEL - TYPE BITMAP - COLOR 0 0 0 - END - END - END -END diff --git a/msautotest/misc/style_opacity.map b/msautotest/misc/style_opacity.map index d6cf970e88..a956b80ab2 100644 --- a/msautotest/misc/style_opacity.map +++ b/msautotest/misc/style_opacity.map @@ -3,9 +3,9 @@ # # REQUIRES: INPUT=SHAPEFILE OUTPUT=PNG SUPPORTS=AGG # -# RUN_PARMS: style_opacity_test001.png [SHP2IMG] -m [MAPFILE] -l style_opacity_test001 -o [RESULT] -# RUN_PARMS: style_opacity_test002.png [SHP2IMG] -m [MAPFILE] -l style_opacity_test002 -o [RESULT] -# RUN_PARMS: style_opacity_test003.png [SHP2IMG] -m [MAPFILE] -l style_opacity_test003 -o [RESULT] +# RUN_PARMS: style_opacity_test001.png [MAP2IMG] -m [MAPFILE] -l style_opacity_test001 -o [RESULT] +# RUN_PARMS: style_opacity_test002.png [MAP2IMG] -m [MAPFILE] -l style_opacity_test002 -o [RESULT] +# RUN_PARMS: style_opacity_test003.png [MAP2IMG] -m [MAPFILE] -l style_opacity_test003 -o [RESULT] # MAP NAME 'style_opacity' diff --git a/msautotest/misc/tiles_scales_z2.map b/msautotest/misc/tiles_scales_z2.map new file mode 100644 index 0000000000..52385ca544 --- /dev/null +++ b/msautotest/misc/tiles_scales_z2.map @@ -0,0 +1,44 @@ +# +# Test for mode=tile and the use of MAXSCALEDENOM and MINSCALEDENOM when +# UNITS=dd. +# This test should generate a blank tile because the layer is out of scale +# (zoom level too high). +# +# REQUIRES: INPUT=OGR OUTPUT=PNG SUPPORTS=PROJ +# +# RUN_PARMS: tile_scale_z2.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&MODE=tile&TILEMODE=gmap&TILE=1+1+2&LAYERS=canada-poly" > [RESULT_DEMIME] +# +MAP + NAME "TILE_SCALE_TEST" + IMAGETYPE PNG + EXTENT -140.992892 41.976786 -55.630945 71.990315 + SIZE 400 400 + DEBUG 5 + UNITS dd + + PROJECTION + "init=epsg:4326" + END #projection + + LAYER + DEBUG 5 + NAME "canada-poly" + TYPE POLYGON + STATUS DEFAULT + CONNECTIONTYPE OGR + CONNECTION "data/canada.dgn" + DATA "elements" + MINSCALEDENOM 30000000 + MAXSCALEDENOM 70000000 + PROJECTION + "init=epsg:4326" + END #projection + CLASS + STYLE + OUTLINECOLOR 0 0 0 + COLOR 120 120 120 + END + END #class + END #layer + +END #map diff --git a/msautotest/misc/tiles_scales_z3.map b/msautotest/misc/tiles_scales_z3.map new file mode 100644 index 0000000000..39c8415826 --- /dev/null +++ b/msautotest/misc/tiles_scales_z3.map @@ -0,0 +1,44 @@ +# +# Test for mode=tile and the use of MAXSCALEDENOM and MINSCALEDENOM when +# UNITS=dd. +# This test should generate a non-blank tile because the scale is in the +# layer range. +# +# REQUIRES: INPUT=OGR OUTPUT=PNG SUPPORTS=PROJ +# +# RUN_PARMS: tile_scale_z3.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&MODE=tile&TILEMODE=gmap&TILE=2+2+3&LAYERS=canada-poly" > [RESULT_DEMIME] +# +MAP + NAME "TILE_SCALE_TEST" + IMAGETYPE PNG + EXTENT -140.992892 41.976786 -55.630945 71.990315 + SIZE 400 400 + DEBUG 5 + UNITS dd + + PROJECTION + "init=epsg:4326" + END #projection + + LAYER + DEBUG 5 + NAME "canada-poly" + TYPE POLYGON + STATUS DEFAULT + CONNECTIONTYPE OGR + CONNECTION "data/canada.dgn" + DATA "elements" + MINSCALEDENOM 30000000 + MAXSCALEDENOM 70000000 + PROJECTION + "init=epsg:4326" + END #projection + CLASS + STYLE + OUTLINECOLOR 0 0 0 + COLOR 120 120 120 + END + END #class + END #layer + +END #map diff --git a/msautotest/misc/tiles_scales_z4.map b/msautotest/misc/tiles_scales_z4.map new file mode 100644 index 0000000000..2478ffe8fc --- /dev/null +++ b/msautotest/misc/tiles_scales_z4.map @@ -0,0 +1,44 @@ +# +# Test for mode=tile and the use of MAXSCALEDENOM and MINSCALEDENOM when +# UNITS=dd. +# This test should generate a blank tile because the layer is out of scale +# (zoom level too low). +# +# REQUIRES: INPUT=OGR OUTPUT=PNG SUPPORTS=PROJ +# +# RUN_PARMS: tile_scale_z4.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&MODE=tile&TILEMODE=gmap&TILE=5+5+4&LAYERS=canada-poly" > [RESULT_DEMIME] +# +MAP + NAME "TILE_SCALE_TEST" + IMAGETYPE PNG + EXTENT -140.992892 41.976786 -55.630945 71.990315 + SIZE 400 400 + DEBUG 5 + UNITS dd + + PROJECTION + "init=epsg:4326" + END #projection + + LAYER + DEBUG 5 + NAME "canada-poly" + TYPE POLYGON + STATUS DEFAULT + CONNECTIONTYPE OGR + CONNECTION "data/canada.dgn" + DATA "elements" + MINSCALEDENOM 30000000 + MAXSCALEDENOM 70000000 + PROJECTION + "init=epsg:4326" + END #projection + CLASS + STYLE + OUTLINECOLOR 0 0 0 + COLOR 120 120 120 + END + END #class + END #layer + +END #map diff --git a/msautotest/misc/union.map b/msautotest/misc/union.map new file mode 100644 index 0000000000..f33990fced --- /dev/null +++ b/msautotest/misc/union.map @@ -0,0 +1,61 @@ +# +# Test UNION LAYER +# +# REQUIRES: OUTPUT=PNG +# +MAP + +STATUS ON +EXTENT 478300 4762880 481650 4765610 +SIZE 400 300 + +IMAGETYPE png +SHAPEPATH ./data/union + +LAYER + STATUS default + NAME 'shppoly' + TYPE POLYGON + CONNECTIONTYPE UNION + CONNECTION "layer1,layer2" # reference to the source layers + STYLEITEM "AUTO" + # Define an empty class that will be filled at runtime from the color and + # styles read from each source layer. + CLASS + END +END + + +LAYER + STATUS OFF + NAME 'layer1' + TYPE POLYGON + DATA 'layer1' + CLASSITEM "AREA" + CLASS + NAME "green" + STYLE + COLOR 0 255 0 + OUTLINECOLOR 255 0 0 + END + END +END + + +LAYER + STATUS OFF + NAME 'layer2' + TYPE POLYGON + DATA 'layer2' + CLASSITEM "AREA" + CLASS + NAME "red" + STYLE + COLOR 255 0 0 + OUTLINECOLOR 255 0 0 + END + END +END + + +END diff --git a/msautotest/msoracle/README.md b/msautotest/msoracle/README.md new file mode 100644 index 0000000000..064f1eef83 --- /dev/null +++ b/msautotest/msoracle/README.md @@ -0,0 +1,20 @@ +# Usage + +A docker composition is provided to make the bootstrap of an Oracle Spatial +database easier. This docker image has been stolen from the QGis project. + +The composition can be launched using the following command: + +``` +$ docker-compose up -d +``` + +Once launched, we still have to load the sample data (also inspired from the +QGis testsuite), using locally: + +``` +$ docker cp sample-data.sql msoracle_oracle_1:/tmp/ +$ docker exec -it msoracle_oracle_1 bash -c \ + "export TNS_ADMIN=/opt/oracle/oradata/dbconfig/XE ; /opt/oracle/product/18c/dbhomeXE/bin/sqlplus -L SYSTEM/adminpass@XE < /tmp/sample-data.sql" +``` + diff --git a/msautotest/msoracle/docker-compose.yaml b/msautotest/msoracle/docker-compose.yaml new file mode 100644 index 0000000000..b03d68bc83 --- /dev/null +++ b/msautotest/msoracle/docker-compose.yaml @@ -0,0 +1,12 @@ +version: '3' +services: + + oracle: + image: oslandia/oracle-slim-for-qgis:18.4.0-xe + environment: + - ORACLE_SID=XE + - ORACLE_PWD=adminpass + - ORACLE_PDB=ORCLPDBTEST + - ORACLE_CHARACTERSET=AL32UTF8 + ports: + - 1521:1521 diff --git a/msautotest/msoracle/expected/oracle.png b/msautotest/msoracle/expected/oracle.png new file mode 100644 index 0000000000..192e13f9a7 Binary files /dev/null and b/msautotest/msoracle/expected/oracle.png differ diff --git a/msautotest/msoracle/oracle.map b/msautotest/msoracle/oracle.map new file mode 100644 index 0000000000..400dcc2ddf --- /dev/null +++ b/msautotest/msoracle/oracle.map @@ -0,0 +1,98 @@ +# RUN_PARMS: oracle.png [MAP2IMG] -s 640 480 -m oracle.map -l oracle -o result/oracle.png +# REQUIRES: INPUT=ORACLESPATIAL +MAP + NAME "OGC:WMS" + EXTENT -72 67 -65 79 + UNITS DD + + DEBUG 5 + + CONFIG "MS_ERRORFILE" stderr + + LEGEND + STATUS ON + KEYSIZE 18 12 + LABEL + FONT Arial + TYPE truetype + SIZE 8 + COLOR 0 0 89 + END + END + + LAYER + NAME "oracle" + TYPE POINT + STATUS OFF + EXTENT -72 67 -65 79 + UNITS DD + DEBUG 5 + CONNECTION "SYSTEM/adminpass@XE" + CONNECTIONTYPE oraclespatial + LABELITEM "name" + DATA "GEOM from (select \"pk\", \"name\", GEOM from SYSTEM.SOME_DATA ) using unique \"pk\" SRID 4326" + + + CLASS + # Start of the first Style + STYLE + # Symbol to be used (reference) + SYMBOL "square" + # Size of the symbol in pixels + SIZE 16 + # Colour (RGB) - red + COLOR 255 0 0 + # Outline colour (RGB) - black + OUTLINECOLOR 0 0 0 + END # end of STYLE + # Start of the second Style + STYLE + # Symbol to be used (reference) + SYMBOL "circle" + # Size of the symbol in pixels + SIZE 10 + # Colour (RGB) - blue + COLOR 0 0 255 + END # end of STYLE + END # end of CLASS + + END # LAYER + + SYMBOL + # Symbol name (referenced in STYLEs) + NAME "square" + TYPE vector # Type of symbol + # Start of the symbol geometry + POINTS + 0 0 + 0 1 + 1 1 + 1 0 + 0 0 + END # end of POINTS + # The symbol should be filled + FILLED true + # Place the according to its center + ANCHORPOINT 0.5 0.5 + END # end of SYMBOL + + # Start of symbol definition + SYMBOL + # Symbol name (referenced in STYLEs) + NAME "circle" + TYPE ellipse # Type of symbol + # Start of the symbol geometry + POINTS + 1 1 + END # end of POINTS + # The symbol should be filled + FILLED true + # Place the according to its center + ANCHORPOINT 0.5 0.5 + END # end of SYMBOL + + + +END # MAP + + diff --git a/msautotest/msoracle/run_test.py b/msautotest/msoracle/run_test.py new file mode 100644 index 0000000000..e458f4c16a --- /dev/null +++ b/msautotest/msoracle/run_test.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python +############################################################################### +# $Id: run_test.py 4851 2005-09-22 18:29:07Z frank $ +# +# Project: MapServer +# Purpose: Test harnass script for MapServer autotest. +# Author: Frank Warmerdam, warmerdam@pobox.com +# +############################################################################### +# Copyright (c) 2002, Frank Warmerdam +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +############################################################################### + +import os +import sys + +import pytest + +sys.path.append("../pymod") + +import mstestlib + +os.environ["TNS_ADMIN"] = "." + + +@pytest.mark.parametrize( + "map,out_file,command", + mstestlib.get_pytests(os.path.dirname(os.path.abspath(__file__))), +) +def test(map, out_file, command, extra_args): + mstestlib.run_pytest(map, out_file, command, extra_args) + + +############################################################################### +# main() + +if __name__ == "__main__": + sys.exit(mstestlib.pytest_main()) diff --git a/msautotest/msoracle/sample-data.sql b/msautotest/msoracle/sample-data.sql new file mode 100644 index 0000000000..0a68037fa5 --- /dev/null +++ b/msautotest/msoracle/sample-data.sql @@ -0,0 +1,79 @@ +CREATE TABLE SYSTEM.SOME_DATA ( "pk" INTEGER PRIMARY KEY, "cnt" INTEGER, "name" VARCHAR2(100) DEFAULT 'qgis', "name2" VARCHAR2(100) DEFAULT 'qgis', "num_char" VARCHAR2(100), "dt" TIMESTAMP, "date" DATE, "time" VARCHAR2(100), GEOM SDO_GEOMETRY); + +INSERT INTO SYSTEM.SOME_DATA ("pk", "cnt", "name", "name2", "num_char", "dt", "date", "time", GEOM) + SELECT 5, -200, NULL, 'NuLl', '5', TIMESTAMP '2020-05-04 12:13:14', DATE '2020-05-02','12:13:01', SDO_GEOMETRY( 2001,4326,SDO_POINT_TYPE(-71.123, 78.23, NULL), NULL, NULL) from dual + UNION ALL SELECT 3, 300, 'Pear', 'PEaR', '3', NULL, NULL, NULL, NULL from dual + UNION ALL SELECT 1, 100, 'Orange', 'oranGe', '1', TIMESTAMP '2020-05-03 12:13:14', DATE '2020-05-03','12:13:14', SDO_GEOMETRY( 2001,4326,SDO_POINT_TYPE(-70.332, 66.33, NULL), NULL, NULL) from dual + UNION ALL SELECT 2, 200, 'Apple', 'Apple', '2', TIMESTAMP '2020-05-04 12:14:14', DATE '2020-05-04','12:14:14', SDO_GEOMETRY( 2001,4326,SDO_POINT_TYPE(-68.2, 70.8, NULL), NULL, NULL) from dual + UNION ALL SELECT 4, 400, 'Honey', 'Honey', '4', TIMESTAMP '2021-05-04 13:13:14', DATE '2021-05-04','13:13:14', SDO_GEOMETRY( 2001,4326,SDO_POINT_TYPE(-65.32, 78.3, NULL), NULL, NULL) from dual; + +INSERT INTO user_sdo_geom_metadata (TABLE_NAME, COLUMN_NAME, DIMINFO, SRID) VALUES ( 'SOME_DATA', 'GEOM', sdo_dim_array(sdo_dim_element('X',-75,-55,0.005),sdo_dim_element('Y',65,85,0.005)),4326); + +CREATE INDEX some_data_spatial_idx ON SYSTEM.SOME_DATA(GEOM) INDEXTYPE IS MDSYS.SPATIAL_INDEX; + +CREATE TABLE SYSTEM.SOME_POLY_DATA ( "pk" INTEGER PRIMARY KEY, GEOM SDO_GEOMETRY); + +INSERT INTO SYSTEM.SOME_POLY_DATA ("pk", GEOM) + SELECT 1, SDO_GEOMETRY( 2003,4326,NULL, SDO_ELEM_INFO_ARRAY(1,1003,1), SDO_ORDINATE_ARRAY(-69.0,81.4 , -69.0,80.2 , -73.7,80.2 , -73.7,76.3 , -74.9,76.3 , -74.9,81.4 , -69.0,81.4)) from dual + UNION ALL SELECT 2, SDO_GEOMETRY( 2003,4326,NULL, SDO_ELEM_INFO_ARRAY(1,1003,1), SDO_ORDINATE_ARRAY(-67.6,81.2 , -66.3,81.2 , -66.3,76.9 , -67.6,76.9 , -67.6,81.2))from dual + UNION ALL SELECT 3, SDO_GEOMETRY( 2003,4326,NULL, SDO_ELEM_INFO_ARRAY(1,1003,1), SDO_ORDINATE_ARRAY(-68.4,75.8 , -67.5,72.6 , -68.6,73.7 , -70.2,72.9 , -68.4,75.8)) from dual + UNION ALL SELECT 4, NULL from dual; + +INSERT INTO user_sdo_geom_metadata (TABLE_NAME, COLUMN_NAME, DIMINFO, SRID) VALUES ( 'SOME_POLY_DATA', 'GEOM', sdo_dim_array(sdo_dim_element('X',-80,-55,0.005),sdo_dim_element('Y',65,85,0.005)),4326); + +CREATE INDEX some_poly_data_spatial_idx ON SYSTEM.SOME_POLY_DATA(GEOM) INDEXTYPE IS MDSYS.SPATIAL_INDEX; + + +CREATE TABLE SYSTEM.POINT_DATA ( "pk" INTEGER PRIMARY KEY, GEOM SDO_GEOMETRY); +INSERT INTO SYSTEM.POINT_DATA ("pk", GEOM) + SELECT 1, SDO_GEOMETRY( 2001,4326,SDO_POINT_TYPE(1, 2, NULL), NULL, NULL) from dual + UNION ALL SELECT 2, SDO_GEOMETRY( 3001,4326,SDO_POINT_TYPE(1, 2, 3), NULL, NULL) from dual + UNION ALL SELECT 3, SDO_GEOMETRY( 3005,4326,NULL, sdo_elem_info_array (1,1,1, 4,1,1), sdo_ordinate_array (1,2,3, 4,5,6)) from dual + UNION ALL SELECT 4, SDO_GEOMETRY( 2005,4326,NULL, sdo_elem_info_array (1,1,1, 3,1,1), sdo_ordinate_array (1,2, 3,4)) from dual + UNION ALL SELECT 5, SDO_GEOMETRY( 3005,4326,NULL, sdo_elem_info_array (1,1,2), sdo_ordinate_array (1,2,3, 4,5,6)) from dual + UNION ALL SELECT 6, SDO_GEOMETRY( 2001,4326,NULL, sdo_elem_info_array (1,1,1), sdo_ordinate_array (1,2)) from dual + UNION ALL SELECT 7, SDO_GEOMETRY( 2001,4326, SDO_POINT_TYPE(3, 4, NULL), NULL, NULL) from dual + UNION ALL SELECT 8, SDO_GEOMETRY( 2001,4326,NULL, sdo_elem_info_array (1,1,1), sdo_ordinate_array (5,6)) from dual; + +CREATE TABLE SYSTEM.LINE_DATA ( "pk" INTEGER PRIMARY KEY, GEOM SDO_GEOMETRY); +INSERT INTO SYSTEM.LINE_DATA ("pk", GEOM) + SELECT 1, SDO_GEOMETRY( 2002,3857,NULL, SDO_ELEM_INFO_ARRAY(1,2,1), SDO_ORDINATE_ARRAY(1,2,3,4,5,6)) from dual + UNION ALL SELECT 2, SDO_GEOMETRY(2002,3857,NULL, SDO_ELEM_INFO_ARRAY(1, 2, 2), SDO_ORDINATE_ARRAY(1, 2, 5, 4, 7, 2.2, 10, .1, 13, 4)) from dual + UNION ALL SELECT 3, SDO_GEOMETRY(2002,3857,NULL, SDO_ELEM_INFO_ARRAY(1,4,3, 1,2,1, 3,2,2, 11,2,1), SDO_ORDINATE_ARRAY(-1, -5, 1, 2, 5, 4, 7, 2.2, 10, 0.1, 13, 4, 17, -6.)) from dual + UNION ALL SELECT 4, SDO_GEOMETRY(3002,3857,NULL, SDO_ELEM_INFO_ARRAY(1,2,1), SDO_ORDINATE_ARRAY(1,2,3,4,5,6,7,8,9)) from dual + UNION ALL SELECT 5, SDO_GEOMETRY(2006,3857,NULL, SDO_ELEM_INFO_ARRAY(1,2,1, 5,2,1), SDO_ORDINATE_ARRAY(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)) from dual + UNION ALL SELECT 6, SDO_GEOMETRY(3006,3857,NULL, SDO_ELEM_INFO_ARRAY(1,2,1, 7,2,1), SDO_ORDINATE_ARRAY(1, 2, 11, 3, 4, -11, 5, 6, 9, 7, 8, 1, 9, 10, -3)) from dual + UNION ALL SELECT 7, SDO_GEOMETRY(2006,3857,NULL, SDO_ELEM_INFO_ARRAY(1,2,2, 11,2,2), SDO_ORDINATE_ARRAY(1, 2, 5, 4, 7, 2.2, 10, .1, 13, 4, -11, -3, 5, 7, 10, -1)) from dual + UNION ALL SELECT 8, SDO_GEOMETRY(2006,3857,NULL, SDO_ELEM_INFO_ARRAY(1,4,3, 1,2,1, 3,2,2, 11,2,1, 15,2,2, 25,2,1), SDO_ORDINATE_ARRAY(-1, -5, 1, 2, 5, 4, 7, 2.2, 10, .1, 13, 4, 17, -6, 1, 3, 5, 5, 7, 3.2, 10, 1.1, 13, 5, -11, -3, 5, 7, 10, -1)) from dual; + +CREATE TABLE SYSTEM.POLY_DATA ( "pk" INTEGER PRIMARY KEY, GEOM SDO_GEOMETRY); +INSERT INTO SYSTEM.POLY_DATA ("pk", GEOM) + SELECT 1, SDO_GEOMETRY(2003,4326,NULL, SDO_ELEM_INFO_ARRAY(1,1003,1), SDO_ORDINATE_ARRAY(1, 2, 11, 2, 11, 22, 1, 22, 1, 2)) from dual + UNION ALL SELECT 2, SDO_GEOMETRY(3003,4326,NULL, SDO_ELEM_INFO_ARRAY(1,1003,1), SDO_ORDINATE_ARRAY(1, 2, 3, 11, 2, 13, 11, 22, 15, 1, 22, 7, 1, 2, 3)) from dual + UNION ALL SELECT 3, SDO_GEOMETRY(2003,4326,NULL, SDO_ELEM_INFO_ARRAY(1,1003,1, 11,2003,1, 19,2003,1), SDO_ORDINATE_ARRAY(1, 2, 11, 2, 11, 22, 1, 22, 1, 2, 5, 6, 8, 9, 8, 6, 5, 6, 3, 4, 5, 6, 3, 6, 3, 4)) from dual + UNION ALL SELECT 4, SDO_GEOMETRY(3003,4326,NULL, SDO_ELEM_INFO_ARRAY(1,1003,1, 16,2003,1), SDO_ORDINATE_ARRAY(1, 2, 3, 11, 2, 13, 11, 22, 15, 1, 22, 7, 1, 2, 3, 5, 6, 1, 8, 9, -1, 8, 6, 2, 5, 6, 1)) from dual + UNION ALL SELECT 5, SDO_GEOMETRY(2003,4326,NULL, SDO_ELEM_INFO_ARRAY(1,1003,3), SDO_ORDINATE_ARRAY(1.0, 2.0, 11.0, 22.0)) from dual + UNION ALL SELECT 6, SDO_GEOMETRY(2003,4326,NULL, SDO_ELEM_INFO_ARRAY(1,1003,4), SDO_ORDINATE_ARRAY(1.0, 2.0, 11.0, 22.0, 15.0, 4.0)) from dual + UNION ALL SELECT 7, SDO_GEOMETRY(2007,4326,NULL, SDO_ELEM_INFO_ARRAY(1,1003,1, 11,1003,1, 21,2003,1, 29,2003,1), SDO_ORDINATE_ARRAY(1, 2, 11, 2, 11, 22, 1, 22, 1, 2, 1, 2, 11, 2, 11, 22, 1, 22, 1, 2, 5, 6, 8, 9, 8, 6, 5, 6, 3, 4, 5, 6, 3, 6, 3, 4)) from dual + UNION ALL SELECT 8, SDO_GEOMETRY(3007,4326,NULL, SDO_ELEM_INFO_ARRAY(1,1003,1, 16,1003,1, 31,2003,1), SDO_ORDINATE_ARRAY(1, 2, 3, 11, 2, 13, 11, 22, 15, 1, 22, 7, 1, 2, 3, 1, 2, 3, 11, 2, 13, 11, 22, 15, 1, 22, 7, 1, 2, 3, 5, 6, 1, 8, 9, -1, 8, 6, 2, 5, 6, 1)) from dual + UNION ALL SELECT 9, SDO_GEOMETRY(2003,4326,NULL, SDO_ELEM_INFO_ARRAY(1,1003,2), SDO_ORDINATE_ARRAY(1, 3, 3, 5, 4, 7, 7, 3, 1, 3)) from dual + UNION ALL SELECT 10, SDO_GEOMETRY(2003, NULL, NULL, SDO_ELEM_INFO_ARRAY(1,1003,2, 11,2003,2), SDO_ORDINATE_ARRAY(1, 3, 3, 5, 4, 7, 7, 3, 1, 3, 3.1, 3.3, 3.3, 3.5, 3.4, 3.7, 3.7, 3.3, 3.1, 3.3)) from dual + UNION ALL SELECT 11, SDO_GEOMETRY(2003, NULL, NULL, SDO_ELEM_INFO_ARRAY(1,1005,4, 1,2,1, 3,2,2, 11,2,1, 13,2,2), SDO_ORDINATE_ARRAY(-1, -5, 1, 2, 5, 4, 7, 2.2, 10, .1, 13, 4, 17, -6, 5, -7, -1, -5)) from dual + UNION ALL SELECT 12, SDO_GEOMETRY(2007, NULL, NULL, SDO_ELEM_INFO_ARRAY(1,1003,2, 11,1003,2), SDO_ORDINATE_ARRAY(1, 3, 3, 5, 4, 7, 7, 3, 1, 3, 11, 3, 13, 5, 14, 7, 17, 3, 11, 3)) from dual + UNION ALL SELECT 13, SDO_GEOMETRY(3003, 5698, NULL, SDO_ELEM_INFO_ARRAY(1, 1005, 4, 1, 2, 2, 7, 2, 1, 10, 2, 2, 22, 2, 1), SDO_ORDINATE_ARRAY(-1, -5, 1, 5, -7, 2, 17, -6, 3, 13, 4, 4, 10, .1, 5, 7, 2.2, 6, 5, 4, 7, 1, 2, 8, -1, -5, 1)) from dual + UNION ALL SELECT 14, SDO_GEOMETRY(2007, 3857, NULL, SDO_ELEM_INFO_ARRAY(1, 1003, 1), SDO_ORDINATE_ARRAY(22, 22, 28, 22, 28, 26, 22, 26, 22, 22)) from dual + UNION ALL SELECT 15, SDO_GEOMETRY(2007, 3857, NULL, SDO_ELEM_INFO_ARRAY(1, 1005, 2, 1, 2, 2, 5, 2, 1, 9, 1003, 2), SDO_ORDINATE_ARRAY(-1, -5, 5, -7, 17, -6, -1, -5, 1, 3, 7, 3, 4, 7, 3, 5, 1, 3)) from dual; + +CREATE TABLE SYSTEM.DATE_TIMES ( "id" INTEGER PRIMARY KEY, "date_field" DATE, "datetime_field" TIMESTAMP ); + +INSERT INTO SYSTEM.DATE_TIMES ("id", "date_field", "datetime_field" ) VALUES (1, DATE '2004-03-04', TIMESTAMP '2004-03-04 13:41:52' ); + +CREATE TABLE SYSTEM.POINT_DATA_IDENTITY ( "pk" NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, GEOM SDO_GEOMETRY); +INSERT INTO SYSTEM.POINT_DATA_IDENTITY (GEOM) + SELECT SDO_GEOMETRY( 2001,4326,SDO_POINT_TYPE(1, 2, NULL), NULL, NULL) from dual; + +CREATE TABLE SYSTEM.GENERATED_COLUMNS ( "pk" INTEGER PRIMARY KEY, "generated_field" GENERATED ALWAYS AS ('test:' || "pk") VIRTUAL); +INSERT INTO SYSTEM.GENERATED_COLUMNS ("pk") SELECT 1 FROM dual; + + +COMMIT; diff --git a/msautotest/msoracle/tnsnames.ora b/msautotest/msoracle/tnsnames.ora new file mode 100644 index 0000000000..0947737252 --- /dev/null +++ b/msautotest/msoracle/tnsnames.ora @@ -0,0 +1,9 @@ +XE = + (DESCRIPTION = + (ADDRESS_LIST = + (ADDRESS = (PROTOCOL = TCP)(Host = 127.0.0.1)(Port = 1521)) + ) + (CONNECT_DATA = + (SERVICE_NAME = XE) + ) +) diff --git a/msautotest/mspython/ogr_query.map b/msautotest/mspython/ogr_query.map index ea52607e0b..1c78c271aa 100644 --- a/msautotest/mspython/ogr_query.map +++ b/msautotest/mspython/ogr_query.map @@ -14,7 +14,6 @@ IMAGETYPE png LAYER NAME shppoly TYPE polygon - DUMP TRUE TEMPLATE "junk.tmpl" CONNECTIONTYPE OGR CONNECTION "../misc/data/shppoly" @@ -23,8 +22,10 @@ LAYER CLASSITEM "AREA" CLASS NAME "test1" - COLOR 0 255 0 - OUTLINECOLOR 255 0 0 + STYLE + COLOR 0 255 0 + OUTLINECOLOR 255 0 0 + END END END diff --git a/msautotest/mspython/run_all_tests.py b/msautotest/mspython/run_all_tests.py index 4d481fa369..711c597999 100755 --- a/msautotest/mspython/run_all_tests.py +++ b/msautotest/mspython/run_all_tests.py @@ -9,17 +9,17 @@ # ############################################################################### # Copyright (c) 2020, Even Rouault, -# +# # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: -# +# # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. -# +# # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL @@ -35,6 +35,6 @@ from pytest import main -if __name__ == '__main__': - sys.argv[0] = 'run_all_tests.py' +if __name__ == "__main__": + sys.argv[0] = "run_all_tests.py" sys.exit(main()) diff --git a/msautotest/mspython/test_bug_check.py b/msautotest/mspython/test_bug_check.py index 3d00860238..a938992b7e 100755 --- a/msautotest/mspython/test_bug_check.py +++ b/msautotest/mspython/test_bug_check.py @@ -9,17 +9,17 @@ # ############################################################################### # Copyright (c) 2007, Frank Warmerdam -# +# # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: -# +# # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. -# +# # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL @@ -30,22 +30,27 @@ ############################################################################### import os -import pytest import pmstestlib +import pytest mapscript_available = False try: import mapscript + mapscript_available = True except ImportError: pass -pytestmark = pytest.mark.skipif(not mapscript_available, reason="mapscript not available") +pytestmark = pytest.mark.skipif( + not mapscript_available, reason="mapscript not available" +) + def get_relpath_to_this(filename): return os.path.join(os.path.dirname(__file__), filename) + ############################################################################### # Attempt to verify that bug673 remains fixed. This bug is trigger if # a map is drawn such that the layer->project flag gets set to FALSE (no @@ -55,49 +60,53 @@ def get_relpath_to_this(filename): # # http://trac.osgeo.org/mapserver/ticket/673 + def test_bug_673(): - map = mapscript.mapObj(get_relpath_to_this('../misc/ogr_direct.map')) + map = mapscript.mapObj(get_relpath_to_this("../misc/ogr_direct.map")) - map.setProjection('+proj=utm +zone=11 +datum=WGS84') + map.setProjection("+proj=utm +zone=11 +datum=WGS84") layer = map.getLayer(0) # Draw map without reprojection. - layer.setProjection('+proj=utm +zone=11 +datum=WGS84') + layer.setProjection("+proj=utm +zone=11 +datum=WGS84") map.draw() # Draw map with reprojection - map.setProjection('+proj=latlong +datum=WGS84') - map.setExtent(-117.25,43.02,-117.21,43.05) + map.setProjection("+proj=latlong +datum=WGS84") + map.setExtent(-117.25, 43.02, -117.21, 43.05) img2 = map.draw() try: - os.mkdir(get_relpath_to_this('result')) - except: + os.mkdir(get_relpath_to_this("result")) + except Exception: pass - img2.save( get_relpath_to_this('result/bug673.png') ) + img2.save(get_relpath_to_this("result/bug673.png")) # Verify we got the image we expected ... at least hopefully we didn't # get all white which would indicate the bug is back. - pmstestlib.compare_and_report( 'bug673.png', this_path = os.path.dirname(__file__) ) + pmstestlib.compare_and_report("bug673.png", this_path=os.path.dirname(__file__)) ############################################################################### # Test reprojection of lines from Polar Stereographic and crossing the antimerdian + def test_reprojection_lines_from_polar_stereographic_to_geographic(): - shape = mapscript.shapeObj( mapscript.MS_SHAPE_LINE ) + shape = mapscript.shapeObj(mapscript.MS_SHAPE_LINE) line = mapscript.lineObj() - line.add( mapscript.pointObj( -5554682.77568025, -96957.3485051449 ) ) # -179 40 - line.add( mapscript.pointObj( -5554682.77568025, 96957.3485051449 ) ) # 179 40 - shape.add( line ) + line.add(mapscript.pointObj(-5554682.77568025, -96957.3485051449)) # -179 40 + line.add(mapscript.pointObj(-5554682.77568025, 96957.3485051449)) # 179 40 + shape.add(line) - polar_proj = mapscript.projectionObj("+proj=stere +lat_0=90 +lat_ts=60 +lon_0=270 +datum=WGS84") + polar_proj = mapscript.projectionObj( + "+proj=stere +lat_0=90 +lat_ts=60 +lon_0=270 +datum=WGS84" + ) longlat_proj = mapscript.projectionObj("+proj=longlat +datum=WGS84") assert shape.project(polar_proj, longlat_proj) == 0 @@ -116,21 +125,25 @@ def test_reprojection_lines_from_polar_stereographic_to_geographic(): assert point21.x == pytest.approx(180.0, abs=1e-7) assert point22.x == pytest.approx(179.0, abs=1e-7) + ############################################################################### # Test reprojection of lines from Polar Stereographic and crossing the antimerdian + def test_reprojection_lines_from_polar_stereographic_to_webmercator(): - shape = mapscript.shapeObj( mapscript.MS_SHAPE_LINE ) + shape = mapscript.shapeObj(mapscript.MS_SHAPE_LINE) line = mapscript.lineObj() - line.add( mapscript.pointObj( -5554682.77568025, -96957.3485051449 ) ) # -179 40 - line.add( mapscript.pointObj( -5554682.77568025, 96957.3485051449 ) ) # 179 40 - shape.add( line ) + line.add(mapscript.pointObj(-5554682.77568025, -96957.3485051449)) # -179 40 + line.add(mapscript.pointObj(-5554682.77568025, 96957.3485051449)) # 179 40 + shape.add(line) - polar_proj = mapscript.projectionObj("+proj=stere +lat_0=90 +lat_ts=60 +lon_0=270 +datum=WGS84") - longlat_proj = mapscript.projectionObj("init=epsg:3857") + polar_proj = mapscript.projectionObj( + "+proj=stere +lat_0=90 +lat_ts=60 +lon_0=270 +datum=WGS84" + ) + webmercator = mapscript.projectionObj("init=epsg:3857") - assert shape.project(polar_proj, longlat_proj) == 0 + assert shape.project(polar_proj, webmercator) == 0 part1 = shape.get(0) assert part1 @@ -145,3 +158,148 @@ def test_reprojection_lines_from_polar_stereographic_to_webmercator(): assert point12.x == pytest.approx(-20037508.34, abs=1e-2) assert point21.x == pytest.approx(20037508.34, abs=1e-2) assert point22.x == pytest.approx(19926188.85, abs=1e-2) + + +############################################################################### +# Test reprojection of rectangle from Polar Stereographic containing north +# pole to webmercator + + +def test_reprojection_rect_from_polar_stereographic_to_webmercator(): + + rect = mapscript.rectObj(-4551441, -7324318, 4798559, 915682) + polar_proj = mapscript.projectionObj( + "+proj=stere +lat_0=90 +lat_ts=60 +lon_0=549 +R=6371229" + ) + webmercator = mapscript.projectionObj("init=epsg:3857") + + assert rect.project(polar_proj, webmercator) == 0 + assert abs(rect.minx - -20e6) < 1e-1 * 20e6 + assert abs(rect.maxx - 20e6) < 1e-1 * 20e6 + + +############################################################################### +# Test reprojection of rectangle involving a datum shift (#6478) + + +def test_reprojection_rect_and_datum_shift(): + + webmercator = mapscript.projectionObj("init=epsg:3857") + epsg_28992 = mapscript.projectionObj("init=epsg:28992") # "Amersfoort / RD New" + + point = mapscript.pointObj(545287, 6867556) + point.project(webmercator, epsg_28992) + if point.x == pytest.approx(121685, abs=2): + # Builds of PROJ >= 6 and < 8 with -DACCEPT_USE_OF_DEPRECATED_PROJ_API_H + # use pj_transform() but it doesn't work well with datum shift + # This is a non-nominal configuration used in some CI confs when use a + # PROJ 7 build to test PROJ.4 API and PROJ 6 API. + pytest.skip( + "This test cannot run with PROJ [6,8[ in builds with ACCEPT_USE_OF_DEPRECATED_PROJ_API_H" + ) + + rect = mapscript.rectObj(545287, 6867556, 545689, 6868025) + assert rect.project(webmercator, epsg_28992) == 0 + assert rect.minx == pytest.approx(121711, abs=2) + + +############################################################################### +# Test reprojection of line crossing the antimeridian from a projection +# with +proj=longlat +lon_wrap=0 + + +def test_reprojection_from_lonlat_wrap_0(): + + src = mapscript.projectionObj("+proj=longlat +lon_wrap=0 +datum=WGS84") + dst = mapscript.projectionObj("+proj=longlat +datum=WGS84") + + shape = mapscript.shapeObj(mapscript.MS_SHAPE_LINE) + line = mapscript.lineObj() + line.add(mapscript.pointObj(179, 45)) + line.add(mapscript.pointObj(182, 45)) + shape.add(line) + + assert shape.project(src, dst) == 0 + + part1 = shape.get(0) + assert part1 + part2 = shape.get(1) + assert part2 + + point11 = part1.get(0) + point12 = part1.get(1) + point21 = part2.get(0) + point22 = part2.get(1) + set_x = [point11.x, point12.x, point21.x, point22.x] + set_x.sort() + assert set_x == pytest.approx([-180, -178, 179, 180], abs=1e-2) + + shape = mapscript.shapeObj(mapscript.MS_SHAPE_LINE) + line = mapscript.lineObj() + line.add(mapscript.pointObj(-179, 45)) + line.add(mapscript.pointObj(-182, 45)) + shape.add(line) + + assert shape.project(src, dst) == 0 + + part1 = shape.get(0) + assert part1 + part2 = shape.get(1) + assert part2 + + point11 = part1.get(0) + point12 = part1.get(1) + point21 = part2.get(0) + point22 = part2.get(1) + set_x = [point11.x, point12.x, point21.x, point22.x] + set_x.sort() + assert set_x == pytest.approx([-180, -179, 178, 180], abs=1e-2) + + +############################################################################### +# Check that we can draw a map several times by changing the map projection + + +def test_bug_6896(): + + try: + os.mkdir(get_relpath_to_this("result")) + except Exception: + pass + + def load_map(): + # Generate a reference image + map = mapscript.mapObj(get_relpath_to_this("../misc/ogr_direct.map")) + layer = map.getLayer(0) + layer.setProjection("+proj=utm +zone=11 +datum=WGS84") + return map + + def draw_another_projection(map): + # Draw map with one reprojection. + map.setProjection("+proj=utm +zone=12 +datum=WGS84") + map.setExtent(-10675, 4781937, -7127, 4784428) + map.draw() + + def draw_wgs84(map): + # Draw map with WGS 84 projection + map.setProjection("+proj=latlong +datum=WGS84") + map.setExtent(-117.25, 43.02, -117.21, 43.05) + img = map.draw() + return img + + map = load_map() + img = draw_wgs84(map) + ref_filename = get_relpath_to_this("result/bug6896_ref.png") + img.save(ref_filename) + + # Reload map + map = load_map() + draw_another_projection(map) + img = draw_wgs84(map) + test_filename = get_relpath_to_this("result/bug6896.png") + img.save(test_filename) + + assert open(ref_filename, "rb").read() == open(test_filename, "rb").read() + + os.unlink(ref_filename) + os.unlink(test_filename) diff --git a/msautotest/mspython/test_mapio.py b/msautotest/mspython/test_mapio.py index 03047d20de..48102e990c 100755 --- a/msautotest/mspython/test_mapio.py +++ b/msautotest/mspython/test_mapio.py @@ -9,17 +9,17 @@ # ############################################################################### # Copyright (c) 2017, Even Rouault, -# +# # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: -# +# # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. -# +# # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL @@ -30,42 +30,50 @@ ############################################################################### import os + import pytest mapscript_available = False try: import mapscript + mapscript_available = True except ImportError: pass -pytestmark = pytest.mark.skipif(not mapscript_available, reason="mapscript not available") +pytestmark = pytest.mark.skipif( + not mapscript_available, reason="mapscript not available" +) def get_relpath_to_this(filename): return os.path.join(os.path.dirname(__file__), filename) + ############################################################################### # + def test_msIO_getAndStripStdoutBufferMimeHeaders(): - if 'SUPPORTS=WMS' not in mapscript.msGetVersion(): + if "SUPPORTS=WMS" not in mapscript.msGetVersion(): pytest.skip() - map = mapscript.mapObj(get_relpath_to_this('test_mapio.map')) + map = mapscript.mapObj(get_relpath_to_this("test_mapio.map")) request = mapscript.OWSRequest() mapscript.msIO_installStdoutToBuffer() - request.loadParamsFromURL('service=WMS&version=1.1.1&request=GetMap&layers=grey&srs=EPSG:4326&bbox=-180,-90,180,90&format=image/png&width=80&height=40&STYLES=') + request.loadParamsFromURL( + "service=WMS&version=1.1.1&request=GetMap&layers=grey&srs=EPSG:4326&bbox=-180,-90,180,90&format=image/png&width=80&height=40&STYLES=" + ) status = map.OWSDispatch(request) assert status == 0 headers = mapscript.msIO_getAndStripStdoutBufferMimeHeaders() assert headers is not None - assert 'Content-Type' in headers - assert headers['Content-Type'] == 'image/png' - assert 'Cache-Control' in headers - assert headers['Cache-Control'] == 'max-age=86400' + assert "Content-Type" in headers + assert headers["Content-Type"] == "image/png" + assert "Cache-Control" in headers + assert headers["Cache-Control"] == "max-age=86400" result = mapscript.msIO_getStdoutBufferBytes() assert result is not None - assert result[1:4] == b'PNG' \ No newline at end of file + assert result[1:4] == b"PNG" diff --git a/msautotest/mspython/test_ogr_query.py b/msautotest/mspython/test_ogr_query.py index 2e96357faf..4b16fd56dc 100755 --- a/msautotest/mspython/test_ogr_query.py +++ b/msautotest/mspython/test_ogr_query.py @@ -9,17 +9,17 @@ # ############################################################################### # Copyright (c) 2010, Frank Warmerdam -# +# # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: -# +# # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. -# +# # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL @@ -31,97 +31,106 @@ # import os -import pytest import pmstestlib +import pytest mapscript_available = False try: import mapscript + mapscript_available = True except ImportError: pass -pytestmark = pytest.mark.skipif(not mapscript_available, reason="mapscript not available") +pytestmark = pytest.mark.skipif( + not mapscript_available, reason="mapscript not available" +) ############################################################################### # Dump query result set ... used when debugging this test script. -def dumpResultSet( layer ): + +def dumpResultSet(layer): layer.open() for i in range(1000): - result = layer.getResult( i ) + result = layer.getResult(i) if result is None: break - - print('(%d,%d)' % (result.shapeindex, result.tileindex)) - - s = layer.getShape( result ) + + print("(%d,%d)" % (result.shapeindex, result.tileindex)) + + s = layer.getShape(result) for i in range(layer.numitems): - print('%s: %s' % (layer.getItem(i), s.getValue(i))) - + print("%s: %s" % (layer.getItem(i), s.getValue(i))) + layer.close() def get_relpath_to_this(filename): return os.path.join(os.path.dirname(__file__), filename) + ############################################################################### # def check_EAS_ID_with_or_without_space(layer, s, expected_value): - name = 'EAS_ID' - actual_value = pmstestlib.get_item_value( layer, s, name ) + name = "EAS_ID" + actual_value = pmstestlib.get_item_value(layer, s, name) if actual_value is None: - print( 'missing expected attribute %s' % name ) + print("missing expected attribute %s" % name) return False if actual_value == expected_value or actual_value == expected_value.strip(): return True else: - print( 'attribute %s is "%s" instead of expected "%s"' % \ - (name, actual_value, str(expected_value)) ) + print( + 'attribute %s is "%s" instead of expected "%s"' + % (name, actual_value, str(expected_value)) + ) return False + ############################################################################### # Execute region query. + def test_ogr_query_2(): - map = mapscript.mapObj(get_relpath_to_this('ogr_query.map')) + map = mapscript.mapObj(get_relpath_to_this("ogr_query.map")) layer = map.getLayer(0) line = mapscript.lineObj() - line.add( mapscript.pointObj( 479000, 4763000 ) ) - line.add( mapscript.pointObj( 480000, 4763000 ) ) - line.add( mapscript.pointObj( 480000, 4764000 ) ) - line.add( mapscript.pointObj( 479000, 4764000 ) ) + line.add(mapscript.pointObj(479000, 4763000)) + line.add(mapscript.pointObj(480000, 4763000)) + line.add(mapscript.pointObj(480000, 4764000)) + line.add(mapscript.pointObj(479000, 4764000)) - poly = mapscript.shapeObj( mapscript.MS_SHAPE_POLYGON ) - poly.add( line ) + poly = mapscript.shapeObj(mapscript.MS_SHAPE_POLYGON) + poly.add(line) - layer.queryByShape( map, poly ) + layer.queryByShape(map, poly) ######################################################################### # Check result count. layer.open() count = 0 for i in range(1000): - result = layer.getResult( i ) + result = layer.getResult(i) if result is None: break - s = layer.getShape( result ) + s = layer.getShape(result) count = count + 1 assert count == 2 ######################################################################### # Check first shape attributes. - - result = layer.getResult( 0 ) - - s = layer.getShape( result ) - - assert check_EAS_ID_with_or_without_space( layer, s,' 158' ) + + result = layer.getResult(0) + + s = layer.getShape(result) + + assert check_EAS_ID_with_or_without_space(layer, s, " 158") ######################################################################### # Check first shape geometry. @@ -130,37 +139,38 @@ def test_ogr_query_2(): assert s.numlines == 1 try: - l = s.getLine( 0 ) - except: - l = s.get( 0 ) + l = s.getLine(0) + except Exception: + l = s.get(0) assert l.numpoints == 61 try: p = l.getPoint(0) - except: + except Exception: p = l.get(5) - assert abs(p.x-480984.25) < 0.01 and abs(p.y-4764875.0) < 0.01 + assert abs(p.x - 480984.25) < 0.01 and abs(p.y - 4764875.0) < 0.01 ######################################################################### # Check last shape attributes. - result = layer.getResult( 1 ) - - s = layer.getShape( result ) + result = layer.getResult(1) + + s = layer.getShape(result) + + assert check_EAS_ID_with_or_without_space(layer, s, " 165") + + layer.close() + layer.close() # discard resultset. - assert check_EAS_ID_with_or_without_space( layer, s,' 165' ) - - layer.close() - layer.close() # discard resultset. ############################################################################### # Execute multiple point query, and check result. -def test_ogr_query_4(): +def test_ogr_query_4(): - map = mapscript.mapObj(get_relpath_to_this('ogr_query.map')) + map = mapscript.mapObj(get_relpath_to_this("ogr_query.map")) layer = map.getLayer(0) rect = mapscript.rectObj() rect.minx = 479000 @@ -168,29 +178,29 @@ def test_ogr_query_4(): rect.miny = 4763000 rect.maxy = 4764000 - layer.queryByRect( map, rect ) + layer.queryByRect(map, rect) ######################################################################### # Check result count. layer.open() count = 0 for i in range(1000): - result = layer.getResult( i ) + result = layer.getResult(i) if result is None: break - + count = count + 1 assert count == 2 ######################################################################### # Check first shape attributes. - - result = layer.getResult( 0 ) - - s = layer.getShape( result ) - - assert check_EAS_ID_with_or_without_space( layer, s,' 158' ) + + result = layer.getResult(0) + + s = layer.getShape(result) + + assert check_EAS_ID_with_or_without_space(layer, s, " 158") ######################################################################### # Check first shape geometry. @@ -199,65 +209,68 @@ def test_ogr_query_4(): assert s.numlines == 1 try: - l = s.getLine( 0 ) - except: - l = s.get( 0 ) + l = s.getLine(0) + except Exception: + l = s.get(0) assert l.numpoints == 61 try: p = l.getPoint(0) - except: + except Exception: p = l.get(5) - assert abs(p.x-480984.25) < 0.01 and abs(p.y-4764875.0) < 0.01 + assert abs(p.x - 480984.25) < 0.01 and abs(p.y - 4764875.0) < 0.01 ######################################################################### # Check last shape attributes. - result = layer.getResult( 1 ) - - s = layer.getShape( result ) + result = layer.getResult(1) + + s = layer.getShape(result) + + assert check_EAS_ID_with_or_without_space(layer, s, " 165") + + layer.close() + layer.close() # discard resultset. - assert check_EAS_ID_with_or_without_space( layer, s,' 165' ) - - layer.close() - layer.close() # discard resultset. ############################################################################### # Confirm that we can still fetch features not in the result set directly # by their feature id. # # NOTE: the ability to fetch features without going through the query API -# seems to be gone in 6.0! +# seems to be gone in 6.0! + def test_ogr_query_6(): - pytest.skip('no longer work') + pytest.skip("no longer work") - map = mapscript.mapObj(get_relpath_to_this('ogr_query.map')) + map = mapscript.mapObj(get_relpath_to_this("ogr_query.map")) layer = map.getLayer(0) layer.open() - + ######################################################################### # Check first shape attributes. - s = mapscript.shapeObj( mapscript.MS_SHAPE_POLYGON ) - layer.resultsGetShape( s, 9, 0 ) - - assert check_EAS_ID_with_or_without_space( layer, s,' 170' ) + s = mapscript.shapeObj(mapscript.MS_SHAPE_POLYGON) + layer.resultsGetShape(s, 9, 0) + + assert check_EAS_ID_with_or_without_space(layer, s, " 170") + + layer.close() + layer.close() # discard resultset. - layer.close() - layer.close() # discard resultset. - ############################################################################### # Change the map extents and see if our query results have been altered. # With the current implementation they will be, though this might be # considered to be a defect. + def test_ogr_query_7(): - map = mapscript.mapObj(get_relpath_to_this('ogr_query.map')) + map = mapscript.mapObj(get_relpath_to_this("ogr_query.map")) layer = map.getLayer(0) rect = mapscript.rectObj() rect.minx = 479000 @@ -265,7 +278,7 @@ def test_ogr_query_7(): rect.miny = 4763000 rect.maxy = 4764000 - layer.queryByRect( map, rect ) + layer.queryByRect(map, rect) map.draw() @@ -274,22 +287,21 @@ def test_ogr_query_7(): layer.open() count = 0 for i in range(1000): - result = layer.getResult( i ) + result = layer.getResult(i) if result is None: break - + count = count + 1 assert count == 2 ######################################################################### # Check first shape attributes. - - result = layer.getResult( 0 ) - - s = layer.getShape( result ) - - assert check_EAS_ID_with_or_without_space( layer, s,' 168' ) - layer.close() - layer.close() # discard resultset. + result = layer.getResult(0) + + s = layer.getShape(result) + assert check_EAS_ID_with_or_without_space(layer, s, " 168") + + layer.close() + layer.close() # discard resultset. diff --git a/msautotest/mspython/test_postgis.py b/msautotest/mspython/test_postgis.py index 321732bf99..38fe11b6df 100755 --- a/msautotest/mspython/test_postgis.py +++ b/msautotest/mspython/test_postgis.py @@ -9,17 +9,17 @@ # ############################################################################### # Copyright (c) 2020, Even Rouault, -# +# # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: -# +# # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. -# +# # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL @@ -31,12 +31,13 @@ import sys -sys.path.append( '../pymod' ) +sys.path.append("../pymod") import pytest mapscript_available = False try: import mapscript + mapscript_available = True except ImportError: pass @@ -46,7 +47,8 @@ def is_postgis_db_installed(): map = mapscript.mapObj() layer = mapscript.layerObj(map) - layer.updateFromString(""" + layer.updateFromString( + """ LAYER CONNECTIONTYPE postgis CONNECTION "dbname=msautotest user=postgres" @@ -54,22 +56,28 @@ def is_postgis_db_installed(): DATA "the_geom from (select * from multipolygon3d order by id) as foo using srid=27700 using unique id" TYPE POLYGON END - """) + """ + ) try: layer.getNumFeatures() return True except mapscript.MapServerError: return False -pytestmark = [pytest.mark.skipif(not mapscript_available, - reason="mapscript not available"), - pytest.mark.skipif(mapscript_available and \ - 'INPUT=POSTGIS' not in mapscript.msGetVersion(), - reason='PostGIS support missing'), - pytest.mark.skipif(mapscript_available and \ - 'INPUT=POSTGIS' in mapscript.msGetVersion() \ - and not is_postgis_db_installed(), - reason="PostGIS 'msautotest' database not setup")] + +pytestmark = [ + pytest.mark.skipif(not mapscript_available, reason="mapscript not available"), + pytest.mark.skipif( + mapscript_available and "INPUT=POSTGIS" not in mapscript.msGetVersion(), + reason="PostGIS support missing", + ), + pytest.mark.skipif( + mapscript_available + and "INPUT=POSTGIS" in mapscript.msGetVersion() + and not is_postgis_db_installed(), + reason="PostGIS 'msautotest' database not setup", + ), +] ############################################################################### # @@ -79,7 +87,8 @@ def test_postgis_numfeatures(): map = mapscript.mapObj() layer = mapscript.layerObj(map) - layer.updateFromString(""" + layer.updateFromString( + """ LAYER CONNECTIONTYPE postgis CONNECTION "dbname=msautotest user=postgres" @@ -87,10 +96,12 @@ def test_postgis_numfeatures(): DATA "the_geom from (select * from multipolygon3d order by id) as foo using srid=27700 using unique id" TYPE POLYGON END - """) + """ + ) numfeatures = layer.getNumFeatures() assert numfeatures == 1 + ############################################################################### # @@ -99,7 +110,8 @@ def test_postgis_invalid_dbname(): map = mapscript.mapObj() layer = mapscript.layerObj(map) - layer.updateFromString(""" + layer.updateFromString( + """ LAYER CONNECTIONTYPE postgis CONNECTION "dbname=invalid_dbname" @@ -107,10 +119,12 @@ def test_postgis_invalid_dbname(): DATA "the_geom from (select * from multipolygon3d order by id) as foo using srid=27700 using unique id" TYPE POLYGON END - """) + """ + ) with pytest.raises(mapscript.MapServerError): layer.getNumFeatures() + ############################################################################### # @@ -119,14 +133,16 @@ def test_postgis_missing_data(): map = mapscript.mapObj() layer = mapscript.layerObj(map) - layer.updateFromString(""" + layer.updateFromString( + """ LAYER CONNECTIONTYPE postgis CONNECTION "dbname=msautotest user=postgres" NAME mylayer TYPE POLYGON END - """) + """ + ) with pytest.raises(mapscript.MapServerError): layer.getNumFeatures() @@ -134,21 +150,25 @@ def test_postgis_missing_data(): ############################################################################### # -@pytest.mark.parametrize("data", - ["the_geom from", - "the_geom from non_existing_table", - "the_geom from (select * from multipolygon3d)", # missing as foo - "the_geom from (select * from multipolygon3d) as foo using unique", # missing value for unique - "the_geom from (select * from multipolygon3d) as foo using unique id using srid=", # missing value for srid= - "the_geom from (select * from non_existing_table order by id) as foo using srid=27700 using unique id", - "the_geom from (select * from multipolygon3d order by id) using srid=27700 using unique id", # missing as foo - "the_geom from (select * from multipolygon3d order by id) as foo using srid=27700", # no using unique but subselect used - ]) + +@pytest.mark.parametrize( + "data", + [ + "the_geom from", + "the_geom from non_existing_table", + "the_geom from (select * from multipolygon3d)", # missing as foo + "the_geom from (select * from multipolygon3d) as foo using unique", # missing value for unique + "the_geom from (select * from multipolygon3d) as foo using unique id using srid=", # missing value for srid= + "the_geom from (select * from non_existing_table order by id) as foo using srid=27700 using unique id", + "the_geom from (select * from multipolygon3d order by id) as foo using srid=27700", # no using unique but subselect used + ], +) def test_postgis_invalid_data(data): map = mapscript.mapObj() layer = mapscript.layerObj(map) - layer.updateFromString(""" + layer.updateFromString( + """ LAYER CONNECTIONTYPE postgis CONNECTION "dbname=msautotest user=postgres" @@ -156,7 +176,9 @@ def test_postgis_invalid_data(data): DATA "%s" TYPE POLYGON END - """ % data) + """ + % data + ) with pytest.raises(mapscript.MapServerError): layer.getNumFeatures() @@ -164,20 +186,27 @@ def test_postgis_invalid_data(data): ############################################################################### # -@pytest.mark.parametrize("data", - ["the_geom from multipolygon3d", - "the_geom from (select * from multipolygon3d) as foo using unique id", - "the_geom FROM (SELECT * FROM multipolygon3d) AS foo USING UNIQUE id", - "the_geom from multipolygon3d using unique id", - "the_geom from multipolygon3d using srid=27700", - "the_geom from multipolygon3d using srid=27700 using unique id", - "the_geom from (select * from multipolygon3d) as foo using unique non_existing_column", - ]) + +@pytest.mark.parametrize( + "data", + [ + "the_geom from multipolygon3d", + "the_geom from (select * from multipolygon3d) as foo using unique id", + "the_geom FROM (SELECT * FROM multipolygon3d) AS foo USING UNIQUE id", + "the_geom from multipolygon3d using unique id", + "the_geom from multipolygon3d using srid=27700", + "the_geom from multipolygon3d using srid=27700 using unique id", + "the_geom from (select * from multipolygon3d) as foo using unique non_existing_column", + # as of pg16 an alias is no longer required for a subquery + "the_geom from (select * from multipolygon3d order by id) using srid=27700 using unique id", + ], +) def test_postgis_valid_data(data): map = mapscript.mapObj() layer = mapscript.layerObj(map) - layer.updateFromString(""" + layer.updateFromString( + """ LAYER CONNECTIONTYPE postgis CONNECTION "dbname=msautotest user=postgres" @@ -185,9 +214,12 @@ def test_postgis_valid_data(data): DATA "%s" TYPE POLYGON END - """ % data) + """ + % data + ) assert layer.getNumFeatures() == 1 + ############################################################################### # @@ -196,7 +228,8 @@ def test_postgis_box_substitution_getExtent(): map = mapscript.mapObj() layer = mapscript.layerObj(map) - layer.updateFromString(""" + layer.updateFromString( + """ LAYER CONNECTIONTYPE postgis CONNECTION "dbname=msautotest user=postgres" @@ -204,13 +237,15 @@ def test_postgis_box_substitution_getExtent(): NAME mylayer TYPE LINE END - """) + """ + ) extent = layer.getExtent() assert extent.minx == 1 assert extent.miny == 2 assert extent.maxx == 10 assert extent.maxy == 11 + ############################################################################### # @@ -219,7 +254,8 @@ def test_postgis_box_substitution_getNumFeatures(): map = mapscript.mapObj() layer = mapscript.layerObj(map) - layer.updateFromString(""" + layer.updateFromString( + """ LAYER CONNECTIONTYPE postgis CONNECTION "dbname=msautotest user=postgres" @@ -227,9 +263,11 @@ def test_postgis_box_substitution_getNumFeatures(): NAME mylayer TYPE LINE END - """) + """ + ) assert layer.getNumFeatures() == 1 + ############################################################################### # @@ -238,7 +276,8 @@ def test_postgis_box_bind_values_getExtent(): map = mapscript.mapObj() layer = mapscript.layerObj(map) - layer.updateFromString(""" + layer.updateFromString( + """ LAYER CONNECTIONTYPE postgis CONNECTION "dbname=msautotest user=postgres" @@ -249,12 +288,14 @@ def test_postgis_box_bind_values_getExtent(): END TYPE POLYGON END - """) + """ + ) extent = layer.getExtent() assert extent.minx < extent.maxx assert extent.miny < extent.maxy + ############################################################################### # @@ -263,7 +304,8 @@ def test_postgis_box_bind_values_getNumFeatures(): map = mapscript.mapObj() layer = mapscript.layerObj(map) - layer.updateFromString(""" + layer.updateFromString( + """ LAYER CONNECTIONTYPE postgis CONNECTION "dbname=msautotest user=postgres" @@ -274,10 +316,12 @@ def test_postgis_box_bind_values_getNumFeatures(): END TYPE POLYGON END - """) + """ + ) assert layer.getNumFeatures() == 15 + ############################################################################### # @@ -286,7 +330,8 @@ def test_postgis_box_bind_values_queryByRect(): map = mapscript.mapObj() layer = mapscript.layerObj(map) - layer.updateFromString(""" + layer.updateFromString( + """ LAYER CONNECTIONTYPE postgis CONNECTION "dbname=msautotest user=postgres" @@ -298,7 +343,8 @@ def test_postgis_box_bind_values_queryByRect(): TYPE POLYGON TEMPLATE "junk.tmpl" END - """) + """ + ) rect = mapscript.rectObj() rect.minx = -1e7 @@ -307,7 +353,7 @@ def test_postgis_box_bind_values_queryByRect(): rect.maxy = 1e7 layer.open() - layer.queryByRect( map, rect ) + layer.queryByRect(map, rect) count = 0 for i in range(1000): @@ -316,3 +362,115 @@ def test_postgis_box_bind_values_queryByRect(): break count += 1 assert count == 15 + + +############################################################################### +# Test fix for https://github.com/MapServer/MapServer/pull/5520 + + +def test_postgis_queryByFilter_bad_filteritem(): + + map = mapscript.mapObj() + layer = mapscript.layerObj(map) + layer.updateFromString( + """ + LAYER + CONNECTIONTYPE postgis + CONNECTION "dbname=msautotest user=postgres" + DATA "the_geom from (select * from province order by gid) as foo using unique gid" + NAME mylayer + TYPE POLYGON + TEMPLATE "junk.tmpl" + FILTER 'Cape Breton Island' + FILTERITEM 'bad_filter_item' + END + """ + ) + + layer.open() + try: + layer.queryByFilter(map, "1 = 1") + assert False + except mapscript.MapServerError: + pass + + # Check that original filter and filteritem are properly restored + assert layer.getFilterString() == '"Cape Breton Island"' + assert layer.filteritem == "bad_filter_item" + + +############################################################################### +# + + +def test_postgis_queryByFilter_bad_expression(): + + map = mapscript.mapObj() + layer = mapscript.layerObj(map) + layer.updateFromString( + """ + LAYER + CONNECTIONTYPE postgis + CONNECTION "dbname=msautotest user=postgres" + DATA "the_geom from (select * from province order by gid) as foo using unique gid" + NAME mylayer + TYPE POLYGON + TEMPLATE "junk.tmpl" + END + """ + ) + + layer.open() + try: + layer.queryByFilter(map, "ERROR") + except mapscript.MapServerError: + pass + + +############################################################################### +# + + +def test_postgis_trim_char_fields(): + + map = mapscript.mapObj() + layer = mapscript.layerObj(map) + layer.updateFromString( + """ + LAYER + CONNECTIONTYPE postgis + CONNECTION "dbname=msautotest user=postgres" + DATA "the_geom from (select * from text_datatypes order by id) as foo using srid=27700 using unique id" + NAME mylayer + TYPE POINT + TEMPLATE "junk.tmpl" + END + """ + ) + + layer.open() + rect = mapscript.rectObj() + rect.minx = -1000 + rect.maxx = 1000 + rect.miny = -1000 + rect.maxy = 1000 + + layer.queryByRect(map, rect) + result = layer.getResult(0) + assert result is not None + s = layer.getShape(result) + assert s is not None + assert [ + s.getValue(i) + for i in filter(lambda i: layer.getItem(i) == "mychar5", range(layer.numitems)) + ] == ["abc"] + assert [ + s.getValue(i) + for i in filter( + lambda i: layer.getItem(i) == "myvarchar5", range(layer.numitems) + ) + ] == ["def "] + assert [ + s.getValue(i) + for i in filter(lambda i: layer.getItem(i) == "mytext", range(layer.numitems)) + ] == ["ghi "] diff --git a/msautotest/mspython/test_projections.py b/msautotest/mspython/test_projections.py new file mode 100644 index 0000000000..bf2e8dfb66 --- /dev/null +++ b/msautotest/mspython/test_projections.py @@ -0,0 +1,127 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +############################################################################### +# Project: MapServer +# Purpose: Test suite for loading projections +# Author: Seth Girvin +# +############################################################################### +# Copyright (c) 2026, Seth Girvin, +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +############################################################################### + +import pytest + +mapscript_available = False +try: + import mapscript + + mapscript_available = True +except ImportError: + pass + +pytestmark = pytest.mark.skipif( + not mapscript_available, reason="mapscript not available" +) + + +def make_layer(): + map = mapscript.mapObj() + layer = mapscript.layerObj(map) + layer.name = "test_layer" + layer.status = mapscript.MS_ON + layer.type = mapscript.MS_LAYER_POLYGON + return layer + + +PROJECTION_CASES = [ + # (input, expected_output, marks) + ("+proj=utm +zone=11 +datum=WGS84", "+proj=utm +zone=11 +datum=WGS84"), + ("+proj=latlong +datum=WGS84", "+proj=latlong +datum=WGS84"), + ("+proj=ortho +datum=WGS84", "+proj=ortho +datum=WGS84"), + ("init=epsg:4326", "+init=epsg:4326"), + ("epsg:4326", "+init=epsg:4326"), + ("EPSG:4326", "+init=epsg:4326"), + ("EPSG:2157", "+init=epsg:2157"), + ("urn:ogc:def:crs:OGC:1.3:CRS84", "+init=epsg:4326"), + ("ESRI:53009", "ESRI:53009"), + ("AUTO:42001,9001,2.35,48.85", "AUTO:42001,9001,2.35,48.85"), + ("AUTO2:42005,1,0,90", "AUTO2:42005,1,0,90"), + # ensure the epsg2 file with the custom projection is in the PROJ_DATA folder + ("init=epsg2:42304", "+init=epsg2:42304"), + # custom projections should have init= appended to load from a file + ("epsg2:42304", "+init=epsg2:42304"), + ("http://www.opengis.net/def/crs/EPSG/0/4326", "+init=epsg:4326 +epsgaxis=ne"), + ("http://www.opengis.net/def/crs/EPSG/0/32615", "+init=epsg:32615"), + ("http://www.opengis.net/def/crs/ESRI/0/53009", "ESRI:53009"), + ("http://www.opengis.net/gml/srs/epsg.xml#4326", "+init=epsg:4326"), + ("urn:ogc:def:crs:ESRI::53009", "ESRI:53009"), + ("urn:ogc:def:crs:EPSG::4326", "+init=epsg:4326 +epsgaxis=ne"), + ("urn:ogc:def:crs:OGC:1.3:CRS84", "+init=epsg:4326"), + ("urn:x-ogc:def:crs:EPSG::3857", "+init=epsg:3857"), + ("urn:EPSG:geographicCRS:4326", "+init=epsg:4326 +epsgaxis=ne"), + ("urn:ogc:def:crs:EPSG::3857", "+init=epsg:3857"), + ("IAU_2015:30100", "IAU_2015:30100"), + ("IGNF:ATIGBONNE.BOURD", "IGNF:ATIGBONNE.BOURD"), + pytest.param( + "urn:x-ogc:def:crs:OGC:1.3:CRS84", + None, + marks=pytest.mark.xfail( + reason="OGC authority not supported in urn:x-ogc: handler" + ), + ), + pytest.param( + "urn:x-ogc:def:crs:OGC::CRS84", + None, + marks=pytest.mark.xfail( + reason="OGC authority not supported in urn:x-ogc: handler" + ), + ), + pytest.param( + "urn:ogc:def:crs:OGC::imageCRS", + None, + marks=pytest.mark.xfail( + reason="imageCRS is pixel space, not supported by PROJ" + ), + ), + # IAU_2015 is used by PROJ rather than IAU:2015 + pytest.param( + "IAU:2015:30100", + "IAU:2015:30100", + marks=pytest.mark.xfail(reason="IAU:2015 is handled as IAU_2015"), + ), + pytest.param( + "urn:ogc:def:crs:+", + None, + marks=pytest.mark.xfail(reason="Invalid projection string"), + ), +] + + +@pytest.mark.parametrize("input_str,expected", PROJECTION_CASES) +def test_projection_string(input_str, expected): + layer = make_layer() + layer.setProjection(input_str) + proj_string = layer.getProjection() + assert proj_string == expected + + layer2 = make_layer() + layer2.setProjection(proj_string) + assert layer2.getProjection() == expected diff --git a/msautotest/mspython/test_rq.py b/msautotest/mspython/test_rq.py index 703d8ab0f7..1bd6f81b98 100755 --- a/msautotest/mspython/test_rq.py +++ b/msautotest/mspython/test_rq.py @@ -9,17 +9,17 @@ # ############################################################################### # Copyright (c) 2004, Frank Warmerdam -# +# # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: -# +# # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. -# +# # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL @@ -29,8 +29,8 @@ # DEALINGS IN THE SOFTWARE. ############################################################################### -import os import math +import os import sys import pmstestlib @@ -39,52 +39,58 @@ mapscript_available = False try: import mapscript + mapscript_available = True except ImportError: pass -pytestmark = pytest.mark.skipif(not mapscript_available, reason="mapscript not available") +pytestmark = pytest.mark.skipif( + not mapscript_available, reason="mapscript not available" +) ############################################################################### # Dump query result set ... used when debugging this test script. -def dumpResultSet( layer ): + +def dumpResultSet(layer): layer.open() for i in range(1000): - result = layer.getResult( i ) + result = layer.getResult(i) if result is None: break - - print('(%d,%d)' % (result.shapeindex, result.tileindex)) - s = layer.getShape( result ) + print("(%d,%d)" % (result.shapeindex, result.tileindex)) + + s = layer.getShape(result) for i in range(layer.numitems): - print('%s: %s' % (layer.getItem(i), s.getValue(i))) - + print("%s: %s" % (layer.getItem(i), s.getValue(i))) + layer.close() def get_relpath_to_this(filename): return os.path.join(os.path.dirname(__file__), filename) + ############################################################################### # Execute region query. + def test_rq_2(): - map = mapscript.mapObj(get_relpath_to_this('../gdal/tileindex.map')) + map = mapscript.mapObj(get_relpath_to_this("../gdal/tileindex.map")) layer = map.getLayer(0) line = mapscript.lineObj() - line.add( mapscript.pointObj( 35, 25 ) ) - line.add( mapscript.pointObj( 45, 25 ) ) - line.add( mapscript.pointObj( 45, 35 ) ) - line.add( mapscript.pointObj( 35, 25 ) ) + line.add(mapscript.pointObj(35, 25)) + line.add(mapscript.pointObj(45, 25)) + line.add(mapscript.pointObj(45, 35)) + line.add(mapscript.pointObj(35, 25)) - poly = mapscript.shapeObj( mapscript.MS_SHAPE_POLYGON ) - poly.add( line ) + poly = mapscript.shapeObj(mapscript.MS_SHAPE_POLYGON) + poly.add(line) - layer.queryByShape( map, poly ) + layer.queryByShape(map, poly) # Scan results, checking count and the first shape information. @@ -93,28 +99,33 @@ def test_rq_2(): layer.open() count = 0 for i in range(1000): - result = layer.getResult( i ) + result = layer.getResult(i) if result is None: break - + count = count + 1 assert count == 55 ######################################################################### # Check first shape attributes. - - result = layer.getResult( 0 ) - s = layer.getShape( result ) - - pmstestlib.check_items( layer, s, - [('value_0','115'), - ('red','115'), - ('green','115'), - ('blue','115'), - ('value_list','115'), - ('x','39.5'), - ('y','29.5')] ) + + result = layer.getResult(0) + s = layer.getShape(result) + + pmstestlib.check_items( + layer, + s, + [ + ("value_0", "115"), + ("red", "115"), + ("green", "115"), + ("blue", "115"), + ("value_list", "115"), + ("x", "39.5"), + ("y", "29.5"), + ], + ) ######################################################################### # Check first shape geometry. @@ -123,130 +134,120 @@ def test_rq_2(): assert s.numlines == 1 try: - l = s.getLine( 0 ) - except: - l = s.get( 0 ) + l = s.getLine(0) + except Exception: + l = s.get(0) assert l.numpoints == 1 try: p = l.getPoint(0) - except: + except Exception: p = l.get(0) assert p.x == 39.5 assert p.y == 29.5 - + ######################################################################### # Check last shape attributes. - result = layer.getResult( 54 ) - s = layer.getShape( result ) + result = layer.getResult(54) + s = layer.getShape(result) + + pmstestlib.check_items(layer, s, [("value_0", "132"), ("x", "44.5"), ("y", "25.5")]) + layer.close() # discard resultset. - pmstestlib.check_items( layer, s, - [('value_0','132'), - ('x','44.5'), - ('y','25.5')] ) - layer.close() - layer.close() # discard resultset. ############################################################################### # Execute multiple point query, and check result. + def test_rq_4(): - map = mapscript.mapObj(get_relpath_to_this('../gdal/tileindex.map')) + map = mapscript.mapObj(get_relpath_to_this("../gdal/tileindex.map")) layer = map.getLayer(0) pnt = mapscript.pointObj() pnt.x = 35.5 pnt.y = 25.5 - - layer.queryByPoint( map, pnt, mapscript.MS_MULTIPLE, - 1.25 ) + + layer.queryByPoint(map, pnt, mapscript.MS_MULTIPLE, 1.25) ######################################################################### # Check result count. layer.open() count = 0 for i in range(1000): - result = layer.getResult( i ) + result = layer.getResult(i) if result is None: break - + count = count + 1 assert count == 9 ######################################################################### # Check first shape attributes. - - result = layer.getResult( 0 ) - s = layer.getShape( result ) - pmstestlib.check_items( layer, s, - [('value_0','123'), - ('x','34.5'), - ('y','26.5')] ) + result = layer.getResult(0) + s = layer.getShape(result) + + pmstestlib.check_items(layer, s, [("value_0", "123"), ("x", "34.5"), ("y", "26.5")]) ######################################################################### # Check last shape attributes. - result = layer.getResult( 8 ) - s = layer.getShape( result ) + result = layer.getResult(8) + s = layer.getShape(result) + + pmstestlib.check_items(layer, s, [("value_0", "107"), ("x", "36.5"), ("y", "24.5")]) + layer.close() # discard resultset. - pmstestlib.check_items( layer, s, - [('value_0','107'), - ('x','36.5'), - ('y','24.5')] ) - layer.close() - layer.close() # discard resultset. ############################################################################### # Execute multiple point query, and check result. Also operates on map, # instead of layer. + def test_rq_6(): - map = mapscript.mapObj(get_relpath_to_this('../gdal/tileindex.map')) + map = mapscript.mapObj(get_relpath_to_this("../gdal/tileindex.map")) layer = map.getLayer(0) pnt = mapscript.pointObj() pnt.x = 35.2 pnt.y = 25.3 - - map.queryByPoint( pnt, mapscript.MS_SINGLE, 10.0 ) + + map.queryByPoint(pnt, mapscript.MS_SINGLE, 10.0) ######################################################################### # Check result count. layer.open() count = 0 for i in range(1000): - result = layer.getResult( i ) + result = layer.getResult(i) if result is None: break - + count = count + 1 assert count == 1 ######################################################################### # Check first shape attributes. - - result = layer.getResult( 0 ) - s = layer.getShape( result ) - - pmstestlib.check_items( layer, s, - [('value_0','115'), - ('x','35.5'), - ('y','25.5')] ) - layer.close() - layer.close() # discard resultset. + + result = layer.getResult(0) + s = layer.getShape(result) + + pmstestlib.check_items(layer, s, [("value_0", "115"), ("x", "35.5"), ("y", "25.5")]) + layer.close() # discard resultset. + ############################################################################### # Execute multiple point query, and check result. + def test_rq_8(): - map = mapscript.mapObj(get_relpath_to_this('../gdal/tileindex.map')) + map = mapscript.mapObj(get_relpath_to_this("../gdal/tileindex.map")) layer = map.getLayer(0) rect = mapscript.rectObj() @@ -255,99 +256,114 @@ def test_rq_8(): rect.miny = 25 rect.maxy = 35 - layer.queryByRect( map, rect ) + layer.queryByRect(map, rect) ######################################################################### # Check result count. layer.open() count = 0 for i in range(1000): - result = layer.getResult( i ) + result = layer.getResult(i) if result is None: break - + count = count + 1 assert count == 100 ######################################################################### # Check first shape attributes. - - result = layer.getResult( 0 ) - s = layer.getShape( result ) - - pmstestlib.check_items( layer, s, - [('value_0','148'), - ('red','148'), - ('green','148'), - ('blue','148'), - ('value_list','148'), - ('x','35.5'), - ('y','34.5')] ) - + + result = layer.getResult(0) + s = layer.getShape(result) + + pmstestlib.check_items( + layer, + s, + [ + ("value_0", "148"), + ("red", "148"), + ("green", "148"), + ("blue", "148"), + ("value_list", "148"), + ("x", "35.5"), + ("y", "34.5"), + ], + ) + ######################################################################### # Check last shape attributes. - result = layer.getResult( 99 ) - s = layer.getShape( result ) - - pmstestlib.check_items( layer, s, - [('value_0','132'), - ('red','132'), - ('green','132'), - ('blue','132'), - ('value_list','132'), - ('x','44.5'), - ('y','25.5')] ) - layer.close() - layer.close() # discard resultset. - - + result = layer.getResult(99) + s = layer.getShape(result) + + pmstestlib.check_items( + layer, + s, + [ + ("value_0", "132"), + ("red", "132"), + ("green", "132"), + ("blue", "132"), + ("value_list", "132"), + ("x", "44.5"), + ("y", "25.5"), + ], + ) + layer.close() # discard resultset. + + ############################################################################### # Execute a shape query without any tolerance and a line query region. + def test_rq_9(): - map = mapscript.mapObj(get_relpath_to_this('../gdal/tileindex.map')) + map = mapscript.mapObj(get_relpath_to_this("../gdal/tileindex.map")) layer = map.getLayer(0) line = mapscript.lineObj() - line.add( mapscript.pointObj( 35, 25 ) ) - line.add( mapscript.pointObj( 45, 25 ) ) - line.add( mapscript.pointObj( 45, 35 ) ) - line.add( mapscript.pointObj( 35, 25 ) ) + line.add(mapscript.pointObj(35, 25)) + line.add(mapscript.pointObj(45, 25)) + line.add(mapscript.pointObj(45, 35)) + line.add(mapscript.pointObj(35, 25)) - poly = mapscript.shapeObj( mapscript.MS_SHAPE_LINE ) - poly.add( line ) + poly = mapscript.shapeObj(mapscript.MS_SHAPE_LINE) + poly.add(line) - layer.queryByShape( map, poly ) + layer.queryByShape(map, poly) ######################################################################### # Check result count. layer.open() count = 0 for i in range(1000): - result = layer.getResult( i ) + result = layer.getResult(i) if result is None: break - + count = count + 1 assert count == 47 ######################################################################### # Check first shape attributes. - - result = layer.getResult( 0 ) - s = layer.getShape( result ) - - pmstestlib.check_items( layer, s, - [('value_0','115'), - ('red','115'), - ('green','115'), - ('blue','115'), - ('value_list','115'), - ('x','39.5'), - ('y','29.5')] ) + + result = layer.getResult(0) + s = layer.getShape(result) + + pmstestlib.check_items( + layer, + s, + [ + ("value_0", "115"), + ("red", "115"), + ("green", "115"), + ("blue", "115"), + ("value_list", "115"), + ("x", "39.5"), + ("y", "29.5"), + ], + ) ######################################################################### # Check first shape geometry. @@ -355,97 +371,103 @@ def test_rq_9(): assert s.numlines == 1 try: - l = s.getLine( 0 ) - except: - l = s.get( 0 ) + l = s.getLine(0) + except Exception: + l = s.get(0) assert l.numpoints == 1 try: p = l.getPoint(0) - except: + except Exception: p = l.get(0) assert p.x == 39.5 assert p.y == 29.5 - + ######################################################################### # Check last shape attributes. - result = layer.getResult( 46 ) - s = layer.getShape( result ) + result = layer.getResult(46) + s = layer.getShape(result) + + pmstestlib.check_items(layer, s, [("value_0", "148"), ("x", "44.5"), ("y", "24.5")]) + layer.close() # discard resultset. - pmstestlib.check_items( layer, s, - [('value_0','148'), - ('x','44.5'), - ('y','24.5')] ) - layer.close() - layer.close() # discard resultset. - ############################################################################### # Open a classified map and post a point query. + def test_rq_10(): + """ + This test requires the GIF driver to be available in GDAL, by setting GDAL_DRIVER_PATH + """ - map = mapscript.mapObj(get_relpath_to_this('../gdal/classtest1.map')) + map = mapscript.mapObj(get_relpath_to_this("../gdal/classtest1.map")) layer = map.getLayer(0) pnt = mapscript.pointObj() pnt.x = 88.5 pnt.y = 7.5 - - layer.queryByPoint( map, pnt, mapscript.MS_SINGLE, - 10.0 ) + + layer.queryByPoint(map, pnt, mapscript.MS_SINGLE, 10.0) ############################################################################### # Scan results. This query is for a transparent pixel within the "x" of # the cubewerx logo. In the future the raster query may well stop returning # "offsite" pixels and we will need to update this test. - ######################################################################### # Check result count. layer.open() count = 0 for i in range(1000): - result = layer.getResult( i ) + result = layer.getResult(i) if result is None: break - + count = count + 1 assert count == 1 ######################################################################### # Check first shape attributes. - - result = layer.getResult( 0 ) - s = layer.getShape( result ) - - pmstestlib.check_items( layer, s, - [('value_0','0'), - ('red','-255'), - ('green','-255'), - ('blue','-255'), - ('class','Text'), - ('x','88.5'), - ('y','7.5')] ) - layer.close() - layer.close() # discard resultset. + + result = layer.getResult(0) + s = layer.getShape(result) + + pmstestlib.check_items( + layer, + s, + [ + ("value_0", "0"), + ("red", "-255"), + ("green", "-255"), + ("blue", "-255"), + ("class", "Text"), + ("x", "88.5"), + ("y", "7.5"), + ], + ) + layer.close() # discard resultset. + ############################################################################### -# Issue another point query, on colored text. +# Issue another point query, on colored text. + -def rqtest_12(): +def test_rqtest_12(): + """ + This test requires the GIF driver to be available in GDAL, by setting GDAL_DRIVER_PATH + """ - map = mapscript.mapObj(get_relpath_to_this('../gdal/classtest1.map')) + map = mapscript.mapObj(get_relpath_to_this("../gdal/classtest1.map")) layer = map.getLayer(0) pnt = mapscript.pointObj() pnt.x = 13.5 pnt.y = 36.5 - pmstestlib.layer.queryByPoint( map, pnt, mapscript.MS_SINGLE, - 10.0 ) + layer.queryByPoint(map, pnt, mapscript.MS_SINGLE, 10.0) ############################################################################### # Scan results. This query is for a pixel at a grid intersection. This @@ -457,45 +479,49 @@ def rqtest_12(): layer.open() count = 0 for i in range(1000): - result = layer.getResult( i ) + result = layer.getResult(i) if result is None: break - + count = count + 1 assert count == 1 - result = layer.getResult( 0 ) - s = layer.getShape( result ) - - pmstestlib.check_items( layer, s, - [('value_0','1'), - ('red','255'), - ('green','0'), - ('blue','0'), - ('class','Grid'), - ('x','13.5'), - ('y','36.5')] ) - layer.close() - layer.close() # discard resultset. - - + result = layer.getResult(0) + s = layer.getShape(result) + + pmstestlib.check_items( + layer, + s, + [ + ("value_0", "1"), + ("red", "255"), + ("green", "0"), + ("blue", "0"), + ("class", "Grid"), + ("x", "13.5"), + ("y", "36.5"), + ], + ) + layer.close() # discard resultset. + + ############################################################################### # Revert to tileindex.map and do a test where we force reprojection + def test_rq_14(): - map = mapscript.mapObj(get_relpath_to_this('../gdal/tileindex.map')) + map = mapscript.mapObj(get_relpath_to_this("../gdal/tileindex.map")) layer = map.getLayer(0) map.setProjection("+proj=utm +zone=30 +datum=WGS84") pnt = mapscript.pointObj() - pnt.x = 889690 - pnt.y = 55369 - - layer.queryByPoint( map, pnt, mapscript.MS_MULTIPLE, - 200000.0 ) + pnt.x = 889690 + pnt.y = 55369 + + layer.queryByPoint(map, pnt, mapscript.MS_MULTIPLE, 200000.0) ############################################################################### # Check result count, and that the results are within the expected distance. @@ -503,119 +529,117 @@ def test_rq_14(): # coordinates from the lat long system of the layer. pnt = mapscript.pointObj() - pnt.x = 889690 - pnt.y = 55369 - + pnt.x = 889690 + pnt.y = 55369 + ######################################################################### # Check result count. layer.open() count = 0 for i in range(1000): - result = layer.getResult( i ) + result = layer.getResult(i) if result is None: break count = count + 1 - s = layer.getShape( result ) - x = float(pmstestlib.get_item_value( layer, s, 'x' )) - y = float(pmstestlib.get_item_value( layer, s, 'y' )) - dist_sq = (x-pnt.x) * (x-pnt.x) + (y-pnt.y) * (y-pnt.y) - dist = math.pow(dist_sq,0.5) + s = layer.getShape(result) + x = float(pmstestlib.get_item_value(layer, s, "x")) + y = float(pmstestlib.get_item_value(layer, s, "y")) + dist_sq = (x - pnt.x) * (x - pnt.x) + (y - pnt.y) * (y - pnt.y) + dist = math.pow(dist_sq, 0.5) assert dist <= 200000.0 assert count == 4 - layer.close() - layer.close() # discard resultset. + layer.close() # discard resultset. + ############################################################################### # Make a similar test with the tileindex file in mapinfo format (#2796) + def test_rq_16(): - map = mapscript.mapObj(get_relpath_to_this('../gdal/tileindex_mi.map')) + map = mapscript.mapObj(get_relpath_to_this("../gdal/tileindex_mi.map")) layer = map.getLayer(0) map.setProjection("+proj=utm +zone=30 +datum=WGS84") pnt = mapscript.pointObj() - pnt.x = 889690 - pnt.y = 55369 + pnt.x = 889690 + pnt.y = 55369 - layer.queryByPoint( map, pnt, mapscript.MS_MULTIPLE, - 200000.0 ) + layer.queryByPoint(map, pnt, mapscript.MS_MULTIPLE, 200000.0) ############################################################################### # Check result count, and that the results are within the expected distance. # This also implicitly verifies the results were reprojected back to UTM # coordinates from the lat long system of the layer. - pnt = mapscript.pointObj() - pnt.x = 889690 - pnt.y = 55369 - + pnt.x = 889690 + pnt.y = 55369 + ######################################################################### # Check result count. layer.open() count = 0 for i in range(1000): - result = layer.getResult( i ) + result = layer.getResult(i) if result is None: break count = count + 1 - s = layer.getShape( result ) - x = float(pmstestlib.get_item_value( layer, s, 'x' )) - y = float(pmstestlib.get_item_value( layer, s, 'y' )) - dist_sq = (x-pnt.x) * (x-pnt.x) + (y-pnt.y) * (y-pnt.y) - dist = math.pow(dist_sq,0.5) + s = layer.getShape(result) + x = float(pmstestlib.get_item_value(layer, s, "x")) + y = float(pmstestlib.get_item_value(layer, s, "y")) + dist_sq = (x - pnt.x) * (x - pnt.x) + (y - pnt.y) * (y - pnt.y) + dist = math.pow(dist_sq, 0.5) assert dist <= 200000.0 assert count == 4 - layer.close() - layer.close() # discard resultset. + layer.close() # discard resultset. + ############################################################################### # Test a layer with a tileindex with mixed SRS -@pytest.mark.skipif(sys.platform == 'win32', reason="Fails on Windows") + +@pytest.mark.skipif(sys.platform == "win32", reason="Fails on Windows") def test_rq_18(): - map = mapscript.mapObj(get_relpath_to_this('../gdal/tileindexmixedsrs.map')) + map = mapscript.mapObj(get_relpath_to_this("../gdal/tileindexmixedsrs.map")) layer = map.getLayer(0) map.setProjection("+proj=latlong +datum=WGS84") pnt = mapscript.pointObj() - pnt.x = -117.6 - pnt.y = 33.9 + pnt.x = -117.6 + pnt.y = 33.9 - layer.queryByPoint( map, pnt, mapscript.MS_SINGLE, - 0.001 ) + layer.queryByPoint(map, pnt, mapscript.MS_SINGLE, 0.001) ######################################################################### # Check result count. layer.open() count = 0 for i in range(1000): - result = layer.getResult( i ) + result = layer.getResult(i) if result is None: break count = count + 1 - s = layer.getShape( result ) - x = float(pmstestlib.get_item_value( layer, s, 'x' )) - y = float(pmstestlib.get_item_value( layer, s, 'y' )) - dist_sq = (x-pnt.x) * (x-pnt.x) + (y-pnt.y) * (y-pnt.y) - dist = math.pow(dist_sq,0.5) + s = layer.getShape(result) + x = float(pmstestlib.get_item_value(layer, s, "x")) + y = float(pmstestlib.get_item_value(layer, s, "y")) + dist_sq = (x - pnt.x) * (x - pnt.x) + (y - pnt.y) * (y - pnt.y) + dist = math.pow(dist_sq, 0.5) assert dist <= 0.001 assert count == 1 - layer.close() - layer.close() # discard resultset. + layer.close() # discard resultset. diff --git a/msautotest/mspython/test_wkt.py b/msautotest/mspython/test_wkt.py index e6e3e991a6..f4fcb7fd96 100755 --- a/msautotest/mspython/test_wkt.py +++ b/msautotest/mspython/test_wkt.py @@ -9,17 +9,17 @@ # ############################################################################### # Copyright (c) 2006, Frank Warmerdam -# +# # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: -# +# # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. -# +# # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL @@ -28,7 +28,7 @@ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. ############################################################################### -# +# # $Log$ # Revision 1.1 2006/09/05 20:40:04 frank # New @@ -40,47 +40,55 @@ mapscript_available = False try: import mapscript + mapscript_available = True except ImportError: pass -pytestmark = pytest.mark.skipif(not mapscript_available, reason="mapscript not available") +pytestmark = pytest.mark.skipif( + not mapscript_available, reason="mapscript not available" +) ############################################################################### # Test simple geometries that should convert back to same thing - OGR only. + def test_wkt_1(): - if 'SUPPORTS=GEOS' in mapscript.msGetVersion(): + if "SUPPORTS=GEOS" in mapscript.msGetVersion(): pytest.skip() - wkt_list = [ 'POINT (5 7)', - 'LINESTRING (5 7, 7 9, 9 -1)', - 'POLYGON ((500 500, 3500 500, 3500 2500, 500 2500, 500 500), ' - '(1000 1000, 1000 1500, 1500 1500, 1500 1000, 1000 1000))', - 'MULTIPOINT (2000 2000, 2000 1900)', - 'MULTILINESTRING ((600 1500, 1600 2500), (700 1500, 1700 2500))'] + wkt_list = [ + "POINT (5 7)", + "LINESTRING (5 7, 7 9, 9 -1)", + "POLYGON ((500 500, 3500 500, 3500 2500, 500 2500, 500 500), " + "(1000 1000, 1000 1500, 1500 1500, 1500 1000, 1000 1000))", + "MULTIPOINT (2000 2000, 2000 1900)", + "MULTILINESTRING ((600 1500, 1600 2500), (700 1500, 1700 2500))", + ] for orig_wkt in wkt_list: - shp = mapscript.shapeObj.fromWKT( orig_wkt ) - new_wkt = shp.toWKT().replace('.0000000000000000', '') + shp = mapscript.shapeObj.fromWKT(orig_wkt) + new_wkt = shp.toWKT().replace(".0000000000000000", "") assert new_wkt == orig_wkt + ############################################################################### # Test MULTIPOLYGON which will translate back as a POLYGON since MapServer # doesn't know how to distinguish - OGR Only. + def test_wkt_2(): - if 'SUPPORTS=GEOS' in mapscript.msGetVersion(): + if "SUPPORTS=GEOS" in mapscript.msGetVersion(): pytest.skip() - orig_wkt = 'MULTIPOLYGON(((50 50, 350 50, 350 250, 50 250, 50 50)),((250 150, 550 150, 550 350, 250 350, 250 150)))' - expected_wkt = 'POLYGON ((50 50, 350 50, 350 250, 50 250, 50 50), (250 150, 550 150, 550 350, 250 350, 250 150))' - - shp = mapscript.shapeObj.fromWKT( orig_wkt ) - new_wkt = shp.toWKT().replace('.0000000000000000', '') + orig_wkt = "MULTIPOLYGON(((50 50, 350 50, 350 250, 50 250, 50 50)),((250 150, 550 150, 550 350, 250 350, 250 150)))" + expected_wkt = "POLYGON ((50 50, 350 50, 350 250, 50 250, 50 50), (250 150, 550 150, 550 350, 250 350, 250 150))" + + shp = mapscript.shapeObj.fromWKT(orig_wkt) + new_wkt = shp.toWKT().replace(".0000000000000000", "") assert new_wkt == expected_wkt @@ -88,20 +96,30 @@ def test_wkt_2(): ############################################################################### # Test simple geometries that should convert back to same thing - GEOS only. + def test_wkt_3(): - if 'SUPPORTS=GEOS' not in mapscript.msGetVersion(): + if "SUPPORTS=GEOS" not in mapscript.msGetVersion(): pytest.skip() - - wkt_list = [ 'POINT (5.0000000000000000 7.0000000000000000)', - 'LINESTRING (5.0000000000000000 7.0000000000000000, 7.0000000000000000 9.0000000000000000, 9.0000000000000000 -1.0000000000000000)', - 'POLYGON ((500.0000000000000000 500.0000000000000000, 3500.0000000000000000 500.0000000000000000, 3500.0000000000000000 2500.0000000000000000, 500.0000000000000000 2500.0000000000000000, 500.0000000000000000 500.0000000000000000), (1000.0000000000000000 1000.0000000000000000, 1000.0000000000000000 1500.0000000000000000, 1500.0000000000000000 1500.0000000000000000, 1500.0000000000000000 1000.0000000000000000, 1000.0000000000000000 1000.0000000000000000))', - 'MULTIPOINT (2000.0000000000000000 2000.0000000000000000, 2000.0000000000000000 1900.0000000000000000)', - 'MULTILINESTRING ((600.0000000000000000 1500.0000000000000000, 1600.0000000000000000 2500.0000000000000000), (700.0000000000000000 1500.0000000000000000, 1700.0000000000000000 2500.0000000000000000))'] + wkt_list = [ + "POINT (5.0000000000000000 7.0000000000000000)", + "LINESTRING (5.0000000000000000 7.0000000000000000, 7.0000000000000000 9.0000000000000000, 9.0000000000000000 -1.0000000000000000)", + "POLYGON ((500.0000000000000000 500.0000000000000000, 3500.0000000000000000 500.0000000000000000, 3500.0000000000000000 2500.0000000000000000, 500.0000000000000000 2500.0000000000000000, 500.0000000000000000 500.0000000000000000), (1000.0000000000000000 1000.0000000000000000, 1000.0000000000000000 1500.0000000000000000, 1500.0000000000000000 1500.0000000000000000, 1500.0000000000000000 1000.0000000000000000, 1000.0000000000000000 1000.0000000000000000))", + "MULTIPOINT (2000.0000000000000000 2000.0000000000000000, 2000.0000000000000000 1900.0000000000000000)", + "MULTILINESTRING ((600.0000000000000000 1500.0000000000000000, 1600.0000000000000000 2500.0000000000000000), (700.0000000000000000 1500.0000000000000000, 1700.0000000000000000 2500.0000000000000000))", + ] for orig_wkt in wkt_list: - shp = mapscript.shapeObj.fromWKT( orig_wkt ) + shp = mapscript.shapeObj.fromWKT(orig_wkt) new_wkt = shp.toWKT() - assert new_wkt == orig_wkt + # Recent GEOS versions format as MULTIPOINT ((x1,y1),(x2,y2)) + if ( + orig_wkt.startswith("MULTIPOINT") + and new_wkt + == "MULTIPOINT ((2000.0000000000000000 2000.0000000000000000), (2000.0000000000000000 1900.0000000000000000))" + ): + pass + else: + assert new_wkt == orig_wkt diff --git a/msautotest/mspython/test_wms_client.py b/msautotest/mspython/test_wms_client.py new file mode 100644 index 0000000000..caf9f9c16b --- /dev/null +++ b/msautotest/mspython/test_wms_client.py @@ -0,0 +1,55 @@ +import os + +import pytest + +mapscript_available = False +try: + import mapscript + + mapscript_available = True +except ImportError: + pass + +pytestmark = [ + pytest.mark.skipif(not mapscript_available, reason="mapscript not available"), + pytest.mark.skipif( + "SUPPORTS=WMS_CLIENT" not in mapscript.msGetVersion(), + reason="WMS Client is not enabled", + ), +] + + +def get_relpath_to_this(filename): + return os.path.join(os.path.dirname(__file__), filename) + + +############################################################################### +# Test that WMS client GetMap request does not modify layer extent or projection + + +def test_wms_client_does_not_modify_layer(): + map = mapscript.mapObj(get_relpath_to_this("wms_client.map")) + + layerObj = map.getLayer(0) + assert layerObj.getExtent().minx == -180 + assert layerObj.getExtent().miny == -90 + assert layerObj.getExtent().maxx == 180 + assert layerObj.getExtent().maxy == 90 + assert layerObj.getProjection() == "+init=epsg:4326" + + # Do a GetMap request in EPSG:32633 + request = mapscript.OWSRequest() + mapscript.msIO_installStdoutToBuffer() + request.loadParamsFromURL( + "&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMap&LAYERS=client&STYLES=&WIDTH=300&HEIGHT=200&FORMAT=image/png&CRS=EPSG:32633&BBOX=920482.6044580448652,7662266.090040001087,1317920.914512843126,8079762.906353433616" + ) + status = map.OWSDispatch(request) + + assert status == 0 + + # Assert that layer extent and projection is not modified + assert layerObj.getExtent().minx == -180 + assert layerObj.getExtent().miny == -90 + assert layerObj.getExtent().maxx == 180 + assert layerObj.getExtent().maxy == 90 + assert layerObj.getProjection() == "+init=epsg:4326" diff --git a/msautotest/mspython/test_xmp.py b/msautotest/mspython/test_xmp.py index b756fcd765..adf07ae266 100755 --- a/msautotest/mspython/test_xmp.py +++ b/msautotest/mspython/test_xmp.py @@ -9,17 +9,17 @@ # ############################################################################### # Copyright (c) 2013, Even Rouault, -# +# # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: -# +# # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. -# +# # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL @@ -30,16 +30,20 @@ ############################################################################### import os + import pytest mapscript_available = False try: import mapscript + mapscript_available = True except ImportError: pass -pytestmark = pytest.mark.skipif(not mapscript_available, reason="mapscript not available") +pytestmark = pytest.mark.skipif( + not mapscript_available, reason="mapscript not available" +) def get_relpath_to_this(filename): @@ -49,36 +53,40 @@ def get_relpath_to_this(filename): ############################################################################### # + def test_xmp(): - if 'SUPPORTS=XMP' not in mapscript.msGetVersion(): + if "SUPPORTS=XMP" not in mapscript.msGetVersion(): pytest.skip() - map = mapscript.mapObj(get_relpath_to_this('test_xmp.map')) + map = mapscript.mapObj(get_relpath_to_this("test_xmp.map")) img = map.draw() try: - os.mkdir(get_relpath_to_this('result')) - except: + os.mkdir(get_relpath_to_this("result")) + except Exception: pass - resultfile = get_relpath_to_this('result/test_xmp.png') - img.save(resultfile, map ) + resultfile = get_relpath_to_this("result/test_xmp.png") + img.save(resultfile, map) - f = open(resultfile, 'rb') - data = f.read() + f = open(resultfile, "rb") + data = f.read().decode("utf-8", "ignore") f.close() def dump_md(): try: from osgeo import gdal + ds = gdal.Open(resultfile) - print(ds.GetMetadata('xml:XMP')) + print(ds.GetMetadata("xml:XMP")) ds = None - except: + except Exception: pass assert 'dc:Title="Super Map"' in data, dump_md() assert 'xmpRights:Marked="true"' in data, dump_md() - assert 'cc:License="http://creativecommons.org/licenses/by-sa/2.0/"' in data, dump_md() + assert ( + 'cc:License="http://creativecommons.org/licenses/by-sa/2.0/"' in data + ), dump_md() assert 'xmlns:lightroom="http://ns.adobe.com/lightroom/1.0/"' in data, dump_md() assert 'lightroom:PrivateRTKInfo="My Information Here"' in data, dump_md() assert 'exif:ExifVersion="dummy"' in data, dump_md() diff --git a/msautotest/mspython/wms_client.map b/msautotest/mspython/wms_client.map new file mode 100644 index 0000000000..37c86ae36a --- /dev/null +++ b/msautotest/mspython/wms_client.map @@ -0,0 +1,51 @@ + + +MAP + NAME WMS_CLIENT_TEST_130 + STATUS ON + SIZE 400 300 + EXTENT -180 -90 180 90 + UNITS DD + PROJECTION + "init=epsg:4326" + END + IMAGECOLOR 255 255 255 + #SYMBOLSET etc/symbols.sym + #FONTSET etc/fonts.txt + + RESOLUTION 96 + IMAGETYPE png24 + + WEB + IMAGEPATH "/tmp/ms_tmp/" + IMAGEURL "/ms_tmp/" + METADATA + "ows_updatesequence" "123" + "wms_title" "Test WMS 1.3.0 client" + "wms_srs" "EPSG:4326" + "ows_enable_request" "*" + "wms_getmap_formatlist" "image/png,image/png; mode=24bit" + "ows_onlineresource" "http://localhost/wmsclient?" + END + END + + LAYER + NAME client + TYPE RASTER + STATUS ON + CONNECTION "https://demo.mapserver.org/cgi-bin/wms?" + CONNECTIONTYPE WMS + TEMPLATE "dummy" + EXTENT -180 -90 180 90 + METADATA + "wms_srs" "EPSG:4326 EPSG:32633" + "wms_name" "cities" + "wms_server_version" "1.3.0" + "wms_format" "image/png" + "wms_enable_request" "*" + END + PROJECTION + "init=epsg:4326" + END + END +END diff --git a/msautotest/mssql/cluster_mssql.map b/msautotest/mssql/cluster_mssql.map new file mode 100644 index 0000000000..33acda6e84 --- /dev/null +++ b/msautotest/mssql/cluster_mssql.map @@ -0,0 +1,54 @@ +# +# Test a clustered layer with the MSSQL driver plugin +# +# REQUIRES: OUTPUT=PNG +# +# RUN_PARMS: cluster_mssql.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: cluster_mssql_getmetadata.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&REQUEST=GetMetadata&LAYER=cities" > [RESULT_DEMIME] + +MAP + NAME 'cluster_mssql' + + PROJECTION + "init=epsg:3857" + END + + SYMBOL + NAME "circle" + TYPE ellipse + POINTS 1 1 END + FILLED true + END + + EXTENT -20026376.39 -20048966.10 20026376.39 20048966.10 + UNITS METERS + SIZE 300 300 + IMAGETYPE png24 + LAYER + NAME 'cities' + INCLUDE 'include/mssql_connection.map' + TYPE POINT + PROCESSING "CLUSTER_ALGORITHM=SIMPLE" + PROCESSING "CLUSTER_GET_ALL_SHAPES=OFF" + PROCESSING "CLUSTER_KEEP_LOCATIONS=OFF" + STATUS ON + DATA "ogr_geometry from (select * from cities) as foo USING UNIQUE ogr_fid USING SRID=3857" + CLUSTER + MAXDISTANCE 50 + REGION "ELLIPSE" + END + CLASSGROUP "Clustered" + CLASS + EXPRESSION ( "[Cluster_FeatureCount]" != "1" ) + GROUP "Clustered" + STYLE + SYMBOL "circle" + SIZE 6 + COLOR "#ffd966" + END + LABEL + TEXT "[Cluster_FeatureCount]" + END + END + END +END diff --git a/msautotest/mssql/create_mssql_db.bat b/msautotest/mssql/create_mssql_db.bat index cb31f0f8c8..448d9febe6 100644 --- a/msautotest/mssql/create_mssql_db.bat +++ b/msautotest/mssql/create_mssql_db.bat @@ -1,7 +1,8 @@ -set SQLPASSWORD=Password12! -set SERVER=(local)\SQL2017 - -sqlcmd -S "%SERVER%" -Q "USE [master]; CREATE DATABASE msautotest;" - -ogr2ogr -s_srs epsg:26915 -t_srs epsg:26915 -f MSSQLSpatial "MSSQL:server=%SERVER%;database=msautotest;User Id=sa;Password=%SQLPASSWORD%;" "query/data/bdry_counpy2.shp" -nln "bdry_counpy2" -ogr2ogr -s_srs epsg:3857 -t_srs epsg:3857 -f MSSQLSpatial "MSSQL:server=%SERVER%;database=msautotest;User Id=sa;Password=%SQLPASSWORD%;" "renderers/data/cities.shp" -nln "cities" +set SQLPASSWORD=Password12! +set SERVER=(local)\SQL2019 +set MSSQLSPATIAL_USE_BCP=FALSE + +sqlcmd -S "%SERVER%" -Q "USE [master]; CREATE DATABASE msautotest;" + +ogr2ogr -a_srs epsg:26915 -f MSSQLSpatial "MSSQL:server=%SERVER%;database=msautotest;UID=sa;PWD=%SQLPASSWORD%;" "query/data/bdry_counpy2.shp" -nln "bdry_counpy2" +ogr2ogr -a_srs epsg:3857 -f MSSQLSpatial "MSSQL:server=%SERVER%;database=msautotest;UID=sa;PWD=%SQLPASSWORD%;" "renderers/data/cities.shp" -nln "cities" diff --git a/msautotest/mssql/expected/cluster_mssql.png b/msautotest/mssql/expected/cluster_mssql.png new file mode 100644 index 0000000000..4a9f761280 Binary files /dev/null and b/msautotest/mssql/expected/cluster_mssql.png differ diff --git a/msautotest/mssql/expected/cluster_mssql_getmetadata.xml b/msautotest/mssql/expected/cluster_mssql_getmetadata.xml new file mode 100644 index 0000000000..14bab00ef6 --- /dev/null +++ b/msautotest/mssql/expected/cluster_mssql_getmetadata.xml @@ -0,0 +1,195 @@ + + + + cities + + + en-US + + + dataset + + + + + + + + + + + + + + + pointOfContact + + + + + + ISO 19115:2003 - Geographic information - Metadata + + + ISO 19115:2003 + + + + + geometryOnly + + + + + point + + + + + + + + + + + + http://www.epsg-registry.org + + + 6.14 + + + + + + + + + + + + + + + + en-US + + + + + + + -19121268.705604 + + + 19864091.077433 + + + -7324485.585568 + + + 17378510.082818 + + + + + + + + + + + + + + + + + + + + + + + + + pointOfContact + + + + + + + + + KB + + + + + service=WMS&version=1.3.0&request=GetMap&width=500&height=300&styles=&layers=cities&format=image/png&crs=&bbox=-7324485.585568,-19121268.705604,17378510.082818,19864091.077433 + + + WWW:DOWNLOAD-1.0-http-get-map + + + cities + + + PNG Format + + + + + + + service=WMS&version=1.3.0&request=GetMap&width=500&height=300&styles=&layers=cities&format=image/jpeg&crs=&bbox=-7324485.585568,-19121268.705604,17378510.082818,19864091.077433 + + + WWW:DOWNLOAD-1.0-http-get-map + + + cities + + + JPEG Format + + + + + + + service=WFS&version=1.1.0&request=GetFeature&typename=cities&outputformat=GML2 + + + WWW:DOWNLOAD-1.0-http--download + + + cities + + + GML2 Format + + + + + + + service=WFS&version=1.1.0&request=GetFeature&typename=cities&outputformat=GML3 + + + WWW:DOWNLOAD-1.0-http--download + + + cities + + + GML3 Format + + + + + + + + diff --git a/msautotest/mssql/expected/line.json b/msautotest/mssql/expected/line.json new file mode 100644 index 0000000000..2d5d430020 --- /dev/null +++ b/msautotest/mssql/expected/line.json @@ -0,0 +1,9 @@ +{ +"type": "FeatureCollection", +"numberMatched": 1, +"name": "line", +"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:EPSG::3857" } }, +"features": [ +{ "type": "Feature", "properties": { "fid": 1 }, "geometry": { "type": "LineString", "coordinates": [ [ 30.0, 10.0 ], [ 10.0, 30.0 ], [ 40.0, 40.0 ] ] } } +] +} diff --git a/msautotest/mssql/expected/multiline.json b/msautotest/mssql/expected/multiline.json new file mode 100644 index 0000000000..b7569969c5 --- /dev/null +++ b/msautotest/mssql/expected/multiline.json @@ -0,0 +1,9 @@ +{ +"type": "FeatureCollection", +"numberMatched": 1, +"name": "multiline", +"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:EPSG::3857" } }, +"features": [ +{ "type": "Feature", "properties": { "fid": 1 }, "geometry": { "type": "MultiLineString", "coordinates": [ [ [ 10.0, 10.0 ], [ 20.0, 20.0 ], [ 10.0, 40.0 ] ], [ [ 40.0, 40.0 ], [ 30.0, 30.0 ], [ 40.0, 20.0 ], [ 30.0, 10.0 ] ] ] } } +] +} diff --git a/msautotest/mssql/expected/multipoint.json b/msautotest/mssql/expected/multipoint.json new file mode 100644 index 0000000000..2759b668f9 --- /dev/null +++ b/msautotest/mssql/expected/multipoint.json @@ -0,0 +1,9 @@ +{ +"type": "FeatureCollection", +"numberMatched": 1, +"name": "multipoint", +"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:EPSG::3857" } }, +"features": [ +{ "type": "Feature", "properties": { "fid": 1 }, "geometry": { "type": "MultiPoint", "coordinates": [ [ 10.0, 40.0 ], [ 40.0, 30.0 ], [ 20.0, 20.0 ], [ 30.0, 10.0 ] ] } } +] +} diff --git a/msautotest/mssql/expected/multipolygon.json b/msautotest/mssql/expected/multipolygon.json new file mode 100644 index 0000000000..5154692b24 --- /dev/null +++ b/msautotest/mssql/expected/multipolygon.json @@ -0,0 +1,9 @@ +{ +"type": "FeatureCollection", +"numberMatched": 1, +"name": "multipolygon", +"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:EPSG::3857" } }, +"features": [ +{ "type": "Feature", "properties": { "fid": 1 }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ 30.0, 20.0 ], [ 45.0, 40.0 ], [ 10.0, 40.0 ], [ 30.0, 20.0 ] ] ], [ [ [ 15.0, 5.0 ], [ 40.0, 10.0 ], [ 10.0, 20.0 ], [ 5.0, 10.0 ], [ 15.0, 5.0 ] ] ] ] } } +] +} diff --git a/msautotest/mssql/expected/multipolygon_with_hole.json b/msautotest/mssql/expected/multipolygon_with_hole.json new file mode 100644 index 0000000000..9fd1a4ff69 --- /dev/null +++ b/msautotest/mssql/expected/multipolygon_with_hole.json @@ -0,0 +1,9 @@ +{ +"type": "FeatureCollection", +"numberMatched": 1, +"name": "multipolygon_with_hole", +"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:EPSG::3857" } }, +"features": [ +{ "type": "Feature", "properties": { "fid": 1 }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ 40.0, 40.0 ], [ 20.0, 45.0 ], [ 45.0, 30.0 ], [ 40.0, 40.0 ] ] ], [ [ [ 20.0, 35.0 ], [ 10.0, 30.0 ], [ 10.0, 10.0 ], [ 30.0, 5.0 ], [ 45.0, 20.0 ], [ 20.0, 35.0 ] ], [ [ 30.0, 20.0 ], [ 20.0, 15.0 ], [ 20.0, 25.0 ], [ 30.0, 20.0 ] ] ] ] } } +] +} diff --git a/msautotest/mssql/expected/null_and_point.json b/msautotest/mssql/expected/null_and_point.json new file mode 100644 index 0000000000..11278fd9f5 --- /dev/null +++ b/msautotest/mssql/expected/null_and_point.json @@ -0,0 +1,10 @@ +{ +"type": "FeatureCollection", +"numberMatched": 2, +"name": "null_and_point", +"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:EPSG::3857" } }, +"features": [ +{ "type": "Feature", "properties": { "fid": 1 }, "geometry": null }, +{ "type": "Feature", "properties": { "fid": 2 }, "geometry": { "type": "Point", "coordinates": [ 10.0, 10.0 ] } } +] +} diff --git a/msautotest/mssql/expected/null_and_point_reprojected.json b/msautotest/mssql/expected/null_and_point_reprojected.json new file mode 100644 index 0000000000..5a5000ee1b --- /dev/null +++ b/msautotest/mssql/expected/null_and_point_reprojected.json @@ -0,0 +1,9 @@ +{ +"type": "FeatureCollection", +"numberMatched": 2, +"name": "null_and_point", +"features": [ +{ "type": "Feature", "properties": { "fid": 1 }, "geometry": null }, +{ "type": "Feature", "properties": { "fid": 2 }, "geometry": { "type": "Point", "coordinates": [ 0.000089831528412, 0.000089831528412 ] } } +] +} diff --git a/msautotest/mssql/expected/null_line.json b/msautotest/mssql/expected/null_line.json new file mode 100644 index 0000000000..22395b32f0 --- /dev/null +++ b/msautotest/mssql/expected/null_line.json @@ -0,0 +1,9 @@ +{ +"type": "FeatureCollection", +"numberMatched": 1, +"name": "null_line", +"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:EPSG::3857" } }, +"features": [ +{ "type": "Feature", "properties": { "fid": 1 }, "geometry": null } +] +} diff --git a/msautotest/mssql/expected/null_multiline.json b/msautotest/mssql/expected/null_multiline.json new file mode 100644 index 0000000000..9f2890a4d7 --- /dev/null +++ b/msautotest/mssql/expected/null_multiline.json @@ -0,0 +1,9 @@ +{ +"type": "FeatureCollection", +"numberMatched": 1, +"name": "null_multiline", +"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:EPSG::3857" } }, +"features": [ +{ "type": "Feature", "properties": { "fid": 1 }, "geometry": null } +] +} diff --git a/msautotest/mssql/expected/null_multipoint.json b/msautotest/mssql/expected/null_multipoint.json new file mode 100644 index 0000000000..8326179aa2 --- /dev/null +++ b/msautotest/mssql/expected/null_multipoint.json @@ -0,0 +1,9 @@ +{ +"type": "FeatureCollection", +"numberMatched": 1, +"name": "null_multipoint", +"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:EPSG::3857" } }, +"features": [ +{ "type": "Feature", "properties": { "fid": 1 }, "geometry": null } +] +} diff --git a/msautotest/mssql/expected/null_multipolygon.json b/msautotest/mssql/expected/null_multipolygon.json new file mode 100644 index 0000000000..6392380835 --- /dev/null +++ b/msautotest/mssql/expected/null_multipolygon.json @@ -0,0 +1,9 @@ +{ +"type": "FeatureCollection", +"numberMatched": 1, +"name": "null_multipolygon", +"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:EPSG::3857" } }, +"features": [ +{ "type": "Feature", "properties": { "fid": 1 }, "geometry": null } +] +} diff --git a/msautotest/mssql/expected/null_point.json b/msautotest/mssql/expected/null_point.json new file mode 100644 index 0000000000..fbc0223a66 --- /dev/null +++ b/msautotest/mssql/expected/null_point.json @@ -0,0 +1,9 @@ +{ +"type": "FeatureCollection", +"numberMatched": 1, +"name": "null_point", +"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:EPSG::3857" } }, +"features": [ +{ "type": "Feature", "properties": { "fid": 1 }, "geometry": null } +] +} diff --git a/msautotest/mssql/expected/null_polygon.json b/msautotest/mssql/expected/null_polygon.json new file mode 100644 index 0000000000..cb58d1d912 --- /dev/null +++ b/msautotest/mssql/expected/null_polygon.json @@ -0,0 +1,9 @@ +{ +"type": "FeatureCollection", +"numberMatched": 1, +"name": "null_polygon", +"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:EPSG::3857" } }, +"features": [ +{ "type": "Feature", "properties": { "fid": 1 }, "geometry": null } +] +} diff --git a/msautotest/mssql/expected/ogcapi_mssql_items.json b/msautotest/mssql/expected/ogcapi_mssql_items.json new file mode 100644 index 0000000000..faad43c013 --- /dev/null +++ b/msautotest/mssql/expected/ogcapi_mssql_items.json @@ -0,0 +1 @@ +{"features":[{"geometry":{"coordinates":[103.672245,30.625609],"type":"Point"},"id":"1","properties":{"name":"崇州市","name_ar":"","name_hi":"","ogr_fid":1},"type":"Feature"},{"geometry":{"coordinates":[104.73443,31.777714],"type":"Point"},"id":"2","properties":{"name":"江油市","name_ar":"","name_hi":"","ogr_fid":2},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/cities/items?f=json&limit=2&offset=0","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/cities/items?f=html&limit=2&offset=0","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/cities/items?f=json&limit=2&offset=2","rel":"next","title":"next page","type":"application/geo+json"}],"numberMatched":6994,"numberReturned":2,"type":"FeatureCollection"} diff --git a/msautotest/mssql/expected/ogcapi_mssql_items_projected.json b/msautotest/mssql/expected/ogcapi_mssql_items_projected.json new file mode 100644 index 0000000000..e54280d961 --- /dev/null +++ b/msautotest/mssql/expected/ogcapi_mssql_items_projected.json @@ -0,0 +1 @@ +{"features":[{"geometry":{"coordinates":[11540741.500532,3584222.176283],"type":"Point"},"id":"1","properties":{"name":"崇州市","name_ar":"","name_hi":"","ogr_fid":1},"type":"Feature"},{"geometry":{"coordinates":[11658983.416124,3734167.308028],"type":"Point"},"id":"2","properties":{"name":"江油市","name_ar":"","name_hi":"","ogr_fid":2},"type":"Feature"}],"links":[{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/cities/items?f=json&limit=2&offset=0&crs=http://www.opengis.net/def/crs/EPSG/0/3857","rel":"self","title":"Items for this collection as GeoJSON","type":"application/geo+json"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/cities/items?f=html&limit=2&offset=0&crs=http://www.opengis.net/def/crs/EPSG/0/3857","rel":"alternate","title":"Items for this collection as HTML","type":"text/html"},{"href":"http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi/collections/cities/items?f=json&limit=2&offset=2&crs=http://www.opengis.net/def/crs/EPSG/0/3857","rel":"next","title":"next page","type":"application/geo+json"}],"numberMatched":6994,"numberReturned":2,"type":"FeatureCollection"} diff --git a/msautotest/mssql/expected/point.json b/msautotest/mssql/expected/point.json new file mode 100644 index 0000000000..d527123ba1 --- /dev/null +++ b/msautotest/mssql/expected/point.json @@ -0,0 +1,9 @@ +{ +"type": "FeatureCollection", +"numberMatched": 1, +"name": "point", +"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:EPSG::3857" } }, +"features": [ +{ "type": "Feature", "properties": { "fid": 1 }, "geometry": { "type": "Point", "coordinates": [ 30.0, 10.0 ] } } +] +} diff --git a/msautotest/mssql/expected/polygon.json b/msautotest/mssql/expected/polygon.json new file mode 100644 index 0000000000..4198b54957 --- /dev/null +++ b/msautotest/mssql/expected/polygon.json @@ -0,0 +1,9 @@ +{ +"type": "FeatureCollection", +"numberMatched": 1, +"name": "polygon", +"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:EPSG::3857" } }, +"features": [ +{ "type": "Feature", "properties": { "fid": 1 }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 30.0, 10.0 ], [ 40.0, 40.0 ], [ 20.0, 40.0 ], [ 10.0, 20.0 ], [ 30.0, 10.0 ] ] ] } } +] +} diff --git a/msautotest/mssql/expected/polygon_with_hole.json b/msautotest/mssql/expected/polygon_with_hole.json new file mode 100644 index 0000000000..c44bc5d1fd --- /dev/null +++ b/msautotest/mssql/expected/polygon_with_hole.json @@ -0,0 +1,9 @@ +{ +"type": "FeatureCollection", +"numberMatched": 1, +"name": "polygon_with_hole", +"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:EPSG::3857" } }, +"features": [ +{ "type": "Feature", "properties": { "fid": 1 }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 35.0, 10.0 ], [ 45.0, 45.0 ], [ 15.0, 40.0 ], [ 10.0, 20.0 ], [ 35.0, 10.0 ] ], [ [ 20.0, 30.0 ], [ 35.0, 35.0 ], [ 30.0, 20.0 ], [ 20.0, 30.0 ] ] ] } } +] +} diff --git a/msautotest/mssql/expected/wfs_mssql_describefeature.xml b/msautotest/mssql/expected/wfs_mssql_describefeature.xml new file mode 100644 index 0000000000..7eaeda33f7 --- /dev/null +++ b/msautotest/mssql/expected/wfs_mssql_describefeature.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/msautotest/mssql/expected/wfs_mssql_describefeature_custom_type.xml b/msautotest/mssql/expected/wfs_mssql_describefeature_custom_type.xml new file mode 100644 index 0000000000..b8c6d695ca --- /dev/null +++ b/msautotest/mssql/expected/wfs_mssql_describefeature_custom_type.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/msautotest/mssql/expected/wfs_mssql_maxfeatures.json b/msautotest/mssql/expected/wfs_mssql_maxfeatures.json index 9896a3c94c..616fa04be1 100644 --- a/msautotest/mssql/expected/wfs_mssql_maxfeatures.json +++ b/msautotest/mssql/expected/wfs_mssql_maxfeatures.json @@ -2,6 +2,7 @@ "type": "FeatureCollection", "numberMatched": 6994, "name": "cities", +"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:EPSG::3857" } }, "features": [ { "type": "Feature", "properties": { "ogr_fid": 1, "name": "崇州市", "name_ar": "", "name_hi": "" }, "geometry": { "type": "Point", "coordinates": [ 11540741.500531593337655, 3584222.176282715518028 ] } }, { "type": "Feature", "properties": { "ogr_fid": 2, "name": "江油市", "name_ar": "", "name_hi": "" }, "geometry": { "type": "Point", "coordinates": [ 11658983.416123732924461, 3734167.308027575723827 ] } }, diff --git a/msautotest/mssql/expected/wfs_mssql_maxfeatures_order.json b/msautotest/mssql/expected/wfs_mssql_maxfeatures_order.json index 3bfc538d94..ed48326263 100644 --- a/msautotest/mssql/expected/wfs_mssql_maxfeatures_order.json +++ b/msautotest/mssql/expected/wfs_mssql_maxfeatures_order.json @@ -2,6 +2,7 @@ "type": "FeatureCollection", "numberMatched": 6994, "name": "cities_with_order", +"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:EPSG::3857" } }, "features": [ { "type": "Feature", "properties": { "ogr_fid": 6994, "name": "Heroica Nogales", "name_ar": "", "name_hi": "" }, "geometry": { "type": "Point", "coordinates": [ -12351166.251028399914503, 3674840.854894261341542 ] } }, { "type": "Feature", "properties": { "ogr_fid": 6993, "name": "Puerto Peñasco", "name_ar": "", "name_hi": "" }, "geometry": { "type": "Point", "coordinates": [ -12639224.034942869096994, 3673296.088174171745777 ] } }, diff --git a/msautotest/mssql/expected/wfs_mssql_maxfeatures_qs.json b/msautotest/mssql/expected/wfs_mssql_maxfeatures_qs.json index b5795d0951..ab59c4f17f 100644 --- a/msautotest/mssql/expected/wfs_mssql_maxfeatures_qs.json +++ b/msautotest/mssql/expected/wfs_mssql_maxfeatures_qs.json @@ -2,6 +2,7 @@ "type": "FeatureCollection", "numberMatched": 6994, "name": "cities", +"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:EPSG::3857" } }, "features": [ { "type": "Feature", "properties": { "ogr_fid": 1, "name": "崇州市", "name_ar": "", "name_hi": "" }, "geometry": { "type": "Point", "coordinates": [ 11540741.500531593337655, 3584222.176282715518028 ] } }, { "type": "Feature", "properties": { "ogr_fid": 2, "name": "江油市", "name_ar": "", "name_hi": "" }, "geometry": { "type": "Point", "coordinates": [ 11658983.416123732924461, 3734167.308027575723827 ] } } diff --git a/msautotest/mssql/filters_mssql.map b/msautotest/mssql/filters_mssql.map index 7a731ac591..3e31fce640 100644 --- a/msautotest/mssql/filters_mssql.map +++ b/msautotest/mssql/filters_mssql.map @@ -3,15 +3,15 @@ # # REQUIRES: OUTPUT=PNG # -# RUN_PARMS: filters_mssql_test001.png [SHP2IMG] -m [MAPFILE] -l filters_mssql_test001 -o [RESULT] -# SKIP filters_mssql_test002.png [SHP2IMG] -m [MAPFILE] -l filters_mssql_test002 -o [RESULT] -# SKIP: filters_mssql_test003.png [SHP2IMG] -m [MAPFILE] -l filters_mssql_test003 -o [RESULT] -# SKIP: filters_mssql_test004.png [SHP2IMG] -m [MAPFILE] -l filters_mssql_test004 -o [RESULT] -# RUN_PARMS: filters_mssql_test005.png [SHP2IMG] -m [MAPFILE] -l filters_mssql_test005 -o [RESULT] -# RUN_PARMS: filters_mssql_test006.png [SHP2IMG] -m [MAPFILE] -l filters_mssql_test006 -o [RESULT] -# SKIP: filters_mssql_test007.png [SHP2IMG] -m [MAPFILE] -l filters_mssql_test007 -o [RESULT] -# SKIP: filters_mssql_test008.png [SHP2IMG] -m [MAPFILE] -l filters_mssql_test008 -o [RESULT] -# SKIP: filters_mssql_test009.png [SHP2IMG] -m [MAPFILE] -l filters_mssql_test009 -o [RESULT] +# RUN_PARMS: filters_mssql_test001.png [MAP2IMG] -m [MAPFILE] -l filters_mssql_test001 -o [RESULT] +# SKIP filters_mssql_test002.png [MAP2IMG] -m [MAPFILE] -l filters_mssql_test002 -o [RESULT] +# SKIP: filters_mssql_test003.png [MAP2IMG] -m [MAPFILE] -l filters_mssql_test003 -o [RESULT] +# SKIP: filters_mssql_test004.png [MAP2IMG] -m [MAPFILE] -l filters_mssql_test004 -o [RESULT] +# RUN_PARMS: filters_mssql_test005.png [MAP2IMG] -m [MAPFILE] -l filters_mssql_test005 -o [RESULT] +# RUN_PARMS: filters_mssql_test006.png [MAP2IMG] -m [MAPFILE] -l filters_mssql_test006 -o [RESULT] +# SKIP: filters_mssql_test007.png [MAP2IMG] -m [MAPFILE] -l filters_mssql_test007 -o [RESULT] +# SKIP: filters_mssql_test008.png [MAP2IMG] -m [MAPFILE] -l filters_mssql_test008 -o [RESULT] +# SKIP: filters_mssql_test009.png [MAP2IMG] -m [MAPFILE] -l filters_mssql_test009 -o [RESULT] # MAP NAME 'filters_mssql' @@ -100,6 +100,6 @@ MAP TYPE LINE DATA '../query/data/bdry_counpy2.shp' STATUS DEFAULT - CLASS COLOR 231 231 231 END + CLASS STYLE COLOR 231 231 231 END END END END diff --git a/msautotest/mssql/include/bdry_counpy2_mssql.map b/msautotest/mssql/include/bdry_counpy2_mssql.map index 236e7c52c2..e99242efd4 100644 --- a/msautotest/mssql/include/bdry_counpy2_mssql.map +++ b/msautotest/mssql/include/bdry_counpy2_mssql.map @@ -1,13 +1,11 @@ - CONNECTIONTYPE PLUGIN - PLUGIN "C:\projects\mapserver\build\Release\msplugin_mssql2008.dll" - CONNECTION "SERVER=(local)\SQL2017;DATABASE=msautotest;uid=sa;pwd=Password12!;" - DATA "ogr_geometry from (select * from bdry_counpy2) as foo USING UNIQUE ogr_fid USING SRID=26915" - STATUS OFF - TYPE POLYGON - CLASS - STYLE - COLOR 255 100 100 - OUTLINECOLOR 181 181 181 - END - END - TEMPLATE 'void' + INCLUDE 'include/mssql_connection.map' + DATA "ogr_geometry from (select * from bdry_counpy2) as foo USING UNIQUE ogr_fid USING SRID=26915" + STATUS OFF + TYPE POLYGON + CLASS + STYLE + COLOR 255 100 100 + OUTLINECOLOR 181 181 181 + END + END + TEMPLATE 'void' diff --git a/msautotest/mssql/include/cities_mssql.map b/msautotest/mssql/include/cities_mssql.map deleted file mode 100644 index 9f53a270b3..0000000000 --- a/msautotest/mssql/include/cities_mssql.map +++ /dev/null @@ -1,6 +0,0 @@ - CONNECTIONTYPE PLUGIN - PLUGIN "C:\projects\mapserver\build\Release\msplugin_mssql2008.dll" - CONNECTION "SERVER=(local)\SQL2017;DATABASE=msautotest;uid=sa;pwd=Password12!;" - STATUS OFF - TYPE POINT - diff --git a/msautotest/mssql/include/mssql_connection.map b/msautotest/mssql/include/mssql_connection.map new file mode 100644 index 0000000000..022899d047 --- /dev/null +++ b/msautotest/mssql/include/mssql_connection.map @@ -0,0 +1,4 @@ + CONNECTIONTYPE PLUGIN + PLUGIN "mssql" + CONNECTION "SERVER=(local)\SQL2019;DATABASE=msautotest;uid=sa;pwd=Password12!;" + STATUS OFF diff --git a/msautotest/mssql/include/wfs_ogr_export_metadata.map b/msautotest/mssql/include/wfs_ogr_export_metadata.map new file mode 100644 index 0000000000..10a0c1aea6 --- /dev/null +++ b/msautotest/mssql/include/wfs_ogr_export_metadata.map @@ -0,0 +1,6 @@ +METADATA + "gml_include_items" "all" + "gml_types" "auto" + "ows_geomtype" "Geometry" + "wfs_use_default_extent_for_getfeature" "false" +END \ No newline at end of file diff --git a/msautotest/mssql/ogcapi_mssql.map b/msautotest/mssql/ogcapi_mssql.map new file mode 100644 index 0000000000..d9d76cde9e --- /dev/null +++ b/msautotest/mssql/ogcapi_mssql.map @@ -0,0 +1,46 @@ +# +# Test OGC API Features with the MSSQL driver plugin and caching +# + +# RUN_PARMS: ogcapi_mssql_items.json [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/cities/items" "QUERY_STRING=f=json&limit=2" > [RESULT_DEMIME] +# RUN_PARMS: ogcapi_mssql_items_projected.json [MAPSERV] "PATH_INFO=/[MAPFILE]/ogcapi/collections/cities/items" "QUERY_STRING=f=json&limit=2&crs=http://www.opengis.net/def/crs/EPSG/0/3857" > [RESULT_DEMIME] + +MAP + NAME 'ogcapi_mssql' + EXTENT -20026376.39 -20048966.10 20026376.39 20048966.10 + UNITS METERS + + SIZE 300 300 + + WEB + METADATA + "oga_title" "ogcapi_mssql" + "oga_onlineresource" "http://localhost/cgi-bin/mapserv/OGCAPI_TEST/ogcapi" + "oga_enable_request" "OGCAPI" + "oga_srs" "EPSG:3857 EPSG:4326" + "oga_features_cache_count" "1" # cache one feature + END + END + + PROJECTION + "init=epsg:3857" + END + + LAYER + NAME 'cities' + EXTENT -20026376.39 -20048966.10 20026376.39 20048966.10 + PROJECTION # required + "init=epsg:3857" + END + INCLUDE 'include/mssql_connection.map' + TYPE POINT + TEMPLATE VOID + DATA "ogr_geometry from (select * from cities) as foo USING UNIQUE ogr_fid USING SRID=3857" + METADATA + "oga_featureid" "ogr_fid" # required + "gml_include_items" "all" + "gml_types" "auto" + END + END + +END diff --git a/msautotest/mssql/run_test.py b/msautotest/mssql/run_test.py index 7d572d0cb6..dd4172c8aa 100644 --- a/msautotest/mssql/run_test.py +++ b/msautotest/mssql/run_test.py @@ -8,17 +8,17 @@ # ############################################################################### # Copyright (c) 2002, Frank Warmerdam -# +# # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: -# +# # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. -# +# # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL @@ -29,14 +29,19 @@ ############################################################################### import os -import pytest import sys -sys.path.append( '../pymod' ) +import pytest + +sys.path.append("../pymod") import mstestlib -@pytest.mark.parametrize('map,out_file,command', mstestlib.get_pytests(os.path.dirname(os.path.abspath(__file__)))) + +@pytest.mark.parametrize( + "map,out_file,command", + mstestlib.get_pytests(os.path.dirname(os.path.abspath(__file__))), +) def test(map, out_file, command, extra_args): mstestlib.run_pytest(map, out_file, command, extra_args) @@ -44,5 +49,5 @@ def test(map, out_file, command, extra_args): ############################################################################### # main() -if __name__ == '__main__': +if __name__ == "__main__": sys.exit(mstestlib.pytest_main()) diff --git a/msautotest/mssql/wfs_mssql.map b/msautotest/mssql/wfs_mssql.map index 6dc58e96bf..0aa97ca267 100644 --- a/msautotest/mssql/wfs_mssql.map +++ b/msautotest/mssql/wfs_mssql.map @@ -6,6 +6,8 @@ # RUN_PARMS: wfs_mssql_maxfeatures.json [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAME=cities&OUTPUTFORMAT=geojson" > [RESULT_DEMIME] # RUN_PARMS: wfs_mssql_maxfeatures_order.json [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAME=cities_with_order&OUTPUTFORMAT=geojson" > [RESULT_DEMIME] # RUN_PARMS: wfs_mssql_maxfeatures_qs.json [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAME=cities&OUTPUTFORMAT=geojson&MAXFEATURES=2" > [RESULT_DEMIME] +# RUN_PARMS: wfs_mssql_describefeature.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&REQUEST=DescribeFeatureType&TYPENAME=cities" > [RESULT_DEMIME_DEVERSION] +# RUN_PARMS: wfs_mssql_describefeature_custom_type.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&REQUEST=DescribeFeatureType&TYPENAME=cities_custom_gml_type" > [RESULT_DEMIME_DEVERSION] MAP NAME 'wfs_mssql' @@ -39,7 +41,8 @@ MAP LAYER NAME 'cities' EXTENT -20026376.39 -20048966.10 20026376.39 20048966.10 - INCLUDE 'include/cities_mssql.map' + INCLUDE 'include/mssql_connection.map' + TYPE POINT DATA "ogr_geometry from (select * from cities) as foo USING UNIQUE ogr_fid USING SRID=3857" METADATA "gml_include_items" "all" @@ -51,7 +54,8 @@ MAP LAYER NAME 'cities_with_order' EXTENT -20026376.39 -20048966.10 20026376.39 20048966.10 - INCLUDE 'include/cities_mssql.map' + INCLUDE 'include/mssql_connection.map' + TYPE POINT DATA "ogr_geometry from (select * from cities) as foo USING UNIQUE ogr_fid USING SRID=3857 ORDER BY ogr_fid DESC" METADATA "gml_include_items" "all" @@ -59,5 +63,17 @@ MAP END END + LAYER + NAME 'cities_custom_gml_type' + EXTENT -20026376.39 -20048966.10 20026376.39 20048966.10 + INCLUDE 'include/mssql_connection.map' + TYPE POINT + DATA "ogr_geometry from (select * from cities) as foo USING UNIQUE ogr_fid USING SRID=3857" + METADATA + "gml_include_items" "all" + "gml_types" "auto" + "gml_ogr_fid_type" "long" # override the default gml type + END + END END diff --git a/msautotest/mssql/wfs_ogr_export.map b/msautotest/mssql/wfs_ogr_export.map new file mode 100644 index 0000000000..6cf4e7c0ed --- /dev/null +++ b/msautotest/mssql/wfs_ogr_export.map @@ -0,0 +1,182 @@ +# +# Test WFS GetFeature with the MSSQL driver plugin and exporting various geometry types to GeoJSON +# +# REQUIRES: INPUT=OGR SUPPORTS=WFS +# +# RUN_PARMS: null_point.json [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAMES=null_point&OUTPUTFORMAT=geojson" > [RESULT_DEMIME] +# RUN_PARMS: null_line.json [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAMES=null_line&OUTPUTFORMAT=geojson" > [RESULT_DEMIME] +# RUN_PARMS: null_polygon.json [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAMES=null_polygon&OUTPUTFORMAT=geojson" > [RESULT_DEMIME] +# RUN_PARMS: null_multipoint.json [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAMES=null_multipoint&OUTPUTFORMAT=geojson" > [RESULT_DEMIME] +# RUN_PARMS: null_multiline.json [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAMES=null_multiline&OUTPUTFORMAT=geojson" > [RESULT_DEMIME] +# RUN_PARMS: null_multipolygon.json [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAMES=null_multipolygon&OUTPUTFORMAT=geojson" > [RESULT_DEMIME] + +# RUN_PARMS: null_and_point.json [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAMES=null_and_point&OUTPUTFORMAT=geojson" > [RESULT_DEMIME] +# RUN_PARMS: null_and_point_reprojected.json [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAMES=null_and_point&OUTPUTFORMAT=geojson&srsName=EPSG:4326" > [RESULT_DEMIME] + +# RUN_PARMS: point.json [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAMES=point&OUTPUTFORMAT=geojson" > [RESULT_DEMIME] +# RUN_PARMS: line.json [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAMES=line&OUTPUTFORMAT=geojson" > [RESULT_DEMIME] +# RUN_PARMS: polygon.json [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAMES=polygon&OUTPUTFORMAT=geojson" > [RESULT_DEMIME] +# RUN_PARMS: polygon_with_hole.json [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAMES=polygon_with_hole&OUTPUTFORMAT=geojson" > [RESULT_DEMIME] + +# RUN_PARMS: multipoint.json [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAMES=multipoint&OUTPUTFORMAT=geojson" > [RESULT_DEMIME] +# RUN_PARMS: multiline.json [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAMES=multiline&OUTPUTFORMAT=geojson" > [RESULT_DEMIME] +# RUN_PARMS: multipolygon.json [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAMES=multipolygon&OUTPUTFORMAT=geojson" > [RESULT_DEMIME] +# RUN_PARMS: multipolygon_with_hole.json [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAMES=multipolygon_with_hole&OUTPUTFORMAT=geojson" > [RESULT_DEMIME] + +MAP + NAME 'wfs_export_mssql' + UNITS METERS + EXTENT 0 0 100 100 + SIZE 100 100 + PROJECTION + "init=epsg:3857" + END + + WEB + METADATA + "wfs_title" "Test wfs export" + "wfs_onlineresource" "http://localhost/path/to/wfs_simple?" + "wfs_srs" "EPSG:3857 EPSG:4326" + "wfs_getfeature_formatlist" "gml,geojson" + "ows_enable_request" "*" + END + END + + OUTPUTFORMAT + NAME "geojson" + DRIVER "OGR/GEOJSON" + MIMETYPE "application/json; subtype=geojson; charset=utf-8" + FORMATOPTION "FORM=SIMPLE" + FORMATOPTION "STORAGE=memory" + FORMATOPTION "LCO:NATIVE_MEDIA_TYPE=application/vnd.geo+json" + END + + # test all null cases + + LAYER + NAME 'null_point' + TYPE POINT + INCLUDE 'include/mssql_connection.map' + INCLUDE 'include/wfs_ogr_export_metadata.map' + DATA "geom from (SELECT 1 fid, geometry::STGeomFromText('POINT EMPTY', 3857) geom) as foo USING UNIQUE fid USING SRID=3857" + END + + LAYER + NAME 'null_line' + TYPE LINE + INCLUDE 'include/mssql_connection.map' + INCLUDE 'include/wfs_ogr_export_metadata.map' + DATA "geom from (SELECT 1 fid, geometry::STGeomFromText('LINESTRING EMPTY', 3857) geom) as foo USING UNIQUE fid USING SRID=3857" + END + + LAYER + NAME 'null_polygon' + TYPE POLYGON + INCLUDE 'include/mssql_connection.map' + INCLUDE 'include/wfs_ogr_export_metadata.map' + DATA "geom from (SELECT 1 fid, geometry::STGeomFromText('POLYGON EMPTY', 3857) geom) as foo USING UNIQUE fid USING SRID=3857" + END + + LAYER + NAME 'null_multipoint' + TYPE POINT + INCLUDE 'include/mssql_connection.map' + INCLUDE 'include/wfs_ogr_export_metadata.map' + DATA "geom from (SELECT 1 fid, geometry::STGeomFromText('MULTIPOINT EMPTY', 3857) geom) as foo USING UNIQUE fid USING SRID=3857" + END + + LAYER + NAME 'null_multiline' + TYPE LINE + INCLUDE 'include/mssql_connection.map' + INCLUDE 'include/wfs_ogr_export_metadata.map' + DATA "geom from (SELECT 1 fid, geometry::STGeomFromText('MULTILINESTRING EMPTY', 3857) geom) as foo USING UNIQUE fid USING SRID=3857" + END + + LAYER + NAME 'null_multipolygon' + TYPE POLYGON + INCLUDE 'include/mssql_connection.map' + INCLUDE 'include/wfs_ogr_export_metadata.map' + DATA "geom from (SELECT 1 fid, geometry::STGeomFromText('MULTIPOLYGON EMPTY', 3857) geom) as foo USING UNIQUE fid USING SRID=3857" + END + + # examples of WKT taken from https://en.wikipedia.org/wiki/Well-known_text_representation_of_geometry + + LAYER + NAME 'point' + TYPE POINT + INCLUDE 'include/mssql_connection.map' + INCLUDE 'include/wfs_ogr_export_metadata.map' + DATA "geom from (SELECT 1 fid, geometry::STGeomFromText('POINT (30 10)', 3857) geom) as foo USING UNIQUE fid USING SRID=3857" + END + + LAYER + NAME 'line' + TYPE LINE + INCLUDE 'include/mssql_connection.map' + INCLUDE 'include/wfs_ogr_export_metadata.map' + DATA "geom from (SELECT 1 fid, geometry::STGeomFromText('LINESTRING (30 10, 10 30, 40 40)', 3857) geom) as foo USING UNIQUE fid USING SRID=3857" + END + + LAYER + NAME 'polygon' + TYPE POLYGON + INCLUDE 'include/mssql_connection.map' + INCLUDE 'include/wfs_ogr_export_metadata.map' + DATA "geom from (SELECT 1 fid, geometry::STGeomFromText('POLYGON ((30 10, 40 40, 20 40, 10 20, 30 10))', 3857) geom) as foo USING UNIQUE fid USING SRID=3857" + END + + LAYER + NAME 'polygon_with_hole' + TYPE POLYGON + INCLUDE 'include/mssql_connection.map' + INCLUDE 'include/wfs_ogr_export_metadata.map' + DATA "geom from (SELECT 1 fid, geometry::STGeomFromText('POLYGON ((35 10, 45 45, 15 40, 10 20, 35 10), (20 30, 35 35, 30 20, 20 30))', 3857) geom) as foo USING UNIQUE fid USING SRID=3857" + END + + LAYER + NAME 'multipoint' + TYPE POINT + INCLUDE 'include/mssql_connection.map' + INCLUDE 'include/wfs_ogr_export_metadata.map' + DATA "geom from (SELECT 1 fid, geometry::STGeomFromText('MULTIPOINT ((10 40), (40 30), (20 20), (30 10))', 3857) geom) as foo USING UNIQUE fid USING SRID=3857" + END + + LAYER + NAME 'multiline' + TYPE LINE + INCLUDE 'include/mssql_connection.map' + INCLUDE 'include/wfs_ogr_export_metadata.map' + DATA "geom from (SELECT 1 fid, geometry::STGeomFromText('MULTILINESTRING ((10 10, 20 20, 10 40), (40 40, 30 30, 40 20, 30 10))', 3857) geom) as foo USING UNIQUE fid USING SRID=3857" + END + + LAYER + NAME 'multipolygon' + TYPE POLYGON + INCLUDE 'include/mssql_connection.map' + INCLUDE 'include/wfs_ogr_export_metadata.map' + DATA "geom from (SELECT 1 fid, geometry::STGeomFromText('MULTIPOLYGON (((30 20, 45 40, 10 40, 30 20)), ((15 5, 40 10, 10 20, 5 10, 15 5)))', 3857) geom) as foo USING UNIQUE fid USING SRID=3857" + END + + LAYER + NAME 'multipolygon_with_hole' + TYPE POLYGON + INCLUDE 'include/mssql_connection.map' + INCLUDE 'include/wfs_ogr_export_metadata.map' + DATA "geom from (SELECT 1 fid, geometry::STGeomFromText('MULTIPOLYGON (((40 40, 20 45, 45 30, 40 40)), + ((20 35, 10 30, 10 10, 30 5, 45 20, 20 35), (30 20, 20 15, 20 25, 30 20)))', 3857) geom) as foo USING UNIQUE fid USING SRID=3857" + END + + LAYER + NAME 'null_and_point' + TYPE POINT + PROJECTION + "init=epsg:3857" + END + INCLUDE 'include/mssql_connection.map' + INCLUDE 'include/wfs_ogr_export_metadata.map' + DATA "geom from (SELECT 1 fid, geometry::STGeomFromText('POINT EMPTY', 3857) geom UNION ALL SELECT 2 fid, geometry::STGeomFromText('POINT (10 10)', 3857) geom) as foo USING UNIQUE fid USING SRID=3857" + END + +END diff --git a/msautotest/php/README b/msautotest/php/README deleted file mode 100644 index c1b73c78b8..0000000000 --- a/msautotest/php/README +++ /dev/null @@ -1,3 +0,0 @@ -To run these test you need PHPUNIT. You can find how to install it at http://www.phpunit.de/manual/3.7/en/installation.html. - -To run the test simply run 'phpunit --process-isolation .' diff --git a/msautotest/php/README.md b/msautotest/php/README.md new file mode 100644 index 0000000000..24fb6f535f --- /dev/null +++ b/msautotest/php/README.md @@ -0,0 +1,24 @@ +# PHPNG MapScript Unit Tests + +To run these tests you need PHPUnit (and PHP's Xdebug extension) installed. +You can find how to install PHPUnit at https://docs.phpunit.de . +The official PHPUnit site is: https://phpunit.de + +# Running the tests + +To run the tests simply run `phpunit .` from inside the `/msautotest/php/` +folder. + +You can run a single test such as: `phpunit classObjTest.php` + +# Configuring the test environment + +This folder includes a `phpunit.xml` configuration file for these tests. More +info about these settings: https://docs.phpunit.de/en/10.1/configuration.html + +# PHPNG (SWIG) MapScript API documentation + +Follow: https://mapserver.org/mapscript/mapscript.html + + + diff --git a/msautotest/php/classObjTest.php b/msautotest/php/classObjTest.php index 3c6fe58075..dc7a0aa1b4 100644 --- a/msautotest/php/classObjTest.php +++ b/msautotest/php/classObjTest.php @@ -1,10 +1,10 @@ assertInstanceOf('labelLeaderObj', $this->class->leader); } + + public function testcreateLegendIcon() + { + $map_file = 'maps/labels-leader.map'; + $map = new mapObj($map_file); + $layer = $map->getLayer(0); + $this->assertInstanceOf('imageObj', $layer->getClass(0)->createLegendIcon( $map, $layer, 50, 50 )); + } + + public function testClone() + { + $this->assertInstanceOf('classObj', $newClass = $this->class->cloneClass()); + } + + # destroy variables, if not can lead to segmentation fault + public function tearDown(): void { + unset($this->class, $map_file, $map, $layer, $classtmp, $style, $newClass); + } + } ?> diff --git a/msautotest/php/colorObjTest.php b/msautotest/php/colorObjTest.php index 0a774787c0..eb02e69abe 100644 --- a/msautotest/php/colorObjTest.php +++ b/msautotest/php/colorObjTest.php @@ -1,62 +1,69 @@ color = $map->getLayer(0)->getClass(0)->getLabel(0)->color; + $this->map = new mapObj($map_file); + $this->color = $this->map->getLayer(0)->getClass(0)->getLabel(0)->color; } public function test__getsetAlpha() { $this->assertEquals(50, $this->color->alpha=50); - $this->color->alpha=$this->originalAlpha; + $this->color->alpha=$this->originalAlpha; } public function test__toHex() { - $this->assertEquals("#00ff00", $this->color->toHex()); - $this->color->alpha=128; - $this->assertEquals("#00ff0080", $this->color->toHex()); - $this->color->alpha = $this->originalAlpha; - } + # Test fails on ubuntu 20.04 + #$this->assertEquals("#00ff00", $this->color->toHex()); + #$this->color->alpha=128; + #$this->assertEquals("#00ff0080", $this->color->toHex()); + #$this->color->alpha = $this->originalAlpha; + } + + public function test__setHex() + { + $this->color->alpha = 80; + $this->assertEquals(0, $this->color->red); + $this->assertEquals(80, $this->color->alpha); + $this->assertEquals(MS_SUCCESS, $this->color->setHex("#ff00ff")); + $this->assertEquals(255, $this->color->red); + $this->assertEquals(255, $this->color->alpha); + $this->assertEquals(MS_SUCCESS, $this->color->setHex("#ff00ff80")); + $this->assertEquals(128, $this->color->alpha); + $this->color->setHex($this->original); + } - public function test__setHex() - { - $this->color->alpha = 80; - $this->assertEquals(0, $this->color->red); - $this->assertEquals(80, $this->color->alpha); - $this->assertEquals(MS_SUCCESS, $this->color->setHex("#ff00ff")); - $this->assertEquals(255, $this->color->red); - $this->assertEquals(255, $this->color->alpha); - $this->assertEquals(MS_SUCCESS, $this->color->setHex("#ff00ff80")); - $this->assertEquals(128, $this->color->alpha); - $this->color->setHex($this->original); - } - - public function test__setRGB() - { - $this->color->alpha = 80; - $this->assertEquals(0, $this->color->red); - $this->assertEquals(80, $this->color->alpha); - $this->assertEquals(MS_SUCCESS, $this->color->setRGB(255, 0, 255)); - $this->assertEquals(255, $this->color->red); - $this->assertEquals(255, $this->color->alpha); - $this->color->setHex($this->original); - $this->assertEquals(0, $this->color->red); - $this->assertEquals(255, $this->color->alpha); - $this->assertEquals(MS_SUCCESS, $this->color->setRGB(255, 0, 255, 80)); - $this->assertEquals(255, $this->color->red); - $this->assertEquals(80, $this->color->alpha); - $this->color->setHex($this->original); - $this->color->alpha = $this->originalAlpha; - } + public function test__setRGB() + { + $this->color->alpha = 80; + $this->assertEquals(0, $this->color->red); + $this->assertEquals(80, $this->color->alpha); + $this->assertEquals(MS_SUCCESS, $this->color->setRGB(255, 0, 255)); + $this->assertEquals(255, $this->color->red); + $this->assertEquals(255, $this->color->alpha); + $this->color->setHex($this->original); + $this->assertEquals(0, $this->color->red); + $this->assertEquals(255, $this->color->alpha); + $this->assertEquals(MS_SUCCESS, $this->color->setRGB(255, 0, 255, 80)); + $this->assertEquals(255, $this->color->red); + $this->assertEquals(80, $this->color->alpha); + $this->color->setHex($this->original); + $this->color->alpha = $this->originalAlpha; + } + + # destroy variables, if not can lead to segmentation fault + public function tearDown(): void { + unset($color, $original, $originalAlpha, $map_file, $map, $this->color); + } } ?> diff --git a/msautotest/php/errorObjTest.php b/msautotest/php/errorObjTest.php deleted file mode 100644 index 1d87627090..0000000000 --- a/msautotest/php/errorObjTest.php +++ /dev/null @@ -1,27 +0,0 @@ -error = ms_GetErrorObj(); - } - - /** - * @expectedException MapScriptException - * @expectedExceptionMessage Property 'isreported' is read-only - */ - public function test__setIsReported() - { - $this->error->isreported = 5; - } - - public function test__getIsReported() - { - $this->assertEquals(0, $this->error->isreported); - } -} - -?> diff --git a/msautotest/php/expected/setprojection-3857.png b/msautotest/php/expected/setprojection-3857.png new file mode 100644 index 0000000000..629da2cddc Binary files /dev/null and b/msautotest/php/expected/setprojection-3857.png differ diff --git a/msautotest/php/expected/setprojection-3978.png b/msautotest/php/expected/setprojection-3978.png new file mode 100644 index 0000000000..6a4f8b45ab Binary files /dev/null and b/msautotest/php/expected/setprojection-3978.png differ diff --git a/msautotest/php/hashtableObjTest.php b/msautotest/php/hashtableObjTest.php index 6ff0ddf34e..f9a7356b01 100644 --- a/msautotest/php/hashtableObjTest.php +++ b/msautotest/php/hashtableObjTest.php @@ -1,29 +1,32 @@ hash = $map->web->metadata; + $this->map = new mapObj($map_file); + $this->hash = $this->map->web->metadata; } - /** - * @expectedException MapScriptException - * @expectedExceptionMessage Property 'numitems' is read-only - */ public function test__setNumItems() - { - $this->hash->numitems = 5; + { # exception not thrown with PHPNG + #$this->hash->numitems = 5; } public function test__getNumItems() { $this->assertEquals(1, $this->hash->numitems); } + + # destroy variables, if not can lead to segmentation fault + public function tearDown(): void { + unset($hash, $map_file, $map, $this->hash); + } + } ?> diff --git a/msautotest/php/labelObjTest.php b/msautotest/php/labelObjTest.php index 4c253c86bc..b390f966da 100644 --- a/msautotest/php/labelObjTest.php +++ b/msautotest/php/labelObjTest.php @@ -1,10 +1,10 @@ assertInstanceOf('labelObj', $newLabel = clone $this->label); + # label->clone() method not available in MapServer 8-dev + #public function testClone() + #{ + #$this->assertInstanceOf('labelObj', $newLabel = $this->label->clone()); + #} + + # destroy variables, if not can lead to segmentation fault + public function tearDown(): void { + unset($label, $map_file, $map, $this->label); } } diff --git a/msautotest/php/labelleaderObjTest.php b/msautotest/php/labelleaderObjTest.php deleted file mode 100644 index 17be2a962b..0000000000 --- a/msautotest/php/labelleaderObjTest.php +++ /dev/null @@ -1,49 +0,0 @@ -getLayer(0); - $class = $layer->getClass(0); - $label = $class->getLabel(0); - $this->labelleader = $class->leader; - } - - public function test__getmaxdistance() - { - $this->assertEquals(30, $this->labelleader->maxdistance); - } - - /** - * @expectedException MapScriptException - * @expectedExceptionMessage Property 'maxdistance' is read-only - */ - public function test__setmaxdistance() - { - $this->labelleader->maxdistance = 35; - } - - public function test__getgridstep() - { - $this->assertEquals(5, $this->labelleader->gridstep); - } - - /** - * @expectedException MapScriptException - * @expectedExceptionMessage Property 'gridstep' is read-only - */ - public function test__setgridstep() - { - $this->labelleader->gridstep = 35; - } - - - -} - -?> diff --git a/msautotest/php/labelleaderObjTest.php.bad b/msautotest/php/labelleaderObjTest.php.bad new file mode 100644 index 0000000000..d1b32aa530 --- /dev/null +++ b/msautotest/php/labelleaderObjTest.php.bad @@ -0,0 +1,49 @@ +getLayer(0); + $class = $layer->getClass(0); + $label = $class->getLabel(0); + $this->labelleader = $class->leader; + } + + public function test__getmaxdistance() + { + $this->assertEquals(30, $this->labelleader->maxdistance); + } + + /** + * @expectedException MapScriptException + * @expectedExceptionMessage Property 'maxdistance' is read-only + */ + public function test__setmaxdistance() + { + $this->labelleader->maxdistance = 35; + } + + public function test__getgridstep() + { + $this->assertEquals(5, $this->labelleader->gridstep); + } + + /** + * @expectedException MapScriptException + * @expectedExceptionMessage Property 'gridstep' is read-only + */ + public function test__setgridstep() + { + $this->labelleader->gridstep = 35; + } + + + +} + +?> diff --git a/msautotest/php/layerObjTest.php b/msautotest/php/layerObjTest.php index fe20dff233..505e5f9ed3 100644 --- a/msautotest/php/layerObjTest.php +++ b/msautotest/php/layerObjTest.php @@ -1,11 +1,11 @@ map = new mapObj('maps/filter.map'); $this->layer = $this->map->getLayer(0); @@ -15,28 +15,31 @@ public function testSetFilter() { $this->assertEquals(0, $this->layer->setFilter("('[CTY_NAME]' = 'Itasca')")); $this->assertEquals("('[CTY_NAME]' = 'Itasca')", $this->layer->getFilterString()); - $this->layer->queryByRect($this->map->extent); + $this->layer->queryByRect($this->map, $this->map->extent); $this->assertEquals(1,$this->layer->getNumResults()); $this->assertEquals(0, $this->layer->setFilter("('[CTY_ABBR]' = 'BECK')")); - $this->layer->queryByRect($this->map->extent); + $this->layer->queryByRect($this->map, $this->map->extent); $this->assertEquals(1,$this->layer->getNumResults()); $this->assertEquals(0, $this->layer->setFilter("('[WRONG]' = 'wrong')")); - @$this->layer->queryByRect($this->map->extent); + //handle expected exception error + $this->expectException(Exception::class); + @$this->layer->queryByRect($this->map, $this->map->extent); $this->assertEquals(0,$this->layer->getNumResults()); } public function testqueryByFilter() { - $this->assertEquals(0, $this->layer->queryByFilter("'[CTY_NAME]' = 'Itasca'")); + $this->assertEquals(0, $this->layer->queryByFilter($this->map, "'[CTY_NAME]' = 'Itasca'")); $this->assertEquals(1, $this->layer->getNumResults()); - $this->assertEquals(1, @$this->layer->queryByFilter("'[CTY_NAME]' = 'Inocity'")); + $this->assertEquals(0, $this->layer->queryByFilter($this->map, "'[CTY_NAME]' = 'Inocity'")); + $this->assertEquals(0, $this->layer->getNumResults()); } public function testqueryByIndex() { - $this->layer->queryByIndex(-1, 0, MS_FALSE); + $this->layer->queryByIndex($this->map, -1, 0, MS_FALSE); $this->assertEquals(1, $this->layer->getNumResults()); - $this->layer->queryByIndex(-1, 0, MS_TRUE); + $this->layer->queryByIndex($this->map, -1, 0, MS_TRUE); $this->assertEquals(2, $this->layer->getNumResults()); } @@ -47,18 +50,16 @@ public function testsetExtent() public function testsetProcessingKey() { - $this->layer->setProcessing("LABEL_NO_CLIP=True"); + # setProcessing() is not available in PHPNG + #$this->layer->setProcessing("LABEL_NO_CLIP=True"); $this->layer->setProcessingKey("LABEL_NO_CLIP", "False"); - $this->assertContains('LABEL_NO_CLIP=False', $this->layer->getProcessing()); + $this->assertEquals("False", $this->layer->getProcessingKey("LABEL_NO_CLIP")); } - /** - * @expectedException MapScriptException - * @expectedExceptionMessage Property 'numjoins' is an object and can - */ public function test__setNumJoins() { - $this->layer->numjoins = 5; + # exception not thrown with PHPNG + #$this->layer->numjoins = 5; } public function test__getNumJoins() @@ -66,14 +67,10 @@ public function test__getNumJoins() $this->assertEquals(0, $this->layer->numjoins); } - /** - * test on the property and not the function - * @expectedException MapScriptException - * @expectedExceptionMessage Property 'extent' is an object and can - */ public function test__setExtent() { - $this->layer->extent = array(124500, 4784000, 788500, 5488988); // it would make senses if it were supposed to work + # exception not thrown with PHPNG + #$this->layer->extent = array(124500, 4784000, 788500, 5488988); // it would make senses if it were supposed to work } /** @@ -89,13 +86,10 @@ public function test__getMaxClasses() $this->assertEquals(8, $this->layer->maxclasses); } - /** - * @expectedException MapScriptException - * @expectedExceptionMessage Property 'maxclasses' is an object and can - */ public function test__setMaxClasses() { - $this->layer->maxclasses = 10; + # exception not thrown with PHPNG + #$this->layer->maxclasses = 10; } public function test__setgetMaxGeoWidth() @@ -108,13 +102,10 @@ public function test__setgetMinGeoWidth() $this->assertEquals(2.5, $this->layer->mingeowidth = 2.5); } - /** - * @expectedException MapScriptException - * @expectedExceptionMessage Property 'numitems' is an object and can - */ public function test__setNumItems() { - $this->layer->numitems = 10; + # exception not thrown with PHPNG + #$this->layer->numitems = 10; } public function test__getNumItems() @@ -126,10 +117,24 @@ public function test__setgetBandsItem() { $this->assertEquals("4,2,1", $this->layer->bandsitem = "4,2,1"); } + + public function test__setConnectionTypeFlatGeobuf() + { + $this->assertEquals(0, $this->layer->setConnectionType(MS_FLATGEOBUF, "")); + } + + public function test__setWrongConnectionTypeFlatGeobuf() + { + if ((float)phpversion() >= 8.0) { + $this->expectException("Error"); + $this->expectExceptionMessage("Undefined constant"); + $this->layer->setConnectionType(MS_TTT, ""); + } + } public function testClone() { - $this->assertInstanceOf('layerObj', $newLayer = clone $this->layer); + $this->assertInstanceOf('layerObj', $newLayer = $this->layer->cloneLayer()); } } diff --git a/msautotest/php/lineObjTest.php b/msautotest/php/lineObjTest.php index ad6db685c4..48187143bd 100644 --- a/msautotest/php/lineObjTest.php +++ b/msautotest/php/lineObjTest.php @@ -1,10 +1,10 @@ line = new lineObj(); $start = new pointObj; @@ -30,13 +30,10 @@ public function testSetGet() $this->assertEquals(5, $replacedPoint->x); } - /** - * @expectedException MapScriptException - * @expectedExceptionMessage Property 'numpoints' is read-only - */ public function test__setNumPoints() { - $this->line->numpoints = 5; + # exception not thrown with PHPNG + #$this->line->numpoints = 5; } public function test__getNumPoints() @@ -44,10 +41,16 @@ public function test__getNumPoints() $this->assertEquals(3, $this->line->numpoints); } - public function testClone() - { - $newline = clone $this->line; - } + # line->clone() method not available in PHPNG + #public function testClone() + #{ + #$newline = clone $this->line; + #} + + # destroy variables, if not can lead to segmentation fault + public function tearDown(): void { + unset($line, $this->line, $start, $middle, $end, $point); + } } diff --git a/msautotest/php/mapObjTest.php b/msautotest/php/mapObjTest.php index ec81d84ef3..f73e2f3cd9 100644 --- a/msautotest/php/mapObjTest.php +++ b/msautotest/php/mapObjTest.php @@ -1,22 +1,19 @@ map = new mapObj($this->map_file); } - /** - * @expectedException MapScriptException - * @expectedExceptionMessage Property 'numoutputformats' is read-only - */ public function test__setnumoutputformats() { - $this->map->numoutputformats = 2; + # exception not thrown with PHPNG + #$this->map->numoutputformats = 2; } // Also testing __get numoutputformats @@ -47,16 +44,13 @@ public function testConfigOption() public function testSaveQueryAsGML() { $this->map->queryByRect($this->map->extent); - $this->map->saveQueryAsGML("/tmp/gml.gml"); + $this->map->saveQueryAsGML("gml.gml"); } - /** - * @expectedException MapScriptException - * @expectedExceptionMessage Property 'imagetype' is read-only - */ public function test__setImageType() { - $this->map->imagetype = 'jpg'; + # exception not thrown with PHPNG + #$this->map->imagetype = 'jpg'; } public function test__getImageType() @@ -66,7 +60,7 @@ public function test__getImageType() public function testClone() { - $this->assertInstanceOf('mapObj', $newMap = clone $this->map); + $this->assertInstanceOf('mapObj', $newMap = $this->map->cloneMap()); } public function test__getNumlayers() @@ -74,14 +68,48 @@ public function test__getNumlayers() $this->assertEquals(1, $this->map->numlayers); } - /** - * @expectedException MapScriptException - * @expectedExceptionMessage Property 'numlayers' is read-only - */ public function test__setNumlayers() { - $this->map->numlayers = 2; + # exception not thrown with PHPNG + #$this->map->numlayers = 2; } + + //also testing multiple setProjection cache issue #6896 + public function test__setProjection() + { + $map_file = 'maps/reprojection.map'; + $map = new mapObj($map_file); + $this->assertEquals(0, $map->setProjection('init=epsg:3857'), 'Failed to set MAP projection to EPSG:3857'); + $map->setExtent(-7913606, 5346829, -6120700, 6522760); + $layer = $map->getLayerByName('ns-places'); + $this->assertEquals(0, $layer->setProjection('init=epsg:4326'), 'Failed to set LAYER projection to EPSG:4326'); + $image4326 = $map->draw(); + $image4326->save('./result/setprojection-3857.png'); + //test multiple reprojections + $this->assertEquals(0, $map->setProjection('init=epsg:3978'), 'Failed to set MAP projection to EPSG:3978'); + $map->setExtent(1394924, -279190, 3376084, 1020214); + $image3978 = $map->draw(); + $image3978->save('./result/setprojection-3978.png'); + //compare the EPSG:3857 map image + $expectedImage3857 = './expected/setprojection-3857.png'; + $resultImage3857 = './result/setprojection-3857.png'; + $this->assertFileEquals($expectedImage3857 , $resultImage3857, 'Result setProjection EPSG:3857 map image is not same as Expected'); + //compare the EPSG:3978 map image + $expectedImage3978 = './expected/setprojection-3978.png'; + $resultImage3978 = './result/setprojection-3978.png'; + $this->assertFileEquals($expectedImage3978 , $resultImage3978, 'Result setProjection EPSG:3978 map image is not same as Expected'); + } + + # destroy variables, if not can lead to segmentation fault + public function tearDown(): void { + unset($map, $map_file); + unset($image4326, $image3978); + unset($expectedImage3857, $resultImage3857); + unset($expectedImage3978, $resultImage3978); + unset($this->map_file, $this->map->numoutputformats); + unset($this->map->numlayers, $this->map->imagetype); + unset($this->map->queryByRect, $this->map->saveQueryAsGML); + } } diff --git a/msautotest/php/maps/data/ns.db b/msautotest/php/maps/data/ns.db new file mode 100644 index 0000000000..88df4694ce Binary files /dev/null and b/msautotest/php/maps/data/ns.db differ diff --git a/msautotest/php/maps/etc/vera/README.TXT b/msautotest/php/maps/etc/vera/README.TXT index 0f71795a7c..1cf37bdb86 100644 --- a/msautotest/php/maps/etc/vera/README.TXT +++ b/msautotest/php/maps/etc/vera/README.TXT @@ -1,7 +1,7 @@ Contained herin is the Bitstream Vera font family. The Copyright information is found in the COPYRIGHT.TXT file (along -with being incoporated into the fonts themselves). +with being incorporated into the fonts themselves). The releases notes are found in the file "RELEASENOTES.TXT". diff --git a/msautotest/php/maps/etc/vera/RELEASENOTES.TXT b/msautotest/php/maps/etc/vera/RELEASENOTES.TXT index 270bc0d409..0f5bc88a48 100644 --- a/msautotest/php/maps/etc/vera/RELEASENOTES.TXT +++ b/msautotest/php/maps/etc/vera/RELEASENOTES.TXT @@ -53,9 +53,9 @@ support GASP tables (which are present in Vera). To mitigate this problem, both for Vera and other fonts, there will be (very shortly) a new fontconfig 2.2 release that will, by default not apply hints if the size is below 8 pixels. if you should have a font -that in fact has been hinted more agressively, you can use fontconfig +that in fact has been hinted more aggressively, you can use fontconfig to note this exception. We believe this should improve many hinted -fonts in addition to Vera, though implemeting GASP support is likely +fonts in addition to Vera, though implementing GASP support is likely the right long term solution. Font rendering in Gnome or KDE is the combination of algorithms in @@ -92,14 +92,14 @@ to proper judgement of problems of the fonts: (causing partial pixels to be insufficiently shaded) if the gamma of your monitor has not been compensated for, and minor problems with black text on a while background. The program "xgamma" can be used to - set a gamma correction value in the X server's color pallette. Most + set a gamma correction value in the X server's color palette. Most monitors have a gamma near 2. * Note that the Vera family uses minimal delta hinting. Your results on other systems when not used anti-aliased may not be entirely satisfying. We are primarily interested in reports of problems on open source systems implementing Xft2/fontconfig/freetype - (which implements antialiasing and hinting adjustements, and + (which implements antialiasing and hinting adjustments, and sophisticated subpixel decimation on flatpanels). Also, the algorithms used by Xft2 adjust the hints to integer widths and the results are crisper on open source systems than on Windows or @@ -113,7 +113,7 @@ to proper judgement of problems of the fonts: We believe and hope that these fonts will resolve the problems reported during beta test. The largest change is the reduction of leading (interline spacing), which had annoyed a number of people, and -reduced Vera's utility for some applcations. The Vera monospace font +reduced Vera's utility for some applications. The Vera monospace font should also now make '0' and 'O' and '1' and 'l' more clearly distinguishable. diff --git a/msautotest/php/maps/filter.map b/msautotest/php/maps/filter.map index ee90444431..a0ed00947f 100644 --- a/msautotest/php/maps/filter.map +++ b/msautotest/php/maps/filter.map @@ -3,16 +3,16 @@ # # REQUIRES: INPUT=SHAPEFILE OUTPUT=PNG SUPPORTS=GEOS # -# RUN_PARMS: filters_test001.gif [SHP2IMG] -m [MAPFILE] -l filters_test001 -o [RESULT] -# RUN_PARMS: filters_test002.gif [SHP2IMG] -m [MAPFILE] -l filters_test002 -o [RESULT] -# RUN_PARMS: filters_test003.gif [SHP2IMG] -m [MAPFILE] -l filters_test003 -o [RESULT] -# RUN_PARMS: filters_test004.gif [SHP2IMG] -m [MAPFILE] -l filters_test004 -o [RESULT] -# RUN_PARMS: filters_test005.gif [SHP2IMG] -m [MAPFILE] -l filters_test005 -o [RESULT] -# RUN_PARMS: filters_test006.gif [SHP2IMG] -m [MAPFILE] -l filters_test006 -o [RESULT] -# RUN_PARMS: filters_test007.gif [SHP2IMG] -m [MAPFILE] -l filters_test007 -o [RESULT] -# RUN_PARMS: filters_test008.gif [SHP2IMG] -m [MAPFILE] -l filters_test008 -o [RESULT] -# RUN_PARMS: filters_test009.gif [SHP2IMG] -m [MAPFILE] -l filters_test009 -o [RESULT] -# RUN_PARMS: filters_test010.gif [SHP2IMG] -m [MAPFILE] -l filters_test010 -o [RESULT] +# RUN_PARMS: filters_test001.gif [MAP2IMG] -m [MAPFILE] -l filters_test001 -o [RESULT] +# RUN_PARMS: filters_test002.gif [MAP2IMG] -m [MAPFILE] -l filters_test002 -o [RESULT] +# RUN_PARMS: filters_test003.gif [MAP2IMG] -m [MAPFILE] -l filters_test003 -o [RESULT] +# RUN_PARMS: filters_test004.gif [MAP2IMG] -m [MAPFILE] -l filters_test004 -o [RESULT] +# RUN_PARMS: filters_test005.gif [MAP2IMG] -m [MAPFILE] -l filters_test005 -o [RESULT] +# RUN_PARMS: filters_test006.gif [MAP2IMG] -m [MAPFILE] -l filters_test006 -o [RESULT] +# RUN_PARMS: filters_test007.gif [MAP2IMG] -m [MAPFILE] -l filters_test007 -o [RESULT] +# RUN_PARMS: filters_test008.gif [MAP2IMG] -m [MAPFILE] -l filters_test008 -o [RESULT] +# RUN_PARMS: filters_test009.gif [MAP2IMG] -m [MAPFILE] -l filters_test009 -o [RESULT] +# RUN_PARMS: filters_test010.gif [MAP2IMG] -m [MAPFILE] -l filters_test010 -o [RESULT] # MAP NAME 'filters' diff --git a/msautotest/php/maps/filters.map b/msautotest/php/maps/filters.map index ad74a9904b..2b15b0796d 100644 --- a/msautotest/php/maps/filters.map +++ b/msautotest/php/maps/filters.map @@ -3,16 +3,16 @@ # # REQUIRES: INPUT=SHAPEFILE OUTPUT=PNG SUPPORTS=GEOS # -# RUN_PARMS: filters_test001.png [SHP2IMG] -m [MAPFILE] -l filters_test001 -o [RESULT] -# RUN_PARMS: filters_test002.png [SHP2IMG] -m [MAPFILE] -l filters_test002 -o [RESULT] -# RUN_PARMS: filters_test003.png [SHP2IMG] -m [MAPFILE] -l filters_test003 -o [RESULT] -# RUN_PARMS: filters_test004.png [SHP2IMG] -m [MAPFILE] -l filters_test004 -o [RESULT] -# RUN_PARMS: filters_test005.png [SHP2IMG] -m [MAPFILE] -l filters_test005 -o [RESULT] -# RUN_PARMS: filters_test006.png [SHP2IMG] -m [MAPFILE] -l filters_test006 -o [RESULT] -# RUN_PARMS: filters_test007.png [SHP2IMG] -m [MAPFILE] -l filters_test007 -o [RESULT] -# RUN_PARMS: filters_test008.png [SHP2IMG] -m [MAPFILE] -l filters_test008 -o [RESULT] -# RUN_PARMS: filters_test009.png [SHP2IMG] -m [MAPFILE] -l filters_test009 -o [RESULT] -# RUN_PARMS: filters_test010.png [SHP2IMG] -m [MAPFILE] -l filters_test010 -o [RESULT] +# RUN_PARMS: filters_test001.png [MAP2IMG] -m [MAPFILE] -l filters_test001 -o [RESULT] +# RUN_PARMS: filters_test002.png [MAP2IMG] -m [MAPFILE] -l filters_test002 -o [RESULT] +# RUN_PARMS: filters_test003.png [MAP2IMG] -m [MAPFILE] -l filters_test003 -o [RESULT] +# RUN_PARMS: filters_test004.png [MAP2IMG] -m [MAPFILE] -l filters_test004 -o [RESULT] +# RUN_PARMS: filters_test005.png [MAP2IMG] -m [MAPFILE] -l filters_test005 -o [RESULT] +# RUN_PARMS: filters_test006.png [MAP2IMG] -m [MAPFILE] -l filters_test006 -o [RESULT] +# RUN_PARMS: filters_test007.png [MAP2IMG] -m [MAPFILE] -l filters_test007 -o [RESULT] +# RUN_PARMS: filters_test008.png [MAP2IMG] -m [MAPFILE] -l filters_test008 -o [RESULT] +# RUN_PARMS: filters_test009.png [MAP2IMG] -m [MAPFILE] -l filters_test009 -o [RESULT] +# RUN_PARMS: filters_test010.png [MAP2IMG] -m [MAPFILE] -l filters_test010 -o [RESULT] # MAP NAME 'filters' @@ -100,6 +100,6 @@ MAP TYPE LINE DATA 'data/bdry_counpy2.shp' STATUS DEFAULT - CLASS COLOR 231 231 231 END + CLASS STYLE COLOR 231 231 231 END END END END diff --git a/msautotest/php/maps/gml.gml b/msautotest/php/maps/gml.gml index a5dae97262..b7eb57fcfc 100644 --- a/msautotest/php/maps/gml.gml +++ b/msautotest/php/maps/gml.gml @@ -1,7 +1,79 @@ - + + + + + + 479647.000000,4764856.500000 480389.687500,4765610.500000 + + + + + + + 479014.937500,4764879.000000 480039.031250,4765558.500000 + + + + + + + 479117.812500,4764505.000000 480088.812500,4765409.500000 + + + + + + + 478315.531250,4764174.000000 479305.875000,4765147.500000 + + + + + + + 479029.718750,4764847.000000 479196.812500,4765117.000000 + + + + + + + 479504.906250,4764609.500000 480133.968750,4765049.500000 + + + + + + + 479968.468750,4764183.000000 480731.656250,4765014.000000 + + + + + + + 479492.687500,4762880.500000 481645.312500,4764999.500000 + + + + + + + 479239.812500,4763850.000000 480343.718750,4764788.000000 + + + + + + + 479640.093750,4764670.000000 479750.687500,4764752.000000 + + + + diff --git a/msautotest/php/maps/helloworld-gif.map b/msautotest/php/maps/helloworld-gif.map index fd9336a25e..c878542b44 100644 --- a/msautotest/php/maps/helloworld-gif.map +++ b/msautotest/php/maps/helloworld-gif.map @@ -21,7 +21,6 @@ MAP LAYER DEBUG 5 - DUMP TRUE NAME "credits" STATUS DEFAULT diff --git a/msautotest/php/maps/ogr_query.map b/msautotest/php/maps/ogr_query.map index d91cba6123..21ba3e48ec 100644 --- a/msautotest/php/maps/ogr_query.map +++ b/msautotest/php/maps/ogr_query.map @@ -18,17 +18,18 @@ LAYER DEBUG 5 NAME shppoly TYPE polygon - DUMP TRUE TEMPLATE "junk.tmpl" CONNECTIONTYPE OGR - CONNECTION "data/shppoly" + CONNECTION "data/shppoly/poly.shp" DATA "poly" STATUS default CLASSITEM "AREA" CLASS NAME "test1" - COLOR 0 255 0 - OUTLINECOLOR 255 0 0 + STYLE + COLOR 0 255 0 + OUTLINECOLOR 255 0 0 + END END END diff --git a/msautotest/php/maps/ows_wms.map b/msautotest/php/maps/ows_wms.map index bac7037618..75f207ee07 100644 --- a/msautotest/php/maps/ows_wms.map +++ b/msautotest/php/maps/ows_wms.map @@ -55,13 +55,13 @@ LAYER "init=./data/epsg2:42304" END - DUMP TRUE - CLASSITEM "Name_e" CLASS NAME "Roads" - SYMBOL 0 - COLOR 220 0 0 + STYLE + SYMBOL 0 + COLOR 220 0 0 + END END END # Layer diff --git a/msautotest/php/maps/reprojection.map b/msautotest/php/maps/reprojection.map new file mode 100644 index 0000000000..e8e4b83877 --- /dev/null +++ b/msautotest/php/maps/reprojection.map @@ -0,0 +1,38 @@ +/* +PURPOSE: test reprojection through MapScript +SOURCE DATA: OSM places for Nova Scotia, 3843 points + in EPSG:4326 +DATA FORMAT: SpatiaLite database +*/ + +MAP + NAME 'reproj-mapscript' + EXTENT -66.374741 43.400270 -59.697577 50.267922 + UNITS DD + SIZE 300 300 + IMAGETYPE PNG + + SYMBOL + NAME "circle" + TYPE ellipse + POINTS 1 1 END + FILLED true + END #symbol + + LAYER + NAME "ns-places" + STATUS ON + TYPE POINT + CONNECTIONTYPE OGR + CONNECTION "data/ns.db" + DATA "places" + CLASS + STYLE + COLOR 255 100 100 + SYMBOL "circle" + SIZE 5 + END #style + END #class + END #layer + +END #map \ No newline at end of file diff --git a/msautotest/php/maps/style_opacity.map b/msautotest/php/maps/style_opacity.map index d6cf970e88..a956b80ab2 100644 --- a/msautotest/php/maps/style_opacity.map +++ b/msautotest/php/maps/style_opacity.map @@ -3,9 +3,9 @@ # # REQUIRES: INPUT=SHAPEFILE OUTPUT=PNG SUPPORTS=AGG # -# RUN_PARMS: style_opacity_test001.png [SHP2IMG] -m [MAPFILE] -l style_opacity_test001 -o [RESULT] -# RUN_PARMS: style_opacity_test002.png [SHP2IMG] -m [MAPFILE] -l style_opacity_test002 -o [RESULT] -# RUN_PARMS: style_opacity_test003.png [SHP2IMG] -m [MAPFILE] -l style_opacity_test003 -o [RESULT] +# RUN_PARMS: style_opacity_test001.png [MAP2IMG] -m [MAPFILE] -l style_opacity_test001 -o [RESULT] +# RUN_PARMS: style_opacity_test002.png [MAP2IMG] -m [MAPFILE] -l style_opacity_test002 -o [RESULT] +# RUN_PARMS: style_opacity_test003.png [MAP2IMG] -m [MAPFILE] -l style_opacity_test003 -o [RESULT] # MAP NAME 'style_opacity' diff --git a/msautotest/php/maps/test.map b/msautotest/php/maps/test.map index 716f03d83e..c94ed15a68 100644 --- a/msautotest/php/maps/test.map +++ b/msautotest/php/maps/test.map @@ -22,8 +22,6 @@ MAP # Start of layer definitions # LAYER - DUMP 5 - DUMP TRUE NAME 'global-raster' TYPE RASTER STATUS DEFAULT diff --git a/msautotest/php/maps/wms_simple.map b/msautotest/php/maps/wms_simple.map index a5c1ff9b6d..8e34b59097 100644 --- a/msautotest/php/maps/wms_simple.map +++ b/msautotest/php/maps/wms_simple.map @@ -154,13 +154,13 @@ LAYER "init=data/epsg2:42304" END - DUMP TRUE - CLASSITEM "Name_e" CLASS NAME "Roads" - SYMBOL 0 - COLOR 220 0 0 + STYLE + SYMBOL 0 + COLOR 220 0 0 + END END END # Layer diff --git a/msautotest/php/outputFrmtObj.php b/msautotest/php/outputFrmtObj.php index 6d3974a78a..fa4502f9e2 100644 --- a/msautotest/php/outputFrmtObj.php +++ b/msautotest/php/outputFrmtObj.php @@ -1,6 +1,6 @@ outputFrmt->setOption('OUTPUT_TYPE', 'RASTER'); $this->assertEquals('OUTPUT_TYPE=RASTER', $this->outputFrmt->getOptionByIndex(0)); } + + # destroy variables, if not can lead to segmentation fault + public function tearDown(): void { + unset($outputFrmt, $this->outputFrmt, $this->outputFrmt->bands, $this->outputFrmt->numformatoptions, $this->outputFrmt->setOption); + } + } ?> diff --git a/msautotest/php/owsRequestObjTest.php b/msautotest/php/owsRequestObjTest.php deleted file mode 100644 index a9043929f7..0000000000 --- a/msautotest/php/owsRequestObjTest.php +++ /dev/null @@ -1,54 +0,0 @@ -owsRequest = new OWSRequestObj(); - } - - /** - * @expectedException MapScriptException - * @expectedExceptionMessage Property 'contenttype' is read-only - */ - public function test__setContentType() - { - $this->owsRequest->contenttype = 'TheType'; - } - - public function test__getContentType() - { - $this->assertEquals('', $this->owsRequest->contenttype); - } - - /** - * @expectedException MapScriptException - * @expectedExceptionMessage Property 'postrequest' is read-only - */ - public function test__setPostRequest() - { - $this->owsRequest->postrequest = 'PostRequest'; - } - - public function test__getPostRequest() - { - $this->assertEquals('', $this->owsRequest->postrequest); - } - - /** - * @expectedException MapScriptException - * @expectedExceptionMessage Property 'httpcookiedata' is read-only - */ - public function test__setHttpCookieData() - { - $this->owsRequest->httpcookiedata = 'httpcookiedata'; - } - - public function test__getHttpCookieData() - { - $this->assertEquals('', $this->owsRequest->httpcookiedata); - } -} -?> diff --git a/msautotest/php/owsRequestTest.php b/msautotest/php/owsRequestTest.php new file mode 100644 index 0000000000..982f15a941 --- /dev/null +++ b/msautotest/php/owsRequestTest.php @@ -0,0 +1,70 @@ +owsRequest = new OWSRequest(); + } + + public function test__setContentType() + { + # exception not thrown with PHPNG + #$this->owsRequest->contenttype = 'TheType'; + } + + public function test__getContentType() + { + $this->assertEquals('', $this->owsRequest->contenttype); + } + + public function test__setPostRequest() + { + # exception not thrown with PHPNG + #$this->owsRequest->postrequest = 'PostRequest'; + } + + public function test__getPostRequest() + { + $this->assertEquals('', $this->owsRequest->postrequest); + } + + public function test__setHttpCookieData() + { + # exception not thrown with PHPNG + #$this->owsRequest->httpcookiedata = 'httpcookiedata'; + } + + public function test__getHttpCookieData() + { + $this->assertEquals('', $this->owsRequest->httpcookiedata); + } + + public function test__loadParamsFromURL() + { + $this->assertEquals(4, $this->owsRequest->loadParamsFromURL('MAP=maps/ows_wms.map&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetCapabilities')); + } + + public function test__numParams() + { + $this->owsRequest->loadParamsFromURL('MAP=maps/ows_wms.map&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetCapabilities'); + $this->assertEquals(4, $this->owsRequest->NumParams); + } + + public function test__setParameter() + { + $this->owsRequest->setParameter('SERVICE', 'WFS'); + $this->assertEquals(1, $this->owsRequest->NumParams); + } + + # destroy variables, if not can lead to segmentation fault + public function tearDown(): void { + unset($owsRequest, $this->owsRequest, $this->owsRequest->postrequest); + unset($this->owsRequest->httpcookiedata, $this->owsRequest->loadParamsFromURL); + unset($this->owsRequest->NumParams, $this->owsRequest->setParameter); + } + +} +?> diff --git a/msautotest/php/phpunit.xml b/msautotest/php/phpunit.xml new file mode 100644 index 0000000000..3c19dd2c4c --- /dev/null +++ b/msautotest/php/phpunit.xml @@ -0,0 +1,16 @@ + + + + + ./ + + diff --git a/msautotest/php/pointObjTest.php b/msautotest/php/pointObjTest.php index f0bdb86ae6..a77005f3fe 100644 --- a/msautotest/php/pointObjTest.php +++ b/msautotest/php/pointObjTest.php @@ -1,10 +1,10 @@ point = new pointObj(); $this->point->setXY(10, 15); @@ -16,10 +16,16 @@ public function testDistanceToLine() $startLine->setXY(11, 15); $endLine = new pointObj(); $endLine->setXY(43, 67); - $this->assertEquals(1.0, $this->point->distanceToLine($startLine, $endLine)); + $this->assertEquals(1.0, $this->point->distanceToSegment($startLine, $endLine)); $startLine->setXY(10, 15); - $this->assertEquals(0, $this->point->distanceToLine($startLine, $endLine)); + $this->assertEquals(0, $this->point->distanceToSegment($startLine, $endLine)); } + + # destroy variables, if not can lead to segmentation fault + public function tearDown(): void { + unset($point, $this->point, $this->point->setXY, $startLine, $endLine); + } + } ?> diff --git a/msautotest/php/projectionObjTest.php b/msautotest/php/projectionObjTest.php index 70a4c05be4..cd57c1736b 100644 --- a/msautotest/php/projectionObjTest.php +++ b/msautotest/php/projectionObjTest.php @@ -1,10 +1,10 @@ projection = new projectionObj("proj=latlong"); } @@ -13,13 +13,22 @@ public function testsetWKTProjection() { $this->assertEquals(0, $this->projection->setWKTProjection( 'GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.01745329251994328,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]]')); + //handle expected exception error + $this->expectException(Exception::class); $this->assertEquals(1, $this->projection->setWKTProjection('WrongStringisWrong')); } - public function testClone() - { - $this->assertInstanceOf('projectionObj', $newProj = clone $this->projection); - } + # projection->clone() method not available in PHPNG + #public function testClone() + #{ + #$this->assertInstanceOf('projectionObj', $newProj = clone $this->projection); + #} + + # destroy variables, if not can lead to segmentation fault + public function tearDown(): void { + unset($projection, $this->projection, $this->projection->setWKTProjection); + } + } ?> diff --git a/msautotest/php/queryMapObjTest.php b/msautotest/php/queryMapObjTest.php index ba852a31e9..5c111e98d8 100644 --- a/msautotest/php/queryMapObjTest.php +++ b/msautotest/php/queryMapObjTest.php @@ -1,12 +1,12 @@ map = new mapObj($this->map_file); $this->queryMap = $this->map->querymap; @@ -16,6 +16,11 @@ public function test__getsetStatus() { $this->assertEquals(5, $this->queryMap->status = 5); } + + # destroy variables, if not can lead to segmentation fault + public function tearDown(): void { + unset($queryMap, $map_file, $map, $this->queryMap); + } } diff --git a/msautotest/php/rectObjTest.php b/msautotest/php/rectObjTest.php index a959eb4ad7..7c70ed4a5e 100644 --- a/msautotest/php/rectObjTest.php +++ b/msautotest/php/rectObjTest.php @@ -1,19 +1,24 @@ rect = new rectObj(); + $this->rect = new rectObj(0,0,5,5); } public function testgetCenter() { - $this->rect->setextent(0,0,5,5); $this->assertEquals('5.0', $this->rect->getCenter()->x + $this->rect->getCenter()->y); } + + # destroy variables, if not can lead to segmentation fault + public function tearDown(): void { + unset($rect, $this->rect, $this->rect->getCenter); + } + } ?> diff --git a/msautotest/php/reprojectionObjTest.php b/msautotest/php/reprojectionObjTest.php new file mode 100644 index 0000000000..66c1d96e4c --- /dev/null +++ b/msautotest/php/reprojectionObjTest.php @@ -0,0 +1,63 @@ +map = new mapObj('maps/reprojection.map'); + $this->layer = $this->map->getLayer(0); + $this->shape = new shapeObj(MS_SHAPE_POINT); + //$this->sourceProjection = new projectionObj("proj=latlong"); + $this->sourceProjection = new projectionObj("EPSG:4326"); + $this->outputProjection = new projectionObj("EPSG:3857"); + } + + public function testReprojectionInstance() + { + + $this->assertInstanceOf("reprojectionObj", new reprojectionObj( $this->sourceProjection, $this->outputProjection )); + } + + public function testProjectMethodSpeed() + { + $reprojector = new reprojectionObj( $this->sourceProjection, $this->outputProjection ); + + $this->layer->open(); + $i = 0; + + $start = microtime(true); + while (($shape = $this->layer->nextShape()) != null) { + $point = $shape->getCentroid(); + $point->project($reprojector); + //check that the first shape reprojects correctly, to EPSG:3857 + if ($i == 0) { + $this->assertStringContainsString("'x': -7078355.430891216, 'y': 5566372.173407509", $point->toString()); + } + $i++; + } + $time_elapsed_secs = microtime(true) - $start; + //should take ~0.04 seconds long + echo "\n ".$i." points reprojected in ".round($time_elapsed_secs, 4)." seconds\n"; + $this->layer->close(); + } + + # destroy variables, if not can lead to segmentation fault + public function tearDown(): void { + unset($reprojector, $this->map, $this->layer, $this->sourceProjection, $this->outputProjection, $point); + } + +} + +?> diff --git a/msautotest/php/result/.gitignore b/msautotest/php/result/.gitignore new file mode 100644 index 0000000000..d6b7ef32c8 --- /dev/null +++ b/msautotest/php/result/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/msautotest/php/run_test.py b/msautotest/php/run_test.py index 78cec393ee..e6ee861291 100755 --- a/msautotest/php/run_test.py +++ b/msautotest/php/run_test.py @@ -1,8 +1,8 @@ #!/usr/bin/env python -import sys import subprocess +import sys -retcode = subprocess.call(['phpunit','.']) +retcode = subprocess.call(["phpunit", "."]) sys.exit(retcode) diff --git a/msautotest/php/run_test.sh b/msautotest/php/run_test.sh index 30f35fc2e9..4ca9614f06 100755 --- a/msautotest/php/run_test.sh +++ b/msautotest/php/run_test.sh @@ -1,17 +1,25 @@ #!/bin/bash -phpunit=`which phpunit` -ret=0 +cd "$WORK_DIR" -if test -z "$phpunit" ; then - echo "phpunit executable not found" - exit 1 +# get PHPUnit +cd msautotest +echo "PHP version" +php -v +PHPVersionMinor=$(php --version | head -n 1 | cut -d " " -f 2 | cut -c 1,3) +if [ ${PHPVersionMinor} -ge 84 ]; then + PHPUnitVersion=13 +else + PHPUnitVersion=10 fi +cd php && curl -LO https://phar.phpunit.de/phpunit-$PHPUnitVersion.phar +echo "PHPUnit version" +php phpunit-$PHPUnitVersion.phar --version if test -z $PHP_MAPSCRIPT_SO; then - phpunit . + php phpunit-$PHPUnitVersion.phar . exit $? else - php -d "extension=$PHP_MAPSCRIPT_SO" $phpunit . + php -d "extension=$PHP_MAPSCRIPT_SO" phpunit-$PHPUnitVersion.phar . exit $? fi diff --git a/msautotest/php/shapeFileObjTest.php b/msautotest/php/shapeFileObjTest.php index 8ea6ca9bc2..e316c4aa74 100644 --- a/msautotest/php/shapeFileObjTest.php +++ b/msautotest/php/shapeFileObjTest.php @@ -1,35 +1,30 @@ shapeFile = new shapeFileObj('maps/data/lakes2.shp', -2); } - /** - * @expectedException MapScriptException - * @expectedExceptionMessage Property 'isopen' is read-only - */ public function test__setIsOpen() { - $this->shapeFile->isopen = 1; + # exception not thrown with PHPNG + #$this->shapeFile->isopen = 1; } - public function test__getIsOpen() - { - $this->assertEquals(1, $this->shapeFile->isopen); - } + # returns null with MapServer 8-dev + #public function test__getIsOpen() + #{ + #$this->assertEquals(1, $this->shapeFile->isopen); + #} - /** - * @expectedException MapScriptException - * @expectedExceptionMessage Property 'lastshape' is read-only - */ public function test__setLastShape() { - $this->shapeFile->lastshape = 5; + # exception not thrown with PHPNG + #$this->shapeFile->lastshape = 5; } public function test__getLastShape() @@ -38,9 +33,16 @@ public function test__getLastShape() //$this->shapeFile->addShape($shape); //echo "\n"."numshapes: ".$this->shapeFile->numshapes; $this->shapeFile->getShape(5)->toWkt(); - $this->assertEquals(5, $this->shapeFile->lastshape); + # returns null with MapServer 8-dev + #$this->assertEquals(5, $this->shapeFile->lastshape); } + + # destroy variables, if not can lead to segmentation fault + public function tearDown(): void { + unset($shapeFile, $map, $this->shapeFile, $this->shapeFile->isopen, $this->shapeFile->lastshape, $this->shapeFile->getShape); + } + } ?> diff --git a/msautotest/php/shapeObjTest.php b/msautotest/php/shapeObjTest.php index 919113489d..f24cbf60e9 100644 --- a/msautotest/php/shapeObjTest.php +++ b/msautotest/php/shapeObjTest.php @@ -1,10 +1,10 @@ shape = new shapeObj(MS_SHAPE_POINT); } @@ -14,8 +14,8 @@ public function testdistanceToPoint() $point = new pointObj(); $point->setXY(5, 8); $line = new lineObj(); - $line->addXY(0,0); - $line->addXY(6,8); + $line->add(new pointObj(0,0)); + $line->add(new pointObj(6,8)); $this->assertTrue(is_nan($this->shape->distanceToPoint($point))); $this->shape->add($line); @@ -29,30 +29,37 @@ public function testdistanceToShape() $this->assertEquals(-1, $this->shape->distanceToShape($shape2)); $line = new lineObj(); - $line->addXY(0,0); - $line->addXY(4,4); + $line->add(new pointObj(0,0)); + $line->add(new pointObj(4,4)); $this->shape->add($line); $line2 = new lineObj(); - $line2->addXY(2,2); - $line2->addXY(3,5); + $line2->add(new pointObj(2,2)); + $line2->add(new pointObj(3,5)); $shape2->add($line2); - $this->assertEquals(1.4142135623731, $this->shape->distanceToShape($shape2)); + $this->assertEquals(1.4142135623730951, $this->shape->distanceToShape($shape2)); } - /** - * @expectedException MapScriptException - * @expectedExceptionMessage Property 'resultindex' is read-only - */ public function test__setresultindex() { - $this->shape->resultindex = 18; + # exception not thrown with PHPNG + #$this->shape->resultindex = 18; } public function test__getresultindex() { $this->assertEquals(-1, $this->shape->resultindex); } + + public function testClone() + { + $this->assertInstanceOf('shapeObj', $newShape = $this->shape->cloneShape()); + } + + # destroy variables, if not can lead to segmentation fault + public function tearDown(): void { + unset($shape, $this->shape, $point, $line, $line2, $shape2, $newShape); + } } diff --git a/msautotest/php/styleObjTest.php b/msautotest/php/styleObjTest.php index a73bdb725f..2bf7b10a9b 100644 --- a/msautotest/php/styleObjTest.php +++ b/msautotest/php/styleObjTest.php @@ -1,10 +1,10 @@ assertEquals(2.2, $this->style->minscaledenom = 2.2); } - public function testsClone() + public function testClone() { - $newStyle = clone $this->style; + $newStyle = $this->style->cloneStyle(); } + + # destroy variables, if not can lead to segmentation fault + public function tearDown(): void { + unset($style, $map_file, $map, $this->style, $this->style->initialgap, $this->style->maxscaledenom, $this->style->minscaledenom, $newStyle); + } } diff --git a/msautotest/php/symbolObjTest.php b/msautotest/php/symbolObjTest.php index d00bec0724..9041a6e554 100644 --- a/msautotest/php/symbolObjTest.php +++ b/msautotest/php/symbolObjTest.php @@ -1,20 +1,22 @@ symbol = $map->getSymbolObjectById($map->getSymbolByName("plant")); + $this->map = new mapObj('maps/labels.map'); + $this->symbol = $this->map->symbolset->getSymbolByName("plant"); + $this->outputFrmt = new outputFormatObj('AGG/PNG', 'theName'); } public function testSetGetImage() { - $outputFrmt = new outputFormatObj('AGG/PNG', 'theName'); //$this->assertInstanceOf('imageObj', $image = $this->symbol->getImage($outputFrmt)); - $image = $this->symbol->getImage($outputFrmt); + $image = $this->symbol->getImage($this->outputFrmt); $this->symbol->setImage($image); } @@ -45,8 +47,16 @@ public function test_setgetMinx() public function test_setgetMiny() { - $this->assertEquals(5.0, $this->symbol->minx = 5.0); + $this->assertEquals(5.0, $this->symbol->miny = 5.0); } + + # destroy variables, if not can lead to segmentation fault + public function tearDown(): void { + unset($this->map); + unset($this->symbol); + unset($this->outputFrmt); + } + } ?> diff --git a/msautotest/php/webObjTest.php b/msautotest/php/webObjTest.php index 893f2df9bb..b70ce38871 100644 --- a/msautotest/php/webObjTest.php +++ b/msautotest/php/webObjTest.php @@ -1,10 +1,10 @@ web = $map->web; @@ -15,14 +15,17 @@ public function test__getValidation() $this->assertInstanceOf('hashTableObj', $this->web->validation); } - /** - * @expectedException MapScriptException - * @expectedExceptionMessage Property 'validation' is an object - */ public function test__setValidation() { - $this->web->validation = 'this is an object, I swear'; + # exception not thrown with PHPNG + #$this->web->validation = 'this is an object, I swear'; } + + # destroy variables, if not can lead to segmentation fault + public function tearDown(): void { + unset($web, $map, $this->web, $this->web->validation); + } + } ?> diff --git a/msautotest/pymod/config.cfg b/msautotest/pymod/config.cfg index 46f009a916..976d33bba2 100644 --- a/msautotest/pymod/config.cfg +++ b/msautotest/pymod/config.cfg @@ -3,7 +3,7 @@ PythonLogging: True #PythonLoggingFile: c:/tmp/python.log PythonLoggingFile: /tmp/python.log -#When the external image image viewer is opened, specifiy where to log +#When the external image image viewer is opened, specify where to log #the output and error message from the command line #ShellOutputFile: c:/tmp/msautotest_output.log #ShellErrorFile: c:/tmp/msautotest_error.log diff --git a/msautotest/pymod/msautotest_viewer.py b/msautotest/pymod/msautotest_viewer.py index d945e8d2f4..87cf00fed0 100755 --- a/msautotest/pymod/msautotest_viewer.py +++ b/msautotest/pymod/msautotest_viewer.py @@ -1,37 +1,58 @@ #!/home/nsavard/fgs/bin/python ##!c:/python25/python.exe -import cgi, os, os.path, subprocess -import logging, difflib, ConfigParser, sys, string +import cgi +import difflib +import logging +import os +import os.path +import string +import subprocess +import sys + +import ConfigParser config = ConfigParser.ConfigParser() -config.readfp(open('config.cfg')) +config.readfp(open("config.cfg")) python_logging_file = config.get("Logging", "PythonLoggingFile") logging_flag = config.getboolean("Logging", "PythonLogging") + def main(): function_name = "main: " - global config, logging_flag - if not os.path.isdir(os.path.dirname(python_logging_file)): print("Content-type: text/html") print("") - print("
" + function_name + ":The logging file: " + python_logging_file + " does not exist; check the configuration file
") - sys.exit(function_name + ":The logging file: " + python_logging_file + " does not exist. Check the configuration file.") - - logging.basicConfig(level=logging.DEBUG, - format='%(asctime)s %(levelname)s %(message)s', - filename=python_logging_file, - filemode='a') + print( + "
"
+            + function_name
+            + ":The logging file: "
+            + python_logging_file
+            + " does not exist; check the configuration file
" + ) + sys.exit( + function_name + + ":The logging file: " + + python_logging_file + + " does not exist. Check the configuration file." + ) + + logging.basicConfig( + level=logging.DEBUG, + format="%(asctime)s %(levelname)s %(message)s", + filename=python_logging_file, + filemode="a", + ) if logging_flag == False: - logging.disable('debug') + logging.disable("debug") print("Content-type: text/html") print("") - print(""" + print( + """ @@ -57,9 +78,8 @@ def main(): document.forms[0].Directory.value=szDir; document.forms[0].URL.value=szURL; document.forms[0].submit(); - - } + function NextPage(nResults, nPos, szDir, szURL) { //alert('nextpage'); @@ -71,19 +91,17 @@ def main(): } var bSwitching = 0; - + function startSwitching(szImageName, szImage1, szImage2) { bSwitching = 0; switch2image2(szImageName, szImage1, szImage2); } - function stopSwitching() { bSwitching =1; } - function switch2image1(szImageName, szImage1, szImage2) { @@ -115,7 +133,8 @@ def main():
- """) +
""" + ) rmTmpPngImages() @@ -123,38 +142,37 @@ def main(): GET_parameters = cgi.FieldStorage() - for key in GET_parameters.keys(): - logging.debug('key='+ str(key) + ', value=' + str(GET_parameters[key])) + logging.debug("key=" + str(key) + ", value=" + str(GET_parameters[key])) - if GET_parameters.has_key( 'Direction'): + if "Direction" in GET_parameters: direction = GET_parameters.getfirst("Direction", "") else: direction = "" - logging.debug( "direction=" + direction) + logging.debug("direction=" + direction) - if GET_parameters.has_key( 'Position'): + if "Position" in GET_parameters: position = GET_parameters.getfirst("Position", "") else: position = 0 - logging.debug( "position=" + str(position)) + logging.debug("position=" + str(position)) - if GET_parameters.has_key( 'Directory'): + if "Directory" in GET_parameters: directory = GET_parameters.getfirst("Directory", "") ##directory = GET_parameters['Directory'].value else: directory = "" - logging.debug( "directory=" + directory) + logging.debug("directory=" + directory) - if GET_parameters.has_key( 'URL'): + if "URL" in GET_parameters: URL = GET_parameters.getfirst("URL", "") - #URL = GET_parameters['URL'].value + # URL = GET_parameters['URL'].value else: URL = "" - #Opening and reading directoy + # Opening and reading directory count = 0 lines_list = [] @@ -162,187 +180,316 @@ def main(): ## Build result & expected directories/URLs current_directory = os.getcwd() - current_directory = current_directory.replace('\\', '/') - logging.debug(function_name + "current directory="+current_directory) - actual_directory = directory + '/result/' - expected_directory = directory + '/expected/' + current_directory = current_directory.replace("\\", "/") + logging.debug(function_name + "current directory=" + current_directory) + actual_directory = directory + "/result/" + expected_directory = directory + "/expected/" - actual_URL = URL+ "/result/" - expected_URL = URL+ "/expected/" + actual_URL = URL + "/result/" + expected_URL = URL + "/expected/" - logging.debug( function_name + "directory="+directory) - logging.debug( function_name + "actual directory="+actual_directory) - logging.debug( function_name + "expected directory="+expected_directory) - logging.debug( function_name + "actual URL="+actual_URL) - logging.debug( function_name + "expected URL="+expected_URL) + logging.debug(function_name + "directory=" + directory) + logging.debug(function_name + "actual directory=" + actual_directory) + logging.debug(function_name + "expected directory=" + expected_directory) + logging.debug(function_name + "actual URL=" + actual_URL) + logging.debug(function_name + "expected URL=" + expected_URL) - - - if os.path.isdir(current_directory): - for file in os.listdir(actual_directory): - if string.find(file, '.aux') != -1: - continue + for file in os.listdir(actual_directory): + if string.find(file, ".aux") != -1: + continue else: - logging.debug( function_name + "filename: " + file) - line = file + ' ' - line += actual_directory + file + ' ' - line += actual_URL + file + ' ' - line += expected_directory + file + ' ' - line += expected_URL + file - - #logging.debug( function_name + lines) + logging.debug(function_name + "filename: " + file) + line = file + " " + line += actual_directory + file + " " + line += actual_URL + file + " " + line += expected_directory + file + " " + line += expected_URL + file + + # logging.debug( function_name + lines) lines_list.append(line) - #logging.debug( function_name + str(lines_list)) + # logging.debug( function_name + str(lines_list)) count = len(lines_list) - #Control "NEXT" and "PREVIOUS" buttons appearance - if direction == "NEXT": - prev_button = "PREV" - if ( int(position) + results_per_page) < count: - next_button = "NEXT" - + # Control "NEXT" and "PREVIOUS" buttons appearance + if direction == "NEXT": + prev_button = ( + 'PREV" + ) + if (int(position) + results_per_page) < count: + next_button = ( + 'NEXT" + ) + else: next_button = "NEXT" - elif direction == "PREV": - next_button = "NEXT" - - if ( int(position) - results_per_page) >= 0: - prev_button = "PREV" + elif direction == "PREV": + next_button = ( + 'NEXT" + ) + + if (int(position) - results_per_page) >= 0: + prev_button = ( + 'PREV" + ) else: prev_button = "PREV" else: prev_button = "PREV" - if ( int(position) + results_per_page) < count: - next_button = "NEXT" + if (int(position) + results_per_page) < count: + next_button = ( + 'NEXT" + ) else: next_button = "NEXT" - logging.debug( function_name + "direction="+direction) - logging.debug( function_name + "count="+str(count)) - logging.debug( function_name + "pos="+str(position)) - logging.debug( function_name + "number of results="+str(results_per_page)) - + logging.debug(function_name + "direction=" + direction) + logging.debug(function_name + "count=" + str(count)) + logging.debug(function_name + "pos=" + str(position)) + logging.debug(function_name + "number of results=" + str(results_per_page)) - #Prepare result output + # Prepare result output i = int(position) parameters_list_list = [] output_list = [] diff_output_list_list = [] - #parameters_list_list value - #File name Actual dir Actual URL Expected dir Expected URL + # parameters_list_list value + # File name Actual dir Actual URL Expected dir Expected URL # [0] [1] [2] [3] [4] - while i < (results_per_page + int(position) ) and i\n") + print( + "\n" + ) - i =0 + i = 0 for parameters_list in parameters_list_list: - #Process xml, dat or html files - if string.find(parameters_list[0], '.xml') != -1 or string.find(parameters_list[0], '.dat') != -1 or string.find(parameters_list[0], '.html') != -1 or string.find(parameters_list[0], '.js') != -1: + # Process xml, dat or html files + if ( + string.find(parameters_list[0], ".xml") != -1 + or string.find(parameters_list[0], ".dat") != -1 + or string.find(parameters_list[0], ".html") != -1 + or string.find(parameters_list[0], ".js") != -1 + ): logging.debug(function_name + str(parameters_list[0])) - print("" + ) + + elif ( + string.find(parameters_list[0], ".tif") != -1 + or string.find(parameters_list[0], ".png") != -1 + ): + # Process tiff, png files logging.debug(function_name + str(parameters_list[0])) - - #Is it a tiff file: II or MM? - #Test with the file in the actual directory: parameters_list[1] + # Is it a tiff file: II or MM? + # Test with the file in the actual directory: parameters_list[1] file_header = open(parameters_list[1], "rb").readline(16) - if ('\x49\x49\x2A\x00' in file_header \ - or '\x49\x49\x00\x2A' in file_header): - - logging.debug(function_name + 'geotiff') + if "\x49\x49\x2A\x00" in file_header or "\x49\x49\x00\x2A" in file_header: + + logging.debug(function_name + "geotiff") expected_PNG_image_URL = tiff2png(parameters_list[3]) actual_PNG_image_URL = tiff2png(parameters_list[1]) - #expected_PNG_image_URL = parameters_list[4] - #actual_PNG_image_URL = parameters_list[2] - print("") + # expected_PNG_image_URL = parameters_list[4] + # actual_PNG_image_URL = parameters_list[2] + print( + "" + ) else: expected_PNG_image_URL = parameters_list[4] actual_PNG_image_URL = parameters_list[2] - print("") - - - #Display switching buttons - print("\n") + print( + "" + ) + + # Display switching buttons + print( + '\n' + ) else: continue - i+=1 #End of for loop + i += 1 # End of for loop - print("\n") + print( + "\n" + ) - print(""" + print( + """
" + prev_button + "" + next_button + "
" + + prev_button + + "" + + next_button + + "
\n") + print( + "") - - - elif string.find(parameters_list[0], '.tif') != -1 or string.find(parameters_list[0], '.png') != -1: - #Process tiff, png files + result_fp = open(parameters_list[1], "r") + result_list = result_fp.readlines() + + output_list = difflib.unified_diff( + expected_list, result_list, "Expected", "Result" + ) + diff_output_list_list.append("".join(output_list)) + + # logging.debug(function_name + str(diff_output_list_list[len(diff_output_list_list) - 1])) + + print( + "
Diff output expected vs actual ---File: " + parameters_list[0] + "
\n" + ) - - expected_fp = open(parameters_list[3], 'r') + expected_fp = open(parameters_list[3], "r") expected_list = expected_fp.readlines() - result_fp = open(parameters_list[1], 'r') - result_list = result_fp.readlines() - - output_list = difflib.unified_diff(expected_list, result_list, "Expected", "Result") - diff_output_list_list.append(''.join(output_list)) - - #logging.debug(function_name + str(diff_output_list_list[len(diff_output_list_list) - 1])) - - print("
Diff output expected vs actual ---File: " + + parameters_list[0] + + "
File:" + parameters_list[0] + "GeoTiff converted to Png.
File:" + + parameters_list[0] + + "GeoTiff converted to Png.
File:" + parameters_list[0] + "
\n") - - #Display images - print("
ExpectedActual
Start switchingStop switchingimage:
File:" + + parameters_list[0] + + "
\n' + ) + + # Display images + print( + '
ExpectedActual
Start switchingStop switchingimage:
" + prev_button + "" + next_button + "
" + + prev_button + + "" + + next_button + + "

- """) + """ + ) + ## Convert GeoTiff to PNG file in order to be able to see the image in the ## browser def tiff2png(tiff_file): function_name = "tiff2png: " - global python_logging_file, logging_flag, config ## Checking if path is found if not os.path.isdir(os.path.dirname(python_logging_file)): print("Content-type: text/html") print("") - print("
" + function_name + ":The logging file: " + python_logging_file + " does not exist; check the configuration file
") - sys.exit(function_name + ":The logging file: " + python_logging_file + "does not exist. Check the configuration file.") - - logging.basicConfig(level=logging.DEBUG, - format='%(asctime)s %(levelname)s %(message)s', - filename=python_logging_file, - filemode='a') + print( + "
"
+            + function_name
+            + ":The logging file: "
+            + python_logging_file
+            + " does not exist; check the configuration file
" + ) + sys.exit( + function_name + + ":The logging file: " + + python_logging_file + + "does not exist. Check the configuration file." + ) + + logging.basicConfig( + level=logging.DEBUG, + format="%(asctime)s %(levelname)s %(message)s", + filename=python_logging_file, + filemode="a", + ) if logging_flag == False: - logging.disable('debug') - + logging.disable("debug") out_file = config.get("Logging", "ShellOutputFile") ## Checking if path is found if not os.path.isdir(os.path.dirname(out_file)): print("Content-type: text/html") print() - print("
" + function_name + ":The output log file: " + out_file + " does not exist; check the configuration file
") - sys.exit(function_name + ":The output log file: " + out_file + " does not exist. Check the configuration file.") + print( + "
"
+            + function_name
+            + ":The output log file: "
+            + out_file
+            + " does not exist; check the configuration file
" + ) + sys.exit( + function_name + + ":The output log file: " + + out_file + + " does not exist. Check the configuration file." + ) out_fp = open(out_file, "a") @@ -351,8 +498,19 @@ def tiff2png(tiff_file): if not os.path.isdir(os.path.dirname(err_file)): print("Content-type: text/html") print("") - print("
" + function_name + ":The error log file: " + err_file + " does not exist; check the configuration file
") - sys.exit(function_name + ":The error log file: " + err_file + " does not exist. Check the configuration file.") + print( + "
"
+            + function_name
+            + ":The error log file: "
+            + err_file
+            + " does not exist; check the configuration file
" + ) + sys.exit( + function_name + + ":The error log file: " + + err_file + + " does not exist. Check the configuration file." + ) err_fp = open(err_file, "a") @@ -361,18 +519,38 @@ def tiff2png(tiff_file): if not os.path.isdir(tmp_path): print("Content-type: text/html") print("") - print("
" + function_name + ":The tmp directory: " + tmp_path + " does not exist; check the configuration file
") - sys.exit(function_name + ":The tmp directory: " + tmp_path + " does not exist. Check the configuration file.") + print( + "
"
+            + function_name
+            + ":The tmp directory: "
+            + tmp_path
+            + " does not exist; check the configuration file
" + ) + sys.exit( + function_name + + ":The tmp directory: " + + tmp_path + + " does not exist. Check the configuration file." + ) tmp_web = config.get("Applications", "TmpWeb") ## Checking if path is found if not os.path.isdir(tmp_web): print("Content-type: text/html") print("") - print("
" + function_name + ":The tmp Web URL: " + tmp_web + " does not exist; check the configuration file
") - sys.exit(function_name + ":The tmp Web URL: " + tmp_path + " does not exist. Check the configuration file.") - - + print( + "
"
+            + function_name
+            + ":The tmp Web URL: "
+            + tmp_web
+            + " does not exist; check the configuration file
" + ) + sys.exit( + function_name + + ":The tmp Web URL: " + + tmp_path + + " does not exist. Check the configuration file." + ) dirname = os.path.dirname(tiff_file) logging.debug(function_name + "dirname=" + dirname) @@ -382,36 +560,47 @@ def tiff2png(tiff_file): basename = os.path.basename(tiff_file) imagename_list = os.path.splitext(basename) - filename = imagename_list[0] + '_msautotest_' + sub_path + filename = imagename_list[0] + "_msautotest_" + sub_path logging.debug(function_name + "filename=" + filename) - PNG_file = tmp_path + filename + '.png' - PNG_URL = tmp_web + filename + '.png' + PNG_file = tmp_path + filename + ".png" + PNG_URL = tmp_web + filename + ".png" logging.debug(function_name + "PNG_URL=" + PNG_URL) image_converter = config.get("Applications", "ImageConverterCmd") ## Command has parameters so we need to get the executable only - image_converter_parameters_list = image_converter.split(' ') + image_converter_parameters_list = image_converter.split(" ") ## Checking if the path exist if not os.path.isdir(os.path.dirname(image_converter_parameters_list[0])): print("Content-type: text/html") print("") - print("
" + function_name + ":The image converter command: " + image_converter_parameters_list[0] + " does not exist; check the configuration file
") - sys.exit(function_name + ":The image converter command: " + image_converter_parameters_list[0] + "does not exist. Check the configuration file.") + print( + "
"
+            + function_name
+            + ":The image converter command: "
+            + image_converter_parameters_list[0]
+            + " does not exist; check the configuration file
" + ) + sys.exit( + function_name + + ":The image converter command: " + + image_converter_parameters_list[0] + + "does not exist. Check the configuration file." + ) ## Executing conversion - cmd = image_converter + " png " + tiff_file + ' ' + PNG_file + cmd = image_converter + " png " + tiff_file + " " + PNG_file logging.debug(function_name + "cmd=" + cmd) - subprocess.call(cmd, shell=True, stdout=out_fp, stderr=err_fp ) + subprocess.call(cmd, shell=True, stdout=out_fp, stderr=err_fp) + + return PNG_URL - return(PNG_URL) ## Remove temporary PNG images file def rmTmpPngImages(): - global config function_name = "rmTmpPngImages: " tmp_path = config.get("Applications", "TmpDir") @@ -419,14 +608,26 @@ def rmTmpPngImages(): if not os.path.isdir(tmp_path): print("Content-type: text/html") print("") - print("
" + function_name + ":The logging file: " + tmp_path + " does not exist; check the configuration file
") - sys.exit(function_name + ":The logging file: " + tmp_path + " does not exist. Check the configuration file.") + print( + "
"
+            + function_name
+            + ":The logging file: "
+            + tmp_path
+            + " does not exist; check the configuration file
" + ) + sys.exit( + function_name + + ":The logging file: " + + tmp_path + + " does not exist. Check the configuration file." + ) for file in os.listdir(tmp_path): filename = tmp_path + file - if string.find(filename, 'msautotest') != -1: - logging.debug( function_name + "filename to remove: " + filename) + if string.find(filename, "msautotest") != -1: + logging.debug(function_name + "filename to remove: " + filename) os.remove(filename) + if __name__ == "__main__": main() diff --git a/msautotest/pymod/mstestlib.py b/msautotest/pymod/mstestlib.py index 3caf04e9f4..10f4d265ef 100644 --- a/msautotest/pymod/mstestlib.py +++ b/msautotest/pymod/mstestlib.py @@ -8,17 +8,17 @@ # ############################################################################### # Copyright (c) 2002, Frank Warmerdam -# +# # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: -# +# # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. -# +# # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL @@ -28,21 +28,24 @@ # DEALINGS IN THE SOFTWARE. ############################################################################### -import sys import os -import pytest import string +import sys + +import pytest from testlib import compare_result + try: import xmlvalidate + xmlvalidate_ok = True -except: - print('Cannot import xmlvalidate. Likely lxml missing') +except Exception: + print("Cannot import xmlvalidate. Likely lxml missing") xmlvalidate_ok = False pass have_pdiff = None -shp2img = 'shp2img' +map2img = "map2img" keep_pass = False quiet = False validate_xml = True @@ -51,15 +54,16 @@ ############################################################################### # get_mapfile_list() -def get_mapfile_list( dirname ): - # scan the current directory for mapfiles. +def get_mapfile_list(dirname): + + # scan the current directory for mapfiles. files = os.listdir(dirname) map_files = [] for file in files: - if file[-4:] == '.map': - map_files.append( file ) + if file[-4:] == ".map": + map_files.append(file) return map_files @@ -68,14 +72,15 @@ def get_mapfile_list( dirname ): # compare_version() # Returns 1 if a > b, 0 if a == b, -1 if a < b + def compare_version(version_a, version_b): - a = version_a.split('.') - b = version_b.split('.') + a = version_a.split(".") + b = version_b.split(".") while len(a) < 3: - a += [ '0' ] + a += ["0"] while len(b) < 3: - b += [ '0' ] + b += ["0"] a_x, a_y, a_z = int(a[0]), int(a[1]), int(a[2]) b_x, b_y, b_z = int(b[0]), int(b[1]), int(b[2]) if a_x > b_x: @@ -92,127 +97,163 @@ def compare_version(version_a, version_b): return -1 return 0 + ############################################################################### # has_requires() -def has_requires( version_info, gdal_version, requires_list ): + +def has_requires(version_info, gdal_version, requires_list): for item in requires_list: - if item.startswith('GDAL>='): + if item.startswith("GDAL>="): if gdal_version is None: return 0 - if compare_version(gdal_version, item[len('GDAL>='):]) < 0: + if compare_version(gdal_version, item[len("GDAL>=") :]) < 0: return 0 - elif item.startswith('GDAL=='): + elif item.startswith("GDAL=="): if gdal_version is None: return 0 - if compare_version(gdal_version, item[len('GDAL=='):]) != 0: + if compare_version(gdal_version, item[len("GDAL==") :]) != 0: return 0 - elif version_info.find( item ) == -1: + elif version_info.find(item) == -1: return 0 return 1 + ############################################################################### # read_test_directives() -def read_test_directives( mapfile_name ): + +def read_test_directives(mapfile_name): runparms_list = [] require_list = [] - - lines = open(mapfile_name).readlines() + + from sys import version_info + + if version_info >= (3, 0, 0): + lines = open(mapfile_name, encoding="utf8").readlines() + else: + lines = open(mapfile_name).readlines() + skip_whole_file = False for line in lines: - req_off = line.find( 'REQUIRES:' ) + req_off = line.find("REQUIRES:") if req_off != -1: - items = line[req_off+9:].split( ) + items = line[req_off + 9 :].split() for item in items: - require_list.append( item ) - - run_off = line.find( 'RUN_PARMS:' ) + require_list.append(item) + + run_off = line.find("RUN_PARMS:") if run_off != -1: - items = line[run_off+10:].split( None, 1 ) + items = line[run_off + 10 :].split(None, 1) if len(items) == 2: - runparms_list.append( (items[0], items[1]) ) + runparms_list.append((items[0], items[1])) elif len(items) == 1: - runparms_list.append( (items[0], - '[SHP2IMG] [RENDERER] -m [MAPFILE] -o [RESULT]') ) - - if len(runparms_list) == 0: - runparms_list.append( (mapfile_name[:-4] + '.png', - '[SHP2IMG] [RENDERER] -m [MAPFILE] -o [RESULT]') ) + runparms_list.append( + (items[0], "[MAP2IMG] [RENDERER] -m [MAPFILE] -o [RESULT]") + ) + + if "SKIP_WHOLE_FILE:" in line: + skip_whole_file = True + + if len(runparms_list) == 0 and not skip_whole_file: + runparms_list.append( + ( + mapfile_name[:-4] + ".png", + "[MAP2IMG] [RENDERER] -m [MAPFILE] -o [RESULT]", + ) + ) return (runparms_list, require_list) - + ############################################################################### # Strip Content-type and other http headers off this file. -def demime_file( filename ): - data = open(filename,'rb').read() +def demime_file(filename): + + data = open(filename, "rb").read() from sys import version_info - if version_info >= (3,0,0): - data = str(data, 'iso-8859-1') + + if version_info >= (3, 0, 0): + data = str(data, "iso-8859-1") + + # remove any double CR which will crash the following code + extension = os.path.splitext(filename)[1] + if extension in (".xml", ".json"): + data = data.replace("\r\r", "\r") offset = -1 - for i in range(len(data)-1): - if data[i] == '\r' and data[i+1] == '\n' and data[i+2] == '\r' and data[i+3] == '\n': + for i in range(len(data) - 1): + if ( + data[i] == "\r" + and data[i + 1] == "\n" + and data[i + 2] == "\r" + and data[i + 3] == "\n" + ): offset = 4 - elif data[i] == '\n' and data[i+1] == '\n': + elif data[i] == "\n" and data[i + 1] == "\n": offset = 2 if offset != -1: - if version_info >= (3,0,0): - open(filename,'wb').write(bytes(data[i+offset:], 'iso-8859-1')) + if version_info >= (3, 0, 0): + open(filename, "wb").write(bytes(data[i + offset :], "iso-8859-1")) else: - open(filename,'wb').write(data[i+offset:]) + open(filename, "wb").write(data[i + offset :]) return return + ############################################################################### # Strip MapServer version comment from file. -def deversion_file( filename ): - data = open(filename,'rb').read() +def deversion_file(filename): + + data = open(filename, "rb").read() from sys import version_info - if version_info >= (3,0,0): - data = str(data, 'iso-8859-1') - start = data.find( '': - end = end+1 + while end < length - 5 and data[end : end + 3] != "-->": + end = end + 1 - if data[end:end+3] != '-->': + if data[end : end + 3] != "-->": return - new_data = data[:start-1] + data[end+4:] - if version_info >= (3,0,0): - open(filename,'wb').write(bytes(new_data, 'iso-8859-1')) + new_data = data[: start - 1] + data[end + 4 :] + if version_info >= (3, 0, 0): + open(filename, "wb").write(bytes(new_data, "iso-8859-1")) else: - open(filename,'wb').write(new_data) + open(filename, "wb").write(new_data) return + ############################################################################### # Strip GDAL version from file. -def degdalversion_file( filename ): - data = open(filename,'rb').read() +def degdalversion_file(filename): + + data = open(filename, "rb").read() from sys import version_info - if version_info >= (3,0,0): - data = str(data, 'iso-8859-1') + + if version_info >= (3, 0, 0): + data = str(data, "iso-8859-1") # Remove GDAL version from GPX file start = data.find('creator="GDAL ') @@ -226,29 +267,32 @@ def degdalversion_file( filename ): if data[end] != '"': return - data = data[:start-1] + data[end+1:] + data = data[: start - 1] + data[end + 1 :] - if version_info >= (3,0,0): - open(filename,'wb').write(bytes(data, 'iso-8859-1')) + if version_info >= (3, 0, 0): + open(filename, "wb").write(bytes(data, "iso-8859-1")) else: - open(filename,'wb').write(data) + open(filename, "wb").write(data) return + ############################################################################### # white out timestamp -def detimestamp_file( filename ): - data = open(filename,'rb').read() +def detimestamp_file(filename): + + data = open(filename, "rb").read() has_found_timestamp = False from sys import version_info - if version_info >= (3,0,0): - data = str(data, 'iso-8859-1') + + if version_info >= (3, 0, 0): + data = str(data, "iso-8859-1") start_find_idx = 0 while True: - start = data[start_find_idx:].find( 'timeStamp="' ) + start = data[start_find_idx:].find('timeStamp="') if start == -1: break start = start + start_find_idx @@ -256,34 +300,37 @@ def detimestamp_file( filename ): start = start + 11 end = start - while data[end+1] != '"': + while data[end + 1] != '"': end = end + 1 - data = data[:start] + data[end+1:] + data = data[:start] + data[end + 1 :] start_find_idx = start + 11 if not has_found_timestamp: return - if version_info >= (3,0,0): - open(filename,'wb').write(bytes(data, 'iso-8859-1')) + if version_info >= (3, 0, 0): + open(filename, "wb").write(bytes(data, "iso-8859-1")) else: - open(filename,'wb').write(data) + open(filename, "wb").write(data) return + ############################################################################### # Keep version="" string -def extract_service_version_file( filename ): - data = open(filename,'rb').read() +def extract_service_version_file(filename): + + data = open(filename, "rb").read() from sys import version_info - if version_info >= (3,0,0): - data = str(data, 'iso-8859-1') + + if version_info >= (3, 0, 0): + data = str(data, "iso-8859-1") # Remove GDAL version from GPX file - start = data.find('WFS_Capabilities') + start = data.find("WFS_Capabilities") if start == -1: return data = data[start:] @@ -293,224 +340,218 @@ def extract_service_version_file( filename ): end = start + len('version="') length = len(data) - result = '' + result = "" while end < length and data[end] != '"': result = result + data[end] end = end + 1 if data[end] != '"': return - if version_info >= (3,0,0): - open(filename,'wb').write(bytes(result, 'iso-8859-1')) + if version_info >= (3, 0, 0): + open(filename, "wb").write(bytes(result, "iso-8859-1")) else: - open(filename,'wb').write(result) + open(filename, "wb").write(result) return - + + ############################################################################### # Collect all the [STRIP:] directives from a command string and remove them # from the command string. -def collect_strip_requests( command ): + +def collect_strip_requests(command): strip_items = [] - while command.find('[STRIP:') != -1: + while command.find("[STRIP:") != -1: - dir_start = command.find('[STRIP:') + dir_start = command.find("[STRIP:") pat_start = dir_start + 7 - pat_end = pat_start+1 + pat_end = pat_start + 1 - while command[pat_end] != ']': - pat_end = pat_end+1 + while command[pat_end] != "]": + pat_end = pat_end + 1 - strip_items.append( command[pat_start:pat_end] ) + strip_items.append(command[pat_start:pat_end]) - command = command[:dir_start] + command[pat_end+1:] + command = command[:dir_start] + command[pat_end + 1 :] return (command, strip_items) - + + ############################################################################### # Strip lines matching substrings. -def apply_strip_items_file( filename, strip_items ): + +def apply_strip_items_file(filename, strip_items): if len(strip_items) == 0: return - + from sys import version_info - data_lines = open(filename,'rb').readlines() - out_data = '' + data_lines = open(filename, "rb").readlines() + out_data = "" for i in range(len(data_lines)): data_line = data_lines[i] - if version_info >= (3,0,0): - data_line = str(data_line, 'iso-8859-1') + if version_info >= (3, 0, 0): + data_line = str(data_line, "iso-8859-1") discard = 0 for item in strip_items: - if data_line.find( item ) != -1: + if data_line.find(item) != -1: discard = 1 if discard == 0: out_data += data_line else: - out_data += '[stripped line matching "%s"]\n' % item + out_data += '[stripped line matching "%s"]\n' % item - if version_info >= (3,0,0): - open(filename,'wb').write(bytes(out_data, 'iso-8859-1')) + if version_info >= (3, 0, 0): + open(filename, "wb").write(bytes(out_data, "iso-8859-1")) else: - open(filename,'wb').write(out_data) + open(filename, "wb").write(out_data) return + ############################################################################### # Do windows exponential conversion on the file (e+0nn to e+nn). -def fixexponent_file( filename ): - data = open(filename,'rb').read() +def fixexponent_file(filename): + + data = open(filename, "rb").read() from sys import version_info - if version_info >= (3,0,0): - data = str(data, 'iso-8859-1') + + if version_info >= (3, 0, 0): + data = str(data, "iso-8859-1") orig_data = data - start = data.find( 'e+0' ) + start = data.find("e+0") while start != -1: - if data[start+3] in string.digits and data[start+4] in string.digits \ - and data[start+5] == '"': - data = data[:start+2] + data[start+3:] - start = data.find( 'e+0', start+3 ) + if ( + data[start + 3] in string.digits + and data[start + 4] in string.digits + and data[start + 5] == '"' + ): + data = data[: start + 2] + data[start + 3 :] + start = data.find("e+0", start + 3) if data != orig_data: - if version_info >= (3,0,0): - open(filename,'wb').write(bytes(data, 'iso-8859-1')) + if version_info >= (3, 0, 0): + open(filename, "wb").write(bytes(data, "iso-8859-1")) else: - open(filename,'wb').write(data) + open(filename, "wb").write(data) return -############################################################################### -# Do windows number of decimal truncation. - -def truncate_one_decimal( filename ): - import re - - data = open(filename,'rb').read() - - from sys import version_info - if version_info >= (3,0,0): - data = str(data, 'iso-8859-1') - - numbers_found = re.compile('[0-9]+\.[0-9]{6,24}', re.M) - - start = 0 - new_data = '' - for number in numbers_found.finditer(data): - end = number.end() - 1 - new_data = new_data + data[start:end] - start = number.end() - - if new_data != '': - new_data = new_data + data[start:] - - if new_data != '' and new_data != data: - if version_info >= (3,0,0): - open(filename,'wb').write(bytes(new_data, 'iso-8859-1')) - else: - open(filename,'wb').write(new_data) - - return ############################################################################### # Replace CR+LF by CR -def crlf( filename ): - + +def crlf(filename): + try: - os.stat( filename ) + os.stat(filename) except OSError: return data = open(filename, "rb").read() from sys import version_info - if version_info >= (3,0,0): - data = str(data, 'iso-8859-1') - #This is a binary file - if '\0' in data: + if version_info >= (3, 0, 0): + data = str(data, "iso-8859-1") + + # This is a binary file + if "\0" in data: return - + newdata = data.replace("\r\n", "\n") if newdata != data: f = open(filename, "wb") - if version_info >= (3,0,0): - f.write(bytes(newdata, 'iso-8859-1')) + if version_info >= (3, 0, 0): + f.write(bytes(newdata, "iso-8859-1")) else: f.write(newdata) f.close() + ############################################################################### def get_gdal_version(): # First try with GDAL Python bindings, otherwise with gdalinfo binary try: from osgeo import gdal - gdal_version = gdal.VersionInfo('VERSION_INFO') - except: - gdal_version = os.popen( 'gdalinfo --version').read() - - # Parse something like "GDAL x.y.zdev, released..." to extract "x.y.z" - if gdal_version.startswith('GDAL '): - gdal_version = gdal_version[len('GDAL '):] - pos = gdal_version.find('dev') - if pos >= 0: - return gdal_version[0:pos] - pos = gdal_version.find(',') + + gdal_version = gdal.VersionInfo("VERSION_INFO") + except Exception: + gdal_version = os.popen("gdalinfo --version").read() + + # Parse GDAL version formats to extract "x.y.z" e.g. + # 'GDAL x.y.zdev' + # 'GDAL 3.11.3 "Eganville", released 2025/07/12' + # 'GDAL 3.11.3 Eganville' + # 'GDAL 3.x.y, released' + if gdal_version.startswith("GDAL "): + gdal_version = gdal_version[len("GDAL ") :] + dev_pos = gdal_version.find("dev") + comma_pos = gdal_version.find(",") + space_pos = gdal_version.find(" ") + positions = [p for p in (dev_pos, comma_pos, space_pos) if p != -1] + pos = min(positions) if positions else -1 if pos >= 0: return gdal_version[0:pos] return None + ############################################################################### + def get_pytests(dirname): ########################################################################### # Create results directory if it does not already exist. if not os.path.exists(os.path.join(dirname, "result")): - os.mkdir(os.path.join(dirname, "result")) + os.mkdir(os.path.join(dirname, "result")) ########################################################################### # Get version info. - version_info = os.popen( shp2img + ' -v' ).read() - #print('version = %s' % version_info) + version_info = os.popen(map2img + " -v").read() + # print('version = %s' % version_info) gdal_version = get_gdal_version() - #print('GDAL version = %s' % gdal_version) + # print('GDAL version = %s' % gdal_version) ########################################################################### # Must we and can we validate XML stuff ? if validate_xml and xmlvalidate_ok: - if xmlvalidate.has_local_ogc_schemas('SCHEMAS_OPENGIS_NET'): + if xmlvalidate.has_local_ogc_schemas("SCHEMAS_OPENGIS_NET"): global ogc_schemas_location - ogc_schemas_location = 'SCHEMAS_OPENGIS_NET' + ogc_schemas_location = "SCHEMAS_OPENGIS_NET" else: - print('Cannot validate XML because SCHEMAS_OPENGIS_NET not found. Run "python ../pymod/xmlvalidate.py -download_ogc_schemas" from msautotest/wxs') + print( + 'Cannot validate XML because SCHEMAS_OPENGIS_NET not found. Run "python ../pymod/xmlvalidate.py -download_ogc_schemas" from msautotest/wxs' + ) tests = [] for map in get_mapfile_list(dirname): - runparms_list, requires_list = read_test_directives( os.path.join(dirname, map) ) + runparms_list, requires_list = read_test_directives(os.path.join(dirname, map)) marks = [] - if not has_requires( version_info, gdal_version, requires_list ): - print('%s: missing some or all of required components, skip.'%(map)) + if not has_requires(version_info, gdal_version, requires_list): + print("%s: missing some or all of required components, skip." % (map)) marks.append(pytest.mark.skip) for out_file, command in runparms_list: out_file = os.path.basename(out_file) - id = map[0:-4]+'_'+out_file.replace('.','_') - param = pytest.param(os.path.join(dirname, map), out_file, command, id=id,marks=marks) + id = map[0:-4] + "_" + out_file.replace(".", "_") + param = pytest.param( + os.path.join(dirname, map), out_file, command, id=id, marks=marks + ) tests.append(param) return tests @@ -527,203 +568,234 @@ def _run(map, out_file, command, extra_args): verbose = extra_args.getoption("verbose") >= 2 renderer = extra_args.getoption("renderer") if renderer: - (resultbase,resultext) = os.path.splitext(out_file) - if renderer in ( 'pdf', 'svg', 'gif'): - out_file = "%s.%s"%(resultbase,renderer) + (resultbase, resultext) = os.path.splitext(out_file) + if renderer in ("pdf", "svg", "gif"): + out_file = "%s.%s" % (resultbase, renderer) else: - out_file = "%s.%s%s"%(resultbase,renderer,resultext) + out_file = "%s.%s%s" % (resultbase, renderer, resultext) - if command.find('[RESULT_DEMIME_DEVERSION]') != -1: + if command.find("[RESULT_DEMIME_DEVERSION]") != -1: demime = 1 deversion = 1 else: - if command.find('[RESULT_DEMIME]') != -1: + if command.find("[RESULT_DEMIME]") != -1: demime = 1 else: demime = 0 - if command.find('[RESULT_DEVERSION]') != -1: + if command.find("[RESULT_DEVERSION]") != -1: deversion = 1 else: deversion = 0 - if command.find('[EXTRACT_SERVICE_VERSION]') != -1: + if command.find("[EXTRACT_SERVICE_VERSION]") != -1: extractserviceversion = 1 else: extractserviceversion = 0 - command = command.replace('[RESULT]', 'result/'+out_file ) - command = command.replace('[RESULT_DEMIME]', 'result/'+out_file ) - command = command.replace('[RESULT_DEVERSION]', 'result/'+out_file ) - command = command.replace('[RESULT_DEMIME_DEVERSION]', 'result/'+out_file ) - command = command.replace('[EXTRACT_SERVICE_VERSION]', 'result/'+out_file ) - command = command.replace('[MAPFILE]', os.path.basename(map) ) - command = command.replace('[SHP2IMG]', shp2img ) + command = command.replace("[RESULT]", "result/" + out_file) + command = command.replace("[RESULT_DEMIME]", "result/" + out_file) + command = command.replace("[RESULT_DEVERSION]", "result/" + out_file) + command = command.replace("[RESULT_DEMIME_DEVERSION]", "result/" + out_file) + command = command.replace("[EXTRACT_SERVICE_VERSION]", "result/" + out_file) + command = command.replace("[MAPFILE]", os.path.basename(map)) + command = command.replace("[MAP2IMG]", map2img) if renderer is not None: - command = command.replace('[RENDERER]', '-i '+renderer ) + command = command.replace("[RENDERER]", "-i " + renderer) else: - command = command.replace('[RENDERER]', '' ) + command = command.replace("[RENDERER]", "") + + os.environ["MS_PDF_CREATION_DATE"] = "dummy date" - #support for environment variable of type [ENV foo=bar] - begin = command.find('[ENV') - envirkey = '' + # support for environment variable of type [ENV foo=bar] + begin = command.find("[ENV") + envirkey = "" if begin != -1: - end = command[begin:].find(']') - equal = command[begin:].find('=') - #print("equal is %d"%equal) - envirkey = command[begin+len('[ENV '):begin+equal] - envirval = command[equal+1:end] + end = command[begin:].find("]") + equal = command[begin:].find("=") + # print("equal is %d"%equal) + envirkey = command[begin + len("[ENV ") : begin + equal] + envirval = command[equal + 1 : end] os.environ[envirkey] = envirval tmp = command - command = tmp[:begin] + tmp[end+1:] - #print('added environment variable (%s)=(%s); new command:%s' % (envirkey,envirval,command)) + command = tmp[:begin] + tmp[end + 1 :] + # print('added environment variable (%s)=(%s); new command:%s' % (envirkey,envirval,command)) # support for POST request method - begin = command.find('[POST]') - end = command.find('[/POST]') - post = '' + begin = command.find("[POST]") + end = command.find("[/POST]") + post = "" if begin != -1 and end != -1 and begin < end: - post = command[begin+len('[POST]'):end] + post = command[begin + len("[POST]") : end] tmp = command - post = post.replace( '"', '\'') + post = post.replace('"', "'") if valgrind: - command = tmp[:begin] + tmp[end+len('[/POST]'):] + command = tmp[:begin] + tmp[end + len("[/POST]") :] else: - command = 'echo "' + post + '" | ' + tmp[:begin] + tmp[end+len('[/POST]'):] - os.environ['CONTENT_LENGTH'] = str(len(post)) - os.environ['REQUEST_METHOD'] = "POST" - os.environ['MS_MAPFILE'] = map - if post[0] == '<': - os.environ['CONTENT_TYPE'] = 'text/xml' + command = ( + 'echo "' + post + '" | ' + tmp[:begin] + tmp[end + len("[/POST]") :] + ) + os.environ["CONTENT_LENGTH"] = str(len(post)) + os.environ["REQUEST_METHOD"] = "POST" + os.environ["MS_MAPFILE"] = map + if post[0] == "<": + os.environ["CONTENT_TYPE"] = "text/xml" if ogc_schemas_location is not None: - xmlvalidate.validate(post, ogc_schemas_location = ogc_schemas_location) + xmlvalidate.validate(post, ogc_schemas_location=ogc_schemas_location) else: - os.environ['CONTENT_TYPE'] = 'application/x-www-form-urlencoded' + os.environ["CONTENT_TYPE"] = "application/x-www-form-urlencoded" - command = command.replace('[MAPSERV]', 'mapserv' ) - command = command.replace('[LEGEND]', 'legend' ) - command = command.replace('[SCALEBAR]', 'scalebar' ) + command = command.replace("[MAPSERV]", "mapserv") + command = command.replace("[LEGEND]", "legend") + command = command.replace("[SCALEBAR]", "scalebar") + + (command, strip_items) = collect_strip_requests(command) + + # option to skip asan log output capturing for tests wanting to capture stderr in result file + asan_skip_log = False + if command.find("[ASAN_SKIP_LOG]") != -1: + asan_skip_log = True + command = command.replace("[ASAN_SKIP_LOG]", "") - (command, strip_items) = collect_strip_requests( command ) - if valgrind: - valgrind_log = 'result/%s.txt'%(out_file+".vgrind.txt") + valgrind_log = "result/%s.txt" % (out_file + ".vgrind.txt") command = command.strip() - if post == '': - command = 'valgrind --tool=memcheck -q --suppressions=../valgrind-suppressions.txt --leak-check=full --show-reachable=yes %s 2>%s'%(command, valgrind_log) + if post == "": + command = ( + "valgrind --tool=memcheck -q --suppressions=../valgrind-suppressions.txt --leak-check=full --show-reachable=yes %s 2>%s" + % (command, valgrind_log) + ) else: - command = 'echo "' + post + '" | valgrind --tool=memcheck -q --suppressions=../valgrind-suppressions.txt --leak-check=full --show-reachable=yes %s 2>%s'%(command, valgrind_log) - elif run_under_asan: - asan_log = 'result/' + out_file + ".asan.txt" + command = ( + 'echo "' + + post + + '" | valgrind --tool=memcheck -q --suppressions=../valgrind-suppressions.txt --leak-check=full --show-reachable=yes %s 2>%s' + % (command, valgrind_log) + ) + elif run_under_asan and not asan_skip_log: + asan_log = "result/" + out_file + ".asan.txt" command = command.strip() command += " 2>%s" % asan_log if verbose: - print('') - print( command ) - - os.system( command ) + print("") + print(command) + + os.system(command) if begin != -1 and end != -1 and begin < end: - del os.environ['CONTENT_LENGTH'] - del os.environ['REQUEST_METHOD'] - del os.environ['MS_MAPFILE'] + del os.environ["CONTENT_LENGTH"] + del os.environ["REQUEST_METHOD"] + del os.environ["MS_MAPFILE"] - if envirkey != '': + if envirkey != "": del os.environ[envirkey] if demime: - demime_file( 'result/'+out_file ) + demime_file("result/" + out_file) if deversion: - deversion_file( 'result/'+out_file ) - degdalversion_file( 'result/'+out_file ) - fixexponent_file( 'result/'+out_file ) - truncate_one_decimal( 'result/'+out_file ) - detimestamp_file( 'result/'+out_file ) + deversion_file("result/" + out_file) + degdalversion_file("result/" + out_file) + fixexponent_file("result/" + out_file) + detimestamp_file("result/" + out_file) if extractserviceversion: - extract_service_version_file( 'result/'+out_file ) + extract_service_version_file("result/" + out_file) if valgrind: if os.path.getsize(valgrind_log) == 0: - os.remove( valgrind_log ) + os.remove(valgrind_log) else: if not quiet: - print(' Valgrind log non empty.') + print(" Valgrind log non empty.") - elif run_under_asan: + elif run_under_asan and not asan_skip_log: if os.path.getsize(asan_log) == 0: - os.remove( asan_log ) + os.remove(asan_log) else: - asan_log_content = open(asan_log, 'rt').read() + asan_log_content = open(asan_log, "rt").read() # We get some unexplained crashes on Travis-CI if "Assertion `unscaled->face" in asan_log_content: - os.remove( asan_log ) - elif 'AddressSanitizer' in asan_log_content or 'LeakSanitizer' in asan_log_content: + os.remove(asan_log) + elif ( + "AddressSanitizer" in asan_log_content + or "LeakSanitizer" in asan_log_content + ): if not quiet: - print(' ASAN log non empty.') + print(" ASAN log non empty.") else: # some other standard error output - os.remove( asan_log ) + os.remove(asan_log) - apply_strip_items_file( 'result/'+out_file, strip_items ) + apply_strip_items_file("result/" + out_file, strip_items) - crlf('result/'+out_file) + crlf("result/" + out_file) - cmp = compare_result( out_file ) + cmp = compare_result(out_file) - if cmp == 'match': + if cmp == "match": if not keep_pass: - os.remove( 'result/' + out_file ) + os.remove("result/" + out_file) if not quiet: - print(' results match.') + print(" results match.") else: - sys.stdout.write('.') + sys.stdout.write(".") sys.stdout.flush() - elif cmp == 'files_differ_image_match': + elif cmp == "files_differ_image_match": if strict: - return False, ('results dont match (though images match)', map, out_file) + return False, ("results don't match (though images match)", map, out_file) else: if not keep_pass: - os.remove( 'result/' + out_file ) + os.remove("result/" + out_file) if not quiet: - print(' result images match, though files differ.') + print(" result images match, though files differ.") else: - sys.stdout.write('.') + sys.stdout.write(".") sys.stdout.flush() - elif cmp == 'files_differ_image_nearly_match': + elif cmp == "files_differ_image_nearly_match": if strict: - return False, ('results dont match (though images perceptually match)', map, out_file) + return False, ( + "results don't match (though images perceptually match)", + map, + out_file, + ) else: if not keep_pass: - os.remove( 'result/' + out_file ) + os.remove("result/" + out_file) if not quiet: - print(' result images perceptually match, though files differ.') + print(" result images perceptually match, though files differ.") else: - print('%s: result images perceptually match, though files differ.'%(out_file)) + print( + "%s: result images perceptually match, though files differ." + % (out_file) + ) - elif cmp == 'nomatch': - return False, ('results dont match', map, out_file) + elif cmp == "nomatch": + return False, ("results don't match", map, out_file) - elif cmp == 'noresult': - with open('result/' + out_file, 'w') as fh: + elif cmp == "noresult": + with open("result/" + out_file, "w") as fh: fh.write("Segmentation fault or other serious error\n") - return False, ('no result file generated', map, out_file) + return False, ("no result file generated", map, out_file) - elif cmp == 'noexpected': + elif cmp == "noexpected": if strict: - return False, ('no existing file expected/' + out_file) + return False, ("no existing file expected/" + out_file) if not quiet: - print(' no expected file exists, accepting result as expected.') + print(" no expected file exists, accepting result as expected.") else: - print('%s: no expected file exists, accepting result as expected.'%(out_file)) + print( + "%s: no expected file exists, accepting result as expected." + % (out_file) + ) - os.rename( 'result/' + out_file, 'expected/' + out_file ) + os.rename("result/" + out_file, "expected/" + out_file) return True, None + ############################################################################### @@ -734,6 +806,7 @@ def run_pytest(map, out_file, command, extra_args): ret, msg = _run(map, out_file, command, extra_args) assert ret, msg + ############################################################################### @@ -742,17 +815,17 @@ def pytest_main(): new_argv = [] help = False for arg in sys.argv: - if arg.endswith('.map'): + if arg.endswith(".map"): maps.append(arg[0:-4]) else: - if arg == '--help': + if arg == "--help": help = True new_argv.append(arg) sys.argv = new_argv if maps: - sys.argv.append('-k') - sys.argv.append(' or '.join(maps)) + sys.argv.append("-k") + sys.argv.append(" or ".join(maps)) ret = pytest.main() if help: - print('\nMapServer note: you can also specify one or several .map filenames') + print("\nMapServer note: you can also specify one or several .map filenames") return ret diff --git a/msautotest/pymod/pmstestlib.py b/msautotest/pymod/pmstestlib.py index 2a9c196a0f..4bf85b2fbe 100644 --- a/msautotest/pymod/pmstestlib.py +++ b/msautotest/pymod/pmstestlib.py @@ -8,17 +8,17 @@ # ############################################################################### # Copyright (c) 2004, Frank Warmerdam -# +# # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: -# +# # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. -# +# # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL @@ -29,63 +29,74 @@ ############################################################################### import os + from testlib import compare_result keep_pass = 0 -def get_item_value( layer, shape_obj, name ): +def get_item_value(layer, shape_obj, name): for i in range(layer.numitems): if layer.getItem(i) == name: return shape_obj.getValue(i) return None + ############################################################################### # -def check_items( layer, shape_obj, nv_list ): +def check_items(layer, shape_obj, nv_list): for nv in nv_list: name = nv[0] expected_value = nv[1] - actual_value = get_item_value( layer, shape_obj, name ) - assert actual_value is not None, ('missing expected attribute %s' % name) + actual_value = get_item_value(layer, shape_obj, name) + assert actual_value is not None, "missing expected attribute %s" % name + + assert ( + str(expected_value) == actual_value + ), 'attribute %s is "%s" instead of expected "%s"' % ( + name, + actual_value, + str(expected_value), + ) - assert str(expected_value) == actual_value, \ - ( 'attribute %s is "%s" instead of expected "%s"' % \ - (name, actual_value, str(expected_value)) ) ############################################################################### # -def compare_and_report( out_file, this_path = '.' ): - cmp = compare_result( out_file, this_path ) +def compare_and_report(out_file, this_path="."): + + cmp = compare_result(out_file, this_path) - if cmp == 'match': + if cmp == "match": if keep_pass == 0: - os.remove( os.path.join(this_path, 'result', out_file) ) + os.remove(os.path.join(this_path, "result", out_file)) - elif cmp == 'files_differ_image_match': + elif cmp == "files_differ_image_match": if keep_pass == 0: - os.remove( os.path.join(this_path, 'result', out_file) ) - print('result images match, though files differ.') + os.remove(os.path.join(this_path, "result", out_file)) + print("result images match, though files differ.") - elif cmp == 'files_differ_image_nearly_match': + elif cmp == "files_differ_image_nearly_match": if keep_pass == 0: - os.remove( os.path.join(this_path, 'result', out_file) ) - print('result images perceptually match, though files differ.') + os.remove(os.path.join(this_path, "result", out_file)) + print("result images perceptually match, though files differ.") - elif cmp == 'nomatch': - assert False, 'results dont match, TEST FAILED.' + elif cmp == "nomatch": + assert False, "results don't match, TEST FAILED." - elif cmp == 'noresult': - assert False, 'no result file generated, TEST FAILED.' + elif cmp == "noresult": + assert False, "no result file generated, TEST FAILED." - elif cmp == 'noexpected': - print('no expected file exists, accepting result as expected.') - os.rename( os.path.join(this_path, 'result', out_file), os.path.join(this_path, 'expected', out_file) ) + elif cmp == "noexpected": + print("no expected file exists, accepting result as expected.") + os.rename( + os.path.join(this_path, "result", out_file), + os.path.join(this_path, "expected", out_file), + ) else: - assert False, 'unexpected cmp value: ' + cmp + assert False, "unexpected cmp value: " + cmp diff --git a/msautotest/pymod/testlib.py b/msautotest/pymod/testlib.py index 636e032855..119eee22a4 100644 --- a/msautotest/pymod/testlib.py +++ b/msautotest/pymod/testlib.py @@ -7,17 +7,17 @@ # ############################################################################### # Copyright (c) 2007, Frank Warmerdam -# +# # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: -# +# # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. -# +# # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL @@ -34,28 +34,30 @@ ############################################################################### # strip_headers() -def strip_headers( filename ): + +def strip_headers(filename): try: header = open(filename, "rb").read(1000) - except: + except Exception: return None from sys import version_info - if version_info >= (3,0,0): - header = str(header, 'iso-8859-1') + + if version_info >= (3, 0, 0): + header = str(header, "iso-8859-1") tmp_filename = None - start_pos = header.find('\x49\x49\x2A\x00') + start_pos = header.find("\x49\x49\x2A\x00") if start_pos < 0: - start_pos = header.find('\x49\x49\x00\x2A') + start_pos = header.find("\x49\x49\x00\x2A") if start_pos < 0: - start_pos = header.find('\x89\x50\x4e\x47\x0d\x0a\x1a\x0a') + start_pos = header.find("\x89\x50\x4e\x47\x0d\x0a\x1a\x0a") if start_pos > 0: f = open(filename, "rb") f.seek(start_pos, 0) data = f.read() f.close() - tmp_filename = filename + '.tmp' + tmp_filename = filename + ".tmp" f = open(tmp_filename, "wb") f.write(data) f.close() @@ -63,84 +65,141 @@ def strip_headers( filename ): return None + +################################################################### +# Check image checksums with GDAL + + +def check_with_gdal(result_file, expected_file): + + from osgeo import gdal + + gdal.PushErrorHandler("CPLQuietErrorHandler") + exp_ds = gdal.Open(expected_file) + gdal.PopErrorHandler() + if exp_ds == None: + return "nomatch" + + res_ds = gdal.Open(result_file) + + match = 1 + for band_num in range(1, exp_ds.RasterCount + 1): + if ( + res_ds.GetRasterBand(band_num).Checksum() + != exp_ds.GetRasterBand(band_num).Checksum() + ): + match = 0 + + if match == 1: + + # Special case for netCDF: we need to eliminate NC_GLOBAL#history + # since it contains the current timedate + if exp_ds.GetDriver().GetDescription() == "netCDF": + if exp_ds.GetGeoTransform() != res_ds.GetGeoTransform(): + return "nomatch" + if exp_ds.GetProjectionRef() != res_ds.GetProjectionRef(): + return "nomatch" + exp_md = exp_ds.GetMetadata() + if "NC_GLOBAL#history" in exp_md: + del exp_md["NC_GLOBAL#history"] + got_md = res_ds.GetMetadata() + if "NC_GLOBAL#history" in got_md: + del got_md["NC_GLOBAL#history"] + if exp_md != got_md: + return "nomatch" + for band_num in range(1, exp_ds.RasterCount + 1): + # to ensure GetMetadata matches requires the .aux.xml + # files associated with the netCDF files to be present + # as they contain stats metadata e.g. STATISTICS_MINIMUM + if ( + res_ds.GetRasterBand(band_num).GetMetadata() + != exp_ds.GetRasterBand(band_num).GetMetadata() + ): + return "nomatch" + return "match" + + return "files_differ_image_match" + + return "nomatch" + + ############################################################################### # compare_result() -def compare_result( filename, this_path = '.' ): + +def compare_result(filename, this_path="."): import filecmp - - result_file = os.path.join(this_path, 'result', filename) - expected_file = os.path.join(this_path, 'expected', filename) + + result_file = os.path.join(this_path, "result", filename) + expected_file = os.path.join(this_path, "expected", filename) try: - os.stat( result_file ) + os.stat(result_file) except OSError: - return 'noresult' - + return "noresult" + try: - os.stat( expected_file ) + os.stat(expected_file) except OSError: - return 'noexpected' + return "noexpected" - if filecmp.cmp(expected_file,result_file,0): - return 'match' + # netCDF files contain a NC_GLOBAL#history that contains a datetime. + # Binary comparison can't work + if not expected_file.endswith(".nc"): + if filecmp.cmp(expected_file, result_file, shallow=False): + return "match" - expected_file_alternative = expected_file + ".alternative" - if os.path.exists( expected_file_alternative ): - if filecmp.cmp(expected_file_alternative,result_file,0): - return 'match' + expected_file_alternative = expected_file + ".alternative" + if os.path.exists(expected_file_alternative): + if filecmp.cmp(expected_file_alternative, result_file, shallow=False): + return "match" + + if expected_file[-4:] == ".xml": + return "nomatch" - if expected_file[-4:] == '.xml': - return 'nomatch' - ################################################################### # Check image checksums with GDAL if it is available. - try: - try: - from osgeo import gdal - except: - import gdal - - gdal.PushErrorHandler('CPLQuietErrorHandler') - exp_ds = gdal.Open( expected_file ) - gdal.PopErrorHandler() - if exp_ds == None: - return 'nomatch' - - res_ds = gdal.Open( result_file ) - - match = 1 - for band_num in range(1,exp_ds.RasterCount+1): - if res_ds.GetRasterBand(band_num).Checksum() != \ - exp_ds.GetRasterBand(band_num).Checksum(): - match = 0 - - if match == 1: - return 'files_differ_image_match' - except: - pass + from osgeo import gdal + + gdal.VersionInfo(None) # make pyflakes happy + has_gdal = True + except Exception: + has_gdal = False + + if has_gdal: + ret = check_with_gdal(result_file, expected_file) + if ret != "nomatch": + return ret + + expected_file_alternative = expected_file + ".alternative" + if os.path.exists(expected_file_alternative): + ret = check_with_gdal(result_file, expected_file_alternative) + if ret != "nomatch": + return ret ################################################################### # Test with perceptualdiff if this is tiff or png. If we discover # we don't have it, then set have_pdiff to 'false' so we will know. - + global have_pdiff try: result = open(result_file, "rb").read(1000) - except: - result = '' + except Exception: + result = "" from sys import version_info - if version_info >= (3,0,0): - result = str(result, 'iso-8859-1') - run_perceptualdiff = have_pdiff != 'false' and \ - ('\x49\x49\x2A\x00' in result \ - or '\x49\x49\x00\x2A' in result \ - or '\x47\x49\x46\x38\x37\x61' in result \ - or '\x89\x50\x4e\x47\x0d\x0a\x1a\x0a' in result) + if version_info >= (3, 0, 0): + result = str(result, "iso-8859-1") + + run_perceptualdiff = have_pdiff != "false" and ( + "\x49\x49\x2A\x00" in result + or "\x49\x49\x00\x2A" in result + or "\x47\x49\x46\x38\x37\x61" in result + or "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a" in result + ) if run_perceptualdiff: @@ -153,12 +212,15 @@ def compare_result( filename, this_path = '.' ): expected_file = tmp_expected_file try: - cmd = 'perceptualdiff %s %s -verbose > pd.out 2>&1 ' % (result_file,expected_file) - os.system( cmd ) - pdout = open('pd.out').read() - os.remove( 'pd.out' ) - except: - pdout = '' + cmd = "perceptualdiff %s %s -verbose > pd.out 2>&1 " % ( + result_file, + expected_file, + ) + os.system(cmd) + pdout = open("pd.out").read() + os.remove("pd.out") + except Exception: + pdout = "" pass if tmp_result_file is not None: @@ -166,18 +228,13 @@ def compare_result( filename, this_path = '.' ): if tmp_expected_file is not None: os.remove(tmp_expected_file) - if pdout.find('PASS:') != -1 \ - and pdout.find('binary identical') != -1: - return 'files_differ_image_match' + if pdout.find("PASS:") != -1 and pdout.find("binary identical") != -1: + return "files_differ_image_match" - if pdout.find('PASS:') != -1 \ - and pdout.find('indistinguishable') != -1: - return 'files_differ_image_nearly_match' + if pdout.find("PASS:") != -1 and pdout.find("indistinguishable") != -1: + return "files_differ_image_nearly_match" - if pdout.find('PASS:') == -1 \ - and pdout.find('FAIL:') == -1: - have_pdiff = 'false' + if pdout.find("PASS:") == -1 and pdout.find("FAIL:") == -1: + have_pdiff = "false" - - return 'nomatch' - + return "nomatch" diff --git a/msautotest/pymod/xmlvalidate.py b/msautotest/pymod/xmlvalidate.py index 9a601a6348..74f92d3c9b 100644 --- a/msautotest/pymod/xmlvalidate.py +++ b/msautotest/pymod/xmlvalidate.py @@ -31,55 +31,84 @@ ############################################################################### import os -import sys -import urllib2 import socket +import sys + +# handle urllib for both Python 2 & 3 +from future.standard_library import install_aliases from lxml import etree +install_aliases() +from urllib.error import HTTPError, URLError +from urllib.request import ( + HTTPHandler, + ProxyHandler, + build_opener, + install_opener, + urlopen, +) + + ############################################################################### # Remove mime header if found def ingest_file_and_strip_mime(filename): - data = '' - f = open(filename, 'rb') + data = "" + f = open(filename, "rb") for line in f.readlines(): - if line == '\r\n': + if line == "\r\n": continue - if line == '\n': + if line == "\n": continue - if line.find('Content-Type') >= 0: + if line.find("Content-Type") >= 0: continue data = data + line f.close() return data + ############################################################################### # Replace http://schemas.opengis.net/foo by $(ogc_schemas_location)/foo + def substitute_ogc_schemas_location(location, ogc_schemas_location): - if ogc_schemas_location is not None and \ - location.startswith('http://schemas.opengis.net/'): - location = ogc_schemas_location + '/' + location[len('http://schemas.opengis.net/'):] + if ogc_schemas_location is not None and location.startswith( + "http://schemas.opengis.net/" + ): + location = ( + ogc_schemas_location + "/" + location[len("http://schemas.opengis.net/") :] + ) return location + ############################################################################### # Replace http://inspire.ec.europa.eu/schemas/foo by $(inspire_schemas_location)/foo + def substitute_inspire_schemas_location(location, inspire_schemas_location): - if inspire_schemas_location is not None and \ - location.startswith('http://inspire.ec.europa.eu/schemas/'): - location = inspire_schemas_location + '/' + location[len('http://inspire.ec.europa.eu/schemas/'):] + if inspire_schemas_location is not None and location.startswith( + "http://inspire.ec.europa.eu/schemas/" + ): + location = ( + inspire_schemas_location + + "/" + + location[len("http://inspire.ec.europa.eu/schemas/") :] + ) return location + ############################################################################### # Validation function -def validate(xml_filename_or_content, xsd_filename = None, \ - application_schema_ns = None, \ - ogc_schemas_location = None, \ - inspire_schemas_location = None): +def validate( + xml_filename_or_content, + xsd_filename=None, + application_schema_ns=None, + ogc_schemas_location=None, + inspire_schemas_location=None, +): try: - if xml_filename_or_content.find('<') == 0: + if xml_filename_or_content.find("<") == 0: doc = etree.XML(xml_filename_or_content) else: doc = etree.XML(ingest_file_and_strip_mime(xml_filename_or_content)) @@ -88,13 +117,17 @@ def validate(xml_filename_or_content, xsd_filename = None, \ return False # Special case if this is a schema - if doc.tag == '{http://www.w3.org/2001/XMLSchema}schema': + if doc.tag == "{http://www.w3.org/2001/XMLSchema}schema": for child in doc: - if child.tag == '{http://www.w3.org/2001/XMLSchema}import': - location = child.get('schemaLocation') - location = substitute_ogc_schemas_location(location, ogc_schemas_location) - location = substitute_inspire_schemas_location(location, inspire_schemas_location) - child.set('schemaLocation', location) + if child.tag == "{http://www.w3.org/2001/XMLSchema}import": + location = child.get("schemaLocation") + location = substitute_ogc_schemas_location( + location, ogc_schemas_location + ) + location = substitute_inspire_schemas_location( + location, inspire_schemas_location + ) + child.set("schemaLocation", location) try: etree.XMLSchema(etree.XML(etree.tostring(doc))) return True @@ -102,25 +135,28 @@ def validate(xml_filename_or_content, xsd_filename = None, \ print(str(e)) return False - schema_locations = doc.get("{http://www.w3.org/2001/XMLSchema-instance}schemaLocation") + schema_locations = doc.get( + "{http://www.w3.org/2001/XMLSchema-instance}schemaLocation" + ) if schema_locations is None: - print('No schemaLocation found') + print("No schemaLocation found") return False # Our stripped GetFeature document have an empty timeStamp, put a # fake value one instead - if doc.get('timeStamp') == '': - doc.set('timeStamp', '1970-01-01T00:00:00Z') + if doc.get("timeStamp") == "": + doc.set("timeStamp", "1970-01-01T00:00:00Z") locations = schema_locations.split() # get schema locations - schema_def = etree.Element("schema", attrib={ + schema_def = etree.Element( + "schema", + attrib={ "elementFormDefault": "qualified", "version": "1.0.0", - }, nsmap={ - None: "http://www.w3.org/2001/XMLSchema" - } + }, + nsmap={None: "http://www.w3.org/2001/XMLSchema"}, ) tempfiles = [] @@ -132,34 +168,38 @@ def validate(xml_filename_or_content, xsd_filename = None, \ if xsd_filename is not None: location = xsd_filename else: - location = os.path.splitext(xml_filename_or_content)[0] + '.xsd' + location = os.path.splitext(xml_filename_or_content)[0] + ".xsd" # Remove mime-type header line if found to generate a valid .xsd sanitized_content = ingest_file_and_strip_mime(location) - location = '/tmp/tmpschema%d.xsd' % len(tempfiles) - f = open(location, 'wb') + location = "/tmp/tmpschema%d.xsd" % len(tempfiles) + f = open(location, "wb") f.write(sanitized_content) tempfiles.append(location) f.close() xsd = etree.XML(sanitized_content) for child in xsd: - if child.tag == '{http://www.w3.org/2001/XMLSchema}import': - sub_ns = child.get('namespace') - sub_location = child.get('schemaLocation') - sub_location = substitute_ogc_schemas_location(sub_location, ogc_schemas_location) - sub_location = substitute_inspire_schemas_location(sub_location, inspire_schemas_location) - etree.SubElement(schema_def, "import", attrib={ - "namespace": sub_ns, - "schemaLocation": sub_location - } + if child.tag == "{http://www.w3.org/2001/XMLSchema}import": + sub_ns = child.get("namespace") + sub_location = child.get("schemaLocation") + sub_location = substitute_ogc_schemas_location( + sub_location, ogc_schemas_location + ) + sub_location = substitute_inspire_schemas_location( + sub_location, inspire_schemas_location + ) + etree.SubElement( + schema_def, + "import", + attrib={"namespace": sub_ns, "schemaLocation": sub_location}, ) import_dict[sub_ns] = sub_location - etree.SubElement(schema_def, "import", attrib={ - "namespace": ns, - "schemaLocation": location - } + etree.SubElement( + schema_def, + "import", + attrib={"namespace": ns, "schemaLocation": location}, ) import_dict[ns] = location @@ -168,17 +208,19 @@ def validate(xml_filename_or_content, xsd_filename = None, \ if ns == application_schema_ns: continue location = substitute_ogc_schemas_location(location, ogc_schemas_location) - location = substitute_inspire_schemas_location(location, inspire_schemas_location) + location = substitute_inspire_schemas_location( + location, inspire_schemas_location + ) if ns not in import_dict: - etree.SubElement(schema_def, "import", attrib={ - "namespace": ns, - "schemaLocation": location - } + etree.SubElement( + schema_def, + "import", + attrib={"namespace": ns, "schemaLocation": location}, ) import_dict[ns] = location # TODO: ugly workaround. But otherwise, the doc is not recognized as schema - #print(etree.tostring(schema_def)) + # print(etree.tostring(schema_def)) schema = etree.XMLSchema(etree.XML(etree.tostring(schema_def))) try: @@ -193,297 +235,331 @@ def validate(xml_filename_or_content, xsd_filename = None, \ return ret + ############################################################################### # Return a handle on a URL + def gdalurlopen(url): timeout = 60 old_timeout = socket.getdefaulttimeout() socket.setdefaulttimeout(timeout) - if 'GDAL_HTTP_PROXY' in os.environ: - proxy = os.environ['GDAL_HTTP_PROXY'] + if "GDAL_HTTP_PROXY" in os.environ: + proxy = os.environ["GDAL_HTTP_PROXY"] - if 'GDAL_HTTP_PROXYUSERPWD' in os.environ: - proxyuserpwd = os.environ['GDAL_HTTP_PROXYUSERPWD'] - proxyHandler = urllib2.ProxyHandler({"http" : \ - "http://%s@%s" % (proxyuserpwd, proxy)}) + if "GDAL_HTTP_PROXYUSERPWD" in os.environ: + proxyuserpwd = os.environ["GDAL_HTTP_PROXYUSERPWD"] + proxyHandler = ProxyHandler( + {"http": "http://%s@%s" % (proxyuserpwd, proxy)} + ) else: proxyuserpwd = None - proxyHandler = urllib2.ProxyHandler({"http" : \ - "http://%s" % (proxy)}) + proxyHandler = ProxyHandler({"http": "http://%s" % (proxy)}) - opener = urllib2.build_opener(proxyHandler, urllib2.HTTPHandler) + opener = build_opener(proxyHandler, HTTPHandler) - urllib2.install_opener(opener) + install_opener(opener) try: - handle = urllib2.urlopen(url) + handle = urlopen(url) socket.setdefaulttimeout(old_timeout) return handle - except urllib2.HTTPError as e: - print('HTTP service for %s is down (HTTP Error: %d)' % (url, e.code)) + except HTTPError as e: + print("HTTP service for %s is down (HTTP Error: %d)" % (url, e.code)) socket.setdefaulttimeout(old_timeout) return None - except urllib2.URLError as e: - print('HTTP service for %s is down (HTTP Error: %s)' % (url, e.reason)) + except URLError as e: + print("HTTP service for %s is down (HTTP Error: %s)" % (url, e.reason)) socket.setdefaulttimeout(old_timeout) return None - except: - print('HTTP service for %s is down.' %(url)) + except Exception: + print("HTTP service for %s is down." % (url)) socket.setdefaulttimeout(old_timeout) return None + ############################################################################### # Download a file + def download(url, output_file): try: handle = gdalurlopen(url) try: handle_info = handle.info() - content_length = handle_info['content-length'] - print('Downloading %s (length = %s bytes)...' % (url, content_length)) - except: - print('Downloading %s...' % (url)) + content_length = handle_info["content-length"] + print("Downloading %s (length = %s bytes)..." % (url, content_length)) + except Exception: + print("Downloading %s..." % (url)) ret = handle.read() - except: + except Exception: ret = None if ret is None: - print('Cannot download %s' % url) + print("Cannot download %s" % url) sys.exit(1) - f = open(output_file, 'wb') + f = open(output_file, "wb") f.write(ret) f.close() + ############################################################################### # Unzip a file -def unzip(zipfilename, target_dir): +def unzip(zipfilename, target_dir): try: import zipfile + zf = zipfile.ZipFile(zipfilename) - except: - os.system('unzip -d ' + target_dir + ' ' + zipfilename) + except Exception: + os.system("unzip -d " + target_dir + " " + zipfilename) return for filename in zf.namelist(): print(filename) outfilename = os.path.join(target_dir, filename) - if filename.endswith('/'): + if filename.endswith("/"): if not os.path.exists(outfilename): - os.makedirs(outfilename) + os.makedirs(outfilename) else: outdirname = os.path.dirname(outfilename) if not os.path.exists(outdirname): - os.makedirs(outdirname) + os.makedirs(outdirname) - outfile = open(outfilename,'wb') + outfile = open(outfilename, "wb") outfile.write(zf.read(filename)) outfile.close() return + ############################################################################### # Transform absolute schemaLocations into relative ones -def transform_abs_links_to_ref_links(path, level = 0): + +def transform_abs_links_to_ref_links(path, level=0): for file in os.listdir(path): - filename=path + '/' + file - if os.path.isdir(filename) and filename.find('examples') < 0: - transform_abs_links_to_ref_links(filename, level+1) - elif filename.endswith('.xsd'): - #print(level) - #print(filename) - f = open(filename, 'rb') + filename = path + "/" + file + if os.path.isdir(filename) and filename.find("examples") < 0: + transform_abs_links_to_ref_links(filename, level + 1) + elif filename.endswith(".xsd"): + # print(level) + # print(filename) + f = open(filename, "rb") lines = f.readlines() f.close() rewrite = False for i in range(len(lines)): l = lines[i] - if l[-1] == '\n': + if l[-1] == "\n": l = l[0:-1] - pos = l.find('http://schemas.opengis.net/') + pos = l.find(b"http://schemas.opengis.net/") if pos >= 0: rewrite = True s = l[0:pos] for j in range(level): - s = s + "../" - s = s + l[pos + len('http://schemas.opengis.net/'):] + s = s + b"../" + s = s + l[pos + len(b"http://schemas.opengis.net/") :] l = s lines[i] = l - pos = l.find('http://www.w3.org/1999/xlink.xsd') + pos = l.find(b"http://www.w3.org/1999/xlink.xsd") if pos >= 0: rewrite = True s = l[0:pos] for j in range(level): - s = s + "../" - s = s + l[pos + len('http://www.w3.org/1999/'):] + s = s + b"../" + s = s + l[pos + len(b"http://www.w3.org/1999/") :] l = s lines[i] = l - pos = l.find('http://www.w3.org/2001/xml.xsd') + pos = l.find(b"http://www.w3.org/2001/xml.xsd") if pos >= 0: rewrite = True s = l[0:pos] for j in range(level): - s = s + "../" - s = s + l[pos + len('http://www.w3.org/2001/'):] + s = s + b"../" + s = s + l[pos + len(b"http://www.w3.org/2001/") :] l = s lines[i] = l if rewrite: - f = open(filename, 'wb') + f = open(filename, "wb") f.writelines(lines) f.close() + ############################################################################### # Transform absolute schemaLocations into relative ones -def transform_inspire_abs_links_to_ref_links(path, level = 0): + +def transform_inspire_abs_links_to_ref_links(path, level=0): for file in os.listdir(path): - filename=path + '/' + file - if os.path.isdir(filename) and filename.find('examples') < 0: - transform_inspire_abs_links_to_ref_links(filename, level+1) - elif filename.endswith('.xsd'): - #print(level) - #print(filename) - f = open(filename, 'rb') + filename = path + "/" + file + if os.path.isdir(filename) and filename.find("examples") < 0: + transform_inspire_abs_links_to_ref_links(filename, level + 1) + elif filename.endswith(".xsd"): + # print(level) + # print(filename) + f = open(filename, "rb") lines = f.readlines() f.close() rewrite = False for i in range(len(lines)): l = lines[i] - if l[-1] == '\n': + if l[-1] == "\n": l = l[0:-1] - pos = l.find('http://schemas.opengis.net/') + pos = l.find(b"http://schemas.opengis.net/") if pos >= 0: rewrite = True s = l[0:pos] for j in range(level): - s = s + "../" - s = s + "../SCHEMAS_OPENGIS_NET/" - s = s + l[pos + len('http://schemas.opengis.net/'):] + s = s + b"../" + s = s + b"../SCHEMAS_OPENGIS_NET/" + s = s + l[pos + len(b"http://schemas.opengis.net/") :] l = s lines[i] = l if rewrite: - f = open(filename, 'wb') + f = open(filename, "wb") f.writelines(lines) f.close() + ############################################################################### # Download OGC schemas -def download_ogc_schemas(ogc_schemas_url = 'http://schemas.opengis.net/SCHEMAS_OPENGIS_NET.zip', \ - xlink_xsd_url = 'http://www.w3.org/1999/xlink.xsd', \ - xml_xsd_url = 'http://www.w3.org/2001/xml.xsd', \ - target_dir = '.', \ - target_subdir = 'SCHEMAS_OPENGIS_NET'): + +def download_ogc_schemas( + ogc_schemas_url="http://schemas.opengis.net/SCHEMAS_OPENGIS_NET.zip", + xlink_xsd_url="http://www.w3.org/1999/xlink.xsd", + xml_xsd_url="http://www.w3.org/2001/xml.xsd", + target_dir=".", + target_subdir="SCHEMAS_OPENGIS_NET", +): try: - os.stat(target_dir + '/' + 'SCHEMAS_OPENGIS_NET.zip') - except: - download(ogc_schemas_url, target_dir + '/' + 'SCHEMAS_OPENGIS_NET.zip') + os.stat(target_dir + "/" + "SCHEMAS_OPENGIS_NET.zip") + except Exception: + download(ogc_schemas_url, target_dir + "/" + "SCHEMAS_OPENGIS_NET.zip") try: - os.stat(target_dir + '/' + target_subdir + '/wfs') - except: + os.stat(target_dir + "/" + target_subdir + "/wfs") + except Exception: try: - os.mkdir(target_dir + '/' + target_subdir) - except: + os.mkdir(target_dir + "/" + target_subdir) + except Exception: pass - unzip(target_dir + '/' + 'SCHEMAS_OPENGIS_NET.zip', target_dir + '/' + target_subdir) + unzip( + target_dir + "/" + "SCHEMAS_OPENGIS_NET.zip", + target_dir + "/" + target_subdir, + ) try: - os.stat(target_dir + '/' + target_subdir + '/wfs') - except: - print('Cannot unzip SCHEMAS_OPENGIS_NET.zip') + os.stat(target_dir + "/" + target_subdir + "/wfs") + except Exception: + print("Cannot unzip SCHEMAS_OPENGIS_NET.zip") sys.exit(1) try: - os.stat(target_dir + '/' + target_subdir + '/xlink.xsd') - except: - download(xlink_xsd_url, target_dir + '/' + target_subdir + '/xlink.xsd') + os.stat(target_dir + "/" + target_subdir + "/xlink.xsd") + except Exception: + download(xlink_xsd_url, target_dir + "/" + target_subdir + "/xlink.xsd") try: - os.stat(target_dir + '/' + target_subdir + '/xml.xsd') - except: - download(xml_xsd_url, target_dir + '/' + target_subdir + '/xml.xsd') + os.stat(target_dir + "/" + target_subdir + "/xml.xsd") + except Exception: + download(xml_xsd_url, target_dir + "/" + target_subdir + "/xml.xsd") + + transform_abs_links_to_ref_links(target_dir + "/" + target_subdir) - transform_abs_links_to_ref_links(target_dir + '/' + target_subdir) ############################################################################### # Download INSPIRE schemas -def download_inspire_schemas(target_dir = '.', \ - target_subdir = 'inspire_schemas'): +def download_inspire_schemas(target_dir=".", target_subdir="inspire_schemas"): download_ogc_schemas() try: - os.stat(target_dir + '/' + 'inspire_common_1.0.1.zip') - except: - download('http://inspire.ec.europa.eu/schemas/common/1.0.1.zip', target_dir + '/' + 'inspire_common_1.0.1.zip') + os.stat(target_dir + "/" + "inspire_common_1.0.1.zip") + except Exception: + download( + "http://inspire.ec.europa.eu/schemas/common/1.0.1.zip", + target_dir + "/" + "inspire_common_1.0.1.zip", + ) try: - os.stat(target_dir + '/' + 'inspire_vs_1.0.1.zip') - except: - download('http://inspire.ec.europa.eu/schemas/inspire_vs/1.0.1.zip', target_dir + '/' + 'inspire_vs_1.0.1.zip') - - for subdir in [ '', '/common', '/inspire_vs', '/inspire_dls', '/inspire_dls/1.0']: + os.stat(target_dir + "/" + "inspire_vs_1.0.1.zip") + except Exception: + download( + "http://inspire.ec.europa.eu/schemas/inspire_vs/1.0.1.zip", + target_dir + "/" + "inspire_vs_1.0.1.zip", + ) + + for subdir in ["", "/common", "/inspire_vs", "/inspire_dls", "/inspire_dls/1.0"]: try: - os.mkdir(target_dir + '/' + target_subdir + subdir) - except: + os.mkdir(target_dir + "/" + target_subdir + subdir) + except Exception: pass try: - os.stat(target_dir + '/' + target_subdir + '/common/1.0') - except: - unzip(target_dir + '/' + 'inspire_common_1.0.1.zip', target_dir + '/' + target_subdir + '/common') + os.stat(target_dir + "/" + target_subdir + "/common/1.0") + except Exception: + unzip( + target_dir + "/" + "inspire_common_1.0.1.zip", + target_dir + "/" + target_subdir + "/common", + ) try: - os.stat(target_dir + '/' + target_subdir + '/common/1.0') - except: - print('Cannot unzip inspire_common_1.0.1.zip') + os.stat(target_dir + "/" + target_subdir + "/common/1.0") + except Exception: + print("Cannot unzip inspire_common_1.0.1.zip") sys.exit(1) try: - os.stat(target_dir + '/' + target_subdir + '/inspire_vs/1.0') - except: - unzip(target_dir + '/' + 'inspire_vs_1.0.1.zip', target_dir + '/' + target_subdir + '/inspire_vs') + os.stat(target_dir + "/" + target_subdir + "/inspire_vs/1.0") + except Exception: + unzip( + target_dir + "/" + "inspire_vs_1.0.1.zip", + target_dir + "/" + target_subdir + "/inspire_vs", + ) try: - os.stat(target_dir + '/' + target_subdir + '/inspire_vs/1.0') - except: - print('Cannot unzip inspire_vs_1.0.1.zip') + os.stat(target_dir + "/" + target_subdir + "/inspire_vs/1.0") + except Exception: + print("Cannot unzip inspire_vs_1.0.1.zip") sys.exit(1) try: - os.stat(target_dir + '/' + target_subdir + '/inspire_dls/1.0/inspire_dls.xsd') - except: - download('http://inspire.ec.europa.eu/schemas/inspire_dls/1.0/inspire_dls.xsd', target_dir + '/' + target_subdir + '/inspire_dls/1.0/inspire_dls.xsd') + os.stat(target_dir + "/" + target_subdir + "/inspire_dls/1.0/inspire_dls.xsd") + except Exception: + download( + "http://inspire.ec.europa.eu/schemas/inspire_dls/1.0/inspire_dls.xsd", + target_dir + "/" + target_subdir + "/inspire_dls/1.0/inspire_dls.xsd", + ) + + transform_inspire_abs_links_to_ref_links(target_dir + "/" + target_subdir) - transform_inspire_abs_links_to_ref_links(target_dir + '/' + target_subdir) ############################################################################### # has_local_ogc_schemas() -def has_local_ogc_schemas(path): +def has_local_ogc_schemas(path): # Autodetect OGC schemas try: - os.stat(path + '/wfs') - os.stat(path + '/xlink.xsd') - os.stat(path + '/xml.xsd') + os.stat(path + "/wfs") + os.stat(path + "/xlink.xsd") + os.stat(path + "/xml.xsd") if False: try: - os.stat(path + '/ogc_catalog.xml') - except: - f = open(path + '/ogc_catalog.xml', 'wb') - f.write(""" + os.stat(path + "/ogc_catalog.xml") + except Exception: + f = open(path + "/ogc_catalog.xml", "wb") + f.write( + """ @@ -493,65 +569,72 @@ def has_local_ogc_schemas(path): - """) + """ + ) f.close() - os.environ['XML_CATALOG_FILES'] = path + '/ogc_catalog.xml' + os.environ["XML_CATALOG_FILES"] = path + "/ogc_catalog.xml" return True - except: + except Exception: return False + ############################################################################### # has_local_inspire_schemas() -def has_local_inspire_schemas(path): +def has_local_inspire_schemas(path): # Autodetect INSPIRE schemas try: - os.stat(path + '/common/1.0/common.xsd') - os.stat(path + '/inspire_vs/1.0/inspire_vs.xsd') - os.stat(path + '/inspire_dls/1.0/inspire_dls.xsd') + os.stat(path + "/common/1.0/common.xsd") + os.stat(path + "/inspire_vs/1.0/inspire_vs.xsd") + os.stat(path + "/inspire_dls/1.0/inspire_dls.xsd") return True - except: + except Exception: return False + ############################################################################### # Usage function + def Usage(): - print('Usage: xmlvalidate.py [-download_ogc_schemas]] [-ogc_schemas_location path]') - print(' [-download_inspire_schemas] [-inspire_schemas_location path]') - print(' [-app_schema_ns ns] [-schema some.xsd') - print(' some.xml') + print("Usage: xmlvalidate.py [-download_ogc_schemas]] [-ogc_schemas_location path]") + print( + " [-download_inspire_schemas] [-inspire_schemas_location path]" + ) + print(" [-app_schema_ns ns] [-schema some.xsd") + print(" some.xml") sys.exit(255) + ############################################################################### # Main -if __name__ == '__main__': +if __name__ == "__main__": argv = sys.argv[1:] i = 0 filename = None xsd_filename = None ogc_schemas_location = None inspire_schemas_location = None - application_schema_ns = 'http://mapserver.gis.umn.edu/mapserver' - - if has_local_ogc_schemas('SCHEMAS_OPENGIS_NET'): - ogc_schemas_location = 'SCHEMAS_OPENGIS_NET' - - if has_local_inspire_schemas('inspire_schemas'): - inspire_schemas_location = 'inspire_schemas' - #transform_inspire_abs_links_to_ref_links('inspire_schemas') + application_schema_ns = "http://mapserver.gis.umn.edu/mapserver" + + if has_local_ogc_schemas("SCHEMAS_OPENGIS_NET"): + ogc_schemas_location = "SCHEMAS_OPENGIS_NET" + + if has_local_inspire_schemas("inspire_schemas"): + inspire_schemas_location = "inspire_schemas" + # transform_inspire_abs_links_to_ref_links('inspire_schemas') while i < len(argv): if argv[i] == "-download_ogc_schemas": download_ogc_schemas() - if i == len(argv)-1: + if i == len(argv) - 1: sys.exit(0) elif argv[i] == "-download_inspire_schemas": download_inspire_schemas() - if i == len(argv)-1: + if i == len(argv) - 1: sys.exit(0) elif argv[i] == "-schema": i = i + 1 @@ -565,9 +648,9 @@ def Usage(): elif argv[i] == "-app_schema_ns": i = i + 1 application_schema_ns = argv[i] - elif argv[i][0] == '-': - print('Unhandled option : %s' % argv[i]) - print('') + elif argv[i][0] == "-": + print("Unhandled option : %s" % argv[i]) + print("") Usage() else: filename = argv[i] @@ -577,10 +660,13 @@ def Usage(): if filename is None: Usage() - if validate(filename, xsd_filename = xsd_filename, \ - application_schema_ns = application_schema_ns, \ - ogc_schemas_location = ogc_schemas_location, - inspire_schemas_location = inspire_schemas_location): + if validate( + filename, + xsd_filename=xsd_filename, + application_schema_ns=application_schema_ns, + ogc_schemas_location=ogc_schemas_location, + inspire_schemas_location=inspire_schemas_location, + ): sys.exit(0) else: sys.exit(1) diff --git a/msautotest/pytest.ini b/msautotest/pytest.ini index 8085d43173..8ae769f05d 100644 --- a/msautotest/pytest.ini +++ b/msautotest/pytest.ini @@ -1,4 +1,6 @@ [pytest] python_files = *.py -testpaths = misc gdal query renderers wxs sld mspython - +testpaths = api config misc gdal query renderers wxs sld mspython +norecursedirs = php mssql +env = + MAPSERVER_CONFIG_FILE=../etc/mapserv.conf diff --git a/msautotest/query/6907_01.conf b/msautotest/query/6907_01.conf new file mode 100644 index 0000000000..a90b9e0553 --- /dev/null +++ b/msautotest/query/6907_01.conf @@ -0,0 +1,6 @@ +CONFIG + ENV + MS_MAP_PATTERN "." + MS_EMPTY_URL "http://localhost/6907_01.html" + END +END diff --git a/msautotest/query/6907_01.map b/msautotest/query/6907_01.map new file mode 100644 index 0000000000..fc0669fccd --- /dev/null +++ b/msautotest/query/6907_01.map @@ -0,0 +1,32 @@ +# Test 1: mode=itemquery - matching record +# RUN_PARMS: 6907_01_test001.txt [MAPSERV] QUERY_STRING='map=[MAPFILE]&mode=itemquery&qlayer=bdry_counpy2&qstring=ANOK&qitem=cty_abbr' > [RESULT] +# +# Test 2: mode=itemquery - no matching record +# RUN_PARMS: 6907_01_test002.txt [MAPSERV] QUERY_STRING='map=[MAPFILE]&mode=itemquery&qlayer=bdry_counpy2&qstring=ABCD&qitem=cty_abbr' > [RESULT] +# +# Test 3: mode=itemquery - no matching record, MS_EMPTY_URL in config +# RUN_PARMS: 6907_01_test003.txt [MAPSERV] -conf 6907_01.conf QUERY_STRING='map=[MAPFILE]&mode=itemquery&qlayer=bdry_counpy2&qstring=ABCD&qitem=cty_abbr' > [RESULT] +MAP + NAME 'query' + EXTENT 125000 4785000 789000 5489000 + UNITS METERS + + WEB + QUERYFORMAT 'tmpl' + END + + OUTPUTFORMAT + NAME 'tmpl' + DRIVER 'TEMPLATE' + MIMETYPE 'text/html' + FORMATOPTION "FILE=template/6907.tmpl" + END + + LAYER + NAME 'bdry_counpy2' + VALIDATION + qstring '^[A-Z]{4}$' + END + INCLUDE 'include/bdry_counpy2_shapefile.map' + END +END diff --git a/msautotest/query/6907_02.map b/msautotest/query/6907_02.map new file mode 100644 index 0000000000..bb1672be8c --- /dev/null +++ b/msautotest/query/6907_02.map @@ -0,0 +1,30 @@ +# Test 1: mode=itemquery - matching record +# RUN_PARMS: 6907_02_test001.txt [MAPSERV] QUERY_STRING='map=[MAPFILE]&mode=itemquery&qlayer=bdry_counpy2&qstring=ANOK&qitem=cty_abbr' > [RESULT] +# +# Test 2: mode=itemquery - no matching record +# RUN_PARMS: 6907_02_test002.txt [MAPSERV] QUERY_STRING='map=[MAPFILE]&mode=itemquery&qlayer=bdry_counpy2&qstring=ABCD&qitem=cty_abbr' > [RESULT] +MAP + NAME 'query' + EXTENT 125000 4785000 789000 5489000 + UNITS METERS + + WEB + EMPTY 'http://localhost/6907_02.html' + QUERYFORMAT 'tmpl' + END + + OUTPUTFORMAT + NAME 'tmpl' + DRIVER 'TEMPLATE' + MIMETYPE 'text/html' + FORMATOPTION "FILE=template/6907.tmpl" + END + + LAYER + NAME 'bdry_counpy2' + VALIDATION + qstring '^[A-Z]{4}$' + END + INCLUDE 'include/bdry_counpy2_shapefile.map' + END +END diff --git a/msautotest/query/context.map b/msautotest/query/context.map index e21483e440..ae67ba9982 100644 --- a/msautotest/query/context.map +++ b/msautotest/query/context.map @@ -3,9 +3,11 @@ # # REQUIRES: INPUT=SHAPEFILE # -# RUN_PARMS: context_test001.png [SHP2IMG] -m [MAPFILE] -l "bdry_counpy2" -o [RESULT] -# RUN_PARMS: context_test002.png [SHP2IMG] -m [MAPFILE] -l "bdry_counpy2 indx_q100kpy4" -o [RESULT] -# RUN_PARMS: context_test003.png [SHP2IMG] -m [MAPFILE] -l "indx_q100kpy4" -o [RESULT] +# RUN_PARMS: context_test001.png [MAP2IMG] -m [MAPFILE] -l "bdry_counpy2" -o [RESULT] +# RUN_PARMS: context_test002.png [MAP2IMG] -m [MAPFILE] -l "bdry_counpy2 indx_q100kpy4" -o [RESULT] +# RUN_PARMS: context_test003.png [MAP2IMG] -m [MAPFILE] -l "indx_q100kpy4" -o [RESULT] +# RUN_PARMS: context_test004.png [MAP2IMG] -m [MAPFILE] -l "req_fail" -o [RESULT] +# RUN_PARMS: context_test005.png [MAP2IMG] -m [MAPFILE] -l "lreq_fail" -o [RESULT] # MAP NAME 'context' @@ -25,4 +27,16 @@ MAP REQUIRES '![bdry_counpy2]' INCLUDE 'include/indx_q100kpy4_shapefile.map' END + + LAYER + NAME 'req_fail' + REQUIRES '[non_existant]' + INCLUDE 'include/bdry_counpy2_shapefile.map' + END + + LAYER + NAME 'lreq_fail' + LABELREQUIRES '[non_existant]' + INCLUDE 'include/bdry_counpy2_shapefile.map' + END END diff --git a/msautotest/query/expected/6907_01_test001.txt b/msautotest/query/expected/6907_01_test001.txt new file mode 100644 index 0000000000..3f4db3ce69 --- /dev/null +++ b/msautotest/query/expected/6907_01_test001.txt @@ -0,0 +1,4 @@ +Content-Type: text/html + +Anoka:ANOK + diff --git a/msautotest/query/expected/6907_01_test002.txt b/msautotest/query/expected/6907_01_test002.txt new file mode 100644 index 0000000000..1ef38c7a04 --- /dev/null +++ b/msautotest/query/expected/6907_01_test002.txt @@ -0,0 +1,4 @@ +Content-Type: text/html + + + diff --git a/msautotest/query/expected/6907_01_test003.txt b/msautotest/query/expected/6907_01_test003.txt new file mode 100644 index 0000000000..e11fa68333 --- /dev/null +++ b/msautotest/query/expected/6907_01_test003.txt @@ -0,0 +1,5 @@ +Status: 302 Found +Uri: http://localhost/6907_01.html +Location: http://localhost/6907_01.html +Content-Type: text/html + diff --git a/msautotest/query/expected/6907_02_test001.txt b/msautotest/query/expected/6907_02_test001.txt new file mode 100644 index 0000000000..3f4db3ce69 --- /dev/null +++ b/msautotest/query/expected/6907_02_test001.txt @@ -0,0 +1,4 @@ +Content-Type: text/html + +Anoka:ANOK + diff --git a/msautotest/query/expected/6907_02_test002.txt b/msautotest/query/expected/6907_02_test002.txt new file mode 100644 index 0000000000..27450584b8 --- /dev/null +++ b/msautotest/query/expected/6907_02_test002.txt @@ -0,0 +1,5 @@ +Status: 302 Found +Uri: http://localhost/6907_02.html +Location: http://localhost/6907_02.html +Content-Type: text/html + diff --git a/msautotest/query/expected/context_test004.png b/msautotest/query/expected/context_test004.png new file mode 100644 index 0000000000..0f51863b07 Binary files /dev/null and b/msautotest/query/expected/context_test004.png differ diff --git a/msautotest/query/expected/context_test005.png b/msautotest/query/expected/context_test005.png new file mode 100644 index 0000000000..cf36e3b14c Binary files /dev/null and b/msautotest/query/expected/context_test005.png differ diff --git a/msautotest/query/expected/expressions_test011.txt b/msautotest/query/expected/expressions_test011.txt new file mode 100644 index 0000000000..e5b50f56a0 --- /dev/null +++ b/msautotest/query/expected/expressions_test011.txt @@ -0,0 +1,2 @@ +CTY_NAME,CTY_FIPS +Anoka,3 diff --git a/msautotest/query/expected/expressions_test012.txt b/msautotest/query/expected/expressions_test012.txt new file mode 100644 index 0000000000..e5b50f56a0 --- /dev/null +++ b/msautotest/query/expected/expressions_test012.txt @@ -0,0 +1,2 @@ +CTY_NAME,CTY_FIPS +Anoka,3 diff --git a/msautotest/query/expected/rfc62_test001.txt b/msautotest/query/expected/rfc62_test001.txt index 6e2d90e9f7..48964a3cdb 100644 --- a/msautotest/query/expected/rfc62_test001.txt +++ b/msautotest/query/expected/rfc62_test001.txt @@ -5,52 +5,55 @@ Content-Transfer-Encoding: binary - - - 363237.62610408955045148.789110125 - 591752.16423774395386497.208 - - - - - - 493479.37420531,5386074.14118232 495062.336832765,5385983.99124965 496639.674560181,5385894.1616558 498248.095687447,5385802.56185817 499839.824008464,5385711.91271809 501136.55,5385638.064 501467.943141889,5385767.80541868 502638.13038141,5386225.93726688 503053.46464599,5386388.54188931 503331.026,5386497.208 503699.302,5386362.789 503698.47332,5386220.67017644 503689.147461229,5384621.28310618 503685.055,5383919.425 504644.774816817,5383819.88892449 505192.831,5383763.048 506067.396491085,5383051.22448901 506253.563241776,5382899.70025046 506630.795,5382592.665 507778.537,5382437.824 507871.292629229,5382391.32496513 509368.38182872,5381640.82385308 509937.620566855,5381355.46055867 510949.994331869,5380847.95062758 512525.992895043,5380057.89170881 513230.628453252,5379704.65305729 514170.309633563,5379233.58441887 515764.572623581,5378434.3694173 516470.849667691,5378080.30787761 517228.900216171,5377700.29192411 518897.19338599,5376863.96508426 519529.106322551,5376547.18278313 520047.475,5376287.321 520466.380787187,5376350.25746135 522091.309059952,5376594.38690181 522113.824951348,5376597.76969234 523693.324360806,5376835.07389432 525252.915,5377069.387 525268.759120909,5377065.65928362 526793.056620754,5376707.03107132 526885.07181278,5376685.38225025 526949.266,5376670.279 527300.354487204,5375095.81309175 527453.283,5374410.001 527653.748,5373931.762 527552.376,5373516.272 527561.324482355,5373492.93455844 527584.165,5373433.367 527689.675,5373378.304 527467.839,5373137.301 527419.949,5373112.983 527263.544,5372956.911 527236.163,5372848.09 527187.896,5372687.294 527355.022,5372578.487 527551.876,5372306.489 527284.621,5372027.292 526948.617157886,5371912.32001848 526808.709,5371864.447 526695.139,5371883.978 526590.927,5371920.846 526075.661,5371920.909 525551.907,5372120.757 525341.266173163,5371887.38511232 525248.727017776,5371784.85970117 525010.16,5371520.548 523716.552877634,5371602.24673338 523215.28,5371633.905 522261.964,5371345.684 522081.031,5370213.964 522049.140180406,5370143.10519535 521489.688,5368900.048 521544.961,5368616.504 521513.120101352,5368531.18873901 521240.425,5367800.523 521992.925984955,5366919.9380308 522064.973201944,5366835.62758122 523065.189,5365665.164 523666.976011613,5365532.75264644 524448.259809692,5365360.84656802 524886.643,5365264.389 525244.446667801,5365004.31195121 525427.486,5364871.266 526834.242807884,5364987.74375145 528421.99597393,5365119.20778105 530057.692838637,5365254.64149055 531318.261,5365359.015 531669.519146117,5365456.4436309 531899.413299638,5365520.20947626 533278.556856069,5365902.74314843 534241.395,5366169.806 534868.727747756,5366198.30814352 535862.499,5366243.459 536421.444,5366210.286 536454.059088547,5366166.01439868 536898.969905572,5365562.09409084 537405.791,5364874.137 537774.253,5364249.45 538097.711706761,5364153.29342588 538186.691,5364126.842 538319.041,5364034.482 538324.474611288,5363980.41003903 538327.413,5363951.169 538414.038,5363814.04 538395.746,5363692.567 538556.296,5363474.732 538811.359,5362962.664 539721.502142637,5362643.71368574 540222.235,5362468.237 540222.828774539,5362400.67690394 540234.913,5361025.725 539954.577111015,5360403.18325763 539237.043643193,5358809.75711129 538768.842,5357770.022 538904.831920846,5357188.24951072 539282.403957909,5355572.97521305 539282.922,5355570.759 540081.374204488,5353942.74454074 540329.13587328,5353437.56767859 540590.318,5352905.027 540942.106976105,5352331.80678252 541403.832,5351579.452 541417.411,5351552.996 541474.645,5351499.686 541494.378,5351448.573 541624.045,5351037.925 541767.388,5350787.633 541812.104206218,5350737.01131558 541915.439606497,5350620.02885074 542131.328,5350375.629 542342.064,5350459.941 542592.8,5350317.92 542980.498,5349690.624 543341.824,5349263.856 543389.647582808,5349143.8744296 543502.934526602,5348859.65596197 544030.594209357,5347535.84386643 544389.417,5346635.616 544768.189708664,5345907.09214577 545042.706,5345379.093 545073.768,5345257.683 545021.138,5345107.205 545118.353,5345016.884 545179.190362287,5344923.47621679 545339.834,5344676.829 545269.944,5344570.675 545186.589398349,5344588.4800933 545115.225,5344603.724 545081.255,5344466.053 545106.151,5344394.924 545191.755318209,5344356.5039508 545227.844,5344340.307 545298.941,5344346.737 545371.522,5344400.113 545523.83,5344463.388 545586.267,5344417.879 545628.81,5344307.061 545635.73476791,5344288.83903495 545677.475,5344179.003 545516.198,5344179.26 545555.649,5343991.229 545445.555,5343934.775 545421.307,5343871.903 545491.434,5343639.037 545538.047,5343613.163 545681.931,5343700.456 545746.764,5343666.085 545703.861,5343435.096 545706.126,5343306.977 545734.89,5343192.657 545789.228,5343078.85 545910.732,5342898.581 545988.563,5342763.042 546114.709,5342698.909 546115.698565205,5342696.85945804 546147.23,5342631.553 546099.611,5342525.263 546179.368,5342382.332 546158.143,5342277.49 546150.242,5342183.254 546163.392,5342087.953 546233.891,5341968.105 546353.795,5341862.244 546384.093,5341764.612 546371.817,5341675.898 546406.042,5341602.999 546467.242,5341562.122 546531.158,5341491.935 546595.782,5341335.301 546682.801,5341392.514 546731.492,5341367.902 546734.074,5341254.298 546793.797,5341142.706 546796.920124315,5341069.75795911 546800.946,5340975.724 546829.702804815,5340970.51317348 546859.637,5340965.089 546935.417183097,5341071.23316396 546936.136,5341072.24 546994.659,5341132.003 547025.26,5341199.564 546963.581,5341297.553 546887.189,5341353.43 546935.716,5341398.907 547072.874,5341380.582 547160.491,5341339.93 547262.645,5341263.274 547371.941,5341246.27 547411.486,5341304.645 547431.656,5341385.091 547458.37,5341472.693 547509.618,5341562.351 547633.969,5341668.982 547780.999,5341777.041 547863.135,5341848.435 547938.604,5341902.793 547996.069,5342012.268 548007.097,5342074.731 548143.653,5342126.208 548308.86,5342204.793 548387.097,5342223.672 548433.107741179,5342228.82930415 548491.389,5342235.362 548715.885,5342303.656 548870.555,5342262.366 548906.069,5342283.049 548943.59,5342478.201 548975.205,5342520.155 549068.213,5342595.674 549082.311,5342611.542 549106.066,5342631.815 549156.741,5342640.279 549178.145,5342622.246 549222.795,5342635.598 549263.035,5342705.726 549286.127,5342707.16 549404.759,5342610.306 549423.329,5342586.074 549419.404,5342562.883 549425.606,5342537.617 549466.072,5342510.179 549505.77,5342500.024 549596.625,5342514.089 549689.059,5342607.213 549735.331,5342623.671 549807.163,5342642.514 549885.559,5342736.136 549938.37,5342806.687 549971.284,5342840.631 549986.154,5342838.599 550024.735,5342814.544 550035.879,5342814.024 550049.848570131,5342826.35841657 550071.906,5342845.834 550094.243,5342862.703 550318.605327384,5342887.60770346 550332.887,5342889.193 550868.403,5343258.589 551925.594654075,5343445.68418898 553425.443,5343711.118 553578.372584271,5343793.91646471 554224.079,5344143.512 554085.870587265,5344554.99014036 553914.031,5345066.596 553481.9264489,5345394.2815694 552677.609,5346004.234 552609.440410738,5346144.33610868 552346.012,5346685.742 552444.413,5347216.198 552402.526,5347288.068 552361.392,5347278.118 552339.54,5347255.994 552295.374,5347239.533 552289.772,5347243.496 552281.329,5347265.033 552284.446,5347284.823 552276.548,5347314.393 552280.935,5347330.49 552291.325,5347343.862 552283.775,5347357.997 552261.357,5347352.542 552266.636,5347383.777 552267.104,5347400.147 552259.794,5347433.119 552135.332922751,5347756.9139764 551818.987,5348579.912 552011.692122779,5349362.04263356 552311.103,5350577.259 551995.831180082,5350977.01317121 551766.796794742,5351267.42114651 551438.976,5351683.087 551558.184,5352415.97 551736.233514996,5352447.85081675 552226.802,5352535.69 552243.048600333,5352608.64290264 552606.198576243,5354239.3129685 552697.159,5354647.757 553325.020739725,5355090.22467331 554632.112,5356011.36 554909.239293551,5355952.68797318 556570.094131868,5355601.05996 557671.494,5355367.877 557813.151,5355282.853 557852.942,5355215.942 557871.717,5355150.979 557932.772,5355078.108 558020.656,5354938.197 558187.756692178,5354956.78989982 558778.765,5355022.55 558790.328,5355198.369 558702.307,5355270.335 558980.747,5355712.925 559635.379,5355565.659 559677.087,5355376.809 559786.810811494,5355374.80082759 559805.761,5355374.454 560859.984,5355728.689 560814.212227964,5356064.57548428 560813.302,5356071.255 560936.77,5356322.694 561414.838624699,5356616.91326795 562070.552,5357020.461 563038.704053898,5357233.97825157 563335.065,5357299.338 563434.912,5356225.854 564642.203329377,5356187.53414005 566223.008507408,5356137.35881654 567103.531216315,5356109.41070984 567349.329,5356101.609 567838.950266071,5356028.57469323 567893.874,5356020.382 567983.964348441,5356131.18676823 568287.36,5356504.342 569112.243,5356673.332 569443.754407045,5356673.74895058 569985.247,5356674.43 570188.606034177,5356175.6787925 570471.953,5355480.752 570693.19,5355401.973 570753.122,5355168.03 570553.534,5354928.086 570582.743058388,5354564.37549861 570632.193,5353948.626 571113.672375693,5353821.77213622 571321.57,5353766.998 571820.091694902,5352988.91756426 571842.076,5352954.605 572753.430929069,5352767.5145328 573241.44,5352667.332 574122.572,5352472.759 573760.517640225,5351433.58949544 573202.312,5349831.426 573206.581376533,5349773.97250468 573288.533,5348671.14 573541.192540589,5348175.20240659 573650.98,5347959.704 573715.909870876,5346529.39454321 573727.362,5346277.121 574594.340651411,5345907.36682371 575024.331,5345723.982 575406.126598792,5344926.54940408 575677.971,5344358.765 575794.823,5344303.805 575846.914,5344295.233 575882.736,5344300.341 575916.052,5344276.698 575950.266,5344232.068 575942.526,5344193.675 575931.616,5344176.546 575919.753,5344168.977 575904.466,5344139.747 575911.253,5344110.192 575913.739,5344093.859 575929.123,5344084.8 575982.415,5344032.705 576050.58,5343963.515 576139.078,5344071.23 576146.845,5344076.583 576154.723,5344089.04 576178.436,5344135.985 576198.8,5344186.59 576205.981,5344220.345 576268.150525235,5344257.21948135 576433.947,5344355.558 576460.035,5344455.958 576417.133,5344486.881 576399.273,5344526.786 576354.144,5344585.471 576316.658,5344597.013 576278.769,5344623.372 576276.991,5344663.801 576288.047,5344700.696 576291.346,5344731.62 576294.855,5344793.119 576317.462,5344814.419 576321.125,5344913.0 576349.05,5344935.274 576385.209,5344930.2 576414.963,5344941.406 576425.449,5344974.588 576457.025,5345019.169 577270.438,5345017.463 577419.695,5344869.717 577637.723,5344867.429 577638.74,5344807.844 577637.608,5344800.109 577633.787,5344777.823 577646.083,5344556.27 577858.395498627,5344374.82075384 578098.111,5344169.952 577983.545,5344010.28 577870.799266675,5343995.66099251 577339.663,5343926.792 577439.156,5343374.154 577418.045950075,5343349.80729019 577240.295,5343144.803 577351.031,5342737.143 577787.435,5342734.114 577877.676,5342773.635 577914.760715966,5342747.23188922 578338.551,5342445.507 578563.657,5342445.51 578891.533,5342877.409 579539.718,5343074.151 579580.062887345,5343081.82671725 580109.056,5343182.469 580428.643,5343386.14 580570.447,5343424.578 580677.436,5343415.589 580696.864,5343369.234 580882.552,5343338.819 580954.788,5343365.782 581109.486,5343367.669 581126.558,5343356.794 581153.692,5343349.151 581193.740207828,5343304.2287266 581245.307,5343246.386 581503.321,5343237.092 582188.375,5343343.567 582804.217608689,5342272.24544707 582857.38,5342179.764 583410.230499244,5341785.21975707 584115.486,5341281.911 584321.459250725,5340199.72573453 584373.67,5339925.41 584444.052922083,5339936.64709769 585781.454,5340150.172 586052.911303773,5340219.45571218 586060.401197404,5340221.36734848 586482.241,5340329.033 586722.47098628,5340235.02169628 586732.73026337,5340231.00684356 586733.455131214,5340230.72317468 586733.706,5340230.625 586734.346642791,5340230.77208047 587666.252684771,5340444.72153606 587998.941,5340521.101 588074.727157533,5340246.81160393 588103.872,5340141.329 588454.006,5339912.343 589289.403356798,5339559.18325302 589300.922048736,5338697.20336088 589330.88158939,5337083.19477104 589344.840832338,5335466.18659232 589375.799835842,5333832.17777631 589413.759065257,5332205.16868353 589447.718723428,5330598.15973728 589421.677569149,5328983.15297854 589404.637199152,5327394.14613183 589393.595521865,5325750.13889061 589391.554825624,5324141.13150972 589423.51370196,5322505.12249251 589449.47354742,5320910.11388143 589472.432393428,5319277.10519543 589492.391231896,5317645.09663268 589557.327364741,5316038.14876436 589610.247050873,5314432.24530066 589687.166826041,5312827.34054162 589760.086571563,5311223.43592443 589794.004664517,5309590.53503253 589813.924074779,5307985.63306279 589833.843145254,5306374.73141241 589854.761727334,5304754.83021731 589850.690324137,5303335.91779226 589849.684085117,5303211.98796954 589836.604834502,5301638.02294658 589832.518533866,5299924.1285249 589798.437037778,5298307.22945341 589824.356272078,5296703.32672913 589854.276024973,5295110.42310374 589891.711273188,5293825.43772011 589898.886326741,5293578.51503776 589900.694793715,5293498.51986128 589929.132166673,5292256.59471918 589933.561446002,5292093.60451093 589938.92656038,5291897.61628293 589944.665983588,5291687.94137658 589978.174239362,5290612.81826398 589988.033286093,5290296.71219285 589992.999549548,5289628.50289911 589997.657264298,5289007.72209249 590004.831688645,5288699.91846514 590021.925512196,5287966.18961244 590030.902163723,5287416.83060779 590047.888728129,5287100.83929792 590116.712163097,5285889.05999224 590136.447356351,5285541.38202484 590141.319825875,5285482.00858994 590175.239774093,5285070.33194198 590230.150033524,5284431.97369368 590273.753377139,5283924.92451864 590346.768671837,5282820.0795009 590359.934884135,5282321.34384726 590402.762389907,5281209.87528104 590403.198955841,5281188.00091585 590415.115143658,5280689.07781656 590416.300550313,5280640.07923013 590463.878699903,5279545.29749472 590490.045015092,5279050.93621315 590552.560083105,5277945.279267 590571.104668187,5277527.54101025 590576.16388836,5277451.23059324 590642.992486551,5276371.88525474 590677.095635271,5275864.33661944 590741.616737182,5274903.6128942 590756.607487748,5274689.18124283 590780.02667555,5274264.06806792 590821.121166164,5273556.46268782 590844.100980463,5273088.03833184 590859.025397483,5272784.54684905 590866.269046009,5272637.23848383 590905.219199914,5271479.27161332 590935.204816209,5271148.0304548 590944.950154602,5271040.72081967 591043.399631439,5269877.75215533 591053.769301984,5269755.19296268 591076.692479513,5269425.13953795 591110.517197168,5268259.48564049 591117.254888758,5267973.99391934 591128.122845498,5267811.8733961 591206.009888956,5266651.40546997 591199.616494462,5266222.16843626 591198.488342556,5266148.60815838 591175.006180318,5265104.63989 591175.439715822,5265012.45511298 591177.687918502,5263516.49940567 591178.432325836,5263386.50323498 591185.255417681,5262180.038753 591187.055459458,5261890.54726464 591185.737812806,5261770.48835248 591185.389639317,5260657.07797112 591184.567050358,5260286.58616161 591186.251345165,5260169.58869304 591203.585911612,5258692.558237 591206.144707272,5258557.62363551 591231.790581386,5257040.59378715 591239.281180766,5256698.72609417 591269.618002448,5255310.69324746 591290.448603308,5253691.72817665 591305.65503736,5252101.76256354 591326.173869598,5250510.79678628 591291.880300777,5248901.8326817 591296.39843466,5247279.68033507 591193.586980174,5247275.43286786 591221.166060928,5245605.90588963 591242.55956521,5244004.94002282 591286.202814154,5242404.97359231 591309.471500193,5240813.007405 591328.739695874,5239202.04166475 591344.570552771,5237596.07583646 591363.4010812,5235980.11010727 591378.544330248,5234371.1442482 591394.017360582,5232782.18812091 591420.004054301,5231157.24153439 591448.990594695,5229517.29534933 591475.977567139,5227928.34746962 591495.964618956,5226341.39958728 591521.951475128,5224737.45212944 591545.938530749,5223156.50389693 591566.925327205,5221541.55677295 591586.912063263,5219919.60983592 591626.898708537,5218299.78757514 591466.899466999,5218297.69547592 591480.886345409,5216706.71608139 591500.873003762,5215093.76854045 591530.859899174,5213513.81979972 591556.846369643,5211880.87277365 591590.833237315,5210296.92407028 591617.819976923,5208695.97592128 591635.806519539,5207072.02850491 591658.787079717,5205480.07127601 591684.746751559,5203843.08684967 591707.707415759,5202247.10199548 591737.667785504,5200640.11717552 591752.164237744,5199168.19328055 591745.051248586,5199157.97121544 591736.450994764,5199147.03135422 591727.360817793,5199139.1714658 591713.250707976,5199133.66157558 591701.69061102,5199128.86166826 591694.950522966,5199124.78173446 591688.71036928,5199118.07182361 591679.469948723,5199100.29203013 591669.629518109,5199082.05224353 591661.499009181,5199060.75247907 591657.138495057,5199039.52269857 591651.655586978,5199020.88079978 591650.817978316,5199018.0329286 591645.887660254,5199004.72307527 591638.387346142,5198991.37323288 591628.607062769,5198979.09338973 591609.086908203,5198971.29354405 591587.626729705,5198962.36371715 591563.856614487,5198955.82387707 591549.706571326,5198952.96396247 591532.706483829,5198948.07407893 591520.526421268,5198944.57416236 591503.416518085,5198947.18420787 591487.676834431,5198958.85416137 591476.116992589,5198964.40415597 591463.257050205,5198965.75419594 591439.577037757,5198963.40431567 591418.137065166,5198962.85440902 591402.3369922,5198958.64451415 591387.596923142,5198954.67461266 591372.306757534,5198946.71475157 591361.88654159,5198937.07488656 591351.456325752,5198927.43502162 591304.93543812,5198887.46559553 591277.244851213,5198861.24596072 591252.174400459,5198840.7862602 591238.044309966,5198835.94636498 591209.974085347,5198824.48659089 591185.473704708,5198806.90686083 591164.663437088,5198794.24706845 591143.243186502,5198782.22727256 591121.182996363,5198772.62745619 591093.642654176,5198756.32772701 591077.672374188,5198743.5179164 591064.162020583,5198727.87812286 591050.671645469,5198711.34833787 591035.341311237,5198696.33854601 591017.530831238,5198675.11882431 591002.060240344,5198649.51913515 590986.669767733,5198628.77939902 590973.759424895,5198613.57959931 590960.259056729,5198597.27981272 590947.948713249,5198582.09001055 590938.108526502,5198573.56013392 590918.558425989,5198567.75027178 590904.458294847,5198561.14039457 590889.758164789,5198554.52052 590878.218040119,5198548.3906275 590865.947874116,5198540.49075517 590853.017564862,5198526.62094327 590835.706776913,5198492.61134429 590827.656379556,5198475.51154325 590815.27566934,5198445.11188896 590807.865228319,5198426.25210237 590801.604854944,5198410.28228305 590799.154682936,5198402.96236412 590792.974432274,5198392.06249552 590781.944222379,5198382.41263536 590770.844114137,5198376.95273504 590759.913978962,5198370.39284465 590743.933954186,5198367.94293589 590734.783874538,5198363.83301434 590720.763627729,5198352.37318451 590701.123183212,5198332.22346265 590678.922733274,5198311.60375636 590661.822348884,5198294.14399798 590646.401913493,5198274.71425168 590624.981420651,5198252.34455949 590604.671096107,5198237.0347943 590583.300768642,5198221.49503596 590558.060368849,5198202.58532696 590540.330013877,5198186.21556145 590526.889800117,5198176.09571704 590516.419649661,5198168.87583184 590504.739512344,5198162.08594766 590492.529498122,5198160.35601659 590481.579391292,5198154.8961164 590462.528981496,5198136.08638067 590452.04861395,5198119.82658362 590441.59819886,5198101.58680577 590431.067667239,5198078.48707563 590423.507215111,5198058.96729799 590416.736703357,5198037.03754047 590411.006216019,5198016.21776774 590407.195565925,5197988.80805094 590405.235087562,5197968.71825495 590400.83464547,5197949.89845711 590395.204248641,5197932.83864748 590389.583819913,5197914.44885079 590360.542500582,5197856.66953909 590337.021288063,5197803.8301559 590322.27075184,5197780.01045213 590310.39021521,5197756.45073347 590301.83989959,5197742.43090738 590290.779488732,5197724.18113352 590280.779075703,5197705.94135503 590269.868913454,5197698.06147947 590253.21876847,5197690.31162771 590235.548562369,5197679.90180643 590219.688357719,5197669.73197498 590206.158043059,5197655.20217601 590200.9020524,5197647.37190981 590194.337650603,5197637.59239974 590185.677262455,5197620.48260484 590179.526974704,5197607.8227555 590176.976700304,5197596.09288133 590175.116546028,5197589.45295439 590160.376234443,5197574.89316135 590139.905207476,5197529.81369208 590122.754659444,5197505.08400942 590110.984178905,5197483.73427014 590099.853886948,5197470.33445032 590087.693555221,5197455.15465252 590075.353271417,5197441.95483619 590064.343021839,5197430.32499868 590052.562805392,5197419.99515188 590037.91260097,5197409.85531594 590026.242442697,5197401.96544483 590005.472367614,5197396.57558946 589993.272342065,5197394.18566682 589972.602587769,5197402.25567898 589953.18300385,5197417.61561399 589941.803344265,5197430.67553598 589928.463683839,5197443.49546892 589915.783937506,5197452.78543356 589907.204150616,5197460.81539246 589896.374337011,5197467.48537463 589879.214516341,5197473.18539417 589862.824677921,5197478.22541678 589847.684763466,5197480.20546397 589817.164845685,5197480.40559637 589803.08492372,5197482.18564083 589787.234937315,5197481.06572165 589770.215131557,5197487.4257339 589753.295409265,5197497.31571088 589680.976225268,5197524.01576544 589662.106490591,5197533.20575759 589645.596594144,5197535.82580422 589622.536800548,5197542.09584352 589587.437445058,5197565.60576507 589567.907784387,5197577.8857292 589546.078190946,5197592.77567748 589538.838425327,5197601.92561859 589527.948714554,5197613.01555644 589518.259016549,5197624.77548235 589506.189245361,5197633.19545171 589505.049383366,5197638.91540002 589499.559712858,5197652.28529151 589489.909952055,5197661.40524327 589434.07070408,5197687.46522851 589412.131036017,5197699.26520706 589400.071269417,5197707.91517373 589387.341602693,5197720.73510186 589378.831927032,5197733.61501096 589374.672070781,5197739.28497273 589369.252284741,5197747.80491165 589335.242630162,5197758.98494841 589318.732747143,5197762.26498756 589293.742897157,5197766.08505817 589265.763011661,5197768.09515976 589243.223114695,5197770.17523699 589217.07319437,5197770.89534344 589195.01324987,5197771.0054382 589175.523300135,5197771.15552139 589153.043299567,5197768.83564222 589126.173328579,5197767.32577407 589103.603473267,5197771.18583359 589067.693479392,5197767.77602371 589041.923444409,5197763.64617701 589012.183479457,5197762.09632179 588987.733498796,5197760.41644489 588960.273498246,5197757.57659272 588931.003501634,5197754.71674865 588906.01343427,5197749.26691197 588877.943450807,5197747.08705593 588858.973386897,5197742.39718553 588835.763347036,5197738.29732768 588819.913374687,5197737.84740117 588802.893332618,5197734.28751101 588784.433180284,5197725.8476762 588745.252639642,5197698.58812103 588726.862374672,5197685.29833495 588711.012161243,5197674.47851301 588702.962013683,5197667.29862042 588698.641925277,5197663.04868208 588692.011913514,5197661.84872311 588687.741978851,5197664.20871799 588688.892079148,5197668.63866835 588698.782407486,5197683.77847274 588702.562635755,5197693.97835355 588706.832796289,5197701.31826103 588712.403051732,5197712.86812048 588716.793510109,5197733.00789863 588700.933296408,5197722.18807661 588681.903104714,5197711.97826233 588667.862882262,5197700.95843452 588651.992684389,5197690.7986061 588635.402683002,5197689.00869649 588617.772658363,5197686.10880263 588604.8625519,5197680.17891876 588588.432540007,5197677.94901295 588569.392344313,5197667.52920121 588568.968985745,5197667.31239195 588557.8522352,5197661.61931126 588547.992076788,5197653.75943369 588540.762066345,5197652.54947749 588528.412025716,5197649.49956226 588507.092111163,5197650.93964085 588490.662084253,5197648.04974185 588477.872034581,5197644.55983302 588463.171917084,5197637.93996423 588450.931707928,5197627.62012214 588435.541479747,5197616.14030563 588416.051291207,5197605.93049428 588394.591106997,5197595.69069194 588376.280957076,5197587.26085754 588358.440790861,5197578.17102783 588337.000581682,5197566.83123678 588319.900429657,5197558.42139707 588298.460230781,5197547.51160183 588273.419989111,5197534.35184533 588251.399751503,5197521.68207071 588228.729586578,5197512.08226786 588209.209440476,5197503.63243956 588195.699337559,5197497.70255926 588181.739220396,5197491.10268779 588169.469069117,5197483.20282214 588127.08835378,5197447.51337199 588109.338037262,5197431.81361012 588076.167536795,5197406.40401537 588062.727332977,5197396.05418022 588040.007003099,5197379.18445262 587997.189861146,5197355.28233246 587958.036162317,5197333.42528241 587934.705835169,5197316.54555824 587900.945324469,5197290.46597456 587881.355060404,5197276.72620204 587867.284890095,5197267.69635691 587848.304604915,5197253.08659076 587828.074161195,5197231.39690275 587808.333671272,5197207.727233 587783.193123736,5197180.89761988 587766.632839135,5197166.53784091 587752.522488827,5197149.57807775 587745.732257522,5197138.66821992 587736.522042088,5197128.16836874 587730.271910456,5197121.67846324 587716.911795528,5197115.08859059 587694.711369148,5197093.81890817 587675.791005574,5197075.66917921 587662.200554507,5197054.29945952 587646.160169836,5197035.53972414 587622.279769051,5197015.13004106 587608.69953988,5197003.46022203 587589.04913941,5196983.54051516 587574.908610826,5196958.64083484 587565.00829315,5196943.50103515 587549.647782781,5196919.23135408 587540.387403603,5196901.45157881 587526.217157141,5196888.90177197 587518.816939183,5196878.42191328 587513.906830852,5196873.06199065 587475.196042997,5196833.68257137 587466.655723194,5196818.56276583 587456.105228056,5196795.47305158 587447.334793776,5196775.27329955 587426.384069539,5196740.78375027 587410.293298763,5196704.82419429 587398.562542597,5196670.03460656 587380.481562538,5196624.55515828 587366.190803783,5196589.28558758 587347.020127911,5196557.02600837 587327.929317525,5196518.81649047 587314.23855874,5196483.55691752 587296.277646554,5196440.94744036 587285.827234818,5196421.39769053 587275.336907821,5196405.57790241 587258.686522841,5196386.37817774 587240.856106155,5196365.60847489 587227.98572128,5196346.88872802 587212.455244236,5196323.72903949 587199.004821805,5196303.24931373 587185.484489313,5196286.7295474 587173.064104207,5196268.01979873 587168.223898197,5196258.24992236 587163.193747467,5196250.90002183 587144.093191878,5196223.72039212 587129.412808739,5196204.76065684 587115.322662993,5196196.39080917 587096.402530814,5196187.96098466 587068.792084367,5196164.40135765 587050.871800577,5196149.36159726 587039.241604152,5196139.05175853 587031.931475344,5196132.3318624 587023.881323642,5196124.49198137 587015.953105316,5196117.00221901 586992.580754886,5196094.9224347 586964.53051538,5196080.40271676 586951.730491577,5196077.57280607 586939.480530623,5196077.61286298 586930.930460349,5196073.30294781 586919.780208735,5196060.5631325 586897.029712456,5196035.31350178 586872.529340524,5196015.33382462 586835.68847428,5195971.57445331 586813.588136341,5195953.39474664 586794.58788868,5195939.66497915 586784.147715803,5195930.4751241 586769.397436609,5195915.9253453 586755.387185038,5195902.70554921 586744.236920685,5195889.31574148 586730.716613668,5195873.67596848 586719.726349092,5195860.28616011 586712.936126887,5195849.38630597 586703.595872443,5195836.67648281 586694.975680448,5195826.8566261 586683.425585446,5195820.94674245 586665.725424698,5195811.20692794 586622.865243747,5195796.91728017 586582.025195185,5195788.82755819 586559.945052865,5195779.24776306 586542.185001331,5195774.35789842 586526.414894799,5195767.28804722 586511.03465958,5195754.49825415 586493.82445946,5195743.00845621 586473.758613228,5195728.45415584 586473.034191215,5195727.92871298 586460.164032538,5195718.91886859 586447.243726959,5195703.29909382 586431.253494387,5195690.49930414 586414.073240761,5195676.56953205 586398.83302122,5195664.44973183 586382.20284978,5195654.27991781 586362.052757661,5195647.15008869 586339.492672947,5195639.99027143 586326.092639414,5195636.49037208 586313.182545683,5195630.35049818 586297.922356123,5195619.54068464 586239.912275238,5195607.24109084 586213.012355678,5195606.85122332 586194.702459283,5195608.79129025 586175.202527376,5195608.95138161 586160.642644191,5195612.05141839 586143.592665855,5195610.4815163 586121.672741036,5195610.60161962 586105.182824558,5195611.91168447 586012.442814525,5195597.56227868 585983.132887786,5195596.48243003 585966.072919379,5195595.35252344 585942.752828907,5195587.74271535 585919.572762354,5195581.23289501 585870.112760303,5195573.68321133 585796.232735106,5195561.37369507 585746.842854756,5195559.34395277 585712.032814533,5195552.23419481 585679.152811925,5195547.12440644 585661.367196132,5195543.78459015 585634.91243334,5195523.11487374 585607.791931338,5195496.04529199 585587.121714185,5195482.95553059 585567.161562901,5195472.97573272 585551.981493441,5195467.46586432 585533.791404237,5195460.58602501 585505.811518506,5195461.50614952 585483.161563497,5195460.07627352 585441.311455623,5195448.67659626 585432.732356882,5195443.09280206 585365.090631824,5195399.06749319 585316.56012397,5195368.16805768 585280.319737416,5195344.71848361 585239.069391127,5195322.29892302 585208.268998482,5195299.35931787 585074.126805628,5195176.82128407 584917.96486975,5195061.91328176 584889.584452391,5195037.91367918 584867.854023639,5195014.45403853 584858.823763025,5195000.87422927 584852.243456499,5194985.56442674 584836.613141685,5194968.36468898 584831.853038493,5194962.78477256 584808.762843308,5194949.88502505 584793.042671666,5194939.29521655 584780.952478743,5194928.31539452 584746.041678369,5194885.2660314 584726.721244485,5194861.83637984 584674.790426929,5194815.0071424 584657.19035791,5194808.80729629 584640.680465025,5194810.99735394 584619.990524693,5194810.26746383 584603.050358897,5194799.65766237 584503.478615705,5194701.21922258 584468.627719959,5194653.30991578 584446.957195369,5194625.00033104 584427.046745276,5194600.46069678 584404.066381612,5194579.41104001 584391.346232398,5194570.19120361 584291.034924438,5194491.15256438 584184.023492333,5194404.74404223 584162.253119124,5194383.26438593 584139.89272035,5194360.4547473 584128.562297041,5194338.46504452 584119.651874604,5194316.94532453 584108.931435569,5194294.30562596 584084.71089062,5194264.19607715 584009.419376432,5194178.89739061 583968.488572612,5194133.32809687 583928.488177406,5194107.18858604 583893.357732599,5194079.56906716 583883.694145455,5194074.67601182 583867.38755773,5194066.41934326 583846.727706804,5194052.84287567 583836.52725215,5194046.13972265 583756.755905956,5193967.18099636 583724.295297683,5193932.10154781 583711.624848325,5193908.32187421 583691.254414347,5193883.78224845 583591.823615985,5193826.60338736 583570.793274388,5193806.24371974 583557.39301044,5193791.05395607 583533.972641526,5193768.89432087 583511.022243702,5193745.42469792 583501.842204663,5193741.76478552 583489.182202116,5193739.1648793 583468.771606054,5193706.6853432 583451.931093753,5193678.88573722 583421.77064221,5193651.33619733 583390.350062707,5193617.37673521 583358.459490698,5193583.63727348 583295.798276023,5193512.85838203 583274.147510384,5193471.75895 583259.886959878,5193442.44934912 583183.265656295,5193364.20061636 583141.784560925,5193302.98151292 583130.984022225,5193274.82188234 583114.903491413,5193245.93228762 583092.602798409,5193207.91282721 583051.911650411,5193144.06375114 583022.851151542,5193113.8842399 582995.61085177,5193093.66460846 582981.090696483,5193083.09480269 582973.420440263,5193069.0949991 582963.230126083,5193051.75524605 582965.710029067,5193047.59527934 582960.259836966,5193037.15542444 582950.669525145,5193020.04566576 582942.259245083,5193004.71588108 582929.178742569,5192977.62625225 582917.718302239,5192953.87657773 582900.987842822,5192928.05695432 582878.067409964,5192902.16736469 582811.746262828,5192832.21849791 582783.935916247,5192809.34890141 582762.175780734,5192798.0191439 582742.675853992,5192797.30925566 582726.855834484,5192792.89938923 582728.165679079,5192785.63946347 582723.335472528,5192774.54961328 582716.255239147,5192761.65979524 582704.155077147,5192751.1299776 582683.535028339,5192744.22016494 582667.214852815,5192732.09038784 582641.194550911,5192711.66075561 582619.324345211,5192696.81103885 582597.054055172,5192677.75137156 582578.393786582,5192660.5216646 582522.193068794,5192612.99249891 582493.15276908,5192591.8628919 582455.592574425,5192573.92329501 582352.581983529,5192521.784435 582331.8718484,5192510.47467376 582311.941678437,5192497.62492575 582296.911384177,5192479.78520769 582281.851139437,5192464.35546273 582252.572755061,5192449.44172849 582246.710938041,5192446.455854 582218.130851991,5192435.69612955 582176.900740979,5192420.79652024 582087.280198283,5192373.47753914 582058.77999275,5192356.76788231 582023.069747915,5192336.42830578 581955.249275542,5192297.34911592 581865.088646742,5192245.18019697 581831.138468663,5192228.39057209 581808.058491843,5192224.11074617 581774.088363572,5192209.7510941 581708.067913297,5192171.80188511 581682.717725523,5192156.46219784 581648.177317825,5192127.98271051 581552.036389063,5192058.75402492 581521.216055931,5192034.73446767 581494.055645024,5192007.68492526 581462.6652673,5191981.23539948 581436.664922932,5191957.72581081 581419.114809399,5191947.7860208 581407.104511649,5191929.97629043 581400.534422889,5191923.93639561 581393.864259675,5191914.14654425 581389.124135873,5191906.79665439 581379.463924818,5191893.87685533 581371.613718802,5191881.64703847 581363.853609133,5191874.25716575 581351.133483073,5191864.82734372 581331.763370172,5191854.41756959 581310.553309983,5191846.18778071 581291.123294657,5191840.63795137 581267.453294473,5191834.79814878 581248.683201565,5191825.50835878 581234.11279107,5191818.05308999 581231.463031061,5191812.69860067 581220.142829084,5191799.75881157 581202.792409343,5191774.37919856 581189.201998844,5191750.3795491 581182.131764421,5191736.8397436 581161.351287257,5191707.6701935 581134.22107282,5191690.10054557 581094.240906154,5191671.69097873 581060.990822217,5191659.11130778 581013.660822823,5191647.23170708 580971.870897801,5191640.48201675 580927.510968046,5191632.83235118 580879.07083546,5191613.87283887 580844.730571352,5191591.79328453 580798.870197524,5191561.18389313 580753.92957731,5191518.24463966 580717.929110997,5191485.33522101 580701.898740805,5191462.40557576 580688.208481239,5191445.6858457 580679.778474079,5191443.14592222 580664.348773884,5191454.40587812 580653.504886832,5191448.80186727 580648.578693681,5191446.25606061 580633.148334579,5191423.99640466 580622.667795934,5191393.8668123 580612.717354449,5191368.80715835 580595.957193304,5191356.23739794 580566.72717941,5191347.9076584 580551.667152948,5191342.6278041 580532.436852851,5191322.29814781 580509.106581813,5191302.35851017 580485.446584917,5191296.30871331 580443.066407771,5191276.11918598 580403.986033909,5191246.6997477 580350.455650314,5191212.90044224 580282.635433514,5191183.77116369 580205.8351252,5191147.45202046 580143.014865834,5191117.28272746 580078.424565554,5191084.44347641 580048.064015281,5191047.87407583 580029.533560725,5191019.40451381 580004.983328769,5191000.76487116 579967.953262509,5190987.26523939 579923.323081154,5190965.71574531 579868.462645619,5190928.15649751 579835.761993633,5190885.38718536 579816.671490524,5190854.03766205 579793.510983096,5190821.3081784 579752.440480473,5190783.48145969 579746.140396182,5190777.67896152 579676.829948938,5190735.07985899 579630.659385306,5190692.7906212 579564.698451875,5190625.53179203 579531.737954913,5190590.25239741 579510.39743232,5190556.89291362 579492.626984608,5190528.4333517 579465.656543213,5190497.64387059 579439.936264655,5190475.69427822 579407.555802436,5190442.1848611 579362.204921486,5190382.92582383 579339.744278964,5190342.71642941 579321.303922697,5190318.65682098 579295.373732555,5190301.10717924 579263.973593102,5190284.59755719 579237.083257912,5190259.09801555 579207.19268387,5190220.11865133 579181.76199461,5190176.3393184 579152.311654602,5190149.70980606 579110.751401464,5190124.02035368 579063.201085565,5190093.18099791 579044.428208018,5190081.66904062 579019.090823164,5190066.13157752 578966.180426366,5190029.27232584 578922.870091355,5189998.49294618 578888.639691135,5189966.94352281 578862.559068552,5189926.0241635 578838.52873908,5189901.23460032 578815.538645213,5189889.24487867 578789.168433249,5189869.93526434 578763.268194193,5189849.30566317 578744.388260847,5189847.06580132 578739.028178565,5189841.0459048 578730.088028998,5189830.34608527 578722.417797773,5189815.68630555 578714.157532672,5189799.03655312 578703.397418341,5189789.63672896 578684.507498179,5189788.06685941 578669.177653521,5189791.61690765 578656.517661476,5189788.13702409 578638.957564492,5189777.5472545 578621.567441753,5189765.62749988 578599.897194325,5189745.71786623 578574.547025596,5189728.84821818 578547.887013065,5189719.89848327 578514.616975632,5189707.54882835 578480.017123221,5189704.66906801 578451.617018215,5189690.18940999 578426.157008175,5189681.69966285 578404.137254432,5189688.0197177 578390.75721403,5189681.66987328 578363.196990006,5189661.02028473 578327.946982147,5189649.54063194 578299.937171879,5189650.94078151 578278.577344653,5189653.52087737 578266.007222363,5189642.99107864 578252.697079807,5189631.13130036 578236.427081023,5189626.07145793 578210.387042809,5189615.80173633 578202.66688166,5189604.68191607 578190.586708135,5189591.51214648 578172.586592704,5189579.59239713 578148.41646721,5189565.16271486 578125.736166164,5189541.71313253 578105.806005074,5189526.67343263 578095.466141187,5189530.73344535 578078.346282794,5189532.93352092 578044.546143635,5189514.63394327 578024.105863996,5189492.97432665 578006.305463845,5189465.61476322 577980.784908734,5189427.3553778 577969.58454528,5189404.05572625 577956.004146988,5189378.08612131 577946.473985791,5189366.26632124 577928.184078295,5189365.36644178 577905.774027909,5189355.37669693 577875.223760487,5189330.94717567 577852.283608033,5189315.20750383 577823.443279063,5189287.92800728 577813.893143505,5189277.43819169 577794.103006342,5189263.5084794 577775.96288833,5189251.14873826 577752.612670999,5189231.65911498 577737.782344154,5189208.9794792 577720.962045222,5189187.14984524 577697.601857313,5189169.20020383 577674.55185403,5189161.41043743 577643.621920768,5189154.83070399 577613.981867357,5189142.10103753 577600.976878164,5189133.86534911 577554.261538406,5189104.28185795 577525.361292531,5189081.19231351 577506.271013892,5189059.55269228 577487.170755922,5189039.02305776 577467.220639836,5189025.97333749 577445.970652165,5189019.52354485 577439.016374108,5189014.65756724 577416.430456434,5188998.85397575 577388.810326058,5188982.39434393 577346.119976504,5188948.76501319 577331.049773146,5188932.47530347 577324.259372818,5188908.13564167 577317.289001535,5188885.32596236 577306.058691942,5188864.45628539 577292.998421472,5188845.10660111 577277.037984339,5188815.56705901 577256.837573067,5188785.97754359 577235.217266854,5188761.66797259 577231.376946104,5188742.64822839 577223.136663936,5188724.23850369 577194.026727023,5188717.68876193 577171.666606075,5188703.28907487 577143.046180313,5188669.84965918 577122.645849081,5188644.45009502 577118.845473407,5188622.34038885 577112.545013641,5188594.70076574 577100.804574992,5188566.32118521 577082.344269207,5188542.93158509 577060.873958322,5188518.18202034 577039.153780593,5188500.70236827 577017.503733784,5188490.49262684 576997.663457883,5188468.19302251 576976.863053085,5188438.37351648 576958.882921322,5188424.6937953 576941.412707191,5188406.60412517 576925.372389443,5188383.24451097 576907.621924083,5188351.04501599 576887.501422347,5188315.94557151 576869.330921085,5188281.53610671 576850.410409065,5188246.22665786 576832.109885924,5188210.48721068 576808.439286293,5188168.50787388 576793.04890039,5188141.40830288 576769.77857616,5188114.86877432 576744.998475145,5188100.21910916 576718.308520516,5188093.03936414 576697.738433013,5188080.64964511 576674.428173853,5188057.64007408 576638.34786194,5188026.97067752 576595.637561303,5187994.44134583 576556.527286507,5187964.62195867 576523.347143508,5187944.34241699 576484.18693344,5187918.04298745 576452.246733115,5187894.92347366 576418.75640237,5187863.84406828 576390.546038795,5187832.8346292 576380.555688208,5187809.33498276 576375.655168337,5187778.18539894 576365.674810111,5187754.23575815 576353.144640668,5187739.96601379 576327.394423762,5187718.02644793 576309.174412461,5187710.51665601 576271.234189423,5187683.5772295 576240.402110655,5187656.93773156 576233.124068803,5187657.72787386 576225.834239865,5187660.05797394 576214.87431734,5187653.30825299 576198.634460779,5187644.93864603 576184.04461,5187638.5789846 576162.99478831,5187627.28949963 576146.354664754,5187603.26009628 576127.614756088,5187589.35060327 576106.594903317,5187576.30113996 576087.80507291,5187566.80159257 576062.475388892,5187558.98214016 576025.475953312,5187553.43286636 575998.106405775,5187551.32337852 575975.586768737,5187549.05380663 575954.31706723,5187544.37424284 575939.887183307,5187536.25460088 575929.737169917,5187525.10492104 575914.148521236,5187515.43169817 575912.317292537,5187514.29536597 575885.76744941,5187496.0960658 575861.527708176,5187486.08662179 575835.570282122,5187479.34088602 575831.208113,5187478.20725898 575808.84826181,5187463.81783671 575806.938006683,5187447.24807886 575805.357915364,5187440.398193 575803.077763077,5187429.33837247 575797.297703652,5187420.00859235 575791.927682993,5187413.31877177 575778.117784823,5187404.98912166 575762.437985094,5187400.379458 575738.178271836,5187391.91999511 575718.848555843,5187388.36038309 575706.768734994,5187386.23062436 575689.089024546,5187384.68095779 575658.259512094,5187380.98155176 575644.209726034,5187378.8218284 575618.250104463,5187373.86235177 575601.190352471,5187370.56269623 575581.200725273,5187371.4130405 575568.94094971,5187371.69325468 575548.361309906,5187371.21362617 575525.871638659,5187366.96407902 575486.642179172,5187357.65489286 575454.592496697,5187342.91564761 575445.582567783,5187337.72587297 575423.26285158,5187331.05635336 575400.373114675,5187322.60686632 575379.913304209,5187312.42735793 575363.673449834,5187304.0677517 575351.613609611,5187300.82800672 575337.753766715,5187295.57831905 575305.894027984,5187277.75910953 575294.484111203,5187270.77940017 575278.924141491,5187256.46985694 575264.544193081,5187244.60026201 575247.944219052,5187228.96075407 575232.384245731,5187214.43121369 575219.184318711,5187205.00156711 575211.97438135,5187201.16174364 575193.004376827,5187181.30233112 575179.86436086,5187166.80274745 575169.694380349,5187157.41304659 575163.294344543,5187148.73326979 575153.684407833,5187142.4435199 575138.614587,5187137.18385408 575123.334857743,5187136.98412819 575096.555336425,5187136.87460556 575070.565739892,5187133.2451133 575037.186251402,5187128.19577032 575001.006709423,5187117.15655273 574970.657155948,5187111.48716378 574943.557441657,5187099.89779182 574904.487756607,5187077.57876819 574888.307822264,5187064.58921988 574856.727897893,5187036.19014004 574844.997800766,5187018.40057331 574831.507654882,5186995.96109664 574820.837527609,5186977.52151932 574811.487438081,5186962.63187371 574799.147355995,5186945.06231515 574790.837282459,5186932.17262581 574786.057271899,5186926.59278133 574777.657321941,5186920.75300454 574766.21744136,5186915.7632711 574751.767587608,5186909.19361117 574728.857876346,5186902.06410885 574690.288321683,5186887.69497666 574663.758652189,5186879.205556 574639.70885492,5186865.89615218 574627.71890812,5186856.48648449 574599.569001107,5186832.53728825 574572.749105064,5186810.59804301 574546.379212499,5186789.31878148 574508.799314281,5186755.99987188 574479.069310937,5186724.76079637 574461.329265485,5186703.59138008 574449.419203712,5186687.56179498 574434.629200966,5186671.942256 574423.229255771,5186663.20256961 574409.409361287,5186654.87292114 574395.229347899,5186639.26337124 574383.249390361,5186629.19371206 574366.329646117,5186626.33404961 574356.119721672,5186620.03431121 574344.139752869,5186609.30466043 574331.169710523,5186593.26509453 574320.509570112,5186573.94552904 574310.609420016,5186554.85594712 574302.489280041,5186538.21630248 574290.109257948,5186523.95670362 574277.619173183,5186505.93715436 574257.768923824,5186470.62795526 574256.088764186,5186459.58812502 574240.768665721,5186437.78867416 574232.718430034,5186415.63909819 574227.588301466,5186402.77935251 574223.684064193,5186395.95814203 574222.248237434,5186393.44956588 574219.528073623,5186381.06977117 574213.0080005,5186369.970028 574205.397988375,5186361.27027388 574195.19804165,5186353.65055226 574190.40805513,5186349.4006915 574179.048064586,5186338.01103835 574169.408172286,5186334.14125926 574163.408196148,5186329.22142858 574157.058097245,5186316.79169929 574153.767894392,5186301.5319513 574153.857756445,5186293.60205016 574151.067688796,5186286.73218696 574149.907644965,5186282.96225541 574144.607531272,5186270.77250437 574138.617551084,5186265.62267646 574127.987581958,5186256.23298504 574118.487497906,5186241.34334316 574110.377347342,5186224.04370704 574105.847197163,5186210.53395904 574098.957013427,5186192.58430942 574092.09679139,5186172.43468715 574081.416675663,5186154.44510569 574083.456533079,5186148.29514722 574068.116470541,5186128.48567201 574053.696569537,5186119.04604899 574030.336646766,5186098.90672117 574017.336644795,5186085.0771285 574007.776649399,5186075.25742362 573992.766736471,5186064.48782808 573975.906909633,5186056.77822679 573958.987178643,5186054.5885566 573929.17770868,5186053.99909622 573912.917878793,5186046.73947856 573900.307957246,5186037.98981465 573884.858041081,5186026.55023558 573867.528045388,5186008.48077421 573860.607897058,5185992.51110036 573855.88780401,5185982.09131682 573848.427578628,5185961.05171695 573845.65748094,5185952.4218759 573840.337398661,5185941.99210323 573832.127398473,5185933.29236023 573820.147431741,5185922.55271045 573786.547618673,5185897.88362363 573762.367914731,5185878.61168353 573762.107728511,5185878.40430741 573733.297905499,5185858.20507846 573718.858039897,5185850.74543113 573703.808189165,5185843.50579192 573692.608182484,5185831.2361478 573685.428194412,5185824.31636394 573660.758422137,5185811.44696815 573628.128920935,5185805.96762079 573592.949439425,5185798.92833884 573543.569963968,5185777.14949795 573501.390442618,5185760.32046563 573462.590996195,5185751.46127168 573439.081290502,5185743.68179077 573403.541672717,5185728.2426223 573377.901794639,5185708.08333696 573358.171803147,5185687.56395061 573344.311548117,5185657.84457637 573339.551509464,5185650.50475482 573333.161466353,5185641.16498787 573326.581479419,5185634.91518501 573318.771533291,5185629.74539042 573309.131642629,5185625.87561202 573284.772058087,5185624.25606823 573250.312617559,5185620.30673469 573228.37300829,5185619.81713326 573215.023289799,5185622.08734309 573185.563951017,5185629.44777621 573161.744458162,5185633.78814689 573141.714885788,5185637.50845768 573117.965297806,5185636.33889724 573096.815625442,5185632.98931808 573081.76577971,5185625.9696766 573067.9358897,5185617.65002987 573051.056095696,5185611.71040739 573035.98627288,5185606.01074949 573022.716444046,5185601.88103941 573002.656711044,5185596.12147153 572985.386830585,5185584.67192629 572963.756998424,5185571.39248236 572943.377080221,5185554.38306366 572924.327179547,5185539.82358999 572911.707271822,5185531.73391885 572901.207333351,5185524.10420395 572880.55757392,5185516.13467496 572867.937677509,5185508.70499545 572847.487858503,5185497.435505 572829.298017428,5185487.28595987 572818.508054542,5185477.89627266 572801.708151257,5185465.5667305 572790.338157615,5185453.73708484 572780.778161579,5185443.70738383 572772.43811722,5185432.13768065 572764.177963032,5185414.17805757 572758.287840847,5185400.64833557 572754.777739596,5185390.90852264 572750.067626138,5185379.15875683 572744.217451047,5185362.54907342 572738.287389721,5185352.55930701 572733.147254315,5185339.04957137 572725.527051387,5185318.88996497 572720.17700194,5185310.22017136 572713.006996727,5185302.20040205 572705.207043887,5185296.59061328 572699.197088756,5185292.77076963 572690.017179593,5185288.25099167 572674.987297333,5185279.02137857 572664.197346232,5185270.29168318 572650.427374128,5185257.11209795 572635.39749963,5185248.33247916 572621.546562286,5185228.35492222 572613.967367093,5185217.42325747 572608.627317879,5185208.76346365 572603.297249695,5185198.99368382 572597.947200692,5185190.33389019 572592.607151353,5185181.66409651 572584.827157427,5185173.63433838 572572.277163765,5185160.47473119 572555.477250493,5185147.47519813 572542.317260473,5185133.86560767 572526.587313234,5185120.00606647 572516.427310152,5185108.85639088 572505.687287752,5185095.93674831 572494.997189865,5185078.60716117 572483.936986799,5185054.65766523 572476.846857566,5185039.3579877 572470.436630338,5185018.9983626 572458.606452552,5184995.69887223 572447.936321116,5184976.38931013 572440.136361488,5184970.33952724 572430.476502698,5184968.23972725 572418.986688215,5184966.7799519 572403.116945418,5184964.82026146 572389.187197395,5184964.65051338 572372.887436452,5184961.15085034 572342.467763219,5184947.55156953 572323.748027372,5184942.91196447 572296.988251046,5184927.1626456 572282.308304408,5184914.41307181 572267.018380139,5184902.32350055 572252.92843413,5184890.24390767 572237.618324172,5184867.12447783 572219.168208048,5184840.2251527 572207.458062935,5184818.91563524 572190.327986332,5184795.77623844 572178.657792256,5184771.59675703 572169.267545851,5184746.78724279 572164.327348991,5184729.74754935 572154.397015803,5184699.19811825 572137.876928713,5184676.06871057 572122.586986774,5184662.87915372 572102.457140098,5184650.06967892 572085.437329816,5184642.80007745 572067.147412785,5184627.81059757 572047.547445249,5184608.39119792 572025.507540646,5184590.04182844 571995.677878035,5184577.56252377 571969.448205679,5184568.42311176 571945.658459481,5184557.5536781 571921.858724659,5184547.34423621 571899.369047788,5184542.00470847 571856.839805398,5184540.61549006 571838.610017755,5184533.33591069 571813.510214286,5184517.60656298 571801.360275586,5184507.97690457 571785.430190751,5184485.51747845 571768.900105802,5184462.38807174 571759.609937469,5184442.2084972 571750.369675713,5184416.51899238 571739.829370916,5184386.83956208 571727.449125759,5184358.69014527 571716.348757412,5184324.60078161 571711.858339244,5184294.78124444 571702.387774686,5184250.78197852 571698.007326965,5184223.70793833 571692.236908138,5184188.04296499 571678.616515879,5184149.73370086 571671.196232769,5184124.72415482 571653.976058211,5184095.4148402 571644.785951899,5184078.9852161 571633.665821655,5184059.00567224 571627.515648978,5184041.95600142 571624.32529639,5184017.43637308 571618.724969507,5183991.79680247 571600.834696716,5183955.85758511 571590.314566998,5183936.54802198 571576.844376597,5183910.36860005 571562.614218627,5183885.27917787 571549.824119512,5183865.27966455 571528.394200569,5183846.50029121 571510.874258443,5183830.64081007 571488.834350841,5183811.85144794 571460.724580372,5183794.54217623 571438.744804931,5183783.6927113 571418.71503086,5183775.07318267 571398.545233649,5183764.91367635 571374.075382273,5183746.76435002 571351.605678971,5183739.66484594 571326.02591813,5183725.68548619 571294.916159008,5183705.68630341 571271.656297158,5183688.21694678 571247.816405377,5183668.30763197 571225.166521477,5183650.17827293 571204.37654095,5183628.31892831 571187.376704931,5183619.29935054 571158.087127232,5183612.1199707 571132.577487631,5183605.42051659 571110.027889609,5183604.49093501 571096.658200753,5183608.30112706 571077.838611777,5183612.05141812 571066.860652575,5183613.62728872 571065.088878364,5183613.88162442 571045.059311418,5183617.61193752 571026.329599271,5183614.08232049 571007.929833334,5183607.69273429 570992.639892787,5183594.28318229 570968.310070027,5183577.89383158 570945.090146329,5183556.67452303 570926.720122775,5183534.84513493 570909.489964588,5183506.19581403 570898.469905883,5183490.41621569 570884.259714622,5183463.12682293 570871.929610055,5183443.12730254 570859.719540318,5183425.34775146 570846.919679593,5183419.45805811 570836.619872268,5183419.55824262 570823.870150332,5183422.05844045 570813.530395015,5183425.23858606 570801.42062091,5183425.31880348 570783.120919982,5183422.89916471 570764.2611817,5183417.609573 570747.221395223,5183411.44995965 570725.851603927,5183400.17049034 570690.411847401,5183375.2814501 570663.581951345,5183351.59223917 570649.991933264,5183335.33269375 570633.58189381,5183314.63325641 570616.351942797,5183298.33377725 570588.892099255,5183277.06454677 570566.412398741,5183269.96504396 570546.832623008,5183261.57550544 570520.002940305,5183250.67613015 570490.723123479,5183228.94693868 570476.09310321,5183211.34742958 570470.502975612,5183197.39771027 570463.012791271,5183177.89809679 570450.762775238,5183163.20850729 570436.862986975,5183160.39879449 570420.363293979,5183160.41909218 570403.433561554,5183157.57943449 570392.343604713,5183147.74976147 570381.293581186,5183133.94013905 570372.193558583,5183122.37045255 570363.553516521,5183110.14076626 570356.72345227,5183098.6010384 570353.033381187,5183090.17121374 570351.123120402,5183072.29147877 570344.392915325,5183052.3618573 570329.633077584,5183045.58221136 570320.673286362,5183048.12234047 570317.483348693,5183048.30239578 570306.073631865,5183052.5825467 570291.53391412,5183053.29280021 570269.584314517,5183052.81320292 570248.914589126,5183046.17366197 570234.244833749,5183044.46394904 570216.075164516,5183044.02428297 570199.585453605,5183042.95459467 570171.705985217,5183043.73508826 570156.456211215,5183040.2454088 570133.966519518,5183033.58590106 570114.436664,5183020.34642481 570100.956704569,5183007.62683256 570088.6667523,5182996.67719599 570075.836711623,5182979.76764614 570063.006678291,5182963.29809065 570051.936692886,5182951.70844035 570046.406474163,5182932.2387917 570043.22631414,5182918.96902053 570037.686124739,5182901.25934935 570029.036094905,5182889.69965498 570011.416284919,5182881.33008158 569989.51660509,5182876.01054617 569971.256854339,5182870.50094743 569939.027419555,5182868.36155772 569912.227910176,5182867.83204905 569892.238285956,5182868.03240783 569869.6786984,5182867.55282187 569847.729092229,5182866.63323056 569827.04937914,5182860.66368159 569804.609618452,5182849.81422754 569779.479856731,5182835.85486237 569774.559838523,5182829.18503757 569764.859821277,5182817.16536839 569755.579832649,5182807.35566304 569742.139822776,5182791.54611053 569735.459749831,5182779.55638639 569726.179561524,5182757.61683796 569716.389662433,5182752.65707917 569693.829857317,5182738.93766465 569677.890002877,5182729.71807223 569658.340171398,5182717.79858005 569637.040278193,5182700.13919382 569613.770413978,5182681.9998495 569593.040564829,5182667.65041023 569570.490745804,5182653.06100704 569550.370874612,5182638.05156535 569530.66085104,5182614.23223034 569515.300790584,5182593.10278183 569506.574549822,5182570.92934209 569505.450563208,5182568.07328413 569496.190324888,5182543.04377578 569483.800086812,5182514.46437006 569470.38003798,5182496.22484917 569455.590036359,5182479.29533614 569443.369976415,5182461.73578477 569432.33109862,5182443.61244232 569426.729838928,5182434.41643985 569418.059619319,5182411.16689793 569425.899303846,5182400.88688907 569425.239174971,5182392.28701238 569425.178835684,5182371.5572819 569420.788696159,5182358.05753622 569413.338446781,5182334.37797781 569408.898170493,5182312.4883417 569398.477893109,5182283.70890316 569389.037499794,5182248.97952395 569374.22707952,5182206.47034284 569358.22686966,5182175.41103508 569355.026748154,5182164.35123632 569337.386753503,5182144.52181292 569314.727090957,5182139.19229277 569300.837283674,5182135.06259808 569278.337618193,5182129.73307506 569238.517916471,5182102.37415154 569227.607912969,5182089.67451393 569210.987946997,5182072.72503497 569194.537949091,5182054.01557576 569177.327983405,5182036.39611626 569162.577910712,5182015.05666038 569151.587807978,5181996.18710433 569145.247470781,5181968.32758047 569142.757177753,5181947.57789462 569143.14683113,5181926.85815611 569144.856517674,5181909.67834777 569148.37618133,5181893.17849775 569151.335804888,5181873.58869793 569156.595335077,5181850.93889601 569163.734739796,5181822.78913121 569178.053711115,5181776.42947198 569185.732982948,5181740.79979417 569193.362331326,5181709.79005736 569197.411873017,5181686.4702859 569203.351292579,5181657.87054849 569208.710889164,5181639.41069024 569212.82034998,5181611.23098056 569220.369598451,5181574.05132492 569226.309006979,5181544.79159591 569236.498332537,5181515.36179181 569260.446996192,5181461.39205525 569267.566642848,5181448.03209877 569276.616097779,5181425.20222977 569285.485599333,5181405.01232983 569296.295093732,5181386.62237129 569305.314592333,5181366.43246856 569312.504136087,5181346.89259067 569320.913656922,5181327.36269043 569328.003140948,5181304.07286282 569338.67240601,5181271.56308934 569347.661955572,5181254.463147 569363.331126925,5181222.01328165 569380.030329522,5181192.66335738 569382.568093636,5181152.94309365 569371.969329998,5181122.48191173 569359.216991597,5180965.2966766 569356.466493937,5180931.79715987 569400.714079377,5180835.79759475 569406.088560822,5180810.42282477 569470.210304718,5180686.2670101 569494.709058415,5180638.73592729 569517.958036324,5180603.42345928 569528.45725426,5180567.98622535 569551.956060471,5180522.54888325 569565.080144887,5180482.04916657 569632.701739862,5180353.29959366 569635.451395395,5180335.54977244 569643.076210057,5180333.11216466 569656.200418968,5180300.23734905 569788.693776375,5180050.3631495 569791.44343132,5180032.61332794 569866.564916472,5179906.48857881 569890.063717623,5179861.051234 569923.687200949,5179808.11380027 569952.435481921,5179737.30168549 570019.932231169,5179618.73947505 570020.057060485,5179608.5521038 570048.555680866,5179558.11473047 570100.428142559,5179464.73998058 570152.175857315,5179386.6150362 570165.05024202,5179364.36508607 570372.665308705,5179005.67838195 570398.414229224,5178970.49086053 570497.034354773,5178791.30384626 570507.408819459,5178771.11641432 570517.658412031,5178758.49138775 570530.657616301,5178725.67906924 570556.406575207,5178692.92901552 570572.030685854,5178657.55418139 570721.773641377,5178407.99212157 570752.772371449,5178367.74206594 570752.897157919,5178355.05472589 570794.270602216,5178309.74204377 570804.76993574,5178281.92970606 570828.143853053,5178244.11725905 570838.393529426,5178236.61716619 570843.643132023,5178218.86729637 570895.640990572,5178150.86720761 570906.140448343,5178130.55477369 570969.012585702,5178032.05487325 570982.761850645,5178003.99247814 571001.386233398,5177988.67983036 571074.382815125,5177868.86751359 571084.757445356,5177858.80495065 571105.881316483,5177815.80510957 571118.630746215,5177795.55510817 571135.317716381,5177769.52353058 571155.067089262,5177738.67939336 571178.3788501,5177702.36643709 571191.25342064,5177679.61618372 571204.252969058,5177654.36592674 571217.127621113,5177641.86568032 571245.626690569,5177593.92762302 571279.125724919,5177553.67697916 571351.748326282,5177427.55056576 571545.617370039,5177145.35936018 571579.116389857,5177102.54622782 571586.991079517,5177082.29607466 571607.74044401,5177052.10818228 571625.864878269,5177024.3578394 571649.114175186,5176991.60740149 571664.738618166,5176958.79460298 571692.987839876,5176928.60657654 571703.487440808,5176903.35637533 571747.361166652,5176847.98055676 571827.483687211,5176726.97906069 571866.107595415,5176681.72834714 571899.856518111,5176626.29021987 572000.478538353,5176490.2883681 572054.851855255,5176407.09987031 572095.975720517,5176361.84912263 572121.974892958,5176318.97364763 572225.096878772,5176183.03427991 572225.346775964,5176170.34677318 572238.096495436,5176165.40904531 572253.471029412,5176142.90876785 572269.095516803,5176114.9709854 572547.712485134,5175757.5910215 572760.893965755,5175497.02478568 572844.079123081,5175395.33584209 572849.453886825,5175377.5857502 572872.453320513,5175360.08535156 572898.327526985,5175319.77240606 572988.574969836,5175206.52085537 573545.934649102,5174557.76147007 573591.308408477,5174504.94822102 573761.428742256,5174303.75793427 574338.787798271,5173591.748739 574377.661762125,5173548.09188038 574390.286425936,5173533.93543306 574408.161060683,5173529.06014185 574413.285929702,5173524.06006126 574458.785242578,5173544.93429316 574497.159353301,5173519.99618045 574573.657783353,5173498.05743741 574797.278606743,5173490.55375758 574861.027290862,5173470.99022665 574950.025585292,5173461.86377021 574960.6500804,5173418.801141 574966.149742699,5173385.8635856 575005.648162765,5173266.92556518 575106.895002345,5173085.23661197 575180.017919609,5172981.36054137 575194.954994324,5172960.11032358 574893.083955377,5172742.02169226 574523.842045287,5172926.37124191 574431.78157212,5172973.06019764 574381.095188705,5172998.74850092 573839.10716416,5173273.56966953 573150.312561799,5173965.33082721 572757.510447767,5174371.68114196 572589.577408777,5174545.46524465 571865.534280649,5175294.60286016 571450.482921095,5175715.64156857 571150.678513564,5176019.77205896 571044.493889161,5176127.52402428 570945.121584151,5176228.30712328 569545.035437276,5177701.17800856 568850.236130719,5177670.9721113 568728.05098341,5177669.56812704 568116.875348472,5177673.73573361 568078.938388472,5177651.08013966 567961.378124028,5177646.45731162 567681.883438769,5177635.49372379 567475.88721203,5177610.9349869 567415.200550961,5177572.46726768 567333.139183745,5177520.43740788 566815.896282877,5177192.38357472 566323.65295412,5176877.8916627 565860.034179866,5176581.71164289 565488.224218152,5176079.77913727 565481.161765349,5176070.21673024 565453.411951475,5176032.74834523 565453.532749863,5175573.30925204 565453.655343666,5175310.37083667 565617.586827656,5174989.86688538 565431.585416794,5174453.1807221 565350.834790518,5174220.15001986 565246.771769923,5173952.30706415 565213.397238207,5173935.71381454 565064.274326279,5173861.40354321 564699.719173033,5173922.59738972 564566.534359829,5173944.97471402 563637.055802585,5174379.61723962 563363.247225477,5174254.4650846 563279.623352728,5174209.15379638 563105.250305583,5174073.93737222 563072.250867288,5174068.37540315 562974.752526144,5174051.90822064 562754.256276048,5174014.7242604 561973.771623433,5174095.5503325 561791.836067404,5173949.20888339 561777.273175625,5173882.36502476 561770.085367599,5173837.83365963 561659.957984095,5173392.17686987 561456.271602598,5173126.64754164 561350.647173711,5172988.96101705 561168.336898399,5172875.96336649 561122.274951155,5172846.62020246 561115.025082706,5172846.43281955 561069.525647811,5172819.40215804 561031.526119196,5172796.8088985 561001.213949163,5172774.24676329 560948.151970812,5172729.27861894 560796.715775128,5172583.28023213 560721.965447171,5172415.81171328 560764.897430781,5171949.49580538 561279.573152618,5171710.23630282 561498.193996626,5171691.76400878 561983.684774784,5171650.75615382 562458.0508877,5171622.31105753 562848.352779966,5171259.02192256 562859.539976858,5171248.61544857 562968.473798092,5171071.95666214 563003.593971717,5170638.89154875 562892.280327427,5170315.45417486 562605.344449561,5169956.862956 562521.533105642,5169922.6452817 562132.663885022,5169807.49421506 561900.478973164,5169652.65307941 561826.354795942,5169603.18515649 561760.418026613,5169559.18588925 561511.731892284,5169255.37536316 561503.544436728,5169245.37542689 561232.357556692,5168831.43952103 560884.234916915,5168461.19234912 560779.54675206,5168215.66112953 560843.231538989,5168057.81555244 561038.535743858,5167573.71625541 561087.032326471,5167318.58910831 561035.28141488,5167140.27627399 560868.532687849,5166982.99635267 560671.471626746,5166792.09160942 560268.163713109,5166565.78310088 559962.168798069,5166551.63082396 559945.856671366,5166560.75609864 559415.806337168,5166857.39010275 559202.310174281,5166873.86182968 559032.875720978,5166886.95794503 558492.756506145,5166559.43164058 558332.508941898,5166530.87106572 557965.577012159,5166465.43795764 557486.715217369,5166927.60404274 557309.346432995,5167097.17042 557218.850875963,5167183.67258413 557188.102386366,5167213.04831805 557035.047413113,5167359.39571248 557005.673859732,5167387.55266058 556951.989002865,5167438.83518359 556876.680213447,5167510.80571625 556710.56030707,5167383.80753859 556641.187430972,5167330.77705381 556165.510935237,5166648.46758678 555813.836652007,5166611.84826032 555643.345838285,5166843.66525374 555579.975893963,5167076.44918541 555516.231468122,5167353.67092001 555201.307696538,5167484.14578984 555092.187006035,5167489.24138159 554803.260918577,5167502.74625542 554761.950429776,5167538.02842401 554743.638821366,5167553.65383076 554610.457814958,5167667.68803543 554539.088767291,5167944.8785355 554537.714104559,5167969.69122118 554528.216463055,5168143.56751933 554514.594828928,5168391.3818683 554511.658053458,5168444.69476578 554450.598149601,5168462.25837087 554254.481493866,5168518.82441583 554212.483281361,5168530.91892377 554145.733204339,5168296.94974861 554139.232048814,5168174.63656741 554148.541998444,5167985.04144484 553470.693821533,5168011.80270507 553439.712858505,5169533.81262435 553427.732396188,5171162.82285219 553403.752034889,5172759.83301632 553383.771651848,5174368.84314128 553355.791643031,5175981.85334717 553351.810650603,5177595.86318564 553330.828407997,5179198.84213875 551741.892997035,5179287.86144805 550123.957608117,5179265.88261581 548516.021850388,5179243.90363668 546914.085935204,5179232.92441706 545321.149602686,5179201.94532802 543650.216504964,5179203.96679193 542032.28124317,5179264.98679513 540430.345259956,5179248.00759231 538756.412126805,5179248.02907838 537221.431611674,5179254.05218577 535605.424529336,5179255.07890249 533990.417465329,5179274.10537635 532381.410489906,5179317.13142772 530787.403635033,5179294.15814945 529189.396799056,5179301.18453868 527600.390098711,5179330.21047239 526019.384250467,5179566.23320789 524404.377615024,5179556.26010977 522796.370766589,5179501.28761151 521175.36375734,5179442.31544096 519525.325264365,5179380.28135453 519394.355935139,5179375.34611238 517916.328271882,5179332.36865748 516306.291369745,5179249.39311185 514626.252972295,5179185.41839672 513009.216520757,5179180.44179076 511387.180069969,5179185.46510066 509763.143811634,5179209.48807252 508151.107766549,5179225.51104065 506539.070830495,5179170.5356119 504914.034421812,5179180.55899068 503301.998167785,5179179.5824689 501695.962547851,5179211.60507996 500088.927078579,5179251.62748838 498462.889373269,5179247.62316423 496848.851735509,5179237.6171233 495302.815676504,5179229.61132198 495346.84729782,5180821.57463446 495340.878395801,5182446.53695695 495368.909626316,5184043.49993398 495375.93995181,5185617.46334803 495394.971242756,5187232.42574426 495420.002151849,5188825.38856517 495446.03275704,5190405.35159924 495503.064321413,5192017.3136871 495524.095615327,5193646.27538485 495564.126526155,5195247.23755609 495560.156779411,5196842.20002694 495603.188010644,5198467.16141745 495611.218295986,5200062.12367648 495637.248778541,5201663.08557362 495650.279726696,5203296.04675013 495676.309926805,5204889.00866588 495711.353257682,5206502.98535492 495747.398906727,5208109.96516074 495763.443521209,5209683.94554618 495759.488657558,5211278.92586094 495757.534996631,5212916.90557524 495769.579718949,5214497.88577718 495749.624731671,5216090.86619041 495735.659231801,5217311.85113751 494959.659115045,5217313.86122848 494970.705119564,5218929.84108862 494995.750458042,5220523.8209809 495003.795943673,5222123.80097645 495029.841657324,5223733.78054491 495057.886755016,5225323.76027618 495042.932737237,5226942.74021409 495039.977911121,5228534.72027518 495038.023517812,5230142.7000773 495024.069605433,5231766.67981888 495019.115198974,5233362.65844546 495028.162292141,5234979.63287876 495020.209257124,5236590.60763539 495020.25677792,5238222.58188682 495069.303271475,5239826.55568717 495109.350249214,5241446.52931016 495126.397469637,5243072.50317726 495135.444059105,5244676.47748387 495131.495656431,5246452.01174692 494969.496243897,5246452.45230827 494795.543352658,5248054.43014654 494770.589645386,5249647.40528159 494775.636449952,5251262.3794381 494778.681964043,5252833.35429019 494796.728248945,5254433.32831968 494809.774558379,5256034.30238152 494927.819864232,5257612.27448102 494951.864575155,5259160.24900567 495092.910126374,5260757.22018159 495122.945638598,5262364.19987764 495170.980399668,5263944.17941097 495203.018507466,5265676.15736808 495207.054052006,5267287.13741823 495199.089378382,5268885.11787935 495275.123248513,5270449.09659807 495273.160182488,5272126.07581067 495167.197052713,5273752.05834863 495209.110948557,5275537.03499854 495210.271082612,5277133.01502885 495241.46229853,5278739.99404238 495300.561408565,5280442.97098496 495352.374997453,5281951.95047877 495408.40961765,5283572.92834458 495395.446087868,5285230.90769069 493836.441274287,5285240.57888839 493825.510468566,5286899.93388971 493824.545357675,5288432.91510224 493806.596553693,5290017.89177349 493775.648970343,5291608.86854032 493750.699693533,5293150.84586706 493728.753104446,5294776.82181349 493731.649256886,5296388.79709995 493731.935767607,5296550.66961577 493776.730713998,5297964.77137662 493783.330511173,5298155.64321211 493838.093445917,5299556.7446901 493846.756365626,5299768.80360605 493904.424709744,5301149.71765226 493913.118863083,5301361.8390452 493921.563243168,5301580.83533847 493954.755974827,5302733.94120834 493960.013024057,5302956.00006086 493955.9946899,5304317.66657612 493956.565520734,5304575.66254475 493954.046946923,5305931.6415582 493953.86701868,5306165.63792368 493952.442891526,5307544.61650254 493952.326104836,5307798.61254779 493954.463320831,5309145.59144216 493954.877885721,5309403.33739959 493963.859589912,5310780.31549167 493964.929757913,5311018.81171352 493961.567301206,5312372.22816381 493960.325626435,5312628.97419436 493960.367397812,5313923.51638735 493431.384461735,5313928.53994069 493490.434964883,5315540.51239895 493379.48653035,5317130.50072358 493388.531252847,5318741.49042006 493360.577546444,5320361.4818554 493352.622551027,5321960.47243614 493352.081509723,5323845.46083966 492804.884251059,5323832.30308164 492804.728410709,5323846.4905109 492786.743364527,5325445.48257286 492776.789998417,5327070.47405103 492758.836543209,5328679.46609166 492788.880984317,5330290.45520526 492781.9264423,5331879.44663193 492780.972009399,5333482.43757738 492783.017951372,5335104.42818006 492746.065367191,5336708.42150474 492720.11243214,5338317.41412255 492733.157548137,5339930.4039689 492739.203056658,5341545.39423472 492746.063959719,5343265.32127047 492951.176985921,5343257.86832142 492951.052204394,5343265.36828563 492922.29539326,5344928.3569705 492934.35169547,5346483.34022611 492947.410593318,5348110.32261461 492938.469013554,5349693.30712058 492927.530125579,5351349.29100348 492967.586978927,5352956.27129905 492969.645361767,5354555.25463466 492999.703801659,5356189.23530221 493036.761092332,5357797.21559205 493033.82054541,5359419.19892554 493050.878525029,5361022.18076849 493074.959125943,5362394.97688371 493169.268276769,5362392.59408621 493175.88894744,5363984.13924712 493176.488060854,5364130.88764683 493189.479189174,5365604.18347051 493191.047021142,5365750.86928435 493204.537530078,5367207.16519159 493206.293819464,5367380.03820552 493234.845517007,5368810.83304566 493238.445335476,5368978.83094687 493267.496754917,5370400.12577509 493271.190904903,5370583.74849247 493312.272784848,5371989.04571345 493315.329980969,5373555.07264266 493327.388340583,5375159.09941695 493337.44704718,5376772.1264789 493341.504649911,5378352.15344092 493360.562932647,5379960.1795722 493372.621192826,5381564.20619109 493399.679270822,5383172.23157814 493468.737445095,5384806.25386166 493479.37420531,5386074.14118232 + xmlns:gml="http://www.opengis.net/gml/3.2"> + 363237.626104089 5045148.78911013591752.164237744 5386497.208 + + + + 492720.11243214 5166465.43795764591752.164237744 5386497.208 + 493479.37420531 5386074.14118232 495062.336832765 5385983.99124965 496639.674560181 5385894.1616558 498248.095687447 5385802.56185817 499839.824008464 5385711.91271809 501136.55 5385638.064 501467.943141889 5385767.80541868 502638.13038141 5386225.93726688 503053.46464599 5386388.54188931 503331.026 5386497.208 503699.302 5386362.789 503698.47332 5386220.67017644 503689.147461229 5384621.28310618 503685.055 5383919.425 504644.774816817 5383819.88892449 505192.831 5383763.048 506067.396491085 5383051.22448901 506253.563241776 5382899.70025046 506630.795 5382592.665 507778.537 5382437.824 507871.292629229 5382391.32496513 509368.38182872 5381640.82385308 509937.620566855 5381355.46055867 510949.994331869 5380847.95062758 512525.992895043 5380057.89170881 513230.628453252 5379704.65305729 514170.309633563 5379233.58441887 515764.572623581 5378434.3694173 516470.849667691 5378080.30787761 517228.900216171 5377700.29192411 518897.19338599 5376863.96508426 519529.106322551 5376547.18278313 520047.475 5376287.321 520466.380787187 5376350.25746135 522091.309059952 5376594.38690181 522113.824951348 5376597.76969234 523693.324360806 5376835.07389432 525252.915 5377069.387 525268.759120909 5377065.65928362 526793.056620754 5376707.03107132 526885.07181278 5376685.38225025 526949.266 5376670.279 527300.354487204 5375095.81309175 527453.283 5374410.001 527653.748 5373931.762 527552.376 5373516.272 527561.324482355 5373492.93455844 527584.165 5373433.367 527689.675 5373378.304 527467.839 5373137.301 527419.949 5373112.983 527263.544 5372956.911 527236.163 5372848.09 527187.896 5372687.294 527355.022 5372578.487 527551.876 5372306.489 527284.621 5372027.292 526948.617157886 5371912.32001848 526808.709 5371864.447 526695.139 5371883.978 526590.927 5371920.846 526075.661 5371920.909 525551.907 5372120.757 525341.266173163 5371887.38511232 525248.727017776 5371784.85970117 525010.16 5371520.548 523716.552877634 5371602.24673338 523215.28 5371633.905 522261.964 5371345.684 522081.031 5370213.964 522049.140180406 5370143.10519535 521489.688 5368900.048 521544.961 5368616.504 521513.120101352 5368531.18873901 521240.425 5367800.523 521992.925984955 5366919.9380308 522064.973201944 5366835.62758122 523065.189 5365665.164 523666.976011613 5365532.75264644 524448.259809692 5365360.84656802 524886.643 5365264.389 525244.446667801 5365004.31195121 525427.486 5364871.266 526834.242807884 5364987.74375145 528421.99597393 5365119.20778105 530057.692838637 5365254.64149055 531318.261 5365359.015 531669.519146117 5365456.4436309 531899.413299638 5365520.20947626 533278.556856069 5365902.74314843 534241.395 5366169.806 534868.727747756 5366198.30814352 535862.499 5366243.459 536421.444 5366210.286 536454.059088547 5366166.01439868 536898.969905572 5365562.09409084 537405.791 5364874.137 537774.253 5364249.45 538097.711706761 5364153.29342588 538186.691 5364126.842 538319.041 5364034.482 538324.474611288 5363980.41003903 538327.413 5363951.169 538414.038 5363814.04 538395.746 5363692.567 538556.296 5363474.732 538811.359 5362962.664 539721.502142637 5362643.71368574 540222.235 5362468.237 540222.828774539 5362400.67690394 540234.913 5361025.725 539954.577111015 5360403.18325763 539237.043643193 5358809.75711129 538768.842 5357770.022 538904.831920846 5357188.24951072 539282.403957909 5355572.97521305 539282.922 5355570.759 540081.374204488 5353942.74454074 540329.13587328 5353437.56767859 540590.318 5352905.027 540942.106976105 5352331.80678252 541403.832 5351579.452 541417.411 5351552.996 541474.645 5351499.686 541494.378 5351448.573 541624.045 5351037.925 541767.388 5350787.633 541812.104206218 5350737.01131558 541915.439606497 5350620.02885074 542131.328 5350375.629 542342.064 5350459.941 542592.8 5350317.92 542980.498 5349690.624 543341.824 5349263.856 543389.647582808 5349143.8744296 543502.934526602 5348859.65596197 544030.594209357 5347535.84386643 544389.417 5346635.616 544768.189708664 5345907.09214577 545042.706 5345379.093 545073.768 5345257.683 545021.138 5345107.205 545118.353 5345016.884 545179.190362287 5344923.47621679 545339.834 5344676.829 545269.944 5344570.675 545186.589398349 5344588.4800933 545115.225 5344603.724 545081.255 5344466.053 545106.151 5344394.924 545191.755318209 5344356.5039508 545227.844 5344340.307 545298.941 5344346.737 545371.522 5344400.113 545523.83 5344463.388 545586.267 5344417.879 545628.81 5344307.061 545635.73476791 5344288.83903495 545677.475 5344179.003 545516.198 5344179.26 545555.649 5343991.229 545445.555 5343934.775 545421.307 5343871.903 545491.434 5343639.037 545538.047 5343613.163 545681.931 5343700.456 545746.764 5343666.085 545703.861 5343435.096 545706.126 5343306.977 545734.89 5343192.657 545789.228 5343078.85 545910.732 5342898.581 545988.563 5342763.042 546114.709 5342698.909 546115.698565205 5342696.85945804 546147.23 5342631.553 546099.611 5342525.263 546179.368 5342382.332 546158.143 5342277.49 546150.242 5342183.254 546163.392 5342087.953 546233.891 5341968.105 546353.795 5341862.244 546384.093 5341764.612 546371.817 5341675.898 546406.042 5341602.999 546467.242 5341562.122 546531.158 5341491.935 546595.782 5341335.301 546682.801 5341392.514 546731.492 5341367.902 546734.074 5341254.298 546793.797 5341142.706 546796.920124315 5341069.75795911 546800.946 5340975.724 546829.702804815 5340970.51317348 546859.637 5340965.089 546935.417183097 5341071.23316396 546936.136 5341072.24 546994.659 5341132.003 547025.26 5341199.564 546963.581 5341297.553 546887.189 5341353.43 546935.716 5341398.907 547072.874 5341380.582 547160.491 5341339.93 547262.645 5341263.274 547371.941 5341246.27 547411.486 5341304.645 547431.656 5341385.091 547458.37 5341472.693 547509.618 5341562.351 547633.969 5341668.982 547780.999 5341777.041 547863.135 5341848.435 547938.604 5341902.793 547996.069 5342012.268 548007.097 5342074.731 548143.653 5342126.208 548308.86 5342204.793 548387.097 5342223.672 548433.107741179 5342228.82930415 548491.389 5342235.362 548715.885 5342303.656 548870.555 5342262.366 548906.069 5342283.049 548943.59 5342478.201 548975.205 5342520.155 549068.213 5342595.674 549082.311 5342611.542 549106.066 5342631.815 549156.741 5342640.279 549178.145 5342622.246 549222.795 5342635.598 549263.035 5342705.726 549286.127 5342707.16 549404.759 5342610.306 549423.329 5342586.074 549419.404 5342562.883 549425.606 5342537.617 549466.072 5342510.179 549505.77 5342500.024 549596.625 5342514.089 549689.059 5342607.213 549735.331 5342623.671 549807.163 5342642.514 549885.559 5342736.136 549938.37 5342806.687 549971.284 5342840.631 549986.154 5342838.599 550024.735 5342814.544 550035.879 5342814.024 550049.848570131 5342826.35841657 550071.906 5342845.834 550094.243 5342862.703 550318.605327384 5342887.60770346 550332.887 5342889.193 550868.403 5343258.589 551925.594654075 5343445.68418898 553425.443 5343711.118 553578.372584271 5343793.91646471 554224.079 5344143.512 554085.870587265 5344554.99014036 553914.031 5345066.596 553481.9264489 5345394.2815694 552677.609 5346004.234 552609.440410738 5346144.33610868 552346.012 5346685.742 552444.413 5347216.198 552402.526 5347288.068 552361.392 5347278.118 552339.54 5347255.994 552295.374 5347239.533 552289.772 5347243.496 552281.329 5347265.033 552284.446 5347284.823 552276.548 5347314.393 552280.935 5347330.49 552291.325 5347343.862 552283.775 5347357.997 552261.357 5347352.542 552266.636 5347383.777 552267.104 5347400.147 552259.794 5347433.119 552135.332922751 5347756.9139764 551818.987 5348579.912 552011.692122779 5349362.04263356 552311.103 5350577.259 551995.831180082 5350977.01317121 551766.796794742 5351267.42114651 551438.976 5351683.087 551558.184 5352415.97 551736.233514996 5352447.85081675 552226.802 5352535.69 552243.048600333 5352608.64290264 552606.198576243 5354239.3129685 552697.159 5354647.757 553325.020739725 5355090.22467331 554632.112 5356011.36 554909.239293551 5355952.68797318 556570.094131868 5355601.05996 557671.494 5355367.877 557813.151 5355282.853 557852.942 5355215.942 557871.717 5355150.979 557932.772 5355078.108 558020.656 5354938.197 558187.756692178 5354956.78989982 558778.765 5355022.55 558790.328 5355198.369 558702.307 5355270.335 558980.747 5355712.925 559635.379 5355565.659 559677.087 5355376.809 559786.810811494 5355374.80082759 559805.761 5355374.454 560859.984 5355728.689 560814.212227964 5356064.57548428 560813.302 5356071.255 560936.77 5356322.694 561414.838624699 5356616.91326795 562070.552 5357020.461 563038.704053898 5357233.97825157 563335.065 5357299.338 563434.912 5356225.854 564642.203329377 5356187.53414005 566223.008507408 5356137.35881654 567103.531216315 5356109.41070984 567349.329 5356101.609 567838.950266071 5356028.57469323 567893.874 5356020.382 567983.964348441 5356131.18676823 568287.36 5356504.342 569112.243 5356673.332 569443.754407045 5356673.74895058 569985.247 5356674.43 570188.606034177 5356175.6787925 570471.953 5355480.752 570693.19 5355401.973 570753.122 5355168.03 570553.534 5354928.086 570582.743058388 5354564.37549861 570632.193 5353948.626 571113.672375693 5353821.77213622 571321.57 5353766.998 571820.091694902 5352988.91756426 571842.076 5352954.605 572753.430929069 5352767.5145328 573241.44 5352667.332 574122.572 5352472.759 573760.517640225 5351433.58949544 573202.312 5349831.426 573206.581376533 5349773.97250468 573288.533 5348671.14 573541.192540589 5348175.20240659 573650.98 5347959.704 573715.909870876 5346529.39454321 573727.362 5346277.121 574594.340651411 5345907.36682371 575024.331 5345723.982 575406.126598792 5344926.54940408 575677.971 5344358.765 575794.823 5344303.805 575846.914 5344295.233 575882.736 5344300.341 575916.052 5344276.698 575950.266 5344232.068 575942.526 5344193.675 575931.616 5344176.546 575919.753 5344168.977 575904.466 5344139.747 575911.253 5344110.192 575913.739 5344093.859 575929.123 5344084.8 575982.415 5344032.705 576050.58 5343963.515 576139.078 5344071.23 576146.845 5344076.583 576154.723 5344089.04 576178.436 5344135.985 576198.8 5344186.59 576205.981 5344220.345 576268.150525235 5344257.21948135 576433.947 5344355.558 576460.035 5344455.958 576417.133 5344486.881 576399.273 5344526.786 576354.144 5344585.471 576316.658 5344597.013 576278.769 5344623.372 576276.991 5344663.801 576288.047 5344700.696 576291.346 5344731.62 576294.855 5344793.119 576317.462 5344814.419 576321.125 5344913.0 576349.05 5344935.274 576385.209 5344930.2 576414.963 5344941.406 576425.449 5344974.588 576457.025 5345019.169 577270.438 5345017.463 577419.695 5344869.717 577637.723 5344867.429 577638.74 5344807.844 577637.608 5344800.109 577633.787 5344777.823 577646.083 5344556.27 577858.395498627 5344374.82075384 578098.111 5344169.952 577983.545 5344010.28 577870.799266675 5343995.66099251 577339.663 5343926.792 577439.156 5343374.154 577418.045950075 5343349.80729019 577240.295 5343144.803 577351.031 5342737.143 577787.435 5342734.114 577877.676 5342773.635 577914.760715966 5342747.23188922 578338.551 5342445.507 578563.657 5342445.51 578891.533 5342877.409 579539.718 5343074.151 579580.062887345 5343081.82671725 580109.056 5343182.469 580428.643 5343386.14 580570.447 5343424.578 580677.436 5343415.589 580696.864 5343369.234 580882.552 5343338.819 580954.788 5343365.782 581109.486 5343367.669 581126.558 5343356.794 581153.692 5343349.151 581193.740207828 5343304.2287266 581245.307 5343246.386 581503.321 5343237.092 582188.375 5343343.567 582804.217608689 5342272.24544707 582857.38 5342179.764 583410.230499244 5341785.21975707 584115.486 5341281.911 584321.459250725 5340199.72573453 584373.67 5339925.41 584444.052922083 5339936.64709769 585781.454 5340150.172 586052.911303773 5340219.45571218 586060.401197404 5340221.36734848 586482.241 5340329.033 586722.47098628 5340235.02169628 586732.73026337 5340231.00684356 586733.455131214 5340230.72317468 586733.706 5340230.625 586734.346642791 5340230.77208047 587666.252684771 5340444.72153606 587998.941 5340521.101 588074.727157533 5340246.81160393 588103.872 5340141.329 588454.006 5339912.343 589289.403356798 5339559.18325302 589300.922048736 5338697.20336088 589330.88158939 5337083.19477104 589344.840832338 5335466.18659232 589375.799835842 5333832.17777631 589413.759065257 5332205.16868353 589447.718723428 5330598.15973728 589421.677569149 5328983.15297854 589404.637199152 5327394.14613183 589393.595521865 5325750.13889061 589391.554825624 5324141.13150972 589423.51370196 5322505.12249251 589449.47354742 5320910.11388143 589472.432393428 5319277.10519543 589492.391231896 5317645.09663268 589557.327364741 5316038.14876436 589610.247050873 5314432.24530066 589687.166826041 5312827.34054162 589760.086571563 5311223.43592443 589794.004664517 5309590.53503253 589813.924074779 5307985.63306279 589833.843145254 5306374.73141241 589854.761727334 5304754.83021731 589850.690324137 5303335.91779226 589849.684085117 5303211.98796954 589836.604834502 5301638.02294658 589832.518533866 5299924.1285249 589798.437037778 5298307.22945341 589824.356272078 5296703.32672913 589854.276024973 5295110.42310374 589891.711273188 5293825.43772011 589898.886326741 5293578.51503776 589900.694793715 5293498.51986128 589929.132166673 5292256.59471918 589933.561446002 5292093.60451093 589938.92656038 5291897.61628293 589944.665983588 5291687.94137658 589978.174239362 5290612.81826398 589988.033286093 5290296.71219285 589992.999549548 5289628.50289911 589997.657264298 5289007.72209249 590004.831688645 5288699.91846514 590021.925512196 5287966.18961244 590030.902163723 5287416.83060779 590047.888728129 5287100.83929792 590116.712163097 5285889.05999224 590136.447356351 5285541.38202484 590141.319825875 5285482.00858994 590175.239774093 5285070.33194198 590230.150033524 5284431.97369368 590273.753377139 5283924.92451864 590346.768671837 5282820.0795009 590359.934884135 5282321.34384726 590402.762389907 5281209.87528104 590403.198955841 5281188.00091585 590415.115143658 5280689.07781656 590416.300550313 5280640.07923013 590463.878699903 5279545.29749472 590490.045015092 5279050.93621315 590552.560083105 5277945.279267 590571.104668187 5277527.54101025 590576.16388836 5277451.23059324 590642.992486551 5276371.88525474 590677.095635271 5275864.33661944 590741.616737182 5274903.6128942 590756.607487748 5274689.18124283 590780.02667555 5274264.06806792 590821.121166164 5273556.46268782 590844.100980463 5273088.03833184 590859.025397483 5272784.54684905 590866.269046009 5272637.23848383 590905.219199914 5271479.27161332 590935.204816209 5271148.0304548 590944.950154602 5271040.72081967 591043.399631439 5269877.75215533 591053.769301984 5269755.19296268 591076.692479513 5269425.13953795 591110.517197168 5268259.48564049 591117.254888758 5267973.99391934 591128.122845498 5267811.8733961 591206.009888956 5266651.40546997 591199.616494462 5266222.16843626 591198.488342556 5266148.60815838 591175.006180318 5265104.63989 591175.439715822 5265012.45511298 591177.687918502 5263516.49940567 591178.432325836 5263386.50323498 591185.255417681 5262180.038753 591187.055459458 5261890.54726464 591185.737812806 5261770.48835248 591185.389639317 5260657.07797112 591184.567050358 5260286.58616161 591186.251345165 5260169.58869304 591203.585911612 5258692.558237 591206.144707272 5258557.62363551 591231.790581386 5257040.59378715 591239.281180766 5256698.72609417 591269.618002448 5255310.69324746 591290.448603308 5253691.72817665 591305.65503736 5252101.76256354 591326.173869598 5250510.79678628 591291.880300777 5248901.8326817 591296.39843466 5247279.68033507 591193.586980174 5247275.43286786 591221.166060928 5245605.90588963 591242.55956521 5244004.94002282 591286.202814154 5242404.97359231 591309.471500193 5240813.007405 591328.739695874 5239202.04166475 591344.570552771 5237596.07583646 591363.4010812 5235980.11010727 591378.544330248 5234371.1442482 591394.017360582 5232782.18812091 591420.004054301 5231157.24153439 591448.990594695 5229517.29534933 591475.977567139 5227928.34746962 591495.964618956 5226341.39958728 591521.951475128 5224737.45212944 591545.938530749 5223156.50389693 591566.925327205 5221541.55677295 591586.912063263 5219919.60983592 591626.898708537 5218299.78757514 591466.899466999 5218297.69547592 591480.886345409 5216706.71608139 591500.873003762 5215093.76854045 591530.859899174 5213513.81979972 591556.846369643 5211880.87277365 591590.833237315 5210296.92407028 591617.819976923 5208695.97592128 591635.806519539 5207072.02850491 591658.787079717 5205480.07127601 591684.746751559 5203843.08684967 591707.707415759 5202247.10199548 591737.667785504 5200640.11717552 591752.164237744 5199168.19328055 591745.051248586 5199157.97121544 591736.450994764 5199147.03135422 591727.360817793 5199139.1714658 591713.250707976 5199133.66157558 591701.69061102 5199128.86166826 591694.950522966 5199124.78173446 591688.71036928 5199118.07182361 591679.469948723 5199100.29203013 591669.629518109 5199082.05224353 591661.499009181 5199060.75247907 591657.138495057 5199039.52269857 591651.655586978 5199020.88079978 591650.817978316 5199018.0329286 591645.887660254 5199004.72307527 591638.387346142 5198991.37323288 591628.607062769 5198979.09338973 591609.086908203 5198971.29354405 591587.626729705 5198962.36371715 591563.856614487 5198955.82387707 591549.706571326 5198952.96396247 591532.706483829 5198948.07407893 591520.526421268 5198944.57416236 591503.416518085 5198947.18420787 591487.676834431 5198958.85416137 591476.116992589 5198964.40415597 591463.257050205 5198965.75419594 591439.577037757 5198963.40431567 591418.137065166 5198962.85440902 591402.3369922 5198958.64451415 591387.596923142 5198954.67461266 591372.306757534 5198946.71475157 591361.88654159 5198937.07488656 591351.456325752 5198927.43502162 591304.93543812 5198887.46559553 591277.244851213 5198861.24596072 591252.174400459 5198840.7862602 591238.044309966 5198835.94636498 591209.974085347 5198824.48659089 591185.473704708 5198806.90686083 591164.663437088 5198794.24706845 591143.243186502 5198782.22727256 591121.182996363 5198772.62745619 591093.642654176 5198756.32772701 591077.672374188 5198743.5179164 591064.162020583 5198727.87812286 591050.671645469 5198711.34833787 591035.341311237 5198696.33854601 591017.530831238 5198675.11882431 591002.060240344 5198649.51913515 590986.669767733 5198628.77939902 590973.759424895 5198613.57959931 590960.259056729 5198597.27981272 590947.948713249 5198582.09001055 590938.108526502 5198573.56013392 590918.558425989 5198567.75027178 590904.458294847 5198561.14039457 590889.758164789 5198554.52052 590878.218040119 5198548.3906275 590865.947874116 5198540.49075517 590853.017564862 5198526.62094327 590835.706776913 5198492.61134429 590827.656379556 5198475.51154325 590815.27566934 5198445.11188896 590807.865228319 5198426.25210237 590801.604854944 5198410.28228305 590799.154682936 5198402.96236412 590792.974432274 5198392.06249552 590781.944222379 5198382.41263536 590770.844114137 5198376.95273504 590759.913978962 5198370.39284465 590743.933954186 5198367.94293589 590734.783874538 5198363.83301434 590720.763627729 5198352.37318451 590701.123183212 5198332.22346265 590678.922733274 5198311.60375636 590661.822348884 5198294.14399798 590646.401913493 5198274.71425168 590624.981420651 5198252.34455949 590604.671096107 5198237.0347943 590583.300768642 5198221.49503596 590558.060368849 5198202.58532696 590540.330013877 5198186.21556145 590526.889800117 5198176.09571704 590516.419649661 5198168.87583184 590504.739512344 5198162.08594766 590492.529498122 5198160.35601659 590481.579391292 5198154.8961164 590462.528981496 5198136.08638067 590452.04861395 5198119.82658362 590441.59819886 5198101.58680577 590431.067667239 5198078.48707563 590423.507215111 5198058.96729799 590416.736703357 5198037.03754047 590411.006216019 5198016.21776774 590407.195565925 5197988.80805094 590405.235087562 5197968.71825495 590400.83464547 5197949.89845711 590395.204248641 5197932.83864748 590389.583819913 5197914.44885079 590360.542500582 5197856.66953909 590337.021288063 5197803.8301559 590322.27075184 5197780.01045213 590310.39021521 5197756.45073347 590301.83989959 5197742.43090738 590290.779488732 5197724.18113352 590280.779075703 5197705.94135503 590269.868913454 5197698.06147947 590253.21876847 5197690.31162771 590235.548562369 5197679.90180643 590219.688357719 5197669.73197498 590206.158043059 5197655.20217601 590200.9020524 5197647.37190981 590194.337650603 5197637.59239974 590185.677262455 5197620.48260484 590179.526974704 5197607.8227555 590176.976700304 5197596.09288133 590175.116546028 5197589.45295439 590160.376234443 5197574.89316135 590139.905207476 5197529.81369208 590122.754659444 5197505.08400942 590110.984178905 5197483.73427014 590099.853886948 5197470.33445032 590087.693555221 5197455.15465252 590075.353271417 5197441.95483619 590064.343021839 5197430.32499868 590052.562805392 5197419.99515188 590037.91260097 5197409.85531594 590026.242442697 5197401.96544483 590005.472367614 5197396.57558946 589993.272342065 5197394.18566682 589972.602587769 5197402.25567898 589953.18300385 5197417.61561399 589941.803344265 5197430.67553598 589928.463683839 5197443.49546892 589915.783937506 5197452.78543356 589907.204150616 5197460.81539246 589896.374337011 5197467.48537463 589879.214516341 5197473.18539417 589862.824677921 5197478.22541678 589847.684763466 5197480.20546397 589817.164845685 5197480.40559637 589803.08492372 5197482.18564083 589787.234937315 5197481.06572165 589770.215131557 5197487.4257339 589753.295409265 5197497.31571088 589680.976225268 5197524.01576544 589662.106490591 5197533.20575759 589645.596594144 5197535.82580422 589622.536800548 5197542.09584352 589587.437445058 5197565.60576507 589567.907784387 5197577.8857292 589546.078190946 5197592.77567748 589538.838425327 5197601.92561859 589527.948714554 5197613.01555644 589518.259016549 5197624.77548235 589506.189245361 5197633.19545171 589505.049383366 5197638.91540002 589499.559712858 5197652.28529151 589489.909952055 5197661.40524327 589434.07070408 5197687.46522851 589412.131036017 5197699.26520706 589400.071269417 5197707.91517373 589387.341602693 5197720.73510186 589378.831927032 5197733.61501096 589374.672070781 5197739.28497273 589369.252284741 5197747.80491165 589335.242630162 5197758.98494841 589318.732747143 5197762.26498756 589293.742897157 5197766.08505817 589265.763011661 5197768.09515976 589243.223114695 5197770.17523699 589217.07319437 5197770.89534344 589195.01324987 5197771.0054382 589175.523300135 5197771.15552139 589153.043299567 5197768.83564222 589126.173328579 5197767.32577407 589103.603473267 5197771.18583359 589067.693479392 5197767.77602371 589041.923444409 5197763.64617701 589012.183479457 5197762.09632179 588987.733498796 5197760.41644489 588960.273498246 5197757.57659272 588931.003501634 5197754.71674865 588906.01343427 5197749.26691197 588877.943450807 5197747.08705593 588858.973386897 5197742.39718553 588835.763347036 5197738.29732768 588819.913374687 5197737.84740117 588802.893332618 5197734.28751101 588784.433180284 5197725.8476762 588745.252639642 5197698.58812103 588726.862374672 5197685.29833495 588711.012161243 5197674.47851301 588702.962013683 5197667.29862042 588698.641925277 5197663.04868208 588692.011913514 5197661.84872311 588687.741978851 5197664.20871799 588688.892079148 5197668.63866835 588698.782407486 5197683.77847274 588702.562635755 5197693.97835355 588706.832796289 5197701.31826103 588712.403051732 5197712.86812048 588716.793510109 5197733.00789863 588700.933296408 5197722.18807661 588681.903104714 5197711.97826233 588667.862882262 5197700.95843452 588651.992684389 5197690.7986061 588635.402683002 5197689.00869649 588617.772658363 5197686.10880263 588604.8625519 5197680.17891876 588588.432540007 5197677.94901295 588569.392344313 5197667.52920121 588568.968985745 5197667.31239195 588557.8522352 5197661.61931126 588547.992076788 5197653.75943369 588540.762066345 5197652.54947749 588528.412025716 5197649.49956226 588507.092111163 5197650.93964085 588490.662084253 5197648.04974185 588477.872034581 5197644.55983302 588463.171917084 5197637.93996423 588450.931707928 5197627.62012214 588435.541479747 5197616.14030563 588416.051291207 5197605.93049428 588394.591106997 5197595.69069194 588376.280957076 5197587.26085754 588358.440790861 5197578.17102783 588337.000581682 5197566.83123678 588319.900429657 5197558.42139707 588298.460230781 5197547.51160183 588273.419989111 5197534.35184533 588251.399751503 5197521.68207071 588228.729586578 5197512.08226786 588209.209440476 5197503.63243956 588195.699337559 5197497.70255926 588181.739220396 5197491.10268779 588169.469069117 5197483.20282214 588127.08835378 5197447.51337199 588109.338037262 5197431.81361012 588076.167536795 5197406.40401537 588062.727332977 5197396.05418022 588040.007003099 5197379.18445262 587997.189861146 5197355.28233246 587958.036162317 5197333.42528241 587934.705835169 5197316.54555824 587900.945324469 5197290.46597456 587881.355060404 5197276.72620204 587867.284890095 5197267.69635691 587848.304604915 5197253.08659076 587828.074161195 5197231.39690275 587808.333671272 5197207.727233 587783.193123736 5197180.89761988 587766.632839135 5197166.53784091 587752.522488827 5197149.57807775 587745.732257522 5197138.66821992 587736.522042088 5197128.16836874 587730.271910456 5197121.67846324 587716.911795528 5197115.08859059 587694.711369148 5197093.81890817 587675.791005574 5197075.66917921 587662.200554507 5197054.29945952 587646.160169836 5197035.53972414 587622.279769051 5197015.13004106 587608.69953988 5197003.46022203 587589.04913941 5196983.54051516 587574.908610826 5196958.64083484 587565.00829315 5196943.50103515 587549.647782781 5196919.23135408 587540.387403603 5196901.45157881 587526.217157141 5196888.90177197 587518.816939183 5196878.42191328 587513.906830852 5196873.06199065 587475.196042997 5196833.68257137 587466.655723194 5196818.56276583 587456.105228056 5196795.47305158 587447.334793776 5196775.27329955 587426.384069539 5196740.78375027 587410.293298763 5196704.82419429 587398.562542597 5196670.03460656 587380.481562538 5196624.55515828 587366.190803783 5196589.28558758 587347.020127911 5196557.02600837 587327.929317525 5196518.81649047 587314.23855874 5196483.55691752 587296.277646554 5196440.94744036 587285.827234818 5196421.39769053 587275.336907821 5196405.57790241 587258.686522841 5196386.37817774 587240.856106155 5196365.60847489 587227.98572128 5196346.88872802 587212.455244236 5196323.72903949 587199.004821805 5196303.24931373 587185.484489313 5196286.7295474 587173.064104207 5196268.01979873 587168.223898197 5196258.24992236 587163.193747467 5196250.90002183 587144.093191878 5196223.72039212 587129.412808739 5196204.76065684 587115.322662993 5196196.39080917 587096.402530814 5196187.96098466 587068.792084367 5196164.40135765 587050.871800577 5196149.36159726 587039.241604152 5196139.05175853 587031.931475344 5196132.3318624 587023.881323642 5196124.49198137 587015.953105316 5196117.00221901 586992.580754886 5196094.9224347 586964.53051538 5196080.40271676 586951.730491577 5196077.57280607 586939.480530623 5196077.61286298 586930.930460349 5196073.30294781 586919.780208735 5196060.5631325 586897.029712456 5196035.31350178 586872.529340524 5196015.33382462 586835.68847428 5195971.57445331 586813.588136341 5195953.39474664 586794.58788868 5195939.66497915 586784.147715803 5195930.4751241 586769.397436609 5195915.9253453 586755.387185038 5195902.70554921 586744.236920685 5195889.31574148 586730.716613668 5195873.67596848 586719.726349092 5195860.28616011 586712.936126887 5195849.38630597 586703.595872443 5195836.67648281 586694.975680448 5195826.8566261 586683.425585446 5195820.94674245 586665.725424698 5195811.20692794 586622.865243747 5195796.91728017 586582.025195185 5195788.82755819 586559.945052865 5195779.24776306 586542.185001331 5195774.35789842 586526.414894799 5195767.28804722 586511.03465958 5195754.49825415 586493.82445946 5195743.00845621 586473.758613228 5195728.45415584 586473.034191215 5195727.92871298 586460.164032538 5195718.91886859 586447.243726959 5195703.29909382 586431.253494387 5195690.49930414 586414.073240761 5195676.56953205 586398.83302122 5195664.44973183 586382.20284978 5195654.27991781 586362.052757661 5195647.15008869 586339.492672947 5195639.99027143 586326.092639414 5195636.49037208 586313.182545683 5195630.35049818 586297.922356123 5195619.54068464 586239.912275238 5195607.24109084 586213.012355678 5195606.85122332 586194.702459283 5195608.79129025 586175.202527376 5195608.95138161 586160.642644191 5195612.05141839 586143.592665855 5195610.4815163 586121.672741036 5195610.60161962 586105.182824558 5195611.91168447 586012.442814525 5195597.56227868 585983.132887786 5195596.48243003 585966.072919379 5195595.35252344 585942.752828907 5195587.74271535 585919.572762354 5195581.23289501 585870.112760303 5195573.68321133 585796.232735106 5195561.37369507 585746.842854756 5195559.34395277 585712.032814533 5195552.23419481 585679.152811925 5195547.12440644 585661.367196132 5195543.78459015 585634.91243334 5195523.11487374 585607.791931338 5195496.04529199 585587.121714185 5195482.95553059 585567.161562901 5195472.97573272 585551.981493441 5195467.46586432 585533.791404237 5195460.58602501 585505.811518506 5195461.50614952 585483.161563497 5195460.07627352 585441.311455623 5195448.67659626 585432.732356882 5195443.09280206 585365.090631824 5195399.06749319 585316.56012397 5195368.16805768 585280.319737416 5195344.71848361 585239.069391127 5195322.29892302 585208.268998482 5195299.35931787 585074.126805628 5195176.82128407 584917.96486975 5195061.91328176 584889.584452391 5195037.91367918 584867.854023639 5195014.45403853 584858.823763025 5195000.87422927 584852.243456499 5194985.56442674 584836.613141685 5194968.36468898 584831.853038493 5194962.78477256 584808.762843308 5194949.88502505 584793.042671666 5194939.29521655 584780.952478743 5194928.31539452 584746.041678369 5194885.2660314 584726.721244485 5194861.83637984 584674.790426929 5194815.0071424 584657.19035791 5194808.80729629 584640.680465025 5194810.99735394 584619.990524693 5194810.26746383 584603.050358897 5194799.65766237 584503.478615705 5194701.21922258 584468.627719959 5194653.30991578 584446.957195369 5194625.00033104 584427.046745276 5194600.46069678 584404.066381612 5194579.41104001 584391.346232398 5194570.19120361 584291.034924438 5194491.15256438 584184.023492333 5194404.74404223 584162.253119124 5194383.26438593 584139.89272035 5194360.4547473 584128.562297041 5194338.46504452 584119.651874604 5194316.94532453 584108.931435569 5194294.30562596 584084.71089062 5194264.19607715 584009.419376432 5194178.89739061 583968.488572612 5194133.32809687 583928.488177406 5194107.18858604 583893.357732599 5194079.56906716 583883.694145455 5194074.67601182 583867.38755773 5194066.41934326 583846.727706804 5194052.84287567 583836.52725215 5194046.13972265 583756.755905956 5193967.18099636 583724.295297683 5193932.10154781 583711.624848325 5193908.32187421 583691.254414347 5193883.78224845 583591.823615985 5193826.60338736 583570.793274388 5193806.24371974 583557.39301044 5193791.05395607 583533.972641526 5193768.89432087 583511.022243702 5193745.42469792 583501.842204663 5193741.76478552 583489.182202116 5193739.1648793 583468.771606054 5193706.6853432 583451.931093753 5193678.88573722 583421.77064221 5193651.33619733 583390.350062707 5193617.37673521 583358.459490698 5193583.63727348 583295.798276023 5193512.85838203 583274.147510384 5193471.75895 583259.886959878 5193442.44934912 583183.265656295 5193364.20061636 583141.784560925 5193302.98151292 583130.984022225 5193274.82188234 583114.903491413 5193245.93228762 583092.602798409 5193207.91282721 583051.911650411 5193144.06375114 583022.851151542 5193113.8842399 582995.61085177 5193093.66460846 582981.090696483 5193083.09480269 582973.420440263 5193069.0949991 582963.230126083 5193051.75524605 582965.710029067 5193047.59527934 582960.259836966 5193037.15542444 582950.669525145 5193020.04566576 582942.259245083 5193004.71588108 582929.178742569 5192977.62625225 582917.718302239 5192953.87657773 582900.987842822 5192928.05695432 582878.067409964 5192902.16736469 582811.746262828 5192832.21849791 582783.935916247 5192809.34890141 582762.175780734 5192798.0191439 582742.675853992 5192797.30925566 582726.855834484 5192792.89938923 582728.165679079 5192785.63946347 582723.335472528 5192774.54961328 582716.255239147 5192761.65979524 582704.155077147 5192751.1299776 582683.535028339 5192744.22016494 582667.214852815 5192732.09038784 582641.194550911 5192711.66075561 582619.324345211 5192696.81103885 582597.054055172 5192677.75137156 582578.393786582 5192660.5216646 582522.193068794 5192612.99249891 582493.15276908 5192591.8628919 582455.592574425 5192573.92329501 582352.581983529 5192521.784435 582331.8718484 5192510.47467376 582311.941678437 5192497.62492575 582296.911384177 5192479.78520769 582281.851139437 5192464.35546273 582252.572755061 5192449.44172849 582246.710938041 5192446.455854 582218.130851991 5192435.69612955 582176.900740979 5192420.79652024 582087.280198283 5192373.47753914 582058.77999275 5192356.76788231 582023.069747915 5192336.42830578 581955.249275542 5192297.34911592 581865.088646742 5192245.18019697 581831.138468663 5192228.39057209 581808.058491843 5192224.11074617 581774.088363572 5192209.7510941 581708.067913297 5192171.80188511 581682.717725523 5192156.46219784 581648.177317825 5192127.98271051 581552.036389063 5192058.75402492 581521.216055931 5192034.73446767 581494.055645024 5192007.68492526 581462.6652673 5191981.23539948 581436.664922932 5191957.72581081 581419.114809399 5191947.7860208 581407.104511649 5191929.97629043 581400.534422889 5191923.93639561 581393.864259675 5191914.14654425 581389.124135873 5191906.79665439 581379.463924818 5191893.87685533 581371.613718802 5191881.64703847 581363.853609133 5191874.25716575 581351.133483073 5191864.82734372 581331.763370172 5191854.41756959 581310.553309983 5191846.18778071 581291.123294657 5191840.63795137 581267.453294473 5191834.79814878 581248.683201565 5191825.50835878 581234.11279107 5191818.05308999 581231.463031061 5191812.69860067 581220.142829084 5191799.75881157 581202.792409343 5191774.37919856 581189.201998844 5191750.3795491 581182.131764421 5191736.8397436 581161.351287257 5191707.6701935 581134.22107282 5191690.10054557 581094.240906154 5191671.69097873 581060.990822217 5191659.11130778 581013.660822823 5191647.23170708 580971.870897801 5191640.48201675 580927.510968046 5191632.83235118 580879.07083546 5191613.87283887 580844.730571352 5191591.79328453 580798.870197524 5191561.18389313 580753.92957731 5191518.24463966 580717.929110997 5191485.33522101 580701.898740805 5191462.40557576 580688.208481239 5191445.6858457 580679.778474079 5191443.14592222 580664.348773884 5191454.40587812 580653.504886832 5191448.80186727 580648.578693681 5191446.25606061 580633.148334579 5191423.99640466 580622.667795934 5191393.8668123 580612.717354449 5191368.80715835 580595.957193304 5191356.23739794 580566.72717941 5191347.9076584 580551.667152948 5191342.6278041 580532.436852851 5191322.29814781 580509.106581813 5191302.35851017 580485.446584917 5191296.30871331 580443.066407771 5191276.11918598 580403.986033909 5191246.6997477 580350.455650314 5191212.90044224 580282.635433514 5191183.77116369 580205.8351252 5191147.45202046 580143.014865834 5191117.28272746 580078.424565554 5191084.44347641 580048.064015281 5191047.87407583 580029.533560725 5191019.40451381 580004.983328769 5191000.76487116 579967.953262509 5190987.26523939 579923.323081154 5190965.71574531 579868.462645619 5190928.15649751 579835.761993633 5190885.38718536 579816.671490524 5190854.03766205 579793.510983096 5190821.3081784 579752.440480473 5190783.48145969 579746.140396182 5190777.67896152 579676.829948938 5190735.07985899 579630.659385306 5190692.7906212 579564.698451875 5190625.53179203 579531.737954913 5190590.25239741 579510.39743232 5190556.89291362 579492.626984608 5190528.4333517 579465.656543213 5190497.64387059 579439.936264655 5190475.69427822 579407.555802436 5190442.1848611 579362.204921486 5190382.92582383 579339.744278964 5190342.71642941 579321.303922697 5190318.65682098 579295.373732555 5190301.10717924 579263.973593102 5190284.59755719 579237.083257912 5190259.09801555 579207.19268387 5190220.11865133 579181.76199461 5190176.3393184 579152.311654602 5190149.70980606 579110.751401464 5190124.02035368 579063.201085565 5190093.18099791 579044.428208018 5190081.66904062 579019.090823164 5190066.13157752 578966.180426366 5190029.27232584 578922.870091355 5189998.49294618 578888.639691135 5189966.94352281 578862.559068552 5189926.0241635 578838.52873908 5189901.23460032 578815.538645213 5189889.24487867 578789.168433249 5189869.93526434 578763.268194193 5189849.30566317 578744.388260847 5189847.06580132 578739.028178565 5189841.0459048 578730.088028998 5189830.34608527 578722.417797773 5189815.68630555 578714.157532672 5189799.03655312 578703.397418341 5189789.63672896 578684.507498179 5189788.06685941 578669.177653521 5189791.61690765 578656.517661476 5189788.13702409 578638.957564492 5189777.5472545 578621.567441753 5189765.62749988 578599.897194325 5189745.71786623 578574.547025596 5189728.84821818 578547.887013065 5189719.89848327 578514.616975632 5189707.54882835 578480.017123221 5189704.66906801 578451.617018215 5189690.18940999 578426.157008175 5189681.69966285 578404.137254432 5189688.0197177 578390.75721403 5189681.66987328 578363.196990006 5189661.02028473 578327.946982147 5189649.54063194 578299.937171879 5189650.94078151 578278.577344653 5189653.52087737 578266.007222363 5189642.99107864 578252.697079807 5189631.13130036 578236.427081023 5189626.07145793 578210.387042809 5189615.80173633 578202.66688166 5189604.68191607 578190.586708135 5189591.51214648 578172.586592704 5189579.59239713 578148.41646721 5189565.16271486 578125.736166164 5189541.71313253 578105.806005074 5189526.67343263 578095.466141187 5189530.73344535 578078.346282794 5189532.93352092 578044.546143635 5189514.63394327 578024.105863996 5189492.97432665 578006.305463845 5189465.61476322 577980.784908734 5189427.3553778 577969.58454528 5189404.05572625 577956.004146988 5189378.08612131 577946.473985791 5189366.26632124 577928.184078295 5189365.36644178 577905.774027909 5189355.37669693 577875.223760487 5189330.94717567 577852.283608033 5189315.20750383 577823.443279063 5189287.92800728 577813.893143505 5189277.43819169 577794.103006342 5189263.5084794 577775.96288833 5189251.14873826 577752.612670999 5189231.65911498 577737.782344154 5189208.9794792 577720.962045222 5189187.14984524 577697.601857313 5189169.20020383 577674.55185403 5189161.41043743 577643.621920768 5189154.83070399 577613.981867357 5189142.10103753 577600.976878164 5189133.86534911 577554.261538406 5189104.28185795 577525.361292531 5189081.19231351 577506.271013892 5189059.55269228 577487.170755922 5189039.02305776 577467.220639836 5189025.97333749 577445.970652165 5189019.52354485 577439.016374108 5189014.65756724 577416.430456434 5188998.85397575 577388.810326058 5188982.39434393 577346.119976504 5188948.76501319 577331.049773146 5188932.47530347 577324.259372818 5188908.13564167 577317.289001535 5188885.32596236 577306.058691942 5188864.45628539 577292.998421472 5188845.10660111 577277.037984339 5188815.56705901 577256.837573067 5188785.97754359 577235.217266854 5188761.66797259 577231.376946104 5188742.64822839 577223.136663936 5188724.23850369 577194.026727023 5188717.68876193 577171.666606075 5188703.28907487 577143.046180313 5188669.84965918 577122.645849081 5188644.45009502 577118.845473407 5188622.34038885 577112.545013641 5188594.70076574 577100.804574992 5188566.32118521 577082.344269207 5188542.93158509 577060.873958322 5188518.18202034 577039.153780593 5188500.70236827 577017.503733784 5188490.49262684 576997.663457883 5188468.19302251 576976.863053085 5188438.37351648 576958.882921322 5188424.6937953 576941.412707191 5188406.60412517 576925.372389443 5188383.24451097 576907.621924083 5188351.04501599 576887.501422347 5188315.94557151 576869.330921085 5188281.53610671 576850.410409065 5188246.22665786 576832.109885924 5188210.48721068 576808.439286293 5188168.50787388 576793.04890039 5188141.40830288 576769.77857616 5188114.86877432 576744.998475145 5188100.21910916 576718.308520516 5188093.03936414 576697.738433013 5188080.64964511 576674.428173853 5188057.64007408 576638.34786194 5188026.97067752 576595.637561303 5187994.44134583 576556.527286507 5187964.62195867 576523.347143508 5187944.34241699 576484.18693344 5187918.04298745 576452.246733115 5187894.92347366 576418.75640237 5187863.84406828 576390.546038795 5187832.8346292 576380.555688208 5187809.33498276 576375.655168337 5187778.18539894 576365.674810111 5187754.23575815 576353.144640668 5187739.96601379 576327.394423762 5187718.02644793 576309.174412461 5187710.51665601 576271.234189423 5187683.5772295 576240.402110655 5187656.93773156 576233.124068803 5187657.72787386 576225.834239865 5187660.05797394 576214.87431734 5187653.30825299 576198.634460779 5187644.93864603 576184.04461 5187638.5789846 576162.99478831 5187627.28949963 576146.354664754 5187603.26009628 576127.614756088 5187589.35060327 576106.594903317 5187576.30113996 576087.80507291 5187566.80159257 576062.475388892 5187558.98214016 576025.475953312 5187553.43286636 575998.106405775 5187551.32337852 575975.586768737 5187549.05380663 575954.31706723 5187544.37424284 575939.887183307 5187536.25460088 575929.737169917 5187525.10492104 575914.148521236 5187515.43169817 575912.317292537 5187514.29536597 575885.76744941 5187496.0960658 575861.527708176 5187486.08662179 575835.570282122 5187479.34088602 575831.208113 5187478.20725898 575808.84826181 5187463.81783671 575806.938006683 5187447.24807886 575805.357915364 5187440.398193 575803.077763077 5187429.33837247 575797.297703652 5187420.00859235 575791.927682993 5187413.31877177 575778.117784823 5187404.98912166 575762.437985094 5187400.379458 575738.178271836 5187391.91999511 575718.848555843 5187388.36038309 575706.768734994 5187386.23062436 575689.089024546 5187384.68095779 575658.259512094 5187380.98155176 575644.209726034 5187378.8218284 575618.250104463 5187373.86235177 575601.190352471 5187370.56269623 575581.200725273 5187371.4130405 575568.94094971 5187371.69325468 575548.361309906 5187371.21362617 575525.871638659 5187366.96407902 575486.642179172 5187357.65489286 575454.592496697 5187342.91564761 575445.582567783 5187337.72587297 575423.26285158 5187331.05635336 575400.373114675 5187322.60686632 575379.913304209 5187312.42735793 575363.673449834 5187304.0677517 575351.613609611 5187300.82800672 575337.753766715 5187295.57831905 575305.894027984 5187277.75910953 575294.484111203 5187270.77940017 575278.924141491 5187256.46985694 575264.544193081 5187244.60026201 575247.944219052 5187228.96075407 575232.384245731 5187214.43121369 575219.184318711 5187205.00156711 575211.97438135 5187201.16174364 575193.004376827 5187181.30233112 575179.86436086 5187166.80274745 575169.694380349 5187157.41304659 575163.294344543 5187148.73326979 575153.684407833 5187142.4435199 575138.614587 5187137.18385408 575123.334857743 5187136.98412819 575096.555336425 5187136.87460556 575070.565739892 5187133.2451133 575037.186251402 5187128.19577032 575001.006709423 5187117.15655273 574970.657155948 5187111.48716378 574943.557441657 5187099.89779182 574904.487756607 5187077.57876819 574888.307822264 5187064.58921988 574856.727897893 5187036.19014004 574844.997800766 5187018.40057331 574831.507654882 5186995.96109664 574820.837527609 5186977.52151932 574811.487438081 5186962.63187371 574799.147355995 5186945.06231515 574790.837282459 5186932.17262581 574786.057271899 5186926.59278133 574777.657321941 5186920.75300454 574766.21744136 5186915.7632711 574751.767587608 5186909.19361117 574728.857876346 5186902.06410885 574690.288321683 5186887.69497666 574663.758652189 5186879.205556 574639.70885492 5186865.89615218 574627.71890812 5186856.48648449 574599.569001107 5186832.53728825 574572.749105064 5186810.59804301 574546.379212499 5186789.31878148 574508.799314281 5186755.99987188 574479.069310937 5186724.76079637 574461.329265485 5186703.59138008 574449.419203712 5186687.56179498 574434.629200966 5186671.942256 574423.229255771 5186663.20256961 574409.409361287 5186654.87292114 574395.229347899 5186639.26337124 574383.249390361 5186629.19371206 574366.329646117 5186626.33404961 574356.119721672 5186620.03431121 574344.139752869 5186609.30466043 574331.169710523 5186593.26509453 574320.509570112 5186573.94552904 574310.609420016 5186554.85594712 574302.489280041 5186538.21630248 574290.109257948 5186523.95670362 574277.619173183 5186505.93715436 574257.768923824 5186470.62795526 574256.088764186 5186459.58812502 574240.768665721 5186437.78867416 574232.718430034 5186415.63909819 574227.588301466 5186402.77935251 574223.684064193 5186395.95814203 574222.248237434 5186393.44956588 574219.528073623 5186381.06977117 574213.0080005 5186369.970028 574205.397988375 5186361.27027388 574195.19804165 5186353.65055226 574190.40805513 5186349.4006915 574179.048064586 5186338.01103835 574169.408172286 5186334.14125926 574163.408196148 5186329.22142858 574157.058097245 5186316.79169929 574153.767894392 5186301.5319513 574153.857756445 5186293.60205016 574151.067688796 5186286.73218696 574149.907644965 5186282.96225541 574144.607531272 5186270.77250437 574138.617551084 5186265.62267646 574127.987581958 5186256.23298504 574118.487497906 5186241.34334316 574110.377347342 5186224.04370704 574105.847197163 5186210.53395904 574098.957013427 5186192.58430942 574092.09679139 5186172.43468715 574081.416675663 5186154.44510569 574083.456533079 5186148.29514722 574068.116470541 5186128.48567201 574053.696569537 5186119.04604899 574030.336646766 5186098.90672117 574017.336644795 5186085.0771285 574007.776649399 5186075.25742362 573992.766736471 5186064.48782808 573975.906909633 5186056.77822679 573958.987178643 5186054.5885566 573929.17770868 5186053.99909622 573912.917878793 5186046.73947856 573900.307957246 5186037.98981465 573884.858041081 5186026.55023558 573867.528045388 5186008.48077421 573860.607897058 5185992.51110036 573855.88780401 5185982.09131682 573848.427578628 5185961.05171695 573845.65748094 5185952.4218759 573840.337398661 5185941.99210323 573832.127398473 5185933.29236023 573820.147431741 5185922.55271045 573786.547618673 5185897.88362363 573762.367914731 5185878.61168353 573762.107728511 5185878.40430741 573733.297905499 5185858.20507846 573718.858039897 5185850.74543113 573703.808189165 5185843.50579192 573692.608182484 5185831.2361478 573685.428194412 5185824.31636394 573660.758422137 5185811.44696815 573628.128920935 5185805.96762079 573592.949439425 5185798.92833884 573543.569963968 5185777.14949795 573501.390442618 5185760.32046563 573462.590996195 5185751.46127168 573439.081290502 5185743.68179077 573403.541672717 5185728.2426223 573377.901794639 5185708.08333696 573358.171803147 5185687.56395061 573344.311548117 5185657.84457637 573339.551509464 5185650.50475482 573333.161466353 5185641.16498787 573326.581479419 5185634.91518501 573318.771533291 5185629.74539042 573309.131642629 5185625.87561202 573284.772058087 5185624.25606823 573250.312617559 5185620.30673469 573228.37300829 5185619.81713326 573215.023289799 5185622.08734309 573185.563951017 5185629.44777621 573161.744458162 5185633.78814689 573141.714885788 5185637.50845768 573117.965297806 5185636.33889724 573096.815625442 5185632.98931808 573081.76577971 5185625.9696766 573067.9358897 5185617.65002987 573051.056095696 5185611.71040739 573035.98627288 5185606.01074949 573022.716444046 5185601.88103941 573002.656711044 5185596.12147153 572985.386830585 5185584.67192629 572963.756998424 5185571.39248236 572943.377080221 5185554.38306366 572924.327179547 5185539.82358999 572911.707271822 5185531.73391885 572901.207333351 5185524.10420395 572880.55757392 5185516.13467496 572867.937677509 5185508.70499545 572847.487858503 5185497.435505 572829.298017428 5185487.28595987 572818.508054542 5185477.89627266 572801.708151257 5185465.5667305 572790.338157615 5185453.73708484 572780.778161579 5185443.70738383 572772.43811722 5185432.13768065 572764.177963032 5185414.17805757 572758.287840847 5185400.64833557 572754.777739596 5185390.90852264 572750.067626138 5185379.15875683 572744.217451047 5185362.54907342 572738.287389721 5185352.55930701 572733.147254315 5185339.04957137 572725.527051387 5185318.88996497 572720.17700194 5185310.22017136 572713.006996727 5185302.20040205 572705.207043887 5185296.59061328 572699.197088756 5185292.77076963 572690.017179593 5185288.25099167 572674.987297333 5185279.02137857 572664.197346232 5185270.29168318 572650.427374128 5185257.11209795 572635.39749963 5185248.33247916 572621.546562286 5185228.35492222 572613.967367093 5185217.42325747 572608.627317879 5185208.76346365 572603.297249695 5185198.99368382 572597.947200692 5185190.33389019 572592.607151353 5185181.66409651 572584.827157427 5185173.63433838 572572.277163765 5185160.47473119 572555.477250493 5185147.47519813 572542.317260473 5185133.86560767 572526.587313234 5185120.00606647 572516.427310152 5185108.85639088 572505.687287752 5185095.93674831 572494.997189865 5185078.60716117 572483.936986799 5185054.65766523 572476.846857566 5185039.3579877 572470.436630338 5185018.9983626 572458.606452552 5184995.69887223 572447.936321116 5184976.38931013 572440.136361488 5184970.33952724 572430.476502698 5184968.23972725 572418.986688215 5184966.7799519 572403.116945418 5184964.82026146 572389.187197395 5184964.65051338 572372.887436452 5184961.15085034 572342.467763219 5184947.55156953 572323.748027372 5184942.91196447 572296.988251046 5184927.1626456 572282.308304408 5184914.41307181 572267.018380139 5184902.32350055 572252.92843413 5184890.24390767 572237.618324172 5184867.12447783 572219.168208048 5184840.2251527 572207.458062935 5184818.91563524 572190.327986332 5184795.77623844 572178.657792256 5184771.59675703 572169.267545851 5184746.78724279 572164.327348991 5184729.74754935 572154.397015803 5184699.19811825 572137.876928713 5184676.06871057 572122.586986774 5184662.87915372 572102.457140098 5184650.06967892 572085.437329816 5184642.80007745 572067.147412785 5184627.81059757 572047.547445249 5184608.39119792 572025.507540646 5184590.04182844 571995.677878035 5184577.56252377 571969.448205679 5184568.42311176 571945.658459481 5184557.5536781 571921.858724659 5184547.34423621 571899.369047788 5184542.00470847 571856.839805398 5184540.61549006 571838.610017755 5184533.33591069 571813.510214286 5184517.60656298 571801.360275586 5184507.97690457 571785.430190751 5184485.51747845 571768.900105802 5184462.38807174 571759.609937469 5184442.2084972 571750.369675713 5184416.51899238 571739.829370916 5184386.83956208 571727.449125759 5184358.69014527 571716.348757412 5184324.60078161 571711.858339244 5184294.78124444 571702.387774686 5184250.78197852 571698.007326965 5184223.70793833 571692.236908138 5184188.04296499 571678.616515879 5184149.73370086 571671.196232769 5184124.72415482 571653.976058211 5184095.4148402 571644.785951899 5184078.9852161 571633.665821655 5184059.00567224 571627.515648978 5184041.95600142 571624.32529639 5184017.43637308 571618.724969507 5183991.79680247 571600.834696716 5183955.85758511 571590.314566998 5183936.54802198 571576.844376597 5183910.36860005 571562.614218627 5183885.27917787 571549.824119512 5183865.27966455 571528.394200569 5183846.50029121 571510.874258443 5183830.64081007 571488.834350841 5183811.85144794 571460.724580372 5183794.54217623 571438.744804931 5183783.6927113 571418.71503086 5183775.07318267 571398.545233649 5183764.91367635 571374.075382273 5183746.76435002 571351.605678971 5183739.66484594 571326.02591813 5183725.68548619 571294.916159008 5183705.68630341 571271.656297158 5183688.21694678 571247.816405377 5183668.30763197 571225.166521477 5183650.17827293 571204.37654095 5183628.31892831 571187.376704931 5183619.29935054 571158.087127232 5183612.1199707 571132.577487631 5183605.42051659 571110.027889609 5183604.49093501 571096.658200753 5183608.30112706 571077.838611777 5183612.05141812 571066.860652575 5183613.62728872 571065.088878364 5183613.88162442 571045.059311418 5183617.61193752 571026.329599271 5183614.08232049 571007.929833334 5183607.69273429 570992.639892787 5183594.28318229 570968.310070027 5183577.89383158 570945.090146329 5183556.67452303 570926.720122775 5183534.84513493 570909.489964588 5183506.19581403 570898.469905883 5183490.41621569 570884.259714622 5183463.12682293 570871.929610055 5183443.12730254 570859.719540318 5183425.34775146 570846.919679593 5183419.45805811 570836.619872268 5183419.55824262 570823.870150332 5183422.05844045 570813.530395015 5183425.23858606 570801.42062091 5183425.31880348 570783.120919982 5183422.89916471 570764.2611817 5183417.609573 570747.221395223 5183411.44995965 570725.851603927 5183400.17049034 570690.411847401 5183375.2814501 570663.581951345 5183351.59223917 570649.991933264 5183335.33269375 570633.58189381 5183314.63325641 570616.351942797 5183298.33377725 570588.892099255 5183277.06454677 570566.412398741 5183269.96504396 570546.832623008 5183261.57550544 570520.002940305 5183250.67613015 570490.723123479 5183228.94693868 570476.09310321 5183211.34742958 570470.502975612 5183197.39771027 570463.012791271 5183177.89809679 570450.762775238 5183163.20850729 570436.862986975 5183160.39879449 570420.363293979 5183160.41909218 570403.433561554 5183157.57943449 570392.343604713 5183147.74976147 570381.293581186 5183133.94013905 570372.193558583 5183122.37045255 570363.553516521 5183110.14076626 570356.72345227 5183098.6010384 570353.033381187 5183090.17121374 570351.123120402 5183072.29147877 570344.392915325 5183052.3618573 570329.633077584 5183045.58221136 570320.673286362 5183048.12234047 570317.483348693 5183048.30239578 570306.073631865 5183052.5825467 570291.53391412 5183053.29280021 570269.584314517 5183052.81320292 570248.914589126 5183046.17366197 570234.244833749 5183044.46394904 570216.075164516 5183044.02428297 570199.585453605 5183042.95459467 570171.705985217 5183043.73508826 570156.456211215 5183040.2454088 570133.966519518 5183033.58590106 570114.436664 5183020.34642481 570100.956704569 5183007.62683256 570088.6667523 5182996.67719599 570075.836711623 5182979.76764614 570063.006678291 5182963.29809065 570051.936692886 5182951.70844035 570046.406474163 5182932.2387917 570043.22631414 5182918.96902053 570037.686124739 5182901.25934935 570029.036094905 5182889.69965498 570011.416284919 5182881.33008158 569989.51660509 5182876.01054617 569971.256854339 5182870.50094743 569939.027419555 5182868.36155772 569912.227910176 5182867.83204905 569892.238285956 5182868.03240783 569869.6786984 5182867.55282187 569847.729092229 5182866.63323056 569827.04937914 5182860.66368159 569804.609618452 5182849.81422754 569779.479856731 5182835.85486237 569774.559838523 5182829.18503757 569764.859821277 5182817.16536839 569755.579832649 5182807.35566304 569742.139822776 5182791.54611053 569735.459749831 5182779.55638639 569726.179561524 5182757.61683796 569716.389662433 5182752.65707917 569693.829857317 5182738.93766465 569677.890002877 5182729.71807223 569658.340171398 5182717.79858005 569637.040278193 5182700.13919382 569613.770413978 5182681.9998495 569593.040564829 5182667.65041023 569570.490745804 5182653.06100704 569550.370874612 5182638.05156535 569530.66085104 5182614.23223034 569515.300790584 5182593.10278183 569506.574549822 5182570.92934209 569505.450563208 5182568.07328413 569496.190324888 5182543.04377578 569483.800086812 5182514.46437006 569470.38003798 5182496.22484917 569455.590036359 5182479.29533614 569443.369976415 5182461.73578477 569432.33109862 5182443.61244232 569426.729838928 5182434.41643985 569418.059619319 5182411.16689793 569425.899303846 5182400.88688907 569425.239174971 5182392.28701238 569425.178835684 5182371.5572819 569420.788696159 5182358.05753622 569413.338446781 5182334.37797781 569408.898170493 5182312.4883417 569398.477893109 5182283.70890316 569389.037499794 5182248.97952395 569374.22707952 5182206.47034284 569358.22686966 5182175.41103508 569355.026748154 5182164.35123632 569337.386753503 5182144.52181292 569314.727090957 5182139.19229277 569300.837283674 5182135.06259808 569278.337618193 5182129.73307506 569238.517916471 5182102.37415154 569227.607912969 5182089.67451393 569210.987946997 5182072.72503497 569194.537949091 5182054.01557576 569177.327983405 5182036.39611626 569162.577910712 5182015.05666038 569151.587807978 5181996.18710433 569145.247470781 5181968.32758047 569142.757177753 5181947.57789462 569143.14683113 5181926.85815611 569144.856517674 5181909.67834777 569148.37618133 5181893.17849775 569151.335804888 5181873.58869793 569156.595335077 5181850.93889601 569163.734739796 5181822.78913121 569178.053711115 5181776.42947198 569185.732982948 5181740.79979417 569193.362331326 5181709.79005736 569197.411873017 5181686.4702859 569203.351292579 5181657.87054849 569208.710889164 5181639.41069024 569212.82034998 5181611.23098056 569220.369598451 5181574.05132492 569226.309006979 5181544.79159591 569236.498332537 5181515.36179181 569260.446996192 5181461.39205525 569267.566642848 5181448.03209877 569276.616097779 5181425.20222977 569285.485599333 5181405.01232983 569296.295093732 5181386.62237129 569305.314592333 5181366.43246856 569312.504136087 5181346.89259067 569320.913656922 5181327.36269043 569328.003140948 5181304.07286282 569338.67240601 5181271.56308934 569347.661955572 5181254.463147 569363.331126925 5181222.01328165 569380.030329522 5181192.66335738 569382.568093636 5181152.94309365 569371.969329998 5181122.48191173 569359.216991597 5180965.2966766 569356.466493937 5180931.79715987 569400.714079377 5180835.79759475 569406.088560822 5180810.42282477 569470.210304718 5180686.2670101 569494.709058415 5180638.73592729 569517.958036324 5180603.42345928 569528.45725426 5180567.98622535 569551.956060471 5180522.54888325 569565.080144887 5180482.04916657 569632.701739862 5180353.29959366 569635.451395395 5180335.54977244 569643.076210057 5180333.11216466 569656.200418968 5180300.23734905 569788.693776375 5180050.3631495 569791.44343132 5180032.61332794 569866.564916472 5179906.48857881 569890.063717623 5179861.051234 569923.687200949 5179808.11380027 569952.435481921 5179737.30168549 570019.932231169 5179618.73947505 570020.057060485 5179608.5521038 570048.555680866 5179558.11473047 570100.428142559 5179464.73998058 570152.175857315 5179386.6150362 570165.05024202 5179364.36508607 570372.665308705 5179005.67838195 570398.414229224 5178970.49086053 570497.034354773 5178791.30384626 570507.408819459 5178771.11641432 570517.658412031 5178758.49138775 570530.657616301 5178725.67906924 570556.406575207 5178692.92901552 570572.030685854 5178657.55418139 570721.773641377 5178407.99212157 570752.772371449 5178367.74206594 570752.897157919 5178355.05472589 570794.270602216 5178309.74204377 570804.76993574 5178281.92970606 570828.143853053 5178244.11725905 570838.393529426 5178236.61716619 570843.643132023 5178218.86729637 570895.640990572 5178150.86720761 570906.140448343 5178130.55477369 570969.012585702 5178032.05487325 570982.761850645 5178003.99247814 571001.386233398 5177988.67983036 571074.382815125 5177868.86751359 571084.757445356 5177858.80495065 571105.881316483 5177815.80510957 571118.630746215 5177795.55510817 571135.317716381 5177769.52353058 571155.067089262 5177738.67939336 571178.3788501 5177702.36643709 571191.25342064 5177679.61618372 571204.252969058 5177654.36592674 571217.127621113 5177641.86568032 571245.626690569 5177593.92762302 571279.125724919 5177553.67697916 571351.748326282 5177427.55056576 571545.617370039 5177145.35936018 571579.116389857 5177102.54622782 571586.991079517 5177082.29607466 571607.74044401 5177052.10818228 571625.864878269 5177024.3578394 571649.114175186 5176991.60740149 571664.738618166 5176958.79460298 571692.987839876 5176928.60657654 571703.487440808 5176903.35637533 571747.361166652 5176847.98055676 571827.483687211 5176726.97906069 571866.107595415 5176681.72834714 571899.856518111 5176626.29021987 572000.478538353 5176490.2883681 572054.851855255 5176407.09987031 572095.975720517 5176361.84912263 572121.974892958 5176318.97364763 572225.096878772 5176183.03427991 572225.346775964 5176170.34677318 572238.096495436 5176165.40904531 572253.471029412 5176142.90876785 572269.095516803 5176114.9709854 572547.712485134 5175757.5910215 572760.893965755 5175497.02478568 572844.079123081 5175395.33584209 572849.453886825 5175377.5857502 572872.453320513 5175360.08535156 572898.327526985 5175319.77240606 572988.574969836 5175206.52085537 573545.934649102 5174557.76147007 573591.308408477 5174504.94822102 573761.428742256 5174303.75793427 574338.787798271 5173591.748739 574377.661762125 5173548.09188038 574390.286425936 5173533.93543306 574408.161060683 5173529.06014185 574413.285929702 5173524.06006126 574458.785242578 5173544.93429316 574497.159353301 5173519.99618045 574573.657783353 5173498.05743741 574797.278606743 5173490.55375758 574861.027290862 5173470.99022665 574950.025585292 5173461.86377021 574960.6500804 5173418.801141 574966.149742699 5173385.8635856 575005.648162765 5173266.92556518 575106.895002345 5173085.23661197 575180.017919609 5172981.36054137 575194.954994324 5172960.11032358 574893.083955377 5172742.02169226 574523.842045287 5172926.37124191 574431.78157212 5172973.06019764 574381.095188705 5172998.74850092 573839.10716416 5173273.56966953 573150.312561799 5173965.33082721 572757.510447767 5174371.68114196 572589.577408777 5174545.46524465 571865.534280649 5175294.60286016 571450.482921095 5175715.64156857 571150.678513564 5176019.77205896 571044.493889161 5176127.52402428 570945.121584151 5176228.30712328 569545.035437276 5177701.17800856 568850.236130719 5177670.9721113 568728.05098341 5177669.56812704 568116.875348472 5177673.73573361 568078.938388472 5177651.08013966 567961.378124028 5177646.45731162 567681.883438769 5177635.49372379 567475.88721203 5177610.9349869 567415.200550961 5177572.46726768 567333.139183745 5177520.43740788 566815.896282877 5177192.38357472 566323.65295412 5176877.8916627 565860.034179866 5176581.71164289 565488.224218152 5176079.77913727 565481.161765349 5176070.21673024 565453.411951475 5176032.74834523 565453.532749863 5175573.30925204 565453.655343666 5175310.37083667 565617.586827656 5174989.86688538 565431.585416794 5174453.1807221 565350.834790518 5174220.15001986 565246.771769923 5173952.30706415 565213.397238207 5173935.71381454 565064.274326279 5173861.40354321 564699.719173033 5173922.59738972 564566.534359829 5173944.97471402 563637.055802585 5174379.61723962 563363.247225477 5174254.4650846 563279.623352728 5174209.15379638 563105.250305583 5174073.93737222 563072.250867288 5174068.37540315 562974.752526144 5174051.90822064 562754.256276048 5174014.7242604 561973.771623433 5174095.5503325 561791.836067404 5173949.20888339 561777.273175625 5173882.36502476 561770.085367599 5173837.83365963 561659.957984095 5173392.17686987 561456.271602598 5173126.64754164 561350.647173711 5172988.96101705 561168.336898399 5172875.96336649 561122.274951155 5172846.62020246 561115.025082706 5172846.43281955 561069.525647811 5172819.40215804 561031.526119196 5172796.8088985 561001.213949163 5172774.24676329 560948.151970812 5172729.27861894 560796.715775128 5172583.28023213 560721.965447171 5172415.81171328 560764.897430781 5171949.49580538 561279.573152618 5171710.23630282 561498.193996626 5171691.76400878 561983.684774784 5171650.75615382 562458.0508877 5171622.31105753 562848.352779966 5171259.02192256 562859.539976858 5171248.61544857 562968.473798092 5171071.95666214 563003.593971717 5170638.89154875 562892.280327427 5170315.45417486 562605.344449561 5169956.862956 562521.533105642 5169922.6452817 562132.663885022 5169807.49421506 561900.478973164 5169652.65307941 561826.354795942 5169603.18515649 561760.418026613 5169559.18588925 561511.731892284 5169255.37536316 561503.544436728 5169245.37542689 561232.357556692 5168831.43952103 560884.234916915 5168461.19234912 560779.54675206 5168215.66112953 560843.231538989 5168057.81555244 561038.535743858 5167573.71625541 561087.032326471 5167318.58910831 561035.28141488 5167140.27627399 560868.532687849 5166982.99635267 560671.471626746 5166792.09160942 560268.163713109 5166565.78310088 559962.168798069 5166551.63082396 559945.856671366 5166560.75609864 559415.806337168 5166857.39010275 559202.310174281 5166873.86182968 559032.875720978 5166886.95794503 558492.756506145 5166559.43164058 558332.508941898 5166530.87106572 557965.577012159 5166465.43795764 557486.715217369 5166927.60404274 557309.346432995 5167097.17042 557218.850875963 5167183.67258413 557188.102386366 5167213.04831805 557035.047413113 5167359.39571248 557005.673859732 5167387.55266058 556951.989002865 5167438.83518359 556876.680213447 5167510.80571625 556710.56030707 5167383.80753859 556641.187430972 5167330.77705381 556165.510935237 5166648.46758678 555813.836652007 5166611.84826032 555643.345838285 5166843.66525374 555579.975893963 5167076.44918541 555516.231468122 5167353.67092001 555201.307696538 5167484.14578984 555092.187006035 5167489.24138159 554803.260918577 5167502.74625542 554761.950429776 5167538.02842401 554743.638821366 5167553.65383076 554610.457814958 5167667.68803543 554539.088767291 5167944.8785355 554537.714104559 5167969.69122118 554528.216463055 5168143.56751933 554514.594828928 5168391.3818683 554511.658053458 5168444.69476578 554450.598149601 5168462.25837087 554254.481493866 5168518.82441583 554212.483281361 5168530.91892377 554145.733204339 5168296.94974861 554139.232048814 5168174.63656741 554148.541998444 5167985.04144484 553470.693821533 5168011.80270507 553439.712858505 5169533.81262435 553427.732396188 5171162.82285219 553403.752034889 5172759.83301632 553383.771651848 5174368.84314128 553355.791643031 5175981.85334717 553351.810650603 5177595.86318564 553330.828407997 5179198.84213875 551741.892997035 5179287.86144805 550123.957608117 5179265.88261581 548516.021850388 5179243.90363668 546914.085935204 5179232.92441706 545321.149602686 5179201.94532802 543650.216504964 5179203.96679193 542032.28124317 5179264.98679513 540430.345259956 5179248.00759231 538756.412126805 5179248.02907838 537221.431611674 5179254.05218577 535605.424529336 5179255.07890249 533990.417465329 5179274.10537635 532381.410489906 5179317.13142772 530787.403635033 5179294.15814945 529189.396799056 5179301.18453868 527600.390098711 5179330.21047239 526019.384250467 5179566.23320789 524404.377615024 5179556.26010977 522796.370766589 5179501.28761151 521175.36375734 5179442.31544096 519525.325264365 5179380.28135453 519394.355935139 5179375.34611238 517916.328271882 5179332.36865748 516306.291369745 5179249.39311185 514626.252972295 5179185.41839672 513009.216520757 5179180.44179076 511387.180069969 5179185.46510066 509763.143811634 5179209.48807252 508151.107766549 5179225.51104065 506539.070830495 5179170.5356119 504914.034421812 5179180.55899068 503301.998167785 5179179.5824689 501695.962547851 5179211.60507996 500088.927078579 5179251.62748838 498462.889373269 5179247.62316423 496848.851735509 5179237.6171233 495302.815676504 5179229.61132198 495346.84729782 5180821.57463446 495340.878395801 5182446.53695695 495368.909626316 5184043.49993398 495375.93995181 5185617.46334803 495394.971242756 5187232.42574426 495420.002151849 5188825.38856517 495446.03275704 5190405.35159924 495503.064321413 5192017.3136871 495524.095615327 5193646.27538485 495564.126526155 5195247.23755609 495560.156779411 5196842.20002694 495603.188010644 5198467.16141745 495611.218295986 5200062.12367648 495637.248778541 5201663.08557362 495650.279726696 5203296.04675013 495676.309926805 5204889.00866588 495711.353257682 5206502.98535492 495747.398906727 5208109.96516074 495763.443521209 5209683.94554618 495759.488657558 5211278.92586094 495757.534996631 5212916.90557524 495769.579718949 5214497.88577718 495749.624731671 5216090.86619041 495735.659231801 5217311.85113751 494959.659115045 5217313.86122848 494970.705119564 5218929.84108862 494995.750458042 5220523.8209809 495003.795943673 5222123.80097645 495029.841657324 5223733.78054491 495057.886755016 5225323.76027618 495042.932737237 5226942.74021409 495039.977911121 5228534.72027518 495038.023517812 5230142.7000773 495024.069605433 5231766.67981888 495019.115198974 5233362.65844546 495028.162292141 5234979.63287876 495020.209257124 5236590.60763539 495020.25677792 5238222.58188682 495069.303271475 5239826.55568717 495109.350249214 5241446.52931016 495126.397469637 5243072.50317726 495135.444059105 5244676.47748387 495131.495656431 5246452.01174692 494969.496243897 5246452.45230827 494795.543352658 5248054.43014654 494770.589645386 5249647.40528159 494775.636449952 5251262.3794381 494778.681964043 5252833.35429019 494796.728248945 5254433.32831968 494809.774558379 5256034.30238152 494927.819864232 5257612.27448102 494951.864575155 5259160.24900567 495092.910126374 5260757.22018159 495122.945638598 5262364.19987764 495170.980399668 5263944.17941097 495203.018507466 5265676.15736808 495207.054052006 5267287.13741823 495199.089378382 5268885.11787935 495275.123248513 5270449.09659807 495273.160182488 5272126.07581067 495167.197052713 5273752.05834863 495209.110948557 5275537.03499854 495210.271082612 5277133.01502885 495241.46229853 5278739.99404238 495300.561408565 5280442.97098496 495352.374997453 5281951.95047877 495408.40961765 5283572.92834458 495395.446087868 5285230.90769069 493836.441274287 5285240.57888839 493825.510468566 5286899.93388971 493824.545357675 5288432.91510224 493806.596553693 5290017.89177349 493775.648970343 5291608.86854032 493750.699693533 5293150.84586706 493728.753104446 5294776.82181349 493731.649256886 5296388.79709995 493731.935767607 5296550.66961577 493776.730713998 5297964.77137662 493783.330511173 5298155.64321211 493838.093445917 5299556.7446901 493846.756365626 5299768.80360605 493904.424709744 5301149.71765226 493913.118863083 5301361.8390452 493921.563243168 5301580.83533847 493954.755974827 5302733.94120834 493960.013024057 5302956.00006086 493955.9946899 5304317.66657612 493956.565520734 5304575.66254475 493954.046946923 5305931.6415582 493953.86701868 5306165.63792368 493952.442891526 5307544.61650254 493952.326104836 5307798.61254779 493954.463320831 5309145.59144216 493954.877885721 5309403.33739959 493963.859589912 5310780.31549167 493964.929757913 5311018.81171352 493961.567301206 5312372.22816381 493960.325626435 5312628.97419436 493960.367397812 5313923.51638735 493431.384461735 5313928.53994069 493490.434964883 5315540.51239895 493379.48653035 5317130.50072358 493388.531252847 5318741.49042006 493360.577546444 5320361.4818554 493352.622551027 5321960.47243614 493352.081509723 5323845.46083966 492804.884251059 5323832.30308164 492804.728410709 5323846.4905109 492786.743364527 5325445.48257286 492776.789998417 5327070.47405103 492758.836543209 5328679.46609166 492788.880984317 5330290.45520526 492781.9264423 5331879.44663193 492780.972009399 5333482.43757738 492783.017951372 5335104.42818006 492746.065367191 5336708.42150474 492720.11243214 5338317.41412255 492733.157548137 5339930.4039689 492739.203056658 5341545.39423472 492746.063959719 5343265.32127047 492951.176985921 5343257.86832142 492951.052204394 5343265.36828563 492922.29539326 5344928.3569705 492934.35169547 5346483.34022611 492947.410593318 5348110.32261461 492938.469013554 5349693.30712058 492927.530125579 5351349.29100348 492967.586978927 5352956.27129905 492969.645361767 5354555.25463466 492999.703801659 5356189.23530221 493036.761092332 5357797.21559205 493033.82054541 5359419.19892554 493050.878525029 5361022.18076849 493074.959125943 5362394.97688371 493169.268276769 5362392.59408621 493175.88894744 5363984.13924712 493176.488060854 5364130.88764683 493189.479189174 5365604.18347051 493191.047021142 5365750.86928435 493204.537530078 5367207.16519159 493206.293819464 5367380.03820552 493234.845517007 5368810.83304566 493238.445335476 5368978.83094687 493267.496754917 5370400.12577509 493271.190904903 5370583.74849247 493312.272784848 5371989.04571345 493315.329980969 5373555.07264266 493327.388340583 5375159.09941695 493337.44704718 5376772.1264789 493341.504649911 5378352.15344092 493360.562932647 5379960.1795722 493372.621192826 5381564.20619109 493399.679270822 5383172.23157814 493468.737445095 5384806.25386166 493479.37420531 5386074.14118232 - - - - 373992.834567751,5252100.90249579 375578.907291097,5252060.9016806 377183.981372119,5252035.90076999 378770.053836318,5251988.90012694 380424.132814015,5252045.89859687 382036.206902856,5252012.8979458 383378.268520258,5251983.89746 385004.34489571,5252002.89649079 386772.428209329,5252032.89545573 388359.488754287,5251990.89431465 389964.549770751,5251954.89312519 391575.611064042,5251920.89196047 393178.672571485,5251902.89076516 393228.738270271,5253772.88131533 393228.792456634,5255363.87321734 393234.396568643,5255577.49913186 393290.022245729,5255616.371974 393390.058438338,5255644.18441468 393456.779853272,5255644.18446989 393523.470080964,5255646.05951586 393612.378616319,5255608.99727381 393710.566996525,5255520.06029167 393761.41076364,5255461.24811933 393799.504685641,5255421.87334027 393801.348444994,5255419.99835078 393841.473568551,5255376.87359007 393843.129820376,5255374.99860038 393872.227230318,5255341.53053376 393872.254834063,5255341.49878372 393897.254849763,5255312.87393979 393937.723412979,5255260.37422077 393978.628478725,5255178.31214177 394000.095924966,5255115.37495644 394028.845055521,5255056.68775393 394150.002619737,5254954.68830693 394178.156529424,5254854.00129532 394182.905333014,5254813.68898684 394167.965771729,5254770.93918013 394099.587293418,5254748.62675282 394009.927251763,5254741.75174377 393877.07762318,5254723.93926859 393780.791470774,5254692.25187944 393703.692246657,5254621.56469184 393669.876928002,5254578.31489037 393670.062654952,5254526.25264556 393700.781229152,5254485.56535535 393760.812865314,5254427.44065828 393853.751326504,5254348.19106971 393938.597961266,5254334.50365964 393995.006383031,5254332.81618377 394145.355850435,5254326.25375792 394274.486167185,5254332.44126676 394384.022495763,5254354.19119954 394496.36942946,5254317.6914001 394536.806777902,5254266.94164156 394531.897189883,5254175.75455242 394583.272771438,5254133.81725321 394667.119014884,5254110.19237722 394714.55412945,5253986.94293421 394721.021368279,5253935.8181618 394744.520795483,5253892.44335681 394735.643469879,5253835.25610857 394714.858845106,5253761.25643422 394717.749468196,5253733.17612058 394721.13823463,5253700.25670446 394781.639561834,5253669.81934075 394850.141230463,5253640.19447216 394876.479432891,5253639.04667605 394969.176980153,5253635.00699702 394976.271037152,5253635.81949367 395519.510298066,5253611.56960918 395527.698069839,5253610.13211528 395591.795584246,5253645.88197253 395621.11081318,5253691.13179129 395623.173960433,5253707.38172584 395623.176417391,5253707.40122329 395626.206167995,5253731.44412897 395624.42712544,5253796.81886485 395634.993873549,5253906.81842208 395675.779923451,5253998.44306012 395723.252798144,5254063.06781092 395768.693664449,5254108.19264151 395804.538842082,5254108.56764903 395837.383216462,5254089.31773351 395891.728427757,5254069.75532382 395967.856422362,5254069.50534305 396028.203464222,5254095.56775665 396091.7057842,5254090.2552933 396158.018641153,5254025.69305678 396207.143077038,5253954.25583919 396239.860088802,5253867.81867238 396265.140567313,5253817.38136647 396287.703064163,5253791.94396523 396349.451795259,5253686.44436663 396349.452518554,5253686.44313108 396435.981260687,5253538.63241924 396471.021093905,5253535.14250544 396585.330355029,5253523.75747785 396741.052982495,5253460.13270856 396914.055403227,5253336.13314084 397183.096578436,5253318.38319059 397545.171773706,5253275.94581428 397881.089840105,5253237.88341716 398071.64310277,5253157.87611795 398411.165163381,5253015.32152345 398631.698949906,5252845.19695914 399211.553391767,5252512.82267203 399663.185514918,5252316.76194781 399663.18890481,5252316.76047621 399860.037217754,5252231.26058686 400083.512972148,5252184.8230912 400127.578144634,5252211.26051796 400233.550599022,5252199.82299713 400392.403112184,5252270.94779296 400644.262451817,5252429.8224055 400740.299196128,5252477.88478972 400989.095604804,5252627.32196682 401273.410740343,5252782.18896504 401273.424874001,5252782.19666367 401461.623488353,5252884.69648485 402111.037066948,5253242.0084967 402756.197989468,5253528.32078538 402756.232668418,5253528.33619738 402793.32506112,5253544.82077835 402867.907487764,5253578.15366794 403433.110881015,5253830.75824447 404070.552136632,5254094.38338663 404491.656023924,5254280.81508194 404491.669532849,5254280.82106263 404783.560952753,5254410.07122691 405363.374686197,5254661.44665537 405734.208224886,5254827.88450101 406041.500987131,5254961.06164401 406211.470139018,5255034.72431631 406211.538019337,5255034.75373486 407660.240902993,5255662.48321719 407660.246229705,5255662.48552528 409257.927861926,5256354.76517912 409768.695446346,5256576.08211699 409768.735834776,5256576.09961805 410876.518642679,5257056.12235784 412464.215509083,5257744.10071817 412464.225407797,5257744.10500746 413134.450013265,5258034.52484274 413134.466727295,5258034.53208522 414078.413610222,5258443.55154306 415221.098420247,5258938.68567606 415571.629807004,5259102.51900859 415769.741983816,5259195.11379287 416434.655664678,5259066.41721755 417233.950045496,5258911.95358296 417489.386345476,5258862.59051942 418521.576772072,5257884.97093374 418521.591206801,5257884.95726216 418620.339921949,5257791.45653319 418831.135731339,5257384.15777492 418831.142864938,5257384.14399141 419054.28907216,5256952.8940561 419277.644919394,5256325.22223341 419856.168262366,5254699.46313352 419856.169413348,5254699.45989922 419961.504463663,5254403.46415262 420370.297607175,5253877.47685802 420370.308017787,5253877.46346286 420684.45751304,5253473.27560163 420699.582566932,5253465.52549195 420722.613575374,5253443.65040793 420764.831886821,5253403.65025458 420829.73680308,5253321.52519332 420834.64266021,5253306.21276429 420854.485740219,5253272.90031502 420866.891582105,5253252.40034442 420911.702847702,5253185.7753913 420916.608703616,5253170.4004639 420929.139875651,5253160.0879085 420943.95161062,5253126.9005183 420948.92029462,5253121.71300567 420976.294371275,5253075.65058271 420989.130741489,5253056.910871 420989.137780079,5253056.90059542 421006.168577563,5253032.02561281 421021.011645038,5253001.33820388 421045.854749242,5252965.46322743 421050.760526428,5252947.58832284 421095.478050707,5252880.96338574 421190.632859417,5252775.46322344 421240.569406453,5252713.83819618 421287.849247044,5252639.52580995 421318.005367827,5252616.21317859 421315.286159703,5252603.58831637 421350.066321376,5252547.21341889 421382.409098178,5252495.96350618 421384.314008781,5252452.71385708 421391.845169808,5252445.08884084 421391.719840624,5252434.83893032 421396.030730076,5252381.526842 421375.216517007,5252341.1524139 421374.62137633,5252297.90279171 421389.339211332,5252259.71546142 421439.620257473,5252220.90275569 421482.62079669,5252210.08988797 421515.370809449,5252189.33971675 421547.839000509,5252150.77720407 421547.525768606,5252127.96490559 421557.619477922,5252120.15236577 421554.900351987,5252110.08998223 421562.462842742,5252104.90244671 421559.837466754,5252094.77756272 421579.680564474,5252061.40264186 421612.18009031,5252025.40261033 421690.211223396,5251971.02725899 421722.616760143,5251927.4647989 421729.92868152,5251904.46492394 421734.020257746,5251833.27800685 421753.863120106,5251792.34065896 421788.862620665,5251753.71563313 421889.644066225,5251693.90261076 422075.827735249,5251576.96673523 422075.831736897,5251576.96422193 422108.800519537,5251556.276567 422205.645840043,5251504.99070285 422207.113423663,5251504.21352236 422244.926218816,5251488.58827447 422292.238430961,5251448.1506557 422350.049479048,5251363.71333411 422397.70382296,5251271.46369329 422432.732605257,5251169.65177332 422437.887611685,5251126.65211682 422435.792387474,5251081.15255657 422428.885208473,5251056.21535543 422411.540394442,5251033.96573417 422294.688318968,5250847.59360662 422255.654102918,5250779.59461272 422219.55840433,5250741.97031117 422061.99058887,5250679.15993049 422061.990289746,5250679.15981114 422010.145087406,5250658.47312548 421961.424283542,5250626.16139231 421855.856373036,5250525.97581499 421817.417266538,5250501.03890998 421735.883675561,5250481.85237194 421596.130524203,5250476.16627958 421514.722253168,5250467.04214947 421468.689318028,5250444.85528805 421437.437048994,5250394.48102527 421385.401717388,5250301.16982975 421335.678528613,5250195.23371455 421331.737705773,5250093.67212132 421345.735002741,5249999.48529523 421345.537144329,5249912.26386602 421345.22786428,5249775.92471481 421330.504103495,5249628.73861119 421338.875153431,5249499.17714312 421346.218410959,5249478.73975099 421345.591940809,5249433.052648 421357.778483914,5249394.74036538 421359.683396659,5249351.49071882 421369.55787616,5249328.42832716 421388.837111648,5249252.0538087 421423.517340626,5249000.05566585 421452.195427332,5248684.68313187 421461.975917627,5248654.05831132 421524.318507261,5248574.43346162 421551.567482383,5248523.30867083 421555.157836141,5248413.99708926 421539.312288896,5248368.49761892 421513.247526146,5248315.49829921 421511.959865427,5248306.3313929 421507.5586117,5248274.99869791 421494.776839725,5248267.49887062 421340.200046766,5247926.69059106 421332.261646246,5247904.0033505 421282.412996707,5247785.31727213 421271.379475581,5247721.88040245 421269.46880705,5247584.75658579 421247.996825848,5247498.63249077 421244.400567,5247422.57066615 421252.336254887,5247360.19613367 421277.364405893,5247245.38441401 421304.456728695,5247181.44724735 421339.299551238,5247127.63493585 421471.860304437,5246978.44769333 421531.765467603,5246901.51039967 421541.921863026,5246898.82284537 421541.671292921,5246881.07300122 421568.982868386,5246832.4482153 421593.91995487,5246801.57329442 421593.700633866,5246783.7609511 421611.231792789,5246768.32345282 421613.66902469,5246758.13602316 421625.918251708,5246725.01121945 421633.230187974,5246702.011365 421635.604998005,5246694.32391421 421639.93604477,5246678.39095562 421645.322834495,5246658.57415329 421650.29145582,5246650.94918262 421644.821612398,5246620.44948996 421629.007389331,5246577.57498222 421600.161055511,5246517.01322451 421592.253901606,5246494.26348113 421558.751936342,5246456.57655645 421510.09362297,5246426.76467374 421491.873574267,5246399.07754727 421496.34096919,5246353.2654105 421516.309362567,5246327.64048607 421576.496443293,5246270.95303882 421616.746461364,5246242.39049484 421659.746948449,5246226.57782083 421715.435305397,5246213.20253434 421755.779319922,5246192.26492625 421808.372488355,5246135.70254511 421823.215606206,5246104.95270991 421832.77703582,5246064.20300146 421814.086858946,5245993.32876096 421792.834284135,5245927.57949187 421792.671749198,5245729.39374021 421797.327140677,5245698.89397675 421819.764106339,5245665.5816151 421855.170759483,5245652.33148713 421944.047787528,5245651.14338276 421984.517061154,5245637.95572049 422052.078932474,5245568.33087781 422083.297635789,5245543.83088341 422094.860118614,5245534.76838561 422231.393049078,5245487.20538154 422494.835058808,5245435.32906221 422527.553920511,5245414.57903166 422585.115589298,5245345.26678407 422604.927507429,5245311.95445981 422614.582703433,5245271.14227407 422606.017937438,5245205.26794313 422600.673425301,5245184.95566728 422595.548148442,5245179.95574776 422577.171372993,5245137.08126729 422561.639125466,5245116.89405706 422520.6059753,5245087.01960419 422496.489997244,5245048.03760108 422496.479184468,5245048.02012289 422489.416161383,5245036.64527414 422465.600875504,5244965.77108275 422451.848246604,5244892.39684717 422444.003756088,5244874.70956057 422443.659198623,5244849.27229659 422435.720794628,5244826.46005738 422429.843664227,5244763.08567718 422442.249562794,5244742.58578611 422477.625066146,5244732.02315724 422660.347730712,5244719.27210901 422743.942863871,5244700.39675247 422963.69518479,5244608.45872556 423072.791232932,5244599.39562315 423110.854537993,5244596.33291229 423143.604744552,5244578.08288079 423166.198307476,5244554.89546129 423245.539479632,5244411.58384623 423315.663827504,5244337.02163418 423388.726692196,5244292.83411446 423573.57349836,5244249.58340654 423702.951124235,5244211.9160219 423738.013431865,5244201.70787795 423803.889657037,5244190.5825884 423854.7032688,5244187.39481166 423905.611101011,5244199.39438211 423944.175441444,5244229.33134657 423957.145196942,5244251.95603977 423970.647234945,5244307.70539568 423968.961654285,5244371.32976515 423956.461831138,5244386.70468763 423959.21228526,5244399.32954351 423946.649802952,5244409.57951822 423946.869106871,5244427.39183766 423975.151799351,5244452.45390945 424018.528200691,5244464.57851692 424066.779324932,5244463.95322252 424112.279913318,5244448.01560082 424152.404835283,5244414.51569212 424167.153929631,5244373.64101704 424163.056649859,5244261.89218054 424195.368266019,5244208.08003203 424255.74343179,5244166.64258895 424356.681736983,5244114.45501461 424416.837842521,5244062.89268459 424421.524595356,5244034.83044647 424449.05641287,5244031.89281265 424519.086735325,5243982.76546948 424587.461809958,5243966.63786594 424650.273090999,5243910.07338602 424723.272104283,5243858.32094554 424773.928287044,5243842.44405399 424811.677647115,5243811.50533222 424927.488323561,5243721.18903625 424937.268631943,5243688.06396576 424954.736658528,5243659.93853504 424974.109535597,5243586.00097629 424975.857432102,5243517.43907775 424985.79453947,5243502.06382617 424998.231354667,5243476.56357253 425048.85636252,5243463.24915306 425127.701049451,5243472.43337074 425229.201617576,5243463.61684715 425303.545163236,5243437.11409532 425303.549402951,5243437.11258231 425317.732624008,5243432.05107015 425378.357317052,5243405.9238695 425403.270589048,5243382.7576384 425403.294305405,5243382.73558515 425406.013000479,5243380.23549935 425463.136866116,5243328.35868973 425462.480264155,5243317.17132501 425460.792492731,5243308.85897413 425455.948497517,5243302.23423474 425447.948330789,5243298.98459044 425433.698218927,5243299.17266596 425417.541907133,5243301.48579805 425397.916946351,5243307.98652995 425372.697715243,5243299.17513742 425355.634743497,5243288.48843276 425343.821153443,5243256.42672351 425345.507970825,5243233.92687414 425359.506696935,5243189.05174343 425375.537302995,5243163.98883738 425400.474334798,5243142.23803789 425418.38050765,5243134.98738237 425447.099902502,5243148.17358989 425447.288209402,5243174.17332972 425462.758500157,5243219.79725953 425479.946995741,5243247.3587953 425506.354472486,5243279.91990916 425551.353092976,5243223.41863382 425560.165621094,5243221.98079062 425563.165913152,5243230.60558541 425565.041097145,5243236.04295671 425567.791365844,5243243.98026831 425570.51055476,5243257.41752786 425573.260993946,5243270.85478616 425578.761759986,5243294.10433792 425588.762423759,5243312.85375104 425604.075602435,5243330.66545811 425621.201379501,5243351.16456581 425642.827135771,5243369.78850955 425669.796296844,5243375.84985863 425674.858885241,5243377.34963909 425674.934197452,5243377.3720909 425702.109362684,5243385.47345691 425719.078194943,5243383.59778787 425737.890648983,5243377.09708887 425740.010214788,5243376.08200283 425740.109384381,5243376.03450929 425761.078005389,5243366.28375434 425789.608818469,5243344.59530833 425809.233420225,5243326.53218786 425816.420044734,5243296.40718753 426022.641687027,5243334.64846594 426081.079571282,5243331.45862981 426093.704510585,5243326.14566952 426234.451831359,5243202.57865267 426287.545445784,5243184.13917769 426328.358659772,5243196.2624079 426417.171624064,5243187.63389151 426447.264740691,5243159.32044218 426501.824110273,5243044.3818262 426523.822067562,5242973.00661389 426573.256469659,5242860.56817836 426566.505935163,5242845.19359849 426561.84949313,5242840.25633441 426541.161697012,5242836.19471257 426506.16099743,5242822.94625908 426475.597836297,5242809.76012506 426445.065699758,5242789.32405904 426410.783342017,5242762.76320388 426390.126228305,5242740.45175531 426380.937483647,5242702.88998672 426397.812090207,5242685.82696422 426417.436826176,5242672.20129717 426441.593045662,5242664.88788584 426469.34307169,5242658.44932016 426505.249829028,5242665.32279647 426546.53168879,5242674.07103677 426594.938630275,5242683.56898076 426637.970333149,5242686.81720254 426676.283491168,5242697.87804186 426692.813726213,5242661.00272043 426732.687135307,5242599.56418343 426767.090643263,5242502.68870327 426766.370063986,5242444.2517858 426737.743017776,5242386.12849988 426704.430449989,5242392.62979268 426685.680638845,5242403.56795129 426673.243710305,5242425.13075245 426662.68210293,5242456.5058842 426653.807730458,5242478.94353205 426640.558491852,5242506.81880599 426626.277661489,5242524.00672317 426603.058893881,5242529.50761442 426567.932890937,5242506.50926029 426552.525403249,5242470.82272563 426532.586656173,5242436.01136702 426531.554476479,5242406.44919003 426532.209783214,5242376.01195274 426541.959052007,5242350.01180343 426559.70846546,5242326.57380431 426578.426722354,5242305.88573951 426698.018928816,5242225.31913873 426758.705564592,5242181.87958072 426801.611539326,5242161.94052329 426821.54958683,5242174.31459496 426838.704463395,5242125.87685449 426893.765245675,5242056.62526697 426931.421250946,5242039.06139951 426931.434142717,5242039.0553835 426972.139735793,5242020.05992068 427007.608597992,5242014.49602885 427033.328422654,5242042.24472045 427115.299629895,5242099.67834344 427169.14506588,5242139.6757763 427217.614665312,5242154.2986667 427247.770431821,5242131.04765762 427239.581279795,5242080.36096614 427190.422425647,5242009.80112922 427177.202226058,5241966.86457046 427219.669392251,5241905.30091825 427490.136874861,5241795.35342681 427512.448034294,5241746.85296971 427507.760063851,5241733.04078954 427507.759671562,5241733.03963564 427501.853222022,5241715.66619228 427483.663894005,5241661.97993435 427478.163338843,5241645.66781074 427480.631867742,5241637.98028176 427482.693269968,5241602.41802925 427563.09782598,5241527.85294411 427643.815676353,5241478.60010886 427747.346199541,5241429.09634358 427792.783324321,5241405.59470699 427815.658418391,5241402.78129942 427818.878061245,5241430.4059122 427805.691923493,5241477.15601728 427810.349081718,5241504.90557021 427823.006131273,5241527.15484779 427853.632211953,5241553.77835203 427875.100874598,5241545.52755272 427894.693937325,5241518.65200213 427931.098640841,5241460.15105773 427984.095254346,5241338.90001456 427967.063393539,5241323.77584948 427909.719454053,5241332.27811207 427881.9693509,5241336.02921031 427856.87540505,5241336.15523362 427837.531114493,5241323.8436373 427806.623272624,5241280.97029621 427798.40278573,5241227.72112499 427827.806545662,5241140.97072671 427912.239736362,5240982.4687407 427931.769059366,5240916.2185537 427967.487252672,5240889.52983904 427995.612847748,5240901.4035792 428012.488644879,5240922.52769432 428031.333942422,5240967.02651368 428039.459680497,5240988.46348396 428060.336104983,5241028.52476154 428081.80502093,5241028.39888512 428118.523800084,5241020.08496068 428120.147969765,5240993.27264091 428118.209497271,5240962.83550012 428113.489469795,5240923.39855585 428097.081744029,5240880.5871207 428092.424386219,5240846.52512457 428097.704233305,5240800.58783112 428125.672611899,5240781.77435971 428184.549253219,5240819.20910681 428236.333450341,5240899.89374799 428269.99163211,5240952.82938605 428343.930485838,5240977.26363916 428504.0568526,5240980.44456402 428567.432091882,5240972.12954915 428655.649986489,5240922.87639123 428655.651697681,5240922.87543563 428688.555916929,5240904.50021297 428723.554659362,5240855.87422389 428712.615154558,5240795.0627241 428673.236494842,5240688.87780087 428690.485102474,5240640.44003526 428675.358599653,5240596.56605342 428657.107577197,5240568.69205421 428651.169687618,5240557.81739627 428651.160664338,5240557.80093873 428644.41924635,5240545.5052847 428623.668155315,5240516.0689024 428613.667428521,5240495.50699915 428602.760277172,5240469.63268145 428613.352949152,5240432.82008249 428632.946483765,5240421.13188599 428649.461729364,5240419.69512131 428649.477817678,5240419.69372169 428667.009157433,5240418.19301698 428693.853194224,5240420.6293949 428727.072282869,5240423.12801109 428760.134723848,5240413.06424771 428787.790365439,5240386.93835144 428783.227121532,5240364.50124191 428769.601255609,5240340.43951859 428717.066414307,5240239.63008705 428715.566183702,5240232.69271154 428715.562033437,5240232.67315401 428711.534302746,5240213.69304935 428720.252020059,5240178.81800834 428733.65803114,5240167.94255714 428756.001637324,5240157.87923191 428873.314854283,5240151.68697586 428889.533813333,5240154.31128684 428904.003803169,5240189.99787059 428890.004641763,5240219.99817334 428889.997553997,5240220.01339022 428826.133473843,5240357.12455032 428814.633920726,5240374.12486755 428813.85340258,5240397.49968768 428821.166689827,5240420.62417844 428821.323734269,5240445.7489443 428808.824202717,5240463.68679377 428797.262182377,5240481.74960362 428790.294168904,5240506.81216173 428785.919902026,5240531.12462036 428788.764605456,5240560.62423626 428799.297372305,5240606.06089284 428829.922839666,5240613.24707387 428910.766150719,5240579.24407202 428965.98346615,5240520.11734574 428995.512532296,5240443.67932694 429018.412369999,5240235.11777138 429017.568253364,5240210.75486928 429017.567843021,5240210.74302597 429015.033679321,5240119.18145608 429002.40693177,5240066.99494499 428980.186843911,5240030.12118959 428963.061005979,5240007.80959388 428932.498020183,5239999.93591942 428898.466516229,5240000.24981342 428866.279027279,5240008.50105994 428839.403909706,5240011.37713698 428812.528794088,5240014.31571345 428782.903146086,5240001.06704946 428772.027527097,5239984.13014935 428769.183050688,5239961.81796831 428787.93256643,5239941.87987918 428810.213418579,5239923.81662794 428852.213254071,5239908.31504367 428880.806625119,5239889.31404135 428918.306174644,5239865.87521318 428946.02464913,5239850.37421478 428963.89966876,5239846.62351449 428988.087549267,5239852.74746581 429009.619129659,5239857.93403474 429038.338239975,5239862.30781587 429067.869285496,5239848.61922639 429082.02488005,5239824.43136283 429092.711921048,5239807.30607803 429113.149653999,5239809.68021716 429135.868729714,5239814.42924124 429155.213141218,5239830.61580114 429176.40206056,5239870.30207417 429189.090447692,5239895.23882903 429205.278721611,5239915.73798017 429226.029556688,5239937.04943682 429239.561334774,5239950.42376122 429270.093125982,5239960.04742155 429289.812022869,5239959.85911383 429307.655739024,5239954.42093016 429318.185960559,5239919.35831226 429314.497440658,5239888.04624441 429303.496283107,5239854.17199984 429285.463961808,5239824.73550436 429268.244174647,5239796.17396783 429242.961629583,5239761.42531821 429218.554036165,5239724.92664865 429205.80275119,5239687.42750933 429203.801659862,5239653.42789686 429212.644708541,5239629.11525166 429206.300160118,5239605.42822512 429226.456074569,5239589.9275356 429297.330867545,5239566.17483461 429355.800126289,5239568.04741385 429449.738312711,5239566.91856172 429472.050756455,5239559.73020856 429482.644478939,5239556.2923037 429481.519022639,5239542.16747608 429471.924252162,5239512.29313736 429456.391765878,5239477.04409093 429452.578216649,5239444.85703525 429472.26552096,5239433.91882306 429509.015824461,5239434.60480516 429569.953948181,5239439.53975444 429635.392277044,5239449.84947094 429658.767480121,5239450.59850281 429675.018451436,5239477.28509707 429662.644383491,5239509.66031799 429649.36371348,5239531.1606728 429620.0211097,5239574.41149419 429603.958999517,5239590.59951032 429584.990912165,5239616.10006281 429646.367570047,5239653.47220739 429723.150912821,5239700.78113141 429768.932656751,5239705.216711 429778.495361437,5239709.34128149 429789.339649382,5239723.65320889 429792.15282376,5239744.21541078 429789.622492541,5239773.77775224 429782.623291445,5239800.65280105 429772.061991163,5239841.02787613 429769.625608838,5239876.840158 429775.970203341,5239901.90217487 429794.971026962,5239923.2137056 429812.908888172,5239930.21290716 429842.471412956,5239923.77425089 429913.096007612,5239893.77161789 429931.814444053,5239879.33347736 429933.407380568,5239853.33364222 429929.562292602,5239812.14666484 429918.340670766,5239724.46040224 429912.65153681,5239674.39857929 429902.931945658,5239650.27419233 429935.180327918,5239591.52338711 429973.148951156,5239578.33444311 430011.399714245,5239593.08274051 430068.747601033,5239709.32935724 430104.749154568,5239749.45252428 430125.281040108,5239764.45154868 430178.781839177,5239776.57424458 430204.094282369,5239768.63577498 430251.805343489,5239709.89195168 430251.81153196,5239709.88433218 430279.123172799,5239676.25850589 430295.933210702,5239594.8210309 430272.30593641,5239529.07257987 430247.085395536,5239478.88655797 430247.065130004,5239478.84626715 430220.2709934,5239425.57562951 430224.142785711,5239323.82636509 430242.452446773,5239254.0166138 430242.453204368,5239254.01372529 430243.515585201,5239250.01371672 430307.918014048,5239114.51225511 430345.917967379,5239103.94828284 430509.421577742,5239178.12840114 430513.204927995,5239243.12767728 430514.268204909,5239267.25242264 430514.394006515,5239292.37719784 430518.11363941,5239319.18931041 430527.302092121,5239346.87619038 430541.708992321,5239363.81294971 430556.115635628,5239372.68727956 430581.209769303,5239378.68619498 430607.990648845,5239360.62275108 430628.458752676,5239335.43462885 430622.769726485,5239288.93526851 430624.330668107,5239239.68563383 430636.704479254,5239199.43547551 430720.392427261,5239193.432083 430735.205178018,5239197.74393575 430737.955512096,5239207.55623717 430732.612233708,5239223.61881733 430731.019275082,5239248.80616369 430733.051910451,5239291.74320637 430736.803137519,5239329.30522511 430745.897585315,5239348.99217966 430767.55470928,5239371.1785958 430790.96164739,5239387.11499449 430825.962364775,5239401.17593282 430850.11868049,5239397.42497198 430867.087071903,5239382.11190711 430872.336367945,5239358.79939359 430863.116264319,5239318.61262171 430848.520746561,5239266.73867259 430829.331130686,5239205.05249797 430804.860599863,5239155.11643903 430805.640128327,5239100.99187713 430827.261959432,5238996.55439349 430856.19553098,5238866.61682865 430881.163245,5238828.24113217 430888.412483633,5238802.67855485 430994.004072172,5238709.98750294 431080.160372442,5238691.17161198 431098.035827311,5238701.17078844 431134.099803186,5238738.79397669 431158.165643339,5238837.54213327 431184.762837348,5238938.91516358 431198.76634806,5239045.35116963 431206.924039531,5239088.47546214 431250.675982808,5239138.78572757 431322.302881923,5239181.03241588 431508.086377232,5239206.77454937 431586.649121875,5239195.64641174 431674.77256393,5239126.01837977 431707.302910094,5239090.07984728 431773.397136633,5239089.20213385 431853.899430004,5239141.51087506 431858.115192378,5239144.50846021 431858.118308525,5239144.51067592 431925.122044907,5239244.9445654 431971.123111785,5239267.19248425 432081.75283505,5239387.8119124 432115.536372922,5239450.93498927 432187.66442913,5239528.7438672 432231.541792749,5239591.74153242 432285.105257091,5239608.86418795 432358.950122511,5239625.79851256 432384.544386038,5239635.60987891 432476.327458173,5239670.16831957 432519.985170762,5239705.10373376 432538.581183597,5239770.91491781 432537.272025559,5239875.03909702 432499.655637394,5239998.33592644 432499.650701986,5239998.35210343 432485.933293273,5240043.35228728 432456.843008563,5240158.10251364 432462.751426357,5240224.03921639 432545.035988315,5240306.91014946 432665.978644202,5240437.52910212 432735.951760437,5240555.96274664 432772.830394313,5240659.7103696 432783.582195138,5240712.95948416 432773.80185245,5240743.52212786 432747.430744904,5240870.83463821 432740.150425606,5240901.5221782 432700.809895495,5241011.21036396 432702.282582003,5241133.0842805 432683.129292311,5241229.77174948 432679.978172552,5241389.89553201 432684.355048866,5241447.08237286 432698.621560686,5241638.26320182 432701.112413624,5241671.64230216 432733.116586203,5241793.20247775 432766.649482272,5241835.88825501 432817.431125492,5241835.32369436 432893.211893738,5241801.32089719 432930.86720768,5241762.81968784 432937.74013186,5241696.69496167 432934.895621542,5241673.82026886 432975.618981181,5241634.19734614 433035.299531864,5241576.12949839 433065.831015856,5241575.75325846 433090.548317766,5241524.69017794 433082.516327646,5241503.75317963 433088.703155593,5241481.37811423 433077.638806391,5241426.81651988 433064.85609881,5241384.81739093 433052.948370177,5241341.94323378 433035.759609423,5241307.13172477 433023.008469064,5241274.94501313 433002.100439071,5241224.94628289 432984.848976842,5241183.8848292 432973.004039787,5241150.01059518 432948.533713887,5241107.199451 432929.689295617,5241091.13785405 432912.595155358,5241083.26361733 432892.157383533,5241079.88947947 432886.280046016,5241008.82781364 432878.592327649,5241003.95316819 432908.873317092,5240988.38956232 432990.186678174,5240995.01118797 433125.470673771,5241046.69273617 433202.41072646,5241106.75159756 433240.598761453,5241113.87498056 433276.00495307,5241103.3111239 433306.191943067,5241080.06008524 433315.721542831,5241026.62263938 433279.719955761,5240986.37444233 433233.624954605,5240959.00155092 433215.624161483,5240938.87745283 433207.497706383,5240895.8156422 433217.403375183,5240875.37790742 433237.433954787,5240849.68980265 433270.152296439,5240829.00113802 433473.153172742,5240806.24303517 433486.926229535,5240806.70438945 433640.87343626,5240811.86113884 433657.21633902,5240781.67321963 433662.496730744,5240753.86073263 433659.526597813,5240711.86119926 433670.150897073,5240687.61096449 433717.651350201,5240689.98400406 433749.152401172,5240714.73251384 433767.184370929,5240732.54413103 433770.87227664,5240744.16888502 433780.873280974,5240772.73074225 433783.030159372,5240791.60549936 433787.468880752,5240828.23001772 433788.595162866,5240867.54214931 433788.689670627,5240890.91695373 433777.253065306,5240921.3546709 433773.879200159,5240957.22951423 433771.317637024,5240986.79187616 433771.694554536,5241045.91637549 433768.320658869,5241080.85372631 433776.540284025,5241105.8531858 433789.260495716,5241147.85232229 433806.417399061,5241163.78899188 433828.855250641,5241169.10053339 433860.011363253,5241157.16186084 433886.292540027,5241148.41086085 433896.979315517,5241123.41062978 433903.134598141,5241092.03563562 433935.976173921,5241016.84741113 433945.630440891,5240953.28503696 433961.503825146,5240899.53482843 433965.7832798,5240843.09761488 433974.594196579,5240792.0976717 433976.03087931,5240766.53532179 433977.09276369,5240747.28543562 433970.685162101,5240707.16102505 433971.496766906,5240679.348719 433983.996025023,5240653.41092003 434015.214438556,5240635.40979117 434043.902248747,5240637.97109793 434075.277785002,5240646.84474346 434112.09118276,5240665.53058703 434148.905043138,5240698.46631491 434180.906698373,5240741.65215643 434195.719971089,5240761.8388873 434211.971868986,5240816.3377807 434220.19193392,5240854.83713223 434222.067557409,5240873.5869033 434241.006222484,5240904.83587636 434252.881785709,5240919.27277439 434298.412807851,5240901.0835637 434323.380344057,5240857.58289734 434388.252207605,5240745.14365928 434428.563939087,5240711.64228378 434598.533568062,5240697.19795746 434621.345994915,5240689.38458853 434636.37661395,5240666.32166018 434641.000410428,5240628.19677809 434630.687253396,5240610.50984184 434559.24830167,5240583.26298071 434541.028096777,5240542.95155038 434553.558695938,5240519.88872408 434596.589940439,5240509.26205056 434795.029932381,5240537.62871093 434833.123973468,5240537.31465642 434839.40907487,5240654.06346419 434822.474092101,5240735.50100316 434765.007717438,5240822.50265152 434684.164755862,5240866.50559792 434494.102128314,5240909.13801159 434456.290411626,5240942.5142849 434404.325310105,5241067.57789284 434372.140203973,5241149.20354399 434372.51627875,5241182.20326118 434387.891974371,5241199.82749155 434517.549547792,5241208.57213582 434540.330645197,5241198.25879058 434583.205149595,5241172.44475129 434661.54834205,5241136.0043512 434841.078404615,5241055.37267875 434894.046485081,5241021.80828753 434932.171858896,5241023.93171551 434955.423032129,5241054.24302467 434951.238314312,5241140.68000359 434936.333023844,5241173.805346 434822.677966645,5241238.43445985 434759.459640864,5241267.06180588 434752.085328024,5241289.99942189 434821.055931976,5241329.93379125 434958.401236139,5241343.74058618 434981.182331396,5241333.36474135 435027.739890408,5241170.2391488 435049.674745139,5241083.67644605 435074.406137693,5241052.36388019 435102.297994234,5241017.04983175 435147.797597646,5240993.73566177 435208.672816838,5240985.54574391 435297.673829562,5240994.79204024 435348.580798414,5241004.3523881 435427.237401503,5240995.911747 435459.73607311,5240947.28580622 435461.577682184,5240881.2862531 435417.605940684,5240800.4136875 435360.978188456,5240729.91655763 435335.070249373,5240684.48047569 435308.879979266,5240605.98216783 435318.252560504,5240529.60739034 435327.970144866,5240491.54479481 435357.874794744,5240435.29401785 435416.061988824,5240411.85432427 435672.595260259,5240411.71883674 435733.783971351,5240433.96616044 435754.472706267,5240466.71505769 435761.322074096,5240636.77594295 435792.229890398,5240677.14936381 435830.700095411,5240712.27251749 435848.575562725,5240722.20920977 435868.482063045,5240725.02087502 435932.514118905,5240734.08068995 435986.07760781,5240751.265869 436077.421720139,5240740.1372271 436110.045804047,5240704.26117487 436119.763381843,5240666.13607507 436098.322137513,5240557.07530029 436002.126920508,5240344.76838717 435919.183471615,5240183.08554247 435900.430334234,5240091.77452353 435909.802908791,5240015.462236 435932.364580498,5239984.77405167 435998.239740005,5239973.89643851 436130.522482608,5239987.82841245 436216.866962218,5239989.44986387 436282.491116767,5239948.00999744 436310.13607359,5239900.15144092 436310.146012239,5239900.13423528 436314.927028895,5239891.88410326 436308.422644324,5239759.82289152 436261.512212425,5239643.51321499 436337.10443938,5239579.19811188 436537.229423017,5239531.37777043 436583.230599633,5239556.31319154 436624.984416431,5239662.56066302 436663.862125178,5239735.74600741 436681.68475947,5239744.44308314 436776.177303905,5239790.55348417 436842.271794076,5239797.36322366 436867.584065984,5239784.42478527 437085.521855142,5239741.54118056 437125.676814098,5239692.85240449 437094.298736023,5239606.85434395 437073.264902961,5239533.41826443 437080.231693169,5239472.29344289 437110.481250245,5239451.72985777 437186.731983737,5239456.03919625 437365.047397084,5239502.40652987 437425.860012499,5239491.5916167 437468.57765199,5239447.9026931 437475.544444263,5239386.96536572 437482.542480397,5239325.84053824 437522.697435373,5239277.21425514 437560.666045375,5239264.08779469 437580.197312131,5239260.02452319 437610.416718976,5239272.83568628 437621.292480367,5239293.33508607 437622.324774962,5239324.70980852 437611.700991516,5239364.02244985 437455.494870464,5239783.27570405 437443.215267497,5239836.08830908 437445.123244434,5239887.96283987 437450.342641733,5239906.3374876 437450.347889116,5239906.35599495 437456.030848428,5239926.39960345 437474.062978259,5239948.7736965 437517.063781731,5239962.89682964 437555.595300937,5239961.89525972 437583.282601181,5239949.26922112 437606.500821088,5239927.70593253 437619.248859425,5239909.45763575 437619.250318217,5239909.45554755 437629.656158395,5239894.58023312 437675.998165075,5239830.82881344 437696.497377478,5239802.14068875 437705.340308494,5239775.26552782 437708.870553345,5239744.01561725 437710.494056127,5239698.32839287 437698.585230546,5239623.20444359 437674.799156616,5239482.83147037 437670.984439789,5239416.6446226 437662.669450621,5239343.27051337 437654.4491004,5239296.77119908 437657.073587843,5239280.64621209 437658.728630001,5239243.70892073 437677.291149487,5239239.95818656 437712.13297461,5239173.58225214 437731.097668167,5239046.45742307 437755.845748605,5238982.64438241 437793.156087948,5238908.64340053 437843.718200552,5238885.20399595 437965.750597553,5238891.5739302 438004.252138613,5238929.19706778 438040.724101232,5239017.75741157 438090.134415949,5239129.0045567 438136.668534147,5239204.75208445 438170.013539817,5239234.87549231 438163.046756841,5239295.87532698 438115.204168358,5239342.12694817 438100.831669138,5239421.00195332 438131.488734614,5239438.43806637 438184.801629892,5239437.87338346 438214.676698245,5239432.93469441 438283.739359472,5239421.61944476 438296.994445698,5239415.5557913 438329.239022643,5239400.80523163 438437.298788852,5239293.11409011 438452.047293976,5239244.61384118 438433.482131179,5239168.67766156 438514.481798405,5239139.79954699 438549.480454447,5239091.17346592 438673.252324028,5238780.04565372 438695.782471667,5238741.67000697 438751.657965869,5238743.66769376 438784.783713906,5238758.54122276 438833.692179504,5238813.91380826 438839.538503137,5238889.9755147 438810.699777323,5239047.78805148 438786.735412326,5239185.28803407 438767.175213891,5239259.10079892 438724.332162124,5239290.10233117 438564.958089619,5239355.233395 438519.928529332,5239416.67229178 438429.524979497,5239519.23774584 438377.589883729,5239603.92675149 438374.590019929,5239608.73933899 438357.561167422,5239685.05197432 438373.187377406,5239717.8635921 438429.344976154,5239745.29858925 438556.440012263,5239754.10581809 438815.34760613,5239733.59536249 438891.316162765,5239709.90492309 438926.220649085,5239648.65393875 438914.559412155,5239501.40548772 438908.525245354,5239415.09386287 438940.741618406,5239336.0931154 438988.835302735,5239322.90373775 439062.711437133,5239339.77558419 439129.589808234,5239425.45972052 439210.252749671,5239607.58009717 439292.22414004,5239667.638805 439376.382288985,5239704.88508916 439465.414627068,5239716.63135797 439513.664902466,5239713.56690371 439536.414736543,5239703.25354585 439593.755440673,5239598.50194687 439638.878740756,5239537.00053739 439674.25358268,5239523.99918029 439705.004656862,5239548.99774147 439830.69699692,5239664.55426803 439885.716561564,5239709.61218704 439956.232664447,5239767.3608965 440088.641011908,5239799.04275131 440139.359885916,5239790.85323295 440189.984756065,5239775.10127166 440487.856115501,5239596.71532639 440538.700415786,5239601.27571161 440577.107973763,5239631.33642834 440610.985784719,5239707.27201084 440651.956115299,5239744.83257141 440690.175582139,5239757.26842014 440718.23854545,5239764.51722091 440761.301026818,5239753.89053208 440824.519400125,5239727.88812473 440924.013321674,5239523.63546545 440986.260127313,5239414.07117183 441003.852972908,5239383.07066466 441036.633871203,5239365.00694531 441173.979066398,5239376.18873734 441291.04337579,5239402.8712553 441354.794450956,5239420.05602454 441392.825726046,5239411.99202088 441440.731307861,5239381.05276855 441491.136818155,5239347.42593154 441493.574229786,5239344.23835334 441493.587389503,5239344.22123925 441508.761182833,5239324.48786526 441518.510056681,5239288.8002086 441571.289899878,5239234.86091105 441581.226790564,5239214.48564198 441585.913042356,5239176.36070888 441579.036780257,5239140.48623483 441575.129828213,5239120.54903067 441546.345628468,5239039.61326235 441530.123504235,5238943.17708428 441511.37028775,5238851.99097485 441507.710331387,5238742.80436791 441501.707377636,5238656.49270168 441493.549271239,5238603.24339929 441476.33205697,5238583.62189494 441476.329728245,5238583.61924102 441458.985180196,5238563.87008886 441429.29631842,5238530.18403958 441396.076642976,5238510.24804221 441332.701606564,5238523.56305899 441281.202243367,5238554.18996856 441206.484416552,5238598.63023806 441057.298043148,5238666.13591042 440786.235695324,5238732.58409754 440656.829091591,5238751.65178565 440587.983901285,5238724.46730539 440544.325799127,5238679.21941592 440515.761043529,5238618.47101433 440479.508738079,5238557.97292788 440452.754029706,5238423.59996689 440496.125317121,5238302.80786469 440509.530410747,5238265.47373108 440546.684033701,5238178.72280403 440535.775152283,5238102.72378253 440465.895558396,5237981.47750861 440440.175602292,5237951.29128005 440424.893899722,5237941.22948069 440345.171513987,5237850.67090272 440336.919410036,5237789.73416911 440356.949868082,5237761.60853853 440384.69947114,5237743.54501877 440476.137710158,5237745.10373216 440613.796650775,5237794.47270553 440687.672693014,5237808.96955544 440763.735481931,5237800.52897406 440788.89097666,5237772.40312995 440810.292601431,5237629.9032299 440819.633772036,5237551.02838808 440871.316520024,5237398.08980561 440940.623532631,5237219.46316716 440970.183512161,5237137.96250331 441047.899395154,5237035.58498744 441135.08212044,5236874.51997715 441192.234670401,5236752.08094346 441214.451439632,5236688.39295611 441221.574781394,5236665.73814057 441285.788072267,5236461.51653938 441289.722091617,5236357.32958354 441261.282853973,5236311.89357319 441220.343959355,5236279.33299498 441062.560589792,5236250.46474664 440986.215969461,5236241.09298271 440924.933185458,5236208.72075081 440741.335777967,5236139.54135676 440715.647163772,5236111.91761485 440723.209458194,5236104.16735379 440672.333934418,5236099.54450094 440641.018489675,5236018.6088612 440630.172535218,5235955.29724899 440644.732999327,5235891.54708265 440669.669049976,5235843.04637898 440644.043191708,5235822.98508389 440658.729086492,5235772.04732342 440662.725529522,5235665.29789207 440623.283412227,5235536.2379243 440584.280417695,5235455.3651075 440575.495354601,5235343.67874378 440625.116849115,5235228.80246467 440702.425348697,5235093.42516809 440714.658382803,5235063.58900382 440714.674431357,5235063.54986167 440722.298861412,5235044.98717064 440724.516683928,5235016.92477053 440706.359116846,5234981.55077171 440642.85860784,5234979.74093689 440546.702907181,5235016.30720196 440484.297972655,5235068.62194755 440484.263266197,5235068.65108297 440405.67463157,5235134.62477446 440365.300209635,5235160.37628181 440324.957127734,5235188.81526885 440284.519951066,5235207.00433058 440208.237848106,5235197.69507939 440159.517234211,5235152.38492862 440161.735149471,5235127.01001267 440187.014841593,5235075.19681752 440187.022127705,5235075.18185581 440213.981925731,5235019.82107614 440306.697122824,5234894.38057269 440379.632892236,5234827.50298701 440470.412787053,5234768.12460166 440533.631107711,5234742.12213731 440571.442747795,5234708.6207866 440680.035343596,5234651.61663597 440747.75181527,5234569.73936387 440772.531006692,5234503.36378106 440718.215156819,5234414.99165994 440669.494548843,5234369.8065099 440572.962490945,5234365.74808085 440395.368248681,5234387.88036666 440258.148422701,5234384.26113899 440207.21024784,5234374.70083887 440158.583734338,5234339.64061923 440122.29985871,5234268.8301315 440119.173049981,5234215.51813306 440090.670904486,5234157.39473195 440074.138911785,5234138.6455555 440057.231910311,5234119.70889619 440001.262363279,5234107.46132857 439930.450422999,5234138.77657961 439849.71068062,5234198.21055297 439849.701854857,5234198.21704977 439695.985829721,5234311.47269851 439632.391316819,5234301.85043114 439591.201679903,5234246.4775473 439577.667707645,5234167.85366846 439576.006009139,5234005.22988334 439578.035745568,5233959.54261979 439546.751743926,5233883.66946714 439535.469896253,5233868.1075504 439520.969136584,5233848.35829837 439369.61973713,5233710.30312965 439200.363211198,5233549.43638284 439160.610433611,5233474.3135878 439153.066707842,5233460.85403865 439083.792839363,5233337.25529365 439056.164919099,5233255.31953942 439041.192180802,5233161.75846476 439086.493357043,5232881.88395102 439135.611899983,5232718.75830086 439126.637497383,5232584.25982799 439087.351361412,5232472.88740837 438992.001659106,5232344.39243787 438968.875465424,5232319.20610378 438833.747659715,5232272.33706153 438805.809995006,5232272.65070901 438735.186365234,5232316.59075578 438697.218125769,5232334.77967178 438581.50288598,5232437.59611368 438548.597067155,5232453.1598485 438515.283108483,5232423.03646631 438507.281591136,5232387.53708028 438580.865386734,5232135.2860753 438638.801335452,5232088.97157379 438762.643389194,5232029.27948903 438818.142025621,5231988.0275591 438848.360110935,5231967.46399434 438875.325116093,5231873.15117868 438873.841266481,5231851.6369036 438873.355169078,5231844.58899715 438869.352748842,5231786.83964154 438848.694907786,5231751.52827589 438696.03694936,5231732.78463683 438675.661519899,5231725.4105251 438647.284570385,5231682.47452698 438638.686987563,5231591.1006173 438672.64951322,5231435.78800661 438720.084119182,5231359.09922028 438780.864757263,5231335.65946491 438821.396122206,5231332.65785774 438913.022363814,5231349.52902715 438978.929458025,5231360.46378004 438984.304531395,5231361.46355502 439114.338608571,5231410.89539182 439185.652136542,5231425.39238962 439248.117312359,5231330.70319233 439257.990989991,5231297.57808319 439275.145003773,5231241.51538211 439297.016099857,5231144.82784887 439305.697711813,5231002.4537472 439260.376607367,5230802.33230114 439216.184637924,5230701.0849359 439225.713398765,5230640.08508735 439245.430025552,5230586.52227234 439441.359505498,5230368.57895915 439466.16989883,5230314.95346074 439468.261750086,5230269.2662857 439438.739566986,5230181.57815323 439434.132329078,5230167.89352542 439425.225553461,5230156.4564756 439408.443325912,5230135.20732065 439382.095837913,5230049.08411184 439406.905915137,5229987.95868446 439500.059319369,5229908.20576649 439625.679705032,5229782.38951951 439670.833827792,5229726.07578102 439678.427328598,5229719.20054957 439731.769341654,5229671.26142325 439731.775551865,5229671.25583629 439776.580378828,5229630.94756117 439951.674516426,5229618.94090755 440225.015363138,5229517.11882869 440336.264049925,5229472.73997381 440452.637757724,5229428.36093118 440523.417927887,5229394.48354551 440543.510915306,5229374.10797608 440619.008348185,5229304.66827219 440653.786417605,5229225.60523348 440688.250898201,5229120.97996977 440778.277048724,5228990.60286 440792.899522296,5228929.47792629 440774.490707801,5228871.16671833 440704.798275231,5228762.73295662 440707.0783475,5228734.73315326 440724.577452884,5228711.73272466 440938.07878393,5228719.59957889 440982.609893299,5228711.41048132 441011.578557547,5228706.22194098 441128.485624857,5228712.59245844 441166.705078667,5228724.90338483 441182.331551983,5228757.71494788 441137.30314561,5228829.34089773 441125.337268149,5228898.02812966 441121.404298563,5229004.71465878 441157.626134058,5229072.96256135 441216.34623029,5229097.83505936 441307.815379263,5229096.76908142 441335.408165425,5229071.08080381 441362.309971006,5228964.08092637 441369.464518175,5228923.45609055 441377.339160205,5228914.20589085 441375.884759661,5228519.21018982 441365.863750525,5227298.78616829 441362.816500156,5226925.22778895 441353.32899797,5226487.98282069 441334.385239866,5225613.43036079 441330.001586979,5225411.68267304 441327.747107756,5225307.24636884 441305.316984763,5224021.76087509 441299.678154161,5223699.26450647 441286.810453585,5222411.9036632 441283.609245141,5222092.28217366 441270.835642402,5220813.67119782 441267.540172935,5220482.29982725 441265.859079109,5219175.40754827 441265.471236449,5218876.31699548 441267.821811269,5217580.29948915 441268.401594674,5217255.3341868 441258.191667242,5216733.34001911 441237.333320755,5215666.35190995 441227.842303915,5215148.2014038 441208.265160845,5214080.36946304 441195.274251281,5213564.59398568 441168.196807764,5212489.38722958 441156.02005255,5212012.08004007 441127.127687256,5210880.40508843 441117.388581936,5210406.78527438 441094.058619425,5209273.42265027 441092.101754418,5208823.73991009 441086.988839287,5207653.43979129 441092.937830809,5207196.00699117 441107.919134768,5206040.4563889 441099.180074391,5205568.61773998 441076.86011304,5204365.48110994 441068.033916685,5203923.5198378 441044.810329775,5202759.50826854 441038.390380076,5202318.23443591 441022.763161913,5201240.53378684 441015.248841091,5200779.38528998 440996.713401008,5199638.56070505 440997.788580086,5199042.66427922 440999.66263242,5198009.587543 440997.677376318,5197479.59631226 440993.611925358,5196381.61446136 440987.346268008,5195878.46659537 440973.561784197,5194770.64128997 440965.045984715,5194262.9622736 440946.511668596,5193160.66818059 440937.027880396,5192677.64501441 440915.462465655,5191580.69461056 440913.290734644,5191084.45276957 440908.411922532,5189960.72122732 440898.739585907,5189444.7298283 440878.361997923,5188359.74790141 440868.844368726,5187794.75728581 440851.311907451,5186754.77454703 440840.168994679,5186181.03408972 440820.262004985,5185156.80111335 440808.556140411,5184569.02963089 440788.211689919,5183546.82785545 440447.274474624,5183551.58421118 439133.213072692,5183569.8587156 437519.214606452,5183597.88873491 435909.216377732,5183632.91857415 434321.217792016,5183656.94819719 432729.219448619,5183687.97779001 431126.220916499,5183713.00771019 429532.222317095,5183736.03751201 427926.224039936,5183768.06739585 426250.225657675,5183796.09869613 424640.227328401,5183826.1287231 423021.215323013,5183838.14759326 421418.182848745,5183803.15020699 419845.153118906,5183829.1516743 418239.122759583,5183856.15320425 416630.092083367,5183876.15490039 415034.06331545,5183946.15575987 413468.035170976,5184019.156598 411927.0077774,5184102.15730687 410320.977603268,5184140.15890349 408731.947575327,5184173.16060055 407127.917199638,5184205.16237558 405509.88661979,5184240.16416644 403893.850467498,5184279.17067505 402376.809351054,5184305.18266293 400767.765827735,5184336.19538155 399155.722151603,5184365.20819777 397568.67961072,5184411.22069788 397484.635123672,5182839.23587902 397438.590081989,5181207.25121208 397410.545932918,5179591.26622548 397351.500174909,5177964.28589945 397292.452470757,5176353.32576343 397156.403121981,5174745.3656852 397136.356979965,5173154.40478628 397080.309523306,5171545.44435402 397070.262855338,5169930.48393691 397074.216493664,5168318.52340502 397059.169441951,5166697.56308368 397026.153268514,5165076.32148286 397524.818123527,5165067.79049237 398121.172223473,5165059.66575611 398079.094836043,5163519.64134919 398074.045935741,5161865.68223921 398059.997632782,5160238.72242226 398075.949416946,5158601.76287673 398049.901485214,5156996.80243326 398044.852873508,5155360.84277007 398061.802940095,5153673.8844116 397990.753525199,5152039.92440306 397986.706260507,5150439.96320876 397981.694931268,5148843.95455868 397971.683228179,5147199.94555985 397972.671962545,5145598.93676736 397962.660579673,5143995.92785993 397947.649143106,5142391.91887313 397932.637595763,5140770.90973277 397907.625956819,5139153.90054444 397871.614199177,5137540.89132351 397847.602616648,5135930.88208476 397841.591240943,5134313.87274973 397844.579951222,5132687.86328606 397831.568827347,5131116.8540907 397799.55716051,5129508.84465574 397772.545330568,5127866.83496574 397769.602433453,5127095.8616232 397766.539781408,5127081.11154329 397761.664540702,5127057.83016732 397741.664049093,5127033.83007812 397721.601028402,5127005.82996553 397703.850524161,5126974.8298291 397690.850103905,5126944.82968593 397670.912112201,5126920.82959777 397657.786647643,5126884.82941976 397649.473768279,5126849.82923463 397645.004726745,5126818.4540605 397643.3483687,5126806.828996 397635.035482062,5126770.82880521 397628.847581176,5126727.82856701 397627.534752913,5126683.82830922 397618.971812944,5126640.82807793 397612.783911683,5126597.82784006 397604.4710243,5126561.82764997 397591.595617786,5126533.82752065 397578.407636095,5126495.82733311 397565.46972113,5126466.82719851 397545.344180905,5126436.82707907 397527.781224448,5126412.82698805 397507.593182574,5126382.82686947 397494.655252618,5126351.82672409 397474.529718163,5126322.82661191 397471.34202389,5126302.60775191 397468.529352856,5126284.82640523 397460.091433225,5126244.8261941 397454.091060634,5126205.82598176 397445.590639645,5126165.82577112 397444.027755832,5126114.82547489 397438.089904983,5126078.82528037 397425.151973375,5126047.82513668 397397.963862016,5126024.82508369 397373.463344054,5126008.82506407 397344.087731071,5125990.82504784 397305.337011941,5125979.82510165 397269.086369297,5125973.82517735 397233.335833894,5125981.82533342 397202.647953329,5125999.82553214 397179.272708267,5126019.82571988 397160.553757661,5126035.20086627 397148.834882151,5126044.82595783 397132.772294143,5126069.82615172 397121.772332701,5126100.82636484 397103.334705913,5126125.82656536 397092.459782577,5126161.82680651 397081.647381872,5126200.82706453 397075.835099479,5126244.82733626 397072.147795239,5126280.82755525 397067.835406618,5126306.42146587 397066.08545198,5126316.82778114 397062.648201959,5126359.82803953 397056.585866089,5126396.82827085 397045.710944138,5126432.82851025 397027.460872742,5126464.82874777 397016.460920688,5126496.82896388 396993.21071066,5126520.82916915 396969.772954926,5126538.82934018 396939.022558013,5126553.8295148 396898.396942019,5126560.82967184 396855.458795444,5126568.82984108 396819.083119819,5126557.82988318 396792.082547279,5126539.82985873 396774.519586055,5126515.82977324 396754.581592814,5126492.82970056 396734.393537423,5126461.82958359 396716.643028971,5126431.82946552 396696.454972903,5126400.82934927 396683.579551284,5126371.82922318 396670.579120159,5126341.82909202 396659.078702435,5126310.297698 396644.515705503,5126274.82879108 396631.390228143,5126238.82862717 396618.389788858,5126207.82849133 396605.264318258,5126172.82833358 396596.701364704,5126129.82811725 396590.826006225,5126093.82793236 396582.263052331,5126050.82771637 396576.075137571,5126007.82749328 396574.949857411,5125971.82729413 396573.637016015,5125927.82705053 396577.261814638,5125891.82683664 396595.511885163,5125859.8265997 396606.574358413,5125830.8264017 396629.824563343,5125805.82618797 396647.319162537,5125787.41633249 396496.946542206,5125694.16972709 396265.286206196,5125662.98278777 396160.816273646,5125738.57728593 396134.753495823,5125759.67123408 396052.504443825,5125823.62741535 396003.377069077,5125861.82845485 395945.971110523,5126029.07954184 395968.784521861,5126100.82986161 396043.817816002,5126209.1427239 396069.754253405,5126270.44142693 396082.850393495,5126301.39311046 396095.748378117,5126315.60244372 396095.756961454,5126315.61189973 396148.758271506,5126374.73706626 396293.917828993,5126499.7373284 396410.233127903,5126621.23766537 396495.391869976,5126771.61326048 396477.236287709,5126903.7390479 396447.01740699,5126953.27065725 396386.798790024,5127105.33416577 396321.236427432,5127269.05399634 396229.298063942,5127353.99220683 396131.015871768,5127441.55544318 396115.829386175,5127462.17909169 396115.828279149,5127462.18059506 396066.015476462,5127529.80609163 395983.734586901,5127756.49502677 395923.733826088,5127783.74532406 395777.326113984,5127902.27757212 395777.308245804,5127902.29204828 395726.294356848,5127943.62166756 395549.292459624,5128067.5602533 395353.352636097,5128173.62377797 395211.19494155,5128281.09341984 395079.411735468,5128299.68757608 394960.878470623,5128283.28152324 394781.906211452,5128198.87527613 394617.215350449,5128105.37520948 394538.216159199,5128051.72570248 394430.805121636,5127978.78129481 394333.866057581,5127977.43777842 394248.209101525,5128061.40714611 394197.834475444,5128209.75173291 394146.054233813,5128439.94045916 394112.617113715,5128554.12858191 394090.929403945,5128570.94121182 394060.054237649,5128611.37897475 393913.240703544,5128772.19256588 393830.17833932,5128951.81859017 393716.803734575,5129221.19508348 393649.741102212,5129334.41449471 393593.271673627,5129359.63347651 393541.208155385,5129334.6334693 393522.332596165,5129302.28961079 393502.519354101,5129249.38316098 393485.268439118,5129170.44533793 393460.892125407,5129056.50737175 393434.734730461,5128966.81952098 393406.827666262,5128921.06937453 393281.887002488,5128775.88149651 393162.478318341,5128709.72521971 393074.570595567,5128699.94412585 392948.131162291,5128708.25694998 392938.886078307,5128717.09598999 392938.881089356,5128717.10075982 392869.349294331,5128783.78870889 392856.131338188,5128904.03926276 392869.788619186,5129001.85215899 392921.040097872,5129082.50864999 392939.594223998,5129096.3771071 392939.603005278,5129096.38367075 393010.885818893,5129149.72750229 393111.387893415,5129209.66505377 393203.984079088,5129328.85288977 393215.891632466,5129464.35346913 393173.016630795,5129545.26016531 393150.858439436,5129570.56502282 393036.140792715,5129701.57362622 393002.98422843,5129725.82379725 392941.396243187,5129736.47843803 392903.451574447,5129743.04281602 392753.699271544,5129746.01187008 392503.539385536,5129775.94998378 392399.632345048,5129873.1693424 392239.412465554,5130032.26405602 392210.100676357,5130168.70217224 392213.070651679,5130306.92148529 392219.540503596,5130424.39070673 392209.916467398,5130554.61000795 392149.072499686,5130638.14170229 392048.790525459,5130732.51725212 391875.069984154,5130832.39293655 391663.504815478,5130896.51853027 391580.222853181,5130960.33141186 391436.940407299,5131072.70707042 391358.345878462,5131119.9261223 391358.337790057,5131119.93098495 391332.095618879,5131135.70747265 391169.843461014,5131170.05160012 391090.329432917,5131198.60780057 391090.311258207,5131198.61432773 391004.028975747,5131229.58332307 390870.621635629,5131333.89640539 390701.182026774,5131384.3968375 390459.210143678,5131442.20989569 390404.616155957,5131506.96020143 390404.773253846,5131600.33552766 390419.305721358,5131710.67964326 390412.243757333,5131781.58615058 390338.024937405,5131896.52414872 390204.523538589,5131962.2745484 390046.80271229,5131993.02485559 389913.988072682,5131976.18122009 389735.78932966,5131895.87789917 389735.42215901,5131895.71243772 389716.515360771,5131867.05611908 389571.981062729,5131772.08725552 389506.51136487,5131775.83735682 389479.604770387,5131782.21241387 389234.03940457,5131869.58802097 389096.006383826,5131901.213303 388922.035336683,5131933.83863323 388773.189300139,5131927.77631271 388634.030436623,5131872.40133634 388526.340893101,5131827.68260284 388437.463981855,5131767.6200527 388351.21178844,5131674.49490861 388256.834163314,5131549.83844281 388149.08215691,5131510.58849153 388127.769379886,5131515.21353581 388127.399562769,5131515.29264081 388069.331118797,5131527.71365645 388022.768344655,5131571.80759559 387956.643615577,5131701.96429489 387902.206568144,5131832.24597249 387809.018355722,5131902.40253741 387683.516554347,5131910.62147954 387590.171097294,5131879.4340258 387503.856283962,5131776.34013029 387426.478629891,5131625.71485673 387356.320156636,5131508.18341269 387263.786609173,5131417.74582555 387182.780887846,5131291.45026806 387182.409113164,5131290.87063628 387177.44021241,5131283.30812538 387127.000702834,5131158.62039828 387071.99810947,5130982.80755732 387039.590880763,5130934.40124346 386913.932180852,5130881.58882868 386890.025426821,5130867.80758648 386778.398073713,5130803.74512643 386670.708572628,5130768.96398226 386582.706761838,5130723.37028123 386497.674054816,5130708.37039707 386497.663885286,5130708.36860975 386492.517716472,5130707.46415414 386475.986184474,5130704.68292709 386341.452834485,5130701.27690786 386253.63935409,5130737.27714263 386147.951236715,5130835.27754052 386056.543827963,5130858.77774916 385983.85493916,5130831.99656867 385948.760142974,5130782.65277654 385908.258559579,5130689.3714036 385903.444393696,5130535.05859079 385896.787461117,5130478.83973587 385888.9116599,5130412.96461326 385852.847603138,5130316.15198014 385777.314182535,5130219.30817553 385722.469283381,5130190.43322317 385648.123974982,5130151.37078959 385475.682733631,5130049.2459285 385294.460745839,5130009.18371524 385092.770554928,5130051.68420095 384884.862006922,5130139.96602552 384880.021818156,5130140.61623874 384702.015678741,5130164.52893091 384570.919338906,5130112.6541042 384489.198661461,5130051.27916677 384432.354144517,5130014.24695822 384365.384582075,5129979.05834044 384256.071374883,5129978.46283999 384095.632846489,5129978.49152223 383967.631733082,5129951.80193996 383901.537153416,5129914.83208574 383870.442760021,5129874.39403732 383834.973140548,5129815.95589644 383818.316026528,5129747.01804328 383817.347899687,5129745.05059834 383817.347248667,5129745.04927532 383794.44034032,5129698.54885066 383712.031781964,5129536.95358107 383616.686453127,5129449.63944961 383467.309981205,5129404.13700936 383343.559376889,5129422.29130741 383185.264346579,5129474.58983867 383172.933891244,5129478.66365389 382432.112672226,5129129.30767849 382050.545617803,5128946.48889483 381930.669198259,5128890.45567463 381813.761564185,5128836.01625451 381555.44536519,5128886.57970874 381368.697109312,5128923.13427606 381021.946477756,5129068.91016897 380846.041160551,5129252.40756313 380614.072408873,5129385.43525726 380507.415444003,5129383.96480723 380366.976564238,5129343.80628053 380170.662848542,5129349.99066149 380077.944277665,5129418.39550277 380040.790213423,5129629.4263673 379955.47919401,5129806.17517836 379954.121354302,5129807.34346081 379915.854329741,5129840.26832905 379915.841474504,5129840.2793996 379794.292249493,5129944.95398924 379279.665993473,5130123.85218926 378897.416206212,5130353.6275367 378366.6809587,5130916.98226256 378366.669410609,5130916.9945204 378237.170204929,5131054.46130696 377947.108891135,5131310.67560811 377506.601105877,5131497.25225083 377506.577075931,5131497.26242869 377469.077028666,5131513.13683829 377272.357976651,5131591.66498638 377034.074980805,5131570.78614464 376768.355508367,5131649.93818213 376762.104174374,5131658.76955849 376695.137538811,5131753.37457609 376657.888268789,5131833.68653146 376593.7950704,5131913.02930396 376523.576565284,5131969.90321229 376404.419467585,5131961.21379023 376265.792989486,5131910.33652847 376138.384541883,5131794.20940704 376002.693305361,5131555.42582811 375983.661649708,5131533.08106143 375893.25356053,5131426.92399242 375744.783231971,5131374.14032947 375599.438955512,5131406.57551903 375531.627207405,5131503.76198948 375519.971366165,5131543.44932595 375519.969779084,5131543.45472667 375497.784644065,5131618.94901437 375472.066917037,5131716.38615851 375393.12918816,5131738.35365392 375292.127979765,5131691.28950564 375215.439271748,5131631.81949125 375151.469708879,5131598.25594608 375151.466609136,5131598.2543156 375141.2508288,5131592.88077914 375081.032066892,5131623.00482986 375032.908051499,5131728.37911571 374983.628283286,5131874.87840432 374901.879817448,5132042.06468055 374671.819852731,5132365.71739828 374385.573430713,5132800.46300037 374334.449073106,5132878.08721254 374251.043722939,5132992.52342011 374211.887897763,5133046.36656284 374110.638995748,5133185.33374073 374110.628800055,5133185.34772794 374100.639104321,5133199.05233533 374058.889312703,5133236.48917747 374004.170838717,5133285.73831497 373785.326565466,5133350.95355605 373598.668780583,5133318.79427626 373493.324466251,5133324.98007656 373445.043516532,5133372.69806519 373307.606872866,5133508.38339578 372977.297673735,5133932.09695315 372790.173713299,5134104.59397872 372790.170162929,5134104.59724814 372775.955042474,5134117.68750249 372616.612187284,5134264.74746524 372415.738702513,5134480.15052 372296.050727994,5134498.89858207 372182.611876215,5134445.24047566 372110.235077686,5134337.05177184 372038.734154073,5134297.76935155 371981.640729843,5134350.42468931 371910.20526255,5134544.45482948 371871.615119463,5134847.01677682 371871.613784306,5134847.02728489 371870.177754423,5134858.32925617 371825.681054914,5135139.17234848 371732.870849389,5135362.63963708 371632.871459507,5135456.4505272 371498.902091211,5135469.07334565 371358.618872436,5135378.66479156 371231.74097487,5135209.69394335 371179.165366849,5134977.74499291 371171.737240818,5134944.97416816 371149.550387032,5134864.23037611 371149.54857798,5134864.22379249 371102.921133998,5134694.62925355 371045.605330146,5134462.97203032 370950.884457963,5134341.37672201 370801.727018197,5134318.18680016 370567.694307639,5134313.58925654 370355.194118364,5134397.67957449 370170.318219683,5134413.73907981 370049.723713777,5134411.08087486 369743.345798776,5134327.79465235 369517.516662406,5134301.45274707 369360.186666137,5134283.1009439 369208.373999229,5134340.25473874 368975.278848685,5134340.25096428 368826.122522064,5134402.81105038 368532.309491415,5134496.65004185 368175.933545762,5134586.92551616 368028.589043977,5134596.79812841 367916.025289972,5134552.98380722 367905.228118526,5134542.16171798 367821.367215384,5134458.10728 367710.61665657,5134466.16798652 367475.710658418,5134591.3204227 367345.462794344,5134810.38079058 367239.401311117,5134934.12905694 367239.398405859,5134934.1324489 367221.307735114,5134955.25376096 367124.0914264,5135181.47090497 367082.156269516,5135375.50144765 366884.034768684,5135724.18567314 366793.943845536,5135974.49666413 366778.853974814,5136270.5276158 366807.978677004,5136463.10776126 366809.450611755,5136472.84057867 366824.57760034,5136614.80954984 366821.144583642,5136950.93443061 366845.334161347,5137095.80979895 366875.554018653,5137165.74778068 366875.804959058,5137235.8727713 366886.212501567,5137328.0291741 366923.08862478,5137396.46726575 366947.058138981,5137443.53015 366943.46508978,5137497.40508064 366978.653845522,5137576.56189309 367025.780404329,5137673.46889857 367073.093865672,5137725.68841608 367104.875728692,5137758.34518228 367121.626369416,5137799.34544999 367102.002053342,5137858.68886621 367050.877367345,5137903.3755169 366984.940474588,5137976.06191797 366918.191126759,5138052.34205411 366879.389001928,5138103.86746532 366856.816879829,5138133.84102677 366808.567344957,5138188.37147059 366781.879859463,5138200.4022785 366723.879623085,5138206.55757204 366647.597692618,5138187.11882044 366589.003223451,5138157.58661265 366536.397323923,5138113.34832342 366535.564825097,5138112.64824369 366485.313702831,5138049.80368183 366453.312870236,5138001.05316715 366416.593619779,5137978.95881858 366416.587707755,5137978.95525782 366386.499459196,5137960.83332812 366339.185982065,5137907.73881331 366288.122364621,5137845.83173942 366216.683841031,5137799.36182728 366108.557463946,5137741.9225659 366029.025822986,5137745.79625858 365970.026257097,5137802.23277408 365930.277242936,5137891.48209619 365920.371655258,5137944.51316849 365932.841234391,5138000.70085767 365960.811103591,5138072.01379758 365972.686771742,5138116.57648041 365972.687422175,5138116.57892797 365975.061905694,5138125.51401698 365972.469001608,5138189.13895637 365940.282070582,5138244.32591086 365898.688475529,5138272.70021792 365827.313242323,5138284.48028935 365732.281270375,5138269.79122924 365647.405031084,5138212.88359962 365569.934628535,5138122.63235302 365567.655039181,5138116.57448271 365567.653283612,5138116.56981739 365527.901621939,5138010.41294692 365499.08722652,5137882.66251335 365474.398328754,5137789.91213682 365400.896571652,5137690.84846121 365376.365258986,5137684.03591527 365333.990003365,5137661.53583604 365283.864981056,5137655.28574247 365239.771714256,5137686.41065965 365197.397982532,5137774.94182825 365179.555719593,5137881.72304155 365166.307346518,5137999.16051247 365161.902624819,5138110.22299993 365160.902713005,5138116.56674776 365160.902198506,5138116.57001858 365149.778695896,5138187.28547338 365117.904723126,5138259.47290813 365048.404931382,5138268.69152207 364993.341983506,5138231.22266712 364917.278734731,5138169.87877381 364875.965555283,5138116.56689138 364867.996674336,5138106.28493355 364801.183660132,5138062.75355874 364798.97112409,5138062.28804314 364750.089825187,5138052.00346172 364711.183923816,5138074.09713491 364666.187346678,5138118.2502155 364662.872128751,5138121.50328703 364641.967104594,5138209.56573682 364635.062474466,5138327.78445968 364649.313931514,5138435.87822487 364689.065706344,5138569.37828793 364696.285289058,5138631.03454516 364658.223828381,5138704.12821014 364605.78730269,5138771.34684599 364544.225664251,5138829.62796356 364490.91345493,5138846.69035307 364423.038507611,5138845.0964658 364356.851023245,5138840.90883246 364313.007271247,5138837.22124436 364281.069995494,5138851.15867724 364260.289258966,5138887.31487852 364263.47720422,5138920.37737891 364314.665608134,5138991.03372048 364391.104176879,5139075.7213625 364468.574177013,5139173.69025623 364493.012619355,5139244.84654557 364487.076089082,5139315.69027176 364439.077085231,5139385.34640949 364394.734339416,5139455.94005373 364319.141655568,5139528.87738026 364216.486331473,5139589.62715005 364095.080909628,5139641.93937995 363959.643840167,5139663.97033556 363868.425079219,5139656.56389265 363818.924788449,5139631.43879367 363808.392994932,5139590.40753212 363823.485954133,5139532.93882924 363839.172370844,5139453.87638284 363837.827523682,5139372.53265086 363841.545639761,5139325.87642051 363818.638210236,5139236.7826455 363785.481169167,5139175.62634255 363716.855629066,5139130.25121296 363615.824412883,5139124.84475658 363521.76249225,5139160.5008027 363371.857973439,5139277.59420678 363243.796764983,5139363.9689119 363237.626104089,5139370.40515816 363243.364277513,5139737.56253265 363288.385949383,5141356.56204431 363326.407379677,5142957.5615029 363362.428937446,5144568.560907 363393.450473892,5146178.56025039 363423.472146704,5147799.55953667 363462.493638907,5149407.55881229 363508.51540958,5151036.55805747 363525.541458662,5152632.54365357 363546.568453368,5154268.52794437 363567.595379654,5155902.51222113 363588.622172094,5157530.49652267 363626.648776953,5159144.48095067 363644.675349591,5160763.46526335 363661.701697692,5162371.44965229 363685.728248551,5163991.43389613 363709.754736729,5165609.41812413 363291.783016622,5165620.07441053 363315.77770652,5167225.40265729 363337.803609773,5168831.38711532 363364.829545382,5170438.37152247 363394.855248387,5172030.35603161 363427.881124527,5173632.3403966 363454.906150243,5175186.32520418 363467.932862727,5176859.30886258 363504.95904189,5178481.29290082 363550.977890328,5180075.29164102 363580.994093155,5181701.29615338 363611.010184343,5183316.30059055 363641.026261061,5184930.30498119 365281.047940272,5184892.29791889 366907.07038705,5184868.29350236 368514.094609698,5184840.29551664 370108.118282876,5184782.29747898 371712.142246418,5184739.29951398 373341.166495797,5184691.30160356 373382.189451016,5186298.30396487 373391.212936974,5187983.30635824 373441.235923314,5189582.30862248 373500.258375488,5191128.31076725 373541.281566533,5192751.31295644 373588.304614556,5194354.31507048 373653.328067132,5195956.31712917 373679.350870619,5197573.31916324 373718.373690395,5199170.32112234 373765.39676851,5200771.3230325 373810.419975119,5202384.32490804 373864.442539376,5203931.32664582 373465.40057681,5203942.92090823 373500.454499719,5205564.32904337 373528.486156668,5207158.32407421 373555.531914217,5208769.30919172 373587.577486548,5210369.29435633 373634.623218261,5211958.27954698 373683.669690791,5213571.26446363 373729.716095648,5215185.24932957 373769.762010239,5216789.23425526 373804.807979489,5218402.21906225 373825.852371883,5219978.20420591 373804.895460481,5221568.18928244 373851.941887044,5223185.1738895 373909.988276518,5224784.15858966 373945.033749309,5226384.14329541 373981.079382714,5227989.12790541 374019.124894757,5229587.11253092 374045.169847411,5231185.09714693 374094.216351173,5232802.08146562 374128.26138167,5234373.06628169 374141.315162816,5235996.05154401 374166.369620794,5237623.03668185 374208.423516773,5239209.02210155 374251.477236066,5240789.00753324 374283.530978323,5242386.43028713 373681.502561762,5242386.55653017 373719.557267099,5244003.97891204 373769.611971478,5245604.9638833 373819.667365047,5247227.94860987 373878.722823408,5248840.93337997 373941.779351181,5250481.91784665 373992.834567751,5252100.90249579 + + + + 363237.626104089 5125662.98278777441585.913042356 5259195.11379287 + 373992.834567751 5252100.90249579 375578.907291097 5252060.9016806 377183.981372119 5252035.90076999 378770.053836318 5251988.90012694 380424.132814015 5252045.89859687 382036.206902856 5252012.8979458 383378.268520258 5251983.89746 385004.34489571 5252002.89649079 386772.428209329 5252032.89545573 388359.488754287 5251990.89431465 389964.549770751 5251954.89312519 391575.611064042 5251920.89196047 393178.672571485 5251902.89076516 393228.738270271 5253772.88131533 393228.792456634 5255363.87321734 393234.396568643 5255577.49913186 393290.022245729 5255616.371974 393390.058438338 5255644.18441468 393456.779853272 5255644.18446989 393523.470080964 5255646.05951586 393612.378616319 5255608.99727381 393710.566996525 5255520.06029167 393761.41076364 5255461.24811933 393799.504685641 5255421.87334027 393801.348444994 5255419.99835078 393841.473568551 5255376.87359007 393843.129820376 5255374.99860038 393872.227230318 5255341.53053376 393872.254834063 5255341.49878372 393897.254849763 5255312.87393979 393937.723412979 5255260.37422077 393978.628478725 5255178.31214177 394000.095924966 5255115.37495644 394028.845055521 5255056.68775393 394150.002619737 5254954.68830693 394178.156529424 5254854.00129532 394182.905333014 5254813.68898684 394167.965771729 5254770.93918013 394099.587293418 5254748.62675282 394009.927251763 5254741.75174377 393877.07762318 5254723.93926859 393780.791470774 5254692.25187944 393703.692246657 5254621.56469184 393669.876928002 5254578.31489037 393670.062654952 5254526.25264556 393700.781229152 5254485.56535535 393760.812865314 5254427.44065828 393853.751326504 5254348.19106971 393938.597961266 5254334.50365964 393995.006383031 5254332.81618377 394145.355850435 5254326.25375792 394274.486167185 5254332.44126676 394384.022495763 5254354.19119954 394496.36942946 5254317.6914001 394536.806777902 5254266.94164156 394531.897189883 5254175.75455242 394583.272771438 5254133.81725321 394667.119014884 5254110.19237722 394714.55412945 5253986.94293421 394721.021368279 5253935.8181618 394744.520795483 5253892.44335681 394735.643469879 5253835.25610857 394714.858845106 5253761.25643422 394717.749468196 5253733.17612058 394721.13823463 5253700.25670446 394781.639561834 5253669.81934075 394850.141230463 5253640.19447216 394876.479432891 5253639.04667605 394969.176980153 5253635.00699702 394976.271037152 5253635.81949367 395519.510298066 5253611.56960918 395527.698069839 5253610.13211528 395591.795584246 5253645.88197253 395621.11081318 5253691.13179129 395623.173960433 5253707.38172584 395623.176417391 5253707.40122329 395626.206167995 5253731.44412897 395624.42712544 5253796.81886485 395634.993873549 5253906.81842208 395675.779923451 5253998.44306012 395723.252798144 5254063.06781092 395768.693664449 5254108.19264151 395804.538842082 5254108.56764903 395837.383216462 5254089.31773351 395891.728427757 5254069.75532382 395967.856422362 5254069.50534305 396028.203464222 5254095.56775665 396091.7057842 5254090.2552933 396158.018641153 5254025.69305678 396207.143077038 5253954.25583919 396239.860088802 5253867.81867238 396265.140567313 5253817.38136647 396287.703064163 5253791.94396523 396349.451795259 5253686.44436663 396349.452518554 5253686.44313108 396435.981260687 5253538.63241924 396471.021093905 5253535.14250544 396585.330355029 5253523.75747785 396741.052982495 5253460.13270856 396914.055403227 5253336.13314084 397183.096578436 5253318.38319059 397545.171773706 5253275.94581428 397881.089840105 5253237.88341716 398071.64310277 5253157.87611795 398411.165163381 5253015.32152345 398631.698949906 5252845.19695914 399211.553391767 5252512.82267203 399663.185514918 5252316.76194781 399663.18890481 5252316.76047621 399860.037217754 5252231.26058686 400083.512972148 5252184.8230912 400127.578144634 5252211.26051796 400233.550599022 5252199.82299713 400392.403112184 5252270.94779296 400644.262451817 5252429.8224055 400740.299196128 5252477.88478972 400989.095604804 5252627.32196682 401273.410740343 5252782.18896504 401273.424874001 5252782.19666367 401461.623488353 5252884.69648485 402111.037066948 5253242.0084967 402756.197989468 5253528.32078538 402756.232668418 5253528.33619738 402793.32506112 5253544.82077835 402867.907487764 5253578.15366794 403433.110881015 5253830.75824447 404070.552136632 5254094.38338663 404491.656023924 5254280.81508194 404491.669532849 5254280.82106263 404783.560952753 5254410.07122691 405363.374686197 5254661.44665537 405734.208224886 5254827.88450101 406041.500987131 5254961.06164401 406211.470139018 5255034.72431631 406211.538019337 5255034.75373486 407660.240902993 5255662.48321719 407660.246229705 5255662.48552528 409257.927861926 5256354.76517912 409768.695446346 5256576.08211699 409768.735834776 5256576.09961805 410876.518642679 5257056.12235784 412464.215509083 5257744.10071817 412464.225407797 5257744.10500746 413134.450013265 5258034.52484274 413134.466727295 5258034.53208522 414078.413610222 5258443.55154306 415221.098420247 5258938.68567606 415571.629807004 5259102.51900859 415769.741983816 5259195.11379287 416434.655664678 5259066.41721755 417233.950045496 5258911.95358296 417489.386345476 5258862.59051942 418521.576772072 5257884.97093374 418521.591206801 5257884.95726216 418620.339921949 5257791.45653319 418831.135731339 5257384.15777492 418831.142864938 5257384.14399141 419054.28907216 5256952.8940561 419277.644919394 5256325.22223341 419856.168262366 5254699.46313352 419856.169413348 5254699.45989922 419961.504463663 5254403.46415262 420370.297607175 5253877.47685802 420370.308017787 5253877.46346286 420684.45751304 5253473.27560163 420699.582566932 5253465.52549195 420722.613575374 5253443.65040793 420764.831886821 5253403.65025458 420829.73680308 5253321.52519332 420834.64266021 5253306.21276429 420854.485740219 5253272.90031502 420866.891582105 5253252.40034442 420911.702847702 5253185.7753913 420916.608703616 5253170.4004639 420929.139875651 5253160.0879085 420943.95161062 5253126.9005183 420948.92029462 5253121.71300567 420976.294371275 5253075.65058271 420989.130741489 5253056.910871 420989.137780079 5253056.90059542 421006.168577563 5253032.02561281 421021.011645038 5253001.33820388 421045.854749242 5252965.46322743 421050.760526428 5252947.58832284 421095.478050707 5252880.96338574 421190.632859417 5252775.46322344 421240.569406453 5252713.83819618 421287.849247044 5252639.52580995 421318.005367827 5252616.21317859 421315.286159703 5252603.58831637 421350.066321376 5252547.21341889 421382.409098178 5252495.96350618 421384.314008781 5252452.71385708 421391.845169808 5252445.08884084 421391.719840624 5252434.83893032 421396.030730076 5252381.526842 421375.216517007 5252341.1524139 421374.62137633 5252297.90279171 421389.339211332 5252259.71546142 421439.620257473 5252220.90275569 421482.62079669 5252210.08988797 421515.370809449 5252189.33971675 421547.839000509 5252150.77720407 421547.525768606 5252127.96490559 421557.619477922 5252120.15236577 421554.900351987 5252110.08998223 421562.462842742 5252104.90244671 421559.837466754 5252094.77756272 421579.680564474 5252061.40264186 421612.18009031 5252025.40261033 421690.211223396 5251971.02725899 421722.616760143 5251927.4647989 421729.92868152 5251904.46492394 421734.020257746 5251833.27800685 421753.863120106 5251792.34065896 421788.862620665 5251753.71563313 421889.644066225 5251693.90261076 422075.827735249 5251576.96673523 422075.831736897 5251576.96422193 422108.800519537 5251556.276567 422205.645840043 5251504.99070285 422207.113423663 5251504.21352236 422244.926218816 5251488.58827447 422292.238430961 5251448.1506557 422350.049479048 5251363.71333411 422397.70382296 5251271.46369329 422432.732605257 5251169.65177332 422437.887611685 5251126.65211682 422435.792387474 5251081.15255657 422428.885208473 5251056.21535543 422411.540394442 5251033.96573417 422294.688318968 5250847.59360662 422255.654102918 5250779.59461272 422219.55840433 5250741.97031117 422061.99058887 5250679.15993049 422061.990289746 5250679.15981114 422010.145087406 5250658.47312548 421961.424283542 5250626.16139231 421855.856373036 5250525.97581499 421817.417266538 5250501.03890998 421735.883675561 5250481.85237194 421596.130524203 5250476.16627958 421514.722253168 5250467.04214947 421468.689318028 5250444.85528805 421437.437048994 5250394.48102527 421385.401717388 5250301.16982975 421335.678528613 5250195.23371455 421331.737705773 5250093.67212132 421345.735002741 5249999.48529523 421345.537144329 5249912.26386602 421345.22786428 5249775.92471481 421330.504103495 5249628.73861119 421338.875153431 5249499.17714312 421346.218410959 5249478.73975099 421345.591940809 5249433.052648 421357.778483914 5249394.74036538 421359.683396659 5249351.49071882 421369.55787616 5249328.42832716 421388.837111648 5249252.0538087 421423.517340626 5249000.05566585 421452.195427332 5248684.68313187 421461.975917627 5248654.05831132 421524.318507261 5248574.43346162 421551.567482383 5248523.30867083 421555.157836141 5248413.99708926 421539.312288896 5248368.49761892 421513.247526146 5248315.49829921 421511.959865427 5248306.3313929 421507.5586117 5248274.99869791 421494.776839725 5248267.49887062 421340.200046766 5247926.69059106 421332.261646246 5247904.0033505 421282.412996707 5247785.31727213 421271.379475581 5247721.88040245 421269.46880705 5247584.75658579 421247.996825848 5247498.63249077 421244.400567 5247422.57066615 421252.336254887 5247360.19613367 421277.364405893 5247245.38441401 421304.456728695 5247181.44724735 421339.299551238 5247127.63493585 421471.860304437 5246978.44769333 421531.765467603 5246901.51039967 421541.921863026 5246898.82284537 421541.671292921 5246881.07300122 421568.982868386 5246832.4482153 421593.91995487 5246801.57329442 421593.700633866 5246783.7609511 421611.231792789 5246768.32345282 421613.66902469 5246758.13602316 421625.918251708 5246725.01121945 421633.230187974 5246702.011365 421635.604998005 5246694.32391421 421639.93604477 5246678.39095562 421645.322834495 5246658.57415329 421650.29145582 5246650.94918262 421644.821612398 5246620.44948996 421629.007389331 5246577.57498222 421600.161055511 5246517.01322451 421592.253901606 5246494.26348113 421558.751936342 5246456.57655645 421510.09362297 5246426.76467374 421491.873574267 5246399.07754727 421496.34096919 5246353.2654105 421516.309362567 5246327.64048607 421576.496443293 5246270.95303882 421616.746461364 5246242.39049484 421659.746948449 5246226.57782083 421715.435305397 5246213.20253434 421755.779319922 5246192.26492625 421808.372488355 5246135.70254511 421823.215606206 5246104.95270991 421832.77703582 5246064.20300146 421814.086858946 5245993.32876096 421792.834284135 5245927.57949187 421792.671749198 5245729.39374021 421797.327140677 5245698.89397675 421819.764106339 5245665.5816151 421855.170759483 5245652.33148713 421944.047787528 5245651.14338276 421984.517061154 5245637.95572049 422052.078932474 5245568.33087781 422083.297635789 5245543.83088341 422094.860118614 5245534.76838561 422231.393049078 5245487.20538154 422494.835058808 5245435.32906221 422527.553920511 5245414.57903166 422585.115589298 5245345.26678407 422604.927507429 5245311.95445981 422614.582703433 5245271.14227407 422606.017937438 5245205.26794313 422600.673425301 5245184.95566728 422595.548148442 5245179.95574776 422577.171372993 5245137.08126729 422561.639125466 5245116.89405706 422520.6059753 5245087.01960419 422496.489997244 5245048.03760108 422496.479184468 5245048.02012289 422489.416161383 5245036.64527414 422465.600875504 5244965.77108275 422451.848246604 5244892.39684717 422444.003756088 5244874.70956057 422443.659198623 5244849.27229659 422435.720794628 5244826.46005738 422429.843664227 5244763.08567718 422442.249562794 5244742.58578611 422477.625066146 5244732.02315724 422660.347730712 5244719.27210901 422743.942863871 5244700.39675247 422963.69518479 5244608.45872556 423072.791232932 5244599.39562315 423110.854537993 5244596.33291229 423143.604744552 5244578.08288079 423166.198307476 5244554.89546129 423245.539479632 5244411.58384623 423315.663827504 5244337.02163418 423388.726692196 5244292.83411446 423573.57349836 5244249.58340654 423702.951124235 5244211.9160219 423738.013431865 5244201.70787795 423803.889657037 5244190.5825884 423854.7032688 5244187.39481166 423905.611101011 5244199.39438211 423944.175441444 5244229.33134657 423957.145196942 5244251.95603977 423970.647234945 5244307.70539568 423968.961654285 5244371.32976515 423956.461831138 5244386.70468763 423959.21228526 5244399.32954351 423946.649802952 5244409.57951822 423946.869106871 5244427.39183766 423975.151799351 5244452.45390945 424018.528200691 5244464.57851692 424066.779324932 5244463.95322252 424112.279913318 5244448.01560082 424152.404835283 5244414.51569212 424167.153929631 5244373.64101704 424163.056649859 5244261.89218054 424195.368266019 5244208.08003203 424255.74343179 5244166.64258895 424356.681736983 5244114.45501461 424416.837842521 5244062.89268459 424421.524595356 5244034.83044647 424449.05641287 5244031.89281265 424519.086735325 5243982.76546948 424587.461809958 5243966.63786594 424650.273090999 5243910.07338602 424723.272104283 5243858.32094554 424773.928287044 5243842.44405399 424811.677647115 5243811.50533222 424927.488323561 5243721.18903625 424937.268631943 5243688.06396576 424954.736658528 5243659.93853504 424974.109535597 5243586.00097629 424975.857432102 5243517.43907775 424985.79453947 5243502.06382617 424998.231354667 5243476.56357253 425048.85636252 5243463.24915306 425127.701049451 5243472.43337074 425229.201617576 5243463.61684715 425303.545163236 5243437.11409532 425303.549402951 5243437.11258231 425317.732624008 5243432.05107015 425378.357317052 5243405.9238695 425403.270589048 5243382.7576384 425403.294305405 5243382.73558515 425406.013000479 5243380.23549935 425463.136866116 5243328.35868973 425462.480264155 5243317.17132501 425460.792492731 5243308.85897413 425455.948497517 5243302.23423474 425447.948330789 5243298.98459044 425433.698218927 5243299.17266596 425417.541907133 5243301.48579805 425397.916946351 5243307.98652995 425372.697715243 5243299.17513742 425355.634743497 5243288.48843276 425343.821153443 5243256.42672351 425345.507970825 5243233.92687414 425359.506696935 5243189.05174343 425375.537302995 5243163.98883738 425400.474334798 5243142.23803789 425418.38050765 5243134.98738237 425447.099902502 5243148.17358989 425447.288209402 5243174.17332972 425462.758500157 5243219.79725953 425479.946995741 5243247.3587953 425506.354472486 5243279.91990916 425551.353092976 5243223.41863382 425560.165621094 5243221.98079062 425563.165913152 5243230.60558541 425565.041097145 5243236.04295671 425567.791365844 5243243.98026831 425570.51055476 5243257.41752786 425573.260993946 5243270.85478616 425578.761759986 5243294.10433792 425588.762423759 5243312.85375104 425604.075602435 5243330.66545811 425621.201379501 5243351.16456581 425642.827135771 5243369.78850955 425669.796296844 5243375.84985863 425674.858885241 5243377.34963909 425674.934197452 5243377.3720909 425702.109362684 5243385.47345691 425719.078194943 5243383.59778787 425737.890648983 5243377.09708887 425740.010214788 5243376.08200283 425740.109384381 5243376.03450929 425761.078005389 5243366.28375434 425789.608818469 5243344.59530833 425809.233420225 5243326.53218786 425816.420044734 5243296.40718753 426022.641687027 5243334.64846594 426081.079571282 5243331.45862981 426093.704510585 5243326.14566952 426234.451831359 5243202.57865267 426287.545445784 5243184.13917769 426328.358659772 5243196.2624079 426417.171624064 5243187.63389151 426447.264740691 5243159.32044218 426501.824110273 5243044.3818262 426523.822067562 5242973.00661389 426573.256469659 5242860.56817836 426566.505935163 5242845.19359849 426561.84949313 5242840.25633441 426541.161697012 5242836.19471257 426506.16099743 5242822.94625908 426475.597836297 5242809.76012506 426445.065699758 5242789.32405904 426410.783342017 5242762.76320388 426390.126228305 5242740.45175531 426380.937483647 5242702.88998672 426397.812090207 5242685.82696422 426417.436826176 5242672.20129717 426441.593045662 5242664.88788584 426469.34307169 5242658.44932016 426505.249829028 5242665.32279647 426546.53168879 5242674.07103677 426594.938630275 5242683.56898076 426637.970333149 5242686.81720254 426676.283491168 5242697.87804186 426692.813726213 5242661.00272043 426732.687135307 5242599.56418343 426767.090643263 5242502.68870327 426766.370063986 5242444.2517858 426737.743017776 5242386.12849988 426704.430449989 5242392.62979268 426685.680638845 5242403.56795129 426673.243710305 5242425.13075245 426662.68210293 5242456.5058842 426653.807730458 5242478.94353205 426640.558491852 5242506.81880599 426626.277661489 5242524.00672317 426603.058893881 5242529.50761442 426567.932890937 5242506.50926029 426552.525403249 5242470.82272563 426532.586656173 5242436.01136702 426531.554476479 5242406.44919003 426532.209783214 5242376.01195274 426541.959052007 5242350.01180343 426559.70846546 5242326.57380431 426578.426722354 5242305.88573951 426698.018928816 5242225.31913873 426758.705564592 5242181.87958072 426801.611539326 5242161.94052329 426821.54958683 5242174.31459496 426838.704463395 5242125.87685449 426893.765245675 5242056.62526697 426931.421250946 5242039.06139951 426931.434142717 5242039.0553835 426972.139735793 5242020.05992068 427007.608597992 5242014.49602885 427033.328422654 5242042.24472045 427115.299629895 5242099.67834344 427169.14506588 5242139.6757763 427217.614665312 5242154.2986667 427247.770431821 5242131.04765762 427239.581279795 5242080.36096614 427190.422425647 5242009.80112922 427177.202226058 5241966.86457046 427219.669392251 5241905.30091825 427490.136874861 5241795.35342681 427512.448034294 5241746.85296971 427507.760063851 5241733.04078954 427507.759671562 5241733.03963564 427501.853222022 5241715.66619228 427483.663894005 5241661.97993435 427478.163338843 5241645.66781074 427480.631867742 5241637.98028176 427482.693269968 5241602.41802925 427563.09782598 5241527.85294411 427643.815676353 5241478.60010886 427747.346199541 5241429.09634358 427792.783324321 5241405.59470699 427815.658418391 5241402.78129942 427818.878061245 5241430.4059122 427805.691923493 5241477.15601728 427810.349081718 5241504.90557021 427823.006131273 5241527.15484779 427853.632211953 5241553.77835203 427875.100874598 5241545.52755272 427894.693937325 5241518.65200213 427931.098640841 5241460.15105773 427984.095254346 5241338.90001456 427967.063393539 5241323.77584948 427909.719454053 5241332.27811207 427881.9693509 5241336.02921031 427856.87540505 5241336.15523362 427837.531114493 5241323.8436373 427806.623272624 5241280.97029621 427798.40278573 5241227.72112499 427827.806545662 5241140.97072671 427912.239736362 5240982.4687407 427931.769059366 5240916.2185537 427967.487252672 5240889.52983904 427995.612847748 5240901.4035792 428012.488644879 5240922.52769432 428031.333942422 5240967.02651368 428039.459680497 5240988.46348396 428060.336104983 5241028.52476154 428081.80502093 5241028.39888512 428118.523800084 5241020.08496068 428120.147969765 5240993.27264091 428118.209497271 5240962.83550012 428113.489469795 5240923.39855585 428097.081744029 5240880.5871207 428092.424386219 5240846.52512457 428097.704233305 5240800.58783112 428125.672611899 5240781.77435971 428184.549253219 5240819.20910681 428236.333450341 5240899.89374799 428269.99163211 5240952.82938605 428343.930485838 5240977.26363916 428504.0568526 5240980.44456402 428567.432091882 5240972.12954915 428655.649986489 5240922.87639123 428655.651697681 5240922.87543563 428688.555916929 5240904.50021297 428723.554659362 5240855.87422389 428712.615154558 5240795.0627241 428673.236494842 5240688.87780087 428690.485102474 5240640.44003526 428675.358599653 5240596.56605342 428657.107577197 5240568.69205421 428651.169687618 5240557.81739627 428651.160664338 5240557.80093873 428644.41924635 5240545.5052847 428623.668155315 5240516.0689024 428613.667428521 5240495.50699915 428602.760277172 5240469.63268145 428613.352949152 5240432.82008249 428632.946483765 5240421.13188599 428649.461729364 5240419.69512131 428649.477817678 5240419.69372169 428667.009157433 5240418.19301698 428693.853194224 5240420.6293949 428727.072282869 5240423.12801109 428760.134723848 5240413.06424771 428787.790365439 5240386.93835144 428783.227121532 5240364.50124191 428769.601255609 5240340.43951859 428717.066414307 5240239.63008705 428715.566183702 5240232.69271154 428715.562033437 5240232.67315401 428711.534302746 5240213.69304935 428720.252020059 5240178.81800834 428733.65803114 5240167.94255714 428756.001637324 5240157.87923191 428873.314854283 5240151.68697586 428889.533813333 5240154.31128684 428904.003803169 5240189.99787059 428890.004641763 5240219.99817334 428889.997553997 5240220.01339022 428826.133473843 5240357.12455032 428814.633920726 5240374.12486755 428813.85340258 5240397.49968768 428821.166689827 5240420.62417844 428821.323734269 5240445.7489443 428808.824202717 5240463.68679377 428797.262182377 5240481.74960362 428790.294168904 5240506.81216173 428785.919902026 5240531.12462036 428788.764605456 5240560.62423626 428799.297372305 5240606.06089284 428829.922839666 5240613.24707387 428910.766150719 5240579.24407202 428965.98346615 5240520.11734574 428995.512532296 5240443.67932694 429018.412369999 5240235.11777138 429017.568253364 5240210.75486928 429017.567843021 5240210.74302597 429015.033679321 5240119.18145608 429002.40693177 5240066.99494499 428980.186843911 5240030.12118959 428963.061005979 5240007.80959388 428932.498020183 5239999.93591942 428898.466516229 5240000.24981342 428866.279027279 5240008.50105994 428839.403909706 5240011.37713698 428812.528794088 5240014.31571345 428782.903146086 5240001.06704946 428772.027527097 5239984.13014935 428769.183050688 5239961.81796831 428787.93256643 5239941.87987918 428810.213418579 5239923.81662794 428852.213254071 5239908.31504367 428880.806625119 5239889.31404135 428918.306174644 5239865.87521318 428946.02464913 5239850.37421478 428963.89966876 5239846.62351449 428988.087549267 5239852.74746581 429009.619129659 5239857.93403474 429038.338239975 5239862.30781587 429067.869285496 5239848.61922639 429082.02488005 5239824.43136283 429092.711921048 5239807.30607803 429113.149653999 5239809.68021716 429135.868729714 5239814.42924124 429155.213141218 5239830.61580114 429176.40206056 5239870.30207417 429189.090447692 5239895.23882903 429205.278721611 5239915.73798017 429226.029556688 5239937.04943682 429239.561334774 5239950.42376122 429270.093125982 5239960.04742155 429289.812022869 5239959.85911383 429307.655739024 5239954.42093016 429318.185960559 5239919.35831226 429314.497440658 5239888.04624441 429303.496283107 5239854.17199984 429285.463961808 5239824.73550436 429268.244174647 5239796.17396783 429242.961629583 5239761.42531821 429218.554036165 5239724.92664865 429205.80275119 5239687.42750933 429203.801659862 5239653.42789686 429212.644708541 5239629.11525166 429206.300160118 5239605.42822512 429226.456074569 5239589.9275356 429297.330867545 5239566.17483461 429355.800126289 5239568.04741385 429449.738312711 5239566.91856172 429472.050756455 5239559.73020856 429482.644478939 5239556.2923037 429481.519022639 5239542.16747608 429471.924252162 5239512.29313736 429456.391765878 5239477.04409093 429452.578216649 5239444.85703525 429472.26552096 5239433.91882306 429509.015824461 5239434.60480516 429569.953948181 5239439.53975444 429635.392277044 5239449.84947094 429658.767480121 5239450.59850281 429675.018451436 5239477.28509707 429662.644383491 5239509.66031799 429649.36371348 5239531.1606728 429620.0211097 5239574.41149419 429603.958999517 5239590.59951032 429584.990912165 5239616.10006281 429646.367570047 5239653.47220739 429723.150912821 5239700.78113141 429768.932656751 5239705.216711 429778.495361437 5239709.34128149 429789.339649382 5239723.65320889 429792.15282376 5239744.21541078 429789.622492541 5239773.77775224 429782.623291445 5239800.65280105 429772.061991163 5239841.02787613 429769.625608838 5239876.840158 429775.970203341 5239901.90217487 429794.971026962 5239923.2137056 429812.908888172 5239930.21290716 429842.471412956 5239923.77425089 429913.096007612 5239893.77161789 429931.814444053 5239879.33347736 429933.407380568 5239853.33364222 429929.562292602 5239812.14666484 429918.340670766 5239724.46040224 429912.65153681 5239674.39857929 429902.931945658 5239650.27419233 429935.180327918 5239591.52338711 429973.148951156 5239578.33444311 430011.399714245 5239593.08274051 430068.747601033 5239709.32935724 430104.749154568 5239749.45252428 430125.281040108 5239764.45154868 430178.781839177 5239776.57424458 430204.094282369 5239768.63577498 430251.805343489 5239709.89195168 430251.81153196 5239709.88433218 430279.123172799 5239676.25850589 430295.933210702 5239594.8210309 430272.30593641 5239529.07257987 430247.085395536 5239478.88655797 430247.065130004 5239478.84626715 430220.2709934 5239425.57562951 430224.142785711 5239323.82636509 430242.452446773 5239254.0166138 430242.453204368 5239254.01372529 430243.515585201 5239250.01371672 430307.918014048 5239114.51225511 430345.917967379 5239103.94828284 430509.421577742 5239178.12840114 430513.204927995 5239243.12767728 430514.268204909 5239267.25242264 430514.394006515 5239292.37719784 430518.11363941 5239319.18931041 430527.302092121 5239346.87619038 430541.708992321 5239363.81294971 430556.115635628 5239372.68727956 430581.209769303 5239378.68619498 430607.990648845 5239360.62275108 430628.458752676 5239335.43462885 430622.769726485 5239288.93526851 430624.330668107 5239239.68563383 430636.704479254 5239199.43547551 430720.392427261 5239193.432083 430735.205178018 5239197.74393575 430737.955512096 5239207.55623717 430732.612233708 5239223.61881733 430731.019275082 5239248.80616369 430733.051910451 5239291.74320637 430736.803137519 5239329.30522511 430745.897585315 5239348.99217966 430767.55470928 5239371.1785958 430790.96164739 5239387.11499449 430825.962364775 5239401.17593282 430850.11868049 5239397.42497198 430867.087071903 5239382.11190711 430872.336367945 5239358.79939359 430863.116264319 5239318.61262171 430848.520746561 5239266.73867259 430829.331130686 5239205.05249797 430804.860599863 5239155.11643903 430805.640128327 5239100.99187713 430827.261959432 5238996.55439349 430856.19553098 5238866.61682865 430881.163245 5238828.24113217 430888.412483633 5238802.67855485 430994.004072172 5238709.98750294 431080.160372442 5238691.17161198 431098.035827311 5238701.17078844 431134.099803186 5238738.79397669 431158.165643339 5238837.54213327 431184.762837348 5238938.91516358 431198.76634806 5239045.35116963 431206.924039531 5239088.47546214 431250.675982808 5239138.78572757 431322.302881923 5239181.03241588 431508.086377232 5239206.77454937 431586.649121875 5239195.64641174 431674.77256393 5239126.01837977 431707.302910094 5239090.07984728 431773.397136633 5239089.20213385 431853.899430004 5239141.51087506 431858.115192378 5239144.50846021 431858.118308525 5239144.51067592 431925.122044907 5239244.9445654 431971.123111785 5239267.19248425 432081.75283505 5239387.8119124 432115.536372922 5239450.93498927 432187.66442913 5239528.7438672 432231.541792749 5239591.74153242 432285.105257091 5239608.86418795 432358.950122511 5239625.79851256 432384.544386038 5239635.60987891 432476.327458173 5239670.16831957 432519.985170762 5239705.10373376 432538.581183597 5239770.91491781 432537.272025559 5239875.03909702 432499.655637394 5239998.33592644 432499.650701986 5239998.35210343 432485.933293273 5240043.35228728 432456.843008563 5240158.10251364 432462.751426357 5240224.03921639 432545.035988315 5240306.91014946 432665.978644202 5240437.52910212 432735.951760437 5240555.96274664 432772.830394313 5240659.7103696 432783.582195138 5240712.95948416 432773.80185245 5240743.52212786 432747.430744904 5240870.83463821 432740.150425606 5240901.5221782 432700.809895495 5241011.21036396 432702.282582003 5241133.0842805 432683.129292311 5241229.77174948 432679.978172552 5241389.89553201 432684.355048866 5241447.08237286 432698.621560686 5241638.26320182 432701.112413624 5241671.64230216 432733.116586203 5241793.20247775 432766.649482272 5241835.88825501 432817.431125492 5241835.32369436 432893.211893738 5241801.32089719 432930.86720768 5241762.81968784 432937.74013186 5241696.69496167 432934.895621542 5241673.82026886 432975.618981181 5241634.19734614 433035.299531864 5241576.12949839 433065.831015856 5241575.75325846 433090.548317766 5241524.69017794 433082.516327646 5241503.75317963 433088.703155593 5241481.37811423 433077.638806391 5241426.81651988 433064.85609881 5241384.81739093 433052.948370177 5241341.94323378 433035.759609423 5241307.13172477 433023.008469064 5241274.94501313 433002.100439071 5241224.94628289 432984.848976842 5241183.8848292 432973.004039787 5241150.01059518 432948.533713887 5241107.199451 432929.689295617 5241091.13785405 432912.595155358 5241083.26361733 432892.157383533 5241079.88947947 432886.280046016 5241008.82781364 432878.592327649 5241003.95316819 432908.873317092 5240988.38956232 432990.186678174 5240995.01118797 433125.470673771 5241046.69273617 433202.41072646 5241106.75159756 433240.598761453 5241113.87498056 433276.00495307 5241103.3111239 433306.191943067 5241080.06008524 433315.721542831 5241026.62263938 433279.719955761 5240986.37444233 433233.624954605 5240959.00155092 433215.624161483 5240938.87745283 433207.497706383 5240895.8156422 433217.403375183 5240875.37790742 433237.433954787 5240849.68980265 433270.152296439 5240829.00113802 433473.153172742 5240806.24303517 433486.926229535 5240806.70438945 433640.87343626 5240811.86113884 433657.21633902 5240781.67321963 433662.496730744 5240753.86073263 433659.526597813 5240711.86119926 433670.150897073 5240687.61096449 433717.651350201 5240689.98400406 433749.152401172 5240714.73251384 433767.184370929 5240732.54413103 433770.87227664 5240744.16888502 433780.873280974 5240772.73074225 433783.030159372 5240791.60549936 433787.468880752 5240828.23001772 433788.595162866 5240867.54214931 433788.689670627 5240890.91695373 433777.253065306 5240921.3546709 433773.879200159 5240957.22951423 433771.317637024 5240986.79187616 433771.694554536 5241045.91637549 433768.320658869 5241080.85372631 433776.540284025 5241105.8531858 433789.260495716 5241147.85232229 433806.417399061 5241163.78899188 433828.855250641 5241169.10053339 433860.011363253 5241157.16186084 433886.292540027 5241148.41086085 433896.979315517 5241123.41062978 433903.134598141 5241092.03563562 433935.976173921 5241016.84741113 433945.630440891 5240953.28503696 433961.503825146 5240899.53482843 433965.7832798 5240843.09761488 433974.594196579 5240792.0976717 433976.03087931 5240766.53532179 433977.09276369 5240747.28543562 433970.685162101 5240707.16102505 433971.496766906 5240679.348719 433983.996025023 5240653.41092003 434015.214438556 5240635.40979117 434043.902248747 5240637.97109793 434075.277785002 5240646.84474346 434112.09118276 5240665.53058703 434148.905043138 5240698.46631491 434180.906698373 5240741.65215643 434195.719971089 5240761.8388873 434211.971868986 5240816.3377807 434220.19193392 5240854.83713223 434222.067557409 5240873.5869033 434241.006222484 5240904.83587636 434252.881785709 5240919.27277439 434298.412807851 5240901.0835637 434323.380344057 5240857.58289734 434388.252207605 5240745.14365928 434428.563939087 5240711.64228378 434598.533568062 5240697.19795746 434621.345994915 5240689.38458853 434636.37661395 5240666.32166018 434641.000410428 5240628.19677809 434630.687253396 5240610.50984184 434559.24830167 5240583.26298071 434541.028096777 5240542.95155038 434553.558695938 5240519.88872408 434596.589940439 5240509.26205056 434795.029932381 5240537.62871093 434833.123973468 5240537.31465642 434839.40907487 5240654.06346419 434822.474092101 5240735.50100316 434765.007717438 5240822.50265152 434684.164755862 5240866.50559792 434494.102128314 5240909.13801159 434456.290411626 5240942.5142849 434404.325310105 5241067.57789284 434372.140203973 5241149.20354399 434372.51627875 5241182.20326118 434387.891974371 5241199.82749155 434517.549547792 5241208.57213582 434540.330645197 5241198.25879058 434583.205149595 5241172.44475129 434661.54834205 5241136.0043512 434841.078404615 5241055.37267875 434894.046485081 5241021.80828753 434932.171858896 5241023.93171551 434955.423032129 5241054.24302467 434951.238314312 5241140.68000359 434936.333023844 5241173.805346 434822.677966645 5241238.43445985 434759.459640864 5241267.06180588 434752.085328024 5241289.99942189 434821.055931976 5241329.93379125 434958.401236139 5241343.74058618 434981.182331396 5241333.36474135 435027.739890408 5241170.2391488 435049.674745139 5241083.67644605 435074.406137693 5241052.36388019 435102.297994234 5241017.04983175 435147.797597646 5240993.73566177 435208.672816838 5240985.54574391 435297.673829562 5240994.79204024 435348.580798414 5241004.3523881 435427.237401503 5240995.911747 435459.73607311 5240947.28580622 435461.577682184 5240881.2862531 435417.605940684 5240800.4136875 435360.978188456 5240729.91655763 435335.070249373 5240684.48047569 435308.879979266 5240605.98216783 435318.252560504 5240529.60739034 435327.970144866 5240491.54479481 435357.874794744 5240435.29401785 435416.061988824 5240411.85432427 435672.595260259 5240411.71883674 435733.783971351 5240433.96616044 435754.472706267 5240466.71505769 435761.322074096 5240636.77594295 435792.229890398 5240677.14936381 435830.700095411 5240712.27251749 435848.575562725 5240722.20920977 435868.482063045 5240725.02087502 435932.514118905 5240734.08068995 435986.07760781 5240751.265869 436077.421720139 5240740.1372271 436110.045804047 5240704.26117487 436119.763381843 5240666.13607507 436098.322137513 5240557.07530029 436002.126920508 5240344.76838717 435919.183471615 5240183.08554247 435900.430334234 5240091.77452353 435909.802908791 5240015.462236 435932.364580498 5239984.77405167 435998.239740005 5239973.89643851 436130.522482608 5239987.82841245 436216.866962218 5239989.44986387 436282.491116767 5239948.00999744 436310.13607359 5239900.15144092 436310.146012239 5239900.13423528 436314.927028895 5239891.88410326 436308.422644324 5239759.82289152 436261.512212425 5239643.51321499 436337.10443938 5239579.19811188 436537.229423017 5239531.37777043 436583.230599633 5239556.31319154 436624.984416431 5239662.56066302 436663.862125178 5239735.74600741 436681.68475947 5239744.44308314 436776.177303905 5239790.55348417 436842.271794076 5239797.36322366 436867.584065984 5239784.42478527 437085.521855142 5239741.54118056 437125.676814098 5239692.85240449 437094.298736023 5239606.85434395 437073.264902961 5239533.41826443 437080.231693169 5239472.29344289 437110.481250245 5239451.72985777 437186.731983737 5239456.03919625 437365.047397084 5239502.40652987 437425.860012499 5239491.5916167 437468.57765199 5239447.9026931 437475.544444263 5239386.96536572 437482.542480397 5239325.84053824 437522.697435373 5239277.21425514 437560.666045375 5239264.08779469 437580.197312131 5239260.02452319 437610.416718976 5239272.83568628 437621.292480367 5239293.33508607 437622.324774962 5239324.70980852 437611.700991516 5239364.02244985 437455.494870464 5239783.27570405 437443.215267497 5239836.08830908 437445.123244434 5239887.96283987 437450.342641733 5239906.3374876 437450.347889116 5239906.35599495 437456.030848428 5239926.39960345 437474.062978259 5239948.7736965 437517.063781731 5239962.89682964 437555.595300937 5239961.89525972 437583.282601181 5239949.26922112 437606.500821088 5239927.70593253 437619.248859425 5239909.45763575 437619.250318217 5239909.45554755 437629.656158395 5239894.58023312 437675.998165075 5239830.82881344 437696.497377478 5239802.14068875 437705.340308494 5239775.26552782 437708.870553345 5239744.01561725 437710.494056127 5239698.32839287 437698.585230546 5239623.20444359 437674.799156616 5239482.83147037 437670.984439789 5239416.6446226 437662.669450621 5239343.27051337 437654.4491004 5239296.77119908 437657.073587843 5239280.64621209 437658.728630001 5239243.70892073 437677.291149487 5239239.95818656 437712.13297461 5239173.58225214 437731.097668167 5239046.45742307 437755.845748605 5238982.64438241 437793.156087948 5238908.64340053 437843.718200552 5238885.20399595 437965.750597553 5238891.5739302 438004.252138613 5238929.19706778 438040.724101232 5239017.75741157 438090.134415949 5239129.0045567 438136.668534147 5239204.75208445 438170.013539817 5239234.87549231 438163.046756841 5239295.87532698 438115.204168358 5239342.12694817 438100.831669138 5239421.00195332 438131.488734614 5239438.43806637 438184.801629892 5239437.87338346 438214.676698245 5239432.93469441 438283.739359472 5239421.61944476 438296.994445698 5239415.5557913 438329.239022643 5239400.80523163 438437.298788852 5239293.11409011 438452.047293976 5239244.61384118 438433.482131179 5239168.67766156 438514.481798405 5239139.79954699 438549.480454447 5239091.17346592 438673.252324028 5238780.04565372 438695.782471667 5238741.67000697 438751.657965869 5238743.66769376 438784.783713906 5238758.54122276 438833.692179504 5238813.91380826 438839.538503137 5238889.9755147 438810.699777323 5239047.78805148 438786.735412326 5239185.28803407 438767.175213891 5239259.10079892 438724.332162124 5239290.10233117 438564.958089619 5239355.233395 438519.928529332 5239416.67229178 438429.524979497 5239519.23774584 438377.589883729 5239603.92675149 438374.590019929 5239608.73933899 438357.561167422 5239685.05197432 438373.187377406 5239717.8635921 438429.344976154 5239745.29858925 438556.440012263 5239754.10581809 438815.34760613 5239733.59536249 438891.316162765 5239709.90492309 438926.220649085 5239648.65393875 438914.559412155 5239501.40548772 438908.525245354 5239415.09386287 438940.741618406 5239336.0931154 438988.835302735 5239322.90373775 439062.711437133 5239339.77558419 439129.589808234 5239425.45972052 439210.252749671 5239607.58009717 439292.22414004 5239667.638805 439376.382288985 5239704.88508916 439465.414627068 5239716.63135797 439513.664902466 5239713.56690371 439536.414736543 5239703.25354585 439593.755440673 5239598.50194687 439638.878740756 5239537.00053739 439674.25358268 5239523.99918029 439705.004656862 5239548.99774147 439830.69699692 5239664.55426803 439885.716561564 5239709.61218704 439956.232664447 5239767.3608965 440088.641011908 5239799.04275131 440139.359885916 5239790.85323295 440189.984756065 5239775.10127166 440487.856115501 5239596.71532639 440538.700415786 5239601.27571161 440577.107973763 5239631.33642834 440610.985784719 5239707.27201084 440651.956115299 5239744.83257141 440690.175582139 5239757.26842014 440718.23854545 5239764.51722091 440761.301026818 5239753.89053208 440824.519400125 5239727.88812473 440924.013321674 5239523.63546545 440986.260127313 5239414.07117183 441003.852972908 5239383.07066466 441036.633871203 5239365.00694531 441173.979066398 5239376.18873734 441291.04337579 5239402.8712553 441354.794450956 5239420.05602454 441392.825726046 5239411.99202088 441440.731307861 5239381.05276855 441491.136818155 5239347.42593154 441493.574229786 5239344.23835334 441493.587389503 5239344.22123925 441508.761182833 5239324.48786526 441518.510056681 5239288.8002086 441571.289899878 5239234.86091105 441581.226790564 5239214.48564198 441585.913042356 5239176.36070888 441579.036780257 5239140.48623483 441575.129828213 5239120.54903067 441546.345628468 5239039.61326235 441530.123504235 5238943.17708428 441511.37028775 5238851.99097485 441507.710331387 5238742.80436791 441501.707377636 5238656.49270168 441493.549271239 5238603.24339929 441476.33205697 5238583.62189494 441476.329728245 5238583.61924102 441458.985180196 5238563.87008886 441429.29631842 5238530.18403958 441396.076642976 5238510.24804221 441332.701606564 5238523.56305899 441281.202243367 5238554.18996856 441206.484416552 5238598.63023806 441057.298043148 5238666.13591042 440786.235695324 5238732.58409754 440656.829091591 5238751.65178565 440587.983901285 5238724.46730539 440544.325799127 5238679.21941592 440515.761043529 5238618.47101433 440479.508738079 5238557.97292788 440452.754029706 5238423.59996689 440496.125317121 5238302.80786469 440509.530410747 5238265.47373108 440546.684033701 5238178.72280403 440535.775152283 5238102.72378253 440465.895558396 5237981.47750861 440440.175602292 5237951.29128005 440424.893899722 5237941.22948069 440345.171513987 5237850.67090272 440336.919410036 5237789.73416911 440356.949868082 5237761.60853853 440384.69947114 5237743.54501877 440476.137710158 5237745.10373216 440613.796650775 5237794.47270553 440687.672693014 5237808.96955544 440763.735481931 5237800.52897406 440788.89097666 5237772.40312995 440810.292601431 5237629.9032299 440819.633772036 5237551.02838808 440871.316520024 5237398.08980561 440940.623532631 5237219.46316716 440970.183512161 5237137.96250331 441047.899395154 5237035.58498744 441135.08212044 5236874.51997715 441192.234670401 5236752.08094346 441214.451439632 5236688.39295611 441221.574781394 5236665.73814057 441285.788072267 5236461.51653938 441289.722091617 5236357.32958354 441261.282853973 5236311.89357319 441220.343959355 5236279.33299498 441062.560589792 5236250.46474664 440986.215969461 5236241.09298271 440924.933185458 5236208.72075081 440741.335777967 5236139.54135676 440715.647163772 5236111.91761485 440723.209458194 5236104.16735379 440672.333934418 5236099.54450094 440641.018489675 5236018.6088612 440630.172535218 5235955.29724899 440644.732999327 5235891.54708265 440669.669049976 5235843.04637898 440644.043191708 5235822.98508389 440658.729086492 5235772.04732342 440662.725529522 5235665.29789207 440623.283412227 5235536.2379243 440584.280417695 5235455.3651075 440575.495354601 5235343.67874378 440625.116849115 5235228.80246467 440702.425348697 5235093.42516809 440714.658382803 5235063.58900382 440714.674431357 5235063.54986167 440722.298861412 5235044.98717064 440724.516683928 5235016.92477053 440706.359116846 5234981.55077171 440642.85860784 5234979.74093689 440546.702907181 5235016.30720196 440484.297972655 5235068.62194755 440484.263266197 5235068.65108297 440405.67463157 5235134.62477446 440365.300209635 5235160.37628181 440324.957127734 5235188.81526885 440284.519951066 5235207.00433058 440208.237848106 5235197.69507939 440159.517234211 5235152.38492862 440161.735149471 5235127.01001267 440187.014841593 5235075.19681752 440187.022127705 5235075.18185581 440213.981925731 5235019.82107614 440306.697122824 5234894.38057269 440379.632892236 5234827.50298701 440470.412787053 5234768.12460166 440533.631107711 5234742.12213731 440571.442747795 5234708.6207866 440680.035343596 5234651.61663597 440747.75181527 5234569.73936387 440772.531006692 5234503.36378106 440718.215156819 5234414.99165994 440669.494548843 5234369.8065099 440572.962490945 5234365.74808085 440395.368248681 5234387.88036666 440258.148422701 5234384.26113899 440207.21024784 5234374.70083887 440158.583734338 5234339.64061923 440122.29985871 5234268.8301315 440119.173049981 5234215.51813306 440090.670904486 5234157.39473195 440074.138911785 5234138.6455555 440057.231910311 5234119.70889619 440001.262363279 5234107.46132857 439930.450422999 5234138.77657961 439849.71068062 5234198.21055297 439849.701854857 5234198.21704977 439695.985829721 5234311.47269851 439632.391316819 5234301.85043114 439591.201679903 5234246.4775473 439577.667707645 5234167.85366846 439576.006009139 5234005.22988334 439578.035745568 5233959.54261979 439546.751743926 5233883.66946714 439535.469896253 5233868.1075504 439520.969136584 5233848.35829837 439369.61973713 5233710.30312965 439200.363211198 5233549.43638284 439160.610433611 5233474.3135878 439153.066707842 5233460.85403865 439083.792839363 5233337.25529365 439056.164919099 5233255.31953942 439041.192180802 5233161.75846476 439086.493357043 5232881.88395102 439135.611899983 5232718.75830086 439126.637497383 5232584.25982799 439087.351361412 5232472.88740837 438992.001659106 5232344.39243787 438968.875465424 5232319.20610378 438833.747659715 5232272.33706153 438805.809995006 5232272.65070901 438735.186365234 5232316.59075578 438697.218125769 5232334.77967178 438581.50288598 5232437.59611368 438548.597067155 5232453.1598485 438515.283108483 5232423.03646631 438507.281591136 5232387.53708028 438580.865386734 5232135.2860753 438638.801335452 5232088.97157379 438762.643389194 5232029.27948903 438818.142025621 5231988.0275591 438848.360110935 5231967.46399434 438875.325116093 5231873.15117868 438873.841266481 5231851.6369036 438873.355169078 5231844.58899715 438869.352748842 5231786.83964154 438848.694907786 5231751.52827589 438696.03694936 5231732.78463683 438675.661519899 5231725.4105251 438647.284570385 5231682.47452698 438638.686987563 5231591.1006173 438672.64951322 5231435.78800661 438720.084119182 5231359.09922028 438780.864757263 5231335.65946491 438821.396122206 5231332.65785774 438913.022363814 5231349.52902715 438978.929458025 5231360.46378004 438984.304531395 5231361.46355502 439114.338608571 5231410.89539182 439185.652136542 5231425.39238962 439248.117312359 5231330.70319233 439257.990989991 5231297.57808319 439275.145003773 5231241.51538211 439297.016099857 5231144.82784887 439305.697711813 5231002.4537472 439260.376607367 5230802.33230114 439216.184637924 5230701.0849359 439225.713398765 5230640.08508735 439245.430025552 5230586.52227234 439441.359505498 5230368.57895915 439466.16989883 5230314.95346074 439468.261750086 5230269.2662857 439438.739566986 5230181.57815323 439434.132329078 5230167.89352542 439425.225553461 5230156.4564756 439408.443325912 5230135.20732065 439382.095837913 5230049.08411184 439406.905915137 5229987.95868446 439500.059319369 5229908.20576649 439625.679705032 5229782.38951951 439670.833827792 5229726.07578102 439678.427328598 5229719.20054957 439731.769341654 5229671.26142325 439731.775551865 5229671.25583629 439776.580378828 5229630.94756117 439951.674516426 5229618.94090755 440225.015363138 5229517.11882869 440336.264049925 5229472.73997381 440452.637757724 5229428.36093118 440523.417927887 5229394.48354551 440543.510915306 5229374.10797608 440619.008348185 5229304.66827219 440653.786417605 5229225.60523348 440688.250898201 5229120.97996977 440778.277048724 5228990.60286 440792.899522296 5228929.47792629 440774.490707801 5228871.16671833 440704.798275231 5228762.73295662 440707.0783475 5228734.73315326 440724.577452884 5228711.73272466 440938.07878393 5228719.59957889 440982.609893299 5228711.41048132 441011.578557547 5228706.22194098 441128.485624857 5228712.59245844 441166.705078667 5228724.90338483 441182.331551983 5228757.71494788 441137.30314561 5228829.34089773 441125.337268149 5228898.02812966 441121.404298563 5229004.71465878 441157.626134058 5229072.96256135 441216.34623029 5229097.83505936 441307.815379263 5229096.76908142 441335.408165425 5229071.08080381 441362.309971006 5228964.08092637 441369.464518175 5228923.45609055 441377.339160205 5228914.20589085 441375.884759661 5228519.21018982 441365.863750525 5227298.78616829 441362.816500156 5226925.22778895 441353.32899797 5226487.98282069 441334.385239866 5225613.43036079 441330.001586979 5225411.68267304 441327.747107756 5225307.24636884 441305.316984763 5224021.76087509 441299.678154161 5223699.26450647 441286.810453585 5222411.9036632 441283.609245141 5222092.28217366 441270.835642402 5220813.67119782 441267.540172935 5220482.29982725 441265.859079109 5219175.40754827 441265.471236449 5218876.31699548 441267.821811269 5217580.29948915 441268.401594674 5217255.3341868 441258.191667242 5216733.34001911 441237.333320755 5215666.35190995 441227.842303915 5215148.2014038 441208.265160845 5214080.36946304 441195.274251281 5213564.59398568 441168.196807764 5212489.38722958 441156.02005255 5212012.08004007 441127.127687256 5210880.40508843 441117.388581936 5210406.78527438 441094.058619425 5209273.42265027 441092.101754418 5208823.73991009 441086.988839287 5207653.43979129 441092.937830809 5207196.00699117 441107.919134768 5206040.4563889 441099.180074391 5205568.61773998 441076.86011304 5204365.48110994 441068.033916685 5203923.5198378 441044.810329775 5202759.50826854 441038.390380076 5202318.23443591 441022.763161913 5201240.53378684 441015.248841091 5200779.38528998 440996.713401008 5199638.56070505 440997.788580086 5199042.66427922 440999.66263242 5198009.587543 440997.677376318 5197479.59631226 440993.611925358 5196381.61446136 440987.346268008 5195878.46659537 440973.561784197 5194770.64128997 440965.045984715 5194262.9622736 440946.511668596 5193160.66818059 440937.027880396 5192677.64501441 440915.462465655 5191580.69461056 440913.290734644 5191084.45276957 440908.411922532 5189960.72122732 440898.739585907 5189444.7298283 440878.361997923 5188359.74790141 440868.844368726 5187794.75728581 440851.311907451 5186754.77454703 440840.168994679 5186181.03408972 440820.262004985 5185156.80111335 440808.556140411 5184569.02963089 440788.211689919 5183546.82785545 440447.274474624 5183551.58421118 439133.213072692 5183569.8587156 437519.214606452 5183597.88873491 435909.216377732 5183632.91857415 434321.217792016 5183656.94819719 432729.219448619 5183687.97779001 431126.220916499 5183713.00771019 429532.222317095 5183736.03751201 427926.224039936 5183768.06739585 426250.225657675 5183796.09869613 424640.227328401 5183826.1287231 423021.215323013 5183838.14759326 421418.182848745 5183803.15020699 419845.153118906 5183829.1516743 418239.122759583 5183856.15320425 416630.092083367 5183876.15490039 415034.06331545 5183946.15575987 413468.035170976 5184019.156598 411927.0077774 5184102.15730687 410320.977603268 5184140.15890349 408731.947575327 5184173.16060055 407127.917199638 5184205.16237558 405509.88661979 5184240.16416644 403893.850467498 5184279.17067505 402376.809351054 5184305.18266293 400767.765827735 5184336.19538155 399155.722151603 5184365.20819777 397568.67961072 5184411.22069788 397484.635123672 5182839.23587902 397438.590081989 5181207.25121208 397410.545932918 5179591.26622548 397351.500174909 5177964.28589945 397292.452470757 5176353.32576343 397156.403121981 5174745.3656852 397136.356979965 5173154.40478628 397080.309523306 5171545.44435402 397070.262855338 5169930.48393691 397074.216493664 5168318.52340502 397059.169441951 5166697.56308368 397026.153268514 5165076.32148286 397524.818123527 5165067.79049237 398121.172223473 5165059.66575611 398079.094836043 5163519.64134919 398074.045935741 5161865.68223921 398059.997632782 5160238.72242226 398075.949416946 5158601.76287673 398049.901485214 5156996.80243326 398044.852873508 5155360.84277007 398061.802940095 5153673.8844116 397990.753525199 5152039.92440306 397986.706260507 5150439.96320876 397981.694931268 5148843.95455868 397971.683228179 5147199.94555985 397972.671962545 5145598.93676736 397962.660579673 5143995.92785993 397947.649143106 5142391.91887313 397932.637595763 5140770.90973277 397907.625956819 5139153.90054444 397871.614199177 5137540.89132351 397847.602616648 5135930.88208476 397841.591240943 5134313.87274973 397844.579951222 5132687.86328606 397831.568827347 5131116.8540907 397799.55716051 5129508.84465574 397772.545330568 5127866.83496574 397769.602433453 5127095.8616232 397766.539781408 5127081.11154329 397761.664540702 5127057.83016732 397741.664049093 5127033.83007812 397721.601028402 5127005.82996553 397703.850524161 5126974.8298291 397690.850103905 5126944.82968593 397670.912112201 5126920.82959777 397657.786647643 5126884.82941976 397649.473768279 5126849.82923463 397645.004726745 5126818.4540605 397643.3483687 5126806.828996 397635.035482062 5126770.82880521 397628.847581176 5126727.82856701 397627.534752913 5126683.82830922 397618.971812944 5126640.82807793 397612.783911683 5126597.82784006 397604.4710243 5126561.82764997 397591.595617786 5126533.82752065 397578.407636095 5126495.82733311 397565.46972113 5126466.82719851 397545.344180905 5126436.82707907 397527.781224448 5126412.82698805 397507.593182574 5126382.82686947 397494.655252618 5126351.82672409 397474.529718163 5126322.82661191 397471.34202389 5126302.60775191 397468.529352856 5126284.82640523 397460.091433225 5126244.8261941 397454.091060634 5126205.82598176 397445.590639645 5126165.82577112 397444.027755832 5126114.82547489 397438.089904983 5126078.82528037 397425.151973375 5126047.82513668 397397.963862016 5126024.82508369 397373.463344054 5126008.82506407 397344.087731071 5125990.82504784 397305.337011941 5125979.82510165 397269.086369297 5125973.82517735 397233.335833894 5125981.82533342 397202.647953329 5125999.82553214 397179.272708267 5126019.82571988 397160.553757661 5126035.20086627 397148.834882151 5126044.82595783 397132.772294143 5126069.82615172 397121.772332701 5126100.82636484 397103.334705913 5126125.82656536 397092.459782577 5126161.82680651 397081.647381872 5126200.82706453 397075.835099479 5126244.82733626 397072.147795239 5126280.82755525 397067.835406618 5126306.42146587 397066.08545198 5126316.82778114 397062.648201959 5126359.82803953 397056.585866089 5126396.82827085 397045.710944138 5126432.82851025 397027.460872742 5126464.82874777 397016.460920688 5126496.82896388 396993.21071066 5126520.82916915 396969.772954926 5126538.82934018 396939.022558013 5126553.8295148 396898.396942019 5126560.82967184 396855.458795444 5126568.82984108 396819.083119819 5126557.82988318 396792.082547279 5126539.82985873 396774.519586055 5126515.82977324 396754.581592814 5126492.82970056 396734.393537423 5126461.82958359 396716.643028971 5126431.82946552 396696.454972903 5126400.82934927 396683.579551284 5126371.82922318 396670.579120159 5126341.82909202 396659.078702435 5126310.297698 396644.515705503 5126274.82879108 396631.390228143 5126238.82862717 396618.389788858 5126207.82849133 396605.264318258 5126172.82833358 396596.701364704 5126129.82811725 396590.826006225 5126093.82793236 396582.263052331 5126050.82771637 396576.075137571 5126007.82749328 396574.949857411 5125971.82729413 396573.637016015 5125927.82705053 396577.261814638 5125891.82683664 396595.511885163 5125859.8265997 396606.574358413 5125830.8264017 396629.824563343 5125805.82618797 396647.319162537 5125787.41633249 396496.946542206 5125694.16972709 396265.286206196 5125662.98278777 396160.816273646 5125738.57728593 396134.753495823 5125759.67123408 396052.504443825 5125823.62741535 396003.377069077 5125861.82845485 395945.971110523 5126029.07954184 395968.784521861 5126100.82986161 396043.817816002 5126209.1427239 396069.754253405 5126270.44142693 396082.850393495 5126301.39311046 396095.748378117 5126315.60244372 396095.756961454 5126315.61189973 396148.758271506 5126374.73706626 396293.917828993 5126499.7373284 396410.233127903 5126621.23766537 396495.391869976 5126771.61326048 396477.236287709 5126903.7390479 396447.01740699 5126953.27065725 396386.798790024 5127105.33416577 396321.236427432 5127269.05399634 396229.298063942 5127353.99220683 396131.015871768 5127441.55544318 396115.829386175 5127462.17909169 396115.828279149 5127462.18059506 396066.015476462 5127529.80609163 395983.734586901 5127756.49502677 395923.733826088 5127783.74532406 395777.326113984 5127902.27757212 395777.308245804 5127902.29204828 395726.294356848 5127943.62166756 395549.292459624 5128067.5602533 395353.352636097 5128173.62377797 395211.19494155 5128281.09341984 395079.411735468 5128299.68757608 394960.878470623 5128283.28152324 394781.906211452 5128198.87527613 394617.215350449 5128105.37520948 394538.216159199 5128051.72570248 394430.805121636 5127978.78129481 394333.866057581 5127977.43777842 394248.209101525 5128061.40714611 394197.834475444 5128209.75173291 394146.054233813 5128439.94045916 394112.617113715 5128554.12858191 394090.929403945 5128570.94121182 394060.054237649 5128611.37897475 393913.240703544 5128772.19256588 393830.17833932 5128951.81859017 393716.803734575 5129221.19508348 393649.741102212 5129334.41449471 393593.271673627 5129359.63347651 393541.208155385 5129334.6334693 393522.332596165 5129302.28961079 393502.519354101 5129249.38316098 393485.268439118 5129170.44533793 393460.892125407 5129056.50737175 393434.734730461 5128966.81952098 393406.827666262 5128921.06937453 393281.887002488 5128775.88149651 393162.478318341 5128709.72521971 393074.570595567 5128699.94412585 392948.131162291 5128708.25694998 392938.886078307 5128717.09598999 392938.881089356 5128717.10075982 392869.349294331 5128783.78870889 392856.131338188 5128904.03926276 392869.788619186 5129001.85215899 392921.040097872 5129082.50864999 392939.594223998 5129096.3771071 392939.603005278 5129096.38367075 393010.885818893 5129149.72750229 393111.387893415 5129209.66505377 393203.984079088 5129328.85288977 393215.891632466 5129464.35346913 393173.016630795 5129545.26016531 393150.858439436 5129570.56502282 393036.140792715 5129701.57362622 393002.98422843 5129725.82379725 392941.396243187 5129736.47843803 392903.451574447 5129743.04281602 392753.699271544 5129746.01187008 392503.539385536 5129775.94998378 392399.632345048 5129873.1693424 392239.412465554 5130032.26405602 392210.100676357 5130168.70217224 392213.070651679 5130306.92148529 392219.540503596 5130424.39070673 392209.916467398 5130554.61000795 392149.072499686 5130638.14170229 392048.790525459 5130732.51725212 391875.069984154 5130832.39293655 391663.504815478 5130896.51853027 391580.222853181 5130960.33141186 391436.940407299 5131072.70707042 391358.345878462 5131119.9261223 391358.337790057 5131119.93098495 391332.095618879 5131135.70747265 391169.843461014 5131170.05160012 391090.329432917 5131198.60780057 391090.311258207 5131198.61432773 391004.028975747 5131229.58332307 390870.621635629 5131333.89640539 390701.182026774 5131384.3968375 390459.210143678 5131442.20989569 390404.616155957 5131506.96020143 390404.773253846 5131600.33552766 390419.305721358 5131710.67964326 390412.243757333 5131781.58615058 390338.024937405 5131896.52414872 390204.523538589 5131962.2745484 390046.80271229 5131993.02485559 389913.988072682 5131976.18122009 389735.78932966 5131895.87789917 389735.42215901 5131895.71243772 389716.515360771 5131867.05611908 389571.981062729 5131772.08725552 389506.51136487 5131775.83735682 389479.604770387 5131782.21241387 389234.03940457 5131869.58802097 389096.006383826 5131901.213303 388922.035336683 5131933.83863323 388773.189300139 5131927.77631271 388634.030436623 5131872.40133634 388526.340893101 5131827.68260284 388437.463981855 5131767.6200527 388351.21178844 5131674.49490861 388256.834163314 5131549.83844281 388149.08215691 5131510.58849153 388127.769379886 5131515.21353581 388127.399562769 5131515.29264081 388069.331118797 5131527.71365645 388022.768344655 5131571.80759559 387956.643615577 5131701.96429489 387902.206568144 5131832.24597249 387809.018355722 5131902.40253741 387683.516554347 5131910.62147954 387590.171097294 5131879.4340258 387503.856283962 5131776.34013029 387426.478629891 5131625.71485673 387356.320156636 5131508.18341269 387263.786609173 5131417.74582555 387182.780887846 5131291.45026806 387182.409113164 5131290.87063628 387177.44021241 5131283.30812538 387127.000702834 5131158.62039828 387071.99810947 5130982.80755732 387039.590880763 5130934.40124346 386913.932180852 5130881.58882868 386890.025426821 5130867.80758648 386778.398073713 5130803.74512643 386670.708572628 5130768.96398226 386582.706761838 5130723.37028123 386497.674054816 5130708.37039707 386497.663885286 5130708.36860975 386492.517716472 5130707.46415414 386475.986184474 5130704.68292709 386341.452834485 5130701.27690786 386253.63935409 5130737.27714263 386147.951236715 5130835.27754052 386056.543827963 5130858.77774916 385983.85493916 5130831.99656867 385948.760142974 5130782.65277654 385908.258559579 5130689.3714036 385903.444393696 5130535.05859079 385896.787461117 5130478.83973587 385888.9116599 5130412.96461326 385852.847603138 5130316.15198014 385777.314182535 5130219.30817553 385722.469283381 5130190.43322317 385648.123974982 5130151.37078959 385475.682733631 5130049.2459285 385294.460745839 5130009.18371524 385092.770554928 5130051.68420095 384884.862006922 5130139.96602552 384880.021818156 5130140.61623874 384702.015678741 5130164.52893091 384570.919338906 5130112.6541042 384489.198661461 5130051.27916677 384432.354144517 5130014.24695822 384365.384582075 5129979.05834044 384256.071374883 5129978.46283999 384095.632846489 5129978.49152223 383967.631733082 5129951.80193996 383901.537153416 5129914.83208574 383870.442760021 5129874.39403732 383834.973140548 5129815.95589644 383818.316026528 5129747.01804328 383817.347899687 5129745.05059834 383817.347248667 5129745.04927532 383794.44034032 5129698.54885066 383712.031781964 5129536.95358107 383616.686453127 5129449.63944961 383467.309981205 5129404.13700936 383343.559376889 5129422.29130741 383185.264346579 5129474.58983867 383172.933891244 5129478.66365389 382432.112672226 5129129.30767849 382050.545617803 5128946.48889483 381930.669198259 5128890.45567463 381813.761564185 5128836.01625451 381555.44536519 5128886.57970874 381368.697109312 5128923.13427606 381021.946477756 5129068.91016897 380846.041160551 5129252.40756313 380614.072408873 5129385.43525726 380507.415444003 5129383.96480723 380366.976564238 5129343.80628053 380170.662848542 5129349.99066149 380077.944277665 5129418.39550277 380040.790213423 5129629.4263673 379955.47919401 5129806.17517836 379954.121354302 5129807.34346081 379915.854329741 5129840.26832905 379915.841474504 5129840.2793996 379794.292249493 5129944.95398924 379279.665993473 5130123.85218926 378897.416206212 5130353.6275367 378366.6809587 5130916.98226256 378366.669410609 5130916.9945204 378237.170204929 5131054.46130696 377947.108891135 5131310.67560811 377506.601105877 5131497.25225083 377506.577075931 5131497.26242869 377469.077028666 5131513.13683829 377272.357976651 5131591.66498638 377034.074980805 5131570.78614464 376768.355508367 5131649.93818213 376762.104174374 5131658.76955849 376695.137538811 5131753.37457609 376657.888268789 5131833.68653146 376593.7950704 5131913.02930396 376523.576565284 5131969.90321229 376404.419467585 5131961.21379023 376265.792989486 5131910.33652847 376138.384541883 5131794.20940704 376002.693305361 5131555.42582811 375983.661649708 5131533.08106143 375893.25356053 5131426.92399242 375744.783231971 5131374.14032947 375599.438955512 5131406.57551903 375531.627207405 5131503.76198948 375519.971366165 5131543.44932595 375519.969779084 5131543.45472667 375497.784644065 5131618.94901437 375472.066917037 5131716.38615851 375393.12918816 5131738.35365392 375292.127979765 5131691.28950564 375215.439271748 5131631.81949125 375151.469708879 5131598.25594608 375151.466609136 5131598.2543156 375141.2508288 5131592.88077914 375081.032066892 5131623.00482986 375032.908051499 5131728.37911571 374983.628283286 5131874.87840432 374901.879817448 5132042.06468055 374671.819852731 5132365.71739828 374385.573430713 5132800.46300037 374334.449073106 5132878.08721254 374251.043722939 5132992.52342011 374211.887897763 5133046.36656284 374110.638995748 5133185.33374073 374110.628800055 5133185.34772794 374100.639104321 5133199.05233533 374058.889312703 5133236.48917747 374004.170838717 5133285.73831497 373785.326565466 5133350.95355605 373598.668780583 5133318.79427626 373493.324466251 5133324.98007656 373445.043516532 5133372.69806519 373307.606872866 5133508.38339578 372977.297673735 5133932.09695315 372790.173713299 5134104.59397872 372790.170162929 5134104.59724814 372775.955042474 5134117.68750249 372616.612187284 5134264.74746524 372415.738702513 5134480.15052 372296.050727994 5134498.89858207 372182.611876215 5134445.24047566 372110.235077686 5134337.05177184 372038.734154073 5134297.76935155 371981.640729843 5134350.42468931 371910.20526255 5134544.45482948 371871.615119463 5134847.01677682 371871.613784306 5134847.02728489 371870.177754423 5134858.32925617 371825.681054914 5135139.17234848 371732.870849389 5135362.63963708 371632.871459507 5135456.4505272 371498.902091211 5135469.07334565 371358.618872436 5135378.66479156 371231.74097487 5135209.69394335 371179.165366849 5134977.74499291 371171.737240818 5134944.97416816 371149.550387032 5134864.23037611 371149.54857798 5134864.22379249 371102.921133998 5134694.62925355 371045.605330146 5134462.97203032 370950.884457963 5134341.37672201 370801.727018197 5134318.18680016 370567.694307639 5134313.58925654 370355.194118364 5134397.67957449 370170.318219683 5134413.73907981 370049.723713777 5134411.08087486 369743.345798776 5134327.79465235 369517.516662406 5134301.45274707 369360.186666137 5134283.1009439 369208.373999229 5134340.25473874 368975.278848685 5134340.25096428 368826.122522064 5134402.81105038 368532.309491415 5134496.65004185 368175.933545762 5134586.92551616 368028.589043977 5134596.79812841 367916.025289972 5134552.98380722 367905.228118526 5134542.16171798 367821.367215384 5134458.10728 367710.61665657 5134466.16798652 367475.710658418 5134591.3204227 367345.462794344 5134810.38079058 367239.401311117 5134934.12905694 367239.398405859 5134934.1324489 367221.307735114 5134955.25376096 367124.0914264 5135181.47090497 367082.156269516 5135375.50144765 366884.034768684 5135724.18567314 366793.943845536 5135974.49666413 366778.853974814 5136270.5276158 366807.978677004 5136463.10776126 366809.450611755 5136472.84057867 366824.57760034 5136614.80954984 366821.144583642 5136950.93443061 366845.334161347 5137095.80979895 366875.554018653 5137165.74778068 366875.804959058 5137235.8727713 366886.212501567 5137328.0291741 366923.08862478 5137396.46726575 366947.058138981 5137443.53015 366943.46508978 5137497.40508064 366978.653845522 5137576.56189309 367025.780404329 5137673.46889857 367073.093865672 5137725.68841608 367104.875728692 5137758.34518228 367121.626369416 5137799.34544999 367102.002053342 5137858.68886621 367050.877367345 5137903.3755169 366984.940474588 5137976.06191797 366918.191126759 5138052.34205411 366879.389001928 5138103.86746532 366856.816879829 5138133.84102677 366808.567344957 5138188.37147059 366781.879859463 5138200.4022785 366723.879623085 5138206.55757204 366647.597692618 5138187.11882044 366589.003223451 5138157.58661265 366536.397323923 5138113.34832342 366535.564825097 5138112.64824369 366485.313702831 5138049.80368183 366453.312870236 5138001.05316715 366416.593619779 5137978.95881858 366416.587707755 5137978.95525782 366386.499459196 5137960.83332812 366339.185982065 5137907.73881331 366288.122364621 5137845.83173942 366216.683841031 5137799.36182728 366108.557463946 5137741.9225659 366029.025822986 5137745.79625858 365970.026257097 5137802.23277408 365930.277242936 5137891.48209619 365920.371655258 5137944.51316849 365932.841234391 5138000.70085767 365960.811103591 5138072.01379758 365972.686771742 5138116.57648041 365972.687422175 5138116.57892797 365975.061905694 5138125.51401698 365972.469001608 5138189.13895637 365940.282070582 5138244.32591086 365898.688475529 5138272.70021792 365827.313242323 5138284.48028935 365732.281270375 5138269.79122924 365647.405031084 5138212.88359962 365569.934628535 5138122.63235302 365567.655039181 5138116.57448271 365567.653283612 5138116.56981739 365527.901621939 5138010.41294692 365499.08722652 5137882.66251335 365474.398328754 5137789.91213682 365400.896571652 5137690.84846121 365376.365258986 5137684.03591527 365333.990003365 5137661.53583604 365283.864981056 5137655.28574247 365239.771714256 5137686.41065965 365197.397982532 5137774.94182825 365179.555719593 5137881.72304155 365166.307346518 5137999.16051247 365161.902624819 5138110.22299993 365160.902713005 5138116.56674776 365160.902198506 5138116.57001858 365149.778695896 5138187.28547338 365117.904723126 5138259.47290813 365048.404931382 5138268.69152207 364993.341983506 5138231.22266712 364917.278734731 5138169.87877381 364875.965555283 5138116.56689138 364867.996674336 5138106.28493355 364801.183660132 5138062.75355874 364798.97112409 5138062.28804314 364750.089825187 5138052.00346172 364711.183923816 5138074.09713491 364666.187346678 5138118.2502155 364662.872128751 5138121.50328703 364641.967104594 5138209.56573682 364635.062474466 5138327.78445968 364649.313931514 5138435.87822487 364689.065706344 5138569.37828793 364696.285289058 5138631.03454516 364658.223828381 5138704.12821014 364605.78730269 5138771.34684599 364544.225664251 5138829.62796356 364490.91345493 5138846.69035307 364423.038507611 5138845.0964658 364356.851023245 5138840.90883246 364313.007271247 5138837.22124436 364281.069995494 5138851.15867724 364260.289258966 5138887.31487852 364263.47720422 5138920.37737891 364314.665608134 5138991.03372048 364391.104176879 5139075.7213625 364468.574177013 5139173.69025623 364493.012619355 5139244.84654557 364487.076089082 5139315.69027176 364439.077085231 5139385.34640949 364394.734339416 5139455.94005373 364319.141655568 5139528.87738026 364216.486331473 5139589.62715005 364095.080909628 5139641.93937995 363959.643840167 5139663.97033556 363868.425079219 5139656.56389265 363818.924788449 5139631.43879367 363808.392994932 5139590.40753212 363823.485954133 5139532.93882924 363839.172370844 5139453.87638284 363837.827523682 5139372.53265086 363841.545639761 5139325.87642051 363818.638210236 5139236.7826455 363785.481169167 5139175.62634255 363716.855629066 5139130.25121296 363615.824412883 5139124.84475658 363521.76249225 5139160.5008027 363371.857973439 5139277.59420678 363243.796764983 5139363.9689119 363237.626104089 5139370.40515816 363243.364277513 5139737.56253265 363288.385949383 5141356.56204431 363326.407379677 5142957.5615029 363362.428937446 5144568.560907 363393.450473892 5146178.56025039 363423.472146704 5147799.55953667 363462.493638907 5149407.55881229 363508.51540958 5151036.55805747 363525.541458662 5152632.54365357 363546.568453368 5154268.52794437 363567.595379654 5155902.51222113 363588.622172094 5157530.49652267 363626.648776953 5159144.48095067 363644.675349591 5160763.46526335 363661.701697692 5162371.44965229 363685.728248551 5163991.43389613 363709.754736729 5165609.41812413 363291.783016622 5165620.07441053 363315.77770652 5167225.40265729 363337.803609773 5168831.38711532 363364.829545382 5170438.37152247 363394.855248387 5172030.35603161 363427.881124527 5173632.3403966 363454.906150243 5175186.32520418 363467.932862727 5176859.30886258 363504.95904189 5178481.29290082 363550.977890328 5180075.29164102 363580.994093155 5181701.29615338 363611.010184343 5183316.30059055 363641.026261061 5184930.30498119 365281.047940272 5184892.29791889 366907.07038705 5184868.29350236 368514.094609698 5184840.29551664 370108.118282876 5184782.29747898 371712.142246418 5184739.29951398 373341.166495797 5184691.30160356 373382.189451016 5186298.30396487 373391.212936974 5187983.30635824 373441.235923314 5189582.30862248 373500.258375488 5191128.31076725 373541.281566533 5192751.31295644 373588.304614556 5194354.31507048 373653.328067132 5195956.31712917 373679.350870619 5197573.31916324 373718.373690395 5199170.32112234 373765.39676851 5200771.3230325 373810.419975119 5202384.32490804 373864.442539376 5203931.32664582 373465.40057681 5203942.92090823 373500.454499719 5205564.32904337 373528.486156668 5207158.32407421 373555.531914217 5208769.30919172 373587.577486548 5210369.29435633 373634.623218261 5211958.27954698 373683.669690791 5213571.26446363 373729.716095648 5215185.24932957 373769.762010239 5216789.23425526 373804.807979489 5218402.21906225 373825.852371883 5219978.20420591 373804.895460481 5221568.18928244 373851.941887044 5223185.1738895 373909.988276518 5224784.15858966 373945.033749309 5226384.14329541 373981.079382714 5227989.12790541 374019.124894757 5229587.11253092 374045.169847411 5231185.09714693 374094.216351173 5232802.08146562 374128.26138167 5234373.06628169 374141.315162816 5235996.05154401 374166.369620794 5237623.03668185 374208.423516773 5239209.02210155 374251.477236066 5240789.00753324 374283.530978323 5242386.43028713 373681.502561762 5242386.55653017 373719.557267099 5244003.97891204 373769.611971478 5245604.9638833 373819.667365047 5247227.94860987 373878.722823408 5248840.93337997 373941.779351181 5250481.91784665 373992.834567751 5252100.90249579 - - - - 441092.101754418,5208823.73991009 441972.032773827,5208775.41142816 443587.033226362,5208743.38172553 445198.051095369,5208718.35237246 446806.068363107,5208679.32334738 448644.087087741,5208608.29073645 450247.104615585,5208574.26195256 451834.124374432,5208602.23232861 453438.144212413,5208629.20233618 455033.163135423,5208636.17288165 456597.180129897,5208600.14499324 458225.198505544,5208581.11560367 459821.21517858,5208522.08790625 461439.233700543,5208509.05869865 463040.246910989,5208498.99806743 464622.256143646,5208453.92261524 466193.264646374,5208387.84811905 467933.276195024,5208379.76399427 469529.286922469,5208375.68679552 471117.297912188,5208380.60985085 472733.308665441,5208371.53186471 474328.319527427,5208369.45480206 475930.330365635,5208364.37748519 477560.337852849,5208249.30028279 479172.346439863,5208171.22321294 480784.356447228,5208136.14551495 482340.360106787,5208086.1204854 483907.362597763,5208023.10295594 485482.366095061,5207990.08506313 487695.37368665,5208030.05902892 489296.378898243,5208051.040287 490905.384432413,5208083.02133299 492543.389047529,5208082.00243547 494141.393716148,5208086.98394688 495747.398906727,5208109.96516074 495711.353257682,5206502.98535492 495676.309926805,5204889.00866588 495650.279726696,5203296.04675013 495637.248778541,5201663.08557362 495611.218295986,5200062.12367648 495603.188010644,5198467.16141745 495560.156779411,5196842.20002694 495564.126526155,5195247.23755609 495524.095615327,5193646.27538485 495503.064321413,5192017.3136871 495446.03275704,5190405.35159924 495420.002151849,5188825.38856517 495394.971242756,5187232.42574426 495375.93995181,5185617.46334803 495368.909626316,5184043.49993398 495340.878395801,5182446.53695695 495346.84729782,5180821.57463446 495302.815676504,5179229.61132198 495238.783334567,5177631.64792968 495199.767500209,5176019.63582349 495197.755906868,5174450.61531256 495162.742991802,5172830.59400039 495126.729927639,5171207.57265376 495067.716229818,5169609.55161623 495088.705029187,5168017.53073455 495086.692865267,5166393.50936063 495112.681912028,5164799.4883054 495107.669755823,5163187.46698448 495145.659310535,5161586.4456535 495178.648737239,5159980.6429203 495797.673211287,5159977.23447586 495717.658886368,5158361.40025725 495738.648547533,5156735.37796876 495734.637160115,5155107.35571706 495746.626973123,5153550.33429246 495747.61601901,5151951.3123082 495770.605990571,5150333.28983519 495773.615683926,5148704.27380344 495760.64120287,5147100.26336865 495755.667156541,5145494.25280909 495748.693082425,5143884.24220147 495748.719955069,5142239.23124588 495769.747660932,5140613.22013602 495815.776178388,5139024.20891946 495828.803448126,5137406.19781468 495830.829879582,5135804.18689701 495858.858328788,5134171.17538212 495862.885291437,5132548.16418396 495864.911866238,5130943.15308686 495858.938034687,5129335.14203562 495883.965846267,5127742.13058836 495856.990847918,5126129.11972733 495850.017037609,5124518.10854358 495835.043321767,5122871.09719571 495822.057922962,5121293.10356628 495835.052794276,5119689.14462307 495835.046800069,5118075.18610661 495827.040391883,5116474.22734309 495830.03459665,5114867.2685059 495843.029308365,5113258.30950871 495834.022797801,5111638.35111148 494234.941171807,5111635.37770315 492634.859519821,5111644.40406969 490947.773415802,5111651.43200419 489445.696786071,5111649.45714681 487838.614772884,5111656.48387701 486177.529781002,5111689.51091615 484578.448198062,5111689.5378244 482966.365654519,5111715.56435322 481334.282092909,5111736.59141491 479721.221100558,5111770.63479686 478124.175610684,5111798.68941725 476457.129157939,5111754.7481173 474848.084947473,5111654.80580315 473223.039842219,5111578.86331326 471623.995501651,5111486.91997601 470034.951263299,5111396.97599809 468383.905221494,5111292.03408398 466657.856325405,5111261.0935366 466801.849456444,5112811.07011109 466840.839130967,5114420.0494352 466837.82780885,5116011.03046653 466825.816297009,5117602.01185281 466806.804704029,5119187.99361209 466796.788476539,5121475.96660114 465169.751832345,5121562.03758123 463582.716668467,5121567.10778504 461978.681115782,5121582.17868885 460382.654975318,5121633.22463705 458863.634782301,5121649.25671468 458729.164257097,5121647.19708141 457106.611589166,5121622.29420132 455534.590852865,5121594.3278256 453901.569310636,5121566.36280177 452150.546221549,5121533.40039558 450644.526317509,5121524.43260388 448848.502614519,5121502.47117366 447142.480120161,5121473.5079516 445555.459188838,5121450.54218051 444012.438820035,5121440.57537843 442433.41800387,5121415.6095591 440877.37695095,5121394.6590622 439268.330052994,5121375.71365614 438623.813339239,5121376.09834029 438608.466924173,5121441.5166267 438596.591390315,5121527.9850023 438582.028332704,5121589.10994768 438548.558156946,5121795.26548809 438546.089318335,5121802.82800448 438536.401429659,5121851.26540118 438496.493851218,5121925.35985063 438461.242758608,5121953.57955277 438377.709007713,5121979.89467277 438306.488190201,5121972.92841773 438237.736223155,5121953.39968798 438155.890192362,5121903.34042007 438058.606268627,5121828.21939093 438017.948835643,5121826.06454523 437838.380916,5121901.57002048 437750.12819346,5121963.47875683 437689.782536252,5122024.98029865 437649.749976677,5122084.512416 437637.155825486,5122098.543979 437614.748826392,5122138.54440989 437591.404435887,5122162.35790414 437549.528288354,5122205.1096879 437534.527896677,5122230.61041166 437527.027817008,5122305.58004155 437509.98489396,5122463.40794018 437519.278954217,5123033.77386323 437546.282736399,5124637.78625312 437573.286513144,5126246.79863957 437598.290210678,5127849.81099969 437625.294012361,5129486.82352584 437635.297323898,5131096.83636224 437641.300538971,5132700.84923972 437648.303832046,5134323.86219173 437665.307315615,5135919.8745398 437698.311182421,5137532.88643811 437718.314733817,5139136.89865929 437736.318211385,5140725.91078311 437725.321201069,5142354.92416177 437725.324428085,5143976.93706535 437726.327686801,5145591.94983279 437727.330981757,5147211.9625931 437702.333741618,5148765.97566464 437697.348137997,5150407.98503925 437791.389300783,5152014.98244466 437837.429981925,5153635.98146622 437843.469251102,5155223.98172365 437843.494396201,5156242.79447432 437843.509384072,5156849.98210987 437837.784713312,5157878.73248683 437834.549029165,5158459.98268407 437842.257240392,5159295.10758917 437912.69554087,5159295.9805468 438546.704763059,5159386.9622125 438820.677249212,5159416.79805414 438868.021643891,5159421.9529385 438955.523526871,5159460.20043565 439389.43905896,5159649.78182603 439428.658644014,5159666.93696318 439837.293205181,5159883.92545398 439920.105839013,5159851.92304252 439928.95258192,5159831.79768159 440168.295395738,5159825.88464183 440394.891556092,5159824.69064082 440428.731220104,5159825.84576899 440435.50090148,5160474.87791456 440441.639697625,5161063.90983245 440435.976045197,5162089.00518069 440432.67738969,5162683.9123425 440422.825660397,5163685.13271532 440416.715119515,5164306.91495392 440429.239983656,5165367.88476372 440435.75289353,5165918.916557 440442.465107261,5166975.79273044 440445.789838809,5167498.91830244 440467.877617866,5168576.200343 440478.827657615,5169110.91948283 440497.446274702,5170172.6390742 440506.865079036,5170708.92074466 440537.889487585,5171749.7025147 440553.902074748,5172286.92153435 440572.989475617,5173352.60984766 440582.9399676,5173908.92276828 440604.370555919,5174951.2984902 440615.977504472,5175516.92387936 440637.563766231,5176535.7995613 440650.014973456,5177123.92495227 440650.699677025,5178172.94869223 440651.06097089,5178732.9083982 440684.750599837,5179797.67179249 440702.111525844,5180345.88134396 440731.830135607,5181339.36469896 440750.161804751,5181951.85443125 440774.193317489,5182959.24389991 440788.211689919,5183546.82785545 440808.556140411,5184569.02963089 440820.262004985,5185156.80111335 440840.168994679,5186181.03408972 440851.311907451,5186754.77454703 440868.844368726,5187794.75728581 440878.361997923,5188359.74790141 440898.739585907,5189444.7298283 440908.411922532,5189960.72122732 440913.290734644,5191084.45276957 440915.462465655,5191580.69461056 440937.027880396,5192677.64501441 440946.511668596,5193160.66818059 440965.045984715,5194262.9622736 440973.561784197,5194770.64128997 440987.346268008,5195878.46659537 440993.611925358,5196381.61446136 440997.677376318,5197479.59631226 440999.66263242,5198009.587543 440997.788580086,5199042.66427922 440996.713401008,5199638.56070505 441015.248841091,5200779.38528998 441022.763161913,5201240.53378684 441038.390380076,5202318.23443591 441044.810329775,5202759.50826854 441068.033916685,5203923.5198378 441076.86011304,5204365.48110994 441099.180074391,5205568.61773998 441107.919134768,5206040.4563889 441092.937830809,5207196.00699117 441086.988839287,5207653.43979129 441092.101754418,5208823.73991009 + + + + 437509.98489396 5111261.0935366495883.965846267 5208823.73991009 + 441092.101754418 5208823.73991009 441972.032773827 5208775.41142816 443587.033226362 5208743.38172553 445198.051095369 5208718.35237246 446806.068363107 5208679.32334738 448644.087087741 5208608.29073645 450247.104615585 5208574.26195256 451834.124374432 5208602.23232861 453438.144212413 5208629.20233618 455033.163135423 5208636.17288165 456597.180129897 5208600.14499324 458225.198505544 5208581.11560367 459821.21517858 5208522.08790625 461439.233700543 5208509.05869865 463040.246910989 5208498.99806743 464622.256143646 5208453.92261524 466193.264646374 5208387.84811905 467933.276195024 5208379.76399427 469529.286922469 5208375.68679552 471117.297912188 5208380.60985085 472733.308665441 5208371.53186471 474328.319527427 5208369.45480206 475930.330365635 5208364.37748519 477560.337852849 5208249.30028279 479172.346439863 5208171.22321294 480784.356447228 5208136.14551495 482340.360106787 5208086.1204854 483907.362597763 5208023.10295594 485482.366095061 5207990.08506313 487695.37368665 5208030.05902892 489296.378898243 5208051.040287 490905.384432413 5208083.02133299 492543.389047529 5208082.00243547 494141.393716148 5208086.98394688 495747.398906727 5208109.96516074 495711.353257682 5206502.98535492 495676.309926805 5204889.00866588 495650.279726696 5203296.04675013 495637.248778541 5201663.08557362 495611.218295986 5200062.12367648 495603.188010644 5198467.16141745 495560.156779411 5196842.20002694 495564.126526155 5195247.23755609 495524.095615327 5193646.27538485 495503.064321413 5192017.3136871 495446.03275704 5190405.35159924 495420.002151849 5188825.38856517 495394.971242756 5187232.42574426 495375.93995181 5185617.46334803 495368.909626316 5184043.49993398 495340.878395801 5182446.53695695 495346.84729782 5180821.57463446 495302.815676504 5179229.61132198 495238.783334567 5177631.64792968 495199.767500209 5176019.63582349 495197.755906868 5174450.61531256 495162.742991802 5172830.59400039 495126.729927639 5171207.57265376 495067.716229818 5169609.55161623 495088.705029187 5168017.53073455 495086.692865267 5166393.50936063 495112.681912028 5164799.4883054 495107.669755823 5163187.46698448 495145.659310535 5161586.4456535 495178.648737239 5159980.6429203 495797.673211287 5159977.23447586 495717.658886368 5158361.40025725 495738.648547533 5156735.37796876 495734.637160115 5155107.35571706 495746.626973123 5153550.33429246 495747.61601901 5151951.3123082 495770.605990571 5150333.28983519 495773.615683926 5148704.27380344 495760.64120287 5147100.26336865 495755.667156541 5145494.25280909 495748.693082425 5143884.24220147 495748.719955069 5142239.23124588 495769.747660932 5140613.22013602 495815.776178388 5139024.20891946 495828.803448126 5137406.19781468 495830.829879582 5135804.18689701 495858.858328788 5134171.17538212 495862.885291437 5132548.16418396 495864.911866238 5130943.15308686 495858.938034687 5129335.14203562 495883.965846267 5127742.13058836 495856.990847918 5126129.11972733 495850.017037609 5124518.10854358 495835.043321767 5122871.09719571 495822.057922962 5121293.10356628 495835.052794276 5119689.14462307 495835.046800069 5118075.18610661 495827.040391883 5116474.22734309 495830.03459665 5114867.2685059 495843.029308365 5113258.30950871 495834.022797801 5111638.35111148 494234.941171807 5111635.37770315 492634.859519821 5111644.40406969 490947.773415802 5111651.43200419 489445.696786071 5111649.45714681 487838.614772884 5111656.48387701 486177.529781002 5111689.51091615 484578.448198062 5111689.5378244 482966.365654519 5111715.56435322 481334.282092909 5111736.59141491 479721.221100558 5111770.63479686 478124.175610684 5111798.68941725 476457.129157939 5111754.7481173 474848.084947473 5111654.80580315 473223.039842219 5111578.86331326 471623.995501651 5111486.91997601 470034.951263299 5111396.97599809 468383.905221494 5111292.03408398 466657.856325405 5111261.0935366 466801.849456444 5112811.07011109 466840.839130967 5114420.0494352 466837.82780885 5116011.03046653 466825.816297009 5117602.01185281 466806.804704029 5119187.99361209 466796.788476539 5121475.96660114 465169.751832345 5121562.03758123 463582.716668467 5121567.10778504 461978.681115782 5121582.17868885 460382.654975318 5121633.22463705 458863.634782301 5121649.25671468 458729.164257097 5121647.19708141 457106.611589166 5121622.29420132 455534.590852865 5121594.3278256 453901.569310636 5121566.36280177 452150.546221549 5121533.40039558 450644.526317509 5121524.43260388 448848.502614519 5121502.47117366 447142.480120161 5121473.5079516 445555.459188838 5121450.54218051 444012.438820035 5121440.57537843 442433.41800387 5121415.6095591 440877.37695095 5121394.6590622 439268.330052994 5121375.71365614 438623.813339239 5121376.09834029 438608.466924173 5121441.5166267 438596.591390315 5121527.9850023 438582.028332704 5121589.10994768 438548.558156946 5121795.26548809 438546.089318335 5121802.82800448 438536.401429659 5121851.26540118 438496.493851218 5121925.35985063 438461.242758608 5121953.57955277 438377.709007713 5121979.89467277 438306.488190201 5121972.92841773 438237.736223155 5121953.39968798 438155.890192362 5121903.34042007 438058.606268627 5121828.21939093 438017.948835643 5121826.06454523 437838.380916 5121901.57002048 437750.12819346 5121963.47875683 437689.782536252 5122024.98029865 437649.749976677 5122084.512416 437637.155825486 5122098.543979 437614.748826392 5122138.54440989 437591.404435887 5122162.35790414 437549.528288354 5122205.1096879 437534.527896677 5122230.61041166 437527.027817008 5122305.58004155 437509.98489396 5122463.40794018 437519.278954217 5123033.77386323 437546.282736399 5124637.78625312 437573.286513144 5126246.79863957 437598.290210678 5127849.81099969 437625.294012361 5129486.82352584 437635.297323898 5131096.83636224 437641.300538971 5132700.84923972 437648.303832046 5134323.86219173 437665.307315615 5135919.8745398 437698.311182421 5137532.88643811 437718.314733817 5139136.89865929 437736.318211385 5140725.91078311 437725.321201069 5142354.92416177 437725.324428085 5143976.93706535 437726.327686801 5145591.94983279 437727.330981757 5147211.9625931 437702.333741618 5148765.97566464 437697.348137997 5150407.98503925 437791.389300783 5152014.98244466 437837.429981925 5153635.98146622 437843.469251102 5155223.98172365 437843.494396201 5156242.79447432 437843.509384072 5156849.98210987 437837.784713312 5157878.73248683 437834.549029165 5158459.98268407 437842.257240392 5159295.10758917 437912.69554087 5159295.9805468 438546.704763059 5159386.9622125 438820.677249212 5159416.79805414 438868.021643891 5159421.9529385 438955.523526871 5159460.20043565 439389.43905896 5159649.78182603 439428.658644014 5159666.93696318 439837.293205181 5159883.92545398 439920.105839013 5159851.92304252 439928.95258192 5159831.79768159 440168.295395738 5159825.88464183 440394.891556092 5159824.69064082 440428.731220104 5159825.84576899 440435.50090148 5160474.87791456 440441.639697625 5161063.90983245 440435.976045197 5162089.00518069 440432.67738969 5162683.9123425 440422.825660397 5163685.13271532 440416.715119515 5164306.91495392 440429.239983656 5165367.88476372 440435.75289353 5165918.916557 440442.465107261 5166975.79273044 440445.789838809 5167498.91830244 440467.877617866 5168576.200343 440478.827657615 5169110.91948283 440497.446274702 5170172.6390742 440506.865079036 5170708.92074466 440537.889487585 5171749.7025147 440553.902074748 5172286.92153435 440572.989475617 5173352.60984766 440582.9399676 5173908.92276828 440604.370555919 5174951.2984902 440615.977504472 5175516.92387936 440637.563766231 5176535.7995613 440650.014973456 5177123.92495227 440650.699677025 5178172.94869223 440651.06097089 5178732.9083982 440684.750599837 5179797.67179249 440702.111525844 5180345.88134396 440731.830135607 5181339.36469896 440750.161804751 5181951.85443125 440774.193317489 5182959.24389991 440788.211689919 5183546.82785545 440808.556140411 5184569.02963089 440820.262004985 5185156.80111335 440840.168994679 5186181.03408972 440851.311907451 5186754.77454703 440868.844368726 5187794.75728581 440878.361997923 5188359.74790141 440898.739585907 5189444.7298283 440908.411922532 5189960.72122732 440913.290734644 5191084.45276957 440915.462465655 5191580.69461056 440937.027880396 5192677.64501441 440946.511668596 5193160.66818059 440965.045984715 5194262.9622736 440973.561784197 5194770.64128997 440987.346268008 5195878.46659537 440993.611925358 5196381.61446136 440997.677376318 5197479.59631226 440999.66263242 5198009.587543 440997.788580086 5199042.66427922 440996.713401008 5199638.56070505 441015.248841091 5200779.38528998 441022.763161913 5201240.53378684 441038.390380076 5202318.23443591 441044.810329775 5202759.50826854 441068.033916685 5203923.5198378 441076.86011304 5204365.48110994 441099.180074391 5205568.61773998 441107.919134768 5206040.4563889 441092.937830809 5207196.00699117 441086.988839287 5207653.43979129 441092.101754418 5208823.73991009 - - - - 396647.319162537,5125787.41633249 396629.824563343,5125805.82618797 396606.574358413,5125830.8264017 396595.511885163,5125859.8265997 396577.261814638,5125891.82683664 396573.637016015,5125927.82705053 396574.949857411,5125971.82729413 396576.075137571,5126007.82749328 396582.263052331,5126050.82771637 396590.826006225,5126093.82793236 396596.701364704,5126129.82811725 396605.264318258,5126172.82833358 396618.389788858,5126207.82849133 396631.390228143,5126238.82862717 396644.515705503,5126274.82879108 396659.078702435,5126310.297698 396670.579120159,5126341.82909202 396683.579551284,5126371.82922318 396696.454972903,5126400.82934927 396716.643028971,5126431.82946552 396734.393537423,5126461.82958359 396754.581592814,5126492.82970056 396774.519586055,5126515.82977324 396792.082547279,5126539.82985873 396819.083119819,5126557.82988318 396855.458795444,5126568.82984108 396898.396942019,5126560.82967184 396939.022558013,5126553.8295148 396969.772954926,5126538.82934018 396993.21071066,5126520.82916915 397016.460920688,5126496.82896388 397027.460872742,5126464.82874777 397045.710944138,5126432.82851025 397056.585866089,5126396.82827085 397062.648201959,5126359.82803953 397066.08545198,5126316.82778114 397067.835406618,5126306.42146587 397072.147795239,5126280.82755525 397075.835099479,5126244.82733626 397081.647381872,5126200.82706453 397092.459782577,5126161.82680651 397103.334705913,5126125.82656536 397121.772332701,5126100.82636484 397132.772294143,5126069.82615172 397148.834882151,5126044.82595783 397160.553757661,5126035.20086627 397179.272708267,5126019.82571988 397202.647953329,5125999.82553214 397233.335833894,5125981.82533342 397269.086369297,5125973.82517735 397305.337011941,5125979.82510165 397344.087731071,5125990.82504784 397373.463344054,5126008.82506407 397397.963862016,5126024.82508369 397425.151973375,5126047.82513668 397438.089904983,5126078.82528037 397444.027755832,5126114.82547489 397445.590639645,5126165.82577112 397454.091060634,5126205.82598176 397460.091433225,5126244.8261941 397468.529352856,5126284.82640523 397471.34202389,5126302.60775191 397474.529718163,5126322.82661191 397494.655252618,5126351.82672409 397507.593182574,5126382.82686947 397527.781224448,5126412.82698805 397545.344180905,5126436.82707907 397565.46972113,5126466.82719851 397578.407636095,5126495.82733311 397591.595617786,5126533.82752065 397604.4710243,5126561.82764997 397612.783911683,5126597.82784006 397618.971812944,5126640.82807793 397627.534752913,5126683.82830922 397628.847581176,5126727.82856701 397635.035482062,5126770.82880521 397643.3483687,5126806.828996 397645.004726745,5126818.4540605 397649.473768279,5126849.82923463 397657.786647643,5126884.82941976 397670.912112201,5126920.82959777 397690.850103905,5126944.82968593 397703.850524161,5126974.8298291 397721.601028402,5127005.82996553 397741.664049093,5127033.83007812 397761.664540702,5127057.83016732 397766.539781408,5127081.11154329 397769.602433453,5127095.8616232 397772.545330568,5127866.83496574 397799.55716051,5129508.84465574 397831.568827347,5131116.8540907 397844.579951222,5132687.86328606 397841.591240943,5134313.87274973 397847.602616648,5135930.88208476 397871.614199177,5137540.89132351 397907.625956819,5139153.90054444 397932.637595763,5140770.90973277 397947.649143106,5142391.91887313 397962.660579673,5143995.92785993 397972.671962545,5145598.93676736 397971.683228179,5147199.94555985 397981.694931268,5148843.95455868 397986.706260507,5150439.96320876 397990.753525199,5152039.92440306 398061.802940095,5153673.8844116 398044.852873508,5155360.84277007 398049.901485214,5156996.80243326 398075.949416946,5158601.76287673 398059.997632782,5160238.72242226 398074.045935741,5161865.68223921 398079.094836043,5163519.64134919 398121.172223473,5165059.66575611 397524.818123527,5165067.79049237 397026.153268514,5165076.32148286 397059.169441951,5166697.56308368 397074.216493664,5168318.52340502 397070.262855338,5169930.48393691 397080.309523306,5171545.44435402 397136.356979965,5173154.40478628 397156.403121981,5174745.3656852 397292.452470757,5176353.32576343 397351.500174909,5177964.28589945 397410.545932918,5179591.26622548 397438.590081989,5181207.25121208 397484.635123672,5182839.23587902 397568.67961072,5184411.22069788 399155.722151603,5184365.20819777 400767.765827735,5184336.19538155 402376.809351054,5184305.18266293 403893.850467498,5184279.17067505 405509.88661979,5184240.16416644 407127.917199638,5184205.16237558 408731.947575327,5184173.16060055 410320.977603268,5184140.15890349 411927.0077774,5184102.15730687 413468.035170976,5184019.156598 415034.06331545,5183946.15575987 416630.092083367,5183876.15490039 418239.122759583,5183856.15320425 419845.153118906,5183829.1516743 421418.182848745,5183803.15020699 423021.215323013,5183838.14759326 424640.227328401,5183826.1287231 426250.225657675,5183796.09869613 427926.224039936,5183768.06739585 429532.222317095,5183736.03751201 431126.220916499,5183713.00771019 432729.219448619,5183687.97779001 434321.217792016,5183656.94819719 435909.216377732,5183632.91857415 437519.214606452,5183597.88873491 439133.213072692,5183569.8587156 440447.274474624,5183551.58421118 440788.211689919,5183546.82785545 440774.193317489,5182959.24389991 440750.161804751,5181951.85443125 440731.830135607,5181339.36469896 440702.111525844,5180345.88134396 440684.750599837,5179797.67179249 440651.06097089,5178732.9083982 440650.699677025,5178172.94869223 440650.014973456,5177123.92495227 440637.563766231,5176535.7995613 440615.977504472,5175516.92387936 440604.370555919,5174951.2984902 440582.9399676,5173908.92276828 440572.989475617,5173352.60984766 440553.902074748,5172286.92153435 440537.889487585,5171749.7025147 440506.865079036,5170708.92074466 440497.446274702,5170172.6390742 440478.827657615,5169110.91948283 440467.877617866,5168576.200343 440445.789838809,5167498.91830244 440442.465107261,5166975.79273044 440435.75289353,5165918.916557 440429.239983656,5165367.88476372 440416.715119515,5164306.91495392 440422.825660397,5163685.13271532 440432.67738969,5162683.9123425 440435.976045197,5162089.00518069 440441.639697625,5161063.90983245 440435.50090148,5160474.87791456 440428.731220104,5159825.84576899 440394.891556092,5159824.69064082 440168.295395738,5159825.88464183 439928.95258192,5159831.79768159 439920.105839013,5159851.92304252 439837.293205181,5159883.92545398 439428.658644014,5159666.93696318 439389.43905896,5159649.78182603 438955.523526871,5159460.20043565 438868.021643891,5159421.9529385 438820.677249212,5159416.79805414 438546.704763059,5159386.9622125 437912.69554087,5159295.9805468 437842.257240392,5159295.10758917 437834.549029165,5158459.98268407 437837.784713312,5157878.73248683 437843.509384072,5156849.98210987 437843.494396201,5156242.79447432 437843.469251102,5155223.98172365 437837.429981925,5153635.98146622 437791.389300783,5152014.98244466 437697.348137997,5150407.98503925 437702.333741618,5148765.97566464 437727.330981757,5147211.9625931 437726.327686801,5145591.94983279 437725.324428085,5143976.93706535 437725.321201069,5142354.92416177 437736.318211385,5140725.91078311 437718.314733817,5139136.89865929 437698.311182421,5137532.88643811 437665.307315615,5135919.8745398 437648.303832046,5134323.86219173 437641.300538971,5132700.84923972 437635.297323898,5131096.83636224 437625.294012361,5129486.82352584 437598.290210678,5127849.81099969 437573.286513144,5126246.79863957 437546.282736399,5124637.78625312 437519.278954217,5123033.77386323 437509.98489396,5122463.40794018 437527.027817008,5122305.58004155 437534.527896677,5122230.61041166 437549.528288354,5122205.1096879 437591.404435887,5122162.35790414 437614.748826392,5122138.54440989 437637.155825486,5122098.543979 437649.749976677,5122084.512416 437689.782536252,5122024.98029865 437750.12819346,5121963.47875683 437838.380916,5121901.57002048 438017.948835643,5121826.06454523 438058.606268627,5121828.21939093 438155.890192362,5121903.34042007 438237.736223155,5121953.39968798 438306.488190201,5121972.92841773 438377.709007713,5121979.89467277 438461.242758608,5121953.57955277 438496.493851218,5121925.35985063 438536.401429659,5121851.26540118 438546.089318335,5121802.82800448 438548.558156946,5121795.26548809 438582.028332704,5121589.10994768 438596.591390315,5121527.9850023 438608.466924173,5121441.5166267 438623.813339239,5121376.09834029 437492.278289034,5121376.77370461 437489.281897405,5119808.78685956 437484.285556978,5118193.80044963 437485.289502675,5116528.81424446 437456.292405097,5114947.82823075 437452.2960581,5113347.84157795 437431.299201951,5111764.85524216 435862.25607009,5111768.89945371 434242.211499074,5111795.9449713 432640.167442508,5111821.99004314 431057.123883495,5111860.03457731 429450.079784996,5111869.07996791 427689.031503852,5111876.12973772 426075.987253384,5111896.17531676 424471.943303663,5111909.22068335 422855.899076511,5111917.26641124 421230.245048103,5111933.30087059 419693.843452792,5111956.33283067 417964.469828952,5111966.36879395 416363.067141303,5111988.40214818 414771.7584298,5111973.43514807 413159.168052034,5111993.46874153 411548.296462609,5112009.50229384 409948.518902999,5112091.53610421 408231.145662077,5112170.57246601 406647.680959646,5112207.60578157 405044.934660928,5112231.63941539 403453.563699325,5112279.67291954 401873.540795608,5112322.6780784 400243.517022892,5112330.68303475 398556.492460839,5112347.68827534 396933.468840334,5112364.69334166 395351.445842091,5112389.69839127 393853.36157894,5112421.64078434 393859.299199886,5112441.70349511 393847.736572546,5112465.70380383 393843.674086977,5112508.70430647 393837.111552817,5112544.70473691 393845.049242344,5112587.70520303 393850.486883488,5112623.70559688 393863.112129893,5112659.70596873 393882.862472251,5112690.70626172 393895.237694829,5112714.70649737 393914.988037748,5112745.70679013 393932.300840051,5112773.70705606 393951.926169584,5112797.70726924 393969.238977644,5112828.70756912 393996.051911514,5112851.70774863 394013.302206987,5112875.70796879 394033.052551765,5112906.70826081 394045.552790225,5112937.70857504 394058.178039574,5112973.70894566 394065.990716505,5113008.70931965 394078.553456494,5113039.70963341 394091.116196692,5113070.70994707 394103.741446914,5113106.7103173 394121.054257676,5113137.71061607 394135.992030064,5113166.71089934 394148.492270238,5113197.71121282 394159.961246877,5113229.555289 394160.023832358,5113276.71207453 394160.086424654,5113327.68140335 394149.617585741,5113364.68185631 394144.680060856,5113391.71342881 394133.367462626,5113430.71390723 394126.742428434,5113466.71433695 394110.492242135,5113497.71474007 394104.117234372,5113546.7153168 394104.867321865,5113589.715803 394093.492216285,5113625.71624779 394082.117110468,5113661.71669265 394077.929611646,5113697.7171149 394071.4295835,5113736.71757855 394060.054477088,5113772.71802356 394048.67937044,5113808.71846863 394042.054334609,5113844.71889871 394042.804423075,5113888.71939632 394043.554509784,5113931.71988254 394051.429691031,5113967.72026654 394056.929849101,5114010.72073754 394069.555101945,5114046.72110623 394077.367782725,5114082.72149018 394090.055540472,5114120.72188119 394090.743123231,5114161.72234455 394098.74331963,5114204.72280715 394099.493406947,5114247.72329291 394104.993565904,5114290.72376339 394124.743913448,5114318.72401772 394137.244157168,5114349.72432931 394149.869411885,5114385.72469713 394167.682245546,5114421.88129988 394186.807568417,5114440.72520192 394211.245479328,5114463.72538385 394237.995918334,5114482.72551285 394267.121393583,5114501.72563407 394298.496888663,5114512.72565728 394322.809787916,5114529.72577122 394354.372799104,5114547.72587293 394383.373260707,5114559.72591491 394414.87377337,5114578.72602795 394446.31177054,5114589.72605056 394477.812278199,5114605.72612945 394506.812740696,5114617.72617113 394531.250660501,5114643.7263858 394550.876001888,5114666.72658206 394563.376246602,5114695.72686919 394571.313948641,5114738.72732926 394596.001896305,5114776.72767818 394601.377046541,5114812.7280673 394597.377067299,5114855.72856603 394590.752034629,5114891.7289943 394579.376931218,5114928.72944943 394566.470547747,5114962.32362117 394551.626620873,5114988.73021814 394532.87638519,5115015.7305847 394514.126143602,5115039.73091745 394490.500829059,5115064.73127761 394466.875503023,5115083.73157005 394448.125269927,5115112.73195959 394424.562455412,5115137.73231986 394408.249755359,5115164.73267895 394389.49952137,5115193.73306878 394370.874292663,5115224.73348092 394354.499087194,5115249.73381784 394330.873768359,5115273.73416751 394292.935731185,5115298.73457599 394269.247901644,5115317.73486951 394252.872695053,5115342.73520681 394239.060047403,5115378.73566023 394222.747343077,5115404.7360088 394204.059609094,5115434.73641064 394187.809414129,5115465.73681579 394169.121683087,5115497.73724048 394157.621557243,5115526.73760732 394138.933823844,5115557.73802086 394127.496203812,5115589.73842162 394111.183502991,5115618.73880474 394097.37084405,5115649.73920224 394088.55823042,5115662.61437765 394080.933132024,5115673.73952926 394062.307899905,5115705.73995438 394046.057702473,5115736.74036029 394034.557574845,5115765.74072766 394020.682415429,5115797.74113709 394004.494726822,5115833.74159972 393997.869679337,5115865.74198489 393986.494564888,5115901.74243145 393975.119453643,5115939.74290076 393963.744340432,5115976.7433588 393952.306715737,5116007.74374905 393933.618974614,5116036.74414123 393917.243760681,5116060.74446893 393893.680939688,5116087.74485512 393874.86818897,5116112.74520261 393861.180482468,5116116.74529445 393854.61792906,5116145.74564587 393850.430407537,5116171.74595519 393841.930304956,5116189.58993661 393825.117594874,5116220.74659747 393813.554946164,5116239.74685252 393797.054710209,5116252.74705632 393778.241944662,5116269.74731346 393761.866720345,5116288.74758506 393747.866531327,5116306.74783726 393731.491306684,5116325.74810897 393712.553531926,5116338.74832133 393696.178306954,5116357.74859315 393670.302942922,5116382.74896571 393653.802704186,5116394.74915854 393642.240055644,5116414.74942545 393623.552301824,5116438.74976227 393611.927147149,5116455.74999538 393600.552012397,5116482.75034137 393588.926857469,5116499.75057455 393577.489216607,5116523.75088674 393565.926567222,5116543.75115391 393554.36391611,5116562.75140974 393542.86377383,5116586.75172227 393519.113442233,5116612.84585085 393512.488355425,5116623.75224775 393500.925705356,5116643.75251513 393482.112936403,5116660.75277343 393465.550194804,5116672.75296711 393439.424804218,5116685.75320523 393415.736950249,5116697.75342361 393391.86158697,5116705.75359715 393368.111233285,5116718.75382724 393344.360877897,5116730.754046 393320.548015241,5116738.75421946 393301.610235368,5116750.75442168 393277.859881082,5116763.754652 393254.109525117,5116775.75487097 393235.171746349,5116788.75508474 393211.483891073,5116800.75530361 393192.546112027,5116813.75551748 393175.983368809,5116825.75571176 393149.857976147,5116838.75595065 393133.482745994,5116857.75622424 393114.544966382,5116870.75643831 393098.169735903,5116889.75671202 393086.419569485,5116902.75690122 393067.606797293,5116919.75716067 393056.231655549,5116945.75749706 393037.418884445,5116963.75776805 393033.04384287,5116982.75800023 393021.606196787,5117006.75831414 393015.106140246,5117038.75870223 393008.418569061,5117062.75899965 393004.168536393,5117086.75928857 392997.668478094,5117117.75966531 392993.543454455,5117146.76001093 392987.043397381,5117178.76039914 392987.793453825,5117209.76075054 392988.418505414,5117238.76107952 392989.168561865,5117269.76143089 392989.668601508,5117291.82418106 392989.981126498,5117305.76183911 392985.918606405,5117336.76220736 392986.731171,5117372.76261556 392987.418726433,5117403.76296708 392988.168784299,5117435.76332978 392981.606221287,5117464.76368403 392982.29377667,5117495.76403552 392983.043833052,5117526.76438677 392978.918811594,5117557.76475526 392972.418749256,5117586.76510935 392973.106305979,5117618.76547222 392961.668657377,5117642.76578678 392957.418623605,5117666.76607586 392943.54343573,5117690.76639915 392927.168201979,5117710.76668571 392915.418030818,5117722.76686452 392891.855181635,5117742.76717676 392872.917395103,5117754.76738123 392740.790424309,5117861.76907524 392717.040059422,5117873.7692973 392698.28978547,5117893.76959306 392681.727035677,5117905.76978954 392662.914256339,5117922.77005132 392651.16408497,5117935.77024211 392632.413809005,5117954.77052666 392608.288447914,5117974.89584341 392608.475965431,5117985.83346794 392585.663132786,5118011.77134664 392574.100471765,5118030.77160564 392562.600318191,5118054.77192172 392543.787538836,5118072.7721954 392532.224877397,5118091.77245454 392520.724723346,5118115.77277076 392509.162062944,5118135.77304143 392497.724409603,5118159.77335752 392486.161748931,5118179.77362828 392474.724095295,5118203.77394446 392463.223940494,5118227.77426091 392456.411352287,5118244.77448028 392443.81744214,5118278.61866355 392440.723664055,5118295.77512132 392426.910971326,5118319.77544629 392422.785945318,5118351.77582793 392416.160868597,5118375.77612696 392411.910830245,5118399.7764174 392405.410764244,5118430.77679624 392401.160725746,5118454.77708672 392394.660660804,5118486.77747706 392390.410622159,5118510.77776756 392383.848052215,5118539.7781238 392379.723024262,5118570.7784941 392380.473076701,5118602.77885811 392381.160626871,5118633.77921086 392381.973185368,5118669.77962043 392382.66073303,5118698.77995023 392383.348283211,5118729.78030293 392388.910912823,5118760.78063776 392389.598463053,5118791.78099041 392397.47362799,5118820.78129376 392398.286186632,5118856.78170317 392398.973736932,5118887.78205574 392399.723788257,5118918.78240806 392400.536346912,5118954.7828174 392394.036280934,5118986.78320784 392394.723831189,5119017.78356036 392402.786508491,5119053.7839429 392403.411555271,5119082.78427269 392408.849177143,5119108.78455032 392417.411893277,5119168.78520562 392417.974432822,5119192.7854783 392411.474365244,5119223.78585728 392407.349337824,5119255.78623893 392408.036884392,5119283.78655692 392408.911947902,5119322.78700013 392414.349572639,5119350.78730042 392415.224633688,5119387.78772067 392411.099604812,5119418.78809085 392411.787155176,5119449.78844309 392405.349588049,5119480.78882191 392405.974634815,5119509.78915149 392406.84969828,5119548.78959456 392407.537246085,5119577.78992386 392408.224796407,5119608.79027604 392409.037355083,5119644.79068494 392416.975025357,5119675.79100988 392417.66257575,5119706.79136198 392423.162703331,5119735.79167309 392423.850253773,5119766.79202514 392431.787924406,5119797.79234988 392437.10054279,5119821.79260439 392437.85059438,5119852.79295612 392440.631903442,5119863.0118125 392445.725761732,5119881.79325808 392451.225892287,5119912.79359182 392459.163563436,5119943.7939163 392459.663602176,5119967.79418881 392465.16373042,5119996.79449956 392473.101401848,5120027.79482389 392473.78895269,5120058.79517564 392481.726624313,5120089.79549988 392482.351671638,5120118.79582895 392483.101723595,5120149.79618038 392483.914282962,5120185.7965887 392484.601833886,5120216.79694033 392485.414393263,5120252.7973486 392486.164446509,5120284.79771139 392486.977005895,5120320.79811962 392492.477137348,5120351.7984528 392493.039677325,5120375.79872483 392500.977349717,5120406.79904862 392506.414977796,5120435.79935907 392514.352650416,5120466.79968275 392526.915390478,5120489.79989728 392539.353123455,5120508.80006657 392551.915865102,5120532.8002924 392564.353598353,5120551.80046157 392583.978948531,5120567.80056886 392600.010505845,5120597.11334179 392608.979424349,5120610.8009635 392621.417158159,5120629.80113245 392641.042509008,5120645.80123949 392658.105311672,5120657.80131071 392677.949415731,5120673.20766002 392702.106091439,5120687.8014834 392721.731446962,5120706.80162438 392738.856751236,5120718.80169515 392758.419602039,5120734.80180206 392775.544906569,5120746.80187274 392795.10775498,5120760.80195676 392814.670606259,5120776.8020635 392831.795911176,5120788.80213404 392851.421266561,5120806.80226318 392871.046620767,5120823.80238087 392883.484356665,5120842.80254903 392900.734673902,5120861.80269853 392908.547337548,5120884.80292997 392921.110082889,5120908.80315436 392926.422705908,5120932.80340675 392927.23526959,5120968.80381304 392923.17274389,5120999.80418134 392923.860299875,5121031.80454259 392917.360232791,5121062.80492038 392913.110194025,5121086.80520984 392901.672533419,5121110.80552728 392894.984954546,5121135.80583765 392883.547293661,5121159.80615517 392879.297254538,5121183.80644472 392872.609673993,5121207.80674378 392873.484742288,5121246.80718397 392874.172292332,5121274.80749975 392886.79754389,5121301.80775747 392899.172776234,5121317.80789102 392911.673014952,5121336.80805814 392924.235761778,5121360.8082818 392936.798508767,5121384.8085054 392949.23624684,5121403.80867259 392968.861603252,5121419.80877747 392981.299341611,5121438.80894455 393001.049710309,5121461.80912832 393010.924899806,5121476.90301098 393025.925184951,5121497.80943949 393038.362923867,5121516.80960635 393058.113293343,5121539.80978982 393070.613533636,5121558.80995632 393082.988769071,5121575.81010056 393107.301699889,5121586.81012968 393126.864554048,5121600.81021148 393143.927362765,5121612.81028039 393163.552721167,5121628.81038452 393175.990461243,5121647.81055094 393195.67832541,5121666.81068871 393208.24107521,5121690.81091119 393225.428892612,5121706.81102468 393244.929243869,5121718.81108366 393269.117168119,5121725.81106744 393300.36770149,5121724.81093268 393316.930465618,5121711.81072005 393340.680854092,5121699.81049043 393366.931291185,5121691.81029627 393395.494260176,5121678.81003645 393426.619784935,5121673.8098571 393457.870317864,5121672.80972254 393493.933433088,5121671.80956902 393525.246476345,5121676.80950206 393549.43439937,5121682.80947448 393580.809942319,5121686.80939592 393604.997867081,5121693.80937958 393629.310800374,5121704.80940789 393653.436221126,5121709.80936915 393672.936572303,5121720.80941637 393697.312011842,5121734.80947815 393714.374823146,5121746.80954619 393734.000184865,5121762.80964918 393758.313120639,5121774.80968847 393782.501044747,5121780.80966054 393813.876588865,5121784.80958162 393845.064623317,5121784.80945833 393869.377557989,5121795.80948618 393893.565484088,5121802.80946941 393913.253352945,5121821.80960556 393930.378664812,5121832.80966169 393949.879019183,5121844.80971963 393974.129453519,5121855.80974747 393980.567088586,5121870.55988801 394006.005040641,5121879.80989136 394035.005558621,5121891.80991148 394061.69354385,5121907.8099857 394090.694062249,5121919.81000568 394122.25713511,5121937.81008288 394153.757708931,5121956.81017145 394178.383194166,5121992.81047819 394222.321522601,5122034.81077535 394246.571967771,5122050.81085858 394270.947420551,5122069.8109749 394295.447896778,5122100.8112253 394315.073277083,5122124.81141642 394339.44873778,5122147.8115773 394355.355301223,5122169.96801237 394376.261957671,5122195.81196876 394395.887337237,5122218.81214828 394413.262692471,5122249.81242635 394432.950587952,5122280.81269506 394452.575970121,5122304.81288546 394469.951326235,5122335.81316318 394494.326789315,5122358.81332314 394513.952172303,5122382.81351323 394533.702570425,5122413.81378107 394550.890411741,5122437.81398072 394570.578303909,5122465.81421501 394587.828650453,5122491.81443659 394607.516545024,5122520.81468184 394620.079319934,5122551.814978 394639.642203691,5122575.81516761 394657.017560798,5122605.81543301 394676.767961315,5122636.8156999 394696.455857359,5122665.81594455 394713.643700911,5122689.81614332 394733.269090836,5122715.8163545 394745.519324584,5122726.81642786 394740.082037153,5122766.81665835 394764.832648369,5122789.81667434 394789.833325575,5122820.81673085 394817.146519537,5122848.81676288 394834.709504156,5122871.81680952 394859.522638279,5122897.81684226 394879.273106525,5122913.81684432 394904.023723511,5122937.81686765 394928.836848953,5122962.81689628 394955.774941809,5122978.81686992 394973.337932572,5123002.81692346 394998.151057066,5123027.81695315 395029.9017329,5123043.81690827 395058.496141839,5123064.81690259 395086.215481581,5123078.81686417 395110.841047887,5123096.81685942 395142.654238941,5123114.81682611 395171.842330564,5123125.81676686 395203.5305036,5123141.81672417 395235.343701373,5123160.81669716 395266.906833568,5123171.81662922 395303.282541552,5123181.81653703 395339.658256907,5123192.8164504 395371.221388458,5123203.81638321 395407.472063324,5123209.81627095 395439.222735558,5123225.81623018 395468.473349008,5123239.81618895 395495.598993273,5123262.81620467 395520.349596002,5123285.81623017 395537.912581366,5123309.81628975 395557.850600111,5123332.81633486 395578.03868312,5123363.81642235 395591.164181148,5123399.81656481 395596.977014847,5123430.81670912 395610.102504936,5123465.81684662 395623.102962563,5123496.81696328 395637.353749434,5123568.81729667 395645.91672001,5123611.81749581 395651.854592615,5123647.81766739 395653.417494831,5123697.81793139 395654.667824093,5123738.81814797 395656.043170504,5123781.81837485 395652.605941696,5123825.81862529 395641.731025185,5123861.81886043 395630.731076702,5123893.81907422 395619.731128427,5123925.81928775 395601.418532393,5123954.81951223 395590.418584587,5123986.8197252 395572.168505251,5124017.8199595 395556.168419549,5124042.82015293 395537.855824659,5124071.82037606 395534.231056787,5124110.82059811 395535.606404653,5124153.82082305 395544.981758839,5124179.53967623 395548.73190043,5124189.8209675 395561.669832457,5124217.82107007 395574.607786881,5124248.82118892 395592.420824241,5124279.8212903 395607.796319737,5124310.82140083 395625.484331816,5124338.82148718 395645.672408739,5124369.82158095 395663.42294382,5124400.82168386 395683.423456846,5124423.82173593 395703.549031724,5124454.821831 395721.112002747,5124477.82189239 395745.67504009,5124493.82189127 395772.800673097,5124516.8219192 395958.867494766,5124673.13461351 395977.555427812,5124688.82213398 396009.118543949,5124699.82208402 396040.931715948,5124717.82207188 396077.057357066,5124721.82196805 396120.495636621,5124727.82184993 396168.496434268,5124725.82167189 396211.684657849,5124724.82151611 396254.997912928,5124727.82138216 396291.248570403,5124733.82128959 396327.436734009,5124740.82120298 396363.812422571,5124750.8211327 396402.375604091,5124754.82102145 396438.751299561,5124765.82095723 396474.93945521,5124771.8208658 396511.315150251,5124782.82080208 396542.878263716,5124793.82075525 396579.253958297,5124804.82069207 396618.004692763,5124815.820621 396642.630239036,5124833.82063855 396667.130768482,5124849.82064543 396698.94393558,5124867.82063893 396716.506905183,5124891.82071572 396741.25748856,5124914.82076257 396768.383111651,5124937.8208017 396786.133633971,5124968.82091883 396794.321494945,5124999.82106858 396813.38483359,5125071.82141678 396826.385275015,5125102.82155089 396839.510747052,5125137.82170776 396854.8862279,5125168.82183446 396860.76158493,5125204.82202163 396869.136890501,5125227.82212598 396873.887063443,5125240.82218496 396882.324977473,5125278.82237547 396888.387873065,5125319.82259116 396896.950824709,5125362.82281031 396898.263654907,5125405.82305318 396904.451566561,5125448.82328028 396893.576642937,5125484.82352222 396889.889346691,5125521.82374655 396878.889385499,5125552.82395972 396860.639310797,5125584.82420152 396842.389214871,5125613.82442575 396819.201529806,5125641.82465958 396802.951381453,5125658.82480822 396772.513554689,5125683.82504716 396749.138309812,5125703.82523489 396725.700564154,5125723.82542252 396695.075184765,5125741.82562109 396671.63743966,5125761.82580809 396647.319162537,5125787.41633249 + + + + 392379.723024262 5111764.85524216440788.211689919 5184411.22069788 + 396647.319162537 5125787.41633249 396629.824563343 5125805.82618797 396606.574358413 5125830.8264017 396595.511885163 5125859.8265997 396577.261814638 5125891.82683664 396573.637016015 5125927.82705053 396574.949857411 5125971.82729413 396576.075137571 5126007.82749328 396582.263052331 5126050.82771637 396590.826006225 5126093.82793236 396596.701364704 5126129.82811725 396605.264318258 5126172.82833358 396618.389788858 5126207.82849133 396631.390228143 5126238.82862717 396644.515705503 5126274.82879108 396659.078702435 5126310.297698 396670.579120159 5126341.82909202 396683.579551284 5126371.82922318 396696.454972903 5126400.82934927 396716.643028971 5126431.82946552 396734.393537423 5126461.82958359 396754.581592814 5126492.82970056 396774.519586055 5126515.82977324 396792.082547279 5126539.82985873 396819.083119819 5126557.82988318 396855.458795444 5126568.82984108 396898.396942019 5126560.82967184 396939.022558013 5126553.8295148 396969.772954926 5126538.82934018 396993.21071066 5126520.82916915 397016.460920688 5126496.82896388 397027.460872742 5126464.82874777 397045.710944138 5126432.82851025 397056.585866089 5126396.82827085 397062.648201959 5126359.82803953 397066.08545198 5126316.82778114 397067.835406618 5126306.42146587 397072.147795239 5126280.82755525 397075.835099479 5126244.82733626 397081.647381872 5126200.82706453 397092.459782577 5126161.82680651 397103.334705913 5126125.82656536 397121.772332701 5126100.82636484 397132.772294143 5126069.82615172 397148.834882151 5126044.82595783 397160.553757661 5126035.20086627 397179.272708267 5126019.82571988 397202.647953329 5125999.82553214 397233.335833894 5125981.82533342 397269.086369297 5125973.82517735 397305.337011941 5125979.82510165 397344.087731071 5125990.82504784 397373.463344054 5126008.82506407 397397.963862016 5126024.82508369 397425.151973375 5126047.82513668 397438.089904983 5126078.82528037 397444.027755832 5126114.82547489 397445.590639645 5126165.82577112 397454.091060634 5126205.82598176 397460.091433225 5126244.8261941 397468.529352856 5126284.82640523 397471.34202389 5126302.60775191 397474.529718163 5126322.82661191 397494.655252618 5126351.82672409 397507.593182574 5126382.82686947 397527.781224448 5126412.82698805 397545.344180905 5126436.82707907 397565.46972113 5126466.82719851 397578.407636095 5126495.82733311 397591.595617786 5126533.82752065 397604.4710243 5126561.82764997 397612.783911683 5126597.82784006 397618.971812944 5126640.82807793 397627.534752913 5126683.82830922 397628.847581176 5126727.82856701 397635.035482062 5126770.82880521 397643.3483687 5126806.828996 397645.004726745 5126818.4540605 397649.473768279 5126849.82923463 397657.786647643 5126884.82941976 397670.912112201 5126920.82959777 397690.850103905 5126944.82968593 397703.850524161 5126974.8298291 397721.601028402 5127005.82996553 397741.664049093 5127033.83007812 397761.664540702 5127057.83016732 397766.539781408 5127081.11154329 397769.602433453 5127095.8616232 397772.545330568 5127866.83496574 397799.55716051 5129508.84465574 397831.568827347 5131116.8540907 397844.579951222 5132687.86328606 397841.591240943 5134313.87274973 397847.602616648 5135930.88208476 397871.614199177 5137540.89132351 397907.625956819 5139153.90054444 397932.637595763 5140770.90973277 397947.649143106 5142391.91887313 397962.660579673 5143995.92785993 397972.671962545 5145598.93676736 397971.683228179 5147199.94555985 397981.694931268 5148843.95455868 397986.706260507 5150439.96320876 397990.753525199 5152039.92440306 398061.802940095 5153673.8844116 398044.852873508 5155360.84277007 398049.901485214 5156996.80243326 398075.949416946 5158601.76287673 398059.997632782 5160238.72242226 398074.045935741 5161865.68223921 398079.094836043 5163519.64134919 398121.172223473 5165059.66575611 397524.818123527 5165067.79049237 397026.153268514 5165076.32148286 397059.169441951 5166697.56308368 397074.216493664 5168318.52340502 397070.262855338 5169930.48393691 397080.309523306 5171545.44435402 397136.356979965 5173154.40478628 397156.403121981 5174745.3656852 397292.452470757 5176353.32576343 397351.500174909 5177964.28589945 397410.545932918 5179591.26622548 397438.590081989 5181207.25121208 397484.635123672 5182839.23587902 397568.67961072 5184411.22069788 399155.722151603 5184365.20819777 400767.765827735 5184336.19538155 402376.809351054 5184305.18266293 403893.850467498 5184279.17067505 405509.88661979 5184240.16416644 407127.917199638 5184205.16237558 408731.947575327 5184173.16060055 410320.977603268 5184140.15890349 411927.0077774 5184102.15730687 413468.035170976 5184019.156598 415034.06331545 5183946.15575987 416630.092083367 5183876.15490039 418239.122759583 5183856.15320425 419845.153118906 5183829.1516743 421418.182848745 5183803.15020699 423021.215323013 5183838.14759326 424640.227328401 5183826.1287231 426250.225657675 5183796.09869613 427926.224039936 5183768.06739585 429532.222317095 5183736.03751201 431126.220916499 5183713.00771019 432729.219448619 5183687.97779001 434321.217792016 5183656.94819719 435909.216377732 5183632.91857415 437519.214606452 5183597.88873491 439133.213072692 5183569.8587156 440447.274474624 5183551.58421118 440788.211689919 5183546.82785545 440774.193317489 5182959.24389991 440750.161804751 5181951.85443125 440731.830135607 5181339.36469896 440702.111525844 5180345.88134396 440684.750599837 5179797.67179249 440651.06097089 5178732.9083982 440650.699677025 5178172.94869223 440650.014973456 5177123.92495227 440637.563766231 5176535.7995613 440615.977504472 5175516.92387936 440604.370555919 5174951.2984902 440582.9399676 5173908.92276828 440572.989475617 5173352.60984766 440553.902074748 5172286.92153435 440537.889487585 5171749.7025147 440506.865079036 5170708.92074466 440497.446274702 5170172.6390742 440478.827657615 5169110.91948283 440467.877617866 5168576.200343 440445.789838809 5167498.91830244 440442.465107261 5166975.79273044 440435.75289353 5165918.916557 440429.239983656 5165367.88476372 440416.715119515 5164306.91495392 440422.825660397 5163685.13271532 440432.67738969 5162683.9123425 440435.976045197 5162089.00518069 440441.639697625 5161063.90983245 440435.50090148 5160474.87791456 440428.731220104 5159825.84576899 440394.891556092 5159824.69064082 440168.295395738 5159825.88464183 439928.95258192 5159831.79768159 439920.105839013 5159851.92304252 439837.293205181 5159883.92545398 439428.658644014 5159666.93696318 439389.43905896 5159649.78182603 438955.523526871 5159460.20043565 438868.021643891 5159421.9529385 438820.677249212 5159416.79805414 438546.704763059 5159386.9622125 437912.69554087 5159295.9805468 437842.257240392 5159295.10758917 437834.549029165 5158459.98268407 437837.784713312 5157878.73248683 437843.509384072 5156849.98210987 437843.494396201 5156242.79447432 437843.469251102 5155223.98172365 437837.429981925 5153635.98146622 437791.389300783 5152014.98244466 437697.348137997 5150407.98503925 437702.333741618 5148765.97566464 437727.330981757 5147211.9625931 437726.327686801 5145591.94983279 437725.324428085 5143976.93706535 437725.321201069 5142354.92416177 437736.318211385 5140725.91078311 437718.314733817 5139136.89865929 437698.311182421 5137532.88643811 437665.307315615 5135919.8745398 437648.303832046 5134323.86219173 437641.300538971 5132700.84923972 437635.297323898 5131096.83636224 437625.294012361 5129486.82352584 437598.290210678 5127849.81099969 437573.286513144 5126246.79863957 437546.282736399 5124637.78625312 437519.278954217 5123033.77386323 437509.98489396 5122463.40794018 437527.027817008 5122305.58004155 437534.527896677 5122230.61041166 437549.528288354 5122205.1096879 437591.404435887 5122162.35790414 437614.748826392 5122138.54440989 437637.155825486 5122098.543979 437649.749976677 5122084.512416 437689.782536252 5122024.98029865 437750.12819346 5121963.47875683 437838.380916 5121901.57002048 438017.948835643 5121826.06454523 438058.606268627 5121828.21939093 438155.890192362 5121903.34042007 438237.736223155 5121953.39968798 438306.488190201 5121972.92841773 438377.709007713 5121979.89467277 438461.242758608 5121953.57955277 438496.493851218 5121925.35985063 438536.401429659 5121851.26540118 438546.089318335 5121802.82800448 438548.558156946 5121795.26548809 438582.028332704 5121589.10994768 438596.591390315 5121527.9850023 438608.466924173 5121441.5166267 438623.813339239 5121376.09834029 437492.278289034 5121376.77370461 437489.281897405 5119808.78685956 437484.285556978 5118193.80044963 437485.289502675 5116528.81424446 437456.292405097 5114947.82823075 437452.2960581 5113347.84157795 437431.299201951 5111764.85524216 435862.25607009 5111768.89945371 434242.211499074 5111795.9449713 432640.167442508 5111821.99004314 431057.123883495 5111860.03457731 429450.079784996 5111869.07996791 427689.031503852 5111876.12973772 426075.987253384 5111896.17531676 424471.943303663 5111909.22068335 422855.899076511 5111917.26641124 421230.245048103 5111933.30087059 419693.843452792 5111956.33283067 417964.469828952 5111966.36879395 416363.067141303 5111988.40214818 414771.7584298 5111973.43514807 413159.168052034 5111993.46874153 411548.296462609 5112009.50229384 409948.518902999 5112091.53610421 408231.145662077 5112170.57246601 406647.680959646 5112207.60578157 405044.934660928 5112231.63941539 403453.563699325 5112279.67291954 401873.540795608 5112322.6780784 400243.517022892 5112330.68303475 398556.492460839 5112347.68827534 396933.468840334 5112364.69334166 395351.445842091 5112389.69839127 393853.36157894 5112421.64078434 393859.299199886 5112441.70349511 393847.736572546 5112465.70380383 393843.674086977 5112508.70430647 393837.111552817 5112544.70473691 393845.049242344 5112587.70520303 393850.486883488 5112623.70559688 393863.112129893 5112659.70596873 393882.862472251 5112690.70626172 393895.237694829 5112714.70649737 393914.988037748 5112745.70679013 393932.300840051 5112773.70705606 393951.926169584 5112797.70726924 393969.238977644 5112828.70756912 393996.051911514 5112851.70774863 394013.302206987 5112875.70796879 394033.052551765 5112906.70826081 394045.552790225 5112937.70857504 394058.178039574 5112973.70894566 394065.990716505 5113008.70931965 394078.553456494 5113039.70963341 394091.116196692 5113070.70994707 394103.741446914 5113106.7103173 394121.054257676 5113137.71061607 394135.992030064 5113166.71089934 394148.492270238 5113197.71121282 394159.961246877 5113229.555289 394160.023832358 5113276.71207453 394160.086424654 5113327.68140335 394149.617585741 5113364.68185631 394144.680060856 5113391.71342881 394133.367462626 5113430.71390723 394126.742428434 5113466.71433695 394110.492242135 5113497.71474007 394104.117234372 5113546.7153168 394104.867321865 5113589.715803 394093.492216285 5113625.71624779 394082.117110468 5113661.71669265 394077.929611646 5113697.7171149 394071.4295835 5113736.71757855 394060.054477088 5113772.71802356 394048.67937044 5113808.71846863 394042.054334609 5113844.71889871 394042.804423075 5113888.71939632 394043.554509784 5113931.71988254 394051.429691031 5113967.72026654 394056.929849101 5114010.72073754 394069.555101945 5114046.72110623 394077.367782725 5114082.72149018 394090.055540472 5114120.72188119 394090.743123231 5114161.72234455 394098.74331963 5114204.72280715 394099.493406947 5114247.72329291 394104.993565904 5114290.72376339 394124.743913448 5114318.72401772 394137.244157168 5114349.72432931 394149.869411885 5114385.72469713 394167.682245546 5114421.88129988 394186.807568417 5114440.72520192 394211.245479328 5114463.72538385 394237.995918334 5114482.72551285 394267.121393583 5114501.72563407 394298.496888663 5114512.72565728 394322.809787916 5114529.72577122 394354.372799104 5114547.72587293 394383.373260707 5114559.72591491 394414.87377337 5114578.72602795 394446.31177054 5114589.72605056 394477.812278199 5114605.72612945 394506.812740696 5114617.72617113 394531.250660501 5114643.7263858 394550.876001888 5114666.72658206 394563.376246602 5114695.72686919 394571.313948641 5114738.72732926 394596.001896305 5114776.72767818 394601.377046541 5114812.7280673 394597.377067299 5114855.72856603 394590.752034629 5114891.7289943 394579.376931218 5114928.72944943 394566.470547747 5114962.32362117 394551.626620873 5114988.73021814 394532.87638519 5115015.7305847 394514.126143602 5115039.73091745 394490.500829059 5115064.73127761 394466.875503023 5115083.73157005 394448.125269927 5115112.73195959 394424.562455412 5115137.73231986 394408.249755359 5115164.73267895 394389.49952137 5115193.73306878 394370.874292663 5115224.73348092 394354.499087194 5115249.73381784 394330.873768359 5115273.73416751 394292.935731185 5115298.73457599 394269.247901644 5115317.73486951 394252.872695053 5115342.73520681 394239.060047403 5115378.73566023 394222.747343077 5115404.7360088 394204.059609094 5115434.73641064 394187.809414129 5115465.73681579 394169.121683087 5115497.73724048 394157.621557243 5115526.73760732 394138.933823844 5115557.73802086 394127.496203812 5115589.73842162 394111.183502991 5115618.73880474 394097.37084405 5115649.73920224 394088.55823042 5115662.61437765 394080.933132024 5115673.73952926 394062.307899905 5115705.73995438 394046.057702473 5115736.74036029 394034.557574845 5115765.74072766 394020.682415429 5115797.74113709 394004.494726822 5115833.74159972 393997.869679337 5115865.74198489 393986.494564888 5115901.74243145 393975.119453643 5115939.74290076 393963.744340432 5115976.7433588 393952.306715737 5116007.74374905 393933.618974614 5116036.74414123 393917.243760681 5116060.74446893 393893.680939688 5116087.74485512 393874.86818897 5116112.74520261 393861.180482468 5116116.74529445 393854.61792906 5116145.74564587 393850.430407537 5116171.74595519 393841.930304956 5116189.58993661 393825.117594874 5116220.74659747 393813.554946164 5116239.74685252 393797.054710209 5116252.74705632 393778.241944662 5116269.74731346 393761.866720345 5116288.74758506 393747.866531327 5116306.74783726 393731.491306684 5116325.74810897 393712.553531926 5116338.74832133 393696.178306954 5116357.74859315 393670.302942922 5116382.74896571 393653.802704186 5116394.74915854 393642.240055644 5116414.74942545 393623.552301824 5116438.74976227 393611.927147149 5116455.74999538 393600.552012397 5116482.75034137 393588.926857469 5116499.75057455 393577.489216607 5116523.75088674 393565.926567222 5116543.75115391 393554.36391611 5116562.75140974 393542.86377383 5116586.75172227 393519.113442233 5116612.84585085 393512.488355425 5116623.75224775 393500.925705356 5116643.75251513 393482.112936403 5116660.75277343 393465.550194804 5116672.75296711 393439.424804218 5116685.75320523 393415.736950249 5116697.75342361 393391.86158697 5116705.75359715 393368.111233285 5116718.75382724 393344.360877897 5116730.754046 393320.548015241 5116738.75421946 393301.610235368 5116750.75442168 393277.859881082 5116763.754652 393254.109525117 5116775.75487097 393235.171746349 5116788.75508474 393211.483891073 5116800.75530361 393192.546112027 5116813.75551748 393175.983368809 5116825.75571176 393149.857976147 5116838.75595065 393133.482745994 5116857.75622424 393114.544966382 5116870.75643831 393098.169735903 5116889.75671202 393086.419569485 5116902.75690122 393067.606797293 5116919.75716067 393056.231655549 5116945.75749706 393037.418884445 5116963.75776805 393033.04384287 5116982.75800023 393021.606196787 5117006.75831414 393015.106140246 5117038.75870223 393008.418569061 5117062.75899965 393004.168536393 5117086.75928857 392997.668478094 5117117.75966531 392993.543454455 5117146.76001093 392987.043397381 5117178.76039914 392987.793453825 5117209.76075054 392988.418505414 5117238.76107952 392989.168561865 5117269.76143089 392989.668601508 5117291.82418106 392989.981126498 5117305.76183911 392985.918606405 5117336.76220736 392986.731171 5117372.76261556 392987.418726433 5117403.76296708 392988.168784299 5117435.76332978 392981.606221287 5117464.76368403 392982.29377667 5117495.76403552 392983.043833052 5117526.76438677 392978.918811594 5117557.76475526 392972.418749256 5117586.76510935 392973.106305979 5117618.76547222 392961.668657377 5117642.76578678 392957.418623605 5117666.76607586 392943.54343573 5117690.76639915 392927.168201979 5117710.76668571 392915.418030818 5117722.76686452 392891.855181635 5117742.76717676 392872.917395103 5117754.76738123 392740.790424309 5117861.76907524 392717.040059422 5117873.7692973 392698.28978547 5117893.76959306 392681.727035677 5117905.76978954 392662.914256339 5117922.77005132 392651.16408497 5117935.77024211 392632.413809005 5117954.77052666 392608.288447914 5117974.89584341 392608.475965431 5117985.83346794 392585.663132786 5118011.77134664 392574.100471765 5118030.77160564 392562.600318191 5118054.77192172 392543.787538836 5118072.7721954 392532.224877397 5118091.77245454 392520.724723346 5118115.77277076 392509.162062944 5118135.77304143 392497.724409603 5118159.77335752 392486.161748931 5118179.77362828 392474.724095295 5118203.77394446 392463.223940494 5118227.77426091 392456.411352287 5118244.77448028 392443.81744214 5118278.61866355 392440.723664055 5118295.77512132 392426.910971326 5118319.77544629 392422.785945318 5118351.77582793 392416.160868597 5118375.77612696 392411.910830245 5118399.7764174 392405.410764244 5118430.77679624 392401.160725746 5118454.77708672 392394.660660804 5118486.77747706 392390.410622159 5118510.77776756 392383.848052215 5118539.7781238 392379.723024262 5118570.7784941 392380.473076701 5118602.77885811 392381.160626871 5118633.77921086 392381.973185368 5118669.77962043 392382.66073303 5118698.77995023 392383.348283211 5118729.78030293 392388.910912823 5118760.78063776 392389.598463053 5118791.78099041 392397.47362799 5118820.78129376 392398.286186632 5118856.78170317 392398.973736932 5118887.78205574 392399.723788257 5118918.78240806 392400.536346912 5118954.7828174 392394.036280934 5118986.78320784 392394.723831189 5119017.78356036 392402.786508491 5119053.7839429 392403.411555271 5119082.78427269 392408.849177143 5119108.78455032 392417.411893277 5119168.78520562 392417.974432822 5119192.7854783 392411.474365244 5119223.78585728 392407.349337824 5119255.78623893 392408.036884392 5119283.78655692 392408.911947902 5119322.78700013 392414.349572639 5119350.78730042 392415.224633688 5119387.78772067 392411.099604812 5119418.78809085 392411.787155176 5119449.78844309 392405.349588049 5119480.78882191 392405.974634815 5119509.78915149 392406.84969828 5119548.78959456 392407.537246085 5119577.78992386 392408.224796407 5119608.79027604 392409.037355083 5119644.79068494 392416.975025357 5119675.79100988 392417.66257575 5119706.79136198 392423.162703331 5119735.79167309 392423.850253773 5119766.79202514 392431.787924406 5119797.79234988 392437.10054279 5119821.79260439 392437.85059438 5119852.79295612 392440.631903442 5119863.0118125 392445.725761732 5119881.79325808 392451.225892287 5119912.79359182 392459.163563436 5119943.7939163 392459.663602176 5119967.79418881 392465.16373042 5119996.79449956 392473.101401848 5120027.79482389 392473.78895269 5120058.79517564 392481.726624313 5120089.79549988 392482.351671638 5120118.79582895 392483.101723595 5120149.79618038 392483.914282962 5120185.7965887 392484.601833886 5120216.79694033 392485.414393263 5120252.7973486 392486.164446509 5120284.79771139 392486.977005895 5120320.79811962 392492.477137348 5120351.7984528 392493.039677325 5120375.79872483 392500.977349717 5120406.79904862 392506.414977796 5120435.79935907 392514.352650416 5120466.79968275 392526.915390478 5120489.79989728 392539.353123455 5120508.80006657 392551.915865102 5120532.8002924 392564.353598353 5120551.80046157 392583.978948531 5120567.80056886 392600.010505845 5120597.11334179 392608.979424349 5120610.8009635 392621.417158159 5120629.80113245 392641.042509008 5120645.80123949 392658.105311672 5120657.80131071 392677.949415731 5120673.20766002 392702.106091439 5120687.8014834 392721.731446962 5120706.80162438 392738.856751236 5120718.80169515 392758.419602039 5120734.80180206 392775.544906569 5120746.80187274 392795.10775498 5120760.80195676 392814.670606259 5120776.8020635 392831.795911176 5120788.80213404 392851.421266561 5120806.80226318 392871.046620767 5120823.80238087 392883.484356665 5120842.80254903 392900.734673902 5120861.80269853 392908.547337548 5120884.80292997 392921.110082889 5120908.80315436 392926.422705908 5120932.80340675 392927.23526959 5120968.80381304 392923.17274389 5120999.80418134 392923.860299875 5121031.80454259 392917.360232791 5121062.80492038 392913.110194025 5121086.80520984 392901.672533419 5121110.80552728 392894.984954546 5121135.80583765 392883.547293661 5121159.80615517 392879.297254538 5121183.80644472 392872.609673993 5121207.80674378 392873.484742288 5121246.80718397 392874.172292332 5121274.80749975 392886.79754389 5121301.80775747 392899.172776234 5121317.80789102 392911.673014952 5121336.80805814 392924.235761778 5121360.8082818 392936.798508767 5121384.8085054 392949.23624684 5121403.80867259 392968.861603252 5121419.80877747 392981.299341611 5121438.80894455 393001.049710309 5121461.80912832 393010.924899806 5121476.90301098 393025.925184951 5121497.80943949 393038.362923867 5121516.80960635 393058.113293343 5121539.80978982 393070.613533636 5121558.80995632 393082.988769071 5121575.81010056 393107.301699889 5121586.81012968 393126.864554048 5121600.81021148 393143.927362765 5121612.81028039 393163.552721167 5121628.81038452 393175.990461243 5121647.81055094 393195.67832541 5121666.81068871 393208.24107521 5121690.81091119 393225.428892612 5121706.81102468 393244.929243869 5121718.81108366 393269.117168119 5121725.81106744 393300.36770149 5121724.81093268 393316.930465618 5121711.81072005 393340.680854092 5121699.81049043 393366.931291185 5121691.81029627 393395.494260176 5121678.81003645 393426.619784935 5121673.8098571 393457.870317864 5121672.80972254 393493.933433088 5121671.80956902 393525.246476345 5121676.80950206 393549.43439937 5121682.80947448 393580.809942319 5121686.80939592 393604.997867081 5121693.80937958 393629.310800374 5121704.80940789 393653.436221126 5121709.80936915 393672.936572303 5121720.80941637 393697.312011842 5121734.80947815 393714.374823146 5121746.80954619 393734.000184865 5121762.80964918 393758.313120639 5121774.80968847 393782.501044747 5121780.80966054 393813.876588865 5121784.80958162 393845.064623317 5121784.80945833 393869.377557989 5121795.80948618 393893.565484088 5121802.80946941 393913.253352945 5121821.80960556 393930.378664812 5121832.80966169 393949.879019183 5121844.80971963 393974.129453519 5121855.80974747 393980.567088586 5121870.55988801 394006.005040641 5121879.80989136 394035.005558621 5121891.80991148 394061.69354385 5121907.8099857 394090.694062249 5121919.81000568 394122.25713511 5121937.81008288 394153.757708931 5121956.81017145 394178.383194166 5121992.81047819 394222.321522601 5122034.81077535 394246.571967771 5122050.81085858 394270.947420551 5122069.8109749 394295.447896778 5122100.8112253 394315.073277083 5122124.81141642 394339.44873778 5122147.8115773 394355.355301223 5122169.96801237 394376.261957671 5122195.81196876 394395.887337237 5122218.81214828 394413.262692471 5122249.81242635 394432.950587952 5122280.81269506 394452.575970121 5122304.81288546 394469.951326235 5122335.81316318 394494.326789315 5122358.81332314 394513.952172303 5122382.81351323 394533.702570425 5122413.81378107 394550.890411741 5122437.81398072 394570.578303909 5122465.81421501 394587.828650453 5122491.81443659 394607.516545024 5122520.81468184 394620.079319934 5122551.814978 394639.642203691 5122575.81516761 394657.017560798 5122605.81543301 394676.767961315 5122636.8156999 394696.455857359 5122665.81594455 394713.643700911 5122689.81614332 394733.269090836 5122715.8163545 394745.519324584 5122726.81642786 394740.082037153 5122766.81665835 394764.832648369 5122789.81667434 394789.833325575 5122820.81673085 394817.146519537 5122848.81676288 394834.709504156 5122871.81680952 394859.522638279 5122897.81684226 394879.273106525 5122913.81684432 394904.023723511 5122937.81686765 394928.836848953 5122962.81689628 394955.774941809 5122978.81686992 394973.337932572 5123002.81692346 394998.151057066 5123027.81695315 395029.9017329 5123043.81690827 395058.496141839 5123064.81690259 395086.215481581 5123078.81686417 395110.841047887 5123096.81685942 395142.654238941 5123114.81682611 395171.842330564 5123125.81676686 395203.5305036 5123141.81672417 395235.343701373 5123160.81669716 395266.906833568 5123171.81662922 395303.282541552 5123181.81653703 395339.658256907 5123192.8164504 395371.221388458 5123203.81638321 395407.472063324 5123209.81627095 395439.222735558 5123225.81623018 395468.473349008 5123239.81618895 395495.598993273 5123262.81620467 395520.349596002 5123285.81623017 395537.912581366 5123309.81628975 395557.850600111 5123332.81633486 395578.03868312 5123363.81642235 395591.164181148 5123399.81656481 395596.977014847 5123430.81670912 395610.102504936 5123465.81684662 395623.102962563 5123496.81696328 395637.353749434 5123568.81729667 395645.91672001 5123611.81749581 395651.854592615 5123647.81766739 395653.417494831 5123697.81793139 395654.667824093 5123738.81814797 395656.043170504 5123781.81837485 395652.605941696 5123825.81862529 395641.731025185 5123861.81886043 395630.731076702 5123893.81907422 395619.731128427 5123925.81928775 395601.418532393 5123954.81951223 395590.418584587 5123986.8197252 395572.168505251 5124017.8199595 395556.168419549 5124042.82015293 395537.855824659 5124071.82037606 395534.231056787 5124110.82059811 395535.606404653 5124153.82082305 395544.981758839 5124179.53967623 395548.73190043 5124189.8209675 395561.669832457 5124217.82107007 395574.607786881 5124248.82118892 395592.420824241 5124279.8212903 395607.796319737 5124310.82140083 395625.484331816 5124338.82148718 395645.672408739 5124369.82158095 395663.42294382 5124400.82168386 395683.423456846 5124423.82173593 395703.549031724 5124454.821831 395721.112002747 5124477.82189239 395745.67504009 5124493.82189127 395772.800673097 5124516.8219192 395958.867494766 5124673.13461351 395977.555427812 5124688.82213398 396009.118543949 5124699.82208402 396040.931715948 5124717.82207188 396077.057357066 5124721.82196805 396120.495636621 5124727.82184993 396168.496434268 5124725.82167189 396211.684657849 5124724.82151611 396254.997912928 5124727.82138216 396291.248570403 5124733.82128959 396327.436734009 5124740.82120298 396363.812422571 5124750.8211327 396402.375604091 5124754.82102145 396438.751299561 5124765.82095723 396474.93945521 5124771.8208658 396511.315150251 5124782.82080208 396542.878263716 5124793.82075525 396579.253958297 5124804.82069207 396618.004692763 5124815.820621 396642.630239036 5124833.82063855 396667.130768482 5124849.82064543 396698.94393558 5124867.82063893 396716.506905183 5124891.82071572 396741.25748856 5124914.82076257 396768.383111651 5124937.8208017 396786.133633971 5124968.82091883 396794.321494945 5124999.82106858 396813.38483359 5125071.82141678 396826.385275015 5125102.82155089 396839.510747052 5125137.82170776 396854.8862279 5125168.82183446 396860.76158493 5125204.82202163 396869.136890501 5125227.82212598 396873.887063443 5125240.82218496 396882.324977473 5125278.82237547 396888.387873065 5125319.82259116 396896.950824709 5125362.82281031 396898.263654907 5125405.82305318 396904.451566561 5125448.82328028 396893.576642937 5125484.82352222 396889.889346691 5125521.82374655 396878.889385499 5125552.82395972 396860.639310797 5125584.82420152 396842.389214871 5125613.82442575 396819.201529806 5125641.82465958 396802.951381453 5125658.82480822 396772.513554689 5125683.82504716 396749.138309812 5125703.82523489 396725.700564154 5125723.82542252 396695.075184765 5125741.82562109 396671.63743966 5125761.82580809 396647.319162537 5125787.41633249 - - - - 495302.815676504,5179229.61132198 496848.851735509,5179237.6171233 498462.889373269,5179247.62316423 500088.927078579,5179251.62748838 501695.962547851,5179211.60507996 503301.998167785,5179179.5824689 504914.034421812,5179180.55899068 506539.070830495,5179170.5356119 508151.107766549,5179225.51104065 509763.143811634,5179209.48807252 511387.180069969,5179185.46510066 513009.216520757,5179180.44179076 514626.252972295,5179185.41839672 516306.291369745,5179249.39311185 517916.328271882,5179332.36865748 519394.355935139,5179375.34611238 519525.325264365,5179380.28135453 521175.36375734,5179442.31544096 522796.370766589,5179501.28761151 524404.377615024,5179556.26010977 526019.384250467,5179566.23320789 527600.390098711,5179330.21047239 529189.396799056,5179301.18453868 530787.403635033,5179294.15814945 532381.410489906,5179317.13142772 533990.417465329,5179274.10537635 535605.424529336,5179255.07890249 537221.431611674,5179254.05218577 538756.412126805,5179248.02907838 540430.345259956,5179248.00759231 542032.28124317,5179264.98679513 543650.216504964,5179203.96679193 545321.149602686,5179201.94532802 546914.085935204,5179232.92441706 548516.021850388,5179243.90363668 550123.957608117,5179265.88261581 551741.892997035,5179287.86144805 553330.828407997,5179198.84213875 553351.810650603,5177595.86318564 553355.791643031,5175981.85334717 553383.771651848,5174368.84314128 553403.752034889,5172759.83301632 553427.732396188,5171162.82285219 553439.712858505,5169533.81262435 553470.693821533,5168011.80270507 554148.541998444,5167985.04144484 554149.79188147,5167979.13513634 554151.166735834,5167971.1663125 554174.155182149,5167046.78496991 554183.46475896,5166824.59587825 554191.772036319,5166399.53048851 554223.377252946,5164789.42574919 554224.189225934,5164746.42545538 554232.364692507,5163730.35619613 554234.549012593,5163461.97940743 554236.857683187,5163137.75850086 554240.601430421,5162608.34872624 554244.906755111,5162000.96967673 554246.778649942,5161738.18667267 554248.338695482,5161530.7477857 554248.525869733,5161503.15385152 554248.775540927,5161475.49741577 554251.271266753,5161113.58874818 554252.831221565,5160898.33730785 554253.579917212,5160787.86781934 554255.575923938,5160448.74055673 554255.700630369,5160423.74039029 554257.260422794,5160194.48885564 554259.007522042,5159949.14346083 554259.132296334,5159930.01833279 554259.381916446,5159897.95561735 554264.935552704,5159149.07558582 554270.426787606,5158408.69560226 554271.300335202,5158285.91352566 554274.045944533,5157915.09852562 554280.84758196,5156997.90483189 554282.532351766,5156767.34077324 554283.281150991,5156665.96508748 554287.274622583,5156114.61760652 554292.641004632,5155387.23767468 554294.825056096,5155096.329449 554295.012231495,5155068.89176298 554300.501530121,5154162.38562499 554303.745101346,5153617.78818249 554304.306478476,5153522.66253715 554304.556081921,5153489.22480916 554304.743230328,5153459.47460703 554312.041320595,5152239.34131381 554314.349359272,5151861.83874214 554323.893317074,5150293.26553368 554305.826173649,5149840.20040545 554302.700056984,5149446.01108743 554301.949803335,5149356.10442308 554302.135468315,5148767.66409191 554302.135402434,5148746.47648999 554302.822634196,5148667.69484551 554307.256891665,5147673.72120305 554308.068781662,5147486.59528035 554310.067648001,5147144.15607869 554319.374803053,5145529.42927739 554328.619462153,5143917.07743959 554332.054989073,5143322.07444199 554337.614206444,5142331.100688 554337.864068976,5142289.7879786 554338.986979247,5141635.15971549 554339.673131105,5141212.81385632 554339.735131423,5141054.4380685 554342.209073819,5140666.37355679 553744.439883277,5140665.6359454 552140.489637614,5140654.66904886 550514.540006892,5140624.70248202 548910.589773269,5140611.73553649 547286.07778693,5140615.76910864 545689.439928457,5140613.80205839 544190.486586884,5140616.8330177 542576.911810792,5140615.86630563 540952.837370015,5140612.89978375 539356.887082251,5140610.93267754 537734.925434632,5140604.9619813 536127.946556834,5140608.98539251 534329.970129577,5140608.01152846 532718.366168833,5140591.034837 531115.012187083,5140590.05813077 529512.033176919,5140583.08137621 527905.054220142,5140572.10465667 526302.075232683,5140570.12792372 524724.095912882,5140574.15084742 523113.117017892,5140575.1742278 521506.138065647,5140576.19754254 519900.159148136,5140564.22079982 518289.159252459,5140559.22819305 516683.142984441,5140571.22329294 515111.689717197,5140557.21843482 513527.89233112,5140574.21367801 511910.000819644,5140589.20884539 510293.828064161,5140601.204038 508669.592740126,5140609.19921645 507083.889113586,5140611.19450178 505559.498296073,5140634.19012381 503943.013177162,5140629.18532095 502322.652996529,5140626.1805358 500702.480180676,5140631.17582888 499099.925449201,5140637.18350592 497493.839733782,5140624.20112631 495769.747660932,5140613.22013602 495748.719955069,5142239.23124588 495748.693082425,5143884.24220147 495755.667156541,5145494.25280909 495760.64120287,5147100.26336865 495773.615683926,5148704.27380344 495770.605990571,5150333.28983519 495747.61601901,5151951.3123082 495746.626973123,5153550.33429246 495734.637160115,5155107.35571706 495738.648547533,5156735.37796876 495717.658886368,5158361.40025725 495797.673211287,5159977.23447586 495178.648737239,5159980.6429203 495145.659310535,5161586.4456535 495107.669755823,5163187.46698448 495112.681912028,5164799.4883054 495086.692865267,5166393.50936063 495088.705029187,5168017.53073455 495067.716229818,5169609.55161623 495126.729927639,5171207.57265376 495162.742991802,5172830.59400039 495197.755906868,5174450.61531256 495199.767500209,5176019.63582349 495238.783334567,5177631.64792968 495302.815676504,5179229.61132198 + + + + 495067.716229818 5140557.21843482554342.209073819 5179566.23320789 + 495302.815676504 5179229.61132198 496848.851735509 5179237.6171233 498462.889373269 5179247.62316423 500088.927078579 5179251.62748838 501695.962547851 5179211.60507996 503301.998167785 5179179.5824689 504914.034421812 5179180.55899068 506539.070830495 5179170.5356119 508151.107766549 5179225.51104065 509763.143811634 5179209.48807252 511387.180069969 5179185.46510066 513009.216520757 5179180.44179076 514626.252972295 5179185.41839672 516306.291369745 5179249.39311185 517916.328271882 5179332.36865748 519394.355935139 5179375.34611238 519525.325264365 5179380.28135453 521175.36375734 5179442.31544096 522796.370766589 5179501.28761151 524404.377615024 5179556.26010977 526019.384250467 5179566.23320789 527600.390098711 5179330.21047239 529189.396799056 5179301.18453868 530787.403635033 5179294.15814945 532381.410489906 5179317.13142772 533990.417465329 5179274.10537635 535605.424529336 5179255.07890249 537221.431611674 5179254.05218577 538756.412126805 5179248.02907838 540430.345259956 5179248.00759231 542032.28124317 5179264.98679513 543650.216504964 5179203.96679193 545321.149602686 5179201.94532802 546914.085935204 5179232.92441706 548516.021850388 5179243.90363668 550123.957608117 5179265.88261581 551741.892997035 5179287.86144805 553330.828407997 5179198.84213875 553351.810650603 5177595.86318564 553355.791643031 5175981.85334717 553383.771651848 5174368.84314128 553403.752034889 5172759.83301632 553427.732396188 5171162.82285219 553439.712858505 5169533.81262435 553470.693821533 5168011.80270507 554148.541998444 5167985.04144484 554149.79188147 5167979.13513634 554151.166735834 5167971.1663125 554174.155182149 5167046.78496991 554183.46475896 5166824.59587825 554191.772036319 5166399.53048851 554223.377252946 5164789.42574919 554224.189225934 5164746.42545538 554232.364692507 5163730.35619613 554234.549012593 5163461.97940743 554236.857683187 5163137.75850086 554240.601430421 5162608.34872624 554244.906755111 5162000.96967673 554246.778649942 5161738.18667267 554248.338695482 5161530.7477857 554248.525869733 5161503.15385152 554248.775540927 5161475.49741577 554251.271266753 5161113.58874818 554252.831221565 5160898.33730785 554253.579917212 5160787.86781934 554255.575923938 5160448.74055673 554255.700630369 5160423.74039029 554257.260422794 5160194.48885564 554259.007522042 5159949.14346083 554259.132296334 5159930.01833279 554259.381916446 5159897.95561735 554264.935552704 5159149.07558582 554270.426787606 5158408.69560226 554271.300335202 5158285.91352566 554274.045944533 5157915.09852562 554280.84758196 5156997.90483189 554282.532351766 5156767.34077324 554283.281150991 5156665.96508748 554287.274622583 5156114.61760652 554292.641004632 5155387.23767468 554294.825056096 5155096.329449 554295.012231495 5155068.89176298 554300.501530121 5154162.38562499 554303.745101346 5153617.78818249 554304.306478476 5153522.66253715 554304.556081921 5153489.22480916 554304.743230328 5153459.47460703 554312.041320595 5152239.34131381 554314.349359272 5151861.83874214 554323.893317074 5150293.26553368 554305.826173649 5149840.20040545 554302.700056984 5149446.01108743 554301.949803335 5149356.10442308 554302.135468315 5148767.66409191 554302.135402434 5148746.47648999 554302.822634196 5148667.69484551 554307.256891665 5147673.72120305 554308.068781662 5147486.59528035 554310.067648001 5147144.15607869 554319.374803053 5145529.42927739 554328.619462153 5143917.07743959 554332.054989073 5143322.07444199 554337.614206444 5142331.100688 554337.864068976 5142289.7879786 554338.986979247 5141635.15971549 554339.673131105 5141212.81385632 554339.735131423 5141054.4380685 554342.209073819 5140666.37355679 553744.439883277 5140665.6359454 552140.489637614 5140654.66904886 550514.540006892 5140624.70248202 548910.589773269 5140611.73553649 547286.07778693 5140615.76910864 545689.439928457 5140613.80205839 544190.486586884 5140616.8330177 542576.911810792 5140615.86630563 540952.837370015 5140612.89978375 539356.887082251 5140610.93267754 537734.925434632 5140604.9619813 536127.946556834 5140608.98539251 534329.970129577 5140608.01152846 532718.366168833 5140591.034837 531115.012187083 5140590.05813077 529512.033176919 5140583.08137621 527905.054220142 5140572.10465667 526302.075232683 5140570.12792372 524724.095912882 5140574.15084742 523113.117017892 5140575.1742278 521506.138065647 5140576.19754254 519900.159148136 5140564.22079982 518289.159252459 5140559.22819305 516683.142984441 5140571.22329294 515111.689717197 5140557.21843482 513527.89233112 5140574.21367801 511910.000819644 5140589.20884539 510293.828064161 5140601.204038 508669.592740126 5140609.19921645 507083.889113586 5140611.19450178 505559.498296073 5140634.19012381 503943.013177162 5140629.18532095 502322.652996529 5140626.1805358 500702.480180676 5140631.17582888 499099.925449201 5140637.18350592 497493.839733782 5140624.20112631 495769.747660932 5140613.22013602 495748.719955069 5142239.23124588 495748.693082425 5143884.24220147 495755.667156541 5145494.25280909 495760.64120287 5147100.26336865 495773.615683926 5148704.27380344 495770.605990571 5150333.28983519 495747.61601901 5151951.3123082 495746.626973123 5153550.33429246 495734.637160115 5155107.35571706 495738.648547533 5156735.37796876 495717.658886368 5158361.40025725 495797.673211287 5159977.23447586 495178.648737239 5159980.6429203 495145.659310535 5161586.4456535 495107.669755823 5163187.46698448 495112.681912028 5164799.4883054 495086.692865267 5166393.50936063 495088.705029187 5168017.53073455 495067.716229818 5169609.55161623 495126.729927639 5171207.57265376 495162.742991802 5172830.59400039 495197.755906868 5174450.61531256 495199.767500209 5176019.63582349 495238.783334567 5177631.64792968 495302.815676504 5179229.61132198 - - - - 495769.747660932,5140613.22013602 497493.839733782,5140624.20112631 499099.925449201,5140637.18350592 500702.480180676,5140631.17582888 502322.652996529,5140626.1805358 503943.013177162,5140629.18532095 505559.498296073,5140634.19012381 507083.889113586,5140611.19450178 508669.592740126,5140609.19921645 510293.828064161,5140601.204038 511910.000819644,5140589.20884539 513527.89233112,5140574.21367801 515111.689717197,5140557.21843482 516683.142984441,5140571.22329294 518289.159252459,5140559.22819305 519900.159148136,5140564.22079982 521506.138065647,5140576.19754254 523113.117017892,5140575.1742278 524724.095912882,5140574.15084742 526302.075232683,5140570.12792372 527905.054220142,5140572.10465667 529512.033176919,5140583.08137621 531115.012187083,5140590.05813077 532718.366168833,5140591.034837 534329.970129577,5140608.01152846 536127.946556834,5140608.98539251 537734.925434632,5140604.9619813 539356.887082251,5140610.93267754 540952.837370015,5140612.89978375 542576.911810792,5140615.86630563 544190.486586884,5140616.8330177 545689.439928457,5140613.80205839 547286.07778693,5140615.76910864 548910.589773269,5140611.73553649 550514.540006892,5140624.70248202 552140.489637614,5140654.66904886 553744.439883277,5140665.6359454 554342.209073819,5140666.37355679 554342.233833628,5140666.37358734 554342.358772653,5140648.21724442 554352.603403535,5139042.67776921 554362.910511869,5137431.91946821 554372.34305014,5135950.28679076 554374.092605357,5135825.9111256 554379.778688583,5135430.65900772 554382.215254471,5135157.87632369 554390.399518766,5134210.62133909 554403.706775292,5132676.01947908 554404.206573933,5132616.98791651 554416.451723541,5131196.88662423 554417.451338271,5131084.32352432 554418.388476769,5130978.6979612 554424.011233388,5130321.53820713 554426.322826127,5130056.09928885 554425.135289221,5130034.2866976 554431.509937198,5129978.34879021 554434.009678648,5129918.47343372 554438.13425802,5129821.50410496 554438.696698607,5129807.62902265 554442.759014259,5129784.44132778 554445.571389713,5129769.34744787 554445.008323505,5129586.22150791 554447.257595597,5129376.28287651 554448.632153618,5129248.87593935 554441.694558447,5129159.90685325 554443.569481045,5129151.50052536 554445.506511538,5129020.28105749 554453.316871103,5128413.18400358 554456.003313945,5128103.40108881 554452.814810878,5127761.61811038 554449.438747144,5127399.71002693 554447.437918208,5127123.23986379 554447.062796869,5127082.1146548 554448.562504679,5127002.89546264 554455.184985191,5126267.76648391 554455.184676468,5126171.07847522 554455.058527227,5125810.29532751 554454.054583054,5124569.50753942 554452.79948873,5122971.90532119 554452.172098942,5122223.96383826 554453.484041657,5122060.83794376 554455.674360441,5121405.49590233 554456.362027103,5121363.65225197 554478.679820162,5120033.59289083 554478.99355503,5119750.28113143 554480.875596368,5118133.66033641 554481.377553571,5117684.22399995 554484.944978905,5116540.78940651 554489.701491879,5115028.26197265 554491.139379615,5114932.29344219 554514.833354161,5113333.29707605 554522.335407162,5112827.07946503 554534.589770591,5111770.45689264 554535.027392622,5111740.45695946 554535.652606605,5111688.55082766 554551.658348326,5110300.52273345 554554.159240296,5110084.99196981 554572.353248283,5108514.05798831 554576.292166395,5108172.18374812 554591.234780263,5106936.90520942 554590.672454214,5106899.81156213 554584.799324661,5106499.93766508 554592.616912497,5105303.62790302 554592.429485455,5105287.81544546 554581.933214056,5104483.0363755 554581.186729472,5103682.88207219 554581.249264502,5103674.60084072 554584.189251516,5103093.22717131 554584.564675901,5102994.57114941 554590.691312287,5102594.04071861 554591.253978603,5102553.60330241 554568.629437552,5102545.85383945 554480.818797228,5102497.51221917 554394.758125457,5102448.29556352 554325.69710991,5102404.35975707 554236.511316787,5102396.23682528 554140.200644842,5102390.95780032 554105.951326077,5102381.70861039 554006.203309133,5102354.77347075 553895.642898913,5102350.46352219 553832.456554275,5102357.37120581 553772.707675745,5102356.96632954 553682.584419698,5102343.62468572 553609.335862589,5102326.43891521 553461.77634549,5102272.4737048 553355.153599082,5102208.32008551 553224.156442003,5102109.51087989 553154.032950968,5102059.10638963 553148.845548024,5102059.04400946 553140.658238217,5102049.57547528 553044.910189871,5102007.51530512 552994.223573846,5102023.20392956 552950.661870638,5102027.26742294 552890.975457625,5102034.11253008 552790.97741619,5102010.02115849 552709.666511637,5101989.42934651 552639.980380199,5101971.27475981 552566.481923366,5101925.55784552 552503.358245955,5101886.62192277 552479.483745789,5101871.90376969 552397.110439891,5101828.87455699 552346.799029958,5101787.43834941 552318.924663206,5101756.43909103 552255.488376177,5101747.22183884 552182.302315528,5101725.59860195 552058.804813389,5101669.5703917 551982.556406799,5101620.25981795 551833.559557177,5101511.88862801 551704.874931212,5101372.79832701 551595.689948365,5101229.98884483 551523.941768908,5101086.83474873 551457.818362936,5100977.61791267 551411.319606158,5100864.55688417 551380.82056902,5100746.96424872 551334.821931918,5100594.55959859 551317.760111766,5100486.65411858 551300.573136332,5100424.65473556 551297.510729787,5100413.59234561 551270.386672281,5100281.59343787 551227.387872398,5100157.87612939 551193.451336726,5100054.50228915 551188.951743405,5099958.12772837 551168.140058366,5099827.84742246 551161.578091684,5099704.5667546 551158.953466592,5099607.19215365 551118.89198163,5099519.19341386 551055.705905587,5099432.22647519 551007.831993604,5099362.9466117 550964.520459462,5099305.35409998 550921.771455629,5099235.07412108 550866.022686856,5099163.32571097 550820.898685985,5099103.95200429 550798.024323204,5099033.54655423 550790.587333623,5098917.45339688 550789.52493389,5098892.45351158 550789.087588548,5098847.32868299 550788.71273913,5098803.11009965 550805.400313442,5098689.48510191 550816.71303623,5098559.79778976 550822.838257872,5098458.73550047 550825.588512559,5098365.86076342 550859.713439288,5098204.67300627 550885.463345372,5098095.45401594 550883.026099186,5098031.11055205 550870.339222261,5097908.76754253 550862.339671889,5097814.14307154 550835.527951187,5097718.80031329 550805.028886145,5097594.89524803 550809.654053215,5097518.92665392 550789.154710702,5097426.20873526 550751.530758417,5097304.21009257 550714.906553155,5097254.36742052 550673.844942598,5097198.58738006 550590.721755413,5097080.55860137 550542.160233131,5097036.37245824 550491.973709423,5097001.09257416 550365.163777452,5096878.15865468 550334.852109523,5096778.34727154 550310.727814306,5096684.81696374 550316.290469509,5096604.31712294 550309.728175924,5096574.03614743 550318.978190406,5096518.5673725 550326.790640858,5096491.62977781 550313.228427415,5096473.94267983 550296.916313546,5096439.25571311 550289.041689036,5096361.53744597 550297.291764992,5096291.81874812 550308.541688008,5096255.00610377 550322.354089704,5096211.13092128 550317.291897743,5096139.75631034 550284.542665925,5096071.25738025 550247.668392169,5096038.50842221 550217.23146193,5096020.94674768 550180.419666482,5095994.54151571 550104.296075735,5095955.01231634 549989.673197379,5095894.54666119 549850.988229078,5095831.51912271 549789.114369961,5095799.0207972 549702.17851544,5095738.21071076 549622.054824984,5095752.46266394 549498.119437673,5095744.68455112 549458.745151586,5095727.24810707 549379.121568022,5095701.18770715 549323.247485056,5095709.93907356 549308.747725346,5095711.40818131 549254.561116424,5095719.40950802 549162.812631523,5095730.911762 549121.125806116,5095741.22526522 549075.751533407,5095755.10134605 548969.753307069,5095760.60397996 548872.567449687,5095759.70016915 548831.880561098,5095787.8260719 548759.694280633,5095787.60913109 548668.820810466,5095789.42389983 548559.447587701,5095816.36402521 548491.136141183,5095855.49056886 548439.949388799,5095901.52290282 548366.825545358,5095933.39959453 548304.326424988,5096004.24460061 548194.828244741,5096019.05977103 547988.394076832,5096088.78336742 547861.146149204,5096125.91137619 547703.523643693,5096204.53995125 547698.398724912,5096207.10256733 547469.52754957,5096238.45187426 547259.530969925,5096309.17552288 547100.2835743,5096360.74174086 547009.535044148,5096397.83757056 546897.536815154,5096465.30878043 546758.976469298,5096569.59296632 546667.352936202,5096620.126242 546581.166812912,5096670.47188094 546471.04354446,5096750.53671288 546346.732980185,5096853.82052419 546260.484326146,5096926.29104226 546139.173822117,5096977.26252863 546089.487147772,5096994.38866717 546078.23733479,5096998.26392488 545939.364607453,5097066.89199786 545807.491745403,5097146.23858723 545797.804358794,5097176.51991972 545763.742428123,5097188.208197 545612.307453801,5097245.02412425 545455.622652952,5097256.43416338 545332.499832048,5097230.96857232 545228.189170155,5097213.53372805 545091.754058384,5097199.88090418 544968.568701521,5097195.54020531 544885.945138796,5097192.69850155 544835.133531849,5097184.88729308 544768.38474138,5097150.10787432 544655.636770422,5097098.92342916 544506.514470127,5097016.42755734 544424.703441951,5096975.71105005 544228.894428452,5096899.65380548 544087.771959286,5096826.9702006 543971.711544846,5096760.47344728 543804.589568653,5096641.38451572 543683.904238125,5096561.41921796 543572.968767686,5096452.86010173 543476.28303757,5096352.30059195 543376.097356744,5096256.27239851 543279.286644267,5096130.58805322 543174.538568908,5095996.09146618 543096.290071761,5095825.62569112 543083.540359618,5095754.22018835 543073.415608845,5095676.4709084 543052.603528349,5095608.65933726 543043.041216238,5095582.12848651 543015.604254459,5095506.06713256 543011.541940421,5095386.28670537 543031.791665603,5095319.1928493 543036.104133727,5095278.00548819 543022.416925227,5095215.47495881 542971.167886651,5095111.10187962 542934.293582281,5095029.94705025 542907.294089969,5094971.10433811 542832.670466591,5094831.95081922 542759.109314617,5094698.20349685 542699.047897229,5094604.54934263 542614.611937776,5094444.95871608 542548.363098513,5094370.17961229 542494.551552431,5094293.4939562 542461.364642398,5094242.7138662 542457.677225166,5094215.90162597 542448.739895674,5094187.62077892 542372.488737527,5093978.65562436 542360.801056537,5093946.56242515 542309.112311312,5093767.22140284 542326.921786931,5093532.22280021 542331.920230532,5093405.3799217 542258.045219705,5093304.53883344 542092.232986639,5093107.07581767 541872.735145832,5093003.01966359 541630.736858292,5092838.05828172 541553.486502912,5092713.87367658 541475.23533276,5092524.59583772 541470.733414002,5092365.34716469 541479.8578229,5092328.81596462 541503.418796123,5092234.22234624 541561.729180114,5092132.84666223 541662.539346825,5092063.18842708 541740.162327585,5091990.59329668 541731.286383227,5091902.87544188 541656.411309875,5091809.12802645 541484.160549609,5091550.10303766 541272.41156773,5091394.89071915 541186.974460643,5091332.23705942 541108.474813244,5091274.70818659 541001.850639414,5091224.4612031 540845.164685801,5091177.40293178 540681.479676533,5091195.43809871 540516.857879928,5091265.25415992 540460.733977699,5091289.09912509 540324.04837952,5091289.54000824 540236.11256392,5091323.54193943 540181.426148367,5091347.16812319 540118.489899045,5091374.3257366 539974.430807429,5091474.82858421 539923.306818993,5091495.82970216 539822.308315667,5091501.1759217 539654.62293823,5091484.36770569 539634.060698161,5091482.30573092 539496.874622779,5091447.12188651 539430.625709959,5091458.02970369 539347.252245524,5091483.15659615 538901.82538179,5091775.79062633 538715.641387779,5091830.95113367 538533.645830736,5091945.14211264 538303.400263202,5092009.92830984 538046.343180148,5092111.4023769 537951.0326951,5092148.99809719 537688.287930376,5092230.94117665 537489.541848367,5092289.28916968 537413.793434159,5092317.19699642 537397.856179987,5092317.47861736 537217.859784307,5092372.85743922 537020.613266138,5092403.45558747 536776.616341385,5092364.11782328 536726.866708995,5092340.05665768 536705.741865714,5092329.90097392 536632.492407924,5092294.71543747 536585.867693434,5092268.71671314 536365.056530663,5092145.69150694 536158.431488057,5091953.16646956 535810.494785362,5091686.92653195 535607.868614117,5091436.43308542 535550.054839239,5091309.24785732 535526.054308586,5091256.49880046 535361.30292556,5091030.91054732 535197.739366394,5090827.75961084 534983.302928682,5090708.54677201 534975.990390074,5090700.1095053 534879.614878251,5090589.08132967 534855.799773533,5090416.61438987 534876.608963023,5090239.95892745 534836.043226101,5090017.05524812 534817.790979542,5089870.74423803 534817.039536308,5089785.74487069 534821.414110595,5089764.40117162 534838.974905119,5089678.87012473 534878.597079132,5089545.43265137 534882.406579019,5089372.77755804 534847.715288643,5089123.28018157 534810.713355892,5088981.06333606 534782.586301887,5088839.03377921 534725.023444326,5088773.25437114 534701.7736268,5088765.78622723 534616.83679632,5088738.75718989 534503.588062959,5088724.57248241 534218.779208096,5088715.67306195 534153.842315869,5088700.86221224 534096.780553753,5088699.55107727 534002.906770908,5088697.58457155 533875.907879244,5088664.33783136 533794.657462215,5088579.34038347 533629.220857022,5088505.9073536 533565.158226408,5088450.78428096 533468.471505822,5088422.8180355 533371.5346313,5088386.19561015 533345.222300536,5088376.2588091 533246.098566801,5088374.04243326 533134.100287361,5088387.66999686 533053.351642428,5088403.79679844 532947.789912736,5088369.36206378 532873.540227785,5088332.73910107 532509.166881397,5088161.06154654 532428.354532438,5088111.68883798 532145.980028413,5087939.16560066 532032.104583705,5087835.57533889 531976.791977225,5087791.38948815 531944.729045281,5087745.92184295 531861.791778069,5087701.14290642 531791.854590106,5087669.73856017 531769.729688322,5087659.80166253 531692.105634678,5087657.17853421 531549.482170086,5087641.55705451 531328.546886412,5087609.00007167 531105.424480406,5087595.19300065 530949.301344763,5087588.19677961 530815.239800053,5087548.54403017 530587.989829637,5087399.51933915 530361.739724948,5087245.99466495 530276.613639391,5087134.90379811 530201.425892234,5087073.71856372 530178.238315577,5087054.8755124 530166.925778738,5087045.71960301 530073.112856642,5086964.03497242 529996.049952806,5086894.31860062 529899.73769556,5086845.63377937 529789.363666918,5086825.32407778 529688.740368069,5086848.20131101 529494.493905717,5086904.79927491 529373.49582456,5086925.45826143 529247.684695074,5086915.52384933 529166.184278109,5086843.93260436 529096.933960279,5086785.15346782 529056.24665812,5086769.87331063 528969.434367144,5086726.78197412 528861.121365829,5086635.50402786 528742.122196648,5086604.06962396 528628.436532059,5086625.54093117 528594.562252274,5086640.44787669 528522.688782083,5086672.07435211 528341.693613527,5086799.10894473 528193.946475428,5086849.20584002 528075.822557464,5086830.36506603 528065.510088577,5086825.6466 527999.760301715,5086796.33590466 527940.135041522,5086747.86896365 527913.884925928,5086726.52601027 527900.507649324,5086608.33976038 527905.631045558,5086533.77772395 527908.755069676,5086488.40300583 527969.935319263,5086173.34151323 528006.744198495,5086019.31058801 528031.116158065,5085885.96729806 528016.801707287,5085783.03094922 527981.988494533,5085728.40721481 527891.613954849,5085698.78462118 527780.553104804,5085714.8496666 527660.617419261,5085733.66490349 527562.118626276,5085735.44850864 527432.244961223,5085725.51421095 527337.370899841,5085716.54781397 527247.871960968,5085716.48746736 527197.685451768,5085735.26977585 527128.748771501,5085735.30268376 527083.999147679,5085727.92881864 527031.187090902,5085719.21140819 526951.500687246,5085726.3070187 526862.876663815,5085722.71542908 526789.440092505,5085725.37342445 526707.128588975,5085726.25039747 526663.191266112,5085710.06408344 526576.441035807,5085651.03539149 526470.815790519,5085581.1322417 526398.440800242,5085541.72804887 526267.8143935,5085404.73229071 526208.813406882,5085326.82808613 526133.687661253,5085251.61174947 526005.749479571,5085151.30313868 525934.18575,5085056.33687744 525876.997590496,5084995.55749565 525774.059986827,5084936.34170608 525712.122429799,5084901.09348486 525643.434864606,5084862.03295775 525563.809308518,5084794.94167141 525527.18311805,5084721.47439883 525480.432353319,5084662.3197558 525445.806784436,5084618.47719655 525307.180536708,5084490.45033238 525256.180183479,5084448.35815621 525164.929648197,5084377.67343567 525114.804138952,5084329.23754085 525078.178360449,5084275.55136234 525065.676875733,5084202.17725981 525082.799247978,5084092.02148807 525136.731363179,5083875.36568599 525150.229969059,5083818.95956524 525119.91607812,5083741.08593065 525083.227968253,5083695.49343971 525015.22749572,5083640.87053201 524881.853261333,5083610.34276616 524797.728752767,5083591.56371031 524684.103419219,5083521.6607867 524516.790512188,5083423.13440168 524406.727079277,5083329.13784184 524348.539358438,5083291.73331102 524257.320423798,5083240.45469684 524072.975713012,5083111.52273351 523995.193273789,5083022.90035144 523870.536556867,5082944.74777554 523849.317726914,5082931.46715093 523746.442946063,5082893.84496389 523675.754916731,5082838.34714099 523572.034805653,5082731.72554414 523465.503325469,5082673.57236842 523351.877500948,5082586.70085376 523287.471129895,5082552.67145458 523219.471600665,5082542.76694407 523170.222398242,5082555.36179053 523102.160700595,5082559.7696632 523019.817631392,5082552.58422999 522925.817890391,5082522.11802415 522847.911523316,5082482.71400065 522779.068248294,5082472.80951167 522676.099132467,5082412.00002842 522583.972869627,5082317.87805913 522510.751757,5082185.41219931 522445.407215215,5082123.60180991 522355.938355149,5082080.63560336 522304.90702684,5082055.54330932 522268.0,5082010.16958982 522245.905907833,5081983.01410646 522218.24799108,5081900.70296995 522151.183405212,5081784.23683287 522118.058565398,5081777.14395229 522107.652081143,5081762.89432596 522050.119530341,5081683.99014334 521959.836363481,5081565.80584201 521904.427080188,5081415.40220842 521806.050176923,5081295.40562429 521736.361320744,5081210.37679555 521638.798921699,5081175.37948123 521552.047630877,5081086.7573533 521509.171192366,5081009.69655305 521500.263137414,5080930.91618412 521420.729350447,5080793.98178856 521339.321128633,5080680.26599542 521330.444228291,5080597.89190719 521312.629500438,5080498.51818188 521232.189330561,5080357.02135212 521149.00133893,5080305.0863367 521079.311686957,5080189.83902419 521064.154908118,5080162.30837969 520984.527127586,5080017.87406021 520943.711927634,5079891.5323831 520911.491440783,5079808.19013152 520845.333744257,5079724.53622009 520733.019447553,5079610.07120933 520678.579743701,5079500.1984832 520642.79704178,5079427.98122832 520547.760564012,5079180.70442154 520508.163114216,5079015.89429761 520454.754459399,5078899.39660678 520366.409151145,5078805.68083873 520320.470709426,5078751.74493411 520303.344046281,5078678.3709813 520331.467299477,5078616.90205635 520391.746725926,5078563.05726936 520484.805189179,5078429.86859109 520467.08377477,5078315.37000025 520442.456839998,5078228.40259782 520379.670641144,5078006.43728687 520318.410473331,5077573.59872656 520227.403646236,5077268.2285798 520243.650506458,5077145.94796097 520188.741108066,5077001.66930245 520130.927676593,5076946.51496206 520092.364552924,5076909.70373633 519940.143532455,5076772.67744857 519871.6410893,5076654.11766659 519803.263239278,5076519.58926871 519758.262173949,5076463.77836818 519707.605788464,5076443.71730519 519641.730802684,5076425.31285877 519570.605738453,5076402.31483303 519477.168372371,5076380.91110195 519397.76236417,5076367.88194885 519329.35664538,5076369.32080713 519255.980060639,5076284.88550096 519215.447162592,5076207.32447978 519092.819894412,5076080.85928294 519087.069834222,5076076.76568395 518929.943206973,5075965.36356215 518680.877962343,5075781.18269435 518506.312666539,5075616.21892506 518354.746343315,5075416.0050175 518298.181700958,5075312.16333726 518240.804530774,5075206.79044069 518212.832647039,5075071.38596346 518200.203039623,5074881.04416176 518261.164746312,5074615.35776503 518287.412799618,5074544.98284723 518401.623040541,5074237.79569916 518450.679042617,5073991.51559776 518494.489266897,5073913.98411745 518497.800052583,5073845.98464487 518566.35882161,5073718.07808583 518574.358384786,5073703.10929978 518643.573359234,5073573.89023206 518675.819223336,5073418.23466318 518686.25583899,5073386.14097374 518727.127784287,5073276.95356544 518770.188669651,5073226.42184938 518806.278999855,5073101.20342542 518833.052560087,5072801.73670198 518818.172294192,5072585.48888734 518726.197100836,5072295.36835572 518584.818466704,5072100.31056835 518507.722742472,5071993.93814527 518147.000360161,5071720.13578819 517996.093251593,5071631.60856814 517714.463120206,5071321.80490865 517541.550912004,5071015.90515659 517486.67423325,5070927.18839981 517371.701977201,5070741.34883498 517325.134407101,5070516.60189141 517321.071465435,5070497.00840821 517315.008311529,5070467.97755455 517131.465213529,5069912.86164261 517075.770270269,5069585.95961113 517004.567228692,5068919.84229127 517000.160020265,5068878.71776642 516997.815762788,5068856.93676833 516877.740684883,5068291.4134032 516747.919276087,5067871.23270709 516658.074530766,5067792.89172011 516480.947581747,5067638.42843006 516301.474970896,5067402.96596768 516202.817110283,5067294.28174024 516074.408775172,5067152.84850915 515893.874616341,5066954.10452861 515660.402139589,5066697.08109542 515350.931932957,5066500.12137847 515252.209107856,5066285.09448824 515227.426317466,5066202.06522534 515208.362664928,5066139.6917276 515171.330043942,5066058.50646442 515140.704343312,5066011.32047405 515077.98508073,5065957.16659232 515034.109929957,5065928.85558567 514987.578595246,5065902.29461005 514964.921365397,5065846.13983452 514904.607569742,5065757.11148287 514849.044479065,5065702.86368084 514792.481244811,5065641.52227023 514773.887419227,5065628.99165989 514713.637173165,5065588.3374827 514616.949307903,5065524.46578352 514551.542748757,5065478.40556277 514460.418275543,5065458.31424451 514321.138030146,5065436.78655562 514311.512994071,5065430.44313314 514270.106587703,5065403.10079269 514228.699537633,5065346.1339482 514168.573644724,5065275.79275576 514091.416569648,5065200.2957877 513995.541158195,5065134.73657938 513924.853518293,5065093.92637879 513879.103270323,5065060.27173699 513840.634367204,5065034.52304618 513817.070760505,5064972.14962395 513740.976909832,5064930.52705584 513621.133138238,5064871.28077813 513535.945053981,5064803.00260584 513446.22508532,5064703.3500536 513421.535750777,5064606.97721166 513387.410085961,5064559.82251892 513305.721633215,5064476.32575796 513173.284087993,5064409.92361498 513034.910236196,5064395.52074699 512853.724361751,5064382.27508195 512766.28759974,5064373.74595858 512720.474578948,5064327.56025598 512668.567797679,5064277.9372469 512575.442971553,5064240.72121893 512482.223565524,5064165.31831459 512402.472862269,5064094.2900304 512377.253908737,5064072.69720353 511062.392778509,5064071.91450292 509457.409628247,5064066.95095005 507903.301034838,5064065.98619059 506303.005568183,5064071.02239891 504702.459958992,5064069.05872826 503088.821052274,5064081.09516618 501481.713509822,5064101.13136529 499857.508514904,5064110.1681411 498300.449057285,5064129.20350494 496691.169585719,5064134.24028947 495086.89002906,5064130.27709148 493493.361208123,5064153.31341955 491872.206767928,5064171.35049707 490277.552024482,5064146.3873352 488947.308563874,5064129.41802083 488951.993514498,5065755.4076836 488963.362488911,5067334.38565655 488955.82394657,5068945.35767412 488955.129678321,5070583.32900462 488951.340430278,5072144.30170687 488951.395791378,5073758.27334245 488949.982506543,5075382.24478543 488948.350288336,5076995.21637679 488949.780433451,5078595.18808382 488952.085812196,5080210.15946079 488967.578720022,5081806.13086345 488966.603498611,5083471.10132991 488959.62738009,5085087.0727308 488960.651301265,5086693.04410525 488942.143396357,5088296.01584302 488938.698739494,5089923.98680048 488938.722481702,5091522.95816492 488938.728721907,5091943.35687819 489257.737604697,5091942.9451303 490293.766474881,5091942.92726372 490603.306351279,5091942.92192925 490883.814225059,5091946.5420335 491916.936983,5091959.89901845 492488.890332139,5091953.85803386 492786.742335496,5091950.72796563 493533.106969024,5091955.30881303 494107.873015854,5091956.54892235 495168.121370497,5091958.84319296 495653.63491057,5091958.83486902 495729.480807959,5091960.70853896 495718.945751742,5093579.80772311 495723.957943447,5095178.77149585 495729.963918394,5096779.7308946 495733.969895892,5098394.68992644 495743.976059032,5099997.64911727 495749.983476115,5101977.59875299 495753.98952509,5103597.55750941 495770.996088307,5105202.51638607 495793.002926426,5106803.47523639 495820.010010398,5108384.43446898 495831.016509534,5109990.39328381 495834.022797801,5111638.35111148 495843.029308365,5113258.30950871 495830.03459665,5114867.2685059 495827.040391883,5116474.22734309 495835.046800069,5118075.18610661 495835.052794276,5119689.14462307 495822.057922962,5121293.10356628 495835.043321767,5122871.09719571 495850.017037609,5124518.10854358 495856.990847918,5126129.11972733 495883.965846267,5127742.13058836 495858.938034687,5129335.14203562 495864.911866238,5130943.15308686 495862.885291437,5132548.16418396 495858.858328788,5134171.17538212 495830.829879582,5135804.18689701 495828.803448126,5137406.19781468 495815.776178388,5139024.20891946 495769.747660932,5140613.22013602 + + + + 488938.698739494 5064065.98619059554592.616912497 5140666.37358734 + 495769.747660932 5140613.22013602 497493.839733782 5140624.20112631 499099.925449201 5140637.18350592 500702.480180676 5140631.17582888 502322.652996529 5140626.1805358 503943.013177162 5140629.18532095 505559.498296073 5140634.19012381 507083.889113586 5140611.19450178 508669.592740126 5140609.19921645 510293.828064161 5140601.204038 511910.000819644 5140589.20884539 513527.89233112 5140574.21367801 515111.689717197 5140557.21843482 516683.142984441 5140571.22329294 518289.159252459 5140559.22819305 519900.159148136 5140564.22079982 521506.138065647 5140576.19754254 523113.117017892 5140575.1742278 524724.095912882 5140574.15084742 526302.075232683 5140570.12792372 527905.054220142 5140572.10465667 529512.033176919 5140583.08137621 531115.012187083 5140590.05813077 532718.366168833 5140591.034837 534329.970129577 5140608.01152846 536127.946556834 5140608.98539251 537734.925434632 5140604.9619813 539356.887082251 5140610.93267754 540952.837370015 5140612.89978375 542576.911810792 5140615.86630563 544190.486586884 5140616.8330177 545689.439928457 5140613.80205839 547286.07778693 5140615.76910864 548910.589773269 5140611.73553649 550514.540006892 5140624.70248202 552140.489637614 5140654.66904886 553744.439883277 5140665.6359454 554342.209073819 5140666.37355679 554342.233833628 5140666.37358734 554342.358772653 5140648.21724442 554352.603403535 5139042.67776921 554362.910511869 5137431.91946821 554372.34305014 5135950.28679076 554374.092605357 5135825.9111256 554379.778688583 5135430.65900772 554382.215254471 5135157.87632369 554390.399518766 5134210.62133909 554403.706775292 5132676.01947908 554404.206573933 5132616.98791651 554416.451723541 5131196.88662423 554417.451338271 5131084.32352432 554418.388476769 5130978.6979612 554424.011233388 5130321.53820713 554426.322826127 5130056.09928885 554425.135289221 5130034.2866976 554431.509937198 5129978.34879021 554434.009678648 5129918.47343372 554438.13425802 5129821.50410496 554438.696698607 5129807.62902265 554442.759014259 5129784.44132778 554445.571389713 5129769.34744787 554445.008323505 5129586.22150791 554447.257595597 5129376.28287651 554448.632153618 5129248.87593935 554441.694558447 5129159.90685325 554443.569481045 5129151.50052536 554445.506511538 5129020.28105749 554453.316871103 5128413.18400358 554456.003313945 5128103.40108881 554452.814810878 5127761.61811038 554449.438747144 5127399.71002693 554447.437918208 5127123.23986379 554447.062796869 5127082.1146548 554448.562504679 5127002.89546264 554455.184985191 5126267.76648391 554455.184676468 5126171.07847522 554455.058527227 5125810.29532751 554454.054583054 5124569.50753942 554452.79948873 5122971.90532119 554452.172098942 5122223.96383826 554453.484041657 5122060.83794376 554455.674360441 5121405.49590233 554456.362027103 5121363.65225197 554478.679820162 5120033.59289083 554478.99355503 5119750.28113143 554480.875596368 5118133.66033641 554481.377553571 5117684.22399995 554484.944978905 5116540.78940651 554489.701491879 5115028.26197265 554491.139379615 5114932.29344219 554514.833354161 5113333.29707605 554522.335407162 5112827.07946503 554534.589770591 5111770.45689264 554535.027392622 5111740.45695946 554535.652606605 5111688.55082766 554551.658348326 5110300.52273345 554554.159240296 5110084.99196981 554572.353248283 5108514.05798831 554576.292166395 5108172.18374812 554591.234780263 5106936.90520942 554590.672454214 5106899.81156213 554584.799324661 5106499.93766508 554592.616912497 5105303.62790302 554592.429485455 5105287.81544546 554581.933214056 5104483.0363755 554581.186729472 5103682.88207219 554581.249264502 5103674.60084072 554584.189251516 5103093.22717131 554584.564675901 5102994.57114941 554590.691312287 5102594.04071861 554591.253978603 5102553.60330241 554568.629437552 5102545.85383945 554480.818797228 5102497.51221917 554394.758125457 5102448.29556352 554325.69710991 5102404.35975707 554236.511316787 5102396.23682528 554140.200644842 5102390.95780032 554105.951326077 5102381.70861039 554006.203309133 5102354.77347075 553895.642898913 5102350.46352219 553832.456554275 5102357.37120581 553772.707675745 5102356.96632954 553682.584419698 5102343.62468572 553609.335862589 5102326.43891521 553461.77634549 5102272.4737048 553355.153599082 5102208.32008551 553224.156442003 5102109.51087989 553154.032950968 5102059.10638963 553148.845548024 5102059.04400946 553140.658238217 5102049.57547528 553044.910189871 5102007.51530512 552994.223573846 5102023.20392956 552950.661870638 5102027.26742294 552890.975457625 5102034.11253008 552790.97741619 5102010.02115849 552709.666511637 5101989.42934651 552639.980380199 5101971.27475981 552566.481923366 5101925.55784552 552503.358245955 5101886.62192277 552479.483745789 5101871.90376969 552397.110439891 5101828.87455699 552346.799029958 5101787.43834941 552318.924663206 5101756.43909103 552255.488376177 5101747.22183884 552182.302315528 5101725.59860195 552058.804813389 5101669.5703917 551982.556406799 5101620.25981795 551833.559557177 5101511.88862801 551704.874931212 5101372.79832701 551595.689948365 5101229.98884483 551523.941768908 5101086.83474873 551457.818362936 5100977.61791267 551411.319606158 5100864.55688417 551380.82056902 5100746.96424872 551334.821931918 5100594.55959859 551317.760111766 5100486.65411858 551300.573136332 5100424.65473556 551297.510729787 5100413.59234561 551270.386672281 5100281.59343787 551227.387872398 5100157.87612939 551193.451336726 5100054.50228915 551188.951743405 5099958.12772837 551168.140058366 5099827.84742246 551161.578091684 5099704.5667546 551158.953466592 5099607.19215365 551118.89198163 5099519.19341386 551055.705905587 5099432.22647519 551007.831993604 5099362.9466117 550964.520459462 5099305.35409998 550921.771455629 5099235.07412108 550866.022686856 5099163.32571097 550820.898685985 5099103.95200429 550798.024323204 5099033.54655423 550790.587333623 5098917.45339688 550789.52493389 5098892.45351158 550789.087588548 5098847.32868299 550788.71273913 5098803.11009965 550805.400313442 5098689.48510191 550816.71303623 5098559.79778976 550822.838257872 5098458.73550047 550825.588512559 5098365.86076342 550859.713439288 5098204.67300627 550885.463345372 5098095.45401594 550883.026099186 5098031.11055205 550870.339222261 5097908.76754253 550862.339671889 5097814.14307154 550835.527951187 5097718.80031329 550805.028886145 5097594.89524803 550809.654053215 5097518.92665392 550789.154710702 5097426.20873526 550751.530758417 5097304.21009257 550714.906553155 5097254.36742052 550673.844942598 5097198.58738006 550590.721755413 5097080.55860137 550542.160233131 5097036.37245824 550491.973709423 5097001.09257416 550365.163777452 5096878.15865468 550334.852109523 5096778.34727154 550310.727814306 5096684.81696374 550316.290469509 5096604.31712294 550309.728175924 5096574.03614743 550318.978190406 5096518.5673725 550326.790640858 5096491.62977781 550313.228427415 5096473.94267983 550296.916313546 5096439.25571311 550289.041689036 5096361.53744597 550297.291764992 5096291.81874812 550308.541688008 5096255.00610377 550322.354089704 5096211.13092128 550317.291897743 5096139.75631034 550284.542665925 5096071.25738025 550247.668392169 5096038.50842221 550217.23146193 5096020.94674768 550180.419666482 5095994.54151571 550104.296075735 5095955.01231634 549989.673197379 5095894.54666119 549850.988229078 5095831.51912271 549789.114369961 5095799.0207972 549702.17851544 5095738.21071076 549622.054824984 5095752.46266394 549498.119437673 5095744.68455112 549458.745151586 5095727.24810707 549379.121568022 5095701.18770715 549323.247485056 5095709.93907356 549308.747725346 5095711.40818131 549254.561116424 5095719.40950802 549162.812631523 5095730.911762 549121.125806116 5095741.22526522 549075.751533407 5095755.10134605 548969.753307069 5095760.60397996 548872.567449687 5095759.70016915 548831.880561098 5095787.8260719 548759.694280633 5095787.60913109 548668.820810466 5095789.42389983 548559.447587701 5095816.36402521 548491.136141183 5095855.49056886 548439.949388799 5095901.52290282 548366.825545358 5095933.39959453 548304.326424988 5096004.24460061 548194.828244741 5096019.05977103 547988.394076832 5096088.78336742 547861.146149204 5096125.91137619 547703.523643693 5096204.53995125 547698.398724912 5096207.10256733 547469.52754957 5096238.45187426 547259.530969925 5096309.17552288 547100.2835743 5096360.74174086 547009.535044148 5096397.83757056 546897.536815154 5096465.30878043 546758.976469298 5096569.59296632 546667.352936202 5096620.126242 546581.166812912 5096670.47188094 546471.04354446 5096750.53671288 546346.732980185 5096853.82052419 546260.484326146 5096926.29104226 546139.173822117 5096977.26252863 546089.487147772 5096994.38866717 546078.23733479 5096998.26392488 545939.364607453 5097066.89199786 545807.491745403 5097146.23858723 545797.804358794 5097176.51991972 545763.742428123 5097188.208197 545612.307453801 5097245.02412425 545455.622652952 5097256.43416338 545332.499832048 5097230.96857232 545228.189170155 5097213.53372805 545091.754058384 5097199.88090418 544968.568701521 5097195.54020531 544885.945138796 5097192.69850155 544835.133531849 5097184.88729308 544768.38474138 5097150.10787432 544655.636770422 5097098.92342916 544506.514470127 5097016.42755734 544424.703441951 5096975.71105005 544228.894428452 5096899.65380548 544087.771959286 5096826.9702006 543971.711544846 5096760.47344728 543804.589568653 5096641.38451572 543683.904238125 5096561.41921796 543572.968767686 5096452.86010173 543476.28303757 5096352.30059195 543376.097356744 5096256.27239851 543279.286644267 5096130.58805322 543174.538568908 5095996.09146618 543096.290071761 5095825.62569112 543083.540359618 5095754.22018835 543073.415608845 5095676.4709084 543052.603528349 5095608.65933726 543043.041216238 5095582.12848651 543015.604254459 5095506.06713256 543011.541940421 5095386.28670537 543031.791665603 5095319.1928493 543036.104133727 5095278.00548819 543022.416925227 5095215.47495881 542971.167886651 5095111.10187962 542934.293582281 5095029.94705025 542907.294089969 5094971.10433811 542832.670466591 5094831.95081922 542759.109314617 5094698.20349685 542699.047897229 5094604.54934263 542614.611937776 5094444.95871608 542548.363098513 5094370.17961229 542494.551552431 5094293.4939562 542461.364642398 5094242.7138662 542457.677225166 5094215.90162597 542448.739895674 5094187.62077892 542372.488737527 5093978.65562436 542360.801056537 5093946.56242515 542309.112311312 5093767.22140284 542326.921786931 5093532.22280021 542331.920230532 5093405.3799217 542258.045219705 5093304.53883344 542092.232986639 5093107.07581767 541872.735145832 5093003.01966359 541630.736858292 5092838.05828172 541553.486502912 5092713.87367658 541475.23533276 5092524.59583772 541470.733414002 5092365.34716469 541479.8578229 5092328.81596462 541503.418796123 5092234.22234624 541561.729180114 5092132.84666223 541662.539346825 5092063.18842708 541740.162327585 5091990.59329668 541731.286383227 5091902.87544188 541656.411309875 5091809.12802645 541484.160549609 5091550.10303766 541272.41156773 5091394.89071915 541186.974460643 5091332.23705942 541108.474813244 5091274.70818659 541001.850639414 5091224.4612031 540845.164685801 5091177.40293178 540681.479676533 5091195.43809871 540516.857879928 5091265.25415992 540460.733977699 5091289.09912509 540324.04837952 5091289.54000824 540236.11256392 5091323.54193943 540181.426148367 5091347.16812319 540118.489899045 5091374.3257366 539974.430807429 5091474.82858421 539923.306818993 5091495.82970216 539822.308315667 5091501.1759217 539654.62293823 5091484.36770569 539634.060698161 5091482.30573092 539496.874622779 5091447.12188651 539430.625709959 5091458.02970369 539347.252245524 5091483.15659615 538901.82538179 5091775.79062633 538715.641387779 5091830.95113367 538533.645830736 5091945.14211264 538303.400263202 5092009.92830984 538046.343180148 5092111.4023769 537951.0326951 5092148.99809719 537688.287930376 5092230.94117665 537489.541848367 5092289.28916968 537413.793434159 5092317.19699642 537397.856179987 5092317.47861736 537217.859784307 5092372.85743922 537020.613266138 5092403.45558747 536776.616341385 5092364.11782328 536726.866708995 5092340.05665768 536705.741865714 5092329.90097392 536632.492407924 5092294.71543747 536585.867693434 5092268.71671314 536365.056530663 5092145.69150694 536158.431488057 5091953.16646956 535810.494785362 5091686.92653195 535607.868614117 5091436.43308542 535550.054839239 5091309.24785732 535526.054308586 5091256.49880046 535361.30292556 5091030.91054732 535197.739366394 5090827.75961084 534983.302928682 5090708.54677201 534975.990390074 5090700.1095053 534879.614878251 5090589.08132967 534855.799773533 5090416.61438987 534876.608963023 5090239.95892745 534836.043226101 5090017.05524812 534817.790979542 5089870.74423803 534817.039536308 5089785.74487069 534821.414110595 5089764.40117162 534838.974905119 5089678.87012473 534878.597079132 5089545.43265137 534882.406579019 5089372.77755804 534847.715288643 5089123.28018157 534810.713355892 5088981.06333606 534782.586301887 5088839.03377921 534725.023444326 5088773.25437114 534701.7736268 5088765.78622723 534616.83679632 5088738.75718989 534503.588062959 5088724.57248241 534218.779208096 5088715.67306195 534153.842315869 5088700.86221224 534096.780553753 5088699.55107727 534002.906770908 5088697.58457155 533875.907879244 5088664.33783136 533794.657462215 5088579.34038347 533629.220857022 5088505.9073536 533565.158226408 5088450.78428096 533468.471505822 5088422.8180355 533371.5346313 5088386.19561015 533345.222300536 5088376.2588091 533246.098566801 5088374.04243326 533134.100287361 5088387.66999686 533053.351642428 5088403.79679844 532947.789912736 5088369.36206378 532873.540227785 5088332.73910107 532509.166881397 5088161.06154654 532428.354532438 5088111.68883798 532145.980028413 5087939.16560066 532032.104583705 5087835.57533889 531976.791977225 5087791.38948815 531944.729045281 5087745.92184295 531861.791778069 5087701.14290642 531791.854590106 5087669.73856017 531769.729688322 5087659.80166253 531692.105634678 5087657.17853421 531549.482170086 5087641.55705451 531328.546886412 5087609.00007167 531105.424480406 5087595.19300065 530949.301344763 5087588.19677961 530815.239800053 5087548.54403017 530587.989829637 5087399.51933915 530361.739724948 5087245.99466495 530276.613639391 5087134.90379811 530201.425892234 5087073.71856372 530178.238315577 5087054.8755124 530166.925778738 5087045.71960301 530073.112856642 5086964.03497242 529996.049952806 5086894.31860062 529899.73769556 5086845.63377937 529789.363666918 5086825.32407778 529688.740368069 5086848.20131101 529494.493905717 5086904.79927491 529373.49582456 5086925.45826143 529247.684695074 5086915.52384933 529166.184278109 5086843.93260436 529096.933960279 5086785.15346782 529056.24665812 5086769.87331063 528969.434367144 5086726.78197412 528861.121365829 5086635.50402786 528742.122196648 5086604.06962396 528628.436532059 5086625.54093117 528594.562252274 5086640.44787669 528522.688782083 5086672.07435211 528341.693613527 5086799.10894473 528193.946475428 5086849.20584002 528075.822557464 5086830.36506603 528065.510088577 5086825.6466 527999.760301715 5086796.33590466 527940.135041522 5086747.86896365 527913.884925928 5086726.52601027 527900.507649324 5086608.33976038 527905.631045558 5086533.77772395 527908.755069676 5086488.40300583 527969.935319263 5086173.34151323 528006.744198495 5086019.31058801 528031.116158065 5085885.96729806 528016.801707287 5085783.03094922 527981.988494533 5085728.40721481 527891.613954849 5085698.78462118 527780.553104804 5085714.8496666 527660.617419261 5085733.66490349 527562.118626276 5085735.44850864 527432.244961223 5085725.51421095 527337.370899841 5085716.54781397 527247.871960968 5085716.48746736 527197.685451768 5085735.26977585 527128.748771501 5085735.30268376 527083.999147679 5085727.92881864 527031.187090902 5085719.21140819 526951.500687246 5085726.3070187 526862.876663815 5085722.71542908 526789.440092505 5085725.37342445 526707.128588975 5085726.25039747 526663.191266112 5085710.06408344 526576.441035807 5085651.03539149 526470.815790519 5085581.1322417 526398.440800242 5085541.72804887 526267.8143935 5085404.73229071 526208.813406882 5085326.82808613 526133.687661253 5085251.61174947 526005.749479571 5085151.30313868 525934.18575 5085056.33687744 525876.997590496 5084995.55749565 525774.059986827 5084936.34170608 525712.122429799 5084901.09348486 525643.434864606 5084862.03295775 525563.809308518 5084794.94167141 525527.18311805 5084721.47439883 525480.432353319 5084662.3197558 525445.806784436 5084618.47719655 525307.180536708 5084490.45033238 525256.180183479 5084448.35815621 525164.929648197 5084377.67343567 525114.804138952 5084329.23754085 525078.178360449 5084275.55136234 525065.676875733 5084202.17725981 525082.799247978 5084092.02148807 525136.731363179 5083875.36568599 525150.229969059 5083818.95956524 525119.91607812 5083741.08593065 525083.227968253 5083695.49343971 525015.22749572 5083640.87053201 524881.853261333 5083610.34276616 524797.728752767 5083591.56371031 524684.103419219 5083521.6607867 524516.790512188 5083423.13440168 524406.727079277 5083329.13784184 524348.539358438 5083291.73331102 524257.320423798 5083240.45469684 524072.975713012 5083111.52273351 523995.193273789 5083022.90035144 523870.536556867 5082944.74777554 523849.317726914 5082931.46715093 523746.442946063 5082893.84496389 523675.754916731 5082838.34714099 523572.034805653 5082731.72554414 523465.503325469 5082673.57236842 523351.877500948 5082586.70085376 523287.471129895 5082552.67145458 523219.471600665 5082542.76694407 523170.222398242 5082555.36179053 523102.160700595 5082559.7696632 523019.817631392 5082552.58422999 522925.817890391 5082522.11802415 522847.911523316 5082482.71400065 522779.068248294 5082472.80951167 522676.099132467 5082412.00002842 522583.972869627 5082317.87805913 522510.751757 5082185.41219931 522445.407215215 5082123.60180991 522355.938355149 5082080.63560336 522304.90702684 5082055.54330932 522268.000077275 5082010.16958982 522245.905907833 5081983.01410646 522218.24799108 5081900.70296995 522151.183405212 5081784.23683287 522118.058565398 5081777.14395229 522107.652081143 5081762.89432596 522050.119530341 5081683.99014334 521959.836363481 5081565.80584201 521904.427080188 5081415.40220842 521806.050176923 5081295.40562429 521736.361320744 5081210.37679555 521638.798921699 5081175.37948123 521552.047630877 5081086.7573533 521509.171192366 5081009.69655305 521500.263137414 5080930.91618412 521420.729350447 5080793.98178856 521339.321128633 5080680.26599542 521330.444228291 5080597.89190719 521312.629500438 5080498.51818188 521232.189330561 5080357.02135212 521149.00133893 5080305.0863367 521079.311686957 5080189.83902419 521064.154908118 5080162.30837969 520984.527127586 5080017.87406021 520943.711927634 5079891.5323831 520911.491440783 5079808.19013152 520845.333744257 5079724.53622009 520733.019447553 5079610.07120933 520678.579743701 5079500.1984832 520642.79704178 5079427.98122832 520547.760564012 5079180.70442154 520508.163114216 5079015.89429761 520454.754459399 5078899.39660678 520366.409151145 5078805.68083873 520320.470709426 5078751.74493411 520303.344046281 5078678.3709813 520331.467299477 5078616.90205635 520391.746725926 5078563.05726936 520484.805189179 5078429.86859109 520467.08377477 5078315.37000025 520442.456839998 5078228.40259782 520379.670641144 5078006.43728687 520318.410473331 5077573.59872656 520227.403646236 5077268.2285798 520243.650506458 5077145.94796097 520188.741108066 5077001.66930245 520130.927676593 5076946.51496206 520092.364552924 5076909.70373633 519940.143532455 5076772.67744857 519871.6410893 5076654.11766659 519803.263239278 5076519.58926871 519758.262173949 5076463.77836818 519707.605788464 5076443.71730519 519641.730802684 5076425.31285877 519570.605738453 5076402.31483303 519477.168372371 5076380.91110195 519397.76236417 5076367.88194885 519329.35664538 5076369.32080713 519255.980060639 5076284.88550096 519215.447162592 5076207.32447978 519092.819894412 5076080.85928294 519087.069834222 5076076.76568395 518929.943206973 5075965.36356215 518680.877962343 5075781.18269435 518506.312666539 5075616.21892506 518354.746343315 5075416.0050175 518298.181700958 5075312.16333726 518240.804530774 5075206.79044069 518212.832647039 5075071.38596346 518200.203039623 5074881.04416176 518261.164746312 5074615.35776503 518287.412799618 5074544.98284723 518401.623040541 5074237.79569916 518450.679042617 5073991.51559776 518494.489266897 5073913.98411745 518497.800052583 5073845.98464487 518566.35882161 5073718.07808583 518574.358384786 5073703.10929978 518643.573359234 5073573.89023206 518675.819223336 5073418.23466318 518686.25583899 5073386.14097374 518727.127784287 5073276.95356544 518770.188669651 5073226.42184938 518806.278999855 5073101.20342542 518833.052560087 5072801.73670198 518818.172294192 5072585.48888734 518726.197100836 5072295.36835572 518584.818466704 5072100.31056835 518507.722742472 5071993.93814527 518147.000360161 5071720.13578819 517996.093251593 5071631.60856814 517714.463120206 5071321.80490865 517541.550912004 5071015.90515659 517486.67423325 5070927.18839981 517371.701977201 5070741.34883498 517325.134407101 5070516.60189141 517321.071465435 5070497.00840821 517315.008311529 5070467.97755455 517131.465213529 5069912.86164261 517075.770270269 5069585.95961113 517004.567228692 5068919.84229127 517000.160020265 5068878.71776642 516997.815762788 5068856.93676833 516877.740684883 5068291.4134032 516747.919276087 5067871.23270709 516658.074530766 5067792.89172011 516480.947581747 5067638.42843006 516301.474970896 5067402.96596768 516202.817110283 5067294.28174024 516074.408775172 5067152.84850915 515893.874616341 5066954.10452861 515660.402139589 5066697.08109542 515350.931932957 5066500.12137847 515252.209107856 5066285.09448824 515227.426317466 5066202.06522534 515208.362664928 5066139.6917276 515171.330043942 5066058.50646442 515140.704343312 5066011.32047405 515077.98508073 5065957.16659232 515034.109929957 5065928.85558567 514987.578595246 5065902.29461005 514964.921365397 5065846.13983452 514904.607569742 5065757.11148287 514849.044479065 5065702.86368084 514792.481244811 5065641.52227023 514773.887419227 5065628.99165989 514713.637173165 5065588.3374827 514616.949307903 5065524.46578352 514551.542748757 5065478.40556277 514460.418275543 5065458.31424451 514321.138030146 5065436.78655562 514311.512994071 5065430.44313314 514270.106587703 5065403.10079269 514228.699537633 5065346.1339482 514168.573644724 5065275.79275576 514091.416569648 5065200.2957877 513995.541158195 5065134.73657938 513924.853518293 5065093.92637879 513879.103270323 5065060.27173699 513840.634367204 5065034.52304618 513817.070760505 5064972.14962395 513740.976909832 5064930.52705584 513621.133138238 5064871.28077813 513535.945053981 5064803.00260584 513446.22508532 5064703.3500536 513421.535750777 5064606.97721166 513387.410085961 5064559.82251892 513305.721633215 5064476.32575796 513173.284087993 5064409.92361498 513034.910236196 5064395.52074699 512853.724361751 5064382.27508195 512766.28759974 5064373.74595858 512720.474578948 5064327.56025598 512668.567797679 5064277.9372469 512575.442971553 5064240.72121893 512482.223565524 5064165.31831459 512402.472862269 5064094.2900304 512377.253908737 5064072.69720353 511062.392778509 5064071.91450292 509457.409628247 5064066.95095005 507903.301034838 5064065.98619059 506303.005568183 5064071.02239891 504702.459958992 5064069.05872826 503088.821052274 5064081.09516618 501481.713509822 5064101.13136529 499857.508514904 5064110.1681411 498300.449057285 5064129.20350494 496691.169585719 5064134.24028947 495086.89002906 5064130.27709148 493493.361208123 5064153.31341955 491872.206767928 5064171.35049707 490277.552024482 5064146.3873352 488947.308563874 5064129.41802083 488951.993514498 5065755.4076836 488963.362488911 5067334.38565655 488955.82394657 5068945.35767412 488955.129678321 5070583.32900462 488951.340430278 5072144.30170687 488951.395791378 5073758.27334245 488949.982506543 5075382.24478543 488948.350288336 5076995.21637679 488949.780433451 5078595.18808382 488952.085812196 5080210.15946079 488967.578720022 5081806.13086345 488966.603498611 5083471.10132991 488959.62738009 5085087.0727308 488960.651301265 5086693.04410525 488942.143396357 5088296.01584302 488938.698739494 5089923.98680048 488938.722481702 5091522.95816492 488938.728721907 5091943.35687819 489257.737604697 5091942.9451303 490293.766474881 5091942.92726372 490603.306351279 5091942.92192925 490883.814225059 5091946.5420335 491916.936983 5091959.89901845 492488.890332139 5091953.85803386 492786.742335496 5091950.72796563 493533.106969024 5091955.30881303 494107.873015854 5091956.54892235 495168.121370497 5091958.84319296 495653.63491057 5091958.83486902 495729.480807959 5091960.70853896 495718.945751742 5093579.80772311 495723.957943447 5095178.77149585 495729.963918394 5096779.7308946 495733.969895892 5098394.68992644 495743.976059032 5099997.64911727 495749.983476115 5101977.59875299 495753.98952509 5103597.55750941 495770.996088307 5105202.51638607 495793.002926426 5106803.47523639 495820.010010398 5108384.43446898 495831.016509534 5109990.39328381 495834.022797801 5111638.35111148 495843.029308365 5113258.30950871 495830.03459665 5114867.2685059 495827.040391883 5116474.22734309 495835.046800069 5118075.18610661 495835.052794276 5119689.14462307 495822.057922962 5121293.10356628 495835.043321767 5122871.09719571 495850.017037609 5124518.10854358 495856.990847918 5126129.11972733 495883.965846267 5127742.13058836 495858.938034687 5129335.14203562 495864.911866238 5130943.15308686 495862.885291437 5132548.16418396 495858.858328788 5134171.17538212 495830.829879582 5135804.18689701 495828.803448126 5137406.19781468 495815.776178388 5139024.20891946 495769.747660932 5140613.22013602 - - - - 438623.813339239,5121376.09834029 439268.330052994,5121375.71365614 440877.37695095,5121394.6590622 442433.41800387,5121415.6095591 444012.438820035,5121440.57537843 445555.459188838,5121450.54218051 447142.480120161,5121473.5079516 448848.502614519,5121502.47117366 450644.526317509,5121524.43260388 452150.546221549,5121533.40039558 453901.569310636,5121566.36280177 455534.590852865,5121594.3278256 457106.611589166,5121622.29420132 458729.164257097,5121647.19708141 458863.634782301,5121649.25671468 460382.654975318,5121633.22463705 461978.681115782,5121582.17868885 463582.716668467,5121567.10778504 465169.751832345,5121562.03758123 466796.788476539,5121475.96660114 466806.804704029,5119187.99361209 466825.816297009,5117602.01185281 466837.82780885,5116011.03046653 466840.839130967,5114420.0494352 466801.849456444,5112811.07011109 466657.856325405,5111261.0935366 466632.866852024,5109653.11330102 466609.877339502,5108056.13277789 466589.575273206,5106476.15188722 466571.491993683,5104899.17081937 466559.908942111,5103319.18954126 466559.920202827,5101716.20818807 466518.898924679,5100094.22799554 466510.94108788,5098501.24660003 466507.952266847,5096898.26517664 466491.962848709,5095312.283773 466503.973831077,5093696.30281881 466501.981832964,5092081.29258997 464966.925456697,5092134.34856581 464893.922778272,5092135.94350583 463946.419248898,5092156.64646804 463318.864953662,5092169.65673431 463291.863961833,5092170.21967628 462445.583082424,5092165.76503196 461635.834808413,5092161.49728313 461618.802937696,5092161.40381719 460610.997352688,5092152.80308464 460025.768559792,5092147.78839446 459868.765849071,5092147.98032192 459859.768794261,5091855.45249348 459795.783384233,5090371.47038962 459780.800153885,5088762.4882138 459800.817670382,5087147.50499564 459819.834954137,5085557.52145021 459806.851424333,5083986.53863791 459795.868361068,5082376.55613539 459785.885309762,5080768.57353337 459803.90294958,5079156.58997051 459838.920779818,5077568.60547445 459847.93848736,5075940.62221269 459857.956280213,5074310.63885958 459893.973142688,5072831.65289935 459922.991558528,5071198.66869116 459988.01118836,5069548.68316325 460017.02975173,5067916.69870545 460032.04539514,5066264.71406684 460041.028713195,5064660.7197052 460131.011340174,5062777.72341361 460144.994716183,5061168.72902498 460122.977060133,5059557.7358896 460077.958996613,5057968.74334245 460051.941257301,5056360.75013156 460043.923999539,5054751.75629883 460056.907247183,5053136.76185339 460071.891694615,5051630.7669731 460074.874724017,5050022.77280059 460087.85787808,5048401.77842505 460107.841019503,5046762.78397566 460144.824871777,5045148.78911013 458524.781590879,5045176.82370185 456908.73824789,5045187.85830708 455289.694928309,5045207.89301589 453679.651972685,5045238.9276109 452069.60898391,5045265.96227953 450454.566100183,5045315.99723879 448848.52322357,5045342.03199364 447227.479844585,5045357.06705671 445602.43635967,5045371.10223244 443990.393022387,5045363.13693017 442376.349896029,5045381.17194423 440741.310287012,5045399.18928944 440743.325486712,5047051.20963912 440743.340272337,5048666.2294772 440737.355311769,5050328.24981781 440743.370475576,5051976.26998853 440736.385283229,5053624.29005426 440740.400672329,5055309.31056787 440738.41510013,5056909.32997383 440732.429559395,5058529.3495573 440719.443697991,5060141.36896486 440710.45771364,5061732.38808982 440713.472395444,5063361.4076792 440704.486013821,5064917.42629141 440736.501443889,5066530.44573053 440761.497686472,5068130.41721815 440748.49242791,5069747.3876625 440740.487379777,5071357.35826486 440722.482032441,5072973.32878071 440689.476298381,5074578.29956977 440650.470456414,5076176.27058634 440593.464060144,5077802.24127423 440526.457438358,5079432.21209404 440496.764629372,5081004.18385891 440462.196598954,5082623.15488739 440413.784341035,5084296.12516544 440404.342141333,5085902.09633443 440428.369623751,5087503.06719217 440489.866800447,5089115.03726386 440467.143033784,5090726.00846609 440435.387686029,5092390.7289012 439141.605134714,5092415.81236261 438919.380788042,5092423.34716401 438811.503081546,5092422.50521428 437422.874361799,5092480.40230125 437240.307268621,5092487.43647359 437249.335970774,5094066.0056598 437263.332731688,5095662.99035577 437285.329488268,5097271.9769604 437321.326614066,5098877.96324363 437351.32362098,5100475.94963939 437351.3196229,5102176.93580248 437374.316482574,5103766.92231232 437389.313116093,5105366.90887882 437403.309687181,5106983.89528868 437394.305703213,5108574.88247635 437399.30209855,5110162.86930928 437431.299201951,5111764.85524216 437452.2960581,5113347.84157795 437456.292405097,5114947.82823075 437485.289502675,5116528.81424446 437484.285556978,5118193.80044963 437489.281897405,5119808.78685956 437492.278289034,5121376.77370461 438623.813339239,5121376.09834029 + + + + 437240.307268621 5045148.78911013466840.839130967 5121649.25671468 + 438623.813339239 5121376.09834029 439268.330052994 5121375.71365614 440877.37695095 5121394.6590622 442433.41800387 5121415.6095591 444012.438820035 5121440.57537843 445555.459188838 5121450.54218051 447142.480120161 5121473.5079516 448848.502614519 5121502.47117366 450644.526317509 5121524.43260388 452150.546221549 5121533.40039558 453901.569310636 5121566.36280177 455534.590852865 5121594.3278256 457106.611589166 5121622.29420132 458729.164257097 5121647.19708141 458863.634782301 5121649.25671468 460382.654975318 5121633.22463705 461978.681115782 5121582.17868885 463582.716668467 5121567.10778504 465169.751832345 5121562.03758123 466796.788476539 5121475.96660114 466806.804704029 5119187.99361209 466825.816297009 5117602.01185281 466837.82780885 5116011.03046653 466840.839130967 5114420.0494352 466801.849456444 5112811.07011109 466657.856325405 5111261.0935366 466632.866852024 5109653.11330102 466609.877339502 5108056.13277789 466589.575273206 5106476.15188722 466571.491993683 5104899.17081937 466559.908942111 5103319.18954126 466559.920202827 5101716.20818807 466518.898924679 5100094.22799554 466510.94108788 5098501.24660003 466507.952266847 5096898.26517664 466491.962848709 5095312.283773 466503.973831077 5093696.30281881 466501.981832964 5092081.29258997 464966.925456697 5092134.34856581 464893.922778272 5092135.94350583 463946.419248898 5092156.64646804 463318.864953662 5092169.65673431 463291.863961833 5092170.21967628 462445.583082424 5092165.76503196 461635.834808413 5092161.49728313 461618.802937696 5092161.40381719 460610.997352688 5092152.80308464 460025.768559792 5092147.78839446 459868.765849071 5092147.98032192 459859.768794261 5091855.45249348 459795.783384233 5090371.47038962 459780.800153885 5088762.4882138 459800.817670382 5087147.50499564 459819.834954137 5085557.52145021 459806.851424333 5083986.53863791 459795.868361068 5082376.55613539 459785.885309762 5080768.57353337 459803.90294958 5079156.58997051 459838.920779818 5077568.60547445 459847.93848736 5075940.62221269 459857.956280213 5074310.63885958 459893.973142688 5072831.65289935 459922.991558528 5071198.66869116 459988.01118836 5069548.68316325 460017.02975173 5067916.69870545 460032.04539514 5066264.71406684 460041.028713195 5064660.7197052 460131.011340174 5062777.72341361 460144.994716183 5061168.72902498 460122.977060133 5059557.7358896 460077.958996613 5057968.74334245 460051.941257301 5056360.75013156 460043.923999539 5054751.75629883 460056.907247183 5053136.76185339 460071.891694615 5051630.7669731 460074.874724017 5050022.77280059 460087.85787808 5048401.77842505 460107.841019503 5046762.78397566 460144.824871777 5045148.78911013 458524.781590879 5045176.82370185 456908.73824789 5045187.85830708 455289.694928309 5045207.89301589 453679.651972685 5045238.9276109 452069.60898391 5045265.96227953 450454.566100183 5045315.99723879 448848.52322357 5045342.03199364 447227.479844585 5045357.06705671 445602.43635967 5045371.10223244 443990.393022387 5045363.13693017 442376.349896029 5045381.17194423 440741.310287012 5045399.18928944 440743.325486712 5047051.20963912 440743.340272337 5048666.2294772 440737.355311769 5050328.24981781 440743.370475576 5051976.26998853 440736.385283229 5053624.29005426 440740.400672329 5055309.31056787 440738.41510013 5056909.32997383 440732.429559395 5058529.3495573 440719.443697991 5060141.36896486 440710.45771364 5061732.38808982 440713.472395444 5063361.4076792 440704.486013821 5064917.42629141 440736.501443889 5066530.44573053 440761.497686472 5068130.41721815 440748.49242791 5069747.3876625 440740.487379777 5071357.35826486 440722.482032441 5072973.32878071 440689.476298381 5074578.29956977 440650.470456414 5076176.27058634 440593.464060144 5077802.24127423 440526.457438358 5079432.21209404 440496.764629372 5081004.18385891 440462.196598954 5082623.15488739 440413.784341035 5084296.12516544 440404.342141333 5085902.09633443 440428.369623751 5087503.06719217 440489.866800447 5089115.03726386 440467.143033784 5090726.00846609 440435.387686029 5092390.7289012 439141.605134714 5092415.81236261 438919.380788042 5092423.34716401 438811.503081546 5092422.50521428 437422.874361799 5092480.40230125 437240.307268621 5092487.43647359 437249.335970774 5094066.0056598 437263.332731688 5095662.99035577 437285.329488268 5097271.9769604 437321.326614066 5098877.96324363 437351.32362098 5100475.94963939 437351.3196229 5102176.93580248 437374.316482574 5103766.92231232 437389.313116093 5105366.90887882 437403.309687181 5106983.89528868 437394.305703213 5108574.88247635 437399.30209855 5110162.86930928 437431.299201951 5111764.85524216 437452.2960581 5113347.84157795 437456.292405097 5114947.82823075 437485.289502675 5116528.81424446 437484.285556978 5118193.80044963 437489.281897405 5119808.78685956 437492.278289034 5121376.77370461 438623.813339239 5121376.09834029 - + --xxOGRBoundaryxx @@ -59,23 +62,47 @@ Content-Type: application/binary Content-Transfer-Encoding: binary - - - + + + + 0 + + + + + - - - + + + + + + + + + + + + + + - + - + diff --git a/msautotest/query/expected/rfc62_test002.txt b/msautotest/query/expected/rfc62_test002.txt index dfba700831..c55dde2b9e 100644 --- a/msautotest/query/expected/rfc62_test002.txt +++ b/msautotest/query/expected/rfc62_test002.txt @@ -5,52 +5,55 @@ Content-Transfer-Encoding: binary - - - 363237.62610408955045148.789110125 - 591752.16423774395386497.208 - - - - - - 493479.37420531,5386074.14118232 495062.336832765,5385983.99124965 496639.674560181,5385894.1616558 498248.095687447,5385802.56185817 499839.824008464,5385711.91271809 501136.55,5385638.064 501467.943141889,5385767.80541868 502638.13038141,5386225.93726688 503053.46464599,5386388.54188931 503331.026,5386497.208 503699.302,5386362.789 503698.47332,5386220.67017644 503689.147461229,5384621.28310618 503685.055,5383919.425 504644.774816817,5383819.88892449 505192.831,5383763.048 506067.396491085,5383051.22448901 506253.563241776,5382899.70025046 506630.795,5382592.665 507778.537,5382437.824 507871.292629229,5382391.32496513 509368.38182872,5381640.82385308 509937.620566855,5381355.46055867 510949.994331869,5380847.95062758 512525.992895043,5380057.89170881 513230.628453252,5379704.65305729 514170.309633563,5379233.58441887 515764.572623581,5378434.3694173 516470.849667691,5378080.30787761 517228.900216171,5377700.29192411 518897.19338599,5376863.96508426 519529.106322551,5376547.18278313 520047.475,5376287.321 520466.380787187,5376350.25746135 522091.309059952,5376594.38690181 522113.824951348,5376597.76969234 523693.324360806,5376835.07389432 525252.915,5377069.387 525268.759120909,5377065.65928362 526793.056620754,5376707.03107132 526885.07181278,5376685.38225025 526949.266,5376670.279 527300.354487204,5375095.81309175 527453.283,5374410.001 527653.748,5373931.762 527552.376,5373516.272 527561.324482355,5373492.93455844 527584.165,5373433.367 527689.675,5373378.304 527467.839,5373137.301 527419.949,5373112.983 527263.544,5372956.911 527236.163,5372848.09 527187.896,5372687.294 527355.022,5372578.487 527551.876,5372306.489 527284.621,5372027.292 526948.617157886,5371912.32001848 526808.709,5371864.447 526695.139,5371883.978 526590.927,5371920.846 526075.661,5371920.909 525551.907,5372120.757 525341.266173163,5371887.38511232 525248.727017776,5371784.85970117 525010.16,5371520.548 523716.552877634,5371602.24673338 523215.28,5371633.905 522261.964,5371345.684 522081.031,5370213.964 522049.140180406,5370143.10519535 521489.688,5368900.048 521544.961,5368616.504 521513.120101352,5368531.18873901 521240.425,5367800.523 521992.925984955,5366919.9380308 522064.973201944,5366835.62758122 523065.189,5365665.164 523666.976011613,5365532.75264644 524448.259809692,5365360.84656802 524886.643,5365264.389 525244.446667801,5365004.31195121 525427.486,5364871.266 526834.242807884,5364987.74375145 528421.99597393,5365119.20778105 530057.692838637,5365254.64149055 531318.261,5365359.015 531669.519146117,5365456.4436309 531899.413299638,5365520.20947626 533278.556856069,5365902.74314843 534241.395,5366169.806 534868.727747756,5366198.30814352 535862.499,5366243.459 536421.444,5366210.286 536454.059088547,5366166.01439868 536898.969905572,5365562.09409084 537405.791,5364874.137 537774.253,5364249.45 538097.711706761,5364153.29342588 538186.691,5364126.842 538319.041,5364034.482 538324.474611288,5363980.41003903 538327.413,5363951.169 538414.038,5363814.04 538395.746,5363692.567 538556.296,5363474.732 538811.359,5362962.664 539721.502142637,5362643.71368574 540222.235,5362468.237 540222.828774539,5362400.67690394 540234.913,5361025.725 539954.577111015,5360403.18325763 539237.043643193,5358809.75711129 538768.842,5357770.022 538904.831920846,5357188.24951072 539282.403957909,5355572.97521305 539282.922,5355570.759 540081.374204488,5353942.74454074 540329.13587328,5353437.56767859 540590.318,5352905.027 540942.106976105,5352331.80678252 541403.832,5351579.452 541417.411,5351552.996 541474.645,5351499.686 541494.378,5351448.573 541624.045,5351037.925 541767.388,5350787.633 541812.104206218,5350737.01131558 541915.439606497,5350620.02885074 542131.328,5350375.629 542342.064,5350459.941 542592.8,5350317.92 542980.498,5349690.624 543341.824,5349263.856 543389.647582808,5349143.8744296 543502.934526602,5348859.65596197 544030.594209357,5347535.84386643 544389.417,5346635.616 544768.189708664,5345907.09214577 545042.706,5345379.093 545073.768,5345257.683 545021.138,5345107.205 545118.353,5345016.884 545179.190362287,5344923.47621679 545339.834,5344676.829 545269.944,5344570.675 545186.589398349,5344588.4800933 545115.225,5344603.724 545081.255,5344466.053 545106.151,5344394.924 545191.755318209,5344356.5039508 545227.844,5344340.307 545298.941,5344346.737 545371.522,5344400.113 545523.83,5344463.388 545586.267,5344417.879 545628.81,5344307.061 545635.73476791,5344288.83903495 545677.475,5344179.003 545516.198,5344179.26 545555.649,5343991.229 545445.555,5343934.775 545421.307,5343871.903 545491.434,5343639.037 545538.047,5343613.163 545681.931,5343700.456 545746.764,5343666.085 545703.861,5343435.096 545706.126,5343306.977 545734.89,5343192.657 545789.228,5343078.85 545910.732,5342898.581 545988.563,5342763.042 546114.709,5342698.909 546115.698565205,5342696.85945804 546147.23,5342631.553 546099.611,5342525.263 546179.368,5342382.332 546158.143,5342277.49 546150.242,5342183.254 546163.392,5342087.953 546233.891,5341968.105 546353.795,5341862.244 546384.093,5341764.612 546371.817,5341675.898 546406.042,5341602.999 546467.242,5341562.122 546531.158,5341491.935 546595.782,5341335.301 546682.801,5341392.514 546731.492,5341367.902 546734.074,5341254.298 546793.797,5341142.706 546796.920124315,5341069.75795911 546800.946,5340975.724 546829.702804815,5340970.51317348 546859.637,5340965.089 546935.417183097,5341071.23316396 546936.136,5341072.24 546994.659,5341132.003 547025.26,5341199.564 546963.581,5341297.553 546887.189,5341353.43 546935.716,5341398.907 547072.874,5341380.582 547160.491,5341339.93 547262.645,5341263.274 547371.941,5341246.27 547411.486,5341304.645 547431.656,5341385.091 547458.37,5341472.693 547509.618,5341562.351 547633.969,5341668.982 547780.999,5341777.041 547863.135,5341848.435 547938.604,5341902.793 547996.069,5342012.268 548007.097,5342074.731 548143.653,5342126.208 548308.86,5342204.793 548387.097,5342223.672 548433.107741179,5342228.82930415 548491.389,5342235.362 548715.885,5342303.656 548870.555,5342262.366 548906.069,5342283.049 548943.59,5342478.201 548975.205,5342520.155 549068.213,5342595.674 549082.311,5342611.542 549106.066,5342631.815 549156.741,5342640.279 549178.145,5342622.246 549222.795,5342635.598 549263.035,5342705.726 549286.127,5342707.16 549404.759,5342610.306 549423.329,5342586.074 549419.404,5342562.883 549425.606,5342537.617 549466.072,5342510.179 549505.77,5342500.024 549596.625,5342514.089 549689.059,5342607.213 549735.331,5342623.671 549807.163,5342642.514 549885.559,5342736.136 549938.37,5342806.687 549971.284,5342840.631 549986.154,5342838.599 550024.735,5342814.544 550035.879,5342814.024 550049.848570131,5342826.35841657 550071.906,5342845.834 550094.243,5342862.703 550318.605327384,5342887.60770346 550332.887,5342889.193 550868.403,5343258.589 551925.594654075,5343445.68418898 553425.443,5343711.118 553578.372584271,5343793.91646471 554224.079,5344143.512 554085.870587265,5344554.99014036 553914.031,5345066.596 553481.9264489,5345394.2815694 552677.609,5346004.234 552609.440410738,5346144.33610868 552346.012,5346685.742 552444.413,5347216.198 552402.526,5347288.068 552361.392,5347278.118 552339.54,5347255.994 552295.374,5347239.533 552289.772,5347243.496 552281.329,5347265.033 552284.446,5347284.823 552276.548,5347314.393 552280.935,5347330.49 552291.325,5347343.862 552283.775,5347357.997 552261.357,5347352.542 552266.636,5347383.777 552267.104,5347400.147 552259.794,5347433.119 552135.332922751,5347756.9139764 551818.987,5348579.912 552011.692122779,5349362.04263356 552311.103,5350577.259 551995.831180082,5350977.01317121 551766.796794742,5351267.42114651 551438.976,5351683.087 551558.184,5352415.97 551736.233514996,5352447.85081675 552226.802,5352535.69 552243.048600333,5352608.64290264 552606.198576243,5354239.3129685 552697.159,5354647.757 553325.020739725,5355090.22467331 554632.112,5356011.36 554909.239293551,5355952.68797318 556570.094131868,5355601.05996 557671.494,5355367.877 557813.151,5355282.853 557852.942,5355215.942 557871.717,5355150.979 557932.772,5355078.108 558020.656,5354938.197 558187.756692178,5354956.78989982 558778.765,5355022.55 558790.328,5355198.369 558702.307,5355270.335 558980.747,5355712.925 559635.379,5355565.659 559677.087,5355376.809 559786.810811494,5355374.80082759 559805.761,5355374.454 560859.984,5355728.689 560814.212227964,5356064.57548428 560813.302,5356071.255 560936.77,5356322.694 561414.838624699,5356616.91326795 562070.552,5357020.461 563038.704053898,5357233.97825157 563335.065,5357299.338 563434.912,5356225.854 564642.203329377,5356187.53414005 566223.008507408,5356137.35881654 567103.531216315,5356109.41070984 567349.329,5356101.609 567838.950266071,5356028.57469323 567893.874,5356020.382 567983.964348441,5356131.18676823 568287.36,5356504.342 569112.243,5356673.332 569443.754407045,5356673.74895058 569985.247,5356674.43 570188.606034177,5356175.6787925 570471.953,5355480.752 570693.19,5355401.973 570753.122,5355168.03 570553.534,5354928.086 570582.743058388,5354564.37549861 570632.193,5353948.626 571113.672375693,5353821.77213622 571321.57,5353766.998 571820.091694902,5352988.91756426 571842.076,5352954.605 572753.430929069,5352767.5145328 573241.44,5352667.332 574122.572,5352472.759 573760.517640225,5351433.58949544 573202.312,5349831.426 573206.581376533,5349773.97250468 573288.533,5348671.14 573541.192540589,5348175.20240659 573650.98,5347959.704 573715.909870876,5346529.39454321 573727.362,5346277.121 574594.340651411,5345907.36682371 575024.331,5345723.982 575406.126598792,5344926.54940408 575677.971,5344358.765 575794.823,5344303.805 575846.914,5344295.233 575882.736,5344300.341 575916.052,5344276.698 575950.266,5344232.068 575942.526,5344193.675 575931.616,5344176.546 575919.753,5344168.977 575904.466,5344139.747 575911.253,5344110.192 575913.739,5344093.859 575929.123,5344084.8 575982.415,5344032.705 576050.58,5343963.515 576139.078,5344071.23 576146.845,5344076.583 576154.723,5344089.04 576178.436,5344135.985 576198.8,5344186.59 576205.981,5344220.345 576268.150525235,5344257.21948135 576433.947,5344355.558 576460.035,5344455.958 576417.133,5344486.881 576399.273,5344526.786 576354.144,5344585.471 576316.658,5344597.013 576278.769,5344623.372 576276.991,5344663.801 576288.047,5344700.696 576291.346,5344731.62 576294.855,5344793.119 576317.462,5344814.419 576321.125,5344913.0 576349.05,5344935.274 576385.209,5344930.2 576414.963,5344941.406 576425.449,5344974.588 576457.025,5345019.169 577270.438,5345017.463 577419.695,5344869.717 577637.723,5344867.429 577638.74,5344807.844 577637.608,5344800.109 577633.787,5344777.823 577646.083,5344556.27 577858.395498627,5344374.82075384 578098.111,5344169.952 577983.545,5344010.28 577870.799266675,5343995.66099251 577339.663,5343926.792 577439.156,5343374.154 577418.045950075,5343349.80729019 577240.295,5343144.803 577351.031,5342737.143 577787.435,5342734.114 577877.676,5342773.635 577914.760715966,5342747.23188922 578338.551,5342445.507 578563.657,5342445.51 578891.533,5342877.409 579539.718,5343074.151 579580.062887345,5343081.82671725 580109.056,5343182.469 580428.643,5343386.14 580570.447,5343424.578 580677.436,5343415.589 580696.864,5343369.234 580882.552,5343338.819 580954.788,5343365.782 581109.486,5343367.669 581126.558,5343356.794 581153.692,5343349.151 581193.740207828,5343304.2287266 581245.307,5343246.386 581503.321,5343237.092 582188.375,5343343.567 582804.217608689,5342272.24544707 582857.38,5342179.764 583410.230499244,5341785.21975707 584115.486,5341281.911 584321.459250725,5340199.72573453 584373.67,5339925.41 584444.052922083,5339936.64709769 585781.454,5340150.172 586052.911303773,5340219.45571218 586060.401197404,5340221.36734848 586482.241,5340329.033 586722.47098628,5340235.02169628 586732.73026337,5340231.00684356 586733.455131214,5340230.72317468 586733.706,5340230.625 586734.346642791,5340230.77208047 587666.252684771,5340444.72153606 587998.941,5340521.101 588074.727157533,5340246.81160393 588103.872,5340141.329 588454.006,5339912.343 589289.403356798,5339559.18325302 589300.922048736,5338697.20336088 589330.88158939,5337083.19477104 589344.840832338,5335466.18659232 589375.799835842,5333832.17777631 589413.759065257,5332205.16868353 589447.718723428,5330598.15973728 589421.677569149,5328983.15297854 589404.637199152,5327394.14613183 589393.595521865,5325750.13889061 589391.554825624,5324141.13150972 589423.51370196,5322505.12249251 589449.47354742,5320910.11388143 589472.432393428,5319277.10519543 589492.391231896,5317645.09663268 589557.327364741,5316038.14876436 589610.247050873,5314432.24530066 589687.166826041,5312827.34054162 589760.086571563,5311223.43592443 589794.004664517,5309590.53503253 589813.924074779,5307985.63306279 589833.843145254,5306374.73141241 589854.761727334,5304754.83021731 589850.690324137,5303335.91779226 589849.684085117,5303211.98796954 589836.604834502,5301638.02294658 589832.518533866,5299924.1285249 589798.437037778,5298307.22945341 589824.356272078,5296703.32672913 589854.276024973,5295110.42310374 589891.711273188,5293825.43772011 589898.886326741,5293578.51503776 589900.694793715,5293498.51986128 589929.132166673,5292256.59471918 589933.561446002,5292093.60451093 589938.92656038,5291897.61628293 589944.665983588,5291687.94137658 589978.174239362,5290612.81826398 589988.033286093,5290296.71219285 589992.999549548,5289628.50289911 589997.657264298,5289007.72209249 590004.831688645,5288699.91846514 590021.925512196,5287966.18961244 590030.902163723,5287416.83060779 590047.888728129,5287100.83929792 590116.712163097,5285889.05999224 590136.447356351,5285541.38202484 590141.319825875,5285482.00858994 590175.239774093,5285070.33194198 590230.150033524,5284431.97369368 590273.753377139,5283924.92451864 590346.768671837,5282820.0795009 590359.934884135,5282321.34384726 590402.762389907,5281209.87528104 590403.198955841,5281188.00091585 590415.115143658,5280689.07781656 590416.300550313,5280640.07923013 590463.878699903,5279545.29749472 590490.045015092,5279050.93621315 590552.560083105,5277945.279267 590571.104668187,5277527.54101025 590576.16388836,5277451.23059324 590642.992486551,5276371.88525474 590677.095635271,5275864.33661944 590741.616737182,5274903.6128942 590756.607487748,5274689.18124283 590780.02667555,5274264.06806792 590821.121166164,5273556.46268782 590844.100980463,5273088.03833184 590859.025397483,5272784.54684905 590866.269046009,5272637.23848383 590905.219199914,5271479.27161332 590935.204816209,5271148.0304548 590944.950154602,5271040.72081967 591043.399631439,5269877.75215533 591053.769301984,5269755.19296268 591076.692479513,5269425.13953795 591110.517197168,5268259.48564049 591117.254888758,5267973.99391934 591128.122845498,5267811.8733961 591206.009888956,5266651.40546997 591199.616494462,5266222.16843626 591198.488342556,5266148.60815838 591175.006180318,5265104.63989 591175.439715822,5265012.45511298 591177.687918502,5263516.49940567 591178.432325836,5263386.50323498 591185.255417681,5262180.038753 591187.055459458,5261890.54726464 591185.737812806,5261770.48835248 591185.389639317,5260657.07797112 591184.567050358,5260286.58616161 591186.251345165,5260169.58869304 591203.585911612,5258692.558237 591206.144707272,5258557.62363551 591231.790581386,5257040.59378715 591239.281180766,5256698.72609417 591269.618002448,5255310.69324746 591290.448603308,5253691.72817665 591305.65503736,5252101.76256354 591326.173869598,5250510.79678628 591291.880300777,5248901.8326817 591296.39843466,5247279.68033507 591193.586980174,5247275.43286786 591221.166060928,5245605.90588963 591242.55956521,5244004.94002282 591286.202814154,5242404.97359231 591309.471500193,5240813.007405 591328.739695874,5239202.04166475 591344.570552771,5237596.07583646 591363.4010812,5235980.11010727 591378.544330248,5234371.1442482 591394.017360582,5232782.18812091 591420.004054301,5231157.24153439 591448.990594695,5229517.29534933 591475.977567139,5227928.34746962 591495.964618956,5226341.39958728 591521.951475128,5224737.45212944 591545.938530749,5223156.50389693 591566.925327205,5221541.55677295 591586.912063263,5219919.60983592 591626.898708537,5218299.78757514 591466.899466999,5218297.69547592 591480.886345409,5216706.71608139 591500.873003762,5215093.76854045 591530.859899174,5213513.81979972 591556.846369643,5211880.87277365 591590.833237315,5210296.92407028 591617.819976923,5208695.97592128 591635.806519539,5207072.02850491 591658.787079717,5205480.07127601 591684.746751559,5203843.08684967 591707.707415759,5202247.10199548 591737.667785504,5200640.11717552 591752.164237744,5199168.19328055 591745.051248586,5199157.97121544 591736.450994764,5199147.03135422 591727.360817793,5199139.1714658 591713.250707976,5199133.66157558 591701.69061102,5199128.86166826 591694.950522966,5199124.78173446 591688.71036928,5199118.07182361 591679.469948723,5199100.29203013 591669.629518109,5199082.05224353 591661.499009181,5199060.75247907 591657.138495057,5199039.52269857 591651.655586978,5199020.88079978 591650.817978316,5199018.0329286 591645.887660254,5199004.72307527 591638.387346142,5198991.37323288 591628.607062769,5198979.09338973 591609.086908203,5198971.29354405 591587.626729705,5198962.36371715 591563.856614487,5198955.82387707 591549.706571326,5198952.96396247 591532.706483829,5198948.07407893 591520.526421268,5198944.57416236 591503.416518085,5198947.18420787 591487.676834431,5198958.85416137 591476.116992589,5198964.40415597 591463.257050205,5198965.75419594 591439.577037757,5198963.40431567 591418.137065166,5198962.85440902 591402.3369922,5198958.64451415 591387.596923142,5198954.67461266 591372.306757534,5198946.71475157 591361.88654159,5198937.07488656 591351.456325752,5198927.43502162 591304.93543812,5198887.46559553 591277.244851213,5198861.24596072 591252.174400459,5198840.7862602 591238.044309966,5198835.94636498 591209.974085347,5198824.48659089 591185.473704708,5198806.90686083 591164.663437088,5198794.24706845 591143.243186502,5198782.22727256 591121.182996363,5198772.62745619 591093.642654176,5198756.32772701 591077.672374188,5198743.5179164 591064.162020583,5198727.87812286 591050.671645469,5198711.34833787 591035.341311237,5198696.33854601 591017.530831238,5198675.11882431 591002.060240344,5198649.51913515 590986.669767733,5198628.77939902 590973.759424895,5198613.57959931 590960.259056729,5198597.27981272 590947.948713249,5198582.09001055 590938.108526502,5198573.56013392 590918.558425989,5198567.75027178 590904.458294847,5198561.14039457 590889.758164789,5198554.52052 590878.218040119,5198548.3906275 590865.947874116,5198540.49075517 590853.017564862,5198526.62094327 590835.706776913,5198492.61134429 590827.656379556,5198475.51154325 590815.27566934,5198445.11188896 590807.865228319,5198426.25210237 590801.604854944,5198410.28228305 590799.154682936,5198402.96236412 590792.974432274,5198392.06249552 590781.944222379,5198382.41263536 590770.844114137,5198376.95273504 590759.913978962,5198370.39284465 590743.933954186,5198367.94293589 590734.783874538,5198363.83301434 590720.763627729,5198352.37318451 590701.123183212,5198332.22346265 590678.922733274,5198311.60375636 590661.822348884,5198294.14399798 590646.401913493,5198274.71425168 590624.981420651,5198252.34455949 590604.671096107,5198237.0347943 590583.300768642,5198221.49503596 590558.060368849,5198202.58532696 590540.330013877,5198186.21556145 590526.889800117,5198176.09571704 590516.419649661,5198168.87583184 590504.739512344,5198162.08594766 590492.529498122,5198160.35601659 590481.579391292,5198154.8961164 590462.528981496,5198136.08638067 590452.04861395,5198119.82658362 590441.59819886,5198101.58680577 590431.067667239,5198078.48707563 590423.507215111,5198058.96729799 590416.736703357,5198037.03754047 590411.006216019,5198016.21776774 590407.195565925,5197988.80805094 590405.235087562,5197968.71825495 590400.83464547,5197949.89845711 590395.204248641,5197932.83864748 590389.583819913,5197914.44885079 590360.542500582,5197856.66953909 590337.021288063,5197803.8301559 590322.27075184,5197780.01045213 590310.39021521,5197756.45073347 590301.83989959,5197742.43090738 590290.779488732,5197724.18113352 590280.779075703,5197705.94135503 590269.868913454,5197698.06147947 590253.21876847,5197690.31162771 590235.548562369,5197679.90180643 590219.688357719,5197669.73197498 590206.158043059,5197655.20217601 590200.9020524,5197647.37190981 590194.337650603,5197637.59239974 590185.677262455,5197620.48260484 590179.526974704,5197607.8227555 590176.976700304,5197596.09288133 590175.116546028,5197589.45295439 590160.376234443,5197574.89316135 590139.905207476,5197529.81369208 590122.754659444,5197505.08400942 590110.984178905,5197483.73427014 590099.853886948,5197470.33445032 590087.693555221,5197455.15465252 590075.353271417,5197441.95483619 590064.343021839,5197430.32499868 590052.562805392,5197419.99515188 590037.91260097,5197409.85531594 590026.242442697,5197401.96544483 590005.472367614,5197396.57558946 589993.272342065,5197394.18566682 589972.602587769,5197402.25567898 589953.18300385,5197417.61561399 589941.803344265,5197430.67553598 589928.463683839,5197443.49546892 589915.783937506,5197452.78543356 589907.204150616,5197460.81539246 589896.374337011,5197467.48537463 589879.214516341,5197473.18539417 589862.824677921,5197478.22541678 589847.684763466,5197480.20546397 589817.164845685,5197480.40559637 589803.08492372,5197482.18564083 589787.234937315,5197481.06572165 589770.215131557,5197487.4257339 589753.295409265,5197497.31571088 589680.976225268,5197524.01576544 589662.106490591,5197533.20575759 589645.596594144,5197535.82580422 589622.536800548,5197542.09584352 589587.437445058,5197565.60576507 589567.907784387,5197577.8857292 589546.078190946,5197592.77567748 589538.838425327,5197601.92561859 589527.948714554,5197613.01555644 589518.259016549,5197624.77548235 589506.189245361,5197633.19545171 589505.049383366,5197638.91540002 589499.559712858,5197652.28529151 589489.909952055,5197661.40524327 589434.07070408,5197687.46522851 589412.131036017,5197699.26520706 589400.071269417,5197707.91517373 589387.341602693,5197720.73510186 589378.831927032,5197733.61501096 589374.672070781,5197739.28497273 589369.252284741,5197747.80491165 589335.242630162,5197758.98494841 589318.732747143,5197762.26498756 589293.742897157,5197766.08505817 589265.763011661,5197768.09515976 589243.223114695,5197770.17523699 589217.07319437,5197770.89534344 589195.01324987,5197771.0054382 589175.523300135,5197771.15552139 589153.043299567,5197768.83564222 589126.173328579,5197767.32577407 589103.603473267,5197771.18583359 589067.693479392,5197767.77602371 589041.923444409,5197763.64617701 589012.183479457,5197762.09632179 588987.733498796,5197760.41644489 588960.273498246,5197757.57659272 588931.003501634,5197754.71674865 588906.01343427,5197749.26691197 588877.943450807,5197747.08705593 588858.973386897,5197742.39718553 588835.763347036,5197738.29732768 588819.913374687,5197737.84740117 588802.893332618,5197734.28751101 588784.433180284,5197725.8476762 588745.252639642,5197698.58812103 588726.862374672,5197685.29833495 588711.012161243,5197674.47851301 588702.962013683,5197667.29862042 588698.641925277,5197663.04868208 588692.011913514,5197661.84872311 588687.741978851,5197664.20871799 588688.892079148,5197668.63866835 588698.782407486,5197683.77847274 588702.562635755,5197693.97835355 588706.832796289,5197701.31826103 588712.403051732,5197712.86812048 588716.793510109,5197733.00789863 588700.933296408,5197722.18807661 588681.903104714,5197711.97826233 588667.862882262,5197700.95843452 588651.992684389,5197690.7986061 588635.402683002,5197689.00869649 588617.772658363,5197686.10880263 588604.8625519,5197680.17891876 588588.432540007,5197677.94901295 588569.392344313,5197667.52920121 588568.968985745,5197667.31239195 588557.8522352,5197661.61931126 588547.992076788,5197653.75943369 588540.762066345,5197652.54947749 588528.412025716,5197649.49956226 588507.092111163,5197650.93964085 588490.662084253,5197648.04974185 588477.872034581,5197644.55983302 588463.171917084,5197637.93996423 588450.931707928,5197627.62012214 588435.541479747,5197616.14030563 588416.051291207,5197605.93049428 588394.591106997,5197595.69069194 588376.280957076,5197587.26085754 588358.440790861,5197578.17102783 588337.000581682,5197566.83123678 588319.900429657,5197558.42139707 588298.460230781,5197547.51160183 588273.419989111,5197534.35184533 588251.399751503,5197521.68207071 588228.729586578,5197512.08226786 588209.209440476,5197503.63243956 588195.699337559,5197497.70255926 588181.739220396,5197491.10268779 588169.469069117,5197483.20282214 588127.08835378,5197447.51337199 588109.338037262,5197431.81361012 588076.167536795,5197406.40401537 588062.727332977,5197396.05418022 588040.007003099,5197379.18445262 587997.189861146,5197355.28233246 587958.036162317,5197333.42528241 587934.705835169,5197316.54555824 587900.945324469,5197290.46597456 587881.355060404,5197276.72620204 587867.284890095,5197267.69635691 587848.304604915,5197253.08659076 587828.074161195,5197231.39690275 587808.333671272,5197207.727233 587783.193123736,5197180.89761988 587766.632839135,5197166.53784091 587752.522488827,5197149.57807775 587745.732257522,5197138.66821992 587736.522042088,5197128.16836874 587730.271910456,5197121.67846324 587716.911795528,5197115.08859059 587694.711369148,5197093.81890817 587675.791005574,5197075.66917921 587662.200554507,5197054.29945952 587646.160169836,5197035.53972414 587622.279769051,5197015.13004106 587608.69953988,5197003.46022203 587589.04913941,5196983.54051516 587574.908610826,5196958.64083484 587565.00829315,5196943.50103515 587549.647782781,5196919.23135408 587540.387403603,5196901.45157881 587526.217157141,5196888.90177197 587518.816939183,5196878.42191328 587513.906830852,5196873.06199065 587475.196042997,5196833.68257137 587466.655723194,5196818.56276583 587456.105228056,5196795.47305158 587447.334793776,5196775.27329955 587426.384069539,5196740.78375027 587410.293298763,5196704.82419429 587398.562542597,5196670.03460656 587380.481562538,5196624.55515828 587366.190803783,5196589.28558758 587347.020127911,5196557.02600837 587327.929317525,5196518.81649047 587314.23855874,5196483.55691752 587296.277646554,5196440.94744036 587285.827234818,5196421.39769053 587275.336907821,5196405.57790241 587258.686522841,5196386.37817774 587240.856106155,5196365.60847489 587227.98572128,5196346.88872802 587212.455244236,5196323.72903949 587199.004821805,5196303.24931373 587185.484489313,5196286.7295474 587173.064104207,5196268.01979873 587168.223898197,5196258.24992236 587163.193747467,5196250.90002183 587144.093191878,5196223.72039212 587129.412808739,5196204.76065684 587115.322662993,5196196.39080917 587096.402530814,5196187.96098466 587068.792084367,5196164.40135765 587050.871800577,5196149.36159726 587039.241604152,5196139.05175853 587031.931475344,5196132.3318624 587023.881323642,5196124.49198137 587015.953105316,5196117.00221901 586992.580754886,5196094.9224347 586964.53051538,5196080.40271676 586951.730491577,5196077.57280607 586939.480530623,5196077.61286298 586930.930460349,5196073.30294781 586919.780208735,5196060.5631325 586897.029712456,5196035.31350178 586872.529340524,5196015.33382462 586835.68847428,5195971.57445331 586813.588136341,5195953.39474664 586794.58788868,5195939.66497915 586784.147715803,5195930.4751241 586769.397436609,5195915.9253453 586755.387185038,5195902.70554921 586744.236920685,5195889.31574148 586730.716613668,5195873.67596848 586719.726349092,5195860.28616011 586712.936126887,5195849.38630597 586703.595872443,5195836.67648281 586694.975680448,5195826.8566261 586683.425585446,5195820.94674245 586665.725424698,5195811.20692794 586622.865243747,5195796.91728017 586582.025195185,5195788.82755819 586559.945052865,5195779.24776306 586542.185001331,5195774.35789842 586526.414894799,5195767.28804722 586511.03465958,5195754.49825415 586493.82445946,5195743.00845621 586473.758613228,5195728.45415584 586473.034191215,5195727.92871298 586460.164032538,5195718.91886859 586447.243726959,5195703.29909382 586431.253494387,5195690.49930414 586414.073240761,5195676.56953205 586398.83302122,5195664.44973183 586382.20284978,5195654.27991781 586362.052757661,5195647.15008869 586339.492672947,5195639.99027143 586326.092639414,5195636.49037208 586313.182545683,5195630.35049818 586297.922356123,5195619.54068464 586239.912275238,5195607.24109084 586213.012355678,5195606.85122332 586194.702459283,5195608.79129025 586175.202527376,5195608.95138161 586160.642644191,5195612.05141839 586143.592665855,5195610.4815163 586121.672741036,5195610.60161962 586105.182824558,5195611.91168447 586012.442814525,5195597.56227868 585983.132887786,5195596.48243003 585966.072919379,5195595.35252344 585942.752828907,5195587.74271535 585919.572762354,5195581.23289501 585870.112760303,5195573.68321133 585796.232735106,5195561.37369507 585746.842854756,5195559.34395277 585712.032814533,5195552.23419481 585679.152811925,5195547.12440644 585661.367196132,5195543.78459015 585634.91243334,5195523.11487374 585607.791931338,5195496.04529199 585587.121714185,5195482.95553059 585567.161562901,5195472.97573272 585551.981493441,5195467.46586432 585533.791404237,5195460.58602501 585505.811518506,5195461.50614952 585483.161563497,5195460.07627352 585441.311455623,5195448.67659626 585432.732356882,5195443.09280206 585365.090631824,5195399.06749319 585316.56012397,5195368.16805768 585280.319737416,5195344.71848361 585239.069391127,5195322.29892302 585208.268998482,5195299.35931787 585074.126805628,5195176.82128407 584917.96486975,5195061.91328176 584889.584452391,5195037.91367918 584867.854023639,5195014.45403853 584858.823763025,5195000.87422927 584852.243456499,5194985.56442674 584836.613141685,5194968.36468898 584831.853038493,5194962.78477256 584808.762843308,5194949.88502505 584793.042671666,5194939.29521655 584780.952478743,5194928.31539452 584746.041678369,5194885.2660314 584726.721244485,5194861.83637984 584674.790426929,5194815.0071424 584657.19035791,5194808.80729629 584640.680465025,5194810.99735394 584619.990524693,5194810.26746383 584603.050358897,5194799.65766237 584503.478615705,5194701.21922258 584468.627719959,5194653.30991578 584446.957195369,5194625.00033104 584427.046745276,5194600.46069678 584404.066381612,5194579.41104001 584391.346232398,5194570.19120361 584291.034924438,5194491.15256438 584184.023492333,5194404.74404223 584162.253119124,5194383.26438593 584139.89272035,5194360.4547473 584128.562297041,5194338.46504452 584119.651874604,5194316.94532453 584108.931435569,5194294.30562596 584084.71089062,5194264.19607715 584009.419376432,5194178.89739061 583968.488572612,5194133.32809687 583928.488177406,5194107.18858604 583893.357732599,5194079.56906716 583883.694145455,5194074.67601182 583867.38755773,5194066.41934326 583846.727706804,5194052.84287567 583836.52725215,5194046.13972265 583756.755905956,5193967.18099636 583724.295297683,5193932.10154781 583711.624848325,5193908.32187421 583691.254414347,5193883.78224845 583591.823615985,5193826.60338736 583570.793274388,5193806.24371974 583557.39301044,5193791.05395607 583533.972641526,5193768.89432087 583511.022243702,5193745.42469792 583501.842204663,5193741.76478552 583489.182202116,5193739.1648793 583468.771606054,5193706.6853432 583451.931093753,5193678.88573722 583421.77064221,5193651.33619733 583390.350062707,5193617.37673521 583358.459490698,5193583.63727348 583295.798276023,5193512.85838203 583274.147510384,5193471.75895 583259.886959878,5193442.44934912 583183.265656295,5193364.20061636 583141.784560925,5193302.98151292 583130.984022225,5193274.82188234 583114.903491413,5193245.93228762 583092.602798409,5193207.91282721 583051.911650411,5193144.06375114 583022.851151542,5193113.8842399 582995.61085177,5193093.66460846 582981.090696483,5193083.09480269 582973.420440263,5193069.0949991 582963.230126083,5193051.75524605 582965.710029067,5193047.59527934 582960.259836966,5193037.15542444 582950.669525145,5193020.04566576 582942.259245083,5193004.71588108 582929.178742569,5192977.62625225 582917.718302239,5192953.87657773 582900.987842822,5192928.05695432 582878.067409964,5192902.16736469 582811.746262828,5192832.21849791 582783.935916247,5192809.34890141 582762.175780734,5192798.0191439 582742.675853992,5192797.30925566 582726.855834484,5192792.89938923 582728.165679079,5192785.63946347 582723.335472528,5192774.54961328 582716.255239147,5192761.65979524 582704.155077147,5192751.1299776 582683.535028339,5192744.22016494 582667.214852815,5192732.09038784 582641.194550911,5192711.66075561 582619.324345211,5192696.81103885 582597.054055172,5192677.75137156 582578.393786582,5192660.5216646 582522.193068794,5192612.99249891 582493.15276908,5192591.8628919 582455.592574425,5192573.92329501 582352.581983529,5192521.784435 582331.8718484,5192510.47467376 582311.941678437,5192497.62492575 582296.911384177,5192479.78520769 582281.851139437,5192464.35546273 582252.572755061,5192449.44172849 582246.710938041,5192446.455854 582218.130851991,5192435.69612955 582176.900740979,5192420.79652024 582087.280198283,5192373.47753914 582058.77999275,5192356.76788231 582023.069747915,5192336.42830578 581955.249275542,5192297.34911592 581865.088646742,5192245.18019697 581831.138468663,5192228.39057209 581808.058491843,5192224.11074617 581774.088363572,5192209.7510941 581708.067913297,5192171.80188511 581682.717725523,5192156.46219784 581648.177317825,5192127.98271051 581552.036389063,5192058.75402492 581521.216055931,5192034.73446767 581494.055645024,5192007.68492526 581462.6652673,5191981.23539948 581436.664922932,5191957.72581081 581419.114809399,5191947.7860208 581407.104511649,5191929.97629043 581400.534422889,5191923.93639561 581393.864259675,5191914.14654425 581389.124135873,5191906.79665439 581379.463924818,5191893.87685533 581371.613718802,5191881.64703847 581363.853609133,5191874.25716575 581351.133483073,5191864.82734372 581331.763370172,5191854.41756959 581310.553309983,5191846.18778071 581291.123294657,5191840.63795137 581267.453294473,5191834.79814878 581248.683201565,5191825.50835878 581234.11279107,5191818.05308999 581231.463031061,5191812.69860067 581220.142829084,5191799.75881157 581202.792409343,5191774.37919856 581189.201998844,5191750.3795491 581182.131764421,5191736.8397436 581161.351287257,5191707.6701935 581134.22107282,5191690.10054557 581094.240906154,5191671.69097873 581060.990822217,5191659.11130778 581013.660822823,5191647.23170708 580971.870897801,5191640.48201675 580927.510968046,5191632.83235118 580879.07083546,5191613.87283887 580844.730571352,5191591.79328453 580798.870197524,5191561.18389313 580753.92957731,5191518.24463966 580717.929110997,5191485.33522101 580701.898740805,5191462.40557576 580688.208481239,5191445.6858457 580679.778474079,5191443.14592222 580664.348773884,5191454.40587812 580653.504886832,5191448.80186727 580648.578693681,5191446.25606061 580633.148334579,5191423.99640466 580622.667795934,5191393.8668123 580612.717354449,5191368.80715835 580595.957193304,5191356.23739794 580566.72717941,5191347.9076584 580551.667152948,5191342.6278041 580532.436852851,5191322.29814781 580509.106581813,5191302.35851017 580485.446584917,5191296.30871331 580443.066407771,5191276.11918598 580403.986033909,5191246.6997477 580350.455650314,5191212.90044224 580282.635433514,5191183.77116369 580205.8351252,5191147.45202046 580143.014865834,5191117.28272746 580078.424565554,5191084.44347641 580048.064015281,5191047.87407583 580029.533560725,5191019.40451381 580004.983328769,5191000.76487116 579967.953262509,5190987.26523939 579923.323081154,5190965.71574531 579868.462645619,5190928.15649751 579835.761993633,5190885.38718536 579816.671490524,5190854.03766205 579793.510983096,5190821.3081784 579752.440480473,5190783.48145969 579746.140396182,5190777.67896152 579676.829948938,5190735.07985899 579630.659385306,5190692.7906212 579564.698451875,5190625.53179203 579531.737954913,5190590.25239741 579510.39743232,5190556.89291362 579492.626984608,5190528.4333517 579465.656543213,5190497.64387059 579439.936264655,5190475.69427822 579407.555802436,5190442.1848611 579362.204921486,5190382.92582383 579339.744278964,5190342.71642941 579321.303922697,5190318.65682098 579295.373732555,5190301.10717924 579263.973593102,5190284.59755719 579237.083257912,5190259.09801555 579207.19268387,5190220.11865133 579181.76199461,5190176.3393184 579152.311654602,5190149.70980606 579110.751401464,5190124.02035368 579063.201085565,5190093.18099791 579044.428208018,5190081.66904062 579019.090823164,5190066.13157752 578966.180426366,5190029.27232584 578922.870091355,5189998.49294618 578888.639691135,5189966.94352281 578862.559068552,5189926.0241635 578838.52873908,5189901.23460032 578815.538645213,5189889.24487867 578789.168433249,5189869.93526434 578763.268194193,5189849.30566317 578744.388260847,5189847.06580132 578739.028178565,5189841.0459048 578730.088028998,5189830.34608527 578722.417797773,5189815.68630555 578714.157532672,5189799.03655312 578703.397418341,5189789.63672896 578684.507498179,5189788.06685941 578669.177653521,5189791.61690765 578656.517661476,5189788.13702409 578638.957564492,5189777.5472545 578621.567441753,5189765.62749988 578599.897194325,5189745.71786623 578574.547025596,5189728.84821818 578547.887013065,5189719.89848327 578514.616975632,5189707.54882835 578480.017123221,5189704.66906801 578451.617018215,5189690.18940999 578426.157008175,5189681.69966285 578404.137254432,5189688.0197177 578390.75721403,5189681.66987328 578363.196990006,5189661.02028473 578327.946982147,5189649.54063194 578299.937171879,5189650.94078151 578278.577344653,5189653.52087737 578266.007222363,5189642.99107864 578252.697079807,5189631.13130036 578236.427081023,5189626.07145793 578210.387042809,5189615.80173633 578202.66688166,5189604.68191607 578190.586708135,5189591.51214648 578172.586592704,5189579.59239713 578148.41646721,5189565.16271486 578125.736166164,5189541.71313253 578105.806005074,5189526.67343263 578095.466141187,5189530.73344535 578078.346282794,5189532.93352092 578044.546143635,5189514.63394327 578024.105863996,5189492.97432665 578006.305463845,5189465.61476322 577980.784908734,5189427.3553778 577969.58454528,5189404.05572625 577956.004146988,5189378.08612131 577946.473985791,5189366.26632124 577928.184078295,5189365.36644178 577905.774027909,5189355.37669693 577875.223760487,5189330.94717567 577852.283608033,5189315.20750383 577823.443279063,5189287.92800728 577813.893143505,5189277.43819169 577794.103006342,5189263.5084794 577775.96288833,5189251.14873826 577752.612670999,5189231.65911498 577737.782344154,5189208.9794792 577720.962045222,5189187.14984524 577697.601857313,5189169.20020383 577674.55185403,5189161.41043743 577643.621920768,5189154.83070399 577613.981867357,5189142.10103753 577600.976878164,5189133.86534911 577554.261538406,5189104.28185795 577525.361292531,5189081.19231351 577506.271013892,5189059.55269228 577487.170755922,5189039.02305776 577467.220639836,5189025.97333749 577445.970652165,5189019.52354485 577439.016374108,5189014.65756724 577416.430456434,5188998.85397575 577388.810326058,5188982.39434393 577346.119976504,5188948.76501319 577331.049773146,5188932.47530347 577324.259372818,5188908.13564167 577317.289001535,5188885.32596236 577306.058691942,5188864.45628539 577292.998421472,5188845.10660111 577277.037984339,5188815.56705901 577256.837573067,5188785.97754359 577235.217266854,5188761.66797259 577231.376946104,5188742.64822839 577223.136663936,5188724.23850369 577194.026727023,5188717.68876193 577171.666606075,5188703.28907487 577143.046180313,5188669.84965918 577122.645849081,5188644.45009502 577118.845473407,5188622.34038885 577112.545013641,5188594.70076574 577100.804574992,5188566.32118521 577082.344269207,5188542.93158509 577060.873958322,5188518.18202034 577039.153780593,5188500.70236827 577017.503733784,5188490.49262684 576997.663457883,5188468.19302251 576976.863053085,5188438.37351648 576958.882921322,5188424.6937953 576941.412707191,5188406.60412517 576925.372389443,5188383.24451097 576907.621924083,5188351.04501599 576887.501422347,5188315.94557151 576869.330921085,5188281.53610671 576850.410409065,5188246.22665786 576832.109885924,5188210.48721068 576808.439286293,5188168.50787388 576793.04890039,5188141.40830288 576769.77857616,5188114.86877432 576744.998475145,5188100.21910916 576718.308520516,5188093.03936414 576697.738433013,5188080.64964511 576674.428173853,5188057.64007408 576638.34786194,5188026.97067752 576595.637561303,5187994.44134583 576556.527286507,5187964.62195867 576523.347143508,5187944.34241699 576484.18693344,5187918.04298745 576452.246733115,5187894.92347366 576418.75640237,5187863.84406828 576390.546038795,5187832.8346292 576380.555688208,5187809.33498276 576375.655168337,5187778.18539894 576365.674810111,5187754.23575815 576353.144640668,5187739.96601379 576327.394423762,5187718.02644793 576309.174412461,5187710.51665601 576271.234189423,5187683.5772295 576240.402110655,5187656.93773156 576233.124068803,5187657.72787386 576225.834239865,5187660.05797394 576214.87431734,5187653.30825299 576198.634460779,5187644.93864603 576184.04461,5187638.5789846 576162.99478831,5187627.28949963 576146.354664754,5187603.26009628 576127.614756088,5187589.35060327 576106.594903317,5187576.30113996 576087.80507291,5187566.80159257 576062.475388892,5187558.98214016 576025.475953312,5187553.43286636 575998.106405775,5187551.32337852 575975.586768737,5187549.05380663 575954.31706723,5187544.37424284 575939.887183307,5187536.25460088 575929.737169917,5187525.10492104 575914.148521236,5187515.43169817 575912.317292537,5187514.29536597 575885.76744941,5187496.0960658 575861.527708176,5187486.08662179 575835.570282122,5187479.34088602 575831.208113,5187478.20725898 575808.84826181,5187463.81783671 575806.938006683,5187447.24807886 575805.357915364,5187440.398193 575803.077763077,5187429.33837247 575797.297703652,5187420.00859235 575791.927682993,5187413.31877177 575778.117784823,5187404.98912166 575762.437985094,5187400.379458 575738.178271836,5187391.91999511 575718.848555843,5187388.36038309 575706.768734994,5187386.23062436 575689.089024546,5187384.68095779 575658.259512094,5187380.98155176 575644.209726034,5187378.8218284 575618.250104463,5187373.86235177 575601.190352471,5187370.56269623 575581.200725273,5187371.4130405 575568.94094971,5187371.69325468 575548.361309906,5187371.21362617 575525.871638659,5187366.96407902 575486.642179172,5187357.65489286 575454.592496697,5187342.91564761 575445.582567783,5187337.72587297 575423.26285158,5187331.05635336 575400.373114675,5187322.60686632 575379.913304209,5187312.42735793 575363.673449834,5187304.0677517 575351.613609611,5187300.82800672 575337.753766715,5187295.57831905 575305.894027984,5187277.75910953 575294.484111203,5187270.77940017 575278.924141491,5187256.46985694 575264.544193081,5187244.60026201 575247.944219052,5187228.96075407 575232.384245731,5187214.43121369 575219.184318711,5187205.00156711 575211.97438135,5187201.16174364 575193.004376827,5187181.30233112 575179.86436086,5187166.80274745 575169.694380349,5187157.41304659 575163.294344543,5187148.73326979 575153.684407833,5187142.4435199 575138.614587,5187137.18385408 575123.334857743,5187136.98412819 575096.555336425,5187136.87460556 575070.565739892,5187133.2451133 575037.186251402,5187128.19577032 575001.006709423,5187117.15655273 574970.657155948,5187111.48716378 574943.557441657,5187099.89779182 574904.487756607,5187077.57876819 574888.307822264,5187064.58921988 574856.727897893,5187036.19014004 574844.997800766,5187018.40057331 574831.507654882,5186995.96109664 574820.837527609,5186977.52151932 574811.487438081,5186962.63187371 574799.147355995,5186945.06231515 574790.837282459,5186932.17262581 574786.057271899,5186926.59278133 574777.657321941,5186920.75300454 574766.21744136,5186915.7632711 574751.767587608,5186909.19361117 574728.857876346,5186902.06410885 574690.288321683,5186887.69497666 574663.758652189,5186879.205556 574639.70885492,5186865.89615218 574627.71890812,5186856.48648449 574599.569001107,5186832.53728825 574572.749105064,5186810.59804301 574546.379212499,5186789.31878148 574508.799314281,5186755.99987188 574479.069310937,5186724.76079637 574461.329265485,5186703.59138008 574449.419203712,5186687.56179498 574434.629200966,5186671.942256 574423.229255771,5186663.20256961 574409.409361287,5186654.87292114 574395.229347899,5186639.26337124 574383.249390361,5186629.19371206 574366.329646117,5186626.33404961 574356.119721672,5186620.03431121 574344.139752869,5186609.30466043 574331.169710523,5186593.26509453 574320.509570112,5186573.94552904 574310.609420016,5186554.85594712 574302.489280041,5186538.21630248 574290.109257948,5186523.95670362 574277.619173183,5186505.93715436 574257.768923824,5186470.62795526 574256.088764186,5186459.58812502 574240.768665721,5186437.78867416 574232.718430034,5186415.63909819 574227.588301466,5186402.77935251 574223.684064193,5186395.95814203 574222.248237434,5186393.44956588 574219.528073623,5186381.06977117 574213.0080005,5186369.970028 574205.397988375,5186361.27027388 574195.19804165,5186353.65055226 574190.40805513,5186349.4006915 574179.048064586,5186338.01103835 574169.408172286,5186334.14125926 574163.408196148,5186329.22142858 574157.058097245,5186316.79169929 574153.767894392,5186301.5319513 574153.857756445,5186293.60205016 574151.067688796,5186286.73218696 574149.907644965,5186282.96225541 574144.607531272,5186270.77250437 574138.617551084,5186265.62267646 574127.987581958,5186256.23298504 574118.487497906,5186241.34334316 574110.377347342,5186224.04370704 574105.847197163,5186210.53395904 574098.957013427,5186192.58430942 574092.09679139,5186172.43468715 574081.416675663,5186154.44510569 574083.456533079,5186148.29514722 574068.116470541,5186128.48567201 574053.696569537,5186119.04604899 574030.336646766,5186098.90672117 574017.336644795,5186085.0771285 574007.776649399,5186075.25742362 573992.766736471,5186064.48782808 573975.906909633,5186056.77822679 573958.987178643,5186054.5885566 573929.17770868,5186053.99909622 573912.917878793,5186046.73947856 573900.307957246,5186037.98981465 573884.858041081,5186026.55023558 573867.528045388,5186008.48077421 573860.607897058,5185992.51110036 573855.88780401,5185982.09131682 573848.427578628,5185961.05171695 573845.65748094,5185952.4218759 573840.337398661,5185941.99210323 573832.127398473,5185933.29236023 573820.147431741,5185922.55271045 573786.547618673,5185897.88362363 573762.367914731,5185878.61168353 573762.107728511,5185878.40430741 573733.297905499,5185858.20507846 573718.858039897,5185850.74543113 573703.808189165,5185843.50579192 573692.608182484,5185831.2361478 573685.428194412,5185824.31636394 573660.758422137,5185811.44696815 573628.128920935,5185805.96762079 573592.949439425,5185798.92833884 573543.569963968,5185777.14949795 573501.390442618,5185760.32046563 573462.590996195,5185751.46127168 573439.081290502,5185743.68179077 573403.541672717,5185728.2426223 573377.901794639,5185708.08333696 573358.171803147,5185687.56395061 573344.311548117,5185657.84457637 573339.551509464,5185650.50475482 573333.161466353,5185641.16498787 573326.581479419,5185634.91518501 573318.771533291,5185629.74539042 573309.131642629,5185625.87561202 573284.772058087,5185624.25606823 573250.312617559,5185620.30673469 573228.37300829,5185619.81713326 573215.023289799,5185622.08734309 573185.563951017,5185629.44777621 573161.744458162,5185633.78814689 573141.714885788,5185637.50845768 573117.965297806,5185636.33889724 573096.815625442,5185632.98931808 573081.76577971,5185625.9696766 573067.9358897,5185617.65002987 573051.056095696,5185611.71040739 573035.98627288,5185606.01074949 573022.716444046,5185601.88103941 573002.656711044,5185596.12147153 572985.386830585,5185584.67192629 572963.756998424,5185571.39248236 572943.377080221,5185554.38306366 572924.327179547,5185539.82358999 572911.707271822,5185531.73391885 572901.207333351,5185524.10420395 572880.55757392,5185516.13467496 572867.937677509,5185508.70499545 572847.487858503,5185497.435505 572829.298017428,5185487.28595987 572818.508054542,5185477.89627266 572801.708151257,5185465.5667305 572790.338157615,5185453.73708484 572780.778161579,5185443.70738383 572772.43811722,5185432.13768065 572764.177963032,5185414.17805757 572758.287840847,5185400.64833557 572754.777739596,5185390.90852264 572750.067626138,5185379.15875683 572744.217451047,5185362.54907342 572738.287389721,5185352.55930701 572733.147254315,5185339.04957137 572725.527051387,5185318.88996497 572720.17700194,5185310.22017136 572713.006996727,5185302.20040205 572705.207043887,5185296.59061328 572699.197088756,5185292.77076963 572690.017179593,5185288.25099167 572674.987297333,5185279.02137857 572664.197346232,5185270.29168318 572650.427374128,5185257.11209795 572635.39749963,5185248.33247916 572621.546562286,5185228.35492222 572613.967367093,5185217.42325747 572608.627317879,5185208.76346365 572603.297249695,5185198.99368382 572597.947200692,5185190.33389019 572592.607151353,5185181.66409651 572584.827157427,5185173.63433838 572572.277163765,5185160.47473119 572555.477250493,5185147.47519813 572542.317260473,5185133.86560767 572526.587313234,5185120.00606647 572516.427310152,5185108.85639088 572505.687287752,5185095.93674831 572494.997189865,5185078.60716117 572483.936986799,5185054.65766523 572476.846857566,5185039.3579877 572470.436630338,5185018.9983626 572458.606452552,5184995.69887223 572447.936321116,5184976.38931013 572440.136361488,5184970.33952724 572430.476502698,5184968.23972725 572418.986688215,5184966.7799519 572403.116945418,5184964.82026146 572389.187197395,5184964.65051338 572372.887436452,5184961.15085034 572342.467763219,5184947.55156953 572323.748027372,5184942.91196447 572296.988251046,5184927.1626456 572282.308304408,5184914.41307181 572267.018380139,5184902.32350055 572252.92843413,5184890.24390767 572237.618324172,5184867.12447783 572219.168208048,5184840.2251527 572207.458062935,5184818.91563524 572190.327986332,5184795.77623844 572178.657792256,5184771.59675703 572169.267545851,5184746.78724279 572164.327348991,5184729.74754935 572154.397015803,5184699.19811825 572137.876928713,5184676.06871057 572122.586986774,5184662.87915372 572102.457140098,5184650.06967892 572085.437329816,5184642.80007745 572067.147412785,5184627.81059757 572047.547445249,5184608.39119792 572025.507540646,5184590.04182844 571995.677878035,5184577.56252377 571969.448205679,5184568.42311176 571945.658459481,5184557.5536781 571921.858724659,5184547.34423621 571899.369047788,5184542.00470847 571856.839805398,5184540.61549006 571838.610017755,5184533.33591069 571813.510214286,5184517.60656298 571801.360275586,5184507.97690457 571785.430190751,5184485.51747845 571768.900105802,5184462.38807174 571759.609937469,5184442.2084972 571750.369675713,5184416.51899238 571739.829370916,5184386.83956208 571727.449125759,5184358.69014527 571716.348757412,5184324.60078161 571711.858339244,5184294.78124444 571702.387774686,5184250.78197852 571698.007326965,5184223.70793833 571692.236908138,5184188.04296499 571678.616515879,5184149.73370086 571671.196232769,5184124.72415482 571653.976058211,5184095.4148402 571644.785951899,5184078.9852161 571633.665821655,5184059.00567224 571627.515648978,5184041.95600142 571624.32529639,5184017.43637308 571618.724969507,5183991.79680247 571600.834696716,5183955.85758511 571590.314566998,5183936.54802198 571576.844376597,5183910.36860005 571562.614218627,5183885.27917787 571549.824119512,5183865.27966455 571528.394200569,5183846.50029121 571510.874258443,5183830.64081007 571488.834350841,5183811.85144794 571460.724580372,5183794.54217623 571438.744804931,5183783.6927113 571418.71503086,5183775.07318267 571398.545233649,5183764.91367635 571374.075382273,5183746.76435002 571351.605678971,5183739.66484594 571326.02591813,5183725.68548619 571294.916159008,5183705.68630341 571271.656297158,5183688.21694678 571247.816405377,5183668.30763197 571225.166521477,5183650.17827293 571204.37654095,5183628.31892831 571187.376704931,5183619.29935054 571158.087127232,5183612.1199707 571132.577487631,5183605.42051659 571110.027889609,5183604.49093501 571096.658200753,5183608.30112706 571077.838611777,5183612.05141812 571066.860652575,5183613.62728872 571065.088878364,5183613.88162442 571045.059311418,5183617.61193752 571026.329599271,5183614.08232049 571007.929833334,5183607.69273429 570992.639892787,5183594.28318229 570968.310070027,5183577.89383158 570945.090146329,5183556.67452303 570926.720122775,5183534.84513493 570909.489964588,5183506.19581403 570898.469905883,5183490.41621569 570884.259714622,5183463.12682293 570871.929610055,5183443.12730254 570859.719540318,5183425.34775146 570846.919679593,5183419.45805811 570836.619872268,5183419.55824262 570823.870150332,5183422.05844045 570813.530395015,5183425.23858606 570801.42062091,5183425.31880348 570783.120919982,5183422.89916471 570764.2611817,5183417.609573 570747.221395223,5183411.44995965 570725.851603927,5183400.17049034 570690.411847401,5183375.2814501 570663.581951345,5183351.59223917 570649.991933264,5183335.33269375 570633.58189381,5183314.63325641 570616.351942797,5183298.33377725 570588.892099255,5183277.06454677 570566.412398741,5183269.96504396 570546.832623008,5183261.57550544 570520.002940305,5183250.67613015 570490.723123479,5183228.94693868 570476.09310321,5183211.34742958 570470.502975612,5183197.39771027 570463.012791271,5183177.89809679 570450.762775238,5183163.20850729 570436.862986975,5183160.39879449 570420.363293979,5183160.41909218 570403.433561554,5183157.57943449 570392.343604713,5183147.74976147 570381.293581186,5183133.94013905 570372.193558583,5183122.37045255 570363.553516521,5183110.14076626 570356.72345227,5183098.6010384 570353.033381187,5183090.17121374 570351.123120402,5183072.29147877 570344.392915325,5183052.3618573 570329.633077584,5183045.58221136 570320.673286362,5183048.12234047 570317.483348693,5183048.30239578 570306.073631865,5183052.5825467 570291.53391412,5183053.29280021 570269.584314517,5183052.81320292 570248.914589126,5183046.17366197 570234.244833749,5183044.46394904 570216.075164516,5183044.02428297 570199.585453605,5183042.95459467 570171.705985217,5183043.73508826 570156.456211215,5183040.2454088 570133.966519518,5183033.58590106 570114.436664,5183020.34642481 570100.956704569,5183007.62683256 570088.6667523,5182996.67719599 570075.836711623,5182979.76764614 570063.006678291,5182963.29809065 570051.936692886,5182951.70844035 570046.406474163,5182932.2387917 570043.22631414,5182918.96902053 570037.686124739,5182901.25934935 570029.036094905,5182889.69965498 570011.416284919,5182881.33008158 569989.51660509,5182876.01054617 569971.256854339,5182870.50094743 569939.027419555,5182868.36155772 569912.227910176,5182867.83204905 569892.238285956,5182868.03240783 569869.6786984,5182867.55282187 569847.729092229,5182866.63323056 569827.04937914,5182860.66368159 569804.609618452,5182849.81422754 569779.479856731,5182835.85486237 569774.559838523,5182829.18503757 569764.859821277,5182817.16536839 569755.579832649,5182807.35566304 569742.139822776,5182791.54611053 569735.459749831,5182779.55638639 569726.179561524,5182757.61683796 569716.389662433,5182752.65707917 569693.829857317,5182738.93766465 569677.890002877,5182729.71807223 569658.340171398,5182717.79858005 569637.040278193,5182700.13919382 569613.770413978,5182681.9998495 569593.040564829,5182667.65041023 569570.490745804,5182653.06100704 569550.370874612,5182638.05156535 569530.66085104,5182614.23223034 569515.300790584,5182593.10278183 569506.574549822,5182570.92934209 569505.450563208,5182568.07328413 569496.190324888,5182543.04377578 569483.800086812,5182514.46437006 569470.38003798,5182496.22484917 569455.590036359,5182479.29533614 569443.369976415,5182461.73578477 569432.33109862,5182443.61244232 569426.729838928,5182434.41643985 569418.059619319,5182411.16689793 569425.899303846,5182400.88688907 569425.239174971,5182392.28701238 569425.178835684,5182371.5572819 569420.788696159,5182358.05753622 569413.338446781,5182334.37797781 569408.898170493,5182312.4883417 569398.477893109,5182283.70890316 569389.037499794,5182248.97952395 569374.22707952,5182206.47034284 569358.22686966,5182175.41103508 569355.026748154,5182164.35123632 569337.386753503,5182144.52181292 569314.727090957,5182139.19229277 569300.837283674,5182135.06259808 569278.337618193,5182129.73307506 569238.517916471,5182102.37415154 569227.607912969,5182089.67451393 569210.987946997,5182072.72503497 569194.537949091,5182054.01557576 569177.327983405,5182036.39611626 569162.577910712,5182015.05666038 569151.587807978,5181996.18710433 569145.247470781,5181968.32758047 569142.757177753,5181947.57789462 569143.14683113,5181926.85815611 569144.856517674,5181909.67834777 569148.37618133,5181893.17849775 569151.335804888,5181873.58869793 569156.595335077,5181850.93889601 569163.734739796,5181822.78913121 569178.053711115,5181776.42947198 569185.732982948,5181740.79979417 569193.362331326,5181709.79005736 569197.411873017,5181686.4702859 569203.351292579,5181657.87054849 569208.710889164,5181639.41069024 569212.82034998,5181611.23098056 569220.369598451,5181574.05132492 569226.309006979,5181544.79159591 569236.498332537,5181515.36179181 569260.446996192,5181461.39205525 569267.566642848,5181448.03209877 569276.616097779,5181425.20222977 569285.485599333,5181405.01232983 569296.295093732,5181386.62237129 569305.314592333,5181366.43246856 569312.504136087,5181346.89259067 569320.913656922,5181327.36269043 569328.003140948,5181304.07286282 569338.67240601,5181271.56308934 569347.661955572,5181254.463147 569363.331126925,5181222.01328165 569380.030329522,5181192.66335738 569382.568093636,5181152.94309365 569371.969329998,5181122.48191173 569359.216991597,5180965.2966766 569356.466493937,5180931.79715987 569400.714079377,5180835.79759475 569406.088560822,5180810.42282477 569470.210304718,5180686.2670101 569494.709058415,5180638.73592729 569517.958036324,5180603.42345928 569528.45725426,5180567.98622535 569551.956060471,5180522.54888325 569565.080144887,5180482.04916657 569632.701739862,5180353.29959366 569635.451395395,5180335.54977244 569643.076210057,5180333.11216466 569656.200418968,5180300.23734905 569788.693776375,5180050.3631495 569791.44343132,5180032.61332794 569866.564916472,5179906.48857881 569890.063717623,5179861.051234 569923.687200949,5179808.11380027 569952.435481921,5179737.30168549 570019.932231169,5179618.73947505 570020.057060485,5179608.5521038 570048.555680866,5179558.11473047 570100.428142559,5179464.73998058 570152.175857315,5179386.6150362 570165.05024202,5179364.36508607 570372.665308705,5179005.67838195 570398.414229224,5178970.49086053 570497.034354773,5178791.30384626 570507.408819459,5178771.11641432 570517.658412031,5178758.49138775 570530.657616301,5178725.67906924 570556.406575207,5178692.92901552 570572.030685854,5178657.55418139 570721.773641377,5178407.99212157 570752.772371449,5178367.74206594 570752.897157919,5178355.05472589 570794.270602216,5178309.74204377 570804.76993574,5178281.92970606 570828.143853053,5178244.11725905 570838.393529426,5178236.61716619 570843.643132023,5178218.86729637 570895.640990572,5178150.86720761 570906.140448343,5178130.55477369 570969.012585702,5178032.05487325 570982.761850645,5178003.99247814 571001.386233398,5177988.67983036 571074.382815125,5177868.86751359 571084.757445356,5177858.80495065 571105.881316483,5177815.80510957 571118.630746215,5177795.55510817 571135.317716381,5177769.52353058 571155.067089262,5177738.67939336 571178.3788501,5177702.36643709 571191.25342064,5177679.61618372 571204.252969058,5177654.36592674 571217.127621113,5177641.86568032 571245.626690569,5177593.92762302 571279.125724919,5177553.67697916 571351.748326282,5177427.55056576 571545.617370039,5177145.35936018 571579.116389857,5177102.54622782 571586.991079517,5177082.29607466 571607.74044401,5177052.10818228 571625.864878269,5177024.3578394 571649.114175186,5176991.60740149 571664.738618166,5176958.79460298 571692.987839876,5176928.60657654 571703.487440808,5176903.35637533 571747.361166652,5176847.98055676 571827.483687211,5176726.97906069 571866.107595415,5176681.72834714 571899.856518111,5176626.29021987 572000.478538353,5176490.2883681 572054.851855255,5176407.09987031 572095.975720517,5176361.84912263 572121.974892958,5176318.97364763 572225.096878772,5176183.03427991 572225.346775964,5176170.34677318 572238.096495436,5176165.40904531 572253.471029412,5176142.90876785 572269.095516803,5176114.9709854 572547.712485134,5175757.5910215 572760.893965755,5175497.02478568 572844.079123081,5175395.33584209 572849.453886825,5175377.5857502 572872.453320513,5175360.08535156 572898.327526985,5175319.77240606 572988.574969836,5175206.52085537 573545.934649102,5174557.76147007 573591.308408477,5174504.94822102 573761.428742256,5174303.75793427 574338.787798271,5173591.748739 574377.661762125,5173548.09188038 574390.286425936,5173533.93543306 574408.161060683,5173529.06014185 574413.285929702,5173524.06006126 574458.785242578,5173544.93429316 574497.159353301,5173519.99618045 574573.657783353,5173498.05743741 574797.278606743,5173490.55375758 574861.027290862,5173470.99022665 574950.025585292,5173461.86377021 574960.6500804,5173418.801141 574966.149742699,5173385.8635856 575005.648162765,5173266.92556518 575106.895002345,5173085.23661197 575180.017919609,5172981.36054137 575194.954994324,5172960.11032358 574893.083955377,5172742.02169226 574523.842045287,5172926.37124191 574431.78157212,5172973.06019764 574381.095188705,5172998.74850092 573839.10716416,5173273.56966953 573150.312561799,5173965.33082721 572757.510447767,5174371.68114196 572589.577408777,5174545.46524465 571865.534280649,5175294.60286016 571450.482921095,5175715.64156857 571150.678513564,5176019.77205896 571044.493889161,5176127.52402428 570945.121584151,5176228.30712328 569545.035437276,5177701.17800856 568850.236130719,5177670.9721113 568728.05098341,5177669.56812704 568116.875348472,5177673.73573361 568078.938388472,5177651.08013966 567961.378124028,5177646.45731162 567681.883438769,5177635.49372379 567475.88721203,5177610.9349869 567415.200550961,5177572.46726768 567333.139183745,5177520.43740788 566815.896282877,5177192.38357472 566323.65295412,5176877.8916627 565860.034179866,5176581.71164289 565488.224218152,5176079.77913727 565481.161765349,5176070.21673024 565453.411951475,5176032.74834523 565453.532749863,5175573.30925204 565453.655343666,5175310.37083667 565617.586827656,5174989.86688538 565431.585416794,5174453.1807221 565350.834790518,5174220.15001986 565246.771769923,5173952.30706415 565213.397238207,5173935.71381454 565064.274326279,5173861.40354321 564699.719173033,5173922.59738972 564566.534359829,5173944.97471402 563637.055802585,5174379.61723962 563363.247225477,5174254.4650846 563279.623352728,5174209.15379638 563105.250305583,5174073.93737222 563072.250867288,5174068.37540315 562974.752526144,5174051.90822064 562754.256276048,5174014.7242604 561973.771623433,5174095.5503325 561791.836067404,5173949.20888339 561777.273175625,5173882.36502476 561770.085367599,5173837.83365963 561659.957984095,5173392.17686987 561456.271602598,5173126.64754164 561350.647173711,5172988.96101705 561168.336898399,5172875.96336649 561122.274951155,5172846.62020246 561115.025082706,5172846.43281955 561069.525647811,5172819.40215804 561031.526119196,5172796.8088985 561001.213949163,5172774.24676329 560948.151970812,5172729.27861894 560796.715775128,5172583.28023213 560721.965447171,5172415.81171328 560764.897430781,5171949.49580538 561279.573152618,5171710.23630282 561498.193996626,5171691.76400878 561983.684774784,5171650.75615382 562458.0508877,5171622.31105753 562848.352779966,5171259.02192256 562859.539976858,5171248.61544857 562968.473798092,5171071.95666214 563003.593971717,5170638.89154875 562892.280327427,5170315.45417486 562605.344449561,5169956.862956 562521.533105642,5169922.6452817 562132.663885022,5169807.49421506 561900.478973164,5169652.65307941 561826.354795942,5169603.18515649 561760.418026613,5169559.18588925 561511.731892284,5169255.37536316 561503.544436728,5169245.37542689 561232.357556692,5168831.43952103 560884.234916915,5168461.19234912 560779.54675206,5168215.66112953 560843.231538989,5168057.81555244 561038.535743858,5167573.71625541 561087.032326471,5167318.58910831 561035.28141488,5167140.27627399 560868.532687849,5166982.99635267 560671.471626746,5166792.09160942 560268.163713109,5166565.78310088 559962.168798069,5166551.63082396 559945.856671366,5166560.75609864 559415.806337168,5166857.39010275 559202.310174281,5166873.86182968 559032.875720978,5166886.95794503 558492.756506145,5166559.43164058 558332.508941898,5166530.87106572 557965.577012159,5166465.43795764 557486.715217369,5166927.60404274 557309.346432995,5167097.17042 557218.850875963,5167183.67258413 557188.102386366,5167213.04831805 557035.047413113,5167359.39571248 557005.673859732,5167387.55266058 556951.989002865,5167438.83518359 556876.680213447,5167510.80571625 556710.56030707,5167383.80753859 556641.187430972,5167330.77705381 556165.510935237,5166648.46758678 555813.836652007,5166611.84826032 555643.345838285,5166843.66525374 555579.975893963,5167076.44918541 555516.231468122,5167353.67092001 555201.307696538,5167484.14578984 555092.187006035,5167489.24138159 554803.260918577,5167502.74625542 554761.950429776,5167538.02842401 554743.638821366,5167553.65383076 554610.457814958,5167667.68803543 554539.088767291,5167944.8785355 554537.714104559,5167969.69122118 554528.216463055,5168143.56751933 554514.594828928,5168391.3818683 554511.658053458,5168444.69476578 554450.598149601,5168462.25837087 554254.481493866,5168518.82441583 554212.483281361,5168530.91892377 554145.733204339,5168296.94974861 554139.232048814,5168174.63656741 554148.541998444,5167985.04144484 553470.693821533,5168011.80270507 553439.712858505,5169533.81262435 553427.732396188,5171162.82285219 553403.752034889,5172759.83301632 553383.771651848,5174368.84314128 553355.791643031,5175981.85334717 553351.810650603,5177595.86318564 553330.828407997,5179198.84213875 551741.892997035,5179287.86144805 550123.957608117,5179265.88261581 548516.021850388,5179243.90363668 546914.085935204,5179232.92441706 545321.149602686,5179201.94532802 543650.216504964,5179203.96679193 542032.28124317,5179264.98679513 540430.345259956,5179248.00759231 538756.412126805,5179248.02907838 537221.431611674,5179254.05218577 535605.424529336,5179255.07890249 533990.417465329,5179274.10537635 532381.410489906,5179317.13142772 530787.403635033,5179294.15814945 529189.396799056,5179301.18453868 527600.390098711,5179330.21047239 526019.384250467,5179566.23320789 524404.377615024,5179556.26010977 522796.370766589,5179501.28761151 521175.36375734,5179442.31544096 519525.325264365,5179380.28135453 519394.355935139,5179375.34611238 517916.328271882,5179332.36865748 516306.291369745,5179249.39311185 514626.252972295,5179185.41839672 513009.216520757,5179180.44179076 511387.180069969,5179185.46510066 509763.143811634,5179209.48807252 508151.107766549,5179225.51104065 506539.070830495,5179170.5356119 504914.034421812,5179180.55899068 503301.998167785,5179179.5824689 501695.962547851,5179211.60507996 500088.927078579,5179251.62748838 498462.889373269,5179247.62316423 496848.851735509,5179237.6171233 495302.815676504,5179229.61132198 495346.84729782,5180821.57463446 495340.878395801,5182446.53695695 495368.909626316,5184043.49993398 495375.93995181,5185617.46334803 495394.971242756,5187232.42574426 495420.002151849,5188825.38856517 495446.03275704,5190405.35159924 495503.064321413,5192017.3136871 495524.095615327,5193646.27538485 495564.126526155,5195247.23755609 495560.156779411,5196842.20002694 495603.188010644,5198467.16141745 495611.218295986,5200062.12367648 495637.248778541,5201663.08557362 495650.279726696,5203296.04675013 495676.309926805,5204889.00866588 495711.353257682,5206502.98535492 495747.398906727,5208109.96516074 495763.443521209,5209683.94554618 495759.488657558,5211278.92586094 495757.534996631,5212916.90557524 495769.579718949,5214497.88577718 495749.624731671,5216090.86619041 495735.659231801,5217311.85113751 494959.659115045,5217313.86122848 494970.705119564,5218929.84108862 494995.750458042,5220523.8209809 495003.795943673,5222123.80097645 495029.841657324,5223733.78054491 495057.886755016,5225323.76027618 495042.932737237,5226942.74021409 495039.977911121,5228534.72027518 495038.023517812,5230142.7000773 495024.069605433,5231766.67981888 495019.115198974,5233362.65844546 495028.162292141,5234979.63287876 495020.209257124,5236590.60763539 495020.25677792,5238222.58188682 495069.303271475,5239826.55568717 495109.350249214,5241446.52931016 495126.397469637,5243072.50317726 495135.444059105,5244676.47748387 495131.495656431,5246452.01174692 494969.496243897,5246452.45230827 494795.543352658,5248054.43014654 494770.589645386,5249647.40528159 494775.636449952,5251262.3794381 494778.681964043,5252833.35429019 494796.728248945,5254433.32831968 494809.774558379,5256034.30238152 494927.819864232,5257612.27448102 494951.864575155,5259160.24900567 495092.910126374,5260757.22018159 495122.945638598,5262364.19987764 495170.980399668,5263944.17941097 495203.018507466,5265676.15736808 495207.054052006,5267287.13741823 495199.089378382,5268885.11787935 495275.123248513,5270449.09659807 495273.160182488,5272126.07581067 495167.197052713,5273752.05834863 495209.110948557,5275537.03499854 495210.271082612,5277133.01502885 495241.46229853,5278739.99404238 495300.561408565,5280442.97098496 495352.374997453,5281951.95047877 495408.40961765,5283572.92834458 495395.446087868,5285230.90769069 493836.441274287,5285240.57888839 493825.510468566,5286899.93388971 493824.545357675,5288432.91510224 493806.596553693,5290017.89177349 493775.648970343,5291608.86854032 493750.699693533,5293150.84586706 493728.753104446,5294776.82181349 493731.649256886,5296388.79709995 493731.935767607,5296550.66961577 493776.730713998,5297964.77137662 493783.330511173,5298155.64321211 493838.093445917,5299556.7446901 493846.756365626,5299768.80360605 493904.424709744,5301149.71765226 493913.118863083,5301361.8390452 493921.563243168,5301580.83533847 493954.755974827,5302733.94120834 493960.013024057,5302956.00006086 493955.9946899,5304317.66657612 493956.565520734,5304575.66254475 493954.046946923,5305931.6415582 493953.86701868,5306165.63792368 493952.442891526,5307544.61650254 493952.326104836,5307798.61254779 493954.463320831,5309145.59144216 493954.877885721,5309403.33739959 493963.859589912,5310780.31549167 493964.929757913,5311018.81171352 493961.567301206,5312372.22816381 493960.325626435,5312628.97419436 493960.367397812,5313923.51638735 493431.384461735,5313928.53994069 493490.434964883,5315540.51239895 493379.48653035,5317130.50072358 493388.531252847,5318741.49042006 493360.577546444,5320361.4818554 493352.622551027,5321960.47243614 493352.081509723,5323845.46083966 492804.884251059,5323832.30308164 492804.728410709,5323846.4905109 492786.743364527,5325445.48257286 492776.789998417,5327070.47405103 492758.836543209,5328679.46609166 492788.880984317,5330290.45520526 492781.9264423,5331879.44663193 492780.972009399,5333482.43757738 492783.017951372,5335104.42818006 492746.065367191,5336708.42150474 492720.11243214,5338317.41412255 492733.157548137,5339930.4039689 492739.203056658,5341545.39423472 492746.063959719,5343265.32127047 492951.176985921,5343257.86832142 492951.052204394,5343265.36828563 492922.29539326,5344928.3569705 492934.35169547,5346483.34022611 492947.410593318,5348110.32261461 492938.469013554,5349693.30712058 492927.530125579,5351349.29100348 492967.586978927,5352956.27129905 492969.645361767,5354555.25463466 492999.703801659,5356189.23530221 493036.761092332,5357797.21559205 493033.82054541,5359419.19892554 493050.878525029,5361022.18076849 493074.959125943,5362394.97688371 493169.268276769,5362392.59408621 493175.88894744,5363984.13924712 493176.488060854,5364130.88764683 493189.479189174,5365604.18347051 493191.047021142,5365750.86928435 493204.537530078,5367207.16519159 493206.293819464,5367380.03820552 493234.845517007,5368810.83304566 493238.445335476,5368978.83094687 493267.496754917,5370400.12577509 493271.190904903,5370583.74849247 493312.272784848,5371989.04571345 493315.329980969,5373555.07264266 493327.388340583,5375159.09941695 493337.44704718,5376772.1264789 493341.504649911,5378352.15344092 493360.562932647,5379960.1795722 493372.621192826,5381564.20619109 493399.679270822,5383172.23157814 493468.737445095,5384806.25386166 493479.37420531,5386074.14118232 + xmlns:gml="http://www.opengis.net/gml/3.2"> + 363237.626104089 5045148.78911013591752.164237744 5386497.208 + + + + 492720.11243214 5166465.43795764591752.164237744 5386497.208 + 493479.37420531 5386074.14118232 495062.336832765 5385983.99124965 496639.674560181 5385894.1616558 498248.095687447 5385802.56185817 499839.824008464 5385711.91271809 501136.55 5385638.064 501467.943141889 5385767.80541868 502638.13038141 5386225.93726688 503053.46464599 5386388.54188931 503331.026 5386497.208 503699.302 5386362.789 503698.47332 5386220.67017644 503689.147461229 5384621.28310618 503685.055 5383919.425 504644.774816817 5383819.88892449 505192.831 5383763.048 506067.396491085 5383051.22448901 506253.563241776 5382899.70025046 506630.795 5382592.665 507778.537 5382437.824 507871.292629229 5382391.32496513 509368.38182872 5381640.82385308 509937.620566855 5381355.46055867 510949.994331869 5380847.95062758 512525.992895043 5380057.89170881 513230.628453252 5379704.65305729 514170.309633563 5379233.58441887 515764.572623581 5378434.3694173 516470.849667691 5378080.30787761 517228.900216171 5377700.29192411 518897.19338599 5376863.96508426 519529.106322551 5376547.18278313 520047.475 5376287.321 520466.380787187 5376350.25746135 522091.309059952 5376594.38690181 522113.824951348 5376597.76969234 523693.324360806 5376835.07389432 525252.915 5377069.387 525268.759120909 5377065.65928362 526793.056620754 5376707.03107132 526885.07181278 5376685.38225025 526949.266 5376670.279 527300.354487204 5375095.81309175 527453.283 5374410.001 527653.748 5373931.762 527552.376 5373516.272 527561.324482355 5373492.93455844 527584.165 5373433.367 527689.675 5373378.304 527467.839 5373137.301 527419.949 5373112.983 527263.544 5372956.911 527236.163 5372848.09 527187.896 5372687.294 527355.022 5372578.487 527551.876 5372306.489 527284.621 5372027.292 526948.617157886 5371912.32001848 526808.709 5371864.447 526695.139 5371883.978 526590.927 5371920.846 526075.661 5371920.909 525551.907 5372120.757 525341.266173163 5371887.38511232 525248.727017776 5371784.85970117 525010.16 5371520.548 523716.552877634 5371602.24673338 523215.28 5371633.905 522261.964 5371345.684 522081.031 5370213.964 522049.140180406 5370143.10519535 521489.688 5368900.048 521544.961 5368616.504 521513.120101352 5368531.18873901 521240.425 5367800.523 521992.925984955 5366919.9380308 522064.973201944 5366835.62758122 523065.189 5365665.164 523666.976011613 5365532.75264644 524448.259809692 5365360.84656802 524886.643 5365264.389 525244.446667801 5365004.31195121 525427.486 5364871.266 526834.242807884 5364987.74375145 528421.99597393 5365119.20778105 530057.692838637 5365254.64149055 531318.261 5365359.015 531669.519146117 5365456.4436309 531899.413299638 5365520.20947626 533278.556856069 5365902.74314843 534241.395 5366169.806 534868.727747756 5366198.30814352 535862.499 5366243.459 536421.444 5366210.286 536454.059088547 5366166.01439868 536898.969905572 5365562.09409084 537405.791 5364874.137 537774.253 5364249.45 538097.711706761 5364153.29342588 538186.691 5364126.842 538319.041 5364034.482 538324.474611288 5363980.41003903 538327.413 5363951.169 538414.038 5363814.04 538395.746 5363692.567 538556.296 5363474.732 538811.359 5362962.664 539721.502142637 5362643.71368574 540222.235 5362468.237 540222.828774539 5362400.67690394 540234.913 5361025.725 539954.577111015 5360403.18325763 539237.043643193 5358809.75711129 538768.842 5357770.022 538904.831920846 5357188.24951072 539282.403957909 5355572.97521305 539282.922 5355570.759 540081.374204488 5353942.74454074 540329.13587328 5353437.56767859 540590.318 5352905.027 540942.106976105 5352331.80678252 541403.832 5351579.452 541417.411 5351552.996 541474.645 5351499.686 541494.378 5351448.573 541624.045 5351037.925 541767.388 5350787.633 541812.104206218 5350737.01131558 541915.439606497 5350620.02885074 542131.328 5350375.629 542342.064 5350459.941 542592.8 5350317.92 542980.498 5349690.624 543341.824 5349263.856 543389.647582808 5349143.8744296 543502.934526602 5348859.65596197 544030.594209357 5347535.84386643 544389.417 5346635.616 544768.189708664 5345907.09214577 545042.706 5345379.093 545073.768 5345257.683 545021.138 5345107.205 545118.353 5345016.884 545179.190362287 5344923.47621679 545339.834 5344676.829 545269.944 5344570.675 545186.589398349 5344588.4800933 545115.225 5344603.724 545081.255 5344466.053 545106.151 5344394.924 545191.755318209 5344356.5039508 545227.844 5344340.307 545298.941 5344346.737 545371.522 5344400.113 545523.83 5344463.388 545586.267 5344417.879 545628.81 5344307.061 545635.73476791 5344288.83903495 545677.475 5344179.003 545516.198 5344179.26 545555.649 5343991.229 545445.555 5343934.775 545421.307 5343871.903 545491.434 5343639.037 545538.047 5343613.163 545681.931 5343700.456 545746.764 5343666.085 545703.861 5343435.096 545706.126 5343306.977 545734.89 5343192.657 545789.228 5343078.85 545910.732 5342898.581 545988.563 5342763.042 546114.709 5342698.909 546115.698565205 5342696.85945804 546147.23 5342631.553 546099.611 5342525.263 546179.368 5342382.332 546158.143 5342277.49 546150.242 5342183.254 546163.392 5342087.953 546233.891 5341968.105 546353.795 5341862.244 546384.093 5341764.612 546371.817 5341675.898 546406.042 5341602.999 546467.242 5341562.122 546531.158 5341491.935 546595.782 5341335.301 546682.801 5341392.514 546731.492 5341367.902 546734.074 5341254.298 546793.797 5341142.706 546796.920124315 5341069.75795911 546800.946 5340975.724 546829.702804815 5340970.51317348 546859.637 5340965.089 546935.417183097 5341071.23316396 546936.136 5341072.24 546994.659 5341132.003 547025.26 5341199.564 546963.581 5341297.553 546887.189 5341353.43 546935.716 5341398.907 547072.874 5341380.582 547160.491 5341339.93 547262.645 5341263.274 547371.941 5341246.27 547411.486 5341304.645 547431.656 5341385.091 547458.37 5341472.693 547509.618 5341562.351 547633.969 5341668.982 547780.999 5341777.041 547863.135 5341848.435 547938.604 5341902.793 547996.069 5342012.268 548007.097 5342074.731 548143.653 5342126.208 548308.86 5342204.793 548387.097 5342223.672 548433.107741179 5342228.82930415 548491.389 5342235.362 548715.885 5342303.656 548870.555 5342262.366 548906.069 5342283.049 548943.59 5342478.201 548975.205 5342520.155 549068.213 5342595.674 549082.311 5342611.542 549106.066 5342631.815 549156.741 5342640.279 549178.145 5342622.246 549222.795 5342635.598 549263.035 5342705.726 549286.127 5342707.16 549404.759 5342610.306 549423.329 5342586.074 549419.404 5342562.883 549425.606 5342537.617 549466.072 5342510.179 549505.77 5342500.024 549596.625 5342514.089 549689.059 5342607.213 549735.331 5342623.671 549807.163 5342642.514 549885.559 5342736.136 549938.37 5342806.687 549971.284 5342840.631 549986.154 5342838.599 550024.735 5342814.544 550035.879 5342814.024 550049.848570131 5342826.35841657 550071.906 5342845.834 550094.243 5342862.703 550318.605327384 5342887.60770346 550332.887 5342889.193 550868.403 5343258.589 551925.594654075 5343445.68418898 553425.443 5343711.118 553578.372584271 5343793.91646471 554224.079 5344143.512 554085.870587265 5344554.99014036 553914.031 5345066.596 553481.9264489 5345394.2815694 552677.609 5346004.234 552609.440410738 5346144.33610868 552346.012 5346685.742 552444.413 5347216.198 552402.526 5347288.068 552361.392 5347278.118 552339.54 5347255.994 552295.374 5347239.533 552289.772 5347243.496 552281.329 5347265.033 552284.446 5347284.823 552276.548 5347314.393 552280.935 5347330.49 552291.325 5347343.862 552283.775 5347357.997 552261.357 5347352.542 552266.636 5347383.777 552267.104 5347400.147 552259.794 5347433.119 552135.332922751 5347756.9139764 551818.987 5348579.912 552011.692122779 5349362.04263356 552311.103 5350577.259 551995.831180082 5350977.01317121 551766.796794742 5351267.42114651 551438.976 5351683.087 551558.184 5352415.97 551736.233514996 5352447.85081675 552226.802 5352535.69 552243.048600333 5352608.64290264 552606.198576243 5354239.3129685 552697.159 5354647.757 553325.020739725 5355090.22467331 554632.112 5356011.36 554909.239293551 5355952.68797318 556570.094131868 5355601.05996 557671.494 5355367.877 557813.151 5355282.853 557852.942 5355215.942 557871.717 5355150.979 557932.772 5355078.108 558020.656 5354938.197 558187.756692178 5354956.78989982 558778.765 5355022.55 558790.328 5355198.369 558702.307 5355270.335 558980.747 5355712.925 559635.379 5355565.659 559677.087 5355376.809 559786.810811494 5355374.80082759 559805.761 5355374.454 560859.984 5355728.689 560814.212227964 5356064.57548428 560813.302 5356071.255 560936.77 5356322.694 561414.838624699 5356616.91326795 562070.552 5357020.461 563038.704053898 5357233.97825157 563335.065 5357299.338 563434.912 5356225.854 564642.203329377 5356187.53414005 566223.008507408 5356137.35881654 567103.531216315 5356109.41070984 567349.329 5356101.609 567838.950266071 5356028.57469323 567893.874 5356020.382 567983.964348441 5356131.18676823 568287.36 5356504.342 569112.243 5356673.332 569443.754407045 5356673.74895058 569985.247 5356674.43 570188.606034177 5356175.6787925 570471.953 5355480.752 570693.19 5355401.973 570753.122 5355168.03 570553.534 5354928.086 570582.743058388 5354564.37549861 570632.193 5353948.626 571113.672375693 5353821.77213622 571321.57 5353766.998 571820.091694902 5352988.91756426 571842.076 5352954.605 572753.430929069 5352767.5145328 573241.44 5352667.332 574122.572 5352472.759 573760.517640225 5351433.58949544 573202.312 5349831.426 573206.581376533 5349773.97250468 573288.533 5348671.14 573541.192540589 5348175.20240659 573650.98 5347959.704 573715.909870876 5346529.39454321 573727.362 5346277.121 574594.340651411 5345907.36682371 575024.331 5345723.982 575406.126598792 5344926.54940408 575677.971 5344358.765 575794.823 5344303.805 575846.914 5344295.233 575882.736 5344300.341 575916.052 5344276.698 575950.266 5344232.068 575942.526 5344193.675 575931.616 5344176.546 575919.753 5344168.977 575904.466 5344139.747 575911.253 5344110.192 575913.739 5344093.859 575929.123 5344084.8 575982.415 5344032.705 576050.58 5343963.515 576139.078 5344071.23 576146.845 5344076.583 576154.723 5344089.04 576178.436 5344135.985 576198.8 5344186.59 576205.981 5344220.345 576268.150525235 5344257.21948135 576433.947 5344355.558 576460.035 5344455.958 576417.133 5344486.881 576399.273 5344526.786 576354.144 5344585.471 576316.658 5344597.013 576278.769 5344623.372 576276.991 5344663.801 576288.047 5344700.696 576291.346 5344731.62 576294.855 5344793.119 576317.462 5344814.419 576321.125 5344913.0 576349.05 5344935.274 576385.209 5344930.2 576414.963 5344941.406 576425.449 5344974.588 576457.025 5345019.169 577270.438 5345017.463 577419.695 5344869.717 577637.723 5344867.429 577638.74 5344807.844 577637.608 5344800.109 577633.787 5344777.823 577646.083 5344556.27 577858.395498627 5344374.82075384 578098.111 5344169.952 577983.545 5344010.28 577870.799266675 5343995.66099251 577339.663 5343926.792 577439.156 5343374.154 577418.045950075 5343349.80729019 577240.295 5343144.803 577351.031 5342737.143 577787.435 5342734.114 577877.676 5342773.635 577914.760715966 5342747.23188922 578338.551 5342445.507 578563.657 5342445.51 578891.533 5342877.409 579539.718 5343074.151 579580.062887345 5343081.82671725 580109.056 5343182.469 580428.643 5343386.14 580570.447 5343424.578 580677.436 5343415.589 580696.864 5343369.234 580882.552 5343338.819 580954.788 5343365.782 581109.486 5343367.669 581126.558 5343356.794 581153.692 5343349.151 581193.740207828 5343304.2287266 581245.307 5343246.386 581503.321 5343237.092 582188.375 5343343.567 582804.217608689 5342272.24544707 582857.38 5342179.764 583410.230499244 5341785.21975707 584115.486 5341281.911 584321.459250725 5340199.72573453 584373.67 5339925.41 584444.052922083 5339936.64709769 585781.454 5340150.172 586052.911303773 5340219.45571218 586060.401197404 5340221.36734848 586482.241 5340329.033 586722.47098628 5340235.02169628 586732.73026337 5340231.00684356 586733.455131214 5340230.72317468 586733.706 5340230.625 586734.346642791 5340230.77208047 587666.252684771 5340444.72153606 587998.941 5340521.101 588074.727157533 5340246.81160393 588103.872 5340141.329 588454.006 5339912.343 589289.403356798 5339559.18325302 589300.922048736 5338697.20336088 589330.88158939 5337083.19477104 589344.840832338 5335466.18659232 589375.799835842 5333832.17777631 589413.759065257 5332205.16868353 589447.718723428 5330598.15973728 589421.677569149 5328983.15297854 589404.637199152 5327394.14613183 589393.595521865 5325750.13889061 589391.554825624 5324141.13150972 589423.51370196 5322505.12249251 589449.47354742 5320910.11388143 589472.432393428 5319277.10519543 589492.391231896 5317645.09663268 589557.327364741 5316038.14876436 589610.247050873 5314432.24530066 589687.166826041 5312827.34054162 589760.086571563 5311223.43592443 589794.004664517 5309590.53503253 589813.924074779 5307985.63306279 589833.843145254 5306374.73141241 589854.761727334 5304754.83021731 589850.690324137 5303335.91779226 589849.684085117 5303211.98796954 589836.604834502 5301638.02294658 589832.518533866 5299924.1285249 589798.437037778 5298307.22945341 589824.356272078 5296703.32672913 589854.276024973 5295110.42310374 589891.711273188 5293825.43772011 589898.886326741 5293578.51503776 589900.694793715 5293498.51986128 589929.132166673 5292256.59471918 589933.561446002 5292093.60451093 589938.92656038 5291897.61628293 589944.665983588 5291687.94137658 589978.174239362 5290612.81826398 589988.033286093 5290296.71219285 589992.999549548 5289628.50289911 589997.657264298 5289007.72209249 590004.831688645 5288699.91846514 590021.925512196 5287966.18961244 590030.902163723 5287416.83060779 590047.888728129 5287100.83929792 590116.712163097 5285889.05999224 590136.447356351 5285541.38202484 590141.319825875 5285482.00858994 590175.239774093 5285070.33194198 590230.150033524 5284431.97369368 590273.753377139 5283924.92451864 590346.768671837 5282820.0795009 590359.934884135 5282321.34384726 590402.762389907 5281209.87528104 590403.198955841 5281188.00091585 590415.115143658 5280689.07781656 590416.300550313 5280640.07923013 590463.878699903 5279545.29749472 590490.045015092 5279050.93621315 590552.560083105 5277945.279267 590571.104668187 5277527.54101025 590576.16388836 5277451.23059324 590642.992486551 5276371.88525474 590677.095635271 5275864.33661944 590741.616737182 5274903.6128942 590756.607487748 5274689.18124283 590780.02667555 5274264.06806792 590821.121166164 5273556.46268782 590844.100980463 5273088.03833184 590859.025397483 5272784.54684905 590866.269046009 5272637.23848383 590905.219199914 5271479.27161332 590935.204816209 5271148.0304548 590944.950154602 5271040.72081967 591043.399631439 5269877.75215533 591053.769301984 5269755.19296268 591076.692479513 5269425.13953795 591110.517197168 5268259.48564049 591117.254888758 5267973.99391934 591128.122845498 5267811.8733961 591206.009888956 5266651.40546997 591199.616494462 5266222.16843626 591198.488342556 5266148.60815838 591175.006180318 5265104.63989 591175.439715822 5265012.45511298 591177.687918502 5263516.49940567 591178.432325836 5263386.50323498 591185.255417681 5262180.038753 591187.055459458 5261890.54726464 591185.737812806 5261770.48835248 591185.389639317 5260657.07797112 591184.567050358 5260286.58616161 591186.251345165 5260169.58869304 591203.585911612 5258692.558237 591206.144707272 5258557.62363551 591231.790581386 5257040.59378715 591239.281180766 5256698.72609417 591269.618002448 5255310.69324746 591290.448603308 5253691.72817665 591305.65503736 5252101.76256354 591326.173869598 5250510.79678628 591291.880300777 5248901.8326817 591296.39843466 5247279.68033507 591193.586980174 5247275.43286786 591221.166060928 5245605.90588963 591242.55956521 5244004.94002282 591286.202814154 5242404.97359231 591309.471500193 5240813.007405 591328.739695874 5239202.04166475 591344.570552771 5237596.07583646 591363.4010812 5235980.11010727 591378.544330248 5234371.1442482 591394.017360582 5232782.18812091 591420.004054301 5231157.24153439 591448.990594695 5229517.29534933 591475.977567139 5227928.34746962 591495.964618956 5226341.39958728 591521.951475128 5224737.45212944 591545.938530749 5223156.50389693 591566.925327205 5221541.55677295 591586.912063263 5219919.60983592 591626.898708537 5218299.78757514 591466.899466999 5218297.69547592 591480.886345409 5216706.71608139 591500.873003762 5215093.76854045 591530.859899174 5213513.81979972 591556.846369643 5211880.87277365 591590.833237315 5210296.92407028 591617.819976923 5208695.97592128 591635.806519539 5207072.02850491 591658.787079717 5205480.07127601 591684.746751559 5203843.08684967 591707.707415759 5202247.10199548 591737.667785504 5200640.11717552 591752.164237744 5199168.19328055 591745.051248586 5199157.97121544 591736.450994764 5199147.03135422 591727.360817793 5199139.1714658 591713.250707976 5199133.66157558 591701.69061102 5199128.86166826 591694.950522966 5199124.78173446 591688.71036928 5199118.07182361 591679.469948723 5199100.29203013 591669.629518109 5199082.05224353 591661.499009181 5199060.75247907 591657.138495057 5199039.52269857 591651.655586978 5199020.88079978 591650.817978316 5199018.0329286 591645.887660254 5199004.72307527 591638.387346142 5198991.37323288 591628.607062769 5198979.09338973 591609.086908203 5198971.29354405 591587.626729705 5198962.36371715 591563.856614487 5198955.82387707 591549.706571326 5198952.96396247 591532.706483829 5198948.07407893 591520.526421268 5198944.57416236 591503.416518085 5198947.18420787 591487.676834431 5198958.85416137 591476.116992589 5198964.40415597 591463.257050205 5198965.75419594 591439.577037757 5198963.40431567 591418.137065166 5198962.85440902 591402.3369922 5198958.64451415 591387.596923142 5198954.67461266 591372.306757534 5198946.71475157 591361.88654159 5198937.07488656 591351.456325752 5198927.43502162 591304.93543812 5198887.46559553 591277.244851213 5198861.24596072 591252.174400459 5198840.7862602 591238.044309966 5198835.94636498 591209.974085347 5198824.48659089 591185.473704708 5198806.90686083 591164.663437088 5198794.24706845 591143.243186502 5198782.22727256 591121.182996363 5198772.62745619 591093.642654176 5198756.32772701 591077.672374188 5198743.5179164 591064.162020583 5198727.87812286 591050.671645469 5198711.34833787 591035.341311237 5198696.33854601 591017.530831238 5198675.11882431 591002.060240344 5198649.51913515 590986.669767733 5198628.77939902 590973.759424895 5198613.57959931 590960.259056729 5198597.27981272 590947.948713249 5198582.09001055 590938.108526502 5198573.56013392 590918.558425989 5198567.75027178 590904.458294847 5198561.14039457 590889.758164789 5198554.52052 590878.218040119 5198548.3906275 590865.947874116 5198540.49075517 590853.017564862 5198526.62094327 590835.706776913 5198492.61134429 590827.656379556 5198475.51154325 590815.27566934 5198445.11188896 590807.865228319 5198426.25210237 590801.604854944 5198410.28228305 590799.154682936 5198402.96236412 590792.974432274 5198392.06249552 590781.944222379 5198382.41263536 590770.844114137 5198376.95273504 590759.913978962 5198370.39284465 590743.933954186 5198367.94293589 590734.783874538 5198363.83301434 590720.763627729 5198352.37318451 590701.123183212 5198332.22346265 590678.922733274 5198311.60375636 590661.822348884 5198294.14399798 590646.401913493 5198274.71425168 590624.981420651 5198252.34455949 590604.671096107 5198237.0347943 590583.300768642 5198221.49503596 590558.060368849 5198202.58532696 590540.330013877 5198186.21556145 590526.889800117 5198176.09571704 590516.419649661 5198168.87583184 590504.739512344 5198162.08594766 590492.529498122 5198160.35601659 590481.579391292 5198154.8961164 590462.528981496 5198136.08638067 590452.04861395 5198119.82658362 590441.59819886 5198101.58680577 590431.067667239 5198078.48707563 590423.507215111 5198058.96729799 590416.736703357 5198037.03754047 590411.006216019 5198016.21776774 590407.195565925 5197988.80805094 590405.235087562 5197968.71825495 590400.83464547 5197949.89845711 590395.204248641 5197932.83864748 590389.583819913 5197914.44885079 590360.542500582 5197856.66953909 590337.021288063 5197803.8301559 590322.27075184 5197780.01045213 590310.39021521 5197756.45073347 590301.83989959 5197742.43090738 590290.779488732 5197724.18113352 590280.779075703 5197705.94135503 590269.868913454 5197698.06147947 590253.21876847 5197690.31162771 590235.548562369 5197679.90180643 590219.688357719 5197669.73197498 590206.158043059 5197655.20217601 590200.9020524 5197647.37190981 590194.337650603 5197637.59239974 590185.677262455 5197620.48260484 590179.526974704 5197607.8227555 590176.976700304 5197596.09288133 590175.116546028 5197589.45295439 590160.376234443 5197574.89316135 590139.905207476 5197529.81369208 590122.754659444 5197505.08400942 590110.984178905 5197483.73427014 590099.853886948 5197470.33445032 590087.693555221 5197455.15465252 590075.353271417 5197441.95483619 590064.343021839 5197430.32499868 590052.562805392 5197419.99515188 590037.91260097 5197409.85531594 590026.242442697 5197401.96544483 590005.472367614 5197396.57558946 589993.272342065 5197394.18566682 589972.602587769 5197402.25567898 589953.18300385 5197417.61561399 589941.803344265 5197430.67553598 589928.463683839 5197443.49546892 589915.783937506 5197452.78543356 589907.204150616 5197460.81539246 589896.374337011 5197467.48537463 589879.214516341 5197473.18539417 589862.824677921 5197478.22541678 589847.684763466 5197480.20546397 589817.164845685 5197480.40559637 589803.08492372 5197482.18564083 589787.234937315 5197481.06572165 589770.215131557 5197487.4257339 589753.295409265 5197497.31571088 589680.976225268 5197524.01576544 589662.106490591 5197533.20575759 589645.596594144 5197535.82580422 589622.536800548 5197542.09584352 589587.437445058 5197565.60576507 589567.907784387 5197577.8857292 589546.078190946 5197592.77567748 589538.838425327 5197601.92561859 589527.948714554 5197613.01555644 589518.259016549 5197624.77548235 589506.189245361 5197633.19545171 589505.049383366 5197638.91540002 589499.559712858 5197652.28529151 589489.909952055 5197661.40524327 589434.07070408 5197687.46522851 589412.131036017 5197699.26520706 589400.071269417 5197707.91517373 589387.341602693 5197720.73510186 589378.831927032 5197733.61501096 589374.672070781 5197739.28497273 589369.252284741 5197747.80491165 589335.242630162 5197758.98494841 589318.732747143 5197762.26498756 589293.742897157 5197766.08505817 589265.763011661 5197768.09515976 589243.223114695 5197770.17523699 589217.07319437 5197770.89534344 589195.01324987 5197771.0054382 589175.523300135 5197771.15552139 589153.043299567 5197768.83564222 589126.173328579 5197767.32577407 589103.603473267 5197771.18583359 589067.693479392 5197767.77602371 589041.923444409 5197763.64617701 589012.183479457 5197762.09632179 588987.733498796 5197760.41644489 588960.273498246 5197757.57659272 588931.003501634 5197754.71674865 588906.01343427 5197749.26691197 588877.943450807 5197747.08705593 588858.973386897 5197742.39718553 588835.763347036 5197738.29732768 588819.913374687 5197737.84740117 588802.893332618 5197734.28751101 588784.433180284 5197725.8476762 588745.252639642 5197698.58812103 588726.862374672 5197685.29833495 588711.012161243 5197674.47851301 588702.962013683 5197667.29862042 588698.641925277 5197663.04868208 588692.011913514 5197661.84872311 588687.741978851 5197664.20871799 588688.892079148 5197668.63866835 588698.782407486 5197683.77847274 588702.562635755 5197693.97835355 588706.832796289 5197701.31826103 588712.403051732 5197712.86812048 588716.793510109 5197733.00789863 588700.933296408 5197722.18807661 588681.903104714 5197711.97826233 588667.862882262 5197700.95843452 588651.992684389 5197690.7986061 588635.402683002 5197689.00869649 588617.772658363 5197686.10880263 588604.8625519 5197680.17891876 588588.432540007 5197677.94901295 588569.392344313 5197667.52920121 588568.968985745 5197667.31239195 588557.8522352 5197661.61931126 588547.992076788 5197653.75943369 588540.762066345 5197652.54947749 588528.412025716 5197649.49956226 588507.092111163 5197650.93964085 588490.662084253 5197648.04974185 588477.872034581 5197644.55983302 588463.171917084 5197637.93996423 588450.931707928 5197627.62012214 588435.541479747 5197616.14030563 588416.051291207 5197605.93049428 588394.591106997 5197595.69069194 588376.280957076 5197587.26085754 588358.440790861 5197578.17102783 588337.000581682 5197566.83123678 588319.900429657 5197558.42139707 588298.460230781 5197547.51160183 588273.419989111 5197534.35184533 588251.399751503 5197521.68207071 588228.729586578 5197512.08226786 588209.209440476 5197503.63243956 588195.699337559 5197497.70255926 588181.739220396 5197491.10268779 588169.469069117 5197483.20282214 588127.08835378 5197447.51337199 588109.338037262 5197431.81361012 588076.167536795 5197406.40401537 588062.727332977 5197396.05418022 588040.007003099 5197379.18445262 587997.189861146 5197355.28233246 587958.036162317 5197333.42528241 587934.705835169 5197316.54555824 587900.945324469 5197290.46597456 587881.355060404 5197276.72620204 587867.284890095 5197267.69635691 587848.304604915 5197253.08659076 587828.074161195 5197231.39690275 587808.333671272 5197207.727233 587783.193123736 5197180.89761988 587766.632839135 5197166.53784091 587752.522488827 5197149.57807775 587745.732257522 5197138.66821992 587736.522042088 5197128.16836874 587730.271910456 5197121.67846324 587716.911795528 5197115.08859059 587694.711369148 5197093.81890817 587675.791005574 5197075.66917921 587662.200554507 5197054.29945952 587646.160169836 5197035.53972414 587622.279769051 5197015.13004106 587608.69953988 5197003.46022203 587589.04913941 5196983.54051516 587574.908610826 5196958.64083484 587565.00829315 5196943.50103515 587549.647782781 5196919.23135408 587540.387403603 5196901.45157881 587526.217157141 5196888.90177197 587518.816939183 5196878.42191328 587513.906830852 5196873.06199065 587475.196042997 5196833.68257137 587466.655723194 5196818.56276583 587456.105228056 5196795.47305158 587447.334793776 5196775.27329955 587426.384069539 5196740.78375027 587410.293298763 5196704.82419429 587398.562542597 5196670.03460656 587380.481562538 5196624.55515828 587366.190803783 5196589.28558758 587347.020127911 5196557.02600837 587327.929317525 5196518.81649047 587314.23855874 5196483.55691752 587296.277646554 5196440.94744036 587285.827234818 5196421.39769053 587275.336907821 5196405.57790241 587258.686522841 5196386.37817774 587240.856106155 5196365.60847489 587227.98572128 5196346.88872802 587212.455244236 5196323.72903949 587199.004821805 5196303.24931373 587185.484489313 5196286.7295474 587173.064104207 5196268.01979873 587168.223898197 5196258.24992236 587163.193747467 5196250.90002183 587144.093191878 5196223.72039212 587129.412808739 5196204.76065684 587115.322662993 5196196.39080917 587096.402530814 5196187.96098466 587068.792084367 5196164.40135765 587050.871800577 5196149.36159726 587039.241604152 5196139.05175853 587031.931475344 5196132.3318624 587023.881323642 5196124.49198137 587015.953105316 5196117.00221901 586992.580754886 5196094.9224347 586964.53051538 5196080.40271676 586951.730491577 5196077.57280607 586939.480530623 5196077.61286298 586930.930460349 5196073.30294781 586919.780208735 5196060.5631325 586897.029712456 5196035.31350178 586872.529340524 5196015.33382462 586835.68847428 5195971.57445331 586813.588136341 5195953.39474664 586794.58788868 5195939.66497915 586784.147715803 5195930.4751241 586769.397436609 5195915.9253453 586755.387185038 5195902.70554921 586744.236920685 5195889.31574148 586730.716613668 5195873.67596848 586719.726349092 5195860.28616011 586712.936126887 5195849.38630597 586703.595872443 5195836.67648281 586694.975680448 5195826.8566261 586683.425585446 5195820.94674245 586665.725424698 5195811.20692794 586622.865243747 5195796.91728017 586582.025195185 5195788.82755819 586559.945052865 5195779.24776306 586542.185001331 5195774.35789842 586526.414894799 5195767.28804722 586511.03465958 5195754.49825415 586493.82445946 5195743.00845621 586473.758613228 5195728.45415584 586473.034191215 5195727.92871298 586460.164032538 5195718.91886859 586447.243726959 5195703.29909382 586431.253494387 5195690.49930414 586414.073240761 5195676.56953205 586398.83302122 5195664.44973183 586382.20284978 5195654.27991781 586362.052757661 5195647.15008869 586339.492672947 5195639.99027143 586326.092639414 5195636.49037208 586313.182545683 5195630.35049818 586297.922356123 5195619.54068464 586239.912275238 5195607.24109084 586213.012355678 5195606.85122332 586194.702459283 5195608.79129025 586175.202527376 5195608.95138161 586160.642644191 5195612.05141839 586143.592665855 5195610.4815163 586121.672741036 5195610.60161962 586105.182824558 5195611.91168447 586012.442814525 5195597.56227868 585983.132887786 5195596.48243003 585966.072919379 5195595.35252344 585942.752828907 5195587.74271535 585919.572762354 5195581.23289501 585870.112760303 5195573.68321133 585796.232735106 5195561.37369507 585746.842854756 5195559.34395277 585712.032814533 5195552.23419481 585679.152811925 5195547.12440644 585661.367196132 5195543.78459015 585634.91243334 5195523.11487374 585607.791931338 5195496.04529199 585587.121714185 5195482.95553059 585567.161562901 5195472.97573272 585551.981493441 5195467.46586432 585533.791404237 5195460.58602501 585505.811518506 5195461.50614952 585483.161563497 5195460.07627352 585441.311455623 5195448.67659626 585432.732356882 5195443.09280206 585365.090631824 5195399.06749319 585316.56012397 5195368.16805768 585280.319737416 5195344.71848361 585239.069391127 5195322.29892302 585208.268998482 5195299.35931787 585074.126805628 5195176.82128407 584917.96486975 5195061.91328176 584889.584452391 5195037.91367918 584867.854023639 5195014.45403853 584858.823763025 5195000.87422927 584852.243456499 5194985.56442674 584836.613141685 5194968.36468898 584831.853038493 5194962.78477256 584808.762843308 5194949.88502505 584793.042671666 5194939.29521655 584780.952478743 5194928.31539452 584746.041678369 5194885.2660314 584726.721244485 5194861.83637984 584674.790426929 5194815.0071424 584657.19035791 5194808.80729629 584640.680465025 5194810.99735394 584619.990524693 5194810.26746383 584603.050358897 5194799.65766237 584503.478615705 5194701.21922258 584468.627719959 5194653.30991578 584446.957195369 5194625.00033104 584427.046745276 5194600.46069678 584404.066381612 5194579.41104001 584391.346232398 5194570.19120361 584291.034924438 5194491.15256438 584184.023492333 5194404.74404223 584162.253119124 5194383.26438593 584139.89272035 5194360.4547473 584128.562297041 5194338.46504452 584119.651874604 5194316.94532453 584108.931435569 5194294.30562596 584084.71089062 5194264.19607715 584009.419376432 5194178.89739061 583968.488572612 5194133.32809687 583928.488177406 5194107.18858604 583893.357732599 5194079.56906716 583883.694145455 5194074.67601182 583867.38755773 5194066.41934326 583846.727706804 5194052.84287567 583836.52725215 5194046.13972265 583756.755905956 5193967.18099636 583724.295297683 5193932.10154781 583711.624848325 5193908.32187421 583691.254414347 5193883.78224845 583591.823615985 5193826.60338736 583570.793274388 5193806.24371974 583557.39301044 5193791.05395607 583533.972641526 5193768.89432087 583511.022243702 5193745.42469792 583501.842204663 5193741.76478552 583489.182202116 5193739.1648793 583468.771606054 5193706.6853432 583451.931093753 5193678.88573722 583421.77064221 5193651.33619733 583390.350062707 5193617.37673521 583358.459490698 5193583.63727348 583295.798276023 5193512.85838203 583274.147510384 5193471.75895 583259.886959878 5193442.44934912 583183.265656295 5193364.20061636 583141.784560925 5193302.98151292 583130.984022225 5193274.82188234 583114.903491413 5193245.93228762 583092.602798409 5193207.91282721 583051.911650411 5193144.06375114 583022.851151542 5193113.8842399 582995.61085177 5193093.66460846 582981.090696483 5193083.09480269 582973.420440263 5193069.0949991 582963.230126083 5193051.75524605 582965.710029067 5193047.59527934 582960.259836966 5193037.15542444 582950.669525145 5193020.04566576 582942.259245083 5193004.71588108 582929.178742569 5192977.62625225 582917.718302239 5192953.87657773 582900.987842822 5192928.05695432 582878.067409964 5192902.16736469 582811.746262828 5192832.21849791 582783.935916247 5192809.34890141 582762.175780734 5192798.0191439 582742.675853992 5192797.30925566 582726.855834484 5192792.89938923 582728.165679079 5192785.63946347 582723.335472528 5192774.54961328 582716.255239147 5192761.65979524 582704.155077147 5192751.1299776 582683.535028339 5192744.22016494 582667.214852815 5192732.09038784 582641.194550911 5192711.66075561 582619.324345211 5192696.81103885 582597.054055172 5192677.75137156 582578.393786582 5192660.5216646 582522.193068794 5192612.99249891 582493.15276908 5192591.8628919 582455.592574425 5192573.92329501 582352.581983529 5192521.784435 582331.8718484 5192510.47467376 582311.941678437 5192497.62492575 582296.911384177 5192479.78520769 582281.851139437 5192464.35546273 582252.572755061 5192449.44172849 582246.710938041 5192446.455854 582218.130851991 5192435.69612955 582176.900740979 5192420.79652024 582087.280198283 5192373.47753914 582058.77999275 5192356.76788231 582023.069747915 5192336.42830578 581955.249275542 5192297.34911592 581865.088646742 5192245.18019697 581831.138468663 5192228.39057209 581808.058491843 5192224.11074617 581774.088363572 5192209.7510941 581708.067913297 5192171.80188511 581682.717725523 5192156.46219784 581648.177317825 5192127.98271051 581552.036389063 5192058.75402492 581521.216055931 5192034.73446767 581494.055645024 5192007.68492526 581462.6652673 5191981.23539948 581436.664922932 5191957.72581081 581419.114809399 5191947.7860208 581407.104511649 5191929.97629043 581400.534422889 5191923.93639561 581393.864259675 5191914.14654425 581389.124135873 5191906.79665439 581379.463924818 5191893.87685533 581371.613718802 5191881.64703847 581363.853609133 5191874.25716575 581351.133483073 5191864.82734372 581331.763370172 5191854.41756959 581310.553309983 5191846.18778071 581291.123294657 5191840.63795137 581267.453294473 5191834.79814878 581248.683201565 5191825.50835878 581234.11279107 5191818.05308999 581231.463031061 5191812.69860067 581220.142829084 5191799.75881157 581202.792409343 5191774.37919856 581189.201998844 5191750.3795491 581182.131764421 5191736.8397436 581161.351287257 5191707.6701935 581134.22107282 5191690.10054557 581094.240906154 5191671.69097873 581060.990822217 5191659.11130778 581013.660822823 5191647.23170708 580971.870897801 5191640.48201675 580927.510968046 5191632.83235118 580879.07083546 5191613.87283887 580844.730571352 5191591.79328453 580798.870197524 5191561.18389313 580753.92957731 5191518.24463966 580717.929110997 5191485.33522101 580701.898740805 5191462.40557576 580688.208481239 5191445.6858457 580679.778474079 5191443.14592222 580664.348773884 5191454.40587812 580653.504886832 5191448.80186727 580648.578693681 5191446.25606061 580633.148334579 5191423.99640466 580622.667795934 5191393.8668123 580612.717354449 5191368.80715835 580595.957193304 5191356.23739794 580566.72717941 5191347.9076584 580551.667152948 5191342.6278041 580532.436852851 5191322.29814781 580509.106581813 5191302.35851017 580485.446584917 5191296.30871331 580443.066407771 5191276.11918598 580403.986033909 5191246.6997477 580350.455650314 5191212.90044224 580282.635433514 5191183.77116369 580205.8351252 5191147.45202046 580143.014865834 5191117.28272746 580078.424565554 5191084.44347641 580048.064015281 5191047.87407583 580029.533560725 5191019.40451381 580004.983328769 5191000.76487116 579967.953262509 5190987.26523939 579923.323081154 5190965.71574531 579868.462645619 5190928.15649751 579835.761993633 5190885.38718536 579816.671490524 5190854.03766205 579793.510983096 5190821.3081784 579752.440480473 5190783.48145969 579746.140396182 5190777.67896152 579676.829948938 5190735.07985899 579630.659385306 5190692.7906212 579564.698451875 5190625.53179203 579531.737954913 5190590.25239741 579510.39743232 5190556.89291362 579492.626984608 5190528.4333517 579465.656543213 5190497.64387059 579439.936264655 5190475.69427822 579407.555802436 5190442.1848611 579362.204921486 5190382.92582383 579339.744278964 5190342.71642941 579321.303922697 5190318.65682098 579295.373732555 5190301.10717924 579263.973593102 5190284.59755719 579237.083257912 5190259.09801555 579207.19268387 5190220.11865133 579181.76199461 5190176.3393184 579152.311654602 5190149.70980606 579110.751401464 5190124.02035368 579063.201085565 5190093.18099791 579044.428208018 5190081.66904062 579019.090823164 5190066.13157752 578966.180426366 5190029.27232584 578922.870091355 5189998.49294618 578888.639691135 5189966.94352281 578862.559068552 5189926.0241635 578838.52873908 5189901.23460032 578815.538645213 5189889.24487867 578789.168433249 5189869.93526434 578763.268194193 5189849.30566317 578744.388260847 5189847.06580132 578739.028178565 5189841.0459048 578730.088028998 5189830.34608527 578722.417797773 5189815.68630555 578714.157532672 5189799.03655312 578703.397418341 5189789.63672896 578684.507498179 5189788.06685941 578669.177653521 5189791.61690765 578656.517661476 5189788.13702409 578638.957564492 5189777.5472545 578621.567441753 5189765.62749988 578599.897194325 5189745.71786623 578574.547025596 5189728.84821818 578547.887013065 5189719.89848327 578514.616975632 5189707.54882835 578480.017123221 5189704.66906801 578451.617018215 5189690.18940999 578426.157008175 5189681.69966285 578404.137254432 5189688.0197177 578390.75721403 5189681.66987328 578363.196990006 5189661.02028473 578327.946982147 5189649.54063194 578299.937171879 5189650.94078151 578278.577344653 5189653.52087737 578266.007222363 5189642.99107864 578252.697079807 5189631.13130036 578236.427081023 5189626.07145793 578210.387042809 5189615.80173633 578202.66688166 5189604.68191607 578190.586708135 5189591.51214648 578172.586592704 5189579.59239713 578148.41646721 5189565.16271486 578125.736166164 5189541.71313253 578105.806005074 5189526.67343263 578095.466141187 5189530.73344535 578078.346282794 5189532.93352092 578044.546143635 5189514.63394327 578024.105863996 5189492.97432665 578006.305463845 5189465.61476322 577980.784908734 5189427.3553778 577969.58454528 5189404.05572625 577956.004146988 5189378.08612131 577946.473985791 5189366.26632124 577928.184078295 5189365.36644178 577905.774027909 5189355.37669693 577875.223760487 5189330.94717567 577852.283608033 5189315.20750383 577823.443279063 5189287.92800728 577813.893143505 5189277.43819169 577794.103006342 5189263.5084794 577775.96288833 5189251.14873826 577752.612670999 5189231.65911498 577737.782344154 5189208.9794792 577720.962045222 5189187.14984524 577697.601857313 5189169.20020383 577674.55185403 5189161.41043743 577643.621920768 5189154.83070399 577613.981867357 5189142.10103753 577600.976878164 5189133.86534911 577554.261538406 5189104.28185795 577525.361292531 5189081.19231351 577506.271013892 5189059.55269228 577487.170755922 5189039.02305776 577467.220639836 5189025.97333749 577445.970652165 5189019.52354485 577439.016374108 5189014.65756724 577416.430456434 5188998.85397575 577388.810326058 5188982.39434393 577346.119976504 5188948.76501319 577331.049773146 5188932.47530347 577324.259372818 5188908.13564167 577317.289001535 5188885.32596236 577306.058691942 5188864.45628539 577292.998421472 5188845.10660111 577277.037984339 5188815.56705901 577256.837573067 5188785.97754359 577235.217266854 5188761.66797259 577231.376946104 5188742.64822839 577223.136663936 5188724.23850369 577194.026727023 5188717.68876193 577171.666606075 5188703.28907487 577143.046180313 5188669.84965918 577122.645849081 5188644.45009502 577118.845473407 5188622.34038885 577112.545013641 5188594.70076574 577100.804574992 5188566.32118521 577082.344269207 5188542.93158509 577060.873958322 5188518.18202034 577039.153780593 5188500.70236827 577017.503733784 5188490.49262684 576997.663457883 5188468.19302251 576976.863053085 5188438.37351648 576958.882921322 5188424.6937953 576941.412707191 5188406.60412517 576925.372389443 5188383.24451097 576907.621924083 5188351.04501599 576887.501422347 5188315.94557151 576869.330921085 5188281.53610671 576850.410409065 5188246.22665786 576832.109885924 5188210.48721068 576808.439286293 5188168.50787388 576793.04890039 5188141.40830288 576769.77857616 5188114.86877432 576744.998475145 5188100.21910916 576718.308520516 5188093.03936414 576697.738433013 5188080.64964511 576674.428173853 5188057.64007408 576638.34786194 5188026.97067752 576595.637561303 5187994.44134583 576556.527286507 5187964.62195867 576523.347143508 5187944.34241699 576484.18693344 5187918.04298745 576452.246733115 5187894.92347366 576418.75640237 5187863.84406828 576390.546038795 5187832.8346292 576380.555688208 5187809.33498276 576375.655168337 5187778.18539894 576365.674810111 5187754.23575815 576353.144640668 5187739.96601379 576327.394423762 5187718.02644793 576309.174412461 5187710.51665601 576271.234189423 5187683.5772295 576240.402110655 5187656.93773156 576233.124068803 5187657.72787386 576225.834239865 5187660.05797394 576214.87431734 5187653.30825299 576198.634460779 5187644.93864603 576184.04461 5187638.5789846 576162.99478831 5187627.28949963 576146.354664754 5187603.26009628 576127.614756088 5187589.35060327 576106.594903317 5187576.30113996 576087.80507291 5187566.80159257 576062.475388892 5187558.98214016 576025.475953312 5187553.43286636 575998.106405775 5187551.32337852 575975.586768737 5187549.05380663 575954.31706723 5187544.37424284 575939.887183307 5187536.25460088 575929.737169917 5187525.10492104 575914.148521236 5187515.43169817 575912.317292537 5187514.29536597 575885.76744941 5187496.0960658 575861.527708176 5187486.08662179 575835.570282122 5187479.34088602 575831.208113 5187478.20725898 575808.84826181 5187463.81783671 575806.938006683 5187447.24807886 575805.357915364 5187440.398193 575803.077763077 5187429.33837247 575797.297703652 5187420.00859235 575791.927682993 5187413.31877177 575778.117784823 5187404.98912166 575762.437985094 5187400.379458 575738.178271836 5187391.91999511 575718.848555843 5187388.36038309 575706.768734994 5187386.23062436 575689.089024546 5187384.68095779 575658.259512094 5187380.98155176 575644.209726034 5187378.8218284 575618.250104463 5187373.86235177 575601.190352471 5187370.56269623 575581.200725273 5187371.4130405 575568.94094971 5187371.69325468 575548.361309906 5187371.21362617 575525.871638659 5187366.96407902 575486.642179172 5187357.65489286 575454.592496697 5187342.91564761 575445.582567783 5187337.72587297 575423.26285158 5187331.05635336 575400.373114675 5187322.60686632 575379.913304209 5187312.42735793 575363.673449834 5187304.0677517 575351.613609611 5187300.82800672 575337.753766715 5187295.57831905 575305.894027984 5187277.75910953 575294.484111203 5187270.77940017 575278.924141491 5187256.46985694 575264.544193081 5187244.60026201 575247.944219052 5187228.96075407 575232.384245731 5187214.43121369 575219.184318711 5187205.00156711 575211.97438135 5187201.16174364 575193.004376827 5187181.30233112 575179.86436086 5187166.80274745 575169.694380349 5187157.41304659 575163.294344543 5187148.73326979 575153.684407833 5187142.4435199 575138.614587 5187137.18385408 575123.334857743 5187136.98412819 575096.555336425 5187136.87460556 575070.565739892 5187133.2451133 575037.186251402 5187128.19577032 575001.006709423 5187117.15655273 574970.657155948 5187111.48716378 574943.557441657 5187099.89779182 574904.487756607 5187077.57876819 574888.307822264 5187064.58921988 574856.727897893 5187036.19014004 574844.997800766 5187018.40057331 574831.507654882 5186995.96109664 574820.837527609 5186977.52151932 574811.487438081 5186962.63187371 574799.147355995 5186945.06231515 574790.837282459 5186932.17262581 574786.057271899 5186926.59278133 574777.657321941 5186920.75300454 574766.21744136 5186915.7632711 574751.767587608 5186909.19361117 574728.857876346 5186902.06410885 574690.288321683 5186887.69497666 574663.758652189 5186879.205556 574639.70885492 5186865.89615218 574627.71890812 5186856.48648449 574599.569001107 5186832.53728825 574572.749105064 5186810.59804301 574546.379212499 5186789.31878148 574508.799314281 5186755.99987188 574479.069310937 5186724.76079637 574461.329265485 5186703.59138008 574449.419203712 5186687.56179498 574434.629200966 5186671.942256 574423.229255771 5186663.20256961 574409.409361287 5186654.87292114 574395.229347899 5186639.26337124 574383.249390361 5186629.19371206 574366.329646117 5186626.33404961 574356.119721672 5186620.03431121 574344.139752869 5186609.30466043 574331.169710523 5186593.26509453 574320.509570112 5186573.94552904 574310.609420016 5186554.85594712 574302.489280041 5186538.21630248 574290.109257948 5186523.95670362 574277.619173183 5186505.93715436 574257.768923824 5186470.62795526 574256.088764186 5186459.58812502 574240.768665721 5186437.78867416 574232.718430034 5186415.63909819 574227.588301466 5186402.77935251 574223.684064193 5186395.95814203 574222.248237434 5186393.44956588 574219.528073623 5186381.06977117 574213.0080005 5186369.970028 574205.397988375 5186361.27027388 574195.19804165 5186353.65055226 574190.40805513 5186349.4006915 574179.048064586 5186338.01103835 574169.408172286 5186334.14125926 574163.408196148 5186329.22142858 574157.058097245 5186316.79169929 574153.767894392 5186301.5319513 574153.857756445 5186293.60205016 574151.067688796 5186286.73218696 574149.907644965 5186282.96225541 574144.607531272 5186270.77250437 574138.617551084 5186265.62267646 574127.987581958 5186256.23298504 574118.487497906 5186241.34334316 574110.377347342 5186224.04370704 574105.847197163 5186210.53395904 574098.957013427 5186192.58430942 574092.09679139 5186172.43468715 574081.416675663 5186154.44510569 574083.456533079 5186148.29514722 574068.116470541 5186128.48567201 574053.696569537 5186119.04604899 574030.336646766 5186098.90672117 574017.336644795 5186085.0771285 574007.776649399 5186075.25742362 573992.766736471 5186064.48782808 573975.906909633 5186056.77822679 573958.987178643 5186054.5885566 573929.17770868 5186053.99909622 573912.917878793 5186046.73947856 573900.307957246 5186037.98981465 573884.858041081 5186026.55023558 573867.528045388 5186008.48077421 573860.607897058 5185992.51110036 573855.88780401 5185982.09131682 573848.427578628 5185961.05171695 573845.65748094 5185952.4218759 573840.337398661 5185941.99210323 573832.127398473 5185933.29236023 573820.147431741 5185922.55271045 573786.547618673 5185897.88362363 573762.367914731 5185878.61168353 573762.107728511 5185878.40430741 573733.297905499 5185858.20507846 573718.858039897 5185850.74543113 573703.808189165 5185843.50579192 573692.608182484 5185831.2361478 573685.428194412 5185824.31636394 573660.758422137 5185811.44696815 573628.128920935 5185805.96762079 573592.949439425 5185798.92833884 573543.569963968 5185777.14949795 573501.390442618 5185760.32046563 573462.590996195 5185751.46127168 573439.081290502 5185743.68179077 573403.541672717 5185728.2426223 573377.901794639 5185708.08333696 573358.171803147 5185687.56395061 573344.311548117 5185657.84457637 573339.551509464 5185650.50475482 573333.161466353 5185641.16498787 573326.581479419 5185634.91518501 573318.771533291 5185629.74539042 573309.131642629 5185625.87561202 573284.772058087 5185624.25606823 573250.312617559 5185620.30673469 573228.37300829 5185619.81713326 573215.023289799 5185622.08734309 573185.563951017 5185629.44777621 573161.744458162 5185633.78814689 573141.714885788 5185637.50845768 573117.965297806 5185636.33889724 573096.815625442 5185632.98931808 573081.76577971 5185625.9696766 573067.9358897 5185617.65002987 573051.056095696 5185611.71040739 573035.98627288 5185606.01074949 573022.716444046 5185601.88103941 573002.656711044 5185596.12147153 572985.386830585 5185584.67192629 572963.756998424 5185571.39248236 572943.377080221 5185554.38306366 572924.327179547 5185539.82358999 572911.707271822 5185531.73391885 572901.207333351 5185524.10420395 572880.55757392 5185516.13467496 572867.937677509 5185508.70499545 572847.487858503 5185497.435505 572829.298017428 5185487.28595987 572818.508054542 5185477.89627266 572801.708151257 5185465.5667305 572790.338157615 5185453.73708484 572780.778161579 5185443.70738383 572772.43811722 5185432.13768065 572764.177963032 5185414.17805757 572758.287840847 5185400.64833557 572754.777739596 5185390.90852264 572750.067626138 5185379.15875683 572744.217451047 5185362.54907342 572738.287389721 5185352.55930701 572733.147254315 5185339.04957137 572725.527051387 5185318.88996497 572720.17700194 5185310.22017136 572713.006996727 5185302.20040205 572705.207043887 5185296.59061328 572699.197088756 5185292.77076963 572690.017179593 5185288.25099167 572674.987297333 5185279.02137857 572664.197346232 5185270.29168318 572650.427374128 5185257.11209795 572635.39749963 5185248.33247916 572621.546562286 5185228.35492222 572613.967367093 5185217.42325747 572608.627317879 5185208.76346365 572603.297249695 5185198.99368382 572597.947200692 5185190.33389019 572592.607151353 5185181.66409651 572584.827157427 5185173.63433838 572572.277163765 5185160.47473119 572555.477250493 5185147.47519813 572542.317260473 5185133.86560767 572526.587313234 5185120.00606647 572516.427310152 5185108.85639088 572505.687287752 5185095.93674831 572494.997189865 5185078.60716117 572483.936986799 5185054.65766523 572476.846857566 5185039.3579877 572470.436630338 5185018.9983626 572458.606452552 5184995.69887223 572447.936321116 5184976.38931013 572440.136361488 5184970.33952724 572430.476502698 5184968.23972725 572418.986688215 5184966.7799519 572403.116945418 5184964.82026146 572389.187197395 5184964.65051338 572372.887436452 5184961.15085034 572342.467763219 5184947.55156953 572323.748027372 5184942.91196447 572296.988251046 5184927.1626456 572282.308304408 5184914.41307181 572267.018380139 5184902.32350055 572252.92843413 5184890.24390767 572237.618324172 5184867.12447783 572219.168208048 5184840.2251527 572207.458062935 5184818.91563524 572190.327986332 5184795.77623844 572178.657792256 5184771.59675703 572169.267545851 5184746.78724279 572164.327348991 5184729.74754935 572154.397015803 5184699.19811825 572137.876928713 5184676.06871057 572122.586986774 5184662.87915372 572102.457140098 5184650.06967892 572085.437329816 5184642.80007745 572067.147412785 5184627.81059757 572047.547445249 5184608.39119792 572025.507540646 5184590.04182844 571995.677878035 5184577.56252377 571969.448205679 5184568.42311176 571945.658459481 5184557.5536781 571921.858724659 5184547.34423621 571899.369047788 5184542.00470847 571856.839805398 5184540.61549006 571838.610017755 5184533.33591069 571813.510214286 5184517.60656298 571801.360275586 5184507.97690457 571785.430190751 5184485.51747845 571768.900105802 5184462.38807174 571759.609937469 5184442.2084972 571750.369675713 5184416.51899238 571739.829370916 5184386.83956208 571727.449125759 5184358.69014527 571716.348757412 5184324.60078161 571711.858339244 5184294.78124444 571702.387774686 5184250.78197852 571698.007326965 5184223.70793833 571692.236908138 5184188.04296499 571678.616515879 5184149.73370086 571671.196232769 5184124.72415482 571653.976058211 5184095.4148402 571644.785951899 5184078.9852161 571633.665821655 5184059.00567224 571627.515648978 5184041.95600142 571624.32529639 5184017.43637308 571618.724969507 5183991.79680247 571600.834696716 5183955.85758511 571590.314566998 5183936.54802198 571576.844376597 5183910.36860005 571562.614218627 5183885.27917787 571549.824119512 5183865.27966455 571528.394200569 5183846.50029121 571510.874258443 5183830.64081007 571488.834350841 5183811.85144794 571460.724580372 5183794.54217623 571438.744804931 5183783.6927113 571418.71503086 5183775.07318267 571398.545233649 5183764.91367635 571374.075382273 5183746.76435002 571351.605678971 5183739.66484594 571326.02591813 5183725.68548619 571294.916159008 5183705.68630341 571271.656297158 5183688.21694678 571247.816405377 5183668.30763197 571225.166521477 5183650.17827293 571204.37654095 5183628.31892831 571187.376704931 5183619.29935054 571158.087127232 5183612.1199707 571132.577487631 5183605.42051659 571110.027889609 5183604.49093501 571096.658200753 5183608.30112706 571077.838611777 5183612.05141812 571066.860652575 5183613.62728872 571065.088878364 5183613.88162442 571045.059311418 5183617.61193752 571026.329599271 5183614.08232049 571007.929833334 5183607.69273429 570992.639892787 5183594.28318229 570968.310070027 5183577.89383158 570945.090146329 5183556.67452303 570926.720122775 5183534.84513493 570909.489964588 5183506.19581403 570898.469905883 5183490.41621569 570884.259714622 5183463.12682293 570871.929610055 5183443.12730254 570859.719540318 5183425.34775146 570846.919679593 5183419.45805811 570836.619872268 5183419.55824262 570823.870150332 5183422.05844045 570813.530395015 5183425.23858606 570801.42062091 5183425.31880348 570783.120919982 5183422.89916471 570764.2611817 5183417.609573 570747.221395223 5183411.44995965 570725.851603927 5183400.17049034 570690.411847401 5183375.2814501 570663.581951345 5183351.59223917 570649.991933264 5183335.33269375 570633.58189381 5183314.63325641 570616.351942797 5183298.33377725 570588.892099255 5183277.06454677 570566.412398741 5183269.96504396 570546.832623008 5183261.57550544 570520.002940305 5183250.67613015 570490.723123479 5183228.94693868 570476.09310321 5183211.34742958 570470.502975612 5183197.39771027 570463.012791271 5183177.89809679 570450.762775238 5183163.20850729 570436.862986975 5183160.39879449 570420.363293979 5183160.41909218 570403.433561554 5183157.57943449 570392.343604713 5183147.74976147 570381.293581186 5183133.94013905 570372.193558583 5183122.37045255 570363.553516521 5183110.14076626 570356.72345227 5183098.6010384 570353.033381187 5183090.17121374 570351.123120402 5183072.29147877 570344.392915325 5183052.3618573 570329.633077584 5183045.58221136 570320.673286362 5183048.12234047 570317.483348693 5183048.30239578 570306.073631865 5183052.5825467 570291.53391412 5183053.29280021 570269.584314517 5183052.81320292 570248.914589126 5183046.17366197 570234.244833749 5183044.46394904 570216.075164516 5183044.02428297 570199.585453605 5183042.95459467 570171.705985217 5183043.73508826 570156.456211215 5183040.2454088 570133.966519518 5183033.58590106 570114.436664 5183020.34642481 570100.956704569 5183007.62683256 570088.6667523 5182996.67719599 570075.836711623 5182979.76764614 570063.006678291 5182963.29809065 570051.936692886 5182951.70844035 570046.406474163 5182932.2387917 570043.22631414 5182918.96902053 570037.686124739 5182901.25934935 570029.036094905 5182889.69965498 570011.416284919 5182881.33008158 569989.51660509 5182876.01054617 569971.256854339 5182870.50094743 569939.027419555 5182868.36155772 569912.227910176 5182867.83204905 569892.238285956 5182868.03240783 569869.6786984 5182867.55282187 569847.729092229 5182866.63323056 569827.04937914 5182860.66368159 569804.609618452 5182849.81422754 569779.479856731 5182835.85486237 569774.559838523 5182829.18503757 569764.859821277 5182817.16536839 569755.579832649 5182807.35566304 569742.139822776 5182791.54611053 569735.459749831 5182779.55638639 569726.179561524 5182757.61683796 569716.389662433 5182752.65707917 569693.829857317 5182738.93766465 569677.890002877 5182729.71807223 569658.340171398 5182717.79858005 569637.040278193 5182700.13919382 569613.770413978 5182681.9998495 569593.040564829 5182667.65041023 569570.490745804 5182653.06100704 569550.370874612 5182638.05156535 569530.66085104 5182614.23223034 569515.300790584 5182593.10278183 569506.574549822 5182570.92934209 569505.450563208 5182568.07328413 569496.190324888 5182543.04377578 569483.800086812 5182514.46437006 569470.38003798 5182496.22484917 569455.590036359 5182479.29533614 569443.369976415 5182461.73578477 569432.33109862 5182443.61244232 569426.729838928 5182434.41643985 569418.059619319 5182411.16689793 569425.899303846 5182400.88688907 569425.239174971 5182392.28701238 569425.178835684 5182371.5572819 569420.788696159 5182358.05753622 569413.338446781 5182334.37797781 569408.898170493 5182312.4883417 569398.477893109 5182283.70890316 569389.037499794 5182248.97952395 569374.22707952 5182206.47034284 569358.22686966 5182175.41103508 569355.026748154 5182164.35123632 569337.386753503 5182144.52181292 569314.727090957 5182139.19229277 569300.837283674 5182135.06259808 569278.337618193 5182129.73307506 569238.517916471 5182102.37415154 569227.607912969 5182089.67451393 569210.987946997 5182072.72503497 569194.537949091 5182054.01557576 569177.327983405 5182036.39611626 569162.577910712 5182015.05666038 569151.587807978 5181996.18710433 569145.247470781 5181968.32758047 569142.757177753 5181947.57789462 569143.14683113 5181926.85815611 569144.856517674 5181909.67834777 569148.37618133 5181893.17849775 569151.335804888 5181873.58869793 569156.595335077 5181850.93889601 569163.734739796 5181822.78913121 569178.053711115 5181776.42947198 569185.732982948 5181740.79979417 569193.362331326 5181709.79005736 569197.411873017 5181686.4702859 569203.351292579 5181657.87054849 569208.710889164 5181639.41069024 569212.82034998 5181611.23098056 569220.369598451 5181574.05132492 569226.309006979 5181544.79159591 569236.498332537 5181515.36179181 569260.446996192 5181461.39205525 569267.566642848 5181448.03209877 569276.616097779 5181425.20222977 569285.485599333 5181405.01232983 569296.295093732 5181386.62237129 569305.314592333 5181366.43246856 569312.504136087 5181346.89259067 569320.913656922 5181327.36269043 569328.003140948 5181304.07286282 569338.67240601 5181271.56308934 569347.661955572 5181254.463147 569363.331126925 5181222.01328165 569380.030329522 5181192.66335738 569382.568093636 5181152.94309365 569371.969329998 5181122.48191173 569359.216991597 5180965.2966766 569356.466493937 5180931.79715987 569400.714079377 5180835.79759475 569406.088560822 5180810.42282477 569470.210304718 5180686.2670101 569494.709058415 5180638.73592729 569517.958036324 5180603.42345928 569528.45725426 5180567.98622535 569551.956060471 5180522.54888325 569565.080144887 5180482.04916657 569632.701739862 5180353.29959366 569635.451395395 5180335.54977244 569643.076210057 5180333.11216466 569656.200418968 5180300.23734905 569788.693776375 5180050.3631495 569791.44343132 5180032.61332794 569866.564916472 5179906.48857881 569890.063717623 5179861.051234 569923.687200949 5179808.11380027 569952.435481921 5179737.30168549 570019.932231169 5179618.73947505 570020.057060485 5179608.5521038 570048.555680866 5179558.11473047 570100.428142559 5179464.73998058 570152.175857315 5179386.6150362 570165.05024202 5179364.36508607 570372.665308705 5179005.67838195 570398.414229224 5178970.49086053 570497.034354773 5178791.30384626 570507.408819459 5178771.11641432 570517.658412031 5178758.49138775 570530.657616301 5178725.67906924 570556.406575207 5178692.92901552 570572.030685854 5178657.55418139 570721.773641377 5178407.99212157 570752.772371449 5178367.74206594 570752.897157919 5178355.05472589 570794.270602216 5178309.74204377 570804.76993574 5178281.92970606 570828.143853053 5178244.11725905 570838.393529426 5178236.61716619 570843.643132023 5178218.86729637 570895.640990572 5178150.86720761 570906.140448343 5178130.55477369 570969.012585702 5178032.05487325 570982.761850645 5178003.99247814 571001.386233398 5177988.67983036 571074.382815125 5177868.86751359 571084.757445356 5177858.80495065 571105.881316483 5177815.80510957 571118.630746215 5177795.55510817 571135.317716381 5177769.52353058 571155.067089262 5177738.67939336 571178.3788501 5177702.36643709 571191.25342064 5177679.61618372 571204.252969058 5177654.36592674 571217.127621113 5177641.86568032 571245.626690569 5177593.92762302 571279.125724919 5177553.67697916 571351.748326282 5177427.55056576 571545.617370039 5177145.35936018 571579.116389857 5177102.54622782 571586.991079517 5177082.29607466 571607.74044401 5177052.10818228 571625.864878269 5177024.3578394 571649.114175186 5176991.60740149 571664.738618166 5176958.79460298 571692.987839876 5176928.60657654 571703.487440808 5176903.35637533 571747.361166652 5176847.98055676 571827.483687211 5176726.97906069 571866.107595415 5176681.72834714 571899.856518111 5176626.29021987 572000.478538353 5176490.2883681 572054.851855255 5176407.09987031 572095.975720517 5176361.84912263 572121.974892958 5176318.97364763 572225.096878772 5176183.03427991 572225.346775964 5176170.34677318 572238.096495436 5176165.40904531 572253.471029412 5176142.90876785 572269.095516803 5176114.9709854 572547.712485134 5175757.5910215 572760.893965755 5175497.02478568 572844.079123081 5175395.33584209 572849.453886825 5175377.5857502 572872.453320513 5175360.08535156 572898.327526985 5175319.77240606 572988.574969836 5175206.52085537 573545.934649102 5174557.76147007 573591.308408477 5174504.94822102 573761.428742256 5174303.75793427 574338.787798271 5173591.748739 574377.661762125 5173548.09188038 574390.286425936 5173533.93543306 574408.161060683 5173529.06014185 574413.285929702 5173524.06006126 574458.785242578 5173544.93429316 574497.159353301 5173519.99618045 574573.657783353 5173498.05743741 574797.278606743 5173490.55375758 574861.027290862 5173470.99022665 574950.025585292 5173461.86377021 574960.6500804 5173418.801141 574966.149742699 5173385.8635856 575005.648162765 5173266.92556518 575106.895002345 5173085.23661197 575180.017919609 5172981.36054137 575194.954994324 5172960.11032358 574893.083955377 5172742.02169226 574523.842045287 5172926.37124191 574431.78157212 5172973.06019764 574381.095188705 5172998.74850092 573839.10716416 5173273.56966953 573150.312561799 5173965.33082721 572757.510447767 5174371.68114196 572589.577408777 5174545.46524465 571865.534280649 5175294.60286016 571450.482921095 5175715.64156857 571150.678513564 5176019.77205896 571044.493889161 5176127.52402428 570945.121584151 5176228.30712328 569545.035437276 5177701.17800856 568850.236130719 5177670.9721113 568728.05098341 5177669.56812704 568116.875348472 5177673.73573361 568078.938388472 5177651.08013966 567961.378124028 5177646.45731162 567681.883438769 5177635.49372379 567475.88721203 5177610.9349869 567415.200550961 5177572.46726768 567333.139183745 5177520.43740788 566815.896282877 5177192.38357472 566323.65295412 5176877.8916627 565860.034179866 5176581.71164289 565488.224218152 5176079.77913727 565481.161765349 5176070.21673024 565453.411951475 5176032.74834523 565453.532749863 5175573.30925204 565453.655343666 5175310.37083667 565617.586827656 5174989.86688538 565431.585416794 5174453.1807221 565350.834790518 5174220.15001986 565246.771769923 5173952.30706415 565213.397238207 5173935.71381454 565064.274326279 5173861.40354321 564699.719173033 5173922.59738972 564566.534359829 5173944.97471402 563637.055802585 5174379.61723962 563363.247225477 5174254.4650846 563279.623352728 5174209.15379638 563105.250305583 5174073.93737222 563072.250867288 5174068.37540315 562974.752526144 5174051.90822064 562754.256276048 5174014.7242604 561973.771623433 5174095.5503325 561791.836067404 5173949.20888339 561777.273175625 5173882.36502476 561770.085367599 5173837.83365963 561659.957984095 5173392.17686987 561456.271602598 5173126.64754164 561350.647173711 5172988.96101705 561168.336898399 5172875.96336649 561122.274951155 5172846.62020246 561115.025082706 5172846.43281955 561069.525647811 5172819.40215804 561031.526119196 5172796.8088985 561001.213949163 5172774.24676329 560948.151970812 5172729.27861894 560796.715775128 5172583.28023213 560721.965447171 5172415.81171328 560764.897430781 5171949.49580538 561279.573152618 5171710.23630282 561498.193996626 5171691.76400878 561983.684774784 5171650.75615382 562458.0508877 5171622.31105753 562848.352779966 5171259.02192256 562859.539976858 5171248.61544857 562968.473798092 5171071.95666214 563003.593971717 5170638.89154875 562892.280327427 5170315.45417486 562605.344449561 5169956.862956 562521.533105642 5169922.6452817 562132.663885022 5169807.49421506 561900.478973164 5169652.65307941 561826.354795942 5169603.18515649 561760.418026613 5169559.18588925 561511.731892284 5169255.37536316 561503.544436728 5169245.37542689 561232.357556692 5168831.43952103 560884.234916915 5168461.19234912 560779.54675206 5168215.66112953 560843.231538989 5168057.81555244 561038.535743858 5167573.71625541 561087.032326471 5167318.58910831 561035.28141488 5167140.27627399 560868.532687849 5166982.99635267 560671.471626746 5166792.09160942 560268.163713109 5166565.78310088 559962.168798069 5166551.63082396 559945.856671366 5166560.75609864 559415.806337168 5166857.39010275 559202.310174281 5166873.86182968 559032.875720978 5166886.95794503 558492.756506145 5166559.43164058 558332.508941898 5166530.87106572 557965.577012159 5166465.43795764 557486.715217369 5166927.60404274 557309.346432995 5167097.17042 557218.850875963 5167183.67258413 557188.102386366 5167213.04831805 557035.047413113 5167359.39571248 557005.673859732 5167387.55266058 556951.989002865 5167438.83518359 556876.680213447 5167510.80571625 556710.56030707 5167383.80753859 556641.187430972 5167330.77705381 556165.510935237 5166648.46758678 555813.836652007 5166611.84826032 555643.345838285 5166843.66525374 555579.975893963 5167076.44918541 555516.231468122 5167353.67092001 555201.307696538 5167484.14578984 555092.187006035 5167489.24138159 554803.260918577 5167502.74625542 554761.950429776 5167538.02842401 554743.638821366 5167553.65383076 554610.457814958 5167667.68803543 554539.088767291 5167944.8785355 554537.714104559 5167969.69122118 554528.216463055 5168143.56751933 554514.594828928 5168391.3818683 554511.658053458 5168444.69476578 554450.598149601 5168462.25837087 554254.481493866 5168518.82441583 554212.483281361 5168530.91892377 554145.733204339 5168296.94974861 554139.232048814 5168174.63656741 554148.541998444 5167985.04144484 553470.693821533 5168011.80270507 553439.712858505 5169533.81262435 553427.732396188 5171162.82285219 553403.752034889 5172759.83301632 553383.771651848 5174368.84314128 553355.791643031 5175981.85334717 553351.810650603 5177595.86318564 553330.828407997 5179198.84213875 551741.892997035 5179287.86144805 550123.957608117 5179265.88261581 548516.021850388 5179243.90363668 546914.085935204 5179232.92441706 545321.149602686 5179201.94532802 543650.216504964 5179203.96679193 542032.28124317 5179264.98679513 540430.345259956 5179248.00759231 538756.412126805 5179248.02907838 537221.431611674 5179254.05218577 535605.424529336 5179255.07890249 533990.417465329 5179274.10537635 532381.410489906 5179317.13142772 530787.403635033 5179294.15814945 529189.396799056 5179301.18453868 527600.390098711 5179330.21047239 526019.384250467 5179566.23320789 524404.377615024 5179556.26010977 522796.370766589 5179501.28761151 521175.36375734 5179442.31544096 519525.325264365 5179380.28135453 519394.355935139 5179375.34611238 517916.328271882 5179332.36865748 516306.291369745 5179249.39311185 514626.252972295 5179185.41839672 513009.216520757 5179180.44179076 511387.180069969 5179185.46510066 509763.143811634 5179209.48807252 508151.107766549 5179225.51104065 506539.070830495 5179170.5356119 504914.034421812 5179180.55899068 503301.998167785 5179179.5824689 501695.962547851 5179211.60507996 500088.927078579 5179251.62748838 498462.889373269 5179247.62316423 496848.851735509 5179237.6171233 495302.815676504 5179229.61132198 495346.84729782 5180821.57463446 495340.878395801 5182446.53695695 495368.909626316 5184043.49993398 495375.93995181 5185617.46334803 495394.971242756 5187232.42574426 495420.002151849 5188825.38856517 495446.03275704 5190405.35159924 495503.064321413 5192017.3136871 495524.095615327 5193646.27538485 495564.126526155 5195247.23755609 495560.156779411 5196842.20002694 495603.188010644 5198467.16141745 495611.218295986 5200062.12367648 495637.248778541 5201663.08557362 495650.279726696 5203296.04675013 495676.309926805 5204889.00866588 495711.353257682 5206502.98535492 495747.398906727 5208109.96516074 495763.443521209 5209683.94554618 495759.488657558 5211278.92586094 495757.534996631 5212916.90557524 495769.579718949 5214497.88577718 495749.624731671 5216090.86619041 495735.659231801 5217311.85113751 494959.659115045 5217313.86122848 494970.705119564 5218929.84108862 494995.750458042 5220523.8209809 495003.795943673 5222123.80097645 495029.841657324 5223733.78054491 495057.886755016 5225323.76027618 495042.932737237 5226942.74021409 495039.977911121 5228534.72027518 495038.023517812 5230142.7000773 495024.069605433 5231766.67981888 495019.115198974 5233362.65844546 495028.162292141 5234979.63287876 495020.209257124 5236590.60763539 495020.25677792 5238222.58188682 495069.303271475 5239826.55568717 495109.350249214 5241446.52931016 495126.397469637 5243072.50317726 495135.444059105 5244676.47748387 495131.495656431 5246452.01174692 494969.496243897 5246452.45230827 494795.543352658 5248054.43014654 494770.589645386 5249647.40528159 494775.636449952 5251262.3794381 494778.681964043 5252833.35429019 494796.728248945 5254433.32831968 494809.774558379 5256034.30238152 494927.819864232 5257612.27448102 494951.864575155 5259160.24900567 495092.910126374 5260757.22018159 495122.945638598 5262364.19987764 495170.980399668 5263944.17941097 495203.018507466 5265676.15736808 495207.054052006 5267287.13741823 495199.089378382 5268885.11787935 495275.123248513 5270449.09659807 495273.160182488 5272126.07581067 495167.197052713 5273752.05834863 495209.110948557 5275537.03499854 495210.271082612 5277133.01502885 495241.46229853 5278739.99404238 495300.561408565 5280442.97098496 495352.374997453 5281951.95047877 495408.40961765 5283572.92834458 495395.446087868 5285230.90769069 493836.441274287 5285240.57888839 493825.510468566 5286899.93388971 493824.545357675 5288432.91510224 493806.596553693 5290017.89177349 493775.648970343 5291608.86854032 493750.699693533 5293150.84586706 493728.753104446 5294776.82181349 493731.649256886 5296388.79709995 493731.935767607 5296550.66961577 493776.730713998 5297964.77137662 493783.330511173 5298155.64321211 493838.093445917 5299556.7446901 493846.756365626 5299768.80360605 493904.424709744 5301149.71765226 493913.118863083 5301361.8390452 493921.563243168 5301580.83533847 493954.755974827 5302733.94120834 493960.013024057 5302956.00006086 493955.9946899 5304317.66657612 493956.565520734 5304575.66254475 493954.046946923 5305931.6415582 493953.86701868 5306165.63792368 493952.442891526 5307544.61650254 493952.326104836 5307798.61254779 493954.463320831 5309145.59144216 493954.877885721 5309403.33739959 493963.859589912 5310780.31549167 493964.929757913 5311018.81171352 493961.567301206 5312372.22816381 493960.325626435 5312628.97419436 493960.367397812 5313923.51638735 493431.384461735 5313928.53994069 493490.434964883 5315540.51239895 493379.48653035 5317130.50072358 493388.531252847 5318741.49042006 493360.577546444 5320361.4818554 493352.622551027 5321960.47243614 493352.081509723 5323845.46083966 492804.884251059 5323832.30308164 492804.728410709 5323846.4905109 492786.743364527 5325445.48257286 492776.789998417 5327070.47405103 492758.836543209 5328679.46609166 492788.880984317 5330290.45520526 492781.9264423 5331879.44663193 492780.972009399 5333482.43757738 492783.017951372 5335104.42818006 492746.065367191 5336708.42150474 492720.11243214 5338317.41412255 492733.157548137 5339930.4039689 492739.203056658 5341545.39423472 492746.063959719 5343265.32127047 492951.176985921 5343257.86832142 492951.052204394 5343265.36828563 492922.29539326 5344928.3569705 492934.35169547 5346483.34022611 492947.410593318 5348110.32261461 492938.469013554 5349693.30712058 492927.530125579 5351349.29100348 492967.586978927 5352956.27129905 492969.645361767 5354555.25463466 492999.703801659 5356189.23530221 493036.761092332 5357797.21559205 493033.82054541 5359419.19892554 493050.878525029 5361022.18076849 493074.959125943 5362394.97688371 493169.268276769 5362392.59408621 493175.88894744 5363984.13924712 493176.488060854 5364130.88764683 493189.479189174 5365604.18347051 493191.047021142 5365750.86928435 493204.537530078 5367207.16519159 493206.293819464 5367380.03820552 493234.845517007 5368810.83304566 493238.445335476 5368978.83094687 493267.496754917 5370400.12577509 493271.190904903 5370583.74849247 493312.272784848 5371989.04571345 493315.329980969 5373555.07264266 493327.388340583 5375159.09941695 493337.44704718 5376772.1264789 493341.504649911 5378352.15344092 493360.562932647 5379960.1795722 493372.621192826 5381564.20619109 493399.679270822 5383172.23157814 493468.737445095 5384806.25386166 493479.37420531 5386074.14118232 - - - - 373992.834567751,5252100.90249579 375578.907291097,5252060.9016806 377183.981372119,5252035.90076999 378770.053836318,5251988.90012694 380424.132814015,5252045.89859687 382036.206902856,5252012.8979458 383378.268520258,5251983.89746 385004.34489571,5252002.89649079 386772.428209329,5252032.89545573 388359.488754287,5251990.89431465 389964.549770751,5251954.89312519 391575.611064042,5251920.89196047 393178.672571485,5251902.89076516 393228.738270271,5253772.88131533 393228.792456634,5255363.87321734 393234.396568643,5255577.49913186 393290.022245729,5255616.371974 393390.058438338,5255644.18441468 393456.779853272,5255644.18446989 393523.470080964,5255646.05951586 393612.378616319,5255608.99727381 393710.566996525,5255520.06029167 393761.41076364,5255461.24811933 393799.504685641,5255421.87334027 393801.348444994,5255419.99835078 393841.473568551,5255376.87359007 393843.129820376,5255374.99860038 393872.227230318,5255341.53053376 393872.254834063,5255341.49878372 393897.254849763,5255312.87393979 393937.723412979,5255260.37422077 393978.628478725,5255178.31214177 394000.095924966,5255115.37495644 394028.845055521,5255056.68775393 394150.002619737,5254954.68830693 394178.156529424,5254854.00129532 394182.905333014,5254813.68898684 394167.965771729,5254770.93918013 394099.587293418,5254748.62675282 394009.927251763,5254741.75174377 393877.07762318,5254723.93926859 393780.791470774,5254692.25187944 393703.692246657,5254621.56469184 393669.876928002,5254578.31489037 393670.062654952,5254526.25264556 393700.781229152,5254485.56535535 393760.812865314,5254427.44065828 393853.751326504,5254348.19106971 393938.597961266,5254334.50365964 393995.006383031,5254332.81618377 394145.355850435,5254326.25375792 394274.486167185,5254332.44126676 394384.022495763,5254354.19119954 394496.36942946,5254317.6914001 394536.806777902,5254266.94164156 394531.897189883,5254175.75455242 394583.272771438,5254133.81725321 394667.119014884,5254110.19237722 394714.55412945,5253986.94293421 394721.021368279,5253935.8181618 394744.520795483,5253892.44335681 394735.643469879,5253835.25610857 394714.858845106,5253761.25643422 394717.749468196,5253733.17612058 394721.13823463,5253700.25670446 394781.639561834,5253669.81934075 394850.141230463,5253640.19447216 394876.479432891,5253639.04667605 394969.176980153,5253635.00699702 394976.271037152,5253635.81949367 395519.510298066,5253611.56960918 395527.698069839,5253610.13211528 395591.795584246,5253645.88197253 395621.11081318,5253691.13179129 395623.173960433,5253707.38172584 395623.176417391,5253707.40122329 395626.206167995,5253731.44412897 395624.42712544,5253796.81886485 395634.993873549,5253906.81842208 395675.779923451,5253998.44306012 395723.252798144,5254063.06781092 395768.693664449,5254108.19264151 395804.538842082,5254108.56764903 395837.383216462,5254089.31773351 395891.728427757,5254069.75532382 395967.856422362,5254069.50534305 396028.203464222,5254095.56775665 396091.7057842,5254090.2552933 396158.018641153,5254025.69305678 396207.143077038,5253954.25583919 396239.860088802,5253867.81867238 396265.140567313,5253817.38136647 396287.703064163,5253791.94396523 396349.451795259,5253686.44436663 396349.452518554,5253686.44313108 396435.981260687,5253538.63241924 396471.021093905,5253535.14250544 396585.330355029,5253523.75747785 396741.052982495,5253460.13270856 396914.055403227,5253336.13314084 397183.096578436,5253318.38319059 397545.171773706,5253275.94581428 397881.089840105,5253237.88341716 398071.64310277,5253157.87611795 398411.165163381,5253015.32152345 398631.698949906,5252845.19695914 399211.553391767,5252512.82267203 399663.185514918,5252316.76194781 399663.18890481,5252316.76047621 399860.037217754,5252231.26058686 400083.512972148,5252184.8230912 400127.578144634,5252211.26051796 400233.550599022,5252199.82299713 400392.403112184,5252270.94779296 400644.262451817,5252429.8224055 400740.299196128,5252477.88478972 400989.095604804,5252627.32196682 401273.410740343,5252782.18896504 401273.424874001,5252782.19666367 401461.623488353,5252884.69648485 402111.037066948,5253242.0084967 402756.197989468,5253528.32078538 402756.232668418,5253528.33619738 402793.32506112,5253544.82077835 402867.907487764,5253578.15366794 403433.110881015,5253830.75824447 404070.552136632,5254094.38338663 404491.656023924,5254280.81508194 404491.669532849,5254280.82106263 404783.560952753,5254410.07122691 405363.374686197,5254661.44665537 405734.208224886,5254827.88450101 406041.500987131,5254961.06164401 406211.470139018,5255034.72431631 406211.538019337,5255034.75373486 407660.240902993,5255662.48321719 407660.246229705,5255662.48552528 409257.927861926,5256354.76517912 409768.695446346,5256576.08211699 409768.735834776,5256576.09961805 410876.518642679,5257056.12235784 412464.215509083,5257744.10071817 412464.225407797,5257744.10500746 413134.450013265,5258034.52484274 413134.466727295,5258034.53208522 414078.413610222,5258443.55154306 415221.098420247,5258938.68567606 415571.629807004,5259102.51900859 415769.741983816,5259195.11379287 416434.655664678,5259066.41721755 417233.950045496,5258911.95358296 417489.386345476,5258862.59051942 418521.576772072,5257884.97093374 418521.591206801,5257884.95726216 418620.339921949,5257791.45653319 418831.135731339,5257384.15777492 418831.142864938,5257384.14399141 419054.28907216,5256952.8940561 419277.644919394,5256325.22223341 419856.168262366,5254699.46313352 419856.169413348,5254699.45989922 419961.504463663,5254403.46415262 420370.297607175,5253877.47685802 420370.308017787,5253877.46346286 420684.45751304,5253473.27560163 420699.582566932,5253465.52549195 420722.613575374,5253443.65040793 420764.831886821,5253403.65025458 420829.73680308,5253321.52519332 420834.64266021,5253306.21276429 420854.485740219,5253272.90031502 420866.891582105,5253252.40034442 420911.702847702,5253185.7753913 420916.608703616,5253170.4004639 420929.139875651,5253160.0879085 420943.95161062,5253126.9005183 420948.92029462,5253121.71300567 420976.294371275,5253075.65058271 420989.130741489,5253056.910871 420989.137780079,5253056.90059542 421006.168577563,5253032.02561281 421021.011645038,5253001.33820388 421045.854749242,5252965.46322743 421050.760526428,5252947.58832284 421095.478050707,5252880.96338574 421190.632859417,5252775.46322344 421240.569406453,5252713.83819618 421287.849247044,5252639.52580995 421318.005367827,5252616.21317859 421315.286159703,5252603.58831637 421350.066321376,5252547.21341889 421382.409098178,5252495.96350618 421384.314008781,5252452.71385708 421391.845169808,5252445.08884084 421391.719840624,5252434.83893032 421396.030730076,5252381.526842 421375.216517007,5252341.1524139 421374.62137633,5252297.90279171 421389.339211332,5252259.71546142 421439.620257473,5252220.90275569 421482.62079669,5252210.08988797 421515.370809449,5252189.33971675 421547.839000509,5252150.77720407 421547.525768606,5252127.96490559 421557.619477922,5252120.15236577 421554.900351987,5252110.08998223 421562.462842742,5252104.90244671 421559.837466754,5252094.77756272 421579.680564474,5252061.40264186 421612.18009031,5252025.40261033 421690.211223396,5251971.02725899 421722.616760143,5251927.4647989 421729.92868152,5251904.46492394 421734.020257746,5251833.27800685 421753.863120106,5251792.34065896 421788.862620665,5251753.71563313 421889.644066225,5251693.90261076 422075.827735249,5251576.96673523 422075.831736897,5251576.96422193 422108.800519537,5251556.276567 422205.645840043,5251504.99070285 422207.113423663,5251504.21352236 422244.926218816,5251488.58827447 422292.238430961,5251448.1506557 422350.049479048,5251363.71333411 422397.70382296,5251271.46369329 422432.732605257,5251169.65177332 422437.887611685,5251126.65211682 422435.792387474,5251081.15255657 422428.885208473,5251056.21535543 422411.540394442,5251033.96573417 422294.688318968,5250847.59360662 422255.654102918,5250779.59461272 422219.55840433,5250741.97031117 422061.99058887,5250679.15993049 422061.990289746,5250679.15981114 422010.145087406,5250658.47312548 421961.424283542,5250626.16139231 421855.856373036,5250525.97581499 421817.417266538,5250501.03890998 421735.883675561,5250481.85237194 421596.130524203,5250476.16627958 421514.722253168,5250467.04214947 421468.689318028,5250444.85528805 421437.437048994,5250394.48102527 421385.401717388,5250301.16982975 421335.678528613,5250195.23371455 421331.737705773,5250093.67212132 421345.735002741,5249999.48529523 421345.537144329,5249912.26386602 421345.22786428,5249775.92471481 421330.504103495,5249628.73861119 421338.875153431,5249499.17714312 421346.218410959,5249478.73975099 421345.591940809,5249433.052648 421357.778483914,5249394.74036538 421359.683396659,5249351.49071882 421369.55787616,5249328.42832716 421388.837111648,5249252.0538087 421423.517340626,5249000.05566585 421452.195427332,5248684.68313187 421461.975917627,5248654.05831132 421524.318507261,5248574.43346162 421551.567482383,5248523.30867083 421555.157836141,5248413.99708926 421539.312288896,5248368.49761892 421513.247526146,5248315.49829921 421511.959865427,5248306.3313929 421507.5586117,5248274.99869791 421494.776839725,5248267.49887062 421340.200046766,5247926.69059106 421332.261646246,5247904.0033505 421282.412996707,5247785.31727213 421271.379475581,5247721.88040245 421269.46880705,5247584.75658579 421247.996825848,5247498.63249077 421244.400567,5247422.57066615 421252.336254887,5247360.19613367 421277.364405893,5247245.38441401 421304.456728695,5247181.44724735 421339.299551238,5247127.63493585 421471.860304437,5246978.44769333 421531.765467603,5246901.51039967 421541.921863026,5246898.82284537 421541.671292921,5246881.07300122 421568.982868386,5246832.4482153 421593.91995487,5246801.57329442 421593.700633866,5246783.7609511 421611.231792789,5246768.32345282 421613.66902469,5246758.13602316 421625.918251708,5246725.01121945 421633.230187974,5246702.011365 421635.604998005,5246694.32391421 421639.93604477,5246678.39095562 421645.322834495,5246658.57415329 421650.29145582,5246650.94918262 421644.821612398,5246620.44948996 421629.007389331,5246577.57498222 421600.161055511,5246517.01322451 421592.253901606,5246494.26348113 421558.751936342,5246456.57655645 421510.09362297,5246426.76467374 421491.873574267,5246399.07754727 421496.34096919,5246353.2654105 421516.309362567,5246327.64048607 421576.496443293,5246270.95303882 421616.746461364,5246242.39049484 421659.746948449,5246226.57782083 421715.435305397,5246213.20253434 421755.779319922,5246192.26492625 421808.372488355,5246135.70254511 421823.215606206,5246104.95270991 421832.77703582,5246064.20300146 421814.086858946,5245993.32876096 421792.834284135,5245927.57949187 421792.671749198,5245729.39374021 421797.327140677,5245698.89397675 421819.764106339,5245665.5816151 421855.170759483,5245652.33148713 421944.047787528,5245651.14338276 421984.517061154,5245637.95572049 422052.078932474,5245568.33087781 422083.297635789,5245543.83088341 422094.860118614,5245534.76838561 422231.393049078,5245487.20538154 422494.835058808,5245435.32906221 422527.553920511,5245414.57903166 422585.115589298,5245345.26678407 422604.927507429,5245311.95445981 422614.582703433,5245271.14227407 422606.017937438,5245205.26794313 422600.673425301,5245184.95566728 422595.548148442,5245179.95574776 422577.171372993,5245137.08126729 422561.639125466,5245116.89405706 422520.6059753,5245087.01960419 422496.489997244,5245048.03760108 422496.479184468,5245048.02012289 422489.416161383,5245036.64527414 422465.600875504,5244965.77108275 422451.848246604,5244892.39684717 422444.003756088,5244874.70956057 422443.659198623,5244849.27229659 422435.720794628,5244826.46005738 422429.843664227,5244763.08567718 422442.249562794,5244742.58578611 422477.625066146,5244732.02315724 422660.347730712,5244719.27210901 422743.942863871,5244700.39675247 422963.69518479,5244608.45872556 423072.791232932,5244599.39562315 423110.854537993,5244596.33291229 423143.604744552,5244578.08288079 423166.198307476,5244554.89546129 423245.539479632,5244411.58384623 423315.663827504,5244337.02163418 423388.726692196,5244292.83411446 423573.57349836,5244249.58340654 423702.951124235,5244211.9160219 423738.013431865,5244201.70787795 423803.889657037,5244190.5825884 423854.7032688,5244187.39481166 423905.611101011,5244199.39438211 423944.175441444,5244229.33134657 423957.145196942,5244251.95603977 423970.647234945,5244307.70539568 423968.961654285,5244371.32976515 423956.461831138,5244386.70468763 423959.21228526,5244399.32954351 423946.649802952,5244409.57951822 423946.869106871,5244427.39183766 423975.151799351,5244452.45390945 424018.528200691,5244464.57851692 424066.779324932,5244463.95322252 424112.279913318,5244448.01560082 424152.404835283,5244414.51569212 424167.153929631,5244373.64101704 424163.056649859,5244261.89218054 424195.368266019,5244208.08003203 424255.74343179,5244166.64258895 424356.681736983,5244114.45501461 424416.837842521,5244062.89268459 424421.524595356,5244034.83044647 424449.05641287,5244031.89281265 424519.086735325,5243982.76546948 424587.461809958,5243966.63786594 424650.273090999,5243910.07338602 424723.272104283,5243858.32094554 424773.928287044,5243842.44405399 424811.677647115,5243811.50533222 424927.488323561,5243721.18903625 424937.268631943,5243688.06396576 424954.736658528,5243659.93853504 424974.109535597,5243586.00097629 424975.857432102,5243517.43907775 424985.79453947,5243502.06382617 424998.231354667,5243476.56357253 425048.85636252,5243463.24915306 425127.701049451,5243472.43337074 425229.201617576,5243463.61684715 425303.545163236,5243437.11409532 425303.549402951,5243437.11258231 425317.732624008,5243432.05107015 425378.357317052,5243405.9238695 425403.270589048,5243382.7576384 425403.294305405,5243382.73558515 425406.013000479,5243380.23549935 425463.136866116,5243328.35868973 425462.480264155,5243317.17132501 425460.792492731,5243308.85897413 425455.948497517,5243302.23423474 425447.948330789,5243298.98459044 425433.698218927,5243299.17266596 425417.541907133,5243301.48579805 425397.916946351,5243307.98652995 425372.697715243,5243299.17513742 425355.634743497,5243288.48843276 425343.821153443,5243256.42672351 425345.507970825,5243233.92687414 425359.506696935,5243189.05174343 425375.537302995,5243163.98883738 425400.474334798,5243142.23803789 425418.38050765,5243134.98738237 425447.099902502,5243148.17358989 425447.288209402,5243174.17332972 425462.758500157,5243219.79725953 425479.946995741,5243247.3587953 425506.354472486,5243279.91990916 425551.353092976,5243223.41863382 425560.165621094,5243221.98079062 425563.165913152,5243230.60558541 425565.041097145,5243236.04295671 425567.791365844,5243243.98026831 425570.51055476,5243257.41752786 425573.260993946,5243270.85478616 425578.761759986,5243294.10433792 425588.762423759,5243312.85375104 425604.075602435,5243330.66545811 425621.201379501,5243351.16456581 425642.827135771,5243369.78850955 425669.796296844,5243375.84985863 425674.858885241,5243377.34963909 425674.934197452,5243377.3720909 425702.109362684,5243385.47345691 425719.078194943,5243383.59778787 425737.890648983,5243377.09708887 425740.010214788,5243376.08200283 425740.109384381,5243376.03450929 425761.078005389,5243366.28375434 425789.608818469,5243344.59530833 425809.233420225,5243326.53218786 425816.420044734,5243296.40718753 426022.641687027,5243334.64846594 426081.079571282,5243331.45862981 426093.704510585,5243326.14566952 426234.451831359,5243202.57865267 426287.545445784,5243184.13917769 426328.358659772,5243196.2624079 426417.171624064,5243187.63389151 426447.264740691,5243159.32044218 426501.824110273,5243044.3818262 426523.822067562,5242973.00661389 426573.256469659,5242860.56817836 426566.505935163,5242845.19359849 426561.84949313,5242840.25633441 426541.161697012,5242836.19471257 426506.16099743,5242822.94625908 426475.597836297,5242809.76012506 426445.065699758,5242789.32405904 426410.783342017,5242762.76320388 426390.126228305,5242740.45175531 426380.937483647,5242702.88998672 426397.812090207,5242685.82696422 426417.436826176,5242672.20129717 426441.593045662,5242664.88788584 426469.34307169,5242658.44932016 426505.249829028,5242665.32279647 426546.53168879,5242674.07103677 426594.938630275,5242683.56898076 426637.970333149,5242686.81720254 426676.283491168,5242697.87804186 426692.813726213,5242661.00272043 426732.687135307,5242599.56418343 426767.090643263,5242502.68870327 426766.370063986,5242444.2517858 426737.743017776,5242386.12849988 426704.430449989,5242392.62979268 426685.680638845,5242403.56795129 426673.243710305,5242425.13075245 426662.68210293,5242456.5058842 426653.807730458,5242478.94353205 426640.558491852,5242506.81880599 426626.277661489,5242524.00672317 426603.058893881,5242529.50761442 426567.932890937,5242506.50926029 426552.525403249,5242470.82272563 426532.586656173,5242436.01136702 426531.554476479,5242406.44919003 426532.209783214,5242376.01195274 426541.959052007,5242350.01180343 426559.70846546,5242326.57380431 426578.426722354,5242305.88573951 426698.018928816,5242225.31913873 426758.705564592,5242181.87958072 426801.611539326,5242161.94052329 426821.54958683,5242174.31459496 426838.704463395,5242125.87685449 426893.765245675,5242056.62526697 426931.421250946,5242039.06139951 426931.434142717,5242039.0553835 426972.139735793,5242020.05992068 427007.608597992,5242014.49602885 427033.328422654,5242042.24472045 427115.299629895,5242099.67834344 427169.14506588,5242139.6757763 427217.614665312,5242154.2986667 427247.770431821,5242131.04765762 427239.581279795,5242080.36096614 427190.422425647,5242009.80112922 427177.202226058,5241966.86457046 427219.669392251,5241905.30091825 427490.136874861,5241795.35342681 427512.448034294,5241746.85296971 427507.760063851,5241733.04078954 427507.759671562,5241733.03963564 427501.853222022,5241715.66619228 427483.663894005,5241661.97993435 427478.163338843,5241645.66781074 427480.631867742,5241637.98028176 427482.693269968,5241602.41802925 427563.09782598,5241527.85294411 427643.815676353,5241478.60010886 427747.346199541,5241429.09634358 427792.783324321,5241405.59470699 427815.658418391,5241402.78129942 427818.878061245,5241430.4059122 427805.691923493,5241477.15601728 427810.349081718,5241504.90557021 427823.006131273,5241527.15484779 427853.632211953,5241553.77835203 427875.100874598,5241545.52755272 427894.693937325,5241518.65200213 427931.098640841,5241460.15105773 427984.095254346,5241338.90001456 427967.063393539,5241323.77584948 427909.719454053,5241332.27811207 427881.9693509,5241336.02921031 427856.87540505,5241336.15523362 427837.531114493,5241323.8436373 427806.623272624,5241280.97029621 427798.40278573,5241227.72112499 427827.806545662,5241140.97072671 427912.239736362,5240982.4687407 427931.769059366,5240916.2185537 427967.487252672,5240889.52983904 427995.612847748,5240901.4035792 428012.488644879,5240922.52769432 428031.333942422,5240967.02651368 428039.459680497,5240988.46348396 428060.336104983,5241028.52476154 428081.80502093,5241028.39888512 428118.523800084,5241020.08496068 428120.147969765,5240993.27264091 428118.209497271,5240962.83550012 428113.489469795,5240923.39855585 428097.081744029,5240880.5871207 428092.424386219,5240846.52512457 428097.704233305,5240800.58783112 428125.672611899,5240781.77435971 428184.549253219,5240819.20910681 428236.333450341,5240899.89374799 428269.99163211,5240952.82938605 428343.930485838,5240977.26363916 428504.0568526,5240980.44456402 428567.432091882,5240972.12954915 428655.649986489,5240922.87639123 428655.651697681,5240922.87543563 428688.555916929,5240904.50021297 428723.554659362,5240855.87422389 428712.615154558,5240795.0627241 428673.236494842,5240688.87780087 428690.485102474,5240640.44003526 428675.358599653,5240596.56605342 428657.107577197,5240568.69205421 428651.169687618,5240557.81739627 428651.160664338,5240557.80093873 428644.41924635,5240545.5052847 428623.668155315,5240516.0689024 428613.667428521,5240495.50699915 428602.760277172,5240469.63268145 428613.352949152,5240432.82008249 428632.946483765,5240421.13188599 428649.461729364,5240419.69512131 428649.477817678,5240419.69372169 428667.009157433,5240418.19301698 428693.853194224,5240420.6293949 428727.072282869,5240423.12801109 428760.134723848,5240413.06424771 428787.790365439,5240386.93835144 428783.227121532,5240364.50124191 428769.601255609,5240340.43951859 428717.066414307,5240239.63008705 428715.566183702,5240232.69271154 428715.562033437,5240232.67315401 428711.534302746,5240213.69304935 428720.252020059,5240178.81800834 428733.65803114,5240167.94255714 428756.001637324,5240157.87923191 428873.314854283,5240151.68697586 428889.533813333,5240154.31128684 428904.003803169,5240189.99787059 428890.004641763,5240219.99817334 428889.997553997,5240220.01339022 428826.133473843,5240357.12455032 428814.633920726,5240374.12486755 428813.85340258,5240397.49968768 428821.166689827,5240420.62417844 428821.323734269,5240445.7489443 428808.824202717,5240463.68679377 428797.262182377,5240481.74960362 428790.294168904,5240506.81216173 428785.919902026,5240531.12462036 428788.764605456,5240560.62423626 428799.297372305,5240606.06089284 428829.922839666,5240613.24707387 428910.766150719,5240579.24407202 428965.98346615,5240520.11734574 428995.512532296,5240443.67932694 429018.412369999,5240235.11777138 429017.568253364,5240210.75486928 429017.567843021,5240210.74302597 429015.033679321,5240119.18145608 429002.40693177,5240066.99494499 428980.186843911,5240030.12118959 428963.061005979,5240007.80959388 428932.498020183,5239999.93591942 428898.466516229,5240000.24981342 428866.279027279,5240008.50105994 428839.403909706,5240011.37713698 428812.528794088,5240014.31571345 428782.903146086,5240001.06704946 428772.027527097,5239984.13014935 428769.183050688,5239961.81796831 428787.93256643,5239941.87987918 428810.213418579,5239923.81662794 428852.213254071,5239908.31504367 428880.806625119,5239889.31404135 428918.306174644,5239865.87521318 428946.02464913,5239850.37421478 428963.89966876,5239846.62351449 428988.087549267,5239852.74746581 429009.619129659,5239857.93403474 429038.338239975,5239862.30781587 429067.869285496,5239848.61922639 429082.02488005,5239824.43136283 429092.711921048,5239807.30607803 429113.149653999,5239809.68021716 429135.868729714,5239814.42924124 429155.213141218,5239830.61580114 429176.40206056,5239870.30207417 429189.090447692,5239895.23882903 429205.278721611,5239915.73798017 429226.029556688,5239937.04943682 429239.561334774,5239950.42376122 429270.093125982,5239960.04742155 429289.812022869,5239959.85911383 429307.655739024,5239954.42093016 429318.185960559,5239919.35831226 429314.497440658,5239888.04624441 429303.496283107,5239854.17199984 429285.463961808,5239824.73550436 429268.244174647,5239796.17396783 429242.961629583,5239761.42531821 429218.554036165,5239724.92664865 429205.80275119,5239687.42750933 429203.801659862,5239653.42789686 429212.644708541,5239629.11525166 429206.300160118,5239605.42822512 429226.456074569,5239589.9275356 429297.330867545,5239566.17483461 429355.800126289,5239568.04741385 429449.738312711,5239566.91856172 429472.050756455,5239559.73020856 429482.644478939,5239556.2923037 429481.519022639,5239542.16747608 429471.924252162,5239512.29313736 429456.391765878,5239477.04409093 429452.578216649,5239444.85703525 429472.26552096,5239433.91882306 429509.015824461,5239434.60480516 429569.953948181,5239439.53975444 429635.392277044,5239449.84947094 429658.767480121,5239450.59850281 429675.018451436,5239477.28509707 429662.644383491,5239509.66031799 429649.36371348,5239531.1606728 429620.0211097,5239574.41149419 429603.958999517,5239590.59951032 429584.990912165,5239616.10006281 429646.367570047,5239653.47220739 429723.150912821,5239700.78113141 429768.932656751,5239705.216711 429778.495361437,5239709.34128149 429789.339649382,5239723.65320889 429792.15282376,5239744.21541078 429789.622492541,5239773.77775224 429782.623291445,5239800.65280105 429772.061991163,5239841.02787613 429769.625608838,5239876.840158 429775.970203341,5239901.90217487 429794.971026962,5239923.2137056 429812.908888172,5239930.21290716 429842.471412956,5239923.77425089 429913.096007612,5239893.77161789 429931.814444053,5239879.33347736 429933.407380568,5239853.33364222 429929.562292602,5239812.14666484 429918.340670766,5239724.46040224 429912.65153681,5239674.39857929 429902.931945658,5239650.27419233 429935.180327918,5239591.52338711 429973.148951156,5239578.33444311 430011.399714245,5239593.08274051 430068.747601033,5239709.32935724 430104.749154568,5239749.45252428 430125.281040108,5239764.45154868 430178.781839177,5239776.57424458 430204.094282369,5239768.63577498 430251.805343489,5239709.89195168 430251.81153196,5239709.88433218 430279.123172799,5239676.25850589 430295.933210702,5239594.8210309 430272.30593641,5239529.07257987 430247.085395536,5239478.88655797 430247.065130004,5239478.84626715 430220.2709934,5239425.57562951 430224.142785711,5239323.82636509 430242.452446773,5239254.0166138 430242.453204368,5239254.01372529 430243.515585201,5239250.01371672 430307.918014048,5239114.51225511 430345.917967379,5239103.94828284 430509.421577742,5239178.12840114 430513.204927995,5239243.12767728 430514.268204909,5239267.25242264 430514.394006515,5239292.37719784 430518.11363941,5239319.18931041 430527.302092121,5239346.87619038 430541.708992321,5239363.81294971 430556.115635628,5239372.68727956 430581.209769303,5239378.68619498 430607.990648845,5239360.62275108 430628.458752676,5239335.43462885 430622.769726485,5239288.93526851 430624.330668107,5239239.68563383 430636.704479254,5239199.43547551 430720.392427261,5239193.432083 430735.205178018,5239197.74393575 430737.955512096,5239207.55623717 430732.612233708,5239223.61881733 430731.019275082,5239248.80616369 430733.051910451,5239291.74320637 430736.803137519,5239329.30522511 430745.897585315,5239348.99217966 430767.55470928,5239371.1785958 430790.96164739,5239387.11499449 430825.962364775,5239401.17593282 430850.11868049,5239397.42497198 430867.087071903,5239382.11190711 430872.336367945,5239358.79939359 430863.116264319,5239318.61262171 430848.520746561,5239266.73867259 430829.331130686,5239205.05249797 430804.860599863,5239155.11643903 430805.640128327,5239100.99187713 430827.261959432,5238996.55439349 430856.19553098,5238866.61682865 430881.163245,5238828.24113217 430888.412483633,5238802.67855485 430994.004072172,5238709.98750294 431080.160372442,5238691.17161198 431098.035827311,5238701.17078844 431134.099803186,5238738.79397669 431158.165643339,5238837.54213327 431184.762837348,5238938.91516358 431198.76634806,5239045.35116963 431206.924039531,5239088.47546214 431250.675982808,5239138.78572757 431322.302881923,5239181.03241588 431508.086377232,5239206.77454937 431586.649121875,5239195.64641174 431674.77256393,5239126.01837977 431707.302910094,5239090.07984728 431773.397136633,5239089.20213385 431853.899430004,5239141.51087506 431858.115192378,5239144.50846021 431858.118308525,5239144.51067592 431925.122044907,5239244.9445654 431971.123111785,5239267.19248425 432081.75283505,5239387.8119124 432115.536372922,5239450.93498927 432187.66442913,5239528.7438672 432231.541792749,5239591.74153242 432285.105257091,5239608.86418795 432358.950122511,5239625.79851256 432384.544386038,5239635.60987891 432476.327458173,5239670.16831957 432519.985170762,5239705.10373376 432538.581183597,5239770.91491781 432537.272025559,5239875.03909702 432499.655637394,5239998.33592644 432499.650701986,5239998.35210343 432485.933293273,5240043.35228728 432456.843008563,5240158.10251364 432462.751426357,5240224.03921639 432545.035988315,5240306.91014946 432665.978644202,5240437.52910212 432735.951760437,5240555.96274664 432772.830394313,5240659.7103696 432783.582195138,5240712.95948416 432773.80185245,5240743.52212786 432747.430744904,5240870.83463821 432740.150425606,5240901.5221782 432700.809895495,5241011.21036396 432702.282582003,5241133.0842805 432683.129292311,5241229.77174948 432679.978172552,5241389.89553201 432684.355048866,5241447.08237286 432698.621560686,5241638.26320182 432701.112413624,5241671.64230216 432733.116586203,5241793.20247775 432766.649482272,5241835.88825501 432817.431125492,5241835.32369436 432893.211893738,5241801.32089719 432930.86720768,5241762.81968784 432937.74013186,5241696.69496167 432934.895621542,5241673.82026886 432975.618981181,5241634.19734614 433035.299531864,5241576.12949839 433065.831015856,5241575.75325846 433090.548317766,5241524.69017794 433082.516327646,5241503.75317963 433088.703155593,5241481.37811423 433077.638806391,5241426.81651988 433064.85609881,5241384.81739093 433052.948370177,5241341.94323378 433035.759609423,5241307.13172477 433023.008469064,5241274.94501313 433002.100439071,5241224.94628289 432984.848976842,5241183.8848292 432973.004039787,5241150.01059518 432948.533713887,5241107.199451 432929.689295617,5241091.13785405 432912.595155358,5241083.26361733 432892.157383533,5241079.88947947 432886.280046016,5241008.82781364 432878.592327649,5241003.95316819 432908.873317092,5240988.38956232 432990.186678174,5240995.01118797 433125.470673771,5241046.69273617 433202.41072646,5241106.75159756 433240.598761453,5241113.87498056 433276.00495307,5241103.3111239 433306.191943067,5241080.06008524 433315.721542831,5241026.62263938 433279.719955761,5240986.37444233 433233.624954605,5240959.00155092 433215.624161483,5240938.87745283 433207.497706383,5240895.8156422 433217.403375183,5240875.37790742 433237.433954787,5240849.68980265 433270.152296439,5240829.00113802 433473.153172742,5240806.24303517 433486.926229535,5240806.70438945 433640.87343626,5240811.86113884 433657.21633902,5240781.67321963 433662.496730744,5240753.86073263 433659.526597813,5240711.86119926 433670.150897073,5240687.61096449 433717.651350201,5240689.98400406 433749.152401172,5240714.73251384 433767.184370929,5240732.54413103 433770.87227664,5240744.16888502 433780.873280974,5240772.73074225 433783.030159372,5240791.60549936 433787.468880752,5240828.23001772 433788.595162866,5240867.54214931 433788.689670627,5240890.91695373 433777.253065306,5240921.3546709 433773.879200159,5240957.22951423 433771.317637024,5240986.79187616 433771.694554536,5241045.91637549 433768.320658869,5241080.85372631 433776.540284025,5241105.8531858 433789.260495716,5241147.85232229 433806.417399061,5241163.78899188 433828.855250641,5241169.10053339 433860.011363253,5241157.16186084 433886.292540027,5241148.41086085 433896.979315517,5241123.41062978 433903.134598141,5241092.03563562 433935.976173921,5241016.84741113 433945.630440891,5240953.28503696 433961.503825146,5240899.53482843 433965.7832798,5240843.09761488 433974.594196579,5240792.0976717 433976.03087931,5240766.53532179 433977.09276369,5240747.28543562 433970.685162101,5240707.16102505 433971.496766906,5240679.348719 433983.996025023,5240653.41092003 434015.214438556,5240635.40979117 434043.902248747,5240637.97109793 434075.277785002,5240646.84474346 434112.09118276,5240665.53058703 434148.905043138,5240698.46631491 434180.906698373,5240741.65215643 434195.719971089,5240761.8388873 434211.971868986,5240816.3377807 434220.19193392,5240854.83713223 434222.067557409,5240873.5869033 434241.006222484,5240904.83587636 434252.881785709,5240919.27277439 434298.412807851,5240901.0835637 434323.380344057,5240857.58289734 434388.252207605,5240745.14365928 434428.563939087,5240711.64228378 434598.533568062,5240697.19795746 434621.345994915,5240689.38458853 434636.37661395,5240666.32166018 434641.000410428,5240628.19677809 434630.687253396,5240610.50984184 434559.24830167,5240583.26298071 434541.028096777,5240542.95155038 434553.558695938,5240519.88872408 434596.589940439,5240509.26205056 434795.029932381,5240537.62871093 434833.123973468,5240537.31465642 434839.40907487,5240654.06346419 434822.474092101,5240735.50100316 434765.007717438,5240822.50265152 434684.164755862,5240866.50559792 434494.102128314,5240909.13801159 434456.290411626,5240942.5142849 434404.325310105,5241067.57789284 434372.140203973,5241149.20354399 434372.51627875,5241182.20326118 434387.891974371,5241199.82749155 434517.549547792,5241208.57213582 434540.330645197,5241198.25879058 434583.205149595,5241172.44475129 434661.54834205,5241136.0043512 434841.078404615,5241055.37267875 434894.046485081,5241021.80828753 434932.171858896,5241023.93171551 434955.423032129,5241054.24302467 434951.238314312,5241140.68000359 434936.333023844,5241173.805346 434822.677966645,5241238.43445985 434759.459640864,5241267.06180588 434752.085328024,5241289.99942189 434821.055931976,5241329.93379125 434958.401236139,5241343.74058618 434981.182331396,5241333.36474135 435027.739890408,5241170.2391488 435049.674745139,5241083.67644605 435074.406137693,5241052.36388019 435102.297994234,5241017.04983175 435147.797597646,5240993.73566177 435208.672816838,5240985.54574391 435297.673829562,5240994.79204024 435348.580798414,5241004.3523881 435427.237401503,5240995.911747 435459.73607311,5240947.28580622 435461.577682184,5240881.2862531 435417.605940684,5240800.4136875 435360.978188456,5240729.91655763 435335.070249373,5240684.48047569 435308.879979266,5240605.98216783 435318.252560504,5240529.60739034 435327.970144866,5240491.54479481 435357.874794744,5240435.29401785 435416.061988824,5240411.85432427 435672.595260259,5240411.71883674 435733.783971351,5240433.96616044 435754.472706267,5240466.71505769 435761.322074096,5240636.77594295 435792.229890398,5240677.14936381 435830.700095411,5240712.27251749 435848.575562725,5240722.20920977 435868.482063045,5240725.02087502 435932.514118905,5240734.08068995 435986.07760781,5240751.265869 436077.421720139,5240740.1372271 436110.045804047,5240704.26117487 436119.763381843,5240666.13607507 436098.322137513,5240557.07530029 436002.126920508,5240344.76838717 435919.183471615,5240183.08554247 435900.430334234,5240091.77452353 435909.802908791,5240015.462236 435932.364580498,5239984.77405167 435998.239740005,5239973.89643851 436130.522482608,5239987.82841245 436216.866962218,5239989.44986387 436282.491116767,5239948.00999744 436310.13607359,5239900.15144092 436310.146012239,5239900.13423528 436314.927028895,5239891.88410326 436308.422644324,5239759.82289152 436261.512212425,5239643.51321499 436337.10443938,5239579.19811188 436537.229423017,5239531.37777043 436583.230599633,5239556.31319154 436624.984416431,5239662.56066302 436663.862125178,5239735.74600741 436681.68475947,5239744.44308314 436776.177303905,5239790.55348417 436842.271794076,5239797.36322366 436867.584065984,5239784.42478527 437085.521855142,5239741.54118056 437125.676814098,5239692.85240449 437094.298736023,5239606.85434395 437073.264902961,5239533.41826443 437080.231693169,5239472.29344289 437110.481250245,5239451.72985777 437186.731983737,5239456.03919625 437365.047397084,5239502.40652987 437425.860012499,5239491.5916167 437468.57765199,5239447.9026931 437475.544444263,5239386.96536572 437482.542480397,5239325.84053824 437522.697435373,5239277.21425514 437560.666045375,5239264.08779469 437580.197312131,5239260.02452319 437610.416718976,5239272.83568628 437621.292480367,5239293.33508607 437622.324774962,5239324.70980852 437611.700991516,5239364.02244985 437455.494870464,5239783.27570405 437443.215267497,5239836.08830908 437445.123244434,5239887.96283987 437450.342641733,5239906.3374876 437450.347889116,5239906.35599495 437456.030848428,5239926.39960345 437474.062978259,5239948.7736965 437517.063781731,5239962.89682964 437555.595300937,5239961.89525972 437583.282601181,5239949.26922112 437606.500821088,5239927.70593253 437619.248859425,5239909.45763575 437619.250318217,5239909.45554755 437629.656158395,5239894.58023312 437675.998165075,5239830.82881344 437696.497377478,5239802.14068875 437705.340308494,5239775.26552782 437708.870553345,5239744.01561725 437710.494056127,5239698.32839287 437698.585230546,5239623.20444359 437674.799156616,5239482.83147037 437670.984439789,5239416.6446226 437662.669450621,5239343.27051337 437654.4491004,5239296.77119908 437657.073587843,5239280.64621209 437658.728630001,5239243.70892073 437677.291149487,5239239.95818656 437712.13297461,5239173.58225214 437731.097668167,5239046.45742307 437755.845748605,5238982.64438241 437793.156087948,5238908.64340053 437843.718200552,5238885.20399595 437965.750597553,5238891.5739302 438004.252138613,5238929.19706778 438040.724101232,5239017.75741157 438090.134415949,5239129.0045567 438136.668534147,5239204.75208445 438170.013539817,5239234.87549231 438163.046756841,5239295.87532698 438115.204168358,5239342.12694817 438100.831669138,5239421.00195332 438131.488734614,5239438.43806637 438184.801629892,5239437.87338346 438214.676698245,5239432.93469441 438283.739359472,5239421.61944476 438296.994445698,5239415.5557913 438329.239022643,5239400.80523163 438437.298788852,5239293.11409011 438452.047293976,5239244.61384118 438433.482131179,5239168.67766156 438514.481798405,5239139.79954699 438549.480454447,5239091.17346592 438673.252324028,5238780.04565372 438695.782471667,5238741.67000697 438751.657965869,5238743.66769376 438784.783713906,5238758.54122276 438833.692179504,5238813.91380826 438839.538503137,5238889.9755147 438810.699777323,5239047.78805148 438786.735412326,5239185.28803407 438767.175213891,5239259.10079892 438724.332162124,5239290.10233117 438564.958089619,5239355.233395 438519.928529332,5239416.67229178 438429.524979497,5239519.23774584 438377.589883729,5239603.92675149 438374.590019929,5239608.73933899 438357.561167422,5239685.05197432 438373.187377406,5239717.8635921 438429.344976154,5239745.29858925 438556.440012263,5239754.10581809 438815.34760613,5239733.59536249 438891.316162765,5239709.90492309 438926.220649085,5239648.65393875 438914.559412155,5239501.40548772 438908.525245354,5239415.09386287 438940.741618406,5239336.0931154 438988.835302735,5239322.90373775 439062.711437133,5239339.77558419 439129.589808234,5239425.45972052 439210.252749671,5239607.58009717 439292.22414004,5239667.638805 439376.382288985,5239704.88508916 439465.414627068,5239716.63135797 439513.664902466,5239713.56690371 439536.414736543,5239703.25354585 439593.755440673,5239598.50194687 439638.878740756,5239537.00053739 439674.25358268,5239523.99918029 439705.004656862,5239548.99774147 439830.69699692,5239664.55426803 439885.716561564,5239709.61218704 439956.232664447,5239767.3608965 440088.641011908,5239799.04275131 440139.359885916,5239790.85323295 440189.984756065,5239775.10127166 440487.856115501,5239596.71532639 440538.700415786,5239601.27571161 440577.107973763,5239631.33642834 440610.985784719,5239707.27201084 440651.956115299,5239744.83257141 440690.175582139,5239757.26842014 440718.23854545,5239764.51722091 440761.301026818,5239753.89053208 440824.519400125,5239727.88812473 440924.013321674,5239523.63546545 440986.260127313,5239414.07117183 441003.852972908,5239383.07066466 441036.633871203,5239365.00694531 441173.979066398,5239376.18873734 441291.04337579,5239402.8712553 441354.794450956,5239420.05602454 441392.825726046,5239411.99202088 441440.731307861,5239381.05276855 441491.136818155,5239347.42593154 441493.574229786,5239344.23835334 441493.587389503,5239344.22123925 441508.761182833,5239324.48786526 441518.510056681,5239288.8002086 441571.289899878,5239234.86091105 441581.226790564,5239214.48564198 441585.913042356,5239176.36070888 441579.036780257,5239140.48623483 441575.129828213,5239120.54903067 441546.345628468,5239039.61326235 441530.123504235,5238943.17708428 441511.37028775,5238851.99097485 441507.710331387,5238742.80436791 441501.707377636,5238656.49270168 441493.549271239,5238603.24339929 441476.33205697,5238583.62189494 441476.329728245,5238583.61924102 441458.985180196,5238563.87008886 441429.29631842,5238530.18403958 441396.076642976,5238510.24804221 441332.701606564,5238523.56305899 441281.202243367,5238554.18996856 441206.484416552,5238598.63023806 441057.298043148,5238666.13591042 440786.235695324,5238732.58409754 440656.829091591,5238751.65178565 440587.983901285,5238724.46730539 440544.325799127,5238679.21941592 440515.761043529,5238618.47101433 440479.508738079,5238557.97292788 440452.754029706,5238423.59996689 440496.125317121,5238302.80786469 440509.530410747,5238265.47373108 440546.684033701,5238178.72280403 440535.775152283,5238102.72378253 440465.895558396,5237981.47750861 440440.175602292,5237951.29128005 440424.893899722,5237941.22948069 440345.171513987,5237850.67090272 440336.919410036,5237789.73416911 440356.949868082,5237761.60853853 440384.69947114,5237743.54501877 440476.137710158,5237745.10373216 440613.796650775,5237794.47270553 440687.672693014,5237808.96955544 440763.735481931,5237800.52897406 440788.89097666,5237772.40312995 440810.292601431,5237629.9032299 440819.633772036,5237551.02838808 440871.316520024,5237398.08980561 440940.623532631,5237219.46316716 440970.183512161,5237137.96250331 441047.899395154,5237035.58498744 441135.08212044,5236874.51997715 441192.234670401,5236752.08094346 441214.451439632,5236688.39295611 441221.574781394,5236665.73814057 441285.788072267,5236461.51653938 441289.722091617,5236357.32958354 441261.282853973,5236311.89357319 441220.343959355,5236279.33299498 441062.560589792,5236250.46474664 440986.215969461,5236241.09298271 440924.933185458,5236208.72075081 440741.335777967,5236139.54135676 440715.647163772,5236111.91761485 440723.209458194,5236104.16735379 440672.333934418,5236099.54450094 440641.018489675,5236018.6088612 440630.172535218,5235955.29724899 440644.732999327,5235891.54708265 440669.669049976,5235843.04637898 440644.043191708,5235822.98508389 440658.729086492,5235772.04732342 440662.725529522,5235665.29789207 440623.283412227,5235536.2379243 440584.280417695,5235455.3651075 440575.495354601,5235343.67874378 440625.116849115,5235228.80246467 440702.425348697,5235093.42516809 440714.658382803,5235063.58900382 440714.674431357,5235063.54986167 440722.298861412,5235044.98717064 440724.516683928,5235016.92477053 440706.359116846,5234981.55077171 440642.85860784,5234979.74093689 440546.702907181,5235016.30720196 440484.297972655,5235068.62194755 440484.263266197,5235068.65108297 440405.67463157,5235134.62477446 440365.300209635,5235160.37628181 440324.957127734,5235188.81526885 440284.519951066,5235207.00433058 440208.237848106,5235197.69507939 440159.517234211,5235152.38492862 440161.735149471,5235127.01001267 440187.014841593,5235075.19681752 440187.022127705,5235075.18185581 440213.981925731,5235019.82107614 440306.697122824,5234894.38057269 440379.632892236,5234827.50298701 440470.412787053,5234768.12460166 440533.631107711,5234742.12213731 440571.442747795,5234708.6207866 440680.035343596,5234651.61663597 440747.75181527,5234569.73936387 440772.531006692,5234503.36378106 440718.215156819,5234414.99165994 440669.494548843,5234369.8065099 440572.962490945,5234365.74808085 440395.368248681,5234387.88036666 440258.148422701,5234384.26113899 440207.21024784,5234374.70083887 440158.583734338,5234339.64061923 440122.29985871,5234268.8301315 440119.173049981,5234215.51813306 440090.670904486,5234157.39473195 440074.138911785,5234138.6455555 440057.231910311,5234119.70889619 440001.262363279,5234107.46132857 439930.450422999,5234138.77657961 439849.71068062,5234198.21055297 439849.701854857,5234198.21704977 439695.985829721,5234311.47269851 439632.391316819,5234301.85043114 439591.201679903,5234246.4775473 439577.667707645,5234167.85366846 439576.006009139,5234005.22988334 439578.035745568,5233959.54261979 439546.751743926,5233883.66946714 439535.469896253,5233868.1075504 439520.969136584,5233848.35829837 439369.61973713,5233710.30312965 439200.363211198,5233549.43638284 439160.610433611,5233474.3135878 439153.066707842,5233460.85403865 439083.792839363,5233337.25529365 439056.164919099,5233255.31953942 439041.192180802,5233161.75846476 439086.493357043,5232881.88395102 439135.611899983,5232718.75830086 439126.637497383,5232584.25982799 439087.351361412,5232472.88740837 438992.001659106,5232344.39243787 438968.875465424,5232319.20610378 438833.747659715,5232272.33706153 438805.809995006,5232272.65070901 438735.186365234,5232316.59075578 438697.218125769,5232334.77967178 438581.50288598,5232437.59611368 438548.597067155,5232453.1598485 438515.283108483,5232423.03646631 438507.281591136,5232387.53708028 438580.865386734,5232135.2860753 438638.801335452,5232088.97157379 438762.643389194,5232029.27948903 438818.142025621,5231988.0275591 438848.360110935,5231967.46399434 438875.325116093,5231873.15117868 438873.841266481,5231851.6369036 438873.355169078,5231844.58899715 438869.352748842,5231786.83964154 438848.694907786,5231751.52827589 438696.03694936,5231732.78463683 438675.661519899,5231725.4105251 438647.284570385,5231682.47452698 438638.686987563,5231591.1006173 438672.64951322,5231435.78800661 438720.084119182,5231359.09922028 438780.864757263,5231335.65946491 438821.396122206,5231332.65785774 438913.022363814,5231349.52902715 438978.929458025,5231360.46378004 438984.304531395,5231361.46355502 439114.338608571,5231410.89539182 439185.652136542,5231425.39238962 439248.117312359,5231330.70319233 439257.990989991,5231297.57808319 439275.145003773,5231241.51538211 439297.016099857,5231144.82784887 439305.697711813,5231002.4537472 439260.376607367,5230802.33230114 439216.184637924,5230701.0849359 439225.713398765,5230640.08508735 439245.430025552,5230586.52227234 439441.359505498,5230368.57895915 439466.16989883,5230314.95346074 439468.261750086,5230269.2662857 439438.739566986,5230181.57815323 439434.132329078,5230167.89352542 439425.225553461,5230156.4564756 439408.443325912,5230135.20732065 439382.095837913,5230049.08411184 439406.905915137,5229987.95868446 439500.059319369,5229908.20576649 439625.679705032,5229782.38951951 439670.833827792,5229726.07578102 439678.427328598,5229719.20054957 439731.769341654,5229671.26142325 439731.775551865,5229671.25583629 439776.580378828,5229630.94756117 439951.674516426,5229618.94090755 440225.015363138,5229517.11882869 440336.264049925,5229472.73997381 440452.637757724,5229428.36093118 440523.417927887,5229394.48354551 440543.510915306,5229374.10797608 440619.008348185,5229304.66827219 440653.786417605,5229225.60523348 440688.250898201,5229120.97996977 440778.277048724,5228990.60286 440792.899522296,5228929.47792629 440774.490707801,5228871.16671833 440704.798275231,5228762.73295662 440707.0783475,5228734.73315326 440724.577452884,5228711.73272466 440938.07878393,5228719.59957889 440982.609893299,5228711.41048132 441011.578557547,5228706.22194098 441128.485624857,5228712.59245844 441166.705078667,5228724.90338483 441182.331551983,5228757.71494788 441137.30314561,5228829.34089773 441125.337268149,5228898.02812966 441121.404298563,5229004.71465878 441157.626134058,5229072.96256135 441216.34623029,5229097.83505936 441307.815379263,5229096.76908142 441335.408165425,5229071.08080381 441362.309971006,5228964.08092637 441369.464518175,5228923.45609055 441377.339160205,5228914.20589085 441375.884759661,5228519.21018982 441365.863750525,5227298.78616829 441362.816500156,5226925.22778895 441353.32899797,5226487.98282069 441334.385239866,5225613.43036079 441330.001586979,5225411.68267304 441327.747107756,5225307.24636884 441305.316984763,5224021.76087509 441299.678154161,5223699.26450647 441286.810453585,5222411.9036632 441283.609245141,5222092.28217366 441270.835642402,5220813.67119782 441267.540172935,5220482.29982725 441265.859079109,5219175.40754827 441265.471236449,5218876.31699548 441267.821811269,5217580.29948915 441268.401594674,5217255.3341868 441258.191667242,5216733.34001911 441237.333320755,5215666.35190995 441227.842303915,5215148.2014038 441208.265160845,5214080.36946304 441195.274251281,5213564.59398568 441168.196807764,5212489.38722958 441156.02005255,5212012.08004007 441127.127687256,5210880.40508843 441117.388581936,5210406.78527438 441094.058619425,5209273.42265027 441092.101754418,5208823.73991009 441086.988839287,5207653.43979129 441092.937830809,5207196.00699117 441107.919134768,5206040.4563889 441099.180074391,5205568.61773998 441076.86011304,5204365.48110994 441068.033916685,5203923.5198378 441044.810329775,5202759.50826854 441038.390380076,5202318.23443591 441022.763161913,5201240.53378684 441015.248841091,5200779.38528998 440996.713401008,5199638.56070505 440997.788580086,5199042.66427922 440999.66263242,5198009.587543 440997.677376318,5197479.59631226 440993.611925358,5196381.61446136 440987.346268008,5195878.46659537 440973.561784197,5194770.64128997 440965.045984715,5194262.9622736 440946.511668596,5193160.66818059 440937.027880396,5192677.64501441 440915.462465655,5191580.69461056 440913.290734644,5191084.45276957 440908.411922532,5189960.72122732 440898.739585907,5189444.7298283 440878.361997923,5188359.74790141 440868.844368726,5187794.75728581 440851.311907451,5186754.77454703 440840.168994679,5186181.03408972 440820.262004985,5185156.80111335 440808.556140411,5184569.02963089 440788.211689919,5183546.82785545 440447.274474624,5183551.58421118 439133.213072692,5183569.8587156 437519.214606452,5183597.88873491 435909.216377732,5183632.91857415 434321.217792016,5183656.94819719 432729.219448619,5183687.97779001 431126.220916499,5183713.00771019 429532.222317095,5183736.03751201 427926.224039936,5183768.06739585 426250.225657675,5183796.09869613 424640.227328401,5183826.1287231 423021.215323013,5183838.14759326 421418.182848745,5183803.15020699 419845.153118906,5183829.1516743 418239.122759583,5183856.15320425 416630.092083367,5183876.15490039 415034.06331545,5183946.15575987 413468.035170976,5184019.156598 411927.0077774,5184102.15730687 410320.977603268,5184140.15890349 408731.947575327,5184173.16060055 407127.917199638,5184205.16237558 405509.88661979,5184240.16416644 403893.850467498,5184279.17067505 402376.809351054,5184305.18266293 400767.765827735,5184336.19538155 399155.722151603,5184365.20819777 397568.67961072,5184411.22069788 397484.635123672,5182839.23587902 397438.590081989,5181207.25121208 397410.545932918,5179591.26622548 397351.500174909,5177964.28589945 397292.452470757,5176353.32576343 397156.403121981,5174745.3656852 397136.356979965,5173154.40478628 397080.309523306,5171545.44435402 397070.262855338,5169930.48393691 397074.216493664,5168318.52340502 397059.169441951,5166697.56308368 397026.153268514,5165076.32148286 397524.818123527,5165067.79049237 398121.172223473,5165059.66575611 398079.094836043,5163519.64134919 398074.045935741,5161865.68223921 398059.997632782,5160238.72242226 398075.949416946,5158601.76287673 398049.901485214,5156996.80243326 398044.852873508,5155360.84277007 398061.802940095,5153673.8844116 397990.753525199,5152039.92440306 397986.706260507,5150439.96320876 397981.694931268,5148843.95455868 397971.683228179,5147199.94555985 397972.671962545,5145598.93676736 397962.660579673,5143995.92785993 397947.649143106,5142391.91887313 397932.637595763,5140770.90973277 397907.625956819,5139153.90054444 397871.614199177,5137540.89132351 397847.602616648,5135930.88208476 397841.591240943,5134313.87274973 397844.579951222,5132687.86328606 397831.568827347,5131116.8540907 397799.55716051,5129508.84465574 397772.545330568,5127866.83496574 397769.602433453,5127095.8616232 397766.539781408,5127081.11154329 397761.664540702,5127057.83016732 397741.664049093,5127033.83007812 397721.601028402,5127005.82996553 397703.850524161,5126974.8298291 397690.850103905,5126944.82968593 397670.912112201,5126920.82959777 397657.786647643,5126884.82941976 397649.473768279,5126849.82923463 397645.004726745,5126818.4540605 397643.3483687,5126806.828996 397635.035482062,5126770.82880521 397628.847581176,5126727.82856701 397627.534752913,5126683.82830922 397618.971812944,5126640.82807793 397612.783911683,5126597.82784006 397604.4710243,5126561.82764997 397591.595617786,5126533.82752065 397578.407636095,5126495.82733311 397565.46972113,5126466.82719851 397545.344180905,5126436.82707907 397527.781224448,5126412.82698805 397507.593182574,5126382.82686947 397494.655252618,5126351.82672409 397474.529718163,5126322.82661191 397471.34202389,5126302.60775191 397468.529352856,5126284.82640523 397460.091433225,5126244.8261941 397454.091060634,5126205.82598176 397445.590639645,5126165.82577112 397444.027755832,5126114.82547489 397438.089904983,5126078.82528037 397425.151973375,5126047.82513668 397397.963862016,5126024.82508369 397373.463344054,5126008.82506407 397344.087731071,5125990.82504784 397305.337011941,5125979.82510165 397269.086369297,5125973.82517735 397233.335833894,5125981.82533342 397202.647953329,5125999.82553214 397179.272708267,5126019.82571988 397160.553757661,5126035.20086627 397148.834882151,5126044.82595783 397132.772294143,5126069.82615172 397121.772332701,5126100.82636484 397103.334705913,5126125.82656536 397092.459782577,5126161.82680651 397081.647381872,5126200.82706453 397075.835099479,5126244.82733626 397072.147795239,5126280.82755525 397067.835406618,5126306.42146587 397066.08545198,5126316.82778114 397062.648201959,5126359.82803953 397056.585866089,5126396.82827085 397045.710944138,5126432.82851025 397027.460872742,5126464.82874777 397016.460920688,5126496.82896388 396993.21071066,5126520.82916915 396969.772954926,5126538.82934018 396939.022558013,5126553.8295148 396898.396942019,5126560.82967184 396855.458795444,5126568.82984108 396819.083119819,5126557.82988318 396792.082547279,5126539.82985873 396774.519586055,5126515.82977324 396754.581592814,5126492.82970056 396734.393537423,5126461.82958359 396716.643028971,5126431.82946552 396696.454972903,5126400.82934927 396683.579551284,5126371.82922318 396670.579120159,5126341.82909202 396659.078702435,5126310.297698 396644.515705503,5126274.82879108 396631.390228143,5126238.82862717 396618.389788858,5126207.82849133 396605.264318258,5126172.82833358 396596.701364704,5126129.82811725 396590.826006225,5126093.82793236 396582.263052331,5126050.82771637 396576.075137571,5126007.82749328 396574.949857411,5125971.82729413 396573.637016015,5125927.82705053 396577.261814638,5125891.82683664 396595.511885163,5125859.8265997 396606.574358413,5125830.8264017 396629.824563343,5125805.82618797 396647.319162537,5125787.41633249 396496.946542206,5125694.16972709 396265.286206196,5125662.98278777 396160.816273646,5125738.57728593 396134.753495823,5125759.67123408 396052.504443825,5125823.62741535 396003.377069077,5125861.82845485 395945.971110523,5126029.07954184 395968.784521861,5126100.82986161 396043.817816002,5126209.1427239 396069.754253405,5126270.44142693 396082.850393495,5126301.39311046 396095.748378117,5126315.60244372 396095.756961454,5126315.61189973 396148.758271506,5126374.73706626 396293.917828993,5126499.7373284 396410.233127903,5126621.23766537 396495.391869976,5126771.61326048 396477.236287709,5126903.7390479 396447.01740699,5126953.27065725 396386.798790024,5127105.33416577 396321.236427432,5127269.05399634 396229.298063942,5127353.99220683 396131.015871768,5127441.55544318 396115.829386175,5127462.17909169 396115.828279149,5127462.18059506 396066.015476462,5127529.80609163 395983.734586901,5127756.49502677 395923.733826088,5127783.74532406 395777.326113984,5127902.27757212 395777.308245804,5127902.29204828 395726.294356848,5127943.62166756 395549.292459624,5128067.5602533 395353.352636097,5128173.62377797 395211.19494155,5128281.09341984 395079.411735468,5128299.68757608 394960.878470623,5128283.28152324 394781.906211452,5128198.87527613 394617.215350449,5128105.37520948 394538.216159199,5128051.72570248 394430.805121636,5127978.78129481 394333.866057581,5127977.43777842 394248.209101525,5128061.40714611 394197.834475444,5128209.75173291 394146.054233813,5128439.94045916 394112.617113715,5128554.12858191 394090.929403945,5128570.94121182 394060.054237649,5128611.37897475 393913.240703544,5128772.19256588 393830.17833932,5128951.81859017 393716.803734575,5129221.19508348 393649.741102212,5129334.41449471 393593.271673627,5129359.63347651 393541.208155385,5129334.6334693 393522.332596165,5129302.28961079 393502.519354101,5129249.38316098 393485.268439118,5129170.44533793 393460.892125407,5129056.50737175 393434.734730461,5128966.81952098 393406.827666262,5128921.06937453 393281.887002488,5128775.88149651 393162.478318341,5128709.72521971 393074.570595567,5128699.94412585 392948.131162291,5128708.25694998 392938.886078307,5128717.09598999 392938.881089356,5128717.10075982 392869.349294331,5128783.78870889 392856.131338188,5128904.03926276 392869.788619186,5129001.85215899 392921.040097872,5129082.50864999 392939.594223998,5129096.3771071 392939.603005278,5129096.38367075 393010.885818893,5129149.72750229 393111.387893415,5129209.66505377 393203.984079088,5129328.85288977 393215.891632466,5129464.35346913 393173.016630795,5129545.26016531 393150.858439436,5129570.56502282 393036.140792715,5129701.57362622 393002.98422843,5129725.82379725 392941.396243187,5129736.47843803 392903.451574447,5129743.04281602 392753.699271544,5129746.01187008 392503.539385536,5129775.94998378 392399.632345048,5129873.1693424 392239.412465554,5130032.26405602 392210.100676357,5130168.70217224 392213.070651679,5130306.92148529 392219.540503596,5130424.39070673 392209.916467398,5130554.61000795 392149.072499686,5130638.14170229 392048.790525459,5130732.51725212 391875.069984154,5130832.39293655 391663.504815478,5130896.51853027 391580.222853181,5130960.33141186 391436.940407299,5131072.70707042 391358.345878462,5131119.9261223 391358.337790057,5131119.93098495 391332.095618879,5131135.70747265 391169.843461014,5131170.05160012 391090.329432917,5131198.60780057 391090.311258207,5131198.61432773 391004.028975747,5131229.58332307 390870.621635629,5131333.89640539 390701.182026774,5131384.3968375 390459.210143678,5131442.20989569 390404.616155957,5131506.96020143 390404.773253846,5131600.33552766 390419.305721358,5131710.67964326 390412.243757333,5131781.58615058 390338.024937405,5131896.52414872 390204.523538589,5131962.2745484 390046.80271229,5131993.02485559 389913.988072682,5131976.18122009 389735.78932966,5131895.87789917 389735.42215901,5131895.71243772 389716.515360771,5131867.05611908 389571.981062729,5131772.08725552 389506.51136487,5131775.83735682 389479.604770387,5131782.21241387 389234.03940457,5131869.58802097 389096.006383826,5131901.213303 388922.035336683,5131933.83863323 388773.189300139,5131927.77631271 388634.030436623,5131872.40133634 388526.340893101,5131827.68260284 388437.463981855,5131767.6200527 388351.21178844,5131674.49490861 388256.834163314,5131549.83844281 388149.08215691,5131510.58849153 388127.769379886,5131515.21353581 388127.399562769,5131515.29264081 388069.331118797,5131527.71365645 388022.768344655,5131571.80759559 387956.643615577,5131701.96429489 387902.206568144,5131832.24597249 387809.018355722,5131902.40253741 387683.516554347,5131910.62147954 387590.171097294,5131879.4340258 387503.856283962,5131776.34013029 387426.478629891,5131625.71485673 387356.320156636,5131508.18341269 387263.786609173,5131417.74582555 387182.780887846,5131291.45026806 387182.409113164,5131290.87063628 387177.44021241,5131283.30812538 387127.000702834,5131158.62039828 387071.99810947,5130982.80755732 387039.590880763,5130934.40124346 386913.932180852,5130881.58882868 386890.025426821,5130867.80758648 386778.398073713,5130803.74512643 386670.708572628,5130768.96398226 386582.706761838,5130723.37028123 386497.674054816,5130708.37039707 386497.663885286,5130708.36860975 386492.517716472,5130707.46415414 386475.986184474,5130704.68292709 386341.452834485,5130701.27690786 386253.63935409,5130737.27714263 386147.951236715,5130835.27754052 386056.543827963,5130858.77774916 385983.85493916,5130831.99656867 385948.760142974,5130782.65277654 385908.258559579,5130689.3714036 385903.444393696,5130535.05859079 385896.787461117,5130478.83973587 385888.9116599,5130412.96461326 385852.847603138,5130316.15198014 385777.314182535,5130219.30817553 385722.469283381,5130190.43322317 385648.123974982,5130151.37078959 385475.682733631,5130049.2459285 385294.460745839,5130009.18371524 385092.770554928,5130051.68420095 384884.862006922,5130139.96602552 384880.021818156,5130140.61623874 384702.015678741,5130164.52893091 384570.919338906,5130112.6541042 384489.198661461,5130051.27916677 384432.354144517,5130014.24695822 384365.384582075,5129979.05834044 384256.071374883,5129978.46283999 384095.632846489,5129978.49152223 383967.631733082,5129951.80193996 383901.537153416,5129914.83208574 383870.442760021,5129874.39403732 383834.973140548,5129815.95589644 383818.316026528,5129747.01804328 383817.347899687,5129745.05059834 383817.347248667,5129745.04927532 383794.44034032,5129698.54885066 383712.031781964,5129536.95358107 383616.686453127,5129449.63944961 383467.309981205,5129404.13700936 383343.559376889,5129422.29130741 383185.264346579,5129474.58983867 383172.933891244,5129478.66365389 382432.112672226,5129129.30767849 382050.545617803,5128946.48889483 381930.669198259,5128890.45567463 381813.761564185,5128836.01625451 381555.44536519,5128886.57970874 381368.697109312,5128923.13427606 381021.946477756,5129068.91016897 380846.041160551,5129252.40756313 380614.072408873,5129385.43525726 380507.415444003,5129383.96480723 380366.976564238,5129343.80628053 380170.662848542,5129349.99066149 380077.944277665,5129418.39550277 380040.790213423,5129629.4263673 379955.47919401,5129806.17517836 379954.121354302,5129807.34346081 379915.854329741,5129840.26832905 379915.841474504,5129840.2793996 379794.292249493,5129944.95398924 379279.665993473,5130123.85218926 378897.416206212,5130353.6275367 378366.6809587,5130916.98226256 378366.669410609,5130916.9945204 378237.170204929,5131054.46130696 377947.108891135,5131310.67560811 377506.601105877,5131497.25225083 377506.577075931,5131497.26242869 377469.077028666,5131513.13683829 377272.357976651,5131591.66498638 377034.074980805,5131570.78614464 376768.355508367,5131649.93818213 376762.104174374,5131658.76955849 376695.137538811,5131753.37457609 376657.888268789,5131833.68653146 376593.7950704,5131913.02930396 376523.576565284,5131969.90321229 376404.419467585,5131961.21379023 376265.792989486,5131910.33652847 376138.384541883,5131794.20940704 376002.693305361,5131555.42582811 375983.661649708,5131533.08106143 375893.25356053,5131426.92399242 375744.783231971,5131374.14032947 375599.438955512,5131406.57551903 375531.627207405,5131503.76198948 375519.971366165,5131543.44932595 375519.969779084,5131543.45472667 375497.784644065,5131618.94901437 375472.066917037,5131716.38615851 375393.12918816,5131738.35365392 375292.127979765,5131691.28950564 375215.439271748,5131631.81949125 375151.469708879,5131598.25594608 375151.466609136,5131598.2543156 375141.2508288,5131592.88077914 375081.032066892,5131623.00482986 375032.908051499,5131728.37911571 374983.628283286,5131874.87840432 374901.879817448,5132042.06468055 374671.819852731,5132365.71739828 374385.573430713,5132800.46300037 374334.449073106,5132878.08721254 374251.043722939,5132992.52342011 374211.887897763,5133046.36656284 374110.638995748,5133185.33374073 374110.628800055,5133185.34772794 374100.639104321,5133199.05233533 374058.889312703,5133236.48917747 374004.170838717,5133285.73831497 373785.326565466,5133350.95355605 373598.668780583,5133318.79427626 373493.324466251,5133324.98007656 373445.043516532,5133372.69806519 373307.606872866,5133508.38339578 372977.297673735,5133932.09695315 372790.173713299,5134104.59397872 372790.170162929,5134104.59724814 372775.955042474,5134117.68750249 372616.612187284,5134264.74746524 372415.738702513,5134480.15052 372296.050727994,5134498.89858207 372182.611876215,5134445.24047566 372110.235077686,5134337.05177184 372038.734154073,5134297.76935155 371981.640729843,5134350.42468931 371910.20526255,5134544.45482948 371871.615119463,5134847.01677682 371871.613784306,5134847.02728489 371870.177754423,5134858.32925617 371825.681054914,5135139.17234848 371732.870849389,5135362.63963708 371632.871459507,5135456.4505272 371498.902091211,5135469.07334565 371358.618872436,5135378.66479156 371231.74097487,5135209.69394335 371179.165366849,5134977.74499291 371171.737240818,5134944.97416816 371149.550387032,5134864.23037611 371149.54857798,5134864.22379249 371102.921133998,5134694.62925355 371045.605330146,5134462.97203032 370950.884457963,5134341.37672201 370801.727018197,5134318.18680016 370567.694307639,5134313.58925654 370355.194118364,5134397.67957449 370170.318219683,5134413.73907981 370049.723713777,5134411.08087486 369743.345798776,5134327.79465235 369517.516662406,5134301.45274707 369360.186666137,5134283.1009439 369208.373999229,5134340.25473874 368975.278848685,5134340.25096428 368826.122522064,5134402.81105038 368532.309491415,5134496.65004185 368175.933545762,5134586.92551616 368028.589043977,5134596.79812841 367916.025289972,5134552.98380722 367905.228118526,5134542.16171798 367821.367215384,5134458.10728 367710.61665657,5134466.16798652 367475.710658418,5134591.3204227 367345.462794344,5134810.38079058 367239.401311117,5134934.12905694 367239.398405859,5134934.1324489 367221.307735114,5134955.25376096 367124.0914264,5135181.47090497 367082.156269516,5135375.50144765 366884.034768684,5135724.18567314 366793.943845536,5135974.49666413 366778.853974814,5136270.5276158 366807.978677004,5136463.10776126 366809.450611755,5136472.84057867 366824.57760034,5136614.80954984 366821.144583642,5136950.93443061 366845.334161347,5137095.80979895 366875.554018653,5137165.74778068 366875.804959058,5137235.8727713 366886.212501567,5137328.0291741 366923.08862478,5137396.46726575 366947.058138981,5137443.53015 366943.46508978,5137497.40508064 366978.653845522,5137576.56189309 367025.780404329,5137673.46889857 367073.093865672,5137725.68841608 367104.875728692,5137758.34518228 367121.626369416,5137799.34544999 367102.002053342,5137858.68886621 367050.877367345,5137903.3755169 366984.940474588,5137976.06191797 366918.191126759,5138052.34205411 366879.389001928,5138103.86746532 366856.816879829,5138133.84102677 366808.567344957,5138188.37147059 366781.879859463,5138200.4022785 366723.879623085,5138206.55757204 366647.597692618,5138187.11882044 366589.003223451,5138157.58661265 366536.397323923,5138113.34832342 366535.564825097,5138112.64824369 366485.313702831,5138049.80368183 366453.312870236,5138001.05316715 366416.593619779,5137978.95881858 366416.587707755,5137978.95525782 366386.499459196,5137960.83332812 366339.185982065,5137907.73881331 366288.122364621,5137845.83173942 366216.683841031,5137799.36182728 366108.557463946,5137741.9225659 366029.025822986,5137745.79625858 365970.026257097,5137802.23277408 365930.277242936,5137891.48209619 365920.371655258,5137944.51316849 365932.841234391,5138000.70085767 365960.811103591,5138072.01379758 365972.686771742,5138116.57648041 365972.687422175,5138116.57892797 365975.061905694,5138125.51401698 365972.469001608,5138189.13895637 365940.282070582,5138244.32591086 365898.688475529,5138272.70021792 365827.313242323,5138284.48028935 365732.281270375,5138269.79122924 365647.405031084,5138212.88359962 365569.934628535,5138122.63235302 365567.655039181,5138116.57448271 365567.653283612,5138116.56981739 365527.901621939,5138010.41294692 365499.08722652,5137882.66251335 365474.398328754,5137789.91213682 365400.896571652,5137690.84846121 365376.365258986,5137684.03591527 365333.990003365,5137661.53583604 365283.864981056,5137655.28574247 365239.771714256,5137686.41065965 365197.397982532,5137774.94182825 365179.555719593,5137881.72304155 365166.307346518,5137999.16051247 365161.902624819,5138110.22299993 365160.902713005,5138116.56674776 365160.902198506,5138116.57001858 365149.778695896,5138187.28547338 365117.904723126,5138259.47290813 365048.404931382,5138268.69152207 364993.341983506,5138231.22266712 364917.278734731,5138169.87877381 364875.965555283,5138116.56689138 364867.996674336,5138106.28493355 364801.183660132,5138062.75355874 364798.97112409,5138062.28804314 364750.089825187,5138052.00346172 364711.183923816,5138074.09713491 364666.187346678,5138118.2502155 364662.872128751,5138121.50328703 364641.967104594,5138209.56573682 364635.062474466,5138327.78445968 364649.313931514,5138435.87822487 364689.065706344,5138569.37828793 364696.285289058,5138631.03454516 364658.223828381,5138704.12821014 364605.78730269,5138771.34684599 364544.225664251,5138829.62796356 364490.91345493,5138846.69035307 364423.038507611,5138845.0964658 364356.851023245,5138840.90883246 364313.007271247,5138837.22124436 364281.069995494,5138851.15867724 364260.289258966,5138887.31487852 364263.47720422,5138920.37737891 364314.665608134,5138991.03372048 364391.104176879,5139075.7213625 364468.574177013,5139173.69025623 364493.012619355,5139244.84654557 364487.076089082,5139315.69027176 364439.077085231,5139385.34640949 364394.734339416,5139455.94005373 364319.141655568,5139528.87738026 364216.486331473,5139589.62715005 364095.080909628,5139641.93937995 363959.643840167,5139663.97033556 363868.425079219,5139656.56389265 363818.924788449,5139631.43879367 363808.392994932,5139590.40753212 363823.485954133,5139532.93882924 363839.172370844,5139453.87638284 363837.827523682,5139372.53265086 363841.545639761,5139325.87642051 363818.638210236,5139236.7826455 363785.481169167,5139175.62634255 363716.855629066,5139130.25121296 363615.824412883,5139124.84475658 363521.76249225,5139160.5008027 363371.857973439,5139277.59420678 363243.796764983,5139363.9689119 363237.626104089,5139370.40515816 363243.364277513,5139737.56253265 363288.385949383,5141356.56204431 363326.407379677,5142957.5615029 363362.428937446,5144568.560907 363393.450473892,5146178.56025039 363423.472146704,5147799.55953667 363462.493638907,5149407.55881229 363508.51540958,5151036.55805747 363525.541458662,5152632.54365357 363546.568453368,5154268.52794437 363567.595379654,5155902.51222113 363588.622172094,5157530.49652267 363626.648776953,5159144.48095067 363644.675349591,5160763.46526335 363661.701697692,5162371.44965229 363685.728248551,5163991.43389613 363709.754736729,5165609.41812413 363291.783016622,5165620.07441053 363315.77770652,5167225.40265729 363337.803609773,5168831.38711532 363364.829545382,5170438.37152247 363394.855248387,5172030.35603161 363427.881124527,5173632.3403966 363454.906150243,5175186.32520418 363467.932862727,5176859.30886258 363504.95904189,5178481.29290082 363550.977890328,5180075.29164102 363580.994093155,5181701.29615338 363611.010184343,5183316.30059055 363641.026261061,5184930.30498119 365281.047940272,5184892.29791889 366907.07038705,5184868.29350236 368514.094609698,5184840.29551664 370108.118282876,5184782.29747898 371712.142246418,5184739.29951398 373341.166495797,5184691.30160356 373382.189451016,5186298.30396487 373391.212936974,5187983.30635824 373441.235923314,5189582.30862248 373500.258375488,5191128.31076725 373541.281566533,5192751.31295644 373588.304614556,5194354.31507048 373653.328067132,5195956.31712917 373679.350870619,5197573.31916324 373718.373690395,5199170.32112234 373765.39676851,5200771.3230325 373810.419975119,5202384.32490804 373864.442539376,5203931.32664582 373465.40057681,5203942.92090823 373500.454499719,5205564.32904337 373528.486156668,5207158.32407421 373555.531914217,5208769.30919172 373587.577486548,5210369.29435633 373634.623218261,5211958.27954698 373683.669690791,5213571.26446363 373729.716095648,5215185.24932957 373769.762010239,5216789.23425526 373804.807979489,5218402.21906225 373825.852371883,5219978.20420591 373804.895460481,5221568.18928244 373851.941887044,5223185.1738895 373909.988276518,5224784.15858966 373945.033749309,5226384.14329541 373981.079382714,5227989.12790541 374019.124894757,5229587.11253092 374045.169847411,5231185.09714693 374094.216351173,5232802.08146562 374128.26138167,5234373.06628169 374141.315162816,5235996.05154401 374166.369620794,5237623.03668185 374208.423516773,5239209.02210155 374251.477236066,5240789.00753324 374283.530978323,5242386.43028713 373681.502561762,5242386.55653017 373719.557267099,5244003.97891204 373769.611971478,5245604.9638833 373819.667365047,5247227.94860987 373878.722823408,5248840.93337997 373941.779351181,5250481.91784665 373992.834567751,5252100.90249579 + + + + 363237.626104089 5125662.98278777441585.913042356 5259195.11379287 + 373992.834567751 5252100.90249579 375578.907291097 5252060.9016806 377183.981372119 5252035.90076999 378770.053836318 5251988.90012694 380424.132814015 5252045.89859687 382036.206902856 5252012.8979458 383378.268520258 5251983.89746 385004.34489571 5252002.89649079 386772.428209329 5252032.89545573 388359.488754287 5251990.89431465 389964.549770751 5251954.89312519 391575.611064042 5251920.89196047 393178.672571485 5251902.89076516 393228.738270271 5253772.88131533 393228.792456634 5255363.87321734 393234.396568643 5255577.49913186 393290.022245729 5255616.371974 393390.058438338 5255644.18441468 393456.779853272 5255644.18446989 393523.470080964 5255646.05951586 393612.378616319 5255608.99727381 393710.566996525 5255520.06029167 393761.41076364 5255461.24811933 393799.504685641 5255421.87334027 393801.348444994 5255419.99835078 393841.473568551 5255376.87359007 393843.129820376 5255374.99860038 393872.227230318 5255341.53053376 393872.254834063 5255341.49878372 393897.254849763 5255312.87393979 393937.723412979 5255260.37422077 393978.628478725 5255178.31214177 394000.095924966 5255115.37495644 394028.845055521 5255056.68775393 394150.002619737 5254954.68830693 394178.156529424 5254854.00129532 394182.905333014 5254813.68898684 394167.965771729 5254770.93918013 394099.587293418 5254748.62675282 394009.927251763 5254741.75174377 393877.07762318 5254723.93926859 393780.791470774 5254692.25187944 393703.692246657 5254621.56469184 393669.876928002 5254578.31489037 393670.062654952 5254526.25264556 393700.781229152 5254485.56535535 393760.812865314 5254427.44065828 393853.751326504 5254348.19106971 393938.597961266 5254334.50365964 393995.006383031 5254332.81618377 394145.355850435 5254326.25375792 394274.486167185 5254332.44126676 394384.022495763 5254354.19119954 394496.36942946 5254317.6914001 394536.806777902 5254266.94164156 394531.897189883 5254175.75455242 394583.272771438 5254133.81725321 394667.119014884 5254110.19237722 394714.55412945 5253986.94293421 394721.021368279 5253935.8181618 394744.520795483 5253892.44335681 394735.643469879 5253835.25610857 394714.858845106 5253761.25643422 394717.749468196 5253733.17612058 394721.13823463 5253700.25670446 394781.639561834 5253669.81934075 394850.141230463 5253640.19447216 394876.479432891 5253639.04667605 394969.176980153 5253635.00699702 394976.271037152 5253635.81949367 395519.510298066 5253611.56960918 395527.698069839 5253610.13211528 395591.795584246 5253645.88197253 395621.11081318 5253691.13179129 395623.173960433 5253707.38172584 395623.176417391 5253707.40122329 395626.206167995 5253731.44412897 395624.42712544 5253796.81886485 395634.993873549 5253906.81842208 395675.779923451 5253998.44306012 395723.252798144 5254063.06781092 395768.693664449 5254108.19264151 395804.538842082 5254108.56764903 395837.383216462 5254089.31773351 395891.728427757 5254069.75532382 395967.856422362 5254069.50534305 396028.203464222 5254095.56775665 396091.7057842 5254090.2552933 396158.018641153 5254025.69305678 396207.143077038 5253954.25583919 396239.860088802 5253867.81867238 396265.140567313 5253817.38136647 396287.703064163 5253791.94396523 396349.451795259 5253686.44436663 396349.452518554 5253686.44313108 396435.981260687 5253538.63241924 396471.021093905 5253535.14250544 396585.330355029 5253523.75747785 396741.052982495 5253460.13270856 396914.055403227 5253336.13314084 397183.096578436 5253318.38319059 397545.171773706 5253275.94581428 397881.089840105 5253237.88341716 398071.64310277 5253157.87611795 398411.165163381 5253015.32152345 398631.698949906 5252845.19695914 399211.553391767 5252512.82267203 399663.185514918 5252316.76194781 399663.18890481 5252316.76047621 399860.037217754 5252231.26058686 400083.512972148 5252184.8230912 400127.578144634 5252211.26051796 400233.550599022 5252199.82299713 400392.403112184 5252270.94779296 400644.262451817 5252429.8224055 400740.299196128 5252477.88478972 400989.095604804 5252627.32196682 401273.410740343 5252782.18896504 401273.424874001 5252782.19666367 401461.623488353 5252884.69648485 402111.037066948 5253242.0084967 402756.197989468 5253528.32078538 402756.232668418 5253528.33619738 402793.32506112 5253544.82077835 402867.907487764 5253578.15366794 403433.110881015 5253830.75824447 404070.552136632 5254094.38338663 404491.656023924 5254280.81508194 404491.669532849 5254280.82106263 404783.560952753 5254410.07122691 405363.374686197 5254661.44665537 405734.208224886 5254827.88450101 406041.500987131 5254961.06164401 406211.470139018 5255034.72431631 406211.538019337 5255034.75373486 407660.240902993 5255662.48321719 407660.246229705 5255662.48552528 409257.927861926 5256354.76517912 409768.695446346 5256576.08211699 409768.735834776 5256576.09961805 410876.518642679 5257056.12235784 412464.215509083 5257744.10071817 412464.225407797 5257744.10500746 413134.450013265 5258034.52484274 413134.466727295 5258034.53208522 414078.413610222 5258443.55154306 415221.098420247 5258938.68567606 415571.629807004 5259102.51900859 415769.741983816 5259195.11379287 416434.655664678 5259066.41721755 417233.950045496 5258911.95358296 417489.386345476 5258862.59051942 418521.576772072 5257884.97093374 418521.591206801 5257884.95726216 418620.339921949 5257791.45653319 418831.135731339 5257384.15777492 418831.142864938 5257384.14399141 419054.28907216 5256952.8940561 419277.644919394 5256325.22223341 419856.168262366 5254699.46313352 419856.169413348 5254699.45989922 419961.504463663 5254403.46415262 420370.297607175 5253877.47685802 420370.308017787 5253877.46346286 420684.45751304 5253473.27560163 420699.582566932 5253465.52549195 420722.613575374 5253443.65040793 420764.831886821 5253403.65025458 420829.73680308 5253321.52519332 420834.64266021 5253306.21276429 420854.485740219 5253272.90031502 420866.891582105 5253252.40034442 420911.702847702 5253185.7753913 420916.608703616 5253170.4004639 420929.139875651 5253160.0879085 420943.95161062 5253126.9005183 420948.92029462 5253121.71300567 420976.294371275 5253075.65058271 420989.130741489 5253056.910871 420989.137780079 5253056.90059542 421006.168577563 5253032.02561281 421021.011645038 5253001.33820388 421045.854749242 5252965.46322743 421050.760526428 5252947.58832284 421095.478050707 5252880.96338574 421190.632859417 5252775.46322344 421240.569406453 5252713.83819618 421287.849247044 5252639.52580995 421318.005367827 5252616.21317859 421315.286159703 5252603.58831637 421350.066321376 5252547.21341889 421382.409098178 5252495.96350618 421384.314008781 5252452.71385708 421391.845169808 5252445.08884084 421391.719840624 5252434.83893032 421396.030730076 5252381.526842 421375.216517007 5252341.1524139 421374.62137633 5252297.90279171 421389.339211332 5252259.71546142 421439.620257473 5252220.90275569 421482.62079669 5252210.08988797 421515.370809449 5252189.33971675 421547.839000509 5252150.77720407 421547.525768606 5252127.96490559 421557.619477922 5252120.15236577 421554.900351987 5252110.08998223 421562.462842742 5252104.90244671 421559.837466754 5252094.77756272 421579.680564474 5252061.40264186 421612.18009031 5252025.40261033 421690.211223396 5251971.02725899 421722.616760143 5251927.4647989 421729.92868152 5251904.46492394 421734.020257746 5251833.27800685 421753.863120106 5251792.34065896 421788.862620665 5251753.71563313 421889.644066225 5251693.90261076 422075.827735249 5251576.96673523 422075.831736897 5251576.96422193 422108.800519537 5251556.276567 422205.645840043 5251504.99070285 422207.113423663 5251504.21352236 422244.926218816 5251488.58827447 422292.238430961 5251448.1506557 422350.049479048 5251363.71333411 422397.70382296 5251271.46369329 422432.732605257 5251169.65177332 422437.887611685 5251126.65211682 422435.792387474 5251081.15255657 422428.885208473 5251056.21535543 422411.540394442 5251033.96573417 422294.688318968 5250847.59360662 422255.654102918 5250779.59461272 422219.55840433 5250741.97031117 422061.99058887 5250679.15993049 422061.990289746 5250679.15981114 422010.145087406 5250658.47312548 421961.424283542 5250626.16139231 421855.856373036 5250525.97581499 421817.417266538 5250501.03890998 421735.883675561 5250481.85237194 421596.130524203 5250476.16627958 421514.722253168 5250467.04214947 421468.689318028 5250444.85528805 421437.437048994 5250394.48102527 421385.401717388 5250301.16982975 421335.678528613 5250195.23371455 421331.737705773 5250093.67212132 421345.735002741 5249999.48529523 421345.537144329 5249912.26386602 421345.22786428 5249775.92471481 421330.504103495 5249628.73861119 421338.875153431 5249499.17714312 421346.218410959 5249478.73975099 421345.591940809 5249433.052648 421357.778483914 5249394.74036538 421359.683396659 5249351.49071882 421369.55787616 5249328.42832716 421388.837111648 5249252.0538087 421423.517340626 5249000.05566585 421452.195427332 5248684.68313187 421461.975917627 5248654.05831132 421524.318507261 5248574.43346162 421551.567482383 5248523.30867083 421555.157836141 5248413.99708926 421539.312288896 5248368.49761892 421513.247526146 5248315.49829921 421511.959865427 5248306.3313929 421507.5586117 5248274.99869791 421494.776839725 5248267.49887062 421340.200046766 5247926.69059106 421332.261646246 5247904.0033505 421282.412996707 5247785.31727213 421271.379475581 5247721.88040245 421269.46880705 5247584.75658579 421247.996825848 5247498.63249077 421244.400567 5247422.57066615 421252.336254887 5247360.19613367 421277.364405893 5247245.38441401 421304.456728695 5247181.44724735 421339.299551238 5247127.63493585 421471.860304437 5246978.44769333 421531.765467603 5246901.51039967 421541.921863026 5246898.82284537 421541.671292921 5246881.07300122 421568.982868386 5246832.4482153 421593.91995487 5246801.57329442 421593.700633866 5246783.7609511 421611.231792789 5246768.32345282 421613.66902469 5246758.13602316 421625.918251708 5246725.01121945 421633.230187974 5246702.011365 421635.604998005 5246694.32391421 421639.93604477 5246678.39095562 421645.322834495 5246658.57415329 421650.29145582 5246650.94918262 421644.821612398 5246620.44948996 421629.007389331 5246577.57498222 421600.161055511 5246517.01322451 421592.253901606 5246494.26348113 421558.751936342 5246456.57655645 421510.09362297 5246426.76467374 421491.873574267 5246399.07754727 421496.34096919 5246353.2654105 421516.309362567 5246327.64048607 421576.496443293 5246270.95303882 421616.746461364 5246242.39049484 421659.746948449 5246226.57782083 421715.435305397 5246213.20253434 421755.779319922 5246192.26492625 421808.372488355 5246135.70254511 421823.215606206 5246104.95270991 421832.77703582 5246064.20300146 421814.086858946 5245993.32876096 421792.834284135 5245927.57949187 421792.671749198 5245729.39374021 421797.327140677 5245698.89397675 421819.764106339 5245665.5816151 421855.170759483 5245652.33148713 421944.047787528 5245651.14338276 421984.517061154 5245637.95572049 422052.078932474 5245568.33087781 422083.297635789 5245543.83088341 422094.860118614 5245534.76838561 422231.393049078 5245487.20538154 422494.835058808 5245435.32906221 422527.553920511 5245414.57903166 422585.115589298 5245345.26678407 422604.927507429 5245311.95445981 422614.582703433 5245271.14227407 422606.017937438 5245205.26794313 422600.673425301 5245184.95566728 422595.548148442 5245179.95574776 422577.171372993 5245137.08126729 422561.639125466 5245116.89405706 422520.6059753 5245087.01960419 422496.489997244 5245048.03760108 422496.479184468 5245048.02012289 422489.416161383 5245036.64527414 422465.600875504 5244965.77108275 422451.848246604 5244892.39684717 422444.003756088 5244874.70956057 422443.659198623 5244849.27229659 422435.720794628 5244826.46005738 422429.843664227 5244763.08567718 422442.249562794 5244742.58578611 422477.625066146 5244732.02315724 422660.347730712 5244719.27210901 422743.942863871 5244700.39675247 422963.69518479 5244608.45872556 423072.791232932 5244599.39562315 423110.854537993 5244596.33291229 423143.604744552 5244578.08288079 423166.198307476 5244554.89546129 423245.539479632 5244411.58384623 423315.663827504 5244337.02163418 423388.726692196 5244292.83411446 423573.57349836 5244249.58340654 423702.951124235 5244211.9160219 423738.013431865 5244201.70787795 423803.889657037 5244190.5825884 423854.7032688 5244187.39481166 423905.611101011 5244199.39438211 423944.175441444 5244229.33134657 423957.145196942 5244251.95603977 423970.647234945 5244307.70539568 423968.961654285 5244371.32976515 423956.461831138 5244386.70468763 423959.21228526 5244399.32954351 423946.649802952 5244409.57951822 423946.869106871 5244427.39183766 423975.151799351 5244452.45390945 424018.528200691 5244464.57851692 424066.779324932 5244463.95322252 424112.279913318 5244448.01560082 424152.404835283 5244414.51569212 424167.153929631 5244373.64101704 424163.056649859 5244261.89218054 424195.368266019 5244208.08003203 424255.74343179 5244166.64258895 424356.681736983 5244114.45501461 424416.837842521 5244062.89268459 424421.524595356 5244034.83044647 424449.05641287 5244031.89281265 424519.086735325 5243982.76546948 424587.461809958 5243966.63786594 424650.273090999 5243910.07338602 424723.272104283 5243858.32094554 424773.928287044 5243842.44405399 424811.677647115 5243811.50533222 424927.488323561 5243721.18903625 424937.268631943 5243688.06396576 424954.736658528 5243659.93853504 424974.109535597 5243586.00097629 424975.857432102 5243517.43907775 424985.79453947 5243502.06382617 424998.231354667 5243476.56357253 425048.85636252 5243463.24915306 425127.701049451 5243472.43337074 425229.201617576 5243463.61684715 425303.545163236 5243437.11409532 425303.549402951 5243437.11258231 425317.732624008 5243432.05107015 425378.357317052 5243405.9238695 425403.270589048 5243382.7576384 425403.294305405 5243382.73558515 425406.013000479 5243380.23549935 425463.136866116 5243328.35868973 425462.480264155 5243317.17132501 425460.792492731 5243308.85897413 425455.948497517 5243302.23423474 425447.948330789 5243298.98459044 425433.698218927 5243299.17266596 425417.541907133 5243301.48579805 425397.916946351 5243307.98652995 425372.697715243 5243299.17513742 425355.634743497 5243288.48843276 425343.821153443 5243256.42672351 425345.507970825 5243233.92687414 425359.506696935 5243189.05174343 425375.537302995 5243163.98883738 425400.474334798 5243142.23803789 425418.38050765 5243134.98738237 425447.099902502 5243148.17358989 425447.288209402 5243174.17332972 425462.758500157 5243219.79725953 425479.946995741 5243247.3587953 425506.354472486 5243279.91990916 425551.353092976 5243223.41863382 425560.165621094 5243221.98079062 425563.165913152 5243230.60558541 425565.041097145 5243236.04295671 425567.791365844 5243243.98026831 425570.51055476 5243257.41752786 425573.260993946 5243270.85478616 425578.761759986 5243294.10433792 425588.762423759 5243312.85375104 425604.075602435 5243330.66545811 425621.201379501 5243351.16456581 425642.827135771 5243369.78850955 425669.796296844 5243375.84985863 425674.858885241 5243377.34963909 425674.934197452 5243377.3720909 425702.109362684 5243385.47345691 425719.078194943 5243383.59778787 425737.890648983 5243377.09708887 425740.010214788 5243376.08200283 425740.109384381 5243376.03450929 425761.078005389 5243366.28375434 425789.608818469 5243344.59530833 425809.233420225 5243326.53218786 425816.420044734 5243296.40718753 426022.641687027 5243334.64846594 426081.079571282 5243331.45862981 426093.704510585 5243326.14566952 426234.451831359 5243202.57865267 426287.545445784 5243184.13917769 426328.358659772 5243196.2624079 426417.171624064 5243187.63389151 426447.264740691 5243159.32044218 426501.824110273 5243044.3818262 426523.822067562 5242973.00661389 426573.256469659 5242860.56817836 426566.505935163 5242845.19359849 426561.84949313 5242840.25633441 426541.161697012 5242836.19471257 426506.16099743 5242822.94625908 426475.597836297 5242809.76012506 426445.065699758 5242789.32405904 426410.783342017 5242762.76320388 426390.126228305 5242740.45175531 426380.937483647 5242702.88998672 426397.812090207 5242685.82696422 426417.436826176 5242672.20129717 426441.593045662 5242664.88788584 426469.34307169 5242658.44932016 426505.249829028 5242665.32279647 426546.53168879 5242674.07103677 426594.938630275 5242683.56898076 426637.970333149 5242686.81720254 426676.283491168 5242697.87804186 426692.813726213 5242661.00272043 426732.687135307 5242599.56418343 426767.090643263 5242502.68870327 426766.370063986 5242444.2517858 426737.743017776 5242386.12849988 426704.430449989 5242392.62979268 426685.680638845 5242403.56795129 426673.243710305 5242425.13075245 426662.68210293 5242456.5058842 426653.807730458 5242478.94353205 426640.558491852 5242506.81880599 426626.277661489 5242524.00672317 426603.058893881 5242529.50761442 426567.932890937 5242506.50926029 426552.525403249 5242470.82272563 426532.586656173 5242436.01136702 426531.554476479 5242406.44919003 426532.209783214 5242376.01195274 426541.959052007 5242350.01180343 426559.70846546 5242326.57380431 426578.426722354 5242305.88573951 426698.018928816 5242225.31913873 426758.705564592 5242181.87958072 426801.611539326 5242161.94052329 426821.54958683 5242174.31459496 426838.704463395 5242125.87685449 426893.765245675 5242056.62526697 426931.421250946 5242039.06139951 426931.434142717 5242039.0553835 426972.139735793 5242020.05992068 427007.608597992 5242014.49602885 427033.328422654 5242042.24472045 427115.299629895 5242099.67834344 427169.14506588 5242139.6757763 427217.614665312 5242154.2986667 427247.770431821 5242131.04765762 427239.581279795 5242080.36096614 427190.422425647 5242009.80112922 427177.202226058 5241966.86457046 427219.669392251 5241905.30091825 427490.136874861 5241795.35342681 427512.448034294 5241746.85296971 427507.760063851 5241733.04078954 427507.759671562 5241733.03963564 427501.853222022 5241715.66619228 427483.663894005 5241661.97993435 427478.163338843 5241645.66781074 427480.631867742 5241637.98028176 427482.693269968 5241602.41802925 427563.09782598 5241527.85294411 427643.815676353 5241478.60010886 427747.346199541 5241429.09634358 427792.783324321 5241405.59470699 427815.658418391 5241402.78129942 427818.878061245 5241430.4059122 427805.691923493 5241477.15601728 427810.349081718 5241504.90557021 427823.006131273 5241527.15484779 427853.632211953 5241553.77835203 427875.100874598 5241545.52755272 427894.693937325 5241518.65200213 427931.098640841 5241460.15105773 427984.095254346 5241338.90001456 427967.063393539 5241323.77584948 427909.719454053 5241332.27811207 427881.9693509 5241336.02921031 427856.87540505 5241336.15523362 427837.531114493 5241323.8436373 427806.623272624 5241280.97029621 427798.40278573 5241227.72112499 427827.806545662 5241140.97072671 427912.239736362 5240982.4687407 427931.769059366 5240916.2185537 427967.487252672 5240889.52983904 427995.612847748 5240901.4035792 428012.488644879 5240922.52769432 428031.333942422 5240967.02651368 428039.459680497 5240988.46348396 428060.336104983 5241028.52476154 428081.80502093 5241028.39888512 428118.523800084 5241020.08496068 428120.147969765 5240993.27264091 428118.209497271 5240962.83550012 428113.489469795 5240923.39855585 428097.081744029 5240880.5871207 428092.424386219 5240846.52512457 428097.704233305 5240800.58783112 428125.672611899 5240781.77435971 428184.549253219 5240819.20910681 428236.333450341 5240899.89374799 428269.99163211 5240952.82938605 428343.930485838 5240977.26363916 428504.0568526 5240980.44456402 428567.432091882 5240972.12954915 428655.649986489 5240922.87639123 428655.651697681 5240922.87543563 428688.555916929 5240904.50021297 428723.554659362 5240855.87422389 428712.615154558 5240795.0627241 428673.236494842 5240688.87780087 428690.485102474 5240640.44003526 428675.358599653 5240596.56605342 428657.107577197 5240568.69205421 428651.169687618 5240557.81739627 428651.160664338 5240557.80093873 428644.41924635 5240545.5052847 428623.668155315 5240516.0689024 428613.667428521 5240495.50699915 428602.760277172 5240469.63268145 428613.352949152 5240432.82008249 428632.946483765 5240421.13188599 428649.461729364 5240419.69512131 428649.477817678 5240419.69372169 428667.009157433 5240418.19301698 428693.853194224 5240420.6293949 428727.072282869 5240423.12801109 428760.134723848 5240413.06424771 428787.790365439 5240386.93835144 428783.227121532 5240364.50124191 428769.601255609 5240340.43951859 428717.066414307 5240239.63008705 428715.566183702 5240232.69271154 428715.562033437 5240232.67315401 428711.534302746 5240213.69304935 428720.252020059 5240178.81800834 428733.65803114 5240167.94255714 428756.001637324 5240157.87923191 428873.314854283 5240151.68697586 428889.533813333 5240154.31128684 428904.003803169 5240189.99787059 428890.004641763 5240219.99817334 428889.997553997 5240220.01339022 428826.133473843 5240357.12455032 428814.633920726 5240374.12486755 428813.85340258 5240397.49968768 428821.166689827 5240420.62417844 428821.323734269 5240445.7489443 428808.824202717 5240463.68679377 428797.262182377 5240481.74960362 428790.294168904 5240506.81216173 428785.919902026 5240531.12462036 428788.764605456 5240560.62423626 428799.297372305 5240606.06089284 428829.922839666 5240613.24707387 428910.766150719 5240579.24407202 428965.98346615 5240520.11734574 428995.512532296 5240443.67932694 429018.412369999 5240235.11777138 429017.568253364 5240210.75486928 429017.567843021 5240210.74302597 429015.033679321 5240119.18145608 429002.40693177 5240066.99494499 428980.186843911 5240030.12118959 428963.061005979 5240007.80959388 428932.498020183 5239999.93591942 428898.466516229 5240000.24981342 428866.279027279 5240008.50105994 428839.403909706 5240011.37713698 428812.528794088 5240014.31571345 428782.903146086 5240001.06704946 428772.027527097 5239984.13014935 428769.183050688 5239961.81796831 428787.93256643 5239941.87987918 428810.213418579 5239923.81662794 428852.213254071 5239908.31504367 428880.806625119 5239889.31404135 428918.306174644 5239865.87521318 428946.02464913 5239850.37421478 428963.89966876 5239846.62351449 428988.087549267 5239852.74746581 429009.619129659 5239857.93403474 429038.338239975 5239862.30781587 429067.869285496 5239848.61922639 429082.02488005 5239824.43136283 429092.711921048 5239807.30607803 429113.149653999 5239809.68021716 429135.868729714 5239814.42924124 429155.213141218 5239830.61580114 429176.40206056 5239870.30207417 429189.090447692 5239895.23882903 429205.278721611 5239915.73798017 429226.029556688 5239937.04943682 429239.561334774 5239950.42376122 429270.093125982 5239960.04742155 429289.812022869 5239959.85911383 429307.655739024 5239954.42093016 429318.185960559 5239919.35831226 429314.497440658 5239888.04624441 429303.496283107 5239854.17199984 429285.463961808 5239824.73550436 429268.244174647 5239796.17396783 429242.961629583 5239761.42531821 429218.554036165 5239724.92664865 429205.80275119 5239687.42750933 429203.801659862 5239653.42789686 429212.644708541 5239629.11525166 429206.300160118 5239605.42822512 429226.456074569 5239589.9275356 429297.330867545 5239566.17483461 429355.800126289 5239568.04741385 429449.738312711 5239566.91856172 429472.050756455 5239559.73020856 429482.644478939 5239556.2923037 429481.519022639 5239542.16747608 429471.924252162 5239512.29313736 429456.391765878 5239477.04409093 429452.578216649 5239444.85703525 429472.26552096 5239433.91882306 429509.015824461 5239434.60480516 429569.953948181 5239439.53975444 429635.392277044 5239449.84947094 429658.767480121 5239450.59850281 429675.018451436 5239477.28509707 429662.644383491 5239509.66031799 429649.36371348 5239531.1606728 429620.0211097 5239574.41149419 429603.958999517 5239590.59951032 429584.990912165 5239616.10006281 429646.367570047 5239653.47220739 429723.150912821 5239700.78113141 429768.932656751 5239705.216711 429778.495361437 5239709.34128149 429789.339649382 5239723.65320889 429792.15282376 5239744.21541078 429789.622492541 5239773.77775224 429782.623291445 5239800.65280105 429772.061991163 5239841.02787613 429769.625608838 5239876.840158 429775.970203341 5239901.90217487 429794.971026962 5239923.2137056 429812.908888172 5239930.21290716 429842.471412956 5239923.77425089 429913.096007612 5239893.77161789 429931.814444053 5239879.33347736 429933.407380568 5239853.33364222 429929.562292602 5239812.14666484 429918.340670766 5239724.46040224 429912.65153681 5239674.39857929 429902.931945658 5239650.27419233 429935.180327918 5239591.52338711 429973.148951156 5239578.33444311 430011.399714245 5239593.08274051 430068.747601033 5239709.32935724 430104.749154568 5239749.45252428 430125.281040108 5239764.45154868 430178.781839177 5239776.57424458 430204.094282369 5239768.63577498 430251.805343489 5239709.89195168 430251.81153196 5239709.88433218 430279.123172799 5239676.25850589 430295.933210702 5239594.8210309 430272.30593641 5239529.07257987 430247.085395536 5239478.88655797 430247.065130004 5239478.84626715 430220.2709934 5239425.57562951 430224.142785711 5239323.82636509 430242.452446773 5239254.0166138 430242.453204368 5239254.01372529 430243.515585201 5239250.01371672 430307.918014048 5239114.51225511 430345.917967379 5239103.94828284 430509.421577742 5239178.12840114 430513.204927995 5239243.12767728 430514.268204909 5239267.25242264 430514.394006515 5239292.37719784 430518.11363941 5239319.18931041 430527.302092121 5239346.87619038 430541.708992321 5239363.81294971 430556.115635628 5239372.68727956 430581.209769303 5239378.68619498 430607.990648845 5239360.62275108 430628.458752676 5239335.43462885 430622.769726485 5239288.93526851 430624.330668107 5239239.68563383 430636.704479254 5239199.43547551 430720.392427261 5239193.432083 430735.205178018 5239197.74393575 430737.955512096 5239207.55623717 430732.612233708 5239223.61881733 430731.019275082 5239248.80616369 430733.051910451 5239291.74320637 430736.803137519 5239329.30522511 430745.897585315 5239348.99217966 430767.55470928 5239371.1785958 430790.96164739 5239387.11499449 430825.962364775 5239401.17593282 430850.11868049 5239397.42497198 430867.087071903 5239382.11190711 430872.336367945 5239358.79939359 430863.116264319 5239318.61262171 430848.520746561 5239266.73867259 430829.331130686 5239205.05249797 430804.860599863 5239155.11643903 430805.640128327 5239100.99187713 430827.261959432 5238996.55439349 430856.19553098 5238866.61682865 430881.163245 5238828.24113217 430888.412483633 5238802.67855485 430994.004072172 5238709.98750294 431080.160372442 5238691.17161198 431098.035827311 5238701.17078844 431134.099803186 5238738.79397669 431158.165643339 5238837.54213327 431184.762837348 5238938.91516358 431198.76634806 5239045.35116963 431206.924039531 5239088.47546214 431250.675982808 5239138.78572757 431322.302881923 5239181.03241588 431508.086377232 5239206.77454937 431586.649121875 5239195.64641174 431674.77256393 5239126.01837977 431707.302910094 5239090.07984728 431773.397136633 5239089.20213385 431853.899430004 5239141.51087506 431858.115192378 5239144.50846021 431858.118308525 5239144.51067592 431925.122044907 5239244.9445654 431971.123111785 5239267.19248425 432081.75283505 5239387.8119124 432115.536372922 5239450.93498927 432187.66442913 5239528.7438672 432231.541792749 5239591.74153242 432285.105257091 5239608.86418795 432358.950122511 5239625.79851256 432384.544386038 5239635.60987891 432476.327458173 5239670.16831957 432519.985170762 5239705.10373376 432538.581183597 5239770.91491781 432537.272025559 5239875.03909702 432499.655637394 5239998.33592644 432499.650701986 5239998.35210343 432485.933293273 5240043.35228728 432456.843008563 5240158.10251364 432462.751426357 5240224.03921639 432545.035988315 5240306.91014946 432665.978644202 5240437.52910212 432735.951760437 5240555.96274664 432772.830394313 5240659.7103696 432783.582195138 5240712.95948416 432773.80185245 5240743.52212786 432747.430744904 5240870.83463821 432740.150425606 5240901.5221782 432700.809895495 5241011.21036396 432702.282582003 5241133.0842805 432683.129292311 5241229.77174948 432679.978172552 5241389.89553201 432684.355048866 5241447.08237286 432698.621560686 5241638.26320182 432701.112413624 5241671.64230216 432733.116586203 5241793.20247775 432766.649482272 5241835.88825501 432817.431125492 5241835.32369436 432893.211893738 5241801.32089719 432930.86720768 5241762.81968784 432937.74013186 5241696.69496167 432934.895621542 5241673.82026886 432975.618981181 5241634.19734614 433035.299531864 5241576.12949839 433065.831015856 5241575.75325846 433090.548317766 5241524.69017794 433082.516327646 5241503.75317963 433088.703155593 5241481.37811423 433077.638806391 5241426.81651988 433064.85609881 5241384.81739093 433052.948370177 5241341.94323378 433035.759609423 5241307.13172477 433023.008469064 5241274.94501313 433002.100439071 5241224.94628289 432984.848976842 5241183.8848292 432973.004039787 5241150.01059518 432948.533713887 5241107.199451 432929.689295617 5241091.13785405 432912.595155358 5241083.26361733 432892.157383533 5241079.88947947 432886.280046016 5241008.82781364 432878.592327649 5241003.95316819 432908.873317092 5240988.38956232 432990.186678174 5240995.01118797 433125.470673771 5241046.69273617 433202.41072646 5241106.75159756 433240.598761453 5241113.87498056 433276.00495307 5241103.3111239 433306.191943067 5241080.06008524 433315.721542831 5241026.62263938 433279.719955761 5240986.37444233 433233.624954605 5240959.00155092 433215.624161483 5240938.87745283 433207.497706383 5240895.8156422 433217.403375183 5240875.37790742 433237.433954787 5240849.68980265 433270.152296439 5240829.00113802 433473.153172742 5240806.24303517 433486.926229535 5240806.70438945 433640.87343626 5240811.86113884 433657.21633902 5240781.67321963 433662.496730744 5240753.86073263 433659.526597813 5240711.86119926 433670.150897073 5240687.61096449 433717.651350201 5240689.98400406 433749.152401172 5240714.73251384 433767.184370929 5240732.54413103 433770.87227664 5240744.16888502 433780.873280974 5240772.73074225 433783.030159372 5240791.60549936 433787.468880752 5240828.23001772 433788.595162866 5240867.54214931 433788.689670627 5240890.91695373 433777.253065306 5240921.3546709 433773.879200159 5240957.22951423 433771.317637024 5240986.79187616 433771.694554536 5241045.91637549 433768.320658869 5241080.85372631 433776.540284025 5241105.8531858 433789.260495716 5241147.85232229 433806.417399061 5241163.78899188 433828.855250641 5241169.10053339 433860.011363253 5241157.16186084 433886.292540027 5241148.41086085 433896.979315517 5241123.41062978 433903.134598141 5241092.03563562 433935.976173921 5241016.84741113 433945.630440891 5240953.28503696 433961.503825146 5240899.53482843 433965.7832798 5240843.09761488 433974.594196579 5240792.0976717 433976.03087931 5240766.53532179 433977.09276369 5240747.28543562 433970.685162101 5240707.16102505 433971.496766906 5240679.348719 433983.996025023 5240653.41092003 434015.214438556 5240635.40979117 434043.902248747 5240637.97109793 434075.277785002 5240646.84474346 434112.09118276 5240665.53058703 434148.905043138 5240698.46631491 434180.906698373 5240741.65215643 434195.719971089 5240761.8388873 434211.971868986 5240816.3377807 434220.19193392 5240854.83713223 434222.067557409 5240873.5869033 434241.006222484 5240904.83587636 434252.881785709 5240919.27277439 434298.412807851 5240901.0835637 434323.380344057 5240857.58289734 434388.252207605 5240745.14365928 434428.563939087 5240711.64228378 434598.533568062 5240697.19795746 434621.345994915 5240689.38458853 434636.37661395 5240666.32166018 434641.000410428 5240628.19677809 434630.687253396 5240610.50984184 434559.24830167 5240583.26298071 434541.028096777 5240542.95155038 434553.558695938 5240519.88872408 434596.589940439 5240509.26205056 434795.029932381 5240537.62871093 434833.123973468 5240537.31465642 434839.40907487 5240654.06346419 434822.474092101 5240735.50100316 434765.007717438 5240822.50265152 434684.164755862 5240866.50559792 434494.102128314 5240909.13801159 434456.290411626 5240942.5142849 434404.325310105 5241067.57789284 434372.140203973 5241149.20354399 434372.51627875 5241182.20326118 434387.891974371 5241199.82749155 434517.549547792 5241208.57213582 434540.330645197 5241198.25879058 434583.205149595 5241172.44475129 434661.54834205 5241136.0043512 434841.078404615 5241055.37267875 434894.046485081 5241021.80828753 434932.171858896 5241023.93171551 434955.423032129 5241054.24302467 434951.238314312 5241140.68000359 434936.333023844 5241173.805346 434822.677966645 5241238.43445985 434759.459640864 5241267.06180588 434752.085328024 5241289.99942189 434821.055931976 5241329.93379125 434958.401236139 5241343.74058618 434981.182331396 5241333.36474135 435027.739890408 5241170.2391488 435049.674745139 5241083.67644605 435074.406137693 5241052.36388019 435102.297994234 5241017.04983175 435147.797597646 5240993.73566177 435208.672816838 5240985.54574391 435297.673829562 5240994.79204024 435348.580798414 5241004.3523881 435427.237401503 5240995.911747 435459.73607311 5240947.28580622 435461.577682184 5240881.2862531 435417.605940684 5240800.4136875 435360.978188456 5240729.91655763 435335.070249373 5240684.48047569 435308.879979266 5240605.98216783 435318.252560504 5240529.60739034 435327.970144866 5240491.54479481 435357.874794744 5240435.29401785 435416.061988824 5240411.85432427 435672.595260259 5240411.71883674 435733.783971351 5240433.96616044 435754.472706267 5240466.71505769 435761.322074096 5240636.77594295 435792.229890398 5240677.14936381 435830.700095411 5240712.27251749 435848.575562725 5240722.20920977 435868.482063045 5240725.02087502 435932.514118905 5240734.08068995 435986.07760781 5240751.265869 436077.421720139 5240740.1372271 436110.045804047 5240704.26117487 436119.763381843 5240666.13607507 436098.322137513 5240557.07530029 436002.126920508 5240344.76838717 435919.183471615 5240183.08554247 435900.430334234 5240091.77452353 435909.802908791 5240015.462236 435932.364580498 5239984.77405167 435998.239740005 5239973.89643851 436130.522482608 5239987.82841245 436216.866962218 5239989.44986387 436282.491116767 5239948.00999744 436310.13607359 5239900.15144092 436310.146012239 5239900.13423528 436314.927028895 5239891.88410326 436308.422644324 5239759.82289152 436261.512212425 5239643.51321499 436337.10443938 5239579.19811188 436537.229423017 5239531.37777043 436583.230599633 5239556.31319154 436624.984416431 5239662.56066302 436663.862125178 5239735.74600741 436681.68475947 5239744.44308314 436776.177303905 5239790.55348417 436842.271794076 5239797.36322366 436867.584065984 5239784.42478527 437085.521855142 5239741.54118056 437125.676814098 5239692.85240449 437094.298736023 5239606.85434395 437073.264902961 5239533.41826443 437080.231693169 5239472.29344289 437110.481250245 5239451.72985777 437186.731983737 5239456.03919625 437365.047397084 5239502.40652987 437425.860012499 5239491.5916167 437468.57765199 5239447.9026931 437475.544444263 5239386.96536572 437482.542480397 5239325.84053824 437522.697435373 5239277.21425514 437560.666045375 5239264.08779469 437580.197312131 5239260.02452319 437610.416718976 5239272.83568628 437621.292480367 5239293.33508607 437622.324774962 5239324.70980852 437611.700991516 5239364.02244985 437455.494870464 5239783.27570405 437443.215267497 5239836.08830908 437445.123244434 5239887.96283987 437450.342641733 5239906.3374876 437450.347889116 5239906.35599495 437456.030848428 5239926.39960345 437474.062978259 5239948.7736965 437517.063781731 5239962.89682964 437555.595300937 5239961.89525972 437583.282601181 5239949.26922112 437606.500821088 5239927.70593253 437619.248859425 5239909.45763575 437619.250318217 5239909.45554755 437629.656158395 5239894.58023312 437675.998165075 5239830.82881344 437696.497377478 5239802.14068875 437705.340308494 5239775.26552782 437708.870553345 5239744.01561725 437710.494056127 5239698.32839287 437698.585230546 5239623.20444359 437674.799156616 5239482.83147037 437670.984439789 5239416.6446226 437662.669450621 5239343.27051337 437654.4491004 5239296.77119908 437657.073587843 5239280.64621209 437658.728630001 5239243.70892073 437677.291149487 5239239.95818656 437712.13297461 5239173.58225214 437731.097668167 5239046.45742307 437755.845748605 5238982.64438241 437793.156087948 5238908.64340053 437843.718200552 5238885.20399595 437965.750597553 5238891.5739302 438004.252138613 5238929.19706778 438040.724101232 5239017.75741157 438090.134415949 5239129.0045567 438136.668534147 5239204.75208445 438170.013539817 5239234.87549231 438163.046756841 5239295.87532698 438115.204168358 5239342.12694817 438100.831669138 5239421.00195332 438131.488734614 5239438.43806637 438184.801629892 5239437.87338346 438214.676698245 5239432.93469441 438283.739359472 5239421.61944476 438296.994445698 5239415.5557913 438329.239022643 5239400.80523163 438437.298788852 5239293.11409011 438452.047293976 5239244.61384118 438433.482131179 5239168.67766156 438514.481798405 5239139.79954699 438549.480454447 5239091.17346592 438673.252324028 5238780.04565372 438695.782471667 5238741.67000697 438751.657965869 5238743.66769376 438784.783713906 5238758.54122276 438833.692179504 5238813.91380826 438839.538503137 5238889.9755147 438810.699777323 5239047.78805148 438786.735412326 5239185.28803407 438767.175213891 5239259.10079892 438724.332162124 5239290.10233117 438564.958089619 5239355.233395 438519.928529332 5239416.67229178 438429.524979497 5239519.23774584 438377.589883729 5239603.92675149 438374.590019929 5239608.73933899 438357.561167422 5239685.05197432 438373.187377406 5239717.8635921 438429.344976154 5239745.29858925 438556.440012263 5239754.10581809 438815.34760613 5239733.59536249 438891.316162765 5239709.90492309 438926.220649085 5239648.65393875 438914.559412155 5239501.40548772 438908.525245354 5239415.09386287 438940.741618406 5239336.0931154 438988.835302735 5239322.90373775 439062.711437133 5239339.77558419 439129.589808234 5239425.45972052 439210.252749671 5239607.58009717 439292.22414004 5239667.638805 439376.382288985 5239704.88508916 439465.414627068 5239716.63135797 439513.664902466 5239713.56690371 439536.414736543 5239703.25354585 439593.755440673 5239598.50194687 439638.878740756 5239537.00053739 439674.25358268 5239523.99918029 439705.004656862 5239548.99774147 439830.69699692 5239664.55426803 439885.716561564 5239709.61218704 439956.232664447 5239767.3608965 440088.641011908 5239799.04275131 440139.359885916 5239790.85323295 440189.984756065 5239775.10127166 440487.856115501 5239596.71532639 440538.700415786 5239601.27571161 440577.107973763 5239631.33642834 440610.985784719 5239707.27201084 440651.956115299 5239744.83257141 440690.175582139 5239757.26842014 440718.23854545 5239764.51722091 440761.301026818 5239753.89053208 440824.519400125 5239727.88812473 440924.013321674 5239523.63546545 440986.260127313 5239414.07117183 441003.852972908 5239383.07066466 441036.633871203 5239365.00694531 441173.979066398 5239376.18873734 441291.04337579 5239402.8712553 441354.794450956 5239420.05602454 441392.825726046 5239411.99202088 441440.731307861 5239381.05276855 441491.136818155 5239347.42593154 441493.574229786 5239344.23835334 441493.587389503 5239344.22123925 441508.761182833 5239324.48786526 441518.510056681 5239288.8002086 441571.289899878 5239234.86091105 441581.226790564 5239214.48564198 441585.913042356 5239176.36070888 441579.036780257 5239140.48623483 441575.129828213 5239120.54903067 441546.345628468 5239039.61326235 441530.123504235 5238943.17708428 441511.37028775 5238851.99097485 441507.710331387 5238742.80436791 441501.707377636 5238656.49270168 441493.549271239 5238603.24339929 441476.33205697 5238583.62189494 441476.329728245 5238583.61924102 441458.985180196 5238563.87008886 441429.29631842 5238530.18403958 441396.076642976 5238510.24804221 441332.701606564 5238523.56305899 441281.202243367 5238554.18996856 441206.484416552 5238598.63023806 441057.298043148 5238666.13591042 440786.235695324 5238732.58409754 440656.829091591 5238751.65178565 440587.983901285 5238724.46730539 440544.325799127 5238679.21941592 440515.761043529 5238618.47101433 440479.508738079 5238557.97292788 440452.754029706 5238423.59996689 440496.125317121 5238302.80786469 440509.530410747 5238265.47373108 440546.684033701 5238178.72280403 440535.775152283 5238102.72378253 440465.895558396 5237981.47750861 440440.175602292 5237951.29128005 440424.893899722 5237941.22948069 440345.171513987 5237850.67090272 440336.919410036 5237789.73416911 440356.949868082 5237761.60853853 440384.69947114 5237743.54501877 440476.137710158 5237745.10373216 440613.796650775 5237794.47270553 440687.672693014 5237808.96955544 440763.735481931 5237800.52897406 440788.89097666 5237772.40312995 440810.292601431 5237629.9032299 440819.633772036 5237551.02838808 440871.316520024 5237398.08980561 440940.623532631 5237219.46316716 440970.183512161 5237137.96250331 441047.899395154 5237035.58498744 441135.08212044 5236874.51997715 441192.234670401 5236752.08094346 441214.451439632 5236688.39295611 441221.574781394 5236665.73814057 441285.788072267 5236461.51653938 441289.722091617 5236357.32958354 441261.282853973 5236311.89357319 441220.343959355 5236279.33299498 441062.560589792 5236250.46474664 440986.215969461 5236241.09298271 440924.933185458 5236208.72075081 440741.335777967 5236139.54135676 440715.647163772 5236111.91761485 440723.209458194 5236104.16735379 440672.333934418 5236099.54450094 440641.018489675 5236018.6088612 440630.172535218 5235955.29724899 440644.732999327 5235891.54708265 440669.669049976 5235843.04637898 440644.043191708 5235822.98508389 440658.729086492 5235772.04732342 440662.725529522 5235665.29789207 440623.283412227 5235536.2379243 440584.280417695 5235455.3651075 440575.495354601 5235343.67874378 440625.116849115 5235228.80246467 440702.425348697 5235093.42516809 440714.658382803 5235063.58900382 440714.674431357 5235063.54986167 440722.298861412 5235044.98717064 440724.516683928 5235016.92477053 440706.359116846 5234981.55077171 440642.85860784 5234979.74093689 440546.702907181 5235016.30720196 440484.297972655 5235068.62194755 440484.263266197 5235068.65108297 440405.67463157 5235134.62477446 440365.300209635 5235160.37628181 440324.957127734 5235188.81526885 440284.519951066 5235207.00433058 440208.237848106 5235197.69507939 440159.517234211 5235152.38492862 440161.735149471 5235127.01001267 440187.014841593 5235075.19681752 440187.022127705 5235075.18185581 440213.981925731 5235019.82107614 440306.697122824 5234894.38057269 440379.632892236 5234827.50298701 440470.412787053 5234768.12460166 440533.631107711 5234742.12213731 440571.442747795 5234708.6207866 440680.035343596 5234651.61663597 440747.75181527 5234569.73936387 440772.531006692 5234503.36378106 440718.215156819 5234414.99165994 440669.494548843 5234369.8065099 440572.962490945 5234365.74808085 440395.368248681 5234387.88036666 440258.148422701 5234384.26113899 440207.21024784 5234374.70083887 440158.583734338 5234339.64061923 440122.29985871 5234268.8301315 440119.173049981 5234215.51813306 440090.670904486 5234157.39473195 440074.138911785 5234138.6455555 440057.231910311 5234119.70889619 440001.262363279 5234107.46132857 439930.450422999 5234138.77657961 439849.71068062 5234198.21055297 439849.701854857 5234198.21704977 439695.985829721 5234311.47269851 439632.391316819 5234301.85043114 439591.201679903 5234246.4775473 439577.667707645 5234167.85366846 439576.006009139 5234005.22988334 439578.035745568 5233959.54261979 439546.751743926 5233883.66946714 439535.469896253 5233868.1075504 439520.969136584 5233848.35829837 439369.61973713 5233710.30312965 439200.363211198 5233549.43638284 439160.610433611 5233474.3135878 439153.066707842 5233460.85403865 439083.792839363 5233337.25529365 439056.164919099 5233255.31953942 439041.192180802 5233161.75846476 439086.493357043 5232881.88395102 439135.611899983 5232718.75830086 439126.637497383 5232584.25982799 439087.351361412 5232472.88740837 438992.001659106 5232344.39243787 438968.875465424 5232319.20610378 438833.747659715 5232272.33706153 438805.809995006 5232272.65070901 438735.186365234 5232316.59075578 438697.218125769 5232334.77967178 438581.50288598 5232437.59611368 438548.597067155 5232453.1598485 438515.283108483 5232423.03646631 438507.281591136 5232387.53708028 438580.865386734 5232135.2860753 438638.801335452 5232088.97157379 438762.643389194 5232029.27948903 438818.142025621 5231988.0275591 438848.360110935 5231967.46399434 438875.325116093 5231873.15117868 438873.841266481 5231851.6369036 438873.355169078 5231844.58899715 438869.352748842 5231786.83964154 438848.694907786 5231751.52827589 438696.03694936 5231732.78463683 438675.661519899 5231725.4105251 438647.284570385 5231682.47452698 438638.686987563 5231591.1006173 438672.64951322 5231435.78800661 438720.084119182 5231359.09922028 438780.864757263 5231335.65946491 438821.396122206 5231332.65785774 438913.022363814 5231349.52902715 438978.929458025 5231360.46378004 438984.304531395 5231361.46355502 439114.338608571 5231410.89539182 439185.652136542 5231425.39238962 439248.117312359 5231330.70319233 439257.990989991 5231297.57808319 439275.145003773 5231241.51538211 439297.016099857 5231144.82784887 439305.697711813 5231002.4537472 439260.376607367 5230802.33230114 439216.184637924 5230701.0849359 439225.713398765 5230640.08508735 439245.430025552 5230586.52227234 439441.359505498 5230368.57895915 439466.16989883 5230314.95346074 439468.261750086 5230269.2662857 439438.739566986 5230181.57815323 439434.132329078 5230167.89352542 439425.225553461 5230156.4564756 439408.443325912 5230135.20732065 439382.095837913 5230049.08411184 439406.905915137 5229987.95868446 439500.059319369 5229908.20576649 439625.679705032 5229782.38951951 439670.833827792 5229726.07578102 439678.427328598 5229719.20054957 439731.769341654 5229671.26142325 439731.775551865 5229671.25583629 439776.580378828 5229630.94756117 439951.674516426 5229618.94090755 440225.015363138 5229517.11882869 440336.264049925 5229472.73997381 440452.637757724 5229428.36093118 440523.417927887 5229394.48354551 440543.510915306 5229374.10797608 440619.008348185 5229304.66827219 440653.786417605 5229225.60523348 440688.250898201 5229120.97996977 440778.277048724 5228990.60286 440792.899522296 5228929.47792629 440774.490707801 5228871.16671833 440704.798275231 5228762.73295662 440707.0783475 5228734.73315326 440724.577452884 5228711.73272466 440938.07878393 5228719.59957889 440982.609893299 5228711.41048132 441011.578557547 5228706.22194098 441128.485624857 5228712.59245844 441166.705078667 5228724.90338483 441182.331551983 5228757.71494788 441137.30314561 5228829.34089773 441125.337268149 5228898.02812966 441121.404298563 5229004.71465878 441157.626134058 5229072.96256135 441216.34623029 5229097.83505936 441307.815379263 5229096.76908142 441335.408165425 5229071.08080381 441362.309971006 5228964.08092637 441369.464518175 5228923.45609055 441377.339160205 5228914.20589085 441375.884759661 5228519.21018982 441365.863750525 5227298.78616829 441362.816500156 5226925.22778895 441353.32899797 5226487.98282069 441334.385239866 5225613.43036079 441330.001586979 5225411.68267304 441327.747107756 5225307.24636884 441305.316984763 5224021.76087509 441299.678154161 5223699.26450647 441286.810453585 5222411.9036632 441283.609245141 5222092.28217366 441270.835642402 5220813.67119782 441267.540172935 5220482.29982725 441265.859079109 5219175.40754827 441265.471236449 5218876.31699548 441267.821811269 5217580.29948915 441268.401594674 5217255.3341868 441258.191667242 5216733.34001911 441237.333320755 5215666.35190995 441227.842303915 5215148.2014038 441208.265160845 5214080.36946304 441195.274251281 5213564.59398568 441168.196807764 5212489.38722958 441156.02005255 5212012.08004007 441127.127687256 5210880.40508843 441117.388581936 5210406.78527438 441094.058619425 5209273.42265027 441092.101754418 5208823.73991009 441086.988839287 5207653.43979129 441092.937830809 5207196.00699117 441107.919134768 5206040.4563889 441099.180074391 5205568.61773998 441076.86011304 5204365.48110994 441068.033916685 5203923.5198378 441044.810329775 5202759.50826854 441038.390380076 5202318.23443591 441022.763161913 5201240.53378684 441015.248841091 5200779.38528998 440996.713401008 5199638.56070505 440997.788580086 5199042.66427922 440999.66263242 5198009.587543 440997.677376318 5197479.59631226 440993.611925358 5196381.61446136 440987.346268008 5195878.46659537 440973.561784197 5194770.64128997 440965.045984715 5194262.9622736 440946.511668596 5193160.66818059 440937.027880396 5192677.64501441 440915.462465655 5191580.69461056 440913.290734644 5191084.45276957 440908.411922532 5189960.72122732 440898.739585907 5189444.7298283 440878.361997923 5188359.74790141 440868.844368726 5187794.75728581 440851.311907451 5186754.77454703 440840.168994679 5186181.03408972 440820.262004985 5185156.80111335 440808.556140411 5184569.02963089 440788.211689919 5183546.82785545 440447.274474624 5183551.58421118 439133.213072692 5183569.8587156 437519.214606452 5183597.88873491 435909.216377732 5183632.91857415 434321.217792016 5183656.94819719 432729.219448619 5183687.97779001 431126.220916499 5183713.00771019 429532.222317095 5183736.03751201 427926.224039936 5183768.06739585 426250.225657675 5183796.09869613 424640.227328401 5183826.1287231 423021.215323013 5183838.14759326 421418.182848745 5183803.15020699 419845.153118906 5183829.1516743 418239.122759583 5183856.15320425 416630.092083367 5183876.15490039 415034.06331545 5183946.15575987 413468.035170976 5184019.156598 411927.0077774 5184102.15730687 410320.977603268 5184140.15890349 408731.947575327 5184173.16060055 407127.917199638 5184205.16237558 405509.88661979 5184240.16416644 403893.850467498 5184279.17067505 402376.809351054 5184305.18266293 400767.765827735 5184336.19538155 399155.722151603 5184365.20819777 397568.67961072 5184411.22069788 397484.635123672 5182839.23587902 397438.590081989 5181207.25121208 397410.545932918 5179591.26622548 397351.500174909 5177964.28589945 397292.452470757 5176353.32576343 397156.403121981 5174745.3656852 397136.356979965 5173154.40478628 397080.309523306 5171545.44435402 397070.262855338 5169930.48393691 397074.216493664 5168318.52340502 397059.169441951 5166697.56308368 397026.153268514 5165076.32148286 397524.818123527 5165067.79049237 398121.172223473 5165059.66575611 398079.094836043 5163519.64134919 398074.045935741 5161865.68223921 398059.997632782 5160238.72242226 398075.949416946 5158601.76287673 398049.901485214 5156996.80243326 398044.852873508 5155360.84277007 398061.802940095 5153673.8844116 397990.753525199 5152039.92440306 397986.706260507 5150439.96320876 397981.694931268 5148843.95455868 397971.683228179 5147199.94555985 397972.671962545 5145598.93676736 397962.660579673 5143995.92785993 397947.649143106 5142391.91887313 397932.637595763 5140770.90973277 397907.625956819 5139153.90054444 397871.614199177 5137540.89132351 397847.602616648 5135930.88208476 397841.591240943 5134313.87274973 397844.579951222 5132687.86328606 397831.568827347 5131116.8540907 397799.55716051 5129508.84465574 397772.545330568 5127866.83496574 397769.602433453 5127095.8616232 397766.539781408 5127081.11154329 397761.664540702 5127057.83016732 397741.664049093 5127033.83007812 397721.601028402 5127005.82996553 397703.850524161 5126974.8298291 397690.850103905 5126944.82968593 397670.912112201 5126920.82959777 397657.786647643 5126884.82941976 397649.473768279 5126849.82923463 397645.004726745 5126818.4540605 397643.3483687 5126806.828996 397635.035482062 5126770.82880521 397628.847581176 5126727.82856701 397627.534752913 5126683.82830922 397618.971812944 5126640.82807793 397612.783911683 5126597.82784006 397604.4710243 5126561.82764997 397591.595617786 5126533.82752065 397578.407636095 5126495.82733311 397565.46972113 5126466.82719851 397545.344180905 5126436.82707907 397527.781224448 5126412.82698805 397507.593182574 5126382.82686947 397494.655252618 5126351.82672409 397474.529718163 5126322.82661191 397471.34202389 5126302.60775191 397468.529352856 5126284.82640523 397460.091433225 5126244.8261941 397454.091060634 5126205.82598176 397445.590639645 5126165.82577112 397444.027755832 5126114.82547489 397438.089904983 5126078.82528037 397425.151973375 5126047.82513668 397397.963862016 5126024.82508369 397373.463344054 5126008.82506407 397344.087731071 5125990.82504784 397305.337011941 5125979.82510165 397269.086369297 5125973.82517735 397233.335833894 5125981.82533342 397202.647953329 5125999.82553214 397179.272708267 5126019.82571988 397160.553757661 5126035.20086627 397148.834882151 5126044.82595783 397132.772294143 5126069.82615172 397121.772332701 5126100.82636484 397103.334705913 5126125.82656536 397092.459782577 5126161.82680651 397081.647381872 5126200.82706453 397075.835099479 5126244.82733626 397072.147795239 5126280.82755525 397067.835406618 5126306.42146587 397066.08545198 5126316.82778114 397062.648201959 5126359.82803953 397056.585866089 5126396.82827085 397045.710944138 5126432.82851025 397027.460872742 5126464.82874777 397016.460920688 5126496.82896388 396993.21071066 5126520.82916915 396969.772954926 5126538.82934018 396939.022558013 5126553.8295148 396898.396942019 5126560.82967184 396855.458795444 5126568.82984108 396819.083119819 5126557.82988318 396792.082547279 5126539.82985873 396774.519586055 5126515.82977324 396754.581592814 5126492.82970056 396734.393537423 5126461.82958359 396716.643028971 5126431.82946552 396696.454972903 5126400.82934927 396683.579551284 5126371.82922318 396670.579120159 5126341.82909202 396659.078702435 5126310.297698 396644.515705503 5126274.82879108 396631.390228143 5126238.82862717 396618.389788858 5126207.82849133 396605.264318258 5126172.82833358 396596.701364704 5126129.82811725 396590.826006225 5126093.82793236 396582.263052331 5126050.82771637 396576.075137571 5126007.82749328 396574.949857411 5125971.82729413 396573.637016015 5125927.82705053 396577.261814638 5125891.82683664 396595.511885163 5125859.8265997 396606.574358413 5125830.8264017 396629.824563343 5125805.82618797 396647.319162537 5125787.41633249 396496.946542206 5125694.16972709 396265.286206196 5125662.98278777 396160.816273646 5125738.57728593 396134.753495823 5125759.67123408 396052.504443825 5125823.62741535 396003.377069077 5125861.82845485 395945.971110523 5126029.07954184 395968.784521861 5126100.82986161 396043.817816002 5126209.1427239 396069.754253405 5126270.44142693 396082.850393495 5126301.39311046 396095.748378117 5126315.60244372 396095.756961454 5126315.61189973 396148.758271506 5126374.73706626 396293.917828993 5126499.7373284 396410.233127903 5126621.23766537 396495.391869976 5126771.61326048 396477.236287709 5126903.7390479 396447.01740699 5126953.27065725 396386.798790024 5127105.33416577 396321.236427432 5127269.05399634 396229.298063942 5127353.99220683 396131.015871768 5127441.55544318 396115.829386175 5127462.17909169 396115.828279149 5127462.18059506 396066.015476462 5127529.80609163 395983.734586901 5127756.49502677 395923.733826088 5127783.74532406 395777.326113984 5127902.27757212 395777.308245804 5127902.29204828 395726.294356848 5127943.62166756 395549.292459624 5128067.5602533 395353.352636097 5128173.62377797 395211.19494155 5128281.09341984 395079.411735468 5128299.68757608 394960.878470623 5128283.28152324 394781.906211452 5128198.87527613 394617.215350449 5128105.37520948 394538.216159199 5128051.72570248 394430.805121636 5127978.78129481 394333.866057581 5127977.43777842 394248.209101525 5128061.40714611 394197.834475444 5128209.75173291 394146.054233813 5128439.94045916 394112.617113715 5128554.12858191 394090.929403945 5128570.94121182 394060.054237649 5128611.37897475 393913.240703544 5128772.19256588 393830.17833932 5128951.81859017 393716.803734575 5129221.19508348 393649.741102212 5129334.41449471 393593.271673627 5129359.63347651 393541.208155385 5129334.6334693 393522.332596165 5129302.28961079 393502.519354101 5129249.38316098 393485.268439118 5129170.44533793 393460.892125407 5129056.50737175 393434.734730461 5128966.81952098 393406.827666262 5128921.06937453 393281.887002488 5128775.88149651 393162.478318341 5128709.72521971 393074.570595567 5128699.94412585 392948.131162291 5128708.25694998 392938.886078307 5128717.09598999 392938.881089356 5128717.10075982 392869.349294331 5128783.78870889 392856.131338188 5128904.03926276 392869.788619186 5129001.85215899 392921.040097872 5129082.50864999 392939.594223998 5129096.3771071 392939.603005278 5129096.38367075 393010.885818893 5129149.72750229 393111.387893415 5129209.66505377 393203.984079088 5129328.85288977 393215.891632466 5129464.35346913 393173.016630795 5129545.26016531 393150.858439436 5129570.56502282 393036.140792715 5129701.57362622 393002.98422843 5129725.82379725 392941.396243187 5129736.47843803 392903.451574447 5129743.04281602 392753.699271544 5129746.01187008 392503.539385536 5129775.94998378 392399.632345048 5129873.1693424 392239.412465554 5130032.26405602 392210.100676357 5130168.70217224 392213.070651679 5130306.92148529 392219.540503596 5130424.39070673 392209.916467398 5130554.61000795 392149.072499686 5130638.14170229 392048.790525459 5130732.51725212 391875.069984154 5130832.39293655 391663.504815478 5130896.51853027 391580.222853181 5130960.33141186 391436.940407299 5131072.70707042 391358.345878462 5131119.9261223 391358.337790057 5131119.93098495 391332.095618879 5131135.70747265 391169.843461014 5131170.05160012 391090.329432917 5131198.60780057 391090.311258207 5131198.61432773 391004.028975747 5131229.58332307 390870.621635629 5131333.89640539 390701.182026774 5131384.3968375 390459.210143678 5131442.20989569 390404.616155957 5131506.96020143 390404.773253846 5131600.33552766 390419.305721358 5131710.67964326 390412.243757333 5131781.58615058 390338.024937405 5131896.52414872 390204.523538589 5131962.2745484 390046.80271229 5131993.02485559 389913.988072682 5131976.18122009 389735.78932966 5131895.87789917 389735.42215901 5131895.71243772 389716.515360771 5131867.05611908 389571.981062729 5131772.08725552 389506.51136487 5131775.83735682 389479.604770387 5131782.21241387 389234.03940457 5131869.58802097 389096.006383826 5131901.213303 388922.035336683 5131933.83863323 388773.189300139 5131927.77631271 388634.030436623 5131872.40133634 388526.340893101 5131827.68260284 388437.463981855 5131767.6200527 388351.21178844 5131674.49490861 388256.834163314 5131549.83844281 388149.08215691 5131510.58849153 388127.769379886 5131515.21353581 388127.399562769 5131515.29264081 388069.331118797 5131527.71365645 388022.768344655 5131571.80759559 387956.643615577 5131701.96429489 387902.206568144 5131832.24597249 387809.018355722 5131902.40253741 387683.516554347 5131910.62147954 387590.171097294 5131879.4340258 387503.856283962 5131776.34013029 387426.478629891 5131625.71485673 387356.320156636 5131508.18341269 387263.786609173 5131417.74582555 387182.780887846 5131291.45026806 387182.409113164 5131290.87063628 387177.44021241 5131283.30812538 387127.000702834 5131158.62039828 387071.99810947 5130982.80755732 387039.590880763 5130934.40124346 386913.932180852 5130881.58882868 386890.025426821 5130867.80758648 386778.398073713 5130803.74512643 386670.708572628 5130768.96398226 386582.706761838 5130723.37028123 386497.674054816 5130708.37039707 386497.663885286 5130708.36860975 386492.517716472 5130707.46415414 386475.986184474 5130704.68292709 386341.452834485 5130701.27690786 386253.63935409 5130737.27714263 386147.951236715 5130835.27754052 386056.543827963 5130858.77774916 385983.85493916 5130831.99656867 385948.760142974 5130782.65277654 385908.258559579 5130689.3714036 385903.444393696 5130535.05859079 385896.787461117 5130478.83973587 385888.9116599 5130412.96461326 385852.847603138 5130316.15198014 385777.314182535 5130219.30817553 385722.469283381 5130190.43322317 385648.123974982 5130151.37078959 385475.682733631 5130049.2459285 385294.460745839 5130009.18371524 385092.770554928 5130051.68420095 384884.862006922 5130139.96602552 384880.021818156 5130140.61623874 384702.015678741 5130164.52893091 384570.919338906 5130112.6541042 384489.198661461 5130051.27916677 384432.354144517 5130014.24695822 384365.384582075 5129979.05834044 384256.071374883 5129978.46283999 384095.632846489 5129978.49152223 383967.631733082 5129951.80193996 383901.537153416 5129914.83208574 383870.442760021 5129874.39403732 383834.973140548 5129815.95589644 383818.316026528 5129747.01804328 383817.347899687 5129745.05059834 383817.347248667 5129745.04927532 383794.44034032 5129698.54885066 383712.031781964 5129536.95358107 383616.686453127 5129449.63944961 383467.309981205 5129404.13700936 383343.559376889 5129422.29130741 383185.264346579 5129474.58983867 383172.933891244 5129478.66365389 382432.112672226 5129129.30767849 382050.545617803 5128946.48889483 381930.669198259 5128890.45567463 381813.761564185 5128836.01625451 381555.44536519 5128886.57970874 381368.697109312 5128923.13427606 381021.946477756 5129068.91016897 380846.041160551 5129252.40756313 380614.072408873 5129385.43525726 380507.415444003 5129383.96480723 380366.976564238 5129343.80628053 380170.662848542 5129349.99066149 380077.944277665 5129418.39550277 380040.790213423 5129629.4263673 379955.47919401 5129806.17517836 379954.121354302 5129807.34346081 379915.854329741 5129840.26832905 379915.841474504 5129840.2793996 379794.292249493 5129944.95398924 379279.665993473 5130123.85218926 378897.416206212 5130353.6275367 378366.6809587 5130916.98226256 378366.669410609 5130916.9945204 378237.170204929 5131054.46130696 377947.108891135 5131310.67560811 377506.601105877 5131497.25225083 377506.577075931 5131497.26242869 377469.077028666 5131513.13683829 377272.357976651 5131591.66498638 377034.074980805 5131570.78614464 376768.355508367 5131649.93818213 376762.104174374 5131658.76955849 376695.137538811 5131753.37457609 376657.888268789 5131833.68653146 376593.7950704 5131913.02930396 376523.576565284 5131969.90321229 376404.419467585 5131961.21379023 376265.792989486 5131910.33652847 376138.384541883 5131794.20940704 376002.693305361 5131555.42582811 375983.661649708 5131533.08106143 375893.25356053 5131426.92399242 375744.783231971 5131374.14032947 375599.438955512 5131406.57551903 375531.627207405 5131503.76198948 375519.971366165 5131543.44932595 375519.969779084 5131543.45472667 375497.784644065 5131618.94901437 375472.066917037 5131716.38615851 375393.12918816 5131738.35365392 375292.127979765 5131691.28950564 375215.439271748 5131631.81949125 375151.469708879 5131598.25594608 375151.466609136 5131598.2543156 375141.2508288 5131592.88077914 375081.032066892 5131623.00482986 375032.908051499 5131728.37911571 374983.628283286 5131874.87840432 374901.879817448 5132042.06468055 374671.819852731 5132365.71739828 374385.573430713 5132800.46300037 374334.449073106 5132878.08721254 374251.043722939 5132992.52342011 374211.887897763 5133046.36656284 374110.638995748 5133185.33374073 374110.628800055 5133185.34772794 374100.639104321 5133199.05233533 374058.889312703 5133236.48917747 374004.170838717 5133285.73831497 373785.326565466 5133350.95355605 373598.668780583 5133318.79427626 373493.324466251 5133324.98007656 373445.043516532 5133372.69806519 373307.606872866 5133508.38339578 372977.297673735 5133932.09695315 372790.173713299 5134104.59397872 372790.170162929 5134104.59724814 372775.955042474 5134117.68750249 372616.612187284 5134264.74746524 372415.738702513 5134480.15052 372296.050727994 5134498.89858207 372182.611876215 5134445.24047566 372110.235077686 5134337.05177184 372038.734154073 5134297.76935155 371981.640729843 5134350.42468931 371910.20526255 5134544.45482948 371871.615119463 5134847.01677682 371871.613784306 5134847.02728489 371870.177754423 5134858.32925617 371825.681054914 5135139.17234848 371732.870849389 5135362.63963708 371632.871459507 5135456.4505272 371498.902091211 5135469.07334565 371358.618872436 5135378.66479156 371231.74097487 5135209.69394335 371179.165366849 5134977.74499291 371171.737240818 5134944.97416816 371149.550387032 5134864.23037611 371149.54857798 5134864.22379249 371102.921133998 5134694.62925355 371045.605330146 5134462.97203032 370950.884457963 5134341.37672201 370801.727018197 5134318.18680016 370567.694307639 5134313.58925654 370355.194118364 5134397.67957449 370170.318219683 5134413.73907981 370049.723713777 5134411.08087486 369743.345798776 5134327.79465235 369517.516662406 5134301.45274707 369360.186666137 5134283.1009439 369208.373999229 5134340.25473874 368975.278848685 5134340.25096428 368826.122522064 5134402.81105038 368532.309491415 5134496.65004185 368175.933545762 5134586.92551616 368028.589043977 5134596.79812841 367916.025289972 5134552.98380722 367905.228118526 5134542.16171798 367821.367215384 5134458.10728 367710.61665657 5134466.16798652 367475.710658418 5134591.3204227 367345.462794344 5134810.38079058 367239.401311117 5134934.12905694 367239.398405859 5134934.1324489 367221.307735114 5134955.25376096 367124.0914264 5135181.47090497 367082.156269516 5135375.50144765 366884.034768684 5135724.18567314 366793.943845536 5135974.49666413 366778.853974814 5136270.5276158 366807.978677004 5136463.10776126 366809.450611755 5136472.84057867 366824.57760034 5136614.80954984 366821.144583642 5136950.93443061 366845.334161347 5137095.80979895 366875.554018653 5137165.74778068 366875.804959058 5137235.8727713 366886.212501567 5137328.0291741 366923.08862478 5137396.46726575 366947.058138981 5137443.53015 366943.46508978 5137497.40508064 366978.653845522 5137576.56189309 367025.780404329 5137673.46889857 367073.093865672 5137725.68841608 367104.875728692 5137758.34518228 367121.626369416 5137799.34544999 367102.002053342 5137858.68886621 367050.877367345 5137903.3755169 366984.940474588 5137976.06191797 366918.191126759 5138052.34205411 366879.389001928 5138103.86746532 366856.816879829 5138133.84102677 366808.567344957 5138188.37147059 366781.879859463 5138200.4022785 366723.879623085 5138206.55757204 366647.597692618 5138187.11882044 366589.003223451 5138157.58661265 366536.397323923 5138113.34832342 366535.564825097 5138112.64824369 366485.313702831 5138049.80368183 366453.312870236 5138001.05316715 366416.593619779 5137978.95881858 366416.587707755 5137978.95525782 366386.499459196 5137960.83332812 366339.185982065 5137907.73881331 366288.122364621 5137845.83173942 366216.683841031 5137799.36182728 366108.557463946 5137741.9225659 366029.025822986 5137745.79625858 365970.026257097 5137802.23277408 365930.277242936 5137891.48209619 365920.371655258 5137944.51316849 365932.841234391 5138000.70085767 365960.811103591 5138072.01379758 365972.686771742 5138116.57648041 365972.687422175 5138116.57892797 365975.061905694 5138125.51401698 365972.469001608 5138189.13895637 365940.282070582 5138244.32591086 365898.688475529 5138272.70021792 365827.313242323 5138284.48028935 365732.281270375 5138269.79122924 365647.405031084 5138212.88359962 365569.934628535 5138122.63235302 365567.655039181 5138116.57448271 365567.653283612 5138116.56981739 365527.901621939 5138010.41294692 365499.08722652 5137882.66251335 365474.398328754 5137789.91213682 365400.896571652 5137690.84846121 365376.365258986 5137684.03591527 365333.990003365 5137661.53583604 365283.864981056 5137655.28574247 365239.771714256 5137686.41065965 365197.397982532 5137774.94182825 365179.555719593 5137881.72304155 365166.307346518 5137999.16051247 365161.902624819 5138110.22299993 365160.902713005 5138116.56674776 365160.902198506 5138116.57001858 365149.778695896 5138187.28547338 365117.904723126 5138259.47290813 365048.404931382 5138268.69152207 364993.341983506 5138231.22266712 364917.278734731 5138169.87877381 364875.965555283 5138116.56689138 364867.996674336 5138106.28493355 364801.183660132 5138062.75355874 364798.97112409 5138062.28804314 364750.089825187 5138052.00346172 364711.183923816 5138074.09713491 364666.187346678 5138118.2502155 364662.872128751 5138121.50328703 364641.967104594 5138209.56573682 364635.062474466 5138327.78445968 364649.313931514 5138435.87822487 364689.065706344 5138569.37828793 364696.285289058 5138631.03454516 364658.223828381 5138704.12821014 364605.78730269 5138771.34684599 364544.225664251 5138829.62796356 364490.91345493 5138846.69035307 364423.038507611 5138845.0964658 364356.851023245 5138840.90883246 364313.007271247 5138837.22124436 364281.069995494 5138851.15867724 364260.289258966 5138887.31487852 364263.47720422 5138920.37737891 364314.665608134 5138991.03372048 364391.104176879 5139075.7213625 364468.574177013 5139173.69025623 364493.012619355 5139244.84654557 364487.076089082 5139315.69027176 364439.077085231 5139385.34640949 364394.734339416 5139455.94005373 364319.141655568 5139528.87738026 364216.486331473 5139589.62715005 364095.080909628 5139641.93937995 363959.643840167 5139663.97033556 363868.425079219 5139656.56389265 363818.924788449 5139631.43879367 363808.392994932 5139590.40753212 363823.485954133 5139532.93882924 363839.172370844 5139453.87638284 363837.827523682 5139372.53265086 363841.545639761 5139325.87642051 363818.638210236 5139236.7826455 363785.481169167 5139175.62634255 363716.855629066 5139130.25121296 363615.824412883 5139124.84475658 363521.76249225 5139160.5008027 363371.857973439 5139277.59420678 363243.796764983 5139363.9689119 363237.626104089 5139370.40515816 363243.364277513 5139737.56253265 363288.385949383 5141356.56204431 363326.407379677 5142957.5615029 363362.428937446 5144568.560907 363393.450473892 5146178.56025039 363423.472146704 5147799.55953667 363462.493638907 5149407.55881229 363508.51540958 5151036.55805747 363525.541458662 5152632.54365357 363546.568453368 5154268.52794437 363567.595379654 5155902.51222113 363588.622172094 5157530.49652267 363626.648776953 5159144.48095067 363644.675349591 5160763.46526335 363661.701697692 5162371.44965229 363685.728248551 5163991.43389613 363709.754736729 5165609.41812413 363291.783016622 5165620.07441053 363315.77770652 5167225.40265729 363337.803609773 5168831.38711532 363364.829545382 5170438.37152247 363394.855248387 5172030.35603161 363427.881124527 5173632.3403966 363454.906150243 5175186.32520418 363467.932862727 5176859.30886258 363504.95904189 5178481.29290082 363550.977890328 5180075.29164102 363580.994093155 5181701.29615338 363611.010184343 5183316.30059055 363641.026261061 5184930.30498119 365281.047940272 5184892.29791889 366907.07038705 5184868.29350236 368514.094609698 5184840.29551664 370108.118282876 5184782.29747898 371712.142246418 5184739.29951398 373341.166495797 5184691.30160356 373382.189451016 5186298.30396487 373391.212936974 5187983.30635824 373441.235923314 5189582.30862248 373500.258375488 5191128.31076725 373541.281566533 5192751.31295644 373588.304614556 5194354.31507048 373653.328067132 5195956.31712917 373679.350870619 5197573.31916324 373718.373690395 5199170.32112234 373765.39676851 5200771.3230325 373810.419975119 5202384.32490804 373864.442539376 5203931.32664582 373465.40057681 5203942.92090823 373500.454499719 5205564.32904337 373528.486156668 5207158.32407421 373555.531914217 5208769.30919172 373587.577486548 5210369.29435633 373634.623218261 5211958.27954698 373683.669690791 5213571.26446363 373729.716095648 5215185.24932957 373769.762010239 5216789.23425526 373804.807979489 5218402.21906225 373825.852371883 5219978.20420591 373804.895460481 5221568.18928244 373851.941887044 5223185.1738895 373909.988276518 5224784.15858966 373945.033749309 5226384.14329541 373981.079382714 5227989.12790541 374019.124894757 5229587.11253092 374045.169847411 5231185.09714693 374094.216351173 5232802.08146562 374128.26138167 5234373.06628169 374141.315162816 5235996.05154401 374166.369620794 5237623.03668185 374208.423516773 5239209.02210155 374251.477236066 5240789.00753324 374283.530978323 5242386.43028713 373681.502561762 5242386.55653017 373719.557267099 5244003.97891204 373769.611971478 5245604.9638833 373819.667365047 5247227.94860987 373878.722823408 5248840.93337997 373941.779351181 5250481.91784665 373992.834567751 5252100.90249579 - - - - 441092.101754418,5208823.73991009 441972.032773827,5208775.41142816 443587.033226362,5208743.38172553 445198.051095369,5208718.35237246 446806.068363107,5208679.32334738 448644.087087741,5208608.29073645 450247.104615585,5208574.26195256 451834.124374432,5208602.23232861 453438.144212413,5208629.20233618 455033.163135423,5208636.17288165 456597.180129897,5208600.14499324 458225.198505544,5208581.11560367 459821.21517858,5208522.08790625 461439.233700543,5208509.05869865 463040.246910989,5208498.99806743 464622.256143646,5208453.92261524 466193.264646374,5208387.84811905 467933.276195024,5208379.76399427 469529.286922469,5208375.68679552 471117.297912188,5208380.60985085 472733.308665441,5208371.53186471 474328.319527427,5208369.45480206 475930.330365635,5208364.37748519 477560.337852849,5208249.30028279 479172.346439863,5208171.22321294 480784.356447228,5208136.14551495 482340.360106787,5208086.1204854 483907.362597763,5208023.10295594 485482.366095061,5207990.08506313 487695.37368665,5208030.05902892 489296.378898243,5208051.040287 490905.384432413,5208083.02133299 492543.389047529,5208082.00243547 494141.393716148,5208086.98394688 495747.398906727,5208109.96516074 495711.353257682,5206502.98535492 495676.309926805,5204889.00866588 495650.279726696,5203296.04675013 495637.248778541,5201663.08557362 495611.218295986,5200062.12367648 495603.188010644,5198467.16141745 495560.156779411,5196842.20002694 495564.126526155,5195247.23755609 495524.095615327,5193646.27538485 495503.064321413,5192017.3136871 495446.03275704,5190405.35159924 495420.002151849,5188825.38856517 495394.971242756,5187232.42574426 495375.93995181,5185617.46334803 495368.909626316,5184043.49993398 495340.878395801,5182446.53695695 495346.84729782,5180821.57463446 495302.815676504,5179229.61132198 495238.783334567,5177631.64792968 495199.767500209,5176019.63582349 495197.755906868,5174450.61531256 495162.742991802,5172830.59400039 495126.729927639,5171207.57265376 495067.716229818,5169609.55161623 495088.705029187,5168017.53073455 495086.692865267,5166393.50936063 495112.681912028,5164799.4883054 495107.669755823,5163187.46698448 495145.659310535,5161586.4456535 495178.648737239,5159980.6429203 495797.673211287,5159977.23447586 495717.658886368,5158361.40025725 495738.648547533,5156735.37796876 495734.637160115,5155107.35571706 495746.626973123,5153550.33429246 495747.61601901,5151951.3123082 495770.605990571,5150333.28983519 495773.615683926,5148704.27380344 495760.64120287,5147100.26336865 495755.667156541,5145494.25280909 495748.693082425,5143884.24220147 495748.719955069,5142239.23124588 495769.747660932,5140613.22013602 495815.776178388,5139024.20891946 495828.803448126,5137406.19781468 495830.829879582,5135804.18689701 495858.858328788,5134171.17538212 495862.885291437,5132548.16418396 495864.911866238,5130943.15308686 495858.938034687,5129335.14203562 495883.965846267,5127742.13058836 495856.990847918,5126129.11972733 495850.017037609,5124518.10854358 495835.043321767,5122871.09719571 495822.057922962,5121293.10356628 495835.052794276,5119689.14462307 495835.046800069,5118075.18610661 495827.040391883,5116474.22734309 495830.03459665,5114867.2685059 495843.029308365,5113258.30950871 495834.022797801,5111638.35111148 494234.941171807,5111635.37770315 492634.859519821,5111644.40406969 490947.773415802,5111651.43200419 489445.696786071,5111649.45714681 487838.614772884,5111656.48387701 486177.529781002,5111689.51091615 484578.448198062,5111689.5378244 482966.365654519,5111715.56435322 481334.282092909,5111736.59141491 479721.221100558,5111770.63479686 478124.175610684,5111798.68941725 476457.129157939,5111754.7481173 474848.084947473,5111654.80580315 473223.039842219,5111578.86331326 471623.995501651,5111486.91997601 470034.951263299,5111396.97599809 468383.905221494,5111292.03408398 466657.856325405,5111261.0935366 466801.849456444,5112811.07011109 466840.839130967,5114420.0494352 466837.82780885,5116011.03046653 466825.816297009,5117602.01185281 466806.804704029,5119187.99361209 466796.788476539,5121475.96660114 465169.751832345,5121562.03758123 463582.716668467,5121567.10778504 461978.681115782,5121582.17868885 460382.654975318,5121633.22463705 458863.634782301,5121649.25671468 458729.164257097,5121647.19708141 457106.611589166,5121622.29420132 455534.590852865,5121594.3278256 453901.569310636,5121566.36280177 452150.546221549,5121533.40039558 450644.526317509,5121524.43260388 448848.502614519,5121502.47117366 447142.480120161,5121473.5079516 445555.459188838,5121450.54218051 444012.438820035,5121440.57537843 442433.41800387,5121415.6095591 440877.37695095,5121394.6590622 439268.330052994,5121375.71365614 438623.813339239,5121376.09834029 438608.466924173,5121441.5166267 438596.591390315,5121527.9850023 438582.028332704,5121589.10994768 438548.558156946,5121795.26548809 438546.089318335,5121802.82800448 438536.401429659,5121851.26540118 438496.493851218,5121925.35985063 438461.242758608,5121953.57955277 438377.709007713,5121979.89467277 438306.488190201,5121972.92841773 438237.736223155,5121953.39968798 438155.890192362,5121903.34042007 438058.606268627,5121828.21939093 438017.948835643,5121826.06454523 437838.380916,5121901.57002048 437750.12819346,5121963.47875683 437689.782536252,5122024.98029865 437649.749976677,5122084.512416 437637.155825486,5122098.543979 437614.748826392,5122138.54440989 437591.404435887,5122162.35790414 437549.528288354,5122205.1096879 437534.527896677,5122230.61041166 437527.027817008,5122305.58004155 437509.98489396,5122463.40794018 437519.278954217,5123033.77386323 437546.282736399,5124637.78625312 437573.286513144,5126246.79863957 437598.290210678,5127849.81099969 437625.294012361,5129486.82352584 437635.297323898,5131096.83636224 437641.300538971,5132700.84923972 437648.303832046,5134323.86219173 437665.307315615,5135919.8745398 437698.311182421,5137532.88643811 437718.314733817,5139136.89865929 437736.318211385,5140725.91078311 437725.321201069,5142354.92416177 437725.324428085,5143976.93706535 437726.327686801,5145591.94983279 437727.330981757,5147211.9625931 437702.333741618,5148765.97566464 437697.348137997,5150407.98503925 437791.389300783,5152014.98244466 437837.429981925,5153635.98146622 437843.469251102,5155223.98172365 437843.494396201,5156242.79447432 437843.509384072,5156849.98210987 437837.784713312,5157878.73248683 437834.549029165,5158459.98268407 437842.257240392,5159295.10758917 437912.69554087,5159295.9805468 438546.704763059,5159386.9622125 438820.677249212,5159416.79805414 438868.021643891,5159421.9529385 438955.523526871,5159460.20043565 439389.43905896,5159649.78182603 439428.658644014,5159666.93696318 439837.293205181,5159883.92545398 439920.105839013,5159851.92304252 439928.95258192,5159831.79768159 440168.295395738,5159825.88464183 440394.891556092,5159824.69064082 440428.731220104,5159825.84576899 440435.50090148,5160474.87791456 440441.639697625,5161063.90983245 440435.976045197,5162089.00518069 440432.67738969,5162683.9123425 440422.825660397,5163685.13271532 440416.715119515,5164306.91495392 440429.239983656,5165367.88476372 440435.75289353,5165918.916557 440442.465107261,5166975.79273044 440445.789838809,5167498.91830244 440467.877617866,5168576.200343 440478.827657615,5169110.91948283 440497.446274702,5170172.6390742 440506.865079036,5170708.92074466 440537.889487585,5171749.7025147 440553.902074748,5172286.92153435 440572.989475617,5173352.60984766 440582.9399676,5173908.92276828 440604.370555919,5174951.2984902 440615.977504472,5175516.92387936 440637.563766231,5176535.7995613 440650.014973456,5177123.92495227 440650.699677025,5178172.94869223 440651.06097089,5178732.9083982 440684.750599837,5179797.67179249 440702.111525844,5180345.88134396 440731.830135607,5181339.36469896 440750.161804751,5181951.85443125 440774.193317489,5182959.24389991 440788.211689919,5183546.82785545 440808.556140411,5184569.02963089 440820.262004985,5185156.80111335 440840.168994679,5186181.03408972 440851.311907451,5186754.77454703 440868.844368726,5187794.75728581 440878.361997923,5188359.74790141 440898.739585907,5189444.7298283 440908.411922532,5189960.72122732 440913.290734644,5191084.45276957 440915.462465655,5191580.69461056 440937.027880396,5192677.64501441 440946.511668596,5193160.66818059 440965.045984715,5194262.9622736 440973.561784197,5194770.64128997 440987.346268008,5195878.46659537 440993.611925358,5196381.61446136 440997.677376318,5197479.59631226 440999.66263242,5198009.587543 440997.788580086,5199042.66427922 440996.713401008,5199638.56070505 441015.248841091,5200779.38528998 441022.763161913,5201240.53378684 441038.390380076,5202318.23443591 441044.810329775,5202759.50826854 441068.033916685,5203923.5198378 441076.86011304,5204365.48110994 441099.180074391,5205568.61773998 441107.919134768,5206040.4563889 441092.937830809,5207196.00699117 441086.988839287,5207653.43979129 441092.101754418,5208823.73991009 + + + + 437509.98489396 5111261.0935366495883.965846267 5208823.73991009 + 441092.101754418 5208823.73991009 441972.032773827 5208775.41142816 443587.033226362 5208743.38172553 445198.051095369 5208718.35237246 446806.068363107 5208679.32334738 448644.087087741 5208608.29073645 450247.104615585 5208574.26195256 451834.124374432 5208602.23232861 453438.144212413 5208629.20233618 455033.163135423 5208636.17288165 456597.180129897 5208600.14499324 458225.198505544 5208581.11560367 459821.21517858 5208522.08790625 461439.233700543 5208509.05869865 463040.246910989 5208498.99806743 464622.256143646 5208453.92261524 466193.264646374 5208387.84811905 467933.276195024 5208379.76399427 469529.286922469 5208375.68679552 471117.297912188 5208380.60985085 472733.308665441 5208371.53186471 474328.319527427 5208369.45480206 475930.330365635 5208364.37748519 477560.337852849 5208249.30028279 479172.346439863 5208171.22321294 480784.356447228 5208136.14551495 482340.360106787 5208086.1204854 483907.362597763 5208023.10295594 485482.366095061 5207990.08506313 487695.37368665 5208030.05902892 489296.378898243 5208051.040287 490905.384432413 5208083.02133299 492543.389047529 5208082.00243547 494141.393716148 5208086.98394688 495747.398906727 5208109.96516074 495711.353257682 5206502.98535492 495676.309926805 5204889.00866588 495650.279726696 5203296.04675013 495637.248778541 5201663.08557362 495611.218295986 5200062.12367648 495603.188010644 5198467.16141745 495560.156779411 5196842.20002694 495564.126526155 5195247.23755609 495524.095615327 5193646.27538485 495503.064321413 5192017.3136871 495446.03275704 5190405.35159924 495420.002151849 5188825.38856517 495394.971242756 5187232.42574426 495375.93995181 5185617.46334803 495368.909626316 5184043.49993398 495340.878395801 5182446.53695695 495346.84729782 5180821.57463446 495302.815676504 5179229.61132198 495238.783334567 5177631.64792968 495199.767500209 5176019.63582349 495197.755906868 5174450.61531256 495162.742991802 5172830.59400039 495126.729927639 5171207.57265376 495067.716229818 5169609.55161623 495088.705029187 5168017.53073455 495086.692865267 5166393.50936063 495112.681912028 5164799.4883054 495107.669755823 5163187.46698448 495145.659310535 5161586.4456535 495178.648737239 5159980.6429203 495797.673211287 5159977.23447586 495717.658886368 5158361.40025725 495738.648547533 5156735.37796876 495734.637160115 5155107.35571706 495746.626973123 5153550.33429246 495747.61601901 5151951.3123082 495770.605990571 5150333.28983519 495773.615683926 5148704.27380344 495760.64120287 5147100.26336865 495755.667156541 5145494.25280909 495748.693082425 5143884.24220147 495748.719955069 5142239.23124588 495769.747660932 5140613.22013602 495815.776178388 5139024.20891946 495828.803448126 5137406.19781468 495830.829879582 5135804.18689701 495858.858328788 5134171.17538212 495862.885291437 5132548.16418396 495864.911866238 5130943.15308686 495858.938034687 5129335.14203562 495883.965846267 5127742.13058836 495856.990847918 5126129.11972733 495850.017037609 5124518.10854358 495835.043321767 5122871.09719571 495822.057922962 5121293.10356628 495835.052794276 5119689.14462307 495835.046800069 5118075.18610661 495827.040391883 5116474.22734309 495830.03459665 5114867.2685059 495843.029308365 5113258.30950871 495834.022797801 5111638.35111148 494234.941171807 5111635.37770315 492634.859519821 5111644.40406969 490947.773415802 5111651.43200419 489445.696786071 5111649.45714681 487838.614772884 5111656.48387701 486177.529781002 5111689.51091615 484578.448198062 5111689.5378244 482966.365654519 5111715.56435322 481334.282092909 5111736.59141491 479721.221100558 5111770.63479686 478124.175610684 5111798.68941725 476457.129157939 5111754.7481173 474848.084947473 5111654.80580315 473223.039842219 5111578.86331326 471623.995501651 5111486.91997601 470034.951263299 5111396.97599809 468383.905221494 5111292.03408398 466657.856325405 5111261.0935366 466801.849456444 5112811.07011109 466840.839130967 5114420.0494352 466837.82780885 5116011.03046653 466825.816297009 5117602.01185281 466806.804704029 5119187.99361209 466796.788476539 5121475.96660114 465169.751832345 5121562.03758123 463582.716668467 5121567.10778504 461978.681115782 5121582.17868885 460382.654975318 5121633.22463705 458863.634782301 5121649.25671468 458729.164257097 5121647.19708141 457106.611589166 5121622.29420132 455534.590852865 5121594.3278256 453901.569310636 5121566.36280177 452150.546221549 5121533.40039558 450644.526317509 5121524.43260388 448848.502614519 5121502.47117366 447142.480120161 5121473.5079516 445555.459188838 5121450.54218051 444012.438820035 5121440.57537843 442433.41800387 5121415.6095591 440877.37695095 5121394.6590622 439268.330052994 5121375.71365614 438623.813339239 5121376.09834029 438608.466924173 5121441.5166267 438596.591390315 5121527.9850023 438582.028332704 5121589.10994768 438548.558156946 5121795.26548809 438546.089318335 5121802.82800448 438536.401429659 5121851.26540118 438496.493851218 5121925.35985063 438461.242758608 5121953.57955277 438377.709007713 5121979.89467277 438306.488190201 5121972.92841773 438237.736223155 5121953.39968798 438155.890192362 5121903.34042007 438058.606268627 5121828.21939093 438017.948835643 5121826.06454523 437838.380916 5121901.57002048 437750.12819346 5121963.47875683 437689.782536252 5122024.98029865 437649.749976677 5122084.512416 437637.155825486 5122098.543979 437614.748826392 5122138.54440989 437591.404435887 5122162.35790414 437549.528288354 5122205.1096879 437534.527896677 5122230.61041166 437527.027817008 5122305.58004155 437509.98489396 5122463.40794018 437519.278954217 5123033.77386323 437546.282736399 5124637.78625312 437573.286513144 5126246.79863957 437598.290210678 5127849.81099969 437625.294012361 5129486.82352584 437635.297323898 5131096.83636224 437641.300538971 5132700.84923972 437648.303832046 5134323.86219173 437665.307315615 5135919.8745398 437698.311182421 5137532.88643811 437718.314733817 5139136.89865929 437736.318211385 5140725.91078311 437725.321201069 5142354.92416177 437725.324428085 5143976.93706535 437726.327686801 5145591.94983279 437727.330981757 5147211.9625931 437702.333741618 5148765.97566464 437697.348137997 5150407.98503925 437791.389300783 5152014.98244466 437837.429981925 5153635.98146622 437843.469251102 5155223.98172365 437843.494396201 5156242.79447432 437843.509384072 5156849.98210987 437837.784713312 5157878.73248683 437834.549029165 5158459.98268407 437842.257240392 5159295.10758917 437912.69554087 5159295.9805468 438546.704763059 5159386.9622125 438820.677249212 5159416.79805414 438868.021643891 5159421.9529385 438955.523526871 5159460.20043565 439389.43905896 5159649.78182603 439428.658644014 5159666.93696318 439837.293205181 5159883.92545398 439920.105839013 5159851.92304252 439928.95258192 5159831.79768159 440168.295395738 5159825.88464183 440394.891556092 5159824.69064082 440428.731220104 5159825.84576899 440435.50090148 5160474.87791456 440441.639697625 5161063.90983245 440435.976045197 5162089.00518069 440432.67738969 5162683.9123425 440422.825660397 5163685.13271532 440416.715119515 5164306.91495392 440429.239983656 5165367.88476372 440435.75289353 5165918.916557 440442.465107261 5166975.79273044 440445.789838809 5167498.91830244 440467.877617866 5168576.200343 440478.827657615 5169110.91948283 440497.446274702 5170172.6390742 440506.865079036 5170708.92074466 440537.889487585 5171749.7025147 440553.902074748 5172286.92153435 440572.989475617 5173352.60984766 440582.9399676 5173908.92276828 440604.370555919 5174951.2984902 440615.977504472 5175516.92387936 440637.563766231 5176535.7995613 440650.014973456 5177123.92495227 440650.699677025 5178172.94869223 440651.06097089 5178732.9083982 440684.750599837 5179797.67179249 440702.111525844 5180345.88134396 440731.830135607 5181339.36469896 440750.161804751 5181951.85443125 440774.193317489 5182959.24389991 440788.211689919 5183546.82785545 440808.556140411 5184569.02963089 440820.262004985 5185156.80111335 440840.168994679 5186181.03408972 440851.311907451 5186754.77454703 440868.844368726 5187794.75728581 440878.361997923 5188359.74790141 440898.739585907 5189444.7298283 440908.411922532 5189960.72122732 440913.290734644 5191084.45276957 440915.462465655 5191580.69461056 440937.027880396 5192677.64501441 440946.511668596 5193160.66818059 440965.045984715 5194262.9622736 440973.561784197 5194770.64128997 440987.346268008 5195878.46659537 440993.611925358 5196381.61446136 440997.677376318 5197479.59631226 440999.66263242 5198009.587543 440997.788580086 5199042.66427922 440996.713401008 5199638.56070505 441015.248841091 5200779.38528998 441022.763161913 5201240.53378684 441038.390380076 5202318.23443591 441044.810329775 5202759.50826854 441068.033916685 5203923.5198378 441076.86011304 5204365.48110994 441099.180074391 5205568.61773998 441107.919134768 5206040.4563889 441092.937830809 5207196.00699117 441086.988839287 5207653.43979129 441092.101754418 5208823.73991009 - - - - 396647.319162537,5125787.41633249 396629.824563343,5125805.82618797 396606.574358413,5125830.8264017 396595.511885163,5125859.8265997 396577.261814638,5125891.82683664 396573.637016015,5125927.82705053 396574.949857411,5125971.82729413 396576.075137571,5126007.82749328 396582.263052331,5126050.82771637 396590.826006225,5126093.82793236 396596.701364704,5126129.82811725 396605.264318258,5126172.82833358 396618.389788858,5126207.82849133 396631.390228143,5126238.82862717 396644.515705503,5126274.82879108 396659.078702435,5126310.297698 396670.579120159,5126341.82909202 396683.579551284,5126371.82922318 396696.454972903,5126400.82934927 396716.643028971,5126431.82946552 396734.393537423,5126461.82958359 396754.581592814,5126492.82970056 396774.519586055,5126515.82977324 396792.082547279,5126539.82985873 396819.083119819,5126557.82988318 396855.458795444,5126568.82984108 396898.396942019,5126560.82967184 396939.022558013,5126553.8295148 396969.772954926,5126538.82934018 396993.21071066,5126520.82916915 397016.460920688,5126496.82896388 397027.460872742,5126464.82874777 397045.710944138,5126432.82851025 397056.585866089,5126396.82827085 397062.648201959,5126359.82803953 397066.08545198,5126316.82778114 397067.835406618,5126306.42146587 397072.147795239,5126280.82755525 397075.835099479,5126244.82733626 397081.647381872,5126200.82706453 397092.459782577,5126161.82680651 397103.334705913,5126125.82656536 397121.772332701,5126100.82636484 397132.772294143,5126069.82615172 397148.834882151,5126044.82595783 397160.553757661,5126035.20086627 397179.272708267,5126019.82571988 397202.647953329,5125999.82553214 397233.335833894,5125981.82533342 397269.086369297,5125973.82517735 397305.337011941,5125979.82510165 397344.087731071,5125990.82504784 397373.463344054,5126008.82506407 397397.963862016,5126024.82508369 397425.151973375,5126047.82513668 397438.089904983,5126078.82528037 397444.027755832,5126114.82547489 397445.590639645,5126165.82577112 397454.091060634,5126205.82598176 397460.091433225,5126244.8261941 397468.529352856,5126284.82640523 397471.34202389,5126302.60775191 397474.529718163,5126322.82661191 397494.655252618,5126351.82672409 397507.593182574,5126382.82686947 397527.781224448,5126412.82698805 397545.344180905,5126436.82707907 397565.46972113,5126466.82719851 397578.407636095,5126495.82733311 397591.595617786,5126533.82752065 397604.4710243,5126561.82764997 397612.783911683,5126597.82784006 397618.971812944,5126640.82807793 397627.534752913,5126683.82830922 397628.847581176,5126727.82856701 397635.035482062,5126770.82880521 397643.3483687,5126806.828996 397645.004726745,5126818.4540605 397649.473768279,5126849.82923463 397657.786647643,5126884.82941976 397670.912112201,5126920.82959777 397690.850103905,5126944.82968593 397703.850524161,5126974.8298291 397721.601028402,5127005.82996553 397741.664049093,5127033.83007812 397761.664540702,5127057.83016732 397766.539781408,5127081.11154329 397769.602433453,5127095.8616232 397772.545330568,5127866.83496574 397799.55716051,5129508.84465574 397831.568827347,5131116.8540907 397844.579951222,5132687.86328606 397841.591240943,5134313.87274973 397847.602616648,5135930.88208476 397871.614199177,5137540.89132351 397907.625956819,5139153.90054444 397932.637595763,5140770.90973277 397947.649143106,5142391.91887313 397962.660579673,5143995.92785993 397972.671962545,5145598.93676736 397971.683228179,5147199.94555985 397981.694931268,5148843.95455868 397986.706260507,5150439.96320876 397990.753525199,5152039.92440306 398061.802940095,5153673.8844116 398044.852873508,5155360.84277007 398049.901485214,5156996.80243326 398075.949416946,5158601.76287673 398059.997632782,5160238.72242226 398074.045935741,5161865.68223921 398079.094836043,5163519.64134919 398121.172223473,5165059.66575611 397524.818123527,5165067.79049237 397026.153268514,5165076.32148286 397059.169441951,5166697.56308368 397074.216493664,5168318.52340502 397070.262855338,5169930.48393691 397080.309523306,5171545.44435402 397136.356979965,5173154.40478628 397156.403121981,5174745.3656852 397292.452470757,5176353.32576343 397351.500174909,5177964.28589945 397410.545932918,5179591.26622548 397438.590081989,5181207.25121208 397484.635123672,5182839.23587902 397568.67961072,5184411.22069788 399155.722151603,5184365.20819777 400767.765827735,5184336.19538155 402376.809351054,5184305.18266293 403893.850467498,5184279.17067505 405509.88661979,5184240.16416644 407127.917199638,5184205.16237558 408731.947575327,5184173.16060055 410320.977603268,5184140.15890349 411927.0077774,5184102.15730687 413468.035170976,5184019.156598 415034.06331545,5183946.15575987 416630.092083367,5183876.15490039 418239.122759583,5183856.15320425 419845.153118906,5183829.1516743 421418.182848745,5183803.15020699 423021.215323013,5183838.14759326 424640.227328401,5183826.1287231 426250.225657675,5183796.09869613 427926.224039936,5183768.06739585 429532.222317095,5183736.03751201 431126.220916499,5183713.00771019 432729.219448619,5183687.97779001 434321.217792016,5183656.94819719 435909.216377732,5183632.91857415 437519.214606452,5183597.88873491 439133.213072692,5183569.8587156 440447.274474624,5183551.58421118 440788.211689919,5183546.82785545 440774.193317489,5182959.24389991 440750.161804751,5181951.85443125 440731.830135607,5181339.36469896 440702.111525844,5180345.88134396 440684.750599837,5179797.67179249 440651.06097089,5178732.9083982 440650.699677025,5178172.94869223 440650.014973456,5177123.92495227 440637.563766231,5176535.7995613 440615.977504472,5175516.92387936 440604.370555919,5174951.2984902 440582.9399676,5173908.92276828 440572.989475617,5173352.60984766 440553.902074748,5172286.92153435 440537.889487585,5171749.7025147 440506.865079036,5170708.92074466 440497.446274702,5170172.6390742 440478.827657615,5169110.91948283 440467.877617866,5168576.200343 440445.789838809,5167498.91830244 440442.465107261,5166975.79273044 440435.75289353,5165918.916557 440429.239983656,5165367.88476372 440416.715119515,5164306.91495392 440422.825660397,5163685.13271532 440432.67738969,5162683.9123425 440435.976045197,5162089.00518069 440441.639697625,5161063.90983245 440435.50090148,5160474.87791456 440428.731220104,5159825.84576899 440394.891556092,5159824.69064082 440168.295395738,5159825.88464183 439928.95258192,5159831.79768159 439920.105839013,5159851.92304252 439837.293205181,5159883.92545398 439428.658644014,5159666.93696318 439389.43905896,5159649.78182603 438955.523526871,5159460.20043565 438868.021643891,5159421.9529385 438820.677249212,5159416.79805414 438546.704763059,5159386.9622125 437912.69554087,5159295.9805468 437842.257240392,5159295.10758917 437834.549029165,5158459.98268407 437837.784713312,5157878.73248683 437843.509384072,5156849.98210987 437843.494396201,5156242.79447432 437843.469251102,5155223.98172365 437837.429981925,5153635.98146622 437791.389300783,5152014.98244466 437697.348137997,5150407.98503925 437702.333741618,5148765.97566464 437727.330981757,5147211.9625931 437726.327686801,5145591.94983279 437725.324428085,5143976.93706535 437725.321201069,5142354.92416177 437736.318211385,5140725.91078311 437718.314733817,5139136.89865929 437698.311182421,5137532.88643811 437665.307315615,5135919.8745398 437648.303832046,5134323.86219173 437641.300538971,5132700.84923972 437635.297323898,5131096.83636224 437625.294012361,5129486.82352584 437598.290210678,5127849.81099969 437573.286513144,5126246.79863957 437546.282736399,5124637.78625312 437519.278954217,5123033.77386323 437509.98489396,5122463.40794018 437527.027817008,5122305.58004155 437534.527896677,5122230.61041166 437549.528288354,5122205.1096879 437591.404435887,5122162.35790414 437614.748826392,5122138.54440989 437637.155825486,5122098.543979 437649.749976677,5122084.512416 437689.782536252,5122024.98029865 437750.12819346,5121963.47875683 437838.380916,5121901.57002048 438017.948835643,5121826.06454523 438058.606268627,5121828.21939093 438155.890192362,5121903.34042007 438237.736223155,5121953.39968798 438306.488190201,5121972.92841773 438377.709007713,5121979.89467277 438461.242758608,5121953.57955277 438496.493851218,5121925.35985063 438536.401429659,5121851.26540118 438546.089318335,5121802.82800448 438548.558156946,5121795.26548809 438582.028332704,5121589.10994768 438596.591390315,5121527.9850023 438608.466924173,5121441.5166267 438623.813339239,5121376.09834029 437492.278289034,5121376.77370461 437489.281897405,5119808.78685956 437484.285556978,5118193.80044963 437485.289502675,5116528.81424446 437456.292405097,5114947.82823075 437452.2960581,5113347.84157795 437431.299201951,5111764.85524216 435862.25607009,5111768.89945371 434242.211499074,5111795.9449713 432640.167442508,5111821.99004314 431057.123883495,5111860.03457731 429450.079784996,5111869.07996791 427689.031503852,5111876.12973772 426075.987253384,5111896.17531676 424471.943303663,5111909.22068335 422855.899076511,5111917.26641124 421230.245048103,5111933.30087059 419693.843452792,5111956.33283067 417964.469828952,5111966.36879395 416363.067141303,5111988.40214818 414771.7584298,5111973.43514807 413159.168052034,5111993.46874153 411548.296462609,5112009.50229384 409948.518902999,5112091.53610421 408231.145662077,5112170.57246601 406647.680959646,5112207.60578157 405044.934660928,5112231.63941539 403453.563699325,5112279.67291954 401873.540795608,5112322.6780784 400243.517022892,5112330.68303475 398556.492460839,5112347.68827534 396933.468840334,5112364.69334166 395351.445842091,5112389.69839127 393853.36157894,5112421.64078434 393859.299199886,5112441.70349511 393847.736572546,5112465.70380383 393843.674086977,5112508.70430647 393837.111552817,5112544.70473691 393845.049242344,5112587.70520303 393850.486883488,5112623.70559688 393863.112129893,5112659.70596873 393882.862472251,5112690.70626172 393895.237694829,5112714.70649737 393914.988037748,5112745.70679013 393932.300840051,5112773.70705606 393951.926169584,5112797.70726924 393969.238977644,5112828.70756912 393996.051911514,5112851.70774863 394013.302206987,5112875.70796879 394033.052551765,5112906.70826081 394045.552790225,5112937.70857504 394058.178039574,5112973.70894566 394065.990716505,5113008.70931965 394078.553456494,5113039.70963341 394091.116196692,5113070.70994707 394103.741446914,5113106.7103173 394121.054257676,5113137.71061607 394135.992030064,5113166.71089934 394148.492270238,5113197.71121282 394159.961246877,5113229.555289 394160.023832358,5113276.71207453 394160.086424654,5113327.68140335 394149.617585741,5113364.68185631 394144.680060856,5113391.71342881 394133.367462626,5113430.71390723 394126.742428434,5113466.71433695 394110.492242135,5113497.71474007 394104.117234372,5113546.7153168 394104.867321865,5113589.715803 394093.492216285,5113625.71624779 394082.117110468,5113661.71669265 394077.929611646,5113697.7171149 394071.4295835,5113736.71757855 394060.054477088,5113772.71802356 394048.67937044,5113808.71846863 394042.054334609,5113844.71889871 394042.804423075,5113888.71939632 394043.554509784,5113931.71988254 394051.429691031,5113967.72026654 394056.929849101,5114010.72073754 394069.555101945,5114046.72110623 394077.367782725,5114082.72149018 394090.055540472,5114120.72188119 394090.743123231,5114161.72234455 394098.74331963,5114204.72280715 394099.493406947,5114247.72329291 394104.993565904,5114290.72376339 394124.743913448,5114318.72401772 394137.244157168,5114349.72432931 394149.869411885,5114385.72469713 394167.682245546,5114421.88129988 394186.807568417,5114440.72520192 394211.245479328,5114463.72538385 394237.995918334,5114482.72551285 394267.121393583,5114501.72563407 394298.496888663,5114512.72565728 394322.809787916,5114529.72577122 394354.372799104,5114547.72587293 394383.373260707,5114559.72591491 394414.87377337,5114578.72602795 394446.31177054,5114589.72605056 394477.812278199,5114605.72612945 394506.812740696,5114617.72617113 394531.250660501,5114643.7263858 394550.876001888,5114666.72658206 394563.376246602,5114695.72686919 394571.313948641,5114738.72732926 394596.001896305,5114776.72767818 394601.377046541,5114812.7280673 394597.377067299,5114855.72856603 394590.752034629,5114891.7289943 394579.376931218,5114928.72944943 394566.470547747,5114962.32362117 394551.626620873,5114988.73021814 394532.87638519,5115015.7305847 394514.126143602,5115039.73091745 394490.500829059,5115064.73127761 394466.875503023,5115083.73157005 394448.125269927,5115112.73195959 394424.562455412,5115137.73231986 394408.249755359,5115164.73267895 394389.49952137,5115193.73306878 394370.874292663,5115224.73348092 394354.499087194,5115249.73381784 394330.873768359,5115273.73416751 394292.935731185,5115298.73457599 394269.247901644,5115317.73486951 394252.872695053,5115342.73520681 394239.060047403,5115378.73566023 394222.747343077,5115404.7360088 394204.059609094,5115434.73641064 394187.809414129,5115465.73681579 394169.121683087,5115497.73724048 394157.621557243,5115526.73760732 394138.933823844,5115557.73802086 394127.496203812,5115589.73842162 394111.183502991,5115618.73880474 394097.37084405,5115649.73920224 394088.55823042,5115662.61437765 394080.933132024,5115673.73952926 394062.307899905,5115705.73995438 394046.057702473,5115736.74036029 394034.557574845,5115765.74072766 394020.682415429,5115797.74113709 394004.494726822,5115833.74159972 393997.869679337,5115865.74198489 393986.494564888,5115901.74243145 393975.119453643,5115939.74290076 393963.744340432,5115976.7433588 393952.306715737,5116007.74374905 393933.618974614,5116036.74414123 393917.243760681,5116060.74446893 393893.680939688,5116087.74485512 393874.86818897,5116112.74520261 393861.180482468,5116116.74529445 393854.61792906,5116145.74564587 393850.430407537,5116171.74595519 393841.930304956,5116189.58993661 393825.117594874,5116220.74659747 393813.554946164,5116239.74685252 393797.054710209,5116252.74705632 393778.241944662,5116269.74731346 393761.866720345,5116288.74758506 393747.866531327,5116306.74783726 393731.491306684,5116325.74810897 393712.553531926,5116338.74832133 393696.178306954,5116357.74859315 393670.302942922,5116382.74896571 393653.802704186,5116394.74915854 393642.240055644,5116414.74942545 393623.552301824,5116438.74976227 393611.927147149,5116455.74999538 393600.552012397,5116482.75034137 393588.926857469,5116499.75057455 393577.489216607,5116523.75088674 393565.926567222,5116543.75115391 393554.36391611,5116562.75140974 393542.86377383,5116586.75172227 393519.113442233,5116612.84585085 393512.488355425,5116623.75224775 393500.925705356,5116643.75251513 393482.112936403,5116660.75277343 393465.550194804,5116672.75296711 393439.424804218,5116685.75320523 393415.736950249,5116697.75342361 393391.86158697,5116705.75359715 393368.111233285,5116718.75382724 393344.360877897,5116730.754046 393320.548015241,5116738.75421946 393301.610235368,5116750.75442168 393277.859881082,5116763.754652 393254.109525117,5116775.75487097 393235.171746349,5116788.75508474 393211.483891073,5116800.75530361 393192.546112027,5116813.75551748 393175.983368809,5116825.75571176 393149.857976147,5116838.75595065 393133.482745994,5116857.75622424 393114.544966382,5116870.75643831 393098.169735903,5116889.75671202 393086.419569485,5116902.75690122 393067.606797293,5116919.75716067 393056.231655549,5116945.75749706 393037.418884445,5116963.75776805 393033.04384287,5116982.75800023 393021.606196787,5117006.75831414 393015.106140246,5117038.75870223 393008.418569061,5117062.75899965 393004.168536393,5117086.75928857 392997.668478094,5117117.75966531 392993.543454455,5117146.76001093 392987.043397381,5117178.76039914 392987.793453825,5117209.76075054 392988.418505414,5117238.76107952 392989.168561865,5117269.76143089 392989.668601508,5117291.82418106 392989.981126498,5117305.76183911 392985.918606405,5117336.76220736 392986.731171,5117372.76261556 392987.418726433,5117403.76296708 392988.168784299,5117435.76332978 392981.606221287,5117464.76368403 392982.29377667,5117495.76403552 392983.043833052,5117526.76438677 392978.918811594,5117557.76475526 392972.418749256,5117586.76510935 392973.106305979,5117618.76547222 392961.668657377,5117642.76578678 392957.418623605,5117666.76607586 392943.54343573,5117690.76639915 392927.168201979,5117710.76668571 392915.418030818,5117722.76686452 392891.855181635,5117742.76717676 392872.917395103,5117754.76738123 392740.790424309,5117861.76907524 392717.040059422,5117873.7692973 392698.28978547,5117893.76959306 392681.727035677,5117905.76978954 392662.914256339,5117922.77005132 392651.16408497,5117935.77024211 392632.413809005,5117954.77052666 392608.288447914,5117974.89584341 392608.475965431,5117985.83346794 392585.663132786,5118011.77134664 392574.100471765,5118030.77160564 392562.600318191,5118054.77192172 392543.787538836,5118072.7721954 392532.224877397,5118091.77245454 392520.724723346,5118115.77277076 392509.162062944,5118135.77304143 392497.724409603,5118159.77335752 392486.161748931,5118179.77362828 392474.724095295,5118203.77394446 392463.223940494,5118227.77426091 392456.411352287,5118244.77448028 392443.81744214,5118278.61866355 392440.723664055,5118295.77512132 392426.910971326,5118319.77544629 392422.785945318,5118351.77582793 392416.160868597,5118375.77612696 392411.910830245,5118399.7764174 392405.410764244,5118430.77679624 392401.160725746,5118454.77708672 392394.660660804,5118486.77747706 392390.410622159,5118510.77776756 392383.848052215,5118539.7781238 392379.723024262,5118570.7784941 392380.473076701,5118602.77885811 392381.160626871,5118633.77921086 392381.973185368,5118669.77962043 392382.66073303,5118698.77995023 392383.348283211,5118729.78030293 392388.910912823,5118760.78063776 392389.598463053,5118791.78099041 392397.47362799,5118820.78129376 392398.286186632,5118856.78170317 392398.973736932,5118887.78205574 392399.723788257,5118918.78240806 392400.536346912,5118954.7828174 392394.036280934,5118986.78320784 392394.723831189,5119017.78356036 392402.786508491,5119053.7839429 392403.411555271,5119082.78427269 392408.849177143,5119108.78455032 392417.411893277,5119168.78520562 392417.974432822,5119192.7854783 392411.474365244,5119223.78585728 392407.349337824,5119255.78623893 392408.036884392,5119283.78655692 392408.911947902,5119322.78700013 392414.349572639,5119350.78730042 392415.224633688,5119387.78772067 392411.099604812,5119418.78809085 392411.787155176,5119449.78844309 392405.349588049,5119480.78882191 392405.974634815,5119509.78915149 392406.84969828,5119548.78959456 392407.537246085,5119577.78992386 392408.224796407,5119608.79027604 392409.037355083,5119644.79068494 392416.975025357,5119675.79100988 392417.66257575,5119706.79136198 392423.162703331,5119735.79167309 392423.850253773,5119766.79202514 392431.787924406,5119797.79234988 392437.10054279,5119821.79260439 392437.85059438,5119852.79295612 392440.631903442,5119863.0118125 392445.725761732,5119881.79325808 392451.225892287,5119912.79359182 392459.163563436,5119943.7939163 392459.663602176,5119967.79418881 392465.16373042,5119996.79449956 392473.101401848,5120027.79482389 392473.78895269,5120058.79517564 392481.726624313,5120089.79549988 392482.351671638,5120118.79582895 392483.101723595,5120149.79618038 392483.914282962,5120185.7965887 392484.601833886,5120216.79694033 392485.414393263,5120252.7973486 392486.164446509,5120284.79771139 392486.977005895,5120320.79811962 392492.477137348,5120351.7984528 392493.039677325,5120375.79872483 392500.977349717,5120406.79904862 392506.414977796,5120435.79935907 392514.352650416,5120466.79968275 392526.915390478,5120489.79989728 392539.353123455,5120508.80006657 392551.915865102,5120532.8002924 392564.353598353,5120551.80046157 392583.978948531,5120567.80056886 392600.010505845,5120597.11334179 392608.979424349,5120610.8009635 392621.417158159,5120629.80113245 392641.042509008,5120645.80123949 392658.105311672,5120657.80131071 392677.949415731,5120673.20766002 392702.106091439,5120687.8014834 392721.731446962,5120706.80162438 392738.856751236,5120718.80169515 392758.419602039,5120734.80180206 392775.544906569,5120746.80187274 392795.10775498,5120760.80195676 392814.670606259,5120776.8020635 392831.795911176,5120788.80213404 392851.421266561,5120806.80226318 392871.046620767,5120823.80238087 392883.484356665,5120842.80254903 392900.734673902,5120861.80269853 392908.547337548,5120884.80292997 392921.110082889,5120908.80315436 392926.422705908,5120932.80340675 392927.23526959,5120968.80381304 392923.17274389,5120999.80418134 392923.860299875,5121031.80454259 392917.360232791,5121062.80492038 392913.110194025,5121086.80520984 392901.672533419,5121110.80552728 392894.984954546,5121135.80583765 392883.547293661,5121159.80615517 392879.297254538,5121183.80644472 392872.609673993,5121207.80674378 392873.484742288,5121246.80718397 392874.172292332,5121274.80749975 392886.79754389,5121301.80775747 392899.172776234,5121317.80789102 392911.673014952,5121336.80805814 392924.235761778,5121360.8082818 392936.798508767,5121384.8085054 392949.23624684,5121403.80867259 392968.861603252,5121419.80877747 392981.299341611,5121438.80894455 393001.049710309,5121461.80912832 393010.924899806,5121476.90301098 393025.925184951,5121497.80943949 393038.362923867,5121516.80960635 393058.113293343,5121539.80978982 393070.613533636,5121558.80995632 393082.988769071,5121575.81010056 393107.301699889,5121586.81012968 393126.864554048,5121600.81021148 393143.927362765,5121612.81028039 393163.552721167,5121628.81038452 393175.990461243,5121647.81055094 393195.67832541,5121666.81068871 393208.24107521,5121690.81091119 393225.428892612,5121706.81102468 393244.929243869,5121718.81108366 393269.117168119,5121725.81106744 393300.36770149,5121724.81093268 393316.930465618,5121711.81072005 393340.680854092,5121699.81049043 393366.931291185,5121691.81029627 393395.494260176,5121678.81003645 393426.619784935,5121673.8098571 393457.870317864,5121672.80972254 393493.933433088,5121671.80956902 393525.246476345,5121676.80950206 393549.43439937,5121682.80947448 393580.809942319,5121686.80939592 393604.997867081,5121693.80937958 393629.310800374,5121704.80940789 393653.436221126,5121709.80936915 393672.936572303,5121720.80941637 393697.312011842,5121734.80947815 393714.374823146,5121746.80954619 393734.000184865,5121762.80964918 393758.313120639,5121774.80968847 393782.501044747,5121780.80966054 393813.876588865,5121784.80958162 393845.064623317,5121784.80945833 393869.377557989,5121795.80948618 393893.565484088,5121802.80946941 393913.253352945,5121821.80960556 393930.378664812,5121832.80966169 393949.879019183,5121844.80971963 393974.129453519,5121855.80974747 393980.567088586,5121870.55988801 394006.005040641,5121879.80989136 394035.005558621,5121891.80991148 394061.69354385,5121907.8099857 394090.694062249,5121919.81000568 394122.25713511,5121937.81008288 394153.757708931,5121956.81017145 394178.383194166,5121992.81047819 394222.321522601,5122034.81077535 394246.571967771,5122050.81085858 394270.947420551,5122069.8109749 394295.447896778,5122100.8112253 394315.073277083,5122124.81141642 394339.44873778,5122147.8115773 394355.355301223,5122169.96801237 394376.261957671,5122195.81196876 394395.887337237,5122218.81214828 394413.262692471,5122249.81242635 394432.950587952,5122280.81269506 394452.575970121,5122304.81288546 394469.951326235,5122335.81316318 394494.326789315,5122358.81332314 394513.952172303,5122382.81351323 394533.702570425,5122413.81378107 394550.890411741,5122437.81398072 394570.578303909,5122465.81421501 394587.828650453,5122491.81443659 394607.516545024,5122520.81468184 394620.079319934,5122551.814978 394639.642203691,5122575.81516761 394657.017560798,5122605.81543301 394676.767961315,5122636.8156999 394696.455857359,5122665.81594455 394713.643700911,5122689.81614332 394733.269090836,5122715.8163545 394745.519324584,5122726.81642786 394740.082037153,5122766.81665835 394764.832648369,5122789.81667434 394789.833325575,5122820.81673085 394817.146519537,5122848.81676288 394834.709504156,5122871.81680952 394859.522638279,5122897.81684226 394879.273106525,5122913.81684432 394904.023723511,5122937.81686765 394928.836848953,5122962.81689628 394955.774941809,5122978.81686992 394973.337932572,5123002.81692346 394998.151057066,5123027.81695315 395029.9017329,5123043.81690827 395058.496141839,5123064.81690259 395086.215481581,5123078.81686417 395110.841047887,5123096.81685942 395142.654238941,5123114.81682611 395171.842330564,5123125.81676686 395203.5305036,5123141.81672417 395235.343701373,5123160.81669716 395266.906833568,5123171.81662922 395303.282541552,5123181.81653703 395339.658256907,5123192.8164504 395371.221388458,5123203.81638321 395407.472063324,5123209.81627095 395439.222735558,5123225.81623018 395468.473349008,5123239.81618895 395495.598993273,5123262.81620467 395520.349596002,5123285.81623017 395537.912581366,5123309.81628975 395557.850600111,5123332.81633486 395578.03868312,5123363.81642235 395591.164181148,5123399.81656481 395596.977014847,5123430.81670912 395610.102504936,5123465.81684662 395623.102962563,5123496.81696328 395637.353749434,5123568.81729667 395645.91672001,5123611.81749581 395651.854592615,5123647.81766739 395653.417494831,5123697.81793139 395654.667824093,5123738.81814797 395656.043170504,5123781.81837485 395652.605941696,5123825.81862529 395641.731025185,5123861.81886043 395630.731076702,5123893.81907422 395619.731128427,5123925.81928775 395601.418532393,5123954.81951223 395590.418584587,5123986.8197252 395572.168505251,5124017.8199595 395556.168419549,5124042.82015293 395537.855824659,5124071.82037606 395534.231056787,5124110.82059811 395535.606404653,5124153.82082305 395544.981758839,5124179.53967623 395548.73190043,5124189.8209675 395561.669832457,5124217.82107007 395574.607786881,5124248.82118892 395592.420824241,5124279.8212903 395607.796319737,5124310.82140083 395625.484331816,5124338.82148718 395645.672408739,5124369.82158095 395663.42294382,5124400.82168386 395683.423456846,5124423.82173593 395703.549031724,5124454.821831 395721.112002747,5124477.82189239 395745.67504009,5124493.82189127 395772.800673097,5124516.8219192 395958.867494766,5124673.13461351 395977.555427812,5124688.82213398 396009.118543949,5124699.82208402 396040.931715948,5124717.82207188 396077.057357066,5124721.82196805 396120.495636621,5124727.82184993 396168.496434268,5124725.82167189 396211.684657849,5124724.82151611 396254.997912928,5124727.82138216 396291.248570403,5124733.82128959 396327.436734009,5124740.82120298 396363.812422571,5124750.8211327 396402.375604091,5124754.82102145 396438.751299561,5124765.82095723 396474.93945521,5124771.8208658 396511.315150251,5124782.82080208 396542.878263716,5124793.82075525 396579.253958297,5124804.82069207 396618.004692763,5124815.820621 396642.630239036,5124833.82063855 396667.130768482,5124849.82064543 396698.94393558,5124867.82063893 396716.506905183,5124891.82071572 396741.25748856,5124914.82076257 396768.383111651,5124937.8208017 396786.133633971,5124968.82091883 396794.321494945,5124999.82106858 396813.38483359,5125071.82141678 396826.385275015,5125102.82155089 396839.510747052,5125137.82170776 396854.8862279,5125168.82183446 396860.76158493,5125204.82202163 396869.136890501,5125227.82212598 396873.887063443,5125240.82218496 396882.324977473,5125278.82237547 396888.387873065,5125319.82259116 396896.950824709,5125362.82281031 396898.263654907,5125405.82305318 396904.451566561,5125448.82328028 396893.576642937,5125484.82352222 396889.889346691,5125521.82374655 396878.889385499,5125552.82395972 396860.639310797,5125584.82420152 396842.389214871,5125613.82442575 396819.201529806,5125641.82465958 396802.951381453,5125658.82480822 396772.513554689,5125683.82504716 396749.138309812,5125703.82523489 396725.700564154,5125723.82542252 396695.075184765,5125741.82562109 396671.63743966,5125761.82580809 396647.319162537,5125787.41633249 + + + + 392379.723024262 5111764.85524216440788.211689919 5184411.22069788 + 396647.319162537 5125787.41633249 396629.824563343 5125805.82618797 396606.574358413 5125830.8264017 396595.511885163 5125859.8265997 396577.261814638 5125891.82683664 396573.637016015 5125927.82705053 396574.949857411 5125971.82729413 396576.075137571 5126007.82749328 396582.263052331 5126050.82771637 396590.826006225 5126093.82793236 396596.701364704 5126129.82811725 396605.264318258 5126172.82833358 396618.389788858 5126207.82849133 396631.390228143 5126238.82862717 396644.515705503 5126274.82879108 396659.078702435 5126310.297698 396670.579120159 5126341.82909202 396683.579551284 5126371.82922318 396696.454972903 5126400.82934927 396716.643028971 5126431.82946552 396734.393537423 5126461.82958359 396754.581592814 5126492.82970056 396774.519586055 5126515.82977324 396792.082547279 5126539.82985873 396819.083119819 5126557.82988318 396855.458795444 5126568.82984108 396898.396942019 5126560.82967184 396939.022558013 5126553.8295148 396969.772954926 5126538.82934018 396993.21071066 5126520.82916915 397016.460920688 5126496.82896388 397027.460872742 5126464.82874777 397045.710944138 5126432.82851025 397056.585866089 5126396.82827085 397062.648201959 5126359.82803953 397066.08545198 5126316.82778114 397067.835406618 5126306.42146587 397072.147795239 5126280.82755525 397075.835099479 5126244.82733626 397081.647381872 5126200.82706453 397092.459782577 5126161.82680651 397103.334705913 5126125.82656536 397121.772332701 5126100.82636484 397132.772294143 5126069.82615172 397148.834882151 5126044.82595783 397160.553757661 5126035.20086627 397179.272708267 5126019.82571988 397202.647953329 5125999.82553214 397233.335833894 5125981.82533342 397269.086369297 5125973.82517735 397305.337011941 5125979.82510165 397344.087731071 5125990.82504784 397373.463344054 5126008.82506407 397397.963862016 5126024.82508369 397425.151973375 5126047.82513668 397438.089904983 5126078.82528037 397444.027755832 5126114.82547489 397445.590639645 5126165.82577112 397454.091060634 5126205.82598176 397460.091433225 5126244.8261941 397468.529352856 5126284.82640523 397471.34202389 5126302.60775191 397474.529718163 5126322.82661191 397494.655252618 5126351.82672409 397507.593182574 5126382.82686947 397527.781224448 5126412.82698805 397545.344180905 5126436.82707907 397565.46972113 5126466.82719851 397578.407636095 5126495.82733311 397591.595617786 5126533.82752065 397604.4710243 5126561.82764997 397612.783911683 5126597.82784006 397618.971812944 5126640.82807793 397627.534752913 5126683.82830922 397628.847581176 5126727.82856701 397635.035482062 5126770.82880521 397643.3483687 5126806.828996 397645.004726745 5126818.4540605 397649.473768279 5126849.82923463 397657.786647643 5126884.82941976 397670.912112201 5126920.82959777 397690.850103905 5126944.82968593 397703.850524161 5126974.8298291 397721.601028402 5127005.82996553 397741.664049093 5127033.83007812 397761.664540702 5127057.83016732 397766.539781408 5127081.11154329 397769.602433453 5127095.8616232 397772.545330568 5127866.83496574 397799.55716051 5129508.84465574 397831.568827347 5131116.8540907 397844.579951222 5132687.86328606 397841.591240943 5134313.87274973 397847.602616648 5135930.88208476 397871.614199177 5137540.89132351 397907.625956819 5139153.90054444 397932.637595763 5140770.90973277 397947.649143106 5142391.91887313 397962.660579673 5143995.92785993 397972.671962545 5145598.93676736 397971.683228179 5147199.94555985 397981.694931268 5148843.95455868 397986.706260507 5150439.96320876 397990.753525199 5152039.92440306 398061.802940095 5153673.8844116 398044.852873508 5155360.84277007 398049.901485214 5156996.80243326 398075.949416946 5158601.76287673 398059.997632782 5160238.72242226 398074.045935741 5161865.68223921 398079.094836043 5163519.64134919 398121.172223473 5165059.66575611 397524.818123527 5165067.79049237 397026.153268514 5165076.32148286 397059.169441951 5166697.56308368 397074.216493664 5168318.52340502 397070.262855338 5169930.48393691 397080.309523306 5171545.44435402 397136.356979965 5173154.40478628 397156.403121981 5174745.3656852 397292.452470757 5176353.32576343 397351.500174909 5177964.28589945 397410.545932918 5179591.26622548 397438.590081989 5181207.25121208 397484.635123672 5182839.23587902 397568.67961072 5184411.22069788 399155.722151603 5184365.20819777 400767.765827735 5184336.19538155 402376.809351054 5184305.18266293 403893.850467498 5184279.17067505 405509.88661979 5184240.16416644 407127.917199638 5184205.16237558 408731.947575327 5184173.16060055 410320.977603268 5184140.15890349 411927.0077774 5184102.15730687 413468.035170976 5184019.156598 415034.06331545 5183946.15575987 416630.092083367 5183876.15490039 418239.122759583 5183856.15320425 419845.153118906 5183829.1516743 421418.182848745 5183803.15020699 423021.215323013 5183838.14759326 424640.227328401 5183826.1287231 426250.225657675 5183796.09869613 427926.224039936 5183768.06739585 429532.222317095 5183736.03751201 431126.220916499 5183713.00771019 432729.219448619 5183687.97779001 434321.217792016 5183656.94819719 435909.216377732 5183632.91857415 437519.214606452 5183597.88873491 439133.213072692 5183569.8587156 440447.274474624 5183551.58421118 440788.211689919 5183546.82785545 440774.193317489 5182959.24389991 440750.161804751 5181951.85443125 440731.830135607 5181339.36469896 440702.111525844 5180345.88134396 440684.750599837 5179797.67179249 440651.06097089 5178732.9083982 440650.699677025 5178172.94869223 440650.014973456 5177123.92495227 440637.563766231 5176535.7995613 440615.977504472 5175516.92387936 440604.370555919 5174951.2984902 440582.9399676 5173908.92276828 440572.989475617 5173352.60984766 440553.902074748 5172286.92153435 440537.889487585 5171749.7025147 440506.865079036 5170708.92074466 440497.446274702 5170172.6390742 440478.827657615 5169110.91948283 440467.877617866 5168576.200343 440445.789838809 5167498.91830244 440442.465107261 5166975.79273044 440435.75289353 5165918.916557 440429.239983656 5165367.88476372 440416.715119515 5164306.91495392 440422.825660397 5163685.13271532 440432.67738969 5162683.9123425 440435.976045197 5162089.00518069 440441.639697625 5161063.90983245 440435.50090148 5160474.87791456 440428.731220104 5159825.84576899 440394.891556092 5159824.69064082 440168.295395738 5159825.88464183 439928.95258192 5159831.79768159 439920.105839013 5159851.92304252 439837.293205181 5159883.92545398 439428.658644014 5159666.93696318 439389.43905896 5159649.78182603 438955.523526871 5159460.20043565 438868.021643891 5159421.9529385 438820.677249212 5159416.79805414 438546.704763059 5159386.9622125 437912.69554087 5159295.9805468 437842.257240392 5159295.10758917 437834.549029165 5158459.98268407 437837.784713312 5157878.73248683 437843.509384072 5156849.98210987 437843.494396201 5156242.79447432 437843.469251102 5155223.98172365 437837.429981925 5153635.98146622 437791.389300783 5152014.98244466 437697.348137997 5150407.98503925 437702.333741618 5148765.97566464 437727.330981757 5147211.9625931 437726.327686801 5145591.94983279 437725.324428085 5143976.93706535 437725.321201069 5142354.92416177 437736.318211385 5140725.91078311 437718.314733817 5139136.89865929 437698.311182421 5137532.88643811 437665.307315615 5135919.8745398 437648.303832046 5134323.86219173 437641.300538971 5132700.84923972 437635.297323898 5131096.83636224 437625.294012361 5129486.82352584 437598.290210678 5127849.81099969 437573.286513144 5126246.79863957 437546.282736399 5124637.78625312 437519.278954217 5123033.77386323 437509.98489396 5122463.40794018 437527.027817008 5122305.58004155 437534.527896677 5122230.61041166 437549.528288354 5122205.1096879 437591.404435887 5122162.35790414 437614.748826392 5122138.54440989 437637.155825486 5122098.543979 437649.749976677 5122084.512416 437689.782536252 5122024.98029865 437750.12819346 5121963.47875683 437838.380916 5121901.57002048 438017.948835643 5121826.06454523 438058.606268627 5121828.21939093 438155.890192362 5121903.34042007 438237.736223155 5121953.39968798 438306.488190201 5121972.92841773 438377.709007713 5121979.89467277 438461.242758608 5121953.57955277 438496.493851218 5121925.35985063 438536.401429659 5121851.26540118 438546.089318335 5121802.82800448 438548.558156946 5121795.26548809 438582.028332704 5121589.10994768 438596.591390315 5121527.9850023 438608.466924173 5121441.5166267 438623.813339239 5121376.09834029 437492.278289034 5121376.77370461 437489.281897405 5119808.78685956 437484.285556978 5118193.80044963 437485.289502675 5116528.81424446 437456.292405097 5114947.82823075 437452.2960581 5113347.84157795 437431.299201951 5111764.85524216 435862.25607009 5111768.89945371 434242.211499074 5111795.9449713 432640.167442508 5111821.99004314 431057.123883495 5111860.03457731 429450.079784996 5111869.07996791 427689.031503852 5111876.12973772 426075.987253384 5111896.17531676 424471.943303663 5111909.22068335 422855.899076511 5111917.26641124 421230.245048103 5111933.30087059 419693.843452792 5111956.33283067 417964.469828952 5111966.36879395 416363.067141303 5111988.40214818 414771.7584298 5111973.43514807 413159.168052034 5111993.46874153 411548.296462609 5112009.50229384 409948.518902999 5112091.53610421 408231.145662077 5112170.57246601 406647.680959646 5112207.60578157 405044.934660928 5112231.63941539 403453.563699325 5112279.67291954 401873.540795608 5112322.6780784 400243.517022892 5112330.68303475 398556.492460839 5112347.68827534 396933.468840334 5112364.69334166 395351.445842091 5112389.69839127 393853.36157894 5112421.64078434 393859.299199886 5112441.70349511 393847.736572546 5112465.70380383 393843.674086977 5112508.70430647 393837.111552817 5112544.70473691 393845.049242344 5112587.70520303 393850.486883488 5112623.70559688 393863.112129893 5112659.70596873 393882.862472251 5112690.70626172 393895.237694829 5112714.70649737 393914.988037748 5112745.70679013 393932.300840051 5112773.70705606 393951.926169584 5112797.70726924 393969.238977644 5112828.70756912 393996.051911514 5112851.70774863 394013.302206987 5112875.70796879 394033.052551765 5112906.70826081 394045.552790225 5112937.70857504 394058.178039574 5112973.70894566 394065.990716505 5113008.70931965 394078.553456494 5113039.70963341 394091.116196692 5113070.70994707 394103.741446914 5113106.7103173 394121.054257676 5113137.71061607 394135.992030064 5113166.71089934 394148.492270238 5113197.71121282 394159.961246877 5113229.555289 394160.023832358 5113276.71207453 394160.086424654 5113327.68140335 394149.617585741 5113364.68185631 394144.680060856 5113391.71342881 394133.367462626 5113430.71390723 394126.742428434 5113466.71433695 394110.492242135 5113497.71474007 394104.117234372 5113546.7153168 394104.867321865 5113589.715803 394093.492216285 5113625.71624779 394082.117110468 5113661.71669265 394077.929611646 5113697.7171149 394071.4295835 5113736.71757855 394060.054477088 5113772.71802356 394048.67937044 5113808.71846863 394042.054334609 5113844.71889871 394042.804423075 5113888.71939632 394043.554509784 5113931.71988254 394051.429691031 5113967.72026654 394056.929849101 5114010.72073754 394069.555101945 5114046.72110623 394077.367782725 5114082.72149018 394090.055540472 5114120.72188119 394090.743123231 5114161.72234455 394098.74331963 5114204.72280715 394099.493406947 5114247.72329291 394104.993565904 5114290.72376339 394124.743913448 5114318.72401772 394137.244157168 5114349.72432931 394149.869411885 5114385.72469713 394167.682245546 5114421.88129988 394186.807568417 5114440.72520192 394211.245479328 5114463.72538385 394237.995918334 5114482.72551285 394267.121393583 5114501.72563407 394298.496888663 5114512.72565728 394322.809787916 5114529.72577122 394354.372799104 5114547.72587293 394383.373260707 5114559.72591491 394414.87377337 5114578.72602795 394446.31177054 5114589.72605056 394477.812278199 5114605.72612945 394506.812740696 5114617.72617113 394531.250660501 5114643.7263858 394550.876001888 5114666.72658206 394563.376246602 5114695.72686919 394571.313948641 5114738.72732926 394596.001896305 5114776.72767818 394601.377046541 5114812.7280673 394597.377067299 5114855.72856603 394590.752034629 5114891.7289943 394579.376931218 5114928.72944943 394566.470547747 5114962.32362117 394551.626620873 5114988.73021814 394532.87638519 5115015.7305847 394514.126143602 5115039.73091745 394490.500829059 5115064.73127761 394466.875503023 5115083.73157005 394448.125269927 5115112.73195959 394424.562455412 5115137.73231986 394408.249755359 5115164.73267895 394389.49952137 5115193.73306878 394370.874292663 5115224.73348092 394354.499087194 5115249.73381784 394330.873768359 5115273.73416751 394292.935731185 5115298.73457599 394269.247901644 5115317.73486951 394252.872695053 5115342.73520681 394239.060047403 5115378.73566023 394222.747343077 5115404.7360088 394204.059609094 5115434.73641064 394187.809414129 5115465.73681579 394169.121683087 5115497.73724048 394157.621557243 5115526.73760732 394138.933823844 5115557.73802086 394127.496203812 5115589.73842162 394111.183502991 5115618.73880474 394097.37084405 5115649.73920224 394088.55823042 5115662.61437765 394080.933132024 5115673.73952926 394062.307899905 5115705.73995438 394046.057702473 5115736.74036029 394034.557574845 5115765.74072766 394020.682415429 5115797.74113709 394004.494726822 5115833.74159972 393997.869679337 5115865.74198489 393986.494564888 5115901.74243145 393975.119453643 5115939.74290076 393963.744340432 5115976.7433588 393952.306715737 5116007.74374905 393933.618974614 5116036.74414123 393917.243760681 5116060.74446893 393893.680939688 5116087.74485512 393874.86818897 5116112.74520261 393861.180482468 5116116.74529445 393854.61792906 5116145.74564587 393850.430407537 5116171.74595519 393841.930304956 5116189.58993661 393825.117594874 5116220.74659747 393813.554946164 5116239.74685252 393797.054710209 5116252.74705632 393778.241944662 5116269.74731346 393761.866720345 5116288.74758506 393747.866531327 5116306.74783726 393731.491306684 5116325.74810897 393712.553531926 5116338.74832133 393696.178306954 5116357.74859315 393670.302942922 5116382.74896571 393653.802704186 5116394.74915854 393642.240055644 5116414.74942545 393623.552301824 5116438.74976227 393611.927147149 5116455.74999538 393600.552012397 5116482.75034137 393588.926857469 5116499.75057455 393577.489216607 5116523.75088674 393565.926567222 5116543.75115391 393554.36391611 5116562.75140974 393542.86377383 5116586.75172227 393519.113442233 5116612.84585085 393512.488355425 5116623.75224775 393500.925705356 5116643.75251513 393482.112936403 5116660.75277343 393465.550194804 5116672.75296711 393439.424804218 5116685.75320523 393415.736950249 5116697.75342361 393391.86158697 5116705.75359715 393368.111233285 5116718.75382724 393344.360877897 5116730.754046 393320.548015241 5116738.75421946 393301.610235368 5116750.75442168 393277.859881082 5116763.754652 393254.109525117 5116775.75487097 393235.171746349 5116788.75508474 393211.483891073 5116800.75530361 393192.546112027 5116813.75551748 393175.983368809 5116825.75571176 393149.857976147 5116838.75595065 393133.482745994 5116857.75622424 393114.544966382 5116870.75643831 393098.169735903 5116889.75671202 393086.419569485 5116902.75690122 393067.606797293 5116919.75716067 393056.231655549 5116945.75749706 393037.418884445 5116963.75776805 393033.04384287 5116982.75800023 393021.606196787 5117006.75831414 393015.106140246 5117038.75870223 393008.418569061 5117062.75899965 393004.168536393 5117086.75928857 392997.668478094 5117117.75966531 392993.543454455 5117146.76001093 392987.043397381 5117178.76039914 392987.793453825 5117209.76075054 392988.418505414 5117238.76107952 392989.168561865 5117269.76143089 392989.668601508 5117291.82418106 392989.981126498 5117305.76183911 392985.918606405 5117336.76220736 392986.731171 5117372.76261556 392987.418726433 5117403.76296708 392988.168784299 5117435.76332978 392981.606221287 5117464.76368403 392982.29377667 5117495.76403552 392983.043833052 5117526.76438677 392978.918811594 5117557.76475526 392972.418749256 5117586.76510935 392973.106305979 5117618.76547222 392961.668657377 5117642.76578678 392957.418623605 5117666.76607586 392943.54343573 5117690.76639915 392927.168201979 5117710.76668571 392915.418030818 5117722.76686452 392891.855181635 5117742.76717676 392872.917395103 5117754.76738123 392740.790424309 5117861.76907524 392717.040059422 5117873.7692973 392698.28978547 5117893.76959306 392681.727035677 5117905.76978954 392662.914256339 5117922.77005132 392651.16408497 5117935.77024211 392632.413809005 5117954.77052666 392608.288447914 5117974.89584341 392608.475965431 5117985.83346794 392585.663132786 5118011.77134664 392574.100471765 5118030.77160564 392562.600318191 5118054.77192172 392543.787538836 5118072.7721954 392532.224877397 5118091.77245454 392520.724723346 5118115.77277076 392509.162062944 5118135.77304143 392497.724409603 5118159.77335752 392486.161748931 5118179.77362828 392474.724095295 5118203.77394446 392463.223940494 5118227.77426091 392456.411352287 5118244.77448028 392443.81744214 5118278.61866355 392440.723664055 5118295.77512132 392426.910971326 5118319.77544629 392422.785945318 5118351.77582793 392416.160868597 5118375.77612696 392411.910830245 5118399.7764174 392405.410764244 5118430.77679624 392401.160725746 5118454.77708672 392394.660660804 5118486.77747706 392390.410622159 5118510.77776756 392383.848052215 5118539.7781238 392379.723024262 5118570.7784941 392380.473076701 5118602.77885811 392381.160626871 5118633.77921086 392381.973185368 5118669.77962043 392382.66073303 5118698.77995023 392383.348283211 5118729.78030293 392388.910912823 5118760.78063776 392389.598463053 5118791.78099041 392397.47362799 5118820.78129376 392398.286186632 5118856.78170317 392398.973736932 5118887.78205574 392399.723788257 5118918.78240806 392400.536346912 5118954.7828174 392394.036280934 5118986.78320784 392394.723831189 5119017.78356036 392402.786508491 5119053.7839429 392403.411555271 5119082.78427269 392408.849177143 5119108.78455032 392417.411893277 5119168.78520562 392417.974432822 5119192.7854783 392411.474365244 5119223.78585728 392407.349337824 5119255.78623893 392408.036884392 5119283.78655692 392408.911947902 5119322.78700013 392414.349572639 5119350.78730042 392415.224633688 5119387.78772067 392411.099604812 5119418.78809085 392411.787155176 5119449.78844309 392405.349588049 5119480.78882191 392405.974634815 5119509.78915149 392406.84969828 5119548.78959456 392407.537246085 5119577.78992386 392408.224796407 5119608.79027604 392409.037355083 5119644.79068494 392416.975025357 5119675.79100988 392417.66257575 5119706.79136198 392423.162703331 5119735.79167309 392423.850253773 5119766.79202514 392431.787924406 5119797.79234988 392437.10054279 5119821.79260439 392437.85059438 5119852.79295612 392440.631903442 5119863.0118125 392445.725761732 5119881.79325808 392451.225892287 5119912.79359182 392459.163563436 5119943.7939163 392459.663602176 5119967.79418881 392465.16373042 5119996.79449956 392473.101401848 5120027.79482389 392473.78895269 5120058.79517564 392481.726624313 5120089.79549988 392482.351671638 5120118.79582895 392483.101723595 5120149.79618038 392483.914282962 5120185.7965887 392484.601833886 5120216.79694033 392485.414393263 5120252.7973486 392486.164446509 5120284.79771139 392486.977005895 5120320.79811962 392492.477137348 5120351.7984528 392493.039677325 5120375.79872483 392500.977349717 5120406.79904862 392506.414977796 5120435.79935907 392514.352650416 5120466.79968275 392526.915390478 5120489.79989728 392539.353123455 5120508.80006657 392551.915865102 5120532.8002924 392564.353598353 5120551.80046157 392583.978948531 5120567.80056886 392600.010505845 5120597.11334179 392608.979424349 5120610.8009635 392621.417158159 5120629.80113245 392641.042509008 5120645.80123949 392658.105311672 5120657.80131071 392677.949415731 5120673.20766002 392702.106091439 5120687.8014834 392721.731446962 5120706.80162438 392738.856751236 5120718.80169515 392758.419602039 5120734.80180206 392775.544906569 5120746.80187274 392795.10775498 5120760.80195676 392814.670606259 5120776.8020635 392831.795911176 5120788.80213404 392851.421266561 5120806.80226318 392871.046620767 5120823.80238087 392883.484356665 5120842.80254903 392900.734673902 5120861.80269853 392908.547337548 5120884.80292997 392921.110082889 5120908.80315436 392926.422705908 5120932.80340675 392927.23526959 5120968.80381304 392923.17274389 5120999.80418134 392923.860299875 5121031.80454259 392917.360232791 5121062.80492038 392913.110194025 5121086.80520984 392901.672533419 5121110.80552728 392894.984954546 5121135.80583765 392883.547293661 5121159.80615517 392879.297254538 5121183.80644472 392872.609673993 5121207.80674378 392873.484742288 5121246.80718397 392874.172292332 5121274.80749975 392886.79754389 5121301.80775747 392899.172776234 5121317.80789102 392911.673014952 5121336.80805814 392924.235761778 5121360.8082818 392936.798508767 5121384.8085054 392949.23624684 5121403.80867259 392968.861603252 5121419.80877747 392981.299341611 5121438.80894455 393001.049710309 5121461.80912832 393010.924899806 5121476.90301098 393025.925184951 5121497.80943949 393038.362923867 5121516.80960635 393058.113293343 5121539.80978982 393070.613533636 5121558.80995632 393082.988769071 5121575.81010056 393107.301699889 5121586.81012968 393126.864554048 5121600.81021148 393143.927362765 5121612.81028039 393163.552721167 5121628.81038452 393175.990461243 5121647.81055094 393195.67832541 5121666.81068871 393208.24107521 5121690.81091119 393225.428892612 5121706.81102468 393244.929243869 5121718.81108366 393269.117168119 5121725.81106744 393300.36770149 5121724.81093268 393316.930465618 5121711.81072005 393340.680854092 5121699.81049043 393366.931291185 5121691.81029627 393395.494260176 5121678.81003645 393426.619784935 5121673.8098571 393457.870317864 5121672.80972254 393493.933433088 5121671.80956902 393525.246476345 5121676.80950206 393549.43439937 5121682.80947448 393580.809942319 5121686.80939592 393604.997867081 5121693.80937958 393629.310800374 5121704.80940789 393653.436221126 5121709.80936915 393672.936572303 5121720.80941637 393697.312011842 5121734.80947815 393714.374823146 5121746.80954619 393734.000184865 5121762.80964918 393758.313120639 5121774.80968847 393782.501044747 5121780.80966054 393813.876588865 5121784.80958162 393845.064623317 5121784.80945833 393869.377557989 5121795.80948618 393893.565484088 5121802.80946941 393913.253352945 5121821.80960556 393930.378664812 5121832.80966169 393949.879019183 5121844.80971963 393974.129453519 5121855.80974747 393980.567088586 5121870.55988801 394006.005040641 5121879.80989136 394035.005558621 5121891.80991148 394061.69354385 5121907.8099857 394090.694062249 5121919.81000568 394122.25713511 5121937.81008288 394153.757708931 5121956.81017145 394178.383194166 5121992.81047819 394222.321522601 5122034.81077535 394246.571967771 5122050.81085858 394270.947420551 5122069.8109749 394295.447896778 5122100.8112253 394315.073277083 5122124.81141642 394339.44873778 5122147.8115773 394355.355301223 5122169.96801237 394376.261957671 5122195.81196876 394395.887337237 5122218.81214828 394413.262692471 5122249.81242635 394432.950587952 5122280.81269506 394452.575970121 5122304.81288546 394469.951326235 5122335.81316318 394494.326789315 5122358.81332314 394513.952172303 5122382.81351323 394533.702570425 5122413.81378107 394550.890411741 5122437.81398072 394570.578303909 5122465.81421501 394587.828650453 5122491.81443659 394607.516545024 5122520.81468184 394620.079319934 5122551.814978 394639.642203691 5122575.81516761 394657.017560798 5122605.81543301 394676.767961315 5122636.8156999 394696.455857359 5122665.81594455 394713.643700911 5122689.81614332 394733.269090836 5122715.8163545 394745.519324584 5122726.81642786 394740.082037153 5122766.81665835 394764.832648369 5122789.81667434 394789.833325575 5122820.81673085 394817.146519537 5122848.81676288 394834.709504156 5122871.81680952 394859.522638279 5122897.81684226 394879.273106525 5122913.81684432 394904.023723511 5122937.81686765 394928.836848953 5122962.81689628 394955.774941809 5122978.81686992 394973.337932572 5123002.81692346 394998.151057066 5123027.81695315 395029.9017329 5123043.81690827 395058.496141839 5123064.81690259 395086.215481581 5123078.81686417 395110.841047887 5123096.81685942 395142.654238941 5123114.81682611 395171.842330564 5123125.81676686 395203.5305036 5123141.81672417 395235.343701373 5123160.81669716 395266.906833568 5123171.81662922 395303.282541552 5123181.81653703 395339.658256907 5123192.8164504 395371.221388458 5123203.81638321 395407.472063324 5123209.81627095 395439.222735558 5123225.81623018 395468.473349008 5123239.81618895 395495.598993273 5123262.81620467 395520.349596002 5123285.81623017 395537.912581366 5123309.81628975 395557.850600111 5123332.81633486 395578.03868312 5123363.81642235 395591.164181148 5123399.81656481 395596.977014847 5123430.81670912 395610.102504936 5123465.81684662 395623.102962563 5123496.81696328 395637.353749434 5123568.81729667 395645.91672001 5123611.81749581 395651.854592615 5123647.81766739 395653.417494831 5123697.81793139 395654.667824093 5123738.81814797 395656.043170504 5123781.81837485 395652.605941696 5123825.81862529 395641.731025185 5123861.81886043 395630.731076702 5123893.81907422 395619.731128427 5123925.81928775 395601.418532393 5123954.81951223 395590.418584587 5123986.8197252 395572.168505251 5124017.8199595 395556.168419549 5124042.82015293 395537.855824659 5124071.82037606 395534.231056787 5124110.82059811 395535.606404653 5124153.82082305 395544.981758839 5124179.53967623 395548.73190043 5124189.8209675 395561.669832457 5124217.82107007 395574.607786881 5124248.82118892 395592.420824241 5124279.8212903 395607.796319737 5124310.82140083 395625.484331816 5124338.82148718 395645.672408739 5124369.82158095 395663.42294382 5124400.82168386 395683.423456846 5124423.82173593 395703.549031724 5124454.821831 395721.112002747 5124477.82189239 395745.67504009 5124493.82189127 395772.800673097 5124516.8219192 395958.867494766 5124673.13461351 395977.555427812 5124688.82213398 396009.118543949 5124699.82208402 396040.931715948 5124717.82207188 396077.057357066 5124721.82196805 396120.495636621 5124727.82184993 396168.496434268 5124725.82167189 396211.684657849 5124724.82151611 396254.997912928 5124727.82138216 396291.248570403 5124733.82128959 396327.436734009 5124740.82120298 396363.812422571 5124750.8211327 396402.375604091 5124754.82102145 396438.751299561 5124765.82095723 396474.93945521 5124771.8208658 396511.315150251 5124782.82080208 396542.878263716 5124793.82075525 396579.253958297 5124804.82069207 396618.004692763 5124815.820621 396642.630239036 5124833.82063855 396667.130768482 5124849.82064543 396698.94393558 5124867.82063893 396716.506905183 5124891.82071572 396741.25748856 5124914.82076257 396768.383111651 5124937.8208017 396786.133633971 5124968.82091883 396794.321494945 5124999.82106858 396813.38483359 5125071.82141678 396826.385275015 5125102.82155089 396839.510747052 5125137.82170776 396854.8862279 5125168.82183446 396860.76158493 5125204.82202163 396869.136890501 5125227.82212598 396873.887063443 5125240.82218496 396882.324977473 5125278.82237547 396888.387873065 5125319.82259116 396896.950824709 5125362.82281031 396898.263654907 5125405.82305318 396904.451566561 5125448.82328028 396893.576642937 5125484.82352222 396889.889346691 5125521.82374655 396878.889385499 5125552.82395972 396860.639310797 5125584.82420152 396842.389214871 5125613.82442575 396819.201529806 5125641.82465958 396802.951381453 5125658.82480822 396772.513554689 5125683.82504716 396749.138309812 5125703.82523489 396725.700564154 5125723.82542252 396695.075184765 5125741.82562109 396671.63743966 5125761.82580809 396647.319162537 5125787.41633249 - - - - 495302.815676504,5179229.61132198 496848.851735509,5179237.6171233 498462.889373269,5179247.62316423 500088.927078579,5179251.62748838 501695.962547851,5179211.60507996 503301.998167785,5179179.5824689 504914.034421812,5179180.55899068 506539.070830495,5179170.5356119 508151.107766549,5179225.51104065 509763.143811634,5179209.48807252 511387.180069969,5179185.46510066 513009.216520757,5179180.44179076 514626.252972295,5179185.41839672 516306.291369745,5179249.39311185 517916.328271882,5179332.36865748 519394.355935139,5179375.34611238 519525.325264365,5179380.28135453 521175.36375734,5179442.31544096 522796.370766589,5179501.28761151 524404.377615024,5179556.26010977 526019.384250467,5179566.23320789 527600.390098711,5179330.21047239 529189.396799056,5179301.18453868 530787.403635033,5179294.15814945 532381.410489906,5179317.13142772 533990.417465329,5179274.10537635 535605.424529336,5179255.07890249 537221.431611674,5179254.05218577 538756.412126805,5179248.02907838 540430.345259956,5179248.00759231 542032.28124317,5179264.98679513 543650.216504964,5179203.96679193 545321.149602686,5179201.94532802 546914.085935204,5179232.92441706 548516.021850388,5179243.90363668 550123.957608117,5179265.88261581 551741.892997035,5179287.86144805 553330.828407997,5179198.84213875 553351.810650603,5177595.86318564 553355.791643031,5175981.85334717 553383.771651848,5174368.84314128 553403.752034889,5172759.83301632 553427.732396188,5171162.82285219 553439.712858505,5169533.81262435 553470.693821533,5168011.80270507 554148.541998444,5167985.04144484 554149.79188147,5167979.13513634 554151.166735834,5167971.1663125 554174.155182149,5167046.78496991 554183.46475896,5166824.59587825 554191.772036319,5166399.53048851 554223.377252946,5164789.42574919 554224.189225934,5164746.42545538 554232.364692507,5163730.35619613 554234.549012593,5163461.97940743 554236.857683187,5163137.75850086 554240.601430421,5162608.34872624 554244.906755111,5162000.96967673 554246.778649942,5161738.18667267 554248.338695482,5161530.7477857 554248.525869733,5161503.15385152 554248.775540927,5161475.49741577 554251.271266753,5161113.58874818 554252.831221565,5160898.33730785 554253.579917212,5160787.86781934 554255.575923938,5160448.74055673 554255.700630369,5160423.74039029 554257.260422794,5160194.48885564 554259.007522042,5159949.14346083 554259.132296334,5159930.01833279 554259.381916446,5159897.95561735 554264.935552704,5159149.07558582 554270.426787606,5158408.69560226 554271.300335202,5158285.91352566 554274.045944533,5157915.09852562 554280.84758196,5156997.90483189 554282.532351766,5156767.34077324 554283.281150991,5156665.96508748 554287.274622583,5156114.61760652 554292.641004632,5155387.23767468 554294.825056096,5155096.329449 554295.012231495,5155068.89176298 554300.501530121,5154162.38562499 554303.745101346,5153617.78818249 554304.306478476,5153522.66253715 554304.556081921,5153489.22480916 554304.743230328,5153459.47460703 554312.041320595,5152239.34131381 554314.349359272,5151861.83874214 554323.893317074,5150293.26553368 554305.826173649,5149840.20040545 554302.700056984,5149446.01108743 554301.949803335,5149356.10442308 554302.135468315,5148767.66409191 554302.135402434,5148746.47648999 554302.822634196,5148667.69484551 554307.256891665,5147673.72120305 554308.068781662,5147486.59528035 554310.067648001,5147144.15607869 554319.374803053,5145529.42927739 554328.619462153,5143917.07743959 554332.054989073,5143322.07444199 554337.614206444,5142331.100688 554337.864068976,5142289.7879786 554338.986979247,5141635.15971549 554339.673131105,5141212.81385632 554339.735131423,5141054.4380685 554342.209073819,5140666.37355679 553744.439883277,5140665.6359454 552140.489637614,5140654.66904886 550514.540006892,5140624.70248202 548910.589773269,5140611.73553649 547286.07778693,5140615.76910864 545689.439928457,5140613.80205839 544190.486586884,5140616.8330177 542576.911810792,5140615.86630563 540952.837370015,5140612.89978375 539356.887082251,5140610.93267754 537734.925434632,5140604.9619813 536127.946556834,5140608.98539251 534329.970129577,5140608.01152846 532718.366168833,5140591.034837 531115.012187083,5140590.05813077 529512.033176919,5140583.08137621 527905.054220142,5140572.10465667 526302.075232683,5140570.12792372 524724.095912882,5140574.15084742 523113.117017892,5140575.1742278 521506.138065647,5140576.19754254 519900.159148136,5140564.22079982 518289.159252459,5140559.22819305 516683.142984441,5140571.22329294 515111.689717197,5140557.21843482 513527.89233112,5140574.21367801 511910.000819644,5140589.20884539 510293.828064161,5140601.204038 508669.592740126,5140609.19921645 507083.889113586,5140611.19450178 505559.498296073,5140634.19012381 503943.013177162,5140629.18532095 502322.652996529,5140626.1805358 500702.480180676,5140631.17582888 499099.925449201,5140637.18350592 497493.839733782,5140624.20112631 495769.747660932,5140613.22013602 495748.719955069,5142239.23124588 495748.693082425,5143884.24220147 495755.667156541,5145494.25280909 495760.64120287,5147100.26336865 495773.615683926,5148704.27380344 495770.605990571,5150333.28983519 495747.61601901,5151951.3123082 495746.626973123,5153550.33429246 495734.637160115,5155107.35571706 495738.648547533,5156735.37796876 495717.658886368,5158361.40025725 495797.673211287,5159977.23447586 495178.648737239,5159980.6429203 495145.659310535,5161586.4456535 495107.669755823,5163187.46698448 495112.681912028,5164799.4883054 495086.692865267,5166393.50936063 495088.705029187,5168017.53073455 495067.716229818,5169609.55161623 495126.729927639,5171207.57265376 495162.742991802,5172830.59400039 495197.755906868,5174450.61531256 495199.767500209,5176019.63582349 495238.783334567,5177631.64792968 495302.815676504,5179229.61132198 + + + + 495067.716229818 5140557.21843482554342.209073819 5179566.23320789 + 495302.815676504 5179229.61132198 496848.851735509 5179237.6171233 498462.889373269 5179247.62316423 500088.927078579 5179251.62748838 501695.962547851 5179211.60507996 503301.998167785 5179179.5824689 504914.034421812 5179180.55899068 506539.070830495 5179170.5356119 508151.107766549 5179225.51104065 509763.143811634 5179209.48807252 511387.180069969 5179185.46510066 513009.216520757 5179180.44179076 514626.252972295 5179185.41839672 516306.291369745 5179249.39311185 517916.328271882 5179332.36865748 519394.355935139 5179375.34611238 519525.325264365 5179380.28135453 521175.36375734 5179442.31544096 522796.370766589 5179501.28761151 524404.377615024 5179556.26010977 526019.384250467 5179566.23320789 527600.390098711 5179330.21047239 529189.396799056 5179301.18453868 530787.403635033 5179294.15814945 532381.410489906 5179317.13142772 533990.417465329 5179274.10537635 535605.424529336 5179255.07890249 537221.431611674 5179254.05218577 538756.412126805 5179248.02907838 540430.345259956 5179248.00759231 542032.28124317 5179264.98679513 543650.216504964 5179203.96679193 545321.149602686 5179201.94532802 546914.085935204 5179232.92441706 548516.021850388 5179243.90363668 550123.957608117 5179265.88261581 551741.892997035 5179287.86144805 553330.828407997 5179198.84213875 553351.810650603 5177595.86318564 553355.791643031 5175981.85334717 553383.771651848 5174368.84314128 553403.752034889 5172759.83301632 553427.732396188 5171162.82285219 553439.712858505 5169533.81262435 553470.693821533 5168011.80270507 554148.541998444 5167985.04144484 554149.79188147 5167979.13513634 554151.166735834 5167971.1663125 554174.155182149 5167046.78496991 554183.46475896 5166824.59587825 554191.772036319 5166399.53048851 554223.377252946 5164789.42574919 554224.189225934 5164746.42545538 554232.364692507 5163730.35619613 554234.549012593 5163461.97940743 554236.857683187 5163137.75850086 554240.601430421 5162608.34872624 554244.906755111 5162000.96967673 554246.778649942 5161738.18667267 554248.338695482 5161530.7477857 554248.525869733 5161503.15385152 554248.775540927 5161475.49741577 554251.271266753 5161113.58874818 554252.831221565 5160898.33730785 554253.579917212 5160787.86781934 554255.575923938 5160448.74055673 554255.700630369 5160423.74039029 554257.260422794 5160194.48885564 554259.007522042 5159949.14346083 554259.132296334 5159930.01833279 554259.381916446 5159897.95561735 554264.935552704 5159149.07558582 554270.426787606 5158408.69560226 554271.300335202 5158285.91352566 554274.045944533 5157915.09852562 554280.84758196 5156997.90483189 554282.532351766 5156767.34077324 554283.281150991 5156665.96508748 554287.274622583 5156114.61760652 554292.641004632 5155387.23767468 554294.825056096 5155096.329449 554295.012231495 5155068.89176298 554300.501530121 5154162.38562499 554303.745101346 5153617.78818249 554304.306478476 5153522.66253715 554304.556081921 5153489.22480916 554304.743230328 5153459.47460703 554312.041320595 5152239.34131381 554314.349359272 5151861.83874214 554323.893317074 5150293.26553368 554305.826173649 5149840.20040545 554302.700056984 5149446.01108743 554301.949803335 5149356.10442308 554302.135468315 5148767.66409191 554302.135402434 5148746.47648999 554302.822634196 5148667.69484551 554307.256891665 5147673.72120305 554308.068781662 5147486.59528035 554310.067648001 5147144.15607869 554319.374803053 5145529.42927739 554328.619462153 5143917.07743959 554332.054989073 5143322.07444199 554337.614206444 5142331.100688 554337.864068976 5142289.7879786 554338.986979247 5141635.15971549 554339.673131105 5141212.81385632 554339.735131423 5141054.4380685 554342.209073819 5140666.37355679 553744.439883277 5140665.6359454 552140.489637614 5140654.66904886 550514.540006892 5140624.70248202 548910.589773269 5140611.73553649 547286.07778693 5140615.76910864 545689.439928457 5140613.80205839 544190.486586884 5140616.8330177 542576.911810792 5140615.86630563 540952.837370015 5140612.89978375 539356.887082251 5140610.93267754 537734.925434632 5140604.9619813 536127.946556834 5140608.98539251 534329.970129577 5140608.01152846 532718.366168833 5140591.034837 531115.012187083 5140590.05813077 529512.033176919 5140583.08137621 527905.054220142 5140572.10465667 526302.075232683 5140570.12792372 524724.095912882 5140574.15084742 523113.117017892 5140575.1742278 521506.138065647 5140576.19754254 519900.159148136 5140564.22079982 518289.159252459 5140559.22819305 516683.142984441 5140571.22329294 515111.689717197 5140557.21843482 513527.89233112 5140574.21367801 511910.000819644 5140589.20884539 510293.828064161 5140601.204038 508669.592740126 5140609.19921645 507083.889113586 5140611.19450178 505559.498296073 5140634.19012381 503943.013177162 5140629.18532095 502322.652996529 5140626.1805358 500702.480180676 5140631.17582888 499099.925449201 5140637.18350592 497493.839733782 5140624.20112631 495769.747660932 5140613.22013602 495748.719955069 5142239.23124588 495748.693082425 5143884.24220147 495755.667156541 5145494.25280909 495760.64120287 5147100.26336865 495773.615683926 5148704.27380344 495770.605990571 5150333.28983519 495747.61601901 5151951.3123082 495746.626973123 5153550.33429246 495734.637160115 5155107.35571706 495738.648547533 5156735.37796876 495717.658886368 5158361.40025725 495797.673211287 5159977.23447586 495178.648737239 5159980.6429203 495145.659310535 5161586.4456535 495107.669755823 5163187.46698448 495112.681912028 5164799.4883054 495086.692865267 5166393.50936063 495088.705029187 5168017.53073455 495067.716229818 5169609.55161623 495126.729927639 5171207.57265376 495162.742991802 5172830.59400039 495197.755906868 5174450.61531256 495199.767500209 5176019.63582349 495238.783334567 5177631.64792968 495302.815676504 5179229.61132198 - - - - 495769.747660932,5140613.22013602 497493.839733782,5140624.20112631 499099.925449201,5140637.18350592 500702.480180676,5140631.17582888 502322.652996529,5140626.1805358 503943.013177162,5140629.18532095 505559.498296073,5140634.19012381 507083.889113586,5140611.19450178 508669.592740126,5140609.19921645 510293.828064161,5140601.204038 511910.000819644,5140589.20884539 513527.89233112,5140574.21367801 515111.689717197,5140557.21843482 516683.142984441,5140571.22329294 518289.159252459,5140559.22819305 519900.159148136,5140564.22079982 521506.138065647,5140576.19754254 523113.117017892,5140575.1742278 524724.095912882,5140574.15084742 526302.075232683,5140570.12792372 527905.054220142,5140572.10465667 529512.033176919,5140583.08137621 531115.012187083,5140590.05813077 532718.366168833,5140591.034837 534329.970129577,5140608.01152846 536127.946556834,5140608.98539251 537734.925434632,5140604.9619813 539356.887082251,5140610.93267754 540952.837370015,5140612.89978375 542576.911810792,5140615.86630563 544190.486586884,5140616.8330177 545689.439928457,5140613.80205839 547286.07778693,5140615.76910864 548910.589773269,5140611.73553649 550514.540006892,5140624.70248202 552140.489637614,5140654.66904886 553744.439883277,5140665.6359454 554342.209073819,5140666.37355679 554342.233833628,5140666.37358734 554342.358772653,5140648.21724442 554352.603403535,5139042.67776921 554362.910511869,5137431.91946821 554372.34305014,5135950.28679076 554374.092605357,5135825.9111256 554379.778688583,5135430.65900772 554382.215254471,5135157.87632369 554390.399518766,5134210.62133909 554403.706775292,5132676.01947908 554404.206573933,5132616.98791651 554416.451723541,5131196.88662423 554417.451338271,5131084.32352432 554418.388476769,5130978.6979612 554424.011233388,5130321.53820713 554426.322826127,5130056.09928885 554425.135289221,5130034.2866976 554431.509937198,5129978.34879021 554434.009678648,5129918.47343372 554438.13425802,5129821.50410496 554438.696698607,5129807.62902265 554442.759014259,5129784.44132778 554445.571389713,5129769.34744787 554445.008323505,5129586.22150791 554447.257595597,5129376.28287651 554448.632153618,5129248.87593935 554441.694558447,5129159.90685325 554443.569481045,5129151.50052536 554445.506511538,5129020.28105749 554453.316871103,5128413.18400358 554456.003313945,5128103.40108881 554452.814810878,5127761.61811038 554449.438747144,5127399.71002693 554447.437918208,5127123.23986379 554447.062796869,5127082.1146548 554448.562504679,5127002.89546264 554455.184985191,5126267.76648391 554455.184676468,5126171.07847522 554455.058527227,5125810.29532751 554454.054583054,5124569.50753942 554452.79948873,5122971.90532119 554452.172098942,5122223.96383826 554453.484041657,5122060.83794376 554455.674360441,5121405.49590233 554456.362027103,5121363.65225197 554478.679820162,5120033.59289083 554478.99355503,5119750.28113143 554480.875596368,5118133.66033641 554481.377553571,5117684.22399995 554484.944978905,5116540.78940651 554489.701491879,5115028.26197265 554491.139379615,5114932.29344219 554514.833354161,5113333.29707605 554522.335407162,5112827.07946503 554534.589770591,5111770.45689264 554535.027392622,5111740.45695946 554535.652606605,5111688.55082766 554551.658348326,5110300.52273345 554554.159240296,5110084.99196981 554572.353248283,5108514.05798831 554576.292166395,5108172.18374812 554591.234780263,5106936.90520942 554590.672454214,5106899.81156213 554584.799324661,5106499.93766508 554592.616912497,5105303.62790302 554592.429485455,5105287.81544546 554581.933214056,5104483.0363755 554581.186729472,5103682.88207219 554581.249264502,5103674.60084072 554584.189251516,5103093.22717131 554584.564675901,5102994.57114941 554590.691312287,5102594.04071861 554591.253978603,5102553.60330241 554568.629437552,5102545.85383945 554480.818797228,5102497.51221917 554394.758125457,5102448.29556352 554325.69710991,5102404.35975707 554236.511316787,5102396.23682528 554140.200644842,5102390.95780032 554105.951326077,5102381.70861039 554006.203309133,5102354.77347075 553895.642898913,5102350.46352219 553832.456554275,5102357.37120581 553772.707675745,5102356.96632954 553682.584419698,5102343.62468572 553609.335862589,5102326.43891521 553461.77634549,5102272.4737048 553355.153599082,5102208.32008551 553224.156442003,5102109.51087989 553154.032950968,5102059.10638963 553148.845548024,5102059.04400946 553140.658238217,5102049.57547528 553044.910189871,5102007.51530512 552994.223573846,5102023.20392956 552950.661870638,5102027.26742294 552890.975457625,5102034.11253008 552790.97741619,5102010.02115849 552709.666511637,5101989.42934651 552639.980380199,5101971.27475981 552566.481923366,5101925.55784552 552503.358245955,5101886.62192277 552479.483745789,5101871.90376969 552397.110439891,5101828.87455699 552346.799029958,5101787.43834941 552318.924663206,5101756.43909103 552255.488376177,5101747.22183884 552182.302315528,5101725.59860195 552058.804813389,5101669.5703917 551982.556406799,5101620.25981795 551833.559557177,5101511.88862801 551704.874931212,5101372.79832701 551595.689948365,5101229.98884483 551523.941768908,5101086.83474873 551457.818362936,5100977.61791267 551411.319606158,5100864.55688417 551380.82056902,5100746.96424872 551334.821931918,5100594.55959859 551317.760111766,5100486.65411858 551300.573136332,5100424.65473556 551297.510729787,5100413.59234561 551270.386672281,5100281.59343787 551227.387872398,5100157.87612939 551193.451336726,5100054.50228915 551188.951743405,5099958.12772837 551168.140058366,5099827.84742246 551161.578091684,5099704.5667546 551158.953466592,5099607.19215365 551118.89198163,5099519.19341386 551055.705905587,5099432.22647519 551007.831993604,5099362.9466117 550964.520459462,5099305.35409998 550921.771455629,5099235.07412108 550866.022686856,5099163.32571097 550820.898685985,5099103.95200429 550798.024323204,5099033.54655423 550790.587333623,5098917.45339688 550789.52493389,5098892.45351158 550789.087588548,5098847.32868299 550788.71273913,5098803.11009965 550805.400313442,5098689.48510191 550816.71303623,5098559.79778976 550822.838257872,5098458.73550047 550825.588512559,5098365.86076342 550859.713439288,5098204.67300627 550885.463345372,5098095.45401594 550883.026099186,5098031.11055205 550870.339222261,5097908.76754253 550862.339671889,5097814.14307154 550835.527951187,5097718.80031329 550805.028886145,5097594.89524803 550809.654053215,5097518.92665392 550789.154710702,5097426.20873526 550751.530758417,5097304.21009257 550714.906553155,5097254.36742052 550673.844942598,5097198.58738006 550590.721755413,5097080.55860137 550542.160233131,5097036.37245824 550491.973709423,5097001.09257416 550365.163777452,5096878.15865468 550334.852109523,5096778.34727154 550310.727814306,5096684.81696374 550316.290469509,5096604.31712294 550309.728175924,5096574.03614743 550318.978190406,5096518.5673725 550326.790640858,5096491.62977781 550313.228427415,5096473.94267983 550296.916313546,5096439.25571311 550289.041689036,5096361.53744597 550297.291764992,5096291.81874812 550308.541688008,5096255.00610377 550322.354089704,5096211.13092128 550317.291897743,5096139.75631034 550284.542665925,5096071.25738025 550247.668392169,5096038.50842221 550217.23146193,5096020.94674768 550180.419666482,5095994.54151571 550104.296075735,5095955.01231634 549989.673197379,5095894.54666119 549850.988229078,5095831.51912271 549789.114369961,5095799.0207972 549702.17851544,5095738.21071076 549622.054824984,5095752.46266394 549498.119437673,5095744.68455112 549458.745151586,5095727.24810707 549379.121568022,5095701.18770715 549323.247485056,5095709.93907356 549308.747725346,5095711.40818131 549254.561116424,5095719.40950802 549162.812631523,5095730.911762 549121.125806116,5095741.22526522 549075.751533407,5095755.10134605 548969.753307069,5095760.60397996 548872.567449687,5095759.70016915 548831.880561098,5095787.8260719 548759.694280633,5095787.60913109 548668.820810466,5095789.42389983 548559.447587701,5095816.36402521 548491.136141183,5095855.49056886 548439.949388799,5095901.52290282 548366.825545358,5095933.39959453 548304.326424988,5096004.24460061 548194.828244741,5096019.05977103 547988.394076832,5096088.78336742 547861.146149204,5096125.91137619 547703.523643693,5096204.53995125 547698.398724912,5096207.10256733 547469.52754957,5096238.45187426 547259.530969925,5096309.17552288 547100.2835743,5096360.74174086 547009.535044148,5096397.83757056 546897.536815154,5096465.30878043 546758.976469298,5096569.59296632 546667.352936202,5096620.126242 546581.166812912,5096670.47188094 546471.04354446,5096750.53671288 546346.732980185,5096853.82052419 546260.484326146,5096926.29104226 546139.173822117,5096977.26252863 546089.487147772,5096994.38866717 546078.23733479,5096998.26392488 545939.364607453,5097066.89199786 545807.491745403,5097146.23858723 545797.804358794,5097176.51991972 545763.742428123,5097188.208197 545612.307453801,5097245.02412425 545455.622652952,5097256.43416338 545332.499832048,5097230.96857232 545228.189170155,5097213.53372805 545091.754058384,5097199.88090418 544968.568701521,5097195.54020531 544885.945138796,5097192.69850155 544835.133531849,5097184.88729308 544768.38474138,5097150.10787432 544655.636770422,5097098.92342916 544506.514470127,5097016.42755734 544424.703441951,5096975.71105005 544228.894428452,5096899.65380548 544087.771959286,5096826.9702006 543971.711544846,5096760.47344728 543804.589568653,5096641.38451572 543683.904238125,5096561.41921796 543572.968767686,5096452.86010173 543476.28303757,5096352.30059195 543376.097356744,5096256.27239851 543279.286644267,5096130.58805322 543174.538568908,5095996.09146618 543096.290071761,5095825.62569112 543083.540359618,5095754.22018835 543073.415608845,5095676.4709084 543052.603528349,5095608.65933726 543043.041216238,5095582.12848651 543015.604254459,5095506.06713256 543011.541940421,5095386.28670537 543031.791665603,5095319.1928493 543036.104133727,5095278.00548819 543022.416925227,5095215.47495881 542971.167886651,5095111.10187962 542934.293582281,5095029.94705025 542907.294089969,5094971.10433811 542832.670466591,5094831.95081922 542759.109314617,5094698.20349685 542699.047897229,5094604.54934263 542614.611937776,5094444.95871608 542548.363098513,5094370.17961229 542494.551552431,5094293.4939562 542461.364642398,5094242.7138662 542457.677225166,5094215.90162597 542448.739895674,5094187.62077892 542372.488737527,5093978.65562436 542360.801056537,5093946.56242515 542309.112311312,5093767.22140284 542326.921786931,5093532.22280021 542331.920230532,5093405.3799217 542258.045219705,5093304.53883344 542092.232986639,5093107.07581767 541872.735145832,5093003.01966359 541630.736858292,5092838.05828172 541553.486502912,5092713.87367658 541475.23533276,5092524.59583772 541470.733414002,5092365.34716469 541479.8578229,5092328.81596462 541503.418796123,5092234.22234624 541561.729180114,5092132.84666223 541662.539346825,5092063.18842708 541740.162327585,5091990.59329668 541731.286383227,5091902.87544188 541656.411309875,5091809.12802645 541484.160549609,5091550.10303766 541272.41156773,5091394.89071915 541186.974460643,5091332.23705942 541108.474813244,5091274.70818659 541001.850639414,5091224.4612031 540845.164685801,5091177.40293178 540681.479676533,5091195.43809871 540516.857879928,5091265.25415992 540460.733977699,5091289.09912509 540324.04837952,5091289.54000824 540236.11256392,5091323.54193943 540181.426148367,5091347.16812319 540118.489899045,5091374.3257366 539974.430807429,5091474.82858421 539923.306818993,5091495.82970216 539822.308315667,5091501.1759217 539654.62293823,5091484.36770569 539634.060698161,5091482.30573092 539496.874622779,5091447.12188651 539430.625709959,5091458.02970369 539347.252245524,5091483.15659615 538901.82538179,5091775.79062633 538715.641387779,5091830.95113367 538533.645830736,5091945.14211264 538303.400263202,5092009.92830984 538046.343180148,5092111.4023769 537951.0326951,5092148.99809719 537688.287930376,5092230.94117665 537489.541848367,5092289.28916968 537413.793434159,5092317.19699642 537397.856179987,5092317.47861736 537217.859784307,5092372.85743922 537020.613266138,5092403.45558747 536776.616341385,5092364.11782328 536726.866708995,5092340.05665768 536705.741865714,5092329.90097392 536632.492407924,5092294.71543747 536585.867693434,5092268.71671314 536365.056530663,5092145.69150694 536158.431488057,5091953.16646956 535810.494785362,5091686.92653195 535607.868614117,5091436.43308542 535550.054839239,5091309.24785732 535526.054308586,5091256.49880046 535361.30292556,5091030.91054732 535197.739366394,5090827.75961084 534983.302928682,5090708.54677201 534975.990390074,5090700.1095053 534879.614878251,5090589.08132967 534855.799773533,5090416.61438987 534876.608963023,5090239.95892745 534836.043226101,5090017.05524812 534817.790979542,5089870.74423803 534817.039536308,5089785.74487069 534821.414110595,5089764.40117162 534838.974905119,5089678.87012473 534878.597079132,5089545.43265137 534882.406579019,5089372.77755804 534847.715288643,5089123.28018157 534810.713355892,5088981.06333606 534782.586301887,5088839.03377921 534725.023444326,5088773.25437114 534701.7736268,5088765.78622723 534616.83679632,5088738.75718989 534503.588062959,5088724.57248241 534218.779208096,5088715.67306195 534153.842315869,5088700.86221224 534096.780553753,5088699.55107727 534002.906770908,5088697.58457155 533875.907879244,5088664.33783136 533794.657462215,5088579.34038347 533629.220857022,5088505.9073536 533565.158226408,5088450.78428096 533468.471505822,5088422.8180355 533371.5346313,5088386.19561015 533345.222300536,5088376.2588091 533246.098566801,5088374.04243326 533134.100287361,5088387.66999686 533053.351642428,5088403.79679844 532947.789912736,5088369.36206378 532873.540227785,5088332.73910107 532509.166881397,5088161.06154654 532428.354532438,5088111.68883798 532145.980028413,5087939.16560066 532032.104583705,5087835.57533889 531976.791977225,5087791.38948815 531944.729045281,5087745.92184295 531861.791778069,5087701.14290642 531791.854590106,5087669.73856017 531769.729688322,5087659.80166253 531692.105634678,5087657.17853421 531549.482170086,5087641.55705451 531328.546886412,5087609.00007167 531105.424480406,5087595.19300065 530949.301344763,5087588.19677961 530815.239800053,5087548.54403017 530587.989829637,5087399.51933915 530361.739724948,5087245.99466495 530276.613639391,5087134.90379811 530201.425892234,5087073.71856372 530178.238315577,5087054.8755124 530166.925778738,5087045.71960301 530073.112856642,5086964.03497242 529996.049952806,5086894.31860062 529899.73769556,5086845.63377937 529789.363666918,5086825.32407778 529688.740368069,5086848.20131101 529494.493905717,5086904.79927491 529373.49582456,5086925.45826143 529247.684695074,5086915.52384933 529166.184278109,5086843.93260436 529096.933960279,5086785.15346782 529056.24665812,5086769.87331063 528969.434367144,5086726.78197412 528861.121365829,5086635.50402786 528742.122196648,5086604.06962396 528628.436532059,5086625.54093117 528594.562252274,5086640.44787669 528522.688782083,5086672.07435211 528341.693613527,5086799.10894473 528193.946475428,5086849.20584002 528075.822557464,5086830.36506603 528065.510088577,5086825.6466 527999.760301715,5086796.33590466 527940.135041522,5086747.86896365 527913.884925928,5086726.52601027 527900.507649324,5086608.33976038 527905.631045558,5086533.77772395 527908.755069676,5086488.40300583 527969.935319263,5086173.34151323 528006.744198495,5086019.31058801 528031.116158065,5085885.96729806 528016.801707287,5085783.03094922 527981.988494533,5085728.40721481 527891.613954849,5085698.78462118 527780.553104804,5085714.8496666 527660.617419261,5085733.66490349 527562.118626276,5085735.44850864 527432.244961223,5085725.51421095 527337.370899841,5085716.54781397 527247.871960968,5085716.48746736 527197.685451768,5085735.26977585 527128.748771501,5085735.30268376 527083.999147679,5085727.92881864 527031.187090902,5085719.21140819 526951.500687246,5085726.3070187 526862.876663815,5085722.71542908 526789.440092505,5085725.37342445 526707.128588975,5085726.25039747 526663.191266112,5085710.06408344 526576.441035807,5085651.03539149 526470.815790519,5085581.1322417 526398.440800242,5085541.72804887 526267.8143935,5085404.73229071 526208.813406882,5085326.82808613 526133.687661253,5085251.61174947 526005.749479571,5085151.30313868 525934.18575,5085056.33687744 525876.997590496,5084995.55749565 525774.059986827,5084936.34170608 525712.122429799,5084901.09348486 525643.434864606,5084862.03295775 525563.809308518,5084794.94167141 525527.18311805,5084721.47439883 525480.432353319,5084662.3197558 525445.806784436,5084618.47719655 525307.180536708,5084490.45033238 525256.180183479,5084448.35815621 525164.929648197,5084377.67343567 525114.804138952,5084329.23754085 525078.178360449,5084275.55136234 525065.676875733,5084202.17725981 525082.799247978,5084092.02148807 525136.731363179,5083875.36568599 525150.229969059,5083818.95956524 525119.91607812,5083741.08593065 525083.227968253,5083695.49343971 525015.22749572,5083640.87053201 524881.853261333,5083610.34276616 524797.728752767,5083591.56371031 524684.103419219,5083521.6607867 524516.790512188,5083423.13440168 524406.727079277,5083329.13784184 524348.539358438,5083291.73331102 524257.320423798,5083240.45469684 524072.975713012,5083111.52273351 523995.193273789,5083022.90035144 523870.536556867,5082944.74777554 523849.317726914,5082931.46715093 523746.442946063,5082893.84496389 523675.754916731,5082838.34714099 523572.034805653,5082731.72554414 523465.503325469,5082673.57236842 523351.877500948,5082586.70085376 523287.471129895,5082552.67145458 523219.471600665,5082542.76694407 523170.222398242,5082555.36179053 523102.160700595,5082559.7696632 523019.817631392,5082552.58422999 522925.817890391,5082522.11802415 522847.911523316,5082482.71400065 522779.068248294,5082472.80951167 522676.099132467,5082412.00002842 522583.972869627,5082317.87805913 522510.751757,5082185.41219931 522445.407215215,5082123.60180991 522355.938355149,5082080.63560336 522304.90702684,5082055.54330932 522268.0,5082010.16958982 522245.905907833,5081983.01410646 522218.24799108,5081900.70296995 522151.183405212,5081784.23683287 522118.058565398,5081777.14395229 522107.652081143,5081762.89432596 522050.119530341,5081683.99014334 521959.836363481,5081565.80584201 521904.427080188,5081415.40220842 521806.050176923,5081295.40562429 521736.361320744,5081210.37679555 521638.798921699,5081175.37948123 521552.047630877,5081086.7573533 521509.171192366,5081009.69655305 521500.263137414,5080930.91618412 521420.729350447,5080793.98178856 521339.321128633,5080680.26599542 521330.444228291,5080597.89190719 521312.629500438,5080498.51818188 521232.189330561,5080357.02135212 521149.00133893,5080305.0863367 521079.311686957,5080189.83902419 521064.154908118,5080162.30837969 520984.527127586,5080017.87406021 520943.711927634,5079891.5323831 520911.491440783,5079808.19013152 520845.333744257,5079724.53622009 520733.019447553,5079610.07120933 520678.579743701,5079500.1984832 520642.79704178,5079427.98122832 520547.760564012,5079180.70442154 520508.163114216,5079015.89429761 520454.754459399,5078899.39660678 520366.409151145,5078805.68083873 520320.470709426,5078751.74493411 520303.344046281,5078678.3709813 520331.467299477,5078616.90205635 520391.746725926,5078563.05726936 520484.805189179,5078429.86859109 520467.08377477,5078315.37000025 520442.456839998,5078228.40259782 520379.670641144,5078006.43728687 520318.410473331,5077573.59872656 520227.403646236,5077268.2285798 520243.650506458,5077145.94796097 520188.741108066,5077001.66930245 520130.927676593,5076946.51496206 520092.364552924,5076909.70373633 519940.143532455,5076772.67744857 519871.6410893,5076654.11766659 519803.263239278,5076519.58926871 519758.262173949,5076463.77836818 519707.605788464,5076443.71730519 519641.730802684,5076425.31285877 519570.605738453,5076402.31483303 519477.168372371,5076380.91110195 519397.76236417,5076367.88194885 519329.35664538,5076369.32080713 519255.980060639,5076284.88550096 519215.447162592,5076207.32447978 519092.819894412,5076080.85928294 519087.069834222,5076076.76568395 518929.943206973,5075965.36356215 518680.877962343,5075781.18269435 518506.312666539,5075616.21892506 518354.746343315,5075416.0050175 518298.181700958,5075312.16333726 518240.804530774,5075206.79044069 518212.832647039,5075071.38596346 518200.203039623,5074881.04416176 518261.164746312,5074615.35776503 518287.412799618,5074544.98284723 518401.623040541,5074237.79569916 518450.679042617,5073991.51559776 518494.489266897,5073913.98411745 518497.800052583,5073845.98464487 518566.35882161,5073718.07808583 518574.358384786,5073703.10929978 518643.573359234,5073573.89023206 518675.819223336,5073418.23466318 518686.25583899,5073386.14097374 518727.127784287,5073276.95356544 518770.188669651,5073226.42184938 518806.278999855,5073101.20342542 518833.052560087,5072801.73670198 518818.172294192,5072585.48888734 518726.197100836,5072295.36835572 518584.818466704,5072100.31056835 518507.722742472,5071993.93814527 518147.000360161,5071720.13578819 517996.093251593,5071631.60856814 517714.463120206,5071321.80490865 517541.550912004,5071015.90515659 517486.67423325,5070927.18839981 517371.701977201,5070741.34883498 517325.134407101,5070516.60189141 517321.071465435,5070497.00840821 517315.008311529,5070467.97755455 517131.465213529,5069912.86164261 517075.770270269,5069585.95961113 517004.567228692,5068919.84229127 517000.160020265,5068878.71776642 516997.815762788,5068856.93676833 516877.740684883,5068291.4134032 516747.919276087,5067871.23270709 516658.074530766,5067792.89172011 516480.947581747,5067638.42843006 516301.474970896,5067402.96596768 516202.817110283,5067294.28174024 516074.408775172,5067152.84850915 515893.874616341,5066954.10452861 515660.402139589,5066697.08109542 515350.931932957,5066500.12137847 515252.209107856,5066285.09448824 515227.426317466,5066202.06522534 515208.362664928,5066139.6917276 515171.330043942,5066058.50646442 515140.704343312,5066011.32047405 515077.98508073,5065957.16659232 515034.109929957,5065928.85558567 514987.578595246,5065902.29461005 514964.921365397,5065846.13983452 514904.607569742,5065757.11148287 514849.044479065,5065702.86368084 514792.481244811,5065641.52227023 514773.887419227,5065628.99165989 514713.637173165,5065588.3374827 514616.949307903,5065524.46578352 514551.542748757,5065478.40556277 514460.418275543,5065458.31424451 514321.138030146,5065436.78655562 514311.512994071,5065430.44313314 514270.106587703,5065403.10079269 514228.699537633,5065346.1339482 514168.573644724,5065275.79275576 514091.416569648,5065200.2957877 513995.541158195,5065134.73657938 513924.853518293,5065093.92637879 513879.103270323,5065060.27173699 513840.634367204,5065034.52304618 513817.070760505,5064972.14962395 513740.976909832,5064930.52705584 513621.133138238,5064871.28077813 513535.945053981,5064803.00260584 513446.22508532,5064703.3500536 513421.535750777,5064606.97721166 513387.410085961,5064559.82251892 513305.721633215,5064476.32575796 513173.284087993,5064409.92361498 513034.910236196,5064395.52074699 512853.724361751,5064382.27508195 512766.28759974,5064373.74595858 512720.474578948,5064327.56025598 512668.567797679,5064277.9372469 512575.442971553,5064240.72121893 512482.223565524,5064165.31831459 512402.472862269,5064094.2900304 512377.253908737,5064072.69720353 511062.392778509,5064071.91450292 509457.409628247,5064066.95095005 507903.301034838,5064065.98619059 506303.005568183,5064071.02239891 504702.459958992,5064069.05872826 503088.821052274,5064081.09516618 501481.713509822,5064101.13136529 499857.508514904,5064110.1681411 498300.449057285,5064129.20350494 496691.169585719,5064134.24028947 495086.89002906,5064130.27709148 493493.361208123,5064153.31341955 491872.206767928,5064171.35049707 490277.552024482,5064146.3873352 488947.308563874,5064129.41802083 488951.993514498,5065755.4076836 488963.362488911,5067334.38565655 488955.82394657,5068945.35767412 488955.129678321,5070583.32900462 488951.340430278,5072144.30170687 488951.395791378,5073758.27334245 488949.982506543,5075382.24478543 488948.350288336,5076995.21637679 488949.780433451,5078595.18808382 488952.085812196,5080210.15946079 488967.578720022,5081806.13086345 488966.603498611,5083471.10132991 488959.62738009,5085087.0727308 488960.651301265,5086693.04410525 488942.143396357,5088296.01584302 488938.698739494,5089923.98680048 488938.722481702,5091522.95816492 488938.728721907,5091943.35687819 489257.737604697,5091942.9451303 490293.766474881,5091942.92726372 490603.306351279,5091942.92192925 490883.814225059,5091946.5420335 491916.936983,5091959.89901845 492488.890332139,5091953.85803386 492786.742335496,5091950.72796563 493533.106969024,5091955.30881303 494107.873015854,5091956.54892235 495168.121370497,5091958.84319296 495653.63491057,5091958.83486902 495729.480807959,5091960.70853896 495718.945751742,5093579.80772311 495723.957943447,5095178.77149585 495729.963918394,5096779.7308946 495733.969895892,5098394.68992644 495743.976059032,5099997.64911727 495749.983476115,5101977.59875299 495753.98952509,5103597.55750941 495770.996088307,5105202.51638607 495793.002926426,5106803.47523639 495820.010010398,5108384.43446898 495831.016509534,5109990.39328381 495834.022797801,5111638.35111148 495843.029308365,5113258.30950871 495830.03459665,5114867.2685059 495827.040391883,5116474.22734309 495835.046800069,5118075.18610661 495835.052794276,5119689.14462307 495822.057922962,5121293.10356628 495835.043321767,5122871.09719571 495850.017037609,5124518.10854358 495856.990847918,5126129.11972733 495883.965846267,5127742.13058836 495858.938034687,5129335.14203562 495864.911866238,5130943.15308686 495862.885291437,5132548.16418396 495858.858328788,5134171.17538212 495830.829879582,5135804.18689701 495828.803448126,5137406.19781468 495815.776178388,5139024.20891946 495769.747660932,5140613.22013602 + + + + 488938.698739494 5064065.98619059554592.616912497 5140666.37358734 + 495769.747660932 5140613.22013602 497493.839733782 5140624.20112631 499099.925449201 5140637.18350592 500702.480180676 5140631.17582888 502322.652996529 5140626.1805358 503943.013177162 5140629.18532095 505559.498296073 5140634.19012381 507083.889113586 5140611.19450178 508669.592740126 5140609.19921645 510293.828064161 5140601.204038 511910.000819644 5140589.20884539 513527.89233112 5140574.21367801 515111.689717197 5140557.21843482 516683.142984441 5140571.22329294 518289.159252459 5140559.22819305 519900.159148136 5140564.22079982 521506.138065647 5140576.19754254 523113.117017892 5140575.1742278 524724.095912882 5140574.15084742 526302.075232683 5140570.12792372 527905.054220142 5140572.10465667 529512.033176919 5140583.08137621 531115.012187083 5140590.05813077 532718.366168833 5140591.034837 534329.970129577 5140608.01152846 536127.946556834 5140608.98539251 537734.925434632 5140604.9619813 539356.887082251 5140610.93267754 540952.837370015 5140612.89978375 542576.911810792 5140615.86630563 544190.486586884 5140616.8330177 545689.439928457 5140613.80205839 547286.07778693 5140615.76910864 548910.589773269 5140611.73553649 550514.540006892 5140624.70248202 552140.489637614 5140654.66904886 553744.439883277 5140665.6359454 554342.209073819 5140666.37355679 554342.233833628 5140666.37358734 554342.358772653 5140648.21724442 554352.603403535 5139042.67776921 554362.910511869 5137431.91946821 554372.34305014 5135950.28679076 554374.092605357 5135825.9111256 554379.778688583 5135430.65900772 554382.215254471 5135157.87632369 554390.399518766 5134210.62133909 554403.706775292 5132676.01947908 554404.206573933 5132616.98791651 554416.451723541 5131196.88662423 554417.451338271 5131084.32352432 554418.388476769 5130978.6979612 554424.011233388 5130321.53820713 554426.322826127 5130056.09928885 554425.135289221 5130034.2866976 554431.509937198 5129978.34879021 554434.009678648 5129918.47343372 554438.13425802 5129821.50410496 554438.696698607 5129807.62902265 554442.759014259 5129784.44132778 554445.571389713 5129769.34744787 554445.008323505 5129586.22150791 554447.257595597 5129376.28287651 554448.632153618 5129248.87593935 554441.694558447 5129159.90685325 554443.569481045 5129151.50052536 554445.506511538 5129020.28105749 554453.316871103 5128413.18400358 554456.003313945 5128103.40108881 554452.814810878 5127761.61811038 554449.438747144 5127399.71002693 554447.437918208 5127123.23986379 554447.062796869 5127082.1146548 554448.562504679 5127002.89546264 554455.184985191 5126267.76648391 554455.184676468 5126171.07847522 554455.058527227 5125810.29532751 554454.054583054 5124569.50753942 554452.79948873 5122971.90532119 554452.172098942 5122223.96383826 554453.484041657 5122060.83794376 554455.674360441 5121405.49590233 554456.362027103 5121363.65225197 554478.679820162 5120033.59289083 554478.99355503 5119750.28113143 554480.875596368 5118133.66033641 554481.377553571 5117684.22399995 554484.944978905 5116540.78940651 554489.701491879 5115028.26197265 554491.139379615 5114932.29344219 554514.833354161 5113333.29707605 554522.335407162 5112827.07946503 554534.589770591 5111770.45689264 554535.027392622 5111740.45695946 554535.652606605 5111688.55082766 554551.658348326 5110300.52273345 554554.159240296 5110084.99196981 554572.353248283 5108514.05798831 554576.292166395 5108172.18374812 554591.234780263 5106936.90520942 554590.672454214 5106899.81156213 554584.799324661 5106499.93766508 554592.616912497 5105303.62790302 554592.429485455 5105287.81544546 554581.933214056 5104483.0363755 554581.186729472 5103682.88207219 554581.249264502 5103674.60084072 554584.189251516 5103093.22717131 554584.564675901 5102994.57114941 554590.691312287 5102594.04071861 554591.253978603 5102553.60330241 554568.629437552 5102545.85383945 554480.818797228 5102497.51221917 554394.758125457 5102448.29556352 554325.69710991 5102404.35975707 554236.511316787 5102396.23682528 554140.200644842 5102390.95780032 554105.951326077 5102381.70861039 554006.203309133 5102354.77347075 553895.642898913 5102350.46352219 553832.456554275 5102357.37120581 553772.707675745 5102356.96632954 553682.584419698 5102343.62468572 553609.335862589 5102326.43891521 553461.77634549 5102272.4737048 553355.153599082 5102208.32008551 553224.156442003 5102109.51087989 553154.032950968 5102059.10638963 553148.845548024 5102059.04400946 553140.658238217 5102049.57547528 553044.910189871 5102007.51530512 552994.223573846 5102023.20392956 552950.661870638 5102027.26742294 552890.975457625 5102034.11253008 552790.97741619 5102010.02115849 552709.666511637 5101989.42934651 552639.980380199 5101971.27475981 552566.481923366 5101925.55784552 552503.358245955 5101886.62192277 552479.483745789 5101871.90376969 552397.110439891 5101828.87455699 552346.799029958 5101787.43834941 552318.924663206 5101756.43909103 552255.488376177 5101747.22183884 552182.302315528 5101725.59860195 552058.804813389 5101669.5703917 551982.556406799 5101620.25981795 551833.559557177 5101511.88862801 551704.874931212 5101372.79832701 551595.689948365 5101229.98884483 551523.941768908 5101086.83474873 551457.818362936 5100977.61791267 551411.319606158 5100864.55688417 551380.82056902 5100746.96424872 551334.821931918 5100594.55959859 551317.760111766 5100486.65411858 551300.573136332 5100424.65473556 551297.510729787 5100413.59234561 551270.386672281 5100281.59343787 551227.387872398 5100157.87612939 551193.451336726 5100054.50228915 551188.951743405 5099958.12772837 551168.140058366 5099827.84742246 551161.578091684 5099704.5667546 551158.953466592 5099607.19215365 551118.89198163 5099519.19341386 551055.705905587 5099432.22647519 551007.831993604 5099362.9466117 550964.520459462 5099305.35409998 550921.771455629 5099235.07412108 550866.022686856 5099163.32571097 550820.898685985 5099103.95200429 550798.024323204 5099033.54655423 550790.587333623 5098917.45339688 550789.52493389 5098892.45351158 550789.087588548 5098847.32868299 550788.71273913 5098803.11009965 550805.400313442 5098689.48510191 550816.71303623 5098559.79778976 550822.838257872 5098458.73550047 550825.588512559 5098365.86076342 550859.713439288 5098204.67300627 550885.463345372 5098095.45401594 550883.026099186 5098031.11055205 550870.339222261 5097908.76754253 550862.339671889 5097814.14307154 550835.527951187 5097718.80031329 550805.028886145 5097594.89524803 550809.654053215 5097518.92665392 550789.154710702 5097426.20873526 550751.530758417 5097304.21009257 550714.906553155 5097254.36742052 550673.844942598 5097198.58738006 550590.721755413 5097080.55860137 550542.160233131 5097036.37245824 550491.973709423 5097001.09257416 550365.163777452 5096878.15865468 550334.852109523 5096778.34727154 550310.727814306 5096684.81696374 550316.290469509 5096604.31712294 550309.728175924 5096574.03614743 550318.978190406 5096518.5673725 550326.790640858 5096491.62977781 550313.228427415 5096473.94267983 550296.916313546 5096439.25571311 550289.041689036 5096361.53744597 550297.291764992 5096291.81874812 550308.541688008 5096255.00610377 550322.354089704 5096211.13092128 550317.291897743 5096139.75631034 550284.542665925 5096071.25738025 550247.668392169 5096038.50842221 550217.23146193 5096020.94674768 550180.419666482 5095994.54151571 550104.296075735 5095955.01231634 549989.673197379 5095894.54666119 549850.988229078 5095831.51912271 549789.114369961 5095799.0207972 549702.17851544 5095738.21071076 549622.054824984 5095752.46266394 549498.119437673 5095744.68455112 549458.745151586 5095727.24810707 549379.121568022 5095701.18770715 549323.247485056 5095709.93907356 549308.747725346 5095711.40818131 549254.561116424 5095719.40950802 549162.812631523 5095730.911762 549121.125806116 5095741.22526522 549075.751533407 5095755.10134605 548969.753307069 5095760.60397996 548872.567449687 5095759.70016915 548831.880561098 5095787.8260719 548759.694280633 5095787.60913109 548668.820810466 5095789.42389983 548559.447587701 5095816.36402521 548491.136141183 5095855.49056886 548439.949388799 5095901.52290282 548366.825545358 5095933.39959453 548304.326424988 5096004.24460061 548194.828244741 5096019.05977103 547988.394076832 5096088.78336742 547861.146149204 5096125.91137619 547703.523643693 5096204.53995125 547698.398724912 5096207.10256733 547469.52754957 5096238.45187426 547259.530969925 5096309.17552288 547100.2835743 5096360.74174086 547009.535044148 5096397.83757056 546897.536815154 5096465.30878043 546758.976469298 5096569.59296632 546667.352936202 5096620.126242 546581.166812912 5096670.47188094 546471.04354446 5096750.53671288 546346.732980185 5096853.82052419 546260.484326146 5096926.29104226 546139.173822117 5096977.26252863 546089.487147772 5096994.38866717 546078.23733479 5096998.26392488 545939.364607453 5097066.89199786 545807.491745403 5097146.23858723 545797.804358794 5097176.51991972 545763.742428123 5097188.208197 545612.307453801 5097245.02412425 545455.622652952 5097256.43416338 545332.499832048 5097230.96857232 545228.189170155 5097213.53372805 545091.754058384 5097199.88090418 544968.568701521 5097195.54020531 544885.945138796 5097192.69850155 544835.133531849 5097184.88729308 544768.38474138 5097150.10787432 544655.636770422 5097098.92342916 544506.514470127 5097016.42755734 544424.703441951 5096975.71105005 544228.894428452 5096899.65380548 544087.771959286 5096826.9702006 543971.711544846 5096760.47344728 543804.589568653 5096641.38451572 543683.904238125 5096561.41921796 543572.968767686 5096452.86010173 543476.28303757 5096352.30059195 543376.097356744 5096256.27239851 543279.286644267 5096130.58805322 543174.538568908 5095996.09146618 543096.290071761 5095825.62569112 543083.540359618 5095754.22018835 543073.415608845 5095676.4709084 543052.603528349 5095608.65933726 543043.041216238 5095582.12848651 543015.604254459 5095506.06713256 543011.541940421 5095386.28670537 543031.791665603 5095319.1928493 543036.104133727 5095278.00548819 543022.416925227 5095215.47495881 542971.167886651 5095111.10187962 542934.293582281 5095029.94705025 542907.294089969 5094971.10433811 542832.670466591 5094831.95081922 542759.109314617 5094698.20349685 542699.047897229 5094604.54934263 542614.611937776 5094444.95871608 542548.363098513 5094370.17961229 542494.551552431 5094293.4939562 542461.364642398 5094242.7138662 542457.677225166 5094215.90162597 542448.739895674 5094187.62077892 542372.488737527 5093978.65562436 542360.801056537 5093946.56242515 542309.112311312 5093767.22140284 542326.921786931 5093532.22280021 542331.920230532 5093405.3799217 542258.045219705 5093304.53883344 542092.232986639 5093107.07581767 541872.735145832 5093003.01966359 541630.736858292 5092838.05828172 541553.486502912 5092713.87367658 541475.23533276 5092524.59583772 541470.733414002 5092365.34716469 541479.8578229 5092328.81596462 541503.418796123 5092234.22234624 541561.729180114 5092132.84666223 541662.539346825 5092063.18842708 541740.162327585 5091990.59329668 541731.286383227 5091902.87544188 541656.411309875 5091809.12802645 541484.160549609 5091550.10303766 541272.41156773 5091394.89071915 541186.974460643 5091332.23705942 541108.474813244 5091274.70818659 541001.850639414 5091224.4612031 540845.164685801 5091177.40293178 540681.479676533 5091195.43809871 540516.857879928 5091265.25415992 540460.733977699 5091289.09912509 540324.04837952 5091289.54000824 540236.11256392 5091323.54193943 540181.426148367 5091347.16812319 540118.489899045 5091374.3257366 539974.430807429 5091474.82858421 539923.306818993 5091495.82970216 539822.308315667 5091501.1759217 539654.62293823 5091484.36770569 539634.060698161 5091482.30573092 539496.874622779 5091447.12188651 539430.625709959 5091458.02970369 539347.252245524 5091483.15659615 538901.82538179 5091775.79062633 538715.641387779 5091830.95113367 538533.645830736 5091945.14211264 538303.400263202 5092009.92830984 538046.343180148 5092111.4023769 537951.0326951 5092148.99809719 537688.287930376 5092230.94117665 537489.541848367 5092289.28916968 537413.793434159 5092317.19699642 537397.856179987 5092317.47861736 537217.859784307 5092372.85743922 537020.613266138 5092403.45558747 536776.616341385 5092364.11782328 536726.866708995 5092340.05665768 536705.741865714 5092329.90097392 536632.492407924 5092294.71543747 536585.867693434 5092268.71671314 536365.056530663 5092145.69150694 536158.431488057 5091953.16646956 535810.494785362 5091686.92653195 535607.868614117 5091436.43308542 535550.054839239 5091309.24785732 535526.054308586 5091256.49880046 535361.30292556 5091030.91054732 535197.739366394 5090827.75961084 534983.302928682 5090708.54677201 534975.990390074 5090700.1095053 534879.614878251 5090589.08132967 534855.799773533 5090416.61438987 534876.608963023 5090239.95892745 534836.043226101 5090017.05524812 534817.790979542 5089870.74423803 534817.039536308 5089785.74487069 534821.414110595 5089764.40117162 534838.974905119 5089678.87012473 534878.597079132 5089545.43265137 534882.406579019 5089372.77755804 534847.715288643 5089123.28018157 534810.713355892 5088981.06333606 534782.586301887 5088839.03377921 534725.023444326 5088773.25437114 534701.7736268 5088765.78622723 534616.83679632 5088738.75718989 534503.588062959 5088724.57248241 534218.779208096 5088715.67306195 534153.842315869 5088700.86221224 534096.780553753 5088699.55107727 534002.906770908 5088697.58457155 533875.907879244 5088664.33783136 533794.657462215 5088579.34038347 533629.220857022 5088505.9073536 533565.158226408 5088450.78428096 533468.471505822 5088422.8180355 533371.5346313 5088386.19561015 533345.222300536 5088376.2588091 533246.098566801 5088374.04243326 533134.100287361 5088387.66999686 533053.351642428 5088403.79679844 532947.789912736 5088369.36206378 532873.540227785 5088332.73910107 532509.166881397 5088161.06154654 532428.354532438 5088111.68883798 532145.980028413 5087939.16560066 532032.104583705 5087835.57533889 531976.791977225 5087791.38948815 531944.729045281 5087745.92184295 531861.791778069 5087701.14290642 531791.854590106 5087669.73856017 531769.729688322 5087659.80166253 531692.105634678 5087657.17853421 531549.482170086 5087641.55705451 531328.546886412 5087609.00007167 531105.424480406 5087595.19300065 530949.301344763 5087588.19677961 530815.239800053 5087548.54403017 530587.989829637 5087399.51933915 530361.739724948 5087245.99466495 530276.613639391 5087134.90379811 530201.425892234 5087073.71856372 530178.238315577 5087054.8755124 530166.925778738 5087045.71960301 530073.112856642 5086964.03497242 529996.049952806 5086894.31860062 529899.73769556 5086845.63377937 529789.363666918 5086825.32407778 529688.740368069 5086848.20131101 529494.493905717 5086904.79927491 529373.49582456 5086925.45826143 529247.684695074 5086915.52384933 529166.184278109 5086843.93260436 529096.933960279 5086785.15346782 529056.24665812 5086769.87331063 528969.434367144 5086726.78197412 528861.121365829 5086635.50402786 528742.122196648 5086604.06962396 528628.436532059 5086625.54093117 528594.562252274 5086640.44787669 528522.688782083 5086672.07435211 528341.693613527 5086799.10894473 528193.946475428 5086849.20584002 528075.822557464 5086830.36506603 528065.510088577 5086825.6466 527999.760301715 5086796.33590466 527940.135041522 5086747.86896365 527913.884925928 5086726.52601027 527900.507649324 5086608.33976038 527905.631045558 5086533.77772395 527908.755069676 5086488.40300583 527969.935319263 5086173.34151323 528006.744198495 5086019.31058801 528031.116158065 5085885.96729806 528016.801707287 5085783.03094922 527981.988494533 5085728.40721481 527891.613954849 5085698.78462118 527780.553104804 5085714.8496666 527660.617419261 5085733.66490349 527562.118626276 5085735.44850864 527432.244961223 5085725.51421095 527337.370899841 5085716.54781397 527247.871960968 5085716.48746736 527197.685451768 5085735.26977585 527128.748771501 5085735.30268376 527083.999147679 5085727.92881864 527031.187090902 5085719.21140819 526951.500687246 5085726.3070187 526862.876663815 5085722.71542908 526789.440092505 5085725.37342445 526707.128588975 5085726.25039747 526663.191266112 5085710.06408344 526576.441035807 5085651.03539149 526470.815790519 5085581.1322417 526398.440800242 5085541.72804887 526267.8143935 5085404.73229071 526208.813406882 5085326.82808613 526133.687661253 5085251.61174947 526005.749479571 5085151.30313868 525934.18575 5085056.33687744 525876.997590496 5084995.55749565 525774.059986827 5084936.34170608 525712.122429799 5084901.09348486 525643.434864606 5084862.03295775 525563.809308518 5084794.94167141 525527.18311805 5084721.47439883 525480.432353319 5084662.3197558 525445.806784436 5084618.47719655 525307.180536708 5084490.45033238 525256.180183479 5084448.35815621 525164.929648197 5084377.67343567 525114.804138952 5084329.23754085 525078.178360449 5084275.55136234 525065.676875733 5084202.17725981 525082.799247978 5084092.02148807 525136.731363179 5083875.36568599 525150.229969059 5083818.95956524 525119.91607812 5083741.08593065 525083.227968253 5083695.49343971 525015.22749572 5083640.87053201 524881.853261333 5083610.34276616 524797.728752767 5083591.56371031 524684.103419219 5083521.6607867 524516.790512188 5083423.13440168 524406.727079277 5083329.13784184 524348.539358438 5083291.73331102 524257.320423798 5083240.45469684 524072.975713012 5083111.52273351 523995.193273789 5083022.90035144 523870.536556867 5082944.74777554 523849.317726914 5082931.46715093 523746.442946063 5082893.84496389 523675.754916731 5082838.34714099 523572.034805653 5082731.72554414 523465.503325469 5082673.57236842 523351.877500948 5082586.70085376 523287.471129895 5082552.67145458 523219.471600665 5082542.76694407 523170.222398242 5082555.36179053 523102.160700595 5082559.7696632 523019.817631392 5082552.58422999 522925.817890391 5082522.11802415 522847.911523316 5082482.71400065 522779.068248294 5082472.80951167 522676.099132467 5082412.00002842 522583.972869627 5082317.87805913 522510.751757 5082185.41219931 522445.407215215 5082123.60180991 522355.938355149 5082080.63560336 522304.90702684 5082055.54330932 522268.000077275 5082010.16958982 522245.905907833 5081983.01410646 522218.24799108 5081900.70296995 522151.183405212 5081784.23683287 522118.058565398 5081777.14395229 522107.652081143 5081762.89432596 522050.119530341 5081683.99014334 521959.836363481 5081565.80584201 521904.427080188 5081415.40220842 521806.050176923 5081295.40562429 521736.361320744 5081210.37679555 521638.798921699 5081175.37948123 521552.047630877 5081086.7573533 521509.171192366 5081009.69655305 521500.263137414 5080930.91618412 521420.729350447 5080793.98178856 521339.321128633 5080680.26599542 521330.444228291 5080597.89190719 521312.629500438 5080498.51818188 521232.189330561 5080357.02135212 521149.00133893 5080305.0863367 521079.311686957 5080189.83902419 521064.154908118 5080162.30837969 520984.527127586 5080017.87406021 520943.711927634 5079891.5323831 520911.491440783 5079808.19013152 520845.333744257 5079724.53622009 520733.019447553 5079610.07120933 520678.579743701 5079500.1984832 520642.79704178 5079427.98122832 520547.760564012 5079180.70442154 520508.163114216 5079015.89429761 520454.754459399 5078899.39660678 520366.409151145 5078805.68083873 520320.470709426 5078751.74493411 520303.344046281 5078678.3709813 520331.467299477 5078616.90205635 520391.746725926 5078563.05726936 520484.805189179 5078429.86859109 520467.08377477 5078315.37000025 520442.456839998 5078228.40259782 520379.670641144 5078006.43728687 520318.410473331 5077573.59872656 520227.403646236 5077268.2285798 520243.650506458 5077145.94796097 520188.741108066 5077001.66930245 520130.927676593 5076946.51496206 520092.364552924 5076909.70373633 519940.143532455 5076772.67744857 519871.6410893 5076654.11766659 519803.263239278 5076519.58926871 519758.262173949 5076463.77836818 519707.605788464 5076443.71730519 519641.730802684 5076425.31285877 519570.605738453 5076402.31483303 519477.168372371 5076380.91110195 519397.76236417 5076367.88194885 519329.35664538 5076369.32080713 519255.980060639 5076284.88550096 519215.447162592 5076207.32447978 519092.819894412 5076080.85928294 519087.069834222 5076076.76568395 518929.943206973 5075965.36356215 518680.877962343 5075781.18269435 518506.312666539 5075616.21892506 518354.746343315 5075416.0050175 518298.181700958 5075312.16333726 518240.804530774 5075206.79044069 518212.832647039 5075071.38596346 518200.203039623 5074881.04416176 518261.164746312 5074615.35776503 518287.412799618 5074544.98284723 518401.623040541 5074237.79569916 518450.679042617 5073991.51559776 518494.489266897 5073913.98411745 518497.800052583 5073845.98464487 518566.35882161 5073718.07808583 518574.358384786 5073703.10929978 518643.573359234 5073573.89023206 518675.819223336 5073418.23466318 518686.25583899 5073386.14097374 518727.127784287 5073276.95356544 518770.188669651 5073226.42184938 518806.278999855 5073101.20342542 518833.052560087 5072801.73670198 518818.172294192 5072585.48888734 518726.197100836 5072295.36835572 518584.818466704 5072100.31056835 518507.722742472 5071993.93814527 518147.000360161 5071720.13578819 517996.093251593 5071631.60856814 517714.463120206 5071321.80490865 517541.550912004 5071015.90515659 517486.67423325 5070927.18839981 517371.701977201 5070741.34883498 517325.134407101 5070516.60189141 517321.071465435 5070497.00840821 517315.008311529 5070467.97755455 517131.465213529 5069912.86164261 517075.770270269 5069585.95961113 517004.567228692 5068919.84229127 517000.160020265 5068878.71776642 516997.815762788 5068856.93676833 516877.740684883 5068291.4134032 516747.919276087 5067871.23270709 516658.074530766 5067792.89172011 516480.947581747 5067638.42843006 516301.474970896 5067402.96596768 516202.817110283 5067294.28174024 516074.408775172 5067152.84850915 515893.874616341 5066954.10452861 515660.402139589 5066697.08109542 515350.931932957 5066500.12137847 515252.209107856 5066285.09448824 515227.426317466 5066202.06522534 515208.362664928 5066139.6917276 515171.330043942 5066058.50646442 515140.704343312 5066011.32047405 515077.98508073 5065957.16659232 515034.109929957 5065928.85558567 514987.578595246 5065902.29461005 514964.921365397 5065846.13983452 514904.607569742 5065757.11148287 514849.044479065 5065702.86368084 514792.481244811 5065641.52227023 514773.887419227 5065628.99165989 514713.637173165 5065588.3374827 514616.949307903 5065524.46578352 514551.542748757 5065478.40556277 514460.418275543 5065458.31424451 514321.138030146 5065436.78655562 514311.512994071 5065430.44313314 514270.106587703 5065403.10079269 514228.699537633 5065346.1339482 514168.573644724 5065275.79275576 514091.416569648 5065200.2957877 513995.541158195 5065134.73657938 513924.853518293 5065093.92637879 513879.103270323 5065060.27173699 513840.634367204 5065034.52304618 513817.070760505 5064972.14962395 513740.976909832 5064930.52705584 513621.133138238 5064871.28077813 513535.945053981 5064803.00260584 513446.22508532 5064703.3500536 513421.535750777 5064606.97721166 513387.410085961 5064559.82251892 513305.721633215 5064476.32575796 513173.284087993 5064409.92361498 513034.910236196 5064395.52074699 512853.724361751 5064382.27508195 512766.28759974 5064373.74595858 512720.474578948 5064327.56025598 512668.567797679 5064277.9372469 512575.442971553 5064240.72121893 512482.223565524 5064165.31831459 512402.472862269 5064094.2900304 512377.253908737 5064072.69720353 511062.392778509 5064071.91450292 509457.409628247 5064066.95095005 507903.301034838 5064065.98619059 506303.005568183 5064071.02239891 504702.459958992 5064069.05872826 503088.821052274 5064081.09516618 501481.713509822 5064101.13136529 499857.508514904 5064110.1681411 498300.449057285 5064129.20350494 496691.169585719 5064134.24028947 495086.89002906 5064130.27709148 493493.361208123 5064153.31341955 491872.206767928 5064171.35049707 490277.552024482 5064146.3873352 488947.308563874 5064129.41802083 488951.993514498 5065755.4076836 488963.362488911 5067334.38565655 488955.82394657 5068945.35767412 488955.129678321 5070583.32900462 488951.340430278 5072144.30170687 488951.395791378 5073758.27334245 488949.982506543 5075382.24478543 488948.350288336 5076995.21637679 488949.780433451 5078595.18808382 488952.085812196 5080210.15946079 488967.578720022 5081806.13086345 488966.603498611 5083471.10132991 488959.62738009 5085087.0727308 488960.651301265 5086693.04410525 488942.143396357 5088296.01584302 488938.698739494 5089923.98680048 488938.722481702 5091522.95816492 488938.728721907 5091943.35687819 489257.737604697 5091942.9451303 490293.766474881 5091942.92726372 490603.306351279 5091942.92192925 490883.814225059 5091946.5420335 491916.936983 5091959.89901845 492488.890332139 5091953.85803386 492786.742335496 5091950.72796563 493533.106969024 5091955.30881303 494107.873015854 5091956.54892235 495168.121370497 5091958.84319296 495653.63491057 5091958.83486902 495729.480807959 5091960.70853896 495718.945751742 5093579.80772311 495723.957943447 5095178.77149585 495729.963918394 5096779.7308946 495733.969895892 5098394.68992644 495743.976059032 5099997.64911727 495749.983476115 5101977.59875299 495753.98952509 5103597.55750941 495770.996088307 5105202.51638607 495793.002926426 5106803.47523639 495820.010010398 5108384.43446898 495831.016509534 5109990.39328381 495834.022797801 5111638.35111148 495843.029308365 5113258.30950871 495830.03459665 5114867.2685059 495827.040391883 5116474.22734309 495835.046800069 5118075.18610661 495835.052794276 5119689.14462307 495822.057922962 5121293.10356628 495835.043321767 5122871.09719571 495850.017037609 5124518.10854358 495856.990847918 5126129.11972733 495883.965846267 5127742.13058836 495858.938034687 5129335.14203562 495864.911866238 5130943.15308686 495862.885291437 5132548.16418396 495858.858328788 5134171.17538212 495830.829879582 5135804.18689701 495828.803448126 5137406.19781468 495815.776178388 5139024.20891946 495769.747660932 5140613.22013602 - - - - 438623.813339239,5121376.09834029 439268.330052994,5121375.71365614 440877.37695095,5121394.6590622 442433.41800387,5121415.6095591 444012.438820035,5121440.57537843 445555.459188838,5121450.54218051 447142.480120161,5121473.5079516 448848.502614519,5121502.47117366 450644.526317509,5121524.43260388 452150.546221549,5121533.40039558 453901.569310636,5121566.36280177 455534.590852865,5121594.3278256 457106.611589166,5121622.29420132 458729.164257097,5121647.19708141 458863.634782301,5121649.25671468 460382.654975318,5121633.22463705 461978.681115782,5121582.17868885 463582.716668467,5121567.10778504 465169.751832345,5121562.03758123 466796.788476539,5121475.96660114 466806.804704029,5119187.99361209 466825.816297009,5117602.01185281 466837.82780885,5116011.03046653 466840.839130967,5114420.0494352 466801.849456444,5112811.07011109 466657.856325405,5111261.0935366 466632.866852024,5109653.11330102 466609.877339502,5108056.13277789 466589.575273206,5106476.15188722 466571.491993683,5104899.17081937 466559.908942111,5103319.18954126 466559.920202827,5101716.20818807 466518.898924679,5100094.22799554 466510.94108788,5098501.24660003 466507.952266847,5096898.26517664 466491.962848709,5095312.283773 466503.973831077,5093696.30281881 466501.981832964,5092081.29258997 464966.925456697,5092134.34856581 464893.922778272,5092135.94350583 463946.419248898,5092156.64646804 463318.864953662,5092169.65673431 463291.863961833,5092170.21967628 462445.583082424,5092165.76503196 461635.834808413,5092161.49728313 461618.802937696,5092161.40381719 460610.997352688,5092152.80308464 460025.768559792,5092147.78839446 459868.765849071,5092147.98032192 459859.768794261,5091855.45249348 459795.783384233,5090371.47038962 459780.800153885,5088762.4882138 459800.817670382,5087147.50499564 459819.834954137,5085557.52145021 459806.851424333,5083986.53863791 459795.868361068,5082376.55613539 459785.885309762,5080768.57353337 459803.90294958,5079156.58997051 459838.920779818,5077568.60547445 459847.93848736,5075940.62221269 459857.956280213,5074310.63885958 459893.973142688,5072831.65289935 459922.991558528,5071198.66869116 459988.01118836,5069548.68316325 460017.02975173,5067916.69870545 460032.04539514,5066264.71406684 460041.028713195,5064660.7197052 460131.011340174,5062777.72341361 460144.994716183,5061168.72902498 460122.977060133,5059557.7358896 460077.958996613,5057968.74334245 460051.941257301,5056360.75013156 460043.923999539,5054751.75629883 460056.907247183,5053136.76185339 460071.891694615,5051630.7669731 460074.874724017,5050022.77280059 460087.85787808,5048401.77842505 460107.841019503,5046762.78397566 460144.824871777,5045148.78911013 458524.781590879,5045176.82370185 456908.73824789,5045187.85830708 455289.694928309,5045207.89301589 453679.651972685,5045238.9276109 452069.60898391,5045265.96227953 450454.566100183,5045315.99723879 448848.52322357,5045342.03199364 447227.479844585,5045357.06705671 445602.43635967,5045371.10223244 443990.393022387,5045363.13693017 442376.349896029,5045381.17194423 440741.310287012,5045399.18928944 440743.325486712,5047051.20963912 440743.340272337,5048666.2294772 440737.355311769,5050328.24981781 440743.370475576,5051976.26998853 440736.385283229,5053624.29005426 440740.400672329,5055309.31056787 440738.41510013,5056909.32997383 440732.429559395,5058529.3495573 440719.443697991,5060141.36896486 440710.45771364,5061732.38808982 440713.472395444,5063361.4076792 440704.486013821,5064917.42629141 440736.501443889,5066530.44573053 440761.497686472,5068130.41721815 440748.49242791,5069747.3876625 440740.487379777,5071357.35826486 440722.482032441,5072973.32878071 440689.476298381,5074578.29956977 440650.470456414,5076176.27058634 440593.464060144,5077802.24127423 440526.457438358,5079432.21209404 440496.764629372,5081004.18385891 440462.196598954,5082623.15488739 440413.784341035,5084296.12516544 440404.342141333,5085902.09633443 440428.369623751,5087503.06719217 440489.866800447,5089115.03726386 440467.143033784,5090726.00846609 440435.387686029,5092390.7289012 439141.605134714,5092415.81236261 438919.380788042,5092423.34716401 438811.503081546,5092422.50521428 437422.874361799,5092480.40230125 437240.307268621,5092487.43647359 437249.335970774,5094066.0056598 437263.332731688,5095662.99035577 437285.329488268,5097271.9769604 437321.326614066,5098877.96324363 437351.32362098,5100475.94963939 437351.3196229,5102176.93580248 437374.316482574,5103766.92231232 437389.313116093,5105366.90887882 437403.309687181,5106983.89528868 437394.305703213,5108574.88247635 437399.30209855,5110162.86930928 437431.299201951,5111764.85524216 437452.2960581,5113347.84157795 437456.292405097,5114947.82823075 437485.289502675,5116528.81424446 437484.285556978,5118193.80044963 437489.281897405,5119808.78685956 437492.278289034,5121376.77370461 438623.813339239,5121376.09834029 + + + + 437240.307268621 5045148.78911013466840.839130967 5121649.25671468 + 438623.813339239 5121376.09834029 439268.330052994 5121375.71365614 440877.37695095 5121394.6590622 442433.41800387 5121415.6095591 444012.438820035 5121440.57537843 445555.459188838 5121450.54218051 447142.480120161 5121473.5079516 448848.502614519 5121502.47117366 450644.526317509 5121524.43260388 452150.546221549 5121533.40039558 453901.569310636 5121566.36280177 455534.590852865 5121594.3278256 457106.611589166 5121622.29420132 458729.164257097 5121647.19708141 458863.634782301 5121649.25671468 460382.654975318 5121633.22463705 461978.681115782 5121582.17868885 463582.716668467 5121567.10778504 465169.751832345 5121562.03758123 466796.788476539 5121475.96660114 466806.804704029 5119187.99361209 466825.816297009 5117602.01185281 466837.82780885 5116011.03046653 466840.839130967 5114420.0494352 466801.849456444 5112811.07011109 466657.856325405 5111261.0935366 466632.866852024 5109653.11330102 466609.877339502 5108056.13277789 466589.575273206 5106476.15188722 466571.491993683 5104899.17081937 466559.908942111 5103319.18954126 466559.920202827 5101716.20818807 466518.898924679 5100094.22799554 466510.94108788 5098501.24660003 466507.952266847 5096898.26517664 466491.962848709 5095312.283773 466503.973831077 5093696.30281881 466501.981832964 5092081.29258997 464966.925456697 5092134.34856581 464893.922778272 5092135.94350583 463946.419248898 5092156.64646804 463318.864953662 5092169.65673431 463291.863961833 5092170.21967628 462445.583082424 5092165.76503196 461635.834808413 5092161.49728313 461618.802937696 5092161.40381719 460610.997352688 5092152.80308464 460025.768559792 5092147.78839446 459868.765849071 5092147.98032192 459859.768794261 5091855.45249348 459795.783384233 5090371.47038962 459780.800153885 5088762.4882138 459800.817670382 5087147.50499564 459819.834954137 5085557.52145021 459806.851424333 5083986.53863791 459795.868361068 5082376.55613539 459785.885309762 5080768.57353337 459803.90294958 5079156.58997051 459838.920779818 5077568.60547445 459847.93848736 5075940.62221269 459857.956280213 5074310.63885958 459893.973142688 5072831.65289935 459922.991558528 5071198.66869116 459988.01118836 5069548.68316325 460017.02975173 5067916.69870545 460032.04539514 5066264.71406684 460041.028713195 5064660.7197052 460131.011340174 5062777.72341361 460144.994716183 5061168.72902498 460122.977060133 5059557.7358896 460077.958996613 5057968.74334245 460051.941257301 5056360.75013156 460043.923999539 5054751.75629883 460056.907247183 5053136.76185339 460071.891694615 5051630.7669731 460074.874724017 5050022.77280059 460087.85787808 5048401.77842505 460107.841019503 5046762.78397566 460144.824871777 5045148.78911013 458524.781590879 5045176.82370185 456908.73824789 5045187.85830708 455289.694928309 5045207.89301589 453679.651972685 5045238.9276109 452069.60898391 5045265.96227953 450454.566100183 5045315.99723879 448848.52322357 5045342.03199364 447227.479844585 5045357.06705671 445602.43635967 5045371.10223244 443990.393022387 5045363.13693017 442376.349896029 5045381.17194423 440741.310287012 5045399.18928944 440743.325486712 5047051.20963912 440743.340272337 5048666.2294772 440737.355311769 5050328.24981781 440743.370475576 5051976.26998853 440736.385283229 5053624.29005426 440740.400672329 5055309.31056787 440738.41510013 5056909.32997383 440732.429559395 5058529.3495573 440719.443697991 5060141.36896486 440710.45771364 5061732.38808982 440713.472395444 5063361.4076792 440704.486013821 5064917.42629141 440736.501443889 5066530.44573053 440761.497686472 5068130.41721815 440748.49242791 5069747.3876625 440740.487379777 5071357.35826486 440722.482032441 5072973.32878071 440689.476298381 5074578.29956977 440650.470456414 5076176.27058634 440593.464060144 5077802.24127423 440526.457438358 5079432.21209404 440496.764629372 5081004.18385891 440462.196598954 5082623.15488739 440413.784341035 5084296.12516544 440404.342141333 5085902.09633443 440428.369623751 5087503.06719217 440489.866800447 5089115.03726386 440467.143033784 5090726.00846609 440435.387686029 5092390.7289012 439141.605134714 5092415.81236261 438919.380788042 5092423.34716401 438811.503081546 5092422.50521428 437422.874361799 5092480.40230125 437240.307268621 5092487.43647359 437249.335970774 5094066.0056598 437263.332731688 5095662.99035577 437285.329488268 5097271.9769604 437321.326614066 5098877.96324363 437351.32362098 5100475.94963939 437351.3196229 5102176.93580248 437374.316482574 5103766.92231232 437389.313116093 5105366.90887882 437403.309687181 5106983.89528868 437394.305703213 5108574.88247635 437399.30209855 5110162.86930928 437431.299201951 5111764.85524216 437452.2960581 5113347.84157795 437456.292405097 5114947.82823075 437485.289502675 5116528.81424446 437484.285556978 5118193.80044963 437489.281897405 5119808.78685956 437492.278289034 5121376.77370461 438623.813339239 5121376.09834029 - + --xxOGRBoundaryxx @@ -59,23 +62,47 @@ Content-Type: application/binary Content-Transfer-Encoding: binary - - - + + + + 0 + + + + + - - - + + + + + + + + + + + + + + - + - + diff --git a/msautotest/query/expected/rfc62_test003.txt b/msautotest/query/expected/rfc62_test003.txt index 49831211f0..9b6b6d1b8d 100644 --- a/msautotest/query/expected/rfc62_test003.txt +++ b/msautotest/query/expected/rfc62_test003.txt @@ -1,84 +1,108 @@ --xxOGRBoundaryxx -Content-Disposition: attachment; filename=foo -bar.gml +Content-Disposition: attachment; filename=some_default_value.gml Content-Type: application/binary Content-Transfer-Encoding: binary - - - 363237.62610408955045148.789110125 - 591752.16423774395386497.208 - - - - - - 493479.37420531,5386074.14118232 495062.336832765,5385983.99124965 496639.674560181,5385894.1616558 498248.095687447,5385802.56185817 499839.824008464,5385711.91271809 501136.55,5385638.064 501467.943141889,5385767.80541868 502638.13038141,5386225.93726688 503053.46464599,5386388.54188931 503331.026,5386497.208 503699.302,5386362.789 503698.47332,5386220.67017644 503689.147461229,5384621.28310618 503685.055,5383919.425 504644.774816817,5383819.88892449 505192.831,5383763.048 506067.396491085,5383051.22448901 506253.563241776,5382899.70025046 506630.795,5382592.665 507778.537,5382437.824 507871.292629229,5382391.32496513 509368.38182872,5381640.82385308 509937.620566855,5381355.46055867 510949.994331869,5380847.95062758 512525.992895043,5380057.89170881 513230.628453252,5379704.65305729 514170.309633563,5379233.58441887 515764.572623581,5378434.3694173 516470.849667691,5378080.30787761 517228.900216171,5377700.29192411 518897.19338599,5376863.96508426 519529.106322551,5376547.18278313 520047.475,5376287.321 520466.380787187,5376350.25746135 522091.309059952,5376594.38690181 522113.824951348,5376597.76969234 523693.324360806,5376835.07389432 525252.915,5377069.387 525268.759120909,5377065.65928362 526793.056620754,5376707.03107132 526885.07181278,5376685.38225025 526949.266,5376670.279 527300.354487204,5375095.81309175 527453.283,5374410.001 527653.748,5373931.762 527552.376,5373516.272 527561.324482355,5373492.93455844 527584.165,5373433.367 527689.675,5373378.304 527467.839,5373137.301 527419.949,5373112.983 527263.544,5372956.911 527236.163,5372848.09 527187.896,5372687.294 527355.022,5372578.487 527551.876,5372306.489 527284.621,5372027.292 526948.617157886,5371912.32001848 526808.709,5371864.447 526695.139,5371883.978 526590.927,5371920.846 526075.661,5371920.909 525551.907,5372120.757 525341.266173163,5371887.38511232 525248.727017776,5371784.85970117 525010.16,5371520.548 523716.552877634,5371602.24673338 523215.28,5371633.905 522261.964,5371345.684 522081.031,5370213.964 522049.140180406,5370143.10519535 521489.688,5368900.048 521544.961,5368616.504 521513.120101352,5368531.18873901 521240.425,5367800.523 521992.925984955,5366919.9380308 522064.973201944,5366835.62758122 523065.189,5365665.164 523666.976011613,5365532.75264644 524448.259809692,5365360.84656802 524886.643,5365264.389 525244.446667801,5365004.31195121 525427.486,5364871.266 526834.242807884,5364987.74375145 528421.99597393,5365119.20778105 530057.692838637,5365254.64149055 531318.261,5365359.015 531669.519146117,5365456.4436309 531899.413299638,5365520.20947626 533278.556856069,5365902.74314843 534241.395,5366169.806 534868.727747756,5366198.30814352 535862.499,5366243.459 536421.444,5366210.286 536454.059088547,5366166.01439868 536898.969905572,5365562.09409084 537405.791,5364874.137 537774.253,5364249.45 538097.711706761,5364153.29342588 538186.691,5364126.842 538319.041,5364034.482 538324.474611288,5363980.41003903 538327.413,5363951.169 538414.038,5363814.04 538395.746,5363692.567 538556.296,5363474.732 538811.359,5362962.664 539721.502142637,5362643.71368574 540222.235,5362468.237 540222.828774539,5362400.67690394 540234.913,5361025.725 539954.577111015,5360403.18325763 539237.043643193,5358809.75711129 538768.842,5357770.022 538904.831920846,5357188.24951072 539282.403957909,5355572.97521305 539282.922,5355570.759 540081.374204488,5353942.74454074 540329.13587328,5353437.56767859 540590.318,5352905.027 540942.106976105,5352331.80678252 541403.832,5351579.452 541417.411,5351552.996 541474.645,5351499.686 541494.378,5351448.573 541624.045,5351037.925 541767.388,5350787.633 541812.104206218,5350737.01131558 541915.439606497,5350620.02885074 542131.328,5350375.629 542342.064,5350459.941 542592.8,5350317.92 542980.498,5349690.624 543341.824,5349263.856 543389.647582808,5349143.8744296 543502.934526602,5348859.65596197 544030.594209357,5347535.84386643 544389.417,5346635.616 544768.189708664,5345907.09214577 545042.706,5345379.093 545073.768,5345257.683 545021.138,5345107.205 545118.353,5345016.884 545179.190362287,5344923.47621679 545339.834,5344676.829 545269.944,5344570.675 545186.589398349,5344588.4800933 545115.225,5344603.724 545081.255,5344466.053 545106.151,5344394.924 545191.755318209,5344356.5039508 545227.844,5344340.307 545298.941,5344346.737 545371.522,5344400.113 545523.83,5344463.388 545586.267,5344417.879 545628.81,5344307.061 545635.73476791,5344288.83903495 545677.475,5344179.003 545516.198,5344179.26 545555.649,5343991.229 545445.555,5343934.775 545421.307,5343871.903 545491.434,5343639.037 545538.047,5343613.163 545681.931,5343700.456 545746.764,5343666.085 545703.861,5343435.096 545706.126,5343306.977 545734.89,5343192.657 545789.228,5343078.85 545910.732,5342898.581 545988.563,5342763.042 546114.709,5342698.909 546115.698565205,5342696.85945804 546147.23,5342631.553 546099.611,5342525.263 546179.368,5342382.332 546158.143,5342277.49 546150.242,5342183.254 546163.392,5342087.953 546233.891,5341968.105 546353.795,5341862.244 546384.093,5341764.612 546371.817,5341675.898 546406.042,5341602.999 546467.242,5341562.122 546531.158,5341491.935 546595.782,5341335.301 546682.801,5341392.514 546731.492,5341367.902 546734.074,5341254.298 546793.797,5341142.706 546796.920124315,5341069.75795911 546800.946,5340975.724 546829.702804815,5340970.51317348 546859.637,5340965.089 546935.417183097,5341071.23316396 546936.136,5341072.24 546994.659,5341132.003 547025.26,5341199.564 546963.581,5341297.553 546887.189,5341353.43 546935.716,5341398.907 547072.874,5341380.582 547160.491,5341339.93 547262.645,5341263.274 547371.941,5341246.27 547411.486,5341304.645 547431.656,5341385.091 547458.37,5341472.693 547509.618,5341562.351 547633.969,5341668.982 547780.999,5341777.041 547863.135,5341848.435 547938.604,5341902.793 547996.069,5342012.268 548007.097,5342074.731 548143.653,5342126.208 548308.86,5342204.793 548387.097,5342223.672 548433.107741179,5342228.82930415 548491.389,5342235.362 548715.885,5342303.656 548870.555,5342262.366 548906.069,5342283.049 548943.59,5342478.201 548975.205,5342520.155 549068.213,5342595.674 549082.311,5342611.542 549106.066,5342631.815 549156.741,5342640.279 549178.145,5342622.246 549222.795,5342635.598 549263.035,5342705.726 549286.127,5342707.16 549404.759,5342610.306 549423.329,5342586.074 549419.404,5342562.883 549425.606,5342537.617 549466.072,5342510.179 549505.77,5342500.024 549596.625,5342514.089 549689.059,5342607.213 549735.331,5342623.671 549807.163,5342642.514 549885.559,5342736.136 549938.37,5342806.687 549971.284,5342840.631 549986.154,5342838.599 550024.735,5342814.544 550035.879,5342814.024 550049.848570131,5342826.35841657 550071.906,5342845.834 550094.243,5342862.703 550318.605327384,5342887.60770346 550332.887,5342889.193 550868.403,5343258.589 551925.594654075,5343445.68418898 553425.443,5343711.118 553578.372584271,5343793.91646471 554224.079,5344143.512 554085.870587265,5344554.99014036 553914.031,5345066.596 553481.9264489,5345394.2815694 552677.609,5346004.234 552609.440410738,5346144.33610868 552346.012,5346685.742 552444.413,5347216.198 552402.526,5347288.068 552361.392,5347278.118 552339.54,5347255.994 552295.374,5347239.533 552289.772,5347243.496 552281.329,5347265.033 552284.446,5347284.823 552276.548,5347314.393 552280.935,5347330.49 552291.325,5347343.862 552283.775,5347357.997 552261.357,5347352.542 552266.636,5347383.777 552267.104,5347400.147 552259.794,5347433.119 552135.332922751,5347756.9139764 551818.987,5348579.912 552011.692122779,5349362.04263356 552311.103,5350577.259 551995.831180082,5350977.01317121 551766.796794742,5351267.42114651 551438.976,5351683.087 551558.184,5352415.97 551736.233514996,5352447.85081675 552226.802,5352535.69 552243.048600333,5352608.64290264 552606.198576243,5354239.3129685 552697.159,5354647.757 553325.020739725,5355090.22467331 554632.112,5356011.36 554909.239293551,5355952.68797318 556570.094131868,5355601.05996 557671.494,5355367.877 557813.151,5355282.853 557852.942,5355215.942 557871.717,5355150.979 557932.772,5355078.108 558020.656,5354938.197 558187.756692178,5354956.78989982 558778.765,5355022.55 558790.328,5355198.369 558702.307,5355270.335 558980.747,5355712.925 559635.379,5355565.659 559677.087,5355376.809 559786.810811494,5355374.80082759 559805.761,5355374.454 560859.984,5355728.689 560814.212227964,5356064.57548428 560813.302,5356071.255 560936.77,5356322.694 561414.838624699,5356616.91326795 562070.552,5357020.461 563038.704053898,5357233.97825157 563335.065,5357299.338 563434.912,5356225.854 564642.203329377,5356187.53414005 566223.008507408,5356137.35881654 567103.531216315,5356109.41070984 567349.329,5356101.609 567838.950266071,5356028.57469323 567893.874,5356020.382 567983.964348441,5356131.18676823 568287.36,5356504.342 569112.243,5356673.332 569443.754407045,5356673.74895058 569985.247,5356674.43 570188.606034177,5356175.6787925 570471.953,5355480.752 570693.19,5355401.973 570753.122,5355168.03 570553.534,5354928.086 570582.743058388,5354564.37549861 570632.193,5353948.626 571113.672375693,5353821.77213622 571321.57,5353766.998 571820.091694902,5352988.91756426 571842.076,5352954.605 572753.430929069,5352767.5145328 573241.44,5352667.332 574122.572,5352472.759 573760.517640225,5351433.58949544 573202.312,5349831.426 573206.581376533,5349773.97250468 573288.533,5348671.14 573541.192540589,5348175.20240659 573650.98,5347959.704 573715.909870876,5346529.39454321 573727.362,5346277.121 574594.340651411,5345907.36682371 575024.331,5345723.982 575406.126598792,5344926.54940408 575677.971,5344358.765 575794.823,5344303.805 575846.914,5344295.233 575882.736,5344300.341 575916.052,5344276.698 575950.266,5344232.068 575942.526,5344193.675 575931.616,5344176.546 575919.753,5344168.977 575904.466,5344139.747 575911.253,5344110.192 575913.739,5344093.859 575929.123,5344084.8 575982.415,5344032.705 576050.58,5343963.515 576139.078,5344071.23 576146.845,5344076.583 576154.723,5344089.04 576178.436,5344135.985 576198.8,5344186.59 576205.981,5344220.345 576268.150525235,5344257.21948135 576433.947,5344355.558 576460.035,5344455.958 576417.133,5344486.881 576399.273,5344526.786 576354.144,5344585.471 576316.658,5344597.013 576278.769,5344623.372 576276.991,5344663.801 576288.047,5344700.696 576291.346,5344731.62 576294.855,5344793.119 576317.462,5344814.419 576321.125,5344913.0 576349.05,5344935.274 576385.209,5344930.2 576414.963,5344941.406 576425.449,5344974.588 576457.025,5345019.169 577270.438,5345017.463 577419.695,5344869.717 577637.723,5344867.429 577638.74,5344807.844 577637.608,5344800.109 577633.787,5344777.823 577646.083,5344556.27 577858.395498627,5344374.82075384 578098.111,5344169.952 577983.545,5344010.28 577870.799266675,5343995.66099251 577339.663,5343926.792 577439.156,5343374.154 577418.045950075,5343349.80729019 577240.295,5343144.803 577351.031,5342737.143 577787.435,5342734.114 577877.676,5342773.635 577914.760715966,5342747.23188922 578338.551,5342445.507 578563.657,5342445.51 578891.533,5342877.409 579539.718,5343074.151 579580.062887345,5343081.82671725 580109.056,5343182.469 580428.643,5343386.14 580570.447,5343424.578 580677.436,5343415.589 580696.864,5343369.234 580882.552,5343338.819 580954.788,5343365.782 581109.486,5343367.669 581126.558,5343356.794 581153.692,5343349.151 581193.740207828,5343304.2287266 581245.307,5343246.386 581503.321,5343237.092 582188.375,5343343.567 582804.217608689,5342272.24544707 582857.38,5342179.764 583410.230499244,5341785.21975707 584115.486,5341281.911 584321.459250725,5340199.72573453 584373.67,5339925.41 584444.052922083,5339936.64709769 585781.454,5340150.172 586052.911303773,5340219.45571218 586060.401197404,5340221.36734848 586482.241,5340329.033 586722.47098628,5340235.02169628 586732.73026337,5340231.00684356 586733.455131214,5340230.72317468 586733.706,5340230.625 586734.346642791,5340230.77208047 587666.252684771,5340444.72153606 587998.941,5340521.101 588074.727157533,5340246.81160393 588103.872,5340141.329 588454.006,5339912.343 589289.403356798,5339559.18325302 589300.922048736,5338697.20336088 589330.88158939,5337083.19477104 589344.840832338,5335466.18659232 589375.799835842,5333832.17777631 589413.759065257,5332205.16868353 589447.718723428,5330598.15973728 589421.677569149,5328983.15297854 589404.637199152,5327394.14613183 589393.595521865,5325750.13889061 589391.554825624,5324141.13150972 589423.51370196,5322505.12249251 589449.47354742,5320910.11388143 589472.432393428,5319277.10519543 589492.391231896,5317645.09663268 589557.327364741,5316038.14876436 589610.247050873,5314432.24530066 589687.166826041,5312827.34054162 589760.086571563,5311223.43592443 589794.004664517,5309590.53503253 589813.924074779,5307985.63306279 589833.843145254,5306374.73141241 589854.761727334,5304754.83021731 589850.690324137,5303335.91779226 589849.684085117,5303211.98796954 589836.604834502,5301638.02294658 589832.518533866,5299924.1285249 589798.437037778,5298307.22945341 589824.356272078,5296703.32672913 589854.276024973,5295110.42310374 589891.711273188,5293825.43772011 589898.886326741,5293578.51503776 589900.694793715,5293498.51986128 589929.132166673,5292256.59471918 589933.561446002,5292093.60451093 589938.92656038,5291897.61628293 589944.665983588,5291687.94137658 589978.174239362,5290612.81826398 589988.033286093,5290296.71219285 589992.999549548,5289628.50289911 589997.657264298,5289007.72209249 590004.831688645,5288699.91846514 590021.925512196,5287966.18961244 590030.902163723,5287416.83060779 590047.888728129,5287100.83929792 590116.712163097,5285889.05999224 590136.447356351,5285541.38202484 590141.319825875,5285482.00858994 590175.239774093,5285070.33194198 590230.150033524,5284431.97369368 590273.753377139,5283924.92451864 590346.768671837,5282820.0795009 590359.934884135,5282321.34384726 590402.762389907,5281209.87528104 590403.198955841,5281188.00091585 590415.115143658,5280689.07781656 590416.300550313,5280640.07923013 590463.878699903,5279545.29749472 590490.045015092,5279050.93621315 590552.560083105,5277945.279267 590571.104668187,5277527.54101025 590576.16388836,5277451.23059324 590642.992486551,5276371.88525474 590677.095635271,5275864.33661944 590741.616737182,5274903.6128942 590756.607487748,5274689.18124283 590780.02667555,5274264.06806792 590821.121166164,5273556.46268782 590844.100980463,5273088.03833184 590859.025397483,5272784.54684905 590866.269046009,5272637.23848383 590905.219199914,5271479.27161332 590935.204816209,5271148.0304548 590944.950154602,5271040.72081967 591043.399631439,5269877.75215533 591053.769301984,5269755.19296268 591076.692479513,5269425.13953795 591110.517197168,5268259.48564049 591117.254888758,5267973.99391934 591128.122845498,5267811.8733961 591206.009888956,5266651.40546997 591199.616494462,5266222.16843626 591198.488342556,5266148.60815838 591175.006180318,5265104.63989 591175.439715822,5265012.45511298 591177.687918502,5263516.49940567 591178.432325836,5263386.50323498 591185.255417681,5262180.038753 591187.055459458,5261890.54726464 591185.737812806,5261770.48835248 591185.389639317,5260657.07797112 591184.567050358,5260286.58616161 591186.251345165,5260169.58869304 591203.585911612,5258692.558237 591206.144707272,5258557.62363551 591231.790581386,5257040.59378715 591239.281180766,5256698.72609417 591269.618002448,5255310.69324746 591290.448603308,5253691.72817665 591305.65503736,5252101.76256354 591326.173869598,5250510.79678628 591291.880300777,5248901.8326817 591296.39843466,5247279.68033507 591193.586980174,5247275.43286786 591221.166060928,5245605.90588963 591242.55956521,5244004.94002282 591286.202814154,5242404.97359231 591309.471500193,5240813.007405 591328.739695874,5239202.04166475 591344.570552771,5237596.07583646 591363.4010812,5235980.11010727 591378.544330248,5234371.1442482 591394.017360582,5232782.18812091 591420.004054301,5231157.24153439 591448.990594695,5229517.29534933 591475.977567139,5227928.34746962 591495.964618956,5226341.39958728 591521.951475128,5224737.45212944 591545.938530749,5223156.50389693 591566.925327205,5221541.55677295 591586.912063263,5219919.60983592 591626.898708537,5218299.78757514 591466.899466999,5218297.69547592 591480.886345409,5216706.71608139 591500.873003762,5215093.76854045 591530.859899174,5213513.81979972 591556.846369643,5211880.87277365 591590.833237315,5210296.92407028 591617.819976923,5208695.97592128 591635.806519539,5207072.02850491 591658.787079717,5205480.07127601 591684.746751559,5203843.08684967 591707.707415759,5202247.10199548 591737.667785504,5200640.11717552 591752.164237744,5199168.19328055 591745.051248586,5199157.97121544 591736.450994764,5199147.03135422 591727.360817793,5199139.1714658 591713.250707976,5199133.66157558 591701.69061102,5199128.86166826 591694.950522966,5199124.78173446 591688.71036928,5199118.07182361 591679.469948723,5199100.29203013 591669.629518109,5199082.05224353 591661.499009181,5199060.75247907 591657.138495057,5199039.52269857 591651.655586978,5199020.88079978 591650.817978316,5199018.0329286 591645.887660254,5199004.72307527 591638.387346142,5198991.37323288 591628.607062769,5198979.09338973 591609.086908203,5198971.29354405 591587.626729705,5198962.36371715 591563.856614487,5198955.82387707 591549.706571326,5198952.96396247 591532.706483829,5198948.07407893 591520.526421268,5198944.57416236 591503.416518085,5198947.18420787 591487.676834431,5198958.85416137 591476.116992589,5198964.40415597 591463.257050205,5198965.75419594 591439.577037757,5198963.40431567 591418.137065166,5198962.85440902 591402.3369922,5198958.64451415 591387.596923142,5198954.67461266 591372.306757534,5198946.71475157 591361.88654159,5198937.07488656 591351.456325752,5198927.43502162 591304.93543812,5198887.46559553 591277.244851213,5198861.24596072 591252.174400459,5198840.7862602 591238.044309966,5198835.94636498 591209.974085347,5198824.48659089 591185.473704708,5198806.90686083 591164.663437088,5198794.24706845 591143.243186502,5198782.22727256 591121.182996363,5198772.62745619 591093.642654176,5198756.32772701 591077.672374188,5198743.5179164 591064.162020583,5198727.87812286 591050.671645469,5198711.34833787 591035.341311237,5198696.33854601 591017.530831238,5198675.11882431 591002.060240344,5198649.51913515 590986.669767733,5198628.77939902 590973.759424895,5198613.57959931 590960.259056729,5198597.27981272 590947.948713249,5198582.09001055 590938.108526502,5198573.56013392 590918.558425989,5198567.75027178 590904.458294847,5198561.14039457 590889.758164789,5198554.52052 590878.218040119,5198548.3906275 590865.947874116,5198540.49075517 590853.017564862,5198526.62094327 590835.706776913,5198492.61134429 590827.656379556,5198475.51154325 590815.27566934,5198445.11188896 590807.865228319,5198426.25210237 590801.604854944,5198410.28228305 590799.154682936,5198402.96236412 590792.974432274,5198392.06249552 590781.944222379,5198382.41263536 590770.844114137,5198376.95273504 590759.913978962,5198370.39284465 590743.933954186,5198367.94293589 590734.783874538,5198363.83301434 590720.763627729,5198352.37318451 590701.123183212,5198332.22346265 590678.922733274,5198311.60375636 590661.822348884,5198294.14399798 590646.401913493,5198274.71425168 590624.981420651,5198252.34455949 590604.671096107,5198237.0347943 590583.300768642,5198221.49503596 590558.060368849,5198202.58532696 590540.330013877,5198186.21556145 590526.889800117,5198176.09571704 590516.419649661,5198168.87583184 590504.739512344,5198162.08594766 590492.529498122,5198160.35601659 590481.579391292,5198154.8961164 590462.528981496,5198136.08638067 590452.04861395,5198119.82658362 590441.59819886,5198101.58680577 590431.067667239,5198078.48707563 590423.507215111,5198058.96729799 590416.736703357,5198037.03754047 590411.006216019,5198016.21776774 590407.195565925,5197988.80805094 590405.235087562,5197968.71825495 590400.83464547,5197949.89845711 590395.204248641,5197932.83864748 590389.583819913,5197914.44885079 590360.542500582,5197856.66953909 590337.021288063,5197803.8301559 590322.27075184,5197780.01045213 590310.39021521,5197756.45073347 590301.83989959,5197742.43090738 590290.779488732,5197724.18113352 590280.779075703,5197705.94135503 590269.868913454,5197698.06147947 590253.21876847,5197690.31162771 590235.548562369,5197679.90180643 590219.688357719,5197669.73197498 590206.158043059,5197655.20217601 590200.9020524,5197647.37190981 590194.337650603,5197637.59239974 590185.677262455,5197620.48260484 590179.526974704,5197607.8227555 590176.976700304,5197596.09288133 590175.116546028,5197589.45295439 590160.376234443,5197574.89316135 590139.905207476,5197529.81369208 590122.754659444,5197505.08400942 590110.984178905,5197483.73427014 590099.853886948,5197470.33445032 590087.693555221,5197455.15465252 590075.353271417,5197441.95483619 590064.343021839,5197430.32499868 590052.562805392,5197419.99515188 590037.91260097,5197409.85531594 590026.242442697,5197401.96544483 590005.472367614,5197396.57558946 589993.272342065,5197394.18566682 589972.602587769,5197402.25567898 589953.18300385,5197417.61561399 589941.803344265,5197430.67553598 589928.463683839,5197443.49546892 589915.783937506,5197452.78543356 589907.204150616,5197460.81539246 589896.374337011,5197467.48537463 589879.214516341,5197473.18539417 589862.824677921,5197478.22541678 589847.684763466,5197480.20546397 589817.164845685,5197480.40559637 589803.08492372,5197482.18564083 589787.234937315,5197481.06572165 589770.215131557,5197487.4257339 589753.295409265,5197497.31571088 589680.976225268,5197524.01576544 589662.106490591,5197533.20575759 589645.596594144,5197535.82580422 589622.536800548,5197542.09584352 589587.437445058,5197565.60576507 589567.907784387,5197577.8857292 589546.078190946,5197592.77567748 589538.838425327,5197601.92561859 589527.948714554,5197613.01555644 589518.259016549,5197624.77548235 589506.189245361,5197633.19545171 589505.049383366,5197638.91540002 589499.559712858,5197652.28529151 589489.909952055,5197661.40524327 589434.07070408,5197687.46522851 589412.131036017,5197699.26520706 589400.071269417,5197707.91517373 589387.341602693,5197720.73510186 589378.831927032,5197733.61501096 589374.672070781,5197739.28497273 589369.252284741,5197747.80491165 589335.242630162,5197758.98494841 589318.732747143,5197762.26498756 589293.742897157,5197766.08505817 589265.763011661,5197768.09515976 589243.223114695,5197770.17523699 589217.07319437,5197770.89534344 589195.01324987,5197771.0054382 589175.523300135,5197771.15552139 589153.043299567,5197768.83564222 589126.173328579,5197767.32577407 589103.603473267,5197771.18583359 589067.693479392,5197767.77602371 589041.923444409,5197763.64617701 589012.183479457,5197762.09632179 588987.733498796,5197760.41644489 588960.273498246,5197757.57659272 588931.003501634,5197754.71674865 588906.01343427,5197749.26691197 588877.943450807,5197747.08705593 588858.973386897,5197742.39718553 588835.763347036,5197738.29732768 588819.913374687,5197737.84740117 588802.893332618,5197734.28751101 588784.433180284,5197725.8476762 588745.252639642,5197698.58812103 588726.862374672,5197685.29833495 588711.012161243,5197674.47851301 588702.962013683,5197667.29862042 588698.641925277,5197663.04868208 588692.011913514,5197661.84872311 588687.741978851,5197664.20871799 588688.892079148,5197668.63866835 588698.782407486,5197683.77847274 588702.562635755,5197693.97835355 588706.832796289,5197701.31826103 588712.403051732,5197712.86812048 588716.793510109,5197733.00789863 588700.933296408,5197722.18807661 588681.903104714,5197711.97826233 588667.862882262,5197700.95843452 588651.992684389,5197690.7986061 588635.402683002,5197689.00869649 588617.772658363,5197686.10880263 588604.8625519,5197680.17891876 588588.432540007,5197677.94901295 588569.392344313,5197667.52920121 588568.968985745,5197667.31239195 588557.8522352,5197661.61931126 588547.992076788,5197653.75943369 588540.762066345,5197652.54947749 588528.412025716,5197649.49956226 588507.092111163,5197650.93964085 588490.662084253,5197648.04974185 588477.872034581,5197644.55983302 588463.171917084,5197637.93996423 588450.931707928,5197627.62012214 588435.541479747,5197616.14030563 588416.051291207,5197605.93049428 588394.591106997,5197595.69069194 588376.280957076,5197587.26085754 588358.440790861,5197578.17102783 588337.000581682,5197566.83123678 588319.900429657,5197558.42139707 588298.460230781,5197547.51160183 588273.419989111,5197534.35184533 588251.399751503,5197521.68207071 588228.729586578,5197512.08226786 588209.209440476,5197503.63243956 588195.699337559,5197497.70255926 588181.739220396,5197491.10268779 588169.469069117,5197483.20282214 588127.08835378,5197447.51337199 588109.338037262,5197431.81361012 588076.167536795,5197406.40401537 588062.727332977,5197396.05418022 588040.007003099,5197379.18445262 587997.189861146,5197355.28233246 587958.036162317,5197333.42528241 587934.705835169,5197316.54555824 587900.945324469,5197290.46597456 587881.355060404,5197276.72620204 587867.284890095,5197267.69635691 587848.304604915,5197253.08659076 587828.074161195,5197231.39690275 587808.333671272,5197207.727233 587783.193123736,5197180.89761988 587766.632839135,5197166.53784091 587752.522488827,5197149.57807775 587745.732257522,5197138.66821992 587736.522042088,5197128.16836874 587730.271910456,5197121.67846324 587716.911795528,5197115.08859059 587694.711369148,5197093.81890817 587675.791005574,5197075.66917921 587662.200554507,5197054.29945952 587646.160169836,5197035.53972414 587622.279769051,5197015.13004106 587608.69953988,5197003.46022203 587589.04913941,5196983.54051516 587574.908610826,5196958.64083484 587565.00829315,5196943.50103515 587549.647782781,5196919.23135408 587540.387403603,5196901.45157881 587526.217157141,5196888.90177197 587518.816939183,5196878.42191328 587513.906830852,5196873.06199065 587475.196042997,5196833.68257137 587466.655723194,5196818.56276583 587456.105228056,5196795.47305158 587447.334793776,5196775.27329955 587426.384069539,5196740.78375027 587410.293298763,5196704.82419429 587398.562542597,5196670.03460656 587380.481562538,5196624.55515828 587366.190803783,5196589.28558758 587347.020127911,5196557.02600837 587327.929317525,5196518.81649047 587314.23855874,5196483.55691752 587296.277646554,5196440.94744036 587285.827234818,5196421.39769053 587275.336907821,5196405.57790241 587258.686522841,5196386.37817774 587240.856106155,5196365.60847489 587227.98572128,5196346.88872802 587212.455244236,5196323.72903949 587199.004821805,5196303.24931373 587185.484489313,5196286.7295474 587173.064104207,5196268.01979873 587168.223898197,5196258.24992236 587163.193747467,5196250.90002183 587144.093191878,5196223.72039212 587129.412808739,5196204.76065684 587115.322662993,5196196.39080917 587096.402530814,5196187.96098466 587068.792084367,5196164.40135765 587050.871800577,5196149.36159726 587039.241604152,5196139.05175853 587031.931475344,5196132.3318624 587023.881323642,5196124.49198137 587015.953105316,5196117.00221901 586992.580754886,5196094.9224347 586964.53051538,5196080.40271676 586951.730491577,5196077.57280607 586939.480530623,5196077.61286298 586930.930460349,5196073.30294781 586919.780208735,5196060.5631325 586897.029712456,5196035.31350178 586872.529340524,5196015.33382462 586835.68847428,5195971.57445331 586813.588136341,5195953.39474664 586794.58788868,5195939.66497915 586784.147715803,5195930.4751241 586769.397436609,5195915.9253453 586755.387185038,5195902.70554921 586744.236920685,5195889.31574148 586730.716613668,5195873.67596848 586719.726349092,5195860.28616011 586712.936126887,5195849.38630597 586703.595872443,5195836.67648281 586694.975680448,5195826.8566261 586683.425585446,5195820.94674245 586665.725424698,5195811.20692794 586622.865243747,5195796.91728017 586582.025195185,5195788.82755819 586559.945052865,5195779.24776306 586542.185001331,5195774.35789842 586526.414894799,5195767.28804722 586511.03465958,5195754.49825415 586493.82445946,5195743.00845621 586473.758613228,5195728.45415584 586473.034191215,5195727.92871298 586460.164032538,5195718.91886859 586447.243726959,5195703.29909382 586431.253494387,5195690.49930414 586414.073240761,5195676.56953205 586398.83302122,5195664.44973183 586382.20284978,5195654.27991781 586362.052757661,5195647.15008869 586339.492672947,5195639.99027143 586326.092639414,5195636.49037208 586313.182545683,5195630.35049818 586297.922356123,5195619.54068464 586239.912275238,5195607.24109084 586213.012355678,5195606.85122332 586194.702459283,5195608.79129025 586175.202527376,5195608.95138161 586160.642644191,5195612.05141839 586143.592665855,5195610.4815163 586121.672741036,5195610.60161962 586105.182824558,5195611.91168447 586012.442814525,5195597.56227868 585983.132887786,5195596.48243003 585966.072919379,5195595.35252344 585942.752828907,5195587.74271535 585919.572762354,5195581.23289501 585870.112760303,5195573.68321133 585796.232735106,5195561.37369507 585746.842854756,5195559.34395277 585712.032814533,5195552.23419481 585679.152811925,5195547.12440644 585661.367196132,5195543.78459015 585634.91243334,5195523.11487374 585607.791931338,5195496.04529199 585587.121714185,5195482.95553059 585567.161562901,5195472.97573272 585551.981493441,5195467.46586432 585533.791404237,5195460.58602501 585505.811518506,5195461.50614952 585483.161563497,5195460.07627352 585441.311455623,5195448.67659626 585432.732356882,5195443.09280206 585365.090631824,5195399.06749319 585316.56012397,5195368.16805768 585280.319737416,5195344.71848361 585239.069391127,5195322.29892302 585208.268998482,5195299.35931787 585074.126805628,5195176.82128407 584917.96486975,5195061.91328176 584889.584452391,5195037.91367918 584867.854023639,5195014.45403853 584858.823763025,5195000.87422927 584852.243456499,5194985.56442674 584836.613141685,5194968.36468898 584831.853038493,5194962.78477256 584808.762843308,5194949.88502505 584793.042671666,5194939.29521655 584780.952478743,5194928.31539452 584746.041678369,5194885.2660314 584726.721244485,5194861.83637984 584674.790426929,5194815.0071424 584657.19035791,5194808.80729629 584640.680465025,5194810.99735394 584619.990524693,5194810.26746383 584603.050358897,5194799.65766237 584503.478615705,5194701.21922258 584468.627719959,5194653.30991578 584446.957195369,5194625.00033104 584427.046745276,5194600.46069678 584404.066381612,5194579.41104001 584391.346232398,5194570.19120361 584291.034924438,5194491.15256438 584184.023492333,5194404.74404223 584162.253119124,5194383.26438593 584139.89272035,5194360.4547473 584128.562297041,5194338.46504452 584119.651874604,5194316.94532453 584108.931435569,5194294.30562596 584084.71089062,5194264.19607715 584009.419376432,5194178.89739061 583968.488572612,5194133.32809687 583928.488177406,5194107.18858604 583893.357732599,5194079.56906716 583883.694145455,5194074.67601182 583867.38755773,5194066.41934326 583846.727706804,5194052.84287567 583836.52725215,5194046.13972265 583756.755905956,5193967.18099636 583724.295297683,5193932.10154781 583711.624848325,5193908.32187421 583691.254414347,5193883.78224845 583591.823615985,5193826.60338736 583570.793274388,5193806.24371974 583557.39301044,5193791.05395607 583533.972641526,5193768.89432087 583511.022243702,5193745.42469792 583501.842204663,5193741.76478552 583489.182202116,5193739.1648793 583468.771606054,5193706.6853432 583451.931093753,5193678.88573722 583421.77064221,5193651.33619733 583390.350062707,5193617.37673521 583358.459490698,5193583.63727348 583295.798276023,5193512.85838203 583274.147510384,5193471.75895 583259.886959878,5193442.44934912 583183.265656295,5193364.20061636 583141.784560925,5193302.98151292 583130.984022225,5193274.82188234 583114.903491413,5193245.93228762 583092.602798409,5193207.91282721 583051.911650411,5193144.06375114 583022.851151542,5193113.8842399 582995.61085177,5193093.66460846 582981.090696483,5193083.09480269 582973.420440263,5193069.0949991 582963.230126083,5193051.75524605 582965.710029067,5193047.59527934 582960.259836966,5193037.15542444 582950.669525145,5193020.04566576 582942.259245083,5193004.71588108 582929.178742569,5192977.62625225 582917.718302239,5192953.87657773 582900.987842822,5192928.05695432 582878.067409964,5192902.16736469 582811.746262828,5192832.21849791 582783.935916247,5192809.34890141 582762.175780734,5192798.0191439 582742.675853992,5192797.30925566 582726.855834484,5192792.89938923 582728.165679079,5192785.63946347 582723.335472528,5192774.54961328 582716.255239147,5192761.65979524 582704.155077147,5192751.1299776 582683.535028339,5192744.22016494 582667.214852815,5192732.09038784 582641.194550911,5192711.66075561 582619.324345211,5192696.81103885 582597.054055172,5192677.75137156 582578.393786582,5192660.5216646 582522.193068794,5192612.99249891 582493.15276908,5192591.8628919 582455.592574425,5192573.92329501 582352.581983529,5192521.784435 582331.8718484,5192510.47467376 582311.941678437,5192497.62492575 582296.911384177,5192479.78520769 582281.851139437,5192464.35546273 582252.572755061,5192449.44172849 582246.710938041,5192446.455854 582218.130851991,5192435.69612955 582176.900740979,5192420.79652024 582087.280198283,5192373.47753914 582058.77999275,5192356.76788231 582023.069747915,5192336.42830578 581955.249275542,5192297.34911592 581865.088646742,5192245.18019697 581831.138468663,5192228.39057209 581808.058491843,5192224.11074617 581774.088363572,5192209.7510941 581708.067913297,5192171.80188511 581682.717725523,5192156.46219784 581648.177317825,5192127.98271051 581552.036389063,5192058.75402492 581521.216055931,5192034.73446767 581494.055645024,5192007.68492526 581462.6652673,5191981.23539948 581436.664922932,5191957.72581081 581419.114809399,5191947.7860208 581407.104511649,5191929.97629043 581400.534422889,5191923.93639561 581393.864259675,5191914.14654425 581389.124135873,5191906.79665439 581379.463924818,5191893.87685533 581371.613718802,5191881.64703847 581363.853609133,5191874.25716575 581351.133483073,5191864.82734372 581331.763370172,5191854.41756959 581310.553309983,5191846.18778071 581291.123294657,5191840.63795137 581267.453294473,5191834.79814878 581248.683201565,5191825.50835878 581234.11279107,5191818.05308999 581231.463031061,5191812.69860067 581220.142829084,5191799.75881157 581202.792409343,5191774.37919856 581189.201998844,5191750.3795491 581182.131764421,5191736.8397436 581161.351287257,5191707.6701935 581134.22107282,5191690.10054557 581094.240906154,5191671.69097873 581060.990822217,5191659.11130778 581013.660822823,5191647.23170708 580971.870897801,5191640.48201675 580927.510968046,5191632.83235118 580879.07083546,5191613.87283887 580844.730571352,5191591.79328453 580798.870197524,5191561.18389313 580753.92957731,5191518.24463966 580717.929110997,5191485.33522101 580701.898740805,5191462.40557576 580688.208481239,5191445.6858457 580679.778474079,5191443.14592222 580664.348773884,5191454.40587812 580653.504886832,5191448.80186727 580648.578693681,5191446.25606061 580633.148334579,5191423.99640466 580622.667795934,5191393.8668123 580612.717354449,5191368.80715835 580595.957193304,5191356.23739794 580566.72717941,5191347.9076584 580551.667152948,5191342.6278041 580532.436852851,5191322.29814781 580509.106581813,5191302.35851017 580485.446584917,5191296.30871331 580443.066407771,5191276.11918598 580403.986033909,5191246.6997477 580350.455650314,5191212.90044224 580282.635433514,5191183.77116369 580205.8351252,5191147.45202046 580143.014865834,5191117.28272746 580078.424565554,5191084.44347641 580048.064015281,5191047.87407583 580029.533560725,5191019.40451381 580004.983328769,5191000.76487116 579967.953262509,5190987.26523939 579923.323081154,5190965.71574531 579868.462645619,5190928.15649751 579835.761993633,5190885.38718536 579816.671490524,5190854.03766205 579793.510983096,5190821.3081784 579752.440480473,5190783.48145969 579746.140396182,5190777.67896152 579676.829948938,5190735.07985899 579630.659385306,5190692.7906212 579564.698451875,5190625.53179203 579531.737954913,5190590.25239741 579510.39743232,5190556.89291362 579492.626984608,5190528.4333517 579465.656543213,5190497.64387059 579439.936264655,5190475.69427822 579407.555802436,5190442.1848611 579362.204921486,5190382.92582383 579339.744278964,5190342.71642941 579321.303922697,5190318.65682098 579295.373732555,5190301.10717924 579263.973593102,5190284.59755719 579237.083257912,5190259.09801555 579207.19268387,5190220.11865133 579181.76199461,5190176.3393184 579152.311654602,5190149.70980606 579110.751401464,5190124.02035368 579063.201085565,5190093.18099791 579044.428208018,5190081.66904062 579019.090823164,5190066.13157752 578966.180426366,5190029.27232584 578922.870091355,5189998.49294618 578888.639691135,5189966.94352281 578862.559068552,5189926.0241635 578838.52873908,5189901.23460032 578815.538645213,5189889.24487867 578789.168433249,5189869.93526434 578763.268194193,5189849.30566317 578744.388260847,5189847.06580132 578739.028178565,5189841.0459048 578730.088028998,5189830.34608527 578722.417797773,5189815.68630555 578714.157532672,5189799.03655312 578703.397418341,5189789.63672896 578684.507498179,5189788.06685941 578669.177653521,5189791.61690765 578656.517661476,5189788.13702409 578638.957564492,5189777.5472545 578621.567441753,5189765.62749988 578599.897194325,5189745.71786623 578574.547025596,5189728.84821818 578547.887013065,5189719.89848327 578514.616975632,5189707.54882835 578480.017123221,5189704.66906801 578451.617018215,5189690.18940999 578426.157008175,5189681.69966285 578404.137254432,5189688.0197177 578390.75721403,5189681.66987328 578363.196990006,5189661.02028473 578327.946982147,5189649.54063194 578299.937171879,5189650.94078151 578278.577344653,5189653.52087737 578266.007222363,5189642.99107864 578252.697079807,5189631.13130036 578236.427081023,5189626.07145793 578210.387042809,5189615.80173633 578202.66688166,5189604.68191607 578190.586708135,5189591.51214648 578172.586592704,5189579.59239713 578148.41646721,5189565.16271486 578125.736166164,5189541.71313253 578105.806005074,5189526.67343263 578095.466141187,5189530.73344535 578078.346282794,5189532.93352092 578044.546143635,5189514.63394327 578024.105863996,5189492.97432665 578006.305463845,5189465.61476322 577980.784908734,5189427.3553778 577969.58454528,5189404.05572625 577956.004146988,5189378.08612131 577946.473985791,5189366.26632124 577928.184078295,5189365.36644178 577905.774027909,5189355.37669693 577875.223760487,5189330.94717567 577852.283608033,5189315.20750383 577823.443279063,5189287.92800728 577813.893143505,5189277.43819169 577794.103006342,5189263.5084794 577775.96288833,5189251.14873826 577752.612670999,5189231.65911498 577737.782344154,5189208.9794792 577720.962045222,5189187.14984524 577697.601857313,5189169.20020383 577674.55185403,5189161.41043743 577643.621920768,5189154.83070399 577613.981867357,5189142.10103753 577600.976878164,5189133.86534911 577554.261538406,5189104.28185795 577525.361292531,5189081.19231351 577506.271013892,5189059.55269228 577487.170755922,5189039.02305776 577467.220639836,5189025.97333749 577445.970652165,5189019.52354485 577439.016374108,5189014.65756724 577416.430456434,5188998.85397575 577388.810326058,5188982.39434393 577346.119976504,5188948.76501319 577331.049773146,5188932.47530347 577324.259372818,5188908.13564167 577317.289001535,5188885.32596236 577306.058691942,5188864.45628539 577292.998421472,5188845.10660111 577277.037984339,5188815.56705901 577256.837573067,5188785.97754359 577235.217266854,5188761.66797259 577231.376946104,5188742.64822839 577223.136663936,5188724.23850369 577194.026727023,5188717.68876193 577171.666606075,5188703.28907487 577143.046180313,5188669.84965918 577122.645849081,5188644.45009502 577118.845473407,5188622.34038885 577112.545013641,5188594.70076574 577100.804574992,5188566.32118521 577082.344269207,5188542.93158509 577060.873958322,5188518.18202034 577039.153780593,5188500.70236827 577017.503733784,5188490.49262684 576997.663457883,5188468.19302251 576976.863053085,5188438.37351648 576958.882921322,5188424.6937953 576941.412707191,5188406.60412517 576925.372389443,5188383.24451097 576907.621924083,5188351.04501599 576887.501422347,5188315.94557151 576869.330921085,5188281.53610671 576850.410409065,5188246.22665786 576832.109885924,5188210.48721068 576808.439286293,5188168.50787388 576793.04890039,5188141.40830288 576769.77857616,5188114.86877432 576744.998475145,5188100.21910916 576718.308520516,5188093.03936414 576697.738433013,5188080.64964511 576674.428173853,5188057.64007408 576638.34786194,5188026.97067752 576595.637561303,5187994.44134583 576556.527286507,5187964.62195867 576523.347143508,5187944.34241699 576484.18693344,5187918.04298745 576452.246733115,5187894.92347366 576418.75640237,5187863.84406828 576390.546038795,5187832.8346292 576380.555688208,5187809.33498276 576375.655168337,5187778.18539894 576365.674810111,5187754.23575815 576353.144640668,5187739.96601379 576327.394423762,5187718.02644793 576309.174412461,5187710.51665601 576271.234189423,5187683.5772295 576240.402110655,5187656.93773156 576233.124068803,5187657.72787386 576225.834239865,5187660.05797394 576214.87431734,5187653.30825299 576198.634460779,5187644.93864603 576184.04461,5187638.5789846 576162.99478831,5187627.28949963 576146.354664754,5187603.26009628 576127.614756088,5187589.35060327 576106.594903317,5187576.30113996 576087.80507291,5187566.80159257 576062.475388892,5187558.98214016 576025.475953312,5187553.43286636 575998.106405775,5187551.32337852 575975.586768737,5187549.05380663 575954.31706723,5187544.37424284 575939.887183307,5187536.25460088 575929.737169917,5187525.10492104 575914.148521236,5187515.43169817 575912.317292537,5187514.29536597 575885.76744941,5187496.0960658 575861.527708176,5187486.08662179 575835.570282122,5187479.34088602 575831.208113,5187478.20725898 575808.84826181,5187463.81783671 575806.938006683,5187447.24807886 575805.357915364,5187440.398193 575803.077763077,5187429.33837247 575797.297703652,5187420.00859235 575791.927682993,5187413.31877177 575778.117784823,5187404.98912166 575762.437985094,5187400.379458 575738.178271836,5187391.91999511 575718.848555843,5187388.36038309 575706.768734994,5187386.23062436 575689.089024546,5187384.68095779 575658.259512094,5187380.98155176 575644.209726034,5187378.8218284 575618.250104463,5187373.86235177 575601.190352471,5187370.56269623 575581.200725273,5187371.4130405 575568.94094971,5187371.69325468 575548.361309906,5187371.21362617 575525.871638659,5187366.96407902 575486.642179172,5187357.65489286 575454.592496697,5187342.91564761 575445.582567783,5187337.72587297 575423.26285158,5187331.05635336 575400.373114675,5187322.60686632 575379.913304209,5187312.42735793 575363.673449834,5187304.0677517 575351.613609611,5187300.82800672 575337.753766715,5187295.57831905 575305.894027984,5187277.75910953 575294.484111203,5187270.77940017 575278.924141491,5187256.46985694 575264.544193081,5187244.60026201 575247.944219052,5187228.96075407 575232.384245731,5187214.43121369 575219.184318711,5187205.00156711 575211.97438135,5187201.16174364 575193.004376827,5187181.30233112 575179.86436086,5187166.80274745 575169.694380349,5187157.41304659 575163.294344543,5187148.73326979 575153.684407833,5187142.4435199 575138.614587,5187137.18385408 575123.334857743,5187136.98412819 575096.555336425,5187136.87460556 575070.565739892,5187133.2451133 575037.186251402,5187128.19577032 575001.006709423,5187117.15655273 574970.657155948,5187111.48716378 574943.557441657,5187099.89779182 574904.487756607,5187077.57876819 574888.307822264,5187064.58921988 574856.727897893,5187036.19014004 574844.997800766,5187018.40057331 574831.507654882,5186995.96109664 574820.837527609,5186977.52151932 574811.487438081,5186962.63187371 574799.147355995,5186945.06231515 574790.837282459,5186932.17262581 574786.057271899,5186926.59278133 574777.657321941,5186920.75300454 574766.21744136,5186915.7632711 574751.767587608,5186909.19361117 574728.857876346,5186902.06410885 574690.288321683,5186887.69497666 574663.758652189,5186879.205556 574639.70885492,5186865.89615218 574627.71890812,5186856.48648449 574599.569001107,5186832.53728825 574572.749105064,5186810.59804301 574546.379212499,5186789.31878148 574508.799314281,5186755.99987188 574479.069310937,5186724.76079637 574461.329265485,5186703.59138008 574449.419203712,5186687.56179498 574434.629200966,5186671.942256 574423.229255771,5186663.20256961 574409.409361287,5186654.87292114 574395.229347899,5186639.26337124 574383.249390361,5186629.19371206 574366.329646117,5186626.33404961 574356.119721672,5186620.03431121 574344.139752869,5186609.30466043 574331.169710523,5186593.26509453 574320.509570112,5186573.94552904 574310.609420016,5186554.85594712 574302.489280041,5186538.21630248 574290.109257948,5186523.95670362 574277.619173183,5186505.93715436 574257.768923824,5186470.62795526 574256.088764186,5186459.58812502 574240.768665721,5186437.78867416 574232.718430034,5186415.63909819 574227.588301466,5186402.77935251 574223.684064193,5186395.95814203 574222.248237434,5186393.44956588 574219.528073623,5186381.06977117 574213.0080005,5186369.970028 574205.397988375,5186361.27027388 574195.19804165,5186353.65055226 574190.40805513,5186349.4006915 574179.048064586,5186338.01103835 574169.408172286,5186334.14125926 574163.408196148,5186329.22142858 574157.058097245,5186316.79169929 574153.767894392,5186301.5319513 574153.857756445,5186293.60205016 574151.067688796,5186286.73218696 574149.907644965,5186282.96225541 574144.607531272,5186270.77250437 574138.617551084,5186265.62267646 574127.987581958,5186256.23298504 574118.487497906,5186241.34334316 574110.377347342,5186224.04370704 574105.847197163,5186210.53395904 574098.957013427,5186192.58430942 574092.09679139,5186172.43468715 574081.416675663,5186154.44510569 574083.456533079,5186148.29514722 574068.116470541,5186128.48567201 574053.696569537,5186119.04604899 574030.336646766,5186098.90672117 574017.336644795,5186085.0771285 574007.776649399,5186075.25742362 573992.766736471,5186064.48782808 573975.906909633,5186056.77822679 573958.987178643,5186054.5885566 573929.17770868,5186053.99909622 573912.917878793,5186046.73947856 573900.307957246,5186037.98981465 573884.858041081,5186026.55023558 573867.528045388,5186008.48077421 573860.607897058,5185992.51110036 573855.88780401,5185982.09131682 573848.427578628,5185961.05171695 573845.65748094,5185952.4218759 573840.337398661,5185941.99210323 573832.127398473,5185933.29236023 573820.147431741,5185922.55271045 573786.547618673,5185897.88362363 573762.367914731,5185878.61168353 573762.107728511,5185878.40430741 573733.297905499,5185858.20507846 573718.858039897,5185850.74543113 573703.808189165,5185843.50579192 573692.608182484,5185831.2361478 573685.428194412,5185824.31636394 573660.758422137,5185811.44696815 573628.128920935,5185805.96762079 573592.949439425,5185798.92833884 573543.569963968,5185777.14949795 573501.390442618,5185760.32046563 573462.590996195,5185751.46127168 573439.081290502,5185743.68179077 573403.541672717,5185728.2426223 573377.901794639,5185708.08333696 573358.171803147,5185687.56395061 573344.311548117,5185657.84457637 573339.551509464,5185650.50475482 573333.161466353,5185641.16498787 573326.581479419,5185634.91518501 573318.771533291,5185629.74539042 573309.131642629,5185625.87561202 573284.772058087,5185624.25606823 573250.312617559,5185620.30673469 573228.37300829,5185619.81713326 573215.023289799,5185622.08734309 573185.563951017,5185629.44777621 573161.744458162,5185633.78814689 573141.714885788,5185637.50845768 573117.965297806,5185636.33889724 573096.815625442,5185632.98931808 573081.76577971,5185625.9696766 573067.9358897,5185617.65002987 573051.056095696,5185611.71040739 573035.98627288,5185606.01074949 573022.716444046,5185601.88103941 573002.656711044,5185596.12147153 572985.386830585,5185584.67192629 572963.756998424,5185571.39248236 572943.377080221,5185554.38306366 572924.327179547,5185539.82358999 572911.707271822,5185531.73391885 572901.207333351,5185524.10420395 572880.55757392,5185516.13467496 572867.937677509,5185508.70499545 572847.487858503,5185497.435505 572829.298017428,5185487.28595987 572818.508054542,5185477.89627266 572801.708151257,5185465.5667305 572790.338157615,5185453.73708484 572780.778161579,5185443.70738383 572772.43811722,5185432.13768065 572764.177963032,5185414.17805757 572758.287840847,5185400.64833557 572754.777739596,5185390.90852264 572750.067626138,5185379.15875683 572744.217451047,5185362.54907342 572738.287389721,5185352.55930701 572733.147254315,5185339.04957137 572725.527051387,5185318.88996497 572720.17700194,5185310.22017136 572713.006996727,5185302.20040205 572705.207043887,5185296.59061328 572699.197088756,5185292.77076963 572690.017179593,5185288.25099167 572674.987297333,5185279.02137857 572664.197346232,5185270.29168318 572650.427374128,5185257.11209795 572635.39749963,5185248.33247916 572621.546562286,5185228.35492222 572613.967367093,5185217.42325747 572608.627317879,5185208.76346365 572603.297249695,5185198.99368382 572597.947200692,5185190.33389019 572592.607151353,5185181.66409651 572584.827157427,5185173.63433838 572572.277163765,5185160.47473119 572555.477250493,5185147.47519813 572542.317260473,5185133.86560767 572526.587313234,5185120.00606647 572516.427310152,5185108.85639088 572505.687287752,5185095.93674831 572494.997189865,5185078.60716117 572483.936986799,5185054.65766523 572476.846857566,5185039.3579877 572470.436630338,5185018.9983626 572458.606452552,5184995.69887223 572447.936321116,5184976.38931013 572440.136361488,5184970.33952724 572430.476502698,5184968.23972725 572418.986688215,5184966.7799519 572403.116945418,5184964.82026146 572389.187197395,5184964.65051338 572372.887436452,5184961.15085034 572342.467763219,5184947.55156953 572323.748027372,5184942.91196447 572296.988251046,5184927.1626456 572282.308304408,5184914.41307181 572267.018380139,5184902.32350055 572252.92843413,5184890.24390767 572237.618324172,5184867.12447783 572219.168208048,5184840.2251527 572207.458062935,5184818.91563524 572190.327986332,5184795.77623844 572178.657792256,5184771.59675703 572169.267545851,5184746.78724279 572164.327348991,5184729.74754935 572154.397015803,5184699.19811825 572137.876928713,5184676.06871057 572122.586986774,5184662.87915372 572102.457140098,5184650.06967892 572085.437329816,5184642.80007745 572067.147412785,5184627.81059757 572047.547445249,5184608.39119792 572025.507540646,5184590.04182844 571995.677878035,5184577.56252377 571969.448205679,5184568.42311176 571945.658459481,5184557.5536781 571921.858724659,5184547.34423621 571899.369047788,5184542.00470847 571856.839805398,5184540.61549006 571838.610017755,5184533.33591069 571813.510214286,5184517.60656298 571801.360275586,5184507.97690457 571785.430190751,5184485.51747845 571768.900105802,5184462.38807174 571759.609937469,5184442.2084972 571750.369675713,5184416.51899238 571739.829370916,5184386.83956208 571727.449125759,5184358.69014527 571716.348757412,5184324.60078161 571711.858339244,5184294.78124444 571702.387774686,5184250.78197852 571698.007326965,5184223.70793833 571692.236908138,5184188.04296499 571678.616515879,5184149.73370086 571671.196232769,5184124.72415482 571653.976058211,5184095.4148402 571644.785951899,5184078.9852161 571633.665821655,5184059.00567224 571627.515648978,5184041.95600142 571624.32529639,5184017.43637308 571618.724969507,5183991.79680247 571600.834696716,5183955.85758511 571590.314566998,5183936.54802198 571576.844376597,5183910.36860005 571562.614218627,5183885.27917787 571549.824119512,5183865.27966455 571528.394200569,5183846.50029121 571510.874258443,5183830.64081007 571488.834350841,5183811.85144794 571460.724580372,5183794.54217623 571438.744804931,5183783.6927113 571418.71503086,5183775.07318267 571398.545233649,5183764.91367635 571374.075382273,5183746.76435002 571351.605678971,5183739.66484594 571326.02591813,5183725.68548619 571294.916159008,5183705.68630341 571271.656297158,5183688.21694678 571247.816405377,5183668.30763197 571225.166521477,5183650.17827293 571204.37654095,5183628.31892831 571187.376704931,5183619.29935054 571158.087127232,5183612.1199707 571132.577487631,5183605.42051659 571110.027889609,5183604.49093501 571096.658200753,5183608.30112706 571077.838611777,5183612.05141812 571066.860652575,5183613.62728872 571065.088878364,5183613.88162442 571045.059311418,5183617.61193752 571026.329599271,5183614.08232049 571007.929833334,5183607.69273429 570992.639892787,5183594.28318229 570968.310070027,5183577.89383158 570945.090146329,5183556.67452303 570926.720122775,5183534.84513493 570909.489964588,5183506.19581403 570898.469905883,5183490.41621569 570884.259714622,5183463.12682293 570871.929610055,5183443.12730254 570859.719540318,5183425.34775146 570846.919679593,5183419.45805811 570836.619872268,5183419.55824262 570823.870150332,5183422.05844045 570813.530395015,5183425.23858606 570801.42062091,5183425.31880348 570783.120919982,5183422.89916471 570764.2611817,5183417.609573 570747.221395223,5183411.44995965 570725.851603927,5183400.17049034 570690.411847401,5183375.2814501 570663.581951345,5183351.59223917 570649.991933264,5183335.33269375 570633.58189381,5183314.63325641 570616.351942797,5183298.33377725 570588.892099255,5183277.06454677 570566.412398741,5183269.96504396 570546.832623008,5183261.57550544 570520.002940305,5183250.67613015 570490.723123479,5183228.94693868 570476.09310321,5183211.34742958 570470.502975612,5183197.39771027 570463.012791271,5183177.89809679 570450.762775238,5183163.20850729 570436.862986975,5183160.39879449 570420.363293979,5183160.41909218 570403.433561554,5183157.57943449 570392.343604713,5183147.74976147 570381.293581186,5183133.94013905 570372.193558583,5183122.37045255 570363.553516521,5183110.14076626 570356.72345227,5183098.6010384 570353.033381187,5183090.17121374 570351.123120402,5183072.29147877 570344.392915325,5183052.3618573 570329.633077584,5183045.58221136 570320.673286362,5183048.12234047 570317.483348693,5183048.30239578 570306.073631865,5183052.5825467 570291.53391412,5183053.29280021 570269.584314517,5183052.81320292 570248.914589126,5183046.17366197 570234.244833749,5183044.46394904 570216.075164516,5183044.02428297 570199.585453605,5183042.95459467 570171.705985217,5183043.73508826 570156.456211215,5183040.2454088 570133.966519518,5183033.58590106 570114.436664,5183020.34642481 570100.956704569,5183007.62683256 570088.6667523,5182996.67719599 570075.836711623,5182979.76764614 570063.006678291,5182963.29809065 570051.936692886,5182951.70844035 570046.406474163,5182932.2387917 570043.22631414,5182918.96902053 570037.686124739,5182901.25934935 570029.036094905,5182889.69965498 570011.416284919,5182881.33008158 569989.51660509,5182876.01054617 569971.256854339,5182870.50094743 569939.027419555,5182868.36155772 569912.227910176,5182867.83204905 569892.238285956,5182868.03240783 569869.6786984,5182867.55282187 569847.729092229,5182866.63323056 569827.04937914,5182860.66368159 569804.609618452,5182849.81422754 569779.479856731,5182835.85486237 569774.559838523,5182829.18503757 569764.859821277,5182817.16536839 569755.579832649,5182807.35566304 569742.139822776,5182791.54611053 569735.459749831,5182779.55638639 569726.179561524,5182757.61683796 569716.389662433,5182752.65707917 569693.829857317,5182738.93766465 569677.890002877,5182729.71807223 569658.340171398,5182717.79858005 569637.040278193,5182700.13919382 569613.770413978,5182681.9998495 569593.040564829,5182667.65041023 569570.490745804,5182653.06100704 569550.370874612,5182638.05156535 569530.66085104,5182614.23223034 569515.300790584,5182593.10278183 569506.574549822,5182570.92934209 569505.450563208,5182568.07328413 569496.190324888,5182543.04377578 569483.800086812,5182514.46437006 569470.38003798,5182496.22484917 569455.590036359,5182479.29533614 569443.369976415,5182461.73578477 569432.33109862,5182443.61244232 569426.729838928,5182434.41643985 569418.059619319,5182411.16689793 569425.899303846,5182400.88688907 569425.239174971,5182392.28701238 569425.178835684,5182371.5572819 569420.788696159,5182358.05753622 569413.338446781,5182334.37797781 569408.898170493,5182312.4883417 569398.477893109,5182283.70890316 569389.037499794,5182248.97952395 569374.22707952,5182206.47034284 569358.22686966,5182175.41103508 569355.026748154,5182164.35123632 569337.386753503,5182144.52181292 569314.727090957,5182139.19229277 569300.837283674,5182135.06259808 569278.337618193,5182129.73307506 569238.517916471,5182102.37415154 569227.607912969,5182089.67451393 569210.987946997,5182072.72503497 569194.537949091,5182054.01557576 569177.327983405,5182036.39611626 569162.577910712,5182015.05666038 569151.587807978,5181996.18710433 569145.247470781,5181968.32758047 569142.757177753,5181947.57789462 569143.14683113,5181926.85815611 569144.856517674,5181909.67834777 569148.37618133,5181893.17849775 569151.335804888,5181873.58869793 569156.595335077,5181850.93889601 569163.734739796,5181822.78913121 569178.053711115,5181776.42947198 569185.732982948,5181740.79979417 569193.362331326,5181709.79005736 569197.411873017,5181686.4702859 569203.351292579,5181657.87054849 569208.710889164,5181639.41069024 569212.82034998,5181611.23098056 569220.369598451,5181574.05132492 569226.309006979,5181544.79159591 569236.498332537,5181515.36179181 569260.446996192,5181461.39205525 569267.566642848,5181448.03209877 569276.616097779,5181425.20222977 569285.485599333,5181405.01232983 569296.295093732,5181386.62237129 569305.314592333,5181366.43246856 569312.504136087,5181346.89259067 569320.913656922,5181327.36269043 569328.003140948,5181304.07286282 569338.67240601,5181271.56308934 569347.661955572,5181254.463147 569363.331126925,5181222.01328165 569380.030329522,5181192.66335738 569382.568093636,5181152.94309365 569371.969329998,5181122.48191173 569359.216991597,5180965.2966766 569356.466493937,5180931.79715987 569400.714079377,5180835.79759475 569406.088560822,5180810.42282477 569470.210304718,5180686.2670101 569494.709058415,5180638.73592729 569517.958036324,5180603.42345928 569528.45725426,5180567.98622535 569551.956060471,5180522.54888325 569565.080144887,5180482.04916657 569632.701739862,5180353.29959366 569635.451395395,5180335.54977244 569643.076210057,5180333.11216466 569656.200418968,5180300.23734905 569788.693776375,5180050.3631495 569791.44343132,5180032.61332794 569866.564916472,5179906.48857881 569890.063717623,5179861.051234 569923.687200949,5179808.11380027 569952.435481921,5179737.30168549 570019.932231169,5179618.73947505 570020.057060485,5179608.5521038 570048.555680866,5179558.11473047 570100.428142559,5179464.73998058 570152.175857315,5179386.6150362 570165.05024202,5179364.36508607 570372.665308705,5179005.67838195 570398.414229224,5178970.49086053 570497.034354773,5178791.30384626 570507.408819459,5178771.11641432 570517.658412031,5178758.49138775 570530.657616301,5178725.67906924 570556.406575207,5178692.92901552 570572.030685854,5178657.55418139 570721.773641377,5178407.99212157 570752.772371449,5178367.74206594 570752.897157919,5178355.05472589 570794.270602216,5178309.74204377 570804.76993574,5178281.92970606 570828.143853053,5178244.11725905 570838.393529426,5178236.61716619 570843.643132023,5178218.86729637 570895.640990572,5178150.86720761 570906.140448343,5178130.55477369 570969.012585702,5178032.05487325 570982.761850645,5178003.99247814 571001.386233398,5177988.67983036 571074.382815125,5177868.86751359 571084.757445356,5177858.80495065 571105.881316483,5177815.80510957 571118.630746215,5177795.55510817 571135.317716381,5177769.52353058 571155.067089262,5177738.67939336 571178.3788501,5177702.36643709 571191.25342064,5177679.61618372 571204.252969058,5177654.36592674 571217.127621113,5177641.86568032 571245.626690569,5177593.92762302 571279.125724919,5177553.67697916 571351.748326282,5177427.55056576 571545.617370039,5177145.35936018 571579.116389857,5177102.54622782 571586.991079517,5177082.29607466 571607.74044401,5177052.10818228 571625.864878269,5177024.3578394 571649.114175186,5176991.60740149 571664.738618166,5176958.79460298 571692.987839876,5176928.60657654 571703.487440808,5176903.35637533 571747.361166652,5176847.98055676 571827.483687211,5176726.97906069 571866.107595415,5176681.72834714 571899.856518111,5176626.29021987 572000.478538353,5176490.2883681 572054.851855255,5176407.09987031 572095.975720517,5176361.84912263 572121.974892958,5176318.97364763 572225.096878772,5176183.03427991 572225.346775964,5176170.34677318 572238.096495436,5176165.40904531 572253.471029412,5176142.90876785 572269.095516803,5176114.9709854 572547.712485134,5175757.5910215 572760.893965755,5175497.02478568 572844.079123081,5175395.33584209 572849.453886825,5175377.5857502 572872.453320513,5175360.08535156 572898.327526985,5175319.77240606 572988.574969836,5175206.52085537 573545.934649102,5174557.76147007 573591.308408477,5174504.94822102 573761.428742256,5174303.75793427 574338.787798271,5173591.748739 574377.661762125,5173548.09188038 574390.286425936,5173533.93543306 574408.161060683,5173529.06014185 574413.285929702,5173524.06006126 574458.785242578,5173544.93429316 574497.159353301,5173519.99618045 574573.657783353,5173498.05743741 574797.278606743,5173490.55375758 574861.027290862,5173470.99022665 574950.025585292,5173461.86377021 574960.6500804,5173418.801141 574966.149742699,5173385.8635856 575005.648162765,5173266.92556518 575106.895002345,5173085.23661197 575180.017919609,5172981.36054137 575194.954994324,5172960.11032358 574893.083955377,5172742.02169226 574523.842045287,5172926.37124191 574431.78157212,5172973.06019764 574381.095188705,5172998.74850092 573839.10716416,5173273.56966953 573150.312561799,5173965.33082721 572757.510447767,5174371.68114196 572589.577408777,5174545.46524465 571865.534280649,5175294.60286016 571450.482921095,5175715.64156857 571150.678513564,5176019.77205896 571044.493889161,5176127.52402428 570945.121584151,5176228.30712328 569545.035437276,5177701.17800856 568850.236130719,5177670.9721113 568728.05098341,5177669.56812704 568116.875348472,5177673.73573361 568078.938388472,5177651.08013966 567961.378124028,5177646.45731162 567681.883438769,5177635.49372379 567475.88721203,5177610.9349869 567415.200550961,5177572.46726768 567333.139183745,5177520.43740788 566815.896282877,5177192.38357472 566323.65295412,5176877.8916627 565860.034179866,5176581.71164289 565488.224218152,5176079.77913727 565481.161765349,5176070.21673024 565453.411951475,5176032.74834523 565453.532749863,5175573.30925204 565453.655343666,5175310.37083667 565617.586827656,5174989.86688538 565431.585416794,5174453.1807221 565350.834790518,5174220.15001986 565246.771769923,5173952.30706415 565213.397238207,5173935.71381454 565064.274326279,5173861.40354321 564699.719173033,5173922.59738972 564566.534359829,5173944.97471402 563637.055802585,5174379.61723962 563363.247225477,5174254.4650846 563279.623352728,5174209.15379638 563105.250305583,5174073.93737222 563072.250867288,5174068.37540315 562974.752526144,5174051.90822064 562754.256276048,5174014.7242604 561973.771623433,5174095.5503325 561791.836067404,5173949.20888339 561777.273175625,5173882.36502476 561770.085367599,5173837.83365963 561659.957984095,5173392.17686987 561456.271602598,5173126.64754164 561350.647173711,5172988.96101705 561168.336898399,5172875.96336649 561122.274951155,5172846.62020246 561115.025082706,5172846.43281955 561069.525647811,5172819.40215804 561031.526119196,5172796.8088985 561001.213949163,5172774.24676329 560948.151970812,5172729.27861894 560796.715775128,5172583.28023213 560721.965447171,5172415.81171328 560764.897430781,5171949.49580538 561279.573152618,5171710.23630282 561498.193996626,5171691.76400878 561983.684774784,5171650.75615382 562458.0508877,5171622.31105753 562848.352779966,5171259.02192256 562859.539976858,5171248.61544857 562968.473798092,5171071.95666214 563003.593971717,5170638.89154875 562892.280327427,5170315.45417486 562605.344449561,5169956.862956 562521.533105642,5169922.6452817 562132.663885022,5169807.49421506 561900.478973164,5169652.65307941 561826.354795942,5169603.18515649 561760.418026613,5169559.18588925 561511.731892284,5169255.37536316 561503.544436728,5169245.37542689 561232.357556692,5168831.43952103 560884.234916915,5168461.19234912 560779.54675206,5168215.66112953 560843.231538989,5168057.81555244 561038.535743858,5167573.71625541 561087.032326471,5167318.58910831 561035.28141488,5167140.27627399 560868.532687849,5166982.99635267 560671.471626746,5166792.09160942 560268.163713109,5166565.78310088 559962.168798069,5166551.63082396 559945.856671366,5166560.75609864 559415.806337168,5166857.39010275 559202.310174281,5166873.86182968 559032.875720978,5166886.95794503 558492.756506145,5166559.43164058 558332.508941898,5166530.87106572 557965.577012159,5166465.43795764 557486.715217369,5166927.60404274 557309.346432995,5167097.17042 557218.850875963,5167183.67258413 557188.102386366,5167213.04831805 557035.047413113,5167359.39571248 557005.673859732,5167387.55266058 556951.989002865,5167438.83518359 556876.680213447,5167510.80571625 556710.56030707,5167383.80753859 556641.187430972,5167330.77705381 556165.510935237,5166648.46758678 555813.836652007,5166611.84826032 555643.345838285,5166843.66525374 555579.975893963,5167076.44918541 555516.231468122,5167353.67092001 555201.307696538,5167484.14578984 555092.187006035,5167489.24138159 554803.260918577,5167502.74625542 554761.950429776,5167538.02842401 554743.638821366,5167553.65383076 554610.457814958,5167667.68803543 554539.088767291,5167944.8785355 554537.714104559,5167969.69122118 554528.216463055,5168143.56751933 554514.594828928,5168391.3818683 554511.658053458,5168444.69476578 554450.598149601,5168462.25837087 554254.481493866,5168518.82441583 554212.483281361,5168530.91892377 554145.733204339,5168296.94974861 554139.232048814,5168174.63656741 554148.541998444,5167985.04144484 553470.693821533,5168011.80270507 553439.712858505,5169533.81262435 553427.732396188,5171162.82285219 553403.752034889,5172759.83301632 553383.771651848,5174368.84314128 553355.791643031,5175981.85334717 553351.810650603,5177595.86318564 553330.828407997,5179198.84213875 551741.892997035,5179287.86144805 550123.957608117,5179265.88261581 548516.021850388,5179243.90363668 546914.085935204,5179232.92441706 545321.149602686,5179201.94532802 543650.216504964,5179203.96679193 542032.28124317,5179264.98679513 540430.345259956,5179248.00759231 538756.412126805,5179248.02907838 537221.431611674,5179254.05218577 535605.424529336,5179255.07890249 533990.417465329,5179274.10537635 532381.410489906,5179317.13142772 530787.403635033,5179294.15814945 529189.396799056,5179301.18453868 527600.390098711,5179330.21047239 526019.384250467,5179566.23320789 524404.377615024,5179556.26010977 522796.370766589,5179501.28761151 521175.36375734,5179442.31544096 519525.325264365,5179380.28135453 519394.355935139,5179375.34611238 517916.328271882,5179332.36865748 516306.291369745,5179249.39311185 514626.252972295,5179185.41839672 513009.216520757,5179180.44179076 511387.180069969,5179185.46510066 509763.143811634,5179209.48807252 508151.107766549,5179225.51104065 506539.070830495,5179170.5356119 504914.034421812,5179180.55899068 503301.998167785,5179179.5824689 501695.962547851,5179211.60507996 500088.927078579,5179251.62748838 498462.889373269,5179247.62316423 496848.851735509,5179237.6171233 495302.815676504,5179229.61132198 495346.84729782,5180821.57463446 495340.878395801,5182446.53695695 495368.909626316,5184043.49993398 495375.93995181,5185617.46334803 495394.971242756,5187232.42574426 495420.002151849,5188825.38856517 495446.03275704,5190405.35159924 495503.064321413,5192017.3136871 495524.095615327,5193646.27538485 495564.126526155,5195247.23755609 495560.156779411,5196842.20002694 495603.188010644,5198467.16141745 495611.218295986,5200062.12367648 495637.248778541,5201663.08557362 495650.279726696,5203296.04675013 495676.309926805,5204889.00866588 495711.353257682,5206502.98535492 495747.398906727,5208109.96516074 495763.443521209,5209683.94554618 495759.488657558,5211278.92586094 495757.534996631,5212916.90557524 495769.579718949,5214497.88577718 495749.624731671,5216090.86619041 495735.659231801,5217311.85113751 494959.659115045,5217313.86122848 494970.705119564,5218929.84108862 494995.750458042,5220523.8209809 495003.795943673,5222123.80097645 495029.841657324,5223733.78054491 495057.886755016,5225323.76027618 495042.932737237,5226942.74021409 495039.977911121,5228534.72027518 495038.023517812,5230142.7000773 495024.069605433,5231766.67981888 495019.115198974,5233362.65844546 495028.162292141,5234979.63287876 495020.209257124,5236590.60763539 495020.25677792,5238222.58188682 495069.303271475,5239826.55568717 495109.350249214,5241446.52931016 495126.397469637,5243072.50317726 495135.444059105,5244676.47748387 495131.495656431,5246452.01174692 494969.496243897,5246452.45230827 494795.543352658,5248054.43014654 494770.589645386,5249647.40528159 494775.636449952,5251262.3794381 494778.681964043,5252833.35429019 494796.728248945,5254433.32831968 494809.774558379,5256034.30238152 494927.819864232,5257612.27448102 494951.864575155,5259160.24900567 495092.910126374,5260757.22018159 495122.945638598,5262364.19987764 495170.980399668,5263944.17941097 495203.018507466,5265676.15736808 495207.054052006,5267287.13741823 495199.089378382,5268885.11787935 495275.123248513,5270449.09659807 495273.160182488,5272126.07581067 495167.197052713,5273752.05834863 495209.110948557,5275537.03499854 495210.271082612,5277133.01502885 495241.46229853,5278739.99404238 495300.561408565,5280442.97098496 495352.374997453,5281951.95047877 495408.40961765,5283572.92834458 495395.446087868,5285230.90769069 493836.441274287,5285240.57888839 493825.510468566,5286899.93388971 493824.545357675,5288432.91510224 493806.596553693,5290017.89177349 493775.648970343,5291608.86854032 493750.699693533,5293150.84586706 493728.753104446,5294776.82181349 493731.649256886,5296388.79709995 493731.935767607,5296550.66961577 493776.730713998,5297964.77137662 493783.330511173,5298155.64321211 493838.093445917,5299556.7446901 493846.756365626,5299768.80360605 493904.424709744,5301149.71765226 493913.118863083,5301361.8390452 493921.563243168,5301580.83533847 493954.755974827,5302733.94120834 493960.013024057,5302956.00006086 493955.9946899,5304317.66657612 493956.565520734,5304575.66254475 493954.046946923,5305931.6415582 493953.86701868,5306165.63792368 493952.442891526,5307544.61650254 493952.326104836,5307798.61254779 493954.463320831,5309145.59144216 493954.877885721,5309403.33739959 493963.859589912,5310780.31549167 493964.929757913,5311018.81171352 493961.567301206,5312372.22816381 493960.325626435,5312628.97419436 493960.367397812,5313923.51638735 493431.384461735,5313928.53994069 493490.434964883,5315540.51239895 493379.48653035,5317130.50072358 493388.531252847,5318741.49042006 493360.577546444,5320361.4818554 493352.622551027,5321960.47243614 493352.081509723,5323845.46083966 492804.884251059,5323832.30308164 492804.728410709,5323846.4905109 492786.743364527,5325445.48257286 492776.789998417,5327070.47405103 492758.836543209,5328679.46609166 492788.880984317,5330290.45520526 492781.9264423,5331879.44663193 492780.972009399,5333482.43757738 492783.017951372,5335104.42818006 492746.065367191,5336708.42150474 492720.11243214,5338317.41412255 492733.157548137,5339930.4039689 492739.203056658,5341545.39423472 492746.063959719,5343265.32127047 492951.176985921,5343257.86832142 492951.052204394,5343265.36828563 492922.29539326,5344928.3569705 492934.35169547,5346483.34022611 492947.410593318,5348110.32261461 492938.469013554,5349693.30712058 492927.530125579,5351349.29100348 492967.586978927,5352956.27129905 492969.645361767,5354555.25463466 492999.703801659,5356189.23530221 493036.761092332,5357797.21559205 493033.82054541,5359419.19892554 493050.878525029,5361022.18076849 493074.959125943,5362394.97688371 493169.268276769,5362392.59408621 493175.88894744,5363984.13924712 493176.488060854,5364130.88764683 493189.479189174,5365604.18347051 493191.047021142,5365750.86928435 493204.537530078,5367207.16519159 493206.293819464,5367380.03820552 493234.845517007,5368810.83304566 493238.445335476,5368978.83094687 493267.496754917,5370400.12577509 493271.190904903,5370583.74849247 493312.272784848,5371989.04571345 493315.329980969,5373555.07264266 493327.388340583,5375159.09941695 493337.44704718,5376772.1264789 493341.504649911,5378352.15344092 493360.562932647,5379960.1795722 493372.621192826,5381564.20619109 493399.679270822,5383172.23157814 493468.737445095,5384806.25386166 493479.37420531,5386074.14118232 + xmlns:gml="http://www.opengis.net/gml/3.2"> + 363237.626104089 5045148.78911013591752.164237744 5386497.208 + + + + 492720.11243214 5166465.43795764591752.164237744 5386497.208 + 493479.37420531 5386074.14118232 495062.336832765 5385983.99124965 496639.674560181 5385894.1616558 498248.095687447 5385802.56185817 499839.824008464 5385711.91271809 501136.55 5385638.064 501467.943141889 5385767.80541868 502638.13038141 5386225.93726688 503053.46464599 5386388.54188931 503331.026 5386497.208 503699.302 5386362.789 503698.47332 5386220.67017644 503689.147461229 5384621.28310618 503685.055 5383919.425 504644.774816817 5383819.88892449 505192.831 5383763.048 506067.396491085 5383051.22448901 506253.563241776 5382899.70025046 506630.795 5382592.665 507778.537 5382437.824 507871.292629229 5382391.32496513 509368.38182872 5381640.82385308 509937.620566855 5381355.46055867 510949.994331869 5380847.95062758 512525.992895043 5380057.89170881 513230.628453252 5379704.65305729 514170.309633563 5379233.58441887 515764.572623581 5378434.3694173 516470.849667691 5378080.30787761 517228.900216171 5377700.29192411 518897.19338599 5376863.96508426 519529.106322551 5376547.18278313 520047.475 5376287.321 520466.380787187 5376350.25746135 522091.309059952 5376594.38690181 522113.824951348 5376597.76969234 523693.324360806 5376835.07389432 525252.915 5377069.387 525268.759120909 5377065.65928362 526793.056620754 5376707.03107132 526885.07181278 5376685.38225025 526949.266 5376670.279 527300.354487204 5375095.81309175 527453.283 5374410.001 527653.748 5373931.762 527552.376 5373516.272 527561.324482355 5373492.93455844 527584.165 5373433.367 527689.675 5373378.304 527467.839 5373137.301 527419.949 5373112.983 527263.544 5372956.911 527236.163 5372848.09 527187.896 5372687.294 527355.022 5372578.487 527551.876 5372306.489 527284.621 5372027.292 526948.617157886 5371912.32001848 526808.709 5371864.447 526695.139 5371883.978 526590.927 5371920.846 526075.661 5371920.909 525551.907 5372120.757 525341.266173163 5371887.38511232 525248.727017776 5371784.85970117 525010.16 5371520.548 523716.552877634 5371602.24673338 523215.28 5371633.905 522261.964 5371345.684 522081.031 5370213.964 522049.140180406 5370143.10519535 521489.688 5368900.048 521544.961 5368616.504 521513.120101352 5368531.18873901 521240.425 5367800.523 521992.925984955 5366919.9380308 522064.973201944 5366835.62758122 523065.189 5365665.164 523666.976011613 5365532.75264644 524448.259809692 5365360.84656802 524886.643 5365264.389 525244.446667801 5365004.31195121 525427.486 5364871.266 526834.242807884 5364987.74375145 528421.99597393 5365119.20778105 530057.692838637 5365254.64149055 531318.261 5365359.015 531669.519146117 5365456.4436309 531899.413299638 5365520.20947626 533278.556856069 5365902.74314843 534241.395 5366169.806 534868.727747756 5366198.30814352 535862.499 5366243.459 536421.444 5366210.286 536454.059088547 5366166.01439868 536898.969905572 5365562.09409084 537405.791 5364874.137 537774.253 5364249.45 538097.711706761 5364153.29342588 538186.691 5364126.842 538319.041 5364034.482 538324.474611288 5363980.41003903 538327.413 5363951.169 538414.038 5363814.04 538395.746 5363692.567 538556.296 5363474.732 538811.359 5362962.664 539721.502142637 5362643.71368574 540222.235 5362468.237 540222.828774539 5362400.67690394 540234.913 5361025.725 539954.577111015 5360403.18325763 539237.043643193 5358809.75711129 538768.842 5357770.022 538904.831920846 5357188.24951072 539282.403957909 5355572.97521305 539282.922 5355570.759 540081.374204488 5353942.74454074 540329.13587328 5353437.56767859 540590.318 5352905.027 540942.106976105 5352331.80678252 541403.832 5351579.452 541417.411 5351552.996 541474.645 5351499.686 541494.378 5351448.573 541624.045 5351037.925 541767.388 5350787.633 541812.104206218 5350737.01131558 541915.439606497 5350620.02885074 542131.328 5350375.629 542342.064 5350459.941 542592.8 5350317.92 542980.498 5349690.624 543341.824 5349263.856 543389.647582808 5349143.8744296 543502.934526602 5348859.65596197 544030.594209357 5347535.84386643 544389.417 5346635.616 544768.189708664 5345907.09214577 545042.706 5345379.093 545073.768 5345257.683 545021.138 5345107.205 545118.353 5345016.884 545179.190362287 5344923.47621679 545339.834 5344676.829 545269.944 5344570.675 545186.589398349 5344588.4800933 545115.225 5344603.724 545081.255 5344466.053 545106.151 5344394.924 545191.755318209 5344356.5039508 545227.844 5344340.307 545298.941 5344346.737 545371.522 5344400.113 545523.83 5344463.388 545586.267 5344417.879 545628.81 5344307.061 545635.73476791 5344288.83903495 545677.475 5344179.003 545516.198 5344179.26 545555.649 5343991.229 545445.555 5343934.775 545421.307 5343871.903 545491.434 5343639.037 545538.047 5343613.163 545681.931 5343700.456 545746.764 5343666.085 545703.861 5343435.096 545706.126 5343306.977 545734.89 5343192.657 545789.228 5343078.85 545910.732 5342898.581 545988.563 5342763.042 546114.709 5342698.909 546115.698565205 5342696.85945804 546147.23 5342631.553 546099.611 5342525.263 546179.368 5342382.332 546158.143 5342277.49 546150.242 5342183.254 546163.392 5342087.953 546233.891 5341968.105 546353.795 5341862.244 546384.093 5341764.612 546371.817 5341675.898 546406.042 5341602.999 546467.242 5341562.122 546531.158 5341491.935 546595.782 5341335.301 546682.801 5341392.514 546731.492 5341367.902 546734.074 5341254.298 546793.797 5341142.706 546796.920124315 5341069.75795911 546800.946 5340975.724 546829.702804815 5340970.51317348 546859.637 5340965.089 546935.417183097 5341071.23316396 546936.136 5341072.24 546994.659 5341132.003 547025.26 5341199.564 546963.581 5341297.553 546887.189 5341353.43 546935.716 5341398.907 547072.874 5341380.582 547160.491 5341339.93 547262.645 5341263.274 547371.941 5341246.27 547411.486 5341304.645 547431.656 5341385.091 547458.37 5341472.693 547509.618 5341562.351 547633.969 5341668.982 547780.999 5341777.041 547863.135 5341848.435 547938.604 5341902.793 547996.069 5342012.268 548007.097 5342074.731 548143.653 5342126.208 548308.86 5342204.793 548387.097 5342223.672 548433.107741179 5342228.82930415 548491.389 5342235.362 548715.885 5342303.656 548870.555 5342262.366 548906.069 5342283.049 548943.59 5342478.201 548975.205 5342520.155 549068.213 5342595.674 549082.311 5342611.542 549106.066 5342631.815 549156.741 5342640.279 549178.145 5342622.246 549222.795 5342635.598 549263.035 5342705.726 549286.127 5342707.16 549404.759 5342610.306 549423.329 5342586.074 549419.404 5342562.883 549425.606 5342537.617 549466.072 5342510.179 549505.77 5342500.024 549596.625 5342514.089 549689.059 5342607.213 549735.331 5342623.671 549807.163 5342642.514 549885.559 5342736.136 549938.37 5342806.687 549971.284 5342840.631 549986.154 5342838.599 550024.735 5342814.544 550035.879 5342814.024 550049.848570131 5342826.35841657 550071.906 5342845.834 550094.243 5342862.703 550318.605327384 5342887.60770346 550332.887 5342889.193 550868.403 5343258.589 551925.594654075 5343445.68418898 553425.443 5343711.118 553578.372584271 5343793.91646471 554224.079 5344143.512 554085.870587265 5344554.99014036 553914.031 5345066.596 553481.9264489 5345394.2815694 552677.609 5346004.234 552609.440410738 5346144.33610868 552346.012 5346685.742 552444.413 5347216.198 552402.526 5347288.068 552361.392 5347278.118 552339.54 5347255.994 552295.374 5347239.533 552289.772 5347243.496 552281.329 5347265.033 552284.446 5347284.823 552276.548 5347314.393 552280.935 5347330.49 552291.325 5347343.862 552283.775 5347357.997 552261.357 5347352.542 552266.636 5347383.777 552267.104 5347400.147 552259.794 5347433.119 552135.332922751 5347756.9139764 551818.987 5348579.912 552011.692122779 5349362.04263356 552311.103 5350577.259 551995.831180082 5350977.01317121 551766.796794742 5351267.42114651 551438.976 5351683.087 551558.184 5352415.97 551736.233514996 5352447.85081675 552226.802 5352535.69 552243.048600333 5352608.64290264 552606.198576243 5354239.3129685 552697.159 5354647.757 553325.020739725 5355090.22467331 554632.112 5356011.36 554909.239293551 5355952.68797318 556570.094131868 5355601.05996 557671.494 5355367.877 557813.151 5355282.853 557852.942 5355215.942 557871.717 5355150.979 557932.772 5355078.108 558020.656 5354938.197 558187.756692178 5354956.78989982 558778.765 5355022.55 558790.328 5355198.369 558702.307 5355270.335 558980.747 5355712.925 559635.379 5355565.659 559677.087 5355376.809 559786.810811494 5355374.80082759 559805.761 5355374.454 560859.984 5355728.689 560814.212227964 5356064.57548428 560813.302 5356071.255 560936.77 5356322.694 561414.838624699 5356616.91326795 562070.552 5357020.461 563038.704053898 5357233.97825157 563335.065 5357299.338 563434.912 5356225.854 564642.203329377 5356187.53414005 566223.008507408 5356137.35881654 567103.531216315 5356109.41070984 567349.329 5356101.609 567838.950266071 5356028.57469323 567893.874 5356020.382 567983.964348441 5356131.18676823 568287.36 5356504.342 569112.243 5356673.332 569443.754407045 5356673.74895058 569985.247 5356674.43 570188.606034177 5356175.6787925 570471.953 5355480.752 570693.19 5355401.973 570753.122 5355168.03 570553.534 5354928.086 570582.743058388 5354564.37549861 570632.193 5353948.626 571113.672375693 5353821.77213622 571321.57 5353766.998 571820.091694902 5352988.91756426 571842.076 5352954.605 572753.430929069 5352767.5145328 573241.44 5352667.332 574122.572 5352472.759 573760.517640225 5351433.58949544 573202.312 5349831.426 573206.581376533 5349773.97250468 573288.533 5348671.14 573541.192540589 5348175.20240659 573650.98 5347959.704 573715.909870876 5346529.39454321 573727.362 5346277.121 574594.340651411 5345907.36682371 575024.331 5345723.982 575406.126598792 5344926.54940408 575677.971 5344358.765 575794.823 5344303.805 575846.914 5344295.233 575882.736 5344300.341 575916.052 5344276.698 575950.266 5344232.068 575942.526 5344193.675 575931.616 5344176.546 575919.753 5344168.977 575904.466 5344139.747 575911.253 5344110.192 575913.739 5344093.859 575929.123 5344084.8 575982.415 5344032.705 576050.58 5343963.515 576139.078 5344071.23 576146.845 5344076.583 576154.723 5344089.04 576178.436 5344135.985 576198.8 5344186.59 576205.981 5344220.345 576268.150525235 5344257.21948135 576433.947 5344355.558 576460.035 5344455.958 576417.133 5344486.881 576399.273 5344526.786 576354.144 5344585.471 576316.658 5344597.013 576278.769 5344623.372 576276.991 5344663.801 576288.047 5344700.696 576291.346 5344731.62 576294.855 5344793.119 576317.462 5344814.419 576321.125 5344913.0 576349.05 5344935.274 576385.209 5344930.2 576414.963 5344941.406 576425.449 5344974.588 576457.025 5345019.169 577270.438 5345017.463 577419.695 5344869.717 577637.723 5344867.429 577638.74 5344807.844 577637.608 5344800.109 577633.787 5344777.823 577646.083 5344556.27 577858.395498627 5344374.82075384 578098.111 5344169.952 577983.545 5344010.28 577870.799266675 5343995.66099251 577339.663 5343926.792 577439.156 5343374.154 577418.045950075 5343349.80729019 577240.295 5343144.803 577351.031 5342737.143 577787.435 5342734.114 577877.676 5342773.635 577914.760715966 5342747.23188922 578338.551 5342445.507 578563.657 5342445.51 578891.533 5342877.409 579539.718 5343074.151 579580.062887345 5343081.82671725 580109.056 5343182.469 580428.643 5343386.14 580570.447 5343424.578 580677.436 5343415.589 580696.864 5343369.234 580882.552 5343338.819 580954.788 5343365.782 581109.486 5343367.669 581126.558 5343356.794 581153.692 5343349.151 581193.740207828 5343304.2287266 581245.307 5343246.386 581503.321 5343237.092 582188.375 5343343.567 582804.217608689 5342272.24544707 582857.38 5342179.764 583410.230499244 5341785.21975707 584115.486 5341281.911 584321.459250725 5340199.72573453 584373.67 5339925.41 584444.052922083 5339936.64709769 585781.454 5340150.172 586052.911303773 5340219.45571218 586060.401197404 5340221.36734848 586482.241 5340329.033 586722.47098628 5340235.02169628 586732.73026337 5340231.00684356 586733.455131214 5340230.72317468 586733.706 5340230.625 586734.346642791 5340230.77208047 587666.252684771 5340444.72153606 587998.941 5340521.101 588074.727157533 5340246.81160393 588103.872 5340141.329 588454.006 5339912.343 589289.403356798 5339559.18325302 589300.922048736 5338697.20336088 589330.88158939 5337083.19477104 589344.840832338 5335466.18659232 589375.799835842 5333832.17777631 589413.759065257 5332205.16868353 589447.718723428 5330598.15973728 589421.677569149 5328983.15297854 589404.637199152 5327394.14613183 589393.595521865 5325750.13889061 589391.554825624 5324141.13150972 589423.51370196 5322505.12249251 589449.47354742 5320910.11388143 589472.432393428 5319277.10519543 589492.391231896 5317645.09663268 589557.327364741 5316038.14876436 589610.247050873 5314432.24530066 589687.166826041 5312827.34054162 589760.086571563 5311223.43592443 589794.004664517 5309590.53503253 589813.924074779 5307985.63306279 589833.843145254 5306374.73141241 589854.761727334 5304754.83021731 589850.690324137 5303335.91779226 589849.684085117 5303211.98796954 589836.604834502 5301638.02294658 589832.518533866 5299924.1285249 589798.437037778 5298307.22945341 589824.356272078 5296703.32672913 589854.276024973 5295110.42310374 589891.711273188 5293825.43772011 589898.886326741 5293578.51503776 589900.694793715 5293498.51986128 589929.132166673 5292256.59471918 589933.561446002 5292093.60451093 589938.92656038 5291897.61628293 589944.665983588 5291687.94137658 589978.174239362 5290612.81826398 589988.033286093 5290296.71219285 589992.999549548 5289628.50289911 589997.657264298 5289007.72209249 590004.831688645 5288699.91846514 590021.925512196 5287966.18961244 590030.902163723 5287416.83060779 590047.888728129 5287100.83929792 590116.712163097 5285889.05999224 590136.447356351 5285541.38202484 590141.319825875 5285482.00858994 590175.239774093 5285070.33194198 590230.150033524 5284431.97369368 590273.753377139 5283924.92451864 590346.768671837 5282820.0795009 590359.934884135 5282321.34384726 590402.762389907 5281209.87528104 590403.198955841 5281188.00091585 590415.115143658 5280689.07781656 590416.300550313 5280640.07923013 590463.878699903 5279545.29749472 590490.045015092 5279050.93621315 590552.560083105 5277945.279267 590571.104668187 5277527.54101025 590576.16388836 5277451.23059324 590642.992486551 5276371.88525474 590677.095635271 5275864.33661944 590741.616737182 5274903.6128942 590756.607487748 5274689.18124283 590780.02667555 5274264.06806792 590821.121166164 5273556.46268782 590844.100980463 5273088.03833184 590859.025397483 5272784.54684905 590866.269046009 5272637.23848383 590905.219199914 5271479.27161332 590935.204816209 5271148.0304548 590944.950154602 5271040.72081967 591043.399631439 5269877.75215533 591053.769301984 5269755.19296268 591076.692479513 5269425.13953795 591110.517197168 5268259.48564049 591117.254888758 5267973.99391934 591128.122845498 5267811.8733961 591206.009888956 5266651.40546997 591199.616494462 5266222.16843626 591198.488342556 5266148.60815838 591175.006180318 5265104.63989 591175.439715822 5265012.45511298 591177.687918502 5263516.49940567 591178.432325836 5263386.50323498 591185.255417681 5262180.038753 591187.055459458 5261890.54726464 591185.737812806 5261770.48835248 591185.389639317 5260657.07797112 591184.567050358 5260286.58616161 591186.251345165 5260169.58869304 591203.585911612 5258692.558237 591206.144707272 5258557.62363551 591231.790581386 5257040.59378715 591239.281180766 5256698.72609417 591269.618002448 5255310.69324746 591290.448603308 5253691.72817665 591305.65503736 5252101.76256354 591326.173869598 5250510.79678628 591291.880300777 5248901.8326817 591296.39843466 5247279.68033507 591193.586980174 5247275.43286786 591221.166060928 5245605.90588963 591242.55956521 5244004.94002282 591286.202814154 5242404.97359231 591309.471500193 5240813.007405 591328.739695874 5239202.04166475 591344.570552771 5237596.07583646 591363.4010812 5235980.11010727 591378.544330248 5234371.1442482 591394.017360582 5232782.18812091 591420.004054301 5231157.24153439 591448.990594695 5229517.29534933 591475.977567139 5227928.34746962 591495.964618956 5226341.39958728 591521.951475128 5224737.45212944 591545.938530749 5223156.50389693 591566.925327205 5221541.55677295 591586.912063263 5219919.60983592 591626.898708537 5218299.78757514 591466.899466999 5218297.69547592 591480.886345409 5216706.71608139 591500.873003762 5215093.76854045 591530.859899174 5213513.81979972 591556.846369643 5211880.87277365 591590.833237315 5210296.92407028 591617.819976923 5208695.97592128 591635.806519539 5207072.02850491 591658.787079717 5205480.07127601 591684.746751559 5203843.08684967 591707.707415759 5202247.10199548 591737.667785504 5200640.11717552 591752.164237744 5199168.19328055 591745.051248586 5199157.97121544 591736.450994764 5199147.03135422 591727.360817793 5199139.1714658 591713.250707976 5199133.66157558 591701.69061102 5199128.86166826 591694.950522966 5199124.78173446 591688.71036928 5199118.07182361 591679.469948723 5199100.29203013 591669.629518109 5199082.05224353 591661.499009181 5199060.75247907 591657.138495057 5199039.52269857 591651.655586978 5199020.88079978 591650.817978316 5199018.0329286 591645.887660254 5199004.72307527 591638.387346142 5198991.37323288 591628.607062769 5198979.09338973 591609.086908203 5198971.29354405 591587.626729705 5198962.36371715 591563.856614487 5198955.82387707 591549.706571326 5198952.96396247 591532.706483829 5198948.07407893 591520.526421268 5198944.57416236 591503.416518085 5198947.18420787 591487.676834431 5198958.85416137 591476.116992589 5198964.40415597 591463.257050205 5198965.75419594 591439.577037757 5198963.40431567 591418.137065166 5198962.85440902 591402.3369922 5198958.64451415 591387.596923142 5198954.67461266 591372.306757534 5198946.71475157 591361.88654159 5198937.07488656 591351.456325752 5198927.43502162 591304.93543812 5198887.46559553 591277.244851213 5198861.24596072 591252.174400459 5198840.7862602 591238.044309966 5198835.94636498 591209.974085347 5198824.48659089 591185.473704708 5198806.90686083 591164.663437088 5198794.24706845 591143.243186502 5198782.22727256 591121.182996363 5198772.62745619 591093.642654176 5198756.32772701 591077.672374188 5198743.5179164 591064.162020583 5198727.87812286 591050.671645469 5198711.34833787 591035.341311237 5198696.33854601 591017.530831238 5198675.11882431 591002.060240344 5198649.51913515 590986.669767733 5198628.77939902 590973.759424895 5198613.57959931 590960.259056729 5198597.27981272 590947.948713249 5198582.09001055 590938.108526502 5198573.56013392 590918.558425989 5198567.75027178 590904.458294847 5198561.14039457 590889.758164789 5198554.52052 590878.218040119 5198548.3906275 590865.947874116 5198540.49075517 590853.017564862 5198526.62094327 590835.706776913 5198492.61134429 590827.656379556 5198475.51154325 590815.27566934 5198445.11188896 590807.865228319 5198426.25210237 590801.604854944 5198410.28228305 590799.154682936 5198402.96236412 590792.974432274 5198392.06249552 590781.944222379 5198382.41263536 590770.844114137 5198376.95273504 590759.913978962 5198370.39284465 590743.933954186 5198367.94293589 590734.783874538 5198363.83301434 590720.763627729 5198352.37318451 590701.123183212 5198332.22346265 590678.922733274 5198311.60375636 590661.822348884 5198294.14399798 590646.401913493 5198274.71425168 590624.981420651 5198252.34455949 590604.671096107 5198237.0347943 590583.300768642 5198221.49503596 590558.060368849 5198202.58532696 590540.330013877 5198186.21556145 590526.889800117 5198176.09571704 590516.419649661 5198168.87583184 590504.739512344 5198162.08594766 590492.529498122 5198160.35601659 590481.579391292 5198154.8961164 590462.528981496 5198136.08638067 590452.04861395 5198119.82658362 590441.59819886 5198101.58680577 590431.067667239 5198078.48707563 590423.507215111 5198058.96729799 590416.736703357 5198037.03754047 590411.006216019 5198016.21776774 590407.195565925 5197988.80805094 590405.235087562 5197968.71825495 590400.83464547 5197949.89845711 590395.204248641 5197932.83864748 590389.583819913 5197914.44885079 590360.542500582 5197856.66953909 590337.021288063 5197803.8301559 590322.27075184 5197780.01045213 590310.39021521 5197756.45073347 590301.83989959 5197742.43090738 590290.779488732 5197724.18113352 590280.779075703 5197705.94135503 590269.868913454 5197698.06147947 590253.21876847 5197690.31162771 590235.548562369 5197679.90180643 590219.688357719 5197669.73197498 590206.158043059 5197655.20217601 590200.9020524 5197647.37190981 590194.337650603 5197637.59239974 590185.677262455 5197620.48260484 590179.526974704 5197607.8227555 590176.976700304 5197596.09288133 590175.116546028 5197589.45295439 590160.376234443 5197574.89316135 590139.905207476 5197529.81369208 590122.754659444 5197505.08400942 590110.984178905 5197483.73427014 590099.853886948 5197470.33445032 590087.693555221 5197455.15465252 590075.353271417 5197441.95483619 590064.343021839 5197430.32499868 590052.562805392 5197419.99515188 590037.91260097 5197409.85531594 590026.242442697 5197401.96544483 590005.472367614 5197396.57558946 589993.272342065 5197394.18566682 589972.602587769 5197402.25567898 589953.18300385 5197417.61561399 589941.803344265 5197430.67553598 589928.463683839 5197443.49546892 589915.783937506 5197452.78543356 589907.204150616 5197460.81539246 589896.374337011 5197467.48537463 589879.214516341 5197473.18539417 589862.824677921 5197478.22541678 589847.684763466 5197480.20546397 589817.164845685 5197480.40559637 589803.08492372 5197482.18564083 589787.234937315 5197481.06572165 589770.215131557 5197487.4257339 589753.295409265 5197497.31571088 589680.976225268 5197524.01576544 589662.106490591 5197533.20575759 589645.596594144 5197535.82580422 589622.536800548 5197542.09584352 589587.437445058 5197565.60576507 589567.907784387 5197577.8857292 589546.078190946 5197592.77567748 589538.838425327 5197601.92561859 589527.948714554 5197613.01555644 589518.259016549 5197624.77548235 589506.189245361 5197633.19545171 589505.049383366 5197638.91540002 589499.559712858 5197652.28529151 589489.909952055 5197661.40524327 589434.07070408 5197687.46522851 589412.131036017 5197699.26520706 589400.071269417 5197707.91517373 589387.341602693 5197720.73510186 589378.831927032 5197733.61501096 589374.672070781 5197739.28497273 589369.252284741 5197747.80491165 589335.242630162 5197758.98494841 589318.732747143 5197762.26498756 589293.742897157 5197766.08505817 589265.763011661 5197768.09515976 589243.223114695 5197770.17523699 589217.07319437 5197770.89534344 589195.01324987 5197771.0054382 589175.523300135 5197771.15552139 589153.043299567 5197768.83564222 589126.173328579 5197767.32577407 589103.603473267 5197771.18583359 589067.693479392 5197767.77602371 589041.923444409 5197763.64617701 589012.183479457 5197762.09632179 588987.733498796 5197760.41644489 588960.273498246 5197757.57659272 588931.003501634 5197754.71674865 588906.01343427 5197749.26691197 588877.943450807 5197747.08705593 588858.973386897 5197742.39718553 588835.763347036 5197738.29732768 588819.913374687 5197737.84740117 588802.893332618 5197734.28751101 588784.433180284 5197725.8476762 588745.252639642 5197698.58812103 588726.862374672 5197685.29833495 588711.012161243 5197674.47851301 588702.962013683 5197667.29862042 588698.641925277 5197663.04868208 588692.011913514 5197661.84872311 588687.741978851 5197664.20871799 588688.892079148 5197668.63866835 588698.782407486 5197683.77847274 588702.562635755 5197693.97835355 588706.832796289 5197701.31826103 588712.403051732 5197712.86812048 588716.793510109 5197733.00789863 588700.933296408 5197722.18807661 588681.903104714 5197711.97826233 588667.862882262 5197700.95843452 588651.992684389 5197690.7986061 588635.402683002 5197689.00869649 588617.772658363 5197686.10880263 588604.8625519 5197680.17891876 588588.432540007 5197677.94901295 588569.392344313 5197667.52920121 588568.968985745 5197667.31239195 588557.8522352 5197661.61931126 588547.992076788 5197653.75943369 588540.762066345 5197652.54947749 588528.412025716 5197649.49956226 588507.092111163 5197650.93964085 588490.662084253 5197648.04974185 588477.872034581 5197644.55983302 588463.171917084 5197637.93996423 588450.931707928 5197627.62012214 588435.541479747 5197616.14030563 588416.051291207 5197605.93049428 588394.591106997 5197595.69069194 588376.280957076 5197587.26085754 588358.440790861 5197578.17102783 588337.000581682 5197566.83123678 588319.900429657 5197558.42139707 588298.460230781 5197547.51160183 588273.419989111 5197534.35184533 588251.399751503 5197521.68207071 588228.729586578 5197512.08226786 588209.209440476 5197503.63243956 588195.699337559 5197497.70255926 588181.739220396 5197491.10268779 588169.469069117 5197483.20282214 588127.08835378 5197447.51337199 588109.338037262 5197431.81361012 588076.167536795 5197406.40401537 588062.727332977 5197396.05418022 588040.007003099 5197379.18445262 587997.189861146 5197355.28233246 587958.036162317 5197333.42528241 587934.705835169 5197316.54555824 587900.945324469 5197290.46597456 587881.355060404 5197276.72620204 587867.284890095 5197267.69635691 587848.304604915 5197253.08659076 587828.074161195 5197231.39690275 587808.333671272 5197207.727233 587783.193123736 5197180.89761988 587766.632839135 5197166.53784091 587752.522488827 5197149.57807775 587745.732257522 5197138.66821992 587736.522042088 5197128.16836874 587730.271910456 5197121.67846324 587716.911795528 5197115.08859059 587694.711369148 5197093.81890817 587675.791005574 5197075.66917921 587662.200554507 5197054.29945952 587646.160169836 5197035.53972414 587622.279769051 5197015.13004106 587608.69953988 5197003.46022203 587589.04913941 5196983.54051516 587574.908610826 5196958.64083484 587565.00829315 5196943.50103515 587549.647782781 5196919.23135408 587540.387403603 5196901.45157881 587526.217157141 5196888.90177197 587518.816939183 5196878.42191328 587513.906830852 5196873.06199065 587475.196042997 5196833.68257137 587466.655723194 5196818.56276583 587456.105228056 5196795.47305158 587447.334793776 5196775.27329955 587426.384069539 5196740.78375027 587410.293298763 5196704.82419429 587398.562542597 5196670.03460656 587380.481562538 5196624.55515828 587366.190803783 5196589.28558758 587347.020127911 5196557.02600837 587327.929317525 5196518.81649047 587314.23855874 5196483.55691752 587296.277646554 5196440.94744036 587285.827234818 5196421.39769053 587275.336907821 5196405.57790241 587258.686522841 5196386.37817774 587240.856106155 5196365.60847489 587227.98572128 5196346.88872802 587212.455244236 5196323.72903949 587199.004821805 5196303.24931373 587185.484489313 5196286.7295474 587173.064104207 5196268.01979873 587168.223898197 5196258.24992236 587163.193747467 5196250.90002183 587144.093191878 5196223.72039212 587129.412808739 5196204.76065684 587115.322662993 5196196.39080917 587096.402530814 5196187.96098466 587068.792084367 5196164.40135765 587050.871800577 5196149.36159726 587039.241604152 5196139.05175853 587031.931475344 5196132.3318624 587023.881323642 5196124.49198137 587015.953105316 5196117.00221901 586992.580754886 5196094.9224347 586964.53051538 5196080.40271676 586951.730491577 5196077.57280607 586939.480530623 5196077.61286298 586930.930460349 5196073.30294781 586919.780208735 5196060.5631325 586897.029712456 5196035.31350178 586872.529340524 5196015.33382462 586835.68847428 5195971.57445331 586813.588136341 5195953.39474664 586794.58788868 5195939.66497915 586784.147715803 5195930.4751241 586769.397436609 5195915.9253453 586755.387185038 5195902.70554921 586744.236920685 5195889.31574148 586730.716613668 5195873.67596848 586719.726349092 5195860.28616011 586712.936126887 5195849.38630597 586703.595872443 5195836.67648281 586694.975680448 5195826.8566261 586683.425585446 5195820.94674245 586665.725424698 5195811.20692794 586622.865243747 5195796.91728017 586582.025195185 5195788.82755819 586559.945052865 5195779.24776306 586542.185001331 5195774.35789842 586526.414894799 5195767.28804722 586511.03465958 5195754.49825415 586493.82445946 5195743.00845621 586473.758613228 5195728.45415584 586473.034191215 5195727.92871298 586460.164032538 5195718.91886859 586447.243726959 5195703.29909382 586431.253494387 5195690.49930414 586414.073240761 5195676.56953205 586398.83302122 5195664.44973183 586382.20284978 5195654.27991781 586362.052757661 5195647.15008869 586339.492672947 5195639.99027143 586326.092639414 5195636.49037208 586313.182545683 5195630.35049818 586297.922356123 5195619.54068464 586239.912275238 5195607.24109084 586213.012355678 5195606.85122332 586194.702459283 5195608.79129025 586175.202527376 5195608.95138161 586160.642644191 5195612.05141839 586143.592665855 5195610.4815163 586121.672741036 5195610.60161962 586105.182824558 5195611.91168447 586012.442814525 5195597.56227868 585983.132887786 5195596.48243003 585966.072919379 5195595.35252344 585942.752828907 5195587.74271535 585919.572762354 5195581.23289501 585870.112760303 5195573.68321133 585796.232735106 5195561.37369507 585746.842854756 5195559.34395277 585712.032814533 5195552.23419481 585679.152811925 5195547.12440644 585661.367196132 5195543.78459015 585634.91243334 5195523.11487374 585607.791931338 5195496.04529199 585587.121714185 5195482.95553059 585567.161562901 5195472.97573272 585551.981493441 5195467.46586432 585533.791404237 5195460.58602501 585505.811518506 5195461.50614952 585483.161563497 5195460.07627352 585441.311455623 5195448.67659626 585432.732356882 5195443.09280206 585365.090631824 5195399.06749319 585316.56012397 5195368.16805768 585280.319737416 5195344.71848361 585239.069391127 5195322.29892302 585208.268998482 5195299.35931787 585074.126805628 5195176.82128407 584917.96486975 5195061.91328176 584889.584452391 5195037.91367918 584867.854023639 5195014.45403853 584858.823763025 5195000.87422927 584852.243456499 5194985.56442674 584836.613141685 5194968.36468898 584831.853038493 5194962.78477256 584808.762843308 5194949.88502505 584793.042671666 5194939.29521655 584780.952478743 5194928.31539452 584746.041678369 5194885.2660314 584726.721244485 5194861.83637984 584674.790426929 5194815.0071424 584657.19035791 5194808.80729629 584640.680465025 5194810.99735394 584619.990524693 5194810.26746383 584603.050358897 5194799.65766237 584503.478615705 5194701.21922258 584468.627719959 5194653.30991578 584446.957195369 5194625.00033104 584427.046745276 5194600.46069678 584404.066381612 5194579.41104001 584391.346232398 5194570.19120361 584291.034924438 5194491.15256438 584184.023492333 5194404.74404223 584162.253119124 5194383.26438593 584139.89272035 5194360.4547473 584128.562297041 5194338.46504452 584119.651874604 5194316.94532453 584108.931435569 5194294.30562596 584084.71089062 5194264.19607715 584009.419376432 5194178.89739061 583968.488572612 5194133.32809687 583928.488177406 5194107.18858604 583893.357732599 5194079.56906716 583883.694145455 5194074.67601182 583867.38755773 5194066.41934326 583846.727706804 5194052.84287567 583836.52725215 5194046.13972265 583756.755905956 5193967.18099636 583724.295297683 5193932.10154781 583711.624848325 5193908.32187421 583691.254414347 5193883.78224845 583591.823615985 5193826.60338736 583570.793274388 5193806.24371974 583557.39301044 5193791.05395607 583533.972641526 5193768.89432087 583511.022243702 5193745.42469792 583501.842204663 5193741.76478552 583489.182202116 5193739.1648793 583468.771606054 5193706.6853432 583451.931093753 5193678.88573722 583421.77064221 5193651.33619733 583390.350062707 5193617.37673521 583358.459490698 5193583.63727348 583295.798276023 5193512.85838203 583274.147510384 5193471.75895 583259.886959878 5193442.44934912 583183.265656295 5193364.20061636 583141.784560925 5193302.98151292 583130.984022225 5193274.82188234 583114.903491413 5193245.93228762 583092.602798409 5193207.91282721 583051.911650411 5193144.06375114 583022.851151542 5193113.8842399 582995.61085177 5193093.66460846 582981.090696483 5193083.09480269 582973.420440263 5193069.0949991 582963.230126083 5193051.75524605 582965.710029067 5193047.59527934 582960.259836966 5193037.15542444 582950.669525145 5193020.04566576 582942.259245083 5193004.71588108 582929.178742569 5192977.62625225 582917.718302239 5192953.87657773 582900.987842822 5192928.05695432 582878.067409964 5192902.16736469 582811.746262828 5192832.21849791 582783.935916247 5192809.34890141 582762.175780734 5192798.0191439 582742.675853992 5192797.30925566 582726.855834484 5192792.89938923 582728.165679079 5192785.63946347 582723.335472528 5192774.54961328 582716.255239147 5192761.65979524 582704.155077147 5192751.1299776 582683.535028339 5192744.22016494 582667.214852815 5192732.09038784 582641.194550911 5192711.66075561 582619.324345211 5192696.81103885 582597.054055172 5192677.75137156 582578.393786582 5192660.5216646 582522.193068794 5192612.99249891 582493.15276908 5192591.8628919 582455.592574425 5192573.92329501 582352.581983529 5192521.784435 582331.8718484 5192510.47467376 582311.941678437 5192497.62492575 582296.911384177 5192479.78520769 582281.851139437 5192464.35546273 582252.572755061 5192449.44172849 582246.710938041 5192446.455854 582218.130851991 5192435.69612955 582176.900740979 5192420.79652024 582087.280198283 5192373.47753914 582058.77999275 5192356.76788231 582023.069747915 5192336.42830578 581955.249275542 5192297.34911592 581865.088646742 5192245.18019697 581831.138468663 5192228.39057209 581808.058491843 5192224.11074617 581774.088363572 5192209.7510941 581708.067913297 5192171.80188511 581682.717725523 5192156.46219784 581648.177317825 5192127.98271051 581552.036389063 5192058.75402492 581521.216055931 5192034.73446767 581494.055645024 5192007.68492526 581462.6652673 5191981.23539948 581436.664922932 5191957.72581081 581419.114809399 5191947.7860208 581407.104511649 5191929.97629043 581400.534422889 5191923.93639561 581393.864259675 5191914.14654425 581389.124135873 5191906.79665439 581379.463924818 5191893.87685533 581371.613718802 5191881.64703847 581363.853609133 5191874.25716575 581351.133483073 5191864.82734372 581331.763370172 5191854.41756959 581310.553309983 5191846.18778071 581291.123294657 5191840.63795137 581267.453294473 5191834.79814878 581248.683201565 5191825.50835878 581234.11279107 5191818.05308999 581231.463031061 5191812.69860067 581220.142829084 5191799.75881157 581202.792409343 5191774.37919856 581189.201998844 5191750.3795491 581182.131764421 5191736.8397436 581161.351287257 5191707.6701935 581134.22107282 5191690.10054557 581094.240906154 5191671.69097873 581060.990822217 5191659.11130778 581013.660822823 5191647.23170708 580971.870897801 5191640.48201675 580927.510968046 5191632.83235118 580879.07083546 5191613.87283887 580844.730571352 5191591.79328453 580798.870197524 5191561.18389313 580753.92957731 5191518.24463966 580717.929110997 5191485.33522101 580701.898740805 5191462.40557576 580688.208481239 5191445.6858457 580679.778474079 5191443.14592222 580664.348773884 5191454.40587812 580653.504886832 5191448.80186727 580648.578693681 5191446.25606061 580633.148334579 5191423.99640466 580622.667795934 5191393.8668123 580612.717354449 5191368.80715835 580595.957193304 5191356.23739794 580566.72717941 5191347.9076584 580551.667152948 5191342.6278041 580532.436852851 5191322.29814781 580509.106581813 5191302.35851017 580485.446584917 5191296.30871331 580443.066407771 5191276.11918598 580403.986033909 5191246.6997477 580350.455650314 5191212.90044224 580282.635433514 5191183.77116369 580205.8351252 5191147.45202046 580143.014865834 5191117.28272746 580078.424565554 5191084.44347641 580048.064015281 5191047.87407583 580029.533560725 5191019.40451381 580004.983328769 5191000.76487116 579967.953262509 5190987.26523939 579923.323081154 5190965.71574531 579868.462645619 5190928.15649751 579835.761993633 5190885.38718536 579816.671490524 5190854.03766205 579793.510983096 5190821.3081784 579752.440480473 5190783.48145969 579746.140396182 5190777.67896152 579676.829948938 5190735.07985899 579630.659385306 5190692.7906212 579564.698451875 5190625.53179203 579531.737954913 5190590.25239741 579510.39743232 5190556.89291362 579492.626984608 5190528.4333517 579465.656543213 5190497.64387059 579439.936264655 5190475.69427822 579407.555802436 5190442.1848611 579362.204921486 5190382.92582383 579339.744278964 5190342.71642941 579321.303922697 5190318.65682098 579295.373732555 5190301.10717924 579263.973593102 5190284.59755719 579237.083257912 5190259.09801555 579207.19268387 5190220.11865133 579181.76199461 5190176.3393184 579152.311654602 5190149.70980606 579110.751401464 5190124.02035368 579063.201085565 5190093.18099791 579044.428208018 5190081.66904062 579019.090823164 5190066.13157752 578966.180426366 5190029.27232584 578922.870091355 5189998.49294618 578888.639691135 5189966.94352281 578862.559068552 5189926.0241635 578838.52873908 5189901.23460032 578815.538645213 5189889.24487867 578789.168433249 5189869.93526434 578763.268194193 5189849.30566317 578744.388260847 5189847.06580132 578739.028178565 5189841.0459048 578730.088028998 5189830.34608527 578722.417797773 5189815.68630555 578714.157532672 5189799.03655312 578703.397418341 5189789.63672896 578684.507498179 5189788.06685941 578669.177653521 5189791.61690765 578656.517661476 5189788.13702409 578638.957564492 5189777.5472545 578621.567441753 5189765.62749988 578599.897194325 5189745.71786623 578574.547025596 5189728.84821818 578547.887013065 5189719.89848327 578514.616975632 5189707.54882835 578480.017123221 5189704.66906801 578451.617018215 5189690.18940999 578426.157008175 5189681.69966285 578404.137254432 5189688.0197177 578390.75721403 5189681.66987328 578363.196990006 5189661.02028473 578327.946982147 5189649.54063194 578299.937171879 5189650.94078151 578278.577344653 5189653.52087737 578266.007222363 5189642.99107864 578252.697079807 5189631.13130036 578236.427081023 5189626.07145793 578210.387042809 5189615.80173633 578202.66688166 5189604.68191607 578190.586708135 5189591.51214648 578172.586592704 5189579.59239713 578148.41646721 5189565.16271486 578125.736166164 5189541.71313253 578105.806005074 5189526.67343263 578095.466141187 5189530.73344535 578078.346282794 5189532.93352092 578044.546143635 5189514.63394327 578024.105863996 5189492.97432665 578006.305463845 5189465.61476322 577980.784908734 5189427.3553778 577969.58454528 5189404.05572625 577956.004146988 5189378.08612131 577946.473985791 5189366.26632124 577928.184078295 5189365.36644178 577905.774027909 5189355.37669693 577875.223760487 5189330.94717567 577852.283608033 5189315.20750383 577823.443279063 5189287.92800728 577813.893143505 5189277.43819169 577794.103006342 5189263.5084794 577775.96288833 5189251.14873826 577752.612670999 5189231.65911498 577737.782344154 5189208.9794792 577720.962045222 5189187.14984524 577697.601857313 5189169.20020383 577674.55185403 5189161.41043743 577643.621920768 5189154.83070399 577613.981867357 5189142.10103753 577600.976878164 5189133.86534911 577554.261538406 5189104.28185795 577525.361292531 5189081.19231351 577506.271013892 5189059.55269228 577487.170755922 5189039.02305776 577467.220639836 5189025.97333749 577445.970652165 5189019.52354485 577439.016374108 5189014.65756724 577416.430456434 5188998.85397575 577388.810326058 5188982.39434393 577346.119976504 5188948.76501319 577331.049773146 5188932.47530347 577324.259372818 5188908.13564167 577317.289001535 5188885.32596236 577306.058691942 5188864.45628539 577292.998421472 5188845.10660111 577277.037984339 5188815.56705901 577256.837573067 5188785.97754359 577235.217266854 5188761.66797259 577231.376946104 5188742.64822839 577223.136663936 5188724.23850369 577194.026727023 5188717.68876193 577171.666606075 5188703.28907487 577143.046180313 5188669.84965918 577122.645849081 5188644.45009502 577118.845473407 5188622.34038885 577112.545013641 5188594.70076574 577100.804574992 5188566.32118521 577082.344269207 5188542.93158509 577060.873958322 5188518.18202034 577039.153780593 5188500.70236827 577017.503733784 5188490.49262684 576997.663457883 5188468.19302251 576976.863053085 5188438.37351648 576958.882921322 5188424.6937953 576941.412707191 5188406.60412517 576925.372389443 5188383.24451097 576907.621924083 5188351.04501599 576887.501422347 5188315.94557151 576869.330921085 5188281.53610671 576850.410409065 5188246.22665786 576832.109885924 5188210.48721068 576808.439286293 5188168.50787388 576793.04890039 5188141.40830288 576769.77857616 5188114.86877432 576744.998475145 5188100.21910916 576718.308520516 5188093.03936414 576697.738433013 5188080.64964511 576674.428173853 5188057.64007408 576638.34786194 5188026.97067752 576595.637561303 5187994.44134583 576556.527286507 5187964.62195867 576523.347143508 5187944.34241699 576484.18693344 5187918.04298745 576452.246733115 5187894.92347366 576418.75640237 5187863.84406828 576390.546038795 5187832.8346292 576380.555688208 5187809.33498276 576375.655168337 5187778.18539894 576365.674810111 5187754.23575815 576353.144640668 5187739.96601379 576327.394423762 5187718.02644793 576309.174412461 5187710.51665601 576271.234189423 5187683.5772295 576240.402110655 5187656.93773156 576233.124068803 5187657.72787386 576225.834239865 5187660.05797394 576214.87431734 5187653.30825299 576198.634460779 5187644.93864603 576184.04461 5187638.5789846 576162.99478831 5187627.28949963 576146.354664754 5187603.26009628 576127.614756088 5187589.35060327 576106.594903317 5187576.30113996 576087.80507291 5187566.80159257 576062.475388892 5187558.98214016 576025.475953312 5187553.43286636 575998.106405775 5187551.32337852 575975.586768737 5187549.05380663 575954.31706723 5187544.37424284 575939.887183307 5187536.25460088 575929.737169917 5187525.10492104 575914.148521236 5187515.43169817 575912.317292537 5187514.29536597 575885.76744941 5187496.0960658 575861.527708176 5187486.08662179 575835.570282122 5187479.34088602 575831.208113 5187478.20725898 575808.84826181 5187463.81783671 575806.938006683 5187447.24807886 575805.357915364 5187440.398193 575803.077763077 5187429.33837247 575797.297703652 5187420.00859235 575791.927682993 5187413.31877177 575778.117784823 5187404.98912166 575762.437985094 5187400.379458 575738.178271836 5187391.91999511 575718.848555843 5187388.36038309 575706.768734994 5187386.23062436 575689.089024546 5187384.68095779 575658.259512094 5187380.98155176 575644.209726034 5187378.8218284 575618.250104463 5187373.86235177 575601.190352471 5187370.56269623 575581.200725273 5187371.4130405 575568.94094971 5187371.69325468 575548.361309906 5187371.21362617 575525.871638659 5187366.96407902 575486.642179172 5187357.65489286 575454.592496697 5187342.91564761 575445.582567783 5187337.72587297 575423.26285158 5187331.05635336 575400.373114675 5187322.60686632 575379.913304209 5187312.42735793 575363.673449834 5187304.0677517 575351.613609611 5187300.82800672 575337.753766715 5187295.57831905 575305.894027984 5187277.75910953 575294.484111203 5187270.77940017 575278.924141491 5187256.46985694 575264.544193081 5187244.60026201 575247.944219052 5187228.96075407 575232.384245731 5187214.43121369 575219.184318711 5187205.00156711 575211.97438135 5187201.16174364 575193.004376827 5187181.30233112 575179.86436086 5187166.80274745 575169.694380349 5187157.41304659 575163.294344543 5187148.73326979 575153.684407833 5187142.4435199 575138.614587 5187137.18385408 575123.334857743 5187136.98412819 575096.555336425 5187136.87460556 575070.565739892 5187133.2451133 575037.186251402 5187128.19577032 575001.006709423 5187117.15655273 574970.657155948 5187111.48716378 574943.557441657 5187099.89779182 574904.487756607 5187077.57876819 574888.307822264 5187064.58921988 574856.727897893 5187036.19014004 574844.997800766 5187018.40057331 574831.507654882 5186995.96109664 574820.837527609 5186977.52151932 574811.487438081 5186962.63187371 574799.147355995 5186945.06231515 574790.837282459 5186932.17262581 574786.057271899 5186926.59278133 574777.657321941 5186920.75300454 574766.21744136 5186915.7632711 574751.767587608 5186909.19361117 574728.857876346 5186902.06410885 574690.288321683 5186887.69497666 574663.758652189 5186879.205556 574639.70885492 5186865.89615218 574627.71890812 5186856.48648449 574599.569001107 5186832.53728825 574572.749105064 5186810.59804301 574546.379212499 5186789.31878148 574508.799314281 5186755.99987188 574479.069310937 5186724.76079637 574461.329265485 5186703.59138008 574449.419203712 5186687.56179498 574434.629200966 5186671.942256 574423.229255771 5186663.20256961 574409.409361287 5186654.87292114 574395.229347899 5186639.26337124 574383.249390361 5186629.19371206 574366.329646117 5186626.33404961 574356.119721672 5186620.03431121 574344.139752869 5186609.30466043 574331.169710523 5186593.26509453 574320.509570112 5186573.94552904 574310.609420016 5186554.85594712 574302.489280041 5186538.21630248 574290.109257948 5186523.95670362 574277.619173183 5186505.93715436 574257.768923824 5186470.62795526 574256.088764186 5186459.58812502 574240.768665721 5186437.78867416 574232.718430034 5186415.63909819 574227.588301466 5186402.77935251 574223.684064193 5186395.95814203 574222.248237434 5186393.44956588 574219.528073623 5186381.06977117 574213.0080005 5186369.970028 574205.397988375 5186361.27027388 574195.19804165 5186353.65055226 574190.40805513 5186349.4006915 574179.048064586 5186338.01103835 574169.408172286 5186334.14125926 574163.408196148 5186329.22142858 574157.058097245 5186316.79169929 574153.767894392 5186301.5319513 574153.857756445 5186293.60205016 574151.067688796 5186286.73218696 574149.907644965 5186282.96225541 574144.607531272 5186270.77250437 574138.617551084 5186265.62267646 574127.987581958 5186256.23298504 574118.487497906 5186241.34334316 574110.377347342 5186224.04370704 574105.847197163 5186210.53395904 574098.957013427 5186192.58430942 574092.09679139 5186172.43468715 574081.416675663 5186154.44510569 574083.456533079 5186148.29514722 574068.116470541 5186128.48567201 574053.696569537 5186119.04604899 574030.336646766 5186098.90672117 574017.336644795 5186085.0771285 574007.776649399 5186075.25742362 573992.766736471 5186064.48782808 573975.906909633 5186056.77822679 573958.987178643 5186054.5885566 573929.17770868 5186053.99909622 573912.917878793 5186046.73947856 573900.307957246 5186037.98981465 573884.858041081 5186026.55023558 573867.528045388 5186008.48077421 573860.607897058 5185992.51110036 573855.88780401 5185982.09131682 573848.427578628 5185961.05171695 573845.65748094 5185952.4218759 573840.337398661 5185941.99210323 573832.127398473 5185933.29236023 573820.147431741 5185922.55271045 573786.547618673 5185897.88362363 573762.367914731 5185878.61168353 573762.107728511 5185878.40430741 573733.297905499 5185858.20507846 573718.858039897 5185850.74543113 573703.808189165 5185843.50579192 573692.608182484 5185831.2361478 573685.428194412 5185824.31636394 573660.758422137 5185811.44696815 573628.128920935 5185805.96762079 573592.949439425 5185798.92833884 573543.569963968 5185777.14949795 573501.390442618 5185760.32046563 573462.590996195 5185751.46127168 573439.081290502 5185743.68179077 573403.541672717 5185728.2426223 573377.901794639 5185708.08333696 573358.171803147 5185687.56395061 573344.311548117 5185657.84457637 573339.551509464 5185650.50475482 573333.161466353 5185641.16498787 573326.581479419 5185634.91518501 573318.771533291 5185629.74539042 573309.131642629 5185625.87561202 573284.772058087 5185624.25606823 573250.312617559 5185620.30673469 573228.37300829 5185619.81713326 573215.023289799 5185622.08734309 573185.563951017 5185629.44777621 573161.744458162 5185633.78814689 573141.714885788 5185637.50845768 573117.965297806 5185636.33889724 573096.815625442 5185632.98931808 573081.76577971 5185625.9696766 573067.9358897 5185617.65002987 573051.056095696 5185611.71040739 573035.98627288 5185606.01074949 573022.716444046 5185601.88103941 573002.656711044 5185596.12147153 572985.386830585 5185584.67192629 572963.756998424 5185571.39248236 572943.377080221 5185554.38306366 572924.327179547 5185539.82358999 572911.707271822 5185531.73391885 572901.207333351 5185524.10420395 572880.55757392 5185516.13467496 572867.937677509 5185508.70499545 572847.487858503 5185497.435505 572829.298017428 5185487.28595987 572818.508054542 5185477.89627266 572801.708151257 5185465.5667305 572790.338157615 5185453.73708484 572780.778161579 5185443.70738383 572772.43811722 5185432.13768065 572764.177963032 5185414.17805757 572758.287840847 5185400.64833557 572754.777739596 5185390.90852264 572750.067626138 5185379.15875683 572744.217451047 5185362.54907342 572738.287389721 5185352.55930701 572733.147254315 5185339.04957137 572725.527051387 5185318.88996497 572720.17700194 5185310.22017136 572713.006996727 5185302.20040205 572705.207043887 5185296.59061328 572699.197088756 5185292.77076963 572690.017179593 5185288.25099167 572674.987297333 5185279.02137857 572664.197346232 5185270.29168318 572650.427374128 5185257.11209795 572635.39749963 5185248.33247916 572621.546562286 5185228.35492222 572613.967367093 5185217.42325747 572608.627317879 5185208.76346365 572603.297249695 5185198.99368382 572597.947200692 5185190.33389019 572592.607151353 5185181.66409651 572584.827157427 5185173.63433838 572572.277163765 5185160.47473119 572555.477250493 5185147.47519813 572542.317260473 5185133.86560767 572526.587313234 5185120.00606647 572516.427310152 5185108.85639088 572505.687287752 5185095.93674831 572494.997189865 5185078.60716117 572483.936986799 5185054.65766523 572476.846857566 5185039.3579877 572470.436630338 5185018.9983626 572458.606452552 5184995.69887223 572447.936321116 5184976.38931013 572440.136361488 5184970.33952724 572430.476502698 5184968.23972725 572418.986688215 5184966.7799519 572403.116945418 5184964.82026146 572389.187197395 5184964.65051338 572372.887436452 5184961.15085034 572342.467763219 5184947.55156953 572323.748027372 5184942.91196447 572296.988251046 5184927.1626456 572282.308304408 5184914.41307181 572267.018380139 5184902.32350055 572252.92843413 5184890.24390767 572237.618324172 5184867.12447783 572219.168208048 5184840.2251527 572207.458062935 5184818.91563524 572190.327986332 5184795.77623844 572178.657792256 5184771.59675703 572169.267545851 5184746.78724279 572164.327348991 5184729.74754935 572154.397015803 5184699.19811825 572137.876928713 5184676.06871057 572122.586986774 5184662.87915372 572102.457140098 5184650.06967892 572085.437329816 5184642.80007745 572067.147412785 5184627.81059757 572047.547445249 5184608.39119792 572025.507540646 5184590.04182844 571995.677878035 5184577.56252377 571969.448205679 5184568.42311176 571945.658459481 5184557.5536781 571921.858724659 5184547.34423621 571899.369047788 5184542.00470847 571856.839805398 5184540.61549006 571838.610017755 5184533.33591069 571813.510214286 5184517.60656298 571801.360275586 5184507.97690457 571785.430190751 5184485.51747845 571768.900105802 5184462.38807174 571759.609937469 5184442.2084972 571750.369675713 5184416.51899238 571739.829370916 5184386.83956208 571727.449125759 5184358.69014527 571716.348757412 5184324.60078161 571711.858339244 5184294.78124444 571702.387774686 5184250.78197852 571698.007326965 5184223.70793833 571692.236908138 5184188.04296499 571678.616515879 5184149.73370086 571671.196232769 5184124.72415482 571653.976058211 5184095.4148402 571644.785951899 5184078.9852161 571633.665821655 5184059.00567224 571627.515648978 5184041.95600142 571624.32529639 5184017.43637308 571618.724969507 5183991.79680247 571600.834696716 5183955.85758511 571590.314566998 5183936.54802198 571576.844376597 5183910.36860005 571562.614218627 5183885.27917787 571549.824119512 5183865.27966455 571528.394200569 5183846.50029121 571510.874258443 5183830.64081007 571488.834350841 5183811.85144794 571460.724580372 5183794.54217623 571438.744804931 5183783.6927113 571418.71503086 5183775.07318267 571398.545233649 5183764.91367635 571374.075382273 5183746.76435002 571351.605678971 5183739.66484594 571326.02591813 5183725.68548619 571294.916159008 5183705.68630341 571271.656297158 5183688.21694678 571247.816405377 5183668.30763197 571225.166521477 5183650.17827293 571204.37654095 5183628.31892831 571187.376704931 5183619.29935054 571158.087127232 5183612.1199707 571132.577487631 5183605.42051659 571110.027889609 5183604.49093501 571096.658200753 5183608.30112706 571077.838611777 5183612.05141812 571066.860652575 5183613.62728872 571065.088878364 5183613.88162442 571045.059311418 5183617.61193752 571026.329599271 5183614.08232049 571007.929833334 5183607.69273429 570992.639892787 5183594.28318229 570968.310070027 5183577.89383158 570945.090146329 5183556.67452303 570926.720122775 5183534.84513493 570909.489964588 5183506.19581403 570898.469905883 5183490.41621569 570884.259714622 5183463.12682293 570871.929610055 5183443.12730254 570859.719540318 5183425.34775146 570846.919679593 5183419.45805811 570836.619872268 5183419.55824262 570823.870150332 5183422.05844045 570813.530395015 5183425.23858606 570801.42062091 5183425.31880348 570783.120919982 5183422.89916471 570764.2611817 5183417.609573 570747.221395223 5183411.44995965 570725.851603927 5183400.17049034 570690.411847401 5183375.2814501 570663.581951345 5183351.59223917 570649.991933264 5183335.33269375 570633.58189381 5183314.63325641 570616.351942797 5183298.33377725 570588.892099255 5183277.06454677 570566.412398741 5183269.96504396 570546.832623008 5183261.57550544 570520.002940305 5183250.67613015 570490.723123479 5183228.94693868 570476.09310321 5183211.34742958 570470.502975612 5183197.39771027 570463.012791271 5183177.89809679 570450.762775238 5183163.20850729 570436.862986975 5183160.39879449 570420.363293979 5183160.41909218 570403.433561554 5183157.57943449 570392.343604713 5183147.74976147 570381.293581186 5183133.94013905 570372.193558583 5183122.37045255 570363.553516521 5183110.14076626 570356.72345227 5183098.6010384 570353.033381187 5183090.17121374 570351.123120402 5183072.29147877 570344.392915325 5183052.3618573 570329.633077584 5183045.58221136 570320.673286362 5183048.12234047 570317.483348693 5183048.30239578 570306.073631865 5183052.5825467 570291.53391412 5183053.29280021 570269.584314517 5183052.81320292 570248.914589126 5183046.17366197 570234.244833749 5183044.46394904 570216.075164516 5183044.02428297 570199.585453605 5183042.95459467 570171.705985217 5183043.73508826 570156.456211215 5183040.2454088 570133.966519518 5183033.58590106 570114.436664 5183020.34642481 570100.956704569 5183007.62683256 570088.6667523 5182996.67719599 570075.836711623 5182979.76764614 570063.006678291 5182963.29809065 570051.936692886 5182951.70844035 570046.406474163 5182932.2387917 570043.22631414 5182918.96902053 570037.686124739 5182901.25934935 570029.036094905 5182889.69965498 570011.416284919 5182881.33008158 569989.51660509 5182876.01054617 569971.256854339 5182870.50094743 569939.027419555 5182868.36155772 569912.227910176 5182867.83204905 569892.238285956 5182868.03240783 569869.6786984 5182867.55282187 569847.729092229 5182866.63323056 569827.04937914 5182860.66368159 569804.609618452 5182849.81422754 569779.479856731 5182835.85486237 569774.559838523 5182829.18503757 569764.859821277 5182817.16536839 569755.579832649 5182807.35566304 569742.139822776 5182791.54611053 569735.459749831 5182779.55638639 569726.179561524 5182757.61683796 569716.389662433 5182752.65707917 569693.829857317 5182738.93766465 569677.890002877 5182729.71807223 569658.340171398 5182717.79858005 569637.040278193 5182700.13919382 569613.770413978 5182681.9998495 569593.040564829 5182667.65041023 569570.490745804 5182653.06100704 569550.370874612 5182638.05156535 569530.66085104 5182614.23223034 569515.300790584 5182593.10278183 569506.574549822 5182570.92934209 569505.450563208 5182568.07328413 569496.190324888 5182543.04377578 569483.800086812 5182514.46437006 569470.38003798 5182496.22484917 569455.590036359 5182479.29533614 569443.369976415 5182461.73578477 569432.33109862 5182443.61244232 569426.729838928 5182434.41643985 569418.059619319 5182411.16689793 569425.899303846 5182400.88688907 569425.239174971 5182392.28701238 569425.178835684 5182371.5572819 569420.788696159 5182358.05753622 569413.338446781 5182334.37797781 569408.898170493 5182312.4883417 569398.477893109 5182283.70890316 569389.037499794 5182248.97952395 569374.22707952 5182206.47034284 569358.22686966 5182175.41103508 569355.026748154 5182164.35123632 569337.386753503 5182144.52181292 569314.727090957 5182139.19229277 569300.837283674 5182135.06259808 569278.337618193 5182129.73307506 569238.517916471 5182102.37415154 569227.607912969 5182089.67451393 569210.987946997 5182072.72503497 569194.537949091 5182054.01557576 569177.327983405 5182036.39611626 569162.577910712 5182015.05666038 569151.587807978 5181996.18710433 569145.247470781 5181968.32758047 569142.757177753 5181947.57789462 569143.14683113 5181926.85815611 569144.856517674 5181909.67834777 569148.37618133 5181893.17849775 569151.335804888 5181873.58869793 569156.595335077 5181850.93889601 569163.734739796 5181822.78913121 569178.053711115 5181776.42947198 569185.732982948 5181740.79979417 569193.362331326 5181709.79005736 569197.411873017 5181686.4702859 569203.351292579 5181657.87054849 569208.710889164 5181639.41069024 569212.82034998 5181611.23098056 569220.369598451 5181574.05132492 569226.309006979 5181544.79159591 569236.498332537 5181515.36179181 569260.446996192 5181461.39205525 569267.566642848 5181448.03209877 569276.616097779 5181425.20222977 569285.485599333 5181405.01232983 569296.295093732 5181386.62237129 569305.314592333 5181366.43246856 569312.504136087 5181346.89259067 569320.913656922 5181327.36269043 569328.003140948 5181304.07286282 569338.67240601 5181271.56308934 569347.661955572 5181254.463147 569363.331126925 5181222.01328165 569380.030329522 5181192.66335738 569382.568093636 5181152.94309365 569371.969329998 5181122.48191173 569359.216991597 5180965.2966766 569356.466493937 5180931.79715987 569400.714079377 5180835.79759475 569406.088560822 5180810.42282477 569470.210304718 5180686.2670101 569494.709058415 5180638.73592729 569517.958036324 5180603.42345928 569528.45725426 5180567.98622535 569551.956060471 5180522.54888325 569565.080144887 5180482.04916657 569632.701739862 5180353.29959366 569635.451395395 5180335.54977244 569643.076210057 5180333.11216466 569656.200418968 5180300.23734905 569788.693776375 5180050.3631495 569791.44343132 5180032.61332794 569866.564916472 5179906.48857881 569890.063717623 5179861.051234 569923.687200949 5179808.11380027 569952.435481921 5179737.30168549 570019.932231169 5179618.73947505 570020.057060485 5179608.5521038 570048.555680866 5179558.11473047 570100.428142559 5179464.73998058 570152.175857315 5179386.6150362 570165.05024202 5179364.36508607 570372.665308705 5179005.67838195 570398.414229224 5178970.49086053 570497.034354773 5178791.30384626 570507.408819459 5178771.11641432 570517.658412031 5178758.49138775 570530.657616301 5178725.67906924 570556.406575207 5178692.92901552 570572.030685854 5178657.55418139 570721.773641377 5178407.99212157 570752.772371449 5178367.74206594 570752.897157919 5178355.05472589 570794.270602216 5178309.74204377 570804.76993574 5178281.92970606 570828.143853053 5178244.11725905 570838.393529426 5178236.61716619 570843.643132023 5178218.86729637 570895.640990572 5178150.86720761 570906.140448343 5178130.55477369 570969.012585702 5178032.05487325 570982.761850645 5178003.99247814 571001.386233398 5177988.67983036 571074.382815125 5177868.86751359 571084.757445356 5177858.80495065 571105.881316483 5177815.80510957 571118.630746215 5177795.55510817 571135.317716381 5177769.52353058 571155.067089262 5177738.67939336 571178.3788501 5177702.36643709 571191.25342064 5177679.61618372 571204.252969058 5177654.36592674 571217.127621113 5177641.86568032 571245.626690569 5177593.92762302 571279.125724919 5177553.67697916 571351.748326282 5177427.55056576 571545.617370039 5177145.35936018 571579.116389857 5177102.54622782 571586.991079517 5177082.29607466 571607.74044401 5177052.10818228 571625.864878269 5177024.3578394 571649.114175186 5176991.60740149 571664.738618166 5176958.79460298 571692.987839876 5176928.60657654 571703.487440808 5176903.35637533 571747.361166652 5176847.98055676 571827.483687211 5176726.97906069 571866.107595415 5176681.72834714 571899.856518111 5176626.29021987 572000.478538353 5176490.2883681 572054.851855255 5176407.09987031 572095.975720517 5176361.84912263 572121.974892958 5176318.97364763 572225.096878772 5176183.03427991 572225.346775964 5176170.34677318 572238.096495436 5176165.40904531 572253.471029412 5176142.90876785 572269.095516803 5176114.9709854 572547.712485134 5175757.5910215 572760.893965755 5175497.02478568 572844.079123081 5175395.33584209 572849.453886825 5175377.5857502 572872.453320513 5175360.08535156 572898.327526985 5175319.77240606 572988.574969836 5175206.52085537 573545.934649102 5174557.76147007 573591.308408477 5174504.94822102 573761.428742256 5174303.75793427 574338.787798271 5173591.748739 574377.661762125 5173548.09188038 574390.286425936 5173533.93543306 574408.161060683 5173529.06014185 574413.285929702 5173524.06006126 574458.785242578 5173544.93429316 574497.159353301 5173519.99618045 574573.657783353 5173498.05743741 574797.278606743 5173490.55375758 574861.027290862 5173470.99022665 574950.025585292 5173461.86377021 574960.6500804 5173418.801141 574966.149742699 5173385.8635856 575005.648162765 5173266.92556518 575106.895002345 5173085.23661197 575180.017919609 5172981.36054137 575194.954994324 5172960.11032358 574893.083955377 5172742.02169226 574523.842045287 5172926.37124191 574431.78157212 5172973.06019764 574381.095188705 5172998.74850092 573839.10716416 5173273.56966953 573150.312561799 5173965.33082721 572757.510447767 5174371.68114196 572589.577408777 5174545.46524465 571865.534280649 5175294.60286016 571450.482921095 5175715.64156857 571150.678513564 5176019.77205896 571044.493889161 5176127.52402428 570945.121584151 5176228.30712328 569545.035437276 5177701.17800856 568850.236130719 5177670.9721113 568728.05098341 5177669.56812704 568116.875348472 5177673.73573361 568078.938388472 5177651.08013966 567961.378124028 5177646.45731162 567681.883438769 5177635.49372379 567475.88721203 5177610.9349869 567415.200550961 5177572.46726768 567333.139183745 5177520.43740788 566815.896282877 5177192.38357472 566323.65295412 5176877.8916627 565860.034179866 5176581.71164289 565488.224218152 5176079.77913727 565481.161765349 5176070.21673024 565453.411951475 5176032.74834523 565453.532749863 5175573.30925204 565453.655343666 5175310.37083667 565617.586827656 5174989.86688538 565431.585416794 5174453.1807221 565350.834790518 5174220.15001986 565246.771769923 5173952.30706415 565213.397238207 5173935.71381454 565064.274326279 5173861.40354321 564699.719173033 5173922.59738972 564566.534359829 5173944.97471402 563637.055802585 5174379.61723962 563363.247225477 5174254.4650846 563279.623352728 5174209.15379638 563105.250305583 5174073.93737222 563072.250867288 5174068.37540315 562974.752526144 5174051.90822064 562754.256276048 5174014.7242604 561973.771623433 5174095.5503325 561791.836067404 5173949.20888339 561777.273175625 5173882.36502476 561770.085367599 5173837.83365963 561659.957984095 5173392.17686987 561456.271602598 5173126.64754164 561350.647173711 5172988.96101705 561168.336898399 5172875.96336649 561122.274951155 5172846.62020246 561115.025082706 5172846.43281955 561069.525647811 5172819.40215804 561031.526119196 5172796.8088985 561001.213949163 5172774.24676329 560948.151970812 5172729.27861894 560796.715775128 5172583.28023213 560721.965447171 5172415.81171328 560764.897430781 5171949.49580538 561279.573152618 5171710.23630282 561498.193996626 5171691.76400878 561983.684774784 5171650.75615382 562458.0508877 5171622.31105753 562848.352779966 5171259.02192256 562859.539976858 5171248.61544857 562968.473798092 5171071.95666214 563003.593971717 5170638.89154875 562892.280327427 5170315.45417486 562605.344449561 5169956.862956 562521.533105642 5169922.6452817 562132.663885022 5169807.49421506 561900.478973164 5169652.65307941 561826.354795942 5169603.18515649 561760.418026613 5169559.18588925 561511.731892284 5169255.37536316 561503.544436728 5169245.37542689 561232.357556692 5168831.43952103 560884.234916915 5168461.19234912 560779.54675206 5168215.66112953 560843.231538989 5168057.81555244 561038.535743858 5167573.71625541 561087.032326471 5167318.58910831 561035.28141488 5167140.27627399 560868.532687849 5166982.99635267 560671.471626746 5166792.09160942 560268.163713109 5166565.78310088 559962.168798069 5166551.63082396 559945.856671366 5166560.75609864 559415.806337168 5166857.39010275 559202.310174281 5166873.86182968 559032.875720978 5166886.95794503 558492.756506145 5166559.43164058 558332.508941898 5166530.87106572 557965.577012159 5166465.43795764 557486.715217369 5166927.60404274 557309.346432995 5167097.17042 557218.850875963 5167183.67258413 557188.102386366 5167213.04831805 557035.047413113 5167359.39571248 557005.673859732 5167387.55266058 556951.989002865 5167438.83518359 556876.680213447 5167510.80571625 556710.56030707 5167383.80753859 556641.187430972 5167330.77705381 556165.510935237 5166648.46758678 555813.836652007 5166611.84826032 555643.345838285 5166843.66525374 555579.975893963 5167076.44918541 555516.231468122 5167353.67092001 555201.307696538 5167484.14578984 555092.187006035 5167489.24138159 554803.260918577 5167502.74625542 554761.950429776 5167538.02842401 554743.638821366 5167553.65383076 554610.457814958 5167667.68803543 554539.088767291 5167944.8785355 554537.714104559 5167969.69122118 554528.216463055 5168143.56751933 554514.594828928 5168391.3818683 554511.658053458 5168444.69476578 554450.598149601 5168462.25837087 554254.481493866 5168518.82441583 554212.483281361 5168530.91892377 554145.733204339 5168296.94974861 554139.232048814 5168174.63656741 554148.541998444 5167985.04144484 553470.693821533 5168011.80270507 553439.712858505 5169533.81262435 553427.732396188 5171162.82285219 553403.752034889 5172759.83301632 553383.771651848 5174368.84314128 553355.791643031 5175981.85334717 553351.810650603 5177595.86318564 553330.828407997 5179198.84213875 551741.892997035 5179287.86144805 550123.957608117 5179265.88261581 548516.021850388 5179243.90363668 546914.085935204 5179232.92441706 545321.149602686 5179201.94532802 543650.216504964 5179203.96679193 542032.28124317 5179264.98679513 540430.345259956 5179248.00759231 538756.412126805 5179248.02907838 537221.431611674 5179254.05218577 535605.424529336 5179255.07890249 533990.417465329 5179274.10537635 532381.410489906 5179317.13142772 530787.403635033 5179294.15814945 529189.396799056 5179301.18453868 527600.390098711 5179330.21047239 526019.384250467 5179566.23320789 524404.377615024 5179556.26010977 522796.370766589 5179501.28761151 521175.36375734 5179442.31544096 519525.325264365 5179380.28135453 519394.355935139 5179375.34611238 517916.328271882 5179332.36865748 516306.291369745 5179249.39311185 514626.252972295 5179185.41839672 513009.216520757 5179180.44179076 511387.180069969 5179185.46510066 509763.143811634 5179209.48807252 508151.107766549 5179225.51104065 506539.070830495 5179170.5356119 504914.034421812 5179180.55899068 503301.998167785 5179179.5824689 501695.962547851 5179211.60507996 500088.927078579 5179251.62748838 498462.889373269 5179247.62316423 496848.851735509 5179237.6171233 495302.815676504 5179229.61132198 495346.84729782 5180821.57463446 495340.878395801 5182446.53695695 495368.909626316 5184043.49993398 495375.93995181 5185617.46334803 495394.971242756 5187232.42574426 495420.002151849 5188825.38856517 495446.03275704 5190405.35159924 495503.064321413 5192017.3136871 495524.095615327 5193646.27538485 495564.126526155 5195247.23755609 495560.156779411 5196842.20002694 495603.188010644 5198467.16141745 495611.218295986 5200062.12367648 495637.248778541 5201663.08557362 495650.279726696 5203296.04675013 495676.309926805 5204889.00866588 495711.353257682 5206502.98535492 495747.398906727 5208109.96516074 495763.443521209 5209683.94554618 495759.488657558 5211278.92586094 495757.534996631 5212916.90557524 495769.579718949 5214497.88577718 495749.624731671 5216090.86619041 495735.659231801 5217311.85113751 494959.659115045 5217313.86122848 494970.705119564 5218929.84108862 494995.750458042 5220523.8209809 495003.795943673 5222123.80097645 495029.841657324 5223733.78054491 495057.886755016 5225323.76027618 495042.932737237 5226942.74021409 495039.977911121 5228534.72027518 495038.023517812 5230142.7000773 495024.069605433 5231766.67981888 495019.115198974 5233362.65844546 495028.162292141 5234979.63287876 495020.209257124 5236590.60763539 495020.25677792 5238222.58188682 495069.303271475 5239826.55568717 495109.350249214 5241446.52931016 495126.397469637 5243072.50317726 495135.444059105 5244676.47748387 495131.495656431 5246452.01174692 494969.496243897 5246452.45230827 494795.543352658 5248054.43014654 494770.589645386 5249647.40528159 494775.636449952 5251262.3794381 494778.681964043 5252833.35429019 494796.728248945 5254433.32831968 494809.774558379 5256034.30238152 494927.819864232 5257612.27448102 494951.864575155 5259160.24900567 495092.910126374 5260757.22018159 495122.945638598 5262364.19987764 495170.980399668 5263944.17941097 495203.018507466 5265676.15736808 495207.054052006 5267287.13741823 495199.089378382 5268885.11787935 495275.123248513 5270449.09659807 495273.160182488 5272126.07581067 495167.197052713 5273752.05834863 495209.110948557 5275537.03499854 495210.271082612 5277133.01502885 495241.46229853 5278739.99404238 495300.561408565 5280442.97098496 495352.374997453 5281951.95047877 495408.40961765 5283572.92834458 495395.446087868 5285230.90769069 493836.441274287 5285240.57888839 493825.510468566 5286899.93388971 493824.545357675 5288432.91510224 493806.596553693 5290017.89177349 493775.648970343 5291608.86854032 493750.699693533 5293150.84586706 493728.753104446 5294776.82181349 493731.649256886 5296388.79709995 493731.935767607 5296550.66961577 493776.730713998 5297964.77137662 493783.330511173 5298155.64321211 493838.093445917 5299556.7446901 493846.756365626 5299768.80360605 493904.424709744 5301149.71765226 493913.118863083 5301361.8390452 493921.563243168 5301580.83533847 493954.755974827 5302733.94120834 493960.013024057 5302956.00006086 493955.9946899 5304317.66657612 493956.565520734 5304575.66254475 493954.046946923 5305931.6415582 493953.86701868 5306165.63792368 493952.442891526 5307544.61650254 493952.326104836 5307798.61254779 493954.463320831 5309145.59144216 493954.877885721 5309403.33739959 493963.859589912 5310780.31549167 493964.929757913 5311018.81171352 493961.567301206 5312372.22816381 493960.325626435 5312628.97419436 493960.367397812 5313923.51638735 493431.384461735 5313928.53994069 493490.434964883 5315540.51239895 493379.48653035 5317130.50072358 493388.531252847 5318741.49042006 493360.577546444 5320361.4818554 493352.622551027 5321960.47243614 493352.081509723 5323845.46083966 492804.884251059 5323832.30308164 492804.728410709 5323846.4905109 492786.743364527 5325445.48257286 492776.789998417 5327070.47405103 492758.836543209 5328679.46609166 492788.880984317 5330290.45520526 492781.9264423 5331879.44663193 492780.972009399 5333482.43757738 492783.017951372 5335104.42818006 492746.065367191 5336708.42150474 492720.11243214 5338317.41412255 492733.157548137 5339930.4039689 492739.203056658 5341545.39423472 492746.063959719 5343265.32127047 492951.176985921 5343257.86832142 492951.052204394 5343265.36828563 492922.29539326 5344928.3569705 492934.35169547 5346483.34022611 492947.410593318 5348110.32261461 492938.469013554 5349693.30712058 492927.530125579 5351349.29100348 492967.586978927 5352956.27129905 492969.645361767 5354555.25463466 492999.703801659 5356189.23530221 493036.761092332 5357797.21559205 493033.82054541 5359419.19892554 493050.878525029 5361022.18076849 493074.959125943 5362394.97688371 493169.268276769 5362392.59408621 493175.88894744 5363984.13924712 493176.488060854 5364130.88764683 493189.479189174 5365604.18347051 493191.047021142 5365750.86928435 493204.537530078 5367207.16519159 493206.293819464 5367380.03820552 493234.845517007 5368810.83304566 493238.445335476 5368978.83094687 493267.496754917 5370400.12577509 493271.190904903 5370583.74849247 493312.272784848 5371989.04571345 493315.329980969 5373555.07264266 493327.388340583 5375159.09941695 493337.44704718 5376772.1264789 493341.504649911 5378352.15344092 493360.562932647 5379960.1795722 493372.621192826 5381564.20619109 493399.679270822 5383172.23157814 493468.737445095 5384806.25386166 493479.37420531 5386074.14118232 - - - - 373992.834567751,5252100.90249579 375578.907291097,5252060.9016806 377183.981372119,5252035.90076999 378770.053836318,5251988.90012694 380424.132814015,5252045.89859687 382036.206902856,5252012.8979458 383378.268520258,5251983.89746 385004.34489571,5252002.89649079 386772.428209329,5252032.89545573 388359.488754287,5251990.89431465 389964.549770751,5251954.89312519 391575.611064042,5251920.89196047 393178.672571485,5251902.89076516 393228.738270271,5253772.88131533 393228.792456634,5255363.87321734 393234.396568643,5255577.49913186 393290.022245729,5255616.371974 393390.058438338,5255644.18441468 393456.779853272,5255644.18446989 393523.470080964,5255646.05951586 393612.378616319,5255608.99727381 393710.566996525,5255520.06029167 393761.41076364,5255461.24811933 393799.504685641,5255421.87334027 393801.348444994,5255419.99835078 393841.473568551,5255376.87359007 393843.129820376,5255374.99860038 393872.227230318,5255341.53053376 393872.254834063,5255341.49878372 393897.254849763,5255312.87393979 393937.723412979,5255260.37422077 393978.628478725,5255178.31214177 394000.095924966,5255115.37495644 394028.845055521,5255056.68775393 394150.002619737,5254954.68830693 394178.156529424,5254854.00129532 394182.905333014,5254813.68898684 394167.965771729,5254770.93918013 394099.587293418,5254748.62675282 394009.927251763,5254741.75174377 393877.07762318,5254723.93926859 393780.791470774,5254692.25187944 393703.692246657,5254621.56469184 393669.876928002,5254578.31489037 393670.062654952,5254526.25264556 393700.781229152,5254485.56535535 393760.812865314,5254427.44065828 393853.751326504,5254348.19106971 393938.597961266,5254334.50365964 393995.006383031,5254332.81618377 394145.355850435,5254326.25375792 394274.486167185,5254332.44126676 394384.022495763,5254354.19119954 394496.36942946,5254317.6914001 394536.806777902,5254266.94164156 394531.897189883,5254175.75455242 394583.272771438,5254133.81725321 394667.119014884,5254110.19237722 394714.55412945,5253986.94293421 394721.021368279,5253935.8181618 394744.520795483,5253892.44335681 394735.643469879,5253835.25610857 394714.858845106,5253761.25643422 394717.749468196,5253733.17612058 394721.13823463,5253700.25670446 394781.639561834,5253669.81934075 394850.141230463,5253640.19447216 394876.479432891,5253639.04667605 394969.176980153,5253635.00699702 394976.271037152,5253635.81949367 395519.510298066,5253611.56960918 395527.698069839,5253610.13211528 395591.795584246,5253645.88197253 395621.11081318,5253691.13179129 395623.173960433,5253707.38172584 395623.176417391,5253707.40122329 395626.206167995,5253731.44412897 395624.42712544,5253796.81886485 395634.993873549,5253906.81842208 395675.779923451,5253998.44306012 395723.252798144,5254063.06781092 395768.693664449,5254108.19264151 395804.538842082,5254108.56764903 395837.383216462,5254089.31773351 395891.728427757,5254069.75532382 395967.856422362,5254069.50534305 396028.203464222,5254095.56775665 396091.7057842,5254090.2552933 396158.018641153,5254025.69305678 396207.143077038,5253954.25583919 396239.860088802,5253867.81867238 396265.140567313,5253817.38136647 396287.703064163,5253791.94396523 396349.451795259,5253686.44436663 396349.452518554,5253686.44313108 396435.981260687,5253538.63241924 396471.021093905,5253535.14250544 396585.330355029,5253523.75747785 396741.052982495,5253460.13270856 396914.055403227,5253336.13314084 397183.096578436,5253318.38319059 397545.171773706,5253275.94581428 397881.089840105,5253237.88341716 398071.64310277,5253157.87611795 398411.165163381,5253015.32152345 398631.698949906,5252845.19695914 399211.553391767,5252512.82267203 399663.185514918,5252316.76194781 399663.18890481,5252316.76047621 399860.037217754,5252231.26058686 400083.512972148,5252184.8230912 400127.578144634,5252211.26051796 400233.550599022,5252199.82299713 400392.403112184,5252270.94779296 400644.262451817,5252429.8224055 400740.299196128,5252477.88478972 400989.095604804,5252627.32196682 401273.410740343,5252782.18896504 401273.424874001,5252782.19666367 401461.623488353,5252884.69648485 402111.037066948,5253242.0084967 402756.197989468,5253528.32078538 402756.232668418,5253528.33619738 402793.32506112,5253544.82077835 402867.907487764,5253578.15366794 403433.110881015,5253830.75824447 404070.552136632,5254094.38338663 404491.656023924,5254280.81508194 404491.669532849,5254280.82106263 404783.560952753,5254410.07122691 405363.374686197,5254661.44665537 405734.208224886,5254827.88450101 406041.500987131,5254961.06164401 406211.470139018,5255034.72431631 406211.538019337,5255034.75373486 407660.240902993,5255662.48321719 407660.246229705,5255662.48552528 409257.927861926,5256354.76517912 409768.695446346,5256576.08211699 409768.735834776,5256576.09961805 410876.518642679,5257056.12235784 412464.215509083,5257744.10071817 412464.225407797,5257744.10500746 413134.450013265,5258034.52484274 413134.466727295,5258034.53208522 414078.413610222,5258443.55154306 415221.098420247,5258938.68567606 415571.629807004,5259102.51900859 415769.741983816,5259195.11379287 416434.655664678,5259066.41721755 417233.950045496,5258911.95358296 417489.386345476,5258862.59051942 418521.576772072,5257884.97093374 418521.591206801,5257884.95726216 418620.339921949,5257791.45653319 418831.135731339,5257384.15777492 418831.142864938,5257384.14399141 419054.28907216,5256952.8940561 419277.644919394,5256325.22223341 419856.168262366,5254699.46313352 419856.169413348,5254699.45989922 419961.504463663,5254403.46415262 420370.297607175,5253877.47685802 420370.308017787,5253877.46346286 420684.45751304,5253473.27560163 420699.582566932,5253465.52549195 420722.613575374,5253443.65040793 420764.831886821,5253403.65025458 420829.73680308,5253321.52519332 420834.64266021,5253306.21276429 420854.485740219,5253272.90031502 420866.891582105,5253252.40034442 420911.702847702,5253185.7753913 420916.608703616,5253170.4004639 420929.139875651,5253160.0879085 420943.95161062,5253126.9005183 420948.92029462,5253121.71300567 420976.294371275,5253075.65058271 420989.130741489,5253056.910871 420989.137780079,5253056.90059542 421006.168577563,5253032.02561281 421021.011645038,5253001.33820388 421045.854749242,5252965.46322743 421050.760526428,5252947.58832284 421095.478050707,5252880.96338574 421190.632859417,5252775.46322344 421240.569406453,5252713.83819618 421287.849247044,5252639.52580995 421318.005367827,5252616.21317859 421315.286159703,5252603.58831637 421350.066321376,5252547.21341889 421382.409098178,5252495.96350618 421384.314008781,5252452.71385708 421391.845169808,5252445.08884084 421391.719840624,5252434.83893032 421396.030730076,5252381.526842 421375.216517007,5252341.1524139 421374.62137633,5252297.90279171 421389.339211332,5252259.71546142 421439.620257473,5252220.90275569 421482.62079669,5252210.08988797 421515.370809449,5252189.33971675 421547.839000509,5252150.77720407 421547.525768606,5252127.96490559 421557.619477922,5252120.15236577 421554.900351987,5252110.08998223 421562.462842742,5252104.90244671 421559.837466754,5252094.77756272 421579.680564474,5252061.40264186 421612.18009031,5252025.40261033 421690.211223396,5251971.02725899 421722.616760143,5251927.4647989 421729.92868152,5251904.46492394 421734.020257746,5251833.27800685 421753.863120106,5251792.34065896 421788.862620665,5251753.71563313 421889.644066225,5251693.90261076 422075.827735249,5251576.96673523 422075.831736897,5251576.96422193 422108.800519537,5251556.276567 422205.645840043,5251504.99070285 422207.113423663,5251504.21352236 422244.926218816,5251488.58827447 422292.238430961,5251448.1506557 422350.049479048,5251363.71333411 422397.70382296,5251271.46369329 422432.732605257,5251169.65177332 422437.887611685,5251126.65211682 422435.792387474,5251081.15255657 422428.885208473,5251056.21535543 422411.540394442,5251033.96573417 422294.688318968,5250847.59360662 422255.654102918,5250779.59461272 422219.55840433,5250741.97031117 422061.99058887,5250679.15993049 422061.990289746,5250679.15981114 422010.145087406,5250658.47312548 421961.424283542,5250626.16139231 421855.856373036,5250525.97581499 421817.417266538,5250501.03890998 421735.883675561,5250481.85237194 421596.130524203,5250476.16627958 421514.722253168,5250467.04214947 421468.689318028,5250444.85528805 421437.437048994,5250394.48102527 421385.401717388,5250301.16982975 421335.678528613,5250195.23371455 421331.737705773,5250093.67212132 421345.735002741,5249999.48529523 421345.537144329,5249912.26386602 421345.22786428,5249775.92471481 421330.504103495,5249628.73861119 421338.875153431,5249499.17714312 421346.218410959,5249478.73975099 421345.591940809,5249433.052648 421357.778483914,5249394.74036538 421359.683396659,5249351.49071882 421369.55787616,5249328.42832716 421388.837111648,5249252.0538087 421423.517340626,5249000.05566585 421452.195427332,5248684.68313187 421461.975917627,5248654.05831132 421524.318507261,5248574.43346162 421551.567482383,5248523.30867083 421555.157836141,5248413.99708926 421539.312288896,5248368.49761892 421513.247526146,5248315.49829921 421511.959865427,5248306.3313929 421507.5586117,5248274.99869791 421494.776839725,5248267.49887062 421340.200046766,5247926.69059106 421332.261646246,5247904.0033505 421282.412996707,5247785.31727213 421271.379475581,5247721.88040245 421269.46880705,5247584.75658579 421247.996825848,5247498.63249077 421244.400567,5247422.57066615 421252.336254887,5247360.19613367 421277.364405893,5247245.38441401 421304.456728695,5247181.44724735 421339.299551238,5247127.63493585 421471.860304437,5246978.44769333 421531.765467603,5246901.51039967 421541.921863026,5246898.82284537 421541.671292921,5246881.07300122 421568.982868386,5246832.4482153 421593.91995487,5246801.57329442 421593.700633866,5246783.7609511 421611.231792789,5246768.32345282 421613.66902469,5246758.13602316 421625.918251708,5246725.01121945 421633.230187974,5246702.011365 421635.604998005,5246694.32391421 421639.93604477,5246678.39095562 421645.322834495,5246658.57415329 421650.29145582,5246650.94918262 421644.821612398,5246620.44948996 421629.007389331,5246577.57498222 421600.161055511,5246517.01322451 421592.253901606,5246494.26348113 421558.751936342,5246456.57655645 421510.09362297,5246426.76467374 421491.873574267,5246399.07754727 421496.34096919,5246353.2654105 421516.309362567,5246327.64048607 421576.496443293,5246270.95303882 421616.746461364,5246242.39049484 421659.746948449,5246226.57782083 421715.435305397,5246213.20253434 421755.779319922,5246192.26492625 421808.372488355,5246135.70254511 421823.215606206,5246104.95270991 421832.77703582,5246064.20300146 421814.086858946,5245993.32876096 421792.834284135,5245927.57949187 421792.671749198,5245729.39374021 421797.327140677,5245698.89397675 421819.764106339,5245665.5816151 421855.170759483,5245652.33148713 421944.047787528,5245651.14338276 421984.517061154,5245637.95572049 422052.078932474,5245568.33087781 422083.297635789,5245543.83088341 422094.860118614,5245534.76838561 422231.393049078,5245487.20538154 422494.835058808,5245435.32906221 422527.553920511,5245414.57903166 422585.115589298,5245345.26678407 422604.927507429,5245311.95445981 422614.582703433,5245271.14227407 422606.017937438,5245205.26794313 422600.673425301,5245184.95566728 422595.548148442,5245179.95574776 422577.171372993,5245137.08126729 422561.639125466,5245116.89405706 422520.6059753,5245087.01960419 422496.489997244,5245048.03760108 422496.479184468,5245048.02012289 422489.416161383,5245036.64527414 422465.600875504,5244965.77108275 422451.848246604,5244892.39684717 422444.003756088,5244874.70956057 422443.659198623,5244849.27229659 422435.720794628,5244826.46005738 422429.843664227,5244763.08567718 422442.249562794,5244742.58578611 422477.625066146,5244732.02315724 422660.347730712,5244719.27210901 422743.942863871,5244700.39675247 422963.69518479,5244608.45872556 423072.791232932,5244599.39562315 423110.854537993,5244596.33291229 423143.604744552,5244578.08288079 423166.198307476,5244554.89546129 423245.539479632,5244411.58384623 423315.663827504,5244337.02163418 423388.726692196,5244292.83411446 423573.57349836,5244249.58340654 423702.951124235,5244211.9160219 423738.013431865,5244201.70787795 423803.889657037,5244190.5825884 423854.7032688,5244187.39481166 423905.611101011,5244199.39438211 423944.175441444,5244229.33134657 423957.145196942,5244251.95603977 423970.647234945,5244307.70539568 423968.961654285,5244371.32976515 423956.461831138,5244386.70468763 423959.21228526,5244399.32954351 423946.649802952,5244409.57951822 423946.869106871,5244427.39183766 423975.151799351,5244452.45390945 424018.528200691,5244464.57851692 424066.779324932,5244463.95322252 424112.279913318,5244448.01560082 424152.404835283,5244414.51569212 424167.153929631,5244373.64101704 424163.056649859,5244261.89218054 424195.368266019,5244208.08003203 424255.74343179,5244166.64258895 424356.681736983,5244114.45501461 424416.837842521,5244062.89268459 424421.524595356,5244034.83044647 424449.05641287,5244031.89281265 424519.086735325,5243982.76546948 424587.461809958,5243966.63786594 424650.273090999,5243910.07338602 424723.272104283,5243858.32094554 424773.928287044,5243842.44405399 424811.677647115,5243811.50533222 424927.488323561,5243721.18903625 424937.268631943,5243688.06396576 424954.736658528,5243659.93853504 424974.109535597,5243586.00097629 424975.857432102,5243517.43907775 424985.79453947,5243502.06382617 424998.231354667,5243476.56357253 425048.85636252,5243463.24915306 425127.701049451,5243472.43337074 425229.201617576,5243463.61684715 425303.545163236,5243437.11409532 425303.549402951,5243437.11258231 425317.732624008,5243432.05107015 425378.357317052,5243405.9238695 425403.270589048,5243382.7576384 425403.294305405,5243382.73558515 425406.013000479,5243380.23549935 425463.136866116,5243328.35868973 425462.480264155,5243317.17132501 425460.792492731,5243308.85897413 425455.948497517,5243302.23423474 425447.948330789,5243298.98459044 425433.698218927,5243299.17266596 425417.541907133,5243301.48579805 425397.916946351,5243307.98652995 425372.697715243,5243299.17513742 425355.634743497,5243288.48843276 425343.821153443,5243256.42672351 425345.507970825,5243233.92687414 425359.506696935,5243189.05174343 425375.537302995,5243163.98883738 425400.474334798,5243142.23803789 425418.38050765,5243134.98738237 425447.099902502,5243148.17358989 425447.288209402,5243174.17332972 425462.758500157,5243219.79725953 425479.946995741,5243247.3587953 425506.354472486,5243279.91990916 425551.353092976,5243223.41863382 425560.165621094,5243221.98079062 425563.165913152,5243230.60558541 425565.041097145,5243236.04295671 425567.791365844,5243243.98026831 425570.51055476,5243257.41752786 425573.260993946,5243270.85478616 425578.761759986,5243294.10433792 425588.762423759,5243312.85375104 425604.075602435,5243330.66545811 425621.201379501,5243351.16456581 425642.827135771,5243369.78850955 425669.796296844,5243375.84985863 425674.858885241,5243377.34963909 425674.934197452,5243377.3720909 425702.109362684,5243385.47345691 425719.078194943,5243383.59778787 425737.890648983,5243377.09708887 425740.010214788,5243376.08200283 425740.109384381,5243376.03450929 425761.078005389,5243366.28375434 425789.608818469,5243344.59530833 425809.233420225,5243326.53218786 425816.420044734,5243296.40718753 426022.641687027,5243334.64846594 426081.079571282,5243331.45862981 426093.704510585,5243326.14566952 426234.451831359,5243202.57865267 426287.545445784,5243184.13917769 426328.358659772,5243196.2624079 426417.171624064,5243187.63389151 426447.264740691,5243159.32044218 426501.824110273,5243044.3818262 426523.822067562,5242973.00661389 426573.256469659,5242860.56817836 426566.505935163,5242845.19359849 426561.84949313,5242840.25633441 426541.161697012,5242836.19471257 426506.16099743,5242822.94625908 426475.597836297,5242809.76012506 426445.065699758,5242789.32405904 426410.783342017,5242762.76320388 426390.126228305,5242740.45175531 426380.937483647,5242702.88998672 426397.812090207,5242685.82696422 426417.436826176,5242672.20129717 426441.593045662,5242664.88788584 426469.34307169,5242658.44932016 426505.249829028,5242665.32279647 426546.53168879,5242674.07103677 426594.938630275,5242683.56898076 426637.970333149,5242686.81720254 426676.283491168,5242697.87804186 426692.813726213,5242661.00272043 426732.687135307,5242599.56418343 426767.090643263,5242502.68870327 426766.370063986,5242444.2517858 426737.743017776,5242386.12849988 426704.430449989,5242392.62979268 426685.680638845,5242403.56795129 426673.243710305,5242425.13075245 426662.68210293,5242456.5058842 426653.807730458,5242478.94353205 426640.558491852,5242506.81880599 426626.277661489,5242524.00672317 426603.058893881,5242529.50761442 426567.932890937,5242506.50926029 426552.525403249,5242470.82272563 426532.586656173,5242436.01136702 426531.554476479,5242406.44919003 426532.209783214,5242376.01195274 426541.959052007,5242350.01180343 426559.70846546,5242326.57380431 426578.426722354,5242305.88573951 426698.018928816,5242225.31913873 426758.705564592,5242181.87958072 426801.611539326,5242161.94052329 426821.54958683,5242174.31459496 426838.704463395,5242125.87685449 426893.765245675,5242056.62526697 426931.421250946,5242039.06139951 426931.434142717,5242039.0553835 426972.139735793,5242020.05992068 427007.608597992,5242014.49602885 427033.328422654,5242042.24472045 427115.299629895,5242099.67834344 427169.14506588,5242139.6757763 427217.614665312,5242154.2986667 427247.770431821,5242131.04765762 427239.581279795,5242080.36096614 427190.422425647,5242009.80112922 427177.202226058,5241966.86457046 427219.669392251,5241905.30091825 427490.136874861,5241795.35342681 427512.448034294,5241746.85296971 427507.760063851,5241733.04078954 427507.759671562,5241733.03963564 427501.853222022,5241715.66619228 427483.663894005,5241661.97993435 427478.163338843,5241645.66781074 427480.631867742,5241637.98028176 427482.693269968,5241602.41802925 427563.09782598,5241527.85294411 427643.815676353,5241478.60010886 427747.346199541,5241429.09634358 427792.783324321,5241405.59470699 427815.658418391,5241402.78129942 427818.878061245,5241430.4059122 427805.691923493,5241477.15601728 427810.349081718,5241504.90557021 427823.006131273,5241527.15484779 427853.632211953,5241553.77835203 427875.100874598,5241545.52755272 427894.693937325,5241518.65200213 427931.098640841,5241460.15105773 427984.095254346,5241338.90001456 427967.063393539,5241323.77584948 427909.719454053,5241332.27811207 427881.9693509,5241336.02921031 427856.87540505,5241336.15523362 427837.531114493,5241323.8436373 427806.623272624,5241280.97029621 427798.40278573,5241227.72112499 427827.806545662,5241140.97072671 427912.239736362,5240982.4687407 427931.769059366,5240916.2185537 427967.487252672,5240889.52983904 427995.612847748,5240901.4035792 428012.488644879,5240922.52769432 428031.333942422,5240967.02651368 428039.459680497,5240988.46348396 428060.336104983,5241028.52476154 428081.80502093,5241028.39888512 428118.523800084,5241020.08496068 428120.147969765,5240993.27264091 428118.209497271,5240962.83550012 428113.489469795,5240923.39855585 428097.081744029,5240880.5871207 428092.424386219,5240846.52512457 428097.704233305,5240800.58783112 428125.672611899,5240781.77435971 428184.549253219,5240819.20910681 428236.333450341,5240899.89374799 428269.99163211,5240952.82938605 428343.930485838,5240977.26363916 428504.0568526,5240980.44456402 428567.432091882,5240972.12954915 428655.649986489,5240922.87639123 428655.651697681,5240922.87543563 428688.555916929,5240904.50021297 428723.554659362,5240855.87422389 428712.615154558,5240795.0627241 428673.236494842,5240688.87780087 428690.485102474,5240640.44003526 428675.358599653,5240596.56605342 428657.107577197,5240568.69205421 428651.169687618,5240557.81739627 428651.160664338,5240557.80093873 428644.41924635,5240545.5052847 428623.668155315,5240516.0689024 428613.667428521,5240495.50699915 428602.760277172,5240469.63268145 428613.352949152,5240432.82008249 428632.946483765,5240421.13188599 428649.461729364,5240419.69512131 428649.477817678,5240419.69372169 428667.009157433,5240418.19301698 428693.853194224,5240420.6293949 428727.072282869,5240423.12801109 428760.134723848,5240413.06424771 428787.790365439,5240386.93835144 428783.227121532,5240364.50124191 428769.601255609,5240340.43951859 428717.066414307,5240239.63008705 428715.566183702,5240232.69271154 428715.562033437,5240232.67315401 428711.534302746,5240213.69304935 428720.252020059,5240178.81800834 428733.65803114,5240167.94255714 428756.001637324,5240157.87923191 428873.314854283,5240151.68697586 428889.533813333,5240154.31128684 428904.003803169,5240189.99787059 428890.004641763,5240219.99817334 428889.997553997,5240220.01339022 428826.133473843,5240357.12455032 428814.633920726,5240374.12486755 428813.85340258,5240397.49968768 428821.166689827,5240420.62417844 428821.323734269,5240445.7489443 428808.824202717,5240463.68679377 428797.262182377,5240481.74960362 428790.294168904,5240506.81216173 428785.919902026,5240531.12462036 428788.764605456,5240560.62423626 428799.297372305,5240606.06089284 428829.922839666,5240613.24707387 428910.766150719,5240579.24407202 428965.98346615,5240520.11734574 428995.512532296,5240443.67932694 429018.412369999,5240235.11777138 429017.568253364,5240210.75486928 429017.567843021,5240210.74302597 429015.033679321,5240119.18145608 429002.40693177,5240066.99494499 428980.186843911,5240030.12118959 428963.061005979,5240007.80959388 428932.498020183,5239999.93591942 428898.466516229,5240000.24981342 428866.279027279,5240008.50105994 428839.403909706,5240011.37713698 428812.528794088,5240014.31571345 428782.903146086,5240001.06704946 428772.027527097,5239984.13014935 428769.183050688,5239961.81796831 428787.93256643,5239941.87987918 428810.213418579,5239923.81662794 428852.213254071,5239908.31504367 428880.806625119,5239889.31404135 428918.306174644,5239865.87521318 428946.02464913,5239850.37421478 428963.89966876,5239846.62351449 428988.087549267,5239852.74746581 429009.619129659,5239857.93403474 429038.338239975,5239862.30781587 429067.869285496,5239848.61922639 429082.02488005,5239824.43136283 429092.711921048,5239807.30607803 429113.149653999,5239809.68021716 429135.868729714,5239814.42924124 429155.213141218,5239830.61580114 429176.40206056,5239870.30207417 429189.090447692,5239895.23882903 429205.278721611,5239915.73798017 429226.029556688,5239937.04943682 429239.561334774,5239950.42376122 429270.093125982,5239960.04742155 429289.812022869,5239959.85911383 429307.655739024,5239954.42093016 429318.185960559,5239919.35831226 429314.497440658,5239888.04624441 429303.496283107,5239854.17199984 429285.463961808,5239824.73550436 429268.244174647,5239796.17396783 429242.961629583,5239761.42531821 429218.554036165,5239724.92664865 429205.80275119,5239687.42750933 429203.801659862,5239653.42789686 429212.644708541,5239629.11525166 429206.300160118,5239605.42822512 429226.456074569,5239589.9275356 429297.330867545,5239566.17483461 429355.800126289,5239568.04741385 429449.738312711,5239566.91856172 429472.050756455,5239559.73020856 429482.644478939,5239556.2923037 429481.519022639,5239542.16747608 429471.924252162,5239512.29313736 429456.391765878,5239477.04409093 429452.578216649,5239444.85703525 429472.26552096,5239433.91882306 429509.015824461,5239434.60480516 429569.953948181,5239439.53975444 429635.392277044,5239449.84947094 429658.767480121,5239450.59850281 429675.018451436,5239477.28509707 429662.644383491,5239509.66031799 429649.36371348,5239531.1606728 429620.0211097,5239574.41149419 429603.958999517,5239590.59951032 429584.990912165,5239616.10006281 429646.367570047,5239653.47220739 429723.150912821,5239700.78113141 429768.932656751,5239705.216711 429778.495361437,5239709.34128149 429789.339649382,5239723.65320889 429792.15282376,5239744.21541078 429789.622492541,5239773.77775224 429782.623291445,5239800.65280105 429772.061991163,5239841.02787613 429769.625608838,5239876.840158 429775.970203341,5239901.90217487 429794.971026962,5239923.2137056 429812.908888172,5239930.21290716 429842.471412956,5239923.77425089 429913.096007612,5239893.77161789 429931.814444053,5239879.33347736 429933.407380568,5239853.33364222 429929.562292602,5239812.14666484 429918.340670766,5239724.46040224 429912.65153681,5239674.39857929 429902.931945658,5239650.27419233 429935.180327918,5239591.52338711 429973.148951156,5239578.33444311 430011.399714245,5239593.08274051 430068.747601033,5239709.32935724 430104.749154568,5239749.45252428 430125.281040108,5239764.45154868 430178.781839177,5239776.57424458 430204.094282369,5239768.63577498 430251.805343489,5239709.89195168 430251.81153196,5239709.88433218 430279.123172799,5239676.25850589 430295.933210702,5239594.8210309 430272.30593641,5239529.07257987 430247.085395536,5239478.88655797 430247.065130004,5239478.84626715 430220.2709934,5239425.57562951 430224.142785711,5239323.82636509 430242.452446773,5239254.0166138 430242.453204368,5239254.01372529 430243.515585201,5239250.01371672 430307.918014048,5239114.51225511 430345.917967379,5239103.94828284 430509.421577742,5239178.12840114 430513.204927995,5239243.12767728 430514.268204909,5239267.25242264 430514.394006515,5239292.37719784 430518.11363941,5239319.18931041 430527.302092121,5239346.87619038 430541.708992321,5239363.81294971 430556.115635628,5239372.68727956 430581.209769303,5239378.68619498 430607.990648845,5239360.62275108 430628.458752676,5239335.43462885 430622.769726485,5239288.93526851 430624.330668107,5239239.68563383 430636.704479254,5239199.43547551 430720.392427261,5239193.432083 430735.205178018,5239197.74393575 430737.955512096,5239207.55623717 430732.612233708,5239223.61881733 430731.019275082,5239248.80616369 430733.051910451,5239291.74320637 430736.803137519,5239329.30522511 430745.897585315,5239348.99217966 430767.55470928,5239371.1785958 430790.96164739,5239387.11499449 430825.962364775,5239401.17593282 430850.11868049,5239397.42497198 430867.087071903,5239382.11190711 430872.336367945,5239358.79939359 430863.116264319,5239318.61262171 430848.520746561,5239266.73867259 430829.331130686,5239205.05249797 430804.860599863,5239155.11643903 430805.640128327,5239100.99187713 430827.261959432,5238996.55439349 430856.19553098,5238866.61682865 430881.163245,5238828.24113217 430888.412483633,5238802.67855485 430994.004072172,5238709.98750294 431080.160372442,5238691.17161198 431098.035827311,5238701.17078844 431134.099803186,5238738.79397669 431158.165643339,5238837.54213327 431184.762837348,5238938.91516358 431198.76634806,5239045.35116963 431206.924039531,5239088.47546214 431250.675982808,5239138.78572757 431322.302881923,5239181.03241588 431508.086377232,5239206.77454937 431586.649121875,5239195.64641174 431674.77256393,5239126.01837977 431707.302910094,5239090.07984728 431773.397136633,5239089.20213385 431853.899430004,5239141.51087506 431858.115192378,5239144.50846021 431858.118308525,5239144.51067592 431925.122044907,5239244.9445654 431971.123111785,5239267.19248425 432081.75283505,5239387.8119124 432115.536372922,5239450.93498927 432187.66442913,5239528.7438672 432231.541792749,5239591.74153242 432285.105257091,5239608.86418795 432358.950122511,5239625.79851256 432384.544386038,5239635.60987891 432476.327458173,5239670.16831957 432519.985170762,5239705.10373376 432538.581183597,5239770.91491781 432537.272025559,5239875.03909702 432499.655637394,5239998.33592644 432499.650701986,5239998.35210343 432485.933293273,5240043.35228728 432456.843008563,5240158.10251364 432462.751426357,5240224.03921639 432545.035988315,5240306.91014946 432665.978644202,5240437.52910212 432735.951760437,5240555.96274664 432772.830394313,5240659.7103696 432783.582195138,5240712.95948416 432773.80185245,5240743.52212786 432747.430744904,5240870.83463821 432740.150425606,5240901.5221782 432700.809895495,5241011.21036396 432702.282582003,5241133.0842805 432683.129292311,5241229.77174948 432679.978172552,5241389.89553201 432684.355048866,5241447.08237286 432698.621560686,5241638.26320182 432701.112413624,5241671.64230216 432733.116586203,5241793.20247775 432766.649482272,5241835.88825501 432817.431125492,5241835.32369436 432893.211893738,5241801.32089719 432930.86720768,5241762.81968784 432937.74013186,5241696.69496167 432934.895621542,5241673.82026886 432975.618981181,5241634.19734614 433035.299531864,5241576.12949839 433065.831015856,5241575.75325846 433090.548317766,5241524.69017794 433082.516327646,5241503.75317963 433088.703155593,5241481.37811423 433077.638806391,5241426.81651988 433064.85609881,5241384.81739093 433052.948370177,5241341.94323378 433035.759609423,5241307.13172477 433023.008469064,5241274.94501313 433002.100439071,5241224.94628289 432984.848976842,5241183.8848292 432973.004039787,5241150.01059518 432948.533713887,5241107.199451 432929.689295617,5241091.13785405 432912.595155358,5241083.26361733 432892.157383533,5241079.88947947 432886.280046016,5241008.82781364 432878.592327649,5241003.95316819 432908.873317092,5240988.38956232 432990.186678174,5240995.01118797 433125.470673771,5241046.69273617 433202.41072646,5241106.75159756 433240.598761453,5241113.87498056 433276.00495307,5241103.3111239 433306.191943067,5241080.06008524 433315.721542831,5241026.62263938 433279.719955761,5240986.37444233 433233.624954605,5240959.00155092 433215.624161483,5240938.87745283 433207.497706383,5240895.8156422 433217.403375183,5240875.37790742 433237.433954787,5240849.68980265 433270.152296439,5240829.00113802 433473.153172742,5240806.24303517 433486.926229535,5240806.70438945 433640.87343626,5240811.86113884 433657.21633902,5240781.67321963 433662.496730744,5240753.86073263 433659.526597813,5240711.86119926 433670.150897073,5240687.61096449 433717.651350201,5240689.98400406 433749.152401172,5240714.73251384 433767.184370929,5240732.54413103 433770.87227664,5240744.16888502 433780.873280974,5240772.73074225 433783.030159372,5240791.60549936 433787.468880752,5240828.23001772 433788.595162866,5240867.54214931 433788.689670627,5240890.91695373 433777.253065306,5240921.3546709 433773.879200159,5240957.22951423 433771.317637024,5240986.79187616 433771.694554536,5241045.91637549 433768.320658869,5241080.85372631 433776.540284025,5241105.8531858 433789.260495716,5241147.85232229 433806.417399061,5241163.78899188 433828.855250641,5241169.10053339 433860.011363253,5241157.16186084 433886.292540027,5241148.41086085 433896.979315517,5241123.41062978 433903.134598141,5241092.03563562 433935.976173921,5241016.84741113 433945.630440891,5240953.28503696 433961.503825146,5240899.53482843 433965.7832798,5240843.09761488 433974.594196579,5240792.0976717 433976.03087931,5240766.53532179 433977.09276369,5240747.28543562 433970.685162101,5240707.16102505 433971.496766906,5240679.348719 433983.996025023,5240653.41092003 434015.214438556,5240635.40979117 434043.902248747,5240637.97109793 434075.277785002,5240646.84474346 434112.09118276,5240665.53058703 434148.905043138,5240698.46631491 434180.906698373,5240741.65215643 434195.719971089,5240761.8388873 434211.971868986,5240816.3377807 434220.19193392,5240854.83713223 434222.067557409,5240873.5869033 434241.006222484,5240904.83587636 434252.881785709,5240919.27277439 434298.412807851,5240901.0835637 434323.380344057,5240857.58289734 434388.252207605,5240745.14365928 434428.563939087,5240711.64228378 434598.533568062,5240697.19795746 434621.345994915,5240689.38458853 434636.37661395,5240666.32166018 434641.000410428,5240628.19677809 434630.687253396,5240610.50984184 434559.24830167,5240583.26298071 434541.028096777,5240542.95155038 434553.558695938,5240519.88872408 434596.589940439,5240509.26205056 434795.029932381,5240537.62871093 434833.123973468,5240537.31465642 434839.40907487,5240654.06346419 434822.474092101,5240735.50100316 434765.007717438,5240822.50265152 434684.164755862,5240866.50559792 434494.102128314,5240909.13801159 434456.290411626,5240942.5142849 434404.325310105,5241067.57789284 434372.140203973,5241149.20354399 434372.51627875,5241182.20326118 434387.891974371,5241199.82749155 434517.549547792,5241208.57213582 434540.330645197,5241198.25879058 434583.205149595,5241172.44475129 434661.54834205,5241136.0043512 434841.078404615,5241055.37267875 434894.046485081,5241021.80828753 434932.171858896,5241023.93171551 434955.423032129,5241054.24302467 434951.238314312,5241140.68000359 434936.333023844,5241173.805346 434822.677966645,5241238.43445985 434759.459640864,5241267.06180588 434752.085328024,5241289.99942189 434821.055931976,5241329.93379125 434958.401236139,5241343.74058618 434981.182331396,5241333.36474135 435027.739890408,5241170.2391488 435049.674745139,5241083.67644605 435074.406137693,5241052.36388019 435102.297994234,5241017.04983175 435147.797597646,5240993.73566177 435208.672816838,5240985.54574391 435297.673829562,5240994.79204024 435348.580798414,5241004.3523881 435427.237401503,5240995.911747 435459.73607311,5240947.28580622 435461.577682184,5240881.2862531 435417.605940684,5240800.4136875 435360.978188456,5240729.91655763 435335.070249373,5240684.48047569 435308.879979266,5240605.98216783 435318.252560504,5240529.60739034 435327.970144866,5240491.54479481 435357.874794744,5240435.29401785 435416.061988824,5240411.85432427 435672.595260259,5240411.71883674 435733.783971351,5240433.96616044 435754.472706267,5240466.71505769 435761.322074096,5240636.77594295 435792.229890398,5240677.14936381 435830.700095411,5240712.27251749 435848.575562725,5240722.20920977 435868.482063045,5240725.02087502 435932.514118905,5240734.08068995 435986.07760781,5240751.265869 436077.421720139,5240740.1372271 436110.045804047,5240704.26117487 436119.763381843,5240666.13607507 436098.322137513,5240557.07530029 436002.126920508,5240344.76838717 435919.183471615,5240183.08554247 435900.430334234,5240091.77452353 435909.802908791,5240015.462236 435932.364580498,5239984.77405167 435998.239740005,5239973.89643851 436130.522482608,5239987.82841245 436216.866962218,5239989.44986387 436282.491116767,5239948.00999744 436310.13607359,5239900.15144092 436310.146012239,5239900.13423528 436314.927028895,5239891.88410326 436308.422644324,5239759.82289152 436261.512212425,5239643.51321499 436337.10443938,5239579.19811188 436537.229423017,5239531.37777043 436583.230599633,5239556.31319154 436624.984416431,5239662.56066302 436663.862125178,5239735.74600741 436681.68475947,5239744.44308314 436776.177303905,5239790.55348417 436842.271794076,5239797.36322366 436867.584065984,5239784.42478527 437085.521855142,5239741.54118056 437125.676814098,5239692.85240449 437094.298736023,5239606.85434395 437073.264902961,5239533.41826443 437080.231693169,5239472.29344289 437110.481250245,5239451.72985777 437186.731983737,5239456.03919625 437365.047397084,5239502.40652987 437425.860012499,5239491.5916167 437468.57765199,5239447.9026931 437475.544444263,5239386.96536572 437482.542480397,5239325.84053824 437522.697435373,5239277.21425514 437560.666045375,5239264.08779469 437580.197312131,5239260.02452319 437610.416718976,5239272.83568628 437621.292480367,5239293.33508607 437622.324774962,5239324.70980852 437611.700991516,5239364.02244985 437455.494870464,5239783.27570405 437443.215267497,5239836.08830908 437445.123244434,5239887.96283987 437450.342641733,5239906.3374876 437450.347889116,5239906.35599495 437456.030848428,5239926.39960345 437474.062978259,5239948.7736965 437517.063781731,5239962.89682964 437555.595300937,5239961.89525972 437583.282601181,5239949.26922112 437606.500821088,5239927.70593253 437619.248859425,5239909.45763575 437619.250318217,5239909.45554755 437629.656158395,5239894.58023312 437675.998165075,5239830.82881344 437696.497377478,5239802.14068875 437705.340308494,5239775.26552782 437708.870553345,5239744.01561725 437710.494056127,5239698.32839287 437698.585230546,5239623.20444359 437674.799156616,5239482.83147037 437670.984439789,5239416.6446226 437662.669450621,5239343.27051337 437654.4491004,5239296.77119908 437657.073587843,5239280.64621209 437658.728630001,5239243.70892073 437677.291149487,5239239.95818656 437712.13297461,5239173.58225214 437731.097668167,5239046.45742307 437755.845748605,5238982.64438241 437793.156087948,5238908.64340053 437843.718200552,5238885.20399595 437965.750597553,5238891.5739302 438004.252138613,5238929.19706778 438040.724101232,5239017.75741157 438090.134415949,5239129.0045567 438136.668534147,5239204.75208445 438170.013539817,5239234.87549231 438163.046756841,5239295.87532698 438115.204168358,5239342.12694817 438100.831669138,5239421.00195332 438131.488734614,5239438.43806637 438184.801629892,5239437.87338346 438214.676698245,5239432.93469441 438283.739359472,5239421.61944476 438296.994445698,5239415.5557913 438329.239022643,5239400.80523163 438437.298788852,5239293.11409011 438452.047293976,5239244.61384118 438433.482131179,5239168.67766156 438514.481798405,5239139.79954699 438549.480454447,5239091.17346592 438673.252324028,5238780.04565372 438695.782471667,5238741.67000697 438751.657965869,5238743.66769376 438784.783713906,5238758.54122276 438833.692179504,5238813.91380826 438839.538503137,5238889.9755147 438810.699777323,5239047.78805148 438786.735412326,5239185.28803407 438767.175213891,5239259.10079892 438724.332162124,5239290.10233117 438564.958089619,5239355.233395 438519.928529332,5239416.67229178 438429.524979497,5239519.23774584 438377.589883729,5239603.92675149 438374.590019929,5239608.73933899 438357.561167422,5239685.05197432 438373.187377406,5239717.8635921 438429.344976154,5239745.29858925 438556.440012263,5239754.10581809 438815.34760613,5239733.59536249 438891.316162765,5239709.90492309 438926.220649085,5239648.65393875 438914.559412155,5239501.40548772 438908.525245354,5239415.09386287 438940.741618406,5239336.0931154 438988.835302735,5239322.90373775 439062.711437133,5239339.77558419 439129.589808234,5239425.45972052 439210.252749671,5239607.58009717 439292.22414004,5239667.638805 439376.382288985,5239704.88508916 439465.414627068,5239716.63135797 439513.664902466,5239713.56690371 439536.414736543,5239703.25354585 439593.755440673,5239598.50194687 439638.878740756,5239537.00053739 439674.25358268,5239523.99918029 439705.004656862,5239548.99774147 439830.69699692,5239664.55426803 439885.716561564,5239709.61218704 439956.232664447,5239767.3608965 440088.641011908,5239799.04275131 440139.359885916,5239790.85323295 440189.984756065,5239775.10127166 440487.856115501,5239596.71532639 440538.700415786,5239601.27571161 440577.107973763,5239631.33642834 440610.985784719,5239707.27201084 440651.956115299,5239744.83257141 440690.175582139,5239757.26842014 440718.23854545,5239764.51722091 440761.301026818,5239753.89053208 440824.519400125,5239727.88812473 440924.013321674,5239523.63546545 440986.260127313,5239414.07117183 441003.852972908,5239383.07066466 441036.633871203,5239365.00694531 441173.979066398,5239376.18873734 441291.04337579,5239402.8712553 441354.794450956,5239420.05602454 441392.825726046,5239411.99202088 441440.731307861,5239381.05276855 441491.136818155,5239347.42593154 441493.574229786,5239344.23835334 441493.587389503,5239344.22123925 441508.761182833,5239324.48786526 441518.510056681,5239288.8002086 441571.289899878,5239234.86091105 441581.226790564,5239214.48564198 441585.913042356,5239176.36070888 441579.036780257,5239140.48623483 441575.129828213,5239120.54903067 441546.345628468,5239039.61326235 441530.123504235,5238943.17708428 441511.37028775,5238851.99097485 441507.710331387,5238742.80436791 441501.707377636,5238656.49270168 441493.549271239,5238603.24339929 441476.33205697,5238583.62189494 441476.329728245,5238583.61924102 441458.985180196,5238563.87008886 441429.29631842,5238530.18403958 441396.076642976,5238510.24804221 441332.701606564,5238523.56305899 441281.202243367,5238554.18996856 441206.484416552,5238598.63023806 441057.298043148,5238666.13591042 440786.235695324,5238732.58409754 440656.829091591,5238751.65178565 440587.983901285,5238724.46730539 440544.325799127,5238679.21941592 440515.761043529,5238618.47101433 440479.508738079,5238557.97292788 440452.754029706,5238423.59996689 440496.125317121,5238302.80786469 440509.530410747,5238265.47373108 440546.684033701,5238178.72280403 440535.775152283,5238102.72378253 440465.895558396,5237981.47750861 440440.175602292,5237951.29128005 440424.893899722,5237941.22948069 440345.171513987,5237850.67090272 440336.919410036,5237789.73416911 440356.949868082,5237761.60853853 440384.69947114,5237743.54501877 440476.137710158,5237745.10373216 440613.796650775,5237794.47270553 440687.672693014,5237808.96955544 440763.735481931,5237800.52897406 440788.89097666,5237772.40312995 440810.292601431,5237629.9032299 440819.633772036,5237551.02838808 440871.316520024,5237398.08980561 440940.623532631,5237219.46316716 440970.183512161,5237137.96250331 441047.899395154,5237035.58498744 441135.08212044,5236874.51997715 441192.234670401,5236752.08094346 441214.451439632,5236688.39295611 441221.574781394,5236665.73814057 441285.788072267,5236461.51653938 441289.722091617,5236357.32958354 441261.282853973,5236311.89357319 441220.343959355,5236279.33299498 441062.560589792,5236250.46474664 440986.215969461,5236241.09298271 440924.933185458,5236208.72075081 440741.335777967,5236139.54135676 440715.647163772,5236111.91761485 440723.209458194,5236104.16735379 440672.333934418,5236099.54450094 440641.018489675,5236018.6088612 440630.172535218,5235955.29724899 440644.732999327,5235891.54708265 440669.669049976,5235843.04637898 440644.043191708,5235822.98508389 440658.729086492,5235772.04732342 440662.725529522,5235665.29789207 440623.283412227,5235536.2379243 440584.280417695,5235455.3651075 440575.495354601,5235343.67874378 440625.116849115,5235228.80246467 440702.425348697,5235093.42516809 440714.658382803,5235063.58900382 440714.674431357,5235063.54986167 440722.298861412,5235044.98717064 440724.516683928,5235016.92477053 440706.359116846,5234981.55077171 440642.85860784,5234979.74093689 440546.702907181,5235016.30720196 440484.297972655,5235068.62194755 440484.263266197,5235068.65108297 440405.67463157,5235134.62477446 440365.300209635,5235160.37628181 440324.957127734,5235188.81526885 440284.519951066,5235207.00433058 440208.237848106,5235197.69507939 440159.517234211,5235152.38492862 440161.735149471,5235127.01001267 440187.014841593,5235075.19681752 440187.022127705,5235075.18185581 440213.981925731,5235019.82107614 440306.697122824,5234894.38057269 440379.632892236,5234827.50298701 440470.412787053,5234768.12460166 440533.631107711,5234742.12213731 440571.442747795,5234708.6207866 440680.035343596,5234651.61663597 440747.75181527,5234569.73936387 440772.531006692,5234503.36378106 440718.215156819,5234414.99165994 440669.494548843,5234369.8065099 440572.962490945,5234365.74808085 440395.368248681,5234387.88036666 440258.148422701,5234384.26113899 440207.21024784,5234374.70083887 440158.583734338,5234339.64061923 440122.29985871,5234268.8301315 440119.173049981,5234215.51813306 440090.670904486,5234157.39473195 440074.138911785,5234138.6455555 440057.231910311,5234119.70889619 440001.262363279,5234107.46132857 439930.450422999,5234138.77657961 439849.71068062,5234198.21055297 439849.701854857,5234198.21704977 439695.985829721,5234311.47269851 439632.391316819,5234301.85043114 439591.201679903,5234246.4775473 439577.667707645,5234167.85366846 439576.006009139,5234005.22988334 439578.035745568,5233959.54261979 439546.751743926,5233883.66946714 439535.469896253,5233868.1075504 439520.969136584,5233848.35829837 439369.61973713,5233710.30312965 439200.363211198,5233549.43638284 439160.610433611,5233474.3135878 439153.066707842,5233460.85403865 439083.792839363,5233337.25529365 439056.164919099,5233255.31953942 439041.192180802,5233161.75846476 439086.493357043,5232881.88395102 439135.611899983,5232718.75830086 439126.637497383,5232584.25982799 439087.351361412,5232472.88740837 438992.001659106,5232344.39243787 438968.875465424,5232319.20610378 438833.747659715,5232272.33706153 438805.809995006,5232272.65070901 438735.186365234,5232316.59075578 438697.218125769,5232334.77967178 438581.50288598,5232437.59611368 438548.597067155,5232453.1598485 438515.283108483,5232423.03646631 438507.281591136,5232387.53708028 438580.865386734,5232135.2860753 438638.801335452,5232088.97157379 438762.643389194,5232029.27948903 438818.142025621,5231988.0275591 438848.360110935,5231967.46399434 438875.325116093,5231873.15117868 438873.841266481,5231851.6369036 438873.355169078,5231844.58899715 438869.352748842,5231786.83964154 438848.694907786,5231751.52827589 438696.03694936,5231732.78463683 438675.661519899,5231725.4105251 438647.284570385,5231682.47452698 438638.686987563,5231591.1006173 438672.64951322,5231435.78800661 438720.084119182,5231359.09922028 438780.864757263,5231335.65946491 438821.396122206,5231332.65785774 438913.022363814,5231349.52902715 438978.929458025,5231360.46378004 438984.304531395,5231361.46355502 439114.338608571,5231410.89539182 439185.652136542,5231425.39238962 439248.117312359,5231330.70319233 439257.990989991,5231297.57808319 439275.145003773,5231241.51538211 439297.016099857,5231144.82784887 439305.697711813,5231002.4537472 439260.376607367,5230802.33230114 439216.184637924,5230701.0849359 439225.713398765,5230640.08508735 439245.430025552,5230586.52227234 439441.359505498,5230368.57895915 439466.16989883,5230314.95346074 439468.261750086,5230269.2662857 439438.739566986,5230181.57815323 439434.132329078,5230167.89352542 439425.225553461,5230156.4564756 439408.443325912,5230135.20732065 439382.095837913,5230049.08411184 439406.905915137,5229987.95868446 439500.059319369,5229908.20576649 439625.679705032,5229782.38951951 439670.833827792,5229726.07578102 439678.427328598,5229719.20054957 439731.769341654,5229671.26142325 439731.775551865,5229671.25583629 439776.580378828,5229630.94756117 439951.674516426,5229618.94090755 440225.015363138,5229517.11882869 440336.264049925,5229472.73997381 440452.637757724,5229428.36093118 440523.417927887,5229394.48354551 440543.510915306,5229374.10797608 440619.008348185,5229304.66827219 440653.786417605,5229225.60523348 440688.250898201,5229120.97996977 440778.277048724,5228990.60286 440792.899522296,5228929.47792629 440774.490707801,5228871.16671833 440704.798275231,5228762.73295662 440707.0783475,5228734.73315326 440724.577452884,5228711.73272466 440938.07878393,5228719.59957889 440982.609893299,5228711.41048132 441011.578557547,5228706.22194098 441128.485624857,5228712.59245844 441166.705078667,5228724.90338483 441182.331551983,5228757.71494788 441137.30314561,5228829.34089773 441125.337268149,5228898.02812966 441121.404298563,5229004.71465878 441157.626134058,5229072.96256135 441216.34623029,5229097.83505936 441307.815379263,5229096.76908142 441335.408165425,5229071.08080381 441362.309971006,5228964.08092637 441369.464518175,5228923.45609055 441377.339160205,5228914.20589085 441375.884759661,5228519.21018982 441365.863750525,5227298.78616829 441362.816500156,5226925.22778895 441353.32899797,5226487.98282069 441334.385239866,5225613.43036079 441330.001586979,5225411.68267304 441327.747107756,5225307.24636884 441305.316984763,5224021.76087509 441299.678154161,5223699.26450647 441286.810453585,5222411.9036632 441283.609245141,5222092.28217366 441270.835642402,5220813.67119782 441267.540172935,5220482.29982725 441265.859079109,5219175.40754827 441265.471236449,5218876.31699548 441267.821811269,5217580.29948915 441268.401594674,5217255.3341868 441258.191667242,5216733.34001911 441237.333320755,5215666.35190995 441227.842303915,5215148.2014038 441208.265160845,5214080.36946304 441195.274251281,5213564.59398568 441168.196807764,5212489.38722958 441156.02005255,5212012.08004007 441127.127687256,5210880.40508843 441117.388581936,5210406.78527438 441094.058619425,5209273.42265027 441092.101754418,5208823.73991009 441086.988839287,5207653.43979129 441092.937830809,5207196.00699117 441107.919134768,5206040.4563889 441099.180074391,5205568.61773998 441076.86011304,5204365.48110994 441068.033916685,5203923.5198378 441044.810329775,5202759.50826854 441038.390380076,5202318.23443591 441022.763161913,5201240.53378684 441015.248841091,5200779.38528998 440996.713401008,5199638.56070505 440997.788580086,5199042.66427922 440999.66263242,5198009.587543 440997.677376318,5197479.59631226 440993.611925358,5196381.61446136 440987.346268008,5195878.46659537 440973.561784197,5194770.64128997 440965.045984715,5194262.9622736 440946.511668596,5193160.66818059 440937.027880396,5192677.64501441 440915.462465655,5191580.69461056 440913.290734644,5191084.45276957 440908.411922532,5189960.72122732 440898.739585907,5189444.7298283 440878.361997923,5188359.74790141 440868.844368726,5187794.75728581 440851.311907451,5186754.77454703 440840.168994679,5186181.03408972 440820.262004985,5185156.80111335 440808.556140411,5184569.02963089 440788.211689919,5183546.82785545 440447.274474624,5183551.58421118 439133.213072692,5183569.8587156 437519.214606452,5183597.88873491 435909.216377732,5183632.91857415 434321.217792016,5183656.94819719 432729.219448619,5183687.97779001 431126.220916499,5183713.00771019 429532.222317095,5183736.03751201 427926.224039936,5183768.06739585 426250.225657675,5183796.09869613 424640.227328401,5183826.1287231 423021.215323013,5183838.14759326 421418.182848745,5183803.15020699 419845.153118906,5183829.1516743 418239.122759583,5183856.15320425 416630.092083367,5183876.15490039 415034.06331545,5183946.15575987 413468.035170976,5184019.156598 411927.0077774,5184102.15730687 410320.977603268,5184140.15890349 408731.947575327,5184173.16060055 407127.917199638,5184205.16237558 405509.88661979,5184240.16416644 403893.850467498,5184279.17067505 402376.809351054,5184305.18266293 400767.765827735,5184336.19538155 399155.722151603,5184365.20819777 397568.67961072,5184411.22069788 397484.635123672,5182839.23587902 397438.590081989,5181207.25121208 397410.545932918,5179591.26622548 397351.500174909,5177964.28589945 397292.452470757,5176353.32576343 397156.403121981,5174745.3656852 397136.356979965,5173154.40478628 397080.309523306,5171545.44435402 397070.262855338,5169930.48393691 397074.216493664,5168318.52340502 397059.169441951,5166697.56308368 397026.153268514,5165076.32148286 397524.818123527,5165067.79049237 398121.172223473,5165059.66575611 398079.094836043,5163519.64134919 398074.045935741,5161865.68223921 398059.997632782,5160238.72242226 398075.949416946,5158601.76287673 398049.901485214,5156996.80243326 398044.852873508,5155360.84277007 398061.802940095,5153673.8844116 397990.753525199,5152039.92440306 397986.706260507,5150439.96320876 397981.694931268,5148843.95455868 397971.683228179,5147199.94555985 397972.671962545,5145598.93676736 397962.660579673,5143995.92785993 397947.649143106,5142391.91887313 397932.637595763,5140770.90973277 397907.625956819,5139153.90054444 397871.614199177,5137540.89132351 397847.602616648,5135930.88208476 397841.591240943,5134313.87274973 397844.579951222,5132687.86328606 397831.568827347,5131116.8540907 397799.55716051,5129508.84465574 397772.545330568,5127866.83496574 397769.602433453,5127095.8616232 397766.539781408,5127081.11154329 397761.664540702,5127057.83016732 397741.664049093,5127033.83007812 397721.601028402,5127005.82996553 397703.850524161,5126974.8298291 397690.850103905,5126944.82968593 397670.912112201,5126920.82959777 397657.786647643,5126884.82941976 397649.473768279,5126849.82923463 397645.004726745,5126818.4540605 397643.3483687,5126806.828996 397635.035482062,5126770.82880521 397628.847581176,5126727.82856701 397627.534752913,5126683.82830922 397618.971812944,5126640.82807793 397612.783911683,5126597.82784006 397604.4710243,5126561.82764997 397591.595617786,5126533.82752065 397578.407636095,5126495.82733311 397565.46972113,5126466.82719851 397545.344180905,5126436.82707907 397527.781224448,5126412.82698805 397507.593182574,5126382.82686947 397494.655252618,5126351.82672409 397474.529718163,5126322.82661191 397471.34202389,5126302.60775191 397468.529352856,5126284.82640523 397460.091433225,5126244.8261941 397454.091060634,5126205.82598176 397445.590639645,5126165.82577112 397444.027755832,5126114.82547489 397438.089904983,5126078.82528037 397425.151973375,5126047.82513668 397397.963862016,5126024.82508369 397373.463344054,5126008.82506407 397344.087731071,5125990.82504784 397305.337011941,5125979.82510165 397269.086369297,5125973.82517735 397233.335833894,5125981.82533342 397202.647953329,5125999.82553214 397179.272708267,5126019.82571988 397160.553757661,5126035.20086627 397148.834882151,5126044.82595783 397132.772294143,5126069.82615172 397121.772332701,5126100.82636484 397103.334705913,5126125.82656536 397092.459782577,5126161.82680651 397081.647381872,5126200.82706453 397075.835099479,5126244.82733626 397072.147795239,5126280.82755525 397067.835406618,5126306.42146587 397066.08545198,5126316.82778114 397062.648201959,5126359.82803953 397056.585866089,5126396.82827085 397045.710944138,5126432.82851025 397027.460872742,5126464.82874777 397016.460920688,5126496.82896388 396993.21071066,5126520.82916915 396969.772954926,5126538.82934018 396939.022558013,5126553.8295148 396898.396942019,5126560.82967184 396855.458795444,5126568.82984108 396819.083119819,5126557.82988318 396792.082547279,5126539.82985873 396774.519586055,5126515.82977324 396754.581592814,5126492.82970056 396734.393537423,5126461.82958359 396716.643028971,5126431.82946552 396696.454972903,5126400.82934927 396683.579551284,5126371.82922318 396670.579120159,5126341.82909202 396659.078702435,5126310.297698 396644.515705503,5126274.82879108 396631.390228143,5126238.82862717 396618.389788858,5126207.82849133 396605.264318258,5126172.82833358 396596.701364704,5126129.82811725 396590.826006225,5126093.82793236 396582.263052331,5126050.82771637 396576.075137571,5126007.82749328 396574.949857411,5125971.82729413 396573.637016015,5125927.82705053 396577.261814638,5125891.82683664 396595.511885163,5125859.8265997 396606.574358413,5125830.8264017 396629.824563343,5125805.82618797 396647.319162537,5125787.41633249 396496.946542206,5125694.16972709 396265.286206196,5125662.98278777 396160.816273646,5125738.57728593 396134.753495823,5125759.67123408 396052.504443825,5125823.62741535 396003.377069077,5125861.82845485 395945.971110523,5126029.07954184 395968.784521861,5126100.82986161 396043.817816002,5126209.1427239 396069.754253405,5126270.44142693 396082.850393495,5126301.39311046 396095.748378117,5126315.60244372 396095.756961454,5126315.61189973 396148.758271506,5126374.73706626 396293.917828993,5126499.7373284 396410.233127903,5126621.23766537 396495.391869976,5126771.61326048 396477.236287709,5126903.7390479 396447.01740699,5126953.27065725 396386.798790024,5127105.33416577 396321.236427432,5127269.05399634 396229.298063942,5127353.99220683 396131.015871768,5127441.55544318 396115.829386175,5127462.17909169 396115.828279149,5127462.18059506 396066.015476462,5127529.80609163 395983.734586901,5127756.49502677 395923.733826088,5127783.74532406 395777.326113984,5127902.27757212 395777.308245804,5127902.29204828 395726.294356848,5127943.62166756 395549.292459624,5128067.5602533 395353.352636097,5128173.62377797 395211.19494155,5128281.09341984 395079.411735468,5128299.68757608 394960.878470623,5128283.28152324 394781.906211452,5128198.87527613 394617.215350449,5128105.37520948 394538.216159199,5128051.72570248 394430.805121636,5127978.78129481 394333.866057581,5127977.43777842 394248.209101525,5128061.40714611 394197.834475444,5128209.75173291 394146.054233813,5128439.94045916 394112.617113715,5128554.12858191 394090.929403945,5128570.94121182 394060.054237649,5128611.37897475 393913.240703544,5128772.19256588 393830.17833932,5128951.81859017 393716.803734575,5129221.19508348 393649.741102212,5129334.41449471 393593.271673627,5129359.63347651 393541.208155385,5129334.6334693 393522.332596165,5129302.28961079 393502.519354101,5129249.38316098 393485.268439118,5129170.44533793 393460.892125407,5129056.50737175 393434.734730461,5128966.81952098 393406.827666262,5128921.06937453 393281.887002488,5128775.88149651 393162.478318341,5128709.72521971 393074.570595567,5128699.94412585 392948.131162291,5128708.25694998 392938.886078307,5128717.09598999 392938.881089356,5128717.10075982 392869.349294331,5128783.78870889 392856.131338188,5128904.03926276 392869.788619186,5129001.85215899 392921.040097872,5129082.50864999 392939.594223998,5129096.3771071 392939.603005278,5129096.38367075 393010.885818893,5129149.72750229 393111.387893415,5129209.66505377 393203.984079088,5129328.85288977 393215.891632466,5129464.35346913 393173.016630795,5129545.26016531 393150.858439436,5129570.56502282 393036.140792715,5129701.57362622 393002.98422843,5129725.82379725 392941.396243187,5129736.47843803 392903.451574447,5129743.04281602 392753.699271544,5129746.01187008 392503.539385536,5129775.94998378 392399.632345048,5129873.1693424 392239.412465554,5130032.26405602 392210.100676357,5130168.70217224 392213.070651679,5130306.92148529 392219.540503596,5130424.39070673 392209.916467398,5130554.61000795 392149.072499686,5130638.14170229 392048.790525459,5130732.51725212 391875.069984154,5130832.39293655 391663.504815478,5130896.51853027 391580.222853181,5130960.33141186 391436.940407299,5131072.70707042 391358.345878462,5131119.9261223 391358.337790057,5131119.93098495 391332.095618879,5131135.70747265 391169.843461014,5131170.05160012 391090.329432917,5131198.60780057 391090.311258207,5131198.61432773 391004.028975747,5131229.58332307 390870.621635629,5131333.89640539 390701.182026774,5131384.3968375 390459.210143678,5131442.20989569 390404.616155957,5131506.96020143 390404.773253846,5131600.33552766 390419.305721358,5131710.67964326 390412.243757333,5131781.58615058 390338.024937405,5131896.52414872 390204.523538589,5131962.2745484 390046.80271229,5131993.02485559 389913.988072682,5131976.18122009 389735.78932966,5131895.87789917 389735.42215901,5131895.71243772 389716.515360771,5131867.05611908 389571.981062729,5131772.08725552 389506.51136487,5131775.83735682 389479.604770387,5131782.21241387 389234.03940457,5131869.58802097 389096.006383826,5131901.213303 388922.035336683,5131933.83863323 388773.189300139,5131927.77631271 388634.030436623,5131872.40133634 388526.340893101,5131827.68260284 388437.463981855,5131767.6200527 388351.21178844,5131674.49490861 388256.834163314,5131549.83844281 388149.08215691,5131510.58849153 388127.769379886,5131515.21353581 388127.399562769,5131515.29264081 388069.331118797,5131527.71365645 388022.768344655,5131571.80759559 387956.643615577,5131701.96429489 387902.206568144,5131832.24597249 387809.018355722,5131902.40253741 387683.516554347,5131910.62147954 387590.171097294,5131879.4340258 387503.856283962,5131776.34013029 387426.478629891,5131625.71485673 387356.320156636,5131508.18341269 387263.786609173,5131417.74582555 387182.780887846,5131291.45026806 387182.409113164,5131290.87063628 387177.44021241,5131283.30812538 387127.000702834,5131158.62039828 387071.99810947,5130982.80755732 387039.590880763,5130934.40124346 386913.932180852,5130881.58882868 386890.025426821,5130867.80758648 386778.398073713,5130803.74512643 386670.708572628,5130768.96398226 386582.706761838,5130723.37028123 386497.674054816,5130708.37039707 386497.663885286,5130708.36860975 386492.517716472,5130707.46415414 386475.986184474,5130704.68292709 386341.452834485,5130701.27690786 386253.63935409,5130737.27714263 386147.951236715,5130835.27754052 386056.543827963,5130858.77774916 385983.85493916,5130831.99656867 385948.760142974,5130782.65277654 385908.258559579,5130689.3714036 385903.444393696,5130535.05859079 385896.787461117,5130478.83973587 385888.9116599,5130412.96461326 385852.847603138,5130316.15198014 385777.314182535,5130219.30817553 385722.469283381,5130190.43322317 385648.123974982,5130151.37078959 385475.682733631,5130049.2459285 385294.460745839,5130009.18371524 385092.770554928,5130051.68420095 384884.862006922,5130139.96602552 384880.021818156,5130140.61623874 384702.015678741,5130164.52893091 384570.919338906,5130112.6541042 384489.198661461,5130051.27916677 384432.354144517,5130014.24695822 384365.384582075,5129979.05834044 384256.071374883,5129978.46283999 384095.632846489,5129978.49152223 383967.631733082,5129951.80193996 383901.537153416,5129914.83208574 383870.442760021,5129874.39403732 383834.973140548,5129815.95589644 383818.316026528,5129747.01804328 383817.347899687,5129745.05059834 383817.347248667,5129745.04927532 383794.44034032,5129698.54885066 383712.031781964,5129536.95358107 383616.686453127,5129449.63944961 383467.309981205,5129404.13700936 383343.559376889,5129422.29130741 383185.264346579,5129474.58983867 383172.933891244,5129478.66365389 382432.112672226,5129129.30767849 382050.545617803,5128946.48889483 381930.669198259,5128890.45567463 381813.761564185,5128836.01625451 381555.44536519,5128886.57970874 381368.697109312,5128923.13427606 381021.946477756,5129068.91016897 380846.041160551,5129252.40756313 380614.072408873,5129385.43525726 380507.415444003,5129383.96480723 380366.976564238,5129343.80628053 380170.662848542,5129349.99066149 380077.944277665,5129418.39550277 380040.790213423,5129629.4263673 379955.47919401,5129806.17517836 379954.121354302,5129807.34346081 379915.854329741,5129840.26832905 379915.841474504,5129840.2793996 379794.292249493,5129944.95398924 379279.665993473,5130123.85218926 378897.416206212,5130353.6275367 378366.6809587,5130916.98226256 378366.669410609,5130916.9945204 378237.170204929,5131054.46130696 377947.108891135,5131310.67560811 377506.601105877,5131497.25225083 377506.577075931,5131497.26242869 377469.077028666,5131513.13683829 377272.357976651,5131591.66498638 377034.074980805,5131570.78614464 376768.355508367,5131649.93818213 376762.104174374,5131658.76955849 376695.137538811,5131753.37457609 376657.888268789,5131833.68653146 376593.7950704,5131913.02930396 376523.576565284,5131969.90321229 376404.419467585,5131961.21379023 376265.792989486,5131910.33652847 376138.384541883,5131794.20940704 376002.693305361,5131555.42582811 375983.661649708,5131533.08106143 375893.25356053,5131426.92399242 375744.783231971,5131374.14032947 375599.438955512,5131406.57551903 375531.627207405,5131503.76198948 375519.971366165,5131543.44932595 375519.969779084,5131543.45472667 375497.784644065,5131618.94901437 375472.066917037,5131716.38615851 375393.12918816,5131738.35365392 375292.127979765,5131691.28950564 375215.439271748,5131631.81949125 375151.469708879,5131598.25594608 375151.466609136,5131598.2543156 375141.2508288,5131592.88077914 375081.032066892,5131623.00482986 375032.908051499,5131728.37911571 374983.628283286,5131874.87840432 374901.879817448,5132042.06468055 374671.819852731,5132365.71739828 374385.573430713,5132800.46300037 374334.449073106,5132878.08721254 374251.043722939,5132992.52342011 374211.887897763,5133046.36656284 374110.638995748,5133185.33374073 374110.628800055,5133185.34772794 374100.639104321,5133199.05233533 374058.889312703,5133236.48917747 374004.170838717,5133285.73831497 373785.326565466,5133350.95355605 373598.668780583,5133318.79427626 373493.324466251,5133324.98007656 373445.043516532,5133372.69806519 373307.606872866,5133508.38339578 372977.297673735,5133932.09695315 372790.173713299,5134104.59397872 372790.170162929,5134104.59724814 372775.955042474,5134117.68750249 372616.612187284,5134264.74746524 372415.738702513,5134480.15052 372296.050727994,5134498.89858207 372182.611876215,5134445.24047566 372110.235077686,5134337.05177184 372038.734154073,5134297.76935155 371981.640729843,5134350.42468931 371910.20526255,5134544.45482948 371871.615119463,5134847.01677682 371871.613784306,5134847.02728489 371870.177754423,5134858.32925617 371825.681054914,5135139.17234848 371732.870849389,5135362.63963708 371632.871459507,5135456.4505272 371498.902091211,5135469.07334565 371358.618872436,5135378.66479156 371231.74097487,5135209.69394335 371179.165366849,5134977.74499291 371171.737240818,5134944.97416816 371149.550387032,5134864.23037611 371149.54857798,5134864.22379249 371102.921133998,5134694.62925355 371045.605330146,5134462.97203032 370950.884457963,5134341.37672201 370801.727018197,5134318.18680016 370567.694307639,5134313.58925654 370355.194118364,5134397.67957449 370170.318219683,5134413.73907981 370049.723713777,5134411.08087486 369743.345798776,5134327.79465235 369517.516662406,5134301.45274707 369360.186666137,5134283.1009439 369208.373999229,5134340.25473874 368975.278848685,5134340.25096428 368826.122522064,5134402.81105038 368532.309491415,5134496.65004185 368175.933545762,5134586.92551616 368028.589043977,5134596.79812841 367916.025289972,5134552.98380722 367905.228118526,5134542.16171798 367821.367215384,5134458.10728 367710.61665657,5134466.16798652 367475.710658418,5134591.3204227 367345.462794344,5134810.38079058 367239.401311117,5134934.12905694 367239.398405859,5134934.1324489 367221.307735114,5134955.25376096 367124.0914264,5135181.47090497 367082.156269516,5135375.50144765 366884.034768684,5135724.18567314 366793.943845536,5135974.49666413 366778.853974814,5136270.5276158 366807.978677004,5136463.10776126 366809.450611755,5136472.84057867 366824.57760034,5136614.80954984 366821.144583642,5136950.93443061 366845.334161347,5137095.80979895 366875.554018653,5137165.74778068 366875.804959058,5137235.8727713 366886.212501567,5137328.0291741 366923.08862478,5137396.46726575 366947.058138981,5137443.53015 366943.46508978,5137497.40508064 366978.653845522,5137576.56189309 367025.780404329,5137673.46889857 367073.093865672,5137725.68841608 367104.875728692,5137758.34518228 367121.626369416,5137799.34544999 367102.002053342,5137858.68886621 367050.877367345,5137903.3755169 366984.940474588,5137976.06191797 366918.191126759,5138052.34205411 366879.389001928,5138103.86746532 366856.816879829,5138133.84102677 366808.567344957,5138188.37147059 366781.879859463,5138200.4022785 366723.879623085,5138206.55757204 366647.597692618,5138187.11882044 366589.003223451,5138157.58661265 366536.397323923,5138113.34832342 366535.564825097,5138112.64824369 366485.313702831,5138049.80368183 366453.312870236,5138001.05316715 366416.593619779,5137978.95881858 366416.587707755,5137978.95525782 366386.499459196,5137960.83332812 366339.185982065,5137907.73881331 366288.122364621,5137845.83173942 366216.683841031,5137799.36182728 366108.557463946,5137741.9225659 366029.025822986,5137745.79625858 365970.026257097,5137802.23277408 365930.277242936,5137891.48209619 365920.371655258,5137944.51316849 365932.841234391,5138000.70085767 365960.811103591,5138072.01379758 365972.686771742,5138116.57648041 365972.687422175,5138116.57892797 365975.061905694,5138125.51401698 365972.469001608,5138189.13895637 365940.282070582,5138244.32591086 365898.688475529,5138272.70021792 365827.313242323,5138284.48028935 365732.281270375,5138269.79122924 365647.405031084,5138212.88359962 365569.934628535,5138122.63235302 365567.655039181,5138116.57448271 365567.653283612,5138116.56981739 365527.901621939,5138010.41294692 365499.08722652,5137882.66251335 365474.398328754,5137789.91213682 365400.896571652,5137690.84846121 365376.365258986,5137684.03591527 365333.990003365,5137661.53583604 365283.864981056,5137655.28574247 365239.771714256,5137686.41065965 365197.397982532,5137774.94182825 365179.555719593,5137881.72304155 365166.307346518,5137999.16051247 365161.902624819,5138110.22299993 365160.902713005,5138116.56674776 365160.902198506,5138116.57001858 365149.778695896,5138187.28547338 365117.904723126,5138259.47290813 365048.404931382,5138268.69152207 364993.341983506,5138231.22266712 364917.278734731,5138169.87877381 364875.965555283,5138116.56689138 364867.996674336,5138106.28493355 364801.183660132,5138062.75355874 364798.97112409,5138062.28804314 364750.089825187,5138052.00346172 364711.183923816,5138074.09713491 364666.187346678,5138118.2502155 364662.872128751,5138121.50328703 364641.967104594,5138209.56573682 364635.062474466,5138327.78445968 364649.313931514,5138435.87822487 364689.065706344,5138569.37828793 364696.285289058,5138631.03454516 364658.223828381,5138704.12821014 364605.78730269,5138771.34684599 364544.225664251,5138829.62796356 364490.91345493,5138846.69035307 364423.038507611,5138845.0964658 364356.851023245,5138840.90883246 364313.007271247,5138837.22124436 364281.069995494,5138851.15867724 364260.289258966,5138887.31487852 364263.47720422,5138920.37737891 364314.665608134,5138991.03372048 364391.104176879,5139075.7213625 364468.574177013,5139173.69025623 364493.012619355,5139244.84654557 364487.076089082,5139315.69027176 364439.077085231,5139385.34640949 364394.734339416,5139455.94005373 364319.141655568,5139528.87738026 364216.486331473,5139589.62715005 364095.080909628,5139641.93937995 363959.643840167,5139663.97033556 363868.425079219,5139656.56389265 363818.924788449,5139631.43879367 363808.392994932,5139590.40753212 363823.485954133,5139532.93882924 363839.172370844,5139453.87638284 363837.827523682,5139372.53265086 363841.545639761,5139325.87642051 363818.638210236,5139236.7826455 363785.481169167,5139175.62634255 363716.855629066,5139130.25121296 363615.824412883,5139124.84475658 363521.76249225,5139160.5008027 363371.857973439,5139277.59420678 363243.796764983,5139363.9689119 363237.626104089,5139370.40515816 363243.364277513,5139737.56253265 363288.385949383,5141356.56204431 363326.407379677,5142957.5615029 363362.428937446,5144568.560907 363393.450473892,5146178.56025039 363423.472146704,5147799.55953667 363462.493638907,5149407.55881229 363508.51540958,5151036.55805747 363525.541458662,5152632.54365357 363546.568453368,5154268.52794437 363567.595379654,5155902.51222113 363588.622172094,5157530.49652267 363626.648776953,5159144.48095067 363644.675349591,5160763.46526335 363661.701697692,5162371.44965229 363685.728248551,5163991.43389613 363709.754736729,5165609.41812413 363291.783016622,5165620.07441053 363315.77770652,5167225.40265729 363337.803609773,5168831.38711532 363364.829545382,5170438.37152247 363394.855248387,5172030.35603161 363427.881124527,5173632.3403966 363454.906150243,5175186.32520418 363467.932862727,5176859.30886258 363504.95904189,5178481.29290082 363550.977890328,5180075.29164102 363580.994093155,5181701.29615338 363611.010184343,5183316.30059055 363641.026261061,5184930.30498119 365281.047940272,5184892.29791889 366907.07038705,5184868.29350236 368514.094609698,5184840.29551664 370108.118282876,5184782.29747898 371712.142246418,5184739.29951398 373341.166495797,5184691.30160356 373382.189451016,5186298.30396487 373391.212936974,5187983.30635824 373441.235923314,5189582.30862248 373500.258375488,5191128.31076725 373541.281566533,5192751.31295644 373588.304614556,5194354.31507048 373653.328067132,5195956.31712917 373679.350870619,5197573.31916324 373718.373690395,5199170.32112234 373765.39676851,5200771.3230325 373810.419975119,5202384.32490804 373864.442539376,5203931.32664582 373465.40057681,5203942.92090823 373500.454499719,5205564.32904337 373528.486156668,5207158.32407421 373555.531914217,5208769.30919172 373587.577486548,5210369.29435633 373634.623218261,5211958.27954698 373683.669690791,5213571.26446363 373729.716095648,5215185.24932957 373769.762010239,5216789.23425526 373804.807979489,5218402.21906225 373825.852371883,5219978.20420591 373804.895460481,5221568.18928244 373851.941887044,5223185.1738895 373909.988276518,5224784.15858966 373945.033749309,5226384.14329541 373981.079382714,5227989.12790541 374019.124894757,5229587.11253092 374045.169847411,5231185.09714693 374094.216351173,5232802.08146562 374128.26138167,5234373.06628169 374141.315162816,5235996.05154401 374166.369620794,5237623.03668185 374208.423516773,5239209.02210155 374251.477236066,5240789.00753324 374283.530978323,5242386.43028713 373681.502561762,5242386.55653017 373719.557267099,5244003.97891204 373769.611971478,5245604.9638833 373819.667365047,5247227.94860987 373878.722823408,5248840.93337997 373941.779351181,5250481.91784665 373992.834567751,5252100.90249579 + + + + 363237.626104089 5125662.98278777441585.913042356 5259195.11379287 + 373992.834567751 5252100.90249579 375578.907291097 5252060.9016806 377183.981372119 5252035.90076999 378770.053836318 5251988.90012694 380424.132814015 5252045.89859687 382036.206902856 5252012.8979458 383378.268520258 5251983.89746 385004.34489571 5252002.89649079 386772.428209329 5252032.89545573 388359.488754287 5251990.89431465 389964.549770751 5251954.89312519 391575.611064042 5251920.89196047 393178.672571485 5251902.89076516 393228.738270271 5253772.88131533 393228.792456634 5255363.87321734 393234.396568643 5255577.49913186 393290.022245729 5255616.371974 393390.058438338 5255644.18441468 393456.779853272 5255644.18446989 393523.470080964 5255646.05951586 393612.378616319 5255608.99727381 393710.566996525 5255520.06029167 393761.41076364 5255461.24811933 393799.504685641 5255421.87334027 393801.348444994 5255419.99835078 393841.473568551 5255376.87359007 393843.129820376 5255374.99860038 393872.227230318 5255341.53053376 393872.254834063 5255341.49878372 393897.254849763 5255312.87393979 393937.723412979 5255260.37422077 393978.628478725 5255178.31214177 394000.095924966 5255115.37495644 394028.845055521 5255056.68775393 394150.002619737 5254954.68830693 394178.156529424 5254854.00129532 394182.905333014 5254813.68898684 394167.965771729 5254770.93918013 394099.587293418 5254748.62675282 394009.927251763 5254741.75174377 393877.07762318 5254723.93926859 393780.791470774 5254692.25187944 393703.692246657 5254621.56469184 393669.876928002 5254578.31489037 393670.062654952 5254526.25264556 393700.781229152 5254485.56535535 393760.812865314 5254427.44065828 393853.751326504 5254348.19106971 393938.597961266 5254334.50365964 393995.006383031 5254332.81618377 394145.355850435 5254326.25375792 394274.486167185 5254332.44126676 394384.022495763 5254354.19119954 394496.36942946 5254317.6914001 394536.806777902 5254266.94164156 394531.897189883 5254175.75455242 394583.272771438 5254133.81725321 394667.119014884 5254110.19237722 394714.55412945 5253986.94293421 394721.021368279 5253935.8181618 394744.520795483 5253892.44335681 394735.643469879 5253835.25610857 394714.858845106 5253761.25643422 394717.749468196 5253733.17612058 394721.13823463 5253700.25670446 394781.639561834 5253669.81934075 394850.141230463 5253640.19447216 394876.479432891 5253639.04667605 394969.176980153 5253635.00699702 394976.271037152 5253635.81949367 395519.510298066 5253611.56960918 395527.698069839 5253610.13211528 395591.795584246 5253645.88197253 395621.11081318 5253691.13179129 395623.173960433 5253707.38172584 395623.176417391 5253707.40122329 395626.206167995 5253731.44412897 395624.42712544 5253796.81886485 395634.993873549 5253906.81842208 395675.779923451 5253998.44306012 395723.252798144 5254063.06781092 395768.693664449 5254108.19264151 395804.538842082 5254108.56764903 395837.383216462 5254089.31773351 395891.728427757 5254069.75532382 395967.856422362 5254069.50534305 396028.203464222 5254095.56775665 396091.7057842 5254090.2552933 396158.018641153 5254025.69305678 396207.143077038 5253954.25583919 396239.860088802 5253867.81867238 396265.140567313 5253817.38136647 396287.703064163 5253791.94396523 396349.451795259 5253686.44436663 396349.452518554 5253686.44313108 396435.981260687 5253538.63241924 396471.021093905 5253535.14250544 396585.330355029 5253523.75747785 396741.052982495 5253460.13270856 396914.055403227 5253336.13314084 397183.096578436 5253318.38319059 397545.171773706 5253275.94581428 397881.089840105 5253237.88341716 398071.64310277 5253157.87611795 398411.165163381 5253015.32152345 398631.698949906 5252845.19695914 399211.553391767 5252512.82267203 399663.185514918 5252316.76194781 399663.18890481 5252316.76047621 399860.037217754 5252231.26058686 400083.512972148 5252184.8230912 400127.578144634 5252211.26051796 400233.550599022 5252199.82299713 400392.403112184 5252270.94779296 400644.262451817 5252429.8224055 400740.299196128 5252477.88478972 400989.095604804 5252627.32196682 401273.410740343 5252782.18896504 401273.424874001 5252782.19666367 401461.623488353 5252884.69648485 402111.037066948 5253242.0084967 402756.197989468 5253528.32078538 402756.232668418 5253528.33619738 402793.32506112 5253544.82077835 402867.907487764 5253578.15366794 403433.110881015 5253830.75824447 404070.552136632 5254094.38338663 404491.656023924 5254280.81508194 404491.669532849 5254280.82106263 404783.560952753 5254410.07122691 405363.374686197 5254661.44665537 405734.208224886 5254827.88450101 406041.500987131 5254961.06164401 406211.470139018 5255034.72431631 406211.538019337 5255034.75373486 407660.240902993 5255662.48321719 407660.246229705 5255662.48552528 409257.927861926 5256354.76517912 409768.695446346 5256576.08211699 409768.735834776 5256576.09961805 410876.518642679 5257056.12235784 412464.215509083 5257744.10071817 412464.225407797 5257744.10500746 413134.450013265 5258034.52484274 413134.466727295 5258034.53208522 414078.413610222 5258443.55154306 415221.098420247 5258938.68567606 415571.629807004 5259102.51900859 415769.741983816 5259195.11379287 416434.655664678 5259066.41721755 417233.950045496 5258911.95358296 417489.386345476 5258862.59051942 418521.576772072 5257884.97093374 418521.591206801 5257884.95726216 418620.339921949 5257791.45653319 418831.135731339 5257384.15777492 418831.142864938 5257384.14399141 419054.28907216 5256952.8940561 419277.644919394 5256325.22223341 419856.168262366 5254699.46313352 419856.169413348 5254699.45989922 419961.504463663 5254403.46415262 420370.297607175 5253877.47685802 420370.308017787 5253877.46346286 420684.45751304 5253473.27560163 420699.582566932 5253465.52549195 420722.613575374 5253443.65040793 420764.831886821 5253403.65025458 420829.73680308 5253321.52519332 420834.64266021 5253306.21276429 420854.485740219 5253272.90031502 420866.891582105 5253252.40034442 420911.702847702 5253185.7753913 420916.608703616 5253170.4004639 420929.139875651 5253160.0879085 420943.95161062 5253126.9005183 420948.92029462 5253121.71300567 420976.294371275 5253075.65058271 420989.130741489 5253056.910871 420989.137780079 5253056.90059542 421006.168577563 5253032.02561281 421021.011645038 5253001.33820388 421045.854749242 5252965.46322743 421050.760526428 5252947.58832284 421095.478050707 5252880.96338574 421190.632859417 5252775.46322344 421240.569406453 5252713.83819618 421287.849247044 5252639.52580995 421318.005367827 5252616.21317859 421315.286159703 5252603.58831637 421350.066321376 5252547.21341889 421382.409098178 5252495.96350618 421384.314008781 5252452.71385708 421391.845169808 5252445.08884084 421391.719840624 5252434.83893032 421396.030730076 5252381.526842 421375.216517007 5252341.1524139 421374.62137633 5252297.90279171 421389.339211332 5252259.71546142 421439.620257473 5252220.90275569 421482.62079669 5252210.08988797 421515.370809449 5252189.33971675 421547.839000509 5252150.77720407 421547.525768606 5252127.96490559 421557.619477922 5252120.15236577 421554.900351987 5252110.08998223 421562.462842742 5252104.90244671 421559.837466754 5252094.77756272 421579.680564474 5252061.40264186 421612.18009031 5252025.40261033 421690.211223396 5251971.02725899 421722.616760143 5251927.4647989 421729.92868152 5251904.46492394 421734.020257746 5251833.27800685 421753.863120106 5251792.34065896 421788.862620665 5251753.71563313 421889.644066225 5251693.90261076 422075.827735249 5251576.96673523 422075.831736897 5251576.96422193 422108.800519537 5251556.276567 422205.645840043 5251504.99070285 422207.113423663 5251504.21352236 422244.926218816 5251488.58827447 422292.238430961 5251448.1506557 422350.049479048 5251363.71333411 422397.70382296 5251271.46369329 422432.732605257 5251169.65177332 422437.887611685 5251126.65211682 422435.792387474 5251081.15255657 422428.885208473 5251056.21535543 422411.540394442 5251033.96573417 422294.688318968 5250847.59360662 422255.654102918 5250779.59461272 422219.55840433 5250741.97031117 422061.99058887 5250679.15993049 422061.990289746 5250679.15981114 422010.145087406 5250658.47312548 421961.424283542 5250626.16139231 421855.856373036 5250525.97581499 421817.417266538 5250501.03890998 421735.883675561 5250481.85237194 421596.130524203 5250476.16627958 421514.722253168 5250467.04214947 421468.689318028 5250444.85528805 421437.437048994 5250394.48102527 421385.401717388 5250301.16982975 421335.678528613 5250195.23371455 421331.737705773 5250093.67212132 421345.735002741 5249999.48529523 421345.537144329 5249912.26386602 421345.22786428 5249775.92471481 421330.504103495 5249628.73861119 421338.875153431 5249499.17714312 421346.218410959 5249478.73975099 421345.591940809 5249433.052648 421357.778483914 5249394.74036538 421359.683396659 5249351.49071882 421369.55787616 5249328.42832716 421388.837111648 5249252.0538087 421423.517340626 5249000.05566585 421452.195427332 5248684.68313187 421461.975917627 5248654.05831132 421524.318507261 5248574.43346162 421551.567482383 5248523.30867083 421555.157836141 5248413.99708926 421539.312288896 5248368.49761892 421513.247526146 5248315.49829921 421511.959865427 5248306.3313929 421507.5586117 5248274.99869791 421494.776839725 5248267.49887062 421340.200046766 5247926.69059106 421332.261646246 5247904.0033505 421282.412996707 5247785.31727213 421271.379475581 5247721.88040245 421269.46880705 5247584.75658579 421247.996825848 5247498.63249077 421244.400567 5247422.57066615 421252.336254887 5247360.19613367 421277.364405893 5247245.38441401 421304.456728695 5247181.44724735 421339.299551238 5247127.63493585 421471.860304437 5246978.44769333 421531.765467603 5246901.51039967 421541.921863026 5246898.82284537 421541.671292921 5246881.07300122 421568.982868386 5246832.4482153 421593.91995487 5246801.57329442 421593.700633866 5246783.7609511 421611.231792789 5246768.32345282 421613.66902469 5246758.13602316 421625.918251708 5246725.01121945 421633.230187974 5246702.011365 421635.604998005 5246694.32391421 421639.93604477 5246678.39095562 421645.322834495 5246658.57415329 421650.29145582 5246650.94918262 421644.821612398 5246620.44948996 421629.007389331 5246577.57498222 421600.161055511 5246517.01322451 421592.253901606 5246494.26348113 421558.751936342 5246456.57655645 421510.09362297 5246426.76467374 421491.873574267 5246399.07754727 421496.34096919 5246353.2654105 421516.309362567 5246327.64048607 421576.496443293 5246270.95303882 421616.746461364 5246242.39049484 421659.746948449 5246226.57782083 421715.435305397 5246213.20253434 421755.779319922 5246192.26492625 421808.372488355 5246135.70254511 421823.215606206 5246104.95270991 421832.77703582 5246064.20300146 421814.086858946 5245993.32876096 421792.834284135 5245927.57949187 421792.671749198 5245729.39374021 421797.327140677 5245698.89397675 421819.764106339 5245665.5816151 421855.170759483 5245652.33148713 421944.047787528 5245651.14338276 421984.517061154 5245637.95572049 422052.078932474 5245568.33087781 422083.297635789 5245543.83088341 422094.860118614 5245534.76838561 422231.393049078 5245487.20538154 422494.835058808 5245435.32906221 422527.553920511 5245414.57903166 422585.115589298 5245345.26678407 422604.927507429 5245311.95445981 422614.582703433 5245271.14227407 422606.017937438 5245205.26794313 422600.673425301 5245184.95566728 422595.548148442 5245179.95574776 422577.171372993 5245137.08126729 422561.639125466 5245116.89405706 422520.6059753 5245087.01960419 422496.489997244 5245048.03760108 422496.479184468 5245048.02012289 422489.416161383 5245036.64527414 422465.600875504 5244965.77108275 422451.848246604 5244892.39684717 422444.003756088 5244874.70956057 422443.659198623 5244849.27229659 422435.720794628 5244826.46005738 422429.843664227 5244763.08567718 422442.249562794 5244742.58578611 422477.625066146 5244732.02315724 422660.347730712 5244719.27210901 422743.942863871 5244700.39675247 422963.69518479 5244608.45872556 423072.791232932 5244599.39562315 423110.854537993 5244596.33291229 423143.604744552 5244578.08288079 423166.198307476 5244554.89546129 423245.539479632 5244411.58384623 423315.663827504 5244337.02163418 423388.726692196 5244292.83411446 423573.57349836 5244249.58340654 423702.951124235 5244211.9160219 423738.013431865 5244201.70787795 423803.889657037 5244190.5825884 423854.7032688 5244187.39481166 423905.611101011 5244199.39438211 423944.175441444 5244229.33134657 423957.145196942 5244251.95603977 423970.647234945 5244307.70539568 423968.961654285 5244371.32976515 423956.461831138 5244386.70468763 423959.21228526 5244399.32954351 423946.649802952 5244409.57951822 423946.869106871 5244427.39183766 423975.151799351 5244452.45390945 424018.528200691 5244464.57851692 424066.779324932 5244463.95322252 424112.279913318 5244448.01560082 424152.404835283 5244414.51569212 424167.153929631 5244373.64101704 424163.056649859 5244261.89218054 424195.368266019 5244208.08003203 424255.74343179 5244166.64258895 424356.681736983 5244114.45501461 424416.837842521 5244062.89268459 424421.524595356 5244034.83044647 424449.05641287 5244031.89281265 424519.086735325 5243982.76546948 424587.461809958 5243966.63786594 424650.273090999 5243910.07338602 424723.272104283 5243858.32094554 424773.928287044 5243842.44405399 424811.677647115 5243811.50533222 424927.488323561 5243721.18903625 424937.268631943 5243688.06396576 424954.736658528 5243659.93853504 424974.109535597 5243586.00097629 424975.857432102 5243517.43907775 424985.79453947 5243502.06382617 424998.231354667 5243476.56357253 425048.85636252 5243463.24915306 425127.701049451 5243472.43337074 425229.201617576 5243463.61684715 425303.545163236 5243437.11409532 425303.549402951 5243437.11258231 425317.732624008 5243432.05107015 425378.357317052 5243405.9238695 425403.270589048 5243382.7576384 425403.294305405 5243382.73558515 425406.013000479 5243380.23549935 425463.136866116 5243328.35868973 425462.480264155 5243317.17132501 425460.792492731 5243308.85897413 425455.948497517 5243302.23423474 425447.948330789 5243298.98459044 425433.698218927 5243299.17266596 425417.541907133 5243301.48579805 425397.916946351 5243307.98652995 425372.697715243 5243299.17513742 425355.634743497 5243288.48843276 425343.821153443 5243256.42672351 425345.507970825 5243233.92687414 425359.506696935 5243189.05174343 425375.537302995 5243163.98883738 425400.474334798 5243142.23803789 425418.38050765 5243134.98738237 425447.099902502 5243148.17358989 425447.288209402 5243174.17332972 425462.758500157 5243219.79725953 425479.946995741 5243247.3587953 425506.354472486 5243279.91990916 425551.353092976 5243223.41863382 425560.165621094 5243221.98079062 425563.165913152 5243230.60558541 425565.041097145 5243236.04295671 425567.791365844 5243243.98026831 425570.51055476 5243257.41752786 425573.260993946 5243270.85478616 425578.761759986 5243294.10433792 425588.762423759 5243312.85375104 425604.075602435 5243330.66545811 425621.201379501 5243351.16456581 425642.827135771 5243369.78850955 425669.796296844 5243375.84985863 425674.858885241 5243377.34963909 425674.934197452 5243377.3720909 425702.109362684 5243385.47345691 425719.078194943 5243383.59778787 425737.890648983 5243377.09708887 425740.010214788 5243376.08200283 425740.109384381 5243376.03450929 425761.078005389 5243366.28375434 425789.608818469 5243344.59530833 425809.233420225 5243326.53218786 425816.420044734 5243296.40718753 426022.641687027 5243334.64846594 426081.079571282 5243331.45862981 426093.704510585 5243326.14566952 426234.451831359 5243202.57865267 426287.545445784 5243184.13917769 426328.358659772 5243196.2624079 426417.171624064 5243187.63389151 426447.264740691 5243159.32044218 426501.824110273 5243044.3818262 426523.822067562 5242973.00661389 426573.256469659 5242860.56817836 426566.505935163 5242845.19359849 426561.84949313 5242840.25633441 426541.161697012 5242836.19471257 426506.16099743 5242822.94625908 426475.597836297 5242809.76012506 426445.065699758 5242789.32405904 426410.783342017 5242762.76320388 426390.126228305 5242740.45175531 426380.937483647 5242702.88998672 426397.812090207 5242685.82696422 426417.436826176 5242672.20129717 426441.593045662 5242664.88788584 426469.34307169 5242658.44932016 426505.249829028 5242665.32279647 426546.53168879 5242674.07103677 426594.938630275 5242683.56898076 426637.970333149 5242686.81720254 426676.283491168 5242697.87804186 426692.813726213 5242661.00272043 426732.687135307 5242599.56418343 426767.090643263 5242502.68870327 426766.370063986 5242444.2517858 426737.743017776 5242386.12849988 426704.430449989 5242392.62979268 426685.680638845 5242403.56795129 426673.243710305 5242425.13075245 426662.68210293 5242456.5058842 426653.807730458 5242478.94353205 426640.558491852 5242506.81880599 426626.277661489 5242524.00672317 426603.058893881 5242529.50761442 426567.932890937 5242506.50926029 426552.525403249 5242470.82272563 426532.586656173 5242436.01136702 426531.554476479 5242406.44919003 426532.209783214 5242376.01195274 426541.959052007 5242350.01180343 426559.70846546 5242326.57380431 426578.426722354 5242305.88573951 426698.018928816 5242225.31913873 426758.705564592 5242181.87958072 426801.611539326 5242161.94052329 426821.54958683 5242174.31459496 426838.704463395 5242125.87685449 426893.765245675 5242056.62526697 426931.421250946 5242039.06139951 426931.434142717 5242039.0553835 426972.139735793 5242020.05992068 427007.608597992 5242014.49602885 427033.328422654 5242042.24472045 427115.299629895 5242099.67834344 427169.14506588 5242139.6757763 427217.614665312 5242154.2986667 427247.770431821 5242131.04765762 427239.581279795 5242080.36096614 427190.422425647 5242009.80112922 427177.202226058 5241966.86457046 427219.669392251 5241905.30091825 427490.136874861 5241795.35342681 427512.448034294 5241746.85296971 427507.760063851 5241733.04078954 427507.759671562 5241733.03963564 427501.853222022 5241715.66619228 427483.663894005 5241661.97993435 427478.163338843 5241645.66781074 427480.631867742 5241637.98028176 427482.693269968 5241602.41802925 427563.09782598 5241527.85294411 427643.815676353 5241478.60010886 427747.346199541 5241429.09634358 427792.783324321 5241405.59470699 427815.658418391 5241402.78129942 427818.878061245 5241430.4059122 427805.691923493 5241477.15601728 427810.349081718 5241504.90557021 427823.006131273 5241527.15484779 427853.632211953 5241553.77835203 427875.100874598 5241545.52755272 427894.693937325 5241518.65200213 427931.098640841 5241460.15105773 427984.095254346 5241338.90001456 427967.063393539 5241323.77584948 427909.719454053 5241332.27811207 427881.9693509 5241336.02921031 427856.87540505 5241336.15523362 427837.531114493 5241323.8436373 427806.623272624 5241280.97029621 427798.40278573 5241227.72112499 427827.806545662 5241140.97072671 427912.239736362 5240982.4687407 427931.769059366 5240916.2185537 427967.487252672 5240889.52983904 427995.612847748 5240901.4035792 428012.488644879 5240922.52769432 428031.333942422 5240967.02651368 428039.459680497 5240988.46348396 428060.336104983 5241028.52476154 428081.80502093 5241028.39888512 428118.523800084 5241020.08496068 428120.147969765 5240993.27264091 428118.209497271 5240962.83550012 428113.489469795 5240923.39855585 428097.081744029 5240880.5871207 428092.424386219 5240846.52512457 428097.704233305 5240800.58783112 428125.672611899 5240781.77435971 428184.549253219 5240819.20910681 428236.333450341 5240899.89374799 428269.99163211 5240952.82938605 428343.930485838 5240977.26363916 428504.0568526 5240980.44456402 428567.432091882 5240972.12954915 428655.649986489 5240922.87639123 428655.651697681 5240922.87543563 428688.555916929 5240904.50021297 428723.554659362 5240855.87422389 428712.615154558 5240795.0627241 428673.236494842 5240688.87780087 428690.485102474 5240640.44003526 428675.358599653 5240596.56605342 428657.107577197 5240568.69205421 428651.169687618 5240557.81739627 428651.160664338 5240557.80093873 428644.41924635 5240545.5052847 428623.668155315 5240516.0689024 428613.667428521 5240495.50699915 428602.760277172 5240469.63268145 428613.352949152 5240432.82008249 428632.946483765 5240421.13188599 428649.461729364 5240419.69512131 428649.477817678 5240419.69372169 428667.009157433 5240418.19301698 428693.853194224 5240420.6293949 428727.072282869 5240423.12801109 428760.134723848 5240413.06424771 428787.790365439 5240386.93835144 428783.227121532 5240364.50124191 428769.601255609 5240340.43951859 428717.066414307 5240239.63008705 428715.566183702 5240232.69271154 428715.562033437 5240232.67315401 428711.534302746 5240213.69304935 428720.252020059 5240178.81800834 428733.65803114 5240167.94255714 428756.001637324 5240157.87923191 428873.314854283 5240151.68697586 428889.533813333 5240154.31128684 428904.003803169 5240189.99787059 428890.004641763 5240219.99817334 428889.997553997 5240220.01339022 428826.133473843 5240357.12455032 428814.633920726 5240374.12486755 428813.85340258 5240397.49968768 428821.166689827 5240420.62417844 428821.323734269 5240445.7489443 428808.824202717 5240463.68679377 428797.262182377 5240481.74960362 428790.294168904 5240506.81216173 428785.919902026 5240531.12462036 428788.764605456 5240560.62423626 428799.297372305 5240606.06089284 428829.922839666 5240613.24707387 428910.766150719 5240579.24407202 428965.98346615 5240520.11734574 428995.512532296 5240443.67932694 429018.412369999 5240235.11777138 429017.568253364 5240210.75486928 429017.567843021 5240210.74302597 429015.033679321 5240119.18145608 429002.40693177 5240066.99494499 428980.186843911 5240030.12118959 428963.061005979 5240007.80959388 428932.498020183 5239999.93591942 428898.466516229 5240000.24981342 428866.279027279 5240008.50105994 428839.403909706 5240011.37713698 428812.528794088 5240014.31571345 428782.903146086 5240001.06704946 428772.027527097 5239984.13014935 428769.183050688 5239961.81796831 428787.93256643 5239941.87987918 428810.213418579 5239923.81662794 428852.213254071 5239908.31504367 428880.806625119 5239889.31404135 428918.306174644 5239865.87521318 428946.02464913 5239850.37421478 428963.89966876 5239846.62351449 428988.087549267 5239852.74746581 429009.619129659 5239857.93403474 429038.338239975 5239862.30781587 429067.869285496 5239848.61922639 429082.02488005 5239824.43136283 429092.711921048 5239807.30607803 429113.149653999 5239809.68021716 429135.868729714 5239814.42924124 429155.213141218 5239830.61580114 429176.40206056 5239870.30207417 429189.090447692 5239895.23882903 429205.278721611 5239915.73798017 429226.029556688 5239937.04943682 429239.561334774 5239950.42376122 429270.093125982 5239960.04742155 429289.812022869 5239959.85911383 429307.655739024 5239954.42093016 429318.185960559 5239919.35831226 429314.497440658 5239888.04624441 429303.496283107 5239854.17199984 429285.463961808 5239824.73550436 429268.244174647 5239796.17396783 429242.961629583 5239761.42531821 429218.554036165 5239724.92664865 429205.80275119 5239687.42750933 429203.801659862 5239653.42789686 429212.644708541 5239629.11525166 429206.300160118 5239605.42822512 429226.456074569 5239589.9275356 429297.330867545 5239566.17483461 429355.800126289 5239568.04741385 429449.738312711 5239566.91856172 429472.050756455 5239559.73020856 429482.644478939 5239556.2923037 429481.519022639 5239542.16747608 429471.924252162 5239512.29313736 429456.391765878 5239477.04409093 429452.578216649 5239444.85703525 429472.26552096 5239433.91882306 429509.015824461 5239434.60480516 429569.953948181 5239439.53975444 429635.392277044 5239449.84947094 429658.767480121 5239450.59850281 429675.018451436 5239477.28509707 429662.644383491 5239509.66031799 429649.36371348 5239531.1606728 429620.0211097 5239574.41149419 429603.958999517 5239590.59951032 429584.990912165 5239616.10006281 429646.367570047 5239653.47220739 429723.150912821 5239700.78113141 429768.932656751 5239705.216711 429778.495361437 5239709.34128149 429789.339649382 5239723.65320889 429792.15282376 5239744.21541078 429789.622492541 5239773.77775224 429782.623291445 5239800.65280105 429772.061991163 5239841.02787613 429769.625608838 5239876.840158 429775.970203341 5239901.90217487 429794.971026962 5239923.2137056 429812.908888172 5239930.21290716 429842.471412956 5239923.77425089 429913.096007612 5239893.77161789 429931.814444053 5239879.33347736 429933.407380568 5239853.33364222 429929.562292602 5239812.14666484 429918.340670766 5239724.46040224 429912.65153681 5239674.39857929 429902.931945658 5239650.27419233 429935.180327918 5239591.52338711 429973.148951156 5239578.33444311 430011.399714245 5239593.08274051 430068.747601033 5239709.32935724 430104.749154568 5239749.45252428 430125.281040108 5239764.45154868 430178.781839177 5239776.57424458 430204.094282369 5239768.63577498 430251.805343489 5239709.89195168 430251.81153196 5239709.88433218 430279.123172799 5239676.25850589 430295.933210702 5239594.8210309 430272.30593641 5239529.07257987 430247.085395536 5239478.88655797 430247.065130004 5239478.84626715 430220.2709934 5239425.57562951 430224.142785711 5239323.82636509 430242.452446773 5239254.0166138 430242.453204368 5239254.01372529 430243.515585201 5239250.01371672 430307.918014048 5239114.51225511 430345.917967379 5239103.94828284 430509.421577742 5239178.12840114 430513.204927995 5239243.12767728 430514.268204909 5239267.25242264 430514.394006515 5239292.37719784 430518.11363941 5239319.18931041 430527.302092121 5239346.87619038 430541.708992321 5239363.81294971 430556.115635628 5239372.68727956 430581.209769303 5239378.68619498 430607.990648845 5239360.62275108 430628.458752676 5239335.43462885 430622.769726485 5239288.93526851 430624.330668107 5239239.68563383 430636.704479254 5239199.43547551 430720.392427261 5239193.432083 430735.205178018 5239197.74393575 430737.955512096 5239207.55623717 430732.612233708 5239223.61881733 430731.019275082 5239248.80616369 430733.051910451 5239291.74320637 430736.803137519 5239329.30522511 430745.897585315 5239348.99217966 430767.55470928 5239371.1785958 430790.96164739 5239387.11499449 430825.962364775 5239401.17593282 430850.11868049 5239397.42497198 430867.087071903 5239382.11190711 430872.336367945 5239358.79939359 430863.116264319 5239318.61262171 430848.520746561 5239266.73867259 430829.331130686 5239205.05249797 430804.860599863 5239155.11643903 430805.640128327 5239100.99187713 430827.261959432 5238996.55439349 430856.19553098 5238866.61682865 430881.163245 5238828.24113217 430888.412483633 5238802.67855485 430994.004072172 5238709.98750294 431080.160372442 5238691.17161198 431098.035827311 5238701.17078844 431134.099803186 5238738.79397669 431158.165643339 5238837.54213327 431184.762837348 5238938.91516358 431198.76634806 5239045.35116963 431206.924039531 5239088.47546214 431250.675982808 5239138.78572757 431322.302881923 5239181.03241588 431508.086377232 5239206.77454937 431586.649121875 5239195.64641174 431674.77256393 5239126.01837977 431707.302910094 5239090.07984728 431773.397136633 5239089.20213385 431853.899430004 5239141.51087506 431858.115192378 5239144.50846021 431858.118308525 5239144.51067592 431925.122044907 5239244.9445654 431971.123111785 5239267.19248425 432081.75283505 5239387.8119124 432115.536372922 5239450.93498927 432187.66442913 5239528.7438672 432231.541792749 5239591.74153242 432285.105257091 5239608.86418795 432358.950122511 5239625.79851256 432384.544386038 5239635.60987891 432476.327458173 5239670.16831957 432519.985170762 5239705.10373376 432538.581183597 5239770.91491781 432537.272025559 5239875.03909702 432499.655637394 5239998.33592644 432499.650701986 5239998.35210343 432485.933293273 5240043.35228728 432456.843008563 5240158.10251364 432462.751426357 5240224.03921639 432545.035988315 5240306.91014946 432665.978644202 5240437.52910212 432735.951760437 5240555.96274664 432772.830394313 5240659.7103696 432783.582195138 5240712.95948416 432773.80185245 5240743.52212786 432747.430744904 5240870.83463821 432740.150425606 5240901.5221782 432700.809895495 5241011.21036396 432702.282582003 5241133.0842805 432683.129292311 5241229.77174948 432679.978172552 5241389.89553201 432684.355048866 5241447.08237286 432698.621560686 5241638.26320182 432701.112413624 5241671.64230216 432733.116586203 5241793.20247775 432766.649482272 5241835.88825501 432817.431125492 5241835.32369436 432893.211893738 5241801.32089719 432930.86720768 5241762.81968784 432937.74013186 5241696.69496167 432934.895621542 5241673.82026886 432975.618981181 5241634.19734614 433035.299531864 5241576.12949839 433065.831015856 5241575.75325846 433090.548317766 5241524.69017794 433082.516327646 5241503.75317963 433088.703155593 5241481.37811423 433077.638806391 5241426.81651988 433064.85609881 5241384.81739093 433052.948370177 5241341.94323378 433035.759609423 5241307.13172477 433023.008469064 5241274.94501313 433002.100439071 5241224.94628289 432984.848976842 5241183.8848292 432973.004039787 5241150.01059518 432948.533713887 5241107.199451 432929.689295617 5241091.13785405 432912.595155358 5241083.26361733 432892.157383533 5241079.88947947 432886.280046016 5241008.82781364 432878.592327649 5241003.95316819 432908.873317092 5240988.38956232 432990.186678174 5240995.01118797 433125.470673771 5241046.69273617 433202.41072646 5241106.75159756 433240.598761453 5241113.87498056 433276.00495307 5241103.3111239 433306.191943067 5241080.06008524 433315.721542831 5241026.62263938 433279.719955761 5240986.37444233 433233.624954605 5240959.00155092 433215.624161483 5240938.87745283 433207.497706383 5240895.8156422 433217.403375183 5240875.37790742 433237.433954787 5240849.68980265 433270.152296439 5240829.00113802 433473.153172742 5240806.24303517 433486.926229535 5240806.70438945 433640.87343626 5240811.86113884 433657.21633902 5240781.67321963 433662.496730744 5240753.86073263 433659.526597813 5240711.86119926 433670.150897073 5240687.61096449 433717.651350201 5240689.98400406 433749.152401172 5240714.73251384 433767.184370929 5240732.54413103 433770.87227664 5240744.16888502 433780.873280974 5240772.73074225 433783.030159372 5240791.60549936 433787.468880752 5240828.23001772 433788.595162866 5240867.54214931 433788.689670627 5240890.91695373 433777.253065306 5240921.3546709 433773.879200159 5240957.22951423 433771.317637024 5240986.79187616 433771.694554536 5241045.91637549 433768.320658869 5241080.85372631 433776.540284025 5241105.8531858 433789.260495716 5241147.85232229 433806.417399061 5241163.78899188 433828.855250641 5241169.10053339 433860.011363253 5241157.16186084 433886.292540027 5241148.41086085 433896.979315517 5241123.41062978 433903.134598141 5241092.03563562 433935.976173921 5241016.84741113 433945.630440891 5240953.28503696 433961.503825146 5240899.53482843 433965.7832798 5240843.09761488 433974.594196579 5240792.0976717 433976.03087931 5240766.53532179 433977.09276369 5240747.28543562 433970.685162101 5240707.16102505 433971.496766906 5240679.348719 433983.996025023 5240653.41092003 434015.214438556 5240635.40979117 434043.902248747 5240637.97109793 434075.277785002 5240646.84474346 434112.09118276 5240665.53058703 434148.905043138 5240698.46631491 434180.906698373 5240741.65215643 434195.719971089 5240761.8388873 434211.971868986 5240816.3377807 434220.19193392 5240854.83713223 434222.067557409 5240873.5869033 434241.006222484 5240904.83587636 434252.881785709 5240919.27277439 434298.412807851 5240901.0835637 434323.380344057 5240857.58289734 434388.252207605 5240745.14365928 434428.563939087 5240711.64228378 434598.533568062 5240697.19795746 434621.345994915 5240689.38458853 434636.37661395 5240666.32166018 434641.000410428 5240628.19677809 434630.687253396 5240610.50984184 434559.24830167 5240583.26298071 434541.028096777 5240542.95155038 434553.558695938 5240519.88872408 434596.589940439 5240509.26205056 434795.029932381 5240537.62871093 434833.123973468 5240537.31465642 434839.40907487 5240654.06346419 434822.474092101 5240735.50100316 434765.007717438 5240822.50265152 434684.164755862 5240866.50559792 434494.102128314 5240909.13801159 434456.290411626 5240942.5142849 434404.325310105 5241067.57789284 434372.140203973 5241149.20354399 434372.51627875 5241182.20326118 434387.891974371 5241199.82749155 434517.549547792 5241208.57213582 434540.330645197 5241198.25879058 434583.205149595 5241172.44475129 434661.54834205 5241136.0043512 434841.078404615 5241055.37267875 434894.046485081 5241021.80828753 434932.171858896 5241023.93171551 434955.423032129 5241054.24302467 434951.238314312 5241140.68000359 434936.333023844 5241173.805346 434822.677966645 5241238.43445985 434759.459640864 5241267.06180588 434752.085328024 5241289.99942189 434821.055931976 5241329.93379125 434958.401236139 5241343.74058618 434981.182331396 5241333.36474135 435027.739890408 5241170.2391488 435049.674745139 5241083.67644605 435074.406137693 5241052.36388019 435102.297994234 5241017.04983175 435147.797597646 5240993.73566177 435208.672816838 5240985.54574391 435297.673829562 5240994.79204024 435348.580798414 5241004.3523881 435427.237401503 5240995.911747 435459.73607311 5240947.28580622 435461.577682184 5240881.2862531 435417.605940684 5240800.4136875 435360.978188456 5240729.91655763 435335.070249373 5240684.48047569 435308.879979266 5240605.98216783 435318.252560504 5240529.60739034 435327.970144866 5240491.54479481 435357.874794744 5240435.29401785 435416.061988824 5240411.85432427 435672.595260259 5240411.71883674 435733.783971351 5240433.96616044 435754.472706267 5240466.71505769 435761.322074096 5240636.77594295 435792.229890398 5240677.14936381 435830.700095411 5240712.27251749 435848.575562725 5240722.20920977 435868.482063045 5240725.02087502 435932.514118905 5240734.08068995 435986.07760781 5240751.265869 436077.421720139 5240740.1372271 436110.045804047 5240704.26117487 436119.763381843 5240666.13607507 436098.322137513 5240557.07530029 436002.126920508 5240344.76838717 435919.183471615 5240183.08554247 435900.430334234 5240091.77452353 435909.802908791 5240015.462236 435932.364580498 5239984.77405167 435998.239740005 5239973.89643851 436130.522482608 5239987.82841245 436216.866962218 5239989.44986387 436282.491116767 5239948.00999744 436310.13607359 5239900.15144092 436310.146012239 5239900.13423528 436314.927028895 5239891.88410326 436308.422644324 5239759.82289152 436261.512212425 5239643.51321499 436337.10443938 5239579.19811188 436537.229423017 5239531.37777043 436583.230599633 5239556.31319154 436624.984416431 5239662.56066302 436663.862125178 5239735.74600741 436681.68475947 5239744.44308314 436776.177303905 5239790.55348417 436842.271794076 5239797.36322366 436867.584065984 5239784.42478527 437085.521855142 5239741.54118056 437125.676814098 5239692.85240449 437094.298736023 5239606.85434395 437073.264902961 5239533.41826443 437080.231693169 5239472.29344289 437110.481250245 5239451.72985777 437186.731983737 5239456.03919625 437365.047397084 5239502.40652987 437425.860012499 5239491.5916167 437468.57765199 5239447.9026931 437475.544444263 5239386.96536572 437482.542480397 5239325.84053824 437522.697435373 5239277.21425514 437560.666045375 5239264.08779469 437580.197312131 5239260.02452319 437610.416718976 5239272.83568628 437621.292480367 5239293.33508607 437622.324774962 5239324.70980852 437611.700991516 5239364.02244985 437455.494870464 5239783.27570405 437443.215267497 5239836.08830908 437445.123244434 5239887.96283987 437450.342641733 5239906.3374876 437450.347889116 5239906.35599495 437456.030848428 5239926.39960345 437474.062978259 5239948.7736965 437517.063781731 5239962.89682964 437555.595300937 5239961.89525972 437583.282601181 5239949.26922112 437606.500821088 5239927.70593253 437619.248859425 5239909.45763575 437619.250318217 5239909.45554755 437629.656158395 5239894.58023312 437675.998165075 5239830.82881344 437696.497377478 5239802.14068875 437705.340308494 5239775.26552782 437708.870553345 5239744.01561725 437710.494056127 5239698.32839287 437698.585230546 5239623.20444359 437674.799156616 5239482.83147037 437670.984439789 5239416.6446226 437662.669450621 5239343.27051337 437654.4491004 5239296.77119908 437657.073587843 5239280.64621209 437658.728630001 5239243.70892073 437677.291149487 5239239.95818656 437712.13297461 5239173.58225214 437731.097668167 5239046.45742307 437755.845748605 5238982.64438241 437793.156087948 5238908.64340053 437843.718200552 5238885.20399595 437965.750597553 5238891.5739302 438004.252138613 5238929.19706778 438040.724101232 5239017.75741157 438090.134415949 5239129.0045567 438136.668534147 5239204.75208445 438170.013539817 5239234.87549231 438163.046756841 5239295.87532698 438115.204168358 5239342.12694817 438100.831669138 5239421.00195332 438131.488734614 5239438.43806637 438184.801629892 5239437.87338346 438214.676698245 5239432.93469441 438283.739359472 5239421.61944476 438296.994445698 5239415.5557913 438329.239022643 5239400.80523163 438437.298788852 5239293.11409011 438452.047293976 5239244.61384118 438433.482131179 5239168.67766156 438514.481798405 5239139.79954699 438549.480454447 5239091.17346592 438673.252324028 5238780.04565372 438695.782471667 5238741.67000697 438751.657965869 5238743.66769376 438784.783713906 5238758.54122276 438833.692179504 5238813.91380826 438839.538503137 5238889.9755147 438810.699777323 5239047.78805148 438786.735412326 5239185.28803407 438767.175213891 5239259.10079892 438724.332162124 5239290.10233117 438564.958089619 5239355.233395 438519.928529332 5239416.67229178 438429.524979497 5239519.23774584 438377.589883729 5239603.92675149 438374.590019929 5239608.73933899 438357.561167422 5239685.05197432 438373.187377406 5239717.8635921 438429.344976154 5239745.29858925 438556.440012263 5239754.10581809 438815.34760613 5239733.59536249 438891.316162765 5239709.90492309 438926.220649085 5239648.65393875 438914.559412155 5239501.40548772 438908.525245354 5239415.09386287 438940.741618406 5239336.0931154 438988.835302735 5239322.90373775 439062.711437133 5239339.77558419 439129.589808234 5239425.45972052 439210.252749671 5239607.58009717 439292.22414004 5239667.638805 439376.382288985 5239704.88508916 439465.414627068 5239716.63135797 439513.664902466 5239713.56690371 439536.414736543 5239703.25354585 439593.755440673 5239598.50194687 439638.878740756 5239537.00053739 439674.25358268 5239523.99918029 439705.004656862 5239548.99774147 439830.69699692 5239664.55426803 439885.716561564 5239709.61218704 439956.232664447 5239767.3608965 440088.641011908 5239799.04275131 440139.359885916 5239790.85323295 440189.984756065 5239775.10127166 440487.856115501 5239596.71532639 440538.700415786 5239601.27571161 440577.107973763 5239631.33642834 440610.985784719 5239707.27201084 440651.956115299 5239744.83257141 440690.175582139 5239757.26842014 440718.23854545 5239764.51722091 440761.301026818 5239753.89053208 440824.519400125 5239727.88812473 440924.013321674 5239523.63546545 440986.260127313 5239414.07117183 441003.852972908 5239383.07066466 441036.633871203 5239365.00694531 441173.979066398 5239376.18873734 441291.04337579 5239402.8712553 441354.794450956 5239420.05602454 441392.825726046 5239411.99202088 441440.731307861 5239381.05276855 441491.136818155 5239347.42593154 441493.574229786 5239344.23835334 441493.587389503 5239344.22123925 441508.761182833 5239324.48786526 441518.510056681 5239288.8002086 441571.289899878 5239234.86091105 441581.226790564 5239214.48564198 441585.913042356 5239176.36070888 441579.036780257 5239140.48623483 441575.129828213 5239120.54903067 441546.345628468 5239039.61326235 441530.123504235 5238943.17708428 441511.37028775 5238851.99097485 441507.710331387 5238742.80436791 441501.707377636 5238656.49270168 441493.549271239 5238603.24339929 441476.33205697 5238583.62189494 441476.329728245 5238583.61924102 441458.985180196 5238563.87008886 441429.29631842 5238530.18403958 441396.076642976 5238510.24804221 441332.701606564 5238523.56305899 441281.202243367 5238554.18996856 441206.484416552 5238598.63023806 441057.298043148 5238666.13591042 440786.235695324 5238732.58409754 440656.829091591 5238751.65178565 440587.983901285 5238724.46730539 440544.325799127 5238679.21941592 440515.761043529 5238618.47101433 440479.508738079 5238557.97292788 440452.754029706 5238423.59996689 440496.125317121 5238302.80786469 440509.530410747 5238265.47373108 440546.684033701 5238178.72280403 440535.775152283 5238102.72378253 440465.895558396 5237981.47750861 440440.175602292 5237951.29128005 440424.893899722 5237941.22948069 440345.171513987 5237850.67090272 440336.919410036 5237789.73416911 440356.949868082 5237761.60853853 440384.69947114 5237743.54501877 440476.137710158 5237745.10373216 440613.796650775 5237794.47270553 440687.672693014 5237808.96955544 440763.735481931 5237800.52897406 440788.89097666 5237772.40312995 440810.292601431 5237629.9032299 440819.633772036 5237551.02838808 440871.316520024 5237398.08980561 440940.623532631 5237219.46316716 440970.183512161 5237137.96250331 441047.899395154 5237035.58498744 441135.08212044 5236874.51997715 441192.234670401 5236752.08094346 441214.451439632 5236688.39295611 441221.574781394 5236665.73814057 441285.788072267 5236461.51653938 441289.722091617 5236357.32958354 441261.282853973 5236311.89357319 441220.343959355 5236279.33299498 441062.560589792 5236250.46474664 440986.215969461 5236241.09298271 440924.933185458 5236208.72075081 440741.335777967 5236139.54135676 440715.647163772 5236111.91761485 440723.209458194 5236104.16735379 440672.333934418 5236099.54450094 440641.018489675 5236018.6088612 440630.172535218 5235955.29724899 440644.732999327 5235891.54708265 440669.669049976 5235843.04637898 440644.043191708 5235822.98508389 440658.729086492 5235772.04732342 440662.725529522 5235665.29789207 440623.283412227 5235536.2379243 440584.280417695 5235455.3651075 440575.495354601 5235343.67874378 440625.116849115 5235228.80246467 440702.425348697 5235093.42516809 440714.658382803 5235063.58900382 440714.674431357 5235063.54986167 440722.298861412 5235044.98717064 440724.516683928 5235016.92477053 440706.359116846 5234981.55077171 440642.85860784 5234979.74093689 440546.702907181 5235016.30720196 440484.297972655 5235068.62194755 440484.263266197 5235068.65108297 440405.67463157 5235134.62477446 440365.300209635 5235160.37628181 440324.957127734 5235188.81526885 440284.519951066 5235207.00433058 440208.237848106 5235197.69507939 440159.517234211 5235152.38492862 440161.735149471 5235127.01001267 440187.014841593 5235075.19681752 440187.022127705 5235075.18185581 440213.981925731 5235019.82107614 440306.697122824 5234894.38057269 440379.632892236 5234827.50298701 440470.412787053 5234768.12460166 440533.631107711 5234742.12213731 440571.442747795 5234708.6207866 440680.035343596 5234651.61663597 440747.75181527 5234569.73936387 440772.531006692 5234503.36378106 440718.215156819 5234414.99165994 440669.494548843 5234369.8065099 440572.962490945 5234365.74808085 440395.368248681 5234387.88036666 440258.148422701 5234384.26113899 440207.21024784 5234374.70083887 440158.583734338 5234339.64061923 440122.29985871 5234268.8301315 440119.173049981 5234215.51813306 440090.670904486 5234157.39473195 440074.138911785 5234138.6455555 440057.231910311 5234119.70889619 440001.262363279 5234107.46132857 439930.450422999 5234138.77657961 439849.71068062 5234198.21055297 439849.701854857 5234198.21704977 439695.985829721 5234311.47269851 439632.391316819 5234301.85043114 439591.201679903 5234246.4775473 439577.667707645 5234167.85366846 439576.006009139 5234005.22988334 439578.035745568 5233959.54261979 439546.751743926 5233883.66946714 439535.469896253 5233868.1075504 439520.969136584 5233848.35829837 439369.61973713 5233710.30312965 439200.363211198 5233549.43638284 439160.610433611 5233474.3135878 439153.066707842 5233460.85403865 439083.792839363 5233337.25529365 439056.164919099 5233255.31953942 439041.192180802 5233161.75846476 439086.493357043 5232881.88395102 439135.611899983 5232718.75830086 439126.637497383 5232584.25982799 439087.351361412 5232472.88740837 438992.001659106 5232344.39243787 438968.875465424 5232319.20610378 438833.747659715 5232272.33706153 438805.809995006 5232272.65070901 438735.186365234 5232316.59075578 438697.218125769 5232334.77967178 438581.50288598 5232437.59611368 438548.597067155 5232453.1598485 438515.283108483 5232423.03646631 438507.281591136 5232387.53708028 438580.865386734 5232135.2860753 438638.801335452 5232088.97157379 438762.643389194 5232029.27948903 438818.142025621 5231988.0275591 438848.360110935 5231967.46399434 438875.325116093 5231873.15117868 438873.841266481 5231851.6369036 438873.355169078 5231844.58899715 438869.352748842 5231786.83964154 438848.694907786 5231751.52827589 438696.03694936 5231732.78463683 438675.661519899 5231725.4105251 438647.284570385 5231682.47452698 438638.686987563 5231591.1006173 438672.64951322 5231435.78800661 438720.084119182 5231359.09922028 438780.864757263 5231335.65946491 438821.396122206 5231332.65785774 438913.022363814 5231349.52902715 438978.929458025 5231360.46378004 438984.304531395 5231361.46355502 439114.338608571 5231410.89539182 439185.652136542 5231425.39238962 439248.117312359 5231330.70319233 439257.990989991 5231297.57808319 439275.145003773 5231241.51538211 439297.016099857 5231144.82784887 439305.697711813 5231002.4537472 439260.376607367 5230802.33230114 439216.184637924 5230701.0849359 439225.713398765 5230640.08508735 439245.430025552 5230586.52227234 439441.359505498 5230368.57895915 439466.16989883 5230314.95346074 439468.261750086 5230269.2662857 439438.739566986 5230181.57815323 439434.132329078 5230167.89352542 439425.225553461 5230156.4564756 439408.443325912 5230135.20732065 439382.095837913 5230049.08411184 439406.905915137 5229987.95868446 439500.059319369 5229908.20576649 439625.679705032 5229782.38951951 439670.833827792 5229726.07578102 439678.427328598 5229719.20054957 439731.769341654 5229671.26142325 439731.775551865 5229671.25583629 439776.580378828 5229630.94756117 439951.674516426 5229618.94090755 440225.015363138 5229517.11882869 440336.264049925 5229472.73997381 440452.637757724 5229428.36093118 440523.417927887 5229394.48354551 440543.510915306 5229374.10797608 440619.008348185 5229304.66827219 440653.786417605 5229225.60523348 440688.250898201 5229120.97996977 440778.277048724 5228990.60286 440792.899522296 5228929.47792629 440774.490707801 5228871.16671833 440704.798275231 5228762.73295662 440707.0783475 5228734.73315326 440724.577452884 5228711.73272466 440938.07878393 5228719.59957889 440982.609893299 5228711.41048132 441011.578557547 5228706.22194098 441128.485624857 5228712.59245844 441166.705078667 5228724.90338483 441182.331551983 5228757.71494788 441137.30314561 5228829.34089773 441125.337268149 5228898.02812966 441121.404298563 5229004.71465878 441157.626134058 5229072.96256135 441216.34623029 5229097.83505936 441307.815379263 5229096.76908142 441335.408165425 5229071.08080381 441362.309971006 5228964.08092637 441369.464518175 5228923.45609055 441377.339160205 5228914.20589085 441375.884759661 5228519.21018982 441365.863750525 5227298.78616829 441362.816500156 5226925.22778895 441353.32899797 5226487.98282069 441334.385239866 5225613.43036079 441330.001586979 5225411.68267304 441327.747107756 5225307.24636884 441305.316984763 5224021.76087509 441299.678154161 5223699.26450647 441286.810453585 5222411.9036632 441283.609245141 5222092.28217366 441270.835642402 5220813.67119782 441267.540172935 5220482.29982725 441265.859079109 5219175.40754827 441265.471236449 5218876.31699548 441267.821811269 5217580.29948915 441268.401594674 5217255.3341868 441258.191667242 5216733.34001911 441237.333320755 5215666.35190995 441227.842303915 5215148.2014038 441208.265160845 5214080.36946304 441195.274251281 5213564.59398568 441168.196807764 5212489.38722958 441156.02005255 5212012.08004007 441127.127687256 5210880.40508843 441117.388581936 5210406.78527438 441094.058619425 5209273.42265027 441092.101754418 5208823.73991009 441086.988839287 5207653.43979129 441092.937830809 5207196.00699117 441107.919134768 5206040.4563889 441099.180074391 5205568.61773998 441076.86011304 5204365.48110994 441068.033916685 5203923.5198378 441044.810329775 5202759.50826854 441038.390380076 5202318.23443591 441022.763161913 5201240.53378684 441015.248841091 5200779.38528998 440996.713401008 5199638.56070505 440997.788580086 5199042.66427922 440999.66263242 5198009.587543 440997.677376318 5197479.59631226 440993.611925358 5196381.61446136 440987.346268008 5195878.46659537 440973.561784197 5194770.64128997 440965.045984715 5194262.9622736 440946.511668596 5193160.66818059 440937.027880396 5192677.64501441 440915.462465655 5191580.69461056 440913.290734644 5191084.45276957 440908.411922532 5189960.72122732 440898.739585907 5189444.7298283 440878.361997923 5188359.74790141 440868.844368726 5187794.75728581 440851.311907451 5186754.77454703 440840.168994679 5186181.03408972 440820.262004985 5185156.80111335 440808.556140411 5184569.02963089 440788.211689919 5183546.82785545 440447.274474624 5183551.58421118 439133.213072692 5183569.8587156 437519.214606452 5183597.88873491 435909.216377732 5183632.91857415 434321.217792016 5183656.94819719 432729.219448619 5183687.97779001 431126.220916499 5183713.00771019 429532.222317095 5183736.03751201 427926.224039936 5183768.06739585 426250.225657675 5183796.09869613 424640.227328401 5183826.1287231 423021.215323013 5183838.14759326 421418.182848745 5183803.15020699 419845.153118906 5183829.1516743 418239.122759583 5183856.15320425 416630.092083367 5183876.15490039 415034.06331545 5183946.15575987 413468.035170976 5184019.156598 411927.0077774 5184102.15730687 410320.977603268 5184140.15890349 408731.947575327 5184173.16060055 407127.917199638 5184205.16237558 405509.88661979 5184240.16416644 403893.850467498 5184279.17067505 402376.809351054 5184305.18266293 400767.765827735 5184336.19538155 399155.722151603 5184365.20819777 397568.67961072 5184411.22069788 397484.635123672 5182839.23587902 397438.590081989 5181207.25121208 397410.545932918 5179591.26622548 397351.500174909 5177964.28589945 397292.452470757 5176353.32576343 397156.403121981 5174745.3656852 397136.356979965 5173154.40478628 397080.309523306 5171545.44435402 397070.262855338 5169930.48393691 397074.216493664 5168318.52340502 397059.169441951 5166697.56308368 397026.153268514 5165076.32148286 397524.818123527 5165067.79049237 398121.172223473 5165059.66575611 398079.094836043 5163519.64134919 398074.045935741 5161865.68223921 398059.997632782 5160238.72242226 398075.949416946 5158601.76287673 398049.901485214 5156996.80243326 398044.852873508 5155360.84277007 398061.802940095 5153673.8844116 397990.753525199 5152039.92440306 397986.706260507 5150439.96320876 397981.694931268 5148843.95455868 397971.683228179 5147199.94555985 397972.671962545 5145598.93676736 397962.660579673 5143995.92785993 397947.649143106 5142391.91887313 397932.637595763 5140770.90973277 397907.625956819 5139153.90054444 397871.614199177 5137540.89132351 397847.602616648 5135930.88208476 397841.591240943 5134313.87274973 397844.579951222 5132687.86328606 397831.568827347 5131116.8540907 397799.55716051 5129508.84465574 397772.545330568 5127866.83496574 397769.602433453 5127095.8616232 397766.539781408 5127081.11154329 397761.664540702 5127057.83016732 397741.664049093 5127033.83007812 397721.601028402 5127005.82996553 397703.850524161 5126974.8298291 397690.850103905 5126944.82968593 397670.912112201 5126920.82959777 397657.786647643 5126884.82941976 397649.473768279 5126849.82923463 397645.004726745 5126818.4540605 397643.3483687 5126806.828996 397635.035482062 5126770.82880521 397628.847581176 5126727.82856701 397627.534752913 5126683.82830922 397618.971812944 5126640.82807793 397612.783911683 5126597.82784006 397604.4710243 5126561.82764997 397591.595617786 5126533.82752065 397578.407636095 5126495.82733311 397565.46972113 5126466.82719851 397545.344180905 5126436.82707907 397527.781224448 5126412.82698805 397507.593182574 5126382.82686947 397494.655252618 5126351.82672409 397474.529718163 5126322.82661191 397471.34202389 5126302.60775191 397468.529352856 5126284.82640523 397460.091433225 5126244.8261941 397454.091060634 5126205.82598176 397445.590639645 5126165.82577112 397444.027755832 5126114.82547489 397438.089904983 5126078.82528037 397425.151973375 5126047.82513668 397397.963862016 5126024.82508369 397373.463344054 5126008.82506407 397344.087731071 5125990.82504784 397305.337011941 5125979.82510165 397269.086369297 5125973.82517735 397233.335833894 5125981.82533342 397202.647953329 5125999.82553214 397179.272708267 5126019.82571988 397160.553757661 5126035.20086627 397148.834882151 5126044.82595783 397132.772294143 5126069.82615172 397121.772332701 5126100.82636484 397103.334705913 5126125.82656536 397092.459782577 5126161.82680651 397081.647381872 5126200.82706453 397075.835099479 5126244.82733626 397072.147795239 5126280.82755525 397067.835406618 5126306.42146587 397066.08545198 5126316.82778114 397062.648201959 5126359.82803953 397056.585866089 5126396.82827085 397045.710944138 5126432.82851025 397027.460872742 5126464.82874777 397016.460920688 5126496.82896388 396993.21071066 5126520.82916915 396969.772954926 5126538.82934018 396939.022558013 5126553.8295148 396898.396942019 5126560.82967184 396855.458795444 5126568.82984108 396819.083119819 5126557.82988318 396792.082547279 5126539.82985873 396774.519586055 5126515.82977324 396754.581592814 5126492.82970056 396734.393537423 5126461.82958359 396716.643028971 5126431.82946552 396696.454972903 5126400.82934927 396683.579551284 5126371.82922318 396670.579120159 5126341.82909202 396659.078702435 5126310.297698 396644.515705503 5126274.82879108 396631.390228143 5126238.82862717 396618.389788858 5126207.82849133 396605.264318258 5126172.82833358 396596.701364704 5126129.82811725 396590.826006225 5126093.82793236 396582.263052331 5126050.82771637 396576.075137571 5126007.82749328 396574.949857411 5125971.82729413 396573.637016015 5125927.82705053 396577.261814638 5125891.82683664 396595.511885163 5125859.8265997 396606.574358413 5125830.8264017 396629.824563343 5125805.82618797 396647.319162537 5125787.41633249 396496.946542206 5125694.16972709 396265.286206196 5125662.98278777 396160.816273646 5125738.57728593 396134.753495823 5125759.67123408 396052.504443825 5125823.62741535 396003.377069077 5125861.82845485 395945.971110523 5126029.07954184 395968.784521861 5126100.82986161 396043.817816002 5126209.1427239 396069.754253405 5126270.44142693 396082.850393495 5126301.39311046 396095.748378117 5126315.60244372 396095.756961454 5126315.61189973 396148.758271506 5126374.73706626 396293.917828993 5126499.7373284 396410.233127903 5126621.23766537 396495.391869976 5126771.61326048 396477.236287709 5126903.7390479 396447.01740699 5126953.27065725 396386.798790024 5127105.33416577 396321.236427432 5127269.05399634 396229.298063942 5127353.99220683 396131.015871768 5127441.55544318 396115.829386175 5127462.17909169 396115.828279149 5127462.18059506 396066.015476462 5127529.80609163 395983.734586901 5127756.49502677 395923.733826088 5127783.74532406 395777.326113984 5127902.27757212 395777.308245804 5127902.29204828 395726.294356848 5127943.62166756 395549.292459624 5128067.5602533 395353.352636097 5128173.62377797 395211.19494155 5128281.09341984 395079.411735468 5128299.68757608 394960.878470623 5128283.28152324 394781.906211452 5128198.87527613 394617.215350449 5128105.37520948 394538.216159199 5128051.72570248 394430.805121636 5127978.78129481 394333.866057581 5127977.43777842 394248.209101525 5128061.40714611 394197.834475444 5128209.75173291 394146.054233813 5128439.94045916 394112.617113715 5128554.12858191 394090.929403945 5128570.94121182 394060.054237649 5128611.37897475 393913.240703544 5128772.19256588 393830.17833932 5128951.81859017 393716.803734575 5129221.19508348 393649.741102212 5129334.41449471 393593.271673627 5129359.63347651 393541.208155385 5129334.6334693 393522.332596165 5129302.28961079 393502.519354101 5129249.38316098 393485.268439118 5129170.44533793 393460.892125407 5129056.50737175 393434.734730461 5128966.81952098 393406.827666262 5128921.06937453 393281.887002488 5128775.88149651 393162.478318341 5128709.72521971 393074.570595567 5128699.94412585 392948.131162291 5128708.25694998 392938.886078307 5128717.09598999 392938.881089356 5128717.10075982 392869.349294331 5128783.78870889 392856.131338188 5128904.03926276 392869.788619186 5129001.85215899 392921.040097872 5129082.50864999 392939.594223998 5129096.3771071 392939.603005278 5129096.38367075 393010.885818893 5129149.72750229 393111.387893415 5129209.66505377 393203.984079088 5129328.85288977 393215.891632466 5129464.35346913 393173.016630795 5129545.26016531 393150.858439436 5129570.56502282 393036.140792715 5129701.57362622 393002.98422843 5129725.82379725 392941.396243187 5129736.47843803 392903.451574447 5129743.04281602 392753.699271544 5129746.01187008 392503.539385536 5129775.94998378 392399.632345048 5129873.1693424 392239.412465554 5130032.26405602 392210.100676357 5130168.70217224 392213.070651679 5130306.92148529 392219.540503596 5130424.39070673 392209.916467398 5130554.61000795 392149.072499686 5130638.14170229 392048.790525459 5130732.51725212 391875.069984154 5130832.39293655 391663.504815478 5130896.51853027 391580.222853181 5130960.33141186 391436.940407299 5131072.70707042 391358.345878462 5131119.9261223 391358.337790057 5131119.93098495 391332.095618879 5131135.70747265 391169.843461014 5131170.05160012 391090.329432917 5131198.60780057 391090.311258207 5131198.61432773 391004.028975747 5131229.58332307 390870.621635629 5131333.89640539 390701.182026774 5131384.3968375 390459.210143678 5131442.20989569 390404.616155957 5131506.96020143 390404.773253846 5131600.33552766 390419.305721358 5131710.67964326 390412.243757333 5131781.58615058 390338.024937405 5131896.52414872 390204.523538589 5131962.2745484 390046.80271229 5131993.02485559 389913.988072682 5131976.18122009 389735.78932966 5131895.87789917 389735.42215901 5131895.71243772 389716.515360771 5131867.05611908 389571.981062729 5131772.08725552 389506.51136487 5131775.83735682 389479.604770387 5131782.21241387 389234.03940457 5131869.58802097 389096.006383826 5131901.213303 388922.035336683 5131933.83863323 388773.189300139 5131927.77631271 388634.030436623 5131872.40133634 388526.340893101 5131827.68260284 388437.463981855 5131767.6200527 388351.21178844 5131674.49490861 388256.834163314 5131549.83844281 388149.08215691 5131510.58849153 388127.769379886 5131515.21353581 388127.399562769 5131515.29264081 388069.331118797 5131527.71365645 388022.768344655 5131571.80759559 387956.643615577 5131701.96429489 387902.206568144 5131832.24597249 387809.018355722 5131902.40253741 387683.516554347 5131910.62147954 387590.171097294 5131879.4340258 387503.856283962 5131776.34013029 387426.478629891 5131625.71485673 387356.320156636 5131508.18341269 387263.786609173 5131417.74582555 387182.780887846 5131291.45026806 387182.409113164 5131290.87063628 387177.44021241 5131283.30812538 387127.000702834 5131158.62039828 387071.99810947 5130982.80755732 387039.590880763 5130934.40124346 386913.932180852 5130881.58882868 386890.025426821 5130867.80758648 386778.398073713 5130803.74512643 386670.708572628 5130768.96398226 386582.706761838 5130723.37028123 386497.674054816 5130708.37039707 386497.663885286 5130708.36860975 386492.517716472 5130707.46415414 386475.986184474 5130704.68292709 386341.452834485 5130701.27690786 386253.63935409 5130737.27714263 386147.951236715 5130835.27754052 386056.543827963 5130858.77774916 385983.85493916 5130831.99656867 385948.760142974 5130782.65277654 385908.258559579 5130689.3714036 385903.444393696 5130535.05859079 385896.787461117 5130478.83973587 385888.9116599 5130412.96461326 385852.847603138 5130316.15198014 385777.314182535 5130219.30817553 385722.469283381 5130190.43322317 385648.123974982 5130151.37078959 385475.682733631 5130049.2459285 385294.460745839 5130009.18371524 385092.770554928 5130051.68420095 384884.862006922 5130139.96602552 384880.021818156 5130140.61623874 384702.015678741 5130164.52893091 384570.919338906 5130112.6541042 384489.198661461 5130051.27916677 384432.354144517 5130014.24695822 384365.384582075 5129979.05834044 384256.071374883 5129978.46283999 384095.632846489 5129978.49152223 383967.631733082 5129951.80193996 383901.537153416 5129914.83208574 383870.442760021 5129874.39403732 383834.973140548 5129815.95589644 383818.316026528 5129747.01804328 383817.347899687 5129745.05059834 383817.347248667 5129745.04927532 383794.44034032 5129698.54885066 383712.031781964 5129536.95358107 383616.686453127 5129449.63944961 383467.309981205 5129404.13700936 383343.559376889 5129422.29130741 383185.264346579 5129474.58983867 383172.933891244 5129478.66365389 382432.112672226 5129129.30767849 382050.545617803 5128946.48889483 381930.669198259 5128890.45567463 381813.761564185 5128836.01625451 381555.44536519 5128886.57970874 381368.697109312 5128923.13427606 381021.946477756 5129068.91016897 380846.041160551 5129252.40756313 380614.072408873 5129385.43525726 380507.415444003 5129383.96480723 380366.976564238 5129343.80628053 380170.662848542 5129349.99066149 380077.944277665 5129418.39550277 380040.790213423 5129629.4263673 379955.47919401 5129806.17517836 379954.121354302 5129807.34346081 379915.854329741 5129840.26832905 379915.841474504 5129840.2793996 379794.292249493 5129944.95398924 379279.665993473 5130123.85218926 378897.416206212 5130353.6275367 378366.6809587 5130916.98226256 378366.669410609 5130916.9945204 378237.170204929 5131054.46130696 377947.108891135 5131310.67560811 377506.601105877 5131497.25225083 377506.577075931 5131497.26242869 377469.077028666 5131513.13683829 377272.357976651 5131591.66498638 377034.074980805 5131570.78614464 376768.355508367 5131649.93818213 376762.104174374 5131658.76955849 376695.137538811 5131753.37457609 376657.888268789 5131833.68653146 376593.7950704 5131913.02930396 376523.576565284 5131969.90321229 376404.419467585 5131961.21379023 376265.792989486 5131910.33652847 376138.384541883 5131794.20940704 376002.693305361 5131555.42582811 375983.661649708 5131533.08106143 375893.25356053 5131426.92399242 375744.783231971 5131374.14032947 375599.438955512 5131406.57551903 375531.627207405 5131503.76198948 375519.971366165 5131543.44932595 375519.969779084 5131543.45472667 375497.784644065 5131618.94901437 375472.066917037 5131716.38615851 375393.12918816 5131738.35365392 375292.127979765 5131691.28950564 375215.439271748 5131631.81949125 375151.469708879 5131598.25594608 375151.466609136 5131598.2543156 375141.2508288 5131592.88077914 375081.032066892 5131623.00482986 375032.908051499 5131728.37911571 374983.628283286 5131874.87840432 374901.879817448 5132042.06468055 374671.819852731 5132365.71739828 374385.573430713 5132800.46300037 374334.449073106 5132878.08721254 374251.043722939 5132992.52342011 374211.887897763 5133046.36656284 374110.638995748 5133185.33374073 374110.628800055 5133185.34772794 374100.639104321 5133199.05233533 374058.889312703 5133236.48917747 374004.170838717 5133285.73831497 373785.326565466 5133350.95355605 373598.668780583 5133318.79427626 373493.324466251 5133324.98007656 373445.043516532 5133372.69806519 373307.606872866 5133508.38339578 372977.297673735 5133932.09695315 372790.173713299 5134104.59397872 372790.170162929 5134104.59724814 372775.955042474 5134117.68750249 372616.612187284 5134264.74746524 372415.738702513 5134480.15052 372296.050727994 5134498.89858207 372182.611876215 5134445.24047566 372110.235077686 5134337.05177184 372038.734154073 5134297.76935155 371981.640729843 5134350.42468931 371910.20526255 5134544.45482948 371871.615119463 5134847.01677682 371871.613784306 5134847.02728489 371870.177754423 5134858.32925617 371825.681054914 5135139.17234848 371732.870849389 5135362.63963708 371632.871459507 5135456.4505272 371498.902091211 5135469.07334565 371358.618872436 5135378.66479156 371231.74097487 5135209.69394335 371179.165366849 5134977.74499291 371171.737240818 5134944.97416816 371149.550387032 5134864.23037611 371149.54857798 5134864.22379249 371102.921133998 5134694.62925355 371045.605330146 5134462.97203032 370950.884457963 5134341.37672201 370801.727018197 5134318.18680016 370567.694307639 5134313.58925654 370355.194118364 5134397.67957449 370170.318219683 5134413.73907981 370049.723713777 5134411.08087486 369743.345798776 5134327.79465235 369517.516662406 5134301.45274707 369360.186666137 5134283.1009439 369208.373999229 5134340.25473874 368975.278848685 5134340.25096428 368826.122522064 5134402.81105038 368532.309491415 5134496.65004185 368175.933545762 5134586.92551616 368028.589043977 5134596.79812841 367916.025289972 5134552.98380722 367905.228118526 5134542.16171798 367821.367215384 5134458.10728 367710.61665657 5134466.16798652 367475.710658418 5134591.3204227 367345.462794344 5134810.38079058 367239.401311117 5134934.12905694 367239.398405859 5134934.1324489 367221.307735114 5134955.25376096 367124.0914264 5135181.47090497 367082.156269516 5135375.50144765 366884.034768684 5135724.18567314 366793.943845536 5135974.49666413 366778.853974814 5136270.5276158 366807.978677004 5136463.10776126 366809.450611755 5136472.84057867 366824.57760034 5136614.80954984 366821.144583642 5136950.93443061 366845.334161347 5137095.80979895 366875.554018653 5137165.74778068 366875.804959058 5137235.8727713 366886.212501567 5137328.0291741 366923.08862478 5137396.46726575 366947.058138981 5137443.53015 366943.46508978 5137497.40508064 366978.653845522 5137576.56189309 367025.780404329 5137673.46889857 367073.093865672 5137725.68841608 367104.875728692 5137758.34518228 367121.626369416 5137799.34544999 367102.002053342 5137858.68886621 367050.877367345 5137903.3755169 366984.940474588 5137976.06191797 366918.191126759 5138052.34205411 366879.389001928 5138103.86746532 366856.816879829 5138133.84102677 366808.567344957 5138188.37147059 366781.879859463 5138200.4022785 366723.879623085 5138206.55757204 366647.597692618 5138187.11882044 366589.003223451 5138157.58661265 366536.397323923 5138113.34832342 366535.564825097 5138112.64824369 366485.313702831 5138049.80368183 366453.312870236 5138001.05316715 366416.593619779 5137978.95881858 366416.587707755 5137978.95525782 366386.499459196 5137960.83332812 366339.185982065 5137907.73881331 366288.122364621 5137845.83173942 366216.683841031 5137799.36182728 366108.557463946 5137741.9225659 366029.025822986 5137745.79625858 365970.026257097 5137802.23277408 365930.277242936 5137891.48209619 365920.371655258 5137944.51316849 365932.841234391 5138000.70085767 365960.811103591 5138072.01379758 365972.686771742 5138116.57648041 365972.687422175 5138116.57892797 365975.061905694 5138125.51401698 365972.469001608 5138189.13895637 365940.282070582 5138244.32591086 365898.688475529 5138272.70021792 365827.313242323 5138284.48028935 365732.281270375 5138269.79122924 365647.405031084 5138212.88359962 365569.934628535 5138122.63235302 365567.655039181 5138116.57448271 365567.653283612 5138116.56981739 365527.901621939 5138010.41294692 365499.08722652 5137882.66251335 365474.398328754 5137789.91213682 365400.896571652 5137690.84846121 365376.365258986 5137684.03591527 365333.990003365 5137661.53583604 365283.864981056 5137655.28574247 365239.771714256 5137686.41065965 365197.397982532 5137774.94182825 365179.555719593 5137881.72304155 365166.307346518 5137999.16051247 365161.902624819 5138110.22299993 365160.902713005 5138116.56674776 365160.902198506 5138116.57001858 365149.778695896 5138187.28547338 365117.904723126 5138259.47290813 365048.404931382 5138268.69152207 364993.341983506 5138231.22266712 364917.278734731 5138169.87877381 364875.965555283 5138116.56689138 364867.996674336 5138106.28493355 364801.183660132 5138062.75355874 364798.97112409 5138062.28804314 364750.089825187 5138052.00346172 364711.183923816 5138074.09713491 364666.187346678 5138118.2502155 364662.872128751 5138121.50328703 364641.967104594 5138209.56573682 364635.062474466 5138327.78445968 364649.313931514 5138435.87822487 364689.065706344 5138569.37828793 364696.285289058 5138631.03454516 364658.223828381 5138704.12821014 364605.78730269 5138771.34684599 364544.225664251 5138829.62796356 364490.91345493 5138846.69035307 364423.038507611 5138845.0964658 364356.851023245 5138840.90883246 364313.007271247 5138837.22124436 364281.069995494 5138851.15867724 364260.289258966 5138887.31487852 364263.47720422 5138920.37737891 364314.665608134 5138991.03372048 364391.104176879 5139075.7213625 364468.574177013 5139173.69025623 364493.012619355 5139244.84654557 364487.076089082 5139315.69027176 364439.077085231 5139385.34640949 364394.734339416 5139455.94005373 364319.141655568 5139528.87738026 364216.486331473 5139589.62715005 364095.080909628 5139641.93937995 363959.643840167 5139663.97033556 363868.425079219 5139656.56389265 363818.924788449 5139631.43879367 363808.392994932 5139590.40753212 363823.485954133 5139532.93882924 363839.172370844 5139453.87638284 363837.827523682 5139372.53265086 363841.545639761 5139325.87642051 363818.638210236 5139236.7826455 363785.481169167 5139175.62634255 363716.855629066 5139130.25121296 363615.824412883 5139124.84475658 363521.76249225 5139160.5008027 363371.857973439 5139277.59420678 363243.796764983 5139363.9689119 363237.626104089 5139370.40515816 363243.364277513 5139737.56253265 363288.385949383 5141356.56204431 363326.407379677 5142957.5615029 363362.428937446 5144568.560907 363393.450473892 5146178.56025039 363423.472146704 5147799.55953667 363462.493638907 5149407.55881229 363508.51540958 5151036.55805747 363525.541458662 5152632.54365357 363546.568453368 5154268.52794437 363567.595379654 5155902.51222113 363588.622172094 5157530.49652267 363626.648776953 5159144.48095067 363644.675349591 5160763.46526335 363661.701697692 5162371.44965229 363685.728248551 5163991.43389613 363709.754736729 5165609.41812413 363291.783016622 5165620.07441053 363315.77770652 5167225.40265729 363337.803609773 5168831.38711532 363364.829545382 5170438.37152247 363394.855248387 5172030.35603161 363427.881124527 5173632.3403966 363454.906150243 5175186.32520418 363467.932862727 5176859.30886258 363504.95904189 5178481.29290082 363550.977890328 5180075.29164102 363580.994093155 5181701.29615338 363611.010184343 5183316.30059055 363641.026261061 5184930.30498119 365281.047940272 5184892.29791889 366907.07038705 5184868.29350236 368514.094609698 5184840.29551664 370108.118282876 5184782.29747898 371712.142246418 5184739.29951398 373341.166495797 5184691.30160356 373382.189451016 5186298.30396487 373391.212936974 5187983.30635824 373441.235923314 5189582.30862248 373500.258375488 5191128.31076725 373541.281566533 5192751.31295644 373588.304614556 5194354.31507048 373653.328067132 5195956.31712917 373679.350870619 5197573.31916324 373718.373690395 5199170.32112234 373765.39676851 5200771.3230325 373810.419975119 5202384.32490804 373864.442539376 5203931.32664582 373465.40057681 5203942.92090823 373500.454499719 5205564.32904337 373528.486156668 5207158.32407421 373555.531914217 5208769.30919172 373587.577486548 5210369.29435633 373634.623218261 5211958.27954698 373683.669690791 5213571.26446363 373729.716095648 5215185.24932957 373769.762010239 5216789.23425526 373804.807979489 5218402.21906225 373825.852371883 5219978.20420591 373804.895460481 5221568.18928244 373851.941887044 5223185.1738895 373909.988276518 5224784.15858966 373945.033749309 5226384.14329541 373981.079382714 5227989.12790541 374019.124894757 5229587.11253092 374045.169847411 5231185.09714693 374094.216351173 5232802.08146562 374128.26138167 5234373.06628169 374141.315162816 5235996.05154401 374166.369620794 5237623.03668185 374208.423516773 5239209.02210155 374251.477236066 5240789.00753324 374283.530978323 5242386.43028713 373681.502561762 5242386.55653017 373719.557267099 5244003.97891204 373769.611971478 5245604.9638833 373819.667365047 5247227.94860987 373878.722823408 5248840.93337997 373941.779351181 5250481.91784665 373992.834567751 5252100.90249579 - - - - 441092.101754418,5208823.73991009 441972.032773827,5208775.41142816 443587.033226362,5208743.38172553 445198.051095369,5208718.35237246 446806.068363107,5208679.32334738 448644.087087741,5208608.29073645 450247.104615585,5208574.26195256 451834.124374432,5208602.23232861 453438.144212413,5208629.20233618 455033.163135423,5208636.17288165 456597.180129897,5208600.14499324 458225.198505544,5208581.11560367 459821.21517858,5208522.08790625 461439.233700543,5208509.05869865 463040.246910989,5208498.99806743 464622.256143646,5208453.92261524 466193.264646374,5208387.84811905 467933.276195024,5208379.76399427 469529.286922469,5208375.68679552 471117.297912188,5208380.60985085 472733.308665441,5208371.53186471 474328.319527427,5208369.45480206 475930.330365635,5208364.37748519 477560.337852849,5208249.30028279 479172.346439863,5208171.22321294 480784.356447228,5208136.14551495 482340.360106787,5208086.1204854 483907.362597763,5208023.10295594 485482.366095061,5207990.08506313 487695.37368665,5208030.05902892 489296.378898243,5208051.040287 490905.384432413,5208083.02133299 492543.389047529,5208082.00243547 494141.393716148,5208086.98394688 495747.398906727,5208109.96516074 495711.353257682,5206502.98535492 495676.309926805,5204889.00866588 495650.279726696,5203296.04675013 495637.248778541,5201663.08557362 495611.218295986,5200062.12367648 495603.188010644,5198467.16141745 495560.156779411,5196842.20002694 495564.126526155,5195247.23755609 495524.095615327,5193646.27538485 495503.064321413,5192017.3136871 495446.03275704,5190405.35159924 495420.002151849,5188825.38856517 495394.971242756,5187232.42574426 495375.93995181,5185617.46334803 495368.909626316,5184043.49993398 495340.878395801,5182446.53695695 495346.84729782,5180821.57463446 495302.815676504,5179229.61132198 495238.783334567,5177631.64792968 495199.767500209,5176019.63582349 495197.755906868,5174450.61531256 495162.742991802,5172830.59400039 495126.729927639,5171207.57265376 495067.716229818,5169609.55161623 495088.705029187,5168017.53073455 495086.692865267,5166393.50936063 495112.681912028,5164799.4883054 495107.669755823,5163187.46698448 495145.659310535,5161586.4456535 495178.648737239,5159980.6429203 495797.673211287,5159977.23447586 495717.658886368,5158361.40025725 495738.648547533,5156735.37796876 495734.637160115,5155107.35571706 495746.626973123,5153550.33429246 495747.61601901,5151951.3123082 495770.605990571,5150333.28983519 495773.615683926,5148704.27380344 495760.64120287,5147100.26336865 495755.667156541,5145494.25280909 495748.693082425,5143884.24220147 495748.719955069,5142239.23124588 495769.747660932,5140613.22013602 495815.776178388,5139024.20891946 495828.803448126,5137406.19781468 495830.829879582,5135804.18689701 495858.858328788,5134171.17538212 495862.885291437,5132548.16418396 495864.911866238,5130943.15308686 495858.938034687,5129335.14203562 495883.965846267,5127742.13058836 495856.990847918,5126129.11972733 495850.017037609,5124518.10854358 495835.043321767,5122871.09719571 495822.057922962,5121293.10356628 495835.052794276,5119689.14462307 495835.046800069,5118075.18610661 495827.040391883,5116474.22734309 495830.03459665,5114867.2685059 495843.029308365,5113258.30950871 495834.022797801,5111638.35111148 494234.941171807,5111635.37770315 492634.859519821,5111644.40406969 490947.773415802,5111651.43200419 489445.696786071,5111649.45714681 487838.614772884,5111656.48387701 486177.529781002,5111689.51091615 484578.448198062,5111689.5378244 482966.365654519,5111715.56435322 481334.282092909,5111736.59141491 479721.221100558,5111770.63479686 478124.175610684,5111798.68941725 476457.129157939,5111754.7481173 474848.084947473,5111654.80580315 473223.039842219,5111578.86331326 471623.995501651,5111486.91997601 470034.951263299,5111396.97599809 468383.905221494,5111292.03408398 466657.856325405,5111261.0935366 466801.849456444,5112811.07011109 466840.839130967,5114420.0494352 466837.82780885,5116011.03046653 466825.816297009,5117602.01185281 466806.804704029,5119187.99361209 466796.788476539,5121475.96660114 465169.751832345,5121562.03758123 463582.716668467,5121567.10778504 461978.681115782,5121582.17868885 460382.654975318,5121633.22463705 458863.634782301,5121649.25671468 458729.164257097,5121647.19708141 457106.611589166,5121622.29420132 455534.590852865,5121594.3278256 453901.569310636,5121566.36280177 452150.546221549,5121533.40039558 450644.526317509,5121524.43260388 448848.502614519,5121502.47117366 447142.480120161,5121473.5079516 445555.459188838,5121450.54218051 444012.438820035,5121440.57537843 442433.41800387,5121415.6095591 440877.37695095,5121394.6590622 439268.330052994,5121375.71365614 438623.813339239,5121376.09834029 438608.466924173,5121441.5166267 438596.591390315,5121527.9850023 438582.028332704,5121589.10994768 438548.558156946,5121795.26548809 438546.089318335,5121802.82800448 438536.401429659,5121851.26540118 438496.493851218,5121925.35985063 438461.242758608,5121953.57955277 438377.709007713,5121979.89467277 438306.488190201,5121972.92841773 438237.736223155,5121953.39968798 438155.890192362,5121903.34042007 438058.606268627,5121828.21939093 438017.948835643,5121826.06454523 437838.380916,5121901.57002048 437750.12819346,5121963.47875683 437689.782536252,5122024.98029865 437649.749976677,5122084.512416 437637.155825486,5122098.543979 437614.748826392,5122138.54440989 437591.404435887,5122162.35790414 437549.528288354,5122205.1096879 437534.527896677,5122230.61041166 437527.027817008,5122305.58004155 437509.98489396,5122463.40794018 437519.278954217,5123033.77386323 437546.282736399,5124637.78625312 437573.286513144,5126246.79863957 437598.290210678,5127849.81099969 437625.294012361,5129486.82352584 437635.297323898,5131096.83636224 437641.300538971,5132700.84923972 437648.303832046,5134323.86219173 437665.307315615,5135919.8745398 437698.311182421,5137532.88643811 437718.314733817,5139136.89865929 437736.318211385,5140725.91078311 437725.321201069,5142354.92416177 437725.324428085,5143976.93706535 437726.327686801,5145591.94983279 437727.330981757,5147211.9625931 437702.333741618,5148765.97566464 437697.348137997,5150407.98503925 437791.389300783,5152014.98244466 437837.429981925,5153635.98146622 437843.469251102,5155223.98172365 437843.494396201,5156242.79447432 437843.509384072,5156849.98210987 437837.784713312,5157878.73248683 437834.549029165,5158459.98268407 437842.257240392,5159295.10758917 437912.69554087,5159295.9805468 438546.704763059,5159386.9622125 438820.677249212,5159416.79805414 438868.021643891,5159421.9529385 438955.523526871,5159460.20043565 439389.43905896,5159649.78182603 439428.658644014,5159666.93696318 439837.293205181,5159883.92545398 439920.105839013,5159851.92304252 439928.95258192,5159831.79768159 440168.295395738,5159825.88464183 440394.891556092,5159824.69064082 440428.731220104,5159825.84576899 440435.50090148,5160474.87791456 440441.639697625,5161063.90983245 440435.976045197,5162089.00518069 440432.67738969,5162683.9123425 440422.825660397,5163685.13271532 440416.715119515,5164306.91495392 440429.239983656,5165367.88476372 440435.75289353,5165918.916557 440442.465107261,5166975.79273044 440445.789838809,5167498.91830244 440467.877617866,5168576.200343 440478.827657615,5169110.91948283 440497.446274702,5170172.6390742 440506.865079036,5170708.92074466 440537.889487585,5171749.7025147 440553.902074748,5172286.92153435 440572.989475617,5173352.60984766 440582.9399676,5173908.92276828 440604.370555919,5174951.2984902 440615.977504472,5175516.92387936 440637.563766231,5176535.7995613 440650.014973456,5177123.92495227 440650.699677025,5178172.94869223 440651.06097089,5178732.9083982 440684.750599837,5179797.67179249 440702.111525844,5180345.88134396 440731.830135607,5181339.36469896 440750.161804751,5181951.85443125 440774.193317489,5182959.24389991 440788.211689919,5183546.82785545 440808.556140411,5184569.02963089 440820.262004985,5185156.80111335 440840.168994679,5186181.03408972 440851.311907451,5186754.77454703 440868.844368726,5187794.75728581 440878.361997923,5188359.74790141 440898.739585907,5189444.7298283 440908.411922532,5189960.72122732 440913.290734644,5191084.45276957 440915.462465655,5191580.69461056 440937.027880396,5192677.64501441 440946.511668596,5193160.66818059 440965.045984715,5194262.9622736 440973.561784197,5194770.64128997 440987.346268008,5195878.46659537 440993.611925358,5196381.61446136 440997.677376318,5197479.59631226 440999.66263242,5198009.587543 440997.788580086,5199042.66427922 440996.713401008,5199638.56070505 441015.248841091,5200779.38528998 441022.763161913,5201240.53378684 441038.390380076,5202318.23443591 441044.810329775,5202759.50826854 441068.033916685,5203923.5198378 441076.86011304,5204365.48110994 441099.180074391,5205568.61773998 441107.919134768,5206040.4563889 441092.937830809,5207196.00699117 441086.988839287,5207653.43979129 441092.101754418,5208823.73991009 + + + + 437509.98489396 5111261.0935366495883.965846267 5208823.73991009 + 441092.101754418 5208823.73991009 441972.032773827 5208775.41142816 443587.033226362 5208743.38172553 445198.051095369 5208718.35237246 446806.068363107 5208679.32334738 448644.087087741 5208608.29073645 450247.104615585 5208574.26195256 451834.124374432 5208602.23232861 453438.144212413 5208629.20233618 455033.163135423 5208636.17288165 456597.180129897 5208600.14499324 458225.198505544 5208581.11560367 459821.21517858 5208522.08790625 461439.233700543 5208509.05869865 463040.246910989 5208498.99806743 464622.256143646 5208453.92261524 466193.264646374 5208387.84811905 467933.276195024 5208379.76399427 469529.286922469 5208375.68679552 471117.297912188 5208380.60985085 472733.308665441 5208371.53186471 474328.319527427 5208369.45480206 475930.330365635 5208364.37748519 477560.337852849 5208249.30028279 479172.346439863 5208171.22321294 480784.356447228 5208136.14551495 482340.360106787 5208086.1204854 483907.362597763 5208023.10295594 485482.366095061 5207990.08506313 487695.37368665 5208030.05902892 489296.378898243 5208051.040287 490905.384432413 5208083.02133299 492543.389047529 5208082.00243547 494141.393716148 5208086.98394688 495747.398906727 5208109.96516074 495711.353257682 5206502.98535492 495676.309926805 5204889.00866588 495650.279726696 5203296.04675013 495637.248778541 5201663.08557362 495611.218295986 5200062.12367648 495603.188010644 5198467.16141745 495560.156779411 5196842.20002694 495564.126526155 5195247.23755609 495524.095615327 5193646.27538485 495503.064321413 5192017.3136871 495446.03275704 5190405.35159924 495420.002151849 5188825.38856517 495394.971242756 5187232.42574426 495375.93995181 5185617.46334803 495368.909626316 5184043.49993398 495340.878395801 5182446.53695695 495346.84729782 5180821.57463446 495302.815676504 5179229.61132198 495238.783334567 5177631.64792968 495199.767500209 5176019.63582349 495197.755906868 5174450.61531256 495162.742991802 5172830.59400039 495126.729927639 5171207.57265376 495067.716229818 5169609.55161623 495088.705029187 5168017.53073455 495086.692865267 5166393.50936063 495112.681912028 5164799.4883054 495107.669755823 5163187.46698448 495145.659310535 5161586.4456535 495178.648737239 5159980.6429203 495797.673211287 5159977.23447586 495717.658886368 5158361.40025725 495738.648547533 5156735.37796876 495734.637160115 5155107.35571706 495746.626973123 5153550.33429246 495747.61601901 5151951.3123082 495770.605990571 5150333.28983519 495773.615683926 5148704.27380344 495760.64120287 5147100.26336865 495755.667156541 5145494.25280909 495748.693082425 5143884.24220147 495748.719955069 5142239.23124588 495769.747660932 5140613.22013602 495815.776178388 5139024.20891946 495828.803448126 5137406.19781468 495830.829879582 5135804.18689701 495858.858328788 5134171.17538212 495862.885291437 5132548.16418396 495864.911866238 5130943.15308686 495858.938034687 5129335.14203562 495883.965846267 5127742.13058836 495856.990847918 5126129.11972733 495850.017037609 5124518.10854358 495835.043321767 5122871.09719571 495822.057922962 5121293.10356628 495835.052794276 5119689.14462307 495835.046800069 5118075.18610661 495827.040391883 5116474.22734309 495830.03459665 5114867.2685059 495843.029308365 5113258.30950871 495834.022797801 5111638.35111148 494234.941171807 5111635.37770315 492634.859519821 5111644.40406969 490947.773415802 5111651.43200419 489445.696786071 5111649.45714681 487838.614772884 5111656.48387701 486177.529781002 5111689.51091615 484578.448198062 5111689.5378244 482966.365654519 5111715.56435322 481334.282092909 5111736.59141491 479721.221100558 5111770.63479686 478124.175610684 5111798.68941725 476457.129157939 5111754.7481173 474848.084947473 5111654.80580315 473223.039842219 5111578.86331326 471623.995501651 5111486.91997601 470034.951263299 5111396.97599809 468383.905221494 5111292.03408398 466657.856325405 5111261.0935366 466801.849456444 5112811.07011109 466840.839130967 5114420.0494352 466837.82780885 5116011.03046653 466825.816297009 5117602.01185281 466806.804704029 5119187.99361209 466796.788476539 5121475.96660114 465169.751832345 5121562.03758123 463582.716668467 5121567.10778504 461978.681115782 5121582.17868885 460382.654975318 5121633.22463705 458863.634782301 5121649.25671468 458729.164257097 5121647.19708141 457106.611589166 5121622.29420132 455534.590852865 5121594.3278256 453901.569310636 5121566.36280177 452150.546221549 5121533.40039558 450644.526317509 5121524.43260388 448848.502614519 5121502.47117366 447142.480120161 5121473.5079516 445555.459188838 5121450.54218051 444012.438820035 5121440.57537843 442433.41800387 5121415.6095591 440877.37695095 5121394.6590622 439268.330052994 5121375.71365614 438623.813339239 5121376.09834029 438608.466924173 5121441.5166267 438596.591390315 5121527.9850023 438582.028332704 5121589.10994768 438548.558156946 5121795.26548809 438546.089318335 5121802.82800448 438536.401429659 5121851.26540118 438496.493851218 5121925.35985063 438461.242758608 5121953.57955277 438377.709007713 5121979.89467277 438306.488190201 5121972.92841773 438237.736223155 5121953.39968798 438155.890192362 5121903.34042007 438058.606268627 5121828.21939093 438017.948835643 5121826.06454523 437838.380916 5121901.57002048 437750.12819346 5121963.47875683 437689.782536252 5122024.98029865 437649.749976677 5122084.512416 437637.155825486 5122098.543979 437614.748826392 5122138.54440989 437591.404435887 5122162.35790414 437549.528288354 5122205.1096879 437534.527896677 5122230.61041166 437527.027817008 5122305.58004155 437509.98489396 5122463.40794018 437519.278954217 5123033.77386323 437546.282736399 5124637.78625312 437573.286513144 5126246.79863957 437598.290210678 5127849.81099969 437625.294012361 5129486.82352584 437635.297323898 5131096.83636224 437641.300538971 5132700.84923972 437648.303832046 5134323.86219173 437665.307315615 5135919.8745398 437698.311182421 5137532.88643811 437718.314733817 5139136.89865929 437736.318211385 5140725.91078311 437725.321201069 5142354.92416177 437725.324428085 5143976.93706535 437726.327686801 5145591.94983279 437727.330981757 5147211.9625931 437702.333741618 5148765.97566464 437697.348137997 5150407.98503925 437791.389300783 5152014.98244466 437837.429981925 5153635.98146622 437843.469251102 5155223.98172365 437843.494396201 5156242.79447432 437843.509384072 5156849.98210987 437837.784713312 5157878.73248683 437834.549029165 5158459.98268407 437842.257240392 5159295.10758917 437912.69554087 5159295.9805468 438546.704763059 5159386.9622125 438820.677249212 5159416.79805414 438868.021643891 5159421.9529385 438955.523526871 5159460.20043565 439389.43905896 5159649.78182603 439428.658644014 5159666.93696318 439837.293205181 5159883.92545398 439920.105839013 5159851.92304252 439928.95258192 5159831.79768159 440168.295395738 5159825.88464183 440394.891556092 5159824.69064082 440428.731220104 5159825.84576899 440435.50090148 5160474.87791456 440441.639697625 5161063.90983245 440435.976045197 5162089.00518069 440432.67738969 5162683.9123425 440422.825660397 5163685.13271532 440416.715119515 5164306.91495392 440429.239983656 5165367.88476372 440435.75289353 5165918.916557 440442.465107261 5166975.79273044 440445.789838809 5167498.91830244 440467.877617866 5168576.200343 440478.827657615 5169110.91948283 440497.446274702 5170172.6390742 440506.865079036 5170708.92074466 440537.889487585 5171749.7025147 440553.902074748 5172286.92153435 440572.989475617 5173352.60984766 440582.9399676 5173908.92276828 440604.370555919 5174951.2984902 440615.977504472 5175516.92387936 440637.563766231 5176535.7995613 440650.014973456 5177123.92495227 440650.699677025 5178172.94869223 440651.06097089 5178732.9083982 440684.750599837 5179797.67179249 440702.111525844 5180345.88134396 440731.830135607 5181339.36469896 440750.161804751 5181951.85443125 440774.193317489 5182959.24389991 440788.211689919 5183546.82785545 440808.556140411 5184569.02963089 440820.262004985 5185156.80111335 440840.168994679 5186181.03408972 440851.311907451 5186754.77454703 440868.844368726 5187794.75728581 440878.361997923 5188359.74790141 440898.739585907 5189444.7298283 440908.411922532 5189960.72122732 440913.290734644 5191084.45276957 440915.462465655 5191580.69461056 440937.027880396 5192677.64501441 440946.511668596 5193160.66818059 440965.045984715 5194262.9622736 440973.561784197 5194770.64128997 440987.346268008 5195878.46659537 440993.611925358 5196381.61446136 440997.677376318 5197479.59631226 440999.66263242 5198009.587543 440997.788580086 5199042.66427922 440996.713401008 5199638.56070505 441015.248841091 5200779.38528998 441022.763161913 5201240.53378684 441038.390380076 5202318.23443591 441044.810329775 5202759.50826854 441068.033916685 5203923.5198378 441076.86011304 5204365.48110994 441099.180074391 5205568.61773998 441107.919134768 5206040.4563889 441092.937830809 5207196.00699117 441086.988839287 5207653.43979129 441092.101754418 5208823.73991009 - - - - 396647.319162537,5125787.41633249 396629.824563343,5125805.82618797 396606.574358413,5125830.8264017 396595.511885163,5125859.8265997 396577.261814638,5125891.82683664 396573.637016015,5125927.82705053 396574.949857411,5125971.82729413 396576.075137571,5126007.82749328 396582.263052331,5126050.82771637 396590.826006225,5126093.82793236 396596.701364704,5126129.82811725 396605.264318258,5126172.82833358 396618.389788858,5126207.82849133 396631.390228143,5126238.82862717 396644.515705503,5126274.82879108 396659.078702435,5126310.297698 396670.579120159,5126341.82909202 396683.579551284,5126371.82922318 396696.454972903,5126400.82934927 396716.643028971,5126431.82946552 396734.393537423,5126461.82958359 396754.581592814,5126492.82970056 396774.519586055,5126515.82977324 396792.082547279,5126539.82985873 396819.083119819,5126557.82988318 396855.458795444,5126568.82984108 396898.396942019,5126560.82967184 396939.022558013,5126553.8295148 396969.772954926,5126538.82934018 396993.21071066,5126520.82916915 397016.460920688,5126496.82896388 397027.460872742,5126464.82874777 397045.710944138,5126432.82851025 397056.585866089,5126396.82827085 397062.648201959,5126359.82803953 397066.08545198,5126316.82778114 397067.835406618,5126306.42146587 397072.147795239,5126280.82755525 397075.835099479,5126244.82733626 397081.647381872,5126200.82706453 397092.459782577,5126161.82680651 397103.334705913,5126125.82656536 397121.772332701,5126100.82636484 397132.772294143,5126069.82615172 397148.834882151,5126044.82595783 397160.553757661,5126035.20086627 397179.272708267,5126019.82571988 397202.647953329,5125999.82553214 397233.335833894,5125981.82533342 397269.086369297,5125973.82517735 397305.337011941,5125979.82510165 397344.087731071,5125990.82504784 397373.463344054,5126008.82506407 397397.963862016,5126024.82508369 397425.151973375,5126047.82513668 397438.089904983,5126078.82528037 397444.027755832,5126114.82547489 397445.590639645,5126165.82577112 397454.091060634,5126205.82598176 397460.091433225,5126244.8261941 397468.529352856,5126284.82640523 397471.34202389,5126302.60775191 397474.529718163,5126322.82661191 397494.655252618,5126351.82672409 397507.593182574,5126382.82686947 397527.781224448,5126412.82698805 397545.344180905,5126436.82707907 397565.46972113,5126466.82719851 397578.407636095,5126495.82733311 397591.595617786,5126533.82752065 397604.4710243,5126561.82764997 397612.783911683,5126597.82784006 397618.971812944,5126640.82807793 397627.534752913,5126683.82830922 397628.847581176,5126727.82856701 397635.035482062,5126770.82880521 397643.3483687,5126806.828996 397645.004726745,5126818.4540605 397649.473768279,5126849.82923463 397657.786647643,5126884.82941976 397670.912112201,5126920.82959777 397690.850103905,5126944.82968593 397703.850524161,5126974.8298291 397721.601028402,5127005.82996553 397741.664049093,5127033.83007812 397761.664540702,5127057.83016732 397766.539781408,5127081.11154329 397769.602433453,5127095.8616232 397772.545330568,5127866.83496574 397799.55716051,5129508.84465574 397831.568827347,5131116.8540907 397844.579951222,5132687.86328606 397841.591240943,5134313.87274973 397847.602616648,5135930.88208476 397871.614199177,5137540.89132351 397907.625956819,5139153.90054444 397932.637595763,5140770.90973277 397947.649143106,5142391.91887313 397962.660579673,5143995.92785993 397972.671962545,5145598.93676736 397971.683228179,5147199.94555985 397981.694931268,5148843.95455868 397986.706260507,5150439.96320876 397990.753525199,5152039.92440306 398061.802940095,5153673.8844116 398044.852873508,5155360.84277007 398049.901485214,5156996.80243326 398075.949416946,5158601.76287673 398059.997632782,5160238.72242226 398074.045935741,5161865.68223921 398079.094836043,5163519.64134919 398121.172223473,5165059.66575611 397524.818123527,5165067.79049237 397026.153268514,5165076.32148286 397059.169441951,5166697.56308368 397074.216493664,5168318.52340502 397070.262855338,5169930.48393691 397080.309523306,5171545.44435402 397136.356979965,5173154.40478628 397156.403121981,5174745.3656852 397292.452470757,5176353.32576343 397351.500174909,5177964.28589945 397410.545932918,5179591.26622548 397438.590081989,5181207.25121208 397484.635123672,5182839.23587902 397568.67961072,5184411.22069788 399155.722151603,5184365.20819777 400767.765827735,5184336.19538155 402376.809351054,5184305.18266293 403893.850467498,5184279.17067505 405509.88661979,5184240.16416644 407127.917199638,5184205.16237558 408731.947575327,5184173.16060055 410320.977603268,5184140.15890349 411927.0077774,5184102.15730687 413468.035170976,5184019.156598 415034.06331545,5183946.15575987 416630.092083367,5183876.15490039 418239.122759583,5183856.15320425 419845.153118906,5183829.1516743 421418.182848745,5183803.15020699 423021.215323013,5183838.14759326 424640.227328401,5183826.1287231 426250.225657675,5183796.09869613 427926.224039936,5183768.06739585 429532.222317095,5183736.03751201 431126.220916499,5183713.00771019 432729.219448619,5183687.97779001 434321.217792016,5183656.94819719 435909.216377732,5183632.91857415 437519.214606452,5183597.88873491 439133.213072692,5183569.8587156 440447.274474624,5183551.58421118 440788.211689919,5183546.82785545 440774.193317489,5182959.24389991 440750.161804751,5181951.85443125 440731.830135607,5181339.36469896 440702.111525844,5180345.88134396 440684.750599837,5179797.67179249 440651.06097089,5178732.9083982 440650.699677025,5178172.94869223 440650.014973456,5177123.92495227 440637.563766231,5176535.7995613 440615.977504472,5175516.92387936 440604.370555919,5174951.2984902 440582.9399676,5173908.92276828 440572.989475617,5173352.60984766 440553.902074748,5172286.92153435 440537.889487585,5171749.7025147 440506.865079036,5170708.92074466 440497.446274702,5170172.6390742 440478.827657615,5169110.91948283 440467.877617866,5168576.200343 440445.789838809,5167498.91830244 440442.465107261,5166975.79273044 440435.75289353,5165918.916557 440429.239983656,5165367.88476372 440416.715119515,5164306.91495392 440422.825660397,5163685.13271532 440432.67738969,5162683.9123425 440435.976045197,5162089.00518069 440441.639697625,5161063.90983245 440435.50090148,5160474.87791456 440428.731220104,5159825.84576899 440394.891556092,5159824.69064082 440168.295395738,5159825.88464183 439928.95258192,5159831.79768159 439920.105839013,5159851.92304252 439837.293205181,5159883.92545398 439428.658644014,5159666.93696318 439389.43905896,5159649.78182603 438955.523526871,5159460.20043565 438868.021643891,5159421.9529385 438820.677249212,5159416.79805414 438546.704763059,5159386.9622125 437912.69554087,5159295.9805468 437842.257240392,5159295.10758917 437834.549029165,5158459.98268407 437837.784713312,5157878.73248683 437843.509384072,5156849.98210987 437843.494396201,5156242.79447432 437843.469251102,5155223.98172365 437837.429981925,5153635.98146622 437791.389300783,5152014.98244466 437697.348137997,5150407.98503925 437702.333741618,5148765.97566464 437727.330981757,5147211.9625931 437726.327686801,5145591.94983279 437725.324428085,5143976.93706535 437725.321201069,5142354.92416177 437736.318211385,5140725.91078311 437718.314733817,5139136.89865929 437698.311182421,5137532.88643811 437665.307315615,5135919.8745398 437648.303832046,5134323.86219173 437641.300538971,5132700.84923972 437635.297323898,5131096.83636224 437625.294012361,5129486.82352584 437598.290210678,5127849.81099969 437573.286513144,5126246.79863957 437546.282736399,5124637.78625312 437519.278954217,5123033.77386323 437509.98489396,5122463.40794018 437527.027817008,5122305.58004155 437534.527896677,5122230.61041166 437549.528288354,5122205.1096879 437591.404435887,5122162.35790414 437614.748826392,5122138.54440989 437637.155825486,5122098.543979 437649.749976677,5122084.512416 437689.782536252,5122024.98029865 437750.12819346,5121963.47875683 437838.380916,5121901.57002048 438017.948835643,5121826.06454523 438058.606268627,5121828.21939093 438155.890192362,5121903.34042007 438237.736223155,5121953.39968798 438306.488190201,5121972.92841773 438377.709007713,5121979.89467277 438461.242758608,5121953.57955277 438496.493851218,5121925.35985063 438536.401429659,5121851.26540118 438546.089318335,5121802.82800448 438548.558156946,5121795.26548809 438582.028332704,5121589.10994768 438596.591390315,5121527.9850023 438608.466924173,5121441.5166267 438623.813339239,5121376.09834029 437492.278289034,5121376.77370461 437489.281897405,5119808.78685956 437484.285556978,5118193.80044963 437485.289502675,5116528.81424446 437456.292405097,5114947.82823075 437452.2960581,5113347.84157795 437431.299201951,5111764.85524216 435862.25607009,5111768.89945371 434242.211499074,5111795.9449713 432640.167442508,5111821.99004314 431057.123883495,5111860.03457731 429450.079784996,5111869.07996791 427689.031503852,5111876.12973772 426075.987253384,5111896.17531676 424471.943303663,5111909.22068335 422855.899076511,5111917.26641124 421230.245048103,5111933.30087059 419693.843452792,5111956.33283067 417964.469828952,5111966.36879395 416363.067141303,5111988.40214818 414771.7584298,5111973.43514807 413159.168052034,5111993.46874153 411548.296462609,5112009.50229384 409948.518902999,5112091.53610421 408231.145662077,5112170.57246601 406647.680959646,5112207.60578157 405044.934660928,5112231.63941539 403453.563699325,5112279.67291954 401873.540795608,5112322.6780784 400243.517022892,5112330.68303475 398556.492460839,5112347.68827534 396933.468840334,5112364.69334166 395351.445842091,5112389.69839127 393853.36157894,5112421.64078434 393859.299199886,5112441.70349511 393847.736572546,5112465.70380383 393843.674086977,5112508.70430647 393837.111552817,5112544.70473691 393845.049242344,5112587.70520303 393850.486883488,5112623.70559688 393863.112129893,5112659.70596873 393882.862472251,5112690.70626172 393895.237694829,5112714.70649737 393914.988037748,5112745.70679013 393932.300840051,5112773.70705606 393951.926169584,5112797.70726924 393969.238977644,5112828.70756912 393996.051911514,5112851.70774863 394013.302206987,5112875.70796879 394033.052551765,5112906.70826081 394045.552790225,5112937.70857504 394058.178039574,5112973.70894566 394065.990716505,5113008.70931965 394078.553456494,5113039.70963341 394091.116196692,5113070.70994707 394103.741446914,5113106.7103173 394121.054257676,5113137.71061607 394135.992030064,5113166.71089934 394148.492270238,5113197.71121282 394159.961246877,5113229.555289 394160.023832358,5113276.71207453 394160.086424654,5113327.68140335 394149.617585741,5113364.68185631 394144.680060856,5113391.71342881 394133.367462626,5113430.71390723 394126.742428434,5113466.71433695 394110.492242135,5113497.71474007 394104.117234372,5113546.7153168 394104.867321865,5113589.715803 394093.492216285,5113625.71624779 394082.117110468,5113661.71669265 394077.929611646,5113697.7171149 394071.4295835,5113736.71757855 394060.054477088,5113772.71802356 394048.67937044,5113808.71846863 394042.054334609,5113844.71889871 394042.804423075,5113888.71939632 394043.554509784,5113931.71988254 394051.429691031,5113967.72026654 394056.929849101,5114010.72073754 394069.555101945,5114046.72110623 394077.367782725,5114082.72149018 394090.055540472,5114120.72188119 394090.743123231,5114161.72234455 394098.74331963,5114204.72280715 394099.493406947,5114247.72329291 394104.993565904,5114290.72376339 394124.743913448,5114318.72401772 394137.244157168,5114349.72432931 394149.869411885,5114385.72469713 394167.682245546,5114421.88129988 394186.807568417,5114440.72520192 394211.245479328,5114463.72538385 394237.995918334,5114482.72551285 394267.121393583,5114501.72563407 394298.496888663,5114512.72565728 394322.809787916,5114529.72577122 394354.372799104,5114547.72587293 394383.373260707,5114559.72591491 394414.87377337,5114578.72602795 394446.31177054,5114589.72605056 394477.812278199,5114605.72612945 394506.812740696,5114617.72617113 394531.250660501,5114643.7263858 394550.876001888,5114666.72658206 394563.376246602,5114695.72686919 394571.313948641,5114738.72732926 394596.001896305,5114776.72767818 394601.377046541,5114812.7280673 394597.377067299,5114855.72856603 394590.752034629,5114891.7289943 394579.376931218,5114928.72944943 394566.470547747,5114962.32362117 394551.626620873,5114988.73021814 394532.87638519,5115015.7305847 394514.126143602,5115039.73091745 394490.500829059,5115064.73127761 394466.875503023,5115083.73157005 394448.125269927,5115112.73195959 394424.562455412,5115137.73231986 394408.249755359,5115164.73267895 394389.49952137,5115193.73306878 394370.874292663,5115224.73348092 394354.499087194,5115249.73381784 394330.873768359,5115273.73416751 394292.935731185,5115298.73457599 394269.247901644,5115317.73486951 394252.872695053,5115342.73520681 394239.060047403,5115378.73566023 394222.747343077,5115404.7360088 394204.059609094,5115434.73641064 394187.809414129,5115465.73681579 394169.121683087,5115497.73724048 394157.621557243,5115526.73760732 394138.933823844,5115557.73802086 394127.496203812,5115589.73842162 394111.183502991,5115618.73880474 394097.37084405,5115649.73920224 394088.55823042,5115662.61437765 394080.933132024,5115673.73952926 394062.307899905,5115705.73995438 394046.057702473,5115736.74036029 394034.557574845,5115765.74072766 394020.682415429,5115797.74113709 394004.494726822,5115833.74159972 393997.869679337,5115865.74198489 393986.494564888,5115901.74243145 393975.119453643,5115939.74290076 393963.744340432,5115976.7433588 393952.306715737,5116007.74374905 393933.618974614,5116036.74414123 393917.243760681,5116060.74446893 393893.680939688,5116087.74485512 393874.86818897,5116112.74520261 393861.180482468,5116116.74529445 393854.61792906,5116145.74564587 393850.430407537,5116171.74595519 393841.930304956,5116189.58993661 393825.117594874,5116220.74659747 393813.554946164,5116239.74685252 393797.054710209,5116252.74705632 393778.241944662,5116269.74731346 393761.866720345,5116288.74758506 393747.866531327,5116306.74783726 393731.491306684,5116325.74810897 393712.553531926,5116338.74832133 393696.178306954,5116357.74859315 393670.302942922,5116382.74896571 393653.802704186,5116394.74915854 393642.240055644,5116414.74942545 393623.552301824,5116438.74976227 393611.927147149,5116455.74999538 393600.552012397,5116482.75034137 393588.926857469,5116499.75057455 393577.489216607,5116523.75088674 393565.926567222,5116543.75115391 393554.36391611,5116562.75140974 393542.86377383,5116586.75172227 393519.113442233,5116612.84585085 393512.488355425,5116623.75224775 393500.925705356,5116643.75251513 393482.112936403,5116660.75277343 393465.550194804,5116672.75296711 393439.424804218,5116685.75320523 393415.736950249,5116697.75342361 393391.86158697,5116705.75359715 393368.111233285,5116718.75382724 393344.360877897,5116730.754046 393320.548015241,5116738.75421946 393301.610235368,5116750.75442168 393277.859881082,5116763.754652 393254.109525117,5116775.75487097 393235.171746349,5116788.75508474 393211.483891073,5116800.75530361 393192.546112027,5116813.75551748 393175.983368809,5116825.75571176 393149.857976147,5116838.75595065 393133.482745994,5116857.75622424 393114.544966382,5116870.75643831 393098.169735903,5116889.75671202 393086.419569485,5116902.75690122 393067.606797293,5116919.75716067 393056.231655549,5116945.75749706 393037.418884445,5116963.75776805 393033.04384287,5116982.75800023 393021.606196787,5117006.75831414 393015.106140246,5117038.75870223 393008.418569061,5117062.75899965 393004.168536393,5117086.75928857 392997.668478094,5117117.75966531 392993.543454455,5117146.76001093 392987.043397381,5117178.76039914 392987.793453825,5117209.76075054 392988.418505414,5117238.76107952 392989.168561865,5117269.76143089 392989.668601508,5117291.82418106 392989.981126498,5117305.76183911 392985.918606405,5117336.76220736 392986.731171,5117372.76261556 392987.418726433,5117403.76296708 392988.168784299,5117435.76332978 392981.606221287,5117464.76368403 392982.29377667,5117495.76403552 392983.043833052,5117526.76438677 392978.918811594,5117557.76475526 392972.418749256,5117586.76510935 392973.106305979,5117618.76547222 392961.668657377,5117642.76578678 392957.418623605,5117666.76607586 392943.54343573,5117690.76639915 392927.168201979,5117710.76668571 392915.418030818,5117722.76686452 392891.855181635,5117742.76717676 392872.917395103,5117754.76738123 392740.790424309,5117861.76907524 392717.040059422,5117873.7692973 392698.28978547,5117893.76959306 392681.727035677,5117905.76978954 392662.914256339,5117922.77005132 392651.16408497,5117935.77024211 392632.413809005,5117954.77052666 392608.288447914,5117974.89584341 392608.475965431,5117985.83346794 392585.663132786,5118011.77134664 392574.100471765,5118030.77160564 392562.600318191,5118054.77192172 392543.787538836,5118072.7721954 392532.224877397,5118091.77245454 392520.724723346,5118115.77277076 392509.162062944,5118135.77304143 392497.724409603,5118159.77335752 392486.161748931,5118179.77362828 392474.724095295,5118203.77394446 392463.223940494,5118227.77426091 392456.411352287,5118244.77448028 392443.81744214,5118278.61866355 392440.723664055,5118295.77512132 392426.910971326,5118319.77544629 392422.785945318,5118351.77582793 392416.160868597,5118375.77612696 392411.910830245,5118399.7764174 392405.410764244,5118430.77679624 392401.160725746,5118454.77708672 392394.660660804,5118486.77747706 392390.410622159,5118510.77776756 392383.848052215,5118539.7781238 392379.723024262,5118570.7784941 392380.473076701,5118602.77885811 392381.160626871,5118633.77921086 392381.973185368,5118669.77962043 392382.66073303,5118698.77995023 392383.348283211,5118729.78030293 392388.910912823,5118760.78063776 392389.598463053,5118791.78099041 392397.47362799,5118820.78129376 392398.286186632,5118856.78170317 392398.973736932,5118887.78205574 392399.723788257,5118918.78240806 392400.536346912,5118954.7828174 392394.036280934,5118986.78320784 392394.723831189,5119017.78356036 392402.786508491,5119053.7839429 392403.411555271,5119082.78427269 392408.849177143,5119108.78455032 392417.411893277,5119168.78520562 392417.974432822,5119192.7854783 392411.474365244,5119223.78585728 392407.349337824,5119255.78623893 392408.036884392,5119283.78655692 392408.911947902,5119322.78700013 392414.349572639,5119350.78730042 392415.224633688,5119387.78772067 392411.099604812,5119418.78809085 392411.787155176,5119449.78844309 392405.349588049,5119480.78882191 392405.974634815,5119509.78915149 392406.84969828,5119548.78959456 392407.537246085,5119577.78992386 392408.224796407,5119608.79027604 392409.037355083,5119644.79068494 392416.975025357,5119675.79100988 392417.66257575,5119706.79136198 392423.162703331,5119735.79167309 392423.850253773,5119766.79202514 392431.787924406,5119797.79234988 392437.10054279,5119821.79260439 392437.85059438,5119852.79295612 392440.631903442,5119863.0118125 392445.725761732,5119881.79325808 392451.225892287,5119912.79359182 392459.163563436,5119943.7939163 392459.663602176,5119967.79418881 392465.16373042,5119996.79449956 392473.101401848,5120027.79482389 392473.78895269,5120058.79517564 392481.726624313,5120089.79549988 392482.351671638,5120118.79582895 392483.101723595,5120149.79618038 392483.914282962,5120185.7965887 392484.601833886,5120216.79694033 392485.414393263,5120252.7973486 392486.164446509,5120284.79771139 392486.977005895,5120320.79811962 392492.477137348,5120351.7984528 392493.039677325,5120375.79872483 392500.977349717,5120406.79904862 392506.414977796,5120435.79935907 392514.352650416,5120466.79968275 392526.915390478,5120489.79989728 392539.353123455,5120508.80006657 392551.915865102,5120532.8002924 392564.353598353,5120551.80046157 392583.978948531,5120567.80056886 392600.010505845,5120597.11334179 392608.979424349,5120610.8009635 392621.417158159,5120629.80113245 392641.042509008,5120645.80123949 392658.105311672,5120657.80131071 392677.949415731,5120673.20766002 392702.106091439,5120687.8014834 392721.731446962,5120706.80162438 392738.856751236,5120718.80169515 392758.419602039,5120734.80180206 392775.544906569,5120746.80187274 392795.10775498,5120760.80195676 392814.670606259,5120776.8020635 392831.795911176,5120788.80213404 392851.421266561,5120806.80226318 392871.046620767,5120823.80238087 392883.484356665,5120842.80254903 392900.734673902,5120861.80269853 392908.547337548,5120884.80292997 392921.110082889,5120908.80315436 392926.422705908,5120932.80340675 392927.23526959,5120968.80381304 392923.17274389,5120999.80418134 392923.860299875,5121031.80454259 392917.360232791,5121062.80492038 392913.110194025,5121086.80520984 392901.672533419,5121110.80552728 392894.984954546,5121135.80583765 392883.547293661,5121159.80615517 392879.297254538,5121183.80644472 392872.609673993,5121207.80674378 392873.484742288,5121246.80718397 392874.172292332,5121274.80749975 392886.79754389,5121301.80775747 392899.172776234,5121317.80789102 392911.673014952,5121336.80805814 392924.235761778,5121360.8082818 392936.798508767,5121384.8085054 392949.23624684,5121403.80867259 392968.861603252,5121419.80877747 392981.299341611,5121438.80894455 393001.049710309,5121461.80912832 393010.924899806,5121476.90301098 393025.925184951,5121497.80943949 393038.362923867,5121516.80960635 393058.113293343,5121539.80978982 393070.613533636,5121558.80995632 393082.988769071,5121575.81010056 393107.301699889,5121586.81012968 393126.864554048,5121600.81021148 393143.927362765,5121612.81028039 393163.552721167,5121628.81038452 393175.990461243,5121647.81055094 393195.67832541,5121666.81068871 393208.24107521,5121690.81091119 393225.428892612,5121706.81102468 393244.929243869,5121718.81108366 393269.117168119,5121725.81106744 393300.36770149,5121724.81093268 393316.930465618,5121711.81072005 393340.680854092,5121699.81049043 393366.931291185,5121691.81029627 393395.494260176,5121678.81003645 393426.619784935,5121673.8098571 393457.870317864,5121672.80972254 393493.933433088,5121671.80956902 393525.246476345,5121676.80950206 393549.43439937,5121682.80947448 393580.809942319,5121686.80939592 393604.997867081,5121693.80937958 393629.310800374,5121704.80940789 393653.436221126,5121709.80936915 393672.936572303,5121720.80941637 393697.312011842,5121734.80947815 393714.374823146,5121746.80954619 393734.000184865,5121762.80964918 393758.313120639,5121774.80968847 393782.501044747,5121780.80966054 393813.876588865,5121784.80958162 393845.064623317,5121784.80945833 393869.377557989,5121795.80948618 393893.565484088,5121802.80946941 393913.253352945,5121821.80960556 393930.378664812,5121832.80966169 393949.879019183,5121844.80971963 393974.129453519,5121855.80974747 393980.567088586,5121870.55988801 394006.005040641,5121879.80989136 394035.005558621,5121891.80991148 394061.69354385,5121907.8099857 394090.694062249,5121919.81000568 394122.25713511,5121937.81008288 394153.757708931,5121956.81017145 394178.383194166,5121992.81047819 394222.321522601,5122034.81077535 394246.571967771,5122050.81085858 394270.947420551,5122069.8109749 394295.447896778,5122100.8112253 394315.073277083,5122124.81141642 394339.44873778,5122147.8115773 394355.355301223,5122169.96801237 394376.261957671,5122195.81196876 394395.887337237,5122218.81214828 394413.262692471,5122249.81242635 394432.950587952,5122280.81269506 394452.575970121,5122304.81288546 394469.951326235,5122335.81316318 394494.326789315,5122358.81332314 394513.952172303,5122382.81351323 394533.702570425,5122413.81378107 394550.890411741,5122437.81398072 394570.578303909,5122465.81421501 394587.828650453,5122491.81443659 394607.516545024,5122520.81468184 394620.079319934,5122551.814978 394639.642203691,5122575.81516761 394657.017560798,5122605.81543301 394676.767961315,5122636.8156999 394696.455857359,5122665.81594455 394713.643700911,5122689.81614332 394733.269090836,5122715.8163545 394745.519324584,5122726.81642786 394740.082037153,5122766.81665835 394764.832648369,5122789.81667434 394789.833325575,5122820.81673085 394817.146519537,5122848.81676288 394834.709504156,5122871.81680952 394859.522638279,5122897.81684226 394879.273106525,5122913.81684432 394904.023723511,5122937.81686765 394928.836848953,5122962.81689628 394955.774941809,5122978.81686992 394973.337932572,5123002.81692346 394998.151057066,5123027.81695315 395029.9017329,5123043.81690827 395058.496141839,5123064.81690259 395086.215481581,5123078.81686417 395110.841047887,5123096.81685942 395142.654238941,5123114.81682611 395171.842330564,5123125.81676686 395203.5305036,5123141.81672417 395235.343701373,5123160.81669716 395266.906833568,5123171.81662922 395303.282541552,5123181.81653703 395339.658256907,5123192.8164504 395371.221388458,5123203.81638321 395407.472063324,5123209.81627095 395439.222735558,5123225.81623018 395468.473349008,5123239.81618895 395495.598993273,5123262.81620467 395520.349596002,5123285.81623017 395537.912581366,5123309.81628975 395557.850600111,5123332.81633486 395578.03868312,5123363.81642235 395591.164181148,5123399.81656481 395596.977014847,5123430.81670912 395610.102504936,5123465.81684662 395623.102962563,5123496.81696328 395637.353749434,5123568.81729667 395645.91672001,5123611.81749581 395651.854592615,5123647.81766739 395653.417494831,5123697.81793139 395654.667824093,5123738.81814797 395656.043170504,5123781.81837485 395652.605941696,5123825.81862529 395641.731025185,5123861.81886043 395630.731076702,5123893.81907422 395619.731128427,5123925.81928775 395601.418532393,5123954.81951223 395590.418584587,5123986.8197252 395572.168505251,5124017.8199595 395556.168419549,5124042.82015293 395537.855824659,5124071.82037606 395534.231056787,5124110.82059811 395535.606404653,5124153.82082305 395544.981758839,5124179.53967623 395548.73190043,5124189.8209675 395561.669832457,5124217.82107007 395574.607786881,5124248.82118892 395592.420824241,5124279.8212903 395607.796319737,5124310.82140083 395625.484331816,5124338.82148718 395645.672408739,5124369.82158095 395663.42294382,5124400.82168386 395683.423456846,5124423.82173593 395703.549031724,5124454.821831 395721.112002747,5124477.82189239 395745.67504009,5124493.82189127 395772.800673097,5124516.8219192 395958.867494766,5124673.13461351 395977.555427812,5124688.82213398 396009.118543949,5124699.82208402 396040.931715948,5124717.82207188 396077.057357066,5124721.82196805 396120.495636621,5124727.82184993 396168.496434268,5124725.82167189 396211.684657849,5124724.82151611 396254.997912928,5124727.82138216 396291.248570403,5124733.82128959 396327.436734009,5124740.82120298 396363.812422571,5124750.8211327 396402.375604091,5124754.82102145 396438.751299561,5124765.82095723 396474.93945521,5124771.8208658 396511.315150251,5124782.82080208 396542.878263716,5124793.82075525 396579.253958297,5124804.82069207 396618.004692763,5124815.820621 396642.630239036,5124833.82063855 396667.130768482,5124849.82064543 396698.94393558,5124867.82063893 396716.506905183,5124891.82071572 396741.25748856,5124914.82076257 396768.383111651,5124937.8208017 396786.133633971,5124968.82091883 396794.321494945,5124999.82106858 396813.38483359,5125071.82141678 396826.385275015,5125102.82155089 396839.510747052,5125137.82170776 396854.8862279,5125168.82183446 396860.76158493,5125204.82202163 396869.136890501,5125227.82212598 396873.887063443,5125240.82218496 396882.324977473,5125278.82237547 396888.387873065,5125319.82259116 396896.950824709,5125362.82281031 396898.263654907,5125405.82305318 396904.451566561,5125448.82328028 396893.576642937,5125484.82352222 396889.889346691,5125521.82374655 396878.889385499,5125552.82395972 396860.639310797,5125584.82420152 396842.389214871,5125613.82442575 396819.201529806,5125641.82465958 396802.951381453,5125658.82480822 396772.513554689,5125683.82504716 396749.138309812,5125703.82523489 396725.700564154,5125723.82542252 396695.075184765,5125741.82562109 396671.63743966,5125761.82580809 396647.319162537,5125787.41633249 + + + + 392379.723024262 5111764.85524216440788.211689919 5184411.22069788 + 396647.319162537 5125787.41633249 396629.824563343 5125805.82618797 396606.574358413 5125830.8264017 396595.511885163 5125859.8265997 396577.261814638 5125891.82683664 396573.637016015 5125927.82705053 396574.949857411 5125971.82729413 396576.075137571 5126007.82749328 396582.263052331 5126050.82771637 396590.826006225 5126093.82793236 396596.701364704 5126129.82811725 396605.264318258 5126172.82833358 396618.389788858 5126207.82849133 396631.390228143 5126238.82862717 396644.515705503 5126274.82879108 396659.078702435 5126310.297698 396670.579120159 5126341.82909202 396683.579551284 5126371.82922318 396696.454972903 5126400.82934927 396716.643028971 5126431.82946552 396734.393537423 5126461.82958359 396754.581592814 5126492.82970056 396774.519586055 5126515.82977324 396792.082547279 5126539.82985873 396819.083119819 5126557.82988318 396855.458795444 5126568.82984108 396898.396942019 5126560.82967184 396939.022558013 5126553.8295148 396969.772954926 5126538.82934018 396993.21071066 5126520.82916915 397016.460920688 5126496.82896388 397027.460872742 5126464.82874777 397045.710944138 5126432.82851025 397056.585866089 5126396.82827085 397062.648201959 5126359.82803953 397066.08545198 5126316.82778114 397067.835406618 5126306.42146587 397072.147795239 5126280.82755525 397075.835099479 5126244.82733626 397081.647381872 5126200.82706453 397092.459782577 5126161.82680651 397103.334705913 5126125.82656536 397121.772332701 5126100.82636484 397132.772294143 5126069.82615172 397148.834882151 5126044.82595783 397160.553757661 5126035.20086627 397179.272708267 5126019.82571988 397202.647953329 5125999.82553214 397233.335833894 5125981.82533342 397269.086369297 5125973.82517735 397305.337011941 5125979.82510165 397344.087731071 5125990.82504784 397373.463344054 5126008.82506407 397397.963862016 5126024.82508369 397425.151973375 5126047.82513668 397438.089904983 5126078.82528037 397444.027755832 5126114.82547489 397445.590639645 5126165.82577112 397454.091060634 5126205.82598176 397460.091433225 5126244.8261941 397468.529352856 5126284.82640523 397471.34202389 5126302.60775191 397474.529718163 5126322.82661191 397494.655252618 5126351.82672409 397507.593182574 5126382.82686947 397527.781224448 5126412.82698805 397545.344180905 5126436.82707907 397565.46972113 5126466.82719851 397578.407636095 5126495.82733311 397591.595617786 5126533.82752065 397604.4710243 5126561.82764997 397612.783911683 5126597.82784006 397618.971812944 5126640.82807793 397627.534752913 5126683.82830922 397628.847581176 5126727.82856701 397635.035482062 5126770.82880521 397643.3483687 5126806.828996 397645.004726745 5126818.4540605 397649.473768279 5126849.82923463 397657.786647643 5126884.82941976 397670.912112201 5126920.82959777 397690.850103905 5126944.82968593 397703.850524161 5126974.8298291 397721.601028402 5127005.82996553 397741.664049093 5127033.83007812 397761.664540702 5127057.83016732 397766.539781408 5127081.11154329 397769.602433453 5127095.8616232 397772.545330568 5127866.83496574 397799.55716051 5129508.84465574 397831.568827347 5131116.8540907 397844.579951222 5132687.86328606 397841.591240943 5134313.87274973 397847.602616648 5135930.88208476 397871.614199177 5137540.89132351 397907.625956819 5139153.90054444 397932.637595763 5140770.90973277 397947.649143106 5142391.91887313 397962.660579673 5143995.92785993 397972.671962545 5145598.93676736 397971.683228179 5147199.94555985 397981.694931268 5148843.95455868 397986.706260507 5150439.96320876 397990.753525199 5152039.92440306 398061.802940095 5153673.8844116 398044.852873508 5155360.84277007 398049.901485214 5156996.80243326 398075.949416946 5158601.76287673 398059.997632782 5160238.72242226 398074.045935741 5161865.68223921 398079.094836043 5163519.64134919 398121.172223473 5165059.66575611 397524.818123527 5165067.79049237 397026.153268514 5165076.32148286 397059.169441951 5166697.56308368 397074.216493664 5168318.52340502 397070.262855338 5169930.48393691 397080.309523306 5171545.44435402 397136.356979965 5173154.40478628 397156.403121981 5174745.3656852 397292.452470757 5176353.32576343 397351.500174909 5177964.28589945 397410.545932918 5179591.26622548 397438.590081989 5181207.25121208 397484.635123672 5182839.23587902 397568.67961072 5184411.22069788 399155.722151603 5184365.20819777 400767.765827735 5184336.19538155 402376.809351054 5184305.18266293 403893.850467498 5184279.17067505 405509.88661979 5184240.16416644 407127.917199638 5184205.16237558 408731.947575327 5184173.16060055 410320.977603268 5184140.15890349 411927.0077774 5184102.15730687 413468.035170976 5184019.156598 415034.06331545 5183946.15575987 416630.092083367 5183876.15490039 418239.122759583 5183856.15320425 419845.153118906 5183829.1516743 421418.182848745 5183803.15020699 423021.215323013 5183838.14759326 424640.227328401 5183826.1287231 426250.225657675 5183796.09869613 427926.224039936 5183768.06739585 429532.222317095 5183736.03751201 431126.220916499 5183713.00771019 432729.219448619 5183687.97779001 434321.217792016 5183656.94819719 435909.216377732 5183632.91857415 437519.214606452 5183597.88873491 439133.213072692 5183569.8587156 440447.274474624 5183551.58421118 440788.211689919 5183546.82785545 440774.193317489 5182959.24389991 440750.161804751 5181951.85443125 440731.830135607 5181339.36469896 440702.111525844 5180345.88134396 440684.750599837 5179797.67179249 440651.06097089 5178732.9083982 440650.699677025 5178172.94869223 440650.014973456 5177123.92495227 440637.563766231 5176535.7995613 440615.977504472 5175516.92387936 440604.370555919 5174951.2984902 440582.9399676 5173908.92276828 440572.989475617 5173352.60984766 440553.902074748 5172286.92153435 440537.889487585 5171749.7025147 440506.865079036 5170708.92074466 440497.446274702 5170172.6390742 440478.827657615 5169110.91948283 440467.877617866 5168576.200343 440445.789838809 5167498.91830244 440442.465107261 5166975.79273044 440435.75289353 5165918.916557 440429.239983656 5165367.88476372 440416.715119515 5164306.91495392 440422.825660397 5163685.13271532 440432.67738969 5162683.9123425 440435.976045197 5162089.00518069 440441.639697625 5161063.90983245 440435.50090148 5160474.87791456 440428.731220104 5159825.84576899 440394.891556092 5159824.69064082 440168.295395738 5159825.88464183 439928.95258192 5159831.79768159 439920.105839013 5159851.92304252 439837.293205181 5159883.92545398 439428.658644014 5159666.93696318 439389.43905896 5159649.78182603 438955.523526871 5159460.20043565 438868.021643891 5159421.9529385 438820.677249212 5159416.79805414 438546.704763059 5159386.9622125 437912.69554087 5159295.9805468 437842.257240392 5159295.10758917 437834.549029165 5158459.98268407 437837.784713312 5157878.73248683 437843.509384072 5156849.98210987 437843.494396201 5156242.79447432 437843.469251102 5155223.98172365 437837.429981925 5153635.98146622 437791.389300783 5152014.98244466 437697.348137997 5150407.98503925 437702.333741618 5148765.97566464 437727.330981757 5147211.9625931 437726.327686801 5145591.94983279 437725.324428085 5143976.93706535 437725.321201069 5142354.92416177 437736.318211385 5140725.91078311 437718.314733817 5139136.89865929 437698.311182421 5137532.88643811 437665.307315615 5135919.8745398 437648.303832046 5134323.86219173 437641.300538971 5132700.84923972 437635.297323898 5131096.83636224 437625.294012361 5129486.82352584 437598.290210678 5127849.81099969 437573.286513144 5126246.79863957 437546.282736399 5124637.78625312 437519.278954217 5123033.77386323 437509.98489396 5122463.40794018 437527.027817008 5122305.58004155 437534.527896677 5122230.61041166 437549.528288354 5122205.1096879 437591.404435887 5122162.35790414 437614.748826392 5122138.54440989 437637.155825486 5122098.543979 437649.749976677 5122084.512416 437689.782536252 5122024.98029865 437750.12819346 5121963.47875683 437838.380916 5121901.57002048 438017.948835643 5121826.06454523 438058.606268627 5121828.21939093 438155.890192362 5121903.34042007 438237.736223155 5121953.39968798 438306.488190201 5121972.92841773 438377.709007713 5121979.89467277 438461.242758608 5121953.57955277 438496.493851218 5121925.35985063 438536.401429659 5121851.26540118 438546.089318335 5121802.82800448 438548.558156946 5121795.26548809 438582.028332704 5121589.10994768 438596.591390315 5121527.9850023 438608.466924173 5121441.5166267 438623.813339239 5121376.09834029 437492.278289034 5121376.77370461 437489.281897405 5119808.78685956 437484.285556978 5118193.80044963 437485.289502675 5116528.81424446 437456.292405097 5114947.82823075 437452.2960581 5113347.84157795 437431.299201951 5111764.85524216 435862.25607009 5111768.89945371 434242.211499074 5111795.9449713 432640.167442508 5111821.99004314 431057.123883495 5111860.03457731 429450.079784996 5111869.07996791 427689.031503852 5111876.12973772 426075.987253384 5111896.17531676 424471.943303663 5111909.22068335 422855.899076511 5111917.26641124 421230.245048103 5111933.30087059 419693.843452792 5111956.33283067 417964.469828952 5111966.36879395 416363.067141303 5111988.40214818 414771.7584298 5111973.43514807 413159.168052034 5111993.46874153 411548.296462609 5112009.50229384 409948.518902999 5112091.53610421 408231.145662077 5112170.57246601 406647.680959646 5112207.60578157 405044.934660928 5112231.63941539 403453.563699325 5112279.67291954 401873.540795608 5112322.6780784 400243.517022892 5112330.68303475 398556.492460839 5112347.68827534 396933.468840334 5112364.69334166 395351.445842091 5112389.69839127 393853.36157894 5112421.64078434 393859.299199886 5112441.70349511 393847.736572546 5112465.70380383 393843.674086977 5112508.70430647 393837.111552817 5112544.70473691 393845.049242344 5112587.70520303 393850.486883488 5112623.70559688 393863.112129893 5112659.70596873 393882.862472251 5112690.70626172 393895.237694829 5112714.70649737 393914.988037748 5112745.70679013 393932.300840051 5112773.70705606 393951.926169584 5112797.70726924 393969.238977644 5112828.70756912 393996.051911514 5112851.70774863 394013.302206987 5112875.70796879 394033.052551765 5112906.70826081 394045.552790225 5112937.70857504 394058.178039574 5112973.70894566 394065.990716505 5113008.70931965 394078.553456494 5113039.70963341 394091.116196692 5113070.70994707 394103.741446914 5113106.7103173 394121.054257676 5113137.71061607 394135.992030064 5113166.71089934 394148.492270238 5113197.71121282 394159.961246877 5113229.555289 394160.023832358 5113276.71207453 394160.086424654 5113327.68140335 394149.617585741 5113364.68185631 394144.680060856 5113391.71342881 394133.367462626 5113430.71390723 394126.742428434 5113466.71433695 394110.492242135 5113497.71474007 394104.117234372 5113546.7153168 394104.867321865 5113589.715803 394093.492216285 5113625.71624779 394082.117110468 5113661.71669265 394077.929611646 5113697.7171149 394071.4295835 5113736.71757855 394060.054477088 5113772.71802356 394048.67937044 5113808.71846863 394042.054334609 5113844.71889871 394042.804423075 5113888.71939632 394043.554509784 5113931.71988254 394051.429691031 5113967.72026654 394056.929849101 5114010.72073754 394069.555101945 5114046.72110623 394077.367782725 5114082.72149018 394090.055540472 5114120.72188119 394090.743123231 5114161.72234455 394098.74331963 5114204.72280715 394099.493406947 5114247.72329291 394104.993565904 5114290.72376339 394124.743913448 5114318.72401772 394137.244157168 5114349.72432931 394149.869411885 5114385.72469713 394167.682245546 5114421.88129988 394186.807568417 5114440.72520192 394211.245479328 5114463.72538385 394237.995918334 5114482.72551285 394267.121393583 5114501.72563407 394298.496888663 5114512.72565728 394322.809787916 5114529.72577122 394354.372799104 5114547.72587293 394383.373260707 5114559.72591491 394414.87377337 5114578.72602795 394446.31177054 5114589.72605056 394477.812278199 5114605.72612945 394506.812740696 5114617.72617113 394531.250660501 5114643.7263858 394550.876001888 5114666.72658206 394563.376246602 5114695.72686919 394571.313948641 5114738.72732926 394596.001896305 5114776.72767818 394601.377046541 5114812.7280673 394597.377067299 5114855.72856603 394590.752034629 5114891.7289943 394579.376931218 5114928.72944943 394566.470547747 5114962.32362117 394551.626620873 5114988.73021814 394532.87638519 5115015.7305847 394514.126143602 5115039.73091745 394490.500829059 5115064.73127761 394466.875503023 5115083.73157005 394448.125269927 5115112.73195959 394424.562455412 5115137.73231986 394408.249755359 5115164.73267895 394389.49952137 5115193.73306878 394370.874292663 5115224.73348092 394354.499087194 5115249.73381784 394330.873768359 5115273.73416751 394292.935731185 5115298.73457599 394269.247901644 5115317.73486951 394252.872695053 5115342.73520681 394239.060047403 5115378.73566023 394222.747343077 5115404.7360088 394204.059609094 5115434.73641064 394187.809414129 5115465.73681579 394169.121683087 5115497.73724048 394157.621557243 5115526.73760732 394138.933823844 5115557.73802086 394127.496203812 5115589.73842162 394111.183502991 5115618.73880474 394097.37084405 5115649.73920224 394088.55823042 5115662.61437765 394080.933132024 5115673.73952926 394062.307899905 5115705.73995438 394046.057702473 5115736.74036029 394034.557574845 5115765.74072766 394020.682415429 5115797.74113709 394004.494726822 5115833.74159972 393997.869679337 5115865.74198489 393986.494564888 5115901.74243145 393975.119453643 5115939.74290076 393963.744340432 5115976.7433588 393952.306715737 5116007.74374905 393933.618974614 5116036.74414123 393917.243760681 5116060.74446893 393893.680939688 5116087.74485512 393874.86818897 5116112.74520261 393861.180482468 5116116.74529445 393854.61792906 5116145.74564587 393850.430407537 5116171.74595519 393841.930304956 5116189.58993661 393825.117594874 5116220.74659747 393813.554946164 5116239.74685252 393797.054710209 5116252.74705632 393778.241944662 5116269.74731346 393761.866720345 5116288.74758506 393747.866531327 5116306.74783726 393731.491306684 5116325.74810897 393712.553531926 5116338.74832133 393696.178306954 5116357.74859315 393670.302942922 5116382.74896571 393653.802704186 5116394.74915854 393642.240055644 5116414.74942545 393623.552301824 5116438.74976227 393611.927147149 5116455.74999538 393600.552012397 5116482.75034137 393588.926857469 5116499.75057455 393577.489216607 5116523.75088674 393565.926567222 5116543.75115391 393554.36391611 5116562.75140974 393542.86377383 5116586.75172227 393519.113442233 5116612.84585085 393512.488355425 5116623.75224775 393500.925705356 5116643.75251513 393482.112936403 5116660.75277343 393465.550194804 5116672.75296711 393439.424804218 5116685.75320523 393415.736950249 5116697.75342361 393391.86158697 5116705.75359715 393368.111233285 5116718.75382724 393344.360877897 5116730.754046 393320.548015241 5116738.75421946 393301.610235368 5116750.75442168 393277.859881082 5116763.754652 393254.109525117 5116775.75487097 393235.171746349 5116788.75508474 393211.483891073 5116800.75530361 393192.546112027 5116813.75551748 393175.983368809 5116825.75571176 393149.857976147 5116838.75595065 393133.482745994 5116857.75622424 393114.544966382 5116870.75643831 393098.169735903 5116889.75671202 393086.419569485 5116902.75690122 393067.606797293 5116919.75716067 393056.231655549 5116945.75749706 393037.418884445 5116963.75776805 393033.04384287 5116982.75800023 393021.606196787 5117006.75831414 393015.106140246 5117038.75870223 393008.418569061 5117062.75899965 393004.168536393 5117086.75928857 392997.668478094 5117117.75966531 392993.543454455 5117146.76001093 392987.043397381 5117178.76039914 392987.793453825 5117209.76075054 392988.418505414 5117238.76107952 392989.168561865 5117269.76143089 392989.668601508 5117291.82418106 392989.981126498 5117305.76183911 392985.918606405 5117336.76220736 392986.731171 5117372.76261556 392987.418726433 5117403.76296708 392988.168784299 5117435.76332978 392981.606221287 5117464.76368403 392982.29377667 5117495.76403552 392983.043833052 5117526.76438677 392978.918811594 5117557.76475526 392972.418749256 5117586.76510935 392973.106305979 5117618.76547222 392961.668657377 5117642.76578678 392957.418623605 5117666.76607586 392943.54343573 5117690.76639915 392927.168201979 5117710.76668571 392915.418030818 5117722.76686452 392891.855181635 5117742.76717676 392872.917395103 5117754.76738123 392740.790424309 5117861.76907524 392717.040059422 5117873.7692973 392698.28978547 5117893.76959306 392681.727035677 5117905.76978954 392662.914256339 5117922.77005132 392651.16408497 5117935.77024211 392632.413809005 5117954.77052666 392608.288447914 5117974.89584341 392608.475965431 5117985.83346794 392585.663132786 5118011.77134664 392574.100471765 5118030.77160564 392562.600318191 5118054.77192172 392543.787538836 5118072.7721954 392532.224877397 5118091.77245454 392520.724723346 5118115.77277076 392509.162062944 5118135.77304143 392497.724409603 5118159.77335752 392486.161748931 5118179.77362828 392474.724095295 5118203.77394446 392463.223940494 5118227.77426091 392456.411352287 5118244.77448028 392443.81744214 5118278.61866355 392440.723664055 5118295.77512132 392426.910971326 5118319.77544629 392422.785945318 5118351.77582793 392416.160868597 5118375.77612696 392411.910830245 5118399.7764174 392405.410764244 5118430.77679624 392401.160725746 5118454.77708672 392394.660660804 5118486.77747706 392390.410622159 5118510.77776756 392383.848052215 5118539.7781238 392379.723024262 5118570.7784941 392380.473076701 5118602.77885811 392381.160626871 5118633.77921086 392381.973185368 5118669.77962043 392382.66073303 5118698.77995023 392383.348283211 5118729.78030293 392388.910912823 5118760.78063776 392389.598463053 5118791.78099041 392397.47362799 5118820.78129376 392398.286186632 5118856.78170317 392398.973736932 5118887.78205574 392399.723788257 5118918.78240806 392400.536346912 5118954.7828174 392394.036280934 5118986.78320784 392394.723831189 5119017.78356036 392402.786508491 5119053.7839429 392403.411555271 5119082.78427269 392408.849177143 5119108.78455032 392417.411893277 5119168.78520562 392417.974432822 5119192.7854783 392411.474365244 5119223.78585728 392407.349337824 5119255.78623893 392408.036884392 5119283.78655692 392408.911947902 5119322.78700013 392414.349572639 5119350.78730042 392415.224633688 5119387.78772067 392411.099604812 5119418.78809085 392411.787155176 5119449.78844309 392405.349588049 5119480.78882191 392405.974634815 5119509.78915149 392406.84969828 5119548.78959456 392407.537246085 5119577.78992386 392408.224796407 5119608.79027604 392409.037355083 5119644.79068494 392416.975025357 5119675.79100988 392417.66257575 5119706.79136198 392423.162703331 5119735.79167309 392423.850253773 5119766.79202514 392431.787924406 5119797.79234988 392437.10054279 5119821.79260439 392437.85059438 5119852.79295612 392440.631903442 5119863.0118125 392445.725761732 5119881.79325808 392451.225892287 5119912.79359182 392459.163563436 5119943.7939163 392459.663602176 5119967.79418881 392465.16373042 5119996.79449956 392473.101401848 5120027.79482389 392473.78895269 5120058.79517564 392481.726624313 5120089.79549988 392482.351671638 5120118.79582895 392483.101723595 5120149.79618038 392483.914282962 5120185.7965887 392484.601833886 5120216.79694033 392485.414393263 5120252.7973486 392486.164446509 5120284.79771139 392486.977005895 5120320.79811962 392492.477137348 5120351.7984528 392493.039677325 5120375.79872483 392500.977349717 5120406.79904862 392506.414977796 5120435.79935907 392514.352650416 5120466.79968275 392526.915390478 5120489.79989728 392539.353123455 5120508.80006657 392551.915865102 5120532.8002924 392564.353598353 5120551.80046157 392583.978948531 5120567.80056886 392600.010505845 5120597.11334179 392608.979424349 5120610.8009635 392621.417158159 5120629.80113245 392641.042509008 5120645.80123949 392658.105311672 5120657.80131071 392677.949415731 5120673.20766002 392702.106091439 5120687.8014834 392721.731446962 5120706.80162438 392738.856751236 5120718.80169515 392758.419602039 5120734.80180206 392775.544906569 5120746.80187274 392795.10775498 5120760.80195676 392814.670606259 5120776.8020635 392831.795911176 5120788.80213404 392851.421266561 5120806.80226318 392871.046620767 5120823.80238087 392883.484356665 5120842.80254903 392900.734673902 5120861.80269853 392908.547337548 5120884.80292997 392921.110082889 5120908.80315436 392926.422705908 5120932.80340675 392927.23526959 5120968.80381304 392923.17274389 5120999.80418134 392923.860299875 5121031.80454259 392917.360232791 5121062.80492038 392913.110194025 5121086.80520984 392901.672533419 5121110.80552728 392894.984954546 5121135.80583765 392883.547293661 5121159.80615517 392879.297254538 5121183.80644472 392872.609673993 5121207.80674378 392873.484742288 5121246.80718397 392874.172292332 5121274.80749975 392886.79754389 5121301.80775747 392899.172776234 5121317.80789102 392911.673014952 5121336.80805814 392924.235761778 5121360.8082818 392936.798508767 5121384.8085054 392949.23624684 5121403.80867259 392968.861603252 5121419.80877747 392981.299341611 5121438.80894455 393001.049710309 5121461.80912832 393010.924899806 5121476.90301098 393025.925184951 5121497.80943949 393038.362923867 5121516.80960635 393058.113293343 5121539.80978982 393070.613533636 5121558.80995632 393082.988769071 5121575.81010056 393107.301699889 5121586.81012968 393126.864554048 5121600.81021148 393143.927362765 5121612.81028039 393163.552721167 5121628.81038452 393175.990461243 5121647.81055094 393195.67832541 5121666.81068871 393208.24107521 5121690.81091119 393225.428892612 5121706.81102468 393244.929243869 5121718.81108366 393269.117168119 5121725.81106744 393300.36770149 5121724.81093268 393316.930465618 5121711.81072005 393340.680854092 5121699.81049043 393366.931291185 5121691.81029627 393395.494260176 5121678.81003645 393426.619784935 5121673.8098571 393457.870317864 5121672.80972254 393493.933433088 5121671.80956902 393525.246476345 5121676.80950206 393549.43439937 5121682.80947448 393580.809942319 5121686.80939592 393604.997867081 5121693.80937958 393629.310800374 5121704.80940789 393653.436221126 5121709.80936915 393672.936572303 5121720.80941637 393697.312011842 5121734.80947815 393714.374823146 5121746.80954619 393734.000184865 5121762.80964918 393758.313120639 5121774.80968847 393782.501044747 5121780.80966054 393813.876588865 5121784.80958162 393845.064623317 5121784.80945833 393869.377557989 5121795.80948618 393893.565484088 5121802.80946941 393913.253352945 5121821.80960556 393930.378664812 5121832.80966169 393949.879019183 5121844.80971963 393974.129453519 5121855.80974747 393980.567088586 5121870.55988801 394006.005040641 5121879.80989136 394035.005558621 5121891.80991148 394061.69354385 5121907.8099857 394090.694062249 5121919.81000568 394122.25713511 5121937.81008288 394153.757708931 5121956.81017145 394178.383194166 5121992.81047819 394222.321522601 5122034.81077535 394246.571967771 5122050.81085858 394270.947420551 5122069.8109749 394295.447896778 5122100.8112253 394315.073277083 5122124.81141642 394339.44873778 5122147.8115773 394355.355301223 5122169.96801237 394376.261957671 5122195.81196876 394395.887337237 5122218.81214828 394413.262692471 5122249.81242635 394432.950587952 5122280.81269506 394452.575970121 5122304.81288546 394469.951326235 5122335.81316318 394494.326789315 5122358.81332314 394513.952172303 5122382.81351323 394533.702570425 5122413.81378107 394550.890411741 5122437.81398072 394570.578303909 5122465.81421501 394587.828650453 5122491.81443659 394607.516545024 5122520.81468184 394620.079319934 5122551.814978 394639.642203691 5122575.81516761 394657.017560798 5122605.81543301 394676.767961315 5122636.8156999 394696.455857359 5122665.81594455 394713.643700911 5122689.81614332 394733.269090836 5122715.8163545 394745.519324584 5122726.81642786 394740.082037153 5122766.81665835 394764.832648369 5122789.81667434 394789.833325575 5122820.81673085 394817.146519537 5122848.81676288 394834.709504156 5122871.81680952 394859.522638279 5122897.81684226 394879.273106525 5122913.81684432 394904.023723511 5122937.81686765 394928.836848953 5122962.81689628 394955.774941809 5122978.81686992 394973.337932572 5123002.81692346 394998.151057066 5123027.81695315 395029.9017329 5123043.81690827 395058.496141839 5123064.81690259 395086.215481581 5123078.81686417 395110.841047887 5123096.81685942 395142.654238941 5123114.81682611 395171.842330564 5123125.81676686 395203.5305036 5123141.81672417 395235.343701373 5123160.81669716 395266.906833568 5123171.81662922 395303.282541552 5123181.81653703 395339.658256907 5123192.8164504 395371.221388458 5123203.81638321 395407.472063324 5123209.81627095 395439.222735558 5123225.81623018 395468.473349008 5123239.81618895 395495.598993273 5123262.81620467 395520.349596002 5123285.81623017 395537.912581366 5123309.81628975 395557.850600111 5123332.81633486 395578.03868312 5123363.81642235 395591.164181148 5123399.81656481 395596.977014847 5123430.81670912 395610.102504936 5123465.81684662 395623.102962563 5123496.81696328 395637.353749434 5123568.81729667 395645.91672001 5123611.81749581 395651.854592615 5123647.81766739 395653.417494831 5123697.81793139 395654.667824093 5123738.81814797 395656.043170504 5123781.81837485 395652.605941696 5123825.81862529 395641.731025185 5123861.81886043 395630.731076702 5123893.81907422 395619.731128427 5123925.81928775 395601.418532393 5123954.81951223 395590.418584587 5123986.8197252 395572.168505251 5124017.8199595 395556.168419549 5124042.82015293 395537.855824659 5124071.82037606 395534.231056787 5124110.82059811 395535.606404653 5124153.82082305 395544.981758839 5124179.53967623 395548.73190043 5124189.8209675 395561.669832457 5124217.82107007 395574.607786881 5124248.82118892 395592.420824241 5124279.8212903 395607.796319737 5124310.82140083 395625.484331816 5124338.82148718 395645.672408739 5124369.82158095 395663.42294382 5124400.82168386 395683.423456846 5124423.82173593 395703.549031724 5124454.821831 395721.112002747 5124477.82189239 395745.67504009 5124493.82189127 395772.800673097 5124516.8219192 395958.867494766 5124673.13461351 395977.555427812 5124688.82213398 396009.118543949 5124699.82208402 396040.931715948 5124717.82207188 396077.057357066 5124721.82196805 396120.495636621 5124727.82184993 396168.496434268 5124725.82167189 396211.684657849 5124724.82151611 396254.997912928 5124727.82138216 396291.248570403 5124733.82128959 396327.436734009 5124740.82120298 396363.812422571 5124750.8211327 396402.375604091 5124754.82102145 396438.751299561 5124765.82095723 396474.93945521 5124771.8208658 396511.315150251 5124782.82080208 396542.878263716 5124793.82075525 396579.253958297 5124804.82069207 396618.004692763 5124815.820621 396642.630239036 5124833.82063855 396667.130768482 5124849.82064543 396698.94393558 5124867.82063893 396716.506905183 5124891.82071572 396741.25748856 5124914.82076257 396768.383111651 5124937.8208017 396786.133633971 5124968.82091883 396794.321494945 5124999.82106858 396813.38483359 5125071.82141678 396826.385275015 5125102.82155089 396839.510747052 5125137.82170776 396854.8862279 5125168.82183446 396860.76158493 5125204.82202163 396869.136890501 5125227.82212598 396873.887063443 5125240.82218496 396882.324977473 5125278.82237547 396888.387873065 5125319.82259116 396896.950824709 5125362.82281031 396898.263654907 5125405.82305318 396904.451566561 5125448.82328028 396893.576642937 5125484.82352222 396889.889346691 5125521.82374655 396878.889385499 5125552.82395972 396860.639310797 5125584.82420152 396842.389214871 5125613.82442575 396819.201529806 5125641.82465958 396802.951381453 5125658.82480822 396772.513554689 5125683.82504716 396749.138309812 5125703.82523489 396725.700564154 5125723.82542252 396695.075184765 5125741.82562109 396671.63743966 5125761.82580809 396647.319162537 5125787.41633249 - - - - 495302.815676504,5179229.61132198 496848.851735509,5179237.6171233 498462.889373269,5179247.62316423 500088.927078579,5179251.62748838 501695.962547851,5179211.60507996 503301.998167785,5179179.5824689 504914.034421812,5179180.55899068 506539.070830495,5179170.5356119 508151.107766549,5179225.51104065 509763.143811634,5179209.48807252 511387.180069969,5179185.46510066 513009.216520757,5179180.44179076 514626.252972295,5179185.41839672 516306.291369745,5179249.39311185 517916.328271882,5179332.36865748 519394.355935139,5179375.34611238 519525.325264365,5179380.28135453 521175.36375734,5179442.31544096 522796.370766589,5179501.28761151 524404.377615024,5179556.26010977 526019.384250467,5179566.23320789 527600.390098711,5179330.21047239 529189.396799056,5179301.18453868 530787.403635033,5179294.15814945 532381.410489906,5179317.13142772 533990.417465329,5179274.10537635 535605.424529336,5179255.07890249 537221.431611674,5179254.05218577 538756.412126805,5179248.02907838 540430.345259956,5179248.00759231 542032.28124317,5179264.98679513 543650.216504964,5179203.96679193 545321.149602686,5179201.94532802 546914.085935204,5179232.92441706 548516.021850388,5179243.90363668 550123.957608117,5179265.88261581 551741.892997035,5179287.86144805 553330.828407997,5179198.84213875 553351.810650603,5177595.86318564 553355.791643031,5175981.85334717 553383.771651848,5174368.84314128 553403.752034889,5172759.83301632 553427.732396188,5171162.82285219 553439.712858505,5169533.81262435 553470.693821533,5168011.80270507 554148.541998444,5167985.04144484 554149.79188147,5167979.13513634 554151.166735834,5167971.1663125 554174.155182149,5167046.78496991 554183.46475896,5166824.59587825 554191.772036319,5166399.53048851 554223.377252946,5164789.42574919 554224.189225934,5164746.42545538 554232.364692507,5163730.35619613 554234.549012593,5163461.97940743 554236.857683187,5163137.75850086 554240.601430421,5162608.34872624 554244.906755111,5162000.96967673 554246.778649942,5161738.18667267 554248.338695482,5161530.7477857 554248.525869733,5161503.15385152 554248.775540927,5161475.49741577 554251.271266753,5161113.58874818 554252.831221565,5160898.33730785 554253.579917212,5160787.86781934 554255.575923938,5160448.74055673 554255.700630369,5160423.74039029 554257.260422794,5160194.48885564 554259.007522042,5159949.14346083 554259.132296334,5159930.01833279 554259.381916446,5159897.95561735 554264.935552704,5159149.07558582 554270.426787606,5158408.69560226 554271.300335202,5158285.91352566 554274.045944533,5157915.09852562 554280.84758196,5156997.90483189 554282.532351766,5156767.34077324 554283.281150991,5156665.96508748 554287.274622583,5156114.61760652 554292.641004632,5155387.23767468 554294.825056096,5155096.329449 554295.012231495,5155068.89176298 554300.501530121,5154162.38562499 554303.745101346,5153617.78818249 554304.306478476,5153522.66253715 554304.556081921,5153489.22480916 554304.743230328,5153459.47460703 554312.041320595,5152239.34131381 554314.349359272,5151861.83874214 554323.893317074,5150293.26553368 554305.826173649,5149840.20040545 554302.700056984,5149446.01108743 554301.949803335,5149356.10442308 554302.135468315,5148767.66409191 554302.135402434,5148746.47648999 554302.822634196,5148667.69484551 554307.256891665,5147673.72120305 554308.068781662,5147486.59528035 554310.067648001,5147144.15607869 554319.374803053,5145529.42927739 554328.619462153,5143917.07743959 554332.054989073,5143322.07444199 554337.614206444,5142331.100688 554337.864068976,5142289.7879786 554338.986979247,5141635.15971549 554339.673131105,5141212.81385632 554339.735131423,5141054.4380685 554342.209073819,5140666.37355679 553744.439883277,5140665.6359454 552140.489637614,5140654.66904886 550514.540006892,5140624.70248202 548910.589773269,5140611.73553649 547286.07778693,5140615.76910864 545689.439928457,5140613.80205839 544190.486586884,5140616.8330177 542576.911810792,5140615.86630563 540952.837370015,5140612.89978375 539356.887082251,5140610.93267754 537734.925434632,5140604.9619813 536127.946556834,5140608.98539251 534329.970129577,5140608.01152846 532718.366168833,5140591.034837 531115.012187083,5140590.05813077 529512.033176919,5140583.08137621 527905.054220142,5140572.10465667 526302.075232683,5140570.12792372 524724.095912882,5140574.15084742 523113.117017892,5140575.1742278 521506.138065647,5140576.19754254 519900.159148136,5140564.22079982 518289.159252459,5140559.22819305 516683.142984441,5140571.22329294 515111.689717197,5140557.21843482 513527.89233112,5140574.21367801 511910.000819644,5140589.20884539 510293.828064161,5140601.204038 508669.592740126,5140609.19921645 507083.889113586,5140611.19450178 505559.498296073,5140634.19012381 503943.013177162,5140629.18532095 502322.652996529,5140626.1805358 500702.480180676,5140631.17582888 499099.925449201,5140637.18350592 497493.839733782,5140624.20112631 495769.747660932,5140613.22013602 495748.719955069,5142239.23124588 495748.693082425,5143884.24220147 495755.667156541,5145494.25280909 495760.64120287,5147100.26336865 495773.615683926,5148704.27380344 495770.605990571,5150333.28983519 495747.61601901,5151951.3123082 495746.626973123,5153550.33429246 495734.637160115,5155107.35571706 495738.648547533,5156735.37796876 495717.658886368,5158361.40025725 495797.673211287,5159977.23447586 495178.648737239,5159980.6429203 495145.659310535,5161586.4456535 495107.669755823,5163187.46698448 495112.681912028,5164799.4883054 495086.692865267,5166393.50936063 495088.705029187,5168017.53073455 495067.716229818,5169609.55161623 495126.729927639,5171207.57265376 495162.742991802,5172830.59400039 495197.755906868,5174450.61531256 495199.767500209,5176019.63582349 495238.783334567,5177631.64792968 495302.815676504,5179229.61132198 + + + + 495067.716229818 5140557.21843482554342.209073819 5179566.23320789 + 495302.815676504 5179229.61132198 496848.851735509 5179237.6171233 498462.889373269 5179247.62316423 500088.927078579 5179251.62748838 501695.962547851 5179211.60507996 503301.998167785 5179179.5824689 504914.034421812 5179180.55899068 506539.070830495 5179170.5356119 508151.107766549 5179225.51104065 509763.143811634 5179209.48807252 511387.180069969 5179185.46510066 513009.216520757 5179180.44179076 514626.252972295 5179185.41839672 516306.291369745 5179249.39311185 517916.328271882 5179332.36865748 519394.355935139 5179375.34611238 519525.325264365 5179380.28135453 521175.36375734 5179442.31544096 522796.370766589 5179501.28761151 524404.377615024 5179556.26010977 526019.384250467 5179566.23320789 527600.390098711 5179330.21047239 529189.396799056 5179301.18453868 530787.403635033 5179294.15814945 532381.410489906 5179317.13142772 533990.417465329 5179274.10537635 535605.424529336 5179255.07890249 537221.431611674 5179254.05218577 538756.412126805 5179248.02907838 540430.345259956 5179248.00759231 542032.28124317 5179264.98679513 543650.216504964 5179203.96679193 545321.149602686 5179201.94532802 546914.085935204 5179232.92441706 548516.021850388 5179243.90363668 550123.957608117 5179265.88261581 551741.892997035 5179287.86144805 553330.828407997 5179198.84213875 553351.810650603 5177595.86318564 553355.791643031 5175981.85334717 553383.771651848 5174368.84314128 553403.752034889 5172759.83301632 553427.732396188 5171162.82285219 553439.712858505 5169533.81262435 553470.693821533 5168011.80270507 554148.541998444 5167985.04144484 554149.79188147 5167979.13513634 554151.166735834 5167971.1663125 554174.155182149 5167046.78496991 554183.46475896 5166824.59587825 554191.772036319 5166399.53048851 554223.377252946 5164789.42574919 554224.189225934 5164746.42545538 554232.364692507 5163730.35619613 554234.549012593 5163461.97940743 554236.857683187 5163137.75850086 554240.601430421 5162608.34872624 554244.906755111 5162000.96967673 554246.778649942 5161738.18667267 554248.338695482 5161530.7477857 554248.525869733 5161503.15385152 554248.775540927 5161475.49741577 554251.271266753 5161113.58874818 554252.831221565 5160898.33730785 554253.579917212 5160787.86781934 554255.575923938 5160448.74055673 554255.700630369 5160423.74039029 554257.260422794 5160194.48885564 554259.007522042 5159949.14346083 554259.132296334 5159930.01833279 554259.381916446 5159897.95561735 554264.935552704 5159149.07558582 554270.426787606 5158408.69560226 554271.300335202 5158285.91352566 554274.045944533 5157915.09852562 554280.84758196 5156997.90483189 554282.532351766 5156767.34077324 554283.281150991 5156665.96508748 554287.274622583 5156114.61760652 554292.641004632 5155387.23767468 554294.825056096 5155096.329449 554295.012231495 5155068.89176298 554300.501530121 5154162.38562499 554303.745101346 5153617.78818249 554304.306478476 5153522.66253715 554304.556081921 5153489.22480916 554304.743230328 5153459.47460703 554312.041320595 5152239.34131381 554314.349359272 5151861.83874214 554323.893317074 5150293.26553368 554305.826173649 5149840.20040545 554302.700056984 5149446.01108743 554301.949803335 5149356.10442308 554302.135468315 5148767.66409191 554302.135402434 5148746.47648999 554302.822634196 5148667.69484551 554307.256891665 5147673.72120305 554308.068781662 5147486.59528035 554310.067648001 5147144.15607869 554319.374803053 5145529.42927739 554328.619462153 5143917.07743959 554332.054989073 5143322.07444199 554337.614206444 5142331.100688 554337.864068976 5142289.7879786 554338.986979247 5141635.15971549 554339.673131105 5141212.81385632 554339.735131423 5141054.4380685 554342.209073819 5140666.37355679 553744.439883277 5140665.6359454 552140.489637614 5140654.66904886 550514.540006892 5140624.70248202 548910.589773269 5140611.73553649 547286.07778693 5140615.76910864 545689.439928457 5140613.80205839 544190.486586884 5140616.8330177 542576.911810792 5140615.86630563 540952.837370015 5140612.89978375 539356.887082251 5140610.93267754 537734.925434632 5140604.9619813 536127.946556834 5140608.98539251 534329.970129577 5140608.01152846 532718.366168833 5140591.034837 531115.012187083 5140590.05813077 529512.033176919 5140583.08137621 527905.054220142 5140572.10465667 526302.075232683 5140570.12792372 524724.095912882 5140574.15084742 523113.117017892 5140575.1742278 521506.138065647 5140576.19754254 519900.159148136 5140564.22079982 518289.159252459 5140559.22819305 516683.142984441 5140571.22329294 515111.689717197 5140557.21843482 513527.89233112 5140574.21367801 511910.000819644 5140589.20884539 510293.828064161 5140601.204038 508669.592740126 5140609.19921645 507083.889113586 5140611.19450178 505559.498296073 5140634.19012381 503943.013177162 5140629.18532095 502322.652996529 5140626.1805358 500702.480180676 5140631.17582888 499099.925449201 5140637.18350592 497493.839733782 5140624.20112631 495769.747660932 5140613.22013602 495748.719955069 5142239.23124588 495748.693082425 5143884.24220147 495755.667156541 5145494.25280909 495760.64120287 5147100.26336865 495773.615683926 5148704.27380344 495770.605990571 5150333.28983519 495747.61601901 5151951.3123082 495746.626973123 5153550.33429246 495734.637160115 5155107.35571706 495738.648547533 5156735.37796876 495717.658886368 5158361.40025725 495797.673211287 5159977.23447586 495178.648737239 5159980.6429203 495145.659310535 5161586.4456535 495107.669755823 5163187.46698448 495112.681912028 5164799.4883054 495086.692865267 5166393.50936063 495088.705029187 5168017.53073455 495067.716229818 5169609.55161623 495126.729927639 5171207.57265376 495162.742991802 5172830.59400039 495197.755906868 5174450.61531256 495199.767500209 5176019.63582349 495238.783334567 5177631.64792968 495302.815676504 5179229.61132198 - - - - 495769.747660932,5140613.22013602 497493.839733782,5140624.20112631 499099.925449201,5140637.18350592 500702.480180676,5140631.17582888 502322.652996529,5140626.1805358 503943.013177162,5140629.18532095 505559.498296073,5140634.19012381 507083.889113586,5140611.19450178 508669.592740126,5140609.19921645 510293.828064161,5140601.204038 511910.000819644,5140589.20884539 513527.89233112,5140574.21367801 515111.689717197,5140557.21843482 516683.142984441,5140571.22329294 518289.159252459,5140559.22819305 519900.159148136,5140564.22079982 521506.138065647,5140576.19754254 523113.117017892,5140575.1742278 524724.095912882,5140574.15084742 526302.075232683,5140570.12792372 527905.054220142,5140572.10465667 529512.033176919,5140583.08137621 531115.012187083,5140590.05813077 532718.366168833,5140591.034837 534329.970129577,5140608.01152846 536127.946556834,5140608.98539251 537734.925434632,5140604.9619813 539356.887082251,5140610.93267754 540952.837370015,5140612.89978375 542576.911810792,5140615.86630563 544190.486586884,5140616.8330177 545689.439928457,5140613.80205839 547286.07778693,5140615.76910864 548910.589773269,5140611.73553649 550514.540006892,5140624.70248202 552140.489637614,5140654.66904886 553744.439883277,5140665.6359454 554342.209073819,5140666.37355679 554342.233833628,5140666.37358734 554342.358772653,5140648.21724442 554352.603403535,5139042.67776921 554362.910511869,5137431.91946821 554372.34305014,5135950.28679076 554374.092605357,5135825.9111256 554379.778688583,5135430.65900772 554382.215254471,5135157.87632369 554390.399518766,5134210.62133909 554403.706775292,5132676.01947908 554404.206573933,5132616.98791651 554416.451723541,5131196.88662423 554417.451338271,5131084.32352432 554418.388476769,5130978.6979612 554424.011233388,5130321.53820713 554426.322826127,5130056.09928885 554425.135289221,5130034.2866976 554431.509937198,5129978.34879021 554434.009678648,5129918.47343372 554438.13425802,5129821.50410496 554438.696698607,5129807.62902265 554442.759014259,5129784.44132778 554445.571389713,5129769.34744787 554445.008323505,5129586.22150791 554447.257595597,5129376.28287651 554448.632153618,5129248.87593935 554441.694558447,5129159.90685325 554443.569481045,5129151.50052536 554445.506511538,5129020.28105749 554453.316871103,5128413.18400358 554456.003313945,5128103.40108881 554452.814810878,5127761.61811038 554449.438747144,5127399.71002693 554447.437918208,5127123.23986379 554447.062796869,5127082.1146548 554448.562504679,5127002.89546264 554455.184985191,5126267.76648391 554455.184676468,5126171.07847522 554455.058527227,5125810.29532751 554454.054583054,5124569.50753942 554452.79948873,5122971.90532119 554452.172098942,5122223.96383826 554453.484041657,5122060.83794376 554455.674360441,5121405.49590233 554456.362027103,5121363.65225197 554478.679820162,5120033.59289083 554478.99355503,5119750.28113143 554480.875596368,5118133.66033641 554481.377553571,5117684.22399995 554484.944978905,5116540.78940651 554489.701491879,5115028.26197265 554491.139379615,5114932.29344219 554514.833354161,5113333.29707605 554522.335407162,5112827.07946503 554534.589770591,5111770.45689264 554535.027392622,5111740.45695946 554535.652606605,5111688.55082766 554551.658348326,5110300.52273345 554554.159240296,5110084.99196981 554572.353248283,5108514.05798831 554576.292166395,5108172.18374812 554591.234780263,5106936.90520942 554590.672454214,5106899.81156213 554584.799324661,5106499.93766508 554592.616912497,5105303.62790302 554592.429485455,5105287.81544546 554581.933214056,5104483.0363755 554581.186729472,5103682.88207219 554581.249264502,5103674.60084072 554584.189251516,5103093.22717131 554584.564675901,5102994.57114941 554590.691312287,5102594.04071861 554591.253978603,5102553.60330241 554568.629437552,5102545.85383945 554480.818797228,5102497.51221917 554394.758125457,5102448.29556352 554325.69710991,5102404.35975707 554236.511316787,5102396.23682528 554140.200644842,5102390.95780032 554105.951326077,5102381.70861039 554006.203309133,5102354.77347075 553895.642898913,5102350.46352219 553832.456554275,5102357.37120581 553772.707675745,5102356.96632954 553682.584419698,5102343.62468572 553609.335862589,5102326.43891521 553461.77634549,5102272.4737048 553355.153599082,5102208.32008551 553224.156442003,5102109.51087989 553154.032950968,5102059.10638963 553148.845548024,5102059.04400946 553140.658238217,5102049.57547528 553044.910189871,5102007.51530512 552994.223573846,5102023.20392956 552950.661870638,5102027.26742294 552890.975457625,5102034.11253008 552790.97741619,5102010.02115849 552709.666511637,5101989.42934651 552639.980380199,5101971.27475981 552566.481923366,5101925.55784552 552503.358245955,5101886.62192277 552479.483745789,5101871.90376969 552397.110439891,5101828.87455699 552346.799029958,5101787.43834941 552318.924663206,5101756.43909103 552255.488376177,5101747.22183884 552182.302315528,5101725.59860195 552058.804813389,5101669.5703917 551982.556406799,5101620.25981795 551833.559557177,5101511.88862801 551704.874931212,5101372.79832701 551595.689948365,5101229.98884483 551523.941768908,5101086.83474873 551457.818362936,5100977.61791267 551411.319606158,5100864.55688417 551380.82056902,5100746.96424872 551334.821931918,5100594.55959859 551317.760111766,5100486.65411858 551300.573136332,5100424.65473556 551297.510729787,5100413.59234561 551270.386672281,5100281.59343787 551227.387872398,5100157.87612939 551193.451336726,5100054.50228915 551188.951743405,5099958.12772837 551168.140058366,5099827.84742246 551161.578091684,5099704.5667546 551158.953466592,5099607.19215365 551118.89198163,5099519.19341386 551055.705905587,5099432.22647519 551007.831993604,5099362.9466117 550964.520459462,5099305.35409998 550921.771455629,5099235.07412108 550866.022686856,5099163.32571097 550820.898685985,5099103.95200429 550798.024323204,5099033.54655423 550790.587333623,5098917.45339688 550789.52493389,5098892.45351158 550789.087588548,5098847.32868299 550788.71273913,5098803.11009965 550805.400313442,5098689.48510191 550816.71303623,5098559.79778976 550822.838257872,5098458.73550047 550825.588512559,5098365.86076342 550859.713439288,5098204.67300627 550885.463345372,5098095.45401594 550883.026099186,5098031.11055205 550870.339222261,5097908.76754253 550862.339671889,5097814.14307154 550835.527951187,5097718.80031329 550805.028886145,5097594.89524803 550809.654053215,5097518.92665392 550789.154710702,5097426.20873526 550751.530758417,5097304.21009257 550714.906553155,5097254.36742052 550673.844942598,5097198.58738006 550590.721755413,5097080.55860137 550542.160233131,5097036.37245824 550491.973709423,5097001.09257416 550365.163777452,5096878.15865468 550334.852109523,5096778.34727154 550310.727814306,5096684.81696374 550316.290469509,5096604.31712294 550309.728175924,5096574.03614743 550318.978190406,5096518.5673725 550326.790640858,5096491.62977781 550313.228427415,5096473.94267983 550296.916313546,5096439.25571311 550289.041689036,5096361.53744597 550297.291764992,5096291.81874812 550308.541688008,5096255.00610377 550322.354089704,5096211.13092128 550317.291897743,5096139.75631034 550284.542665925,5096071.25738025 550247.668392169,5096038.50842221 550217.23146193,5096020.94674768 550180.419666482,5095994.54151571 550104.296075735,5095955.01231634 549989.673197379,5095894.54666119 549850.988229078,5095831.51912271 549789.114369961,5095799.0207972 549702.17851544,5095738.21071076 549622.054824984,5095752.46266394 549498.119437673,5095744.68455112 549458.745151586,5095727.24810707 549379.121568022,5095701.18770715 549323.247485056,5095709.93907356 549308.747725346,5095711.40818131 549254.561116424,5095719.40950802 549162.812631523,5095730.911762 549121.125806116,5095741.22526522 549075.751533407,5095755.10134605 548969.753307069,5095760.60397996 548872.567449687,5095759.70016915 548831.880561098,5095787.8260719 548759.694280633,5095787.60913109 548668.820810466,5095789.42389983 548559.447587701,5095816.36402521 548491.136141183,5095855.49056886 548439.949388799,5095901.52290282 548366.825545358,5095933.39959453 548304.326424988,5096004.24460061 548194.828244741,5096019.05977103 547988.394076832,5096088.78336742 547861.146149204,5096125.91137619 547703.523643693,5096204.53995125 547698.398724912,5096207.10256733 547469.52754957,5096238.45187426 547259.530969925,5096309.17552288 547100.2835743,5096360.74174086 547009.535044148,5096397.83757056 546897.536815154,5096465.30878043 546758.976469298,5096569.59296632 546667.352936202,5096620.126242 546581.166812912,5096670.47188094 546471.04354446,5096750.53671288 546346.732980185,5096853.82052419 546260.484326146,5096926.29104226 546139.173822117,5096977.26252863 546089.487147772,5096994.38866717 546078.23733479,5096998.26392488 545939.364607453,5097066.89199786 545807.491745403,5097146.23858723 545797.804358794,5097176.51991972 545763.742428123,5097188.208197 545612.307453801,5097245.02412425 545455.622652952,5097256.43416338 545332.499832048,5097230.96857232 545228.189170155,5097213.53372805 545091.754058384,5097199.88090418 544968.568701521,5097195.54020531 544885.945138796,5097192.69850155 544835.133531849,5097184.88729308 544768.38474138,5097150.10787432 544655.636770422,5097098.92342916 544506.514470127,5097016.42755734 544424.703441951,5096975.71105005 544228.894428452,5096899.65380548 544087.771959286,5096826.9702006 543971.711544846,5096760.47344728 543804.589568653,5096641.38451572 543683.904238125,5096561.41921796 543572.968767686,5096452.86010173 543476.28303757,5096352.30059195 543376.097356744,5096256.27239851 543279.286644267,5096130.58805322 543174.538568908,5095996.09146618 543096.290071761,5095825.62569112 543083.540359618,5095754.22018835 543073.415608845,5095676.4709084 543052.603528349,5095608.65933726 543043.041216238,5095582.12848651 543015.604254459,5095506.06713256 543011.541940421,5095386.28670537 543031.791665603,5095319.1928493 543036.104133727,5095278.00548819 543022.416925227,5095215.47495881 542971.167886651,5095111.10187962 542934.293582281,5095029.94705025 542907.294089969,5094971.10433811 542832.670466591,5094831.95081922 542759.109314617,5094698.20349685 542699.047897229,5094604.54934263 542614.611937776,5094444.95871608 542548.363098513,5094370.17961229 542494.551552431,5094293.4939562 542461.364642398,5094242.7138662 542457.677225166,5094215.90162597 542448.739895674,5094187.62077892 542372.488737527,5093978.65562436 542360.801056537,5093946.56242515 542309.112311312,5093767.22140284 542326.921786931,5093532.22280021 542331.920230532,5093405.3799217 542258.045219705,5093304.53883344 542092.232986639,5093107.07581767 541872.735145832,5093003.01966359 541630.736858292,5092838.05828172 541553.486502912,5092713.87367658 541475.23533276,5092524.59583772 541470.733414002,5092365.34716469 541479.8578229,5092328.81596462 541503.418796123,5092234.22234624 541561.729180114,5092132.84666223 541662.539346825,5092063.18842708 541740.162327585,5091990.59329668 541731.286383227,5091902.87544188 541656.411309875,5091809.12802645 541484.160549609,5091550.10303766 541272.41156773,5091394.89071915 541186.974460643,5091332.23705942 541108.474813244,5091274.70818659 541001.850639414,5091224.4612031 540845.164685801,5091177.40293178 540681.479676533,5091195.43809871 540516.857879928,5091265.25415992 540460.733977699,5091289.09912509 540324.04837952,5091289.54000824 540236.11256392,5091323.54193943 540181.426148367,5091347.16812319 540118.489899045,5091374.3257366 539974.430807429,5091474.82858421 539923.306818993,5091495.82970216 539822.308315667,5091501.1759217 539654.62293823,5091484.36770569 539634.060698161,5091482.30573092 539496.874622779,5091447.12188651 539430.625709959,5091458.02970369 539347.252245524,5091483.15659615 538901.82538179,5091775.79062633 538715.641387779,5091830.95113367 538533.645830736,5091945.14211264 538303.400263202,5092009.92830984 538046.343180148,5092111.4023769 537951.0326951,5092148.99809719 537688.287930376,5092230.94117665 537489.541848367,5092289.28916968 537413.793434159,5092317.19699642 537397.856179987,5092317.47861736 537217.859784307,5092372.85743922 537020.613266138,5092403.45558747 536776.616341385,5092364.11782328 536726.866708995,5092340.05665768 536705.741865714,5092329.90097392 536632.492407924,5092294.71543747 536585.867693434,5092268.71671314 536365.056530663,5092145.69150694 536158.431488057,5091953.16646956 535810.494785362,5091686.92653195 535607.868614117,5091436.43308542 535550.054839239,5091309.24785732 535526.054308586,5091256.49880046 535361.30292556,5091030.91054732 535197.739366394,5090827.75961084 534983.302928682,5090708.54677201 534975.990390074,5090700.1095053 534879.614878251,5090589.08132967 534855.799773533,5090416.61438987 534876.608963023,5090239.95892745 534836.043226101,5090017.05524812 534817.790979542,5089870.74423803 534817.039536308,5089785.74487069 534821.414110595,5089764.40117162 534838.974905119,5089678.87012473 534878.597079132,5089545.43265137 534882.406579019,5089372.77755804 534847.715288643,5089123.28018157 534810.713355892,5088981.06333606 534782.586301887,5088839.03377921 534725.023444326,5088773.25437114 534701.7736268,5088765.78622723 534616.83679632,5088738.75718989 534503.588062959,5088724.57248241 534218.779208096,5088715.67306195 534153.842315869,5088700.86221224 534096.780553753,5088699.55107727 534002.906770908,5088697.58457155 533875.907879244,5088664.33783136 533794.657462215,5088579.34038347 533629.220857022,5088505.9073536 533565.158226408,5088450.78428096 533468.471505822,5088422.8180355 533371.5346313,5088386.19561015 533345.222300536,5088376.2588091 533246.098566801,5088374.04243326 533134.100287361,5088387.66999686 533053.351642428,5088403.79679844 532947.789912736,5088369.36206378 532873.540227785,5088332.73910107 532509.166881397,5088161.06154654 532428.354532438,5088111.68883798 532145.980028413,5087939.16560066 532032.104583705,5087835.57533889 531976.791977225,5087791.38948815 531944.729045281,5087745.92184295 531861.791778069,5087701.14290642 531791.854590106,5087669.73856017 531769.729688322,5087659.80166253 531692.105634678,5087657.17853421 531549.482170086,5087641.55705451 531328.546886412,5087609.00007167 531105.424480406,5087595.19300065 530949.301344763,5087588.19677961 530815.239800053,5087548.54403017 530587.989829637,5087399.51933915 530361.739724948,5087245.99466495 530276.613639391,5087134.90379811 530201.425892234,5087073.71856372 530178.238315577,5087054.8755124 530166.925778738,5087045.71960301 530073.112856642,5086964.03497242 529996.049952806,5086894.31860062 529899.73769556,5086845.63377937 529789.363666918,5086825.32407778 529688.740368069,5086848.20131101 529494.493905717,5086904.79927491 529373.49582456,5086925.45826143 529247.684695074,5086915.52384933 529166.184278109,5086843.93260436 529096.933960279,5086785.15346782 529056.24665812,5086769.87331063 528969.434367144,5086726.78197412 528861.121365829,5086635.50402786 528742.122196648,5086604.06962396 528628.436532059,5086625.54093117 528594.562252274,5086640.44787669 528522.688782083,5086672.07435211 528341.693613527,5086799.10894473 528193.946475428,5086849.20584002 528075.822557464,5086830.36506603 528065.510088577,5086825.6466 527999.760301715,5086796.33590466 527940.135041522,5086747.86896365 527913.884925928,5086726.52601027 527900.507649324,5086608.33976038 527905.631045558,5086533.77772395 527908.755069676,5086488.40300583 527969.935319263,5086173.34151323 528006.744198495,5086019.31058801 528031.116158065,5085885.96729806 528016.801707287,5085783.03094922 527981.988494533,5085728.40721481 527891.613954849,5085698.78462118 527780.553104804,5085714.8496666 527660.617419261,5085733.66490349 527562.118626276,5085735.44850864 527432.244961223,5085725.51421095 527337.370899841,5085716.54781397 527247.871960968,5085716.48746736 527197.685451768,5085735.26977585 527128.748771501,5085735.30268376 527083.999147679,5085727.92881864 527031.187090902,5085719.21140819 526951.500687246,5085726.3070187 526862.876663815,5085722.71542908 526789.440092505,5085725.37342445 526707.128588975,5085726.25039747 526663.191266112,5085710.06408344 526576.441035807,5085651.03539149 526470.815790519,5085581.1322417 526398.440800242,5085541.72804887 526267.8143935,5085404.73229071 526208.813406882,5085326.82808613 526133.687661253,5085251.61174947 526005.749479571,5085151.30313868 525934.18575,5085056.33687744 525876.997590496,5084995.55749565 525774.059986827,5084936.34170608 525712.122429799,5084901.09348486 525643.434864606,5084862.03295775 525563.809308518,5084794.94167141 525527.18311805,5084721.47439883 525480.432353319,5084662.3197558 525445.806784436,5084618.47719655 525307.180536708,5084490.45033238 525256.180183479,5084448.35815621 525164.929648197,5084377.67343567 525114.804138952,5084329.23754085 525078.178360449,5084275.55136234 525065.676875733,5084202.17725981 525082.799247978,5084092.02148807 525136.731363179,5083875.36568599 525150.229969059,5083818.95956524 525119.91607812,5083741.08593065 525083.227968253,5083695.49343971 525015.22749572,5083640.87053201 524881.853261333,5083610.34276616 524797.728752767,5083591.56371031 524684.103419219,5083521.6607867 524516.790512188,5083423.13440168 524406.727079277,5083329.13784184 524348.539358438,5083291.73331102 524257.320423798,5083240.45469684 524072.975713012,5083111.52273351 523995.193273789,5083022.90035144 523870.536556867,5082944.74777554 523849.317726914,5082931.46715093 523746.442946063,5082893.84496389 523675.754916731,5082838.34714099 523572.034805653,5082731.72554414 523465.503325469,5082673.57236842 523351.877500948,5082586.70085376 523287.471129895,5082552.67145458 523219.471600665,5082542.76694407 523170.222398242,5082555.36179053 523102.160700595,5082559.7696632 523019.817631392,5082552.58422999 522925.817890391,5082522.11802415 522847.911523316,5082482.71400065 522779.068248294,5082472.80951167 522676.099132467,5082412.00002842 522583.972869627,5082317.87805913 522510.751757,5082185.41219931 522445.407215215,5082123.60180991 522355.938355149,5082080.63560336 522304.90702684,5082055.54330932 522268.0,5082010.16958982 522245.905907833,5081983.01410646 522218.24799108,5081900.70296995 522151.183405212,5081784.23683287 522118.058565398,5081777.14395229 522107.652081143,5081762.89432596 522050.119530341,5081683.99014334 521959.836363481,5081565.80584201 521904.427080188,5081415.40220842 521806.050176923,5081295.40562429 521736.361320744,5081210.37679555 521638.798921699,5081175.37948123 521552.047630877,5081086.7573533 521509.171192366,5081009.69655305 521500.263137414,5080930.91618412 521420.729350447,5080793.98178856 521339.321128633,5080680.26599542 521330.444228291,5080597.89190719 521312.629500438,5080498.51818188 521232.189330561,5080357.02135212 521149.00133893,5080305.0863367 521079.311686957,5080189.83902419 521064.154908118,5080162.30837969 520984.527127586,5080017.87406021 520943.711927634,5079891.5323831 520911.491440783,5079808.19013152 520845.333744257,5079724.53622009 520733.019447553,5079610.07120933 520678.579743701,5079500.1984832 520642.79704178,5079427.98122832 520547.760564012,5079180.70442154 520508.163114216,5079015.89429761 520454.754459399,5078899.39660678 520366.409151145,5078805.68083873 520320.470709426,5078751.74493411 520303.344046281,5078678.3709813 520331.467299477,5078616.90205635 520391.746725926,5078563.05726936 520484.805189179,5078429.86859109 520467.08377477,5078315.37000025 520442.456839998,5078228.40259782 520379.670641144,5078006.43728687 520318.410473331,5077573.59872656 520227.403646236,5077268.2285798 520243.650506458,5077145.94796097 520188.741108066,5077001.66930245 520130.927676593,5076946.51496206 520092.364552924,5076909.70373633 519940.143532455,5076772.67744857 519871.6410893,5076654.11766659 519803.263239278,5076519.58926871 519758.262173949,5076463.77836818 519707.605788464,5076443.71730519 519641.730802684,5076425.31285877 519570.605738453,5076402.31483303 519477.168372371,5076380.91110195 519397.76236417,5076367.88194885 519329.35664538,5076369.32080713 519255.980060639,5076284.88550096 519215.447162592,5076207.32447978 519092.819894412,5076080.85928294 519087.069834222,5076076.76568395 518929.943206973,5075965.36356215 518680.877962343,5075781.18269435 518506.312666539,5075616.21892506 518354.746343315,5075416.0050175 518298.181700958,5075312.16333726 518240.804530774,5075206.79044069 518212.832647039,5075071.38596346 518200.203039623,5074881.04416176 518261.164746312,5074615.35776503 518287.412799618,5074544.98284723 518401.623040541,5074237.79569916 518450.679042617,5073991.51559776 518494.489266897,5073913.98411745 518497.800052583,5073845.98464487 518566.35882161,5073718.07808583 518574.358384786,5073703.10929978 518643.573359234,5073573.89023206 518675.819223336,5073418.23466318 518686.25583899,5073386.14097374 518727.127784287,5073276.95356544 518770.188669651,5073226.42184938 518806.278999855,5073101.20342542 518833.052560087,5072801.73670198 518818.172294192,5072585.48888734 518726.197100836,5072295.36835572 518584.818466704,5072100.31056835 518507.722742472,5071993.93814527 518147.000360161,5071720.13578819 517996.093251593,5071631.60856814 517714.463120206,5071321.80490865 517541.550912004,5071015.90515659 517486.67423325,5070927.18839981 517371.701977201,5070741.34883498 517325.134407101,5070516.60189141 517321.071465435,5070497.00840821 517315.008311529,5070467.97755455 517131.465213529,5069912.86164261 517075.770270269,5069585.95961113 517004.567228692,5068919.84229127 517000.160020265,5068878.71776642 516997.815762788,5068856.93676833 516877.740684883,5068291.4134032 516747.919276087,5067871.23270709 516658.074530766,5067792.89172011 516480.947581747,5067638.42843006 516301.474970896,5067402.96596768 516202.817110283,5067294.28174024 516074.408775172,5067152.84850915 515893.874616341,5066954.10452861 515660.402139589,5066697.08109542 515350.931932957,5066500.12137847 515252.209107856,5066285.09448824 515227.426317466,5066202.06522534 515208.362664928,5066139.6917276 515171.330043942,5066058.50646442 515140.704343312,5066011.32047405 515077.98508073,5065957.16659232 515034.109929957,5065928.85558567 514987.578595246,5065902.29461005 514964.921365397,5065846.13983452 514904.607569742,5065757.11148287 514849.044479065,5065702.86368084 514792.481244811,5065641.52227023 514773.887419227,5065628.99165989 514713.637173165,5065588.3374827 514616.949307903,5065524.46578352 514551.542748757,5065478.40556277 514460.418275543,5065458.31424451 514321.138030146,5065436.78655562 514311.512994071,5065430.44313314 514270.106587703,5065403.10079269 514228.699537633,5065346.1339482 514168.573644724,5065275.79275576 514091.416569648,5065200.2957877 513995.541158195,5065134.73657938 513924.853518293,5065093.92637879 513879.103270323,5065060.27173699 513840.634367204,5065034.52304618 513817.070760505,5064972.14962395 513740.976909832,5064930.52705584 513621.133138238,5064871.28077813 513535.945053981,5064803.00260584 513446.22508532,5064703.3500536 513421.535750777,5064606.97721166 513387.410085961,5064559.82251892 513305.721633215,5064476.32575796 513173.284087993,5064409.92361498 513034.910236196,5064395.52074699 512853.724361751,5064382.27508195 512766.28759974,5064373.74595858 512720.474578948,5064327.56025598 512668.567797679,5064277.9372469 512575.442971553,5064240.72121893 512482.223565524,5064165.31831459 512402.472862269,5064094.2900304 512377.253908737,5064072.69720353 511062.392778509,5064071.91450292 509457.409628247,5064066.95095005 507903.301034838,5064065.98619059 506303.005568183,5064071.02239891 504702.459958992,5064069.05872826 503088.821052274,5064081.09516618 501481.713509822,5064101.13136529 499857.508514904,5064110.1681411 498300.449057285,5064129.20350494 496691.169585719,5064134.24028947 495086.89002906,5064130.27709148 493493.361208123,5064153.31341955 491872.206767928,5064171.35049707 490277.552024482,5064146.3873352 488947.308563874,5064129.41802083 488951.993514498,5065755.4076836 488963.362488911,5067334.38565655 488955.82394657,5068945.35767412 488955.129678321,5070583.32900462 488951.340430278,5072144.30170687 488951.395791378,5073758.27334245 488949.982506543,5075382.24478543 488948.350288336,5076995.21637679 488949.780433451,5078595.18808382 488952.085812196,5080210.15946079 488967.578720022,5081806.13086345 488966.603498611,5083471.10132991 488959.62738009,5085087.0727308 488960.651301265,5086693.04410525 488942.143396357,5088296.01584302 488938.698739494,5089923.98680048 488938.722481702,5091522.95816492 488938.728721907,5091943.35687819 489257.737604697,5091942.9451303 490293.766474881,5091942.92726372 490603.306351279,5091942.92192925 490883.814225059,5091946.5420335 491916.936983,5091959.89901845 492488.890332139,5091953.85803386 492786.742335496,5091950.72796563 493533.106969024,5091955.30881303 494107.873015854,5091956.54892235 495168.121370497,5091958.84319296 495653.63491057,5091958.83486902 495729.480807959,5091960.70853896 495718.945751742,5093579.80772311 495723.957943447,5095178.77149585 495729.963918394,5096779.7308946 495733.969895892,5098394.68992644 495743.976059032,5099997.64911727 495749.983476115,5101977.59875299 495753.98952509,5103597.55750941 495770.996088307,5105202.51638607 495793.002926426,5106803.47523639 495820.010010398,5108384.43446898 495831.016509534,5109990.39328381 495834.022797801,5111638.35111148 495843.029308365,5113258.30950871 495830.03459665,5114867.2685059 495827.040391883,5116474.22734309 495835.046800069,5118075.18610661 495835.052794276,5119689.14462307 495822.057922962,5121293.10356628 495835.043321767,5122871.09719571 495850.017037609,5124518.10854358 495856.990847918,5126129.11972733 495883.965846267,5127742.13058836 495858.938034687,5129335.14203562 495864.911866238,5130943.15308686 495862.885291437,5132548.16418396 495858.858328788,5134171.17538212 495830.829879582,5135804.18689701 495828.803448126,5137406.19781468 495815.776178388,5139024.20891946 495769.747660932,5140613.22013602 + + + + 488938.698739494 5064065.98619059554592.616912497 5140666.37358734 + 495769.747660932 5140613.22013602 497493.839733782 5140624.20112631 499099.925449201 5140637.18350592 500702.480180676 5140631.17582888 502322.652996529 5140626.1805358 503943.013177162 5140629.18532095 505559.498296073 5140634.19012381 507083.889113586 5140611.19450178 508669.592740126 5140609.19921645 510293.828064161 5140601.204038 511910.000819644 5140589.20884539 513527.89233112 5140574.21367801 515111.689717197 5140557.21843482 516683.142984441 5140571.22329294 518289.159252459 5140559.22819305 519900.159148136 5140564.22079982 521506.138065647 5140576.19754254 523113.117017892 5140575.1742278 524724.095912882 5140574.15084742 526302.075232683 5140570.12792372 527905.054220142 5140572.10465667 529512.033176919 5140583.08137621 531115.012187083 5140590.05813077 532718.366168833 5140591.034837 534329.970129577 5140608.01152846 536127.946556834 5140608.98539251 537734.925434632 5140604.9619813 539356.887082251 5140610.93267754 540952.837370015 5140612.89978375 542576.911810792 5140615.86630563 544190.486586884 5140616.8330177 545689.439928457 5140613.80205839 547286.07778693 5140615.76910864 548910.589773269 5140611.73553649 550514.540006892 5140624.70248202 552140.489637614 5140654.66904886 553744.439883277 5140665.6359454 554342.209073819 5140666.37355679 554342.233833628 5140666.37358734 554342.358772653 5140648.21724442 554352.603403535 5139042.67776921 554362.910511869 5137431.91946821 554372.34305014 5135950.28679076 554374.092605357 5135825.9111256 554379.778688583 5135430.65900772 554382.215254471 5135157.87632369 554390.399518766 5134210.62133909 554403.706775292 5132676.01947908 554404.206573933 5132616.98791651 554416.451723541 5131196.88662423 554417.451338271 5131084.32352432 554418.388476769 5130978.6979612 554424.011233388 5130321.53820713 554426.322826127 5130056.09928885 554425.135289221 5130034.2866976 554431.509937198 5129978.34879021 554434.009678648 5129918.47343372 554438.13425802 5129821.50410496 554438.696698607 5129807.62902265 554442.759014259 5129784.44132778 554445.571389713 5129769.34744787 554445.008323505 5129586.22150791 554447.257595597 5129376.28287651 554448.632153618 5129248.87593935 554441.694558447 5129159.90685325 554443.569481045 5129151.50052536 554445.506511538 5129020.28105749 554453.316871103 5128413.18400358 554456.003313945 5128103.40108881 554452.814810878 5127761.61811038 554449.438747144 5127399.71002693 554447.437918208 5127123.23986379 554447.062796869 5127082.1146548 554448.562504679 5127002.89546264 554455.184985191 5126267.76648391 554455.184676468 5126171.07847522 554455.058527227 5125810.29532751 554454.054583054 5124569.50753942 554452.79948873 5122971.90532119 554452.172098942 5122223.96383826 554453.484041657 5122060.83794376 554455.674360441 5121405.49590233 554456.362027103 5121363.65225197 554478.679820162 5120033.59289083 554478.99355503 5119750.28113143 554480.875596368 5118133.66033641 554481.377553571 5117684.22399995 554484.944978905 5116540.78940651 554489.701491879 5115028.26197265 554491.139379615 5114932.29344219 554514.833354161 5113333.29707605 554522.335407162 5112827.07946503 554534.589770591 5111770.45689264 554535.027392622 5111740.45695946 554535.652606605 5111688.55082766 554551.658348326 5110300.52273345 554554.159240296 5110084.99196981 554572.353248283 5108514.05798831 554576.292166395 5108172.18374812 554591.234780263 5106936.90520942 554590.672454214 5106899.81156213 554584.799324661 5106499.93766508 554592.616912497 5105303.62790302 554592.429485455 5105287.81544546 554581.933214056 5104483.0363755 554581.186729472 5103682.88207219 554581.249264502 5103674.60084072 554584.189251516 5103093.22717131 554584.564675901 5102994.57114941 554590.691312287 5102594.04071861 554591.253978603 5102553.60330241 554568.629437552 5102545.85383945 554480.818797228 5102497.51221917 554394.758125457 5102448.29556352 554325.69710991 5102404.35975707 554236.511316787 5102396.23682528 554140.200644842 5102390.95780032 554105.951326077 5102381.70861039 554006.203309133 5102354.77347075 553895.642898913 5102350.46352219 553832.456554275 5102357.37120581 553772.707675745 5102356.96632954 553682.584419698 5102343.62468572 553609.335862589 5102326.43891521 553461.77634549 5102272.4737048 553355.153599082 5102208.32008551 553224.156442003 5102109.51087989 553154.032950968 5102059.10638963 553148.845548024 5102059.04400946 553140.658238217 5102049.57547528 553044.910189871 5102007.51530512 552994.223573846 5102023.20392956 552950.661870638 5102027.26742294 552890.975457625 5102034.11253008 552790.97741619 5102010.02115849 552709.666511637 5101989.42934651 552639.980380199 5101971.27475981 552566.481923366 5101925.55784552 552503.358245955 5101886.62192277 552479.483745789 5101871.90376969 552397.110439891 5101828.87455699 552346.799029958 5101787.43834941 552318.924663206 5101756.43909103 552255.488376177 5101747.22183884 552182.302315528 5101725.59860195 552058.804813389 5101669.5703917 551982.556406799 5101620.25981795 551833.559557177 5101511.88862801 551704.874931212 5101372.79832701 551595.689948365 5101229.98884483 551523.941768908 5101086.83474873 551457.818362936 5100977.61791267 551411.319606158 5100864.55688417 551380.82056902 5100746.96424872 551334.821931918 5100594.55959859 551317.760111766 5100486.65411858 551300.573136332 5100424.65473556 551297.510729787 5100413.59234561 551270.386672281 5100281.59343787 551227.387872398 5100157.87612939 551193.451336726 5100054.50228915 551188.951743405 5099958.12772837 551168.140058366 5099827.84742246 551161.578091684 5099704.5667546 551158.953466592 5099607.19215365 551118.89198163 5099519.19341386 551055.705905587 5099432.22647519 551007.831993604 5099362.9466117 550964.520459462 5099305.35409998 550921.771455629 5099235.07412108 550866.022686856 5099163.32571097 550820.898685985 5099103.95200429 550798.024323204 5099033.54655423 550790.587333623 5098917.45339688 550789.52493389 5098892.45351158 550789.087588548 5098847.32868299 550788.71273913 5098803.11009965 550805.400313442 5098689.48510191 550816.71303623 5098559.79778976 550822.838257872 5098458.73550047 550825.588512559 5098365.86076342 550859.713439288 5098204.67300627 550885.463345372 5098095.45401594 550883.026099186 5098031.11055205 550870.339222261 5097908.76754253 550862.339671889 5097814.14307154 550835.527951187 5097718.80031329 550805.028886145 5097594.89524803 550809.654053215 5097518.92665392 550789.154710702 5097426.20873526 550751.530758417 5097304.21009257 550714.906553155 5097254.36742052 550673.844942598 5097198.58738006 550590.721755413 5097080.55860137 550542.160233131 5097036.37245824 550491.973709423 5097001.09257416 550365.163777452 5096878.15865468 550334.852109523 5096778.34727154 550310.727814306 5096684.81696374 550316.290469509 5096604.31712294 550309.728175924 5096574.03614743 550318.978190406 5096518.5673725 550326.790640858 5096491.62977781 550313.228427415 5096473.94267983 550296.916313546 5096439.25571311 550289.041689036 5096361.53744597 550297.291764992 5096291.81874812 550308.541688008 5096255.00610377 550322.354089704 5096211.13092128 550317.291897743 5096139.75631034 550284.542665925 5096071.25738025 550247.668392169 5096038.50842221 550217.23146193 5096020.94674768 550180.419666482 5095994.54151571 550104.296075735 5095955.01231634 549989.673197379 5095894.54666119 549850.988229078 5095831.51912271 549789.114369961 5095799.0207972 549702.17851544 5095738.21071076 549622.054824984 5095752.46266394 549498.119437673 5095744.68455112 549458.745151586 5095727.24810707 549379.121568022 5095701.18770715 549323.247485056 5095709.93907356 549308.747725346 5095711.40818131 549254.561116424 5095719.40950802 549162.812631523 5095730.911762 549121.125806116 5095741.22526522 549075.751533407 5095755.10134605 548969.753307069 5095760.60397996 548872.567449687 5095759.70016915 548831.880561098 5095787.8260719 548759.694280633 5095787.60913109 548668.820810466 5095789.42389983 548559.447587701 5095816.36402521 548491.136141183 5095855.49056886 548439.949388799 5095901.52290282 548366.825545358 5095933.39959453 548304.326424988 5096004.24460061 548194.828244741 5096019.05977103 547988.394076832 5096088.78336742 547861.146149204 5096125.91137619 547703.523643693 5096204.53995125 547698.398724912 5096207.10256733 547469.52754957 5096238.45187426 547259.530969925 5096309.17552288 547100.2835743 5096360.74174086 547009.535044148 5096397.83757056 546897.536815154 5096465.30878043 546758.976469298 5096569.59296632 546667.352936202 5096620.126242 546581.166812912 5096670.47188094 546471.04354446 5096750.53671288 546346.732980185 5096853.82052419 546260.484326146 5096926.29104226 546139.173822117 5096977.26252863 546089.487147772 5096994.38866717 546078.23733479 5096998.26392488 545939.364607453 5097066.89199786 545807.491745403 5097146.23858723 545797.804358794 5097176.51991972 545763.742428123 5097188.208197 545612.307453801 5097245.02412425 545455.622652952 5097256.43416338 545332.499832048 5097230.96857232 545228.189170155 5097213.53372805 545091.754058384 5097199.88090418 544968.568701521 5097195.54020531 544885.945138796 5097192.69850155 544835.133531849 5097184.88729308 544768.38474138 5097150.10787432 544655.636770422 5097098.92342916 544506.514470127 5097016.42755734 544424.703441951 5096975.71105005 544228.894428452 5096899.65380548 544087.771959286 5096826.9702006 543971.711544846 5096760.47344728 543804.589568653 5096641.38451572 543683.904238125 5096561.41921796 543572.968767686 5096452.86010173 543476.28303757 5096352.30059195 543376.097356744 5096256.27239851 543279.286644267 5096130.58805322 543174.538568908 5095996.09146618 543096.290071761 5095825.62569112 543083.540359618 5095754.22018835 543073.415608845 5095676.4709084 543052.603528349 5095608.65933726 543043.041216238 5095582.12848651 543015.604254459 5095506.06713256 543011.541940421 5095386.28670537 543031.791665603 5095319.1928493 543036.104133727 5095278.00548819 543022.416925227 5095215.47495881 542971.167886651 5095111.10187962 542934.293582281 5095029.94705025 542907.294089969 5094971.10433811 542832.670466591 5094831.95081922 542759.109314617 5094698.20349685 542699.047897229 5094604.54934263 542614.611937776 5094444.95871608 542548.363098513 5094370.17961229 542494.551552431 5094293.4939562 542461.364642398 5094242.7138662 542457.677225166 5094215.90162597 542448.739895674 5094187.62077892 542372.488737527 5093978.65562436 542360.801056537 5093946.56242515 542309.112311312 5093767.22140284 542326.921786931 5093532.22280021 542331.920230532 5093405.3799217 542258.045219705 5093304.53883344 542092.232986639 5093107.07581767 541872.735145832 5093003.01966359 541630.736858292 5092838.05828172 541553.486502912 5092713.87367658 541475.23533276 5092524.59583772 541470.733414002 5092365.34716469 541479.8578229 5092328.81596462 541503.418796123 5092234.22234624 541561.729180114 5092132.84666223 541662.539346825 5092063.18842708 541740.162327585 5091990.59329668 541731.286383227 5091902.87544188 541656.411309875 5091809.12802645 541484.160549609 5091550.10303766 541272.41156773 5091394.89071915 541186.974460643 5091332.23705942 541108.474813244 5091274.70818659 541001.850639414 5091224.4612031 540845.164685801 5091177.40293178 540681.479676533 5091195.43809871 540516.857879928 5091265.25415992 540460.733977699 5091289.09912509 540324.04837952 5091289.54000824 540236.11256392 5091323.54193943 540181.426148367 5091347.16812319 540118.489899045 5091374.3257366 539974.430807429 5091474.82858421 539923.306818993 5091495.82970216 539822.308315667 5091501.1759217 539654.62293823 5091484.36770569 539634.060698161 5091482.30573092 539496.874622779 5091447.12188651 539430.625709959 5091458.02970369 539347.252245524 5091483.15659615 538901.82538179 5091775.79062633 538715.641387779 5091830.95113367 538533.645830736 5091945.14211264 538303.400263202 5092009.92830984 538046.343180148 5092111.4023769 537951.0326951 5092148.99809719 537688.287930376 5092230.94117665 537489.541848367 5092289.28916968 537413.793434159 5092317.19699642 537397.856179987 5092317.47861736 537217.859784307 5092372.85743922 537020.613266138 5092403.45558747 536776.616341385 5092364.11782328 536726.866708995 5092340.05665768 536705.741865714 5092329.90097392 536632.492407924 5092294.71543747 536585.867693434 5092268.71671314 536365.056530663 5092145.69150694 536158.431488057 5091953.16646956 535810.494785362 5091686.92653195 535607.868614117 5091436.43308542 535550.054839239 5091309.24785732 535526.054308586 5091256.49880046 535361.30292556 5091030.91054732 535197.739366394 5090827.75961084 534983.302928682 5090708.54677201 534975.990390074 5090700.1095053 534879.614878251 5090589.08132967 534855.799773533 5090416.61438987 534876.608963023 5090239.95892745 534836.043226101 5090017.05524812 534817.790979542 5089870.74423803 534817.039536308 5089785.74487069 534821.414110595 5089764.40117162 534838.974905119 5089678.87012473 534878.597079132 5089545.43265137 534882.406579019 5089372.77755804 534847.715288643 5089123.28018157 534810.713355892 5088981.06333606 534782.586301887 5088839.03377921 534725.023444326 5088773.25437114 534701.7736268 5088765.78622723 534616.83679632 5088738.75718989 534503.588062959 5088724.57248241 534218.779208096 5088715.67306195 534153.842315869 5088700.86221224 534096.780553753 5088699.55107727 534002.906770908 5088697.58457155 533875.907879244 5088664.33783136 533794.657462215 5088579.34038347 533629.220857022 5088505.9073536 533565.158226408 5088450.78428096 533468.471505822 5088422.8180355 533371.5346313 5088386.19561015 533345.222300536 5088376.2588091 533246.098566801 5088374.04243326 533134.100287361 5088387.66999686 533053.351642428 5088403.79679844 532947.789912736 5088369.36206378 532873.540227785 5088332.73910107 532509.166881397 5088161.06154654 532428.354532438 5088111.68883798 532145.980028413 5087939.16560066 532032.104583705 5087835.57533889 531976.791977225 5087791.38948815 531944.729045281 5087745.92184295 531861.791778069 5087701.14290642 531791.854590106 5087669.73856017 531769.729688322 5087659.80166253 531692.105634678 5087657.17853421 531549.482170086 5087641.55705451 531328.546886412 5087609.00007167 531105.424480406 5087595.19300065 530949.301344763 5087588.19677961 530815.239800053 5087548.54403017 530587.989829637 5087399.51933915 530361.739724948 5087245.99466495 530276.613639391 5087134.90379811 530201.425892234 5087073.71856372 530178.238315577 5087054.8755124 530166.925778738 5087045.71960301 530073.112856642 5086964.03497242 529996.049952806 5086894.31860062 529899.73769556 5086845.63377937 529789.363666918 5086825.32407778 529688.740368069 5086848.20131101 529494.493905717 5086904.79927491 529373.49582456 5086925.45826143 529247.684695074 5086915.52384933 529166.184278109 5086843.93260436 529096.933960279 5086785.15346782 529056.24665812 5086769.87331063 528969.434367144 5086726.78197412 528861.121365829 5086635.50402786 528742.122196648 5086604.06962396 528628.436532059 5086625.54093117 528594.562252274 5086640.44787669 528522.688782083 5086672.07435211 528341.693613527 5086799.10894473 528193.946475428 5086849.20584002 528075.822557464 5086830.36506603 528065.510088577 5086825.6466 527999.760301715 5086796.33590466 527940.135041522 5086747.86896365 527913.884925928 5086726.52601027 527900.507649324 5086608.33976038 527905.631045558 5086533.77772395 527908.755069676 5086488.40300583 527969.935319263 5086173.34151323 528006.744198495 5086019.31058801 528031.116158065 5085885.96729806 528016.801707287 5085783.03094922 527981.988494533 5085728.40721481 527891.613954849 5085698.78462118 527780.553104804 5085714.8496666 527660.617419261 5085733.66490349 527562.118626276 5085735.44850864 527432.244961223 5085725.51421095 527337.370899841 5085716.54781397 527247.871960968 5085716.48746736 527197.685451768 5085735.26977585 527128.748771501 5085735.30268376 527083.999147679 5085727.92881864 527031.187090902 5085719.21140819 526951.500687246 5085726.3070187 526862.876663815 5085722.71542908 526789.440092505 5085725.37342445 526707.128588975 5085726.25039747 526663.191266112 5085710.06408344 526576.441035807 5085651.03539149 526470.815790519 5085581.1322417 526398.440800242 5085541.72804887 526267.8143935 5085404.73229071 526208.813406882 5085326.82808613 526133.687661253 5085251.61174947 526005.749479571 5085151.30313868 525934.18575 5085056.33687744 525876.997590496 5084995.55749565 525774.059986827 5084936.34170608 525712.122429799 5084901.09348486 525643.434864606 5084862.03295775 525563.809308518 5084794.94167141 525527.18311805 5084721.47439883 525480.432353319 5084662.3197558 525445.806784436 5084618.47719655 525307.180536708 5084490.45033238 525256.180183479 5084448.35815621 525164.929648197 5084377.67343567 525114.804138952 5084329.23754085 525078.178360449 5084275.55136234 525065.676875733 5084202.17725981 525082.799247978 5084092.02148807 525136.731363179 5083875.36568599 525150.229969059 5083818.95956524 525119.91607812 5083741.08593065 525083.227968253 5083695.49343971 525015.22749572 5083640.87053201 524881.853261333 5083610.34276616 524797.728752767 5083591.56371031 524684.103419219 5083521.6607867 524516.790512188 5083423.13440168 524406.727079277 5083329.13784184 524348.539358438 5083291.73331102 524257.320423798 5083240.45469684 524072.975713012 5083111.52273351 523995.193273789 5083022.90035144 523870.536556867 5082944.74777554 523849.317726914 5082931.46715093 523746.442946063 5082893.84496389 523675.754916731 5082838.34714099 523572.034805653 5082731.72554414 523465.503325469 5082673.57236842 523351.877500948 5082586.70085376 523287.471129895 5082552.67145458 523219.471600665 5082542.76694407 523170.222398242 5082555.36179053 523102.160700595 5082559.7696632 523019.817631392 5082552.58422999 522925.817890391 5082522.11802415 522847.911523316 5082482.71400065 522779.068248294 5082472.80951167 522676.099132467 5082412.00002842 522583.972869627 5082317.87805913 522510.751757 5082185.41219931 522445.407215215 5082123.60180991 522355.938355149 5082080.63560336 522304.90702684 5082055.54330932 522268.000077275 5082010.16958982 522245.905907833 5081983.01410646 522218.24799108 5081900.70296995 522151.183405212 5081784.23683287 522118.058565398 5081777.14395229 522107.652081143 5081762.89432596 522050.119530341 5081683.99014334 521959.836363481 5081565.80584201 521904.427080188 5081415.40220842 521806.050176923 5081295.40562429 521736.361320744 5081210.37679555 521638.798921699 5081175.37948123 521552.047630877 5081086.7573533 521509.171192366 5081009.69655305 521500.263137414 5080930.91618412 521420.729350447 5080793.98178856 521339.321128633 5080680.26599542 521330.444228291 5080597.89190719 521312.629500438 5080498.51818188 521232.189330561 5080357.02135212 521149.00133893 5080305.0863367 521079.311686957 5080189.83902419 521064.154908118 5080162.30837969 520984.527127586 5080017.87406021 520943.711927634 5079891.5323831 520911.491440783 5079808.19013152 520845.333744257 5079724.53622009 520733.019447553 5079610.07120933 520678.579743701 5079500.1984832 520642.79704178 5079427.98122832 520547.760564012 5079180.70442154 520508.163114216 5079015.89429761 520454.754459399 5078899.39660678 520366.409151145 5078805.68083873 520320.470709426 5078751.74493411 520303.344046281 5078678.3709813 520331.467299477 5078616.90205635 520391.746725926 5078563.05726936 520484.805189179 5078429.86859109 520467.08377477 5078315.37000025 520442.456839998 5078228.40259782 520379.670641144 5078006.43728687 520318.410473331 5077573.59872656 520227.403646236 5077268.2285798 520243.650506458 5077145.94796097 520188.741108066 5077001.66930245 520130.927676593 5076946.51496206 520092.364552924 5076909.70373633 519940.143532455 5076772.67744857 519871.6410893 5076654.11766659 519803.263239278 5076519.58926871 519758.262173949 5076463.77836818 519707.605788464 5076443.71730519 519641.730802684 5076425.31285877 519570.605738453 5076402.31483303 519477.168372371 5076380.91110195 519397.76236417 5076367.88194885 519329.35664538 5076369.32080713 519255.980060639 5076284.88550096 519215.447162592 5076207.32447978 519092.819894412 5076080.85928294 519087.069834222 5076076.76568395 518929.943206973 5075965.36356215 518680.877962343 5075781.18269435 518506.312666539 5075616.21892506 518354.746343315 5075416.0050175 518298.181700958 5075312.16333726 518240.804530774 5075206.79044069 518212.832647039 5075071.38596346 518200.203039623 5074881.04416176 518261.164746312 5074615.35776503 518287.412799618 5074544.98284723 518401.623040541 5074237.79569916 518450.679042617 5073991.51559776 518494.489266897 5073913.98411745 518497.800052583 5073845.98464487 518566.35882161 5073718.07808583 518574.358384786 5073703.10929978 518643.573359234 5073573.89023206 518675.819223336 5073418.23466318 518686.25583899 5073386.14097374 518727.127784287 5073276.95356544 518770.188669651 5073226.42184938 518806.278999855 5073101.20342542 518833.052560087 5072801.73670198 518818.172294192 5072585.48888734 518726.197100836 5072295.36835572 518584.818466704 5072100.31056835 518507.722742472 5071993.93814527 518147.000360161 5071720.13578819 517996.093251593 5071631.60856814 517714.463120206 5071321.80490865 517541.550912004 5071015.90515659 517486.67423325 5070927.18839981 517371.701977201 5070741.34883498 517325.134407101 5070516.60189141 517321.071465435 5070497.00840821 517315.008311529 5070467.97755455 517131.465213529 5069912.86164261 517075.770270269 5069585.95961113 517004.567228692 5068919.84229127 517000.160020265 5068878.71776642 516997.815762788 5068856.93676833 516877.740684883 5068291.4134032 516747.919276087 5067871.23270709 516658.074530766 5067792.89172011 516480.947581747 5067638.42843006 516301.474970896 5067402.96596768 516202.817110283 5067294.28174024 516074.408775172 5067152.84850915 515893.874616341 5066954.10452861 515660.402139589 5066697.08109542 515350.931932957 5066500.12137847 515252.209107856 5066285.09448824 515227.426317466 5066202.06522534 515208.362664928 5066139.6917276 515171.330043942 5066058.50646442 515140.704343312 5066011.32047405 515077.98508073 5065957.16659232 515034.109929957 5065928.85558567 514987.578595246 5065902.29461005 514964.921365397 5065846.13983452 514904.607569742 5065757.11148287 514849.044479065 5065702.86368084 514792.481244811 5065641.52227023 514773.887419227 5065628.99165989 514713.637173165 5065588.3374827 514616.949307903 5065524.46578352 514551.542748757 5065478.40556277 514460.418275543 5065458.31424451 514321.138030146 5065436.78655562 514311.512994071 5065430.44313314 514270.106587703 5065403.10079269 514228.699537633 5065346.1339482 514168.573644724 5065275.79275576 514091.416569648 5065200.2957877 513995.541158195 5065134.73657938 513924.853518293 5065093.92637879 513879.103270323 5065060.27173699 513840.634367204 5065034.52304618 513817.070760505 5064972.14962395 513740.976909832 5064930.52705584 513621.133138238 5064871.28077813 513535.945053981 5064803.00260584 513446.22508532 5064703.3500536 513421.535750777 5064606.97721166 513387.410085961 5064559.82251892 513305.721633215 5064476.32575796 513173.284087993 5064409.92361498 513034.910236196 5064395.52074699 512853.724361751 5064382.27508195 512766.28759974 5064373.74595858 512720.474578948 5064327.56025598 512668.567797679 5064277.9372469 512575.442971553 5064240.72121893 512482.223565524 5064165.31831459 512402.472862269 5064094.2900304 512377.253908737 5064072.69720353 511062.392778509 5064071.91450292 509457.409628247 5064066.95095005 507903.301034838 5064065.98619059 506303.005568183 5064071.02239891 504702.459958992 5064069.05872826 503088.821052274 5064081.09516618 501481.713509822 5064101.13136529 499857.508514904 5064110.1681411 498300.449057285 5064129.20350494 496691.169585719 5064134.24028947 495086.89002906 5064130.27709148 493493.361208123 5064153.31341955 491872.206767928 5064171.35049707 490277.552024482 5064146.3873352 488947.308563874 5064129.41802083 488951.993514498 5065755.4076836 488963.362488911 5067334.38565655 488955.82394657 5068945.35767412 488955.129678321 5070583.32900462 488951.340430278 5072144.30170687 488951.395791378 5073758.27334245 488949.982506543 5075382.24478543 488948.350288336 5076995.21637679 488949.780433451 5078595.18808382 488952.085812196 5080210.15946079 488967.578720022 5081806.13086345 488966.603498611 5083471.10132991 488959.62738009 5085087.0727308 488960.651301265 5086693.04410525 488942.143396357 5088296.01584302 488938.698739494 5089923.98680048 488938.722481702 5091522.95816492 488938.728721907 5091943.35687819 489257.737604697 5091942.9451303 490293.766474881 5091942.92726372 490603.306351279 5091942.92192925 490883.814225059 5091946.5420335 491916.936983 5091959.89901845 492488.890332139 5091953.85803386 492786.742335496 5091950.72796563 493533.106969024 5091955.30881303 494107.873015854 5091956.54892235 495168.121370497 5091958.84319296 495653.63491057 5091958.83486902 495729.480807959 5091960.70853896 495718.945751742 5093579.80772311 495723.957943447 5095178.77149585 495729.963918394 5096779.7308946 495733.969895892 5098394.68992644 495743.976059032 5099997.64911727 495749.983476115 5101977.59875299 495753.98952509 5103597.55750941 495770.996088307 5105202.51638607 495793.002926426 5106803.47523639 495820.010010398 5108384.43446898 495831.016509534 5109990.39328381 495834.022797801 5111638.35111148 495843.029308365 5113258.30950871 495830.03459665 5114867.2685059 495827.040391883 5116474.22734309 495835.046800069 5118075.18610661 495835.052794276 5119689.14462307 495822.057922962 5121293.10356628 495835.043321767 5122871.09719571 495850.017037609 5124518.10854358 495856.990847918 5126129.11972733 495883.965846267 5127742.13058836 495858.938034687 5129335.14203562 495864.911866238 5130943.15308686 495862.885291437 5132548.16418396 495858.858328788 5134171.17538212 495830.829879582 5135804.18689701 495828.803448126 5137406.19781468 495815.776178388 5139024.20891946 495769.747660932 5140613.22013602 - - - - 438623.813339239,5121376.09834029 439268.330052994,5121375.71365614 440877.37695095,5121394.6590622 442433.41800387,5121415.6095591 444012.438820035,5121440.57537843 445555.459188838,5121450.54218051 447142.480120161,5121473.5079516 448848.502614519,5121502.47117366 450644.526317509,5121524.43260388 452150.546221549,5121533.40039558 453901.569310636,5121566.36280177 455534.590852865,5121594.3278256 457106.611589166,5121622.29420132 458729.164257097,5121647.19708141 458863.634782301,5121649.25671468 460382.654975318,5121633.22463705 461978.681115782,5121582.17868885 463582.716668467,5121567.10778504 465169.751832345,5121562.03758123 466796.788476539,5121475.96660114 466806.804704029,5119187.99361209 466825.816297009,5117602.01185281 466837.82780885,5116011.03046653 466840.839130967,5114420.0494352 466801.849456444,5112811.07011109 466657.856325405,5111261.0935366 466632.866852024,5109653.11330102 466609.877339502,5108056.13277789 466589.575273206,5106476.15188722 466571.491993683,5104899.17081937 466559.908942111,5103319.18954126 466559.920202827,5101716.20818807 466518.898924679,5100094.22799554 466510.94108788,5098501.24660003 466507.952266847,5096898.26517664 466491.962848709,5095312.283773 466503.973831077,5093696.30281881 466501.981832964,5092081.29258997 464966.925456697,5092134.34856581 464893.922778272,5092135.94350583 463946.419248898,5092156.64646804 463318.864953662,5092169.65673431 463291.863961833,5092170.21967628 462445.583082424,5092165.76503196 461635.834808413,5092161.49728313 461618.802937696,5092161.40381719 460610.997352688,5092152.80308464 460025.768559792,5092147.78839446 459868.765849071,5092147.98032192 459859.768794261,5091855.45249348 459795.783384233,5090371.47038962 459780.800153885,5088762.4882138 459800.817670382,5087147.50499564 459819.834954137,5085557.52145021 459806.851424333,5083986.53863791 459795.868361068,5082376.55613539 459785.885309762,5080768.57353337 459803.90294958,5079156.58997051 459838.920779818,5077568.60547445 459847.93848736,5075940.62221269 459857.956280213,5074310.63885958 459893.973142688,5072831.65289935 459922.991558528,5071198.66869116 459988.01118836,5069548.68316325 460017.02975173,5067916.69870545 460032.04539514,5066264.71406684 460041.028713195,5064660.7197052 460131.011340174,5062777.72341361 460144.994716183,5061168.72902498 460122.977060133,5059557.7358896 460077.958996613,5057968.74334245 460051.941257301,5056360.75013156 460043.923999539,5054751.75629883 460056.907247183,5053136.76185339 460071.891694615,5051630.7669731 460074.874724017,5050022.77280059 460087.85787808,5048401.77842505 460107.841019503,5046762.78397566 460144.824871777,5045148.78911013 458524.781590879,5045176.82370185 456908.73824789,5045187.85830708 455289.694928309,5045207.89301589 453679.651972685,5045238.9276109 452069.60898391,5045265.96227953 450454.566100183,5045315.99723879 448848.52322357,5045342.03199364 447227.479844585,5045357.06705671 445602.43635967,5045371.10223244 443990.393022387,5045363.13693017 442376.349896029,5045381.17194423 440741.310287012,5045399.18928944 440743.325486712,5047051.20963912 440743.340272337,5048666.2294772 440737.355311769,5050328.24981781 440743.370475576,5051976.26998853 440736.385283229,5053624.29005426 440740.400672329,5055309.31056787 440738.41510013,5056909.32997383 440732.429559395,5058529.3495573 440719.443697991,5060141.36896486 440710.45771364,5061732.38808982 440713.472395444,5063361.4076792 440704.486013821,5064917.42629141 440736.501443889,5066530.44573053 440761.497686472,5068130.41721815 440748.49242791,5069747.3876625 440740.487379777,5071357.35826486 440722.482032441,5072973.32878071 440689.476298381,5074578.29956977 440650.470456414,5076176.27058634 440593.464060144,5077802.24127423 440526.457438358,5079432.21209404 440496.764629372,5081004.18385891 440462.196598954,5082623.15488739 440413.784341035,5084296.12516544 440404.342141333,5085902.09633443 440428.369623751,5087503.06719217 440489.866800447,5089115.03726386 440467.143033784,5090726.00846609 440435.387686029,5092390.7289012 439141.605134714,5092415.81236261 438919.380788042,5092423.34716401 438811.503081546,5092422.50521428 437422.874361799,5092480.40230125 437240.307268621,5092487.43647359 437249.335970774,5094066.0056598 437263.332731688,5095662.99035577 437285.329488268,5097271.9769604 437321.326614066,5098877.96324363 437351.32362098,5100475.94963939 437351.3196229,5102176.93580248 437374.316482574,5103766.92231232 437389.313116093,5105366.90887882 437403.309687181,5106983.89528868 437394.305703213,5108574.88247635 437399.30209855,5110162.86930928 437431.299201951,5111764.85524216 437452.2960581,5113347.84157795 437456.292405097,5114947.82823075 437485.289502675,5116528.81424446 437484.285556978,5118193.80044963 437489.281897405,5119808.78685956 437492.278289034,5121376.77370461 438623.813339239,5121376.09834029 + + + + 437240.307268621 5045148.78911013466840.839130967 5121649.25671468 + 438623.813339239 5121376.09834029 439268.330052994 5121375.71365614 440877.37695095 5121394.6590622 442433.41800387 5121415.6095591 444012.438820035 5121440.57537843 445555.459188838 5121450.54218051 447142.480120161 5121473.5079516 448848.502614519 5121502.47117366 450644.526317509 5121524.43260388 452150.546221549 5121533.40039558 453901.569310636 5121566.36280177 455534.590852865 5121594.3278256 457106.611589166 5121622.29420132 458729.164257097 5121647.19708141 458863.634782301 5121649.25671468 460382.654975318 5121633.22463705 461978.681115782 5121582.17868885 463582.716668467 5121567.10778504 465169.751832345 5121562.03758123 466796.788476539 5121475.96660114 466806.804704029 5119187.99361209 466825.816297009 5117602.01185281 466837.82780885 5116011.03046653 466840.839130967 5114420.0494352 466801.849456444 5112811.07011109 466657.856325405 5111261.0935366 466632.866852024 5109653.11330102 466609.877339502 5108056.13277789 466589.575273206 5106476.15188722 466571.491993683 5104899.17081937 466559.908942111 5103319.18954126 466559.920202827 5101716.20818807 466518.898924679 5100094.22799554 466510.94108788 5098501.24660003 466507.952266847 5096898.26517664 466491.962848709 5095312.283773 466503.973831077 5093696.30281881 466501.981832964 5092081.29258997 464966.925456697 5092134.34856581 464893.922778272 5092135.94350583 463946.419248898 5092156.64646804 463318.864953662 5092169.65673431 463291.863961833 5092170.21967628 462445.583082424 5092165.76503196 461635.834808413 5092161.49728313 461618.802937696 5092161.40381719 460610.997352688 5092152.80308464 460025.768559792 5092147.78839446 459868.765849071 5092147.98032192 459859.768794261 5091855.45249348 459795.783384233 5090371.47038962 459780.800153885 5088762.4882138 459800.817670382 5087147.50499564 459819.834954137 5085557.52145021 459806.851424333 5083986.53863791 459795.868361068 5082376.55613539 459785.885309762 5080768.57353337 459803.90294958 5079156.58997051 459838.920779818 5077568.60547445 459847.93848736 5075940.62221269 459857.956280213 5074310.63885958 459893.973142688 5072831.65289935 459922.991558528 5071198.66869116 459988.01118836 5069548.68316325 460017.02975173 5067916.69870545 460032.04539514 5066264.71406684 460041.028713195 5064660.7197052 460131.011340174 5062777.72341361 460144.994716183 5061168.72902498 460122.977060133 5059557.7358896 460077.958996613 5057968.74334245 460051.941257301 5056360.75013156 460043.923999539 5054751.75629883 460056.907247183 5053136.76185339 460071.891694615 5051630.7669731 460074.874724017 5050022.77280059 460087.85787808 5048401.77842505 460107.841019503 5046762.78397566 460144.824871777 5045148.78911013 458524.781590879 5045176.82370185 456908.73824789 5045187.85830708 455289.694928309 5045207.89301589 453679.651972685 5045238.9276109 452069.60898391 5045265.96227953 450454.566100183 5045315.99723879 448848.52322357 5045342.03199364 447227.479844585 5045357.06705671 445602.43635967 5045371.10223244 443990.393022387 5045363.13693017 442376.349896029 5045381.17194423 440741.310287012 5045399.18928944 440743.325486712 5047051.20963912 440743.340272337 5048666.2294772 440737.355311769 5050328.24981781 440743.370475576 5051976.26998853 440736.385283229 5053624.29005426 440740.400672329 5055309.31056787 440738.41510013 5056909.32997383 440732.429559395 5058529.3495573 440719.443697991 5060141.36896486 440710.45771364 5061732.38808982 440713.472395444 5063361.4076792 440704.486013821 5064917.42629141 440736.501443889 5066530.44573053 440761.497686472 5068130.41721815 440748.49242791 5069747.3876625 440740.487379777 5071357.35826486 440722.482032441 5072973.32878071 440689.476298381 5074578.29956977 440650.470456414 5076176.27058634 440593.464060144 5077802.24127423 440526.457438358 5079432.21209404 440496.764629372 5081004.18385891 440462.196598954 5082623.15488739 440413.784341035 5084296.12516544 440404.342141333 5085902.09633443 440428.369623751 5087503.06719217 440489.866800447 5089115.03726386 440467.143033784 5090726.00846609 440435.387686029 5092390.7289012 439141.605134714 5092415.81236261 438919.380788042 5092423.34716401 438811.503081546 5092422.50521428 437422.874361799 5092480.40230125 437240.307268621 5092487.43647359 437249.335970774 5094066.0056598 437263.332731688 5095662.99035577 437285.329488268 5097271.9769604 437321.326614066 5098877.96324363 437351.32362098 5100475.94963939 437351.3196229 5102176.93580248 437374.316482574 5103766.92231232 437389.313116093 5105366.90887882 437403.309687181 5106983.89528868 437394.305703213 5108574.88247635 437399.30209855 5110162.86930928 437431.299201951 5111764.85524216 437452.2960581 5113347.84157795 437456.292405097 5114947.82823075 437485.289502675 5116528.81424446 437484.285556978 5118193.80044963 437489.281897405 5119808.78685956 437492.278289034 5121376.77370461 438623.813339239 5121376.09834029 - + --xxOGRBoundaryxx -Content-Disposition: attachment; filename=foo -bar.xsd +Content-Disposition: attachment; filename=some_default_value.xsd Content-Type: application/binary Content-Transfer-Encoding: binary - - - + + + + 0 + + + + + - - - + + + + + + + + + + + + + + - + - + diff --git a/msautotest/query/expected/template_test003.html b/msautotest/query/expected/template_test003.html new file mode 100644 index 0000000000..0a838d9fdf --- /dev/null +++ b/msautotest/query/expected/template_test003.html @@ -0,0 +1,12 @@ +This template tests using includes with feature template outputs + + -------------------------------------- + + ITEM TAGS: Itasca:ITAS + OLD-STYLE TAG (case sensitive): Itasca, [cty_name] + SHPEXT (basic): 393234.396569 5207990.085063 495769.579719 5305374.105135 + SHPEXT (precision=0): 393234 5207990 495770 5305374 + SHPXY (basic): 393866,5300138 395523,5300136 397144,5300118 398752,5300104 400380,5300034 401965,5299989 403581,5300010 404767,5299982 405120,5299977 406366,5299956 406722,5299951 407974,5299917 408331,5299909 409570,5299883 409937,5299880 411181,5299865 411547,5299861 412780,5299847 414343,5299848 415911,5299855 417536,5299887 419145,5299867 420760,5299876 422374,5299890 423981,5299858 424128,5299855 425613,5299828 425729,5299826 427239,5299805 427348,5299804 428874,5299781 428952,5299780 430512,5299759 432162,5299703 433927,5299681 435451,5299644 437102,5299610 438726,5299576 440357,5299550 440925,5299538 441929,5299516 441941,5300503 441949,5301109 441955,5302102 441959,5302727 441978,5303713 441989,5304322 442014,5305357 442015,5305374 442596,5305369 444194,5305325 445821,5305309 445815,5305154 447390,5305157 447442,5305156 448977,5305135 449043,5305134 450576,5305128 450635,5305127 452199,5305116 452249,5305120 453754,5305109 453810,5305109 455407,5305106 455433,5305106 457040,5305138 457173,5305129 458645,5305038 458759,5305033 460233,5304960 460360,5304953 460406,5304952 461842,5304892 461988,5304885 463126,5304831 463431,5304813 463565,5304805 465166,5304734 466793,5304674 468343,5304651 469918,5304631 471522,5304617 473063,5304601 474644,5304583 476305,5304557 477853,5304548 479479,5304528 481072,5304501 482571,5304505 484183,5304464 484398,5304459 485843,5304429 486014,5304429 487506,5304434 487621,5304431 489170,5304395 490786,5304405 492411,5304374 493956,5304318 493960,5302956 493955,5302734 493922,5301581 493913,5301362 493904,5301150 493847,5299769 493838,5299557 493783,5298156 493777,5297965 493732,5296551 493732,5296389 493729,5294777 493751,5293151 493776,5291609 493807,5290018 493825,5288433 493826,5286900 493836,5285241 495395,5285231 495408,5283573 495352,5281952 495301,5280443 495241,5278740 495210,5277133 495209,5275537 495167,5273752 495273,5272126 495275,5270449 495199,5268885 495207,5267287 495203,5265676 495171,5263944 495123,5262364 495093,5260757 494952,5259160 494928,5257612 494810,5256034 494797,5254433 494779,5252833 494776,5251262 494771,5249647 494796,5248054 494969,5246452 495131,5246452 495135,5244676 495126,5243073 495109,5241447 495069,5239827 495020,5238223 495020,5236591 495028,5234980 495019,5233363 495024,5231767 495038,5230143 495040,5228535 495043,5226943 495058,5225324 495030,5223734 495004,5222124 494996,5220524 494971,5218930 494960,5217314 495736,5217312 495750,5216091 495770,5214498 495758,5212917 495759,5211279 495763,5209684 495747,5208110 494141,5208087 492543,5208082 490905,5208083 489296,5208051 487695,5208030 485482,5207990 483907,5208023 482340,5208086 480784,5208136 479172,5208171 477560,5208249 475930,5208364 474328,5208369 472733,5208372 471117,5208381 469529,5208376 467933,5208380 466193,5208388 464622,5208454 463040,5208499 461439,5208509 459821,5208522 458225,5208581 456597,5208600 455033,5208636 453438,5208629 451834,5208602 450247,5208574 448644,5208608 446806,5208679 445198,5208718 443587,5208743 441972,5208775 441092,5208824 441094,5209273 441117,5210407 441127,5210880 441156,5212012 441168,5212489 441195,5213565 441208,5214080 441228,5215148 441237,5215666 441258,5216733 441268,5217255 441268,5217580 441265,5218876 441266,5219175 441268,5220482 441271,5220814 441284,5222092 441287,5222412 441300,5223699 441305,5224022 441328,5225307 441330,5225412 441334,5225613 441353,5226488 441363,5226925 441366,5227299 441376,5228519 441377,5228914 441369,5228923 441362,5228964 441335,5229071 441308,5229097 441216,5229098 441158,5229073 441121,5229005 441125,5228898 441137,5228829 441182,5228758 441167,5228725 441128,5228713 441012,5228706 440983,5228711 440938,5228720 440725,5228712 440707,5228735 440705,5228763 440774,5228871 440793,5228929 440778,5228991 440688,5229121 440654,5229226 440619,5229305 440544,5229374 440523,5229394 440453,5229428 440336,5229473 440225,5229517 439952,5229619 439777,5229631 439732,5229671 439732,5229671 439678,5229719 439671,5229726 439626,5229782 439500,5229908 439407,5229988 439382,5230049 439408,5230135 439425,5230156 439434,5230168 439439,5230182 439468,5230269 439466,5230315 439441,5230369 439245,5230587 439226,5230640 439216,5230701 439260,5230802 439306,5231002 439297,5231145 439275,5231242 439258,5231298 439248,5231331 439186,5231425 439114,5231411 438984,5231361 438979,5231360 438913,5231350 438821,5231333 438781,5231336 438720,5231359 438673,5231436 438639,5231591 438647,5231682 438676,5231725 438696,5231733 438849,5231752 438869,5231787 438873,5231845 438874,5231852 438875,5231873 438848,5231967 438818,5231988 438763,5232029 438639,5232089 438581,5232135 438507,5232388 438515,5232423 438549,5232453 438582,5232438 438697,5232335 438735,5232317 438806,5232273 438834,5232272 438969,5232319 438992,5232344 439087,5232473 439127,5232584 439136,5232719 439086,5232882 439041,5233162 439056,5233255 439084,5233337 439153,5233461 439161,5233474 439200,5233549 439370,5233710 439521,5233848 439535,5233868 439547,5233884 439578,5233960 439576,5234005 439578,5234168 439591,5234246 439632,5234302 439696,5234311 439850,5234198 439850,5234198 439930,5234139 440001,5234107 440057,5234120 440074,5234139 440091,5234157 440119,5234216 440122,5234269 440159,5234340 440207,5234375 440258,5234384 440395,5234388 440573,5234366 440669,5234370 440718,5234415 440773,5234503 440748,5234570 440680,5234652 440571,5234709 440534,5234742 440470,5234768 440380,5234828 440307,5234894 440214,5235020 440187,5235075 440187,5235075 440162,5235127 440160,5235152 440208,5235198 440285,5235207 440325,5235189 440365,5235160 440406,5235135 440484,5235069 440484,5235069 440547,5235016 440643,5234980 440706,5234982 440725,5235017 440722,5235045 440715,5235064 440715,5235064 440702,5235093 440625,5235229 440575,5235344 440584,5235455 440623,5235536 440663,5235665 440659,5235772 440644,5235823 440670,5235843 440645,5235892 440630,5235955 440641,5236019 440672,5236100 440723,5236104 440716,5236112 440741,5236140 440925,5236209 440986,5236241 441063,5236250 441220,5236279 441261,5236312 441290,5236357 441286,5236462 441222,5236666 441214,5236688 441192,5236752 441135,5236875 441048,5237036 440970,5237138 440941,5237219 440871,5237398 440820,5237551 440810,5237630 440789,5237772 440764,5237801 440688,5237809 440614,5237794 440476,5237745 440385,5237744 440357,5237762 440337,5237790 440345,5237851 440425,5237941 440440,5237951 440466,5237981 440536,5238103 440547,5238179 440510,5238265 440496,5238303 440453,5238424 440480,5238558 440516,5238618 440544,5238679 440588,5238724 440657,5238752 440786,5238733 441057,5238666 441206,5238599 441281,5238554 441333,5238524 441396,5238510 441429,5238530 441459,5238564 441476,5238584 441476,5238584 441494,5238603 441502,5238656 441508,5238743 441511,5238852 441530,5238943 441546,5239040 441575,5239121 441579,5239140 441586,5239176 441581,5239214 441571,5239235 441519,5239289 441509,5239324 441494,5239344 441494,5239344 441491,5239347 441441,5239381 441393,5239412 441355,5239420 441291,5239403 441174,5239376 441037,5239365 441004,5239383 440986,5239414 440924,5239524 440825,5239728 440761,5239754 440718,5239765 440690,5239757 440652,5239745 440611,5239707 440577,5239631 440539,5239601 440488,5239597 440190,5239775 440139,5239791 440089,5239799 439956,5239767 439886,5239710 439831,5239665 439705,5239549 439674,5239524 439639,5239537 439594,5239599 439536,5239703 439514,5239714 439465,5239717 439376,5239705 439292,5239668 439210,5239608 439130,5239425 439063,5239340 438989,5239323 438941,5239336 438909,5239415 438915,5239501 438926,5239649 438891,5239710 438815,5239734 438556,5239754 438429,5239745 438373,5239718 438358,5239685 438375,5239609 438378,5239604 438430,5239519 438520,5239417 438565,5239355 438724,5239290 438767,5239259 438787,5239185 438811,5239048 438840,5238890 438834,5238814 438785,5238759 438752,5238744 438696,5238742 438673,5238780 438549,5239091 438514,5239140 438433,5239169 438452,5239245 438437,5239293 438329,5239401 438297,5239416 438284,5239422 438215,5239433 438185,5239438 438131,5239438 438101,5239421 438115,5239342 438163,5239296 438170,5239235 438137,5239205 438090,5239129 438041,5239018 438004,5238929 437966,5238892 437844,5238885 437793,5238909 437756,5238983 437731,5239046 437712,5239174 437677,5239240 437659,5239244 437657,5239281 437654,5239297 437663,5239343 437671,5239417 437675,5239483 437699,5239623 437710,5239698 437709,5239744 437705,5239775 437696,5239802 437676,5239831 437630,5239895 437619,5239909 437619,5239909 437607,5239928 437583,5239949 437556,5239962 437517,5239963 437474,5239949 437456,5239926 437450,5239906 437450,5239906 437445,5239888 437443,5239836 437455,5239783 437612,5239364 437622,5239325 437621,5239293 437610,5239273 437580,5239260 437561,5239264 437523,5239277 437483,5239326 437476,5239387 437469,5239448 437426,5239492 437365,5239502 437187,5239456 437110,5239452 437080,5239472 437073,5239533 437094,5239607 437126,5239693 437086,5239742 436868,5239784 436842,5239797 436776,5239791 436682,5239744 436664,5239736 436625,5239663 436583,5239556 436537,5239531 436337,5239579 436262,5239644 436308,5239760 436315,5239892 436310,5239900 436310,5239900 436282,5239948 436217,5239989 436131,5239988 435998,5239974 435932,5239985 435910,5240015 435900,5240092 435919,5240183 436002,5240345 436098,5240557 436120,5240666 436110,5240704 436077,5240740 435986,5240751 435933,5240734 435868,5240725 435849,5240722 435831,5240712 435792,5240677 435761,5240637 435754,5240467 435734,5240434 435673,5240412 435416,5240412 435358,5240435 435328,5240492 435318,5240530 435309,5240606 435335,5240684 435361,5240730 435418,5240800 435462,5240881 435460,5240947 435427,5240996 435349,5241004 435298,5240995 435209,5240986 435148,5240994 435102,5241017 435074,5241052 435050,5241084 435028,5241170 434981,5241333 434958,5241344 434821,5241330 434752,5241290 434759,5241267 434823,5241238 434936,5241174 434951,5241141 434955,5241054 434932,5241024 434894,5241022 434841,5241055 434662,5241136 434583,5241172 434540,5241198 434518,5241209 434388,5241200 434373,5241182 434372,5241149 434404,5241068 434456,5240943 434494,5240909 434684,5240867 434765,5240823 434822,5240736 434839,5240654 434833,5240537 434795,5240538 434597,5240509 434554,5240520 434541,5240543 434559,5240583 434631,5240611 434641,5240628 434636,5240666 434621,5240689 434599,5240697 434429,5240712 434388,5240745 434323,5240858 434298,5240901 434253,5240919 434241,5240905 434222,5240874 434220,5240855 434212,5240816 434196,5240762 434181,5240742 434149,5240698 434112,5240666 434075,5240647 434044,5240638 434015,5240635 433984,5240653 433971,5240679 433971,5240707 433977,5240747 433976,5240767 433975,5240792 433966,5240843 433962,5240900 433946,5240953 433936,5241017 433903,5241092 433897,5241123 433886,5241148 433860,5241157 433829,5241169 433806,5241164 433789,5241148 433777,5241106 433768,5241081 433772,5241046 433771,5240987 433774,5240957 433777,5240921 433789,5240891 433789,5240868 433787,5240828 433783,5240792 433781,5240773 433771,5240744 433767,5240733 433749,5240715 433718,5240690 433670,5240688 433660,5240712 433662,5240754 433657,5240782 433641,5240812 433487,5240807 433473,5240806 433270,5240829 433237,5240850 433217,5240875 433207,5240896 433216,5240939 433234,5240959 433280,5240986 433316,5241027 433306,5241080 433276,5241103 433241,5241114 433202,5241107 433125,5241047 432990,5240995 432909,5240988 432879,5241004 432886,5241009 432892,5241080 432913,5241083 432930,5241091 432949,5241107 432973,5241150 432985,5241184 433002,5241225 433023,5241275 433036,5241307 433053,5241342 433065,5241385 433078,5241427 433089,5241481 433083,5241504 433091,5241525 433066,5241576 433035,5241576 432976,5241634 432935,5241674 432938,5241697 432931,5241763 432893,5241801 432817,5241835 432767,5241836 432733,5241793 432701,5241672 432699,5241638 432684,5241447 432680,5241390 432683,5241230 432702,5241133 432701,5241011 432740,5240902 432747,5240871 432774,5240744 432784,5240713 432773,5240660 432736,5240556 432666,5240438 432545,5240307 432463,5240224 432457,5240158 432486,5240043 432500,5239998 432500,5239998 432537,5239875 432539,5239771 432520,5239705 432476,5239670 432385,5239636 432359,5239626 432285,5239609 432232,5239592 432188,5239529 432116,5239451 432082,5239388 431971,5239267 431925,5239245 431858,5239145 431858,5239145 431854,5239142 431773,5239089 431707,5239090 431675,5239126 431587,5239196 431508,5239207 431322,5239181 431251,5239139 431207,5239088 431199,5239045 431185,5238939 431158,5238838 431134,5238739 431098,5238701 431080,5238691 430994,5238710 430888,5238803 430881,5238828 430856,5238867 430827,5238997 430806,5239101 430805,5239155 430829,5239205 430849,5239267 430863,5239319 430872,5239359 430867,5239382 430850,5239397 430826,5239401 430791,5239387 430768,5239371 430746,5239349 430737,5239329 430733,5239292 430731,5239249 430733,5239224 430738,5239208 430735,5239198 430720,5239193 430637,5239199 430624,5239240 430623,5239289 430628,5239335 430608,5239361 430581,5239379 430556,5239373 430542,5239364 430527,5239347 430518,5239319 430514,5239292 430514,5239267 430513,5239243 430509,5239178 430346,5239104 430308,5239115 430244,5239250 430242,5239254 430242,5239254 430224,5239324 430220,5239426 430247,5239479 430247,5239479 430272,5239529 430296,5239595 430279,5239676 430252,5239710 430252,5239710 430204,5239769 430179,5239777 430125,5239764 430105,5239749 430069,5239709 430011,5239593 429973,5239578 429935,5239592 429903,5239650 429913,5239674 429918,5239724 429930,5239812 429933,5239853 429932,5239879 429913,5239894 429842,5239924 429813,5239930 429795,5239923 429776,5239902 429770,5239877 429772,5239841 429783,5239801 429790,5239774 429792,5239744 429789,5239724 429778,5239709 429769,5239705 429723,5239701 429646,5239653 429585,5239616 429604,5239591 429620,5239574 429649,5239531 429663,5239510 429675,5239477 429659,5239451 429635,5239450 429570,5239440 429509,5239435 429472,5239434 429453,5239445 429456,5239477 429472,5239512 429482,5239542 429483,5239556 429472,5239560 429450,5239567 429356,5239568 429297,5239566 429226,5239590 429206,5239605 429213,5239629 429204,5239653 429206,5239687 429219,5239725 429243,5239761 429268,5239796 429285,5239825 429303,5239854 429314,5239888 429318,5239919 429308,5239954 429290,5239960 429270,5239960 429240,5239950 429226,5239937 429205,5239916 429189,5239895 429176,5239870 429155,5239831 429136,5239814 429113,5239810 429093,5239807 429082,5239824 429068,5239849 429038,5239862 429010,5239858 428988,5239853 428964,5239847 428946,5239850 428918,5239866 428881,5239889 428852,5239908 428810,5239924 428788,5239942 428769,5239962 428772,5239984 428783,5240001 428813,5240014 428839,5240011 428866,5240009 428898,5240000 428932,5240000 428963,5240008 428980,5240030 429002,5240067 429015,5240119 429018,5240211 429018,5240211 429018,5240235 428996,5240444 428966,5240520 428911,5240579 428830,5240613 428799,5240606 428789,5240561 428786,5240531 428790,5240507 428797,5240482 428809,5240464 428821,5240446 428821,5240421 428814,5240397 428815,5240374 428826,5240357 428890,5240220 428890,5240220 428904,5240190 428890,5240154 428873,5240152 428756,5240158 428734,5240168 428720,5240179 428712,5240214 428716,5240233 428716,5240233 428717,5240240 428770,5240340 428783,5240365 428788,5240387 428760,5240413 428727,5240423 428694,5240421 428667,5240418 428649,5240420 428649,5240420 428633,5240421 428613,5240433 428603,5240470 428614,5240496 428624,5240516 428644,5240546 428651,5240558 428651,5240558 428657,5240569 428675,5240597 428690,5240640 428673,5240689 428713,5240795 428724,5240856 428689,5240905 428656,5240923 428656,5240923 428567,5240972 428504,5240980 428344,5240977 428270,5240953 428236,5240900 428185,5240819 428126,5240782 428098,5240801 428092,5240847 428097,5240881 428113,5240923 428118,5240963 428120,5240993 428119,5241020 428082,5241028 428060,5241029 428039,5240988 428031,5240967 428012,5240923 427996,5240901 427967,5240890 427932,5240916 427912,5240982 427828,5241141 427798,5241228 427807,5241281 427838,5241324 427857,5241336 427882,5241336 427910,5241332 427967,5241324 427984,5241339 427931,5241460 427895,5241519 427875,5241546 427854,5241554 427823,5241527 427810,5241505 427806,5241477 427819,5241430 427816,5241403 427793,5241406 427747,5241429 427644,5241479 427563,5241528 427483,5241602 427481,5241638 427478,5241646 427484,5241662 427502,5241716 427508,5241733 427508,5241733 427512,5241747 427490,5241795 427220,5241905 427177,5241967 427190,5242010 427240,5242080 427248,5242131 427218,5242154 427169,5242140 427115,5242100 427033,5242042 427008,5242014 426972,5242020 426931,5242039 426931,5242039 426894,5242057 426839,5242126 426822,5242174 426802,5242162 426759,5242182 426698,5242225 426578,5242306 426560,5242327 426542,5242350 426532,5242376 426532,5242406 426533,5242436 426553,5242471 426568,5242507 426603,5242530 426626,5242524 426641,5242507 426654,5242479 426663,5242457 426673,5242425 426686,5242404 426704,5242393 426738,5242386 426766,5242444 426767,5242503 426733,5242600 426693,5242661 426676,5242698 426638,5242687 426595,5242684 426547,5242674 426505,5242665 426469,5242658 426442,5242665 426417,5242672 426398,5242686 426381,5242703 426390,5242740 426411,5242763 426445,5242789 426476,5242810 426506,5242823 426541,5242836 426562,5242840 426567,5242845 426573,5242861 426524,5242973 426502,5243044 426447,5243159 426417,5243188 426328,5243196 426288,5243184 426234,5243203 426094,5243326 426081,5243331 426023,5243335 425816,5243296 425809,5243327 425790,5243345 425761,5243366 425740,5243376 425740,5243376 425738,5243377 425719,5243384 425702,5243385 425675,5243377 425675,5243377 425670,5243376 425643,5243370 425621,5243351 425604,5243331 425589,5243313 425579,5243294 425573,5243271 425571,5243257 425568,5243244 425565,5243236 425563,5243231 425560,5243222 425551,5243223 425506,5243280 425480,5243247 425463,5243220 425447,5243174 425447,5243148 425418,5243135 425400,5243142 425376,5243164 425360,5243189 425346,5243234 425344,5243256 425356,5243288 425373,5243299 425398,5243308 425418,5243301 425434,5243299 425448,5243299 425456,5243302 425461,5243309 425462,5243317 425463,5243328 425406,5243380 425403,5243383 425403,5243383 425378,5243406 425318,5243432 425304,5243437 425304,5243437 425229,5243464 425128,5243472 425049,5243463 424998,5243477 424986,5243502 424976,5243517 424974,5243586 424955,5243660 424937,5243688 424927,5243721 424812,5243812 424774,5243842 424723,5243858 424650,5243910 424587,5243967 424519,5243983 424449,5244032 424422,5244035 424417,5244063 424357,5244114 424256,5244167 424195,5244208 424163,5244262 424167,5244374 424152,5244415 424112,5244448 424067,5244464 424019,5244465 423975,5244452 423947,5244427 423947,5244410 423959,5244399 423956,5244387 423969,5244371 423971,5244308 423957,5244252 423944,5244229 423906,5244199 423855,5244187 423804,5244191 423738,5244202 423703,5244212 423574,5244250 423389,5244293 423316,5244337 423246,5244412 423166,5244555 423144,5244578 423111,5244596 423073,5244599 422964,5244608 422744,5244700 422660,5244719 422478,5244732 422442,5244743 422430,5244763 422436,5244826 422444,5244849 422444,5244875 422452,5244892 422466,5244966 422489,5245037 422496,5245048 422496,5245048 422521,5245087 422562,5245117 422577,5245137 422596,5245180 422601,5245185 422606,5245205 422615,5245271 422605,5245312 422585,5245345 422528,5245415 422495,5245435 422231,5245487 422095,5245535 422083,5245544 422052,5245568 421985,5245638 421944,5245651 421855,5245652 421820,5245666 421797,5245699 421793,5245729 421793,5245928 421814,5245993 421833,5246064 421823,5246105 421808,5246136 421756,5246192 421715,5246213 421660,5246227 421617,5246242 421576,5246271 421516,5246328 421496,5246353 421492,5246399 421510,5246427 421559,5246457 421592,5246494 421600,5246517 421629,5246578 421645,5246620 421650,5246651 421645,5246659 421640,5246678 421636,5246694 421633,5246702 421626,5246725 421614,5246758 421611,5246768 421594,5246784 421594,5246802 421569,5246832 421542,5246881 421542,5246899 421532,5246902 421472,5246978 421339,5247128 421304,5247181 421277,5247245 421252,5247360 421244,5247423 421248,5247499 421269,5247585 421271,5247722 421282,5247785 421332,5247904 421340,5247927 421495,5248267 421508,5248275 421512,5248306 421513,5248315 421539,5248368 421555,5248414 421552,5248523 421524,5248574 421462,5248654 421452,5248685 421424,5249000 421389,5249252 421370,5249328 421360,5249351 421358,5249395 421346,5249433 421346,5249479 421339,5249499 421331,5249629 421345,5249776 421346,5249912 421346,5249999 421332,5250094 421336,5250195 421385,5250301 421437,5250394 421469,5250445 421515,5250467 421596,5250476 421736,5250482 421817,5250501 421856,5250526 421961,5250626 422010,5250658 422062,5250679 422062,5250679 422220,5250742 422256,5250780 422295,5250848 422412,5251034 422429,5251056 422436,5251081 422438,5251127 422433,5251170 422398,5251271 422350,5251364 422292,5251448 422245,5251489 422207,5251504 422206,5251505 422109,5251556 422076,5251577 422076,5251577 421890,5251694 421789,5251754 421754,5251792 421734,5251833 421730,5251904 421723,5251927 421690,5251971 421612,5252025 421580,5252061 421560,5252095 421562,5252105 421555,5252110 421558,5252120 421548,5252128 421548,5252151 421515,5252189 421483,5252210 421440,5252221 421389,5252260 421375,5252298 421375,5252341 421396,5252382 421392,5252435 421392,5252445 421384,5252453 421382,5252496 421350,5252547 421315,5252604 421318,5252616 421288,5252640 421241,5252714 421191,5252775 421095,5252881 421051,5252948 421046,5252965 421021,5253001 421006,5253032 420989,5253057 420989,5253057 420976,5253076 420949,5253122 420944,5253127 420929,5253160 420917,5253170 420912,5253186 420867,5253252 420854,5253273 420835,5253306 420830,5253322 420765,5253404 420723,5253444 420700,5253466 420684,5253473 420370,5253877 420370,5253877 419962,5254403 419856,5254699 419856,5254699 419278,5256325 419054,5256953 418831,5257384 418831,5257384 418620,5257791 418522,5257885 418522,5257885 417489,5258863 417234,5258912 416435,5259066 415770,5259195 415572,5259103 415221,5258939 414078,5258444 413134,5258035 413134,5258035 412464,5257744 412464,5257744 410877,5257056 409769,5256576 409769,5256576 409258,5256355 407660,5255662 407660,5255662 406212,5255035 406211,5255035 406042,5254961 405734,5254828 405363,5254661 404784,5254410 404492,5254281 404492,5254281 404071,5254094 403433,5253831 402868,5253578 402793,5253545 402756,5253528 402756,5253528 402111,5253242 401462,5252885 401273,5252782 401273,5252782 400989,5252627 400740,5252478 400644,5252430 400392,5252271 400234,5252200 400128,5252211 400084,5252185 399860,5252231 399663,5252317 399663,5252317 399212,5252513 398632,5252845 398411,5253015 398072,5253158 397881,5253238 397545,5253276 397183,5253318 396914,5253336 396741,5253460 396585,5253524 396471,5253535 396436,5253539 396349,5253686 396349,5253686 396288,5253792 396265,5253817 396240,5253868 396207,5253954 396158,5254026 396092,5254090 396028,5254096 395968,5254070 395892,5254070 395837,5254089 395805,5254109 395769,5254108 395723,5254063 395676,5253998 395635,5253907 395624,5253797 395626,5253731 395623,5253707 395623,5253707 395621,5253691 395592,5253646 395528,5253610 395520,5253612 394976,5253636 394969,5253635 394876,5253639 394850,5253640 394782,5253670 394721,5253700 394718,5253733 394715,5253761 394736,5253835 394745,5253892 394721,5253936 394715,5253987 394667,5254110 394583,5254134 394532,5254176 394537,5254267 394496,5254318 394384,5254354 394274,5254332 394145,5254326 393995,5254333 393939,5254335 393854,5254348 393761,5254427 393701,5254486 393670,5254526 393670,5254578 393704,5254622 393781,5254692 393877,5254724 394010,5254742 394100,5254749 394168,5254771 394183,5254814 394178,5254854 394150,5254955 394029,5255057 394000,5255115 393979,5255178 393938,5255260 393897,5255313 393872,5255341 393872,5255342 393843,5255375 393841,5255377 393801,5255420 393800,5255422 393761,5255461 393711,5255520 393612,5255609 393523,5255646 393457,5255644 393390,5255644 393290,5255616 393234,5255577 393270,5256929 393323,5258548 393367,5260149 393418,5261696 393464,5263301 393520,5264868 393534,5266490 393620,5268119 393623,5269725 393706,5271317 393563,5272905 393565,5274474 393581,5276048 393593,5277645 393601,5279238 393624,5280830 393524,5280829 393547,5282449 393561,5284055 393564,5285655 393588,5287281 393611,5288873 393646,5290483 393690,5292091 393719,5293716 393762,5295326 393795,5296928 393830,5298547 393866,5300138 + + -------------------------------------- + diff --git a/msautotest/query/expected/template_test004.json b/msautotest/query/expected/template_test004.json new file mode 100644 index 0000000000..7216330df5 --- /dev/null +++ b/msautotest/query/expected/template_test004.json @@ -0,0 +1,5 @@ +[ +{"name":"Cass"}, +{"name":"Carlton"}, +{"name":"Carver"} +] \ No newline at end of file diff --git a/msautotest/query/expected/template_test005.html b/msautotest/query/expected/template_test005.html new file mode 100644 index 0000000000..7d0679d29c --- /dev/null +++ b/msautotest/query/expected/template_test005.html @@ -0,0 +1,8 @@ +This template tests a missing feature template +Content-Type: text/html + + +MapServer Message + +processIncludeTag(): Unable to access file. missing.tmpl + \ No newline at end of file diff --git a/msautotest/query/expected/text_test001.png b/msautotest/query/expected/text_test001.png index 57ed475887..a84a808627 100644 Binary files a/msautotest/query/expected/text_test001.png and b/msautotest/query/expected/text_test001.png differ diff --git a/msautotest/query/expected/text_test002.png b/msautotest/query/expected/text_test002.png index a18b37eb25..d80727b5a1 100644 Binary files a/msautotest/query/expected/text_test002.png and b/msautotest/query/expected/text_test002.png differ diff --git a/msautotest/query/expected/text_test003.png b/msautotest/query/expected/text_test003.png index e955c2fb91..6cbe515412 100644 Binary files a/msautotest/query/expected/text_test003.png and b/msautotest/query/expected/text_test003.png differ diff --git a/msautotest/query/expected/text_test004.png b/msautotest/query/expected/text_test004.png index 3f8179fb90..2e58847ee0 100644 Binary files a/msautotest/query/expected/text_test004.png and b/msautotest/query/expected/text_test004.png differ diff --git a/msautotest/query/expected/text_test005.png b/msautotest/query/expected/text_test005.png index d9fea8b449..6b5eb700c7 100644 Binary files a/msautotest/query/expected/text_test005.png and b/msautotest/query/expected/text_test005.png differ diff --git a/msautotest/query/expected/text_test006.png b/msautotest/query/expected/text_test006.png index 1b03357139..2c5b9af37c 100644 Binary files a/msautotest/query/expected/text_test006.png and b/msautotest/query/expected/text_test006.png differ diff --git a/msautotest/query/expected/text_test007.png b/msautotest/query/expected/text_test007.png index a2a0719519..3033ef1bfe 100644 Binary files a/msautotest/query/expected/text_test007.png and b/msautotest/query/expected/text_test007.png differ diff --git a/msautotest/query/expressions.map b/msautotest/query/expressions.map index 6a8716ea5c..fcebf01a80 100644 --- a/msautotest/query/expressions.map +++ b/msautotest/query/expressions.map @@ -13,6 +13,8 @@ # RUN_PARMS: expressions_test008.txt [MAPSERV] QUERY_STRING="map=[MAPFILE]&mode=nquery&qformat=csv&qlayer=expressions_test008" > [RESULT_DEMIME] # RUN_PARMS: expressions_test009.txt [MAPSERV] QUERY_STRING="map=[MAPFILE]&mode=nquery&qformat=csv&qlayer=expressions_test009" > [RESULT_DEMIME] # RUN_PARMS: expressions_test010.txt [MAPSERV] QUERY_STRING="map=[MAPFILE]&mode=nquery&qformat=csv&qlayer=expressions_test010" > [RESULT_DEMIME] +# RUN_PARMS: expressions_test011.txt [MAPSERV] QUERY_STRING="map=[MAPFILE]&mode=nquery&qformat=csv&qlayer=expressions_test011" > [RESULT_DEMIME] +# RUN_PARMS: expressions_test012.txt [MAPSERV] QUERY_STRING="map=[MAPFILE]&mode=nquery&qformat=csv&qlayer=expressions_test012" > [RESULT_DEMIME] # MAP NAME 'expressions' @@ -132,4 +134,24 @@ MAP END END + # Logical expression with <> + LAYER + NAME 'expressions_test011' + FILTER ('[CTY_NAME]' ~* '^A.*$' AND ('[CTY_NAME]' <> 'Aitkin')) + INCLUDE 'include/bdry_counpy2_shapefile.map' + METADATA + "gml_include_items" "cty_name,cty_fips" + END + END + + # Logical expression with != + LAYER + NAME 'expressions_test012' + FILTER ('[CTY_NAME]' ~* '^A.*$' AND ('[CTY_NAME]' != 'Aitkin')) + INCLUDE 'include/bdry_counpy2_shapefile.map' + METADATA + "gml_include_items" "cty_name,cty_fips" + END + END + END diff --git a/msautotest/query/filters.map b/msautotest/query/filters.map index 3d7fb978ba..e2d7540cf3 100644 --- a/msautotest/query/filters.map +++ b/msautotest/query/filters.map @@ -3,16 +3,16 @@ # # REQUIRES: INPUT=SHAPEFILE OUTPUT=PNG SUPPORTS=GEOS # -# RUN_PARMS: filters_test001.png [SHP2IMG] -m [MAPFILE] -l filters_test001 -o [RESULT] -# RUN_PARMS: filters_test002.png [SHP2IMG] -m [MAPFILE] -l filters_test002 -o [RESULT] -# RUN_PARMS: filters_test003.png [SHP2IMG] -m [MAPFILE] -l filters_test003 -o [RESULT] -# RUN_PARMS: filters_test004.png [SHP2IMG] -m [MAPFILE] -l filters_test004 -o [RESULT] -# RUN_PARMS: filters_test005.png [SHP2IMG] -m [MAPFILE] -l filters_test005 -o [RESULT] -# RUN_PARMS: filters_test006.png [SHP2IMG] -m [MAPFILE] -l filters_test006 -o [RESULT] -# RUN_PARMS: filters_test007.png [SHP2IMG] -m [MAPFILE] -l filters_test007 -o [RESULT] -# RUN_PARMS: filters_test008.png [SHP2IMG] -m [MAPFILE] -l filters_test008 -o [RESULT] -# RUN_PARMS: filters_test009.png [SHP2IMG] -m [MAPFILE] -l filters_test009 -o [RESULT] -# RUN_PARMS: filters_test010.png [SHP2IMG] -m [MAPFILE] -l filters_test010 -o [RESULT] +# RUN_PARMS: filters_test001.png [MAP2IMG] -m [MAPFILE] -l filters_test001 -o [RESULT] +# RUN_PARMS: filters_test002.png [MAP2IMG] -m [MAPFILE] -l filters_test002 -o [RESULT] +# RUN_PARMS: filters_test003.png [MAP2IMG] -m [MAPFILE] -l filters_test003 -o [RESULT] +# RUN_PARMS: filters_test004.png [MAP2IMG] -m [MAPFILE] -l filters_test004 -o [RESULT] +# RUN_PARMS: filters_test005.png [MAP2IMG] -m [MAPFILE] -l filters_test005 -o [RESULT] +# RUN_PARMS: filters_test006.png [MAP2IMG] -m [MAPFILE] -l filters_test006 -o [RESULT] +# RUN_PARMS: filters_test007.png [MAP2IMG] -m [MAPFILE] -l filters_test007 -o [RESULT] +# RUN_PARMS: filters_test008.png [MAP2IMG] -m [MAPFILE] -l filters_test008 -o [RESULT] +# RUN_PARMS: filters_test009.png [MAP2IMG] -m [MAPFILE] -l filters_test009 -o [RESULT] +# RUN_PARMS: filters_test010.png [MAP2IMG] -m [MAPFILE] -l filters_test010 -o [RESULT] # MAP NAME 'filters' @@ -101,6 +101,6 @@ MAP TYPE LINE DATA 'data/bdry_counpy2.shp' STATUS DEFAULT - CLASS COLOR 231 231 231 END + CLASS STYLE COLOR 231 231 231 END END END END diff --git a/msautotest/query/filters_postgis.map b/msautotest/query/filters_postgis.map index 0056d38cac..1e7ddf4ab5 100644 --- a/msautotest/query/filters_postgis.map +++ b/msautotest/query/filters_postgis.map @@ -3,15 +3,15 @@ # # REQUIRES: INPUT=POSTGIS OUTPUT=PNG # -# RUN_PARMS: filters_postgis_test001.png [SHP2IMG] -m [MAPFILE] -l filters_postgis_test001 -o [RESULT] -# RUN_PARMS: filters_postgis_test002.png [SHP2IMG] -m [MAPFILE] -l filters_postgis_test002 -o [RESULT] -# RUN_PARMS: filters_postgis_test003.png [SHP2IMG] -m [MAPFILE] -l filters_postgis_test003 -o [RESULT] -# RUN_PARMS: filters_postgis_test004.png [SHP2IMG] -m [MAPFILE] -l filters_postgis_test004 -o [RESULT] -# RUN_PARMS: filters_postgis_test005.png [SHP2IMG] -m [MAPFILE] -l filters_postgis_test005 -o [RESULT] -# RUN_PARMS: filters_postgis_test006.png [SHP2IMG] -m [MAPFILE] -l filters_postgis_test006 -o [RESULT] -# RUN_PARMS: filters_postgis_test007.png [SHP2IMG] -m [MAPFILE] -l filters_postgis_test007 -o [RESULT] -# RUN_PARMS: filters_postgis_test008.png [SHP2IMG] -m [MAPFILE] -l filters_postgis_test008 -o [RESULT] -# RUN_PARMS: filters_postgis_test009.png [SHP2IMG] -m [MAPFILE] -l filters_postgis_test009 -o [RESULT] +# RUN_PARMS: filters_postgis_test001.png [MAP2IMG] -m [MAPFILE] -l filters_postgis_test001 -o [RESULT] +# RUN_PARMS: filters_postgis_test002.png [MAP2IMG] -m [MAPFILE] -l filters_postgis_test002 -o [RESULT] +# RUN_PARMS: filters_postgis_test003.png [MAP2IMG] -m [MAPFILE] -l filters_postgis_test003 -o [RESULT] +# RUN_PARMS: filters_postgis_test004.png [MAP2IMG] -m [MAPFILE] -l filters_postgis_test004 -o [RESULT] +# RUN_PARMS: filters_postgis_test005.png [MAP2IMG] -m [MAPFILE] -l filters_postgis_test005 -o [RESULT] +# RUN_PARMS: filters_postgis_test006.png [MAP2IMG] -m [MAPFILE] -l filters_postgis_test006 -o [RESULT] +# RUN_PARMS: filters_postgis_test007.png [MAP2IMG] -m [MAPFILE] -l filters_postgis_test007 -o [RESULT] +# RUN_PARMS: filters_postgis_test008.png [MAP2IMG] -m [MAPFILE] -l filters_postgis_test008 -o [RESULT] +# RUN_PARMS: filters_postgis_test009.png [MAP2IMG] -m [MAPFILE] -l filters_postgis_test009 -o [RESULT] # MAP NAME 'filters_postgis' @@ -100,6 +100,6 @@ MAP TYPE LINE DATA 'data/bdry_counpy2.shp' STATUS DEFAULT - CLASS COLOR 231 231 231 END + CLASS STYLE COLOR 231 231 231 END END END END diff --git a/msautotest/query/run_test.py b/msautotest/query/run_test.py index 7d572d0cb6..dd4172c8aa 100755 --- a/msautotest/query/run_test.py +++ b/msautotest/query/run_test.py @@ -8,17 +8,17 @@ # ############################################################################### # Copyright (c) 2002, Frank Warmerdam -# +# # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: -# +# # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. -# +# # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL @@ -29,14 +29,19 @@ ############################################################################### import os -import pytest import sys -sys.path.append( '../pymod' ) +import pytest + +sys.path.append("../pymod") import mstestlib -@pytest.mark.parametrize('map,out_file,command', mstestlib.get_pytests(os.path.dirname(os.path.abspath(__file__)))) + +@pytest.mark.parametrize( + "map,out_file,command", + mstestlib.get_pytests(os.path.dirname(os.path.abspath(__file__))), +) def test(map, out_file, command, extra_args): mstestlib.run_pytest(map, out_file, command, extra_args) @@ -44,5 +49,5 @@ def test(map, out_file, command, extra_args): ############################################################################### # main() -if __name__ == '__main__': +if __name__ == "__main__": sys.exit(mstestlib.pytest_main()) diff --git a/msautotest/query/template.map b/msautotest/query/template.map index 4d5a100e5d..80af12763f 100644 --- a/msautotest/query/template.map +++ b/msautotest/query/template.map @@ -2,6 +2,9 @@ # Test 1: simple mode=query, HTML template # RUN_PARMS: template_test001.html [MAPSERV] QUERY_STRING='map=[MAPFILE]&mode=query&qlayer=bdry_counpy2&mapxy=467000+5259000&qformat=html' > [RESULT_DEMIME] # RUN_PARMS: template_test002.html [MAPSERV] QUERY_STRING='map=[MAPFILE]&mode=query&qlayer=bdry_counpy2&mapxy=467000+5259000&qformat=feature' > [RESULT_DEMIME] +# RUN_PARMS: template_test003.html [MAPSERV] QUERY_STRING='map=[MAPFILE]&mode=query&qlayer=bdry_counpy2&mapxy=467000+5259000&qformat=feature_includes' > [RESULT_DEMIME] +# RUN_PARMS: template_test004.json [MAPSERV] QUERY_STRING='map=[MAPFILE]&mode=itemnquery&qlayer=bdry_counpy2&qstring=/^Ca/&qitem=cty_name&qformat=json' > [RESULT_DEMIME] +# RUN_PARMS: template_test005.html [MAPSERV] QUERY_STRING='map=[MAPFILE]&mode=query&qlayer=bdry_counpy2&mapxy=467000+5259000&qformat=feature_missing_include' > [RESULT_DEMIME] # MAP NAME 'query' @@ -22,9 +25,33 @@ MAP FORMATOPTION "FILE=template/feature.tmpl" END + OUTPUTFORMAT + NAME 'feature_includes' + DRIVER 'TEMPLATE' + MIMETYPE 'text/html' + FORMATOPTION "FILE=template/feature_includes.tmpl" + END + + OUTPUTFORMAT + NAME 'json' + DRIVER 'TEMPLATE' + MIMETYPE "application/json" + FORMATOPTION "FILE=template/feature_json.tmpl" + END + + OUTPUTFORMAT + NAME 'feature_missing_include' + DRIVER 'TEMPLATE' + MIMETYPE 'text/html' + FORMATOPTION "FILE=template/feature_missing_include.tmpl" + END + LAYER NAME 'bdry_counpy2' INCLUDE 'include/bdry_counpy2_shapefile.map' + VALIDATION + qstring '.' + END END LAYER diff --git a/msautotest/query/template/6907.tmpl b/msautotest/query/template/6907.tmpl new file mode 100644 index 0000000000..e774d40e2f --- /dev/null +++ b/msautotest/query/template/6907.tmpl @@ -0,0 +1,3 @@ + +[resultset layer="bdry_counpy2"][feature][item name="cty_name"]:[item name="cty_abbr"] [/feature][/resultset] + diff --git a/msautotest/query/template/feature_includes.tmpl b/msautotest/query/template/feature_includes.tmpl new file mode 100644 index 0000000000..777ef879f7 --- /dev/null +++ b/msautotest/query/template/feature_includes.tmpl @@ -0,0 +1,7 @@ + +This template tests using includes with feature template outputs +[resultset layer="bdry_counpy2"] + -------------------------------------- +[include src="template/item.tmpl"] + -------------------------------------- +[/resultset] diff --git a/msautotest/query/template/feature_json.tmpl b/msautotest/query/template/feature_json.tmpl new file mode 100644 index 0000000000..5101c07256 --- /dev/null +++ b/msautotest/query/template/feature_json.tmpl @@ -0,0 +1,4 @@ +// mapserver template +[ +[resultset layer="bdry_counpy2"][feature trimlast=","][include src="template/item_json.tmpl"][/feature][/resultset] +] \ No newline at end of file diff --git a/msautotest/query/template/feature_missing_include.tmpl b/msautotest/query/template/feature_missing_include.tmpl new file mode 100644 index 0000000000..0571ae462b --- /dev/null +++ b/msautotest/query/template/feature_missing_include.tmpl @@ -0,0 +1,8 @@ + +This template tests a missing feature template +[include src="missing.tmpl"] +[resultset layer="bdry_counpy2"] + -------------------------------------- +[include src="missing.tmpl"] + -------------------------------------- +[/resultset] diff --git a/msautotest/query/template/item.tmpl b/msautotest/query/template/item.tmpl new file mode 100644 index 0000000000..7335f45c2e --- /dev/null +++ b/msautotest/query/template/item.tmpl @@ -0,0 +1,8 @@ + + [feature] + ITEM TAGS: [item name="cty_name"]:[item name="cty_abbr"] + OLD-STYLE TAG (case sensitive): [CTY_NAME], [cty_name] + SHPEXT (basic): [shpext] + SHPEXT (precision=0): [shpext precision="0"] + SHPXY (basic): [shpxy] + [/feature] \ No newline at end of file diff --git a/msautotest/query/template/item_json.tmpl b/msautotest/query/template/item_json.tmpl new file mode 100644 index 0000000000..be52bff13b --- /dev/null +++ b/msautotest/query/template/item_json.tmpl @@ -0,0 +1,2 @@ +//mapserver template +{"name":"[item name="cty_name"]"}, diff --git a/msautotest/query/text.map b/msautotest/query/text.map index 897fe50716..e1634c7b07 100644 --- a/msautotest/query/text.map +++ b/msautotest/query/text.map @@ -3,13 +3,13 @@ # # REQUIRES: INPUT=SHAPEFILE OUTPUT=PNG # -# RUN_PARMS: text_test001.png [SHP2IMG] -m [MAPFILE] -l text_test001 -o [RESULT] -# RUN_PARMS: text_test002.png [SHP2IMG] -m [MAPFILE] -l text_test002 -o [RESULT] -# RUN_PARMS: text_test003.png [SHP2IMG] -m [MAPFILE] -l text_test003 -o [RESULT] -# RUN_PARMS: text_test004.png [SHP2IMG] -m [MAPFILE] -l text_test004 -o [RESULT] -# RUN_PARMS: text_test005.png [SHP2IMG] -m [MAPFILE] -l text_test005 -o [RESULT] -# RUN_PARMS: text_test006.png [SHP2IMG] -m [MAPFILE] -l text_test006 -o [RESULT] -# RUN_PARMS: text_test007.png [SHP2IMG] -m [MAPFILE] -l text_test007 -o [RESULT] +# RUN_PARMS: text_test001.png [MAP2IMG] -m [MAPFILE] -l text_test001 -o [RESULT] +# RUN_PARMS: text_test002.png [MAP2IMG] -m [MAPFILE] -l text_test002 -o [RESULT] +# RUN_PARMS: text_test003.png [MAP2IMG] -m [MAPFILE] -l text_test003 -o [RESULT] +# RUN_PARMS: text_test004.png [MAP2IMG] -m [MAPFILE] -l text_test004 -o [RESULT] +# RUN_PARMS: text_test005.png [MAP2IMG] -m [MAPFILE] -l text_test005 -o [RESULT] +# RUN_PARMS: text_test006.png [MAP2IMG] -m [MAPFILE] -l text_test006 -o [RESULT] +# RUN_PARMS: text_test007.png [MAP2IMG] -m [MAPFILE] -l text_test007 -o [RESULT] # MAP NAME 'text' @@ -41,7 +41,7 @@ MAP END TEXT 'Static Text' END - CLASS OUTLINECOLOR 181 181 181 END + CLASS STYLE OUTLINECOLOR 181 181 181 END END END # @@ -66,7 +66,7 @@ MAP END TEXT ([area]) END - CLASS OUTLINECOLOR 181 181 181 END + CLASS STYLE OUTLINECOLOR 181 181 181 END END END # @@ -91,7 +91,7 @@ MAP END TEXT ("[area]") END - CLASS OUTLINECOLOR 181 181 181 END + CLASS STYLE OUTLINECOLOR 181 181 181 END END END # @@ -116,7 +116,7 @@ MAP END TEXT (tostring([area],"%.2f")) END - CLASS OUTLINECOLOR 181 181 181 END + CLASS STYLE OUTLINECOLOR 181 181 181 END END END # @@ -141,7 +141,7 @@ MAP END TEXT ("Area is: " + tostring([area],"%.2f")) END - CLASS OUTLINECOLOR 181 181 181 END + CLASS STYLE OUTLINECOLOR 181 181 181 END END END # @@ -166,7 +166,7 @@ MAP END TEXT "Area is: [area]" END - CLASS OUTLINECOLOR 181 181 181 END + CLASS STYLE OUTLINECOLOR 181 181 181 END END END # @@ -191,7 +191,7 @@ MAP END TEXT ("[work" + "around]") END - CLASS OUTLINECOLOR 181 181 181 END + CLASS STYLE OUTLINECOLOR 181 181 181 END END END END \ No newline at end of file diff --git a/msautotest/renderers/average_rgb.map b/msautotest/renderers/average_rgb.map index 26bab4cacb..935de0e194 100644 --- a/msautotest/renderers/average_rgb.map +++ b/msautotest/renderers/average_rgb.map @@ -1,7 +1,7 @@ -# RUN_PARMS: average_rgb.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: average_rgb.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: average_rgb.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: average_rgb.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: average_rgb.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: average_rgb.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: average_rgb.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: average_rgb.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # # # Test averaged resampling. Results currently depend on the 2x oversampling diff --git a/msautotest/renderers/baseline_text.map b/msautotest/renderers/baseline_text.map index 927f7d3ef1..bfdbf8b7c2 100644 --- a/msautotest/renderers/baseline_text.map +++ b/msautotest/renderers/baseline_text.map @@ -1,7 +1,7 @@ -# RUN_PARMS: baseline_text.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: baseline_text.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: baseline_text.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: baseline_text.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: baseline_text.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: baseline_text.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: baseline_text.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: baseline_text.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # MAP EXTENT 0 0 100 50 diff --git a/msautotest/renderers/chartlayer_bar.map b/msautotest/renderers/chartlayer_bar.map index 9a3d9eafd7..894105906a 100644 --- a/msautotest/renderers/chartlayer_bar.map +++ b/msautotest/renderers/chartlayer_bar.map @@ -1,7 +1,7 @@ -# RUN_PARMS: chartlayer_bar.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: chartlayer_bar.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: chartlayer_bar.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: chartlayer_bar.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: chartlayer_bar.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: chartlayer_bar.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: chartlayer_bar.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: chartlayer_bar.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # # # Start of map file @@ -22,15 +22,14 @@ IMAGECOLOR 255 255 255 # Start of web interface definition # WEB - MINSCALE 2000000 - MAXSCALE 50000000 + MINSCALEDENOM 2000000 + MAXSCALEDENOM 50000000 # # On Windows systems, /tmp and /tmp/ms_tmp/ should be created at the root # of the drive where the .MAP file resides. # IMAGEPATH "/tmp/ms_tmp/" IMAGEURL "/ms_tmp/" -# LOG "/tmp/gmap.log" END diff --git a/msautotest/renderers/chartlayer_pie.map b/msautotest/renderers/chartlayer_pie.map index 8b6bb1a33a..11c775bec4 100644 --- a/msautotest/renderers/chartlayer_pie.map +++ b/msautotest/renderers/chartlayer_pie.map @@ -1,7 +1,7 @@ -# RUN_PARMS: chartlayer_pie.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: chartlayer_pie.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: chartlayer_pie.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: chartlayer_pie.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: chartlayer_pie.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: chartlayer_pie.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: chartlayer_pie.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: chartlayer_pie.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # # # Test on chart creation diff --git a/msautotest/renderers/chartlayer_pie2.map b/msautotest/renderers/chartlayer_pie2.map index 2a453805d7..6a2b43ef74 100644 --- a/msautotest/renderers/chartlayer_pie2.map +++ b/msautotest/renderers/chartlayer_pie2.map @@ -1,7 +1,7 @@ -# RUN_PARMS: chartlayer_pie2.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: chartlayer_pie2.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: chartlayer_pie2.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: chartlayer_pie2.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: chartlayer_pie2.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: chartlayer_pie2.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: chartlayer_pie2.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: chartlayer_pie2.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # # # Test on chart creation diff --git a/msautotest/renderers/chartlayer_pie_expressions.map b/msautotest/renderers/chartlayer_pie_expressions.map index 21125d2130..52bec9e100 100644 --- a/msautotest/renderers/chartlayer_pie_expressions.map +++ b/msautotest/renderers/chartlayer_pie_expressions.map @@ -1,7 +1,7 @@ -# RUN_PARMS: chartlayer_pie_expressions.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: chartlayer_pie_expressions.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: chartlayer_pie_expressions.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: chartlayer_pie_expressions.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: chartlayer_pie_expressions.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: chartlayer_pie_expressions.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: chartlayer_pie_expressions.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: chartlayer_pie_expressions.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # # # Test on chart creation diff --git a/msautotest/renderers/chartlayer_vbar.map b/msautotest/renderers/chartlayer_vbar.map index 7a584e626f..644cfb95fc 100644 --- a/msautotest/renderers/chartlayer_vbar.map +++ b/msautotest/renderers/chartlayer_vbar.map @@ -1,7 +1,7 @@ -# RUN_PARMS: chartlayer_vbar.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: chartlayer_vbar.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: chartlayer_vbar.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: chartlayer_vbar.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: chartlayer_vbar.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: chartlayer_vbar.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: chartlayer_vbar.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: chartlayer_vbar.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # # # Start of map file @@ -22,15 +22,14 @@ IMAGECOLOR 255 255 255 # Start of web interface definition # WEB - MINSCALE 2000000 - MAXSCALE 50000000 + MINSCALEDENOM 2000000 + MAXSCALEDENOM 50000000 # # On Windows systems, /tmp and /tmp/ms_tmp/ should be created at the root # of the drive where the .MAP file resides. # IMAGEPATH "/tmp/ms_tmp/" IMAGEURL "/ms_tmp/" -# LOG "/tmp/gmap.log" END diff --git a/msautotest/renderers/circle_layer.map b/msautotest/renderers/circle_layer.map index 5a8f56e47a..bce3c7a99a 100644 --- a/msautotest/renderers/circle_layer.map +++ b/msautotest/renderers/circle_layer.map @@ -1,7 +1,7 @@ -# RUN_PARMS: circle_layer.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: circle_layer.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: circle_layer.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: circle_layer.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: circle_layer.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: circle_layer.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: circle_layer.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: circle_layer.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # # # REQUIRES: OUTPUT=PNG diff --git a/msautotest/renderers/compop_hsl_color.map b/msautotest/renderers/compop_hsl_color.map new file mode 100644 index 0000000000..379390e395 --- /dev/null +++ b/msautotest/renderers/compop_hsl_color.map @@ -0,0 +1,25 @@ +# RUN_PARMS: compop_hsl_color.agg.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: compop_hsl_color.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# +MAP + +NAME TEST +STATUS ON +SIZE 200 150 +EXTENT 0.5 0.5 399.5 299.5 +IMAGECOLOR 255 255 0 + +LAYER + NAME rgb + TYPE raster + STATUS default + DATA ../gdal/data/rgba.tif + PROCESSING "BANDS=1,2,3" + PROCESSING "USE_MASK_BAND=NO" + COMPOSITE + OPACITY 100 + COMPOP "hsl-color" + END +END + +END # of map file diff --git a/msautotest/renderers/compop_hsl_color_opacity_50.map b/msautotest/renderers/compop_hsl_color_opacity_50.map new file mode 100644 index 0000000000..dcdd93bfe8 --- /dev/null +++ b/msautotest/renderers/compop_hsl_color_opacity_50.map @@ -0,0 +1,29 @@ +# RUN_PARMS: compop_hsl_color_opacity_50.agg.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: compop_hsl_color_opacity_50.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# +MAP + +# WARNING: compop_hsl_color_opacity_50.cairo.png output is incorrect +# when running Cairo against Pixman versions up to date (0.43.4 at time of writing) +# due to bug fixed per https://gitlab.freedesktop.org/pixman/pixman/-/merge_requests/97 + +NAME TEST +STATUS ON +SIZE 200 150 +EXTENT 0.5 0.5 399.5 299.5 +IMAGECOLOR 255 255 0 + +LAYER + NAME rgb + TYPE raster + STATUS default + DATA ../gdal/data/rgba.tif + PROCESSING "BANDS=1,2,3" + PROCESSING "USE_MASK_BAND=NO" + COMPOSITE + OPACITY 50 + COMPOP "hsl-color" + END +END + +END # of map file diff --git a/msautotest/renderers/compop_hsl_hue.map b/msautotest/renderers/compop_hsl_hue.map new file mode 100644 index 0000000000..879102675b --- /dev/null +++ b/msautotest/renderers/compop_hsl_hue.map @@ -0,0 +1,25 @@ +# RUN_PARMS: compop_hsl_hue.agg.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: compop_hsl_hue.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# +MAP + +NAME TEST +STATUS ON +SIZE 200 150 +EXTENT 0.5 0.5 399.5 299.5 +IMAGECOLOR 255 255 0 + +LAYER + NAME rgb + TYPE raster + STATUS default + DATA ../gdal/data/rgba.tif + PROCESSING "BANDS=1,2,3" + PROCESSING "USE_MASK_BAND=NO" + COMPOSITE + OPACITY 100 + COMPOP "hsl-hue" + END +END + +END # of map file diff --git a/msautotest/renderers/compop_hsl_luminosity.map b/msautotest/renderers/compop_hsl_luminosity.map new file mode 100644 index 0000000000..00cffec9bb --- /dev/null +++ b/msautotest/renderers/compop_hsl_luminosity.map @@ -0,0 +1,25 @@ +# RUN_PARMS: compop_hsl_luminosity.agg.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: compop_hsl_luminosity.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# +MAP + +NAME TEST +STATUS ON +SIZE 200 150 +EXTENT 0.5 0.5 399.5 299.5 +IMAGECOLOR 255 255 0 + +LAYER + NAME rgb + TYPE raster + STATUS default + DATA ../gdal/data/rgba.tif + PROCESSING "BANDS=1,2,3" + PROCESSING "USE_MASK_BAND=NO" + COMPOSITE + OPACITY 100 + COMPOP "hsl-luminosity" + END +END + +END # of map file diff --git a/msautotest/renderers/compop_hsl_saturation.map b/msautotest/renderers/compop_hsl_saturation.map new file mode 100644 index 0000000000..0a0f8fdc2c --- /dev/null +++ b/msautotest/renderers/compop_hsl_saturation.map @@ -0,0 +1,25 @@ +# RUN_PARMS: compop_hsl_saturation.agg.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: compop_hsl_saturation.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# +MAP + +NAME TEST +STATUS ON +SIZE 200 150 +EXTENT 0.5 0.5 399.5 299.5 +IMAGECOLOR 255 255 0 + +LAYER + NAME rgb + TYPE raster + STATUS default + DATA ../gdal/data/rgba.tif + PROCESSING "BANDS=1,2,3" + PROCESSING "USE_MASK_BAND=NO" + COMPOSITE + OPACITY 100 + COMPOP "hsl-saturation" + END +END + +END # of map file diff --git a/msautotest/renderers/compositing.map b/msautotest/renderers/compositing.map index 1f03a1f1d2..ba5de58f52 100644 --- a/msautotest/renderers/compositing.map +++ b/msautotest/renderers/compositing.map @@ -1,7 +1,7 @@ -# RUN_PARMS: compositing.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: compositing.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: compositing.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: compositing.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: compositing.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: compositing.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: compositing.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: compositing.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # # # Test use of 24bit images with a dummy class used to populate the legend. @@ -31,6 +31,7 @@ LAYER STATUS default DATA ../gdal/data/rgba.tif PROCESSING "BANDS=1,2,3" + PROCESSING "USE_MASK_BAND=NO" COMPOSITE OPACITY 45 COMPOP "multiply" diff --git a/msautotest/renderers/data/float64.tif b/msautotest/renderers/data/float64.tif new file mode 100644 index 0000000000..6f3ab122f0 Binary files /dev/null and b/msautotest/renderers/data/float64.tif differ diff --git a/msautotest/renderers/data/int32.tif b/msautotest/renderers/data/int32.tif new file mode 100644 index 0000000000..e57eb49ce9 Binary files /dev/null and b/msautotest/renderers/data/int32.tif differ diff --git a/msautotest/renderers/data/label_alias_offset.dbf b/msautotest/renderers/data/label_alias_offset.dbf index d0d359d48a..70f96f4332 100644 Binary files a/msautotest/renderers/data/label_alias_offset.dbf and b/msautotest/renderers/data/label_alias_offset.dbf differ diff --git a/msautotest/renderers/data/temperature.tif b/msautotest/renderers/data/temperature.tif new file mode 100644 index 0000000000..d0645b2450 Binary files /dev/null and b/msautotest/renderers/data/temperature.tif differ diff --git a/msautotest/renderers/data/wind_12.dbf b/msautotest/renderers/data/wind_12.dbf new file mode 100644 index 0000000000..58f7d40d3a Binary files /dev/null and b/msautotest/renderers/data/wind_12.dbf differ diff --git a/msautotest/renderers/data/wind_12.shp b/msautotest/renderers/data/wind_12.shp new file mode 100644 index 0000000000..a1e629342e Binary files /dev/null and b/msautotest/renderers/data/wind_12.shp differ diff --git a/msautotest/renderers/data/wind_12.shx b/msautotest/renderers/data/wind_12.shx new file mode 100644 index 0000000000..0d13fb9dba Binary files /dev/null and b/msautotest/renderers/data/wind_12.shx differ diff --git a/msautotest/renderers/embed_legend.map b/msautotest/renderers/embed_legend.map index 629e89ff84..b36abc2f51 100644 --- a/msautotest/renderers/embed_legend.map +++ b/msautotest/renderers/embed_legend.map @@ -1,5 +1,5 @@ -# RUN_PARMS: embed_legend.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: embed_legend.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: embed_legend.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: embed_legend.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # # # Simple test of embedded legend support. @@ -38,20 +38,26 @@ LAYER CLASS NAME "Big" EXPRESSION ([AREA] >= 500000) - COLOR 255 0 0 - OUTLINECOLOR 0 0 0 + STYLE + COLOR 255 0 0 + OUTLINECOLOR 0 0 0 + END END CLASS NAME "Medium" EXPRESSION ([AREA] >= 100000 and [AREA] < 500000) - COLOR 0 255 0 - OUTLINECOLOR 0 0 0 + STYLE + COLOR 0 255 0 + OUTLINECOLOR 0 0 0 + END END CLASS NAME "Small" EXPRESSION ([AREA] < 100000) - COLOR 0 0 255 - OUTLINECOLOR 0 0 0 + STYLE + COLOR 0 0 255 + OUTLINECOLOR 0 0 0 + END END END diff --git a/msautotest/renderers/embed_legend_rgba.map b/msautotest/renderers/embed_legend_rgba.map index 4014dd7357..71c2ce5025 100644 --- a/msautotest/renderers/embed_legend_rgba.map +++ b/msautotest/renderers/embed_legend_rgba.map @@ -1,5 +1,5 @@ -# RUN_PARMS: embed_legend_rgba.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: embed_legend_rgba.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: embed_legend_rgba.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: embed_legend_rgba.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # # # Simple test of embedded legend support. @@ -15,7 +15,15 @@ shapepath "../misc/data" IMAGETYPE png fontset "../misc/fonts.lst" -transparent on +OUTPUTFORMAT + DRIVER AGG/PNG + TRANSPARENT ON +END + +OUTPUTFORMAT + DRIVER CAIRO/PNG + TRANSPARENT ON +END LEGEND POSITION LR @@ -38,20 +46,26 @@ LAYER CLASS NAME "Big" EXPRESSION ([AREA] >= 500000) - COLOR 255 0 0 - OUTLINECOLOR 0 0 0 + STYLE + COLOR 255 0 0 + OUTLINECOLOR 0 0 0 + END END CLASS NAME "Medium" EXPRESSION ([AREA] >= 100000 and [AREA] < 500000) - COLOR 0 255 0 - OUTLINECOLOR 0 0 0 + STYLE + COLOR 0 255 0 + OUTLINECOLOR 0 0 0 + END END CLASS NAME "Small" EXPRESSION ([AREA] < 100000) - COLOR 0 0 255 - OUTLINECOLOR 0 0 0 + STYLE + COLOR 0 0 255 + OUTLINECOLOR 0 0 0 + END END END diff --git a/msautotest/renderers/embed_legend_rgba_tr.map b/msautotest/renderers/embed_legend_rgba_tr.map index e1e985e81a..77ad7d2d76 100644 --- a/msautotest/renderers/embed_legend_rgba_tr.map +++ b/msautotest/renderers/embed_legend_rgba_tr.map @@ -1,5 +1,5 @@ -# RUN_PARMS: embed_legend_rgba_tr.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: embed_legend_rgba_tr.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: embed_legend_rgba_tr.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: embed_legend_rgba_tr.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # # # Simple test of embedded legend support. @@ -15,7 +15,15 @@ shapepath "../misc/data" IMAGETYPE png fontset "../misc/fonts.lst" -transparent on +OUTPUTFORMAT + DRIVER AGG/PNG + TRANSPARENT ON +END + +OUTPUTFORMAT + DRIVER CAIRO/PNG + TRANSPARENT ON +END LEGEND POSITION LR @@ -38,20 +46,26 @@ LAYER CLASS NAME "Big" EXPRESSION ([AREA] >= 500000) - COLOR 255 0 0 - OUTLINECOLOR 0 0 0 + STYLE + COLOR 255 0 0 + OUTLINECOLOR 0 0 0 + END END CLASS NAME "Medium" EXPRESSION ([AREA] >= 100000 and [AREA] < 500000) - COLOR 0 255 0 - OUTLINECOLOR 0 0 0 + STYLE + COLOR 0 255 0 + OUTLINECOLOR 0 0 0 + END END CLASS NAME "Small" EXPRESSION ([AREA] < 100000) - COLOR 0 0 255 - OUTLINECOLOR 0 0 0 + STYLE + COLOR 0 0 255 + OUTLINECOLOR 0 0 0 + END END END diff --git a/msautotest/renderers/embed_legend_tr.map b/msautotest/renderers/embed_legend_tr.map index def812f288..a1aa577199 100644 --- a/msautotest/renderers/embed_legend_tr.map +++ b/msautotest/renderers/embed_legend_tr.map @@ -1,5 +1,5 @@ -# RUN_PARMS: embed_legend_tr.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: embed_legend_tr.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: embed_legend_tr.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: embed_legend_tr.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # # # Simple test of embedded legend support. @@ -37,20 +37,26 @@ LAYER CLASS NAME "Big" EXPRESSION ([AREA] >= 500000) - COLOR 255 0 0 - OUTLINECOLOR 0 0 0 + STYLE + COLOR 255 0 0 + OUTLINECOLOR 0 0 0 + END END CLASS NAME "Medium" EXPRESSION ([AREA] >= 100000 and [AREA] < 500000) - COLOR 0 255 0 - OUTLINECOLOR 0 0 0 + STYLE + COLOR 0 255 0 + OUTLINECOLOR 0 0 0 + END END CLASS NAME "Small" EXPRESSION ([AREA] < 100000) - COLOR 0 0 255 - OUTLINECOLOR 0 0 0 + STYLE + COLOR 0 0 255 + OUTLINECOLOR 0 0 0 + END END END diff --git a/msautotest/renderers/embed_sb_rgb.map b/msautotest/renderers/embed_sb_rgb.map index f10f2228c2..aa65c8396c 100644 --- a/msautotest/renderers/embed_sb_rgb.map +++ b/msautotest/renderers/embed_sb_rgb.map @@ -1,5 +1,5 @@ -# RUN_PARMS: embed_sb_rgb.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: embed_sb_rgb.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: embed_sb_rgb.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: embed_sb_rgb.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # # # Test embedded scalebar ... without transparency to RGBA output file. @@ -12,8 +12,6 @@ EXTENT -180 -90 180 90 SIZE 160 40 IMAGECOLOR 0 0 0 fontset "../misc/fonts.lst" - -TRANSPARENT OFF IMAGETYPE png diff --git a/msautotest/renderers/embed_sb_rgb_tr.map b/msautotest/renderers/embed_sb_rgb_tr.map index 1f8f0e5330..a089d0fa18 100644 --- a/msautotest/renderers/embed_sb_rgb_tr.map +++ b/msautotest/renderers/embed_sb_rgb_tr.map @@ -1,5 +1,5 @@ -# RUN_PARMS: embed_sb_rgb_tr.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: embed_sb_rgb_tr.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: embed_sb_rgb_tr.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: embed_sb_rgb_tr.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # # # Test embedded scalebar ... with transparency to RGB output file. @@ -12,7 +12,6 @@ EXTENT -180 -90 180 90 SIZE 160 40 IMAGECOLOR 255 255 255 fontset "../misc/fonts.lst" -TRANSPARENT OFF IMAGETYPE png diff --git a/msautotest/renderers/embed_sb_rgba.map b/msautotest/renderers/embed_sb_rgba.map index 29e6b1e80c..85e0d642dd 100644 --- a/msautotest/renderers/embed_sb_rgba.map +++ b/msautotest/renderers/embed_sb_rgba.map @@ -1,5 +1,5 @@ -# RUN_PARMS: embed_sb_rgba.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: embed_sb_rgba.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: embed_sb_rgba.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: embed_sb_rgba.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # # # Test embedded scalebar ... without transparency to RGBA output file. @@ -12,8 +12,16 @@ EXTENT -180 -90 180 90 SIZE 160 40 IMAGECOLOR 0 0 0 fontset "../misc/fonts.lst" - -TRANSPARENT ON + +OUTPUTFORMAT + DRIVER AGG/PNG + TRANSPARENT ON +END + +OUTPUTFORMAT + DRIVER CAIRO/PNG + TRANSPARENT ON +END IMAGETYPE png diff --git a/msautotest/renderers/embed_sb_rgba_offset.map b/msautotest/renderers/embed_sb_rgba_offset.map index 0227158a55..0bc9715c2c 100644 --- a/msautotest/renderers/embed_sb_rgba_offset.map +++ b/msautotest/renderers/embed_sb_rgba_offset.map @@ -1,5 +1,5 @@ -# RUN_PARMS: embed_sb_rgba_offset.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: embed_sb_rgba_offset.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: embed_sb_rgba_offset.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: embed_sb_rgba_offset.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # # # Test embedded scalebar with an offset. @@ -12,8 +12,16 @@ EXTENT -180 -90 180 90 SIZE 160 40 IMAGECOLOR 0 0 0 fontset "../misc/fonts.lst" - -TRANSPARENT ON + +OUTPUTFORMAT + DRIVER AGG/PNG + TRANSPARENT ON +END + +OUTPUTFORMAT + DRIVER CAIRO/PNG + TRANSPARENT ON +END IMAGETYPE png diff --git a/msautotest/renderers/embed_sb_rgba_tr.map b/msautotest/renderers/embed_sb_rgba_tr.map index a7377c2108..62045a3267 100644 --- a/msautotest/renderers/embed_sb_rgba_tr.map +++ b/msautotest/renderers/embed_sb_rgba_tr.map @@ -1,5 +1,5 @@ -# RUN_PARMS: embed_sb_rgba_tr.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: embed_sb_rgba_tr.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: embed_sb_rgba_tr.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: embed_sb_rgba_tr.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # # # Test embedded scalebar ... with transparency to RGBA output file. @@ -12,7 +12,17 @@ EXTENT -180 -90 180 90 SIZE 160 40 IMAGECOLOR 0 0 0 fontset "../misc/fonts.lst" -TRANSPARENT ON + +OUTPUTFORMAT + DRIVER AGG/PNG + TRANSPARENT ON +END + +OUTPUTFORMAT + DRIVER CAIRO/PNG + TRANSPARENT ON +END + imagecolor 255 255 255 IMAGETYPE png diff --git a/msautotest/renderers/empty.map b/msautotest/renderers/empty.map index 7fd2643341..0d57eedfcf 100644 --- a/msautotest/renderers/empty.map +++ b/msautotest/renderers/empty.map @@ -1,7 +1,7 @@ -# RUN_PARMS: empty.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: empty.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: empty.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: empty.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: empty.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: empty.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: empty.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: empty.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # map diff --git a/msautotest/renderers/entity_encoded_follow_text.map b/msautotest/renderers/entity_encoded_follow_text.map index 2e2512099a..390199da32 100644 --- a/msautotest/renderers/entity_encoded_follow_text.map +++ b/msautotest/renderers/entity_encoded_follow_text.map @@ -1,7 +1,7 @@ -# RUN_PARMS: entity_encoded_follow_text.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: entity_encoded_follow_text.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: entity_encoded_follow_text.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: entity_encoded_follow_text.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: entity_encoded_follow_text.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: entity_encoded_follow_text.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: entity_encoded_follow_text.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: entity_encoded_follow_text.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # # # entity-encoded text rendering test. diff --git a/msautotest/renderers/expected/average_rgb.pdf b/msautotest/renderers/expected/average_rgb.pdf index c281cef9da..979e415c98 100644 Binary files a/msautotest/renderers/expected/average_rgb.pdf and b/msautotest/renderers/expected/average_rgb.pdf differ diff --git a/msautotest/renderers/expected/average_rgb.svg b/msautotest/renderers/expected/average_rgb.svg index acb2ba486f..e12c9d2424 100644 --- a/msautotest/renderers/expected/average_rgb.svg +++ b/msautotest/renderers/expected/average_rgb.svg @@ -1,10 +1,37 @@ - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + diff --git a/msautotest/renderers/expected/baseline_text.cairo.png b/msautotest/renderers/expected/baseline_text.cairo.png index a12c4444da..1269536e08 100644 Binary files a/msautotest/renderers/expected/baseline_text.cairo.png and b/msautotest/renderers/expected/baseline_text.cairo.png differ diff --git a/msautotest/renderers/expected/baseline_text.pdf b/msautotest/renderers/expected/baseline_text.pdf index c7899584be..2fd2eba1ac 100644 Binary files a/msautotest/renderers/expected/baseline_text.pdf and b/msautotest/renderers/expected/baseline_text.pdf differ diff --git a/msautotest/renderers/expected/baseline_text.png b/msautotest/renderers/expected/baseline_text.png index b5845733f1..ca479bd843 100644 Binary files a/msautotest/renderers/expected/baseline_text.png and b/msautotest/renderers/expected/baseline_text.png differ diff --git a/msautotest/renderers/expected/baseline_text.svg b/msautotest/renderers/expected/baseline_text.svg index 7e14bf74f6..86de575c5c 100644 --- a/msautotest/renderers/expected/baseline_text.svg +++ b/msautotest/renderers/expected/baseline_text.svg @@ -1,8 +1,36 @@ - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msautotest/renderers/expected/chartlayer_bar.pdf b/msautotest/renderers/expected/chartlayer_bar.pdf index beb2761bbe..7f8eeee5ee 100644 Binary files a/msautotest/renderers/expected/chartlayer_bar.pdf and b/msautotest/renderers/expected/chartlayer_bar.pdf differ diff --git a/msautotest/renderers/expected/chartlayer_bar.svg b/msautotest/renderers/expected/chartlayer_bar.svg index 71290f2a7a..f5c2c49b06 100644 --- a/msautotest/renderers/expected/chartlayer_bar.svg +++ b/msautotest/renderers/expected/chartlayer_bar.svg @@ -1,18 +1,47 @@ - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msautotest/renderers/expected/chartlayer_pie.cairo.png b/msautotest/renderers/expected/chartlayer_pie.cairo.png index 050d29c773..a76d6def51 100644 Binary files a/msautotest/renderers/expected/chartlayer_pie.cairo.png and b/msautotest/renderers/expected/chartlayer_pie.cairo.png differ diff --git a/msautotest/renderers/expected/chartlayer_pie.pdf b/msautotest/renderers/expected/chartlayer_pie.pdf index 2ba5e85967..1566025bfe 100644 Binary files a/msautotest/renderers/expected/chartlayer_pie.pdf and b/msautotest/renderers/expected/chartlayer_pie.pdf differ diff --git a/msautotest/renderers/expected/chartlayer_pie.svg b/msautotest/renderers/expected/chartlayer_pie.svg index 3baf3c8b53..3cfa4dc373 100644 --- a/msautotest/renderers/expected/chartlayer_pie.svg +++ b/msautotest/renderers/expected/chartlayer_pie.svg @@ -1,18 +1,47 @@ - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msautotest/renderers/expected/chartlayer_pie2.cairo.png b/msautotest/renderers/expected/chartlayer_pie2.cairo.png index f83a3b6d15..fbd48bfe08 100644 Binary files a/msautotest/renderers/expected/chartlayer_pie2.cairo.png and b/msautotest/renderers/expected/chartlayer_pie2.cairo.png differ diff --git a/msautotest/renderers/expected/chartlayer_pie2.pdf b/msautotest/renderers/expected/chartlayer_pie2.pdf index 3e1d70760a..58f3ad7a76 100644 Binary files a/msautotest/renderers/expected/chartlayer_pie2.pdf and b/msautotest/renderers/expected/chartlayer_pie2.pdf differ diff --git a/msautotest/renderers/expected/chartlayer_pie2.svg b/msautotest/renderers/expected/chartlayer_pie2.svg index fd8903ca01..33bef9d78a 100644 --- a/msautotest/renderers/expected/chartlayer_pie2.svg +++ b/msautotest/renderers/expected/chartlayer_pie2.svg @@ -1,18 +1,47 @@ - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msautotest/renderers/expected/chartlayer_pie_expressions.cairo.png b/msautotest/renderers/expected/chartlayer_pie_expressions.cairo.png index ec9d673311..403fa56027 100644 Binary files a/msautotest/renderers/expected/chartlayer_pie_expressions.cairo.png and b/msautotest/renderers/expected/chartlayer_pie_expressions.cairo.png differ diff --git a/msautotest/renderers/expected/chartlayer_pie_expressions.pdf b/msautotest/renderers/expected/chartlayer_pie_expressions.pdf index 7b4c5bd242..0ee70021bc 100644 Binary files a/msautotest/renderers/expected/chartlayer_pie_expressions.pdf and b/msautotest/renderers/expected/chartlayer_pie_expressions.pdf differ diff --git a/msautotest/renderers/expected/chartlayer_pie_expressions.svg b/msautotest/renderers/expected/chartlayer_pie_expressions.svg index 40fd6e5254..c35e0042e0 100644 --- a/msautotest/renderers/expected/chartlayer_pie_expressions.svg +++ b/msautotest/renderers/expected/chartlayer_pie_expressions.svg @@ -1,32 +1,61 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msautotest/renderers/expected/chartlayer_vbar.pdf b/msautotest/renderers/expected/chartlayer_vbar.pdf index 82db7f9a01..5b59736e6e 100644 Binary files a/msautotest/renderers/expected/chartlayer_vbar.pdf and b/msautotest/renderers/expected/chartlayer_vbar.pdf differ diff --git a/msautotest/renderers/expected/chartlayer_vbar.svg b/msautotest/renderers/expected/chartlayer_vbar.svg index e49cb3ee46..7627e52b50 100644 --- a/msautotest/renderers/expected/chartlayer_vbar.svg +++ b/msautotest/renderers/expected/chartlayer_vbar.svg @@ -1,18 +1,47 @@ - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msautotest/renderers/expected/circle_layer.cairo.png b/msautotest/renderers/expected/circle_layer.cairo.png index 5b0cbc1715..6c540670c9 100644 Binary files a/msautotest/renderers/expected/circle_layer.cairo.png and b/msautotest/renderers/expected/circle_layer.cairo.png differ diff --git a/msautotest/renderers/expected/circle_layer.pdf b/msautotest/renderers/expected/circle_layer.pdf index f3fcb73ccd..2d01167014 100644 Binary files a/msautotest/renderers/expected/circle_layer.pdf and b/msautotest/renderers/expected/circle_layer.pdf differ diff --git a/msautotest/renderers/expected/circle_layer.svg b/msautotest/renderers/expected/circle_layer.svg index 9ce685a2ed..3954175c03 100644 --- a/msautotest/renderers/expected/circle_layer.svg +++ b/msautotest/renderers/expected/circle_layer.svg @@ -1,8 +1,37 @@ - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msautotest/renderers/expected/compop_hsl_color.agg.png b/msautotest/renderers/expected/compop_hsl_color.agg.png new file mode 100644 index 0000000000..93a0ed556b Binary files /dev/null and b/msautotest/renderers/expected/compop_hsl_color.agg.png differ diff --git a/msautotest/renderers/expected/compop_hsl_color.cairo.png b/msautotest/renderers/expected/compop_hsl_color.cairo.png new file mode 100644 index 0000000000..ad78e7d2a9 Binary files /dev/null and b/msautotest/renderers/expected/compop_hsl_color.cairo.png differ diff --git a/msautotest/renderers/expected/compop_hsl_color_opacity_50.agg.png b/msautotest/renderers/expected/compop_hsl_color_opacity_50.agg.png new file mode 100644 index 0000000000..984f97a68d Binary files /dev/null and b/msautotest/renderers/expected/compop_hsl_color_opacity_50.agg.png differ diff --git a/msautotest/renderers/expected/compop_hsl_color_opacity_50.cairo.png b/msautotest/renderers/expected/compop_hsl_color_opacity_50.cairo.png new file mode 100644 index 0000000000..1ec2b99dfb Binary files /dev/null and b/msautotest/renderers/expected/compop_hsl_color_opacity_50.cairo.png differ diff --git a/msautotest/renderers/expected/compop_hsl_hue.agg.png b/msautotest/renderers/expected/compop_hsl_hue.agg.png new file mode 100644 index 0000000000..5edeca52a9 Binary files /dev/null and b/msautotest/renderers/expected/compop_hsl_hue.agg.png differ diff --git a/msautotest/renderers/expected/compop_hsl_hue.cairo.png b/msautotest/renderers/expected/compop_hsl_hue.cairo.png new file mode 100644 index 0000000000..8fcbb29c93 Binary files /dev/null and b/msautotest/renderers/expected/compop_hsl_hue.cairo.png differ diff --git a/msautotest/renderers/expected/compop_hsl_luminosity.agg.png b/msautotest/renderers/expected/compop_hsl_luminosity.agg.png new file mode 100644 index 0000000000..694b6099b6 Binary files /dev/null and b/msautotest/renderers/expected/compop_hsl_luminosity.agg.png differ diff --git a/msautotest/renderers/expected/compop_hsl_luminosity.cairo.png b/msautotest/renderers/expected/compop_hsl_luminosity.cairo.png new file mode 100644 index 0000000000..50765064e9 Binary files /dev/null and b/msautotest/renderers/expected/compop_hsl_luminosity.cairo.png differ diff --git a/msautotest/renderers/expected/compop_hsl_saturation.agg.png b/msautotest/renderers/expected/compop_hsl_saturation.agg.png new file mode 100644 index 0000000000..bae7f14b2d Binary files /dev/null and b/msautotest/renderers/expected/compop_hsl_saturation.agg.png differ diff --git a/msautotest/renderers/expected/compop_hsl_saturation.cairo.png b/msautotest/renderers/expected/compop_hsl_saturation.cairo.png new file mode 100644 index 0000000000..64372befdd Binary files /dev/null and b/msautotest/renderers/expected/compop_hsl_saturation.cairo.png differ diff --git a/msautotest/renderers/expected/compositing.pdf b/msautotest/renderers/expected/compositing.pdf index f4d35bae64..2e642c01c4 100644 Binary files a/msautotest/renderers/expected/compositing.pdf and b/msautotest/renderers/expected/compositing.pdf differ diff --git a/msautotest/renderers/expected/compositing.png b/msautotest/renderers/expected/compositing.png index 7957fd23de..f3514f705f 100644 Binary files a/msautotest/renderers/expected/compositing.png and b/msautotest/renderers/expected/compositing.png differ diff --git a/msautotest/renderers/expected/compositing.svg b/msautotest/renderers/expected/compositing.svg index 48f92265cc..9aee49fdad 100644 --- a/msautotest/renderers/expected/compositing.svg +++ b/msautotest/renderers/expected/compositing.svg @@ -1,24 +1,53 @@ - + - - + + - - - - + + + + + + + + + + + + + + - - - + + + + + + + + + + + + + + + + + + + + - - + + - - - + + + + + diff --git a/msautotest/renderers/expected/embed_legend.cairo.png b/msautotest/renderers/expected/embed_legend.cairo.png index d9639128bd..c4df913924 100644 Binary files a/msautotest/renderers/expected/embed_legend.cairo.png and b/msautotest/renderers/expected/embed_legend.cairo.png differ diff --git a/msautotest/renderers/expected/embed_legend_rgba.cairo.png b/msautotest/renderers/expected/embed_legend_rgba.cairo.png index 92d72bbf42..fa9a19a682 100644 Binary files a/msautotest/renderers/expected/embed_legend_rgba.cairo.png and b/msautotest/renderers/expected/embed_legend_rgba.cairo.png differ diff --git a/msautotest/renderers/expected/embed_legend_rgba_tr.cairo.png b/msautotest/renderers/expected/embed_legend_rgba_tr.cairo.png index 92d72bbf42..fa9a19a682 100644 Binary files a/msautotest/renderers/expected/embed_legend_rgba_tr.cairo.png and b/msautotest/renderers/expected/embed_legend_rgba_tr.cairo.png differ diff --git a/msautotest/renderers/expected/embed_legend_tr.cairo.png b/msautotest/renderers/expected/embed_legend_tr.cairo.png index 29d785107b..a3828bd661 100644 Binary files a/msautotest/renderers/expected/embed_legend_tr.cairo.png and b/msautotest/renderers/expected/embed_legend_tr.cairo.png differ diff --git a/msautotest/renderers/expected/embed_sb_rgb.cairo.png b/msautotest/renderers/expected/embed_sb_rgb.cairo.png index 5c78a6f8ca..cce88d429d 100644 Binary files a/msautotest/renderers/expected/embed_sb_rgb.cairo.png and b/msautotest/renderers/expected/embed_sb_rgb.cairo.png differ diff --git a/msautotest/renderers/expected/embed_sb_rgb.png b/msautotest/renderers/expected/embed_sb_rgb.png index 0c3388ca48..e1aaa9aa3f 100644 Binary files a/msautotest/renderers/expected/embed_sb_rgb.png and b/msautotest/renderers/expected/embed_sb_rgb.png differ diff --git a/msautotest/renderers/expected/embed_sb_rgb_tr.cairo.png b/msautotest/renderers/expected/embed_sb_rgb_tr.cairo.png index 3e3bbec1a3..72a3618e0d 100644 Binary files a/msautotest/renderers/expected/embed_sb_rgb_tr.cairo.png and b/msautotest/renderers/expected/embed_sb_rgb_tr.cairo.png differ diff --git a/msautotest/renderers/expected/embed_sb_rgb_tr.png b/msautotest/renderers/expected/embed_sb_rgb_tr.png index 99e9b7c497..bfdaf7bce2 100644 Binary files a/msautotest/renderers/expected/embed_sb_rgb_tr.png and b/msautotest/renderers/expected/embed_sb_rgb_tr.png differ diff --git a/msautotest/renderers/expected/embed_sb_rgba.cairo.png b/msautotest/renderers/expected/embed_sb_rgba.cairo.png index d91eeb3d15..5d8fe80e7a 100644 Binary files a/msautotest/renderers/expected/embed_sb_rgba.cairo.png and b/msautotest/renderers/expected/embed_sb_rgba.cairo.png differ diff --git a/msautotest/renderers/expected/embed_sb_rgba.png b/msautotest/renderers/expected/embed_sb_rgba.png index 50351506ca..1f78086f42 100644 Binary files a/msautotest/renderers/expected/embed_sb_rgba.png and b/msautotest/renderers/expected/embed_sb_rgba.png differ diff --git a/msautotest/renderers/expected/embed_sb_rgba_offset.cairo.png b/msautotest/renderers/expected/embed_sb_rgba_offset.cairo.png index 8bd88c9f03..69c8cdeed0 100644 Binary files a/msautotest/renderers/expected/embed_sb_rgba_offset.cairo.png and b/msautotest/renderers/expected/embed_sb_rgba_offset.cairo.png differ diff --git a/msautotest/renderers/expected/embed_sb_rgba_offset.png b/msautotest/renderers/expected/embed_sb_rgba_offset.png index c37f623b50..e70c320f1b 100644 Binary files a/msautotest/renderers/expected/embed_sb_rgba_offset.png and b/msautotest/renderers/expected/embed_sb_rgba_offset.png differ diff --git a/msautotest/renderers/expected/embed_sb_rgba_tr.cairo.png b/msautotest/renderers/expected/embed_sb_rgba_tr.cairo.png index 27742052a4..d71be1f88f 100644 Binary files a/msautotest/renderers/expected/embed_sb_rgba_tr.cairo.png and b/msautotest/renderers/expected/embed_sb_rgba_tr.cairo.png differ diff --git a/msautotest/renderers/expected/embed_sb_rgba_tr.png b/msautotest/renderers/expected/embed_sb_rgba_tr.png index 2958eb4b7a..68cf091cb0 100644 Binary files a/msautotest/renderers/expected/embed_sb_rgba_tr.png and b/msautotest/renderers/expected/embed_sb_rgba_tr.png differ diff --git a/msautotest/renderers/expected/empty.pdf b/msautotest/renderers/expected/empty.pdf index 45ddca3b6b..75b6181c54 100644 Binary files a/msautotest/renderers/expected/empty.pdf and b/msautotest/renderers/expected/empty.pdf differ diff --git a/msautotest/renderers/expected/empty.svg b/msautotest/renderers/expected/empty.svg index dc8c1df98e..23ac5cbad6 100644 --- a/msautotest/renderers/expected/empty.svg +++ b/msautotest/renderers/expected/empty.svg @@ -1,6 +1,35 @@ - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msautotest/renderers/expected/entity_encoded_follow_text.cairo.png b/msautotest/renderers/expected/entity_encoded_follow_text.cairo.png index ad362f2aa9..e1761daa63 100644 Binary files a/msautotest/renderers/expected/entity_encoded_follow_text.cairo.png and b/msautotest/renderers/expected/entity_encoded_follow_text.cairo.png differ diff --git a/msautotest/renderers/expected/entity_encoded_follow_text.pdf b/msautotest/renderers/expected/entity_encoded_follow_text.pdf index 26bd6aba58..2213d496ab 100644 Binary files a/msautotest/renderers/expected/entity_encoded_follow_text.pdf and b/msautotest/renderers/expected/entity_encoded_follow_text.pdf differ diff --git a/msautotest/renderers/expected/entity_encoded_follow_text.png b/msautotest/renderers/expected/entity_encoded_follow_text.png index ed12250039..a75fd396fe 100644 Binary files a/msautotest/renderers/expected/entity_encoded_follow_text.png and b/msautotest/renderers/expected/entity_encoded_follow_text.png differ diff --git a/msautotest/renderers/expected/entity_encoded_follow_text.svg b/msautotest/renderers/expected/entity_encoded_follow_text.svg index 766366ba93..c094642acf 100644 --- a/msautotest/renderers/expected/entity_encoded_follow_text.svg +++ b/msautotest/renderers/expected/entity_encoded_follow_text.svg @@ -1,20 +1,49 @@ - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msautotest/renderers/expected/font-fail-file.txt b/msautotest/renderers/expected/font-fail-file.txt index 278509ad80..292fb77cc4 100644 --- a/msautotest/renderers/expected/font-fail-file.txt +++ b/msautotest/renderers/expected/font-fail-file.txt @@ -1,6 +1,7 @@ Content-Type: text/html -MapServer Message -msGetFontFace(): General error message. Freetype was unable to load font file "/path/to/inexistant/file.ttf" for key "bogus" +MapServer Message + +msGetFontFace(): General error message. Freetype was unable to load font file "/path/to/inexistent/file.ttf" for key "bogus" \ No newline at end of file diff --git a/msautotest/renderers/expected/font-fail-key.txt b/msautotest/renderers/expected/font-fail-key.txt index 335e4ad607..a2feb26f77 100644 --- a/msautotest/renderers/expected/font-fail-key.txt +++ b/msautotest/renderers/expected/font-fail-key.txt @@ -1,6 +1,7 @@ Content-Type: text/html -MapServer Message +MapServer Message + msGetFontFace(): General error message. Could not find font with key "foobar" in fontset \ No newline at end of file diff --git a/msautotest/renderers/expected/font-fail-missing-glyph.png b/msautotest/renderers/expected/font-fail-missing-glyph.png new file mode 100644 index 0000000000..611bdedc0e Binary files /dev/null and b/msautotest/renderers/expected/font-fail-missing-glyph.png differ diff --git a/msautotest/renderers/expected/geomtransform-vertex-layer.cairo.png b/msautotest/renderers/expected/geomtransform-vertex-layer.cairo.png index 1ef6ecdd39..646d809861 100644 Binary files a/msautotest/renderers/expected/geomtransform-vertex-layer.cairo.png and b/msautotest/renderers/expected/geomtransform-vertex-layer.cairo.png differ diff --git a/msautotest/renderers/expected/geomtransform-vertex-layer.pdf b/msautotest/renderers/expected/geomtransform-vertex-layer.pdf index 4f668e68c3..f7280dea34 100644 Binary files a/msautotest/renderers/expected/geomtransform-vertex-layer.pdf and b/msautotest/renderers/expected/geomtransform-vertex-layer.pdf differ diff --git a/msautotest/renderers/expected/geomtransform-vertex-layer.svg b/msautotest/renderers/expected/geomtransform-vertex-layer.svg index ff0e013cca..deb50369eb 100644 --- a/msautotest/renderers/expected/geomtransform-vertex-layer.svg +++ b/msautotest/renderers/expected/geomtransform-vertex-layer.svg @@ -1,9 +1,38 @@ - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msautotest/renderers/expected/geomtransform-vertex.cairo.png b/msautotest/renderers/expected/geomtransform-vertex.cairo.png index 03fa0eca53..1e8285914a 100644 Binary files a/msautotest/renderers/expected/geomtransform-vertex.cairo.png and b/msautotest/renderers/expected/geomtransform-vertex.cairo.png differ diff --git a/msautotest/renderers/expected/geomtransform-vertex.pdf b/msautotest/renderers/expected/geomtransform-vertex.pdf index 032c646031..d5a7e8d6d8 100644 Binary files a/msautotest/renderers/expected/geomtransform-vertex.pdf and b/msautotest/renderers/expected/geomtransform-vertex.pdf differ diff --git a/msautotest/renderers/expected/geomtransform-vertex.svg b/msautotest/renderers/expected/geomtransform-vertex.svg index fc71381a55..19e75db9cd 100644 --- a/msautotest/renderers/expected/geomtransform-vertex.svg +++ b/msautotest/renderers/expected/geomtransform-vertex.svg @@ -1,39 +1,68 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msautotest/renderers/expected/grid.cairo.png b/msautotest/renderers/expected/grid.cairo.png index 1061c5f238..01c2fadd2c 100644 Binary files a/msautotest/renderers/expected/grid.cairo.png and b/msautotest/renderers/expected/grid.cairo.png differ diff --git a/msautotest/renderers/expected/grid.pdf b/msautotest/renderers/expected/grid.pdf index 2e4ed713a5..9caf1e4b2f 100644 Binary files a/msautotest/renderers/expected/grid.pdf and b/msautotest/renderers/expected/grid.pdf differ diff --git a/msautotest/renderers/expected/grid.png b/msautotest/renderers/expected/grid.png index 42acbba706..de9e956dde 100644 Binary files a/msautotest/renderers/expected/grid.png and b/msautotest/renderers/expected/grid.png differ diff --git a/msautotest/renderers/expected/grid.svg b/msautotest/renderers/expected/grid.svg index 910110968e..6abafa312f 100644 --- a/msautotest/renderers/expected/grid.svg +++ b/msautotest/renderers/expected/grid.svg @@ -1,86 +1,115 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msautotest/renderers/expected/label-align-center.cairo.png b/msautotest/renderers/expected/label-align-center.cairo.png index 7bbbdbe953..3ddc0a7ede 100644 Binary files a/msautotest/renderers/expected/label-align-center.cairo.png and b/msautotest/renderers/expected/label-align-center.cairo.png differ diff --git a/msautotest/renderers/expected/label-align-center.png b/msautotest/renderers/expected/label-align-center.png index 87d623058a..f5a244206f 100644 Binary files a/msautotest/renderers/expected/label-align-center.png and b/msautotest/renderers/expected/label-align-center.png differ diff --git a/msautotest/renderers/expected/label-align-default.cairo.png b/msautotest/renderers/expected/label-align-default.cairo.png index ad1b6e8a2c..eb9f35f49b 100644 Binary files a/msautotest/renderers/expected/label-align-default.cairo.png and b/msautotest/renderers/expected/label-align-default.cairo.png differ diff --git a/msautotest/renderers/expected/label-align-default.png b/msautotest/renderers/expected/label-align-default.png index ba76fcf6f0..d144aeaa3e 100644 Binary files a/msautotest/renderers/expected/label-align-default.png and b/msautotest/renderers/expected/label-align-default.png differ diff --git a/msautotest/renderers/expected/label-align-left.cairo.png b/msautotest/renderers/expected/label-align-left.cairo.png index 7cc363063b..33ccbb9fbe 100644 Binary files a/msautotest/renderers/expected/label-align-left.cairo.png and b/msautotest/renderers/expected/label-align-left.cairo.png differ diff --git a/msautotest/renderers/expected/label-align-left.png b/msautotest/renderers/expected/label-align-left.png index 73b7bfdbd2..d4dddfcb52 100644 Binary files a/msautotest/renderers/expected/label-align-left.png and b/msautotest/renderers/expected/label-align-left.png differ diff --git a/msautotest/renderers/expected/label-align-right.cairo.png b/msautotest/renderers/expected/label-align-right.cairo.png index 23fa6f9fa6..a917c6f4a8 100644 Binary files a/msautotest/renderers/expected/label-align-right.cairo.png and b/msautotest/renderers/expected/label-align-right.cairo.png differ diff --git a/msautotest/renderers/expected/label-align-right.png b/msautotest/renderers/expected/label-align-right.png index fb2d27051f..7f777da104 100644 Binary files a/msautotest/renderers/expected/label-align-right.png and b/msautotest/renderers/expected/label-align-right.png differ diff --git a/msautotest/renderers/expected/label-multifont.cairo.png b/msautotest/renderers/expected/label-multifont.cairo.png index d54e9ec628..220a9ce385 100644 Binary files a/msautotest/renderers/expected/label-multifont.cairo.png and b/msautotest/renderers/expected/label-multifont.cairo.png differ diff --git a/msautotest/renderers/expected/label-multifont.pdf b/msautotest/renderers/expected/label-multifont.pdf index ec89ad6d3c..acaac93b51 100644 Binary files a/msautotest/renderers/expected/label-multifont.pdf and b/msautotest/renderers/expected/label-multifont.pdf differ diff --git a/msautotest/renderers/expected/label-multifont.png b/msautotest/renderers/expected/label-multifont.png index acf9006d37..be83a7ec56 100644 Binary files a/msautotest/renderers/expected/label-multifont.png and b/msautotest/renderers/expected/label-multifont.png differ diff --git a/msautotest/renderers/expected/label-multifont.svg b/msautotest/renderers/expected/label-multifont.svg index 54aaefc9eb..904f32675d 100644 --- a/msautotest/renderers/expected/label-multifont.svg +++ b/msautotest/renderers/expected/label-multifont.svg @@ -1,11 +1,40 @@ - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msautotest/renderers/expected/label_align_attribute.png b/msautotest/renderers/expected/label_align_attribute.png index 91f257d660..81107b7898 100644 Binary files a/msautotest/renderers/expected/label_align_attribute.png and b/msautotest/renderers/expected/label_align_attribute.png differ diff --git a/msautotest/renderers/expected/label_ar-align-center.cairo.png b/msautotest/renderers/expected/label_ar-align-center.cairo.png index 8ee63678fe..bebd2a0556 100644 Binary files a/msautotest/renderers/expected/label_ar-align-center.cairo.png and b/msautotest/renderers/expected/label_ar-align-center.cairo.png differ diff --git a/msautotest/renderers/expected/label_ar-align-center.png b/msautotest/renderers/expected/label_ar-align-center.png index 3124fe8b6c..c807ed06a4 100644 Binary files a/msautotest/renderers/expected/label_ar-align-center.png and b/msautotest/renderers/expected/label_ar-align-center.png differ diff --git a/msautotest/renderers/expected/label_ar-align-default.cairo.png b/msautotest/renderers/expected/label_ar-align-default.cairo.png index 066351ee1a..ec30d46fc6 100644 Binary files a/msautotest/renderers/expected/label_ar-align-default.cairo.png and b/msautotest/renderers/expected/label_ar-align-default.cairo.png differ diff --git a/msautotest/renderers/expected/label_ar-align-default.png b/msautotest/renderers/expected/label_ar-align-default.png index ddab3daaa4..3532efd78e 100644 Binary files a/msautotest/renderers/expected/label_ar-align-default.png and b/msautotest/renderers/expected/label_ar-align-default.png differ diff --git a/msautotest/renderers/expected/label_ar-align-left.cairo.png b/msautotest/renderers/expected/label_ar-align-left.cairo.png index ebbf4ac570..b405c1fd4c 100644 Binary files a/msautotest/renderers/expected/label_ar-align-left.cairo.png and b/msautotest/renderers/expected/label_ar-align-left.cairo.png differ diff --git a/msautotest/renderers/expected/label_ar-align-left.png b/msautotest/renderers/expected/label_ar-align-left.png index ebea27fe77..4e0c96653f 100644 Binary files a/msautotest/renderers/expected/label_ar-align-left.png and b/msautotest/renderers/expected/label_ar-align-left.png differ diff --git a/msautotest/renderers/expected/label_ar-align-right.cairo.png b/msautotest/renderers/expected/label_ar-align-right.cairo.png index 066351ee1a..ec30d46fc6 100644 Binary files a/msautotest/renderers/expected/label_ar-align-right.cairo.png and b/msautotest/renderers/expected/label_ar-align-right.cairo.png differ diff --git a/msautotest/renderers/expected/label_ar-align-right.png b/msautotest/renderers/expected/label_ar-align-right.png index ddab3daaa4..3532efd78e 100644 Binary files a/msautotest/renderers/expected/label_ar-align-right.png and b/msautotest/renderers/expected/label_ar-align-right.png differ diff --git a/msautotest/renderers/expected/label_latin_align_center.png b/msautotest/renderers/expected/label_latin_align_center.png index 28392fc3e2..ea71cef348 100644 Binary files a/msautotest/renderers/expected/label_latin_align_center.png and b/msautotest/renderers/expected/label_latin_align_center.png differ diff --git a/msautotest/renderers/expected/label_latin_align_default.png b/msautotest/renderers/expected/label_latin_align_default.png index d52271aada..2a296b3f03 100644 Binary files a/msautotest/renderers/expected/label_latin_align_default.png and b/msautotest/renderers/expected/label_latin_align_default.png differ diff --git a/msautotest/renderers/expected/label_latin_align_left.png b/msautotest/renderers/expected/label_latin_align_left.png index d52271aada..2a296b3f03 100644 Binary files a/msautotest/renderers/expected/label_latin_align_left.png and b/msautotest/renderers/expected/label_latin_align_left.png differ diff --git a/msautotest/renderers/expected/label_latin_align_right.png b/msautotest/renderers/expected/label_latin_align_right.png index 4e63cedcca..8c0ab79622 100644 Binary files a/msautotest/renderers/expected/label_latin_align_right.png and b/msautotest/renderers/expected/label_latin_align_right.png differ diff --git a/msautotest/renderers/expected/label_noclip.cairo.png b/msautotest/renderers/expected/label_noclip.cairo.png index cc19415e4d..32cd241f94 100644 Binary files a/msautotest/renderers/expected/label_noclip.cairo.png and b/msautotest/renderers/expected/label_noclip.cairo.png differ diff --git a/msautotest/renderers/expected/label_noclip.pdf b/msautotest/renderers/expected/label_noclip.pdf index 065c55fd3b..59d2e23783 100644 Binary files a/msautotest/renderers/expected/label_noclip.pdf and b/msautotest/renderers/expected/label_noclip.pdf differ diff --git a/msautotest/renderers/expected/label_noclip.svg b/msautotest/renderers/expected/label_noclip.svg index 543191786e..710c4a7db9 100644 --- a/msautotest/renderers/expected/label_noclip.svg +++ b/msautotest/renderers/expected/label_noclip.svg @@ -1,12 +1,41 @@ - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msautotest/renderers/expected/label_offset_attribute.png b/msautotest/renderers/expected/label_offset_attribute.png index 7db4c86b03..c2bed2aea1 100644 Binary files a/msautotest/renderers/expected/label_offset_attribute.png and b/msautotest/renderers/expected/label_offset_attribute.png differ diff --git a/msautotest/renderers/expected/label_priority_binding.png b/msautotest/renderers/expected/label_priority_binding.png new file mode 100644 index 0000000000..bc53b12159 Binary files /dev/null and b/msautotest/renderers/expected/label_priority_binding.png differ diff --git a/msautotest/renderers/expected/label_priority_expression.png b/msautotest/renderers/expected/label_priority_expression.png new file mode 100644 index 0000000000..6fe430f241 Binary files /dev/null and b/msautotest/renderers/expected/label_priority_expression.png differ diff --git a/msautotest/renderers/expected/label_priority_fixed.png b/msautotest/renderers/expected/label_priority_fixed.png new file mode 100644 index 0000000000..5f2538ff23 Binary files /dev/null and b/msautotest/renderers/expected/label_priority_fixed.png differ diff --git a/msautotest/renderers/expected/labelcacheoff.cairo.png b/msautotest/renderers/expected/labelcacheoff.cairo.png index 7ca27e5318..e4d28bd2f5 100644 Binary files a/msautotest/renderers/expected/labelcacheoff.cairo.png and b/msautotest/renderers/expected/labelcacheoff.cairo.png differ diff --git a/msautotest/renderers/expected/labelcacheoff.pdf b/msautotest/renderers/expected/labelcacheoff.pdf index 266597fe43..54c304eeac 100644 Binary files a/msautotest/renderers/expected/labelcacheoff.pdf and b/msautotest/renderers/expected/labelcacheoff.pdf differ diff --git a/msautotest/renderers/expected/labelcacheoff.png b/msautotest/renderers/expected/labelcacheoff.png index 1f4f89a3a5..d9cae1ac1d 100644 Binary files a/msautotest/renderers/expected/labelcacheoff.png and b/msautotest/renderers/expected/labelcacheoff.png differ diff --git a/msautotest/renderers/expected/labelcacheoff.svg b/msautotest/renderers/expected/labelcacheoff.svg index daf07bc173..0dc6d5276b 100644 --- a/msautotest/renderers/expected/labelcacheoff.svg +++ b/msautotest/renderers/expected/labelcacheoff.svg @@ -1,14 +1,43 @@ - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msautotest/renderers/expected/labelpnt.cairo.png b/msautotest/renderers/expected/labelpnt.cairo.png index af7bfdc63d..4250512ade 100644 Binary files a/msautotest/renderers/expected/labelpnt.cairo.png and b/msautotest/renderers/expected/labelpnt.cairo.png differ diff --git a/msautotest/renderers/expected/labelpnt.pdf b/msautotest/renderers/expected/labelpnt.pdf index ceb5974f91..6a619dc8b2 100644 Binary files a/msautotest/renderers/expected/labelpnt.pdf and b/msautotest/renderers/expected/labelpnt.pdf differ diff --git a/msautotest/renderers/expected/labelpnt.png b/msautotest/renderers/expected/labelpnt.png index a3e46a7f5d..18facd7b47 100644 Binary files a/msautotest/renderers/expected/labelpnt.png and b/msautotest/renderers/expected/labelpnt.png differ diff --git a/msautotest/renderers/expected/labelpnt.svg b/msautotest/renderers/expected/labelpnt.svg index 634d379fc7..097dceec3c 100644 --- a/msautotest/renderers/expected/labelpnt.svg +++ b/msautotest/renderers/expected/labelpnt.svg @@ -1,15 +1,44 @@ - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msautotest/renderers/expected/labelrot.cairo.png b/msautotest/renderers/expected/labelrot.cairo.png index ec24202832..40711ad415 100644 Binary files a/msautotest/renderers/expected/labelrot.cairo.png and b/msautotest/renderers/expected/labelrot.cairo.png differ diff --git a/msautotest/renderers/expected/labelrot.pdf b/msautotest/renderers/expected/labelrot.pdf index c67ff03dea..fcdd5b3e94 100644 Binary files a/msautotest/renderers/expected/labelrot.pdf and b/msautotest/renderers/expected/labelrot.pdf differ diff --git a/msautotest/renderers/expected/labelrot.png b/msautotest/renderers/expected/labelrot.png index bbc80d32d9..a585b36ad2 100644 Binary files a/msautotest/renderers/expected/labelrot.png and b/msautotest/renderers/expected/labelrot.png differ diff --git a/msautotest/renderers/expected/labelrot.svg b/msautotest/renderers/expected/labelrot.svg index 5af15a0896..85a9d3c73f 100644 --- a/msautotest/renderers/expected/labelrot.svg +++ b/msautotest/renderers/expected/labelrot.svg @@ -1,14 +1,43 @@ - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msautotest/renderers/expected/labels-anno.cairo.png b/msautotest/renderers/expected/labels-anno.cairo.png index 6181dc295f..a1c26f3828 100644 Binary files a/msautotest/renderers/expected/labels-anno.cairo.png and b/msautotest/renderers/expected/labels-anno.cairo.png differ diff --git a/msautotest/renderers/expected/labels-anno.pdf b/msautotest/renderers/expected/labels-anno.pdf index 151240abaa..8c7f279973 100644 Binary files a/msautotest/renderers/expected/labels-anno.pdf and b/msautotest/renderers/expected/labels-anno.pdf differ diff --git a/msautotest/renderers/expected/labels-anno.png b/msautotest/renderers/expected/labels-anno.png index 2826a19b4c..c795b80c62 100644 Binary files a/msautotest/renderers/expected/labels-anno.png and b/msautotest/renderers/expected/labels-anno.png differ diff --git a/msautotest/renderers/expected/labels-anno.svg b/msautotest/renderers/expected/labels-anno.svg index 124562664a..ad2ea89e11 100644 --- a/msautotest/renderers/expected/labels-anno.svg +++ b/msautotest/renderers/expected/labels-anno.svg @@ -1,60 +1,89 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msautotest/renderers/expected/labels-bitmap-multiline.png b/msautotest/renderers/expected/labels-bitmap-multiline.png index 2c46fc3d12..f35137bef8 100644 Binary files a/msautotest/renderers/expected/labels-bitmap-multiline.png and b/msautotest/renderers/expected/labels-bitmap-multiline.png differ diff --git a/msautotest/renderers/expected/labels-bitmap.png b/msautotest/renderers/expected/labels-bitmap.png index 594a65e41b..470e82cb39 100644 Binary files a/msautotest/renderers/expected/labels-bitmap.png and b/msautotest/renderers/expected/labels-bitmap.png differ diff --git a/msautotest/renderers/expected/labels-leader.cairo.png b/msautotest/renderers/expected/labels-leader.cairo.png index 39b40cd3eb..7c9b84af3b 100644 Binary files a/msautotest/renderers/expected/labels-leader.cairo.png and b/msautotest/renderers/expected/labels-leader.cairo.png differ diff --git a/msautotest/renderers/expected/labels-leader.pdf b/msautotest/renderers/expected/labels-leader.pdf index 222560e02c..04fef7f59b 100644 Binary files a/msautotest/renderers/expected/labels-leader.pdf and b/msautotest/renderers/expected/labels-leader.pdf differ diff --git a/msautotest/renderers/expected/labels-leader.png b/msautotest/renderers/expected/labels-leader.png index 66fe36ff73..5981d5d2f4 100644 Binary files a/msautotest/renderers/expected/labels-leader.png and b/msautotest/renderers/expected/labels-leader.png differ diff --git a/msautotest/renderers/expected/labels-leader.svg b/msautotest/renderers/expected/labels-leader.svg index 418478eb26..9f3f53fb94 100644 --- a/msautotest/renderers/expected/labels-leader.svg +++ b/msautotest/renderers/expected/labels-leader.svg @@ -1,61 +1,90 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msautotest/renderers/expected/labels-min-distance.cairo.png b/msautotest/renderers/expected/labels-min-distance.cairo.png index 626cfda480..c929b8881f 100644 Binary files a/msautotest/renderers/expected/labels-min-distance.cairo.png and b/msautotest/renderers/expected/labels-min-distance.cairo.png differ diff --git a/msautotest/renderers/expected/labels-min-distance.pdf b/msautotest/renderers/expected/labels-min-distance.pdf index 5a761f84d1..370f5c9d3d 100644 Binary files a/msautotest/renderers/expected/labels-min-distance.pdf and b/msautotest/renderers/expected/labels-min-distance.pdf differ diff --git a/msautotest/renderers/expected/labels-min-distance.png b/msautotest/renderers/expected/labels-min-distance.png index a6e582a45c..c34eee4df5 100644 Binary files a/msautotest/renderers/expected/labels-min-distance.png and b/msautotest/renderers/expected/labels-min-distance.png differ diff --git a/msautotest/renderers/expected/labels-min-distance.svg b/msautotest/renderers/expected/labels-min-distance.svg index 0bde9155f1..ccedc63472 100644 --- a/msautotest/renderers/expected/labels-min-distance.svg +++ b/msautotest/renderers/expected/labels-min-distance.svg @@ -1,123 +1,152 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msautotest/renderers/expected/labels-wrap.png b/msautotest/renderers/expected/labels-wrap.png index 184beed235..0ebe5c00a2 100644 Binary files a/msautotest/renderers/expected/labels-wrap.png and b/msautotest/renderers/expected/labels-wrap.png differ diff --git a/msautotest/renderers/expected/labels.cairo.png b/msautotest/renderers/expected/labels.cairo.png index bab27521c7..97def7805a 100644 Binary files a/msautotest/renderers/expected/labels.cairo.png and b/msautotest/renderers/expected/labels.cairo.png differ diff --git a/msautotest/renderers/expected/labels.pdf b/msautotest/renderers/expected/labels.pdf index 54d86a12f1..578ecc86ff 100644 Binary files a/msautotest/renderers/expected/labels.pdf and b/msautotest/renderers/expected/labels.pdf differ diff --git a/msautotest/renderers/expected/labels.png b/msautotest/renderers/expected/labels.png index ec73689e43..8257061c3e 100644 Binary files a/msautotest/renderers/expected/labels.png and b/msautotest/renderers/expected/labels.png differ diff --git a/msautotest/renderers/expected/labels.svg b/msautotest/renderers/expected/labels.svg index a7231e4fdf..5e6ab2e735 100644 --- a/msautotest/renderers/expected/labels.svg +++ b/msautotest/renderers/expected/labels.svg @@ -1,56 +1,85 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msautotest/renderers/expected/legend.cairo.png b/msautotest/renderers/expected/legend.cairo.png index 07b5e59a2d..7234715416 100644 Binary files a/msautotest/renderers/expected/legend.cairo.png and b/msautotest/renderers/expected/legend.cairo.png differ diff --git a/msautotest/renderers/expected/legend.pdf b/msautotest/renderers/expected/legend.pdf index 517667e8fd..1e2bdbe86b 100644 Binary files a/msautotest/renderers/expected/legend.pdf and b/msautotest/renderers/expected/legend.pdf differ diff --git a/msautotest/renderers/expected/legend.svg b/msautotest/renderers/expected/legend.svg index 1a21bac8ff..126292c66e 100644 --- a/msautotest/renderers/expected/legend.svg +++ b/msautotest/renderers/expected/legend.svg @@ -1,41 +1,70 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msautotest/renderers/expected/legend_bad_imagetype.txt b/msautotest/renderers/expected/legend_bad_imagetype.txt new file mode 100644 index 0000000000..ffca27d8b8 --- /dev/null +++ b/msautotest/renderers/expected/legend_bad_imagetype.txt @@ -0,0 +1,8 @@ +Content-Type: text/html + + +MapServer Message + +msCGILoadForm(): Web application error. Invalid imagetype value. + + \ No newline at end of file diff --git a/msautotest/renderers/expected/legend_label_offset.cairo.png b/msautotest/renderers/expected/legend_label_offset.cairo.png index bb66be13b2..8bf75894f5 100644 Binary files a/msautotest/renderers/expected/legend_label_offset.cairo.png and b/msautotest/renderers/expected/legend_label_offset.cairo.png differ diff --git a/msautotest/renderers/expected/legend_label_offset.pdf b/msautotest/renderers/expected/legend_label_offset.pdf index 7efe8b3a8c..47b8e89d73 100644 Binary files a/msautotest/renderers/expected/legend_label_offset.pdf and b/msautotest/renderers/expected/legend_label_offset.pdf differ diff --git a/msautotest/renderers/expected/legend_label_offset.svg b/msautotest/renderers/expected/legend_label_offset.svg index f3ff83788f..5ebb4e2066 100644 --- a/msautotest/renderers/expected/legend_label_offset.svg +++ b/msautotest/renderers/expected/legend_label_offset.svg @@ -1,41 +1,70 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msautotest/renderers/expected/legend_sizeunits_meters.cairo.png b/msautotest/renderers/expected/legend_sizeunits_meters.cairo.png index c04b9ab4fe..7234715416 100644 Binary files a/msautotest/renderers/expected/legend_sizeunits_meters.cairo.png and b/msautotest/renderers/expected/legend_sizeunits_meters.cairo.png differ diff --git a/msautotest/renderers/expected/legend_sizeunits_meters.pdf b/msautotest/renderers/expected/legend_sizeunits_meters.pdf index 715d141cce..1e2bdbe86b 100644 Binary files a/msautotest/renderers/expected/legend_sizeunits_meters.pdf and b/msautotest/renderers/expected/legend_sizeunits_meters.pdf differ diff --git a/msautotest/renderers/expected/legend_sizeunits_meters.png b/msautotest/renderers/expected/legend_sizeunits_meters.png index 4e32ab4e06..336c7558b0 100644 Binary files a/msautotest/renderers/expected/legend_sizeunits_meters.png and b/msautotest/renderers/expected/legend_sizeunits_meters.png differ diff --git a/msautotest/renderers/expected/legend_sizeunits_meters.svg b/msautotest/renderers/expected/legend_sizeunits_meters.svg index 9d7b9e64c9..126292c66e 100644 --- a/msautotest/renderers/expected/legend_sizeunits_meters.svg +++ b/msautotest/renderers/expected/legend_sizeunits_meters.svg @@ -1,41 +1,70 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msautotest/renderers/expected/line_aliased.png b/msautotest/renderers/expected/line_aliased.png new file mode 100644 index 0000000000..62417749d0 Binary files /dev/null and b/msautotest/renderers/expected/line_aliased.png differ diff --git a/msautotest/renderers/expected/line_anchorpoint.cairo.png b/msautotest/renderers/expected/line_anchorpoint.cairo.png index c11125b98a..3d3ebf7fd3 100644 Binary files a/msautotest/renderers/expected/line_anchorpoint.cairo.png and b/msautotest/renderers/expected/line_anchorpoint.cairo.png differ diff --git a/msautotest/renderers/expected/line_anti_aliased.png b/msautotest/renderers/expected/line_anti_aliased.png new file mode 100644 index 0000000000..c13a8cff9e Binary files /dev/null and b/msautotest/renderers/expected/line_anti_aliased.png differ diff --git a/msautotest/renderers/expected/line_label_auto.cairo.png b/msautotest/renderers/expected/line_label_auto.cairo.png index e04a075590..7016dc57e5 100644 Binary files a/msautotest/renderers/expected/line_label_auto.cairo.png and b/msautotest/renderers/expected/line_label_auto.cairo.png differ diff --git a/msautotest/renderers/expected/line_label_auto.pdf b/msautotest/renderers/expected/line_label_auto.pdf index 597a6a4fc7..66d9aa580b 100644 Binary files a/msautotest/renderers/expected/line_label_auto.pdf and b/msautotest/renderers/expected/line_label_auto.pdf differ diff --git a/msautotest/renderers/expected/line_label_auto.svg b/msautotest/renderers/expected/line_label_auto.svg index d9765b21c7..f75c709d4d 100644 --- a/msautotest/renderers/expected/line_label_auto.svg +++ b/msautotest/renderers/expected/line_label_auto.svg @@ -1,18 +1,47 @@ - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msautotest/renderers/expected/line_label_auto2.cairo.png b/msautotest/renderers/expected/line_label_auto2.cairo.png index c29ab7e3fd..9d8e0b5aa5 100644 Binary files a/msautotest/renderers/expected/line_label_auto2.cairo.png and b/msautotest/renderers/expected/line_label_auto2.cairo.png differ diff --git a/msautotest/renderers/expected/line_label_auto2.pdf b/msautotest/renderers/expected/line_label_auto2.pdf index 3ac5f01e26..6c9937129e 100644 Binary files a/msautotest/renderers/expected/line_label_auto2.pdf and b/msautotest/renderers/expected/line_label_auto2.pdf differ diff --git a/msautotest/renderers/expected/line_label_auto2.svg b/msautotest/renderers/expected/line_label_auto2.svg index cec6948aa4..9b055ed182 100644 --- a/msautotest/renderers/expected/line_label_auto2.svg +++ b/msautotest/renderers/expected/line_label_auto2.svg @@ -1,66 +1,95 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msautotest/renderers/expected/line_label_follow.cairo.png b/msautotest/renderers/expected/line_label_follow.cairo.png index 7b2022bc45..cd6e821eb4 100644 Binary files a/msautotest/renderers/expected/line_label_follow.cairo.png and b/msautotest/renderers/expected/line_label_follow.cairo.png differ diff --git a/msautotest/renderers/expected/line_label_follow.pdf b/msautotest/renderers/expected/line_label_follow.pdf index beaef47e1b..d3f5093669 100644 Binary files a/msautotest/renderers/expected/line_label_follow.pdf and b/msautotest/renderers/expected/line_label_follow.pdf differ diff --git a/msautotest/renderers/expected/line_label_follow.svg b/msautotest/renderers/expected/line_label_follow.svg index c60764f59c..f1d0074603 100644 --- a/msautotest/renderers/expected/line_label_follow.svg +++ b/msautotest/renderers/expected/line_label_follow.svg @@ -1,30 +1,59 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msautotest/renderers/expected/line_label_follow_offsetted.cairo.png b/msautotest/renderers/expected/line_label_follow_offsetted.cairo.png index 7d1c8d1643..cc21ea42c3 100644 Binary files a/msautotest/renderers/expected/line_label_follow_offsetted.cairo.png and b/msautotest/renderers/expected/line_label_follow_offsetted.cairo.png differ diff --git a/msautotest/renderers/expected/line_label_follow_offsetted.pdf b/msautotest/renderers/expected/line_label_follow_offsetted.pdf index b7a3096a1e..fca01d3a58 100644 Binary files a/msautotest/renderers/expected/line_label_follow_offsetted.pdf and b/msautotest/renderers/expected/line_label_follow_offsetted.pdf differ diff --git a/msautotest/renderers/expected/line_label_follow_offsetted.svg b/msautotest/renderers/expected/line_label_follow_offsetted.svg index 003e4149b0..29a9d42296 100644 --- a/msautotest/renderers/expected/line_label_follow_offsetted.svg +++ b/msautotest/renderers/expected/line_label_follow_offsetted.svg @@ -1,16 +1,45 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msautotest/renderers/expected/line_label_follow_retry.cairo.png b/msautotest/renderers/expected/line_label_follow_retry.cairo.png index ccdac08500..5f5192e873 100644 Binary files a/msautotest/renderers/expected/line_label_follow_retry.cairo.png and b/msautotest/renderers/expected/line_label_follow_retry.cairo.png differ diff --git a/msautotest/renderers/expected/line_label_follow_retry.pdf b/msautotest/renderers/expected/line_label_follow_retry.pdf index 031235d6a2..5aa387e163 100644 Binary files a/msautotest/renderers/expected/line_label_follow_retry.pdf and b/msautotest/renderers/expected/line_label_follow_retry.pdf differ diff --git a/msautotest/renderers/expected/line_label_follow_retry.svg b/msautotest/renderers/expected/line_label_follow_retry.svg index bf0c20d4d4..874e47bae9 100644 --- a/msautotest/renderers/expected/line_label_follow_retry.svg +++ b/msautotest/renderers/expected/line_label_follow_retry.svg @@ -1,76 +1,105 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msautotest/renderers/expected/line_marker_pixmap.cairo.png b/msautotest/renderers/expected/line_marker_pixmap.cairo.png index 51eaf3f5c0..47ec28dd50 100644 Binary files a/msautotest/renderers/expected/line_marker_pixmap.cairo.png and b/msautotest/renderers/expected/line_marker_pixmap.cairo.png differ diff --git a/msautotest/renderers/expected/line_marker_pixmap.pdf b/msautotest/renderers/expected/line_marker_pixmap.pdf index 051dc3c478..7a1a444bb5 100644 Binary files a/msautotest/renderers/expected/line_marker_pixmap.pdf and b/msautotest/renderers/expected/line_marker_pixmap.pdf differ diff --git a/msautotest/renderers/expected/line_marker_pixmap.svg b/msautotest/renderers/expected/line_marker_pixmap.svg index fa986516a2..852afa2b72 100644 --- a/msautotest/renderers/expected/line_marker_pixmap.svg +++ b/msautotest/renderers/expected/line_marker_pixmap.svg @@ -1,30 +1,57 @@ - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msautotest/renderers/expected/line_marker_svg.cairo.png b/msautotest/renderers/expected/line_marker_svg.cairo.png index cb5dd9cb12..740d1f8f66 100644 Binary files a/msautotest/renderers/expected/line_marker_svg.cairo.png and b/msautotest/renderers/expected/line_marker_svg.cairo.png differ diff --git a/msautotest/renderers/expected/line_marker_svg.pdf b/msautotest/renderers/expected/line_marker_svg.pdf index 32704998df..4a2e59f262 100644 Binary files a/msautotest/renderers/expected/line_marker_svg.pdf and b/msautotest/renderers/expected/line_marker_svg.pdf differ diff --git a/msautotest/renderers/expected/line_marker_svg.png b/msautotest/renderers/expected/line_marker_svg.png index c608e7818f..702c060fb6 100644 Binary files a/msautotest/renderers/expected/line_marker_svg.png and b/msautotest/renderers/expected/line_marker_svg.png differ diff --git a/msautotest/renderers/expected/line_marker_svg.svg b/msautotest/renderers/expected/line_marker_svg.svg index f6f297b0c1..9a6c39a201 100644 --- a/msautotest/renderers/expected/line_marker_svg.svg +++ b/msautotest/renderers/expected/line_marker_svg.svg @@ -1,315 +1,344 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msautotest/renderers/expected/line_marker_truetype.cairo.png b/msautotest/renderers/expected/line_marker_truetype.cairo.png index c0aad94008..090e918b14 100644 Binary files a/msautotest/renderers/expected/line_marker_truetype.cairo.png and b/msautotest/renderers/expected/line_marker_truetype.cairo.png differ diff --git a/msautotest/renderers/expected/line_marker_truetype.pdf b/msautotest/renderers/expected/line_marker_truetype.pdf index bc6a0eaf6d..5f1de131cd 100644 Binary files a/msautotest/renderers/expected/line_marker_truetype.pdf and b/msautotest/renderers/expected/line_marker_truetype.pdf differ diff --git a/msautotest/renderers/expected/line_marker_truetype.svg b/msautotest/renderers/expected/line_marker_truetype.svg index 90db8894c3..9c0b1d696d 100644 --- a/msautotest/renderers/expected/line_marker_truetype.svg +++ b/msautotest/renderers/expected/line_marker_truetype.svg @@ -1,96 +1,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msautotest/renderers/expected/line_marker_vector.cairo.png b/msautotest/renderers/expected/line_marker_vector.cairo.png index 3758dc6238..09b186a4e9 100644 Binary files a/msautotest/renderers/expected/line_marker_vector.cairo.png and b/msautotest/renderers/expected/line_marker_vector.cairo.png differ diff --git a/msautotest/renderers/expected/line_marker_vector.pdf b/msautotest/renderers/expected/line_marker_vector.pdf index 2ebfb57463..00614e305e 100644 Binary files a/msautotest/renderers/expected/line_marker_vector.pdf and b/msautotest/renderers/expected/line_marker_vector.pdf differ diff --git a/msautotest/renderers/expected/line_marker_vector.svg b/msautotest/renderers/expected/line_marker_vector.svg index 26abd6f03b..b42fe20c16 100644 --- a/msautotest/renderers/expected/line_marker_vector.svg +++ b/msautotest/renderers/expected/line_marker_vector.svg @@ -1,96 +1,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msautotest/renderers/expected/line_offset.cairo.png b/msautotest/renderers/expected/line_offset.cairo.png index b579bf0251..42d3d9bc14 100644 Binary files a/msautotest/renderers/expected/line_offset.cairo.png and b/msautotest/renderers/expected/line_offset.cairo.png differ diff --git a/msautotest/renderers/expected/line_offset.pdf b/msautotest/renderers/expected/line_offset.pdf index a61306390f..dd357867c2 100644 Binary files a/msautotest/renderers/expected/line_offset.pdf and b/msautotest/renderers/expected/line_offset.pdf differ diff --git a/msautotest/renderers/expected/line_offset.svg b/msautotest/renderers/expected/line_offset.svg index 3160318f19..0e08be6e5c 100644 --- a/msautotest/renderers/expected/line_offset.svg +++ b/msautotest/renderers/expected/line_offset.svg @@ -1,20 +1,49 @@ - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msautotest/renderers/expected/line_pattern.cairo.png b/msautotest/renderers/expected/line_pattern.cairo.png index 15a93e6aee..19d4dd9a22 100644 Binary files a/msautotest/renderers/expected/line_pattern.cairo.png and b/msautotest/renderers/expected/line_pattern.cairo.png differ diff --git a/msautotest/renderers/expected/line_pattern.pdf b/msautotest/renderers/expected/line_pattern.pdf index fbe6079e7a..da00cdf934 100644 Binary files a/msautotest/renderers/expected/line_pattern.pdf and b/msautotest/renderers/expected/line_pattern.pdf differ diff --git a/msautotest/renderers/expected/line_pattern.svg b/msautotest/renderers/expected/line_pattern.svg index 40ff6fde9b..4fb0dc63fd 100644 --- a/msautotest/renderers/expected/line_pattern.svg +++ b/msautotest/renderers/expected/line_pattern.svg @@ -1,9 +1,38 @@ - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msautotest/renderers/expected/line_pattern_offset.cairo.png b/msautotest/renderers/expected/line_pattern_offset.cairo.png index 099718ea1c..457b8d1479 100644 Binary files a/msautotest/renderers/expected/line_pattern_offset.cairo.png and b/msautotest/renderers/expected/line_pattern_offset.cairo.png differ diff --git a/msautotest/renderers/expected/line_pattern_offset.pdf b/msautotest/renderers/expected/line_pattern_offset.pdf index ddc9d2e5a5..44fa4e12df 100644 Binary files a/msautotest/renderers/expected/line_pattern_offset.pdf and b/msautotest/renderers/expected/line_pattern_offset.pdf differ diff --git a/msautotest/renderers/expected/line_pattern_offset.svg b/msautotest/renderers/expected/line_pattern_offset.svg index fa3819bfef..ac50a0575f 100644 --- a/msautotest/renderers/expected/line_pattern_offset.svg +++ b/msautotest/renderers/expected/line_pattern_offset.svg @@ -1,14 +1,43 @@ - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msautotest/renderers/expected/line_short_gap.cairo.png b/msautotest/renderers/expected/line_short_gap.cairo.png index e60f8697e8..7295e0b1b7 100644 Binary files a/msautotest/renderers/expected/line_short_gap.cairo.png and b/msautotest/renderers/expected/line_short_gap.cairo.png differ diff --git a/msautotest/renderers/expected/line_short_gap.pdf b/msautotest/renderers/expected/line_short_gap.pdf index 28db0e0576..569abb5441 100644 Binary files a/msautotest/renderers/expected/line_short_gap.pdf and b/msautotest/renderers/expected/line_short_gap.pdf differ diff --git a/msautotest/renderers/expected/line_short_gap.svg b/msautotest/renderers/expected/line_short_gap.svg index d3f8bcdc46..73f3ec481d 100644 --- a/msautotest/renderers/expected/line_short_gap.svg +++ b/msautotest/renderers/expected/line_short_gap.svg @@ -1,8 +1,37 @@ - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msautotest/renderers/expected/line_simple.cairo.jpg b/msautotest/renderers/expected/line_simple.cairo.jpg index e532dad47f..99df4ff2b0 100644 Binary files a/msautotest/renderers/expected/line_simple.cairo.jpg and b/msautotest/renderers/expected/line_simple.cairo.jpg differ diff --git a/msautotest/renderers/expected/line_simple.cairo.png b/msautotest/renderers/expected/line_simple.cairo.png index 374c8c8111..60ff158b1c 100644 Binary files a/msautotest/renderers/expected/line_simple.cairo.png and b/msautotest/renderers/expected/line_simple.cairo.png differ diff --git a/msautotest/renderers/expected/line_simple.pdf b/msautotest/renderers/expected/line_simple.pdf index 2c28e8e719..5c98356590 100644 Binary files a/msautotest/renderers/expected/line_simple.pdf and b/msautotest/renderers/expected/line_simple.pdf differ diff --git a/msautotest/renderers/expected/line_simple.svg b/msautotest/renderers/expected/line_simple.svg index c2b89acef5..82d8fe96d0 100644 --- a/msautotest/renderers/expected/line_simple.svg +++ b/msautotest/renderers/expected/line_simple.svg @@ -1,9 +1,38 @@ - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msautotest/renderers/expected/lots_of_text.cairo.png b/msautotest/renderers/expected/lots_of_text.cairo.png index b652c50e05..9b6b75710a 100644 Binary files a/msautotest/renderers/expected/lots_of_text.cairo.png and b/msautotest/renderers/expected/lots_of_text.cairo.png differ diff --git a/msautotest/renderers/expected/lots_of_text.png b/msautotest/renderers/expected/lots_of_text.png index 6de1cf5228..8a968f0fb0 100644 Binary files a/msautotest/renderers/expected/lots_of_text.png and b/msautotest/renderers/expected/lots_of_text.png differ diff --git a/msautotest/renderers/expected/marker_anchorpoint.cairo.png b/msautotest/renderers/expected/marker_anchorpoint.cairo.png index 4dbf55d53f..3ac61f2827 100644 Binary files a/msautotest/renderers/expected/marker_anchorpoint.cairo.png and b/msautotest/renderers/expected/marker_anchorpoint.cairo.png differ diff --git a/msautotest/renderers/expected/marker_anchorpoint.pdf b/msautotest/renderers/expected/marker_anchorpoint.pdf index a88c5840da..9d7b3d70a9 100644 Binary files a/msautotest/renderers/expected/marker_anchorpoint.pdf and b/msautotest/renderers/expected/marker_anchorpoint.pdf differ diff --git a/msautotest/renderers/expected/marker_anchorpoint.svg b/msautotest/renderers/expected/marker_anchorpoint.svg index 6f311f2b74..0a1dc2435a 100644 --- a/msautotest/renderers/expected/marker_anchorpoint.svg +++ b/msautotest/renderers/expected/marker_anchorpoint.svg @@ -1,123 +1,150 @@ - + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msautotest/renderers/expected/marker_pixmap.cairo.png b/msautotest/renderers/expected/marker_pixmap.cairo.png index 467fc161c2..a574a97111 100644 Binary files a/msautotest/renderers/expected/marker_pixmap.cairo.png and b/msautotest/renderers/expected/marker_pixmap.cairo.png differ diff --git a/msautotest/renderers/expected/marker_pixmap.pdf b/msautotest/renderers/expected/marker_pixmap.pdf index 2a223384a9..563d5d56f6 100644 Binary files a/msautotest/renderers/expected/marker_pixmap.pdf and b/msautotest/renderers/expected/marker_pixmap.pdf differ diff --git a/msautotest/renderers/expected/marker_pixmap.svg b/msautotest/renderers/expected/marker_pixmap.svg index 089e4a3fa2..d6e5266db2 100644 --- a/msautotest/renderers/expected/marker_pixmap.svg +++ b/msautotest/renderers/expected/marker_pixmap.svg @@ -1,13 +1,40 @@ - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - + + + + + + diff --git a/msautotest/renderers/expected/mask.cairo.png b/msautotest/renderers/expected/mask.cairo.png index 03e1c3d093..2572fa0d7c 100644 Binary files a/msautotest/renderers/expected/mask.cairo.png and b/msautotest/renderers/expected/mask.cairo.png differ diff --git a/msautotest/renderers/expected/mask_opacity.cairo.png b/msautotest/renderers/expected/mask_opacity.cairo.png index f9255a8d88..d62019ee11 100644 Binary files a/msautotest/renderers/expected/mask_opacity.cairo.png and b/msautotest/renderers/expected/mask_opacity.cairo.png differ diff --git a/msautotest/renderers/expected/multilabel-leader.cairo.png b/msautotest/renderers/expected/multilabel-leader.cairo.png index 70a5a694fa..ecb610da59 100644 Binary files a/msautotest/renderers/expected/multilabel-leader.cairo.png and b/msautotest/renderers/expected/multilabel-leader.cairo.png differ diff --git a/msautotest/renderers/expected/multilabel-leader.pdf b/msautotest/renderers/expected/multilabel-leader.pdf index e54d5dece7..a94fbda046 100644 Binary files a/msautotest/renderers/expected/multilabel-leader.pdf and b/msautotest/renderers/expected/multilabel-leader.pdf differ diff --git a/msautotest/renderers/expected/multilabel-leader.png b/msautotest/renderers/expected/multilabel-leader.png index f16cc9c872..e125f2ed72 100644 Binary files a/msautotest/renderers/expected/multilabel-leader.png and b/msautotest/renderers/expected/multilabel-leader.png differ diff --git a/msautotest/renderers/expected/multilabel-leader.svg b/msautotest/renderers/expected/multilabel-leader.svg index 87fa8020b4..d22ae4dd4b 100644 --- a/msautotest/renderers/expected/multilabel-leader.svg +++ b/msautotest/renderers/expected/multilabel-leader.svg @@ -1,376 +1,405 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msautotest/renderers/expected/multilabel.cairo.png b/msautotest/renderers/expected/multilabel.cairo.png index 4531887051..22ac35bff4 100644 Binary files a/msautotest/renderers/expected/multilabel.cairo.png and b/msautotest/renderers/expected/multilabel.cairo.png differ diff --git a/msautotest/renderers/expected/multilabel.pdf b/msautotest/renderers/expected/multilabel.pdf index ae8cdbc3e9..1236710baf 100644 Binary files a/msautotest/renderers/expected/multilabel.pdf and b/msautotest/renderers/expected/multilabel.pdf differ diff --git a/msautotest/renderers/expected/multilabel.png b/msautotest/renderers/expected/multilabel.png index dded62264f..a9ab139b82 100644 Binary files a/msautotest/renderers/expected/multilabel.png and b/msautotest/renderers/expected/multilabel.png differ diff --git a/msautotest/renderers/expected/multilabel.svg b/msautotest/renderers/expected/multilabel.svg index 8570d74d31..e3eac38e6a 100644 --- a/msautotest/renderers/expected/multilabel.svg +++ b/msautotest/renderers/expected/multilabel.svg @@ -1,22 +1,51 @@ - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msautotest/renderers/expected/nodata_8bit.pdf b/msautotest/renderers/expected/nodata_8bit.pdf index d0539615cb..270017cf1c 100644 Binary files a/msautotest/renderers/expected/nodata_8bit.pdf and b/msautotest/renderers/expected/nodata_8bit.pdf differ diff --git a/msautotest/renderers/expected/nodata_8bit.svg b/msautotest/renderers/expected/nodata_8bit.svg index 835d9bce74..2992bf8ee0 100644 --- a/msautotest/renderers/expected/nodata_8bit.svg +++ b/msautotest/renderers/expected/nodata_8bit.svg @@ -1,10 +1,37 @@ - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + diff --git a/msautotest/renderers/expected/outlines1.png b/msautotest/renderers/expected/outlines1.png new file mode 100644 index 0000000000..bb37a7e485 Binary files /dev/null and b/msautotest/renderers/expected/outlines1.png differ diff --git a/msautotest/renderers/expected/outlines2.png b/msautotest/renderers/expected/outlines2.png new file mode 100644 index 0000000000..bb37a7e485 Binary files /dev/null and b/msautotest/renderers/expected/outlines2.png differ diff --git a/msautotest/renderers/expected/outlines3.png b/msautotest/renderers/expected/outlines3.png new file mode 100644 index 0000000000..bb37a7e485 Binary files /dev/null and b/msautotest/renderers/expected/outlines3.png differ diff --git a/msautotest/renderers/expected/outlines4.png b/msautotest/renderers/expected/outlines4.png new file mode 100644 index 0000000000..bb37a7e485 Binary files /dev/null and b/msautotest/renderers/expected/outlines4.png differ diff --git a/msautotest/renderers/expected/outlines5.png b/msautotest/renderers/expected/outlines5.png new file mode 100644 index 0000000000..b3b8f34796 Binary files /dev/null and b/msautotest/renderers/expected/outlines5.png differ diff --git a/msautotest/renderers/expected/outlines6.png b/msautotest/renderers/expected/outlines6.png new file mode 100644 index 0000000000..da42f622a8 Binary files /dev/null and b/msautotest/renderers/expected/outlines6.png differ diff --git a/msautotest/renderers/expected/plb_embed_legend.cairo.png b/msautotest/renderers/expected/plb_embed_legend.cairo.png index deb82fe979..88d778d882 100644 Binary files a/msautotest/renderers/expected/plb_embed_legend.cairo.png and b/msautotest/renderers/expected/plb_embed_legend.cairo.png differ diff --git a/msautotest/renderers/expected/plb_embed_legend_rgba.cairo.png b/msautotest/renderers/expected/plb_embed_legend_rgba.cairo.png index b6a6a2b72c..0fdd9e0cdb 100644 Binary files a/msautotest/renderers/expected/plb_embed_legend_rgba.cairo.png and b/msautotest/renderers/expected/plb_embed_legend_rgba.cairo.png differ diff --git a/msautotest/renderers/expected/plb_embed_legend_rgba_tr.cairo.png b/msautotest/renderers/expected/plb_embed_legend_rgba_tr.cairo.png index b6a6a2b72c..0fdd9e0cdb 100644 Binary files a/msautotest/renderers/expected/plb_embed_legend_rgba_tr.cairo.png and b/msautotest/renderers/expected/plb_embed_legend_rgba_tr.cairo.png differ diff --git a/msautotest/renderers/expected/plb_embed_legend_tr.cairo.png b/msautotest/renderers/expected/plb_embed_legend_tr.cairo.png index d0a18ebca4..cf769a9979 100644 Binary files a/msautotest/renderers/expected/plb_embed_legend_tr.cairo.png and b/msautotest/renderers/expected/plb_embed_legend_tr.cairo.png differ diff --git a/msautotest/renderers/expected/point-polaroffset.cairo.png b/msautotest/renderers/expected/point-polaroffset.cairo.png index 3ed7f80c71..738f6f2b17 100644 Binary files a/msautotest/renderers/expected/point-polaroffset.cairo.png and b/msautotest/renderers/expected/point-polaroffset.cairo.png differ diff --git a/msautotest/renderers/expected/point-polaroffset.pdf b/msautotest/renderers/expected/point-polaroffset.pdf index 1056a02d47..9fb44f3680 100644 Binary files a/msautotest/renderers/expected/point-polaroffset.pdf and b/msautotest/renderers/expected/point-polaroffset.pdf differ diff --git a/msautotest/renderers/expected/point-polaroffset.svg b/msautotest/renderers/expected/point-polaroffset.svg index a2a66f17c3..29642000d7 100644 --- a/msautotest/renderers/expected/point-polaroffset.svg +++ b/msautotest/renderers/expected/point-polaroffset.svg @@ -1,18 +1,47 @@ - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msautotest/renderers/expected/point_ellipse.cairo.png b/msautotest/renderers/expected/point_ellipse.cairo.png index b3f5fc3c9f..aa6d70f99a 100644 Binary files a/msautotest/renderers/expected/point_ellipse.cairo.png and b/msautotest/renderers/expected/point_ellipse.cairo.png differ diff --git a/msautotest/renderers/expected/point_ellipse.pdf b/msautotest/renderers/expected/point_ellipse.pdf index ff57300ee0..16a35be099 100644 Binary files a/msautotest/renderers/expected/point_ellipse.pdf and b/msautotest/renderers/expected/point_ellipse.pdf differ diff --git a/msautotest/renderers/expected/point_ellipse.svg b/msautotest/renderers/expected/point_ellipse.svg index 74e5b7bf80..1559c4653c 100644 --- a/msautotest/renderers/expected/point_ellipse.svg +++ b/msautotest/renderers/expected/point_ellipse.svg @@ -1,10 +1,39 @@ - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msautotest/renderers/expected/point_pixmap.cairo.png b/msautotest/renderers/expected/point_pixmap.cairo.png index 7939c23f21..9da8ea9955 100644 Binary files a/msautotest/renderers/expected/point_pixmap.cairo.png and b/msautotest/renderers/expected/point_pixmap.cairo.png differ diff --git a/msautotest/renderers/expected/point_pixmap.pdf b/msautotest/renderers/expected/point_pixmap.pdf index 647b10b454..495c6d76f0 100644 Binary files a/msautotest/renderers/expected/point_pixmap.pdf and b/msautotest/renderers/expected/point_pixmap.pdf differ diff --git a/msautotest/renderers/expected/point_pixmap.svg b/msautotest/renderers/expected/point_pixmap.svg index fc7e41bc45..ac89074d2d 100644 --- a/msautotest/renderers/expected/point_pixmap.svg +++ b/msautotest/renderers/expected/point_pixmap.svg @@ -1,17 +1,44 @@ - + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - + + + + + + + + diff --git a/msautotest/renderers/expected/point_pixmap_gif.cairo.png b/msautotest/renderers/expected/point_pixmap_gif.cairo.png index 551f9cf167..2edf373141 100644 Binary files a/msautotest/renderers/expected/point_pixmap_gif.cairo.png and b/msautotest/renderers/expected/point_pixmap_gif.cairo.png differ diff --git a/msautotest/renderers/expected/point_pixmap_gif.pdf b/msautotest/renderers/expected/point_pixmap_gif.pdf index 5f979226cb..592eb38a1e 100644 Binary files a/msautotest/renderers/expected/point_pixmap_gif.pdf and b/msautotest/renderers/expected/point_pixmap_gif.pdf differ diff --git a/msautotest/renderers/expected/point_pixmap_gif.svg b/msautotest/renderers/expected/point_pixmap_gif.svg index a8846763a5..16683e1ce6 100644 --- a/msautotest/renderers/expected/point_pixmap_gif.svg +++ b/msautotest/renderers/expected/point_pixmap_gif.svg @@ -1,14 +1,41 @@ - + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - + + + + + + diff --git a/msautotest/renderers/expected/point_svg.cairo.png b/msautotest/renderers/expected/point_svg.cairo.png index b15b015613..a613030aef 100644 Binary files a/msautotest/renderers/expected/point_svg.cairo.png and b/msautotest/renderers/expected/point_svg.cairo.png differ diff --git a/msautotest/renderers/expected/point_svg.pdf b/msautotest/renderers/expected/point_svg.pdf index a111855d41..684bf85071 100644 Binary files a/msautotest/renderers/expected/point_svg.pdf and b/msautotest/renderers/expected/point_svg.pdf differ diff --git a/msautotest/renderers/expected/point_svg.png b/msautotest/renderers/expected/point_svg.png index e3499cec24..2cf8819263 100644 Binary files a/msautotest/renderers/expected/point_svg.png and b/msautotest/renderers/expected/point_svg.png differ diff --git a/msautotest/renderers/expected/point_svg.svg b/msautotest/renderers/expected/point_svg.svg index af57315dcb..6eab0bf870 100644 --- a/msautotest/renderers/expected/point_svg.svg +++ b/msautotest/renderers/expected/point_svg.svg @@ -1,16 +1,49 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msautotest/renderers/expected/point_truetype.cairo.png b/msautotest/renderers/expected/point_truetype.cairo.png index 6b769fbe71..543704a55f 100644 Binary files a/msautotest/renderers/expected/point_truetype.cairo.png and b/msautotest/renderers/expected/point_truetype.cairo.png differ diff --git a/msautotest/renderers/expected/point_truetype.pdf b/msautotest/renderers/expected/point_truetype.pdf index 4c27e1ac4f..26e9e11426 100644 Binary files a/msautotest/renderers/expected/point_truetype.pdf and b/msautotest/renderers/expected/point_truetype.pdf differ diff --git a/msautotest/renderers/expected/point_truetype.svg b/msautotest/renderers/expected/point_truetype.svg index 17c1347cbb..868c936348 100644 --- a/msautotest/renderers/expected/point_truetype.svg +++ b/msautotest/renderers/expected/point_truetype.svg @@ -1,10 +1,39 @@ - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msautotest/renderers/expected/point_vector.cairo.png b/msautotest/renderers/expected/point_vector.cairo.png index 769451773f..bad8d153a7 100644 Binary files a/msautotest/renderers/expected/point_vector.cairo.png and b/msautotest/renderers/expected/point_vector.cairo.png differ diff --git a/msautotest/renderers/expected/point_vector.pdf b/msautotest/renderers/expected/point_vector.pdf index 3b5b07da21..e901968db6 100644 Binary files a/msautotest/renderers/expected/point_vector.pdf and b/msautotest/renderers/expected/point_vector.pdf differ diff --git a/msautotest/renderers/expected/point_vector.svg b/msautotest/renderers/expected/point_vector.svg index d9887b23ad..2c7ce15879 100644 --- a/msautotest/renderers/expected/point_vector.svg +++ b/msautotest/renderers/expected/point_vector.svg @@ -1,10 +1,39 @@ - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msautotest/renderers/expected/poly-label-multiline-pos-auto.cairo.png b/msautotest/renderers/expected/poly-label-multiline-pos-auto.cairo.png index 5c4f2c71fc..efe3eefbc1 100644 Binary files a/msautotest/renderers/expected/poly-label-multiline-pos-auto.cairo.png and b/msautotest/renderers/expected/poly-label-multiline-pos-auto.cairo.png differ diff --git a/msautotest/renderers/expected/poly-label-multiline-pos-auto.pdf b/msautotest/renderers/expected/poly-label-multiline-pos-auto.pdf index e58768ca48..9f439b1932 100644 Binary files a/msautotest/renderers/expected/poly-label-multiline-pos-auto.pdf and b/msautotest/renderers/expected/poly-label-multiline-pos-auto.pdf differ diff --git a/msautotest/renderers/expected/poly-label-multiline-pos-auto.png b/msautotest/renderers/expected/poly-label-multiline-pos-auto.png index 513e9ef48b..4f998804cc 100644 Binary files a/msautotest/renderers/expected/poly-label-multiline-pos-auto.png and b/msautotest/renderers/expected/poly-label-multiline-pos-auto.png differ diff --git a/msautotest/renderers/expected/poly-label-multiline-pos-auto.svg b/msautotest/renderers/expected/poly-label-multiline-pos-auto.svg index e82abe6cf7..591188768f 100644 --- a/msautotest/renderers/expected/poly-label-multiline-pos-auto.svg +++ b/msautotest/renderers/expected/poly-label-multiline-pos-auto.svg @@ -1,42 +1,71 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msautotest/renderers/expected/poly-label-pos-auto.cairo.png b/msautotest/renderers/expected/poly-label-pos-auto.cairo.png index 5d9f4006c0..50d4d378b3 100644 Binary files a/msautotest/renderers/expected/poly-label-pos-auto.cairo.png and b/msautotest/renderers/expected/poly-label-pos-auto.cairo.png differ diff --git a/msautotest/renderers/expected/poly-label-pos-auto.pdf b/msautotest/renderers/expected/poly-label-pos-auto.pdf index f3f914772b..78f5a72a1a 100644 Binary files a/msautotest/renderers/expected/poly-label-pos-auto.pdf and b/msautotest/renderers/expected/poly-label-pos-auto.pdf differ diff --git a/msautotest/renderers/expected/poly-label-pos-auto.png b/msautotest/renderers/expected/poly-label-pos-auto.png index f472946610..4301c3f249 100644 Binary files a/msautotest/renderers/expected/poly-label-pos-auto.png and b/msautotest/renderers/expected/poly-label-pos-auto.png differ diff --git a/msautotest/renderers/expected/poly-label-pos-auto.svg b/msautotest/renderers/expected/poly-label-pos-auto.svg index 2b86e05a72..88c8d939cb 100644 --- a/msautotest/renderers/expected/poly-label-pos-auto.svg +++ b/msautotest/renderers/expected/poly-label-pos-auto.svg @@ -1,42 +1,71 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msautotest/renderers/expected/poly_geomtransform_anchor.cairo.png b/msautotest/renderers/expected/poly_geomtransform_anchor.cairo.png index f12d929791..bbdc0e5447 100644 Binary files a/msautotest/renderers/expected/poly_geomtransform_anchor.cairo.png and b/msautotest/renderers/expected/poly_geomtransform_anchor.cairo.png differ diff --git a/msautotest/renderers/expected/poly_geomtransform_anchor.pdf b/msautotest/renderers/expected/poly_geomtransform_anchor.pdf index cdfd7b848a..7997755407 100644 Binary files a/msautotest/renderers/expected/poly_geomtransform_anchor.pdf and b/msautotest/renderers/expected/poly_geomtransform_anchor.pdf differ diff --git a/msautotest/renderers/expected/poly_geomtransform_anchor.svg b/msautotest/renderers/expected/poly_geomtransform_anchor.svg index c823cc818d..63395c21bb 100644 --- a/msautotest/renderers/expected/poly_geomtransform_anchor.svg +++ b/msautotest/renderers/expected/poly_geomtransform_anchor.svg @@ -1,13 +1,40 @@ - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - + + + + + + diff --git a/msautotest/renderers/expected/polygon-as-line-offset.cairo.png b/msautotest/renderers/expected/polygon-as-line-offset.cairo.png index 0b1c158c4f..4be5745caa 100644 Binary files a/msautotest/renderers/expected/polygon-as-line-offset.cairo.png and b/msautotest/renderers/expected/polygon-as-line-offset.cairo.png differ diff --git a/msautotest/renderers/expected/polygon-as-line-offset.pdf b/msautotest/renderers/expected/polygon-as-line-offset.pdf index 11bab411d9..4bcb0cac02 100644 Binary files a/msautotest/renderers/expected/polygon-as-line-offset.pdf and b/msautotest/renderers/expected/polygon-as-line-offset.pdf differ diff --git a/msautotest/renderers/expected/polygon-as-line-offset.png b/msautotest/renderers/expected/polygon-as-line-offset.png index a5b5af87f7..e166d1ac99 100644 Binary files a/msautotest/renderers/expected/polygon-as-line-offset.png and b/msautotest/renderers/expected/polygon-as-line-offset.png differ diff --git a/msautotest/renderers/expected/polygon-as-line-offset.svg b/msautotest/renderers/expected/polygon-as-line-offset.svg index 0b2a2795c9..d735bf7bd5 100644 --- a/msautotest/renderers/expected/polygon-as-line-offset.svg +++ b/msautotest/renderers/expected/polygon-as-line-offset.svg @@ -1,14 +1,51 @@ - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msautotest/renderers/expected/polygon-as-line.cairo.png b/msautotest/renderers/expected/polygon-as-line.cairo.png index 18ea16cf45..ebf3135724 100644 Binary files a/msautotest/renderers/expected/polygon-as-line.cairo.png and b/msautotest/renderers/expected/polygon-as-line.cairo.png differ diff --git a/msautotest/renderers/expected/polygon-as-line.pdf b/msautotest/renderers/expected/polygon-as-line.pdf index c4b23d4b2d..ddf44656f6 100644 Binary files a/msautotest/renderers/expected/polygon-as-line.pdf and b/msautotest/renderers/expected/polygon-as-line.pdf differ diff --git a/msautotest/renderers/expected/polygon-as-line.svg b/msautotest/renderers/expected/polygon-as-line.svg index 598e88fd51..d4f574a90c 100644 --- a/msautotest/renderers/expected/polygon-as-line.svg +++ b/msautotest/renderers/expected/polygon-as-line.svg @@ -1,25 +1,52 @@ - + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - - + + - - + + - - - - - - + + + + + + diff --git a/msautotest/renderers/expected/polygon-hatch-dashed.cairo.png b/msautotest/renderers/expected/polygon-hatch-dashed.cairo.png index 599f79e54c..8ca87eaef3 100644 Binary files a/msautotest/renderers/expected/polygon-hatch-dashed.cairo.png and b/msautotest/renderers/expected/polygon-hatch-dashed.cairo.png differ diff --git a/msautotest/renderers/expected/polygon-hatch-dashed.pdf b/msautotest/renderers/expected/polygon-hatch-dashed.pdf index 7d0496de26..7c42d35cf4 100644 Binary files a/msautotest/renderers/expected/polygon-hatch-dashed.pdf and b/msautotest/renderers/expected/polygon-hatch-dashed.pdf differ diff --git a/msautotest/renderers/expected/polygon-hatch-dashed.svg b/msautotest/renderers/expected/polygon-hatch-dashed.svg index 3d5b03469f..34da0f3daa 100644 --- a/msautotest/renderers/expected/polygon-hatch-dashed.svg +++ b/msautotest/renderers/expected/polygon-hatch-dashed.svg @@ -1,51 +1,80 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msautotest/renderers/expected/polygon-hatch.cairo.png b/msautotest/renderers/expected/polygon-hatch.cairo.png index 3323337033..7fa21c2491 100644 Binary files a/msautotest/renderers/expected/polygon-hatch.cairo.png and b/msautotest/renderers/expected/polygon-hatch.cairo.png differ diff --git a/msautotest/renderers/expected/polygon-hatch.pdf b/msautotest/renderers/expected/polygon-hatch.pdf index caec881d71..468714a857 100644 Binary files a/msautotest/renderers/expected/polygon-hatch.pdf and b/msautotest/renderers/expected/polygon-hatch.pdf differ diff --git a/msautotest/renderers/expected/polygon-hatch.svg b/msautotest/renderers/expected/polygon-hatch.svg index 45ccf8e6e3..5b962fa3ea 100644 --- a/msautotest/renderers/expected/polygon-hatch.svg +++ b/msautotest/renderers/expected/polygon-hatch.svg @@ -1,114 +1,143 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msautotest/renderers/expected/polygon-pixmap.cairo.png b/msautotest/renderers/expected/polygon-pixmap.cairo.png index c55df3af1e..63f5a33f70 100644 Binary files a/msautotest/renderers/expected/polygon-pixmap.cairo.png and b/msautotest/renderers/expected/polygon-pixmap.cairo.png differ diff --git a/msautotest/renderers/expected/polygon-pixmap.pdf b/msautotest/renderers/expected/polygon-pixmap.pdf index 7bf3b52351..be79e41d96 100644 Binary files a/msautotest/renderers/expected/polygon-pixmap.pdf and b/msautotest/renderers/expected/polygon-pixmap.pdf differ diff --git a/msautotest/renderers/expected/polygon-pixmap.svg b/msautotest/renderers/expected/polygon-pixmap.svg index 2dfdb58b5b..b809aa9f15 100644 --- a/msautotest/renderers/expected/polygon-pixmap.svg +++ b/msautotest/renderers/expected/polygon-pixmap.svg @@ -1,30 +1,57 @@ - + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + - - + + - - + + - - - - - - - - - - + + + + + + + + + + diff --git a/msautotest/renderers/expected/polygon-simple.cairo.png b/msautotest/renderers/expected/polygon-simple.cairo.png index 112a4678ad..97a5bb084c 100644 Binary files a/msautotest/renderers/expected/polygon-simple.cairo.png and b/msautotest/renderers/expected/polygon-simple.cairo.png differ diff --git a/msautotest/renderers/expected/polygon-simple.pdf b/msautotest/renderers/expected/polygon-simple.pdf index aa7b1356a1..e66dd9f1f7 100644 Binary files a/msautotest/renderers/expected/polygon-simple.pdf and b/msautotest/renderers/expected/polygon-simple.pdf differ diff --git a/msautotest/renderers/expected/polygon-simple.png b/msautotest/renderers/expected/polygon-simple.png index cbba08413b..5405c2bf45 100644 Binary files a/msautotest/renderers/expected/polygon-simple.png and b/msautotest/renderers/expected/polygon-simple.png differ diff --git a/msautotest/renderers/expected/polygon-simple.svg b/msautotest/renderers/expected/polygon-simple.svg index 869e44fc90..0a500c80fc 100644 --- a/msautotest/renderers/expected/polygon-simple.svg +++ b/msautotest/renderers/expected/polygon-simple.svg @@ -1,12 +1,41 @@ - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msautotest/renderers/expected/polygon-ttf.cairo.png b/msautotest/renderers/expected/polygon-ttf.cairo.png index 0bfee2ef57..8bbf277823 100644 Binary files a/msautotest/renderers/expected/polygon-ttf.cairo.png and b/msautotest/renderers/expected/polygon-ttf.cairo.png differ diff --git a/msautotest/renderers/expected/polygon-ttf.pdf b/msautotest/renderers/expected/polygon-ttf.pdf index b5a031d1fc..5468439e05 100644 Binary files a/msautotest/renderers/expected/polygon-ttf.pdf and b/msautotest/renderers/expected/polygon-ttf.pdf differ diff --git a/msautotest/renderers/expected/polygon-ttf.svg b/msautotest/renderers/expected/polygon-ttf.svg index 50eacf38c8..075ee9268a 100644 --- a/msautotest/renderers/expected/polygon-ttf.svg +++ b/msautotest/renderers/expected/polygon-ttf.svg @@ -1,30 +1,57 @@ - + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + - - + + - - + + - - - - - - - - - - + + + + + + + + + + diff --git a/msautotest/renderers/expected/polygon-vector.cairo.png b/msautotest/renderers/expected/polygon-vector.cairo.png index 7c9b1e631b..90e8160286 100644 Binary files a/msautotest/renderers/expected/polygon-vector.cairo.png and b/msautotest/renderers/expected/polygon-vector.cairo.png differ diff --git a/msautotest/renderers/expected/polygon-vector.pdf b/msautotest/renderers/expected/polygon-vector.pdf index 9c0b52bc0f..9ae1c9ac48 100644 Binary files a/msautotest/renderers/expected/polygon-vector.pdf and b/msautotest/renderers/expected/polygon-vector.pdf differ diff --git a/msautotest/renderers/expected/polygon-vector.svg b/msautotest/renderers/expected/polygon-vector.svg index f6b610d21b..b67d2961ff 100644 --- a/msautotest/renderers/expected/polygon-vector.svg +++ b/msautotest/renderers/expected/polygon-vector.svg @@ -1,30 +1,57 @@ - + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + - - + + - - + + - - - - - - - - - - + + + + + + + + + + diff --git a/msautotest/renderers/expected/raster_simple.pdf b/msautotest/renderers/expected/raster_simple.pdf index f2ef4443d5..767471a0bd 100644 Binary files a/msautotest/renderers/expected/raster_simple.pdf and b/msautotest/renderers/expected/raster_simple.pdf differ diff --git a/msautotest/renderers/expected/raster_simple.svg b/msautotest/renderers/expected/raster_simple.svg index dc6d70002a..d44a8865cb 100644 --- a/msautotest/renderers/expected/raster_simple.svg +++ b/msautotest/renderers/expected/raster_simple.svg @@ -1,10 +1,37 @@ - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + diff --git a/msautotest/renderers/expected/raster_simple_opacity.pdf b/msautotest/renderers/expected/raster_simple_opacity.pdf index 53d16da017..c341fc2d04 100644 Binary files a/msautotest/renderers/expected/raster_simple_opacity.pdf and b/msautotest/renderers/expected/raster_simple_opacity.pdf differ diff --git a/msautotest/renderers/expected/raster_simple_opacity.svg b/msautotest/renderers/expected/raster_simple_opacity.svg index 1acbbf925f..4c33357d1c 100644 --- a/msautotest/renderers/expected/raster_simple_opacity.svg +++ b/msautotest/renderers/expected/raster_simple_opacity.svg @@ -1,24 +1,53 @@ - + - - + + - - - - + + + + + + + + + + + + + + - - - + + + + + + + + + + + + + + + + + + + + - - + + - - - + + + + + diff --git a/msautotest/renderers/expected/rasterlabel.png b/msautotest/renderers/expected/rasterlabel.png new file mode 100644 index 0000000000..94ac7165be Binary files /dev/null and b/msautotest/renderers/expected/rasterlabel.png differ diff --git a/msautotest/renderers/expected/rasterlabel_float64.png b/msautotest/renderers/expected/rasterlabel_float64.png new file mode 100644 index 0000000000..f1e3cae1b3 Binary files /dev/null and b/msautotest/renderers/expected/rasterlabel_float64.png differ diff --git a/msautotest/renderers/expected/rasterlabel_int32.png b/msautotest/renderers/expected/rasterlabel_int32.png new file mode 100644 index 0000000000..f1e3cae1b3 Binary files /dev/null and b/msautotest/renderers/expected/rasterlabel_int32.png differ diff --git a/msautotest/renderers/expected/reproj.pdf b/msautotest/renderers/expected/reproj.pdf index 9e02f5158d..b98d0a68ca 100644 Binary files a/msautotest/renderers/expected/reproj.pdf and b/msautotest/renderers/expected/reproj.pdf differ diff --git a/msautotest/renderers/expected/reproj.svg b/msautotest/renderers/expected/reproj.svg index 5f9d21961e..a3ea81bd9d 100644 --- a/msautotest/renderers/expected/reproj.svg +++ b/msautotest/renderers/expected/reproj.svg @@ -1,10 +1,37 @@ - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + diff --git a/msautotest/renderers/expected/resolution_text_1.png b/msautotest/renderers/expected/resolution_text_1.png index 7a9101ec90..1ee80a1df0 100644 Binary files a/msautotest/renderers/expected/resolution_text_1.png and b/msautotest/renderers/expected/resolution_text_1.png differ diff --git a/msautotest/renderers/expected/resolution_text_2.png b/msautotest/renderers/expected/resolution_text_2.png index a7506fdc6a..e278355217 100644 Binary files a/msautotest/renderers/expected/resolution_text_2.png and b/msautotest/renderers/expected/resolution_text_2.png differ diff --git a/msautotest/renderers/expected/resolution_text_4.png b/msautotest/renderers/expected/resolution_text_4.png index 579bdee241..da62260450 100644 Binary files a/msautotest/renderers/expected/resolution_text_4.png and b/msautotest/renderers/expected/resolution_text_4.png differ diff --git a/msautotest/renderers/expected/rgb_overlay.pdf b/msautotest/renderers/expected/rgb_overlay.pdf index 6dcc51d256..d67e5960f7 100644 Binary files a/msautotest/renderers/expected/rgb_overlay.pdf and b/msautotest/renderers/expected/rgb_overlay.pdf differ diff --git a/msautotest/renderers/expected/rgb_overlay.svg b/msautotest/renderers/expected/rgb_overlay.svg index 0aa8dc8553..d70417e374 100644 --- a/msautotest/renderers/expected/rgb_overlay.svg +++ b/msautotest/renderers/expected/rgb_overlay.svg @@ -1,12 +1,39 @@ - + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - + + + + diff --git a/msautotest/renderers/expected/rgb_overlay_res.pdf b/msautotest/renderers/expected/rgb_overlay_res.pdf index 439c7268e6..74bcb5e9ad 100644 Binary files a/msautotest/renderers/expected/rgb_overlay_res.pdf and b/msautotest/renderers/expected/rgb_overlay_res.pdf differ diff --git a/msautotest/renderers/expected/rgb_overlay_res.svg b/msautotest/renderers/expected/rgb_overlay_res.svg index 9c2bef8544..cf28218fb4 100644 --- a/msautotest/renderers/expected/rgb_overlay_res.svg +++ b/msautotest/renderers/expected/rgb_overlay_res.svg @@ -1,12 +1,39 @@ - + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - + + + + diff --git a/msautotest/renderers/expected/rgb_overlay_res_to8bit.pdf b/msautotest/renderers/expected/rgb_overlay_res_to8bit.pdf index 439c7268e6..74bcb5e9ad 100644 Binary files a/msautotest/renderers/expected/rgb_overlay_res_to8bit.pdf and b/msautotest/renderers/expected/rgb_overlay_res_to8bit.pdf differ diff --git a/msautotest/renderers/expected/rgb_overlay_res_to8bit.svg b/msautotest/renderers/expected/rgb_overlay_res_to8bit.svg index 9c2bef8544..cf28218fb4 100644 --- a/msautotest/renderers/expected/rgb_overlay_res_to8bit.svg +++ b/msautotest/renderers/expected/rgb_overlay_res_to8bit.svg @@ -1,12 +1,39 @@ - + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - + + + + diff --git a/msautotest/renderers/expected/rgb_overlay_res_to8bit_dithered.pdf b/msautotest/renderers/expected/rgb_overlay_res_to8bit_dithered.pdf index 439c7268e6..74bcb5e9ad 100644 Binary files a/msautotest/renderers/expected/rgb_overlay_res_to8bit_dithered.pdf and b/msautotest/renderers/expected/rgb_overlay_res_to8bit_dithered.pdf differ diff --git a/msautotest/renderers/expected/rgb_overlay_res_to8bit_dithered.svg b/msautotest/renderers/expected/rgb_overlay_res_to8bit_dithered.svg index 9c2bef8544..cf28218fb4 100644 --- a/msautotest/renderers/expected/rgb_overlay_res_to8bit_dithered.svg +++ b/msautotest/renderers/expected/rgb_overlay_res_to8bit_dithered.svg @@ -1,12 +1,39 @@ - + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - + + + + diff --git a/msautotest/renderers/expected/rgba_overlay_res.pdf b/msautotest/renderers/expected/rgba_overlay_res.pdf index 80be63a10f..9261faca5f 100644 Binary files a/msautotest/renderers/expected/rgba_overlay_res.pdf and b/msautotest/renderers/expected/rgba_overlay_res.pdf differ diff --git a/msautotest/renderers/expected/rgba_overlay_res.svg b/msautotest/renderers/expected/rgba_overlay_res.svg index 3c63832f9a..f4318d54b5 100644 --- a/msautotest/renderers/expected/rgba_overlay_res.svg +++ b/msautotest/renderers/expected/rgba_overlay_res.svg @@ -1,12 +1,39 @@ - + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - + + + + diff --git a/msautotest/renderers/expected/style_size_binding.png b/msautotest/renderers/expected/style_size_binding.png new file mode 100644 index 0000000000..ee12bed203 Binary files /dev/null and b/msautotest/renderers/expected/style_size_binding.png differ diff --git a/msautotest/renderers/expected/style_size_expression.png b/msautotest/renderers/expected/style_size_expression.png new file mode 100644 index 0000000000..01ebbae6e6 Binary files /dev/null and b/msautotest/renderers/expected/style_size_expression.png differ diff --git a/msautotest/renderers/expected/style_size_fixed.png b/msautotest/renderers/expected/style_size_fixed.png new file mode 100644 index 0000000000..4fa9826082 Binary files /dev/null and b/msautotest/renderers/expected/style_size_fixed.png differ diff --git a/msautotest/renderers/expected/text_shaping_1.cairo.png b/msautotest/renderers/expected/text_shaping_1.cairo.png index 82c11968cc..35c6dcc49d 100644 Binary files a/msautotest/renderers/expected/text_shaping_1.cairo.png and b/msautotest/renderers/expected/text_shaping_1.cairo.png differ diff --git a/msautotest/renderers/expected/text_shaping_1.pdf b/msautotest/renderers/expected/text_shaping_1.pdf index 87a0e246aa..2a4482f893 100644 Binary files a/msautotest/renderers/expected/text_shaping_1.pdf and b/msautotest/renderers/expected/text_shaping_1.pdf differ diff --git a/msautotest/renderers/expected/text_shaping_1.png b/msautotest/renderers/expected/text_shaping_1.png index d82739245b..235545b6af 100644 Binary files a/msautotest/renderers/expected/text_shaping_1.png and b/msautotest/renderers/expected/text_shaping_1.png differ diff --git a/msautotest/renderers/expected/text_shaping_1.svg b/msautotest/renderers/expected/text_shaping_1.svg index a335d5765c..23a54e0a4e 100644 --- a/msautotest/renderers/expected/text_shaping_1.svg +++ b/msautotest/renderers/expected/text_shaping_1.svg @@ -1,7 +1,36 @@ - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msautotest/renderers/expected/transparent_layer.cairo.png b/msautotest/renderers/expected/transparent_layer.cairo.png index febed1b21b..c80d3362a1 100644 Binary files a/msautotest/renderers/expected/transparent_layer.cairo.png and b/msautotest/renderers/expected/transparent_layer.cairo.png differ diff --git a/msautotest/renderers/expected/transparent_layer.pdf b/msautotest/renderers/expected/transparent_layer.pdf index 0c1df6d25c..dfef3b891c 100644 Binary files a/msautotest/renderers/expected/transparent_layer.pdf and b/msautotest/renderers/expected/transparent_layer.pdf differ diff --git a/msautotest/renderers/expected/transparent_layer.svg b/msautotest/renderers/expected/transparent_layer.svg index 5f608c7e50..bc49b37926 100644 --- a/msautotest/renderers/expected/transparent_layer.svg +++ b/msautotest/renderers/expected/transparent_layer.svg @@ -1,39 +1,68 @@ - + - - + + - - - - + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - + + + + + + + + + diff --git a/msautotest/renderers/expected/uvraster.cairo.png b/msautotest/renderers/expected/uvraster.cairo.png index d49b8a2ab5..250522070d 100644 Binary files a/msautotest/renderers/expected/uvraster.cairo.png and b/msautotest/renderers/expected/uvraster.cairo.png differ diff --git a/msautotest/renderers/expected/uvraster.pdf b/msautotest/renderers/expected/uvraster.pdf deleted file mode 100644 index 871af43103..0000000000 Binary files a/msautotest/renderers/expected/uvraster.pdf and /dev/null differ diff --git a/msautotest/renderers/expected/uvraster.svg b/msautotest/renderers/expected/uvraster.svg deleted file mode 100644 index 5d8b0c91fa..0000000000 --- a/msautotest/renderers/expected/uvraster.svg +++ /dev/null @@ -1,534 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/msautotest/renderers/expected/uvraster_reproj.cairo.png b/msautotest/renderers/expected/uvraster_reproj.cairo.png index 9c517e7ae6..eb797e0e94 100644 Binary files a/msautotest/renderers/expected/uvraster_reproj.cairo.png and b/msautotest/renderers/expected/uvraster_reproj.cairo.png differ diff --git a/msautotest/renderers/expected/uvraster_reproj.pdf b/msautotest/renderers/expected/uvraster_reproj.pdf deleted file mode 100644 index 00f189e962..0000000000 Binary files a/msautotest/renderers/expected/uvraster_reproj.pdf and /dev/null differ diff --git a/msautotest/renderers/expected/uvraster_reproj.png b/msautotest/renderers/expected/uvraster_reproj.png index 7a622ca532..0f94a5c3e1 100644 Binary files a/msautotest/renderers/expected/uvraster_reproj.png and b/msautotest/renderers/expected/uvraster_reproj.png differ diff --git a/msautotest/renderers/expected/uvraster_reproj.svg b/msautotest/renderers/expected/uvraster_reproj.svg deleted file mode 100644 index 9c03cc63b9..0000000000 --- a/msautotest/renderers/expected/uvraster_reproj.svg +++ /dev/null @@ -1,490 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/msautotest/renderers/expected/uvraster_reproj_expr_on_lon_lat.png b/msautotest/renderers/expected/uvraster_reproj_expr_on_lon_lat.png new file mode 100644 index 0000000000..3d5c2f3e4f Binary files /dev/null and b/msautotest/renderers/expected/uvraster_reproj_expr_on_lon_lat.png differ diff --git a/msautotest/renderers/expected/wld_rotate.pdf b/msautotest/renderers/expected/wld_rotate.pdf index a607668f8a..d8bab9a544 100644 Binary files a/msautotest/renderers/expected/wld_rotate.pdf and b/msautotest/renderers/expected/wld_rotate.pdf differ diff --git a/msautotest/renderers/expected/wld_rotate.svg b/msautotest/renderers/expected/wld_rotate.svg index d07180c4b5..fa6749389d 100644 --- a/msautotest/renderers/expected/wld_rotate.svg +++ b/msautotest/renderers/expected/wld_rotate.svg @@ -1,10 +1,37 @@ - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + diff --git a/msautotest/renderers/expected/wld_upsidedown.pdf b/msautotest/renderers/expected/wld_upsidedown.pdf index c508508aad..7c4dd5364e 100644 Binary files a/msautotest/renderers/expected/wld_upsidedown.pdf and b/msautotest/renderers/expected/wld_upsidedown.pdf differ diff --git a/msautotest/renderers/expected/wld_upsidedown.svg b/msautotest/renderers/expected/wld_upsidedown.svg index 76b120ab3d..8d239568d5 100644 --- a/msautotest/renderers/expected/wld_upsidedown.svg +++ b/msautotest/renderers/expected/wld_upsidedown.svg @@ -1,10 +1,37 @@ - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + diff --git a/msautotest/renderers/expected/wmsclient.pdf b/msautotest/renderers/expected/wmsclient.pdf index 6ee253ab32..3865454eb8 100644 Binary files a/msautotest/renderers/expected/wmsclient.pdf and b/msautotest/renderers/expected/wmsclient.pdf differ diff --git a/msautotest/renderers/expected/wmsclient.svg b/msautotest/renderers/expected/wmsclient.svg index fab53ff2aa..d0c91a4d6d 100644 --- a/msautotest/renderers/expected/wmsclient.svg +++ b/msautotest/renderers/expected/wmsclient.svg @@ -1,10 +1,37 @@ - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + diff --git a/msautotest/renderers/font-fail.map b/msautotest/renderers/font-fail.map index 9271e3dfe8..a806c39ff3 100644 --- a/msautotest/renderers/font-fail.map +++ b/msautotest/renderers/font-fail.map @@ -1,5 +1,6 @@ # RUN_PARMS: font-fail-key.txt [MAPSERV] QUERY_STRING="map=[MAPFILE]&mode=map&layer=l1" > [RESULT_DEVERSION] # RUN_PARMS: font-fail-file.txt [MAPSERV] QUERY_STRING="map=[MAPFILE]&mode=map&layer=l2" > [RESULT_DEVERSION] +# RUN_PARMS: font-fail-missing-glyph.png [MAP2IMG] -m [MAPFILE] -l missing_glyph -i png -o [RESULT] MAP @@ -41,4 +42,21 @@ LAYER FEATURE POINTS 50 50 END END END +LAYER + NAME "missing_glyph" + STATUS ON + TYPE POLYGON + FEATURE + POINTS 0 0 400 0 400 300 0 300 0 0 END + END + CLASS + LABEL + TEXT 'this is a test: это проверка' + TYPE truetype + SIZE 8 + FONT "default" + END + END +END + END diff --git a/msautotest/renderers/force_palette.map b/msautotest/renderers/force_palette.map index 1768e12415..073748823b 100644 --- a/msautotest/renderers/force_palette.map +++ b/msautotest/renderers/force_palette.map @@ -1,5 +1,5 @@ -# RUN_PARMS: force_palette.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: force_palette.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: force_palette.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: force_palette.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # # diff --git a/msautotest/renderers/force_palette_rgba.map b/msautotest/renderers/force_palette_rgba.map index b97fa53b8b..f272c4303a 100644 --- a/msautotest/renderers/force_palette_rgba.map +++ b/msautotest/renderers/force_palette_rgba.map @@ -1,5 +1,5 @@ -# RUN_PARMS: force_palette_rgba.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: force_palette_rgba.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: force_palette_rgba.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: force_palette_rgba.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # # diff --git a/msautotest/renderers/force_pc256.map b/msautotest/renderers/force_pc256.map index f84147b129..3548c33396 100644 --- a/msautotest/renderers/force_pc256.map +++ b/msautotest/renderers/force_pc256.map @@ -1,5 +1,5 @@ -# RUN_PARMS: force_pc256.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: force_pc256.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: force_pc256.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: force_pc256.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # # diff --git a/msautotest/renderers/force_pc256_rgba.map b/msautotest/renderers/force_pc256_rgba.map index f48bab45df..c3b1bcbb7b 100644 --- a/msautotest/renderers/force_pc256_rgba.map +++ b/msautotest/renderers/force_pc256_rgba.map @@ -1,5 +1,5 @@ -# RUN_PARMS: force_pc256_rgba.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: force_pc256_rgba.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: force_pc256_rgba.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: force_pc256_rgba.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # # diff --git a/msautotest/renderers/geomtransform-vertex.map b/msautotest/renderers/geomtransform-vertex.map index d618390331..ed055d2e50 100644 --- a/msautotest/renderers/geomtransform-vertex.map +++ b/msautotest/renderers/geomtransform-vertex.map @@ -1,14 +1,14 @@ # # tests vertex geomtransform with auto angle # -# RUN_PARMS: geomtransform-vertex.png [SHP2IMG] -m [MAPFILE] -i png -l "centroid vertex1" -o [RESULT] -# RUN_PARMS: geomtransform-vertex.pdf [SHP2IMG] -m [MAPFILE] -i pdf -l "centroid vertex1" -o [RESULT] -# RUN_PARMS: geomtransform-vertex.svg [SHP2IMG] -m [MAPFILE] -i svg -l "centroid vertex1" -o [RESULT] -# RUN_PARMS: geomtransform-vertex.cairo.png [SHP2IMG] -m [MAPFILE] -l "centroid vertex1" -i cairopng -o [RESULT] -# RUN_PARMS: geomtransform-vertex-layer.png [SHP2IMG] -m [MAPFILE] -i png -l vertex2 -o [RESULT] -# RUN_PARMS: geomtransform-vertex-layer.pdf [SHP2IMG] -m [MAPFILE] -i pdf -l vertex2 -o [RESULT] -# RUN_PARMS: geomtransform-vertex-layer.svg [SHP2IMG] -m [MAPFILE] -i svg -l vertex2 -o [RESULT] -# RUN_PARMS: geomtransform-vertex-layer.cairo.png [SHP2IMG] -m [MAPFILE] -l vertex2 -i cairopng -o [RESULT] +# RUN_PARMS: geomtransform-vertex.png [MAP2IMG] -m [MAPFILE] -i png -l "centroid vertex1" -o [RESULT] +# RUN_PARMS: geomtransform-vertex.pdf [MAP2IMG] -m [MAPFILE] -i pdf -l "centroid vertex1" -o [RESULT] +# RUN_PARMS: geomtransform-vertex.svg [MAP2IMG] -m [MAPFILE] -i svg -l "centroid vertex1" -o [RESULT] +# RUN_PARMS: geomtransform-vertex.cairo.png [MAP2IMG] -m [MAPFILE] -l "centroid vertex1" -i cairopng -o [RESULT] +# RUN_PARMS: geomtransform-vertex-layer.png [MAP2IMG] -m [MAPFILE] -i png -l vertex2 -o [RESULT] +# RUN_PARMS: geomtransform-vertex-layer.pdf [MAP2IMG] -m [MAPFILE] -i pdf -l vertex2 -o [RESULT] +# RUN_PARMS: geomtransform-vertex-layer.svg [MAP2IMG] -m [MAPFILE] -i svg -l vertex2 -o [RESULT] +# RUN_PARMS: geomtransform-vertex-layer.cairo.png [MAP2IMG] -m [MAPFILE] -l vertex2 -i cairopng -o [RESULT] # diff --git a/msautotest/renderers/grid.map b/msautotest/renderers/grid.map index 79bd0ada2b..f902fadc41 100644 --- a/msautotest/renderers/grid.map +++ b/msautotest/renderers/grid.map @@ -1,7 +1,7 @@ -# RUN_PARMS: grid.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: grid.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: grid.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: grid.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: grid.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: grid.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: grid.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: grid.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # # # Test GRID (automatic graticule) @@ -29,8 +29,10 @@ MAP "+proj=merc +datum=WGS84" END CLASS - OUTLINECOLOR 0 0 0 - COLOR 255 255 0 + STYLE + OUTLINECOLOR 0 0 0 + COLOR 255 255 0 + END END END @@ -43,7 +45,9 @@ MAP STATUS ON CLASS NAME "Graticule" - COLOR 0 0 0 + STYLE + COLOR 0 0 0 + END LABEL COLOR 255 0 0 FONT lucida diff --git a/msautotest/renderers/label-multifont.map b/msautotest/renderers/label-multifont.map index fb28b5646a..fc299543db 100644 --- a/msautotest/renderers/label-multifont.map +++ b/msautotest/renderers/label-multifont.map @@ -1,7 +1,7 @@ -# RUN_PARMS: label-multifont.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: label-multifont.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: label-multifont.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: label-multifont.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: label-multifont.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: label-multifont.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: label-multifont.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: label-multifont.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # map diff --git a/msautotest/renderers/label_noclip.map b/msautotest/renderers/label_noclip.map index daf8b5d9c7..954111f67d 100644 --- a/msautotest/renderers/label_noclip.map +++ b/msautotest/renderers/label_noclip.map @@ -1,7 +1,7 @@ -# RUN_PARMS: label_noclip.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: label_noclip.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: label_noclip.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: label_noclip.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: label_noclip.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: label_noclip.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: label_noclip.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: label_noclip.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # map diff --git a/msautotest/renderers/labelcacheoff.map b/msautotest/renderers/labelcacheoff.map index 34f20aec9c..5e64077aaa 100644 --- a/msautotest/renderers/labelcacheoff.map +++ b/msautotest/renderers/labelcacheoff.map @@ -1,7 +1,7 @@ -# RUN_PARMS: labelcacheoff.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: labelcacheoff.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: labelcacheoff.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: labelcacheoff.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: labelcacheoff.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: labelcacheoff.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: labelcacheoff.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: labelcacheoff.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] MAP diff --git a/msautotest/renderers/labelpnt.map b/msautotest/renderers/labelpnt.map index 2a330c004e..715794757c 100644 --- a/msautotest/renderers/labelpnt.map +++ b/msautotest/renderers/labelpnt.map @@ -1,7 +1,7 @@ -# RUN_PARMS: labelpnt.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: labelpnt.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: labelpnt.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: labelpnt.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: labelpnt.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: labelpnt.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: labelpnt.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: labelpnt.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # MAp extent -200 -200 200 200 diff --git a/msautotest/renderers/labelrot.map b/msautotest/renderers/labelrot.map index 277ae7e842..c21166abf4 100644 --- a/msautotest/renderers/labelrot.map +++ b/msautotest/renderers/labelrot.map @@ -1,7 +1,7 @@ -# RUN_PARMS: labelrot.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: labelrot.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: labelrot.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: labelrot.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: labelrot.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: labelrot.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: labelrot.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: labelrot.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # # @@ -14,8 +14,6 @@ MAP IMAGETYPE png - TRANSPARENT OFF - SIZE 400 300 EXTENT 0 0 4000 3000 UNITS meters @@ -35,7 +33,7 @@ MAP TEXT "Polygon" END CLASS - COLOR 0 255 0 + STYLE COLOR 0 255 0 END LABEL COLOR 0 0 0 FONT lucida @@ -60,7 +58,7 @@ MAP END LABELCACHE OFF CLASS - COLOR 0 255 0 + STYLE COLOR 0 255 0 END LABEL COLOR 0 0 0 FONT lucida @@ -85,7 +83,7 @@ MAP END LABELCACHE OFF CLASS - COLOR 0 255 0 + STYLE COLOR 0 255 0 END LABEL COLOR 0 0 0 FONT lucida @@ -110,7 +108,7 @@ MAP TEXT "Rot-Cached" END CLASS - COLOR 0 255 0 + STYLE COLOR 0 255 0 END LABEL COLOR 0 0 0 FONT lucida @@ -135,7 +133,7 @@ MAP TEXT "angle+rot" END CLASS - COLOR 0 255 0 + STYLE COLOR 0 255 0 END LABEL COLOR 0 0 0 FONT lucida @@ -161,7 +159,7 @@ MAP TEXT "Fixed on line" END CLASS - COLOR 255 0 0 + STYLE COLOR 255 0 0 END LABEL COLOR 255 0 0 FONT lucida diff --git a/msautotest/renderers/labels-alignment.map b/msautotest/renderers/labels-alignment.map index 1e664dbe6d..63f00428d7 100644 --- a/msautotest/renderers/labels-alignment.map +++ b/msautotest/renderers/labels-alignment.map @@ -1,27 +1,27 @@ -# RUN_PARMS: label_ar-align-center.png [SHP2IMG] -l center_ar -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: label_ar-align-center.cairo.png [SHP2IMG] -l center_ar -m [MAPFILE] -i cairopng -o [RESULT] -# RUN_PARMS: label-align-center.png [SHP2IMG] -l center -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: label-align-center.cairo.png [SHP2IMG] -l center -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: label_ar-align-center.png [MAP2IMG] -l center_ar -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: label_ar-align-center.cairo.png [MAP2IMG] -l center_ar -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: label-align-center.png [MAP2IMG] -l center -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: label-align-center.cairo.png [MAP2IMG] -l center -m [MAPFILE] -i cairopng -o [RESULT] -# RUN_PARMS: label_ar-align-left.png [SHP2IMG] -l left_ar -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: label_ar-align-left.cairo.png [SHP2IMG] -l left_ar -m [MAPFILE] -i cairopng -o [RESULT] -# RUN_PARMS: label-align-left.png [SHP2IMG] -l left -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: label-align-left.cairo.png [SHP2IMG] -l left -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: label_ar-align-left.png [MAP2IMG] -l left_ar -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: label_ar-align-left.cairo.png [MAP2IMG] -l left_ar -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: label-align-left.png [MAP2IMG] -l left -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: label-align-left.cairo.png [MAP2IMG] -l left -m [MAPFILE] -i cairopng -o [RESULT] -# RUN_PARMS: label_ar-align-right.png [SHP2IMG] -l right_ar -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: label_ar-align-right.cairo.png [SHP2IMG] -l right_ar -m [MAPFILE] -i cairopng -o [RESULT] -# RUN_PARMS: label-align-right.png [SHP2IMG] -l right -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: label-align-right.cairo.png [SHP2IMG] -l right -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: label_ar-align-right.png [MAP2IMG] -l right_ar -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: label_ar-align-right.cairo.png [MAP2IMG] -l right_ar -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: label-align-right.png [MAP2IMG] -l right -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: label-align-right.cairo.png [MAP2IMG] -l right -m [MAPFILE] -i cairopng -o [RESULT] -# RUN_PARMS: label_ar-align-default.png [SHP2IMG] -l default_ar -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: label_ar-align-default.cairo.png [SHP2IMG] -l default_ar -m [MAPFILE] -i cairopng -o [RESULT] -# RUN_PARMS: label-align-default.png [SHP2IMG] -l default -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: label-align-default.cairo.png [SHP2IMG] -l default -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: label_ar-align-default.png [MAP2IMG] -l default_ar -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: label_ar-align-default.cairo.png [MAP2IMG] -l default_ar -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: label-align-default.png [MAP2IMG] -l default -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: label-align-default.cairo.png [MAP2IMG] -l default -m [MAPFILE] -i cairopng -o [RESULT] # -# RUN_PARMS: label_latin_align_left.png [SHP2IMG] -e -20000000 -200000000 20000000 200000000 -l latin_left -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: label_latin_align_right.png [SHP2IMG] -e -20000000 -200000000 20000000 200000000 -l latin_right -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: label_latin_align_center.png [SHP2IMG] -e -20000000 -200000000 20000000 200000000 -l latin_center -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: label_latin_align_default.png [SHP2IMG] -e -20000000 -200000000 20000000 200000000 -l latin_default -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: label_latin_align_left.png [MAP2IMG] -e -20000000 -200000000 20000000 200000000 -l latin_left -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: label_latin_align_right.png [MAP2IMG] -e -20000000 -200000000 20000000 200000000 -l latin_right -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: label_latin_align_center.png [MAP2IMG] -e -20000000 -200000000 20000000 200000000 -l latin_center -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: label_latin_align_default.png [MAP2IMG] -e -20000000 -200000000 20000000 200000000 -l latin_default -m [MAPFILE] -i png -o [RESULT] map imagetype png diff --git a/msautotest/renderers/labels-anno.map b/msautotest/renderers/labels-anno.map index d18b573b96..b730893b86 100644 --- a/msautotest/renderers/labels-anno.map +++ b/msautotest/renderers/labels-anno.map @@ -1,7 +1,7 @@ -# RUN_PARMS: labels-anno.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: labels-anno.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: labels-anno.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: labels-anno.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: labels-anno.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: labels-anno.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: labels-anno.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: labels-anno.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # map diff --git a/msautotest/renderers/labels-attribute-alignment-offset.map b/msautotest/renderers/labels-attribute-alignment-offset.map index c25789b1de..f473666b66 100644 --- a/msautotest/renderers/labels-attribute-alignment-offset.map +++ b/msautotest/renderers/labels-attribute-alignment-offset.map @@ -1,6 +1,6 @@ -# RUN_PARMS: label_align_attribute.png [SHP2IMG] -e -0.0 -0.0 1.0 1.0 -s 1000 1000 -l align_attribute -m [MAPFILE] -o [RESULT] -# RUN_PARMS: label_offset_attribute.png [SHP2IMG] -e -0.0 -0.0 1.0 1.0 -s 1000 1000 -l offset_attribute -m [MAPFILE] -o [RESULT] +# RUN_PARMS: label_align_attribute.png [MAP2IMG] -e -0.0 -0.0 1.0 1.0 -s 1000 1000 -l align_attribute -m [MAPFILE] -o [RESULT] +# RUN_PARMS: label_offset_attribute.png [MAP2IMG] -e -0.0 -0.0 1.0 1.0 -s 1000 1000 -l offset_attribute -m [MAPFILE] -o [RESULT] map diff --git a/msautotest/renderers/labels-bitmap-multiline.map b/msautotest/renderers/labels-bitmap-multiline.map index 16bf6d116f..d7f83d6594 100644 --- a/msautotest/renderers/labels-bitmap-multiline.map +++ b/msautotest/renderers/labels-bitmap-multiline.map @@ -1,4 +1,4 @@ -# RUN_PARMS: labels-bitmap-multiline.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: labels-bitmap-multiline.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] # map diff --git a/msautotest/renderers/labels-bitmap.map b/msautotest/renderers/labels-bitmap.map index e8a5ed3bba..452751ef3a 100644 --- a/msautotest/renderers/labels-bitmap.map +++ b/msautotest/renderers/labels-bitmap.map @@ -1,4 +1,4 @@ -# RUN_PARMS: labels-bitmap.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: labels-bitmap.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] # map diff --git a/msautotest/renderers/labels-leader.map b/msautotest/renderers/labels-leader.map index ab898fa65e..61d2f3804c 100644 --- a/msautotest/renderers/labels-leader.map +++ b/msautotest/renderers/labels-leader.map @@ -1,7 +1,7 @@ -# RUN_PARMS: labels-leader.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: labels-leader.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: labels-leader.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: labels-leader.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: labels-leader.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: labels-leader.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: labels-leader.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: labels-leader.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # # # Test multiple labels/symbols per feature diff --git a/msautotest/renderers/labels-min-distance.map b/msautotest/renderers/labels-min-distance.map index d94b37182d..d67b6f210f 100644 --- a/msautotest/renderers/labels-min-distance.map +++ b/msautotest/renderers/labels-min-distance.map @@ -1,7 +1,7 @@ -# RUN_PARMS: labels-min-distance.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: labels-min-distance.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: labels-min-distance.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: labels-min-distance.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: labels-min-distance.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: labels-min-distance.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: labels-min-distance.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: labels-min-distance.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # map diff --git a/msautotest/renderers/labels-priority.map b/msautotest/renderers/labels-priority.map new file mode 100644 index 0000000000..d180329526 --- /dev/null +++ b/msautotest/renderers/labels-priority.map @@ -0,0 +1,80 @@ +# RUN_PARMS: label_priority_binding.png [MAP2IMG] -m [MAPFILE] -l label_priority_binding -o [RESULT] +# RUN_PARMS: label_priority_fixed.png [MAP2IMG] -m [MAPFILE] -l label_priority_fixed -o [RESULT] +# RUN_PARMS: label_priority_expression.png [MAP2IMG] -m [MAPFILE] -l label_priority_expression -o [RESULT] +# +# Test label priorities +# + +MAP + IMAGETYPE "png" + SIZE 400 400 + EXTENT -.5 -.5 1.5 1.5 + FONTSET "../misc/fonts.lst" + PROJECTION + "init=epsg:4326" + END + LAYER + NAME "label_priority_fixed" + TYPE POINT + STATUS OFF + DATA "data/label_alias_offset.shp" + LABELITEM "label" + CLASS + # make sure pnt7 gets labeling priority + EXPRESSION ([priority] = 7) + LABEL + FONT "default" + TYPE TRUETYPE + SIZE 40 + COLOR 0 0 0 + PRIORITY 10 + END + END + CLASS + EXPRESSION ([priority] != 7) + LABEL + FONT "default" + TYPE TRUETYPE + SIZE 12 + COLOR 0 0 0 + PRIORITY 1 + END + END + END + LAYER + NAME "label_priority_binding" + TYPE POINT + STATUS OFF + DATA "data/label_alias_offset.shp" + LABELITEM "label" + CLASS + LABEL + FONT "default" + TYPE TRUETYPE + SIZE 12 + COLOR 0 0 0 + PRIORITY [priority] + END + END + END + LAYER + NAME "label_priority_expression" + TYPE POINT + STATUS OFF + DATA "data/label_alias_offset.shp" + LABELITEM "label" + CLASS + LABEL + FONT "default" + TYPE TRUETYPE + SIZE 12 + COLOR 0 0 0 + # add a duplicate PRIORITY that will be ignored + # but check it is cleaned up correctly + PRIORITY ([priority] * 2) + # use an expression to invert the label priorities + PRIORITY (10 - [priority]) + END + END + END +END diff --git a/msautotest/renderers/labels-wrap.map b/msautotest/renderers/labels-wrap.map index e7a1fda41a..902462786b 100644 --- a/msautotest/renderers/labels-wrap.map +++ b/msautotest/renderers/labels-wrap.map @@ -1,4 +1,4 @@ -# RUN_PARMS: labels-wrap.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: labels-wrap.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] map imagetype png diff --git a/msautotest/renderers/labels.map b/msautotest/renderers/labels.map index b78037ee62..a95726e19d 100644 --- a/msautotest/renderers/labels.map +++ b/msautotest/renderers/labels.map @@ -1,7 +1,7 @@ -# RUN_PARMS: labels.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: labels.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: labels.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: labels.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: labels.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: labels.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: labels.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: labels.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # map diff --git a/msautotest/renderers/legend.map b/msautotest/renderers/legend.map index c04e8b9c05..125b2a1504 100644 --- a/msautotest/renderers/legend.map +++ b/msautotest/renderers/legend.map @@ -2,7 +2,7 @@ # RUN_PARMS: legend.cairo.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&mode=legend&map.imagetype=cairopng" > [RESULT_DEMIME] # RUN_PARMS: legend.svg [MAPSERV] QUERY_STRING="map=[MAPFILE]&mode=legend&map.imagetype=svg" > [RESULT_DEMIME] # RUN_PARMS: legend.pdf [MAPSERV] QUERY_STRING="map=[MAPFILE]&mode=legend&map.imagetype=pdf" > [RESULT_DEMIME] - +# RUN_PARMS: legend_bad_imagetype.txt [MAPSERV] QUERY_STRING="map=[MAPFILE]&mode=legend&map.imagetype=bogus+image+type" > [RESULT_DEVERSION] # # # legend support. @@ -112,8 +112,10 @@ LAYER STATUS default CLASS NAME "line text+shape" - COLOR 255 0 0 - OUTLINECOLOR 0 0 0 + STYLE + COLOR 255 0 0 + OUTLINECOLOR 0 0 0 + END LABEL type truetype size 9 @@ -123,8 +125,10 @@ LAYER END CLASS NAME "line labelpnt+shape" - COLOR 0 255 0 - OUTLINECOLOR 0 0 0 + STYLE + COLOR 0 255 0 + OUTLINECOLOR 0 0 0 + END LABEL type truetype size 9 @@ -182,8 +186,10 @@ LAYER STATUS default CLASS NAME "poly text+shape" - COLOR 255 0 0 - OUTLINECOLOR 0 0 0 + STYLE + COLOR 255 0 0 + OUTLINECOLOR 0 0 0 + END LABEL type truetype size 9 @@ -193,8 +199,10 @@ LAYER END CLASS NAME "poly labelpnt+shape" - COLOR 0 255 0 - OUTLINECOLOR 0 0 0 + STYLE + COLOR 0 255 0 + OUTLINECOLOR 0 0 0 + END LABEL type truetype size 9 diff --git a/msautotest/renderers/legend_label_offset.map b/msautotest/renderers/legend_label_offset.map index 5c7c921f57..ee509277e6 100644 --- a/msautotest/renderers/legend_label_offset.map +++ b/msautotest/renderers/legend_label_offset.map @@ -118,8 +118,10 @@ LAYER STATUS default CLASS NAME "line text+shape" - COLOR 255 0 0 - OUTLINECOLOR 0 0 0 + STYLE + COLOR 255 0 0 + OUTLINECOLOR 0 0 0 + END LABEL type truetype size 9 @@ -129,8 +131,10 @@ LAYER END CLASS NAME "line labelpnt+shape" - COLOR 0 255 0 - OUTLINECOLOR 0 0 0 + STYLE + COLOR 0 255 0 + OUTLINECOLOR 0 0 0 + END LABEL type truetype size 9 @@ -188,8 +192,10 @@ LAYER STATUS default CLASS NAME "poly text+shape" - COLOR 255 0 0 - OUTLINECOLOR 0 0 0 + STYLE + COLOR 255 0 0 + OUTLINECOLOR 0 0 0 + END LABEL type truetype size 9 @@ -199,8 +205,10 @@ LAYER END CLASS NAME "poly labelpnt+shape" - COLOR 0 255 0 - OUTLINECOLOR 0 0 0 + STYLE + COLOR 0 255 0 + OUTLINECOLOR 0 0 0 + END LABEL type truetype size 9 diff --git a/msautotest/renderers/legend_sizeunits_meters.map b/msautotest/renderers/legend_sizeunits_meters.map index 7ce5f2ba04..072b909b07 100644 --- a/msautotest/renderers/legend_sizeunits_meters.map +++ b/msautotest/renderers/legend_sizeunits_meters.map @@ -118,8 +118,10 @@ LAYER STATUS default CLASS NAME "line text+shape" - COLOR 255 0 0 - OUTLINECOLOR 0 0 0 + STYLE + COLOR 255 0 0 + OUTLINECOLOR 0 0 0 + END LABEL type truetype size 9 @@ -129,8 +131,10 @@ LAYER END CLASS NAME "line labelpnt+shape" - COLOR 0 255 0 - OUTLINECOLOR 0 0 0 + STYLE + COLOR 0 255 0 + OUTLINECOLOR 0 0 0 + END LABEL type truetype size 9 @@ -188,8 +192,10 @@ LAYER STATUS default CLASS NAME "poly text+shape" - COLOR 255 0 0 - OUTLINECOLOR 0 0 0 + STYLE + COLOR 255 0 0 + OUTLINECOLOR 0 0 0 + END LABEL type truetype size 9 @@ -199,8 +205,10 @@ LAYER END CLASS NAME "poly labelpnt+shape" - COLOR 0 255 0 - OUTLINECOLOR 0 0 0 + STYLE + COLOR 0 255 0 + OUTLINECOLOR 0 0 0 + END LABEL type truetype size 9 diff --git a/msautotest/renderers/line_aliased.map b/msautotest/renderers/line_aliased.map new file mode 100755 index 0000000000..bbd458b36a --- /dev/null +++ b/msautotest/renderers/line_aliased.map @@ -0,0 +1,35 @@ +# RUN_PARMS: line_aliased.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# +map + +imagetype png +size 400 300 +extent -166.245673 -55.551347 174.019748 53.883753 +shapepath "../misc/data" +fontset "../misc/fonts.lst" +symbolset "symbolset" + +OUTPUTFORMAT + NAME "png" + DRIVER AGG/PNG + MIMETYPE "image/png" + IMAGEMODE RGBA + EXTENSION "png" + FORMATOPTION "GAMMA=1.0" +END + +layer + type line + data "testlines" + status default + name "lines" + class + style + color 128 128 128 + width 5 + ANTIALIAS FALSE + end + end +end + +end diff --git a/msautotest/renderers/line_anchorpoint.map b/msautotest/renderers/line_anchorpoint.map index 1be3e5830c..2869eb034a 100644 --- a/msautotest/renderers/line_anchorpoint.map +++ b/msautotest/renderers/line_anchorpoint.map @@ -1,5 +1,5 @@ -# RUN_PARMS: line_anchorpoint.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: line_anchorpoint.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: line_anchorpoint.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: line_anchorpoint.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] MAP IMAGECOLOR 255 255 255 diff --git a/msautotest/renderers/line_antialiased.map b/msautotest/renderers/line_antialiased.map new file mode 100755 index 0000000000..97de07ee44 --- /dev/null +++ b/msautotest/renderers/line_antialiased.map @@ -0,0 +1,35 @@ +# RUN_PARMS: line_anti_aliased.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# +map + +imagetype png +size 400 300 +extent -166.245673 -55.551347 174.019748 53.883753 +shapepath "../misc/data" +fontset "../misc/fonts.lst" +symbolset "symbolset" + +OUTPUTFORMAT + NAME "png" + DRIVER AGG/PNG + MIMETYPE "image/png" + IMAGEMODE RGBA + EXTENSION "png" + FORMATOPTION "GAMMA=1.0" +END + +layer + type line + data "testlines" + status default + name "lines" + class + style + color 128 128 128 + width 5 + ANTIALIAS TRUE + end + end +end + +end diff --git a/msautotest/renderers/line_label_auto.map b/msautotest/renderers/line_label_auto.map index e14000ad80..0e64f41445 100644 --- a/msautotest/renderers/line_label_auto.map +++ b/msautotest/renderers/line_label_auto.map @@ -1,8 +1,8 @@ -# RUN_PARMS: line_label_auto.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: line_label_auto.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: line_label_auto.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: line_label_auto.json [SHP2IMG] -m [MAPFILE] -i json -o [RESULT] -# RUN_PARMS: line_label_auto.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: line_label_auto.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: line_label_auto.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: line_label_auto.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: line_label_auto.json [MAP2IMG] -m [MAPFILE] -i json -o [RESULT] +# RUN_PARMS: line_label_auto.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # map diff --git a/msautotest/renderers/line_label_auto2.map b/msautotest/renderers/line_label_auto2.map index f1a9d6a86f..3cdab523fd 100644 --- a/msautotest/renderers/line_label_auto2.map +++ b/msautotest/renderers/line_label_auto2.map @@ -1,7 +1,7 @@ -# RUN_PARMS: line_label_auto2.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: line_label_auto2.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: line_label_auto2.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: line_label_auto2.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: line_label_auto2.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: line_label_auto2.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: line_label_auto2.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: line_label_auto2.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # map diff --git a/msautotest/renderers/line_label_follow.map b/msautotest/renderers/line_label_follow.map index b335a557fd..70a0829e3f 100644 --- a/msautotest/renderers/line_label_follow.map +++ b/msautotest/renderers/line_label_follow.map @@ -1,7 +1,7 @@ -# RUN_PARMS: line_label_follow.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: line_label_follow.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: line_label_follow.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: line_label_follow.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: line_label_follow.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: line_label_follow.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: line_label_follow.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: line_label_follow.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # map diff --git a/msautotest/renderers/line_label_follow_offsetted.map b/msautotest/renderers/line_label_follow_offsetted.map index 478daa7eba..d891de1d89 100644 --- a/msautotest/renderers/line_label_follow_offsetted.map +++ b/msautotest/renderers/line_label_follow_offsetted.map @@ -1,7 +1,7 @@ -# RUN_PARMS: line_label_follow_offsetted.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: line_label_follow_offsetted.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: line_label_follow_offsetted.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: line_label_follow_offsetted.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: line_label_follow_offsetted.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: line_label_follow_offsetted.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: line_label_follow_offsetted.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: line_label_follow_offsetted.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # map diff --git a/msautotest/renderers/line_label_follow_retry.map b/msautotest/renderers/line_label_follow_retry.map index e058a5d922..654825da88 100644 --- a/msautotest/renderers/line_label_follow_retry.map +++ b/msautotest/renderers/line_label_follow_retry.map @@ -1,7 +1,7 @@ -# RUN_PARMS: line_label_follow_retry.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: line_label_follow_retry.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: line_label_follow_retry.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: line_label_follow_retry.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: line_label_follow_retry.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: line_label_follow_retry.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: line_label_follow_retry.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: line_label_follow_retry.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # map diff --git a/msautotest/renderers/line_marker_pixmap.map b/msautotest/renderers/line_marker_pixmap.map index f17001cef1..a9f5fe98ea 100644 --- a/msautotest/renderers/line_marker_pixmap.map +++ b/msautotest/renderers/line_marker_pixmap.map @@ -1,7 +1,7 @@ -# RUN_PARMS: line_marker_pixmap.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: line_marker_pixmap.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: line_marker_pixmap.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: line_marker_pixmap.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: line_marker_pixmap.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: line_marker_pixmap.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: line_marker_pixmap.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: line_marker_pixmap.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # map diff --git a/msautotest/renderers/line_marker_svg.map b/msautotest/renderers/line_marker_svg.map index 64b9bafd14..1aaaa47169 100644 --- a/msautotest/renderers/line_marker_svg.map +++ b/msautotest/renderers/line_marker_svg.map @@ -1,7 +1,7 @@ -# RUN_PARMS: line_marker_svg.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: line_marker_svg.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: line_marker_svg.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: line_marker_svg.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: line_marker_svg.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: line_marker_svg.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: line_marker_svg.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: line_marker_svg.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # map diff --git a/msautotest/renderers/line_marker_truetype.map b/msautotest/renderers/line_marker_truetype.map index 32f2e6acb0..554305cfd3 100644 --- a/msautotest/renderers/line_marker_truetype.map +++ b/msautotest/renderers/line_marker_truetype.map @@ -1,7 +1,7 @@ -# RUN_PARMS: line_marker_truetype.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: line_marker_truetype.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: line_marker_truetype.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: line_marker_truetype.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: line_marker_truetype.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: line_marker_truetype.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: line_marker_truetype.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: line_marker_truetype.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # map diff --git a/msautotest/renderers/line_marker_vector.map b/msautotest/renderers/line_marker_vector.map index 15f4d94e27..5c3586c9fa 100644 --- a/msautotest/renderers/line_marker_vector.map +++ b/msautotest/renderers/line_marker_vector.map @@ -1,7 +1,7 @@ -# RUN_PARMS: line_marker_vector.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: line_marker_vector.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: line_marker_vector.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: line_marker_vector.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: line_marker_vector.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: line_marker_vector.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: line_marker_vector.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: line_marker_vector.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # map diff --git a/msautotest/renderers/line_offset.map b/msautotest/renderers/line_offset.map index f096c89d94..950b213bfe 100644 --- a/msautotest/renderers/line_offset.map +++ b/msautotest/renderers/line_offset.map @@ -1,7 +1,7 @@ -# RUN_PARMS: line_offset.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: line_offset.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: line_offset.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: line_offset.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: line_offset.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: line_offset.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: line_offset.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: line_offset.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # map diff --git a/msautotest/renderers/line_outlines.map b/msautotest/renderers/line_outlines.map new file mode 100644 index 0000000000..a4033077fd --- /dev/null +++ b/msautotest/renderers/line_outlines.map @@ -0,0 +1,123 @@ +# RUN_PARMS: outlines1.png [MAP2IMG] -m [MAPFILE] -o [RESULT] -l outlines1 +# RUN_PARMS: outlines2.png [MAP2IMG] -m [MAPFILE] -o [RESULT] -l outlines2 +# RUN_PARMS: outlines3.png [MAP2IMG] -m [MAPFILE] -o [RESULT] -l outlines3 +# RUN_PARMS: outlines4.png [MAP2IMG] -m [MAPFILE] -o [RESULT] -l outlines4 +# RUN_PARMS: outlines5.png [MAP2IMG] -m [MAPFILE] -o [RESULT] -l outlines5 +# RUN_PARMS: outlines6.png [MAP2IMG] -m [MAPFILE] -o [RESULT] -l outlines6 +# +MAP + NAME "lineoutlines" + STATUS ON + EXTENT -135.620276 -69.508628 173.802333 104.769497 + SIZE 400 300 + IMAGETYPE "png24" + SHAPEPATH "data" + # fixed width and outlinewidth + LAYER + NAME "outlines1" + TYPE LINE + STATUS OFF + DATA "world_testlines" + CLASS + STYLE + COLOR 150 150 150 + WIDTH 6 + OUTLINECOLOR 0 0 0 + OUTLINEWIDTH 1 + END + END + END + # using attribute binding for width + LAYER + NAME "outlines2" + TYPE LINE + STATUS OFF + CONNECTIONTYPE OGR + CONNECTION "data/world_testlines.shp" + DATA "SELECT 6 AS width FROM world_testlines" + CLASS + STYLE + COLOR 150 150 150 + WIDTH [width] + OUTLINECOLOR 0 0 0 + OUTLINEWIDTH 1 + END + END + END + # using attribute binding for outlinewidth + LAYER + NAME "outlines3" + TYPE LINE + STATUS ON + CONNECTIONTYPE OGR + CONNECTION "data/world_testlines.shp" + DATA "SELECT 1 AS outlinewidth FROM world_testlines" + CLASS + STYLE + COLOR 150 150 150 + WIDTH 6 + OUTLINECOLOR 0 0 0 + OUTLINEWIDTH [outlinewidth] + END + END + END + # use bindings for both + LAYER + NAME "outlines4" + TYPE LINE + STATUS OFF + CONNECTIONTYPE OGR + CONNECTION "data/world_testlines.shp" + DATA "SELECT 6 AS width, 1 AS outlinewidth FROM world_testlines" + CLASS + STYLE + COLOR 150 150 150 + WIDTH [width] + OUTLINECOLOR 0 0 0 + OUTLINEWIDTH [outlinewidth] + END + END + END + # use bindings for both - only the first style will have merged lines + LAYER + NAME "outlines5" + TYPE LINE + STATUS OFF + CONNECTIONTYPE OGR + CONNECTION "data/world_testlines.shp" + DATA "SELECT 4 AS width, 1 AS outlinewidth FROM world_testlines" + CLASS + STYLE + COLOR 255 234 0 + WIDTH 12 + OUTLINECOLOR 0 0 0 + OUTLINEWIDTH [outlinewidth] + END + STYLE + COLOR 100 100 100 + WIDTH [width] + END + END + END + # test for https://github.com/MapServer/MapServer/issues/3976 + LAYER + NAME "outlines6" + TYPE LINE + STATUS OFF + CONNECTIONTYPE OGR + CONNECTION "data/world_testlines.shp" + DATA "SELECT '255 0 0' AS color01, '0 0 255' AS color02 FROM world_testlines" + CLASS + STYLE + OFFSET 5 -99 + COLOR [color01] + WIDTH 10 + END + STYLE + OFFSET -5 -99 + COLOR [color02] + WIDTH 10 + END + END + END +END \ No newline at end of file diff --git a/msautotest/renderers/line_pattern.map b/msautotest/renderers/line_pattern.map index 1005ffeeb5..2b7b8fce6b 100644 --- a/msautotest/renderers/line_pattern.map +++ b/msautotest/renderers/line_pattern.map @@ -1,7 +1,7 @@ -# RUN_PARMS: line_pattern.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: line_pattern.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: line_pattern.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: line_pattern.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: line_pattern.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: line_pattern.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: line_pattern.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: line_pattern.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # map diff --git a/msautotest/renderers/line_pattern_offset.map b/msautotest/renderers/line_pattern_offset.map index dd4fc33dbb..8d45aedef2 100644 --- a/msautotest/renderers/line_pattern_offset.map +++ b/msautotest/renderers/line_pattern_offset.map @@ -1,7 +1,7 @@ -# RUN_PARMS: line_pattern_offset.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: line_pattern_offset.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: line_pattern_offset.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: line_pattern_offset.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: line_pattern_offset.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: line_pattern_offset.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: line_pattern_offset.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: line_pattern_offset.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # map diff --git a/msautotest/renderers/line_short_gap.map b/msautotest/renderers/line_short_gap.map index a3d7f812a2..b5717c2b3f 100644 --- a/msautotest/renderers/line_short_gap.map +++ b/msautotest/renderers/line_short_gap.map @@ -1,7 +1,7 @@ -# RUN_PARMS: line_short_gap.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: line_short_gap.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: line_short_gap.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: line_short_gap.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: line_short_gap.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: line_short_gap.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: line_short_gap.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: line_short_gap.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # MAP SIZE 100 100 diff --git a/msautotest/renderers/line_simple.map b/msautotest/renderers/line_simple.map index 8040eac3e4..e3e2aedf51 100644 --- a/msautotest/renderers/line_simple.map +++ b/msautotest/renderers/line_simple.map @@ -1,9 +1,9 @@ -# RUN_PARMS: line_simple.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: line_simple.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: line_simple.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: line_simple.json [SHP2IMG] -m [MAPFILE] -i json -o [RESULT] -# RUN_PARMS: line_simple.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] -# RUN_PARMS: line_simple.cairo.jpg [SHP2IMG] -m [MAPFILE] -i cairojpeg -o [RESULT] +# RUN_PARMS: line_simple.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: line_simple.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: line_simple.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: line_simple.json [MAP2IMG] -m [MAPFILE] -i json -o [RESULT] +# RUN_PARMS: line_simple.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: line_simple.cairo.jpg [MAP2IMG] -m [MAPFILE] -i cairojpeg -o [RESULT] # map diff --git a/msautotest/renderers/lots_of_text.map b/msautotest/renderers/lots_of_text.map index 3f3ea4a814..9dda3f5529 100644 --- a/msautotest/renderers/lots_of_text.map +++ b/msautotest/renderers/lots_of_text.map @@ -1,5 +1,5 @@ -# RUN_PARMS: lots_of_text.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: lots_of_text.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: lots_of_text.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: lots_of_text.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # map diff --git a/msautotest/renderers/marker_anchorpoint.map b/msautotest/renderers/marker_anchorpoint.map index d5aacdd0bc..2a1fcce03c 100644 --- a/msautotest/renderers/marker_anchorpoint.map +++ b/msautotest/renderers/marker_anchorpoint.map @@ -1,7 +1,7 @@ -# RUN_PARMS: marker_anchorpoint.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: marker_anchorpoint.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: marker_anchorpoint.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: marker_anchorpoint.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: marker_anchorpoint.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: marker_anchorpoint.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: marker_anchorpoint.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: marker_anchorpoint.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # # # entity-encoded text rendering test. diff --git a/msautotest/renderers/marker_pixmap.map b/msautotest/renderers/marker_pixmap.map index 6b25bae5a7..0af60ffc4e 100644 --- a/msautotest/renderers/marker_pixmap.map +++ b/msautotest/renderers/marker_pixmap.map @@ -1,7 +1,7 @@ -# RUN_PARMS: marker_pixmap.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: marker_pixmap.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: marker_pixmap.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: marker_pixmap.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: marker_pixmap.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: marker_pixmap.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: marker_pixmap.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: marker_pixmap.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # # # entity-encoded text rendering test. diff --git a/msautotest/renderers/mask.map b/msautotest/renderers/mask.map index c1e9f63d2b..a37e6ae113 100644 --- a/msautotest/renderers/mask.map +++ b/msautotest/renderers/mask.map @@ -1,5 +1,5 @@ -# RUN_PARMS: mask.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: mask.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: mask.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: mask.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # # # entity-encoded text rendering test. @@ -65,7 +65,7 @@ END LAYER - NAME "countours" + NAME "contours" TYPE polygon STATUS on DATA "world_testpoly" diff --git a/msautotest/renderers/mask_opacity.map b/msautotest/renderers/mask_opacity.map index f03509f6b7..beec77e665 100644 --- a/msautotest/renderers/mask_opacity.map +++ b/msautotest/renderers/mask_opacity.map @@ -1,5 +1,5 @@ -# RUN_PARMS: mask_opacity.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: mask_opacity.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: mask_opacity.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: mask_opacity.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # # # entity-encoded text rendering test. @@ -71,7 +71,7 @@ END LAYER - NAME "countours" + NAME "contours" TYPE polygon STATUS on DATA "world_testpoly" diff --git a/msautotest/renderers/multilabel-leader.map b/msautotest/renderers/multilabel-leader.map index 2d24a22b49..1b1e50c24d 100644 --- a/msautotest/renderers/multilabel-leader.map +++ b/msautotest/renderers/multilabel-leader.map @@ -1,7 +1,7 @@ -# RUN_PARMS: multilabel-leader.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: multilabel-leader.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: multilabel-leader.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: multilabel-leader.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: multilabel-leader.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: multilabel-leader.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: multilabel-leader.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: multilabel-leader.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # map diff --git a/msautotest/renderers/multilabel.map b/msautotest/renderers/multilabel.map index 142f7a846e..f56fbb2cb8 100644 --- a/msautotest/renderers/multilabel.map +++ b/msautotest/renderers/multilabel.map @@ -1,7 +1,7 @@ -# RUN_PARMS: multilabel.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: multilabel.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: multilabel.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: multilabel.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: multilabel.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: multilabel.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: multilabel.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: multilabel.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # # # Test multiple labels/symbols per feature diff --git a/msautotest/renderers/nodata_8bit.map b/msautotest/renderers/nodata_8bit.map index 21d505ffc4..64dbde4105 100644 --- a/msautotest/renderers/nodata_8bit.map +++ b/msautotest/renderers/nodata_8bit.map @@ -1,7 +1,7 @@ -# RUN_PARMS: nodata_8bit.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: nodata_8bit.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: nodata_8bit.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: nodata_8bit.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: nodata_8bit.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: nodata_8bit.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: nodata_8bit.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: nodata_8bit.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # # diff --git a/msautotest/renderers/plb_embed_legend.map b/msautotest/renderers/plb_embed_legend.map index d6fa7d3d94..962d6a4632 100644 --- a/msautotest/renderers/plb_embed_legend.map +++ b/msautotest/renderers/plb_embed_legend.map @@ -1,5 +1,5 @@ -# RUN_PARMS: plb_embed_legend.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: plb_embed_legend.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: plb_embed_legend.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: plb_embed_legend.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # # # Simple test of embedded legend support. @@ -39,20 +39,26 @@ LAYER CLASS NAME "Big" EXPRESSION ([AREA] >= 500000) - COLOR 255 0 0 - OUTLINECOLOR 0 0 0 + STYLE + COLOR 255 0 0 + OUTLINECOLOR 0 0 0 + END END CLASS NAME "Medium" EXPRESSION ([AREA] >= 100000 and [AREA] < 500000) - COLOR 0 255 0 - OUTLINECOLOR 0 0 0 + STYLE + COLOR 0 255 0 + OUTLINECOLOR 0 0 0 + END END CLASS NAME "Small" EXPRESSION ([AREA] < 100000) - COLOR 0 0 255 - OUTLINECOLOR 0 0 0 + STYLE + COLOR 0 0 255 + OUTLINECOLOR 0 0 0 + END END END diff --git a/msautotest/renderers/plb_embed_legend_rgba.map b/msautotest/renderers/plb_embed_legend_rgba.map index 1c9062c1b7..fc67353e01 100644 --- a/msautotest/renderers/plb_embed_legend_rgba.map +++ b/msautotest/renderers/plb_embed_legend_rgba.map @@ -1,5 +1,5 @@ -# RUN_PARMS: plb_embed_legend_rgba.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: plb_embed_legend_rgba.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: plb_embed_legend_rgba.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: plb_embed_legend_rgba.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # # # Simple test of embedded legend support. @@ -15,7 +15,15 @@ shapepath "../misc/data" IMAGETYPE png fontset "../misc/fonts.lst" -transparent on +OUTPUTFORMAT + DRIVER AGG/PNG + TRANSPARENT ON +END + +OUTPUTFORMAT + DRIVER CAIRO/PNG + TRANSPARENT ON +END LEGEND POSITION LR @@ -39,20 +47,26 @@ LAYER CLASS NAME "Big" EXPRESSION ([AREA] >= 500000) - COLOR 255 0 0 - OUTLINECOLOR 0 0 0 + STYLE + COLOR 255 0 0 + OUTLINECOLOR 0 0 0 + END END CLASS NAME "Medium" EXPRESSION ([AREA] >= 100000 and [AREA] < 500000) - COLOR 0 255 0 - OUTLINECOLOR 0 0 0 + STYLE + COLOR 0 255 0 + OUTLINECOLOR 0 0 0 + END END CLASS NAME "Small" EXPRESSION ([AREA] < 100000) - COLOR 0 0 255 - OUTLINECOLOR 0 0 0 + STYLE + COLOR 0 0 255 + OUTLINECOLOR 0 0 0 + END END END diff --git a/msautotest/renderers/plb_embed_legend_rgba_tr.map b/msautotest/renderers/plb_embed_legend_rgba_tr.map index a61a4fc18e..932c8e8138 100644 --- a/msautotest/renderers/plb_embed_legend_rgba_tr.map +++ b/msautotest/renderers/plb_embed_legend_rgba_tr.map @@ -1,5 +1,5 @@ -# RUN_PARMS: plb_embed_legend_rgba_tr.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: plb_embed_legend_rgba_tr.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: plb_embed_legend_rgba_tr.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: plb_embed_legend_rgba_tr.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # # # Simple test of embedded legend support. @@ -15,13 +15,21 @@ shapepath "../misc/data" IMAGETYPE png fontset "../misc/fonts.lst" -transparent on +OUTPUTFORMAT + DRIVER AGG/PNG + TRANSPARENT ON +END + +OUTPUTFORMAT + DRIVER CAIRO/PNG + TRANSPARENT ON +END LEGEND POSITION LR STATUS EMBED -postlabelcache true -TRANSPARENT ON + postlabelcache true + TRANSPARENT ON label type truetype color 0 0 0 @@ -39,20 +47,26 @@ LAYER CLASS NAME "Big" EXPRESSION ([AREA] >= 500000) - COLOR 255 0 0 - OUTLINECOLOR 0 0 0 + STYLE + COLOR 255 0 0 + OUTLINECOLOR 0 0 0 + END END CLASS NAME "Medium" EXPRESSION ([AREA] >= 100000 and [AREA] < 500000) - COLOR 0 255 0 - OUTLINECOLOR 0 0 0 + STYLE + COLOR 0 255 0 + OUTLINECOLOR 0 0 0 + END END CLASS NAME "Small" EXPRESSION ([AREA] < 100000) - COLOR 0 0 255 - OUTLINECOLOR 0 0 0 + STYLE + COLOR 0 0 255 + OUTLINECOLOR 0 0 0 + END END END diff --git a/msautotest/renderers/plb_embed_legend_tr.map b/msautotest/renderers/plb_embed_legend_tr.map index 33b81a553b..582763e894 100644 --- a/msautotest/renderers/plb_embed_legend_tr.map +++ b/msautotest/renderers/plb_embed_legend_tr.map @@ -1,5 +1,5 @@ -# RUN_PARMS: plb_embed_legend_tr.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: plb_embed_legend_tr.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: plb_embed_legend_tr.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: plb_embed_legend_tr.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # # # Simple test of embedded legend support. @@ -38,20 +38,26 @@ LAYER CLASS NAME "Big" EXPRESSION ([AREA] >= 500000) - COLOR 255 0 0 - OUTLINECOLOR 0 0 0 + STYLE + COLOR 255 0 0 + OUTLINECOLOR 0 0 0 + END END CLASS NAME "Medium" EXPRESSION ([AREA] >= 100000 and [AREA] < 500000) - COLOR 0 255 0 - OUTLINECOLOR 0 0 0 + STYLE + COLOR 0 255 0 + OUTLINECOLOR 0 0 0 + END END CLASS NAME "Small" EXPRESSION ([AREA] < 100000) - COLOR 0 0 255 - OUTLINECOLOR 0 0 0 + STYLE + COLOR 0 0 255 + OUTLINECOLOR 0 0 0 + END END END diff --git a/msautotest/renderers/point-polaroffset.map b/msautotest/renderers/point-polaroffset.map index ed066b134c..a7a2243de5 100644 --- a/msautotest/renderers/point-polaroffset.map +++ b/msautotest/renderers/point-polaroffset.map @@ -1,7 +1,7 @@ -# RUN_PARMS: point-polaroffset.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: point-polaroffset.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: point-polaroffset.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: point-polaroffset.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: point-polaroffset.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: point-polaroffset.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: point-polaroffset.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: point-polaroffset.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # MAP SIZE 150 100 diff --git a/msautotest/renderers/point_ellipse.map b/msautotest/renderers/point_ellipse.map index 7a8eb0d8ab..4dcf359376 100644 --- a/msautotest/renderers/point_ellipse.map +++ b/msautotest/renderers/point_ellipse.map @@ -1,13 +1,13 @@ -# RUN_PARMS: point_ellipse.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: point_ellipse.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: point_ellipse.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: point_ellipse.json [SHP2IMG] -m [MAPFILE] -i json -l symbol -o [RESULT] -# RUN_PARMS: point_ellipse.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: point_ellipse.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: point_ellipse.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: point_ellipse.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: point_ellipse.json [MAP2IMG] -m [MAPFILE] -i json -l symbol -o [RESULT] +# RUN_PARMS: point_ellipse.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] -# RUN_PARMS: gd_fallback.png [SHP2IMG] -m [MAPFILE] -i gdpng -o [RESULT] -# RUN_PARMS: gd_fallback_gif.png [SHP2IMG] -m [MAPFILE] -i gif -o [RESULT] -# RUN_PARMS: gd_fallback_pc256.png [SHP2IMG] -m [MAPFILE] -i gdpc256 -o [RESULT] -# RUN_PARMS: gd_fallback_jpeg.png [SHP2IMG] -m [MAPFILE] -i gdjpg -o [RESULT] +# RUN_PARMS: gd_fallback.png [MAP2IMG] -m [MAPFILE] -i gdpng -o [RESULT] +# RUN_PARMS: gd_fallback_gif.png [MAP2IMG] -m [MAPFILE] -i gif -o [RESULT] +# RUN_PARMS: gd_fallback_pc256.png [MAP2IMG] -m [MAPFILE] -i gdpc256 -o [RESULT] +# RUN_PARMS: gd_fallback_jpeg.png [MAP2IMG] -m [MAPFILE] -i gdjpg -o [RESULT] # # REQUIRES: OUTPUT=PNG # diff --git a/msautotest/renderers/point_pixmap.map b/msautotest/renderers/point_pixmap.map index 0a67f45aa2..d8d0e24a62 100644 --- a/msautotest/renderers/point_pixmap.map +++ b/msautotest/renderers/point_pixmap.map @@ -1,8 +1,8 @@ -# RUN_PARMS: point_pixmap.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: point_pixmap.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: point_pixmap.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: point_pixmap.json [SHP2IMG] -m [MAPFILE] -i json -l symbol -o [RESULT] -# RUN_PARMS: point_pixmap.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: point_pixmap.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: point_pixmap.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: point_pixmap.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: point_pixmap.json [MAP2IMG] -m [MAPFILE] -i json -l symbol -o [RESULT] +# RUN_PARMS: point_pixmap.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # # # entity-encoded text rendering test. diff --git a/msautotest/renderers/point_pixmap_gif.map b/msautotest/renderers/point_pixmap_gif.map index 3312cea53a..d64ce07ac6 100644 --- a/msautotest/renderers/point_pixmap_gif.map +++ b/msautotest/renderers/point_pixmap_gif.map @@ -1,7 +1,7 @@ -# RUN_PARMS: point_pixmap_gif.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: point_pixmap_gif.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: point_pixmap_gif.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: point_pixmap_gif.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: point_pixmap_gif.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: point_pixmap_gif.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: point_pixmap_gif.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: point_pixmap_gif.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # # # entity-encoded text rendering test. diff --git a/msautotest/renderers/point_svg.map b/msautotest/renderers/point_svg.map index a653b18d22..f37e6f0ba7 100644 --- a/msautotest/renderers/point_svg.map +++ b/msautotest/renderers/point_svg.map @@ -1,7 +1,7 @@ -# RUN_PARMS: point_svg.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: point_svg.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: point_svg.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: point_svg.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: point_svg.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: point_svg.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: point_svg.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: point_svg.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # # # entity-encoded text rendering test. @@ -54,6 +54,24 @@ LAYER END END +LAYER + NAME "too small symbol" + TYPE point + STATUS default + CLASS + NAME "test1" + STYLE + SYMBOL "svgicon" + SIZE 0.1 + END + END + FEATURE + POINTS + 200 200 + END + END +END + LAYER NAME "anchors" TYPE POINT diff --git a/msautotest/renderers/point_truetype.map b/msautotest/renderers/point_truetype.map index e7e4a5b34e..8e3644f1a6 100644 --- a/msautotest/renderers/point_truetype.map +++ b/msautotest/renderers/point_truetype.map @@ -1,7 +1,7 @@ -# RUN_PARMS: point_truetype.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: point_truetype.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: point_truetype.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: point_truetype.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: point_truetype.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: point_truetype.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: point_truetype.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: point_truetype.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # # # entity-encoded text rendering test. diff --git a/msautotest/renderers/point_vector.map b/msautotest/renderers/point_vector.map index c908f43f30..3759b9dfed 100644 --- a/msautotest/renderers/point_vector.map +++ b/msautotest/renderers/point_vector.map @@ -1,8 +1,8 @@ -# RUN_PARMS: point_vector.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: point_vector.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: point_vector.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: point_vector.json [SHP2IMG] -m [MAPFILE] -i json -l symbol -o [RESULT] -# RUN_PARMS: point_vector.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: point_vector.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: point_vector.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: point_vector.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: point_vector.json [MAP2IMG] -m [MAPFILE] -i json -l symbol -o [RESULT] +# RUN_PARMS: point_vector.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # # # entity-encoded text rendering test. diff --git a/msautotest/renderers/poly-label-multiline-pos-auto.map b/msautotest/renderers/poly-label-multiline-pos-auto.map index c5f919234f..5c40ea19fd 100644 --- a/msautotest/renderers/poly-label-multiline-pos-auto.map +++ b/msautotest/renderers/poly-label-multiline-pos-auto.map @@ -1,7 +1,7 @@ -# RUN_PARMS: poly-label-multiline-pos-auto.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: poly-label-multiline-pos-auto.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: poly-label-multiline-pos-auto.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: poly-label-multiline-pos-auto.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: poly-label-multiline-pos-auto.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: poly-label-multiline-pos-auto.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: poly-label-multiline-pos-auto.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: poly-label-multiline-pos-auto.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # map name "label-position-auto" diff --git a/msautotest/renderers/poly-label-pos-auto.map b/msautotest/renderers/poly-label-pos-auto.map index 73b49be4a4..5db991d5f7 100644 --- a/msautotest/renderers/poly-label-pos-auto.map +++ b/msautotest/renderers/poly-label-pos-auto.map @@ -1,7 +1,7 @@ -# RUN_PARMS: poly-label-pos-auto.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: poly-label-pos-auto.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: poly-label-pos-auto.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: poly-label-pos-auto.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: poly-label-pos-auto.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: poly-label-pos-auto.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: poly-label-pos-auto.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: poly-label-pos-auto.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # map name "label-position-auto" diff --git a/msautotest/renderers/poly_geomtransform_anchor.map b/msautotest/renderers/poly_geomtransform_anchor.map index f825d63d24..92fece3d79 100644 --- a/msautotest/renderers/poly_geomtransform_anchor.map +++ b/msautotest/renderers/poly_geomtransform_anchor.map @@ -1,7 +1,7 @@ -# RUN_PARMS: poly_geomtransform_anchor.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: poly_geomtransform_anchor.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: poly_geomtransform_anchor.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: poly_geomtransform_anchor.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: poly_geomtransform_anchor.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: poly_geomtransform_anchor.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: poly_geomtransform_anchor.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: poly_geomtransform_anchor.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # # # entity-encoded text rendering test. diff --git a/msautotest/renderers/polygon-as-line-offset.map b/msautotest/renderers/polygon-as-line-offset.map index fff542db00..fdc7cc2463 100644 --- a/msautotest/renderers/polygon-as-line-offset.map +++ b/msautotest/renderers/polygon-as-line-offset.map @@ -1,7 +1,7 @@ -# RUN_PARMS: polygon-as-line-offset.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: polygon-as-line-offset.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: polygon-as-line-offset.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: polygon-as-line-offset.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: polygon-as-line-offset.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: polygon-as-line-offset.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: polygon-as-line-offset.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: polygon-as-line-offset.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # # # entity-encoded text rendering test. @@ -45,6 +45,16 @@ LAYER WIDTH 1 GEOMTRANSFORM (buffer([shape], -1)) END + STYLE + OUTLINECOLOR 180 0 180 + WIDTH 1 + OFFSET 10 10 + END + STYLE + OUTLINECOLOR 180 0 180 + WIDTH 1 + OFFSET -10 -10 + END END END diff --git a/msautotest/renderers/polygon-as-line.map b/msautotest/renderers/polygon-as-line.map index 7eae8b03ef..03fd0fc800 100644 --- a/msautotest/renderers/polygon-as-line.map +++ b/msautotest/renderers/polygon-as-line.map @@ -1,7 +1,7 @@ -# RUN_PARMS: polygon-as-line.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: polygon-as-line.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: polygon-as-line.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: polygon-as-line.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: polygon-as-line.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: polygon-as-line.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: polygon-as-line.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: polygon-as-line.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # # # entity-encoded text rendering test. diff --git a/msautotest/renderers/polygon-hatch-dashed.map b/msautotest/renderers/polygon-hatch-dashed.map index 17839a861d..93e363161b 100644 --- a/msautotest/renderers/polygon-hatch-dashed.map +++ b/msautotest/renderers/polygon-hatch-dashed.map @@ -1,7 +1,7 @@ -# RUN_PARMS: polygon-hatch-dashed.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: polygon-hatch-dashed.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: polygon-hatch-dashed.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: polygon-hatch-dashed.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: polygon-hatch-dashed.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: polygon-hatch-dashed.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: polygon-hatch-dashed.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: polygon-hatch-dashed.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # # # entity-encoded text rendering test. diff --git a/msautotest/renderers/polygon-hatch.map b/msautotest/renderers/polygon-hatch.map index 20f1fb557e..d5e9cfb3cb 100644 --- a/msautotest/renderers/polygon-hatch.map +++ b/msautotest/renderers/polygon-hatch.map @@ -1,7 +1,7 @@ -# RUN_PARMS: polygon-hatch.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: polygon-hatch.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: polygon-hatch.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: polygon-hatch.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: polygon-hatch.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: polygon-hatch.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: polygon-hatch.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: polygon-hatch.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # # # entity-encoded text rendering test. diff --git a/msautotest/renderers/polygon-hex-alpha.map b/msautotest/renderers/polygon-hex-alpha.map index 10fa0ea9ac..0ba6c86c4b 100644 --- a/msautotest/renderers/polygon-hex-alpha.map +++ b/msautotest/renderers/polygon-hex-alpha.map @@ -1,4 +1,4 @@ -# RUN_PARMS: polygon-hex-alpha.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: polygon-hex-alpha.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] # # # REQUIRES: OUTPUT=PNG diff --git a/msautotest/renderers/polygon-pixmap.map b/msautotest/renderers/polygon-pixmap.map index a36dbb7dbb..65a98dfbf8 100644 --- a/msautotest/renderers/polygon-pixmap.map +++ b/msautotest/renderers/polygon-pixmap.map @@ -1,7 +1,7 @@ -# RUN_PARMS: polygon-pixmap.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: polygon-pixmap.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: polygon-pixmap.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: polygon-pixmap.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: polygon-pixmap.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: polygon-pixmap.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: polygon-pixmap.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: polygon-pixmap.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # # # entity-encoded text rendering test. diff --git a/msautotest/renderers/polygon-simple.map b/msautotest/renderers/polygon-simple.map index 7e27cc0636..63786e8413 100644 --- a/msautotest/renderers/polygon-simple.map +++ b/msautotest/renderers/polygon-simple.map @@ -1,8 +1,8 @@ -# RUN_PARMS: polygon-simple.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: polygon-simple.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: polygon-simple.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: polygon-simple.json [SHP2IMG] -m [MAPFILE] -i json -o [RESULT] -# RUN_PARMS: polygon-simple.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: polygon-simple.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: polygon-simple.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: polygon-simple.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: polygon-simple.json [MAP2IMG] -m [MAPFILE] -i json -o [RESULT] +# RUN_PARMS: polygon-simple.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # # # entity-encoded text rendering test. diff --git a/msautotest/renderers/polygon-ttf.map b/msautotest/renderers/polygon-ttf.map index 731c0185ea..f81e2dd3ab 100644 --- a/msautotest/renderers/polygon-ttf.map +++ b/msautotest/renderers/polygon-ttf.map @@ -1,7 +1,7 @@ -# RUN_PARMS: polygon-ttf.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: polygon-ttf.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: polygon-ttf.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: polygon-ttf.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: polygon-ttf.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: polygon-ttf.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: polygon-ttf.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: polygon-ttf.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # # # entity-encoded text rendering test. diff --git a/msautotest/renderers/polygon-vector.map b/msautotest/renderers/polygon-vector.map index d55b639777..17f03d3e70 100644 --- a/msautotest/renderers/polygon-vector.map +++ b/msautotest/renderers/polygon-vector.map @@ -1,7 +1,7 @@ -# RUN_PARMS: polygon-vector.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: polygon-vector.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: polygon-vector.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: polygon-vector.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: polygon-vector.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: polygon-vector.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: polygon-vector.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: polygon-vector.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # # # entity-encoded text rendering test. diff --git a/msautotest/renderers/polyline_no_clip.map b/msautotest/renderers/polyline_no_clip.map index 4aa664b914..6f1b1afd5f 100644 --- a/msautotest/renderers/polyline_no_clip.map +++ b/msautotest/renderers/polyline_no_clip.map @@ -1,4 +1,4 @@ -# RUN_PARMS: polyline_no_clip.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: polyline_no_clip.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] MAP DEBUG 5 @@ -82,7 +82,7 @@ MAP INITIALGAP 15 ANGLE 180 COLOR 255 0 0 - SYMBOL barb_warm + SYMBOL "barb_warm" GAP -45 SIZE 8 END @@ -94,7 +94,7 @@ MAP END STYLE COLOR 0 0 255 - SYMBOL barb_cold + SYMBOL "barb_cold" SIZE 12 INITIALGAP 45 GAP -45 diff --git a/msautotest/renderers/raster_simple.map b/msautotest/renderers/raster_simple.map index b08a5e8975..890f61d0b5 100644 --- a/msautotest/renderers/raster_simple.map +++ b/msautotest/renderers/raster_simple.map @@ -1,7 +1,7 @@ -# RUN_PARMS: raster_simple.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: raster_simple.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: raster_simple.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: raster_simple.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: raster_simple.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: raster_simple.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: raster_simple.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: raster_simple.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # # # Test use of 24bit images with a dummy class used to populate the legend. @@ -31,6 +31,7 @@ LAYER STATUS default DATA ../gdal/data/rgba.tif PROCESSING "BANDS=1,2,3" + PROCESSING "USE_MASK_BAND=NO" CLASS KEYIMAGE "data/grid.gif" END diff --git a/msautotest/renderers/raster_simple_opacity.map b/msautotest/renderers/raster_simple_opacity.map index abfde054c8..020fff0d54 100644 --- a/msautotest/renderers/raster_simple_opacity.map +++ b/msautotest/renderers/raster_simple_opacity.map @@ -1,7 +1,7 @@ -# RUN_PARMS: raster_simple_opacity.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: raster_simple_opacity.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: raster_simple_opacity.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: raster_simple_opacity.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: raster_simple_opacity.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: raster_simple_opacity.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: raster_simple_opacity.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: raster_simple_opacity.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # # # Test use of 24bit images with a dummy class used to populate the legend. @@ -31,6 +31,7 @@ LAYER STATUS default DATA ../gdal/data/rgba.tif PROCESSING "BANDS=1,2,3" + PROCESSING "USE_MASK_BAND=NO" COMPOSITE OPACITY 50 END diff --git a/msautotest/renderers/rasterlabel.map b/msautotest/renderers/rasterlabel.map new file mode 100644 index 0000000000..c4b1146bb5 --- /dev/null +++ b/msautotest/renderers/rasterlabel.map @@ -0,0 +1,37 @@ +# RUN_PARMS: rasterlabel.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] + +MAP + NAME 'test' + EXTENT -68.2072756 16.8083712 -63.9750679 19.7474043 + SIZE 900 500 + IMAGETYPE PNG + PROJECTION + "init=epsg:4326" + END + + WEB + IMAGEPATH "/tmp/" + IMAGEURL "/tmp/" + END + + LAYER + PROJECTION + "init=epsg:4326" + END + NAME "test" + TYPE POINT + CONNECTIONTYPE RASTERLABEL + STATUS DEFAULT + DATA data/temperature.tif + # PROCESSING "BANDS=1" + PROCESSING "LABEL_SPACING=40" + # PROCESSING "RESAMPLE=BILINEAR" + CLASS + TEXT (tostring([value],"%.1f")+"°") + LABEL + TYPE TRUETYPE + SIZE 7 + END # label + END # class + END +END diff --git a/msautotest/renderers/rasterlabel_datatypes.map b/msautotest/renderers/rasterlabel_datatypes.map new file mode 100644 index 0000000000..d63de7dbbc --- /dev/null +++ b/msautotest/renderers/rasterlabel_datatypes.map @@ -0,0 +1,48 @@ +# RUN_PARMS: rasterlabel_int32.png [MAP2IMG] -m [MAPFILE] -i png -l int32 -o [RESULT] +# RUN_PARMS: rasterlabel_float64.png [MAP2IMG] -m [MAPFILE] -i png -l float64 -o [RESULT] + +MAP + NAME 'test' + EXTENT 600029.81 628680.39 600319.81 628905.39 + SIZE 600 600 + IMAGETYPE PNG + PROJECTION + "init=epsg:2157" + END + + LAYER + PROJECTION + "init=epsg:2157" + END + NAME "int32" + TYPE POINT + CONNECTIONTYPE RASTERLABEL + STATUS OFF + DATA "data/int32.tif" + CLASS + TEXT (tostring([value],"%.0f")) + LABEL + TYPE TRUETYPE + SIZE 7 + END + END + END + + LAYER + PROJECTION + "init=epsg:2157" + END + NAME "float64" + TYPE POINT + CONNECTIONTYPE RASTERLABEL + STATUS OFF + DATA "data/float64.tif" + CLASS + TEXT (tostring([value],"%.0f")) + LABEL + TYPE TRUETYPE + SIZE 7 + END # label + END # class + END +END diff --git a/msautotest/renderers/reproj.map b/msautotest/renderers/reproj.map index 9f1244b51f..8efb726190 100644 --- a/msautotest/renderers/reproj.map +++ b/msautotest/renderers/reproj.map @@ -1,7 +1,7 @@ -# RUN_PARMS: reproj.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: reproj.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: reproj.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: reproj.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: reproj.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: reproj.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: reproj.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: reproj.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # # # Test supports for image reprojection. @@ -26,15 +26,6 @@ PROJECTION "datum=WGS84" END -IMAGETYPE png8_t - -OUTPUTFORMAT - NAME png8_t - DRIVER "GD/PNG" - IMAGEMODE PC256 - TRANSPARENT OFF -END - LAYER NAME grey TYPE raster diff --git a/msautotest/renderers/resolution.map b/msautotest/renderers/resolution.map index bf942575b4..d98bd58227 100644 --- a/msautotest/renderers/resolution.map +++ b/msautotest/renderers/resolution.map @@ -10,9 +10,9 @@ # RUN_PARMS: resolution_text_1.png [MAPSERV] QUERY_STRING="map.resolution=72&WIDTH=25&HEIGHT=25&map=[MAPFILE]&SERVICE=WMS&VERSION=1.1.0&REQUEST=GetMap&SRS=EPSG:4326&BBOX=0,0,100,100&FORMAT=image/png&STYLES=&LAYERS=text" > [RESULT_DEMIME] # RUN_PARMS: resolution_text_2.png [MAPSERV] QUERY_STRING="map.resolution=144&WIDTH=50&HEIGHT=50&map=[MAPFILE]&SERVICE=WMS&VERSION=1.1.0&REQUEST=GetMap&SRS=EPSG:4326&BBOX=0,0,100,100&FORMAT=image/png&STYLES=&LAYERS=text" > [RESULT_DEMIME] # RUN_PARMS: resolution_text_4.png [MAPSERV] QUERY_STRING="map.resolution=288&WIDTH=100&HEIGHT=100&map=[MAPFILE]&SERVICE=WMS&VERSION=1.1.0&REQUEST=GetMap&SRS=EPSG:4326&BBOX=0,0,100,100&FORMAT=image/png&STYLES=&LAYERS=text" > [RESULT_DEMIME] -# RUN_PARMS: legend_resolution_point_1.png [MAPSERV] QUERY_STRING="map.resolution=72&map.legend=keysize+20+20&WIDTH=25&HEIGHT=25&map=[MAPFILE]&SERVICE=WMS&VERSION=1.1.0&REQUEST=GetLegendGraphic&SRS=EPSG:4326&BBOX=0,0,100,100&FORMAT=image/png&STYLES=&LAYERS=point" > [RESULT_DEMIME] -# RUN_PARMS: legend_resolution_point_2.png [MAPSERV] QUERY_STRING="map.resolution=144&map.legend=keysize+40+40&WIDTH=50&HEIGHT=50&map=[MAPFILE]&SERVICE=WMS&VERSION=1.1.0&REQUEST=GetLegendGraphic&SRS=EPSG:4326&BBOX=0,0,100,100&FORMAT=image/png&STYLES=&LAYERS=point" > [RESULT_DEMIME] -# RUN_PARMS: legend_resolution_point_4.png [MAPSERV] QUERY_STRING="map.resolution=288&map.legend=keysize+80+80&WIDTH=100&HEIGHT=100&map=[MAPFILE]&SERVICE=WMS&VERSION=1.1.0&REQUEST=GetLegendGraphic&SRS=EPSG:4326&BBOX=0,0,100,100&FORMAT=image/png&STYLES=&LAYERS=point" > [RESULT_DEMIME] +# RUN_PARMS: legend_resolution_point_1.png [MAPSERV] QUERY_STRING="map.resolution=72&keysize=20+20&WIDTH=25&HEIGHT=25&map=[MAPFILE]&SERVICE=WMS&VERSION=1.1.0&REQUEST=GetLegendGraphic&SRS=EPSG:4326&BBOX=0,0,100,100&FORMAT=image/png&STYLES=&LAYERS=point" > [RESULT_DEMIME] +# RUN_PARMS: legend_resolution_point_2.png [MAPSERV] QUERY_STRING="map.resolution=144&keysize=40+40&WIDTH=50&HEIGHT=50&map=[MAPFILE]&SERVICE=WMS&VERSION=1.1.0&REQUEST=GetLegendGraphic&SRS=EPSG:4326&BBOX=0,0,100,100&FORMAT=image/png&STYLES=&LAYERS=point" > [RESULT_DEMIME] +# RUN_PARMS: legend_resolution_point_4.png [MAPSERV] QUERY_STRING="map.resolution=288&keysize=80+80&WIDTH=100&HEIGHT=100&map=[MAPFILE]&SERVICE=WMS&VERSION=1.1.0&REQUEST=GetLegendGraphic&SRS=EPSG:4326&BBOX=0,0,100,100&FORMAT=image/png&STYLES=&LAYERS=point" > [RESULT_DEMIME] # # REQUIRES: OUTPUT=PNG # diff --git a/msautotest/renderers/rgb_overlay.map b/msautotest/renderers/rgb_overlay.map index f97b2fd117..0440126a4a 100644 --- a/msautotest/renderers/rgb_overlay.map +++ b/msautotest/renderers/rgb_overlay.map @@ -1,7 +1,7 @@ -# RUN_PARMS: rgb_overlay.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: rgb_overlay.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: rgb_overlay.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: rgb_overlay.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: rgb_overlay.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: rgb_overlay.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: rgb_overlay.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: rgb_overlay.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # # # Tests overlaying an RGB image with a transparent value on a greyscale image diff --git a/msautotest/renderers/rgb_overlay_res.map b/msautotest/renderers/rgb_overlay_res.map index 57faa6d7c8..402ca864e9 100644 --- a/msautotest/renderers/rgb_overlay_res.map +++ b/msautotest/renderers/rgb_overlay_res.map @@ -1,7 +1,7 @@ -# RUN_PARMS: rgb_overlay_res.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: rgb_overlay_res.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: rgb_overlay_res.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: rgb_overlay_res.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: rgb_overlay_res.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: rgb_overlay_res.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: rgb_overlay_res.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: rgb_overlay_res.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # # # Tests overlaying an RGB image with a transparent value on a greyscale image diff --git a/msautotest/renderers/rgb_overlay_res_to8bit.map b/msautotest/renderers/rgb_overlay_res_to8bit.map index 0ff467e77f..4480272bba 100644 --- a/msautotest/renderers/rgb_overlay_res_to8bit.map +++ b/msautotest/renderers/rgb_overlay_res_to8bit.map @@ -1,7 +1,7 @@ -# RUN_PARMS: rgb_overlay_res_to8bit.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: rgb_overlay_res_to8bit.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: rgb_overlay_res_to8bit.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: rgb_overlay_res_to8bit.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: rgb_overlay_res_to8bit.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: rgb_overlay_res_to8bit.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: rgb_overlay_res_to8bit.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: rgb_overlay_res_to8bit.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # # # Tests overlaying an RGB image with a transparent value on a greyscale image @@ -27,15 +27,6 @@ PROJECTION "datum=WGS84" END -IMAGETYPE png8_local - -OUTPUTFORMAT - NAME png8_local - DRIVER "GD/PNG" - IMAGEMODE PC256 - TRANSPARENT OFF -END - LAYER NAME grey TYPE raster diff --git a/msautotest/renderers/rgb_overlay_res_to8bit_dithered.map b/msautotest/renderers/rgb_overlay_res_to8bit_dithered.map index 397ed158ee..107a0ccc59 100644 --- a/msautotest/renderers/rgb_overlay_res_to8bit_dithered.map +++ b/msautotest/renderers/rgb_overlay_res_to8bit_dithered.map @@ -1,7 +1,7 @@ -# RUN_PARMS: rgb_overlay_res_to8bit_dithered.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: rgb_overlay_res_to8bit_dithered.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: rgb_overlay_res_to8bit_dithered.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: rgb_overlay_res_to8bit_dithered.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: rgb_overlay_res_to8bit_dithered.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: rgb_overlay_res_to8bit_dithered.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: rgb_overlay_res_to8bit_dithered.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: rgb_overlay_res_to8bit_dithered.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # # # Tests overlaying an RGB image with a transparent value on a greyscale image @@ -25,15 +25,6 @@ PROJECTION "datum=WGS84" END -IMAGETYPE png8_t - -OUTPUTFORMAT - NAME png8_t - DRIVER "GD/PNG" - IMAGEMODE PC256 - TRANSPARENT OFF -END - LAYER NAME grey TYPE raster diff --git a/msautotest/renderers/rgba_overlay_res.map b/msautotest/renderers/rgba_overlay_res.map index c91317e932..7f75bf9da1 100644 --- a/msautotest/renderers/rgba_overlay_res.map +++ b/msautotest/renderers/rgba_overlay_res.map @@ -1,7 +1,7 @@ -# RUN_PARMS: rgba_overlay_res.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: rgba_overlay_res.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: rgba_overlay_res.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: rgba_overlay_res.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: rgba_overlay_res.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: rgba_overlay_res.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: rgba_overlay_res.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: rgba_overlay_res.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # # # Tests overlaying an RGBA image with on a greyscale image diff --git a/msautotest/renderers/run_test.py b/msautotest/renderers/run_test.py index ee65170a60..0933d7fde9 100755 --- a/msautotest/renderers/run_test.py +++ b/msautotest/renderers/run_test.py @@ -8,17 +8,17 @@ # ############################################################################### # Copyright (c) 2002, Frank Warmerdam -# +# # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: -# +# # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. -# +# # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL @@ -29,14 +29,19 @@ ############################################################################### import os -import pytest import sys -sys.path.append( '../pymod' ) +import pytest + +sys.path.append("../pymod") import mstestlib -@pytest.mark.parametrize('map,out_file,command', mstestlib.get_pytests(os.path.dirname(os.path.abspath(__file__)))) + +@pytest.mark.parametrize( + "map,out_file,command", + mstestlib.get_pytests(os.path.dirname(os.path.abspath(__file__))), +) def test(map, out_file, command, extra_args): mstestlib.run_pytest(map, out_file, command, extra_args) @@ -44,5 +49,5 @@ def test(map, out_file, command, extra_args): ############################################################################### # main() -if __name__ == '__main__': +if __name__ == "__main__": sys.exit(mstestlib.pytest_main()) diff --git a/msautotest/renderers/style-size.map b/msautotest/renderers/style-size.map new file mode 100644 index 0000000000..402f637c27 --- /dev/null +++ b/msautotest/renderers/style-size.map @@ -0,0 +1,62 @@ +# RUN_PARMS: style_size_binding.png [MAP2IMG] -m [MAPFILE] -l style_size_binding -o [RESULT] +# RUN_PARMS: style_size_fixed.png [MAP2IMG] -m [MAPFILE] -l style_size_fixed -o [RESULT] +# RUN_PARMS: style_size_expression.png [MAP2IMG] -m [MAPFILE] -l style_size_expression -o [RESULT] +# +# Test style size settings using fixed values, attribute bindings, and expressions +# + +MAP + IMAGETYPE "png" + SIZE 400 400 + EXTENT -.5 -.5 1.5 1.5 + FONTSET "../misc/fonts.lst" + SYMBOLSET "symbolset" + PROJECTION + "init=epsg:4326" + END + LAYER + NAME "style_size_fixed" + TYPE POINT + STATUS OFF + DATA "data/label_alias_offset.shp" + CLASS + STYLE + SYMBOL "circle" + SIZE 12 + COLOR 0 0 255 + END + END + END + LAYER + NAME "style_size_binding" + TYPE POINT + STATUS OFF + DATA "data/label_alias_offset.shp" + CLASS + STYLE + SYMBOL "circle" + # check any duplicate attribute bindings are ignored + SIZE [missing] + SIZE [priority] + COLOR 0 0 255 + END + END + END + LAYER + NAME "style_size_expression" + TYPE POINT + STATUS OFF + DATA "data/label_alias_offset.shp" + LABELITEM "label" + CLASS + STYLE + SYMBOL "circle" + # add a duplicate SIZE that will be ignored + # but check it is cleaned up correctly + SIZE ([priority] * 10) + SIZE ([priority] *2) + COLOR 0 0 255 + END + END + END +END diff --git a/msautotest/renderers/symbolrot.map b/msautotest/renderers/symbolrot.map index f33351f9a6..b6deaa0913 100755 --- a/msautotest/renderers/symbolrot.map +++ b/msautotest/renderers/symbolrot.map @@ -1,4 +1,4 @@ -# RUN_PARMS: symbolrot.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: symbolrot.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] # # Test support for rotating symbols with their map. diff --git a/msautotest/renderers/symbolrot_negative.map b/msautotest/renderers/symbolrot_negative.map new file mode 100644 index 0000000000..708912bd41 --- /dev/null +++ b/msautotest/renderers/symbolrot_negative.map @@ -0,0 +1,151 @@ +# RUN_PARMS: symbolrot.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] + +# +# Test support for rotating symbols counter-clockwise with their map. +# This should produce the same image as when the ANGLE values are clockwise +# +# REQUIRES: OUTPUT=PNG SUPPORTS=PROJ +# +MAP + NAME "test" + + EXTENT 520000 140000 540000 160000 + UNITS METERS + + IMAGECOLOR 255 255 255 + STATUS ON + SIZE 500 500 + + ANGLE -315 + + SYMBOL + NAME "v-line" + TYPE vector + FILLED false + POINTS + 0 0 + 5 10 + 10 0 + END # POINTS + END # SYMBOL + + IMAGETYPE png + + PROJECTION + "init=epsg:21781" + END + + LAYER + NAME line_layer + STATUS DEFAULT + TYPE LINE + PROJECTION + "init=epsg:21781" + END + + FEATURE + WKT "LINESTRING(530000 100000, 530000 200000)" + END + + CLASS + STYLE + WIDTH 1 + COLOR 0 0 0 + PATTERN 10 3 10 3 END + END + END + END + + LAYER + NAME pt_exactly_same_value_as_map_rotation_red + STATUS DEFAULT + TYPE POINT + PROJECTION + "init=epsg:21781" + END + + FEATURE + WKT "POINT(530000 151000)" + END + + CLASS + STYLE + SYMBOL "v-line" + WIDTH 5 + COLOR 0 0 255 + OUTLINECOLOR 32 32 32 + ANGLE -315 + END + END + END + + LAYER + NAME pt_almost_zero_rotation_yellow + STATUS DEFAULT + TYPE POINT + PROJECTION + "init=epsg:21781" + END + + FEATURE + WKT "POINT(530000 148000)" + END + + CLASS + STYLE + SYMBOL "v-line" + WIDTH 5 + COLOR 255 255 0 + OUTLINECOLOR 32 32 32 + ANGLE -359.9999 + END + END + END + + LAYER + NAME pt_other_value_as_map_rotation_green + STATUS DEFAULT + TYPE POINT + PROJECTION + "init=epsg:21781" + END + + FEATURE + WKT "POINT(530000 149500)" + END + + CLASS + STYLE + SYMBOL "v-line" + WIDTH 5 + COLOR 0 255 0 + OUTLINECOLOR 32 32 32 + ANGLE -337.5 + END + END + END + + LAYER + NAME pt_does_not_follow_map_rotation_blue + STATUS DEFAULT + TYPE POINT + PROJECTION + "init=epsg:21781" + END + + FEATURE + WKT "POINT(530000 145000)" + END + + CLASS + STYLE + SYMBOL "v-line" + WIDTH 5 + COLOR 255 0 0 + OUTLINECOLOR 32 32 32 + END + END + END + +END + diff --git a/msautotest/renderers/text-shaping.map b/msautotest/renderers/text-shaping.map index 7082c92313..a7280fd21f 100644 --- a/msautotest/renderers/text-shaping.map +++ b/msautotest/renderers/text-shaping.map @@ -1,7 +1,7 @@ -# RUN_PARMS: text_shaping_1.png [SHP2IMG] -e -7788846 2090453 -7782864 2095850 -l l1 -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: text_shaping_1.cairo.png [SHP2IMG] -e -7788846 2090453 -7782864 2095850 -l l1 -m [MAPFILE] -i cairopng -o [RESULT] -# RUN_PARMS: text_shaping_1.pdf [SHP2IMG] -e -7788846 2090453 -7782864 2095850 -l l1 -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: text_shaping_1.svg [SHP2IMG] -e -7788846 2090453 -7782864 2095850 -l l1 -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: text_shaping_1.png [MAP2IMG] -e -7788846 2090453 -7782864 2095850 -l l1 -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: text_shaping_1.cairo.png [MAP2IMG] -e -7788846 2090453 -7782864 2095850 -l l1 -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: text_shaping_1.pdf [MAP2IMG] -e -7788846 2090453 -7782864 2095850 -l l1 -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: text_shaping_1.svg [MAP2IMG] -e -7788846 2090453 -7782864 2095850 -l l1 -m [MAPFILE] -i svg -o [RESULT] map imagetype png diff --git a/msautotest/renderers/transparent_layer.map b/msautotest/renderers/transparent_layer.map index e7e2c3645e..605edb0741 100644 --- a/msautotest/renderers/transparent_layer.map +++ b/msautotest/renderers/transparent_layer.map @@ -1,7 +1,7 @@ -# RUN_PARMS: transparent_layer.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: transparent_layer.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: transparent_layer.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: transparent_layer.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: transparent_layer.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: transparent_layer.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: transparent_layer.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: transparent_layer.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # # # entity-encoded text rendering test. diff --git a/msautotest/renderers/utfgrid-escaping.map b/msautotest/renderers/utfgrid-escaping.map index 0af4bbd556..3c1532cc84 100644 --- a/msautotest/renderers/utfgrid-escaping.map +++ b/msautotest/renderers/utfgrid-escaping.map @@ -1,4 +1,4 @@ -# RUN_PARMS: utfgrid-escaping.json [SHP2IMG] -m [MAPFILE] -i json -o [RESULT] +# RUN_PARMS: utfgrid-escaping.json [MAP2IMG] -m [MAPFILE] -i json -o [RESULT] # # Test JSon escaping of item and data values. # diff --git a/msautotest/renderers/utfgrid_truetype_symbol.map b/msautotest/renderers/utfgrid_truetype_symbol.map index ac2ba40cf7..68dc962907 100644 --- a/msautotest/renderers/utfgrid_truetype_symbol.map +++ b/msautotest/renderers/utfgrid_truetype_symbol.map @@ -1,6 +1,6 @@ -# RUN_PARMS: utfgrid_truetype_symbol_labelcache.json [SHP2IMG] -m [MAPFILE] -l symbol-labelcache -i json -o [RESULT] -# RUN_PARMS: utfgrid_truetype_symbol_nolabelcache.json [SHP2IMG] -m [MAPFILE] -l symbol-nolabelcache -i json -o [RESULT] -# RUN_PARMS: utfgrid_truetype_symbol_rotation.json [SHP2IMG] -m [MAPFILE] -l symbol-rotation -i json -o [RESULT] +# RUN_PARMS: utfgrid_truetype_symbol_labelcache.json [MAP2IMG] -m [MAPFILE] -l symbol-labelcache -i json -o [RESULT] +# RUN_PARMS: utfgrid_truetype_symbol_nolabelcache.json [MAP2IMG] -m [MAPFILE] -l symbol-nolabelcache -i json -o [RESULT] +# RUN_PARMS: utfgrid_truetype_symbol_rotation.json [MAP2IMG] -m [MAPFILE] -l symbol-rotation -i json -o [RESULT] # # MAP @@ -72,7 +72,7 @@ LAYER END END -# This layer renders the symbol to the utfgrid whith a rotation +# This layer renders the symbol to the utfgrid with a rotation LAYER NAME "symbol-rotation" TYPE point diff --git a/msautotest/renderers/uvraster.map b/msautotest/renderers/uvraster.map index cf4d2012a6..53d2d7037a 100644 --- a/msautotest/renderers/uvraster.map +++ b/msautotest/renderers/uvraster.map @@ -1,7 +1,5 @@ -# RUN_PARMS: uvraster.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: uvraster.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: uvraster.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: uvraster.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: uvraster.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: uvraster.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] MAP NAME 'wind' diff --git a/msautotest/renderers/uvraster_reproj.map b/msautotest/renderers/uvraster_reproj.map index 725bf17b4a..1dbb79c6c6 100644 --- a/msautotest/renderers/uvraster_reproj.map +++ b/msautotest/renderers/uvraster_reproj.map @@ -1,7 +1,5 @@ -# RUN_PARMS: uvraster_reproj.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: uvraster_reproj.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: uvraster_reproj.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: uvraster_reproj.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: uvraster_reproj.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: uvraster_reproj.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] MAP NAME 'wind' diff --git a/msautotest/renderers/uvraster_reproj_expr_on_lon_lat.map b/msautotest/renderers/uvraster_reproj_expr_on_lon_lat.map new file mode 100644 index 0000000000..f96ce05722 --- /dev/null +++ b/msautotest/renderers/uvraster_reproj_expr_on_lon_lat.map @@ -0,0 +1,83 @@ +# RUN_PARMS: uvraster_reproj_expr_on_lon_lat.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] + +MAP + NAME 'wind' + EXTENT -180 -90 180 90 + SIZE 900 500 + IMAGETYPE PNG + PROJECTION + "init=epsg:4326" + END + + WEB + IMAGEPATH "/tmp/" + IMAGEURL "/tmp/" + END + + SYMBOL + NAME "horizline" + TYPE VECTOR + POINTS + 0 0 + 1 0 + END # points + END # symbol + SYMBOL + NAME "arrowhead" + TYPE vector + FILLED true + ANCHORPOINT 0 0.5 + POINTS + 0 2 + 4 1 + 0 0 + END # points + END # symbol + SYMBOL + NAME "arrowtail" + TYPE vector + FILLED true + ANCHORPOINT 1 0.5 # to shift the arrowtail + POINTS + 0 2 + 4 1 + 0 0 + -99 -99 + 0 1 + 4 1 + END # points + END # symbol + + LAYER + PROJECTION + "init=epsg:4326" + END + NAME "wind_1_2_band" + TYPE POINT + CONNECTIONTYPE UVRASTER + STATUS DEFAULT + DATA data/wind_12.tif + PROCESSING "BANDS=1,2" + PROCESSING "UV_SPACING=40" + PROCESSING "UV_SIZE_SCALE=0.5" + CLASS + # Filter on western northern quadrant + EXPRESSION ([lon] <= 0 AND [lat] >= 0) + STYLE + SYMBOL "horizline" + ANGLE [uv_angle] + SIZE [uv_length] + WIDTH 2 + COLOR 255 112 112 + END # style + STYLE + SYMBOL "arrowhead" + ANGLE [uv_angle] + SIZE 7 + COLOR 255 0 0 + POLAROFFSET [uv_length_2] [uv_angle] + END # style + END # + END + +END diff --git a/msautotest/renderers/wld_rotate.map b/msautotest/renderers/wld_rotate.map index 49b1a24da2..7bb76d85a3 100644 --- a/msautotest/renderers/wld_rotate.map +++ b/msautotest/renderers/wld_rotate.map @@ -1,7 +1,7 @@ -# RUN_PARMS: wld_rotate.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: wld_rotate.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: wld_rotate.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: wld_rotate.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: wld_rotate.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: wld_rotate.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: wld_rotate.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: wld_rotate.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # # # Tests support for images with non-northup world files. diff --git a/msautotest/renderers/wld_upsidedown.map b/msautotest/renderers/wld_upsidedown.map index 6719a80aef..ecb5813a27 100644 --- a/msautotest/renderers/wld_upsidedown.map +++ b/msautotest/renderers/wld_upsidedown.map @@ -1,7 +1,7 @@ -# RUN_PARMS: wld_upsidedown.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: wld_upsidedown.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: wld_upsidedown.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: wld_upsidedown.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: wld_upsidedown.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: wld_upsidedown.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: wld_upsidedown.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: wld_upsidedown.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # # # Tests support for upside-down images (like bug 1904). diff --git a/msautotest/renderers/wmsclient.map b/msautotest/renderers/wmsclient.map index 1e8244f053..f59b7c3b42 100644 --- a/msautotest/renderers/wmsclient.map +++ b/msautotest/renderers/wmsclient.map @@ -1,7 +1,7 @@ -# RUN_PARMS: wmsclient.png [SHP2IMG] -m [MAPFILE] -i png -o [RESULT] -# RUN_PARMS: wmsclient.pdf [SHP2IMG] -m [MAPFILE] -i pdf -o [RESULT] -# RUN_PARMS: wmsclient.svg [SHP2IMG] -m [MAPFILE] -i svg -o [RESULT] -# RUN_PARMS: wmsclient.cairo.png [SHP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] +# RUN_PARMS: wmsclient.png [MAP2IMG] -m [MAPFILE] -i png -o [RESULT] +# RUN_PARMS: wmsclient.pdf [MAP2IMG] -m [MAPFILE] -i pdf -o [RESULT] +# RUN_PARMS: wmsclient.svg [MAP2IMG] -m [MAPFILE] -i svg -o [RESULT] +# RUN_PARMS: wmsclient.cairo.png [MAP2IMG] -m [MAPFILE] -i cairopng -o [RESULT] # # # Simple test of WMS client support. @@ -27,7 +27,7 @@ LAYER TYPE RASTER STATUS DEFAULT #CONNECTION "http://mstest.tiles.osgeo.org/wms/vmap0?" - CONNECTION "http://demo.mapserver.org/cgi-bin/mapserv?map=/osgeo/mapserver/msautotest/world/world.map&" + CONNECTION "https://demo.mapserver.org/cgi-bin/msautotest?" CONNECTIONTYPE WMS METADATA "wms_srs" "EPSG:4326" diff --git a/msautotest/requirements.txt b/msautotest/requirements.txt index e40ee84847..9e06feab2a 100644 --- a/msautotest/requirements.txt +++ b/msautotest/requirements.txt @@ -1,9 +1,6 @@ -# Python 2.7 constraints -# more-itertools 6.0 no longer supporting Python 2.7 -more-itertools < 6.0.0; python_version < '3.0' -# pytest 5.0 no longer supporting Python 2.7 -pytest>=3.6.0,<5.0.0; python_version < '3.0' - -pytest>=3.6.0; python_version >= '3.0' +pytest pytest-sugar pytest-env +lxml +future +pyflakes \ No newline at end of file diff --git a/msautotest/sld/data/duplicated_namedstyles.sld b/msautotest/sld/data/duplicated_namedstyles.sld new file mode 100644 index 0000000000..6803c9eefb --- /dev/null +++ b/msautotest/sld/data/duplicated_namedstyles.sld @@ -0,0 +1,37 @@ + + + duplicate + + green + true + + + + + 3 + 0.5 + #00FF00 + + + + + + + + duplicate + + blue + + + + + 1 + 0.5 + #0000FF + + + + + + + \ No newline at end of file diff --git a/msautotest/sld/data/green.sld b/msautotest/sld/data/green.sld new file mode 100644 index 0000000000..2568e38de1 --- /dev/null +++ b/msautotest/sld/data/green.sld @@ -0,0 +1,18 @@ + + + green + + + + + + 3 + 0.5 + #00FF00 + + + + + + + \ No newline at end of file diff --git a/msautotest/sld/data/grid.gif b/msautotest/sld/data/grid.gif new file mode 100644 index 0000000000..3e9eac784e Binary files /dev/null and b/msautotest/sld/data/grid.gif differ diff --git a/msautotest/sld/data/mixed_styles.csv b/msautotest/sld/data/mixed_styles.csv new file mode 100644 index 0000000000..ba4a65e46f --- /dev/null +++ b/msautotest/sld/data/mixed_styles.csv @@ -0,0 +1,5 @@ +WKT,STYLE,comment +"LINESTRING(0.1 0.9,0.9 0.9)","test5#0000FF","red SLD line" +"LINESTRING(0.1 0.8,0.9 0.8)","PEN(c:#000000)","ogr style" +"LINESTRING(0.1 0.7,0.9 0.7)","missing5#00FF00"","green SLD line" +"LINESTRING(0.1 0.6,0.9 0.6)","STYLE WIDTH 1.5 COLOR 0 0 255 END","blue INLINE style" diff --git a/msautotest/sld/data/multi_namedstyles.sld b/msautotest/sld/data/multi_namedstyles.sld new file mode 100644 index 0000000000..60bfb6fce5 --- /dev/null +++ b/msautotest/sld/data/multi_namedstyles.sld @@ -0,0 +1,37 @@ + + + missing + + green + true + + + + + 3 + 0.5 + #00FF00 + + + + + + + + multi_namedstyles + + blue + + + + + 1 + 0.5 + #0000FF + + + + + + + \ No newline at end of file diff --git a/msautotest/sld/data/nomatch_namedstyles.sld b/msautotest/sld/data/nomatch_namedstyles.sld new file mode 100644 index 0000000000..6005fde389 --- /dev/null +++ b/msautotest/sld/data/nomatch_namedstyles.sld @@ -0,0 +1,20 @@ + + + no_matching_layer + + green + true + + + + + 3 + 0.5 + #00FF00 + + + + + + + \ No newline at end of file diff --git a/msautotest/sld/data/raster.xml b/msautotest/sld/data/raster.xml new file mode 100644 index 0000000000..bb7752f1cd --- /dev/null +++ b/msautotest/sld/data/raster.xml @@ -0,0 +1,191 @@ + + + + test + + bg + + + + + + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msautotest/sld/data/twostyles.sld b/msautotest/sld/data/twostyles.sld new file mode 100644 index 0000000000..bf57a823a8 --- /dev/null +++ b/msautotest/sld/data/twostyles.sld @@ -0,0 +1,34 @@ + + + lline + + green + true + + + + + 3 + 0.5 + #00FF00 + + + + + + + blue + + + + + 1 + 0.5 + #0000FF + + + + + + + \ No newline at end of file diff --git a/msautotest/sld/expected/map_label.png b/msautotest/sld/expected/map_label.png index 3aaf39bd19..d11e21ea91 100644 Binary files a/msautotest/sld/expected/map_label.png and b/msautotest/sld/expected/map_label.png differ diff --git a/msautotest/sld/expected/map_linemark.png b/msautotest/sld/expected/map_linemark.png index 13ef5b8f3b..8c9f35876b 100644 Binary files a/msautotest/sld/expected/map_linemark.png and b/msautotest/sld/expected/map_linemark.png differ diff --git a/msautotest/sld/expected/map_style_text.png b/msautotest/sld/expected/map_style_text.png index db2a290105..b3cd54666e 100644 Binary files a/msautotest/sld/expected/map_style_text.png and b/msautotest/sld/expected/map_style_text.png differ diff --git a/msautotest/sld/expected/sld_else_fallback.png b/msautotest/sld/expected/sld_else_fallback.png new file mode 100644 index 0000000000..925b5b0aff Binary files /dev/null and b/msautotest/sld/expected/sld_else_fallback.png differ diff --git a/msautotest/sld/expected/sld_else_from_sld.png b/msautotest/sld/expected/sld_else_from_sld.png new file mode 100644 index 0000000000..925b5b0aff Binary files /dev/null and b/msautotest/sld/expected/sld_else_from_sld.png differ diff --git a/msautotest/sld/expected/sld_else_nofallback.png b/msautotest/sld/expected/sld_else_nofallback.png new file mode 100644 index 0000000000..5846bca631 Binary files /dev/null and b/msautotest/sld/expected/sld_else_nofallback.png differ diff --git a/msautotest/sld/expected/sld_label_function.png b/msautotest/sld/expected/sld_label_function.png index 924df2d8b4..8045eda0d5 100644 Binary files a/msautotest/sld/expected/sld_label_function.png and b/msautotest/sld/expected/sld_label_function.png differ diff --git a/msautotest/sld/expected/sld_label_literal.png b/msautotest/sld/expected/sld_label_literal.png index 54278b7c9e..a5b6c2c8ba 100644 Binary files a/msautotest/sld/expected/sld_label_literal.png and b/msautotest/sld/expected/sld_label_literal.png differ diff --git a/msautotest/sld/expected/sld_label_mixed.png b/msautotest/sld/expected/sld_label_mixed.png index 8bdfcc9adc..91fc80428b 100644 Binary files a/msautotest/sld/expected/sld_label_mixed.png and b/msautotest/sld/expected/sld_label_mixed.png differ diff --git a/msautotest/sld/expected/sld_label_property.png b/msautotest/sld/expected/sld_label_property.png index d703498dc3..6bb65d17da 100644 Binary files a/msautotest/sld/expected/sld_label_property.png and b/msautotest/sld/expected/sld_label_property.png differ diff --git a/msautotest/sld/expected/sld_label_raw.png b/msautotest/sld/expected/sld_label_raw.png index 54278b7c9e..a5b6c2c8ba 100644 Binary files a/msautotest/sld/expected/sld_label_raw.png and b/msautotest/sld/expected/sld_label_raw.png differ diff --git a/msautotest/sld/expected/sld_linemark.png b/msautotest/sld/expected/sld_linemark.png index 13ef5b8f3b..8c9f35876b 100644 Binary files a/msautotest/sld/expected/sld_linemark.png and b/msautotest/sld/expected/sld_linemark.png differ diff --git a/msautotest/sld/expected/sld_named_userstyle_raster.png b/msautotest/sld/expected/sld_named_userstyle_raster.png new file mode 100644 index 0000000000..e977386b4b Binary files /dev/null and b/msautotest/sld/expected/sld_named_userstyle_raster.png differ diff --git a/msautotest/sld/expected/sld_styleitem_attribute.png b/msautotest/sld/expected/sld_styleitem_attribute.png new file mode 100644 index 0000000000..b747e50528 Binary files /dev/null and b/msautotest/sld/expected/sld_styleitem_attribute.png differ diff --git a/msautotest/sld/expected/sld_styleitem_file.png b/msautotest/sld/expected/sld_styleitem_file.png new file mode 100644 index 0000000000..c48d782640 Binary files /dev/null and b/msautotest/sld/expected/sld_styleitem_file.png differ diff --git a/msautotest/sld/expected/sld_styleitem_file_blue.png b/msautotest/sld/expected/sld_styleitem_file_blue.png new file mode 100644 index 0000000000..e560ffca83 Binary files /dev/null and b/msautotest/sld/expected/sld_styleitem_file_blue.png differ diff --git a/msautotest/sld/expected/sld_styleitem_file_duplicate.png b/msautotest/sld/expected/sld_styleitem_file_duplicate.png new file mode 100644 index 0000000000..c48d782640 Binary files /dev/null and b/msautotest/sld/expected/sld_styleitem_file_duplicate.png differ diff --git a/msautotest/sld/expected/sld_styleitem_file_getstyle.xml b/msautotest/sld/expected/sld_styleitem_file_getstyle.xml new file mode 100644 index 0000000000..3aa239e1cb --- /dev/null +++ b/msautotest/sld/expected/sld_styleitem_file_getstyle.xml @@ -0,0 +1,20 @@ + + +green + + + +green#0 + + +#00ff00 +0.50 +3.00 + + + + + + + + diff --git a/msautotest/sld/expected/sld_styleitem_file_getstyle_twostyles.xml b/msautotest/sld/expected/sld_styleitem_file_getstyle_twostyles.xml new file mode 100644 index 0000000000..28ab92fca5 --- /dev/null +++ b/msautotest/sld/expected/sld_styleitem_file_getstyle_twostyles.xml @@ -0,0 +1,37 @@ + + +twostyles + +green +true + + +lline#0 + + +#00ff00 +0.50 +3.00 + + + + + + +blue + + +lline#1 + + +#0000ff +0.50 +1.00 + + + + + + + + diff --git a/msautotest/sld/expected/sld_styleitem_file_getstyle_twostyles_green.xml b/msautotest/sld/expected/sld_styleitem_file_getstyle_twostyles_green.xml new file mode 100644 index 0000000000..28ab92fca5 --- /dev/null +++ b/msautotest/sld/expected/sld_styleitem_file_getstyle_twostyles_green.xml @@ -0,0 +1,37 @@ + + +twostyles + +green +true + + +lline#0 + + +#00ff00 +0.50 +3.00 + + + + + + +blue + + +lline#1 + + +#0000ff +0.50 +1.00 + + + + + + + + diff --git a/msautotest/sld/expected/sld_styleitem_file_green.png b/msautotest/sld/expected/sld_styleitem_file_green.png new file mode 100644 index 0000000000..c48d782640 Binary files /dev/null and b/msautotest/sld/expected/sld_styleitem_file_green.png differ diff --git a/msautotest/sld/expected/sld_styleitem_file_legend.png b/msautotest/sld/expected/sld_styleitem_file_legend.png new file mode 100644 index 0000000000..7667ea4f44 Binary files /dev/null and b/msautotest/sld/expected/sld_styleitem_file_legend.png differ diff --git a/msautotest/sld/expected/sld_styleitem_file_missing.png b/msautotest/sld/expected/sld_styleitem_file_missing.png new file mode 100644 index 0000000000..53618b774e Binary files /dev/null and b/msautotest/sld/expected/sld_styleitem_file_missing.png differ diff --git a/msautotest/sld/expected/sld_styleitem_file_namedstyle_default.png b/msautotest/sld/expected/sld_styleitem_file_namedstyle_default.png new file mode 100644 index 0000000000..e560ffca83 Binary files /dev/null and b/msautotest/sld/expected/sld_styleitem_file_namedstyle_default.png differ diff --git a/msautotest/sld/expected/sld_styleitem_file_namedstyle_first.png b/msautotest/sld/expected/sld_styleitem_file_namedstyle_first.png new file mode 100644 index 0000000000..c48d782640 Binary files /dev/null and b/msautotest/sld/expected/sld_styleitem_file_namedstyle_first.png differ diff --git a/msautotest/sld/expected/sld_styleitem_file_no_match.png b/msautotest/sld/expected/sld_styleitem_file_no_match.png new file mode 100644 index 0000000000..a9f7e05deb Binary files /dev/null and b/msautotest/sld/expected/sld_styleitem_file_no_match.png differ diff --git a/msautotest/sld/expected/sld_styleitem_file_override.png b/msautotest/sld/expected/sld_styleitem_file_override.png new file mode 100644 index 0000000000..1133519ea5 Binary files /dev/null and b/msautotest/sld/expected/sld_styleitem_file_override.png differ diff --git a/msautotest/sld/expected/sld_styleitem_file_raster.png b/msautotest/sld/expected/sld_styleitem_file_raster.png new file mode 100644 index 0000000000..563aa6d7d6 Binary files /dev/null and b/msautotest/sld/expected/sld_styleitem_file_raster.png differ diff --git a/msautotest/sld/expected/sld_styleitem_file_twostyles_legend_blue.png b/msautotest/sld/expected/sld_styleitem_file_twostyles_legend_blue.png new file mode 100644 index 0000000000..d607356455 Binary files /dev/null and b/msautotest/sld/expected/sld_styleitem_file_twostyles_legend_blue.png differ diff --git a/msautotest/sld/expected/sld_styleitem_file_twostyles_legend_green.png b/msautotest/sld/expected/sld_styleitem_file_twostyles_legend_green.png new file mode 100644 index 0000000000..0943b38fa2 Binary files /dev/null and b/msautotest/sld/expected/sld_styleitem_file_twostyles_legend_green.png differ diff --git a/msautotest/sld/expected/sld_url_linemark.png b/msautotest/sld/expected/sld_url_linemark.png index 13ef5b8f3b..8c9f35876b 100644 Binary files a/msautotest/sld/expected/sld_url_linemark.png and b/msautotest/sld/expected/sld_url_linemark.png differ diff --git a/msautotest/sld/label.map b/msautotest/sld/label.map index 6e986e6abe..8ceb325bee 100644 --- a/msautotest/sld/label.map +++ b/msautotest/sld/label.map @@ -5,7 +5,7 @@ # # --- MapServer Message -loadOutputFormat(): General error message. OUTPUTFORMAT (nocreatedatasource) clause references driver (OGR/SDTS), but this driver isn't configured. -msInitDefaultOGROutputFormat(): General error message. OGR `SDTS' driver does not support output. +MapServer Message + +loadOutputFormat(): General error message. OUTPUTFORMAT (nocreatedatasource) clause references driver (OGR/SXF), but this driver isn't configured. +msInitDefaultOGROutputFormat(): General error message. OGR `SXF' driver does not support output. \ No newline at end of file diff --git a/msautotest/wxs/expected/wfs_ogr_gpkg_expose_fid.xml b/msautotest/wxs/expected/wfs_ogr_gpkg_expose_fid.xml new file mode 100644 index 0000000000..bab62f6350 --- /dev/null +++ b/msautotest/wxs/expected/wfs_ogr_gpkg_expose_fid.xml @@ -0,0 +1,35 @@ +Content-Type: text/xml; charset=UTF-8 + + + + + + 2.000000,49.000000 2.000000,49.000000 + + + + + + + 2.000000,49.000000 2.000000,49.000000 + + + + + 2.000000,49.000000 + + + 1 + some place in France + 1 + + + + diff --git a/msautotest/wxs/expected/wfs_ogr_gpkg_filter_intersects_point.xml b/msautotest/wxs/expected/wfs_ogr_gpkg_filter_intersects_point.xml new file mode 100644 index 0000000000..4e13869970 --- /dev/null +++ b/msautotest/wxs/expected/wfs_ogr_gpkg_filter_intersects_point.xml @@ -0,0 +1,34 @@ +Content-Type: text/xml; charset=UTF-8 + + + + + + 0.000000,0.000000 1.000000,1.000000 + + + + + + + 0.000000,0.000000 1.000000,1.000000 + + + + + 1.000000,0.000000 0.000000,1.000000 + + + 1 + LINESTRING(1 0,0 1) + + + + diff --git a/msautotest/wxs/expected/wfs_ogr_gpkg_issue_6325.xml b/msautotest/wxs/expected/wfs_ogr_gpkg_issue_6325.xml new file mode 100644 index 0000000000..482310cb21 --- /dev/null +++ b/msautotest/wxs/expected/wfs_ogr_gpkg_issue_6325.xml @@ -0,0 +1,36 @@ +Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 + + + + + + 0.000000 0.000000 + 10.000000 10.000000 + + + + + + + 0.000000 0.000000 + 10.000000 10.000000 + + + + + 0.000000 0.000000 10.000000 10.000000 + + + 2 + LINESTRING(0 0,10 10) + + + + diff --git a/msautotest/wxs/expected/wfs_ogr_gpkg_pagination_4326.xml b/msautotest/wxs/expected/wfs_ogr_gpkg_pagination_4326.xml new file mode 100644 index 0000000000..b284377fa2 --- /dev/null +++ b/msautotest/wxs/expected/wfs_ogr_gpkg_pagination_4326.xml @@ -0,0 +1,148 @@ +Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 + + + + + + 44.020359 -64.732816 + 44.971547 -62.513078 + + + + + + + + 44.911800 -62.513078 + 44.911800 -62.513078 + + + + + 44.911800 -62.513078 + + + 0 + 0 + 10 + 1 + CBIKA + Sheet Harbour + + + + + 12 + 011D15 + 445500 + 623200 + 1209036 + 0 + 2 + + + + + + + 44.971547 -64.190057 + 44.971547 -64.190057 + + + + + 44.971547 -64.190057 + + + 0 + 0 + 114 + 2 + CBPAK + "Wind"sor + + + + + 12 + 021A16 + 445900 + 640800 + 1208002 + 0 + 2 + + + + + + + 44.375794 -64.333577 + 44.375794 -64.333577 + + + + + 44.375794 -64.333577 + + + 0 + 0 + 115 + 2 + CAWAZ + Lunenburg + + + + + 12 + 021A08 + 442300 + 641900 + 1206006 + 0 + 2 + + + + + + + 44.020359 -64.732816 + 44.020359 -64.732816 + + + + + 44.020359 -64.732816 + + + 0 + 0 + 116 + 2 + CAUWZ + Liverpool + + + + + 12 + 021A02 + 440200 + 644300 + 1204006 + 0 + 2 + + + + diff --git a/msautotest/wxs/expected/wfs_ogr_gpkg_pagination_4326_2.xml b/msautotest/wxs/expected/wfs_ogr_gpkg_pagination_4326_2.xml new file mode 100644 index 0000000000..c7f55e41db --- /dev/null +++ b/msautotest/wxs/expected/wfs_ogr_gpkg_pagination_4326_2.xml @@ -0,0 +1,116 @@ +Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 + + + + + + 44.365195 -64.563218 + 44.682792 -63.570040 + + + + + + + + 44.365195 -64.563218 + 44.365195 -64.563218 + + + + + 44.365195 -64.563218 + + + 0 + 0 + 268 + 3 + CAFBR + Bridgewater + + + + + 12 + 021A07 + 442300 + 643100 + 1206004 + 0 + 3 + + + + + + + 44.682792 -63.570040 + 44.682792 -63.570040 + + + + + 44.682792 -63.570040 + + + 0 + 0 + 392 + 4 + CAIYJ + Dartmouth + + + + + 12 + 011D12 + 444000 + 633400 + 1209022 + 0 + 5 + + + + + + + 44.615583 -63.692011 + 44.615583 -63.692011 + + + + + 44.615583 -63.692011 + + + 0 + 0 + 463 + 96 + CAPHL + Halifax + + + + + 12 + 011D12 + 443900 + 633600 + 1209021 + 2 + 6 + + + + diff --git a/msautotest/wxs/expected/wfs_ogr_gpkg_propertyisnull.xml b/msautotest/wxs/expected/wfs_ogr_gpkg_propertyisnull.xml new file mode 100644 index 0000000000..11d1e74dce --- /dev/null +++ b/msautotest/wxs/expected/wfs_ogr_gpkg_propertyisnull.xml @@ -0,0 +1,35 @@ +Content-Type: text/xml; charset=UTF-8 + + + + + + 2.000000,49.000000 2.000000,49.000000 + + + + + + + 2.000000,49.000000 2.000000,49.000000 + + + + + 2.000000,49.000000 + + + 1 + some place in France + + + + + diff --git a/msautotest/wxs/expected/wfs_ogr_native_sql_36.xml b/msautotest/wxs/expected/wfs_ogr_native_sql_36.xml index 3c6fee5a41..5a76adbc80 100644 --- a/msautotest/wxs/expected/wfs_ogr_native_sql_36.xml +++ b/msautotest/wxs/expected/wfs_ogr_native_sql_36.xml @@ -1,9 +1,38 @@ Content-Type: text/xml; charset=UTF-8 - - -msWFSGetFeature(): WFS server error. FLTApplyFilterToLayer() failed -msOGRFileWhichShapes(): OGR error. ExecuteSQL() failed. Check logs. - - + + + + 643513.360000,4896928.190000 643513.360000,4896928.190000 + + + + + + + + 643513.360000,4896928.190000 643513.360000,4896928.190000 + + + + + 643513.360000,4896928.190000 + + + Fanano + 2910 + 1 + 0 + 0 + + + + diff --git a/msautotest/wxs/expected/wfs_ogr_native_sql_37.xml b/msautotest/wxs/expected/wfs_ogr_native_sql_37.xml index 173940f175..48981469d5 100644 --- a/msautotest/wxs/expected/wfs_ogr_native_sql_37.xml +++ b/msautotest/wxs/expected/wfs_ogr_native_sql_37.xml @@ -12,8 +12,8 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 next="http://localhost/path/to/wfs_simple?SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAMES=towns&COUNT=1&STARTINDEX=3"> - 666678.76000 4876424.90000 - 666678.76000 4876424.90000 + 666678.760000 4876424.900000 + 666678.760000 4876424.900000 @@ -21,13 +21,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 666678.76000 4876424.90000 - 666678.76000 4876424.90000 + 666678.760000 4876424.900000 + 666678.760000 4876424.900000 - 666678.76000 4876424.90000 + 666678.760000 4876424.900000 Cantagallo diff --git a/msautotest/wxs/expected/wfs_ogr_native_sql_38.xml b/msautotest/wxs/expected/wfs_ogr_native_sql_38.xml index 595b51c57b..75bb46b4f7 100644 --- a/msautotest/wxs/expected/wfs_ogr_native_sql_38.xml +++ b/msautotest/wxs/expected/wfs_ogr_native_sql_38.xml @@ -10,8 +10,8 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 timeStamp="" numberMatched="unknown" numberReturned="1"> - 656907.12000 4886687.84000 - 656907.12000 4886687.84000 + 656907.120000 4886687.840000 + 656907.120000 4886687.840000 @@ -19,13 +19,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 656907.12000 4886687.84000 - 656907.12000 4886687.84000 + 656907.120000 4886687.840000 + 656907.120000 4886687.840000 - 656907.12000 4886687.84000 + 656907.120000 4886687.840000 Granaglione diff --git a/msautotest/wxs/expected/wfs_ogr_native_sql_40.xml b/msautotest/wxs/expected/wfs_ogr_native_sql_40.xml index f6df76be44..cbf4262126 100644 --- a/msautotest/wxs/expected/wfs_ogr_native_sql_40.xml +++ b/msautotest/wxs/expected/wfs_ogr_native_sql_40.xml @@ -8,8 +8,32 @@ Content-Type: text/xml; subtype=gml/3.1.1; charset=UTF-8 xmlns:ogc="http://www.opengis.net/ogc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://mapserver.gis.umn.edu/mapserver http://localhost/path/to/wfs_simple?SERVICE=WFS&VERSION=1.1.0&REQUEST=DescribeFeatureType&TYPENAME=towns_with_null&OUTPUTFORMAT=text/xml;%20subtype=gml/3.1.1 http://www.opengis.net/wfs http://schemas.opengis.net/wfs/1.1.0/wfs.xsd"> - - missing - + + + 653901.530000 4866278.050000 + 653901.530000 4866278.050000 + + + + + + + + 653901.530000 4866278.050000 + 653901.530000 4866278.050000 + + + + + 653901.530000 4866278.050000 + + + + 84274 + 1 + 1 + 0 + + diff --git a/msautotest/wxs/expected/wfs_ogr_native_sql_41.xml b/msautotest/wxs/expected/wfs_ogr_native_sql_41.xml index 53226d4adf..b171c4b422 100644 --- a/msautotest/wxs/expected/wfs_ogr_native_sql_41.xml +++ b/msautotest/wxs/expected/wfs_ogr_native_sql_41.xml @@ -10,7 +10,7 @@ Content-Type: text/xml; subtype=gml/2.1.2; charset=UTF-8 timeStamp="" numberMatched="41" numberReturned="41"> - 637137.64000,4865176.12000 710195.30000,4905916.47000 + 637137.640000,4865176.120000 710195.300000,4905916.470000 @@ -18,12 +18,12 @@ Content-Type: text/xml; subtype=gml/2.1.2; charset=UTF-8 - 679352.61000,4874600.65000 679352.61000,4874600.65000 + 679352.610000,4874600.650000 679352.610000,4874600.650000 - 679352.61000,4874600.65000 + 679352.610000,4874600.650000 Barberino di Mugello @@ -37,12 +37,12 @@ Content-Type: text/xml; subtype=gml/2.1.2; charset=UTF-8 - 691242.09000,4869675.97000 691242.09000,4869675.97000 + 691242.090000,4869675.970000 691242.090000,4869675.970000 - 691242.09000,4869675.97000 + 691242.090000,4869675.970000 Borgo San Lorenzo @@ -56,12 +56,12 @@ Content-Type: text/xml; subtype=gml/2.1.2; charset=UTF-8 - 706612.32000,4905916.47000 706612.32000,4905916.47000 + 706612.320000,4905916.470000 706612.320000,4905916.470000 - 706612.32000,4905916.47000 + 706612.320000,4905916.470000 Borgo Tossignano @@ -75,12 +75,12 @@ Content-Type: text/xml; subtype=gml/2.1.2; charset=UTF-8 - 666989.57000,4892926.89000 666989.57000,4892926.89000 + 666989.570000,4892926.890000 666989.570000,4892926.890000 - 666989.57000,4892926.89000 + 666989.570000,4892926.890000 Camugnano @@ -94,12 +94,12 @@ Content-Type: text/xml; subtype=gml/2.1.2; charset=UTF-8 - 666678.76000,4876424.90000 666678.76000,4876424.90000 + 666678.760000,4876424.900000 666678.760000,4876424.900000 - 666678.76000,4876424.90000 + 666678.760000,4876424.900000 Cantagallo @@ -113,12 +113,12 @@ Content-Type: text/xml; subtype=gml/2.1.2; charset=UTF-8 - 709517.65000,4900008.46000 709517.65000,4900008.46000 + 709517.650000,4900008.460000 709517.650000,4900008.460000 - 709517.65000,4900008.46000 + 709517.650000,4900008.460000 Casola Valsenio @@ -132,12 +132,12 @@ Content-Type: text/xml; subtype=gml/2.1.2; charset=UTF-8 - 659557.04000,4904456.57000 659557.04000,4904456.57000 + 659557.040000,4904456.570000 659557.040000,4904456.570000 - 659557.04000,4904456.57000 + 659557.040000,4904456.570000 Castel d'Aiano @@ -151,12 +151,12 @@ Content-Type: text/xml; subtype=gml/2.1.2; charset=UTF-8 - 700027.21000,4898730.81000 700027.21000,4898730.81000 + 700027.210000,4898730.810000 700027.210000,4898730.810000 - 700027.21000,4898730.81000 + 700027.210000,4898730.810000 Castel del Rio @@ -170,12 +170,12 @@ Content-Type: text/xml; subtype=gml/2.1.2; charset=UTF-8 - 662773.00000,4891987.41000 662773.00000,4891987.41000 + 662773.000000,4891987.410000 662773.000000,4891987.410000 - 662773.00000,4891987.41000 + 662773.000000,4891987.410000 Castel di Casio @@ -189,12 +189,12 @@ Content-Type: text/xml; subtype=gml/2.1.2; charset=UTF-8 - 673068.12000,4889949.75000 673068.12000,4889949.75000 + 673068.120000,4889949.750000 673068.120000,4889949.750000 - 673068.12000,4889949.75000 + 673068.120000,4889949.750000 Castiglione dei Pepoli @@ -208,12 +208,12 @@ Content-Type: text/xml; subtype=gml/2.1.2; charset=UTF-8 - 640503.54000,4884416.92000 640503.54000,4884416.92000 + 640503.540000,4884416.920000 640503.540000,4884416.920000 - 640503.54000,4884416.92000 + 640503.540000,4884416.920000 Cutigliano @@ -227,12 +227,12 @@ Content-Type: text/xml; subtype=gml/2.1.2; charset=UTF-8 - 690357.25000,4888070.83000 690357.25000,4888070.83000 + 690357.250000,4888070.830000 690357.250000,4888070.830000 - 690357.25000,4888070.83000 + 690357.250000,4888070.830000 Firenzuola @@ -246,12 +246,12 @@ Content-Type: text/xml; subtype=gml/2.1.2; charset=UTF-8 - 704327.74000,4903948.54000 704327.74000,4903948.54000 + 704327.740000,4903948.540000 704327.740000,4903948.540000 - 704327.74000,4903948.54000 + 704327.740000,4903948.540000 Fontanelice @@ -265,12 +265,12 @@ Content-Type: text/xml; subtype=gml/2.1.2; charset=UTF-8 - 654456.48000,4895565.29000 654456.48000,4895565.29000 + 654456.480000,4895565.290000 654456.480000,4895565.290000 - 654456.48000,4895565.29000 + 654456.480000,4895565.290000 Gaggio Montano @@ -284,12 +284,12 @@ Content-Type: text/xml; subtype=gml/2.1.2; charset=UTF-8 - 656907.12000,4886687.84000 656907.12000,4886687.84000 + 656907.120000,4886687.840000 656907.120000,4886687.840000 - 656907.12000,4886687.84000 + 656907.120000,4886687.840000 Granaglione @@ -303,12 +303,12 @@ Content-Type: text/xml; subtype=gml/2.1.2; charset=UTF-8 - 672130.72000,4902785.47000 672130.72000,4902785.47000 + 672130.720000,4902785.470000 672130.720000,4902785.470000 - 672130.72000,4902785.47000 + 672130.720000,4902785.470000 Grizzana Morandi @@ -322,12 +322,12 @@ Content-Type: text/xml; subtype=gml/2.1.2; charset=UTF-8 - 651437.84000,4891594.12000 651437.84000,4891594.12000 + 651437.840000,4891594.120000 651437.840000,4891594.120000 - 651437.84000,4891594.12000 + 651437.840000,4891594.120000 Lizzano in Belvedere @@ -341,12 +341,12 @@ Content-Type: text/xml; subtype=gml/2.1.2; charset=UTF-8 - 685837.45000,4904282.99000 685837.45000,4904282.99000 + 685837.450000,4904282.990000 685837.450000,4904282.990000 - 685837.45000,4904282.99000 + 685837.450000,4904282.990000 Loiano @@ -360,12 +360,12 @@ Content-Type: text/xml; subtype=gml/2.1.2; charset=UTF-8 - 642083.40000,4866048.77000 642083.40000,4866048.77000 + 642083.400000,4866048.770000 642083.400000,4866048.770000 - 642083.40000,4866048.77000 + 642083.400000,4866048.770000 Marliana @@ -379,12 +379,12 @@ Content-Type: text/xml; subtype=gml/2.1.2; charset=UTF-8 - 709203.27000,4883473.95000 709203.27000,4883473.95000 + 709203.270000,4883473.950000 709203.270000,4883473.950000 - 709203.27000,4883473.95000 + 709203.270000,4883473.950000 Marradi @@ -398,12 +398,12 @@ Content-Type: text/xml; subtype=gml/2.1.2; charset=UTF-8 - 685896.74000,4899660.12000 685896.74000,4899660.12000 + 685896.740000,4899660.120000 685896.740000,4899660.120000 - 685896.74000,4899660.12000 + 685896.740000,4899660.120000 Monghidoro @@ -417,12 +417,12 @@ Content-Type: text/xml; subtype=gml/2.1.2; charset=UTF-8 - 661896.57000,4866692.43000 661896.57000,4866692.43000 + 661896.570000,4866692.430000 661896.570000,4866692.430000 - 661896.57000,4866692.43000 + 661896.570000,4866692.430000 Montale @@ -436,12 +436,12 @@ Content-Type: text/xml; subtype=gml/2.1.2; charset=UTF-8 - 637137.64000,4900625.56000 637137.64000,4900625.56000 + 637137.640000,4900625.560000 637137.640000,4900625.560000 - 637137.64000,4900625.56000 + 637137.640000,4900625.560000 Montecreto @@ -455,12 +455,12 @@ Content-Type: text/xml; subtype=gml/2.1.2; charset=UTF-8 - 663058.32000,4865176.12000 663058.32000,4865176.12000 + 663058.320000,4865176.120000 663058.320000,4865176.120000 - 663058.32000,4865176.12000 + 663058.320000,4865176.120000 Montemurlo @@ -474,12 +474,12 @@ Content-Type: text/xml; subtype=gml/2.1.2; charset=UTF-8 - 655146.14000,4903917.01000 655146.14000,4903917.01000 + 655146.140000,4903917.010000 655146.140000,4903917.010000 - 655146.14000,4903917.01000 + 655146.140000,4903917.010000 Montese @@ -493,12 +493,12 @@ Content-Type: text/xml; subtype=gml/2.1.2; charset=UTF-8 - 680854.53000,4905388.46000 680854.53000,4905388.46000 + 680854.530000,4905388.460000 680854.530000,4905388.460000 - 680854.53000,4905388.46000 + 680854.530000,4905388.460000 Monzuno @@ -512,12 +512,12 @@ Content-Type: text/xml; subtype=gml/2.1.2; charset=UTF-8 - 703892.44000,4887624.73000 703892.44000,4887624.73000 + 703892.440000,4887624.730000 703892.440000,4887624.730000 - 703892.44000,4887624.73000 + 703892.440000,4887624.730000 Palazzuolo sul Senio @@ -531,12 +531,12 @@ Content-Type: text/xml; subtype=gml/2.1.2; charset=UTF-8 - 653901.53000,4866278.05000 653901.53000,4866278.05000 + 653901.530000,4866278.050000 653901.530000,4866278.050000 - 653901.53000,4866278.05000 + 653901.530000,4866278.050000 Pistoia @@ -550,12 +550,12 @@ Content-Type: text/xml; subtype=gml/2.1.2; charset=UTF-8 - 641450.94000,4876458.53000 641450.94000,4876458.53000 + 641450.940000,4876458.530000 641450.940000,4876458.530000 - 641450.94000,4876458.53000 + 641450.940000,4876458.530000 Piteglio @@ -569,12 +569,12 @@ Content-Type: text/xml; subtype=gml/2.1.2; charset=UTF-8 - 657705.77000,4891441.56000 657705.77000,4891441.56000 + 657705.770000,4891441.560000 657705.770000,4891441.560000 - 657705.77000,4891441.56000 + 657705.770000,4891441.560000 Porretta Terme @@ -588,12 +588,12 @@ Content-Type: text/xml; subtype=gml/2.1.2; charset=UTF-8 - 660036.84000,4885407.41000 660036.84000,4885407.41000 + 660036.840000,4885407.410000 660036.840000,4885407.410000 - 660036.84000,4885407.41000 + 660036.840000,4885407.410000 Sambuca Pistoiese @@ -607,12 +607,12 @@ Content-Type: text/xml; subtype=gml/2.1.2; charset=UTF-8 - 678374.68000,4898206.12000 678374.68000,4898206.12000 + 678374.680000,4898206.120000 678374.680000,4898206.120000 - 678374.68000,4898206.12000 + 678374.680000,4898206.120000 San Benedetto Val di Sambro @@ -626,12 +626,12 @@ Content-Type: text/xml; subtype=gml/2.1.2; charset=UTF-8 - 710195.30000,4866937.69000 710195.30000,4866937.69000 + 710195.300000,4866937.690000 710195.300000,4866937.690000 - 710195.30000,4866937.69000 + 710195.300000,4866937.690000 San Godenzo @@ -645,12 +645,12 @@ Content-Type: text/xml; subtype=gml/2.1.2; charset=UTF-8 - 643529.07000,4879703.82000 643529.07000,4879703.82000 + 643529.070000,4879703.820000 643529.070000,4879703.820000 - 643529.07000,4879703.82000 + 643529.070000,4879703.820000 San Marcello Pistoiese @@ -664,12 +664,12 @@ Content-Type: text/xml; subtype=gml/2.1.2; charset=UTF-8 - 686481.16000,4870207.09000 686481.16000,4870207.09000 + 686481.160000,4870207.090000 686481.160000,4870207.090000 - 686481.16000,4870207.09000 + 686481.160000,4870207.090000 San Piero a Sieve @@ -683,12 +683,12 @@ Content-Type: text/xml; subtype=gml/2.1.2; charset=UTF-8 - 688742.95000,4873672.85000 688742.95000,4873672.85000 + 688742.950000,4873672.850000 688742.950000,4873672.850000 - 688742.95000,4873672.85000 + 688742.950000,4873672.850000 Scarperia @@ -702,12 +702,12 @@ Content-Type: text/xml; subtype=gml/2.1.2; charset=UTF-8 - 641470.51000,4898995.21000 641470.51000,4898995.21000 + 641470.510000,4898995.210000 641470.510000,4898995.210000 - 641470.51000,4898995.21000 + 641470.510000,4898995.210000 Sestola @@ -721,12 +721,12 @@ Content-Type: text/xml; subtype=gml/2.1.2; charset=UTF-8 - 670374.33000,4868394.46000 670374.33000,4868394.46000 + 670374.330000,4868394.460000 670374.330000,4868394.460000 - 670374.33000,4868394.46000 + 670374.330000,4868394.460000 Vaiano @@ -740,12 +740,12 @@ Content-Type: text/xml; subtype=gml/2.1.2; charset=UTF-8 - 668148.55000,4905427.52000 668148.55000,4905427.52000 + 668148.550000,4905427.520000 668148.550000,4905427.520000 - 668148.55000,4905427.52000 + 668148.550000,4905427.520000 Vergato @@ -759,12 +759,12 @@ Content-Type: text/xml; subtype=gml/2.1.2; charset=UTF-8 - 672279.27000,4879402.97000 672279.27000,4879402.97000 + 672279.270000,4879402.970000 672279.270000,4879402.970000 - 672279.27000,4879402.97000 + 672279.270000,4879402.970000 Vernio @@ -778,12 +778,12 @@ Content-Type: text/xml; subtype=gml/2.1.2; charset=UTF-8 - 697335.81000,4867309.06000 697335.81000,4867309.06000 + 697335.810000,4867309.060000 697335.810000,4867309.060000 - 697335.81000,4867309.06000 + 697335.810000,4867309.060000 Vicchio diff --git a/msautotest/wxs/expected/wfs_ogr_native_sql_42.xml b/msautotest/wxs/expected/wfs_ogr_native_sql_42.xml index 6bbe411da3..eb96e2dde2 100644 --- a/msautotest/wxs/expected/wfs_ogr_native_sql_42.xml +++ b/msautotest/wxs/expected/wfs_ogr_native_sql_42.xml @@ -11,7 +11,7 @@ Content-Type: text/xml; subtype=gml/2.1.2; charset=UTF-8 next="http://localhost/path/to/wfs_simple?SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAME=towns_disable_default_extent_for_getfeature&OUTPUTFORMAT=GML2&COUNT=1&STARTINDEX=1"> - 672130.72000,4902785.47000 672130.72000,4902785.47000 + 672130.720000,4902785.470000 672130.720000,4902785.470000 @@ -19,12 +19,12 @@ Content-Type: text/xml; subtype=gml/2.1.2; charset=UTF-8 - 672130.72000,4902785.47000 672130.72000,4902785.47000 + 672130.720000,4902785.470000 672130.720000,4902785.470000 - 672130.72000,4902785.47000 + 672130.720000,4902785.470000 Grizzana Morandi diff --git a/msautotest/wxs/expected/wfs_ogr_native_sql_43.xml b/msautotest/wxs/expected/wfs_ogr_native_sql_43.xml index 68a819bed4..5b45d47ba2 100644 --- a/msautotest/wxs/expected/wfs_ogr_native_sql_43.xml +++ b/msautotest/wxs/expected/wfs_ogr_native_sql_43.xml @@ -11,7 +11,7 @@ Content-Type: text/xml; subtype=gml/2.1.2; charset=UTF-8 next="http://localhost/path/to/wfs_simple?SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAME=towns_disable_default_extent_for_getfeature&OUTPUTFORMAT=GML2&COUNT=1&SRSNAME=EPSG%3A4326&STARTINDEX=1"> - 44.25795,11.15631 44.25795,11.15631 + 44.257959,11.156312 44.257959,11.156312 @@ -19,12 +19,12 @@ Content-Type: text/xml; subtype=gml/2.1.2; charset=UTF-8 - 44.25795,11.15631 44.25795,11.15631 + 44.257959,11.156312 44.257959,11.156312 - 44.25795,11.15631 + 44.257959,11.156312 Grizzana Morandi diff --git a/msautotest/wxs/expected/wfs_ogr_native_sql_is_equal_to_invalid_property_name.xml b/msautotest/wxs/expected/wfs_ogr_native_sql_is_equal_to_invalid_property_name.xml new file mode 100644 index 0000000000..4907bb2c37 --- /dev/null +++ b/msautotest/wxs/expected/wfs_ogr_native_sql_is_equal_to_invalid_property_name.xml @@ -0,0 +1,8 @@ +Content-Type: text/xml; charset=UTF-8 + + + + +msWFSGetFeature(): WFS server error. Invalid or Unsupported FILTER in GetFeature : <Filter><PropertyIsEqualTo matchCase=false><PropertyName> + + diff --git a/msautotest/wxs/expected/wfs_ogr_native_sql_like_backslash_and_single_quote.xml b/msautotest/wxs/expected/wfs_ogr_native_sql_like_backslash_and_single_quote.xml new file mode 100644 index 0000000000..98e30b0022 --- /dev/null +++ b/msautotest/wxs/expected/wfs_ogr_native_sql_like_backslash_and_single_quote.xml @@ -0,0 +1,34 @@ +Content-Type: text/xml; charset=UTF-8 + + + + + + 653901.530000,4866278.050000 653901.530000,4866278.050000 + + + + + + + 653901.530000,4866278.050000 653901.530000,4866278.050000 + + + + + 653901.530000,4866278.050000 + + + 2 + with backslash \ with single ' quote + + + + diff --git a/msautotest/wxs/expected/wfs_ogr_native_sql_like_parenthesis.xml b/msautotest/wxs/expected/wfs_ogr_native_sql_like_parenthesis.xml new file mode 100644 index 0000000000..f522e91f66 --- /dev/null +++ b/msautotest/wxs/expected/wfs_ogr_native_sql_like_parenthesis.xml @@ -0,0 +1,34 @@ +Content-Type: text/xml; charset=UTF-8 + + + + + + 653901.530000,4866278.050000 653901.530000,4866278.050000 + + + + + + + 653901.530000,4866278.050000 653901.530000,4866278.050000 + + + + + 653901.530000,4866278.050000 + + + 1 + with parenthesis ( ) + + + + diff --git a/msautotest/wxs/expected/wfs_ogr_nonexistingdrv_caps.xml b/msautotest/wxs/expected/wfs_ogr_nonexistingdrv_caps.xml index 11b586564c..6d4fb3f907 100644 --- a/msautotest/wxs/expected/wfs_ogr_nonexistingdrv_caps.xml +++ b/msautotest/wxs/expected/wfs_ogr_nonexistingdrv_caps.xml @@ -1,7 +1,8 @@ Content-Type: text/html -MapServer Message +MapServer Message + loadOutputFormat(): General error message. OUTPUTFORMAT (nonexistingdrv) clause references driver (OGR/nonexistingdrv), but this driver isn't configured. msInitDefaultOGROutputFormat(): General error message. No OGR driver named `nonexistingdrv' available. \ No newline at end of file diff --git a/msautotest/wxs/expected/wfs_ogr_tileindex_of_shp_bbox_filter.xml b/msautotest/wxs/expected/wfs_ogr_tileindex_of_shp_bbox_filter.xml index 6f0f1d98da..5bd0d92936 100644 --- a/msautotest/wxs/expected/wfs_ogr_tileindex_of_shp_bbox_filter.xml +++ b/msautotest/wxs/expected/wfs_ogr_tileindex_of_shp_bbox_filter.xml @@ -10,21 +10,21 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 timeStamp="" numberMatched="1" numberReturned="1"> - 49.00000 2.00000 - 49.00000 2.00000 + 49.000000 2.000000 + 49.000000 2.000000 - 49.00000 2.00000 - 49.00000 2.00000 + 49.000000 2.000000 + 49.000000 2.000000 - 49.00000 2.00000 + 49.000000 2.000000 diff --git a/msautotest/wxs/expected/wfs_ogr_tileindexmixedsrs_get_feature.xml b/msautotest/wxs/expected/wfs_ogr_tileindexmixedsrs_get_feature.xml index a7e392c204..4f3883a479 100644 --- a/msautotest/wxs/expected/wfs_ogr_tileindexmixedsrs_get_feature.xml +++ b/msautotest/wxs/expected/wfs_ogr_tileindexmixedsrs_get_feature.xml @@ -11,19 +11,19 @@ Content-Type: text/xml; charset=UTF-8 http://mapserver.gis.umn.edu/mapserver http://localhost/path/to/wfs_simple?SERVICE=WFS&VERSION=1.0.0&REQUEST=DescribeFeatureType&TYPENAME=ms:test&OUTPUTFORMAT=XMLSCHEMA"> - 2.00000,49.00000 3.00000,50.00000 + 2.000000,49.000000 3.000000,50.000000 - 2.00000,49.00000 2.00000,49.00000 + 2.000000,49.000000 2.000000,49.000000 - 2.00000,49.00000 + 2.000000,49.000000 @@ -32,12 +32,12 @@ Content-Type: text/xml; charset=UTF-8 - 3.00000,50.00000 3.00000,50.00000 + 3.000000,50.000000 3.000000,50.000000 - 3.00000,50.00000 + 3.000000,50.000000 diff --git a/msautotest/wxs/expected/wfs_ogr_weird_column_names_binary_op_numeric.xml b/msautotest/wxs/expected/wfs_ogr_weird_column_names_binary_op_numeric.xml new file mode 100644 index 0000000000..a5fdf00f11 --- /dev/null +++ b/msautotest/wxs/expected/wfs_ogr_weird_column_names_binary_op_numeric.xml @@ -0,0 +1,37 @@ +Content-Type: text/xml; charset=UTF-8 + + + + + + 1000000.000000,4000000.000000 1000000.000000,4000000.000000 + + + + + + + + 1000000.000000,4000000.000000 1000000.000000,4000000.000000 + + + + + 1000000.000000,4000000.000000 + + + + 1 + + foo + + + + diff --git a/msautotest/wxs/expected/wfs_ogr_weird_column_names_binary_op_string.xml b/msautotest/wxs/expected/wfs_ogr_weird_column_names_binary_op_string.xml new file mode 100644 index 0000000000..a5fdf00f11 --- /dev/null +++ b/msautotest/wxs/expected/wfs_ogr_weird_column_names_binary_op_string.xml @@ -0,0 +1,37 @@ +Content-Type: text/xml; charset=UTF-8 + + + + + + 1000000.000000,4000000.000000 1000000.000000,4000000.000000 + + + + + + + + 1000000.000000,4000000.000000 1000000.000000,4000000.000000 + + + + + 1000000.000000,4000000.000000 + + + + 1 + + foo + + + + diff --git a/msautotest/wxs/expected/wfs_optional_items_get_feature.xml b/msautotest/wxs/expected/wfs_optional_items_get_feature.xml index e4f7e38906..83b997540d 100644 --- a/msautotest/wxs/expected/wfs_optional_items_get_feature.xml +++ b/msautotest/wxs/expected/wfs_optional_items_get_feature.xml @@ -10,23 +10,23 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 timeStamp="" numberMatched="21" numberReturned="21"> - 43.41231 -66.43267 - 47.79644 -59.70969 + 43.412311 -66.432672 + 47.796447 -59.709694 - 47.76789 -61.51051 - 47.79644 -61.45764 + 47.767892 -61.510511 + 47.796447 -61.457648 - 47.77424 -61.51051 47.78860 -61.50894 47.79644 -61.49272 47.78743 -61.45764 47.76789 -61.45998 47.76961 -61.48350 47.77424 -61.51051 + 47.774240 -61.510511 47.788606 -61.508947 47.796447 -61.492725 47.787438 -61.457648 47.767892 -61.459987 47.769615 -61.483502 47.774240 -61.510511 @@ -40,15 +40,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 47.16638 -60.21172 - 47.19271 -60.16877 + 47.166385 -60.211728 + 47.192716 -60.168776 - 47.16638 -60.20485 47.17985 -60.21172 47.19271 -60.19435 47.18763 -60.17344 47.17496 -60.16877 47.16638 -60.20485 + 47.166385 -60.204850 47.179857 -60.211728 47.192716 -60.194354 47.187638 -60.173448 47.174965 -60.168776 47.166385 -60.204850 @@ -62,15 +62,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 47.19106 -62.07696 - 47.62759 -61.43322 + 47.191069 -62.076968 + 47.627593 -61.433227 - 47.24108 -62.01051 47.24604 -61.96674 47.23831 -61.94754 47.22825 -61.93270 47.22220 -61.90699 47.23311 -61.86469 47.24267 -61.84221 47.23857 -61.82873 47.22731 -61.82804 47.21582 -61.83841 47.19106 -61.89528 47.19587 -61.91086 47.20730 -61.93027 47.21146 -61.94369 47.20068 -61.98054 47.20210 -62.00918 47.21127 -62.05713 47.21986 -62.07304 47.23019 -62.07696 47.30062 -62.02523 47.32797 -62.01258 47.35422 -62.01412 47.38157 -62.00145 47.40632 -61.97428 47.46073 -61.87584 47.55646 -61.74402 47.59681 -61.65975 47.61945 -61.58987 47.62006 -61.53210 47.62627 -61.49244 47.62759 -61.46701 47.62579 -61.44364 47.61706 -61.43322 47.60265 -61.44020 47.58445 -61.48263 47.57198 -61.50196 47.54670 -61.52732 47.53100 -61.55423 47.52441 -61.58041 47.53668 -61.60212 47.54664 -61.59275 47.56410 -61.55367 47.58387 -61.54035 47.59656 -61.57531 47.58175 -61.62893 47.56042 -61.67323 47.53788 -61.70753 47.50243 -61.77198 47.46323 -61.81183 47.43985 -61.84363 47.42876 -61.86734 47.41317 -61.88844 47.37958 -61.91082 47.35461 -61.91930 47.34335 -61.91859 47.32832 -61.94748 47.31536 -61.98306 47.25730 -62.02144 47.24108 -62.01051 + 47.241088 -62.010515 47.246040 -61.966742 47.238311 -61.947548 47.228257 -61.932708 47.222202 -61.906997 47.233116 -61.864694 47.242674 -61.842210 47.238572 -61.828736 47.227311 -61.828048 47.215824 -61.838414 47.191069 -61.895286 47.195878 -61.910866 47.207300 -61.930279 47.211466 -61.943690 47.200682 -61.980541 47.202105 -62.009180 47.211273 -62.057130 47.219864 -62.073040 47.230193 -62.076968 47.300625 -62.025236 47.327971 -62.012584 47.354223 -62.014128 47.381572 -62.001451 47.406325 -61.974280 47.460730 -61.875844 47.556462 -61.744027 47.596818 -61.659750 47.619458 -61.589874 47.620068 -61.532104 47.626271 -61.492444 47.627593 -61.467016 47.625790 -61.443646 47.617067 -61.433227 47.602653 -61.440203 47.584451 -61.482632 47.571983 -61.501965 47.546702 -61.527322 47.531009 -61.554237 47.524411 -61.580413 47.536685 -61.602124 47.546644 -61.592755 47.564103 -61.553676 47.583872 -61.540355 47.596569 -61.575318 47.581754 -61.628933 47.560421 -61.673230 47.537886 -61.707530 47.502438 -61.771983 47.463236 -61.811839 47.439850 -61.843632 47.428764 -61.867341 47.413176 -61.888445 47.379589 -61.910824 47.354617 -61.919309 47.343351 -61.918598 47.328320 -61.947480 47.315363 -61.983069 47.257309 -62.021449 47.241088 -62.010515 @@ -84,15 +84,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 47.37578 -61.85020 - 47.53541 -61.62463 + 47.375784 -61.850201 + 47.535418 -61.624632 - 47.39077 -61.85020 47.40527 -61.83772 47.41716 -61.81637 47.42945 -61.80270 47.44433 -61.77925 47.46587 -61.75944 47.48454 -61.73062 47.49872 -61.70481 47.52737 -61.66642 47.53541 -61.64470 47.53286 -61.62463 47.52225 -61.63180 47.51114 -61.65567 47.45830 -61.72907 47.43823 -61.75344 47.41589 -61.77649 47.37997 -61.80321 47.37578 -61.81946 47.39077 -61.85020 + 47.390774 -61.850201 47.405273 -61.837726 47.417160 -61.816375 47.429451 -61.802704 47.444334 -61.779258 47.465873 -61.759440 47.484545 -61.730626 47.498723 -61.704819 47.527379 -61.666427 47.535418 -61.644700 47.532866 -61.624632 47.522259 -61.631801 47.511145 -61.655676 47.458309 -61.729072 47.438230 -61.753441 47.415897 -61.776498 47.379975 -61.803218 47.375784 -61.819462 47.390774 -61.850201 @@ -106,15 +106,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 45.55044 -61.59511 - 47.03152 -60.34353 + 45.550449 -61.595111 + 47.031525 -60.343533 - 45.64995 -60.88100 45.62964 -60.89735 45.63055 -60.92814 45.61131 -61.00908 45.61072 -61.04080 45.60069 -61.06061 45.58886 -61.09728 45.58218 -61.13299 45.56434 -61.16831 45.55872 -61.19037 45.56065 -61.20734 45.58078 -61.20714 45.59226 -61.22567 45.59854 -61.24502 45.59370 -61.26380 45.57932 -61.27601 45.57074 -61.29466 45.55044 -61.30547 45.55804 -61.33436 45.57893 -61.36499 45.60096 -61.37658 45.62222 -61.39131 45.64498 -61.43901 45.68124 -61.47794 45.72090 -61.50435 45.74448 -61.51506 45.79398 -61.53240 45.83324 -61.54064 45.86342 -61.55506 45.90791 -61.56254 45.94146 -61.56423 46.02269 -61.59511 46.03665 -61.57548 46.04540 -61.55132 46.05222 -61.51518 46.05285 -61.48843 46.05503 -61.45536 46.06486 -61.45148 46.07567 -61.46816 46.09111 -61.51066 46.10430 -61.51772 46.14672 -61.48975 46.17439 -61.45567 46.19619 -61.41489 46.21434 -61.36836 46.23455 -61.33384 46.29334 -61.27078 46.39497 -61.18675 46.42631 -61.15240 46.44736 -61.14355 46.51078 -61.10612 46.57439 -61.06319 46.58996 -61.06597 46.61490 -61.09195 46.62260 -61.08137 46.62750 -61.06206 46.62258 -61.04122 46.62967 -61.02303 46.64697 -61.01398 46.65751 -61.01219 46.73777 -60.95217 46.78405 -60.91250 46.79934 -60.89124 46.81256 -60.85802 46.83880 -60.80765 46.88381 -60.75247 46.93979 -60.70840 46.97604 -60.68331 47.00688 -60.67548 47.01668 -60.66590 47.02681 -60.63446 47.02576 -60.60818 47.01756 -60.54331 46.99698 -60.51433 46.99416 -60.50008 47.00184 -60.48380 47.02743 -60.47143 47.03152 -60.44411 47.02334 -60.43075 47.01370 -60.42398 47.00027 -60.42800 46.97970 -60.45590 46.96315 -60.46750 46.94223 -60.46591 46.92785 -60.47316 46.91766 -60.51544 46.90031 -60.52481 46.89381 -60.51047 46.89407 -60.48325 46.88541 -60.45685 46.85658 -60.43096 46.85306 -60.40903 46.85722 -60.37096 46.84174 -60.35207 46.81863 -60.34397 46.79994 -60.34353 46.78409 -60.35725 46.73103 -60.35388 46.68503 -60.38863 46.67134 -60.41431 46.65255 -60.41936 46.65209 -60.40091 46.64560 -60.38121 46.63657 -60.38199 46.62739 -60.39920 46.61609 -60.40979 46.60516 -60.38238 46.58877 -60.37766 46.55717 -60.39962 46.53890 -60.42845 46.51251 -60.44942 46.49831 -60.45121 46.40272 -60.51463 46.38309 -60.53354 46.36266 -60.56105 46.35206 -60.56824 46.33566 -60.56890 46.31001 -60.58650 46.29958 -60.58831 46.27931 -60.59961 46.26988 -60.63265 46.26067 -60.64966 46.24740 -60.64284 46.22487 -60.65291 46.21303 -60.64502 46.21024 -60.63101 46.21637 -60.61606 46.25403 -60.59029 46.30100 -60.53670 46.31771 -60.51452 46.33005 -60.47931 46.30400 -60.47324 46.29501 -60.47952 46.27538 -60.49840 46.26319 -60.51743 46.22776 -60.54436 46.19430 -60.59400 46.10330 -60.70392 46.09247 -60.73247 46.09174 -60.78077 46.07638 -60.81238 46.06139 -60.86219 46.05797 -60.89103 46.07230 -60.92366 46.06668 -60.94590 46.05320 -60.94974 46.03421 -60.97053 46.02431 -60.98510 45.99002 -61.02658 45.97226 -61.05689 45.95590 -61.09692 45.94928 -61.13287 45.94288 -61.15298 45.92864 -61.15989 45.92678 -61.14273 45.93026 -61.11400 45.94794 -61.04426 45.95424 -61.02420 45.95924 -60.99444 45.97081 -60.97345 45.98019 -60.95135 45.99803 -60.94988 46.01138 -60.95681 46.03075 -60.90934 46.03175 -60.89546 46.01957 -60.86935 46.02499 -60.85245 46.04649 -60.81672 46.04855 -60.77818 46.03810 -60.78011 46.00609 -60.82286 45.98055 -60.84022 45.94769 -60.84129 45.93452 -60.87388 45.91784 -60.93525 45.92248 -60.96634 45.91903 -60.99507 45.90151 -61.05953 45.88426 -61.10260 45.84710 -61.13519 45.84304 -61.11695 45.85166 -61.09280 45.86428 -61.05806 45.86543 -61.03352 45.88570 -61.02799 45.89205 -61.00259 45.87647 -60.96039 45.86758 -60.95579 45.85654 -60.98955 45.83520 -60.97494 45.82597 -60.99154 45.82762 -61.02462 45.81520 -61.05403 45.78755 -61.09867 45.76274 -61.15204 45.74052 -61.17983 45.73866 -61.16274 45.72476 -61.14835 45.71458 -61.17342 45.69499 -61.18652 45.68877 -61.16179 45.69638 -61.11746 45.70518 -61.08281 45.71903 -61.05772 45.73432 -61.03713 45.75141 -60.99942 45.75710 -60.97199 45.74426 -60.89393 45.73581 -60.86279 45.72194 -60.84844 45.70705 -60.84805 45.68510 -60.87066 45.66404 -60.88471 45.64995 -60.88100 + 45.649954 -60.881009 45.629648 -60.897351 45.630553 -60.928145 45.611319 -61.009089 45.610721 -61.040806 45.600690 -61.060614 45.588861 -61.097280 45.582181 -61.132995 45.564345 -61.168312 45.558723 -61.190377 45.560650 -61.207340 45.580780 -61.207140 45.592268 -61.225673 45.598546 -61.245028 45.593709 -61.263803 45.579321 -61.276019 45.570740 -61.294666 45.550449 -61.305470 45.558043 -61.334366 45.578931 -61.364992 45.600965 -61.376583 45.622223 -61.391312 45.644981 -61.439011 45.681246 -61.477948 45.720907 -61.504351 45.744486 -61.515065 45.793980 -61.532408 45.833242 -61.540641 45.863422 -61.555060 45.907911 -61.562546 45.941468 -61.564232 46.022697 -61.595111 46.036654 -61.575489 46.045406 -61.551320 46.052222 -61.515187 46.052853 -61.488434 46.055037 -61.455367 46.064862 -61.451486 46.075678 -61.468167 46.091116 -61.510668 46.104307 -61.517727 46.146728 -61.489759 46.174397 -61.455676 46.196198 -61.414895 46.214349 -61.368367 46.234559 -61.333845 46.293343 -61.270789 46.394972 -61.186759 46.426311 -61.152403 46.447362 -61.143556 46.510783 -61.106129 46.574395 -61.063193 46.589967 -61.065977 46.614909 -61.091959 46.622603 -61.081372 46.627500 -61.062069 46.622583 -61.041222 46.629678 -61.023032 46.646978 -61.013984 46.657512 -61.012199 46.737777 -60.952173 46.784059 -60.912506 46.799340 -60.891249 46.812564 -60.858021 46.838805 -60.807653 46.883813 -60.752476 46.939790 -60.708400 46.976042 -60.683312 47.006882 -60.675484 47.016681 -60.665906 47.026816 -60.634462 47.025765 -60.608189 47.017567 -60.543319 46.996989 -60.514337 46.994169 -60.500086 47.001841 -60.483802 47.027437 -60.471435 47.031525 -60.444116 47.023340 -60.430751 47.013703 -60.423989 47.000272 -60.428005 46.979701 -60.455909 46.963151 -60.467506 46.942231 -60.465911 46.927854 -60.473165 46.917662 -60.515443 46.900315 -60.524813 46.893814 -60.510474 46.894074 -60.483257 46.885413 -60.456857 46.856580 -60.430963 46.853060 -60.409033 46.857226 -60.370964 46.841740 -60.352079 46.818636 -60.343976 46.799943 -60.343533 46.784093 -60.357258 46.731037 -60.353887 46.685033 -60.388635 46.671343 -60.414318 46.652557 -60.419369 46.652092 -60.400910 46.645606 -60.381215 46.636579 -60.381992 46.627395 -60.399203 46.616098 -60.409798 46.605166 -60.382381 46.588778 -60.377669 46.557171 -60.399625 46.538904 -60.428453 46.512512 -60.449424 46.498315 -60.451219 46.402727 -60.514638 46.383090 -60.533548 46.362662 -60.561054 46.352066 -60.568243 46.335667 -60.568906 46.310018 -60.586506 46.299584 -60.588312 46.279313 -60.599619 46.269887 -60.632652 46.260672 -60.649667 46.247406 -60.642843 46.224879 -60.652912 46.213036 -60.645026 46.210245 -60.631019 46.216372 -60.616069 46.254031 -60.590291 46.301008 -60.536708 46.317713 -60.514524 46.330057 -60.479319 46.304009 -60.473241 46.295010 -60.479521 46.275389 -60.498401 46.263191 -60.517436 46.227762 -60.544368 46.194306 -60.594006 46.103301 -60.703922 46.092472 -60.732477 46.091743 -60.780770 46.076384 -60.812387 46.061390 -60.862199 46.057978 -60.891033 46.072301 -60.923663 46.066682 -60.945906 46.053207 -60.949743 46.034214 -60.970530 46.024319 -60.985101 45.990020 -61.026588 45.972260 -61.056897 45.955900 -61.096924 45.949285 -61.132870 45.942888 -61.152982 45.928641 -61.159899 45.926780 -61.142735 45.930269 -61.114003 45.947948 -61.044268 45.954245 -61.024203 45.959242 -60.994440 45.970819 -60.973451 45.980190 -60.951350 45.998033 -60.949889 46.011382 -60.956812 46.030755 -60.909348 46.031753 -60.895468 46.019571 -60.869352 46.024994 -60.852458 46.046490 -60.816726 46.048559 -60.778188 46.038101 -60.780111 46.006097 -60.822860 45.980558 -60.840227 45.947690 -60.841299 45.934522 -60.873885 45.917843 -60.935257 45.922481 -60.966344 45.919038 -60.995079 45.901511 -61.059535 45.884264 -61.102601 45.847108 -61.135193 45.843043 -61.116957 45.851666 -61.092804 45.864284 -61.058067 45.865436 -61.033524 45.885703 -61.027991 45.892059 -61.002590 45.876475 -60.960393 45.867581 -60.955792 45.856547 -60.989557 45.835202 -60.974943 45.825971 -60.991547 45.827623 -61.024623 45.815209 -61.054032 45.787550 -61.098679 45.762742 -61.152042 45.740520 -61.179832 45.738664 -61.162740 45.724764 -61.148356 45.714587 -61.173426 45.694994 -61.186525 45.688774 -61.161798 45.696384 -61.117462 45.705184 -61.082816 45.719034 -61.057724 45.734323 -61.037132 45.751419 -60.999423 45.757106 -60.971998 45.744260 -60.893939 45.735813 -60.862792 45.721943 -60.848441 45.707052 -60.848053 45.685106 -60.870666 45.664049 -60.884717 45.649954 -60.881009 @@ -128,15 +128,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 47.25507 -61.75096 - 47.28211 -61.71983 + 47.255073 -61.750964 + 47.282116 -61.719830 - 47.25839 -61.74889 47.27555 -61.75096 47.28211 -61.73032 47.26959 -61.71983 47.25507 -61.73219 47.25839 -61.74889 + 47.258394 -61.748897 47.275550 -61.750964 47.282116 -61.730322 47.269593 -61.719830 47.255073 -61.732191 47.258394 -61.748897 @@ -150,15 +150,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 45.56706 -60.89735 - 46.26194 -59.82000 + 45.567064 -60.897351 + 46.261946 -59.820005 - 45.64995 -60.88100 45.65334 -60.85788 45.66020 -60.84534 45.67380 -60.83094 45.68701 -60.79847 45.69923 -60.77975 45.70884 -60.78105 45.73321 -60.79358 45.76006 -60.79121 45.77727 -60.78225 45.82475 -60.69757 45.84729 -60.68225 45.85917 -60.63459 45.90925 -60.56356 45.93950 -60.52700 45.95351 -60.48027 45.96348 -60.46029 45.97695 -60.45093 45.99023 -60.46314 45.94376 -60.60076 45.92884 -60.60565 45.89439 -60.72412 45.89550 -60.74447 45.90717 -60.76295 45.91857 -60.79750 45.92054 -60.81475 45.92940 -60.81922 45.95427 -60.79976 46.02271 -60.66074 46.09125 -60.55036 46.10734 -60.51539 46.12786 -60.48807 46.14975 -60.46504 46.17784 -60.41634 46.19925 -60.37498 46.21365 -60.35160 46.23167 -60.33912 46.24375 -60.32012 46.26194 -60.29684 46.24950 -60.27082 46.23171 -60.25635 46.21606 -60.25394 46.20099 -60.26973 46.17902 -60.30897 46.16101 -60.32145 46.15207 -60.31694 46.14923 -60.30298 46.16001 -60.27422 46.15336 -60.26011 46.13782 -60.25224 46.13124 -60.23286 46.13521 -60.21687 46.14125 -60.20728 46.15314 -60.20964 46.16640 -60.22711 46.17748 -60.23273 46.20890 -60.22695 46.21941 -60.21959 46.23295 -60.20482 46.24441 -60.17819 46.24760 -60.14918 46.24490 -60.11902 46.23770 -60.08663 46.23102 -60.07793 46.21369 -60.10342 46.20027 -60.09673 46.19739 -60.08276 46.20503 -60.05600 46.20450 -60.03234 46.18480 -59.96880 46.18603 -59.88506 46.18247 -59.85804 46.16907 -59.84614 46.16019 -59.84706 46.15476 -59.88034 46.14507 -59.88451 46.13232 -59.88538 46.11727 -59.91733 46.10226 -59.93860 46.09331 -59.93418 46.08968 -59.91805 46.09727 -59.89672 46.10553 -59.88287 46.11912 -59.85728 46.10500 -59.84858 46.09673 -59.85705 46.06371 -59.89640 46.04947 -59.91967 46.03189 -59.97722 46.01846 -59.98673 46.00824 -59.95654 46.00692 -59.92020 45.99378 -59.88152 45.98035 -59.87493 45.95602 -59.83086 45.94492 -59.82000 45.92699 -59.83261 45.93342 -59.88397 45.92194 -59.93191 45.91221 -59.94668 45.90382 -59.96578 45.90805 -60.01066 45.88187 -60.02632 45.87281 -60.04850 45.87040 -60.06338 45.86898 -60.15724 45.86421 -60.18692 45.85525 -60.19320 45.84632 -60.18875 45.83313 -60.16617 45.81987 -60.15420 45.81394 -60.14241 45.81338 -60.12419 45.80450 -60.11452 45.79102 -60.12383 45.78045 -60.14708 45.76964 -60.19157 45.76788 -60.21385 45.78264 -60.23014 45.78029 -60.24492 45.73712 -60.24305 45.72809 -60.25453 45.71524 -60.27655 45.70017 -60.29750 45.69478 -60.31440 45.70188 -60.34644 45.69266 -60.36852 45.65803 -60.40809 45.64129 -60.44055 45.61741 -60.56182 45.60196 -60.66423 45.59346 -60.68833 45.57752 -60.70696 45.56976 -60.72790 45.56706 -60.75852 45.56972 -60.78298 45.59474 -60.79756 45.60111 -60.81685 45.60145 -60.84547 45.61197 -60.88300 45.62964 -60.89735 45.64995 -60.88100 + 45.649954 -60.881009 45.653348 -60.857881 45.660202 -60.845348 45.673801 -60.830945 45.687014 -60.798470 45.699239 -60.779757 45.708848 -60.781056 45.733215 -60.793583 45.760063 -60.791213 45.777275 -60.782252 45.824757 -60.697572 45.847293 -60.682257 45.859173 -60.634593 45.909256 -60.563568 45.939505 -60.527009 45.953515 -60.480278 45.963481 -60.460290 45.976959 -60.450935 45.990237 -60.463145 45.943763 -60.600767 45.928847 -60.605653 45.894394 -60.724121 45.895501 -60.744475 45.907176 -60.762954 45.918574 -60.797500 45.920545 -60.814756 45.929405 -60.819227 45.954272 -60.799765 46.022713 -60.660742 46.091252 -60.550360 46.107347 -60.515399 46.127860 -60.488072 46.149753 -60.465043 46.177842 -60.416341 46.199254 -60.374984 46.213654 -60.351604 46.231677 -60.339127 46.243759 -60.320120 46.261946 -60.296847 46.249504 -60.270825 46.231712 -60.256352 46.216066 -60.253943 46.200990 -60.269738 46.179029 -60.308979 46.161015 -60.321453 46.152077 -60.316949 46.149237 -60.302985 46.160010 -60.274222 46.153368 -60.260117 46.137822 -60.252248 46.131241 -60.232867 46.135212 -60.216871 46.141252 -60.207283 46.153147 -60.209646 46.166404 -60.227119 46.177483 -60.232739 46.208901 -60.226953 46.219419 -60.219598 46.232951 -60.204821 46.244419 -60.178196 46.247609 -60.149187 46.244900 -60.119022 46.237705 -60.086630 46.231023 -60.077933 46.213696 -60.103429 46.200270 -60.096734 46.197396 -60.082767 46.205031 -60.056007 46.204502 -60.032340 46.184803 -59.968802 46.186039 -59.885068 46.182471 -59.858046 46.169072 -59.846142 46.160191 -59.847065 46.154762 -59.880343 46.145079 -59.884513 46.132328 -59.885385 46.117277 -59.917339 46.102265 -59.938602 46.093312 -59.934184 46.089685 -59.918056 46.097270 -59.896725 46.105537 -59.882871 46.119122 -59.857286 46.105000 -59.848584 46.096735 -59.857056 46.063717 -59.896406 46.049471 -59.919675 46.031898 -59.977221 46.018465 -59.986731 46.008241 -59.956545 46.006928 -59.920202 45.993781 -59.881526 45.980353 -59.874931 45.956021 -59.830867 45.944922 -59.820005 45.926994 -59.832615 45.933429 -59.883977 45.921940 -59.931918 45.912216 -59.946681 45.903823 -59.965788 45.908050 -60.010660 45.881877 -60.026323 45.872811 -60.048501 45.870409 -60.063386 45.868986 -60.157242 45.864219 -60.186927 45.855255 -60.193201 45.846324 -60.188756 45.833138 -60.166170 45.819875 -60.154201 45.813947 -60.142413 45.813383 -60.124199 45.804507 -60.114525 45.791027 -60.123836 45.780453 -60.147087 45.769647 -60.191574 45.767880 -60.213850 45.782649 -60.230146 45.780293 -60.244922 45.737125 -60.243052 45.728097 -60.254532 45.715241 -60.276556 45.700171 -60.297503 45.694783 -60.314407 45.701880 -60.346441 45.692668 -60.368529 45.658030 -60.408093 45.641293 -60.440550 45.617419 -60.561824 45.601961 -60.664237 45.593461 -60.688338 45.577521 -60.706965 45.569765 -60.727909 45.567064 -60.758520 45.569728 -60.782985 45.594741 -60.797560 45.601111 -60.816855 45.601459 -60.845476 45.611974 -60.883004 45.629648 -60.897351 45.649954 -60.881009 @@ -172,15 +172,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 46.06863 -60.68255 - 46.31432 -60.31030 + 46.068634 -60.682556 + 46.314326 -60.310302 - 46.06863 -60.68255 46.08885 -60.67673 46.10483 -60.64716 46.12309 -60.62409 46.16235 -60.58655 46.18281 -60.55930 46.19817 -60.52745 46.24352 -60.48030 46.28600 -60.41893 46.30881 -60.38181 46.31432 -60.35396 46.30346 -60.32144 46.28490 -60.31030 46.27137 -60.31965 46.25853 -60.33662 46.22822 -60.38428 46.22655 -60.40142 46.21560 -60.44629 46.20563 -60.46640 46.18823 -60.48632 46.16847 -60.51602 46.15544 -60.54347 46.11291 -60.60454 46.08640 -60.63586 46.07193 -60.65908 46.06863 -60.68255 + 46.068634 -60.682556 46.088853 -60.676730 46.104831 -60.647161 46.123091 -60.624097 46.162354 -60.586559 46.182819 -60.559300 46.198173 -60.527452 46.243529 -60.480305 46.286000 -60.418937 46.308813 -60.381812 46.314326 -60.353962 46.303460 -60.321443 46.284901 -60.310302 46.271372 -60.319652 46.258539 -60.336627 46.228226 -60.384283 46.226558 -60.401420 46.215606 -60.446297 46.205633 -60.466402 46.188232 -60.486328 46.168474 -60.516022 46.155447 -60.543472 46.112917 -60.604540 46.086404 -60.635868 46.071938 -60.659084 46.068634 -60.682556 @@ -194,15 +194,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 45.99438 -59.79193 - 46.03927 -59.70969 + 45.994384 -59.791931 + 46.039276 -59.709694 - 46.01509 -59.79193 46.02419 -59.75353 46.03767 -59.73340 46.03927 -59.71086 46.02584 -59.70969 46.01534 -59.72240 46.00193 -59.73199 45.99438 -59.74793 46.00099 -59.77262 46.01509 -59.79193 + 46.015090 -59.791931 46.024191 -59.753530 46.037672 -59.733403 46.039276 -59.710864 46.025845 -59.709694 46.015344 -59.722409 46.001939 -59.731993 45.994384 -59.747931 46.000997 -59.772623 46.015090 -59.791931 @@ -216,15 +216,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 45.94981 -64.46414 - 47.04029 -62.02064 + 45.949816 -64.464145 + 47.040290 -62.020645 - 46.05449 -62.49785 46.03300 -62.51661 46.03496 -62.54687 46.03418 -62.56822 46.01993 -62.59284 46.00804 -62.58991 46.00032 -62.57651 46.00641 -62.53083 45.99318 -62.52344 45.97949 -62.53216 45.97084 -62.54547 45.96509 -62.60380 45.96535 -62.65834 45.96788 -62.69069 45.96525 -62.72362 45.94981 -62.81665 45.95738 -62.85356 45.96981 -62.90060 46.01432 -62.96416 46.02739 -62.97164 46.03527 -62.96152 46.04687 -62.95184 46.05736 -62.96876 46.05764 -62.99982 46.05421 -63.03072 46.05771 -63.05459 46.07126 -63.05139 46.08628 -62.99262 46.08952 -62.96708 46.10718 -62.93528 46.12845 -62.92728 46.15073 -62.92913 46.13597 -62.98272 46.13822 -63.00223 46.16316 -62.99459 46.17719 -62.99902 46.18459 -63.01799 46.17762 -63.04315 46.18334 -63.06840 46.18772 -63.10753 46.19211 -63.12829 46.20656 -63.14030 46.22212 -63.12550 46.27070 -63.05104 46.29941 -63.04367 46.30030 -63.05891 46.28759 -63.09549 46.27158 -63.12119 46.24536 -63.14260 46.23740 -63.15262 46.24111 -63.17131 46.25563 -63.18329 46.26368 -63.20442 46.26080 -63.21936 46.25223 -63.22722 46.24260 -63.22526 46.22598 -63.21199 46.21019 -63.21382 46.20361 -63.22828 46.20099 -63.27429 46.19150 -63.30365 46.18228 -63.30922 46.17531 -63.29791 46.17312 -63.27837 46.19427 -63.20265 46.18969 -63.18729 46.18006 -63.18534 46.15991 -63.20295 46.15113 -63.23438 46.13884 -63.26024 46.13390 -63.28661 46.14330 -63.33047 46.16053 -63.43205 46.17750 -63.50244 46.19774 -63.58400 46.19962 -63.64017 46.20814 -63.68197 46.23691 -63.73756 46.28649 -63.80939 46.33444 -63.86938 46.34244 -63.85935 46.34656 -63.83600 46.33888 -63.80931 46.32768 -63.77688 46.33286 -63.76332 46.34335 -63.76227 46.35211 -63.76748 46.36418 -63.79679 46.38352 -63.81385 46.39061 -63.83841 46.38063 -63.90436 46.37893 -63.92367 46.39813 -63.95921 46.40044 -63.98653 46.37680 -64.01103 46.37019 -64.03842 46.37503 -64.07468 46.38964 -64.12604 46.39031 -64.14121 46.39781 -64.15499 46.41500 -64.17090 46.43082 -64.16940 46.46046 -64.14670 46.49174 -64.14906 46.52248 -64.16217 46.53946 -64.13912 46.55044 -64.11418 46.55694 -64.10517 46.57056 -64.10227 46.59207 -64.12093 46.61190 -64.12745 46.61724 -64.14003 46.60962 -64.15763 46.58238 -64.16341 46.57779 -64.17913 46.61318 -64.31790 46.61451 -64.34851 46.60631 -64.40302 46.61293 -64.43312 46.62658 -64.45650 46.64493 -64.46414 46.67128 -64.46185 46.71435 -64.44175 46.75799 -64.39782 46.78555 -64.36052 46.83038 -64.30775 46.84767 -64.29231 46.88736 -64.26616 46.91546 -64.24409 46.94013 -64.20313 46.98252 -64.12227 47.00040 -64.09578 47.02237 -64.07732 47.03708 -64.05263 47.04029 -64.01891 47.02471 -64.01510 46.98389 -64.03687 46.95782 -64.04729 46.94355 -64.04793 46.91516 -64.03057 46.87944 -64.02561 46.86398 -64.03495 46.81703 -64.07364 46.78037 -64.11655 46.75734 -64.16966 46.73816 -64.17838 46.73523 -64.14872 46.72435 -64.14193 46.70418 -64.14089 46.68983 -64.12841 46.68738 -64.08788 46.69701 -64.09004 46.70486 -64.09841 46.71806 -64.08791 46.72050 -64.07069 46.70947 -64.05100 46.71032 -64.03470 46.70525 -64.01677 46.65562 -63.97555 46.64149 -63.95769 46.63139 -63.93486 46.62267 -63.92970 46.61035 -63.93707 46.59878 -63.97280 46.58828 -63.97380 46.58138 -63.96228 46.58758 -63.92702 46.58126 -63.91769 46.55423 -63.90507 46.54220 -63.90713 46.52649 -63.92176 46.50028 -63.98185 46.47410 -64.01052 46.45832 -64.01218 46.45479 -63.99334 46.46916 -63.97424 46.48546 -63.94885 46.49643 -63.92401 46.50171 -63.89213 46.49634 -63.87962 46.48355 -63.86637 46.45011 -63.87591 46.44437 -63.85582 46.44131 -63.82626 46.43386 -63.79409 46.43759 -63.76309 46.45300 -63.75375 46.47420 -63.76460 46.49446 -63.77866 46.51448 -63.76649 46.52736 -63.77966 46.53592 -63.77193 46.54827 -63.73305 46.55956 -63.71573 46.55623 -63.69154 46.54316 -63.63376 46.52821 -63.60085 46.51505 -63.56161 46.50260 -63.55604 46.49096 -63.56578 46.47088 -63.59637 46.45685 -63.59172 46.45387 -63.57518 46.46538 -63.55255 46.47224 -63.53262 46.46525 -63.52109 46.45420 -63.50160 46.48146 -63.47709 46.50251 -63.47478 46.48195 -63.39814 46.47459 -63.36069 46.45773 -63.35262 46.43510 -63.37434 46.42108 -63.36977 46.42447 -63.34417 46.43418 -63.30925 46.42720 -63.29787 46.40922 -63.29845 46.39833 -63.29204 46.39457 -63.27333 46.40117 -63.25882 46.41389 -63.24038 46.41901 -63.20842 46.39981 -63.13111 46.39494 -63.10258 46.38131 -63.08737 46.36004 -63.07687 46.35613 -63.06356 46.36376 -63.04057 46.39313 -63.03545 46.40611 -63.04837 46.41392 -63.01994 46.42362 -62.92441 46.41825 -62.88830 46.41012 -62.86716 46.42232 -62.84103 46.42356 -62.80877 46.42151 -62.78366 46.39836 -62.70087 46.39776 -62.65652 46.40681 -62.63237 46.41728 -62.63105 46.42434 -62.64231 46.42598 -62.70189 46.44281 -62.75185 46.45509 -62.74410 46.45609 -62.71713 46.45420 -62.64461 46.45599 -62.61447 46.45519 -62.55163 46.46069 -62.45581 46.45046 -62.40418 46.46057 -62.27614 46.46030 -62.18637 46.45583 -62.13635 46.44685 -62.08925 46.44837 -62.03535 46.43832 -62.02064 46.42853 -62.02436 46.42149 -62.03693 46.40243 -62.09951 46.39315 -62.11077 46.37680 -62.15835 46.35884 -62.18298 46.33741 -62.22590 46.33344 -62.25475 46.33598 -62.26889 46.35451 -62.29926 46.35397 -62.31547 46.34277 -62.33836 46.34223 -62.37825 46.33187 -62.39808 46.32133 -62.39952 46.30834 -62.38675 46.29917 -62.39252 46.29419 -62.40623 46.28577 -62.41419 46.27100 -62.40786 46.25712 -62.42197 46.25083 -62.45491 46.25577 -62.48323 46.24696 -62.50204 46.23821 -62.49703 46.23211 -62.47728 46.22151 -62.46040 46.21016 -62.46497 46.20525 -62.47859 46.20666 -62.50120 46.20137 -62.52566 46.21144 -62.55862 46.21186 -62.58979 46.19803 -62.59848 46.18918 -62.57524 46.17115 -62.55773 46.16533 -62.57453 46.17215 -62.61489 46.15876 -62.61284 46.14410 -62.58270 46.13099 -62.57532 46.11070 -62.55671 46.11585 -62.53769 46.13048 -62.52585 46.13383 -62.51322 46.12985 -62.50002 46.12040 -62.49295 46.10478 -62.48965 46.07229 -62.50233 46.05449 -62.49785 + 46.054498 -62.497853 46.033009 -62.516619 46.034969 -62.546876 46.034185 -62.568223 46.019937 -62.592840 46.008042 -62.589912 46.000325 -62.576516 46.006410 -62.530834 45.993184 -62.523441 45.979499 -62.532164 45.970843 -62.545473 45.965091 -62.603808 45.965352 -62.658349 45.967882 -62.690694 45.965250 -62.723626 45.949816 -62.816659 45.957382 -62.853567 45.969811 -62.900600 46.014321 -62.964168 46.027392 -62.971646 46.035279 -62.961529 46.046873 -62.951842 46.057369 -62.968766 46.057648 -62.999822 46.054216 -63.030723 46.057714 -63.054591 46.071269 -63.051393 46.086286 -62.992627 46.089526 -62.967081 46.107189 -62.935281 46.128452 -62.927287 46.150730 -62.929130 46.135973 -62.982728 46.138221 -63.002237 46.163160 -62.994596 46.177192 -62.999021 46.184592 -63.017998 46.177627 -63.043154 46.183344 -63.068409 46.187720 -63.107538 46.192119 -63.128290 46.206565 -63.140303 46.222121 -63.125505 46.270708 -63.051049 46.299412 -63.043678 46.300308 -63.058910 46.287596 -63.095490 46.271586 -63.121191 46.245364 -63.142606 46.237407 -63.152626 46.241110 -63.171313 46.255632 -63.183296 46.263682 -63.204428 46.260804 -63.219364 46.252232 -63.227222 46.242600 -63.225263 46.225987 -63.211993 46.210199 -63.213825 46.203611 -63.228284 46.200994 -63.274298 46.191505 -63.303653 46.182283 -63.309223 46.175313 -63.297912 46.173128 -63.278372 46.194270 -63.202654 46.189697 -63.187290 46.180067 -63.185341 46.159917 -63.202955 46.151138 -63.234386 46.138843 -63.260244 46.133907 -63.286612 46.143304 -63.330474 46.160531 -63.432051 46.177506 -63.502449 46.197742 -63.584001 46.199628 -63.640178 46.208142 -63.681971 46.236919 -63.737564 46.286497 -63.809399 46.334449 -63.869384 46.342445 -63.859358 46.346565 -63.836008 46.338888 -63.809314 46.327684 -63.776887 46.332864 -63.763324 46.343350 -63.762274 46.352112 -63.767488 46.364183 -63.796795 46.383525 -63.813856 46.390611 -63.838414 46.380632 -63.904361 46.378939 -63.923678 46.398136 -63.959215 46.400448 -63.986533 46.376808 -64.011034 46.370193 -64.038420 46.375031 -64.074682 46.389642 -64.126048 46.390315 -64.141215 46.397813 -64.154999 46.415006 -64.170902 46.430825 -64.169409 46.460465 -64.146706 46.491741 -64.149067 46.522481 -64.162178 46.539466 -64.139121 46.550449 -64.114182 46.556940 -64.105176 46.570560 -64.102270 46.592070 -64.120931 46.611908 -64.127459 46.617249 -64.140038 46.609627 -64.157637 46.582380 -64.163417 46.577798 -64.179131 46.613188 -64.317908 46.614512 -64.348516 46.606312 -64.403024 46.612939 -64.433122 46.626583 -64.456507 46.644936 -64.464145 46.671283 -64.461857 46.714357 -64.441755 46.757994 -64.397820 46.785550 -64.360527 46.830383 -64.307757 46.847672 -64.292318 46.887364 -64.266167 46.915461 -64.244092 46.940137 -64.203137 46.982520 -64.122270 47.000404 -64.095781 47.022379 -64.077323 47.037086 -64.052631 47.040290 -64.018913 47.024716 -64.015106 46.983890 -64.036878 46.957826 -64.047295 46.943557 -64.047934 46.915161 -64.030578 46.879442 -64.025612 46.863982 -64.034953 46.817032 -64.073642 46.780374 -64.116557 46.757340 -64.169663 46.738162 -64.178386 46.735239 -64.148720 46.724353 -64.141930 46.704180 -64.140894 46.689835 -64.128411 46.687388 -64.087880 46.697019 -64.090049 46.704860 -64.098410 46.718069 -64.087913 46.720505 -64.070690 46.709478 -64.051006 46.710329 -64.034703 46.705255 -64.016772 46.655620 -63.975558 46.641494 -63.957699 46.631394 -63.934867 46.622672 -63.929701 46.610356 -63.937076 46.598780 -63.972803 46.588280 -63.973809 46.581380 -63.962288 46.587583 -63.927028 46.581268 -63.917692 46.554234 -63.905079 46.542200 -63.907131 46.526499 -63.921762 46.500282 -63.981854 46.474104 -64.010522 46.458326 -64.012189 46.454791 -63.993340 46.469160 -63.974246 46.485464 -63.948859 46.496434 -63.924018 46.501716 -63.892139 46.496345 -63.879622 46.483556 -63.866370 46.450111 -63.875915 46.444379 -63.855825 46.441315 -63.826265 46.433860 -63.794095 46.437597 -63.763099 46.453001 -63.753753 46.474204 -63.764601 46.494465 -63.778660 46.514486 -63.766496 46.527369 -63.779668 46.535920 -63.771930 46.548278 -63.733054 46.559566 -63.715735 46.556233 -63.691543 46.543164 -63.633768 46.528218 -63.600859 46.515051 -63.561613 46.502601 -63.556045 46.490962 -63.565786 46.470880 -63.596370 46.456858 -63.591722 46.453879 -63.575188 46.465388 -63.552552 46.472247 -63.532627 46.465254 -63.521092 46.454201 -63.501600 46.481461 -63.477090 46.502518 -63.474781 46.481952 -63.398141 46.474591 -63.360699 46.457736 -63.352620 46.435109 -63.374347 46.421080 -63.369776 46.424473 -63.344178 46.434183 -63.309251 46.427205 -63.297872 46.409225 -63.298454 46.398337 -63.292042 46.394577 -63.273336 46.401178 -63.258821 46.413898 -63.240388 46.419019 -63.208424 46.399810 -63.131116 46.394945 -63.102581 46.381319 -63.087375 46.360047 -63.076879 46.356138 -63.063563 46.363768 -63.040575 46.393137 -63.035454 46.406117 -63.048375 46.413929 -63.019940 46.423626 -62.924414 46.418257 -62.888309 46.410129 -62.867161 46.422327 -62.841034 46.423561 -62.808771 46.421516 -62.783660 46.398364 -62.700871 46.397763 -62.656523 46.406815 -62.632373 46.417289 -62.631052 46.424349 -62.642319 46.425988 -62.701897 46.442812 -62.751851 46.455099 -62.744108 46.456091 -62.717133 46.454205 -62.644615 46.455991 -62.614477 46.455193 -62.551633 46.460698 -62.455812 46.450468 -62.404184 46.460575 -62.276147 46.460303 -62.186376 46.455833 -62.136351 46.446856 -62.089255 46.448370 -62.035351 46.438320 -62.020645 46.428533 -62.024368 46.421493 -62.036934 46.402437 -62.099510 46.393152 -62.110777 46.376801 -62.158351 46.358849 -62.182987 46.337410 -62.225901 46.333443 -62.254756 46.335985 -62.268898 46.354512 -62.299267 46.353970 -62.315470 46.342773 -62.338367 46.342230 -62.378254 46.331875 -62.398082 46.321331 -62.399522 46.308342 -62.386752 46.299171 -62.392525 46.294195 -62.406236 46.285771 -62.414197 46.271001 -62.407866 46.257120 -62.421972 46.250834 -62.454916 46.255776 -62.483236 46.246966 -62.502043 46.238215 -62.497031 46.232112 -62.477283 46.221517 -62.460409 46.210160 -62.464978 46.205252 -62.478590 46.206668 -62.501200 46.201371 -62.525663 46.211445 -62.558629 46.211864 -62.589790 46.198039 -62.598486 46.189188 -62.575245 46.171155 -62.557735 46.165337 -62.574532 46.172150 -62.614894 46.158763 -62.612840 46.144102 -62.582703 46.130992 -62.575321 46.110703 -62.556716 46.115852 -62.537690 46.130485 -62.525851 46.133837 -62.513225 46.129850 -62.500027 46.120403 -62.492953 46.104789 -62.489650 46.072291 -62.502332 46.054498 -62.497853 @@ -238,15 +238,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 45.45817 -61.14640 - 45.57614 -60.90345 + 45.458170 -61.146404 + 45.576146 -60.903456 - 45.46158 -61.06156 45.47786 -61.06640 45.48613 -61.05833 45.49544 -61.04181 45.50863 -61.04863 45.50985 -61.06355 45.50627 -61.09722 45.53218 -61.14272 45.54621 -61.14640 45.55457 -61.13827 45.56531 -61.08149 45.57245 -61.05842 45.57127 -61.04359 45.56733 -61.01483 45.57614 -60.97494 45.57301 -60.94298 45.57287 -60.90910 45.56179 -60.90345 45.55114 -60.91575 45.54872 -60.93052 45.54585 -60.96632 45.53933 -60.99681 45.52582 -61.00591 45.49392 -60.99834 45.48174 -61.01685 45.46219 -61.02995 45.45817 -61.04557 45.46158 -61.06156 + 45.461588 -61.061562 45.477860 -61.066405 45.486135 -61.058336 45.495441 -61.041811 45.508633 -61.048638 45.509854 -61.063551 45.506274 -61.097225 45.532182 -61.142729 45.546215 -61.146404 45.554578 -61.138277 45.565318 -61.081499 45.572456 -61.058421 45.571279 -61.043595 45.567330 -61.014833 45.576146 -60.974940 45.573014 -60.942987 45.572876 -60.909103 45.561792 -60.903456 45.551148 -60.915757 45.548728 -60.930529 45.545854 -60.966328 45.539334 -60.996814 45.525826 -61.005913 45.493926 -60.998348 45.481743 -61.016851 45.462193 -61.029951 45.458170 -61.045573 45.461588 -61.061562 @@ -260,15 +260,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 45.47629 -60.97763 - 45.49487 -60.93785 + 45.476290 -60.977631 + 45.494872 -60.937854 - 45.47795 -60.97763 45.49304 -60.96764 45.49487 -60.94549 45.48687 -60.93785 45.47629 -60.94481 45.47795 -60.97763 + 45.477957 -60.977631 45.493045 -60.967647 45.494872 -60.945495 45.486875 -60.937854 45.476290 -60.944814 45.477957 -60.977631 @@ -282,15 +282,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 46.57850 -63.86379 - 46.62738 -63.77514 + 46.578504 -63.863796 + 46.627388 -63.775140 - 46.58244 -63.83307 46.60437 -63.85922 46.62738 -63.86379 46.62386 -63.84500 46.61144 -63.82089 46.59398 -63.77888 46.57850 -63.77514 46.57914 -63.80885 46.58244 -63.83307 + 46.582447 -63.833071 46.604373 -63.859226 46.627388 -63.863796 46.623862 -63.845001 46.611443 -63.820895 46.593980 -63.778884 46.578504 -63.775140 46.579144 -63.808857 46.582447 -63.833071 @@ -304,15 +304,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 43.44796 -66.23693 - 45.98282 -61.00979 + 43.447966 -66.236930 + 45.982824 -61.009794 - 45.98282 -63.99398 45.98180 -63.97255 45.97346 -63.94384 45.96122 -63.92012 45.89396 -63.83083 45.87592 -63.78724 45.85825 -63.72037 45.86714 -63.68913 45.87983 -63.62732 45.87865 -63.60473 45.86944 -63.56118 45.87440 -63.53489 45.86911 -63.48631 45.85676 -63.46277 45.84583 -63.45646 45.83942 -63.46541 45.82111 -63.55652 45.81303 -63.57177 45.80427 -63.56666 45.79739 -63.53724 45.80505 -63.48357 45.80718 -63.45384 45.80726 -63.41761 45.79490 -63.39412 45.79125 -63.37560 45.80320 -63.32444 45.80122 -63.29972 45.79518 -63.28534 45.78557 -63.28339 45.76781 -63.31482 45.75120 -63.38696 45.73480 -63.38646 45.71098 -63.33643 45.70724 -63.31801 45.71953 -63.31055 45.73484 -63.30120 45.73864 -63.26542 45.75980 -63.23957 45.76272 -63.22491 45.75395 -63.21987 45.74017 -63.22822 45.73340 -63.21169 45.73696 -63.19928 45.75028 -63.18334 45.75857 -63.14461 45.75246 -63.11212 45.75685 -63.09659 45.76997 -63.10400 45.77932 -63.12936 45.79508 -63.12752 45.80190 -63.10777 45.80052 -63.08530 45.79439 -63.05278 45.76828 -62.96013 45.76403 -62.91604 45.74080 -62.80350 45.72278 -62.76806 45.71416 -62.73969 45.71111 -62.70013 45.70256 -62.68980 45.68358 -62.69912 45.67409 -62.73348 45.67216 -62.80449 45.66638 -62.82101 45.64975 -62.80806 45.64508 -62.79281 45.62305 -62.80388 45.61233 -62.79238 45.60877 -62.76877 45.62633 -62.75528 45.62695 -62.73935 45.62009 -62.72294 45.61306 -62.71186 45.60862 -62.69125 45.61510 -62.67690 45.63113 -62.68768 45.63911 -62.71375 45.65501 -62.70644 45.66105 -62.68463 45.66790 -62.61820 45.65580 -62.60246 45.64634 -62.59533 45.64183 -62.57488 45.64230 -62.54095 45.62372 -62.53960 45.61282 -62.53349 45.60958 -62.51740 45.62082 -62.49475 45.62361 -62.43336 45.63128 -62.40525 45.64479 -62.40189 45.64952 -62.41710 45.64455 -62.45393 45.64554 -62.46892 45.65597 -62.46758 45.66413 -62.44691 45.68520 -62.35055 45.73170 -62.22491 45.77555 -62.13189 45.82272 -62.04964 45.84833 -62.01489 45.87034 -61.97469 45.87852 -61.94846 45.87605 -61.92912 45.86975 -61.91480 45.85935 -61.91639 45.84183 -61.95372 45.82378 -61.96019 45.78981 -61.95068 45.72754 -61.93850 45.70509 -61.94256 45.66417 -61.96886 45.64454 -61.97615 45.62855 -61.96568 45.62048 -61.93441 45.62461 -61.91871 45.65036 -61.93087 45.66246 -61.92310 45.66695 -61.89676 45.66447 -61.87751 45.65001 -61.86072 45.63377 -61.85557 45.62184 -61.85813 45.61247 -61.84594 45.61607 -61.82280 45.62771 -61.80752 45.62237 -61.75625 45.61959 -61.69035 45.62383 -61.66941 45.63155 -61.65915 45.63520 -61.63065 45.64580 -61.62372 45.65622 -61.62219 45.66409 -61.60670 45.66982 -61.58463 45.66704 -61.54734 45.62157 -61.45173 45.59688 -61.42623 45.57107 -61.41438 45.54499 -61.38453 45.53329 -61.37668 45.52451 -61.36671 45.51628 -61.33574 45.51526 -61.31543 45.50673 -61.29507 45.49091 -61.26892 45.47754 -61.26730 45.45254 -61.29161 45.43340 -61.31717 45.42126 -61.36414 45.40808 -61.38575 45.40266 -61.39704 45.39935 -61.44336 45.38924 -61.46299 45.38519 -61.47865 45.42257 -61.53212 45.43817 -61.56352 45.44194 -61.59224 45.43708 -61.61102 45.42669 -61.60731 45.41152 -61.56004 45.40226 -61.54278 45.37506 -61.53193 45.35316 -61.51502 45.33889 -61.48798 45.33220 -61.45603 45.33724 -61.43203 45.34266 -61.38694 45.34036 -61.35731 45.32795 -61.31351 45.32548 -61.28925 45.33680 -61.24547 45.33030 -61.19778 45.33272 -61.15463 45.32148 -61.12044 45.31824 -61.05503 45.30632 -61.01880 45.29232 -61.00979 45.27226 -61.01018 45.26901 -61.02263 45.28059 -61.04093 45.27738 -61.05348 45.26171 -61.05603 45.22863 -61.07796 45.20038 -61.11994 45.19370 -61.15534 45.19922 -61.17761 45.20723 -61.18535 45.23814 -61.16242 45.25015 -61.15975 45.26999 -61.17007 45.27557 -61.18709 45.27234 -61.19963 45.25577 -61.21041 45.22609 -61.20923 45.21254 -61.21809 45.22612 -61.24285 45.23449 -61.26843 45.23097 -61.29671 45.23421 -61.31781 45.23075 -61.34079 45.21891 -61.37180 45.19814 -61.40345 45.18478 -61.40180 45.17868 -61.37743 45.18625 -61.33881 45.17993 -61.31968 45.16446 -61.31690 45.15727 -61.33973 45.15030 -61.41918 45.14317 -61.43671 45.13658 -61.46679 45.13264 -61.50538 45.13866 -61.53512 45.13956 -61.56037 45.13450 -61.58425 45.13205 -61.62186 45.15088 -61.70262 45.14510 -61.72431 45.13670 -61.73225 45.12570 -61.69808 45.11580 -61.67871 45.10045 -61.69891 45.07100 -61.68688 45.06624 -61.70024 45.07645 -61.73745 45.06467 -61.78607 45.07760 -61.83187 45.07349 -61.84740 45.05860 -61.84658 45.04993 -61.86490 45.03882 -61.86434 45.02755 -61.86894 45.02041 -61.88629 45.03106 -61.90258 45.03586 -61.91753 45.02059 -61.93235 45.02452 -61.95044 45.04280 -61.98501 45.03191 -62.00217 45.02398 -61.99432 45.01089 -61.98729 45.00533 -61.99847 45.00426 -62.03500 44.99325 -62.08044 44.98755 -62.09685 44.97707 -62.07528 44.98071 -62.05248 44.97903 -62.03564 44.97357 -62.01852 44.96464 -62.01905 44.95846 -62.05118 44.95278 -62.14179 44.94374 -62.17040 44.93181 -62.19586 44.92592 -62.21738 44.93400 -62.24296 44.93551 -62.26504 44.92271 -62.29342 44.90400 -62.32044 44.89914 -62.33368 44.89982 -62.35880 44.89049 -62.36970 44.87994 -62.37628 44.87330 -62.39573 44.87717 -62.41363 44.87363 -62.43121 44.84306 -62.47807 44.84315 -62.49591 44.86694 -62.49651 44.87307 -62.51048 44.86885 -62.52587 44.85236 -62.53094 44.83951 -62.53628 44.83358 -62.55782 44.83718 -62.58101 44.79058 -62.57657 44.77825 -62.58930 44.78212 -62.60728 44.80154 -62.62324 44.80885 -62.64665 44.79649 -62.65936 44.78922 -62.67650 44.77248 -62.68679 44.76757 -62.69994 44.77417 -62.72133 44.77653 -62.75789 44.76252 -62.79435 44.76189 -62.80998 44.78592 -62.84098 44.78736 -62.86295 44.78390 -62.87523 44.77277 -62.87433 44.76249 -62.85268 44.74720 -62.84423 44.73490 -62.85682 44.70440 -62.83989 44.69509 -62.85058 44.69381 -62.86400 44.70733 -62.89626 44.70967 -62.93288 44.70576 -62.97315 44.69538 -63.00975 44.70107 -63.03418 44.72280 -63.04635 44.74501 -63.04814 44.76020 -63.05671 44.76789 -63.06976 44.75438 -63.09067 44.74200 -63.08544 44.71742 -63.06978 44.69085 -63.06554 44.67282 -63.07141 44.67174 -63.09732 44.69478 -63.11371 44.70894 -63.13055 44.73935 -63.12994 44.75113 -63.13309 44.75853 -63.15144 44.75070 -63.16107 44.69850 -63.16711 44.67951 -63.17592 44.67590 -63.19331 44.68607 -63.19727 44.71371 -63.19345 44.73372 -63.19402 44.73894 -63.21119 44.73000 -63.22912 44.68672 -63.23479 44.66773 -63.24357 44.67362 -63.26274 44.69491 -63.26771 44.70488 -63.27691 44.67769 -63.30580 44.65505 -63.29650 44.64529 -63.29980 44.63657 -63.31257 44.61282 -63.32925 44.62313 -63.38102 44.61778 -63.41691 44.62356 -63.43614 44.65330 -63.45125 44.66368 -63.46788 44.66446 -63.48247 44.65943 -63.49551 44.63660 -63.49131 44.60981 -63.46191 44.58642 -63.48578 44.58571 -63.50117 44.59608 -63.51778 44.60091 -63.55762 44.63726 -63.58915 44.64478 -63.60231 44.66100 -63.62047 44.67410 -63.64042 44.69605 -63.67790 44.69535 -63.69343 44.66208 -63.69034 44.64654 -63.67417 44.63098 -63.62804 44.62190 -63.61577 44.60901 -63.62077 44.59063 -63.60144 44.57791 -63.58882 44.55573 -63.58677 44.53772 -63.59225 44.52289 -63.59087 44.50667 -63.57277 44.48720 -63.56159 44.44753 -63.58491 44.44685 -63.60036 44.45305 -63.60928 44.45752 -63.62410 44.45312 -63.63924 44.43808 -63.64304 44.43063 -63.65988 44.43141 -63.67450 44.44660 -63.68316 44.45525 -63.71817 44.45063 -63.75089 44.45968 -63.76314 44.46569 -63.77711 44.45925 -63.81589 44.46373 -63.83084 44.48277 -63.83475 44.48701 -63.85491 44.47472 -63.89200 44.48965 -63.94844 44.49845 -63.96593 44.51482 -63.97897 44.53751 -63.97093 44.55452 -63.95603 44.57298 -63.95792 44.60447 -63.96739 44.61977 -63.95849 44.65636 -63.92477 44.65079 -63.96063 44.63595 -63.98932 44.61740 -64.06023 44.60528 -64.07973 44.59393 -64.08374 44.55639 -64.07766 44.52940 -64.08323 44.49535 -64.05276 44.48495 -64.05370 44.47587 -64.08387 44.45855 -64.10377 44.45250 -64.11974 44.46687 -64.15651 44.47975 -64.16407 44.50869 -64.16507 44.52937 -64.18073 44.54703 -64.21071 44.54838 -64.23993 44.52537 -64.25293 44.52456 -64.28092 44.53034 -64.33762 44.51628 -64.35060 44.47480 -64.34913 44.46594 -64.36166 44.44194 -64.35267 44.43244 -64.36316 44.42730 -64.38837 44.41049 -64.39789 44.39537 -64.38899 44.38954 -64.37492 44.39947 -64.34182 44.39822 -64.32512 44.38986 -64.31496 44.37393 -64.32151 44.36032 -64.28689 44.34709 -64.28443 44.33977 -64.29597 44.34792 -64.33618 44.33970 -64.36316 44.32714 -64.37528 44.31180 -64.37141 44.31042 -64.34239 44.31135 -64.32705 44.30147 -64.31760 44.27481 -64.33023 44.27750 -64.29649 44.27067 -64.28539 44.25617 -64.27874 44.24271 -64.29373 44.23489 -64.31555 44.24020 -64.33989 44.27832 -64.37290 44.28212 -64.38578 44.27078 -64.40196 44.25515 -64.40342 44.24504 -64.42395 44.22510 -64.43513 44.21816 -64.46632 44.14342 -64.52789 44.13246 -64.57603 44.12788 -64.65272 44.11774 -64.66090 44.10615 -64.63274 44.10730 -64.60004 44.09170 -64.58890 44.05398 -64.61235 44.04812 -64.62297 44.04815 -64.64765 44.04354 -64.66245 44.03253 -64.67357 44.02177 -64.70410 43.99448 -64.71426 43.96938 -64.72575 43.95921 -64.74608 43.94882 -64.75917 43.93924 -64.79397 43.92845 -64.82441 43.92440 -64.85363 43.90969 -64.87641 43.89497 -64.87475 43.88673 -64.86443 43.87792 -64.82763 43.85895 -64.81097 43.84917 -64.81390 43.84361 -64.83173 43.83652 -64.85022 43.82392 -64.86207 43.81659 -64.87349 43.82730 -64.89214 43.85113 -64.90117 43.86454 -64.93553 43.86138 -64.94948 43.85127 -64.95738 43.83387 -64.92772 43.79498 -64.93427 43.78760 -64.94556 43.79119 -64.95829 43.81939 -64.96988 43.83978 -64.98572 43.83825 -64.99877 43.82653 -65.00764 43.79084 -64.98793 43.77187 -64.98349 43.75190 -64.99431 43.75299 -65.02305 43.77348 -65.03894 43.78782 -65.04582 43.79722 -65.06021 43.79628 -65.07541 43.77604 -65.07903 43.73541 -65.05460 43.70107 -65.07075 43.68747 -65.09757 43.70421 -65.11294 43.71394 -65.12234 43.71027 -65.13411 43.67766 -65.15658 43.65194 -65.16558 43.64907 -65.18653 43.67104 -65.18936 43.69071 -65.18373 43.70074 -65.18805 43.69658 -65.21709 43.74845 -65.25026 43.75416 -65.26436 43.75276 -65.28460 43.73704 -65.29788 43.72761 -65.29571 43.70626 -65.28264 43.67931 -65.28741 43.65872 -65.29591 43.65134 -65.30721 43.65904 -65.33466 43.66729 -65.34496 43.67731 -65.34930 43.70611 -65.35103 43.71722 -65.37196 43.71375 -65.39087 43.70510 -65.39789 43.63207 -65.38321 43.61044 -65.37522 43.58270 -65.38992 43.56809 -65.38805 43.55214 -65.39411 43.54687 -65.40663 43.54237 -65.42832 43.54345 -65.44484 43.55832 -65.45397 43.56344 -65.46571 43.55586 -65.48923 43.53640 -65.48256 43.52313 -65.46048 43.51129 -65.44970 43.48813 -65.44260 43.47824 -65.44532 43.47026 -65.45440 43.48962 -65.47324 43.50357 -65.48527 43.49428 -65.50239 43.47135 -65.50238 43.45536 -65.50829 43.44796 -65.51952 43.46698 -65.54344 43.48540 -65.59672 43.51281 -65.60651 43.51808 -65.62554 43.51054 -65.64895 43.50030 -65.65670 43.48384 -65.67981 43.47641 -65.71037 43.47714 -65.73178 43.47214 -65.75852 43.47535 -65.77624 43.48442 -65.78356 43.49636 -65.78224 43.50864 -65.77584 43.51526 -65.78697 43.52557 -65.81780 43.53829 -65.82577 43.56683 -65.82054 43.59725 -65.80960 43.64235 -65.80059 43.65785 -65.81197 43.65828 -65.82637 43.64802 -65.83410 43.62969 -65.83150 43.61620 -65.83372 43.58846 -65.84809 43.61167 -65.87487 43.62592 -65.88198 43.68868 -65.88582 43.73416 -65.87178 43.76061 -65.88487 43.76645 -65.90605 43.76378 -65.92202 43.77616 -65.93516 43.79772 -65.94334 43.80644 -65.95584 43.80627 -65.96811 43.79757 -65.97504 43.78239 -65.97080 43.77157 -65.97644 43.76341 -65.98544 43.76873 -66.00467 43.77947 -66.01852 43.76236 -66.03957 43.73707 -66.01133 43.72270 -66.00411 43.71021 -66.00332 43.69475 -66.01126 43.68995 -66.02592 43.68902 -66.04822 43.67663 -66.05463 43.67469 -66.07988 43.68321 -66.08523 43.70291 -66.07988 43.70949 -66.09110 43.70503 -66.12007 43.71254 -66.12839 43.72660 -66.12843 43.74028 -66.13345 43.74065 -66.14789 43.74525 -66.16489 43.77534 -66.17866 43.78310 -66.19411 43.80715 -66.19872 43.83510 -66.21112 43.86042 -66.20059 43.87567 -66.20487 43.89113 -66.21644 43.92608 -66.19597 43.96184 -66.20442 44.00820 -66.20011 44.03735 -66.21679 44.07638 -66.23097 44.10258 -66.23693 44.13126 -66.23200 44.20379 -66.18721 44.23386 -66.17410 44.30255 -66.16062 44.32418 -66.14934 44.35965 -66.12352 44.37992 -66.10069 44.42467 -66.05019 44.46070 -65.98700 44.51464 -65.91161 44.53934 -65.89860 44.55647 -65.90943 44.56171 -65.92894 44.54913 -65.96773 44.55360 -65.99749 44.54844 -66.01761 44.49052 -66.08486 44.46748 -66.10429 44.42855 -66.15672 44.40139 -66.18063 44.39322 -66.18981 44.38020 -66.21386 44.38265 -66.22970 44.39639 -66.23493 44.41136 -66.22473 44.43520 -66.19517 44.45947 -66.16034 44.49450 -66.13957 44.50790 -66.11037 44.55523 -66.05608 44.58880 -65.96048 44.64573 -65.87399 44.65864 -65.83554 44.65646 -65.81444 44.64711 -65.79951 44.62691 -65.79037 44.59899 -65.78531 44.58066 -65.75042 44.58097 -65.72557 44.58903 -65.69648 44.61113 -65.66734 44.61984 -65.66023 44.64571 -65.63146 44.67242 -65.59973 44.69378 -65.56090 44.72362 -65.49510 44.73672 -65.47809 44.76169 -65.47204 44.76023 -65.49272 44.74588 -65.51793 44.71108 -65.61136 44.67711 -65.68179 44.65742 -65.75935 44.66061 -65.77742 44.67031 -65.78715 44.68073 -65.78660 44.69852 -65.76720 44.72203 -65.72988 44.75263 -65.66621 44.76981 -65.64450 44.80234 -65.56229 44.84323 -65.46533 44.88354 -65.39855 44.90961 -65.33175 44.94710 -65.26124 45.00895 -65.15701 45.03001 -65.13034 45.04845 -65.08748 45.07142 -65.04204 45.11271 -64.95375 45.12151 -64.92110 45.12617 -64.89322 45.14602 -64.82409 45.17173 -64.71874 45.23932 -64.47797 45.25713 -64.45254 45.27072 -64.44993 45.27998 -64.45728 45.29273 -64.48296 45.30356 -64.51488 45.31373 -64.53188 45.32760 -64.52401 45.31858 -64.47324 45.29403 -64.39344 45.28069 -64.37822 45.25664 -64.36918 45.22798 -64.38808 45.21080 -64.40293 45.18616 -64.41701 45.17445 -64.41360 45.15072 -64.39941 45.13776 -64.40424 45.11993 -64.42952 45.10884 -64.42834 45.09897 -64.41880 45.08993 -64.39362 45.09391 -64.37622 45.11173 -64.36345 45.11482 -64.34908 45.10663 -64.32086 45.07781 -64.27669 45.03940 -64.23045 45.01926 -64.21670 44.98571 -64.20579 44.97797 -64.19756 44.96879 -64.15990 44.96526 -64.12918 44.97100 -64.10569 44.98233 -64.10155 44.98913 -64.11285 44.99207 -64.12883 44.99311 -64.15099 45.00553 -64.16913 45.03010 -64.15497 45.05013 -64.16864 45.08091 -64.21921 45.10817 -64.23902 45.12606 -64.23883 45.16134 -64.21848 45.18648 -64.19387 45.19746 -64.16980 45.22368 -64.06825 45.24957 -63.94123 45.27200 -63.86450 45.29098 -63.81266 45.29823 -63.80069 45.29903 -63.78490 45.29673 -63.77100 45.30138 -63.73767 45.30873 -63.70782 45.30414 -63.67986 45.29536 -63.64425 45.30431 -63.56493 45.30070 -63.54660 45.27665 -63.52015 45.28169 -63.50694 45.29919 -63.49906 45.31374 -63.50567 45.32734 -63.48479 45.33963 -63.47745 45.35326 -63.48718 45.35714 -63.51817 45.35608 -63.55716 45.37664 -63.62666 45.37111 -63.68112 45.37329 -63.74367 45.38039 -63.78032 45.38066 -63.80573 45.35106 -63.90740 45.34666 -63.93541 45.35149 -63.95807 45.36191 -63.98778 45.36888 -64.01169 45.37179 -64.04062 45.37050 -64.06685 45.37214 -64.09132 45.38626 -64.12142 45.38764 -64.15119 45.38039 -64.17572 45.37898 -64.20201 45.38705 -64.21773 45.38808 -64.24008 45.38300 -64.26595 45.37286 -64.28704 45.36649 -64.30859 45.36182 -64.39260 45.35096 -64.46749 45.35349 -64.48896 45.37951 -64.55534 45.38817 -64.58607 45.39344 -64.63638 45.38603 -64.67370 45.37026 -64.71298 45.35334 -64.73528 45.31042 -64.76707 45.29802 -64.79942 45.29890 -64.82175 45.31432 -64.83837 45.33672 -64.87393 45.33916 -64.89541 45.33261 -64.91675 45.32197 -64.96832 45.32409 -64.98229 45.33549 -64.99114 45.39515 -64.95533 45.44814 -64.88242 45.46542 -64.86768 45.48930 -64.80586 45.50880 -64.76681 45.58019 -64.64480 45.64034 -64.54662 45.67697 -64.49236 45.70040 -64.47382 45.70971 -64.46839 45.73776 -64.44713 45.74940 -64.42498 45.76241 -64.42008 45.78065 -64.41473 45.78914 -64.36872 45.77766 -64.35994 45.75025 -64.38352 45.74067 -64.38133 45.73846 -64.36727 45.74667 -64.32662 45.76138 -64.31542 45.77608 -64.33524 45.78865 -64.32277 45.80810 -64.30890 45.80812 -64.30892 45.82397 -64.29481 45.94073 -64.19468 45.95318 -64.19255 45.96819 -64.08843 45.96807 -64.03141 45.97293 -63.99925 45.98157 -63.99453 45.98282 -63.99398 + 45.982824 -63.993981 45.981800 -63.972552 45.973465 -63.943849 45.961227 -63.920124 45.893962 -63.830838 45.875924 -63.787247 45.858253 -63.720376 45.867146 -63.689137 45.879832 -63.627321 45.878654 -63.604733 45.869442 -63.561186 45.874409 -63.534894 45.869112 -63.486319 45.856760 -63.462774 45.845831 -63.456461 45.839424 -63.465417 45.821112 -63.556528 45.813031 -63.571776 45.804278 -63.566664 45.797393 -63.537241 45.805055 -63.483571 45.807187 -63.453845 45.807268 -63.417617 45.794901 -63.394123 45.791251 -63.375605 45.803200 -63.324445 45.801224 -63.299722 45.795186 -63.285346 45.785574 -63.283394 45.767817 -63.314829 45.751205 -63.386961 45.734802 -63.386468 45.710981 -63.336435 45.707242 -63.318014 45.719538 -63.310557 45.734848 -63.301206 45.738647 -63.265429 45.759809 -63.239570 45.762725 -63.224911 45.753956 -63.219873 45.740177 -63.228224 45.733403 -63.211697 45.736964 -63.199286 45.750283 -63.183349 45.758571 -63.144611 45.752466 -63.112122 45.756850 -63.096592 45.769973 -63.104004 45.779324 -63.129369 45.795080 -63.127528 45.801906 -63.107777 45.800521 -63.085301 45.794393 -63.052788 45.768287 -62.960132 45.764032 -62.916041 45.740807 -62.803508 45.722785 -62.768060 45.714161 -62.739696 45.711119 -62.700136 45.702563 -62.689809 45.683580 -62.699127 45.674090 -62.733486 45.672162 -62.804496 45.666389 -62.821011 45.649759 -62.808063 45.645088 -62.792816 45.623055 -62.803887 45.612338 -62.792380 45.608779 -62.768774 45.626333 -62.755283 45.626951 -62.739351 45.620091 -62.722941 45.613067 -62.711863 45.608621 -62.691253 45.615108 -62.676908 45.631136 -62.687682 45.639114 -62.713757 45.655016 -62.706445 45.661051 -62.684637 45.667903 -62.618209 45.655802 -62.602460 45.646340 -62.595331 45.641832 -62.574887 45.642304 -62.540956 45.623728 -62.539609 45.612824 -62.533491 45.609589 -62.517404 45.620829 -62.494755 45.623613 -62.433363 45.631285 -62.405258 45.644792 -62.401894 45.649528 -62.417100 45.644550 -62.453931 45.645540 -62.468925 45.655977 -62.467588 45.664136 -62.446913 45.685203 -62.350552 45.731705 -62.224910 45.775551 -62.131894 45.822724 -62.049641 45.848330 -62.014899 45.870347 -61.974690 45.878520 -61.948466 45.876051 -61.929127 45.869751 -61.914804 45.859357 -61.916390 45.841830 -61.953724 45.823788 -61.960193 45.789817 -61.950686 45.727545 -61.938500 45.705095 -61.942567 45.664172 -61.968862 45.644547 -61.976155 45.628555 -61.965681 45.620481 -61.934417 45.624616 -61.918710 45.650368 -61.930870 45.662466 -61.923103 45.666954 -61.896760 45.664476 -61.877515 45.650015 -61.860723 45.633775 -61.855572 45.621841 -61.858131 45.612479 -61.845946 45.616073 -61.822804 45.627712 -61.807521 45.622370 -61.756256 45.619590 -61.690359 45.623830 -61.669410 45.631557 -61.659157 45.635205 -61.630659 45.645805 -61.623729 45.656229 -61.622194 45.664095 -61.606700 45.669821 -61.584633 45.667043 -61.547346 45.621572 -61.451732 45.596882 -61.426233 45.571071 -61.414382 45.544994 -61.384535 45.533294 -61.376683 45.524519 -61.366714 45.516288 -61.335744 45.515269 -61.315437 45.506739 -61.295070 45.490916 -61.268926 45.477543 -61.267307 45.452548 -61.291612 45.433402 -61.317174 45.421267 -61.364141 45.408084 -61.385753 45.402663 -61.397044 45.399352 -61.443365 45.389242 -61.462990 45.385190 -61.478656 45.422573 -61.532126 45.438174 -61.563522 45.441947 -61.592248 45.437086 -61.611029 45.426695 -61.607316 45.411520 -61.560044 45.402267 -61.542787 45.375068 -61.531938 45.353168 -61.515029 45.338890 -61.487987 45.332207 -61.456037 45.337242 -61.432031 45.342662 -61.386942 45.340369 -61.357315 45.327955 -61.313510 45.325482 -61.289255 45.336802 -61.245479 45.330303 -61.197786 45.332720 -61.154630 45.321487 -61.120444 45.318249 -61.055031 45.306325 -61.018809 45.292321 -61.009794 45.272262 -61.010186 45.269010 -61.022638 45.280596 -61.040931 45.277383 -61.053488 45.261714 -61.056036 45.228635 -61.077960 45.200386 -61.119941 45.193707 -61.155342 45.199221 -61.177617 45.207231 -61.185356 45.238140 -61.162429 45.250155 -61.159755 45.269991 -61.170070 45.275575 -61.187090 45.272343 -61.199638 45.255779 -61.210415 45.226096 -61.209233 45.212541 -61.218097 45.226123 -61.242859 45.234499 -61.268437 45.230971 -61.296710 45.234214 -61.317813 45.230755 -61.340798 45.218918 -61.371806 45.198140 -61.403458 45.184786 -61.401807 45.178683 -61.377439 45.186255 -61.338814 45.179932 -61.319686 45.164464 -61.316903 45.157275 -61.339733 45.150301 -61.419185 45.143174 -61.436717 45.136584 -61.466798 45.132646 -61.505386 45.138663 -61.535127 45.139567 -61.560370 45.134501 -61.584254 45.132059 -61.621865 45.150889 -61.702625 45.145104 -61.724315 45.136704 -61.732259 45.125701 -61.698080 45.115802 -61.678716 45.100455 -61.698916 45.071007 -61.686889 45.066240 -61.700241 45.076451 -61.737457 45.064678 -61.786075 45.077604 -61.831876 45.073494 -61.847400 45.058609 -61.846581 45.049931 -61.864901 45.038821 -61.864349 45.027553 -61.868946 45.020419 -61.886297 45.031062 -61.902588 45.035869 -61.917534 45.020592 -61.932359 45.024521 -61.950440 45.042804 -61.985012 45.031919 -62.002174 45.023986 -61.994321 45.010895 -61.987292 45.005332 -61.998472 45.004267 -62.035002 44.993255 -62.080440 44.987554 -62.096858 44.977075 -62.075285 44.980718 -62.052487 44.979032 -62.035648 44.973572 -62.018524 44.964645 -62.019059 44.958463 -62.051180 44.952787 -62.141797 44.943747 -62.170408 44.931819 -62.195861 44.925921 -62.217382 44.934008 -62.242967 44.935517 -62.265044 44.922713 -62.293420 44.904000 -62.320441 44.899143 -62.333680 44.899820 -62.358800 44.890490 -62.369704 44.879946 -62.376281 44.873307 -62.395739 44.877176 -62.413635 44.873632 -62.431219 44.843061 -62.478076 44.843152 -62.495918 44.866942 -62.496511 44.873078 -62.510486 44.868855 -62.525878 44.852363 -62.530945 44.839518 -62.536284 44.833584 -62.557825 44.837185 -62.581011 44.790589 -62.576573 44.778250 -62.589305 44.782120 -62.607285 44.801542 -62.623245 44.808850 -62.646650 44.796499 -62.659365 44.789221 -62.676501 44.772488 -62.686791 44.767579 -62.699949 44.774175 -62.721334 44.776538 -62.757892 44.762520 -62.794357 44.761895 -62.809986 44.785925 -62.840985 44.787365 -62.862952 44.783908 -62.875238 44.772776 -62.874332 44.762495 -62.852681 44.747202 -62.844239 44.734904 -62.856823 44.704402 -62.839891 44.695098 -62.850587 44.693810 -62.864009 44.707338 -62.896262 44.709672 -62.932887 44.705766 -62.973158 44.695384 -63.009754 44.701072 -63.034182 44.722800 -63.046355 44.745012 -63.048140 44.760208 -63.056713 44.767890 -63.069764 44.754386 -63.090672 44.742006 -63.085448 44.717428 -63.069788 44.690851 -63.065547 44.672827 -63.071412 44.671741 -63.097324 44.694785 -63.113719 44.708949 -63.130553 44.739357 -63.129940 44.751131 -63.133096 44.758536 -63.151442 44.750707 -63.161071 44.698504 -63.167118 44.679517 -63.175922 44.675906 -63.193312 44.686074 -63.197275 44.713714 -63.193451 44.733720 -63.194027 44.738949 -63.211198 44.730008 -63.229124 44.686725 -63.234797 44.667733 -63.243571 44.673629 -63.262741 44.694917 -63.267719 44.704886 -63.276917 44.677697 -63.305807 44.655051 -63.296500 44.645292 -63.299803 44.636577 -63.312576 44.612826 -63.329257 44.623132 -63.381021 44.617788 -63.416913 44.623568 -63.436144 44.653307 -63.451259 44.663686 -63.467888 44.664463 -63.482470 44.659439 -63.495510 44.636607 -63.491319 44.609818 -63.461913 44.586428 -63.485782 44.585718 -63.501172 44.596085 -63.517788 44.600912 -63.557620 44.637264 -63.589152 44.644786 -63.602316 44.661009 -63.620476 44.674105 -63.640426 44.696054 -63.677904 44.695352 -63.693438 44.662082 -63.690340 44.646542 -63.674177 44.630987 -63.628049 44.621907 -63.615771 44.609013 -63.620776 44.590639 -63.601446 44.577918 -63.588822 44.555734 -63.586777 44.537725 -63.592253 44.522898 -63.590871 44.506679 -63.572776 44.487201 -63.561599 44.447535 -63.584914 44.446850 -63.600362 44.453059 -63.609280 44.457527 -63.624102 44.453121 -63.639248 44.438084 -63.643041 44.430630 -63.659884 44.431416 -63.674503 44.446606 -63.683164 44.455254 -63.718175 44.450634 -63.750892 44.459687 -63.763149 44.465691 -63.777111 44.459258 -63.815892 44.463732 -63.830845 44.482774 -63.834758 44.487015 -63.854910 44.474720 -63.892002 44.489658 -63.948441 44.498450 -63.965939 44.514825 -63.978979 44.537512 -63.970935 44.554528 -63.956032 44.572989 -63.957926 44.604474 -63.967397 44.619773 -63.958493 44.656361 -63.924778 44.650797 -63.960630 44.635953 -63.989326 44.617408 -64.060231 44.605288 -64.079737 44.593937 -64.083740 44.556397 -64.077664 44.529404 -64.083235 44.495357 -64.052760 44.484954 -64.053701 44.475874 -64.083873 44.458556 -64.103775 44.452503 -64.119742 44.466879 -64.156511 44.479759 -64.164074 44.508690 -64.165073 44.529371 -64.180732 44.547035 -64.210716 44.548383 -64.239938 44.525378 -64.252934 44.524567 -64.280923 44.530345 -64.337626 44.516284 -64.350604 44.474806 -64.349138 44.465949 -64.361661 44.441949 -64.352676 44.432440 -64.363164 44.427307 -64.388372 44.410490 -64.397892 44.395372 -64.388998 44.389545 -64.374922 44.399475 -64.341823 44.398224 -64.325125 44.389868 -64.314961 44.373934 -64.321512 44.360328 -64.286895 44.347092 -64.284435 44.339776 -64.295970 44.347920 -64.336183 44.339703 -64.363168 44.327140 -64.375284 44.311805 -64.371416 44.310423 -64.342396 44.311356 -64.327059 44.301474 -64.317604 44.274817 -64.330238 44.277505 -64.296491 44.270676 -64.285392 44.256174 -64.278743 44.242716 -64.293733 44.234890 -64.315555 44.240208 -64.339894 44.278320 -64.372908 44.282123 -64.385782 44.270786 -64.401968 44.255157 -64.403421 44.245044 -64.423958 44.225103 -64.435130 44.218162 -64.466327 44.143425 -64.527892 44.132466 -64.576039 44.127885 -64.652727 44.117748 -64.660902 44.106153 -64.632748 44.107307 -64.600042 44.091702 -64.588909 44.053982 -64.612357 44.048123 -64.622979 44.048159 -64.647654 44.043548 -64.662457 44.032531 -64.673575 44.021770 -64.704107 43.994488 -64.714266 43.969383 -64.725750 43.959210 -64.746088 43.948829 -64.759171 43.939249 -64.793972 43.928452 -64.824417 43.924404 -64.853639 43.909692 -64.876416 43.894973 -64.874751 43.886739 -64.864436 43.877924 -64.827639 43.858950 -64.810974 43.849175 -64.813900 43.843615 -64.831730 43.836521 -64.850221 43.823922 -64.862073 43.816590 -64.873492 43.827300 -64.892140 43.851134 -64.901177 43.864546 -64.935538 43.861382 -64.949480 43.851270 -64.957382 43.833878 -64.927729 43.794981 -64.934270 43.787601 -64.945563 43.791193 -64.958294 43.819392 -64.969884 43.839783 -64.985720 43.838259 -64.998772 43.826535 -65.007645 43.790840 -64.987936 43.771875 -64.983499 43.751909 -64.994314 43.752996 -65.023057 43.773488 -65.038947 43.787820 -65.045820 43.797221 -65.060212 43.796283 -65.075419 43.776048 -65.079039 43.735411 -65.054602 43.701073 -65.070755 43.687472 -65.097574 43.704211 -65.112949 43.713940 -65.122343 43.710273 -65.134116 43.677665 -65.156585 43.651947 -65.165584 43.649076 -65.186536 43.671043 -65.189360 43.690718 -65.183739 43.700746 -65.188053 43.696581 -65.217098 43.748452 -65.250269 43.754163 -65.264369 43.752760 -65.284601 43.737043 -65.297883 43.727610 -65.295712 43.706266 -65.282649 43.679312 -65.287415 43.658728 -65.295911 43.651344 -65.307218 43.659047 -65.334668 43.667295 -65.344962 43.677313 -65.349308 43.706115 -65.351030 43.717227 -65.371964 43.713757 -65.390872 43.705106 -65.397896 43.632078 -65.383218 43.610440 -65.375223 43.582702 -65.389920 43.568094 -65.388050 43.552146 -65.394115 43.546874 -65.406630 43.542374 -65.428323 43.543453 -65.444848 43.558323 -65.453976 43.563448 -65.465715 43.555867 -65.489233 43.536405 -65.482562 43.523131 -65.460483 43.511291 -65.449701 43.488138 -65.442606 43.478244 -65.445324 43.470262 -65.454407 43.489624 -65.473246 43.503577 -65.485278 43.494280 -65.502391 43.471355 -65.502389 43.455369 -65.508297 43.447966 -65.519523 43.466984 -65.543446 43.485401 -65.596720 43.512810 -65.606510 43.518087 -65.625543 43.510544 -65.648958 43.500308 -65.656701 43.483847 -65.679810 43.476417 -65.710371 43.477144 -65.731782 43.472147 -65.758528 43.475355 -65.776247 43.484424 -65.783569 43.496365 -65.782241 43.508647 -65.775846 43.515263 -65.786978 43.525578 -65.817804 43.538293 -65.825777 43.566832 -65.820548 43.597252 -65.809604 43.642357 -65.800594 43.657851 -65.811972 43.658281 -65.826375 43.648022 -65.834103 43.629691 -65.831504 43.616204 -65.833723 43.588468 -65.848095 43.611674 -65.874876 43.625927 -65.881981 43.688686 -65.885829 43.734166 -65.871785 43.760614 -65.884870 43.766452 -65.906053 43.763789 -65.922022 43.776160 -65.935163 43.797725 -65.943341 43.806444 -65.955849 43.806276 -65.968118 43.797575 -65.975048 43.782392 -65.970803 43.771579 -65.976449 43.763414 -65.985442 43.768731 -66.004675 43.779473 -66.018521 43.762360 -66.039570 43.737076 -66.011339 43.722707 -66.004118 43.710216 -66.003327 43.694750 -66.011268 43.689958 -66.025926 43.689029 -66.048226 43.676638 -66.054630 43.674695 -66.079886 43.683215 -66.085232 43.702910 -66.079886 43.709493 -66.091109 43.705030 -66.120075 43.712540 -66.128396 43.726609 -66.128436 43.740281 -66.133459 43.740657 -66.147891 43.745253 -66.164899 43.775349 -66.178661 43.783100 -66.194119 43.807155 -66.198722 43.835107 -66.211124 43.860422 -66.200598 43.875679 -66.204873 43.891138 -66.216444 43.926080 -66.195972 43.961840 -66.204422 44.008201 -66.200114 44.037357 -66.216798 44.076384 -66.230978 44.102584 -66.236930 44.131263 -66.232004 44.203791 -66.187218 44.233860 -66.174108 44.302555 -66.160625 44.324181 -66.149342 44.359659 -66.123522 44.379929 -66.100690 44.424676 -66.050190 44.460703 -65.987006 44.514642 -65.911618 44.539345 -65.898606 44.556478 -65.909438 44.561714 -65.928941 44.549131 -65.967730 44.553607 -65.997497 44.548442 -66.017616 44.490528 -66.084869 44.467482 -66.104298 44.428553 -66.156720 44.401393 -66.180630 44.393220 -66.189818 44.380207 -66.213867 44.382650 -66.229701 44.396396 -66.234936 44.411366 -66.224738 44.435205 -66.195170 44.459479 -66.160343 44.494502 -66.139572 44.507901 -66.110377 44.555236 -66.056089 44.588802 -65.960484 44.645739 -65.873996 44.658640 -65.835548 44.656469 -65.814442 44.647115 -65.799510 44.626913 -65.790379 44.598996 -65.785316 44.580661 -65.750428 44.580974 -65.725576 44.589032 -65.696489 44.611131 -65.667343 44.619841 -65.660230 44.645719 -65.631463 44.672429 -65.599735 44.693781 -65.560907 44.723623 -65.495102 44.736725 -65.478096 44.761693 -65.472046 44.760235 -65.492722 44.745889 -65.517934 44.711085 -65.611360 44.677113 -65.681793 44.657425 -65.759350 44.660612 -65.777422 44.670313 -65.787156 44.680738 -65.786606 44.698524 -65.767202 44.722037 -65.729888 44.752632 -65.666213 44.769814 -65.644507 44.802341 -65.562292 44.843236 -65.465331 44.883541 -65.398553 44.909613 -65.331751 44.947100 -65.261247 45.008954 -65.157013 45.030015 -65.130345 45.048458 -65.087482 45.071422 -65.042046 45.112713 -64.953755 45.121512 -64.921104 45.126170 -64.893229 45.146027 -64.824099 45.171731 -64.718749 45.239323 -64.477978 45.257132 -64.452542 45.270726 -64.449937 45.279982 -64.457281 45.292736 -64.482968 45.303562 -64.514880 45.313731 -64.531883 45.327600 -64.524013 45.318581 -64.473245 45.294033 -64.393444 45.280690 -64.378226 45.256642 -64.369180 45.227983 -64.388086 45.210800 -64.402935 45.186167 -64.417019 45.174458 -64.413608 45.150728 -64.399410 45.137760 -64.404249 45.119935 -64.429529 45.108845 -64.428340 45.098978 -64.418806 45.089939 -64.393622 45.093910 -64.376225 45.111735 -64.363459 45.114823 -64.349086 45.106639 -64.320869 45.077810 -64.276696 45.039404 -64.230459 45.019263 -64.216707 44.985713 -64.205797 44.977978 -64.197566 44.968798 -64.159903 44.965269 -64.129183 44.971002 -64.105692 44.982334 -64.101551 44.989130 -64.112855 44.992074 -64.128833 44.993118 -64.150992 45.005533 -64.169135 45.030106 -64.154972 45.050139 -64.168648 45.080917 -64.219212 45.108179 -64.239022 45.126060 -64.238830 45.161345 -64.218485 45.186486 -64.193873 45.197460 -64.169809 45.223688 -64.068251 45.249577 -63.941239 45.272003 -63.864504 45.290987 -63.812667 45.298230 -63.800698 45.299031 -63.784901 45.296733 -63.771001 45.301380 -63.737671 45.308730 -63.707828 45.304145 -63.679865 45.295369 -63.644258 45.304310 -63.564939 45.300702 -63.546609 45.276650 -63.520159 45.281692 -63.506943 45.299197 -63.499064 45.313748 -63.505672 45.327347 -63.484799 45.339635 -63.477452 45.353265 -63.487189 45.357140 -63.518174 45.356089 -63.557165 45.376640 -63.626664 45.371111 -63.681122 45.373299 -63.743678 45.380392 -63.780323 45.380665 -63.805732 45.351065 -63.907407 45.346668 -63.935410 45.351490 -63.958078 45.361918 -63.987785 45.368884 -64.011698 45.371796 -64.040623 45.370502 -64.066854 45.372147 -64.091320 45.386260 -64.121424 45.387642 -64.151192 45.380392 -64.175720 45.378980 -64.202010 45.387057 -64.217730 45.388081 -64.240086 45.383002 -64.265957 45.372868 -64.287043 45.366498 -64.308597 45.361821 -64.392604 45.350960 -64.467490 45.353499 -64.488964 45.379517 -64.555346 45.388171 -64.586076 45.393441 -64.636382 45.386033 -64.673709 45.370268 -64.712989 45.353347 -64.735284 45.310426 -64.767074 45.298029 -64.799424 45.298909 -64.821751 45.314323 -64.838375 45.336722 -64.873930 45.339164 -64.895419 45.332610 -64.916758 45.321979 -64.968329 45.324093 -64.982296 45.335490 -64.991147 45.395153 -64.955330 45.448146 -64.882425 45.465426 -64.867682 45.489303 -64.805866 45.508805 -64.766810 45.580190 -64.644801 45.640341 -64.546622 45.676979 -64.492363 45.700408 -64.473828 45.709718 -64.468392 45.737760 -64.447136 45.749407 -64.424980 45.762412 -64.420080 45.780650 -64.414732 45.789145 -64.368721 45.777664 -64.359940 45.750255 -64.383522 45.740671 -64.381335 45.738461 -64.367270 45.746672 -64.326628 45.761388 -64.315425 45.776089 -64.335241 45.788651 -64.322774 45.808102 -64.308902 45.808120 -64.308927 45.823976 -64.294811 45.940739 -64.194680 45.953182 -64.192553 45.968192 -64.088437 45.968076 -64.031412 45.972937 -63.999252 45.981579 -63.994538 45.982824 -63.993981 @@ -326,15 +326,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 45.50482 -61.22751 - 45.53473 -61.18069 + 45.504823 -61.227514 + 45.534739 -61.180696 - 45.51045 -61.22751 45.51931 -61.22687 45.52995 -61.21455 45.53473 -61.20094 45.52992 -61.18069 45.51634 -61.18962 45.50482 -61.21028 45.51045 -61.22751 + 45.510451 -61.227514 45.519318 -61.226878 45.529958 -61.214551 45.534739 -61.200944 45.529920 -61.180696 45.516349 -61.189628 45.504823 -61.210287 45.510451 -61.227514 @@ -348,15 +348,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 45.78689 -62.62684 - 45.81546 -62.55613 + 45.786892 -62.626846 + 45.815465 -62.556139 - 45.79069 -62.62192 45.79950 -62.62684 45.80862 -62.62107 45.81546 -62.59606 45.80869 -62.55613 45.79817 -62.55752 45.78689 -62.60347 45.79069 -62.62192 + 45.790699 -62.621922 45.799503 -62.626846 45.808625 -62.621075 45.815465 -62.596064 45.808696 -62.556139 45.798173 -62.557522 45.786892 -62.603470 45.790699 -62.621922 @@ -370,15 +370,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 45.73923 -62.77618 - 45.76402 -62.72846 + 45.739239 -62.776183 + 45.764021 -62.728467 - 45.74288 -62.76845 45.75973 -62.77618 45.76402 -62.76050 45.76045 -62.73682 45.74881 -62.72846 45.73923 -62.74484 45.74288 -62.76845 + 45.742885 -62.768457 45.759737 -62.776183 45.764021 -62.760507 45.760451 -62.736823 45.748816 -62.728467 45.739239 -62.744842 45.742885 -62.768457 @@ -392,15 +392,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 43.91841 -60.11754 - 44.01041 -59.71284 + 43.918413 -60.117541 + 44.010417 -59.712843 - 43.92307 -60.11754 43.93352 -60.11062 43.94339 -60.07098 43.95258 -59.91475 43.95880 -59.86978 43.96940 -59.82193 44.00294 -59.74551 44.01041 -59.72512 44.00599 -59.71284 43.99417 -59.71575 43.98158 -59.73206 43.96591 -59.77585 43.93528 -59.85529 43.92985 -59.88686 43.92813 -59.93384 43.92190 -59.98373 43.91841 -60.05722 43.91957 -60.09712 43.92307 -60.11754 + 43.923078 -60.117541 43.933522 -60.110628 43.943396 -60.070988 43.952586 -59.914751 43.958808 -59.869787 43.969408 -59.821934 44.002943 -59.745514 44.010417 -59.725120 44.005999 -59.712843 43.994175 -59.715759 43.981586 -59.732063 43.965917 -59.775859 43.935280 -59.855295 43.929858 -59.886866 43.928136 -59.933842 43.921907 -59.983735 43.918413 -60.057221 43.919575 -60.097126 43.923078 -60.117541 @@ -414,15 +414,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 44.25244 -66.35756 - 44.36908 -66.25144 + 44.252448 -66.357560 + 44.369088 -66.251440 - 44.25426 -66.34999 44.26331 -66.35756 44.36053 -66.28547 44.36908 -66.27114 44.36868 -66.25668 44.35494 -66.25144 44.34005 -66.26156 44.27920 -66.29795 44.26288 -66.31608 44.25244 -66.33624 44.25426 -66.34999 + 44.254260 -66.349998 44.263314 -66.357560 44.360536 -66.285475 44.369088 -66.271148 44.368689 -66.256681 44.354945 -66.251440 44.340056 -66.261563 44.279201 -66.297959 44.262882 -66.316083 44.252448 -66.336248 44.254260 -66.349998 @@ -436,15 +436,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 44.21850 -66.43267 - 44.25705 -66.37969 + 44.218506 -66.432672 + 44.257055 -66.379694 - 44.22686 -66.43267 44.23618 -66.42797 44.25705 -66.40008 44.25302 -66.38496 44.23929 -66.37969 44.22341 -66.39285 44.21850 -66.40752 44.22686 -66.43267 + 44.226863 -66.432672 44.236182 -66.427973 44.257055 -66.400086 44.253021 -66.384960 44.239292 -66.379694 44.223413 -66.392850 44.218506 -66.407527 44.226863 -66.432672 @@ -458,15 +458,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 43.41231 -65.68783 - 43.47638 -65.61648 + 43.412311 -65.687835 + 43.476384 -65.616482 - 43.41231 -65.65685 43.43182 -65.68286 43.44554 -65.68783 43.47369 -65.65616 43.47638 -65.64022 43.46618 -65.61648 43.44388 -65.61842 43.42851 -65.62655 43.41583 -65.63808 43.41231 -65.65685 + 43.412311 -65.656854 43.431829 -65.682866 43.445545 -65.687835 43.473694 -65.656161 43.476384 -65.640224 43.466182 -65.616482 43.443882 -65.618422 43.428510 -65.626553 43.415833 -65.638089 43.412311 -65.656854 diff --git a/msautotest/wxs/expected/wfs_optional_items_get_feature_alias.xml b/msautotest/wxs/expected/wfs_optional_items_get_feature_alias.xml index 1701d80bdd..c88b190c4b 100644 --- a/msautotest/wxs/expected/wfs_optional_items_get_feature_alias.xml +++ b/msautotest/wxs/expected/wfs_optional_items_get_feature_alias.xml @@ -10,8 +10,8 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 timeStamp="" numberMatched="21" numberReturned="21"> - 43.41231 -66.43267 - 47.79644 -59.70969 + 43.412311 -66.432672 + 47.796447 -59.709694 diff --git a/msautotest/wxs/expected/wfs_optional_items_get_feature_all.xml b/msautotest/wxs/expected/wfs_optional_items_get_feature_all.xml index 769a195875..1edf103a58 100644 --- a/msautotest/wxs/expected/wfs_optional_items_get_feature_all.xml +++ b/msautotest/wxs/expected/wfs_optional_items_get_feature_all.xml @@ -10,23 +10,23 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 timeStamp="" numberMatched="21" numberReturned="21"> - 43.41231 -66.43267 - 47.79644 -59.70969 + 43.412311 -66.432672 + 47.796447 -59.709694 - 47.76789 -61.51051 - 47.79644 -61.45764 + 47.767892 -61.510511 + 47.796447 -61.457648 - 47.77424 -61.51051 47.78860 -61.50894 47.79644 -61.49272 47.78743 -61.45764 47.76789 -61.45998 47.76961 -61.48350 47.77424 -61.51051 + 47.774240 -61.510511 47.788606 -61.508947 47.796447 -61.492725 47.787438 -61.457648 47.767892 -61.459987 47.769615 -61.483502 47.774240 -61.510511 @@ -49,15 +49,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 47.16638 -60.21172 - 47.19271 -60.16877 + 47.166385 -60.211728 + 47.192716 -60.168776 - 47.16638 -60.20485 47.17985 -60.21172 47.19271 -60.19435 47.18763 -60.17344 47.17496 -60.16877 47.16638 -60.20485 + 47.166385 -60.204850 47.179857 -60.211728 47.192716 -60.194354 47.187638 -60.173448 47.174965 -60.168776 47.166385 -60.204850 @@ -80,15 +80,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 47.19106 -62.07696 - 47.62759 -61.43322 + 47.191069 -62.076968 + 47.627593 -61.433227 - 47.24108 -62.01051 47.24604 -61.96674 47.23831 -61.94754 47.22825 -61.93270 47.22220 -61.90699 47.23311 -61.86469 47.24267 -61.84221 47.23857 -61.82873 47.22731 -61.82804 47.21582 -61.83841 47.19106 -61.89528 47.19587 -61.91086 47.20730 -61.93027 47.21146 -61.94369 47.20068 -61.98054 47.20210 -62.00918 47.21127 -62.05713 47.21986 -62.07304 47.23019 -62.07696 47.30062 -62.02523 47.32797 -62.01258 47.35422 -62.01412 47.38157 -62.00145 47.40632 -61.97428 47.46073 -61.87584 47.55646 -61.74402 47.59681 -61.65975 47.61945 -61.58987 47.62006 -61.53210 47.62627 -61.49244 47.62759 -61.46701 47.62579 -61.44364 47.61706 -61.43322 47.60265 -61.44020 47.58445 -61.48263 47.57198 -61.50196 47.54670 -61.52732 47.53100 -61.55423 47.52441 -61.58041 47.53668 -61.60212 47.54664 -61.59275 47.56410 -61.55367 47.58387 -61.54035 47.59656 -61.57531 47.58175 -61.62893 47.56042 -61.67323 47.53788 -61.70753 47.50243 -61.77198 47.46323 -61.81183 47.43985 -61.84363 47.42876 -61.86734 47.41317 -61.88844 47.37958 -61.91082 47.35461 -61.91930 47.34335 -61.91859 47.32832 -61.94748 47.31536 -61.98306 47.25730 -62.02144 47.24108 -62.01051 + 47.241088 -62.010515 47.246040 -61.966742 47.238311 -61.947548 47.228257 -61.932708 47.222202 -61.906997 47.233116 -61.864694 47.242674 -61.842210 47.238572 -61.828736 47.227311 -61.828048 47.215824 -61.838414 47.191069 -61.895286 47.195878 -61.910866 47.207300 -61.930279 47.211466 -61.943690 47.200682 -61.980541 47.202105 -62.009180 47.211273 -62.057130 47.219864 -62.073040 47.230193 -62.076968 47.300625 -62.025236 47.327971 -62.012584 47.354223 -62.014128 47.381572 -62.001451 47.406325 -61.974280 47.460730 -61.875844 47.556462 -61.744027 47.596818 -61.659750 47.619458 -61.589874 47.620068 -61.532104 47.626271 -61.492444 47.627593 -61.467016 47.625790 -61.443646 47.617067 -61.433227 47.602653 -61.440203 47.584451 -61.482632 47.571983 -61.501965 47.546702 -61.527322 47.531009 -61.554237 47.524411 -61.580413 47.536685 -61.602124 47.546644 -61.592755 47.564103 -61.553676 47.583872 -61.540355 47.596569 -61.575318 47.581754 -61.628933 47.560421 -61.673230 47.537886 -61.707530 47.502438 -61.771983 47.463236 -61.811839 47.439850 -61.843632 47.428764 -61.867341 47.413176 -61.888445 47.379589 -61.910824 47.354617 -61.919309 47.343351 -61.918598 47.328320 -61.947480 47.315363 -61.983069 47.257309 -62.021449 47.241088 -62.010515 @@ -111,15 +111,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 47.37578 -61.85020 - 47.53541 -61.62463 + 47.375784 -61.850201 + 47.535418 -61.624632 - 47.39077 -61.85020 47.40527 -61.83772 47.41716 -61.81637 47.42945 -61.80270 47.44433 -61.77925 47.46587 -61.75944 47.48454 -61.73062 47.49872 -61.70481 47.52737 -61.66642 47.53541 -61.64470 47.53286 -61.62463 47.52225 -61.63180 47.51114 -61.65567 47.45830 -61.72907 47.43823 -61.75344 47.41589 -61.77649 47.37997 -61.80321 47.37578 -61.81946 47.39077 -61.85020 + 47.390774 -61.850201 47.405273 -61.837726 47.417160 -61.816375 47.429451 -61.802704 47.444334 -61.779258 47.465873 -61.759440 47.484545 -61.730626 47.498723 -61.704819 47.527379 -61.666427 47.535418 -61.644700 47.532866 -61.624632 47.522259 -61.631801 47.511145 -61.655676 47.458309 -61.729072 47.438230 -61.753441 47.415897 -61.776498 47.379975 -61.803218 47.375784 -61.819462 47.390774 -61.850201 @@ -142,15 +142,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 45.55044 -61.59511 - 47.03152 -60.34353 + 45.550449 -61.595111 + 47.031525 -60.343533 - 45.64995 -60.88100 45.62964 -60.89735 45.63055 -60.92814 45.61131 -61.00908 45.61072 -61.04080 45.60069 -61.06061 45.58886 -61.09728 45.58218 -61.13299 45.56434 -61.16831 45.55872 -61.19037 45.56065 -61.20734 45.58078 -61.20714 45.59226 -61.22567 45.59854 -61.24502 45.59370 -61.26380 45.57932 -61.27601 45.57074 -61.29466 45.55044 -61.30547 45.55804 -61.33436 45.57893 -61.36499 45.60096 -61.37658 45.62222 -61.39131 45.64498 -61.43901 45.68124 -61.47794 45.72090 -61.50435 45.74448 -61.51506 45.79398 -61.53240 45.83324 -61.54064 45.86342 -61.55506 45.90791 -61.56254 45.94146 -61.56423 46.02269 -61.59511 46.03665 -61.57548 46.04540 -61.55132 46.05222 -61.51518 46.05285 -61.48843 46.05503 -61.45536 46.06486 -61.45148 46.07567 -61.46816 46.09111 -61.51066 46.10430 -61.51772 46.14672 -61.48975 46.17439 -61.45567 46.19619 -61.41489 46.21434 -61.36836 46.23455 -61.33384 46.29334 -61.27078 46.39497 -61.18675 46.42631 -61.15240 46.44736 -61.14355 46.51078 -61.10612 46.57439 -61.06319 46.58996 -61.06597 46.61490 -61.09195 46.62260 -61.08137 46.62750 -61.06206 46.62258 -61.04122 46.62967 -61.02303 46.64697 -61.01398 46.65751 -61.01219 46.73777 -60.95217 46.78405 -60.91250 46.79934 -60.89124 46.81256 -60.85802 46.83880 -60.80765 46.88381 -60.75247 46.93979 -60.70840 46.97604 -60.68331 47.00688 -60.67548 47.01668 -60.66590 47.02681 -60.63446 47.02576 -60.60818 47.01756 -60.54331 46.99698 -60.51433 46.99416 -60.50008 47.00184 -60.48380 47.02743 -60.47143 47.03152 -60.44411 47.02334 -60.43075 47.01370 -60.42398 47.00027 -60.42800 46.97970 -60.45590 46.96315 -60.46750 46.94223 -60.46591 46.92785 -60.47316 46.91766 -60.51544 46.90031 -60.52481 46.89381 -60.51047 46.89407 -60.48325 46.88541 -60.45685 46.85658 -60.43096 46.85306 -60.40903 46.85722 -60.37096 46.84174 -60.35207 46.81863 -60.34397 46.79994 -60.34353 46.78409 -60.35725 46.73103 -60.35388 46.68503 -60.38863 46.67134 -60.41431 46.65255 -60.41936 46.65209 -60.40091 46.64560 -60.38121 46.63657 -60.38199 46.62739 -60.39920 46.61609 -60.40979 46.60516 -60.38238 46.58877 -60.37766 46.55717 -60.39962 46.53890 -60.42845 46.51251 -60.44942 46.49831 -60.45121 46.40272 -60.51463 46.38309 -60.53354 46.36266 -60.56105 46.35206 -60.56824 46.33566 -60.56890 46.31001 -60.58650 46.29958 -60.58831 46.27931 -60.59961 46.26988 -60.63265 46.26067 -60.64966 46.24740 -60.64284 46.22487 -60.65291 46.21303 -60.64502 46.21024 -60.63101 46.21637 -60.61606 46.25403 -60.59029 46.30100 -60.53670 46.31771 -60.51452 46.33005 -60.47931 46.30400 -60.47324 46.29501 -60.47952 46.27538 -60.49840 46.26319 -60.51743 46.22776 -60.54436 46.19430 -60.59400 46.10330 -60.70392 46.09247 -60.73247 46.09174 -60.78077 46.07638 -60.81238 46.06139 -60.86219 46.05797 -60.89103 46.07230 -60.92366 46.06668 -60.94590 46.05320 -60.94974 46.03421 -60.97053 46.02431 -60.98510 45.99002 -61.02658 45.97226 -61.05689 45.95590 -61.09692 45.94928 -61.13287 45.94288 -61.15298 45.92864 -61.15989 45.92678 -61.14273 45.93026 -61.11400 45.94794 -61.04426 45.95424 -61.02420 45.95924 -60.99444 45.97081 -60.97345 45.98019 -60.95135 45.99803 -60.94988 46.01138 -60.95681 46.03075 -60.90934 46.03175 -60.89546 46.01957 -60.86935 46.02499 -60.85245 46.04649 -60.81672 46.04855 -60.77818 46.03810 -60.78011 46.00609 -60.82286 45.98055 -60.84022 45.94769 -60.84129 45.93452 -60.87388 45.91784 -60.93525 45.92248 -60.96634 45.91903 -60.99507 45.90151 -61.05953 45.88426 -61.10260 45.84710 -61.13519 45.84304 -61.11695 45.85166 -61.09280 45.86428 -61.05806 45.86543 -61.03352 45.88570 -61.02799 45.89205 -61.00259 45.87647 -60.96039 45.86758 -60.95579 45.85654 -60.98955 45.83520 -60.97494 45.82597 -60.99154 45.82762 -61.02462 45.81520 -61.05403 45.78755 -61.09867 45.76274 -61.15204 45.74052 -61.17983 45.73866 -61.16274 45.72476 -61.14835 45.71458 -61.17342 45.69499 -61.18652 45.68877 -61.16179 45.69638 -61.11746 45.70518 -61.08281 45.71903 -61.05772 45.73432 -61.03713 45.75141 -60.99942 45.75710 -60.97199 45.74426 -60.89393 45.73581 -60.86279 45.72194 -60.84844 45.70705 -60.84805 45.68510 -60.87066 45.66404 -60.88471 45.64995 -60.88100 + 45.649954 -60.881009 45.629648 -60.897351 45.630553 -60.928145 45.611319 -61.009089 45.610721 -61.040806 45.600690 -61.060614 45.588861 -61.097280 45.582181 -61.132995 45.564345 -61.168312 45.558723 -61.190377 45.560650 -61.207340 45.580780 -61.207140 45.592268 -61.225673 45.598546 -61.245028 45.593709 -61.263803 45.579321 -61.276019 45.570740 -61.294666 45.550449 -61.305470 45.558043 -61.334366 45.578931 -61.364992 45.600965 -61.376583 45.622223 -61.391312 45.644981 -61.439011 45.681246 -61.477948 45.720907 -61.504351 45.744486 -61.515065 45.793980 -61.532408 45.833242 -61.540641 45.863422 -61.555060 45.907911 -61.562546 45.941468 -61.564232 46.022697 -61.595111 46.036654 -61.575489 46.045406 -61.551320 46.052222 -61.515187 46.052853 -61.488434 46.055037 -61.455367 46.064862 -61.451486 46.075678 -61.468167 46.091116 -61.510668 46.104307 -61.517727 46.146728 -61.489759 46.174397 -61.455676 46.196198 -61.414895 46.214349 -61.368367 46.234559 -61.333845 46.293343 -61.270789 46.394972 -61.186759 46.426311 -61.152403 46.447362 -61.143556 46.510783 -61.106129 46.574395 -61.063193 46.589967 -61.065977 46.614909 -61.091959 46.622603 -61.081372 46.627500 -61.062069 46.622583 -61.041222 46.629678 -61.023032 46.646978 -61.013984 46.657512 -61.012199 46.737777 -60.952173 46.784059 -60.912506 46.799340 -60.891249 46.812564 -60.858021 46.838805 -60.807653 46.883813 -60.752476 46.939790 -60.708400 46.976042 -60.683312 47.006882 -60.675484 47.016681 -60.665906 47.026816 -60.634462 47.025765 -60.608189 47.017567 -60.543319 46.996989 -60.514337 46.994169 -60.500086 47.001841 -60.483802 47.027437 -60.471435 47.031525 -60.444116 47.023340 -60.430751 47.013703 -60.423989 47.000272 -60.428005 46.979701 -60.455909 46.963151 -60.467506 46.942231 -60.465911 46.927854 -60.473165 46.917662 -60.515443 46.900315 -60.524813 46.893814 -60.510474 46.894074 -60.483257 46.885413 -60.456857 46.856580 -60.430963 46.853060 -60.409033 46.857226 -60.370964 46.841740 -60.352079 46.818636 -60.343976 46.799943 -60.343533 46.784093 -60.357258 46.731037 -60.353887 46.685033 -60.388635 46.671343 -60.414318 46.652557 -60.419369 46.652092 -60.400910 46.645606 -60.381215 46.636579 -60.381992 46.627395 -60.399203 46.616098 -60.409798 46.605166 -60.382381 46.588778 -60.377669 46.557171 -60.399625 46.538904 -60.428453 46.512512 -60.449424 46.498315 -60.451219 46.402727 -60.514638 46.383090 -60.533548 46.362662 -60.561054 46.352066 -60.568243 46.335667 -60.568906 46.310018 -60.586506 46.299584 -60.588312 46.279313 -60.599619 46.269887 -60.632652 46.260672 -60.649667 46.247406 -60.642843 46.224879 -60.652912 46.213036 -60.645026 46.210245 -60.631019 46.216372 -60.616069 46.254031 -60.590291 46.301008 -60.536708 46.317713 -60.514524 46.330057 -60.479319 46.304009 -60.473241 46.295010 -60.479521 46.275389 -60.498401 46.263191 -60.517436 46.227762 -60.544368 46.194306 -60.594006 46.103301 -60.703922 46.092472 -60.732477 46.091743 -60.780770 46.076384 -60.812387 46.061390 -60.862199 46.057978 -60.891033 46.072301 -60.923663 46.066682 -60.945906 46.053207 -60.949743 46.034214 -60.970530 46.024319 -60.985101 45.990020 -61.026588 45.972260 -61.056897 45.955900 -61.096924 45.949285 -61.132870 45.942888 -61.152982 45.928641 -61.159899 45.926780 -61.142735 45.930269 -61.114003 45.947948 -61.044268 45.954245 -61.024203 45.959242 -60.994440 45.970819 -60.973451 45.980190 -60.951350 45.998033 -60.949889 46.011382 -60.956812 46.030755 -60.909348 46.031753 -60.895468 46.019571 -60.869352 46.024994 -60.852458 46.046490 -60.816726 46.048559 -60.778188 46.038101 -60.780111 46.006097 -60.822860 45.980558 -60.840227 45.947690 -60.841299 45.934522 -60.873885 45.917843 -60.935257 45.922481 -60.966344 45.919038 -60.995079 45.901511 -61.059535 45.884264 -61.102601 45.847108 -61.135193 45.843043 -61.116957 45.851666 -61.092804 45.864284 -61.058067 45.865436 -61.033524 45.885703 -61.027991 45.892059 -61.002590 45.876475 -60.960393 45.867581 -60.955792 45.856547 -60.989557 45.835202 -60.974943 45.825971 -60.991547 45.827623 -61.024623 45.815209 -61.054032 45.787550 -61.098679 45.762742 -61.152042 45.740520 -61.179832 45.738664 -61.162740 45.724764 -61.148356 45.714587 -61.173426 45.694994 -61.186525 45.688774 -61.161798 45.696384 -61.117462 45.705184 -61.082816 45.719034 -61.057724 45.734323 -61.037132 45.751419 -60.999423 45.757106 -60.971998 45.744260 -60.893939 45.735813 -60.862792 45.721943 -60.848441 45.707052 -60.848053 45.685106 -60.870666 45.664049 -60.884717 45.649954 -60.881009 @@ -173,15 +173,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 47.25507 -61.75096 - 47.28211 -61.71983 + 47.255073 -61.750964 + 47.282116 -61.719830 - 47.25839 -61.74889 47.27555 -61.75096 47.28211 -61.73032 47.26959 -61.71983 47.25507 -61.73219 47.25839 -61.74889 + 47.258394 -61.748897 47.275550 -61.750964 47.282116 -61.730322 47.269593 -61.719830 47.255073 -61.732191 47.258394 -61.748897 @@ -204,15 +204,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 45.56706 -60.89735 - 46.26194 -59.82000 + 45.567064 -60.897351 + 46.261946 -59.820005 - 45.64995 -60.88100 45.65334 -60.85788 45.66020 -60.84534 45.67380 -60.83094 45.68701 -60.79847 45.69923 -60.77975 45.70884 -60.78105 45.73321 -60.79358 45.76006 -60.79121 45.77727 -60.78225 45.82475 -60.69757 45.84729 -60.68225 45.85917 -60.63459 45.90925 -60.56356 45.93950 -60.52700 45.95351 -60.48027 45.96348 -60.46029 45.97695 -60.45093 45.99023 -60.46314 45.94376 -60.60076 45.92884 -60.60565 45.89439 -60.72412 45.89550 -60.74447 45.90717 -60.76295 45.91857 -60.79750 45.92054 -60.81475 45.92940 -60.81922 45.95427 -60.79976 46.02271 -60.66074 46.09125 -60.55036 46.10734 -60.51539 46.12786 -60.48807 46.14975 -60.46504 46.17784 -60.41634 46.19925 -60.37498 46.21365 -60.35160 46.23167 -60.33912 46.24375 -60.32012 46.26194 -60.29684 46.24950 -60.27082 46.23171 -60.25635 46.21606 -60.25394 46.20099 -60.26973 46.17902 -60.30897 46.16101 -60.32145 46.15207 -60.31694 46.14923 -60.30298 46.16001 -60.27422 46.15336 -60.26011 46.13782 -60.25224 46.13124 -60.23286 46.13521 -60.21687 46.14125 -60.20728 46.15314 -60.20964 46.16640 -60.22711 46.17748 -60.23273 46.20890 -60.22695 46.21941 -60.21959 46.23295 -60.20482 46.24441 -60.17819 46.24760 -60.14918 46.24490 -60.11902 46.23770 -60.08663 46.23102 -60.07793 46.21369 -60.10342 46.20027 -60.09673 46.19739 -60.08276 46.20503 -60.05600 46.20450 -60.03234 46.18480 -59.96880 46.18603 -59.88506 46.18247 -59.85804 46.16907 -59.84614 46.16019 -59.84706 46.15476 -59.88034 46.14507 -59.88451 46.13232 -59.88538 46.11727 -59.91733 46.10226 -59.93860 46.09331 -59.93418 46.08968 -59.91805 46.09727 -59.89672 46.10553 -59.88287 46.11912 -59.85728 46.10500 -59.84858 46.09673 -59.85705 46.06371 -59.89640 46.04947 -59.91967 46.03189 -59.97722 46.01846 -59.98673 46.00824 -59.95654 46.00692 -59.92020 45.99378 -59.88152 45.98035 -59.87493 45.95602 -59.83086 45.94492 -59.82000 45.92699 -59.83261 45.93342 -59.88397 45.92194 -59.93191 45.91221 -59.94668 45.90382 -59.96578 45.90805 -60.01066 45.88187 -60.02632 45.87281 -60.04850 45.87040 -60.06338 45.86898 -60.15724 45.86421 -60.18692 45.85525 -60.19320 45.84632 -60.18875 45.83313 -60.16617 45.81987 -60.15420 45.81394 -60.14241 45.81338 -60.12419 45.80450 -60.11452 45.79102 -60.12383 45.78045 -60.14708 45.76964 -60.19157 45.76788 -60.21385 45.78264 -60.23014 45.78029 -60.24492 45.73712 -60.24305 45.72809 -60.25453 45.71524 -60.27655 45.70017 -60.29750 45.69478 -60.31440 45.70188 -60.34644 45.69266 -60.36852 45.65803 -60.40809 45.64129 -60.44055 45.61741 -60.56182 45.60196 -60.66423 45.59346 -60.68833 45.57752 -60.70696 45.56976 -60.72790 45.56706 -60.75852 45.56972 -60.78298 45.59474 -60.79756 45.60111 -60.81685 45.60145 -60.84547 45.61197 -60.88300 45.62964 -60.89735 45.64995 -60.88100 + 45.649954 -60.881009 45.653348 -60.857881 45.660202 -60.845348 45.673801 -60.830945 45.687014 -60.798470 45.699239 -60.779757 45.708848 -60.781056 45.733215 -60.793583 45.760063 -60.791213 45.777275 -60.782252 45.824757 -60.697572 45.847293 -60.682257 45.859173 -60.634593 45.909256 -60.563568 45.939505 -60.527009 45.953515 -60.480278 45.963481 -60.460290 45.976959 -60.450935 45.990237 -60.463145 45.943763 -60.600767 45.928847 -60.605653 45.894394 -60.724121 45.895501 -60.744475 45.907176 -60.762954 45.918574 -60.797500 45.920545 -60.814756 45.929405 -60.819227 45.954272 -60.799765 46.022713 -60.660742 46.091252 -60.550360 46.107347 -60.515399 46.127860 -60.488072 46.149753 -60.465043 46.177842 -60.416341 46.199254 -60.374984 46.213654 -60.351604 46.231677 -60.339127 46.243759 -60.320120 46.261946 -60.296847 46.249504 -60.270825 46.231712 -60.256352 46.216066 -60.253943 46.200990 -60.269738 46.179029 -60.308979 46.161015 -60.321453 46.152077 -60.316949 46.149237 -60.302985 46.160010 -60.274222 46.153368 -60.260117 46.137822 -60.252248 46.131241 -60.232867 46.135212 -60.216871 46.141252 -60.207283 46.153147 -60.209646 46.166404 -60.227119 46.177483 -60.232739 46.208901 -60.226953 46.219419 -60.219598 46.232951 -60.204821 46.244419 -60.178196 46.247609 -60.149187 46.244900 -60.119022 46.237705 -60.086630 46.231023 -60.077933 46.213696 -60.103429 46.200270 -60.096734 46.197396 -60.082767 46.205031 -60.056007 46.204502 -60.032340 46.184803 -59.968802 46.186039 -59.885068 46.182471 -59.858046 46.169072 -59.846142 46.160191 -59.847065 46.154762 -59.880343 46.145079 -59.884513 46.132328 -59.885385 46.117277 -59.917339 46.102265 -59.938602 46.093312 -59.934184 46.089685 -59.918056 46.097270 -59.896725 46.105537 -59.882871 46.119122 -59.857286 46.105000 -59.848584 46.096735 -59.857056 46.063717 -59.896406 46.049471 -59.919675 46.031898 -59.977221 46.018465 -59.986731 46.008241 -59.956545 46.006928 -59.920202 45.993781 -59.881526 45.980353 -59.874931 45.956021 -59.830867 45.944922 -59.820005 45.926994 -59.832615 45.933429 -59.883977 45.921940 -59.931918 45.912216 -59.946681 45.903823 -59.965788 45.908050 -60.010660 45.881877 -60.026323 45.872811 -60.048501 45.870409 -60.063386 45.868986 -60.157242 45.864219 -60.186927 45.855255 -60.193201 45.846324 -60.188756 45.833138 -60.166170 45.819875 -60.154201 45.813947 -60.142413 45.813383 -60.124199 45.804507 -60.114525 45.791027 -60.123836 45.780453 -60.147087 45.769647 -60.191574 45.767880 -60.213850 45.782649 -60.230146 45.780293 -60.244922 45.737125 -60.243052 45.728097 -60.254532 45.715241 -60.276556 45.700171 -60.297503 45.694783 -60.314407 45.701880 -60.346441 45.692668 -60.368529 45.658030 -60.408093 45.641293 -60.440550 45.617419 -60.561824 45.601961 -60.664237 45.593461 -60.688338 45.577521 -60.706965 45.569765 -60.727909 45.567064 -60.758520 45.569728 -60.782985 45.594741 -60.797560 45.601111 -60.816855 45.601459 -60.845476 45.611974 -60.883004 45.629648 -60.897351 45.649954 -60.881009 @@ -235,15 +235,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 46.06863 -60.68255 - 46.31432 -60.31030 + 46.068634 -60.682556 + 46.314326 -60.310302 - 46.06863 -60.68255 46.08885 -60.67673 46.10483 -60.64716 46.12309 -60.62409 46.16235 -60.58655 46.18281 -60.55930 46.19817 -60.52745 46.24352 -60.48030 46.28600 -60.41893 46.30881 -60.38181 46.31432 -60.35396 46.30346 -60.32144 46.28490 -60.31030 46.27137 -60.31965 46.25853 -60.33662 46.22822 -60.38428 46.22655 -60.40142 46.21560 -60.44629 46.20563 -60.46640 46.18823 -60.48632 46.16847 -60.51602 46.15544 -60.54347 46.11291 -60.60454 46.08640 -60.63586 46.07193 -60.65908 46.06863 -60.68255 + 46.068634 -60.682556 46.088853 -60.676730 46.104831 -60.647161 46.123091 -60.624097 46.162354 -60.586559 46.182819 -60.559300 46.198173 -60.527452 46.243529 -60.480305 46.286000 -60.418937 46.308813 -60.381812 46.314326 -60.353962 46.303460 -60.321443 46.284901 -60.310302 46.271372 -60.319652 46.258539 -60.336627 46.228226 -60.384283 46.226558 -60.401420 46.215606 -60.446297 46.205633 -60.466402 46.188232 -60.486328 46.168474 -60.516022 46.155447 -60.543472 46.112917 -60.604540 46.086404 -60.635868 46.071938 -60.659084 46.068634 -60.682556 @@ -266,15 +266,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 45.99438 -59.79193 - 46.03927 -59.70969 + 45.994384 -59.791931 + 46.039276 -59.709694 - 46.01509 -59.79193 46.02419 -59.75353 46.03767 -59.73340 46.03927 -59.71086 46.02584 -59.70969 46.01534 -59.72240 46.00193 -59.73199 45.99438 -59.74793 46.00099 -59.77262 46.01509 -59.79193 + 46.015090 -59.791931 46.024191 -59.753530 46.037672 -59.733403 46.039276 -59.710864 46.025845 -59.709694 46.015344 -59.722409 46.001939 -59.731993 45.994384 -59.747931 46.000997 -59.772623 46.015090 -59.791931 @@ -297,15 +297,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 45.94981 -64.46414 - 47.04029 -62.02064 + 45.949816 -64.464145 + 47.040290 -62.020645 - 46.05449 -62.49785 46.03300 -62.51661 46.03496 -62.54687 46.03418 -62.56822 46.01993 -62.59284 46.00804 -62.58991 46.00032 -62.57651 46.00641 -62.53083 45.99318 -62.52344 45.97949 -62.53216 45.97084 -62.54547 45.96509 -62.60380 45.96535 -62.65834 45.96788 -62.69069 45.96525 -62.72362 45.94981 -62.81665 45.95738 -62.85356 45.96981 -62.90060 46.01432 -62.96416 46.02739 -62.97164 46.03527 -62.96152 46.04687 -62.95184 46.05736 -62.96876 46.05764 -62.99982 46.05421 -63.03072 46.05771 -63.05459 46.07126 -63.05139 46.08628 -62.99262 46.08952 -62.96708 46.10718 -62.93528 46.12845 -62.92728 46.15073 -62.92913 46.13597 -62.98272 46.13822 -63.00223 46.16316 -62.99459 46.17719 -62.99902 46.18459 -63.01799 46.17762 -63.04315 46.18334 -63.06840 46.18772 -63.10753 46.19211 -63.12829 46.20656 -63.14030 46.22212 -63.12550 46.27070 -63.05104 46.29941 -63.04367 46.30030 -63.05891 46.28759 -63.09549 46.27158 -63.12119 46.24536 -63.14260 46.23740 -63.15262 46.24111 -63.17131 46.25563 -63.18329 46.26368 -63.20442 46.26080 -63.21936 46.25223 -63.22722 46.24260 -63.22526 46.22598 -63.21199 46.21019 -63.21382 46.20361 -63.22828 46.20099 -63.27429 46.19150 -63.30365 46.18228 -63.30922 46.17531 -63.29791 46.17312 -63.27837 46.19427 -63.20265 46.18969 -63.18729 46.18006 -63.18534 46.15991 -63.20295 46.15113 -63.23438 46.13884 -63.26024 46.13390 -63.28661 46.14330 -63.33047 46.16053 -63.43205 46.17750 -63.50244 46.19774 -63.58400 46.19962 -63.64017 46.20814 -63.68197 46.23691 -63.73756 46.28649 -63.80939 46.33444 -63.86938 46.34244 -63.85935 46.34656 -63.83600 46.33888 -63.80931 46.32768 -63.77688 46.33286 -63.76332 46.34335 -63.76227 46.35211 -63.76748 46.36418 -63.79679 46.38352 -63.81385 46.39061 -63.83841 46.38063 -63.90436 46.37893 -63.92367 46.39813 -63.95921 46.40044 -63.98653 46.37680 -64.01103 46.37019 -64.03842 46.37503 -64.07468 46.38964 -64.12604 46.39031 -64.14121 46.39781 -64.15499 46.41500 -64.17090 46.43082 -64.16940 46.46046 -64.14670 46.49174 -64.14906 46.52248 -64.16217 46.53946 -64.13912 46.55044 -64.11418 46.55694 -64.10517 46.57056 -64.10227 46.59207 -64.12093 46.61190 -64.12745 46.61724 -64.14003 46.60962 -64.15763 46.58238 -64.16341 46.57779 -64.17913 46.61318 -64.31790 46.61451 -64.34851 46.60631 -64.40302 46.61293 -64.43312 46.62658 -64.45650 46.64493 -64.46414 46.67128 -64.46185 46.71435 -64.44175 46.75799 -64.39782 46.78555 -64.36052 46.83038 -64.30775 46.84767 -64.29231 46.88736 -64.26616 46.91546 -64.24409 46.94013 -64.20313 46.98252 -64.12227 47.00040 -64.09578 47.02237 -64.07732 47.03708 -64.05263 47.04029 -64.01891 47.02471 -64.01510 46.98389 -64.03687 46.95782 -64.04729 46.94355 -64.04793 46.91516 -64.03057 46.87944 -64.02561 46.86398 -64.03495 46.81703 -64.07364 46.78037 -64.11655 46.75734 -64.16966 46.73816 -64.17838 46.73523 -64.14872 46.72435 -64.14193 46.70418 -64.14089 46.68983 -64.12841 46.68738 -64.08788 46.69701 -64.09004 46.70486 -64.09841 46.71806 -64.08791 46.72050 -64.07069 46.70947 -64.05100 46.71032 -64.03470 46.70525 -64.01677 46.65562 -63.97555 46.64149 -63.95769 46.63139 -63.93486 46.62267 -63.92970 46.61035 -63.93707 46.59878 -63.97280 46.58828 -63.97380 46.58138 -63.96228 46.58758 -63.92702 46.58126 -63.91769 46.55423 -63.90507 46.54220 -63.90713 46.52649 -63.92176 46.50028 -63.98185 46.47410 -64.01052 46.45832 -64.01218 46.45479 -63.99334 46.46916 -63.97424 46.48546 -63.94885 46.49643 -63.92401 46.50171 -63.89213 46.49634 -63.87962 46.48355 -63.86637 46.45011 -63.87591 46.44437 -63.85582 46.44131 -63.82626 46.43386 -63.79409 46.43759 -63.76309 46.45300 -63.75375 46.47420 -63.76460 46.49446 -63.77866 46.51448 -63.76649 46.52736 -63.77966 46.53592 -63.77193 46.54827 -63.73305 46.55956 -63.71573 46.55623 -63.69154 46.54316 -63.63376 46.52821 -63.60085 46.51505 -63.56161 46.50260 -63.55604 46.49096 -63.56578 46.47088 -63.59637 46.45685 -63.59172 46.45387 -63.57518 46.46538 -63.55255 46.47224 -63.53262 46.46525 -63.52109 46.45420 -63.50160 46.48146 -63.47709 46.50251 -63.47478 46.48195 -63.39814 46.47459 -63.36069 46.45773 -63.35262 46.43510 -63.37434 46.42108 -63.36977 46.42447 -63.34417 46.43418 -63.30925 46.42720 -63.29787 46.40922 -63.29845 46.39833 -63.29204 46.39457 -63.27333 46.40117 -63.25882 46.41389 -63.24038 46.41901 -63.20842 46.39981 -63.13111 46.39494 -63.10258 46.38131 -63.08737 46.36004 -63.07687 46.35613 -63.06356 46.36376 -63.04057 46.39313 -63.03545 46.40611 -63.04837 46.41392 -63.01994 46.42362 -62.92441 46.41825 -62.88830 46.41012 -62.86716 46.42232 -62.84103 46.42356 -62.80877 46.42151 -62.78366 46.39836 -62.70087 46.39776 -62.65652 46.40681 -62.63237 46.41728 -62.63105 46.42434 -62.64231 46.42598 -62.70189 46.44281 -62.75185 46.45509 -62.74410 46.45609 -62.71713 46.45420 -62.64461 46.45599 -62.61447 46.45519 -62.55163 46.46069 -62.45581 46.45046 -62.40418 46.46057 -62.27614 46.46030 -62.18637 46.45583 -62.13635 46.44685 -62.08925 46.44837 -62.03535 46.43832 -62.02064 46.42853 -62.02436 46.42149 -62.03693 46.40243 -62.09951 46.39315 -62.11077 46.37680 -62.15835 46.35884 -62.18298 46.33741 -62.22590 46.33344 -62.25475 46.33598 -62.26889 46.35451 -62.29926 46.35397 -62.31547 46.34277 -62.33836 46.34223 -62.37825 46.33187 -62.39808 46.32133 -62.39952 46.30834 -62.38675 46.29917 -62.39252 46.29419 -62.40623 46.28577 -62.41419 46.27100 -62.40786 46.25712 -62.42197 46.25083 -62.45491 46.25577 -62.48323 46.24696 -62.50204 46.23821 -62.49703 46.23211 -62.47728 46.22151 -62.46040 46.21016 -62.46497 46.20525 -62.47859 46.20666 -62.50120 46.20137 -62.52566 46.21144 -62.55862 46.21186 -62.58979 46.19803 -62.59848 46.18918 -62.57524 46.17115 -62.55773 46.16533 -62.57453 46.17215 -62.61489 46.15876 -62.61284 46.14410 -62.58270 46.13099 -62.57532 46.11070 -62.55671 46.11585 -62.53769 46.13048 -62.52585 46.13383 -62.51322 46.12985 -62.50002 46.12040 -62.49295 46.10478 -62.48965 46.07229 -62.50233 46.05449 -62.49785 + 46.054498 -62.497853 46.033009 -62.516619 46.034969 -62.546876 46.034185 -62.568223 46.019937 -62.592840 46.008042 -62.589912 46.000325 -62.576516 46.006410 -62.530834 45.993184 -62.523441 45.979499 -62.532164 45.970843 -62.545473 45.965091 -62.603808 45.965352 -62.658349 45.967882 -62.690694 45.965250 -62.723626 45.949816 -62.816659 45.957382 -62.853567 45.969811 -62.900600 46.014321 -62.964168 46.027392 -62.971646 46.035279 -62.961529 46.046873 -62.951842 46.057369 -62.968766 46.057648 -62.999822 46.054216 -63.030723 46.057714 -63.054591 46.071269 -63.051393 46.086286 -62.992627 46.089526 -62.967081 46.107189 -62.935281 46.128452 -62.927287 46.150730 -62.929130 46.135973 -62.982728 46.138221 -63.002237 46.163160 -62.994596 46.177192 -62.999021 46.184592 -63.017998 46.177627 -63.043154 46.183344 -63.068409 46.187720 -63.107538 46.192119 -63.128290 46.206565 -63.140303 46.222121 -63.125505 46.270708 -63.051049 46.299412 -63.043678 46.300308 -63.058910 46.287596 -63.095490 46.271586 -63.121191 46.245364 -63.142606 46.237407 -63.152626 46.241110 -63.171313 46.255632 -63.183296 46.263682 -63.204428 46.260804 -63.219364 46.252232 -63.227222 46.242600 -63.225263 46.225987 -63.211993 46.210199 -63.213825 46.203611 -63.228284 46.200994 -63.274298 46.191505 -63.303653 46.182283 -63.309223 46.175313 -63.297912 46.173128 -63.278372 46.194270 -63.202654 46.189697 -63.187290 46.180067 -63.185341 46.159917 -63.202955 46.151138 -63.234386 46.138843 -63.260244 46.133907 -63.286612 46.143304 -63.330474 46.160531 -63.432051 46.177506 -63.502449 46.197742 -63.584001 46.199628 -63.640178 46.208142 -63.681971 46.236919 -63.737564 46.286497 -63.809399 46.334449 -63.869384 46.342445 -63.859358 46.346565 -63.836008 46.338888 -63.809314 46.327684 -63.776887 46.332864 -63.763324 46.343350 -63.762274 46.352112 -63.767488 46.364183 -63.796795 46.383525 -63.813856 46.390611 -63.838414 46.380632 -63.904361 46.378939 -63.923678 46.398136 -63.959215 46.400448 -63.986533 46.376808 -64.011034 46.370193 -64.038420 46.375031 -64.074682 46.389642 -64.126048 46.390315 -64.141215 46.397813 -64.154999 46.415006 -64.170902 46.430825 -64.169409 46.460465 -64.146706 46.491741 -64.149067 46.522481 -64.162178 46.539466 -64.139121 46.550449 -64.114182 46.556940 -64.105176 46.570560 -64.102270 46.592070 -64.120931 46.611908 -64.127459 46.617249 -64.140038 46.609627 -64.157637 46.582380 -64.163417 46.577798 -64.179131 46.613188 -64.317908 46.614512 -64.348516 46.606312 -64.403024 46.612939 -64.433122 46.626583 -64.456507 46.644936 -64.464145 46.671283 -64.461857 46.714357 -64.441755 46.757994 -64.397820 46.785550 -64.360527 46.830383 -64.307757 46.847672 -64.292318 46.887364 -64.266167 46.915461 -64.244092 46.940137 -64.203137 46.982520 -64.122270 47.000404 -64.095781 47.022379 -64.077323 47.037086 -64.052631 47.040290 -64.018913 47.024716 -64.015106 46.983890 -64.036878 46.957826 -64.047295 46.943557 -64.047934 46.915161 -64.030578 46.879442 -64.025612 46.863982 -64.034953 46.817032 -64.073642 46.780374 -64.116557 46.757340 -64.169663 46.738162 -64.178386 46.735239 -64.148720 46.724353 -64.141930 46.704180 -64.140894 46.689835 -64.128411 46.687388 -64.087880 46.697019 -64.090049 46.704860 -64.098410 46.718069 -64.087913 46.720505 -64.070690 46.709478 -64.051006 46.710329 -64.034703 46.705255 -64.016772 46.655620 -63.975558 46.641494 -63.957699 46.631394 -63.934867 46.622672 -63.929701 46.610356 -63.937076 46.598780 -63.972803 46.588280 -63.973809 46.581380 -63.962288 46.587583 -63.927028 46.581268 -63.917692 46.554234 -63.905079 46.542200 -63.907131 46.526499 -63.921762 46.500282 -63.981854 46.474104 -64.010522 46.458326 -64.012189 46.454791 -63.993340 46.469160 -63.974246 46.485464 -63.948859 46.496434 -63.924018 46.501716 -63.892139 46.496345 -63.879622 46.483556 -63.866370 46.450111 -63.875915 46.444379 -63.855825 46.441315 -63.826265 46.433860 -63.794095 46.437597 -63.763099 46.453001 -63.753753 46.474204 -63.764601 46.494465 -63.778660 46.514486 -63.766496 46.527369 -63.779668 46.535920 -63.771930 46.548278 -63.733054 46.559566 -63.715735 46.556233 -63.691543 46.543164 -63.633768 46.528218 -63.600859 46.515051 -63.561613 46.502601 -63.556045 46.490962 -63.565786 46.470880 -63.596370 46.456858 -63.591722 46.453879 -63.575188 46.465388 -63.552552 46.472247 -63.532627 46.465254 -63.521092 46.454201 -63.501600 46.481461 -63.477090 46.502518 -63.474781 46.481952 -63.398141 46.474591 -63.360699 46.457736 -63.352620 46.435109 -63.374347 46.421080 -63.369776 46.424473 -63.344178 46.434183 -63.309251 46.427205 -63.297872 46.409225 -63.298454 46.398337 -63.292042 46.394577 -63.273336 46.401178 -63.258821 46.413898 -63.240388 46.419019 -63.208424 46.399810 -63.131116 46.394945 -63.102581 46.381319 -63.087375 46.360047 -63.076879 46.356138 -63.063563 46.363768 -63.040575 46.393137 -63.035454 46.406117 -63.048375 46.413929 -63.019940 46.423626 -62.924414 46.418257 -62.888309 46.410129 -62.867161 46.422327 -62.841034 46.423561 -62.808771 46.421516 -62.783660 46.398364 -62.700871 46.397763 -62.656523 46.406815 -62.632373 46.417289 -62.631052 46.424349 -62.642319 46.425988 -62.701897 46.442812 -62.751851 46.455099 -62.744108 46.456091 -62.717133 46.454205 -62.644615 46.455991 -62.614477 46.455193 -62.551633 46.460698 -62.455812 46.450468 -62.404184 46.460575 -62.276147 46.460303 -62.186376 46.455833 -62.136351 46.446856 -62.089255 46.448370 -62.035351 46.438320 -62.020645 46.428533 -62.024368 46.421493 -62.036934 46.402437 -62.099510 46.393152 -62.110777 46.376801 -62.158351 46.358849 -62.182987 46.337410 -62.225901 46.333443 -62.254756 46.335985 -62.268898 46.354512 -62.299267 46.353970 -62.315470 46.342773 -62.338367 46.342230 -62.378254 46.331875 -62.398082 46.321331 -62.399522 46.308342 -62.386752 46.299171 -62.392525 46.294195 -62.406236 46.285771 -62.414197 46.271001 -62.407866 46.257120 -62.421972 46.250834 -62.454916 46.255776 -62.483236 46.246966 -62.502043 46.238215 -62.497031 46.232112 -62.477283 46.221517 -62.460409 46.210160 -62.464978 46.205252 -62.478590 46.206668 -62.501200 46.201371 -62.525663 46.211445 -62.558629 46.211864 -62.589790 46.198039 -62.598486 46.189188 -62.575245 46.171155 -62.557735 46.165337 -62.574532 46.172150 -62.614894 46.158763 -62.612840 46.144102 -62.582703 46.130992 -62.575321 46.110703 -62.556716 46.115852 -62.537690 46.130485 -62.525851 46.133837 -62.513225 46.129850 -62.500027 46.120403 -62.492953 46.104789 -62.489650 46.072291 -62.502332 46.054498 -62.497853 @@ -328,15 +328,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 45.45817 -61.14640 - 45.57614 -60.90345 + 45.458170 -61.146404 + 45.576146 -60.903456 - 45.46158 -61.06156 45.47786 -61.06640 45.48613 -61.05833 45.49544 -61.04181 45.50863 -61.04863 45.50985 -61.06355 45.50627 -61.09722 45.53218 -61.14272 45.54621 -61.14640 45.55457 -61.13827 45.56531 -61.08149 45.57245 -61.05842 45.57127 -61.04359 45.56733 -61.01483 45.57614 -60.97494 45.57301 -60.94298 45.57287 -60.90910 45.56179 -60.90345 45.55114 -60.91575 45.54872 -60.93052 45.54585 -60.96632 45.53933 -60.99681 45.52582 -61.00591 45.49392 -60.99834 45.48174 -61.01685 45.46219 -61.02995 45.45817 -61.04557 45.46158 -61.06156 + 45.461588 -61.061562 45.477860 -61.066405 45.486135 -61.058336 45.495441 -61.041811 45.508633 -61.048638 45.509854 -61.063551 45.506274 -61.097225 45.532182 -61.142729 45.546215 -61.146404 45.554578 -61.138277 45.565318 -61.081499 45.572456 -61.058421 45.571279 -61.043595 45.567330 -61.014833 45.576146 -60.974940 45.573014 -60.942987 45.572876 -60.909103 45.561792 -60.903456 45.551148 -60.915757 45.548728 -60.930529 45.545854 -60.966328 45.539334 -60.996814 45.525826 -61.005913 45.493926 -60.998348 45.481743 -61.016851 45.462193 -61.029951 45.458170 -61.045573 45.461588 -61.061562 @@ -359,15 +359,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 45.47629 -60.97763 - 45.49487 -60.93785 + 45.476290 -60.977631 + 45.494872 -60.937854 - 45.47795 -60.97763 45.49304 -60.96764 45.49487 -60.94549 45.48687 -60.93785 45.47629 -60.94481 45.47795 -60.97763 + 45.477957 -60.977631 45.493045 -60.967647 45.494872 -60.945495 45.486875 -60.937854 45.476290 -60.944814 45.477957 -60.977631 @@ -390,15 +390,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 46.57850 -63.86379 - 46.62738 -63.77514 + 46.578504 -63.863796 + 46.627388 -63.775140 - 46.58244 -63.83307 46.60437 -63.85922 46.62738 -63.86379 46.62386 -63.84500 46.61144 -63.82089 46.59398 -63.77888 46.57850 -63.77514 46.57914 -63.80885 46.58244 -63.83307 + 46.582447 -63.833071 46.604373 -63.859226 46.627388 -63.863796 46.623862 -63.845001 46.611443 -63.820895 46.593980 -63.778884 46.578504 -63.775140 46.579144 -63.808857 46.582447 -63.833071 @@ -421,15 +421,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 43.44796 -66.23693 - 45.98282 -61.00979 + 43.447966 -66.236930 + 45.982824 -61.009794 - 45.98282 -63.99398 45.98180 -63.97255 45.97346 -63.94384 45.96122 -63.92012 45.89396 -63.83083 45.87592 -63.78724 45.85825 -63.72037 45.86714 -63.68913 45.87983 -63.62732 45.87865 -63.60473 45.86944 -63.56118 45.87440 -63.53489 45.86911 -63.48631 45.85676 -63.46277 45.84583 -63.45646 45.83942 -63.46541 45.82111 -63.55652 45.81303 -63.57177 45.80427 -63.56666 45.79739 -63.53724 45.80505 -63.48357 45.80718 -63.45384 45.80726 -63.41761 45.79490 -63.39412 45.79125 -63.37560 45.80320 -63.32444 45.80122 -63.29972 45.79518 -63.28534 45.78557 -63.28339 45.76781 -63.31482 45.75120 -63.38696 45.73480 -63.38646 45.71098 -63.33643 45.70724 -63.31801 45.71953 -63.31055 45.73484 -63.30120 45.73864 -63.26542 45.75980 -63.23957 45.76272 -63.22491 45.75395 -63.21987 45.74017 -63.22822 45.73340 -63.21169 45.73696 -63.19928 45.75028 -63.18334 45.75857 -63.14461 45.75246 -63.11212 45.75685 -63.09659 45.76997 -63.10400 45.77932 -63.12936 45.79508 -63.12752 45.80190 -63.10777 45.80052 -63.08530 45.79439 -63.05278 45.76828 -62.96013 45.76403 -62.91604 45.74080 -62.80350 45.72278 -62.76806 45.71416 -62.73969 45.71111 -62.70013 45.70256 -62.68980 45.68358 -62.69912 45.67409 -62.73348 45.67216 -62.80449 45.66638 -62.82101 45.64975 -62.80806 45.64508 -62.79281 45.62305 -62.80388 45.61233 -62.79238 45.60877 -62.76877 45.62633 -62.75528 45.62695 -62.73935 45.62009 -62.72294 45.61306 -62.71186 45.60862 -62.69125 45.61510 -62.67690 45.63113 -62.68768 45.63911 -62.71375 45.65501 -62.70644 45.66105 -62.68463 45.66790 -62.61820 45.65580 -62.60246 45.64634 -62.59533 45.64183 -62.57488 45.64230 -62.54095 45.62372 -62.53960 45.61282 -62.53349 45.60958 -62.51740 45.62082 -62.49475 45.62361 -62.43336 45.63128 -62.40525 45.64479 -62.40189 45.64952 -62.41710 45.64455 -62.45393 45.64554 -62.46892 45.65597 -62.46758 45.66413 -62.44691 45.68520 -62.35055 45.73170 -62.22491 45.77555 -62.13189 45.82272 -62.04964 45.84833 -62.01489 45.87034 -61.97469 45.87852 -61.94846 45.87605 -61.92912 45.86975 -61.91480 45.85935 -61.91639 45.84183 -61.95372 45.82378 -61.96019 45.78981 -61.95068 45.72754 -61.93850 45.70509 -61.94256 45.66417 -61.96886 45.64454 -61.97615 45.62855 -61.96568 45.62048 -61.93441 45.62461 -61.91871 45.65036 -61.93087 45.66246 -61.92310 45.66695 -61.89676 45.66447 -61.87751 45.65001 -61.86072 45.63377 -61.85557 45.62184 -61.85813 45.61247 -61.84594 45.61607 -61.82280 45.62771 -61.80752 45.62237 -61.75625 45.61959 -61.69035 45.62383 -61.66941 45.63155 -61.65915 45.63520 -61.63065 45.64580 -61.62372 45.65622 -61.62219 45.66409 -61.60670 45.66982 -61.58463 45.66704 -61.54734 45.62157 -61.45173 45.59688 -61.42623 45.57107 -61.41438 45.54499 -61.38453 45.53329 -61.37668 45.52451 -61.36671 45.51628 -61.33574 45.51526 -61.31543 45.50673 -61.29507 45.49091 -61.26892 45.47754 -61.26730 45.45254 -61.29161 45.43340 -61.31717 45.42126 -61.36414 45.40808 -61.38575 45.40266 -61.39704 45.39935 -61.44336 45.38924 -61.46299 45.38519 -61.47865 45.42257 -61.53212 45.43817 -61.56352 45.44194 -61.59224 45.43708 -61.61102 45.42669 -61.60731 45.41152 -61.56004 45.40226 -61.54278 45.37506 -61.53193 45.35316 -61.51502 45.33889 -61.48798 45.33220 -61.45603 45.33724 -61.43203 45.34266 -61.38694 45.34036 -61.35731 45.32795 -61.31351 45.32548 -61.28925 45.33680 -61.24547 45.33030 -61.19778 45.33272 -61.15463 45.32148 -61.12044 45.31824 -61.05503 45.30632 -61.01880 45.29232 -61.00979 45.27226 -61.01018 45.26901 -61.02263 45.28059 -61.04093 45.27738 -61.05348 45.26171 -61.05603 45.22863 -61.07796 45.20038 -61.11994 45.19370 -61.15534 45.19922 -61.17761 45.20723 -61.18535 45.23814 -61.16242 45.25015 -61.15975 45.26999 -61.17007 45.27557 -61.18709 45.27234 -61.19963 45.25577 -61.21041 45.22609 -61.20923 45.21254 -61.21809 45.22612 -61.24285 45.23449 -61.26843 45.23097 -61.29671 45.23421 -61.31781 45.23075 -61.34079 45.21891 -61.37180 45.19814 -61.40345 45.18478 -61.40180 45.17868 -61.37743 45.18625 -61.33881 45.17993 -61.31968 45.16446 -61.31690 45.15727 -61.33973 45.15030 -61.41918 45.14317 -61.43671 45.13658 -61.46679 45.13264 -61.50538 45.13866 -61.53512 45.13956 -61.56037 45.13450 -61.58425 45.13205 -61.62186 45.15088 -61.70262 45.14510 -61.72431 45.13670 -61.73225 45.12570 -61.69808 45.11580 -61.67871 45.10045 -61.69891 45.07100 -61.68688 45.06624 -61.70024 45.07645 -61.73745 45.06467 -61.78607 45.07760 -61.83187 45.07349 -61.84740 45.05860 -61.84658 45.04993 -61.86490 45.03882 -61.86434 45.02755 -61.86894 45.02041 -61.88629 45.03106 -61.90258 45.03586 -61.91753 45.02059 -61.93235 45.02452 -61.95044 45.04280 -61.98501 45.03191 -62.00217 45.02398 -61.99432 45.01089 -61.98729 45.00533 -61.99847 45.00426 -62.03500 44.99325 -62.08044 44.98755 -62.09685 44.97707 -62.07528 44.98071 -62.05248 44.97903 -62.03564 44.97357 -62.01852 44.96464 -62.01905 44.95846 -62.05118 44.95278 -62.14179 44.94374 -62.17040 44.93181 -62.19586 44.92592 -62.21738 44.93400 -62.24296 44.93551 -62.26504 44.92271 -62.29342 44.90400 -62.32044 44.89914 -62.33368 44.89982 -62.35880 44.89049 -62.36970 44.87994 -62.37628 44.87330 -62.39573 44.87717 -62.41363 44.87363 -62.43121 44.84306 -62.47807 44.84315 -62.49591 44.86694 -62.49651 44.87307 -62.51048 44.86885 -62.52587 44.85236 -62.53094 44.83951 -62.53628 44.83358 -62.55782 44.83718 -62.58101 44.79058 -62.57657 44.77825 -62.58930 44.78212 -62.60728 44.80154 -62.62324 44.80885 -62.64665 44.79649 -62.65936 44.78922 -62.67650 44.77248 -62.68679 44.76757 -62.69994 44.77417 -62.72133 44.77653 -62.75789 44.76252 -62.79435 44.76189 -62.80998 44.78592 -62.84098 44.78736 -62.86295 44.78390 -62.87523 44.77277 -62.87433 44.76249 -62.85268 44.74720 -62.84423 44.73490 -62.85682 44.70440 -62.83989 44.69509 -62.85058 44.69381 -62.86400 44.70733 -62.89626 44.70967 -62.93288 44.70576 -62.97315 44.69538 -63.00975 44.70107 -63.03418 44.72280 -63.04635 44.74501 -63.04814 44.76020 -63.05671 44.76789 -63.06976 44.75438 -63.09067 44.74200 -63.08544 44.71742 -63.06978 44.69085 -63.06554 44.67282 -63.07141 44.67174 -63.09732 44.69478 -63.11371 44.70894 -63.13055 44.73935 -63.12994 44.75113 -63.13309 44.75853 -63.15144 44.75070 -63.16107 44.69850 -63.16711 44.67951 -63.17592 44.67590 -63.19331 44.68607 -63.19727 44.71371 -63.19345 44.73372 -63.19402 44.73894 -63.21119 44.73000 -63.22912 44.68672 -63.23479 44.66773 -63.24357 44.67362 -63.26274 44.69491 -63.26771 44.70488 -63.27691 44.67769 -63.30580 44.65505 -63.29650 44.64529 -63.29980 44.63657 -63.31257 44.61282 -63.32925 44.62313 -63.38102 44.61778 -63.41691 44.62356 -63.43614 44.65330 -63.45125 44.66368 -63.46788 44.66446 -63.48247 44.65943 -63.49551 44.63660 -63.49131 44.60981 -63.46191 44.58642 -63.48578 44.58571 -63.50117 44.59608 -63.51778 44.60091 -63.55762 44.63726 -63.58915 44.64478 -63.60231 44.66100 -63.62047 44.67410 -63.64042 44.69605 -63.67790 44.69535 -63.69343 44.66208 -63.69034 44.64654 -63.67417 44.63098 -63.62804 44.62190 -63.61577 44.60901 -63.62077 44.59063 -63.60144 44.57791 -63.58882 44.55573 -63.58677 44.53772 -63.59225 44.52289 -63.59087 44.50667 -63.57277 44.48720 -63.56159 44.44753 -63.58491 44.44685 -63.60036 44.45305 -63.60928 44.45752 -63.62410 44.45312 -63.63924 44.43808 -63.64304 44.43063 -63.65988 44.43141 -63.67450 44.44660 -63.68316 44.45525 -63.71817 44.45063 -63.75089 44.45968 -63.76314 44.46569 -63.77711 44.45925 -63.81589 44.46373 -63.83084 44.48277 -63.83475 44.48701 -63.85491 44.47472 -63.89200 44.48965 -63.94844 44.49845 -63.96593 44.51482 -63.97897 44.53751 -63.97093 44.55452 -63.95603 44.57298 -63.95792 44.60447 -63.96739 44.61977 -63.95849 44.65636 -63.92477 44.65079 -63.96063 44.63595 -63.98932 44.61740 -64.06023 44.60528 -64.07973 44.59393 -64.08374 44.55639 -64.07766 44.52940 -64.08323 44.49535 -64.05276 44.48495 -64.05370 44.47587 -64.08387 44.45855 -64.10377 44.45250 -64.11974 44.46687 -64.15651 44.47975 -64.16407 44.50869 -64.16507 44.52937 -64.18073 44.54703 -64.21071 44.54838 -64.23993 44.52537 -64.25293 44.52456 -64.28092 44.53034 -64.33762 44.51628 -64.35060 44.47480 -64.34913 44.46594 -64.36166 44.44194 -64.35267 44.43244 -64.36316 44.42730 -64.38837 44.41049 -64.39789 44.39537 -64.38899 44.38954 -64.37492 44.39947 -64.34182 44.39822 -64.32512 44.38986 -64.31496 44.37393 -64.32151 44.36032 -64.28689 44.34709 -64.28443 44.33977 -64.29597 44.34792 -64.33618 44.33970 -64.36316 44.32714 -64.37528 44.31180 -64.37141 44.31042 -64.34239 44.31135 -64.32705 44.30147 -64.31760 44.27481 -64.33023 44.27750 -64.29649 44.27067 -64.28539 44.25617 -64.27874 44.24271 -64.29373 44.23489 -64.31555 44.24020 -64.33989 44.27832 -64.37290 44.28212 -64.38578 44.27078 -64.40196 44.25515 -64.40342 44.24504 -64.42395 44.22510 -64.43513 44.21816 -64.46632 44.14342 -64.52789 44.13246 -64.57603 44.12788 -64.65272 44.11774 -64.66090 44.10615 -64.63274 44.10730 -64.60004 44.09170 -64.58890 44.05398 -64.61235 44.04812 -64.62297 44.04815 -64.64765 44.04354 -64.66245 44.03253 -64.67357 44.02177 -64.70410 43.99448 -64.71426 43.96938 -64.72575 43.95921 -64.74608 43.94882 -64.75917 43.93924 -64.79397 43.92845 -64.82441 43.92440 -64.85363 43.90969 -64.87641 43.89497 -64.87475 43.88673 -64.86443 43.87792 -64.82763 43.85895 -64.81097 43.84917 -64.81390 43.84361 -64.83173 43.83652 -64.85022 43.82392 -64.86207 43.81659 -64.87349 43.82730 -64.89214 43.85113 -64.90117 43.86454 -64.93553 43.86138 -64.94948 43.85127 -64.95738 43.83387 -64.92772 43.79498 -64.93427 43.78760 -64.94556 43.79119 -64.95829 43.81939 -64.96988 43.83978 -64.98572 43.83825 -64.99877 43.82653 -65.00764 43.79084 -64.98793 43.77187 -64.98349 43.75190 -64.99431 43.75299 -65.02305 43.77348 -65.03894 43.78782 -65.04582 43.79722 -65.06021 43.79628 -65.07541 43.77604 -65.07903 43.73541 -65.05460 43.70107 -65.07075 43.68747 -65.09757 43.70421 -65.11294 43.71394 -65.12234 43.71027 -65.13411 43.67766 -65.15658 43.65194 -65.16558 43.64907 -65.18653 43.67104 -65.18936 43.69071 -65.18373 43.70074 -65.18805 43.69658 -65.21709 43.74845 -65.25026 43.75416 -65.26436 43.75276 -65.28460 43.73704 -65.29788 43.72761 -65.29571 43.70626 -65.28264 43.67931 -65.28741 43.65872 -65.29591 43.65134 -65.30721 43.65904 -65.33466 43.66729 -65.34496 43.67731 -65.34930 43.70611 -65.35103 43.71722 -65.37196 43.71375 -65.39087 43.70510 -65.39789 43.63207 -65.38321 43.61044 -65.37522 43.58270 -65.38992 43.56809 -65.38805 43.55214 -65.39411 43.54687 -65.40663 43.54237 -65.42832 43.54345 -65.44484 43.55832 -65.45397 43.56344 -65.46571 43.55586 -65.48923 43.53640 -65.48256 43.52313 -65.46048 43.51129 -65.44970 43.48813 -65.44260 43.47824 -65.44532 43.47026 -65.45440 43.48962 -65.47324 43.50357 -65.48527 43.49428 -65.50239 43.47135 -65.50238 43.45536 -65.50829 43.44796 -65.51952 43.46698 -65.54344 43.48540 -65.59672 43.51281 -65.60651 43.51808 -65.62554 43.51054 -65.64895 43.50030 -65.65670 43.48384 -65.67981 43.47641 -65.71037 43.47714 -65.73178 43.47214 -65.75852 43.47535 -65.77624 43.48442 -65.78356 43.49636 -65.78224 43.50864 -65.77584 43.51526 -65.78697 43.52557 -65.81780 43.53829 -65.82577 43.56683 -65.82054 43.59725 -65.80960 43.64235 -65.80059 43.65785 -65.81197 43.65828 -65.82637 43.64802 -65.83410 43.62969 -65.83150 43.61620 -65.83372 43.58846 -65.84809 43.61167 -65.87487 43.62592 -65.88198 43.68868 -65.88582 43.73416 -65.87178 43.76061 -65.88487 43.76645 -65.90605 43.76378 -65.92202 43.77616 -65.93516 43.79772 -65.94334 43.80644 -65.95584 43.80627 -65.96811 43.79757 -65.97504 43.78239 -65.97080 43.77157 -65.97644 43.76341 -65.98544 43.76873 -66.00467 43.77947 -66.01852 43.76236 -66.03957 43.73707 -66.01133 43.72270 -66.00411 43.71021 -66.00332 43.69475 -66.01126 43.68995 -66.02592 43.68902 -66.04822 43.67663 -66.05463 43.67469 -66.07988 43.68321 -66.08523 43.70291 -66.07988 43.70949 -66.09110 43.70503 -66.12007 43.71254 -66.12839 43.72660 -66.12843 43.74028 -66.13345 43.74065 -66.14789 43.74525 -66.16489 43.77534 -66.17866 43.78310 -66.19411 43.80715 -66.19872 43.83510 -66.21112 43.86042 -66.20059 43.87567 -66.20487 43.89113 -66.21644 43.92608 -66.19597 43.96184 -66.20442 44.00820 -66.20011 44.03735 -66.21679 44.07638 -66.23097 44.10258 -66.23693 44.13126 -66.23200 44.20379 -66.18721 44.23386 -66.17410 44.30255 -66.16062 44.32418 -66.14934 44.35965 -66.12352 44.37992 -66.10069 44.42467 -66.05019 44.46070 -65.98700 44.51464 -65.91161 44.53934 -65.89860 44.55647 -65.90943 44.56171 -65.92894 44.54913 -65.96773 44.55360 -65.99749 44.54844 -66.01761 44.49052 -66.08486 44.46748 -66.10429 44.42855 -66.15672 44.40139 -66.18063 44.39322 -66.18981 44.38020 -66.21386 44.38265 -66.22970 44.39639 -66.23493 44.41136 -66.22473 44.43520 -66.19517 44.45947 -66.16034 44.49450 -66.13957 44.50790 -66.11037 44.55523 -66.05608 44.58880 -65.96048 44.64573 -65.87399 44.65864 -65.83554 44.65646 -65.81444 44.64711 -65.79951 44.62691 -65.79037 44.59899 -65.78531 44.58066 -65.75042 44.58097 -65.72557 44.58903 -65.69648 44.61113 -65.66734 44.61984 -65.66023 44.64571 -65.63146 44.67242 -65.59973 44.69378 -65.56090 44.72362 -65.49510 44.73672 -65.47809 44.76169 -65.47204 44.76023 -65.49272 44.74588 -65.51793 44.71108 -65.61136 44.67711 -65.68179 44.65742 -65.75935 44.66061 -65.77742 44.67031 -65.78715 44.68073 -65.78660 44.69852 -65.76720 44.72203 -65.72988 44.75263 -65.66621 44.76981 -65.64450 44.80234 -65.56229 44.84323 -65.46533 44.88354 -65.39855 44.90961 -65.33175 44.94710 -65.26124 45.00895 -65.15701 45.03001 -65.13034 45.04845 -65.08748 45.07142 -65.04204 45.11271 -64.95375 45.12151 -64.92110 45.12617 -64.89322 45.14602 -64.82409 45.17173 -64.71874 45.23932 -64.47797 45.25713 -64.45254 45.27072 -64.44993 45.27998 -64.45728 45.29273 -64.48296 45.30356 -64.51488 45.31373 -64.53188 45.32760 -64.52401 45.31858 -64.47324 45.29403 -64.39344 45.28069 -64.37822 45.25664 -64.36918 45.22798 -64.38808 45.21080 -64.40293 45.18616 -64.41701 45.17445 -64.41360 45.15072 -64.39941 45.13776 -64.40424 45.11993 -64.42952 45.10884 -64.42834 45.09897 -64.41880 45.08993 -64.39362 45.09391 -64.37622 45.11173 -64.36345 45.11482 -64.34908 45.10663 -64.32086 45.07781 -64.27669 45.03940 -64.23045 45.01926 -64.21670 44.98571 -64.20579 44.97797 -64.19756 44.96879 -64.15990 44.96526 -64.12918 44.97100 -64.10569 44.98233 -64.10155 44.98913 -64.11285 44.99207 -64.12883 44.99311 -64.15099 45.00553 -64.16913 45.03010 -64.15497 45.05013 -64.16864 45.08091 -64.21921 45.10817 -64.23902 45.12606 -64.23883 45.16134 -64.21848 45.18648 -64.19387 45.19746 -64.16980 45.22368 -64.06825 45.24957 -63.94123 45.27200 -63.86450 45.29098 -63.81266 45.29823 -63.80069 45.29903 -63.78490 45.29673 -63.77100 45.30138 -63.73767 45.30873 -63.70782 45.30414 -63.67986 45.29536 -63.64425 45.30431 -63.56493 45.30070 -63.54660 45.27665 -63.52015 45.28169 -63.50694 45.29919 -63.49906 45.31374 -63.50567 45.32734 -63.48479 45.33963 -63.47745 45.35326 -63.48718 45.35714 -63.51817 45.35608 -63.55716 45.37664 -63.62666 45.37111 -63.68112 45.37329 -63.74367 45.38039 -63.78032 45.38066 -63.80573 45.35106 -63.90740 45.34666 -63.93541 45.35149 -63.95807 45.36191 -63.98778 45.36888 -64.01169 45.37179 -64.04062 45.37050 -64.06685 45.37214 -64.09132 45.38626 -64.12142 45.38764 -64.15119 45.38039 -64.17572 45.37898 -64.20201 45.38705 -64.21773 45.38808 -64.24008 45.38300 -64.26595 45.37286 -64.28704 45.36649 -64.30859 45.36182 -64.39260 45.35096 -64.46749 45.35349 -64.48896 45.37951 -64.55534 45.38817 -64.58607 45.39344 -64.63638 45.38603 -64.67370 45.37026 -64.71298 45.35334 -64.73528 45.31042 -64.76707 45.29802 -64.79942 45.29890 -64.82175 45.31432 -64.83837 45.33672 -64.87393 45.33916 -64.89541 45.33261 -64.91675 45.32197 -64.96832 45.32409 -64.98229 45.33549 -64.99114 45.39515 -64.95533 45.44814 -64.88242 45.46542 -64.86768 45.48930 -64.80586 45.50880 -64.76681 45.58019 -64.64480 45.64034 -64.54662 45.67697 -64.49236 45.70040 -64.47382 45.70971 -64.46839 45.73776 -64.44713 45.74940 -64.42498 45.76241 -64.42008 45.78065 -64.41473 45.78914 -64.36872 45.77766 -64.35994 45.75025 -64.38352 45.74067 -64.38133 45.73846 -64.36727 45.74667 -64.32662 45.76138 -64.31542 45.77608 -64.33524 45.78865 -64.32277 45.80810 -64.30890 45.80812 -64.30892 45.82397 -64.29481 45.94073 -64.19468 45.95318 -64.19255 45.96819 -64.08843 45.96807 -64.03141 45.97293 -63.99925 45.98157 -63.99453 45.98282 -63.99398 + 45.982824 -63.993981 45.981800 -63.972552 45.973465 -63.943849 45.961227 -63.920124 45.893962 -63.830838 45.875924 -63.787247 45.858253 -63.720376 45.867146 -63.689137 45.879832 -63.627321 45.878654 -63.604733 45.869442 -63.561186 45.874409 -63.534894 45.869112 -63.486319 45.856760 -63.462774 45.845831 -63.456461 45.839424 -63.465417 45.821112 -63.556528 45.813031 -63.571776 45.804278 -63.566664 45.797393 -63.537241 45.805055 -63.483571 45.807187 -63.453845 45.807268 -63.417617 45.794901 -63.394123 45.791251 -63.375605 45.803200 -63.324445 45.801224 -63.299722 45.795186 -63.285346 45.785574 -63.283394 45.767817 -63.314829 45.751205 -63.386961 45.734802 -63.386468 45.710981 -63.336435 45.707242 -63.318014 45.719538 -63.310557 45.734848 -63.301206 45.738647 -63.265429 45.759809 -63.239570 45.762725 -63.224911 45.753956 -63.219873 45.740177 -63.228224 45.733403 -63.211697 45.736964 -63.199286 45.750283 -63.183349 45.758571 -63.144611 45.752466 -63.112122 45.756850 -63.096592 45.769973 -63.104004 45.779324 -63.129369 45.795080 -63.127528 45.801906 -63.107777 45.800521 -63.085301 45.794393 -63.052788 45.768287 -62.960132 45.764032 -62.916041 45.740807 -62.803508 45.722785 -62.768060 45.714161 -62.739696 45.711119 -62.700136 45.702563 -62.689809 45.683580 -62.699127 45.674090 -62.733486 45.672162 -62.804496 45.666389 -62.821011 45.649759 -62.808063 45.645088 -62.792816 45.623055 -62.803887 45.612338 -62.792380 45.608779 -62.768774 45.626333 -62.755283 45.626951 -62.739351 45.620091 -62.722941 45.613067 -62.711863 45.608621 -62.691253 45.615108 -62.676908 45.631136 -62.687682 45.639114 -62.713757 45.655016 -62.706445 45.661051 -62.684637 45.667903 -62.618209 45.655802 -62.602460 45.646340 -62.595331 45.641832 -62.574887 45.642304 -62.540956 45.623728 -62.539609 45.612824 -62.533491 45.609589 -62.517404 45.620829 -62.494755 45.623613 -62.433363 45.631285 -62.405258 45.644792 -62.401894 45.649528 -62.417100 45.644550 -62.453931 45.645540 -62.468925 45.655977 -62.467588 45.664136 -62.446913 45.685203 -62.350552 45.731705 -62.224910 45.775551 -62.131894 45.822724 -62.049641 45.848330 -62.014899 45.870347 -61.974690 45.878520 -61.948466 45.876051 -61.929127 45.869751 -61.914804 45.859357 -61.916390 45.841830 -61.953724 45.823788 -61.960193 45.789817 -61.950686 45.727545 -61.938500 45.705095 -61.942567 45.664172 -61.968862 45.644547 -61.976155 45.628555 -61.965681 45.620481 -61.934417 45.624616 -61.918710 45.650368 -61.930870 45.662466 -61.923103 45.666954 -61.896760 45.664476 -61.877515 45.650015 -61.860723 45.633775 -61.855572 45.621841 -61.858131 45.612479 -61.845946 45.616073 -61.822804 45.627712 -61.807521 45.622370 -61.756256 45.619590 -61.690359 45.623830 -61.669410 45.631557 -61.659157 45.635205 -61.630659 45.645805 -61.623729 45.656229 -61.622194 45.664095 -61.606700 45.669821 -61.584633 45.667043 -61.547346 45.621572 -61.451732 45.596882 -61.426233 45.571071 -61.414382 45.544994 -61.384535 45.533294 -61.376683 45.524519 -61.366714 45.516288 -61.335744 45.515269 -61.315437 45.506739 -61.295070 45.490916 -61.268926 45.477543 -61.267307 45.452548 -61.291612 45.433402 -61.317174 45.421267 -61.364141 45.408084 -61.385753 45.402663 -61.397044 45.399352 -61.443365 45.389242 -61.462990 45.385190 -61.478656 45.422573 -61.532126 45.438174 -61.563522 45.441947 -61.592248 45.437086 -61.611029 45.426695 -61.607316 45.411520 -61.560044 45.402267 -61.542787 45.375068 -61.531938 45.353168 -61.515029 45.338890 -61.487987 45.332207 -61.456037 45.337242 -61.432031 45.342662 -61.386942 45.340369 -61.357315 45.327955 -61.313510 45.325482 -61.289255 45.336802 -61.245479 45.330303 -61.197786 45.332720 -61.154630 45.321487 -61.120444 45.318249 -61.055031 45.306325 -61.018809 45.292321 -61.009794 45.272262 -61.010186 45.269010 -61.022638 45.280596 -61.040931 45.277383 -61.053488 45.261714 -61.056036 45.228635 -61.077960 45.200386 -61.119941 45.193707 -61.155342 45.199221 -61.177617 45.207231 -61.185356 45.238140 -61.162429 45.250155 -61.159755 45.269991 -61.170070 45.275575 -61.187090 45.272343 -61.199638 45.255779 -61.210415 45.226096 -61.209233 45.212541 -61.218097 45.226123 -61.242859 45.234499 -61.268437 45.230971 -61.296710 45.234214 -61.317813 45.230755 -61.340798 45.218918 -61.371806 45.198140 -61.403458 45.184786 -61.401807 45.178683 -61.377439 45.186255 -61.338814 45.179932 -61.319686 45.164464 -61.316903 45.157275 -61.339733 45.150301 -61.419185 45.143174 -61.436717 45.136584 -61.466798 45.132646 -61.505386 45.138663 -61.535127 45.139567 -61.560370 45.134501 -61.584254 45.132059 -61.621865 45.150889 -61.702625 45.145104 -61.724315 45.136704 -61.732259 45.125701 -61.698080 45.115802 -61.678716 45.100455 -61.698916 45.071007 -61.686889 45.066240 -61.700241 45.076451 -61.737457 45.064678 -61.786075 45.077604 -61.831876 45.073494 -61.847400 45.058609 -61.846581 45.049931 -61.864901 45.038821 -61.864349 45.027553 -61.868946 45.020419 -61.886297 45.031062 -61.902588 45.035869 -61.917534 45.020592 -61.932359 45.024521 -61.950440 45.042804 -61.985012 45.031919 -62.002174 45.023986 -61.994321 45.010895 -61.987292 45.005332 -61.998472 45.004267 -62.035002 44.993255 -62.080440 44.987554 -62.096858 44.977075 -62.075285 44.980718 -62.052487 44.979032 -62.035648 44.973572 -62.018524 44.964645 -62.019059 44.958463 -62.051180 44.952787 -62.141797 44.943747 -62.170408 44.931819 -62.195861 44.925921 -62.217382 44.934008 -62.242967 44.935517 -62.265044 44.922713 -62.293420 44.904000 -62.320441 44.899143 -62.333680 44.899820 -62.358800 44.890490 -62.369704 44.879946 -62.376281 44.873307 -62.395739 44.877176 -62.413635 44.873632 -62.431219 44.843061 -62.478076 44.843152 -62.495918 44.866942 -62.496511 44.873078 -62.510486 44.868855 -62.525878 44.852363 -62.530945 44.839518 -62.536284 44.833584 -62.557825 44.837185 -62.581011 44.790589 -62.576573 44.778250 -62.589305 44.782120 -62.607285 44.801542 -62.623245 44.808850 -62.646650 44.796499 -62.659365 44.789221 -62.676501 44.772488 -62.686791 44.767579 -62.699949 44.774175 -62.721334 44.776538 -62.757892 44.762520 -62.794357 44.761895 -62.809986 44.785925 -62.840985 44.787365 -62.862952 44.783908 -62.875238 44.772776 -62.874332 44.762495 -62.852681 44.747202 -62.844239 44.734904 -62.856823 44.704402 -62.839891 44.695098 -62.850587 44.693810 -62.864009 44.707338 -62.896262 44.709672 -62.932887 44.705766 -62.973158 44.695384 -63.009754 44.701072 -63.034182 44.722800 -63.046355 44.745012 -63.048140 44.760208 -63.056713 44.767890 -63.069764 44.754386 -63.090672 44.742006 -63.085448 44.717428 -63.069788 44.690851 -63.065547 44.672827 -63.071412 44.671741 -63.097324 44.694785 -63.113719 44.708949 -63.130553 44.739357 -63.129940 44.751131 -63.133096 44.758536 -63.151442 44.750707 -63.161071 44.698504 -63.167118 44.679517 -63.175922 44.675906 -63.193312 44.686074 -63.197275 44.713714 -63.193451 44.733720 -63.194027 44.738949 -63.211198 44.730008 -63.229124 44.686725 -63.234797 44.667733 -63.243571 44.673629 -63.262741 44.694917 -63.267719 44.704886 -63.276917 44.677697 -63.305807 44.655051 -63.296500 44.645292 -63.299803 44.636577 -63.312576 44.612826 -63.329257 44.623132 -63.381021 44.617788 -63.416913 44.623568 -63.436144 44.653307 -63.451259 44.663686 -63.467888 44.664463 -63.482470 44.659439 -63.495510 44.636607 -63.491319 44.609818 -63.461913 44.586428 -63.485782 44.585718 -63.501172 44.596085 -63.517788 44.600912 -63.557620 44.637264 -63.589152 44.644786 -63.602316 44.661009 -63.620476 44.674105 -63.640426 44.696054 -63.677904 44.695352 -63.693438 44.662082 -63.690340 44.646542 -63.674177 44.630987 -63.628049 44.621907 -63.615771 44.609013 -63.620776 44.590639 -63.601446 44.577918 -63.588822 44.555734 -63.586777 44.537725 -63.592253 44.522898 -63.590871 44.506679 -63.572776 44.487201 -63.561599 44.447535 -63.584914 44.446850 -63.600362 44.453059 -63.609280 44.457527 -63.624102 44.453121 -63.639248 44.438084 -63.643041 44.430630 -63.659884 44.431416 -63.674503 44.446606 -63.683164 44.455254 -63.718175 44.450634 -63.750892 44.459687 -63.763149 44.465691 -63.777111 44.459258 -63.815892 44.463732 -63.830845 44.482774 -63.834758 44.487015 -63.854910 44.474720 -63.892002 44.489658 -63.948441 44.498450 -63.965939 44.514825 -63.978979 44.537512 -63.970935 44.554528 -63.956032 44.572989 -63.957926 44.604474 -63.967397 44.619773 -63.958493 44.656361 -63.924778 44.650797 -63.960630 44.635953 -63.989326 44.617408 -64.060231 44.605288 -64.079737 44.593937 -64.083740 44.556397 -64.077664 44.529404 -64.083235 44.495357 -64.052760 44.484954 -64.053701 44.475874 -64.083873 44.458556 -64.103775 44.452503 -64.119742 44.466879 -64.156511 44.479759 -64.164074 44.508690 -64.165073 44.529371 -64.180732 44.547035 -64.210716 44.548383 -64.239938 44.525378 -64.252934 44.524567 -64.280923 44.530345 -64.337626 44.516284 -64.350604 44.474806 -64.349138 44.465949 -64.361661 44.441949 -64.352676 44.432440 -64.363164 44.427307 -64.388372 44.410490 -64.397892 44.395372 -64.388998 44.389545 -64.374922 44.399475 -64.341823 44.398224 -64.325125 44.389868 -64.314961 44.373934 -64.321512 44.360328 -64.286895 44.347092 -64.284435 44.339776 -64.295970 44.347920 -64.336183 44.339703 -64.363168 44.327140 -64.375284 44.311805 -64.371416 44.310423 -64.342396 44.311356 -64.327059 44.301474 -64.317604 44.274817 -64.330238 44.277505 -64.296491 44.270676 -64.285392 44.256174 -64.278743 44.242716 -64.293733 44.234890 -64.315555 44.240208 -64.339894 44.278320 -64.372908 44.282123 -64.385782 44.270786 -64.401968 44.255157 -64.403421 44.245044 -64.423958 44.225103 -64.435130 44.218162 -64.466327 44.143425 -64.527892 44.132466 -64.576039 44.127885 -64.652727 44.117748 -64.660902 44.106153 -64.632748 44.107307 -64.600042 44.091702 -64.588909 44.053982 -64.612357 44.048123 -64.622979 44.048159 -64.647654 44.043548 -64.662457 44.032531 -64.673575 44.021770 -64.704107 43.994488 -64.714266 43.969383 -64.725750 43.959210 -64.746088 43.948829 -64.759171 43.939249 -64.793972 43.928452 -64.824417 43.924404 -64.853639 43.909692 -64.876416 43.894973 -64.874751 43.886739 -64.864436 43.877924 -64.827639 43.858950 -64.810974 43.849175 -64.813900 43.843615 -64.831730 43.836521 -64.850221 43.823922 -64.862073 43.816590 -64.873492 43.827300 -64.892140 43.851134 -64.901177 43.864546 -64.935538 43.861382 -64.949480 43.851270 -64.957382 43.833878 -64.927729 43.794981 -64.934270 43.787601 -64.945563 43.791193 -64.958294 43.819392 -64.969884 43.839783 -64.985720 43.838259 -64.998772 43.826535 -65.007645 43.790840 -64.987936 43.771875 -64.983499 43.751909 -64.994314 43.752996 -65.023057 43.773488 -65.038947 43.787820 -65.045820 43.797221 -65.060212 43.796283 -65.075419 43.776048 -65.079039 43.735411 -65.054602 43.701073 -65.070755 43.687472 -65.097574 43.704211 -65.112949 43.713940 -65.122343 43.710273 -65.134116 43.677665 -65.156585 43.651947 -65.165584 43.649076 -65.186536 43.671043 -65.189360 43.690718 -65.183739 43.700746 -65.188053 43.696581 -65.217098 43.748452 -65.250269 43.754163 -65.264369 43.752760 -65.284601 43.737043 -65.297883 43.727610 -65.295712 43.706266 -65.282649 43.679312 -65.287415 43.658728 -65.295911 43.651344 -65.307218 43.659047 -65.334668 43.667295 -65.344962 43.677313 -65.349308 43.706115 -65.351030 43.717227 -65.371964 43.713757 -65.390872 43.705106 -65.397896 43.632078 -65.383218 43.610440 -65.375223 43.582702 -65.389920 43.568094 -65.388050 43.552146 -65.394115 43.546874 -65.406630 43.542374 -65.428323 43.543453 -65.444848 43.558323 -65.453976 43.563448 -65.465715 43.555867 -65.489233 43.536405 -65.482562 43.523131 -65.460483 43.511291 -65.449701 43.488138 -65.442606 43.478244 -65.445324 43.470262 -65.454407 43.489624 -65.473246 43.503577 -65.485278 43.494280 -65.502391 43.471355 -65.502389 43.455369 -65.508297 43.447966 -65.519523 43.466984 -65.543446 43.485401 -65.596720 43.512810 -65.606510 43.518087 -65.625543 43.510544 -65.648958 43.500308 -65.656701 43.483847 -65.679810 43.476417 -65.710371 43.477144 -65.731782 43.472147 -65.758528 43.475355 -65.776247 43.484424 -65.783569 43.496365 -65.782241 43.508647 -65.775846 43.515263 -65.786978 43.525578 -65.817804 43.538293 -65.825777 43.566832 -65.820548 43.597252 -65.809604 43.642357 -65.800594 43.657851 -65.811972 43.658281 -65.826375 43.648022 -65.834103 43.629691 -65.831504 43.616204 -65.833723 43.588468 -65.848095 43.611674 -65.874876 43.625927 -65.881981 43.688686 -65.885829 43.734166 -65.871785 43.760614 -65.884870 43.766452 -65.906053 43.763789 -65.922022 43.776160 -65.935163 43.797725 -65.943341 43.806444 -65.955849 43.806276 -65.968118 43.797575 -65.975048 43.782392 -65.970803 43.771579 -65.976449 43.763414 -65.985442 43.768731 -66.004675 43.779473 -66.018521 43.762360 -66.039570 43.737076 -66.011339 43.722707 -66.004118 43.710216 -66.003327 43.694750 -66.011268 43.689958 -66.025926 43.689029 -66.048226 43.676638 -66.054630 43.674695 -66.079886 43.683215 -66.085232 43.702910 -66.079886 43.709493 -66.091109 43.705030 -66.120075 43.712540 -66.128396 43.726609 -66.128436 43.740281 -66.133459 43.740657 -66.147891 43.745253 -66.164899 43.775349 -66.178661 43.783100 -66.194119 43.807155 -66.198722 43.835107 -66.211124 43.860422 -66.200598 43.875679 -66.204873 43.891138 -66.216444 43.926080 -66.195972 43.961840 -66.204422 44.008201 -66.200114 44.037357 -66.216798 44.076384 -66.230978 44.102584 -66.236930 44.131263 -66.232004 44.203791 -66.187218 44.233860 -66.174108 44.302555 -66.160625 44.324181 -66.149342 44.359659 -66.123522 44.379929 -66.100690 44.424676 -66.050190 44.460703 -65.987006 44.514642 -65.911618 44.539345 -65.898606 44.556478 -65.909438 44.561714 -65.928941 44.549131 -65.967730 44.553607 -65.997497 44.548442 -66.017616 44.490528 -66.084869 44.467482 -66.104298 44.428553 -66.156720 44.401393 -66.180630 44.393220 -66.189818 44.380207 -66.213867 44.382650 -66.229701 44.396396 -66.234936 44.411366 -66.224738 44.435205 -66.195170 44.459479 -66.160343 44.494502 -66.139572 44.507901 -66.110377 44.555236 -66.056089 44.588802 -65.960484 44.645739 -65.873996 44.658640 -65.835548 44.656469 -65.814442 44.647115 -65.799510 44.626913 -65.790379 44.598996 -65.785316 44.580661 -65.750428 44.580974 -65.725576 44.589032 -65.696489 44.611131 -65.667343 44.619841 -65.660230 44.645719 -65.631463 44.672429 -65.599735 44.693781 -65.560907 44.723623 -65.495102 44.736725 -65.478096 44.761693 -65.472046 44.760235 -65.492722 44.745889 -65.517934 44.711085 -65.611360 44.677113 -65.681793 44.657425 -65.759350 44.660612 -65.777422 44.670313 -65.787156 44.680738 -65.786606 44.698524 -65.767202 44.722037 -65.729888 44.752632 -65.666213 44.769814 -65.644507 44.802341 -65.562292 44.843236 -65.465331 44.883541 -65.398553 44.909613 -65.331751 44.947100 -65.261247 45.008954 -65.157013 45.030015 -65.130345 45.048458 -65.087482 45.071422 -65.042046 45.112713 -64.953755 45.121512 -64.921104 45.126170 -64.893229 45.146027 -64.824099 45.171731 -64.718749 45.239323 -64.477978 45.257132 -64.452542 45.270726 -64.449937 45.279982 -64.457281 45.292736 -64.482968 45.303562 -64.514880 45.313731 -64.531883 45.327600 -64.524013 45.318581 -64.473245 45.294033 -64.393444 45.280690 -64.378226 45.256642 -64.369180 45.227983 -64.388086 45.210800 -64.402935 45.186167 -64.417019 45.174458 -64.413608 45.150728 -64.399410 45.137760 -64.404249 45.119935 -64.429529 45.108845 -64.428340 45.098978 -64.418806 45.089939 -64.393622 45.093910 -64.376225 45.111735 -64.363459 45.114823 -64.349086 45.106639 -64.320869 45.077810 -64.276696 45.039404 -64.230459 45.019263 -64.216707 44.985713 -64.205797 44.977978 -64.197566 44.968798 -64.159903 44.965269 -64.129183 44.971002 -64.105692 44.982334 -64.101551 44.989130 -64.112855 44.992074 -64.128833 44.993118 -64.150992 45.005533 -64.169135 45.030106 -64.154972 45.050139 -64.168648 45.080917 -64.219212 45.108179 -64.239022 45.126060 -64.238830 45.161345 -64.218485 45.186486 -64.193873 45.197460 -64.169809 45.223688 -64.068251 45.249577 -63.941239 45.272003 -63.864504 45.290987 -63.812667 45.298230 -63.800698 45.299031 -63.784901 45.296733 -63.771001 45.301380 -63.737671 45.308730 -63.707828 45.304145 -63.679865 45.295369 -63.644258 45.304310 -63.564939 45.300702 -63.546609 45.276650 -63.520159 45.281692 -63.506943 45.299197 -63.499064 45.313748 -63.505672 45.327347 -63.484799 45.339635 -63.477452 45.353265 -63.487189 45.357140 -63.518174 45.356089 -63.557165 45.376640 -63.626664 45.371111 -63.681122 45.373299 -63.743678 45.380392 -63.780323 45.380665 -63.805732 45.351065 -63.907407 45.346668 -63.935410 45.351490 -63.958078 45.361918 -63.987785 45.368884 -64.011698 45.371796 -64.040623 45.370502 -64.066854 45.372147 -64.091320 45.386260 -64.121424 45.387642 -64.151192 45.380392 -64.175720 45.378980 -64.202010 45.387057 -64.217730 45.388081 -64.240086 45.383002 -64.265957 45.372868 -64.287043 45.366498 -64.308597 45.361821 -64.392604 45.350960 -64.467490 45.353499 -64.488964 45.379517 -64.555346 45.388171 -64.586076 45.393441 -64.636382 45.386033 -64.673709 45.370268 -64.712989 45.353347 -64.735284 45.310426 -64.767074 45.298029 -64.799424 45.298909 -64.821751 45.314323 -64.838375 45.336722 -64.873930 45.339164 -64.895419 45.332610 -64.916758 45.321979 -64.968329 45.324093 -64.982296 45.335490 -64.991147 45.395153 -64.955330 45.448146 -64.882425 45.465426 -64.867682 45.489303 -64.805866 45.508805 -64.766810 45.580190 -64.644801 45.640341 -64.546622 45.676979 -64.492363 45.700408 -64.473828 45.709718 -64.468392 45.737760 -64.447136 45.749407 -64.424980 45.762412 -64.420080 45.780650 -64.414732 45.789145 -64.368721 45.777664 -64.359940 45.750255 -64.383522 45.740671 -64.381335 45.738461 -64.367270 45.746672 -64.326628 45.761388 -64.315425 45.776089 -64.335241 45.788651 -64.322774 45.808102 -64.308902 45.808120 -64.308927 45.823976 -64.294811 45.940739 -64.194680 45.953182 -64.192553 45.968192 -64.088437 45.968076 -64.031412 45.972937 -63.999252 45.981579 -63.994538 45.982824 -63.993981 @@ -452,15 +452,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 45.50482 -61.22751 - 45.53473 -61.18069 + 45.504823 -61.227514 + 45.534739 -61.180696 - 45.51045 -61.22751 45.51931 -61.22687 45.52995 -61.21455 45.53473 -61.20094 45.52992 -61.18069 45.51634 -61.18962 45.50482 -61.21028 45.51045 -61.22751 + 45.510451 -61.227514 45.519318 -61.226878 45.529958 -61.214551 45.534739 -61.200944 45.529920 -61.180696 45.516349 -61.189628 45.504823 -61.210287 45.510451 -61.227514 @@ -483,15 +483,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 45.78689 -62.62684 - 45.81546 -62.55613 + 45.786892 -62.626846 + 45.815465 -62.556139 - 45.79069 -62.62192 45.79950 -62.62684 45.80862 -62.62107 45.81546 -62.59606 45.80869 -62.55613 45.79817 -62.55752 45.78689 -62.60347 45.79069 -62.62192 + 45.790699 -62.621922 45.799503 -62.626846 45.808625 -62.621075 45.815465 -62.596064 45.808696 -62.556139 45.798173 -62.557522 45.786892 -62.603470 45.790699 -62.621922 @@ -514,15 +514,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 45.73923 -62.77618 - 45.76402 -62.72846 + 45.739239 -62.776183 + 45.764021 -62.728467 - 45.74288 -62.76845 45.75973 -62.77618 45.76402 -62.76050 45.76045 -62.73682 45.74881 -62.72846 45.73923 -62.74484 45.74288 -62.76845 + 45.742885 -62.768457 45.759737 -62.776183 45.764021 -62.760507 45.760451 -62.736823 45.748816 -62.728467 45.739239 -62.744842 45.742885 -62.768457 @@ -545,15 +545,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 43.91841 -60.11754 - 44.01041 -59.71284 + 43.918413 -60.117541 + 44.010417 -59.712843 - 43.92307 -60.11754 43.93352 -60.11062 43.94339 -60.07098 43.95258 -59.91475 43.95880 -59.86978 43.96940 -59.82193 44.00294 -59.74551 44.01041 -59.72512 44.00599 -59.71284 43.99417 -59.71575 43.98158 -59.73206 43.96591 -59.77585 43.93528 -59.85529 43.92985 -59.88686 43.92813 -59.93384 43.92190 -59.98373 43.91841 -60.05722 43.91957 -60.09712 43.92307 -60.11754 + 43.923078 -60.117541 43.933522 -60.110628 43.943396 -60.070988 43.952586 -59.914751 43.958808 -59.869787 43.969408 -59.821934 44.002943 -59.745514 44.010417 -59.725120 44.005999 -59.712843 43.994175 -59.715759 43.981586 -59.732063 43.965917 -59.775859 43.935280 -59.855295 43.929858 -59.886866 43.928136 -59.933842 43.921907 -59.983735 43.918413 -60.057221 43.919575 -60.097126 43.923078 -60.117541 @@ -576,15 +576,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 44.25244 -66.35756 - 44.36908 -66.25144 + 44.252448 -66.357560 + 44.369088 -66.251440 - 44.25426 -66.34999 44.26331 -66.35756 44.36053 -66.28547 44.36908 -66.27114 44.36868 -66.25668 44.35494 -66.25144 44.34005 -66.26156 44.27920 -66.29795 44.26288 -66.31608 44.25244 -66.33624 44.25426 -66.34999 + 44.254260 -66.349998 44.263314 -66.357560 44.360536 -66.285475 44.369088 -66.271148 44.368689 -66.256681 44.354945 -66.251440 44.340056 -66.261563 44.279201 -66.297959 44.262882 -66.316083 44.252448 -66.336248 44.254260 -66.349998 @@ -607,15 +607,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 44.21850 -66.43267 - 44.25705 -66.37969 + 44.218506 -66.432672 + 44.257055 -66.379694 - 44.22686 -66.43267 44.23618 -66.42797 44.25705 -66.40008 44.25302 -66.38496 44.23929 -66.37969 44.22341 -66.39285 44.21850 -66.40752 44.22686 -66.43267 + 44.226863 -66.432672 44.236182 -66.427973 44.257055 -66.400086 44.253021 -66.384960 44.239292 -66.379694 44.223413 -66.392850 44.218506 -66.407527 44.226863 -66.432672 @@ -638,15 +638,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 43.41231 -65.68783 - 43.47638 -65.61648 + 43.412311 -65.687835 + 43.476384 -65.616482 - 43.41231 -65.65685 43.43182 -65.68286 43.44554 -65.68783 43.47369 -65.65616 43.47638 -65.64022 43.46618 -65.61648 43.44388 -65.61842 43.42851 -65.62655 43.41583 -65.63808 43.41231 -65.65685 + 43.412311 -65.656854 43.431829 -65.682866 43.445545 -65.687835 43.473694 -65.656161 43.476384 -65.640224 43.466182 -65.616482 43.443882 -65.618422 43.428510 -65.626553 43.415833 -65.638089 43.412311 -65.656854 diff --git a/msautotest/wxs/expected/wfs_optional_items_get_feature_area.xml b/msautotest/wxs/expected/wfs_optional_items_get_feature_area.xml index 71673161a1..cd2d0d8aea 100644 --- a/msautotest/wxs/expected/wfs_optional_items_get_feature_area.xml +++ b/msautotest/wxs/expected/wfs_optional_items_get_feature_area.xml @@ -10,8 +10,8 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 timeStamp="" numberMatched="21" numberReturned="21"> - 43.41231 -66.43267 - 47.79644 -59.70969 + 43.412311 -66.432672 + 47.796447 -59.709694 diff --git a/msautotest/wxs/expected/wfs_optional_items_get_feature_area_geometry.xml b/msautotest/wxs/expected/wfs_optional_items_get_feature_area_geometry.xml index 4fe15328f0..de9367a749 100644 --- a/msautotest/wxs/expected/wfs_optional_items_get_feature_area_geometry.xml +++ b/msautotest/wxs/expected/wfs_optional_items_get_feature_area_geometry.xml @@ -10,23 +10,23 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 timeStamp="" numberMatched="21" numberReturned="21"> - 43.41231 -66.43267 - 47.79644 -59.70969 + 43.412311 -66.432672 + 47.796447 -59.709694 - 47.76789 -61.51051 - 47.79644 -61.45764 + 47.767892 -61.510511 + 47.796447 -61.457648 - 47.77424 -61.51051 47.78860 -61.50894 47.79644 -61.49272 47.78743 -61.45764 47.76789 -61.45998 47.76961 -61.48350 47.77424 -61.51051 + 47.774240 -61.510511 47.788606 -61.508947 47.796447 -61.492725 47.787438 -61.457648 47.767892 -61.459987 47.769615 -61.483502 47.774240 -61.510511 @@ -39,15 +39,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 47.16638 -60.21172 - 47.19271 -60.16877 + 47.166385 -60.211728 + 47.192716 -60.168776 - 47.16638 -60.20485 47.17985 -60.21172 47.19271 -60.19435 47.18763 -60.17344 47.17496 -60.16877 47.16638 -60.20485 + 47.166385 -60.204850 47.179857 -60.211728 47.192716 -60.194354 47.187638 -60.173448 47.174965 -60.168776 47.166385 -60.204850 @@ -60,15 +60,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 47.19106 -62.07696 - 47.62759 -61.43322 + 47.191069 -62.076968 + 47.627593 -61.433227 - 47.24108 -62.01051 47.24604 -61.96674 47.23831 -61.94754 47.22825 -61.93270 47.22220 -61.90699 47.23311 -61.86469 47.24267 -61.84221 47.23857 -61.82873 47.22731 -61.82804 47.21582 -61.83841 47.19106 -61.89528 47.19587 -61.91086 47.20730 -61.93027 47.21146 -61.94369 47.20068 -61.98054 47.20210 -62.00918 47.21127 -62.05713 47.21986 -62.07304 47.23019 -62.07696 47.30062 -62.02523 47.32797 -62.01258 47.35422 -62.01412 47.38157 -62.00145 47.40632 -61.97428 47.46073 -61.87584 47.55646 -61.74402 47.59681 -61.65975 47.61945 -61.58987 47.62006 -61.53210 47.62627 -61.49244 47.62759 -61.46701 47.62579 -61.44364 47.61706 -61.43322 47.60265 -61.44020 47.58445 -61.48263 47.57198 -61.50196 47.54670 -61.52732 47.53100 -61.55423 47.52441 -61.58041 47.53668 -61.60212 47.54664 -61.59275 47.56410 -61.55367 47.58387 -61.54035 47.59656 -61.57531 47.58175 -61.62893 47.56042 -61.67323 47.53788 -61.70753 47.50243 -61.77198 47.46323 -61.81183 47.43985 -61.84363 47.42876 -61.86734 47.41317 -61.88844 47.37958 -61.91082 47.35461 -61.91930 47.34335 -61.91859 47.32832 -61.94748 47.31536 -61.98306 47.25730 -62.02144 47.24108 -62.01051 + 47.241088 -62.010515 47.246040 -61.966742 47.238311 -61.947548 47.228257 -61.932708 47.222202 -61.906997 47.233116 -61.864694 47.242674 -61.842210 47.238572 -61.828736 47.227311 -61.828048 47.215824 -61.838414 47.191069 -61.895286 47.195878 -61.910866 47.207300 -61.930279 47.211466 -61.943690 47.200682 -61.980541 47.202105 -62.009180 47.211273 -62.057130 47.219864 -62.073040 47.230193 -62.076968 47.300625 -62.025236 47.327971 -62.012584 47.354223 -62.014128 47.381572 -62.001451 47.406325 -61.974280 47.460730 -61.875844 47.556462 -61.744027 47.596818 -61.659750 47.619458 -61.589874 47.620068 -61.532104 47.626271 -61.492444 47.627593 -61.467016 47.625790 -61.443646 47.617067 -61.433227 47.602653 -61.440203 47.584451 -61.482632 47.571983 -61.501965 47.546702 -61.527322 47.531009 -61.554237 47.524411 -61.580413 47.536685 -61.602124 47.546644 -61.592755 47.564103 -61.553676 47.583872 -61.540355 47.596569 -61.575318 47.581754 -61.628933 47.560421 -61.673230 47.537886 -61.707530 47.502438 -61.771983 47.463236 -61.811839 47.439850 -61.843632 47.428764 -61.867341 47.413176 -61.888445 47.379589 -61.910824 47.354617 -61.919309 47.343351 -61.918598 47.328320 -61.947480 47.315363 -61.983069 47.257309 -62.021449 47.241088 -62.010515 @@ -81,15 +81,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 47.37578 -61.85020 - 47.53541 -61.62463 + 47.375784 -61.850201 + 47.535418 -61.624632 - 47.39077 -61.85020 47.40527 -61.83772 47.41716 -61.81637 47.42945 -61.80270 47.44433 -61.77925 47.46587 -61.75944 47.48454 -61.73062 47.49872 -61.70481 47.52737 -61.66642 47.53541 -61.64470 47.53286 -61.62463 47.52225 -61.63180 47.51114 -61.65567 47.45830 -61.72907 47.43823 -61.75344 47.41589 -61.77649 47.37997 -61.80321 47.37578 -61.81946 47.39077 -61.85020 + 47.390774 -61.850201 47.405273 -61.837726 47.417160 -61.816375 47.429451 -61.802704 47.444334 -61.779258 47.465873 -61.759440 47.484545 -61.730626 47.498723 -61.704819 47.527379 -61.666427 47.535418 -61.644700 47.532866 -61.624632 47.522259 -61.631801 47.511145 -61.655676 47.458309 -61.729072 47.438230 -61.753441 47.415897 -61.776498 47.379975 -61.803218 47.375784 -61.819462 47.390774 -61.850201 @@ -102,15 +102,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 45.55044 -61.59511 - 47.03152 -60.34353 + 45.550449 -61.595111 + 47.031525 -60.343533 - 45.64995 -60.88100 45.62964 -60.89735 45.63055 -60.92814 45.61131 -61.00908 45.61072 -61.04080 45.60069 -61.06061 45.58886 -61.09728 45.58218 -61.13299 45.56434 -61.16831 45.55872 -61.19037 45.56065 -61.20734 45.58078 -61.20714 45.59226 -61.22567 45.59854 -61.24502 45.59370 -61.26380 45.57932 -61.27601 45.57074 -61.29466 45.55044 -61.30547 45.55804 -61.33436 45.57893 -61.36499 45.60096 -61.37658 45.62222 -61.39131 45.64498 -61.43901 45.68124 -61.47794 45.72090 -61.50435 45.74448 -61.51506 45.79398 -61.53240 45.83324 -61.54064 45.86342 -61.55506 45.90791 -61.56254 45.94146 -61.56423 46.02269 -61.59511 46.03665 -61.57548 46.04540 -61.55132 46.05222 -61.51518 46.05285 -61.48843 46.05503 -61.45536 46.06486 -61.45148 46.07567 -61.46816 46.09111 -61.51066 46.10430 -61.51772 46.14672 -61.48975 46.17439 -61.45567 46.19619 -61.41489 46.21434 -61.36836 46.23455 -61.33384 46.29334 -61.27078 46.39497 -61.18675 46.42631 -61.15240 46.44736 -61.14355 46.51078 -61.10612 46.57439 -61.06319 46.58996 -61.06597 46.61490 -61.09195 46.62260 -61.08137 46.62750 -61.06206 46.62258 -61.04122 46.62967 -61.02303 46.64697 -61.01398 46.65751 -61.01219 46.73777 -60.95217 46.78405 -60.91250 46.79934 -60.89124 46.81256 -60.85802 46.83880 -60.80765 46.88381 -60.75247 46.93979 -60.70840 46.97604 -60.68331 47.00688 -60.67548 47.01668 -60.66590 47.02681 -60.63446 47.02576 -60.60818 47.01756 -60.54331 46.99698 -60.51433 46.99416 -60.50008 47.00184 -60.48380 47.02743 -60.47143 47.03152 -60.44411 47.02334 -60.43075 47.01370 -60.42398 47.00027 -60.42800 46.97970 -60.45590 46.96315 -60.46750 46.94223 -60.46591 46.92785 -60.47316 46.91766 -60.51544 46.90031 -60.52481 46.89381 -60.51047 46.89407 -60.48325 46.88541 -60.45685 46.85658 -60.43096 46.85306 -60.40903 46.85722 -60.37096 46.84174 -60.35207 46.81863 -60.34397 46.79994 -60.34353 46.78409 -60.35725 46.73103 -60.35388 46.68503 -60.38863 46.67134 -60.41431 46.65255 -60.41936 46.65209 -60.40091 46.64560 -60.38121 46.63657 -60.38199 46.62739 -60.39920 46.61609 -60.40979 46.60516 -60.38238 46.58877 -60.37766 46.55717 -60.39962 46.53890 -60.42845 46.51251 -60.44942 46.49831 -60.45121 46.40272 -60.51463 46.38309 -60.53354 46.36266 -60.56105 46.35206 -60.56824 46.33566 -60.56890 46.31001 -60.58650 46.29958 -60.58831 46.27931 -60.59961 46.26988 -60.63265 46.26067 -60.64966 46.24740 -60.64284 46.22487 -60.65291 46.21303 -60.64502 46.21024 -60.63101 46.21637 -60.61606 46.25403 -60.59029 46.30100 -60.53670 46.31771 -60.51452 46.33005 -60.47931 46.30400 -60.47324 46.29501 -60.47952 46.27538 -60.49840 46.26319 -60.51743 46.22776 -60.54436 46.19430 -60.59400 46.10330 -60.70392 46.09247 -60.73247 46.09174 -60.78077 46.07638 -60.81238 46.06139 -60.86219 46.05797 -60.89103 46.07230 -60.92366 46.06668 -60.94590 46.05320 -60.94974 46.03421 -60.97053 46.02431 -60.98510 45.99002 -61.02658 45.97226 -61.05689 45.95590 -61.09692 45.94928 -61.13287 45.94288 -61.15298 45.92864 -61.15989 45.92678 -61.14273 45.93026 -61.11400 45.94794 -61.04426 45.95424 -61.02420 45.95924 -60.99444 45.97081 -60.97345 45.98019 -60.95135 45.99803 -60.94988 46.01138 -60.95681 46.03075 -60.90934 46.03175 -60.89546 46.01957 -60.86935 46.02499 -60.85245 46.04649 -60.81672 46.04855 -60.77818 46.03810 -60.78011 46.00609 -60.82286 45.98055 -60.84022 45.94769 -60.84129 45.93452 -60.87388 45.91784 -60.93525 45.92248 -60.96634 45.91903 -60.99507 45.90151 -61.05953 45.88426 -61.10260 45.84710 -61.13519 45.84304 -61.11695 45.85166 -61.09280 45.86428 -61.05806 45.86543 -61.03352 45.88570 -61.02799 45.89205 -61.00259 45.87647 -60.96039 45.86758 -60.95579 45.85654 -60.98955 45.83520 -60.97494 45.82597 -60.99154 45.82762 -61.02462 45.81520 -61.05403 45.78755 -61.09867 45.76274 -61.15204 45.74052 -61.17983 45.73866 -61.16274 45.72476 -61.14835 45.71458 -61.17342 45.69499 -61.18652 45.68877 -61.16179 45.69638 -61.11746 45.70518 -61.08281 45.71903 -61.05772 45.73432 -61.03713 45.75141 -60.99942 45.75710 -60.97199 45.74426 -60.89393 45.73581 -60.86279 45.72194 -60.84844 45.70705 -60.84805 45.68510 -60.87066 45.66404 -60.88471 45.64995 -60.88100 + 45.649954 -60.881009 45.629648 -60.897351 45.630553 -60.928145 45.611319 -61.009089 45.610721 -61.040806 45.600690 -61.060614 45.588861 -61.097280 45.582181 -61.132995 45.564345 -61.168312 45.558723 -61.190377 45.560650 -61.207340 45.580780 -61.207140 45.592268 -61.225673 45.598546 -61.245028 45.593709 -61.263803 45.579321 -61.276019 45.570740 -61.294666 45.550449 -61.305470 45.558043 -61.334366 45.578931 -61.364992 45.600965 -61.376583 45.622223 -61.391312 45.644981 -61.439011 45.681246 -61.477948 45.720907 -61.504351 45.744486 -61.515065 45.793980 -61.532408 45.833242 -61.540641 45.863422 -61.555060 45.907911 -61.562546 45.941468 -61.564232 46.022697 -61.595111 46.036654 -61.575489 46.045406 -61.551320 46.052222 -61.515187 46.052853 -61.488434 46.055037 -61.455367 46.064862 -61.451486 46.075678 -61.468167 46.091116 -61.510668 46.104307 -61.517727 46.146728 -61.489759 46.174397 -61.455676 46.196198 -61.414895 46.214349 -61.368367 46.234559 -61.333845 46.293343 -61.270789 46.394972 -61.186759 46.426311 -61.152403 46.447362 -61.143556 46.510783 -61.106129 46.574395 -61.063193 46.589967 -61.065977 46.614909 -61.091959 46.622603 -61.081372 46.627500 -61.062069 46.622583 -61.041222 46.629678 -61.023032 46.646978 -61.013984 46.657512 -61.012199 46.737777 -60.952173 46.784059 -60.912506 46.799340 -60.891249 46.812564 -60.858021 46.838805 -60.807653 46.883813 -60.752476 46.939790 -60.708400 46.976042 -60.683312 47.006882 -60.675484 47.016681 -60.665906 47.026816 -60.634462 47.025765 -60.608189 47.017567 -60.543319 46.996989 -60.514337 46.994169 -60.500086 47.001841 -60.483802 47.027437 -60.471435 47.031525 -60.444116 47.023340 -60.430751 47.013703 -60.423989 47.000272 -60.428005 46.979701 -60.455909 46.963151 -60.467506 46.942231 -60.465911 46.927854 -60.473165 46.917662 -60.515443 46.900315 -60.524813 46.893814 -60.510474 46.894074 -60.483257 46.885413 -60.456857 46.856580 -60.430963 46.853060 -60.409033 46.857226 -60.370964 46.841740 -60.352079 46.818636 -60.343976 46.799943 -60.343533 46.784093 -60.357258 46.731037 -60.353887 46.685033 -60.388635 46.671343 -60.414318 46.652557 -60.419369 46.652092 -60.400910 46.645606 -60.381215 46.636579 -60.381992 46.627395 -60.399203 46.616098 -60.409798 46.605166 -60.382381 46.588778 -60.377669 46.557171 -60.399625 46.538904 -60.428453 46.512512 -60.449424 46.498315 -60.451219 46.402727 -60.514638 46.383090 -60.533548 46.362662 -60.561054 46.352066 -60.568243 46.335667 -60.568906 46.310018 -60.586506 46.299584 -60.588312 46.279313 -60.599619 46.269887 -60.632652 46.260672 -60.649667 46.247406 -60.642843 46.224879 -60.652912 46.213036 -60.645026 46.210245 -60.631019 46.216372 -60.616069 46.254031 -60.590291 46.301008 -60.536708 46.317713 -60.514524 46.330057 -60.479319 46.304009 -60.473241 46.295010 -60.479521 46.275389 -60.498401 46.263191 -60.517436 46.227762 -60.544368 46.194306 -60.594006 46.103301 -60.703922 46.092472 -60.732477 46.091743 -60.780770 46.076384 -60.812387 46.061390 -60.862199 46.057978 -60.891033 46.072301 -60.923663 46.066682 -60.945906 46.053207 -60.949743 46.034214 -60.970530 46.024319 -60.985101 45.990020 -61.026588 45.972260 -61.056897 45.955900 -61.096924 45.949285 -61.132870 45.942888 -61.152982 45.928641 -61.159899 45.926780 -61.142735 45.930269 -61.114003 45.947948 -61.044268 45.954245 -61.024203 45.959242 -60.994440 45.970819 -60.973451 45.980190 -60.951350 45.998033 -60.949889 46.011382 -60.956812 46.030755 -60.909348 46.031753 -60.895468 46.019571 -60.869352 46.024994 -60.852458 46.046490 -60.816726 46.048559 -60.778188 46.038101 -60.780111 46.006097 -60.822860 45.980558 -60.840227 45.947690 -60.841299 45.934522 -60.873885 45.917843 -60.935257 45.922481 -60.966344 45.919038 -60.995079 45.901511 -61.059535 45.884264 -61.102601 45.847108 -61.135193 45.843043 -61.116957 45.851666 -61.092804 45.864284 -61.058067 45.865436 -61.033524 45.885703 -61.027991 45.892059 -61.002590 45.876475 -60.960393 45.867581 -60.955792 45.856547 -60.989557 45.835202 -60.974943 45.825971 -60.991547 45.827623 -61.024623 45.815209 -61.054032 45.787550 -61.098679 45.762742 -61.152042 45.740520 -61.179832 45.738664 -61.162740 45.724764 -61.148356 45.714587 -61.173426 45.694994 -61.186525 45.688774 -61.161798 45.696384 -61.117462 45.705184 -61.082816 45.719034 -61.057724 45.734323 -61.037132 45.751419 -60.999423 45.757106 -60.971998 45.744260 -60.893939 45.735813 -60.862792 45.721943 -60.848441 45.707052 -60.848053 45.685106 -60.870666 45.664049 -60.884717 45.649954 -60.881009 @@ -123,15 +123,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 47.25507 -61.75096 - 47.28211 -61.71983 + 47.255073 -61.750964 + 47.282116 -61.719830 - 47.25839 -61.74889 47.27555 -61.75096 47.28211 -61.73032 47.26959 -61.71983 47.25507 -61.73219 47.25839 -61.74889 + 47.258394 -61.748897 47.275550 -61.750964 47.282116 -61.730322 47.269593 -61.719830 47.255073 -61.732191 47.258394 -61.748897 @@ -144,15 +144,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 45.56706 -60.89735 - 46.26194 -59.82000 + 45.567064 -60.897351 + 46.261946 -59.820005 - 45.64995 -60.88100 45.65334 -60.85788 45.66020 -60.84534 45.67380 -60.83094 45.68701 -60.79847 45.69923 -60.77975 45.70884 -60.78105 45.73321 -60.79358 45.76006 -60.79121 45.77727 -60.78225 45.82475 -60.69757 45.84729 -60.68225 45.85917 -60.63459 45.90925 -60.56356 45.93950 -60.52700 45.95351 -60.48027 45.96348 -60.46029 45.97695 -60.45093 45.99023 -60.46314 45.94376 -60.60076 45.92884 -60.60565 45.89439 -60.72412 45.89550 -60.74447 45.90717 -60.76295 45.91857 -60.79750 45.92054 -60.81475 45.92940 -60.81922 45.95427 -60.79976 46.02271 -60.66074 46.09125 -60.55036 46.10734 -60.51539 46.12786 -60.48807 46.14975 -60.46504 46.17784 -60.41634 46.19925 -60.37498 46.21365 -60.35160 46.23167 -60.33912 46.24375 -60.32012 46.26194 -60.29684 46.24950 -60.27082 46.23171 -60.25635 46.21606 -60.25394 46.20099 -60.26973 46.17902 -60.30897 46.16101 -60.32145 46.15207 -60.31694 46.14923 -60.30298 46.16001 -60.27422 46.15336 -60.26011 46.13782 -60.25224 46.13124 -60.23286 46.13521 -60.21687 46.14125 -60.20728 46.15314 -60.20964 46.16640 -60.22711 46.17748 -60.23273 46.20890 -60.22695 46.21941 -60.21959 46.23295 -60.20482 46.24441 -60.17819 46.24760 -60.14918 46.24490 -60.11902 46.23770 -60.08663 46.23102 -60.07793 46.21369 -60.10342 46.20027 -60.09673 46.19739 -60.08276 46.20503 -60.05600 46.20450 -60.03234 46.18480 -59.96880 46.18603 -59.88506 46.18247 -59.85804 46.16907 -59.84614 46.16019 -59.84706 46.15476 -59.88034 46.14507 -59.88451 46.13232 -59.88538 46.11727 -59.91733 46.10226 -59.93860 46.09331 -59.93418 46.08968 -59.91805 46.09727 -59.89672 46.10553 -59.88287 46.11912 -59.85728 46.10500 -59.84858 46.09673 -59.85705 46.06371 -59.89640 46.04947 -59.91967 46.03189 -59.97722 46.01846 -59.98673 46.00824 -59.95654 46.00692 -59.92020 45.99378 -59.88152 45.98035 -59.87493 45.95602 -59.83086 45.94492 -59.82000 45.92699 -59.83261 45.93342 -59.88397 45.92194 -59.93191 45.91221 -59.94668 45.90382 -59.96578 45.90805 -60.01066 45.88187 -60.02632 45.87281 -60.04850 45.87040 -60.06338 45.86898 -60.15724 45.86421 -60.18692 45.85525 -60.19320 45.84632 -60.18875 45.83313 -60.16617 45.81987 -60.15420 45.81394 -60.14241 45.81338 -60.12419 45.80450 -60.11452 45.79102 -60.12383 45.78045 -60.14708 45.76964 -60.19157 45.76788 -60.21385 45.78264 -60.23014 45.78029 -60.24492 45.73712 -60.24305 45.72809 -60.25453 45.71524 -60.27655 45.70017 -60.29750 45.69478 -60.31440 45.70188 -60.34644 45.69266 -60.36852 45.65803 -60.40809 45.64129 -60.44055 45.61741 -60.56182 45.60196 -60.66423 45.59346 -60.68833 45.57752 -60.70696 45.56976 -60.72790 45.56706 -60.75852 45.56972 -60.78298 45.59474 -60.79756 45.60111 -60.81685 45.60145 -60.84547 45.61197 -60.88300 45.62964 -60.89735 45.64995 -60.88100 + 45.649954 -60.881009 45.653348 -60.857881 45.660202 -60.845348 45.673801 -60.830945 45.687014 -60.798470 45.699239 -60.779757 45.708848 -60.781056 45.733215 -60.793583 45.760063 -60.791213 45.777275 -60.782252 45.824757 -60.697572 45.847293 -60.682257 45.859173 -60.634593 45.909256 -60.563568 45.939505 -60.527009 45.953515 -60.480278 45.963481 -60.460290 45.976959 -60.450935 45.990237 -60.463145 45.943763 -60.600767 45.928847 -60.605653 45.894394 -60.724121 45.895501 -60.744475 45.907176 -60.762954 45.918574 -60.797500 45.920545 -60.814756 45.929405 -60.819227 45.954272 -60.799765 46.022713 -60.660742 46.091252 -60.550360 46.107347 -60.515399 46.127860 -60.488072 46.149753 -60.465043 46.177842 -60.416341 46.199254 -60.374984 46.213654 -60.351604 46.231677 -60.339127 46.243759 -60.320120 46.261946 -60.296847 46.249504 -60.270825 46.231712 -60.256352 46.216066 -60.253943 46.200990 -60.269738 46.179029 -60.308979 46.161015 -60.321453 46.152077 -60.316949 46.149237 -60.302985 46.160010 -60.274222 46.153368 -60.260117 46.137822 -60.252248 46.131241 -60.232867 46.135212 -60.216871 46.141252 -60.207283 46.153147 -60.209646 46.166404 -60.227119 46.177483 -60.232739 46.208901 -60.226953 46.219419 -60.219598 46.232951 -60.204821 46.244419 -60.178196 46.247609 -60.149187 46.244900 -60.119022 46.237705 -60.086630 46.231023 -60.077933 46.213696 -60.103429 46.200270 -60.096734 46.197396 -60.082767 46.205031 -60.056007 46.204502 -60.032340 46.184803 -59.968802 46.186039 -59.885068 46.182471 -59.858046 46.169072 -59.846142 46.160191 -59.847065 46.154762 -59.880343 46.145079 -59.884513 46.132328 -59.885385 46.117277 -59.917339 46.102265 -59.938602 46.093312 -59.934184 46.089685 -59.918056 46.097270 -59.896725 46.105537 -59.882871 46.119122 -59.857286 46.105000 -59.848584 46.096735 -59.857056 46.063717 -59.896406 46.049471 -59.919675 46.031898 -59.977221 46.018465 -59.986731 46.008241 -59.956545 46.006928 -59.920202 45.993781 -59.881526 45.980353 -59.874931 45.956021 -59.830867 45.944922 -59.820005 45.926994 -59.832615 45.933429 -59.883977 45.921940 -59.931918 45.912216 -59.946681 45.903823 -59.965788 45.908050 -60.010660 45.881877 -60.026323 45.872811 -60.048501 45.870409 -60.063386 45.868986 -60.157242 45.864219 -60.186927 45.855255 -60.193201 45.846324 -60.188756 45.833138 -60.166170 45.819875 -60.154201 45.813947 -60.142413 45.813383 -60.124199 45.804507 -60.114525 45.791027 -60.123836 45.780453 -60.147087 45.769647 -60.191574 45.767880 -60.213850 45.782649 -60.230146 45.780293 -60.244922 45.737125 -60.243052 45.728097 -60.254532 45.715241 -60.276556 45.700171 -60.297503 45.694783 -60.314407 45.701880 -60.346441 45.692668 -60.368529 45.658030 -60.408093 45.641293 -60.440550 45.617419 -60.561824 45.601961 -60.664237 45.593461 -60.688338 45.577521 -60.706965 45.569765 -60.727909 45.567064 -60.758520 45.569728 -60.782985 45.594741 -60.797560 45.601111 -60.816855 45.601459 -60.845476 45.611974 -60.883004 45.629648 -60.897351 45.649954 -60.881009 @@ -165,15 +165,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 46.06863 -60.68255 - 46.31432 -60.31030 + 46.068634 -60.682556 + 46.314326 -60.310302 - 46.06863 -60.68255 46.08885 -60.67673 46.10483 -60.64716 46.12309 -60.62409 46.16235 -60.58655 46.18281 -60.55930 46.19817 -60.52745 46.24352 -60.48030 46.28600 -60.41893 46.30881 -60.38181 46.31432 -60.35396 46.30346 -60.32144 46.28490 -60.31030 46.27137 -60.31965 46.25853 -60.33662 46.22822 -60.38428 46.22655 -60.40142 46.21560 -60.44629 46.20563 -60.46640 46.18823 -60.48632 46.16847 -60.51602 46.15544 -60.54347 46.11291 -60.60454 46.08640 -60.63586 46.07193 -60.65908 46.06863 -60.68255 + 46.068634 -60.682556 46.088853 -60.676730 46.104831 -60.647161 46.123091 -60.624097 46.162354 -60.586559 46.182819 -60.559300 46.198173 -60.527452 46.243529 -60.480305 46.286000 -60.418937 46.308813 -60.381812 46.314326 -60.353962 46.303460 -60.321443 46.284901 -60.310302 46.271372 -60.319652 46.258539 -60.336627 46.228226 -60.384283 46.226558 -60.401420 46.215606 -60.446297 46.205633 -60.466402 46.188232 -60.486328 46.168474 -60.516022 46.155447 -60.543472 46.112917 -60.604540 46.086404 -60.635868 46.071938 -60.659084 46.068634 -60.682556 @@ -186,15 +186,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 45.99438 -59.79193 - 46.03927 -59.70969 + 45.994384 -59.791931 + 46.039276 -59.709694 - 46.01509 -59.79193 46.02419 -59.75353 46.03767 -59.73340 46.03927 -59.71086 46.02584 -59.70969 46.01534 -59.72240 46.00193 -59.73199 45.99438 -59.74793 46.00099 -59.77262 46.01509 -59.79193 + 46.015090 -59.791931 46.024191 -59.753530 46.037672 -59.733403 46.039276 -59.710864 46.025845 -59.709694 46.015344 -59.722409 46.001939 -59.731993 45.994384 -59.747931 46.000997 -59.772623 46.015090 -59.791931 @@ -207,15 +207,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 45.94981 -64.46414 - 47.04029 -62.02064 + 45.949816 -64.464145 + 47.040290 -62.020645 - 46.05449 -62.49785 46.03300 -62.51661 46.03496 -62.54687 46.03418 -62.56822 46.01993 -62.59284 46.00804 -62.58991 46.00032 -62.57651 46.00641 -62.53083 45.99318 -62.52344 45.97949 -62.53216 45.97084 -62.54547 45.96509 -62.60380 45.96535 -62.65834 45.96788 -62.69069 45.96525 -62.72362 45.94981 -62.81665 45.95738 -62.85356 45.96981 -62.90060 46.01432 -62.96416 46.02739 -62.97164 46.03527 -62.96152 46.04687 -62.95184 46.05736 -62.96876 46.05764 -62.99982 46.05421 -63.03072 46.05771 -63.05459 46.07126 -63.05139 46.08628 -62.99262 46.08952 -62.96708 46.10718 -62.93528 46.12845 -62.92728 46.15073 -62.92913 46.13597 -62.98272 46.13822 -63.00223 46.16316 -62.99459 46.17719 -62.99902 46.18459 -63.01799 46.17762 -63.04315 46.18334 -63.06840 46.18772 -63.10753 46.19211 -63.12829 46.20656 -63.14030 46.22212 -63.12550 46.27070 -63.05104 46.29941 -63.04367 46.30030 -63.05891 46.28759 -63.09549 46.27158 -63.12119 46.24536 -63.14260 46.23740 -63.15262 46.24111 -63.17131 46.25563 -63.18329 46.26368 -63.20442 46.26080 -63.21936 46.25223 -63.22722 46.24260 -63.22526 46.22598 -63.21199 46.21019 -63.21382 46.20361 -63.22828 46.20099 -63.27429 46.19150 -63.30365 46.18228 -63.30922 46.17531 -63.29791 46.17312 -63.27837 46.19427 -63.20265 46.18969 -63.18729 46.18006 -63.18534 46.15991 -63.20295 46.15113 -63.23438 46.13884 -63.26024 46.13390 -63.28661 46.14330 -63.33047 46.16053 -63.43205 46.17750 -63.50244 46.19774 -63.58400 46.19962 -63.64017 46.20814 -63.68197 46.23691 -63.73756 46.28649 -63.80939 46.33444 -63.86938 46.34244 -63.85935 46.34656 -63.83600 46.33888 -63.80931 46.32768 -63.77688 46.33286 -63.76332 46.34335 -63.76227 46.35211 -63.76748 46.36418 -63.79679 46.38352 -63.81385 46.39061 -63.83841 46.38063 -63.90436 46.37893 -63.92367 46.39813 -63.95921 46.40044 -63.98653 46.37680 -64.01103 46.37019 -64.03842 46.37503 -64.07468 46.38964 -64.12604 46.39031 -64.14121 46.39781 -64.15499 46.41500 -64.17090 46.43082 -64.16940 46.46046 -64.14670 46.49174 -64.14906 46.52248 -64.16217 46.53946 -64.13912 46.55044 -64.11418 46.55694 -64.10517 46.57056 -64.10227 46.59207 -64.12093 46.61190 -64.12745 46.61724 -64.14003 46.60962 -64.15763 46.58238 -64.16341 46.57779 -64.17913 46.61318 -64.31790 46.61451 -64.34851 46.60631 -64.40302 46.61293 -64.43312 46.62658 -64.45650 46.64493 -64.46414 46.67128 -64.46185 46.71435 -64.44175 46.75799 -64.39782 46.78555 -64.36052 46.83038 -64.30775 46.84767 -64.29231 46.88736 -64.26616 46.91546 -64.24409 46.94013 -64.20313 46.98252 -64.12227 47.00040 -64.09578 47.02237 -64.07732 47.03708 -64.05263 47.04029 -64.01891 47.02471 -64.01510 46.98389 -64.03687 46.95782 -64.04729 46.94355 -64.04793 46.91516 -64.03057 46.87944 -64.02561 46.86398 -64.03495 46.81703 -64.07364 46.78037 -64.11655 46.75734 -64.16966 46.73816 -64.17838 46.73523 -64.14872 46.72435 -64.14193 46.70418 -64.14089 46.68983 -64.12841 46.68738 -64.08788 46.69701 -64.09004 46.70486 -64.09841 46.71806 -64.08791 46.72050 -64.07069 46.70947 -64.05100 46.71032 -64.03470 46.70525 -64.01677 46.65562 -63.97555 46.64149 -63.95769 46.63139 -63.93486 46.62267 -63.92970 46.61035 -63.93707 46.59878 -63.97280 46.58828 -63.97380 46.58138 -63.96228 46.58758 -63.92702 46.58126 -63.91769 46.55423 -63.90507 46.54220 -63.90713 46.52649 -63.92176 46.50028 -63.98185 46.47410 -64.01052 46.45832 -64.01218 46.45479 -63.99334 46.46916 -63.97424 46.48546 -63.94885 46.49643 -63.92401 46.50171 -63.89213 46.49634 -63.87962 46.48355 -63.86637 46.45011 -63.87591 46.44437 -63.85582 46.44131 -63.82626 46.43386 -63.79409 46.43759 -63.76309 46.45300 -63.75375 46.47420 -63.76460 46.49446 -63.77866 46.51448 -63.76649 46.52736 -63.77966 46.53592 -63.77193 46.54827 -63.73305 46.55956 -63.71573 46.55623 -63.69154 46.54316 -63.63376 46.52821 -63.60085 46.51505 -63.56161 46.50260 -63.55604 46.49096 -63.56578 46.47088 -63.59637 46.45685 -63.59172 46.45387 -63.57518 46.46538 -63.55255 46.47224 -63.53262 46.46525 -63.52109 46.45420 -63.50160 46.48146 -63.47709 46.50251 -63.47478 46.48195 -63.39814 46.47459 -63.36069 46.45773 -63.35262 46.43510 -63.37434 46.42108 -63.36977 46.42447 -63.34417 46.43418 -63.30925 46.42720 -63.29787 46.40922 -63.29845 46.39833 -63.29204 46.39457 -63.27333 46.40117 -63.25882 46.41389 -63.24038 46.41901 -63.20842 46.39981 -63.13111 46.39494 -63.10258 46.38131 -63.08737 46.36004 -63.07687 46.35613 -63.06356 46.36376 -63.04057 46.39313 -63.03545 46.40611 -63.04837 46.41392 -63.01994 46.42362 -62.92441 46.41825 -62.88830 46.41012 -62.86716 46.42232 -62.84103 46.42356 -62.80877 46.42151 -62.78366 46.39836 -62.70087 46.39776 -62.65652 46.40681 -62.63237 46.41728 -62.63105 46.42434 -62.64231 46.42598 -62.70189 46.44281 -62.75185 46.45509 -62.74410 46.45609 -62.71713 46.45420 -62.64461 46.45599 -62.61447 46.45519 -62.55163 46.46069 -62.45581 46.45046 -62.40418 46.46057 -62.27614 46.46030 -62.18637 46.45583 -62.13635 46.44685 -62.08925 46.44837 -62.03535 46.43832 -62.02064 46.42853 -62.02436 46.42149 -62.03693 46.40243 -62.09951 46.39315 -62.11077 46.37680 -62.15835 46.35884 -62.18298 46.33741 -62.22590 46.33344 -62.25475 46.33598 -62.26889 46.35451 -62.29926 46.35397 -62.31547 46.34277 -62.33836 46.34223 -62.37825 46.33187 -62.39808 46.32133 -62.39952 46.30834 -62.38675 46.29917 -62.39252 46.29419 -62.40623 46.28577 -62.41419 46.27100 -62.40786 46.25712 -62.42197 46.25083 -62.45491 46.25577 -62.48323 46.24696 -62.50204 46.23821 -62.49703 46.23211 -62.47728 46.22151 -62.46040 46.21016 -62.46497 46.20525 -62.47859 46.20666 -62.50120 46.20137 -62.52566 46.21144 -62.55862 46.21186 -62.58979 46.19803 -62.59848 46.18918 -62.57524 46.17115 -62.55773 46.16533 -62.57453 46.17215 -62.61489 46.15876 -62.61284 46.14410 -62.58270 46.13099 -62.57532 46.11070 -62.55671 46.11585 -62.53769 46.13048 -62.52585 46.13383 -62.51322 46.12985 -62.50002 46.12040 -62.49295 46.10478 -62.48965 46.07229 -62.50233 46.05449 -62.49785 + 46.054498 -62.497853 46.033009 -62.516619 46.034969 -62.546876 46.034185 -62.568223 46.019937 -62.592840 46.008042 -62.589912 46.000325 -62.576516 46.006410 -62.530834 45.993184 -62.523441 45.979499 -62.532164 45.970843 -62.545473 45.965091 -62.603808 45.965352 -62.658349 45.967882 -62.690694 45.965250 -62.723626 45.949816 -62.816659 45.957382 -62.853567 45.969811 -62.900600 46.014321 -62.964168 46.027392 -62.971646 46.035279 -62.961529 46.046873 -62.951842 46.057369 -62.968766 46.057648 -62.999822 46.054216 -63.030723 46.057714 -63.054591 46.071269 -63.051393 46.086286 -62.992627 46.089526 -62.967081 46.107189 -62.935281 46.128452 -62.927287 46.150730 -62.929130 46.135973 -62.982728 46.138221 -63.002237 46.163160 -62.994596 46.177192 -62.999021 46.184592 -63.017998 46.177627 -63.043154 46.183344 -63.068409 46.187720 -63.107538 46.192119 -63.128290 46.206565 -63.140303 46.222121 -63.125505 46.270708 -63.051049 46.299412 -63.043678 46.300308 -63.058910 46.287596 -63.095490 46.271586 -63.121191 46.245364 -63.142606 46.237407 -63.152626 46.241110 -63.171313 46.255632 -63.183296 46.263682 -63.204428 46.260804 -63.219364 46.252232 -63.227222 46.242600 -63.225263 46.225987 -63.211993 46.210199 -63.213825 46.203611 -63.228284 46.200994 -63.274298 46.191505 -63.303653 46.182283 -63.309223 46.175313 -63.297912 46.173128 -63.278372 46.194270 -63.202654 46.189697 -63.187290 46.180067 -63.185341 46.159917 -63.202955 46.151138 -63.234386 46.138843 -63.260244 46.133907 -63.286612 46.143304 -63.330474 46.160531 -63.432051 46.177506 -63.502449 46.197742 -63.584001 46.199628 -63.640178 46.208142 -63.681971 46.236919 -63.737564 46.286497 -63.809399 46.334449 -63.869384 46.342445 -63.859358 46.346565 -63.836008 46.338888 -63.809314 46.327684 -63.776887 46.332864 -63.763324 46.343350 -63.762274 46.352112 -63.767488 46.364183 -63.796795 46.383525 -63.813856 46.390611 -63.838414 46.380632 -63.904361 46.378939 -63.923678 46.398136 -63.959215 46.400448 -63.986533 46.376808 -64.011034 46.370193 -64.038420 46.375031 -64.074682 46.389642 -64.126048 46.390315 -64.141215 46.397813 -64.154999 46.415006 -64.170902 46.430825 -64.169409 46.460465 -64.146706 46.491741 -64.149067 46.522481 -64.162178 46.539466 -64.139121 46.550449 -64.114182 46.556940 -64.105176 46.570560 -64.102270 46.592070 -64.120931 46.611908 -64.127459 46.617249 -64.140038 46.609627 -64.157637 46.582380 -64.163417 46.577798 -64.179131 46.613188 -64.317908 46.614512 -64.348516 46.606312 -64.403024 46.612939 -64.433122 46.626583 -64.456507 46.644936 -64.464145 46.671283 -64.461857 46.714357 -64.441755 46.757994 -64.397820 46.785550 -64.360527 46.830383 -64.307757 46.847672 -64.292318 46.887364 -64.266167 46.915461 -64.244092 46.940137 -64.203137 46.982520 -64.122270 47.000404 -64.095781 47.022379 -64.077323 47.037086 -64.052631 47.040290 -64.018913 47.024716 -64.015106 46.983890 -64.036878 46.957826 -64.047295 46.943557 -64.047934 46.915161 -64.030578 46.879442 -64.025612 46.863982 -64.034953 46.817032 -64.073642 46.780374 -64.116557 46.757340 -64.169663 46.738162 -64.178386 46.735239 -64.148720 46.724353 -64.141930 46.704180 -64.140894 46.689835 -64.128411 46.687388 -64.087880 46.697019 -64.090049 46.704860 -64.098410 46.718069 -64.087913 46.720505 -64.070690 46.709478 -64.051006 46.710329 -64.034703 46.705255 -64.016772 46.655620 -63.975558 46.641494 -63.957699 46.631394 -63.934867 46.622672 -63.929701 46.610356 -63.937076 46.598780 -63.972803 46.588280 -63.973809 46.581380 -63.962288 46.587583 -63.927028 46.581268 -63.917692 46.554234 -63.905079 46.542200 -63.907131 46.526499 -63.921762 46.500282 -63.981854 46.474104 -64.010522 46.458326 -64.012189 46.454791 -63.993340 46.469160 -63.974246 46.485464 -63.948859 46.496434 -63.924018 46.501716 -63.892139 46.496345 -63.879622 46.483556 -63.866370 46.450111 -63.875915 46.444379 -63.855825 46.441315 -63.826265 46.433860 -63.794095 46.437597 -63.763099 46.453001 -63.753753 46.474204 -63.764601 46.494465 -63.778660 46.514486 -63.766496 46.527369 -63.779668 46.535920 -63.771930 46.548278 -63.733054 46.559566 -63.715735 46.556233 -63.691543 46.543164 -63.633768 46.528218 -63.600859 46.515051 -63.561613 46.502601 -63.556045 46.490962 -63.565786 46.470880 -63.596370 46.456858 -63.591722 46.453879 -63.575188 46.465388 -63.552552 46.472247 -63.532627 46.465254 -63.521092 46.454201 -63.501600 46.481461 -63.477090 46.502518 -63.474781 46.481952 -63.398141 46.474591 -63.360699 46.457736 -63.352620 46.435109 -63.374347 46.421080 -63.369776 46.424473 -63.344178 46.434183 -63.309251 46.427205 -63.297872 46.409225 -63.298454 46.398337 -63.292042 46.394577 -63.273336 46.401178 -63.258821 46.413898 -63.240388 46.419019 -63.208424 46.399810 -63.131116 46.394945 -63.102581 46.381319 -63.087375 46.360047 -63.076879 46.356138 -63.063563 46.363768 -63.040575 46.393137 -63.035454 46.406117 -63.048375 46.413929 -63.019940 46.423626 -62.924414 46.418257 -62.888309 46.410129 -62.867161 46.422327 -62.841034 46.423561 -62.808771 46.421516 -62.783660 46.398364 -62.700871 46.397763 -62.656523 46.406815 -62.632373 46.417289 -62.631052 46.424349 -62.642319 46.425988 -62.701897 46.442812 -62.751851 46.455099 -62.744108 46.456091 -62.717133 46.454205 -62.644615 46.455991 -62.614477 46.455193 -62.551633 46.460698 -62.455812 46.450468 -62.404184 46.460575 -62.276147 46.460303 -62.186376 46.455833 -62.136351 46.446856 -62.089255 46.448370 -62.035351 46.438320 -62.020645 46.428533 -62.024368 46.421493 -62.036934 46.402437 -62.099510 46.393152 -62.110777 46.376801 -62.158351 46.358849 -62.182987 46.337410 -62.225901 46.333443 -62.254756 46.335985 -62.268898 46.354512 -62.299267 46.353970 -62.315470 46.342773 -62.338367 46.342230 -62.378254 46.331875 -62.398082 46.321331 -62.399522 46.308342 -62.386752 46.299171 -62.392525 46.294195 -62.406236 46.285771 -62.414197 46.271001 -62.407866 46.257120 -62.421972 46.250834 -62.454916 46.255776 -62.483236 46.246966 -62.502043 46.238215 -62.497031 46.232112 -62.477283 46.221517 -62.460409 46.210160 -62.464978 46.205252 -62.478590 46.206668 -62.501200 46.201371 -62.525663 46.211445 -62.558629 46.211864 -62.589790 46.198039 -62.598486 46.189188 -62.575245 46.171155 -62.557735 46.165337 -62.574532 46.172150 -62.614894 46.158763 -62.612840 46.144102 -62.582703 46.130992 -62.575321 46.110703 -62.556716 46.115852 -62.537690 46.130485 -62.525851 46.133837 -62.513225 46.129850 -62.500027 46.120403 -62.492953 46.104789 -62.489650 46.072291 -62.502332 46.054498 -62.497853 @@ -228,15 +228,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 45.45817 -61.14640 - 45.57614 -60.90345 + 45.458170 -61.146404 + 45.576146 -60.903456 - 45.46158 -61.06156 45.47786 -61.06640 45.48613 -61.05833 45.49544 -61.04181 45.50863 -61.04863 45.50985 -61.06355 45.50627 -61.09722 45.53218 -61.14272 45.54621 -61.14640 45.55457 -61.13827 45.56531 -61.08149 45.57245 -61.05842 45.57127 -61.04359 45.56733 -61.01483 45.57614 -60.97494 45.57301 -60.94298 45.57287 -60.90910 45.56179 -60.90345 45.55114 -60.91575 45.54872 -60.93052 45.54585 -60.96632 45.53933 -60.99681 45.52582 -61.00591 45.49392 -60.99834 45.48174 -61.01685 45.46219 -61.02995 45.45817 -61.04557 45.46158 -61.06156 + 45.461588 -61.061562 45.477860 -61.066405 45.486135 -61.058336 45.495441 -61.041811 45.508633 -61.048638 45.509854 -61.063551 45.506274 -61.097225 45.532182 -61.142729 45.546215 -61.146404 45.554578 -61.138277 45.565318 -61.081499 45.572456 -61.058421 45.571279 -61.043595 45.567330 -61.014833 45.576146 -60.974940 45.573014 -60.942987 45.572876 -60.909103 45.561792 -60.903456 45.551148 -60.915757 45.548728 -60.930529 45.545854 -60.966328 45.539334 -60.996814 45.525826 -61.005913 45.493926 -60.998348 45.481743 -61.016851 45.462193 -61.029951 45.458170 -61.045573 45.461588 -61.061562 @@ -249,15 +249,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 45.47629 -60.97763 - 45.49487 -60.93785 + 45.476290 -60.977631 + 45.494872 -60.937854 - 45.47795 -60.97763 45.49304 -60.96764 45.49487 -60.94549 45.48687 -60.93785 45.47629 -60.94481 45.47795 -60.97763 + 45.477957 -60.977631 45.493045 -60.967647 45.494872 -60.945495 45.486875 -60.937854 45.476290 -60.944814 45.477957 -60.977631 @@ -270,15 +270,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 46.57850 -63.86379 - 46.62738 -63.77514 + 46.578504 -63.863796 + 46.627388 -63.775140 - 46.58244 -63.83307 46.60437 -63.85922 46.62738 -63.86379 46.62386 -63.84500 46.61144 -63.82089 46.59398 -63.77888 46.57850 -63.77514 46.57914 -63.80885 46.58244 -63.83307 + 46.582447 -63.833071 46.604373 -63.859226 46.627388 -63.863796 46.623862 -63.845001 46.611443 -63.820895 46.593980 -63.778884 46.578504 -63.775140 46.579144 -63.808857 46.582447 -63.833071 @@ -291,15 +291,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 43.44796 -66.23693 - 45.98282 -61.00979 + 43.447966 -66.236930 + 45.982824 -61.009794 - 45.98282 -63.99398 45.98180 -63.97255 45.97346 -63.94384 45.96122 -63.92012 45.89396 -63.83083 45.87592 -63.78724 45.85825 -63.72037 45.86714 -63.68913 45.87983 -63.62732 45.87865 -63.60473 45.86944 -63.56118 45.87440 -63.53489 45.86911 -63.48631 45.85676 -63.46277 45.84583 -63.45646 45.83942 -63.46541 45.82111 -63.55652 45.81303 -63.57177 45.80427 -63.56666 45.79739 -63.53724 45.80505 -63.48357 45.80718 -63.45384 45.80726 -63.41761 45.79490 -63.39412 45.79125 -63.37560 45.80320 -63.32444 45.80122 -63.29972 45.79518 -63.28534 45.78557 -63.28339 45.76781 -63.31482 45.75120 -63.38696 45.73480 -63.38646 45.71098 -63.33643 45.70724 -63.31801 45.71953 -63.31055 45.73484 -63.30120 45.73864 -63.26542 45.75980 -63.23957 45.76272 -63.22491 45.75395 -63.21987 45.74017 -63.22822 45.73340 -63.21169 45.73696 -63.19928 45.75028 -63.18334 45.75857 -63.14461 45.75246 -63.11212 45.75685 -63.09659 45.76997 -63.10400 45.77932 -63.12936 45.79508 -63.12752 45.80190 -63.10777 45.80052 -63.08530 45.79439 -63.05278 45.76828 -62.96013 45.76403 -62.91604 45.74080 -62.80350 45.72278 -62.76806 45.71416 -62.73969 45.71111 -62.70013 45.70256 -62.68980 45.68358 -62.69912 45.67409 -62.73348 45.67216 -62.80449 45.66638 -62.82101 45.64975 -62.80806 45.64508 -62.79281 45.62305 -62.80388 45.61233 -62.79238 45.60877 -62.76877 45.62633 -62.75528 45.62695 -62.73935 45.62009 -62.72294 45.61306 -62.71186 45.60862 -62.69125 45.61510 -62.67690 45.63113 -62.68768 45.63911 -62.71375 45.65501 -62.70644 45.66105 -62.68463 45.66790 -62.61820 45.65580 -62.60246 45.64634 -62.59533 45.64183 -62.57488 45.64230 -62.54095 45.62372 -62.53960 45.61282 -62.53349 45.60958 -62.51740 45.62082 -62.49475 45.62361 -62.43336 45.63128 -62.40525 45.64479 -62.40189 45.64952 -62.41710 45.64455 -62.45393 45.64554 -62.46892 45.65597 -62.46758 45.66413 -62.44691 45.68520 -62.35055 45.73170 -62.22491 45.77555 -62.13189 45.82272 -62.04964 45.84833 -62.01489 45.87034 -61.97469 45.87852 -61.94846 45.87605 -61.92912 45.86975 -61.91480 45.85935 -61.91639 45.84183 -61.95372 45.82378 -61.96019 45.78981 -61.95068 45.72754 -61.93850 45.70509 -61.94256 45.66417 -61.96886 45.64454 -61.97615 45.62855 -61.96568 45.62048 -61.93441 45.62461 -61.91871 45.65036 -61.93087 45.66246 -61.92310 45.66695 -61.89676 45.66447 -61.87751 45.65001 -61.86072 45.63377 -61.85557 45.62184 -61.85813 45.61247 -61.84594 45.61607 -61.82280 45.62771 -61.80752 45.62237 -61.75625 45.61959 -61.69035 45.62383 -61.66941 45.63155 -61.65915 45.63520 -61.63065 45.64580 -61.62372 45.65622 -61.62219 45.66409 -61.60670 45.66982 -61.58463 45.66704 -61.54734 45.62157 -61.45173 45.59688 -61.42623 45.57107 -61.41438 45.54499 -61.38453 45.53329 -61.37668 45.52451 -61.36671 45.51628 -61.33574 45.51526 -61.31543 45.50673 -61.29507 45.49091 -61.26892 45.47754 -61.26730 45.45254 -61.29161 45.43340 -61.31717 45.42126 -61.36414 45.40808 -61.38575 45.40266 -61.39704 45.39935 -61.44336 45.38924 -61.46299 45.38519 -61.47865 45.42257 -61.53212 45.43817 -61.56352 45.44194 -61.59224 45.43708 -61.61102 45.42669 -61.60731 45.41152 -61.56004 45.40226 -61.54278 45.37506 -61.53193 45.35316 -61.51502 45.33889 -61.48798 45.33220 -61.45603 45.33724 -61.43203 45.34266 -61.38694 45.34036 -61.35731 45.32795 -61.31351 45.32548 -61.28925 45.33680 -61.24547 45.33030 -61.19778 45.33272 -61.15463 45.32148 -61.12044 45.31824 -61.05503 45.30632 -61.01880 45.29232 -61.00979 45.27226 -61.01018 45.26901 -61.02263 45.28059 -61.04093 45.27738 -61.05348 45.26171 -61.05603 45.22863 -61.07796 45.20038 -61.11994 45.19370 -61.15534 45.19922 -61.17761 45.20723 -61.18535 45.23814 -61.16242 45.25015 -61.15975 45.26999 -61.17007 45.27557 -61.18709 45.27234 -61.19963 45.25577 -61.21041 45.22609 -61.20923 45.21254 -61.21809 45.22612 -61.24285 45.23449 -61.26843 45.23097 -61.29671 45.23421 -61.31781 45.23075 -61.34079 45.21891 -61.37180 45.19814 -61.40345 45.18478 -61.40180 45.17868 -61.37743 45.18625 -61.33881 45.17993 -61.31968 45.16446 -61.31690 45.15727 -61.33973 45.15030 -61.41918 45.14317 -61.43671 45.13658 -61.46679 45.13264 -61.50538 45.13866 -61.53512 45.13956 -61.56037 45.13450 -61.58425 45.13205 -61.62186 45.15088 -61.70262 45.14510 -61.72431 45.13670 -61.73225 45.12570 -61.69808 45.11580 -61.67871 45.10045 -61.69891 45.07100 -61.68688 45.06624 -61.70024 45.07645 -61.73745 45.06467 -61.78607 45.07760 -61.83187 45.07349 -61.84740 45.05860 -61.84658 45.04993 -61.86490 45.03882 -61.86434 45.02755 -61.86894 45.02041 -61.88629 45.03106 -61.90258 45.03586 -61.91753 45.02059 -61.93235 45.02452 -61.95044 45.04280 -61.98501 45.03191 -62.00217 45.02398 -61.99432 45.01089 -61.98729 45.00533 -61.99847 45.00426 -62.03500 44.99325 -62.08044 44.98755 -62.09685 44.97707 -62.07528 44.98071 -62.05248 44.97903 -62.03564 44.97357 -62.01852 44.96464 -62.01905 44.95846 -62.05118 44.95278 -62.14179 44.94374 -62.17040 44.93181 -62.19586 44.92592 -62.21738 44.93400 -62.24296 44.93551 -62.26504 44.92271 -62.29342 44.90400 -62.32044 44.89914 -62.33368 44.89982 -62.35880 44.89049 -62.36970 44.87994 -62.37628 44.87330 -62.39573 44.87717 -62.41363 44.87363 -62.43121 44.84306 -62.47807 44.84315 -62.49591 44.86694 -62.49651 44.87307 -62.51048 44.86885 -62.52587 44.85236 -62.53094 44.83951 -62.53628 44.83358 -62.55782 44.83718 -62.58101 44.79058 -62.57657 44.77825 -62.58930 44.78212 -62.60728 44.80154 -62.62324 44.80885 -62.64665 44.79649 -62.65936 44.78922 -62.67650 44.77248 -62.68679 44.76757 -62.69994 44.77417 -62.72133 44.77653 -62.75789 44.76252 -62.79435 44.76189 -62.80998 44.78592 -62.84098 44.78736 -62.86295 44.78390 -62.87523 44.77277 -62.87433 44.76249 -62.85268 44.74720 -62.84423 44.73490 -62.85682 44.70440 -62.83989 44.69509 -62.85058 44.69381 -62.86400 44.70733 -62.89626 44.70967 -62.93288 44.70576 -62.97315 44.69538 -63.00975 44.70107 -63.03418 44.72280 -63.04635 44.74501 -63.04814 44.76020 -63.05671 44.76789 -63.06976 44.75438 -63.09067 44.74200 -63.08544 44.71742 -63.06978 44.69085 -63.06554 44.67282 -63.07141 44.67174 -63.09732 44.69478 -63.11371 44.70894 -63.13055 44.73935 -63.12994 44.75113 -63.13309 44.75853 -63.15144 44.75070 -63.16107 44.69850 -63.16711 44.67951 -63.17592 44.67590 -63.19331 44.68607 -63.19727 44.71371 -63.19345 44.73372 -63.19402 44.73894 -63.21119 44.73000 -63.22912 44.68672 -63.23479 44.66773 -63.24357 44.67362 -63.26274 44.69491 -63.26771 44.70488 -63.27691 44.67769 -63.30580 44.65505 -63.29650 44.64529 -63.29980 44.63657 -63.31257 44.61282 -63.32925 44.62313 -63.38102 44.61778 -63.41691 44.62356 -63.43614 44.65330 -63.45125 44.66368 -63.46788 44.66446 -63.48247 44.65943 -63.49551 44.63660 -63.49131 44.60981 -63.46191 44.58642 -63.48578 44.58571 -63.50117 44.59608 -63.51778 44.60091 -63.55762 44.63726 -63.58915 44.64478 -63.60231 44.66100 -63.62047 44.67410 -63.64042 44.69605 -63.67790 44.69535 -63.69343 44.66208 -63.69034 44.64654 -63.67417 44.63098 -63.62804 44.62190 -63.61577 44.60901 -63.62077 44.59063 -63.60144 44.57791 -63.58882 44.55573 -63.58677 44.53772 -63.59225 44.52289 -63.59087 44.50667 -63.57277 44.48720 -63.56159 44.44753 -63.58491 44.44685 -63.60036 44.45305 -63.60928 44.45752 -63.62410 44.45312 -63.63924 44.43808 -63.64304 44.43063 -63.65988 44.43141 -63.67450 44.44660 -63.68316 44.45525 -63.71817 44.45063 -63.75089 44.45968 -63.76314 44.46569 -63.77711 44.45925 -63.81589 44.46373 -63.83084 44.48277 -63.83475 44.48701 -63.85491 44.47472 -63.89200 44.48965 -63.94844 44.49845 -63.96593 44.51482 -63.97897 44.53751 -63.97093 44.55452 -63.95603 44.57298 -63.95792 44.60447 -63.96739 44.61977 -63.95849 44.65636 -63.92477 44.65079 -63.96063 44.63595 -63.98932 44.61740 -64.06023 44.60528 -64.07973 44.59393 -64.08374 44.55639 -64.07766 44.52940 -64.08323 44.49535 -64.05276 44.48495 -64.05370 44.47587 -64.08387 44.45855 -64.10377 44.45250 -64.11974 44.46687 -64.15651 44.47975 -64.16407 44.50869 -64.16507 44.52937 -64.18073 44.54703 -64.21071 44.54838 -64.23993 44.52537 -64.25293 44.52456 -64.28092 44.53034 -64.33762 44.51628 -64.35060 44.47480 -64.34913 44.46594 -64.36166 44.44194 -64.35267 44.43244 -64.36316 44.42730 -64.38837 44.41049 -64.39789 44.39537 -64.38899 44.38954 -64.37492 44.39947 -64.34182 44.39822 -64.32512 44.38986 -64.31496 44.37393 -64.32151 44.36032 -64.28689 44.34709 -64.28443 44.33977 -64.29597 44.34792 -64.33618 44.33970 -64.36316 44.32714 -64.37528 44.31180 -64.37141 44.31042 -64.34239 44.31135 -64.32705 44.30147 -64.31760 44.27481 -64.33023 44.27750 -64.29649 44.27067 -64.28539 44.25617 -64.27874 44.24271 -64.29373 44.23489 -64.31555 44.24020 -64.33989 44.27832 -64.37290 44.28212 -64.38578 44.27078 -64.40196 44.25515 -64.40342 44.24504 -64.42395 44.22510 -64.43513 44.21816 -64.46632 44.14342 -64.52789 44.13246 -64.57603 44.12788 -64.65272 44.11774 -64.66090 44.10615 -64.63274 44.10730 -64.60004 44.09170 -64.58890 44.05398 -64.61235 44.04812 -64.62297 44.04815 -64.64765 44.04354 -64.66245 44.03253 -64.67357 44.02177 -64.70410 43.99448 -64.71426 43.96938 -64.72575 43.95921 -64.74608 43.94882 -64.75917 43.93924 -64.79397 43.92845 -64.82441 43.92440 -64.85363 43.90969 -64.87641 43.89497 -64.87475 43.88673 -64.86443 43.87792 -64.82763 43.85895 -64.81097 43.84917 -64.81390 43.84361 -64.83173 43.83652 -64.85022 43.82392 -64.86207 43.81659 -64.87349 43.82730 -64.89214 43.85113 -64.90117 43.86454 -64.93553 43.86138 -64.94948 43.85127 -64.95738 43.83387 -64.92772 43.79498 -64.93427 43.78760 -64.94556 43.79119 -64.95829 43.81939 -64.96988 43.83978 -64.98572 43.83825 -64.99877 43.82653 -65.00764 43.79084 -64.98793 43.77187 -64.98349 43.75190 -64.99431 43.75299 -65.02305 43.77348 -65.03894 43.78782 -65.04582 43.79722 -65.06021 43.79628 -65.07541 43.77604 -65.07903 43.73541 -65.05460 43.70107 -65.07075 43.68747 -65.09757 43.70421 -65.11294 43.71394 -65.12234 43.71027 -65.13411 43.67766 -65.15658 43.65194 -65.16558 43.64907 -65.18653 43.67104 -65.18936 43.69071 -65.18373 43.70074 -65.18805 43.69658 -65.21709 43.74845 -65.25026 43.75416 -65.26436 43.75276 -65.28460 43.73704 -65.29788 43.72761 -65.29571 43.70626 -65.28264 43.67931 -65.28741 43.65872 -65.29591 43.65134 -65.30721 43.65904 -65.33466 43.66729 -65.34496 43.67731 -65.34930 43.70611 -65.35103 43.71722 -65.37196 43.71375 -65.39087 43.70510 -65.39789 43.63207 -65.38321 43.61044 -65.37522 43.58270 -65.38992 43.56809 -65.38805 43.55214 -65.39411 43.54687 -65.40663 43.54237 -65.42832 43.54345 -65.44484 43.55832 -65.45397 43.56344 -65.46571 43.55586 -65.48923 43.53640 -65.48256 43.52313 -65.46048 43.51129 -65.44970 43.48813 -65.44260 43.47824 -65.44532 43.47026 -65.45440 43.48962 -65.47324 43.50357 -65.48527 43.49428 -65.50239 43.47135 -65.50238 43.45536 -65.50829 43.44796 -65.51952 43.46698 -65.54344 43.48540 -65.59672 43.51281 -65.60651 43.51808 -65.62554 43.51054 -65.64895 43.50030 -65.65670 43.48384 -65.67981 43.47641 -65.71037 43.47714 -65.73178 43.47214 -65.75852 43.47535 -65.77624 43.48442 -65.78356 43.49636 -65.78224 43.50864 -65.77584 43.51526 -65.78697 43.52557 -65.81780 43.53829 -65.82577 43.56683 -65.82054 43.59725 -65.80960 43.64235 -65.80059 43.65785 -65.81197 43.65828 -65.82637 43.64802 -65.83410 43.62969 -65.83150 43.61620 -65.83372 43.58846 -65.84809 43.61167 -65.87487 43.62592 -65.88198 43.68868 -65.88582 43.73416 -65.87178 43.76061 -65.88487 43.76645 -65.90605 43.76378 -65.92202 43.77616 -65.93516 43.79772 -65.94334 43.80644 -65.95584 43.80627 -65.96811 43.79757 -65.97504 43.78239 -65.97080 43.77157 -65.97644 43.76341 -65.98544 43.76873 -66.00467 43.77947 -66.01852 43.76236 -66.03957 43.73707 -66.01133 43.72270 -66.00411 43.71021 -66.00332 43.69475 -66.01126 43.68995 -66.02592 43.68902 -66.04822 43.67663 -66.05463 43.67469 -66.07988 43.68321 -66.08523 43.70291 -66.07988 43.70949 -66.09110 43.70503 -66.12007 43.71254 -66.12839 43.72660 -66.12843 43.74028 -66.13345 43.74065 -66.14789 43.74525 -66.16489 43.77534 -66.17866 43.78310 -66.19411 43.80715 -66.19872 43.83510 -66.21112 43.86042 -66.20059 43.87567 -66.20487 43.89113 -66.21644 43.92608 -66.19597 43.96184 -66.20442 44.00820 -66.20011 44.03735 -66.21679 44.07638 -66.23097 44.10258 -66.23693 44.13126 -66.23200 44.20379 -66.18721 44.23386 -66.17410 44.30255 -66.16062 44.32418 -66.14934 44.35965 -66.12352 44.37992 -66.10069 44.42467 -66.05019 44.46070 -65.98700 44.51464 -65.91161 44.53934 -65.89860 44.55647 -65.90943 44.56171 -65.92894 44.54913 -65.96773 44.55360 -65.99749 44.54844 -66.01761 44.49052 -66.08486 44.46748 -66.10429 44.42855 -66.15672 44.40139 -66.18063 44.39322 -66.18981 44.38020 -66.21386 44.38265 -66.22970 44.39639 -66.23493 44.41136 -66.22473 44.43520 -66.19517 44.45947 -66.16034 44.49450 -66.13957 44.50790 -66.11037 44.55523 -66.05608 44.58880 -65.96048 44.64573 -65.87399 44.65864 -65.83554 44.65646 -65.81444 44.64711 -65.79951 44.62691 -65.79037 44.59899 -65.78531 44.58066 -65.75042 44.58097 -65.72557 44.58903 -65.69648 44.61113 -65.66734 44.61984 -65.66023 44.64571 -65.63146 44.67242 -65.59973 44.69378 -65.56090 44.72362 -65.49510 44.73672 -65.47809 44.76169 -65.47204 44.76023 -65.49272 44.74588 -65.51793 44.71108 -65.61136 44.67711 -65.68179 44.65742 -65.75935 44.66061 -65.77742 44.67031 -65.78715 44.68073 -65.78660 44.69852 -65.76720 44.72203 -65.72988 44.75263 -65.66621 44.76981 -65.64450 44.80234 -65.56229 44.84323 -65.46533 44.88354 -65.39855 44.90961 -65.33175 44.94710 -65.26124 45.00895 -65.15701 45.03001 -65.13034 45.04845 -65.08748 45.07142 -65.04204 45.11271 -64.95375 45.12151 -64.92110 45.12617 -64.89322 45.14602 -64.82409 45.17173 -64.71874 45.23932 -64.47797 45.25713 -64.45254 45.27072 -64.44993 45.27998 -64.45728 45.29273 -64.48296 45.30356 -64.51488 45.31373 -64.53188 45.32760 -64.52401 45.31858 -64.47324 45.29403 -64.39344 45.28069 -64.37822 45.25664 -64.36918 45.22798 -64.38808 45.21080 -64.40293 45.18616 -64.41701 45.17445 -64.41360 45.15072 -64.39941 45.13776 -64.40424 45.11993 -64.42952 45.10884 -64.42834 45.09897 -64.41880 45.08993 -64.39362 45.09391 -64.37622 45.11173 -64.36345 45.11482 -64.34908 45.10663 -64.32086 45.07781 -64.27669 45.03940 -64.23045 45.01926 -64.21670 44.98571 -64.20579 44.97797 -64.19756 44.96879 -64.15990 44.96526 -64.12918 44.97100 -64.10569 44.98233 -64.10155 44.98913 -64.11285 44.99207 -64.12883 44.99311 -64.15099 45.00553 -64.16913 45.03010 -64.15497 45.05013 -64.16864 45.08091 -64.21921 45.10817 -64.23902 45.12606 -64.23883 45.16134 -64.21848 45.18648 -64.19387 45.19746 -64.16980 45.22368 -64.06825 45.24957 -63.94123 45.27200 -63.86450 45.29098 -63.81266 45.29823 -63.80069 45.29903 -63.78490 45.29673 -63.77100 45.30138 -63.73767 45.30873 -63.70782 45.30414 -63.67986 45.29536 -63.64425 45.30431 -63.56493 45.30070 -63.54660 45.27665 -63.52015 45.28169 -63.50694 45.29919 -63.49906 45.31374 -63.50567 45.32734 -63.48479 45.33963 -63.47745 45.35326 -63.48718 45.35714 -63.51817 45.35608 -63.55716 45.37664 -63.62666 45.37111 -63.68112 45.37329 -63.74367 45.38039 -63.78032 45.38066 -63.80573 45.35106 -63.90740 45.34666 -63.93541 45.35149 -63.95807 45.36191 -63.98778 45.36888 -64.01169 45.37179 -64.04062 45.37050 -64.06685 45.37214 -64.09132 45.38626 -64.12142 45.38764 -64.15119 45.38039 -64.17572 45.37898 -64.20201 45.38705 -64.21773 45.38808 -64.24008 45.38300 -64.26595 45.37286 -64.28704 45.36649 -64.30859 45.36182 -64.39260 45.35096 -64.46749 45.35349 -64.48896 45.37951 -64.55534 45.38817 -64.58607 45.39344 -64.63638 45.38603 -64.67370 45.37026 -64.71298 45.35334 -64.73528 45.31042 -64.76707 45.29802 -64.79942 45.29890 -64.82175 45.31432 -64.83837 45.33672 -64.87393 45.33916 -64.89541 45.33261 -64.91675 45.32197 -64.96832 45.32409 -64.98229 45.33549 -64.99114 45.39515 -64.95533 45.44814 -64.88242 45.46542 -64.86768 45.48930 -64.80586 45.50880 -64.76681 45.58019 -64.64480 45.64034 -64.54662 45.67697 -64.49236 45.70040 -64.47382 45.70971 -64.46839 45.73776 -64.44713 45.74940 -64.42498 45.76241 -64.42008 45.78065 -64.41473 45.78914 -64.36872 45.77766 -64.35994 45.75025 -64.38352 45.74067 -64.38133 45.73846 -64.36727 45.74667 -64.32662 45.76138 -64.31542 45.77608 -64.33524 45.78865 -64.32277 45.80810 -64.30890 45.80812 -64.30892 45.82397 -64.29481 45.94073 -64.19468 45.95318 -64.19255 45.96819 -64.08843 45.96807 -64.03141 45.97293 -63.99925 45.98157 -63.99453 45.98282 -63.99398 + 45.982824 -63.993981 45.981800 -63.972552 45.973465 -63.943849 45.961227 -63.920124 45.893962 -63.830838 45.875924 -63.787247 45.858253 -63.720376 45.867146 -63.689137 45.879832 -63.627321 45.878654 -63.604733 45.869442 -63.561186 45.874409 -63.534894 45.869112 -63.486319 45.856760 -63.462774 45.845831 -63.456461 45.839424 -63.465417 45.821112 -63.556528 45.813031 -63.571776 45.804278 -63.566664 45.797393 -63.537241 45.805055 -63.483571 45.807187 -63.453845 45.807268 -63.417617 45.794901 -63.394123 45.791251 -63.375605 45.803200 -63.324445 45.801224 -63.299722 45.795186 -63.285346 45.785574 -63.283394 45.767817 -63.314829 45.751205 -63.386961 45.734802 -63.386468 45.710981 -63.336435 45.707242 -63.318014 45.719538 -63.310557 45.734848 -63.301206 45.738647 -63.265429 45.759809 -63.239570 45.762725 -63.224911 45.753956 -63.219873 45.740177 -63.228224 45.733403 -63.211697 45.736964 -63.199286 45.750283 -63.183349 45.758571 -63.144611 45.752466 -63.112122 45.756850 -63.096592 45.769973 -63.104004 45.779324 -63.129369 45.795080 -63.127528 45.801906 -63.107777 45.800521 -63.085301 45.794393 -63.052788 45.768287 -62.960132 45.764032 -62.916041 45.740807 -62.803508 45.722785 -62.768060 45.714161 -62.739696 45.711119 -62.700136 45.702563 -62.689809 45.683580 -62.699127 45.674090 -62.733486 45.672162 -62.804496 45.666389 -62.821011 45.649759 -62.808063 45.645088 -62.792816 45.623055 -62.803887 45.612338 -62.792380 45.608779 -62.768774 45.626333 -62.755283 45.626951 -62.739351 45.620091 -62.722941 45.613067 -62.711863 45.608621 -62.691253 45.615108 -62.676908 45.631136 -62.687682 45.639114 -62.713757 45.655016 -62.706445 45.661051 -62.684637 45.667903 -62.618209 45.655802 -62.602460 45.646340 -62.595331 45.641832 -62.574887 45.642304 -62.540956 45.623728 -62.539609 45.612824 -62.533491 45.609589 -62.517404 45.620829 -62.494755 45.623613 -62.433363 45.631285 -62.405258 45.644792 -62.401894 45.649528 -62.417100 45.644550 -62.453931 45.645540 -62.468925 45.655977 -62.467588 45.664136 -62.446913 45.685203 -62.350552 45.731705 -62.224910 45.775551 -62.131894 45.822724 -62.049641 45.848330 -62.014899 45.870347 -61.974690 45.878520 -61.948466 45.876051 -61.929127 45.869751 -61.914804 45.859357 -61.916390 45.841830 -61.953724 45.823788 -61.960193 45.789817 -61.950686 45.727545 -61.938500 45.705095 -61.942567 45.664172 -61.968862 45.644547 -61.976155 45.628555 -61.965681 45.620481 -61.934417 45.624616 -61.918710 45.650368 -61.930870 45.662466 -61.923103 45.666954 -61.896760 45.664476 -61.877515 45.650015 -61.860723 45.633775 -61.855572 45.621841 -61.858131 45.612479 -61.845946 45.616073 -61.822804 45.627712 -61.807521 45.622370 -61.756256 45.619590 -61.690359 45.623830 -61.669410 45.631557 -61.659157 45.635205 -61.630659 45.645805 -61.623729 45.656229 -61.622194 45.664095 -61.606700 45.669821 -61.584633 45.667043 -61.547346 45.621572 -61.451732 45.596882 -61.426233 45.571071 -61.414382 45.544994 -61.384535 45.533294 -61.376683 45.524519 -61.366714 45.516288 -61.335744 45.515269 -61.315437 45.506739 -61.295070 45.490916 -61.268926 45.477543 -61.267307 45.452548 -61.291612 45.433402 -61.317174 45.421267 -61.364141 45.408084 -61.385753 45.402663 -61.397044 45.399352 -61.443365 45.389242 -61.462990 45.385190 -61.478656 45.422573 -61.532126 45.438174 -61.563522 45.441947 -61.592248 45.437086 -61.611029 45.426695 -61.607316 45.411520 -61.560044 45.402267 -61.542787 45.375068 -61.531938 45.353168 -61.515029 45.338890 -61.487987 45.332207 -61.456037 45.337242 -61.432031 45.342662 -61.386942 45.340369 -61.357315 45.327955 -61.313510 45.325482 -61.289255 45.336802 -61.245479 45.330303 -61.197786 45.332720 -61.154630 45.321487 -61.120444 45.318249 -61.055031 45.306325 -61.018809 45.292321 -61.009794 45.272262 -61.010186 45.269010 -61.022638 45.280596 -61.040931 45.277383 -61.053488 45.261714 -61.056036 45.228635 -61.077960 45.200386 -61.119941 45.193707 -61.155342 45.199221 -61.177617 45.207231 -61.185356 45.238140 -61.162429 45.250155 -61.159755 45.269991 -61.170070 45.275575 -61.187090 45.272343 -61.199638 45.255779 -61.210415 45.226096 -61.209233 45.212541 -61.218097 45.226123 -61.242859 45.234499 -61.268437 45.230971 -61.296710 45.234214 -61.317813 45.230755 -61.340798 45.218918 -61.371806 45.198140 -61.403458 45.184786 -61.401807 45.178683 -61.377439 45.186255 -61.338814 45.179932 -61.319686 45.164464 -61.316903 45.157275 -61.339733 45.150301 -61.419185 45.143174 -61.436717 45.136584 -61.466798 45.132646 -61.505386 45.138663 -61.535127 45.139567 -61.560370 45.134501 -61.584254 45.132059 -61.621865 45.150889 -61.702625 45.145104 -61.724315 45.136704 -61.732259 45.125701 -61.698080 45.115802 -61.678716 45.100455 -61.698916 45.071007 -61.686889 45.066240 -61.700241 45.076451 -61.737457 45.064678 -61.786075 45.077604 -61.831876 45.073494 -61.847400 45.058609 -61.846581 45.049931 -61.864901 45.038821 -61.864349 45.027553 -61.868946 45.020419 -61.886297 45.031062 -61.902588 45.035869 -61.917534 45.020592 -61.932359 45.024521 -61.950440 45.042804 -61.985012 45.031919 -62.002174 45.023986 -61.994321 45.010895 -61.987292 45.005332 -61.998472 45.004267 -62.035002 44.993255 -62.080440 44.987554 -62.096858 44.977075 -62.075285 44.980718 -62.052487 44.979032 -62.035648 44.973572 -62.018524 44.964645 -62.019059 44.958463 -62.051180 44.952787 -62.141797 44.943747 -62.170408 44.931819 -62.195861 44.925921 -62.217382 44.934008 -62.242967 44.935517 -62.265044 44.922713 -62.293420 44.904000 -62.320441 44.899143 -62.333680 44.899820 -62.358800 44.890490 -62.369704 44.879946 -62.376281 44.873307 -62.395739 44.877176 -62.413635 44.873632 -62.431219 44.843061 -62.478076 44.843152 -62.495918 44.866942 -62.496511 44.873078 -62.510486 44.868855 -62.525878 44.852363 -62.530945 44.839518 -62.536284 44.833584 -62.557825 44.837185 -62.581011 44.790589 -62.576573 44.778250 -62.589305 44.782120 -62.607285 44.801542 -62.623245 44.808850 -62.646650 44.796499 -62.659365 44.789221 -62.676501 44.772488 -62.686791 44.767579 -62.699949 44.774175 -62.721334 44.776538 -62.757892 44.762520 -62.794357 44.761895 -62.809986 44.785925 -62.840985 44.787365 -62.862952 44.783908 -62.875238 44.772776 -62.874332 44.762495 -62.852681 44.747202 -62.844239 44.734904 -62.856823 44.704402 -62.839891 44.695098 -62.850587 44.693810 -62.864009 44.707338 -62.896262 44.709672 -62.932887 44.705766 -62.973158 44.695384 -63.009754 44.701072 -63.034182 44.722800 -63.046355 44.745012 -63.048140 44.760208 -63.056713 44.767890 -63.069764 44.754386 -63.090672 44.742006 -63.085448 44.717428 -63.069788 44.690851 -63.065547 44.672827 -63.071412 44.671741 -63.097324 44.694785 -63.113719 44.708949 -63.130553 44.739357 -63.129940 44.751131 -63.133096 44.758536 -63.151442 44.750707 -63.161071 44.698504 -63.167118 44.679517 -63.175922 44.675906 -63.193312 44.686074 -63.197275 44.713714 -63.193451 44.733720 -63.194027 44.738949 -63.211198 44.730008 -63.229124 44.686725 -63.234797 44.667733 -63.243571 44.673629 -63.262741 44.694917 -63.267719 44.704886 -63.276917 44.677697 -63.305807 44.655051 -63.296500 44.645292 -63.299803 44.636577 -63.312576 44.612826 -63.329257 44.623132 -63.381021 44.617788 -63.416913 44.623568 -63.436144 44.653307 -63.451259 44.663686 -63.467888 44.664463 -63.482470 44.659439 -63.495510 44.636607 -63.491319 44.609818 -63.461913 44.586428 -63.485782 44.585718 -63.501172 44.596085 -63.517788 44.600912 -63.557620 44.637264 -63.589152 44.644786 -63.602316 44.661009 -63.620476 44.674105 -63.640426 44.696054 -63.677904 44.695352 -63.693438 44.662082 -63.690340 44.646542 -63.674177 44.630987 -63.628049 44.621907 -63.615771 44.609013 -63.620776 44.590639 -63.601446 44.577918 -63.588822 44.555734 -63.586777 44.537725 -63.592253 44.522898 -63.590871 44.506679 -63.572776 44.487201 -63.561599 44.447535 -63.584914 44.446850 -63.600362 44.453059 -63.609280 44.457527 -63.624102 44.453121 -63.639248 44.438084 -63.643041 44.430630 -63.659884 44.431416 -63.674503 44.446606 -63.683164 44.455254 -63.718175 44.450634 -63.750892 44.459687 -63.763149 44.465691 -63.777111 44.459258 -63.815892 44.463732 -63.830845 44.482774 -63.834758 44.487015 -63.854910 44.474720 -63.892002 44.489658 -63.948441 44.498450 -63.965939 44.514825 -63.978979 44.537512 -63.970935 44.554528 -63.956032 44.572989 -63.957926 44.604474 -63.967397 44.619773 -63.958493 44.656361 -63.924778 44.650797 -63.960630 44.635953 -63.989326 44.617408 -64.060231 44.605288 -64.079737 44.593937 -64.083740 44.556397 -64.077664 44.529404 -64.083235 44.495357 -64.052760 44.484954 -64.053701 44.475874 -64.083873 44.458556 -64.103775 44.452503 -64.119742 44.466879 -64.156511 44.479759 -64.164074 44.508690 -64.165073 44.529371 -64.180732 44.547035 -64.210716 44.548383 -64.239938 44.525378 -64.252934 44.524567 -64.280923 44.530345 -64.337626 44.516284 -64.350604 44.474806 -64.349138 44.465949 -64.361661 44.441949 -64.352676 44.432440 -64.363164 44.427307 -64.388372 44.410490 -64.397892 44.395372 -64.388998 44.389545 -64.374922 44.399475 -64.341823 44.398224 -64.325125 44.389868 -64.314961 44.373934 -64.321512 44.360328 -64.286895 44.347092 -64.284435 44.339776 -64.295970 44.347920 -64.336183 44.339703 -64.363168 44.327140 -64.375284 44.311805 -64.371416 44.310423 -64.342396 44.311356 -64.327059 44.301474 -64.317604 44.274817 -64.330238 44.277505 -64.296491 44.270676 -64.285392 44.256174 -64.278743 44.242716 -64.293733 44.234890 -64.315555 44.240208 -64.339894 44.278320 -64.372908 44.282123 -64.385782 44.270786 -64.401968 44.255157 -64.403421 44.245044 -64.423958 44.225103 -64.435130 44.218162 -64.466327 44.143425 -64.527892 44.132466 -64.576039 44.127885 -64.652727 44.117748 -64.660902 44.106153 -64.632748 44.107307 -64.600042 44.091702 -64.588909 44.053982 -64.612357 44.048123 -64.622979 44.048159 -64.647654 44.043548 -64.662457 44.032531 -64.673575 44.021770 -64.704107 43.994488 -64.714266 43.969383 -64.725750 43.959210 -64.746088 43.948829 -64.759171 43.939249 -64.793972 43.928452 -64.824417 43.924404 -64.853639 43.909692 -64.876416 43.894973 -64.874751 43.886739 -64.864436 43.877924 -64.827639 43.858950 -64.810974 43.849175 -64.813900 43.843615 -64.831730 43.836521 -64.850221 43.823922 -64.862073 43.816590 -64.873492 43.827300 -64.892140 43.851134 -64.901177 43.864546 -64.935538 43.861382 -64.949480 43.851270 -64.957382 43.833878 -64.927729 43.794981 -64.934270 43.787601 -64.945563 43.791193 -64.958294 43.819392 -64.969884 43.839783 -64.985720 43.838259 -64.998772 43.826535 -65.007645 43.790840 -64.987936 43.771875 -64.983499 43.751909 -64.994314 43.752996 -65.023057 43.773488 -65.038947 43.787820 -65.045820 43.797221 -65.060212 43.796283 -65.075419 43.776048 -65.079039 43.735411 -65.054602 43.701073 -65.070755 43.687472 -65.097574 43.704211 -65.112949 43.713940 -65.122343 43.710273 -65.134116 43.677665 -65.156585 43.651947 -65.165584 43.649076 -65.186536 43.671043 -65.189360 43.690718 -65.183739 43.700746 -65.188053 43.696581 -65.217098 43.748452 -65.250269 43.754163 -65.264369 43.752760 -65.284601 43.737043 -65.297883 43.727610 -65.295712 43.706266 -65.282649 43.679312 -65.287415 43.658728 -65.295911 43.651344 -65.307218 43.659047 -65.334668 43.667295 -65.344962 43.677313 -65.349308 43.706115 -65.351030 43.717227 -65.371964 43.713757 -65.390872 43.705106 -65.397896 43.632078 -65.383218 43.610440 -65.375223 43.582702 -65.389920 43.568094 -65.388050 43.552146 -65.394115 43.546874 -65.406630 43.542374 -65.428323 43.543453 -65.444848 43.558323 -65.453976 43.563448 -65.465715 43.555867 -65.489233 43.536405 -65.482562 43.523131 -65.460483 43.511291 -65.449701 43.488138 -65.442606 43.478244 -65.445324 43.470262 -65.454407 43.489624 -65.473246 43.503577 -65.485278 43.494280 -65.502391 43.471355 -65.502389 43.455369 -65.508297 43.447966 -65.519523 43.466984 -65.543446 43.485401 -65.596720 43.512810 -65.606510 43.518087 -65.625543 43.510544 -65.648958 43.500308 -65.656701 43.483847 -65.679810 43.476417 -65.710371 43.477144 -65.731782 43.472147 -65.758528 43.475355 -65.776247 43.484424 -65.783569 43.496365 -65.782241 43.508647 -65.775846 43.515263 -65.786978 43.525578 -65.817804 43.538293 -65.825777 43.566832 -65.820548 43.597252 -65.809604 43.642357 -65.800594 43.657851 -65.811972 43.658281 -65.826375 43.648022 -65.834103 43.629691 -65.831504 43.616204 -65.833723 43.588468 -65.848095 43.611674 -65.874876 43.625927 -65.881981 43.688686 -65.885829 43.734166 -65.871785 43.760614 -65.884870 43.766452 -65.906053 43.763789 -65.922022 43.776160 -65.935163 43.797725 -65.943341 43.806444 -65.955849 43.806276 -65.968118 43.797575 -65.975048 43.782392 -65.970803 43.771579 -65.976449 43.763414 -65.985442 43.768731 -66.004675 43.779473 -66.018521 43.762360 -66.039570 43.737076 -66.011339 43.722707 -66.004118 43.710216 -66.003327 43.694750 -66.011268 43.689958 -66.025926 43.689029 -66.048226 43.676638 -66.054630 43.674695 -66.079886 43.683215 -66.085232 43.702910 -66.079886 43.709493 -66.091109 43.705030 -66.120075 43.712540 -66.128396 43.726609 -66.128436 43.740281 -66.133459 43.740657 -66.147891 43.745253 -66.164899 43.775349 -66.178661 43.783100 -66.194119 43.807155 -66.198722 43.835107 -66.211124 43.860422 -66.200598 43.875679 -66.204873 43.891138 -66.216444 43.926080 -66.195972 43.961840 -66.204422 44.008201 -66.200114 44.037357 -66.216798 44.076384 -66.230978 44.102584 -66.236930 44.131263 -66.232004 44.203791 -66.187218 44.233860 -66.174108 44.302555 -66.160625 44.324181 -66.149342 44.359659 -66.123522 44.379929 -66.100690 44.424676 -66.050190 44.460703 -65.987006 44.514642 -65.911618 44.539345 -65.898606 44.556478 -65.909438 44.561714 -65.928941 44.549131 -65.967730 44.553607 -65.997497 44.548442 -66.017616 44.490528 -66.084869 44.467482 -66.104298 44.428553 -66.156720 44.401393 -66.180630 44.393220 -66.189818 44.380207 -66.213867 44.382650 -66.229701 44.396396 -66.234936 44.411366 -66.224738 44.435205 -66.195170 44.459479 -66.160343 44.494502 -66.139572 44.507901 -66.110377 44.555236 -66.056089 44.588802 -65.960484 44.645739 -65.873996 44.658640 -65.835548 44.656469 -65.814442 44.647115 -65.799510 44.626913 -65.790379 44.598996 -65.785316 44.580661 -65.750428 44.580974 -65.725576 44.589032 -65.696489 44.611131 -65.667343 44.619841 -65.660230 44.645719 -65.631463 44.672429 -65.599735 44.693781 -65.560907 44.723623 -65.495102 44.736725 -65.478096 44.761693 -65.472046 44.760235 -65.492722 44.745889 -65.517934 44.711085 -65.611360 44.677113 -65.681793 44.657425 -65.759350 44.660612 -65.777422 44.670313 -65.787156 44.680738 -65.786606 44.698524 -65.767202 44.722037 -65.729888 44.752632 -65.666213 44.769814 -65.644507 44.802341 -65.562292 44.843236 -65.465331 44.883541 -65.398553 44.909613 -65.331751 44.947100 -65.261247 45.008954 -65.157013 45.030015 -65.130345 45.048458 -65.087482 45.071422 -65.042046 45.112713 -64.953755 45.121512 -64.921104 45.126170 -64.893229 45.146027 -64.824099 45.171731 -64.718749 45.239323 -64.477978 45.257132 -64.452542 45.270726 -64.449937 45.279982 -64.457281 45.292736 -64.482968 45.303562 -64.514880 45.313731 -64.531883 45.327600 -64.524013 45.318581 -64.473245 45.294033 -64.393444 45.280690 -64.378226 45.256642 -64.369180 45.227983 -64.388086 45.210800 -64.402935 45.186167 -64.417019 45.174458 -64.413608 45.150728 -64.399410 45.137760 -64.404249 45.119935 -64.429529 45.108845 -64.428340 45.098978 -64.418806 45.089939 -64.393622 45.093910 -64.376225 45.111735 -64.363459 45.114823 -64.349086 45.106639 -64.320869 45.077810 -64.276696 45.039404 -64.230459 45.019263 -64.216707 44.985713 -64.205797 44.977978 -64.197566 44.968798 -64.159903 44.965269 -64.129183 44.971002 -64.105692 44.982334 -64.101551 44.989130 -64.112855 44.992074 -64.128833 44.993118 -64.150992 45.005533 -64.169135 45.030106 -64.154972 45.050139 -64.168648 45.080917 -64.219212 45.108179 -64.239022 45.126060 -64.238830 45.161345 -64.218485 45.186486 -64.193873 45.197460 -64.169809 45.223688 -64.068251 45.249577 -63.941239 45.272003 -63.864504 45.290987 -63.812667 45.298230 -63.800698 45.299031 -63.784901 45.296733 -63.771001 45.301380 -63.737671 45.308730 -63.707828 45.304145 -63.679865 45.295369 -63.644258 45.304310 -63.564939 45.300702 -63.546609 45.276650 -63.520159 45.281692 -63.506943 45.299197 -63.499064 45.313748 -63.505672 45.327347 -63.484799 45.339635 -63.477452 45.353265 -63.487189 45.357140 -63.518174 45.356089 -63.557165 45.376640 -63.626664 45.371111 -63.681122 45.373299 -63.743678 45.380392 -63.780323 45.380665 -63.805732 45.351065 -63.907407 45.346668 -63.935410 45.351490 -63.958078 45.361918 -63.987785 45.368884 -64.011698 45.371796 -64.040623 45.370502 -64.066854 45.372147 -64.091320 45.386260 -64.121424 45.387642 -64.151192 45.380392 -64.175720 45.378980 -64.202010 45.387057 -64.217730 45.388081 -64.240086 45.383002 -64.265957 45.372868 -64.287043 45.366498 -64.308597 45.361821 -64.392604 45.350960 -64.467490 45.353499 -64.488964 45.379517 -64.555346 45.388171 -64.586076 45.393441 -64.636382 45.386033 -64.673709 45.370268 -64.712989 45.353347 -64.735284 45.310426 -64.767074 45.298029 -64.799424 45.298909 -64.821751 45.314323 -64.838375 45.336722 -64.873930 45.339164 -64.895419 45.332610 -64.916758 45.321979 -64.968329 45.324093 -64.982296 45.335490 -64.991147 45.395153 -64.955330 45.448146 -64.882425 45.465426 -64.867682 45.489303 -64.805866 45.508805 -64.766810 45.580190 -64.644801 45.640341 -64.546622 45.676979 -64.492363 45.700408 -64.473828 45.709718 -64.468392 45.737760 -64.447136 45.749407 -64.424980 45.762412 -64.420080 45.780650 -64.414732 45.789145 -64.368721 45.777664 -64.359940 45.750255 -64.383522 45.740671 -64.381335 45.738461 -64.367270 45.746672 -64.326628 45.761388 -64.315425 45.776089 -64.335241 45.788651 -64.322774 45.808102 -64.308902 45.808120 -64.308927 45.823976 -64.294811 45.940739 -64.194680 45.953182 -64.192553 45.968192 -64.088437 45.968076 -64.031412 45.972937 -63.999252 45.981579 -63.994538 45.982824 -63.993981 @@ -312,15 +312,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 45.50482 -61.22751 - 45.53473 -61.18069 + 45.504823 -61.227514 + 45.534739 -61.180696 - 45.51045 -61.22751 45.51931 -61.22687 45.52995 -61.21455 45.53473 -61.20094 45.52992 -61.18069 45.51634 -61.18962 45.50482 -61.21028 45.51045 -61.22751 + 45.510451 -61.227514 45.519318 -61.226878 45.529958 -61.214551 45.534739 -61.200944 45.529920 -61.180696 45.516349 -61.189628 45.504823 -61.210287 45.510451 -61.227514 @@ -333,15 +333,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 45.78689 -62.62684 - 45.81546 -62.55613 + 45.786892 -62.626846 + 45.815465 -62.556139 - 45.79069 -62.62192 45.79950 -62.62684 45.80862 -62.62107 45.81546 -62.59606 45.80869 -62.55613 45.79817 -62.55752 45.78689 -62.60347 45.79069 -62.62192 + 45.790699 -62.621922 45.799503 -62.626846 45.808625 -62.621075 45.815465 -62.596064 45.808696 -62.556139 45.798173 -62.557522 45.786892 -62.603470 45.790699 -62.621922 @@ -354,15 +354,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 45.73923 -62.77618 - 45.76402 -62.72846 + 45.739239 -62.776183 + 45.764021 -62.728467 - 45.74288 -62.76845 45.75973 -62.77618 45.76402 -62.76050 45.76045 -62.73682 45.74881 -62.72846 45.73923 -62.74484 45.74288 -62.76845 + 45.742885 -62.768457 45.759737 -62.776183 45.764021 -62.760507 45.760451 -62.736823 45.748816 -62.728467 45.739239 -62.744842 45.742885 -62.768457 @@ -375,15 +375,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 43.91841 -60.11754 - 44.01041 -59.71284 + 43.918413 -60.117541 + 44.010417 -59.712843 - 43.92307 -60.11754 43.93352 -60.11062 43.94339 -60.07098 43.95258 -59.91475 43.95880 -59.86978 43.96940 -59.82193 44.00294 -59.74551 44.01041 -59.72512 44.00599 -59.71284 43.99417 -59.71575 43.98158 -59.73206 43.96591 -59.77585 43.93528 -59.85529 43.92985 -59.88686 43.92813 -59.93384 43.92190 -59.98373 43.91841 -60.05722 43.91957 -60.09712 43.92307 -60.11754 + 43.923078 -60.117541 43.933522 -60.110628 43.943396 -60.070988 43.952586 -59.914751 43.958808 -59.869787 43.969408 -59.821934 44.002943 -59.745514 44.010417 -59.725120 44.005999 -59.712843 43.994175 -59.715759 43.981586 -59.732063 43.965917 -59.775859 43.935280 -59.855295 43.929858 -59.886866 43.928136 -59.933842 43.921907 -59.983735 43.918413 -60.057221 43.919575 -60.097126 43.923078 -60.117541 @@ -396,15 +396,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 44.25244 -66.35756 - 44.36908 -66.25144 + 44.252448 -66.357560 + 44.369088 -66.251440 - 44.25426 -66.34999 44.26331 -66.35756 44.36053 -66.28547 44.36908 -66.27114 44.36868 -66.25668 44.35494 -66.25144 44.34005 -66.26156 44.27920 -66.29795 44.26288 -66.31608 44.25244 -66.33624 44.25426 -66.34999 + 44.254260 -66.349998 44.263314 -66.357560 44.360536 -66.285475 44.369088 -66.271148 44.368689 -66.256681 44.354945 -66.251440 44.340056 -66.261563 44.279201 -66.297959 44.262882 -66.316083 44.252448 -66.336248 44.254260 -66.349998 @@ -417,15 +417,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 44.21850 -66.43267 - 44.25705 -66.37969 + 44.218506 -66.432672 + 44.257055 -66.379694 - 44.22686 -66.43267 44.23618 -66.42797 44.25705 -66.40008 44.25302 -66.38496 44.23929 -66.37969 44.22341 -66.39285 44.21850 -66.40752 44.22686 -66.43267 + 44.226863 -66.432672 44.236182 -66.427973 44.257055 -66.400086 44.253021 -66.384960 44.239292 -66.379694 44.223413 -66.392850 44.218506 -66.407527 44.226863 -66.432672 @@ -438,15 +438,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 43.41231 -65.68783 - 43.47638 -65.61648 + 43.412311 -65.687835 + 43.476384 -65.616482 - 43.41231 -65.65685 43.43182 -65.68286 43.44554 -65.68783 43.47369 -65.65616 43.47638 -65.64022 43.46618 -65.61648 43.44388 -65.61842 43.42851 -65.62655 43.41583 -65.63808 43.41231 -65.65685 + 43.412311 -65.656854 43.431829 -65.682866 43.445545 -65.687835 43.473694 -65.656161 43.476384 -65.640224 43.466182 -65.616482 43.443882 -65.618422 43.428510 -65.626553 43.415833 -65.638089 43.412311 -65.656854 diff --git a/msautotest/wxs/expected/wfs_optional_items_get_feature_area_name.xml b/msautotest/wxs/expected/wfs_optional_items_get_feature_area_name.xml index 71673161a1..cd2d0d8aea 100644 --- a/msautotest/wxs/expected/wfs_optional_items_get_feature_area_name.xml +++ b/msautotest/wxs/expected/wfs_optional_items_get_feature_area_name.xml @@ -10,8 +10,8 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 timeStamp="" numberMatched="21" numberReturned="21"> - 43.41231 -66.43267 - 47.79644 -59.70969 + 43.412311 -66.432672 + 47.796447 -59.709694 diff --git a/msautotest/wxs/expected/wfs_optional_items_get_feature_filter_alias.xml b/msautotest/wxs/expected/wfs_optional_items_get_feature_filter_alias.xml index 12e5715ed3..872d567c24 100644 --- a/msautotest/wxs/expected/wfs_optional_items_get_feature_filter_alias.xml +++ b/msautotest/wxs/expected/wfs_optional_items_get_feature_filter_alias.xml @@ -10,8 +10,8 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 timeStamp="" numberMatched="2" numberReturned="2"> - 45.94981 -64.46414 - 47.04029 -62.02064 + 45.949816 -64.464145 + 47.040290 -62.020645 diff --git a/msautotest/wxs/expected/wfs_optional_items_get_feature_geometry.xml b/msautotest/wxs/expected/wfs_optional_items_get_feature_geometry.xml index c224bcf11e..ed8cb96595 100644 --- a/msautotest/wxs/expected/wfs_optional_items_get_feature_geometry.xml +++ b/msautotest/wxs/expected/wfs_optional_items_get_feature_geometry.xml @@ -10,23 +10,23 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 timeStamp="" numberMatched="21" numberReturned="21"> - 43.41231 -66.43267 - 47.79644 -59.70969 + 43.412311 -66.432672 + 47.796447 -59.709694 - 47.76789 -61.51051 - 47.79644 -61.45764 + 47.767892 -61.510511 + 47.796447 -61.457648 - 47.77424 -61.51051 47.78860 -61.50894 47.79644 -61.49272 47.78743 -61.45764 47.76789 -61.45998 47.76961 -61.48350 47.77424 -61.51051 + 47.774240 -61.510511 47.788606 -61.508947 47.796447 -61.492725 47.787438 -61.457648 47.767892 -61.459987 47.769615 -61.483502 47.774240 -61.510511 @@ -38,15 +38,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 47.16638 -60.21172 - 47.19271 -60.16877 + 47.166385 -60.211728 + 47.192716 -60.168776 - 47.16638 -60.20485 47.17985 -60.21172 47.19271 -60.19435 47.18763 -60.17344 47.17496 -60.16877 47.16638 -60.20485 + 47.166385 -60.204850 47.179857 -60.211728 47.192716 -60.194354 47.187638 -60.173448 47.174965 -60.168776 47.166385 -60.204850 @@ -58,15 +58,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 47.19106 -62.07696 - 47.62759 -61.43322 + 47.191069 -62.076968 + 47.627593 -61.433227 - 47.24108 -62.01051 47.24604 -61.96674 47.23831 -61.94754 47.22825 -61.93270 47.22220 -61.90699 47.23311 -61.86469 47.24267 -61.84221 47.23857 -61.82873 47.22731 -61.82804 47.21582 -61.83841 47.19106 -61.89528 47.19587 -61.91086 47.20730 -61.93027 47.21146 -61.94369 47.20068 -61.98054 47.20210 -62.00918 47.21127 -62.05713 47.21986 -62.07304 47.23019 -62.07696 47.30062 -62.02523 47.32797 -62.01258 47.35422 -62.01412 47.38157 -62.00145 47.40632 -61.97428 47.46073 -61.87584 47.55646 -61.74402 47.59681 -61.65975 47.61945 -61.58987 47.62006 -61.53210 47.62627 -61.49244 47.62759 -61.46701 47.62579 -61.44364 47.61706 -61.43322 47.60265 -61.44020 47.58445 -61.48263 47.57198 -61.50196 47.54670 -61.52732 47.53100 -61.55423 47.52441 -61.58041 47.53668 -61.60212 47.54664 -61.59275 47.56410 -61.55367 47.58387 -61.54035 47.59656 -61.57531 47.58175 -61.62893 47.56042 -61.67323 47.53788 -61.70753 47.50243 -61.77198 47.46323 -61.81183 47.43985 -61.84363 47.42876 -61.86734 47.41317 -61.88844 47.37958 -61.91082 47.35461 -61.91930 47.34335 -61.91859 47.32832 -61.94748 47.31536 -61.98306 47.25730 -62.02144 47.24108 -62.01051 + 47.241088 -62.010515 47.246040 -61.966742 47.238311 -61.947548 47.228257 -61.932708 47.222202 -61.906997 47.233116 -61.864694 47.242674 -61.842210 47.238572 -61.828736 47.227311 -61.828048 47.215824 -61.838414 47.191069 -61.895286 47.195878 -61.910866 47.207300 -61.930279 47.211466 -61.943690 47.200682 -61.980541 47.202105 -62.009180 47.211273 -62.057130 47.219864 -62.073040 47.230193 -62.076968 47.300625 -62.025236 47.327971 -62.012584 47.354223 -62.014128 47.381572 -62.001451 47.406325 -61.974280 47.460730 -61.875844 47.556462 -61.744027 47.596818 -61.659750 47.619458 -61.589874 47.620068 -61.532104 47.626271 -61.492444 47.627593 -61.467016 47.625790 -61.443646 47.617067 -61.433227 47.602653 -61.440203 47.584451 -61.482632 47.571983 -61.501965 47.546702 -61.527322 47.531009 -61.554237 47.524411 -61.580413 47.536685 -61.602124 47.546644 -61.592755 47.564103 -61.553676 47.583872 -61.540355 47.596569 -61.575318 47.581754 -61.628933 47.560421 -61.673230 47.537886 -61.707530 47.502438 -61.771983 47.463236 -61.811839 47.439850 -61.843632 47.428764 -61.867341 47.413176 -61.888445 47.379589 -61.910824 47.354617 -61.919309 47.343351 -61.918598 47.328320 -61.947480 47.315363 -61.983069 47.257309 -62.021449 47.241088 -62.010515 @@ -78,15 +78,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 47.37578 -61.85020 - 47.53541 -61.62463 + 47.375784 -61.850201 + 47.535418 -61.624632 - 47.39077 -61.85020 47.40527 -61.83772 47.41716 -61.81637 47.42945 -61.80270 47.44433 -61.77925 47.46587 -61.75944 47.48454 -61.73062 47.49872 -61.70481 47.52737 -61.66642 47.53541 -61.64470 47.53286 -61.62463 47.52225 -61.63180 47.51114 -61.65567 47.45830 -61.72907 47.43823 -61.75344 47.41589 -61.77649 47.37997 -61.80321 47.37578 -61.81946 47.39077 -61.85020 + 47.390774 -61.850201 47.405273 -61.837726 47.417160 -61.816375 47.429451 -61.802704 47.444334 -61.779258 47.465873 -61.759440 47.484545 -61.730626 47.498723 -61.704819 47.527379 -61.666427 47.535418 -61.644700 47.532866 -61.624632 47.522259 -61.631801 47.511145 -61.655676 47.458309 -61.729072 47.438230 -61.753441 47.415897 -61.776498 47.379975 -61.803218 47.375784 -61.819462 47.390774 -61.850201 @@ -98,15 +98,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 45.55044 -61.59511 - 47.03152 -60.34353 + 45.550449 -61.595111 + 47.031525 -60.343533 - 45.64995 -60.88100 45.62964 -60.89735 45.63055 -60.92814 45.61131 -61.00908 45.61072 -61.04080 45.60069 -61.06061 45.58886 -61.09728 45.58218 -61.13299 45.56434 -61.16831 45.55872 -61.19037 45.56065 -61.20734 45.58078 -61.20714 45.59226 -61.22567 45.59854 -61.24502 45.59370 -61.26380 45.57932 -61.27601 45.57074 -61.29466 45.55044 -61.30547 45.55804 -61.33436 45.57893 -61.36499 45.60096 -61.37658 45.62222 -61.39131 45.64498 -61.43901 45.68124 -61.47794 45.72090 -61.50435 45.74448 -61.51506 45.79398 -61.53240 45.83324 -61.54064 45.86342 -61.55506 45.90791 -61.56254 45.94146 -61.56423 46.02269 -61.59511 46.03665 -61.57548 46.04540 -61.55132 46.05222 -61.51518 46.05285 -61.48843 46.05503 -61.45536 46.06486 -61.45148 46.07567 -61.46816 46.09111 -61.51066 46.10430 -61.51772 46.14672 -61.48975 46.17439 -61.45567 46.19619 -61.41489 46.21434 -61.36836 46.23455 -61.33384 46.29334 -61.27078 46.39497 -61.18675 46.42631 -61.15240 46.44736 -61.14355 46.51078 -61.10612 46.57439 -61.06319 46.58996 -61.06597 46.61490 -61.09195 46.62260 -61.08137 46.62750 -61.06206 46.62258 -61.04122 46.62967 -61.02303 46.64697 -61.01398 46.65751 -61.01219 46.73777 -60.95217 46.78405 -60.91250 46.79934 -60.89124 46.81256 -60.85802 46.83880 -60.80765 46.88381 -60.75247 46.93979 -60.70840 46.97604 -60.68331 47.00688 -60.67548 47.01668 -60.66590 47.02681 -60.63446 47.02576 -60.60818 47.01756 -60.54331 46.99698 -60.51433 46.99416 -60.50008 47.00184 -60.48380 47.02743 -60.47143 47.03152 -60.44411 47.02334 -60.43075 47.01370 -60.42398 47.00027 -60.42800 46.97970 -60.45590 46.96315 -60.46750 46.94223 -60.46591 46.92785 -60.47316 46.91766 -60.51544 46.90031 -60.52481 46.89381 -60.51047 46.89407 -60.48325 46.88541 -60.45685 46.85658 -60.43096 46.85306 -60.40903 46.85722 -60.37096 46.84174 -60.35207 46.81863 -60.34397 46.79994 -60.34353 46.78409 -60.35725 46.73103 -60.35388 46.68503 -60.38863 46.67134 -60.41431 46.65255 -60.41936 46.65209 -60.40091 46.64560 -60.38121 46.63657 -60.38199 46.62739 -60.39920 46.61609 -60.40979 46.60516 -60.38238 46.58877 -60.37766 46.55717 -60.39962 46.53890 -60.42845 46.51251 -60.44942 46.49831 -60.45121 46.40272 -60.51463 46.38309 -60.53354 46.36266 -60.56105 46.35206 -60.56824 46.33566 -60.56890 46.31001 -60.58650 46.29958 -60.58831 46.27931 -60.59961 46.26988 -60.63265 46.26067 -60.64966 46.24740 -60.64284 46.22487 -60.65291 46.21303 -60.64502 46.21024 -60.63101 46.21637 -60.61606 46.25403 -60.59029 46.30100 -60.53670 46.31771 -60.51452 46.33005 -60.47931 46.30400 -60.47324 46.29501 -60.47952 46.27538 -60.49840 46.26319 -60.51743 46.22776 -60.54436 46.19430 -60.59400 46.10330 -60.70392 46.09247 -60.73247 46.09174 -60.78077 46.07638 -60.81238 46.06139 -60.86219 46.05797 -60.89103 46.07230 -60.92366 46.06668 -60.94590 46.05320 -60.94974 46.03421 -60.97053 46.02431 -60.98510 45.99002 -61.02658 45.97226 -61.05689 45.95590 -61.09692 45.94928 -61.13287 45.94288 -61.15298 45.92864 -61.15989 45.92678 -61.14273 45.93026 -61.11400 45.94794 -61.04426 45.95424 -61.02420 45.95924 -60.99444 45.97081 -60.97345 45.98019 -60.95135 45.99803 -60.94988 46.01138 -60.95681 46.03075 -60.90934 46.03175 -60.89546 46.01957 -60.86935 46.02499 -60.85245 46.04649 -60.81672 46.04855 -60.77818 46.03810 -60.78011 46.00609 -60.82286 45.98055 -60.84022 45.94769 -60.84129 45.93452 -60.87388 45.91784 -60.93525 45.92248 -60.96634 45.91903 -60.99507 45.90151 -61.05953 45.88426 -61.10260 45.84710 -61.13519 45.84304 -61.11695 45.85166 -61.09280 45.86428 -61.05806 45.86543 -61.03352 45.88570 -61.02799 45.89205 -61.00259 45.87647 -60.96039 45.86758 -60.95579 45.85654 -60.98955 45.83520 -60.97494 45.82597 -60.99154 45.82762 -61.02462 45.81520 -61.05403 45.78755 -61.09867 45.76274 -61.15204 45.74052 -61.17983 45.73866 -61.16274 45.72476 -61.14835 45.71458 -61.17342 45.69499 -61.18652 45.68877 -61.16179 45.69638 -61.11746 45.70518 -61.08281 45.71903 -61.05772 45.73432 -61.03713 45.75141 -60.99942 45.75710 -60.97199 45.74426 -60.89393 45.73581 -60.86279 45.72194 -60.84844 45.70705 -60.84805 45.68510 -60.87066 45.66404 -60.88471 45.64995 -60.88100 + 45.649954 -60.881009 45.629648 -60.897351 45.630553 -60.928145 45.611319 -61.009089 45.610721 -61.040806 45.600690 -61.060614 45.588861 -61.097280 45.582181 -61.132995 45.564345 -61.168312 45.558723 -61.190377 45.560650 -61.207340 45.580780 -61.207140 45.592268 -61.225673 45.598546 -61.245028 45.593709 -61.263803 45.579321 -61.276019 45.570740 -61.294666 45.550449 -61.305470 45.558043 -61.334366 45.578931 -61.364992 45.600965 -61.376583 45.622223 -61.391312 45.644981 -61.439011 45.681246 -61.477948 45.720907 -61.504351 45.744486 -61.515065 45.793980 -61.532408 45.833242 -61.540641 45.863422 -61.555060 45.907911 -61.562546 45.941468 -61.564232 46.022697 -61.595111 46.036654 -61.575489 46.045406 -61.551320 46.052222 -61.515187 46.052853 -61.488434 46.055037 -61.455367 46.064862 -61.451486 46.075678 -61.468167 46.091116 -61.510668 46.104307 -61.517727 46.146728 -61.489759 46.174397 -61.455676 46.196198 -61.414895 46.214349 -61.368367 46.234559 -61.333845 46.293343 -61.270789 46.394972 -61.186759 46.426311 -61.152403 46.447362 -61.143556 46.510783 -61.106129 46.574395 -61.063193 46.589967 -61.065977 46.614909 -61.091959 46.622603 -61.081372 46.627500 -61.062069 46.622583 -61.041222 46.629678 -61.023032 46.646978 -61.013984 46.657512 -61.012199 46.737777 -60.952173 46.784059 -60.912506 46.799340 -60.891249 46.812564 -60.858021 46.838805 -60.807653 46.883813 -60.752476 46.939790 -60.708400 46.976042 -60.683312 47.006882 -60.675484 47.016681 -60.665906 47.026816 -60.634462 47.025765 -60.608189 47.017567 -60.543319 46.996989 -60.514337 46.994169 -60.500086 47.001841 -60.483802 47.027437 -60.471435 47.031525 -60.444116 47.023340 -60.430751 47.013703 -60.423989 47.000272 -60.428005 46.979701 -60.455909 46.963151 -60.467506 46.942231 -60.465911 46.927854 -60.473165 46.917662 -60.515443 46.900315 -60.524813 46.893814 -60.510474 46.894074 -60.483257 46.885413 -60.456857 46.856580 -60.430963 46.853060 -60.409033 46.857226 -60.370964 46.841740 -60.352079 46.818636 -60.343976 46.799943 -60.343533 46.784093 -60.357258 46.731037 -60.353887 46.685033 -60.388635 46.671343 -60.414318 46.652557 -60.419369 46.652092 -60.400910 46.645606 -60.381215 46.636579 -60.381992 46.627395 -60.399203 46.616098 -60.409798 46.605166 -60.382381 46.588778 -60.377669 46.557171 -60.399625 46.538904 -60.428453 46.512512 -60.449424 46.498315 -60.451219 46.402727 -60.514638 46.383090 -60.533548 46.362662 -60.561054 46.352066 -60.568243 46.335667 -60.568906 46.310018 -60.586506 46.299584 -60.588312 46.279313 -60.599619 46.269887 -60.632652 46.260672 -60.649667 46.247406 -60.642843 46.224879 -60.652912 46.213036 -60.645026 46.210245 -60.631019 46.216372 -60.616069 46.254031 -60.590291 46.301008 -60.536708 46.317713 -60.514524 46.330057 -60.479319 46.304009 -60.473241 46.295010 -60.479521 46.275389 -60.498401 46.263191 -60.517436 46.227762 -60.544368 46.194306 -60.594006 46.103301 -60.703922 46.092472 -60.732477 46.091743 -60.780770 46.076384 -60.812387 46.061390 -60.862199 46.057978 -60.891033 46.072301 -60.923663 46.066682 -60.945906 46.053207 -60.949743 46.034214 -60.970530 46.024319 -60.985101 45.990020 -61.026588 45.972260 -61.056897 45.955900 -61.096924 45.949285 -61.132870 45.942888 -61.152982 45.928641 -61.159899 45.926780 -61.142735 45.930269 -61.114003 45.947948 -61.044268 45.954245 -61.024203 45.959242 -60.994440 45.970819 -60.973451 45.980190 -60.951350 45.998033 -60.949889 46.011382 -60.956812 46.030755 -60.909348 46.031753 -60.895468 46.019571 -60.869352 46.024994 -60.852458 46.046490 -60.816726 46.048559 -60.778188 46.038101 -60.780111 46.006097 -60.822860 45.980558 -60.840227 45.947690 -60.841299 45.934522 -60.873885 45.917843 -60.935257 45.922481 -60.966344 45.919038 -60.995079 45.901511 -61.059535 45.884264 -61.102601 45.847108 -61.135193 45.843043 -61.116957 45.851666 -61.092804 45.864284 -61.058067 45.865436 -61.033524 45.885703 -61.027991 45.892059 -61.002590 45.876475 -60.960393 45.867581 -60.955792 45.856547 -60.989557 45.835202 -60.974943 45.825971 -60.991547 45.827623 -61.024623 45.815209 -61.054032 45.787550 -61.098679 45.762742 -61.152042 45.740520 -61.179832 45.738664 -61.162740 45.724764 -61.148356 45.714587 -61.173426 45.694994 -61.186525 45.688774 -61.161798 45.696384 -61.117462 45.705184 -61.082816 45.719034 -61.057724 45.734323 -61.037132 45.751419 -60.999423 45.757106 -60.971998 45.744260 -60.893939 45.735813 -60.862792 45.721943 -60.848441 45.707052 -60.848053 45.685106 -60.870666 45.664049 -60.884717 45.649954 -60.881009 @@ -118,15 +118,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 47.25507 -61.75096 - 47.28211 -61.71983 + 47.255073 -61.750964 + 47.282116 -61.719830 - 47.25839 -61.74889 47.27555 -61.75096 47.28211 -61.73032 47.26959 -61.71983 47.25507 -61.73219 47.25839 -61.74889 + 47.258394 -61.748897 47.275550 -61.750964 47.282116 -61.730322 47.269593 -61.719830 47.255073 -61.732191 47.258394 -61.748897 @@ -138,15 +138,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 45.56706 -60.89735 - 46.26194 -59.82000 + 45.567064 -60.897351 + 46.261946 -59.820005 - 45.64995 -60.88100 45.65334 -60.85788 45.66020 -60.84534 45.67380 -60.83094 45.68701 -60.79847 45.69923 -60.77975 45.70884 -60.78105 45.73321 -60.79358 45.76006 -60.79121 45.77727 -60.78225 45.82475 -60.69757 45.84729 -60.68225 45.85917 -60.63459 45.90925 -60.56356 45.93950 -60.52700 45.95351 -60.48027 45.96348 -60.46029 45.97695 -60.45093 45.99023 -60.46314 45.94376 -60.60076 45.92884 -60.60565 45.89439 -60.72412 45.89550 -60.74447 45.90717 -60.76295 45.91857 -60.79750 45.92054 -60.81475 45.92940 -60.81922 45.95427 -60.79976 46.02271 -60.66074 46.09125 -60.55036 46.10734 -60.51539 46.12786 -60.48807 46.14975 -60.46504 46.17784 -60.41634 46.19925 -60.37498 46.21365 -60.35160 46.23167 -60.33912 46.24375 -60.32012 46.26194 -60.29684 46.24950 -60.27082 46.23171 -60.25635 46.21606 -60.25394 46.20099 -60.26973 46.17902 -60.30897 46.16101 -60.32145 46.15207 -60.31694 46.14923 -60.30298 46.16001 -60.27422 46.15336 -60.26011 46.13782 -60.25224 46.13124 -60.23286 46.13521 -60.21687 46.14125 -60.20728 46.15314 -60.20964 46.16640 -60.22711 46.17748 -60.23273 46.20890 -60.22695 46.21941 -60.21959 46.23295 -60.20482 46.24441 -60.17819 46.24760 -60.14918 46.24490 -60.11902 46.23770 -60.08663 46.23102 -60.07793 46.21369 -60.10342 46.20027 -60.09673 46.19739 -60.08276 46.20503 -60.05600 46.20450 -60.03234 46.18480 -59.96880 46.18603 -59.88506 46.18247 -59.85804 46.16907 -59.84614 46.16019 -59.84706 46.15476 -59.88034 46.14507 -59.88451 46.13232 -59.88538 46.11727 -59.91733 46.10226 -59.93860 46.09331 -59.93418 46.08968 -59.91805 46.09727 -59.89672 46.10553 -59.88287 46.11912 -59.85728 46.10500 -59.84858 46.09673 -59.85705 46.06371 -59.89640 46.04947 -59.91967 46.03189 -59.97722 46.01846 -59.98673 46.00824 -59.95654 46.00692 -59.92020 45.99378 -59.88152 45.98035 -59.87493 45.95602 -59.83086 45.94492 -59.82000 45.92699 -59.83261 45.93342 -59.88397 45.92194 -59.93191 45.91221 -59.94668 45.90382 -59.96578 45.90805 -60.01066 45.88187 -60.02632 45.87281 -60.04850 45.87040 -60.06338 45.86898 -60.15724 45.86421 -60.18692 45.85525 -60.19320 45.84632 -60.18875 45.83313 -60.16617 45.81987 -60.15420 45.81394 -60.14241 45.81338 -60.12419 45.80450 -60.11452 45.79102 -60.12383 45.78045 -60.14708 45.76964 -60.19157 45.76788 -60.21385 45.78264 -60.23014 45.78029 -60.24492 45.73712 -60.24305 45.72809 -60.25453 45.71524 -60.27655 45.70017 -60.29750 45.69478 -60.31440 45.70188 -60.34644 45.69266 -60.36852 45.65803 -60.40809 45.64129 -60.44055 45.61741 -60.56182 45.60196 -60.66423 45.59346 -60.68833 45.57752 -60.70696 45.56976 -60.72790 45.56706 -60.75852 45.56972 -60.78298 45.59474 -60.79756 45.60111 -60.81685 45.60145 -60.84547 45.61197 -60.88300 45.62964 -60.89735 45.64995 -60.88100 + 45.649954 -60.881009 45.653348 -60.857881 45.660202 -60.845348 45.673801 -60.830945 45.687014 -60.798470 45.699239 -60.779757 45.708848 -60.781056 45.733215 -60.793583 45.760063 -60.791213 45.777275 -60.782252 45.824757 -60.697572 45.847293 -60.682257 45.859173 -60.634593 45.909256 -60.563568 45.939505 -60.527009 45.953515 -60.480278 45.963481 -60.460290 45.976959 -60.450935 45.990237 -60.463145 45.943763 -60.600767 45.928847 -60.605653 45.894394 -60.724121 45.895501 -60.744475 45.907176 -60.762954 45.918574 -60.797500 45.920545 -60.814756 45.929405 -60.819227 45.954272 -60.799765 46.022713 -60.660742 46.091252 -60.550360 46.107347 -60.515399 46.127860 -60.488072 46.149753 -60.465043 46.177842 -60.416341 46.199254 -60.374984 46.213654 -60.351604 46.231677 -60.339127 46.243759 -60.320120 46.261946 -60.296847 46.249504 -60.270825 46.231712 -60.256352 46.216066 -60.253943 46.200990 -60.269738 46.179029 -60.308979 46.161015 -60.321453 46.152077 -60.316949 46.149237 -60.302985 46.160010 -60.274222 46.153368 -60.260117 46.137822 -60.252248 46.131241 -60.232867 46.135212 -60.216871 46.141252 -60.207283 46.153147 -60.209646 46.166404 -60.227119 46.177483 -60.232739 46.208901 -60.226953 46.219419 -60.219598 46.232951 -60.204821 46.244419 -60.178196 46.247609 -60.149187 46.244900 -60.119022 46.237705 -60.086630 46.231023 -60.077933 46.213696 -60.103429 46.200270 -60.096734 46.197396 -60.082767 46.205031 -60.056007 46.204502 -60.032340 46.184803 -59.968802 46.186039 -59.885068 46.182471 -59.858046 46.169072 -59.846142 46.160191 -59.847065 46.154762 -59.880343 46.145079 -59.884513 46.132328 -59.885385 46.117277 -59.917339 46.102265 -59.938602 46.093312 -59.934184 46.089685 -59.918056 46.097270 -59.896725 46.105537 -59.882871 46.119122 -59.857286 46.105000 -59.848584 46.096735 -59.857056 46.063717 -59.896406 46.049471 -59.919675 46.031898 -59.977221 46.018465 -59.986731 46.008241 -59.956545 46.006928 -59.920202 45.993781 -59.881526 45.980353 -59.874931 45.956021 -59.830867 45.944922 -59.820005 45.926994 -59.832615 45.933429 -59.883977 45.921940 -59.931918 45.912216 -59.946681 45.903823 -59.965788 45.908050 -60.010660 45.881877 -60.026323 45.872811 -60.048501 45.870409 -60.063386 45.868986 -60.157242 45.864219 -60.186927 45.855255 -60.193201 45.846324 -60.188756 45.833138 -60.166170 45.819875 -60.154201 45.813947 -60.142413 45.813383 -60.124199 45.804507 -60.114525 45.791027 -60.123836 45.780453 -60.147087 45.769647 -60.191574 45.767880 -60.213850 45.782649 -60.230146 45.780293 -60.244922 45.737125 -60.243052 45.728097 -60.254532 45.715241 -60.276556 45.700171 -60.297503 45.694783 -60.314407 45.701880 -60.346441 45.692668 -60.368529 45.658030 -60.408093 45.641293 -60.440550 45.617419 -60.561824 45.601961 -60.664237 45.593461 -60.688338 45.577521 -60.706965 45.569765 -60.727909 45.567064 -60.758520 45.569728 -60.782985 45.594741 -60.797560 45.601111 -60.816855 45.601459 -60.845476 45.611974 -60.883004 45.629648 -60.897351 45.649954 -60.881009 @@ -158,15 +158,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 46.06863 -60.68255 - 46.31432 -60.31030 + 46.068634 -60.682556 + 46.314326 -60.310302 - 46.06863 -60.68255 46.08885 -60.67673 46.10483 -60.64716 46.12309 -60.62409 46.16235 -60.58655 46.18281 -60.55930 46.19817 -60.52745 46.24352 -60.48030 46.28600 -60.41893 46.30881 -60.38181 46.31432 -60.35396 46.30346 -60.32144 46.28490 -60.31030 46.27137 -60.31965 46.25853 -60.33662 46.22822 -60.38428 46.22655 -60.40142 46.21560 -60.44629 46.20563 -60.46640 46.18823 -60.48632 46.16847 -60.51602 46.15544 -60.54347 46.11291 -60.60454 46.08640 -60.63586 46.07193 -60.65908 46.06863 -60.68255 + 46.068634 -60.682556 46.088853 -60.676730 46.104831 -60.647161 46.123091 -60.624097 46.162354 -60.586559 46.182819 -60.559300 46.198173 -60.527452 46.243529 -60.480305 46.286000 -60.418937 46.308813 -60.381812 46.314326 -60.353962 46.303460 -60.321443 46.284901 -60.310302 46.271372 -60.319652 46.258539 -60.336627 46.228226 -60.384283 46.226558 -60.401420 46.215606 -60.446297 46.205633 -60.466402 46.188232 -60.486328 46.168474 -60.516022 46.155447 -60.543472 46.112917 -60.604540 46.086404 -60.635868 46.071938 -60.659084 46.068634 -60.682556 @@ -178,15 +178,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 45.99438 -59.79193 - 46.03927 -59.70969 + 45.994384 -59.791931 + 46.039276 -59.709694 - 46.01509 -59.79193 46.02419 -59.75353 46.03767 -59.73340 46.03927 -59.71086 46.02584 -59.70969 46.01534 -59.72240 46.00193 -59.73199 45.99438 -59.74793 46.00099 -59.77262 46.01509 -59.79193 + 46.015090 -59.791931 46.024191 -59.753530 46.037672 -59.733403 46.039276 -59.710864 46.025845 -59.709694 46.015344 -59.722409 46.001939 -59.731993 45.994384 -59.747931 46.000997 -59.772623 46.015090 -59.791931 @@ -198,15 +198,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 45.94981 -64.46414 - 47.04029 -62.02064 + 45.949816 -64.464145 + 47.040290 -62.020645 - 46.05449 -62.49785 46.03300 -62.51661 46.03496 -62.54687 46.03418 -62.56822 46.01993 -62.59284 46.00804 -62.58991 46.00032 -62.57651 46.00641 -62.53083 45.99318 -62.52344 45.97949 -62.53216 45.97084 -62.54547 45.96509 -62.60380 45.96535 -62.65834 45.96788 -62.69069 45.96525 -62.72362 45.94981 -62.81665 45.95738 -62.85356 45.96981 -62.90060 46.01432 -62.96416 46.02739 -62.97164 46.03527 -62.96152 46.04687 -62.95184 46.05736 -62.96876 46.05764 -62.99982 46.05421 -63.03072 46.05771 -63.05459 46.07126 -63.05139 46.08628 -62.99262 46.08952 -62.96708 46.10718 -62.93528 46.12845 -62.92728 46.15073 -62.92913 46.13597 -62.98272 46.13822 -63.00223 46.16316 -62.99459 46.17719 -62.99902 46.18459 -63.01799 46.17762 -63.04315 46.18334 -63.06840 46.18772 -63.10753 46.19211 -63.12829 46.20656 -63.14030 46.22212 -63.12550 46.27070 -63.05104 46.29941 -63.04367 46.30030 -63.05891 46.28759 -63.09549 46.27158 -63.12119 46.24536 -63.14260 46.23740 -63.15262 46.24111 -63.17131 46.25563 -63.18329 46.26368 -63.20442 46.26080 -63.21936 46.25223 -63.22722 46.24260 -63.22526 46.22598 -63.21199 46.21019 -63.21382 46.20361 -63.22828 46.20099 -63.27429 46.19150 -63.30365 46.18228 -63.30922 46.17531 -63.29791 46.17312 -63.27837 46.19427 -63.20265 46.18969 -63.18729 46.18006 -63.18534 46.15991 -63.20295 46.15113 -63.23438 46.13884 -63.26024 46.13390 -63.28661 46.14330 -63.33047 46.16053 -63.43205 46.17750 -63.50244 46.19774 -63.58400 46.19962 -63.64017 46.20814 -63.68197 46.23691 -63.73756 46.28649 -63.80939 46.33444 -63.86938 46.34244 -63.85935 46.34656 -63.83600 46.33888 -63.80931 46.32768 -63.77688 46.33286 -63.76332 46.34335 -63.76227 46.35211 -63.76748 46.36418 -63.79679 46.38352 -63.81385 46.39061 -63.83841 46.38063 -63.90436 46.37893 -63.92367 46.39813 -63.95921 46.40044 -63.98653 46.37680 -64.01103 46.37019 -64.03842 46.37503 -64.07468 46.38964 -64.12604 46.39031 -64.14121 46.39781 -64.15499 46.41500 -64.17090 46.43082 -64.16940 46.46046 -64.14670 46.49174 -64.14906 46.52248 -64.16217 46.53946 -64.13912 46.55044 -64.11418 46.55694 -64.10517 46.57056 -64.10227 46.59207 -64.12093 46.61190 -64.12745 46.61724 -64.14003 46.60962 -64.15763 46.58238 -64.16341 46.57779 -64.17913 46.61318 -64.31790 46.61451 -64.34851 46.60631 -64.40302 46.61293 -64.43312 46.62658 -64.45650 46.64493 -64.46414 46.67128 -64.46185 46.71435 -64.44175 46.75799 -64.39782 46.78555 -64.36052 46.83038 -64.30775 46.84767 -64.29231 46.88736 -64.26616 46.91546 -64.24409 46.94013 -64.20313 46.98252 -64.12227 47.00040 -64.09578 47.02237 -64.07732 47.03708 -64.05263 47.04029 -64.01891 47.02471 -64.01510 46.98389 -64.03687 46.95782 -64.04729 46.94355 -64.04793 46.91516 -64.03057 46.87944 -64.02561 46.86398 -64.03495 46.81703 -64.07364 46.78037 -64.11655 46.75734 -64.16966 46.73816 -64.17838 46.73523 -64.14872 46.72435 -64.14193 46.70418 -64.14089 46.68983 -64.12841 46.68738 -64.08788 46.69701 -64.09004 46.70486 -64.09841 46.71806 -64.08791 46.72050 -64.07069 46.70947 -64.05100 46.71032 -64.03470 46.70525 -64.01677 46.65562 -63.97555 46.64149 -63.95769 46.63139 -63.93486 46.62267 -63.92970 46.61035 -63.93707 46.59878 -63.97280 46.58828 -63.97380 46.58138 -63.96228 46.58758 -63.92702 46.58126 -63.91769 46.55423 -63.90507 46.54220 -63.90713 46.52649 -63.92176 46.50028 -63.98185 46.47410 -64.01052 46.45832 -64.01218 46.45479 -63.99334 46.46916 -63.97424 46.48546 -63.94885 46.49643 -63.92401 46.50171 -63.89213 46.49634 -63.87962 46.48355 -63.86637 46.45011 -63.87591 46.44437 -63.85582 46.44131 -63.82626 46.43386 -63.79409 46.43759 -63.76309 46.45300 -63.75375 46.47420 -63.76460 46.49446 -63.77866 46.51448 -63.76649 46.52736 -63.77966 46.53592 -63.77193 46.54827 -63.73305 46.55956 -63.71573 46.55623 -63.69154 46.54316 -63.63376 46.52821 -63.60085 46.51505 -63.56161 46.50260 -63.55604 46.49096 -63.56578 46.47088 -63.59637 46.45685 -63.59172 46.45387 -63.57518 46.46538 -63.55255 46.47224 -63.53262 46.46525 -63.52109 46.45420 -63.50160 46.48146 -63.47709 46.50251 -63.47478 46.48195 -63.39814 46.47459 -63.36069 46.45773 -63.35262 46.43510 -63.37434 46.42108 -63.36977 46.42447 -63.34417 46.43418 -63.30925 46.42720 -63.29787 46.40922 -63.29845 46.39833 -63.29204 46.39457 -63.27333 46.40117 -63.25882 46.41389 -63.24038 46.41901 -63.20842 46.39981 -63.13111 46.39494 -63.10258 46.38131 -63.08737 46.36004 -63.07687 46.35613 -63.06356 46.36376 -63.04057 46.39313 -63.03545 46.40611 -63.04837 46.41392 -63.01994 46.42362 -62.92441 46.41825 -62.88830 46.41012 -62.86716 46.42232 -62.84103 46.42356 -62.80877 46.42151 -62.78366 46.39836 -62.70087 46.39776 -62.65652 46.40681 -62.63237 46.41728 -62.63105 46.42434 -62.64231 46.42598 -62.70189 46.44281 -62.75185 46.45509 -62.74410 46.45609 -62.71713 46.45420 -62.64461 46.45599 -62.61447 46.45519 -62.55163 46.46069 -62.45581 46.45046 -62.40418 46.46057 -62.27614 46.46030 -62.18637 46.45583 -62.13635 46.44685 -62.08925 46.44837 -62.03535 46.43832 -62.02064 46.42853 -62.02436 46.42149 -62.03693 46.40243 -62.09951 46.39315 -62.11077 46.37680 -62.15835 46.35884 -62.18298 46.33741 -62.22590 46.33344 -62.25475 46.33598 -62.26889 46.35451 -62.29926 46.35397 -62.31547 46.34277 -62.33836 46.34223 -62.37825 46.33187 -62.39808 46.32133 -62.39952 46.30834 -62.38675 46.29917 -62.39252 46.29419 -62.40623 46.28577 -62.41419 46.27100 -62.40786 46.25712 -62.42197 46.25083 -62.45491 46.25577 -62.48323 46.24696 -62.50204 46.23821 -62.49703 46.23211 -62.47728 46.22151 -62.46040 46.21016 -62.46497 46.20525 -62.47859 46.20666 -62.50120 46.20137 -62.52566 46.21144 -62.55862 46.21186 -62.58979 46.19803 -62.59848 46.18918 -62.57524 46.17115 -62.55773 46.16533 -62.57453 46.17215 -62.61489 46.15876 -62.61284 46.14410 -62.58270 46.13099 -62.57532 46.11070 -62.55671 46.11585 -62.53769 46.13048 -62.52585 46.13383 -62.51322 46.12985 -62.50002 46.12040 -62.49295 46.10478 -62.48965 46.07229 -62.50233 46.05449 -62.49785 + 46.054498 -62.497853 46.033009 -62.516619 46.034969 -62.546876 46.034185 -62.568223 46.019937 -62.592840 46.008042 -62.589912 46.000325 -62.576516 46.006410 -62.530834 45.993184 -62.523441 45.979499 -62.532164 45.970843 -62.545473 45.965091 -62.603808 45.965352 -62.658349 45.967882 -62.690694 45.965250 -62.723626 45.949816 -62.816659 45.957382 -62.853567 45.969811 -62.900600 46.014321 -62.964168 46.027392 -62.971646 46.035279 -62.961529 46.046873 -62.951842 46.057369 -62.968766 46.057648 -62.999822 46.054216 -63.030723 46.057714 -63.054591 46.071269 -63.051393 46.086286 -62.992627 46.089526 -62.967081 46.107189 -62.935281 46.128452 -62.927287 46.150730 -62.929130 46.135973 -62.982728 46.138221 -63.002237 46.163160 -62.994596 46.177192 -62.999021 46.184592 -63.017998 46.177627 -63.043154 46.183344 -63.068409 46.187720 -63.107538 46.192119 -63.128290 46.206565 -63.140303 46.222121 -63.125505 46.270708 -63.051049 46.299412 -63.043678 46.300308 -63.058910 46.287596 -63.095490 46.271586 -63.121191 46.245364 -63.142606 46.237407 -63.152626 46.241110 -63.171313 46.255632 -63.183296 46.263682 -63.204428 46.260804 -63.219364 46.252232 -63.227222 46.242600 -63.225263 46.225987 -63.211993 46.210199 -63.213825 46.203611 -63.228284 46.200994 -63.274298 46.191505 -63.303653 46.182283 -63.309223 46.175313 -63.297912 46.173128 -63.278372 46.194270 -63.202654 46.189697 -63.187290 46.180067 -63.185341 46.159917 -63.202955 46.151138 -63.234386 46.138843 -63.260244 46.133907 -63.286612 46.143304 -63.330474 46.160531 -63.432051 46.177506 -63.502449 46.197742 -63.584001 46.199628 -63.640178 46.208142 -63.681971 46.236919 -63.737564 46.286497 -63.809399 46.334449 -63.869384 46.342445 -63.859358 46.346565 -63.836008 46.338888 -63.809314 46.327684 -63.776887 46.332864 -63.763324 46.343350 -63.762274 46.352112 -63.767488 46.364183 -63.796795 46.383525 -63.813856 46.390611 -63.838414 46.380632 -63.904361 46.378939 -63.923678 46.398136 -63.959215 46.400448 -63.986533 46.376808 -64.011034 46.370193 -64.038420 46.375031 -64.074682 46.389642 -64.126048 46.390315 -64.141215 46.397813 -64.154999 46.415006 -64.170902 46.430825 -64.169409 46.460465 -64.146706 46.491741 -64.149067 46.522481 -64.162178 46.539466 -64.139121 46.550449 -64.114182 46.556940 -64.105176 46.570560 -64.102270 46.592070 -64.120931 46.611908 -64.127459 46.617249 -64.140038 46.609627 -64.157637 46.582380 -64.163417 46.577798 -64.179131 46.613188 -64.317908 46.614512 -64.348516 46.606312 -64.403024 46.612939 -64.433122 46.626583 -64.456507 46.644936 -64.464145 46.671283 -64.461857 46.714357 -64.441755 46.757994 -64.397820 46.785550 -64.360527 46.830383 -64.307757 46.847672 -64.292318 46.887364 -64.266167 46.915461 -64.244092 46.940137 -64.203137 46.982520 -64.122270 47.000404 -64.095781 47.022379 -64.077323 47.037086 -64.052631 47.040290 -64.018913 47.024716 -64.015106 46.983890 -64.036878 46.957826 -64.047295 46.943557 -64.047934 46.915161 -64.030578 46.879442 -64.025612 46.863982 -64.034953 46.817032 -64.073642 46.780374 -64.116557 46.757340 -64.169663 46.738162 -64.178386 46.735239 -64.148720 46.724353 -64.141930 46.704180 -64.140894 46.689835 -64.128411 46.687388 -64.087880 46.697019 -64.090049 46.704860 -64.098410 46.718069 -64.087913 46.720505 -64.070690 46.709478 -64.051006 46.710329 -64.034703 46.705255 -64.016772 46.655620 -63.975558 46.641494 -63.957699 46.631394 -63.934867 46.622672 -63.929701 46.610356 -63.937076 46.598780 -63.972803 46.588280 -63.973809 46.581380 -63.962288 46.587583 -63.927028 46.581268 -63.917692 46.554234 -63.905079 46.542200 -63.907131 46.526499 -63.921762 46.500282 -63.981854 46.474104 -64.010522 46.458326 -64.012189 46.454791 -63.993340 46.469160 -63.974246 46.485464 -63.948859 46.496434 -63.924018 46.501716 -63.892139 46.496345 -63.879622 46.483556 -63.866370 46.450111 -63.875915 46.444379 -63.855825 46.441315 -63.826265 46.433860 -63.794095 46.437597 -63.763099 46.453001 -63.753753 46.474204 -63.764601 46.494465 -63.778660 46.514486 -63.766496 46.527369 -63.779668 46.535920 -63.771930 46.548278 -63.733054 46.559566 -63.715735 46.556233 -63.691543 46.543164 -63.633768 46.528218 -63.600859 46.515051 -63.561613 46.502601 -63.556045 46.490962 -63.565786 46.470880 -63.596370 46.456858 -63.591722 46.453879 -63.575188 46.465388 -63.552552 46.472247 -63.532627 46.465254 -63.521092 46.454201 -63.501600 46.481461 -63.477090 46.502518 -63.474781 46.481952 -63.398141 46.474591 -63.360699 46.457736 -63.352620 46.435109 -63.374347 46.421080 -63.369776 46.424473 -63.344178 46.434183 -63.309251 46.427205 -63.297872 46.409225 -63.298454 46.398337 -63.292042 46.394577 -63.273336 46.401178 -63.258821 46.413898 -63.240388 46.419019 -63.208424 46.399810 -63.131116 46.394945 -63.102581 46.381319 -63.087375 46.360047 -63.076879 46.356138 -63.063563 46.363768 -63.040575 46.393137 -63.035454 46.406117 -63.048375 46.413929 -63.019940 46.423626 -62.924414 46.418257 -62.888309 46.410129 -62.867161 46.422327 -62.841034 46.423561 -62.808771 46.421516 -62.783660 46.398364 -62.700871 46.397763 -62.656523 46.406815 -62.632373 46.417289 -62.631052 46.424349 -62.642319 46.425988 -62.701897 46.442812 -62.751851 46.455099 -62.744108 46.456091 -62.717133 46.454205 -62.644615 46.455991 -62.614477 46.455193 -62.551633 46.460698 -62.455812 46.450468 -62.404184 46.460575 -62.276147 46.460303 -62.186376 46.455833 -62.136351 46.446856 -62.089255 46.448370 -62.035351 46.438320 -62.020645 46.428533 -62.024368 46.421493 -62.036934 46.402437 -62.099510 46.393152 -62.110777 46.376801 -62.158351 46.358849 -62.182987 46.337410 -62.225901 46.333443 -62.254756 46.335985 -62.268898 46.354512 -62.299267 46.353970 -62.315470 46.342773 -62.338367 46.342230 -62.378254 46.331875 -62.398082 46.321331 -62.399522 46.308342 -62.386752 46.299171 -62.392525 46.294195 -62.406236 46.285771 -62.414197 46.271001 -62.407866 46.257120 -62.421972 46.250834 -62.454916 46.255776 -62.483236 46.246966 -62.502043 46.238215 -62.497031 46.232112 -62.477283 46.221517 -62.460409 46.210160 -62.464978 46.205252 -62.478590 46.206668 -62.501200 46.201371 -62.525663 46.211445 -62.558629 46.211864 -62.589790 46.198039 -62.598486 46.189188 -62.575245 46.171155 -62.557735 46.165337 -62.574532 46.172150 -62.614894 46.158763 -62.612840 46.144102 -62.582703 46.130992 -62.575321 46.110703 -62.556716 46.115852 -62.537690 46.130485 -62.525851 46.133837 -62.513225 46.129850 -62.500027 46.120403 -62.492953 46.104789 -62.489650 46.072291 -62.502332 46.054498 -62.497853 @@ -218,15 +218,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 45.45817 -61.14640 - 45.57614 -60.90345 + 45.458170 -61.146404 + 45.576146 -60.903456 - 45.46158 -61.06156 45.47786 -61.06640 45.48613 -61.05833 45.49544 -61.04181 45.50863 -61.04863 45.50985 -61.06355 45.50627 -61.09722 45.53218 -61.14272 45.54621 -61.14640 45.55457 -61.13827 45.56531 -61.08149 45.57245 -61.05842 45.57127 -61.04359 45.56733 -61.01483 45.57614 -60.97494 45.57301 -60.94298 45.57287 -60.90910 45.56179 -60.90345 45.55114 -60.91575 45.54872 -60.93052 45.54585 -60.96632 45.53933 -60.99681 45.52582 -61.00591 45.49392 -60.99834 45.48174 -61.01685 45.46219 -61.02995 45.45817 -61.04557 45.46158 -61.06156 + 45.461588 -61.061562 45.477860 -61.066405 45.486135 -61.058336 45.495441 -61.041811 45.508633 -61.048638 45.509854 -61.063551 45.506274 -61.097225 45.532182 -61.142729 45.546215 -61.146404 45.554578 -61.138277 45.565318 -61.081499 45.572456 -61.058421 45.571279 -61.043595 45.567330 -61.014833 45.576146 -60.974940 45.573014 -60.942987 45.572876 -60.909103 45.561792 -60.903456 45.551148 -60.915757 45.548728 -60.930529 45.545854 -60.966328 45.539334 -60.996814 45.525826 -61.005913 45.493926 -60.998348 45.481743 -61.016851 45.462193 -61.029951 45.458170 -61.045573 45.461588 -61.061562 @@ -238,15 +238,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 45.47629 -60.97763 - 45.49487 -60.93785 + 45.476290 -60.977631 + 45.494872 -60.937854 - 45.47795 -60.97763 45.49304 -60.96764 45.49487 -60.94549 45.48687 -60.93785 45.47629 -60.94481 45.47795 -60.97763 + 45.477957 -60.977631 45.493045 -60.967647 45.494872 -60.945495 45.486875 -60.937854 45.476290 -60.944814 45.477957 -60.977631 @@ -258,15 +258,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 46.57850 -63.86379 - 46.62738 -63.77514 + 46.578504 -63.863796 + 46.627388 -63.775140 - 46.58244 -63.83307 46.60437 -63.85922 46.62738 -63.86379 46.62386 -63.84500 46.61144 -63.82089 46.59398 -63.77888 46.57850 -63.77514 46.57914 -63.80885 46.58244 -63.83307 + 46.582447 -63.833071 46.604373 -63.859226 46.627388 -63.863796 46.623862 -63.845001 46.611443 -63.820895 46.593980 -63.778884 46.578504 -63.775140 46.579144 -63.808857 46.582447 -63.833071 @@ -278,15 +278,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 43.44796 -66.23693 - 45.98282 -61.00979 + 43.447966 -66.236930 + 45.982824 -61.009794 - 45.98282 -63.99398 45.98180 -63.97255 45.97346 -63.94384 45.96122 -63.92012 45.89396 -63.83083 45.87592 -63.78724 45.85825 -63.72037 45.86714 -63.68913 45.87983 -63.62732 45.87865 -63.60473 45.86944 -63.56118 45.87440 -63.53489 45.86911 -63.48631 45.85676 -63.46277 45.84583 -63.45646 45.83942 -63.46541 45.82111 -63.55652 45.81303 -63.57177 45.80427 -63.56666 45.79739 -63.53724 45.80505 -63.48357 45.80718 -63.45384 45.80726 -63.41761 45.79490 -63.39412 45.79125 -63.37560 45.80320 -63.32444 45.80122 -63.29972 45.79518 -63.28534 45.78557 -63.28339 45.76781 -63.31482 45.75120 -63.38696 45.73480 -63.38646 45.71098 -63.33643 45.70724 -63.31801 45.71953 -63.31055 45.73484 -63.30120 45.73864 -63.26542 45.75980 -63.23957 45.76272 -63.22491 45.75395 -63.21987 45.74017 -63.22822 45.73340 -63.21169 45.73696 -63.19928 45.75028 -63.18334 45.75857 -63.14461 45.75246 -63.11212 45.75685 -63.09659 45.76997 -63.10400 45.77932 -63.12936 45.79508 -63.12752 45.80190 -63.10777 45.80052 -63.08530 45.79439 -63.05278 45.76828 -62.96013 45.76403 -62.91604 45.74080 -62.80350 45.72278 -62.76806 45.71416 -62.73969 45.71111 -62.70013 45.70256 -62.68980 45.68358 -62.69912 45.67409 -62.73348 45.67216 -62.80449 45.66638 -62.82101 45.64975 -62.80806 45.64508 -62.79281 45.62305 -62.80388 45.61233 -62.79238 45.60877 -62.76877 45.62633 -62.75528 45.62695 -62.73935 45.62009 -62.72294 45.61306 -62.71186 45.60862 -62.69125 45.61510 -62.67690 45.63113 -62.68768 45.63911 -62.71375 45.65501 -62.70644 45.66105 -62.68463 45.66790 -62.61820 45.65580 -62.60246 45.64634 -62.59533 45.64183 -62.57488 45.64230 -62.54095 45.62372 -62.53960 45.61282 -62.53349 45.60958 -62.51740 45.62082 -62.49475 45.62361 -62.43336 45.63128 -62.40525 45.64479 -62.40189 45.64952 -62.41710 45.64455 -62.45393 45.64554 -62.46892 45.65597 -62.46758 45.66413 -62.44691 45.68520 -62.35055 45.73170 -62.22491 45.77555 -62.13189 45.82272 -62.04964 45.84833 -62.01489 45.87034 -61.97469 45.87852 -61.94846 45.87605 -61.92912 45.86975 -61.91480 45.85935 -61.91639 45.84183 -61.95372 45.82378 -61.96019 45.78981 -61.95068 45.72754 -61.93850 45.70509 -61.94256 45.66417 -61.96886 45.64454 -61.97615 45.62855 -61.96568 45.62048 -61.93441 45.62461 -61.91871 45.65036 -61.93087 45.66246 -61.92310 45.66695 -61.89676 45.66447 -61.87751 45.65001 -61.86072 45.63377 -61.85557 45.62184 -61.85813 45.61247 -61.84594 45.61607 -61.82280 45.62771 -61.80752 45.62237 -61.75625 45.61959 -61.69035 45.62383 -61.66941 45.63155 -61.65915 45.63520 -61.63065 45.64580 -61.62372 45.65622 -61.62219 45.66409 -61.60670 45.66982 -61.58463 45.66704 -61.54734 45.62157 -61.45173 45.59688 -61.42623 45.57107 -61.41438 45.54499 -61.38453 45.53329 -61.37668 45.52451 -61.36671 45.51628 -61.33574 45.51526 -61.31543 45.50673 -61.29507 45.49091 -61.26892 45.47754 -61.26730 45.45254 -61.29161 45.43340 -61.31717 45.42126 -61.36414 45.40808 -61.38575 45.40266 -61.39704 45.39935 -61.44336 45.38924 -61.46299 45.38519 -61.47865 45.42257 -61.53212 45.43817 -61.56352 45.44194 -61.59224 45.43708 -61.61102 45.42669 -61.60731 45.41152 -61.56004 45.40226 -61.54278 45.37506 -61.53193 45.35316 -61.51502 45.33889 -61.48798 45.33220 -61.45603 45.33724 -61.43203 45.34266 -61.38694 45.34036 -61.35731 45.32795 -61.31351 45.32548 -61.28925 45.33680 -61.24547 45.33030 -61.19778 45.33272 -61.15463 45.32148 -61.12044 45.31824 -61.05503 45.30632 -61.01880 45.29232 -61.00979 45.27226 -61.01018 45.26901 -61.02263 45.28059 -61.04093 45.27738 -61.05348 45.26171 -61.05603 45.22863 -61.07796 45.20038 -61.11994 45.19370 -61.15534 45.19922 -61.17761 45.20723 -61.18535 45.23814 -61.16242 45.25015 -61.15975 45.26999 -61.17007 45.27557 -61.18709 45.27234 -61.19963 45.25577 -61.21041 45.22609 -61.20923 45.21254 -61.21809 45.22612 -61.24285 45.23449 -61.26843 45.23097 -61.29671 45.23421 -61.31781 45.23075 -61.34079 45.21891 -61.37180 45.19814 -61.40345 45.18478 -61.40180 45.17868 -61.37743 45.18625 -61.33881 45.17993 -61.31968 45.16446 -61.31690 45.15727 -61.33973 45.15030 -61.41918 45.14317 -61.43671 45.13658 -61.46679 45.13264 -61.50538 45.13866 -61.53512 45.13956 -61.56037 45.13450 -61.58425 45.13205 -61.62186 45.15088 -61.70262 45.14510 -61.72431 45.13670 -61.73225 45.12570 -61.69808 45.11580 -61.67871 45.10045 -61.69891 45.07100 -61.68688 45.06624 -61.70024 45.07645 -61.73745 45.06467 -61.78607 45.07760 -61.83187 45.07349 -61.84740 45.05860 -61.84658 45.04993 -61.86490 45.03882 -61.86434 45.02755 -61.86894 45.02041 -61.88629 45.03106 -61.90258 45.03586 -61.91753 45.02059 -61.93235 45.02452 -61.95044 45.04280 -61.98501 45.03191 -62.00217 45.02398 -61.99432 45.01089 -61.98729 45.00533 -61.99847 45.00426 -62.03500 44.99325 -62.08044 44.98755 -62.09685 44.97707 -62.07528 44.98071 -62.05248 44.97903 -62.03564 44.97357 -62.01852 44.96464 -62.01905 44.95846 -62.05118 44.95278 -62.14179 44.94374 -62.17040 44.93181 -62.19586 44.92592 -62.21738 44.93400 -62.24296 44.93551 -62.26504 44.92271 -62.29342 44.90400 -62.32044 44.89914 -62.33368 44.89982 -62.35880 44.89049 -62.36970 44.87994 -62.37628 44.87330 -62.39573 44.87717 -62.41363 44.87363 -62.43121 44.84306 -62.47807 44.84315 -62.49591 44.86694 -62.49651 44.87307 -62.51048 44.86885 -62.52587 44.85236 -62.53094 44.83951 -62.53628 44.83358 -62.55782 44.83718 -62.58101 44.79058 -62.57657 44.77825 -62.58930 44.78212 -62.60728 44.80154 -62.62324 44.80885 -62.64665 44.79649 -62.65936 44.78922 -62.67650 44.77248 -62.68679 44.76757 -62.69994 44.77417 -62.72133 44.77653 -62.75789 44.76252 -62.79435 44.76189 -62.80998 44.78592 -62.84098 44.78736 -62.86295 44.78390 -62.87523 44.77277 -62.87433 44.76249 -62.85268 44.74720 -62.84423 44.73490 -62.85682 44.70440 -62.83989 44.69509 -62.85058 44.69381 -62.86400 44.70733 -62.89626 44.70967 -62.93288 44.70576 -62.97315 44.69538 -63.00975 44.70107 -63.03418 44.72280 -63.04635 44.74501 -63.04814 44.76020 -63.05671 44.76789 -63.06976 44.75438 -63.09067 44.74200 -63.08544 44.71742 -63.06978 44.69085 -63.06554 44.67282 -63.07141 44.67174 -63.09732 44.69478 -63.11371 44.70894 -63.13055 44.73935 -63.12994 44.75113 -63.13309 44.75853 -63.15144 44.75070 -63.16107 44.69850 -63.16711 44.67951 -63.17592 44.67590 -63.19331 44.68607 -63.19727 44.71371 -63.19345 44.73372 -63.19402 44.73894 -63.21119 44.73000 -63.22912 44.68672 -63.23479 44.66773 -63.24357 44.67362 -63.26274 44.69491 -63.26771 44.70488 -63.27691 44.67769 -63.30580 44.65505 -63.29650 44.64529 -63.29980 44.63657 -63.31257 44.61282 -63.32925 44.62313 -63.38102 44.61778 -63.41691 44.62356 -63.43614 44.65330 -63.45125 44.66368 -63.46788 44.66446 -63.48247 44.65943 -63.49551 44.63660 -63.49131 44.60981 -63.46191 44.58642 -63.48578 44.58571 -63.50117 44.59608 -63.51778 44.60091 -63.55762 44.63726 -63.58915 44.64478 -63.60231 44.66100 -63.62047 44.67410 -63.64042 44.69605 -63.67790 44.69535 -63.69343 44.66208 -63.69034 44.64654 -63.67417 44.63098 -63.62804 44.62190 -63.61577 44.60901 -63.62077 44.59063 -63.60144 44.57791 -63.58882 44.55573 -63.58677 44.53772 -63.59225 44.52289 -63.59087 44.50667 -63.57277 44.48720 -63.56159 44.44753 -63.58491 44.44685 -63.60036 44.45305 -63.60928 44.45752 -63.62410 44.45312 -63.63924 44.43808 -63.64304 44.43063 -63.65988 44.43141 -63.67450 44.44660 -63.68316 44.45525 -63.71817 44.45063 -63.75089 44.45968 -63.76314 44.46569 -63.77711 44.45925 -63.81589 44.46373 -63.83084 44.48277 -63.83475 44.48701 -63.85491 44.47472 -63.89200 44.48965 -63.94844 44.49845 -63.96593 44.51482 -63.97897 44.53751 -63.97093 44.55452 -63.95603 44.57298 -63.95792 44.60447 -63.96739 44.61977 -63.95849 44.65636 -63.92477 44.65079 -63.96063 44.63595 -63.98932 44.61740 -64.06023 44.60528 -64.07973 44.59393 -64.08374 44.55639 -64.07766 44.52940 -64.08323 44.49535 -64.05276 44.48495 -64.05370 44.47587 -64.08387 44.45855 -64.10377 44.45250 -64.11974 44.46687 -64.15651 44.47975 -64.16407 44.50869 -64.16507 44.52937 -64.18073 44.54703 -64.21071 44.54838 -64.23993 44.52537 -64.25293 44.52456 -64.28092 44.53034 -64.33762 44.51628 -64.35060 44.47480 -64.34913 44.46594 -64.36166 44.44194 -64.35267 44.43244 -64.36316 44.42730 -64.38837 44.41049 -64.39789 44.39537 -64.38899 44.38954 -64.37492 44.39947 -64.34182 44.39822 -64.32512 44.38986 -64.31496 44.37393 -64.32151 44.36032 -64.28689 44.34709 -64.28443 44.33977 -64.29597 44.34792 -64.33618 44.33970 -64.36316 44.32714 -64.37528 44.31180 -64.37141 44.31042 -64.34239 44.31135 -64.32705 44.30147 -64.31760 44.27481 -64.33023 44.27750 -64.29649 44.27067 -64.28539 44.25617 -64.27874 44.24271 -64.29373 44.23489 -64.31555 44.24020 -64.33989 44.27832 -64.37290 44.28212 -64.38578 44.27078 -64.40196 44.25515 -64.40342 44.24504 -64.42395 44.22510 -64.43513 44.21816 -64.46632 44.14342 -64.52789 44.13246 -64.57603 44.12788 -64.65272 44.11774 -64.66090 44.10615 -64.63274 44.10730 -64.60004 44.09170 -64.58890 44.05398 -64.61235 44.04812 -64.62297 44.04815 -64.64765 44.04354 -64.66245 44.03253 -64.67357 44.02177 -64.70410 43.99448 -64.71426 43.96938 -64.72575 43.95921 -64.74608 43.94882 -64.75917 43.93924 -64.79397 43.92845 -64.82441 43.92440 -64.85363 43.90969 -64.87641 43.89497 -64.87475 43.88673 -64.86443 43.87792 -64.82763 43.85895 -64.81097 43.84917 -64.81390 43.84361 -64.83173 43.83652 -64.85022 43.82392 -64.86207 43.81659 -64.87349 43.82730 -64.89214 43.85113 -64.90117 43.86454 -64.93553 43.86138 -64.94948 43.85127 -64.95738 43.83387 -64.92772 43.79498 -64.93427 43.78760 -64.94556 43.79119 -64.95829 43.81939 -64.96988 43.83978 -64.98572 43.83825 -64.99877 43.82653 -65.00764 43.79084 -64.98793 43.77187 -64.98349 43.75190 -64.99431 43.75299 -65.02305 43.77348 -65.03894 43.78782 -65.04582 43.79722 -65.06021 43.79628 -65.07541 43.77604 -65.07903 43.73541 -65.05460 43.70107 -65.07075 43.68747 -65.09757 43.70421 -65.11294 43.71394 -65.12234 43.71027 -65.13411 43.67766 -65.15658 43.65194 -65.16558 43.64907 -65.18653 43.67104 -65.18936 43.69071 -65.18373 43.70074 -65.18805 43.69658 -65.21709 43.74845 -65.25026 43.75416 -65.26436 43.75276 -65.28460 43.73704 -65.29788 43.72761 -65.29571 43.70626 -65.28264 43.67931 -65.28741 43.65872 -65.29591 43.65134 -65.30721 43.65904 -65.33466 43.66729 -65.34496 43.67731 -65.34930 43.70611 -65.35103 43.71722 -65.37196 43.71375 -65.39087 43.70510 -65.39789 43.63207 -65.38321 43.61044 -65.37522 43.58270 -65.38992 43.56809 -65.38805 43.55214 -65.39411 43.54687 -65.40663 43.54237 -65.42832 43.54345 -65.44484 43.55832 -65.45397 43.56344 -65.46571 43.55586 -65.48923 43.53640 -65.48256 43.52313 -65.46048 43.51129 -65.44970 43.48813 -65.44260 43.47824 -65.44532 43.47026 -65.45440 43.48962 -65.47324 43.50357 -65.48527 43.49428 -65.50239 43.47135 -65.50238 43.45536 -65.50829 43.44796 -65.51952 43.46698 -65.54344 43.48540 -65.59672 43.51281 -65.60651 43.51808 -65.62554 43.51054 -65.64895 43.50030 -65.65670 43.48384 -65.67981 43.47641 -65.71037 43.47714 -65.73178 43.47214 -65.75852 43.47535 -65.77624 43.48442 -65.78356 43.49636 -65.78224 43.50864 -65.77584 43.51526 -65.78697 43.52557 -65.81780 43.53829 -65.82577 43.56683 -65.82054 43.59725 -65.80960 43.64235 -65.80059 43.65785 -65.81197 43.65828 -65.82637 43.64802 -65.83410 43.62969 -65.83150 43.61620 -65.83372 43.58846 -65.84809 43.61167 -65.87487 43.62592 -65.88198 43.68868 -65.88582 43.73416 -65.87178 43.76061 -65.88487 43.76645 -65.90605 43.76378 -65.92202 43.77616 -65.93516 43.79772 -65.94334 43.80644 -65.95584 43.80627 -65.96811 43.79757 -65.97504 43.78239 -65.97080 43.77157 -65.97644 43.76341 -65.98544 43.76873 -66.00467 43.77947 -66.01852 43.76236 -66.03957 43.73707 -66.01133 43.72270 -66.00411 43.71021 -66.00332 43.69475 -66.01126 43.68995 -66.02592 43.68902 -66.04822 43.67663 -66.05463 43.67469 -66.07988 43.68321 -66.08523 43.70291 -66.07988 43.70949 -66.09110 43.70503 -66.12007 43.71254 -66.12839 43.72660 -66.12843 43.74028 -66.13345 43.74065 -66.14789 43.74525 -66.16489 43.77534 -66.17866 43.78310 -66.19411 43.80715 -66.19872 43.83510 -66.21112 43.86042 -66.20059 43.87567 -66.20487 43.89113 -66.21644 43.92608 -66.19597 43.96184 -66.20442 44.00820 -66.20011 44.03735 -66.21679 44.07638 -66.23097 44.10258 -66.23693 44.13126 -66.23200 44.20379 -66.18721 44.23386 -66.17410 44.30255 -66.16062 44.32418 -66.14934 44.35965 -66.12352 44.37992 -66.10069 44.42467 -66.05019 44.46070 -65.98700 44.51464 -65.91161 44.53934 -65.89860 44.55647 -65.90943 44.56171 -65.92894 44.54913 -65.96773 44.55360 -65.99749 44.54844 -66.01761 44.49052 -66.08486 44.46748 -66.10429 44.42855 -66.15672 44.40139 -66.18063 44.39322 -66.18981 44.38020 -66.21386 44.38265 -66.22970 44.39639 -66.23493 44.41136 -66.22473 44.43520 -66.19517 44.45947 -66.16034 44.49450 -66.13957 44.50790 -66.11037 44.55523 -66.05608 44.58880 -65.96048 44.64573 -65.87399 44.65864 -65.83554 44.65646 -65.81444 44.64711 -65.79951 44.62691 -65.79037 44.59899 -65.78531 44.58066 -65.75042 44.58097 -65.72557 44.58903 -65.69648 44.61113 -65.66734 44.61984 -65.66023 44.64571 -65.63146 44.67242 -65.59973 44.69378 -65.56090 44.72362 -65.49510 44.73672 -65.47809 44.76169 -65.47204 44.76023 -65.49272 44.74588 -65.51793 44.71108 -65.61136 44.67711 -65.68179 44.65742 -65.75935 44.66061 -65.77742 44.67031 -65.78715 44.68073 -65.78660 44.69852 -65.76720 44.72203 -65.72988 44.75263 -65.66621 44.76981 -65.64450 44.80234 -65.56229 44.84323 -65.46533 44.88354 -65.39855 44.90961 -65.33175 44.94710 -65.26124 45.00895 -65.15701 45.03001 -65.13034 45.04845 -65.08748 45.07142 -65.04204 45.11271 -64.95375 45.12151 -64.92110 45.12617 -64.89322 45.14602 -64.82409 45.17173 -64.71874 45.23932 -64.47797 45.25713 -64.45254 45.27072 -64.44993 45.27998 -64.45728 45.29273 -64.48296 45.30356 -64.51488 45.31373 -64.53188 45.32760 -64.52401 45.31858 -64.47324 45.29403 -64.39344 45.28069 -64.37822 45.25664 -64.36918 45.22798 -64.38808 45.21080 -64.40293 45.18616 -64.41701 45.17445 -64.41360 45.15072 -64.39941 45.13776 -64.40424 45.11993 -64.42952 45.10884 -64.42834 45.09897 -64.41880 45.08993 -64.39362 45.09391 -64.37622 45.11173 -64.36345 45.11482 -64.34908 45.10663 -64.32086 45.07781 -64.27669 45.03940 -64.23045 45.01926 -64.21670 44.98571 -64.20579 44.97797 -64.19756 44.96879 -64.15990 44.96526 -64.12918 44.97100 -64.10569 44.98233 -64.10155 44.98913 -64.11285 44.99207 -64.12883 44.99311 -64.15099 45.00553 -64.16913 45.03010 -64.15497 45.05013 -64.16864 45.08091 -64.21921 45.10817 -64.23902 45.12606 -64.23883 45.16134 -64.21848 45.18648 -64.19387 45.19746 -64.16980 45.22368 -64.06825 45.24957 -63.94123 45.27200 -63.86450 45.29098 -63.81266 45.29823 -63.80069 45.29903 -63.78490 45.29673 -63.77100 45.30138 -63.73767 45.30873 -63.70782 45.30414 -63.67986 45.29536 -63.64425 45.30431 -63.56493 45.30070 -63.54660 45.27665 -63.52015 45.28169 -63.50694 45.29919 -63.49906 45.31374 -63.50567 45.32734 -63.48479 45.33963 -63.47745 45.35326 -63.48718 45.35714 -63.51817 45.35608 -63.55716 45.37664 -63.62666 45.37111 -63.68112 45.37329 -63.74367 45.38039 -63.78032 45.38066 -63.80573 45.35106 -63.90740 45.34666 -63.93541 45.35149 -63.95807 45.36191 -63.98778 45.36888 -64.01169 45.37179 -64.04062 45.37050 -64.06685 45.37214 -64.09132 45.38626 -64.12142 45.38764 -64.15119 45.38039 -64.17572 45.37898 -64.20201 45.38705 -64.21773 45.38808 -64.24008 45.38300 -64.26595 45.37286 -64.28704 45.36649 -64.30859 45.36182 -64.39260 45.35096 -64.46749 45.35349 -64.48896 45.37951 -64.55534 45.38817 -64.58607 45.39344 -64.63638 45.38603 -64.67370 45.37026 -64.71298 45.35334 -64.73528 45.31042 -64.76707 45.29802 -64.79942 45.29890 -64.82175 45.31432 -64.83837 45.33672 -64.87393 45.33916 -64.89541 45.33261 -64.91675 45.32197 -64.96832 45.32409 -64.98229 45.33549 -64.99114 45.39515 -64.95533 45.44814 -64.88242 45.46542 -64.86768 45.48930 -64.80586 45.50880 -64.76681 45.58019 -64.64480 45.64034 -64.54662 45.67697 -64.49236 45.70040 -64.47382 45.70971 -64.46839 45.73776 -64.44713 45.74940 -64.42498 45.76241 -64.42008 45.78065 -64.41473 45.78914 -64.36872 45.77766 -64.35994 45.75025 -64.38352 45.74067 -64.38133 45.73846 -64.36727 45.74667 -64.32662 45.76138 -64.31542 45.77608 -64.33524 45.78865 -64.32277 45.80810 -64.30890 45.80812 -64.30892 45.82397 -64.29481 45.94073 -64.19468 45.95318 -64.19255 45.96819 -64.08843 45.96807 -64.03141 45.97293 -63.99925 45.98157 -63.99453 45.98282 -63.99398 + 45.982824 -63.993981 45.981800 -63.972552 45.973465 -63.943849 45.961227 -63.920124 45.893962 -63.830838 45.875924 -63.787247 45.858253 -63.720376 45.867146 -63.689137 45.879832 -63.627321 45.878654 -63.604733 45.869442 -63.561186 45.874409 -63.534894 45.869112 -63.486319 45.856760 -63.462774 45.845831 -63.456461 45.839424 -63.465417 45.821112 -63.556528 45.813031 -63.571776 45.804278 -63.566664 45.797393 -63.537241 45.805055 -63.483571 45.807187 -63.453845 45.807268 -63.417617 45.794901 -63.394123 45.791251 -63.375605 45.803200 -63.324445 45.801224 -63.299722 45.795186 -63.285346 45.785574 -63.283394 45.767817 -63.314829 45.751205 -63.386961 45.734802 -63.386468 45.710981 -63.336435 45.707242 -63.318014 45.719538 -63.310557 45.734848 -63.301206 45.738647 -63.265429 45.759809 -63.239570 45.762725 -63.224911 45.753956 -63.219873 45.740177 -63.228224 45.733403 -63.211697 45.736964 -63.199286 45.750283 -63.183349 45.758571 -63.144611 45.752466 -63.112122 45.756850 -63.096592 45.769973 -63.104004 45.779324 -63.129369 45.795080 -63.127528 45.801906 -63.107777 45.800521 -63.085301 45.794393 -63.052788 45.768287 -62.960132 45.764032 -62.916041 45.740807 -62.803508 45.722785 -62.768060 45.714161 -62.739696 45.711119 -62.700136 45.702563 -62.689809 45.683580 -62.699127 45.674090 -62.733486 45.672162 -62.804496 45.666389 -62.821011 45.649759 -62.808063 45.645088 -62.792816 45.623055 -62.803887 45.612338 -62.792380 45.608779 -62.768774 45.626333 -62.755283 45.626951 -62.739351 45.620091 -62.722941 45.613067 -62.711863 45.608621 -62.691253 45.615108 -62.676908 45.631136 -62.687682 45.639114 -62.713757 45.655016 -62.706445 45.661051 -62.684637 45.667903 -62.618209 45.655802 -62.602460 45.646340 -62.595331 45.641832 -62.574887 45.642304 -62.540956 45.623728 -62.539609 45.612824 -62.533491 45.609589 -62.517404 45.620829 -62.494755 45.623613 -62.433363 45.631285 -62.405258 45.644792 -62.401894 45.649528 -62.417100 45.644550 -62.453931 45.645540 -62.468925 45.655977 -62.467588 45.664136 -62.446913 45.685203 -62.350552 45.731705 -62.224910 45.775551 -62.131894 45.822724 -62.049641 45.848330 -62.014899 45.870347 -61.974690 45.878520 -61.948466 45.876051 -61.929127 45.869751 -61.914804 45.859357 -61.916390 45.841830 -61.953724 45.823788 -61.960193 45.789817 -61.950686 45.727545 -61.938500 45.705095 -61.942567 45.664172 -61.968862 45.644547 -61.976155 45.628555 -61.965681 45.620481 -61.934417 45.624616 -61.918710 45.650368 -61.930870 45.662466 -61.923103 45.666954 -61.896760 45.664476 -61.877515 45.650015 -61.860723 45.633775 -61.855572 45.621841 -61.858131 45.612479 -61.845946 45.616073 -61.822804 45.627712 -61.807521 45.622370 -61.756256 45.619590 -61.690359 45.623830 -61.669410 45.631557 -61.659157 45.635205 -61.630659 45.645805 -61.623729 45.656229 -61.622194 45.664095 -61.606700 45.669821 -61.584633 45.667043 -61.547346 45.621572 -61.451732 45.596882 -61.426233 45.571071 -61.414382 45.544994 -61.384535 45.533294 -61.376683 45.524519 -61.366714 45.516288 -61.335744 45.515269 -61.315437 45.506739 -61.295070 45.490916 -61.268926 45.477543 -61.267307 45.452548 -61.291612 45.433402 -61.317174 45.421267 -61.364141 45.408084 -61.385753 45.402663 -61.397044 45.399352 -61.443365 45.389242 -61.462990 45.385190 -61.478656 45.422573 -61.532126 45.438174 -61.563522 45.441947 -61.592248 45.437086 -61.611029 45.426695 -61.607316 45.411520 -61.560044 45.402267 -61.542787 45.375068 -61.531938 45.353168 -61.515029 45.338890 -61.487987 45.332207 -61.456037 45.337242 -61.432031 45.342662 -61.386942 45.340369 -61.357315 45.327955 -61.313510 45.325482 -61.289255 45.336802 -61.245479 45.330303 -61.197786 45.332720 -61.154630 45.321487 -61.120444 45.318249 -61.055031 45.306325 -61.018809 45.292321 -61.009794 45.272262 -61.010186 45.269010 -61.022638 45.280596 -61.040931 45.277383 -61.053488 45.261714 -61.056036 45.228635 -61.077960 45.200386 -61.119941 45.193707 -61.155342 45.199221 -61.177617 45.207231 -61.185356 45.238140 -61.162429 45.250155 -61.159755 45.269991 -61.170070 45.275575 -61.187090 45.272343 -61.199638 45.255779 -61.210415 45.226096 -61.209233 45.212541 -61.218097 45.226123 -61.242859 45.234499 -61.268437 45.230971 -61.296710 45.234214 -61.317813 45.230755 -61.340798 45.218918 -61.371806 45.198140 -61.403458 45.184786 -61.401807 45.178683 -61.377439 45.186255 -61.338814 45.179932 -61.319686 45.164464 -61.316903 45.157275 -61.339733 45.150301 -61.419185 45.143174 -61.436717 45.136584 -61.466798 45.132646 -61.505386 45.138663 -61.535127 45.139567 -61.560370 45.134501 -61.584254 45.132059 -61.621865 45.150889 -61.702625 45.145104 -61.724315 45.136704 -61.732259 45.125701 -61.698080 45.115802 -61.678716 45.100455 -61.698916 45.071007 -61.686889 45.066240 -61.700241 45.076451 -61.737457 45.064678 -61.786075 45.077604 -61.831876 45.073494 -61.847400 45.058609 -61.846581 45.049931 -61.864901 45.038821 -61.864349 45.027553 -61.868946 45.020419 -61.886297 45.031062 -61.902588 45.035869 -61.917534 45.020592 -61.932359 45.024521 -61.950440 45.042804 -61.985012 45.031919 -62.002174 45.023986 -61.994321 45.010895 -61.987292 45.005332 -61.998472 45.004267 -62.035002 44.993255 -62.080440 44.987554 -62.096858 44.977075 -62.075285 44.980718 -62.052487 44.979032 -62.035648 44.973572 -62.018524 44.964645 -62.019059 44.958463 -62.051180 44.952787 -62.141797 44.943747 -62.170408 44.931819 -62.195861 44.925921 -62.217382 44.934008 -62.242967 44.935517 -62.265044 44.922713 -62.293420 44.904000 -62.320441 44.899143 -62.333680 44.899820 -62.358800 44.890490 -62.369704 44.879946 -62.376281 44.873307 -62.395739 44.877176 -62.413635 44.873632 -62.431219 44.843061 -62.478076 44.843152 -62.495918 44.866942 -62.496511 44.873078 -62.510486 44.868855 -62.525878 44.852363 -62.530945 44.839518 -62.536284 44.833584 -62.557825 44.837185 -62.581011 44.790589 -62.576573 44.778250 -62.589305 44.782120 -62.607285 44.801542 -62.623245 44.808850 -62.646650 44.796499 -62.659365 44.789221 -62.676501 44.772488 -62.686791 44.767579 -62.699949 44.774175 -62.721334 44.776538 -62.757892 44.762520 -62.794357 44.761895 -62.809986 44.785925 -62.840985 44.787365 -62.862952 44.783908 -62.875238 44.772776 -62.874332 44.762495 -62.852681 44.747202 -62.844239 44.734904 -62.856823 44.704402 -62.839891 44.695098 -62.850587 44.693810 -62.864009 44.707338 -62.896262 44.709672 -62.932887 44.705766 -62.973158 44.695384 -63.009754 44.701072 -63.034182 44.722800 -63.046355 44.745012 -63.048140 44.760208 -63.056713 44.767890 -63.069764 44.754386 -63.090672 44.742006 -63.085448 44.717428 -63.069788 44.690851 -63.065547 44.672827 -63.071412 44.671741 -63.097324 44.694785 -63.113719 44.708949 -63.130553 44.739357 -63.129940 44.751131 -63.133096 44.758536 -63.151442 44.750707 -63.161071 44.698504 -63.167118 44.679517 -63.175922 44.675906 -63.193312 44.686074 -63.197275 44.713714 -63.193451 44.733720 -63.194027 44.738949 -63.211198 44.730008 -63.229124 44.686725 -63.234797 44.667733 -63.243571 44.673629 -63.262741 44.694917 -63.267719 44.704886 -63.276917 44.677697 -63.305807 44.655051 -63.296500 44.645292 -63.299803 44.636577 -63.312576 44.612826 -63.329257 44.623132 -63.381021 44.617788 -63.416913 44.623568 -63.436144 44.653307 -63.451259 44.663686 -63.467888 44.664463 -63.482470 44.659439 -63.495510 44.636607 -63.491319 44.609818 -63.461913 44.586428 -63.485782 44.585718 -63.501172 44.596085 -63.517788 44.600912 -63.557620 44.637264 -63.589152 44.644786 -63.602316 44.661009 -63.620476 44.674105 -63.640426 44.696054 -63.677904 44.695352 -63.693438 44.662082 -63.690340 44.646542 -63.674177 44.630987 -63.628049 44.621907 -63.615771 44.609013 -63.620776 44.590639 -63.601446 44.577918 -63.588822 44.555734 -63.586777 44.537725 -63.592253 44.522898 -63.590871 44.506679 -63.572776 44.487201 -63.561599 44.447535 -63.584914 44.446850 -63.600362 44.453059 -63.609280 44.457527 -63.624102 44.453121 -63.639248 44.438084 -63.643041 44.430630 -63.659884 44.431416 -63.674503 44.446606 -63.683164 44.455254 -63.718175 44.450634 -63.750892 44.459687 -63.763149 44.465691 -63.777111 44.459258 -63.815892 44.463732 -63.830845 44.482774 -63.834758 44.487015 -63.854910 44.474720 -63.892002 44.489658 -63.948441 44.498450 -63.965939 44.514825 -63.978979 44.537512 -63.970935 44.554528 -63.956032 44.572989 -63.957926 44.604474 -63.967397 44.619773 -63.958493 44.656361 -63.924778 44.650797 -63.960630 44.635953 -63.989326 44.617408 -64.060231 44.605288 -64.079737 44.593937 -64.083740 44.556397 -64.077664 44.529404 -64.083235 44.495357 -64.052760 44.484954 -64.053701 44.475874 -64.083873 44.458556 -64.103775 44.452503 -64.119742 44.466879 -64.156511 44.479759 -64.164074 44.508690 -64.165073 44.529371 -64.180732 44.547035 -64.210716 44.548383 -64.239938 44.525378 -64.252934 44.524567 -64.280923 44.530345 -64.337626 44.516284 -64.350604 44.474806 -64.349138 44.465949 -64.361661 44.441949 -64.352676 44.432440 -64.363164 44.427307 -64.388372 44.410490 -64.397892 44.395372 -64.388998 44.389545 -64.374922 44.399475 -64.341823 44.398224 -64.325125 44.389868 -64.314961 44.373934 -64.321512 44.360328 -64.286895 44.347092 -64.284435 44.339776 -64.295970 44.347920 -64.336183 44.339703 -64.363168 44.327140 -64.375284 44.311805 -64.371416 44.310423 -64.342396 44.311356 -64.327059 44.301474 -64.317604 44.274817 -64.330238 44.277505 -64.296491 44.270676 -64.285392 44.256174 -64.278743 44.242716 -64.293733 44.234890 -64.315555 44.240208 -64.339894 44.278320 -64.372908 44.282123 -64.385782 44.270786 -64.401968 44.255157 -64.403421 44.245044 -64.423958 44.225103 -64.435130 44.218162 -64.466327 44.143425 -64.527892 44.132466 -64.576039 44.127885 -64.652727 44.117748 -64.660902 44.106153 -64.632748 44.107307 -64.600042 44.091702 -64.588909 44.053982 -64.612357 44.048123 -64.622979 44.048159 -64.647654 44.043548 -64.662457 44.032531 -64.673575 44.021770 -64.704107 43.994488 -64.714266 43.969383 -64.725750 43.959210 -64.746088 43.948829 -64.759171 43.939249 -64.793972 43.928452 -64.824417 43.924404 -64.853639 43.909692 -64.876416 43.894973 -64.874751 43.886739 -64.864436 43.877924 -64.827639 43.858950 -64.810974 43.849175 -64.813900 43.843615 -64.831730 43.836521 -64.850221 43.823922 -64.862073 43.816590 -64.873492 43.827300 -64.892140 43.851134 -64.901177 43.864546 -64.935538 43.861382 -64.949480 43.851270 -64.957382 43.833878 -64.927729 43.794981 -64.934270 43.787601 -64.945563 43.791193 -64.958294 43.819392 -64.969884 43.839783 -64.985720 43.838259 -64.998772 43.826535 -65.007645 43.790840 -64.987936 43.771875 -64.983499 43.751909 -64.994314 43.752996 -65.023057 43.773488 -65.038947 43.787820 -65.045820 43.797221 -65.060212 43.796283 -65.075419 43.776048 -65.079039 43.735411 -65.054602 43.701073 -65.070755 43.687472 -65.097574 43.704211 -65.112949 43.713940 -65.122343 43.710273 -65.134116 43.677665 -65.156585 43.651947 -65.165584 43.649076 -65.186536 43.671043 -65.189360 43.690718 -65.183739 43.700746 -65.188053 43.696581 -65.217098 43.748452 -65.250269 43.754163 -65.264369 43.752760 -65.284601 43.737043 -65.297883 43.727610 -65.295712 43.706266 -65.282649 43.679312 -65.287415 43.658728 -65.295911 43.651344 -65.307218 43.659047 -65.334668 43.667295 -65.344962 43.677313 -65.349308 43.706115 -65.351030 43.717227 -65.371964 43.713757 -65.390872 43.705106 -65.397896 43.632078 -65.383218 43.610440 -65.375223 43.582702 -65.389920 43.568094 -65.388050 43.552146 -65.394115 43.546874 -65.406630 43.542374 -65.428323 43.543453 -65.444848 43.558323 -65.453976 43.563448 -65.465715 43.555867 -65.489233 43.536405 -65.482562 43.523131 -65.460483 43.511291 -65.449701 43.488138 -65.442606 43.478244 -65.445324 43.470262 -65.454407 43.489624 -65.473246 43.503577 -65.485278 43.494280 -65.502391 43.471355 -65.502389 43.455369 -65.508297 43.447966 -65.519523 43.466984 -65.543446 43.485401 -65.596720 43.512810 -65.606510 43.518087 -65.625543 43.510544 -65.648958 43.500308 -65.656701 43.483847 -65.679810 43.476417 -65.710371 43.477144 -65.731782 43.472147 -65.758528 43.475355 -65.776247 43.484424 -65.783569 43.496365 -65.782241 43.508647 -65.775846 43.515263 -65.786978 43.525578 -65.817804 43.538293 -65.825777 43.566832 -65.820548 43.597252 -65.809604 43.642357 -65.800594 43.657851 -65.811972 43.658281 -65.826375 43.648022 -65.834103 43.629691 -65.831504 43.616204 -65.833723 43.588468 -65.848095 43.611674 -65.874876 43.625927 -65.881981 43.688686 -65.885829 43.734166 -65.871785 43.760614 -65.884870 43.766452 -65.906053 43.763789 -65.922022 43.776160 -65.935163 43.797725 -65.943341 43.806444 -65.955849 43.806276 -65.968118 43.797575 -65.975048 43.782392 -65.970803 43.771579 -65.976449 43.763414 -65.985442 43.768731 -66.004675 43.779473 -66.018521 43.762360 -66.039570 43.737076 -66.011339 43.722707 -66.004118 43.710216 -66.003327 43.694750 -66.011268 43.689958 -66.025926 43.689029 -66.048226 43.676638 -66.054630 43.674695 -66.079886 43.683215 -66.085232 43.702910 -66.079886 43.709493 -66.091109 43.705030 -66.120075 43.712540 -66.128396 43.726609 -66.128436 43.740281 -66.133459 43.740657 -66.147891 43.745253 -66.164899 43.775349 -66.178661 43.783100 -66.194119 43.807155 -66.198722 43.835107 -66.211124 43.860422 -66.200598 43.875679 -66.204873 43.891138 -66.216444 43.926080 -66.195972 43.961840 -66.204422 44.008201 -66.200114 44.037357 -66.216798 44.076384 -66.230978 44.102584 -66.236930 44.131263 -66.232004 44.203791 -66.187218 44.233860 -66.174108 44.302555 -66.160625 44.324181 -66.149342 44.359659 -66.123522 44.379929 -66.100690 44.424676 -66.050190 44.460703 -65.987006 44.514642 -65.911618 44.539345 -65.898606 44.556478 -65.909438 44.561714 -65.928941 44.549131 -65.967730 44.553607 -65.997497 44.548442 -66.017616 44.490528 -66.084869 44.467482 -66.104298 44.428553 -66.156720 44.401393 -66.180630 44.393220 -66.189818 44.380207 -66.213867 44.382650 -66.229701 44.396396 -66.234936 44.411366 -66.224738 44.435205 -66.195170 44.459479 -66.160343 44.494502 -66.139572 44.507901 -66.110377 44.555236 -66.056089 44.588802 -65.960484 44.645739 -65.873996 44.658640 -65.835548 44.656469 -65.814442 44.647115 -65.799510 44.626913 -65.790379 44.598996 -65.785316 44.580661 -65.750428 44.580974 -65.725576 44.589032 -65.696489 44.611131 -65.667343 44.619841 -65.660230 44.645719 -65.631463 44.672429 -65.599735 44.693781 -65.560907 44.723623 -65.495102 44.736725 -65.478096 44.761693 -65.472046 44.760235 -65.492722 44.745889 -65.517934 44.711085 -65.611360 44.677113 -65.681793 44.657425 -65.759350 44.660612 -65.777422 44.670313 -65.787156 44.680738 -65.786606 44.698524 -65.767202 44.722037 -65.729888 44.752632 -65.666213 44.769814 -65.644507 44.802341 -65.562292 44.843236 -65.465331 44.883541 -65.398553 44.909613 -65.331751 44.947100 -65.261247 45.008954 -65.157013 45.030015 -65.130345 45.048458 -65.087482 45.071422 -65.042046 45.112713 -64.953755 45.121512 -64.921104 45.126170 -64.893229 45.146027 -64.824099 45.171731 -64.718749 45.239323 -64.477978 45.257132 -64.452542 45.270726 -64.449937 45.279982 -64.457281 45.292736 -64.482968 45.303562 -64.514880 45.313731 -64.531883 45.327600 -64.524013 45.318581 -64.473245 45.294033 -64.393444 45.280690 -64.378226 45.256642 -64.369180 45.227983 -64.388086 45.210800 -64.402935 45.186167 -64.417019 45.174458 -64.413608 45.150728 -64.399410 45.137760 -64.404249 45.119935 -64.429529 45.108845 -64.428340 45.098978 -64.418806 45.089939 -64.393622 45.093910 -64.376225 45.111735 -64.363459 45.114823 -64.349086 45.106639 -64.320869 45.077810 -64.276696 45.039404 -64.230459 45.019263 -64.216707 44.985713 -64.205797 44.977978 -64.197566 44.968798 -64.159903 44.965269 -64.129183 44.971002 -64.105692 44.982334 -64.101551 44.989130 -64.112855 44.992074 -64.128833 44.993118 -64.150992 45.005533 -64.169135 45.030106 -64.154972 45.050139 -64.168648 45.080917 -64.219212 45.108179 -64.239022 45.126060 -64.238830 45.161345 -64.218485 45.186486 -64.193873 45.197460 -64.169809 45.223688 -64.068251 45.249577 -63.941239 45.272003 -63.864504 45.290987 -63.812667 45.298230 -63.800698 45.299031 -63.784901 45.296733 -63.771001 45.301380 -63.737671 45.308730 -63.707828 45.304145 -63.679865 45.295369 -63.644258 45.304310 -63.564939 45.300702 -63.546609 45.276650 -63.520159 45.281692 -63.506943 45.299197 -63.499064 45.313748 -63.505672 45.327347 -63.484799 45.339635 -63.477452 45.353265 -63.487189 45.357140 -63.518174 45.356089 -63.557165 45.376640 -63.626664 45.371111 -63.681122 45.373299 -63.743678 45.380392 -63.780323 45.380665 -63.805732 45.351065 -63.907407 45.346668 -63.935410 45.351490 -63.958078 45.361918 -63.987785 45.368884 -64.011698 45.371796 -64.040623 45.370502 -64.066854 45.372147 -64.091320 45.386260 -64.121424 45.387642 -64.151192 45.380392 -64.175720 45.378980 -64.202010 45.387057 -64.217730 45.388081 -64.240086 45.383002 -64.265957 45.372868 -64.287043 45.366498 -64.308597 45.361821 -64.392604 45.350960 -64.467490 45.353499 -64.488964 45.379517 -64.555346 45.388171 -64.586076 45.393441 -64.636382 45.386033 -64.673709 45.370268 -64.712989 45.353347 -64.735284 45.310426 -64.767074 45.298029 -64.799424 45.298909 -64.821751 45.314323 -64.838375 45.336722 -64.873930 45.339164 -64.895419 45.332610 -64.916758 45.321979 -64.968329 45.324093 -64.982296 45.335490 -64.991147 45.395153 -64.955330 45.448146 -64.882425 45.465426 -64.867682 45.489303 -64.805866 45.508805 -64.766810 45.580190 -64.644801 45.640341 -64.546622 45.676979 -64.492363 45.700408 -64.473828 45.709718 -64.468392 45.737760 -64.447136 45.749407 -64.424980 45.762412 -64.420080 45.780650 -64.414732 45.789145 -64.368721 45.777664 -64.359940 45.750255 -64.383522 45.740671 -64.381335 45.738461 -64.367270 45.746672 -64.326628 45.761388 -64.315425 45.776089 -64.335241 45.788651 -64.322774 45.808102 -64.308902 45.808120 -64.308927 45.823976 -64.294811 45.940739 -64.194680 45.953182 -64.192553 45.968192 -64.088437 45.968076 -64.031412 45.972937 -63.999252 45.981579 -63.994538 45.982824 -63.993981 @@ -298,15 +298,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 45.50482 -61.22751 - 45.53473 -61.18069 + 45.504823 -61.227514 + 45.534739 -61.180696 - 45.51045 -61.22751 45.51931 -61.22687 45.52995 -61.21455 45.53473 -61.20094 45.52992 -61.18069 45.51634 -61.18962 45.50482 -61.21028 45.51045 -61.22751 + 45.510451 -61.227514 45.519318 -61.226878 45.529958 -61.214551 45.534739 -61.200944 45.529920 -61.180696 45.516349 -61.189628 45.504823 -61.210287 45.510451 -61.227514 @@ -318,15 +318,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 45.78689 -62.62684 - 45.81546 -62.55613 + 45.786892 -62.626846 + 45.815465 -62.556139 - 45.79069 -62.62192 45.79950 -62.62684 45.80862 -62.62107 45.81546 -62.59606 45.80869 -62.55613 45.79817 -62.55752 45.78689 -62.60347 45.79069 -62.62192 + 45.790699 -62.621922 45.799503 -62.626846 45.808625 -62.621075 45.815465 -62.596064 45.808696 -62.556139 45.798173 -62.557522 45.786892 -62.603470 45.790699 -62.621922 @@ -338,15 +338,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 45.73923 -62.77618 - 45.76402 -62.72846 + 45.739239 -62.776183 + 45.764021 -62.728467 - 45.74288 -62.76845 45.75973 -62.77618 45.76402 -62.76050 45.76045 -62.73682 45.74881 -62.72846 45.73923 -62.74484 45.74288 -62.76845 + 45.742885 -62.768457 45.759737 -62.776183 45.764021 -62.760507 45.760451 -62.736823 45.748816 -62.728467 45.739239 -62.744842 45.742885 -62.768457 @@ -358,15 +358,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 43.91841 -60.11754 - 44.01041 -59.71284 + 43.918413 -60.117541 + 44.010417 -59.712843 - 43.92307 -60.11754 43.93352 -60.11062 43.94339 -60.07098 43.95258 -59.91475 43.95880 -59.86978 43.96940 -59.82193 44.00294 -59.74551 44.01041 -59.72512 44.00599 -59.71284 43.99417 -59.71575 43.98158 -59.73206 43.96591 -59.77585 43.93528 -59.85529 43.92985 -59.88686 43.92813 -59.93384 43.92190 -59.98373 43.91841 -60.05722 43.91957 -60.09712 43.92307 -60.11754 + 43.923078 -60.117541 43.933522 -60.110628 43.943396 -60.070988 43.952586 -59.914751 43.958808 -59.869787 43.969408 -59.821934 44.002943 -59.745514 44.010417 -59.725120 44.005999 -59.712843 43.994175 -59.715759 43.981586 -59.732063 43.965917 -59.775859 43.935280 -59.855295 43.929858 -59.886866 43.928136 -59.933842 43.921907 -59.983735 43.918413 -60.057221 43.919575 -60.097126 43.923078 -60.117541 @@ -378,15 +378,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 44.25244 -66.35756 - 44.36908 -66.25144 + 44.252448 -66.357560 + 44.369088 -66.251440 - 44.25426 -66.34999 44.26331 -66.35756 44.36053 -66.28547 44.36908 -66.27114 44.36868 -66.25668 44.35494 -66.25144 44.34005 -66.26156 44.27920 -66.29795 44.26288 -66.31608 44.25244 -66.33624 44.25426 -66.34999 + 44.254260 -66.349998 44.263314 -66.357560 44.360536 -66.285475 44.369088 -66.271148 44.368689 -66.256681 44.354945 -66.251440 44.340056 -66.261563 44.279201 -66.297959 44.262882 -66.316083 44.252448 -66.336248 44.254260 -66.349998 @@ -398,15 +398,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 44.21850 -66.43267 - 44.25705 -66.37969 + 44.218506 -66.432672 + 44.257055 -66.379694 - 44.22686 -66.43267 44.23618 -66.42797 44.25705 -66.40008 44.25302 -66.38496 44.23929 -66.37969 44.22341 -66.39285 44.21850 -66.40752 44.22686 -66.43267 + 44.226863 -66.432672 44.236182 -66.427973 44.257055 -66.400086 44.253021 -66.384960 44.239292 -66.379694 44.223413 -66.392850 44.218506 -66.407527 44.226863 -66.432672 @@ -418,15 +418,15 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 43.41231 -65.68783 - 43.47638 -65.61648 + 43.412311 -65.687835 + 43.476384 -65.616482 - 43.41231 -65.65685 43.43182 -65.68286 43.44554 -65.68783 43.47369 -65.65616 43.47638 -65.64022 43.46618 -65.61648 43.44388 -65.61842 43.42851 -65.62655 43.41583 -65.63808 43.41231 -65.65685 + 43.412311 -65.656854 43.431829 -65.682866 43.445545 -65.687835 43.473694 -65.656161 43.476384 -65.640224 43.466182 -65.616482 43.443882 -65.618422 43.428510 -65.626553 43.415833 -65.638089 43.412311 -65.656854 diff --git a/msautotest/wxs/expected/wfs_postgis_10f_precision_gml2.xml b/msautotest/wxs/expected/wfs_postgis_10f_precision_gml2.xml new file mode 100644 index 0000000000..43e961ae69 --- /dev/null +++ b/msautotest/wxs/expected/wfs_postgis_10f_precision_gml2.xml @@ -0,0 +1,50 @@ +Content-Type: text/xml; charset=UTF-8 + + + + + + -64.052355,46.980843 -64.052355,46.980843 + + + + + + + -64.052355,46.980843 -64.052355,46.980843 + + + + + -64.0523554056,46.9808430463 + + + 1 + 0 + 0 + 8 + 1 + BACMK + "Tignish + + + + + 11 + 021I16 + 465700 + 640200 + 0 + 0 + 1 + + + + diff --git a/msautotest/wxs/expected/wfs_postgis_10f_precision_gml3.xml b/msautotest/wxs/expected/wfs_postgis_10f_precision_gml3.xml new file mode 100644 index 0000000000..e52b2e6c42 --- /dev/null +++ b/msautotest/wxs/expected/wfs_postgis_10f_precision_gml3.xml @@ -0,0 +1,51 @@ +Content-Type: text/xml; subtype=gml/3.1.1; charset=UTF-8 + + + + + + 46.980843 -64.052355 + 46.980843 -64.052355 + + + + + + + 46.980843 -64.052355 + 46.980843 -64.052355 + + + + + 46.9808430463 -64.0523554056 + + + 1 + 0 + 0 + 8 + 1 + BACMK + "Tignish + + + + + 11 + 021I16 + 465700 + 640200 + 0 + 0 + 1 + + + + diff --git a/msautotest/wxs/expected/wfs_postgis_issue_6181.xml b/msautotest/wxs/expected/wfs_postgis_issue_6181.xml new file mode 100644 index 0000000000..02ba859b54 --- /dev/null +++ b/msautotest/wxs/expected/wfs_postgis_issue_6181.xml @@ -0,0 +1,35 @@ +Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 + + + + + + 0.000000 0.000000 + 10.000000 10.000000 + + + + + + + 0.000000 0.000000 + 10.000000 10.000000 + + + + + 0.000000 0.000000 10.000000 10.000000 + + + 2 + + + + diff --git a/msautotest/wxs/expected/wfs_postgis_issue_6181_startindex_1.xml b/msautotest/wxs/expected/wfs_postgis_issue_6181_startindex_1.xml new file mode 100644 index 0000000000..bb923b5996 --- /dev/null +++ b/msautotest/wxs/expected/wfs_postgis_issue_6181_startindex_1.xml @@ -0,0 +1,35 @@ +Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 + + + + + + 5.000000 2.000000 + 5.000000 8.000000 + + + + + + + 5.000000 2.000000 + 5.000000 8.000000 + + + + + 5.000000 2.000000 5.000000 8.000000 + + + 3 + + + + diff --git a/msautotest/wxs/expected/wfs_postgis_precision_web_4f_gml2.xml b/msautotest/wxs/expected/wfs_postgis_precision_web_4f_gml2.xml new file mode 100644 index 0000000000..7a4f7ec8d0 --- /dev/null +++ b/msautotest/wxs/expected/wfs_postgis_precision_web_4f_gml2.xml @@ -0,0 +1,50 @@ +Content-Type: text/xml; charset=UTF-8 + + + + + + -64.052355,46.980843 -64.052355,46.980843 + + + + + + + -64.052355,46.980843 -64.052355,46.980843 + + + + + -64.0524,46.9808 + + + 1 + 0 + 0 + 8 + 1 + BACMK + "Tignish + + + + + 11 + 021I16 + 465700 + 640200 + 0 + 0 + 1 + + + + diff --git a/msautotest/wxs/expected/wfs_postgis_precision_web_4f_gml3.xml b/msautotest/wxs/expected/wfs_postgis_precision_web_4f_gml3.xml new file mode 100644 index 0000000000..e40bf86dc9 --- /dev/null +++ b/msautotest/wxs/expected/wfs_postgis_precision_web_4f_gml3.xml @@ -0,0 +1,51 @@ +Content-Type: text/xml; subtype=gml/3.1.1; charset=UTF-8 + + + + + + 46.980843 -64.052355 + 46.980843 -64.052355 + + + + + + + 46.980843 -64.052355 + 46.980843 -64.052355 + + + + + 46.9808 -64.0524 + + + 1 + 0 + 0 + 8 + 1 + BACMK + "Tignish + + + + + 11 + 021I16 + 465700 + 640200 + 0 + 0 + 1 + + + + diff --git a/msautotest/wxs/expected/wfs_postgis_precision_web_4f_layer_10f_gml3.xml b/msautotest/wxs/expected/wfs_postgis_precision_web_4f_layer_10f_gml3.xml new file mode 100644 index 0000000000..3a7cc0e75a --- /dev/null +++ b/msautotest/wxs/expected/wfs_postgis_precision_web_4f_layer_10f_gml3.xml @@ -0,0 +1,51 @@ +Content-Type: text/xml; subtype=gml/3.1.1; charset=UTF-8 + + + + + + 46.980843 -64.052355 + 46.980843 -64.052355 + + + + + + + 46.980843 -64.052355 + 46.980843 -64.052355 + + + + + 46.9808430463 -64.0523554056 + + + 1 + 0 + 0 + 8 + 1 + BACMK + "Tignish + + + + + 11 + 021I16 + 465700 + 640200 + 0 + 0 + 1 + + + + diff --git a/msautotest/wxs/expected/wfs_query_cache.json b/msautotest/wxs/expected/wfs_query_cache.json index 39e26848e2..013710f234 100644 --- a/msautotest/wxs/expected/wfs_query_cache.json +++ b/msautotest/wxs/expected/wfs_query_cache.json @@ -5,10 +5,11 @@ Content-Type: application/json; subtype=geojson; charset=utf-8 "type": "FeatureCollection", "name": "province", "crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } }, +"xy_coordinate_resolution": 0.0001, "features": [ -{ "type": "Feature", "properties": { "NAME_E": "Quebec" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ] ] ] } }, -{ "type": "Feature", "properties": { "NAME_E": "Nova Scotia" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ] ] ] } }, -{ "type": "Feature", "properties": { "NAME_E": "Quebec" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ], [ -95.0008, 49.0004 ] ] ] } }, +{ "type": "Feature", "properties": { "NAME_E": "Quebec" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -61.5105, 47.7742 ], [ -61.5089, 47.7886 ], [ -61.4927, 47.7964 ], [ -61.4576, 47.7874 ], [ -61.46, 47.7679 ], [ -61.4835, 47.7696 ], [ -61.5105, 47.7742 ] ] ] } }, +{ "type": "Feature", "properties": { "NAME_E": "Nova Scotia" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -60.2049, 47.1664 ], [ -60.2117, 47.1799 ], [ -60.1944, 47.1927 ], [ -60.1734, 47.1876 ], [ -60.1688, 47.175 ], [ -60.2049, 47.1664 ] ] ] } }, +{ "type": "Feature", "properties": { "NAME_E": "Quebec" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -62.0105, 47.2411 ], [ -61.9667, 47.246 ], [ -61.9475, 47.2383 ], [ -61.9327, 47.2283 ], [ -61.907, 47.2222 ], [ -61.8647, 47.2331 ], [ -61.8422, 47.2427 ], [ -61.8287, 47.2386 ], [ -61.828, 47.2273 ], [ -61.8384, 47.2158 ], [ -61.8953, 47.1911 ], [ -61.9109, 47.1959 ], [ -61.9303, 47.2073 ], [ -61.9437, 47.2115 ], [ -61.9805, 47.2007 ], [ -62.0092, 47.2021 ], [ -62.0571, 47.2113 ], [ -62.073, 47.2199 ], [ -62.077, 47.2302 ], [ -62.0252, 47.3006 ], [ -62.0126, 47.328 ], [ -62.0141, 47.3542 ], [ -62.0015, 47.3816 ], [ -61.9743, 47.4063 ], [ -61.8758, 47.4607 ], [ -61.744, 47.5565 ], [ -61.6597, 47.5968 ], [ -61.5899, 47.6195 ], [ -61.5321, 47.6201 ], [ -61.4924, 47.6263 ], [ -61.467, 47.6276 ], [ -61.4436, 47.6258 ], [ -61.4332, 47.6171 ], [ -61.4402, 47.6027 ], [ -61.4826, 47.5845 ], [ -61.502, 47.572 ], [ -61.5273, 47.5467 ], [ -61.5542, 47.531 ], [ -61.5804, 47.5244 ], [ -61.6021, 47.5367 ], [ -61.5928, 47.5466 ], [ -61.5537, 47.5641 ], [ -61.5404, 47.5839 ], [ -61.5753, 47.5966 ], [ -61.6289, 47.5818 ], [ -61.6732, 47.5604 ], [ -61.7075, 47.5379 ], [ -61.772, 47.5024 ], [ -61.8118, 47.4632 ], [ -61.8436, 47.4399 ], [ -61.8673, 47.4288 ], [ -61.8884, 47.4132 ], [ -61.9108, 47.3796 ], [ -61.9193, 47.3546 ], [ -61.9186, 47.3434 ], [ -61.9475, 47.3283 ], [ -61.9831, 47.3154 ], [ -62.0214, 47.2573 ], [ -62.0105, 47.2411 ] ] ] } }, { "type": "Feature", "properties": { "NAME_E": "Quebec" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -61.8502, 47.3908 ], [ -61.8377, 47.4053 ], [ -61.8164, 47.4172 ], [ -61.8027, 47.4295 ], [ -61.7793, 47.4443 ], [ -61.7594, 47.4659 ], [ -61.7306, 47.4845 ], [ -61.7048, 47.4987 ], [ -61.6664, 47.5274 ], [ -61.6447, 47.5354 ], [ -61.6246, 47.5329 ], [ -61.6318, 47.5223 ], [ -61.6557, 47.5111 ], [ -61.7291, 47.4583 ], [ -61.7534, 47.4382 ], [ -61.7765, 47.4159 ], [ -61.8032, 47.38 ], [ -61.8195, 47.3758 ], [ -61.8502, 47.3908 ] ] ] } }, { "type": "Feature", "properties": { "NAME_E": "Nova Scotia" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -60.881, 45.65 ], [ -60.8974, 45.6296 ], [ -60.9281, 45.6306 ], [ -61.0091, 45.6113 ], [ -61.0408, 45.6107 ], [ -61.0606, 45.6007 ], [ -61.0973, 45.5889 ], [ -61.133, 45.5822 ], [ -61.1683, 45.5643 ], [ -61.1904, 45.5587 ], [ -61.2073, 45.5606 ], [ -61.2071, 45.5808 ], [ -61.2257, 45.5923 ], [ -61.245, 45.5985 ], [ -61.2638, 45.5937 ], [ -61.276, 45.5793 ], [ -61.2947, 45.5707 ], [ -61.3055, 45.5504 ], [ -61.3344, 45.558 ], [ -61.365, 45.5789 ], [ -61.3766, 45.601 ], [ -61.3913, 45.6222 ], [ -61.439, 45.645 ], [ -61.4779, 45.6812 ], [ -61.5044, 45.7209 ], [ -61.5151, 45.7445 ], [ -61.5324, 45.794 ], [ -61.5406, 45.8332 ], [ -61.5551, 45.8634 ], [ -61.5625, 45.9079 ], [ -61.5642, 45.9415 ], [ -61.5951, 46.0227 ], [ -61.5755, 46.0367 ], [ -61.5513, 46.0454 ], [ -61.5152, 46.0522 ], [ -61.4884, 46.0529 ], [ -61.4554, 46.055 ], [ -61.4515, 46.0649 ], [ -61.4682, 46.0757 ], [ -61.5107, 46.0911 ], [ -61.5177, 46.1043 ], [ -61.4898, 46.1467 ], [ -61.4557, 46.1744 ], [ -61.4149, 46.1962 ], [ -61.3684, 46.2143 ], [ -61.3338, 46.2346 ], [ -61.2708, 46.2933 ], [ -61.1868, 46.395 ], [ -61.1524, 46.4263 ], [ -61.1436, 46.4474 ], [ -61.1061, 46.5108 ], [ -61.0632, 46.5744 ], [ -61.066, 46.59 ], [ -61.092, 46.6149 ], [ -61.0814, 46.6226 ], [ -61.0621, 46.6275 ], [ -61.0412, 46.6226 ], [ -61.023, 46.6297 ], [ -61.014, 46.647 ], [ -61.0122, 46.6575 ], [ -60.9522, 46.7378 ], [ -60.9125, 46.7841 ], [ -60.8912, 46.7993 ], [ -60.858, 46.8126 ], [ -60.8077, 46.8388 ], [ -60.7525, 46.8838 ], [ -60.7084, 46.9398 ], [ -60.6833, 46.976 ], [ -60.6755, 47.0069 ], [ -60.6659, 47.0167 ], [ -60.6345, 47.0268 ], [ -60.6082, 47.0258 ], [ -60.5433, 47.0176 ], [ -60.5143, 46.997 ], [ -60.5001, 46.9942 ], [ -60.4838, 47.0018 ], [ -60.4714, 47.0274 ], [ -60.4441, 47.0315 ], [ -60.4308, 47.0233 ], [ -60.424, 47.0137 ], [ -60.428, 47.0003 ], [ -60.4559, 46.9797 ], [ -60.4675, 46.9632 ], [ -60.4659, 46.9422 ], [ -60.4732, 46.9279 ], [ -60.5154, 46.9177 ], [ -60.5248, 46.9003 ], [ -60.5105, 46.8938 ], [ -60.4833, 46.8941 ], [ -60.4569, 46.8854 ], [ -60.431, 46.8566 ], [ -60.409, 46.8531 ], [ -60.371, 46.8572 ], [ -60.3521, 46.8417 ], [ -60.344, 46.8186 ], [ -60.3435, 46.7999 ], [ -60.3573, 46.7841 ], [ -60.3539, 46.731 ], [ -60.3886, 46.685 ], [ -60.4143, 46.6713 ], [ -60.4194, 46.6526 ], [ -60.4009, 46.6521 ], [ -60.3812, 46.6456 ], [ -60.382, 46.6366 ], [ -60.3992, 46.6274 ], [ -60.4098, 46.6161 ], [ -60.3824, 46.6052 ], [ -60.3777, 46.5888 ], [ -60.3996, 46.5572 ], [ -60.4285, 46.5389 ], [ -60.4494, 46.5125 ], [ -60.4512, 46.4983 ], [ -60.5146, 46.4027 ], [ -60.5335, 46.3831 ], [ -60.5611, 46.3627 ], [ -60.5682, 46.3521 ], [ -60.5689, 46.3357 ], [ -60.5865, 46.31 ], [ -60.5883, 46.2996 ], [ -60.5996, 46.2793 ], [ -60.6327, 46.2699 ], [ -60.6497, 46.2607 ], [ -60.6428, 46.2474 ], [ -60.6529, 46.2249 ], [ -60.645, 46.213 ], [ -60.631, 46.2102 ], [ -60.6161, 46.2164 ], [ -60.5903, 46.254 ], [ -60.5367, 46.301 ], [ -60.5145, 46.3177 ], [ -60.4793, 46.3301 ], [ -60.4732, 46.304 ], [ -60.4795, 46.295 ], [ -60.4984, 46.2754 ], [ -60.5174, 46.2632 ], [ -60.5444, 46.2278 ], [ -60.594, 46.1943 ], [ -60.7039, 46.1033 ], [ -60.7325, 46.0925 ], [ -60.7808, 46.0917 ], [ -60.8124, 46.0764 ], [ -60.8622, 46.0614 ], [ -60.891, 46.058 ], [ -60.9237, 46.0723 ], [ -60.9459, 46.0667 ], [ -60.9497, 46.0532 ], [ -60.9705, 46.0342 ], [ -60.9851, 46.0243 ], [ -61.0266, 45.99 ], [ -61.0569, 45.9723 ], [ -61.0969, 45.9559 ], [ -61.1329, 45.9493 ], [ -61.153, 45.9429 ], [ -61.1599, 45.9286 ], [ -61.1427, 45.9268 ], [ -61.114, 45.9303 ], [ -61.0443, 45.9479 ], [ -61.0242, 45.9542 ], [ -60.9944, 45.9592 ], [ -60.9735, 45.9708 ], [ -60.9514, 45.9802 ], [ -60.9499, 45.998 ], [ -60.9568, 46.0114 ], [ -60.9093, 46.0308 ], [ -60.8955, 46.0318 ], [ -60.8694, 46.0196 ], [ -60.8525, 46.025 ], [ -60.8167, 46.0465 ], [ -60.7782, 46.0486 ], [ -60.7801, 46.0381 ], [ -60.8229, 46.0061 ], [ -60.8402, 45.9806 ], [ -60.8413, 45.9477 ], [ -60.8739, 45.9345 ], [ -60.9353, 45.9178 ], [ -60.9663, 45.9225 ], [ -60.9951, 45.919 ], [ -61.0595, 45.9015 ], [ -61.1026, 45.8843 ], [ -61.1352, 45.8471 ], [ -61.117, 45.843 ], [ -61.0928, 45.8517 ], [ -61.0581, 45.8643 ], [ -61.0335, 45.8654 ], [ -61.028, 45.8857 ], [ -61.0026, 45.8921 ], [ -60.9604, 45.8765 ], [ -60.9558, 45.8676 ], [ -60.9896, 45.8565 ], [ -60.9749, 45.8352 ], [ -60.9915, 45.826 ], [ -61.0246, 45.8276 ], [ -61.054, 45.8152 ], [ -61.0987, 45.7875 ], [ -61.152, 45.7627 ], [ -61.1798, 45.7405 ], [ -61.1627, 45.7387 ], [ -61.1484, 45.7248 ], [ -61.1734, 45.7146 ], [ -61.1865, 45.695 ], [ -61.1618, 45.6888 ], [ -61.1175, 45.6964 ], [ -61.0828, 45.7052 ], [ -61.0577, 45.719 ], [ -61.0371, 45.7343 ], [ -60.9994, 45.7514 ], [ -60.972, 45.7571 ], [ -60.8939, 45.7443 ], [ -60.8628, 45.7358 ], [ -60.8484, 45.7219 ], [ -60.8481, 45.7071 ], [ -60.8707, 45.6851 ], [ -60.8847, 45.664 ], [ -60.881, 45.65 ] ] ] } }, { "type": "Feature", "properties": { "NAME_E": "Quebec" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -61.7489, 47.2584 ], [ -61.751, 47.2756 ], [ -61.7303, 47.2821 ], [ -61.7198, 47.2696 ], [ -61.7322, 47.2551 ], [ -61.7489, 47.2584 ] ] ] } }, diff --git a/msautotest/wxs/expected/wfs_shape_tileindex_of_shp_bbox_filter.xml b/msautotest/wxs/expected/wfs_shape_tileindex_of_shp_bbox_filter.xml index 6f0f1d98da..5bd0d92936 100644 --- a/msautotest/wxs/expected/wfs_shape_tileindex_of_shp_bbox_filter.xml +++ b/msautotest/wxs/expected/wfs_shape_tileindex_of_shp_bbox_filter.xml @@ -10,21 +10,21 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 timeStamp="" numberMatched="1" numberReturned="1"> - 49.00000 2.00000 - 49.00000 2.00000 + 49.000000 2.000000 + 49.000000 2.000000 - 49.00000 2.00000 - 49.00000 2.00000 + 49.000000 2.000000 + 49.000000 2.000000 - 49.00000 2.00000 + 49.000000 2.000000 diff --git a/msautotest/wxs/expected/wfs_shape_tileindexmixedsrs_get_feature.xml b/msautotest/wxs/expected/wfs_shape_tileindexmixedsrs_get_feature.xml index a7e392c204..4f3883a479 100644 --- a/msautotest/wxs/expected/wfs_shape_tileindexmixedsrs_get_feature.xml +++ b/msautotest/wxs/expected/wfs_shape_tileindexmixedsrs_get_feature.xml @@ -11,19 +11,19 @@ Content-Type: text/xml; charset=UTF-8 http://mapserver.gis.umn.edu/mapserver http://localhost/path/to/wfs_simple?SERVICE=WFS&VERSION=1.0.0&REQUEST=DescribeFeatureType&TYPENAME=ms:test&OUTPUTFORMAT=XMLSCHEMA"> - 2.00000,49.00000 3.00000,50.00000 + 2.000000,49.000000 3.000000,50.000000 - 2.00000,49.00000 2.00000,49.00000 + 2.000000,49.000000 2.000000,49.000000 - 2.00000,49.00000 + 2.000000,49.000000 @@ -32,12 +32,12 @@ Content-Type: text/xml; charset=UTF-8 - 3.00000,50.00000 3.00000,50.00000 + 3.000000,50.000000 3.000000,50.000000 - 3.00000,50.00000 + 3.000000,50.000000 diff --git a/msautotest/wxs/expected/wfs_time_getfeature.xml b/msautotest/wxs/expected/wfs_time_getfeature.xml index 9fdf50d7eb..fcd940fb4f 100644 --- a/msautotest/wxs/expected/wfs_time_getfeature.xml +++ b/msautotest/wxs/expected/wfs_time_getfeature.xml @@ -10,21 +10,21 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 timeStamp="" numberMatched="25" numberReturned="25"> - 33.65000 -131.02000 - 48.38999 -119.84999 + 33.650002 -131.020004 + 48.389999 -119.849998 - 37.98000 -130.00000 - 37.98000 -130.00000 + 37.980000 -130.000000 + 37.980000 -130.000000 - 37.98000 -130.00000 + 37.980000 -130.000000 2004-01-01 @@ -34,13 +34,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 42.52000 -130.32000 - 42.52000 -130.32000 + 42.520000 -130.320007 + 42.520000 -130.320007 - 42.52000 -130.32000 + 42.520000 -130.320007 2004-01-01 @@ -50,13 +50,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 46.04999 -131.02000 - 46.04999 -131.02000 + 46.049999 -131.020004 + 46.049999 -131.020004 - 46.04999 -131.02000 + 46.049999 -131.020004 2004-01-01 @@ -66,13 +66,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 44.61999 -124.52999 - 44.61999 -124.52999 + 44.619999 -124.529999 + 44.619999 -124.529999 - 44.61999 -124.52999 + 44.619999 -124.529999 2004-01-01 @@ -82,13 +82,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 37.75000 -122.82000 - 37.75000 -122.82000 + 37.750000 -122.820000 + 37.750000 -122.820000 - 37.75000 -122.82000 + 37.750000 -122.820000 2004-01-01 @@ -98,13 +98,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 37.36000 -122.87999 - 37.36000 -122.87999 + 37.360001 -122.879997 + 37.360001 -122.879997 - 37.36000 -122.87999 + 37.360001 -122.879997 2004-01-01 @@ -114,13 +114,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 36.75000 -122.41999 - 36.75000 -122.41999 + 36.750000 -122.419998 + 36.750000 -122.419998 - 36.75000 -122.41999 + 36.750000 -122.419998 2004-01-02 @@ -130,13 +130,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 48.38999 -124.73999 - 48.38999 -124.73999 + 48.389999 -124.739998 + 48.389999 -124.739998 - 48.38999 -124.73999 + 48.389999 -124.739998 2004-01-02 @@ -146,13 +146,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 42.75000 -124.84999 - 42.75000 -124.84999 + 42.750000 -124.849998 + 42.750000 -124.849998 - 42.75000 -124.84999 + 42.750000 -124.849998 2004-01-02 @@ -162,13 +162,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 44.61000 -124.07000 - 44.61000 -124.07000 + 44.610001 -124.070000 + 44.610001 -124.070000 - 44.61000 -124.07000 + 44.610001 -124.070000 2004-01-02 @@ -178,13 +178,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 48.32000 -122.83999 - 48.32000 -122.83999 + 48.320000 -122.839996 + 48.320000 -122.839996 - 48.32000 -122.83999 + 48.320000 -122.839996 2004-01-02 @@ -194,13 +194,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 38.95999 -123.73999 - 38.95999 -123.73999 + 38.959999 -123.739998 + 38.959999 -123.739998 - 38.95999 -123.73999 + 38.959999 -123.739998 2004-01-02 @@ -210,13 +210,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 39.22000 -123.97000 - 39.22000 -123.97000 + 39.220001 -123.970001 + 39.220001 -123.970001 - 39.22000 -123.97000 + 39.220001 -123.970001 2004-01-03 @@ -226,13 +226,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 38.23000 -123.33000 - 38.23000 -123.33000 + 38.230000 -123.330002 + 38.230000 -123.330002 - 38.23000 -123.33000 + 38.230000 -123.330002 2004-01-03 @@ -242,13 +242,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 41.84999 -124.37999 - 41.84999 -124.37999 + 41.849998 -124.379997 + 41.849998 -124.379997 - 41.84999 -124.37999 + 41.849998 -124.379997 2004-01-03 @@ -258,13 +258,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 40.72000 -124.51999 - 40.72000 -124.51999 + 40.720001 -124.519997 + 40.720001 -124.519997 - 40.72000 -124.51999 + 40.720001 -124.519997 2004-01-03 @@ -274,13 +274,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 46.11999 -124.51000 - 46.11999 -124.51000 + 46.119999 -124.510002 + 46.119999 -124.510002 - 46.11999 -124.51000 + 46.119999 -124.510002 2004-01-03 @@ -290,13 +290,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 47.34000 -124.75000 - 47.34000 -124.75000 + 47.340000 -124.750000 + 47.340000 -124.750000 - 47.34000 -124.75000 + 47.340000 -124.750000 2004-01-03 @@ -306,13 +306,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 34.70999 -120.97000 - 34.70999 -120.97000 + 34.709999 -120.970001 + 34.709999 -120.970001 - 34.70999 -120.97000 + 34.709999 -120.970001 2004-01-04 @@ -322,13 +322,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 34.88000 -120.87000 - 34.88000 -120.87000 + 34.880001 -120.870003 + 34.880001 -120.870003 - 34.88000 -120.87000 + 34.880001 -120.870003 2004-01-04 @@ -338,13 +338,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 34.58000 -120.65000 - 34.58000 -120.65000 + 34.580002 -120.650002 + 34.580002 -120.650002 - 34.58000 -120.65000 + 34.580002 -120.650002 2004-01-04 @@ -354,13 +354,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 34.27000 -120.44999 - 34.27000 -120.44999 + 34.270000 -120.449997 + 34.270000 -120.449997 - 34.27000 -120.44999 + 34.270000 -120.449997 2004-01-04 @@ -370,13 +370,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 34.25000 -120.66000 - 34.25000 -120.66000 + 34.250000 -120.660004 + 34.250000 -120.660004 - 34.25000 -120.66000 + 34.250000 -120.660004 2004-01-04 @@ -386,13 +386,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 34.24000 -119.84999 - 34.24000 -119.84999 + 34.240002 -119.849998 + 34.240002 -119.849998 - 34.24000 -119.84999 + 34.240002 -119.849998 2004-01-04 @@ -402,13 +402,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 33.65000 -120.19999 - 33.65000 -120.19999 + 33.650002 -120.199997 + 33.650002 -120.199997 - 33.65000 -120.19999 + 33.650002 -120.199997 2004-01-04 diff --git a/msautotest/wxs/expected/wfs_time_ogr_getfeature.xml b/msautotest/wxs/expected/wfs_time_ogr_getfeature.xml index 9fdf50d7eb..fcd940fb4f 100644 --- a/msautotest/wxs/expected/wfs_time_ogr_getfeature.xml +++ b/msautotest/wxs/expected/wfs_time_ogr_getfeature.xml @@ -10,21 +10,21 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 timeStamp="" numberMatched="25" numberReturned="25"> - 33.65000 -131.02000 - 48.38999 -119.84999 + 33.650002 -131.020004 + 48.389999 -119.849998 - 37.98000 -130.00000 - 37.98000 -130.00000 + 37.980000 -130.000000 + 37.980000 -130.000000 - 37.98000 -130.00000 + 37.980000 -130.000000 2004-01-01 @@ -34,13 +34,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 42.52000 -130.32000 - 42.52000 -130.32000 + 42.520000 -130.320007 + 42.520000 -130.320007 - 42.52000 -130.32000 + 42.520000 -130.320007 2004-01-01 @@ -50,13 +50,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 46.04999 -131.02000 - 46.04999 -131.02000 + 46.049999 -131.020004 + 46.049999 -131.020004 - 46.04999 -131.02000 + 46.049999 -131.020004 2004-01-01 @@ -66,13 +66,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 44.61999 -124.52999 - 44.61999 -124.52999 + 44.619999 -124.529999 + 44.619999 -124.529999 - 44.61999 -124.52999 + 44.619999 -124.529999 2004-01-01 @@ -82,13 +82,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 37.75000 -122.82000 - 37.75000 -122.82000 + 37.750000 -122.820000 + 37.750000 -122.820000 - 37.75000 -122.82000 + 37.750000 -122.820000 2004-01-01 @@ -98,13 +98,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 37.36000 -122.87999 - 37.36000 -122.87999 + 37.360001 -122.879997 + 37.360001 -122.879997 - 37.36000 -122.87999 + 37.360001 -122.879997 2004-01-01 @@ -114,13 +114,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 36.75000 -122.41999 - 36.75000 -122.41999 + 36.750000 -122.419998 + 36.750000 -122.419998 - 36.75000 -122.41999 + 36.750000 -122.419998 2004-01-02 @@ -130,13 +130,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 48.38999 -124.73999 - 48.38999 -124.73999 + 48.389999 -124.739998 + 48.389999 -124.739998 - 48.38999 -124.73999 + 48.389999 -124.739998 2004-01-02 @@ -146,13 +146,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 42.75000 -124.84999 - 42.75000 -124.84999 + 42.750000 -124.849998 + 42.750000 -124.849998 - 42.75000 -124.84999 + 42.750000 -124.849998 2004-01-02 @@ -162,13 +162,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 44.61000 -124.07000 - 44.61000 -124.07000 + 44.610001 -124.070000 + 44.610001 -124.070000 - 44.61000 -124.07000 + 44.610001 -124.070000 2004-01-02 @@ -178,13 +178,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 48.32000 -122.83999 - 48.32000 -122.83999 + 48.320000 -122.839996 + 48.320000 -122.839996 - 48.32000 -122.83999 + 48.320000 -122.839996 2004-01-02 @@ -194,13 +194,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 38.95999 -123.73999 - 38.95999 -123.73999 + 38.959999 -123.739998 + 38.959999 -123.739998 - 38.95999 -123.73999 + 38.959999 -123.739998 2004-01-02 @@ -210,13 +210,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 39.22000 -123.97000 - 39.22000 -123.97000 + 39.220001 -123.970001 + 39.220001 -123.970001 - 39.22000 -123.97000 + 39.220001 -123.970001 2004-01-03 @@ -226,13 +226,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 38.23000 -123.33000 - 38.23000 -123.33000 + 38.230000 -123.330002 + 38.230000 -123.330002 - 38.23000 -123.33000 + 38.230000 -123.330002 2004-01-03 @@ -242,13 +242,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 41.84999 -124.37999 - 41.84999 -124.37999 + 41.849998 -124.379997 + 41.849998 -124.379997 - 41.84999 -124.37999 + 41.849998 -124.379997 2004-01-03 @@ -258,13 +258,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 40.72000 -124.51999 - 40.72000 -124.51999 + 40.720001 -124.519997 + 40.720001 -124.519997 - 40.72000 -124.51999 + 40.720001 -124.519997 2004-01-03 @@ -274,13 +274,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 46.11999 -124.51000 - 46.11999 -124.51000 + 46.119999 -124.510002 + 46.119999 -124.510002 - 46.11999 -124.51000 + 46.119999 -124.510002 2004-01-03 @@ -290,13 +290,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 47.34000 -124.75000 - 47.34000 -124.75000 + 47.340000 -124.750000 + 47.340000 -124.750000 - 47.34000 -124.75000 + 47.340000 -124.750000 2004-01-03 @@ -306,13 +306,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 34.70999 -120.97000 - 34.70999 -120.97000 + 34.709999 -120.970001 + 34.709999 -120.970001 - 34.70999 -120.97000 + 34.709999 -120.970001 2004-01-04 @@ -322,13 +322,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 34.88000 -120.87000 - 34.88000 -120.87000 + 34.880001 -120.870003 + 34.880001 -120.870003 - 34.88000 -120.87000 + 34.880001 -120.870003 2004-01-04 @@ -338,13 +338,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 34.58000 -120.65000 - 34.58000 -120.65000 + 34.580002 -120.650002 + 34.580002 -120.650002 - 34.58000 -120.65000 + 34.580002 -120.650002 2004-01-04 @@ -354,13 +354,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 34.27000 -120.44999 - 34.27000 -120.44999 + 34.270000 -120.449997 + 34.270000 -120.449997 - 34.27000 -120.44999 + 34.270000 -120.449997 2004-01-04 @@ -370,13 +370,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 34.25000 -120.66000 - 34.25000 -120.66000 + 34.250000 -120.660004 + 34.250000 -120.660004 - 34.25000 -120.66000 + 34.250000 -120.660004 2004-01-04 @@ -386,13 +386,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 34.24000 -119.84999 - 34.24000 -119.84999 + 34.240002 -119.849998 + 34.240002 -119.849998 - 34.24000 -119.84999 + 34.240002 -119.849998 2004-01-04 @@ -402,13 +402,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 33.65000 -120.19999 - 33.65000 -120.19999 + 33.650002 -120.199997 + 33.650002 -120.199997 - 33.65000 -120.19999 + 33.650002 -120.199997 2004-01-04 diff --git a/msautotest/wxs/expected/wfs_time_postgis_date_getfeature.xml b/msautotest/wxs/expected/wfs_time_postgis_date_getfeature.xml index 3d470be9fb..090915f29a 100644 --- a/msautotest/wxs/expected/wfs_time_postgis_date_getfeature.xml +++ b/msautotest/wxs/expected/wfs_time_postgis_date_getfeature.xml @@ -11,21 +11,21 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 next="http://localhost/path/to/wfs_simple?myparam=something&SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAMES=date&MAXFEATURES=1&STARTINDEX=1"> - 37.98000 -130.00000 - 37.98000 -130.00000 + 37.980000 -130.000000 + 37.980000 -130.000000 - 37.98000 -130.00000 - 37.98000 -130.00000 + 37.980000 -130.000000 + 37.980000 -130.000000 - 37.98000 -130.00000 + 37.980000 -130.000000 2004-01-01 diff --git a/msautotest/wxs/expected/wfs_time_postgis_datetime_getfeature.xml b/msautotest/wxs/expected/wfs_time_postgis_datetime_getfeature.xml index ca06ff7aa3..a237654634 100644 --- a/msautotest/wxs/expected/wfs_time_postgis_datetime_getfeature.xml +++ b/msautotest/wxs/expected/wfs_time_postgis_datetime_getfeature.xml @@ -10,21 +10,21 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 timeStamp="" numberMatched="25" numberReturned="25"> - 33.65000 -131.02000 - 48.38999 -119.84999 + 33.650002 -131.020004 + 48.389999 -119.849998 - 37.98000 -130.00000 - 37.98000 -130.00000 + 37.980000 -130.000000 + 37.980000 -130.000000 - 37.98000 -130.00000 + 37.980000 -130.000000 2004-01-01T00:00:00Z @@ -34,13 +34,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 42.52000 -130.32000 - 42.52000 -130.32000 + 42.520000 -130.320007 + 42.520000 -130.320007 - 42.52000 -130.32000 + 42.520000 -130.320007 2004-01-01T00:00:00Z @@ -50,13 +50,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 46.04999 -131.02000 - 46.04999 -131.02000 + 46.049999 -131.020004 + 46.049999 -131.020004 - 46.04999 -131.02000 + 46.049999 -131.020004 2004-01-01T00:00:00Z @@ -66,13 +66,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 44.61999 -124.52999 - 44.61999 -124.52999 + 44.619999 -124.529999 + 44.619999 -124.529999 - 44.61999 -124.52999 + 44.619999 -124.529999 2004-01-01T00:00:00Z @@ -82,13 +82,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 37.75000 -122.82000 - 37.75000 -122.82000 + 37.750000 -122.820000 + 37.750000 -122.820000 - 37.75000 -122.82000 + 37.750000 -122.820000 2004-01-01T00:00:00Z @@ -98,13 +98,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 37.36000 -122.87999 - 37.36000 -122.87999 + 37.360001 -122.879997 + 37.360001 -122.879997 - 37.36000 -122.87999 + 37.360001 -122.879997 2004-01-01T00:00:00Z @@ -114,13 +114,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 36.75000 -122.41999 - 36.75000 -122.41999 + 36.750000 -122.419998 + 36.750000 -122.419998 - 36.75000 -122.41999 + 36.750000 -122.419998 2004-01-02T00:00:00Z @@ -130,13 +130,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 48.38999 -124.73999 - 48.38999 -124.73999 + 48.389999 -124.739998 + 48.389999 -124.739998 - 48.38999 -124.73999 + 48.389999 -124.739998 2004-01-02T00:00:00Z @@ -146,13 +146,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 42.75000 -124.84999 - 42.75000 -124.84999 + 42.750000 -124.849998 + 42.750000 -124.849998 - 42.75000 -124.84999 + 42.750000 -124.849998 2004-01-02T00:00:00Z @@ -162,13 +162,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 44.61000 -124.07000 - 44.61000 -124.07000 + 44.610001 -124.070000 + 44.610001 -124.070000 - 44.61000 -124.07000 + 44.610001 -124.070000 2004-01-02T00:00:00Z @@ -178,13 +178,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 48.32000 -122.83999 - 48.32000 -122.83999 + 48.320000 -122.839996 + 48.320000 -122.839996 - 48.32000 -122.83999 + 48.320000 -122.839996 2004-01-02T00:00:00Z @@ -194,13 +194,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 38.95999 -123.73999 - 38.95999 -123.73999 + 38.959999 -123.739998 + 38.959999 -123.739998 - 38.95999 -123.73999 + 38.959999 -123.739998 2004-01-02T00:00:00Z @@ -210,13 +210,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 39.22000 -123.97000 - 39.22000 -123.97000 + 39.220001 -123.970001 + 39.220001 -123.970001 - 39.22000 -123.97000 + 39.220001 -123.970001 2004-01-03T00:00:00Z @@ -226,13 +226,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 38.23000 -123.33000 - 38.23000 -123.33000 + 38.230000 -123.330002 + 38.230000 -123.330002 - 38.23000 -123.33000 + 38.230000 -123.330002 2004-01-03T00:00:00Z @@ -242,13 +242,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 41.84999 -124.37999 - 41.84999 -124.37999 + 41.849998 -124.379997 + 41.849998 -124.379997 - 41.84999 -124.37999 + 41.849998 -124.379997 2004-01-03T00:00:00Z @@ -258,13 +258,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 40.72000 -124.51999 - 40.72000 -124.51999 + 40.720001 -124.519997 + 40.720001 -124.519997 - 40.72000 -124.51999 + 40.720001 -124.519997 2004-01-03T00:00:00Z @@ -274,13 +274,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 46.11999 -124.51000 - 46.11999 -124.51000 + 46.119999 -124.510002 + 46.119999 -124.510002 - 46.11999 -124.51000 + 46.119999 -124.510002 2004-01-03T00:00:00Z @@ -290,13 +290,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 47.34000 -124.75000 - 47.34000 -124.75000 + 47.340000 -124.750000 + 47.340000 -124.750000 - 47.34000 -124.75000 + 47.340000 -124.750000 2004-01-03T00:00:00Z @@ -306,13 +306,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 34.70999 -120.97000 - 34.70999 -120.97000 + 34.709999 -120.970001 + 34.709999 -120.970001 - 34.70999 -120.97000 + 34.709999 -120.970001 2004-01-04T00:00:00Z @@ -322,13 +322,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 34.88000 -120.87000 - 34.88000 -120.87000 + 34.880001 -120.870003 + 34.880001 -120.870003 - 34.88000 -120.87000 + 34.880001 -120.870003 2004-01-04T00:00:00Z @@ -338,13 +338,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 34.58000 -120.65000 - 34.58000 -120.65000 + 34.580002 -120.650002 + 34.580002 -120.650002 - 34.58000 -120.65000 + 34.580002 -120.650002 2004-01-04T00:00:00Z @@ -354,13 +354,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 34.27000 -120.44999 - 34.27000 -120.44999 + 34.270000 -120.449997 + 34.270000 -120.449997 - 34.27000 -120.44999 + 34.270000 -120.449997 2004-01-04T00:00:00Z @@ -370,13 +370,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 34.25000 -120.66000 - 34.25000 -120.66000 + 34.250000 -120.660004 + 34.250000 -120.660004 - 34.25000 -120.66000 + 34.250000 -120.660004 2004-01-04T00:00:00Z @@ -386,13 +386,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 34.24000 -119.84999 - 34.24000 -119.84999 + 34.240002 -119.849998 + 34.240002 -119.849998 - 34.24000 -119.84999 + 34.240002 -119.849998 2004-01-04T00:00:00Z @@ -402,13 +402,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 33.65000 -120.19999 - 33.65000 -120.19999 + 33.650002 -120.199997 + 33.650002 -120.199997 - 33.65000 -120.19999 + 33.650002 -120.199997 2004-01-04T00:00:00Z diff --git a/msautotest/wxs/expected/wfs_time_postgis_datetime_sortby.xml b/msautotest/wxs/expected/wfs_time_postgis_datetime_sortby.xml index bc349cda87..15ad4c1abe 100644 --- a/msautotest/wxs/expected/wfs_time_postgis_datetime_sortby.xml +++ b/msautotest/wxs/expected/wfs_time_postgis_datetime_sortby.xml @@ -10,21 +10,21 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 timeStamp="" numberMatched="unknown" numberReturned="1"> - 34.70999 -120.97000 - 34.70999 -120.97000 + 34.709999 -120.970001 + 34.709999 -120.970001 - 34.70999 -120.97000 - 34.70999 -120.97000 + 34.709999 -120.970001 + 34.709999 -120.970001 - 34.70999 -120.97000 + 34.709999 -120.970001 2004-01-04T00:00:00Z diff --git a/msautotest/wxs/expected/wfs_time_postgis_time_getfeature.xml b/msautotest/wxs/expected/wfs_time_postgis_time_getfeature.xml index d015d91857..9e70cbefc9 100644 --- a/msautotest/wxs/expected/wfs_time_postgis_time_getfeature.xml +++ b/msautotest/wxs/expected/wfs_time_postgis_time_getfeature.xml @@ -11,21 +11,21 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 next="http://localhost/path/to/wfs_simple?myparam=something&SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAMES=time&MAXFEATURES=1&STARTINDEX=1"> - 37.98000 -130.00000 - 37.98000 -130.00000 + 37.980000 -130.000000 + 37.980000 -130.000000 - 37.98000 -130.00000 - 37.98000 -130.00000 + 37.980000 -130.000000 + 37.980000 -130.000000 - 37.98000 -130.00000 + 37.980000 -130.000000 12:34:56Z diff --git a/msautotest/wxs/expected/wfsogr10_bnazip.zip b/msautotest/wxs/expected/wfsogr10_bnazip.zip deleted file mode 100644 index c7af8286d1..0000000000 Binary files a/msautotest/wxs/expected/wfsogr10_bnazip.zip and /dev/null differ diff --git a/msautotest/wxs/expected/wfsogr10_caps.xml b/msautotest/wxs/expected/wfsogr10_caps.xml index 1082857629..b7b5fe70b9 100644 --- a/msautotest/wxs/expected/wfsogr10_caps.xml +++ b/msautotest/wxs/expected/wfsogr10_caps.xml @@ -8,7 +8,6 @@ Content-Type: text/xml; charset=UTF-8 xmlns:ogc="http://www.opengis.net/ogc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opengis.net/wfs http://schemas.opengis.net/wfs/1.0.0/WFS-capabilities.xsd"> - MapServer WFS Test simple wfs @@ -60,8 +59,9 @@ Content-Type: text/xml; charset=UTF-8 - + + @@ -88,42 +88,42 @@ Content-Type: text/xml; charset=UTF-8 road road EPSG:3978 - + http://localhost/path/to/wfs_simple?request=GetMetadata&layer=road popplace popplace EPSG:3978 - + http://localhost/path/to/wfs_simple?request=GetMetadata&layer=popplace road_with_addfiles road_with_addfiles EPSG:3978 - + http://localhost/path/to/wfs_simple?request=GetMetadata&layer=road_with_addfiles road2_with_addfiles road2_with_addfiles EPSG:3978 - + http://localhost/path/to/wfs_simple?request=GetMetadata&layer=road2_with_addfiles multi multi EPSG:27700 - + http://localhost/path/to/wfs_simple?request=GetMetadata&layer=multi withnullvalues withnullvalues EPSG:27700 - + http://localhost/path/to/wfs_simple?request=GetMetadata&layer=withnullvalues diff --git a/msautotest/wxs/expected/wfsogr10_csvzip.zip b/msautotest/wxs/expected/wfsogr10_csvzip.zip new file mode 100644 index 0000000000..a410626dfd Binary files /dev/null and b/msautotest/wxs/expected/wfsogr10_csvzip.zip differ diff --git a/msautotest/wxs/expected/wfsogr10_datetime.xml b/msautotest/wxs/expected/wfsogr10_datetime.xml new file mode 100644 index 0000000000..a424bccdc8 --- /dev/null +++ b/msautotest/wxs/expected/wfsogr10_datetime.xml @@ -0,0 +1,58 @@ + + + + + 10.000000,30.000000 10.000000,30.000000 + + + + + + + 10.000000,30.000000 10.000000,30.000000 + + + + + 10.000000,30.000000 + + + 1 + 2 + 3.4 + 2021-12-15 + 12:41:00Z + 2021-12-15T12:41:00+01:15 + POINT(10 30) + + + + + + + 10.000000,30.000000 10.000000,30.000000 + + + + + 10.000000,30.000000 + + + 2 + + + + + 2021-12-15T11:41:12Z + POINT(10 30) + + + + diff --git a/msautotest/wxs/expected/wfsogr10_geojson.json b/msautotest/wxs/expected/wfsogr10_geojson.json index 16b098601d..119b4f1e1f 100644 --- a/msautotest/wxs/expected/wfsogr10_geojson.json +++ b/msautotest/wxs/expected/wfsogr10_geojson.json @@ -4,6 +4,7 @@ Content-Type: application/json; subtype=geojson; charset=utf-8 "type": "FeatureCollection", "name": "popplace_fid", "crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:EPSG::3978" } }, +"xy_coordinate_resolution": 1e-05, "features": [ { "type": "Feature", "id": 0, "properties": { "UNIQUE_KEY": "BACMK", "NAME": "\"Tignish", "CAPITAL": 0, "POP_CLASS": 1 }, "geometry": { "type": "Point", "coordinates": [ 2281604.25, 340848.9375 ] } }, { "type": "Feature", "id": 1215011, "properties": { "UNIQUE_KEY": "CAGYX", "NAME": "'Cheticamp", "CAPITAL": 0, "POP_CLASS": 2 }, "geometry": { "type": "Point", "coordinates": [ 2503805.5, 427872.65625 ] } }, diff --git a/msautotest/wxs/expected/wfsogr10_gpx.xml b/msautotest/wxs/expected/wfsogr10_gpx.xml index d9d9c6240d..55e48849db 100644 --- a/msautotest/wxs/expected/wfsogr10_gpx.xml +++ b/msautotest/wxs/expected/wfsogr10_gpx.xml @@ -3,7 +3,9 @@ Content-Type: application/gpx+xml; streamed - + + + 613 diff --git a/msautotest/wxs/expected/wfsogr10_multi.xml b/msautotest/wxs/expected/wfsogr10_multi.xml index a78c880780..17b00a1ff6 100644 --- a/msautotest/wxs/expected/wfsogr10_multi.xml +++ b/msautotest/wxs/expected/wfsogr10_multi.xml @@ -7,33 +7,31 @@ Content-Transfer-Encoding: binary - - - 00 - 100100 - - - - - - 0,0 0,10 10,0 0,01,1 2,2 2,1 1,1100,50 50,100 100,100 100,50 + xmlns:gml="http://www.opengis.net/gml/3.2"> + 0 0100 100 + + + + 0 0100 100 + 0 0 0 10 10 0 0 01 1 2 2 2 1 1 1100 50 50 100 100 100 100 50 4 mp MULTIPOLYGON(((0 0,0 10,10 0,0 0),(1 1,2 2,2 1,1 1)),((100 50,50 100,100 100))) - - - - 30,0 30,10 40,10 40,0 3,0 30,031,1 32,2 32,1 31,1 + + + + 3 040 10 + 30 0 30 10 40 10 40 0 3 0 30 031 1 32 2 32 1 31 1 5 poly POLYGON((30 0,30 10,40 10,40 0,3 0),(31 1,32 2,32 1,31 1)) - + --xxOGRBoundaryxx @@ -42,23 +40,47 @@ Content-Type: application/binary Content-Transfer-Encoding: binary - - - + + + + 0 + + + + + - - - + + + + + + + + + + + + + + - + - + diff --git a/msautotest/wxs/expected/wfsogr10_nullnumeric.csv b/msautotest/wxs/expected/wfsogr10_nullnumeric.csv new file mode 100644 index 0000000000..90f8fc1c0a --- /dev/null +++ b/msautotest/wxs/expected/wfsogr10_nullnumeric.csv @@ -0,0 +1,3 @@ +WKT,id,intvalue,floatvalue,date,time,datetime,WKT +"POINT (10 30)",1,2,3.4,2021/12/15,12:41:00,2021/12/15 12:41:00+0115,POINT(10 30) +"POINT (10 30)",2,,,,,2021/12/15 11:41:12+00,POINT(10 30) diff --git a/msautotest/wxs/expected/wfsogr10_nullnumeric.xml b/msautotest/wxs/expected/wfsogr10_nullnumeric.xml deleted file mode 100644 index cb78d3160a..0000000000 --- a/msautotest/wxs/expected/wfsogr10_nullnumeric.xml +++ /dev/null @@ -1,6 +0,0 @@ -Content-Disposition: attachment; filename=result.csv -Content-Type: text/csv - -WKT,id,intvalue,floatvalue,WKT -"POINT (10 30)",1,2,3.4,POINT(10 30) -"POINT (10 30)",2,,,POINT(10 30) diff --git a/msautotest/wxs/expected/wfsogr10_ograuto.xml b/msautotest/wxs/expected/wfsogr10_ograuto.xml index 12face4c89..a21adcfc58 100644 --- a/msautotest/wxs/expected/wfsogr10_ograuto.xml +++ b/msautotest/wxs/expected/wfsogr10_ograuto.xml @@ -7,26 +7,23 @@ Content-Transfer-Encoding: binary - - - 2281604.25340848.9375 - 2281604.25340848.9375 - - - - - - 2281604.25,340848.9375 + xmlns:gml="http://www.opengis.net/gml/3.2"> + 2281604.25 340848.93752281604.25 340848.9375 + + + + 2281604.25 340848.93752281604.25 340848.9375 + 2281604.25 340848.9375 BACMK "Tignish 0 1 - + --xxOGRBoundaryxx @@ -35,23 +32,47 @@ Content-Type: application/binary Content-Transfer-Encoding: binary - - - + + + + 0 + + + + + - - - + + + + + + + + + + + + + + - + - + diff --git a/msautotest/wxs/expected/wfsogr10_ogrgml.xml b/msautotest/wxs/expected/wfsogr10_ogrgml.xml index ed7003a514..2e90f061b6 100644 --- a/msautotest/wxs/expected/wfsogr10_ogrgml.xml +++ b/msautotest/wxs/expected/wfsogr10_ogrgml.xml @@ -7,20 +7,17 @@ Content-Transfer-Encoding: binary - - - 2576803.5399102.1875 - 2589745.5402556.25 - - - - - - 2589745.5,402556.25 2588416.5,401601.0625 2587278.5,400455.71875 2585757.5,399880.53125 2582523.25,399110.65625 2581190.5,399107.1875 2579286.75,399102.1875 2577761.5,399669.40625 2576803.5,401189.875 + xmlns:gml="http://www.opengis.net/gml/3.2"> + 2576803.5 399102.18752589745.5 402556.25 + + + + 2576803.5 399102.18752589745.5 402556.25 + 2589745.5 402556.25 2588416.5 401601.0625 2587278.5 400455.71875 2585757.5 399880.53125 2582523.25 399110.65625 2581190.5 399107.1875 2579286.75 399102.1875 2577761.5 399669.40625 2576803.5 401189.875 613 1511 0 @@ -31,7 +28,7 @@ Content-Transfer-Encoding: binary - + --xxOGRBoundaryxx @@ -40,23 +37,47 @@ Content-Type: application/binary Content-Transfer-Encoding: binary - - - + + + + 0 + + + + + - - - + + + + + + + + + + + + + + - + - + diff --git a/msautotest/wxs/expected/wfsogr10_shapezip.zip b/msautotest/wxs/expected/wfsogr10_shapezip.zip deleted file mode 100644 index 8f56187091..0000000000 Binary files a/msautotest/wxs/expected/wfsogr10_shapezip.zip and /dev/null differ diff --git a/msautotest/wxs/expected/wfsogr10_shapezip.zip.with_headers b/msautotest/wxs/expected/wfsogr10_shapezip.zip.with_headers new file mode 100644 index 0000000000..0df9671d67 Binary files /dev/null and b/msautotest/wxs/expected/wfsogr10_shapezip.zip.with_headers differ diff --git a/msautotest/wxs/expected/wfsogr10_shapezipmem.zip.with_headers b/msautotest/wxs/expected/wfsogr10_shapezipmem.zip.with_headers new file mode 100644 index 0000000000..0df9671d67 Binary files /dev/null and b/msautotest/wxs/expected/wfsogr10_shapezipmem.zip.with_headers differ diff --git a/msautotest/wxs/expected/wfsogr11_caps.xml b/msautotest/wxs/expected/wfsogr11_caps.xml index e744eb17f4..2574d1f53f 100644 --- a/msautotest/wxs/expected/wfsogr11_caps.xml +++ b/msautotest/wxs/expected/wfsogr11_caps.xml @@ -91,7 +91,7 @@ Content-Type: text/xml; charset=UTF-8 text/csv; streamed text/xml; subtype=gml/2.1.2; driver=ogr application/gpx+xml; streamed - application/zip; driver=ogr/bna + application/zip; driver=ogr/csv application/shapefile MIDMIF MultiMIDMIF @@ -113,14 +113,14 @@ Content-Type: text/xml; charset=UTF-8 text/csv; streamed text/xml; subtype=gml/2.1.2; driver=ogr application/gpx+xml; streamed - application/zip; driver=ogr/bna + application/zip; driver=ogr/csv application/shapefile MIDMIF MultiMIDMIF - -66.633317770969 42.382053788395 - -59.292113839180 48.295511938680 + -66.633318 42.382054 + -59.292114 48.295512 http://localhost/path/to/wfs_simple?request=GetMetadata&layer=road @@ -138,8 +138,8 @@ Content-Type: text/xml; charset=UTF-8 application/json; subtype=geojson - -66.328616887533 42.5631251681 - -59.688212172925 47.941250727064 + -66.328617 42.563125 + -59.688212 47.941251 http://localhost/path/to/wfs_simple?request=GetMetadata&layer=popplace @@ -153,14 +153,14 @@ Content-Type: text/xml; charset=UTF-8 text/csv; streamed text/xml; subtype=gml/2.1.2; driver=ogr application/gpx+xml; streamed - application/zip; driver=ogr/bna + application/zip; driver=ogr/csv application/shapefile MIDMIF MultiMIDMIF - -66.633317770969 42.382053788395 - -59.292113839180 48.295511938680 + -66.633318 42.382054 + -59.292114 48.295512 http://localhost/path/to/wfs_simple?request=GetMetadata&layer=road_with_addfiles @@ -174,14 +174,14 @@ Content-Type: text/xml; charset=UTF-8 text/csv; streamed text/xml; subtype=gml/2.1.2; driver=ogr application/gpx+xml; streamed - application/zip; driver=ogr/bna + application/zip; driver=ogr/csv application/shapefile MIDMIF MultiMIDMIF - -66.633317770969 42.382053788395 - -59.292113839180 48.295511938680 + -66.633318 42.382054 + -59.292114 48.295512 http://localhost/path/to/wfs_simple?request=GetMetadata&layer=road2_with_addfiles @@ -197,8 +197,8 @@ Content-Type: text/xml; charset=UTF-8 MIDMIF - -7.5565511764371 49.766185810692 - -7.5550662982001 49.767147583362 + -7.556551 49.766186 + -7.555066 49.767148 http://localhost/path/to/wfs_simple?request=GetMetadata&layer=multi @@ -215,8 +215,8 @@ Content-Type: text/xml; charset=UTF-8 application/json; subtype=geojson - -7.556341092866 49.766461046013 - -7.556341092866 49.766461046013 + -7.556341 49.766461 + -7.556341 49.766461 http://localhost/path/to/wfs_simple?request=GetMetadata&layer=withnullvalues diff --git a/msautotest/wxs/expected/wfsogr11_ogrgml.xml b/msautotest/wxs/expected/wfsogr11_ogrgml.xml index 0ce73b91e2..4ff3e13486 100644 --- a/msautotest/wxs/expected/wfsogr11_ogrgml.xml +++ b/msautotest/wxs/expected/wfsogr11_ogrgml.xml @@ -7,44 +7,43 @@ Content-Transfer-Encoding: binary - - - 2434957194088.234375 - 2578914.25347013.59375 - - - - - - 2499190.0,194088.234375 + xmlns:gml="http://www.opengis.net/gml/3.2"> + 2434957.0 194088.2343752578914.25 347013.59375 + + + + 2499190.0 194088.2343752499190.0 194088.234375 + 2499190.0 194088.234375 CBIKA Sheet Harbour 0 2 - - - - 2434957.0,347013.59375 + + + + 2434957.0 347013.593752434957.0 347013.59375 + 2434957.0 347013.59375 BACII 'Souris' 0 2 - - - - 2578914.25,292073.09375 + + + + 2578914.25 292073.093752578914.25 292073.09375 + 2578914.25 292073.09375 CAGBW "Canso" 0 2 - + --xxOGRBoundaryxx @@ -53,23 +52,47 @@ Content-Type: application/binary Content-Transfer-Encoding: binary - - - + + + + 0 + + + + + - - - + + + + + + + + + + + + + + - + - + diff --git a/msautotest/wxs/expected/wfsogr11_post_sortby.xml b/msautotest/wxs/expected/wfsogr11_post_sortby.xml index c30de3470e..4e510b881f 100644 --- a/msautotest/wxs/expected/wfsogr11_post_sortby.xml +++ b/msautotest/wxs/expected/wfsogr11_post_sortby.xml @@ -10,21 +10,21 @@ Content-Type: text/xml; subtype=gml/3.1.1; charset=UTF-8 xsi:schemaLocation="http://mapserver.gis.umn.edu/mapserver http://localhost/path/to/wfs_simple?SERVICE=WFS&VERSION=1.1.0&REQUEST=DescribeFeatureType&TYPENAME=popplace&OUTPUTFORMAT=text/xml;%20subtype=gml/3.1.1 http://www.opengis.net/wfs http://schemas.opengis.net/wfs/1.1.0/wfs.xsd"> - 2281604.25000 135734.70312 - 2402416.50000 461586.81250 + 2281604.250000 135734.703125 + 2402416.500000 461586.812500 - 2281604.25000 340848.93750 - 2281604.25000 340848.93750 + 2281604.250000 340848.937500 + 2281604.250000 340848.937500 - 2281604.25000 340848.93750 + 2281604.250000 340848.937500 BACMK @@ -37,13 +37,13 @@ Content-Type: text/xml; subtype=gml/3.1.1; charset=UTF-8 - 2402416.50000 461586.81250 - 2402416.50000 461586.81250 + 2402416.500000 461586.812500 + 2402416.500000 461586.812500 - 2402416.50000 461586.81250 + 2402416.500000 461586.812500 EGIIG @@ -56,13 +56,13 @@ Content-Type: text/xml; subtype=gml/3.1.1; charset=UTF-8 - 2377598.00000 135734.70312 - 2377598.00000 135734.70312 + 2377598.000000 135734.703125 + 2377598.000000 135734.703125 - 2377598.00000 135734.70312 + 2377598.000000 135734.703125 CBPAK diff --git a/msautotest/wxs/expected/wfsogr11_sortby.xml b/msautotest/wxs/expected/wfsogr11_sortby.xml index c30de3470e..4e510b881f 100644 --- a/msautotest/wxs/expected/wfsogr11_sortby.xml +++ b/msautotest/wxs/expected/wfsogr11_sortby.xml @@ -10,21 +10,21 @@ Content-Type: text/xml; subtype=gml/3.1.1; charset=UTF-8 xsi:schemaLocation="http://mapserver.gis.umn.edu/mapserver http://localhost/path/to/wfs_simple?SERVICE=WFS&VERSION=1.1.0&REQUEST=DescribeFeatureType&TYPENAME=popplace&OUTPUTFORMAT=text/xml;%20subtype=gml/3.1.1 http://www.opengis.net/wfs http://schemas.opengis.net/wfs/1.1.0/wfs.xsd"> - 2281604.25000 135734.70312 - 2402416.50000 461586.81250 + 2281604.250000 135734.703125 + 2402416.500000 461586.812500 - 2281604.25000 340848.93750 - 2281604.25000 340848.93750 + 2281604.250000 340848.937500 + 2281604.250000 340848.937500 - 2281604.25000 340848.93750 + 2281604.250000 340848.937500 BACMK @@ -37,13 +37,13 @@ Content-Type: text/xml; subtype=gml/3.1.1; charset=UTF-8 - 2402416.50000 461586.81250 - 2402416.50000 461586.81250 + 2402416.500000 461586.812500 + 2402416.500000 461586.812500 - 2402416.50000 461586.81250 + 2402416.500000 461586.812500 EGIIG @@ -56,13 +56,13 @@ Content-Type: text/xml; subtype=gml/3.1.1; charset=UTF-8 - 2377598.00000 135734.70312 - 2377598.00000 135734.70312 + 2377598.000000 135734.703125 + 2377598.000000 135734.703125 - 2377598.00000 135734.70312 + 2377598.000000 135734.703125 CBPAK diff --git a/msautotest/wxs/expected/wfsogr20_geojson.json b/msautotest/wxs/expected/wfsogr20_geojson.json index 5f3ea40185..cbb502346a 100644 --- a/msautotest/wxs/expected/wfsogr20_geojson.json +++ b/msautotest/wxs/expected/wfsogr20_geojson.json @@ -5,6 +5,7 @@ Content-Type: application/json; subtype=geojson; charset=utf-8 "numberMatched": 28, "name": "popplace_fid", "crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:EPSG::3978" } }, +"xy_coordinate_resolution": 1e-05, "features": [ { "type": "Feature", "id": 0, "properties": { "UNIQUE_KEY": "BACMK", "NAME": "\"Tignish", "CAPITAL": 0, "POP_CLASS": 1 }, "geometry": { "type": "Point", "coordinates": [ 2281604.25, 340848.9375 ] } }, { "type": "Feature", "id": 1215011, "properties": { "UNIQUE_KEY": "CAGYX", "NAME": "'Cheticamp", "CAPITAL": 0, "POP_CLASS": 2 }, "geometry": { "type": "Point", "coordinates": [ 2503805.5, 427872.65625 ] } }, diff --git a/msautotest/wxs/expected/wfsogr20_geojson_resulttype_hits.xml b/msautotest/wxs/expected/wfsogr20_geojson_resulttype_hits.xml new file mode 100644 index 0000000000..de1be6f968 --- /dev/null +++ b/msautotest/wxs/expected/wfsogr20_geojson_resulttype_hits.xml @@ -0,0 +1,12 @@ +Content-Type: text/xml; charset=UTF-8 + + + + + diff --git a/msautotest/wxs/expected/wfsogr20_geojson_with_predefine_native_data.json b/msautotest/wxs/expected/wfsogr20_geojson_with_predefine_native_data.json index 8d16786611..632a9f98a3 100644 --- a/msautotest/wxs/expected/wfsogr20_geojson_with_predefine_native_data.json +++ b/msautotest/wxs/expected/wfsogr20_geojson_with_predefine_native_data.json @@ -6,6 +6,7 @@ Content-Type: application/json; subtype=geojson; charset=utf-8 "numberMatched": 28, "name": "popplace_fid", "crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:EPSG::3978" } }, +"xy_coordinate_resolution": 1e-05, "features": [ { "type": "Feature", "id": 0, "properties": { "UNIQUE_KEY": "BACMK", "NAME": "\"Tignish", "CAPITAL": 0, "POP_CLASS": 1 }, "geometry": { "type": "Point", "coordinates": [ 2281604.25, 340848.9375 ] } }, { "type": "Feature", "id": 1215011, "properties": { "UNIQUE_KEY": "CAGYX", "NAME": "'Cheticamp", "CAPITAL": 0, "POP_CLASS": 2 }, "geometry": { "type": "Point", "coordinates": [ 2503805.5, 427872.65625 ] } }, diff --git a/msautotest/wxs/expected/wfsogr_200_multiplelayers.xml b/msautotest/wxs/expected/wfsogr_200_multiplelayers.xml index 8404062d12..b568e83858 100644 --- a/msautotest/wxs/expected/wfsogr_200_multiplelayers.xml +++ b/msautotest/wxs/expected/wfsogr_200_multiplelayers.xml @@ -10,29 +10,29 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 timeStamp="" numberMatched="100" numberReturned="100"> - 2258982.00000 -70747.91406 - 2615354.50000 495480.93750 + 2258982.000000 -70747.914062 + 2615354.500000 495480.937500 - 2258982.00000 -70747.91406 - 2615354.50000 495480.93750 + 2258982.000000 -70747.914062 + 2615354.500000 495480.937500 - 2577257.00000 402717.03125 - 2580978.50000 430271.18750 + 2577257.000000 402717.031250 + 2580978.500000 430271.187500 - 2577257.00000 430271.18750 2577292.00000 420127.65625 2577297.50000 418604.78125 2577491.75000 417462.90625 2578069.00000 415941.46875 2578836.50000 414230.25000 2579413.25000 412899.18750 2580247.50000 412070.84375 2580693.50000 411149.46875 2580978.50000 408984.37500 2580750.50000 407559.96875 2580066.75000 405736.68750 2579326.00000 403970.43750 2578927.50000 402717.03125 + 2577257.000000 430271.187500 2577292.000000 420127.656250 2577297.500000 418604.781250 2577491.750000 417462.906250 2578069.000000 415941.468750 2578836.500000 414230.250000 2579413.250000 412899.187500 2580247.500000 412070.843750 2580693.500000 411149.468750 2580978.500000 408984.375000 2580750.500000 407559.968750 2580066.750000 405736.687500 2579326.000000 403970.437500 2578927.500000 402717.031250 @@ -41,13 +41,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2423954.25000 261480.26562 - 2445811.25000 287380.78125 + 2423954.250000 261480.265625 + 2445811.250000 287380.781250 - 2442339.75000 261851.75000 2443533.00000 261480.26562 2444388.75000 261737.06250 2445267.75000 262263.75000 2445811.25000 263084.12500 2445806.75000 264416.75000 2445611.75000 265558.56250 2445226.75000 266699.68750 2444460.50000 268030.18750 2443695.00000 268980.00000 2442888.75000 269780.40625 2439266.25000 273433.68750 2423954.25000 287380.78125 + 2442339.750000 261851.750000 2443533.000000 261480.265625 2444388.750000 261737.062500 2445267.750000 262263.750000 2445811.250000 263084.125000 2445806.750000 264416.750000 2445611.750000 265558.562500 2445226.750000 266699.687500 2444460.500000 268030.187500 2443695.000000 268980.000000 2442888.750000 269780.406250 2439266.250000 273433.687500 2423954.250000 287380.781250 @@ -56,13 +56,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2295131.50000 -70747.91406 - 2300237.25000 -55210.80859 + 2295131.500000 -70747.914062 + 2300237.250000 -55210.808594 - 2295131.50000 -70747.91406 2296898.25000 -69277.78906 2297741.25000 -67368.82812 2299021.00000 -64632.40234 2299660.50000 -63264.00000 2299686.25000 -61199.98828 2300237.25000 -59070.42578 2299573.50000 -55210.80859 + 2295131.500000 -70747.914062 2296898.250000 -69277.789062 2297741.250000 -67368.828125 2299021.000000 -64632.402344 2299660.500000 -63264.000000 2299686.250000 -61199.988281 2300237.250000 -59070.425781 2299573.500000 -55210.808594 @@ -71,13 +71,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2401333.25000 456760.09375 - 2418412.00000 495480.93750 + 2401333.250000 456760.093750 + 2418412.000000 495480.937500 - 2416521.25000 486527.18750 2416899.25000 487862.03125 2417658.50000 489388.71875 2418036.75000 490533.00000 2418034.00000 491866.81250 2418412.00000 493582.68750 2417646.75000 494913.84375 2416312.00000 495480.93750 2415168.75000 495477.21875 2413836.75000 494710.87500 2412505.25000 493753.93750 2411364.00000 492797.62500 2410415.25000 490889.50000 2409656.75000 489362.81250 2408896.75000 488217.31250 2407947.50000 486880.59375 2407569.25000 485355.12500 2407000.75000 484019.65625 2406812.75000 482875.81250 2406056.00000 480206.09375 2405677.50000 479061.84375 2405490.75000 477346.59375 2404731.50000 475819.90625 2404926.25000 473724.87500 2405500.50000 472583.50000 2406835.00000 472206.81250 2407979.50000 471638.90625 2408744.75000 469926.75000 2408557.75000 468211.50000 2408370.25000 466877.25000 2408182.50000 465543.00000 2406852.25000 464014.46875 2405520.25000 463248.12500 2403997.25000 462671.56250 2402282.50000 462475.59375 2401333.25000 461138.90625 2401907.75000 459616.53125 2401910.50000 458282.90625 2402294.50000 456760.09375 + 2416521.250000 486527.187500 2416899.250000 487862.031250 2417658.500000 489388.718750 2418036.750000 490533.000000 2418034.000000 491866.812500 2418412.000000 493582.687500 2417646.750000 494913.843750 2416312.000000 495480.937500 2415168.750000 495477.218750 2413836.750000 494710.875000 2412505.250000 493753.937500 2411364.000000 492797.625000 2410415.250000 490889.500000 2409656.750000 489362.812500 2408896.750000 488217.312500 2407947.500000 486880.593750 2407569.250000 485355.125000 2407000.750000 484019.656250 2406812.750000 482875.812500 2406056.000000 480206.093750 2405677.500000 479061.843750 2405490.750000 477346.593750 2404731.500000 475819.906250 2404926.250000 473724.875000 2405500.500000 472583.500000 2406835.000000 472206.812500 2407979.500000 471638.906250 2408744.750000 469926.750000 2408557.750000 468211.500000 2408370.250000 466877.250000 2408182.500000 465543.000000 2406852.250000 464014.468750 2405520.250000 463248.125000 2403997.250000 462671.562500 2402282.500000 462475.593750 2401333.250000 461138.906250 2401907.750000 459616.531250 2401910.500000 458282.906250 2402294.500000 456760.093750 @@ -86,13 +86,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2402294.50000 456524.71875 - 2404001.25000 456760.09375 + 2402294.500000 456524.718750 + 2404001.250000 456760.093750 - 2402294.50000 456760.09375 2404001.25000 456524.71875 + 2402294.500000 456760.093750 2404001.250000 456524.718750 @@ -101,13 +101,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2401926.50000 439809.34375 - 2415274.25000 456760.09375 + 2401926.500000 439809.343750 + 2415274.250000 456760.093750 - 2402294.50000 456760.09375 2402488.25000 455236.50000 2402302.50000 452949.62500 2402305.00000 451806.59375 2401926.50000 450662.15625 2401930.50000 448756.90625 2401933.25000 447423.28125 2401937.25000 445518.25000 2401941.25000 443613.00000 2402325.25000 442090.03125 2403090.75000 440568.43750 2404045.25000 439809.34375 2405377.75000 440385.25000 2406710.00000 440961.18750 2407851.00000 441726.90625 2409183.75000 442112.25000 2410899.00000 442117.81250 2412422.25000 442503.75000 2413564.50000 442888.46875 2414897.00000 443464.40625 2415274.25000 445180.28125 + 2402294.500000 456760.093750 2402488.250000 455236.500000 2402302.500000 452949.625000 2402305.000000 451806.593750 2401926.500000 450662.156250 2401930.500000 448756.906250 2401933.250000 447423.281250 2401937.250000 445518.250000 2401941.250000 443613.000000 2402325.250000 442090.031250 2403090.750000 440568.437500 2404045.250000 439809.343750 2405377.750000 440385.250000 2406710.000000 440961.187500 2407851.000000 441726.906250 2409183.750000 442112.250000 2410899.000000 442117.812500 2412422.250000 442503.750000 2413564.500000 442888.468750 2414897.000000 443464.406250 2415274.250000 445180.281250 @@ -116,13 +116,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2506675.50000 382184.31250 - 2552279.50000 459945.18750 + 2506675.500000 382184.312500 + 2552279.500000 459945.187500 - 2517327.25000 382184.31250 2516878.00000 383523.06250 2516875.75000 384666.09375 2516490.75000 386570.09375 2515149.25000 390376.06250 2514765.25000 391899.03125 2514380.50000 393422.03125 2513805.75000 395134.81250 2513421.25000 396848.21875 2513037.25000 397990.00000 2512080.75000 400082.75000 2510934.50000 401603.09375 2510170.00000 402553.21875 2509024.50000 403692.71875 2508066.75000 405975.87500 2507300.75000 408069.06250 2507486.75000 410165.34375 2508055.00000 411691.40625 2508432.00000 413788.28125 2508809.00000 415694.75000 2508806.50000 416837.78125 2508613.25000 418170.78125 2508036.25000 420645.78125 2508033.25000 421979.40625 2508031.00000 423122.43750 2508028.50000 424265.65625 2507834.50000 425979.65625 2507259.25000 427883.03125 2506682.50000 430167.43750 2506679.75000 431501.06250 2506675.50000 433596.71875 2507051.00000 436455.78125 2507809.75000 437791.87500 2509139.75000 439510.84375 2510280.25000 440848.15625 2511227.75000 443327.90625 2511225.00000 444661.71875 2511411.50000 446567.37500 2512744.25000 446952.71875 2513886.75000 447337.62500 2515217.50000 448675.56250 2516358.75000 449631.87500 2517308.00000 451349.62500 2518257.25000 452686.31250 2519017.50000 453641.40625 2520157.50000 455169.15625 2522057.50000 457461.56250 2522817.25000 458797.65625 2524148.50000 459945.18750 2525673.25000 459568.93750 2527007.25000 459382.84375 2529103.75000 458818.03125 2530819.25000 458633.18750 2533296.75000 458260.03125 2535964.50000 458078.25000 2537108.50000 457700.93750 2538253.00000 456752.03125 2539209.75000 454849.87500 2539787.00000 452375.09375 2539980.00000 451042.06250 2539985.00000 448755.81250 2539991.25000 445707.37500 2540185.00000 444183.96875 2540379.00000 442469.93750 2540954.50000 440375.96875 2541338.75000 439043.56250 2542865.00000 438095.90625 2544203.00000 436004.56250 2544779.75000 433339.18750 2545355.25000 431626.37500 2546125.00000 427818.40625 2546896.75000 423248.37500 2546713.25000 420009.09375 2546906.50000 418676.06250 2546911.25000 416389.84375 2547488.00000 413724.43750 2547683.25000 411438.81250 2548260.50000 408963.81250 2548646.50000 406488.40625 2548840.75000 404583.78125 2548845.50000 402297.53125 2548851.25000 399630.28125 2548855.50000 397534.65625 2548858.50000 396201.03125 2549624.00000 394679.28125 2550387.50000 393729.12500 2551024.00000 392901.12500 2552279.50000 391797.40625 + 2517327.250000 382184.312500 2516878.000000 383523.062500 2516875.750000 384666.093750 2516490.750000 386570.093750 2515149.250000 390376.062500 2514765.250000 391899.031250 2514380.500000 393422.031250 2513805.750000 395134.812500 2513421.250000 396848.218750 2513037.250000 397990.000000 2512080.750000 400082.750000 2510934.500000 401603.093750 2510170.000000 402553.218750 2509024.500000 403692.718750 2508066.750000 405975.875000 2507300.750000 408069.062500 2507486.750000 410165.343750 2508055.000000 411691.406250 2508432.000000 413788.281250 2508809.000000 415694.750000 2508806.500000 416837.781250 2508613.250000 418170.781250 2508036.250000 420645.781250 2508033.250000 421979.406250 2508031.000000 423122.437500 2508028.500000 424265.656250 2507834.500000 425979.656250 2507259.250000 427883.031250 2506682.500000 430167.437500 2506679.750000 431501.062500 2506675.500000 433596.718750 2507051.000000 436455.781250 2507809.750000 437791.875000 2509139.750000 439510.843750 2510280.250000 440848.156250 2511227.750000 443327.906250 2511225.000000 444661.718750 2511411.500000 446567.375000 2512744.250000 446952.718750 2513886.750000 447337.625000 2515217.500000 448675.562500 2516358.750000 449631.875000 2517308.000000 451349.625000 2518257.250000 452686.312500 2519017.500000 453641.406250 2520157.500000 455169.156250 2522057.500000 457461.562500 2522817.250000 458797.656250 2524148.500000 459945.187500 2525673.250000 459568.937500 2527007.250000 459382.843750 2529103.750000 458818.031250 2530819.250000 458633.187500 2533296.750000 458260.031250 2535964.500000 458078.250000 2537108.500000 457700.937500 2538253.000000 456752.031250 2539209.750000 454849.875000 2539787.000000 452375.093750 2539980.000000 451042.062500 2539985.000000 448755.812500 2539991.250000 445707.375000 2540185.000000 444183.968750 2540379.000000 442469.937500 2540954.500000 440375.968750 2541338.750000 439043.562500 2542865.000000 438095.906250 2544203.000000 436004.562500 2544779.750000 433339.187500 2545355.250000 431626.375000 2546125.000000 427818.406250 2546896.750000 423248.375000 2546713.250000 420009.093750 2546906.500000 418676.062500 2546911.250000 416389.843750 2547488.000000 413724.437500 2547683.250000 411438.812500 2548260.500000 408963.812500 2548646.500000 406488.406250 2548840.750000 404583.781250 2548845.500000 402297.531250 2548851.250000 399630.281250 2548855.500000 397534.656250 2548858.500000 396201.031250 2549624.000000 394679.281250 2550387.500000 393729.125000 2551024.000000 392901.125000 2552279.500000 391797.406250 @@ -131,13 +131,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2517327.25000 373668.78125 - 2544336.75000 386026.87500 + 2517327.250000 373668.781250 + 2544336.750000 386026.875000 - 2544336.75000 373668.78125 2542807.50000 374652.65625 2540709.00000 375788.90625 2538231.00000 376352.46875 2536136.50000 375964.65625 2534230.25000 376339.50000 2532511.00000 378620.18750 2532125.25000 380905.18750 2531359.00000 382807.78125 2530025.00000 382994.06250 2528501.25000 382798.53125 2526975.25000 383746.18750 2526400.25000 385268.56250 2525255.25000 386026.87500 2522399.75000 385065.00000 2521070.50000 382965.03125 2519167.75000 382006.25000 2517327.25000 382184.31250 + 2544336.750000 373668.781250 2542807.500000 374652.656250 2540709.000000 375788.906250 2538231.000000 376352.468750 2536136.500000 375964.656250 2534230.250000 376339.500000 2532511.000000 378620.187500 2532125.250000 380905.187500 2531359.000000 382807.781250 2530025.000000 382994.062500 2528501.250000 382798.531250 2526975.250000 383746.187500 2526400.250000 385268.562500 2525255.250000 386026.875000 2522399.750000 385065.000000 2521070.500000 382965.031250 2519167.750000 382006.250000 2517327.250000 382184.312500 @@ -146,13 +146,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2431184.75000 343694.18750 - 2437876.25000 344935.53125 + 2431184.750000 343694.187500 + 2437876.250000 344935.531250 - 2437876.25000 343694.18750 2436853.50000 344316.53125 2435151.25000 344742.09375 2433603.50000 344935.53125 2432210.75000 344858.15625 2431184.75000 344694.00000 + 2437876.250000 343694.187500 2436853.500000 344316.531250 2435151.250000 344742.093750 2433603.500000 344935.531250 2432210.750000 344858.156250 2431184.750000 344694.000000 @@ -161,13 +161,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2408896.25000 336154.03125 - 2438448.25000 355446.78125 + 2408896.250000 336154.031250 + 2438448.250000 355446.781250 - 2408896.25000 336154.03125 2409331.50000 337640.15625 2410470.00000 339930.12500 2412561.75000 341651.53125 2413894.50000 342036.87500 2415417.00000 342804.00000 2417130.00000 343762.00000 2418653.25000 344148.12500 2420745.75000 345488.56250 2422839.50000 346638.37500 2424171.75000 347214.31250 2425501.75000 348933.25000 2427023.50000 350081.21875 2428165.50000 350656.53125 2429115.50000 351993.25000 2431969.50000 353717.15625 2433492.75000 354103.28125 2435396.00000 354871.46875 2436538.00000 355446.78125 2438062.75000 355070.53125 2438448.25000 353166.71875 2438069.25000 352022.28125 2437882.00000 350497.62500 2436362.25000 348396.84375 2435411.50000 347441.15625 2434078.75000 347055.81250 2433128.25000 346290.71875 2432177.00000 345525.59375 2431184.75000 344694.00000 + 2408896.250000 336154.031250 2409331.500000 337640.156250 2410470.000000 339930.125000 2412561.750000 341651.531250 2413894.500000 342036.875000 2415417.000000 342804.000000 2417130.000000 343762.000000 2418653.250000 344148.125000 2420745.750000 345488.562500 2422839.500000 346638.375000 2424171.750000 347214.312500 2425501.750000 348933.250000 2427023.500000 350081.218750 2428165.500000 350656.531250 2429115.500000 351993.250000 2431969.500000 353717.156250 2433492.750000 354103.281250 2435396.000000 354871.468750 2436538.000000 355446.781250 2438062.750000 355070.531250 2438448.250000 353166.718750 2438069.250000 352022.281250 2437882.000000 350497.625000 2436362.250000 348396.843750 2435411.500000 347441.156250 2434078.750000 347055.812500 2433128.250000 346290.718750 2432177.000000 345525.593750 2431184.750000 344694.000000 @@ -176,13 +176,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2408896.25000 335937.25000 - 2431184.75000 344694.00000 + 2408896.250000 335937.250000 + 2431184.750000 344694.000000 - 2431184.75000 344694.00000 2429895.50000 343231.93750 2428945.75000 342085.65625 2428376.25000 340940.78125 2427617.50000 339604.65625 2426286.25000 338457.12500 2424572.50000 337689.56250 2423239.50000 337494.65625 2420763.00000 337296.18750 2418668.50000 336908.40625 2417145.00000 336712.87500 2415240.00000 336325.68750 2414097.25000 336131.37500 2412954.50000 335937.25000 2410096.50000 336118.40625 2408896.25000 336154.03125 + 2431184.750000 344694.000000 2429895.500000 343231.937500 2428945.750000 342085.656250 2428376.250000 340940.781250 2427617.500000 339604.656250 2426286.250000 338457.125000 2424572.500000 337689.562500 2423239.500000 337494.656250 2420763.000000 337296.187500 2418668.500000 336908.406250 2417145.000000 336712.875000 2415240.000000 336325.687500 2414097.250000 336131.375000 2412954.500000 335937.250000 2410096.500000 336118.406250 2408896.250000 336154.031250 @@ -191,13 +191,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2555956.25000 315523.56250 - 2586390.25000 399880.53125 + 2555956.250000 315523.562500 + 2586390.250000 399880.531250 - 2555956.25000 315523.56250 2557409.00000 316400.68750 2558548.50000 317738.00000 2559307.25000 319455.28125 2560447.75000 320792.62500 2561206.25000 322700.15625 2561963.75000 324607.84375 2563484.25000 326327.40625 2565386.50000 327857.81250 2567480.75000 328436.21875 2568768.25000 329139.84375 2569741.50000 329663.06250 2570767.00000 329725.84375 2572054.00000 329830.50000 2573519.00000 330207.18750 2574180.00000 330852.25000 2574523.00000 331888.31250 2574899.50000 333985.21875 2575086.00000 335891.03125 2575272.50000 337796.90625 2575078.75000 339320.34375 2575075.25000 341035.15625 2575071.50000 342749.78125 2575069.25000 343892.81250 2575251.25000 347894.31250 2575627.25000 350181.75000 2575815.50000 351516.03125 2576003.50000 352659.84375 2576571.00000 354566.96875 2577898.75000 357238.50000 2578466.50000 359336.03125 2579413.75000 361625.34375 2580170.00000 364485.46875 2581117.00000 367155.96875 2582252.25000 370779.40625 2582820.25000 372686.50000 2582999.00000 378212.18750 2582994.25000 380498.43750 2582990.25000 382403.62500 2583559.50000 383739.15625 2584317.50000 385456.25000 2585076.00000 387173.31250 2585644.25000 388699.43750 2585641.00000 390223.46875 2586018.00000 391939.31250 2586204.75000 394226.21875 2586390.25000 396513.09375 2586388.25000 397656.31250 2586194.75000 398989.28125 2585757.50000 399880.53125 + 2555956.250000 315523.562500 2557409.000000 316400.687500 2558548.500000 317738.000000 2559307.250000 319455.281250 2560447.750000 320792.625000 2561206.250000 322700.156250 2561963.750000 324607.843750 2563484.250000 326327.406250 2565386.500000 327857.812500 2567480.750000 328436.218750 2568768.250000 329139.843750 2569741.500000 329663.062500 2570767.000000 329725.843750 2572054.000000 329830.500000 2573519.000000 330207.187500 2574180.000000 330852.250000 2574523.000000 331888.312500 2574899.500000 333985.218750 2575086.000000 335891.031250 2575272.500000 337796.906250 2575078.750000 339320.343750 2575075.250000 341035.156250 2575071.500000 342749.781250 2575069.250000 343892.812500 2575251.250000 347894.312500 2575627.250000 350181.750000 2575815.500000 351516.031250 2576003.500000 352659.843750 2576571.000000 354566.968750 2577898.750000 357238.500000 2578466.500000 359336.031250 2579413.750000 361625.343750 2580170.000000 364485.468750 2581117.000000 367155.968750 2582252.250000 370779.406250 2582820.250000 372686.500000 2582999.000000 378212.187500 2582994.250000 380498.437500 2582990.250000 382403.625000 2583559.500000 383739.156250 2584317.500000 385456.250000 2585076.000000 387173.312500 2585644.250000 388699.437500 2585641.000000 390223.468750 2586018.000000 391939.312500 2586204.750000 394226.218750 2586390.250000 396513.093750 2586388.250000 397656.312500 2586194.750000 398989.281250 2585757.500000 399880.531250 @@ -206,13 +206,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2508781.25000 310448.28125 - 2532595.25000 382184.31250 + 2508781.250000 310448.281250 + 2532595.250000 382184.312500 - 2517327.25000 382184.31250 2515168.75000 381040.65625 2514026.75000 380465.34375 2513458.00000 379320.46875 2511174.25000 377979.43750 2510604.75000 376834.37500 2509472.75000 371496.15625 2509480.75000 367685.87500 2509678.25000 364638.25000 2510064.25000 362162.62500 2510259.75000 359686.59375 2510646.25000 357020.56250 2511031.75000 355116.59375 2511607.75000 352832.18750 2511992.75000 350928.18750 2512187.50000 349214.18750 2512000.25000 347308.31250 2511623.00000 345592.46875 2510674.50000 343493.71875 2510105.75000 342348.65625 2509347.00000 340631.56250 2508969.00000 339296.68750 2508781.25000 337962.43750 2508785.00000 336247.81250 2509171.00000 333772.21875 2511651.25000 332065.59375 2513751.75000 329976.75000 2514897.25000 328837.25000 2516044.25000 326745.28125 2517382.50000 324463.37500 2517958.25000 322750.59375 2519487.00000 320469.28125 2521587.75000 318189.84375 2522925.00000 316479.53125 2524260.50000 315531.21875 2525024.50000 314390.65625 2526551.75000 312871.37500 2527887.00000 312113.68750 2530175.75000 310977.87500 2532595.25000 310448.28125 + 2517327.250000 382184.312500 2515168.750000 381040.656250 2514026.750000 380465.343750 2513458.000000 379320.468750 2511174.250000 377979.437500 2510604.750000 376834.375000 2509472.750000 371496.156250 2509480.750000 367685.875000 2509678.250000 364638.250000 2510064.250000 362162.625000 2510259.750000 359686.593750 2510646.250000 357020.562500 2511031.750000 355116.593750 2511607.750000 352832.187500 2511992.750000 350928.187500 2512187.500000 349214.187500 2512000.250000 347308.312500 2511623.000000 345592.468750 2510674.500000 343493.718750 2510105.750000 342348.656250 2509347.000000 340631.562500 2508969.000000 339296.687500 2508781.250000 337962.437500 2508785.000000 336247.812500 2509171.000000 333772.218750 2511651.250000 332065.593750 2513751.750000 329976.750000 2514897.250000 328837.250000 2516044.250000 326745.281250 2517382.500000 324463.375000 2517958.250000 322750.593750 2519487.000000 320469.281250 2521587.750000 318189.843750 2522925.000000 316479.531250 2524260.500000 315531.218750 2525024.500000 314390.656250 2526551.750000 312871.375000 2527887.000000 312113.687500 2530175.750000 310977.875000 2532595.250000 310448.281250 @@ -221,13 +221,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2532595.25000 309490.28125 - 2555956.25000 315523.56250 + 2532595.250000 309490.281250 + 2555956.250000 315523.562500 - 2532595.25000 310448.28125 2533607.00000 310226.96875 2538370.25000 309861.40625 2539894.25000 309866.34375 2541420.00000 309490.28125 2542752.75000 309875.59375 2545418.25000 310646.25000 2546273.00000 310984.06250 2547009.25000 311585.68750 2547395.50000 311944.90625 2547880.50000 312268.15625 2548437.25000 312420.81250 2549011.75000 312681.25000 2549498.25000 312881.78125 2551697.75000 314095.90625 2553983.00000 314674.93750 2555505.75000 315251.46875 2555956.25000 315523.56250 + 2532595.250000 310448.281250 2533607.000000 310226.968750 2538370.250000 309861.406250 2539894.250000 309866.343750 2541420.000000 309490.281250 2542752.750000 309875.593750 2545418.250000 310646.250000 2546273.000000 310984.062500 2547009.250000 311585.687500 2547395.500000 311944.906250 2547880.500000 312268.156250 2548437.250000 312420.812500 2549011.750000 312681.250000 2549498.250000 312881.781250 2551697.750000 314095.906250 2553983.000000 314674.937500 2555505.750000 315251.468750 2555956.250000 315523.562500 @@ -236,13 +236,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2555956.25000 305943.78125 - 2568929.50000 315523.56250 + 2555956.250000 305943.781250 + 2568929.500000 315523.562500 - 2555956.25000 315523.56250 2558366.25000 313927.09375 2559130.50000 312976.96875 2560465.75000 312219.25000 2561799.75000 312032.96875 2562943.00000 312036.68750 2564087.25000 311468.78125 2565421.75000 311092.09375 2566239.50000 311290.40625 2566802.25000 311605.59375 2567556.25000 311515.53125 2568164.25000 311177.84375 2568772.00000 310547.50000 2568929.50000 309534.46875 2568817.00000 308622.71875 2568749.25000 307497.06250 2568738.25000 305943.78125 + 2555956.250000 315523.562500 2558366.250000 313927.093750 2559130.500000 312976.968750 2560465.750000 312219.250000 2561799.750000 312032.968750 2562943.000000 312036.687500 2564087.250000 311468.781250 2565421.750000 311092.093750 2566239.500000 311290.406250 2566802.250000 311605.593750 2567556.250000 311515.531250 2568164.250000 311177.843750 2568772.000000 310547.500000 2568929.500000 309534.468750 2568817.000000 308622.718750 2568749.250000 307497.062500 2568738.250000 305943.781250 @@ -251,13 +251,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2398316.25000 301857.34375 - 2423674.50000 313088.59375 + 2398316.250000 301857.343750 + 2423674.500000 313088.593750 - 2423674.50000 311966.37500 2423485.75000 310822.75000 2422344.50000 310247.43750 2420630.00000 309860.87500 2419294.00000 310999.56250 2418720.50000 312140.93750 2417194.50000 313088.59375 2415289.25000 312891.84375 2414338.00000 312126.71875 2412815.50000 311359.59375 2410913.25000 310210.37500 2409391.00000 309252.84375 2408060.00000 308105.46875 2406157.50000 306575.09375 2404445.50000 305426.50000 2403303.00000 305041.59375 2401591.00000 303893.00000 2400067.75000 303507.06250 2399401.50000 303113.96875 2398880.50000 302657.03125 2398316.25000 301857.34375 + 2423674.500000 311966.375000 2423485.750000 310822.750000 2422344.500000 310247.437500 2420630.000000 309860.875000 2419294.000000 310999.562500 2418720.500000 312140.937500 2417194.500000 313088.593750 2415289.250000 312891.843750 2414338.000000 312126.718750 2412815.500000 311359.593750 2410913.250000 310210.375000 2409391.000000 309252.843750 2408060.000000 308105.468750 2406157.500000 306575.093750 2404445.500000 305426.500000 2403303.000000 305041.593750 2401591.000000 303893.000000 2400067.750000 303507.062500 2399401.500000 303113.968750 2398880.500000 302657.031250 2398316.250000 301857.343750 @@ -266,13 +266,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2380836.00000 301084.96875 - 2408896.25000 336154.03125 + 2380836.000000 301084.968750 + 2408896.250000 336154.031250 - 2380836.00000 301084.96875 2381396.50000 303827.56250 2381774.50000 305162.43750 2382723.25000 307070.75000 2383482.50000 308216.25000 2384812.50000 309935.21875 2386906.00000 311085.21875 2388238.50000 311661.12500 2389760.25000 312809.09375 2390329.00000 313954.15625 2391089.25000 314909.06250 2391467.50000 316243.93750 2391845.50000 317578.78125 2392413.50000 319485.87500 2392980.75000 321392.96875 2393738.75000 323491.09375 2394687.00000 325590.00000 2396969.00000 327312.03125 2398492.75000 327888.59375 2400204.75000 329037.18750 2401918.25000 329423.75000 2403061.50000 329427.43750 2404204.25000 329621.75000 2405916.75000 330579.90625 2406867.25000 331726.03125 2408005.50000 334015.96875 2408764.50000 335352.06250 2408896.25000 336154.03125 + 2380836.000000 301084.968750 2381396.500000 303827.562500 2381774.500000 305162.437500 2382723.250000 307070.750000 2383482.500000 308216.250000 2384812.500000 309935.218750 2386906.000000 311085.218750 2388238.500000 311661.125000 2389760.250000 312809.093750 2390329.000000 313954.156250 2391089.250000 314909.062500 2391467.500000 316243.937500 2391845.500000 317578.781250 2392413.500000 319485.875000 2392980.750000 321392.968750 2393738.750000 323491.093750 2394687.000000 325590.000000 2396969.000000 327312.031250 2398492.750000 327888.593750 2400204.750000 329037.187500 2401918.250000 329423.750000 2403061.500000 329427.437500 2404204.250000 329621.750000 2405916.750000 330579.906250 2406867.250000 331726.031250 2408005.500000 334015.968750 2408764.500000 335352.062500 2408896.250000 336154.031250 @@ -281,13 +281,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2338814.75000 297360.06250 - 2375060.75000 300923.40625 + 2338814.750000 297360.062500 + 2375060.750000 300923.406250 - 2338814.75000 297360.06250 2340636.75000 298360.93750 2342160.00000 298746.90625 2343492.75000 299132.21875 2345778.50000 299520.65625 2347302.00000 299716.18750 2348826.00000 299721.12500 2351683.25000 299920.78125 2353207.50000 299925.71875 2354541.00000 299930.06250 2357017.50000 300128.68750 2358923.00000 300134.84375 2360827.75000 300141.03125 2362161.50000 300145.34375 2363685.00000 300340.87500 2365399.00000 300536.84375 2367113.50000 300923.40625 2368828.25000 300738.56250 2370162.00000 300742.87500 2371306.00000 300365.56250 2374167.25000 298660.03125 2375060.75000 298175.34375 + 2338814.750000 297360.062500 2340636.750000 298360.937500 2342160.000000 298746.906250 2343492.750000 299132.218750 2345778.500000 299520.656250 2347302.000000 299716.187500 2348826.000000 299721.125000 2351683.250000 299920.781250 2353207.500000 299925.718750 2354541.000000 299930.062500 2357017.500000 300128.687500 2358923.000000 300134.843750 2360827.750000 300141.031250 2362161.500000 300145.343750 2363685.000000 300340.875000 2365399.000000 300536.843750 2367113.500000 300923.406250 2368828.250000 300738.562500 2370162.000000 300742.875000 2371306.000000 300365.562500 2374167.250000 298660.031250 2375060.750000 298175.343750 @@ -296,13 +296,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2328808.00000 297360.06250 - 2376921.25000 310977.15625 + 2328808.000000 297360.062500 + 2376921.250000 310977.156250 - 2338814.75000 297360.06250 2337206.50000 298730.84375 2336062.50000 299108.15625 2334345.50000 300245.81250 2333200.75000 301004.12500 2331102.75000 302330.93750 2329958.25000 302898.84375 2328811.25000 304800.18750 2328808.00000 306324.40625 2329948.25000 307661.75000 2331091.25000 307856.06250 2332233.25000 308050.15625 2333376.50000 308053.87500 2334520.00000 307867.15625 2336046.75000 306538.46875 2337192.75000 305208.56250 2337957.25000 304258.40625 2339102.50000 303309.50000 2340245.75000 302932.18750 2342722.50000 302940.21875 2344055.00000 303515.96875 2345959.00000 304284.34375 2347290.50000 305241.28125 2350142.25000 308108.21875 2350900.50000 310015.90625 2351851.00000 310781.00000 2353565.75000 310977.15625 2355283.50000 309458.50000 2356047.50000 308317.93750 2357381.75000 307941.25000 2359477.75000 307948.03125 2361573.50000 308145.25000 2362716.00000 308148.93750 2364240.75000 308153.90625 2365382.75000 308348.18750 2367668.00000 308927.21875 2369189.50000 310075.18750 2370906.00000 309509.12500 2372240.25000 309132.43750 2373386.00000 307993.12500 2374150.75000 306471.37500 2374915.25000 305521.21875 2376255.25000 302477.28125 2376921.25000 301464.28125 + 2338814.750000 297360.062500 2337206.500000 298730.843750 2336062.500000 299108.156250 2334345.500000 300245.812500 2333200.750000 301004.125000 2331102.750000 302330.937500 2329958.250000 302898.843750 2328811.250000 304800.187500 2328808.000000 306324.406250 2329948.250000 307661.750000 2331091.250000 307856.062500 2332233.250000 308050.156250 2333376.500000 308053.875000 2334520.000000 307867.156250 2336046.750000 306538.468750 2337192.750000 305208.562500 2337957.250000 304258.406250 2339102.500000 303309.500000 2340245.750000 302932.187500 2342722.500000 302940.218750 2344055.000000 303515.968750 2345959.000000 304284.343750 2347290.500000 305241.281250 2350142.250000 308108.218750 2350900.500000 310015.906250 2351851.000000 310781.000000 2353565.750000 310977.156250 2355283.500000 309458.500000 2356047.500000 308317.937500 2357381.750000 307941.250000 2359477.750000 307948.031250 2361573.500000 308145.250000 2362716.000000 308148.937500 2364240.750000 308153.906250 2365382.750000 308348.187500 2367668.000000 308927.218750 2369189.500000 310075.187500 2370906.000000 309509.125000 2372240.250000 309132.437500 2373386.000000 307993.125000 2374150.750000 306471.375000 2374915.250000 305521.218750 2376255.250000 302477.281250 2376921.250000 301464.281250 @@ -311,13 +311,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2528707.75000 292187.53125 - 2552125.25000 302480.75000 + 2528707.750000 292187.531250 + 2552125.250000 302480.750000 - 2528707.75000 302480.75000 2529201.50000 302131.09375 2530768.75000 300691.71875 2532485.50000 299935.28125 2533628.50000 299938.96875 2534771.00000 299942.68750 2537059.50000 298997.46875 2538586.00000 297859.18750 2540302.25000 297293.34375 2541445.75000 297106.43750 2542779.50000 297110.75000 2544303.50000 297115.68750 2545827.50000 297120.62500 2547733.25000 296745.81250 2549448.75000 296560.78125 2550592.50000 295993.03125 2551166.75000 294851.68750 2552125.25000 292187.53125 + 2528707.750000 302480.750000 2529201.500000 302131.093750 2530768.750000 300691.718750 2532485.500000 299935.281250 2533628.500000 299938.968750 2534771.000000 299942.687500 2537059.500000 298997.468750 2538586.000000 297859.187500 2540302.250000 297293.343750 2541445.750000 297106.437500 2542779.500000 297110.750000 2544303.500000 297115.687500 2545827.500000 297120.625000 2547733.250000 296745.812500 2549448.750000 296560.781250 2550592.500000 295993.031250 2551166.750000 294851.687500 2552125.250000 292187.531250 @@ -326,13 +326,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2332620.50000 290752.21875 - 2338814.75000 297360.06250 + 2332620.500000 290752.218750 + 2338814.750000 297360.062500 - 2332620.50000 290752.21875 2334361.50000 292625.06250 2335544.75000 294394.87500 2337211.50000 296254.18750 2338814.75000 297360.06250 + 2332620.500000 290752.218750 2334361.500000 292625.062500 2335544.750000 294394.875000 2337211.500000 296254.187500 2338814.750000 297360.062500 @@ -341,13 +341,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2280156.00000 287223.68750 - 2332620.50000 339507.81250 + 2280156.000000 287223.687500 + 2332620.500000 339507.812500 - 2280156.00000 339507.81250 2281118.00000 335129.03125 2281694.00000 332844.62500 2282081.25000 330178.62500 2282465.25000 328655.62500 2282658.00000 327513.21875 2283042.00000 325990.21875 2283044.75000 324656.59375 2283049.25000 322560.93750 2282863.25000 320464.50000 2282866.50000 318940.46875 2282870.75000 316844.62500 2283449.50000 313607.81250 2283834.25000 311703.81250 2284218.75000 309990.40625 2284794.00000 308468.06250 2285368.25000 306945.68750 2286705.50000 305235.37500 2288231.25000 304478.28125 2289566.50000 303720.59375 2290900.50000 303534.31250 2293186.75000 303541.71875 2295091.75000 303547.87500 2296615.75000 303552.84375 2297950.00000 303557.15625 2299665.75000 302991.09375 2300809.75000 302613.81250 2302145.75000 301475.09375 2303671.25000 300717.81250 2304819.00000 298625.87500 2305202.50000 297293.50000 2305777.00000 295771.12500 2306351.75000 294439.34375 2307116.50000 292917.78125 2308837.00000 290446.50000 2309982.50000 289307.15625 2312272.25000 287409.34375 2313796.50000 287223.68750 2315129.50000 287609.18750 2316271.75000 287993.90625 2318367.00000 288381.71875 2319890.25000 288767.65625 2321032.50000 289152.37500 2324079.75000 289543.28125 2326175.75000 289550.06250 2328047.00000 290928.65625 2329952.75000 290934.56250 2331477.25000 290748.65625 2332620.50000 290752.21875 + 2280156.000000 339507.812500 2281118.000000 335129.031250 2281694.000000 332844.625000 2282081.250000 330178.625000 2282465.250000 328655.625000 2282658.000000 327513.218750 2283042.000000 325990.218750 2283044.750000 324656.593750 2283049.250000 322560.937500 2282863.250000 320464.500000 2282866.500000 318940.468750 2282870.750000 316844.625000 2283449.500000 313607.812500 2283834.250000 311703.812500 2284218.750000 309990.406250 2284794.000000 308468.062500 2285368.250000 306945.687500 2286705.500000 305235.375000 2288231.250000 304478.281250 2289566.500000 303720.593750 2290900.500000 303534.312500 2293186.750000 303541.718750 2295091.750000 303547.875000 2296615.750000 303552.843750 2297950.000000 303557.156250 2299665.750000 302991.093750 2300809.750000 302613.812500 2302145.750000 301475.093750 2303671.250000 300717.812500 2304819.000000 298625.875000 2305202.500000 297293.500000 2305777.000000 295771.125000 2306351.750000 294439.343750 2307116.500000 292917.781250 2308837.000000 290446.500000 2309982.500000 289307.156250 2312272.250000 287409.343750 2313796.500000 287223.687500 2315129.500000 287609.187500 2316271.750000 287993.906250 2318367.000000 288381.718750 2319890.250000 288767.656250 2321032.500000 289152.375000 2324079.750000 289543.281250 2326175.750000 289550.062500 2328047.000000 290928.656250 2329952.750000 290934.562500 2331477.250000 290748.656250 2332620.500000 290752.218750 @@ -356,13 +356,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2332620.50000 282176.75000 - 2347757.75000 290759.31250 + 2332620.500000 282176.750000 + 2347757.750000 290759.312500 - 2332620.50000 290752.21875 2333763.00000 290755.75000 2334906.25000 290759.31250 2336432.75000 289620.78125 2337578.00000 288671.50000 2338724.00000 287341.15625 2339867.75000 287154.06250 2341201.50000 287158.18750 2342534.75000 287352.96875 2344059.25000 287167.06250 2345394.50000 286409.03125 2347305.75000 283747.12500 2347757.75000 282176.75000 + 2332620.500000 290752.218750 2333763.000000 290755.750000 2334906.250000 290759.312500 2336432.750000 289620.781250 2337578.000000 288671.500000 2338724.000000 287341.156250 2339867.750000 287154.062500 2341201.500000 287158.187500 2342534.750000 287352.968750 2344059.250000 287167.062500 2345394.500000 286409.031250 2347305.750000 283747.125000 2347757.750000 282176.750000 @@ -371,13 +371,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2517059.75000 273309.50000 - 2580137.75000 291146.93750 + 2517059.750000 273309.500000 + 2580137.750000 291146.937500 - 2517059.75000 291146.93750 2518215.75000 290744.00000 2520694.00000 289990.00000 2522791.00000 289234.78125 2524125.75000 288667.50000 2525080.00000 287908.37500 2526987.75000 286962.12500 2528514.00000 285823.84375 2529850.50000 284494.53125 2531188.00000 282593.62500 2532335.75000 280501.68750 2534815.75000 278604.46875 2536725.25000 276705.43750 2539014.50000 275379.21875 2540921.00000 274623.34375 2543018.25000 274058.53125 2544352.25000 273872.43750 2547020.50000 273309.50000 2548544.75000 273314.43750 2551021.00000 273513.06250 2552163.50000 273897.75000 2553493.75000 275426.12500 2554252.75000 276762.21875 2556537.25000 277722.25000 2557679.50000 278107.15625 2559583.50000 278494.31250 2561488.25000 278881.50000 2562630.25000 279456.81250 2563580.00000 280602.93750 2564338.75000 282320.03125 2566241.25000 283469.43750 2567574.00000 283854.75000 2569097.75000 284050.12500 2570241.25000 283863.40625 2572145.75000 284441.18750 2574429.75000 285210.62500 2575572.25000 285595.31250 2576714.50000 285980.03125 2580137.75000 289230.03125 + 2517059.750000 291146.937500 2518215.750000 290744.000000 2520694.000000 289990.000000 2522791.000000 289234.781250 2524125.750000 288667.500000 2525080.000000 287908.375000 2526987.750000 286962.125000 2528514.000000 285823.843750 2529850.500000 284494.531250 2531188.000000 282593.625000 2532335.750000 280501.687500 2534815.750000 278604.468750 2536725.250000 276705.437500 2539014.500000 275379.218750 2540921.000000 274623.343750 2543018.250000 274058.531250 2544352.250000 273872.437500 2547020.500000 273309.500000 2548544.750000 273314.437500 2551021.000000 273513.062500 2552163.500000 273897.750000 2553493.750000 275426.125000 2554252.750000 276762.218750 2556537.250000 277722.250000 2557679.500000 278107.156250 2559583.500000 278494.312500 2561488.250000 278881.500000 2562630.250000 279456.812500 2563580.000000 280602.937500 2564338.750000 282320.031250 2566241.250000 283469.437500 2567574.000000 283854.750000 2569097.750000 284050.125000 2570241.250000 283863.406250 2572145.750000 284441.187500 2574429.750000 285210.625000 2575572.250000 285595.312500 2576714.500000 285980.031250 2580137.750000 289230.031250 @@ -386,13 +386,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2442115.25000 261851.75000 - 2442339.75000 262496.84375 + 2442115.250000 261851.750000 + 2442339.750000 262496.843750 - 2442115.25000 262496.84375 2442339.75000 261851.75000 + 2442115.250000 262496.843750 2442339.750000 261851.750000 @@ -401,13 +401,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2327897.50000 213607.48437 - 2442115.25000 262496.84375 + 2327897.500000 213607.484375 + 2442115.250000 262496.843750 - 2327897.50000 213607.48437 2329379.25000 215448.14062 2332040.50000 218314.60937 2333372.50000 219080.95312 2335275.25000 220420.75000 2336985.00000 222712.54687 2337361.75000 224619.01562 2337359.00000 225952.65625 2337355.75000 227476.87500 2338306.00000 228622.98437 2339637.75000 229579.92187 2341159.75000 230537.48437 2342302.25000 230922.18750 2343634.25000 231688.53125 2344777.50000 231692.23437 2346110.50000 231887.17187 2347634.25000 232082.51562 2348967.00000 232468.03125 2350680.25000 233045.00000 2351822.00000 233810.90625 2353725.75000 234579.09375 2354676.00000 235534.79687 2356200.00000 235539.75000 2357725.00000 235354.09375 2359058.75000 235358.40625 2360964.25000 234983.57812 2362679.25000 234798.71875 2364202.75000 234994.07812 2366488.75000 235192.07812 2367630.00000 236148.39062 2369724.75000 236726.60937 2371438.50000 237113.17187 2373915.00000 237311.81250 2375630.00000 236936.35937 2378297.75000 236754.39062 2381154.25000 237335.26562 2384010.25000 238106.54687 2387058.25000 238497.43750 2388391.75000 238501.75000 2390487.75000 238127.51562 2392775.50000 237563.51562 2394683.50000 236426.46875 2396209.00000 235669.40625 2397542.75000 235673.71875 2399827.25000 236252.71875 2401920.75000 237402.56250 2404199.25000 241220.43750 2404957.25000 242937.51562 2406668.75000 244657.73437 2408001.25000 245233.65625 2409904.50000 246001.84375 2411236.50000 246768.17187 2413899.25000 248872.65625 2415038.50000 250781.40625 2417318.50000 253837.28125 2418649.25000 255175.21875 2420171.50000 256132.59375 2420931.00000 257087.68750 2422262.75000 258044.62500 2423594.75000 258811.15625 2424927.50000 259196.48437 2426451.50000 259582.42187 2427593.50000 259776.54687 2429498.75000 259973.31250 2430041.50000 259975.06250 2432773.00000 259909.00000 2435971.00000 260275.43750 2438502.75000 261041.62500 2440601.50000 261841.12500 2442115.25000 262496.84375 + 2327897.500000 213607.484375 2329379.250000 215448.140625 2332040.500000 218314.609375 2333372.500000 219080.953125 2335275.250000 220420.750000 2336985.000000 222712.546875 2337361.750000 224619.015625 2337359.000000 225952.656250 2337355.750000 227476.875000 2338306.000000 228622.984375 2339637.750000 229579.921875 2341159.750000 230537.484375 2342302.250000 230922.187500 2343634.250000 231688.531250 2344777.500000 231692.234375 2346110.500000 231887.171875 2347634.250000 232082.515625 2348967.000000 232468.031250 2350680.250000 233045.000000 2351822.000000 233810.906250 2353725.750000 234579.093750 2354676.000000 235534.796875 2356200.000000 235539.750000 2357725.000000 235354.093750 2359058.750000 235358.406250 2360964.250000 234983.578125 2362679.250000 234798.718750 2364202.750000 234994.078125 2366488.750000 235192.078125 2367630.000000 236148.390625 2369724.750000 236726.609375 2371438.500000 237113.171875 2373915.000000 237311.812500 2375630.000000 236936.359375 2378297.750000 236754.390625 2381154.250000 237335.265625 2384010.250000 238106.546875 2387058.250000 238497.437500 2388391.750000 238501.750000 2390487.750000 238127.515625 2392775.500000 237563.515625 2394683.500000 236426.468750 2396209.000000 235669.406250 2397542.750000 235673.718750 2399827.250000 236252.718750 2401920.750000 237402.562500 2404199.250000 241220.437500 2404957.250000 242937.515625 2406668.750000 244657.734375 2408001.250000 245233.656250 2409904.500000 246001.843750 2411236.500000 246768.171875 2413899.250000 248872.656250 2415038.500000 250781.406250 2417318.500000 253837.281250 2418649.250000 255175.218750 2420171.500000 256132.593750 2420931.000000 257087.687500 2422262.750000 258044.625000 2423594.750000 258811.156250 2424927.500000 259196.484375 2426451.500000 259582.421875 2427593.500000 259776.546875 2429498.750000 259973.312500 2430041.500000 259975.062500 2432773.000000 259909.000000 2435971.000000 260275.437500 2438502.750000 261041.625000 2440601.500000 261841.125000 2442115.250000 262496.843750 @@ -416,13 +416,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2337062.75000 171673.95312 - 2399226.25000 211882.15625 + 2337062.750000 171673.953125 + 2399226.250000 211882.156250 - 2346585.25000 211882.15625 2346725.25000 211122.42187 2346919.75000 209217.79687 2347114.00000 207694.35937 2347498.00000 206171.37500 2348263.25000 204459.21875 2348838.00000 203127.46875 2349222.50000 201414.06250 2349227.75000 198937.23437 2349611.25000 197604.81250 2349045.25000 195126.31250 2347712.75000 194550.40625 2345808.50000 194353.60937 2344094.75000 193586.03125 2342001.50000 192626.60937 2341050.50000 191861.53125 2339909.50000 190714.60937 2339150.00000 189378.51562 2337820.75000 187278.56250 2337062.75000 185561.42187 2337066.00000 184037.21875 2337069.50000 182322.57812 2337264.75000 180036.96875 2337649.25000 178323.54687 2338034.25000 176610.15625 2338418.00000 175277.76562 2339181.50000 174327.62500 2339946.75000 172996.45312 2341663.50000 171858.79687 2343379.00000 171673.95312 2344521.50000 171677.64062 2345854.00000 172634.59375 2347564.75000 174354.79687 2348706.25000 175120.50000 2350417.50000 176650.29687 2352320.00000 177799.48437 2353842.75000 178757.04687 2355745.00000 180096.82812 2356887.00000 180672.15625 2358029.25000 181056.85937 2359361.75000 181632.81250 2361074.50000 182400.37500 2362598.25000 182595.89062 2364121.50000 182981.85937 2366217.50000 182988.62500 2368121.00000 183566.42187 2369454.25000 183761.15625 2372121.50000 183769.81250 2373645.50000 184155.75000 2374787.00000 184540.46875 2376119.50000 185116.39062 2377447.50000 187787.96875 2378396.25000 189696.29687 2379726.00000 191605.84375 2380866.25000 192943.17187 2383531.50000 193904.43750 2385626.00000 194673.25000 2387720.50000 195061.04687 2388863.75000 195064.75000 2390577.75000 195260.92187 2392863.25000 195649.34375 2394766.00000 196989.12500 2396287.75000 198137.09375 2398377.50000 200811.14062 2399226.25000 201743.82812 + 2346585.250000 211882.156250 2346725.250000 211122.421875 2346919.750000 209217.796875 2347114.000000 207694.359375 2347498.000000 206171.375000 2348263.250000 204459.218750 2348838.000000 203127.468750 2349222.500000 201414.062500 2349227.750000 198937.234375 2349611.250000 197604.812500 2349045.250000 195126.312500 2347712.750000 194550.406250 2345808.500000 194353.609375 2344094.750000 193586.031250 2342001.500000 192626.609375 2341050.500000 191861.531250 2339909.500000 190714.609375 2339150.000000 189378.515625 2337820.750000 187278.562500 2337062.750000 185561.421875 2337066.000000 184037.218750 2337069.500000 182322.578125 2337264.750000 180036.968750 2337649.250000 178323.546875 2338034.250000 176610.156250 2338418.000000 175277.765625 2339181.500000 174327.625000 2339946.750000 172996.453125 2341663.500000 171858.796875 2343379.000000 171673.953125 2344521.500000 171677.640625 2345854.000000 172634.593750 2347564.750000 174354.796875 2348706.250000 175120.500000 2350417.500000 176650.296875 2352320.000000 177799.484375 2353842.750000 178757.046875 2355745.000000 180096.828125 2356887.000000 180672.156250 2358029.250000 181056.859375 2359361.750000 181632.812500 2361074.500000 182400.375000 2362598.250000 182595.890625 2364121.500000 182981.859375 2366217.500000 182988.625000 2368121.000000 183566.421875 2369454.250000 183761.156250 2372121.500000 183769.812500 2373645.500000 184155.750000 2374787.000000 184540.468750 2376119.500000 185116.390625 2377447.500000 187787.968750 2378396.250000 189696.296875 2379726.000000 191605.843750 2380866.250000 192943.171875 2383531.500000 193904.437500 2385626.000000 194673.250000 2387720.500000 195061.046875 2388863.750000 195064.750000 2390577.750000 195260.921875 2392863.250000 195649.343750 2394766.000000 196989.125000 2396287.750000 198137.093750 2398377.500000 200811.140625 2399226.250000 201743.828125 @@ -431,13 +431,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2437545.00000 127024.38281 - 2524818.25000 276774.43750 + 2437545.000000 127024.382812 + 2524818.250000 276774.437500 - 2437545.00000 127024.38281 2437751.25000 127577.96093 2438700.50000 129295.90625 2439648.75000 131204.50000 2440598.25000 132732.00000 2441738.00000 134450.54687 2442686.50000 136549.59375 2443634.25000 138648.65625 2444773.00000 140748.45312 2447245.50000 142852.25000 2448959.25000 143238.67187 2450674.50000 143243.98437 2452007.00000 143819.85937 2453905.25000 147065.32812 2454473.25000 148591.45312 2454661.75000 149925.95312 2454467.00000 151640.54687 2455036.50000 152785.57812 2456748.00000 154315.45312 2458459.50000 155654.68750 2459982.50000 156612.23437 2462265.75000 157762.60937 2464171.00000 157959.15625 2466646.75000 158538.40625 2468360.50000 158924.79687 2469884.00000 159310.82812 2471788.25000 159888.28125 2473312.50000 159893.01562 2474262.25000 161039.42187 2475403.75000 161805.15625 2476542.25000 164095.45312 2477492.50000 165432.31250 2478631.25000 167531.93750 2480721.50000 170015.82812 2482625.25000 170974.54687 2483768.00000 171168.54687 2485101.00000 171553.78125 2486244.25000 171557.32812 2488527.50000 172707.87500 2489477.25000 174235.37500 2491185.25000 177289.60937 2492325.50000 178817.53125 2493276.25000 179773.31250 2494989.25000 180541.00000 2495557.50000 182257.76562 2495934.75000 183973.95312 2495931.25000 185688.93750 2495929.00000 186832.40625 2496686.50000 188740.21875 2497446.25000 190076.50000 2498967.25000 191605.78125 2500108.50000 192562.14062 2501250.50000 193137.40625 2502964.50000 193333.17187 2504486.75000 194290.75000 2505818.50000 195247.71875 2506577.75000 196774.62500 2507526.00000 198873.65625 2508285.50000 200019.31250 2509235.00000 201546.79687 2509803.25000 203073.14062 2510372.25000 204408.79687 2512082.00000 206700.67187 2513794.25000 207849.46875 2514937.00000 208043.64062 2515888.25000 208808.78125 2517028.50000 210336.70312 2517787.75000 211482.50000 2518356.50000 213008.62500 2519874.75000 215871.81250 2521209.00000 215494.87500 2522543.25000 215308.39062 2523874.00000 216646.42187 2523900.50000 217450.32812 2523922.50000 218405.50000 2524469.00000 219255.85937 2524818.25000 220841.75000 2524815.25000 222175.67187 2524621.00000 224080.70312 2524046.50000 225222.21875 2523473.00000 226363.87500 2522898.50000 227505.37500 2522514.25000 229219.18750 2521940.00000 230551.31250 2521746.25000 231884.81250 2521172.00000 233216.93750 2520597.25000 234930.15625 2519642.00000 236070.48437 2518306.75000 236828.53125 2517163.00000 237015.60937 2516018.75000 237583.79687 2514873.50000 238533.06250 2513537.00000 239862.82812 2512772.75000 241003.73437 2511818.00000 241953.59375 2510862.00000 243475.17187 2510098.00000 244616.07812 2509142.25000 245947.03125 2508187.00000 247087.53125 2507804.00000 248229.62500 2507228.75000 249752.39062 2506652.25000 252227.78125 2506458.25000 253942.20312 2506265.00000 255275.50000 2505880.75000 256608.23437 2505306.75000 257940.35937 2504350.75000 259461.95312 2502062.00000 260788.78125 2500344.75000 261736.23437 2499389.50000 263257.84375 2498812.00000 265923.87500 2498617.50000 267828.75000 2498424.25000 269162.06250 2498041.25000 270304.34375 2497847.25000 271637.65625 2497844.75000 272780.90625 2497841.50000 274305.46875 2497925.50000 276774.43750 + 2437545.000000 127024.382812 2437751.250000 127577.960938 2438700.500000 129295.906250 2439648.750000 131204.500000 2440598.250000 132732.000000 2441738.000000 134450.546875 2442686.500000 136549.593750 2443634.250000 138648.656250 2444773.000000 140748.453125 2447245.500000 142852.250000 2448959.250000 143238.671875 2450674.500000 143243.984375 2452007.000000 143819.859375 2453905.250000 147065.328125 2454473.250000 148591.453125 2454661.750000 149925.953125 2454467.000000 151640.546875 2455036.500000 152785.578125 2456748.000000 154315.453125 2458459.500000 155654.687500 2459982.500000 156612.234375 2462265.750000 157762.609375 2464171.000000 157959.156250 2466646.750000 158538.406250 2468360.500000 158924.796875 2469884.000000 159310.828125 2471788.250000 159888.281250 2473312.500000 159893.015625 2474262.250000 161039.421875 2475403.750000 161805.156250 2476542.250000 164095.453125 2477492.500000 165432.312500 2478631.250000 167531.937500 2480721.500000 170015.828125 2482625.250000 170974.546875 2483768.000000 171168.546875 2485101.000000 171553.781250 2486244.250000 171557.328125 2488527.500000 172707.875000 2489477.250000 174235.375000 2491185.250000 177289.609375 2492325.500000 178817.531250 2493276.250000 179773.312500 2494989.250000 180541.000000 2495557.500000 182257.765625 2495934.750000 183973.953125 2495931.250000 185688.937500 2495929.000000 186832.406250 2496686.500000 188740.218750 2497446.250000 190076.500000 2498967.250000 191605.781250 2500108.500000 192562.140625 2501250.500000 193137.406250 2502964.500000 193333.171875 2504486.750000 194290.750000 2505818.500000 195247.718750 2506577.750000 196774.625000 2507526.000000 198873.656250 2508285.500000 200019.312500 2509235.000000 201546.796875 2509803.250000 203073.140625 2510372.250000 204408.796875 2512082.000000 206700.671875 2513794.250000 207849.468750 2514937.000000 208043.640625 2515888.250000 208808.781250 2517028.500000 210336.703125 2517787.750000 211482.500000 2518356.500000 213008.625000 2519874.750000 215871.812500 2521209.000000 215494.875000 2522543.250000 215308.390625 2523874.000000 216646.421875 2523900.500000 217450.328125 2523922.500000 218405.500000 2524469.000000 219255.859375 2524818.250000 220841.750000 2524815.250000 222175.671875 2524621.000000 224080.703125 2524046.500000 225222.218750 2523473.000000 226363.875000 2522898.500000 227505.375000 2522514.250000 229219.187500 2521940.000000 230551.312500 2521746.250000 231884.812500 2521172.000000 233216.937500 2520597.250000 234930.156250 2519642.000000 236070.484375 2518306.750000 236828.531250 2517163.000000 237015.609375 2516018.750000 237583.796875 2514873.500000 238533.062500 2513537.000000 239862.828125 2512772.750000 241003.734375 2511818.000000 241953.593750 2510862.000000 243475.171875 2510098.000000 244616.078125 2509142.250000 245947.031250 2508187.000000 247087.531250 2507804.000000 248229.625000 2507228.750000 249752.390625 2506652.250000 252227.781250 2506458.250000 253942.203125 2506265.000000 255275.500000 2505880.750000 256608.234375 2505306.750000 257940.359375 2504350.750000 259461.953125 2502062.000000 260788.781250 2500344.750000 261736.234375 2499389.500000 263257.843750 2498812.000000 265923.875000 2498617.500000 267828.750000 2498424.250000 269162.062500 2498041.250000 270304.343750 2497847.250000 271637.656250 2497844.750000 272780.906250 2497841.500000 274305.468750 2497925.500000 276774.437500 @@ -446,13 +446,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2426724.50000 126601.03125 - 2427983.00000 136722.43750 + 2426724.500000 126601.031250 + 2427983.000000 136722.437500 - 2427983.00000 136722.43750 2427856.00000 135556.64062 2427667.75000 134413.15625 2427289.00000 133268.90625 2427293.25000 131173.50000 2426724.50000 129457.31250 2426918.25000 127743.47656 2427111.00000 126601.03125 + 2427983.000000 136722.437500 2427856.000000 135556.640625 2427667.750000 134413.156250 2427289.000000 133268.906250 2427293.250000 131173.500000 2426724.500000 129457.312500 2426918.250000 127743.476562 2427111.000000 126601.031250 @@ -461,13 +461,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2346510.25000 87612.88281 - 2386412.75000 128063.53125 + 2346510.250000 87612.882812 + 2386412.750000 128063.531250 - 2346510.25000 128063.53125 2347096.25000 125008.59375 2347099.00000 123674.96875 2347103.00000 121769.71093 2348444.25000 118154.17187 2349976.50000 114539.24218 2351697.00000 111686.95312 2353796.50000 109598.10937 2355708.25000 106746.43750 2356854.50000 105226.09375 2358001.00000 103705.56250 2360291.75000 101236.32812 2361437.00000 100287.42187 2363915.75000 99342.82812 2366012.50000 98968.61718 2368490.00000 98405.03125 2370395.75000 98220.78906 2372301.50000 97845.75781 2374208.25000 97280.51562 2375923.50000 96904.87500 2377448.25000 96528.80468 2379546.00000 95773.59375 2380500.25000 95014.65625 2381265.25000 93492.89062 2381649.50000 91779.49218 2382414.25000 90638.74218 2386412.75000 87612.88281 + 2346510.250000 128063.531250 2347096.250000 125008.593750 2347099.000000 123674.968750 2347103.000000 121769.710938 2348444.250000 118154.171875 2349976.500000 114539.242188 2351697.000000 111686.953125 2353796.500000 109598.109375 2355708.250000 106746.437500 2356854.500000 105226.093750 2358001.000000 103705.562500 2360291.750000 101236.328125 2361437.000000 100287.421875 2363915.750000 99342.828125 2366012.500000 98968.617188 2368490.000000 98405.031250 2370395.750000 98220.789062 2372301.500000 97845.757812 2374208.250000 97280.515625 2375923.500000 96904.875000 2377448.250000 96528.804688 2379546.000000 95773.593750 2380500.250000 95014.656250 2381265.250000 93492.890625 2381649.500000 91779.492188 2382414.250000 90638.742188 2386412.750000 87612.882812 @@ -476,13 +476,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2312654.00000 64738.70312 - 2381693.75000 98427.06250 + 2312654.000000 64738.703125 + 2381693.750000 98427.062500 - 2312654.00000 97478.49218 2316478.50000 98427.06250 2317813.50000 97859.78125 2319529.00000 97293.73437 2320673.75000 96535.42187 2321443.00000 93299.04687 2321829.00000 90823.60937 2322408.25000 87396.00781 2323365.75000 84731.84375 2323940.50000 83400.07812 2325468.25000 81690.38281 2327185.75000 80171.71875 2329475.75000 78464.49218 2331763.75000 77709.88281 2334813.75000 76767.13281 2336529.50000 76201.07031 2337673.50000 75823.77343 2339961.50000 75069.17187 2341676.25000 74884.13281 2343011.25000 74317.02343 2344919.00000 73179.99218 2346445.25000 72232.30468 2348351.50000 71476.45312 2350067.50000 71101.03125 2352926.00000 70729.24218 2355594.00000 70356.72656 2357118.50000 70171.23437 2359214.50000 69797.01562 2360548.00000 69801.32031 2361881.75000 69805.67968 2363596.50000 70001.63281 2365691.75000 70008.41406 2367025.25000 70012.75000 2368549.75000 69827.28906 2369693.75000 69449.98437 2371791.75000 68504.14062 2372556.25000 67554.00781 2374653.00000 66798.57812 2376560.50000 65852.31250 2378657.00000 65287.51953 2381693.75000 64738.70312 + 2312654.000000 97478.492188 2316478.500000 98427.062500 2317813.500000 97859.781250 2319529.000000 97293.734375 2320673.750000 96535.421875 2321443.000000 93299.046875 2321829.000000 90823.609375 2322408.250000 87396.007812 2323365.750000 84731.843750 2323940.500000 83400.078125 2325468.250000 81690.382812 2327185.750000 80171.718750 2329475.750000 78464.492188 2331763.750000 77709.882812 2334813.750000 76767.132812 2336529.500000 76201.070312 2337673.500000 75823.773438 2339961.500000 75069.171875 2341676.250000 74884.132812 2343011.250000 74317.023438 2344919.000000 73179.992188 2346445.250000 72232.304688 2348351.500000 71476.453125 2350067.500000 71101.031250 2352926.000000 70729.242188 2355594.000000 70356.726562 2357118.500000 70171.234375 2359214.500000 69797.015625 2360548.000000 69801.320312 2361881.750000 69805.679688 2363596.500000 70001.632812 2365691.750000 70008.414062 2367025.250000 70012.750000 2368549.750000 69827.289062 2369693.750000 69449.984375 2371791.750000 68504.140625 2372556.250000 67554.007812 2374653.000000 66798.578125 2376560.500000 65852.312500 2378657.000000 65287.519531 2381693.750000 64738.703125 @@ -491,13 +491,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2280279.75000 34889.78515 - 2281886.75000 40764.59375 + 2280279.750000 34889.785156 + 2281886.750000 40764.593750 - 2280710.50000 34889.78515 2280279.75000 36437.48046 2280385.50000 37863.45312 2280649.50000 39078.17968 2281886.75000 40764.59375 + 2280710.500000 34889.785156 2280279.750000 36437.480469 2280385.500000 37863.453125 2280649.500000 39078.179688 2281886.750000 40764.593750 @@ -506,13 +506,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2280710.50000 33374.88281 - 2281531.25000 34889.78515 + 2280710.500000 33374.882812 + 2281531.250000 34889.785156 - 2281531.25000 33374.88281 2281204.00000 34140.06640 2280710.50000 34889.78515 + 2281531.250000 33374.882812 2281204.000000 34140.066406 2280710.500000 34889.785156 @@ -521,13 +521,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2297238.50000 16173.98535 - 2385409.75000 57395.59765 + 2297238.500000 16173.985352 + 2385409.750000 57395.597656 - 2297238.50000 57395.59765 2300567.50000 54365.34765 2302093.75000 53227.11328 2304002.25000 51899.64843 2306291.50000 50192.41796 2308009.50000 48864.35156 2309917.00000 47536.90625 2311252.25000 46779.17187 2312588.75000 45449.88281 2313924.25000 44501.58984 2316213.25000 43365.79687 2318308.75000 43182.17968 2319642.75000 42995.91406 2320976.50000 43000.22656 2323072.00000 43197.62109 2324977.50000 43203.79296 2326692.00000 43209.32031 2328979.25000 42835.56640 2330314.50000 42077.85156 2331841.75000 40558.73828 2333366.75000 39992.10546 2334891.00000 39997.03515 2337178.00000 39623.42578 2339465.00000 39059.22265 2340800.25000 38301.54296 2342134.50000 37924.65234 2343659.00000 38120.19140 2345182.50000 38315.71875 2346513.75000 39463.07031 2348607.00000 40422.48437 2350131.50000 40618.02343 2351465.00000 40622.35546 2353179.75000 40437.30078 2354706.75000 39108.61718 2355092.00000 37014.21093 2355285.00000 35681.18750 2356621.00000 34542.31250 2357955.50000 34165.64062 2359480.25000 34170.56640 2361767.50000 33415.96093 2362727.00000 30180.16015 2364064.75000 28279.26757 2365781.25000 27332.19140 2367305.50000 27146.71093 2368639.50000 26960.46093 2370547.50000 25823.59960 2373220.00000 23355.38476 2374746.50000 22217.31640 2376273.50000 20698.02539 2378374.50000 18418.58398 2379138.00000 17468.43945 2380664.00000 16901.94726 2382379.25000 16526.32421 2385409.75000 16173.98535 + 2297238.500000 57395.597656 2300567.500000 54365.347656 2302093.750000 53227.113281 2304002.250000 51899.648438 2306291.500000 50192.417969 2308009.500000 48864.351562 2309917.000000 47536.906250 2311252.250000 46779.171875 2312588.750000 45449.882812 2313924.250000 44501.589844 2316213.250000 43365.796875 2318308.750000 43182.179688 2319642.750000 42995.914062 2320976.500000 43000.226562 2323072.000000 43197.621094 2324977.500000 43203.792969 2326692.000000 43209.320312 2328979.250000 42835.566406 2330314.500000 42077.851562 2331841.750000 40558.738281 2333366.750000 39992.105469 2334891.000000 39997.035156 2337178.000000 39623.425781 2339465.000000 39059.222656 2340800.250000 38301.542969 2342134.500000 37924.652344 2343659.000000 38120.191406 2345182.500000 38315.718750 2346513.750000 39463.070312 2348607.000000 40422.484375 2350131.500000 40618.023438 2351465.000000 40622.355469 2353179.750000 40437.300781 2354706.750000 39108.617188 2355092.000000 37014.210938 2355285.000000 35681.187500 2356621.000000 34542.312500 2357955.500000 34165.640625 2359480.250000 34170.566406 2361767.500000 33415.960938 2362727.000000 30180.160156 2364064.750000 28279.267578 2365781.250000 27332.191406 2367305.500000 27146.710938 2368639.500000 26960.460938 2370547.500000 25823.599609 2373220.000000 23355.384766 2374746.500000 22217.316406 2376273.500000 20698.025391 2378374.500000 18418.583984 2379138.000000 17468.439453 2380664.000000 16901.947266 2382379.250000 16526.324219 2385409.750000 16173.985352 @@ -536,13 +536,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2261430.50000 1845.39770 - 2280710.50000 34889.78515 + 2261430.500000 1845.397705 + 2280710.500000 34889.785156 - 2280710.50000 34889.78515 2278700.25000 34289.77734 2277367.00000 34095.06640 2275273.50000 32945.04296 2273560.25000 32367.90429 2271657.50000 31028.10156 2270706.25000 30262.99414 2269185.00000 28924.43164 2267664.25000 27395.26757 2266717.00000 24724.93359 2266150.50000 22436.80664 2265203.00000 19957.07031 2264825.25000 18431.61132 2264069.50000 15380.88964 2263694.25000 12712.42578 2263316.00000 11377.55468 2262749.25000 8899.05175 2262562.00000 7374.19482 2262183.75000 6229.76904 2261995.75000 5086.12451 2261430.50000 1845.39770 + 2280710.500000 34889.785156 2278700.250000 34289.777344 2277367.000000 34095.066406 2275273.500000 32945.042969 2273560.250000 32367.904297 2271657.500000 31028.101562 2270706.250000 30262.994141 2269185.000000 28924.431641 2267664.250000 27395.267578 2266717.000000 24724.933594 2266150.500000 22436.806641 2265203.000000 19957.070312 2264825.250000 18431.611328 2264069.500000 15380.889648 2263694.250000 12712.425781 2263316.000000 11377.554688 2262749.250000 8899.051758 2262562.000000 7374.194824 2262183.750000 6229.769043 2261995.750000 5086.124512 2261430.500000 1845.397705 @@ -551,13 +551,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2258982.00000 -14356.11718 - 2259545.50000 -2543.89502 + 2258982.000000 -14356.117188 + 2259545.500000 -2543.895020 - 2259154.00000 -2543.89502 2259346.75000 -3686.32788 2259540.50000 -5209.93164 2259545.50000 -7686.76123 2259169.25000 -9783.65234 2258982.00000 -11308.47558 2259178.75000 -14356.11718 + 2259154.000000 -2543.895020 2259346.750000 -3686.327881 2259540.500000 -5209.931641 2259545.500000 -7686.761230 2259169.250000 -9783.652344 2258982.000000 -11308.475586 2259178.750000 -14356.117188 @@ -566,13 +566,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2589745.50000 402556.25000 - 2602011.00000 419927.96875 + 2589745.500000 402556.250000 + 2602011.000000 419927.968750 - 2602011.00000 419927.96875 2600927.75000 415340.90625 2599981.50000 414005.78125 2598846.50000 412099.00000 2597898.00000 411144.59375 2596571.25000 409618.21875 2595434.25000 408282.59375 2594485.00000 407518.46875 2593157.25000 406182.31250 2591640.50000 404655.46875 2589745.50000 402556.25000 + 2602011.000000 419927.968750 2600927.750000 415340.906250 2599981.500000 414005.781250 2598846.500000 412099.000000 2597898.000000 411144.593750 2596571.250000 409618.218750 2595434.250000 408282.593750 2594485.000000 407518.468750 2593157.250000 406182.312500 2591640.500000 404655.468750 2589745.500000 402556.250000 @@ -581,13 +581,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2441167.25000 262496.84375 - 2442115.25000 265226.75000 + 2441167.250000 262496.843750 + 2442115.250000 265226.750000 - 2441167.25000 265226.75000 2442115.25000 262496.84375 + 2441167.250000 265226.750000 2442115.250000 262496.843750 @@ -596,13 +596,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2346510.25000 126601.03125 - 2427111.00000 138697.98437 + 2346510.250000 126601.031250 + 2427111.000000 138697.984375 - 2346510.25000 128063.53125 2347651.75000 128638.64062 2349365.25000 129596.50000 2351078.50000 130363.75781 2352602.00000 130749.49218 2353744.00000 131324.59375 2354695.25000 132280.04687 2356027.50000 133046.15625 2357548.50000 134574.93750 2358881.25000 135150.65625 2360404.00000 135917.34375 2361545.75000 136682.82812 2363258.50000 137640.67187 2364782.00000 138026.40625 2366115.75000 138030.57812 2368022.75000 137465.18750 2369168.75000 136135.29687 2370695.75000 134616.03125 2373365.00000 133862.45312 2374509.00000 133484.89062 2376034.00000 133108.68750 2377749.00000 132923.65625 2380034.75000 133311.78125 2381367.50000 133887.46875 2382891.00000 134273.18750 2384223.50000 134848.89062 2385366.25000 135233.42187 2387078.50000 136381.67187 2389173.25000 137150.14062 2390696.75000 137536.04687 2392220.25000 137921.76562 2394124.75000 138499.09375 2395267.50000 138502.67187 2396792.00000 138697.98437 2399079.00000 138133.59375 2400794.00000 138329.53125 2401937.00000 138142.53125 2403463.50000 137385.37500 2404798.25000 136818.03125 2406705.25000 135871.46875 2408422.25000 134733.95312 2409948.25000 133786.21875 2411092.00000 133599.21875 2412426.00000 133413.00000 2413569.75000 133226.01562 2415095.25000 132659.42187 2417383.00000 132095.03125 2418717.00000 131908.64062 2420244.25000 130389.53906 2421771.75000 128679.90625 2423489.00000 127732.77343 2425968.00000 126788.03125 2427111.00000 126601.03125 + 2346510.250000 128063.531250 2347651.750000 128638.640625 2349365.250000 129596.500000 2351078.500000 130363.757812 2352602.000000 130749.492188 2353744.000000 131324.593750 2354695.250000 132280.046875 2356027.500000 133046.156250 2357548.500000 134574.937500 2358881.250000 135150.656250 2360404.000000 135917.343750 2361545.750000 136682.828125 2363258.500000 137640.671875 2364782.000000 138026.406250 2366115.750000 138030.578125 2368022.750000 137465.187500 2369168.750000 136135.296875 2370695.750000 134616.031250 2373365.000000 133862.453125 2374509.000000 133484.890625 2376034.000000 133108.687500 2377749.000000 132923.656250 2380034.750000 133311.781250 2381367.500000 133887.468750 2382891.000000 134273.187500 2384223.500000 134848.890625 2385366.250000 135233.421875 2387078.500000 136381.671875 2389173.250000 137150.140625 2390696.750000 137536.046875 2392220.250000 137921.765625 2394124.750000 138499.093750 2395267.500000 138502.671875 2396792.000000 138697.984375 2399079.000000 138133.593750 2400794.000000 138329.531250 2401937.000000 138142.531250 2403463.500000 137385.375000 2404798.250000 136818.031250 2406705.250000 135871.468750 2408422.250000 134733.953125 2409948.250000 133786.218750 2411092.000000 133599.218750 2412426.000000 133413.000000 2413569.750000 133226.015625 2415095.250000 132659.421875 2417383.000000 132095.031250 2418717.000000 131908.640625 2420244.250000 130389.539062 2421771.750000 128679.906250 2423489.000000 127732.773438 2425968.000000 126788.031250 2427111.000000 126601.031250 @@ -611,13 +611,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2427111.00000 120844.14843 - 2429025.75000 126601.03125 + 2427111.000000 120844.148438 + 2429025.750000 126601.031250 - 2427111.00000 126601.03125 2427686.00000 125078.96093 2428642.00000 123557.92187 2429025.75000 122035.10156 2428879.25000 120844.14843 + 2427111.000000 126601.031250 2427686.000000 125078.960938 2428642.000000 123557.921875 2429025.750000 122035.101562 2428879.250000 120844.148438 @@ -626,13 +626,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2312654.00000 97478.49218 - 2346510.25000 128063.53125 + 2312654.000000 97478.492188 + 2346510.250000 128063.531250 - 2312654.00000 97478.49218 2314362.25000 100722.28125 2315882.00000 103012.99218 2317021.25000 105111.95312 2318161.25000 106829.93750 2318729.50000 108355.74218 2319871.00000 109311.79687 2320820.50000 111029.20312 2321580.00000 112555.59375 2322911.75000 113512.27343 2324243.50000 114659.32031 2325384.75000 115615.39062 2326144.25000 116760.64843 2326713.50000 118286.46093 2327282.50000 119431.10937 2328042.75000 120576.56250 2328992.50000 121722.43750 2330133.75000 122869.07031 2332038.25000 123446.54687 2333942.25000 124023.86718 2336227.50000 124793.09375 2337940.25000 125750.77343 2339273.25000 126136.10156 2341177.25000 126713.38281 2343463.00000 127101.50781 2344796.00000 127486.81250 2346510.25000 128063.53125 + 2312654.000000 97478.492188 2314362.250000 100722.281250 2315882.000000 103012.992188 2317021.250000 105111.953125 2318161.250000 106829.937500 2318729.500000 108355.742188 2319871.000000 109311.796875 2320820.500000 111029.203125 2321580.000000 112555.593750 2322911.750000 113512.273438 2324243.500000 114659.320312 2325384.750000 115615.390625 2326144.250000 116760.648438 2326713.500000 118286.460938 2327282.500000 119431.109375 2328042.750000 120576.562500 2328992.500000 121722.437500 2330133.750000 122869.070312 2332038.250000 123446.546875 2333942.250000 124023.867188 2336227.500000 124793.093750 2337940.250000 125750.773438 2339273.250000 126136.101562 2341177.250000 126713.382812 2343463.000000 127101.507812 2344796.000000 127486.812500 2346510.250000 128063.531250 @@ -641,13 +641,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2386412.75000 87612.88281 - 2428879.25000 120844.14843 + 2386412.750000 87612.882812 + 2428879.250000 120844.148438 - 2428879.25000 120844.14843 2428079.00000 118984.25000 2426936.75000 118409.14062 2425794.50000 117834.21093 2424461.00000 117639.47656 2422364.50000 118204.45312 2421030.25000 118390.67187 2419315.25000 118575.89843 2418172.00000 118572.29687 2416267.25000 117994.84375 2414934.00000 117800.25781 2413791.75000 117225.17968 2411888.25000 116457.28125 2409795.25000 114736.14062 2408462.50000 114160.61718 2406942.25000 112250.86718 2405801.00000 111104.40625 2404850.50000 110339.32812 2403327.25000 109382.09375 2401996.50000 107854.06250 2400665.50000 106516.46093 2399715.50000 105370.40625 2399336.25000 104226.34375 2398388.00000 102127.78906 2397438.50000 100410.40625 2395917.75000 98691.21875 2394397.00000 96972.03906 2393447.00000 95445.04687 2391355.25000 93152.53125 2389263.50000 91241.19531 2388122.50000 90094.55468 2387171.75000 88948.69531 2386412.75000 87612.88281 + 2428879.250000 120844.148438 2428079.000000 118984.250000 2426936.750000 118409.140625 2425794.500000 117834.210938 2424461.000000 117639.476562 2422364.500000 118204.453125 2421030.250000 118390.671875 2419315.250000 118575.898438 2418172.000000 118572.296875 2416267.250000 117994.843750 2414934.000000 117800.257812 2413791.750000 117225.179688 2411888.250000 116457.281250 2409795.250000 114736.140625 2408462.500000 114160.617188 2406942.250000 112250.867188 2405801.000000 111104.406250 2404850.500000 110339.328125 2403327.250000 109382.093750 2401996.500000 107854.062500 2400665.500000 106516.460938 2399715.500000 105370.406250 2399336.250000 104226.343750 2398388.000000 102127.789062 2397438.500000 100410.406250 2395917.750000 98691.218750 2394397.000000 96972.039062 2393447.000000 95445.046875 2391355.250000 93152.531250 2389263.500000 91241.195312 2388122.500000 90094.554688 2387171.750000 88948.695312 2386412.750000 87612.882812 @@ -656,13 +656,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2381693.75000 64738.70312 - 2386412.75000 87612.88281 + 2381693.750000 64738.703125 + 2386412.750000 87612.882812 - 2386412.75000 87612.88281 2385272.25000 86085.25781 2385084.50000 84751.21093 2385088.25000 82846.23437 2384902.00000 80369.30468 2385095.75000 79036.46093 2385288.75000 77703.57812 2385673.00000 75990.35156 2385294.75000 74655.71093 2384344.50000 73319.07812 2383585.50000 71602.31250 2383017.00000 70076.68750 2382449.25000 68360.48437 2382071.75000 66263.73437 2381693.75000 64738.70312 + 2386412.750000 87612.882812 2385272.250000 86085.257812 2385084.500000 84751.210938 2385088.250000 82846.234375 2384902.000000 80369.304688 2385095.750000 79036.460938 2385288.750000 77703.578125 2385673.000000 75990.351562 2385294.750000 74655.710938 2384344.500000 73319.078125 2383585.500000 71602.312500 2383017.000000 70076.687500 2382449.250000 68360.484375 2382071.750000 66263.734375 2381693.750000 64738.703125 @@ -671,13 +671,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2297106.75000 57395.59765 - 2312654.00000 97478.49218 + 2297106.750000 57395.597656 + 2312654.000000 97478.492188 - 2297238.50000 57395.59765 2297106.75000 58187.96484 2297485.00000 59522.62109 2297863.75000 61047.64843 2299194.75000 62385.29296 2300140.75000 65626.69531 2300518.25000 67723.25781 2301084.50000 70201.57031 2301842.50000 72489.88281 2302601.00000 74206.68750 2303169.50000 75922.88281 2303737.00000 77829.64843 2305255.00000 81072.86718 2306393.50000 83552.75781 2307531.50000 86223.25000 2308291.00000 87749.65625 2309619.25000 90611.12500 2310948.00000 93091.81250 2311895.25000 95571.11718 2312654.00000 97478.49218 + 2297238.500000 57395.597656 2297106.750000 58187.964844 2297485.000000 59522.621094 2297863.750000 61047.648438 2299194.750000 62385.292969 2300140.750000 65626.695312 2300518.250000 67723.257812 2301084.500000 70201.570312 2301842.500000 72489.882812 2302601.000000 74206.687500 2303169.500000 75922.882812 2303737.000000 77829.648438 2305255.000000 81072.867188 2306393.500000 83552.757812 2307531.500000 86223.250000 2308291.000000 87749.656250 2309619.250000 90611.125000 2310948.000000 93091.812500 2311895.250000 95571.117188 2312654.000000 97478.492188 @@ -686,13 +686,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2281531.25000 33374.88281 - 2297238.50000 57395.59765 + 2281531.250000 33374.882812 + 2297238.500000 57395.597656 - 2281531.25000 33374.88281 2283055.50000 33379.62500 2284958.50000 34719.06250 2286669.50000 36629.21093 2288191.00000 37967.44140 2289140.50000 39685.00781 2290661.75000 41213.62109 2291421.50000 42549.45312 2292749.75000 45411.08593 2293889.00000 47510.03906 2294836.00000 50179.93359 2295594.00000 52468.23437 2296161.75000 54184.45703 2296350.00000 55328.10546 2297238.50000 57395.59765 + 2281531.250000 33374.882812 2283055.500000 33379.625000 2284958.500000 34719.062500 2286669.500000 36629.210938 2288191.000000 37967.441406 2289140.500000 39685.007812 2290661.750000 41213.621094 2291421.500000 42549.453125 2292749.750000 45411.085938 2293889.000000 47510.039062 2294836.000000 50179.933594 2295594.000000 52468.234375 2296161.750000 54184.457031 2296350.000000 55328.105469 2297238.500000 57395.597656 @@ -701,13 +701,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2381508.00000 16173.98535 - 2385409.75000 64738.70312 + 2381508.000000 16173.985352 + 2385409.750000 64738.703125 - 2381693.75000 64738.70312 2381508.00000 62452.16406 2381512.75000 59975.63281 2381516.00000 58261.21093 2381519.00000 56737.19531 2381714.50000 54261.45703 2382099.00000 52357.66406 2382292.00000 51024.80078 2383060.50000 47979.33593 2383635.50000 46076.12109 2383829.00000 44933.86328 2384212.50000 43601.60156 2384406.00000 42078.15234 2384408.50000 40744.71093 2384793.25000 38840.88281 2384987.75000 36746.12109 2384991.75000 34650.73046 2384804.25000 33126.14843 2384808.75000 30840.17773 2385005.75000 27602.32226 2385008.25000 26268.87109 2385011.00000 24935.43359 2385205.50000 23221.61718 2385208.50000 21697.58203 2385211.50000 20173.74609 2385404.50000 18840.88476 2385409.75000 16173.98535 + 2381693.750000 64738.703125 2381508.000000 62452.164062 2381512.750000 59975.632812 2381516.000000 58261.210938 2381519.000000 56737.195312 2381714.500000 54261.457031 2382099.000000 52357.664062 2382292.000000 51024.800781 2383060.500000 47979.335938 2383635.500000 46076.121094 2383829.000000 44933.863281 2384212.500000 43601.601562 2384406.000000 42078.152344 2384408.500000 40744.710938 2384793.250000 38840.882812 2384987.750000 36746.121094 2384991.750000 34650.730469 2384804.250000 33126.148438 2384808.750000 30840.177734 2385005.750000 27602.322266 2385008.250000 26268.871094 2385011.000000 24935.433594 2385205.500000 23221.617188 2385208.500000 21697.582031 2385211.500000 20173.746094 2385404.500000 18840.884766 2385409.750000 16173.985352 @@ -716,13 +716,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2273022.50000 -64336.01953 - 2385417.50000 33374.88281 + 2273022.500000 -64336.019531 + 2385417.500000 33374.882812 - 2385409.75000 16173.98535 2385415.25000 13316.48437 2385417.50000 12173.60546 2385230.50000 10458.43261 2384279.00000 9693.52734 2383137.00000 9118.44433 2381994.75000 8543.49316 2380472.25000 7586.24560 2379713.25000 5869.44043 2379526.25000 4154.27636 2379528.50000 3011.38769 2379531.75000 1296.96411 2379534.75000 -227.06932 2379919.00000 -1559.31091 2380111.75000 -2701.62646 2379732.25000 -3845.84716 2378401.25000 -5183.49511 2377262.75000 -7282.44091 2375360.75000 -9193.36523 2374029.25000 -10340.43652 2372507.25000 -11488.24902 2370985.25000 -12635.89648 2370224.75000 -13590.76953 2369465.25000 -14736.20996 2368704.50000 -15691.09570 2367562.25000 -16266.02734 2366422.00000 -17793.60937 2364900.75000 -19322.21484 2363949.75000 -20277.68554 2362049.25000 -22569.58789 2361288.75000 -23524.48632 2360528.75000 -24479.34375 2359959.00000 -25624.01757 2359008.75000 -26579.49804 2357867.50000 -27726.10937 2356727.00000 -29063.15820 2355777.00000 -30589.97070 2354636.25000 -31927.01171 2353686.75000 -33263.60937 2353117.75000 -34789.21875 2352742.00000 -37457.33593 2352175.25000 -39745.06250 2351988.25000 -41841.04296 2351801.25000 -43556.22265 2352185.25000 -44888.48828 2352570.75000 -47173.22656 2352954.50000 -48695.90234 2353147.25000 -49838.38281 2353340.75000 -51361.63671 2353535.25000 -53075.43750 2353729.00000 -54789.43359 2353544.25000 -57647.32421 2353355.25000 -58790.98046 2352976.75000 -59935.03515 2352217.50000 -61270.88671 2351267.25000 -62607.31250 2350125.50000 -63373.01171 2348030.25000 -63950.90234 2346697.25000 -64336.01953 2344411.00000 -64152.77734 2343075.75000 -63395.03515 2341549.75000 -62828.27343 2339453.00000 -62263.27734 2337355.75000 -61698.29296 2336212.00000 -61511.50000 2335068.25000 -60943.51562 2334114.00000 -60184.58984 2332777.50000 -58855.31640 2331822.75000 -57905.78906 2329724.50000 -56578.87500 2328391.25000 -56773.44140 2326674.25000 -56016.89062 2325529.50000 -55258.52343 2324575.75000 -54499.41796 2323811.50000 -53549.49218 2322665.25000 -52029.02734 2321900.75000 -50697.95312 2321136.00000 -49557.28125 2320180.50000 -48226.81250 2319036.50000 -47849.41015 2317703.00000 -48044.14062 2316369.75000 -48238.72265 2314464.00000 -47863.69140 2313319.50000 -47295.92578 2312365.00000 -46536.78906 2311221.75000 -46159.39453 2309696.50000 -45973.79687 2308553.00000 -45596.20312 2307027.00000 -45029.62890 2305313.00000 -45415.94531 2304171.25000 -46181.43750 2303031.00000 -47709.04687 2301510.50000 -49618.60156 2300369.75000 -50955.62500 2299991.50000 -52290.47656 2299233.25000 -54007.23828 2298284.50000 -56105.63281 2297141.00000 -56109.19140 2296374.00000 -53825.62109 2296371.50000 -52492.15625 2295796.50000 -50588.96484 2295411.50000 -48494.79687 2295027.25000 -47162.51953 2294644.00000 -46020.83593 2293687.50000 -44118.82031 2292923.00000 -42787.74609 2291015.75000 -42031.60156 2289298.50000 -40703.52734 2288534.25000 -39753.59375 2287389.25000 -38614.09765 2286051.00000 -36332.30859 2285476.50000 -35000.66796 2284712.75000 -34050.54687 2283757.25000 -32720.07421 2282611.00000 -31199.79296 2281656.25000 -30250.29296 2280128.75000 -28540.63476 2279554.75000 -27208.78320 2278789.00000 -25496.74609 2278020.75000 -22260.87109 2276872.50000 -19787.94335 2276678.75000 -18074.11914 2276295.00000 -16932.23828 2275340.50000 -15792.34375 2274576.25000 -14842.23437 2273238.25000 -12751.03320 2273043.00000 -10275.11328 2273040.50000 -8941.64257 2273036.25000 -6846.25927 2273031.50000 -4369.75048 2273027.75000 -2464.96728 2273025.00000 -1131.50891 2273022.50000 201.94564 2273209.00000 2107.54418 2273585.75000 4204.26074 2273774.00000 5347.75195 2273770.75000 7062.16601 2274339.75000 8587.97753 2275095.75000 11447.65429 2276045.00000 13355.62304 2277184.25000 15454.77148 2277751.50000 17551.89648 2278128.00000 20029.44335 2278697.25000 21174.29492 2279075.75000 22318.34960 2279453.75000 24224.55859 2279641.00000 25749.16796 2280018.25000 27655.16015 2280206.50000 28798.79882 2280394.25000 30132.87109 2281531.25000 33374.88281 + 2385409.750000 16173.985352 2385415.250000 13316.484375 2385417.500000 12173.605469 2385230.500000 10458.432617 2384279.000000 9693.527344 2383137.000000 9118.444336 2381994.750000 8543.493164 2380472.250000 7586.245605 2379713.250000 5869.440430 2379526.250000 4154.276367 2379528.500000 3011.387695 2379531.750000 1296.964111 2379534.750000 -227.069321 2379919.000000 -1559.310913 2380111.750000 -2701.626465 2379732.250000 -3845.847168 2378401.250000 -5183.495117 2377262.750000 -7282.440918 2375360.750000 -9193.365234 2374029.250000 -10340.436523 2372507.250000 -11488.249023 2370985.250000 -12635.896484 2370224.750000 -13590.769531 2369465.250000 -14736.209961 2368704.500000 -15691.095703 2367562.250000 -16266.027344 2366422.000000 -17793.609375 2364900.750000 -19322.214844 2363949.750000 -20277.685547 2362049.250000 -22569.587891 2361288.750000 -23524.486328 2360528.750000 -24479.343750 2359959.000000 -25624.017578 2359008.750000 -26579.498047 2357867.500000 -27726.109375 2356727.000000 -29063.158203 2355777.000000 -30589.970703 2354636.250000 -31927.011719 2353686.750000 -33263.609375 2353117.750000 -34789.218750 2352742.000000 -37457.335938 2352175.250000 -39745.062500 2351988.250000 -41841.042969 2351801.250000 -43556.222656 2352185.250000 -44888.488281 2352570.750000 -47173.226562 2352954.500000 -48695.902344 2353147.250000 -49838.382812 2353340.750000 -51361.636719 2353535.250000 -53075.437500 2353729.000000 -54789.433594 2353544.250000 -57647.324219 2353355.250000 -58790.980469 2352976.750000 -59935.035156 2352217.500000 -61270.886719 2351267.250000 -62607.312500 2350125.500000 -63373.011719 2348030.250000 -63950.902344 2346697.250000 -64336.019531 2344411.000000 -64152.777344 2343075.750000 -63395.035156 2341549.750000 -62828.273438 2339453.000000 -62263.277344 2337355.750000 -61698.292969 2336212.000000 -61511.500000 2335068.250000 -60943.515625 2334114.000000 -60184.589844 2332777.500000 -58855.316406 2331822.750000 -57905.789062 2329724.500000 -56578.875000 2328391.250000 -56773.441406 2326674.250000 -56016.890625 2325529.500000 -55258.523438 2324575.750000 -54499.417969 2323811.500000 -53549.492188 2322665.250000 -52029.027344 2321900.750000 -50697.953125 2321136.000000 -49557.281250 2320180.500000 -48226.812500 2319036.500000 -47849.410156 2317703.000000 -48044.140625 2316369.750000 -48238.722656 2314464.000000 -47863.691406 2313319.500000 -47295.925781 2312365.000000 -46536.789062 2311221.750000 -46159.394531 2309696.500000 -45973.796875 2308553.000000 -45596.203125 2307027.000000 -45029.628906 2305313.000000 -45415.945312 2304171.250000 -46181.437500 2303031.000000 -47709.046875 2301510.500000 -49618.601562 2300369.750000 -50955.625000 2299991.500000 -52290.476562 2299233.250000 -54007.238281 2298284.500000 -56105.632812 2297141.000000 -56109.191406 2296374.000000 -53825.621094 2296371.500000 -52492.156250 2295796.500000 -50588.964844 2295411.500000 -48494.796875 2295027.250000 -47162.519531 2294644.000000 -46020.835938 2293687.500000 -44118.820312 2292923.000000 -42787.746094 2291015.750000 -42031.601562 2289298.500000 -40703.527344 2288534.250000 -39753.593750 2287389.250000 -38614.097656 2286051.000000 -36332.308594 2285476.500000 -35000.667969 2284712.750000 -34050.546875 2283757.250000 -32720.074219 2282611.000000 -31199.792969 2281656.250000 -30250.292969 2280128.750000 -28540.634766 2279554.750000 -27208.783203 2278789.000000 -25496.746094 2278020.750000 -22260.871094 2276872.500000 -19787.943359 2276678.750000 -18074.119141 2276295.000000 -16932.238281 2275340.500000 -15792.343750 2274576.250000 -14842.234375 2273238.250000 -12751.033203 2273043.000000 -10275.113281 2273040.500000 -8941.642578 2273036.250000 -6846.259277 2273031.500000 -4369.750488 2273027.750000 -2464.967285 2273025.000000 -1131.508911 2273022.500000 201.945648 2273209.000000 2107.544189 2273585.750000 4204.260742 2273774.000000 5347.751953 2273770.750000 7062.166016 2274339.750000 8587.977539 2275095.750000 11447.654297 2276045.000000 13355.623047 2277184.250000 15454.771484 2277751.500000 17551.896484 2278128.000000 20029.443359 2278697.250000 21174.294922 2279075.750000 22318.349609 2279453.750000 24224.558594 2279641.000000 25749.167969 2280018.250000 27655.160156 2280206.500000 28798.798828 2280394.250000 30132.871094 2281531.250000 33374.882812 @@ -731,13 +731,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2417042.50000 136722.43750 - 2428229.75000 206984.43750 + 2417042.500000 136722.437500 + 2428229.750000 206984.437500 - 2417042.50000 206984.43750 2419909.00000 204110.21875 2420865.25000 202398.57812 2422201.50000 201069.31250 2422965.50000 199928.79687 2423349.75000 198596.54687 2423733.00000 197454.67187 2424309.75000 194599.17187 2424505.00000 192504.20312 2424507.25000 191361.32812 2424510.75000 189646.90625 2424514.50000 187741.90625 2424517.50000 186217.89062 2424521.25000 184313.09375 2424332.25000 183169.43750 2424335.25000 181645.59375 2424337.50000 180502.53125 2424149.75000 179168.48437 2423772.25000 177452.89062 2423774.50000 176310.00000 2423397.75000 174213.25000 2423019.00000 172688.21875 2422641.25000 171162.98437 2422263.00000 169828.35937 2422265.25000 168685.29687 2422268.25000 167161.45312 2422080.50000 165827.40625 2421894.00000 163731.42187 2421899.75000 160873.93750 2422093.25000 159350.53125 2422286.25000 158017.67187 2423049.75000 157067.56250 2424389.25000 154214.42187 2424582.50000 153071.95312 2425347.00000 151740.89062 2426113.50000 149647.89062 2426878.25000 148126.23437 2427263.50000 146222.64062 2427646.75000 145080.75000 2427839.50000 143938.50000 2428034.00000 141843.51562 2428229.75000 139177.21875 2428043.00000 137271.64062 2427983.00000 136722.43750 + 2417042.500000 206984.437500 2419909.000000 204110.218750 2420865.250000 202398.578125 2422201.500000 201069.312500 2422965.500000 199928.796875 2423349.750000 198596.546875 2423733.000000 197454.671875 2424309.750000 194599.171875 2424505.000000 192504.203125 2424507.250000 191361.328125 2424510.750000 189646.906250 2424514.500000 187741.906250 2424517.500000 186217.890625 2424521.250000 184313.093750 2424332.250000 183169.437500 2424335.250000 181645.593750 2424337.500000 180502.531250 2424149.750000 179168.484375 2423772.250000 177452.890625 2423774.500000 176310.000000 2423397.750000 174213.250000 2423019.000000 172688.218750 2422641.250000 171162.984375 2422263.000000 169828.359375 2422265.250000 168685.296875 2422268.250000 167161.453125 2422080.500000 165827.406250 2421894.000000 163731.421875 2421899.750000 160873.937500 2422093.250000 159350.531250 2422286.250000 158017.671875 2423049.750000 157067.562500 2424389.250000 154214.421875 2424582.500000 153071.953125 2425347.000000 151740.890625 2426113.500000 149647.890625 2426878.250000 148126.234375 2427263.500000 146222.640625 2427646.750000 145080.750000 2427839.500000 143938.500000 2428034.000000 141843.515625 2428229.750000 139177.218750 2428043.000000 137271.640625 2427983.000000 136722.437500 @@ -746,13 +746,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2427983.00000 127024.38281 - 2437545.00000 136722.43750 + 2427983.000000 127024.382812 + 2437545.000000 136722.437500 - 2427983.00000 136722.43750 2429730.50000 136509.39062 2431065.75000 135751.32812 2431830.25000 134419.78125 2432595.00000 133278.68750 2433358.75000 132328.25000 2434314.00000 131187.95312 2435078.75000 130047.02343 2435842.75000 128905.95312 2437545.00000 127024.38281 + 2427983.000000 136722.437500 2429730.500000 136509.390625 2431065.750000 135751.328125 2431830.250000 134419.781250 2432595.000000 133278.687500 2433358.750000 132328.250000 2434314.000000 131187.953125 2435078.750000 130047.023438 2435842.750000 128905.953125 2437545.000000 127024.382812 @@ -761,13 +761,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2428879.25000 120844.14843 - 2437545.00000 127024.38281 + 2428879.250000 120844.148438 + 2437545.000000 127024.382812 - 2437545.00000 127024.38281 2437182.50000 126051.61718 2436234.00000 124333.68750 2435664.25000 123188.63281 2434713.50000 122232.84375 2433190.50000 121656.38281 2428879.25000 120844.14843 + 2437545.000000 127024.382812 2437182.500000 126051.617188 2436234.000000 124333.687500 2435664.250000 123188.632812 2434713.500000 122232.843750 2433190.500000 121656.382812 2428879.250000 120844.148438 @@ -776,13 +776,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2364917.00000 200324.98437 - 2399226.25000 219211.67187 + 2364917.000000 200324.984375 + 2399226.250000 219211.671875 - 2364917.00000 219211.67187 2368775.25000 212649.42187 2369152.25000 212290.87500 2370079.50000 211409.39062 2372288.25000 209310.03125 2373868.50000 208388.89062 2375666.50000 206847.62500 2378371.25000 205057.00000 2381376.25000 203180.95312 2383945.75000 202268.12500 2387074.75000 201435.76562 2392200.50000 200634.57812 2395394.00000 200324.98437 2399226.25000 201743.82812 + 2364917.000000 219211.671875 2368775.250000 212649.421875 2369152.250000 212290.875000 2370079.500000 211409.390625 2372288.250000 209310.031250 2373868.500000 208388.890625 2375666.500000 206847.625000 2378371.250000 205057.000000 2381376.250000 203180.953125 2383945.750000 202268.125000 2387074.750000 201435.765625 2392200.500000 200634.578125 2395394.000000 200324.984375 2399226.250000 201743.828125 @@ -791,13 +791,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2376921.25000 301084.96875 - 2380836.00000 301697.28125 + 2376921.250000 301084.968750 + 2380836.000000 301697.281250 - 2376921.25000 301464.28125 2379101.25000 301697.28125 2380836.00000 301084.96875 + 2376921.250000 301464.281250 2379101.250000 301697.281250 2380836.000000 301084.968750 @@ -806,13 +806,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2380836.00000 299794.00000 - 2398316.25000 301915.87500 + 2380836.000000 299794.000000 + 2398316.250000 301915.875000 - 2380836.00000 301084.96875 2381396.75000 300887.09375 2385665.00000 300171.25000 2386999.25000 299794.00000 2388903.50000 299798.96875 2391378.00000 299805.40625 2394038.25000 301335.43750 2396320.25000 301912.40625 2397653.00000 301915.87500 2398316.25000 301857.34375 + 2380836.000000 301084.968750 2381396.750000 300887.093750 2385665.000000 300171.250000 2386999.250000 299794.000000 2388903.500000 299798.968750 2391378.000000 299805.406250 2394038.250000 301335.437500 2396320.250000 301912.406250 2397653.000000 301915.875000 2398316.250000 301857.343750 @@ -821,13 +821,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2375060.75000 298175.34375 - 2376921.25000 301464.28125 + 2375060.750000 298175.343750 + 2376921.250000 301464.281250 - 2375060.75000 298175.34375 2375860.50000 299806.87500 2376921.25000 301464.28125 + 2375060.750000 298175.343750 2375860.500000 299806.875000 2376921.250000 301464.281250 @@ -836,13 +836,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2398316.25000 285013.40625 - 2423954.25000 301857.34375 + 2398316.250000 285013.406250 + 2423954.250000 301857.343750 - 2398316.25000 301857.34375 2399748.25000 301731.06250 2402663.75000 300752.06250 2404715.25000 297555.56250 2405865.75000 295274.00000 2406635.25000 293372.15625 2407022.50000 291659.75000 2407600.25000 290138.34375 2408367.25000 288617.21875 2409896.25000 287098.09375 2412188.75000 285200.40625 2413522.25000 285013.40625 2415805.50000 285400.09375 2418088.25000 285977.25000 2419418.75000 286551.90625 2421699.25000 287509.75000 2423954.25000 287380.78125 + 2398316.250000 301857.343750 2399748.250000 301731.062500 2402663.750000 300752.062500 2404715.250000 297555.562500 2405865.750000 295274.000000 2406635.250000 293372.156250 2407022.500000 291659.750000 2407600.250000 290138.343750 2408367.250000 288617.218750 2409896.250000 287098.093750 2412188.750000 285200.406250 2413522.250000 285013.406250 2415805.500000 285400.093750 2418088.250000 285977.250000 2419418.750000 286551.906250 2421699.250000 287509.750000 2423954.250000 287380.781250 @@ -851,13 +851,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2347757.75000 282176.75000 - 2375060.75000 298175.34375 + 2347757.750000 282176.750000 + 2375060.750000 298175.343750 - 2347757.75000 282176.75000 2349180.75000 282180.50000 2350892.50000 282565.68750 2352604.25000 282950.87500 2354694.50000 284098.71875 2355836.25000 284291.96875 2356725.75000 284492.25000 2357548.00000 284677.34375 2359260.50000 284872.06250 2361544.75000 285068.46875 2363829.50000 285074.43750 2365921.25000 285650.87500 2368009.00000 287369.90625 2369335.75000 288896.28125 2370049.50000 289974.90625 2370471.50000 290612.62500 2371037.25000 291946.75000 2372363.25000 293663.78125 2373120.50000 294807.93750 2373878.00000 295761.84375 2375060.75000 298175.34375 + 2347757.750000 282176.750000 2349180.750000 282180.500000 2350892.500000 282565.687500 2352604.250000 282950.875000 2354694.500000 284098.718750 2355836.250000 284291.968750 2356725.750000 284492.250000 2357548.000000 284677.343750 2359260.500000 284872.062500 2361544.750000 285068.468750 2363829.500000 285074.437500 2365921.250000 285650.875000 2368009.000000 287369.906250 2369335.750000 288896.281250 2370049.500000 289974.906250 2370471.500000 290612.625000 2371037.250000 291946.750000 2372363.250000 293663.781250 2373120.500000 294807.937500 2373878.000000 295761.843750 2375060.750000 298175.343750 @@ -866,13 +866,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2544336.75000 373668.78125 - 2552279.50000 391797.40625 + 2544336.750000 373668.781250 + 2552279.500000 391797.406250 - 2552279.50000 391797.40625 2551522.00000 390843.50000 2550766.25000 389318.59375 2550202.00000 387603.56250 2549635.00000 386459.87500 2549260.50000 384935.78125 2548885.75000 383411.87500 2548325.50000 380554.65625 2547383.75000 378077.34375 2546439.00000 376171.06250 2545494.50000 374264.75000 2544336.75000 373668.78125 + 2552279.500000 391797.406250 2551522.000000 390843.500000 2550766.250000 389318.593750 2550202.000000 387603.562500 2549635.000000 386459.875000 2549260.500000 384935.781250 2548885.750000 383411.875000 2548325.500000 380554.656250 2547383.750000 378077.343750 2546439.000000 376171.062500 2545494.500000 374264.750000 2544336.750000 373668.781250 @@ -881,13 +881,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2529868.00000 310448.28125 - 2544336.75000 373668.78125 + 2529868.000000 310448.281250 + 2544336.750000 373668.781250 - 2544336.75000 373668.78125 2543217.00000 372545.40625 2541696.25000 371780.00000 2539986.75000 370823.62500 2538879.25000 369569.18750 2538470.50000 369106.28125 2537525.75000 367199.96875 2536960.25000 365865.84375 2536394.50000 364341.25000 2536211.75000 362436.93750 2535461.00000 359769.68750 2534706.75000 357864.03125 2534141.75000 356339.46875 2533414.00000 354553.40625 2532821.75000 353099.53125 2531687.75000 351002.43750 2531502.50000 349669.31250 2530561.75000 346811.09375 2530191.00000 344335.28125 2530769.25000 342432.93750 2530777.50000 340338.84375 2530600.75000 336911.40625 2530226.00000 335387.50000 2530041.00000 333863.90625 2530049.25000 331769.81250 2529868.00000 329484.75000 2530070.25000 326439.25000 2530460.75000 324155.68750 2530849.50000 322062.40625 2531428.50000 319969.78125 2531822.50000 316734.31250 2532408.50000 312928.34375 2532595.25000 310448.28125 + 2544336.750000 373668.781250 2543217.000000 372545.406250 2541696.250000 371780.000000 2539986.750000 370823.625000 2538879.250000 369569.187500 2538470.500000 369106.281250 2537525.750000 367199.968750 2536960.250000 365865.843750 2536394.500000 364341.250000 2536211.750000 362436.937500 2535461.000000 359769.687500 2534706.750000 357864.031250 2534141.750000 356339.468750 2533414.000000 354553.406250 2532821.750000 353099.531250 2531687.750000 351002.437500 2531502.500000 349669.312500 2530561.750000 346811.093750 2530191.000000 344335.281250 2530769.250000 342432.937500 2530777.500000 340338.843750 2530600.750000 336911.406250 2530226.000000 335387.500000 2530041.000000 333863.906250 2530049.250000 331769.812500 2529868.000000 329484.750000 2530070.250000 326439.250000 2530460.750000 324155.687500 2530849.500000 322062.406250 2531428.500000 319969.781250 2531822.500000 316734.312500 2532408.500000 312928.343750 2532595.250000 310448.281250 @@ -896,13 +896,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2528707.75000 302480.75000 - 2532595.25000 310448.28125 + 2528707.750000 302480.750000 + 2532595.250000 310448.281250 - 2532595.25000 310448.28125 2532428.75000 307788.03125 2530914.00000 305689.96875 2529782.00000 303021.71875 2528707.75000 302480.75000 + 2532595.250000 310448.281250 2532428.750000 307788.031250 2530914.000000 305689.968750 2529782.000000 303021.718750 2528707.750000 302480.750000 @@ -911,13 +911,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2517059.75000 291146.93750 - 2528707.75000 302480.75000 + 2517059.750000 291146.937500 + 2528707.750000 302480.750000 - 2528707.75000 302480.75000 2525406.25000 302248.65625 2522563.25000 299004.93750 2521052.25000 295954.78125 2519536.75000 293856.71875 2518210.75000 292139.87500 2517059.75000 291146.93750 + 2528707.750000 302480.750000 2525406.250000 302248.656250 2522563.250000 299004.937500 2521052.250000 295954.781250 2519536.750000 293856.718750 2518210.750000 292139.875000 2517059.750000 291146.937500 @@ -926,13 +926,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2497925.50000 276774.43750 - 2517059.75000 291146.93750 + 2497925.500000 276774.437500 + 2517059.750000 291146.937500 - 2517059.75000 291146.93750 2514419.25000 288132.03125 2512900.75000 286795.40625 2511572.50000 285649.56250 2510433.75000 284694.68750 2508534.75000 283547.53125 2505875.25000 282017.50000 2502456.75000 279724.03125 2499989.75000 277813.93750 2497925.50000 276774.43750 + 2517059.750000 291146.937500 2514419.250000 288132.031250 2512900.750000 286795.406250 2511572.500000 285649.562500 2510433.750000 284694.687500 2508534.750000 283547.531250 2505875.250000 282017.500000 2502456.750000 279724.031250 2499989.750000 277813.937500 2497925.500000 276774.437500 @@ -941,13 +941,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2446614.50000 245881.25000 - 2497925.50000 276774.43750 + 2446614.500000 245881.250000 + 2497925.500000 276774.437500 - 2497925.50000 276774.43750 2495810.25000 275328.00000 2494292.50000 273991.40625 2491448.75000 270937.93750 2488982.00000 268837.40625 2486703.75000 267117.90625 2483282.25000 265776.31250 2480812.50000 264437.25000 2478150.75000 263478.37500 2475489.00000 262519.71875 2472258.50000 260988.17187 2469600.00000 259267.87500 2466751.75000 257166.14062 2463520.50000 255825.06250 2460098.50000 254483.50000 2456490.50000 252189.51562 2454781.00000 251042.87500 2453262.50000 249896.71875 2452123.00000 249132.10937 2450985.00000 247986.93750 2448135.25000 246456.42187 2446614.50000 245881.25000 + 2497925.500000 276774.437500 2495810.250000 275328.000000 2494292.500000 273991.406250 2491448.750000 270937.937500 2488982.000000 268837.406250 2486703.750000 267117.906250 2483282.250000 265776.312500 2480812.500000 264437.250000 2478150.750000 263478.375000 2475489.000000 262519.718750 2472258.500000 260988.171875 2469600.000000 259267.875000 2466751.750000 257166.140625 2463520.500000 255825.062500 2460098.500000 254483.500000 2456490.500000 252189.515625 2454781.000000 251042.875000 2453262.500000 249896.718750 2452123.000000 249132.109375 2450985.000000 247986.937500 2448135.250000 246456.421875 2446614.500000 245881.250000 @@ -956,13 +956,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2417042.50000 206984.43750 - 2446614.50000 245881.25000 + 2417042.500000 206984.437500 + 2446614.500000 245881.250000 - 2446614.50000 245881.25000 2445859.25000 244356.34375 2444723.00000 242830.28125 2443774.50000 241875.89062 2442446.25000 240730.23437 2441497.00000 239966.31250 2439789.00000 238629.18750 2438083.25000 236720.89062 2436759.50000 234432.85937 2436008.00000 231765.60937 2435255.25000 229479.06250 2434310.50000 227763.21875 2432606.25000 225283.73437 2430899.00000 223756.35937 2428811.75000 222037.35937 2427105.25000 220129.23437 2425780.00000 218221.95312 2424646.50000 215934.42187 2423511.50000 214218.09375 2422185.50000 212501.23437 2420669.25000 210593.43750 2419721.75000 209639.03125 2417824.75000 207730.26562 2417042.50000 206984.43750 + 2446614.500000 245881.250000 2445859.250000 244356.343750 2444723.000000 242830.281250 2443774.500000 241875.890625 2442446.250000 240730.234375 2441497.000000 239966.312500 2439789.000000 238629.187500 2438083.250000 236720.890625 2436759.500000 234432.859375 2436008.000000 231765.609375 2435255.250000 229479.062500 2434310.500000 227763.218750 2432606.250000 225283.734375 2430899.000000 223756.359375 2428811.750000 222037.359375 2427105.250000 220129.234375 2425780.000000 218221.953125 2424646.500000 215934.421875 2423511.500000 214218.093750 2422185.500000 212501.234375 2420669.250000 210593.437500 2419721.750000 209639.031250 2417824.750000 207730.265625 2417042.500000 206984.437500 @@ -971,13 +971,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2399226.25000 200265.42187 - 2417042.50000 206984.43750 + 2399226.250000 200265.421875 + 2417042.500000 206984.437500 - 2417042.50000 206984.43750 2414220.75000 204294.09375 2412130.50000 203336.71875 2409088.25000 202376.87500 2406237.00000 201036.79687 2402432.75000 200265.42187 2400336.75000 200640.68750 2399226.25000 201743.82812 + 2417042.500000 206984.437500 2414220.750000 204294.093750 2412130.500000 203336.718750 2409088.250000 202376.875000 2406237.000000 201036.796875 2402432.750000 200265.421875 2400336.750000 200640.687500 2399226.250000 201743.828125 @@ -986,13 +986,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2364917.00000 201743.82812 - 2399226.25000 224582.79687 + 2364917.000000 201743.828125 + 2399226.250000 224582.796875 - 2399226.25000 201743.82812 2398425.50000 202539.56250 2397087.50000 203868.75000 2395750.25000 205007.43750 2394218.25000 207097.75000 2393074.25000 207665.78125 2391164.75000 208993.46875 2389636.50000 210322.14062 2388488.75000 211651.81250 2387909.00000 213934.89062 2387522.50000 215266.50000 2387516.50000 216789.62500 2387701.50000 218122.75000 2387876.00000 222311.62500 2386347.00000 223640.29687 2384630.75000 224397.29687 2382726.25000 224582.79687 2380824.25000 224006.65625 2378164.00000 222667.06250 2375504.50000 221137.03125 2372652.50000 220177.67187 2370370.50000 219410.28125 2368086.50000 219404.32812 2366944.00000 219401.32812 2364917.00000 219211.67187 + 2399226.250000 201743.828125 2398425.500000 202539.562500 2397087.500000 203868.750000 2395750.250000 205007.437500 2394218.250000 207097.750000 2393074.250000 207665.781250 2391164.750000 208993.468750 2389636.500000 210322.140625 2388488.750000 211651.812500 2387909.000000 213934.890625 2387522.500000 215266.500000 2387516.500000 216789.625000 2387701.500000 218122.750000 2387876.000000 222311.625000 2386347.000000 223640.296875 2384630.750000 224397.296875 2382726.250000 224582.796875 2380824.250000 224006.656250 2378164.000000 222667.062500 2375504.500000 221137.031250 2372652.500000 220177.671875 2370370.500000 219410.281250 2368086.500000 219404.328125 2366944.000000 219401.328125 2364917.000000 219211.671875 @@ -1001,13 +1001,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2327897.50000 211535.75000 - 2346585.25000 213607.48437 + 2327897.500000 211535.750000 + 2346585.250000 213607.484375 - 2346585.25000 211882.15625 2345840.50000 211731.14062 2343937.00000 211535.75000 2341841.50000 211911.20312 2339745.50000 212286.46875 2336888.00000 212659.76562 2335366.50000 212275.04687 2333462.25000 212270.10937 2331749.75000 212075.18750 2329843.75000 212641.40625 2327897.50000 213607.48437 + 2346585.250000 211882.156250 2345840.500000 211731.140625 2343937.000000 211535.750000 2341841.500000 211911.203125 2339745.500000 212286.468750 2336888.000000 212659.765625 2335366.500000 212275.046875 2333462.250000 212270.109375 2331749.750000 212075.187500 2329843.750000 212641.406250 2327897.500000 213607.484375 @@ -1016,13 +1016,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2346585.25000 211882.15625 - 2364917.00000 219211.67187 + 2346585.250000 211882.156250 + 2364917.000000 219211.671875 - 2364917.00000 219211.67187 2364850.25000 219205.42187 2361998.75000 218055.79687 2360669.25000 217290.87500 2358892.25000 216247.53125 2358389.50000 215952.28125 2357059.75000 215187.15625 2354780.75000 213848.57812 2352499.75000 212890.68750 2350217.00000 212313.75000 2347742.50000 212116.84375 2346585.25000 211882.15625 + 2364917.000000 219211.671875 2364850.250000 219205.421875 2361998.750000 218055.796875 2360669.250000 217290.875000 2358892.250000 216247.531250 2358389.500000 215952.281250 2357059.750000 215187.156250 2354780.750000 213848.578125 2352499.750000 212890.687500 2350217.000000 212313.750000 2347742.500000 212116.843750 2346585.250000 211882.156250 @@ -1031,13 +1031,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2552279.50000 391797.40625 - 2576803.50000 408596.37500 + 2552279.500000 391797.406250 + 2576803.500000 408596.375000 - 2576803.50000 401189.87500 2575467.25000 402138.34375 2573936.50000 404038.15625 2573166.00000 406320.75000 2571445.00000 408220.09375 2569730.00000 408596.37500 2568399.50000 408021.75000 2567258.75000 407638.00000 2566312.50000 406112.43750 2565365.50000 404777.34375 2563847.00000 403631.15625 2562706.75000 403057.00000 2561567.25000 402482.84375 2559473.50000 402287.09375 2557187.75000 402471.40625 2555980.50000 401673.62500 2555723.75000 400544.71875 2555826.50000 397568.50000 2555056.50000 394797.50000 2552279.50000 391797.40625 + 2576803.500000 401189.875000 2575467.250000 402138.343750 2573936.500000 404038.156250 2573166.000000 406320.750000 2571445.000000 408220.093750 2569730.000000 408596.375000 2568399.500000 408021.750000 2567258.750000 407638.000000 2566312.500000 406112.437500 2565365.500000 404777.343750 2563847.000000 403631.156250 2562706.750000 403057.000000 2561567.250000 402482.843750 2559473.500000 402287.093750 2557187.750000 402471.406250 2555980.500000 401673.625000 2555723.750000 400544.718750 2555826.500000 397568.500000 2555056.500000 394797.500000 2552279.500000 391797.406250 @@ -1046,13 +1046,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2576803.50000 401189.87500 - 2578927.50000 402717.03125 + 2576803.500000 401189.875000 + 2578927.500000 402717.031250 - 2576803.50000 401189.87500 2577421.25000 401365.65625 2578424.50000 401900.81250 2578927.50000 402717.03125 + 2576803.500000 401189.875000 2577421.250000 401365.656250 2578424.500000 401900.812500 2578927.500000 402717.031250 @@ -1061,13 +1061,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2576803.50000 399102.18750 - 2589745.50000 402556.25000 + 2576803.500000 399102.187500 + 2589745.500000 402556.250000 - 2589745.50000 402556.25000 2588416.50000 401601.06250 2587278.50000 400455.71875 2585757.50000 399880.53125 2582523.25000 399110.65625 2581190.50000 399107.18750 2579286.75000 399102.18750 2577761.50000 399669.40625 2576803.50000 401189.87500 + 2589745.500000 402556.250000 2588416.500000 401601.062500 2587278.500000 400455.718750 2585757.500000 399880.531250 2582523.250000 399110.656250 2581190.500000 399107.187500 2579286.750000 399102.187500 2577761.500000 399669.406250 2576803.500000 401189.875000 @@ -1076,13 +1076,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2589745.50000 393939.62500 - 2615354.50000 402556.25000 + 2589745.500000 393939.625000 + 2615354.500000 402556.250000 - 2589745.50000 402556.25000 2591141.50000 401863.00000 2592476.75000 401105.34375 2594192.50000 400920.25000 2595526.50000 400734.15625 2597051.00000 400548.53125 2599145.50000 400745.87500 2600478.50000 401131.21875 2602192.25000 401898.84375 2603525.75000 401903.12500 2605241.75000 401146.65625 2606386.75000 400388.37500 2607341.00000 399629.25000 2607726.50000 397344.40625 2609063.00000 396014.90625 2610778.50000 395449.03125 2615354.50000 393939.62500 + 2589745.500000 402556.250000 2591141.500000 401863.000000 2592476.750000 401105.343750 2594192.500000 400920.250000 2595526.500000 400734.156250 2597051.000000 400548.531250 2599145.500000 400745.875000 2600478.500000 401131.218750 2602192.250000 401898.843750 2603525.750000 401903.125000 2605241.750000 401146.656250 2606386.750000 400388.375000 2607341.000000 399629.250000 2607726.500000 397344.406250 2609063.000000 396014.906250 2610778.500000 395449.031250 2615354.500000 393939.625000 @@ -1091,13 +1091,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2442115.25000 245881.25000 - 2446614.50000 262496.84375 + 2442115.250000 245881.250000 + 2446614.500000 262496.843750 - 2442115.25000 262496.84375 2442339.75000 261851.75000 2446590.50000 249634.64062 2446614.50000 245881.25000 + 2442115.250000 262496.843750 2442339.750000 261851.750000 2446590.500000 249634.640625 2446614.500000 245881.250000 @@ -1108,21 +1108,21 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2279399.00000 -55344.50390 - 2600377.00000 461586.81250 + 2279399.000000 -55344.503906 + 2600377.000000 461586.812500 - 2281604.25000 340848.93750 - 2281604.25000 340848.93750 + 2281604.250000 340848.937500 + 2281604.250000 340848.937500 - 2281604.25000 340848.93750 + 2281604.250000 340848.937500 @@ -1131,13 +1131,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2503805.50000 427872.65625 - 2503805.50000 427872.65625 + 2503805.500000 427872.656250 + 2503805.500000 427872.656250 - 2503805.50000 427872.65625 + 2503805.500000 427872.656250 @@ -1146,13 +1146,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2499190.00000 194088.23437 - 2499190.00000 194088.23437 + 2499190.000000 194088.234375 + 2499190.000000 194088.234375 - 2499190.00000 194088.23437 + 2499190.000000 194088.234375 @@ -1161,13 +1161,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2434957.00000 347013.59375 - 2434957.00000 347013.59375 + 2434957.000000 347013.593750 + 2434957.000000 347013.593750 - 2434957.00000 347013.59375 + 2434957.000000 347013.593750 @@ -1176,13 +1176,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2578914.25000 292073.09375 - 2578914.25000 292073.09375 + 2578914.250000 292073.093750 + 2578914.250000 292073.093750 - 2578914.25000 292073.09375 + 2578914.250000 292073.093750 @@ -1191,13 +1191,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2536072.75000 311524.96875 - 2536072.75000 311524.96875 + 2536072.750000 311524.968750 + 2536072.750000 311524.968750 - 2536072.75000 311524.96875 + 2536072.750000 311524.968750 @@ -1206,13 +1206,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2494520.00000 285855.40625 - 2494520.00000 285855.40625 + 2494520.000000 285855.406250 + 2494520.000000 285855.406250 - 2494520.00000 285855.40625 + 2494520.000000 285855.406250 @@ -1221,13 +1221,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2348711.75000 204294.06250 - 2348711.75000 204294.06250 + 2348711.750000 204294.062500 + 2348711.750000 204294.062500 - 2348711.75000 204294.06250 + 2348711.750000 204294.062500 @@ -1236,13 +1236,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2377598.00000 135734.70312 - 2377598.00000 135734.70312 + 2377598.000000 135734.703125 + 2377598.000000 135734.703125 - 2377598.00000 135734.70312 + 2377598.000000 135734.703125 @@ -1251,13 +1251,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2398677.25000 70608.14062 - 2398677.25000 70608.14062 + 2398677.250000 70608.140625 + 2398677.250000 70608.140625 - 2398677.25000 70608.14062 + 2398677.250000 70608.140625 @@ -1266,13 +1266,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2388340.00000 19784.32226 - 2388340.00000 19784.32226 + 2388340.000000 19784.322266 + 2388340.000000 19784.322266 - 2388340.00000 19784.32226 + 2388340.000000 19784.322266 @@ -1281,13 +1281,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2313364.75000 98278.92187 - 2313364.75000 98278.92187 + 2313364.750000 98278.921875 + 2313364.750000 98278.921875 - 2313364.75000 98278.92187 + 2313364.750000 98278.921875 @@ -1296,13 +1296,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2279399.00000 39858.00000 - 2279399.00000 39858.00000 + 2279399.000000 39858.000000 + 2279399.000000 39858.000000 - 2279399.00000 39858.00000 + 2279399.000000 39858.000000 @@ -1311,13 +1311,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2359906.50000 -30454.43554 - 2359906.50000 -30454.43554 + 2359906.500000 -30454.435547 + 2359906.500000 -30454.435547 - 2359906.50000 -30454.43554 + 2359906.500000 -30454.435547 @@ -1326,13 +1326,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2325561.75000 294362.25000 - 2325561.75000 294362.25000 + 2325561.750000 294362.250000 + 2325561.750000 294362.250000 - 2325561.75000 294362.25000 + 2325561.750000 294362.250000 @@ -1341,13 +1341,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2600377.00000 419421.71875 - 2600377.00000 419421.71875 + 2600377.000000 419421.718750 + 2600377.000000 419421.718750 - 2600377.00000 419421.71875 + 2600377.000000 419421.718750 @@ -1356,13 +1356,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2449341.50000 253906.09375 - 2449341.50000 253906.09375 + 2449341.500000 253906.093750 + 2449341.500000 253906.093750 - 2449341.50000 253906.09375 + 2449341.500000 253906.093750 @@ -1371,13 +1371,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2418051.50000 205002.20312 - 2418051.50000 205002.20312 + 2418051.500000 205002.203125 + 2418051.500000 205002.203125 - 2418051.50000 205002.20312 + 2418051.500000 205002.203125 @@ -1386,13 +1386,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2329295.75000 218397.28125 - 2329295.75000 218397.28125 + 2329295.750000 218397.281250 + 2329295.750000 218397.281250 - 2329295.75000 218397.28125 + 2329295.750000 218397.281250 @@ -1401,13 +1401,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2345781.25000 130999.54687 - 2345781.25000 130999.54687 + 2345781.250000 130999.546875 + 2345781.250000 130999.546875 - 2345781.25000 130999.54687 + 2345781.250000 130999.546875 @@ -1416,13 +1416,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2382666.75000 60910.93750 - 2382666.75000 60910.93750 + 2382666.750000 60910.937500 + 2382666.750000 60910.937500 - 2382666.75000 60910.93750 + 2382666.750000 60910.937500 @@ -1431,13 +1431,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2294923.75000 -55344.50390 - 2294923.75000 -55344.50390 + 2294923.750000 -55344.503906 + 2294923.750000 -55344.503906 - 2294923.75000 -55344.50390 + 2294923.750000 -55344.503906 @@ -1446,13 +1446,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2574240.00000 416102.34375 - 2574240.00000 416102.34375 + 2574240.000000 416102.343750 + 2574240.000000 416102.343750 - 2574240.00000 416102.34375 + 2574240.000000 416102.343750 @@ -1461,13 +1461,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2587598.00000 404010.53125 - 2587598.00000 404010.53125 + 2587598.000000 404010.531250 + 2587598.000000 404010.531250 - 2587598.00000 404010.53125 + 2587598.000000 404010.531250 @@ -1476,13 +1476,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2437026.00000 130358.35156 - 2437026.00000 130358.35156 + 2437026.000000 130358.351562 + 2437026.000000 130358.351562 - 2437026.00000 130358.35156 + 2437026.000000 130358.351562 @@ -1491,13 +1491,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2402416.50000 461586.81250 - 2402416.50000 461586.81250 + 2402416.500000 461586.812500 + 2402416.500000 461586.812500 - 2402416.50000 461586.81250 + 2402416.500000 461586.812500 @@ -1506,13 +1506,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2378567.25000 305099.78125 - 2378567.25000 305099.78125 + 2378567.250000 305099.781250 + 2378567.250000 305099.781250 - 2378567.25000 305099.78125 + 2378567.250000 305099.781250 @@ -1521,13 +1521,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2431943.75000 118985.38281 - 2431943.75000 118985.38281 + 2431943.750000 118985.382812 + 2431943.750000 118985.382812 - 2431943.75000 118985.38281 + 2431943.750000 118985.382812 diff --git a/msautotest/wxs/expected/wfsogr_200_multiplelayers_with_count.xml b/msautotest/wxs/expected/wfsogr_200_multiplelayers_with_count.xml index a79861e4f8..4ee93be277 100644 --- a/msautotest/wxs/expected/wfsogr_200_multiplelayers_with_count.xml +++ b/msautotest/wxs/expected/wfsogr_200_multiplelayers_with_count.xml @@ -11,29 +11,29 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 next="http://localhost/path/to/wfs_simple?SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAMES=road%2Cpopplace&COUNT=80&PROPERTYNAME=(ms%3AmsGeometry)(ms%3AmsGeometry)&STARTINDEX=80"> - 2258982.00000 -70747.91406 - 2615354.50000 495480.93750 + 2258982.000000 -70747.914062 + 2615354.500000 495480.937500 - 2258982.00000 -70747.91406 - 2615354.50000 495480.93750 + 2258982.000000 -70747.914062 + 2615354.500000 495480.937500 - 2577257.00000 402717.03125 - 2580978.50000 430271.18750 + 2577257.000000 402717.031250 + 2580978.500000 430271.187500 - 2577257.00000 430271.18750 2577292.00000 420127.65625 2577297.50000 418604.78125 2577491.75000 417462.90625 2578069.00000 415941.46875 2578836.50000 414230.25000 2579413.25000 412899.18750 2580247.50000 412070.84375 2580693.50000 411149.46875 2580978.50000 408984.37500 2580750.50000 407559.96875 2580066.75000 405736.68750 2579326.00000 403970.43750 2578927.50000 402717.03125 + 2577257.000000 430271.187500 2577292.000000 420127.656250 2577297.500000 418604.781250 2577491.750000 417462.906250 2578069.000000 415941.468750 2578836.500000 414230.250000 2579413.250000 412899.187500 2580247.500000 412070.843750 2580693.500000 411149.468750 2580978.500000 408984.375000 2580750.500000 407559.968750 2580066.750000 405736.687500 2579326.000000 403970.437500 2578927.500000 402717.031250 @@ -42,13 +42,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2423954.25000 261480.26562 - 2445811.25000 287380.78125 + 2423954.250000 261480.265625 + 2445811.250000 287380.781250 - 2442339.75000 261851.75000 2443533.00000 261480.26562 2444388.75000 261737.06250 2445267.75000 262263.75000 2445811.25000 263084.12500 2445806.75000 264416.75000 2445611.75000 265558.56250 2445226.75000 266699.68750 2444460.50000 268030.18750 2443695.00000 268980.00000 2442888.75000 269780.40625 2439266.25000 273433.68750 2423954.25000 287380.78125 + 2442339.750000 261851.750000 2443533.000000 261480.265625 2444388.750000 261737.062500 2445267.750000 262263.750000 2445811.250000 263084.125000 2445806.750000 264416.750000 2445611.750000 265558.562500 2445226.750000 266699.687500 2444460.500000 268030.187500 2443695.000000 268980.000000 2442888.750000 269780.406250 2439266.250000 273433.687500 2423954.250000 287380.781250 @@ -57,13 +57,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2295131.50000 -70747.91406 - 2300237.25000 -55210.80859 + 2295131.500000 -70747.914062 + 2300237.250000 -55210.808594 - 2295131.50000 -70747.91406 2296898.25000 -69277.78906 2297741.25000 -67368.82812 2299021.00000 -64632.40234 2299660.50000 -63264.00000 2299686.25000 -61199.98828 2300237.25000 -59070.42578 2299573.50000 -55210.80859 + 2295131.500000 -70747.914062 2296898.250000 -69277.789062 2297741.250000 -67368.828125 2299021.000000 -64632.402344 2299660.500000 -63264.000000 2299686.250000 -61199.988281 2300237.250000 -59070.425781 2299573.500000 -55210.808594 @@ -72,13 +72,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2401333.25000 456760.09375 - 2418412.00000 495480.93750 + 2401333.250000 456760.093750 + 2418412.000000 495480.937500 - 2416521.25000 486527.18750 2416899.25000 487862.03125 2417658.50000 489388.71875 2418036.75000 490533.00000 2418034.00000 491866.81250 2418412.00000 493582.68750 2417646.75000 494913.84375 2416312.00000 495480.93750 2415168.75000 495477.21875 2413836.75000 494710.87500 2412505.25000 493753.93750 2411364.00000 492797.62500 2410415.25000 490889.50000 2409656.75000 489362.81250 2408896.75000 488217.31250 2407947.50000 486880.59375 2407569.25000 485355.12500 2407000.75000 484019.65625 2406812.75000 482875.81250 2406056.00000 480206.09375 2405677.50000 479061.84375 2405490.75000 477346.59375 2404731.50000 475819.90625 2404926.25000 473724.87500 2405500.50000 472583.50000 2406835.00000 472206.81250 2407979.50000 471638.90625 2408744.75000 469926.75000 2408557.75000 468211.50000 2408370.25000 466877.25000 2408182.50000 465543.00000 2406852.25000 464014.46875 2405520.25000 463248.12500 2403997.25000 462671.56250 2402282.50000 462475.59375 2401333.25000 461138.90625 2401907.75000 459616.53125 2401910.50000 458282.90625 2402294.50000 456760.09375 + 2416521.250000 486527.187500 2416899.250000 487862.031250 2417658.500000 489388.718750 2418036.750000 490533.000000 2418034.000000 491866.812500 2418412.000000 493582.687500 2417646.750000 494913.843750 2416312.000000 495480.937500 2415168.750000 495477.218750 2413836.750000 494710.875000 2412505.250000 493753.937500 2411364.000000 492797.625000 2410415.250000 490889.500000 2409656.750000 489362.812500 2408896.750000 488217.312500 2407947.500000 486880.593750 2407569.250000 485355.125000 2407000.750000 484019.656250 2406812.750000 482875.812500 2406056.000000 480206.093750 2405677.500000 479061.843750 2405490.750000 477346.593750 2404731.500000 475819.906250 2404926.250000 473724.875000 2405500.500000 472583.500000 2406835.000000 472206.812500 2407979.500000 471638.906250 2408744.750000 469926.750000 2408557.750000 468211.500000 2408370.250000 466877.250000 2408182.500000 465543.000000 2406852.250000 464014.468750 2405520.250000 463248.125000 2403997.250000 462671.562500 2402282.500000 462475.593750 2401333.250000 461138.906250 2401907.750000 459616.531250 2401910.500000 458282.906250 2402294.500000 456760.093750 @@ -87,13 +87,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2402294.50000 456524.71875 - 2404001.25000 456760.09375 + 2402294.500000 456524.718750 + 2404001.250000 456760.093750 - 2402294.50000 456760.09375 2404001.25000 456524.71875 + 2402294.500000 456760.093750 2404001.250000 456524.718750 @@ -102,13 +102,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2401926.50000 439809.34375 - 2415274.25000 456760.09375 + 2401926.500000 439809.343750 + 2415274.250000 456760.093750 - 2402294.50000 456760.09375 2402488.25000 455236.50000 2402302.50000 452949.62500 2402305.00000 451806.59375 2401926.50000 450662.15625 2401930.50000 448756.90625 2401933.25000 447423.28125 2401937.25000 445518.25000 2401941.25000 443613.00000 2402325.25000 442090.03125 2403090.75000 440568.43750 2404045.25000 439809.34375 2405377.75000 440385.25000 2406710.00000 440961.18750 2407851.00000 441726.90625 2409183.75000 442112.25000 2410899.00000 442117.81250 2412422.25000 442503.75000 2413564.50000 442888.46875 2414897.00000 443464.40625 2415274.25000 445180.28125 + 2402294.500000 456760.093750 2402488.250000 455236.500000 2402302.500000 452949.625000 2402305.000000 451806.593750 2401926.500000 450662.156250 2401930.500000 448756.906250 2401933.250000 447423.281250 2401937.250000 445518.250000 2401941.250000 443613.000000 2402325.250000 442090.031250 2403090.750000 440568.437500 2404045.250000 439809.343750 2405377.750000 440385.250000 2406710.000000 440961.187500 2407851.000000 441726.906250 2409183.750000 442112.250000 2410899.000000 442117.812500 2412422.250000 442503.750000 2413564.500000 442888.468750 2414897.000000 443464.406250 2415274.250000 445180.281250 @@ -117,13 +117,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2506675.50000 382184.31250 - 2552279.50000 459945.18750 + 2506675.500000 382184.312500 + 2552279.500000 459945.187500 - 2517327.25000 382184.31250 2516878.00000 383523.06250 2516875.75000 384666.09375 2516490.75000 386570.09375 2515149.25000 390376.06250 2514765.25000 391899.03125 2514380.50000 393422.03125 2513805.75000 395134.81250 2513421.25000 396848.21875 2513037.25000 397990.00000 2512080.75000 400082.75000 2510934.50000 401603.09375 2510170.00000 402553.21875 2509024.50000 403692.71875 2508066.75000 405975.87500 2507300.75000 408069.06250 2507486.75000 410165.34375 2508055.00000 411691.40625 2508432.00000 413788.28125 2508809.00000 415694.75000 2508806.50000 416837.78125 2508613.25000 418170.78125 2508036.25000 420645.78125 2508033.25000 421979.40625 2508031.00000 423122.43750 2508028.50000 424265.65625 2507834.50000 425979.65625 2507259.25000 427883.03125 2506682.50000 430167.43750 2506679.75000 431501.06250 2506675.50000 433596.71875 2507051.00000 436455.78125 2507809.75000 437791.87500 2509139.75000 439510.84375 2510280.25000 440848.15625 2511227.75000 443327.90625 2511225.00000 444661.71875 2511411.50000 446567.37500 2512744.25000 446952.71875 2513886.75000 447337.62500 2515217.50000 448675.56250 2516358.75000 449631.87500 2517308.00000 451349.62500 2518257.25000 452686.31250 2519017.50000 453641.40625 2520157.50000 455169.15625 2522057.50000 457461.56250 2522817.25000 458797.65625 2524148.50000 459945.18750 2525673.25000 459568.93750 2527007.25000 459382.84375 2529103.75000 458818.03125 2530819.25000 458633.18750 2533296.75000 458260.03125 2535964.50000 458078.25000 2537108.50000 457700.93750 2538253.00000 456752.03125 2539209.75000 454849.87500 2539787.00000 452375.09375 2539980.00000 451042.06250 2539985.00000 448755.81250 2539991.25000 445707.37500 2540185.00000 444183.96875 2540379.00000 442469.93750 2540954.50000 440375.96875 2541338.75000 439043.56250 2542865.00000 438095.90625 2544203.00000 436004.56250 2544779.75000 433339.18750 2545355.25000 431626.37500 2546125.00000 427818.40625 2546896.75000 423248.37500 2546713.25000 420009.09375 2546906.50000 418676.06250 2546911.25000 416389.84375 2547488.00000 413724.43750 2547683.25000 411438.81250 2548260.50000 408963.81250 2548646.50000 406488.40625 2548840.75000 404583.78125 2548845.50000 402297.53125 2548851.25000 399630.28125 2548855.50000 397534.65625 2548858.50000 396201.03125 2549624.00000 394679.28125 2550387.50000 393729.12500 2551024.00000 392901.12500 2552279.50000 391797.40625 + 2517327.250000 382184.312500 2516878.000000 383523.062500 2516875.750000 384666.093750 2516490.750000 386570.093750 2515149.250000 390376.062500 2514765.250000 391899.031250 2514380.500000 393422.031250 2513805.750000 395134.812500 2513421.250000 396848.218750 2513037.250000 397990.000000 2512080.750000 400082.750000 2510934.500000 401603.093750 2510170.000000 402553.218750 2509024.500000 403692.718750 2508066.750000 405975.875000 2507300.750000 408069.062500 2507486.750000 410165.343750 2508055.000000 411691.406250 2508432.000000 413788.281250 2508809.000000 415694.750000 2508806.500000 416837.781250 2508613.250000 418170.781250 2508036.250000 420645.781250 2508033.250000 421979.406250 2508031.000000 423122.437500 2508028.500000 424265.656250 2507834.500000 425979.656250 2507259.250000 427883.031250 2506682.500000 430167.437500 2506679.750000 431501.062500 2506675.500000 433596.718750 2507051.000000 436455.781250 2507809.750000 437791.875000 2509139.750000 439510.843750 2510280.250000 440848.156250 2511227.750000 443327.906250 2511225.000000 444661.718750 2511411.500000 446567.375000 2512744.250000 446952.718750 2513886.750000 447337.625000 2515217.500000 448675.562500 2516358.750000 449631.875000 2517308.000000 451349.625000 2518257.250000 452686.312500 2519017.500000 453641.406250 2520157.500000 455169.156250 2522057.500000 457461.562500 2522817.250000 458797.656250 2524148.500000 459945.187500 2525673.250000 459568.937500 2527007.250000 459382.843750 2529103.750000 458818.031250 2530819.250000 458633.187500 2533296.750000 458260.031250 2535964.500000 458078.250000 2537108.500000 457700.937500 2538253.000000 456752.031250 2539209.750000 454849.875000 2539787.000000 452375.093750 2539980.000000 451042.062500 2539985.000000 448755.812500 2539991.250000 445707.375000 2540185.000000 444183.968750 2540379.000000 442469.937500 2540954.500000 440375.968750 2541338.750000 439043.562500 2542865.000000 438095.906250 2544203.000000 436004.562500 2544779.750000 433339.187500 2545355.250000 431626.375000 2546125.000000 427818.406250 2546896.750000 423248.375000 2546713.250000 420009.093750 2546906.500000 418676.062500 2546911.250000 416389.843750 2547488.000000 413724.437500 2547683.250000 411438.812500 2548260.500000 408963.812500 2548646.500000 406488.406250 2548840.750000 404583.781250 2548845.500000 402297.531250 2548851.250000 399630.281250 2548855.500000 397534.656250 2548858.500000 396201.031250 2549624.000000 394679.281250 2550387.500000 393729.125000 2551024.000000 392901.125000 2552279.500000 391797.406250 @@ -132,13 +132,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2517327.25000 373668.78125 - 2544336.75000 386026.87500 + 2517327.250000 373668.781250 + 2544336.750000 386026.875000 - 2544336.75000 373668.78125 2542807.50000 374652.65625 2540709.00000 375788.90625 2538231.00000 376352.46875 2536136.50000 375964.65625 2534230.25000 376339.50000 2532511.00000 378620.18750 2532125.25000 380905.18750 2531359.00000 382807.78125 2530025.00000 382994.06250 2528501.25000 382798.53125 2526975.25000 383746.18750 2526400.25000 385268.56250 2525255.25000 386026.87500 2522399.75000 385065.00000 2521070.50000 382965.03125 2519167.75000 382006.25000 2517327.25000 382184.31250 + 2544336.750000 373668.781250 2542807.500000 374652.656250 2540709.000000 375788.906250 2538231.000000 376352.468750 2536136.500000 375964.656250 2534230.250000 376339.500000 2532511.000000 378620.187500 2532125.250000 380905.187500 2531359.000000 382807.781250 2530025.000000 382994.062500 2528501.250000 382798.531250 2526975.250000 383746.187500 2526400.250000 385268.562500 2525255.250000 386026.875000 2522399.750000 385065.000000 2521070.500000 382965.031250 2519167.750000 382006.250000 2517327.250000 382184.312500 @@ -147,13 +147,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2431184.75000 343694.18750 - 2437876.25000 344935.53125 + 2431184.750000 343694.187500 + 2437876.250000 344935.531250 - 2437876.25000 343694.18750 2436853.50000 344316.53125 2435151.25000 344742.09375 2433603.50000 344935.53125 2432210.75000 344858.15625 2431184.75000 344694.00000 + 2437876.250000 343694.187500 2436853.500000 344316.531250 2435151.250000 344742.093750 2433603.500000 344935.531250 2432210.750000 344858.156250 2431184.750000 344694.000000 @@ -162,13 +162,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2408896.25000 336154.03125 - 2438448.25000 355446.78125 + 2408896.250000 336154.031250 + 2438448.250000 355446.781250 - 2408896.25000 336154.03125 2409331.50000 337640.15625 2410470.00000 339930.12500 2412561.75000 341651.53125 2413894.50000 342036.87500 2415417.00000 342804.00000 2417130.00000 343762.00000 2418653.25000 344148.12500 2420745.75000 345488.56250 2422839.50000 346638.37500 2424171.75000 347214.31250 2425501.75000 348933.25000 2427023.50000 350081.21875 2428165.50000 350656.53125 2429115.50000 351993.25000 2431969.50000 353717.15625 2433492.75000 354103.28125 2435396.00000 354871.46875 2436538.00000 355446.78125 2438062.75000 355070.53125 2438448.25000 353166.71875 2438069.25000 352022.28125 2437882.00000 350497.62500 2436362.25000 348396.84375 2435411.50000 347441.15625 2434078.75000 347055.81250 2433128.25000 346290.71875 2432177.00000 345525.59375 2431184.75000 344694.00000 + 2408896.250000 336154.031250 2409331.500000 337640.156250 2410470.000000 339930.125000 2412561.750000 341651.531250 2413894.500000 342036.875000 2415417.000000 342804.000000 2417130.000000 343762.000000 2418653.250000 344148.125000 2420745.750000 345488.562500 2422839.500000 346638.375000 2424171.750000 347214.312500 2425501.750000 348933.250000 2427023.500000 350081.218750 2428165.500000 350656.531250 2429115.500000 351993.250000 2431969.500000 353717.156250 2433492.750000 354103.281250 2435396.000000 354871.468750 2436538.000000 355446.781250 2438062.750000 355070.531250 2438448.250000 353166.718750 2438069.250000 352022.281250 2437882.000000 350497.625000 2436362.250000 348396.843750 2435411.500000 347441.156250 2434078.750000 347055.812500 2433128.250000 346290.718750 2432177.000000 345525.593750 2431184.750000 344694.000000 @@ -177,13 +177,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2408896.25000 335937.25000 - 2431184.75000 344694.00000 + 2408896.250000 335937.250000 + 2431184.750000 344694.000000 - 2431184.75000 344694.00000 2429895.50000 343231.93750 2428945.75000 342085.65625 2428376.25000 340940.78125 2427617.50000 339604.65625 2426286.25000 338457.12500 2424572.50000 337689.56250 2423239.50000 337494.65625 2420763.00000 337296.18750 2418668.50000 336908.40625 2417145.00000 336712.87500 2415240.00000 336325.68750 2414097.25000 336131.37500 2412954.50000 335937.25000 2410096.50000 336118.40625 2408896.25000 336154.03125 + 2431184.750000 344694.000000 2429895.500000 343231.937500 2428945.750000 342085.656250 2428376.250000 340940.781250 2427617.500000 339604.656250 2426286.250000 338457.125000 2424572.500000 337689.562500 2423239.500000 337494.656250 2420763.000000 337296.187500 2418668.500000 336908.406250 2417145.000000 336712.875000 2415240.000000 336325.687500 2414097.250000 336131.375000 2412954.500000 335937.250000 2410096.500000 336118.406250 2408896.250000 336154.031250 @@ -192,13 +192,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2555956.25000 315523.56250 - 2586390.25000 399880.53125 + 2555956.250000 315523.562500 + 2586390.250000 399880.531250 - 2555956.25000 315523.56250 2557409.00000 316400.68750 2558548.50000 317738.00000 2559307.25000 319455.28125 2560447.75000 320792.62500 2561206.25000 322700.15625 2561963.75000 324607.84375 2563484.25000 326327.40625 2565386.50000 327857.81250 2567480.75000 328436.21875 2568768.25000 329139.84375 2569741.50000 329663.06250 2570767.00000 329725.84375 2572054.00000 329830.50000 2573519.00000 330207.18750 2574180.00000 330852.25000 2574523.00000 331888.31250 2574899.50000 333985.21875 2575086.00000 335891.03125 2575272.50000 337796.90625 2575078.75000 339320.34375 2575075.25000 341035.15625 2575071.50000 342749.78125 2575069.25000 343892.81250 2575251.25000 347894.31250 2575627.25000 350181.75000 2575815.50000 351516.03125 2576003.50000 352659.84375 2576571.00000 354566.96875 2577898.75000 357238.50000 2578466.50000 359336.03125 2579413.75000 361625.34375 2580170.00000 364485.46875 2581117.00000 367155.96875 2582252.25000 370779.40625 2582820.25000 372686.50000 2582999.00000 378212.18750 2582994.25000 380498.43750 2582990.25000 382403.62500 2583559.50000 383739.15625 2584317.50000 385456.25000 2585076.00000 387173.31250 2585644.25000 388699.43750 2585641.00000 390223.46875 2586018.00000 391939.31250 2586204.75000 394226.21875 2586390.25000 396513.09375 2586388.25000 397656.31250 2586194.75000 398989.28125 2585757.50000 399880.53125 + 2555956.250000 315523.562500 2557409.000000 316400.687500 2558548.500000 317738.000000 2559307.250000 319455.281250 2560447.750000 320792.625000 2561206.250000 322700.156250 2561963.750000 324607.843750 2563484.250000 326327.406250 2565386.500000 327857.812500 2567480.750000 328436.218750 2568768.250000 329139.843750 2569741.500000 329663.062500 2570767.000000 329725.843750 2572054.000000 329830.500000 2573519.000000 330207.187500 2574180.000000 330852.250000 2574523.000000 331888.312500 2574899.500000 333985.218750 2575086.000000 335891.031250 2575272.500000 337796.906250 2575078.750000 339320.343750 2575075.250000 341035.156250 2575071.500000 342749.781250 2575069.250000 343892.812500 2575251.250000 347894.312500 2575627.250000 350181.750000 2575815.500000 351516.031250 2576003.500000 352659.843750 2576571.000000 354566.968750 2577898.750000 357238.500000 2578466.500000 359336.031250 2579413.750000 361625.343750 2580170.000000 364485.468750 2581117.000000 367155.968750 2582252.250000 370779.406250 2582820.250000 372686.500000 2582999.000000 378212.187500 2582994.250000 380498.437500 2582990.250000 382403.625000 2583559.500000 383739.156250 2584317.500000 385456.250000 2585076.000000 387173.312500 2585644.250000 388699.437500 2585641.000000 390223.468750 2586018.000000 391939.312500 2586204.750000 394226.218750 2586390.250000 396513.093750 2586388.250000 397656.312500 2586194.750000 398989.281250 2585757.500000 399880.531250 @@ -207,13 +207,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2508781.25000 310448.28125 - 2532595.25000 382184.31250 + 2508781.250000 310448.281250 + 2532595.250000 382184.312500 - 2517327.25000 382184.31250 2515168.75000 381040.65625 2514026.75000 380465.34375 2513458.00000 379320.46875 2511174.25000 377979.43750 2510604.75000 376834.37500 2509472.75000 371496.15625 2509480.75000 367685.87500 2509678.25000 364638.25000 2510064.25000 362162.62500 2510259.75000 359686.59375 2510646.25000 357020.56250 2511031.75000 355116.59375 2511607.75000 352832.18750 2511992.75000 350928.18750 2512187.50000 349214.18750 2512000.25000 347308.31250 2511623.00000 345592.46875 2510674.50000 343493.71875 2510105.75000 342348.65625 2509347.00000 340631.56250 2508969.00000 339296.68750 2508781.25000 337962.43750 2508785.00000 336247.81250 2509171.00000 333772.21875 2511651.25000 332065.59375 2513751.75000 329976.75000 2514897.25000 328837.25000 2516044.25000 326745.28125 2517382.50000 324463.37500 2517958.25000 322750.59375 2519487.00000 320469.28125 2521587.75000 318189.84375 2522925.00000 316479.53125 2524260.50000 315531.21875 2525024.50000 314390.65625 2526551.75000 312871.37500 2527887.00000 312113.68750 2530175.75000 310977.87500 2532595.25000 310448.28125 + 2517327.250000 382184.312500 2515168.750000 381040.656250 2514026.750000 380465.343750 2513458.000000 379320.468750 2511174.250000 377979.437500 2510604.750000 376834.375000 2509472.750000 371496.156250 2509480.750000 367685.875000 2509678.250000 364638.250000 2510064.250000 362162.625000 2510259.750000 359686.593750 2510646.250000 357020.562500 2511031.750000 355116.593750 2511607.750000 352832.187500 2511992.750000 350928.187500 2512187.500000 349214.187500 2512000.250000 347308.312500 2511623.000000 345592.468750 2510674.500000 343493.718750 2510105.750000 342348.656250 2509347.000000 340631.562500 2508969.000000 339296.687500 2508781.250000 337962.437500 2508785.000000 336247.812500 2509171.000000 333772.218750 2511651.250000 332065.593750 2513751.750000 329976.750000 2514897.250000 328837.250000 2516044.250000 326745.281250 2517382.500000 324463.375000 2517958.250000 322750.593750 2519487.000000 320469.281250 2521587.750000 318189.843750 2522925.000000 316479.531250 2524260.500000 315531.218750 2525024.500000 314390.656250 2526551.750000 312871.375000 2527887.000000 312113.687500 2530175.750000 310977.875000 2532595.250000 310448.281250 @@ -222,13 +222,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2532595.25000 309490.28125 - 2555956.25000 315523.56250 + 2532595.250000 309490.281250 + 2555956.250000 315523.562500 - 2532595.25000 310448.28125 2533607.00000 310226.96875 2538370.25000 309861.40625 2539894.25000 309866.34375 2541420.00000 309490.28125 2542752.75000 309875.59375 2545418.25000 310646.25000 2546273.00000 310984.06250 2547009.25000 311585.68750 2547395.50000 311944.90625 2547880.50000 312268.15625 2548437.25000 312420.81250 2549011.75000 312681.25000 2549498.25000 312881.78125 2551697.75000 314095.90625 2553983.00000 314674.93750 2555505.75000 315251.46875 2555956.25000 315523.56250 + 2532595.250000 310448.281250 2533607.000000 310226.968750 2538370.250000 309861.406250 2539894.250000 309866.343750 2541420.000000 309490.281250 2542752.750000 309875.593750 2545418.250000 310646.250000 2546273.000000 310984.062500 2547009.250000 311585.687500 2547395.500000 311944.906250 2547880.500000 312268.156250 2548437.250000 312420.812500 2549011.750000 312681.250000 2549498.250000 312881.781250 2551697.750000 314095.906250 2553983.000000 314674.937500 2555505.750000 315251.468750 2555956.250000 315523.562500 @@ -237,13 +237,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2555956.25000 305943.78125 - 2568929.50000 315523.56250 + 2555956.250000 305943.781250 + 2568929.500000 315523.562500 - 2555956.25000 315523.56250 2558366.25000 313927.09375 2559130.50000 312976.96875 2560465.75000 312219.25000 2561799.75000 312032.96875 2562943.00000 312036.68750 2564087.25000 311468.78125 2565421.75000 311092.09375 2566239.50000 311290.40625 2566802.25000 311605.59375 2567556.25000 311515.53125 2568164.25000 311177.84375 2568772.00000 310547.50000 2568929.50000 309534.46875 2568817.00000 308622.71875 2568749.25000 307497.06250 2568738.25000 305943.78125 + 2555956.250000 315523.562500 2558366.250000 313927.093750 2559130.500000 312976.968750 2560465.750000 312219.250000 2561799.750000 312032.968750 2562943.000000 312036.687500 2564087.250000 311468.781250 2565421.750000 311092.093750 2566239.500000 311290.406250 2566802.250000 311605.593750 2567556.250000 311515.531250 2568164.250000 311177.843750 2568772.000000 310547.500000 2568929.500000 309534.468750 2568817.000000 308622.718750 2568749.250000 307497.062500 2568738.250000 305943.781250 @@ -252,13 +252,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2398316.25000 301857.34375 - 2423674.50000 313088.59375 + 2398316.250000 301857.343750 + 2423674.500000 313088.593750 - 2423674.50000 311966.37500 2423485.75000 310822.75000 2422344.50000 310247.43750 2420630.00000 309860.87500 2419294.00000 310999.56250 2418720.50000 312140.93750 2417194.50000 313088.59375 2415289.25000 312891.84375 2414338.00000 312126.71875 2412815.50000 311359.59375 2410913.25000 310210.37500 2409391.00000 309252.84375 2408060.00000 308105.46875 2406157.50000 306575.09375 2404445.50000 305426.50000 2403303.00000 305041.59375 2401591.00000 303893.00000 2400067.75000 303507.06250 2399401.50000 303113.96875 2398880.50000 302657.03125 2398316.25000 301857.34375 + 2423674.500000 311966.375000 2423485.750000 310822.750000 2422344.500000 310247.437500 2420630.000000 309860.875000 2419294.000000 310999.562500 2418720.500000 312140.937500 2417194.500000 313088.593750 2415289.250000 312891.843750 2414338.000000 312126.718750 2412815.500000 311359.593750 2410913.250000 310210.375000 2409391.000000 309252.843750 2408060.000000 308105.468750 2406157.500000 306575.093750 2404445.500000 305426.500000 2403303.000000 305041.593750 2401591.000000 303893.000000 2400067.750000 303507.062500 2399401.500000 303113.968750 2398880.500000 302657.031250 2398316.250000 301857.343750 @@ -267,13 +267,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2380836.00000 301084.96875 - 2408896.25000 336154.03125 + 2380836.000000 301084.968750 + 2408896.250000 336154.031250 - 2380836.00000 301084.96875 2381396.50000 303827.56250 2381774.50000 305162.43750 2382723.25000 307070.75000 2383482.50000 308216.25000 2384812.50000 309935.21875 2386906.00000 311085.21875 2388238.50000 311661.12500 2389760.25000 312809.09375 2390329.00000 313954.15625 2391089.25000 314909.06250 2391467.50000 316243.93750 2391845.50000 317578.78125 2392413.50000 319485.87500 2392980.75000 321392.96875 2393738.75000 323491.09375 2394687.00000 325590.00000 2396969.00000 327312.03125 2398492.75000 327888.59375 2400204.75000 329037.18750 2401918.25000 329423.75000 2403061.50000 329427.43750 2404204.25000 329621.75000 2405916.75000 330579.90625 2406867.25000 331726.03125 2408005.50000 334015.96875 2408764.50000 335352.06250 2408896.25000 336154.03125 + 2380836.000000 301084.968750 2381396.500000 303827.562500 2381774.500000 305162.437500 2382723.250000 307070.750000 2383482.500000 308216.250000 2384812.500000 309935.218750 2386906.000000 311085.218750 2388238.500000 311661.125000 2389760.250000 312809.093750 2390329.000000 313954.156250 2391089.250000 314909.062500 2391467.500000 316243.937500 2391845.500000 317578.781250 2392413.500000 319485.875000 2392980.750000 321392.968750 2393738.750000 323491.093750 2394687.000000 325590.000000 2396969.000000 327312.031250 2398492.750000 327888.593750 2400204.750000 329037.187500 2401918.250000 329423.750000 2403061.500000 329427.437500 2404204.250000 329621.750000 2405916.750000 330579.906250 2406867.250000 331726.031250 2408005.500000 334015.968750 2408764.500000 335352.062500 2408896.250000 336154.031250 @@ -282,13 +282,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2338814.75000 297360.06250 - 2375060.75000 300923.40625 + 2338814.750000 297360.062500 + 2375060.750000 300923.406250 - 2338814.75000 297360.06250 2340636.75000 298360.93750 2342160.00000 298746.90625 2343492.75000 299132.21875 2345778.50000 299520.65625 2347302.00000 299716.18750 2348826.00000 299721.12500 2351683.25000 299920.78125 2353207.50000 299925.71875 2354541.00000 299930.06250 2357017.50000 300128.68750 2358923.00000 300134.84375 2360827.75000 300141.03125 2362161.50000 300145.34375 2363685.00000 300340.87500 2365399.00000 300536.84375 2367113.50000 300923.40625 2368828.25000 300738.56250 2370162.00000 300742.87500 2371306.00000 300365.56250 2374167.25000 298660.03125 2375060.75000 298175.34375 + 2338814.750000 297360.062500 2340636.750000 298360.937500 2342160.000000 298746.906250 2343492.750000 299132.218750 2345778.500000 299520.656250 2347302.000000 299716.187500 2348826.000000 299721.125000 2351683.250000 299920.781250 2353207.500000 299925.718750 2354541.000000 299930.062500 2357017.500000 300128.687500 2358923.000000 300134.843750 2360827.750000 300141.031250 2362161.500000 300145.343750 2363685.000000 300340.875000 2365399.000000 300536.843750 2367113.500000 300923.406250 2368828.250000 300738.562500 2370162.000000 300742.875000 2371306.000000 300365.562500 2374167.250000 298660.031250 2375060.750000 298175.343750 @@ -297,13 +297,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2328808.00000 297360.06250 - 2376921.25000 310977.15625 + 2328808.000000 297360.062500 + 2376921.250000 310977.156250 - 2338814.75000 297360.06250 2337206.50000 298730.84375 2336062.50000 299108.15625 2334345.50000 300245.81250 2333200.75000 301004.12500 2331102.75000 302330.93750 2329958.25000 302898.84375 2328811.25000 304800.18750 2328808.00000 306324.40625 2329948.25000 307661.75000 2331091.25000 307856.06250 2332233.25000 308050.15625 2333376.50000 308053.87500 2334520.00000 307867.15625 2336046.75000 306538.46875 2337192.75000 305208.56250 2337957.25000 304258.40625 2339102.50000 303309.50000 2340245.75000 302932.18750 2342722.50000 302940.21875 2344055.00000 303515.96875 2345959.00000 304284.34375 2347290.50000 305241.28125 2350142.25000 308108.21875 2350900.50000 310015.90625 2351851.00000 310781.00000 2353565.75000 310977.15625 2355283.50000 309458.50000 2356047.50000 308317.93750 2357381.75000 307941.25000 2359477.75000 307948.03125 2361573.50000 308145.25000 2362716.00000 308148.93750 2364240.75000 308153.90625 2365382.75000 308348.18750 2367668.00000 308927.21875 2369189.50000 310075.18750 2370906.00000 309509.12500 2372240.25000 309132.43750 2373386.00000 307993.12500 2374150.75000 306471.37500 2374915.25000 305521.21875 2376255.25000 302477.28125 2376921.25000 301464.28125 + 2338814.750000 297360.062500 2337206.500000 298730.843750 2336062.500000 299108.156250 2334345.500000 300245.812500 2333200.750000 301004.125000 2331102.750000 302330.937500 2329958.250000 302898.843750 2328811.250000 304800.187500 2328808.000000 306324.406250 2329948.250000 307661.750000 2331091.250000 307856.062500 2332233.250000 308050.156250 2333376.500000 308053.875000 2334520.000000 307867.156250 2336046.750000 306538.468750 2337192.750000 305208.562500 2337957.250000 304258.406250 2339102.500000 303309.500000 2340245.750000 302932.187500 2342722.500000 302940.218750 2344055.000000 303515.968750 2345959.000000 304284.343750 2347290.500000 305241.281250 2350142.250000 308108.218750 2350900.500000 310015.906250 2351851.000000 310781.000000 2353565.750000 310977.156250 2355283.500000 309458.500000 2356047.500000 308317.937500 2357381.750000 307941.250000 2359477.750000 307948.031250 2361573.500000 308145.250000 2362716.000000 308148.937500 2364240.750000 308153.906250 2365382.750000 308348.187500 2367668.000000 308927.218750 2369189.500000 310075.187500 2370906.000000 309509.125000 2372240.250000 309132.437500 2373386.000000 307993.125000 2374150.750000 306471.375000 2374915.250000 305521.218750 2376255.250000 302477.281250 2376921.250000 301464.281250 @@ -312,13 +312,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2528707.75000 292187.53125 - 2552125.25000 302480.75000 + 2528707.750000 292187.531250 + 2552125.250000 302480.750000 - 2528707.75000 302480.75000 2529201.50000 302131.09375 2530768.75000 300691.71875 2532485.50000 299935.28125 2533628.50000 299938.96875 2534771.00000 299942.68750 2537059.50000 298997.46875 2538586.00000 297859.18750 2540302.25000 297293.34375 2541445.75000 297106.43750 2542779.50000 297110.75000 2544303.50000 297115.68750 2545827.50000 297120.62500 2547733.25000 296745.81250 2549448.75000 296560.78125 2550592.50000 295993.03125 2551166.75000 294851.68750 2552125.25000 292187.53125 + 2528707.750000 302480.750000 2529201.500000 302131.093750 2530768.750000 300691.718750 2532485.500000 299935.281250 2533628.500000 299938.968750 2534771.000000 299942.687500 2537059.500000 298997.468750 2538586.000000 297859.187500 2540302.250000 297293.343750 2541445.750000 297106.437500 2542779.500000 297110.750000 2544303.500000 297115.687500 2545827.500000 297120.625000 2547733.250000 296745.812500 2549448.750000 296560.781250 2550592.500000 295993.031250 2551166.750000 294851.687500 2552125.250000 292187.531250 @@ -327,13 +327,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2332620.50000 290752.21875 - 2338814.75000 297360.06250 + 2332620.500000 290752.218750 + 2338814.750000 297360.062500 - 2332620.50000 290752.21875 2334361.50000 292625.06250 2335544.75000 294394.87500 2337211.50000 296254.18750 2338814.75000 297360.06250 + 2332620.500000 290752.218750 2334361.500000 292625.062500 2335544.750000 294394.875000 2337211.500000 296254.187500 2338814.750000 297360.062500 @@ -342,13 +342,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2280156.00000 287223.68750 - 2332620.50000 339507.81250 + 2280156.000000 287223.687500 + 2332620.500000 339507.812500 - 2280156.00000 339507.81250 2281118.00000 335129.03125 2281694.00000 332844.62500 2282081.25000 330178.62500 2282465.25000 328655.62500 2282658.00000 327513.21875 2283042.00000 325990.21875 2283044.75000 324656.59375 2283049.25000 322560.93750 2282863.25000 320464.50000 2282866.50000 318940.46875 2282870.75000 316844.62500 2283449.50000 313607.81250 2283834.25000 311703.81250 2284218.75000 309990.40625 2284794.00000 308468.06250 2285368.25000 306945.68750 2286705.50000 305235.37500 2288231.25000 304478.28125 2289566.50000 303720.59375 2290900.50000 303534.31250 2293186.75000 303541.71875 2295091.75000 303547.87500 2296615.75000 303552.84375 2297950.00000 303557.15625 2299665.75000 302991.09375 2300809.75000 302613.81250 2302145.75000 301475.09375 2303671.25000 300717.81250 2304819.00000 298625.87500 2305202.50000 297293.50000 2305777.00000 295771.12500 2306351.75000 294439.34375 2307116.50000 292917.78125 2308837.00000 290446.50000 2309982.50000 289307.15625 2312272.25000 287409.34375 2313796.50000 287223.68750 2315129.50000 287609.18750 2316271.75000 287993.90625 2318367.00000 288381.71875 2319890.25000 288767.65625 2321032.50000 289152.37500 2324079.75000 289543.28125 2326175.75000 289550.06250 2328047.00000 290928.65625 2329952.75000 290934.56250 2331477.25000 290748.65625 2332620.50000 290752.21875 + 2280156.000000 339507.812500 2281118.000000 335129.031250 2281694.000000 332844.625000 2282081.250000 330178.625000 2282465.250000 328655.625000 2282658.000000 327513.218750 2283042.000000 325990.218750 2283044.750000 324656.593750 2283049.250000 322560.937500 2282863.250000 320464.500000 2282866.500000 318940.468750 2282870.750000 316844.625000 2283449.500000 313607.812500 2283834.250000 311703.812500 2284218.750000 309990.406250 2284794.000000 308468.062500 2285368.250000 306945.687500 2286705.500000 305235.375000 2288231.250000 304478.281250 2289566.500000 303720.593750 2290900.500000 303534.312500 2293186.750000 303541.718750 2295091.750000 303547.875000 2296615.750000 303552.843750 2297950.000000 303557.156250 2299665.750000 302991.093750 2300809.750000 302613.812500 2302145.750000 301475.093750 2303671.250000 300717.812500 2304819.000000 298625.875000 2305202.500000 297293.500000 2305777.000000 295771.125000 2306351.750000 294439.343750 2307116.500000 292917.781250 2308837.000000 290446.500000 2309982.500000 289307.156250 2312272.250000 287409.343750 2313796.500000 287223.687500 2315129.500000 287609.187500 2316271.750000 287993.906250 2318367.000000 288381.718750 2319890.250000 288767.656250 2321032.500000 289152.375000 2324079.750000 289543.281250 2326175.750000 289550.062500 2328047.000000 290928.656250 2329952.750000 290934.562500 2331477.250000 290748.656250 2332620.500000 290752.218750 @@ -357,13 +357,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2332620.50000 282176.75000 - 2347757.75000 290759.31250 + 2332620.500000 282176.750000 + 2347757.750000 290759.312500 - 2332620.50000 290752.21875 2333763.00000 290755.75000 2334906.25000 290759.31250 2336432.75000 289620.78125 2337578.00000 288671.50000 2338724.00000 287341.15625 2339867.75000 287154.06250 2341201.50000 287158.18750 2342534.75000 287352.96875 2344059.25000 287167.06250 2345394.50000 286409.03125 2347305.75000 283747.12500 2347757.75000 282176.75000 + 2332620.500000 290752.218750 2333763.000000 290755.750000 2334906.250000 290759.312500 2336432.750000 289620.781250 2337578.000000 288671.500000 2338724.000000 287341.156250 2339867.750000 287154.062500 2341201.500000 287158.187500 2342534.750000 287352.968750 2344059.250000 287167.062500 2345394.500000 286409.031250 2347305.750000 283747.125000 2347757.750000 282176.750000 @@ -372,13 +372,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2517059.75000 273309.50000 - 2580137.75000 291146.93750 + 2517059.750000 273309.500000 + 2580137.750000 291146.937500 - 2517059.75000 291146.93750 2518215.75000 290744.00000 2520694.00000 289990.00000 2522791.00000 289234.78125 2524125.75000 288667.50000 2525080.00000 287908.37500 2526987.75000 286962.12500 2528514.00000 285823.84375 2529850.50000 284494.53125 2531188.00000 282593.62500 2532335.75000 280501.68750 2534815.75000 278604.46875 2536725.25000 276705.43750 2539014.50000 275379.21875 2540921.00000 274623.34375 2543018.25000 274058.53125 2544352.25000 273872.43750 2547020.50000 273309.50000 2548544.75000 273314.43750 2551021.00000 273513.06250 2552163.50000 273897.75000 2553493.75000 275426.12500 2554252.75000 276762.21875 2556537.25000 277722.25000 2557679.50000 278107.15625 2559583.50000 278494.31250 2561488.25000 278881.50000 2562630.25000 279456.81250 2563580.00000 280602.93750 2564338.75000 282320.03125 2566241.25000 283469.43750 2567574.00000 283854.75000 2569097.75000 284050.12500 2570241.25000 283863.40625 2572145.75000 284441.18750 2574429.75000 285210.62500 2575572.25000 285595.31250 2576714.50000 285980.03125 2580137.75000 289230.03125 + 2517059.750000 291146.937500 2518215.750000 290744.000000 2520694.000000 289990.000000 2522791.000000 289234.781250 2524125.750000 288667.500000 2525080.000000 287908.375000 2526987.750000 286962.125000 2528514.000000 285823.843750 2529850.500000 284494.531250 2531188.000000 282593.625000 2532335.750000 280501.687500 2534815.750000 278604.468750 2536725.250000 276705.437500 2539014.500000 275379.218750 2540921.000000 274623.343750 2543018.250000 274058.531250 2544352.250000 273872.437500 2547020.500000 273309.500000 2548544.750000 273314.437500 2551021.000000 273513.062500 2552163.500000 273897.750000 2553493.750000 275426.125000 2554252.750000 276762.218750 2556537.250000 277722.250000 2557679.500000 278107.156250 2559583.500000 278494.312500 2561488.250000 278881.500000 2562630.250000 279456.812500 2563580.000000 280602.937500 2564338.750000 282320.031250 2566241.250000 283469.437500 2567574.000000 283854.750000 2569097.750000 284050.125000 2570241.250000 283863.406250 2572145.750000 284441.187500 2574429.750000 285210.625000 2575572.250000 285595.312500 2576714.500000 285980.031250 2580137.750000 289230.031250 @@ -387,13 +387,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2442115.25000 261851.75000 - 2442339.75000 262496.84375 + 2442115.250000 261851.750000 + 2442339.750000 262496.843750 - 2442115.25000 262496.84375 2442339.75000 261851.75000 + 2442115.250000 262496.843750 2442339.750000 261851.750000 @@ -402,13 +402,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2327897.50000 213607.48437 - 2442115.25000 262496.84375 + 2327897.500000 213607.484375 + 2442115.250000 262496.843750 - 2327897.50000 213607.48437 2329379.25000 215448.14062 2332040.50000 218314.60937 2333372.50000 219080.95312 2335275.25000 220420.75000 2336985.00000 222712.54687 2337361.75000 224619.01562 2337359.00000 225952.65625 2337355.75000 227476.87500 2338306.00000 228622.98437 2339637.75000 229579.92187 2341159.75000 230537.48437 2342302.25000 230922.18750 2343634.25000 231688.53125 2344777.50000 231692.23437 2346110.50000 231887.17187 2347634.25000 232082.51562 2348967.00000 232468.03125 2350680.25000 233045.00000 2351822.00000 233810.90625 2353725.75000 234579.09375 2354676.00000 235534.79687 2356200.00000 235539.75000 2357725.00000 235354.09375 2359058.75000 235358.40625 2360964.25000 234983.57812 2362679.25000 234798.71875 2364202.75000 234994.07812 2366488.75000 235192.07812 2367630.00000 236148.39062 2369724.75000 236726.60937 2371438.50000 237113.17187 2373915.00000 237311.81250 2375630.00000 236936.35937 2378297.75000 236754.39062 2381154.25000 237335.26562 2384010.25000 238106.54687 2387058.25000 238497.43750 2388391.75000 238501.75000 2390487.75000 238127.51562 2392775.50000 237563.51562 2394683.50000 236426.46875 2396209.00000 235669.40625 2397542.75000 235673.71875 2399827.25000 236252.71875 2401920.75000 237402.56250 2404199.25000 241220.43750 2404957.25000 242937.51562 2406668.75000 244657.73437 2408001.25000 245233.65625 2409904.50000 246001.84375 2411236.50000 246768.17187 2413899.25000 248872.65625 2415038.50000 250781.40625 2417318.50000 253837.28125 2418649.25000 255175.21875 2420171.50000 256132.59375 2420931.00000 257087.68750 2422262.75000 258044.62500 2423594.75000 258811.15625 2424927.50000 259196.48437 2426451.50000 259582.42187 2427593.50000 259776.54687 2429498.75000 259973.31250 2430041.50000 259975.06250 2432773.00000 259909.00000 2435971.00000 260275.43750 2438502.75000 261041.62500 2440601.50000 261841.12500 2442115.25000 262496.84375 + 2327897.500000 213607.484375 2329379.250000 215448.140625 2332040.500000 218314.609375 2333372.500000 219080.953125 2335275.250000 220420.750000 2336985.000000 222712.546875 2337361.750000 224619.015625 2337359.000000 225952.656250 2337355.750000 227476.875000 2338306.000000 228622.984375 2339637.750000 229579.921875 2341159.750000 230537.484375 2342302.250000 230922.187500 2343634.250000 231688.531250 2344777.500000 231692.234375 2346110.500000 231887.171875 2347634.250000 232082.515625 2348967.000000 232468.031250 2350680.250000 233045.000000 2351822.000000 233810.906250 2353725.750000 234579.093750 2354676.000000 235534.796875 2356200.000000 235539.750000 2357725.000000 235354.093750 2359058.750000 235358.406250 2360964.250000 234983.578125 2362679.250000 234798.718750 2364202.750000 234994.078125 2366488.750000 235192.078125 2367630.000000 236148.390625 2369724.750000 236726.609375 2371438.500000 237113.171875 2373915.000000 237311.812500 2375630.000000 236936.359375 2378297.750000 236754.390625 2381154.250000 237335.265625 2384010.250000 238106.546875 2387058.250000 238497.437500 2388391.750000 238501.750000 2390487.750000 238127.515625 2392775.500000 237563.515625 2394683.500000 236426.468750 2396209.000000 235669.406250 2397542.750000 235673.718750 2399827.250000 236252.718750 2401920.750000 237402.562500 2404199.250000 241220.437500 2404957.250000 242937.515625 2406668.750000 244657.734375 2408001.250000 245233.656250 2409904.500000 246001.843750 2411236.500000 246768.171875 2413899.250000 248872.656250 2415038.500000 250781.406250 2417318.500000 253837.281250 2418649.250000 255175.218750 2420171.500000 256132.593750 2420931.000000 257087.687500 2422262.750000 258044.625000 2423594.750000 258811.156250 2424927.500000 259196.484375 2426451.500000 259582.421875 2427593.500000 259776.546875 2429498.750000 259973.312500 2430041.500000 259975.062500 2432773.000000 259909.000000 2435971.000000 260275.437500 2438502.750000 261041.625000 2440601.500000 261841.125000 2442115.250000 262496.843750 @@ -417,13 +417,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2337062.75000 171673.95312 - 2399226.25000 211882.15625 + 2337062.750000 171673.953125 + 2399226.250000 211882.156250 - 2346585.25000 211882.15625 2346725.25000 211122.42187 2346919.75000 209217.79687 2347114.00000 207694.35937 2347498.00000 206171.37500 2348263.25000 204459.21875 2348838.00000 203127.46875 2349222.50000 201414.06250 2349227.75000 198937.23437 2349611.25000 197604.81250 2349045.25000 195126.31250 2347712.75000 194550.40625 2345808.50000 194353.60937 2344094.75000 193586.03125 2342001.50000 192626.60937 2341050.50000 191861.53125 2339909.50000 190714.60937 2339150.00000 189378.51562 2337820.75000 187278.56250 2337062.75000 185561.42187 2337066.00000 184037.21875 2337069.50000 182322.57812 2337264.75000 180036.96875 2337649.25000 178323.54687 2338034.25000 176610.15625 2338418.00000 175277.76562 2339181.50000 174327.62500 2339946.75000 172996.45312 2341663.50000 171858.79687 2343379.00000 171673.95312 2344521.50000 171677.64062 2345854.00000 172634.59375 2347564.75000 174354.79687 2348706.25000 175120.50000 2350417.50000 176650.29687 2352320.00000 177799.48437 2353842.75000 178757.04687 2355745.00000 180096.82812 2356887.00000 180672.15625 2358029.25000 181056.85937 2359361.75000 181632.81250 2361074.50000 182400.37500 2362598.25000 182595.89062 2364121.50000 182981.85937 2366217.50000 182988.62500 2368121.00000 183566.42187 2369454.25000 183761.15625 2372121.50000 183769.81250 2373645.50000 184155.75000 2374787.00000 184540.46875 2376119.50000 185116.39062 2377447.50000 187787.96875 2378396.25000 189696.29687 2379726.00000 191605.84375 2380866.25000 192943.17187 2383531.50000 193904.43750 2385626.00000 194673.25000 2387720.50000 195061.04687 2388863.75000 195064.75000 2390577.75000 195260.92187 2392863.25000 195649.34375 2394766.00000 196989.12500 2396287.75000 198137.09375 2398377.50000 200811.14062 2399226.25000 201743.82812 + 2346585.250000 211882.156250 2346725.250000 211122.421875 2346919.750000 209217.796875 2347114.000000 207694.359375 2347498.000000 206171.375000 2348263.250000 204459.218750 2348838.000000 203127.468750 2349222.500000 201414.062500 2349227.750000 198937.234375 2349611.250000 197604.812500 2349045.250000 195126.312500 2347712.750000 194550.406250 2345808.500000 194353.609375 2344094.750000 193586.031250 2342001.500000 192626.609375 2341050.500000 191861.531250 2339909.500000 190714.609375 2339150.000000 189378.515625 2337820.750000 187278.562500 2337062.750000 185561.421875 2337066.000000 184037.218750 2337069.500000 182322.578125 2337264.750000 180036.968750 2337649.250000 178323.546875 2338034.250000 176610.156250 2338418.000000 175277.765625 2339181.500000 174327.625000 2339946.750000 172996.453125 2341663.500000 171858.796875 2343379.000000 171673.953125 2344521.500000 171677.640625 2345854.000000 172634.593750 2347564.750000 174354.796875 2348706.250000 175120.500000 2350417.500000 176650.296875 2352320.000000 177799.484375 2353842.750000 178757.046875 2355745.000000 180096.828125 2356887.000000 180672.156250 2358029.250000 181056.859375 2359361.750000 181632.812500 2361074.500000 182400.375000 2362598.250000 182595.890625 2364121.500000 182981.859375 2366217.500000 182988.625000 2368121.000000 183566.421875 2369454.250000 183761.156250 2372121.500000 183769.812500 2373645.500000 184155.750000 2374787.000000 184540.468750 2376119.500000 185116.390625 2377447.500000 187787.968750 2378396.250000 189696.296875 2379726.000000 191605.843750 2380866.250000 192943.171875 2383531.500000 193904.437500 2385626.000000 194673.250000 2387720.500000 195061.046875 2388863.750000 195064.750000 2390577.750000 195260.921875 2392863.250000 195649.343750 2394766.000000 196989.125000 2396287.750000 198137.093750 2398377.500000 200811.140625 2399226.250000 201743.828125 @@ -432,13 +432,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2437545.00000 127024.38281 - 2524818.25000 276774.43750 + 2437545.000000 127024.382812 + 2524818.250000 276774.437500 - 2437545.00000 127024.38281 2437751.25000 127577.96093 2438700.50000 129295.90625 2439648.75000 131204.50000 2440598.25000 132732.00000 2441738.00000 134450.54687 2442686.50000 136549.59375 2443634.25000 138648.65625 2444773.00000 140748.45312 2447245.50000 142852.25000 2448959.25000 143238.67187 2450674.50000 143243.98437 2452007.00000 143819.85937 2453905.25000 147065.32812 2454473.25000 148591.45312 2454661.75000 149925.95312 2454467.00000 151640.54687 2455036.50000 152785.57812 2456748.00000 154315.45312 2458459.50000 155654.68750 2459982.50000 156612.23437 2462265.75000 157762.60937 2464171.00000 157959.15625 2466646.75000 158538.40625 2468360.50000 158924.79687 2469884.00000 159310.82812 2471788.25000 159888.28125 2473312.50000 159893.01562 2474262.25000 161039.42187 2475403.75000 161805.15625 2476542.25000 164095.45312 2477492.50000 165432.31250 2478631.25000 167531.93750 2480721.50000 170015.82812 2482625.25000 170974.54687 2483768.00000 171168.54687 2485101.00000 171553.78125 2486244.25000 171557.32812 2488527.50000 172707.87500 2489477.25000 174235.37500 2491185.25000 177289.60937 2492325.50000 178817.53125 2493276.25000 179773.31250 2494989.25000 180541.00000 2495557.50000 182257.76562 2495934.75000 183973.95312 2495931.25000 185688.93750 2495929.00000 186832.40625 2496686.50000 188740.21875 2497446.25000 190076.50000 2498967.25000 191605.78125 2500108.50000 192562.14062 2501250.50000 193137.40625 2502964.50000 193333.17187 2504486.75000 194290.75000 2505818.50000 195247.71875 2506577.75000 196774.62500 2507526.00000 198873.65625 2508285.50000 200019.31250 2509235.00000 201546.79687 2509803.25000 203073.14062 2510372.25000 204408.79687 2512082.00000 206700.67187 2513794.25000 207849.46875 2514937.00000 208043.64062 2515888.25000 208808.78125 2517028.50000 210336.70312 2517787.75000 211482.50000 2518356.50000 213008.62500 2519874.75000 215871.81250 2521209.00000 215494.87500 2522543.25000 215308.39062 2523874.00000 216646.42187 2523900.50000 217450.32812 2523922.50000 218405.50000 2524469.00000 219255.85937 2524818.25000 220841.75000 2524815.25000 222175.67187 2524621.00000 224080.70312 2524046.50000 225222.21875 2523473.00000 226363.87500 2522898.50000 227505.37500 2522514.25000 229219.18750 2521940.00000 230551.31250 2521746.25000 231884.81250 2521172.00000 233216.93750 2520597.25000 234930.15625 2519642.00000 236070.48437 2518306.75000 236828.53125 2517163.00000 237015.60937 2516018.75000 237583.79687 2514873.50000 238533.06250 2513537.00000 239862.82812 2512772.75000 241003.73437 2511818.00000 241953.59375 2510862.00000 243475.17187 2510098.00000 244616.07812 2509142.25000 245947.03125 2508187.00000 247087.53125 2507804.00000 248229.62500 2507228.75000 249752.39062 2506652.25000 252227.78125 2506458.25000 253942.20312 2506265.00000 255275.50000 2505880.75000 256608.23437 2505306.75000 257940.35937 2504350.75000 259461.95312 2502062.00000 260788.78125 2500344.75000 261736.23437 2499389.50000 263257.84375 2498812.00000 265923.87500 2498617.50000 267828.75000 2498424.25000 269162.06250 2498041.25000 270304.34375 2497847.25000 271637.65625 2497844.75000 272780.90625 2497841.50000 274305.46875 2497925.50000 276774.43750 + 2437545.000000 127024.382812 2437751.250000 127577.960938 2438700.500000 129295.906250 2439648.750000 131204.500000 2440598.250000 132732.000000 2441738.000000 134450.546875 2442686.500000 136549.593750 2443634.250000 138648.656250 2444773.000000 140748.453125 2447245.500000 142852.250000 2448959.250000 143238.671875 2450674.500000 143243.984375 2452007.000000 143819.859375 2453905.250000 147065.328125 2454473.250000 148591.453125 2454661.750000 149925.953125 2454467.000000 151640.546875 2455036.500000 152785.578125 2456748.000000 154315.453125 2458459.500000 155654.687500 2459982.500000 156612.234375 2462265.750000 157762.609375 2464171.000000 157959.156250 2466646.750000 158538.406250 2468360.500000 158924.796875 2469884.000000 159310.828125 2471788.250000 159888.281250 2473312.500000 159893.015625 2474262.250000 161039.421875 2475403.750000 161805.156250 2476542.250000 164095.453125 2477492.500000 165432.312500 2478631.250000 167531.937500 2480721.500000 170015.828125 2482625.250000 170974.546875 2483768.000000 171168.546875 2485101.000000 171553.781250 2486244.250000 171557.328125 2488527.500000 172707.875000 2489477.250000 174235.375000 2491185.250000 177289.609375 2492325.500000 178817.531250 2493276.250000 179773.312500 2494989.250000 180541.000000 2495557.500000 182257.765625 2495934.750000 183973.953125 2495931.250000 185688.937500 2495929.000000 186832.406250 2496686.500000 188740.218750 2497446.250000 190076.500000 2498967.250000 191605.781250 2500108.500000 192562.140625 2501250.500000 193137.406250 2502964.500000 193333.171875 2504486.750000 194290.750000 2505818.500000 195247.718750 2506577.750000 196774.625000 2507526.000000 198873.656250 2508285.500000 200019.312500 2509235.000000 201546.796875 2509803.250000 203073.140625 2510372.250000 204408.796875 2512082.000000 206700.671875 2513794.250000 207849.468750 2514937.000000 208043.640625 2515888.250000 208808.781250 2517028.500000 210336.703125 2517787.750000 211482.500000 2518356.500000 213008.625000 2519874.750000 215871.812500 2521209.000000 215494.875000 2522543.250000 215308.390625 2523874.000000 216646.421875 2523900.500000 217450.328125 2523922.500000 218405.500000 2524469.000000 219255.859375 2524818.250000 220841.750000 2524815.250000 222175.671875 2524621.000000 224080.703125 2524046.500000 225222.218750 2523473.000000 226363.875000 2522898.500000 227505.375000 2522514.250000 229219.187500 2521940.000000 230551.312500 2521746.250000 231884.812500 2521172.000000 233216.937500 2520597.250000 234930.156250 2519642.000000 236070.484375 2518306.750000 236828.531250 2517163.000000 237015.609375 2516018.750000 237583.796875 2514873.500000 238533.062500 2513537.000000 239862.828125 2512772.750000 241003.734375 2511818.000000 241953.593750 2510862.000000 243475.171875 2510098.000000 244616.078125 2509142.250000 245947.031250 2508187.000000 247087.531250 2507804.000000 248229.625000 2507228.750000 249752.390625 2506652.250000 252227.781250 2506458.250000 253942.203125 2506265.000000 255275.500000 2505880.750000 256608.234375 2505306.750000 257940.359375 2504350.750000 259461.953125 2502062.000000 260788.781250 2500344.750000 261736.234375 2499389.500000 263257.843750 2498812.000000 265923.875000 2498617.500000 267828.750000 2498424.250000 269162.062500 2498041.250000 270304.343750 2497847.250000 271637.656250 2497844.750000 272780.906250 2497841.500000 274305.468750 2497925.500000 276774.437500 @@ -447,13 +447,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2426724.50000 126601.03125 - 2427983.00000 136722.43750 + 2426724.500000 126601.031250 + 2427983.000000 136722.437500 - 2427983.00000 136722.43750 2427856.00000 135556.64062 2427667.75000 134413.15625 2427289.00000 133268.90625 2427293.25000 131173.50000 2426724.50000 129457.31250 2426918.25000 127743.47656 2427111.00000 126601.03125 + 2427983.000000 136722.437500 2427856.000000 135556.640625 2427667.750000 134413.156250 2427289.000000 133268.906250 2427293.250000 131173.500000 2426724.500000 129457.312500 2426918.250000 127743.476562 2427111.000000 126601.031250 @@ -462,13 +462,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2346510.25000 87612.88281 - 2386412.75000 128063.53125 + 2346510.250000 87612.882812 + 2386412.750000 128063.531250 - 2346510.25000 128063.53125 2347096.25000 125008.59375 2347099.00000 123674.96875 2347103.00000 121769.71093 2348444.25000 118154.17187 2349976.50000 114539.24218 2351697.00000 111686.95312 2353796.50000 109598.10937 2355708.25000 106746.43750 2356854.50000 105226.09375 2358001.00000 103705.56250 2360291.75000 101236.32812 2361437.00000 100287.42187 2363915.75000 99342.82812 2366012.50000 98968.61718 2368490.00000 98405.03125 2370395.75000 98220.78906 2372301.50000 97845.75781 2374208.25000 97280.51562 2375923.50000 96904.87500 2377448.25000 96528.80468 2379546.00000 95773.59375 2380500.25000 95014.65625 2381265.25000 93492.89062 2381649.50000 91779.49218 2382414.25000 90638.74218 2386412.75000 87612.88281 + 2346510.250000 128063.531250 2347096.250000 125008.593750 2347099.000000 123674.968750 2347103.000000 121769.710938 2348444.250000 118154.171875 2349976.500000 114539.242188 2351697.000000 111686.953125 2353796.500000 109598.109375 2355708.250000 106746.437500 2356854.500000 105226.093750 2358001.000000 103705.562500 2360291.750000 101236.328125 2361437.000000 100287.421875 2363915.750000 99342.828125 2366012.500000 98968.617188 2368490.000000 98405.031250 2370395.750000 98220.789062 2372301.500000 97845.757812 2374208.250000 97280.515625 2375923.500000 96904.875000 2377448.250000 96528.804688 2379546.000000 95773.593750 2380500.250000 95014.656250 2381265.250000 93492.890625 2381649.500000 91779.492188 2382414.250000 90638.742188 2386412.750000 87612.882812 @@ -477,13 +477,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2312654.00000 64738.70312 - 2381693.75000 98427.06250 + 2312654.000000 64738.703125 + 2381693.750000 98427.062500 - 2312654.00000 97478.49218 2316478.50000 98427.06250 2317813.50000 97859.78125 2319529.00000 97293.73437 2320673.75000 96535.42187 2321443.00000 93299.04687 2321829.00000 90823.60937 2322408.25000 87396.00781 2323365.75000 84731.84375 2323940.50000 83400.07812 2325468.25000 81690.38281 2327185.75000 80171.71875 2329475.75000 78464.49218 2331763.75000 77709.88281 2334813.75000 76767.13281 2336529.50000 76201.07031 2337673.50000 75823.77343 2339961.50000 75069.17187 2341676.25000 74884.13281 2343011.25000 74317.02343 2344919.00000 73179.99218 2346445.25000 72232.30468 2348351.50000 71476.45312 2350067.50000 71101.03125 2352926.00000 70729.24218 2355594.00000 70356.72656 2357118.50000 70171.23437 2359214.50000 69797.01562 2360548.00000 69801.32031 2361881.75000 69805.67968 2363596.50000 70001.63281 2365691.75000 70008.41406 2367025.25000 70012.75000 2368549.75000 69827.28906 2369693.75000 69449.98437 2371791.75000 68504.14062 2372556.25000 67554.00781 2374653.00000 66798.57812 2376560.50000 65852.31250 2378657.00000 65287.51953 2381693.75000 64738.70312 + 2312654.000000 97478.492188 2316478.500000 98427.062500 2317813.500000 97859.781250 2319529.000000 97293.734375 2320673.750000 96535.421875 2321443.000000 93299.046875 2321829.000000 90823.609375 2322408.250000 87396.007812 2323365.750000 84731.843750 2323940.500000 83400.078125 2325468.250000 81690.382812 2327185.750000 80171.718750 2329475.750000 78464.492188 2331763.750000 77709.882812 2334813.750000 76767.132812 2336529.500000 76201.070312 2337673.500000 75823.773438 2339961.500000 75069.171875 2341676.250000 74884.132812 2343011.250000 74317.023438 2344919.000000 73179.992188 2346445.250000 72232.304688 2348351.500000 71476.453125 2350067.500000 71101.031250 2352926.000000 70729.242188 2355594.000000 70356.726562 2357118.500000 70171.234375 2359214.500000 69797.015625 2360548.000000 69801.320312 2361881.750000 69805.679688 2363596.500000 70001.632812 2365691.750000 70008.414062 2367025.250000 70012.750000 2368549.750000 69827.289062 2369693.750000 69449.984375 2371791.750000 68504.140625 2372556.250000 67554.007812 2374653.000000 66798.578125 2376560.500000 65852.312500 2378657.000000 65287.519531 2381693.750000 64738.703125 @@ -492,13 +492,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2280279.75000 34889.78515 - 2281886.75000 40764.59375 + 2280279.750000 34889.785156 + 2281886.750000 40764.593750 - 2280710.50000 34889.78515 2280279.75000 36437.48046 2280385.50000 37863.45312 2280649.50000 39078.17968 2281886.75000 40764.59375 + 2280710.500000 34889.785156 2280279.750000 36437.480469 2280385.500000 37863.453125 2280649.500000 39078.179688 2281886.750000 40764.593750 @@ -507,13 +507,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2280710.50000 33374.88281 - 2281531.25000 34889.78515 + 2280710.500000 33374.882812 + 2281531.250000 34889.785156 - 2281531.25000 33374.88281 2281204.00000 34140.06640 2280710.50000 34889.78515 + 2281531.250000 33374.882812 2281204.000000 34140.066406 2280710.500000 34889.785156 @@ -522,13 +522,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2297238.50000 16173.98535 - 2385409.75000 57395.59765 + 2297238.500000 16173.985352 + 2385409.750000 57395.597656 - 2297238.50000 57395.59765 2300567.50000 54365.34765 2302093.75000 53227.11328 2304002.25000 51899.64843 2306291.50000 50192.41796 2308009.50000 48864.35156 2309917.00000 47536.90625 2311252.25000 46779.17187 2312588.75000 45449.88281 2313924.25000 44501.58984 2316213.25000 43365.79687 2318308.75000 43182.17968 2319642.75000 42995.91406 2320976.50000 43000.22656 2323072.00000 43197.62109 2324977.50000 43203.79296 2326692.00000 43209.32031 2328979.25000 42835.56640 2330314.50000 42077.85156 2331841.75000 40558.73828 2333366.75000 39992.10546 2334891.00000 39997.03515 2337178.00000 39623.42578 2339465.00000 39059.22265 2340800.25000 38301.54296 2342134.50000 37924.65234 2343659.00000 38120.19140 2345182.50000 38315.71875 2346513.75000 39463.07031 2348607.00000 40422.48437 2350131.50000 40618.02343 2351465.00000 40622.35546 2353179.75000 40437.30078 2354706.75000 39108.61718 2355092.00000 37014.21093 2355285.00000 35681.18750 2356621.00000 34542.31250 2357955.50000 34165.64062 2359480.25000 34170.56640 2361767.50000 33415.96093 2362727.00000 30180.16015 2364064.75000 28279.26757 2365781.25000 27332.19140 2367305.50000 27146.71093 2368639.50000 26960.46093 2370547.50000 25823.59960 2373220.00000 23355.38476 2374746.50000 22217.31640 2376273.50000 20698.02539 2378374.50000 18418.58398 2379138.00000 17468.43945 2380664.00000 16901.94726 2382379.25000 16526.32421 2385409.75000 16173.98535 + 2297238.500000 57395.597656 2300567.500000 54365.347656 2302093.750000 53227.113281 2304002.250000 51899.648438 2306291.500000 50192.417969 2308009.500000 48864.351562 2309917.000000 47536.906250 2311252.250000 46779.171875 2312588.750000 45449.882812 2313924.250000 44501.589844 2316213.250000 43365.796875 2318308.750000 43182.179688 2319642.750000 42995.914062 2320976.500000 43000.226562 2323072.000000 43197.621094 2324977.500000 43203.792969 2326692.000000 43209.320312 2328979.250000 42835.566406 2330314.500000 42077.851562 2331841.750000 40558.738281 2333366.750000 39992.105469 2334891.000000 39997.035156 2337178.000000 39623.425781 2339465.000000 39059.222656 2340800.250000 38301.542969 2342134.500000 37924.652344 2343659.000000 38120.191406 2345182.500000 38315.718750 2346513.750000 39463.070312 2348607.000000 40422.484375 2350131.500000 40618.023438 2351465.000000 40622.355469 2353179.750000 40437.300781 2354706.750000 39108.617188 2355092.000000 37014.210938 2355285.000000 35681.187500 2356621.000000 34542.312500 2357955.500000 34165.640625 2359480.250000 34170.566406 2361767.500000 33415.960938 2362727.000000 30180.160156 2364064.750000 28279.267578 2365781.250000 27332.191406 2367305.500000 27146.710938 2368639.500000 26960.460938 2370547.500000 25823.599609 2373220.000000 23355.384766 2374746.500000 22217.316406 2376273.500000 20698.025391 2378374.500000 18418.583984 2379138.000000 17468.439453 2380664.000000 16901.947266 2382379.250000 16526.324219 2385409.750000 16173.985352 @@ -537,13 +537,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2261430.50000 1845.39770 - 2280710.50000 34889.78515 + 2261430.500000 1845.397705 + 2280710.500000 34889.785156 - 2280710.50000 34889.78515 2278700.25000 34289.77734 2277367.00000 34095.06640 2275273.50000 32945.04296 2273560.25000 32367.90429 2271657.50000 31028.10156 2270706.25000 30262.99414 2269185.00000 28924.43164 2267664.25000 27395.26757 2266717.00000 24724.93359 2266150.50000 22436.80664 2265203.00000 19957.07031 2264825.25000 18431.61132 2264069.50000 15380.88964 2263694.25000 12712.42578 2263316.00000 11377.55468 2262749.25000 8899.05175 2262562.00000 7374.19482 2262183.75000 6229.76904 2261995.75000 5086.12451 2261430.50000 1845.39770 + 2280710.500000 34889.785156 2278700.250000 34289.777344 2277367.000000 34095.066406 2275273.500000 32945.042969 2273560.250000 32367.904297 2271657.500000 31028.101562 2270706.250000 30262.994141 2269185.000000 28924.431641 2267664.250000 27395.267578 2266717.000000 24724.933594 2266150.500000 22436.806641 2265203.000000 19957.070312 2264825.250000 18431.611328 2264069.500000 15380.889648 2263694.250000 12712.425781 2263316.000000 11377.554688 2262749.250000 8899.051758 2262562.000000 7374.194824 2262183.750000 6229.769043 2261995.750000 5086.124512 2261430.500000 1845.397705 @@ -552,13 +552,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2258982.00000 -14356.11718 - 2259545.50000 -2543.89502 + 2258982.000000 -14356.117188 + 2259545.500000 -2543.895020 - 2259154.00000 -2543.89502 2259346.75000 -3686.32788 2259540.50000 -5209.93164 2259545.50000 -7686.76123 2259169.25000 -9783.65234 2258982.00000 -11308.47558 2259178.75000 -14356.11718 + 2259154.000000 -2543.895020 2259346.750000 -3686.327881 2259540.500000 -5209.931641 2259545.500000 -7686.761230 2259169.250000 -9783.652344 2258982.000000 -11308.475586 2259178.750000 -14356.117188 @@ -567,13 +567,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2589745.50000 402556.25000 - 2602011.00000 419927.96875 + 2589745.500000 402556.250000 + 2602011.000000 419927.968750 - 2602011.00000 419927.96875 2600927.75000 415340.90625 2599981.50000 414005.78125 2598846.50000 412099.00000 2597898.00000 411144.59375 2596571.25000 409618.21875 2595434.25000 408282.59375 2594485.00000 407518.46875 2593157.25000 406182.31250 2591640.50000 404655.46875 2589745.50000 402556.25000 + 2602011.000000 419927.968750 2600927.750000 415340.906250 2599981.500000 414005.781250 2598846.500000 412099.000000 2597898.000000 411144.593750 2596571.250000 409618.218750 2595434.250000 408282.593750 2594485.000000 407518.468750 2593157.250000 406182.312500 2591640.500000 404655.468750 2589745.500000 402556.250000 @@ -582,13 +582,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2441167.25000 262496.84375 - 2442115.25000 265226.75000 + 2441167.250000 262496.843750 + 2442115.250000 265226.750000 - 2441167.25000 265226.75000 2442115.25000 262496.84375 + 2441167.250000 265226.750000 2442115.250000 262496.843750 @@ -597,13 +597,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2346510.25000 126601.03125 - 2427111.00000 138697.98437 + 2346510.250000 126601.031250 + 2427111.000000 138697.984375 - 2346510.25000 128063.53125 2347651.75000 128638.64062 2349365.25000 129596.50000 2351078.50000 130363.75781 2352602.00000 130749.49218 2353744.00000 131324.59375 2354695.25000 132280.04687 2356027.50000 133046.15625 2357548.50000 134574.93750 2358881.25000 135150.65625 2360404.00000 135917.34375 2361545.75000 136682.82812 2363258.50000 137640.67187 2364782.00000 138026.40625 2366115.75000 138030.57812 2368022.75000 137465.18750 2369168.75000 136135.29687 2370695.75000 134616.03125 2373365.00000 133862.45312 2374509.00000 133484.89062 2376034.00000 133108.68750 2377749.00000 132923.65625 2380034.75000 133311.78125 2381367.50000 133887.46875 2382891.00000 134273.18750 2384223.50000 134848.89062 2385366.25000 135233.42187 2387078.50000 136381.67187 2389173.25000 137150.14062 2390696.75000 137536.04687 2392220.25000 137921.76562 2394124.75000 138499.09375 2395267.50000 138502.67187 2396792.00000 138697.98437 2399079.00000 138133.59375 2400794.00000 138329.53125 2401937.00000 138142.53125 2403463.50000 137385.37500 2404798.25000 136818.03125 2406705.25000 135871.46875 2408422.25000 134733.95312 2409948.25000 133786.21875 2411092.00000 133599.21875 2412426.00000 133413.00000 2413569.75000 133226.01562 2415095.25000 132659.42187 2417383.00000 132095.03125 2418717.00000 131908.64062 2420244.25000 130389.53906 2421771.75000 128679.90625 2423489.00000 127732.77343 2425968.00000 126788.03125 2427111.00000 126601.03125 + 2346510.250000 128063.531250 2347651.750000 128638.640625 2349365.250000 129596.500000 2351078.500000 130363.757812 2352602.000000 130749.492188 2353744.000000 131324.593750 2354695.250000 132280.046875 2356027.500000 133046.156250 2357548.500000 134574.937500 2358881.250000 135150.656250 2360404.000000 135917.343750 2361545.750000 136682.828125 2363258.500000 137640.671875 2364782.000000 138026.406250 2366115.750000 138030.578125 2368022.750000 137465.187500 2369168.750000 136135.296875 2370695.750000 134616.031250 2373365.000000 133862.453125 2374509.000000 133484.890625 2376034.000000 133108.687500 2377749.000000 132923.656250 2380034.750000 133311.781250 2381367.500000 133887.468750 2382891.000000 134273.187500 2384223.500000 134848.890625 2385366.250000 135233.421875 2387078.500000 136381.671875 2389173.250000 137150.140625 2390696.750000 137536.046875 2392220.250000 137921.765625 2394124.750000 138499.093750 2395267.500000 138502.671875 2396792.000000 138697.984375 2399079.000000 138133.593750 2400794.000000 138329.531250 2401937.000000 138142.531250 2403463.500000 137385.375000 2404798.250000 136818.031250 2406705.250000 135871.468750 2408422.250000 134733.953125 2409948.250000 133786.218750 2411092.000000 133599.218750 2412426.000000 133413.000000 2413569.750000 133226.015625 2415095.250000 132659.421875 2417383.000000 132095.031250 2418717.000000 131908.640625 2420244.250000 130389.539062 2421771.750000 128679.906250 2423489.000000 127732.773438 2425968.000000 126788.031250 2427111.000000 126601.031250 @@ -612,13 +612,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2427111.00000 120844.14843 - 2429025.75000 126601.03125 + 2427111.000000 120844.148438 + 2429025.750000 126601.031250 - 2427111.00000 126601.03125 2427686.00000 125078.96093 2428642.00000 123557.92187 2429025.75000 122035.10156 2428879.25000 120844.14843 + 2427111.000000 126601.031250 2427686.000000 125078.960938 2428642.000000 123557.921875 2429025.750000 122035.101562 2428879.250000 120844.148438 @@ -627,13 +627,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2312654.00000 97478.49218 - 2346510.25000 128063.53125 + 2312654.000000 97478.492188 + 2346510.250000 128063.531250 - 2312654.00000 97478.49218 2314362.25000 100722.28125 2315882.00000 103012.99218 2317021.25000 105111.95312 2318161.25000 106829.93750 2318729.50000 108355.74218 2319871.00000 109311.79687 2320820.50000 111029.20312 2321580.00000 112555.59375 2322911.75000 113512.27343 2324243.50000 114659.32031 2325384.75000 115615.39062 2326144.25000 116760.64843 2326713.50000 118286.46093 2327282.50000 119431.10937 2328042.75000 120576.56250 2328992.50000 121722.43750 2330133.75000 122869.07031 2332038.25000 123446.54687 2333942.25000 124023.86718 2336227.50000 124793.09375 2337940.25000 125750.77343 2339273.25000 126136.10156 2341177.25000 126713.38281 2343463.00000 127101.50781 2344796.00000 127486.81250 2346510.25000 128063.53125 + 2312654.000000 97478.492188 2314362.250000 100722.281250 2315882.000000 103012.992188 2317021.250000 105111.953125 2318161.250000 106829.937500 2318729.500000 108355.742188 2319871.000000 109311.796875 2320820.500000 111029.203125 2321580.000000 112555.593750 2322911.750000 113512.273438 2324243.500000 114659.320312 2325384.750000 115615.390625 2326144.250000 116760.648438 2326713.500000 118286.460938 2327282.500000 119431.109375 2328042.750000 120576.562500 2328992.500000 121722.437500 2330133.750000 122869.070312 2332038.250000 123446.546875 2333942.250000 124023.867188 2336227.500000 124793.093750 2337940.250000 125750.773438 2339273.250000 126136.101562 2341177.250000 126713.382812 2343463.000000 127101.507812 2344796.000000 127486.812500 2346510.250000 128063.531250 @@ -642,13 +642,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2386412.75000 87612.88281 - 2428879.25000 120844.14843 + 2386412.750000 87612.882812 + 2428879.250000 120844.148438 - 2428879.25000 120844.14843 2428079.00000 118984.25000 2426936.75000 118409.14062 2425794.50000 117834.21093 2424461.00000 117639.47656 2422364.50000 118204.45312 2421030.25000 118390.67187 2419315.25000 118575.89843 2418172.00000 118572.29687 2416267.25000 117994.84375 2414934.00000 117800.25781 2413791.75000 117225.17968 2411888.25000 116457.28125 2409795.25000 114736.14062 2408462.50000 114160.61718 2406942.25000 112250.86718 2405801.00000 111104.40625 2404850.50000 110339.32812 2403327.25000 109382.09375 2401996.50000 107854.06250 2400665.50000 106516.46093 2399715.50000 105370.40625 2399336.25000 104226.34375 2398388.00000 102127.78906 2397438.50000 100410.40625 2395917.75000 98691.21875 2394397.00000 96972.03906 2393447.00000 95445.04687 2391355.25000 93152.53125 2389263.50000 91241.19531 2388122.50000 90094.55468 2387171.75000 88948.69531 2386412.75000 87612.88281 + 2428879.250000 120844.148438 2428079.000000 118984.250000 2426936.750000 118409.140625 2425794.500000 117834.210938 2424461.000000 117639.476562 2422364.500000 118204.453125 2421030.250000 118390.671875 2419315.250000 118575.898438 2418172.000000 118572.296875 2416267.250000 117994.843750 2414934.000000 117800.257812 2413791.750000 117225.179688 2411888.250000 116457.281250 2409795.250000 114736.140625 2408462.500000 114160.617188 2406942.250000 112250.867188 2405801.000000 111104.406250 2404850.500000 110339.328125 2403327.250000 109382.093750 2401996.500000 107854.062500 2400665.500000 106516.460938 2399715.500000 105370.406250 2399336.250000 104226.343750 2398388.000000 102127.789062 2397438.500000 100410.406250 2395917.750000 98691.218750 2394397.000000 96972.039062 2393447.000000 95445.046875 2391355.250000 93152.531250 2389263.500000 91241.195312 2388122.500000 90094.554688 2387171.750000 88948.695312 2386412.750000 87612.882812 @@ -657,13 +657,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2381693.75000 64738.70312 - 2386412.75000 87612.88281 + 2381693.750000 64738.703125 + 2386412.750000 87612.882812 - 2386412.75000 87612.88281 2385272.25000 86085.25781 2385084.50000 84751.21093 2385088.25000 82846.23437 2384902.00000 80369.30468 2385095.75000 79036.46093 2385288.75000 77703.57812 2385673.00000 75990.35156 2385294.75000 74655.71093 2384344.50000 73319.07812 2383585.50000 71602.31250 2383017.00000 70076.68750 2382449.25000 68360.48437 2382071.75000 66263.73437 2381693.75000 64738.70312 + 2386412.750000 87612.882812 2385272.250000 86085.257812 2385084.500000 84751.210938 2385088.250000 82846.234375 2384902.000000 80369.304688 2385095.750000 79036.460938 2385288.750000 77703.578125 2385673.000000 75990.351562 2385294.750000 74655.710938 2384344.500000 73319.078125 2383585.500000 71602.312500 2383017.000000 70076.687500 2382449.250000 68360.484375 2382071.750000 66263.734375 2381693.750000 64738.703125 @@ -672,13 +672,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2297106.75000 57395.59765 - 2312654.00000 97478.49218 + 2297106.750000 57395.597656 + 2312654.000000 97478.492188 - 2297238.50000 57395.59765 2297106.75000 58187.96484 2297485.00000 59522.62109 2297863.75000 61047.64843 2299194.75000 62385.29296 2300140.75000 65626.69531 2300518.25000 67723.25781 2301084.50000 70201.57031 2301842.50000 72489.88281 2302601.00000 74206.68750 2303169.50000 75922.88281 2303737.00000 77829.64843 2305255.00000 81072.86718 2306393.50000 83552.75781 2307531.50000 86223.25000 2308291.00000 87749.65625 2309619.25000 90611.12500 2310948.00000 93091.81250 2311895.25000 95571.11718 2312654.00000 97478.49218 + 2297238.500000 57395.597656 2297106.750000 58187.964844 2297485.000000 59522.621094 2297863.750000 61047.648438 2299194.750000 62385.292969 2300140.750000 65626.695312 2300518.250000 67723.257812 2301084.500000 70201.570312 2301842.500000 72489.882812 2302601.000000 74206.687500 2303169.500000 75922.882812 2303737.000000 77829.648438 2305255.000000 81072.867188 2306393.500000 83552.757812 2307531.500000 86223.250000 2308291.000000 87749.656250 2309619.250000 90611.125000 2310948.000000 93091.812500 2311895.250000 95571.117188 2312654.000000 97478.492188 @@ -687,13 +687,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2281531.25000 33374.88281 - 2297238.50000 57395.59765 + 2281531.250000 33374.882812 + 2297238.500000 57395.597656 - 2281531.25000 33374.88281 2283055.50000 33379.62500 2284958.50000 34719.06250 2286669.50000 36629.21093 2288191.00000 37967.44140 2289140.50000 39685.00781 2290661.75000 41213.62109 2291421.50000 42549.45312 2292749.75000 45411.08593 2293889.00000 47510.03906 2294836.00000 50179.93359 2295594.00000 52468.23437 2296161.75000 54184.45703 2296350.00000 55328.10546 2297238.50000 57395.59765 + 2281531.250000 33374.882812 2283055.500000 33379.625000 2284958.500000 34719.062500 2286669.500000 36629.210938 2288191.000000 37967.441406 2289140.500000 39685.007812 2290661.750000 41213.621094 2291421.500000 42549.453125 2292749.750000 45411.085938 2293889.000000 47510.039062 2294836.000000 50179.933594 2295594.000000 52468.234375 2296161.750000 54184.457031 2296350.000000 55328.105469 2297238.500000 57395.597656 @@ -702,13 +702,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2381508.00000 16173.98535 - 2385409.75000 64738.70312 + 2381508.000000 16173.985352 + 2385409.750000 64738.703125 - 2381693.75000 64738.70312 2381508.00000 62452.16406 2381512.75000 59975.63281 2381516.00000 58261.21093 2381519.00000 56737.19531 2381714.50000 54261.45703 2382099.00000 52357.66406 2382292.00000 51024.80078 2383060.50000 47979.33593 2383635.50000 46076.12109 2383829.00000 44933.86328 2384212.50000 43601.60156 2384406.00000 42078.15234 2384408.50000 40744.71093 2384793.25000 38840.88281 2384987.75000 36746.12109 2384991.75000 34650.73046 2384804.25000 33126.14843 2384808.75000 30840.17773 2385005.75000 27602.32226 2385008.25000 26268.87109 2385011.00000 24935.43359 2385205.50000 23221.61718 2385208.50000 21697.58203 2385211.50000 20173.74609 2385404.50000 18840.88476 2385409.75000 16173.98535 + 2381693.750000 64738.703125 2381508.000000 62452.164062 2381512.750000 59975.632812 2381516.000000 58261.210938 2381519.000000 56737.195312 2381714.500000 54261.457031 2382099.000000 52357.664062 2382292.000000 51024.800781 2383060.500000 47979.335938 2383635.500000 46076.121094 2383829.000000 44933.863281 2384212.500000 43601.601562 2384406.000000 42078.152344 2384408.500000 40744.710938 2384793.250000 38840.882812 2384987.750000 36746.121094 2384991.750000 34650.730469 2384804.250000 33126.148438 2384808.750000 30840.177734 2385005.750000 27602.322266 2385008.250000 26268.871094 2385011.000000 24935.433594 2385205.500000 23221.617188 2385208.500000 21697.582031 2385211.500000 20173.746094 2385404.500000 18840.884766 2385409.750000 16173.985352 @@ -717,13 +717,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2273022.50000 -64336.01953 - 2385417.50000 33374.88281 + 2273022.500000 -64336.019531 + 2385417.500000 33374.882812 - 2385409.75000 16173.98535 2385415.25000 13316.48437 2385417.50000 12173.60546 2385230.50000 10458.43261 2384279.00000 9693.52734 2383137.00000 9118.44433 2381994.75000 8543.49316 2380472.25000 7586.24560 2379713.25000 5869.44043 2379526.25000 4154.27636 2379528.50000 3011.38769 2379531.75000 1296.96411 2379534.75000 -227.06932 2379919.00000 -1559.31091 2380111.75000 -2701.62646 2379732.25000 -3845.84716 2378401.25000 -5183.49511 2377262.75000 -7282.44091 2375360.75000 -9193.36523 2374029.25000 -10340.43652 2372507.25000 -11488.24902 2370985.25000 -12635.89648 2370224.75000 -13590.76953 2369465.25000 -14736.20996 2368704.50000 -15691.09570 2367562.25000 -16266.02734 2366422.00000 -17793.60937 2364900.75000 -19322.21484 2363949.75000 -20277.68554 2362049.25000 -22569.58789 2361288.75000 -23524.48632 2360528.75000 -24479.34375 2359959.00000 -25624.01757 2359008.75000 -26579.49804 2357867.50000 -27726.10937 2356727.00000 -29063.15820 2355777.00000 -30589.97070 2354636.25000 -31927.01171 2353686.75000 -33263.60937 2353117.75000 -34789.21875 2352742.00000 -37457.33593 2352175.25000 -39745.06250 2351988.25000 -41841.04296 2351801.25000 -43556.22265 2352185.25000 -44888.48828 2352570.75000 -47173.22656 2352954.50000 -48695.90234 2353147.25000 -49838.38281 2353340.75000 -51361.63671 2353535.25000 -53075.43750 2353729.00000 -54789.43359 2353544.25000 -57647.32421 2353355.25000 -58790.98046 2352976.75000 -59935.03515 2352217.50000 -61270.88671 2351267.25000 -62607.31250 2350125.50000 -63373.01171 2348030.25000 -63950.90234 2346697.25000 -64336.01953 2344411.00000 -64152.77734 2343075.75000 -63395.03515 2341549.75000 -62828.27343 2339453.00000 -62263.27734 2337355.75000 -61698.29296 2336212.00000 -61511.50000 2335068.25000 -60943.51562 2334114.00000 -60184.58984 2332777.50000 -58855.31640 2331822.75000 -57905.78906 2329724.50000 -56578.87500 2328391.25000 -56773.44140 2326674.25000 -56016.89062 2325529.50000 -55258.52343 2324575.75000 -54499.41796 2323811.50000 -53549.49218 2322665.25000 -52029.02734 2321900.75000 -50697.95312 2321136.00000 -49557.28125 2320180.50000 -48226.81250 2319036.50000 -47849.41015 2317703.00000 -48044.14062 2316369.75000 -48238.72265 2314464.00000 -47863.69140 2313319.50000 -47295.92578 2312365.00000 -46536.78906 2311221.75000 -46159.39453 2309696.50000 -45973.79687 2308553.00000 -45596.20312 2307027.00000 -45029.62890 2305313.00000 -45415.94531 2304171.25000 -46181.43750 2303031.00000 -47709.04687 2301510.50000 -49618.60156 2300369.75000 -50955.62500 2299991.50000 -52290.47656 2299233.25000 -54007.23828 2298284.50000 -56105.63281 2297141.00000 -56109.19140 2296374.00000 -53825.62109 2296371.50000 -52492.15625 2295796.50000 -50588.96484 2295411.50000 -48494.79687 2295027.25000 -47162.51953 2294644.00000 -46020.83593 2293687.50000 -44118.82031 2292923.00000 -42787.74609 2291015.75000 -42031.60156 2289298.50000 -40703.52734 2288534.25000 -39753.59375 2287389.25000 -38614.09765 2286051.00000 -36332.30859 2285476.50000 -35000.66796 2284712.75000 -34050.54687 2283757.25000 -32720.07421 2282611.00000 -31199.79296 2281656.25000 -30250.29296 2280128.75000 -28540.63476 2279554.75000 -27208.78320 2278789.00000 -25496.74609 2278020.75000 -22260.87109 2276872.50000 -19787.94335 2276678.75000 -18074.11914 2276295.00000 -16932.23828 2275340.50000 -15792.34375 2274576.25000 -14842.23437 2273238.25000 -12751.03320 2273043.00000 -10275.11328 2273040.50000 -8941.64257 2273036.25000 -6846.25927 2273031.50000 -4369.75048 2273027.75000 -2464.96728 2273025.00000 -1131.50891 2273022.50000 201.94564 2273209.00000 2107.54418 2273585.75000 4204.26074 2273774.00000 5347.75195 2273770.75000 7062.16601 2274339.75000 8587.97753 2275095.75000 11447.65429 2276045.00000 13355.62304 2277184.25000 15454.77148 2277751.50000 17551.89648 2278128.00000 20029.44335 2278697.25000 21174.29492 2279075.75000 22318.34960 2279453.75000 24224.55859 2279641.00000 25749.16796 2280018.25000 27655.16015 2280206.50000 28798.79882 2280394.25000 30132.87109 2281531.25000 33374.88281 + 2385409.750000 16173.985352 2385415.250000 13316.484375 2385417.500000 12173.605469 2385230.500000 10458.432617 2384279.000000 9693.527344 2383137.000000 9118.444336 2381994.750000 8543.493164 2380472.250000 7586.245605 2379713.250000 5869.440430 2379526.250000 4154.276367 2379528.500000 3011.387695 2379531.750000 1296.964111 2379534.750000 -227.069321 2379919.000000 -1559.310913 2380111.750000 -2701.626465 2379732.250000 -3845.847168 2378401.250000 -5183.495117 2377262.750000 -7282.440918 2375360.750000 -9193.365234 2374029.250000 -10340.436523 2372507.250000 -11488.249023 2370985.250000 -12635.896484 2370224.750000 -13590.769531 2369465.250000 -14736.209961 2368704.500000 -15691.095703 2367562.250000 -16266.027344 2366422.000000 -17793.609375 2364900.750000 -19322.214844 2363949.750000 -20277.685547 2362049.250000 -22569.587891 2361288.750000 -23524.486328 2360528.750000 -24479.343750 2359959.000000 -25624.017578 2359008.750000 -26579.498047 2357867.500000 -27726.109375 2356727.000000 -29063.158203 2355777.000000 -30589.970703 2354636.250000 -31927.011719 2353686.750000 -33263.609375 2353117.750000 -34789.218750 2352742.000000 -37457.335938 2352175.250000 -39745.062500 2351988.250000 -41841.042969 2351801.250000 -43556.222656 2352185.250000 -44888.488281 2352570.750000 -47173.226562 2352954.500000 -48695.902344 2353147.250000 -49838.382812 2353340.750000 -51361.636719 2353535.250000 -53075.437500 2353729.000000 -54789.433594 2353544.250000 -57647.324219 2353355.250000 -58790.980469 2352976.750000 -59935.035156 2352217.500000 -61270.886719 2351267.250000 -62607.312500 2350125.500000 -63373.011719 2348030.250000 -63950.902344 2346697.250000 -64336.019531 2344411.000000 -64152.777344 2343075.750000 -63395.035156 2341549.750000 -62828.273438 2339453.000000 -62263.277344 2337355.750000 -61698.292969 2336212.000000 -61511.500000 2335068.250000 -60943.515625 2334114.000000 -60184.589844 2332777.500000 -58855.316406 2331822.750000 -57905.789062 2329724.500000 -56578.875000 2328391.250000 -56773.441406 2326674.250000 -56016.890625 2325529.500000 -55258.523438 2324575.750000 -54499.417969 2323811.500000 -53549.492188 2322665.250000 -52029.027344 2321900.750000 -50697.953125 2321136.000000 -49557.281250 2320180.500000 -48226.812500 2319036.500000 -47849.410156 2317703.000000 -48044.140625 2316369.750000 -48238.722656 2314464.000000 -47863.691406 2313319.500000 -47295.925781 2312365.000000 -46536.789062 2311221.750000 -46159.394531 2309696.500000 -45973.796875 2308553.000000 -45596.203125 2307027.000000 -45029.628906 2305313.000000 -45415.945312 2304171.250000 -46181.437500 2303031.000000 -47709.046875 2301510.500000 -49618.601562 2300369.750000 -50955.625000 2299991.500000 -52290.476562 2299233.250000 -54007.238281 2298284.500000 -56105.632812 2297141.000000 -56109.191406 2296374.000000 -53825.621094 2296371.500000 -52492.156250 2295796.500000 -50588.964844 2295411.500000 -48494.796875 2295027.250000 -47162.519531 2294644.000000 -46020.835938 2293687.500000 -44118.820312 2292923.000000 -42787.746094 2291015.750000 -42031.601562 2289298.500000 -40703.527344 2288534.250000 -39753.593750 2287389.250000 -38614.097656 2286051.000000 -36332.308594 2285476.500000 -35000.667969 2284712.750000 -34050.546875 2283757.250000 -32720.074219 2282611.000000 -31199.792969 2281656.250000 -30250.292969 2280128.750000 -28540.634766 2279554.750000 -27208.783203 2278789.000000 -25496.746094 2278020.750000 -22260.871094 2276872.500000 -19787.943359 2276678.750000 -18074.119141 2276295.000000 -16932.238281 2275340.500000 -15792.343750 2274576.250000 -14842.234375 2273238.250000 -12751.033203 2273043.000000 -10275.113281 2273040.500000 -8941.642578 2273036.250000 -6846.259277 2273031.500000 -4369.750488 2273027.750000 -2464.967285 2273025.000000 -1131.508911 2273022.500000 201.945648 2273209.000000 2107.544189 2273585.750000 4204.260742 2273774.000000 5347.751953 2273770.750000 7062.166016 2274339.750000 8587.977539 2275095.750000 11447.654297 2276045.000000 13355.623047 2277184.250000 15454.771484 2277751.500000 17551.896484 2278128.000000 20029.443359 2278697.250000 21174.294922 2279075.750000 22318.349609 2279453.750000 24224.558594 2279641.000000 25749.167969 2280018.250000 27655.160156 2280206.500000 28798.798828 2280394.250000 30132.871094 2281531.250000 33374.882812 @@ -732,13 +732,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2417042.50000 136722.43750 - 2428229.75000 206984.43750 + 2417042.500000 136722.437500 + 2428229.750000 206984.437500 - 2417042.50000 206984.43750 2419909.00000 204110.21875 2420865.25000 202398.57812 2422201.50000 201069.31250 2422965.50000 199928.79687 2423349.75000 198596.54687 2423733.00000 197454.67187 2424309.75000 194599.17187 2424505.00000 192504.20312 2424507.25000 191361.32812 2424510.75000 189646.90625 2424514.50000 187741.90625 2424517.50000 186217.89062 2424521.25000 184313.09375 2424332.25000 183169.43750 2424335.25000 181645.59375 2424337.50000 180502.53125 2424149.75000 179168.48437 2423772.25000 177452.89062 2423774.50000 176310.00000 2423397.75000 174213.25000 2423019.00000 172688.21875 2422641.25000 171162.98437 2422263.00000 169828.35937 2422265.25000 168685.29687 2422268.25000 167161.45312 2422080.50000 165827.40625 2421894.00000 163731.42187 2421899.75000 160873.93750 2422093.25000 159350.53125 2422286.25000 158017.67187 2423049.75000 157067.56250 2424389.25000 154214.42187 2424582.50000 153071.95312 2425347.00000 151740.89062 2426113.50000 149647.89062 2426878.25000 148126.23437 2427263.50000 146222.64062 2427646.75000 145080.75000 2427839.50000 143938.50000 2428034.00000 141843.51562 2428229.75000 139177.21875 2428043.00000 137271.64062 2427983.00000 136722.43750 + 2417042.500000 206984.437500 2419909.000000 204110.218750 2420865.250000 202398.578125 2422201.500000 201069.312500 2422965.500000 199928.796875 2423349.750000 198596.546875 2423733.000000 197454.671875 2424309.750000 194599.171875 2424505.000000 192504.203125 2424507.250000 191361.328125 2424510.750000 189646.906250 2424514.500000 187741.906250 2424517.500000 186217.890625 2424521.250000 184313.093750 2424332.250000 183169.437500 2424335.250000 181645.593750 2424337.500000 180502.531250 2424149.750000 179168.484375 2423772.250000 177452.890625 2423774.500000 176310.000000 2423397.750000 174213.250000 2423019.000000 172688.218750 2422641.250000 171162.984375 2422263.000000 169828.359375 2422265.250000 168685.296875 2422268.250000 167161.453125 2422080.500000 165827.406250 2421894.000000 163731.421875 2421899.750000 160873.937500 2422093.250000 159350.531250 2422286.250000 158017.671875 2423049.750000 157067.562500 2424389.250000 154214.421875 2424582.500000 153071.953125 2425347.000000 151740.890625 2426113.500000 149647.890625 2426878.250000 148126.234375 2427263.500000 146222.640625 2427646.750000 145080.750000 2427839.500000 143938.500000 2428034.000000 141843.515625 2428229.750000 139177.218750 2428043.000000 137271.640625 2427983.000000 136722.437500 @@ -747,13 +747,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2427983.00000 127024.38281 - 2437545.00000 136722.43750 + 2427983.000000 127024.382812 + 2437545.000000 136722.437500 - 2427983.00000 136722.43750 2429730.50000 136509.39062 2431065.75000 135751.32812 2431830.25000 134419.78125 2432595.00000 133278.68750 2433358.75000 132328.25000 2434314.00000 131187.95312 2435078.75000 130047.02343 2435842.75000 128905.95312 2437545.00000 127024.38281 + 2427983.000000 136722.437500 2429730.500000 136509.390625 2431065.750000 135751.328125 2431830.250000 134419.781250 2432595.000000 133278.687500 2433358.750000 132328.250000 2434314.000000 131187.953125 2435078.750000 130047.023438 2435842.750000 128905.953125 2437545.000000 127024.382812 @@ -762,13 +762,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2428879.25000 120844.14843 - 2437545.00000 127024.38281 + 2428879.250000 120844.148438 + 2437545.000000 127024.382812 - 2437545.00000 127024.38281 2437182.50000 126051.61718 2436234.00000 124333.68750 2435664.25000 123188.63281 2434713.50000 122232.84375 2433190.50000 121656.38281 2428879.25000 120844.14843 + 2437545.000000 127024.382812 2437182.500000 126051.617188 2436234.000000 124333.687500 2435664.250000 123188.632812 2434713.500000 122232.843750 2433190.500000 121656.382812 2428879.250000 120844.148438 @@ -777,13 +777,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2364917.00000 200324.98437 - 2399226.25000 219211.67187 + 2364917.000000 200324.984375 + 2399226.250000 219211.671875 - 2364917.00000 219211.67187 2368775.25000 212649.42187 2369152.25000 212290.87500 2370079.50000 211409.39062 2372288.25000 209310.03125 2373868.50000 208388.89062 2375666.50000 206847.62500 2378371.25000 205057.00000 2381376.25000 203180.95312 2383945.75000 202268.12500 2387074.75000 201435.76562 2392200.50000 200634.57812 2395394.00000 200324.98437 2399226.25000 201743.82812 + 2364917.000000 219211.671875 2368775.250000 212649.421875 2369152.250000 212290.875000 2370079.500000 211409.390625 2372288.250000 209310.031250 2373868.500000 208388.890625 2375666.500000 206847.625000 2378371.250000 205057.000000 2381376.250000 203180.953125 2383945.750000 202268.125000 2387074.750000 201435.765625 2392200.500000 200634.578125 2395394.000000 200324.984375 2399226.250000 201743.828125 @@ -792,13 +792,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2376921.25000 301084.96875 - 2380836.00000 301697.28125 + 2376921.250000 301084.968750 + 2380836.000000 301697.281250 - 2376921.25000 301464.28125 2379101.25000 301697.28125 2380836.00000 301084.96875 + 2376921.250000 301464.281250 2379101.250000 301697.281250 2380836.000000 301084.968750 @@ -807,13 +807,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2380836.00000 299794.00000 - 2398316.25000 301915.87500 + 2380836.000000 299794.000000 + 2398316.250000 301915.875000 - 2380836.00000 301084.96875 2381396.75000 300887.09375 2385665.00000 300171.25000 2386999.25000 299794.00000 2388903.50000 299798.96875 2391378.00000 299805.40625 2394038.25000 301335.43750 2396320.25000 301912.40625 2397653.00000 301915.87500 2398316.25000 301857.34375 + 2380836.000000 301084.968750 2381396.750000 300887.093750 2385665.000000 300171.250000 2386999.250000 299794.000000 2388903.500000 299798.968750 2391378.000000 299805.406250 2394038.250000 301335.437500 2396320.250000 301912.406250 2397653.000000 301915.875000 2398316.250000 301857.343750 @@ -822,13 +822,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2375060.75000 298175.34375 - 2376921.25000 301464.28125 + 2375060.750000 298175.343750 + 2376921.250000 301464.281250 - 2375060.75000 298175.34375 2375860.50000 299806.87500 2376921.25000 301464.28125 + 2375060.750000 298175.343750 2375860.500000 299806.875000 2376921.250000 301464.281250 @@ -837,13 +837,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2398316.25000 285013.40625 - 2423954.25000 301857.34375 + 2398316.250000 285013.406250 + 2423954.250000 301857.343750 - 2398316.25000 301857.34375 2399748.25000 301731.06250 2402663.75000 300752.06250 2404715.25000 297555.56250 2405865.75000 295274.00000 2406635.25000 293372.15625 2407022.50000 291659.75000 2407600.25000 290138.34375 2408367.25000 288617.21875 2409896.25000 287098.09375 2412188.75000 285200.40625 2413522.25000 285013.40625 2415805.50000 285400.09375 2418088.25000 285977.25000 2419418.75000 286551.90625 2421699.25000 287509.75000 2423954.25000 287380.78125 + 2398316.250000 301857.343750 2399748.250000 301731.062500 2402663.750000 300752.062500 2404715.250000 297555.562500 2405865.750000 295274.000000 2406635.250000 293372.156250 2407022.500000 291659.750000 2407600.250000 290138.343750 2408367.250000 288617.218750 2409896.250000 287098.093750 2412188.750000 285200.406250 2413522.250000 285013.406250 2415805.500000 285400.093750 2418088.250000 285977.250000 2419418.750000 286551.906250 2421699.250000 287509.750000 2423954.250000 287380.781250 @@ -852,13 +852,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2347757.75000 282176.75000 - 2375060.75000 298175.34375 + 2347757.750000 282176.750000 + 2375060.750000 298175.343750 - 2347757.75000 282176.75000 2349180.75000 282180.50000 2350892.50000 282565.68750 2352604.25000 282950.87500 2354694.50000 284098.71875 2355836.25000 284291.96875 2356725.75000 284492.25000 2357548.00000 284677.34375 2359260.50000 284872.06250 2361544.75000 285068.46875 2363829.50000 285074.43750 2365921.25000 285650.87500 2368009.00000 287369.90625 2369335.75000 288896.28125 2370049.50000 289974.90625 2370471.50000 290612.62500 2371037.25000 291946.75000 2372363.25000 293663.78125 2373120.50000 294807.93750 2373878.00000 295761.84375 2375060.75000 298175.34375 + 2347757.750000 282176.750000 2349180.750000 282180.500000 2350892.500000 282565.687500 2352604.250000 282950.875000 2354694.500000 284098.718750 2355836.250000 284291.968750 2356725.750000 284492.250000 2357548.000000 284677.343750 2359260.500000 284872.062500 2361544.750000 285068.468750 2363829.500000 285074.437500 2365921.250000 285650.875000 2368009.000000 287369.906250 2369335.750000 288896.281250 2370049.500000 289974.906250 2370471.500000 290612.625000 2371037.250000 291946.750000 2372363.250000 293663.781250 2373120.500000 294807.937500 2373878.000000 295761.843750 2375060.750000 298175.343750 @@ -867,13 +867,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2544336.75000 373668.78125 - 2552279.50000 391797.40625 + 2544336.750000 373668.781250 + 2552279.500000 391797.406250 - 2552279.50000 391797.40625 2551522.00000 390843.50000 2550766.25000 389318.59375 2550202.00000 387603.56250 2549635.00000 386459.87500 2549260.50000 384935.78125 2548885.75000 383411.87500 2548325.50000 380554.65625 2547383.75000 378077.34375 2546439.00000 376171.06250 2545494.50000 374264.75000 2544336.75000 373668.78125 + 2552279.500000 391797.406250 2551522.000000 390843.500000 2550766.250000 389318.593750 2550202.000000 387603.562500 2549635.000000 386459.875000 2549260.500000 384935.781250 2548885.750000 383411.875000 2548325.500000 380554.656250 2547383.750000 378077.343750 2546439.000000 376171.062500 2545494.500000 374264.750000 2544336.750000 373668.781250 @@ -882,13 +882,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2529868.00000 310448.28125 - 2544336.75000 373668.78125 + 2529868.000000 310448.281250 + 2544336.750000 373668.781250 - 2544336.75000 373668.78125 2543217.00000 372545.40625 2541696.25000 371780.00000 2539986.75000 370823.62500 2538879.25000 369569.18750 2538470.50000 369106.28125 2537525.75000 367199.96875 2536960.25000 365865.84375 2536394.50000 364341.25000 2536211.75000 362436.93750 2535461.00000 359769.68750 2534706.75000 357864.03125 2534141.75000 356339.46875 2533414.00000 354553.40625 2532821.75000 353099.53125 2531687.75000 351002.43750 2531502.50000 349669.31250 2530561.75000 346811.09375 2530191.00000 344335.28125 2530769.25000 342432.93750 2530777.50000 340338.84375 2530600.75000 336911.40625 2530226.00000 335387.50000 2530041.00000 333863.90625 2530049.25000 331769.81250 2529868.00000 329484.75000 2530070.25000 326439.25000 2530460.75000 324155.68750 2530849.50000 322062.40625 2531428.50000 319969.78125 2531822.50000 316734.31250 2532408.50000 312928.34375 2532595.25000 310448.28125 + 2544336.750000 373668.781250 2543217.000000 372545.406250 2541696.250000 371780.000000 2539986.750000 370823.625000 2538879.250000 369569.187500 2538470.500000 369106.281250 2537525.750000 367199.968750 2536960.250000 365865.843750 2536394.500000 364341.250000 2536211.750000 362436.937500 2535461.000000 359769.687500 2534706.750000 357864.031250 2534141.750000 356339.468750 2533414.000000 354553.406250 2532821.750000 353099.531250 2531687.750000 351002.437500 2531502.500000 349669.312500 2530561.750000 346811.093750 2530191.000000 344335.281250 2530769.250000 342432.937500 2530777.500000 340338.843750 2530600.750000 336911.406250 2530226.000000 335387.500000 2530041.000000 333863.906250 2530049.250000 331769.812500 2529868.000000 329484.750000 2530070.250000 326439.250000 2530460.750000 324155.687500 2530849.500000 322062.406250 2531428.500000 319969.781250 2531822.500000 316734.312500 2532408.500000 312928.343750 2532595.250000 310448.281250 @@ -897,13 +897,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2528707.75000 302480.75000 - 2532595.25000 310448.28125 + 2528707.750000 302480.750000 + 2532595.250000 310448.281250 - 2532595.25000 310448.28125 2532428.75000 307788.03125 2530914.00000 305689.96875 2529782.00000 303021.71875 2528707.75000 302480.75000 + 2532595.250000 310448.281250 2532428.750000 307788.031250 2530914.000000 305689.968750 2529782.000000 303021.718750 2528707.750000 302480.750000 @@ -912,13 +912,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2517059.75000 291146.93750 - 2528707.75000 302480.75000 + 2517059.750000 291146.937500 + 2528707.750000 302480.750000 - 2528707.75000 302480.75000 2525406.25000 302248.65625 2522563.25000 299004.93750 2521052.25000 295954.78125 2519536.75000 293856.71875 2518210.75000 292139.87500 2517059.75000 291146.93750 + 2528707.750000 302480.750000 2525406.250000 302248.656250 2522563.250000 299004.937500 2521052.250000 295954.781250 2519536.750000 293856.718750 2518210.750000 292139.875000 2517059.750000 291146.937500 @@ -927,13 +927,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2497925.50000 276774.43750 - 2517059.75000 291146.93750 + 2497925.500000 276774.437500 + 2517059.750000 291146.937500 - 2517059.75000 291146.93750 2514419.25000 288132.03125 2512900.75000 286795.40625 2511572.50000 285649.56250 2510433.75000 284694.68750 2508534.75000 283547.53125 2505875.25000 282017.50000 2502456.75000 279724.03125 2499989.75000 277813.93750 2497925.50000 276774.43750 + 2517059.750000 291146.937500 2514419.250000 288132.031250 2512900.750000 286795.406250 2511572.500000 285649.562500 2510433.750000 284694.687500 2508534.750000 283547.531250 2505875.250000 282017.500000 2502456.750000 279724.031250 2499989.750000 277813.937500 2497925.500000 276774.437500 @@ -942,13 +942,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2446614.50000 245881.25000 - 2497925.50000 276774.43750 + 2446614.500000 245881.250000 + 2497925.500000 276774.437500 - 2497925.50000 276774.43750 2495810.25000 275328.00000 2494292.50000 273991.40625 2491448.75000 270937.93750 2488982.00000 268837.40625 2486703.75000 267117.90625 2483282.25000 265776.31250 2480812.50000 264437.25000 2478150.75000 263478.37500 2475489.00000 262519.71875 2472258.50000 260988.17187 2469600.00000 259267.87500 2466751.75000 257166.14062 2463520.50000 255825.06250 2460098.50000 254483.50000 2456490.50000 252189.51562 2454781.00000 251042.87500 2453262.50000 249896.71875 2452123.00000 249132.10937 2450985.00000 247986.93750 2448135.25000 246456.42187 2446614.50000 245881.25000 + 2497925.500000 276774.437500 2495810.250000 275328.000000 2494292.500000 273991.406250 2491448.750000 270937.937500 2488982.000000 268837.406250 2486703.750000 267117.906250 2483282.250000 265776.312500 2480812.500000 264437.250000 2478150.750000 263478.375000 2475489.000000 262519.718750 2472258.500000 260988.171875 2469600.000000 259267.875000 2466751.750000 257166.140625 2463520.500000 255825.062500 2460098.500000 254483.500000 2456490.500000 252189.515625 2454781.000000 251042.875000 2453262.500000 249896.718750 2452123.000000 249132.109375 2450985.000000 247986.937500 2448135.250000 246456.421875 2446614.500000 245881.250000 @@ -957,13 +957,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2417042.50000 206984.43750 - 2446614.50000 245881.25000 + 2417042.500000 206984.437500 + 2446614.500000 245881.250000 - 2446614.50000 245881.25000 2445859.25000 244356.34375 2444723.00000 242830.28125 2443774.50000 241875.89062 2442446.25000 240730.23437 2441497.00000 239966.31250 2439789.00000 238629.18750 2438083.25000 236720.89062 2436759.50000 234432.85937 2436008.00000 231765.60937 2435255.25000 229479.06250 2434310.50000 227763.21875 2432606.25000 225283.73437 2430899.00000 223756.35937 2428811.75000 222037.35937 2427105.25000 220129.23437 2425780.00000 218221.95312 2424646.50000 215934.42187 2423511.50000 214218.09375 2422185.50000 212501.23437 2420669.25000 210593.43750 2419721.75000 209639.03125 2417824.75000 207730.26562 2417042.50000 206984.43750 + 2446614.500000 245881.250000 2445859.250000 244356.343750 2444723.000000 242830.281250 2443774.500000 241875.890625 2442446.250000 240730.234375 2441497.000000 239966.312500 2439789.000000 238629.187500 2438083.250000 236720.890625 2436759.500000 234432.859375 2436008.000000 231765.609375 2435255.250000 229479.062500 2434310.500000 227763.218750 2432606.250000 225283.734375 2430899.000000 223756.359375 2428811.750000 222037.359375 2427105.250000 220129.234375 2425780.000000 218221.953125 2424646.500000 215934.421875 2423511.500000 214218.093750 2422185.500000 212501.234375 2420669.250000 210593.437500 2419721.750000 209639.031250 2417824.750000 207730.265625 2417042.500000 206984.437500 @@ -972,13 +972,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2399226.25000 200265.42187 - 2417042.50000 206984.43750 + 2399226.250000 200265.421875 + 2417042.500000 206984.437500 - 2417042.50000 206984.43750 2414220.75000 204294.09375 2412130.50000 203336.71875 2409088.25000 202376.87500 2406237.00000 201036.79687 2402432.75000 200265.42187 2400336.75000 200640.68750 2399226.25000 201743.82812 + 2417042.500000 206984.437500 2414220.750000 204294.093750 2412130.500000 203336.718750 2409088.250000 202376.875000 2406237.000000 201036.796875 2402432.750000 200265.421875 2400336.750000 200640.687500 2399226.250000 201743.828125 @@ -987,13 +987,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2364917.00000 201743.82812 - 2399226.25000 224582.79687 + 2364917.000000 201743.828125 + 2399226.250000 224582.796875 - 2399226.25000 201743.82812 2398425.50000 202539.56250 2397087.50000 203868.75000 2395750.25000 205007.43750 2394218.25000 207097.75000 2393074.25000 207665.78125 2391164.75000 208993.46875 2389636.50000 210322.14062 2388488.75000 211651.81250 2387909.00000 213934.89062 2387522.50000 215266.50000 2387516.50000 216789.62500 2387701.50000 218122.75000 2387876.00000 222311.62500 2386347.00000 223640.29687 2384630.75000 224397.29687 2382726.25000 224582.79687 2380824.25000 224006.65625 2378164.00000 222667.06250 2375504.50000 221137.03125 2372652.50000 220177.67187 2370370.50000 219410.28125 2368086.50000 219404.32812 2366944.00000 219401.32812 2364917.00000 219211.67187 + 2399226.250000 201743.828125 2398425.500000 202539.562500 2397087.500000 203868.750000 2395750.250000 205007.437500 2394218.250000 207097.750000 2393074.250000 207665.781250 2391164.750000 208993.468750 2389636.500000 210322.140625 2388488.750000 211651.812500 2387909.000000 213934.890625 2387522.500000 215266.500000 2387516.500000 216789.625000 2387701.500000 218122.750000 2387876.000000 222311.625000 2386347.000000 223640.296875 2384630.750000 224397.296875 2382726.250000 224582.796875 2380824.250000 224006.656250 2378164.000000 222667.062500 2375504.500000 221137.031250 2372652.500000 220177.671875 2370370.500000 219410.281250 2368086.500000 219404.328125 2366944.000000 219401.328125 2364917.000000 219211.671875 @@ -1002,13 +1002,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2327897.50000 211535.75000 - 2346585.25000 213607.48437 + 2327897.500000 211535.750000 + 2346585.250000 213607.484375 - 2346585.25000 211882.15625 2345840.50000 211731.14062 2343937.00000 211535.75000 2341841.50000 211911.20312 2339745.50000 212286.46875 2336888.00000 212659.76562 2335366.50000 212275.04687 2333462.25000 212270.10937 2331749.75000 212075.18750 2329843.75000 212641.40625 2327897.50000 213607.48437 + 2346585.250000 211882.156250 2345840.500000 211731.140625 2343937.000000 211535.750000 2341841.500000 211911.203125 2339745.500000 212286.468750 2336888.000000 212659.765625 2335366.500000 212275.046875 2333462.250000 212270.109375 2331749.750000 212075.187500 2329843.750000 212641.406250 2327897.500000 213607.484375 @@ -1017,13 +1017,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2346585.25000 211882.15625 - 2364917.00000 219211.67187 + 2346585.250000 211882.156250 + 2364917.000000 219211.671875 - 2364917.00000 219211.67187 2364850.25000 219205.42187 2361998.75000 218055.79687 2360669.25000 217290.87500 2358892.25000 216247.53125 2358389.50000 215952.28125 2357059.75000 215187.15625 2354780.75000 213848.57812 2352499.75000 212890.68750 2350217.00000 212313.75000 2347742.50000 212116.84375 2346585.25000 211882.15625 + 2364917.000000 219211.671875 2364850.250000 219205.421875 2361998.750000 218055.796875 2360669.250000 217290.875000 2358892.250000 216247.531250 2358389.500000 215952.281250 2357059.750000 215187.156250 2354780.750000 213848.578125 2352499.750000 212890.687500 2350217.000000 212313.750000 2347742.500000 212116.843750 2346585.250000 211882.156250 @@ -1032,13 +1032,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2552279.50000 391797.40625 - 2576803.50000 408596.37500 + 2552279.500000 391797.406250 + 2576803.500000 408596.375000 - 2576803.50000 401189.87500 2575467.25000 402138.34375 2573936.50000 404038.15625 2573166.00000 406320.75000 2571445.00000 408220.09375 2569730.00000 408596.37500 2568399.50000 408021.75000 2567258.75000 407638.00000 2566312.50000 406112.43750 2565365.50000 404777.34375 2563847.00000 403631.15625 2562706.75000 403057.00000 2561567.25000 402482.84375 2559473.50000 402287.09375 2557187.75000 402471.40625 2555980.50000 401673.62500 2555723.75000 400544.71875 2555826.50000 397568.50000 2555056.50000 394797.50000 2552279.50000 391797.40625 + 2576803.500000 401189.875000 2575467.250000 402138.343750 2573936.500000 404038.156250 2573166.000000 406320.750000 2571445.000000 408220.093750 2569730.000000 408596.375000 2568399.500000 408021.750000 2567258.750000 407638.000000 2566312.500000 406112.437500 2565365.500000 404777.343750 2563847.000000 403631.156250 2562706.750000 403057.000000 2561567.250000 402482.843750 2559473.500000 402287.093750 2557187.750000 402471.406250 2555980.500000 401673.625000 2555723.750000 400544.718750 2555826.500000 397568.500000 2555056.500000 394797.500000 2552279.500000 391797.406250 @@ -1047,13 +1047,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2576803.50000 401189.87500 - 2578927.50000 402717.03125 + 2576803.500000 401189.875000 + 2578927.500000 402717.031250 - 2576803.50000 401189.87500 2577421.25000 401365.65625 2578424.50000 401900.81250 2578927.50000 402717.03125 + 2576803.500000 401189.875000 2577421.250000 401365.656250 2578424.500000 401900.812500 2578927.500000 402717.031250 @@ -1062,13 +1062,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2576803.50000 399102.18750 - 2589745.50000 402556.25000 + 2576803.500000 399102.187500 + 2589745.500000 402556.250000 - 2589745.50000 402556.25000 2588416.50000 401601.06250 2587278.50000 400455.71875 2585757.50000 399880.53125 2582523.25000 399110.65625 2581190.50000 399107.18750 2579286.75000 399102.18750 2577761.50000 399669.40625 2576803.50000 401189.87500 + 2589745.500000 402556.250000 2588416.500000 401601.062500 2587278.500000 400455.718750 2585757.500000 399880.531250 2582523.250000 399110.656250 2581190.500000 399107.187500 2579286.750000 399102.187500 2577761.500000 399669.406250 2576803.500000 401189.875000 @@ -1077,13 +1077,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2589745.50000 393939.62500 - 2615354.50000 402556.25000 + 2589745.500000 393939.625000 + 2615354.500000 402556.250000 - 2589745.50000 402556.25000 2591141.50000 401863.00000 2592476.75000 401105.34375 2594192.50000 400920.25000 2595526.50000 400734.15625 2597051.00000 400548.53125 2599145.50000 400745.87500 2600478.50000 401131.21875 2602192.25000 401898.84375 2603525.75000 401903.12500 2605241.75000 401146.65625 2606386.75000 400388.37500 2607341.00000 399629.25000 2607726.50000 397344.40625 2609063.00000 396014.90625 2610778.50000 395449.03125 2615354.50000 393939.62500 + 2589745.500000 402556.250000 2591141.500000 401863.000000 2592476.750000 401105.343750 2594192.500000 400920.250000 2595526.500000 400734.156250 2597051.000000 400548.531250 2599145.500000 400745.875000 2600478.500000 401131.218750 2602192.250000 401898.843750 2603525.750000 401903.125000 2605241.750000 401146.656250 2606386.750000 400388.375000 2607341.000000 399629.250000 2607726.500000 397344.406250 2609063.000000 396014.906250 2610778.500000 395449.031250 2615354.500000 393939.625000 @@ -1092,13 +1092,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2442115.25000 245881.25000 - 2446614.50000 262496.84375 + 2442115.250000 245881.250000 + 2446614.500000 262496.843750 - 2442115.25000 262496.84375 2442339.75000 261851.75000 2446590.50000 249634.64062 2446614.50000 245881.25000 + 2442115.250000 262496.843750 2442339.750000 261851.750000 2446590.500000 249634.640625 2446614.500000 245881.250000 @@ -1109,21 +1109,21 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2281604.25000 194088.23437 - 2578914.25000 427872.65625 + 2281604.250000 194088.234375 + 2578914.250000 427872.656250 - 2281604.25000 340848.93750 - 2281604.25000 340848.93750 + 2281604.250000 340848.937500 + 2281604.250000 340848.937500 - 2281604.25000 340848.93750 + 2281604.250000 340848.937500 @@ -1132,13 +1132,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2503805.50000 427872.65625 - 2503805.50000 427872.65625 + 2503805.500000 427872.656250 + 2503805.500000 427872.656250 - 2503805.50000 427872.65625 + 2503805.500000 427872.656250 @@ -1147,13 +1147,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2499190.00000 194088.23437 - 2499190.00000 194088.23437 + 2499190.000000 194088.234375 + 2499190.000000 194088.234375 - 2499190.00000 194088.23437 + 2499190.000000 194088.234375 @@ -1162,13 +1162,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2434957.00000 347013.59375 - 2434957.00000 347013.59375 + 2434957.000000 347013.593750 + 2434957.000000 347013.593750 - 2434957.00000 347013.59375 + 2434957.000000 347013.593750 @@ -1177,13 +1177,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2578914.25000 292073.09375 - 2578914.25000 292073.09375 + 2578914.250000 292073.093750 + 2578914.250000 292073.093750 - 2578914.25000 292073.09375 + 2578914.250000 292073.093750 @@ -1192,13 +1192,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2536072.75000 311524.96875 - 2536072.75000 311524.96875 + 2536072.750000 311524.968750 + 2536072.750000 311524.968750 - 2536072.75000 311524.96875 + 2536072.750000 311524.968750 @@ -1207,13 +1207,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2494520.00000 285855.40625 - 2494520.00000 285855.40625 + 2494520.000000 285855.406250 + 2494520.000000 285855.406250 - 2494520.00000 285855.40625 + 2494520.000000 285855.406250 @@ -1222,13 +1222,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2348711.75000 204294.06250 - 2348711.75000 204294.06250 + 2348711.750000 204294.062500 + 2348711.750000 204294.062500 - 2348711.75000 204294.06250 + 2348711.750000 204294.062500 diff --git a/msautotest/wxs/expected/wfsogr_addfiles_onelayer.txt b/msautotest/wxs/expected/wfsogr_addfiles_onelayer.txt index 3c1caeee51..60f55f4cf3 100644 --- a/msautotest/wxs/expected/wfsogr_addfiles_onelayer.txt +++ b/msautotest/wxs/expected/wfsogr_addfiles_onelayer.txt @@ -7,20 +7,17 @@ Content-Transfer-Encoding: binary - - - 2576803.5399102.1875 - 2589745.5402556.25 - - - - - - 2589745.5,402556.25 2588416.5,401601.0625 2587278.5,400455.71875 2585757.5,399880.53125 2582523.25,399110.65625 2581190.5,399107.1875 2579286.75,399102.1875 2577761.5,399669.40625 2576803.5,401189.875 + xmlns:gml="http://www.opengis.net/gml/3.2"> + 2576803.5 399102.18752589745.5 402556.25 + + + + 2576803.5 399102.18752589745.5 402556.25 + 2589745.5 402556.25 2588416.5 401601.0625 2587278.5 400455.71875 2585757.5 399880.53125 2582523.25 399110.65625 2581190.5 399107.1875 2579286.75 399102.1875 2577761.5 399669.40625 2576803.5 401189.875 613 1511 0 @@ -31,7 +28,7 @@ Content-Transfer-Encoding: binary - + --xxOGRBoundaryxx @@ -40,23 +37,47 @@ Content-Type: application/binary Content-Transfer-Encoding: binary - - - + + + + 0 + + + + + - - - + + + + + + + + + + + + + + - + - + diff --git a/msautotest/wxs/expected/wfsogr_addfiles_onelayer.zip b/msautotest/wxs/expected/wfsogr_addfiles_onelayer.zip index 6391e4a7e9..13a118e51b 100644 Binary files a/msautotest/wxs/expected/wfsogr_addfiles_onelayer.zip and b/msautotest/wxs/expected/wfsogr_addfiles_onelayer.zip differ diff --git a/msautotest/wxs/expected/wfsogr_addfiles_twolayers.txt b/msautotest/wxs/expected/wfsogr_addfiles_twolayers.txt index ff406ec860..83b3966d04 100644 --- a/msautotest/wxs/expected/wfsogr_addfiles_twolayers.txt +++ b/msautotest/wxs/expected/wfsogr_addfiles_twolayers.txt @@ -7,20 +7,17 @@ Content-Transfer-Encoding: binary - - - 2576803.5399102.1875 - 2589745.5402556.25 - - - - - - 2589745.5,402556.25 2588416.5,401601.0625 2587278.5,400455.71875 2585757.5,399880.53125 2582523.25,399110.65625 2581190.5,399107.1875 2579286.75,399102.1875 2577761.5,399669.40625 2576803.5,401189.875 + xmlns:gml="http://www.opengis.net/gml/3.2"> + 2576803.5 399102.18752589745.5 402556.25 + + + + 2576803.5 399102.18752589745.5 402556.25 + 2589745.5 402556.25 2588416.5 401601.0625 2587278.5 400455.71875 2585757.5 399880.53125 2582523.25 399110.65625 2581190.5 399107.1875 2579286.75 399102.1875 2577761.5 399669.40625 2576803.5 401189.875 613 1511 0 @@ -31,10 +28,11 @@ Content-Transfer-Encoding: binary - - - - 2589745.5,402556.25 2588416.5,401601.0625 2587278.5,400455.71875 2585757.5,399880.53125 2582523.25,399110.65625 2581190.5,399107.1875 2579286.75,399102.1875 2577761.5,399669.40625 2576803.5,401189.875 + + + + 2576803.5 399102.18752589745.5 402556.25 + 2589745.5 402556.25 2588416.5 401601.0625 2587278.5 400455.71875 2585757.5 399880.53125 2582523.25 399110.65625 2581190.5 399107.1875 2579286.75 399102.1875 2577761.5 399669.40625 2576803.5 401189.875 613 1511 0 @@ -45,7 +43,7 @@ Content-Transfer-Encoding: binary - + --xxOGRBoundaryxx @@ -54,23 +52,47 @@ Content-Type: application/binary Content-Transfer-Encoding: binary - - - + + + + 0 + + + + + - - - + + + + + + + + + + + + + + - + - + @@ -139,12 +161,12 @@ Content-Transfer-Encoding: binary - + - + diff --git a/msautotest/wxs/expected/wfsogr_getpropertyvalue_sortby.xml b/msautotest/wxs/expected/wfsogr_getpropertyvalue_sortby.xml index 190fc6afb3..1d52697c45 100644 --- a/msautotest/wxs/expected/wfsogr_getpropertyvalue_sortby.xml +++ b/msautotest/wxs/expected/wfsogr_getpropertyvalue_sortby.xml @@ -10,21 +10,21 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 timeStamp="" numberMatched="unknown" numberReturned="3"> - 2431943.75000 118985.38281 - 2587598.00000 404010.53125 + 2431943.750000 118985.382812 + 2587598.000000 404010.531250 - 2431943.75000 118985.38281 - 2431943.75000 118985.38281 + 2431943.750000 118985.382812 + 2431943.750000 118985.382812 - 2431943.75000 118985.38281 + 2431943.750000 118985.382812 CAPHL @@ -37,13 +37,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2437026.00000 130358.35156 - 2437026.00000 130358.35156 + 2437026.000000 130358.351562 + 2437026.000000 130358.351562 - 2437026.00000 130358.35156 + 2437026.000000 130358.351562 CAIYJ @@ -56,13 +56,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2587598.00000 404010.53125 - 2587598.00000 404010.53125 + 2587598.000000 404010.531250 + 2587598.000000 404010.531250 - 2587598.00000 404010.53125 + 2587598.000000 404010.531250 CBLGX diff --git a/msautotest/wxs/expected/wfsogr_post_sortby.xml b/msautotest/wxs/expected/wfsogr_post_sortby.xml index 86c789208d..7daf710aca 100644 --- a/msautotest/wxs/expected/wfsogr_post_sortby.xml +++ b/msautotest/wxs/expected/wfsogr_post_sortby.xml @@ -10,21 +10,21 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 timeStamp="" numberMatched="unknown" numberReturned="3"> - 2281604.25000 135734.70312 - 2402416.50000 461586.81250 + 2281604.250000 135734.703125 + 2402416.500000 461586.812500 - 2281604.25000 340848.93750 - 2281604.25000 340848.93750 + 2281604.250000 340848.937500 + 2281604.250000 340848.937500 - 2281604.25000 340848.93750 + 2281604.250000 340848.937500 BACMK @@ -37,13 +37,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2402416.50000 461586.81250 - 2402416.50000 461586.81250 + 2402416.500000 461586.812500 + 2402416.500000 461586.812500 - 2402416.50000 461586.81250 + 2402416.500000 461586.812500 EGIIG @@ -56,13 +56,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2377598.00000 135734.70312 - 2377598.00000 135734.70312 + 2377598.000000 135734.703125 + 2377598.000000 135734.703125 - 2377598.00000 135734.70312 + 2377598.000000 135734.703125 CBPAK diff --git a/msautotest/wxs/expected/wfsogr_sortby.xml b/msautotest/wxs/expected/wfsogr_sortby.xml index 86c789208d..7daf710aca 100644 --- a/msautotest/wxs/expected/wfsogr_sortby.xml +++ b/msautotest/wxs/expected/wfsogr_sortby.xml @@ -10,21 +10,21 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 timeStamp="" numberMatched="unknown" numberReturned="3"> - 2281604.25000 135734.70312 - 2402416.50000 461586.81250 + 2281604.250000 135734.703125 + 2402416.500000 461586.812500 - 2281604.25000 340848.93750 - 2281604.25000 340848.93750 + 2281604.250000 340848.937500 + 2281604.250000 340848.937500 - 2281604.25000 340848.93750 + 2281604.250000 340848.937500 BACMK @@ -37,13 +37,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2402416.50000 461586.81250 - 2402416.50000 461586.81250 + 2402416.500000 461586.812500 + 2402416.500000 461586.812500 - 2402416.50000 461586.81250 + 2402416.500000 461586.812500 EGIIG @@ -56,13 +56,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2377598.00000 135734.70312 - 2377598.00000 135734.70312 + 2377598.000000 135734.703125 + 2377598.000000 135734.703125 - 2377598.00000 135734.70312 + 2377598.000000 135734.703125 CBPAK diff --git a/msautotest/wxs/expected/wfsogr_sortby_asc.xml b/msautotest/wxs/expected/wfsogr_sortby_asc.xml index 86c789208d..7daf710aca 100644 --- a/msautotest/wxs/expected/wfsogr_sortby_asc.xml +++ b/msautotest/wxs/expected/wfsogr_sortby_asc.xml @@ -10,21 +10,21 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 timeStamp="" numberMatched="unknown" numberReturned="3"> - 2281604.25000 135734.70312 - 2402416.50000 461586.81250 + 2281604.250000 135734.703125 + 2402416.500000 461586.812500 - 2281604.25000 340848.93750 - 2281604.25000 340848.93750 + 2281604.250000 340848.937500 + 2281604.250000 340848.937500 - 2281604.25000 340848.93750 + 2281604.250000 340848.937500 BACMK @@ -37,13 +37,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2402416.50000 461586.81250 - 2402416.50000 461586.81250 + 2402416.500000 461586.812500 + 2402416.500000 461586.812500 - 2402416.50000 461586.81250 + 2402416.500000 461586.812500 EGIIG @@ -56,13 +56,13 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8 - 2377598.00000 135734.70312 - 2377598.00000 135734.70312 + 2377598.000000 135734.703125 + 2377598.000000 135734.703125 - 2377598.00000 135734.70312 + 2377598.000000 135734.703125 CBPAK diff --git a/msautotest/wxs/expected/wms111_test_xml_escaping.xml b/msautotest/wxs/expected/wms111_test_xml_escaping.xml index c2bd5075fb..72d48cd13d 100644 --- a/msautotest/wxs/expected/wms111_test_xml_escaping.xml +++ b/msautotest/wxs/expected/wms111_test_xml_escaping.xml @@ -5,7 +5,6 @@ ]> - OGC:WMS title & title @@ -58,6 +57,7 @@ image/tiff application/vnd.google-earth.kml+xml application/vnd.google-earth.kmz + application/vnd.mapbox-vector-tile application/x-protobuf application/json @@ -125,18 +125,18 @@
EPSG:4326 EPSG:4269 - + + minx="-67.572500" miny="42.000000" maxx="-58.927500" maxy="48.500000" /> - province - title&title - abstract&abstract - - - text/xml - - + province + title&title + abstract&abstract + + + text/xml + + + + + + diff --git a/msautotest/wxs/expected/wms_cap130.xml b/msautotest/wxs/expected/wms_cap130.xml index 29ff6575bb..11fae34ccd 100644 --- a/msautotest/wxs/expected/wms_cap130.xml +++ b/msautotest/wxs/expected/wms_cap130.xml @@ -2,7 +2,6 @@ Content-Type: text/xml; charset=UTF-8 - WMS Test simple wms @@ -62,8 +61,9 @@ Content-Type: text/xml; charset=UTF-8 - text/plain application/vnd.ogc.gml + OTHER_GFI_RESULT + text/plain @@ -122,29 +122,29 @@ Content-Type: text/xml; charset=UTF-8 EPSG:4269 EPSG:4326 - -67.5725 - -58.9275 - 42 - 48.5 + -67.572500 + -58.927500 + 42.000000 + 48.500000 + minx="42.000000" miny="-67.572500" maxx="48.500000" maxy="-58.927500" /> - road - road - EPSG:43204 - - -66.6333 - -59.2921 - 42.3821 - 48.2955 - - - - text/xml - - + road + road + EPSG:43204 + + -66.633318 + -59.292114 + 42.382054 + 48.295512 + + + + text/xml + + + + + + diff --git a/msautotest/wxs/expected/wms_custom_projection_getmap110.png b/msautotest/wxs/expected/wms_custom_projection_getmap110.png new file mode 100644 index 0000000000..e2b4c016e2 Binary files /dev/null and b/msautotest/wxs/expected/wms_custom_projection_getmap110.png differ diff --git a/msautotest/wxs/expected/wms_custom_projection_getmap130.png b/msautotest/wxs/expected/wms_custom_projection_getmap130.png new file mode 100644 index 0000000000..e2b4c016e2 Binary files /dev/null and b/msautotest/wxs/expected/wms_custom_projection_getmap130.png differ diff --git a/msautotest/wxs/expected/wms_custom_projection_not_specified.xml b/msautotest/wxs/expected/wms_custom_projection_not_specified.xml new file mode 100644 index 0000000000..b29dabaec1 --- /dev/null +++ b/msautotest/wxs/expected/wms_custom_projection_not_specified.xml @@ -0,0 +1,6 @@ + + + +msWMSLoadGetMapParams(): WMS server error. Invalid CRS given : CRS must be valid for all requested layers. + + diff --git a/msautotest/wxs/expected/wms_dimension_cap.xml b/msautotest/wxs/expected/wms_dimension_cap.xml index 65e7bb18e0..e0a563882c 100644 --- a/msautotest/wxs/expected/wms_dimension_cap.xml +++ b/msautotest/wxs/expected/wms_dimension_cap.xml @@ -7,10 +7,9 @@ Content-Type: application/vnd.ogc.wms_xml; charset=UTF-8 ]> - OGC:WMS - + wms_dimesion @@ -39,6 +38,7 @@ Content-Type: application/vnd.ogc.wms_xml; charset=UTF-8 image/tiff application/vnd.google-earth.kml+xml application/vnd.google-earth.kmz + application/vnd.mapbox-vector-tile application/x-protobuf application/json @@ -77,28 +77,28 @@ Content-Type: application/vnd.ogc.wms_xml; charset=UTF-8 wms_dimesion - + wms_dimesion wms_dimesion EPSG:4326 - + + minx="0.000178" miny="-0.002134" maxx="0.003420" maxy="0.000314" /> - lakes_elev - Lakes - EPSG:4326 - - - - 500, 490, 480 - - first, second, third - - text/xml - - + lakes_elev + Lakes + EPSG:4326 + + + + 500, 490, 480 + + first, second, third + + text/xml + + - lakes_elev_range - Lakes - EPSG:4326 - - - - 490/800 - - text/xml - - + lakes_elev_range + Lakes + EPSG:4326 + + + + 490/800 + + text/xml + + - lakes_elev_multi_range - Lakes - EPSG:4326 - - - - 480/500,800/900 - - text/xml - - + lakes_elev_multi_range + Lakes + EPSG:4326 + + + + 480/500,800/900 + + text/xml + + - lakes_elev_range - Lakes - EPSG:4326 - - 0.00017826 - 0.003420 - -0.00213 - 0.00031377 - - - 490/800 - - text/xml - - + lakes_elev_range + Lakes + EPSG:4326 + + 0.000178 + 0.003420 + -0.002134 + 0.000314 + + + 490/800 + + text/xml + + - lakes_elev_multi_range - Lakes - EPSG:4326 - - 0.00017826 - 0.003420 - -0.00213 - 0.00031377 - - - 480/500,800/900 - - text/xml - - + lakes_elev_multi_range + Lakes + EPSG:4326 + + 0.000178 + 0.003420 + -0.002134 + 0.000314 + + + 480/500,800/900 + + text/xml + + + land_shallow_topo_2048 Land Surface, Shallow Water, and Shaded Topography @@ -158,10 +157,10 @@ Content-Type: application/vnd.ogc.wms_xml; charset=UTF-8 EROS
EPSG:4326 - + + minx="-180.000000" miny="-90.000000" maxx="180.000000" maxy="90.000000" + resx="0.17578125" resy="0.17578125" /> @@ -180,14 +179,14 @@ Content-Type: application/vnd.ogc.wms_xml; charset=UTF-8 Vectors Vectors Vector layers - + rivers Rivers @@ -197,9 +196,9 @@ Content-Type: application/vnd.ogc.wms_xml; charset=UTF-8 world EPSG:4326 - + + minx="-164.624557" miny="-36.904354" maxx="161.065826" maxy="72.234184" /> text/html @@ -219,28 +218,28 @@ Content-Type: application/vnd.ogc.wms_xml; charset=UTF-8 - toronto - Toronto Landsat 5 TM - Toronto Landsat 5 TM - - Toronto - Landsat - TM - - EPSG:26917 - EPSG:4326 - - - - text/html - - - - image/tiff - - + toronto + Toronto Landsat 5 TM + Toronto Landsat 5 TM + + Toronto + Landsat + TM + + EPSG:26917 + EPSG:4326 + + + + text/html + + + + image/tiff + + diff --git a/msautotest/wxs/expected/wms_get_map_ext_sld_fileproto.xml b/msautotest/wxs/expected/wms_get_map_ext_sld_fileproto.xml index 6a1a4ada4f..8a19ee3377 100644 --- a/msautotest/wxs/expected/wms_get_map_ext_sld_fileproto.xml +++ b/msautotest/wxs/expected/wms_get_map_ext_sld_fileproto.xml @@ -3,6 +3,6 @@ msSLDApplySLDURL: WMS server error. Could not open SLD file:///etc/passwd and save it in a temporary file. Please make sure that the sld url is valid and that the temporary path is set. The temporary path can be defined for example by setting TEMPPATH in the map file. Please check the MapServer documentation on temporary path settings. -msHTTPExecuteRequests(): HTTP request error. HTTP: request failed with curl error code 1 (Protocol file not supported or disabled in libcurl) for file:///etc/passwd +msHTTPExecuteRequests(): HTTP request error. HTTP: request failed with curl error code 1 (Protocol "file" not supported or disabled in libcurl) for file:///etc/passwd diff --git a/msautotest/wxs/expected/wms_get_map_ext_sld_proto.xml b/msautotest/wxs/expected/wms_get_map_ext_sld_proto.xml index 062ce29297..b27bf2b258 100644 --- a/msautotest/wxs/expected/wms_get_map_ext_sld_proto.xml +++ b/msautotest/wxs/expected/wms_get_map_ext_sld_proto.xml @@ -3,6 +3,6 @@ msSLDApplySLDURL: WMS server error. Could not open SLD myproto://localhost:8000/wxs/etc/repeat.sld.notfound and save it in a temporary file. Please make sure that the sld url is valid and that the temporary path is set. The temporary path can be defined for example by setting TEMPPATH in the map file. Please check the MapServer documentation on temporary path settings. -msHTTPExecuteRequests(): HTTP request error. HTTP: request failed with curl error code 1 (Protocol myproto not supported or disabled in libcurl) for myproto://localhost:8000/wxs/etc/repeat.sld.notfound +msHTTPExecuteRequests(): HTTP request error. HTTP: request failed with curl error code 1 (Protocol "myproto" not supported or disabled in libcurl) for myproto://localhost:8000/wxs/etc/repeat.sld.notfound diff --git a/msautotest/wxs/expected/wms_get_map_line_elsefilter_no_symbolizer_sld.png b/msautotest/wxs/expected/wms_get_map_line_elsefilter_no_symbolizer_sld.png new file mode 100644 index 0000000000..be80c1db2d Binary files /dev/null and b/msautotest/wxs/expected/wms_get_map_line_elsefilter_no_symbolizer_sld.png differ diff --git a/msautotest/wxs/expected/wms_get_map_mark_symbol_sld_legend.png b/msautotest/wxs/expected/wms_get_map_mark_symbol_sld_legend.png new file mode 100644 index 0000000000..e7d617f52a Binary files /dev/null and b/msautotest/wxs/expected/wms_get_map_mark_symbol_sld_legend.png differ diff --git a/msautotest/wxs/expected/wms_get_map_missing_styles.xml b/msautotest/wxs/expected/wms_get_map_missing_styles.xml index 880f04fcd6..20363b921f 100644 --- a/msautotest/wxs/expected/wms_get_map_missing_styles.xml +++ b/msautotest/wxs/expected/wms_get_map_missing_styles.xml @@ -2,6 +2,6 @@ -msWMSLoadGetMapParams(): WMS server error. Missing required parameter STYLES. Note to service administrators: defining the "wms_allow_getmap_without_styles" "true" MAP.WEB.METADATA item will disable this check (backward compatibility with behaviour of MapServer < 8.0) +msWMSLoadGetMapParams(): WMS server error. Missing required parameter STYLES. Note to service administrators: defining the "wms_allow_getmap_without_styles" "true" MAP.WEB.METADATA item will disable this check (backward compatibility with behavior of MapServer < 8.0) diff --git a/msautotest/wxs/expected/wms_get_map_multi_layers_one_sld_on_one_layer.png b/msautotest/wxs/expected/wms_get_map_multi_layers_one_sld_on_one_layer.png index 7038cf6606..efc9cf0898 100644 Binary files a/msautotest/wxs/expected/wms_get_map_multi_layers_one_sld_on_one_layer.png and b/msautotest/wxs/expected/wms_get_map_multi_layers_one_sld_on_one_layer.png differ diff --git a/msautotest/wxs/expected/wms_get_map_multi_layers_one_sld_on_one_layer_postgis.png b/msautotest/wxs/expected/wms_get_map_multi_layers_one_sld_on_one_layer_postgis.png index 7038cf6606..efc9cf0898 100644 Binary files a/msautotest/wxs/expected/wms_get_map_multi_layers_one_sld_on_one_layer_postgis.png and b/msautotest/wxs/expected/wms_get_map_multi_layers_one_sld_on_one_layer_postgis.png differ diff --git a/msautotest/wxs/expected/wms_get_map_polygon.kmz b/msautotest/wxs/expected/wms_get_map_polygon.kmz index 57f45f97f8..b106df63e3 100644 Binary files a/msautotest/wxs/expected/wms_get_map_polygon.kmz and b/msautotest/wxs/expected/wms_get_map_polygon.kmz differ diff --git a/msautotest/wxs/expected/wms_get_map_polygon_postgis_boxtoken.png b/msautotest/wxs/expected/wms_get_map_polygon_postgis_boxtoken.png new file mode 100644 index 0000000000..96068aeada Binary files /dev/null and b/msautotest/wxs/expected/wms_get_map_polygon_postgis_boxtoken.png differ diff --git a/msautotest/wxs/expected/wms_get_map_symbol_ext_svg_sld.png b/msautotest/wxs/expected/wms_get_map_symbol_ext_svg_sld.png index 974d80dbe2..eccbf9cad5 100644 Binary files a/msautotest/wxs/expected/wms_get_map_symbol_ext_svg_sld.png and b/msautotest/wxs/expected/wms_get_map_symbol_ext_svg_sld.png differ diff --git a/msautotest/wxs/expected/wms_get_map_tileindexmixedsrs.tif b/msautotest/wxs/expected/wms_get_map_tileindexmixedsrs.tif index f72fc81881..d6e6de2c7c 100644 Binary files a/msautotest/wxs/expected/wms_get_map_tileindexmixedsrs.tif and b/msautotest/wxs/expected/wms_get_map_tileindexmixedsrs.tif differ diff --git a/msautotest/wxs/expected/wms_getfeatureinfo130_empty.txt b/msautotest/wxs/expected/wms_getfeatureinfo130_empty.txt new file mode 100644 index 0000000000..3b3122de8a --- /dev/null +++ b/msautotest/wxs/expected/wms_getfeatureinfo130_empty.txt @@ -0,0 +1,5 @@ +Status: 302 Found +Uri: https://example.com/empty.html +Location: https://example.com/empty.html +Content-Type: text/html + diff --git a/msautotest/wxs/expected/wms_getfeatureinfo_float64_raster.json b/msautotest/wxs/expected/wms_getfeatureinfo_float64_raster.json new file mode 100644 index 0000000000..26e0c11cf0 --- /dev/null +++ b/msautotest/wxs/expected/wms_getfeatureinfo_float64_raster.json @@ -0,0 +1,8 @@ +{ +"type": "FeatureCollection", +"name": "float64", +"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:EPSG::2157" } }, +"features": [ +{ "type": "Feature", "properties": { "x": "600182.31", "y": "628802.89", "value_0": 114140618.0, "value_list": "114140618", "red": "255", "green": "255", "blue": "255" }, "geometry": { "type": "Point", "coordinates": [ 600182.310000000055879, 628802.89000000001397 ] } } +] +} diff --git a/msautotest/wxs/expected/wms_getfeatureinfo_int32_raster.json b/msautotest/wxs/expected/wms_getfeatureinfo_int32_raster.json new file mode 100644 index 0000000000..3d2826a5ec --- /dev/null +++ b/msautotest/wxs/expected/wms_getfeatureinfo_int32_raster.json @@ -0,0 +1,8 @@ +{ +"type": "FeatureCollection", +"name": "int32", +"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:EPSG::2157" } }, +"features": [ +{ "type": "Feature", "properties": { "x": "600182.31", "y": "628802.89", "value_0": 114140618, "value_list": "114140618", "red": "255", "green": "255", "blue": "255" }, "geometry": { "type": "Point", "coordinates": [ 600182.310000000055879, 628802.89000000001397 ] } } +] +} diff --git a/msautotest/wxs/expected/wms_getmap130transparentinvalidexception.xml b/msautotest/wxs/expected/wms_getmap130transparentinvalidexception.xml new file mode 100644 index 0000000000..b17da6ff3b --- /dev/null +++ b/msautotest/wxs/expected/wms_getmap130transparentinvalidexception.xml @@ -0,0 +1,8 @@ +Content-Type: text/xml; charset=UTF-8 + + + + +msWMSLoadGetMapParams(): WMS server error. Value for TRANSPARENT must be either TRUE or FALSE. + + diff --git a/msautotest/wxs/expected/wms_getstyles1.xml b/msautotest/wxs/expected/wms_getstyles1.xml new file mode 100644 index 0000000000..c9ab4d3e25 --- /dev/null +++ b/msautotest/wxs/expected/wms_getstyles1.xml @@ -0,0 +1,19 @@ + + +Test1 + + + + + +#ff0000 +2.00 +10.00 10.00 + + + + + + + + diff --git a/msautotest/wxs/expected/wms_getstyles2.xml b/msautotest/wxs/expected/wms_getstyles2.xml new file mode 100644 index 0000000000..10494ae614 --- /dev/null +++ b/msautotest/wxs/expected/wms_getstyles2.xml @@ -0,0 +1,27 @@ + + +Test2 + + + + + +tostring([FID],"%d") + + + +0.5 +0.5 + + + + +#000000 + + + + + + + + diff --git a/msautotest/wxs/expected/wms_getstyles_expressions1.xml b/msautotest/wxs/expected/wms_getstyles_expressions1.xml index da140d1ce2..bacc2e3715 100644 --- a/msautotest/wxs/expected/wms_getstyles_expressions1.xml +++ b/msautotest/wxs/expected/wms_getstyles_expressions1.xml @@ -4,7 +4,7 @@ -FID1FID10 +FID1FID10 diff --git a/msautotest/wxs/expected/wms_getstyles_expressions13.xml b/msautotest/wxs/expected/wms_getstyles_expressions13.xml new file mode 100644 index 0000000000..33d125496d --- /dev/null +++ b/msautotest/wxs/expected/wms_getstyles_expressions13.xml @@ -0,0 +1,26 @@ + + +Test13 + + + +FID2 +FID4 +FID6 + + + +square + +#dc0000 + + +1 + + + + + + + + diff --git a/msautotest/wxs/expected/wms_getstyles_expressions14.xml b/msautotest/wxs/expected/wms_getstyles_expressions14.xml new file mode 100644 index 0000000000..1551b780ee --- /dev/null +++ b/msautotest/wxs/expected/wms_getstyles_expressions14.xml @@ -0,0 +1,24 @@ + + +Test14 + + + +FID2 + + + +square + +#dc0000 + + +1 + + + + + + + + diff --git a/msautotest/wxs/expected/wms_getstyles_expressions15.xml b/msautotest/wxs/expected/wms_getstyles_expressions15.xml new file mode 100644 index 0000000000..98125c7fcd --- /dev/null +++ b/msautotest/wxs/expected/wms_getstyles_expressions15.xml @@ -0,0 +1,23 @@ + + +Test15 + + + + + + +square + +#dc0000 + + +1 + + + + + + + + diff --git a/msautotest/wxs/expected/wms_getstyles_expressions16.xml b/msautotest/wxs/expected/wms_getstyles_expressions16.xml new file mode 100644 index 0000000000..0af9ee8954 --- /dev/null +++ b/msautotest/wxs/expected/wms_getstyles_expressions16.xml @@ -0,0 +1,25 @@ + + +Test16 + + + +locationtypeprimary location +locationtypesecondary location + + + +square + +#dc0000 + + +1 + + + + + + + + diff --git a/msautotest/wxs/expected/wms_getstyles_expressions17.xml b/msautotest/wxs/expected/wms_getstyles_expressions17.xml new file mode 100644 index 0000000000..7c6035be93 --- /dev/null +++ b/msautotest/wxs/expected/wms_getstyles_expressions17.xml @@ -0,0 +1,25 @@ + + +Test17 + + + +poi"main" square +poicity's centre + + + +square + +#dc0000 + + +1 + + + + + + + + diff --git a/msautotest/wxs/expected/wms_getstyles_expressions18.xml b/msautotest/wxs/expected/wms_getstyles_expressions18.xml new file mode 100644 index 0000000000..534985ce77 --- /dev/null +++ b/msautotest/wxs/expected/wms_getstyles_expressions18.xml @@ -0,0 +1,25 @@ + + +Test18 + + + +locationtypeprimary location +locationtypesecondary location + + + +square + +#dc0000 + + +1 + + + + + + + + diff --git a/msautotest/wxs/expected/wms_getstyles_expressions19.xml b/msautotest/wxs/expected/wms_getstyles_expressions19.xml new file mode 100644 index 0000000000..832521549c --- /dev/null +++ b/msautotest/wxs/expected/wms_getstyles_expressions19.xml @@ -0,0 +1,24 @@ + + +Test19 + + + +locationtypeprimary location + + + +square + +#dc0000 + + +1 + + + + + + + + diff --git a/msautotest/wxs/expected/wms_getstyles_expressions2.xml b/msautotest/wxs/expected/wms_getstyles_expressions2.xml index 99a4bdd51e..2c6b259379 100644 --- a/msautotest/wxs/expected/wms_getstyles_expressions2.xml +++ b/msautotest/wxs/expected/wms_getstyles_expressions2.xml @@ -4,7 +4,7 @@ -FID1FID10 +FID1FID10 diff --git a/msautotest/wxs/expected/wms_getstyles_expressions20.xml b/msautotest/wxs/expected/wms_getstyles_expressions20.xml new file mode 100644 index 0000000000..58fd487f45 --- /dev/null +++ b/msautotest/wxs/expected/wms_getstyles_expressions20.xml @@ -0,0 +1,24 @@ + + +Test20 + + + +locationtypeprimary location + + + +square + +#dc0000 + + +1 + + + + + + + + diff --git a/msautotest/wxs/expected/wms_getstyles_expressions21.xml b/msautotest/wxs/expected/wms_getstyles_expressions21.xml new file mode 100644 index 0000000000..c92ffcc79c --- /dev/null +++ b/msautotest/wxs/expected/wms_getstyles_expressions21.xml @@ -0,0 +1,24 @@ + + +Test21 + + + +FID1FID10 + + + +square + +#dc0000 + + +1 + + + + + + + + diff --git a/msautotest/wxs/expected/wms_getstyles_expressions22.xml b/msautotest/wxs/expected/wms_getstyles_expressions22.xml new file mode 100644 index 0000000000..342d7b7464 --- /dev/null +++ b/msautotest/wxs/expected/wms_getstyles_expressions22.xml @@ -0,0 +1,24 @@ + + +Test22 + + + +locationtypeprimary location locationtype secondary location + + + +square + +#dc0000 + + +1 + + + + + + + + diff --git a/msautotest/wxs/expected/wms_getstyles_expressions23.xml b/msautotest/wxs/expected/wms_getstyles_expressions23.xml new file mode 100644 index 0000000000..5b3f87d0b5 --- /dev/null +++ b/msautotest/wxs/expected/wms_getstyles_expressions23.xml @@ -0,0 +1,24 @@ + + +Test23 + + + +FID1FID10 + + + +square + +#dc0000 + + +1 + + + + + + + + diff --git a/msautotest/wxs/expected/wms_getstyles_expressions24.xml b/msautotest/wxs/expected/wms_getstyles_expressions24.xml new file mode 100644 index 0000000000..b3f98d9918 --- /dev/null +++ b/msautotest/wxs/expected/wms_getstyles_expressions24.xml @@ -0,0 +1,28 @@ + + +Test24 + + + +Not Test +Property1Not Applicable + + + + +And Test +Property1With AND value + + + + +Or Test +Property1With OR value + + + + + + + + diff --git a/msautotest/wxs/expected/wms_getstyles_expressions25.xml b/msautotest/wxs/expected/wms_getstyles_expressions25.xml new file mode 100644 index 0000000000..f592787f94 --- /dev/null +++ b/msautotest/wxs/expected/wms_getstyles_expressions25.xml @@ -0,0 +1,28 @@ + + +Test25 + + + +Or Test +Property1Not valueProperty1An Or value + + + + +And Test +Property1AnProperty1A Not value + + + + +Not Test +Property1A Not value + + + + + + + + diff --git a/msautotest/wxs/expected/wms_getstyles_expressions26.xml b/msautotest/wxs/expected/wms_getstyles_expressions26.xml new file mode 100644 index 0000000000..3e38710a56 --- /dev/null +++ b/msautotest/wxs/expected/wms_getstyles_expressions26.xml @@ -0,0 +1,24 @@ + + +Test26 + + + +FID1FID10 + + + +square + +#dc0000 + + +1 + + + + + + + + diff --git a/msautotest/wxs/expected/wms_getstyles_expressions27.xml b/msautotest/wxs/expected/wms_getstyles_expressions27.xml new file mode 100644 index 0000000000..cc0d816135 --- /dev/null +++ b/msautotest/wxs/expected/wms_getstyles_expressions27.xml @@ -0,0 +1,24 @@ + + +Test27 + + + +FID1FID10 + + + +square + +#dc0000 + + +1 + + + + + + + + diff --git a/msautotest/wxs/expected/wms_getstyles_expressions28.xml b/msautotest/wxs/expected/wms_getstyles_expressions28.xml new file mode 100644 index 0000000000..aa13973e8d --- /dev/null +++ b/msautotest/wxs/expected/wms_getstyles_expressions28.xml @@ -0,0 +1,24 @@ + + +Test28 + + + +FID1FID10 + + + +square + +#dc0000 + + +1 + + + + + + + + diff --git a/msautotest/wxs/expected/wms_getstyles_expressions29.xml b/msautotest/wxs/expected/wms_getstyles_expressions29.xml new file mode 100644 index 0000000000..c9d7d8adfd --- /dev/null +++ b/msautotest/wxs/expected/wms_getstyles_expressions29.xml @@ -0,0 +1,24 @@ + + +Test29 + + + +FID1FID10 + + + +square + +#dc0000 + + +1 + + + + + + + + diff --git a/msautotest/wxs/expected/wms_getstyles_expressions3.xml b/msautotest/wxs/expected/wms_getstyles_expressions3.xml index 0dc2e9add1..79e4629349 100644 --- a/msautotest/wxs/expected/wms_getstyles_expressions3.xml +++ b/msautotest/wxs/expected/wms_getstyles_expressions3.xml @@ -4,7 +4,7 @@ -FID1FID10 +FID1FID10 diff --git a/msautotest/wxs/expected/wms_getstyles_expressions30.xml b/msautotest/wxs/expected/wms_getstyles_expressions30.xml new file mode 100644 index 0000000000..1fd786a807 --- /dev/null +++ b/msautotest/wxs/expected/wms_getstyles_expressions30.xml @@ -0,0 +1,24 @@ + + +Test30 + + + +FID! 1 + + + +square + +#dc0000 + + +1 + + + + + + + + diff --git a/msautotest/wxs/expected/wms_getstyles_expressions31.xml b/msautotest/wxs/expected/wms_getstyles_expressions31.xml new file mode 100644 index 0000000000..38adfa195c --- /dev/null +++ b/msautotest/wxs/expected/wms_getstyles_expressions31.xml @@ -0,0 +1,24 @@ + + +Test31 + + + +FID! 1 + + + +square + +#dc0000 + + +1 + + + + + + + + diff --git a/msautotest/wxs/expected/wms_getstyles_expressions32.xml b/msautotest/wxs/expected/wms_getstyles_expressions32.xml new file mode 100644 index 0000000000..acc4d4ef9e --- /dev/null +++ b/msautotest/wxs/expected/wms_getstyles_expressions32.xml @@ -0,0 +1,24 @@ + + +Test32 + + + +field_le0field_le6 + + + +square + +#00b050 + + +1 + + + + + + + + diff --git a/msautotest/wxs/expected/wms_getstyles_expressions33.xml b/msautotest/wxs/expected/wms_getstyles_expressions33.xml new file mode 100644 index 0000000000..e9fdfc4ded --- /dev/null +++ b/msautotest/wxs/expected/wms_getstyles_expressions33.xml @@ -0,0 +1,24 @@ + + +Test33 + + + +field_ge0field_ge6 + + + +square + +#00b050 + + +1 + + + + + + + + diff --git a/msautotest/wxs/expected/wms_getstyles_expressions34.xml b/msautotest/wxs/expected/wms_getstyles_expressions34.xml new file mode 100644 index 0000000000..981b17c9ed --- /dev/null +++ b/msautotest/wxs/expected/wms_getstyles_expressions34.xml @@ -0,0 +1,24 @@ + + +Test34 + + + +field_lt0field_lt10 + + + +square + +#00b050 + + +1 + + + + + + + + diff --git a/msautotest/wxs/expected/wms_getstyles_expressions35.xml b/msautotest/wxs/expected/wms_getstyles_expressions35.xml new file mode 100644 index 0000000000..6cfc979e6b --- /dev/null +++ b/msautotest/wxs/expected/wms_getstyles_expressions35.xml @@ -0,0 +1,24 @@ + + +Test35 + + + +field_gt0field_gt10 + + + +square + +#00b050 + + +1 + + + + + + + + diff --git a/msautotest/wxs/expected/wms_getstyles_expressions36.xml b/msautotest/wxs/expected/wms_getstyles_expressions36.xml new file mode 100644 index 0000000000..4d43bc3bae --- /dev/null +++ b/msautotest/wxs/expected/wms_getstyles_expressions36.xml @@ -0,0 +1,24 @@ + + +Test36 + + + +field_ne0field_ne99 + + + +square + +#00b050 + + +1 + + + + + + + + diff --git a/msautotest/wxs/expected/wms_getstyles_expressions37.xml b/msautotest/wxs/expected/wms_getstyles_expressions37.xml new file mode 100644 index 0000000000..c1b1bb7bcf --- /dev/null +++ b/msautotest/wxs/expected/wms_getstyles_expressions37.xml @@ -0,0 +1,24 @@ + + +Test37 + + + +field_le0field_le6 + + + +square + +#00b050 + + +1 + + + + + + + + diff --git a/msautotest/wxs/expected/wms_getstyles_expressions4.xml b/msautotest/wxs/expected/wms_getstyles_expressions4.xml index 95a271ed7f..239d9a5754 100644 --- a/msautotest/wxs/expected/wms_getstyles_expressions4.xml +++ b/msautotest/wxs/expected/wms_getstyles_expressions4.xml @@ -4,7 +4,7 @@ -FID1FID10 +FID1FID10 diff --git a/msautotest/wxs/expected/wms_getstyles_expressions5.xml b/msautotest/wxs/expected/wms_getstyles_expressions5.xml index 3255b7f3cb..3205643de2 100644 --- a/msautotest/wxs/expected/wms_getstyles_expressions5.xml +++ b/msautotest/wxs/expected/wms_getstyles_expressions5.xml @@ -4,7 +4,7 @@ -FID1FID10 +FID1FID10 diff --git a/msautotest/wxs/expected/wms_getstyles_expressions6.xml b/msautotest/wxs/expected/wms_getstyles_expressions6.xml index da50dabeb7..7c8b0e8459 100644 --- a/msautotest/wxs/expected/wms_getstyles_expressions6.xml +++ b/msautotest/wxs/expected/wms_getstyles_expressions6.xml @@ -4,7 +4,7 @@ -FID1FID10 +FID1FID10 diff --git a/msautotest/wxs/expected/wms_gradient_legend.png b/msautotest/wxs/expected/wms_gradient_legend.png new file mode 100644 index 0000000000..11944bc9d6 Binary files /dev/null and b/msautotest/wxs/expected/wms_gradient_legend.png differ diff --git a/msautotest/wxs/expected/wms_grid_reproj_to_3857_non_square_pixels_beyond_validity.png b/msautotest/wxs/expected/wms_grid_reproj_to_3857_non_square_pixels_beyond_validity.png index 1966daf623..5190670606 100644 Binary files a/msautotest/wxs/expected/wms_grid_reproj_to_3857_non_square_pixels_beyond_validity.png and b/msautotest/wxs/expected/wms_grid_reproj_to_3857_non_square_pixels_beyond_validity.png differ diff --git a/msautotest/wxs/expected/wms_grid_reproj_to_3857_square_pixels_beyond_validity.png b/msautotest/wxs/expected/wms_grid_reproj_to_3857_square_pixels_beyond_validity.png index bca97786e8..0cd529b343 100644 Binary files a/msautotest/wxs/expected/wms_grid_reproj_to_3857_square_pixels_beyond_validity.png and b/msautotest/wxs/expected/wms_grid_reproj_to_3857_square_pixels_beyond_validity.png differ diff --git a/msautotest/wxs/expected/wms_grid_reproj_to_3857_square_pixels_within_validity.png b/msautotest/wxs/expected/wms_grid_reproj_to_3857_square_pixels_within_validity.png index 0466590656..3cfa46cc64 100644 Binary files a/msautotest/wxs/expected/wms_grid_reproj_to_3857_square_pixels_within_validity.png and b/msautotest/wxs/expected/wms_grid_reproj_to_3857_square_pixels_within_validity.png differ diff --git a/msautotest/wxs/expected/wms_inspire_cap.xml b/msautotest/wxs/expected/wms_inspire_cap.xml index c63290cfc7..d352a16bd1 100644 --- a/msautotest/wxs/expected/wms_inspire_cap.xml +++ b/msautotest/wxs/expected/wms_inspire_cap.xml @@ -1,6 +1,5 @@ - - + WMS INSPIRE Testdienst @@ -57,6 +56,7 @@ image/tiff application/vnd.google-earth.kml+xml application/vnd.google-earth.kmz + application/vnd.mapbox-vector-tile application/x-protobuf application/json @@ -116,21 +116,21 @@ EPSG:3046 EPSG:3047 - 12.6101 - 12.7593 - 53.4177 - 53.4404 + 12.610067 + 12.759267 + 53.417736 + 53.440368 + minx="53.417736" miny="12.610067" maxx="53.440368" maxy="12.759267" /> + minx="53.417736" miny="12.610067" maxx="53.440368" maxy="12.759267" /> + minx="53.417736" miny="12.610067" maxx="53.440368" maxy="12.759267" /> - TN.CommonTransportElements - TN.CommonTransportElements - Nicht verfügbar - - no-keyword here - - EPSG:4326 - - 12.6108 - 12.7584 - 53.4183 - 53.44 - - - - - - - - - - - - - - - - - - text/xml - - + TN.CommonTransportElements + TN.CommonTransportElements + Nicht verfügbar + + no-keyword here + + EPSG:4326 + + 12.610800 + 12.758400 + 53.418300 + 53.440000 + + + + + + + + + + + + + + + + + + text/xml + + - TN.CommonTransportElements - TN.CommonTransportElements - Nicht verfügbar - - no-keyword here - - EPSG:4326 - - - - - - - - - - - - - - - - - - text/xml - - + TN.CommonTransportElements + TN.CommonTransportElements + Nicht verfügbar + + no-keyword here + + EPSG:4326 + + + + + + + + + + + + + + + + + + text/xml + + - + @@ -332,17 +332,17 @@ no-keyword here EPSG:25833 - + + minx="12.610968" miny="53.418436" maxx="12.758457" maxy="53.437931" /> + minx="12.610968" miny="53.418436" maxx="12.758457" maxy="53.437931" /> + minx="12.610968" miny="53.418436" maxx="12.758457" maxy="53.437931" /> - TN.RoadTransportNetwork - TN.RoadTransportNetwork - Nicht verfügbar - - no-keyword here - - EPSG:4326 - - - - - - - - - - - - - - - - - - text/xml - - + TN.RoadTransportNetwork + TN.RoadTransportNetwork + Nicht verfügbar + + no-keyword here + + EPSG:4326 + + + + + + + + + + + + + + + + + + text/xml + + TN.RoadTransportNetwork.RoadLink Straßensegment @@ -429,17 +429,17 @@ no-keyword here EPSG:25833 - + + minx="12.631673" miny="53.418846" maxx="12.758338" maxy="53.435725" /> + minx="12.631673" miny="53.418846" maxx="12.758338" maxy="53.435725" /> + minx="12.631673" miny="53.418846" maxx="12.758338" maxy="53.435725" /> no-keyword here EPSG:25833 - + + minx="12.631525" miny="53.418754" maxx="12.758358" maxy="53.435815" /> + minx="12.631525" miny="53.418754" maxx="12.758358" maxy="53.435815" /> + minx="12.631525" miny="53.418754" maxx="12.758358" maxy="53.435815" /> no-keyword here EPSG:25833 - + + minx="12.669519" miny="53.429872" maxx="12.676042" maxy="53.432040" /> + minx="12.669519" miny="53.429872" maxx="12.676042" maxy="53.432040" /> + minx="12.669519" miny="53.429872" maxx="12.676042" maxy="53.432040" /> no-keyword here EPSG:25833 - + + minx="12.631377" miny="53.418662" maxx="12.758377" maxy="53.435905" /> + minx="12.631377" miny="53.418662" maxx="12.758377" maxy="53.435905" /> + minx="12.631377" miny="53.418662" maxx="12.758377" maxy="53.435905" /> - TN.RailTransportNetwork - TN.RailTransportNetwork - Nicht verfügbar - - no-keyword here - - EPSG:4326 - - - - - - - - - - - - - - - - - - text/xml - - + TN.RailTransportNetwork + TN.RailTransportNetwork + Nicht verfügbar + + no-keyword here + + EPSG:4326 + + + + + + + + + + + + + + + + + + text/xml + + TN.RailTransportNetwork.RailwayLink Eisenbahnverbindung @@ -685,17 +685,17 @@ no-keyword here EPSG:25833 - + + minx="12.610855" miny="53.428021" maxx="12.718663" maxy="53.439214" /> + minx="12.610855" miny="53.428021" maxx="12.718663" maxy="53.439214" /> + minx="12.610855" miny="53.428021" maxx="12.718663" maxy="53.439214" /> no-keyword here EPSG:25833 - + + minx="12.682559" miny="53.430400" maxx="12.693541" maxy="53.433999" /> + minx="12.682559" miny="53.430400" maxx="12.693541" maxy="53.433999" /> + minx="12.682559" miny="53.430400" maxx="12.693541" maxy="53.433999" /> no-keyword here EPSG:25833 - + + minx="12.683703" miny="53.431010" maxx="12.692433" maxy="53.433041" /> + minx="12.683703" miny="53.431010" maxx="12.692433" maxy="53.433041" /> + minx="12.683703" miny="53.431010" maxx="12.692433" maxy="53.433041" /> no-keyword here EPSG:25833 - + + minx="12.610785" miny="53.427930" maxx="12.718668" maxy="53.439304" /> + minx="12.610785" miny="53.427930" maxx="12.718668" maxy="53.439304" /> + minx="12.610785" miny="53.427930" maxx="12.718668" maxy="53.439304" /> - OGC:WMS INSPIRE test service @@ -58,6 +57,7 @@ image/tiff application/vnd.google-earth.kml+xml application/vnd.google-earth.kmz + application/vnd.mapbox-vector-tile application/x-protobuf application/json @@ -118,17 +118,17 @@ EPSG:3045 EPSG:3046 EPSG:3047 - + + minx="12.610067" miny="53.417736" maxx="12.759267" maxy="53.440368" /> + minx="12.610067" miny="53.417736" maxx="12.759267" maxy="53.440368" /> + minx="12.610067" miny="53.417736" maxx="12.759267" maxy="53.440368" /> - TN.CommonTransportElements - TN.CommonTransportElements - - no-keyword here - - EPSG:4326 - - - - - - - - - - - - - - - - - - text/xml - - + TN.CommonTransportElements + TN.CommonTransportElements + + no-keyword here + + EPSG:4326 + + + + + + + + + + + + + + + + + + text/xml + + - + @@ -328,17 +328,17 @@ no-keyword here EPSG:25833 - + + minx="12.610968" miny="53.418436" maxx="12.758457" maxy="53.437931" /> + minx="12.610968" miny="53.418436" maxx="12.758457" maxy="53.437931" /> + minx="12.610968" miny="53.418436" maxx="12.758457" maxy="53.437931" /> - TN.RoadTransportNetwork - TN.RoadTransportNetwork - - no-keyword here - - EPSG:4326 - - - - - - - - - - - - - - - - - - text/xml - - + TN.RoadTransportNetwork + TN.RoadTransportNetwork + + no-keyword here + + EPSG:4326 + + + + + + + + + + + + + + + + + + text/xml + + TN.RoadTransportNetwork.RoadLink Road link @@ -423,17 +423,17 @@ no-keyword here EPSG:25833 - + + minx="12.631673" miny="53.418846" maxx="12.758338" maxy="53.435725" /> + minx="12.631673" miny="53.418846" maxx="12.758338" maxy="53.435725" /> + minx="12.631673" miny="53.418846" maxx="12.758338" maxy="53.435725" /> no-keyword here EPSG:25833 - + + minx="12.631525" miny="53.418754" maxx="12.758358" maxy="53.435815" /> + minx="12.631525" miny="53.418754" maxx="12.758358" maxy="53.435815" /> + minx="12.631525" miny="53.418754" maxx="12.758358" maxy="53.435815" /> no-keyword here EPSG:25833 - + + minx="12.669519" miny="53.429872" maxx="12.676042" maxy="53.432040" /> + minx="12.669519" miny="53.429872" maxx="12.676042" maxy="53.432040" /> + minx="12.669519" miny="53.429872" maxx="12.676042" maxy="53.432040" /> no-keyword here EPSG:25833 - + + minx="12.631377" miny="53.418662" maxx="12.758377" maxy="53.435905" /> + minx="12.631377" miny="53.418662" maxx="12.758377" maxy="53.435905" /> + minx="12.631377" miny="53.418662" maxx="12.758377" maxy="53.435905" /> - TN.RailTransportNetwork - TN.RailTransportNetwork - - no-keyword here - - EPSG:4326 - - - - - - - - - - - - - - - - - - text/xml - - + TN.RailTransportNetwork + TN.RailTransportNetwork + + no-keyword here + + EPSG:4326 + + + + + + + + + + + + + + + + + + text/xml + + TN.RailTransportNetwork.RailwayLink Railway link @@ -674,17 +674,17 @@ no-keyword here EPSG:25833 - + + minx="12.610855" miny="53.428021" maxx="12.718663" maxy="53.439214" /> + minx="12.610855" miny="53.428021" maxx="12.718663" maxy="53.439214" /> + minx="12.610855" miny="53.428021" maxx="12.718663" maxy="53.439214" /> no-keyword here EPSG:25833 - + + minx="12.682559" miny="53.430400" maxx="12.693541" maxy="53.433999" /> + minx="12.682559" miny="53.430400" maxx="12.693541" maxy="53.433999" /> + minx="12.682559" miny="53.430400" maxx="12.693541" maxy="53.433999" /> no-keyword here EPSG:25833 - + + minx="12.683703" miny="53.431010" maxx="12.692433" maxy="53.433041" /> + minx="12.683703" miny="53.431010" maxx="12.692433" maxy="53.433041" /> + minx="12.683703" miny="53.431010" maxx="12.692433" maxy="53.433041" /> no-keyword here EPSG:25833 - + + minx="12.610785" miny="53.427930" maxx="12.718668" maxy="53.439304" /> + minx="12.610785" miny="53.427930" maxx="12.718668" maxy="53.439304" /> + minx="12.610785" miny="53.427930" maxx="12.718668" maxy="53.439304" /> - OGC:WMS INSPIRE Testdienst @@ -58,6 +57,7 @@ image/tiff application/vnd.google-earth.kml+xml application/vnd.google-earth.kmz + application/vnd.mapbox-vector-tile application/x-protobuf application/json @@ -118,17 +118,17 @@ EPSG:3045 EPSG:3046 EPSG:3047 - + + minx="12.610067" miny="53.417736" maxx="12.759267" maxy="53.440368" /> + minx="12.610067" miny="53.417736" maxx="12.759267" maxy="53.440368" /> + minx="12.610067" miny="53.417736" maxx="12.759267" maxy="53.440368" /> - TN.CommonTransportElements - TN.CommonTransportElements - Nicht verfügbar - - no-keyword here - - EPSG:4326 - - - - - - - - - - - - - - - - - - text/xml - - + TN.CommonTransportElements + TN.CommonTransportElements + Nicht verfügbar + + no-keyword here + + EPSG:4326 + + + + + + + + + + + + + + + + + + text/xml + + - + @@ -332,17 +332,17 @@ no-keyword here EPSG:25833 - + + minx="12.610968" miny="53.418436" maxx="12.758457" maxy="53.437931" /> + minx="12.610968" miny="53.418436" maxx="12.758457" maxy="53.437931" /> + minx="12.610968" miny="53.418436" maxx="12.758457" maxy="53.437931" /> - TN.RoadTransportNetwork - TN.RoadTransportNetwork - Nicht verfügbar - - no-keyword here - - EPSG:4326 - - - - - - - - - - - - - - - - - - text/xml - - + TN.RoadTransportNetwork + TN.RoadTransportNetwork + Nicht verfügbar + + no-keyword here + + EPSG:4326 + + + + + + + + + + + + + + + + + + text/xml + + TN.RoadTransportNetwork.RoadLink Straßensegment @@ -429,17 +429,17 @@ no-keyword here EPSG:25833 - + + minx="12.631673" miny="53.418846" maxx="12.758338" maxy="53.435725" /> + minx="12.631673" miny="53.418846" maxx="12.758338" maxy="53.435725" /> + minx="12.631673" miny="53.418846" maxx="12.758338" maxy="53.435725" /> no-keyword here EPSG:25833 - + + minx="12.631525" miny="53.418754" maxx="12.758358" maxy="53.435815" /> + minx="12.631525" miny="53.418754" maxx="12.758358" maxy="53.435815" /> + minx="12.631525" miny="53.418754" maxx="12.758358" maxy="53.435815" /> no-keyword here EPSG:25833 - + + minx="12.669519" miny="53.429872" maxx="12.676042" maxy="53.432040" /> + minx="12.669519" miny="53.429872" maxx="12.676042" maxy="53.432040" /> + minx="12.669519" miny="53.429872" maxx="12.676042" maxy="53.432040" /> no-keyword here EPSG:25833 - + + minx="12.631377" miny="53.418662" maxx="12.758377" maxy="53.435905" /> + minx="12.631377" miny="53.418662" maxx="12.758377" maxy="53.435905" /> + minx="12.631377" miny="53.418662" maxx="12.758377" maxy="53.435905" /> - TN.RailTransportNetwork - TN.RailTransportNetwork - Nicht verfügbar - - no-keyword here - - EPSG:4326 - - - - - - - - - - - - - - - - - - text/xml - - + TN.RailTransportNetwork + TN.RailTransportNetwork + Nicht verfügbar + + no-keyword here + + EPSG:4326 + + + + + + + + + + + + + + + + + + text/xml + + TN.RailTransportNetwork.RailwayLink Eisenbahnverbindung @@ -685,17 +685,17 @@ no-keyword here EPSG:25833 - + + minx="12.610855" miny="53.428021" maxx="12.718663" maxy="53.439214" /> + minx="12.610855" miny="53.428021" maxx="12.718663" maxy="53.439214" /> + minx="12.610855" miny="53.428021" maxx="12.718663" maxy="53.439214" /> no-keyword here EPSG:25833 - + + minx="12.682559" miny="53.430400" maxx="12.693541" maxy="53.433999" /> + minx="12.682559" miny="53.430400" maxx="12.693541" maxy="53.433999" /> + minx="12.682559" miny="53.430400" maxx="12.693541" maxy="53.433999" /> no-keyword here EPSG:25833 - + + minx="12.683703" miny="53.431010" maxx="12.692433" maxy="53.433041" /> + minx="12.683703" miny="53.431010" maxx="12.692433" maxy="53.433041" /> + minx="12.683703" miny="53.431010" maxx="12.692433" maxy="53.433041" /> no-keyword here EPSG:25833 - + + minx="12.610785" miny="53.427930" maxx="12.718668" maxy="53.439304" /> + minx="12.610785" miny="53.427930" maxx="12.718668" maxy="53.439304" /> + minx="12.610785" miny="53.427930" maxx="12.718668" maxy="53.439304" /> - - + WMS INSPIRE test service @@ -57,6 +56,7 @@ image/tiff application/vnd.google-earth.kml+xml application/vnd.google-earth.kmz + application/vnd.mapbox-vector-tile application/x-protobuf application/json @@ -116,21 +116,21 @@ EPSG:3046 EPSG:3047 - 12.6101 - 12.7593 - 53.4177 - 53.4404 + 12.610067 + 12.759267 + 53.417736 + 53.440368 + minx="53.417736" miny="12.610067" maxx="53.440368" maxy="12.759267" /> + minx="53.417736" miny="12.610067" maxx="53.440368" maxy="12.759267" /> + minx="53.417736" miny="12.610067" maxx="53.440368" maxy="12.759267" /> - TN.CommonTransportElements - TN.CommonTransportElements - - no-keyword here - - EPSG:4326 - - 12.6108 - 12.7584 - 53.4183 - 53.44 - - - - - - - - - - - - - - - - - - text/xml - - + TN.CommonTransportElements + TN.CommonTransportElements + + no-keyword here + + EPSG:4326 + + 12.610800 + 12.758400 + 53.418300 + 53.440000 + + + + + + + + + + + + + + + + + + text/xml + + - TN.CommonTransportElements - TN.CommonTransportElements - Nicht verfügbar - - no-keyword here - - EPSG:4326 - - 12.6108 - 12.7584 - 53.4183 - 53.44 - - - - - - - - - - - - - - - - - - text/xml - - + TN.CommonTransportElements + TN.CommonTransportElements + Nicht verfügbar + + no-keyword here + + EPSG:4326 + + 12.610800 + 12.758400 + 53.418300 + 53.440000 + + + + + + + + + + + + + + + + + + text/xml + + - TN.RoadTransportNetwork.RoadLink - Transport networks: Road Link - myroadlinklayerabstract - - myroadlinklayerkeyword1 - myroadlinklayerkeyword2 - - - -66.6333 - -59.2921 - 42.3821 - 48.2955 - - - - - - text/xml - - + TN.RoadTransportNetwork.RoadLink + Transport networks: Road Link + myroadlinklayerabstract + + myroadlinklayerkeyword1 + myroadlinklayerkeyword2 + + + -66.633318 + -59.292114 + 42.382054 + 48.295512 + + + + + + text/xml + + + TN.RailTransportNetwork.RailwayLink Transport networks: Railway Link @@ -180,15 +180,15 @@ myrailwaylinklayerkeyword2 - -66.6333 - -59.2921 - 42.3821 - 48.2955 + -66.633318 + -59.292114 + 42.382054 + 48.295512 + minx="42.382054" miny="-66.633318" maxx="48.295512" maxy="-59.292114" /> + minx="42.382054" miny="-66.633318" maxx="48.295512" maxy="-59.292114" /> @@ -213,15 +213,15 @@ myairlinklayerkeyword2 - -66.6333 - -59.2921 - 42.3821 - 48.2955 + -66.633318 + -59.292114 + 42.382054 + 48.295512 + minx="42.382054" miny="-66.633318" maxx="48.295512" maxy="-59.292114" /> + minx="42.382054" miny="-66.633318" maxx="48.295512" maxy="-59.292114" /> diff --git a/msautotest/wxs/expected/wms_inspire_scenario1_cap130_eng.xml b/msautotest/wxs/expected/wms_inspire_scenario1_cap130_eng.xml index 1c1e621bee..21a753ebe1 100644 --- a/msautotest/wxs/expected/wms_inspire_scenario1_cap130_eng.xml +++ b/msautotest/wxs/expected/wms_inspire_scenario1_cap130_eng.xml @@ -1,6 +1,5 @@ - - + WMS myservicetitle @@ -55,6 +54,7 @@ image/tiff application/vnd.google-earth.kml+xml application/vnd.google-earth.kmz + application/vnd.mapbox-vector-tile application/x-protobuf application/json @@ -103,15 +103,15 @@ EPSG:4269 EPSG:3035 - -66.6333 - -59.2921 - 42.3821 - 48.2955 + -66.633300 + -59.292100 + 42.382100 + 48.295500 + minx="42.382100" miny="-66.633300" maxx="48.295500" maxy="-59.292100" /> + minx="42.382100" miny="-66.633300" maxx="48.295500" maxy="-59.292100" /> @@ -127,29 +127,29 @@ - TN.RoadTransportNetwork.RoadLink - Transport networks: Road Link - myroadlinklayerabstract - - myroadlinklayerkeyword1 - myroadlinklayerkeyword2 - - - -66.6333 - -59.2921 - 42.3821 - 48.2955 - - - - - - text/xml - - + TN.RoadTransportNetwork.RoadLink + Transport networks: Road Link + myroadlinklayerabstract + + myroadlinklayerkeyword1 + myroadlinklayerkeyword2 + + + -66.633318 + -59.292114 + 42.382054 + 48.295512 + + + + + + text/xml + + + TN.RailTransportNetwork.RailwayLink Transport networks: Railway Link @@ -180,15 +180,15 @@ myrailwaylinklayerkeyword2 - -66.6333 - -59.2921 - 42.3821 - 48.2955 + -66.633318 + -59.292114 + 42.382054 + 48.295512 + minx="42.382054" miny="-66.633318" maxx="48.295512" maxy="-59.292114" /> + minx="42.382054" miny="-66.633318" maxx="48.295512" maxy="-59.292114" /> @@ -213,15 +213,15 @@ myairlinklayerkeyword2 - -66.6333 - -59.2921 - 42.3821 - 48.2955 + -66.633318 + -59.292114 + 42.382054 + 48.295512 + minx="42.382054" miny="-66.633318" maxx="48.295512" maxy="-59.292114" /> + minx="42.382054" miny="-66.633318" maxx="48.295512" maxy="-59.292114" /> diff --git a/msautotest/wxs/expected/wms_inspire_scenario1_cap130_ger.xml b/msautotest/wxs/expected/wms_inspire_scenario1_cap130_ger.xml index c93d3b8394..b85705496b 100644 --- a/msautotest/wxs/expected/wms_inspire_scenario1_cap130_ger.xml +++ b/msautotest/wxs/expected/wms_inspire_scenario1_cap130_ger.xml @@ -1,6 +1,5 @@ - - + WMS myservicetitleger @@ -55,6 +54,7 @@ image/tiff application/vnd.google-earth.kml+xml application/vnd.google-earth.kmz + application/vnd.mapbox-vector-tile application/x-protobuf application/json @@ -103,15 +103,15 @@ EPSG:4269 EPSG:3035 - -66.6333 - -59.2921 - 42.3821 - 48.2955 + -66.633300 + -59.292100 + 42.382100 + 48.295500 + minx="42.382100" miny="-66.633300" maxx="48.295500" maxy="-59.292100" /> + minx="42.382100" miny="-66.633300" maxx="48.295500" maxy="-59.292100" /> @@ -127,29 +127,29 @@ - TN.RoadTransportNetwork.RoadLink - Verkehrsnetze: Straßensegment - myroadlinklayerabstractger - - myroadlinklayerkeyword1 - myroadlinklayerkeyword2 - - - -66.6333 - -59.2921 - 42.3821 - 48.2955 - - - - - - text/xml - - + TN.RoadTransportNetwork.RoadLink + Verkehrsnetze: Straßensegment + myroadlinklayerabstractger + + myroadlinklayerkeyword1 + myroadlinklayerkeyword2 + + + -66.633318 + -59.292114 + 42.382054 + 48.295512 + + + + + + text/xml + + + TN.RailTransportNetwork.RailwayLink Verkehrsnetze: Eisenbahnverbindung @@ -180,15 +180,15 @@ myrailwaylinklayerkeyword2 - -66.6333 - -59.2921 - 42.3821 - 48.2955 + -66.633318 + -59.292114 + 42.382054 + 48.295512 + minx="42.382054" miny="-66.633318" maxx="48.295512" maxy="-59.292114" /> + minx="42.382054" miny="-66.633318" maxx="48.295512" maxy="-59.292114" /> @@ -213,15 +213,15 @@ myairlinklayerkeyword2 - -66.6333 - -59.2921 - 42.3821 - 48.2955 + -66.633318 + -59.292114 + 42.382054 + 48.295512 + minx="42.382054" miny="-66.633318" maxx="48.295512" maxy="-59.292114" /> + minx="42.382054" miny="-66.633318" maxx="48.295512" maxy="-59.292114" /> diff --git a/msautotest/wxs/expected/wms_inspire_scenario2_cap111.xml b/msautotest/wxs/expected/wms_inspire_scenario2_cap111.xml index 0ba1cc48f4..c479762e67 100644 --- a/msautotest/wxs/expected/wms_inspire_scenario2_cap111.xml +++ b/msautotest/wxs/expected/wms_inspire_scenario2_cap111.xml @@ -5,7 +5,6 @@ ]> - OGC:WMS myservicetitle @@ -57,6 +56,7 @@ image/tiff application/vnd.google-earth.kml+xml application/vnd.google-earth.kmz + application/vnd.mapbox-vector-tile application/x-protobuf application/json @@ -125,11 +125,11 @@ EPSG:4326 EPSG:4269 EPSG:3035 - + + minx="-66.633300" miny="42.382100" maxx="-59.292100" maxy="48.295500" /> + minx="-66.633300" miny="42.382100" maxx="-59.292100" maxy="48.295500" /> - TN.RoadTransportNetwork.RoadLink - Transport networks: Road Link - myroadlinklayerabstract - - myroadlinklayerkeyword1 - myroadlinklayerkeyword2 - - - - - - - text/xml - - + TN.RoadTransportNetwork.RoadLink + Transport networks: Road Link + myroadlinklayerabstract + + myroadlinklayerkeyword1 + myroadlinklayerkeyword2 + + + + + + + text/xml + + + TN.RailTransportNetwork.RailwayLink Transport networks: Railway Link @@ -188,11 +188,11 @@ myrailwaylinklayerkeyword1 myrailwaylinklayerkeyword2 - + + minx="-66.633318" miny="42.382054" maxx="-59.292114" maxy="48.295512" /> + minx="-66.633318" miny="42.382054" maxx="-59.292114" maxy="48.295512" /> @@ -216,11 +216,11 @@ myairlinklayerkeyword1 myairlinklayerkeyword2 - + + minx="-66.633318" miny="42.382054" maxx="-59.292114" maxy="48.295512" /> + minx="-66.633318" miny="42.382054" maxx="-59.292114" maxy="48.295512" /> diff --git a/msautotest/wxs/expected/wms_inspire_scenario2_cap111_eng.xml b/msautotest/wxs/expected/wms_inspire_scenario2_cap111_eng.xml index 0ba1cc48f4..c479762e67 100644 --- a/msautotest/wxs/expected/wms_inspire_scenario2_cap111_eng.xml +++ b/msautotest/wxs/expected/wms_inspire_scenario2_cap111_eng.xml @@ -5,7 +5,6 @@ ]> - OGC:WMS myservicetitle @@ -57,6 +56,7 @@ image/tiff application/vnd.google-earth.kml+xml application/vnd.google-earth.kmz + application/vnd.mapbox-vector-tile application/x-protobuf application/json @@ -125,11 +125,11 @@ EPSG:4326 EPSG:4269 EPSG:3035 - + + minx="-66.633300" miny="42.382100" maxx="-59.292100" maxy="48.295500" /> + minx="-66.633300" miny="42.382100" maxx="-59.292100" maxy="48.295500" /> - TN.RoadTransportNetwork.RoadLink - Transport networks: Road Link - myroadlinklayerabstract - - myroadlinklayerkeyword1 - myroadlinklayerkeyword2 - - - - - - - text/xml - - + TN.RoadTransportNetwork.RoadLink + Transport networks: Road Link + myroadlinklayerabstract + + myroadlinklayerkeyword1 + myroadlinklayerkeyword2 + + + + + + + text/xml + + + TN.RailTransportNetwork.RailwayLink Transport networks: Railway Link @@ -188,11 +188,11 @@ myrailwaylinklayerkeyword1 myrailwaylinklayerkeyword2 - + + minx="-66.633318" miny="42.382054" maxx="-59.292114" maxy="48.295512" /> + minx="-66.633318" miny="42.382054" maxx="-59.292114" maxy="48.295512" /> @@ -216,11 +216,11 @@ myairlinklayerkeyword1 myairlinklayerkeyword2 - + + minx="-66.633318" miny="42.382054" maxx="-59.292114" maxy="48.295512" /> + minx="-66.633318" miny="42.382054" maxx="-59.292114" maxy="48.295512" /> diff --git a/msautotest/wxs/expected/wms_inspire_scenario2_cap111_ger.xml b/msautotest/wxs/expected/wms_inspire_scenario2_cap111_ger.xml index c8d97cb258..e47c3b4375 100644 --- a/msautotest/wxs/expected/wms_inspire_scenario2_cap111_ger.xml +++ b/msautotest/wxs/expected/wms_inspire_scenario2_cap111_ger.xml @@ -5,7 +5,6 @@ ]> - OGC:WMS myservicetitleger @@ -57,6 +56,7 @@ image/tiff application/vnd.google-earth.kml+xml application/vnd.google-earth.kmz + application/vnd.mapbox-vector-tile application/x-protobuf application/json @@ -125,11 +125,11 @@ EPSG:4326 EPSG:4269 EPSG:3035 - + + minx="-66.633300" miny="42.382100" maxx="-59.292100" maxy="48.295500" /> + minx="-66.633300" miny="42.382100" maxx="-59.292100" maxy="48.295500" /> - TN.RoadTransportNetwork.RoadLink - Verkehrsnetze: Straßensegment - myroadlinklayerabstractger - - myroadlinklayerkeyword1 - myroadlinklayerkeyword2 - - - - - - - text/xml - - + TN.RoadTransportNetwork.RoadLink + Verkehrsnetze: Straßensegment + myroadlinklayerabstractger + + myroadlinklayerkeyword1 + myroadlinklayerkeyword2 + + + + + + + text/xml + + + TN.RailTransportNetwork.RailwayLink Verkehrsnetze: Eisenbahnverbindung @@ -188,11 +188,11 @@ myrailwaylinklayerkeyword1 myrailwaylinklayerkeyword2 - + + minx="-66.633318" miny="42.382054" maxx="-59.292114" maxy="48.295512" /> + minx="-66.633318" miny="42.382054" maxx="-59.292114" maxy="48.295512" /> @@ -216,11 +216,11 @@ myairlinklayerkeyword1 myairlinklayerkeyword2 - + + minx="-66.633318" miny="42.382054" maxx="-59.292114" maxy="48.295512" /> + minx="-66.633318" miny="42.382054" maxx="-59.292114" maxy="48.295512" /> diff --git a/msautotest/wxs/expected/wms_inspire_scenario2_cap130.xml b/msautotest/wxs/expected/wms_inspire_scenario2_cap130.xml index e53959b7cf..f06c7f4c49 100644 --- a/msautotest/wxs/expected/wms_inspire_scenario2_cap130.xml +++ b/msautotest/wxs/expected/wms_inspire_scenario2_cap130.xml @@ -1,6 +1,5 @@ - - + WMS myservicetitle @@ -55,6 +54,7 @@ image/tiff application/vnd.google-earth.kml+xml application/vnd.google-earth.kmz + application/vnd.mapbox-vector-tile application/x-protobuf application/json @@ -122,15 +122,15 @@ EPSG:4269 EPSG:3035 - -66.6333 - -59.2921 - 42.3821 - 48.2955 + -66.633300 + -59.292100 + 42.382100 + 48.295500 + minx="42.382100" miny="-66.633300" maxx="48.295500" maxy="-59.292100" /> + minx="42.382100" miny="-66.633300" maxx="48.295500" maxy="-59.292100" /> - TN.RoadTransportNetwork.RoadLink - Transport networks: Road Link - myroadlinklayerabstract - - myroadlinklayerkeyword1 - myroadlinklayerkeyword2 - - - -66.6333 - -59.2921 - 42.3821 - 48.2955 - - - - - - text/xml - - + TN.RoadTransportNetwork.RoadLink + Transport networks: Road Link + myroadlinklayerabstract + + myroadlinklayerkeyword1 + myroadlinklayerkeyword2 + + + -66.633318 + -59.292114 + 42.382054 + 48.295512 + + + + + + text/xml + + + TN.RailTransportNetwork.RailwayLink Transport networks: Railway Link @@ -195,15 +195,15 @@ myrailwaylinklayerkeyword2 - -66.6333 - -59.2921 - 42.3821 - 48.2955 + -66.633318 + -59.292114 + 42.382054 + 48.295512 + minx="42.382054" miny="-66.633318" maxx="48.295512" maxy="-59.292114" /> + minx="42.382054" miny="-66.633318" maxx="48.295512" maxy="-59.292114" /> @@ -228,15 +228,15 @@ myairlinklayerkeyword2 - -66.6333 - -59.2921 - 42.3821 - 48.2955 + -66.633318 + -59.292114 + 42.382054 + 48.295512 + minx="42.382054" miny="-66.633318" maxx="48.295512" maxy="-59.292114" /> + minx="42.382054" miny="-66.633318" maxx="48.295512" maxy="-59.292114" /> diff --git a/msautotest/wxs/expected/wms_inspire_scenario2_cap130_eng.xml b/msautotest/wxs/expected/wms_inspire_scenario2_cap130_eng.xml index e53959b7cf..f06c7f4c49 100644 --- a/msautotest/wxs/expected/wms_inspire_scenario2_cap130_eng.xml +++ b/msautotest/wxs/expected/wms_inspire_scenario2_cap130_eng.xml @@ -1,6 +1,5 @@ - - + WMS myservicetitle @@ -55,6 +54,7 @@ image/tiff application/vnd.google-earth.kml+xml application/vnd.google-earth.kmz + application/vnd.mapbox-vector-tile application/x-protobuf application/json @@ -122,15 +122,15 @@ EPSG:4269 EPSG:3035 - -66.6333 - -59.2921 - 42.3821 - 48.2955 + -66.633300 + -59.292100 + 42.382100 + 48.295500 + minx="42.382100" miny="-66.633300" maxx="48.295500" maxy="-59.292100" /> + minx="42.382100" miny="-66.633300" maxx="48.295500" maxy="-59.292100" /> - TN.RoadTransportNetwork.RoadLink - Transport networks: Road Link - myroadlinklayerabstract - - myroadlinklayerkeyword1 - myroadlinklayerkeyword2 - - - -66.6333 - -59.2921 - 42.3821 - 48.2955 - - - - - - text/xml - - + TN.RoadTransportNetwork.RoadLink + Transport networks: Road Link + myroadlinklayerabstract + + myroadlinklayerkeyword1 + myroadlinklayerkeyword2 + + + -66.633318 + -59.292114 + 42.382054 + 48.295512 + + + + + + text/xml + + + TN.RailTransportNetwork.RailwayLink Transport networks: Railway Link @@ -195,15 +195,15 @@ myrailwaylinklayerkeyword2 - -66.6333 - -59.2921 - 42.3821 - 48.2955 + -66.633318 + -59.292114 + 42.382054 + 48.295512 + minx="42.382054" miny="-66.633318" maxx="48.295512" maxy="-59.292114" /> + minx="42.382054" miny="-66.633318" maxx="48.295512" maxy="-59.292114" /> @@ -228,15 +228,15 @@ myairlinklayerkeyword2 - -66.6333 - -59.2921 - 42.3821 - 48.2955 + -66.633318 + -59.292114 + 42.382054 + 48.295512 + minx="42.382054" miny="-66.633318" maxx="48.295512" maxy="-59.292114" /> + minx="42.382054" miny="-66.633318" maxx="48.295512" maxy="-59.292114" /> diff --git a/msautotest/wxs/expected/wms_inspire_scenario2_cap130_ger.xml b/msautotest/wxs/expected/wms_inspire_scenario2_cap130_ger.xml index cc437ff81b..94f626a1bf 100644 --- a/msautotest/wxs/expected/wms_inspire_scenario2_cap130_ger.xml +++ b/msautotest/wxs/expected/wms_inspire_scenario2_cap130_ger.xml @@ -1,6 +1,5 @@ - - + WMS myservicetitleger @@ -55,6 +54,7 @@ image/tiff application/vnd.google-earth.kml+xml application/vnd.google-earth.kmz + application/vnd.mapbox-vector-tile application/x-protobuf application/json @@ -122,15 +122,15 @@ EPSG:4269 EPSG:3035 - -66.6333 - -59.2921 - 42.3821 - 48.2955 + -66.633300 + -59.292100 + 42.382100 + 48.295500 + minx="42.382100" miny="-66.633300" maxx="48.295500" maxy="-59.292100" /> + minx="42.382100" miny="-66.633300" maxx="48.295500" maxy="-59.292100" /> - TN.RoadTransportNetwork.RoadLink - Verkehrsnetze: Straßensegment - myroadlinklayerabstractger - - myroadlinklayerkeyword1 - myroadlinklayerkeyword2 - - - -66.6333 - -59.2921 - 42.3821 - 48.2955 - - - - - - text/xml - - + TN.RoadTransportNetwork.RoadLink + Verkehrsnetze: Straßensegment + myroadlinklayerabstractger + + myroadlinklayerkeyword1 + myroadlinklayerkeyword2 + + + -66.633318 + -59.292114 + 42.382054 + 48.295512 + + + + + + text/xml + + + TN.RailTransportNetwork.RailwayLink Verkehrsnetze: Eisenbahnverbindung @@ -195,15 +195,15 @@ myrailwaylinklayerkeyword2 - -66.6333 - -59.2921 - 42.3821 - 48.2955 + -66.633318 + -59.292114 + 42.382054 + 48.295512 + minx="42.382054" miny="-66.633318" maxx="48.295512" maxy="-59.292114" /> + minx="42.382054" miny="-66.633318" maxx="48.295512" maxy="-59.292114" /> @@ -228,15 +228,15 @@ myairlinklayerkeyword2 - -66.6333 - -59.2921 - 42.3821 - 48.2955 + -66.633318 + -59.292114 + 42.382054 + 48.295512 + minx="42.382054" miny="-66.633318" maxx="48.295512" maxy="-59.292114" /> + minx="42.382054" miny="-66.633318" maxx="48.295512" maxy="-59.292114" /> diff --git a/msautotest/wxs/expected/wms_invalid_request_with_400_status.txt b/msautotest/wxs/expected/wms_invalid_request_with_400_status.txt new file mode 100644 index 0000000000..718198876f --- /dev/null +++ b/msautotest/wxs/expected/wms_invalid_request_with_400_status.txt @@ -0,0 +1,9 @@ +Status: 400 Bad Request +Content-Type: text/xml; charset=UTF-8 + + + + +msWMSDispatch(): WMS server error. Incomplete WMS request: VERSION parameter missing + + diff --git a/msautotest/wxs/expected/wms_invalid_request_with_500_status.txt b/msautotest/wxs/expected/wms_invalid_request_with_500_status.txt new file mode 100644 index 0000000000..9a0a606d87 --- /dev/null +++ b/msautotest/wxs/expected/wms_invalid_request_with_500_status.txt @@ -0,0 +1,8 @@ +Status: 500 Internal Server Error +Content-Type: text/html + + +MapServer Message + +msLoadMap(): Unable to access file. (i_do_not_exist.map) + \ No newline at end of file diff --git a/msautotest/wxs/expected/wms_invalid_request_without_500_status.txt b/msautotest/wxs/expected/wms_invalid_request_without_500_status.txt new file mode 100644 index 0000000000..d8aa4b8ee1 --- /dev/null +++ b/msautotest/wxs/expected/wms_invalid_request_without_500_status.txt @@ -0,0 +1,7 @@ +Content-Type: text/html + + +MapServer Message + +msLoadMap(): Unable to access file. (i_do_not_exist.map) + \ No newline at end of file diff --git a/msautotest/wxs/expected/wms_layer_groups_caps111.xml b/msautotest/wxs/expected/wms_layer_groups_caps111.xml index 33f0c99cef..81fc6f496a 100644 --- a/msautotest/wxs/expected/wms_layer_groups_caps111.xml +++ b/msautotest/wxs/expected/wms_layer_groups_caps111.xml @@ -5,10 +5,9 @@ ]> - OGC:WMS - + TESTGROUP @@ -37,6 +36,7 @@ image/tiff application/vnd.google-earth.kml+xml application/vnd.google-earth.kmz + application/vnd.mapbox-vector-tile application/x-protobuf application/json @@ -97,52 +97,54 @@ TESTGROUP - + TESTGROUP TESTGROUP EPSG:4326 - + + minx="0.000000" miny="0.000000" maxx="100.000000" maxy="150.000000" /> g1 g1 sg1 + sg1 - g1sg1l1 - - g1sg1l1 - - - text/xml - - + g1sg1l1 + + g1sg1l1 + + + text/xml + + - g1sg1l2 - - g1sg1l2 - - - text/xml - - + g1sg1l2 + + g1sg1l2 + + + text/xml + + sg2 + sg2 - g1sg2l1 - - g1sg2l1 - - - text/xml - - + g1sg2l1 + + g1sg2l1 + + + text/xml + + @@ -151,39 +153,47 @@ g2 sg3 + sg3 - g2sg3l1 - - g2sg3l1 - - - text/xml - - + g2sg3l1 + + g2sg3l1 + + + text/xml + + - - g3 - My g3 + + g3 + Group g3 title + Group g3 Abstract + + g3l1 + g3l1 title + g3l1 Abstract text/xml - + + sg4 - sg4 + Group g3/sg4 title + Group g3/sg4 Abstract - g3sg4l1 - - g3sg4l1 - - - text/xml - - + g3sg4l1 + g3sg4l1 title + g3sg4l1 Abstract + + + text/xml + + diff --git a/msautotest/wxs/expected/wms_layer_groups_map_all.png b/msautotest/wxs/expected/wms_layer_groups_map_all.png index a5fd97ff99..e7d2adbe56 100644 Binary files a/msautotest/wxs/expected/wms_layer_groups_map_all.png and b/msautotest/wxs/expected/wms_layer_groups_map_all.png differ diff --git a/msautotest/wxs/expected/wms_layer_groups_map_g1.png b/msautotest/wxs/expected/wms_layer_groups_map_g1.png index 31bae69949..bfb2afd5a5 100644 Binary files a/msautotest/wxs/expected/wms_layer_groups_map_g1.png and b/msautotest/wxs/expected/wms_layer_groups_map_g1.png differ diff --git a/msautotest/wxs/expected/wms_layer_groups_map_g2sg3l1.png b/msautotest/wxs/expected/wms_layer_groups_map_g2sg3l1.png index b5dbba6235..69f46ff8a6 100644 Binary files a/msautotest/wxs/expected/wms_layer_groups_map_g2sg3l1.png and b/msautotest/wxs/expected/wms_layer_groups_map_g2sg3l1.png differ diff --git a/msautotest/wxs/expected/wms_layer_groups_map_g3.png b/msautotest/wxs/expected/wms_layer_groups_map_g3.png index f795e698b2..ba30ee4ceb 100644 Binary files a/msautotest/wxs/expected/wms_layer_groups_map_g3.png and b/msautotest/wxs/expected/wms_layer_groups_map_g3.png differ diff --git a/msautotest/wxs/expected/wms_layer_groups_map_query_g3.xml b/msautotest/wxs/expected/wms_layer_groups_map_query_g3.xml index 67b9e43485..bb62fd4e6c 100644 --- a/msautotest/wxs/expected/wms_layer_groups_map_query_g3.xml +++ b/msautotest/wxs/expected/wms_layer_groups_map_query_g3.xml @@ -4,7 +4,18 @@ xmlns:gml="http://www.opengis.net/gml" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> + + g3l1 title + + + + 50.000000,90.000000 50.000000,90.000000 + + + + + g3sg4l1 title diff --git a/msautotest/wxs/expected/wms_layer_groups_map_query_root.xml b/msautotest/wxs/expected/wms_layer_groups_map_query_root.xml index d32a4f0efc..3b3a3be78d 100644 --- a/msautotest/wxs/expected/wms_layer_groups_map_query_root.xml +++ b/msautotest/wxs/expected/wms_layer_groups_map_query_root.xml @@ -13,7 +13,18 @@ + + g3l1 title + + + + 50.000000,90.000000 50.000000,90.000000 + + + + + g3sg4l1 title diff --git a/msautotest/wxs/expected/wms_layer_groups_map_sg1.png b/msautotest/wxs/expected/wms_layer_groups_map_sg1.png index 278b22eced..1ed736930d 100644 Binary files a/msautotest/wxs/expected/wms_layer_groups_map_sg1.png and b/msautotest/wxs/expected/wms_layer_groups_map_sg1.png differ diff --git a/msautotest/wxs/expected/wms_layer_groups_map_sg2.png b/msautotest/wxs/expected/wms_layer_groups_map_sg2.png index 6cf8ba51c7..b6efcbc8cb 100644 Binary files a/msautotest/wxs/expected/wms_layer_groups_map_sg2.png and b/msautotest/wxs/expected/wms_layer_groups_map_sg2.png differ diff --git a/msautotest/wxs/expected/wms_multiple_metadataurl_cap.xml b/msautotest/wxs/expected/wms_multiple_metadataurl_cap.xml index 57e60c3cd8..af29fbe804 100644 --- a/msautotest/wxs/expected/wms_multiple_metadataurl_cap.xml +++ b/msautotest/wxs/expected/wms_multiple_metadataurl_cap.xml @@ -7,7 +7,6 @@ Content-Type: application/vnd.ogc.wms_xml; charset=UTF-8 ]> - OGC:WMS Test simple wms @@ -124,32 +123,32 @@ Content-Type: application/vnd.ogc.wms_xml; charset=UTF-8 EPSG:42101 EPSG:4269 EPSG:4326 - + + minx="-67.572500" miny="42.000000" maxx="-58.927500" maxy="48.500000" /> - road - road - EPSG:43204 - - - + road + road + EPSG:43204 + + + text/xml - + - + text/html - + - - text/foo - - - - text/bar - - + + text/foo + + + + text/bar + + - popplace - popplace - - - text/xml - - + popplace + popplace + + + text/xml + + - road - road - - - text/xml - - + road + road + + + text/xml + + - popplace - popplace - EPSG:3978 - - - - text/xml - - + popplace + popplace + EPSG:3978 + + + + text/xml + + - road - road - EPSG:3978 - - - - text/xml - - + road + road + EPSG:3978 + + + + text/xml + + + + + + WMS_TEST + + + popplace + 1 + #LayerFolder_check + + "Tignish + #style_label_ff000000 + + + -64.05235541,46.98084305 + + + + + 'Cheticamp + #style_label_ff000000 + + + -60.98103788,46.68932288 + + + + + Sheet Harbour + #style_label_ff000000 + + + -62.51307844,44.91180032 + + + + + 'Souris' + #style_label_ff000000 + + + -62.27242993,46.37327164 + + + + + "Canso" + #style_label_ff000000 + + + -61.03874329,45.31128627 + + + + + Port Hawkesbury + #style_label_ff000000 + + + -61.37997660,45.65230747 + + + + + Antigonish + #style_label_ff000000 + + + -61.99737466,45.63945856 + + + + + Springhill + #style_label_ff000000 + + + -64.10962754,45.62796308 + + + + + "Wind"sor + #style_label_ff000000 + + + -64.19005686,44.97154750 + + + + + Lunenburg + #style_label_ff000000 + + + -64.33357666,44.37579449 + + + + + Liverpool + #style_label_ff000000 + + + -64.73281556,44.02035866 + + + + + Middleton + #style_label_ff000000 + + + -65.11482838,44.93816141 + + + + + Digby + #style_label_ff000000 + + + -65.81602426,44.61104869 + + + + + Shelburne + #style_label_ff000000 + + + -65.31837062,43.74011817 + + + + + Summerside + #style_label_ff000000 + + + -63.83197912,46.43127112 + + + + + New Glasgow + #style_label_ff000000 + + + -62.69300570,45.58942182 + + + + + Tr"uro + #style_label_ff000000 + + + -63.33519337,45.34330165 + + + + + Amherst + #style_label_ff000000 + + + -64.24404418,45.81894901 + + + + + Kentville + #style_label_ff000000 + + + -64.56907366,45.06472860 + + + + + Bridgewater + #style_label_ff000000 + + + -64.56321843,44.36519508 + + + + + Yarmouth + #style_label_ff000000 + + + -66.15895655,43.79770276 + + + + + Sydney Mines + #style_label_ff000000 + + + -60.28066115,46.27689752 + + + + + Sydney + #style_label_ff000000 + + + -60.21496347,46.12332205 + + + + + Dartmouth + #style_label_ff000000 + + + -63.57003995,44.68279156 + + + + + Fatima + #style_label_ff000000 + + + -61.90309910,47.40477005 + + + + + Charlottetown + #style_label_ff000000 + + + -63.16701651,46.29119095 + + + + + Halifax + #style_label_ff000000 + + + -63.69201127,44.61558257 + + + + + + diff --git a/msautotest/wxs/expected/wms_tiled_tiled_disabled.png b/msautotest/wxs/expected/wms_tiled_tiled_disabled.png new file mode 100644 index 0000000000..18005ce3f0 Binary files /dev/null and b/msautotest/wxs/expected/wms_tiled_tiled_disabled.png differ diff --git a/msautotest/wxs/expected/wms_tiled_tiled_enabled.png b/msautotest/wxs/expected/wms_tiled_tiled_enabled.png new file mode 100644 index 0000000000..ae3e2f6066 Binary files /dev/null and b/msautotest/wxs/expected/wms_tiled_tiled_enabled.png differ diff --git a/msautotest/wxs/expected/wms_time_cap.xml b/msautotest/wxs/expected/wms_time_cap.xml index e851db1594..3316e7b035 100644 --- a/msautotest/wxs/expected/wms_time_cap.xml +++ b/msautotest/wxs/expected/wms_time_cap.xml @@ -7,7 +7,6 @@ Content-Type: application/vnd.ogc.wms_xml; charset=UTF-8 ]> - OGC:WMS Test WMS time support @@ -73,24 +72,24 @@ Content-Type: application/vnd.ogc.wms_xml; charset=UTF-8 Test WMS time support WMS_TIME_EXTENTS_RESOLUTION_NO_DEFAULT EPSG:4326 - + - + minx="-131.000000" miny="5.000000" maxx="-68.000000" maxy="68.000000" /> + - pattern4 - pattern4 - EPSG:4326 - - - - 2004-01-01/2004-02-01 - - text/xml - - + pattern4 + pattern4 + EPSG:4326 + + + + 2004-01-01/2004-02-01 + + text/xml + + diff --git a/msautotest/wxs/expected/wms_time_cap130.xml b/msautotest/wxs/expected/wms_time_cap130.xml index dd3de2d453..0cd1cfd3d4 100644 --- a/msautotest/wxs/expected/wms_time_cap130.xml +++ b/msautotest/wxs/expected/wms_time_cap130.xml @@ -2,7 +2,6 @@ Content-Type: text/xml; charset=UTF-8 - WMS Test WMS time support @@ -92,33 +91,33 @@ Content-Type: text/xml; charset=UTF-8 WMS_TIME_EXTENTS_RESOLUTION_NO_DEFAULT EPSG:4326 - -131 - -68 - 5 - 68 + -131.000000 + -68.000000 + 5.000000 + 68.000000 + minx="5.000000" miny="-131.000000" maxx="68.000000" maxy="-68.000000" /> 2e+06 5e+07 - pattern4 - pattern4 - EPSG:4326 - - -131.02 - -119.85 - 33.65 - 48.39 - - - 2004-01-01/2004-02-01 - - text/xml - - + pattern4 + pattern4 + EPSG:4326 + + -131.020004 + -119.849998 + 33.650002 + 48.389999 + + + 2004-01-01/2004-02-01 + + text/xml + + diff --git a/msautotest/wxs/expected/wms_time_cap130_postgis_postgis.xml b/msautotest/wxs/expected/wms_time_cap130_postgis_postgis.xml index dd3de2d453..0cd1cfd3d4 100644 --- a/msautotest/wxs/expected/wms_time_cap130_postgis_postgis.xml +++ b/msautotest/wxs/expected/wms_time_cap130_postgis_postgis.xml @@ -2,7 +2,6 @@ Content-Type: text/xml; charset=UTF-8 - WMS Test WMS time support @@ -92,33 +91,33 @@ Content-Type: text/xml; charset=UTF-8 WMS_TIME_EXTENTS_RESOLUTION_NO_DEFAULT EPSG:4326 - -131 - -68 - 5 - 68 + -131.000000 + -68.000000 + 5.000000 + 68.000000 + minx="5.000000" miny="-131.000000" maxx="68.000000" maxy="-68.000000" /> 2e+06 5e+07 - pattern4 - pattern4 - EPSG:4326 - - -131.02 - -119.85 - 33.65 - 48.39 - - - 2004-01-01/2004-02-01 - - text/xml - - + pattern4 + pattern4 + EPSG:4326 + + -131.020004 + -119.849998 + 33.650002 + 48.389999 + + + 2004-01-01/2004-02-01 + + text/xml + + diff --git a/msautotest/wxs/expected/wms_time_cap_postgis_postgis.xml b/msautotest/wxs/expected/wms_time_cap_postgis_postgis.xml index e851db1594..3316e7b035 100644 --- a/msautotest/wxs/expected/wms_time_cap_postgis_postgis.xml +++ b/msautotest/wxs/expected/wms_time_cap_postgis_postgis.xml @@ -7,7 +7,6 @@ Content-Type: application/vnd.ogc.wms_xml; charset=UTF-8 ]> - OGC:WMS Test WMS time support @@ -73,24 +72,24 @@ Content-Type: application/vnd.ogc.wms_xml; charset=UTF-8 Test WMS time support WMS_TIME_EXTENTS_RESOLUTION_NO_DEFAULT EPSG:4326 - + - + minx="-131.000000" miny="5.000000" maxx="-68.000000" maxy="68.000000" /> + - pattern4 - pattern4 - EPSG:4326 - - - - 2004-01-01/2004-02-01 - - text/xml - - + pattern4 + pattern4 + EPSG:4326 + + + + 2004-01-01/2004-02-01 + + text/xml + + diff --git a/msautotest/wxs/expected/wms_time_multi_ranges_reso_hour.png b/msautotest/wxs/expected/wms_time_multi_ranges_reso_hour.png index 65b3cdd7d1..34fc2fd0a0 100644 Binary files a/msautotest/wxs/expected/wms_time_multi_ranges_reso_hour.png and b/msautotest/wxs/expected/wms_time_multi_ranges_reso_hour.png differ diff --git a/msautotest/wxs/expected/wms_time_multi_ranges_reso_hour_postgis.png b/msautotest/wxs/expected/wms_time_multi_ranges_reso_hour_postgis.png index 65b3cdd7d1..34fc2fd0a0 100644 Binary files a/msautotest/wxs/expected/wms_time_multi_ranges_reso_hour_postgis.png and b/msautotest/wxs/expected/wms_time_multi_ranges_reso_hour_postgis.png differ diff --git a/msautotest/wxs/expected/wms_time_multi_reverse.png b/msautotest/wxs/expected/wms_time_multi_reverse.png index d6ea237359..ff2fb9f933 100644 Binary files a/msautotest/wxs/expected/wms_time_multi_reverse.png and b/msautotest/wxs/expected/wms_time_multi_reverse.png differ diff --git a/msautotest/wxs/expected/wms_time_multi_reverse_postgis.png b/msautotest/wxs/expected/wms_time_multi_reverse_postgis.png index d6ea237359..ff2fb9f933 100644 Binary files a/msautotest/wxs/expected/wms_time_multi_reverse_postgis.png and b/msautotest/wxs/expected/wms_time_multi_reverse_postgis.png differ diff --git a/msautotest/wxs/expected/wms_time_no_time_param.png b/msautotest/wxs/expected/wms_time_no_time_param.png index 65b3cdd7d1..34fc2fd0a0 100644 Binary files a/msautotest/wxs/expected/wms_time_no_time_param.png and b/msautotest/wxs/expected/wms_time_no_time_param.png differ diff --git a/msautotest/wxs/expected/wms_time_no_time_param_postgis.png b/msautotest/wxs/expected/wms_time_no_time_param_postgis.png index 65b3cdd7d1..34fc2fd0a0 100644 Binary files a/msautotest/wxs/expected/wms_time_no_time_param_postgis.png and b/msautotest/wxs/expected/wms_time_no_time_param_postgis.png differ diff --git a/msautotest/wxs/expected/wms_uvraster_lonwrap180_accross_hemisphere.png b/msautotest/wxs/expected/wms_uvraster_lonwrap180_accross_hemisphere.png index f1e7e67101..acc5994e86 100644 Binary files a/msautotest/wxs/expected/wms_uvraster_lonwrap180_accross_hemisphere.png and b/msautotest/wxs/expected/wms_uvraster_lonwrap180_accross_hemisphere.png differ diff --git a/msautotest/wxs/expected/wms_uvraster_lonwrap180_accross_hemisphere.png.alternative b/msautotest/wxs/expected/wms_uvraster_lonwrap180_accross_hemisphere.png.alternative new file mode 100644 index 0000000000..14aeb15bbd Binary files /dev/null and b/msautotest/wxs/expected/wms_uvraster_lonwrap180_accross_hemisphere.png.alternative differ diff --git a/msautotest/wxs/expected/wms_uvraster_lonwrap180_east_hemisphere.png b/msautotest/wxs/expected/wms_uvraster_lonwrap180_east_hemisphere.png index 05b1f814a6..e6b82fe487 100644 Binary files a/msautotest/wxs/expected/wms_uvraster_lonwrap180_east_hemisphere.png and b/msautotest/wxs/expected/wms_uvraster_lonwrap180_east_hemisphere.png differ diff --git a/msautotest/wxs/expected/wms_uvraster_lonwrap180_east_hemisphere.png.alternative b/msautotest/wxs/expected/wms_uvraster_lonwrap180_east_hemisphere.png.alternative new file mode 100644 index 0000000000..1bf19e017b Binary files /dev/null and b/msautotest/wxs/expected/wms_uvraster_lonwrap180_east_hemisphere.png.alternative differ diff --git a/msautotest/wxs/expected/wms_uvraster_lonwrap180_west_hemisphere.png.alternative b/msautotest/wxs/expected/wms_uvraster_lonwrap180_west_hemisphere.png.alternative new file mode 100644 index 0000000000..a118de4eaa Binary files /dev/null and b/msautotest/wxs/expected/wms_uvraster_lonwrap180_west_hemisphere.png.alternative differ diff --git a/msautotest/wxs/expected/wms_uvraster_lonwrap180_whole_world.png b/msautotest/wxs/expected/wms_uvraster_lonwrap180_whole_world.png index 3690e83e67..e0f7687415 100644 Binary files a/msautotest/wxs/expected/wms_uvraster_lonwrap180_whole_world.png and b/msautotest/wxs/expected/wms_uvraster_lonwrap180_whole_world.png differ diff --git a/msautotest/wxs/expected/wms_uvraster_lonwrap180_whole_world.png.alternative b/msautotest/wxs/expected/wms_uvraster_lonwrap180_whole_world.png.alternative new file mode 100644 index 0000000000..a78c0bb097 Binary files /dev/null and b/msautotest/wxs/expected/wms_uvraster_lonwrap180_whole_world.png.alternative differ diff --git a/msautotest/wxs/expected/wms_uvraster_map_reprojection_extent_intersecting_layer.png b/msautotest/wxs/expected/wms_uvraster_map_reprojection_extent_intersecting_layer.png index 4b8d02422c..b31861b9d4 100644 Binary files a/msautotest/wxs/expected/wms_uvraster_map_reprojection_extent_intersecting_layer.png and b/msautotest/wxs/expected/wms_uvraster_map_reprojection_extent_intersecting_layer.png differ diff --git a/msautotest/wxs/expected/wms_uvraster_map_reprojection_extent_larger_than_layer.png b/msautotest/wxs/expected/wms_uvraster_map_reprojection_extent_larger_than_layer.png index d9c5ccfba3..882b40ba0c 100644 Binary files a/msautotest/wxs/expected/wms_uvraster_map_reprojection_extent_larger_than_layer.png and b/msautotest/wxs/expected/wms_uvraster_map_reprojection_extent_larger_than_layer.png differ diff --git a/msautotest/wxs/expected/wms_uvraster_map_reprojection_extent_smaller_than_layer.png b/msautotest/wxs/expected/wms_uvraster_map_reprojection_extent_smaller_than_layer.png index f0b16e92e9..37cbf0e46a 100644 Binary files a/msautotest/wxs/expected/wms_uvraster_map_reprojection_extent_smaller_than_layer.png and b/msautotest/wxs/expected/wms_uvraster_map_reprojection_extent_smaller_than_layer.png differ diff --git a/msautotest/wxs/expected/wms_uvraster_map_reprojection_geog_to_polar_stereo.png b/msautotest/wxs/expected/wms_uvraster_map_reprojection_geog_to_polar_stereo.png new file mode 100644 index 0000000000..8e3600a9b9 Binary files /dev/null and b/msautotest/wxs/expected/wms_uvraster_map_reprojection_geog_to_polar_stereo.png differ diff --git a/msautotest/wxs/expected/wms_uvraster_map_reprojection_getfeatureinfo.xml b/msautotest/wxs/expected/wms_uvraster_map_reprojection_getfeatureinfo.xml index 7e113462b9..7f5114b83c 100644 --- a/msautotest/wxs/expected/wms_uvraster_map_reprojection_getfeatureinfo.xml +++ b/msautotest/wxs/expected/wms_uvraster_map_reprojection_getfeatureinfo.xml @@ -12,12 +12,12 @@ 82.689740,80.025912 82.689740,80.025912 - 0.000000 - 180.000000 + 177.584208 + 357.584208 2.378277 1.189139 - 2.378277 - 0.000000 + -2.376163 + 0.100247 diff --git a/msautotest/wxs/expected/wms_uvraster_tileindex_inline.png b/msautotest/wxs/expected/wms_uvraster_tileindex_inline.png new file mode 100644 index 0000000000..b8d9a84be2 Binary files /dev/null and b/msautotest/wxs/expected/wms_uvraster_tileindex_inline.png differ diff --git a/msautotest/wxs/expected/wms_uvraster_tileindex_offline.png b/msautotest/wxs/expected/wms_uvraster_tileindex_offline.png new file mode 100644 index 0000000000..b8d9a84be2 Binary files /dev/null and b/msautotest/wxs/expected/wms_uvraster_tileindex_offline.png differ diff --git a/msautotest/wxs/expected/wmsclient_proj.png b/msautotest/wxs/expected/wmsclient_proj.png new file mode 100644 index 0000000000..fceb0e1292 Binary files /dev/null and b/msautotest/wxs/expected/wmsclient_proj.png differ diff --git a/msautotest/wxs/ogr_connectionoptions.map b/msautotest/wxs/ogr_connectionoptions.map index 5d2727c674..c94a2fa35e 100644 --- a/msautotest/wxs/ogr_connectionoptions.map +++ b/msautotest/wxs/ogr_connectionoptions.map @@ -82,7 +82,6 @@ LAYER "init=epsg:4326" END - DUMP TRUE END # Layer END # Map File diff --git a/msautotest/wxs/ows_all.map b/msautotest/wxs/ows_all.map index 832d8adf4e..3b5b6ccb4a 100644 --- a/msautotest/wxs/ows_all.map +++ b/msautotest/wxs/ows_all.map @@ -81,13 +81,13 @@ LAYER "init=./data/epsg2:42304" END - DUMP TRUE - CLASSITEM "Name_e" CLASS NAME "Roads" - SYMBOL 0 - COLOR 220 0 0 + STYLE + SYMBOL 0 + COLOR 220 0 0 + END END END # Layer @@ -109,13 +109,14 @@ LAYER # "init=epsg:42304" END - DUMP TRUE CLASSITEM "Name_e" CLASS NAME "Province" - COLOR 200 255 0 - OUTLINECOLOR 120 120 120 + STYLE + COLOR 200 255 0 + OUTLINECOLOR 120 120 120 + END END END # Layer diff --git a/msautotest/wxs/ows_context.map b/msautotest/wxs/ows_context.map new file mode 100644 index 0000000000..03a80f28a3 --- /dev/null +++ b/msautotest/wxs/ows_context.map @@ -0,0 +1,73 @@ +# +# Test OWS Context loading +# +# REQUIRES: INPUT=GDAL OUTPUT=PNG SUPPORTS=WMS + +# Capabilities updatesequence (less than) +# RUN_PARMS: ows_context_caps.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&CONTEXT=ows_context.xml&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetCapabilities" > [RESULT_DEVERSION] +# RUN_PARMS: ows_context_with_layer_list_caps.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&CONTEXT=ows_context_with_layer_list.xml&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetCapabilities" > [RESULT_DEVERSION] + +MAP + +NAME OWS_CONTEXT_TEST +STATUS ON +SIZE 400 300 +#EXTENT 2018000 -73300 3410396 647400 +EXTENT -67.5725 42 -58.9275 48.5 +UNITS METERS +IMAGECOLOR 255 255 255 +SHAPEPATH ./data +SYMBOLSET etc/symbols.sym +FONTSET etc/fonts.txt + +# +# Start of web interface definition +# +WEB + + IMAGEPATH "/tmp/ms_tmp/" + IMAGEURL "/ms_tmp/" + + METADATA + "wms_onlineresource" "http://localhost/path/to/wfs_simple?myparam=something&" + "ows_enable_request" "*" + END +END + +PROJECTION + "init=epsg:4326" +# "init=./data/epsg2:42304" +# "init=epsg:42304" +END + + +# +# Start of layer definitions +# + +LAYER + NAME province + DATA province + METADATA + "wms_title" "province" + END + TYPE POINT + STATUS ON + PROJECTION + "init=./data/epsg2:42304" +# "init=epsg:42304" + END + + CLASSITEM "Name_e" + + CLASS + NAME "Province" + STYLE + COLOR 200 255 0 + OUTLINECOLOR 120 120 120 + END + END +END # Layer + + +END # Map File diff --git a/msautotest/wxs/ows_context.xml b/msautotest/wxs/ows_context.xml new file mode 100644 index 0000000000..8d3a4719f2 --- /dev/null +++ b/msautotest/wxs/ows_context.xml @@ -0,0 +1,13 @@ + + + + + + + + Map Context demo + Demo for map context document + + + + diff --git a/msautotest/wxs/ows_context_with_layer_list.xml b/msautotest/wxs/ows_context_with_layer_list.xml new file mode 100644 index 0000000000..1c47d492b3 --- /dev/null +++ b/msautotest/wxs/ows_context_with_layer_list.xml @@ -0,0 +1,23 @@ + + + + + + + + Map Context demo + Demo for map context document + + + + + + + + diff --git a/msautotest/wxs/ows_disable.map b/msautotest/wxs/ows_disable.map index 80c3e99e98..a31dfa1023 100644 --- a/msautotest/wxs/ows_disable.map +++ b/msautotest/wxs/ows_disable.map @@ -36,7 +36,6 @@ LAYER PROJECTION "init=epsg:32611" END - DUMP TRUE END # Layer diff --git a/msautotest/wxs/ows_empty.map b/msautotest/wxs/ows_empty.map index 08b344acf3..5638d5b955 100644 --- a/msautotest/wxs/ows_empty.map +++ b/msautotest/wxs/ows_empty.map @@ -10,6 +10,7 @@ # RUN_PARMS: wms_empty_cap_latestversion.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&REQUEST=GetCapabilities" > [RESULT_DEMIME] [RESULT_DEVERSION] # RUN_PARMS: wms_empty_cap130.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetCapabilities" > [RESULT_DEMIME] [RESULT_DEVERSION] # RUN_PARMS: wms_empty_cap111.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetCapabilities" > [RESULT_DEMIME] [RESULT_DEVERSION] +# RUN_PARMS: wms_empty_cap110.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.1.0&REQUEST=GetCapabilities" > [RESULT_DEMIME] [RESULT_DEVERSION] # RUN_PARMS: wms_empty_cap100.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.0.0&REQUEST=GetCapabilities" > [RESULT_DEMIME] [RESULT_DEVERSION] # # Test empty WCS diff --git a/msautotest/wxs/ows_metadata.map b/msautotest/wxs/ows_metadata.map index 81da17dfa0..2f41bff47b 100644 --- a/msautotest/wxs/ows_metadata.map +++ b/msautotest/wxs/ows_metadata.map @@ -111,13 +111,13 @@ LAYER "init=./data/epsg2:42304" END - DUMP TRUE - CLASSITEM "Name_e" CLASS NAME "Roads" - SYMBOL 0 - COLOR 220 0 0 + STYLE + SYMBOL 0 + COLOR 220 0 0 + END END END # Layer @@ -128,6 +128,7 @@ LAYER "ows_title" "province" "ows_abstract" "province" "wfs_featureid" "NAME_E" + "ows_attribution_title" "MapServer" END TYPE POINT STATUS ON @@ -136,13 +137,14 @@ LAYER # "init=epsg:42304" END - DUMP TRUE CLASSITEM "Name_e" CLASS NAME "Province" - COLOR 200 255 0 - OUTLINECOLOR 120 120 120 + STYLE + COLOR 200 255 0 + OUTLINECOLOR 120 120 120 + END END END # Layer @@ -160,7 +162,6 @@ LAYER PROJECTION "init=epsg:32611" END - DUMP TRUE END # Layer END # Map File diff --git a/msautotest/wxs/ows_no_service_strict_compliance.map b/msautotest/wxs/ows_no_service_strict_compliance.map new file mode 100644 index 0000000000..47c9e3b3ef --- /dev/null +++ b/msautotest/wxs/ows_no_service_strict_compliance.map @@ -0,0 +1,116 @@ +# +# Test OWS Services enabling/disabling. +# +# REQUIRES: SUPPORTS=WMS SUPPORTS=WFS +# +# Test invalid/missing service parameter values +# + +# RUN_PARMS: ows_no_service_strict_compliance.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&REQUEST=GetCapabilities" > [RESULT] +# RUN_PARMS: ows_invalid_service_strict_compliance.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=&REQUEST=GetCapabilities" > [RESULT] +# RUN_PARMS: ows_invalid_service_strict_compliance.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=zzzz&VERSION=2.0.0&REQUEST=GetCapabilities" > [RESULT] + + + +# Results expected for all tests: +# Service Exception sent with HTTP status code 200 + +MAP + +NAME WMS_WFS_TEST +SHAPEPATH ./data + +WEB + METADATA + "wms_onlineresource" "http://localhost/path/to/ows?" + "ows_updatesequence" "123" + "wfs_title" "Test simple wfs" + "wfs_onlineresource" "http://localhost/path/to/wfs_simple?" + "wfs_srs" "EPSG:4326 EPSG:4269" + "ows_abstract" "Test WFS Abstract" + "ows_keywordlist" "ogc,wfs,gml,om" + "ows_service_onlineresource" "http://localhost" + "ows_fees" "none" + "ows_accessconstraints" "none" + "ows_addresstype" "postal" + "ows_address" "123 SomeRoad Road" + "ows_city" "Toronto" + "ows_stateorprovince" "Ontario" + "ows_postcode" "xxx-xxx" + "ows_country" "Canada" + "ows_contactelectronicmailaddress" "tomkralidis@xxxxxxx.xxx" + "ows_contactvoicetelephone" "+xx-xxx-xxx-xxxx" + "ows_contactfacsimiletelephone" "+xx-xxx-xxx-xxxx" + "ows_contactperson" "Tom Kralidis" + "ows_contactorganization" "MapServer" + "ows_contactposition" "self" + "ows_hoursofservice" "0800h - 1600h EST" + "ows_contactinstructions" "during hours of service" + "ows_role" "staff" + "ows_enable_request" "*" # not read at all, all layers contains their setting. + "ows_compliance_mode" "true" + END +END + +PROJECTION + "init=epsg:4326" +END + +LAYER + NAME road + DATA road + TEMPLATE "ttt" + METADATA + "wms_title" "road" + "wms_description" "Roads of I.P.E." + "wms_srs" "EPSG:43204" + "gml_include_items" "all" + "ows_enable_request" "!*" # not read, wms_enable_request + "wms_enable_request" "*" + END + TYPE LINE + STATUS ON + PROJECTION + "init=./data/epsg2:42304" + END + + CLASSITEM "Name_e" + CLASS + NAME "Roads" + STYLE + SYMBOL 0 + COLOR 220 0 0 + END + END +END # Layer + +LAYER + NAME province + DATA province + METADATA + "wfs_title" "province" + "wfs_description" "province" + "wfs_result_fields" "NAME_E YEAR_EST AREA_KMSQ" + "wfs_featureid" "NAME_E" + "ows_enable_request" "*" # not read, wfs_enable_request + "wfs_enable_request" "!*" # all disabled + END + TYPE POINT + STATUS ON + PROJECTION + "init=./data/epsg2:42304" +# "init=epsg:42304" + END + + CLASSITEM "Name_e" + + CLASS + NAME "Province" + STYLE + COLOR 200 255 0 + OUTLINECOLOR 120 120 120 + END + END +END # Layer + +END # Map File diff --git a/msautotest/wxs/ows_sos.map b/msautotest/wxs/ows_sos.map index 6467beb835..09e3a5a30a 100644 --- a/msautotest/wxs/ows_sos.map +++ b/msautotest/wxs/ows_sos.map @@ -32,7 +32,6 @@ MAP "init=epsg:4326" END DEBUG ON - TRANSPARENT ON WEB HEADER "templates/query_header.html" FOOTER "templates/query_footer.html" @@ -72,15 +71,16 @@ MAP DEBUG ON TYPE POINT STATUS ON - DUMP TRUE DATA "./data/obs.shp" PROJECTION "init=epsg:4326" END CLASS NAME "obs" - COLOR 255 0 0 - SIZE 10 + STYLE + COLOR 255 0 0 + SIZE 10 + END END METADATA "sos_offering_id" "Water" # mandatory to tie layers to groups diff --git a/msautotest/wxs/ows_test_xml_escaping.map b/msautotest/wxs/ows_test_xml_escaping.map index 3ef8a94d19..c54d5048de 100644 --- a/msautotest/wxs/ows_test_xml_escaping.map +++ b/msautotest/wxs/ows_test_xml_escaping.map @@ -95,13 +95,14 @@ LAYER # "init=epsg:42304" END - DUMP TRUE CLASSITEM "Name_e" CLASS NAME "Province" - COLOR 200 255 0 - OUTLINECOLOR 120 120 120 + STYLE + COLOR 200 255 0 + OUTLINECOLOR 120 120 120 + END END END # Layer diff --git a/msautotest/wxs/ows_wcs.map b/msautotest/wxs/ows_wcs.map index 9c1ed10602..a8286772b4 100644 --- a/msautotest/wxs/ows_wcs.map +++ b/msautotest/wxs/ows_wcs.map @@ -28,7 +28,7 @@ MAXSIZE 5000 #CONFIG "MS_ERRORFILE" "stderr" IMAGETYPE PNG -TRANSPARENT OFF + SHAPEPATH "data" OUTPUTFORMAT @@ -38,13 +38,6 @@ OUTPUTFORMAT IMAGEMODE BYTE EXTENSION "tif" END -OUTPUTFORMAT - NAME GDPNGGREY - DRIVER "GD/PNG" - MIMETYPE "image/png; mode=8bit" - IMAGEMODE PC256 - EXTENSION "png" -END OUTPUTFORMAT NAME AAIGRID DRIVER "GDAL/AAIGRID" @@ -97,7 +90,6 @@ LAYER NAME grey TYPE raster STATUS ON - DUMP TRUE TILEINDEX "wcs_index.shp" TILEITEM "location" diff --git a/msautotest/wxs/ows_wfs.map b/msautotest/wxs/ows_wfs.map index 5ea5e2ed1c..e44e7d5071 100644 --- a/msautotest/wxs/ows_wfs.map +++ b/msautotest/wxs/ows_wfs.map @@ -100,13 +100,14 @@ LAYER # "init=epsg:42304" END - DUMP TRUE CLASSITEM "Name_e" CLASS NAME "Province" - COLOR 200 255 0 - OUTLINECOLOR 120 120 120 + STYLE + COLOR 200 255 0 + OUTLINECOLOR 120 120 120 + END END END # Layer diff --git a/msautotest/wxs/ows_wms.map b/msautotest/wxs/ows_wms.map index a1977457a6..b4be79e1c0 100644 --- a/msautotest/wxs/ows_wms.map +++ b/msautotest/wxs/ows_wms.map @@ -14,7 +14,7 @@ # RUN_PARMS: ows_wms_getfeatureinfo_plain_alias.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetFeatureInfo&CRS=EPSG%3A4326&BBOX=35.18749999863387,-141.0000000021858,90.81250000136613,-51.99999999781419&WIDTH=560&HEIGHT=350&LAYERS=road2&STYLES=&FORMAT=image%2Fpng&BGCOLOR=0xFFFFFF&TRANSPARENT=FALSE&QUERY_LAYERS=road2&INFO_FORMAT=text%2Fplain&I=483&J=291&FEATURE_COUNT=5" > [RESULT_DEVERSION] # RUN_PARMS: ows_wms_getfeatureinfo_gml_alias.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetFeatureInfo&CRS=EPSG%3A4326&BBOX=35.18749999863387,-141.0000000021858,90.81250000136613,-51.99999999781419&WIDTH=560&HEIGHT=350&LAYERS=road2&STYLES=&FORMAT=image%2Fpng&BGCOLOR=0xFFFFFF&TRANSPARENT=FALSE&QUERY_LAYERS=road2&INFO_FORMAT=application%2Fvnd.ogc.gml&I=483&J=291&FEATURE_COUNT=5" > [RESULT_DEVERSION] # RUN_PARMS: ows_wms_getmap.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.1.0&REQUEST=GetMap&SRS=EPSG:4326&BBOX=-67.5725,42.3683,-58.9275,48.13&FORMAT=image/png&WIDTH=300&HEIGHT=200&STYLES=&LAYERS=road" > [RESULT_DEVERSION] -# RUN_PARMS: ows_wms_describelayer.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=DescribeLayer&layers=road&sld_version=1.1.0&WIDTH=600&HEIGHT=600" > [RESULT_DEVERSION] +# RUN_PARMS: ows_wms_describelayer.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=DescribeLayer&layers=road&sld_version=1.1.0" > [RESULT_DEVERSION] # RUN_PARMS: ows_wms_getlegendgraphic.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&x=500&y=300&LAYER=popplace&FORMAT=agg/png&VERSION=1.1.1&REQUEST=GetLegendGraphic&STYLES=&EXCEPTIONS=application%252Fvnd.ogc.se_inimage&SRS=EPSG:42304&BBOX=-2200000,-712631,3072800,3840000&WIDTH=600&HEIGHT=600" > [RESULT_DEVERSION] # RUN_PARMS: ows_wms_getmap_exception.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&REQUEST=GetMap&VERSION=1.3.0&LAYERS=road&CRS=EPSG%3A4326&BBOX=35.18749999863387,-141.0000000021858,90.81250000136613,-51.99999999781419&WIDTH=560&HEIGHT=350&STYLES=&FORMAT=image%2Fpng&BGCOLOR=0xFFFFFF&TRANSPARENT=FALSE&EXCEPTIONS=INIMAGE" > [RESULT_DEVERSION] [RESULT_DEMIME] # RUN_PARMS: ows_wms_getmap_valid.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&REQUEST=GetMap&VERSION=1.3.0&LAYERS=road3&CRS=EPSG%3A4326&BBOX=35.18749999863387,-141.0000000021858,90.81250000136613,-51.99999999781419&WIDTH=560&HEIGHT=350&STYLES=&FORMAT=image%2Fpng&BGCOLOR=0xFFFFFF&TRANSPARENT=FALSE&EXCEPTIONS=INIMAGE" > [RESULT_DEVERSION] [RESULT_DEMIME] @@ -63,13 +63,13 @@ LAYER "init=./data/epsg2:42304" END - DUMP TRUE - CLASSITEM "Name_e" CLASS NAME "Roads" - SYMBOL 0 - COLOR 220 0 0 + STYLE + SYMBOL 0 + COLOR 220 0 0 + END END END # Layer @@ -94,13 +94,13 @@ LAYER "init=./data/epsg2:42304" END - DUMP TRUE - CLASSITEM "Name_e" CLASS NAME "Roads" - SYMBOL 0 - COLOR 220 0 0 + STYLE + SYMBOL 0 + COLOR 220 0 0 + END END END # Layer @@ -123,13 +123,13 @@ LAYER "init=./data/epsg2:42304" END - DUMP TRUE - CLASSITEM "Name_e" CLASS NAME "Roads" - SYMBOL 0 - COLOR 220 0 0 + STYLE + SYMBOL 0 + COLOR 220 0 0 + END END END # Layer diff --git a/msautotest/wxs/ows_wms_rootlayer_name.map b/msautotest/wxs/ows_wms_rootlayer_name.map index 75c21894dd..4285485480 100644 --- a/msautotest/wxs/ows_wms_rootlayer_name.map +++ b/msautotest/wxs/ows_wms_rootlayer_name.map @@ -50,13 +50,13 @@ LAYER "init=./data/epsg2:42304" END - DUMP TRUE - CLASSITEM "Name_e" CLASS NAME "Roads" - SYMBOL 0 - COLOR 220 0 0 + STYLE + SYMBOL 0 + COLOR 220 0 0 + END END END # Layer @@ -81,13 +81,13 @@ LAYER "init=./data/epsg2:42304" END - DUMP TRUE - CLASSITEM "Name_e" CLASS NAME "Roads" - SYMBOL 0 - COLOR 220 0 0 + STYLE + SYMBOL 0 + COLOR 220 0 0 + END END END # Layer @@ -110,13 +110,13 @@ LAYER "init=./data/epsg2:42304" END - DUMP TRUE - CLASSITEM "Name_e" CLASS NAME "Roads" - SYMBOL 0 - COLOR 220 0 0 + STYLE + SYMBOL 0 + COLOR 220 0 0 + END END END # Layer diff --git a/msautotest/wxs/ows_wms_rootlayer_name_empty.map b/msautotest/wxs/ows_wms_rootlayer_name_empty.map index db27f6cbea..936961096e 100644 --- a/msautotest/wxs/ows_wms_rootlayer_name_empty.map +++ b/msautotest/wxs/ows_wms_rootlayer_name_empty.map @@ -50,13 +50,13 @@ LAYER "init=./data/epsg2:42304" END - DUMP TRUE - CLASSITEM "Name_e" CLASS NAME "Roads" - SYMBOL 0 - COLOR 220 0 0 + STYLE + SYMBOL 0 + COLOR 220 0 0 + END END END # Layer @@ -81,13 +81,13 @@ LAYER "init=./data/epsg2:42304" END - DUMP TRUE - CLASSITEM "Name_e" CLASS NAME "Roads" - SYMBOL 0 - COLOR 220 0 0 + STYLE + SYMBOL 0 + COLOR 220 0 0 + END END END # Layer @@ -110,13 +110,13 @@ LAYER "init=./data/epsg2:42304" END - DUMP TRUE - CLASSITEM "Name_e" CLASS NAME "Roads" - SYMBOL 0 - COLOR 220 0 0 + STYLE + SYMBOL 0 + COLOR 220 0 0 + END END END # Layer diff --git a/msautotest/wxs/point_symbol_identification.map b/msautotest/wxs/point_symbol_identification.map new file mode 100644 index 0000000000..c1e174c603 --- /dev/null +++ b/msautotest/wxs/point_symbol_identification.map @@ -0,0 +1,347 @@ +# +# Test GetFeatureInfo on points with symbols +# +# REQUIRES: SUPPORTS=WMS +# + +# RUN_PARMS: point_symbol_identification_rotation_30.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&REQUEST=GetMap&SERVICE=WMS&VERSION=1.1.0&LAYERS=test_rotation_30&SRS=EPSG:3857&BBOX=1000,2000,1400,2300&FORMAT=png&WIDTH=200&HEIGHT=150&STYLES=" > [RESULT_DEMIME] +# RUN_PARMS: point_symbol_identification_rotation_30_i_73_j_82.xml [MAPSERV] QUERY_STRING="MAP=[MAPFILE]&REQUEST=GetFeatureInfo&SERVICE=WMS&VERSION=1.1.0&LAYERS=test_rotation_30&SRS=EPSG:3857&BBOX=1000,2000,1400,2300&FORMAT=png&WIDTH=200&HEIGHT=150&STYLES=&QUERY_LAYERS=test_rotation_30&INFO_FORMAT=application%2Fvnd.ogc.gml&I=73&J=82" > [RESULT_DEVERSION] +# RUN_PARMS: point_symbol_identification_rotation_30_i_73_j_82_with_styles.xml [MAPSERV] QUERY_STRING="MAP=[MAPFILE]&REQUEST=GetFeatureInfo&SERVICE=WMS&VERSION=1.1.0&LAYERS=test_rotation_30&SRS=EPSG:3857&BBOX=1000,2000,1400,2300&FORMAT=png&WIDTH=200&HEIGHT=150&STYLES=test&QUERY_LAYERS=test_rotation_30&INFO_FORMAT=application%2Fvnd.ogc.gml&I=73&J=82" > [RESULT_DEVERSION] +# RUN_PARMS: point_symbol_identification_rotation_30_i_70_j_82.xml [MAPSERV] QUERY_STRING="MAP=[MAPFILE]&REQUEST=GetFeatureInfo&SERVICE=WMS&VERSION=1.1.0&LAYERS=test_rotation_30&SRS=EPSG:3857&BBOX=1000,2000,1400,2300&FORMAT=png&WIDTH=200&HEIGHT=150&STYLES=&QUERY_LAYERS=test_rotation_30&INFO_FORMAT=application%2Fvnd.ogc.gml&I=70&J=82" > [RESULT_DEVERSION] +# RUN_PARMS: point_symbol_identification_rotation_30_i_118_j_78.xml [MAPSERV] QUERY_STRING="MAP=[MAPFILE]&REQUEST=GetFeatureInfo&SERVICE=WMS&VERSION=1.1.0&LAYERS=test_rotation_30&SRS=EPSG:3857&BBOX=1000,2000,1400,2300&FORMAT=png&WIDTH=200&HEIGHT=150&STYLES=&QUERY_LAYERS=test_rotation_30&INFO_FORMAT=application%2Fvnd.ogc.gml&I=111&J=78" > [RESULT_DEVERSION] +# RUN_PARMS: point_symbol_identification_rotation_30_i_159_j_91.xml [MAPSERV] QUERY_STRING="MAP=[MAPFILE]&REQUEST=GetFeatureInfo&SERVICE=WMS&VERSION=1.1.0&LAYERS=test_rotation_30&SRS=EPSG:3857&BBOX=1000,2000,1400,2300&FORMAT=png&WIDTH=200&HEIGHT=150&STYLES=&QUERY_LAYERS=test_rotation_30&INFO_FORMAT=application%2Fvnd.ogc.gml&I=159&J=91" > [RESULT_DEVERSION] +# RUN_PARMS: point_symbol_identification_rotation_30_classgroup_i_159_j_91.xml [MAPSERV] QUERY_STRING="MAP=[MAPFILE]&REQUEST=GetFeatureInfo&SERVICE=WMS&VERSION=1.1.0&LAYERS=test_classgroup&SRS=EPSG:3857&BBOX=1000,2000,1400,2300&FORMAT=png&WIDTH=200&HEIGHT=150&STYLES=&QUERY_LAYERS=test_classgroup&INFO_FORMAT=application%2Fvnd.ogc.gml&I=159&J=91&FEATURE_COUNT=10" > [RESULT_DEVERSION] +# RUN_PARMS: point_symbol_identification_wrong_layer.xml [MAPSERV] QUERY_STRING="MAP=[MAPFILE]&REQUEST=GetFeatureInfo&SERVICE=WMS&VERSION=1.1.0&LAYERS=wrong_layer&SRS=EPSG:3857&BBOX=1000,2000,1400,2300&FORMAT=png&WIDTH=200&HEIGHT=150&STYLES=&QUERY_LAYERS=test_classgroup&INFO_FORMAT=application%2Fvnd.ogc.gml&I=159&J=91" > [RESULT_DEVERSION] +# RUN_PARMS: point_symbol_identification_wrong_styles.xml [MAPSERV] QUERY_STRING="MAP=[MAPFILE]&REQUEST=GetFeatureInfo&SERVICE=WMS&VERSION=1.1.0&LAYERS=test_rotation_30&SRS=EPSG:3857&BBOX=1000,2000,1400,2300&FORMAT=png&WIDTH=200&HEIGHT=150&STYLES=wrong_styles&QUERY_LAYERS=test_rotation_30&INFO_FORMAT=application%2Fvnd.ogc.gml&I=73&J=82" > [RESULT_DEVERSION] +# RUN_PARMS: point_symbol_identification_wrong_number_of_styles.xml [MAPSERV] QUERY_STRING="MAP=[MAPFILE]&REQUEST=GetFeatureInfo&SERVICE=WMS&VERSION=1.1.0&LAYERS=test_rotation_30&SRS=EPSG:3857&BBOX=1000,2000,1400,2300&FORMAT=png&WIDTH=200&HEIGHT=150&STYLES=test,test&QUERY_LAYERS=test_rotation_30&INFO_FORMAT=application%2Fvnd.ogc.gml&I=73&J=82" > [RESULT_DEVERSION] +# RUN_PARMS: point_symbol_identification_two_layers.xml [MAPSERV] QUERY_STRING="MAP=[MAPFILE]&REQUEST=GetFeatureInfo&SERVICE=WMS&VERSION=1.1.0&LAYERS=test_rotation_30,test_classgroup&SRS=EPSG:3857&BBOX=1000,2000,1400,2300&FORMAT=png&WIDTH=200&HEIGHT=150&STYLES=test,test&QUERY_LAYERS=test_rotation_30,test_classgroup&INFO_FORMAT=application%2Fvnd.ogc.gml&I=73&J=82&NUM_FEATURES=10" > [RESULT_DEVERSION] +# RUN_PARMS: point_symbol_identification_class_minscaledenom_5700.xml [MAPSERV] QUERY_STRING="MAP=[MAPFILE]&REQUEST=GetFeatureInfo&SERVICE=WMS&VERSION=1.1.0&LAYERS=test_class_minscaledenom_5700&SRS=EPSG:3857&BBOX=1000,2000,1400,2300&FORMAT=png&WIDTH=200&HEIGHT=150&STYLES=&QUERY_LAYERS=test_class_minscaledenom_5700&INFO_FORMAT=application%2Fvnd.ogc.gml&I=73&J=82" > [RESULT_DEVERSION] +# RUN_PARMS: point_symbol_identification_style_minscaledenom_5700.xml [MAPSERV] QUERY_STRING="MAP=[MAPFILE]&REQUEST=GetFeatureInfo&SERVICE=WMS&VERSION=1.1.0&LAYERS=test_style_minscaledenom_5700&SRS=EPSG:3857&BBOX=1000,2000,1400,2300&FORMAT=png&WIDTH=200&HEIGHT=150&STYLES=&QUERY_LAYERS=test_style_minscaledenom_5700&INFO_FORMAT=application%2Fvnd.ogc.gml&I=73&J=82" > [RESULT_DEVERSION] +# RUN_PARMS: point_symbol_identification_expression_false.xml [MAPSERV] QUERY_STRING="MAP=[MAPFILE]&REQUEST=GetFeatureInfo&SERVICE=WMS&VERSION=1.1.0&LAYERS=test_expression_false&SRS=EPSG:3857&BBOX=1000,2000,1400,2300&FORMAT=png&WIDTH=200&HEIGHT=150&STYLES=&QUERY_LAYERS=test_expression_false&INFO_FORMAT=application%2Fvnd.ogc.gml&I=73&J=82" > [RESULT_DEVERSION] + +# RUN_PARMS: point_symbol_identification_anchor.png [MAPSERV] QUERY_STRING="MAP=[MAPFILE]&REQUEST=GetMap&SERVICE=WMS&VERSION=1.1.0&LAYERS=test_anchor&SRS=EPSG:3857&BBOX=1000,2000,1400,2300&FORMAT=png&WIDTH=200&HEIGHT=150&STYLES=" > [RESULT_DEMIME] +# RUN_PARMS: point_symbol_identification_anchor_match.xml [MAPSERV] QUERY_STRING="MAP=[MAPFILE]&REQUEST=GetFeatureInfo&SERVICE=WMS&VERSION=1.1.0&LAYERS=test_anchor&SRS=EPSG:3857&BBOX=1000,2000,1400,2300&WIDTH=200&HEIGHT=150&STYLES=&QUERY_LAYERS=test_anchor&INFO_FORMAT=application%2Fvnd.ogc.gml&I=93&J=40" > [RESULT_DEVERSION] +# RUN_PARMS: point_symbol_identification_anchor_no_match1.xml [MAPSERV] QUERY_STRING="MAP=[MAPFILE]&REQUEST=GetFeatureInfo&SERVICE=WMS&VERSION=1.1.0&LAYERS=test_anchor&SRS=EPSG:3857&BBOX=1000,2000,1400,2300&WIDTH=200&HEIGHT=150&STYLES=&QUERY_LAYERS=test_anchor&INFO_FORMAT=application%2Fvnd.ogc.gml&I=75&J=25" > [RESULT_DEVERSION] +# RUN_PARMS: point_symbol_identification_anchor_no_match2.xml [MAPSERV] QUERY_STRING="MAP=[MAPFILE]&REQUEST=GetFeatureInfo&SERVICE=WMS&VERSION=1.1.0&LAYERS=test_anchor&SRS=EPSG:3857&BBOX=1000,2000,1400,2300&WIDTH=200&HEIGHT=150&STYLES=&QUERY_LAYERS=test_anchor&INFO_FORMAT=application%2Fvnd.ogc.gml&I=100&J=25" > [RESULT_DEVERSION] +# RUN_PARMS: point_symbol_identification_anchor_no_match3.xml [MAPSERV] QUERY_STRING="MAP=[MAPFILE]&REQUEST=GetFeatureInfo&SERVICE=WMS&VERSION=1.1.0&LAYERS=test_anchor&SRS=EPSG:3857&BBOX=1000,2000,1400,2300&WIDTH=200&HEIGHT=150&STYLES=&QUERY_LAYERS=test_anchor&INFO_FORMAT=application%2Fvnd.ogc.gml&I=88&J=53" > [RESULT_DEVERSION] + + +# RUN_PARMS: point_symbol_identification_mode_query_classauto.txt [MAPSERV] QUERY_STRING="MAP=[MAPFILE]&mode=query&layer=test_classgroup&qlayer=test_rotation_30&imgxy=73+62&imgext=1000+2000+1400+2300&imgsize=200+150" > [RESULT_DEMIME] +# RUN_PARMS: point_symbol_identification_mode_query_classgroup.txt [MAPSERV] QUERY_STRING="MAP=[MAPFILE]&mode=query&layer=test_classgroup&qlayer=test_classgroup&imgxy=73+62&imgext=1000+2000+1400+2300&imgsize=200+150" > [RESULT_DEMIME] + +MAP + +STATUS ON +EXTENT 1000 2000 1400 2300 +SIZE 200 150 +IMAGECOLOR 127 127 127 +SYMBOLSET "etc/symbols.sym" + +WEB + METADATA + "ows_updatesequence" "123" + "wms_title" "Test simple wms" + "wms_onlineresource" "http://localhost/path/to/wms_simple?" + "wms_srs" "EPSG:3857" + "ows_schemas_location" "http://schemas.opengis.net" + "ows_keywordlist" "ogc,wms,mapserver" + "ows_service_onlineresource" "http://www.mapserver.org/" + "ows_fees" "None" + "ows_accessconstraints" "None" + "ows_addresstype" "postal" + "ows_address" "123 SomeRoad Road" + "ows_city" "Toronto" + "ows_stateorprovince" "Ontario" + "ows_postcode" "xxx-xxx" + "ows_country" "Canada" + "ows_contactelectronicmailaddress" "tomkralidis@xxxxxxx.xxx" + "ows_contactvoicetelephone" "+xx-xxx-xxx-xxxx" + "ows_contactfacsimiletelephone" "+xx-xxx-xxx-xxxx" + "ows_contactperson" "Tom Kralidis" + "ows_contactorganization" "MapServer" + "ows_contactposition" "self" + + "ows_rootlayer_title" "My Layers" + "ows_rootlayer_abstract" "These are my layers" + "ows_rootlayer_keywordlist" "layers,list" + "ows_enable_request" "*" # not read at all, all layers contains their setting. + END +END + + PROJECTION + "init=epsg:3857" + END + + WEB + QUERYFORMAT 'tmpl' + END + + OUTPUTFORMAT + NAME 'tmpl' + DRIVER 'TEMPLATE' + MIMETYPE 'text/plain' + FORMATOPTION "FILE=templates/point_symbol_identification.tmpl" + END + +LAYER + NAME "test_rotation_30" + TYPE point + STATUS OFF + TEMPLATE "ttt" + + METADATA + "wms_title" "test_rotation_30" + "wms_description" "test_rotation_30" + "wms_srs" "EPSG:3857" + "gml_include_items" "all" + "ows_enable_request" "*" + END + + EXTENT 1000 2000 1400 2300 + + IDENTIFY + CLASSAUTO + END + + PROJECTION + "init=epsg:3857" + END + + CLASS + GROUP "test" + STYLE + ANGLE 30 + SYMBOL "Road_Works_inner_transparent" + END + END + + FEATURE + POINTS + 1200 2150 + END + END +END + + +LAYER + NAME "test_classgroup" + TYPE point + STATUS OFF + TEMPLATE "ttt" + + EXTENT 1000 2000 1400 2300 + + METADATA + "wms_title" "test_classgroup" + "wms_description" "test_classgroup" + "wms_srs" "EPSG:3857" + "gml_include_items" "all" + "ows_enable_request" "*" + END + + IDENTIFY + CLASSGROUP "test" + END + + PROJECTION + "init=epsg:3857" + END + + CLASS + GROUP "test" + STYLE + ANGLE 30 + SYMBOL "Road_Works_inner_transparent" + END + END + + FEATURE + POINTS + 1200 2100 + END + END + + FEATURE + POINTS + 1200 2150 + END + END + + FEATURE + POINTS + 1201 2151 + END + END +END + + +LAYER + NAME "test_class_minscaledenom_5700" + TYPE point + STATUS OFF + TEMPLATE "ttt" + + METADATA + "wms_title" "test_class_minscaledenom_5700" + "wms_description" "test_class_minscaledenom_5700" + "wms_srs" "EPSG:3857" + "gml_include_items" "all" + "ows_enable_request" "*" + END + + EXTENT 1000 2000 1400 2300 + + IDENTIFY + CLASSAUTO + END + + PROJECTION + "init=epsg:3857" + END + + CLASS + MINSCALEDENOM 5700 + GROUP "test" + STYLE + ANGLE 30 + SYMBOL "Road_Works_inner_transparent" + END + END + + FEATURE + POINTS + 1200 2150 + END + END +END + + +LAYER + NAME "test_style_minscaledenom_5700" + TYPE point + STATUS OFF + TEMPLATE "ttt" + + METADATA + "wms_title" "test_style_minscaledenom_5700" + "wms_description" "test_style_minscaledenom_5700" + "wms_srs" "EPSG:3857" + "gml_include_items" "all" + "ows_enable_request" "*" + END + + EXTENT 1000 2000 1400 2300 + + IDENTIFY + CLASSAUTO + END + + PROJECTION + "init=epsg:3857" + END + + CLASS + GROUP "test" + STYLE + MINSCALEDENOM 5700 + ANGLE 30 + SYMBOL "Road_Works_inner_transparent" + END + END + + FEATURE + POINTS + 1200 2150 + END + END +END + + +LAYER + NAME "test_expression_false" + TYPE point + STATUS OFF + TEMPLATE "ttt" + + METADATA + "wms_title" "test_expression_false" + "wms_description" "test_expression_false" + "wms_srs" "EPSG:3857" + "gml_include_items" "all" + "ows_enable_request" "*" + END + + EXTENT 1000 2000 1400 2300 + + IDENTIFY + CLASSAUTO + END + + PROJECTION + "init=epsg:3857" + END + + CLASS + EXPRESSION (false) + GROUP "test" + STYLE + ANGLE 30 + SYMBOL "Road_Works_inner_transparent" + END + END + + FEATURE + POINTS + 1200 2150 + END + END +END + +SYMBOL + NAME "Road_Works_inner_transparent_with_anchor" + TYPE svg + IMAGE "../misc/data/Road_Works_inner_transparent.svg" + ANCHORPOINT 0.5 1.0 +END + +LAYER + NAME "test_anchor" + TYPE point + STATUS OFF + TEMPLATE "ttt" + + METADATA + "wms_title" "test_anchor" + "wms_description" "test_anchor" + "wms_srs" "EPSG:3857" + "gml_include_items" "all" + "ows_enable_request" "*" + END + + EXTENT 1000 2000 1400 2300 + + IDENTIFY + CLASSAUTO + END + + PROJECTION + "init=epsg:3857" + END + + CLASS + GROUP "test" + STYLE + SYMBOL "Road_Works_inner_transparent_with_anchor" + SIZE 60 + END + END + + FEATURE + POINTS + 1200 2150 + END + END +END + + +END diff --git a/msautotest/wxs/run_test.py b/msautotest/wxs/run_test.py index ee65170a60..0933d7fde9 100755 --- a/msautotest/wxs/run_test.py +++ b/msautotest/wxs/run_test.py @@ -8,17 +8,17 @@ # ############################################################################### # Copyright (c) 2002, Frank Warmerdam -# +# # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: -# +# # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. -# +# # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL @@ -29,14 +29,19 @@ ############################################################################### import os -import pytest import sys -sys.path.append( '../pymod' ) +import pytest + +sys.path.append("../pymod") import mstestlib -@pytest.mark.parametrize('map,out_file,command', mstestlib.get_pytests(os.path.dirname(os.path.abspath(__file__)))) + +@pytest.mark.parametrize( + "map,out_file,command", + mstestlib.get_pytests(os.path.dirname(os.path.abspath(__file__))), +) def test(map, out_file, command, extra_args): mstestlib.run_pytest(map, out_file, command, extra_args) @@ -44,5 +49,5 @@ def test(map, out_file, command, extra_args): ############################################################################### # main() -if __name__ == '__main__': +if __name__ == "__main__": sys.exit(mstestlib.pytest_main()) diff --git a/msautotest/wxs/sos.map b/msautotest/wxs/sos.map index 564e979bf6..a88fd371fa 100644 --- a/msautotest/wxs/sos.map +++ b/msautotest/wxs/sos.map @@ -122,7 +122,6 @@ MAP "init=epsg:4326" END DEBUG ON - TRANSPARENT ON WEB HEADER "templates/query_header.html" FOOTER "templates/query_footer.html" @@ -162,15 +161,16 @@ MAP DEBUG ON TYPE POINT STATUS ON - DUMP TRUE DATA "./data/obs.shp" PROJECTION "init=epsg:4326" END CLASS NAME "obs" - COLOR 255 0 0 - SIZE 10 + STYLE + COLOR 255 0 0 + SIZE 10 + END END METADATA "sos_offering_id" "Water" # mandatory to tie layers to groups diff --git a/msautotest/wxs/templates/point_symbol_identification.tmpl b/msautotest/wxs/templates/point_symbol_identification.tmpl new file mode 100644 index 0000000000..f9282a58b2 --- /dev/null +++ b/msautotest/wxs/templates/point_symbol_identification.tmpl @@ -0,0 +1,3 @@ + +[resultset layer="test_rotation_30"][feature]X=[shpminx],Y=[shpminy][/feature][/resultset] +[resultset layer="test_classgroup"][feature]X=[shpminx],Y=[shpminy][/feature][/resultset] diff --git a/msautotest/wxs/templates/raster_query.html b/msautotest/wxs/templates/raster_query.html new file mode 100644 index 0000000000..db8130acec --- /dev/null +++ b/msautotest/wxs/templates/raster_query.html @@ -0,0 +1,19 @@ + +Blue: [blue]
+Green: [green]
+Red: [red]
+ +Band 1: [value_0]
+[item name="value_1" format="Band 2: $value" nullformat=""]
+Band 3: [item name="value_2" padding=5]
+Band 4: [item name="value_3" pattern="^\d*\.\d+$" nullformat="-1"]
+[item name="value_4" format="Band 5: $value"]
+[item name="value_5" format="Band 6: $value"]
+[item name="value_6" format="Band 7: $value"]
+[item name="value_7" format="Band 8: $value"]
+[item name="value_8" format="Band 9: $value"]
+Band 99: [item name="value_99" nullformat="missing" ignoremissing="true"]
+ +Value List: [value_list]
+X: [item name="x" precision=0]
+Y: [item name="y" precision=2]
\ No newline at end of file diff --git a/msautotest/wxs/tomk_workshop.map b/msautotest/wxs/tomk_workshop.map index 5adf1a934a..e581145cb7 100644 --- a/msautotest/wxs/tomk_workshop.map +++ b/msautotest/wxs/tomk_workshop.map @@ -86,13 +86,13 @@ MAP END # image format options - OUTPUTFORMAT - NAME png - DRIVER "GD/PNG" - MIMETYPE "image/png" - IMAGEMODE RGBA - EXTENSION "png" - END + OUTPUTFORMAT + NAME png + DRIVER "AGG/PNG8" + MIMETYPE "image/png" + EXTENSION "png" + TRANSPARENT ON + END OUTPUTFORMAT NAME GEOTIFF_RGB @@ -247,7 +247,7 @@ MAP # sets: # /WMT_MS_Capabilities/Service/ContactInformation/ContactElectronicMailAddress - # /WCS_Capabilities/Service/contactInfo/address/eletronicMailAddress + # /WCS_Capabilities/Service/contactInfo/address/electronicMailAddress "ows_contactelectronicmailaddress" "tom.kralidis@ec.gc.ca" # sets: @@ -256,7 +256,7 @@ MAP # /WFS_Capabilities/FeatureTypeList/FeatureType[*]/SRS # unless differently defined in LAYER object # if you are setting > 1 SRS for WMS, you need to define "wms_srs" and "wfs_srs" - # seperately because OGC:WFS only accepts one OUTPUT SRS + # separately because OGC:WFS only accepts one OUTPUT SRS "ows_srs" "EPSG:4326" # sets /WMT_MS_Capabilities/Capability/Layer/Attribution/OnlineResource/@xlink:href @@ -355,9 +355,6 @@ MAP # what type of data is this? TYPE RASTER - # allow data access via query and WCS - DUMP TRUE - # always returned with interface STATUS ON @@ -546,9 +543,6 @@ MAP END - # data is queryable - DUMP TRUE - # query templates for HTML-based queries # responds to OGC:WMS request=GetFeatureInfo......&info_format=text/html HEADER ./templates/rivers_query_header.html @@ -560,7 +554,9 @@ MAP # how will this data look? CLASS NAME "Rivers" - COLOR 0 0 255 + STYLE + COLOR 0 0 255 + END # if you want to use a canned graphic for the # legend do it like this. # this is what will show up when a user does either @@ -577,7 +573,6 @@ MAP NAME "toronto" STATUS ON TYPE RASTER - DUMP TRUE DATA ./data/toronto.tif PROJECTION "init=epsg:26917" diff --git a/msautotest/wxs/wcs_custom_projection.map b/msautotest/wxs/wcs_custom_projection.map new file mode 100644 index 0000000000..07046607f3 --- /dev/null +++ b/msautotest/wxs/wcs_custom_projection.map @@ -0,0 +1,57 @@ +# +# Test WCS with non-EPSG projections +# +# REQUIRES: INPUT=GDAL OUTPUT=PNG SUPPORTS=WCS + +# RUN_PARMS: wcs_custom_projection_capabilities100.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WCS&VERSION=1.0.0&REQUEST=GetCapabilities" > [RESULT_DEMIME] +# RUN_PARMS: wcs_custom_projection_capabilities111.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WCS&VERSION=1.1.1&REQUEST=GetCapabilities" > [RESULT_DEMIME] +# RUN_PARMS: wcs_custom_projection_capabilities201.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WCS&VERSION=2.0.1&REQUEST=GetCapabilities" > [RESULT_DEMIME] + +# RUN_PARMS: wcs_custom_projection_describe100.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WCS&VERSION=1.0.0&REQUEST=DescribeCoverage&COVERAGE=test" > [RESULT_DEMIME] +# RUN_PARMS: wcs_custom_projection_describe111.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WCS&VERSION=1.1.1&REQUEST=DescribeCoverage&IDENTIFIER=test" > [RESULT_DEMIME] +# RUN_PARMS: wcs_custom_projection_describe201.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WCS&VERSION=2.0.1&REQUEST=DescribeCoverage&COVERAGEID=test" > [RESULT_DEMIME] + +# RUN_PARMS: wcs_custom_projection_coverage100.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WCS&VERSION=1.0.0&REQUEST=GetCoverage&COVERAGE=test&BBOX=-3276599.0027238373,8498088.094072288,-3258457.2498260457,8507095.190921152&CRS=ESRI:53009&WIDTH=512&HEIGHT=254&RESPONSE_CRS=ESRI:53009&FORMAT=png" > [RESULT_DEMIME] +# RUN_PARMS: wcs_custom_projection_coverage111.dat [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WCS&VERSION=1.1.1&REQUEST=GetCoverage&IDENTIFIER=test&BOUNDINGBOX=-3276599.0027238373,8498088.094072288,-3258457.2498260457,8507095.190921152,urn:ogc:def:crs:ESRI::53009&&WIDTH=512&HEIGHT=254&OUTPUTCRS=urn:ogc:def:crs:ESRI::53009&FORMAT=png" > [RESULT_DEMIME] +# RUN_PARMS: wcs_custom_projection_coverage201.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WCS&VERSION=2.0.1&REQUEST=GetCoverage&COVERAGEID=test&SUBSETTINGCRS=urn:ogc:def:crs:ESRI::53009&SUBSET=x(-3276599.0027238373,-3258457.2498260457)&SUBSET=y(8498088.094072288,8507095.190921152)&SCALESIZE=x(512),y(254)&OUTPUTCRS=urn:ogc:def:crs:ESRI::53009&FORMAT=image/png" > [RESULT_DEMIME] + +# RUN_PARMS: wcs_custom_projection_42304_coverage100.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WCS&VERSION=1.0.0&REQUEST=GetCoverage&COVERAGE=test&BBOX=-3276599.0027238373,8498088.094072288,-3258457.2498260457,8507095.190921152&CRS=ESRI:53009&WIDTH=512&HEIGHT=254&RESPONSE_CRS=epsg2:42304&FORMAT=png" > [RESULT_DEMIME] +# RUN_PARMS: wcs_custom_projection_42304_coverage111.dat [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WCS&VERSION=1.1.1&REQUEST=GetCoverage&IDENTIFIER=test&BOUNDINGBOX=-3276599.0027238373,8498088.094072288,-3258457.2498260457,8507095.190921152,urn:ogc:def:crs:ESRI::53009&&WIDTH=512&HEIGHT=254&OUTPUTCRS=urn:ogc:def:crs:epsg2::42304&FORMAT=png" > [RESULT_DEMIME] +# RUN_PARMS: wcs_custom_projection_42304_coverage201.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WCS&VERSION=2.0.1&REQUEST=GetCoverage&COVERAGEID=test&SUBSETTINGCRS=urn:ogc:def:crs:ESRI::53009&SUBSET=x(-3276599.0027238373,-3258457.2498260457)&SUBSET=y(8498088.094072288,8507095.190921152)&SCALESIZE=x(512),y(254)&OUTPUTCRS=urn:ogc:def:crs:epsg2::42304&FORMAT=image/png" > [RESULT_DEMIME] + +MAP + +NAME WCS_CUSTOM_PROJECTION +SIZE 400 400 +EXTENT -11137750 8151000 -11037500 8195750 + +PROJECTION + "esri:54052" +END + +WEB + METADATA + "wcs_label" "WCS Projection Demo" + "ows_enable_request" "*" + "wcs_onlineresource" "http://localhost/path/to/wcs_custom_projection?" + "ows_srs" "ESRI:54052 EPSG:4326 ESRI:53009 epsg2:42304" + "wcs_formats" "GTiff PNG" + END +END + +LAYER + NAME test + TYPE raster + DATA data/tileSG-000-019_3-3.tif + METADATA + "ows_srs" "ESRI:54052 EPSG:4326 ESRI:53009 epsg2:42304" + "wcs_label" "test/soil" + "wcs_rangeset_name" "Range 1" ### required to support DescribeCoverage request + "wcs_rangeset_label" "My Label" + END + PROJECTION + "esri:54052" + END +END + +END diff --git a/msautotest/wxs/wcs_grib_input_output.map b/msautotest/wxs/wcs_grib_input_output.map index f9a948e9d5..6b26f2a7b6 100644 --- a/msautotest/wxs/wcs_grib_input_output.map +++ b/msautotest/wxs/wcs_grib_input_output.map @@ -17,7 +17,6 @@ EXTENT -180 -90 180 90 MAXSIZE 5000 IMAGETYPE PNG -TRANSPARENT OFF SHAPEPATH "data" OUTPUTFORMAT @@ -81,7 +80,6 @@ LAYER NAME temperatures TYPE raster STATUS ON - DUMP TRUE DATA "temperatures.grb2" PROJECTION diff --git a/msautotest/wxs/wcs_grib_output.map b/msautotest/wxs/wcs_grib_output.map index 930dec6eb4..f51a921618 100644 --- a/msautotest/wxs/wcs_grib_output.map +++ b/msautotest/wxs/wcs_grib_output.map @@ -17,7 +17,6 @@ EXTENT -180 -90 180 90 MAXSIZE 5000 IMAGETYPE PNG -TRANSPARENT OFF SHAPEPATH "data" OUTPUTFORMAT @@ -81,7 +80,6 @@ LAYER NAME temperatures TYPE raster STATUS ON - DUMP TRUE DATA "temperatures.tif" PROJECTION diff --git a/msautotest/wxs/wcs_input_rot_lon_lat_space_lon0_beyond_180.map b/msautotest/wxs/wcs_input_rot_lon_lat_space_lon0_beyond_180.map new file mode 100644 index 0000000000..8d05df31e4 --- /dev/null +++ b/msautotest/wxs/wcs_input_rot_lon_lat_space_lon0_beyond_180.map @@ -0,0 +1,49 @@ +# +# +# Test querying in EPSG:4326 a raster georeferenced in rotated pole lat/lon +# with lon_0 > 180 +# +# + +# RUN_PARMS: wcs_input_rot_pole_lon_lat_space_lon0_beyond_180.tif [MAPSERV] QUERY_STRING="map=[MAPFILE]&REQUEST=GetCoverage&SERVICE=WCS&VERSION=2.0.1&COVERAGEID=hrepa-sample&FORMAT=image/tiff&SUBSETTINGCRS=EPSG:4326&SUBSET=x(-120,-85)&SUBSET=y(48,66)" > [RESULT_DEMIME] + +MAP + NAME "" + IMAGETYPE "PNG" + EXTENT -180 -90 180 90 + MAXSIZE 16384 + SIZE 500 300 + CONFIG "PROJ_LIB" "./data/proj/input_rot_pole_lon_lat_space_lon0_beyond_180" + PROJECTION + "init=epsg:4326" + END + OUTPUTFORMAT + NAME "GEOTIFF_32" + DRIVER "GDAL/GTiff" + MIMETYPE "image/tiff" + IMAGEMODE FLOAT32 + EXTENSION "tif" + END + WEB + METADATA + "ows_srs" "EPSG:4326 EPSG:102977" + "ows_enable_request" "*" + "ows_extent" "-180 -90 180 90" + "ows_onlineresource" "http://example.com" + END + END + LAYER + NAME "hrepa-sample" + TYPE RASTER + TEMPLATE "ttt.html" + PROJECTION + "init=epsg:102977" + END + DATA "data/input_rot_pole_lon_lat_space_lon0_beyond_180.tif" + METADATA + "ows_extent" "-13.6849561 -11.1662507 41.1700330 15.5637507" + "ows_size" "200 97" + "ows_resolution" "0.274274945045819 -0.275567024872444" + END + END +END diff --git a/msautotest/wxs/wcs_inspire_scenario1.map b/msautotest/wxs/wcs_inspire_scenario1.map index 6c6c829964..7a5354c0a6 100644 --- a/msautotest/wxs/wcs_inspire_scenario1.map +++ b/msautotest/wxs/wcs_inspire_scenario1.map @@ -30,7 +30,6 @@ MAXSIZE 5000 #CONFIG "MS_ERRORFILE" "stderr" IMAGETYPE PNG -TRANSPARENT OFF SHAPEPATH "data" OUTPUTFORMAT @@ -40,13 +39,6 @@ OUTPUTFORMAT IMAGEMODE BYTE EXTENSION "tif" END -OUTPUTFORMAT - NAME GDPNGGREY - DRIVER "GD/PNG" - MIMETYPE "image/png; mode=8bit" - IMAGEMODE PC256 - EXTENSION "png" -END OUTPUTFORMAT NAME AAIGRID DRIVER "GDAL/AAIGRID" @@ -114,7 +106,6 @@ LAYER NAME grey TYPE raster STATUS ON - DUMP TRUE TILEINDEX "wcs_index.shp" TILEITEM "location" diff --git a/msautotest/wxs/wcs_inspire_scenario2.map b/msautotest/wxs/wcs_inspire_scenario2.map index 9be566ddd0..4d9e4aba24 100644 --- a/msautotest/wxs/wcs_inspire_scenario2.map +++ b/msautotest/wxs/wcs_inspire_scenario2.map @@ -30,7 +30,6 @@ MAXSIZE 5000 #CONFIG "MS_ERRORFILE" "stderr" IMAGETYPE PNG -TRANSPARENT OFF SHAPEPATH "data" OUTPUTFORMAT @@ -40,13 +39,6 @@ OUTPUTFORMAT IMAGEMODE BYTE EXTENSION "tif" END -OUTPUTFORMAT - NAME GDPNGGREY - DRIVER "GD/PNG" - MIMETYPE "image/png; mode=8bit" - IMAGEMODE PC256 - EXTENSION "png" -END OUTPUTFORMAT NAME AAIGRID DRIVER "GDAL/AAIGRID" @@ -118,7 +110,6 @@ LAYER NAME grey TYPE raster STATUS ON - DUMP TRUE TILEINDEX "wcs_index.shp" TILEITEM "location" diff --git a/msautotest/wxs/wcs_mask.map b/msautotest/wxs/wcs_mask.map index 99bbcd8403..41758cd996 100644 --- a/msautotest/wxs/wcs_mask.map +++ b/msautotest/wxs/wcs_mask.map @@ -122,7 +122,6 @@ MAXSIZE 5000 #CONFIG "MS_ERRORFILE" "stderr" IMAGETYPE PNG -TRANSPARENT OFF SHAPEPATH "data" OUTPUTFORMAT @@ -132,13 +131,6 @@ OUTPUTFORMAT IMAGEMODE BYTE EXTENSION "tif" END -OUTPUTFORMAT - NAME GDPNGGREY - DRIVER "GD/PNG" - MIMETYPE "image/png; mode=8bit" - IMAGEMODE PC256 - EXTENSION "png" -END OUTPUTFORMAT NAME AAIGRID DRIVER "GDAL/AAIGRID" @@ -206,7 +198,6 @@ LAYER NAME grey TYPE raster STATUS ON - DUMP TRUE TILEINDEX "wcs_index.shp" TILEITEM "location" MASK "mask" diff --git a/msautotest/wxs/wcs_multi.map b/msautotest/wxs/wcs_multi.map index 4f34c4d71d..1928e63cbd 100644 --- a/msautotest/wxs/wcs_multi.map +++ b/msautotest/wxs/wcs_multi.map @@ -123,7 +123,6 @@ LAYER NAME multi TYPE raster STATUS ON - DUMP TRUE DATA data/multiband.tif @@ -156,7 +155,6 @@ LAYER NAME multi_new TYPE raster STATUS ON - DUMP TRUE DATA data/multiband.tif @@ -205,7 +203,6 @@ LAYER NAME multi_no_metadata TYPE raster STATUS ON - DUMP TRUE DATA data/multiband.tif diff --git a/msautotest/wxs/wcs_multiple_metadatalink.map b/msautotest/wxs/wcs_multiple_metadatalink.map index 23373123d9..ec0892e36d 100644 --- a/msautotest/wxs/wcs_multiple_metadatalink.map +++ b/msautotest/wxs/wcs_multiple_metadatalink.map @@ -17,7 +17,6 @@ MAXSIZE 5000 #CONFIG "MS_ERRORFILE" "stderr" IMAGETYPE PNG -TRANSPARENT OFF SHAPEPATH "data" OUTPUTFORMAT @@ -27,13 +26,6 @@ OUTPUTFORMAT IMAGEMODE BYTE EXTENSION "tif" END -OUTPUTFORMAT - NAME GDPNGGREY - DRIVER "GD/PNG" - MIMETYPE "image/png; mode=8bit" - IMAGEMODE PC256 - EXTENSION "png" -END OUTPUTFORMAT NAME AAIGRID DRIVER "GDAL/AAIGRID" @@ -86,7 +78,6 @@ LAYER NAME grey TYPE raster STATUS ON - DUMP TRUE TILEINDEX "wcs_index.shp" TILEITEM "location" diff --git a/msautotest/wxs/wcs_netcdf_3d_input_output.map b/msautotest/wxs/wcs_netcdf_3d_input_output.map new file mode 100644 index 0000000000..577292a44e --- /dev/null +++ b/msautotest/wxs/wcs_netcdf_3d_input_output.map @@ -0,0 +1,94 @@ +# +# Test WCS. +# +# REQUIRES: INPUT=GDAL OUTPUT=PNG SUPPORTS=WCS + +# RUN_PARMS: wcs_netcdf_3d_input_output.nc [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WCS&VERSION=2.0.1&REQUEST=GetCoverage&COVERAGEID=multi&FORMAT=application/x-netCDF&RANGESUBSET=2,3" > [RESULT_DEMIME] + +MAP + +NAME TEST +SIZE 105 61 +EXTENT 14.4702712 47.8188382 18.0111282 49.8911432 + +#CONFIG "MS_ERRORFILE" "stderr" + +OUTPUTFORMAT + NAME netCDF + DRIVER "GDAL/netCDF" + MIMETYPE "application/x-netCDF" + IMAGEMODE Float32 + EXTENSION "nc" +END + +PROJECTION + "init=epsg:4326" +END + +WEB + METADATA + # OWS stuff for server + "ows_updatesequence" "2007-10-30T14:23:38Z" + "ows_title" "First Test Service" + "ows_fees" "NONE" + "ows_accessconstraints" "NONE" + "ows_abstract" "Test Abstract" + "ows_keywordlist" "keyword,list" + "ows_service_onlineresource" "http://198.202.74.215/cgi-bin/wcs_demo" + "ows_contactorganization" "OSGeo" + "ows_contactperson" "Frank Warmerdam" + "ows_contactposition" "Software Developer" + "ows_contactvoicetelephone" "(613) 754-2041" + "ows_contactfacsimiletelephone" "(613) 754-2041x343" + "ows_address" "3594 Foymount Rd" + "ows_city" "Eganville" + "ows_stateorprovince" "Ontario" + "ows_postcode" "K0J 1T0" + "ows_country" "Canada" + "ows_contactelectronicmailaddress" "warmerdam@pobox.com" + "ows_hoursofservice" "0800h - 1600h EST" + "ows_contactinstructions" "during hours of service" + "ows_role" "staff" + "ows_enable_request" "*" + + # OGC:WCS + "wcs_label" "Test Label" + "wcs_description" "Test description" + "wcs_onlineresource" "http://devgeo.cciw.ca/cgi-bin/mapserv/ecows" + "wcs_metadatalink_href" "http://devgeo.cciw.ca/index.html" + END #METADATA +END #WEB + +LAYER + NAME multi + TYPE raster + STATUS ON + + DATA expected/wcs_netcdf_3d_output.nc + + PROJECTION + "init=epsg:4326" + END + METADATA + "ows_extent" "14.4702712 47.8188382 18.0111282 49.8911432" + "wcs_size" "105 61" + + "wcs_label" "Test label" + "wcs_formats" "netCDF" + "wcs_native_format" "image/tiff" + "wcs_description" "Test description" + "wcs_metadatalink_href" "http://www.gdal.org/metadata_test_link.html" + "wcs_keywordlist" "test,mapserver" + "wcs_abstract" "abstract" + "wcs_imagemode" "BYTE" + + "wcs_bandcount" "3" + "wcs_rangeset_axes" "bands" + "wcs_rangeset_name" "name" + "wcs_rangeset_label" "Bands" + "wcs_rangeset_description" "description" + "wcs_rangeset_nullvalue" "0" + END +END + +END diff --git a/msautotest/wxs/wcs_netcdf_3d_output.map b/msautotest/wxs/wcs_netcdf_3d_output.map new file mode 100644 index 0000000000..f19c039385 --- /dev/null +++ b/msautotest/wxs/wcs_netcdf_3d_output.map @@ -0,0 +1,110 @@ +# +# Test WCS. +# +# REQUIRES: INPUT=GDAL OUTPUT=PNG SUPPORTS=WCS + +# RUN_PARMS: wcs_netcdf_3d_output.nc [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WCS&VERSION=2.0.1&REQUEST=GetCoverage&COVERAGEID=multi&FORMAT=application/x-netCDF&RANGESUBSET=1,5,9" > [RESULT_DEMIME] + +MAP + +NAME TEST +SIZE 105 61 +EXTENT 14.4702712 47.8188382 18.0111282 49.8911432 + +#CONFIG "MS_ERRORFILE" "stderr" + +OUTPUTFORMAT + NAME netCDF + DRIVER "GDAL/netCDF" + MIMETYPE "application/x-netCDF" + IMAGEMODE Float32 + EXTENSION "nc" +END + +PROJECTION + "init=epsg:4326" +END + +WEB + METADATA + # OWS stuff for server + "ows_updatesequence" "2007-10-30T14:23:38Z" + "ows_title" "First Test Service" + "ows_fees" "NONE" + "ows_accessconstraints" "NONE" + "ows_abstract" "Test Abstract" + "ows_keywordlist" "keyword,list" + "ows_service_onlineresource" "http://198.202.74.215/cgi-bin/wcs_demo" + "ows_contactorganization" "OSGeo" + "ows_contactperson" "Frank Warmerdam" + "ows_contactposition" "Software Developer" + "ows_contactvoicetelephone" "(613) 754-2041" + "ows_contactfacsimiletelephone" "(613) 754-2041x343" + "ows_address" "3594 Foymount Rd" + "ows_city" "Eganville" + "ows_stateorprovince" "Ontario" + "ows_postcode" "K0J 1T0" + "ows_country" "Canada" + "ows_contactelectronicmailaddress" "warmerdam@pobox.com" + "ows_hoursofservice" "0800h - 1600h EST" + "ows_contactinstructions" "during hours of service" + "ows_role" "staff" + "ows_enable_request" "*" + + # OGC:WCS + "wcs_label" "Test Label" + "wcs_description" "Test description" + "wcs_onlineresource" "http://devgeo.cciw.ca/cgi-bin/mapserv/ecows" + "wcs_metadatalink_href" "http://devgeo.cciw.ca/index.html" + END #METADATA +END #WEB + +LAYER + NAME multi + TYPE raster + STATUS ON + + DATA data/multiband.tif + + PROJECTION + "init=epsg:4326" + END + METADATA + "ows_extent" "14.4702712 47.8188382 18.0111282 49.8911432" + "wcs_size" "105 61" + + "wcs_label" "Test label" + "wcs_formats" "netCDF" + "wcs_native_format" "image/tiff" + "wcs_description" "Test description" + "wcs_metadatalink_href" "http://www.gdal.org/metadata_test_link.html" + "wcs_keywordlist" "test,mapserver" + "wcs_abstract" "abstract" + "wcs_imagemode" "BYTE" + + "wcs_bandcount" "9" + "wcs_rangeset_axes" "bands" + "wcs_rangeset_name" "name" + "wcs_rangeset_label" "Bands" + "wcs_rangeset_description" "description" + "wcs_rangeset_nullvalue" "0" + + # Metadata items to apply to the "time" extra dimension. + "wcs_outputformat_netCDF_mdi_default_time#calendar" "standard" + "wcs_outputformat_netCDF_mdi_default_time#standard_name" "time" + "wcs_outputformat_netCDF_mdi_default_time#units" "hours since 1900-01-01 00:00:00" + + # Values of each band along the "time" extra dimension. + "wcs_outputformat_netCDF_mdi_BAND_1_default_NETCDF_DIM_time" "10" + "wcs_outputformat_netCDF_mdi_BAND_2_default_NETCDF_DIM_time" "20" + "wcs_outputformat_netCDF_mdi_BAND_3_default_NETCDF_DIM_time" "30" + "wcs_outputformat_netCDF_mdi_BAND_4_default_NETCDF_DIM_time" "40" + "wcs_outputformat_netCDF_mdi_BAND_5_default_NETCDF_DIM_time" "50" + "wcs_outputformat_netCDF_mdi_BAND_6_default_NETCDF_DIM_time" "60" + "wcs_outputformat_netCDF_mdi_BAND_7_default_NETCDF_DIM_time" "70" + "wcs_outputformat_netCDF_mdi_BAND_8_default_NETCDF_DIM_time" "80" + "wcs_outputformat_netCDF_mdi_BAND_9_default_NETCDF_DIM_time" "90" + END +END + +END diff --git a/msautotest/wxs/wcs_netcdf_input_output.map b/msautotest/wxs/wcs_netcdf_input_output.map new file mode 100644 index 0000000000..40a2d3c8c7 --- /dev/null +++ b/msautotest/wxs/wcs_netcdf_input_output.map @@ -0,0 +1,111 @@ +# +# Test WCS with netCDF input and output +# +# REQUIRES: INPUT=GDAL OUTPUT=PNG SUPPORTS=WCS + +# RUN_PARMS: wcs_netcdf_input_output_wcs10_get_coverage.nc [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WCS&REQUEST=GetCoverage&VERSION=1.0.0&COVERAGE=precipitation&CRS=EPSG:4326&BBOX=-80,-20,-79.5,-19.5&RESX=0.25&RESY=0.25&FORMAT=netCDF" > [RESULT_DEMIME] + +# RUN_PARMS: wcs_netcdf_input_output_wcs20_get_coverage.nc [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WCS&REQUEST=GetCoverage&VERSION=2.0.1&COVERAGEID=precipitation&FORMAT=application/x-netcdf&SUBSET=long(-80,-79.5)&SUBSETTINGCRS=http://www.opengis.net/def/crs/EPSG/0/4326" > [RESULT_DEMIME] + +MAP + +NAME TEST +SIZE 400 300 +EXTENT -180 -90 180 90 +MAXSIZE 5000 + +IMAGETYPE PNG +SHAPEPATH "data" + +OUTPUTFORMAT + NAME netCDF + DRIVER "GDAL/netCDF" + MIMETYPE "application/x-netCDF" + IMAGEMODE Float32 + EXTENSION "nc" +END + +PROJECTION + "init=epsg:4326" +END + +WEB + METADATA + # OWS stuff for server + "ows_updatesequence" "2007-10-30T14:23:38Z" + "ows_title" "First Test Service" + "ows_fees" "NONE" + "ows_accessconstraints" "NONE" + "ows_abstract" "Test Abstract" + "ows_keywordlist" "keyword,list" + "ows_service_onlineresource" "http://198.202.74.215/cgi-bin/wcs_demo" + "ows_contactorganization" "OSGeo" + "ows_contactperson" "Frank Warmerdam" + "ows_contactposition" "Software Developer" + "ows_contactvoicetelephone" "(613) 754-2041" + "ows_contactfacsimiletelephone" "(613) 754-2041x343" + "ows_address" "3594 Foymount Rd" + "ows_city" "Eganville" + "ows_stateorprovince" "Ontario" + "ows_postcode" "K0J 1T0" + "ows_country" "Canada" + "ows_contactelectronicmailaddress" "warmerdam@pobox.com" + "ows_hoursofservice" "0800h - 1600h EST" + "ows_contactinstructions" "during hours of service" + "ows_role" "staff" + "ows_enable_request" "*" + "ows_srs" "EPSG:4326" + + # OGC:WCS + "wcs_label" "Test Label" + "wcs_description" "Test description" + "wcs_onlineresource" "http://devgeo.cciw.ca/cgi-bin/mapserv/ecows" + "wcs_metadatalink_href" "http://devgeo.cciw.ca/index.html" + "wcs_formats" "netCDF" + END +END + +LAYER + NAME precipitation + TYPE raster + STATUS ON + DATA "trmm-2x2.nc" + + PROJECTION + "init=epsg:4326" + END + METADATA + "ows_extent" "-80 -20 -79.5 -19.5" + "wcs_label" "Test label" + "ows_srs" "EPSG:4326" + "wcs_resolution" "0.25 0.25" + "wcs_bandcount" "1" + "wcs_imagemode" "Float32" + "wcs_formats" "netCDF" + "wcs_description" "Test description" + "wcs_metadatalink_href" "http://www.gdal.org/metadata_test_link.html" + "wcs_keywordlist" "test,mapserver" + "wcs_abstract" "abstract" + + # WCS 2.0 stuff + "wcs_native_format" "application/x-netcdf" + "wcs_band_names" "precipitation" + "precipitation_band_interpretation" "interp" + "precipitation_band_uom" "uom" + "precipitation_band_definition" "precipitation" + "precipitation_band_description" "precipitation" + "precipitation_interval" "-100 100" + "precipitation_significant_figures" "1" + + # WCS 1.x stuff + "wcs_nativeformat" "netCDF" + "wcs_rangeset_axes" "bands" + "wcs_rangeset_name" "precipitation" + "wcs_rangeset_label" "Bands" + "wcs_rangeset_description" "precipitation" + + "wcs_rangeset_nullvalue" "-9999.9004" + END +END + +END diff --git a/msautotest/wxs/wcs_post.map b/msautotest/wxs/wcs_post.map index d2391373ac..52554d1e6f 100644 --- a/msautotest/wxs/wcs_post.map +++ b/msautotest/wxs/wcs_post.map @@ -156,7 +156,6 @@ SIZE 400 300 EXTENT 0 0 400 300 IMAGETYPE PNG -TRANSPARENT OFF SHAPEPATH "data" OUTPUTFORMAT @@ -166,20 +165,6 @@ OUTPUTFORMAT IMAGEMODE BYTE EXTENSION "tif" END -OUTPUTFORMAT - NAME GDPNG - DRIVER "AGG/PNG" - MIMETYPE "image/png" - IMAGEMODE RGB - EXTENSION "png" -END -OUTPUTFORMAT - NAME GDPNGGREY - DRIVER "GD/PNG" - MIMETYPE "image/png; mode=8bit" - IMAGEMODE PC256 - EXTENSION "png" -END OUTPUTFORMAT NAME AAIGRID DRIVER "GDAL/AAIGRID" @@ -231,7 +216,6 @@ LAYER NAME grey TYPE raster STATUS ON - DUMP TRUE TILEINDEX "wcs_index.shp" TILEITEM "location" @@ -244,7 +228,7 @@ LAYER "ows_srs" "EPSG:32611 EPSG:4326" "wcs_resolution" "10 10" "wcs_bandcount" "1" - "wcs_formats" "GEOTIFF_BYTE GDPNG AAIGRID" + "wcs_formats" "GEOTIFF_BYTE PNG AAIGRID" "wcs_nativeformat" "GeoTIFF" "wcs_description" "Test description" "wcs_metadatalink_href" "http://www.gdal.org/metadata_test_link.html" diff --git a/msautotest/wxs/wcs_simple.map b/msautotest/wxs/wcs_simple.map index 0c68e4f1fc..73d7fa7600 100644 --- a/msautotest/wxs/wcs_simple.map +++ b/msautotest/wxs/wcs_simple.map @@ -23,7 +23,10 @@ # # Capabilities 1.0.0 # RUN_PARMS: wcs_cap.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WCS&VERSION=1.0.0&REQUEST=GetCapabilities" > [RESULT_DEVERSION] [RESULT_DEMIME] -# RUN_PARMS: wcs_cap.txt [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WCS&VERSION=1.0.0&REQUEST=GetCapabilities" > [RESULT_DEVERSION] [RESULT] +# Also test duplicated parameter not to cause memory leak +# RUN_PARMS: wcs_cap.txt [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WCS&VERSION=1.0.0&VERSION=1.0.0&REQUEST=GetCapabilities" > [RESULT_DEVERSION] [RESULT] +# +# RUN_PARMS: wcs10_caps_section_error.txt [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WCS&VERSION=1.0.0&REQUEST=GetCapabilities&SECTION=error" > [RESULT] # # Capabilities updatesequence (less than) # RUN_PARMS: wcs_caps_updatesequence.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WCS&VERSION=1.0.0&REQUEST=GetCapabilities&updatesequence=1999-10-21T12:22:33Z" > [RESULT_DEMIME] @@ -51,7 +54,6 @@ # Capabilities 1.1 selected sections # RUN_PARMS: wcs11_caps_section3.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WCS&VERSION=1.1.1&REQUEST=GetCapabilities§ions=All" > [RESULT_DEMIME] # -# # Coverage description # RUN_PARMS: wcs_describe.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WCS&VERSION=1.0.0&REQUEST=DescribeCoverage&COVERAGE=grey" > [RESULT_DEMIME] # @@ -272,7 +274,6 @@ MAXSIZE 5000 #CONFIG "MS_ERRORFILE" "stderr" IMAGETYPE PNG -TRANSPARENT OFF SHAPEPATH "data" OUTPUTFORMAT @@ -282,13 +283,6 @@ OUTPUTFORMAT IMAGEMODE BYTE EXTENSION "tif" END -OUTPUTFORMAT - NAME GDPNGGREY - DRIVER "GD/PNG" - MIMETYPE "image/png; mode=8bit" - IMAGEMODE PC256 - EXTENSION "png" -END OUTPUTFORMAT NAME AAIGRID DRIVER "GDAL/AAIGRID" @@ -341,7 +335,6 @@ LAYER NAME grey TYPE raster STATUS ON - DUMP TRUE TILEINDEX "wcs_index.shp" TILEITEM "location" diff --git a/msautotest/wxs/wcs_simple_layer_specific_option.map b/msautotest/wxs/wcs_simple_layer_specific_option.map index c77abdabf8..9b526f5548 100644 --- a/msautotest/wxs/wcs_simple_layer_specific_option.map +++ b/msautotest/wxs/wcs_simple_layer_specific_option.map @@ -17,7 +17,6 @@ MAXSIZE 5000 #CONFIG "MS_ERRORFILE" "stderr" IMAGETYPE PNG -TRANSPARENT OFF SHAPEPATH "data" OUTPUTFORMAT @@ -71,7 +70,6 @@ LAYER NAME grey TYPE raster STATUS ON - DUMP TRUE DATA "grey.tif" PROJECTION @@ -103,6 +101,10 @@ Acquisition: 1999-10-11 18:47" # Will not do anything useful as only the GRIB driver of GDAL 2.3.0 has BAND specific creation option, but at least exercices the code "wcs_outputformat_GEOTIFF_creationoption_BAND_1_foo" "bar" "wcs_outputformat_GEOTIFF_creationoption_BAND_10_foo" "bar" + + "wcs_outputformat_GEOTIFF_mdi_default_FOO" "BAR" + "wcs_outputformat_GEOTIFF_mdi_BAND_1_default_BAR" "BAR_BAND_1" + "wcs_outputformat_GEOTIFF_mdi_BAND_10_default_BAZ" "BAZ_BAND_10" END END diff --git a/msautotest/wxs/wcs_tileindexlayer.map b/msautotest/wxs/wcs_tileindexlayer.map new file mode 100644 index 0000000000..a643b81a46 --- /dev/null +++ b/msautotest/wxs/wcs_tileindexlayer.map @@ -0,0 +1,114 @@ +# +# REQUIRES: INPUT=GDAL OUTPUT=PNG SUPPORTS=WCS SUPPORTS=PROJ +# +# RUN_PARMS: wcs_get_capabilities_indexlayers.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WCS&VERSION=1.0.0&REQUEST=GetCapabilities" > [RESULT_DEVERSION] +# +# RUN_PARMS: wcs_describe_coverage_indexlayers_a.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WCS&VERSION=1.0.0&REQUEST=DescribeCoverage&COVERAGE=a" > [RESULT_DEVERSION] +# +# RUN_PARMS: wcs_get_coverage_indexlayers_a.tif [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WCS&VERSION=1.0.0&REQUEST=GetCoverage&WIDTH=8&HEIGHT=8&FORMAT=image/tiff&BBOX=110.0,-18,118.0,-10.0&COVERAGE=a&CRS=EPSG:4326" > [RESULT_DEMIME] +# +# RUN_PARMS: wcs_get_coverage_indexlayers_a_20200101.tif [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WCS&VERSION=1.0.0&REQUEST=GetCoverage&WIDTH=8&HEIGHT=8&FORMAT=image/tiff&BBOX=110.0,-18,118.0,-10.0&COVERAGE=a&CRS=EPSG:4326&TIME=2020-01-01" > [RESULT_DEMIME] +# + +MAP + +NAME TEST +STATUS ON +SIZE 8 8 +EXTENT 110 -18 118 -10 +IMAGECOLOR 0 0 0 + +PROJECTION + "+init=epsg:4326" +END + +OUTPUTFORMAT + NAME GEOTIFF_F32 + DRIVER "GDAL/GTiff" + MIMETYPE "image/tiff" + IMAGEMODE FLOAT32 + EXTENSION "tif" +END + + +# +# Start of web interface definition +# +WEB + + IMAGEPATH "/tmp/ms_tmp/" + IMAGEURL "/ms_tmp/" + + METADATA + "wcs_onlineresource" "http://localhost/path/to/?" + "wcs_srs" "EPSG:4326" + "wcs_label" "title" + "ows_enable_request" "*" + END +END + +SHAPEPATH "data/raster_timeseries/" + +LAYER + NAME "a_index" + PROJECTION + "init=epsg:4326" + END + TYPE TILEINDEX + STATUS OFF + DATA "index.shp" + # This filter should be APPENDED to, by WCS or WMS time queries + FILTER ( "[layer]" eq "a" ) +END + +LAYER + NAME a + TYPE raster + STATUS ON + TILEINDEX a_index + TILEITEM "location" + PROJECTION + "+init=epsg:4326" + END + METADATA + "wcs_enable_request" "*" + "wcs_label" "wcs_layer_a" + "wcs_rangeset_name" "Range 1" ### required to support DescribeCoverage request + "wcs_rangeset_label" "My Label" ### required to support DescribeCoverage request + "wcs_extent" "110 -18 118 -10" + "wcs_rangeset_nullvalue" "-1.0" + "wcs_timeposition" "2020-01-01,2020-01-02" + "wcs_nilvalues" "-1.0" + "wcs_timeitem" "date" + "wcs_size" "8 8" + "wcs_resolution" "1 1" + "wcs_srs" "EPSG:4326" + END +END + +LAYER + NAME b + TYPE raster + STATUS ON + TILEINDEX b_index + TILEITEM "location" + PROJECTION + "+init=epsg:4326" + END + METADATA + "wcs_enable_request" "*" + "wcs_label" "wcs_layer_b" + "wcs_rangeset_name" "Range 1" ### required to support DescribeCoverage request + "wcs_rangeset_label" "My Label" ### required to support DescribeCoverage request + "wcs_extent" "110 -18 118 -10" + "wcs_rangeset_nullvalue" "-1.0" + "wcs_timeposition" "2020-01-01,2020-01-02" + "wcs_nilvalues" "-1.0" + "wcs_timeitem" "date" + "wcs_size" "8 8" + "wcs_resolution" "1 1" + "wcs_srs" "EPSG:4326" + END +END + +END # of map file diff --git a/msautotest/wxs/wcs_tileindexmixedsrs.map b/msautotest/wxs/wcs_tileindexmixedsrs.map index 96d4d8ba1e..dfc9d6da5b 100644 --- a/msautotest/wxs/wcs_tileindexmixedsrs.map +++ b/msautotest/wxs/wcs_tileindexmixedsrs.map @@ -59,13 +59,12 @@ LAYER NAME grey_26711 TYPE raster STATUS ON - DUMP TRUE TILEINDEX "../gdal/data/tile_index_mixed_srs_26711.shp" TILEITEM "location" TILESRS "src_srs" PROJECTION # AUTO isn't supported by WCS server code - # and we must explicitely set a EPSG code + # and we must explicitly set a EPSG code "+init=epsg:26711" END METADATA diff --git a/msautotest/wxs/wfs_200.map b/msautotest/wxs/wfs_200.map index 02341a16f5..19f675615f 100644 --- a/msautotest/wxs/wfs_200.map +++ b/msautotest/wxs/wfs_200.map @@ -39,7 +39,7 @@ # RUN_PARMS: wfs_200_caps_205.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.5&REQUEST=GetCapabilities" > [EXTRACT_SERVICE_VERSION] -# undefined behaviour (I think): repeated parameter. We take the first value. +# undefined behavior (I think): repeated parameter. We take the first value. # RUN_PARMS: wfs_200_caps_200_110.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&VERSION=1.1.0&REQUEST=GetCapabilities" > [EXTRACT_SERVICE_VERSION] # Capabilities : ACCEPTVERSIONS @@ -189,7 +189,7 @@ # RUN_PARMS: wfs_200_exception_getfeature_resourceid_disable_layer.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAMES=province&RESOURCEID=disabled_province.977" > [RESULT_DEVERSION] # RUN_PARMS: wfs_200_getfeature_several_resourceid.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAMES=province&RESOURCEID=province.977,province.978" > [RESULT_DEVERSION] # RUN_PARMS: wfs_200_getfeature_resourceid_notypenames.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&RESOURCEID=province.977" > [RESULT_DEVERSION] -# RUN_PARMS: wfs_200_exception_getfeature_resourceid_inexisting.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAMES=province&RESOURCEID=province.123456" > [RESULT_DEVERSION] +# RUN_PARMS: wfs_200_getfeature_resourceid_inexisting.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAMES=province&RESOURCEID=province.123456" > [RESULT_DEVERSION] # RUN_PARMS: wfs_200_exception_getfeature_resourceid_badstructure.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAMES=province&RESOURCEID=foo" > [RESULT_DEVERSION] # RUN_PARMS: wfs_200_exception_getfeature_resourceid_invalid_typename.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&RESOURCEID=foo.123456" > [RESULT_DEVERSION] # RUN_PARMS: wfs_200_exception_getfeature_resourceid_filter_invalid_typename.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAMES=province&FILTER=()" > [RESULT_DEVERSION] @@ -214,7 +214,7 @@ # RUN_PARMS: wfs_200_getfeature_startindex_19_count2.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAMES=province&STARTINDEX=19&COUNT=2" > [RESULT_DEVERSION] # Should return 1 feature, have a previous uri pointing to STARTINDEX=18 and no next uri # RUN_PARMS: wfs_200_getfeature_startindex_20_count2.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAMES=province&STARTINDEX=20&COUNT=2" > [RESULT_DEVERSION] -# Should return 0 feature. No previous uri : behaviour not defined in WFS 2.0 spec +# Should return 0 feature. No previous uri : behavior not defined in WFS 2.0 spec # RUN_PARMS: wfs_200_getfeature_startindex_21_count2.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAMES=province&STARTINDEX=21&COUNT=2" > [RESULT_DEVERSION] # # ------------------- @@ -340,13 +340,14 @@ LAYER # "init=epsg:42304" END - DUMP TRUE CLASSITEM "Name_e" CLASS NAME "Province" - COLOR 200 255 0 - OUTLINECOLOR 120 120 120 + STYLE + COLOR 200 255 0 + OUTLINECOLOR 120 120 120 + END END END # Layer @@ -370,13 +371,14 @@ LAYER # "init=epsg:42304" END - DUMP TRUE CLASSITEM "Name_e" CLASS NAME "Province" - COLOR 200 255 0 - OUTLINECOLOR 120 120 120 + STYLE + COLOR 200 255 0 + OUTLINECOLOR 120 120 120 + END END END # Layer diff --git a/msautotest/wxs/wfs_200_allgeoms.map b/msautotest/wxs/wfs_200_allgeoms.map index f2dcc4e1c3..c5e9d07c38 100644 --- a/msautotest/wxs/wfs_200_allgeoms.map +++ b/msautotest/wxs/wfs_200_allgeoms.map @@ -29,7 +29,7 @@ # RUN_PARMS: wfs_200_allgeoms_post_getfeature_filter_first_layer.xml [MAPSERV] [POST][/POST] > [RESULT_DEVERSION] # RUN_PARMS: wfs_200_allgeoms_post_getfeature_filter_second_layer.xml [MAPSERV] [POST][/POST] > [RESULT_DEVERSION] # -# Test numberMatched behaviour +# Test numberMatched behavior # RUN_PARMS: wfs_200_allgeoms_getfeature_count_0.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAMES=point,multipoint,linestring,multilinestring,polygon,multipolygon&COUNT=0" > [RESULT_DEVERSION] # RUN_PARMS: wfs_200_allgeoms_getfeature_bbox_count_0.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAMES=point,multipoint,linestring,multilinestring,polygon,multipolygon&BBOX=222638,6274861,333959,6446276,EPSG:3857&COUNT=0" > [RESULT_DEVERSION] # diff --git a/msautotest/wxs/wfs_200_cite_postgis.map b/msautotest/wxs/wfs_200_cite_postgis.map index af180e424e..ce1469a1c6 100644 --- a/msautotest/wxs/wfs_200_cite_postgis.map +++ b/msautotest/wxs/wfs_200_cite_postgis.map @@ -16,6 +16,7 @@ # RUN_PARMS: wfs_200_cite_postgis_propertyisnil_nillable_property.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&service=WFS&version=2.0.0&request=GetFeature&resultType=hits&typenames=province&filter=NomFrancais" > [RESULT_DEVERSION] # RUN_PARMS: wfs_200_cite_postgis_not_propertyisnil_nillable_property.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&service=WFS&version=2.0.0&request=GetFeature&resultType=hits&typenames=province&filter=NomFrancais" > [RESULT_DEVERSION] # RUN_PARMS: wfs_200_cite_postgis_filter_resourceid_stringvalue.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&service=WFS&version=2.0.0&request=GetFeature&typenames=province&Filter=" > [RESULT_DEVERSION] +# RUN_PARMS: wfs_200_cite_postgis_filter_or_resourceid_stringvalue.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&service=WFS&version=2.0.0&request=GetFeature&typenames=province&Filter=" > [RESULT_DEVERSION] # RUN_PARMS: wfs_200_cite_postgis_filter_like.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&service=WFS&version=2.0.0&request=GetFeature&typenames=province&Filter=island_e*" > [RESULT_DEVERSION] MAP diff --git a/msautotest/wxs/wfs_200_fid.map b/msautotest/wxs/wfs_200_fid.map new file mode 100644 index 0000000000..fdea609ffd --- /dev/null +++ b/msautotest/wxs/wfs_200_fid.map @@ -0,0 +1,81 @@ +# +# Test WFS 2.0 and FeatureId filtering +# +# REQUIRES: INPUT=OGR SUPPORTS=WFS +# +# Filter by FeatureId without OGR_EXPOSE_FID (native WFS FID filtering) +# RUN_PARMS: wfs_filter_ogr_fid_native.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAMES=popplace_gpkg_nofid&FILTER=" > [RESULT_DEVERSION] +# RUN_PARMS: wfs_filter_ogr_fid_native_range.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAMES=popplace_gpkg_nofid&FILTER=" > [RESULT_DEVERSION] +# DescribeFeatureType for popplace_gpkg_nofid to verify fid is NOT exposed as a field +# RUN_PARMS: wfs_filter_ogr_fid_native_describe.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&REQUEST=DescribeFeatureType&TYPENAMES=popplace_gpkg_nofid" > [RESULT_DEVERSION] + +# Filter by FID using OGR_EXPOSE_FID +# RUN_PARMS: wfs_filter_ogr_fid.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAMES=popplace_gpkg&FILTER=fid1" > [RESULT_DEVERSION] +# RUN_PARMS: wfs_filter_ogr_fid_range.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAMES=popplace_gpkg&FILTER=fid15" > [RESULT_DEVERSION] +# DescribeFeatureType for popplace_gpkg to verify fid is exposed as a field +# RUN_PARMS: wfs_filter_ogr_fid_describe.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&REQUEST=DescribeFeatureType&TYPENAMES=popplace_gpkg" > [RESULT_DEVERSION] + +MAP + NAME WFS_FILTER + STATUS ON + SIZE 400 300 + EXTENT -67.5725 42 -58.9275 48.5 + UNITS DD + IMAGECOLOR 255 255 255 + SHAPEPATH ./data + + WEB + + IMAGEPATH "/tmp/ms_tmp/" + IMAGEURL "/ms_tmp/" + + METADATA + "wfs_title" "Test simple wfs" + "wfs_onlineresource" "http://localhost/path/to/wfs_simple?" + "wfs_srs" "EPSG:4326 EPSG:4269" + "ows_enable_request" "*" + END + END + + PROJECTION + "init=epsg:4326" + END + + LAYER + NAME popplace_gpkg_nofid + CONNECTIONTYPE OGR + CONNECTION "./data/popplace.gpkg" + METADATA + "wfs_title" "popplace_gpkg_nofid" + "wfs_featureid" "fid" + "wfs_description" "Cities (GeoPackage without OGR_EXPOSE_FID)" + "gml_include_items" "all" + "gml_types" "auto" + END + TYPE POINT + STATUS ON + PROJECTION + "epsg:3978" + END + END # Layer + + LAYER + NAME popplace_gpkg + CONNECTIONTYPE OGR + CONNECTION "./data/popplace.gpkg" + PROCESSING "OGR_EXPOSE_FID=YES" + METADATA + "wfs_title" "popplace_gpkg" + "wfs_description" "Cities (GeoPackage with FID)" + "wfs_featureid" "fid" + "gml_include_items" "all" + "gml_types" "auto" + END + TYPE POINT + STATUS ON + PROJECTION + "epsg:3978" + END + END # Layer + +END # Map File diff --git a/msautotest/wxs/wfs_200_inspire.map b/msautotest/wxs/wfs_200_inspire.map index 67f92a1dfd..6f10e992de 100644 --- a/msautotest/wxs/wfs_200_inspire.map +++ b/msautotest/wxs/wfs_200_inspire.map @@ -37,7 +37,7 @@ WEB #"wfs_validate_xml" "true" #"wfs_schemas_dir" "SCHEMAS_OPENGIS_NET" - "inspire_schemas_location" "http://inspire.ec.europa.eu/schemas" # this is actually the default value + "inspire_schemas_location" "https://inspire.ec.europa.eu/schemas" # this is actually the default value "wfs_inspire_capabilities" "embed" @@ -119,13 +119,14 @@ LAYER # "init=epsg:42304" END - DUMP TRUE CLASSITEM "Name_e" CLASS NAME "Province" - COLOR 200 255 0 - OUTLINECOLOR 120 120 120 + STYLE + COLOR 200 255 0 + OUTLINECOLOR 120 120 120 + END END END # Layer diff --git a/msautotest/wxs/wfs_200_inspire_missing_md.map b/msautotest/wxs/wfs_200_inspire_missing_md.map index 836700fb7c..1cecefc9e5 100644 --- a/msautotest/wxs/wfs_200_inspire_missing_md.map +++ b/msautotest/wxs/wfs_200_inspire_missing_md.map @@ -63,13 +63,14 @@ LAYER # "init=epsg:42304" END - DUMP TRUE CLASSITEM "Name_e" CLASS NAME "Province" - COLOR 200 255 0 - OUTLINECOLOR 120 120 120 + STYLE + COLOR 200 255 0 + OUTLINECOLOR 120 120 120 + END END END # Layer diff --git a/msautotest/wxs/wfs_200_inspire_scenario1.map b/msautotest/wxs/wfs_200_inspire_scenario1.map index 937817595b..558e8d580d 100644 --- a/msautotest/wxs/wfs_200_inspire_scenario1.map +++ b/msautotest/wxs/wfs_200_inspire_scenario1.map @@ -106,13 +106,14 @@ LAYER # "init=epsg:42304" END - DUMP TRUE CLASSITEM "Name_e" CLASS NAME "Province" - COLOR 200 255 0 - OUTLINECOLOR 120 120 120 + STYLE + COLOR 200 255 0 + OUTLINECOLOR 120 120 120 + END END END # Layer diff --git a/msautotest/wxs/wfs_200_low_wfsmaxfeatures.map b/msautotest/wxs/wfs_200_low_wfsmaxfeatures.map index 897fcb90d1..fb42fe3035 100644 --- a/msautotest/wxs/wfs_200_low_wfsmaxfeatures.map +++ b/msautotest/wxs/wfs_200_low_wfsmaxfeatures.map @@ -83,13 +83,14 @@ LAYER # "init=epsg:42304" END - DUMP TRUE CLASSITEM "Name_e" CLASS NAME "Province" - COLOR 200 255 0 - OUTLINECOLOR 120 120 120 + STYLE + COLOR 200 255 0 + OUTLINECOLOR 120 120 120 + END END END # Layer diff --git a/msautotest/wxs/wfs_200_low_wfsmaxfeatures_no_compute_number_matched.map b/msautotest/wxs/wfs_200_low_wfsmaxfeatures_no_compute_number_matched.map index df754b98e2..c239b94d9e 100644 --- a/msautotest/wxs/wfs_200_low_wfsmaxfeatures_no_compute_number_matched.map +++ b/msautotest/wxs/wfs_200_low_wfsmaxfeatures_no_compute_number_matched.map @@ -89,13 +89,14 @@ LAYER # "init=epsg:42304" END - DUMP TRUE CLASSITEM "Name_e" CLASS NAME "Province" - COLOR 200 255 0 - OUTLINECOLOR 120 120 120 + STYLE + COLOR 200 255 0 + OUTLINECOLOR 120 120 120 + END END END # Layer diff --git a/msautotest/wxs/wfs_alltypes.map b/msautotest/wxs/wfs_alltypes.map index 3a06b7e1a4..7f3071d177 100644 --- a/msautotest/wxs/wfs_alltypes.map +++ b/msautotest/wxs/wfs_alltypes.map @@ -75,7 +75,6 @@ LAYER END TYPE LINE STATUS ON - DUMP TRUE END # Layer END # Map File diff --git a/msautotest/wxs/wfs_autotypes_geopackage.map b/msautotest/wxs/wfs_autotypes_geopackage.map new file mode 100644 index 0000000000..1ce42d8897 --- /dev/null +++ b/msautotest/wxs/wfs_autotypes_geopackage.map @@ -0,0 +1,75 @@ +# +# Test WFS types when reading from a geopackage +# +# REQUIRES: INPUT=OGR SUPPORTS=WFS +# +# RUN_PARMS: wfs_autotypes10_geopackage.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=DescribeFeatureType&TYPENAMES=autotypes" > [RESULT_DEVERSION] +# RUN_PARMS: wfs_autotypes11_geopackage.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.1.0&REQUEST=DescribeFeatureType&TYPENAMES=autotypes" > [RESULT_DEVERSION] +# RUN_PARMS: wfs_autotypes20_geopackage.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&REQUEST=DescribeFeatureType&TYPENAMES=autotypes" > [RESULT_DEVERSION] +# RUN_PARMS: wfs_getfeaturetypes10_geopackage.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAMES=autotypes" > [RESULT_DEVERSION] +# RUN_PARMS: wfs_getfeaturetypes11_geopackage.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.1.0&REQUEST=GetFeature&TYPENAMES=autotypes" > [RESULT_DEVERSION] +# RUN_PARMS: wfs_getfeaturetypes20_geopackage.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAMES=autotypes" > [RESULT_DEVERSION] + +# also check GeoJSON output +# RUN_PARMS: wfs_getfeaturetypes20_geopackage.json [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAMES=autotypes&outputFormat=geojson" > [RESULT_DEVERSION] + +MAP + +NAME WFS_TEST +STATUS ON +SIZE 400 300 +EXTENT -180 -90 180 90 + +OUTPUTFORMAT + NAME "geojson" + DRIVER "OGR/GEOJSON" + MIMETYPE "application/json" + FORMATOPTION "FORM=SIMPLE" + FORMATOPTION "STORAGE=memory" +END + +# +# Start of web interface definition +# +WEB + + METADATA + "ows_updatesequence" "123" + "wfs_title" "Test simple wfs" + "wfs_onlineresource" "http://localhost/path/to/wfs_simple?myparam=something&" + "wfs_srs" "EPSG:4326" + "ows_enable_request" "*" + "wfs_getfeature_formatlist" "geojson" + END +END + +PROJECTION + "init=epsg:4326" +END + + +# +# Start of layer definitions +# + +LAYER + + NAME autotypes + CONNECTIONTYPE OGR + CONNECTION "./data/types.gpkg" + + METADATA + "wfs_title" "autotypes" + "wfs_featureid" "id" + "gml_include_items" "all" + "gml_types" "auto" + END + + PROJECTION + "init=epsg:4326" + END + TYPE POINT + STATUS ON +END + +END # Map File diff --git a/msautotest/wxs/wfs_autotypes_postgis.map b/msautotest/wxs/wfs_autotypes_postgis.map new file mode 100644 index 0000000000..269869513b --- /dev/null +++ b/msautotest/wxs/wfs_autotypes_postgis.map @@ -0,0 +1,103 @@ +# +# Test WFS +# +# REQUIRES: INPUT=OGR SUPPORTS=WFS +# +# RUN_PARMS: wfs_autotypes10_postgis.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=DescribeFeatureType&TYPENAMES=autotypes" > [RESULT_DEVERSION] +# RUN_PARMS: wfs_autotypes11_postgis.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.1.0&REQUEST=DescribeFeatureType&TYPENAMES=autotypes" > [RESULT_DEVERSION] +# RUN_PARMS: wfs_autotypes20_postgis.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&REQUEST=DescribeFeatureType&TYPENAMES=autotypes" > [RESULT_DEVERSION] +# RUN_PARMS: wfs_getfeaturetypes10_postgis.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAMES=autotypes" > [RESULT_DEVERSION] +# RUN_PARMS: wfs_getfeaturetypes11_postgis.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.1.0&REQUEST=GetFeature&TYPENAMES=autotypes" > [RESULT_DEVERSION] +# RUN_PARMS: wfs_getfeaturetypes20_postgis.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAMES=autotypes" > [RESULT_DEVERSION] + +# also check GeoJSON output +# RUN_PARMS: wfs_getfeaturetypes20_booleans_postgis.json [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAMES=booleans&outputFormat=geojson" > [RESULT_DEVERSION] + +MAP + +NAME WFS_TEST +STATUS ON +SIZE 400 300 +EXTENT -180 -90 180 90 + +OUTPUTFORMAT + NAME "geojson" + DRIVER "OGR/GEOJSON" + MIMETYPE "application/json" + FORMATOPTION "FORM=SIMPLE" + FORMATOPTION "STORAGE=memory" +END + +# +# Start of web interface definition +# +WEB + + IMAGEPATH "/tmp/ms_tmp/" + IMAGEURL "/ms_tmp/" + + METADATA + "ows_updatesequence" "123" + "wfs_title" "Test simple wfs" + "wfs_onlineresource" "http://localhost/path/to/wfs_simple?myparam=something&" + "wfs_srs" "EPSG:4326" + "ows_enable_request" "*" + "wfs_getfeature_formatlist" "geojson" + END +END + +PROJECTION + "init=epsg:4326" +END + + +# +# Start of layer definitions +# + +LAYER + + NAME autotypes + INCLUDE "postgis.include" + DATA "the_geom from (select * from autotypes) as foo using unique id using srid=4326" + + METADATA + "wfs_title" "autotypes" + "wfs_featureid" "id" + "gml_include_items" "all" + "gml_types" "auto" + END + + PROJECTION + "init=epsg:4326" + END + TYPE POINT + STATUS ON +END + + +LAYER + + NAME booleans + INCLUDE "postgis.include" + DATA "the_geom from ( + select 1 as id + ,1::Boolean as my_bool_true + ,0::Boolean as my_bool_false + ,GeomFromEWKT('SRID=4326;POINT(1 2)') as the_geom + ) as foo using unique id using srid=4326" + METADATA + "wfs_title" "booleans" + "wfs_featureid" "id" + "gml_include_items" "all" + "gml_types" "auto" + END + + PROJECTION + "init=epsg:4326" + END + TYPE POINT + STATUS ON +END + +END # Map File diff --git a/msautotest/wxs/wfs_client_100.map b/msautotest/wxs/wfs_client_100.map new file mode 100644 index 0000000000..3be1020587 --- /dev/null +++ b/msautotest/wxs/wfs_client_100.map @@ -0,0 +1,54 @@ +# +# Test WFS 1.0.0 Client +# +# REQUIRES: OUTPUT=PNG SUPPORTS=WFS_CLIENT SUPPORTS=WFS +# GetFeature +# RUN_PARMS: wfs_client_100.xml [MAPSERV] -conf ../etc/mapserv.conf QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=continents" > [RESULT_DEMIME] + +MAP + NAME WFS_CLIENT_TEST_100 + STATUS ON + SIZE 400 300 + EXTENT -180 -90 180 90 + UNITS DD + PROJECTION + "init=epsg:4326" + END + SYMBOLSET etc/symbols.sym + FONTSET etc/fonts.txt + + WEB + IMAGEPATH "./tmp" + METADATA + "ows_updatesequence" "123" + "wfs_title" "Test WFS 1.0.0 client" + "wfs_srs" "EPSG:4326" + "ows_enable_request" "*" + "ows_onlineresource" "http://localhost/wfsclient?" + END + END + + LAYER + NAME "continents" + TYPE POLYGON + STATUS ON + CONNECTION "https://demo.mapserver.org/cgi-bin/wfs?" + CONNECTIONTYPE WFS + METADATA + "wfs_typename" "continents" + "wfs_version" "1.0.0" + "wfs_connectiontimeout" "60" + "wfs_maxfeatures" "2" + END + PROJECTION + "init=epsg:4326" + END + CLASS + NAME "Continents" + STYLE + COLOR 255 128 128 + OUTLINECOLOR 96 96 96 + END + END + END # Layer +END diff --git a/msautotest/wxs/wfs_combined_filter.map b/msautotest/wxs/wfs_combined_filter.map index 4311014835..59208a2795 100644 --- a/msautotest/wxs/wfs_combined_filter.map +++ b/msautotest/wxs/wfs_combined_filter.map @@ -84,7 +84,6 @@ LAYER END TEMPLATE "wfs_ogr.map" - DUMP TRUE END # Layer END # Map File diff --git a/msautotest/wxs/wfs_custom_projection.map b/msautotest/wxs/wfs_custom_projection.map new file mode 100644 index 0000000000..8d65bf39bd --- /dev/null +++ b/msautotest/wxs/wfs_custom_projection.map @@ -0,0 +1,62 @@ +# +# Test WFS with non-EPSG projections +# +# REQUIRES: INPUT=GDAL SUPPORTS=WFS + +# RUN_PARMS: wfs_custom_projection_capabilities100.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetCapabilities" > [RESULT_DEMIME] +# RUN_PARMS: wfs_custom_projection_capabilities110.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.1.0&REQUEST=GetCapabilities" > [RESULT_DEMIME] +# RUN_PARMS: wfs_custom_projection_capabilities200.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&REQUEST=GetCapabilities" > [RESULT_DEMIME] + + +# wfs 1.0 does not have an srsname parameter and we cannot override the output projection +# RUN_PARMS: wfs_custom_projection_getfeature100.json [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=cities&OUTPUTFORMAT=geojson" > [RESULT_DEMIME] + +# RUN_PARMS: wfs_custom_projection_getfeature110_53009.json [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.1.0&SRSNAME=ESRI:53009&REQUEST=GetFeature&TYPENAME=cities&OUTPUTFORMAT=geojson" > [RESULT_DEMIME] +# RUN_PARMS: wfs_custom_projection_getfeature110_42304.json [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.1.0&SRSNAME=epsg2:42304&REQUEST=GetFeature&TYPENAME=cities&OUTPUTFORMAT=geojson" > [RESULT_DEMIME] + +# RUN_PARMS: wfs_custom_projection_getfeature200_53009.json [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&SRSNAME=ESRI:53009&REQUEST=GetFeature&TYPENAMES=cities&OUTPUTFORMAT=geojson" > [RESULT_DEMIME] +# RUN_PARMS: wfs_custom_projection_getfeature200_42304.json [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&SRSNAME=epsg2:42304&REQUEST=GetFeature&TYPENAMES=cities&OUTPUTFORMAT=geojson" > [RESULT_DEMIME] + +MAP + NAME "cities" + EXTENT -20037508.34 -20048966.1 20037508.34 20048966.1 + PROJECTION + "epsg:3857" + END + + WEB + METADATA + "wfs_enable_request" "*" + "wfs_srs" "EPSG:3857 EPSG:4326 ESRI:54030 ESRI:53009 epsg2:42304" + "wfs_onlineresource" "http://localhost/path/to/wfs_custom_projection?" + "wfs_getfeature_formatlist" "geojson" + "wfs_maxfeatures" "1" + END + END + + OUTPUTFORMAT + NAME "geojson" + DRIVER "OGR/GEOJSON" + MIMETYPE "application/json; subtype=geojson; charset=utf-8" + FORMATOPTION "FORM=SIMPLE" + FORMATOPTION "STORAGE=memory" + FORMATOPTION "LCO:NATIVE_MEDIA_TYPE=application/vnd.geo+json" + FORMATOPTION "USE_FEATUREID=true" + FORMATOPTION "LCO:COORDINATE_PRECISION=3" + END + + LAYER + NAME "cities" + TYPE POINT + PROJECTION + "esri:53009" + END + STATUS OFF + METADATA + "gml_include_items" "all" + END + CONNECTIONTYPE OGR + CONNECTION "./data/worldcity_53009.geojson" + END + +END \ No newline at end of file diff --git a/msautotest/wxs/wfs_default_version_110.map b/msautotest/wxs/wfs_default_version_110.map index f1f460e04f..250f85162d 100644 --- a/msautotest/wxs/wfs_default_version_110.map +++ b/msautotest/wxs/wfs_default_version_110.map @@ -100,13 +100,14 @@ LAYER # "init=epsg:42304" END - DUMP TRUE CLASSITEM "Name_e" CLASS NAME "Province" - COLOR 200 255 0 - OUTLINECOLOR 120 120 120 + STYLE + COLOR 200 255 0 + OUTLINECOLOR 120 120 120 + END END END # Layer diff --git a/msautotest/wxs/wfs_filter.map b/msautotest/wxs/wfs_filter.map index 3120279659..e49bd8394b 100644 --- a/msautotest/wxs/wfs_filter.map +++ b/msautotest/wxs/wfs_filter.map @@ -129,6 +129,10 @@ # # Verify INTERSECTS Results: Canso, Port Hawkesbury # RUN_PARMS: wfs_filter_intersects.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=popplace&FILTER=Geometry-61.63,45.04 -60.78,45.04 -60.78,46.08 -61.63,46.08" > [RESULT] + +# Intersects with an empty multipolygon. Check that we don't crash at least. See https://github.com/MapServer/MapServer/issues/6176 +# RUN_PARMS: wfs_filter_intersects_empty_multipolygon.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=popplace&FILTER=Geometry" > [RESULT] + # # RUN_PARMS: wfs_filter_200_intersects.xml [MAPSERV] [POST]Geometry-61.63 45.04 -60.78 45.04 -60.78 46.08 -61.63 46.08[/POST] > [RESULT_DEVERSION] @@ -272,13 +276,14 @@ LAYER "init=epsg:3978" END - DUMP TRUE CLASSITEM "Name_e" CLASS NAME "Province" - COLOR 200 255 0 - OUTLINECOLOR 120 120 120 + STYLE + COLOR 200 255 0 + OUTLINECOLOR 120 120 120 + END END END # Layer @@ -298,11 +303,12 @@ LAYER "init=epsg:3978" END - DUMP TRUE CLASS NAME "Parks" - COLOR 200 255 0 - OUTLINECOLOR 120 120 120 + STYLE + COLOR 200 255 0 + OUTLINECOLOR 120 120 120 + END END END # Layer @@ -324,14 +330,16 @@ LAYER "init=epsg:3978" END - DUMP TRUE LabelItem "Name" CLASSITEM "Capital" CLASS EXPRESSION /./ - SYMBOL 2 - SIZE 8 + STYLE + SYMBOL 2 + SIZE 8 + COLOR 0 0 0 + END NAME "Cities" LABEL COLOR 0 0 0 @@ -342,7 +350,6 @@ LAYER PARTIALS FALSE OUTLINECOLOR 255 255 255 END - COLOR 0 0 0 END END # Layer @@ -361,13 +368,13 @@ LAYER "init=epsg:3978" END - DUMP TRUE - CLASSITEM "Name_e" CLASS NAME "Roads" - SYMBOL 0 - COLOR 220 0 0 + STYLE + SYMBOL 0 + COLOR 220 0 0 + END END END # Layer @@ -386,7 +393,6 @@ LAYER "init=epsg:4326" END - DUMP TRUE END # Layer END # Map File diff --git a/msautotest/wxs/wfs_filter_ogr.map b/msautotest/wxs/wfs_filter_ogr.map index 69109573a8..4a2ca93286 100644 --- a/msautotest/wxs/wfs_filter_ogr.map +++ b/msautotest/wxs/wfs_filter_ogr.map @@ -193,13 +193,14 @@ LAYER "init=epsg:3978" END - DUMP TRUE CLASSITEM "Name_e" CLASS NAME "Province" - COLOR 200 255 0 - OUTLINECOLOR 120 120 120 + STYLE + COLOR 200 255 0 + OUTLINECOLOR 120 120 120 + END END END # Layer @@ -221,14 +222,16 @@ LAYER "init=epsg:3978" END - DUMP TRUE LabelItem "Name" CLASSITEM "Capital" CLASS EXPRESSION /./ - SYMBOL 2 - SIZE 8 + STYLE + SYMBOL 2 + SIZE 8 + COLOR 0 0 0 + END NAME "Cities" LABEL COLOR 0 0 0 @@ -239,7 +242,6 @@ LAYER PARTIALS FALSE OUTLINECOLOR 255 255 255 END - COLOR 0 0 0 END END # Layer diff --git a/msautotest/wxs/wfs_filter_postgis.map b/msautotest/wxs/wfs_filter_postgis.map index ffc237641b..45ebd8126a 100644 --- a/msautotest/wxs/wfs_filter_postgis.map +++ b/msautotest/wxs/wfs_filter_postgis.map @@ -153,6 +153,12 @@ # Filter and FilterItem and RESULTTYPE=hits (RFC 114) # RUN_PARMS: wfs_filter_postgis_filter_item_hits.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.1.0&REQUEST=GetFeature&TYPENAME=province_with_filter_item&RESULTTYPE=hits" > [RESULT_DEVERSION] # RUN_PARMS: wfs_filter_postgis_filter_item_hits_start_index.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.1.0&REQUEST=GetFeature&TYPENAME=province_with_filter_item&RESULTTYPE=hits&STARTINDEX=1" > [RESULT_DEVERSION] +# +# No default EXTENT +# RUN_PARMS: wfs_filter_postgis_filter_item_hits_no_extent.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.1.0&REQUEST=GetFeature&TYPENAME=province_with_filter_item_no_extent&RESULTTYPE=hits" > [RESULT_DEVERSION] +# +# No default EXTENT + NATIVE_FILTER +# RUN_PARMS: wfs_filter_postgis_native_filter_hits_no_extent.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.1.0&REQUEST=GetFeature&TYPENAME=province_with_native_filter_no_extent&RESULTTYPE=hits" > [RESULT_DEVERSION] MAP #CONFIG "MS_ERRORFILE" "stderr" @@ -184,6 +190,7 @@ WEB "wfs_srs" "EPSG:4326 EPSG:4269" "ows_schemas_location" "http://ogc.dmsolutions.ca" "ows_enable_request" "*" + "wfs_use_default_extent_for_getfeature" "false" END END @@ -206,6 +213,7 @@ LAYER "wfs_title" "province" "wfs_description" "province" "gml_include_items" "all" + "wfs_use_default_extent_for_getfeature" "true" END TYPE POLYGON STATUS ON @@ -213,13 +221,14 @@ LAYER "init=epsg:3978" END - DUMP TRUE CLASSITEM "Name_e" CLASS NAME "Province" - COLOR 200 255 0 - OUTLINECOLOR 120 120 120 + STYLE + COLOR 200 255 0 + OUTLINECOLOR 120 120 120 + END END END # Layer @@ -232,6 +241,7 @@ LAYER "wfs_title" "popplace" "wfs_description" "Cities" "gml_include_items" "all" + "wfs_use_default_extent_for_getfeature" "true" END TYPE POINT STATUS ON @@ -239,14 +249,16 @@ LAYER "init=epsg:3978" END - DUMP TRUE LabelItem "Name" CLASSITEM "Capital" CLASS EXPRESSION /./ - SYMBOL 2 - SIZE 8 + STYLE + SYMBOL 2 + SIZE 8 + COLOR 0 0 0 + END NAME "Cities" LABEL COLOR 0 0 0 @@ -257,7 +269,6 @@ LAYER PARTIALS FALSE OUTLINECOLOR 255 255 255 END - COLOR 0 0 0 END END # Layer @@ -272,6 +283,7 @@ LAYER "wfs_title" "province_with_filter_item" "wfs_description" "province_with_filter_item" "gml_include_items" "all" + "wfs_use_default_extent_for_getfeature" "true" END TYPE POLYGON STATUS ON @@ -282,4 +294,44 @@ LAYER END # Layer +LAYER + NAME province_with_filter_item_no_extent + INCLUDE "postgis.include" + DATA "the_geom from (select * from province order by gid) as foo using srid=3978 using unique gid" + FILTER 'Cape Breton Island' + FILTERITEM 'island_e' + METADATA + "wfs_title" "province_with_filter_item_no_extent" + "wfs_description" "province_with_filter_item_no_extent" + "wfs_use_default_extent_for_getfeature" "false" + "gml_include_items" "all" + END + TYPE POLYGON + STATUS ON + PROJECTION + "init=epsg:3978" + END + +END # Layer + + +LAYER + NAME province_with_native_filter_no_extent + INCLUDE "postgis.include" + DATA "the_geom from (select * from province order by gid) as foo using srid=3978 using unique gid" + PROCESSING "NATIVE_FILTER=island_e='Cape Breton Island'" + METADATA + "wfs_title" "province_with_native_filter_no_extent" + "wfs_description" "province_with_native_filter_no_extent" + "wfs_use_default_extent_for_getfeature" "false" + "gml_include_items" "all" + END + TYPE POLYGON + STATUS ON + PROJECTION + "init=epsg:3978" + END + +END # Layer + END # Map File diff --git a/msautotest/wxs/wfs_filter_projmeter.map b/msautotest/wxs/wfs_filter_projmeter.map index 488dbbc1bf..f4e84583a1 100644 --- a/msautotest/wxs/wfs_filter_projmeter.map +++ b/msautotest/wxs/wfs_filter_projmeter.map @@ -60,15 +60,6 @@ SYMBOLSET etc/symbols.sym FONTSET etc/fonts.txt -OUTPUTFORMAT - NAME GDPNG - DRIVER "GD/PNG" - MIMETYPE "image/png" - IMAGEMODE RGB - EXTENSION "png" -END - - # # Start of web interface definition # @@ -113,13 +104,14 @@ LAYER "init=./data/epsg2:42304" END - DUMP TRUE CLASSITEM "Name_e" CLASS NAME "Province" - COLOR 200 255 0 - OUTLINECOLOR 120 120 120 + STYLE + COLOR 200 255 0 + OUTLINECOLOR 120 120 120 + END END END # Layer @@ -139,11 +131,12 @@ LAYER "init=./data/epsg2:42304" END - DUMP TRUE CLASS NAME "Parks" - COLOR 200 255 0 - OUTLINECOLOR 120 120 120 + STYLE + COLOR 200 255 0 + OUTLINECOLOR 120 120 120 + END END END # Layer @@ -165,14 +158,16 @@ LAYER "init=./data/epsg2:42304" END - DUMP TRUE LabelItem "Name" CLASSITEM "Capital" CLASS EXPRESSION /./ - SYMBOL 2 - SIZE 8 + STYLE + SYMBOL 2 + SIZE 8 + COLOR 0 0 0 + END NAME "Cities" LABEL COLOR 0 0 0 @@ -183,7 +178,6 @@ LAYER PARTIALS FALSE OUTLINECOLOR 255 255 255 END - COLOR 0 0 0 END END # Layer @@ -202,13 +196,13 @@ LAYER "init=./data/epsg2:42304" END - DUMP TRUE - CLASSITEM "Name_e" CLASS NAME "Roads" - SYMBOL 0 - COLOR 220 0 0 + STYLE + SYMBOL 0 + COLOR 220 0 0 + END END END # Layer diff --git a/msautotest/wxs/wfs_group.map b/msautotest/wxs/wfs_group.map index 9f20607ec4..f904623230 100644 --- a/msautotest/wxs/wfs_group.map +++ b/msautotest/wxs/wfs_group.map @@ -119,13 +119,14 @@ LAYER # "init=epsg:42304" END - DUMP TRUE CLASSITEM "Name_e" CLASS NAME "Province" - COLOR 200 255 0 - OUTLINECOLOR 120 120 120 + STYLE + COLOR 200 255 0 + OUTLINECOLOR 120 120 120 + END END END # Layer diff --git a/msautotest/wxs/wfs_misc.map b/msautotest/wxs/wfs_misc.map index ad41c6333d..e36e9834f1 100644 --- a/msautotest/wxs/wfs_misc.map +++ b/msautotest/wxs/wfs_misc.map @@ -28,15 +28,6 @@ SYMBOLSET etc/symbols.sym FONTSET etc/fonts.txt -OUTPUTFORMAT - NAME GDPNG - DRIVER "GD/PNG" - MIMETYPE "image/png" - IMAGEMODE RGB - EXTENSION "png" -END - - # # Start of web interface definition # @@ -81,13 +72,14 @@ LAYER "init=./data/epsg2:42304" END - DUMP TRUE CLASSITEM "Name_e" CLASS NAME "Province" - COLOR 200 255 0 - OUTLINECOLOR 120 120 120 + STYLE + COLOR 200 255 0 + OUTLINECOLOR 120 120 120 + END END END # Layer @@ -107,11 +99,12 @@ LAYER "init=./data/epsg2:42304" END - DUMP TRUE CLASS NAME "Parks" - COLOR 200 255 0 - OUTLINECOLOR 120 120 120 + STYLE + COLOR 200 255 0 + OUTLINECOLOR 120 120 120 + END END END # Layer @@ -132,14 +125,16 @@ LAYER "init=./data/epsg2:42304" END - DUMP TRUE LabelItem "Name" CLASSITEM "Capital" CLASS EXPRESSION /./ - SYMBOL 2 - SIZE 8 + STYLE + SYMBOL 2 + SIZE 8 + COLOR 0 0 0 + END NAME "Cities" LABEL COLOR 0 0 0 @@ -150,7 +145,6 @@ LAYER PARTIALS FALSE OUTLINECOLOR 255 255 255 END - COLOR 0 0 0 END END # Layer @@ -169,13 +163,13 @@ LAYER "init=./data/epsg2:42304" END - DUMP TRUE - CLASSITEM "Name_e" CLASS NAME "Roads" - SYMBOL 0 - COLOR 220 0 0 + STYLE + SYMBOL 0 + COLOR 220 0 0 + END END END # Layer diff --git a/msautotest/wxs/wfs_multi_geom_elements.map b/msautotest/wxs/wfs_multi_geom_elements.map index 1f2d25f673..ad371af820 100644 --- a/msautotest/wxs/wfs_multi_geom_elements.map +++ b/msautotest/wxs/wfs_multi_geom_elements.map @@ -86,7 +86,6 @@ LAYER "init=epsg:27700" END - DUMP TRUE END END # Map File diff --git a/msautotest/wxs/wfs_multiple_metadataurl.map b/msautotest/wxs/wfs_multiple_metadataurl.map index 44716b0d32..9b2851cce5 100644 --- a/msautotest/wxs/wfs_multiple_metadataurl.map +++ b/msautotest/wxs/wfs_multiple_metadataurl.map @@ -100,13 +100,14 @@ LAYER # "init=epsg:42304" END - DUMP TRUE CLASSITEM "Name_e" CLASS NAME "Province" - COLOR 200 255 0 - OUTLINECOLOR 120 120 120 + STYLE + COLOR 200 255 0 + OUTLINECOLOR 120 120 120 + END END END # Layer diff --git a/msautotest/wxs/wfs_ogr.map b/msautotest/wxs/wfs_ogr.map index 82c7209267..6393acae0c 100644 --- a/msautotest/wxs/wfs_ogr.map +++ b/msautotest/wxs/wfs_ogr.map @@ -23,11 +23,14 @@ # Generate dump streamed directly to GPX (test #4776) # RUN_PARMS: wfsogr10_gpx.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=road&featureid=road.1521&OUTPUTFORMAT=OGRGPX" > [RESULT_DEVERSION] # -# Generate dump to BNA in ZIP (test #4933) -# RUN_PARMS: wfsogr10_bnazip.zip [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=road&featureid=road.1521&OUTPUTFORMAT=OGRBNAZIP" > [RESULT_DEVERSION] +# Generate dump to CSV in ZIP (test #4933) +# RUN_PARMS: wfsogr10_csvzip.zip [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=road&featureid=road.1521&OUTPUTFORMAT=OGRCSVZIP" > [RESULT_DEVERSION] # -# Generate dump to SHAPEZIP -# RUN_PARMS: wfsogr10_shapezip.zip [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=road&featureid=road.1521&OUTPUTFORMAT=SHAPEZIP" > [RESULT] +# Generate dump to SHAPEZIP, with HTTP headers +# RUN_PARMS: wfsogr10_shapezip.zip.with_headers [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=road&featureid=road.1521&OUTPUTFORMAT=SHAPEZIP" > [RESULT] +# +# Generate dump to SHAPEZIP using in-memory creation, with HTTP headers +# RUN_PARMS: wfsogr10_shapezipmem.zip.with_headers [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=road&featureid=road.1521&OUTPUTFORMAT=SHAPEZIPMEM" > [RESULT] # # Generate dump streamed directly to OGR GML from memory. # RUN_PARMS: wfsogr10_ogrgml.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=road&featureid=road.1521&OUTPUTFORMAT=OGRGML" > [RESULT] @@ -44,8 +47,11 @@ # Test fetching from two layers with a filter. # RUN_PARMS: wfsogr10_twolayer.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=popplace,road&OUTPUTFORMAT=MultiMIDMIF&FILTER=(POINT-65.86,44.56+-65.76,44.68)(POINT-65.86,44.56+-65.76,44.68)" > [RESULT] # -# Test writing features with null numeric fields (#4633) -# RUN_PARMS: wfsogr10_nullnumeric.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=withnullvalues&OUTPUTFORMAT=CSV" > [RESULT] +# Test writing features with null numeric fields (#4633) and datetime (#6434) +# RUN_PARMS: wfsogr10_nullnumeric.csv [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=withnullvalues&OUTPUTFORMAT=CSV" > [RESULT_DEMIME] +# +# Test writing features with null numeric fields (#4633) and datetime (#6434) +# RUN_PARMS: wfsogr10_datetime.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=withnullvalues" > [RESULT_DEMIME] # WFS 1.1 # @@ -91,7 +97,7 @@ # # Test wfs_additional_files_in_output # RUN_PARMS: wfsogr_addfiles_onelayer.txt [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=road_with_addfiles&featureid=road_with_addfiles.1521&OUTPUTFORMAT=OGRGML" > [RESULT_DEVERSION] -# RUN_PARMS: wfsogr_addfiles_onelayer.zip [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=road_with_addfiles&featureid=road_with_addfiles.1521&OUTPUTFORMAT=OGRBNAZIP" > [RESULT_DEVERSION] +# RUN_PARMS: wfsogr_addfiles_onelayer.zip [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=road_with_addfiles&featureid=road_with_addfiles.1521&OUTPUTFORMAT=OGRCSVZIP" > [RESULT_DEVERSION] # RUN_PARMS: wfsogr_addfiles_twolayers.txt [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=road_with_addfiles,road2_with_addfiles&featureid=road_with_addfiles.1521,road2_with_addfiles.1521&OUTPUTFORMAT=OGRGML" > [RESULT_DEVERSION] MAP @@ -151,12 +157,14 @@ OUTPUTFORMAT END OUTPUTFORMAT - NAME "OGRBNAZIP" - DRIVER "OGR/BNA" - MIMETYPE "application/zip; driver=ogr/bna" + NAME "OGRCSVZIP" + DRIVER "OGR/CSV" + MIMETYPE "application/zip; driver=ogr/csv" + FORMATOPTION "LCO:GEOMETRY=AS_WKT" FORMATOPTION "STORAGE=memory" FORMATOPTION "FORM=zip" - FORMATOPTION "FILENAME=result.bna.zip" + FORMATOPTION "FILENAME=result.csv.zip" + FORMATOPTION "TIMESTAMP=0" END @@ -168,6 +176,18 @@ OUTPUTFORMAT FORMATOPTION "FORM=zip" FORMATOPTION "FILENAME=result.zip" FORMATOPTION "LCO:DBF_DATE_LAST_UPDATE=2018-06-18" + FORMATOPTION "TIMESTAMP=0" +END + +OUTPUTFORMAT + NAME "SHAPEZIPMEM" + DRIVER "OGR/ESRI Shapefile" + MIMETYPE "application/shapefile" + FORMATOPTION "STORAGE=memory" + FORMATOPTION "FORM=zip" + FORMATOPTION "FILENAME=result.zip" + FORMATOPTION "LCO:DBF_DATE_LAST_UPDATE=2018-06-18" + FORMATOPTION "TIMESTAMP=0" END OUTPUTFORMAT @@ -245,7 +265,7 @@ LAYER "ows_title" "road" "ows_description" "road" "wfs_featureid" "ROAD_ID" - "wfs_getfeature_formatlist" "csv,csvstream,ogrgml,ogrgpx,ogrbnazip,ogrgmlstream,shapezip,midmif,multimidmif" + "wfs_getfeature_formatlist" "csv,csvstream,ogrgml,ogrgpx,ogrcsvzip,ogrgmlstream,shapezip,shapezipmem,midmif,multimidmif" "gml_include_items" "all" "gml_exclude_items" "ROAD_" "gml_types" "auto" @@ -257,7 +277,6 @@ LAYER END TEMPLATE "wfs_ogr.map" - DUMP TRUE END # Layer LAYER @@ -281,7 +300,6 @@ LAYER "init=epsg:3978" END - DUMP TRUE END # Layer # To test wfs_additional_files_in_output @@ -292,7 +310,7 @@ LAYER "ows_title" "road_with_addfiles" "ows_description" "road_with_addfiles" "wfs_featureid" "ROAD_ID" - "wfs_getfeature_formatlist" "csv,csvstream,ogrgml,ogrgpx,ogrbnazip,ogrgmlstream,shapezip,midmif,multimidmif" + "wfs_getfeature_formatlist" "csv,csvstream,ogrgml,ogrgpx,ogrcsvzip,ogrgmlstream,shapezip,midmif,multimidmif" "wfs_additional_files_in_output" "wfs_ogr_common_addfile.txt,wfs_ogr_common_addfile.txt,addfiles/,addfiles,road_with_addfiles.txt" "gml_include_items" "all" "gml_exclude_items" "ROAD_" @@ -305,7 +323,6 @@ LAYER END TEMPLATE "wfs_ogr.map" - DUMP TRUE END # Layer # To test wfs_additional_files_in_output @@ -316,7 +333,7 @@ LAYER "ows_title" "road2_with_addfiles" "ows_description" "road2_with_addfiles" "wfs_featureid" "ROAD_ID" - "wfs_getfeature_formatlist" "csv,csvstream,ogrgml,ogrgpx,ogrbnazip,ogrgmlstream,shapezip,midmif,multimidmif" + "wfs_getfeature_formatlist" "csv,csvstream,ogrgml,ogrgpx,ogrcsvzip,ogrgmlstream,shapezip,midmif,multimidmif" "wfs_additional_files_in_output" "road2_with_addfiles.txt,nonexistingfile" "gml_include_items" "all" "gml_exclude_items" "ROAD_" @@ -329,7 +346,6 @@ LAYER END TEMPLATE "wfs_ogr.map" - DUMP TRUE END # Layer LAYER @@ -352,8 +368,6 @@ LAYER PROJECTION "init=epsg:27700" END - - DUMP TRUE END LAYER @@ -376,8 +390,6 @@ LAYER PROJECTION "init=epsg:27700" END - - DUMP TRUE END END # Map File diff --git a/msautotest/wxs/wfs_ogr_25d.map b/msautotest/wxs/wfs_ogr_25d.map index fe6a08ba2e..985ea9f66d 100755 --- a/msautotest/wxs/wfs_ogr_25d.map +++ b/msautotest/wxs/wfs_ogr_25d.map @@ -1,7 +1,7 @@ # # Test both 2.5D support in OGR input and GML/WFS output # -# REQUIRES: SUPPORTS=WFS SUPPORTS=POINT_Z_M INPUT=OGR +# REQUIRES: SUPPORTS=WFS INPUT=OGR # # # RUN_PARMS: wfs_ogr_25d_gml2.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=point3d,linestring3d,polygon3d,multipoint3d,multilinestring3d,multipolygon3d" > [RESULT] @@ -51,8 +51,6 @@ LAYER PROJECTION "init=epsg:27700" END - - DUMP TRUE END LAYER @@ -73,8 +71,6 @@ LAYER PROJECTION "init=epsg:27700" END - - DUMP TRUE END @@ -96,8 +92,6 @@ LAYER PROJECTION "init=epsg:27700" END - - DUMP TRUE END @@ -119,8 +113,6 @@ LAYER PROJECTION "init=epsg:27700" END - - DUMP TRUE END LAYER @@ -141,8 +133,6 @@ LAYER PROJECTION "init=epsg:27700" END - - DUMP TRUE END LAYER @@ -163,8 +153,6 @@ LAYER PROJECTION "init=epsg:27700" END - - DUMP TRUE END diff --git a/msautotest/wxs/wfs_ogr_drv_nocreatedatasource.map b/msautotest/wxs/wfs_ogr_drv_nocreatedatasource.map index 3b1f9b8758..08035e3531 100644 --- a/msautotest/wxs/wfs_ogr_drv_nocreatedatasource.map +++ b/msautotest/wxs/wfs_ogr_drv_nocreatedatasource.map @@ -12,7 +12,7 @@ MAP OUTPUTFORMAT NAME "nocreatedatasource" - DRIVER "OGR/SDTS" + DRIVER "OGR/SXF" MIMETYPE "text/nocreatedatasource" END diff --git a/msautotest/wxs/wfs_ogr_geojson.map b/msautotest/wxs/wfs_ogr_geojson.map index 31fa1a5e95..1d89979dd0 100644 --- a/msautotest/wxs/wfs_ogr_geojson.map +++ b/msautotest/wxs/wfs_ogr_geojson.map @@ -9,6 +9,9 @@ # RUN_PARMS: wfsogr20_geojson.json [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAMES=popplace_fid&OUTPUTFORMAT=geojson&COUNT=10" > [RESULT] # # RUN_PARMS: wfsogr20_geojson_with_predefine_native_data.json [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAMES=popplace_fid&OUTPUTFORMAT=geojson_with_predefined_native_data&COUNT=10" > [RESULT] +# +# Check that OUTPUTFORMAT does not affect resultType=hits and returns XML +# RUN_PARMS: wfsogr20_geojson_resulttype_hits.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAME=popplace_fid&OUTPUTFORMAT=geojson&RESULTTYPE=hits" > [RESULT_DEVERSION] MAP diff --git a/msautotest/wxs/wfs_ogr_gpkg.map b/msautotest/wxs/wfs_ogr_gpkg.map index 93461b6633..dd3079973d 100644 --- a/msautotest/wxs/wfs_ogr_gpkg.map +++ b/msautotest/wxs/wfs_ogr_gpkg.map @@ -8,6 +8,25 @@ # Filter using startIndex # RUN_PARMS: wfs_ogr_gpkg_filter_startindex.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=popplace&propertyname=(name)&maxfeatures=10&startindex=0" > [RESULT] # RUN_PARMS: wfs_ogr_gpkg_filter_startindex2.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=popplace&propertyname=(name)&maxfeatures=10&startindex=10" > [RESULT] +# +# RUN_PARMS: wfs_ogr_gpkg_issue_6325.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAMES=test_6325&BBOX=0.75,0.75,9,9&COUNT=1" > [RESULT_DEVERSION] +# +# Pagination with BBOX in other SRS than source +# Ideally this should return all seven expected result, but some features being skipped where requested BBOX and source BBOX overlaps, and the next 3 expected features does not fall wihing startIndex and count. +# Expected is 4 results and next link with startIndex 7 +# RUN_PARMS: wfs_ogr_gpkg_pagination_4326.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAMES=popplace&BBOX=43.0,-65.0,45.0,-62.0&COUNT=7&STARTINDEX=0" > [RESULT_DEVERSION] +# Expect 3 results, one previous link with count 7, no next link +# RUN_PARMS: wfs_ogr_gpkg_pagination_4326_2.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAMES=popplace&BBOX=43.0,-65.0,45.0,-62.0&COUNT=7&STARTINDEX=7" > [RESULT_DEVERSION] +# +# Filter using intersect with point +# RUN_PARMS: wfs_ogr_gpkg_filter_intersects_point.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=test_6325&FILTER=msGeometry1.000000,0.000000" > [RESULT] +# +# PropertyIsNull +# RUN_PARMS: wfs_ogr_gpkg_propertyisnull.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=test_6446&FILTER=fieldisnull" > [RESULT] +# +# OGR_EXPOSE_FID processing key +# RUN_PARMS: wfs_ogr_gpkg_expose_fid.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=test_expose_fid&MAXFEATURES=1" > [RESULT] +# MAP @@ -82,4 +101,59 @@ LAYER END END # Layer + +LAYER + NAME "test_6325" + CONNECTIONTYPE OGR + CONNECTION "./data/test_6325.gpkg" + METADATA + "ows_title" "test_6325" + "wfs_featureid" "id" + "gml_include_items" "all" + "gml_types" "auto" + "wfs_use_default_extent_for_getfeature" "no" + END + TYPE LINE + STATUS ON + PROJECTION + "init=epsg:4326" + END +END # Layer + +LAYER + NAME "test_6446" + CONNECTIONTYPE OGR + CONNECTION "./data/test_6446.gpkg" + METADATA + "ows_title" "test_6446" + "wfs_featureid" "id" + "gml_include_items" "all" + "gml_types" "auto" + "wfs_use_default_extent_for_getfeature" "no" + END + TYPE POINT + STATUS ON + PROJECTION + "init=epsg:4326" + END +END # Layer + +LAYER + NAME "test_expose_fid" + CONNECTIONTYPE OGR + CONNECTION "./data/test.gpkg" + PROCESSING "OGR_EXPOSE_FID=YES" + METADATA + "ows_title" "test_expose_fid" + "wfs_featureid" "fid" + "gml_include_items" "all" + "gml_types" "auto" + END + TYPE POINT + STATUS ON + PROJECTION + "init=epsg:4326" + END +END # Layer + END # Map File diff --git a/msautotest/wxs/wfs_ogr_invalid_filename.map b/msautotest/wxs/wfs_ogr_invalid_filename.map index 34ccf97b58..7391e29478 100644 --- a/msautotest/wxs/wfs_ogr_invalid_filename.map +++ b/msautotest/wxs/wfs_ogr_invalid_filename.map @@ -100,7 +100,6 @@ LAYER END TEMPLATE "wfs_ogr.map" - DUMP TRUE END # Layer END # Map File diff --git a/msautotest/wxs/wfs_ogr_native_sql.map b/msautotest/wxs/wfs_ogr_native_sql.map index 306019fb11..0c349be172 100644 --- a/msautotest/wxs/wfs_ogr_native_sql.map +++ b/msautotest/wxs/wfs_ogr_native_sql.map @@ -21,6 +21,8 @@ # RUN_PARMS: wfs_ogr_native_sql_05.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=towns&OUTPUTFORMAT=GML2&FILTER=namefanano" > [RESULT] # RUN_PARMS: wfs_ogr_native_sql_06.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=towns&OUTPUTFORMAT=GML2&FILTER=nameFanano" > [RESULT] +# RUN_PARMS: wfs_ogr_native_sql_is_equal_to_invalid_property_name.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=towns&OUTPUTFORMAT=GML2&FILTER=" OR 1=1 OR 1="fanano" > [RESULT] + # RUN_PARMS: wfs_ogr_native_sql_06_disable_default_extent_for_getfeature.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=towns_disable_default_extent_for_getfeature&OUTPUTFORMAT=GML2&FILTER=nameFanano" > [RESULT] # RUN_PARMS: wfs_ogr_native_sql_07.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=towns&OUTPUTFORMAT=GML2&FILTER=namefanano" > [RESULT] @@ -49,6 +51,8 @@ # # RUN_PARMS: wfs_ogr_native_sql_20.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=towns&OUTPUTFORMAT=GML2&FILTER=nameV*o" > [RESULT] # RUN_PARMS: wfs_ogr_native_sql_21.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=towns&OUTPUTFORMAT=GML2&FILTER=namev*o" > [RESULT] +# RUN_PARMS: wfs_ogr_native_sql_like_parenthesis.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=layer_with_special_characters&OUTPUTFORMAT=GML2&FILTER=text*( )" > [RESULT] +# RUN_PARMS: wfs_ogr_native_sql_like_backslash_and_single_quote.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=layer_with_special_characters&OUTPUTFORMAT=GML2&FILTER=text*\ with single ' quote" > [RESULT] # # bug in MS: ? is treated as * in this case: # @@ -96,6 +100,9 @@ # RUN_PARMS: wfs_ogr_native_sql_42.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAME=towns_disable_default_extent_for_getfeature&OUTPUTFORMAT=GML2&COUNT=1" > [RESULT_DEVERSION] # RUN_PARMS: wfs_ogr_native_sql_43.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAME=towns_disable_default_extent_for_getfeature&OUTPUTFORMAT=GML2&COUNT=1&SRSNAME=EPSG:4326" > [RESULT_DEVERSION] +# RUN_PARMS: wfs_ogr_weird_column_names_binary_op_numeric.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=weird_column_names&OUTPUTFORMAT=GML2&FILTER=]1" > [RESULT] +# RUN_PARMS: wfs_ogr_weird_column_names_binary_op_string.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=weird_column_names&OUTPUTFORMAT=GML2&FILTER=a%26quot;bfoo" > [RESULT] + MAP NAME WFS_OGR_NATIVE_SQL_TEST @@ -331,5 +338,51 @@ LAYER TEMPLATE "wfs_ogr_native_sql.map" END # Layer +# Layer + +LAYER + + NAME layer_with_special_characters + DATA "layer_with_special_characters" + CONNECTIONTYPE OGR + CONNECTION "./data/db.sqlite" + PROCESSING "NATIVE_SQL=YES" + METADATA + "ows_title" "layer_with_special_characters" + "wfs_featureid" "ID" + "gml_include_items" "all" + "gml_types" "auto" + "wfs_getfeature_formatlist" "ogrgml" + END + TYPE POINT + STATUS ON + PROJECTION + "init=epsg:32632" + END + + TEMPLATE "wfs_ogr_native_sql.map" +END # Layer + +LAYER + + NAME weird_column_names + CONNECTIONTYPE OGR + CONNECTION "./data/weird_column_names.db" + PROCESSING "NATIVE_SQL=YES" + METADATA + "ows_title" "weird_column_names" + "wfs_featureid" "ID" + "gml_include_items" "all" + "gml_types" "auto" + "wfs_getfeature_formatlist" "ogrgml" + END + TYPE POINT + STATUS ON + PROJECTION + "init=epsg:32632" + END + + TEMPLATE "wfs_ogr_native_sql.map" +END # Layer END # Map File diff --git a/msautotest/wxs/wfs_ogr_no_native_sql.map b/msautotest/wxs/wfs_ogr_no_native_sql.map index 2e6a6d9661..7a3d4f95e2 100644 --- a/msautotest/wxs/wfs_ogr_no_native_sql.map +++ b/msautotest/wxs/wfs_ogr_no_native_sql.map @@ -17,6 +17,9 @@ # # RUN_PARMS: wfs_ogr_native_sql_05.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=towns&OUTPUTFORMAT=GML2&FILTER=namefanano" > [RESULT] # RUN_PARMS: wfs_ogr_native_sql_06.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=towns&OUTPUTFORMAT=GML2&FILTER=nameFanano" > [RESULT] + +# RUN_PARMS: wfs_ogr_native_sql_is_equal_to_invalid_property_name.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=towns&OUTPUTFORMAT=GML2&FILTER=" OR 1=1 OR 1="fanano" > [RESULT] + # RUN_PARMS: wfs_ogr_native_sql_07.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=towns&OUTPUTFORMAT=GML2&FILTER=namefanano" > [RESULT] # RUN_PARMS: wfs_ogr_native_sql_08.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=towns&OUTPUTFORMAT=GML2&FILTER=nameFanano" > [RESULT] # @@ -46,7 +49,7 @@ # # bug in MS: ? is treated as * in this case: # -# UN_PARMS: wfs_ogr_native_sql_22.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=towns&OUTPUTFORMAT=GML2&FILTER=name?r*" > [RESULT] +# RUN_PARMS: wfs_ogr_native_sql_22.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=towns&OUTPUTFORMAT=GML2&FILTER=name?r*" > [RESULT] # # spatial predicates # intersects, disjoint, touches, overlaps, crosses, within, contains, equals, beyond, dwithin @@ -62,6 +65,9 @@ # RUN_PARMS: wfs_ogr_native_sql_31.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=towns&OUTPUTFORMAT=GML2&FILTER=20000Geometry653627 4881103 653174 4890443 663148 4887813 663330 4879471 653627 4881103" > [RESULT] # RUN_PARMS: wfs_ogr_native_sql_32.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=towns&OUTPUTFORMAT=GML2&FILTER=1000Geometry653627 4881103 653174 4890443 663148 4887813 663330 4879471 653627 4881103" > [RESULT] +# RUN_PARMS: wfs_ogr_weird_column_names_binary_op_numeric.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=weird_column_names&OUTPUTFORMAT=GML2&FILTER=]1" > [RESULT] +# RUN_PARMS: wfs_ogr_weird_column_names_binary_op_string.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=weird_column_names&OUTPUTFORMAT=GML2&FILTER=a%26quot;bfoo" > [RESULT] + MAP NAME WFS_OGR_NATIVE_SQL_TEST @@ -119,4 +125,26 @@ LAYER TEMPLATE "wfs_ogr_native_sql.map" END # Layer +LAYER + + NAME weird_column_names + CONNECTIONTYPE OGR + CONNECTION "./data/weird_column_names.db" + PROCESSING "NATIVE_SQL=NO" + METADATA + "ows_title" "weird_column_names" + "wfs_featureid" "ID" + "gml_include_items" "all" + "gml_types" "auto" + "wfs_getfeature_formatlist" "ogrgml" + END + TYPE POINT + STATUS ON + PROJECTION + "init=epsg:32632" + END + + TEMPLATE "wfs_ogr_native_sql.map" +END # Layer + END # Map File diff --git a/msautotest/wxs/wfs_ogr_tileindex_of_shp.map b/msautotest/wxs/wfs_ogr_tileindex_of_shp.map index 57775a835e..1e0f3d6906 100644 --- a/msautotest/wxs/wfs_ogr_tileindex_of_shp.map +++ b/msautotest/wxs/wfs_ogr_tileindex_of_shp.map @@ -78,8 +78,6 @@ LAYER PROJECTION "init=epsg:4326" END - - DUMP TRUE END # Layer diff --git a/msautotest/wxs/wfs_ogr_tileindexmixedsrs.map b/msautotest/wxs/wfs_ogr_tileindexmixedsrs.map index 4bacc44c86..a596c97236 100644 --- a/msautotest/wxs/wfs_ogr_tileindexmixedsrs.map +++ b/msautotest/wxs/wfs_ogr_tileindexmixedsrs.map @@ -78,8 +78,6 @@ LAYER PROJECTION "init=epsg:4326" END - - DUMP TRUE END # Layer diff --git a/msautotest/wxs/wfs_optional_items.map b/msautotest/wxs/wfs_optional_items.map index 1c49819923..f7b4f16f0a 100644 --- a/msautotest/wxs/wfs_optional_items.map +++ b/msautotest/wxs/wfs_optional_items.map @@ -134,13 +134,14 @@ LAYER # "init=epsg:42304" END - DUMP TRUE CLASSITEM "Name_e" CLASS NAME "Province" - COLOR 200 255 0 - OUTLINECOLOR 120 120 120 + STYLE + COLOR 200 255 0 + OUTLINECOLOR 120 120 120 + END END END # Layer diff --git a/msautotest/wxs/wfs_postgis_10f_precision.map b/msautotest/wxs/wfs_postgis_10f_precision.map new file mode 100644 index 0000000000..b5e89980b8 --- /dev/null +++ b/msautotest/wxs/wfs_postgis_10f_precision.map @@ -0,0 +1,70 @@ +# +# Test rounding geometry floating point number to 10 decimal places support in PostGIS input and GML/WFS output +# +# REQUIRES: SUPPORTS=WFS INPUT=POSTGIS +# +# +# RUN_PARMS: wfs_postgis_10f_precision_gml2.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=popplace&MAXFEATURES=1" > [RESULT] +# RUN_PARMS: wfs_postgis_10f_precision_gml3.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.1.0&REQUEST=GetFeature&TYPENAME=popplace&MAXFEATURES=1" > [RESULT] + +MAP + #CONFIG "MS_ERRORFILE" "stderr" + NAME WFS_FILTER + STATUS ON + SIZE 400 300 + #EXTENT 2018000 -73300 3410396 647400 + #UNITS METERS + EXTENT -67.5725 42 -58.9275 48.5 + UNITS DD + IMAGECOLOR 255 255 255 + SHAPEPATH ./data + SYMBOLSET etc/symbols.sym + FONTSET etc/fonts.txt + + + # + # Start of web interface definition + # + WEB + + IMAGEPATH "/tmp/ms_tmp/" + IMAGEURL "/ms_tmp/" + + METADATA + "ows_updatesequence" "123" + "wfs_title" "Test simple wfs" + "wfs_onlineresource" "http://localhost/path/to/wfs_simple?" + "wfs_srs" "EPSG:4326 EPSG:4269" + "ows_schemas_location" "http://ogc.dmsolutions.ca" + "ows_enable_request" "*" + "wfs_geometry_precision" "10" + + END + END + + PROJECTION + "init=epsg:4326" + END + + # + # Start of layer definitions + # + + LAYER + NAME popplace + INCLUDE "postgis.include" + DATA "the_geom from (select * from popplace order by gid) as foo using srid=3978 using unique gid" + METADATA + "wfs_title" "popplace" + "wfs_description" "Cities" + "gml_include_items" "all" + END + TYPE POINT + STATUS ON + PROJECTION + "init=epsg:3978" + END + + LabelItem "Name" + END # Layer +END # Map File diff --git a/msautotest/wxs/wfs_postgis_25d.map b/msautotest/wxs/wfs_postgis_25d.map index ba2e772568..9799f12af4 100755 --- a/msautotest/wxs/wfs_postgis_25d.map +++ b/msautotest/wxs/wfs_postgis_25d.map @@ -1,7 +1,7 @@ # # Test both 2.5D support in PostGIS input and GML/WFS output # -# REQUIRES: SUPPORTS=WFS SUPPORTS=POINT_Z_M INPUT=POSTGIS +# REQUIRES: SUPPORTS=WFS INPUT=POSTGIS # # # RUN_PARMS: wfs_postgis_25d_gml2.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=point3d,linestring3d,polygon3d,multipoint3d,multilinestring3d,multipolygon3d" > [RESULT] @@ -51,8 +51,6 @@ LAYER PROJECTION "init=epsg:27700" END - - DUMP TRUE END LAYER @@ -74,7 +72,6 @@ LAYER "init=epsg:27700" END - DUMP TRUE END @@ -96,8 +93,6 @@ LAYER PROJECTION "init=epsg:27700" END - - DUMP TRUE END @@ -119,8 +114,6 @@ LAYER PROJECTION "init=epsg:27700" END - - DUMP TRUE END LAYER @@ -142,7 +135,6 @@ LAYER "init=epsg:27700" END - DUMP TRUE END LAYER @@ -164,7 +156,6 @@ LAYER "init=epsg:27700" END - DUMP TRUE END diff --git a/msautotest/wxs/wfs_postgis_4f_precision.map b/msautotest/wxs/wfs_postgis_4f_precision.map new file mode 100644 index 0000000000..5713531f84 --- /dev/null +++ b/msautotest/wxs/wfs_postgis_4f_precision.map @@ -0,0 +1,97 @@ +# +# Test rounding geometry floating point number to 4 decimal places support in PostGIS input and GML/WFS output +# +# REQUIRES: SUPPORTS=WFS INPUT=POSTGIS +# +# +# RUN_PARMS: wfs_postgis_precision_web_4f_gml2.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=popplace&MAXFEATURES=1" > [RESULT] +# RUN_PARMS: wfs_postgis_precision_web_4f_gml3.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.1.0&REQUEST=GetFeature&TYPENAME=popplace&MAXFEATURES=1" > [RESULT] +# RUN_PARMS: wfs_postgis_precision_web_4f_layer_10f_gml3.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.1.0&REQUEST=GetFeature&TYPENAME=popplace_10&MAXFEATURES=1" > [RESULT] + +MAP + #CONFIG "MS_ERRORFILE" "stderr" + NAME WFS_FILTER + STATUS ON + SIZE 400 300 + #EXTENT 2018000 -73300 3410396 647400 + #UNITS METERS + EXTENT -67.5725 42 -58.9275 48.5 + UNITS DD + IMAGECOLOR 255 255 255 + SHAPEPATH ./data + SYMBOLSET etc/symbols.sym + FONTSET etc/fonts.txt + + + # + # Start of web interface definition + # + WEB + + IMAGEPATH "/tmp/ms_tmp/" + IMAGEURL "/ms_tmp/" + + METADATA + "ows_updatesequence" "123" + "wfs_title" "Test simple wfs" + "wfs_onlineresource" "http://localhost/path/to/wfs_simple?" + "wfs_srs" "EPSG:4326 EPSG:4269" + "ows_schemas_location" "http://ogc.dmsolutions.ca" + "ows_enable_request" "*" + "wfs_geometry_precision" "4" + + END + END + + PROJECTION + "init=epsg:4326" + END + + # + # Start of layer definitions + # + + LAYER + NAME popplace + INCLUDE "postgis.include" + DATA "the_geom from (select * from popplace order by gid) as foo using srid=3978 using unique gid" + METADATA + "wfs_title" "popplace" + "wfs_description" "Cities" + "gml_include_items" "all" + END + TYPE POINT + STATUS ON + PROJECTION + "init=epsg:3978" + END + + LabelItem "Name" + END # Layer + + LAYER + NAME popplace_10 + INCLUDE "postgis.include" + DATA "the_geom from (select * from popplace order by gid) as foo using srid=3978 using unique gid" + METADATA + "wfs_title" "popplace" + "wfs_description" "Cities" + "wfs_geometry_precision" "10" + "gml_include_items" "all" + + END + TYPE POINT + STATUS ON + PROJECTION + "init=epsg:3978" + END + LabelItem "Name" + END # Layer + + + + + + + END # Map File + \ No newline at end of file diff --git a/msautotest/wxs/wfs_postgis_paging.map b/msautotest/wxs/wfs_postgis_paging.map new file mode 100644 index 0000000000..785ec9b786 --- /dev/null +++ b/msautotest/wxs/wfs_postgis_paging.map @@ -0,0 +1,62 @@ +# +# Test WFS paging with PostGIS +# +# REQUIRES: SUPPORTS=WFS INPUT=POSTGIS +# +# RUN_PARMS: wfs_postgis_issue_6181.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAMES=test_6181&BBOX=0.75,0.75,9,9&COUNT=1" > [RESULT_DEVERSION] +# RUN_PARMS: wfs_postgis_issue_6181_startindex_1.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAMES=test_6181&BBOX=0.75,0.75,9,9&COUNT=1&STARTINDEX=1" > [RESULT_DEVERSION] + +MAP + +NAME WFS_POSTGIS_PAGING +STATUS ON +SIZE 400 300 +EXTENT 6 30 21 50 +UNITS METERS +IMAGECOLOR 255 255 255 + +# +# Start of web interface definition +# + +WEB + + IMAGEPATH "tmp/" + IMAGEURL "/ms_tmp/" + + METADATA + "wfs_title" "Test simple wfs" + "wfs_onlineresource" "http://localhost/path/to/wfs_simple?" + "wfs_srs" "EPSG:27700" + "wfs_enable_request" "*" + END +END + +PROJECTION + "init=epsg:27700" +END + +# +# Start of layer definitions +# + +LAYER + NAME test_6181 + INCLUDE "postgis.include" + DATA "the_geom from (select * from test_wfs_paging order by id) as foo using srid=27700 using unique id" + METADATA + "wfs_title" "test_6181" + "wfs_description" "test_6181" + "gml_include_items" "all" + "wfs_featureid" "id" + END + TYPE LINE + STATUS ON + PROJECTION + "init=epsg:27700" + END + +END # Layer + + +END # Map File diff --git a/msautotest/wxs/wfs_query_cache.map b/msautotest/wxs/wfs_query_cache.map index 4738e7db9c..af89c05812 100644 --- a/msautotest/wxs/wfs_query_cache.map +++ b/msautotest/wxs/wfs_query_cache.map @@ -8,6 +8,10 @@ # RUN_PARMS: wfs_query_cache.json [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=province&MAXFEATURES=10&OUTPUTFORMAT=geojson" > [RESULT] +# RUN_PARMS: wfs2_query_cache.json [MAPSERV] "QUERY_STRING=map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAMES=province&MAXFEATURES=10&OUTPUTFORMAT=geojson" > [RESULT] + +# RUN_PARMS: wfs2_query_cache_no_default_extent.json [MAPSERV] "QUERY_STRING=map=[MAPFILE]&SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAMES=province2&MAXFEATURES=10&OUTPUTFORMAT=geojson" > [RESULT] + # This one will emit 'map->query.max_cached_shape_ram_amount = 10000 reached after 2 cached features' # Gives different result in Travis and Vagrant for some unknown reason # RUN_disabled_PARMS: wfs_query_cache_2.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=province&FILTER=NAME_ENova Scotia" > [RESULT] @@ -104,5 +108,23 @@ LAYER END # Layer +LAYER + NAME province2 + DATA province + METADATA + "wfs_title" "province2" + "wfs_description" "province2" + "wfs_use_default_extent_for_getfeature" "false" + "wfs_featureid" "NAME_E" + "gml_include_items" "NAME_E" + "gml_default_items" "NAME_E" + END + TYPE POINT + STATUS ON + PROJECTION + "init=./data/epsg2:42304" + END + +END # Layer END # Map File diff --git a/msautotest/wxs/wfs_shape_tileindex_of_shp.map b/msautotest/wxs/wfs_shape_tileindex_of_shp.map index 46378949fb..c5c4a70504 100644 --- a/msautotest/wxs/wfs_shape_tileindex_of_shp.map +++ b/msautotest/wxs/wfs_shape_tileindex_of_shp.map @@ -77,8 +77,6 @@ LAYER PROJECTION "init=epsg:4326" END - - DUMP TRUE END # Layer diff --git a/msautotest/wxs/wfs_shape_tileindexmixedsrs.map b/msautotest/wxs/wfs_shape_tileindexmixedsrs.map index 519b8df451..a4803f1547 100644 --- a/msautotest/wxs/wfs_shape_tileindexmixedsrs.map +++ b/msautotest/wxs/wfs_shape_tileindexmixedsrs.map @@ -77,8 +77,6 @@ LAYER PROJECTION "init=epsg:4326" END - - DUMP TRUE END # Layer diff --git a/msautotest/wxs/wfs_simple.map b/msautotest/wxs/wfs_simple.map index ba42f150a4..4619379c84 100644 --- a/msautotest/wxs/wfs_simple.map +++ b/msautotest/wxs/wfs_simple.map @@ -29,7 +29,7 @@ # Generate layer info using property name. # RUN_PARMS: wfs_get_feature_propertyname.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=province&propertyname=(name_e)" > [RESULT] # -# Generate layer info using property name and a geoemtry property. +# Generate layer info using property name and a geometry property. # RUN_PARMS: wfs_get_feature_propertyname_geometry.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=province&propertyname=(name_e,msGeometry)" > [RESULT] # # Invalid number of property name tuples @@ -172,13 +172,14 @@ LAYER # "init=epsg:42304" END - DUMP TRUE CLASSITEM "Name_e" CLASS NAME "Province" - COLOR 200 255 0 - OUTLINECOLOR 120 120 120 + STYLE + COLOR 200 255 0 + OUTLINECOLOR 120 120 120 + END END END # Layer diff --git a/msautotest/wxs/wfs_simple_ogr.map b/msautotest/wxs/wfs_simple_ogr.map index c56a734200..61f12a6e2e 100644 --- a/msautotest/wxs/wfs_simple_ogr.map +++ b/msautotest/wxs/wfs_simple_ogr.map @@ -29,7 +29,7 @@ # Generate layer info using property name. # RUN_PARMS: wfs_get_feature_propertyname_ogr.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=province&propertyname=(name_e)" > [RESULT] # -# Generate layer info using property name and a geoemtry property. +# Generate layer info using property name and a geometry property. # RUN_PARMS: wfs_get_feature_propertyname_geometry_ogr.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=province&propertyname=(name_e,msGeometry)" > [RESULT] # # Get Feature by id @@ -162,13 +162,14 @@ LAYER # "init=epsg:42304" END - DUMP TRUE CLASSITEM "Name_e" CLASS NAME "Province" - COLOR 200 255 0 - OUTLINECOLOR 120 120 120 + STYLE + COLOR 200 255 0 + OUTLINECOLOR 120 120 120 + END END END # Layer diff --git a/msautotest/wxs/wms_client_111.map b/msautotest/wxs/wms_client_111.map index 4e96d9d66f..1e166fe0ff 100644 --- a/msautotest/wxs/wms_client_111.map +++ b/msautotest/wxs/wms_client_111.map @@ -5,11 +5,15 @@ # # # GetMap +# RUN_PARMS: wms_client_111.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMap&LAYERS=client&STYLES=&WIDTH=300&HEIGHT=200&FORMAT=image/png&CRS=EPSG:4326&BBOX=-90,-180,90,180" > [RESULT_DEMIME] # RUN_PARMS: wms_client_111.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetMap&LAYERS=client&STYLES=&WIDTH=300&HEIGHT=200&FORMAT=image/png&SRS=EPSG:4326&BBOX=-180,-90,180,90" > [RESULT_DEMIME] # # GetFeatureInfo +# RUN_PARMS: wms_client_111.html [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetFeatureInfo&LAYERS=client&STYLES=&WIDTH=300&HEIGHT=200&FORMAT=image/png&CRS=EPSG:4326&BBOX=-90,-180,90,180&QUERY_LAYERS=client&I=100&J=150&INFO_FORMAT=text/html&FEATURE_COUNT=5" > [RESULT] # RUN_PARMS: wms_client_111.html [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetFeatureInfo&LAYERS=client&STYLES=&WIDTH=300&HEIGHT=200&FORMAT=image/png&SRS=EPSG:4326&BBOX=-180,-90,180,90&QUERY_LAYERS=client&I=100&J=150&INFO_FORMAT=text/html&FEATURE_COUNT=5" > [RESULT] +# # GetLegendGraphic +# RUN_PARMS: wms_client_111_legendgraphic.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetLegendGraphic&LAYER=client&FORMAT=image/png&TRANSPARENT=FALSE&SLD_VERSION=1.1.0" > [RESULT_DEMIME] # RUN_PARMS: wms_client_111_legendgraphic.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetLegendGraphic&LAYER=client&FORMAT=image/png" > [RESULT_DEMIME] @@ -46,7 +50,7 @@ MAP NAME client TYPE RASTER STATUS ON - CONNECTION "http://demo.mapserver.org/cgi-bin/wms?" + CONNECTION "https://demo.mapserver.org/cgi-bin/wms?" CONNECTIONTYPE WMS TEMPLATE "dummy" METADATA @@ -55,6 +59,7 @@ MAP "wms_server_version" "1.1.1" "wms_format" "image/png" "wms_enable_request" "*" + "wms_allowed_gdal_drivers" "PNG" # would be set automatically given wms_format=image/png END END END diff --git a/msautotest/wxs/wms_client_111_axis_fail.map b/msautotest/wxs/wms_client_111_axis_fail.map index 783f6db4a0..2cffb085b0 100644 --- a/msautotest/wxs/wms_client_111_axis_fail.map +++ b/msautotest/wxs/wms_client_111_axis_fail.map @@ -5,9 +5,11 @@ # # # GetMap +# RUN_PARMS: wms_client_111_axis_fail.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMap&LAYERS=client&STYLES=&WIDTH=300&HEIGHT=200&FORMAT=image/png&CRS=EPSG:4326&BBOX=-90,-180,90,180" > [RESULT_DEMIME] # RUN_PARMS: wms_client_111_axis_fail.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetMap&LAYERS=client&STYLES=&WIDTH=300&HEIGHT=200&FORMAT=image/png&SRS=EPSG:4326&BBOX=-180,-90,180,90" > [RESULT_DEMIME] # # GetFeatureInfo +# RUN_PARMS: wms_client_111_axis_fail.html [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetFeatureInfo&LAYERS=client&STYLES=&WIDTH=300&HEIGHT=200&FORMAT=image/png&CRS=EPSG:4326&BBOX=-90,-180,90,180&QUERY_LAYERS=client&I=100&J=150&INFO_FORMAT=text/html&FEATURE_COUNT=5" > [RESULT] # RUN_PARMS: wms_client_111_axis_fail.html [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetFeatureInfo&LAYERS=client&STYLES=&WIDTH=300&HEIGHT=200&FORMAT=image/png&SRS=EPSG:4326&BBOX=-180,-90,180,90&QUERY_LAYERS=client&I=100&J=150&INFO_FORMAT=text/html&FEATURE_COUNT=5" > [RESULT] @@ -44,7 +46,7 @@ MAP NAME client TYPE RASTER STATUS ON - CONNECTION "http://demo.mapserver.org/cgi-bin/wms?" + CONNECTION "https://demo.mapserver.org/cgi-bin/wms?" CONNECTIONTYPE WMS TEMPLATE "dummy" METADATA diff --git a/msautotest/wxs/wms_client_130.map b/msautotest/wxs/wms_client_130.map index 938b861e83..1a86eb32e0 100644 --- a/msautotest/wxs/wms_client_130.map +++ b/msautotest/wxs/wms_client_130.map @@ -5,12 +5,24 @@ # # # GetMap +# RUN_PARMS: wms_client_130.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMap&LAYERS=client&STYLES=&WIDTH=300&HEIGHT=200&FORMAT=image/png&CRS=EPSG:4326&BBOX=-90,-180,90,180" > [RESULT_DEMIME] # RUN_PARMS: wms_client_130.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetMap&LAYERS=client&STYLES=&WIDTH=300&HEIGHT=200&FORMAT=image/png&SRS=EPSG:4326&BBOX=-180,-90,180,90" > [RESULT_DEMIME] # +# RUN_PARMS: wms_client_crs_32633.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMap&LAYERS=client&STYLES=&WIDTH=300&HEIGHT=200&FORMAT=image/png&CRS=EPSG:32633&BBOX=920482.6044580448652,7662266.090040001087,1317920.914512843126,8079762.906353433616" > [RESULT_DEMIME] +# RUN_PARMS: wms_client_crs_32633.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetMap&LAYERS=client&STYLES=&WIDTH=300&HEIGHT=200&FORMAT=image/png&SRS=EPSG:32633&BBOX=920482.6044580448652,7662266.090040001087,1317920.914512843126,8079762.906353433616" > [RESULT_DEMIME] +# +# Request with STYLES. Note that the remote server does not publish any styles. +# RUN_PARMS: wms_client_undefined_style_exception.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMap&LAYERS=wms_style&STYLES=undefined_style&WIDTH=300&HEIGHT=200&FORMAT=image/png&CRS=EPSG:4326&BBOX=-90,-180,90,180" > [RESULT_DEMIME] +# Tests that the request is valid, but resulting image contains error as 'named_style' is not defined in remote server. +# RUN_PARMS: wms_client_style_remote_exception.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMap&LAYERS=wms_style&STYLES=named_style&WIDTH=300&HEIGHT=200&FORMAT=image/png&CRS=EPSG:4326&BBOX=-90,-180,90,180" > [RESULT_DEMIME] +# # GetFeatureInfo +# RUN_PARMS: wms_client_130.html [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetFeatureInfo&LAYERS=client&STYLES=&WIDTH=300&HEIGHT=200&FORMAT=image/png&CRS=EPSG:4326&BBOX=-90,-180,90,180&QUERY_LAYERS=client&I=100&J=150&INFO_FORMAT=text/html&FEATURE_COUNT=5" > [RESULT] # RUN_PARMS: wms_client_130.html [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetFeatureInfo&LAYERS=client&STYLES=&WIDTH=300&HEIGHT=200&FORMAT=image/png&SRS=EPSG:4326&BBOX=-180,-90,180,90&QUERY_LAYERS=client&I=100&J=150&INFO_FORMAT=text/html&FEATURE_COUNT=5" > [RESULT] +# # GetLegendGraphic # RUN_PARMS: wms_client_130_legendgraphic.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetLegendGraphic&LAYER=client&FORMAT=image/png&TRANSPARENT=FALSE&SLD_VERSION=1.1.0" > [RESULT_DEMIME] +# RUN_PARMS: wms_client_130_legendgraphic.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetLegendGraphic&LAYER=client&FORMAT=image/png&TRANSPARENT=FALSE&SLD_VERSION=1.1.0" > [RESULT_DEMIME] MAP @@ -46,15 +58,34 @@ MAP NAME client TYPE RASTER STATUS ON - CONNECTION "http://demo.mapserver.org/cgi-bin/wms?" + CONNECTION "https://demo.mapserver.org/cgi-bin/wms?" CONNECTIONTYPE WMS TEMPLATE "dummy" + EXTENT -180 -90 180 90 METADATA - "wms_srs" "EPSG:4326" + "wms_srs" "EPSG:4326 EPSG:32633" + "wms_name" "cities" + "wms_server_version" "1.3.0" + "wms_format" "image/png" + "wms_enable_request" "*" + END + END + + LAYER + NAME wms_style + TYPE RASTER + STATUS ON + CONNECTION "https://demo.mapserver.org/cgi-bin/wms?" + CONNECTIONTYPE WMS + TEMPLATE "dummy" + EXTENT -180 -90 180 90 + METADATA + "wms_srs" "EPSG:4326 EPSG:32633" "wms_name" "cities" "wms_server_version" "1.3.0" "wms_format" "image/png" "wms_enable_request" "*" + "wms_style" "named_style" END END END diff --git a/msautotest/wxs/wms_client_130_axis_fail.map b/msautotest/wxs/wms_client_130_axis_fail.map index 529bec7ef8..e46295c643 100644 --- a/msautotest/wxs/wms_client_130_axis_fail.map +++ b/msautotest/wxs/wms_client_130_axis_fail.map @@ -5,9 +5,11 @@ # # # GetMap +# RUN_PARMS: wms_client_130_axis_fail.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMap&LAYERS=client&STYLES=&WIDTH=300&HEIGHT=200&FORMAT=image/png&CRS=EPSG:4326&BBOX=-90,-180,90,180" > [RESULT_DEMIME] # RUN_PARMS: wms_client_130_axis_fail.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetMap&LAYERS=client&STYLES=&WIDTH=300&HEIGHT=200&FORMAT=image/png&SRS=EPSG:4326&BBOX=-180,-90,180,90" > [RESULT_DEMIME] -# + # GetFeatureInfo +# RUN_PARMS: wms_client_130_axis_fail.html [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetFeatureInfo&LAYERS=client&STYLES=&WIDTH=300&HEIGHT=200&FORMAT=image/png&CRS=EPSG:4326&BBOX=-90,-180,90,180&QUERY_LAYERS=client&I=100&J=150&INFO_FORMAT=text/html&FEATURE_COUNT=5" > [RESULT] # RUN_PARMS: wms_client_130_axis_fail.html [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetFeatureInfo&LAYERS=client&STYLES=&WIDTH=300&HEIGHT=200&FORMAT=image/png&SRS=EPSG:4326&BBOX=-180,-90,180,90&QUERY_LAYERS=client&I=100&J=150&INFO_FORMAT=text/html&FEATURE_COUNT=5" > [RESULT] @@ -44,7 +46,7 @@ MAP NAME client TYPE RASTER STATUS ON - CONNECTION "http://demo.mapserver.org/cgi-bin/wms?" + CONNECTION "https://demo.mapserver.org/cgi-bin/wms?" CONNECTIONTYPE WMS TEMPLATE "dummy" METADATA diff --git a/msautotest/wxs/wms_contour_input_data_rotate_lat_lon.map b/msautotest/wxs/wms_contour_input_data_rotate_lat_lon.map new file mode 100644 index 0000000000..7f6286ee61 --- /dev/null +++ b/msautotest/wxs/wms_contour_input_data_rotate_lat_lon.map @@ -0,0 +1,60 @@ +# +# +# Test contouring in EPSG:3857 and EPSG:4326 a raster georeferenced in rotated +# pole lat/lon +# +# + +# RUN_PARMS: wms_contour_input_data_rotate_lat_lon_request_3857.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&REQUEST=GetMap&SERVICE=WMS&VERSION=1.3.0&FORMAT=image%2Fpng&STYLES=&LAYERS=sample&WIDTH=400&HEIGHT=200&CRS=EPSG%3A3857&BBOX=-19106576.88229376%2C1389011.8799984828%2C4089954.3853118718%2C13410571.879998483" > [RESULT_DEMIME] + +# RUN_PARMS: wms_contour_input_data_rotate_lat_lon_request_4326.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&REQUEST=GetMap&SERVICE=WMS&VERSION=1.3.0&FORMAT=image%2Fpng&STYLES=&LAYERS=sample&WIDTH=400&HEIGHT=200&CRS=EPSG%3A4326&BBOX=0,-180,90,180" > [RESULT_DEMIME] + +MAP + NAME TEST + IMAGETYPE "PNG" + EXTENT -180 -90 180 90 + MAXSIZE 16384 + SIZE 500 300 + PROJECTION + "init=epsg:4326" + END + WEB + METADATA + "ows_srs" "EPSG:4326 EPSG:3857" + "ows_enable_request" "*" + "ows_extent" "-180 -90 180 90" + "ows_onlineresource" "http://example.com" + END + END + LAYER + NAME "sample" + TYPE LINE + CONNECTIONTYPE CONTOUR + PROCESSING "CONTOUR_INTERVAL=5" + PROCESSING "CONTOUR_ITEM=pixel" + TOLERANCE 25 + TEMPLATE "ttt.html" + PROJECTION + "proj=ob_tran" + "o_proj=longlat" + "o_lon_p=0" + "o_lat_p=31.758312" + "lon_0=-92.402969" + "R=6371229" + "no_defs" + END + DATA "data/input_contour_rotated_pole.tif" + METADATA + "ows_title" "RDPS - Air temperature at 2m above ground (contour) [°C]" + "ows_extent" "-180 -3.8249855 180 90" + END + LABELITEM "pixel" + CLASS + STYLE + WIDTH 1 + COLOR 255 0 0 + END + END + + END +END diff --git a/msautotest/wxs/wms_contour_request_3857_overlapping_antimeridian.map b/msautotest/wxs/wms_contour_request_3857_overlapping_antimeridian.map new file mode 100644 index 0000000000..b64a947925 --- /dev/null +++ b/msautotest/wxs/wms_contour_request_3857_overlapping_antimeridian.map @@ -0,0 +1,56 @@ +# +# +# Test contouring in EPSG:3857 a raster georeferenced in long/lat, and make +# the request overlap the antimeridian +# +# + +# RUN_PARMS: wms_contour_request_3857_overlapping_antimeridian.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&REQUEST=GetMap&SERVICE=WMS&VERSION=1.3.0&FORMAT=image%2Fpng&STYLES=&LAYERS=sample&WIDTH=200&HEIGHT=66&CRS=EPSG%3A3857&BBOX=-27543180.431148082%2C5106587.702716162%2C-12709106.689404964%2C10017764.358611304" > [RESULT_DEMIME] + +MAP + NAME TEST + IMAGETYPE "PNG" + EXTENT -180 -90 180 90 + MAXSIZE 16384 + SIZE 500 300 + PROJECTION + "init=epsg:4326" + END + WEB + METADATA + "ows_srs" "EPSG:4326 EPSG:3857" + "ows_enable_request" "*" + "ows_extent" "-180 -90 180 90" + "ows_onlineresource" "http://example.com" + END + END + LAYER + NAME "sample" + TYPE LINE + CONNECTIONTYPE CONTOUR + PROCESSING "CONTOUR_INTERVAL=50" + PROCESSING "CONTOUR_ITEM=pixel" + TOLERANCE 25 + TEMPLATE "ttt.html" + PROJECTION + "proj=longlat" + "lon_wrap=0" + "a=6371229" + "b=6371229" + "no_defs" + END + DATA "data/input_contour_line_worldwide.tif" + METADATA + "ows_title" "GDPS - Thickness between 1000mb and 500mb (contour) [m] [experimental]" + "ows_extent" "-180.075 -90.075 179.925 90.75" + END + LABELITEM "pixel" + CLASS + STYLE + WIDTH 1 + COLOR 255 0 0 + END + END + + END +END diff --git a/msautotest/wxs/wms_custom_projection.map b/msautotest/wxs/wms_custom_projection.map new file mode 100644 index 0000000000..24d4d4956a --- /dev/null +++ b/msautotest/wxs/wms_custom_projection.map @@ -0,0 +1,82 @@ +# +# Test WMS with a custom projection in a text file +# +# REQUIRES: OUTPUT=PNG SUPPORTS=WMS +# +# +# GetMap +# RUN_PARMS: wms_custom_projection_getmap110.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.1.0&REQUEST=GetMap&SRS=epsg2:42304&BBOX=2258982,-70747.9140625,2615354.5,495480.9375&FORMAT=image/png&WIDTH=300&HEIGHT=200&STYLES=&LAYERS=road" > [RESULT_DEMIME] +# RUN_PARMS: wms_custom_projection_getmap130.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMap&CRS=epsg2:42304&BBOX=2258982,-70747.9140625,2615354.5,495480.9375&FORMAT=image/png&WIDTH=300&HEIGHT=200&STYLES=&LAYERS=road" > [RESULT_DEMIME] +# test with alternative advertised layer projection +# RUN_PARMS: wms_custom_projection2_getmap130.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMap&CRS=epsg2:3978&BBOX=2258982,-70747.9140625,2615354.5,495480.9375&FORMAT=image/png&WIDTH=300&HEIGHT=200&STYLES=&LAYERS=road" > [RESULT_DEMIME] + +# only projection codes referenced in the map can be used +# RUN_PARMS: wms_custom_projection_not_specified.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMap&CRS=esri:54009&BBOX=2258982,-70747.9140625,2615354.5,495480.9375&FORMAT=image/png&WIDTH=300&HEIGHT=200&STYLES=&LAYERS=road" > [RESULT_DEMIME] +# convert from custom projection to EPSG:4326 +# RUN_PARMS: wms_custom_projection_4326.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMap&CRS=EPSG:4326&BBOX=42.000000,-67.572500,48.500000,-58.927500&FORMAT=image/png&WIDTH=300&HEIGHT=200&STYLES=&LAYERS=road" > [RESULT_DEMIME] + +# GetCapabilities +# RUN_PARMS: wms_custom_projection_getcapabilities.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetCapabilities" > [RESULT_DEVERSION] [RESULT_DEMIME] + +MAP + +NAME WMS_CUSTOM_PROJECTION +STATUS ON +SIZE 400 300 +EXTENT -67.5725 42 -58.9275 48.5 +UNITS DD +IMAGECOLOR 255 255 255 +SHAPEPATH ./data + +OUTPUTFORMAT + NAME png + DRIVER "AGG/PNG8" + MIMETYPE "image/png" + EXTENSION "png" +END + +WEB + + IMAGEPATH "/tmp/ms_tmp/" + IMAGEURL "/ms_tmp/" + + METADATA + "wms_title" "Test custom projection wms" + "wms_onlineresource" "http://localhost/path/to/wms_custom_projection?" + "wms_srs" "EPSG:4326 epsg2:42304" + "ows_enable_request" "*" + END +END + +PROJECTION + "init=epsg:4326" +END + +LAYER + NAME road + DATA road + TEMPLATE "ttt" + METADATA + "wms_title" "road" + # add in an additional custom code + # ensure the epsg2 file with the custom projection is in the PROJ_DATA folder + "wms_srs" "epsg2:42304 epsg2:3978" + "gml_include_items" "all" + END + TYPE LINE + STATUS ON + PROJECTION + "init=epsg2:42304" + END + + CLASSITEM "Name_e" + CLASS + NAME "Roads" + STYLE + SYMBOL 0 + COLOR 220 0 0 + END + END +END # Layer + +END # Map File diff --git a/msautotest/wxs/wms_dimensions.map b/msautotest/wxs/wms_dimensions.map index 7024655ea1..d0d7ff864d 100644 --- a/msautotest/wxs/wms_dimensions.map +++ b/msautotest/wxs/wms_dimensions.map @@ -155,7 +155,7 @@ LAYER NAME lakes_elev METADATA - "DESCRIPTION" "Lakes with dimesions (elevation and text)" + "DESCRIPTION" "Lakes with dimensions (elevation and text)" "wms_title" "Lakes" "wms_description" "Lakes" "wms_dimensionlist" "elevation, text_dimension" @@ -190,7 +190,7 @@ LAYER NAME lakes_elev_range METADATA - "DESCRIPTION" "Lakes with dimesions (elevation and text)" + "DESCRIPTION" "Lakes with dimensions (elevation and text)" "wms_title" "Lakes" "wms_description" "Lakes" "wms_dimensionlist" "elevation" @@ -217,7 +217,7 @@ LAYER NAME lakes_elev_multi_range METADATA - "DESCRIPTION" "Lakes with dimesions (elevation and text)" + "DESCRIPTION" "Lakes with dimensions (elevation and text)" "wms_title" "Lakes" "wms_description" "Lakes" "wms_dimensionlist" "elevation" diff --git a/msautotest/wxs/wms_filter.map b/msautotest/wxs/wms_filter.map index 50d1176b61..afdcc44d5c 100644 --- a/msautotest/wxs/wms_filter.map +++ b/msautotest/wxs/wms_filter.map @@ -34,6 +34,12 @@ # GetMap 1.3.0 filter with invalid group name # RUN_PARMS: wms_filter_getmap130_wrong_group.txt [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMap&CRS=EPSG%3A4326&BBOX=40,-70,50,-60&WIDTH=400&HEIGHT=400&LAYERS=inval_group&STYLES=&FORMAT=image%2Fpng&BGCOLOR=0xFFFFFF&TRANSPARENT=FALSE&EXCEPTIONS=XML&FILTER=(REG_CODE12)" > [RESULT_DEMIME] # +# GetMap 1.3.0 same layer with two styles and two filters +# RUN_PARMS: wms_filter_getmap130_repeated_layer.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMap&CRS=EPSG%3A4326&BBOX=40,-70,50,-60&WIDTH=400&HEIGHT=400&LAYERS=road,road&STYLES=default,green&FORMAT=image%2Fpng&BGCOLOR=0xFFFFFF&TRANSPARENT=FALSE&EXCEPTIONS=INIMAGE&FILTER=(F_CODE74)(Geometry46,-630.5)" > [RESULT_DEMIME] +# +# GetMap 1.3.0 same layer with two styles and two filters, one empty +# RUN_PARMS: wms_filter_getmap130_repeated_layer_empty_filter.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMap&CRS=EPSG%3A4326&BBOX=40,-70,50,-60&WIDTH=400&HEIGHT=400&LAYERS=road,road&STYLES=default,green&FORMAT=image%2Fpng&BGCOLOR=0xFFFFFF&TRANSPARENT=FALSE&EXCEPTIONS=INIMAGE&FILTER=()(Geometry46,-630.5)" > [RESULT_DEMIME] +# MAP @@ -95,13 +101,14 @@ LAYER "init=epsg:3978" END - DUMP TRUE CLASSITEM "Name_e" CLASS NAME "Province" - COLOR 200 255 0 - OUTLINECOLOR 120 120 120 + STYLE + COLOR 200 255 0 + OUTLINECOLOR 120 120 120 + END END END # Layer @@ -122,14 +129,16 @@ LAYER "init=epsg:3978" END - DUMP TRUE LabelItem "Name" CLASSITEM "Capital" CLASS EXPRESSION /./ - SYMBOL 2 - SIZE 8 + STYLE + SYMBOL 2 + SIZE 8 + COLOR 0 0 0 + END NAME "Cities" LABEL COLOR 0 0 0 @@ -140,7 +149,6 @@ LAYER PARTIALS FALSE OUTLINECOLOR 255 255 255 END - COLOR 0 0 0 END END # Layer @@ -158,14 +166,27 @@ LAYER "init=epsg:3978" END - DUMP TRUE - CLASSITEM "Name_e" + CLASSGROUP "default" + CLASS + GROUP "default" NAME "Roads" - SYMBOL 0 - COLOR 220 0 0 + STYLE + SYMBOL 0 + COLOR 220 0 0 + END END + + CLASS + GROUP "green" + NAME "Roads" + STYLE + SYMBOL 0 + COLOR 0 255 0 + END + END + END # Layer diff --git a/msautotest/wxs/wms_filter_color_bind.map b/msautotest/wxs/wms_filter_color_bind.map new file mode 100644 index 0000000000..d06cd493d2 --- /dev/null +++ b/msautotest/wxs/wms_filter_color_bind.map @@ -0,0 +1,106 @@ +# +# Test WMS vendor-specific FILTER with attribute color binding +# +# REQUIRES: INPUT=GDAL OUTPUT=PNG SUPPORTS=WMS +# +# +# RUN_PARMS: wms_filter_color_bind.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMap&FORMAT=image/png&TRANSPARENT=true&LAYERS=test001&WIDTH=500&HEIGHT=500&CRS=EPSG:4326&BBOX=0,-1.5,1,0&STYLES=&FILTER=(%3CFilter%20xmlns=%22http://www.opengis.net/ogc%22%3E%3CPropertyIsEqualTo%3E%3CPropertyName%3Esymbol%3C/PropertyName%3E%3CLiteral%3Ecircle%3C/Literal%3E%3C/PropertyIsEqualTo%3E%3C/Filter%3E)" > [RESULT_DEMIME] + +MAP + NAME WMS_FILTER_COLOR_BIND + STATUS ON + SIZE 500 500 + EXTENT -1.5 0 -0.5 1 + UNITS DD + IMAGECOLOR 255 255 255 + SHAPEPATH ../misc/data + SYMBOLSET etc/symbols.sym + FONTSET ../misc/fonts.lst + + WEB + + IMAGEPATH "/tmp/ms_tmp/" + IMAGEURL "/ms_tmp/" + + METADATA + "wms_title" "Test simple wms" + "wms_onlineresource" "http://localhost/path/to/wms_simple?" + "wms_srs" "EPSG:4326" + "ows_schemas_location" "http://ogc.dmsolutions.ca" + "ows_enable_request" "*" + END + END + + PROJECTION + "init=epsg:4326" + END + + IMAGETYPE PNG + + SYMBOL + NAME 'triangle' + TYPE VECTOR + POINTS + 0 4 + 2 0 + 4 4 + 0 4 + END + FILLED TRUE + END + + SYMBOL + NAME 'square' + TYPE VECTOR + POINTS 0 0 1 0 1 1 0 1 0 0 END + FILLED TRUE + END + + SYMBOL + NAME 'circle' + TYPE ELLIPSE + POINTS 1 1 END + FILLED TRUE + END + + LAYER + METADATA + "wms_title" "test001" + "wms_description" "test001" + END + PROJECTION + "init=epsg:4326" + END + + NAME 'test001' + TYPE POINT + DATA 'attrbind' + STATUS OFF + LABELITEM 'text' + CLASS + STYLE # a shadow + COLOR 151 151 151 + SYMBOL [symbol] + OFFSET 2 2 + SIZE [size] + END + STYLE + COLOR [color] + SYMBOL [symbol] + SIZE [size] + END + LABEL + STYLE + GEOMTRANSFORM "labelpoly" + COLOR [color] + END + TYPE TRUETYPE + FONT 'default' + COLOR [lcolor] + SIZE [lsize] + POSITION UR + END + END + END +END + diff --git a/msautotest/wxs/wms_getfeatureinfo_datatypes_raster.map b/msautotest/wxs/wms_getfeatureinfo_datatypes_raster.map new file mode 100644 index 0000000000..1cf4d7b91d --- /dev/null +++ b/msautotest/wxs/wms_getfeatureinfo_datatypes_raster.map @@ -0,0 +1,70 @@ +# +# Test WMS GetfeatureInfo with a raster Int32 layer +# +# REQUIRES: SUPPORTS=WMS +# +# RUN_PARMS: wms_getfeatureinfo_int32_raster.json [MAPSERV] "QUERY_STRING=map=[MAPFILE]&service=WMS&request=GetFeatureInfo&version=1.3.0&CRS=EPSG:2157&width=200&height=200&layers=int32&bbox=600181.89,628797.70,600191.27,628807.09&query_layers=int32&i=50&j=50&STYLES=&info_format=geojson" > [RESULT_DEMIME] +# RUN_PARMS: wms_getfeatureinfo_float64_raster.json [MAPSERV] "QUERY_STRING=map=[MAPFILE]&service=WMS&request=GetFeatureInfo&version=1.3.0&CRS=EPSG:2157&width=200&height=200&layers=float64&bbox=600181.89,628797.70,600191.27,628807.09&query_layers=float64&i=50&j=50&STYLES=&info_format=geojson" > [RESULT_DEMIME] + +MAP + + NAME 'test' + EXTENT 600029.81 628680.39 600319.81 628905.39 + SIZE 600 600 + IMAGETYPE PNG + PROJECTION + "init=epsg:2157" + END + + WEB + METADATA + "ows_enable_request" "*" + "ows_srs" "EPSG:2157" + "ows_title" "WMS Getfeatureinfo" + "wms_getfeatureinfo_formatlist" "geojson" + "wms_onlineresource" "http://localhost/cgi-bin/mapserv?map=mymap.map" + END + END + + OUTPUTFORMAT + NAME "geojson" + DRIVER "OGR/GEOJSON" + MIMETYPE "application/json; subtype=geojson; charset=utf-8" + FORMATOPTION "FORM=SIMPLE" + FORMATOPTION "STORAGE=memory" + FORMATOPTION "LCO:NATIVE_MEDIA_TYPE=application/vnd.geo+json" + FORMATOPTION "USE_FEATUREID=true" + END + + + LAYER + NAME "int32" + STATUS OFF + TYPE RASTER + TEMPLATE "blank" + DATA "data/int32.tif" + PROJECTION + "EPSG:2157" + END + METADATA + "gml_include_items" "all" + "gml_value_0_type" "Long" + END + END + + LAYER + NAME "float64" + STATUS OFF + TYPE RASTER + TEMPLATE "blank" + DATA "data/float64.tif" + PROJECTION + "EPSG:2157" + END + METADATA + "gml_include_items" "all" + "gml_value_0_type" "Real" + END + END + +END # of map file diff --git a/msautotest/wxs/wms_grid_reproj_to_3857.map b/msautotest/wxs/wms_grid_reproj_to_3857.map index 0ae96122ba..31ed34f611 100644 --- a/msautotest/wxs/wms_grid_reproj_to_3857.map +++ b/msautotest/wxs/wms_grid_reproj_to_3857.map @@ -29,10 +29,10 @@ MAP END OUTPUTFORMAT - NAME GDPNG - DRIVER "GD/PNG" - MIMETYPE "image/png" - EXTENSION "png" + NAME png + DRIVER "AGG/PNG8" + MIMETYPE "image/png" + EXTENSION "png" END LAYER @@ -47,16 +47,18 @@ MAP CLASS NAME "Graticule" - COLOR 255 153 0 + STYLE + COLOR 255 153 0 + END LABEL - COLOR 0 0 0 - FONT lucida - TYPE truetype - SIZE 8 - POSITION AUTO - PARTIALS FALSE - BUFFER 5 - OUTLINECOLOR 255 255 255 + COLOR 0 0 0 + FONT lucida + TYPE truetype + SIZE 8 + POSITION AUTO + PARTIALS FALSE + BUFFER 5 + OUTLINECOLOR 255 255 255 END END diff --git a/msautotest/wxs/wms_inspire_scenario1.map b/msautotest/wxs/wms_inspire_scenario1.map index 2bcdf05cfb..bab01f90ba 100644 --- a/msautotest/wxs/wms_inspire_scenario1.map +++ b/msautotest/wxs/wms_inspire_scenario1.map @@ -157,14 +157,18 @@ LAYER NAME "myclass1" GROUP "inspire_common:DEFAULT" EXPRESSION "67" - COLOR 255 0 0 + STYLE + COLOR 255 0 0 + END END CLASS NAME "myclass2" GROUP "inspire_common:DEFAULT" EXPRESSION "68" - COLOR 0 255 0 + STYLE + COLOR 0 255 0 + END END END # Layer @@ -208,7 +212,9 @@ LAYER NAME "myclass3" GROUP "inspire_common:DEFAULT" EXPRESSION "74" - COLOR 0 0 255 + STYLE + COLOR 0 0 255 + END END END # Layer @@ -242,7 +248,9 @@ LAYER NAME "myclass4" GROUP "inspire_common:DEFAULT" EXPRESSION "66" - COLOR 0 255 255 + STYLE + COLOR 0 255 255 + END END END # Layer diff --git a/msautotest/wxs/wms_inspire_scenario2.map b/msautotest/wxs/wms_inspire_scenario2.map index f891edb8ed..36820d651d 100644 --- a/msautotest/wxs/wms_inspire_scenario2.map +++ b/msautotest/wxs/wms_inspire_scenario2.map @@ -163,14 +163,18 @@ LAYER NAME "myclass1" GROUP "inspire_common:DEFAULT" EXPRESSION "67" - COLOR 255 0 0 + STYLE + COLOR 255 0 0 + END END CLASS NAME "myclass2" GROUP "inspire_common:DEFAULT" EXPRESSION "68" - COLOR 0 255 0 + STYLE + COLOR 0 255 0 + END END END # Layer @@ -214,7 +218,9 @@ LAYER NAME "myclass3" GROUP "inspire_common:DEFAULT" EXPRESSION "74" - COLOR 0 0 255 + STYLE + COLOR 0 0 255 + END END END # Layer @@ -248,7 +254,9 @@ LAYER NAME "myclass4" GROUP "inspire_common:DEFAULT" EXPRESSION "66" - COLOR 0 255 255 + STYLE + COLOR 0 255 255 + END END END # Layer diff --git a/msautotest/wxs/wms_layer_groups.map b/msautotest/wxs/wms_layer_groups.map index 0c0a709354..e9a4ec5487 100644 --- a/msautotest/wxs/wms_layer_groups.map +++ b/msautotest/wxs/wms_layer_groups.map @@ -114,11 +114,17 @@ MAP END LAYER + TEMPLATE "ttt" TYPE POINT - NAME "g3" + NAME "g3l1" STATUS ON METADATA - "wms_title" "My g3" + "wms_title" "g3l1 title" + "wms_abstract" "g3l1 Abstract" + + "wms_layer_group" "/g3" + "wms_group_title" "Group g3 title" + "wms_group_abstract" "Group g3 Abstract" END CLASS LABEL @@ -126,7 +132,7 @@ MAP COLOR 0 0 0 SIZE 8 POSITION cc - END + END END FEATURE POINTS 50 90 END END END @@ -138,6 +144,10 @@ MAP STATUS ON METADATA "wms_layer_group" "/g3/sg4" + "wms_title" "g3sg4l1 title" + "wms_abstract" "g3sg4l1 Abstract" + "wms_group_title" "Group g3/sg4 title" + "wms_group_abstract" "Group g3/sg4 Abstract" END CLASS LABEL @@ -145,7 +155,7 @@ MAP COLOR 0 0 0 SIZE 8 POSITION cc - END + END END FEATURE POINTS 50 110 END END END diff --git a/msautotest/wxs/wms_legend.map b/msautotest/wxs/wms_legend.map index 53d9dfe767..144b194553 100644 --- a/msautotest/wxs/wms_legend.map +++ b/msautotest/wxs/wms_legend.map @@ -19,9 +19,9 @@ # RUN_PARMS: wms_content_legend_empty_sld.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.1.0&REQUEST=GetLegendGraphic&SRS=EPSG:3978&WIDTH=560&HEIGHT=350&LAYER=layer1&FORMAT=image/png&BGCOLOR=0xFFFFFF&TRANSPARENT=FALSE&EXCEPTIONS=INIMAGE&BBOX=2291338,-73348,2301636,-64058&SLD_BODY=layer1sld roadsSLD 74 titleF_CODE744center-line#ff00ff2.0SLD 66 titleF_CODE666center-line#ff00ff2.0" > [RESULT_DEMIME] # RUN_PARMS: mode_maplegend_all.png [MAPSERV] QUERY_STRING='map=[MAPFILE]&mode=maplegend&mapext=2258982+-70747+2615354+495480&layer=layer1' > [RESULT_DEMIME] # RUN_PARMS: mode_maplegend_74.png [MAPSERV] QUERY_STRING='map=[MAPFILE]&mode=maplegend&mapext=2291338+-73348+2301636+-64058&layer=layer1' > [RESULT_DEMIME] -# RUN_PARMS: wms_content_legend_l1_changefont.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.1.0&REQUEST=GetLegendGraphic&LAYER=layer1&FORMAT=image/png&BGCOLOR=0xFFFFFF&TRANSPARENT=FALSE&EXCEPTIONS=INIMAGE&map.legend.label=font+VeraBd" > [RESULT_DEMIME] # RUN_PARMS: wms_legend_notext.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.1.0&REQUEST=GetLegendGraphic&LAYER=layer3&FORMAT=image/png" > [RESULT_DEMIME] # RUN_PARMS: wms_keyimage_legend.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.1.0&REQUEST=GetLegendGraphic&LAYER=layer4&FORMAT=image/png&TRANSPARENT=FALSE&EXCEPTIONS=INIMAGE" > [RESULT_DEMIME] +# RUN_PARMS: wms_gradient_legend.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetLegendGraphic&LAYER=gradient&SLD_VERSION=1.1.0&FORMAT=image/png&TRANSPARENT=FALSE&EXCEPTIONS=INIMAGE" > [RESULT_DEMIME] MAP @@ -229,4 +229,27 @@ LAYER END #Class END # Layer +LAYER + NAME "gradient" + DATA multiband.tif + METADATA + "wms_title" "gradient_opacity" + END + TYPE RASTER + STATUS ON + + CLASSITEM "GRADIENT" + CLASS + NAME "-250 m to -50 m" + GROUP "Blue" + EXPRESSION ([pixel] >= -250 AND [pixel] < -50) + STYLE + OPACITY 70 + RANGEITEM "pixel" + COLORRANGE 128 172 239 7 6 111 + DATARANGE -250.000000 -50.000000 + END # STYLE + TITLE "-250 m to -50 m" + END # CLASS +END # Layer END # Map File diff --git a/msautotest/wxs/wms_multiple_metadataurl.map b/msautotest/wxs/wms_multiple_metadataurl.map index d4ed43df20..7951f70be6 100644 --- a/msautotest/wxs/wms_multiple_metadataurl.map +++ b/msautotest/wxs/wms_multiple_metadataurl.map @@ -21,10 +21,9 @@ FONTSET etc/fonts.txt OUTPUTFORMAT - NAME GDPNG - DRIVER "GD/PNG" + NAME png + DRIVER "AGG/PNG8" MIMETYPE "image/png" -# IMAGEMODE RGB EXTENSION "png" END @@ -114,13 +113,13 @@ LAYER "init=./data/epsg2:42304" END - DUMP TRUE - CLASSITEM "Name_e" CLASS NAME "Roads" - SYMBOL 0 - COLOR 220 0 0 + STYLE + SYMBOL 0 + COLOR 220 0 0 + END END END # Layer diff --git a/msautotest/wxs/wms_mvt.map b/msautotest/wxs/wms_mvt.map index 59cef0b474..c188b0f688 100644 --- a/msautotest/wxs/wms_mvt.map +++ b/msautotest/wxs/wms_mvt.map @@ -3,15 +3,20 @@ # # REQUIRES: INPUT=GDAL SUPPORTS=PBF SUPPORTS=WMS # -# RUN_PARMS: wms_mvt.mvt [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.1.0&REQUEST=GetMap&SRS=EPSG:3857&BBOX=-7514065.628545966,5009377.085697311,-6261721.357121638,6261721.357121639&WIDTH=256&HEIGHT=256&STYLES=&LAYERS=road&FORMAT=application/x-protobuf" > [RESULT_DEVERSION] +# RUN_PARMS: wms_mvt_xprotobuf.mvt [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.1.0&REQUEST=GetMap&SRS=EPSG:3857&BBOX=-7514065.628545966,5009377.085697311,-6261721.357121638,6261721.357121639&WIDTH=256&HEIGHT=256&STYLES=&LAYERS=road&FORMAT=application/x-protobuf" > [RESULT_DEVERSION] +# RUN_PARMS: wms_mvt.mvt [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.1.0&REQUEST=GetMap&SRS=EPSG:3857&BBOX=-7514065.628545966,5009377.085697311,-6261721.357121638,6261721.357121639&WIDTH=256&HEIGHT=256&STYLES=&LAYERS=road&FORMAT=application/vnd.mapbox-vector-tile" > [RESULT_DEVERSION] + +# Test access with STYLES and FILTER parameters +# RUN_PARMS: wms_mvt_filtered.mvt [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.1.0&REQUEST=GetMap&SRS=EPSG:3857&BBOX=-7514065.628545966,5009377.085697311,-6261721.357121638,6261721.357121639&WIDTH=256&HEIGHT=256&STYLES=&LAYERS=road&FILTER=F_CODE67&FORMAT=application/vnd.mapbox-vector-tile" > [RESULT_DEVERSION] +# RUN_PARMS: wms_mvt_group.mvt [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.1.0&REQUEST=GetMap&SRS=EPSG:3857&BBOX=-7514065.628545966,5009377.085697311,-6261721.357121638,6261721.357121639&WIDTH=256&HEIGHT=256&STYLES=main&LAYERS=road2&FORMAT=application/vnd.mapbox-vector-tile" > [RESULT_DEVERSION] +# RUN_PARMS: wms_mvt_defaultgroup.mvt [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.1.0&REQUEST=GetMap&SRS=EPSG:3857&BBOX=-7514065.628545966,5009377.085697311,-6261721.357121638,6261721.357121639&WIDTH=256&HEIGHT=256&STYLES=&LAYERS=road2&FORMAT=application/vnd.mapbox-vector-tile" > [RESULT_DEVERSION] + MAP -NAME WMS_TEST +NAME WMS_MVT_TEST STATUS ON SIZE 400 300 -#EXTENT 2018000 -73300 3410396 647400 -#UNITS METERS EXTENT -67.5725 42 -58.9275 48.5 UNITS DD IMAGECOLOR 255 255 255 @@ -30,39 +35,15 @@ WEB METADATA "ows_updatesequence" "123" - "wms_title" "Test simple wms" + "wms_title" "Test simple MVT wms" "wms_onlineresource" "http://localhost/path/to/wms_simple?" "wms_srs" "EPSG:42304 EPSG:42101 EPSG:4269 EPSG:4326" - "ows_schemas_location" "http://schemas.opengis.net" - "ows_keywordlist" "ogc,wms,mapserver" - "ows_service_onlineresource" "http://www.mapserver.org/" - "ows_fees" "None" - "ows_accessconstraints" "None" - "ows_addresstype" "postal" - "ows_address" "123 SomeRoad Road" - "ows_city" "Toronto" - "ows_stateorprovince" "Ontario" - "ows_postcode" "xxx-xxx" - "ows_country" "Canada" - "ows_contactelectronicmailaddress" "tomkralidis@xxxxxxx.xxx" - "ows_contactvoicetelephone" "+xx-xxx-xxx-xxxx" - "ows_contactfacsimiletelephone" "+xx-xxx-xxx-xxxx" - "ows_contactperson" "Tom Kralidis" - "ows_contactorganization" "MapServer" - "ows_contactposition" "self" - - "ows_rootlayer_title" "My Layers" - "ows_rootlayer_abstract" "These are my layers" - "ows_rootlayer_keywordlist" "layers,list" - "ows_layerlimit" "1" "ows_enable_request" "*" - "wms_getmap_formatlist" "image/png,image/png; mode=24bit,image/jpeg,image/gif,image/png; mode=8bit,image/tiff,application/x-protobuf" END END PROJECTION "init=epsg:4326" - #"init=./data/epsg2:42304" END @@ -86,14 +67,63 @@ LAYER "init=./data/epsg2:42304" END - DUMP TRUE + CLASSITEM "Name_e" + CLASS + NAME "Roads" + STYLE + SYMBOL 0 + COLOR 220 0 0 + END + END +END # Layer + +# A road layer with WMS groups +LAYER + NAME road2 + DATA road + TEMPLATE "ttt" + METADATA + "wms_title" "road2" + "wms_description" "Roads of I.P.E." + "wms_srs" "EPSG:43204 EPSG:3857" + "gml_include_items" "all" + END + TYPE LINE + STATUS ON + PROJECTION + "init=./data/epsg2:42304" + END CLASSITEM "Name_e" + CLASSGROUP "all" + CLASS + GROUP "all" NAME "Roads" - SYMBOL 0 - COLOR 220 0 0 + STYLE + SYMBOL 0 + COLOR 0 0 0 + END END + + CLASS + GROUP "main" + NAME "Roads" + EXPRESSION ([F_CODE] = 67) + STYLE + SYMBOL 0 + COLOR 0 220 0 + END + END + CLASS + GROUP "other" + NAME "Roads" + EXPRESSION ([F_CODE] != 67) + STYLE + SYMBOL 0 + COLOR 220 0 0 + END + END END # Layer END # Map File diff --git a/msautotest/wxs/wms_nosld.map b/msautotest/wxs/wms_nosld.map index 1c2862b1fb..1e86308a1f 100644 --- a/msautotest/wxs/wms_nosld.map +++ b/msautotest/wxs/wms_nosld.map @@ -29,8 +29,8 @@ SYMBOLSET etc/symbols.sym FONTSET etc/fonts.txt OUTPUTFORMAT - NAME GDPNG - DRIVER "GD/PNG" + NAME png + DRIVER "AGG/PNG8" MIMETYPE "image/png" EXTENSION "png" END @@ -82,13 +82,14 @@ LAYER # "init=epsg:42304" END - DUMP TRUE CLASSITEM "Name_e" CLASS NAME "Province" - COLOR 200 255 0 - OUTLINECOLOR 120 120 120 + STYLE + COLOR 200 255 0 + OUTLINECOLOR 120 120 120 + END END END # Layer @@ -108,14 +109,16 @@ LAYER # "init=epsg:42304" END - DUMP TRUE LabelItem "Name" CLASSITEM "Capital" CLASS EXPRESSION /./ - SYMBOL 2 - SIZE 8 + STYLE + SYMBOL 2 + SIZE 8 + COLOR 0 0 0 + END NAME "Cities" LABEL COLOR 0 0 0 @@ -126,7 +129,6 @@ LAYER PARTIALS FALSE OUTLINECOLOR 255 255 255 END - COLOR 0 0 0 END END # Layer @@ -145,13 +147,13 @@ LAYER # "init=epsg:42304" END - DUMP TRUE - CLASSITEM "Name_e" CLASS NAME "Roads" - SYMBOL 0 - COLOR 220 0 0 + STYLE + SYMBOL 0 + COLOR 220 0 0 + END END END # Layer diff --git a/msautotest/wxs/wms_nosld_postgis.map b/msautotest/wxs/wms_nosld_postgis.map index 54266638b7..f9492b9108 100644 --- a/msautotest/wxs/wms_nosld_postgis.map +++ b/msautotest/wxs/wms_nosld_postgis.map @@ -29,8 +29,8 @@ SYMBOLSET etc/symbols.sym FONTSET etc/fonts.txt OUTPUTFORMAT - NAME GDPNG - DRIVER "GD/PNG" + NAME png + DRIVER "AGG/PNG8" MIMETYPE "image/png" EXTENSION "png" END @@ -83,13 +83,14 @@ LAYER # "init=epsg:42304" END - DUMP TRUE CLASSITEM "name_e" CLASS NAME "Province" - COLOR 200 255 0 - OUTLINECOLOR 120 120 120 + STYLE + COLOR 200 255 0 + OUTLINECOLOR 120 120 120 + END END END # Layer @@ -110,14 +111,16 @@ LAYER # "init=epsg:42304" END - DUMP TRUE LabelItem "name" CLASSITEM "capital" CLASS EXPRESSION /./ - SYMBOL 2 - SIZE 8 + STYLE + SYMBOL 2 + SIZE 8 + COLOR 0 0 0 + END NAME "Cities" LABEL COLOR 0 0 0 @@ -128,7 +131,6 @@ LAYER PARTIALS FALSE OUTLINECOLOR 255 255 255 END - COLOR 0 0 0 END END # Layer @@ -148,13 +150,13 @@ LAYER # "init=epsg:42304" END - DUMP TRUE - CLASSITEM "name_e" CLASS NAME "Roads" - SYMBOL 0 - COLOR 220 0 0 + STYLE + SYMBOL 0 + COLOR 220 0 0 + END END END # Layer diff --git a/msautotest/wxs/wms_polar_stereo.map b/msautotest/wxs/wms_polar_stereo.map index 5f3cd11d54..3069713144 100644 --- a/msautotest/wxs/wms_polar_stereo.map +++ b/msautotest/wxs/wms_polar_stereo.map @@ -19,15 +19,6 @@ PROJECTION "init=epsg:4326" END -IMAGETYPE png8_t - -OUTPUTFORMAT - NAME png8_t - DRIVER "GD/PNG" - IMAGEMODE PC256 - TRANSPARENT OFF -END - WEB METADATA "ows_enable_request" "*" diff --git a/msautotest/wxs/wms_postgis_boxtoken.map b/msautotest/wxs/wms_postgis_boxtoken.map new file mode 100644 index 0000000000..0a01fb95e4 --- /dev/null +++ b/msautotest/wxs/wms_postgis_boxtoken.map @@ -0,0 +1,101 @@ +# +# Test the !BOX! token trick, through WMS +# +# REQUIRES: INPUT=POSTGIS INPUT=GDAL OUTPUT=PNG SUPPORTS=WMS +# +# Draw a map with a single polygon layer. BBOX is set to keep image square +# RUN_PARMS: wms_get_map_polygon_postgis_boxtoken.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.1.0&REQUEST=GetMap&SRS=EPSG:4326&BBOX=-67.5725,42.3683,-58.9275,48.13&FORMAT=image/png;%20mode=8bit&WIDTH=300&HEIGHT=200&STYLES=&LAYERS=road" > [RESULT_DEMIME] +# +MAP + +NAME WMS_TEST +STATUS ON +SIZE 400 300 +#EXTENT 2018000 -73300 3410396 647400 +#UNITS METERS +EXTENT -67.5725 42 -58.9275 48.5 +UNITS DD +IMAGECOLOR 255 255 255 +SHAPEPATH ./data +SYMBOLSET etc/symbols.sym +FONTSET etc/fonts.txt + + +# +# Start of web interface definition +# +WEB + + IMAGEPATH "/tmp/ms_tmp/" + IMAGEURL "/ms_tmp/" + + METADATA + "ows_updatesequence" "123" + "wms_title" "Test simple wms" + "wms_onlineresource" "http://localhost/path/to/wms_simple?" + "ows_srs" "EPSG:42304 EPSG:42101 EPSG:4269 EPSG:4326" + "ows_schemas_location" "http://schemas.opengis.net" + "ows_keywordlist" "ogc,wms,mapserver" + "ows_service_onlineresource" "https://mapserver.org/" + "ows_fees" "None" + "ows_accessconstraints" "None" + "ows_addresstype" "postal" + "ows_address" "123 SomeRoad Road" + "ows_city" "Lunenburg" + "ows_stateorprovince" "Nova Scotia" + "ows_postcode" "xxx-xxx" + "ows_country" "Canada" + "ows_contactelectronicmailaddress" "jmckenna@xxxxxxx.xxx" + "ows_contactvoicetelephone" "+xx-xxx-xxx-xxxx" + "ows_contactfacsimiletelephone" "+xx-xxx-xxx-xxxx" + "ows_contactperson" "Jeff McKenna" + "ows_contactorganization" "MapServer" + "ows_contactposition" "self" + + "ows_rootlayer_title" "My Layers" + "ows_rootlayer_abstract" "These are my layers" + "ows_rootlayer_keywordlist" "layers,list" + "ows_layerlimit" "1" + "ows_enable_request" "*" + "wms_getmap_formatlist" "image/png,image/png; mode=24bit,image/jpeg,image/gif,image/png; mode=8bit,image/tiff" + END +END + +PROJECTION + "init=epsg:4326" + #"init=./data/epsg2:42304" +END + + +# +# Start of layer definitions +# + +LAYER + NAME road + INCLUDE "postgis.include" + DATA "the_geom from (select * from road WHERE ST_Intersects(the_geom, !BOX!)) as foo using unique gid using srid=3978" + TEMPLATE "ttt" + METADATA + "wms_title" "road" + "wms_description" "Roads of I.P.E." + "wms_srs" "EPSG:43204" + "gml_include_items" "all" + END + TYPE LINE + STATUS ON + PROJECTION + "init=epsg:3978" + END + + CLASSITEM "name_e" + CLASS + NAME "Roads" + STYLE + SYMBOL 0 + COLOR 220 0 0 + END + END +END # Layer + +END # Map File diff --git a/msautotest/wxs/wms_raster.map b/msautotest/wxs/wms_raster.map index 7b7fd7b41d..9fd8383a42 100644 --- a/msautotest/wxs/wms_raster.map +++ b/msautotest/wxs/wms_raster.map @@ -31,15 +31,7 @@ IMAGECOLOR 255 255 255 SHAPEPATH ./data SYMBOLSET etc/symbols.sym FONTSET etc/fonts.txt - - -OUTPUTFORMAT - NAME GDPNG - DRIVER "GD/PNG" - MIMETYPE "image/png" - EXTENSION "png" -END - +DEBUG 1 # # Start of web interface definition @@ -102,15 +94,12 @@ LAYER "init=epsg:32611" END - DUMP TRUE - END # Layer LAYER NAME grey TYPE raster STATUS ON - DUMP TRUE TILEINDEX "wcs_index.shp" TILEITEM "location" diff --git a/msautotest/wxs/wms_raster_query.map b/msautotest/wxs/wms_raster_query.map new file mode 100644 index 0000000000..0f6f6dd2d0 --- /dev/null +++ b/msautotest/wxs/wms_raster_query.map @@ -0,0 +1,53 @@ +# +# Test Raster Queries using different output formats and templates +# +# REQUIRES: INPUT=GDAL SUPPORTS=WMS + +# RUN_PARMS: wms_raster_query.json [MAPSERV] QUERY_STRING="map=[MAPFILE]&&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetFeatureInfo&FORMAT=image%2Fpng&TRANSPARENT=true&QUERY_LAYERS=raster&LAYERS=raster&STYLES=&FILTER=&INFO_FORMAT=geojson&I=50&J=50&CRS=EPSG%3A4326&WIDTH=101&HEIGHT=101&BBOX=48.79202566966527%2C15.757350496548119%2C49.16611202635983%2C16.13143685324268" > [RESULT_DEVERSION] +# RUN_PARMS: wms_raster_query.html [MAPSERV] QUERY_STRING="map=[MAPFILE]&&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetFeatureInfo&FORMAT=image%2Fpng&TRANSPARENT=true&QUERY_LAYERS=raster&LAYERS=raster&STYLES=&FILTER=&INFO_FORMAT=text/html&I=50&J=50&CRS=EPSG%3A4326&WIDTH=101&HEIGHT=101&BBOX=48.79202566966527%2C15.757350496548119%2C49.16611202635983%2C16.13143685324268" > [RESULT_DEVERSION] + +MAP + NAME "TEST" + SIZE 105 61 + EXTENT 14.4702712 47.8188382 18.0111282 49.8911432 + OUTPUTFORMAT + NAME "GEOTIFF_8" + DRIVER "GDAL/GTiff" + MIMETYPE "image/tiff" + IMAGEMODE BYTE + EXTENSION "tif" + END + OUTPUTFORMAT + NAME "geojson" + DRIVER "OGR/GEOJSON" + MIMETYPE "application/json; subtype=geojson; charset=utf-8" + FORMATOPTION "FORM=SIMPLE" + FORMATOPTION "STORAGE=memory" + FORMATOPTION "LCO:NATIVE_MEDIA_TYPE=application/vnd.geo+json" + END + PROJECTION + "init=epsg:4326" + END + WEB + METADATA + "ows_enable_request" "*" + "wms_getfeatureinfo_formatlist" "text/html,geojson" + END + END + #METADATA + #WEB + LAYER + NAME "raster" + TYPE RASTER + STATUS ON + DATA "data/multiband.tif" + TEMPLATE "templates/raster_query.html" + PROJECTION + "init=epsg:4326" + END + METADATA + "gml_include_items" "all" + "gml_types" "auto" + END + END +END \ No newline at end of file diff --git a/msautotest/wxs/wms_raster_query_nan.map b/msautotest/wxs/wms_raster_query_nan.map new file mode 100644 index 0000000000..b2062e38e4 --- /dev/null +++ b/msautotest/wxs/wms_raster_query_nan.map @@ -0,0 +1,49 @@ +# +# Test Raster Queries with NaN values and classes +# +# REQUIRES: INPUT=GDAL SUPPORTS=WMS + +# RUN_PARMS: wms_raster_query_nan.txt [MAPSERV] QUERY_STRING="map=[MAPFILE]&&exceptions=XML&version=1.3.0&feature_count=101&styles=&service=WMS&request=GetFeatureInfo&layers=test&bbox=3757032.814272985%2C-626172.1357121654%2C4383204.9499851465%2C0&width=256&height=256&crs=EPSG%3A3857&query_layers=test&info_format=text%2Fplain&i=43&j=168" > [RESULT_DEMIME] + +MAP + NAME 'RASTER_NAN_QUERY' + SIZE 800 800 + UNITS METERS + EXTENT 33.89333673234122 -4.676208154654717 40.77100565298233 2.661891659578913 + PROJECTION + 'epsg:4326' + END + WEB + METADATA + 'ows_enable_request' '*' + 'ows_srs' 'EPSG:4326 EPSG:3857 EPSG:54009 EPSG:54012' + END + END + LAYER + NAME 'test' + TYPE RASTER + DATA "data/nan.tif" + PROJECTION + 'EPSG:32737' + END + EXTENT -67111.201 9481062.486 696888.799 10294362.486 + STATUS ON + TEMPLATE 'ttt' + CLASS + NAME '0 - 731.2' + GROUP 'Default' + EXPRESSION ( ( [pixel] >= 0 ) AND ( [pixel] <= 731.2 ) ) + STYLE + COLOR '#56a1b3' + END + END + CLASS + NAME '731.2 - 7012' + GROUP 'Default' + EXPRESSION ( ( [pixel] >= 731.2 ) AND ( [pixel] <= 7012 ) ) + STYLE + COLOR '#d7191c' + END + END + END +END \ No newline at end of file diff --git a/msautotest/wxs/wms_simple.map b/msautotest/wxs/wms_simple.map index ec0e1da817..a2398164aa 100644 --- a/msautotest/wxs/wms_simple.map +++ b/msautotest/wxs/wms_simple.map @@ -3,12 +3,18 @@ # # REQUIRES: INPUT=GDAL OUTPUT=PNG SUPPORTS=WMS # +# RUN_PARMS: wms_invalid_request_without_500_status.txt [MAPSERV] QUERY_STRING="map=i_do_not_exist.map&SERVICE=WMS" > [RESULT] +# RUN_PARMS: wms_invalid_request_with_500_status.txt MS_WMS_ERROR_STATUS_CODE=ON [MAPSERV] QUERY_STRING="map=i_do_not_exist.map&SERVICE=WMS" > [RESULT] +# RUN_PARMS: wms_invalid_request_with_400_status.txt MS_WMS_ERROR_STATUS_CODE=ON [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS" > [RESULT] # -# Capabilities (return latest supported version by default +# +# Capabilities (return latest supported version by default (1.3.0) # # RUN_PARMS: wms_cap_latestversion.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&REQUEST=GetCapabilities" > [RESULT_DEVERSION] # # RUN_PARMS: wms_cap.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetCapabilities" > [RESULT_DEVERSION] +# RUN_PARMS: wms_cap110.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.1.0&REQUEST=GetCapabilities" > [RESULT_DEVERSION] +# RUN_PARMS: wms_cap100.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.0.0&REQUEST=GetCapabilities" > [RESULT_DEVERSION] # # version exception # RUN_PARMS: wms_version_exception.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1" > [RESULT] @@ -64,8 +70,14 @@ # GetMap exception (number of layers < LayerLimit) # RUN_PARMS: wms_getmap130layerlimitexception.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMap&SRS=EPSG%3A4326&BBOX=35.18749999863387,-141.0000000021858,90.81250000136613,-51.99999999781419&WIDTH=560&HEIGHT=350&LAYERS=road,road&STYLES=&FORMAT=image%2Fpng&BGCOLOR=0xFFFFFF&TRANSPARENT=FALSE&EXCEPTIONS=XML" > [RESULT] # +# GetMap (non-standard compliant parameter value for TRANSPARENT evaluates to FALSE) +# RUN_PARMS: wms_getmap130.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMap&CRS=EPSG%3A4326&BBOX=35.18749999863387,-141.0000000021858,90.81250000136613,-51.99999999781419&WIDTH=560&HEIGHT=350&LAYERS=road&STYLES=&FORMAT=image%2Fpng&BGCOLOR=0xFFFFFF&TRANSPARENT=zzzz&EXCEPTIONS=INIMAGE" > [RESULT_DEMIME] +# # GetFeatureInfo # RUN_PARMS: wms_getfeatureinfo130.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetFeatureInfo&CRS=EPSG%3A4326&BBOX=35.18749999863387,-141.0000000021858,90.81250000136613,-51.99999999781419&WIDTH=560&HEIGHT=350&LAYERS=road&STYLES=&FORMAT=image%2Fpng&BGCOLOR=0xFFFFFF&TRANSPARENT=FALSE&QUERY_LAYERS=road&INFO_FORMAT=application%2Fvnd.ogc.gml&I=483&J=291&FEATURE_COUNT=5" > [RESULT] + +# RUN_PARMS: wms_getfeatureinfo130_empty.txt [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetFeatureInfo&CRS=EPSG%3A4326&BBOX=35.18749999863387,-141.0000000021858,90.81250000136613,-51.99999999781419&WIDTH=560&HEIGHT=350&LAYERS=road&STYLES=&FORMAT=image%2Fpng&BGCOLOR=0xFFFFFF&TRANSPARENT=FALSE&QUERY_LAYERS=road&INFO_FORMAT=OTHER_GFI_RESULT&I=1&J=291&FEATURE_COUNT=5" > [RESULT] + # # DescribeLayer # RUN_PARMS: wms_describelayer130.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=DescribeLayer&layers=road&sld_version=1.1.0" > [RESULT] @@ -88,10 +100,9 @@ FONTSET etc/fonts.txt OUTPUTFORMAT - NAME GDPNG - DRIVER "GD/PNG" + NAME png + DRIVER "AGG/PNG8" MIMETYPE "image/png" -# IMAGEMODE RGB EXTENSION "png" END @@ -103,6 +114,7 @@ WEB IMAGEPATH "/tmp/ms_tmp/" IMAGEURL "/ms_tmp/" + EMPTY "https://example.com/empty.html" METADATA "ows_updatesequence" "123" @@ -133,6 +145,7 @@ WEB "ows_layerlimit" "1" "ows_enable_request" "*" "wms_getmap_formatlist" "image/png,image/png; mode=24bit,image/jpeg,image/gif,image/png; mode=8bit,image/tiff" + "wms_getfeatureinfo_formatlist" "application/vnd.ogc.gml,OTHER_GFI_RESULT" END END @@ -162,13 +175,13 @@ LAYER "init=./data/epsg2:42304" END - DUMP TRUE - CLASSITEM "Name_e" CLASS NAME "Roads" - SYMBOL 0 - COLOR 220 0 0 + STYLE + SYMBOL 0 + COLOR 220 0 0 + END END END # Layer diff --git a/msautotest/wxs/wms_simple_kml.map b/msautotest/wxs/wms_simple_kml.map index 9d5ed66624..5b1a65d2b3 100644 --- a/msautotest/wxs/wms_simple_kml.map +++ b/msautotest/wxs/wms_simple_kml.map @@ -9,6 +9,8 @@ # Same with KMZ output # RUN_PARMS: wms_get_map_polygon.kmz [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.1.0&REQUEST=GetMap&SRS=EPSG:4326&BBOX=-67.5725,42.3683,-58.9275,48.13&FORMAT=kmz&WIDTH=300&HEIGHT=200&STYLES=&LAYERS=road" > [RESULT_DEMIME] +# RUN_PARMS: wms_simple_kml_label.kml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMap&CRS=EPSG%3A4326&BBOX=40,-70,50,-60&WIDTH=400&HEIGHT=400&LAYERS=popplace&STYLES=&FORMAT=kml" > [RESULT_DEMIME] + MAP NAME WMS_TEST @@ -23,6 +25,17 @@ SHAPEPATH ./data SYMBOLSET etc/symbols.sym FONTSET etc/fonts.txt +# override the default settings to add TIMESTAMP=0 +# so output remains the same on each run +OUTPUTFORMAT + NAME "kmz" + DRIVER KMZ + MIMETYPE "application/vnd.google-earth.kmz" + IMAGEMODE RGB + EXTENSION "kmz" + FORMATOPTION "TIMESTAMP=0" +END + # # Start of web interface definition # @@ -88,13 +101,45 @@ LAYER "init=./data/epsg2:42304" END - DUMP TRUE - CLASSITEM "Name_e" CLASS NAME "Roads" - SYMBOL 0 - COLOR 220 0 0 + STYLE + SYMBOL 0 + COLOR 220 0 0 + END + END +END # Layer + +LAYER + NAME popplace + DATA popplace + METADATA + "wms_title" "popplace" + "wms_description" "Cities of I.P.E." + "wms_result_fields" "NAME" + "gml_NAME_alias" "NAME_ALIAS" + END + TYPE POINT + STATUS ON + PROJECTION + "init=epsg:3978" + END + + LabelItem "Name" + CLASSITEM "Capital" + + CLASS + NAME "Cities" + LABEL + COLOR 0 0 0 + FONT Vera + TYPE truetype + SIZE 8 + POSITION AUTO + PARTIALS FALSE + OUTLINECOLOR 255 255 255 + END END END # Layer diff --git a/msautotest/wxs/wms_simple_no_onlineresource.map b/msautotest/wxs/wms_simple_no_onlineresource.map new file mode 100644 index 0000000000..b9c7625aae --- /dev/null +++ b/msautotest/wxs/wms_simple_no_onlineresource.map @@ -0,0 +1,81 @@ +# +# Test WMS + +# SKIP_WHOLE_FILE: + +MAP + +NAME WMS_TEST +STATUS ON +SIZE 400 300 +#EXTENT 2018000 -73300 3410396 647400 +#UNITS METERS +EXTENT -67.5725 42 -58.9275 48.5 +UNITS DD +IMAGECOLOR 255 255 255 +SHAPEPATH ./data +SYMBOLSET etc/symbols.sym +FONTSET etc/fonts.txt + + +OUTPUTFORMAT + NAME png + DRIVER "AGG/PNG8" + MIMETYPE "image/png" + EXTENSION "png" +END + + +# +# Start of web interface definition +# +WEB + + IMAGEPATH "/tmp/ms_tmp/" + IMAGEURL "/ms_tmp/" + EMPTY "https://example.com/empty.html" + + METADATA + "wms_title" "test" + "wms_srs" "EPSG:42304 EPSG:4326" + "ows_enable_request" "*" + END +END + +PROJECTION + "init=epsg:4326" + #"init=./data/epsg2:42304" +END + + +# +# Start of layer definitions +# + +LAYER + NAME road + DATA road + TEMPLATE "ttt" + METADATA + "wms_title" "road" + "wms_description" "Roads of I.P.E." + "wms_srs" "EPSG:43204" + "gml_include_items" "all" + END + TYPE LINE + STATUS ON + PROJECTION + "init=./data/epsg2:42304" + END + + CLASSITEM "Name_e" + CLASS + NAME "Roads" + STYLE + SYMBOL 0 + COLOR 220 0 0 + END + END +END # Layer + +END # Map File diff --git a/msautotest/wxs/wms_simple_postgis.map b/msautotest/wxs/wms_simple_postgis.map index 7f66de4bcc..9d8d067e0e 100644 --- a/msautotest/wxs/wms_simple_postgis.map +++ b/msautotest/wxs/wms_simple_postgis.map @@ -79,10 +79,9 @@ FONTSET etc/fonts.txt OUTPUTFORMAT - NAME GDPNG - DRIVER "GD/PNG" + NAME png + DRIVER "AGG/PNG8" MIMETYPE "image/png" -# IMAGEMODE RGB EXTENSION "png" END @@ -154,13 +153,13 @@ LAYER "init=epsg:3978" END - DUMP TRUE - CLASSITEM "name_e" CLASS NAME "Roads" - SYMBOL 0 - COLOR 220 0 0 + STYLE + SYMBOL 0 + COLOR 220 0 0 + END END END # Layer diff --git a/msautotest/wxs/wms_simple_strict_compliance.map b/msautotest/wxs/wms_simple_strict_compliance.map new file mode 100644 index 0000000000..d7a4160eb0 --- /dev/null +++ b/msautotest/wxs/wms_simple_strict_compliance.map @@ -0,0 +1,119 @@ +# +# Test WMS, check for strict standard compliance +# +# REQUIRES: INPUT=GDAL OUTPUT=PNG SUPPORTS=WMS +# +# GetMap +# RUN_PARMS: wms_getmap130.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMap&CRS=EPSG%3A4326&BBOX=35.18749999863387,-141.0000000021858,90.81250000136613,-51.99999999781419&WIDTH=560&HEIGHT=350&LAYERS=road&STYLES=&FORMAT=image%2Fpng&BGCOLOR=0xFFFFFF&TRANSPARENT=FALSE&EXCEPTIONS=INIMAGE" > [RESULT_DEMIME] +# +# GetMap exception (wrong parameter value for TRANSPARENT) +# RUN_PARMS: wms_getmap130transparentinvalidexception.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMap&CRS=EPSG%3A4326&BBOX=35.18749999863387,-141.0000000021858,90.81250000136613,-51.99999999781419&WIDTH=560&HEIGHT=350&LAYERS=road&STYLES=&FORMAT=image%2Fpng&BGCOLOR=0xFFFFFF&TRANSPARENT=zzzz&EXCEPTIONS=XML" > [RESULT] +# +# GetMap exception (TRANSPARENT parameters are case sensitive) +# RUN_PARMS: wms_getmap130transparentinvalidexception.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMap&CRS=EPSG%3A4326&BBOX=35.18749999863387,-141.0000000021858,90.81250000136613,-51.99999999781419&WIDTH=560&HEIGHT=350&LAYERS=road&STYLES=&FORMAT=image%2Fpng&BGCOLOR=0xFFFFFF&TRANSPARENT=true&EXCEPTIONS=XML" > [RESULT] +# +MAP + +NAME WMS_TEST +STATUS ON +SIZE 400 300 +#EXTENT 2018000 -73300 3410396 647400 +#UNITS METERS +EXTENT -67.5725 42 -58.9275 48.5 +UNITS DD +IMAGECOLOR 255 255 255 +SHAPEPATH ./data +SYMBOLSET etc/symbols.sym +FONTSET etc/fonts.txt + + +OUTPUTFORMAT + NAME png + DRIVER "AGG/PNG8" + MIMETYPE "image/png" + EXTENSION "png" +END + + +# +# Start of web interface definition +# +WEB + + IMAGEPATH "/tmp/ms_tmp/" + IMAGEURL "/ms_tmp/" + EMPTY "https://example.com/empty.html" + + METADATA + "ows_updatesequence" "123" + "wms_title" "Test simple wms" + "wms_onlineresource" "http://localhost/path/to/wms_simple?" + "wms_srs" "EPSG:42304 EPSG:42101 EPSG:4269 EPSG:4326" + "ows_schemas_location" "http://schemas.opengis.net" + "ows_keywordlist" "ogc,wms,mapserver" + "ows_service_onlineresource" "http://www.mapserver.org/" + "ows_fees" "None" + "ows_accessconstraints" "None" + "ows_addresstype" "postal" + "ows_address" "123 SomeRoad Road" + "ows_city" "Toronto" + "ows_stateorprovince" "Ontario" + "ows_postcode" "xxx-xxx" + "ows_country" "Canada" + "ows_contactelectronicmailaddress" "tomkralidis@xxxxxxx.xxx" + "ows_contactvoicetelephone" "+xx-xxx-xxx-xxxx" + "ows_contactfacsimiletelephone" "+xx-xxx-xxx-xxxx" + "ows_contactperson" "Tom Kralidis" + "ows_contactorganization" "MapServer" + "ows_contactposition" "self" + + "ows_rootlayer_title" "My Layers" + "ows_rootlayer_abstract" "These are my layers" + "ows_rootlayer_keywordlist" "layers,list" + "ows_layerlimit" "1" + "ows_enable_request" "*" + + "wms_getmap_formatlist" "image/png,image/png; mode=24bit,image/jpeg,image/gif,image/png; mode=8bit,image/tiff" + "wms_getfeatureinfo_formatlist" "application/vnd.ogc.gml,OTHER_GFI_RESULT" + + "wms_compliance_mode" "true" + END +END + +PROJECTION + "init=epsg:4326" + #"init=./data/epsg2:42304" +END + + +# +# Start of layer definitions +# + +LAYER + NAME road + DATA road + TEMPLATE "ttt" + METADATA + "wms_title" "road" + "wms_description" "Roads of I.P.E." + "wms_srs" "EPSG:43204" + "gml_include_items" "all" + END + TYPE LINE + STATUS ON + PROJECTION + "init=./data/epsg2:42304" + END + + CLASSITEM "Name_e" + CLASS + NAME "Roads" + STYLE + SYMBOL 0 + COLOR 220 0 0 + END + END +END # Layer + +END # Map File diff --git a/msautotest/wxs/wms_sld.map b/msautotest/wxs/wms_sld.map index 4092f9562d..65c5ea9688 100644 --- a/msautotest/wxs/wms_sld.map +++ b/msautotest/wxs/wms_sld.map @@ -25,6 +25,9 @@ # other roads. # RUN_PARMS: wms_get_map_line_elsefilter_sld.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.1.0&REQUEST=GetMap&SRS=EPSG:4326&BBOX=-68.125,42,-58.375,48.5&FORMAT=image/png; mode=24bit&WIDTH=300&HEIGHT=200&STYLES=&LAYERS=road&sld_body=roadxxxROAD_ID900center-line#0000ff2.0center-line#ff00002.0" > [RESULT_DEMIME] # +# Strictly speaking we should reject this, as a Rule without a symbolizer is invalid. For now we just check we don't crash +# RUN_PARMS: wms_get_map_line_elsefilter_no_symbolizer_sld.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.1.0&REQUEST=GetMap&SRS=EPSG:4326&BBOX=-68.125,42,-58.375,48.5&FORMAT=image/png; mode=24bit&WIDTH=300&HEIGHT=200&STYLES=&LAYERS=road&sld_body=roadxxx" > [RESULT_DEMIME] +# # Generate map image with polygon drawn as a simple solid fill (province) # RUN_PARMS: wms_get_map_polygon_fill_sld.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.1.0&REQUEST=GetMap&SRS=EPSG:4326&BBOX=-68.125,42,-58.375,48.5&FORMAT=image/png; mode=24bit&WIDTH=300&HEIGHT=200&STYLES=&LAYERS=province&sld_body=Provincexxxthe_area#ff0000" > [RESULT_DEMIME] # @@ -39,6 +42,7 @@ # # Generate map image with symbols drawn as filled mark symbol # RUN_PARMS: wms_get_map_mark_symbol_sld.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.1.0&REQUEST=GetMap&SRS=EPSG:4326&BBOX=-68.125,42,-58.375,48.5&FORMAT=image/png; mode=24bit&WIDTH=300&HEIGHT=200&STYLES=&LAYERS=popplace&sld_body=popplacexxxlocatedAtstar#ff000010.0" > [RESULT_DEMIME] +# RUN_PARMS: wms_get_map_mark_symbol_sld_legend.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.1.0&REQUEST=GetLegendGraphic&SRS=EPSG:4326&FORMAT=image/png; mode=24bit&LAYER=popplace&sld_body=popplacexxxlocatedAtstar#ff000010.0" > [RESULT_DEMIME] # RUN_PARMS: wms_get_map_repeated_layer_sld.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.1.0&REQUEST=GetMap&SRS=EPSG:4326&BBOX=-68.125,42,-58.375,48.5&FORMAT=image/png; mode=24bit&WIDTH=300&HEIGHT=200&STYLES=&LAYERS=popplace&sld_body=popplacexxxlocatedAtcircle#00000014.0popplacexxxlocatedAtstar#ff000010.0" > [RESULT_DEMIME] # RUN_PARMS: wms_get_map_repeated_layer_ext_sld.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.1.0&REQUEST=GetMap&SRS=EPSG:4326&BBOX=-68.125,42,-58.375,48.5&FORMAT=image/png; mode=24bit&WIDTH=300&HEIGHT=200&STYLES=&LAYERS=popplace&sld=http://localhost:8000/wxs/etc/repeat.sld" > [RESULT_DEMIME] # RUN_PARMS: wms_get_map_ext_sld_404.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.1.0&REQUEST=GetMap&SRS=EPSG:4326&BBOX=-68.125,42,-58.375,48.5&FORMAT=image/png; mode=24bit&WIDTH=300&HEIGHT=200&STYLES=&LAYERS=popplace&sld=http://localhost:8000/wxs/etc/repeat.sld.notfound" > [RESULT_DEMIME] @@ -155,13 +159,14 @@ LAYER "init=epsg:3978" END - DUMP TRUE CLASSITEM "Name_e" CLASS NAME "Province" - COLOR 200 255 0 - OUTLINECOLOR 120 120 120 + STYLE + COLOR 200 255 0 + OUTLINECOLOR 120 120 120 + END END END # Layer @@ -181,14 +186,16 @@ LAYER "init=epsg:3978" END - DUMP TRUE LabelItem "Name" CLASSITEM "Capital" CLASS EXPRESSION /./ - SYMBOL 2 - SIZE 8 + STYLE + SYMBOL 2 + SIZE 8 + COLOR 0 0 0 + END NAME "Cities" LABEL COLOR 0 0 0 @@ -199,7 +206,6 @@ LAYER PARTIALS FALSE OUTLINECOLOR 255 255 255 END - COLOR 0 0 0 END END # Layer @@ -217,13 +223,13 @@ LAYER "init=epsg:3978" END - DUMP TRUE - CLASSITEM "Name_e" CLASS NAME "Roads" - SYMBOL 0 - COLOR 220 0 0 + STYLE + SYMBOL 0 + COLOR 220 0 0 + END END END # Layer @@ -241,15 +247,12 @@ LAYER "init=epsg:3978" END - DUMP TRUE - CLASSITEM "Name_e" CLASSGROUP 'style_red' CLASS GROUP 'style_red' NAME "Roads" STYLE - COLOR 220 0 0 WIDTH 16 END @@ -259,7 +262,6 @@ LAYER GROUP 'style_green' NAME "Roads" STYLE - COLOR 0 220 0 WIDTH 8 END @@ -269,7 +271,6 @@ LAYER GROUP 'style_blue' NAME "Roads" STYLE - COLOR 0 0 220 WIDTH 2 END diff --git a/msautotest/wxs/wms_sld2.map b/msautotest/wxs/wms_sld2.map index 5556fac0b1..75308ddb8e 100644 --- a/msautotest/wxs/wms_sld2.map +++ b/msautotest/wxs/wms_sld2.map @@ -60,13 +60,14 @@ LAYER "init=epsg:3978" END - DUMP TRUE CLASSITEM "Name_e" CLASS NAME "Province" - COLOR 200 255 0 - OUTLINECOLOR 120 120 120 + STYLE + COLOR 200 255 0 + OUTLINECOLOR 120 120 120 + END END END # Layer @@ -86,14 +87,16 @@ LAYER "init=epsg:3978" END - DUMP TRUE LabelItem "Name" CLASSITEM "Capital" CLASS EXPRESSION /./ - SYMBOL 2 - SIZE 8 + STYLE + SYMBOL 2 + SIZE 8 + COLOR 0 0 0 + END NAME "Cities" LABEL COLOR 0 0 0 @@ -104,7 +107,6 @@ LAYER PARTIALS FALSE OUTLINECOLOR 255 255 255 END - COLOR 0 0 0 END END # Layer @@ -122,13 +124,13 @@ LAYER "init=epsg:3978" END - DUMP TRUE - CLASSITEM "Name_e" CLASS NAME "Roads" - SYMBOL 0 - COLOR 220 0 0 + STYLE + SYMBOL 0 + COLOR 220 0 0 + END END END # Layer @@ -146,8 +148,6 @@ LAYER "init=epsg:3978" END - DUMP TRUE - CLASSITEM "Name_e" CLASSGROUP 'style_red' CLASS diff --git a/msautotest/wxs/wms_sld_postgis.map b/msautotest/wxs/wms_sld_postgis.map index aa11a9544b..91b86c4be9 100644 --- a/msautotest/wxs/wms_sld_postgis.map +++ b/msautotest/wxs/wms_sld_postgis.map @@ -170,13 +170,14 @@ LAYER "init=epsg:3978" END - DUMP TRUE CLASSITEM "name_e" CLASS NAME "Province" - COLOR 200 255 0 - OUTLINECOLOR 120 120 120 + STYLE + COLOR 200 255 0 + OUTLINECOLOR 120 120 120 + END END END # Layer @@ -197,14 +198,16 @@ LAYER "init=epsg:3978" END - DUMP TRUE LabelItem "name" CLASSITEM "capital" CLASS EXPRESSION /./ - SYMBOL 2 - SIZE 8 + STYLE + SYMBOL 2 + SIZE 8 + COLOR 0 0 0 + END NAME "Cities" LABEL COLOR 0 0 0 @@ -215,7 +218,6 @@ LAYER PARTIALS FALSE OUTLINECOLOR 255 255 255 END - COLOR 0 0 0 END END # Layer @@ -234,13 +236,13 @@ LAYER "init=epsg:3978" END - DUMP TRUE - CLASSITEM "name_e" CLASS NAME "Roads" - SYMBOL 0 - COLOR 220 0 0 + STYLE + SYMBOL 0 + COLOR 220 0 0 + END END END # Layer @@ -260,8 +262,6 @@ LAYER PROJECTION "init=epsg:3978" END - - DUMP TRUE END # Layer @@ -279,15 +279,12 @@ LAYER "init=epsg:3978" END - DUMP TRUE - CLASSITEM "name_e" CLASSGROUP 'style_red' CLASS GROUP 'style_red' NAME "Roads" STYLE - COLOR 220 0 0 WIDTH 16 END @@ -297,7 +294,6 @@ LAYER GROUP 'style_green' NAME "Roads" STYLE - COLOR 0 220 0 WIDTH 8 END @@ -307,7 +303,6 @@ LAYER GROUP 'style_blue' NAME "Roads" STYLE - COLOR 0 0 220 WIDTH 2 END diff --git a/msautotest/wxs/wms_sld_proj.map b/msautotest/wxs/wms_sld_proj.map index 659d94a954..aa73ec90aa 100644 --- a/msautotest/wxs/wms_sld_proj.map +++ b/msautotest/wxs/wms_sld_proj.map @@ -70,13 +70,14 @@ LAYER "init=epsg:3978" END - DUMP TRUE CLASSITEM "Name_e" CLASS NAME "Province" - COLOR 200 255 0 - OUTLINECOLOR 120 120 120 + STYLE + COLOR 200 255 0 + OUTLINECOLOR 120 120 120 + END END END # Layer @@ -96,14 +97,16 @@ LAYER "init=epsg:3978" END - DUMP TRUE LabelItem "Name" CLASSITEM "Capital" CLASS EXPRESSION /./ - SYMBOL 2 - SIZE 8 + STYLE + SYMBOL 2 + SIZE 8 + COLOR 0 0 0 + END NAME "Cities" LABEL COLOR 0 0 0 @@ -114,7 +117,6 @@ LAYER PARTIALS FALSE OUTLINECOLOR 255 255 255 END - COLOR 0 0 0 END END # Layer @@ -132,13 +134,13 @@ LAYER "init=epsg:3978" END - DUMP TRUE - CLASSITEM "Name_e" CLASS NAME "Roads" - SYMBOL 0 - COLOR 220 0 0 + STYLE + SYMBOL 0 + COLOR 220 0 0 + END END END # Layer diff --git a/msautotest/wxs/wms_sld_validation.map b/msautotest/wxs/wms_sld_validation.map index 85b4edb967..72975fb91b 100644 --- a/msautotest/wxs/wms_sld_validation.map +++ b/msautotest/wxs/wms_sld_validation.map @@ -63,13 +63,14 @@ LAYER "init=epsg:3978" END - DUMP TRUE CLASSITEM "Name_e" CLASS NAME "Province" - COLOR 200 255 0 - OUTLINECOLOR 120 120 120 + STYLE + COLOR 200 255 0 + OUTLINECOLOR 120 120 120 + END END END # Layer @@ -89,14 +90,16 @@ LAYER "init=epsg:3978" END - DUMP TRUE LabelItem "Name" CLASSITEM "Capital" CLASS EXPRESSION /./ - SYMBOL 2 - SIZE 8 + STYLE + SYMBOL 2 + SIZE 8 + COLOR 0 0 0 + END NAME "Cities" LABEL COLOR 0 0 0 @@ -107,7 +110,6 @@ LAYER PARTIALS FALSE OUTLINECOLOR 255 255 255 END - COLOR 0 0 0 END END # Layer @@ -125,13 +127,13 @@ LAYER "init=epsg:3978" END - DUMP TRUE - CLASSITEM "Name_e" CLASS NAME "Roads" - SYMBOL 0 - COLOR 220 0 0 + STYLE + SYMBOL 0 + COLOR 220 0 0 + END END END # Layer @@ -149,15 +151,12 @@ LAYER "init=epsg:3978" END - DUMP TRUE - CLASSITEM "Name_e" CLASSGROUP 'style_red' CLASS GROUP 'style_red' NAME "Roads" STYLE - COLOR 220 0 0 WIDTH 16 END @@ -167,7 +166,6 @@ LAYER GROUP 'style_green' NAME "Roads" STYLE - COLOR 0 220 0 WIDTH 8 END @@ -177,7 +175,6 @@ LAYER GROUP 'style_blue' NAME "Roads" STYLE - COLOR 0 0 220 WIDTH 2 END diff --git a/msautotest/wxs/wms_src_non_square_pixel_ticket5445.map b/msautotest/wxs/wms_src_non_square_pixel_ticket5445.map index 746557abd8..307a5f1f4e 100644 --- a/msautotest/wxs/wms_src_non_square_pixel_ticket5445.map +++ b/msautotest/wxs/wms_src_non_square_pixel_ticket5445.map @@ -3,7 +3,7 @@ # # REQUIRES: INPUT=GDAL OUTPUT=PNG SUPPORTS=WMS # -# RUN_PARMS: wms_src_non_square_pixel_ticket5445.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&BBOX=-7.21916,48.40401621621622,-3.4696399999999996,50.43078378378378&SERVICE=WMS&REQUEST=GetMap&FORMAT=image/png&styles=&layers=continent&width=1000&height=541&srs=EPSG:4326&EXCEPTIONS=application/vnd.ogc.se_inimage&TRANSPARENT=TRUE&VERSION=1.1.1&STYLES=" > [RESULT_DEMIME] +# RUN_PARMS: wms_src_non_square_pixel_ticket5445.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&BBOX=-7.21916,48.40401621621622,-3.4696399999999996,50.43078378378378&SERVICE=WMS&REQUEST=GetMap&FORMAT=image/png;%20mode=8bit&styles=&layers=continent&width=1000&height=541&srs=EPSG:4326&EXCEPTIONS=application/vnd.ogc.se_inimage&TRANSPARENT=TRUE&VERSION=1.1.1&STYLES=" > [RESULT_DEMIME] MAP @@ -20,13 +20,6 @@ PROJECTION "init=epsg:3395" END -OUTPUTFORMAT - NAME GDPNG - DRIVER "GD/PNG" - MIMETYPE "image/png" - EXTENSION "png" -END - # # Start of web interface definition # diff --git a/msautotest/wxs/wms_styles.map b/msautotest/wxs/wms_styles.map new file mode 100644 index 0000000000..2859594047 --- /dev/null +++ b/msautotest/wxs/wms_styles.map @@ -0,0 +1,45 @@ +# +# Test WMS SLD returned by GetStyles requests +# +# REQUIRES: SUPPORTS=WMS +# +# +# GetStyles +# RUN_PARMS: wms_getstyles1.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetStyles&layers=Test1" > [RESULT_DEMIME] + +# Below test is disabled because there's a memory leak during the call to yyparse() in msSLDGenerateTextSLD() +# DISABLED: wms_getstyles2.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetStyles&layers=Test2" > [RESULT_DEMIME] + +MAP + NAME WMS_TEST + + WEB + METADATA + "ows_enable_request" "*" + END + END + + LAYER + NAME "Test1" + TYPE LINE + CLASS + STYLE + COLOR 255 0 0 + WIDTH 2 + PATTERN 10 10 END + END + END + END + + # test for unsupported expression. We just check that this does not + # cause a crash, but the current "expected" result is not optimal + LAYER + NAME "Test2" + TYPE POINT + CLASS + TEXT (tostring([FID],"%d")) + LABEL + END + END + END +END diff --git a/msautotest/wxs/wms_styles_expressions.map b/msautotest/wxs/wms_styles_expressions.map index 6680579344..7f04fae8e7 100644 --- a/msautotest/wxs/wms_styles_expressions.map +++ b/msautotest/wxs/wms_styles_expressions.map @@ -17,6 +17,32 @@ # RUN_PARMS: wms_getstyles_expressions10.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetStyles&layers=Test10" > [RESULT_DEMIME] # RUN_PARMS: wms_getstyles_expressions11.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetStyles&layers=Test11" > [RESULT_DEMIME] # RUN_PARMS: wms_getstyles_expressions12.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetStyles&layers=Test12" > [RESULT_DEMIME] +# RUN_PARMS: wms_getstyles_expressions13.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetStyles&layers=Test13" > [RESULT_DEMIME] +# RUN_PARMS: wms_getstyles_expressions14.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetStyles&layers=Test14" > [RESULT_DEMIME] +# RUN_PARMS: wms_getstyles_expressions15.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetStyles&layers=Test15" > [RESULT_DEMIME] +# RUN_PARMS: wms_getstyles_expressions16.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetStyles&layers=Test16" > [RESULT_DEMIME] +# RUN_PARMS: wms_getstyles_expressions17.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetStyles&layers=Test17" > [RESULT_DEMIME] +# RUN_PARMS: wms_getstyles_expressions18.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetStyles&layers=Test18" > [RESULT_DEMIME] +# RUN_PARMS: wms_getstyles_expressions19.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetStyles&layers=Test19" > [RESULT_DEMIME] +# RUN_PARMS: wms_getstyles_expressions20.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetStyles&layers=Test20" > [RESULT_DEMIME] +# RUN_PARMS: wms_getstyles_expressions21.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetStyles&layers=Test21" > [RESULT_DEMIME] +# RUN_PARMS: wms_getstyles_expressions22.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetStyles&layers=Test22" > [RESULT_DEMIME] +# RUN_PARMS: wms_getstyles_expressions23.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetStyles&layers=Test23" > [RESULT_DEMIME] +# RUN_PARMS: wms_getstyles_expressions24.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetStyles&layers=Test24" > [RESULT_DEMIME] + +# RUN_PARMS: wms_getstyles_expressions26.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetStyles&layers=Test26" > [RESULT_DEMIME] +# RUN_PARMS: wms_getstyles_expressions27.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetStyles&layers=Test27" > [RESULT_DEMIME] +# RUN_PARMS: wms_getstyles_expressions28.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetStyles&layers=Test28" > [RESULT_DEMIME] +# RUN_PARMS: wms_getstyles_expressions29.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetStyles&layers=Test29" > [RESULT_DEMIME] +# RUN_PARMS: wms_getstyles_expressions30.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetStyles&layers=Test30" > [RESULT_DEMIME] +# RUN_PARMS: wms_getstyles_expressions31.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetStyles&layers=Test31" > [RESULT_DEMIME] + +# RUN_PARMS: wms_getstyles_expressions32.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetStyles&layers=Test32" > [RESULT_DEMIME] +# RUN_PARMS: wms_getstyles_expressions33.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetStyles&layers=Test33" > [RESULT_DEMIME] +# RUN_PARMS: wms_getstyles_expressions34.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetStyles&layers=Test34" > [RESULT_DEMIME] +# RUN_PARMS: wms_getstyles_expressions35.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetStyles&layers=Test35" > [RESULT_DEMIME] +# RUN_PARMS: wms_getstyles_expressions36.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetStyles&layers=Test36" > [RESULT_DEMIME] +# RUN_PARMS: wms_getstyles_expressions37.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetStyles&layers=Test37" > [RESULT_DEMIME] MAP NAME WMS_TEST @@ -172,4 +198,369 @@ MAP END END END + + # list expression + LAYER + NAME "Test13" + TYPE POINT + CLASSITEM "FID" + CLASS + EXPRESSION {2,4,6} + STYLE + COLOR 220 0 0 + WIDTH 1 + END + END + END + + # list expression with one value + LAYER + NAME "Test14" + TYPE POINT + CLASSITEM "FID" + CLASS + EXPRESSION {2} + STYLE + COLOR 220 0 0 + WIDTH 1 + END + END + END + + # empty list expression + LAYER + NAME "Test15" + TYPE POINT + CLASSITEM "FID" + CLASS + EXPRESSION {} + STYLE + COLOR 220 0 0 + WIDTH 1 + END + END + END + + # string list expression + LAYER + NAME "Test16" + TYPE POINT + CLASSITEM "locationtype" + CLASS + EXPRESSION {primary location,secondary location} + STYLE + COLOR 220 0 0 + WIDTH 1 + END + END + END + + # string list expression with quotes + LAYER + NAME "Test17" + TYPE POINT + CLASSITEM "poi" + CLASS + EXPRESSION {"main" square,city's centre} + STYLE + COLOR 220 0 0 + WIDTH 1 + END + END + END + + # string list expression with trailing space + LAYER + NAME "Test18" + TYPE POINT + CLASSITEM "locationtype" + CLASS + EXPRESSION {primary location,secondary location } + STYLE + COLOR 220 0 0 + WIDTH 1 + END + END + END + + # string expression + LAYER + NAME "Test19" + TYPE POINT + CLASS + EXPRESSION ( [locationtype] = "primary location" ) + STYLE + COLOR 220 0 0 + WIDTH 1 + END + END + END + + # string expression with trailing space + LAYER + NAME "Test20" + TYPE POINT + CLASS + EXPRESSION ( [locationtype] = "primary location " ) + STYLE + COLOR 220 0 0 + WIDTH 1 + END + END + END + + # test for multiple expressions with brackets and spaces + LAYER + NAME "Test21" + TYPE POINT + CLASS + EXPRESSION ( ( [FID] > 1 ) AND ( [FID] <= 10 ) ) + STYLE + COLOR 220 0 0 + WIDTH 1 + END + END + END + + # test for multiple string expressions with brackets and spaces + LAYER + NAME "Test22" + TYPE POINT + CLASS + EXPRESSION ( ( [locationtype] = "primary location " ) OR ( [locationtype] = " secondary location" ) ) + STYLE + COLOR 220 0 0 + WIDTH 1 + END + END + END + + # test for multiple expressions with spaces but not brackets + LAYER + NAME "Test23" + TYPE POINT + CLASS + EXPRESSION ( [FID] > 1 AND [FID] <= 10 ) + STYLE + COLOR 220 0 0 + WIDTH 1 + END + END + END + + # test for string expressions containing logic operators + LAYER + NAME "Test24" + TYPE POINT + CLASS + NAME "Not Test" + EXPRESSION ("[Property1]" = "Not Applicable") + STYLE + COLOR 0 0 255 + SYMBOL "star" + END + END + CLASS + NAME "And Test" + EXPRESSION ("[Property1]" = "With AND value") + STYLE + COLOR 0 255 0 + SYMBOL "star" + END + END + CLASS + NAME "Or Test" + EXPRESSION ("[Property1]" = "With OR value") + STYLE + COLOR 255 0 0 + SYMBOL "star" + END + END + END + + LAYER + NAME "Test25" + TYPE POINT + CLASS + NAME "Or Test" + EXPRESSION (("[Property1]" = "Not value") OR ("[Property1]" = "An Or value")) + STYLE + COLOR 0 0 255 + SYMBOL "star" + END + END + CLASS + # TODO - this test incorrectly output "An" to the filter rather than "An And value" + NAME "And Test" + EXPRESSION (("[Property1]" = "An And value") AND ("[Property1]" = "A Not value")) + STYLE + COLOR 0 255 0 + SYMBOL "star" + END + END + CLASS + NAME "Not Test" + EXPRESSION (NOT ("[Property1]" = "A Not value")) + STYLE + COLOR 255 0 0 + SYMBOL "star" + END + END + END + + LAYER + NAME "Test26" + TYPE POINT + CLASS + EXPRESSION ( [FID] <> 1 AND [FID] <> 10 ) + STYLE + COLOR 220 0 0 + WIDTH 1 + END + END + END + + LAYER + NAME "Test27" + TYPE POINT + CLASS + EXPRESSION ([FID] != 1 AND [FID] ne 10 ) + STYLE + COLOR 220 0 0 + WIDTH 1 + END + END + END + + # no spaces around comparison operator + LAYER + NAME "Test28" + TYPE POINT + CLASS + EXPRESSION ( [FID]=1 or [FID]=10 ) + STYLE + COLOR 220 0 0 + WIDTH 1 + END + END + END + + # no spaces around comparison operators + LAYER + NAME "Test29" + TYPE POINT + CLASS + EXPRESSION ( [FID]<>1 AND [FID]!=10 ) + STYLE + COLOR 220 0 0 + WIDTH 1 + END + END + END + + # invalid comparison operator in this case will assume a literal + # after the equals and output ! 1 + LAYER + NAME "Test30" + TYPE POINT + CLASS + EXPRESSION ( [FID] =! 1 ) + STYLE + COLOR 220 0 0 + WIDTH 1 + END + END + END + + # invalid comparison operator in this case will assume a literal + # after the > and output ! 1 + LAYER + NAME "Test31" + TYPE POINT + CLASS + EXPRESSION ( [FID] >! 1 ) + STYLE + COLOR 220 0 0 + WIDTH 1 + END + END + END + + # field name containing "le" + LAYER + NAME "Test32" + TYPE POINT + CLASS + EXPRESSION (([field_le] > 0) AND ([field_le] <= 6)) + STYLE + COLOR 0 176 80 + WIDTH 1 + END + END + END + + # field name containing "ge" + LAYER + NAME "Test33" + TYPE POINT + CLASS + EXPRESSION (([field_ge] > 0) AND ([field_ge] >= 6)) + STYLE + COLOR 0 176 80 + WIDTH 1 + END + END + END + + # field name containing "lt" + LAYER + NAME "Test34" + TYPE POINT + CLASS + EXPRESSION (([field_lt] > 0) AND ([field_lt] <= 10)) + STYLE + COLOR 0 176 80 + WIDTH 1 + END + END + END + + # field name containing "gt" + LAYER + NAME "Test35" + TYPE POINT + CLASS + EXPRESSION (([field_gt] > 0) AND ([field_gt] <= 10)) + STYLE + COLOR 0 176 80 + WIDTH 1 + END + END + END + + # field name containing "ne" + LAYER + NAME "Test36" + TYPE POINT + CLASS + EXPRESSION (([field_ne] != 0) AND ([field_ne] != 99)) + STYLE + COLOR 0 176 80 + WIDTH 1 + END + END + END + + # field name containing "le" with no spaces around operator + LAYER + NAME "Test37" + TYPE POINT + CLASS + EXPRESSION (([field_le]>0) AND ([field_le]<=6)) + STYLE + COLOR 0 176 80 + WIDTH 1 + END + END + END END diff --git a/msautotest/wxs/wms_tiled.map b/msautotest/wxs/wms_tiled.map new file mode 100644 index 0000000000..0d9a932e50 --- /dev/null +++ b/msautotest/wxs/wms_tiled.map @@ -0,0 +1,74 @@ +# +# Test WMS-C TILED=TRUE +# +# REQUIRES: INPUT=GDAL OUTPUT=PNG SUPPORTS=WMS + +# RUN_PARMS: wms_tiled_tiled_disabled.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&VERSION=1.3.0&REQUEST=GetMap&CRS=EPSG%3A4326&BBOX=44.1,-65.755,47.3,-58.375&WIDTH=400&HEIGHT=400&LAYERS=popplace&STYLES=&FORMAT=image%2Fpng;%20mode=8bit" > [RESULT_DEMIME] + +# RUN_PARMS: wms_tiled_tiled_enabled.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&VERSION=1.3.0&REQUEST=GetMap&CRS=EPSG%3A4326&BBOX=44.1,-65.755,47.3,-58.375&WIDTH=400&HEIGHT=400&LAYERS=popplace&STYLES=&FORMAT=image%2Fpng;%20mode=8bit&TILED=TRUE" > [RESULT_DEMIME] + +MAP + +NAME WMS_TILED +STATUS ON +SIZE 400 300 +UNITS DD +IMAGECOLOR 255 255 255 +SHAPEPATH ./data +SYMBOLSET etc/symbols.sym +FONTSET etc/fonts.txt + + +# +# Start of web interface definition +# +WEB + + IMAGEPATH "/tmp/ms_tmp/" + IMAGEURL "/ms_tmp/" + + METADATA + "wms_title" "Test simple wms" + "wms_onlineresource" "http://localhost/path/to/wms_simple?" + "wms_srs" "EPSG:42304 EPSG:42101 EPSG:4269 EPSG:4326" + "ows_schemas_location" "http://ogc.dmsolutions.ca" + "wms_sld_enabled" "false" + "ows_enable_request" "*" + "tile_map_edge_buffer" "50" + END +END + +PROJECTION + "init=epsg:4326" +END + + +# +# Start of layer definitions +# + + +LAYER + NAME popplace + DATA popplace + METADATA + "wms_title" "popplace" + "wms_description" "Cities of I.P.E." + END + TYPE POINT + STATUS ON + PROJECTION + "init=./data/epsg2:42304" + END + CLASS + NAME "Cities" + STYLE + SYMBOL 2 + SIZE 40 + COLOR 0 0 0 + END + END +END # Layer + + +END # Map File diff --git a/msautotest/wxs/wms_tileindexmixedsrs.map b/msautotest/wxs/wms_tileindexmixedsrs.map index b7c4030da0..859b31e94f 100644 --- a/msautotest/wxs/wms_tileindexmixedsrs.map +++ b/msautotest/wxs/wms_tileindexmixedsrs.map @@ -47,7 +47,6 @@ LAYER NAME grey TYPE raster STATUS ON - DUMP TRUE TILEINDEX "../gdal/data/tile_index_mixed_srs.shp" TILEITEM "location" TILESRS "src_srs" diff --git a/msautotest/wxs/wms_time1.map b/msautotest/wxs/wms_time1.map index bb747c9703..89abb23e54 100644 --- a/msautotest/wxs/wms_time1.map +++ b/msautotest/wxs/wms_time1.map @@ -65,8 +65,8 @@ FONTSET ./etc/fonts.txt # Start of web interface definition # WEB - MINSCALE 2000000 - MAXSCALE 50000000 + MINSCALEDENOM 2000000 + MAXSCALEDENOM 50000000 IMAGEPATH "/tmp/ms_tmp/" IMAGEURL "/ms_tmp/" @@ -119,9 +119,11 @@ LAYER STATUS DEFAULT DATA pattern4 CLASS - SYMBOL 2 - SIZE 8 - COLOR 255 0 0 + STYLE + SYMBOL 2 + SIZE 8 + COLOR 255 0 0 + END END END diff --git a/msautotest/wxs/wms_time1_postgis.map b/msautotest/wxs/wms_time1_postgis.map index 603f259090..858251614d 100644 --- a/msautotest/wxs/wms_time1_postgis.map +++ b/msautotest/wxs/wms_time1_postgis.map @@ -65,8 +65,8 @@ FONTSET ./etc/fonts.txt # Start of web interface definition # WEB - MINSCALE 2000000 - MAXSCALE 50000000 + MINSCALEDENOM 2000000 + MAXSCALEDENOM 50000000 IMAGEPATH "/tmp/ms_tmp/" IMAGEURL "/ms_tmp/" @@ -120,9 +120,11 @@ LAYER INCLUDE "postgis.include" DATA "the_geom from (select * from pattern4 order by gid) as foo using unique gid using srid=4326" CLASS - SYMBOL 2 - SIZE 8 - COLOR 255 0 0 + STYLE + SYMBOL 2 + SIZE 8 + COLOR 255 0 0 + END END END diff --git a/msautotest/wxs/wms_time2.map b/msautotest/wxs/wms_time2.map index b97051e972..3d240f064a 100644 --- a/msautotest/wxs/wms_time2.map +++ b/msautotest/wxs/wms_time2.map @@ -25,8 +25,8 @@ FONTSET ./etc/fonts.txt # Start of web interface definition # WEB - MINSCALE 2000000 - MAXSCALE 50000000 + MINSCALEDENOM 2000000 + MAXSCALEDENOM 50000000 IMAGEPATH "/tmp/ms_tmp/" IMAGEURL "/ms_tmp/" @@ -78,9 +78,11 @@ LAYER STATUS DEFAULT DATA pattern4 CLASS - SYMBOL 2 - SIZE 8 - COLOR 255 0 0 + STYLE + SYMBOL 2 + SIZE 8 + COLOR 255 0 0 + END END END diff --git a/msautotest/wxs/wms_time2_postgis.map b/msautotest/wxs/wms_time2_postgis.map index 0fe6fe3935..115dcc8fbb 100644 --- a/msautotest/wxs/wms_time2_postgis.map +++ b/msautotest/wxs/wms_time2_postgis.map @@ -25,8 +25,8 @@ FONTSET ./etc/fonts.txt # Start of web interface definition # WEB - MINSCALE 2000000 - MAXSCALE 50000000 + MINSCALEDENOM 2000000 + MAXSCALEDENOM 50000000 IMAGEPATH "/tmp/ms_tmp/" IMAGEURL "/ms_tmp/" @@ -80,9 +80,11 @@ LAYER INCLUDE "postgis.include" DATA "the_geom from (select * from pattern4 order by gid) as foo using unique gid using srid=4326" CLASS - SYMBOL 2 - SIZE 8 - COLOR 255 0 0 + STYLE + SYMBOL 2 + SIZE 8 + COLOR 255 0 0 + END END END diff --git a/msautotest/wxs/wms_time_pattern.map b/msautotest/wxs/wms_time_pattern.map index a43fe8cde8..d9f899b816 100644 --- a/msautotest/wxs/wms_time_pattern.map +++ b/msautotest/wxs/wms_time_pattern.map @@ -258,8 +258,8 @@ FONTSET ./etc/fonts.txt # Start of web interface definition # WEB - MINSCALE 2000000 - MAXSCALE 50000000 + MINSCALEDENOM 2000000 + MAXSCALEDENOM 50000000 IMAGEPATH "/tmp/ms_tmp/" IMAGEURL "/ms_tmp/" @@ -308,9 +308,11 @@ LAYER STATUS ON DATA pattern1 CLASS - SYMBOL 2 - SIZE 8 - COLOR 255 0 0 + STYLE + SYMBOL 2 + SIZE 8 + COLOR 255 0 0 + END END END @@ -334,9 +336,11 @@ LAYER STATUS ON DATA pattern2 CLASS - SYMBOL 2 - SIZE 8 - COLOR 255 0 0 + STYLE + SYMBOL 2 + SIZE 8 + COLOR 255 0 0 + END END END @@ -360,9 +364,11 @@ LAYER STATUS ON DATA pattern3 CLASS - SYMBOL 2 - SIZE 8 - COLOR 255 0 0 + STYLE + SYMBOL 2 + SIZE 8 + COLOR 255 0 0 + END END END @@ -385,9 +391,11 @@ LAYER STATUS ON DATA pattern4 CLASS - SYMBOL 2 - SIZE 8 - COLOR 255 0 0 + STYLE + SYMBOL 2 + SIZE 8 + COLOR 255 0 0 + END END END @@ -410,9 +418,11 @@ LAYER STATUS ON DATA pattern5 CLASS - SYMBOL 2 - SIZE 8 - COLOR 255 0 0 + STYLE + SYMBOL 2 + SIZE 8 + COLOR 255 0 0 + END END END @@ -436,9 +446,11 @@ LAYER STATUS ON DATA pattern6 CLASS - SYMBOL 2 - SIZE 8 - COLOR 255 0 0 + STYLE + SYMBOL 2 + SIZE 8 + COLOR 255 0 0 + END END END @@ -462,9 +474,11 @@ LAYER STATUS ON DATA pattern7 CLASS - SYMBOL 2 - SIZE 8 - COLOR 255 0 0 + STYLE + SYMBOL 2 + SIZE 8 + COLOR 255 0 0 + END END END @@ -488,9 +502,11 @@ LAYER STATUS ON DATA pattern8 CLASS - SYMBOL 2 - SIZE 8 - COLOR 255 0 0 + STYLE + SYMBOL 2 + SIZE 8 + COLOR 255 0 0 + END END END @@ -513,9 +529,11 @@ LAYER STATUS ON DATA pattern9 CLASS - SYMBOL 2 - SIZE 8 - COLOR 255 0 0 + STYLE + SYMBOL 2 + SIZE 8 + COLOR 255 0 0 + END END END @@ -540,9 +558,11 @@ LAYER STATUS ON DATA pattern10 CLASS - SYMBOL 2 - SIZE 8 - COLOR 255 0 0 + STYLE + SYMBOL 2 + SIZE 8 + COLOR 255 0 0 + END END END @@ -567,9 +587,11 @@ LAYER STATUS ON DATA pattern11 CLASS - SYMBOL 2 - SIZE 8 - COLOR 255 0 0 + STYLE + SYMBOL 2 + SIZE 8 + COLOR 255 0 0 + END END END @@ -593,9 +615,11 @@ LAYER STATUS ON DATA pattern12 CLASS - SYMBOL 2 - SIZE 8 - COLOR 255 0 0 + STYLE + SYMBOL 2 + SIZE 8 + COLOR 255 0 0 + END END END @@ -619,9 +643,11 @@ LAYER STATUS ON DATA pattern13 CLASS - SYMBOL 2 - SIZE 8 - COLOR 255 0 0 + STYLE + SYMBOL 2 + SIZE 8 + COLOR 255 0 0 + END END END @@ -644,9 +670,11 @@ LAYER STATUS ON DATA pattern14 CLASS - SYMBOL 2 - SIZE 8 - COLOR 255 0 0 + STYLE + SYMBOL 2 + SIZE 8 + COLOR 255 0 0 + END END END @@ -668,9 +696,11 @@ LAYER STATUS ON DATA pattern15 CLASS - SYMBOL 2 - SIZE 8 - COLOR 255 0 0 + STYLE + SYMBOL 2 + SIZE 8 + COLOR 255 0 0 + END END END diff --git a/msautotest/wxs/wms_time_pattern_12_13_test.map b/msautotest/wxs/wms_time_pattern_12_13_test.map index 1780f1dd99..614c6a2351 100644 --- a/msautotest/wxs/wms_time_pattern_12_13_test.map +++ b/msautotest/wxs/wms_time_pattern_12_13_test.map @@ -55,8 +55,8 @@ FONTSET ./etc/fonts.txt # Start of web interface definition # WEB - MINSCALE 2000000 - MAXSCALE 50000000 + MINSCALEDENOM 2000000 + MAXSCALEDENOM 50000000 IMAGEPATH "/tmp/ms_tmp/" IMAGEURL "/ms_tmp/" @@ -106,9 +106,11 @@ LAYER STATUS ON DATA pattern12 CLASS - SYMBOL 2 - SIZE 8 - COLOR 255 0 0 + STYLE + SYMBOL 2 + SIZE 8 + COLOR 255 0 0 + END END END @@ -131,9 +133,11 @@ LAYER STATUS ON DATA pattern13 CLASS - SYMBOL 2 - SIZE 8 - COLOR 255 0 0 + STYLE + SYMBOL 2 + SIZE 8 + COLOR 255 0 0 + END END END diff --git a/msautotest/wxs/wms_time_pattern_12_13_test_postgis.map b/msautotest/wxs/wms_time_pattern_12_13_test_postgis.map index fad5b61d70..3ea7f30a3b 100644 --- a/msautotest/wxs/wms_time_pattern_12_13_test_postgis.map +++ b/msautotest/wxs/wms_time_pattern_12_13_test_postgis.map @@ -55,8 +55,8 @@ FONTSET ./etc/fonts.txt # Start of web interface definition # WEB - MINSCALE 2000000 - MAXSCALE 50000000 + MINSCALEDENOM 2000000 + MAXSCALEDENOM 50000000 IMAGEPATH "/tmp/ms_tmp/" IMAGEURL "/ms_tmp/" @@ -107,9 +107,11 @@ LAYER INCLUDE "postgis.include" DATA "the_geom from (select * from pattern12 order by gid) as foo using unique gid using srid=4326" CLASS - SYMBOL 2 - SIZE 8 - COLOR 255 0 0 + STYLE + SYMBOL 2 + SIZE 8 + COLOR 255 0 0 + END END END @@ -133,9 +135,11 @@ LAYER INCLUDE "postgis.include" DATA "the_geom from (select * from pattern13 order by gid) as foo using unique gid using srid=4326" CLASS - SYMBOL 2 - SIZE 8 - COLOR 255 0 0 + STYLE + SYMBOL 2 + SIZE 8 + COLOR 255 0 0 + END END END diff --git a/msautotest/wxs/wms_time_pattern_fail.map b/msautotest/wxs/wms_time_pattern_fail.map index a4f63d46ea..2fd8c858c5 100644 --- a/msautotest/wxs/wms_time_pattern_fail.map +++ b/msautotest/wxs/wms_time_pattern_fail.map @@ -36,8 +36,8 @@ FONTSET ./etc/fonts.txt # Start of web interface definition # WEB - MINSCALE 2000000 - MAXSCALE 50000000 + MINSCALEDENOM 2000000 + MAXSCALEDENOM 50000000 IMAGEPATH "/tmp/ms_tmp/" IMAGEURL "/ms_tmp/" @@ -87,9 +87,11 @@ LAYER STATUS ON DATA pattern12 CLASS - SYMBOL 2 - SIZE 8 - COLOR 255 0 0 + STYLE + SYMBOL 2 + SIZE 8 + COLOR 255 0 0 + END END END @@ -112,9 +114,11 @@ LAYER STATUS ON DATA pattern13 CLASS - SYMBOL 2 - SIZE 8 - COLOR 255 0 0 + STYLE + SYMBOL 2 + SIZE 8 + COLOR 255 0 0 + END END END diff --git a/msautotest/wxs/wms_time_pattern_postgis.map b/msautotest/wxs/wms_time_pattern_postgis.map index d1e20c657f..d1694310c2 100644 --- a/msautotest/wxs/wms_time_pattern_postgis.map +++ b/msautotest/wxs/wms_time_pattern_postgis.map @@ -258,8 +258,8 @@ FONTSET ./etc/fonts.txt # Start of web interface definition # WEB - MINSCALE 2000000 - MAXSCALE 50000000 + MINSCALEDENOM 2000000 + MAXSCALEDENOM 50000000 IMAGEPATH "/tmp/ms_tmp/" IMAGEURL "/ms_tmp/" @@ -309,9 +309,11 @@ LAYER INCLUDE "postgis.include" DATA "the_geom from (select * from pattern1 order by gid) as foo using unique gid using srid=4326" CLASS - SYMBOL 2 - SIZE 8 - COLOR 255 0 0 + STYLE + SYMBOL 2 + SIZE 8 + COLOR 255 0 0 + END END END @@ -336,9 +338,11 @@ LAYER INCLUDE "postgis.include" DATA "the_geom from (select * from pattern2 order by gid) as foo using unique gid using srid=4326" CLASS - SYMBOL 2 - SIZE 8 - COLOR 255 0 0 + STYLE + SYMBOL 2 + SIZE 8 + COLOR 255 0 0 + END END END @@ -363,9 +367,11 @@ LAYER INCLUDE "postgis.include" DATA "the_geom from (select * from pattern3 order by gid) as foo using unique gid using srid=4326" CLASS - SYMBOL 2 - SIZE 8 - COLOR 255 0 0 + STYLE + SYMBOL 2 + SIZE 8 + COLOR 255 0 0 + END END END @@ -389,9 +395,11 @@ LAYER INCLUDE "postgis.include" DATA "the_geom from (select * from pattern4 order by gid) as foo using unique gid using srid=4326" CLASS - SYMBOL 2 - SIZE 8 - COLOR 255 0 0 + STYLE + SYMBOL 2 + SIZE 8 + COLOR 255 0 0 + END END END @@ -415,9 +423,11 @@ LAYER INCLUDE "postgis.include" DATA "the_geom from (select * from pattern5 order by gid) as foo using unique gid using srid=4326" CLASS - SYMBOL 2 - SIZE 8 - COLOR 255 0 0 + STYLE + SYMBOL 2 + SIZE 8 + COLOR 255 0 0 + END END END @@ -442,9 +452,11 @@ LAYER INCLUDE "postgis.include" DATA "the_geom from (select * from pattern6 order by gid) as foo using unique gid using srid=4326" CLASS - SYMBOL 2 - SIZE 8 - COLOR 255 0 0 + STYLE + SYMBOL 2 + SIZE 8 + COLOR 255 0 0 + END END END @@ -469,9 +481,11 @@ LAYER INCLUDE "postgis.include" DATA "the_geom from (select * from pattern7 order by gid) as foo using unique gid using srid=4326" CLASS - SYMBOL 2 - SIZE 8 - COLOR 255 0 0 + STYLE + SYMBOL 2 + SIZE 8 + COLOR 255 0 0 + END END END @@ -496,9 +510,11 @@ LAYER INCLUDE "postgis.include" DATA "the_geom from (select * from pattern8 order by gid) as foo using unique gid using srid=4326" CLASS - SYMBOL 2 - SIZE 8 - COLOR 255 0 0 + STYLE + SYMBOL 2 + SIZE 8 + COLOR 255 0 0 + END END END @@ -522,9 +538,11 @@ LAYER INCLUDE "postgis.include" DATA "the_geom from (select * from pattern9 order by gid) as foo using unique gid using srid=4326" CLASS - SYMBOL 2 - SIZE 8 - COLOR 255 0 0 + STYLE + SYMBOL 2 + SIZE 8 + COLOR 255 0 0 + END END END @@ -550,9 +568,11 @@ LAYER INCLUDE "postgis.include" DATA "the_geom from (select * from pattern10 order by gid) as foo using unique gid using srid=4326" CLASS - SYMBOL 2 - SIZE 8 - COLOR 255 0 0 + STYLE + SYMBOL 2 + SIZE 8 + COLOR 255 0 0 + END END END @@ -578,9 +598,11 @@ LAYER INCLUDE "postgis.include" DATA "the_geom from (select * from pattern11 order by gid) as foo using unique gid using srid=4326" CLASS - SYMBOL 2 - SIZE 8 - COLOR 255 0 0 + STYLE + SYMBOL 2 + SIZE 8 + COLOR 255 0 0 + END END END @@ -605,9 +627,11 @@ LAYER INCLUDE "postgis.include" DATA "the_geom from (select * from pattern12 order by gid) as foo using unique gid using srid=4326" CLASS - SYMBOL 2 - SIZE 8 - COLOR 255 0 0 + STYLE + SYMBOL 2 + SIZE 8 + COLOR 255 0 0 + END END END @@ -632,9 +656,11 @@ LAYER INCLUDE "postgis.include" DATA "the_geom from (select * from pattern13 order by gid) as foo using unique gid using srid=4326" CLASS - SYMBOL 2 - SIZE 8 - COLOR 255 0 0 + STYLE + SYMBOL 2 + SIZE 8 + COLOR 255 0 0 + END END END @@ -658,9 +684,11 @@ LAYER INCLUDE "postgis.include" DATA "the_geom from (select * from pattern14 order by gid) as foo using unique gid using srid=4326" CLASS - SYMBOL 2 - SIZE 8 - COLOR 255 0 0 + STYLE + SYMBOL 2 + SIZE 8 + COLOR 255 0 0 + END END END @@ -683,9 +711,11 @@ LAYER INCLUDE "postgis.include" DATA "the_geom from (select * from pattern15 order by gid) as foo using unique gid using srid=4326" CLASS - SYMBOL 2 - SIZE 8 - COLOR 255 0 0 + STYLE + SYMBOL 2 + SIZE 8 + COLOR 255 0 0 + END END END diff --git a/msautotest/wxs/wms_uvraster_map_reprojection.map b/msautotest/wxs/wms_uvraster_map_reprojection.map index 780fad3038..6fb9d44e45 100644 --- a/msautotest/wxs/wms_uvraster_map_reprojection.map +++ b/msautotest/wxs/wms_uvraster_map_reprojection.map @@ -10,9 +10,11 @@ # RUN_PARMS: wms_uvraster_map_reprojection_extent_intersecting_layer.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMap&BBOX=30,-200,60,-100&CRS=EPSG:4326&WIDTH=400&HEIGHT=200&LAYERS=test&STYLES=&FORMAT=image/png&TRANSPARENT=TRUE" > [RESULT_DEMIME] # # RUN_PARMS: wms_uvraster_map_reprojection_getfeatureinfo.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetFeatureInfo&BBOX=-30.28229908443537965,-68.01500508646998355,123.14801627670399853,120.98499491353001645&CRS=EPSG:4326&WIDTH=983&HEIGHT=798&LAYERS=test&STYLES=&FORMAT=image/png&QUERY_LAYERS=test&INFO_FORMAT=application/vnd.ogc.gml&I=798&J=232&FEATURE_COUNT=10" > [RESULT_DEMIME] +# +# RUN_PARMS: wms_uvraster_map_reprojection_geog_to_polar_stereo.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMap&BBOX=-12367396,-12367396,12367396,12367396&CRS=EPSG:3995&WIDTH=200&HEIGHT=200&LAYERS=data_in_geographic&STYLES=&FORMAT=image/png&TRANSPARENT=TRUE" > [RESULT_DEMIME] MAP - NAME test + NAME xtest EXTENT -180 -90 180 90 MAXSIZE 4096 SIZE 500 300 @@ -41,6 +43,7 @@ MAP WEB METADATA "ows_enable_request" "*" + "wms_srs" "EPSG:4326 EPSG:3995" "wms_onlineresource" "http://localhost:8080/mapserv.cgi?map=/home/even/mapserver/mapserver/msautotest/wxs/wms_uvraster_map_reprojection.map&" END END @@ -55,8 +58,9 @@ MAP TOLERANCE 20 METADATA - "wms_title" "test" - "gml_include_items" "all" + "wms_title" "test" + "gml_include_items" "uv_angle,uv_minus_angle,uv_length,uv_length_2,u,v" + "wms_srs" "EPSG:4326 EPSG:3995" END PROJECTION @@ -84,4 +88,37 @@ MAP END END END + + + LAYER + NAME "data_in_geographic" + TYPE POINT + CONNECTIONTYPE uvraster + PROCESSING "BANDS=1,2" + PROCESSING "UV_SPACING=20" + TEMPLATE "ttt" + TOLERANCE 20 + + METADATA + "wms_title" "data_in_geographic" + "gml_include_items" "uv_angle,uv_minus_angle,uv_length,uv_length_2,u,v" + "wms_srs" "EPSG:4326 EPSG:3995" + END + + PROJECTION + "init=epsg:4326" + END + + DATA 'wind_to_west_north_hemisphere.tif' + + CLASS + STYLE + COLOR 0 0 127 + SYMBOL "arrow_wind" + ANGLE [uv_angle] + SIZE 12 + END + END + END + END diff --git a/msautotest/wxs/wms_uvraster_tileindex.map b/msautotest/wxs/wms_uvraster_tileindex.map new file mode 100644 index 0000000000..f35b6c96ed --- /dev/null +++ b/msautotest/wxs/wms_uvraster_tileindex.map @@ -0,0 +1,114 @@ +# +# Test WMS TIME support for UVRaster with tileindex +# +# REQUIRES: INPUT=GDAL OUTPUT=PNG SUPPORTS=WMS +# +# RUN_PARMS: wms_uvraster_tileindex_inline.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMap&BBOX=-90,-180,90,180&CRS=EPSG:4326&WIDTH=400&HEIGHT=200&LAYERS=test_inline_tileindex&STYLES=&FORMAT=image/png" > [RESULT_DEMIME] + +# RUN_PARMS: wms_uvraster_tileindex_offline.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMap&BBOX=-90,-180,90,180&CRS=EPSG:4326&WIDTH=400&HEIGHT=200&LAYERS=test_offline_tileindex&STYLES=&FORMAT=image/png" > [RESULT_DEMIME] + +MAP + NAME uvraster_tileindex + EXTENT -180 -90 180 90 + MAXSIZE 4096 + SIZE 500 300 + SHAPEPATH ../renderers/data + + PROJECTION + "init=epsg:4326" + END + + SYMBOL + NAME "arrow" + FILLED TRUE + POINTS + 1.2 0 + 1.2 6 + 3 6 + 0 10 + -3 6 + -1.2 6 + -1.2 0 + 1.2 0 + END + END + + WEB + METADATA + "ows_enable_request" "*" + END + END + + LAYER + NAME "test_inline_tileindex" + TYPE POINT + CONNECTIONTYPE uvraster + TILEINDEX "wind_12.shp" + TILEITEM "location" + + METADATA + "wms_timeitem" "timestamp" + "wms_timeextent" "2025-09-01T00:00:00Z/2025-12-31T00:00:00Z/PT300S" + "wms_timedefault" "2025-12-15T18:00:00Z" + END + + EXTENT -180 -90 180 90 + + PROCESSING "BANDS=1,2" + PROCESSING "UV_SPACING=40" + + PROJECTION + "init=epsg:4326" + END + + CLASS + STYLE + SYMBOL "arrow" + COLOR 255 0 0 + ANGLE [uv_angle] + SIZE 10 + END + END + + END + + LAYER + STATUS OFF + NAME "my_tileindex" + TYPE POLYGON + DATA "wind_12.shp" + END + + LAYER + NAME "test_offline_tileindex" + TYPE POINT + CONNECTIONTYPE uvraster + TILEINDEX "my_tileindex" + + METADATA + "wms_timeitem" "timestamp" + "wms_timeextent" "2025-09-01T00:00:00Z/2025-12-31T00:00:00Z/PT300S" + "wms_timedefault" "2025-12-15T18:00:00Z" + END + + EXTENT -180 -90 180 90 + + PROCESSING "BANDS=1,2" + PROCESSING "UV_SPACING=40" + + PROJECTION + "init=epsg:4326" + END + + CLASS + STYLE + SYMBOL "arrow" + COLOR 255 0 0 + ANGLE [uv_angle] + SIZE 10 + END + END + + END + +END diff --git a/msautotest/wxs/wmsclient_proj.map b/msautotest/wxs/wmsclient_proj.map new file mode 100644 index 0000000000..60821cf9cc --- /dev/null +++ b/msautotest/wxs/wmsclient_proj.map @@ -0,0 +1,41 @@ +#RUN_PARMS: wmsclient_proj.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&LAYERS=pop&BBOX=-20026376,-20048966,-200,-200&WIDTH=200&HEIGHT=200&VERSION=1.1.1&FORMAT=image%2Fpng&SERVICE=WMS&REQUEST=GetMap&STYLES=&EXCEPTIONS=application%2Fvnd.ogc.se_inimage&SRS=EPSG%3A3857" > [RESULT_DEMIME] + +# +# Test requeseting a WMS layer in another projection than defined on the layers PROJECTION directive. +# + +MAP + NAME TEST + STATUS ON + SIZE 360 145 + EXTENT -180 -60 180 85 + IMAGECOLOR 255 255 0 + + IMAGETYPE png + PROJECTION + "init=epsg:4326" + END # PROJECTION + + LAYER + NAME "pop" + TYPE RASTER + STATUS DEFAULT + CONNECTION "https://demo.mapserver.org/cgi-bin/msautotest?" + CONNECTIONTYPE WMS + EXTENT -180 -60 180 85 + METADATA + "wms_srs" "EPSG:4326 EPSG:3857" + "wms_name" "world_merc" + "wms_server_version" "1.1.1" + "wms_format" "image/png" + "wms_enable_request" "*" + END + + PROJECTION + "init=epsg:4326" + END # PROJECTION + + END + +END # of map file + diff --git a/scalebar.c b/scalebar.c deleted file mode 100644 index 67ba5f4398..0000000000 --- a/scalebar.c +++ /dev/null @@ -1,69 +0,0 @@ -/****************************************************************************** - * $Id$ - * - * Project: MapServer - * Purpose: Commandline scalebar generating utility, mostly for testing. - * Author: Steve Lime and the MapServer team. - * - ****************************************************************************** - * Copyright (c) 1996-2005 Regents of the University of Minnesota. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies of this Software or works derived from this Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - ****************************************************************************/ - -#include "mapserver.h" - - - -int main(int argc, char *argv[]) -{ - mapObj *map=NULL; - imageObj *image = NULL; - - msSetup(); - if(argc > 1 && strcmp(argv[1], "-v") == 0) { - printf("%s\n", msGetVersion()); - exit(0); - } - - /* ---- check the number of arguments, return syntax if not correct ---- */ - if( argc < 3 ) { - fprintf(stdout,"Syntax: scalebar [mapfile] [output image]\n" ); - exit(1); - } - - map = msLoadMap(argv[1], NULL); - if(!map) { - msWriteError(stderr); - exit(1); - } - - image = msDrawScalebar(map); - - if(!image) { - msWriteError(stderr); - exit(1); - } - - msSaveImage(map, image, argv[2]); - msFreeImage(image); - - msFreeMap(map); - return(MS_TRUE); -} diff --git a/scripts/build-mapscript-php.sh b/scripts/build-mapscript-php.sh new file mode 100755 index 0000000000..6c6b702458 --- /dev/null +++ b/scripts/build-mapscript-php.sh @@ -0,0 +1,51 @@ +#!/bin/bash +set -eu # Exit on error and treat unset variables as errors + +cd "$WORK_DIR" + +# Ensure the PHP version is provided +if [ -z "${PHP_VERSION:-}" ]; then + echo "Error: PHP version not specified. Make sure to pass it as an environment variable." + exit 1 +fi + +export DEBIAN_FRONTEND=noninteractive + +apt-get update -y + +# general dependencies +apt-get install -y sudo software-properties-common wget curl git python3 python3-pip +sudo ln -s /usr/bin/python3 /usr/bin/python + + +# for pre-installed software see +# https://github.com/actions/runner-images/blob/main/images/ubuntu/Ubuntu2404-Readme.md +# both swig and php are included, so removed these +sudo apt-get -qq remove "php*-cli" "php*-dev" +sudo apt-get -qq remove "swig*" + +# https://github.com/oerdnj/deb.sury.org/issues/56 +add-apt-repository ppa:ondrej/php -y +LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php -y + +sudo apt-get -qq update +sudo apt-get -qq install php"${PHP_VERSION}"-cli php"${PHP_VERSION}"-dev php"${PHP_VERSION}"-mbstring php"${PHP_VERSION}"-xml php"${PHP_VERSION}"-pcov + +# install build dependencies +ci/ubuntu/setup.sh + +# build the project +export CC="ccache gcc" +export CXX="ccache g++" + +make cmakebuild_mapscript_php + +echo "PHP includes" + +php-config --includes + +cd "$WORK_DIR" + +make php-testcase + +echo "Done!" \ No newline at end of file diff --git a/scripts/build-mapscript-python.sh b/scripts/build-mapscript-python.sh new file mode 100755 index 0000000000..b2c83fa5ba --- /dev/null +++ b/scripts/build-mapscript-python.sh @@ -0,0 +1,61 @@ +#!/bin/bash +set -eu # Exit on error and treat unset variables as errors + +cd "$WORK_DIR" + +# Ensure the Python version is provided +if [ -z "${PYTHON_VERSION:-}" ]; then + echo "Error: Python version not specified. Make sure to pass it as an environment variable." + exit 1 +fi + +export DEBIAN_FRONTEND=noninteractive + +apt-get update -y + +# https://github.com/pyenv/pyenv/wiki#suggested-build-environment + +# general dependencies +apt-get install -y sudo software-properties-common wget + +# pyenv dependencies +apt-get install -y \ + build-essential libssl-dev zlib1g-dev \ + libbz2-dev libreadline-dev libsqlite3-dev curl git \ + libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev + +# install pyenv +curl https://pyenv.run | bash +# https://github.com/pyenv/pyenv?tab=readme-ov-file#b-set-up-your-shell-environment-for-pyenv + +# set up pyenv environment +export PYENV_ROOT="$HOME/.pyenv" +export PATH="$PYENV_ROOT/bin:$PATH" + +# initialize pyenv (for non-interactive shell) +eval "$(pyenv init --path)" +eval "$(pyenv init -)" + +# verify installation +pyenv --version + +# export CRYPTOGRAPHY_DONT_BUILD_RUST=1 # to avoid issue when building Cryptography python module +pyenv install -s "$PYTHON_VERSION" + +# set the global Python version +pyenv global $PYTHON_VERSION + +# install build dependencies +ci/ubuntu/setup.sh + +cd "$WORK_DIR" + +export CC="ccache gcc" +export CXX="ccache g++" + +# only build MapServer with the Python MapScript and not PHP, Perl etc. +make cmakebuild_mapscript_python MFLAGS="-j$(nproc)" CMAKE_C_FLAGS="-O2" CMAKE_CXX_FLAGS="-O2" LIBMAPSERVER_EXTRA_FLAGS="-Wall -Werror -Wextra" +# build the wheel and run the Python MapScript test suite +make mspython-wheel + +echo "Done!" \ No newline at end of file diff --git a/genhtml.patch b/scripts/coverage/genhtml.patch similarity index 100% rename from genhtml.patch rename to scripts/coverage/genhtml.patch diff --git a/run_code_coverage_upload.sh b/scripts/coverage/run_code_coverage_upload.sh similarity index 94% rename from run_code_coverage_upload.sh rename to scripts/coverage/run_code_coverage_upload.sh index 7dd6d3d985..d4a9fe2378 100755 --- a/run_code_coverage_upload.sh +++ b/scripts/coverage/run_code_coverage_upload.sh @@ -2,7 +2,7 @@ lcov --directory . --capture --output-file mapserver.info cp /usr/bin/genhtml . -# to remove date and occurences number, so that only real differences show up +# to remove date and occurrences number, so that only real differences show up patch -p0 < genhtml.patch ./genhtml -o ./mapserver_coverage_html --num-spaces 2 mapserver.info diff --git a/scripts/coverity-scan.sh b/scripts/coverity-scan.sh new file mode 100755 index 0000000000..6c5a8ca3e2 --- /dev/null +++ b/scripts/coverity-scan.sh @@ -0,0 +1,83 @@ +#!/bin/bash +set -eu # Exit on error and treat unset variables as errors + +# Ensure TOKEN is set +if [ -z "${TOKEN:-}" ]; then + echo "Error: TOKEN is not set. Make sure to pass it as an environment variable." + exit 1 +fi + +# first install necessary packages +apt-get update -y +apt-get install software-properties-common -y + +# Install libraries +apt-get update -y +apt-get install -y software-properties-common +add-apt-repository -y ppa:ubuntugis/ubuntugis-unstable +apt-get update -y + +apt-get install -y --allow-unauthenticated \ + protobuf-c-compiler libprotobuf-c-dev bison flex libfribidi-dev cmake \ + librsvg2-dev colordiff libpq-dev libpng-dev libjpeg-dev libgif-dev \ + libgeos-dev libfreetype6-dev libfcgi-dev libcurl4-gnutls-dev libcairo2-dev \ + libgdal-dev libproj-dev libxml2-dev libexempi-dev lcov lftp postgis \ + libharfbuzz-dev gdal-bin ccache curl \ + postgresql-server-dev-16 postgresql-16-postgis-3 postgresql-16-postgis-3-scripts \ + swig wget git jq + +# Build MapServer +cd "${WORK_DIR}" +git config --global --add safe.directory "${WORK_DIR}" + +mkdir build +touch src/maplexer.l +touch src/mapparser.y +flex --nounistd -Pmsyy -i -osrc/maplexer.c src/maplexer.l +yacc -d -osrc/mapparser.c src/mapparser.y +cd build +cmake -G "Unix Makefiles" \ + -DWITH_CLIENT_WMS=1 -DWITH_CLIENT_WFS=1 -DWITH_SOS=1 \ + -DWITH_PYTHON=0 -DWITH_JAVA=0 -DWITH_PERL=0 \ + -DWITH_FCGI=0 -DWITH_EXEMPI=1 -DWITH_KML=1 -DWITH_THREAD_SAFETY=1 \ + -DWITH_RSVG=1 -DWITH_CURL=1 -DWITH_FRIBIDI=1 -DWITH_HARFBUZZ=1 \ + .. + +# Download Coverity Build Tool +wget -q "https://scan.coverity.com/download/cxx/linux64" \ + --post-data "token=$TOKEN&project=mapserver%2Fmapserver" \ + -O cov-analysis-linux64.tar.gz +mkdir -p cov-analysis-linux64 +tar xzf cov-analysis-linux64.tar.gz --strip 1 -C cov-analysis-linux64 + +# Build with cov-build +export PATH=`pwd`/cov-analysis-linux64/bin:$PATH +cov-build --dir cov-int make +tar czf cov-int.tgz cov-int + +## Below from https://scan.coverity.com/projects/mapserver-mapserver/builds/new + +# Initialize a build. Fetch a cloud upload url. +curl -X POST \ + -d version=main \ + -d description="$(git rev-parse --abbrev-ref HEAD) $(git rev-parse --short HEAD)" \ + -d token="$TOKEN" \ + -d email=steve.lime@state.mn.us \ + -d file_name="cov-int.tgz" \ + https://scan.coverity.com/projects/1409/builds/init \ + | tee response + +# Store response data to use in later stages. +upload_url=$(jq -r '.url' response) +build_id=$(jq -r '.build_id' response) + +# Upload the tarball to the Cloud. +curl -X PUT \ + --header 'Content-Type: application/json' \ + --upload-file cov-int.tgz \ + $upload_url + +# Trigger the build on Scan. +curl -X PUT \ + -d token="$TOKEN" \ + https://scan.coverity.com/projects/1409/builds/$build_id/enqueue diff --git a/scripts/cppcheck.sh b/scripts/cppcheck.sh new file mode 100755 index 0000000000..7509ec8e6b --- /dev/null +++ b/scripts/cppcheck.sh @@ -0,0 +1,391 @@ +#!/bin/bash +apt-get update -y +apt-get install -y cppcheck + +cppcheck --version + +LOG_FILE=/tmp/cppcheck_mapserver.txt + +SCRIPT_DIR=$(dirname "$0") +case $SCRIPT_DIR in + "/"*) + ;; + ".") + SCRIPT_DIR=$(pwd) + ;; + *) + SCRIPT_DIR=$(pwd)/$(dirname "$0") + ;; +esac + +TOPDIR="$SCRIPT_DIR/../src" + +CPPCHECK_VERSION="$(cppcheck --version | awk '{print $2}')" +CPPCHECK_VERSION="$(cppcheck --version | awk '{print $2}')" +CPPCHECK_MAJOR_VERSION=$(echo "$CPPCHECK_VERSION" | cut -d. -f1) +CPPCHECK_MINOR_VERSION=$(echo "$CPPCHECK_VERSION" | cut -d. -f2) +CPPCHECK_VERSION=$(("$CPPCHECK_MAJOR_VERSION" * 100 + "$CPPCHECK_MINOR_VERSION")) +CPPCHECK_VERSION_GT_2_7=$(expr "$CPPCHECK_VERSION" \>= 207 || /bin/true) +if test "$CPPCHECK_VERSION_GT_2_7" = 1; then + POSIX="--library=gnu" +else + POSIX="--std=posix" +fi + +echo "" > ${LOG_FILE} +for dirname in ${TOPDIR}/.; do + echo "Running cppcheck on $dirname ... (can be long)" + if ! cppcheck --inline-suppr --template='{file}:{line},{severity},{id},{message}' \ + --enable=all --inconclusive --std=c99 --std=c++11 ${POSIX} \ + "-I${TOPDIR}" \ + -DUSE_CURL -DUSE_CAIRO -DUSE_RSVG -DUSE_ICONV -DUSE_FRIBIDI -DUSE_HARFBUZZ -DUSE_EXEMPI -DUSE_GEOS -DUSE_LIBXML2 -DUSE_THREAD -DUSE_FASTCGI -DUSE_WFS_LYR -DUSE_WMS_LYR \ + -DGEOS_VERSION_MAJOR=3 -DGEOS_VERSION_MINOR=8 \ + -DRETURN_FALSE="return false" \ + -Dcppcheck_assert=assert \ + "$dirname" \ + -j 8 >>${LOG_FILE} 2>&1 ; then + echo "cppcheck failed" + exit 1 + fi +done + +ret_code=0 + +# exclude logs matching patterns below, and write to temporary file +grep -v "unmatchedSuppression" ${LOG_FILE} \ + | grep -v "/renderers/agg" \ + | grep -v "/third-party" \ + | grep -v "/build" \ + | grep -v "yacc.c" \ + | grep -v "maplexer.c" \ + > ${LOG_FILE}.tmp +mv ${LOG_FILE}.tmp ${LOG_FILE} + +if grep "null pointer" ${LOG_FILE} ; then + echo "Null pointer check failed" + ret_code=1 +fi + +if grep "duplicateBreak" ${LOG_FILE} ; then + echo "duplicateBreak check failed" + ret_code=1 +fi + +if grep "duplicateBranch" ${LOG_FILE} ; then + echo "duplicateBranch check failed" + ret_code=1 +fi + +if grep "uninitMemberVar" ${LOG_FILE} ; then + echo "uninitMemberVar check failed" + ret_code=1 +fi + +if grep "useInitializationList" ${LOG_FILE} ; then + echo "uninitMemberVar check failed" + ret_code=1 +fi + +if grep "clarifyCalculation" ${LOG_FILE} ; then + echo "clarifyCalculation check failed" + ret_code=1 +fi + +if grep "invalidPrintfArgType_uint" ${LOG_FILE} ; then + echo "invalidPrintfArgType_uint check failed" + ret_code=1 +fi + +if grep "catchExceptionByValue" ${LOG_FILE} ; then + echo "catchExceptionByValue check failed" + ret_code=1 +fi + +if grep "memleakOnRealloc" ${LOG_FILE} ; then + echo "memleakOnRealloc check failed" + ret_code=1 +fi + +if grep "arrayIndexOutOfBoundsCond" ${LOG_FILE} ; then + echo "arrayIndexOutOfBoundsCond check failed" + ret_code=1 +fi + +if grep "arrayIndexOutOfBounds," ${LOG_FILE} ; then + echo "arrayIndexOutOfBounds check failed" + ret_code=1 +fi + +if grep "syntaxError" ${LOG_FILE} | grep -v "is invalid C code" ; then + echo "syntaxError check failed" + ret_code=1 +fi + +if grep "memleak," ${LOG_FILE} ; then + echo "memleak check failed" + ret_code=1 +fi + +if grep "eraseDereference" ${LOG_FILE} ; then + echo "eraseDereference check failed" + ret_code=1 +fi + +if grep "memsetClass," ${LOG_FILE} ; then + echo "memsetClass check failed" + ret_code=1 +fi + +if grep "uninitvar," ${LOG_FILE} ; then + echo "uninitvar check failed" + ret_code=1 +fi + +if grep "uninitdata," ${LOG_FILE} ; then + echo "uninitdata check failed" + ret_code=1 +fi + +if grep "va_list_usedBeforeStarted" ${LOG_FILE} ; then + echo "va_list_usedBeforeStarted check failed" + ret_code=1 +fi + +if grep "duplInheritedMember" ${LOG_FILE} ; then + echo "duplInheritedMember check failed" + ret_code=1 +fi + +if grep "terminateStrncpy" ${LOG_FILE} ; then + echo "terminateStrncpy check failed" + ret_code=1 +fi + +if grep "operatorEqVarError" ${LOG_FILE} ; then + echo "operatorEqVarError check failed" + ret_code=1 +fi + +if grep "uselessAssignmentPtrArg" ${LOG_FILE} ; then + echo "uselessAssignmentPtrArg check failed" + ret_code=1 +fi + +if grep "bufferNotZeroTerminated" ${LOG_FILE} ; then + echo "bufferNotZeroTerminated check failed" + ret_code=1 +fi + +if grep "sizeofDivisionMemfunc" ${LOG_FILE} ; then + echo "sizeofDivisionMemfunc check failed" + ret_code=1 +fi + +if grep "selfAssignment" ${LOG_FILE} ; then + echo "selfAssignment check failed" + ret_code=1 +fi + +if grep "invalidPrintfArgType_sint" ${LOG_FILE} ; then + echo "invalidPrintfArgType_sint check failed" + ret_code=1 +fi + +if grep "redundantAssignInSwitch" ${LOG_FILE} ; then + echo "redundantAssignInSwitch check failed" + ret_code=1 +fi + +if grep "publicAllocationError" ${LOG_FILE} ; then + echo "publicAllocationError check failed" + ret_code=1 +fi + +if grep "invalidScanfArgType_int" ${LOG_FILE} ; then + echo "invalidScanfArgType_int check failed" + ret_code=1 +fi + +if grep "invalidscanf," ${LOG_FILE} ; then + echo "invalidscanf check failed" + ret_code=1 +fi + +if grep "moduloAlwaysTrueFalse" ${LOG_FILE} ; then + echo "moduloAlwaysTrueFalse check failed" + ret_code=1 +fi + +if grep "charLiteralWithCharPtrCompare" ${LOG_FILE} ; then + echo "charLiteralWithCharPtrCompare check failed" + ret_code=1 +fi + +if grep "noConstructor" ${LOG_FILE} ; then + echo "noConstructor check failed" + ret_code=1 +fi + +if grep "noExplicitConstructor" ${LOG_FILE} ; then + echo "noExplicitConstructor check failed" + ret_code=1 +fi + +if grep "noCopyConstructor" ${LOG_FILE} ; then + echo "noCopyConstructor check failed" + ret_code=1 +fi + +if grep "passedByValue" ${LOG_FILE} ; then + echo "passedByValue check failed" + ret_code=1 +fi + +if grep "postfixOperator" ${LOG_FILE} ; then + echo "postfixOperator check failed" + ret_code=1 +fi + +if grep "redundantCopy" ${LOG_FILE} ; then + echo "redundantCopy check failed" + ret_code=1 +fi + +if grep "stlIfStrFind" ${LOG_FILE} ; then + echo "stlIfStrFind check failed" + ret_code=1 +fi + +if grep "functionStatic" ${LOG_FILE} ; then + echo "functionStatic check failed" + ret_code=1 +fi + +if grep "knownConditionTrueFalse" ${LOG_FILE} ; then + echo "knownConditionTrueFalse check failed" + ret_code=1 +fi + +if grep "arrayIndexThenCheck" ${LOG_FILE} ; then + echo "arrayIndexThenCheck check failed" + ret_code=1 +fi + +if grep "unusedPrivateFunction" ${LOG_FILE} ; then + echo "unusedPrivateFunction check failed" + ret_code=1 +fi + +if grep "redundantCondition" ${LOG_FILE} ; then + echo "redundantCondition check failed" + ret_code=1 +fi + +if grep "unusedStructMember" ${LOG_FILE} ; then + echo "unusedStructMember check failed" + ret_code=1 +fi + +if grep "multiCondition" ${LOG_FILE} ; then + echo "multiCondition check failed" + ret_code=1 +fi + +if grep "duplicateExpression" ${LOG_FILE} ; then + echo "duplicateExpression check failed" + ret_code=1 +fi + +if grep "operatorEq" ${LOG_FILE} ; then + echo "operatorEq check failed" + ret_code=1 +fi + +if grep "truncLongCastAssignment" ${LOG_FILE} ; then + echo "truncLongCastAssignment check failed" + ret_code=1 +fi + +if grep "exceptRethrowCopy" ${LOG_FILE} ; then + echo "exceptRethrowCopy check failed" + ret_code=1 +fi + +if grep "unusedVariable" ${LOG_FILE} ; then + echo "unusedVariable check failed" + ret_code=1 +fi + +if grep "unsafeClassCanLeak" ${LOG_FILE} ; then + echo "unsafeClassCanLeak check failed" + ret_code=1 +fi + +if grep "unsignedLessThanZero" ${LOG_FILE} ; then + echo "unsignedLessThanZero check failed" + ret_code=1 +fi + +if grep "unpreciseMathCall" ${LOG_FILE} ; then + echo "unpreciseMathCall check failed" + ret_code=1 +fi + +if grep "unreachableCode" ${LOG_FILE} ; then + echo "unreachableCode check failed" + ret_code=1 +fi + +if grep "clarifyCondition" ${LOG_FILE} ; then + echo "clarifyCondition check failed" + ret_code=1 +fi + +if grep "redundantIfRemove" ${LOG_FILE} ; then + echo "redundantIfRemove check failed" + ret_code=1 +fi + +if grep "unassignedVariable" ${LOG_FILE} ; then + echo "unassignedVariable check failed" + ret_code=1 +fi + +if grep "redundantAssignment" ${LOG_FILE} ; then + echo "redundantAssignment check failed" + ret_code=1 +fi + +if grep "unreadVariable" ${LOG_FILE} ; then + echo "unreadVariable check failed" + ret_code=1 +fi + +if grep "AssignmentAddressToInteger" ${LOG_FILE} ; then + echo "AssignmentAddressToInteger check failed" + ret_code=1 +fi + + +# Check any remaining errors +if grep "error," ${LOG_FILE} | grep -v "uninitvar" | \ + grep -v "memleak," | grep -v "memleakOnRealloc" | \ + grep -v "is invalid C code" ; then + + echo "Errors check failed" + ret_code=1 +fi + +# Check any remaining warnings +if grep "warning," ${LOG_FILE}; then + echo "Warnings check failed" + ret_code=1 +fi + +if [ ${ret_code} = 0 ]; then + echo "cppcheck succeeded" +fi + +# temporarily pass all checks +# exit ${ret_code} +exit 0 diff --git a/scripts/docker/Dockerfile b/scripts/docker/Dockerfile index 12e9ef7ddb..b1591e5b73 100644 --- a/scripts/docker/Dockerfile +++ b/scripts/docker/Dockerfile @@ -115,7 +115,6 @@ RUN cd /build && \ -DWITH_KML=ON \ -DWITH_LIBXML2=ON \ -DWITH_OGR=ON \ - -DWITH_POINT_Z_M=ON \ -DWITH_PROJ=ON \ -DWITH_SOS=ON \ -DWITH_THREAD_SAFETY=ON \ @@ -147,7 +146,7 @@ RUN cd /build && \ # && wget http://download.osgeo.org/proj/vdatum/egm08_25/egm08_25.gtx && mv egm08_25.gtx /usr/share/proj \ # && rm -rf /vdatum -# Force buit libraries dependencies +# Update given built libraries dependencies RUN ldconfig # Enable these Apache modules @@ -161,4 +160,4 @@ ENV HOST_IP `ifconfig | grep inet | grep Mask:255.255.255.0 | cut -d ' ' -f 12 | CMD sudo service apache2 start && bash -USER msuser \ No newline at end of file +USER msuser diff --git a/scripts/docker/Dockerfile_mapcache b/scripts/docker/Dockerfile_mapcache index 7d60f483c6..f90cf16a2b 100644 --- a/scripts/docker/Dockerfile_mapcache +++ b/scripts/docker/Dockerfile_mapcache @@ -115,7 +115,6 @@ RUN cd /build && \ -DWITH_KML=ON \ -DWITH_LIBXML2=ON \ -DWITH_OGR=ON \ - -DWITH_POINT_Z_M=ON \ -DWITH_PROJ=ON \ -DWITH_SOS=ON \ -DWITH_THREAD_SAFETY=ON \ @@ -163,7 +162,7 @@ RUN cd /build \ # && wget http://download.osgeo.org/proj/vdatum/egm08_25/egm08_25.gtx && mv egm08_25.gtx /usr/share/proj \ # && rm -rf /vdatum -# Force buit libraries dependencies +# Update given built libraries dependencies RUN ldconfig # Apache configuration for mapcache @@ -187,4 +186,4 @@ ENV HOST_IP `ifconfig | grep inet | grep Mask:255.255.255.0 | cut -d ' ' -f 12 | CMD sudo service apache2 start && bash -USER msuser \ No newline at end of file +USER msuser diff --git a/scripts/docker/Dockerfile_oracle_mapcache b/scripts/docker/Dockerfile_oracle_mapcache index 26e0206437..9a76dfa930 100644 --- a/scripts/docker/Dockerfile_oracle_mapcache +++ b/scripts/docker/Dockerfile_oracle_mapcache @@ -127,7 +127,6 @@ RUN cd /build && \ -DWITH_LIBXML2=ON \ -DWITH_OGR=ON \ -DWITH_ORACLESPATIAL=ON \ - -DWITH_POINT_Z_M=ON \ -DWITH_PROJ=ON \ -DWITH_SOS=ON \ -DWITH_THREAD_SAFETY=ON \ @@ -175,7 +174,7 @@ RUN cd /build \ # && wget http://download.osgeo.org/proj/vdatum/egm08_25/egm08_25.gtx && mv egm08_25.gtx /usr/share/proj \ # && rm -rf /vdatum -# Force buit libraries dependencies +# Update given built libraries dependencies RUN ldconfig # Apache configuration for mapcache @@ -199,4 +198,4 @@ ENV HOST_IP `ifconfig | grep inet | grep Mask:255.255.255.0 | cut -d ' ' -f 12 | CMD sudo service apache2 start && bash -USER msuser \ No newline at end of file +USER msuser diff --git a/scripts/fix_typos.sh b/scripts/fix_typos.sh new file mode 100755 index 0000000000..6c04a0a0ef --- /dev/null +++ b/scripts/fix_typos.sh @@ -0,0 +1,70 @@ +#!/bin/sh +# -*- coding: utf-8 -*- +############################################################################### +# $Id$ +# +# Project: GDAL +# Purpose: (Interactive) script to identify and fix typos +# Author: Even Rouault +# +############################################################################### +# Copyright (c) 2016, Even Rouault +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +############################################################################### + +set -eu + +SCRIPT_DIR=$(dirname "$0") +case $SCRIPT_DIR in + "/"*) + ;; + ".") + SCRIPT_DIR=$(pwd) + ;; + *) + SCRIPT_DIR=$(pwd)"/"$(dirname "$0") + ;; +esac +GDAL_ROOT=$SCRIPT_DIR/.. +cd "$GDAL_ROOT" + +if ! test -d fix_typos; then + # Get our fork of codespell that adds --words-white-list and full filename support for -S option + mkdir fix_typos + (cd fix_typos + git clone https://github.com/rouault/codespell + (cd codespell && git checkout gdal_improvements) + # Aggregate base dictionary + QGIS one + Debian Lintian one + curl https://raw.githubusercontent.com/qgis/QGIS/master/scripts/spell_check/spelling.dat | sed "s/:/->/" | sed "s/:%//" | grep -v "colour->" | grep -v "colours->" > qgis.txt + curl https://salsa.debian.org/lintian/lintian/-/raw/master/data/spelling/corrections | grep "||" | grep -v "#" | sed "s/||/->/" > debian.txt + cat codespell/data/dictionary.txt qgis.txt debian.txt | awk 'NF' > gdal_dict.txt + echo "difered->deferred" >> gdal_dict.txt + echo "differed->deferred" >> gdal_dict.txt + grep -v 404 < gdal_dict.txt > gdal_dict.txt.tmp + mv gdal_dict.txt.tmp gdal_dict.txt + ) +fi + +EXCLUDED_FILES="**/.git/*,*.pdf,*.svg,*.phar,*.dat*,./scripts/fix_typos.sh,src/mapscript/java/makefile.vc,src/mapscript/csharp/Makefile.vc,src/opengl/*,msautotest/api/test.json,msautotest/api/out.html,msautotest/php/maps/etc/vera/COPYRIGHT.TXT" +AUTHORIZED_LIST="CPL_SUPRESS_CPLUSPLUS,unpreciseMathCall,koordinates,msMetadataFreeParmsObj,metres,kilometre,kilometres,iColorParm,FO,Cartesian,msOWSPrintLatLonBoundingBox,msWFSFreeParmsObj,TeGenerateArc,TeGeometryAlgorithm,msProjectHasLonWrapOrOver,msProjectHasLonWrap,pdfLonWrap,dfLonWrap,LatLonBox,latLonBoxNode,ESPACE,MSUVRASTER_LON,needsLonLat,reprojectorToLonLat,lon,bHasLonWrap,LatLonBoundingBox,GEOSBUF_JOIN_MITRE,HB_VERSION_ATLEAST,msBuildRequestParms,E_GIF_ERR_NOT_WRITEABLE,WriteableBitmap,RUN_PARMS" + +python3 fix_typos/codespell/codespell.py -w -i 3 -q 2 -S "$EXCLUDED_FILES,./build*/*" \ + -x scripts/typos_allowlist.txt --words-white-list=$AUTHORIZED_LIST \ + -D ./fix_typos/gdal_dict.txt src msautotest diff --git a/install-msautotest.sh b/scripts/install-msautotest.sh similarity index 100% rename from install-msautotest.sh rename to scripts/install-msautotest.sh diff --git a/scripts/mapaxisorder/create_mapaxisorder_csv.py b/scripts/mapaxisorder/create_mapaxisorder_csv.py new file mode 100644 index 0000000000..3e0de1f722 --- /dev/null +++ b/scripts/mapaxisorder/create_mapaxisorder_csv.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python +############################################################################### +# Project: MapServer +# Purpose: Generate the list of EPSG SRS codes that need axis inversion +# Author: Even Rouault /dev/null ; } diff --git a/release-notes.sh b/scripts/release/release-notes.sh similarity index 100% rename from release-notes.sh rename to scripts/release/release-notes.sh diff --git a/release.sh b/scripts/release/release.sh similarity index 94% rename from release.sh rename to scripts/release/release.sh index 2a7a0f90a9..5892fc68a7 100755 --- a/release.sh +++ b/scripts/release/release.sh @@ -25,7 +25,7 @@ fi echo "#" echo "# make sure:" echo "# - you are on branch-$ms_version_major-$ms_version_minor" -echo "# - you have edited HISTORY.TXT with changes related to this release" +echo "# - you have edited HISTORY.md with changes related to this release" echo "#" echo "" @@ -38,7 +38,7 @@ else echo "sed -i '/set (MapServer_VERSION_SUFFIX/c\set (MapServer_VERSION_SUFFIX \"\")' CMakeLists.txt" fi -echo "git add HISTORY.TXT CMakeLists.txt" +echo "git add HISTORY.md CMakeLists.txt" echo "git commit -m \"update for $ms_version release\"" echo "git tag -a $tagname -m \"Create $ms_version tag\"" echo "git push origin branch-$ms_version_major-$ms_version_minor --tags" diff --git a/stablemerge.sh b/scripts/stablemerge.sh similarity index 100% rename from stablemerge.sh rename to scripts/stablemerge.sh diff --git a/scripts/typos_allowlist.txt b/scripts/typos_allowlist.txt new file mode 100644 index 0000000000..e747a73056 --- /dev/null +++ b/scripts/typos_allowlist.txt @@ -0,0 +1,18 @@ +- memory leak in msInsertLayer, from Ned Harding (#2784) +- mapwcs.c: fix lonLatEnvelope/@srsName (#2507) + * FORMATOPTION "POLYMOUSEOUT=return nd();" + if ((strstr(outstr, "lat]") || strstr(outstr, "lon]") || + "long-axis", "lon", "lon_axis", "lon-axis", NULL}; +#define MSUVRASTER_LON "lon" +const char *_ms_script_prefix_te = "te:"; + {"ang", 8736}, {"aring", 229}, {"asymp", 8776}, {"atilde", 227}, + {"curren", 164}, {"dArr", 8659}, {"dagger", 8224}, {"darr", 8595}, +Node BA + text "colision after retry because of second bend" + text "SmalL#label#multiline" + text "LargE#label" + text "SmalL" + text "LargE" + "wms_style_title.ger" "INSPIRE Standard Stil" + "wms_style_inspire_common:DEFAULT_title.ger" "INSPIRE Standard Stil" + INSPIRE Standard Stil diff --git a/scripts/vagrant/mapserver.sh b/scripts/vagrant/mapserver.sh index bb5178c0dd..07ccfdddfc 100755 --- a/scripts/vagrant/mapserver.sh +++ b/scripts/vagrant/mapserver.sh @@ -6,38 +6,23 @@ export NUMTHREADS cd /vagrant cd msautotest -python -m SimpleHTTPServer &> /dev/null & +python -m http.server &> /dev/null & cd .. mkdir build_vagrant -touch maplexer.l -touch mapparser.y -flex --nounistd -Pmsyy -i -omaplexer.c maplexer.l -yacc -d -omapparser.c mapparser.y +touch src/maplexer.l +touch src/mapparser.y +flex --nounistd -Pmsyy -i -osrc/maplexer.c src/maplexer.l +yacc -d -osrc/mapparser.c src/mapparser.y cd build_vagrant cmake -G "Unix Makefiles" -DWITH_CLIENT_WMS=1 \ - -DWITH_CLIENT_WFS=1 -DWITH_KML=1 -DWITH_SOS=1 -DWITH_PHP=1 \ - -DWITH_PYTHON=1 -DWITH_JAVA=0 -DWITH_THREAD_SAFETY=1 \ + -DWITH_CLIENT_WFS=1 -DWITH_KML=1 -DWITH_SOS=1 -DWITH_PHPNG=1 \ + -DWITH_PYTHON=1 -DWITH_JAVA=0 -DWITH_PERL=1 -DWITH_THREAD_SAFETY=1 \ -DWITH_FCGI=0 -DWITH_EXEMPI=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo \ -DWITH_RSVG=1 -DWITH_CURL=1 -DWITH_FRIBIDI=1 -DWITH_HARFBUZZ=1 \ - -DPROJ_INCLUDE_DIR=/vagrant/install-vagrant-proj-6/include_proj4_api_only -DPROJ_LIBRARY=/vagrant/install-vagrant-proj-6/lib/libproj.so.15 \ - -DCMAKE_C_FLAGS="-DACCEPT_USE_OF_DEPRECATED_PROJ_API_H -DPROJ_RENAME_SYMBOLS" -DCMAKE_CXX_FLAGS="-DACCEPT_USE_OF_DEPRECATED_PROJ_API_H -DPROJ_RENAME_SYMBOLS" \ + -DWITH_CSHARP=1 \ .. make -j $NUMTHREADS sudo make install cd .. - -mkdir build_vagrant_proj6 -cd build_vagrant_proj6 -cmake -G "Unix Makefiles" -DWITH_CLIENT_WMS=1 \ - -DWITH_CLIENT_WFS=1 -DWITH_KML=1 -DWITH_SOS=1 -DWITH_PHP=1 \ - -DWITH_PYTHON=1 -DWITH_JAVA=0 -DWITH_THREAD_SAFETY=1 \ - -DWITH_FCGI=0 -DWITH_EXEMPI=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo \ - -DWITH_RSVG=1 -DWITH_CURL=1 -DWITH_FRIBIDI=1 -DWITH_HARFBUZZ=1 \ - -DPROJ_INCLUDE_DIR=/vagrant/install-vagrant-proj-6/include -DPROJ_LIBRARY=/vagrant/install-vagrant-proj-6/lib/libproj.so.15 \ - -DCMAKE_C_FLAGS="-DPROJ_RENAME_SYMBOLS" -DCMAKE_CXX_FLAGS="-DPROJ_RENAME_SYMBOLS" \ - .. - -make -j $NUMTHREADS -cd .. diff --git a/scripts/vagrant/msautotest.sh b/scripts/vagrant/msautotest.sh new file mode 100644 index 0000000000..c38e3f02e1 --- /dev/null +++ b/scripts/vagrant/msautotest.sh @@ -0,0 +1,6 @@ +#!/bin/sh + +cd /vagrant/msautotest + +# copy custom projection to the PROJ_DATA folder +sudo cp ./wxs/data/epsg2 /usr/share/proj/ diff --git a/scripts/vagrant/packages.sh b/scripts/vagrant/packages.sh index a4d2f3749f..52ef294383 100755 --- a/scripts/vagrant/packages.sh +++ b/scripts/vagrant/packages.sh @@ -1,27 +1,24 @@ #!/bin/sh -sed -i 's#deb http://us.archive.ubuntu.com/ubuntu/#deb mirror://mirrors.ubuntu.com/mirrors.txt#' /etc/apt/sources.list - export DEBIAN_FRONTEND=noninteractive +apt-get install -y software-properties-common +add-apt-repository -y ppa:ubuntugis/ubuntugis-unstable + +sed -i 's#deb http://us.archive.ubuntu.com/ubuntu/#deb mirror://mirrors.ubuntu.com/mirrors.txt#' /etc/apt/sources.list apt-get update -apt-get install -y python-software-properties -add-apt-repository -y ppa:ubuntugis/ppa -add-apt-repository -y ppa:ubuntugis/ubuntugis-testing -add-apt-repository -y ppa:dluxen/cmake-backports -apt-get update -apt-get -y upgrade # install packages we need -apt-get install -q -y git build-essential pkg-config cmake3 libgeos-dev rake \ - libpq-dev python-all-dev libproj-dev libxml2-dev postgis php5-dev \ - postgresql-server-dev-9.3 postgresql-9.3-postgis-2.2 vim bison flex swig \ - librsvg2-dev libpng12-dev libjpeg-dev libgif-dev \ +apt-get install -q -y git build-essential pkg-config cmake libgeos-dev rake \ + libpq-dev python3-dev python3-pip python3-venv libproj-dev libxml2-dev postgis php-dev \ + postgresql-server-dev-16 postgresql-16-postgis-3 postgresql-16-postgis-3-scripts vim bison flex swig \ + librsvg2-dev libpng-dev libjpeg-dev libgif-dev \ libfreetype6-dev libfcgi-dev libcurl4-gnutls-dev libcairo2-dev \ - libgdal1-dev libfribidi-dev libexempi-dev \ - libprotobuf-dev libprotobuf-c0-dev protobuf-c-compiler libharfbuzz-dev gdal-bin \ - curl sqlite3 + libgdal-dev libfribidi-dev libexempi-dev \ + libprotobuf-dev libprotobuf-c-dev protobuf-c-compiler libharfbuzz-dev gdal-bin \ + curl sqlite3 libperl-dev python-is-python3 \ + libmono-system-drawing4.0-cil mono-mcs # for csharp bindings -curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py -python get-pip.py -pip install -U -r /vagrant/msautotest/requirements.txt +export PIP_BREAK_SYSTEM_PACKAGES=true +export PIP_NO_WARN_SCRIPT_LOCATION=true +python -m pip install -r /vagrant/msautotest/requirements.txt diff --git a/scripts/vagrant/postgis.sh b/scripts/vagrant/postgis.sh index 41bb08246f..3bc29e39d0 100755 --- a/scripts/vagrant/postgis.sh +++ b/scripts/vagrant/postgis.sh @@ -2,9 +2,9 @@ cd /vagrant/msautotest -sed -i 's/md5/trust/' /etc/postgresql/9.3/main/pg_hba.conf -sed -i 's/peer/trust/' /etc/postgresql/9.3/main/pg_hba.conf +sed -i 's/md5/trust/' /etc/postgresql/16/main/pg_hba.conf +sed -i 's/peer/trust/' /etc/postgresql/16/main/pg_hba.conf -service postgresql restart +service postgresql restart 16 ./create_postgis_test_data.sh diff --git a/scripts/vagrant/proj6.sh b/scripts/vagrant/proj6.sh deleted file mode 100755 index 6ec73b65fd..0000000000 --- a/scripts/vagrant/proj6.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash - -set -eu - -NUMTHREADS=$(nproc) -export NUMTHREADS - -cd /vagrant -curl -s http://download.osgeo.org/proj/proj-6.1.1.tar.gz > proj-6.1.1.tar.gz -tar xzf proj-6.1.1.tar.gz -rm -rf vagrant-proj -rm -rf /vagrant/install-vagrant-proj-6 -mv proj-6.1.1 vagrant-proj -(cd vagrant-proj/data && curl -s http://download.osgeo.org/proj/proj-datumgrid-1.8.tar.gz > proj-datumgrid-1.8.tar.gz && tar xvzf proj-datumgrid-1.8.tar.gz) -(cd vagrant-proj; CFLAGS='-DPROJ_RENAME_SYMBOLS -O2' CXXFLAGS='-DPROJ_RENAME_SYMBOLS -O2' ./configure --disable-static --prefix=/vagrant/install-vagrant-proj-6 && make -j $NUMTHREADS && make -j $NUMTHREADS install) -cp -r /vagrant/install-vagrant-proj-6/include /vagrant/install-vagrant-proj-6/include_proj4_api_only -rm -f /vagrant/install-vagrant-proj-6/include_proj4_api_only/proj.h diff --git a/scripts/vagrant/virtualbox-fix.sh b/scripts/vagrant/virtualbox-fix.sh deleted file mode 100755 index 4e0cf7e3aa..0000000000 --- a/scripts/vagrant/virtualbox-fix.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh - -if [ ! -e "/usr/lib/VBoxGuestAdditions" ]; then - ln -s /opt/VBoxGuestAdditions-4.3.10/lib/VBoxGuestAdditions /usr/lib/VBoxGuestAdditions -fi diff --git a/share/ogcapi/templates/html-bootstrap/collection-item.html b/share/ogcapi/templates/html-bootstrap/collection-item.html new file mode 100644 index 0000000000..ffe7dd0f51 --- /dev/null +++ b/share/ogcapi/templates/html-bootstrap/collection-item.html @@ -0,0 +1,46 @@ +{% include "header.html" %} + + + +

{{ template.title }} - Collection Item: {{ response.collection.title }}

+ +
+
+

Properties

+
    +
  • ID: {{ response.id }}
  • + {% for key, value in response.properties %} +
  • {{ key }}: {{ value }}
  • + {% endfor %} +
+
+
+
Loading...
+
+
+ + + +{% include "footer.html" %} diff --git a/share/ogcapi/templates/html-bootstrap/collection-items.html b/share/ogcapi/templates/html-bootstrap/collection-items.html new file mode 100644 index 0000000000..6cb7429c5f --- /dev/null +++ b/share/ogcapi/templates/html-bootstrap/collection-items.html @@ -0,0 +1,315 @@ +{% include "header.html" %} + +{% set show_prev_link = false %} +{% set show_next_link = false %} +{% for link in response.links %} + {% if link.rel == "alternate" %}{% set json_link = link %}{% endif %} + {% if link.rel == "prev" %}{% set prev_link = link %}{% set show_prev_link = true %}{% endif %} + {% if link.rel == "next" %}{% set next_link = link %}{% set show_next_link = true %}{% endif %} +{% endfor %} + + + +

{{ template.title }} - Collection Items: {{ response.collection.title }}

+ +
Loading...
+ +

+ Number of matching items: {{ response.numberMatched }}
+ Number of returned items: {{ response.numberReturned }}
+ Page: of
+

+ +
+ {% if show_prev_link == true %} + + {% endif %} +
+ +
+ {% if show_next_link == true %} + + {% endif %} +
+ + Clear filters +
+
+
+ + + + +{% if response.features %} +{% for key, value in response.features.0.properties %} + +{% endfor %} +{% endif %} + + + +{% if response.features %} +{% for key, value in response.features.0.properties %} + +{% endfor %} +{% endif %} + + + +{% for feature in response.features %} + + + {% for key, value in feature.properties %} + + {% endfor %} + +{% endfor %} + +
ID{{ key }}
{{ feature.id }}{{ value }}
+
+ + + +{% include "footer.html" %} diff --git a/share/ogcapi/templates/html-bootstrap/collection-queryables.html b/share/ogcapi/templates/html-bootstrap/collection-queryables.html new file mode 100644 index 0000000000..2e20328c0b --- /dev/null +++ b/share/ogcapi/templates/html-bootstrap/collection-queryables.html @@ -0,0 +1,35 @@ +{% include "header.html" %} + + + +

{{ template.title }} - Collection: {{ response.title }}

+ +

Queryables:

+ +
+
+
    + {% for key, value in response.properties %} +
  • {{ key }}: + {% if existsIn(value, "type") %} + {{ value.type }} + {% endif %} + {% if existsIn(value, "type") and existsIn(value, "format") %} + ,  + {% endif %} + {% if existsIn(value, "format") %} + {{ value.format }} + {% endif %} +
  • + {% endfor %} +
+
+
+ +{% include "footer.html" %} diff --git a/share/ogcapi/templates/html-bootstrap/collection-schema.html b/share/ogcapi/templates/html-bootstrap/collection-schema.html new file mode 100644 index 0000000000..d2c535a0a1 --- /dev/null +++ b/share/ogcapi/templates/html-bootstrap/collection-schema.html @@ -0,0 +1,35 @@ +{% include "header.html" %} + + + +

{{ template.title }} - Collection: {{ response.title }}

+ +

Schema:

+ +
+
+
    + {% for key, value in response.properties %} +
  • {{ key }}: + {% if existsIn(value, "type") %} + {{ value.type }} + {% endif %} + {% if existsIn(value, "type") and existsIn(value, "format") %} + ,  + {% endif %} + {% if existsIn(value, "format") %} + {{ value.format }} + {% endif %} +
  • + {% endfor %} +
+
+
+ +{% include "footer.html" %} diff --git a/share/ogcapi/templates/html-bootstrap/collection-sortables.html b/share/ogcapi/templates/html-bootstrap/collection-sortables.html new file mode 100644 index 0000000000..36ad3e640b --- /dev/null +++ b/share/ogcapi/templates/html-bootstrap/collection-sortables.html @@ -0,0 +1,35 @@ +{% include "header.html" %} + + + +

{{ template.title }} - Collection: {{ response.title }}

+ +

Sortables:

+ +
+
+
    + {% for key, value in response.properties %} +
  • {{ key }}: + {% if existsIn(value, "type") %} + {{ value.type }} + {% endif %} + {% if existsIn(value, "type") and existsIn(value, "format") %} + ,  + {% endif %} + {% if existsIn(value, "format") %} + {{ value.format }} + {% endif %} +
  • + {% endfor %} +
+
+
+ +{% include "footer.html" %} diff --git a/share/ogcapi/templates/html-bootstrap/collection.html b/share/ogcapi/templates/html-bootstrap/collection.html new file mode 100644 index 0000000000..3fbe0de633 --- /dev/null +++ b/share/ogcapi/templates/html-bootstrap/collection.html @@ -0,0 +1,78 @@ +{% include "header.html" %} + + + +

{{ template.title }} - Collection: {{ response.title }}

+ +
+
+ +

{{ response.description }}

+ {% if existsIn(response, "keywords") and length(response.keywords) > 0 %} +

+ {% for keyword in response.keywords %} + {{ keyword }} + {% endfor %} +

+ {% endif %} + + {% if existsIn(response, "storageCrs") %} +

Storage CRS: + {{ response.storageCrs }} +

+ {% endif %} + + {% if existsIn(response, "crs") %} +

+ Supported CRS: +

    + {% for href in response.crs %} +
  • {{ href }}
  • + {% endfor %} +
+

+ {% endif %} + +

Links

+ +
+
+
Loading...
+
+
+ + + +{% include "footer.html" %} diff --git a/share/ogcapi/templates/html-bootstrap/collections.html b/share/ogcapi/templates/html-bootstrap/collections.html new file mode 100644 index 0000000000..6d65ba3102 --- /dev/null +++ b/share/ogcapi/templates/html-bootstrap/collections.html @@ -0,0 +1,35 @@ +{% include "header.html" %} + + + +

{{ template.title }} - Collections

+ +
+ + + + + + + + + + +{%- for collection in response.collections %} + + + + + + +{% endfor -%} + +
#TitleTypeDescription
{{ loop.index1 }}{{ collection.title }}{{ collection.itemType }}{{ collection.description }}
+
+{%- include "footer.html" -%} diff --git a/share/ogcapi/templates/html-bootstrap/conformance.html b/share/ogcapi/templates/html-bootstrap/conformance.html new file mode 100644 index 0000000000..a833074cf8 --- /dev/null +++ b/share/ogcapi/templates/html-bootstrap/conformance.html @@ -0,0 +1,22 @@ +{% include "header.html" %} + + + +

{{ template.title }} - Conformance

+ +

This API implements the conformance classes from standards and community specifications that are listed below.

+ +

Links

+
    +{% for url in response.conformsTo %} +
  • {{ url }}
  • +{% endfor %} +
+ +{% include "footer.html" %} diff --git a/share/ogcapi/templates/html-bootstrap/debug.html b/share/ogcapi/templates/html-bootstrap/debug.html new file mode 100644 index 0000000000..04d5254b05 --- /dev/null +++ b/share/ogcapi/templates/html-bootstrap/debug.html @@ -0,0 +1,15 @@ +{% if existsIn(template.tags, "debug") %} + {% if template.tags.debug == "true" %} +
+

Template Data

+

+ API Root: {{ template.api_root }}
+ Path: {{ template.path }}
+ Params: {{ template.params }}
+ Extra Params: {{ {{ template.extra_params }}
+ Title: {{ template.title }}
+ Tags: {{ template.tags }}
+

+
+ {% endif %} +{% endif %} diff --git a/share/ogcapi/templates/html-bootstrap/footer.html b/share/ogcapi/templates/html-bootstrap/footer.html new file mode 100644 index 0000000000..d0c3e00a2c --- /dev/null +++ b/share/ogcapi/templates/html-bootstrap/footer.html @@ -0,0 +1,5 @@ + {% include "debug.html" %} + + + + diff --git a/share/ogcapi/templates/html-bootstrap/header.html b/share/ogcapi/templates/html-bootstrap/header.html new file mode 100644 index 0000000000..d3e3237e94 --- /dev/null +++ b/share/ogcapi/templates/html-bootstrap/header.html @@ -0,0 +1,71 @@ + + + + {{ template.title }} + + + + + + + + + + + + +
+
diff --git a/share/ogcapi/templates/html-bootstrap/landing.html b/share/ogcapi/templates/html-bootstrap/landing.html new file mode 100644 index 0000000000..d056740d76 --- /dev/null +++ b/share/ogcapi/templates/html-bootstrap/landing.html @@ -0,0 +1,22 @@ +{% include "header.html" %} + + + +

{{ response.title }}

+

+ {{ response.description }} +

+ +

Links

+ + +{% include "footer.html" %} diff --git a/share/ogcapi/templates/html-bootstrap/openapi.html b/share/ogcapi/templates/html-bootstrap/openapi.html new file mode 100644 index 0000000000..fb7ecbe443 --- /dev/null +++ b/share/ogcapi/templates/html-bootstrap/openapi.html @@ -0,0 +1,52 @@ + + + + + Swagger UI - {{ template.title }} + + + + + +
+ + + + + + diff --git a/share/ogcapi/templates/html-index-bootstrap/footer.html b/share/ogcapi/templates/html-index-bootstrap/footer.html new file mode 100644 index 0000000000..df60a12b9a --- /dev/null +++ b/share/ogcapi/templates/html-index-bootstrap/footer.html @@ -0,0 +1,4 @@ +
+
+ + diff --git a/share/ogcapi/templates/html-index-bootstrap/header.html b/share/ogcapi/templates/html-index-bootstrap/header.html new file mode 100644 index 0000000000..7690a11f4c --- /dev/null +++ b/share/ogcapi/templates/html-index-bootstrap/header.html @@ -0,0 +1,52 @@ + + + + MapServer Landing Page + + + + + + + + + +
+
diff --git a/share/ogcapi/templates/html-index-bootstrap/landing.html b/share/ogcapi/templates/html-index-bootstrap/landing.html new file mode 100644 index 0000000000..bfc87d0965 --- /dev/null +++ b/share/ogcapi/templates/html-index-bootstrap/landing.html @@ -0,0 +1,39 @@ +{% include "header.html" %} + +

MapServer Homepage

+

+ This page lists all available Mapfiles hosted by MapServer. +

+

Links

+
+ + + + + + + + + + + + + {% for link in response.linkset -%} + + + + + + + + + {% endfor %} + +
#KeyNameLayer CountHTML DocumentationJSON
{{ loop.index1 }}{{ link.key }}{{ link.title }}{{ link.layer-count }}{{ link.service-doc.0.title }}{{ link.service-desc.0.title }}
+
+{% include "footer.html" -%} \ No newline at end of file diff --git a/share/ogcapi/templates/html-index-bootstrap/map.html b/share/ogcapi/templates/html-index-bootstrap/map.html new file mode 100644 index 0000000000..62e22cfc04 --- /dev/null +++ b/share/ogcapi/templates/html-index-bootstrap/map.html @@ -0,0 +1,56 @@ +{% include "header.html" %} + +

MapServer Mapfile Landing Page

+
    +
  • Title: {{response.title}}
  • +
  • Layer Count: {{response.layer-count}}
  • +
  • Map Name: {{response.name}}
  • +
+

+ Below are all the services available for this Mapfile. +

+
+ + + + + + + + + + + {% set index = 1 -%} + {% for link in response.linkset -%} + {% if existsIn(link, "service-doc") -%} + {% for service in link.service-doc -%} + + + + + + + {% set index = index + 1 -%} + {% endfor -%} + {% endif -%} + {% if existsIn(link, "service-desc") -%} + {% for service in link.service-desc -%} + + + + + + + {% set index = index + 1 -%} + {% endfor -%} + {% endif -%} + {% endfor -%} + +
#TypeServiceTitle
{{ index }}{{ service.service }}{{ service.title }}{{ link.title }}
{{ index }}{{ service.service }}{{ service.title }}{{ link.title }}
+
+{% include "footer.html" -%} \ No newline at end of file diff --git a/share/ogcapi/templates/html-index-plain/footer.html b/share/ogcapi/templates/html-index-plain/footer.html new file mode 100644 index 0000000000..691287b6e3 --- /dev/null +++ b/share/ogcapi/templates/html-index-plain/footer.html @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/share/ogcapi/templates/html-index-plain/header.html b/share/ogcapi/templates/html-index-plain/header.html new file mode 100644 index 0000000000..aa9b875c8c --- /dev/null +++ b/share/ogcapi/templates/html-index-plain/header.html @@ -0,0 +1,7 @@ + + + + MapServer Landing Page + + + \ No newline at end of file diff --git a/share/ogcapi/templates/html-index-plain/landing.html b/share/ogcapi/templates/html-index-plain/landing.html new file mode 100644 index 0000000000..c1a8ec7aa3 --- /dev/null +++ b/share/ogcapi/templates/html-index-plain/landing.html @@ -0,0 +1,30 @@ +{% include "header.html" %} +

MapServer Homepage

+

+ This page lists all available Mapfiles hosted by MapServer. +

+ + + + + + + + + + + + + {% for link in response.linkset -%} + + + + + + + + + {% endfor %} + +
#KeyNameLayer CountHTML DocumentationJSON
{{ loop.index1 }}{{ link.key }}{{ link.title }}{{ link.layer-count }}{{ link.service-doc.0.title }}{{ link.service-desc.0.title }}
+{% include "footer.html" -%} diff --git a/share/ogcapi/templates/html-index-plain/map.html b/share/ogcapi/templates/html-index-plain/map.html new file mode 100644 index 0000000000..ac42e0c90c --- /dev/null +++ b/share/ogcapi/templates/html-index-plain/map.html @@ -0,0 +1,48 @@ +{% include "header.html" %} +

MapServer Mapfile Landing Page

+
    +
  • Title: {{response.title}}
  • +
  • Layer Count: {{response.layer-count}}
  • +
  • Map Name: {{response.name}}
  • +
+

+ Below are all the services available for this Mapfile. +

+ + + + + + + + + + + {% set index = 1 -%} + {% for link in response.linkset -%} + {% if existsIn(link, "service-doc") -%} + {% for service in link.service-doc -%} + + + + + + + {% set index = index + 1 -%} + {% endfor -%} + {% endif -%} + {% if existsIn(link, "service-desc") -%} + {% for service in link.service-desc -%} + + + + + + + {% set index = index + 1 -%} + {% endfor -%} + {% endif -%} + {% endfor -%} + +
#TypeServiceTitle
{{ index }}{{ service.service }}{{ service.title }}{{ link.title }}
{{ index }}{{ service.service }}{{ service.title }}{{ link.title }}
+{% include "footer.html" -%} \ No newline at end of file diff --git a/share/ogcapi/templates/html-plain/collection-item.html b/share/ogcapi/templates/html-plain/collection-item.html new file mode 100644 index 0000000000..f96b09c70a --- /dev/null +++ b/share/ogcapi/templates/html-plain/collection-item.html @@ -0,0 +1,13 @@ +{% include "header.html" %} + +

{{ template.title }} - Collection Item: {{ response.collection.title }}

+ +

Properties:

+
    +
  • ID: {{ response.id }}
  • +{% for key, value in response.properties %} +
  • {{ key }}: {{ value }}
  • +{% endfor %} +
+ +{% include "footer.html" %} diff --git a/share/ogcapi/templates/html-plain/collection-items.html b/share/ogcapi/templates/html-plain/collection-items.html new file mode 100644 index 0000000000..eaafde77d2 --- /dev/null +++ b/share/ogcapi/templates/html-plain/collection-items.html @@ -0,0 +1,33 @@ +{% include "header.html" %} + +

{{ template.title }} - Collection Items: {{ response.collection.title }}

+ +

+ Number of matching items: {{ response.numberMatched }}
+ Number of returned items: {{ response.numberReturned }}
+

+ + + + + +{% if response.features %} +{% for key, value in response.features.0.properties %} + +{% endfor %} +{% endif %} + + + +{% for feature in response.features %} + + + {% for key, value in feature.properties %} + + {% endfor %} + +{% endfor %} + +
ID{{ key }}
{{ feature.id }}{{ value }}
+ +{% include "footer.html" %} diff --git a/share/ogcapi/templates/html-plain/collection-queryables.html b/share/ogcapi/templates/html-plain/collection-queryables.html new file mode 100644 index 0000000000..a4f55eca00 --- /dev/null +++ b/share/ogcapi/templates/html-plain/collection-queryables.html @@ -0,0 +1,22 @@ +{% include "header.html" %} + +

{{ template.title }} - Collection Queryables: {{ response.description }}

+ +

Queryables:

+
    +{% for key, value in response.properties %} +
  • {{ key }}: + {% if existsIn(value, "type") %} + {{ value.type }} + {% endif %} + {% if existsIn(value, "type") and existsIn(value, "format") %} + ,  + {% endif %} + {% if existsIn(value, "format") %} + {{ value.format }} + {% endif %} +
  • +{% endfor %} +
+ +{% include "footer.html" %} diff --git a/share/ogcapi/templates/html-plain/collection-schema.html b/share/ogcapi/templates/html-plain/collection-schema.html new file mode 100644 index 0000000000..857f9c1ed3 --- /dev/null +++ b/share/ogcapi/templates/html-plain/collection-schema.html @@ -0,0 +1,22 @@ +{% include "header.html" %} + +

{{ template.title }} - Collection schema: {{ response.description }}

+ +

Schema:

+
    +{% for key, value in response.properties %} +
  • {{ key }}: + {% if existsIn(value, "type") %} + {{ value.type }} + {% endif %} + {% if existsIn(value, "type") and existsIn(value, "format") %} + ,  + {% endif %} + {% if existsIn(value, "format") %} + {{ value.format }} + {% endif %} +
  • +{% endfor %} +
+ +{% include "footer.html" %} diff --git a/share/ogcapi/templates/html-plain/collection-sortables.html b/share/ogcapi/templates/html-plain/collection-sortables.html new file mode 100644 index 0000000000..265e904546 --- /dev/null +++ b/share/ogcapi/templates/html-plain/collection-sortables.html @@ -0,0 +1,22 @@ +{% include "header.html" %} + +

{{ template.title }} - Collection Sortables: {{ response.description }}

+ +

Sortables:

+
    +{% for key, value in response.properties %} +
  • {{ key }}: + {% if existsIn(value, "type") %} + {{ value.type }} + {% endif %} + {% if existsIn(value, "type") and existsIn(value, "format") %} + ,  + {% endif %} + {% if existsIn(value, "format") %} + {{ value.format }} + {% endif %} +
  • +{% endfor %} +
+ +{% include "footer.html" %} diff --git a/share/ogcapi/templates/html-plain/collection.html b/share/ogcapi/templates/html-plain/collection.html new file mode 100644 index 0000000000..59d28ed263 --- /dev/null +++ b/share/ogcapi/templates/html-plain/collection.html @@ -0,0 +1,36 @@ +{% include "header.html" %} + +

{{ template.title }} - Collection: {{ response.title }}

+ +

{{ response.description }}

+{% if existsIn(response, "keywords") and length(response.keywords) > 0 %} +

Keywords

+
    + {% for keyword in response.keywords %} +
  • {{ keyword }}
  • + {% endfor %} +
+{% endif %} + +{% if existsIn(response, "storageCrs") %} +

Storage CRS

+{{ response.storageCrs }} +{% endif %} + +{% if existsIn(response, "crs") %} +

Supported CRS

+
    +{% for href in response.crs %} +
  • {{ href }}
  • +{% endfor %} +
+{% endif %} + +

Links

+ + +{% include "footer.html" %} diff --git a/share/ogcapi/templates/html-plain/collections.html b/share/ogcapi/templates/html-plain/collections.html new file mode 100644 index 0000000000..7e48aff7b2 --- /dev/null +++ b/share/ogcapi/templates/html-plain/collections.html @@ -0,0 +1,25 @@ +{% include "header.html" %} + +

{{ template.title }} - Collections

+ + + + + + + + + + + +{%- for collection in response.collections %} + + + + + + +{% endfor -%} + +
#TitleTypeDescription
{{ loop.index1 }}{{ collection.title }}{{ collection.itemType }}{{ collection.description }}
+{%- include "footer.html" -%} diff --git a/share/ogcapi/templates/html-plain/conformance.html b/share/ogcapi/templates/html-plain/conformance.html new file mode 100644 index 0000000000..3af3531d86 --- /dev/null +++ b/share/ogcapi/templates/html-plain/conformance.html @@ -0,0 +1,14 @@ +{% include "header.html" %} + +

{{ template.title }} - Conformance

+ +

This API implements the conformance classes from standards and community specifications that are listed below.

+ +

Links

+
    +{% for url in response.conformsTo %} +
  • {{ url }}
  • +{% endfor %} +
+ +{% include "footer.html" %} diff --git a/share/ogcapi/templates/html-plain/debug.html b/share/ogcapi/templates/html-plain/debug.html new file mode 100644 index 0000000000..45f76a144b --- /dev/null +++ b/share/ogcapi/templates/html-plain/debug.html @@ -0,0 +1,13 @@ +{% if existsIn(template.tags, "debug") %} + {% if template.tags.debug == "true" %} +

Template Data

+

+ API Root: {{ template.api_root }}
+ Path: {{ template.path }}
+ Params: {{ template.params }}
+ Extra Params: {{ {{ template.extra_params }}
+ Title: {{ template.title }}
+ Tags: {{ template.tags }}
+

+ {% endif %} +{% endif %} diff --git a/share/ogcapi/templates/html-plain/footer.html b/share/ogcapi/templates/html-plain/footer.html new file mode 100644 index 0000000000..f34032c25f --- /dev/null +++ b/share/ogcapi/templates/html-plain/footer.html @@ -0,0 +1,3 @@ + {% include "debug.html" %} + + diff --git a/share/ogcapi/templates/html-plain/header.html b/share/ogcapi/templates/html-plain/header.html new file mode 100644 index 0000000000..af336a7cdc --- /dev/null +++ b/share/ogcapi/templates/html-plain/header.html @@ -0,0 +1,7 @@ + + + + {{ template.title }} + + + diff --git a/share/ogcapi/templates/html-plain/landing.html b/share/ogcapi/templates/html-plain/landing.html new file mode 100644 index 0000000000..1ebe829371 --- /dev/null +++ b/share/ogcapi/templates/html-plain/landing.html @@ -0,0 +1,15 @@ +{% include "header.html" %} + +

{{ response.title }}

+

+ {{ response.description }} +

+ +

Links

+ + +{% include "footer.html" %} diff --git a/share/ogcapi/templates/html-plain/openapi.html b/share/ogcapi/templates/html-plain/openapi.html new file mode 100644 index 0000000000..fb7ecbe443 --- /dev/null +++ b/share/ogcapi/templates/html-plain/openapi.html @@ -0,0 +1,52 @@ + + + + + Swagger UI - {{ template.title }} + + + + + +
+ + + + + + diff --git a/shp2img.c b/shp2img.c deleted file mode 100644 index 3d13c47a90..0000000000 --- a/shp2img.c +++ /dev/null @@ -1,324 +0,0 @@ -/****************************************************************************** - * $Id$ - * - * Project: MapServer - * Purpose: Commandline .map rendering utility, mostly for testing. - * Author: Steve Lime and the MapServer team. - * - ****************************************************************************** - * Copyright (c) 1996-2005 Regents of the University of Minnesota. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies of this Software or works derived from this Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - ****************************************************************************/ - -#include "mapserver.h" -#include "maptime.h" - - - -int main(int argc, char *argv[]) -{ - int i,j,k; - - mapObj *map=NULL; - imageObj *image = NULL; - - char **layers=NULL; - int num_layers=0; - - int layer_found=0; - - char *outfile=NULL; /* no -o sends image to STDOUT */ - - int iterations = 1; - int draws = 0; - - for(i=1; i= MS_DEBUGLEVEL_TUNING) - msGettimeofday(&requeststarttime, NULL); - - if(argc > 1 && strcmp(argv[1], "-v") == 0) { - printf("%s\n", msGetVersion()); - exit(0); - } - - /* ---- check the number of arguments, return syntax if not correct ---- */ - if( argc < 3 ) { - fprintf(stdout, "\nPurpose: convert a mapfile to an image\n\n"); - fprintf(stdout, - "Syntax: shp2img -m mapfile [-o image] [-e minx miny maxx maxy] [-s sizex sizey]\n" - " [-l \"layer1 [layers2...]\"] [-i format]\n" - " [-all_debug n] [-map_debug n] [-layer_debug n] [-p n] [-c n] [-d layername datavalue]\n"); - - - fprintf(stdout," -m mapfile: Map file to operate on - required\n" ); - fprintf(stdout," -i format: Override the IMAGETYPE value to pick output format\n" ); - fprintf(stdout," -o image: output filename (stdout if not provided)\n"); - fprintf(stdout," -e minx miny maxx maxy: extents to render\n"); - fprintf(stdout," -s sizex sizey: output image size\n"); - fprintf(stdout," -l layers: layers / groups to enable - make sure they are quoted and space separated if more than one listed\n" ); - fprintf(stdout," -all_debug n: Set debug level for map and all layers\n" ); - fprintf(stdout," -map_debug n: Set map debug level\n" ); - fprintf(stdout," -layer_debug layer_name n: Set layer debug level\n" ); - fprintf(stdout," -c n: draw map n number of times\n" ); - fprintf(stdout," -p n: pause for n seconds after reading the map\n" ); - fprintf(stdout," -d layername datavalue: change DATA value for layer\n" ); - - - exit(0); - } - - if ( msSetup() != MS_SUCCESS ) { - msWriteError(stderr); - exit(1); - } - - /* Use PROJ_LIB env vars if set */ - msProjLibInitFromEnv(); - - /* Use MS_ERRORFILE and MS_DEBUGLEVEL env vars if set */ - if ( msDebugInitFromEnv() != MS_SUCCESS ) { - msWriteError(stderr); - msCleanup(); - exit(1); - } - - for(i=1; iimagetype ); - map->imagetype = msStrdup( argv[i+1] ); - msApplyOutputFormat( &(map->outputformat), format, - map->transparent, map->interlace, - map->imagequality ); - } - i+=1; - } - - if(strcmp(argv[i],"-d") == 0) { /* swap layer data */ - for(j=0; jnumlayers; j++) { - if(strcmp(GET_LAYER(map, j)->name, argv[i+1]) == 0) { - free(GET_LAYER(map, j)->data); - GET_LAYER(map, j)->data = msStrdup(argv[i+2]); - break; - } - } - i+=2; - } - - if(strcmp(argv[i], "-all_debug") == 0 && i < argc-1 ) { /* global debug */ - int debug_level = atoi(argv[++i]); - - /* msSetGlobalDebugLevel() already called. Just need to force debug - * level in map and all layers - */ - map->debug = debug_level; - for(j=0; jnumlayers; j++) { - GET_LAYER(map, j)->debug = debug_level; - } - - } - - if(strcmp(argv[i], "-map_debug") == 0 && i < argc-1 ) { /* debug */ - map->debug = atoi(argv[++i]); - - /* Send output to stderr by default */ - if (msGetErrorFile() == NULL) - msSetErrorFile("stderr", NULL); - } - - if(strcmp(argv[i], "-layer_debug") == 0 && i < argc-1 ) { /* debug */ - const char *layer_name = argv[++i]; - int debug_level = atoi(argv[++i]); - int got_layer = 0; - - for(j=0; jnumlayers; j++) { - if(strcmp(GET_LAYER(map, j)->name,layer_name) == 0 ) { - GET_LAYER(map, j)->debug = debug_level; - got_layer = 1; - } - } - if( !got_layer ) - fprintf( stderr, - " Did not find layer '%s' from -layer_debug switch.\n", - layer_name ); - - /* Send output to stderr by default */ - if (msGetErrorFile() == NULL) - msSetErrorFile("stderr", NULL); - } - - if(strcmp(argv[i],"-e") == 0) { /* change extent */ - if( argc <= i+4 ) { - fprintf( stderr, - "Argument -e needs 4 space separated numbers as argument.\n" ); - msCleanup(); - exit(1); - } - map->extent.minx = atof(argv[i+1]); - map->extent.miny = atof(argv[i+2]); - map->extent.maxx = atof(argv[i+3]); - map->extent.maxy = atof(argv[i+4]); - i+=4; - } - - if (strcmp(argv[i], "-s") == 0) { - msMapSetSize(map, atoi(argv[i+1]), atoi(argv[i+2])); - i+=2; - } - - if(strcmp(argv[i],"-l") == 0) { /* load layer list */ - layers = msStringSplit(argv[i+1], ' ', &(num_layers)); - - for(j=0; jnumlayers; k++) { - if((GET_LAYER(map, k)->name && strcasecmp(GET_LAYER(map, k)->name, layers[j]) == 0) || (GET_LAYER(map, k)->group && strcasecmp(GET_LAYER(map, k)->group, layers[j]) == 0)) { - layer_found = 1; - break; - } - } - if (layer_found==0) { - fprintf(stderr, "Layer (-l) \"%s\" not found\n", layers[j]); - msCleanup(); - exit(1); - } - } - - for(j=0; jnumlayers; j++) { - if(GET_LAYER(map, j)->status == MS_DEFAULT) - continue; - else { - GET_LAYER(map, j)->status = MS_OFF; - for(k=0; kname && strcasecmp(GET_LAYER(map, j)->name, layers[k]) == 0) || - (GET_LAYER(map, j)->group && strcasecmp(GET_LAYER(map, j)->group, layers[k]) == 0)) { - GET_LAYER(map, j)->status = MS_ON; - break; - } - } - } - } - - msFreeCharArray(layers, num_layers); - - i+=1; - } - } - - image = msDrawMap(map, MS_FALSE); - - if(!image) { - msWriteError(stderr); - - msFreeMap(map); - msCleanup(); - exit(1); - } - - if( msSaveImage(map, image, outfile) != MS_SUCCESS ) { - msWriteError(stderr); - } - - msFreeImage(image); - msFreeMap(map); - - if(msGetGlobalDebugLevel() >= MS_DEBUGLEVEL_TUNING) { - msGettimeofday(&requestendtime, NULL); - msDebug("shp2img total time: %.3fs\n", - (requestendtime.tv_sec+requestendtime.tv_usec/1.0e6)- - (requeststarttime.tv_sec+requeststarttime.tv_usec/1.0e6) ); - } - - msCleanup(); - - } /* for(draws=0; draws - - - -char* AddFileSuffix ( const char * Filename, const char * Suffix ) -{ - char *pszFullname, *pszBasename; - int i; - - /* -------------------------------------------------------------------- */ - /* Compute the base (layer) name. If there is any extension */ - /* on the passed in filename we will strip it off. */ - /* -------------------------------------------------------------------- */ - pszBasename = (char *) msSmallMalloc(strlen(Filename)+5); - strcpy( pszBasename, Filename ); - for( i = (int)strlen(pszBasename)-1; - i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/' - && pszBasename[i] != '\\'; - i-- ) {} - - if( pszBasename[i] == '.' ) - pszBasename[i] = '\0'; - - /* -------------------------------------------------------------------- */ - /* Open the .shp and .shx files. Note that files pulled from */ - /* a PC to Unix with upper case filenames won't work! */ - /* -------------------------------------------------------------------- */ - pszFullname = (char *) msSmallMalloc(strlen(pszBasename) + 5); - sprintf( pszFullname, "%s%s", pszBasename, Suffix); - - free(pszBasename); - return (pszFullname); -} - - -int main(int argc, char *argv[]) -{ - shapefileObj shapefile; - - treeObj *tree; - int byte_order = MS_NEW_LSB_ORDER, i; - int depth=0; - - if(argc > 1 && strcmp(argv[1], "-v") == 0) { - printf("%s\n", msGetVersion()); - exit(0); - } - - /* -------------------------------------------------------------------- */ - /* Establish the byte order on this machine to decide default */ - /* index format */ - /* -------------------------------------------------------------------- */ - i = 1; - if( *((uchar *) &i) == 1 ) - byte_order = MS_NEW_LSB_ORDER; - else - byte_order = MS_NEW_MSB_ORDER; - - - if(argc<2) { - fprintf(stdout,"Syntax:\n"); - fprintf(stdout," shptree [] []\n" ); - fprintf(stdout,"Where:\n"); - fprintf(stdout," is the name of the .shp file to index.\n"); - fprintf(stdout," (optional) is the maximum depth of the index\n"); - fprintf(stdout," to create, default is 0 meaning that shptree\n"); - fprintf(stdout," will calculate a reasonable default depth.\n"); - fprintf(stdout," (optional) is one of:\n"); - fprintf(stdout," NL: LSB byte order, using new index format\n"); - fprintf(stdout," NM: MSB byte order, using new index format\n"); - fprintf(stdout," The following old format options are deprecated:\n"); - fprintf(stdout," N: Native byte order\n"); - fprintf(stdout," L: LSB (intel) byte order\n"); - fprintf(stdout," M: MSB byte order\n"); - fprintf(stdout," The default index_format on this system is: %s\n\n", - (byte_order == MS_NEW_LSB_ORDER) ? "NL" : "NM" ); - exit(0); - } - - if(argc >= 3) - depth = atoi(argv[2]); - - if(argc >= 4) { - if( !strcasecmp(argv[3],"N" )) - byte_order = MS_NATIVE_ORDER; - if( !strcasecmp(argv[3],"L" )) - byte_order = MS_LSB_ORDER; - if( !strcasecmp(argv[3],"M" )) - byte_order = MS_MSB_ORDER; - if( !strcasecmp(argv[3],"NL" )) - byte_order = MS_NEW_LSB_ORDER; - if( !strcasecmp(argv[3],"NM" )) - byte_order = MS_NEW_MSB_ORDER; - } - - if(msShapefileOpen(&shapefile, "rb", argv[1], MS_TRUE) == -1) { - fprintf(stdout, "Error opening shapefile %s.\n", argv[1]); - exit(0); - } - - printf( "creating index of %s %s format\n",(byte_order < 1 ? "old (deprecated)" :"new"), - ((byte_order == MS_NATIVE_ORDER) ? "native" : - ((byte_order == MS_LSB_ORDER) || (byte_order == MS_NEW_LSB_ORDER)? " LSB":"MSB"))); - - tree = msCreateTree(&shapefile, depth); - if(!tree) { -#if MAX_SUBNODE == 2 - fprintf(stdout, "Error generating binary tree.\n"); -#else - fprintf(stdout, "Error generating quadtree.\n"); -#endif - exit(0); - } - - msWriteTree(tree, AddFileSuffix(argv[1], MS_INDEX_EXTENSION), byte_order); - msDestroyTree(tree); - - /* - ** Clean things up - */ - msShapefileClose(&shapefile); - - return(0); -} diff --git a/shptreetst.c b/shptreetst.c deleted file mode 100644 index 5325647db7..0000000000 --- a/shptreetst.c +++ /dev/null @@ -1,173 +0,0 @@ -/****************************************************************************** - * $Id$ - * - * Project: MapServer - * Purpose: Utility program to visualize a quadtree search - * Author: Steve Lime and the MapServer team. - * - ****************************************************************************** - * Copyright (c) 1996-2005 Regents of the University of Minnesota. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies of this Software or works derived from this Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - ****************************************************************************/ - -#include "mapserver.h" -#include -#ifndef _WIN32 -#include -#endif -#include - - - -#ifdef SHPT_POLYGON -#undef MAPSERVER -#else -#define MAPSERVER 1 -#define SHPT_POLYGON MS_SHP_POLYGON -#endif - - -char* AddFileSuffix ( const char * Filename, const char * Suffix ) -{ - char *pszFullname, *pszBasename; - int i; - - /* -------------------------------------------------------------------- */ - /* Compute the base (layer) name. If there is any extension */ - /* on the passed in filename we will strip it off. */ - /* -------------------------------------------------------------------- */ - pszBasename = (char *) msSmallMalloc(strlen(Filename)+5); - strcpy( pszBasename, Filename ); - for( i = (int)strlen(pszBasename)-1; - i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/' - && pszBasename[i] != '\\'; - i-- ) {} - - if( pszBasename[i] == '.' ) - pszBasename[i] = '\0'; - - /* -------------------------------------------------------------------- */ - /* Open the .shp and .shx files. Note that files pulled from */ - /* a PC to Unix with upper case filenames won't work! */ - /* -------------------------------------------------------------------- */ - pszFullname = (char *) msSmallMalloc(strlen(pszBasename) + 5); - sprintf( pszFullname, "%s%s", pszBasename, Suffix); - - return (pszFullname); -} - - -int main( int argc, char ** argv ) - -{ - SHPTreeHandle qix; - - int i,j; - rectObj rect; - - int pos; - ms_bitarray bitmap = NULL; - - /* - char mBigEndian; - */ - treeNodeObj *node = NULL; - - - /* -------------------------------------------------------------------- */ - /* Display a usage message. */ - /* -------------------------------------------------------------------- */ - if( argc <= 1 ) { - printf( "shptreetst shapefile {minx miny maxx maxy}\n" ); - exit( 1 ); - } - - /* - i = 1; - if( *((unsigned char *) &i) == 1 ) - mBigEndian = 0; - else - mBigEndian = 1; - */ - - qix = msSHPDiskTreeOpen (AddFileSuffix(argv[1],".qix"), 0 /* no debug*/); - if( qix == NULL ) { - printf("unable to open index file %s \n", argv[1]); - exit(-1); - } - - printf ("This %s %s index supports a shapefile with %d shapes, %d depth \n", - (qix->version ? "new": "old"), (qix->LSB_order? "LSB": "MSB"), (int) qix->nShapes, (int) qix->nDepth); - - /* -------------------------------------------------------------------- */ - /* Skim over the list of shapes, printing all the vertices. */ - /* -------------------------------------------------------------------- */ - - pos = ftell (qix->fp); - j = 0; - - while( pos && j < 20) { - j ++; - /* fprintf (stderr,"box %d, at %d pos \n", j, (int) ftell(qix)); - */ - - node = readTreeNode (qix); - if (node ) { - fprintf (stdout,"shapes %d, node %d, %f,%f,%f,%f \n",(int) node->numshapes,node->numsubnodes,node->rect.minx, node->rect.miny, node->rect.maxx, node->rect.maxy); - - } else { - pos = 0; - } - } - - printf ("read entire file now at quad box rec %d file pos %ld\n", j, ftell (qix->fp)); - - j = qix->nShapes; - msSHPDiskTreeClose (qix); - - if( argc >= 5 ) { - rect.minx = atof (argv[2]); - rect.miny = atof (argv[3]); - rect.maxx = atof (argv[4]); - rect.maxy = atof (argv[5]); - } else { - printf ("using last read box as a search \n"); - rect.minx = node->rect.minx; - rect.miny = node->rect.miny; - rect.maxx = node->rect.maxx; - rect.maxy = node->rect.maxy; - } - - bitmap = msSearchDiskTree( argv[1], rect, 0 /* no debug*/, j ); - - if ( bitmap ) { - printf ("result of rectangle search was \n"); - for ( i=0; i -#ifndef _WIN32 -#include -#endif -#include - - - -#ifdef SHPT_POLYGON -#undef MAPSERVER -#else -#define MAPSERVER 1 -#define SHPT_POLYGON SHP_POLYGON -#endif - -char* AddFileSuffix ( const char * Filename, const char * Suffix ) -{ - char *pszFullname, *pszBasename; - int i; - - /* -------------------------------------------------------------------- */ - /* Compute the base (layer) name. If there is any extension */ - /* on the passed in filename we will strip it off. */ - /* -------------------------------------------------------------------- */ - pszBasename = (char *) msSmallMalloc(strlen(Filename)+5); - strcpy( pszBasename, Filename ); - for( i = strlen(pszBasename)-1; - i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/' - && pszBasename[i] != '\\'; - i-- ) {} - - if( pszBasename[i] == '.' ) - pszBasename[i] = '\0'; - - /* -------------------------------------------------------------------- */ - /* Open the .shp and .shx files. Note that files pulled from */ - /* a PC to Unix with upper case filenames won't work! */ - /* -------------------------------------------------------------------- */ - pszFullname = (char *) msSmallMalloc(strlen(pszBasename) + 5); - sprintf( pszFullname, "%s%s", pszBasename, Suffix); - - free(pszBasename); - return (pszFullname); -} - - -int main( int argc, char ** argv ) - -{ - SHPHandle hSHP; - DBFHandle hDBF; - SHPTreeHandle qix; - - char *myfile = NULL; - - treeNodeObj *node; - -#ifdef MAPSERVER - shapeObj shape; - lineObj line[3]; - pointObj pts[6]; -#else - SHPObject *shape; - double X[6], Y[6]; -#endif - int result; - - /* - char mBigEndian; - int i; - */ - - int this_rec; - - /* -------------------------------------------------------------------- */ - /* Display a usage message. */ - /* -------------------------------------------------------------------- */ - if( argc <= 2 ) { - printf( "shptreevis shapefile new_shapefile \n" ); - exit( 1 ); - } - - /* - i = 1; - if( *((unsigned char *) &i) == 1 ) - mBigEndian = 0; - else - mBigEndian = 1; - */ - - - qix = msSHPDiskTreeOpen (AddFileSuffix(argv[1],".qix"), 0 /* no debug*/); - if( qix == NULL ) { - printf("unable to open index file %s \n", argv[1]); - exit(-1); - } - - /* -------------------------------------------------------------------- */ - /* Open the passed shapefile. */ - /* -------------------------------------------------------------------- */ - myfile = AddFileSuffix(argv[2],".shp"); - -#ifdef MAPSERVER - hSHP = msSHPCreate ( myfile, SHPT_POLYGON ); - hDBF = msDBFCreate ( AddFileSuffix(argv[2],".dbf") ); -#else - hSHP = SHPCreate ( myfile, SHPT_POLYGON ); - hDBF = DBFCreate ( AddFileSuffix(argv[2],".dbf") ); -#endif - - if ( (!hSHP) || (!hDBF) ) { - printf ("create error for %s ... exiting \n", myfile); - exit (-1); - } - - /* add fields to dbf */ -#ifdef MAPSERVER - msDBFAddField ( hDBF, "ITEMS", FTInteger, 15,0 ); - msDBFAddField ( hDBF, "SUBNODES", FTInteger, 15,0 ); - msDBFAddField ( hDBF, "FACTOR", FTInteger, 15,0 ); -#else - DBFAddField ( hDBF, "ITEMS", FTInteger, 15,0 ); - DBFAddField ( hDBF, "SUBNODES", FTInteger, 15,0 ); - DBFAddField ( hDBF, "FACTOR", FTInteger, 15,0 ); -#endif - -#ifndef MAPSERVER - SHPClose ( hSHP ); - hSHP = SHPOpen ( myfile, "r+b" ); - - DBFClose (hDBF); - hDBF = DBFOpen ( myfile, "r+b"); -#endif - - printf ("This %s %s index supports a shapefile with %d shapes, %d depth \n", - (qix->version ? "new": "old"), (qix->LSB_order? "LSB": "MSB"), (int) qix->nShapes, (int) qix->nDepth); - - - /* -------------------------------------------------------------------- */ - /* Skim over the list of shapes, printing all the vertices. */ - /* -------------------------------------------------------------------- */ - - while( 1 ) { - node = readTreeNode (qix); - if (node ) { - - this_rec = hDBF->nRecords; - -#ifdef MAPSERVER - msDBFWriteIntegerAttribute( hDBF, this_rec, 0, node->numshapes); - msDBFWriteIntegerAttribute( hDBF, this_rec, 1, node->numsubnodes); -#else - DBFWriteIntegerAttribute( hDBF, this_rec, 0, node->numshapes); - DBFWriteIntegerAttribute( hDBF, this_rec, 1, node->numsubnodes); -#endif - -#ifdef MAPSERVER - shape.numlines = 1; - shape.type = SHPT_POLYGON; - - pts[0].x = node->rect.minx; - pts[0].y = node->rect.miny; - pts[1].x = node->rect.maxx; - pts[1].y = node->rect.miny; - pts[2].x = node->rect.maxx; - pts[2].y = node->rect.maxy; - pts[3].x = node->rect.minx; - pts[3].y = node->rect.maxy; - pts[4].x = node->rect.minx; - pts[4].y = node->rect.miny; - - line[0].numpoints = 5; - line[0].point = &pts[0]; - shape.line = &line[0]; - shape.bounds = node->rect; - - result = msSHPWriteShape ( hSHP, &shape ); - if ( result < 0 ) { - printf ("unable to write shape \n"); - exit (0); - } - -#else - X[0] = node->rect.minx; - X[1] = node->rect.maxx; - X[2] = node->rect.maxx; - X[3] = node->rect.minx; - X[4] = node->rect.minx; - - Y[0] = node->rect.miny; - Y[1] = node->rect.miny; - Y[2] = node->rect.maxy; - Y[3] = node->rect.maxy; - Y[4] = node->rect.miny; - - shape = SHPCreateSimpleObject( SHPT_POLYGON, 5, X, Y, NULL); - SHPWriteObject(hSHP, -1, shape); - SHPDestroyObject ( shape ); -#endif - } else - break; - } - -#ifdef MAPSERVER - msSHPClose( hSHP ); - msDBFClose( hDBF ); -#else - SHPClose( hSHP ); - DBFClose( hDBF ); -#endif - - msSHPDiskTreeClose (qix); - - return(0); -} diff --git a/sortshp.c b/sortshp.c deleted file mode 100644 index f131da5de8..0000000000 --- a/sortshp.c +++ /dev/null @@ -1,244 +0,0 @@ -/****************************************************************************** - * $Id$ - * - * Project: MapServer - * Purpose: Command line utility to sort a shapefile based on a single - * attribute in ascending or decending order. Useful for - * prioritizing drawing or labeling of shapes. - * Author: Steve Lime and the MapServer team. - * - ****************************************************************************** - * Copyright (c) 1996-2005 Regents of the University of Minnesota. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies of this Software or works derived from this Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - ****************************************************************************/ - -#include -#include -#include -#include - -#include "mapserver.h" - - - -typedef struct { - double number; - char string[255]; - int index; -} sortStruct; - -static int compare_string_descending(const void *a, const void *b) -{ - const sortStruct *i = a, *j = b; - return(strcmp(j->string, i->string)); -} - -static int compare_string_ascending(const void *a, const void *b) -{ - const sortStruct *i = a, *j = b; - return(strcmp(i->string, j->string)); -} - -static int compare_number_descending(const void *a, const void *b) -{ - const sortStruct *i = a, *j = b; - if(i->number > j->number) - return(-1); - if(i->number < j->number) - return(1); - return(0); -} - -static int compare_number_ascending(const void *a, const void *b) -{ - const sortStruct *i = a, *j = b; - if(i->number > j->number) - return(1); - if(i->number < j->number) - return(-1); - return(0); -} - -int main(int argc, char *argv[]) -{ - SHPHandle inSHP,outSHP; /* ---- Shapefile file pointers ---- */ - DBFHandle inDBF,outDBF; /* ---- DBF file pointers ---- */ - sortStruct *array; - shapeObj shape; - int shpType, nShapes; - int fieldNumber=-1; /* ---- Field number of item to be sorted on ---- */ - DBFFieldType dbfField; - char fName[20]; - int fWidth,fnDecimals; - char buffer[1024]; - int i,j; - int num_fields, num_records; - - if(argc > 1 && strcmp(argv[1], "-v") == 0) { - printf("%s\n", msGetVersion()); - exit(0); - } - - /* ------------------------------------------------------------------------------- */ - /* Check the number of arguments, return syntax if not correct */ - /* ------------------------------------------------------------------------------- */ - if( argc != 5 ) { - fprintf(stderr,"Syntax: sortshp [infile] [outfile] [item] [ascending|descending]\n" ); - exit(1); - } - - msSetErrorFile("stderr", NULL); - - /* ------------------------------------------------------------------------------- */ - /* Open the shapefile */ - /* ------------------------------------------------------------------------------- */ - inSHP = msSHPOpen(argv[1], "rb" ); - if( !inSHP ) { - fprintf(stderr,"Unable to open %s shapefile.\n",argv[1]); - exit(1); - } - msSHPGetInfo(inSHP, &nShapes, &shpType); - - /* ------------------------------------------------------------------------------- */ - /* Open the dbf file */ - /* ------------------------------------------------------------------------------- */ - snprintf(buffer, sizeof(buffer), "%s.dbf",argv[1]); - inDBF = msDBFOpen(buffer,"rb"); - if( inDBF == NULL ) { - fprintf(stderr,"Unable to open %s XBASE file.\n",buffer); - exit(1); - } - - num_fields = msDBFGetFieldCount(inDBF); - num_records = msDBFGetRecordCount(inDBF); - - for(i=0; ipool, r->remaining + 1); + + if (!buffer) + return NULL; + + size = r->remaining; + buffer[size] = '\0'; + + while ((blen = ap_get_client_block(r, buf, sizeof(buf))) > 0) { + if (rpos + blen > size) { + rsize = blen - rpos; + } else { + rsize = blen; + } + memcpy((char *)buffer + rpos, buf, rsize); + rpos += rsize; + } + + return buffer; +} + +/* +** Extract Map File name from params and load it. +** Returns map object or NULL on error. +*/ +static mapObj *msModuleLoadMap(mapservObj *mapserv, + mapserver_dir_config *conf) { + int i; + /* OK, here's the magic: we take the mapObj from our stored config. + * We will use a copy of it created by msCopyMap since MapServer + * modifies the object at several places during request processing + */ + mapObj *map = msNewMapObj(); + if (!map) + return NULL; + msCopyMap(map, conf->map); + + /* check for any %variable% substitutions here, also do any map_ changes, we + * do this here so WMS/WFS */ + /* services can take advantage of these "vendor specific" extensions */ + for (i = 0; i < mapserv->request->NumParams; i++) { + /* + ** a few CGI variables should be skipped altogether + ** + ** qstring: there is separate per layer validation for attribute queries and + *the substitution checks + ** below conflict with that so we avoid it here + */ + if (strncasecmp(mapserv->request->ParamNames[i], "qstring", 7) == 0) + continue; + + if (strncasecmp(mapserv->request->ParamNames[i], "map_", 4) == 0 || + strncasecmp(mapserv->request->ParamNames[i], "map.", 4) == + 0) { /* check to see if there are any additions to the mapfile */ + if (msUpdateMapFromURL(map, mapserv->request->ParamNames[i], + mapserv->request->ParamValues[i]) != MS_SUCCESS) { + msFreeMap(map); + return NULL; + } + continue; + } + } + + msApplySubstitutions(map, mapserv->request->ParamNames, + mapserv->request->ParamValues, + mapserv->request->NumParams); + msApplyDefaultSubstitutions(map); + + /* check to see if a ogc map context is passed as argument. if there */ + /* is one load it */ + + for (i = 0; i < mapserv->request->NumParams; i++) { + if (strcasecmp(mapserv->request->ParamNames[i], "context") == 0) { + if (mapserv->request->ParamValues[i] && + strlen(mapserv->request->ParamValues[i]) > 0) { + if (strncasecmp(mapserv->request->ParamValues[i], "http", 4) == 0) { + if (msGetConfigOption(map, "CGI_CONTEXT_URL")) + msLoadMapContextURL(map, mapserv->request->ParamValues[i], + MS_FALSE); + } else + msLoadMapContext(map, mapserv->request->ParamValues[i], MS_FALSE); + } + } + } + /* + * RFC-42 HTTP Cookie Forwarding + * Here we set the http_cookie_data metadata to handle the + * HTTP Cookie Forwarding. The content of this metadata is the cookie + * content. In the future, this metadata will probably be replaced + * by an object that is part of the mapObject that would contain + * information on the application status (such as cookie). + */ + if (mapserv->request->httpcookiedata != NULL) { + msInsertHashTable(&(map->web.metadata), "http_cookie_data", + mapserv->request->httpcookiedata); + } + + return map; +} + +/*** + * The main request handler. + **/ +static int mapserver_handler(request_rec *r) { + /* acquire the appropriate configuration for this directory */ + mapserver_dir_config *conf; + conf = (mapserver_dir_config *)ap_get_module_config(r->per_dir_config, + &mapserver_module); + + /* decline the request if there's no map configured */ + if (!conf || !conf->map) + return DECLINED; + + apr_finfo_t mapstat; + if (apr_stat(&mapstat, conf->mapfile_name, APR_FINFO_MTIME, r->pool) == + APR_SUCCESS) { + if (apr_time_sec(mapstat.mtime) > apr_time_sec(conf->mtime)) { + mapObj *newmap = msLoadMap(conf->mapfile_name, NULL); + if (newmap) { + msFreeMap(conf->map); + conf->map = newmap; + conf->mtime = mapstat.mtime; + } else { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, + "unable to reload map file %s", conf->mapfile_name); + } + } + } else { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, + "%s: unable to stat file %s", __func__, conf->mapfile_name); + } + + /* make a copy of the URI so we can modify it safely */ + char *uri = apr_pstrdup(r->pool, r->uri); + int len = strlen(uri); + int conf_uri_len = strlen(conf->uri); + + /* If the URI points to a subdirectory we want to decline. + */ + if (len > conf_uri_len) + return DECLINED; + + int argc = 0; + char **ParamNames = NULL; + char **ParamValues = NULL; + char *post_data = NULL; + int szMethod = -1; + char *szContentType = NULL; + mapservObj *mapserv = NULL; + + /* Try decoding the query string */ + if (r->method_number == M_GET) { + argc = mapserver_decode_args(r->pool, (char *)apr_pstrdup(r->pool, r->args), + &ParamNames, &ParamValues); + szMethod = MS_GET_REQUEST; + } else if (r->method_number == M_POST) { + szContentType = (char *)apr_table_get(r->headers_in, "Content-Type"); + post_data = mapserver_read_post_data(r); + szMethod = MS_POST_REQUEST; + if (strcmp(szContentType, "application/x-www-form-urlencoded") == 0) { + argc = + mapserver_decode_args(r->pool, (char *)apr_pstrdup(r->pool, r->args), + &ParamNames, &ParamValues); + } + } else + return HTTP_METHOD_NOT_ALLOWED; + + if (!argc && !post_data) + return HTTP_BAD_REQUEST; + + /* Now we install the IO redirection. + */ + if (msIO_installApacheRedirect(r) != MS_TRUE) + ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, + "%s: could not install apache redirect", __func__); + + mapserv = msAllocMapServObj(); + mapserv->request->NumParams = argc; + mapserv->request->ParamNames = ParamNames; + mapserv->request->ParamValues = ParamValues; + mapserv->request->type = (enum MS_REQUEST_TYPE)szMethod; + mapserv->request->postrequest = post_data; + mapserv->request->contenttype = szContentType; + + // mapserv->map = msModuleLoadMap(mapserv,conf); + mapserv->map = conf->map; + if (!mapserv->map) { + msCGIWriteError(mapserv); + goto end_request; + } + + if (msCGIDispatchRequest(mapserv) != MS_SUCCESS) { + msCGIWriteError(mapserv); + goto end_request; + } + +end_request: + if (mapserv) { + mapserv->request->ParamNames = NULL; + mapserv->request->ParamValues = NULL; + mapserv->request->postrequest = NULL; + mapserv->request->contenttype = NULL; + mapserv->map = NULL; + msFreeMapServObj(mapserv); + } + msResetErrorList(); + + /* Check if status was set inside MapServer functions. If it was, we + * return it's value instead of simply OK. This is to support redirects + * from maptemplate.c + */ + if (r->status == HTTP_MOVED_TEMPORARILY) + return r->status; + + return OK; +} + +/* This function will be called on startup to allow us to register our + * handler. We don't do anything else yet... + */ +static void mapserver_register_hooks(apr_pool_t *p) { + ap_hook_handler(mapserver_handler, NULL, NULL, APR_HOOK_MIDDLE); +} + +/* That's the second part of the overall magic. This function will be called + * when the configuration reaches the "WMS_Map" parameter. It will be passed + * in as argument and should contain the full path and name of the map file. + * We try to load it and store the resulting mapObj in the config of the + * current directory. If we fail we throw a message... + */ +static const char *mapserver_set_map(cmd_parms *cmd, void *config, + const char *arg) { + mapserver_dir_config *conf = (mapserver_dir_config *)config; + /* if the mapObj already exists the WMS_Map was given more than once - + * may be the user forgot to comment something out... + */ + if (conf->map) { + msWriteError(stderr); + return (char *)apr_psprintf(cmd->temp_pool, + "An MAP-file has already been registered for " + "this URI - not accepting '%s'.", + arg); + } + /* Simply try loading the argument as map file. */ + conf->mapfile_name = apr_pstrdup(cmd->pool, arg); + conf->map = msLoadMap((char *)arg, NULL); + + /* Ooops - we failed. We report it and fail. So beware: Always do a + * configcheck before really restarting your web server! + */ + + if (!conf->map) { + msWriteError(stderr); + return (char *)apr_psprintf( + cmd->temp_pool, "The given MAP-file '%s' could not be loaded", arg); + } + + apr_finfo_t status; + if (apr_stat(&status, conf->mapfile_name, APR_FINFO_MTIME, cmd->pool) != + APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, + "%s: unable to stat file %s", __func__, conf->mapfile_name); + } + conf->mtime = status.mtime; + return NULL; +} + +/* This function creates the (default) directory configuration. Well, we have + * no defaults to set so we simply alloc the memory... + */ +static void *mapserver_create_dir_config(apr_pool_t *p, char *dir) { + mapserver_dir_config *newconf; + newconf = + (mapserver_dir_config *)apr_pcalloc(p, sizeof(mapserver_dir_config)); + newconf->config_pool = p; + newconf->uri = apr_pstrdup(p, dir); + newconf->map = NULL; + newconf->mapfile_name = NULL; + newconf->mtime = apr_time_from_sec(0); + + if (dir) { + int len = strlen(dir); + if (len > 1 && dir[len - 1] == '/') + newconf->uri[len - 1] = '\0'; + } + return newconf; +} + +/* This structure defines our single config option which takes exactly one + * argument. + */ +static const command_rec mapserver_options[] = { + AP_INIT_TAKE1("Mapfile", mapserver_set_map, NULL, ACCESS_CONF, + "WMS_Map "), + {NULL}}; + +/* The following structure declares everything Apache needs to treat us as + * a module. Merging would mean inheriting from the parent directory but that + * doesn't make much sense here since we would only inherit the map file... + */ +/* Dispatch list for API hooks */ +module AP_MODULE_DECLARE_DATA mapserver_module = { + STANDARD20_MODULE_STUFF, + mapserver_create_dir_config, /* create per-dir config structures */ + NULL, /* merge per-dir config structures */ + NULL, /* create per-server config structures */ + NULL, /* merge per-server config structures */ + mapserver_options, /* table of config file commands */ + mapserver_register_hooks /* register hooks */ +}; diff --git a/src/apps/coshp.c b/src/apps/coshp.c new file mode 100644 index 0000000000..e17ea89942 --- /dev/null +++ b/src/apps/coshp.c @@ -0,0 +1,251 @@ +/****************************************************************************** + * + * Project: MapServer + * Purpose: Command line utility to sort a shapefile based on the + * spatial index file. + * + ****************************************************************************** + * Copyright (c) 2021 Paul Ramsey + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + ****************************************************************************/ + +#include +#include +#include +#include + +#include "../mapserver.h" + +typedef struct { + SHPHandle inSHP, outSHP; + DBFHandle inDBF, outDBF; + int currentOutRecord; + int numDbfFields; +} writeState; + +static char *AddFileSuffix(const char *Filename, const char *Suffix) { + char *pszFullname, *pszBasename; + int i; + + /* -------------------------------------------------------------------- */ + /* Compute the base (layer) name. If there is any extension */ + /* on the passed in filename we will strip it off. */ + /* -------------------------------------------------------------------- */ + pszBasename = (char *)msSmallMalloc(strlen(Filename) + 5); + strcpy(pszBasename, Filename); + for (i = (int)strlen(pszBasename) - 1; + i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/' && + pszBasename[i] != '\\'; + i--) { + } + + if (pszBasename[i] == '.') + pszBasename[i] = '\0'; + + /* -------------------------------------------------------------------- */ + /* Open the .shp and .shx files. Note that files pulled from */ + /* a PC to Unix with upper case filenames won't work! */ + /* -------------------------------------------------------------------- */ + pszFullname = (char *)msSmallMalloc(strlen(pszBasename) + 5); + sprintf(pszFullname, "%s%s", pszBasename, Suffix); + + free(pszBasename); + return (pszFullname); +} + +static int writeShape(writeState *state, int shapeId) { + int j = 0; + int i = state->currentOutRecord; + char fName[20]; + int fWidth, fnDecimals; + shapeObj shape; + + /* Copy the DBF record over */ + for (j = 0; j < state->numDbfFields; j++) { + + DBFFieldType dbfField = + msDBFGetFieldInfo(state->inDBF, j, fName, &fWidth, &fnDecimals); + + switch (dbfField) { + case FTInteger: + msDBFWriteIntegerAttribute( + state->outDBF, i, j, + msDBFReadIntegerAttribute(state->inDBF, shapeId, j)); + break; + case FTDouble: + msDBFWriteDoubleAttribute( + state->outDBF, i, j, + msDBFReadDoubleAttribute(state->inDBF, shapeId, j)); + break; + case FTString: + msDBFWriteStringAttribute( + state->outDBF, i, j, + msDBFReadStringAttribute(state->inDBF, shapeId, j)); + break; + default: + fprintf(stderr, "Unsupported data type for field: %s, exiting.\n", fName); + exit(0); + } + } + + /* Copy the SHP record over */ + msSHPReadShape(state->inSHP, shapeId, &shape); + msSHPWriteShape(state->outSHP, &shape); + msFreeShape(&shape); + + /* Increment output row number */ + state->currentOutRecord++; + + return MS_SUCCESS; +} + +static int writeNode(writeState *state, treeNodeObj *node) { + int i; + if (node->ids) { + for (i = 0; i < node->numshapes; i++) { + int curRec = state->currentOutRecord; + writeShape(state, node->ids[i]); + node->ids[i] = curRec; + } + } + for (i = 0; i < node->numsubnodes; i++) { + if (node->subnode[i]) + writeNode(state, node->subnode[i]); + } + return MS_SUCCESS; +} + +int main(int argc, char *argv[]) { + treeObj *tree; /* In-memory index */ + shapefileObj shapefile; /* Input shapefile */ + SHPHandle outSHP; /* Output SHP */ + DBFHandle outDBF; /* Output DBF */ + DBFFieldType dbfField; + writeState state; + int shpType, nShapes; + char fName[20]; + int fWidth, fnDecimals; + char buffer[1024]; + int numFields; + int i; + + if (argc > 1 && strcmp(argv[1], "-v") == 0) { + printf("%s\n", msGetVersion()); + exit(0); + } + + /* ------------------------------------------------------------------------------- + */ + /* Check the number of arguments, return syntax if not correct */ + /* ------------------------------------------------------------------------------- + */ + if (argc != 3) { + fprintf(stderr, "Syntax: %s [infile] [outfile]\n", argv[0]); + exit(1); + } + + msSetErrorFile("stderr", NULL); + + /* ------------------------------------------------------------------------------- + */ + /* Open the shapefile */ + /* ------------------------------------------------------------------------------- + */ + if (msShapefileOpen(&shapefile, "rb", argv[1], MS_TRUE) < 0) { + fprintf(stdout, "Error opening shapefile %s.\n", argv[1]); + exit(0); + } + + nShapes = shapefile.numshapes; + shpType = shapefile.type; + numFields = msDBFGetFieldCount(shapefile.hDBF); + + /* ------------------------------------------------------------------------------- + */ + /* Index the shapefile (auto-calculate depth) */ + /* ------------------------------------------------------------------------------- + */ + tree = msCreateTree(&shapefile, 0); + msTreeTrim(tree); + + /* ------------------------------------------------------------------------------- + */ + /* Setup the output .shp/.shx and .dbf files */ + /* ------------------------------------------------------------------------------- + */ + outSHP = msSHPCreate(argv[2], shpType); + if (outSHP == NULL) { + fprintf(stderr, "Failed to create file '%s'.\n", argv[2]); + exit(1); + } + + sprintf(buffer, "%s.dbf", argv[2]); + outDBF = msDBFCreate(buffer); + if (outDBF == NULL) { + fprintf(stderr, "Failed to create dbf file '%s'.\n", buffer); + exit(1); + } + + /* Clone the fields from the input to the output definition */ + for (i = 0; i < numFields; i++) { + dbfField = msDBFGetFieldInfo( + shapefile.hDBF, i, fName, &fWidth, + &fnDecimals); /* ---- Get field info from in file ---- */ + msDBFAddField(outDBF, fName, dbfField, fWidth, fnDecimals); + } + + /* ------------------------------------------------------------------------------- + */ + /* Write the sorted .shp/.shx and .dbf files */ + /* ------------------------------------------------------------------------------- + */ + + /* Set up writer state */ + state.inSHP = shapefile.hSHP; + state.outSHP = outSHP; + state.inDBF = shapefile.hDBF; + state.outDBF = outDBF; + state.currentOutRecord = 0; + state.numDbfFields = numFields; + + writeNode(&state, tree->root); + + /* ------------------------------------------------------------------------------- + */ + /* Write the spatial index */ + /* ------------------------------------------------------------------------------- + */ + msWriteTree(tree, AddFileSuffix(argv[2], MS_INDEX_EXTENSION), + MS_NEW_LSB_ORDER); + msDestroyTree(tree); + + /* ------------------------------------------------------------------------------- + */ + /* Close all files */ + /* ------------------------------------------------------------------------------- + */ + msShapefileClose(&shapefile); + msSHPClose(outSHP); + msDBFClose(outDBF); + + fprintf(stdout, "Wrote %d spatially sorted shapes into shapefile '%s'\n", + nShapes, argv[2]); + return (0); +} diff --git a/src/apps/coshp.md b/src/apps/coshp.md new file mode 100644 index 0000000000..8f401c66ef --- /dev/null +++ b/src/apps/coshp.md @@ -0,0 +1,101 @@ +# MapServer QIX File (aka ShpTree) + +https://support.esri.com/en/white-paper/279 + +## Shape File Model + +The shape file consists of three standard components. + +* **shp** file contains the binary representations of the shapes (points, lines, polygons) +* **dbf** file contains the associated attribute information for each shape, one row per shape +* **shx** includes an ordered list of byte offsets of shapes in the **shp** file + +The records in each component are inter-related by their **order of appearance**. The first entry in the **shx** file is the byte offset to the first shape in the shape file, and the first record of the dbf file contains the attributes of the first shape. + +In addition to the standard three components, the QIX model adds a fourth component. + +* **qix** file contains a binary quad-tree, in which every node in the three includes a bounds, a list of child nodes, and a list of "shape ids" that are contained in that node. The "shape ids" are just the record numbers. So "shape id" **0** corresponds to the first record in the shp/dbf/shx files, and so on. + +## Header + +There is an **8 byte** header. + +* **byte 0, len 3** are file signature string, always "SQT" +* **byte 3, len 1** signals the byte-order of multi-byte types + * [see code](https://github.com/MapServer/MapServer/blob/8af82513f8be8a380acbb5d92f9c5dec360ee5f1/maptree.h#L72-L76) + * 1 = LSB (little-endian) + * 2 = MSB (big-endian) + * 0 = native (the endian of the system that wrote the file (probably LSB)) +* **byte 4, len 1** is the version number + * 1 = current version +* **byte 5, len 3** is reserved for future use +* **byte 8, len 4** is an **integer** count of number of shapes in the tree +* **byte 12, len 4** is an **integer** count of depth of the three + +All **integer** values may require a byte swap, if the system byte order differs from the file byte order. + +## Nodes + +Nodes contain an + +* **byte 0, len 4** is an **integer** offset from the just after the numShapes of this node to the start of the next sibling node +* **byte 4, len 8** is a the **double** minx of the node +* **byte 12, len 8** is a the **double** miny of the node +* **byte 20, len 8** is a the **double** maxx of the node +* **byte 28, len 8** is a the **double** maxy of the node +* **byte 36, len 4** is an **integer** numShapes, the count of shape ids stored in this node +* **byte 40, len 4\*numShapes** is an **array of integer** shape ids +* **byte 40+4\*numShapes, 40+4\*numShapes+4** is an **integer** numChildren number of child nodes under this node + +All **integer** and **double** values may require a byte swap, if the system byte order differs from the file byte order. + +Note that the **offset** is the distance in bytes from just after the numShapes entry, 40 bytes from the start of the node. Or put another way, "offset + 40" is the distance from the start of **this** node to the start of the **next sibling** node. + +## Arrangement of Components + +* The file starts with a header. +* A node and all its descendents always form a contiguous range of the file. +* A node has at most four children. +* Both internal and leaf nodes may contain shape ids. + +``` +Header +Node A +Node AA +Node AAA +Node AAB +Node AAC +Node AB +Node ABA +Node ABB +Node AC +Node B +Node BA +Node BAA +Node BAB +Node BB +Node C +``` + +## Searching + +### The Tree + +The spatial search will involve a "query box" and will return a list of "shape id". + +* Recursively search from the top node. +* Check that the node box and the query box intersect. +* If they do not, return. +* If they do, then add the "shape ids" in the node to the result list. +* Call the search function on each child node. + +You can use the "offset" of each child to find the location of the next child in the set. + +Implementation of a reader will probably want to opportunistically load portions of the whole tree into a memory structure, rather than hopping around with random reads. If "distance to next sibling" < some size, load whole subtree into memory and iterate on that. + +### For Features + +Once the tree search is complete, retrieving the features involves pulling the data from the **shp** and **dbf** files. If the shape file has been "cloud optimized", a query rectangle should involve a minimized number of range requests on the data files, since the order of records should match the order of nodes in the tree. + +Analyze the "shape id" list coming out of the tree search, and find contiguous or almost-contiguous ranges of ids. Lookup the [byte offsets](https://www.esri.com/content/dam/esrisites/sitecore-archive/Files/Pdfs/library/whitepapers/pdfs/shapefile.pdf#page=28) from the **shx** file, then retrieve those ranges of data from the **shp** file. The **dbf** file is based on a fixed-length record, so once the header is read, finding the byte offset of a record just involving multiplying the record length by the shape id number. + diff --git a/src/apps/legend.c b/src/apps/legend.c new file mode 100644 index 0000000000..760a63a200 --- /dev/null +++ b/src/apps/legend.c @@ -0,0 +1,65 @@ +/****************************************************************************** + * $Id$ + * + * Project: MapServer + * Purpose: Mainline of commandline legend generation test utility. + * Author: Steve Lime and the MapServer team. + * + ****************************************************************************** + * Copyright (c) 1996-2005 Regents of the University of Minnesota. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + ****************************************************************************/ + +#include "../mapserver.h" + +int main(int argc, char *argv[]) { + mapObj *map = NULL; + imageObj *img = NULL; + + msSetup(); + if (argc > 1 && strcmp(argv[1], "-v") == 0) { + printf("%s\n", msGetVersion()); + exit(0); + } + + if (argc < 3) { + fprintf(stdout, "Syntax: legend [mapfile] [output image]\n"); + exit(0); + } + + map = msLoadMap(argv[1], NULL, NULL); + if (!map) { + msWriteError(stderr); + exit(0); + } + + img = msDrawLegend(map, MS_FALSE, NULL); + if (!img) { + msWriteError(stderr); + exit(0); + } + + msSaveImage(NULL, img, argv[2]); + + msFreeImage(img); + msFreeMap(map); + + return (MS_TRUE); +} diff --git a/src/apps/map2img.c b/src/apps/map2img.c new file mode 100644 index 0000000000..80593c7603 --- /dev/null +++ b/src/apps/map2img.c @@ -0,0 +1,392 @@ +/****************************************************************************** + * $Id$ + * + * Project: MapServer + * Purpose: Commandline .map rendering utility, mostly for testing. + * Author: Steve Lime and the MapServer team. + * + ****************************************************************************** + * Copyright (c) 1996-2005 Regents of the University of Minnesota. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + ****************************************************************************/ + +#include + +#include "../mapserver.h" +#include "../maptime.h" + +#include "limits.h" + +/** + * Check if the required number of arguments are available for the + * parsed option or otherwise print an error message and exit. + * + * @param option option name for the error message + * @param num_required_arguments number of arguments required by option + * @param num_remaining_arguments number of arguments following the option + * @param config optional config object to free if we exit + * @param map optional map object to free if we exit + */ +static void hasMoreArgumentsOrExit(const char *option, + int num_required_arguments, + int num_remaining_arguments, + configObj *config, mapObj *map) { + (void)map; + if (num_remaining_arguments < num_required_arguments) { + if (num_required_arguments == 1) + fprintf(stderr, "Argument %s requires an additional argument.\n", option); + else + fprintf(stderr, "Argument %s needs %i space separated arguments.\n", + option, num_required_arguments); + msCleanup(); + msFreeConfig(config); + exit(1); + } +} + +int main(int argc, char *argv[]) { + int i, j, k; + + mapObj *map = NULL; + imageObj *image = NULL; + configObj *config = NULL; + + char **layers = NULL; + int num_layers = 0; + + int layer_found = 0; + + char *outfile = NULL; /* no -o sends image to STDOUT */ + + int iterations = 1; + int draws = 0; + + /* ---- output version info and exit --- */ + if (argc > 1 && strcmp(argv[1], "-v") == 0) { + printf("%s\n", msGetVersion()); + exit(0); + } + + /* ---- check the number of arguments, return syntax if not correct ---- */ + if (argc < 3) { + fprintf(stdout, "\nPurpose: convert a mapfile to an image\n\n"); + fprintf(stdout, "Syntax: map2img -m mapfile [-o image] [-e minx miny maxx " + "maxy] [-s sizex sizey]\n" + " [-l \"layer1 [layers2...]\"] [-i format]\n" + " [-all_debug n] [-map_debug n] " + "[-layer_debug n] [-p n] [-c n] [-d layername datavalue]\n" + " [-conf filename]\n"); + fprintf(stdout, " -m mapfile: Map file to operate on - required\n"); + fprintf( + stdout, + " -i format: Override the IMAGETYPE value to pick output format\n"); + fprintf(stdout, " -o image: output filename (stdout if not provided)\n"); + fprintf(stdout, " -e minx miny maxx maxy: extents to render\n"); + fprintf(stdout, " -s sizex sizey: output image size\n"); + fprintf(stdout, " -l layers: layers / groups to enable - make sure they " + "are quoted and space separated if more than one listed\n"); + fprintf(stdout, " -all_debug n: Set debug level for map and all layers\n"); + fprintf(stdout, " -map_debug n: Set map debug level\n"); + fprintf(stdout, " -layer_debug layer_name n: Set layer debug level\n"); + fprintf(stdout, " -c n: draw map n number of times\n"); + fprintf(stdout, " -p n: pause for n seconds after reading the map\n"); + fprintf(stdout, " -d layername datavalue: change DATA value for layer\n"); + fprintf( + stdout, + " -conf filename: filename of the MapServer configuration file.\n"); + exit(0); + } + + if (msSetup() != MS_SUCCESS) { + msWriteError(stderr); + exit(1); + } + + bool some_debug_requested = FALSE; + const char *config_filename = NULL; + for (i = 1; i < argc; i++) { + if (strcmp(argv[i], "-c") == 0) { /* user specified number of draws */ + hasMoreArgumentsOrExit("-c", 1, argc - i - 1, config, map); + iterations = atoi(argv[i + 1]); + if (iterations < 0 || iterations > INT_MAX - 1) { + printf("Invalid number of iterations"); + return 1; + } + printf("We will draw %d times...\n", iterations); + continue; + } + + if (strcmp(argv[i], "-all_debug") == 0) { /* global debug */ + hasMoreArgumentsOrExit("-all_debug", 1, argc - i - 1, config, map); + int debug_level = atoi(argv[++i]); + + some_debug_requested = TRUE; + + msSetGlobalDebugLevel(debug_level); + + continue; + } + + if (i < argc - 1 && (strcmp(argv[i], "-map_debug") == 0 || + strcmp(argv[i], "-layer_debug") == 0)) { + + some_debug_requested = TRUE; + continue; + } + + if (strcmp(argv[i], "-conf") == 0) { + hasMoreArgumentsOrExit("-conf", 1, argc - i - 1, config, map); + config_filename = argv[i + 1]; + ++i; + continue; + } + } + + if (some_debug_requested) { + /* Send output to stderr by default */ + if (msGetErrorFile() == NULL) + msSetErrorFile("stderr", NULL); + } + + config = msLoadConfig(config_filename); + + for (draws = 0; draws < iterations; draws++) { + + struct mstimeval requeststarttime, requestendtime; + + if (msGetGlobalDebugLevel() >= MS_DEBUGLEVEL_TUNING) + msGettimeofday(&requeststarttime, NULL); + + /* Use PROJ_DATA/PROJ_LIB env vars if set */ + msProjDataInitFromEnv(); + + /* Use MS_ERRORFILE and MS_DEBUGLEVEL env vars if set */ + if (msDebugInitFromEnv() != MS_SUCCESS) { + msWriteError(stderr); + msCleanup(); + msFreeConfig(config); + exit(1); + } + + for (i = 1; i < argc; + i++) { /* Step though the user arguments, 1st to find map file */ + + if (strcmp(argv[i], "-m") == 0) { + hasMoreArgumentsOrExit("-m", 1, argc - i - 1, config, map); + map = msLoadMap(argv[i + 1], NULL, config); + if (!map) { + msWriteError(stderr); + msCleanup(); + msFreeConfig(config); + exit(1); + } + msApplyDefaultSubstitutions(map); + } + } + + if (!map) { + fprintf(stderr, "Mapfile (-m) option not specified.\n"); + msCleanup(); + msFreeConfig(config); + exit(1); + } + + for (i = 1; i < argc; i++) { /* Step though the user arguments */ + + if (strcmp(argv[i], "-m") == 0) { /* skip it */ + i += 1; + } + + if (strcmp(argv[i], "-p") == 0) { + hasMoreArgumentsOrExit("-p", 1, argc - i - 1, config, map); + int pause_length = atoi(argv[i + 1]); + time_t start_time = time(NULL); + + printf("Start pause of %d seconds.\n", pause_length); + while (time(NULL) < start_time + pause_length) { + } + printf("Done pause.\n"); + + i += 1; + } + + if (strcmp(argv[i], "-o") == 0) { /* load the output image filename */ + hasMoreArgumentsOrExit("-o", 1, argc - i - 1, config, map); + outfile = argv[i + 1]; + i += 1; + } + + if (strcmp(argv[i], "-i") == 0) { + hasMoreArgumentsOrExit("-i", 1, argc - i - 1, config, map); + outputFormatObj *format; + + format = msSelectOutputFormat(map, argv[i + 1]); + + if (format == NULL) + printf("No such OUTPUTFORMAT as %s.\n", argv[i + 1]); + else { + msFree((char *)map->imagetype); + map->imagetype = msStrdup(argv[i + 1]); + msApplyOutputFormat(&(map->outputformat), format, MS_NOOVERRIDE); + } + i += 1; + } + + if (strcmp(argv[i], "-d") == 0) { /* swap layer data */ + hasMoreArgumentsOrExit("-d", 2, argc - i - 1, config, map); + for (j = 0; j < map->numlayers; j++) { + if (strcmp(GET_LAYER(map, j)->name, argv[i + 1]) == 0) { + free(GET_LAYER(map, j)->data); + GET_LAYER(map, j)->data = msStrdup(argv[i + 2]); + break; + } + } + i += 2; + } + + if (strcmp(argv[i], "-all_debug") == 0) { /* global debug */ + hasMoreArgumentsOrExit("-all_debug", 1, argc - i - 1, config, map); + int debug_level = atoi(argv[++i]); + + /* msSetGlobalDebugLevel() already called. Just need to force debug + * level in map and all layers + */ + map->debug = debug_level; + for (j = 0; j < map->numlayers; j++) { + GET_LAYER(map, j)->debug = debug_level; + } + } + + if (strcmp(argv[i], "-map_debug") == 0) { /* debug */ + hasMoreArgumentsOrExit("-map_debug", 1, argc - i - 1, config, map); + map->debug = atoi(argv[++i]); + } + + if (strcmp(argv[i], "-layer_debug") == 0) { /* debug */ + hasMoreArgumentsOrExit("-layer_debug", 2, argc - i - 1, config, map); + const char *layer_name = argv[++i]; + int debug_level = atoi(argv[++i]); + int got_layer = 0; + + for (j = 0; j < map->numlayers; j++) { + if (strcmp(GET_LAYER(map, j)->name, layer_name) == 0) { + GET_LAYER(map, j)->debug = debug_level; + got_layer = 1; + } + } + if (!got_layer) + fprintf(stderr, + " Did not find layer '%s' from -layer_debug switch.\n", + layer_name); + } + + if (strcmp(argv[i], "-e") == 0) { /* change extent */ + hasMoreArgumentsOrExit("-e", 4, argc - i - 1, config, map); + map->extent.minx = atof(argv[i + 1]); + map->extent.miny = atof(argv[i + 2]); + map->extent.maxx = atof(argv[i + 3]); + map->extent.maxy = atof(argv[i + 4]); + i += 4; + } + + if (strcmp(argv[i], "-s") == 0) { + hasMoreArgumentsOrExit("-s", 2, argc - i - 1, config, map); + msMapSetSize(map, atoi(argv[i + 1]), atoi(argv[i + 2])); + i += 2; + } + + if (strcmp(argv[i], "-l") == 0) { /* load layer list */ + hasMoreArgumentsOrExit("-l", 1, argc - i - 1, config, map); + layers = msStringSplit(argv[i + 1], ' ', &(num_layers)); + + for (j = 0; j < num_layers; j++) { /* loop over -l */ + layer_found = 0; + for (k = 0; k < map->numlayers; k++) { + if ((GET_LAYER(map, k)->name && + strcasecmp(GET_LAYER(map, k)->name, layers[j]) == 0) || + (GET_LAYER(map, k)->group && + strcasecmp(GET_LAYER(map, k)->group, layers[j]) == 0)) { + layer_found = 1; + break; + } + } + if (layer_found == 0) { + fprintf(stderr, "Layer (-l) \"%s\" not found\n", layers[j]); + msFreeCharArray(layers, num_layers); + msFreeMap(map); + msCleanup(); + msFreeConfig(config); + exit(1); + } + } + + for (j = 0; j < map->numlayers; j++) { + if (GET_LAYER(map, j)->status == MS_DEFAULT) + continue; + else { + GET_LAYER(map, j)->status = MS_OFF; + for (k = 0; k < num_layers; k++) { + if ((GET_LAYER(map, j)->name && + strcasecmp(GET_LAYER(map, j)->name, layers[k]) == 0) || + (GET_LAYER(map, j)->group && + strcasecmp(GET_LAYER(map, j)->group, layers[k]) == 0)) { + GET_LAYER(map, j)->status = MS_ON; + break; + } + } + } + } + + msFreeCharArray(layers, num_layers); + + i += 1; + } + } + + image = msDrawMap(map, MS_FALSE); + + if (!image) { + msWriteError(stderr); + + msFreeMap(map); + msCleanup(); + msFreeConfig(config); + exit(1); + } + + if (msSaveImage(map, image, outfile) != MS_SUCCESS) { + msWriteError(stderr); + } + + msFreeImage(image); + msFreeMap(map); + + if (msGetGlobalDebugLevel() >= MS_DEBUGLEVEL_TUNING) { + msGettimeofday(&requestendtime, NULL); + msDebug("map2img total time: %.3fs\n", + (requestendtime.tv_sec + requestendtime.tv_usec / 1.0e6) - + (requeststarttime.tv_sec + requeststarttime.tv_usec / 1.0e6)); + } + + } /* for(draws=0; draws +#include +#include + +#ifdef USE_FASTCGI +#define NO_FCGI_DEFINES +#include "fcgi_stdio.h" +#endif + +#include "mapserv.h" +#include "../mapio.h" +#include "../maptime.h" + +#include "cpl_conv.h" + +#ifndef _WIN32 +#include +#endif + +/************************************************************************/ +/* FastCGI cleanup functions. */ +/************************************************************************/ + +static int finish_process = 0; + +#ifndef _WIN32 +static void msCleanupOnSignal(int nInData) { + (void)nInData; + finish_process = 1; +#ifdef USE_FASTCGI + /* Ask libfcgi to stop accepting new requests. This causes a blocked + * FCGI_Accept() to return -1, so the main loop can exit promptly + * instead of waiting for the next request to arrive. Safe to call + * from a signal handler: it just sets an internal flag (declared in + * fcgiapp.h, which is pulled in via fcgi_stdio.h above). */ + FCGX_ShutdownPending(); +#endif +} +#endif + +#ifdef _WIN32 +static void msCleanupOnExit(void) { finish_process = 1; } +#endif + +#ifdef USE_FASTCGI + +/************************************************************************/ +/* msIO_fcgiRead() */ +/* */ +/* This is the default implementation via stdio. */ +/************************************************************************/ + +static int msIO_fcgiRead(void *cbData, void *data, int byteCount) + +{ + return (int)FCGI_fread(data, 1, byteCount, (FCGI_FILE *)cbData); +} + +/************************************************************************/ +/* msIO_fcgiWrite() */ +/* */ +/* This is the default implementation via stdio. */ +/************************************************************************/ + +static int msIO_fcgiWrite(void *cbData, void *data, int byteCount) + +{ + return (int)FCGI_fwrite(data, 1, byteCount, (FCGI_FILE *)cbData); +} + +/************************************************************************/ +/* msIO_installFastCGIRedirect() */ +/************************************************************************/ +static int msIO_installFastCGIRedirect() + +{ + msIOContext stdin_ctx, stdout_ctx, stderr_ctx; + + stdin_ctx.label = "fcgi"; + stdin_ctx.write_channel = MS_FALSE; + stdin_ctx.readWriteFunc = msIO_fcgiRead; + stdin_ctx.cbData = (void *)FCGI_stdin; + + stdout_ctx.label = "fcgi"; + stdout_ctx.write_channel = MS_TRUE; + stdout_ctx.readWriteFunc = msIO_fcgiWrite; + stdout_ctx.cbData = (void *)FCGI_stdout; + + stderr_ctx.label = "fcgi"; + stderr_ctx.write_channel = MS_TRUE; + stderr_ctx.readWriteFunc = msIO_fcgiWrite; + stderr_ctx.cbData = (void *)FCGI_stderr; + + msIO_installHandlers(&stdin_ctx, &stdout_ctx, &stderr_ctx); + + return MS_TRUE; +} + +#endif +/************************************************************************/ +/* main() */ +/************************************************************************/ +int main(int argc, char *argv[]) { + int sendheaders = MS_TRUE; + struct mstimeval execstarttime, execendtime; + struct mstimeval requeststarttime, requestendtime; + mapservObj *mapserv = NULL; + configObj *config = NULL; + + /* + ** Process -v and -h command line arguments first end exit. We want to avoid + *any error messages + ** associated with msLoadConfig() or msSetup(). + */ + const char *config_filename = NULL; + const bool use_command_line_options = getenv("QUERY_STRING") == NULL; + if (use_command_line_options) { + /* WARNING: + * Do not parse command line arguments (especially those that could have + * dangerous consequences if controlled through a web request), without + * checking that the QUERY_STRING environment variable is *not* set, because + * in a CGI context, command line arguments can be generated from the + * content of the QUERY_STRING, and thus cause a security problem. For ex, + * "http://example.com/mapserv.cgi?-conf+bar would result in "mapserv.cgi + * -conf bar" being invoked. See + * https://github.com/MapServer/MapServer/pull/6429#issuecomment-952533589 + * and https://datatracker.ietf.org/doc/html/rfc3875#section-4.4 + */ + for (int iArg = 1; iArg < argc; iArg++) { + if (strcmp(argv[iArg], "-v") == 0) { + printf("%s\n", msGetVersion()); + fflush(stdout); + exit(0); + } else if (strcmp(argv[iArg], "-h") == 0 || + strcmp(argv[iArg], "--help") == 0) { + printf("Usage: mapserv [--help] [-v] [-nh] [QUERY_STRING=value] " + "[PATH_INFO=value]\n"); + printf(" [-conf filename]\n"); + printf("\n"); + printf("Options :\n"); + printf(" -h, --help Display this help message.\n"); + printf(" -v Display version and exit.\n"); + printf( + " -nh Suppress HTTP headers in CGI mode.\n"); + printf(" -conf filename Filename of the MapServer " + "configuration file.\n"); + printf(" QUERY_STRING=value Set the QUERY_STRING in GET request " + "mode.\n"); + printf(" PATH_INFO=value Set the PATH_INFO for an API " + "request.\n"); + fflush(stdout); + exit(0); + } else if (iArg < argc - 1 && strcmp(argv[iArg], "-conf") == 0) { + config_filename = argv[iArg + 1]; + ++iArg; + } + } + } + + config = msLoadConfig(config_filename); // first thing + if (config == NULL) { +#ifdef USE_FASTCGI + msIO_installFastCGIRedirect(); // FastCGI setup for error handling here + FCGI_Accept(); +#endif + msCGIWriteError(mapserv); + exit(0); + } + + /* -------------------------------------------------------------------- */ + /* Initialize mapserver. This sets up threads, GD and GEOS as */ + /* well as using MS_ERRORFILE and MS_DEBUGLEVEL env vars if set. */ + /* -------------------------------------------------------------------- */ + if (msSetup() != MS_SUCCESS) { +#ifdef USE_FASTCGI + msIO_installFastCGIRedirect(); // FastCGI setup for error handling here + FCGI_Accept(); +#endif + msCGIWriteError(mapserv); + msCleanup(); + msFreeConfig(config); + exit(0); + } + + const char *ms_index_dir = + msConfigGetEnv(config, "MS_INDEX_TEMPLATE_DIRECTORY"); + + if (msGetGlobalDebugLevel() >= MS_DEBUGLEVEL_TUNING) + msGettimeofday(&execstarttime, NULL); + + /* -------------------------------------------------------------------- */ + /* Process arguments. In normal use as a cgi-bin there are no */ + /* commandline switches, but we provide a few for test/debug */ + /* purposes. */ + /* -------------------------------------------------------------------- */ + if (use_command_line_options) { + for (int iArg = 1; iArg < argc; iArg++) { + if (strcmp(argv[iArg], "-nh") == 0) { + sendheaders = MS_FALSE; + msIO_setHeaderEnabled(MS_FALSE); + } else if (strncmp(argv[iArg], "QUERY_STRING=", 13) == 0) { + /* Debugging hook... pass "QUERY_STRING=..." on the command-line */ + putenv("REQUEST_METHOD=GET"); + /* coverity[tainted_string] */ + putenv(argv[iArg]); + } else if (strncmp(argv[iArg], "PATH_INFO=", 10) == 0) { + /* Debugging hook for APIs... pass "PATH_INFO=..." on the command-line + */ + putenv("REQUEST_METHOD=GET"); + /* coverity[tainted_string] */ + putenv(argv[iArg]); + } + } + } + + /* -------------------------------------------------------------------- */ + /* Setup cleanup magic, mainly for FastCGI case. */ + /* -------------------------------------------------------------------- */ +#ifndef _WIN32 + { + /* Install via sigaction without SA_RESTART so that a blocking + * accept()/select() inside FCGI_Accept() returns EINTR when the + * signal arrives while the process is idle. Combined with + * FCGX_ShutdownPending() in the handler, this lets the FastCGI + * loop exit on SIGTERM instead of waiting for the next request. */ + struct sigaction sa; + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = msCleanupOnSignal; + sigemptyset(&sa.sa_mask); + sigaddset(&sa.sa_mask, SIGUSR1); + sigaddset(&sa.sa_mask, SIGTERM); + sa.sa_flags = 0; /* deliberately no SA_RESTART */ + sigaction(SIGUSR1, &sa, NULL); + sigaction(SIGTERM, &sa, NULL); + } +#endif + +#ifdef USE_FASTCGI + msIO_installFastCGIRedirect(); + + /* In FastCGI case we loop accepting multiple requests. In normal CGI */ + /* use we only accept and process one request. */ + while (!finish_process && FCGI_Accept() >= 0) { +#endif /* def USE_FASTCGI */ + + /* -------------------------------------------------------------------- */ + /* Process a request. */ + /* -------------------------------------------------------------------- */ + mapserv = msAllocMapServObj(); + mapserv->sendheaders = sendheaders; /* override the default if necessary + (via command line -nh switch) */ + + mapserv->request->NumParams = + loadParams(mapserv->request, NULL, NULL, 0, NULL); + + if (msCGIIsAPIRequest(mapserv) == MS_FALSE && + mapserv->request->NumParams == -1) { /* no QUERY_STRING or PATH_INFO */ + if (ms_index_dir != NULL) { + // return the landing page + msCGIDispatchIndexRequest(mapserv, config); + goto end_request; + } + msCGIWriteError(mapserv); + goto end_request; + } + + mapserv->map = msCGILoadMap(mapserv, config); + if (!mapserv->map) { + for (int i = 0; i < mapserv->request->NumParams; + i++) { /* a map parameter was sent */ + if (strcasecmp(mapserv->request->ParamNames[i], "map") == 0) { + msCGIWriteError(mapserv); + goto end_request; + } + } + if (ms_index_dir != NULL && mapserv->request->path_info != NULL && + strcmp(mapserv->request->path_info, "/") == 0) { + // return the landing page + msCGIDispatchIndexRequest(mapserv, config); + goto end_request; + } + msCGIWriteError(mapserv); + goto end_request; + } + + if (mapserv->map->debug >= MS_DEBUGLEVEL_TUNING) + msGettimeofday(&requeststarttime, NULL); + +#ifdef USE_FASTCGI + if (mapserv->map->debug) { + static int nRequestCounter = 1; + + msDebug("CGI Request %d on process %d\n", nRequestCounter, getpid()); + nRequestCounter++; + } +#endif + + if (mapserv->request->api_path != NULL) { + switch (mapserv->request->api_path_length) { + case 0: // just in case, treat as normal + if (msCGIDispatchRequest(mapserv) != MS_SUCCESS) { + msCGIWriteError(mapserv); + goto end_request; + } + break; + + case 1: + if (ms_index_dir != NULL) { + // Try normal dispatch first + if (msCGIDispatchRequest(mapserv) != MS_SUCCESS) { + errorObj *ms_error = msGetErrorObj(); + int show_index = MS_FALSE; + if (mapserv->request->NumParams == 0) { + show_index = MS_TRUE; + } else if (ms_error != NULL && ms_error->code == MS_WEBERR) { + if (strstr(ms_error->message, "No query information to decode") != + NULL || + strstr(ms_error->message, + "Traditional BROWSE mode requires a TEMPLATE") != + NULL) { + // Fallback to landing page + show_index = MS_TRUE; + } + } + + if (show_index && + msCGIDispatchMapIndexRequest(mapserv, config) == MS_SUCCESS) { + } else { + msCGIWriteError(mapserv); + goto end_request; + } + } + } else { + if (msCGIDispatchRequest(mapserv) != MS_SUCCESS) { + msCGIWriteError(mapserv); + goto end_request; + } + } + break; + + default: // length > 1 + if (msCGIDispatchAPIRequest(mapserv) != MS_SUCCESS) { + msCGIWriteError(mapserv); + goto end_request; + } + break; + } + } else { + // api_path == NULL + if (msCGIDispatchRequest(mapserv) != MS_SUCCESS) { + msCGIWriteError(mapserv); + goto end_request; + } + } + + end_request: + if (mapserv->map && mapserv->map->debug >= MS_DEBUGLEVEL_TUNING) { + msGettimeofday(&requestendtime, NULL); + msDebug("mapserv request processing time (msLoadMap not incl.): %.3fs\n", + (requestendtime.tv_sec + requestendtime.tv_usec / 1.0e6) - + (requeststarttime.tv_sec + requeststarttime.tv_usec / 1.0e6)); + } + msFreeMapServObj(mapserv); +#ifdef USE_FASTCGI + /* FCGI_ --- return to top of loop */ + msResetErrorList(); + continue; + } /* end fastcgi loop */ +#endif + + /* normal case, processing is complete */ + if (msGetGlobalDebugLevel() >= MS_DEBUGLEVEL_TUNING) { + msGettimeofday(&execendtime, NULL); + msDebug("mapserv total execution time: %.3fs\n", + (execendtime.tv_sec + execendtime.tv_usec / 1.0e6) - + (execstarttime.tv_sec + execstarttime.tv_usec / 1.0e6)); + } + msCleanup(); + msFreeConfig(config); + +#ifdef _WIN32 + /* flush pending writes to stdout */ + fflush(stdout); +#endif + + exit(0); +} diff --git a/src/apps/mapserv.h b/src/apps/mapserv.h new file mode 100644 index 0000000000..8535656d43 --- /dev/null +++ b/src/apps/mapserv.h @@ -0,0 +1,79 @@ +/****************************************************************************** + * $Id$ + * + * Project: MapServer + * Purpose: Declarations supporting mapserv.c. + * Author: Steve Lime and the MapServer team. + * + ****************************************************************************** + * Copyright (c) 1996-2005 Regents of the University of Minnesota. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + ****************************************************************************/ + +#ifndef MAPSERV_H +#define MAPSERV_H + +#if defined(_WIN32) && !defined(__CYGWIN__) +#include +#endif + +#include +#include + +#include "../maptemplate.h" +#include "../maptile.h" + +#include "../cgiutil.h" + +/* +** Defines +*/ +#define NUMEXP "[-]?(([0-9]+)|([0-9]*[.][0-9]+)([eE][-+]?[0-9]+)?)" +#define EXTENT_PADDING .05 + +/* +** Macros +*/ +#define TEMPLATE_TYPE(s) \ + (((strncmp("http://", s, 7) == 0) || (strncmp("https://", s, 8) == 0) || \ + (strncmp("ftp://", s, 6)) == 0) \ + ? MS_URL \ + : MS_FILE) + +MS_DLL_EXPORT void msCGIWriteError(mapservObj *mapserv); +MS_DLL_EXPORT mapObj *msCGILoadMap(mapservObj *mapserv, configObj *context); +MS_DLL_EXPORT int msCGIDispatchMapIndexRequest(mapservObj *mapserv, + configObj *config); +MS_DLL_EXPORT int msCGIDispatchIndexRequest(mapservObj *mapserv, + configObj *config); +int msCGISetMode(mapservObj *mapserv); +int msCGILoadForm(mapservObj *mapserv); +int msCGIDispatchBrowseRequest(mapservObj *mapserv); +int msCGIDispatchCoordinateRequest(mapservObj *mapserv); +int msCGIDispatchQueryRequest(mapservObj *mapserv); +int msCGIDispatchImageRequest(mapservObj *mapserv); +int msCGIDispatchLegendRequest(mapservObj *mapserv); +int msCGIDispatchLegendIconRequest(mapservObj *mapserv); +MS_DLL_EXPORT int msCGIDispatchRequest(mapservObj *mapserv); + +MS_DLL_EXPORT int msCGIIsAPIRequest(mapservObj *mapserv); +MS_DLL_EXPORT int msCGIDispatchAPIRequest(mapservObj *mapserv); + +#endif /* MAPSERV_H */ diff --git a/msencrypt.c b/src/apps/msencrypt.c similarity index 81% rename from msencrypt.c rename to src/apps/msencrypt.c index fdf77df9db..e9e453e2a4 100644 --- a/msencrypt.c +++ b/src/apps/msencrypt.c @@ -27,19 +27,16 @@ * DEALINGS IN THE SOFTWARE. ****************************************************************************/ -#include "mapserver.h" +#include "../mapserver.h" - - -void PrintUsage() -{ - printf("Usage: msencrypt <-keygen filename>|<-key filename string_to_encrypt>\n"); +void PrintUsage() { + printf("Usage: msencrypt <-keygen filename>|<-key filename " + "string_to_encrypt>\n"); } -int main(int argc, char *argv[]) -{ +int main(int argc, char *argv[]) { - if (argc == 3 && strcmp(argv[1], "-keygen")==0) { + if (argc == 3 && strcmp(argv[1], "-keygen") == 0) { /* TODO: Move this to a function */ unsigned char pabyKey[16]; @@ -55,17 +52,17 @@ int main(int argc, char *argv[]) printf("ERROR: Failed writing to %s\n", argv[2]); return -1; } - } else if (argc == 4 && strcmp(argv[1], "-key")==0) { + } else if (argc == 4 && strcmp(argv[1], "-key") == 0) { unsigned char key[16]; char *pszBuf; - if (msReadEncryptionKeyFromFile(argv[2], key) != MS_SUCCESS) { + if (msReadEncryptionKeyFromFile(argv[2], key, NULL) != MS_SUCCESS) { printf("ERROR: Failed reading key from file %s\n", argv[2]); return -1; } - pszBuf = (char*)malloc((strlen(argv[3])*2+17)*sizeof(char)); - MS_CHECK_ALLOC(pszBuf, (strlen(argv[3])*2+17)*sizeof(char), -1); + pszBuf = (char *)malloc((strlen(argv[3]) * 2 + 17) * sizeof(char)); + MS_CHECK_ALLOC(pszBuf, (strlen(argv[3]) * 2 + 17) * sizeof(char), -1); msEncryptStringWithKey(key, argv[3], pszBuf); diff --git a/src/apps/scalebar.c b/src/apps/scalebar.c new file mode 100644 index 0000000000..4d587fbe11 --- /dev/null +++ b/src/apps/scalebar.c @@ -0,0 +1,66 @@ +/****************************************************************************** + * $Id$ + * + * Project: MapServer + * Purpose: Commandline scalebar generating utility, mostly for testing. + * Author: Steve Lime and the MapServer team. + * + ****************************************************************************** + * Copyright (c) 1996-2005 Regents of the University of Minnesota. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + ****************************************************************************/ + +#include "../mapserver.h" + +int main(int argc, char *argv[]) { + mapObj *map = NULL; + imageObj *image = NULL; + + msSetup(); + if (argc > 1 && strcmp(argv[1], "-v") == 0) { + printf("%s\n", msGetVersion()); + exit(0); + } + + /* ---- check the number of arguments, return syntax if not correct ---- */ + if (argc < 3) { + fprintf(stdout, "Syntax: scalebar [mapfile] [output image]\n"); + exit(1); + } + + map = msLoadMap(argv[1], NULL, NULL); + if (!map) { + msWriteError(stderr); + exit(1); + } + + image = msDrawScalebar(map); + + if (!image) { + msWriteError(stderr); + exit(1); + } + + msSaveImage(map, image, argv[2]); + msFreeImage(image); + + msFreeMap(map); + return (MS_TRUE); +} diff --git a/src/apps/shptree.c b/src/apps/shptree.c new file mode 100644 index 0000000000..0ced389e12 --- /dev/null +++ b/src/apps/shptree.c @@ -0,0 +1,159 @@ +/****************************************************************************** + * $Id$ + * + * Project: MapServer + * Purpose: Commandline utility to generate .qix shapefile spatial indexes. + * Author: Steve Lime and the MapServer team. + * + ****************************************************************************** + * Copyright (c) 1996-2005 Regents of the University of Minnesota. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + ****************************************************************************/ + +#include "../mapserver.h" +#include "../maptree.h" +#include + +char *AddFileSuffix(const char *Filename, const char *Suffix) { + char *pszFullname, *pszBasename; + int i; + + /* -------------------------------------------------------------------- */ + /* Compute the base (layer) name. If there is any extension */ + /* on the passed in filename we will strip it off. */ + /* -------------------------------------------------------------------- */ + pszBasename = (char *)msSmallMalloc(strlen(Filename) + 5); + strcpy(pszBasename, Filename); + for (i = (int)strlen(pszBasename) - 1; + i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/' && + pszBasename[i] != '\\'; + i--) { + } + + if (pszBasename[i] == '.') + pszBasename[i] = '\0'; + + /* -------------------------------------------------------------------- */ + /* Open the .shp and .shx files. Note that files pulled from */ + /* a PC to Unix with upper case filenames won't work! */ + /* -------------------------------------------------------------------- */ + pszFullname = (char *)msSmallMalloc(strlen(pszBasename) + 5); + sprintf(pszFullname, "%s%s", pszBasename, Suffix); + + free(pszBasename); + return (pszFullname); +} + +int main(int argc, char *argv[]) { + shapefileObj shapefile; + + treeObj *tree; + int byte_order = MS_NEW_LSB_ORDER, i; + int depth = 0; + + if (argc > 1 && strcmp(argv[1], "-v") == 0) { + printf("%s\n", msGetVersion()); + exit(0); + } + + /* -------------------------------------------------------------------- */ + /* Establish the byte order on this machine to decide default */ + /* index format */ + /* -------------------------------------------------------------------- */ + i = 1; + /* cppcheck-suppress knownConditionTrueFalse */ + if (*((uchar *)&i) == 1) + byte_order = MS_NEW_LSB_ORDER; + else + byte_order = MS_NEW_MSB_ORDER; + + if (argc < 2) { + fprintf(stdout, "Syntax:\n"); + fprintf(stdout, " shptree [] []\n"); + fprintf(stdout, "Where:\n"); + fprintf(stdout, " is the name of the .shp file to index.\n"); + fprintf(stdout, + " (optional) is the maximum depth of the index\n"); + fprintf(stdout, + " to create, default is 0 meaning that shptree\n"); + fprintf(stdout, " will calculate a reasonable default depth.\n"); + fprintf(stdout, " (optional) is one of:\n"); + fprintf(stdout, " NL: LSB byte order, using new index format\n"); + fprintf(stdout, " NM: MSB byte order, using new index format\n"); + fprintf(stdout, + " The following old format options are deprecated:\n"); + fprintf(stdout, " N: Native byte order\n"); + fprintf(stdout, " L: LSB (intel) byte order\n"); + fprintf(stdout, " M: MSB byte order\n"); + fprintf(stdout, " The default index_format on this system is: %s\n\n", + (byte_order == MS_NEW_LSB_ORDER) ? "NL" : "NM"); + exit(0); + } + + if (argc >= 3) + depth = atoi(argv[2]); + + if (argc >= 4) { + if (!strcasecmp(argv[3], "N")) + byte_order = MS_NATIVE_ORDER; + if (!strcasecmp(argv[3], "L")) + byte_order = MS_LSB_ORDER; + if (!strcasecmp(argv[3], "M")) + byte_order = MS_MSB_ORDER; + if (!strcasecmp(argv[3], "NL")) + byte_order = MS_NEW_LSB_ORDER; + if (!strcasecmp(argv[3], "NM")) + byte_order = MS_NEW_MSB_ORDER; + } + + if (msShapefileOpen(&shapefile, "rb", argv[1], MS_TRUE) == -1) { + fprintf(stdout, "Error opening shapefile %s.\n", argv[1]); + exit(0); + } + + printf( + "creating index of %s %s format\n", + (byte_order < 1 ? "old (deprecated)" : "new"), + ((byte_order == MS_NATIVE_ORDER) + ? "native" + : ((byte_order == MS_LSB_ORDER) || (byte_order == MS_NEW_LSB_ORDER) + ? " LSB" + : "MSB"))); + + tree = msCreateTree(&shapefile, depth); + if (!tree) { +#if MAX_SUBNODE == 2 + fprintf(stdout, "Error generating binary tree.\n"); +#else + fprintf(stdout, "Error generating quadtree.\n"); +#endif + exit(0); + } + + msWriteTree(tree, AddFileSuffix(argv[1], MS_INDEX_EXTENSION), byte_order); + msDestroyTree(tree); + + /* + ** Clean things up + */ + msShapefileClose(&shapefile); + + return (0); +} diff --git a/src/apps/shptreetst.c b/src/apps/shptreetst.c new file mode 100644 index 0000000000..3e5a1e98b1 --- /dev/null +++ b/src/apps/shptreetst.c @@ -0,0 +1,178 @@ +/****************************************************************************** + * $Id$ + * + * Project: MapServer + * Purpose: Utility program to visualize a quadtree search + * Author: Steve Lime and the MapServer team. + * + ****************************************************************************** + * Copyright (c) 1996-2005 Regents of the University of Minnesota. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + ****************************************************************************/ + +#include "../mapserver.h" +#include +#ifndef _WIN32 +#include +#endif +#include +#include + +#ifdef SHPT_POLYGON +#undef MAPSERVER +#else +#define MAPSERVER 1 +#define SHPT_POLYGON MS_SHP_POLYGON +#endif + +char *AddFileSuffix(const char *Filename, const char *Suffix) { + char *pszFullname, *pszBasename; + int i; + + /* -------------------------------------------------------------------- */ + /* Compute the base (layer) name. If there is any extension */ + /* on the passed in filename we will strip it off. */ + /* -------------------------------------------------------------------- */ + pszBasename = (char *)msSmallMalloc(strlen(Filename) + 5); + strcpy(pszBasename, Filename); + for (i = (int)strlen(pszBasename) - 1; + i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/' && + pszBasename[i] != '\\'; + i--) { + } + + if (pszBasename[i] == '.') + pszBasename[i] = '\0'; + + /* -------------------------------------------------------------------- */ + /* Open the .shp and .shx files. Note that files pulled from */ + /* a PC to Unix with upper case filenames won't work! */ + /* -------------------------------------------------------------------- */ + pszFullname = (char *)msSmallMalloc(strlen(pszBasename) + 5); + sprintf(pszFullname, "%s%s", pszBasename, Suffix); + msFree(pszBasename); + + return (pszFullname); +} + +int main(int argc, char **argv) + +{ + SHPTreeHandle qix; + + int i, j; + rectObj rect; + + int pos; + ms_bitarray bitmap = NULL; + + /* + char mBigEndian; + */ + treeNodeObj *node = NULL; + + /* -------------------------------------------------------------------- */ + /* Display a usage message. */ + /* -------------------------------------------------------------------- */ + if (argc <= 1) { + printf("shptreetst shapefile {minx miny maxx maxy}\n"); + exit(1); + } + + /* + i = 1; + if( *((unsigned char *) &i) == 1 ) + mBigEndian = 0; + else + mBigEndian = 1; + */ + + qix = msSHPDiskTreeOpen(AddFileSuffix(argv[1], ".qix"), 0 /* no debug*/); + if (qix == NULL) { + printf("unable to open index file %s \n", argv[1]); + exit(-1); + } + + printf("This %s %s index supports a shapefile with %d shapes, %d depth \n", + (qix->version ? "new" : "old"), (qix->LSB_order ? "LSB" : "MSB"), + (int)qix->nShapes, (int)qix->nDepth); + + /* -------------------------------------------------------------------- */ + /* Skim over the list of shapes, printing all the vertices. */ + /* -------------------------------------------------------------------- */ + + pos = ftell(qix->fp); + j = 0; + + while (pos && j < 20) { + j++; + /* fprintf (stderr,"box %d, at %d pos \n", j, (int) ftell(qix)); + */ + + node = readTreeNode(qix); + if (node) { + fprintf(stdout, "shapes %d, node %d, %f,%f,%f,%f \n", + (int)node->numshapes, node->numsubnodes, node->rect.minx, + node->rect.miny, node->rect.maxx, node->rect.maxy); + + } else { + pos = 0; + } + } + + printf("read entire file now at quad box rec %d file pos %ld\n", j, + ftell(qix->fp)); + + j = qix->nShapes; + msSHPDiskTreeClose(qix); + + if (argc >= 5) { + rect.minx = atof(argv[2]); + rect.miny = atof(argv[3]); + rect.maxx = atof(argv[4]); + rect.maxy = atof(argv[5]); + } else { + if (node == NULL) { + printf("node == NULL"); + return 1; + } + printf("using last read box as a search \n"); + rect.minx = node->rect.minx; + rect.miny = node->rect.miny; + rect.maxx = node->rect.maxx; + rect.maxy = node->rect.maxy; + } + + bitmap = msSearchDiskTree(argv[1], rect, 0 /* no debug*/, j); + + /* j < INT_MAX - 1 test just to please Coverity untrusted bound loop warning + */ + if (bitmap && j < INT_MAX - 1) { + printf("result of rectangle search was \n"); + for (i = 0; i < j; i++) { + if (msGetBit(bitmap, i)) { + printf(" %d,", i); + } + } + } + printf("\n"); + + return (0); +} diff --git a/src/apps/shptreevis.c b/src/apps/shptreevis.c new file mode 100644 index 0000000000..d22b5dda86 --- /dev/null +++ b/src/apps/shptreevis.c @@ -0,0 +1,241 @@ +/****************************************************************************** + * $Id$ + * + * Project: MapServer + * Purpose: Utility program to visualize a quadtree + * Author: Steve Lime and the MapServer team. + * + ****************************************************************************** + * Copyright (c) 1996-2005 Regents of the University of Minnesota. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + ****************************************************************************/ + +#include "../mapserver.h" +#include +#ifndef _WIN32 +#include +#endif +#include + +#ifdef SHPT_POLYGON +#undef MAPSERVER +#else +#define MAPSERVER 1 +#define SHPT_POLYGON SHP_POLYGON +#endif + +char *AddFileSuffix(const char *Filename, const char *Suffix) { + char *pszFullname, *pszBasename; + size_t i; + + /* -------------------------------------------------------------------- */ + /* Compute the base (layer) name. If there is any extension */ + /* on the passed in filename we will strip it off. */ + /* -------------------------------------------------------------------- */ + pszBasename = (char *)msSmallMalloc(strlen(Filename) + 5); + strcpy(pszBasename, Filename); + for (i = strlen(pszBasename) - 1; + i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/' && + pszBasename[i] != '\\'; + i--) { + } + + if (pszBasename[i] == '.') + pszBasename[i] = '\0'; + + /* -------------------------------------------------------------------- */ + /* Open the .shp and .shx files. Note that files pulled from */ + /* a PC to Unix with upper case filenames won't work! */ + /* -------------------------------------------------------------------- */ + pszFullname = (char *)msSmallMalloc(strlen(pszBasename) + 5); + sprintf(pszFullname, "%s%s", pszBasename, Suffix); + + free(pszBasename); + return (pszFullname); +} + +int main(int argc, char **argv) + +{ + SHPHandle hSHP; + DBFHandle hDBF; + SHPTreeHandle qix; + + char *myfile = NULL; + + treeNodeObj *node; + +#ifdef MAPSERVER + shapeObj shape; + lineObj line[3]; + pointObj pts[6]; +#else + SHPObject *shape; + double X[6], Y[6]; +#endif + int result; + + /* + char mBigEndian; + int i; + */ + + int this_rec; + + /* -------------------------------------------------------------------- */ + /* Display a usage message. */ + /* -------------------------------------------------------------------- */ + if (argc <= 2) { + printf("shptreevis shapefile new_shapefile \n"); + exit(1); + } + + /* + i = 1; + if( *((unsigned char *) &i) == 1 ) + mBigEndian = 0; + else + mBigEndian = 1; + */ + + qix = msSHPDiskTreeOpen(AddFileSuffix(argv[1], ".qix"), 0 /* no debug*/); + if (qix == NULL) { + printf("unable to open index file %s \n", argv[1]); + exit(-1); + } + + /* -------------------------------------------------------------------- */ + /* Open the passed shapefile. */ + /* -------------------------------------------------------------------- */ + myfile = AddFileSuffix(argv[2], ".shp"); + +#ifdef MAPSERVER + hSHP = msSHPCreate(myfile, SHPT_POLYGON); + hDBF = msDBFCreate(AddFileSuffix(argv[2], ".dbf")); +#else + hSHP = SHPCreate(myfile, SHPT_POLYGON); + hDBF = DBFCreate(AddFileSuffix(argv[2], ".dbf")); +#endif + + if ((!hSHP) || (!hDBF)) { + printf("create error for %s ... exiting \n", myfile); + exit(-1); + } + + /* add fields to dbf */ +#ifdef MAPSERVER + msDBFAddField(hDBF, "ITEMS", FTInteger, 15, 0); + msDBFAddField(hDBF, "SUBNODES", FTInteger, 15, 0); + msDBFAddField(hDBF, "FACTOR", FTInteger, 15, 0); +#else + DBFAddField(hDBF, "ITEMS", FTInteger, 15, 0); + DBFAddField(hDBF, "SUBNODES", FTInteger, 15, 0); + DBFAddField(hDBF, "FACTOR", FTInteger, 15, 0); +#endif + +#ifndef MAPSERVER + SHPClose(hSHP); + hSHP = SHPOpen(myfile, "r+b"); + + DBFClose(hDBF); + hDBF = DBFOpen(myfile, "r+b"); +#endif + + printf("This %s %s index supports a shapefile with %d shapes, %d depth \n", + (qix->version ? "new" : "old"), (qix->LSB_order ? "LSB" : "MSB"), + (int)qix->nShapes, (int)qix->nDepth); + + /* -------------------------------------------------------------------- */ + /* Skim over the list of shapes, printing all the vertices. */ + /* -------------------------------------------------------------------- */ + + while (1) { + node = readTreeNode(qix); + if (node) { + + this_rec = hDBF->nRecords; + +#ifdef MAPSERVER + msDBFWriteIntegerAttribute(hDBF, this_rec, 0, node->numshapes); + msDBFWriteIntegerAttribute(hDBF, this_rec, 1, node->numsubnodes); +#else + DBFWriteIntegerAttribute(hDBF, this_rec, 0, node->numshapes); + DBFWriteIntegerAttribute(hDBF, this_rec, 1, node->numsubnodes); +#endif + +#ifdef MAPSERVER + shape.numlines = 1; + shape.type = SHPT_POLYGON; + + pts[0].x = node->rect.minx; + pts[0].y = node->rect.miny; + pts[1].x = node->rect.maxx; + pts[1].y = node->rect.miny; + pts[2].x = node->rect.maxx; + pts[2].y = node->rect.maxy; + pts[3].x = node->rect.minx; + pts[3].y = node->rect.maxy; + pts[4].x = node->rect.minx; + pts[4].y = node->rect.miny; + + line[0].numpoints = 5; + line[0].point = &pts[0]; + shape.line = &line[0]; + shape.bounds = node->rect; + + result = msSHPWriteShape(hSHP, &shape); + if (result < 0) { + printf("unable to write shape \n"); + exit(0); + } + +#else + X[0] = node->rect.minx; + X[1] = node->rect.maxx; + X[2] = node->rect.maxx; + X[3] = node->rect.minx; + X[4] = node->rect.minx; + + Y[0] = node->rect.miny; + Y[1] = node->rect.miny; + Y[2] = node->rect.maxy; + Y[3] = node->rect.maxy; + Y[4] = node->rect.miny; + + shape = SHPCreateSimpleObject(SHPT_POLYGON, 5, X, Y, NULL); + SHPWriteObject(hSHP, -1, shape); + SHPDestroyObject(shape); +#endif + } else + break; + } + +#ifdef MAPSERVER + msSHPClose(hSHP); + msDBFClose(hDBF); +#else + SHPClose(hSHP); + DBFClose(hDBF); +#endif + + msSHPDiskTreeClose(qix); + + return (0); +} diff --git a/src/apps/sortshp.c b/src/apps/sortshp.c new file mode 100644 index 0000000000..95d9d11433 --- /dev/null +++ b/src/apps/sortshp.c @@ -0,0 +1,260 @@ +/****************************************************************************** + * $Id$ + * + * Project: MapServer + * Purpose: Command line utility to sort a shapefile based on a single + * attribute in ascending or descending order. Useful for + * prioritizing drawing or labeling of shapes. + * Author: Steve Lime and the MapServer team. + * + ****************************************************************************** + * Copyright (c) 1996-2005 Regents of the University of Minnesota. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + ****************************************************************************/ + +#include +#include +#include +#include + +#include "../mapserver.h" + +typedef struct { + double number; + char string[255]; + int index; +} sortStruct; + +static int compare_string_descending(const void *a, const void *b) { + const sortStruct *i = a, *j = b; + return (strcmp(j->string, i->string)); +} + +static int compare_string_ascending(const void *a, const void *b) { + const sortStruct *i = a, *j = b; + return (strcmp(i->string, j->string)); +} + +static int compare_number_descending(const void *a, const void *b) { + const sortStruct *i = a, *j = b; + if (i->number > j->number) + return (-1); + if (i->number < j->number) + return (1); + return (0); +} + +static int compare_number_ascending(const void *a, const void *b) { + const sortStruct *i = a, *j = b; + if (i->number > j->number) + return (1); + if (i->number < j->number) + return (-1); + return (0); +} + +int main(int argc, char *argv[]) { + SHPHandle inSHP, outSHP; /* ---- Shapefile file pointers ---- */ + DBFHandle inDBF, outDBF; /* ---- DBF file pointers ---- */ + sortStruct *array; + shapeObj shape; + int shpType, nShapes; + int fieldNumber = -1; /* ---- Field number of item to be sorted on ---- */ + DBFFieldType dbfField; + char fName[20]; + int fWidth, fnDecimals; + char buffer[1024]; + int i, j; + int num_fields, num_records; + + if (argc > 1 && strcmp(argv[1], "-v") == 0) { + printf("%s\n", msGetVersion()); + exit(0); + } + + /* ------------------------------------------------------------------------------- + */ + /* Check the number of arguments, return syntax if not correct */ + /* ------------------------------------------------------------------------------- + */ + if (argc != 5) { + fprintf( + stderr, + "Syntax: sortshp [infile] [outfile] [item] [ascending|descending]\n"); + exit(1); + } + + msSetErrorFile("stderr", NULL); + + /* ------------------------------------------------------------------------------- + */ + /* Open the shapefile */ + /* ------------------------------------------------------------------------------- + */ + inSHP = msSHPOpen(argv[1], "rb"); + if (!inSHP) { + fprintf(stderr, "Unable to open %s shapefile.\n", argv[1]); + exit(1); + } + msSHPGetInfo(inSHP, &nShapes, &shpType); + + /* ------------------------------------------------------------------------------- + */ + /* Open the dbf file */ + /* ------------------------------------------------------------------------------- + */ + snprintf(buffer, sizeof(buffer), "%s.dbf", argv[1]); + inDBF = msDBFOpen(buffer, "rb"); + if (inDBF == NULL) { + fprintf(stderr, "Unable to open %s XBASE file.\n", buffer); + exit(1); + } + + num_fields = msDBFGetFieldCount(inDBF); + num_records = msDBFGetRecordCount(inDBF); + + for (i = 0; i < num_fields; i++) { + msDBFGetFieldInfo(inDBF, i, fName, NULL, NULL); + if (strncasecmp(argv[3], fName, (int)strlen(argv[3])) == + 0) { /* ---- Found it ---- */ + fieldNumber = i; + break; + } + } + + if (fieldNumber < 0) { + fprintf(stderr, "Item %s doesn't exist in %s\n", argv[3], buffer); + exit(1); + } + + array = (sortStruct *)malloc(sizeof(sortStruct) * + num_records); /* ---- Allocate the array ---- */ + if (!array) { + fprintf(stderr, "Unable to allocate sort array.\n"); + exit(1); + } + + /* ------------------------------------------------------------------------------- + */ + /* Load the array to be sorted */ + /* ------------------------------------------------------------------------------- + */ + dbfField = msDBFGetFieldInfo(inDBF, fieldNumber, NULL, NULL, NULL); + switch (dbfField) { + case FTString: + for (i = 0; i < num_records; i++) { + strlcpy(array[i].string, msDBFReadStringAttribute(inDBF, i, fieldNumber), + sizeof(array[i].string)); + array[i].index = i; + } + + if (*argv[4] == 'd') + qsort(array, num_records, sizeof(sortStruct), compare_string_descending); + else + qsort(array, num_records, sizeof(sortStruct), compare_string_ascending); + break; + case FTInteger: + case FTDouble: + for (i = 0; i < num_records; i++) { + array[i].number = msDBFReadDoubleAttribute(inDBF, i, fieldNumber); + array[i].index = i; + } + + if (*argv[4] == 'd') + qsort(array, num_records, sizeof(sortStruct), compare_number_descending); + else + qsort(array, num_records, sizeof(sortStruct), compare_number_ascending); + + break; + default: + fprintf(stderr, "Data type for item %s not supported.\n", argv[3]); + exit(1); + } + + /* ------------------------------------------------------------------------------- + */ + /* Setup the output .shp/.shx and .dbf files */ + /* ------------------------------------------------------------------------------- + */ + outSHP = msSHPCreate(argv[2], shpType); + if (outSHP == NULL) { + fprintf(stderr, "Failed to create file '%s'.\n", argv[2]); + exit(1); + } + + sprintf(buffer, "%s.dbf", argv[2]); + outDBF = msDBFCreate(buffer); + if (outDBF == NULL) { + fprintf(stderr, "Failed to create dbf file '%s'.\n", buffer); + exit(1); + } + + for (i = 0; i < num_fields; i++) { + dbfField = msDBFGetFieldInfo( + inDBF, i, fName, &fWidth, + &fnDecimals); /* ---- Get field info from in file ---- */ + msDBFAddField(outDBF, fName, dbfField, fWidth, fnDecimals); + } + + /* ------------------------------------------------------------------------------- + */ + /* Write the sorted .shp/.shx and .dbf files */ + /* ------------------------------------------------------------------------------- + */ + for (i = 0; i < num_records; i++) { /* ---- For each shape/record ---- */ + + for (j = 0; j < num_fields; j++) { /* ---- For each .dbf field ---- */ + + dbfField = msDBFGetFieldInfo(inDBF, j, fName, &fWidth, &fnDecimals); + + switch (dbfField) { + case FTInteger: + msDBFWriteIntegerAttribute( + outDBF, i, j, msDBFReadIntegerAttribute(inDBF, array[i].index, j)); + break; + case FTDouble: + msDBFWriteDoubleAttribute( + outDBF, i, j, msDBFReadDoubleAttribute(inDBF, array[i].index, j)); + break; + case FTString: + msDBFWriteStringAttribute( + outDBF, i, j, msDBFReadStringAttribute(inDBF, array[i].index, j)); + break; + default: + fprintf(stderr, "Unsupported data type for field: %s, exiting.\n", + fName); + exit(0); + } + } + + msSHPReadShape(inSHP, array[i].index, &shape); + msSHPWriteShape(outSHP, &shape); + msFreeShape(&shape); + } + + free(array); + + msSHPClose(inSHP); + msDBFClose(inDBF); + msSHPClose(outSHP); + msDBFClose(outDBF); + + return (0); +} diff --git a/testcopy.c b/src/apps/testcopy.c similarity index 93% rename from testcopy.c rename to src/apps/testcopy.c index 782fa8a035..991cbdc6cb 100644 --- a/testcopy.c +++ b/src/apps/testcopy.c @@ -27,14 +27,11 @@ * DEALINGS IN THE SOFTWARE. ****************************************************************************/ -#include "mapserver.h" +#include "../mapserver.h" +void printAtts(mapObj *, const char *); - -void printAtts(mapObj*, const char*); - -int main(int argc, char *argv[]) -{ +int main(int argc, char *argv[]) { mapObj *original_map, *clone_map; @@ -45,7 +42,7 @@ int main(int argc, char *argv[]) /* Load map file */ original_map = msLoadMap("tests/test.map", NULL); - if (original_map == NULL) { + if (original_map == NULL) { /* Write errors */ msWriteError(stderr); msResetErrorList(); @@ -75,8 +72,7 @@ int main(int argc, char *argv[]) exit(0); } -void printAtts(mapObj *map, const char *title) -{ +void printAtts(mapObj *map, const char *title) { printf("\n%s Attributes\n----------------------\n", title); printf("Map Name: %s\n", map->name); printf("Numlayers: %d\n", map->numlayers); diff --git a/testexpr.c b/src/apps/testexpr.c similarity index 91% rename from testexpr.c rename to src/apps/testexpr.c index db306a02d1..ef23a35705 100644 --- a/testexpr.c +++ b/src/apps/testexpr.c @@ -29,11 +29,9 @@ #include -#include "mapserver.h" -#include "mapparser.h" -#include "mapfile.h" - - +#include "../mapserver.h" +#include "../mapparser.h" +#include "../mapfile.h" extern int msyyparse(); extern int msyylex(); @@ -43,17 +41,16 @@ extern int msyyresult; /* result of parsing, true/false */ extern int msyystate; extern char *msyystring; -int main(int argc, char *argv[]) -{ +int main(int argc, char *argv[]) { int status; - if(argc > 1 && strcmp(argv[1], "-v") == 0) { + if (argc > 1 && strcmp(argv[1], "-v") == 0) { printf("%s\n", msGetVersion()); exit(0); } /* ---- check the number of arguments, return syntax if not correct ---- */ - if( argc < 2) { + if (argc < 2) { fprintf(stdout, "Syntax: testexpr [string]\n"); exit(0); } @@ -62,7 +59,7 @@ int main(int argc, char *argv[]) msyystring = argv[1]; status = msyyparse(); - if(status != 0) + if (status != 0) printf("Error parsing expression near %s.\n", msyystring_buffer); else printf("Expression evalulated to: %d.\n", msyyresult); diff --git a/src/apps/tile4ms.c b/src/apps/tile4ms.c new file mode 100644 index 0000000000..634a7ec1ea --- /dev/null +++ b/src/apps/tile4ms.c @@ -0,0 +1,284 @@ +/****************************************************************************** + * $Id$ + * + * Project: MapServer + * Purpose: Create shapefile of rectangles from extents of several shapefiles + * (=tiles) + * Create DBF with file names for shape tiles, in column LOCATION as + * required by mapserv. + * For use with Mapserv tiling capability. + * Author: Herbie Freytag hfreytag@dlwc.nsw.gov.au + * + * Note: + * Resulting shape files do not display in ArcView. + * + ****************************************************************************** + * Copyright (c) 1996-2005 Regents of the University of Minnesota. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + *****************************************************************************/ + +/* + * This is a modified version of Herbie's program that works with MapServer's + * shapelib and should be using the MapServer makefile. + * + */ + +#include "../mapserver.h" +#include + +/***********************************************************************/ +int process_shapefiles(char *metaFileNameP, char *tileFileNameP, + int tile_path_only) { + SHPHandle hSHP, tileSHP; + rectObj extentRect; + lineObj line; + shapeObj shapeRect; + DBFHandle tileDBF; + DBFHandle shpDBF; + + typedef struct DBFFieldDef_struct { + DBFFieldType type; + char name[12]; + int width; + int decimals; + } DBFFieldDef; + + DBFFieldDef *theFields = NULL; + char fldname[256]; + int width; + int decimals; + int fieldCnt; + int i; + + FILE *metaFP = NULL; + char *p; + char tileshapeName[256]; + char tiledbfName[256]; + char shapeFileName[256]; + int entityNum; + + int tilesFound = 0; + int tilesProcessed = 0; + + msInitShape(&shapeRect); + line.point = (pointObj *)msSmallMalloc(sizeof(pointObj) * 5); + line.numpoints = 5; + + /* open metafile */ + /* ------------- */ + if (NULL == (metaFP = fopen(metaFileNameP, "r"))) { + printf("Unable to open:%s\n", metaFileNameP); + return (1); + } + + /* create new tileindex shapefiles and create a header */ + /* -------------------------------------------------- */ + snprintf(tileshapeName, sizeof(tileshapeName), "%s.shp", tileFileNameP); + + if (NULL == (tileSHP = msSHPCreate(tileFileNameP, SHP_POLYGON))) { + fclose(metaFP); + printf("Unable to create %s.shp (.shx)\n", tileFileNameP); + return (1); + } + + /* create new tileindex dbf-file */ + /* ----------------------------- */ + snprintf(tiledbfName, sizeof(tiledbfName), "%s.dbf", tileFileNameP); + if (NULL == (tileDBF = msDBFCreate(tiledbfName))) { + fclose(metaFP); + msSHPClose(tileSHP); + printf("DBFCreate(%s) failed.\n", tiledbfName); + return (1); + } + + if (msDBFAddField(tileDBF, "LOCATION", FTString, 255, 0) == -1) { + fclose(metaFP); + msSHPClose(tileSHP); + msDBFClose(tileDBF); + printf("DBFAddField(fieldname='LOCATION') failed.\n"); + return (1); + } + + /* loop through files listed in metafile */ + /* ===================================== */ + while (fgets(shapeFileName, 255, metaFP)) { + + if ((p = strchr(shapeFileName, '\n')) != NULL) + *p = '\0'; + + if (!strlen(shapeFileName)) + break; + + tilesFound++; + + /* read the DBFFields for this shapefile */ + /* and save them if the first, otherwise compare them */ + + shpDBF = msDBFOpen(shapeFileName, "rb"); + + if (shpDBF == NULL) { + printf("Aborted. Unable to open DBF:%s\n", shapeFileName); + break; + } + + if (theFields == NULL) { + fieldCnt = msDBFGetFieldCount(shpDBF); + theFields = (DBFFieldDef *)msSmallCalloc(fieldCnt, sizeof(DBFFieldDef)); + for (i = 0; i < fieldCnt; i++) { + theFields[i].type = + msDBFGetFieldInfo(shpDBF, i, theFields[i].name, &theFields[i].width, + &theFields[i].decimals); + if (theFields[i].type == FTInvalid) { + printf("Aborted. DBF Invalid field (%d of %d) file:%s\n", i, fieldCnt, + shapeFileName); + break; + } + } + } else { + fieldCnt = msDBFGetFieldCount(shpDBF); + for (i = 0; i < fieldCnt; i++) { + if (theFields[i].type != + msDBFGetFieldInfo(shpDBF, i, fldname, &width, &decimals) || + strcmp(theFields[i].name, fldname) || theFields[i].width != width || + theFields[i].decimals != decimals) { + printf("Aborted. DBF fields do not match for file:%s\n", + shapeFileName); + break; + } + } + } + msDBFClose(shpDBF); + + /* Get rid of .shp extension if it was included. */ + if (strlen(shapeFileName) > 4 && + (p = shapeFileName + strlen(shapeFileName) - 4) && + strcasecmp(p, ".shp") == 0) + *p = '\0'; + + if (!strlen(shapeFileName)) + break; + + /* read extent from shapefile */ + /* -------------------------- */ + hSHP = msSHPOpen(shapeFileName, "rb"); + + if (hSHP == NULL) { + printf("Aborted. Unable to open SHP:%s\n", shapeFileName); + break; + } + + msSHPReadBounds(hSHP, -1, &extentRect); + /* SHPGetInfo(hSHP, &nEntities, &nShapeType, adfBndsMin, adfBndsMax); */ + + /* printf("File: %s Bounds 0/1: + * (%15.10lg,%15.10lg)\n\t(%15.10lg,%15.10lg)\n", shapeFileName, + * adfBndsMin[0], adfBndsMin[1], adfBndsMax[0], adfBndsMax[1] ); */ + + msSHPClose(hSHP); + + /* create rectangle describing current shapefile extent */ + /* ---------------------------------------------------- */ + + line.point[0].x = line.point[4].x = extentRect.minx; /* bottom left */ + line.point[0].y = line.point[4].y = extentRect.miny; + line.point[1].x = extentRect.minx; /* top left */ + line.point[1].y = extentRect.maxy; + line.point[2].x = extentRect.maxx; /* top left */ + line.point[2].y = extentRect.maxy; + line.point[3].x = extentRect.maxx; /* bottom right */ + line.point[3].y = extentRect.miny; + + /* create and add shape object. Returns link to entry in DBF file */ + /* --------------------------------------------------------------- */ + + shapeRect.type = MS_SHAPE_POLYGON; + msAddLine(&shapeRect, &line); + entityNum = msSHPWriteShape(tileSHP, &shapeRect); + + msFreeShape(&shapeRect); + + /* store filepath of current shapefile as attribute of rectangle */ + /* ------------------------------------------------------------- */ + + /* Strip off filename if requested */ + if (tile_path_only) { + char *pszTmp; + if ((pszTmp = strrchr(shapeFileName, '/')) != NULL || + (pszTmp = strrchr(shapeFileName, '\\')) != NULL) { + *(pszTmp + 1) = '\0'; /* Keep the trailing '/' only. */ + } + } + + msDBFWriteStringAttribute(tileDBF, entityNum, 0, shapeFileName); + + tilesProcessed++; + } + + msSHPClose(tileSHP); + msDBFClose(tileDBF); + + fclose(metaFP); + + free(line.point); + free(theFields); + + printf("Processed %i of %i files\n", tilesProcessed, tilesFound); + + return (0); +} + +/***********************************************************************/ +void print_usage_and_exit(void) { + + printf("\nusage: tile4ms [-tile-path-only]\n"); + printf("\tINPUT file containing list of shapefile " + "names\n\t\t(complete paths 255 chars max, no extension)\n"); + printf("\tOUTPUT shape file of extent rectangles and " + "names\n\t\tof tiles in .dbf\n"); + printf("-tile-path-only\tOptional flag. If specified then only the path to " + "the \n\t\tshape files will be stored in the LOCATION " + "field\n\t\tinstead of storing the full filename.\n\n"); + exit(1); +} + +/***********************************************************************/ +int main(int argc, char **argv) { + int tile_path_only = 0; + + /* stun user with existence of help */ + /* -------------------------------- */ + if ((argc == 2) && (strstr(argv[1], "-h"))) { + print_usage_and_exit(); + } + + /* check arguments */ + /* --------------- */ + if (argc < 3) { + print_usage_and_exit(); + } + + if (argc == 4 && strcmp(argv[3], "-tile-path-only") == 0) { + tile_path_only = 1; + } + + process_shapefiles(argv[1], argv[2], tile_path_only); + + exit(0); +} diff --git a/src/cgiutil.c b/src/cgiutil.c new file mode 100644 index 0000000000..2ebb50d337 --- /dev/null +++ b/src/cgiutil.c @@ -0,0 +1,537 @@ +/****************************************************************************** + * $Id$ + * + * Project: MapServer + * Purpose: cgiRequestObj and CGI parameter parsing. + * Author: Steve Lime and the MapServer team. + * + * Notes: Portions derived from NCSA HTTPd Server's example CGI programs + *(util.c). + * + ****************************************************************************** + * Copyright (c) 1996-2005 Regents of the University of Minnesota. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + ****************************************************************************/ + +#include +#include +#include +#include +#include "mapserver.h" +#include "cgiutil.h" + +#include "cpl_conv.h" + +#define LF 10 +#define CR 13 + +int readPostBody(cgiRequestObj *request, char **data) { + size_t data_max, data_len; + int chunk_size; + + (void)request; + + msIO_needBinaryStdin(); + + /* -------------------------------------------------------------------- */ + /* If the length is provided, read in one gulp. */ + /* -------------------------------------------------------------------- */ + if (getenv("CONTENT_LENGTH") != NULL) { + data_max = (size_t)atoi(getenv("CONTENT_LENGTH")); + /* Test for suspicious CONTENT_LENGTH (negative value or SIZE_MAX) */ + if (data_max >= SIZE_MAX) { + // msIO_setHeader("Content-Type","text/html"); + // msIO_sendHeaders(); + // msIO_printf("Suspicious Content-Length.\n"); + msSetError(MS_WEBERR, "Suspicious Content-Length.", "readPostBody()"); + return MS_FAILURE; + } + *data = (char *)malloc(data_max + 1); + if (*data == NULL) { + // msIO_setHeader("Content-Type","text/html"); + // msIO_sendHeaders(); + // msIO_printf("malloc() failed, Content-Length: %u unreasonably + // large?\n", (unsigned int)data_max ); + msSetError(MS_WEBERR, + "malloc() failed, Content-Length: %u unreasonably large?", + "readPostBody()", (unsigned int)data_max); + return MS_FAILURE; + } + + if ((int)msIO_fread(*data, 1, data_max, stdin) < (int)data_max) { + // msIO_setHeader("Content-Type","text/html"); + // msIO_sendHeaders(); + // msIO_printf("POST body is short\n"); + msSetError(MS_WEBERR, "POST body is short.", "readPostBody()"); + return MS_FAILURE; + } + + (*data)[data_max] = '\0'; + return MS_SUCCESS; + } + /* -------------------------------------------------------------------- */ + /* Otherwise read in chunks to the end. */ + /* -------------------------------------------------------------------- */ +#define DATA_ALLOC_SIZE 10000 + + data_max = DATA_ALLOC_SIZE; + data_len = 0; + *data = (char *)msSmallMalloc(data_max + 1); + (*data)[data_max] = '\0'; + + while ((chunk_size = msIO_fread(*data + data_len, 1, data_max - data_len, + stdin)) > 0) { + data_len += chunk_size; + + if (data_len == data_max) { + /* Realloc buffer, making sure we check for possible size_t overflow */ + if (data_max > SIZE_MAX - (DATA_ALLOC_SIZE + 1)) { + // msIO_setHeader("Content-Type","text/html"); + // msIO_sendHeaders(); + // msIO_printf("Possible size_t overflow, cannot reallocate input + // buffer, POST body too large?\n" ); + msSetError(MS_WEBERR, + "Possible size_t overflow, cannot reallocate input buffer, " + "POST body too large?", + "readPostBody()"); + return MS_FAILURE; + } + + data_max = data_max + DATA_ALLOC_SIZE; + *data = (char *)msSmallRealloc(*data, data_max + 1); + } + } + + (*data)[data_len] = '\0'; + return MS_SUCCESS; +} + +static char *msGetEnv(const char *name, void *thread_context) { + (void)thread_context; + return getenv(name); +} + +int loadParams(cgiRequestObj *request, + char *(*getenv2)(const char *, void *thread_context), + char *raw_post_data, ms_uint32 raw_post_data_length, + void *thread_context) { + int m = 0; + char *s, *queryString = NULL, *httpCookie = NULL; + int debuglevel; + int maxParams = MS_DEFAULT_CGI_PARAMS; + + if (getenv2 == NULL) + getenv2 = &msGetEnv; + + if (getenv2("REQUEST_METHOD", thread_context) == NULL) { + msIO_printf("This script can only be used to decode form results and \n"); + msIO_printf("should be initiated as a CGI process via a httpd server.\n"); + msIO_printf("For other options please try using the --help switch.\n"); + return -1; + } + + debuglevel = (int)msGetGlobalDebugLevel(); + + if (strcmp(getenv2("REQUEST_METHOD", thread_context), "POST") == 0 && + CPLGetConfigOption("MS_NO_POST", NULL) == + NULL) { /* we've got a post from a form */ + char *post_data; + int data_len; + request->type = MS_POST_REQUEST; + + if (request->contenttype == NULL) { + s = getenv2("CONTENT_TYPE", thread_context); + if (s != NULL) { + request->contenttype = msStrdup(s); + } else { + /* we've to set default Content-Type which is + * application/octet-stream according to + * W3 RFC 2626 section 7.2.1 */ + request->contenttype = msStrdup("application/octet-stream"); + } + } + + if (raw_post_data) { + post_data = msStrdup(raw_post_data); + data_len = raw_post_data_length; + } else { + if (MS_SUCCESS != readPostBody(request, &post_data)) + return -1; + data_len = strlen(post_data); + } + + /* if the content_type is application/x-www-form-urlencoded, + we have to parse it like the QUERY_STRING variable */ + if (strncmp(request->contenttype, "application/x-www-form-urlencoded", + strlen("application/x-www-form-urlencoded")) == 0) { + while (data_len > 0 && isspace(post_data[data_len - 1])) + post_data[--data_len] = '\0'; + + while (post_data[0]) { + if (m >= maxParams) { + maxParams *= 2; + request->ParamNames = (char **)msSmallRealloc( + request->ParamNames, sizeof(char *) * maxParams); + request->ParamValues = (char **)msSmallRealloc( + request->ParamValues, sizeof(char *) * maxParams); + } + request->ParamValues[m] = makeword(post_data, '&'); + plustospace(request->ParamValues[m]); + unescape_url(request->ParamValues[m]); + request->ParamNames[m] = makeword(request->ParamValues[m], '='); + m++; + } + free(post_data); + } else + request->postrequest = post_data; + + /* check the QUERY_STRING even in the post request since it can contain + information. Eg a wfs request with */ + s = getenv2("QUERY_STRING", thread_context); + if (s) { + if (debuglevel >= MS_DEBUGLEVEL_DEBUG) + msDebug("loadParams() QUERY_STRING: %s\n", s); + + queryString = msStrdup(s); + while (queryString[0] != '\0') { + if (m >= maxParams) { + maxParams *= 2; + request->ParamNames = (char **)msSmallRealloc( + request->ParamNames, sizeof(char *) * maxParams); + request->ParamValues = (char **)msSmallRealloc( + request->ParamValues, sizeof(char *) * maxParams); + } + request->ParamValues[m] = makeword(queryString, '&'); + plustospace(request->ParamValues[m]); + unescape_url(request->ParamValues[m]); + request->ParamNames[m] = makeword(request->ParamValues[m], '='); + m++; + } + } + } else { + if (strcmp(getenv2("REQUEST_METHOD", thread_context), "GET") == + 0) { /* we've got a get request */ + request->type = MS_GET_REQUEST; + + s = getenv2("QUERY_STRING", thread_context); + if (s == NULL) { + // msIO_setHeader("Content-Type","text/html"); + // msIO_sendHeaders(); + // msIO_printf("No query information to decode. QUERY_STRING not + // set.\n"); + msSetError(MS_WEBERR, + "No query information to decode. QUERY_STRING not set.", + "loadParams()"); + return -1; + } + + if (debuglevel >= MS_DEBUGLEVEL_DEBUG) + msDebug("loadParams() QUERY_STRING: %s\n", s); + + if (strlen(s) == 0) { + // msIO_setHeader("Content-Type","text/html"); + // msIO_sendHeaders(); + // msIO_printf("No query information to decode. QUERY_STRING is set, but + // empty.\n"); + msSetError( + MS_WEBERR, + "No query information to decode. QUERY_STRING is set, but empty.", + "loadParams()"); + return -1; + } + + /* don't modify the string returned by getenv2 */ + queryString = msStrdup(s); + while (queryString[0] != '\0') { + if (m >= maxParams) { + maxParams *= 2; + request->ParamNames = (char **)msSmallRealloc( + request->ParamNames, sizeof(char *) * maxParams); + request->ParamValues = (char **)msSmallRealloc( + request->ParamValues, sizeof(char *) * maxParams); + } + request->ParamValues[m] = makeword(queryString, '&'); + plustospace(request->ParamValues[m]); + unescape_url(request->ParamValues[m]); + request->ParamNames[m] = makeword(request->ParamValues[m], '='); + m++; + } + } else { + // msIO_setHeader("Content-Type","text/html"); + // msIO_sendHeaders(); + // msIO_printf("This script should be referenced with a METHOD of GET or + // METHOD of POST.\n"); + msSetError(MS_WEBERR, + "This script should be referenced with a METHOD of GET or " + "METHOD of POST.", + "loadParams()"); + return -1; + } + } + + /* check for any available cookies */ + s = getenv2("HTTP_COOKIE", thread_context); + if (s != NULL) { + httpCookie = msStrdup(s); + request->httpcookiedata = msStrdup(s); + while (httpCookie[0] != '\0') { + if (m >= maxParams) { + maxParams *= 2; + request->ParamNames = (char **)msSmallRealloc( + request->ParamNames, sizeof(char *) * maxParams); + request->ParamValues = (char **)msSmallRealloc( + request->ParamValues, sizeof(char *) * maxParams); + } + request->ParamValues[m] = makeword(httpCookie, ';'); + plustospace(request->ParamValues[m]); + unescape_url(request->ParamValues[m]); + request->ParamNames[m] = makeword_skip(request->ParamValues[m], '=', ' '); + m++; + } + } + + if (queryString) + free(queryString); + if (httpCookie) + free(httpCookie); + + return (m); +} + +void getword(char *word, char *line, char stop) { + int x = 0, y; + + for (x = 0; ((line[x]) && (line[x] != stop)); x++) + word[x] = line[x]; + + word[x] = '\0'; + if (line[x]) + ++x; + y = 0; + + while ((line[y++] = line[x++])) + ; +} + +char *makeword_skip(char *line, char stop, char skip) { + int x = 0, y, offset = 0; + char *word = (char *)msSmallMalloc(sizeof(char) * (strlen(line) + 1)); + + for (x = 0; ((line[x]) && (line[x] == skip)); x++) + ; + offset = x; + + for (x = offset; ((line[x]) && (line[x] != stop)); x++) + word[x - offset] = line[x]; + + word[x - offset] = '\0'; + if (line[x]) + ++x; + y = 0; + + while ((line[y++] = line[x++])) + ; + return word; +} + +char *makeword(char *line, char stop) { + int x = 0, y; + char *word = (char *)msSmallMalloc(sizeof(char) * (strlen(line) + 1)); + + for (x = 0; ((line[x]) && (line[x] != stop)); x++) + word[x] = line[x]; + + word[x] = '\0'; + if (line[x]) + ++x; + y = 0; + + while ((line[y++] = line[x++])) + ; + return word; +} + +char *fmakeword(FILE *f, char stop, int *cl) { + int wsize; + char *word; + int ll; + + wsize = 102400; + ll = 0; + word = (char *)msSmallMalloc(sizeof(char) * (wsize + 1)); + + while (1) { + word[ll] = (char)fgetc(f); + if (ll == wsize) { + word[ll + 1] = '\0'; + wsize += 102400; + word = (char *)msSmallRealloc(word, sizeof(char) * (wsize + 1)); + } + --(*cl); + if ((word[ll] == stop) || (feof(f)) || (!(*cl))) { + if (word[ll] != stop) + ll++; + word[ll] = '\0'; + word = (char *)msSmallRealloc(word, ll + 1); + return word; + } + ++ll; + } +} + +static int hex_to_integer(char c) { + if (c >= '0' && c <= '9') + return c - '0'; + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + return -1; +} + +void unescape_url(char *url) { + register int x, y, hi, lo; + + for (x = 0, y = 0; url[y]; ++x, ++y) { + if (url[y] == '%') { + hi = hex_to_integer(url[y + 1]); + if (hi < 0) { + /* %-encoding is malformed, leave as-is */ + url[x] = '%'; + continue; + } + lo = hex_to_integer(url[y + 2]); + if (lo < 0) { + /* %-encoding is malformed, leave as-is */ + url[x] = '%'; + continue; + } + url[x] = (char)(hi * 16 + lo); + y += 2; + } else { + url[x] = url[y]; + } + } + url[x] = '\0'; +} + +void plustospace(char *str) { + register int x; + + for (x = 0; str[x]; x++) + if (str[x] == '+') + str[x] = ' '; +} + +int rind(char *s, char c) { + register int x; + for (x = strlen(s) - 1; x != -1; x--) + if (s[x] == c) + return x; + return -1; +} + +void send_fd(FILE *f, FILE *fd) { + int c; + + while (1) { + c = fgetc(f); + if (c == EOF) + return; + fputc((char)c, fd); + } +} + +int ind(char *s, char c) { + register int x; + + for (x = 0; s[x]; x++) + if (s[x] == c) + return x; + + return -1; +} + +/* +** patched version according to CERT advisory... +*/ +void escape_shell_cmd(char *cmd) { + register int x, y, l; + + l = strlen(cmd); + for (x = 0; cmd[x]; x++) { + if (ind("&;`'\"|*?~<>^()[]{}$\\\n", cmd[x]) != -1) { + for (y = l + 1; y > x; y--) + cmd[y] = cmd[y - 1]; + l++; /* length has been increased */ + cmd[x] = '\\'; + x++; /* skip the character */ + } + } +} + +/* +** Allocate a new request holder structure +*/ +cgiRequestObj *msAllocCgiObj() { + cgiRequestObj *request = (cgiRequestObj *)malloc(sizeof(cgiRequestObj)); + + if (!request) + return NULL; + + request->ParamNames = + (char **)msSmallMalloc(MS_DEFAULT_CGI_PARAMS * sizeof(char *)); + request->ParamValues = + (char **)msSmallMalloc(MS_DEFAULT_CGI_PARAMS * sizeof(char *)); + request->NumParams = 0; + request->type = MS_GET_REQUEST; + request->contenttype = NULL; + request->postrequest = NULL; + request->httpcookiedata = NULL; + + request->path_info = NULL; + request->api_path = NULL; + request->api_path_length = 0; + + return request; +} + +void msFreeCgiObj(cgiRequestObj *request) { + msFreeCharArray(request->ParamNames, request->NumParams); + msFreeCharArray(request->ParamValues, request->NumParams); + request->ParamNames = NULL; + request->ParamValues = NULL; + request->NumParams = 0; + request->type = -1; + msFree(request->contenttype); + msFree(request->postrequest); + msFree(request->httpcookiedata); + request->contenttype = NULL; + request->postrequest = NULL; + request->httpcookiedata = NULL; + + if (request->api_path) { + msFreeCharArray(request->api_path, request->api_path_length); + request->api_path = NULL; + request->api_path_length = 0; + } + + msFree(request); +} diff --git a/cgiutil.h b/src/cgiutil.h similarity index 76% rename from cgiutil.h rename to src/cgiutil.h index 264d13d70f..67922b9d15 100644 --- a/cgiutil.h +++ b/src/cgiutil.h @@ -5,7 +5,8 @@ * Purpose: cgiRequestObj and CGI parsing utility related declarations. * Author: Steve Lime and the MapServer team. * - * Notes: Portions derived from NCSA HTTPd Server's example CGI programs (util.c). + * Notes: Portions derived from NCSA HTTPd Server's example CGI programs + *(util.c). * ****************************************************************************** * Copyright (c) 1996-2005 Regents of the University of Minnesota. @@ -37,9 +38,9 @@ extern "C" { #endif #if defined(_WIN32) && !defined(__CYGWIN__) -# define MS_DLL_EXPORT __declspec(dllexport) +#define MS_DLL_EXPORT __declspec(dllexport) #else -#define MS_DLL_EXPORT +#define MS_DLL_EXPORT #endif /* @@ -47,9 +48,11 @@ extern "C" { */ #define MS_DEFAULT_CGI_PARAMS 100 -enum MS_REQUEST_TYPE {MS_GET_REQUEST, MS_POST_REQUEST}; +enum MS_REQUEST_TYPE { MS_GET_REQUEST, MS_POST_REQUEST }; -/* structure to hold request information */ +/** +Class for programming OWS services +*/ typedef struct { #ifndef SWIG char **ParamNames; @@ -59,31 +62,37 @@ typedef struct { #ifdef SWIG %immutable; #endif - int NumParams; + int NumParams; ///< The number of querystring parameters #ifdef SWIG %mutable; #endif - enum MS_REQUEST_TYPE type; - char *contenttype; - - char *postrequest; + enum MS_REQUEST_TYPE + type; ///< A :ref:`request type constant` + char *contenttype; ///< The content type of the request + char *postrequest; ///< Any POST data request + char *httpcookiedata; ///< Any cookie data associated with the request - char *httpcookiedata; +#ifndef SWIG + const char *path_info; + int api_path_length; + char **api_path; +#endif } cgiRequestObj; - /* ** Function prototypes */ #ifndef SWIG -MS_DLL_EXPORT int loadParams(cgiRequestObj *request, char* (*getenv2)(const char*, void* thread_context), - char *raw_post_data, ms_uint32 raw_post_data_length, void* thread_context); +MS_DLL_EXPORT int +loadParams(cgiRequestObj *request, + char *(*getenv2)(const char *, void *thread_context), + char *raw_post_data, ms_uint32 raw_post_data_length, + void *thread_context); MS_DLL_EXPORT void getword(char *, char *, char); MS_DLL_EXPORT char *makeword_skip(char *, char, char); MS_DLL_EXPORT char *makeword(char *, char); MS_DLL_EXPORT char *fmakeword(FILE *, char, int *); -MS_DLL_EXPORT char x2c(char *); MS_DLL_EXPORT void unescape_url(char *); MS_DLL_EXPORT void plustospace(char *); MS_DLL_EXPORT int rind(char *, char); diff --git a/src/check_md5sum.cmake b/src/check_md5sum.cmake new file mode 100644 index 0000000000..fdce6b6e98 --- /dev/null +++ b/src/check_md5sum.cmake @@ -0,0 +1,7 @@ +file(READ "${IN_FILE}" CONTENTS) + +string(MD5 MD5SUM "${CONTENTS}") + +if(NOT("${MD5SUM}" STREQUAL "${EXPECTED_MD5SUM}")) + message(FATAL_ERROR "File ${IN_FILE} has been modified. target ${TARGET} should be manually run. And ${FILENAME_CMAKE} should be updated with \"${MD5SUM}\"") +endif() diff --git a/src/classobject.c b/src/classobject.c new file mode 100644 index 0000000000..dc9619df0d --- /dev/null +++ b/src/classobject.c @@ -0,0 +1,197 @@ +/****************************************************************************** + * $Id$ + * + * Project: MapServer + * Purpose: Functions for operating on a classObj that don't belong in a + * more specific file such as mapfile.c. + * Adapted from mapobject.c. + * Author: Sean Gillies, sgillies@frii.com + * + ****************************************************************************** + * Copyright (c) 2004, Sean Gillies + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + ****************************************************************************/ + +#include "mapserver.h" + +/* +** Add a label to a classObj (order doesn't matter for labels like it does with +*styles) +*/ +int msAddLabelToClass(classObj *class, labelObj *label) { + if (!label) { + msSetError(MS_CHILDERR, "Can't add a NULL label.", "msAddLabelToClass()"); + return MS_FAILURE; + } + if (msGrowClassLabels(class) == NULL) + return MS_FAILURE; + + /* msGrowClassLabels will alloc the label, free it in this case */ + free(class->labels[class->numlabels]); + class->labels[class->numlabels] = label; + MS_REFCNT_INCR(label); + class->numlabels++; + return MS_SUCCESS; +} + +/* +** Remove a label from a classObj. +*/ +labelObj *msRemoveLabelFromClass(classObj *class, int nLabelIndex) { + int i; + labelObj *label; + + if (nLabelIndex < 0 || nLabelIndex >= class->numlabels) { + msSetError(MS_CHILDERR, "Cannot remove label, invalid index %d", + "msRemoveLabelFromClass()", nLabelIndex); + return NULL; + } else { + label = class->labels[nLabelIndex]; + for (i = nLabelIndex; i < class->numlabels - 1; i++) { + class->labels[i] = class->labels[i + 1]; + } + class->labels[class->numlabels - 1] = NULL; + class->numlabels--; + MS_REFCNT_DECR(label); + return label; + } +} + +/** + * Move the style up inside the array of styles. + */ +int msMoveStyleUp(classObj *class, int nStyleIndex) { + styleObj *psTmpStyle = NULL; + if (class && nStyleIndex < class->numstyles && nStyleIndex > 0) { + psTmpStyle = (styleObj *)malloc(sizeof(styleObj)); + initStyle(psTmpStyle); + + msCopyStyle(psTmpStyle, class->styles[nStyleIndex]); + + msCopyStyle(class->styles[nStyleIndex], class->styles[nStyleIndex - 1]); + + msCopyStyle(class->styles[nStyleIndex - 1], psTmpStyle); + + return (MS_SUCCESS); + } + msSetError(MS_CHILDERR, "Invalid index: %d", "msMoveStyleUp()", nStyleIndex); + return (MS_FAILURE); +} + +/** + * Move the style down inside the array of styles. + */ +int msMoveStyleDown(classObj *class, int nStyleIndex) { + styleObj *psTmpStyle = NULL; + + if (class && nStyleIndex < class->numstyles - 1 && nStyleIndex >= 0) { + psTmpStyle = (styleObj *)malloc(sizeof(styleObj)); + initStyle(psTmpStyle); + + msCopyStyle(psTmpStyle, class->styles[nStyleIndex]); + + msCopyStyle(class->styles[nStyleIndex], class->styles[nStyleIndex + 1]); + + msCopyStyle(class->styles[nStyleIndex + 1], psTmpStyle); + + return (MS_SUCCESS); + } + msSetError(MS_CHILDERR, "Invalid index: %d", "msMoveStyleDown()", + nStyleIndex); + return (MS_FAILURE); +} + +/* Moved here from mapscript.i + * + * Returns the index at which the style was inserted + * + */ +int msInsertStyle(classObj *class, styleObj *style, int nStyleIndex) { + int i; + + if (!style) { + msSetError(MS_CHILDERR, "Can't insert a NULL Style", "msInsertStyle()"); + return -1; + } + + /* Ensure there is room for a new style */ + if (msGrowClassStyles(class) == NULL) { + return -1; + } + /* Catch attempt to insert past end of styles array */ + else if (nStyleIndex >= class->numstyles) { + msSetError(MS_CHILDERR, "Cannot insert style beyond index %d", + "insertStyle()", class->numstyles - 1); + return -1; + } else if (nStyleIndex < 0) { /* Insert at the end by default */ + class->styles[class->numstyles] = style; + MS_REFCNT_INCR(style); + class->numstyles++; + return class->numstyles - 1; + } else { + /* Move styles existing at the specified nStyleIndex or greater */ + /* to a higher nStyleIndex */ + for (i = class->numstyles - 1; i >= nStyleIndex; i--) { + class->styles[i + 1] = class->styles[i]; + } + class->styles[nStyleIndex] = style; + MS_REFCNT_INCR(style); + class->numstyles++; + return nStyleIndex; + } +} + +styleObj *msRemoveStyle(classObj *class, int nStyleIndex) { + int i; + styleObj *style; + if (nStyleIndex < 0 || nStyleIndex >= class->numstyles) { + msSetError(MS_CHILDERR, "Cannot remove style, invalid nStyleIndex %d", + "removeStyle()", nStyleIndex); + return NULL; + } else { + style = class->styles[nStyleIndex]; + for (i = nStyleIndex; i < class->numstyles - 1; i++) { + class->styles[i] = class->styles[i + 1]; + } + class->styles[class->numstyles - 1] = NULL; + class->numstyles--; + MS_REFCNT_DECR(style); + return style; + } +} + +/** + * Delete the style identified by the index and shift + * styles that follows the deleted style. + */ +int msDeleteStyle(classObj *class, int nStyleIndex) { + if (class && nStyleIndex < class->numstyles && nStyleIndex >= 0) { + if (freeStyle(class->styles[nStyleIndex]) == MS_SUCCESS) + msFree(class->styles[nStyleIndex]); + for (int i = nStyleIndex; i < class->numstyles - 1; i++) { + class->styles[i] = class->styles[i + 1]; + } + class->styles[class->numstyles - 1] = NULL; + class->numstyles--; + return (MS_SUCCESS); + } + msSetError(MS_CHILDERR, "Invalid index: %d", "msDeleteStyle()", nStyleIndex); + return (MS_FAILURE); +} diff --git a/src/cql2.cpp b/src/cql2.cpp new file mode 100644 index 0000000000..df5e01ae44 --- /dev/null +++ b/src/cql2.cpp @@ -0,0 +1,646 @@ +/****************************************************************************** + * + * Project: MapServer + * Purpose: CQL2 expression + * Author: Even Rouault + * + ****************************************************************************** + * Copyright (C) 2026 Even Rouault + * + * SPDX-License-Identifier: MIT + ****************************************************************************/ + +#include "cql2.h" + +#include +#include +#include +#include +#include + +#include "mapogcfilter.h" +#include "mapows.h" + +/************************************************************************/ +/* to_string() */ +/************************************************************************/ + +static std::string to_string(double x) { + char szBuf[32]; + snprintf(szBuf, sizeof(szBuf), "%.17g", x); + return szBuf; +} + +/************************************************************************/ +/* cql2_expr_node(cql2_op) */ +/************************************************************************/ + +cql2_expr_node::cql2_expr_node(cql2_op op) + : m_op(op), m_node_type(CQL2_NT_OPERATION) { + switch (op) { + case CQL2_OR: + case CQL2_AND: + case CQL2_NOT: + case CQL2_EQ: + case CQL2_IEQ: + case CQL2_NE: + case CQL2_INE: + case CQL2_GE: + case CQL2_LE: + case CQL2_LT: + case CQL2_GT: + case CQL2_IN: + case CQL2_LIKE: + case CQL2_ILIKE: + case CQL2_BETWEEN: + case CQL2_IS_NULL: + case CQL2_S_INTERSECTS: + case CQL2_S_EQUALS: + case CQL2_S_DISJOINT: + case CQL2_S_TOUCHES: + case CQL2_S_WITHIN: + case CQL2_S_OVERLAPS: + case CQL2_S_CROSSES: + case CQL2_S_CONTAINS: + m_field_type = CQL2_BOOLEAN; + break; + + case CQL2_ADD: + case CQL2_SUBTRACT: + case CQL2_MULTIPLY: + case CQL2_DIV: + case CQL2_MOD: + case CQL2_ARGUMENT_LIST: + case CQL2_CUSTOM_FUNC: + break; + + case CQL2_NONE: + assert(false); + break; + } +} + +/************************************************************************/ +/* ~cql2_expr_node() */ +/************************************************************************/ + +cql2_expr_node::~cql2_expr_node() = default; + +/************************************************************************/ +/* PushSubExpression() */ +/************************************************************************/ + +void cql2_expr_node::PushSubExpression(cql2_expr_node *child) { + m_depth = std::max(m_depth, 1 + child->m_depth); + m_apoChildren.push_back(std::unique_ptr(child)); +} + +/************************************************************************/ +/* ReverseSubExpressions() */ +/************************************************************************/ + +void cql2_expr_node::ReverseSubExpressions() { + for (size_t i = 0; i < m_apoChildren.size() / 2; i++) { + std::swap(m_apoChildren[i], m_apoChildren[m_apoChildren.size() - i - 1]); + } +} + +/************************************************************************/ +/* RebalanceAndOr() */ +/************************************************************************/ + +void cql2_expr_node::RebalanceAndOr() { + std::queue nodes; + nodes.push(this); + while (!nodes.empty()) { + cql2_expr_node *node = nodes.front(); + nodes.pop(); + if (node->m_node_type == CQL2_NT_OPERATION) { + const auto op = node->m_op; + if ((op == CQL2_OR || op == CQL2_AND) && node->m_apoChildren.size() > 2) { + std::vector> exprs; + for (auto &subexpr : node->m_apoChildren) { + subexpr->RebalanceAndOr(); + exprs.push_back(std::move(subexpr)); + } + node->m_apoChildren.clear(); + + while (exprs.size() > 2) { + std::vector> new_exprs; + for (size_t i = 0; i < exprs.size(); i++) { + if (i + 1 < exprs.size()) { + auto cur_expr = std::make_unique(op); + cur_expr->PushSubExpression(exprs[i].release()); + cur_expr->PushSubExpression(exprs[i + 1].release()); + i++; + new_exprs.push_back(std::move(cur_expr)); + } else { + new_exprs.push_back(std::move(exprs[i])); + } + } + exprs = std::move(new_exprs); + } + assert(exprs.size() == 2); + node->m_apoChildren = std::move(exprs); + } else { + for (auto &subexpr : node->m_apoChildren) { + nodes.push(subexpr.get()); + } + } + } + } +} + +/************************************************************************/ +/* cql2_create_and_or_or() */ +/************************************************************************/ + +cql2_expr_node *cql2_create_and_or_or(cql2_op op, + std::unique_ptr left, + std::unique_ptr right) { + auto poNode = std::make_unique(op); + poNode->m_field_type = CQL2_BOOLEAN; + + if (left->m_node_type == CQL2_NT_OPERATION && left->m_op == op) { + poNode->m_apoChildren = std::move(left->m_apoChildren); + + // Temporary non-binary formulation + if (right->m_node_type == CQL2_NT_OPERATION && right->m_op == op) { + poNode->m_apoChildren.insert( + poNode->m_apoChildren.end(), + std::make_move_iterator(right->m_apoChildren.begin()), + std::make_move_iterator(right->m_apoChildren.end())); + } else { + poNode->m_apoChildren.push_back(std::move(right)); + } + } else if (right->m_node_type == CQL2_NT_OPERATION && right->m_op == op) { + // Temporary non-binary formulation + poNode->m_apoChildren = std::move(right->m_apoChildren); + + poNode->m_apoChildren.push_back(std::move(left)); + } else { + poNode->m_apoChildren.push_back(std::move(left)); + poNode->m_apoChildren.push_back(std::move(right)); + } + + return poNode.release(); +} + +/************************************************************************/ +/* getItemAliasOrName() */ +/************************************************************************/ + +static const char *getItemAliasOrName(const layerObj *layer, const char *item) { + std::string key = std::string(item) + "_alias"; + if (const char *value = + msOWSLookupMetadata(&(layer->metadata), "OGA", key.c_str())) { + return value; + } + return item; +} + +/************************************************************************/ +/* ChangeBBOXToWKT() */ +/************************************************************************/ + +bool cql2_expr_node::ChangeBBOXToWKT(const layerObj *layer, + const std::string &filterCrs, + bool axisInverted) { + if (m_node_type == CQL2_NT_OPERATION && m_op == CQL2_CUSTOM_FUNC && + EQUAL(m_osVal.c_str(), "BBOX") && m_apoChildren.size() == 4 && + m_apoChildren[0]->IsNumeric() && m_apoChildren[1]->IsNumeric() && + m_apoChildren[2]->IsNumeric() && m_apoChildren[3]->IsNumeric()) { + rectObj rect; + rect.minx = m_apoChildren[0]->AsDouble(); + rect.miny = m_apoChildren[1]->AsDouble(); + rect.maxx = m_apoChildren[2]->AsDouble(); + rect.maxy = m_apoChildren[3]->AsDouble(); + + if (axisInverted) { + std::swap(rect.minx, rect.miny); + std::swap(rect.maxx, rect.maxy); + } + + projectionObj shapeProj; + msInitProjection(&shapeProj); + msProjectionInheritContextFrom(&shapeProj, &(layer->projection)); + if (msLoadProjectionString(&shapeProj, filterCrs.c_str()) != 0) { + msFreeProjection(&shapeProj); + return false; + } + + int status = msProjectRect( + &shapeProj, const_cast(&(layer->projection)), &rect); + msFreeProjection(&shapeProj); + if (status != MS_SUCCESS) { + return false; + } + + const std::string minx = to_string(rect.minx); + const std::string miny = to_string(rect.miny); + const std::string maxx = to_string(rect.maxx); + const std::string maxy = to_string(rect.maxy); + + std::string s("POLYGON(("); + s += minx + " " + miny + ","; + s += minx + " " + maxy + ","; + s += maxx + " " + maxy + ","; + s += maxx + " " + miny + ","; + s += minx + " " + miny; + s += "))"; + + m_node_type = CQL2_NT_CONSTANT; + m_field_type = CQL2_WKT; + m_osVal = std::move(s); + m_apoChildren.clear(); + m_alreadyReprojected = true; + + return true; + + } else { + for (auto &child : m_apoChildren) { + if (!child->ChangeBBOXToWKT(layer, filterCrs, axisInverted)) { + return false; + } + } + } + return true; +} + +/************************************************************************/ +/* ToMapServerFilter() */ +/************************************************************************/ + +std::string cql2_expr_node::ToMapServerFilter( + const layerObj *layer, const std::vector &queryableItems, + const std::string &geometryName, const std::string &filterCrs, + bool axisInverted, std::string &errorMsg) const { + if (!errorMsg.empty()) + return std::string(); + + switch (m_node_type) { + case CQL2_NT_CONSTANT: { + switch (m_field_type) { + case CQL2_INTEGER: { + return std::to_string(m_nVal); + } + + case CQL2_DOUBLE: { + return to_string(m_dfVal); + } + + case CQL2_STRING: { + return std::string("'") + .append(msStdStringEscape(m_osVal.c_str())) + .append("'"); + } + + case CQL2_WKT: { + if (m_alreadyReprojected) + return m_osVal; + + shapeObj *shape = msShapeFromWKT(m_osVal.c_str()); + if (!shape) { + errorMsg = m_osVal; + errorMsg += " is invalid WKT"; + return std::string(); + } + + projectionObj shapeProj; + msInitProjection(&shapeProj); + msProjectionInheritContextFrom(&shapeProj, &(layer->projection)); + if (msLoadProjectionString(&shapeProj, filterCrs.c_str()) != 0) { + msFreeProjection(&shapeProj); + errorMsg = "Cannot process filter-crs"; + return std::string(); + } + + if (axisInverted) + msAxisSwapShape(shape); + + if (msProjectShape(&shapeProj, + const_cast(&(layer->projection)), + shape) != MS_SUCCESS) { + msFreeProjection(&shapeProj); + errorMsg = "Cannot reproject " + m_osVal; + return std::string(); + } + + msFreeProjection(&shapeProj); + char *wkt = msShapeToWKT(shape); + + msFreeShape(shape); + msFree(shape); + + if (!wkt) { + errorMsg = "Cannot export back to WKT"; + return std::string(); + } + std::string s(wkt); + msFree(wkt); + return s; + } + + case CQL2_BOOLEAN: { + return m_nVal ? "1" : "0"; + } + } + break; + } + + case CQL2_NT_COLUMN: { + if (std::find(queryableItems.begin(), queryableItems.end(), + m_osVal.c_str()) == queryableItems.end()) { + errorMsg = m_osVal; + errorMsg += " is not a queryable item"; + break; + } + + // Find actual item name from alias + const char *pszItem = nullptr; + for (int j = 0; j < layer->numitems; ++j) { + if (m_osVal == getItemAliasOrName(layer, layer->items[j])) { + pszItem = layer->items[j]; + break; + } + } + + const char *pszType = + msOWSLookupMetadata(&(layer->metadata), "OFG", + std::string(pszItem).append("_type").c_str()); + if (pszType && (EQUAL(pszType, "Integer") || EQUAL(pszType, "Long") || + EQUAL(pszType, "Real"))) + return std::string("[").append(msStdStringEscape(pszItem)).append("]"); + else if (pszType && (EQUAL(pszType, "Date") || EQUAL(pszType, "DateTime"))) + return std::string("`[").append(msStdStringEscape(pszItem)).append("]`"); + else + return std::string("\"[") + .append(msStdStringEscape(pszItem)) + .append("]\""); + } + + case CQL2_NT_OPERATION: { + const auto ReturnBinaryOp = [this, layer, axisInverted, &queryableItems, + &geometryName, &filterCrs, + &errorMsg](const char *pszOp) { + assert(m_apoChildren.size() == 2); + return std::string("(") + .append(m_apoChildren[0]->ToMapServerFilter(layer, queryableItems, + geometryName, filterCrs, + axisInverted, errorMsg)) + .append(" ") + .append(pszOp) + .append(" ") + .append(m_apoChildren[1]->ToMapServerFilter(layer, queryableItems, + geometryName, filterCrs, + axisInverted, errorMsg)) + .append(")"); + }; + + switch (m_op) { + case CQL2_OR: + return ReturnBinaryOp("OR"); + + case CQL2_AND: + return ReturnBinaryOp("AND"); + + case CQL2_NOT: { + assert(m_apoChildren.size() == 1); + return std::string("(NOT ") + .append(m_apoChildren[0]->ToMapServerFilter(layer, queryableItems, + geometryName, filterCrs, + axisInverted, errorMsg)) + .append(")"); + } + + case CQL2_EQ: + return ReturnBinaryOp("="); + + case CQL2_NE: + return ReturnBinaryOp("!="); + + case CQL2_GE: + return ReturnBinaryOp(">="); + + case CQL2_LE: + return ReturnBinaryOp("<="); + + case CQL2_LT: + return ReturnBinaryOp("<"); + + case CQL2_GT: + return ReturnBinaryOp(">"); + + case CQL2_IN: { + assert(m_apoChildren.size() >= 2); + std::string s = "(("; + for (size_t i = 1; i < m_apoChildren.size(); ++i) { + if (i > 1) + s.append(") OR ("); + s.append(m_apoChildren[0]->ToMapServerFilter(layer, queryableItems, + geometryName, filterCrs, + axisInverted, errorMsg)) + .append(" ") + .append("=") + .append(" ") + .append(m_apoChildren[i]->ToMapServerFilter( + layer, queryableItems, geometryName, filterCrs, axisInverted, + errorMsg)); + } + s += "))"; + return s; + } + + case CQL2_LIKE: + case CQL2_ILIKE: { + assert(m_apoChildren.size() == 2); + FEPropertyIsLike propIsLike; + propIsLike.pszWildCard = const_cast("%"); + propIsLike.pszSingleChar = const_cast("_"); + propIsLike.pszEscapeChar = const_cast("\\"); + propIsLike.bCaseInsensitive = 0; + return std::string("(") + .append(m_apoChildren[0]->ToMapServerFilter(layer, queryableItems, + geometryName, filterCrs, + axisInverted, errorMsg)) + .append(" ") + .append(m_op == CQL2_LIKE ? "~" : "~*") + .append(" \"") + .append(msGetLikePatternAsRegex(&propIsLike, + m_apoChildren[1]->m_osVal.c_str())) + .append("\")"); + } + + case CQL2_IEQ: + case CQL2_INE: { + assert(m_apoChildren.size() == 2); + FEPropertyIsLike propIsLike; + propIsLike.pszWildCard = const_cast(""); + propIsLike.pszSingleChar = const_cast(""); + propIsLike.pszEscapeChar = const_cast("\\"); + propIsLike.bCaseInsensitive = 0; + std::string s; + if (m_op == CQL2_INE) + s = "( NOT"; + s.append("(") + .append(m_apoChildren[0]->ToMapServerFilter(layer, queryableItems, + geometryName, filterCrs, + axisInverted, errorMsg)) + .append(" ~* \"") + .append(msGetLikePatternAsRegex(&propIsLike, + m_apoChildren[1]->m_osVal.c_str())) + .append("\")"); + if (m_op == CQL2_INE) + s.append(")"); + return s; + } + + case CQL2_BETWEEN: { + assert(m_apoChildren.size() == 3); + return std::string("((") + .append(m_apoChildren[0]->ToMapServerFilter(layer, queryableItems, + geometryName, filterCrs, + axisInverted, errorMsg)) + .append(" ") + .append(">=") + .append(" ") + .append(m_apoChildren[1]->ToMapServerFilter(layer, queryableItems, + geometryName, filterCrs, + axisInverted, errorMsg)) + .append(") AND (") + .append(m_apoChildren[0]->ToMapServerFilter(layer, queryableItems, + geometryName, filterCrs, + axisInverted, errorMsg)) + .append(" ") + .append("<=") + .append(" ") + .append(m_apoChildren[2]->ToMapServerFilter(layer, queryableItems, + geometryName, filterCrs, + axisInverted, errorMsg)) + .append("))"); + } + + case CQL2_IS_NULL: { + errorMsg = "IS NULL not supported by MapServer"; + break; + } + + case CQL2_S_INTERSECTS: + case CQL2_S_EQUALS: + case CQL2_S_DISJOINT: + case CQL2_S_TOUCHES: + case CQL2_S_WITHIN: + case CQL2_S_OVERLAPS: + case CQL2_S_CROSSES: + case CQL2_S_CONTAINS: { + const char *pszFunc = ""; + switch (m_op) { + case CQL2_S_INTERSECTS: + pszFunc = "intersects"; + break; + case CQL2_S_EQUALS: + pszFunc = "equals"; + break; + case CQL2_S_DISJOINT: + pszFunc = "disjoint"; + break; + case CQL2_S_TOUCHES: + pszFunc = "touches"; + break; + case CQL2_S_WITHIN: + pszFunc = "within"; + break; + case CQL2_S_OVERLAPS: + pszFunc = "overlaps"; + break; + case CQL2_S_CROSSES: + pszFunc = "crosses"; + break; + case CQL2_S_CONTAINS: + pszFunc = "contains"; + break; + default: + assert(false); + break; + } + + assert(m_apoChildren.size() == 2); + if (m_apoChildren[0]->m_node_type != CQL2_NT_COLUMN || + m_apoChildren[0]->m_osVal != geometryName) { + errorMsg = "First parameter of s_"; + errorMsg += pszFunc; + errorMsg += "() must be the geometry " + "column name '" + + geometryName + "'"; + return std::string(); + } + + if (!m_apoChildren[1]->ChangeBBOXToWKT(layer, filterCrs, axisInverted)) { + errorMsg = "Error while reprojecting BBOX"; + return std::string(); + } + + if (m_apoChildren[1]->m_field_type != CQL2_WKT) { + errorMsg = "Second parameter of s_"; + errorMsg += pszFunc; + errorMsg += "() must be " + "BBOX(minx,miny,maxx,maxy) or a WKT literal'"; + return std::string(); + } + + std::string s("("); + s += pszFunc; + s += "([shape],fromText('"; + s += m_apoChildren[1]->ToMapServerFilter(layer, queryableItems, + geometryName, filterCrs, + axisInverted, errorMsg); + s += "'))=true)"; + return s; + } + + case CQL2_CUSTOM_FUNC: { + if (m_osVal == "TIMESTAMP" || m_osVal == "DATE") { + if (m_apoChildren.size() == 1 && + m_apoChildren[0]->m_field_type == CQL2_STRING) { + const std::string &val = m_apoChildren[0]->m_osVal; + // Reject anything that isn't a valid RFC 3339 timestamp/date + if (val.find_first_of("`'\"\\") != std::string::npos) { + errorMsg = "Invalid characters in " + m_osVal + "() argument"; + break; + } + return std::string("`").append(val).append("`"); + } else { + errorMsg = "Unhandled syntax for function "; + errorMsg += m_osVal; + } + } else { + errorMsg = "Unhandled function "; + errorMsg += m_osVal; + } + break; + } + + case CQL2_ADD: + return ReturnBinaryOp("+"); + + case CQL2_SUBTRACT: + return ReturnBinaryOp("-"); + + case CQL2_MULTIPLY: + return ReturnBinaryOp("*"); + + case CQL2_DIV: + return ReturnBinaryOp("/"); + + case CQL2_MOD: + return ReturnBinaryOp("%"); + + case CQL2_NONE: + case CQL2_ARGUMENT_LIST: + assert(false); + break; + } + } + } + return std::string(); +} diff --git a/src/cql2.h b/src/cql2.h new file mode 100644 index 0000000000..0bfe3f1f8f --- /dev/null +++ b/src/cql2.h @@ -0,0 +1,127 @@ +/****************************************************************************** + * + * Project: MapServer + * Purpose: CQL2 expression + * Author: Even Rouault + * + ****************************************************************************** + * Copyright (C) 2026 Even Rouault + * + * SPDX-License-Identifier: MIT + ****************************************************************************/ + +#ifndef CQL2_H_INCLUDED +#define CQL2_H_INCLUDED + +#include +#include +#include + +#include "mapserver.h" + +typedef enum { + CQL2_NONE, + + /* temporary value only set during parsing and replaced by something else + * at the end */ + CQL2_ARGUMENT_LIST, + CQL2_CUSTOM_FUNC, + + CQL2_OR, + CQL2_AND, + + CQL2_NOT, + + CQL2_EQ, + CQL2_IEQ, + CQL2_NE, + CQL2_INE, + CQL2_GE, + CQL2_LE, + CQL2_LT, + CQL2_GT, + + CQL2_IS_NULL, + + CQL2_IN, + CQL2_LIKE, + CQL2_ILIKE, + CQL2_BETWEEN, + + CQL2_S_INTERSECTS, + CQL2_S_EQUALS, + CQL2_S_DISJOINT, + CQL2_S_TOUCHES, + CQL2_S_WITHIN, + CQL2_S_OVERLAPS, + CQL2_S_CROSSES, + CQL2_S_CONTAINS, + + CQL2_ADD, + CQL2_SUBTRACT, + CQL2_MULTIPLY, + CQL2_DIV, + CQL2_MOD, + +} cql2_op; + +typedef enum { + CQL2_INTEGER, + CQL2_DOUBLE, + CQL2_STRING, + CQL2_WKT, + CQL2_BOOLEAN, +} cql2_field_type; + +typedef enum { + CQL2_NT_CONSTANT, + CQL2_NT_COLUMN, + CQL2_NT_OPERATION +} cql2_node_type; + +struct cql2_expr_node { + cql2_expr_node(cql2_op op); + cql2_expr_node(bool v) : m_field_type(CQL2_BOOLEAN), m_nVal(v) {} + cql2_expr_node(int v) : m_field_type(CQL2_INTEGER), m_nVal(v) {} + cql2_expr_node(double v) : m_field_type(CQL2_DOUBLE), m_dfVal(v) {} + cql2_expr_node(const std::string &v) + : m_field_type(CQL2_STRING), m_osVal(v) {} + cql2_expr_node(const char *v) : m_field_type(CQL2_STRING), m_osVal(v) {} + ~cql2_expr_node(); + + cql2_op m_op = CQL2_NONE; + cql2_node_type m_node_type = CQL2_NT_CONSTANT; + cql2_field_type m_field_type = CQL2_INTEGER; + + int m_nVal = 0; + double m_dfVal = 0; + std::string m_osVal{}; + std::vector> m_apoChildren{}; + int m_depth = 0; + bool m_alreadyReprojected = false; + + bool HasReachedMaxDepth() const { return m_depth > 32; } + bool IsNumeric() const { + return m_field_type == CQL2_INTEGER || m_field_type == CQL2_DOUBLE; + } + double AsDouble() const { + if (m_field_type == CQL2_INTEGER) + return m_nVal; + else if (m_field_type == CQL2_DOUBLE) + return m_dfVal; + else + return 0; + } + void PushSubExpression(cql2_expr_node *node); + void ReverseSubExpressions(); + void RebalanceAndOr(); + bool ChangeBBOXToWKT(const layerObj *layer, const std::string &filterCrs, + bool axisInverted); + std::string ToMapServerFilter(const layerObj *layer, + const std::vector &queryableItems, + const std::string &geometryName, + const std::string &filterCrs, bool axisInverted, + std::string &errorMsg) const; +}; + +#endif diff --git a/src/cql2json.cpp b/src/cql2json.cpp new file mode 100644 index 0000000000..25842f0b81 --- /dev/null +++ b/src/cql2json.cpp @@ -0,0 +1,305 @@ +/****************************************************************************** + * + * Project: MapServer + * Purpose: CQL2 JSON Parser + * Author: Even Rouault + * + ****************************************************************************** + * Copyright (C) 2026 Even Rouault + * + * SPDX-License-Identifier: MIT + ****************************************************************************/ + +#include "cql2json.h" + +#include "cpl_conv.h" +#include "ogr_api.h" + +#include "third-party/include_nlohmann_json.hpp" + +using json = nlohmann::json; + +static std::unique_ptr ParseOperator(const json &j, + std::string &errorMsg); + +/************************************************************************/ +/* sGeoJSONType() */ +/************************************************************************/ + +static bool isGeoJSONType(const std::string &s) { + return s == "Point" || s == "LineString" || s == "Polygon" || + s == "MultiPoint" || s == "MultiLineString" || s == "MultiPolygon" || + s == "GeometryCollection"; +} + +/************************************************************************/ +/* ParseObject() */ +/************************************************************************/ + +static std::unique_ptr ParseObject(const json &j, + std::string &errorMsg) { + if (j.is_object()) { + if (j.contains("op")) { + return ParseOperator(j, errorMsg); + } else if (j.contains("property")) { + const auto property = j["property"]; + if (!property.is_string()) { + errorMsg = "Value of 'property' is not a string"; + return nullptr; + } + auto expr = std::make_unique(property.get()); + expr->m_node_type = CQL2_NT_COLUMN; + return expr; + } else if (j.contains("type") && j["type"].is_string() && + isGeoJSONType(j["type"].get())) { + OGRGeometryH hGeom = OGR_G_CreateGeometryFromJson(j.dump().c_str()); + if (!hGeom) { + errorMsg = "Invalid GeoJSON geometry"; + return nullptr; + } + char *pszWkt = nullptr; + OGR_G_ExportToIsoWkt(hGeom, &pszWkt); + OGR_G_DestroyGeometry(hGeom); + if (!pszWkt) + return nullptr; + auto expr = std::make_unique(pszWkt); + CPLFree(pszWkt); + expr->m_field_type = CQL2_WKT; + return expr; + } else if (j.contains("bbox")) { + const auto bbox = j["bbox"]; + if (!bbox.is_array() || (bbox.size() != 4 && bbox.size() != 6) || + !bbox[0].is_number() || !bbox[1].is_number() || + !bbox[2].is_number() || !bbox[3].is_number() || + !(bbox.size() == 4 || + (bbox.size() == 6 && bbox[4].is_number() && bbox[5].is_number()))) { + errorMsg = "Value of bbox is not array of 4 or 6 numeric values"; + return nullptr; + } + auto expr = std::make_unique(CQL2_CUSTOM_FUNC); + expr->m_osVal = "BBOX"; + if (bbox.size() == 4) { + for (int i = 0; i < 4; ++i) { + expr->m_apoChildren.push_back( + std::make_unique(bbox[i].get())); + } + } else { + expr->m_apoChildren.push_back( + std::make_unique(bbox[0].get())); + expr->m_apoChildren.push_back( + std::make_unique(bbox[1].get())); + // skip minz + expr->m_apoChildren.push_back( + std::make_unique(bbox[3].get())); + expr->m_apoChildren.push_back( + std::make_unique(bbox[4].get())); + } + return expr; + } else if (j.contains("date")) { + const auto date = j["date"]; + if (!date.is_string()) { + errorMsg = "Value of 'date' is not a string"; + return nullptr; + } + auto expr = std::make_unique(CQL2_CUSTOM_FUNC); + expr->m_osVal = "DATE"; + expr->m_apoChildren.push_back( + std::make_unique(date.get())); + return expr; + } else if (j.contains("timestamp")) { + const auto timestamp = j["timestamp"]; + if (!timestamp.is_string()) { + errorMsg = "Value of 'timestamp' is not a string"; + return nullptr; + } + auto expr = std::make_unique(CQL2_CUSTOM_FUNC); + expr->m_osVal = "TIMESTAMP"; + expr->m_apoChildren.push_back( + std::make_unique(timestamp.get())); + return expr; + } else { + errorMsg = "Object has no 'op', 'property', 'type', 'bbox', 'date' or " + "'timestamp' member"; + } + } else if (j.is_string()) { + return std::make_unique(j.get()); + } else if (j.is_number_integer()) { + return std::make_unique(j.get()); + } else if (j.is_number()) { + return std::make_unique(j.get()); + } else if (j.is_boolean()) { + return std::make_unique(j.get()); + } else { + errorMsg = "Unexpected JSON type"; + } + return nullptr; +} + +/************************************************************************/ +/* ParseOperator() */ +/************************************************************************/ + +static std::unique_ptr ParseOperator(const json &j, + std::string &errorMsg) { + if (!j.is_object()) { + errorMsg = "Not a dictionnary"; + return nullptr; + } + + if (!j.contains("op")) { + errorMsg = "Missing \"op\" member"; + return nullptr; + } + const auto jOp = j["op"]; + if (!jOp.is_string()) { + errorMsg = "Value of \"op\" member is not a string"; + return nullptr; + } + const auto op = jOp.get(); + + if (!j.contains("args")) { + errorMsg = "Missing \"args\" member"; + return nullptr; + } + const auto jArgs = j["args"]; + if (!jArgs.is_array()) { + errorMsg = "Value of \"args\" member is not an array"; + return nullptr; + } + + if (op == "in") { + if (jArgs.size() != 2) { + errorMsg = "'" + op + "' operator expects 2 arguments"; + return nullptr; + } + auto firstArg = ParseObject(jArgs[0], errorMsg); + if (!firstArg) + return nullptr; + if (!jArgs[1].is_array()) { + errorMsg = "Second argument of 'in' operator must be an array"; + return nullptr; + } + auto expr = std::make_unique(CQL2_IN); + expr->m_apoChildren.push_back(std::move(firstArg)); + for (const auto &jArg : jArgs[1]) { + auto arg = ParseObject(jArg, errorMsg); + if (!arg) + return nullptr; + expr->m_apoChildren.push_back(std::move(arg)); + } + return expr; + } + + std::vector> args; + bool caseInsensitive = false; + for (const auto &jArgIn : jArgs) { + json jArg = jArgIn; + if (jArg.is_object() && jArg.contains("op") && jArg["op"].is_string() && + jArg["op"].get() == "casei" && jArg.contains("args") && + jArg["args"].is_array() && jArg["args"].size() == 1) { + jArg = jArg["args"][0]; + caseInsensitive = true; + } + auto arg = ParseObject(jArg, errorMsg); + if (!arg) + return nullptr; + args.push_back(std::move(arg)); + } + + static const struct { + const char *op_name; + cql2_op op; + } binaryOperators[] = { + {"and", CQL2_AND}, + {"or", CQL2_OR}, + + {"=", CQL2_EQ}, + {"<>", CQL2_NE}, + {"<", CQL2_LT}, + {">", CQL2_GT}, + {"<=", CQL2_LE}, + {">=", CQL2_GE}, + + {"+", CQL2_ADD}, + {"-", CQL2_SUBTRACT}, + {"*", CQL2_MULTIPLY}, + {"/", CQL2_DIV}, + {"div", CQL2_DIV}, + {"%", CQL2_MOD}, + + {"like", CQL2_LIKE}, + + {"s_intersects", CQL2_S_INTERSECTS}, + {"s_equals", CQL2_S_EQUALS}, + {"s_disjoint", CQL2_S_DISJOINT}, + {"s_touches", CQL2_S_TOUCHES}, + {"s_within", CQL2_S_WITHIN}, + {"s_overlaps", CQL2_S_OVERLAPS}, + {"s_crosses", CQL2_S_CROSSES}, + {"s_contains", CQL2_S_CONTAINS}, + }; + + for (const auto &opIter : binaryOperators) { + if (op == opIter.op_name) { + if (args.size() != 2) { + errorMsg = "'" + op + "' operator expects 2 arguments"; + return nullptr; + } + auto cql2Op = opIter.op; + if (caseInsensitive) { + if (cql2Op == CQL2_EQ) { + cql2Op = CQL2_IEQ; + } else if (cql2Op == CQL2_NE) { + cql2Op = CQL2_INE; + } else if (cql2Op == CQL2_LIKE) { + cql2Op = CQL2_ILIKE; + } else { + errorMsg = "casei is only supported for '=', '<>' and 'like'"; + return nullptr; + } + } + auto expr = std::make_unique(cql2Op); + expr->m_apoChildren = std::move(args); + return expr; + } + } + + if (op == "not") { + if (args.size() != 1) { + errorMsg = "'" + op + "' operator expects one argument"; + return nullptr; + } + auto expr = std::make_unique(CQL2_NOT); + expr->m_apoChildren = std::move(args); + return expr; + } + + if (op == "between") { + if (args.size() != 3) { + errorMsg = "'" + op + "' operator expects 3 arguments"; + return nullptr; + } + auto expr = std::make_unique(CQL2_BETWEEN); + expr->m_apoChildren = std::move(args); + return expr; + } + + errorMsg = "Unhandled operator: "; + errorMsg += op; + return nullptr; +} + +/************************************************************************/ +/* CQL2JSONParse() */ +/************************************************************************/ + +std::unique_ptr CQL2JSONParse(const char *pszInput, + std::string &errorMsg) { + try { + return ParseOperator(json::parse(pszInput), errorMsg); + } catch (const std::exception &e) { + errorMsg = "Exception while parsing CQL2 JSON: "; + errorMsg += e.what(); + } + return nullptr; +} diff --git a/src/cql2json.h b/src/cql2json.h new file mode 100644 index 0000000000..83f6004c5e --- /dev/null +++ b/src/cql2json.h @@ -0,0 +1,21 @@ +/****************************************************************************** + * + * Project: MapServer + * Purpose: CQL2 JSON Parser + * Author: Even Rouault + * + ****************************************************************************** + * Copyright (C) 2026 Even Rouault + * + * SPDX-License-Identifier: MIT + ****************************************************************************/ + +#ifndef CQL2JSON_H_INCLUDED +#define CQL2JSON_H_INCLUDED + +#include "cql2.h" + +std::unique_ptr CQL2JSONParse(const char *pszInput, + std::string &osError); + +#endif diff --git a/src/cql2text.cpp b/src/cql2text.cpp new file mode 100644 index 0000000000..f4accef590 --- /dev/null +++ b/src/cql2text.cpp @@ -0,0 +1,289 @@ +/****************************************************************************** + * + * Project: MapServer + * Purpose: CQL2 Text Parser + * Author: Even Rouault + * + ****************************************************************************** + * Copyright (C) 2026 Even Rouault + * + * SPDX-License-Identifier: MIT + ****************************************************************************/ + +#include "cql2text.h" +#include "cql2textparser.hpp" +#include "mapserver.h" + +#include +#include +#include +#include + +/************************************************************************/ +/* CQL2TextParse() */ +/************************************************************************/ + +std::unique_ptr CQL2TextParse(const char *pszInput, + std::string &osError) { + cql2text_parse_context context; + + context.pszInput = pszInput; + context.pszNext = pszInput; + context.pszLastValid = pszInput; + context.nStartToken = CQL2_TOK_VALUE_START; + + if (cql2textparse(&context) == 0) { + context.poRoot->RebalanceAndOr(); + return std::unique_ptr(context.poRoot); + } else { + delete context.poRoot; + osError = std::move(context.osError); + return nullptr; + } +} + +/************************************************************************/ +/* cql2texterror() */ +/************************************************************************/ + +void cql2texterror(cql2text_parse_context *context, const char *msg) { + std::string osMsg("CQL2Text Expression Parsing Error: "); + osMsg += msg; + osMsg += ". Occurred around :\n"; + + int n = static_cast(context->pszLastValid - context->pszInput); + + for (int i = std::max(0, n - 40); i < n + 40 && context->pszInput[i] != '\0'; + i++) + osMsg += context->pszInput[i]; + osMsg += "\n"; + for (int i = 0; i < std::min(n, 40); i++) + osMsg += " "; + osMsg += "^"; + + context->osError = std::move(osMsg); +} + +/************************************************************************/ +/* swqlex() */ +/* */ +/* Read back a token from the input. */ +/************************************************************************/ + +int cql2textlex(cql2_expr_node **ppNode, cql2text_parse_context *context) { + const char *pszInput = context->pszNext; + + *ppNode = nullptr; + + /* -------------------------------------------------------------------- */ + /* Do we have a start symbol to return? */ + /* -------------------------------------------------------------------- */ + if (context->nStartToken != 0) { + int nRet = context->nStartToken; + context->nStartToken = 0; + return nRet; + } + + /* -------------------------------------------------------------------- */ + /* Skip white space. */ + /* -------------------------------------------------------------------- */ + while (*pszInput == ' ' || *pszInput == '\t' || *pszInput == 10 || + *pszInput == 13) + pszInput++; + + context->pszLastValid = pszInput; + + if (*pszInput == '\0') { + context->pszNext = pszInput; + return EOF; + } + + /* -------------------------------------------------------------------- */ + /* Handle string constants. */ + /* -------------------------------------------------------------------- */ + if (*pszInput == '"' || *pszInput == '\'') { + char chQuote = *pszInput; + bool bFoundEndQuote = false; + + int nRet = *pszInput == '"' ? CQL2_TOK_IDENTIFIER : CQL2_TOK_STRING; + + pszInput++; + + std::string token; + + while (*pszInput != '\0') { + if (*pszInput == '\\' && pszInput[1] != 0) + pszInput++; + else if (*pszInput == '\'' && pszInput[1] == chQuote) + pszInput++; + else if (*pszInput == chQuote) { + pszInput++; + bFoundEndQuote = true; + break; + } + + token += *(pszInput++); + } + + if (!bFoundEndQuote) { + context->osError = "Did not find end-of-string character"; + return YYerror; + } + + *ppNode = new cql2_expr_node(token); + + context->pszNext = pszInput; + + return nRet; + } + + /* -------------------------------------------------------------------- */ + /* Handle numbers. */ + /* -------------------------------------------------------------------- */ + else if (*pszInput >= '0' && *pszInput <= '9') { + std::string osToken; + + osToken += *pszInput; + + // collect non-decimal part of number + const char *pszNext = pszInput + 1; + while (*pszNext >= '0' && *pszNext <= '9') + osToken += *(pszNext++); + + // collect decimal places. + if (*pszNext == '.') { + osToken += *(pszNext++); + while (*pszNext >= '0' && *pszNext <= '9') + osToken += *(pszNext++); + } + + // collect exponent + if (*pszNext == 'e' || *pszNext == 'E') { + osToken += *(pszNext++); + if (*pszNext == '-' || *pszNext == '+') + osToken += *(pszNext++); + while (*pszNext >= '0' && *pszNext <= '9') + osToken += *(pszNext++); + } + + context->pszNext = pszNext; + + if (strstr(osToken.c_str(), ".") || strstr(osToken.c_str(), "e") || + strstr(osToken.c_str(), "E")) { + *ppNode = new cql2_expr_node(atof(osToken.c_str())); + return CQL2_TOK_DOUBLE_NUMBER; + } else { + *ppNode = new cql2_expr_node(atoi(osToken.c_str())); + return CQL2_TOK_INTEGER_NUMBER; + } + } + + /* -------------------------------------------------------------------- */ + /* Handle alpha-numerics. */ + /* -------------------------------------------------------------------- */ + else if (isalnum(static_cast(*pszInput))) { + int nReturn = CQL2_TOK_IDENTIFIER; + std::string osToken; + const char *pszNext = pszInput + 1; + + osToken += *pszInput; + + // collect text characters + while (isalnum(static_cast(*pszNext)) || *pszNext == '_' || + static_cast(*pszNext) > 127) + osToken += *(pszNext++); + + context->pszNext = pszNext; + + if (osToken == "true") { + *ppNode = new cql2_expr_node(true); + nReturn = CQL2_TOK_BOOLEAN_LITERAL; + } else if (osToken == "false") { + *ppNode = new cql2_expr_node(false); + nReturn = CQL2_TOK_BOOLEAN_LITERAL; + } else if (EQUAL(osToken.c_str(), "OR")) + nReturn = CQL2_TOK_OR; + else if (EQUAL(osToken.c_str(), "AND")) + nReturn = CQL2_TOK_AND; + else if (EQUAL(osToken.c_str(), "NOT")) + nReturn = CQL2_TOK_NOT; + else if (EQUAL(osToken.c_str(), "LIKE")) + nReturn = CQL2_TOK_LIKE; + else if (EQUAL(osToken.c_str(), "IN")) + nReturn = CQL2_TOK_IN; + else if (EQUAL(osToken.c_str(), "BETWEEN")) + nReturn = CQL2_TOK_BETWEEN; + else if (EQUAL(osToken.c_str(), "IS")) + nReturn = CQL2_TOK_IS; + else if (EQUAL(osToken.c_str(), "NULL")) + nReturn = CQL2_TOK_NULL; + else if (EQUAL(osToken.c_str(), "CASEI")) + nReturn = CQL2_TOK_CASEI; + else if (EQUAL(osToken.c_str(), "DIV")) + nReturn = CQL2_TOK_DIV; + else if (EQUAL(osToken.c_str(), "S_INTERSECTS")) + nReturn = CQL2_TOK_S_INTERSECTS; + else if (EQUAL(osToken.c_str(), "S_EQUALS")) + nReturn = CQL2_TOK_S_EQUALS; + else if (EQUAL(osToken.c_str(), "S_DISJOINT")) + nReturn = CQL2_TOK_S_DISJOINT; + else if (EQUAL(osToken.c_str(), "S_TOUCHES")) + nReturn = CQL2_TOK_S_TOUCHES; + else if (EQUAL(osToken.c_str(), "S_WITHIN")) + nReturn = CQL2_TOK_S_WITHIN; + else if (EQUAL(osToken.c_str(), "S_OVERLAPS")) + nReturn = CQL2_TOK_S_OVERLAPS; + else if (EQUAL(osToken.c_str(), "S_CROSSES")) + nReturn = CQL2_TOK_S_CROSSES; + else if (EQUAL(osToken.c_str(), "S_CONTAINS")) + nReturn = CQL2_TOK_S_CONTAINS; + else if (EQUAL(osToken.c_str(), "POINT") || + EQUAL(osToken.c_str(), "LINESTRING") || + EQUAL(osToken.c_str(), "POLYGON") || + EQUAL(osToken.c_str(), "MULTIPOINT") || + EQUAL(osToken.c_str(), "MULTILINESTRING") || + EQUAL(osToken.c_str(), "MULTIPOLYGON") || + EQUAL(osToken.c_str(), "GEOMETRYCOLLECTION")) { + while (*pszNext == ' ') + ++pszNext; + if (*pszNext == '(') { + int nLevel = 0; + while (*pszNext) { + osToken += *pszNext; + if (*pszNext == '(') { + ++nLevel; + } else if (*pszNext == ')') { + --nLevel; + if (nLevel <= 0) + break; + } + ++pszNext; + } + if (nLevel != 0) { + context->osError = "Unbalanced or missing parenthesis in WKT"; + return YYerror; + } + context->pszNext = pszNext + 1; + *ppNode = new cql2_expr_node(osToken); + (*ppNode)->m_field_type = CQL2_WKT; + nReturn = CQL2_TOK_WKT; + } else { + *ppNode = new cql2_expr_node(osToken); + nReturn = CQL2_TOK_IDENTIFIER; + } + } else { + *ppNode = new cql2_expr_node(osToken); + nReturn = CQL2_TOK_IDENTIFIER; + } + + return nReturn; + } + + /* -------------------------------------------------------------------- */ + /* Handle special tokens. */ + /* -------------------------------------------------------------------- */ + else { + context->pszNext = pszInput + 1; + return *pszInput; + } +} diff --git a/src/cql2text.h b/src/cql2text.h new file mode 100644 index 0000000000..9f48975147 --- /dev/null +++ b/src/cql2text.h @@ -0,0 +1,42 @@ +/****************************************************************************** + * + * Project: MapServer + * Purpose: CQL2 Text Parser + * Author: Even Rouault + * + ****************************************************************************** + * Copyright (C) 2026 Even Rouault + * + * SPDX-License-Identifier: MIT + ****************************************************************************/ + +#ifndef CQL2TEXT_H_INCLUDED +#define CQL2TEXT_H_INCLUDED + +#include "cql2.h" + +#include +#include + +struct cql2text_parse_context { + int nStartToken = 0; + const char *pszInput = nullptr; + const char *pszNext = nullptr; + const char *pszLastValid = nullptr; + + cql2_expr_node *poRoot = nullptr; + std::string osError{}; +}; + +std::unique_ptr CQL2TextParse(const char *pszInput, + std::string &osError); + +int cql2textparse(cql2text_parse_context *context); +int cql2textlex(cql2_expr_node **ppNode, cql2text_parse_context *context); +void cql2texterror(cql2text_parse_context *context, const char *msg); + +cql2_expr_node *cql2_create_and_or_or(cql2_op op, + std::unique_ptr left, + std::unique_ptr right); + +#endif diff --git a/src/cql2textparser.cpp b/src/cql2textparser.cpp new file mode 100644 index 0000000000..81b9645acc --- /dev/null +++ b/src/cql2textparser.cpp @@ -0,0 +1,2461 @@ +/* A Bison parser, made by GNU Bison 3.8.2. */ + +/* Bison implementation for Yacc-like parsers in C + + Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 Free Software Foundation, + Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* C LALR(1) parser skeleton written by Richard Stallman, by + simplifying the original so-called "semantic" parser. */ + +/* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual, + especially those whose name start with YY_ or yy_. They are + private implementation details that can be changed or removed. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output, and Bison version. */ +#define YYBISON 30802 + +/* Bison version string. */ +#define YYBISON_VERSION "3.8.2" + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 1 + +/* Push parsers. */ +#define YYPUSH 0 + +/* Pull parsers. */ +#define YYPULL 1 + + +/* Substitute the variable and function names. */ +#define yyparse cql2textparse +#define yylex cql2textlex +#define yyerror cql2texterror +#define yydebug cql2textdebug +#define yynerrs cql2textnerrs + +/* First part of user prologue. */ + +/****************************************************************************** + * + * Project: MapServer + * Purpose: CQL2 text expression parser grammar. + * Requires Bison 3.0.0 or newer to process. Use "cql2textparser" target. + * Author: Even Rouault + * + ****************************************************************************** + * Copyright (C) 2026 Even Rouault + * + * SPDX-License-Identifier: MIT + ****************************************************************************/ + +// Inspired from GDAL SQL parser: https://github.com/OSGeo/gdal/blob/master/ogr/swq_parser.y + +#include "cql2text.h" + +#define YYSTYPE cql2_expr_node * + +/* Defining YYSTYPE_IS_TRIVIAL is needed because the parser is generated as a C++ file. */ +/* See http://www.gnu.org/s/bison/manual/html_node/Memory-Management.html that suggests */ +/* increase YYINITDEPTH instead, but this will consume memory. */ +/* Setting YYSTYPE_IS_TRIVIAL overcomes this limitation, but might be fragile because */ +/* it appears to be a non documented feature of Bison */ +#define YYSTYPE_IS_TRIVIAL 1 + + +# ifndef YY_CAST +# ifdef __cplusplus +# define YY_CAST(Type, Val) static_cast (Val) +# define YY_REINTERPRET_CAST(Type, Val) reinterpret_cast (Val) +# else +# define YY_CAST(Type, Val) ((Type) (Val)) +# define YY_REINTERPRET_CAST(Type, Val) ((Type) (Val)) +# endif +# endif +# ifndef YY_NULLPTR +# if defined __cplusplus +# if 201103L <= __cplusplus +# define YY_NULLPTR nullptr +# else +# define YY_NULLPTR 0 +# endif +# else +# define YY_NULLPTR ((void*)0) +# endif +# endif + +#include "cql2textparser.hpp" +/* Symbol kind. */ +enum yysymbol_kind_t +{ + YYSYMBOL_YYEMPTY = -2, + YYSYMBOL_YYEOF = 0, /* "end of string" */ + YYSYMBOL_YYerror = 1, /* error */ + YYSYMBOL_YYUNDEF = 2, /* "invalid token" */ + YYSYMBOL_CQL2_TOK_VALUE_START = 3, /* CQL2_TOK_VALUE_START */ + YYSYMBOL_CQL2_TOK_INTEGER_NUMBER = 4, /* "integer number" */ + YYSYMBOL_CQL2_TOK_DOUBLE_NUMBER = 5, /* "floating point number" */ + YYSYMBOL_CQL2_TOK_STRING = 6, /* "string" */ + YYSYMBOL_CQL2_TOK_IDENTIFIER = 7, /* "identifier" */ + YYSYMBOL_CQL2_TOK_WKT = 8, /* "wkt geometry" */ + YYSYMBOL_CQL2_TOK_NOT = 9, /* "NOT" */ + YYSYMBOL_CQL2_TOK_OR = 10, /* "OR" */ + YYSYMBOL_CQL2_TOK_AND = 11, /* "AND" */ + YYSYMBOL_CQL2_TOK_DIV = 12, /* "DIV" */ + YYSYMBOL_CQL2_TOK_IS = 13, /* "IS" */ + YYSYMBOL_CQL2_TOK_NULL = 14, /* "NULL" */ + YYSYMBOL_CQL2_TOK_BOOLEAN_LITERAL = 15, /* "true/false" */ + YYSYMBOL_CQL2_TOK_CASEI = 16, /* "CASEI" */ + YYSYMBOL_CQL2_TOK_S_INTERSECTS = 17, /* "S_INTERSECTS" */ + YYSYMBOL_CQL2_TOK_S_EQUALS = 18, /* "S_EQUALS" */ + YYSYMBOL_CQL2_TOK_S_DISJOINT = 19, /* "S_DISJOINT" */ + YYSYMBOL_CQL2_TOK_S_TOUCHES = 20, /* "S_TOUCHES" */ + YYSYMBOL_CQL2_TOK_S_WITHIN = 21, /* "S_WITHIN" */ + YYSYMBOL_CQL2_TOK_S_OVERLAPS = 22, /* "S_OVERLAPS" */ + YYSYMBOL_CQL2_TOK_S_CROSSES = 23, /* "S_CROSSES" */ + YYSYMBOL_CQL2_TOK_S_CONTAINS = 24, /* "S_CONTAINS" */ + YYSYMBOL_25_ = 25, /* '=' */ + YYSYMBOL_26_ = 26, /* '<' */ + YYSYMBOL_27_ = 27, /* '>' */ + YYSYMBOL_28_ = 28, /* '!' */ + YYSYMBOL_CQL2_TOK_BETWEEN = 29, /* CQL2_TOK_BETWEEN */ + YYSYMBOL_CQL2_TOK_IN = 30, /* CQL2_TOK_IN */ + YYSYMBOL_CQL2_TOK_LIKE = 31, /* CQL2_TOK_LIKE */ + YYSYMBOL_32_ = 32, /* '+' */ + YYSYMBOL_33_ = 33, /* '-' */ + YYSYMBOL_34_ = 34, /* '*' */ + YYSYMBOL_35_ = 35, /* '/' */ + YYSYMBOL_36_ = 36, /* '%' */ + YYSYMBOL_CQL2_TOK_UMINUS = 37, /* CQL2_TOK_UMINUS */ + YYSYMBOL_38_ = 38, /* '(' */ + YYSYMBOL_39_ = 39, /* ')' */ + YYSYMBOL_40_ = 40, /* ',' */ + YYSYMBOL_YYACCEPT = 41, /* $accept */ + YYSYMBOL_input = 42, /* input */ + YYSYMBOL_boolean_expr = 43, /* boolean_expr */ + YYSYMBOL_value_expr_list = 44, /* value_expr_list */ + YYSYMBOL_value_expr_or_boolean_literal = 45, /* value_expr_or_boolean_literal */ + YYSYMBOL_value_expr = 46 /* value_expr */ +}; +typedef enum yysymbol_kind_t yysymbol_kind_t; + + + + +#ifdef short +# undef short +#endif + +/* On compilers that do not define __PTRDIFF_MAX__ etc., make sure + and (if available) are included + so that the code can choose integer types of a good width. */ + +#ifndef __PTRDIFF_MAX__ +# include /* INFRINGES ON USER NAME SPACE */ +# if defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__ +# include /* INFRINGES ON USER NAME SPACE */ +# define YY_STDINT_H +# endif +#endif + +/* Narrow types that promote to a signed type and that can represent a + signed or unsigned integer of at least N bits. In tables they can + save space and decrease cache pressure. Promoting to a signed type + helps avoid bugs in integer arithmetic. */ + +#ifdef __INT_LEAST8_MAX__ +typedef __INT_LEAST8_TYPE__ yytype_int8; +#elif defined YY_STDINT_H +typedef int_least8_t yytype_int8; +#else +typedef signed char yytype_int8; +#endif + +#ifdef __INT_LEAST16_MAX__ +typedef __INT_LEAST16_TYPE__ yytype_int16; +#elif defined YY_STDINT_H +typedef int_least16_t yytype_int16; +#else +typedef short yytype_int16; +#endif + +/* Work around bug in HP-UX 11.23, which defines these macros + incorrectly for preprocessor constants. This workaround can likely + be removed in 2023, as HPE has promised support for HP-UX 11.23 + (aka HP-UX 11i v2) only through the end of 2022; see Table 2 of + . */ +#ifdef __hpux +# undef UINT_LEAST8_MAX +# undef UINT_LEAST16_MAX +# define UINT_LEAST8_MAX 255 +# define UINT_LEAST16_MAX 65535 +#endif + +#if defined __UINT_LEAST8_MAX__ && __UINT_LEAST8_MAX__ <= __INT_MAX__ +typedef __UINT_LEAST8_TYPE__ yytype_uint8; +#elif (!defined __UINT_LEAST8_MAX__ && defined YY_STDINT_H \ + && UINT_LEAST8_MAX <= INT_MAX) +typedef uint_least8_t yytype_uint8; +#elif !defined __UINT_LEAST8_MAX__ && UCHAR_MAX <= INT_MAX +typedef unsigned char yytype_uint8; +#else +typedef short yytype_uint8; +#endif + +#if defined __UINT_LEAST16_MAX__ && __UINT_LEAST16_MAX__ <= __INT_MAX__ +typedef __UINT_LEAST16_TYPE__ yytype_uint16; +#elif (!defined __UINT_LEAST16_MAX__ && defined YY_STDINT_H \ + && UINT_LEAST16_MAX <= INT_MAX) +typedef uint_least16_t yytype_uint16; +#elif !defined __UINT_LEAST16_MAX__ && USHRT_MAX <= INT_MAX +typedef unsigned short yytype_uint16; +#else +typedef int yytype_uint16; +#endif + +#ifndef YYPTRDIFF_T +# if defined __PTRDIFF_TYPE__ && defined __PTRDIFF_MAX__ +# define YYPTRDIFF_T __PTRDIFF_TYPE__ +# define YYPTRDIFF_MAXIMUM __PTRDIFF_MAX__ +# elif defined PTRDIFF_MAX +# ifndef ptrdiff_t +# include /* INFRINGES ON USER NAME SPACE */ +# endif +# define YYPTRDIFF_T ptrdiff_t +# define YYPTRDIFF_MAXIMUM PTRDIFF_MAX +# else +# define YYPTRDIFF_T long +# define YYPTRDIFF_MAXIMUM LONG_MAX +# endif +#endif + +#ifndef YYSIZE_T +# ifdef __SIZE_TYPE__ +# define YYSIZE_T __SIZE_TYPE__ +# elif defined size_t +# define YYSIZE_T size_t +# elif defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__ +# include /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# else +# define YYSIZE_T unsigned +# endif +#endif + +#define YYSIZE_MAXIMUM \ + YY_CAST (YYPTRDIFF_T, \ + (YYPTRDIFF_MAXIMUM < YY_CAST (YYSIZE_T, -1) \ + ? YYPTRDIFF_MAXIMUM \ + : YY_CAST (YYSIZE_T, -1))) + +#define YYSIZEOF(X) YY_CAST (YYPTRDIFF_T, sizeof (X)) + + +/* Stored state numbers (used for stacks). */ +typedef yytype_uint8 yy_state_t; + +/* State numbers in computations. */ +typedef int yy_state_fast_t; + +#ifndef YY_ +# if defined YYENABLE_NLS && YYENABLE_NLS +# if ENABLE_NLS +# include /* INFRINGES ON USER NAME SPACE */ +# define YY_(Msgid) dgettext ("bison-runtime", Msgid) +# endif +# endif +# ifndef YY_ +# define YY_(Msgid) Msgid +# endif +#endif + + +#ifndef YY_ATTRIBUTE_PURE +# if defined __GNUC__ && 2 < __GNUC__ + (96 <= __GNUC_MINOR__) +# define YY_ATTRIBUTE_PURE __attribute__ ((__pure__)) +# else +# define YY_ATTRIBUTE_PURE +# endif +#endif + +#ifndef YY_ATTRIBUTE_UNUSED +# if defined __GNUC__ && 2 < __GNUC__ + (7 <= __GNUC_MINOR__) +# define YY_ATTRIBUTE_UNUSED __attribute__ ((__unused__)) +# else +# define YY_ATTRIBUTE_UNUSED +# endif +#endif + +/* Suppress unused-variable warnings by "using" E. */ +#if ! defined lint || defined __GNUC__ +# define YY_USE(E) ((void) (E)) +#else +# define YY_USE(E) /* empty */ +#endif + +/* Suppress an incorrect diagnostic about yylval being uninitialized. */ +#if defined __GNUC__ && ! defined __ICC && 406 <= __GNUC__ * 100 + __GNUC_MINOR__ +# if __GNUC__ * 100 + __GNUC_MINOR__ < 407 +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ + _Pragma ("GCC diagnostic push") \ + _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") +# else +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ + _Pragma ("GCC diagnostic push") \ + _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") \ + _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") +# endif +# define YY_IGNORE_MAYBE_UNINITIALIZED_END \ + _Pragma ("GCC diagnostic pop") +#else +# define YY_INITIAL_VALUE(Value) Value +#endif +#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_END +#endif +#ifndef YY_INITIAL_VALUE +# define YY_INITIAL_VALUE(Value) /* Nothing. */ +#endif + +#if defined __cplusplus && defined __GNUC__ && ! defined __ICC && 6 <= __GNUC__ +# define YY_IGNORE_USELESS_CAST_BEGIN \ + _Pragma ("GCC diagnostic push") \ + _Pragma ("GCC diagnostic ignored \"-Wuseless-cast\"") +# define YY_IGNORE_USELESS_CAST_END \ + _Pragma ("GCC diagnostic pop") +#endif +#ifndef YY_IGNORE_USELESS_CAST_BEGIN +# define YY_IGNORE_USELESS_CAST_BEGIN +# define YY_IGNORE_USELESS_CAST_END +#endif + + +#define YY_ASSERT(E) ((void) (0 && (E))) + +#if 1 + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# ifdef YYSTACK_USE_ALLOCA +# if YYSTACK_USE_ALLOCA +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# elif defined __BUILTIN_VA_ARG_INCR +# include /* INFRINGES ON USER NAME SPACE */ +# elif defined _AIX +# define YYSTACK_ALLOC __alloca +# elif defined _MSC_VER +# include /* INFRINGES ON USER NAME SPACE */ +# define alloca _alloca +# else +# define YYSTACK_ALLOC alloca +# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS +# include /* INFRINGES ON USER NAME SPACE */ + /* Use EXIT_SUCCESS as a witness for stdlib.h. */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# endif +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's 'empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) +# ifndef YYSTACK_ALLOC_MAXIMUM + /* The OS might guarantee only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + invoke alloca (N) if N exceeds 4096. Use a slightly smaller number + to allow for a few compiler-allocated temporary stack slots. */ +# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ +# endif +# else +# define YYSTACK_ALLOC YYMALLOC +# define YYSTACK_FREE YYFREE +# ifndef YYSTACK_ALLOC_MAXIMUM +# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM +# endif +# if (defined __cplusplus && ! defined EXIT_SUCCESS \ + && ! ((defined YYMALLOC || defined malloc) \ + && (defined YYFREE || defined free))) +# include /* INFRINGES ON USER NAME SPACE */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# endif +# endif +# ifndef YYMALLOC +# define YYMALLOC malloc +# if ! defined malloc && ! defined EXIT_SUCCESS +void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# ifndef YYFREE +# define YYFREE free +# if ! defined free && ! defined EXIT_SUCCESS +void free (void *); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# endif +#endif /* 1 */ + +#if (! defined yyoverflow \ + && (! defined __cplusplus \ + || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + yy_state_t yyss_alloc; + YYSTYPE yyvs_alloc; +}; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (YYSIZEOF (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (YYSIZEOF (yy_state_t) + YYSIZEOF (YYSTYPE)) \ + + YYSTACK_GAP_MAXIMUM) + +# define YYCOPY_NEEDED 1 + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ + do \ + { \ + YYPTRDIFF_T yynewbytes; \ + YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ + Stack = &yyptr->Stack_alloc; \ + yynewbytes = yystacksize * YYSIZEOF (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / YYSIZEOF (*yyptr); \ + } \ + while (0) + +#endif + +#if defined YYCOPY_NEEDED && YYCOPY_NEEDED +/* Copy COUNT objects from SRC to DST. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined __GNUC__ && 1 < __GNUC__ +# define YYCOPY(Dst, Src, Count) \ + __builtin_memcpy (Dst, Src, YY_CAST (YYSIZE_T, (Count)) * sizeof (*(Src))) +# else +# define YYCOPY(Dst, Src, Count) \ + do \ + { \ + YYPTRDIFF_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (Dst)[yyi] = (Src)[yyi]; \ + } \ + while (0) +# endif +# endif +#endif /* !YYCOPY_NEEDED */ + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 24 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 399 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 41 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 6 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 53 +/* YYNSTATES -- Number of states. */ +#define YYNSTATES 162 + +/* YYMAXUTOK -- Last valid token kind. */ +#define YYMAXUTOK 283 + + +/* YYTRANSLATE(TOKEN-NUM) -- Symbol number corresponding to TOKEN-NUM + as returned by yylex, with out-of-bounds checking. */ +#define YYTRANSLATE(YYX) \ + (0 <= (YYX) && (YYX) <= YYMAXUTOK \ + ? YY_CAST (yysymbol_kind_t, yytranslate[YYX]) \ + : YYSYMBOL_YYUNDEF) + +/* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM + as returned by yylex. */ +static const yytype_int8 yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 28, 2, 2, 2, 36, 2, 2, + 38, 39, 34, 32, 40, 33, 2, 35, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 26, 25, 27, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 29, 30, 31, 37 +}; + +#if YYDEBUG +/* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ +static const yytype_int16 yyrline[] = +{ + 0, 85, 85, 86, 93, 104, 115, 127, 140, 153, + 166, 179, 191, 204, 217, 231, 244, 257, 273, 286, + 302, 317, 334, 348, 365, 377, 392, 405, 418, 431, + 444, 457, 470, 483, 496, 501, 507, 519, 533, 535, + 541, 546, 551, 556, 561, 567, 577, 590, 603, 616, + 629, 642, 655, 685 +}; +#endif + +/** Accessing symbol of state STATE. */ +#define YY_ACCESSING_SYMBOL(State) YY_CAST (yysymbol_kind_t, yystos[State]) + +#if 1 +/* The user-facing name of the symbol whose (internal) number is + YYSYMBOL. No bounds checking. */ +static const char *yysymbol_name (yysymbol_kind_t yysymbol) YY_ATTRIBUTE_UNUSED; + +/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = +{ + "\"end of string\"", "error", "\"invalid token\"", + "CQL2_TOK_VALUE_START", "\"integer number\"", + "\"floating point number\"", "\"string\"", "\"identifier\"", + "\"wkt geometry\"", "\"NOT\"", "\"OR\"", "\"AND\"", "\"DIV\"", "\"IS\"", + "\"NULL\"", "\"true/false\"", "\"CASEI\"", "\"S_INTERSECTS\"", + "\"S_EQUALS\"", "\"S_DISJOINT\"", "\"S_TOUCHES\"", "\"S_WITHIN\"", + "\"S_OVERLAPS\"", "\"S_CROSSES\"", "\"S_CONTAINS\"", "'='", "'<'", "'>'", + "'!'", "CQL2_TOK_BETWEEN", "CQL2_TOK_IN", "CQL2_TOK_LIKE", "'+'", "'-'", + "'*'", "'/'", "'%'", "CQL2_TOK_UMINUS", "'('", "')'", "','", "$accept", + "input", "boolean_expr", "value_expr_list", + "value_expr_or_boolean_literal", "value_expr", YY_NULLPTR +}; + +static const char * +yysymbol_name (yysymbol_kind_t yysymbol) +{ + return yytname[yysymbol]; +} +#endif + +#define YYPACT_NINF (-41) + +#define yypact_value_is_default(Yyn) \ + ((Yyn) == YYPACT_NINF) + +#define YYTABLE_NINF (-40) + +#define yytable_value_is_error(Yyn) \ + 0 + +/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +static const yytype_int16 yypact[] = +{ + 20, 97, 25, -41, -41, -41, -11, -41, 97, -21, + -6, 1, 5, 34, 35, 37, 38, 42, 60, 138, + 97, 46, 72, 250, -41, 138, -41, 36, 138, 138, + 138, 138, 138, 138, 138, 138, 138, 138, -41, 11, + 151, 97, 97, 118, 78, 138, -7, 41, 132, 138, + 62, 104, 138, 138, 138, 138, 138, 88, 19, 118, + 239, 59, 160, 176, 185, 194, 203, 212, 221, 255, + -41, -41, 117, -41, -41, -41, 363, 138, 91, 126, + -41, 120, -41, 138, 118, 363, 138, 363, 347, 138, + -41, 26, 26, -41, -41, -41, -41, 138, -41, 122, + 138, 138, 138, 138, 138, 138, 138, 138, 356, 138, + -41, -41, 363, -41, 363, 138, 102, -41, 119, 133, + 125, 139, 280, 288, 296, 305, 313, 321, 330, 338, + 138, 115, 363, -41, 142, 121, 145, 124, -41, -41, + -41, -41, -41, -41, -41, -41, 363, -41, 128, 161, + 130, 163, 167, 135, 169, 140, 150, -41, 152, -41, + -41, -41 +}; + +/* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. + Performed when YYTABLE does not specify something else to do. Zero + means the default is an error. */ +static const yytype_int8 yydefact[] = +{ + 2, 0, 0, 40, 41, 42, 44, 43, 0, 35, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 3, 0, 38, 1, 0, 6, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, + 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 37, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 34, 53, 5, 4, 39, 7, 38, 0, 0, 0, + 50, 0, 24, 0, 0, 12, 0, 13, 0, 0, + 16, 46, 47, 48, 49, 51, 45, 0, 10, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 17, 25, 14, 9, 15, 0, 0, 36, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 22, 20, 0, 0, 0, 0, 26, 27, + 28, 29, 30, 31, 32, 33, 23, 21, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 8, 0, 18, + 19, 11 +}; + +/* YYPGOTO[NTERM-NUM]. */ +static const yytype_int8 yypgoto[] = +{ + -41, -41, 0, -20, -40, -19 +}; + +/* YYDEFGOTO[NTERM-NUM]. */ +static const yytype_int8 yydefgoto[] = +{ + 0, 2, 21, 57, 22, 23 +}; + +/* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule whose + number is the opposite. If YYTABLE_NINF, syntax error. */ +static const yytype_int16 yytable[] = +{ + 38, 40, 81, 75, -39, 27, 58, 82, 26, 60, + 61, 62, 63, 64, 65, 66, 67, 68, 69, 98, + 39, 41, 42, 1, 76, 24, 80, 25, 85, 87, + 88, 45, 28, 91, 92, 93, 94, 95, 45, 29, + 76, 72, 73, 30, 113, 3, 4, 5, 6, 7, + 70, 52, 53, 54, 55, 56, 41, 42, 108, 97, + 54, 55, 56, 59, 112, 76, 83, 114, 84, 116, + 58, 45, 31, 32, 19, 33, 34, 117, 58, 37, + 35, 122, 123, 124, 125, 126, 127, 128, 129, 131, + 58, 52, 53, 54, 55, 56, 132, 43, 36, 100, + 89, 3, 4, 5, 6, 7, 8, 77, 78, 79, + 90, 146, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 3, 4, 5, 6, 7, 96, 42, 109, + 19, 118, 110, 74, 111, 20, 3, 4, 5, 6, + 7, 133, 3, 4, 5, 6, 7, 119, 120, 135, + 134, 19, 136, 121, 147, 137, 37, 86, 148, 149, + 44, 150, 151, 45, 46, 19, 152, 153, 154, 155, + 37, 19, 45, 156, 157, 158, 37, 47, 48, 159, + 49, 50, 51, 52, 53, 54, 55, 56, 45, 160, + 71, 161, 52, 53, 54, 55, 56, 45, 0, 0, + 101, 0, 0, 0, 0, 0, 45, 0, 52, 53, + 54, 55, 56, 0, 0, 45, 102, 52, 53, 54, + 55, 56, 0, 0, 45, 103, 52, 53, 54, 55, + 56, 0, 0, 45, 104, 52, 53, 54, 55, 56, + 0, 0, 0, 105, 52, 53, 54, 55, 56, 0, + 0, 45, 106, 52, 53, 54, 55, 56, 0, 44, + 0, 107, 45, 46, 0, 0, 0, 45, 0, 0, + 0, 52, 53, 54, 55, 56, 47, 48, 99, 49, + 50, 51, 52, 53, 54, 55, 56, 52, 53, 54, + 55, 56, 45, 0, 71, 0, 0, 0, 0, 0, + 45, 0, 0, 0, 0, 0, 0, 0, 45, 0, + 0, 0, 52, 53, 54, 55, 56, 45, 0, 138, + 52, 53, 54, 55, 56, 45, 0, 139, 52, 53, + 54, 55, 56, 45, 0, 140, 0, 52, 53, 54, + 55, 56, 45, 0, 141, 52, 53, 54, 55, 56, + 45, 0, 142, 52, 53, 54, 55, 56, 115, 45, + 143, 0, 52, 53, 54, 55, 56, 130, 45, 144, + 52, 53, 54, 55, 56, 45, 0, 145, 0, 52, + 53, 54, 55, 56, 0, 0, 0, 0, 52, 53, + 54, 55, 56, 0, 0, 52, 53, 54, 55, 56 +}; + +static const yytype_int16 yycheck[] = +{ + 19, 20, 9, 43, 25, 26, 25, 14, 8, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 59, + 20, 10, 11, 3, 43, 0, 45, 38, 47, 48, + 49, 12, 38, 52, 53, 54, 55, 56, 12, 38, + 59, 41, 42, 38, 84, 4, 5, 6, 7, 8, + 39, 32, 33, 34, 35, 36, 10, 11, 77, 40, + 34, 35, 36, 27, 83, 84, 25, 86, 27, 89, + 89, 12, 38, 38, 33, 38, 38, 97, 97, 38, + 38, 100, 101, 102, 103, 104, 105, 106, 107, 109, + 109, 32, 33, 34, 35, 36, 115, 25, 38, 40, + 38, 4, 5, 6, 7, 8, 9, 29, 30, 31, + 6, 130, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 4, 5, 6, 7, 8, 39, 11, 38, + 33, 9, 6, 15, 14, 38, 4, 5, 6, 7, + 8, 39, 4, 5, 6, 7, 8, 25, 26, 16, + 31, 33, 27, 31, 39, 16, 38, 25, 16, 38, + 9, 16, 38, 12, 13, 33, 38, 6, 38, 6, + 38, 33, 12, 6, 39, 6, 38, 26, 27, 39, + 29, 30, 31, 32, 33, 34, 35, 36, 12, 39, + 39, 39, 32, 33, 34, 35, 36, 12, -1, -1, + 40, -1, -1, -1, -1, -1, 12, -1, 32, 33, + 34, 35, 36, -1, -1, 12, 40, 32, 33, 34, + 35, 36, -1, -1, 12, 40, 32, 33, 34, 35, + 36, -1, -1, 12, 40, 32, 33, 34, 35, 36, + -1, -1, -1, 40, 32, 33, 34, 35, 36, -1, + -1, 12, 40, 32, 33, 34, 35, 36, -1, 9, + -1, 40, 12, 13, -1, -1, -1, 12, -1, -1, + -1, 32, 33, 34, 35, 36, 26, 27, 39, 29, + 30, 31, 32, 33, 34, 35, 36, 32, 33, 34, + 35, 36, 12, -1, 39, -1, -1, -1, -1, -1, + 12, -1, -1, -1, -1, -1, -1, -1, 12, -1, + -1, -1, 32, 33, 34, 35, 36, 12, -1, 39, + 32, 33, 34, 35, 36, 12, -1, 39, 32, 33, + 34, 35, 36, 12, -1, 39, -1, 32, 33, 34, + 35, 36, 12, -1, 39, 32, 33, 34, 35, 36, + 12, -1, 39, 32, 33, 34, 35, 36, 11, 12, + 39, -1, 32, 33, 34, 35, 36, 11, 12, 39, + 32, 33, 34, 35, 36, 12, -1, 39, -1, 32, + 33, 34, 35, 36, -1, -1, -1, -1, 32, 33, + 34, 35, 36, -1, -1, 32, 33, 34, 35, 36 +}; + +/* YYSTOS[STATE-NUM] -- The symbol kind of the accessing symbol of + state STATE-NUM. */ +static const yytype_int8 yystos[] = +{ + 0, 3, 42, 4, 5, 6, 7, 8, 9, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 33, + 38, 43, 45, 46, 0, 38, 43, 26, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 46, 43, + 46, 10, 11, 25, 9, 12, 13, 26, 27, 29, + 30, 31, 32, 33, 34, 35, 36, 44, 46, 27, + 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, + 39, 39, 43, 43, 15, 45, 46, 29, 30, 31, + 46, 9, 14, 25, 27, 46, 25, 46, 46, 38, + 6, 46, 46, 46, 46, 46, 39, 40, 45, 39, + 40, 40, 40, 40, 40, 40, 40, 40, 46, 38, + 6, 14, 46, 45, 46, 11, 44, 44, 9, 25, + 26, 31, 46, 46, 46, 46, 46, 46, 46, 46, + 11, 44, 46, 39, 31, 16, 27, 16, 39, 39, + 39, 39, 39, 39, 39, 39, 46, 39, 16, 38, + 16, 38, 38, 6, 38, 6, 6, 39, 6, 39, + 39, 39 +}; + +/* YYR1[RULE-NUM] -- Symbol kind of the left-hand side of rule RULE-NUM. */ +static const yytype_int8 yyr1[] = +{ + 0, 41, 42, 42, 43, 43, 43, 43, 43, 43, + 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, + 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, + 43, 43, 43, 43, 43, 43, 44, 44, 45, 45, + 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, + 46, 46, 46, 46 +}; + +/* YYR2[RULE-NUM] -- Number of symbols on the right-hand side of rule RULE-NUM. */ +static const yytype_int8 yyr2[] = +{ + 0, 2, 0, 2, 3, 3, 2, 3, 9, 4, + 4, 10, 3, 3, 4, 4, 3, 4, 9, 10, + 5, 6, 5, 6, 3, 4, 6, 6, 6, 6, + 6, 6, 6, 6, 3, 1, 3, 1, 1, 1, + 1, 1, 1, 1, 1, 4, 3, 3, 3, 3, + 3, 3, 2, 3 +}; + + +enum { YYENOMEM = -2 }; + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab +#define YYNOMEM goto yyexhaustedlab + + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ + do \ + if (yychar == YYEMPTY) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + YYPOPSTACK (yylen); \ + yystate = *yyssp; \ + goto yybackup; \ + } \ + else \ + { \ + yyerror (context, YY_("syntax error: cannot back up")); \ + YYERROR; \ + } \ + while (0) + +/* Backward compatibility with an undocumented macro. + Use YYerror or YYUNDEF. */ +#define YYERRCODE YYUNDEF + + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (0) + + + + +# define YY_SYMBOL_PRINT(Title, Kind, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yy_symbol_print (stderr, \ + Kind, Value, context); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (0) + + +/*-----------------------------------. +| Print this symbol's value on YYO. | +`-----------------------------------*/ + +static void +yy_symbol_value_print (FILE *yyo, + yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep, cql2text_parse_context *context) +{ + FILE *yyoutput = yyo; + YY_USE (yyoutput); + YY_USE (context); + if (!yyvaluep) + return; + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + YY_USE (yykind); + YY_IGNORE_MAYBE_UNINITIALIZED_END +} + + +/*---------------------------. +| Print this symbol on YYO. | +`---------------------------*/ + +static void +yy_symbol_print (FILE *yyo, + yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep, cql2text_parse_context *context) +{ + YYFPRINTF (yyo, "%s %s (", + yykind < YYNTOKENS ? "token" : "nterm", yysymbol_name (yykind)); + + yy_symbol_value_print (yyo, yykind, yyvaluep, context); + YYFPRINTF (yyo, ")"); +} + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (included). | +`------------------------------------------------------------------*/ + +static void +yy_stack_print (yy_state_t *yybottom, yy_state_t *yytop) +{ + YYFPRINTF (stderr, "Stack now"); + for (; yybottom <= yytop; yybottom++) + { + int yybot = *yybottom; + YYFPRINTF (stderr, " %d", yybot); + } + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (0) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +static void +yy_reduce_print (yy_state_t *yyssp, YYSTYPE *yyvsp, + int yyrule, cql2text_parse_context *context) +{ + int yylno = yyrline[yyrule]; + int yynrhs = yyr2[yyrule]; + int yyi; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %d):\n", + yyrule - 1, yylno); + /* The symbols being reduced. */ + for (yyi = 0; yyi < yynrhs; yyi++) + { + YYFPRINTF (stderr, " $%d = ", yyi + 1); + yy_symbol_print (stderr, + YY_ACCESSING_SYMBOL (+yyssp[yyi + 1 - yynrhs]), + &yyvsp[(yyi + 1) - (yynrhs)], context); + YYFPRINTF (stderr, "\n"); + } +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (yyssp, yyvsp, Rule, context); \ +} while (0) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) ((void) 0) +# define YY_SYMBOL_PRINT(Title, Kind, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + +/* Context of a parse error. */ +typedef struct +{ + yy_state_t *yyssp; + yysymbol_kind_t yytoken; +} yypcontext_t; + +/* Put in YYARG at most YYARGN of the expected tokens given the + current YYCTX, and return the number of tokens stored in YYARG. If + YYARG is null, return the number of expected tokens (guaranteed to + be less than YYNTOKENS). Return YYENOMEM on memory exhaustion. + Return 0 if there are more than YYARGN expected tokens, yet fill + YYARG up to YYARGN. */ +static int +yypcontext_expected_tokens (const yypcontext_t *yyctx, + yysymbol_kind_t yyarg[], int yyargn) +{ + /* Actual size of YYARG. */ + int yycount = 0; + int yyn = yypact[+*yyctx->yyssp]; + if (!yypact_value_is_default (yyn)) + { + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. In other words, skip the first -YYN actions for + this state because they are default actions. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn + 1; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yyx; + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYSYMBOL_YYerror + && !yytable_value_is_error (yytable[yyx + yyn])) + { + if (!yyarg) + ++yycount; + else if (yycount == yyargn) + return 0; + else + yyarg[yycount++] = YY_CAST (yysymbol_kind_t, yyx); + } + } + if (yyarg && yycount == 0 && 0 < yyargn) + yyarg[0] = YYSYMBOL_YYEMPTY; + return yycount; +} + + + + +#ifndef yystrlen +# if defined __GLIBC__ && defined _STRING_H +# define yystrlen(S) (YY_CAST (YYPTRDIFF_T, strlen (S))) +# else +/* Return the length of YYSTR. */ +static YYPTRDIFF_T +yystrlen (const char *yystr) +{ + YYPTRDIFF_T yylen; + for (yylen = 0; yystr[yylen]; yylen++) + continue; + return yylen; +} +# endif +#endif + +#ifndef yystpcpy +# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +static char * +yystpcpy (char *yydest, const char *yysrc) +{ + char *yyd = yydest; + const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +#endif + +#ifndef yytnamerr +/* Copy to YYRES the contents of YYSTR after stripping away unnecessary + quotes and backslashes, so that it's suitable for yyerror. The + heuristic is that double-quoting is unnecessary unless the string + contains an apostrophe, a comma, or backslash (other than + backslash-backslash). YYSTR is taken from yytname. If YYRES is + null, do not copy; instead, return the length of what the result + would have been. */ +static YYPTRDIFF_T +yytnamerr (char *yyres, const char *yystr) +{ + if (*yystr == '"') + { + YYPTRDIFF_T yyn = 0; + char const *yyp = yystr; + for (;;) + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; + + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + else + goto append; + + append: + default: + if (yyres) + yyres[yyn] = *yyp; + yyn++; + break; + + case '"': + if (yyres) + yyres[yyn] = '\0'; + return yyn; + } + do_not_strip_quotes: ; + } + + if (yyres) + return yystpcpy (yyres, yystr) - yyres; + else + return yystrlen (yystr); +} +#endif + + +static int +yy_syntax_error_arguments (const yypcontext_t *yyctx, + yysymbol_kind_t yyarg[], int yyargn) +{ + /* Actual size of YYARG. */ + int yycount = 0; + /* There are many possibilities here to consider: + - If this state is a consistent state with a default action, then + the only way this function was invoked is if the default action + is an error action. In that case, don't check for expected + tokens because there are none. + - The only way there can be no lookahead present (in yychar) is if + this state is a consistent state with a default action. Thus, + detecting the absence of a lookahead is sufficient to determine + that there is no unexpected or expected token to report. In that + case, just report a simple "syntax error". + - Don't assume there isn't a lookahead just because this state is a + consistent state with a default action. There might have been a + previous inconsistent state, consistent state with a non-default + action, or user semantic action that manipulated yychar. + - Of course, the expected token list depends on states to have + correct lookahead information, and it depends on the parser not + to perform extra reductions after fetching a lookahead from the + scanner and before detecting a syntax error. Thus, state merging + (from LALR or IELR) and default reductions corrupt the expected + token list. However, the list is correct for canonical LR with + one exception: it will still contain any token that will not be + accepted due to an error action in a later state. + */ + if (yyctx->yytoken != YYSYMBOL_YYEMPTY) + { + int yyn; + if (yyarg) + yyarg[yycount] = yyctx->yytoken; + ++yycount; + yyn = yypcontext_expected_tokens (yyctx, + yyarg ? yyarg + 1 : yyarg, yyargn - 1); + if (yyn == YYENOMEM) + return YYENOMEM; + else + yycount += yyn; + } + return yycount; +} + +/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message + about the unexpected token YYTOKEN for the state stack whose top is + YYSSP. + + Return 0 if *YYMSG was successfully written. Return -1 if *YYMSG is + not large enough to hold the message. In that case, also set + *YYMSG_ALLOC to the required number of bytes. Return YYENOMEM if the + required number of bytes is too large to store. */ +static int +yysyntax_error (YYPTRDIFF_T *yymsg_alloc, char **yymsg, + const yypcontext_t *yyctx) +{ + enum { YYARGS_MAX = 5 }; + /* Internationalized format string. */ + const char *yyformat = YY_NULLPTR; + /* Arguments of yyformat: reported tokens (one for the "unexpected", + one per "expected"). */ + yysymbol_kind_t yyarg[YYARGS_MAX]; + /* Cumulated lengths of YYARG. */ + YYPTRDIFF_T yysize = 0; + + /* Actual size of YYARG. */ + int yycount = yy_syntax_error_arguments (yyctx, yyarg, YYARGS_MAX); + if (yycount == YYENOMEM) + return YYENOMEM; + + switch (yycount) + { +#define YYCASE_(N, S) \ + case N: \ + yyformat = S; \ + break + default: /* Avoid compiler warnings. */ + YYCASE_(0, YY_("syntax error")); + YYCASE_(1, YY_("syntax error, unexpected %s")); + YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); + YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); + YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); + YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); +#undef YYCASE_ + } + + /* Compute error message size. Don't count the "%s"s, but reserve + room for the terminator. */ + yysize = yystrlen (yyformat) - 2 * yycount + 1; + { + int yyi; + for (yyi = 0; yyi < yycount; ++yyi) + { + YYPTRDIFF_T yysize1 + = yysize + yytnamerr (YY_NULLPTR, yytname[yyarg[yyi]]); + if (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM) + yysize = yysize1; + else + return YYENOMEM; + } + } + + if (*yymsg_alloc < yysize) + { + *yymsg_alloc = 2 * yysize; + if (! (yysize <= *yymsg_alloc + && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM)) + *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM; + return -1; + } + + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + { + char *yyp = *yymsg; + int yyi = 0; + while ((*yyp = *yyformat) != '\0') + if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yytname[yyarg[yyi++]]); + yyformat += 2; + } + else + { + ++yyp; + ++yyformat; + } + } + return 0; +} + + +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +static void +yydestruct (const char *yymsg, + yysymbol_kind_t yykind, YYSTYPE *yyvaluep, cql2text_parse_context *context) +{ + YY_USE (yyvaluep); + YY_USE (context); + if (!yymsg) + yymsg = "Deleting"; + YY_SYMBOL_PRINT (yymsg, yykind, yyvaluep, yylocationp); + + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + switch (yykind) + { + case YYSYMBOL_CQL2_TOK_INTEGER_NUMBER: /* "integer number" */ + { delete (*yyvaluep); } + break; + + case YYSYMBOL_CQL2_TOK_DOUBLE_NUMBER: /* "floating point number" */ + { delete (*yyvaluep); } + break; + + case YYSYMBOL_CQL2_TOK_STRING: /* "string" */ + { delete (*yyvaluep); } + break; + + case YYSYMBOL_CQL2_TOK_IDENTIFIER: /* "identifier" */ + { delete (*yyvaluep); } + break; + + case YYSYMBOL_CQL2_TOK_WKT: /* "wkt geometry" */ + { delete (*yyvaluep); } + break; + + case YYSYMBOL_CQL2_TOK_BOOLEAN_LITERAL: /* "true/false" */ + { delete (*yyvaluep); } + break; + + case YYSYMBOL_boolean_expr: /* boolean_expr */ + { delete (*yyvaluep); } + break; + + case YYSYMBOL_value_expr_list: /* value_expr_list */ + { delete (*yyvaluep); } + break; + + case YYSYMBOL_value_expr_or_boolean_literal: /* value_expr_or_boolean_literal */ + { delete (*yyvaluep); } + break; + + case YYSYMBOL_value_expr: /* value_expr */ + { delete (*yyvaluep); } + break; + + default: + break; + } + YY_IGNORE_MAYBE_UNINITIALIZED_END +} + + + + + + +/*----------. +| yyparse. | +`----------*/ + +int +yyparse (cql2text_parse_context *context) +{ +/* Lookahead token kind. */ +int yychar; + + +/* The semantic value of the lookahead symbol. */ +/* Default value used for initialization, for pacifying older GCCs + or non-GCC compilers. */ +YY_INITIAL_VALUE (static YYSTYPE yyval_default;) +YYSTYPE yylval YY_INITIAL_VALUE (= yyval_default); + + /* Number of syntax errors so far. */ + int yynerrs = 0; + + yy_state_fast_t yystate = 0; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus = 0; + + /* Refer to the stacks through separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* Their size. */ + YYPTRDIFF_T yystacksize = YYINITDEPTH; + + /* The state stack: array, bottom, top. */ + yy_state_t yyssa[YYINITDEPTH]; + yy_state_t *yyss = yyssa; + yy_state_t *yyssp = yyss; + + /* The semantic value stack: array, bottom, top. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs = yyvsa; + YYSTYPE *yyvsp = yyvs; + + int yyn; + /* The return value of yyparse. */ + int yyresult; + /* Lookahead symbol kind. */ + yysymbol_kind_t yytoken = YYSYMBOL_YYEMPTY; + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + + /* Buffer for error messages, and its allocated size. */ + char yymsgbuf[128]; + char *yymsg = yymsgbuf; + YYPTRDIFF_T yymsg_alloc = sizeof yymsgbuf; + +#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) + + /* The number of symbols on the RHS of the reduced rule. + Keep to zero when no symbol should be popped. */ + int yylen = 0; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yychar = YYEMPTY; /* Cause a token to be read. */ + + goto yysetstate; + + +/*------------------------------------------------------------. +| yynewstate -- push a new state, which is found in yystate. | +`------------------------------------------------------------*/ +yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. So pushing a state here evens the stacks. */ + yyssp++; + + +/*--------------------------------------------------------------------. +| yysetstate -- set current state (the top of the stack) to yystate. | +`--------------------------------------------------------------------*/ +yysetstate: + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + YY_ASSERT (0 <= yystate && yystate < YYNSTATES); + YY_IGNORE_USELESS_CAST_BEGIN + *yyssp = YY_CAST (yy_state_t, yystate); + YY_IGNORE_USELESS_CAST_END + YY_STACK_PRINT (yyss, yyssp); + + if (yyss + yystacksize - 1 <= yyssp) +#if !defined yyoverflow && !defined YYSTACK_RELOCATE + YYNOMEM; +#else + { + /* Get the current used size of the three stacks, in elements. */ + YYPTRDIFF_T yysize = yyssp - yyss + 1; + +# if defined yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + yy_state_t *yyss1 = yyss; + YYSTYPE *yyvs1 = yyvs; + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow (YY_("memory exhausted"), + &yyss1, yysize * YYSIZEOF (*yyssp), + &yyvs1, yysize * YYSIZEOF (*yyvsp), + &yystacksize); + yyss = yyss1; + yyvs = yyvs1; + } +# else /* defined YYSTACK_RELOCATE */ + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + YYNOMEM; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + yy_state_t *yyss1 = yyss; + union yyalloc *yyptr = + YY_CAST (union yyalloc *, + YYSTACK_ALLOC (YY_CAST (YYSIZE_T, YYSTACK_BYTES (yystacksize)))); + if (! yyptr) + YYNOMEM; + YYSTACK_RELOCATE (yyss_alloc, yyss); + YYSTACK_RELOCATE (yyvs_alloc, yyvs); +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + + YY_IGNORE_USELESS_CAST_BEGIN + YYDPRINTF ((stderr, "Stack size increased to %ld\n", + YY_CAST (long, yystacksize))); + YY_IGNORE_USELESS_CAST_END + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } +#endif /* !defined yyoverflow && !defined YYSTACK_RELOCATE */ + + + if (yystate == YYFINAL) + YYACCEPT; + + goto yybackup; + + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + /* Do appropriate processing given the current state. Read a + lookahead token if we need one and don't already have one. */ + + /* First try to decide what to do without reference to lookahead token. */ + yyn = yypact[yystate]; + if (yypact_value_is_default (yyn)) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* YYCHAR is either empty, or end-of-input, or a valid lookahead. */ + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token\n")); + yychar = yylex (&yylval, context); + } + + if (yychar <= END) + { + yychar = END; + yytoken = YYSYMBOL_YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else if (yychar == YYerror) + { + /* The scanner already issued an error message, process directly + to error recovery. But do not keep the error token as + lookahead, it is too special and may lead us to an endless + loop in error recovery. */ + yychar = YYUNDEF; + yytoken = YYSYMBOL_YYerror; + goto yyerrlab1; + } + else + { + yytoken = YYTRANSLATE (yychar); + YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yytable_value_is_error (yyn)) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + /* Shift the lookahead token. */ + YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); + yystate = yyn; + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + *++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_END + + /* Discard the shifted token. */ + yychar = YYEMPTY; + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + '$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + case 3: /* input: CQL2_TOK_VALUE_START boolean_expr */ + { + context->poRoot = yyvsp[0]; + } + break; + + case 4: /* boolean_expr: boolean_expr "AND" boolean_expr */ + { + yyval = cql2_create_and_or_or( CQL2_AND, std::unique_ptr(yyvsp[-2]), std::unique_ptr(yyvsp[0]) ); + if( yyval->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete yyval; + YYERROR; + } + } + break; + + case 5: /* boolean_expr: boolean_expr "OR" boolean_expr */ + { + yyval = cql2_create_and_or_or( CQL2_OR, std::unique_ptr(yyvsp[-2]), std::unique_ptr(yyvsp[0]) ); + if( yyval->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete yyval; + YYERROR; + } + } + break; + + case 6: /* boolean_expr: "NOT" boolean_expr */ + { + yyval = new cql2_expr_node( CQL2_NOT ); + yyval->PushSubExpression( yyvsp[0] ); + if( yyval->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete yyval; + YYERROR; + } + } + break; + + case 7: /* boolean_expr: value_expr_or_boolean_literal '=' value_expr_or_boolean_literal */ + { + yyval = new cql2_expr_node( CQL2_EQ ); + yyval->PushSubExpression( yyvsp[-2] ); + yyval->PushSubExpression( yyvsp[0] ); + if( yyval->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete yyval; + YYERROR; + } + } + break; + + case 8: /* boolean_expr: "CASEI" '(' value_expr ')' '=' "CASEI" '(' "string" ')' */ + { + yyval = new cql2_expr_node( CQL2_IEQ); + yyval->PushSubExpression( yyvsp[-6] ); + yyval->PushSubExpression( yyvsp[-1] ); + if( yyval->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete yyval; + YYERROR; + } + } + break; + + case 9: /* boolean_expr: value_expr '<' '>' value_expr_or_boolean_literal */ + { + yyval = new cql2_expr_node( CQL2_NE ); + yyval->PushSubExpression( yyvsp[-3] ); + yyval->PushSubExpression( yyvsp[0] ); + if( yyval->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete yyval; + YYERROR; + } + } + break; + + case 10: /* boolean_expr: "true/false" '<' '>' value_expr_or_boolean_literal */ + { + yyval = new cql2_expr_node( CQL2_NE ); + yyval->PushSubExpression( yyvsp[-3] ); + yyval->PushSubExpression( yyvsp[0] ); + if( yyval->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete yyval; + YYERROR; + } + } + break; + + case 11: /* boolean_expr: "CASEI" '(' value_expr ')' '<' '>' "CASEI" '(' "string" ')' */ + { + yyval = new cql2_expr_node( CQL2_INE); + yyval->PushSubExpression( yyvsp[-7] ); + yyval->PushSubExpression( yyvsp[-1] ); + if( yyval->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete yyval; + YYERROR; + } + } + break; + + case 12: /* boolean_expr: value_expr '<' value_expr */ + { + yyval = new cql2_expr_node( CQL2_LT ); + yyval->PushSubExpression( yyvsp[-2] ); + yyval->PushSubExpression( yyvsp[0] ); + if( yyval->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete yyval; + YYERROR; + } + } + break; + + case 13: /* boolean_expr: value_expr '>' value_expr */ + { + yyval = new cql2_expr_node( CQL2_GT ); + yyval->PushSubExpression( yyvsp[-2] ); + yyval->PushSubExpression( yyvsp[0] ); + if( yyval->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete yyval; + YYERROR; + } + } + break; + + case 14: /* boolean_expr: value_expr '<' '=' value_expr */ + { + yyval = new cql2_expr_node( CQL2_LE ); + yyval->PushSubExpression( yyvsp[-3] ); + yyval->PushSubExpression( yyvsp[0] ); + if( yyval->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete yyval; + YYERROR; + } + } + break; + + case 15: /* boolean_expr: value_expr '>' '=' value_expr */ + { + yyval = new cql2_expr_node( CQL2_GE ); + yyval->PushSubExpression( yyvsp[-3] ); + yyval->PushSubExpression( yyvsp[0] ); + if( yyval->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete yyval; + YYERROR; + } + } + break; + + case 16: /* boolean_expr: value_expr CQL2_TOK_LIKE "string" */ + { + yyval = new cql2_expr_node( CQL2_LIKE); + yyval->PushSubExpression( yyvsp[-2] ); + yyval->PushSubExpression( yyvsp[0] ); + if( yyval->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete yyval; + YYERROR; + } + } + break; + + case 17: /* boolean_expr: value_expr "NOT" CQL2_TOK_LIKE "string" */ + { + cql2_expr_node *like = new cql2_expr_node( CQL2_LIKE ); + like->PushSubExpression( yyvsp[-3] ); + like->PushSubExpression( yyvsp[0] ); + + yyval = new cql2_expr_node( CQL2_NOT ); + yyval->PushSubExpression( like ); + if( yyval->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete yyval; + YYERROR; + } + } + break; + + case 18: /* boolean_expr: "CASEI" '(' value_expr ')' CQL2_TOK_LIKE "CASEI" '(' "string" ')' */ + { + yyval = new cql2_expr_node( CQL2_ILIKE); + yyval->PushSubExpression( yyvsp[-6] ); + yyval->PushSubExpression( yyvsp[-1] ); + if( yyval->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete yyval; + YYERROR; + } + } + break; + + case 19: /* boolean_expr: "CASEI" '(' value_expr ')' "NOT" CQL2_TOK_LIKE "CASEI" '(' "string" ')' */ + { + cql2_expr_node *like = new cql2_expr_node( CQL2_ILIKE ); + like->PushSubExpression( yyvsp[-7] ); + like->PushSubExpression( yyvsp[-1] ); + + yyval = new cql2_expr_node( CQL2_NOT ); + yyval->PushSubExpression( like ); + if( yyval->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete yyval; + YYERROR; + } + } + break; + + case 20: /* boolean_expr: value_expr CQL2_TOK_IN '(' value_expr_list ')' */ + { + yyval = yyvsp[-1]; + yyval->m_field_type = CQL2_BOOLEAN; + yyval->m_op = CQL2_IN; + yyval->PushSubExpression( yyvsp[-4] ); + yyval->ReverseSubExpressions(); + if( yyval->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete yyval; + YYERROR; + } + } + break; + + case 21: /* boolean_expr: value_expr "NOT" CQL2_TOK_IN '(' value_expr_list ')' */ + { + cql2_expr_node *in = yyvsp[-1]; + in->m_op = CQL2_IN; + in->PushSubExpression( yyvsp[-5] ); + in->ReverseSubExpressions(); + + yyval = new cql2_expr_node( CQL2_NOT ); + yyval->PushSubExpression( in ); + if( yyval->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete yyval; + YYERROR; + } + } + break; + + case 22: /* boolean_expr: value_expr CQL2_TOK_BETWEEN value_expr "AND" value_expr */ + { + yyval = new cql2_expr_node( CQL2_BETWEEN ); + yyval->PushSubExpression( yyvsp[-4] ); + yyval->PushSubExpression( yyvsp[-2] ); + yyval->PushSubExpression( yyvsp[0] ); + if( yyval->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete yyval; + YYERROR; + } + } + break; + + case 23: /* boolean_expr: value_expr "NOT" CQL2_TOK_BETWEEN value_expr "AND" value_expr */ + { + cql2_expr_node *between = new cql2_expr_node( CQL2_BETWEEN ); + between->PushSubExpression( yyvsp[-5] ); + between->PushSubExpression( yyvsp[-2] ); + between->PushSubExpression( yyvsp[0] ); + + yyval = new cql2_expr_node( CQL2_NOT ); + yyval->PushSubExpression( between ); + if( yyval->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete yyval; + YYERROR; + } + } + break; + + case 24: /* boolean_expr: value_expr "IS" "NULL" */ + { + yyval = new cql2_expr_node( CQL2_IS_NULL ); + yyval->PushSubExpression( yyvsp[-2] ); + if( yyval->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete yyval; + YYERROR; + } + } + break; + + case 25: /* boolean_expr: value_expr "IS" "NOT" "NULL" */ + { + cql2_expr_node *is_null = new cql2_expr_node( CQL2_IS_NULL ); + is_null->PushSubExpression( yyvsp[-3] ); + + yyval = new cql2_expr_node( CQL2_NOT ); + yyval->PushSubExpression( is_null ); + if( yyval->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete yyval; + YYERROR; + } + } + break; + + case 26: /* boolean_expr: "S_INTERSECTS" '(' value_expr ',' value_expr ')' */ + { + yyval = new cql2_expr_node( CQL2_S_INTERSECTS ); + yyval->PushSubExpression( yyvsp[-3] ); + yyval->PushSubExpression( yyvsp[-1] ); + if( yyval->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete yyval; + YYERROR; + } + } + break; + + case 27: /* boolean_expr: "S_EQUALS" '(' value_expr ',' value_expr ')' */ + { + yyval = new cql2_expr_node( CQL2_S_EQUALS ); + yyval->PushSubExpression( yyvsp[-3] ); + yyval->PushSubExpression( yyvsp[-1] ); + if( yyval->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete yyval; + YYERROR; + } + } + break; + + case 28: /* boolean_expr: "S_DISJOINT" '(' value_expr ',' value_expr ')' */ + { + yyval = new cql2_expr_node( CQL2_S_DISJOINT ); + yyval->PushSubExpression( yyvsp[-3] ); + yyval->PushSubExpression( yyvsp[-1] ); + if( yyval->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete yyval; + YYERROR; + } + } + break; + + case 29: /* boolean_expr: "S_TOUCHES" '(' value_expr ',' value_expr ')' */ + { + yyval = new cql2_expr_node( CQL2_S_TOUCHES ); + yyval->PushSubExpression( yyvsp[-3] ); + yyval->PushSubExpression( yyvsp[-1] ); + if( yyval->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete yyval; + YYERROR; + } + } + break; + + case 30: /* boolean_expr: "S_WITHIN" '(' value_expr ',' value_expr ')' */ + { + yyval = new cql2_expr_node( CQL2_S_WITHIN ); + yyval->PushSubExpression( yyvsp[-3] ); + yyval->PushSubExpression( yyvsp[-1] ); + if( yyval->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete yyval; + YYERROR; + } + } + break; + + case 31: /* boolean_expr: "S_OVERLAPS" '(' value_expr ',' value_expr ')' */ + { + yyval = new cql2_expr_node( CQL2_S_OVERLAPS ); + yyval->PushSubExpression( yyvsp[-3] ); + yyval->PushSubExpression( yyvsp[-1] ); + if( yyval->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete yyval; + YYERROR; + } + } + break; + + case 32: /* boolean_expr: "S_CROSSES" '(' value_expr ',' value_expr ')' */ + { + yyval = new cql2_expr_node( CQL2_S_CROSSES ); + yyval->PushSubExpression( yyvsp[-3] ); + yyval->PushSubExpression( yyvsp[-1] ); + if( yyval->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete yyval; + YYERROR; + } + } + break; + + case 33: /* boolean_expr: "S_CONTAINS" '(' value_expr ',' value_expr ')' */ + { + yyval = new cql2_expr_node( CQL2_S_CONTAINS ); + yyval->PushSubExpression( yyvsp[-3] ); + yyval->PushSubExpression( yyvsp[-1] ); + if( yyval->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete yyval; + YYERROR; + } + } + break; + + case 34: /* boolean_expr: '(' boolean_expr ')' */ + { + yyval = yyvsp[-1]; + } + break; + + case 35: /* boolean_expr: "true/false" */ + { + yyval = yyvsp[0]; + } + break; + + case 36: /* value_expr_list: value_expr ',' value_expr_list */ + { + yyval = yyvsp[0]; + yyval->PushSubExpression( yyvsp[-2] ); + if( yyval->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete yyval; + YYERROR; + } + } + break; + + case 37: /* value_expr_list: value_expr */ + { + yyval = new cql2_expr_node( CQL2_ARGUMENT_LIST ); /* temporary value */ + yyval->PushSubExpression( yyvsp[0] ); + if( yyval->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete yyval; + YYERROR; + } + } + break; + + case 39: /* value_expr_or_boolean_literal: "true/false" */ + { + yyval = yyvsp[0]; + } + break; + + case 40: /* value_expr: "integer number" */ + { + yyval = yyvsp[0]; + } + break; + + case 41: /* value_expr: "floating point number" */ + { + yyval = yyvsp[0]; + } + break; + + case 42: /* value_expr: "string" */ + { + yyval = yyvsp[0]; + } + break; + + case 43: /* value_expr: "wkt geometry" */ + { + yyval = yyvsp[0]; + } + break; + + case 44: /* value_expr: "identifier" */ + { + yyval = yyvsp[0]; // validation deferred. + yyval->m_node_type = CQL2_NT_COLUMN; + } + break; + + case 45: /* value_expr: "identifier" '(' value_expr_list ')' */ + { + yyval = yyvsp[-1]; + yyval->m_node_type = CQL2_NT_OPERATION; + yyval->m_op = CQL2_CUSTOM_FUNC; + yyval->m_osVal = yyvsp[-3]->m_osVal; + yyval->ReverseSubExpressions(); + delete yyvsp[-3]; + } + break; + + case 46: /* value_expr: value_expr '+' value_expr */ + { + yyval = new cql2_expr_node( CQL2_ADD ); + yyval->PushSubExpression( yyvsp[-2] ); + yyval->PushSubExpression( yyvsp[0] ); + if( yyval->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete yyval; + YYERROR; + } + } + break; + + case 47: /* value_expr: value_expr '-' value_expr */ + { + yyval = new cql2_expr_node( CQL2_SUBTRACT ); + yyval->PushSubExpression( yyvsp[-2] ); + yyval->PushSubExpression( yyvsp[0] ); + if( yyval->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete yyval; + YYERROR; + } + } + break; + + case 48: /* value_expr: value_expr '*' value_expr */ + { + yyval = new cql2_expr_node( CQL2_MULTIPLY ); + yyval->PushSubExpression( yyvsp[-2] ); + yyval->PushSubExpression( yyvsp[0] ); + if( yyval->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete yyval; + YYERROR; + } + } + break; + + case 49: /* value_expr: value_expr '/' value_expr */ + { + yyval = new cql2_expr_node( CQL2_DIV ); + yyval->PushSubExpression( yyvsp[-2] ); + yyval->PushSubExpression( yyvsp[0] ); + if( yyval->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete yyval; + YYERROR; + } + } + break; + + case 50: /* value_expr: value_expr "DIV" value_expr */ + { + yyval = new cql2_expr_node( CQL2_DIV ); + yyval->PushSubExpression( yyvsp[-2] ); + yyval->PushSubExpression( yyvsp[0] ); + if( yyval->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete yyval; + YYERROR; + } + } + break; + + case 51: /* value_expr: value_expr '%' value_expr */ + { + yyval = new cql2_expr_node( CQL2_MOD ); + yyval->PushSubExpression( yyvsp[-2] ); + yyval->PushSubExpression( yyvsp[0] ); + if( yyval->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete yyval; + YYERROR; + } + } + break; + + case 52: /* value_expr: '-' value_expr */ + { + if (yyvsp[0]->m_node_type == CQL2_NT_CONSTANT ) + { + if( yyvsp[0]->m_field_type == CQL2_INTEGER && + yyvsp[0]->m_nVal == -2147483648 ) + { + yyval = yyvsp[0]; + } + else + { + yyval = yyvsp[0]; + yyval->m_nVal *= -1; + yyval->m_dfVal *= -1; + } + } + else + { + yyval = new cql2_expr_node( CQL2_MULTIPLY ); + yyval->PushSubExpression( new cql2_expr_node(-1) ); + yyval->PushSubExpression( yyvsp[0] ); + if( yyval->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete yyval; + YYERROR; + } + } + } + break; + + case 53: /* value_expr: '(' value_expr ')' */ + { + yyval = yyvsp[-1]; + } + break; + + + + default: break; + } + /* User semantic actions sometimes alter yychar, and that requires + that yytoken be updated with the new translation. We take the + approach of translating immediately before every use of yytoken. + One alternative is translating here after every semantic action, + but that translation would be missed if the semantic action invokes + YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or + if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an + incorrect destructor might then be invoked immediately. In the + case of YYERROR or YYBACKUP, subsequent parser actions might lead + to an incorrect destructor call or verbose syntax error message + before the lookahead is translated. */ + YY_SYMBOL_PRINT ("-> $$ =", YY_CAST (yysymbol_kind_t, yyr1[yyn]), &yyval, &yyloc); + + YYPOPSTACK (yylen); + yylen = 0; + + *++yyvsp = yyval; + + /* Now 'shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + { + const int yylhs = yyr1[yyn] - YYNTOKENS; + const int yyi = yypgoto[yylhs] + *yyssp; + yystate = (0 <= yyi && yyi <= YYLAST && yycheck[yyi] == *yyssp + ? yytable[yyi] + : yydefgoto[yylhs]); + } + + goto yynewstate; + + +/*--------------------------------------. +| yyerrlab -- here on detecting error. | +`--------------------------------------*/ +yyerrlab: + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = yychar == YYEMPTY ? YYSYMBOL_YYEMPTY : YYTRANSLATE (yychar); + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; + { + yypcontext_t yyctx + = {yyssp, yytoken}; + char const *yymsgp = YY_("syntax error"); + int yysyntax_error_status; + yysyntax_error_status = yysyntax_error (&yymsg_alloc, &yymsg, &yyctx); + if (yysyntax_error_status == 0) + yymsgp = yymsg; + else if (yysyntax_error_status == -1) + { + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = YY_CAST (char *, + YYSTACK_ALLOC (YY_CAST (YYSIZE_T, yymsg_alloc))); + if (yymsg) + { + yysyntax_error_status + = yysyntax_error (&yymsg_alloc, &yymsg, &yyctx); + yymsgp = yymsg; + } + else + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + yysyntax_error_status = YYENOMEM; + } + } + yyerror (context, yymsgp); + if (yysyntax_error_status == YYENOMEM) + YYNOMEM; + } + } + + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + if (yychar <= END) + { + /* Return failure if at end of input. */ + if (yychar == END) + YYABORT; + } + else + { + yydestruct ("Error: discarding", + yytoken, &yylval, context); + yychar = YYEMPTY; + } + } + + /* Else will try to reuse lookahead token after shifting the error + token. */ + goto yyerrlab1; + + +/*---------------------------------------------------. +| yyerrorlab -- error raised explicitly by YYERROR. | +`---------------------------------------------------*/ +yyerrorlab: + /* Pacify compilers when the user code never invokes YYERROR and the + label yyerrorlab therefore never appears in user code. */ + if (0) + YYERROR; + ++yynerrs; + + /* Do not reclaim the symbols of the rule whose action triggered + this YYERROR. */ + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + yystate = *yyssp; + goto yyerrlab1; + + +/*-------------------------------------------------------------. +| yyerrlab1 -- common code for both syntax error and YYERROR. | +`-------------------------------------------------------------*/ +yyerrlab1: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + /* Pop stack until we find a state that shifts the error token. */ + for (;;) + { + yyn = yypact[yystate]; + if (!yypact_value_is_default (yyn)) + { + yyn += YYSYMBOL_YYerror; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYSYMBOL_YYerror) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + + yydestruct ("Error: popping", + YY_ACCESSING_SYMBOL (yystate), yyvsp, context); + YYPOPSTACK (1); + yystate = *yyssp; + YY_STACK_PRINT (yyss, yyssp); + } + + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + *++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_END + + + /* Shift the error token. */ + YY_SYMBOL_PRINT ("Shifting", YY_ACCESSING_SYMBOL (yyn), yyvsp, yylsp); + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturnlab; + + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturnlab; + + +/*-----------------------------------------------------------. +| yyexhaustedlab -- YYNOMEM (memory exhaustion) comes here. | +`-----------------------------------------------------------*/ +yyexhaustedlab: + yyerror (context, YY_("memory exhausted")); + yyresult = 2; + goto yyreturnlab; + + +/*----------------------------------------------------------. +| yyreturnlab -- parsing is finished, clean up and return. | +`----------------------------------------------------------*/ +yyreturnlab: + if (yychar != YYEMPTY) + { + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = YYTRANSLATE (yychar); + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval, context); + } + /* Do not reclaim the symbols of the rule whose action triggered + this YYABORT or YYACCEPT. */ + YYPOPSTACK (yylen); + YY_STACK_PRINT (yyss, yyssp); + while (yyssp != yyss) + { + yydestruct ("Cleanup: popping", + YY_ACCESSING_SYMBOL (+*yyssp), yyvsp, context); + YYPOPSTACK (1); + } +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + return yyresult; +} + diff --git a/src/cql2textparser.hpp b/src/cql2textparser.hpp new file mode 100644 index 0000000000..9d4706bde6 --- /dev/null +++ b/src/cql2textparser.hpp @@ -0,0 +1,100 @@ +/* A Bison parser, made by GNU Bison 3.8.2. */ + +/* Bison interface for Yacc-like parsers in C + + Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 Free Software Foundation, + Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual, + especially those whose name start with YY_ or yy_. They are + private implementation details that can be changed or removed. */ + +#ifndef YY_CQL2TEXT_CQL2TEXTPARSER_HPP_INCLUDED +# define YY_CQL2TEXT_CQL2TEXTPARSER_HPP_INCLUDED +/* Debug traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif +#if YYDEBUG +extern int cql2textdebug; +#endif + +/* Token kinds. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + enum yytokentype + { + YYEMPTY = -2, + END = 0, /* "end of string" */ + YYerror = 256, /* error */ + YYUNDEF = 257, /* "invalid token" */ + CQL2_TOK_VALUE_START = 258, /* CQL2_TOK_VALUE_START */ + CQL2_TOK_INTEGER_NUMBER = 259, /* "integer number" */ + CQL2_TOK_DOUBLE_NUMBER = 260, /* "floating point number" */ + CQL2_TOK_STRING = 261, /* "string" */ + CQL2_TOK_IDENTIFIER = 262, /* "identifier" */ + CQL2_TOK_WKT = 263, /* "wkt geometry" */ + CQL2_TOK_NOT = 264, /* "NOT" */ + CQL2_TOK_OR = 265, /* "OR" */ + CQL2_TOK_AND = 266, /* "AND" */ + CQL2_TOK_DIV = 267, /* "DIV" */ + CQL2_TOK_IS = 268, /* "IS" */ + CQL2_TOK_NULL = 269, /* "NULL" */ + CQL2_TOK_BOOLEAN_LITERAL = 270, /* "true/false" */ + CQL2_TOK_CASEI = 271, /* "CASEI" */ + CQL2_TOK_S_INTERSECTS = 272, /* "S_INTERSECTS" */ + CQL2_TOK_S_EQUALS = 273, /* "S_EQUALS" */ + CQL2_TOK_S_DISJOINT = 274, /* "S_DISJOINT" */ + CQL2_TOK_S_TOUCHES = 275, /* "S_TOUCHES" */ + CQL2_TOK_S_WITHIN = 276, /* "S_WITHIN" */ + CQL2_TOK_S_OVERLAPS = 277, /* "S_OVERLAPS" */ + CQL2_TOK_S_CROSSES = 278, /* "S_CROSSES" */ + CQL2_TOK_S_CONTAINS = 279, /* "S_CONTAINS" */ + CQL2_TOK_BETWEEN = 280, /* CQL2_TOK_BETWEEN */ + CQL2_TOK_IN = 281, /* CQL2_TOK_IN */ + CQL2_TOK_LIKE = 282, /* CQL2_TOK_LIKE */ + CQL2_TOK_UMINUS = 283 /* CQL2_TOK_UMINUS */ + }; + typedef enum yytokentype yytoken_kind_t; +#endif + +/* Value type. */ +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef int YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define YYSTYPE_IS_DECLARED 1 +#endif + + + + +int cql2textparse (cql2text_parse_context *context); + + +#endif /* !YY_CQL2TEXT_CQL2TEXTPARSER_HPP_INCLUDED */ diff --git a/src/cql2textparser.y b/src/cql2textparser.y new file mode 100644 index 0000000000..700274a78b --- /dev/null +++ b/src/cql2textparser.y @@ -0,0 +1,688 @@ +%{ +/****************************************************************************** + * + * Project: MapServer + * Purpose: CQL2 text expression parser grammar. + * Requires Bison 3.0.0 or newer to process. Use "cql2textparser" target. + * Author: Even Rouault + * + ****************************************************************************** + * Copyright (C) 2026 Even Rouault + * + * SPDX-License-Identifier: MIT + ****************************************************************************/ + +// Inspired from GDAL SQL parser: https://github.com/OSGeo/gdal/blob/master/ogr/swq_parser.y + +#include "cql2text.h" + +#define YYSTYPE cql2_expr_node * + +/* Defining YYSTYPE_IS_TRIVIAL is needed because the parser is generated as a C++ file. */ +/* See http://www.gnu.org/s/bison/manual/html_node/Memory-Management.html that suggests */ +/* increase YYINITDEPTH instead, but this will consume memory. */ +/* Setting YYSTYPE_IS_TRIVIAL overcomes this limitation, but might be fragile because */ +/* it appears to be a non documented feature of Bison */ +#define YYSTYPE_IS_TRIVIAL 1 +%} + +%define api.pure +%define parse.error verbose +%require "3.0" + +%parse-param {cql2text_parse_context *context} +%lex-param {cql2text_parse_context *context} + +%token CQL2_TOK_VALUE_START + +%token CQL2_TOK_INTEGER_NUMBER "integer number" +%token CQL2_TOK_DOUBLE_NUMBER "floating point number" +%token CQL2_TOK_STRING "string" +%token CQL2_TOK_IDENTIFIER "identifier" +%token CQL2_TOK_WKT "wkt geometry" + +%token END 0 "end of string" + +%token CQL2_TOK_NOT "NOT" +%token CQL2_TOK_OR "OR" +%token CQL2_TOK_AND "AND" + +%token CQL2_TOK_DIV "DIV" + +%token CQL2_TOK_IS "IS" +%token CQL2_TOK_NULL "NULL" + +%token CQL2_TOK_BOOLEAN_LITERAL "true/false" + +%token CQL2_TOK_CASEI "CASEI" + +%token CQL2_TOK_S_INTERSECTS "S_INTERSECTS" +%token CQL2_TOK_S_EQUALS "S_EQUALS" +%token CQL2_TOK_S_DISJOINT "S_DISJOINT" +%token CQL2_TOK_S_TOUCHES "S_TOUCHES" +%token CQL2_TOK_S_WITHIN "S_WITHIN" +%token CQL2_TOK_S_OVERLAPS "S_OVERLAPS" +%token CQL2_TOK_S_CROSSES "S_CROSSES" +%token CQL2_TOK_S_CONTAINS "S_CONTAINS" + +%left CQL2_TOK_OR +%left CQL2_TOK_AND +%left CQL2_TOK_NOT + +%left '=' '<' '>' '!' CQL2_TOK_BETWEEN CQL2_TOK_IN CQL2_TOK_LIKE CQL2_TOK_IS + +%left '+' '-' +%left '*' '/' CQL2_TOK_DIV '%' +%left CQL2_TOK_UMINUS + +/* Any grammar rule that does $$ = must be listed afterwards */ +/* as well as CQL2_TOK_INTEGER_NUMBER CQL2_TOK_DOUBLE_NUMBER CQL2_TOK_STRING CQL2_TOK_IDENTIFIER CQL2_TOK_BOOLEAN_LITERAL that are allocated by cql2textlex(), and identifier */ +%destructor { delete $$; } CQL2_TOK_INTEGER_NUMBER CQL2_TOK_DOUBLE_NUMBER CQL2_TOK_STRING CQL2_TOK_IDENTIFIER CQL2_TOK_WKT CQL2_TOK_BOOLEAN_LITERAL +%destructor { delete $$; } boolean_expr value_expr_or_boolean_literal value_expr value_expr_list + +%% + +input: + | CQL2_TOK_VALUE_START boolean_expr + { + context->poRoot = $2; + } + +boolean_expr: + + boolean_expr CQL2_TOK_AND boolean_expr + { + $$ = cql2_create_and_or_or( CQL2_AND, std::unique_ptr($1), std::unique_ptr($3) ); + if( $$->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete $$; + YYERROR; + } + } + + | boolean_expr CQL2_TOK_OR boolean_expr + { + $$ = cql2_create_and_or_or( CQL2_OR, std::unique_ptr($1), std::unique_ptr($3) ); + if( $$->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete $$; + YYERROR; + } + } + + | CQL2_TOK_NOT boolean_expr + { + $$ = new cql2_expr_node( CQL2_NOT ); + $$->PushSubExpression( $2 ); + if( $$->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete $$; + YYERROR; + } + } + + | value_expr_or_boolean_literal '=' value_expr_or_boolean_literal + { + $$ = new cql2_expr_node( CQL2_EQ ); + $$->PushSubExpression( $1 ); + $$->PushSubExpression( $3 ); + if( $$->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete $$; + YYERROR; + } + } + + | CQL2_TOK_CASEI '(' value_expr ')' '=' CQL2_TOK_CASEI '(' CQL2_TOK_STRING ')' + { + $$ = new cql2_expr_node( CQL2_IEQ); + $$->PushSubExpression( $3 ); + $$->PushSubExpression( $8 ); + if( $$->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete $$; + YYERROR; + } + } + + | value_expr '<' '>' value_expr_or_boolean_literal + { + $$ = new cql2_expr_node( CQL2_NE ); + $$->PushSubExpression( $1 ); + $$->PushSubExpression( $4 ); + if( $$->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete $$; + YYERROR; + } + } + + | CQL2_TOK_BOOLEAN_LITERAL '<' '>' value_expr_or_boolean_literal + { + $$ = new cql2_expr_node( CQL2_NE ); + $$->PushSubExpression( $1 ); + $$->PushSubExpression( $4 ); + if( $$->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete $$; + YYERROR; + } + } + + | CQL2_TOK_CASEI '(' value_expr ')' '<' '>' CQL2_TOK_CASEI '(' CQL2_TOK_STRING ')' + { + $$ = new cql2_expr_node( CQL2_INE); + $$->PushSubExpression( $3 ); + $$->PushSubExpression( $9 ); + if( $$->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete $$; + YYERROR; + } + } + | value_expr '<' value_expr + { + $$ = new cql2_expr_node( CQL2_LT ); + $$->PushSubExpression( $1 ); + $$->PushSubExpression( $3 ); + if( $$->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete $$; + YYERROR; + } + } + + | value_expr '>' value_expr + { + $$ = new cql2_expr_node( CQL2_GT ); + $$->PushSubExpression( $1 ); + $$->PushSubExpression( $3 ); + if( $$->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete $$; + YYERROR; + } + } + + | value_expr '<' '=' value_expr + { + $$ = new cql2_expr_node( CQL2_LE ); + $$->PushSubExpression( $1 ); + $$->PushSubExpression( $4 ); + if( $$->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete $$; + YYERROR; + } + } + + + | value_expr '>' '=' value_expr + { + $$ = new cql2_expr_node( CQL2_GE ); + $$->PushSubExpression( $1 ); + $$->PushSubExpression( $4 ); + if( $$->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete $$; + YYERROR; + } + } + + | value_expr CQL2_TOK_LIKE CQL2_TOK_STRING + { + $$ = new cql2_expr_node( CQL2_LIKE); + $$->PushSubExpression( $1 ); + $$->PushSubExpression( $3 ); + if( $$->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete $$; + YYERROR; + } + } + + | value_expr CQL2_TOK_NOT CQL2_TOK_LIKE CQL2_TOK_STRING + { + cql2_expr_node *like = new cql2_expr_node( CQL2_LIKE ); + like->PushSubExpression( $1 ); + like->PushSubExpression( $4 ); + + $$ = new cql2_expr_node( CQL2_NOT ); + $$->PushSubExpression( like ); + if( $$->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete $$; + YYERROR; + } + } + + | CQL2_TOK_CASEI '(' value_expr ')' CQL2_TOK_LIKE CQL2_TOK_CASEI '(' CQL2_TOK_STRING ')' + { + $$ = new cql2_expr_node( CQL2_ILIKE); + $$->PushSubExpression( $3 ); + $$->PushSubExpression( $8 ); + if( $$->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete $$; + YYERROR; + } + } + + | CQL2_TOK_CASEI '(' value_expr ')' CQL2_TOK_NOT CQL2_TOK_LIKE CQL2_TOK_CASEI '(' CQL2_TOK_STRING ')' + { + cql2_expr_node *like = new cql2_expr_node( CQL2_ILIKE ); + like->PushSubExpression( $3 ); + like->PushSubExpression( $9 ); + + $$ = new cql2_expr_node( CQL2_NOT ); + $$->PushSubExpression( like ); + if( $$->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete $$; + YYERROR; + } + } + + | value_expr CQL2_TOK_IN '(' value_expr_list ')' + { + $$ = $4; + $$->m_field_type = CQL2_BOOLEAN; + $$->m_op = CQL2_IN; + $$->PushSubExpression( $1 ); + $$->ReverseSubExpressions(); + if( $$->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete $$; + YYERROR; + } + } + + | value_expr CQL2_TOK_NOT CQL2_TOK_IN '(' value_expr_list ')' + { + cql2_expr_node *in = $5; + in->m_op = CQL2_IN; + in->PushSubExpression( $1 ); + in->ReverseSubExpressions(); + + $$ = new cql2_expr_node( CQL2_NOT ); + $$->PushSubExpression( in ); + if( $$->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete $$; + YYERROR; + } + } + + | value_expr CQL2_TOK_BETWEEN value_expr CQL2_TOK_AND value_expr + { + $$ = new cql2_expr_node( CQL2_BETWEEN ); + $$->PushSubExpression( $1 ); + $$->PushSubExpression( $3 ); + $$->PushSubExpression( $5 ); + if( $$->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete $$; + YYERROR; + } + } + + | value_expr CQL2_TOK_NOT CQL2_TOK_BETWEEN value_expr CQL2_TOK_AND value_expr + { + cql2_expr_node *between = new cql2_expr_node( CQL2_BETWEEN ); + between->PushSubExpression( $1 ); + between->PushSubExpression( $4 ); + between->PushSubExpression( $6 ); + + $$ = new cql2_expr_node( CQL2_NOT ); + $$->PushSubExpression( between ); + if( $$->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete $$; + YYERROR; + } + } + + | value_expr CQL2_TOK_IS CQL2_TOK_NULL + { + $$ = new cql2_expr_node( CQL2_IS_NULL ); + $$->PushSubExpression( $1 ); + if( $$->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete $$; + YYERROR; + } + } + + | value_expr CQL2_TOK_IS CQL2_TOK_NOT CQL2_TOK_NULL + { + cql2_expr_node *is_null = new cql2_expr_node( CQL2_IS_NULL ); + is_null->PushSubExpression( $1 ); + + $$ = new cql2_expr_node( CQL2_NOT ); + $$->PushSubExpression( is_null ); + if( $$->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete $$; + YYERROR; + } + } + + | CQL2_TOK_S_INTERSECTS '(' value_expr ',' value_expr ')' + { + $$ = new cql2_expr_node( CQL2_S_INTERSECTS ); + $$->PushSubExpression( $3 ); + $$->PushSubExpression( $5 ); + if( $$->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete $$; + YYERROR; + } + } + + | CQL2_TOK_S_EQUALS '(' value_expr ',' value_expr ')' + { + $$ = new cql2_expr_node( CQL2_S_EQUALS ); + $$->PushSubExpression( $3 ); + $$->PushSubExpression( $5 ); + if( $$->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete $$; + YYERROR; + } + } + + | CQL2_TOK_S_DISJOINT '(' value_expr ',' value_expr ')' + { + $$ = new cql2_expr_node( CQL2_S_DISJOINT ); + $$->PushSubExpression( $3 ); + $$->PushSubExpression( $5 ); + if( $$->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete $$; + YYERROR; + } + } + + | CQL2_TOK_S_TOUCHES '(' value_expr ',' value_expr ')' + { + $$ = new cql2_expr_node( CQL2_S_TOUCHES ); + $$->PushSubExpression( $3 ); + $$->PushSubExpression( $5 ); + if( $$->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete $$; + YYERROR; + } + } + + | CQL2_TOK_S_WITHIN '(' value_expr ',' value_expr ')' + { + $$ = new cql2_expr_node( CQL2_S_WITHIN ); + $$->PushSubExpression( $3 ); + $$->PushSubExpression( $5 ); + if( $$->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete $$; + YYERROR; + } + } + + | CQL2_TOK_S_OVERLAPS '(' value_expr ',' value_expr ')' + { + $$ = new cql2_expr_node( CQL2_S_OVERLAPS ); + $$->PushSubExpression( $3 ); + $$->PushSubExpression( $5 ); + if( $$->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete $$; + YYERROR; + } + } + + | CQL2_TOK_S_CROSSES '(' value_expr ',' value_expr ')' + { + $$ = new cql2_expr_node( CQL2_S_CROSSES ); + $$->PushSubExpression( $3 ); + $$->PushSubExpression( $5 ); + if( $$->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete $$; + YYERROR; + } + } + + | CQL2_TOK_S_CONTAINS '(' value_expr ',' value_expr ')' + { + $$ = new cql2_expr_node( CQL2_S_CONTAINS ); + $$->PushSubExpression( $3 ); + $$->PushSubExpression( $5 ); + if( $$->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete $$; + YYERROR; + } + } + + | '(' boolean_expr ')' + { + $$ = $2; + } + + | CQL2_TOK_BOOLEAN_LITERAL + { + $$ = $1; + } + +value_expr_list: + value_expr ',' value_expr_list + { + $$ = $3; + $$->PushSubExpression( $1 ); + if( $$->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete $$; + YYERROR; + } + } + + | value_expr + { + $$ = new cql2_expr_node( CQL2_ARGUMENT_LIST ); /* temporary value */ + $$->PushSubExpression( $1 ); + if( $$->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete $$; + YYERROR; + } + } + +value_expr_or_boolean_literal: + + value_expr + + | CQL2_TOK_BOOLEAN_LITERAL + { + $$ = $1; + } + +value_expr: + CQL2_TOK_INTEGER_NUMBER + { + $$ = $1; + } + + | CQL2_TOK_DOUBLE_NUMBER + { + $$ = $1; + } + + | CQL2_TOK_STRING + { + $$ = $1; + } + + | CQL2_TOK_WKT + { + $$ = $1; + } + + | CQL2_TOK_IDENTIFIER + { + $$ = $1; // validation deferred. + $$->m_node_type = CQL2_NT_COLUMN; + } + + | CQL2_TOK_IDENTIFIER '(' value_expr_list ')' + { + $$ = $3; + $$->m_node_type = CQL2_NT_OPERATION; + $$->m_op = CQL2_CUSTOM_FUNC; + $$->m_osVal = $1->m_osVal; + $$->ReverseSubExpressions(); + delete $1; + } + + | value_expr '+' value_expr + { + $$ = new cql2_expr_node( CQL2_ADD ); + $$->PushSubExpression( $1 ); + $$->PushSubExpression( $3 ); + if( $$->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete $$; + YYERROR; + } + } + + | value_expr '-' value_expr + { + $$ = new cql2_expr_node( CQL2_SUBTRACT ); + $$->PushSubExpression( $1 ); + $$->PushSubExpression( $3 ); + if( $$->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete $$; + YYERROR; + } + } + + | value_expr '*' value_expr + { + $$ = new cql2_expr_node( CQL2_MULTIPLY ); + $$->PushSubExpression( $1 ); + $$->PushSubExpression( $3 ); + if( $$->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete $$; + YYERROR; + } + } + + | value_expr '/' value_expr + { + $$ = new cql2_expr_node( CQL2_DIV ); + $$->PushSubExpression( $1 ); + $$->PushSubExpression( $3 ); + if( $$->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete $$; + YYERROR; + } + } + + | value_expr CQL2_TOK_DIV value_expr + { + $$ = new cql2_expr_node( CQL2_DIV ); + $$->PushSubExpression( $1 ); + $$->PushSubExpression( $3 ); + if( $$->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete $$; + YYERROR; + } + } + + | value_expr '%' value_expr + { + $$ = new cql2_expr_node( CQL2_MOD ); + $$->PushSubExpression( $1 ); + $$->PushSubExpression( $3 ); + if( $$->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete $$; + YYERROR; + } + } + + | '-' value_expr %prec CQL2_TOK_UMINUS + { + if ($2->m_node_type == CQL2_NT_CONSTANT ) + { + if( $2->m_field_type == CQL2_INTEGER && + $2->m_nVal == -2147483648 ) + { + $$ = $2; + } + else + { + $$ = $2; + $$->m_nVal *= -1; + $$->m_dfVal *= -1; + } + } + else + { + $$ = new cql2_expr_node( CQL2_MULTIPLY ); + $$->PushSubExpression( new cql2_expr_node(-1) ); + $$->PushSubExpression( $2 ); + if( $$->HasReachedMaxDepth() ) + { + yyerror (context, "Maximum expression depth reached"); + delete $$; + YYERROR; + } + } + } + + | '(' value_expr ')' + { + $$ = $2; + } diff --git a/dejavu-sans-condensed.h b/src/dejavu-sans-condensed.h similarity index 100% rename from dejavu-sans-condensed.h rename to src/dejavu-sans-condensed.h diff --git a/src/dxfcolor.h b/src/dxfcolor.h new file mode 100644 index 0000000000..1267ae5b6c --- /dev/null +++ b/src/dxfcolor.h @@ -0,0 +1,69 @@ +struct dxfcolor { + int r, g, b; +}; +struct dxfcolor ctable[256] = { + {0, 0, 0}, {255, 0, 0}, {255, 255, 0}, {0, 255, 0}, + {0, 255, 255}, {0, 0, 255}, {255, 0, 255}, {255, 255, 255}, + {128, 128, 128}, {192, 192, 192}, {255, 0, 0}, {255, 127, 127}, + {204, 0, 0}, {204, 102, 102}, {153, 0, 0}, {153, 76, 76}, + {127, 0, 0}, {127, 63, 63}, {76, 0, 0}, {76, 38, 38}, + {255, 63, 0}, {255, 159, 127}, {204, 51, 0}, {204, 127, 102}, + {153, 38, 0}, {153, 95, 76}, {127, 31, 0}, {127, 79, 63}, + {76, 19, 0}, {76, 47, 38}, {255, 127, 0}, {255, 191, 127}, + {204, 102, 0}, {204, 153, 102}, {153, 76, 0}, {153, 114, 76}, + {127, 63, 0}, {127, 95, 63}, {76, 38, 0}, {76, 57, 38}, + {255, 191, 0}, {255, 223, 127}, {204, 153, 0}, {204, 178, 102}, + {153, 114, 0}, {153, 133, 76}, {127, 95, 0}, {127, 111, 63}, + {76, 57, 0}, {76, 66, 38}, {255, 255, 0}, {255, 255, 127}, + {204, 204, 0}, {204, 204, 102}, {153, 153, 0}, {153, 153, 76}, + {127, 127, 0}, {127, 127, 63}, {76, 76, 0}, {76, 76, 38}, + {191, 255, 0}, {223, 255, 127}, {153, 204, 0}, {178, 204, 102}, + {114, 153, 0}, {133, 153, 76}, {95, 127, 0}, {111, 127, 63}, + {57, 76, 0}, {66, 76, 38}, {127, 255, 0}, {191, 255, 127}, + {102, 204, 0}, {153, 204, 102}, {76, 153, 0}, {114, 153, 76}, + {63, 127, 0}, {95, 127, 63}, {38, 76, 0}, {57, 76, 38}, + {63, 255, 0}, {159, 255, 127}, {51, 204, 0}, {127, 204, 102}, + {38, 153, 0}, {95, 153, 76}, {31, 127, 0}, {79, 127, 63}, + {19, 76, 0}, {47, 76, 38}, {0, 255, 0}, {127, 255, 127}, + {0, 204, 0}, {102, 204, 102}, {0, 153, 0}, {76, 153, 76}, + {0, 127, 0}, {63, 127, 63}, {0, 76, 0}, {38, 76, 38}, + {0, 255, 63}, {127, 255, 159}, {0, 204, 51}, {102, 204, 127}, + {0, 153, 38}, {76, 153, 95}, {0, 127, 31}, {63, 127, 79}, + {0, 76, 19}, {38, 76, 47}, {0, 255, 127}, {127, 255, 191}, + {0, 204, 102}, {102, 204, 153}, {0, 153, 76}, {76, 153, 114}, + {0, 127, 63}, {63, 127, 95}, {0, 76, 38}, {38, 76, 57}, + {0, 255, 191}, {127, 255, 223}, {0, 204, 153}, {102, 204, 178}, + {0, 153, 114}, {76, 153, 133}, {0, 127, 95}, {63, 127, 111}, + {0, 76, 57}, {38, 76, 66}, {0, 255, 255}, {127, 255, 255}, + {0, 204, 204}, {102, 204, 204}, {0, 153, 153}, {76, 153, 153}, + {0, 127, 127}, {63, 127, 127}, {0, 76, 76}, {38, 76, 76}, + {0, 191, 255}, {127, 223, 255}, {0, 153, 204}, {102, 178, 204}, + {0, 114, 153}, {76, 133, 153}, {0, 95, 127}, {63, 111, 127}, + {0, 57, 76}, {38, 66, 76}, {0, 127, 255}, {127, 191, 255}, + {0, 102, 204}, {102, 153, 204}, {0, 76, 153}, {76, 114, 153}, + {0, 63, 127}, {63, 95, 127}, {0, 38, 76}, {38, 57, 76}, + {0, 63, 255}, {127, 159, 255}, {0, 51, 204}, {102, 127, 204}, + {0, 38, 153}, {76, 95, 153}, {0, 31, 127}, {63, 79, 127}, + {0, 19, 76}, {38, 47, 76}, {0, 0, 255}, {127, 127, 255}, + {0, 0, 204}, {102, 102, 204}, {0, 0, 153}, {76, 76, 153}, + {0, 0, 127}, {63, 63, 127}, {0, 0, 76}, {38, 38, 76}, + {63, 0, 255}, {159, 127, 255}, {51, 0, 204}, {127, 102, 204}, + {38, 0, 153}, {95, 76, 153}, {31, 0, 127}, {79, 63, 127}, + {19, 0, 76}, {47, 38, 76}, {127, 0, 255}, {191, 127, 255}, + {102, 0, 204}, {153, 102, 204}, {76, 0, 153}, {114, 76, 153}, + {63, 0, 127}, {95, 63, 127}, {38, 0, 76}, {57, 38, 76}, + {191, 0, 255}, {223, 127, 255}, {153, 0, 204}, {178, 102, 204}, + {114, 0, 153}, {133, 76, 153}, {95, 0, 127}, {111, 63, 127}, + {57, 0, 76}, {66, 38, 76}, {255, 0, 255}, {255, 127, 255}, + {204, 0, 204}, {204, 102, 204}, {153, 0, 153}, {153, 76, 153}, + {127, 0, 127}, {127, 63, 127}, {76, 0, 76}, {76, 38, 76}, + {255, 0, 191}, {255, 127, 223}, {204, 0, 153}, {204, 102, 178}, + {153, 0, 114}, {153, 76, 133}, {127, 0, 95}, {127, 63, 111}, + {76, 0, 57}, {76, 38, 66}, {255, 0, 127}, {255, 127, 191}, + {204, 0, 102}, {204, 102, 153}, {153, 0, 76}, {153, 76, 114}, + {127, 0, 63}, {127, 63, 95}, {76, 0, 38}, {76, 38, 57}, + {255, 0, 63}, {255, 127, 159}, {204, 0, 51}, {204, 102, 127}, + {153, 0, 38}, {153, 76, 95}, {127, 0, 31}, {127, 63, 79}, + {76, 0, 19}, {76, 38, 47}, {51, 51, 51}, {91, 91, 91}, + {132, 132, 132}, {173, 173, 173}, {214, 214, 214}, {255, 255, 255}, +}; diff --git a/src/flatgeobuf/LICENSE b/src/flatgeobuf/LICENSE new file mode 100644 index 0000000000..acd7d34a38 --- /dev/null +++ b/src/flatgeobuf/LICENSE @@ -0,0 +1,9 @@ +Copyright (c) 2018, Björn Harrtell + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/src/flatgeobuf/feature_generated.h b/src/flatgeobuf/feature_generated.h new file mode 100644 index 0000000000..c39a18f192 --- /dev/null +++ b/src/flatgeobuf/feature_generated.h @@ -0,0 +1,287 @@ +// automatically generated by the FlatBuffers compiler, do not modify + + +#ifndef FLATBUFFERS_GENERATED_FEATURE_FLATGEOBUF_H_ +#define FLATBUFFERS_GENERATED_FEATURE_FLATGEOBUF_H_ + +#include "flatbuffers/flatbuffers.h" + +// Ensure the included flatbuffers.h is the same version as when this file was +// generated, otherwise it may not be compatible. +static_assert(FLATBUFFERS_VERSION_MAJOR == 2 && + FLATBUFFERS_VERSION_MINOR == 0 && + FLATBUFFERS_VERSION_REVISION == 6, + "Non-compatible flatbuffers version included"); + +#include "header_generated.h" + +namespace mapserver { +namespace FlatGeobuf { + +struct Geometry; +struct GeometryBuilder; + +struct Feature; +struct FeatureBuilder; + +struct Geometry FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef GeometryBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_ENDS = 4, + VT_XY = 6, + VT_Z = 8, + VT_M = 10, + VT_T = 12, + VT_TM = 14, + VT_TYPE = 16, + VT_PARTS = 18 + }; + const flatbuffers::Vector *ends() const { + return GetPointer *>(VT_ENDS); + } + const flatbuffers::Vector *xy() const { + return GetPointer *>(VT_XY); + } + const flatbuffers::Vector *z() const { + return GetPointer *>(VT_Z); + } + const flatbuffers::Vector *m() const { + return GetPointer *>(VT_M); + } + const flatbuffers::Vector *t() const { + return GetPointer *>(VT_T); + } + const flatbuffers::Vector *tm() const { + return GetPointer *>(VT_TM); + } + FlatGeobuf::GeometryType type() const { + return static_cast(GetField(VT_TYPE, 0)); + } + const flatbuffers::Vector> *parts() const { + return GetPointer> *>(VT_PARTS); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffset(verifier, VT_ENDS) && + verifier.VerifyVector(ends()) && + VerifyOffset(verifier, VT_XY) && + verifier.VerifyVector(xy()) && + VerifyOffset(verifier, VT_Z) && + verifier.VerifyVector(z()) && + VerifyOffset(verifier, VT_M) && + verifier.VerifyVector(m()) && + VerifyOffset(verifier, VT_T) && + verifier.VerifyVector(t()) && + VerifyOffset(verifier, VT_TM) && + verifier.VerifyVector(tm()) && + VerifyField(verifier, VT_TYPE, 1) && + VerifyOffset(verifier, VT_PARTS) && + verifier.VerifyVector(parts()) && + verifier.VerifyVectorOfTables(parts()) && + verifier.EndTable(); + } +}; + +struct GeometryBuilder { + typedef Geometry Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_ends(flatbuffers::Offset> ends) { + fbb_.AddOffset(Geometry::VT_ENDS, ends); + } + void add_xy(flatbuffers::Offset> xy) { + fbb_.AddOffset(Geometry::VT_XY, xy); + } + void add_z(flatbuffers::Offset> z) { + fbb_.AddOffset(Geometry::VT_Z, z); + } + void add_m(flatbuffers::Offset> m) { + fbb_.AddOffset(Geometry::VT_M, m); + } + void add_t(flatbuffers::Offset> t) { + fbb_.AddOffset(Geometry::VT_T, t); + } + void add_tm(flatbuffers::Offset> tm) { + fbb_.AddOffset(Geometry::VT_TM, tm); + } + void add_type(FlatGeobuf::GeometryType type) { + fbb_.AddElement(Geometry::VT_TYPE, static_cast(type), 0); + } + void add_parts(flatbuffers::Offset>> parts) { + fbb_.AddOffset(Geometry::VT_PARTS, parts); + } + explicit GeometryBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateGeometry( + flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset> ends = 0, + flatbuffers::Offset> xy = 0, + flatbuffers::Offset> z = 0, + flatbuffers::Offset> m = 0, + flatbuffers::Offset> t = 0, + flatbuffers::Offset> tm = 0, + FlatGeobuf::GeometryType type = FlatGeobuf::GeometryType::Unknown, + flatbuffers::Offset>> parts = 0) { + GeometryBuilder builder_(_fbb); + builder_.add_parts(parts); + builder_.add_tm(tm); + builder_.add_t(t); + builder_.add_m(m); + builder_.add_z(z); + builder_.add_xy(xy); + builder_.add_ends(ends); + builder_.add_type(type); + return builder_.Finish(); +} + +inline flatbuffers::Offset CreateGeometryDirect( + flatbuffers::FlatBufferBuilder &_fbb, + const std::vector *ends = nullptr, + const std::vector *xy = nullptr, + const std::vector *z = nullptr, + const std::vector *m = nullptr, + const std::vector *t = nullptr, + const std::vector *tm = nullptr, + FlatGeobuf::GeometryType type = FlatGeobuf::GeometryType::Unknown, + const std::vector> *parts = nullptr) { + auto ends__ = ends ? _fbb.CreateVector(*ends) : 0; + auto xy__ = xy ? _fbb.CreateVector(*xy) : 0; + auto z__ = z ? _fbb.CreateVector(*z) : 0; + auto m__ = m ? _fbb.CreateVector(*m) : 0; + auto t__ = t ? _fbb.CreateVector(*t) : 0; + auto tm__ = tm ? _fbb.CreateVector(*tm) : 0; + auto parts__ = parts ? _fbb.CreateVector>(*parts) : 0; + return FlatGeobuf::CreateGeometry( + _fbb, + ends__, + xy__, + z__, + m__, + t__, + tm__, + type, + parts__); +} + +struct Feature FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef FeatureBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_GEOMETRY = 4, + VT_PROPERTIES = 6, + VT_COLUMNS = 8 + }; + const FlatGeobuf::Geometry *geometry() const { + return GetPointer(VT_GEOMETRY); + } + const flatbuffers::Vector *properties() const { + return GetPointer *>(VT_PROPERTIES); + } + const flatbuffers::Vector> *columns() const { + return GetPointer> *>(VT_COLUMNS); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffset(verifier, VT_GEOMETRY) && + verifier.VerifyTable(geometry()) && + VerifyOffset(verifier, VT_PROPERTIES) && + verifier.VerifyVector(properties()) && + VerifyOffset(verifier, VT_COLUMNS) && + verifier.VerifyVector(columns()) && + verifier.VerifyVectorOfTables(columns()) && + verifier.EndTable(); + } +}; + +struct FeatureBuilder { + typedef Feature Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_geometry(flatbuffers::Offset geometry) { + fbb_.AddOffset(Feature::VT_GEOMETRY, geometry); + } + void add_properties(flatbuffers::Offset> properties) { + fbb_.AddOffset(Feature::VT_PROPERTIES, properties); + } + void add_columns(flatbuffers::Offset>> columns) { + fbb_.AddOffset(Feature::VT_COLUMNS, columns); + } + explicit FeatureBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateFeature( + flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset geometry = 0, + flatbuffers::Offset> properties = 0, + flatbuffers::Offset>> columns = 0) { + FeatureBuilder builder_(_fbb); + builder_.add_columns(columns); + builder_.add_properties(properties); + builder_.add_geometry(geometry); + return builder_.Finish(); +} + +inline flatbuffers::Offset CreateFeatureDirect( + flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset geometry = 0, + const std::vector *properties = nullptr, + const std::vector> *columns = nullptr) { + auto properties__ = properties ? _fbb.CreateVector(*properties) : 0; + auto columns__ = columns ? _fbb.CreateVector>(*columns) : 0; + return FlatGeobuf::CreateFeature( + _fbb, + geometry, + properties__, + columns__); +} + +inline const FlatGeobuf::Feature *GetFeature(const void *buf) { + return flatbuffers::GetRoot(buf); +} + +inline const FlatGeobuf::Feature *GetSizePrefixedFeature(const void *buf) { + return flatbuffers::GetSizePrefixedRoot(buf); +} + +inline bool VerifyFeatureBuffer( + flatbuffers::Verifier &verifier) { + return verifier.VerifyBuffer(nullptr); +} + +inline bool VerifySizePrefixedFeatureBuffer( + flatbuffers::Verifier &verifier) { + return verifier.VerifySizePrefixedBuffer(nullptr); +} + +inline void FinishFeatureBuffer( + flatbuffers::FlatBufferBuilder &fbb, + flatbuffers::Offset root) { + fbb.Finish(root); +} + +inline void FinishSizePrefixedFeatureBuffer( + flatbuffers::FlatBufferBuilder &fbb, + flatbuffers::Offset root) { + fbb.FinishSizePrefixed(root); +} + +} // namespace FlatGeobuf +} + +#endif // FLATBUFFERS_GENERATED_FEATURE_FLATGEOBUF_H_ diff --git a/src/flatgeobuf/flatgeobuf_c.cpp b/src/flatgeobuf/flatgeobuf_c.cpp new file mode 100644 index 0000000000..ff783244ec --- /dev/null +++ b/src/flatgeobuf/flatgeobuf_c.cpp @@ -0,0 +1,399 @@ +#include "flatgeobuf_c.h" + +#include "feature_generated.h" +#include "geometryreader.h" +#include "packedrtree.h" +#include + +using namespace mapserver::flatbuffers; +using namespace mapserver::FlatGeobuf; + +typedef flatgeobuf_ctx ctx; + +uint8_t flatgeobuf_magicbytes[] = { 0x66, 0x67, 0x62, 0x03, 0x66, 0x67, 0x62, 0x01 }; +uint8_t FLATGEOBUF_MAGICBYTES_SIZE = sizeof(flatgeobuf_magicbytes); +uint32_t INIT_BUFFER_SIZE = 1024 * 4; + +template +void parse_value(uint8_t *data, char **values, uint16_t i, uint32_t &offset, bool found) +{ + using std::to_string; + if (found) + { + msFree(values[i]); + values[i] = msStrdup(to_string(*((T*) (data + offset))).c_str()); + } + offset += sizeof(T); +} + +ctx *flatgeobuf_init_ctx() +{ + ctx *c = (ctx *) malloc(sizeof(ctx)); + memset(c, 0, sizeof(ctx)); + c->is_null_geom = false; + c->done = false; + return c; +} + +void flatgeobuf_free_ctx(ctx *ctx) +{ + if (ctx->columns) { + for (uint32_t i = 0; i < ctx->columns_len; i++) + free(ctx->columns[i].name); + free(ctx->columns); + } + if (ctx->search_result) + free(ctx->search_result); + if (ctx->buf) + free(ctx->buf); + if (ctx->wkt) + free(ctx->wkt); + free(ctx); +} + +void flatgeobuf_ensure_line(ctx *ctx, uint32_t len) +{ + if (!ctx->line) { + ctx->line_len = len; + ctx->line = (lineObj *) malloc(ctx->line_len * sizeof(lineObj)); + return; + } + if (ctx->line_len < len) { + ctx->line_len = len; + ctx->line = (lineObj *) realloc(ctx->buf, ctx->line_len * sizeof(lineObj)); + } +} + +void flatgeobuf_ensure_point(ctx *ctx, uint32_t len) +{ + if (!ctx->point) { + ctx->point_len = len; + ctx->point = (pointObj *) malloc(ctx->point_len * sizeof(pointObj)); + return; + } + if (ctx->point_len < len) { + ctx->point_len = len; + ctx->point = (pointObj *) realloc(ctx->buf, ctx->point_len * sizeof(pointObj)); + } +} + +int flatgeobuf_ensure_buf(ctx *ctx, uint32_t size) +{ + if (size > 100 * 1024 * 1024) { + msSetError(MS_FGBERR, "Invalid buffer size requested", "flatgeobuf_ensure_buf"); + return -1; + } + if (!ctx->buf) { + ctx->buf_size = std::max(INIT_BUFFER_SIZE, size); + ctx->buf = (uint8_t *) malloc(ctx->buf_size); + if (ctx->buf == NULL) { + msSetError(MS_FGBERR, "Failed to allocate buffer", "flatgeobuf_ensure_buf"); + return -1; + } + return 0; + } + if (ctx->buf_size < size) { + ctx->buf_size = std::max(ctx->buf_size * 2, size); + auto buf = (uint8_t *) realloc(ctx->buf, ctx->buf_size); + if (buf == NULL) { + msSetError(MS_FGBERR, "Failed to reallocate buffer", "flatgeobuf_ensure_buf"); + return -1; + } + ctx->buf = buf; + } + return 0; +} + +int flatgeobuf_decode_feature(ctx *ctx, layerObj *layer, shapeObj *shape) +{ + ctx->is_null_geom = false; + + uint32_t featureSize; + if (VSIFReadL(&featureSize, sizeof(featureSize), 1, ctx->file) != 1) { + if (VSIFEofL(ctx->file)) { + ctx->done = true; + return 0; + } + return -1; + } + + ctx->offset += sizeof(uoffset_t); + if (flatgeobuf_ensure_buf(ctx, featureSize) != 0) { + return -1; + } + + if (VSIFReadL(ctx->buf, 1, featureSize, ctx->file) != featureSize) { + msSetError(MS_FGBERR, "Failed to read feature", "flatgeobuf_decode_feature"); + return -1; + } + ctx->offset += featureSize; + auto feature = GetFeature(ctx->buf); + const auto geometry = feature->geometry(); + if (geometry) { + GeometryReader(ctx, geometry).read(shape); + } else { + ctx->is_null_geom = true; + return 0; + } + auto properties = feature->properties(); + if (properties && properties->size() != 0) { + ctx->properties = (uint8_t *) properties->data(); + ctx->properties_size = properties->size(); + flatgeobuf_decode_properties(ctx, layer, shape); + } else { + ctx->properties_size = 0; + } + + return 0; +} + +int flatgeobuf_decode_properties(ctx *ctx, layerObj *layer, shapeObj *shape) +{ + uint8_t type; + uint32_t offset = 0; + uint8_t *data = ctx->properties; + uint32_t size = ctx->properties_size; + uint16_t numvalues = layer->numitems; + bool found; + char **values; + + if (numvalues == 0) + return 0; + + values = (char **) msSmallCalloc(sizeof(char *), numvalues); + if (shape->values) msFreeCharArray(shape->values, shape->numvalues); + shape->numvalues = numvalues; + shape->values = values; + + if (size > 0 && size < (sizeof(uint16_t) + sizeof(uint8_t))) { + msSetError(MS_FGBERR, "Unexpected properties data size", "flatgeobuf_decode_properties"); + return -1; + } + while (offset + 1 < size) { + uint16_t i; + memcpy(&i, data + offset, sizeof(uint16_t)); + offset += sizeof(uint16_t); + if (i >= ctx->columns_len) { + msSetError(MS_FGBERR, "Column index out of range", "flatgeobuf_decode_properties"); + return -1; + } + const auto& column = ctx->columns[i]; + const int32_t ii = column.itemindex; + found = ii != -1; + type = column.type; + switch (type) { + case flatgeobuf_column_type_bool: + parse_value(data, values, ii, offset, found); + break; + case flatgeobuf_column_type_byte: + parse_value(data, values, ii, offset, found); + break; + case flatgeobuf_column_type_ubyte: + parse_value(data, values, ii, offset, found); + break; + case flatgeobuf_column_type_short: + parse_value(data, values, ii, offset, found); + break; + case flatgeobuf_column_type_ushort: + parse_value(data, values, ii, offset, found); + break; + case flatgeobuf_column_type_int: + parse_value(data, values, ii, offset, found); + break; + case flatgeobuf_column_type_uint: + parse_value(data, values, ii, offset, found); + break; + case flatgeobuf_column_type_long: + parse_value(data, values, ii, offset, found); + break; + case flatgeobuf_column_type_ulong: + parse_value(data, values, ii, offset, found); + break; + case flatgeobuf_column_type_float: + parse_value(data, values, ii, offset, found); + break; + case flatgeobuf_column_type_double: + parse_value(data, values, ii, offset, found); + break; + case flatgeobuf_column_type_datetime: + case flatgeobuf_column_type_string: { + uint32_t len; + if (offset + sizeof(len) > size){ + msSetError(MS_FGBERR, "Invalid size for string value", "flatgeobuf_decode_properties"); + return -1; + } + memcpy(&len, data + offset, sizeof(uint32_t)); + offset += sizeof(len); + if (found) { + char *str = (char *) msSmallMalloc(len + 1); + memcpy(str, data + offset, len); + str[len] = '\0'; + msFree(values[ii]); + values[ii] = str; + } + offset += len; + break; + } + } + } + + for(int i = 0; i < shape->numvalues; i++) + { + if( shape->values[i] == NULL) + shape->values[i] = msStrdup(""); + } + + return 0; +} + +int flatgeobuf_check_magicbytes(ctx *ctx) +{ + if (ctx->offset != 0) { + msSetError(MS_FGBERR, "Unexpected offset", "flatgeobuf_check_magicbytes"); + return -1; + } + if (flatgeobuf_ensure_buf(ctx, FLATGEOBUF_MAGICBYTES_SIZE) != 0) + return -1; + if (VSIFReadL(ctx->buf, 8, 1, ctx->file) != 1) { + msSetError(MS_FGBERR, "Failed to read magicbytes", "flatgeobuf_check_magicbytes"); + return -1; + } + uint32_t i; + for (i = 0; i < FLATGEOBUF_MAGICBYTES_SIZE / 2; i++) { + if (ctx->buf[i] != flatgeobuf_magicbytes[i]) { + msSetError(MS_FGBERR, "Data is not FlatGeobuf", "flatgeobuf_check_magicbytes"); + return -1; + } + } + ctx->offset += FLATGEOBUF_MAGICBYTES_SIZE; + return 0; +} + +int flatgeobuf_decode_header(ctx *ctx) +{ + if (ctx->offset != FLATGEOBUF_MAGICBYTES_SIZE) { + msSetError(MS_FGBERR, "Unexpected offset", "flatgeobuf_decode_header"); + return -1; + } + if (VSIFSeekL(ctx->file, ctx->offset, SEEK_SET) == -1) { + msSetError(MS_FGBERR, "Unable to get seek in file", "flatgeobuf_decode_header"); + return -1; + } + uint32_t headerSize; + if (VSIFReadL(&headerSize, 4, 1, ctx->file) != 1) { + msSetError(MS_FGBERR, "Failed to read header size", "flatgeobuf_decode_header"); + return -1; + } + ctx->offset += sizeof(uoffset_t); + if (flatgeobuf_ensure_buf(ctx, headerSize) != 0) { + return -1; + } + if (VSIFReadL(ctx->buf, 1, headerSize, ctx->file) != headerSize) { + msSetError(MS_FGBERR, "Failed to read header", "flatgeobuf_decode_header"); + return -1; + } + auto header = GetHeader(ctx->buf); + ctx->offset += headerSize; + + ctx->geometry_type = (uint8_t) header->geometry_type(); + ctx->features_count = header->features_count(); + auto envelope = header->envelope(); + if (envelope != nullptr) { + ctx->has_extent = true; + ctx->xmin = envelope->Get(0); + ctx->ymin = envelope->Get(1); + ctx->xmax = envelope->Get(2); + ctx->ymax = envelope->Get(3); + ctx->bounds.minx = ctx->xmin; + ctx->bounds.miny = ctx->ymin; + ctx->bounds.maxx = ctx->xmax; + ctx->bounds.maxy = ctx->ymax; + } + ctx->has_z = header->has_z(); + ctx->has_m = header->has_m(); + ctx->has_t = header->has_t(); + ctx->has_tm = header->has_tm(); + ctx->index_node_size = header->index_node_size(); + auto crs = header->crs(); + if (crs != nullptr) { + ctx->srid = crs->code(); + auto wkt = crs->wkt(); + if (wkt != nullptr) + ctx->wkt = msStrdup(wkt->c_str()); + } + auto columns = header->columns(); + if (columns != nullptr) { + auto size = columns->size(); + ctx->columns = (flatgeobuf_column *) malloc(size * sizeof(flatgeobuf_column)); + memset(ctx->columns, 0, size * sizeof(flatgeobuf_column)); + ctx->columns_len = size; + for (uint32_t i = 0; i < size; i++) { + auto column = columns->Get(i); + ctx->columns[i].name = msStrdup(column->name()->c_str()); + ctx->columns[i].type = (uint8_t) column->type(); + ctx->columns[i].itemindex = -1; + } + } + + ctx->index_offset = ctx->offset; + ctx->feature_offset = ctx->offset; + if ( ctx->index_node_size > 0) + ctx->feature_offset += PackedRTree::size(ctx->features_count, ctx->index_node_size); + + return 0; +} + +int flatgeobuf_index_search(ctx *ctx, rectObj *rect) +{ + const auto treeOffset = ctx->offset; + const auto readNode = [treeOffset, ctx] (uint8_t *buf, size_t i, size_t s) { + if (VSIFSeekL(ctx->file, treeOffset + i, SEEK_SET) == -1) + throw std::runtime_error("Unable to seek in file"); + if (VSIFReadL(buf, 1, s, ctx->file) != s) + throw std::runtime_error("Unable to read file"); + }; + NodeItem n { rect->minx, rect->miny, rect->maxx, rect->maxy, 0 }; + try { + const auto foundItems = PackedRTree::streamSearch(ctx->features_count, ctx->index_node_size, n, readNode); + ctx->search_result = (flatgeobuf_search_item *) malloc(foundItems.size() * sizeof(flatgeobuf_search_item)); + memcpy(ctx->search_result, foundItems.data(), foundItems.size() * sizeof(flatgeobuf_search_item)); + ctx->search_result_len = (uint32_t) foundItems.size(); + } catch (const std::exception &e) { + msSetError(MS_FGBERR, "Unable to seek or read file", "flatgeobuf_index_search"); + return -1; + } + return 0; +} + +int flatgeobuf_index_skip(ctx *ctx) +{ + auto treeSize = PackedRTree::size(ctx->features_count, ctx->index_node_size); + ctx->offset += treeSize; + if (VSIFSeekL(ctx->file, ctx->offset, SEEK_SET) == -1) { + msSetError(MS_FGBERR, "Unable to seek in file", "flatgeobuf_index_skip"); + return -1; + } + return 0; +} + +int flatgeobuf_read_feature_offset(ctx *ctx, uint64_t index, uint64_t *featureOffset) +{ + try { + const auto levelBounds = PackedRTree::generateLevelBounds(ctx->features_count, ctx->index_node_size); + const auto bottomLevelOffset = ctx->index_offset + (levelBounds.front().first * sizeof(NodeItem)); + const auto nodeItemOffset = bottomLevelOffset + (index * sizeof(NodeItem)); + const auto featureOffsetOffset = nodeItemOffset + (sizeof(double) * 4); + if (VSIFSeekL(ctx->file, featureOffsetOffset, SEEK_SET) == -1) { + msSetError(MS_FGBERR, "Failed to seek feature offset", "flatgeobuf_read_feature_offset"); + return -1; + } + if (VSIFReadL(featureOffset, sizeof(uint64_t), 1, ctx->file) != 1) { + msSetError(MS_FGBERR, "Failed to read feature offset", "flatgeobuf_read_feature_offset"); + return -1; + } + return 0; + } catch (const std::exception& e) { + msSetError(MS_FGBERR, "Failed to calculate tree size", "flatgeobuf_read_feature_offset"); + return -1; + } +} diff --git a/src/flatgeobuf/flatgeobuf_c.h b/src/flatgeobuf/flatgeobuf_c.h new file mode 100644 index 0000000000..32d804ac12 --- /dev/null +++ b/src/flatgeobuf/flatgeobuf_c.h @@ -0,0 +1,136 @@ +#ifndef FLATGEOBUF_C_H +#define FLATGEOBUF_C_H + +#include "../../mapserver.h" +#include "../../maperror.h" +#include "../../mapprimitive.h" +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern uint8_t flatgeobuf_magicbytes[]; +extern uint8_t FLATGEOBUF_MAGICBYTES_SIZE; + +// need c compatible variant of this enum +#define flatgeobuf_column_type_byte UINT8_C(0) +#define flatgeobuf_column_type_ubyte UINT8_C(1) +#define flatgeobuf_column_type_bool UINT8_C(2) +#define flatgeobuf_column_type_short UINT8_C(3) +#define flatgeobuf_column_type_ushort UINT8_C(4) +#define flatgeobuf_column_type_int UINT8_C(5) +#define flatgeobuf_column_type_uint UINT8_C(6) +#define flatgeobuf_column_type_long UINT8_C(7) +#define flatgeobuf_column_type_ulong UINT8_C(8) +#define flatgeobuf_column_type_float UINT8_C(9) +#define flatgeobuf_column_type_double UINT8_C(10) +#define flatgeobuf_column_type_string UINT8_C(11) +#define flatgeobuf_column_type_json UINT8_C(12) +#define flatgeobuf_column_type_datetime UINT8_C(13) +#define flatgeobuf_column_type_binary UINT8_C(14) + +typedef struct flatgeobuf_column +{ + char *name; + uint8_t type; + const char *title; + const char *description; + uint32_t width; + uint32_t precision; + uint32_t scale; + bool nullable; + bool unique; + bool primary_key; + const char * metadata; + int32_t itemindex; +} flatgeobuf_column; + +typedef struct flatgeobuf_item +{ + double xmin; + double xmax; + double ymin; + double ymax; + uint32_t size; + uint64_t offset; +} flatgeobuf_item; + +typedef struct flatgeobuf_search_item { + uint64_t offset; + uint64_t index; +} flatgeobuf_search_item; + +typedef struct flatgeobuf_ctx +{ + VSILFILE *file; + uint64_t index_offset; + uint64_t feature_offset; + uint64_t offset; + uint8_t *buf; + uint32_t buf_size; + bool done; + + // header contents + const char *name; + uint64_t features_count; + uint8_t geometry_type; + bool has_extent; + double xmin; + double xmax; + double ymin; + double ymax; + bool has_z; + bool has_m; + bool has_t; + bool has_tm; + uint16_t index_node_size; + int32_t srid; + char *wkt; + flatgeobuf_column *columns; + uint16_t columns_len; + + // mapserver structs + rectObj bounds; + + // index search result + flatgeobuf_search_item *search_result; + uint32_t search_result_len; + uint32_t search_index; + + // shape parts buffers + // NOTE: not used at this time, need to introduce optional free in mapdraw + lineObj *line; + uint32_t line_len; + pointObj *point; + uint32_t point_len; + + bool is_null_geom; + uint64_t feature_index; + int ms_type; + uint8_t *properties; + uint32_t properties_size; +} flatgeobuf_ctx; + +flatgeobuf_ctx *flatgeobuf_init_ctx(); +void flatgeobuf_free_ctx(flatgeobuf_ctx *ctx); + +int flatgeobuf_ensure_buf(flatgeobuf_ctx *ctx, uint32_t size); +void flatgeobuf_ensure_line(flatgeobuf_ctx *ctx, uint32_t len); +void flatgeobuf_ensure_point(flatgeobuf_ctx *ctx, uint32_t len); + +int flatgeobuf_check_magicbytes(flatgeobuf_ctx *ctx); +int flatgeobuf_decode_header(flatgeobuf_ctx *ctx); +int flatgeobuf_decode_feature(flatgeobuf_ctx *ctx, layerObj *layer, shapeObj *shape); +int flatgeobuf_decode_properties(flatgeobuf_ctx *ctx, layerObj *layer, shapeObj *shape); + +int flatgeobuf_index_search(flatgeobuf_ctx *ctx, rectObj *rect); +int flatgeobuf_index_skip(flatgeobuf_ctx *ctx); +int flatgeobuf_read_feature_offset(flatgeobuf_ctx *ctx, uint64_t index, uint64_t *featureOffset); + +#ifdef __cplusplus +} +#endif + +#endif /* FLATGEOBUF_C_H */ diff --git a/src/flatgeobuf/geometryreader.cpp b/src/flatgeobuf/geometryreader.cpp new file mode 100644 index 0000000000..9f485a9e9c --- /dev/null +++ b/src/flatgeobuf/geometryreader.cpp @@ -0,0 +1,150 @@ +#include "geometryreader.h" + +using namespace mapserver::flatbuffers; +using namespace mapserver::FlatGeobuf; + +void GeometryReader::readPoint(shapeObj *shape) +{ + lineObj *l = (lineObj *) malloc(sizeof(lineObj)); + pointObj *p = (pointObj *) malloc(sizeof(pointObj)); + + p->x = m_xy[m_offset + 0]; + p->y = m_xy[m_offset + 1]; + if (m_has_z) + p->z = m_geometry->z()->data()[m_offset]; + if (m_has_m) + p->m = m_geometry->m()->data()[m_offset]; + + l[0].numpoints = 1; + l[0].point = p; + shape->numlines = 1; + shape->line = l; + shape->type = MS_SHAPE_POINT; +} + +void GeometryReader::readLineObj(lineObj *line) +{ + const double *z = m_has_z ? m_geometry->z()->data() : nullptr; + const double *m = m_has_m ? m_geometry->m()->data() : nullptr; + + line->point = (pointObj *) malloc(m_length * sizeof(pointObj)); + line->numpoints = m_length; + + for (uint32_t i = m_offset; i < m_offset + m_length; i++) { + pointObj *point = &line->point[i - m_offset]; + memcpy(point, &m_xy[i * 2], 2 * sizeof(double)); + if (m_has_z) + point->z = z[i]; + if (m_has_m) + point->m = m[i]; + } +} + +void GeometryReader::readMultiPoint(shapeObj *shape) +{ + readLineString(shape); + shape->type = MS_SHAPE_POINT; +} + +void GeometryReader::readLineString(shapeObj *shape) +{ + lineObj *line = (lineObj *) malloc(sizeof(lineObj)); + readLineObj(line); + shape->numlines = 1; + shape->line = line; + shape->type = MS_SHAPE_LINE; +} + +void GeometryReader::readMultiLineString(shapeObj *shape) +{ + readPolygon(shape); + shape->type = MS_SHAPE_LINE; +} + +void GeometryReader::readPolygon(shapeObj *shape) +{ + const auto ends = m_geometry->ends(); + + uint32_t nrings = 1; + if (ends != nullptr && ends->size() > 1) + nrings = ends->size(); + + lineObj *line = (lineObj *) malloc(nrings * sizeof(lineObj)); + if (nrings > 1) { + for (uint32_t i = 0; i < nrings; i++) { + const auto e = ends->Get(i); + m_length = e - m_offset; + readLineObj(&line[i]); + m_offset = e; + } + } else { + readLineObj(line); + } + shape->numlines = nrings; + shape->line = line; + shape->type = MS_SHAPE_POLYGON; +} + +void GeometryReader::readMultiPolygon(shapeObj *shape) +{ + const auto parts = m_geometry->parts(); + lineObj *line = (lineObj *) nullptr; + auto numlines = 0; + for (size_t i = 0; i < parts->size(); i++) { + GeometryReader(m_ctx, parts->Get(i), GeometryType::Polygon).read(shape); + lineObj *tmp = line; + line = (lineObj *) realloc(line, (numlines + shape->numlines) * sizeof(lineObj)); + if (!line) { + free(tmp); + free(shape->line); + break; + } + for (int j = 0; j < shape->numlines; j++) + line[numlines + j] = shape->line[j]; + numlines += shape->numlines; + free(shape->line); + } + shape->line = line; + shape->numlines = numlines; +} + +/*void GeometryReader::readGeometryCollection(shapeObj *shape) +{ + // TODO + return; +}*/ + +void GeometryReader::read(shapeObj *shape) +{ + // nested types + switch (m_geometry_type) { + //case GeometryType::GeometryCollection: return readGeometryCollection(shape); + case GeometryType::MultiPolygon: return readMultiPolygon(shape); + /*case GeometryType::CompoundCurve: return readCompoundCurve(); + case GeometryType::CurvePolygon: return readCurvePolygon(); + case GeometryType::MultiCurve: return readMultiCurve(); + case GeometryType::MultiSurface: return readMultiSurface(); + case GeometryType::PolyhedralSurface: return readPolyhedralSurface();*/ + default: break; + } + + // if not nested must have geometry data + const auto pXy = m_geometry->xy(); + const auto xySize = pXy->size(); + m_xy = pXy->data(); + m_length = xySize / 2; + + switch (m_geometry_type) { + case GeometryType::Point: return readPoint(shape); + case GeometryType::MultiPoint: return readMultiPoint(shape); + case GeometryType::LineString: return readLineString(shape); + case GeometryType::MultiLineString: return readMultiLineString(shape); + case GeometryType::Polygon: return readPolygon(shape); + /* + case GeometryType::CircularString: return readSimpleCurve(true); + case GeometryType::Triangle: return readTriangle(); + case GeometryType::TIN: return readTIN(); + */ + default: break; + } +} \ No newline at end of file diff --git a/src/flatgeobuf/geometryreader.h b/src/flatgeobuf/geometryreader.h new file mode 100644 index 0000000000..bbdac4d85b --- /dev/null +++ b/src/flatgeobuf/geometryreader.h @@ -0,0 +1,63 @@ +#ifndef FLATGEOBUF_GEOMETRYREADER_H +#define FLATGEOBUF_GEOMETRYREADER_H + +#include "../../mapserver.h" +#include "../../maperror.h" +#include "../../mapprimitive.h" + +#include "flatgeobuf_c.h" +#include "feature_generated.h" + +namespace mapserver { +namespace FlatGeobuf { + +class GeometryReader { + private: + flatgeobuf_ctx *m_ctx; + const FlatGeobuf::Geometry *m_geometry; + FlatGeobuf::GeometryType m_geometry_type; + bool m_has_z; + bool m_has_m; + + const double *m_xy = nullptr; + uint32_t m_length = 0; + uint32_t m_offset = 0; + + void readPoint(shapeObj *); + void readMultiPoint(shapeObj *); + void readLineString(shapeObj *); + void readMultiLineString(shapeObj *); + void readPolygon(shapeObj *); + void readMultiPolygon(shapeObj *); + //void readGeometryCollection(shapeObj *); + + void readLineObj(lineObj *line); + + public: + GeometryReader( + flatgeobuf_ctx *ctx, + const FlatGeobuf::Geometry *geometry) : + m_ctx (ctx), + m_geometry (geometry), + m_geometry_type ((FlatGeobuf::GeometryType) ctx->geometry_type), + m_has_z (ctx->has_z), + m_has_m (ctx->has_m) + { } + GeometryReader( + flatgeobuf_ctx *ctx, + const FlatGeobuf::Geometry *geometry, + const FlatGeobuf::GeometryType geometry_type) : + m_ctx (ctx), + m_geometry (geometry), + m_geometry_type (geometry_type), + m_has_z (ctx->has_z), + m_has_m (ctx->has_m) + { } + void read(shapeObj *); +}; + +} +} + + +#endif /* FLATGEOBUF_GEOMETRYREADER_H */ \ No newline at end of file diff --git a/src/flatgeobuf/header_generated.h b/src/flatgeobuf/header_generated.h new file mode 100644 index 0000000000..7cdb135019 --- /dev/null +++ b/src/flatgeobuf/header_generated.h @@ -0,0 +1,724 @@ +// automatically generated by the FlatBuffers compiler, do not modify + + +#ifndef FLATBUFFERS_GENERATED_HEADER_FLATGEOBUF_H_ +#define FLATBUFFERS_GENERATED_HEADER_FLATGEOBUF_H_ + +#include "flatbuffers/flatbuffers.h" + +// Ensure the included flatbuffers.h is the same version as when this file was +// generated, otherwise it may not be compatible. +static_assert(FLATBUFFERS_VERSION_MAJOR == 2 && + FLATBUFFERS_VERSION_MINOR == 0 && + FLATBUFFERS_VERSION_REVISION == 6, + "Non-compatible flatbuffers version included"); + +namespace mapserver { +namespace FlatGeobuf { + +struct Column; +struct ColumnBuilder; + +struct Crs; +struct CrsBuilder; + +struct Header; +struct HeaderBuilder; + +enum class GeometryType : uint8_t { + Unknown = 0, + Point = 1, + LineString = 2, + Polygon = 3, + MultiPoint = 4, + MultiLineString = 5, + MultiPolygon = 6, + GeometryCollection = 7, + CircularString = 8, + CompoundCurve = 9, + CurvePolygon = 10, + MultiCurve = 11, + MultiSurface = 12, + Curve = 13, + Surface = 14, + PolyhedralSurface = 15, + TIN = 16, + Triangle = 17, + MIN = Unknown, + MAX = Triangle +}; + +inline const GeometryType (&EnumValuesGeometryType())[18] { + static const GeometryType values[] = { + GeometryType::Unknown, + GeometryType::Point, + GeometryType::LineString, + GeometryType::Polygon, + GeometryType::MultiPoint, + GeometryType::MultiLineString, + GeometryType::MultiPolygon, + GeometryType::GeometryCollection, + GeometryType::CircularString, + GeometryType::CompoundCurve, + GeometryType::CurvePolygon, + GeometryType::MultiCurve, + GeometryType::MultiSurface, + GeometryType::Curve, + GeometryType::Surface, + GeometryType::PolyhedralSurface, + GeometryType::TIN, + GeometryType::Triangle + }; + return values; +} + +inline const char * const *EnumNamesGeometryType() { + static const char * const names[19] = { + "Unknown", + "Point", + "LineString", + "Polygon", + "MultiPoint", + "MultiLineString", + "MultiPolygon", + "GeometryCollection", + "CircularString", + "CompoundCurve", + "CurvePolygon", + "MultiCurve", + "MultiSurface", + "Curve", + "Surface", + "PolyhedralSurface", + "TIN", + "Triangle", + nullptr + }; + return names; +} + +inline const char *EnumNameGeometryType(GeometryType e) { + if (flatbuffers::IsOutRange(e, GeometryType::Unknown, GeometryType::Triangle)) return ""; + const size_t index = static_cast(e); + return EnumNamesGeometryType()[index]; +} + +enum class ColumnType : uint8_t { + Byte = 0, + UByte = 1, + Bool = 2, + Short = 3, + UShort = 4, + Int = 5, + UInt = 6, + Long = 7, + ULong = 8, + Float = 9, + Double = 10, + String = 11, + Json = 12, + DateTime = 13, + Binary = 14, + MIN = Byte, + MAX = Binary +}; + +inline const ColumnType (&EnumValuesColumnType())[15] { + static const ColumnType values[] = { + ColumnType::Byte, + ColumnType::UByte, + ColumnType::Bool, + ColumnType::Short, + ColumnType::UShort, + ColumnType::Int, + ColumnType::UInt, + ColumnType::Long, + ColumnType::ULong, + ColumnType::Float, + ColumnType::Double, + ColumnType::String, + ColumnType::Json, + ColumnType::DateTime, + ColumnType::Binary + }; + return values; +} + +inline const char * const *EnumNamesColumnType() { + static const char * const names[16] = { + "Byte", + "UByte", + "Bool", + "Short", + "UShort", + "Int", + "UInt", + "Long", + "ULong", + "Float", + "Double", + "String", + "Json", + "DateTime", + "Binary", + nullptr + }; + return names; +} + +inline const char *EnumNameColumnType(ColumnType e) { + if (flatbuffers::IsOutRange(e, ColumnType::Byte, ColumnType::Binary)) return ""; + const size_t index = static_cast(e); + return EnumNamesColumnType()[index]; +} + +struct Column FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef ColumnBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_NAME = 4, + VT_TYPE = 6, + VT_TITLE = 8, + VT_DESCRIPTION = 10, + VT_WIDTH = 12, + VT_PRECISION = 14, + VT_SCALE = 16, + VT_NULLABLE = 18, + VT_UNIQUE = 20, + VT_PRIMARY_KEY = 22, + VT_METADATA = 24 + }; + const flatbuffers::String *name() const { + return GetPointer(VT_NAME); + } + FlatGeobuf::ColumnType type() const { + return static_cast(GetField(VT_TYPE, 0)); + } + const flatbuffers::String *title() const { + return GetPointer(VT_TITLE); + } + const flatbuffers::String *description() const { + return GetPointer(VT_DESCRIPTION); + } + int32_t width() const { + return GetField(VT_WIDTH, -1); + } + int32_t precision() const { + return GetField(VT_PRECISION, -1); + } + int32_t scale() const { + return GetField(VT_SCALE, -1); + } + bool nullable() const { + return GetField(VT_NULLABLE, 1) != 0; + } + bool unique() const { + return GetField(VT_UNIQUE, 0) != 0; + } + bool primary_key() const { + return GetField(VT_PRIMARY_KEY, 0) != 0; + } + const flatbuffers::String *metadata() const { + return GetPointer(VT_METADATA); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffsetRequired(verifier, VT_NAME) && + verifier.VerifyString(name()) && + VerifyField(verifier, VT_TYPE, 1) && + VerifyOffset(verifier, VT_TITLE) && + verifier.VerifyString(title()) && + VerifyOffset(verifier, VT_DESCRIPTION) && + verifier.VerifyString(description()) && + VerifyField(verifier, VT_WIDTH, 4) && + VerifyField(verifier, VT_PRECISION, 4) && + VerifyField(verifier, VT_SCALE, 4) && + VerifyField(verifier, VT_NULLABLE, 1) && + VerifyField(verifier, VT_UNIQUE, 1) && + VerifyField(verifier, VT_PRIMARY_KEY, 1) && + VerifyOffset(verifier, VT_METADATA) && + verifier.VerifyString(metadata()) && + verifier.EndTable(); + } +}; + +struct ColumnBuilder { + typedef Column Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_name(flatbuffers::Offset name) { + fbb_.AddOffset(Column::VT_NAME, name); + } + void add_type(FlatGeobuf::ColumnType type) { + fbb_.AddElement(Column::VT_TYPE, static_cast(type), 0); + } + void add_title(flatbuffers::Offset title) { + fbb_.AddOffset(Column::VT_TITLE, title); + } + void add_description(flatbuffers::Offset description) { + fbb_.AddOffset(Column::VT_DESCRIPTION, description); + } + void add_width(int32_t width) { + fbb_.AddElement(Column::VT_WIDTH, width, -1); + } + void add_precision(int32_t precision) { + fbb_.AddElement(Column::VT_PRECISION, precision, -1); + } + void add_scale(int32_t scale) { + fbb_.AddElement(Column::VT_SCALE, scale, -1); + } + void add_nullable(bool nullable) { + fbb_.AddElement(Column::VT_NULLABLE, static_cast(nullable), 1); + } + void add_unique(bool unique) { + fbb_.AddElement(Column::VT_UNIQUE, static_cast(unique), 0); + } + void add_primary_key(bool primary_key) { + fbb_.AddElement(Column::VT_PRIMARY_KEY, static_cast(primary_key), 0); + } + void add_metadata(flatbuffers::Offset metadata) { + fbb_.AddOffset(Column::VT_METADATA, metadata); + } + explicit ColumnBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + fbb_.Required(o, Column::VT_NAME); + return o; + } +}; + +inline flatbuffers::Offset CreateColumn( + flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset name = 0, + FlatGeobuf::ColumnType type = FlatGeobuf::ColumnType::Byte, + flatbuffers::Offset title = 0, + flatbuffers::Offset description = 0, + int32_t width = -1, + int32_t precision = -1, + int32_t scale = -1, + bool nullable = true, + bool unique = false, + bool primary_key = false, + flatbuffers::Offset metadata = 0) { + ColumnBuilder builder_(_fbb); + builder_.add_metadata(metadata); + builder_.add_scale(scale); + builder_.add_precision(precision); + builder_.add_width(width); + builder_.add_description(description); + builder_.add_title(title); + builder_.add_name(name); + builder_.add_primary_key(primary_key); + builder_.add_unique(unique); + builder_.add_nullable(nullable); + builder_.add_type(type); + return builder_.Finish(); +} + +inline flatbuffers::Offset CreateColumnDirect( + flatbuffers::FlatBufferBuilder &_fbb, + const char *name = nullptr, + FlatGeobuf::ColumnType type = FlatGeobuf::ColumnType::Byte, + const char *title = nullptr, + const char *description = nullptr, + int32_t width = -1, + int32_t precision = -1, + int32_t scale = -1, + bool nullable = true, + bool unique = false, + bool primary_key = false, + const char *metadata = nullptr) { + auto name__ = name ? _fbb.CreateString(name) : 0; + auto title__ = title ? _fbb.CreateString(title) : 0; + auto description__ = description ? _fbb.CreateString(description) : 0; + auto metadata__ = metadata ? _fbb.CreateString(metadata) : 0; + return FlatGeobuf::CreateColumn( + _fbb, + name__, + type, + title__, + description__, + width, + precision, + scale, + nullable, + unique, + primary_key, + metadata__); +} + +struct Crs FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef CrsBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_ORG = 4, + VT_CODE = 6, + VT_NAME = 8, + VT_DESCRIPTION = 10, + VT_WKT = 12, + VT_CODE_STRING = 14 + }; + const flatbuffers::String *org() const { + return GetPointer(VT_ORG); + } + int32_t code() const { + return GetField(VT_CODE, 0); + } + const flatbuffers::String *name() const { + return GetPointer(VT_NAME); + } + const flatbuffers::String *description() const { + return GetPointer(VT_DESCRIPTION); + } + const flatbuffers::String *wkt() const { + return GetPointer(VT_WKT); + } + const flatbuffers::String *code_string() const { + return GetPointer(VT_CODE_STRING); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffset(verifier, VT_ORG) && + verifier.VerifyString(org()) && + VerifyField(verifier, VT_CODE, 4) && + VerifyOffset(verifier, VT_NAME) && + verifier.VerifyString(name()) && + VerifyOffset(verifier, VT_DESCRIPTION) && + verifier.VerifyString(description()) && + VerifyOffset(verifier, VT_WKT) && + verifier.VerifyString(wkt()) && + VerifyOffset(verifier, VT_CODE_STRING) && + verifier.VerifyString(code_string()) && + verifier.EndTable(); + } +}; + +struct CrsBuilder { + typedef Crs Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_org(flatbuffers::Offset org) { + fbb_.AddOffset(Crs::VT_ORG, org); + } + void add_code(int32_t code) { + fbb_.AddElement(Crs::VT_CODE, code, 0); + } + void add_name(flatbuffers::Offset name) { + fbb_.AddOffset(Crs::VT_NAME, name); + } + void add_description(flatbuffers::Offset description) { + fbb_.AddOffset(Crs::VT_DESCRIPTION, description); + } + void add_wkt(flatbuffers::Offset wkt) { + fbb_.AddOffset(Crs::VT_WKT, wkt); + } + void add_code_string(flatbuffers::Offset code_string) { + fbb_.AddOffset(Crs::VT_CODE_STRING, code_string); + } + explicit CrsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateCrs( + flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset org = 0, + int32_t code = 0, + flatbuffers::Offset name = 0, + flatbuffers::Offset description = 0, + flatbuffers::Offset wkt = 0, + flatbuffers::Offset code_string = 0) { + CrsBuilder builder_(_fbb); + builder_.add_code_string(code_string); + builder_.add_wkt(wkt); + builder_.add_description(description); + builder_.add_name(name); + builder_.add_code(code); + builder_.add_org(org); + return builder_.Finish(); +} + +inline flatbuffers::Offset CreateCrsDirect( + flatbuffers::FlatBufferBuilder &_fbb, + const char *org = nullptr, + int32_t code = 0, + const char *name = nullptr, + const char *description = nullptr, + const char *wkt = nullptr, + const char *code_string = nullptr) { + auto org__ = org ? _fbb.CreateString(org) : 0; + auto name__ = name ? _fbb.CreateString(name) : 0; + auto description__ = description ? _fbb.CreateString(description) : 0; + auto wkt__ = wkt ? _fbb.CreateString(wkt) : 0; + auto code_string__ = code_string ? _fbb.CreateString(code_string) : 0; + return FlatGeobuf::CreateCrs( + _fbb, + org__, + code, + name__, + description__, + wkt__, + code_string__); +} + +struct Header FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef HeaderBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_NAME = 4, + VT_ENVELOPE = 6, + VT_GEOMETRY_TYPE = 8, + VT_HAS_Z = 10, + VT_HAS_M = 12, + VT_HAS_T = 14, + VT_HAS_TM = 16, + VT_COLUMNS = 18, + VT_FEATURES_COUNT = 20, + VT_INDEX_NODE_SIZE = 22, + VT_CRS = 24, + VT_TITLE = 26, + VT_DESCRIPTION = 28, + VT_METADATA = 30 + }; + const flatbuffers::String *name() const { + return GetPointer(VT_NAME); + } + const flatbuffers::Vector *envelope() const { + return GetPointer *>(VT_ENVELOPE); + } + FlatGeobuf::GeometryType geometry_type() const { + return static_cast(GetField(VT_GEOMETRY_TYPE, 0)); + } + bool has_z() const { + return GetField(VT_HAS_Z, 0) != 0; + } + bool has_m() const { + return GetField(VT_HAS_M, 0) != 0; + } + bool has_t() const { + return GetField(VT_HAS_T, 0) != 0; + } + bool has_tm() const { + return GetField(VT_HAS_TM, 0) != 0; + } + const flatbuffers::Vector> *columns() const { + return GetPointer> *>(VT_COLUMNS); + } + uint64_t features_count() const { + return GetField(VT_FEATURES_COUNT, 0); + } + uint16_t index_node_size() const { + return GetField(VT_INDEX_NODE_SIZE, 16); + } + const FlatGeobuf::Crs *crs() const { + return GetPointer(VT_CRS); + } + const flatbuffers::String *title() const { + return GetPointer(VT_TITLE); + } + const flatbuffers::String *description() const { + return GetPointer(VT_DESCRIPTION); + } + const flatbuffers::String *metadata() const { + return GetPointer(VT_METADATA); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffset(verifier, VT_NAME) && + verifier.VerifyString(name()) && + VerifyOffset(verifier, VT_ENVELOPE) && + verifier.VerifyVector(envelope()) && + VerifyField(verifier, VT_GEOMETRY_TYPE, 1) && + VerifyField(verifier, VT_HAS_Z, 1) && + VerifyField(verifier, VT_HAS_M, 1) && + VerifyField(verifier, VT_HAS_T, 1) && + VerifyField(verifier, VT_HAS_TM, 1) && + VerifyOffset(verifier, VT_COLUMNS) && + verifier.VerifyVector(columns()) && + verifier.VerifyVectorOfTables(columns()) && + VerifyField(verifier, VT_FEATURES_COUNT, 8) && + VerifyField(verifier, VT_INDEX_NODE_SIZE, 2) && + VerifyOffset(verifier, VT_CRS) && + verifier.VerifyTable(crs()) && + VerifyOffset(verifier, VT_TITLE) && + verifier.VerifyString(title()) && + VerifyOffset(verifier, VT_DESCRIPTION) && + verifier.VerifyString(description()) && + VerifyOffset(verifier, VT_METADATA) && + verifier.VerifyString(metadata()) && + verifier.EndTable(); + } +}; + +struct HeaderBuilder { + typedef Header Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_name(flatbuffers::Offset name) { + fbb_.AddOffset(Header::VT_NAME, name); + } + void add_envelope(flatbuffers::Offset> envelope) { + fbb_.AddOffset(Header::VT_ENVELOPE, envelope); + } + void add_geometry_type(FlatGeobuf::GeometryType geometry_type) { + fbb_.AddElement(Header::VT_GEOMETRY_TYPE, static_cast(geometry_type), 0); + } + void add_has_z(bool has_z) { + fbb_.AddElement(Header::VT_HAS_Z, static_cast(has_z), 0); + } + void add_has_m(bool has_m) { + fbb_.AddElement(Header::VT_HAS_M, static_cast(has_m), 0); + } + void add_has_t(bool has_t) { + fbb_.AddElement(Header::VT_HAS_T, static_cast(has_t), 0); + } + void add_has_tm(bool has_tm) { + fbb_.AddElement(Header::VT_HAS_TM, static_cast(has_tm), 0); + } + void add_columns(flatbuffers::Offset>> columns) { + fbb_.AddOffset(Header::VT_COLUMNS, columns); + } + void add_features_count(uint64_t features_count) { + fbb_.AddElement(Header::VT_FEATURES_COUNT, features_count, 0); + } + void add_index_node_size(uint16_t index_node_size) { + fbb_.AddElement(Header::VT_INDEX_NODE_SIZE, index_node_size, 16); + } + void add_crs(flatbuffers::Offset crs) { + fbb_.AddOffset(Header::VT_CRS, crs); + } + void add_title(flatbuffers::Offset title) { + fbb_.AddOffset(Header::VT_TITLE, title); + } + void add_description(flatbuffers::Offset description) { + fbb_.AddOffset(Header::VT_DESCRIPTION, description); + } + void add_metadata(flatbuffers::Offset metadata) { + fbb_.AddOffset(Header::VT_METADATA, metadata); + } + explicit HeaderBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset
Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset
(end); + return o; + } +}; + +inline flatbuffers::Offset
CreateHeader( + flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset name = 0, + flatbuffers::Offset> envelope = 0, + FlatGeobuf::GeometryType geometry_type = FlatGeobuf::GeometryType::Unknown, + bool has_z = false, + bool has_m = false, + bool has_t = false, + bool has_tm = false, + flatbuffers::Offset>> columns = 0, + uint64_t features_count = 0, + uint16_t index_node_size = 16, + flatbuffers::Offset crs = 0, + flatbuffers::Offset title = 0, + flatbuffers::Offset description = 0, + flatbuffers::Offset metadata = 0) { + HeaderBuilder builder_(_fbb); + builder_.add_features_count(features_count); + builder_.add_metadata(metadata); + builder_.add_description(description); + builder_.add_title(title); + builder_.add_crs(crs); + builder_.add_columns(columns); + builder_.add_envelope(envelope); + builder_.add_name(name); + builder_.add_index_node_size(index_node_size); + builder_.add_has_tm(has_tm); + builder_.add_has_t(has_t); + builder_.add_has_m(has_m); + builder_.add_has_z(has_z); + builder_.add_geometry_type(geometry_type); + return builder_.Finish(); +} + +inline flatbuffers::Offset
CreateHeaderDirect( + flatbuffers::FlatBufferBuilder &_fbb, + const char *name = nullptr, + const std::vector *envelope = nullptr, + FlatGeobuf::GeometryType geometry_type = FlatGeobuf::GeometryType::Unknown, + bool has_z = false, + bool has_m = false, + bool has_t = false, + bool has_tm = false, + const std::vector> *columns = nullptr, + uint64_t features_count = 0, + uint16_t index_node_size = 16, + flatbuffers::Offset crs = 0, + const char *title = nullptr, + const char *description = nullptr, + const char *metadata = nullptr) { + auto name__ = name ? _fbb.CreateString(name) : 0; + auto envelope__ = envelope ? _fbb.CreateVector(*envelope) : 0; + auto columns__ = columns ? _fbb.CreateVector>(*columns) : 0; + auto title__ = title ? _fbb.CreateString(title) : 0; + auto description__ = description ? _fbb.CreateString(description) : 0; + auto metadata__ = metadata ? _fbb.CreateString(metadata) : 0; + return FlatGeobuf::CreateHeader( + _fbb, + name__, + envelope__, + geometry_type, + has_z, + has_m, + has_t, + has_tm, + columns__, + features_count, + index_node_size, + crs, + title__, + description__, + metadata__); +} + +inline const FlatGeobuf::Header *GetHeader(const void *buf) { + return flatbuffers::GetRoot(buf); +} + +inline const FlatGeobuf::Header *GetSizePrefixedHeader(const void *buf) { + return flatbuffers::GetSizePrefixedRoot(buf); +} + +inline bool VerifyHeaderBuffer( + flatbuffers::Verifier &verifier) { + return verifier.VerifyBuffer(nullptr); +} + +inline bool VerifySizePrefixedHeaderBuffer( + flatbuffers::Verifier &verifier) { + return verifier.VerifySizePrefixedBuffer(nullptr); +} + +inline void FinishHeaderBuffer( + flatbuffers::FlatBufferBuilder &fbb, + flatbuffers::Offset root) { + fbb.Finish(root); +} + +inline void FinishSizePrefixedHeaderBuffer( + flatbuffers::FlatBufferBuilder &fbb, + flatbuffers::Offset root) { + fbb.FinishSizePrefixed(root); +} + +} // namespace FlatGeobuf +} + +#endif // FLATBUFFERS_GENERATED_HEADER_FLATGEOBUF_H_ diff --git a/src/flatgeobuf/include/flatbuffers/LICENSE b/src/flatgeobuf/include/flatbuffers/LICENSE new file mode 100644 index 0000000000..78d9b1a428 --- /dev/null +++ b/src/flatgeobuf/include/flatbuffers/LICENSE @@ -0,0 +1,203 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2014 Google Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/src/flatgeobuf/include/flatbuffers/allocator.h b/src/flatgeobuf/include/flatbuffers/allocator.h new file mode 100644 index 0000000000..4062216eb4 --- /dev/null +++ b/src/flatgeobuf/include/flatbuffers/allocator.h @@ -0,0 +1,70 @@ +/* + * Copyright 2021 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLATBUFFERS_ALLOCATOR_H_ +#define FLATBUFFERS_ALLOCATOR_H_ + +#include "flatbuffers/base.h" + +namespace mapserver { +namespace flatbuffers { + +// Allocator interface. This is flatbuffers-specific and meant only for +// `vector_downward` usage. +class Allocator { + public: + virtual ~Allocator() {} + + // Allocate `size` bytes of memory. + virtual uint8_t *allocate(size_t size) = 0; + + // Deallocate `size` bytes of memory at `p` allocated by this allocator. + virtual void deallocate(uint8_t *p, size_t size) = 0; + + // Reallocate `new_size` bytes of memory, replacing the old region of size + // `old_size` at `p`. In contrast to a normal realloc, this grows downwards, + // and is intended specifcally for `vector_downward` use. + // `in_use_back` and `in_use_front` indicate how much of `old_size` is + // actually in use at each end, and needs to be copied. + virtual uint8_t *reallocate_downward(uint8_t *old_p, size_t old_size, + size_t new_size, size_t in_use_back, + size_t in_use_front) { + FLATBUFFERS_ASSERT(new_size > old_size); // vector_downward only grows + uint8_t *new_p = allocate(new_size); + memcpy_downward(old_p, old_size, new_p, new_size, in_use_back, + in_use_front); + deallocate(old_p, old_size); + return new_p; + } + + protected: + // Called by `reallocate_downward` to copy memory from `old_p` of `old_size` + // to `new_p` of `new_size`. Only memory of size `in_use_front` and + // `in_use_back` will be copied from the front and back of the old memory + // allocation. + void memcpy_downward(uint8_t *old_p, size_t old_size, uint8_t *new_p, + size_t new_size, size_t in_use_back, + size_t in_use_front) { + memcpy(new_p + new_size - in_use_back, old_p + old_size - in_use_back, + in_use_back); + memcpy(new_p, old_p, in_use_front); + } +}; + +} // namespace flatbuffers +} // namespace mapserver + +#endif // FLATBUFFERS_ALLOCATOR_H_ \ No newline at end of file diff --git a/src/flatgeobuf/include/flatbuffers/array.h b/src/flatgeobuf/include/flatbuffers/array.h new file mode 100644 index 0000000000..9e9b964554 --- /dev/null +++ b/src/flatgeobuf/include/flatbuffers/array.h @@ -0,0 +1,245 @@ +/* + * Copyright 2021 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLATBUFFERS_ARRAY_H_ +#define FLATBUFFERS_ARRAY_H_ + +#include "flatbuffers/base.h" +#include "flatbuffers/stl_emulation.h" +#include "flatbuffers/vector.h" + +namespace mapserver { +namespace flatbuffers { + +// This is used as a helper type for accessing arrays. +template class Array { + // Array can carry only POD data types (scalars or structs). + typedef typename flatbuffers::bool_constant::value> + scalar_tag; + typedef + typename flatbuffers::conditional::type + IndirectHelperType; + + public: + typedef uint16_t size_type; + typedef typename IndirectHelper::return_type return_type; + typedef VectorIterator const_iterator; + typedef VectorReverseIterator const_reverse_iterator; + + // If T is a LE-scalar or a struct (!scalar_tag::value). + static FLATBUFFERS_CONSTEXPR bool is_span_observable = + (scalar_tag::value && (FLATBUFFERS_LITTLEENDIAN || sizeof(T) == 1)) || + !scalar_tag::value; + + FLATBUFFERS_CONSTEXPR uint16_t size() const { return length; } + + return_type Get(uoffset_t i) const { + FLATBUFFERS_ASSERT(i < size()); + return IndirectHelper::Read(Data(), i); + } + + return_type operator[](uoffset_t i) const { return Get(i); } + + // If this is a Vector of enums, T will be its storage type, not the enum + // type. This function makes it convenient to retrieve value with enum + // type E. + template E GetEnum(uoffset_t i) const { + return static_cast(Get(i)); + } + + const_iterator begin() const { return const_iterator(Data(), 0); } + const_iterator end() const { return const_iterator(Data(), size()); } + + const_reverse_iterator rbegin() const { + return const_reverse_iterator(end()); + } + const_reverse_iterator rend() const { + return const_reverse_iterator(begin()); + } + + const_iterator cbegin() const { return begin(); } + const_iterator cend() const { return end(); } + + const_reverse_iterator crbegin() const { return rbegin(); } + const_reverse_iterator crend() const { return rend(); } + + // Get a mutable pointer to elements inside this array. + // This method used to mutate arrays of structs followed by a @p Mutate + // operation. For primitive types use @p Mutate directly. + // @warning Assignments and reads to/from the dereferenced pointer are not + // automatically converted to the correct endianness. + typename flatbuffers::conditional::type + GetMutablePointer(uoffset_t i) const { + FLATBUFFERS_ASSERT(i < size()); + return const_cast(&data()[i]); + } + + // Change elements if you have a non-const pointer to this object. + void Mutate(uoffset_t i, const T &val) { MutateImpl(scalar_tag(), i, val); } + + // The raw data in little endian format. Use with care. + const uint8_t *Data() const { return data_; } + + uint8_t *Data() { return data_; } + + // Similarly, but typed, much like std::vector::data + const T *data() const { return reinterpret_cast(Data()); } + T *data() { return reinterpret_cast(Data()); } + + // Copy data from a span with endian conversion. + // If this Array and the span overlap, the behavior is undefined. + void CopyFromSpan(flatbuffers::span src) { + const auto p1 = reinterpret_cast(src.data()); + const auto p2 = Data(); + FLATBUFFERS_ASSERT(!(p1 >= p2 && p1 < (p2 + length)) && + !(p2 >= p1 && p2 < (p1 + length))); + (void)p1; + (void)p2; + CopyFromSpanImpl(flatbuffers::bool_constant(), src); + } + + protected: + void MutateImpl(flatbuffers::true_type, uoffset_t i, const T &val) { + FLATBUFFERS_ASSERT(i < size()); + WriteScalar(data() + i, val); + } + + void MutateImpl(flatbuffers::false_type, uoffset_t i, const T &val) { + *(GetMutablePointer(i)) = val; + } + + void CopyFromSpanImpl(flatbuffers::true_type, + flatbuffers::span src) { + // Use std::memcpy() instead of std::copy() to avoid performance degradation + // due to aliasing if T is char or unsigned char. + // The size is known at compile time, so memcpy would be inlined. + std::memcpy(data(), src.data(), length * sizeof(T)); + } + + // Copy data from flatbuffers::span with endian conversion. + void CopyFromSpanImpl(flatbuffers::false_type, + flatbuffers::span src) { + for (size_type k = 0; k < length; k++) { Mutate(k, src[k]); } + } + + // This class is only used to access pre-existing data. Don't ever + // try to construct these manually. + // 'constexpr' allows us to use 'size()' at compile time. + // @note Must not use 'FLATBUFFERS_CONSTEXPR' here, as const is not allowed on + // a constructor. +#if defined(__cpp_constexpr) + constexpr Array(); +#else + Array(); +#endif + + uint8_t data_[length * sizeof(T)]; + + private: + // This class is a pointer. Copying will therefore create an invalid object. + // Private and unimplemented copy constructor. + Array(const Array &); + Array &operator=(const Array &); +}; + +// Specialization for Array[struct] with access using Offset pointer. +// This specialization used by idl_gen_text.cpp. +template class Array, length> { + static_assert(flatbuffers::is_same::value, "unexpected type T"); + + public: + typedef const void *return_type; + + const uint8_t *Data() const { return data_; } + + // Make idl_gen_text.cpp::PrintContainer happy. + return_type operator[](uoffset_t) const { + FLATBUFFERS_ASSERT(false); + return nullptr; + } + + private: + // This class is only used to access pre-existing data. + Array(); + Array(const Array &); + Array &operator=(const Array &); + + uint8_t data_[1]; +}; + +template +FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span make_span(Array &arr) + FLATBUFFERS_NOEXCEPT { + static_assert( + Array::is_span_observable, + "wrong type U, only plain struct, LE-scalar, or byte types are allowed"); + return span(arr.data(), N); +} + +template +FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span make_span( + const Array &arr) FLATBUFFERS_NOEXCEPT { + static_assert( + Array::is_span_observable, + "wrong type U, only plain struct, LE-scalar, or byte types are allowed"); + return span(arr.data(), N); +} + +template +FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span +make_bytes_span(Array &arr) FLATBUFFERS_NOEXCEPT { + static_assert(Array::is_span_observable, + "internal error, Array might hold only scalars or structs"); + return span(arr.Data(), sizeof(U) * N); +} + +template +FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span +make_bytes_span(const Array &arr) FLATBUFFERS_NOEXCEPT { + static_assert(Array::is_span_observable, + "internal error, Array might hold only scalars or structs"); + return span(arr.Data(), sizeof(U) * N); +} + +// Cast a raw T[length] to a raw flatbuffers::Array +// without endian conversion. Use with care. +// TODO: move these Cast-methods to `internal` namespace. +template +Array &CastToArray(T (&arr)[length]) { + return *reinterpret_cast *>(arr); +} + +template +const Array &CastToArray(const T (&arr)[length]) { + return *reinterpret_cast *>(arr); +} + +template +Array &CastToArrayOfEnum(T (&arr)[length]) { + static_assert(sizeof(E) == sizeof(T), "invalid enum type E"); + return *reinterpret_cast *>(arr); +} + +template +const Array &CastToArrayOfEnum(const T (&arr)[length]) { + static_assert(sizeof(E) == sizeof(T), "invalid enum type E"); + return *reinterpret_cast *>(arr); +} + +} // namespace flatbuffers +} // namespace mapserver + +#endif // FLATBUFFERS_ARRAY_H_ diff --git a/src/flatgeobuf/include/flatbuffers/base.h b/src/flatgeobuf/include/flatbuffers/base.h new file mode 100644 index 0000000000..c276236a82 --- /dev/null +++ b/src/flatgeobuf/include/flatbuffers/base.h @@ -0,0 +1,482 @@ +#ifndef FLATBUFFERS_BASE_H_ +#define FLATBUFFERS_BASE_H_ + +// clang-format off + +// If activate should be declared and included first. +#if defined(FLATBUFFERS_MEMORY_LEAK_TRACKING) && \ + defined(_MSC_VER) && defined(_DEBUG) + // The _CRTDBG_MAP_ALLOC inside will replace + // calloc/free (etc) to its debug version using #define directives. + #define _CRTDBG_MAP_ALLOC + #include + #include + // Replace operator new by trace-enabled version. + #define DEBUG_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__) + #define new DEBUG_NEW +#endif + +#if !defined(FLATBUFFERS_ASSERT) +#include +#define FLATBUFFERS_ASSERT assert +#elif defined(FLATBUFFERS_ASSERT_INCLUDE) +// Include file with forward declaration +#include FLATBUFFERS_ASSERT_INCLUDE +#endif + +#ifndef ARDUINO +#include +#endif + +#include +#include +#include + +#if defined(ARDUINO) && !defined(ARDUINOSTL_M_H) + #include +#else + #include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#if defined(__unix__) && !defined(FLATBUFFERS_LOCALE_INDEPENDENT) + #include +#endif + +#ifdef __ANDROID__ + #include +#endif + +#if defined(__ICCARM__) +#include +#endif + +// Note the __clang__ check is needed, because clang presents itself +// as an older GNUC compiler (4.2). +// Clang 3.3 and later implement all of the ISO C++ 2011 standard. +// Clang 3.4 and later implement all of the ISO C++ 2014 standard. +// http://clang.llvm.org/cxx_status.html + +// Note the MSVC value '__cplusplus' may be incorrect: +// The '__cplusplus' predefined macro in the MSVC stuck at the value 199711L, +// indicating (erroneously!) that the compiler conformed to the C++98 Standard. +// This value should be correct starting from MSVC2017-15.7-Preview-3. +// The '__cplusplus' will be valid only if MSVC2017-15.7-P3 and the `/Zc:__cplusplus` switch is set. +// Workaround (for details see MSDN): +// Use the _MSC_VER and _MSVC_LANG definition instead of the __cplusplus for compatibility. +// The _MSVC_LANG macro reports the Standard version regardless of the '/Zc:__cplusplus' switch. + +#if defined(__GNUC__) && !defined(__clang__) + #define FLATBUFFERS_GCC (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) +#else + #define FLATBUFFERS_GCC 0 +#endif + +#if defined(__clang__) + #define FLATBUFFERS_CLANG (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) +#else + #define FLATBUFFERS_CLANG 0 +#endif + +/// @cond FLATBUFFERS_INTERNAL +#if __cplusplus <= 199711L && \ + (!defined(_MSC_VER) || _MSC_VER < 1600) && \ + (!defined(__GNUC__) || \ + (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__ < 40400)) + #error A C++11 compatible compiler with support for the auto typing is \ + required for FlatBuffers. + #error __cplusplus _MSC_VER __GNUC__ __GNUC_MINOR__ __GNUC_PATCHLEVEL__ +#endif + +#if !defined(__clang__) && \ + defined(__GNUC__) && \ + (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__ < 40600) + // Backwards compatibility for g++ 4.4, and 4.5 which don't have the nullptr + // and constexpr keywords. Note the __clang__ check is needed, because clang + // presents itself as an older GNUC compiler. + #ifndef nullptr_t + const class nullptr_t { + public: + template inline operator T*() const { return 0; } + private: + void operator&() const; + } nullptr = {}; + #endif + #ifndef constexpr + #define constexpr const + #endif +#endif + +// The wire format uses a little endian encoding (since that's efficient for +// the common platforms). +#if defined(__s390x__) + #define FLATBUFFERS_LITTLEENDIAN 0 +#endif // __s390x__ +#if !defined(FLATBUFFERS_LITTLEENDIAN) + #if defined(__GNUC__) || defined(__clang__) || defined(__ICCARM__) + #if (defined(__BIG_ENDIAN__) || \ + (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) + #define FLATBUFFERS_LITTLEENDIAN 0 + #else + #define FLATBUFFERS_LITTLEENDIAN 1 + #endif // __BIG_ENDIAN__ + #elif defined(_MSC_VER) + #if defined(_M_PPC) + #define FLATBUFFERS_LITTLEENDIAN 0 + #else + #define FLATBUFFERS_LITTLEENDIAN 1 + #endif + #else + #error Unable to determine endianness, define FLATBUFFERS_LITTLEENDIAN. + #endif +#endif // !defined(FLATBUFFERS_LITTLEENDIAN) + +#define FLATBUFFERS_VERSION_MAJOR 2 +#define FLATBUFFERS_VERSION_MINOR 0 +#define FLATBUFFERS_VERSION_REVISION 6 +#define FLATBUFFERS_STRING_EXPAND(X) #X +#define FLATBUFFERS_STRING(X) FLATBUFFERS_STRING_EXPAND(X) +namespace mapserver { +namespace flatbuffers { + // Returns version as string "MAJOR.MINOR.REVISION". + const char* FLATBUFFERS_VERSION(); +} } + +#if (!defined(_MSC_VER) || _MSC_VER > 1600) && \ + (!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 407)) || \ + defined(__clang__) + #define FLATBUFFERS_FINAL_CLASS final + #define FLATBUFFERS_OVERRIDE override + #define FLATBUFFERS_EXPLICIT_CPP11 explicit + #define FLATBUFFERS_VTABLE_UNDERLYING_TYPE : flatbuffers::voffset_t +#else + #define FLATBUFFERS_FINAL_CLASS + #define FLATBUFFERS_OVERRIDE + #define FLATBUFFERS_EXPLICIT_CPP11 + #define FLATBUFFERS_VTABLE_UNDERLYING_TYPE +#endif + +#if (!defined(_MSC_VER) || _MSC_VER >= 1900) && \ + (!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 406)) || \ + (defined(__cpp_constexpr) && __cpp_constexpr >= 200704) + #define FLATBUFFERS_CONSTEXPR constexpr + #define FLATBUFFERS_CONSTEXPR_CPP11 constexpr + #define FLATBUFFERS_CONSTEXPR_DEFINED +#else + #define FLATBUFFERS_CONSTEXPR const + #define FLATBUFFERS_CONSTEXPR_CPP11 +#endif + +#if (defined(__cplusplus) && __cplusplus >= 201402L) || \ + (defined(__cpp_constexpr) && __cpp_constexpr >= 201304) + #define FLATBUFFERS_CONSTEXPR_CPP14 FLATBUFFERS_CONSTEXPR_CPP11 +#else + #define FLATBUFFERS_CONSTEXPR_CPP14 +#endif + +#if (defined(__GXX_EXPERIMENTAL_CXX0X__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 406)) || \ + (defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 190023026)) || \ + defined(__clang__) + #define FLATBUFFERS_NOEXCEPT noexcept +#else + #define FLATBUFFERS_NOEXCEPT +#endif + +// NOTE: the FLATBUFFERS_DELETE_FUNC macro may change the access mode to +// private, so be sure to put it at the end or reset access mode explicitly. +#if (!defined(_MSC_VER) || _MSC_FULL_VER >= 180020827) && \ + (!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 404)) || \ + defined(__clang__) + #define FLATBUFFERS_DELETE_FUNC(func) func = delete +#else + #define FLATBUFFERS_DELETE_FUNC(func) private: func +#endif + +#if (!defined(_MSC_VER) || _MSC_VER >= 1900) && \ + (!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 409)) || \ + defined(__clang__) + #define FLATBUFFERS_DEFAULT_DECLARATION +#endif + +// Check if we can use template aliases +// Not possible if Microsoft Compiler before 2012 +// Possible is the language feature __cpp_alias_templates is defined well +// Or possible if the C++ std is C+11 or newer +#if (defined(_MSC_VER) && _MSC_VER > 1700 /* MSVC2012 */) \ + || (defined(__cpp_alias_templates) && __cpp_alias_templates >= 200704) \ + || (defined(__cplusplus) && __cplusplus >= 201103L) + #define FLATBUFFERS_TEMPLATES_ALIASES +#endif + +#ifndef FLATBUFFERS_HAS_STRING_VIEW + // Only provide flatbuffers::string_view if __has_include can be used + // to detect a header that provides an implementation + #if defined(__has_include) + // Check for std::string_view (in c++17) + #if __has_include() && (__cplusplus >= 201606 || (defined(_HAS_CXX17) && _HAS_CXX17)) + #include + namespace mapserver { +namespace flatbuffers { + typedef std::string_view string_view; + } } + #define FLATBUFFERS_HAS_STRING_VIEW 1 + // Check for std::experimental::string_view (in c++14, compiler-dependent) + #elif __has_include() && (__cplusplus >= 201411) + #include + namespace mapserver { +namespace flatbuffers { + typedef std::experimental::string_view string_view; + } } + #define FLATBUFFERS_HAS_STRING_VIEW 1 + // Check for absl::string_view + #elif __has_include("absl/strings/string_view.h") && (__cplusplus >= 201411) + #include "absl/strings/string_view.h" + namespace mapserver { +namespace flatbuffers { + typedef absl::string_view string_view; + } } + #define FLATBUFFERS_HAS_STRING_VIEW 1 + #endif + #endif // __has_include +#endif // !FLATBUFFERS_HAS_STRING_VIEW + +#ifndef FLATBUFFERS_GENERAL_HEAP_ALLOC_OK + // Allow heap allocations to be used + #define FLATBUFFERS_GENERAL_HEAP_ALLOC_OK 1 +#endif // !FLATBUFFERS_GENERAL_HEAP_ALLOC_OK + +#ifndef FLATBUFFERS_HAS_NEW_STRTOD + // Modern (C++11) strtod and strtof functions are available for use. + // 1) nan/inf strings as argument of strtod; + // 2) hex-float as argument of strtod/strtof. + #if (defined(_MSC_VER) && _MSC_VER >= 1900) || \ + (defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 409)) || \ + (defined(__clang__)) + #define FLATBUFFERS_HAS_NEW_STRTOD 1 + #endif +#endif // !FLATBUFFERS_HAS_NEW_STRTOD + +#ifndef FLATBUFFERS_LOCALE_INDEPENDENT + // Enable locale independent functions {strtof_l, strtod_l,strtoll_l, strtoull_l}. + #if ((defined(_MSC_VER) && _MSC_VER >= 1800) || \ + (defined(_XOPEN_VERSION) && (_XOPEN_VERSION>=700)) && (!defined(__ANDROID_API__) || (defined(__ANDROID_API__) && (__ANDROID_API__>=21)))) + #define FLATBUFFERS_LOCALE_INDEPENDENT 1 + #else + #define FLATBUFFERS_LOCALE_INDEPENDENT 0 + #endif +#endif // !FLATBUFFERS_LOCALE_INDEPENDENT + +// Suppress Undefined Behavior Sanitizer (recoverable only). Usage: +// - __supress_ubsan__("undefined") +// - __supress_ubsan__("signed-integer-overflow") +#if defined(__clang__) && (__clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >=7)) + #define __supress_ubsan__(type) __attribute__((no_sanitize(type))) +#elif defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 409) + #define __supress_ubsan__(type) __attribute__((no_sanitize_undefined)) +#else + #define __supress_ubsan__(type) +#endif + +// This is constexpr function used for checking compile-time constants. +// Avoid `#pragma warning(disable: 4127) // C4127: expression is constant`. +template FLATBUFFERS_CONSTEXPR inline bool IsConstTrue(T t) { + return !!t; +} + +// Enable C++ attribute [[]] if std:c++17 or higher. +#if ((__cplusplus >= 201703L) \ + || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201703L))) + // All attributes unknown to an implementation are ignored without causing an error. + #define FLATBUFFERS_ATTRIBUTE(attr) attr + + #define FLATBUFFERS_FALLTHROUGH() [[fallthrough]] +#else + #define FLATBUFFERS_ATTRIBUTE(attr) + + #if FLATBUFFERS_CLANG >= 30800 + #define FLATBUFFERS_FALLTHROUGH() [[clang::fallthrough]] + #elif FLATBUFFERS_GCC >= 70300 + #define FLATBUFFERS_FALLTHROUGH() [[gnu::fallthrough]] + #else + #define FLATBUFFERS_FALLTHROUGH() + #endif +#endif + +/// @endcond + +/// @file +namespace mapserver { +namespace flatbuffers { + +/// @cond FLATBUFFERS_INTERNAL +// Our default offset / size type, 32bit on purpose on 64bit systems. +// Also, using a consistent offset type maintains compatibility of serialized +// offset values between 32bit and 64bit systems. +typedef uint32_t uoffset_t; + +// Signed offsets for references that can go in both directions. +typedef int32_t soffset_t; + +// Offset/index used in v-tables, can be changed to uint8_t in +// format forks to save a bit of space if desired. +typedef uint16_t voffset_t; + +typedef uintmax_t largest_scalar_t; + +// In 32bits, this evaluates to 2GB - 1 +#define FLATBUFFERS_MAX_BUFFER_SIZE ((1ULL << (sizeof(::mapserver::flatbuffers::soffset_t) * 8 - 1)) - 1) + +// We support aligning the contents of buffers up to this size. +#ifndef FLATBUFFERS_MAX_ALIGNMENT + #define FLATBUFFERS_MAX_ALIGNMENT 32 +#endif + +/// @brief The length of a FlatBuffer file header. +static const size_t kFileIdentifierLength = 4; + +inline bool VerifyAlignmentRequirements(size_t align, size_t min_align = 1) { + return (min_align <= align) && (align <= (FLATBUFFERS_MAX_ALIGNMENT)) && + (align & (align - 1)) == 0; // must be power of 2 +} + +#if defined(_MSC_VER) + #pragma warning(disable: 4351) // C4351: new behavior: elements of array ... will be default initialized + #pragma warning(push) + #pragma warning(disable: 4127) // C4127: conditional expression is constant +#endif + +template T EndianSwap(T t) { + #if defined(_MSC_VER) + #define FLATBUFFERS_BYTESWAP16 _byteswap_ushort + #define FLATBUFFERS_BYTESWAP32 _byteswap_ulong + #define FLATBUFFERS_BYTESWAP64 _byteswap_uint64 + #elif defined(__ICCARM__) + #define FLATBUFFERS_BYTESWAP16 __REV16 + #define FLATBUFFERS_BYTESWAP32 __REV + #define FLATBUFFERS_BYTESWAP64(x) \ + ((__REV(static_cast(x >> 32U))) | (static_cast(__REV(static_cast(x)))) << 32U) + #else + #if defined(__GNUC__) && __GNUC__ * 100 + __GNUC_MINOR__ < 408 && !defined(__clang__) + // __builtin_bswap16 was missing prior to GCC 4.8. + #define FLATBUFFERS_BYTESWAP16(x) \ + static_cast(__builtin_bswap32(static_cast(x) << 16)) + #else + #define FLATBUFFERS_BYTESWAP16 __builtin_bswap16 + #endif + #define FLATBUFFERS_BYTESWAP32 __builtin_bswap32 + #define FLATBUFFERS_BYTESWAP64 __builtin_bswap64 + #endif + if (sizeof(T) == 1) { // Compile-time if-then's. + return t; + } else if (sizeof(T) == 2) { + union { T t; uint16_t i; } u = { t }; + u.i = FLATBUFFERS_BYTESWAP16(u.i); + return u.t; + } else if (sizeof(T) == 4) { + union { T t; uint32_t i; } u = { t }; + u.i = FLATBUFFERS_BYTESWAP32(u.i); + return u.t; + } else if (sizeof(T) == 8) { + union { T t; uint64_t i; } u = { t }; + u.i = FLATBUFFERS_BYTESWAP64(u.i); + return u.t; + } else { + FLATBUFFERS_ASSERT(0); + return t; + } +} + +#if defined(_MSC_VER) + #pragma warning(pop) +#endif + + +template T EndianScalar(T t) { + #if FLATBUFFERS_LITTLEENDIAN + return t; + #else + return EndianSwap(t); + #endif +} + +template +// UBSAN: C++ aliasing type rules, see std::bit_cast<> for details. +__supress_ubsan__("alignment") +T ReadScalar(const void *p) { + return EndianScalar(*reinterpret_cast(p)); +} + +// See https://github.com/google/flatbuffers/issues/5950 + +#if (FLATBUFFERS_GCC >= 100000) && (FLATBUFFERS_GCC < 110000) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wstringop-overflow" +#endif + +template +// UBSAN: C++ aliasing type rules, see std::bit_cast<> for details. +__supress_ubsan__("alignment") +void WriteScalar(void *p, T t) { + *reinterpret_cast(p) = EndianScalar(t); +} + +template struct Offset; +template __supress_ubsan__("alignment") void WriteScalar(void *p, Offset t) { + *reinterpret_cast(p) = EndianScalar(t.o); +} + +#if (FLATBUFFERS_GCC >= 100000) && (FLATBUFFERS_GCC < 110000) + #pragma GCC diagnostic pop +#endif + +// Computes how many bytes you'd have to pad to be able to write an +// "scalar_size" scalar if the buffer had grown to "buf_size" (downwards in +// memory). +__supress_ubsan__("unsigned-integer-overflow") +inline size_t PaddingBytes(size_t buf_size, size_t scalar_size) { + return ((~buf_size) + 1) & (scalar_size - 1); +} + +// Generic 'operator==' with conditional specialisations. +// T e - new value of a scalar field. +// T def - default of scalar (is known at compile-time). +template inline bool IsTheSameAs(T e, T def) { return e == def; } + +#if defined(FLATBUFFERS_NAN_DEFAULTS) && \ + defined(FLATBUFFERS_HAS_NEW_STRTOD) && (FLATBUFFERS_HAS_NEW_STRTOD > 0) +// Like `operator==(e, def)` with weak NaN if T=(float|double). +template inline bool IsFloatTheSameAs(T e, T def) { + return (e == def) || ((def != def) && (e != e)); +} +template<> inline bool IsTheSameAs(float e, float def) { + return IsFloatTheSameAs(e, def); +} +template<> inline bool IsTheSameAs(double e, double def) { + return IsFloatTheSameAs(e, def); +} +#endif + +// Check 'v' is out of closed range [low; high]. +// Workaround for GCC warning [-Werror=type-limits]: +// comparison is always true due to limited range of data type. +template +inline bool IsOutRange(const T &v, const T &low, const T &high) { + return (v < low) || (high < v); +} + +// Check 'v' is in closed range [low; high]. +template +inline bool IsInRange(const T &v, const T &low, const T &high) { + return !IsOutRange(v, low, high); +} + +} // namespace flatbuffers +} // namespace mapserver +#endif // FLATBUFFERS_BASE_H_ diff --git a/src/flatgeobuf/include/flatbuffers/bfbs_generator.h b/src/flatgeobuf/include/flatbuffers/bfbs_generator.h new file mode 100644 index 0000000000..0741d817f8 --- /dev/null +++ b/src/flatgeobuf/include/flatbuffers/bfbs_generator.h @@ -0,0 +1,45 @@ +/* + * Copyright 2021 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLATBUFFERS_BFBS_GENERATOR_H_ +#define FLATBUFFERS_BFBS_GENERATOR_H_ + +#include + +namespace mapserver { +namespace flatbuffers { + +enum GeneratorStatus { + OK, + FAILED, + FAILED_VERIFICATION, +}; + +// A Flatbuffer Code Generator that receives a binary serialized reflection.fbs +// and generates code from it. +class BfbsGenerator { + public: + virtual ~BfbsGenerator() {} + + // Generate code from the provided `buffer` of given `length`. The buffer is + // a serialized reflection.fbs. + virtual GeneratorStatus Generate(const uint8_t *buffer, int64_t length) = 0; +}; + +} // namespace flatbuffers +} // namespace mapserver + +#endif // FLATBUFFERS_BFBS_GENERATOR_H_ diff --git a/src/flatgeobuf/include/flatbuffers/buffer.h b/src/flatgeobuf/include/flatbuffers/buffer.h new file mode 100644 index 0000000000..88f27052ec --- /dev/null +++ b/src/flatgeobuf/include/flatbuffers/buffer.h @@ -0,0 +1,144 @@ +/* + * Copyright 2021 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLATBUFFERS_BUFFER_H_ +#define FLATBUFFERS_BUFFER_H_ + +#include "flatbuffers/base.h" + +namespace mapserver { +namespace flatbuffers { + +// Wrapper for uoffset_t to allow safe template specialization. +// Value is allowed to be 0 to indicate a null object (see e.g. AddOffset). +template struct Offset { + uoffset_t o; + Offset() : o(0) {} + Offset(uoffset_t _o) : o(_o) {} + Offset Union() const { return Offset(o); } + bool IsNull() const { return !o; } +}; + +inline void EndianCheck() { + int endiantest = 1; + // If this fails, see FLATBUFFERS_LITTLEENDIAN above. + FLATBUFFERS_ASSERT(*reinterpret_cast(&endiantest) == + FLATBUFFERS_LITTLEENDIAN); + (void)endiantest; +} + +template FLATBUFFERS_CONSTEXPR size_t AlignOf() { + // clang-format off + #ifdef _MSC_VER + return __alignof(T); + #else + #ifndef alignof + return __alignof__(T); + #else + return alignof(T); + #endif + #endif + // clang-format on +} + +// Lexicographically compare two strings (possibly containing nulls), and +// return true if the first is less than the second. +static inline bool StringLessThan(const char *a_data, uoffset_t a_size, + const char *b_data, uoffset_t b_size) { + const auto cmp = memcmp(a_data, b_data, (std::min)(a_size, b_size)); + return cmp == 0 ? a_size < b_size : cmp < 0; +} + +// When we read serialized data from memory, in the case of most scalars, +// we want to just read T, but in the case of Offset, we want to actually +// perform the indirection and return a pointer. +// The template specialization below does just that. +// It is wrapped in a struct since function templates can't overload on the +// return type like this. +// The typedef is for the convenience of callers of this function +// (avoiding the need for a trailing return decltype) +template struct IndirectHelper { + typedef T return_type; + typedef T mutable_return_type; + static const size_t element_stride = sizeof(T); + static return_type Read(const uint8_t *p, uoffset_t i) { + return EndianScalar((reinterpret_cast(p))[i]); + } +}; +template struct IndirectHelper> { + typedef const T *return_type; + typedef T *mutable_return_type; + static const size_t element_stride = sizeof(uoffset_t); + static return_type Read(const uint8_t *p, uoffset_t i) { + p += i * sizeof(uoffset_t); + return reinterpret_cast(p + ReadScalar(p)); + } +}; +template struct IndirectHelper { + typedef const T *return_type; + typedef T *mutable_return_type; + static const size_t element_stride = sizeof(T); + static return_type Read(const uint8_t *p, uoffset_t i) { + return reinterpret_cast(p + i * sizeof(T)); + } +}; + +/// @brief Get a pointer to the the file_identifier section of the buffer. +/// @return Returns a const char pointer to the start of the file_identifier +/// characters in the buffer. The returned char * has length +/// 'flatbuffers::FlatBufferBuilder::kFileIdentifierLength'. +/// This function is UNDEFINED for FlatBuffers whose schema does not include +/// a file_identifier (likely points at padding or the start of a the root +/// vtable). +inline const char *GetBufferIdentifier(const void *buf, + bool size_prefixed = false) { + return reinterpret_cast(buf) + + ((size_prefixed) ? 2 * sizeof(uoffset_t) : sizeof(uoffset_t)); +} + +// Helper to see if the identifier in a buffer has the expected value. +inline bool BufferHasIdentifier(const void *buf, const char *identifier, + bool size_prefixed = false) { + return strncmp(GetBufferIdentifier(buf, size_prefixed), identifier, + flatbuffers::kFileIdentifierLength) == 0; +} + +/// @cond FLATBUFFERS_INTERNAL +// Helpers to get a typed pointer to the root object contained in the buffer. +template T *GetMutableRoot(void *buf) { + EndianCheck(); + return reinterpret_cast( + reinterpret_cast(buf) + + EndianScalar(*reinterpret_cast(buf))); +} + +template T *GetMutableSizePrefixedRoot(void *buf) { + return GetMutableRoot(reinterpret_cast(buf) + + sizeof(uoffset_t)); +} + +template const T *GetRoot(const void *buf) { + return GetMutableRoot(const_cast(buf)); +} + +template const T *GetSizePrefixedRoot(const void *buf) { + return GetRoot(reinterpret_cast(buf) + sizeof(uoffset_t)); +} + +} // namespace flatbuffers +} // namespace mapserver + +#endif // FLATBUFFERS_BUFFER_H_ \ No newline at end of file diff --git a/src/flatgeobuf/include/flatbuffers/buffer_ref.h b/src/flatgeobuf/include/flatbuffers/buffer_ref.h new file mode 100644 index 0000000000..24c6e81934 --- /dev/null +++ b/src/flatgeobuf/include/flatbuffers/buffer_ref.h @@ -0,0 +1,55 @@ +/* + * Copyright 2021 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLATBUFFERS_BUFFER_REF_H_ +#define FLATBUFFERS_BUFFER_REF_H_ + +#include "flatbuffers/base.h" +#include "flatbuffers/verifier.h" + +namespace mapserver { +namespace flatbuffers { + +// Convenient way to bundle a buffer and its length, to pass it around +// typed by its root. +// A BufferRef does not own its buffer. +struct BufferRefBase {}; // for std::is_base_of + +template struct BufferRef : BufferRefBase { + BufferRef() : buf(nullptr), len(0), must_free(false) {} + BufferRef(uint8_t *_buf, uoffset_t _len) + : buf(_buf), len(_len), must_free(false) {} + + ~BufferRef() { + if (must_free) free(buf); + } + + const T *GetRoot() const { return flatbuffers::GetRoot(buf); } + + bool Verify() { + Verifier verifier(buf, len); + return verifier.VerifyBuffer(nullptr); + } + + uint8_t *buf; + uoffset_t len; + bool must_free; +}; + +} // namespace flatbuffers +} // namespace mapserver + +#endif // FLATBUFFERS_BUFFER_REF_H_ \ No newline at end of file diff --git a/src/flatgeobuf/include/flatbuffers/code_generators.h b/src/flatgeobuf/include/flatbuffers/code_generators.h new file mode 100644 index 0000000000..8ebec3da17 --- /dev/null +++ b/src/flatgeobuf/include/flatbuffers/code_generators.h @@ -0,0 +1,235 @@ +/* + * Copyright 2014 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLATBUFFERS_CODE_GENERATORS_H_ +#define FLATBUFFERS_CODE_GENERATORS_H_ + +#include +#include + +#include "flatbuffers/idl.h" + +namespace mapserver { +namespace flatbuffers { + +// Utility class to assist in generating code through use of text templates. +// +// Example code: +// CodeWriter code("\t"); +// code.SetValue("NAME", "Foo"); +// code += "void {{NAME}}() { printf("%s", "{{NAME}}"); }"; +// code.SetValue("NAME", "Bar"); +// code += "void {{NAME}}() { printf("%s", "{{NAME}}"); }"; +// std::cout << code.ToString() << std::endl; +// +// Output: +// void Foo() { printf("%s", "Foo"); } +// void Bar() { printf("%s", "Bar"); } +class CodeWriter { + public: + CodeWriter(std::string pad = std::string()) + : pad_(pad), cur_ident_lvl_(0), ignore_ident_(false) {} + + // Clears the current "written" code. + void Clear() { + stream_.str(""); + stream_.clear(); + } + + // Associates a key with a value. All subsequent calls to operator+=, where + // the specified key is contained in {{ and }} delimiters will be replaced by + // the given value. + void SetValue(const std::string &key, const std::string &value) { + value_map_[key] = value; + } + + std::string GetValue(const std::string &key) const { + const auto it = value_map_.find(key); + return it == value_map_.end() ? "" : it->second; + } + + // Appends the given text to the generated code as well as a newline + // character. Any text within {{ and }} delimiters is replaced by values + // previously stored in the CodeWriter by calling SetValue above. The newline + // will be suppressed if the text ends with the \\ character. + void operator+=(std::string text); + + // Returns the current contents of the CodeWriter as a std::string. + std::string ToString() const { return stream_.str(); } + + // Increase ident level for writing code + void IncrementIdentLevel() { cur_ident_lvl_++; } + // Decrease ident level for writing code + void DecrementIdentLevel() { + if (cur_ident_lvl_) cur_ident_lvl_--; + } + + void SetPadding(const std::string &padding) { pad_ = padding; } + + private: + std::map value_map_; + std::stringstream stream_; + std::string pad_; + int cur_ident_lvl_; + bool ignore_ident_; + + // Add ident padding (tab or space) based on ident level + void AppendIdent(std::stringstream &stream); +}; + +class BaseGenerator { + public: + virtual bool generate() = 0; + + static std::string NamespaceDir(const Parser &parser, const std::string &path, + const Namespace &ns, + const bool dasherize = false); + + std::string GeneratedFileName(const std::string &path, + const std::string &file_name, + const IDLOptions &options) const; + + protected: + BaseGenerator(const Parser &parser, const std::string &path, + const std::string &file_name, std::string qualifying_start, + std::string qualifying_separator, std::string default_extension) + : parser_(parser), + path_(path), + file_name_(file_name), + qualifying_start_(qualifying_start), + qualifying_separator_(qualifying_separator), + default_extension_(default_extension) {} + virtual ~BaseGenerator() {} + + // No copy/assign. + BaseGenerator &operator=(const BaseGenerator &); + BaseGenerator(const BaseGenerator &); + + std::string NamespaceDir(const Namespace &ns, + const bool dasherize = false) const; + + static const char *FlatBuffersGeneratedWarning(); + + static std::string FullNamespace(const char *separator, const Namespace &ns); + + static std::string LastNamespacePart(const Namespace &ns); + + // tracks the current namespace for early exit in WrapInNameSpace + // c++, java and csharp returns a different namespace from + // the following default (no early exit, always fully qualify), + // which works for js and php + virtual const Namespace *CurrentNameSpace() const { return nullptr; } + + // Ensure that a type is prefixed with its namespace even within + // its own namespace to avoid conflict between generated method + // names and similarly named classes or structs + std::string WrapInNameSpace(const Namespace *ns, + const std::string &name) const; + + std::string WrapInNameSpace(const Definition &def) const; + + std::string GetNameSpace(const Definition &def) const; + + const Parser &parser_; + const std::string &path_; + const std::string &file_name_; + const std::string qualifying_start_; + const std::string qualifying_separator_; + const std::string default_extension_; +}; + +struct CommentConfig { + const char *first_line; + const char *content_line_prefix; + const char *last_line; +}; + +extern void GenComment(const std::vector &dc, + std::string *code_ptr, const CommentConfig *config, + const char *prefix = ""); + +class FloatConstantGenerator { + public: + virtual ~FloatConstantGenerator() {} + std::string GenFloatConstant(const FieldDef &field) const; + + private: + virtual std::string Value(double v, const std::string &src) const = 0; + virtual std::string Inf(double v) const = 0; + virtual std::string NaN(double v) const = 0; + + virtual std::string Value(float v, const std::string &src) const = 0; + virtual std::string Inf(float v) const = 0; + virtual std::string NaN(float v) const = 0; + + template + std::string GenFloatConstantImpl(const FieldDef &field) const; +}; + +class SimpleFloatConstantGenerator : public FloatConstantGenerator { + public: + SimpleFloatConstantGenerator(const char *nan_number, + const char *pos_inf_number, + const char *neg_inf_number); + + private: + std::string Value(double v, + const std::string &src) const FLATBUFFERS_OVERRIDE; + std::string Inf(double v) const FLATBUFFERS_OVERRIDE; + std::string NaN(double v) const FLATBUFFERS_OVERRIDE; + + std::string Value(float v, const std::string &src) const FLATBUFFERS_OVERRIDE; + std::string Inf(float v) const FLATBUFFERS_OVERRIDE; + std::string NaN(float v) const FLATBUFFERS_OVERRIDE; + + const std::string nan_number_; + const std::string pos_inf_number_; + const std::string neg_inf_number_; +}; + +// C++, C#, Java like generator. +class TypedFloatConstantGenerator : public FloatConstantGenerator { + public: + TypedFloatConstantGenerator(const char *double_prefix, + const char *single_prefix, const char *nan_number, + const char *pos_inf_number, + const char *neg_inf_number = ""); + + private: + std::string Value(double v, + const std::string &src) const FLATBUFFERS_OVERRIDE; + std::string Inf(double v) const FLATBUFFERS_OVERRIDE; + + std::string NaN(double v) const FLATBUFFERS_OVERRIDE; + + std::string Value(float v, const std::string &src) const FLATBUFFERS_OVERRIDE; + std::string Inf(float v) const FLATBUFFERS_OVERRIDE; + std::string NaN(float v) const FLATBUFFERS_OVERRIDE; + + std::string MakeNaN(const std::string &prefix) const; + std::string MakeInf(bool neg, const std::string &prefix) const; + + const std::string double_prefix_; + const std::string single_prefix_; + const std::string nan_number_; + const std::string pos_inf_number_; + const std::string neg_inf_number_; +}; + +} // namespace flatbuffers +} // namespace mapserver + +#endif // FLATBUFFERS_CODE_GENERATORS_H_ diff --git a/src/flatgeobuf/include/flatbuffers/default_allocator.h b/src/flatgeobuf/include/flatbuffers/default_allocator.h new file mode 100644 index 0000000000..907c02d9a0 --- /dev/null +++ b/src/flatgeobuf/include/flatbuffers/default_allocator.h @@ -0,0 +1,66 @@ +/* + * Copyright 2021 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLATBUFFERS_DEFAULT_ALLOCATOR_H_ +#define FLATBUFFERS_DEFAULT_ALLOCATOR_H_ + +#include "flatbuffers/allocator.h" +#include "flatbuffers/base.h" + +namespace mapserver { +namespace flatbuffers { + +// DefaultAllocator uses new/delete to allocate memory regions +class DefaultAllocator : public Allocator { + public: + uint8_t *allocate(size_t size) FLATBUFFERS_OVERRIDE { + return new uint8_t[size]; + } + + void deallocate(uint8_t *p, size_t) FLATBUFFERS_OVERRIDE { delete[] p; } + + static void dealloc(void *p, size_t) { delete[] static_cast(p); } +}; + +// These functions allow for a null allocator to mean use the default allocator, +// as used by DetachedBuffer and vector_downward below. +// This is to avoid having a statically or dynamically allocated default +// allocator, or having to move it between the classes that may own it. +inline uint8_t *Allocate(Allocator *allocator, size_t size) { + return allocator ? allocator->allocate(size) + : DefaultAllocator().allocate(size); +} + +inline void Deallocate(Allocator *allocator, uint8_t *p, size_t size) { + if (allocator) + allocator->deallocate(p, size); + else + DefaultAllocator().deallocate(p, size); +} + +inline uint8_t *ReallocateDownward(Allocator *allocator, uint8_t *old_p, + size_t old_size, size_t new_size, + size_t in_use_back, size_t in_use_front) { + return allocator ? allocator->reallocate_downward(old_p, old_size, new_size, + in_use_back, in_use_front) + : DefaultAllocator().reallocate_downward( + old_p, old_size, new_size, in_use_back, in_use_front); +} + +} // namespace flatbuffers +} // namespace mapserver + +#endif // FLATBUFFERS_DEFAULT_ALLOCATOR_H_ \ No newline at end of file diff --git a/src/flatgeobuf/include/flatbuffers/detached_buffer.h b/src/flatgeobuf/include/flatbuffers/detached_buffer.h new file mode 100644 index 0000000000..981c1a6439 --- /dev/null +++ b/src/flatgeobuf/include/flatbuffers/detached_buffer.h @@ -0,0 +1,116 @@ +/* + * Copyright 2021 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLATBUFFERS_DETACHED_BUFFER_H_ +#define FLATBUFFERS_DETACHED_BUFFER_H_ + +#include "flatbuffers/allocator.h" +#include "flatbuffers/base.h" +#include "flatbuffers/default_allocator.h" + +namespace mapserver { +namespace flatbuffers { + +// DetachedBuffer is a finished flatbuffer memory region, detached from its +// builder. The original memory region and allocator are also stored so that +// the DetachedBuffer can manage the memory lifetime. +class DetachedBuffer { + public: + DetachedBuffer() + : allocator_(nullptr), + own_allocator_(false), + buf_(nullptr), + reserved_(0), + cur_(nullptr), + size_(0) {} + + DetachedBuffer(Allocator *allocator, bool own_allocator, uint8_t *buf, + size_t reserved, uint8_t *cur, size_t sz) + : allocator_(allocator), + own_allocator_(own_allocator), + buf_(buf), + reserved_(reserved), + cur_(cur), + size_(sz) {} + + DetachedBuffer(DetachedBuffer &&other) + : allocator_(other.allocator_), + own_allocator_(other.own_allocator_), + buf_(other.buf_), + reserved_(other.reserved_), + cur_(other.cur_), + size_(other.size_) { + other.reset(); + } + + DetachedBuffer &operator=(DetachedBuffer &&other) { + if (this == &other) return *this; + + destroy(); + + allocator_ = other.allocator_; + own_allocator_ = other.own_allocator_; + buf_ = other.buf_; + reserved_ = other.reserved_; + cur_ = other.cur_; + size_ = other.size_; + + other.reset(); + + return *this; + } + + ~DetachedBuffer() { destroy(); } + + const uint8_t *data() const { return cur_; } + + uint8_t *data() { return cur_; } + + size_t size() const { return size_; } + + // These may change access mode, leave these at end of public section + FLATBUFFERS_DELETE_FUNC(DetachedBuffer(const DetachedBuffer &other)); + FLATBUFFERS_DELETE_FUNC( + DetachedBuffer &operator=(const DetachedBuffer &other)); + + protected: + Allocator *allocator_; + bool own_allocator_; + uint8_t *buf_; + size_t reserved_; + uint8_t *cur_; + size_t size_; + + inline void destroy() { + if (buf_) Deallocate(allocator_, buf_, reserved_); + if (own_allocator_ && allocator_) { delete allocator_; } + reset(); + } + + inline void reset() { + allocator_ = nullptr; + own_allocator_ = false; + buf_ = nullptr; + reserved_ = 0; + cur_ = nullptr; + size_ = 0; + } +}; + +} // namespace flatbuffers +} // namespace mapserver + +#endif // FLATBUFFERS_DETACHED_BUFFER_H_ diff --git a/src/flatgeobuf/include/flatbuffers/flatbuffer_builder.h b/src/flatgeobuf/include/flatbuffers/flatbuffer_builder.h new file mode 100644 index 0000000000..bd9cddea85 --- /dev/null +++ b/src/flatgeobuf/include/flatbuffers/flatbuffer_builder.h @@ -0,0 +1,1216 @@ +/* + * Copyright 2021 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLATBUFFERS_FLATBUFFER_BUILDER_H_ +#define FLATBUFFERS_FLATBUFFER_BUILDER_H_ + +#include +#include + +#include "flatbuffers/allocator.h" +#include "flatbuffers/array.h" +#include "flatbuffers/base.h" +#include "flatbuffers/buffer_ref.h" +#include "flatbuffers/default_allocator.h" +#include "flatbuffers/detached_buffer.h" +#include "flatbuffers/stl_emulation.h" +#include "flatbuffers/string.h" +#include "flatbuffers/struct.h" +#include "flatbuffers/table.h" +#include "flatbuffers/vector.h" +#include "flatbuffers/vector_downward.h" +#include "flatbuffers/verifier.h" + +namespace mapserver { +namespace flatbuffers { + +// Converts a Field ID to a virtual table offset. +inline voffset_t FieldIndexToOffset(voffset_t field_id) { + // Should correspond to what EndTable() below builds up. + const int fixed_fields = 2; // Vtable size and Object Size. + return static_cast((field_id + fixed_fields) * sizeof(voffset_t)); +} + +template> +const T *data(const std::vector &v) { + // Eventually the returned pointer gets passed down to memcpy, so + // we need it to be non-null to avoid undefined behavior. + static uint8_t t; + return v.empty() ? reinterpret_cast(&t) : &v.front(); +} +template> +T *data(std::vector &v) { + // Eventually the returned pointer gets passed down to memcpy, so + // we need it to be non-null to avoid undefined behavior. + static uint8_t t; + return v.empty() ? reinterpret_cast(&t) : &v.front(); +} + +/// @addtogroup flatbuffers_cpp_api +/// @{ +/// @class FlatBufferBuilder +/// @brief Helper class to hold data needed in creation of a FlatBuffer. +/// To serialize data, you typically call one of the `Create*()` functions in +/// the generated code, which in turn call a sequence of `StartTable`/ +/// `PushElement`/`AddElement`/`EndTable`, or the builtin `CreateString`/ +/// `CreateVector` functions. Do this is depth-first order to build up a tree to +/// the root. `Finish()` wraps up the buffer ready for transport. +class FlatBufferBuilder { + public: + /// @brief Default constructor for FlatBufferBuilder. + /// @param[in] initial_size The initial size of the buffer, in bytes. Defaults + /// to `1024`. + /// @param[in] allocator An `Allocator` to use. If null will use + /// `DefaultAllocator`. + /// @param[in] own_allocator Whether the builder/vector should own the + /// allocator. Defaults to / `false`. + /// @param[in] buffer_minalign Force the buffer to be aligned to the given + /// minimum alignment upon reallocation. Only needed if you intend to store + /// types with custom alignment AND you wish to read the buffer in-place + /// directly after creation. + explicit FlatBufferBuilder( + size_t initial_size = 1024, Allocator *allocator = nullptr, + bool own_allocator = false, + size_t buffer_minalign = AlignOf()) + : buf_(initial_size, allocator, own_allocator, buffer_minalign), + num_field_loc(0), + max_voffset_(0), + nested(false), + finished(false), + minalign_(1), + force_defaults_(false), + dedup_vtables_(true), + string_pool(nullptr) { + EndianCheck(); + } + + /// @brief Move constructor for FlatBufferBuilder. + FlatBufferBuilder(FlatBufferBuilder &&other) + : buf_(1024, nullptr, false, AlignOf()), + num_field_loc(0), + max_voffset_(0), + nested(false), + finished(false), + minalign_(1), + force_defaults_(false), + dedup_vtables_(true), + string_pool(nullptr) { + EndianCheck(); + // Default construct and swap idiom. + // Lack of delegating constructors in vs2010 makes it more verbose than + // needed. + Swap(other); + } + + /// @brief Move assignment operator for FlatBufferBuilder. + FlatBufferBuilder &operator=(FlatBufferBuilder &&other) { + // Move construct a temporary and swap idiom + FlatBufferBuilder temp(std::move(other)); + Swap(temp); + return *this; + } + + void Swap(FlatBufferBuilder &other) { + using std::swap; + buf_.swap(other.buf_); + swap(num_field_loc, other.num_field_loc); + swap(max_voffset_, other.max_voffset_); + swap(nested, other.nested); + swap(finished, other.finished); + swap(minalign_, other.minalign_); + swap(force_defaults_, other.force_defaults_); + swap(dedup_vtables_, other.dedup_vtables_); + swap(string_pool, other.string_pool); + } + + ~FlatBufferBuilder() { + if (string_pool) delete string_pool; + } + + void Reset() { + Clear(); // clear builder state + buf_.reset(); // deallocate buffer + } + + /// @brief Reset all the state in this FlatBufferBuilder so it can be reused + /// to construct another buffer. + void Clear() { + ClearOffsets(); + buf_.clear(); + nested = false; + finished = false; + minalign_ = 1; + if (string_pool) string_pool->clear(); + } + + /// @brief The current size of the serialized buffer, counting from the end. + /// @return Returns an `uoffset_t` with the current size of the buffer. + uoffset_t GetSize() const { return buf_.size(); } + + /// @brief Get the serialized buffer (after you call `Finish()`). + /// @return Returns an `uint8_t` pointer to the FlatBuffer data inside the + /// buffer. + uint8_t *GetBufferPointer() const { + Finished(); + return buf_.data(); + } + + /// @brief Get the serialized buffer (after you call `Finish()`) as a span. + /// @return Returns a constructed flatbuffers::span that is a view over the + /// FlatBuffer data inside the buffer. + flatbuffers::span GetBufferSpan() const { + Finished(); + return flatbuffers::span(buf_.data(), buf_.size()); + } + + /// @brief Get a pointer to an unfinished buffer. + /// @return Returns a `uint8_t` pointer to the unfinished buffer. + uint8_t *GetCurrentBufferPointer() const { return buf_.data(); } + + /// @brief Get the released pointer to the serialized buffer. + /// @warning Do NOT attempt to use this FlatBufferBuilder afterwards! + /// @return A `FlatBuffer` that owns the buffer and its allocator and + /// behaves similar to a `unique_ptr` with a deleter. + FLATBUFFERS_ATTRIBUTE([[deprecated("use Release() instead")]]) + DetachedBuffer ReleaseBufferPointer() { + Finished(); + return buf_.release(); + } + + /// @brief Get the released DetachedBuffer. + /// @return A `DetachedBuffer` that owns the buffer and its allocator. + DetachedBuffer Release() { + Finished(); + return buf_.release(); + } + + /// @brief Get the released pointer to the serialized buffer. + /// @param size The size of the memory block containing + /// the serialized `FlatBuffer`. + /// @param offset The offset from the released pointer where the finished + /// `FlatBuffer` starts. + /// @return A raw pointer to the start of the memory block containing + /// the serialized `FlatBuffer`. + /// @remark If the allocator is owned, it gets deleted when the destructor is + /// called.. + uint8_t *ReleaseRaw(size_t &size, size_t &offset) { + Finished(); + return buf_.release_raw(size, offset); + } + + /// @brief get the minimum alignment this buffer needs to be accessed + /// properly. This is only known once all elements have been written (after + /// you call Finish()). You can use this information if you need to embed + /// a FlatBuffer in some other buffer, such that you can later read it + /// without first having to copy it into its own buffer. + size_t GetBufferMinAlignment() const { + Finished(); + return minalign_; + } + + /// @cond FLATBUFFERS_INTERNAL + void Finished() const { + // If you get this assert, you're attempting to get access a buffer + // which hasn't been finished yet. Be sure to call + // FlatBufferBuilder::Finish with your root table. + // If you really need to access an unfinished buffer, call + // GetCurrentBufferPointer instead. + FLATBUFFERS_ASSERT(finished); + } + /// @endcond + + /// @brief In order to save space, fields that are set to their default value + /// don't get serialized into the buffer. + /// @param[in] fd When set to `true`, always serializes default values that + /// are set. Optional fields which are not set explicitly, will still not be + /// serialized. + void ForceDefaults(bool fd) { force_defaults_ = fd; } + + /// @brief By default vtables are deduped in order to save space. + /// @param[in] dedup When set to `true`, dedup vtables. + void DedupVtables(bool dedup) { dedup_vtables_ = dedup; } + + /// @cond FLATBUFFERS_INTERNAL + void Pad(size_t num_bytes) { buf_.fill(num_bytes); } + + void TrackMinAlign(size_t elem_size) { + if (elem_size > minalign_) minalign_ = elem_size; + } + + void Align(size_t elem_size) { + TrackMinAlign(elem_size); + buf_.fill(PaddingBytes(buf_.size(), elem_size)); + } + + void PushFlatBuffer(const uint8_t *bytes, size_t size) { + PushBytes(bytes, size); + finished = true; + } + + void PushBytes(const uint8_t *bytes, size_t size) { buf_.push(bytes, size); } + + void PopBytes(size_t amount) { buf_.pop(amount); } + + template void AssertScalarT() { + // The code assumes power of 2 sizes and endian-swap-ability. + static_assert(flatbuffers::is_scalar::value, "T must be a scalar type"); + } + + // Write a single aligned scalar to the buffer + template uoffset_t PushElement(T element) { + AssertScalarT(); + Align(sizeof(T)); + buf_.push_small(EndianScalar(element)); + return GetSize(); + } + + template uoffset_t PushElement(Offset off) { + // Special case for offsets: see ReferTo below. + return PushElement(ReferTo(off.o)); + } + + // When writing fields, we track where they are, so we can create correct + // vtables later. + void TrackField(voffset_t field, uoffset_t off) { + FieldLoc fl = { off, field }; + buf_.scratch_push_small(fl); + num_field_loc++; + if (field > max_voffset_) { max_voffset_ = field; } + } + + // Like PushElement, but additionally tracks the field this represents. + template void AddElement(voffset_t field, T e, T def) { + // We don't serialize values equal to the default. + if (IsTheSameAs(e, def) && !force_defaults_) return; + TrackField(field, PushElement(e)); + } + + template void AddElement(voffset_t field, T e) { + TrackField(field, PushElement(e)); + } + + template void AddOffset(voffset_t field, Offset off) { + if (off.IsNull()) return; // Don't store. + AddElement(field, ReferTo(off.o), static_cast(0)); + } + + template void AddStruct(voffset_t field, const T *structptr) { + if (!structptr) return; // Default, don't store. + Align(AlignOf()); + buf_.push_small(*structptr); + TrackField(field, GetSize()); + } + + void AddStructOffset(voffset_t field, uoffset_t off) { + TrackField(field, off); + } + + // Offsets initially are relative to the end of the buffer (downwards). + // This function converts them to be relative to the current location + // in the buffer (when stored here), pointing upwards. + uoffset_t ReferTo(uoffset_t off) { + // Align to ensure GetSize() below is correct. + Align(sizeof(uoffset_t)); + // Offset must refer to something already in buffer. + const uoffset_t size = GetSize(); + FLATBUFFERS_ASSERT(off && off <= size); + return size - off + static_cast(sizeof(uoffset_t)); + } + + void NotNested() { + // If you hit this, you're trying to construct a Table/Vector/String + // during the construction of its parent table (between the MyTableBuilder + // and table.Finish(). + // Move the creation of these sub-objects to above the MyTableBuilder to + // not get this assert. + // Ignoring this assert may appear to work in simple cases, but the reason + // it is here is that storing objects in-line may cause vtable offsets + // to not fit anymore. It also leads to vtable duplication. + FLATBUFFERS_ASSERT(!nested); + // If you hit this, fields were added outside the scope of a table. + FLATBUFFERS_ASSERT(!num_field_loc); + } + + // From generated code (or from the parser), we call StartTable/EndTable + // with a sequence of AddElement calls in between. + uoffset_t StartTable() { + NotNested(); + nested = true; + return GetSize(); + } + + // This finishes one serialized object by generating the vtable if it's a + // table, comparing it against existing vtables, and writing the + // resulting vtable offset. + uoffset_t EndTable(uoffset_t start) { + // If you get this assert, a corresponding StartTable wasn't called. + FLATBUFFERS_ASSERT(nested); + // Write the vtable offset, which is the start of any Table. + // We fill it's value later. + auto vtableoffsetloc = PushElement(0); + // Write a vtable, which consists entirely of voffset_t elements. + // It starts with the number of offsets, followed by a type id, followed + // by the offsets themselves. In reverse: + // Include space for the last offset and ensure empty tables have a + // minimum size. + max_voffset_ = + (std::max)(static_cast(max_voffset_ + sizeof(voffset_t)), + FieldIndexToOffset(0)); + buf_.fill_big(max_voffset_); + auto table_object_size = vtableoffsetloc - start; + // Vtable use 16bit offsets. + FLATBUFFERS_ASSERT(table_object_size < 0x10000); + WriteScalar(buf_.data() + sizeof(voffset_t), + static_cast(table_object_size)); + WriteScalar(buf_.data(), max_voffset_); + // Write the offsets into the table + for (auto it = buf_.scratch_end() - num_field_loc * sizeof(FieldLoc); + it < buf_.scratch_end(); it += sizeof(FieldLoc)) { + auto field_location = reinterpret_cast(it); + auto pos = static_cast(vtableoffsetloc - field_location->off); + // If this asserts, it means you've set a field twice. + FLATBUFFERS_ASSERT( + !ReadScalar(buf_.data() + field_location->id)); + WriteScalar(buf_.data() + field_location->id, pos); + } + ClearOffsets(); + auto vt1 = reinterpret_cast(buf_.data()); + auto vt1_size = ReadScalar(vt1); + auto vt_use = GetSize(); + // See if we already have generated a vtable with this exact same + // layout before. If so, make it point to the old one, remove this one. + if (dedup_vtables_) { + for (auto it = buf_.scratch_data(); it < buf_.scratch_end(); + it += sizeof(uoffset_t)) { + auto vt_offset_ptr = reinterpret_cast(it); + auto vt2 = reinterpret_cast(buf_.data_at(*vt_offset_ptr)); + auto vt2_size = ReadScalar(vt2); + if (vt1_size != vt2_size || 0 != memcmp(vt2, vt1, vt1_size)) continue; + vt_use = *vt_offset_ptr; + buf_.pop(GetSize() - vtableoffsetloc); + break; + } + } + // If this is a new vtable, remember it. + if (vt_use == GetSize()) { buf_.scratch_push_small(vt_use); } + // Fill the vtable offset we created above. + // The offset points from the beginning of the object to where the + // vtable is stored. + // Offsets default direction is downward in memory for future format + // flexibility (storing all vtables at the start of the file). + WriteScalar(buf_.data_at(vtableoffsetloc), + static_cast(vt_use) - + static_cast(vtableoffsetloc)); + + nested = false; + return vtableoffsetloc; + } + + FLATBUFFERS_ATTRIBUTE([[deprecated("call the version above instead")]]) + uoffset_t EndTable(uoffset_t start, voffset_t /*numfields*/) { + return EndTable(start); + } + + // This checks a required field has been set in a given table that has + // just been constructed. + template void Required(Offset table, voffset_t field); + + uoffset_t StartStruct(size_t alignment) { + Align(alignment); + return GetSize(); + } + + uoffset_t EndStruct() { return GetSize(); } + + void ClearOffsets() { + buf_.scratch_pop(num_field_loc * sizeof(FieldLoc)); + num_field_loc = 0; + max_voffset_ = 0; + } + + // Aligns such that when "len" bytes are written, an object can be written + // after it with "alignment" without padding. + void PreAlign(size_t len, size_t alignment) { + if (len == 0) return; + TrackMinAlign(alignment); + buf_.fill(PaddingBytes(GetSize() + len, alignment)); + } + template void PreAlign(size_t len) { + AssertScalarT(); + PreAlign(len, sizeof(T)); + } + /// @endcond + + /// @brief Store a string in the buffer, which can contain any binary data. + /// @param[in] str A const char pointer to the data to be stored as a string. + /// @param[in] len The number of bytes that should be stored from `str`. + /// @return Returns the offset in the buffer where the string starts. + Offset CreateString(const char *str, size_t len) { + NotNested(); + PreAlign(len + 1); // Always 0-terminated. + buf_.fill(1); + PushBytes(reinterpret_cast(str), len); + PushElement(static_cast(len)); + return Offset(GetSize()); + } + + /// @brief Store a string in the buffer, which is null-terminated. + /// @param[in] str A const char pointer to a C-string to add to the buffer. + /// @return Returns the offset in the buffer where the string starts. + Offset CreateString(const char *str) { + return CreateString(str, strlen(str)); + } + + /// @brief Store a string in the buffer, which is null-terminated. + /// @param[in] str A char pointer to a C-string to add to the buffer. + /// @return Returns the offset in the buffer where the string starts. + Offset CreateString(char *str) { + return CreateString(str, strlen(str)); + } + + /// @brief Store a string in the buffer, which can contain any binary data. + /// @param[in] str A const reference to a std::string to store in the buffer. + /// @return Returns the offset in the buffer where the string starts. + Offset CreateString(const std::string &str) { + return CreateString(str.c_str(), str.length()); + } + + // clang-format off + #ifdef FLATBUFFERS_HAS_STRING_VIEW + /// @brief Store a string in the buffer, which can contain any binary data. + /// @param[in] str A const string_view to copy in to the buffer. + /// @return Returns the offset in the buffer where the string starts. + Offset CreateString(flatbuffers::string_view str) { + return CreateString(str.data(), str.size()); + } + #endif // FLATBUFFERS_HAS_STRING_VIEW + // clang-format on + + /// @brief Store a string in the buffer, which can contain any binary data. + /// @param[in] str A const pointer to a `String` struct to add to the buffer. + /// @return Returns the offset in the buffer where the string starts + Offset CreateString(const String *str) { + return str ? CreateString(str->c_str(), str->size()) : 0; + } + + /// @brief Store a string in the buffer, which can contain any binary data. + /// @param[in] str A const reference to a std::string like type with support + /// of T::c_str() and T::length() to store in the buffer. + /// @return Returns the offset in the buffer where the string starts. + template Offset CreateString(const T &str) { + return CreateString(str.c_str(), str.length()); + } + + /// @brief Store a string in the buffer, which can contain any binary data. + /// If a string with this exact contents has already been serialized before, + /// instead simply returns the offset of the existing string. This uses a map + /// stored on the heap, but only stores the numerical offsets. + /// @param[in] str A const char pointer to the data to be stored as a string. + /// @param[in] len The number of bytes that should be stored from `str`. + /// @return Returns the offset in the buffer where the string starts. + Offset CreateSharedString(const char *str, size_t len) { + FLATBUFFERS_ASSERT(FLATBUFFERS_GENERAL_HEAP_ALLOC_OK); + if (!string_pool) + string_pool = new StringOffsetMap(StringOffsetCompare(buf_)); + auto size_before_string = buf_.size(); + // Must first serialize the string, since the set is all offsets into + // buffer. + auto off = CreateString(str, len); + auto it = string_pool->find(off); + // If it exists we reuse existing serialized data! + if (it != string_pool->end()) { + // We can remove the string we serialized. + buf_.pop(buf_.size() - size_before_string); + return *it; + } + // Record this string for future use. + string_pool->insert(off); + return off; + } + +#ifdef FLATBUFFERS_HAS_STRING_VIEW + /// @brief Store a string in the buffer, which can contain any binary data. + /// If a string with this exact contents has already been serialized before, + /// instead simply returns the offset of the existing string. This uses a map + /// stored on the heap, but only stores the numerical offsets. + /// @param[in] str A const std::string_view to store in the buffer. + /// @return Returns the offset in the buffer where the string starts + Offset CreateSharedString(const flatbuffers::string_view str) { + return CreateSharedString(str.data(), str.size()); + } +#else + /// @brief Store a string in the buffer, which null-terminated. + /// If a string with this exact contents has already been serialized before, + /// instead simply returns the offset of the existing string. This uses a map + /// stored on the heap, but only stores the numerical offsets. + /// @param[in] str A const char pointer to a C-string to add to the buffer. + /// @return Returns the offset in the buffer where the string starts. + Offset CreateSharedString(const char *str) { + return CreateSharedString(str, strlen(str)); + } + + /// @brief Store a string in the buffer, which can contain any binary data. + /// If a string with this exact contents has already been serialized before, + /// instead simply returns the offset of the existing string. This uses a map + /// stored on the heap, but only stores the numerical offsets. + /// @param[in] str A const reference to a std::string to store in the buffer. + /// @return Returns the offset in the buffer where the string starts. + Offset CreateSharedString(const std::string &str) { + return CreateSharedString(str.c_str(), str.length()); + } +#endif + + /// @brief Store a string in the buffer, which can contain any binary data. + /// If a string with this exact contents has already been serialized before, + /// instead simply returns the offset of the existing string. This uses a map + /// stored on the heap, but only stores the numerical offsets. + /// @param[in] str A const pointer to a `String` struct to add to the buffer. + /// @return Returns the offset in the buffer where the string starts + Offset CreateSharedString(const String *str) { + return CreateSharedString(str->c_str(), str->size()); + } + + /// @cond FLATBUFFERS_INTERNAL + uoffset_t EndVector(size_t len) { + FLATBUFFERS_ASSERT(nested); // Hit if no corresponding StartVector. + nested = false; + return PushElement(static_cast(len)); + } + + void StartVector(size_t len, size_t elemsize) { + NotNested(); + nested = true; + PreAlign(len * elemsize); + PreAlign(len * elemsize, elemsize); // Just in case elemsize > uoffset_t. + } + + // Call this right before StartVector/CreateVector if you want to force the + // alignment to be something different than what the element size would + // normally dictate. + // This is useful when storing a nested_flatbuffer in a vector of bytes, + // or when storing SIMD floats, etc. + void ForceVectorAlignment(size_t len, size_t elemsize, size_t alignment) { + if (len == 0) return; + FLATBUFFERS_ASSERT(VerifyAlignmentRequirements(alignment)); + PreAlign(len * elemsize, alignment); + } + + // Similar to ForceVectorAlignment but for String fields. + void ForceStringAlignment(size_t len, size_t alignment) { + if (len == 0) return; + FLATBUFFERS_ASSERT(VerifyAlignmentRequirements(alignment)); + PreAlign((len + 1) * sizeof(char), alignment); + } + + /// @endcond + + /// @brief Serialize an array into a FlatBuffer `vector`. + /// @tparam T The data type of the array elements. + /// @param[in] v A pointer to the array of type `T` to serialize into the + /// buffer as a `vector`. + /// @param[in] len The number of elements to serialize. + /// @return Returns a typed `Offset` into the serialized data indicating + /// where the vector is stored. + template Offset> CreateVector(const T *v, size_t len) { + // If this assert hits, you're specifying a template argument that is + // causing the wrong overload to be selected, remove it. + AssertScalarT(); + StartVector(len, sizeof(T)); + if (len == 0) { return Offset>(EndVector(len)); } + // clang-format off + #if FLATBUFFERS_LITTLEENDIAN + PushBytes(reinterpret_cast(v), len * sizeof(T)); + #else + if (sizeof(T) == 1) { + PushBytes(reinterpret_cast(v), len); + } else { + for (auto i = len; i > 0; ) { + PushElement(v[--i]); + } + } + #endif + // clang-format on + return Offset>(EndVector(len)); + } + + /// @brief Serialize an array like object into a FlatBuffer `vector`. + /// @tparam T The data type of the array elements. + /// @tparam C The type of the array. + /// @param[in] array A reference to an array like object of type `T` to + /// serialize into the buffer as a `vector`. + /// @return Returns a typed `Offset` into the serialized data indicating + /// where the vector is stored. + template Offset> CreateVector(const C &array) { + return CreateVector(array.data(), array.size()); + } + + /// @brief Serialize an initializer list into a FlatBuffer `vector`. + /// @tparam T The data type of the initializer list elements. + /// @param[in] v The value of the initializer list. + /// @return Returns a typed `Offset` into the serialized data indicating + /// where the vector is stored. + template + Offset> CreateVector(std::initializer_list v) { + return CreateVector(v.begin(), v.size()); + } + + template + Offset>> CreateVector(const Offset *v, size_t len) { + StartVector(len, sizeof(Offset)); + for (auto i = len; i > 0;) { PushElement(v[--i]); } + return Offset>>(EndVector(len)); + } + + /// @brief Serialize a `std::vector` into a FlatBuffer `vector`. + /// @tparam T The data type of the `std::vector` elements. + /// @param v A const reference to the `std::vector` to serialize into the + /// buffer as a `vector`. + /// @return Returns a typed `Offset` into the serialized data indicating + /// where the vector is stored. + template> + Offset> CreateVector(const std::vector &v) { + return CreateVector(data(v), v.size()); + } + + // vector may be implemented using a bit-set, so we can't access it as + // an array. Instead, read elements manually. + // Background: https://isocpp.org/blog/2012/11/on-vectorbool + Offset> CreateVector(const std::vector &v) { + StartVector(v.size(), sizeof(uint8_t)); + for (auto i = v.size(); i > 0;) { + PushElement(static_cast(v[--i])); + } + return Offset>(EndVector(v.size())); + } + + /// @brief Serialize values returned by a function into a FlatBuffer `vector`. + /// This is a convenience function that takes care of iteration for you. + /// @tparam T The data type of the `std::vector` elements. + /// @param f A function that takes the current iteration 0..vector_size-1 and + /// returns any type that you can construct a FlatBuffers vector out of. + /// @return Returns a typed `Offset` into the serialized data indicating + /// where the vector is stored. + template + Offset> CreateVector(size_t vector_size, + const std::function &f) { + FLATBUFFERS_ASSERT(FLATBUFFERS_GENERAL_HEAP_ALLOC_OK); + std::vector elems(vector_size); + for (size_t i = 0; i < vector_size; i++) elems[i] = f(i); + return CreateVector(elems); + } + + /// @brief Serialize values returned by a function into a FlatBuffer `vector`. + /// This is a convenience function that takes care of iteration for you. This + /// uses a vector stored on the heap to store the intermediate results of the + /// iteration. + /// @tparam T The data type of the `std::vector` elements. + /// @param f A function that takes the current iteration 0..vector_size-1, + /// and the state parameter returning any type that you can construct a + /// FlatBuffers vector out of. + /// @param state State passed to f. + /// @return Returns a typed `Offset` into the serialized data indicating + /// where the vector is stored. + template + Offset> CreateVector(size_t vector_size, F f, S *state) { + FLATBUFFERS_ASSERT(FLATBUFFERS_GENERAL_HEAP_ALLOC_OK); + std::vector elems(vector_size); + for (size_t i = 0; i < vector_size; i++) elems[i] = f(i, state); + return CreateVector(elems); + } + + /// @brief Serialize a `std::vector` into a FlatBuffer `vector`. + /// whereas StringType is any type that is accepted by the CreateString() + /// overloads. + /// This is a convenience function for a common case. + /// @param v A const reference to the `std::vector` to serialize into the + /// buffer as a `vector`. + /// @return Returns a typed `Offset` into the serialized data indicating + /// where the vector is stored. + template> + Offset>> CreateVectorOfStrings( + const std::vector &v) { + return CreateVectorOfStrings(v.cbegin(), v.cend()); + } + + /// @brief Serialize a collection of Strings into a FlatBuffer `vector`. + /// This is a convenience function for a common case. + /// @param begin The beginning iterator of the collection + /// @param end The ending iterator of the collection + /// @return Returns a typed `Offset` into the serialized data indicating + /// where the vector is stored. + template + Offset>> CreateVectorOfStrings(It begin, It end) { + auto size = std::distance(begin, end); + auto scratch_buffer_usage = size * sizeof(Offset); + // If there is not enough space to store the offsets, there definitely won't + // be enough space to store all the strings. So ensuring space for the + // scratch region is OK, for it it fails, it would have failed later. + buf_.ensure_space(scratch_buffer_usage); + for (auto it = begin; it != end; ++it) { + buf_.scratch_push_small(CreateString(*it)); + } + StartVector(size, sizeof(Offset)); + for (auto i = 1; i <= size; i++) { + // Note we re-evaluate the buf location each iteration to account for any + // underlying buffer resizing that may occur. + PushElement(*reinterpret_cast *>( + buf_.scratch_end() - i * sizeof(Offset))); + } + buf_.scratch_pop(scratch_buffer_usage); + return Offset>>(EndVector(size)); + } + + /// @brief Serialize an array of structs into a FlatBuffer `vector`. + /// @tparam T The data type of the struct array elements. + /// @param[in] v A pointer to the array of type `T` to serialize into the + /// buffer as a `vector`. + /// @param[in] len The number of elements to serialize. + /// @return Returns a typed `Offset` into the serialized data indicating + /// where the vector is stored. + template + Offset> CreateVectorOfStructs(const T *v, size_t len) { + StartVector(len * sizeof(T) / AlignOf(), AlignOf()); + if (len > 0) { + PushBytes(reinterpret_cast(v), sizeof(T) * len); + } + return Offset>(EndVector(len)); + } + + /// @brief Serialize an array of native structs into a FlatBuffer `vector`. + /// @tparam T The data type of the struct array elements. + /// @tparam S The data type of the native struct array elements. + /// @param[in] v A pointer to the array of type `S` to serialize into the + /// buffer as a `vector`. + /// @param[in] len The number of elements to serialize. + /// @param[in] pack_func Pointer to a function to convert the native struct + /// to the FlatBuffer struct. + /// @return Returns a typed `Offset` into the serialized data indicating + /// where the vector is stored. + template + Offset> CreateVectorOfNativeStructs( + const S *v, size_t len, T (*const pack_func)(const S &)) { + FLATBUFFERS_ASSERT(pack_func); + auto structs = StartVectorOfStructs(len); + for (size_t i = 0; i < len; i++) { structs[i] = pack_func(v[i]); } + return EndVectorOfStructs(len); + } + + /// @brief Serialize an array of native structs into a FlatBuffer `vector`. + /// @tparam T The data type of the struct array elements. + /// @tparam S The data type of the native struct array elements. + /// @param[in] v A pointer to the array of type `S` to serialize into the + /// buffer as a `vector`. + /// @param[in] len The number of elements to serialize. + /// @return Returns a typed `Offset` into the serialized data indicating + /// where the vector is stored. + template + Offset> CreateVectorOfNativeStructs(const S *v, + size_t len) { + extern T Pack(const S &); + return CreateVectorOfNativeStructs(v, len, Pack); + } + + /// @brief Serialize an array of structs into a FlatBuffer `vector`. + /// @tparam T The data type of the struct array elements. + /// @param[in] filler A function that takes the current iteration + /// 0..vector_size-1 and a pointer to the struct that must be filled. + /// @return Returns a typed `Offset` into the serialized data indicating + /// where the vector is stored. + /// This is mostly useful when flatbuffers are generated with mutation + /// accessors. + template + Offset> CreateVectorOfStructs( + size_t vector_size, const std::function &filler) { + T *structs = StartVectorOfStructs(vector_size); + for (size_t i = 0; i < vector_size; i++) { + filler(i, structs); + structs++; + } + return EndVectorOfStructs(vector_size); + } + + /// @brief Serialize an array of structs into a FlatBuffer `vector`. + /// @tparam T The data type of the struct array elements. + /// @param[in] f A function that takes the current iteration 0..vector_size-1, + /// a pointer to the struct that must be filled and the state argument. + /// @param[in] state Arbitrary state to pass to f. + /// @return Returns a typed `Offset` into the serialized data indicating + /// where the vector is stored. + /// This is mostly useful when flatbuffers are generated with mutation + /// accessors. + template + Offset> CreateVectorOfStructs(size_t vector_size, F f, + S *state) { + T *structs = StartVectorOfStructs(vector_size); + for (size_t i = 0; i < vector_size; i++) { + f(i, structs, state); + structs++; + } + return EndVectorOfStructs(vector_size); + } + + /// @brief Serialize a `std::vector` of structs into a FlatBuffer `vector`. + /// @tparam T The data type of the `std::vector` struct elements. + /// @param[in] v A const reference to the `std::vector` of structs to + /// serialize into the buffer as a `vector`. + /// @return Returns a typed `Offset` into the serialized data indicating + /// where the vector is stored. + template> + Offset> CreateVectorOfStructs( + const std::vector &v) { + return CreateVectorOfStructs(data(v), v.size()); + } + + /// @brief Serialize a `std::vector` of native structs into a FlatBuffer + /// `vector`. + /// @tparam T The data type of the `std::vector` struct elements. + /// @tparam S The data type of the `std::vector` native struct elements. + /// @param[in] v A const reference to the `std::vector` of structs to + /// serialize into the buffer as a `vector`. + /// @param[in] pack_func Pointer to a function to convert the native struct + /// to the FlatBuffer struct. + /// @return Returns a typed `Offset` into the serialized data indicating + /// where the vector is stored. + template> + Offset> CreateVectorOfNativeStructs( + const std::vector &v, T (*const pack_func)(const S &)) { + return CreateVectorOfNativeStructs(data(v), v.size(), pack_func); + } + + /// @brief Serialize a `std::vector` of native structs into a FlatBuffer + /// `vector`. + /// @tparam T The data type of the `std::vector` struct elements. + /// @tparam S The data type of the `std::vector` native struct elements. + /// @param[in] v A const reference to the `std::vector` of structs to + /// serialize into the buffer as a `vector`. + /// @return Returns a typed `Offset` into the serialized data indicating + /// where the vector is stored. + template> + Offset> CreateVectorOfNativeStructs( + const std::vector &v) { + return CreateVectorOfNativeStructs(data(v), v.size()); + } + + /// @cond FLATBUFFERS_INTERNAL + template struct StructKeyComparator { + bool operator()(const T &a, const T &b) const { + return a.KeyCompareLessThan(&b); + } + }; + /// @endcond + + /// @brief Serialize a `std::vector` of structs into a FlatBuffer `vector` + /// in sorted order. + /// @tparam T The data type of the `std::vector` struct elements. + /// @param[in] v A const reference to the `std::vector` of structs to + /// serialize into the buffer as a `vector`. + /// @return Returns a typed `Offset` into the serialized data indicating + /// where the vector is stored. + template> + Offset> CreateVectorOfSortedStructs( + std::vector *v) { + return CreateVectorOfSortedStructs(data(*v), v->size()); + } + + /// @brief Serialize a `std::vector` of native structs into a FlatBuffer + /// `vector` in sorted order. + /// @tparam T The data type of the `std::vector` struct elements. + /// @tparam S The data type of the `std::vector` native struct elements. + /// @param[in] v A const reference to the `std::vector` of structs to + /// serialize into the buffer as a `vector`. + /// @return Returns a typed `Offset` into the serialized data indicating + /// where the vector is stored. + template> + Offset> CreateVectorOfSortedNativeStructs( + std::vector *v) { + return CreateVectorOfSortedNativeStructs(data(*v), v->size()); + } + + /// @brief Serialize an array of structs into a FlatBuffer `vector` in sorted + /// order. + /// @tparam T The data type of the struct array elements. + /// @param[in] v A pointer to the array of type `T` to serialize into the + /// buffer as a `vector`. + /// @param[in] len The number of elements to serialize. + /// @return Returns a typed `Offset` into the serialized data indicating + /// where the vector is stored. + template + Offset> CreateVectorOfSortedStructs(T *v, size_t len) { + std::stable_sort(v, v + len, StructKeyComparator()); + return CreateVectorOfStructs(v, len); + } + + /// @brief Serialize an array of native structs into a FlatBuffer `vector` in + /// sorted order. + /// @tparam T The data type of the struct array elements. + /// @tparam S The data type of the native struct array elements. + /// @param[in] v A pointer to the array of type `S` to serialize into the + /// buffer as a `vector`. + /// @param[in] len The number of elements to serialize. + /// @return Returns a typed `Offset` into the serialized data indicating + /// where the vector is stored. + template + Offset> CreateVectorOfSortedNativeStructs(S *v, + size_t len) { + extern T Pack(const S &); + auto structs = StartVectorOfStructs(len); + for (size_t i = 0; i < len; i++) { structs[i] = Pack(v[i]); } + std::stable_sort(structs, structs + len, StructKeyComparator()); + return EndVectorOfStructs(len); + } + + /// @cond FLATBUFFERS_INTERNAL + template struct TableKeyComparator { + TableKeyComparator(vector_downward &buf) : buf_(buf) {} + TableKeyComparator(const TableKeyComparator &other) : buf_(other.buf_) {} + bool operator()(const Offset &a, const Offset &b) const { + auto table_a = reinterpret_cast(buf_.data_at(a.o)); + auto table_b = reinterpret_cast(buf_.data_at(b.o)); + return table_a->KeyCompareLessThan(table_b); + } + vector_downward &buf_; + + private: + FLATBUFFERS_DELETE_FUNC( + TableKeyComparator &operator=(const TableKeyComparator &other)); + }; + /// @endcond + + /// @brief Serialize an array of `table` offsets as a `vector` in the buffer + /// in sorted order. + /// @tparam T The data type that the offset refers to. + /// @param[in] v An array of type `Offset` that contains the `table` + /// offsets to store in the buffer in sorted order. + /// @param[in] len The number of elements to store in the `vector`. + /// @return Returns a typed `Offset` into the serialized data indicating + /// where the vector is stored. + template + Offset>> CreateVectorOfSortedTables(Offset *v, + size_t len) { + std::stable_sort(v, v + len, TableKeyComparator(buf_)); + return CreateVector(v, len); + } + + /// @brief Serialize an array of `table` offsets as a `vector` in the buffer + /// in sorted order. + /// @tparam T The data type that the offset refers to. + /// @param[in] v An array of type `Offset` that contains the `table` + /// offsets to store in the buffer in sorted order. + /// @return Returns a typed `Offset` into the serialized data indicating + /// where the vector is stored. + template> + Offset>> CreateVectorOfSortedTables( + std::vector, Alloc> *v) { + return CreateVectorOfSortedTables(data(*v), v->size()); + } + + /// @brief Specialized version of `CreateVector` for non-copying use cases. + /// Write the data any time later to the returned buffer pointer `buf`. + /// @param[in] len The number of elements to store in the `vector`. + /// @param[in] elemsize The size of each element in the `vector`. + /// @param[out] buf A pointer to a `uint8_t` pointer that can be + /// written to at a later time to serialize the data into a `vector` + /// in the buffer. + uoffset_t CreateUninitializedVector(size_t len, size_t elemsize, + uint8_t **buf) { + NotNested(); + StartVector(len, elemsize); + buf_.make_space(len * elemsize); + auto vec_start = GetSize(); + auto vec_end = EndVector(len); + *buf = buf_.data_at(vec_start); + return vec_end; + } + + /// @brief Specialized version of `CreateVector` for non-copying use cases. + /// Write the data any time later to the returned buffer pointer `buf`. + /// @tparam T The data type of the data that will be stored in the buffer + /// as a `vector`. + /// @param[in] len The number of elements to store in the `vector`. + /// @param[out] buf A pointer to a pointer of type `T` that can be + /// written to at a later time to serialize the data into a `vector` + /// in the buffer. + template + Offset> CreateUninitializedVector(size_t len, T **buf) { + AssertScalarT(); + return CreateUninitializedVector(len, sizeof(T), + reinterpret_cast(buf)); + } + + template + Offset> CreateUninitializedVectorOfStructs(size_t len, + T **buf) { + return CreateUninitializedVector(len, sizeof(T), + reinterpret_cast(buf)); + } + + // @brief Create a vector of scalar type T given as input a vector of scalar + // type U, useful with e.g. pre "enum class" enums, or any existing scalar + // data of the wrong type. + template + Offset> CreateVectorScalarCast(const U *v, size_t len) { + AssertScalarT(); + AssertScalarT(); + StartVector(len, sizeof(T)); + for (auto i = len; i > 0;) { PushElement(static_cast(v[--i])); } + return Offset>(EndVector(len)); + } + + /// @brief Write a struct by itself, typically to be part of a union. + template Offset CreateStruct(const T &structobj) { + NotNested(); + Align(AlignOf()); + buf_.push_small(structobj); + return Offset(GetSize()); + } + + /// @brief Finish serializing a buffer by writing the root offset. + /// @param[in] file_identifier If a `file_identifier` is given, the buffer + /// will be prefixed with a standard FlatBuffers file header. + template + void Finish(Offset root, const char *file_identifier = nullptr) { + Finish(root.o, file_identifier, false); + } + + /// @brief Finish a buffer with a 32 bit size field pre-fixed (size of the + /// buffer following the size field). These buffers are NOT compatible + /// with standard buffers created by Finish, i.e. you can't call GetRoot + /// on them, you have to use GetSizePrefixedRoot instead. + /// All >32 bit quantities in this buffer will be aligned when the whole + /// size pre-fixed buffer is aligned. + /// These kinds of buffers are useful for creating a stream of FlatBuffers. + template + void FinishSizePrefixed(Offset root, + const char *file_identifier = nullptr) { + Finish(root.o, file_identifier, true); + } + + void SwapBufAllocator(FlatBufferBuilder &other) { + buf_.swap_allocator(other.buf_); + } + + /// @brief The length of a FlatBuffer file header. + static const size_t kFileIdentifierLength = + ::mapserver::flatbuffers::kFileIdentifierLength; + + protected: + // You shouldn't really be copying instances of this class. + FlatBufferBuilder(const FlatBufferBuilder &); + FlatBufferBuilder &operator=(const FlatBufferBuilder &); + + void Finish(uoffset_t root, const char *file_identifier, bool size_prefix) { + NotNested(); + buf_.clear_scratch(); + // This will cause the whole buffer to be aligned. + PreAlign((size_prefix ? sizeof(uoffset_t) : 0) + sizeof(uoffset_t) + + (file_identifier ? kFileIdentifierLength : 0), + minalign_); + if (file_identifier) { + FLATBUFFERS_ASSERT(strlen(file_identifier) == kFileIdentifierLength); + PushBytes(reinterpret_cast(file_identifier), + kFileIdentifierLength); + } + PushElement(ReferTo(root)); // Location of root. + if (size_prefix) { PushElement(GetSize()); } + finished = true; + } + + struct FieldLoc { + uoffset_t off; + voffset_t id; + }; + + vector_downward buf_; + + // Accumulating offsets of table members while it is being built. + // We store these in the scratch pad of buf_, after the vtable offsets. + uoffset_t num_field_loc; + // Track how much of the vtable is in use, so we can output the most compact + // possible vtable. + voffset_t max_voffset_; + + // Ensure objects are not nested. + bool nested; + + // Ensure the buffer is finished before it is being accessed. + bool finished; + + size_t minalign_; + + bool force_defaults_; // Serialize values equal to their defaults anyway. + + bool dedup_vtables_; + + struct StringOffsetCompare { + StringOffsetCompare(const vector_downward &buf) : buf_(&buf) {} + bool operator()(const Offset &a, const Offset &b) const { + auto stra = reinterpret_cast(buf_->data_at(a.o)); + auto strb = reinterpret_cast(buf_->data_at(b.o)); + return StringLessThan(stra->data(), stra->size(), strb->data(), + strb->size()); + } + const vector_downward *buf_; + }; + + // For use with CreateSharedString. Instantiated on first use only. + typedef std::set, StringOffsetCompare> StringOffsetMap; + StringOffsetMap *string_pool; + + private: + // Allocates space for a vector of structures. + // Must be completed with EndVectorOfStructs(). + template T *StartVectorOfStructs(size_t vector_size) { + StartVector(vector_size * sizeof(T) / AlignOf(), AlignOf()); + return reinterpret_cast(buf_.make_space(vector_size * sizeof(T))); + } + + // End the vector of structures in the flatbuffers. + // Vector should have previously be started with StartVectorOfStructs(). + template + Offset> EndVectorOfStructs(size_t vector_size) { + return Offset>(EndVector(vector_size)); + } +}; +/// @} + +/// Helpers to get a typed pointer to objects that are currently being built. +/// @warning Creating new objects will lead to reallocations and invalidates +/// the pointer! +template +T *GetMutableTemporaryPointer(FlatBufferBuilder &fbb, Offset offset) { + return reinterpret_cast(fbb.GetCurrentBufferPointer() + fbb.GetSize() - + offset.o); +} + +template +const T *GetTemporaryPointer(FlatBufferBuilder &fbb, Offset offset) { + return GetMutableTemporaryPointer(fbb, offset); +} + +template +void FlatBufferBuilder::Required(Offset table, voffset_t field) { + auto table_ptr = reinterpret_cast(buf_.data_at(table.o)); + bool ok = table_ptr->GetOptionalFieldOffset(field) != 0; + // If this fails, the caller will show what field needs to be set. + FLATBUFFERS_ASSERT(ok); + (void)ok; +} + +} // namespace flatbuffers +} // namespace mapserver + +#endif // FLATBUFFERS_VECTOR_DOWNWARD_H_ diff --git a/src/flatgeobuf/include/flatbuffers/flatbuffers.h b/src/flatgeobuf/include/flatbuffers/flatbuffers.h new file mode 100644 index 0000000000..1672765743 --- /dev/null +++ b/src/flatgeobuf/include/flatbuffers/flatbuffers.h @@ -0,0 +1,272 @@ +/* + * Copyright 2014 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLATBUFFERS_H_ +#define FLATBUFFERS_H_ + +// TODO: These includes are for mitigating the pains of users editing their +// source because they relied on flatbuffers.h to include everything for them. +#include "flatbuffers/array.h" +#include "flatbuffers/base.h" +#include "flatbuffers/buffer.h" +#include "flatbuffers/buffer_ref.h" +#include "flatbuffers/detached_buffer.h" +#include "flatbuffers/flatbuffer_builder.h" +#include "flatbuffers/stl_emulation.h" +#include "flatbuffers/string.h" +#include "flatbuffers/struct.h" +#include "flatbuffers/table.h" +#include "flatbuffers/vector.h" +#include "flatbuffers/vector_downward.h" +#include "flatbuffers/verifier.h" + +namespace mapserver { +namespace flatbuffers { + +/// @brief This can compute the start of a FlatBuffer from a root pointer, i.e. +/// it is the opposite transformation of GetRoot(). +/// This may be useful if you want to pass on a root and have the recipient +/// delete the buffer afterwards. +inline const uint8_t *GetBufferStartFromRootPointer(const void *root) { + auto table = reinterpret_cast(root); + auto vtable = table->GetVTable(); + // Either the vtable is before the root or after the root. + auto start = (std::min)(vtable, reinterpret_cast(root)); + // Align to at least sizeof(uoffset_t). + start = reinterpret_cast(reinterpret_cast(start) & + ~(sizeof(uoffset_t) - 1)); + // Additionally, there may be a file_identifier in the buffer, and the root + // offset. The buffer may have been aligned to any size between + // sizeof(uoffset_t) and FLATBUFFERS_MAX_ALIGNMENT (see "force_align"). + // Sadly, the exact alignment is only known when constructing the buffer, + // since it depends on the presence of values with said alignment properties. + // So instead, we simply look at the next uoffset_t values (root, + // file_identifier, and alignment padding) to see which points to the root. + // None of the other values can "impersonate" the root since they will either + // be 0 or four ASCII characters. + static_assert(flatbuffers::kFileIdentifierLength == sizeof(uoffset_t), + "file_identifier is assumed to be the same size as uoffset_t"); + for (auto possible_roots = FLATBUFFERS_MAX_ALIGNMENT / sizeof(uoffset_t) + 1; + possible_roots; possible_roots--) { + start -= sizeof(uoffset_t); + if (ReadScalar(start) + start == + reinterpret_cast(root)) + return start; + } + // We didn't find the root, either the "root" passed isn't really a root, + // or the buffer is corrupt. + // Assert, because calling this function with bad data may cause reads + // outside of buffer boundaries. + FLATBUFFERS_ASSERT(false); + return nullptr; +} + +/// @brief This return the prefixed size of a FlatBuffer. +inline uoffset_t GetPrefixedSize(const uint8_t *buf) { + return ReadScalar(buf); +} + +// Base class for native objects (FlatBuffer data de-serialized into native +// C++ data structures). +// Contains no functionality, purely documentative. +struct NativeTable {}; + +/// @brief Function types to be used with resolving hashes into objects and +/// back again. The resolver gets a pointer to a field inside an object API +/// object that is of the type specified in the schema using the attribute +/// `cpp_type` (it is thus important whatever you write to this address +/// matches that type). The value of this field is initially null, so you +/// may choose to implement a delayed binding lookup using this function +/// if you wish. The resolver does the opposite lookup, for when the object +/// is being serialized again. +typedef uint64_t hash_value_t; +typedef std::function + resolver_function_t; +typedef std::function rehasher_function_t; + +// Helper function to test if a field is present, using any of the field +// enums in the generated code. +// `table` must be a generated table type. Since this is a template parameter, +// this is not typechecked to be a subclass of Table, so beware! +// Note: this function will return false for fields equal to the default +// value, since they're not stored in the buffer (unless force_defaults was +// used). +template +bool IsFieldPresent(const T *table, typename T::FlatBuffersVTableOffset field) { + // Cast, since Table is a private baseclass of any table types. + return reinterpret_cast(table)->CheckField( + static_cast(field)); +} + +// Utility function for reverse lookups on the EnumNames*() functions +// (in the generated C++ code) +// names must be NULL terminated. +inline int LookupEnum(const char **names, const char *name) { + for (const char **p = names; *p; p++) + if (!strcmp(*p, name)) return static_cast(p - names); + return -1; +} + +// These macros allow us to layout a struct with a guarantee that they'll end +// up looking the same on different compilers and platforms. +// It does this by disallowing the compiler to do any padding, and then +// does padding itself by inserting extra padding fields that make every +// element aligned to its own size. +// Additionally, it manually sets the alignment of the struct as a whole, +// which is typically its largest element, or a custom size set in the schema +// by the force_align attribute. +// These are used in the generated code only. + +// clang-format off +#if defined(_MSC_VER) + #define FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(alignment) \ + __pragma(pack(1)) \ + struct __declspec(align(alignment)) + #define FLATBUFFERS_STRUCT_END(name, size) \ + __pragma(pack()) \ + static_assert(sizeof(name) == size, "compiler breaks packing rules") +#elif defined(__GNUC__) || defined(__clang__) || defined(__ICCARM__) + #define FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(alignment) \ + _Pragma("pack(1)") \ + struct __attribute__((aligned(alignment))) + #define FLATBUFFERS_STRUCT_END(name, size) \ + _Pragma("pack()") \ + static_assert(sizeof(name) == size, "compiler breaks packing rules") +#else + #error Unknown compiler, please define structure alignment macros +#endif +// clang-format on + +// Minimal reflection via code generation. +// Besides full-fat reflection (see reflection.h) and parsing/printing by +// loading schemas (see idl.h), we can also have code generation for minimal +// reflection data which allows pretty-printing and other uses without needing +// a schema or a parser. +// Generate code with --reflect-types (types only) or --reflect-names (names +// also) to enable. +// See minireflect.h for utilities using this functionality. + +// These types are organized slightly differently as the ones in idl.h. +enum SequenceType { ST_TABLE, ST_STRUCT, ST_UNION, ST_ENUM }; + +// Scalars have the same order as in idl.h +// clang-format off +#define FLATBUFFERS_GEN_ELEMENTARY_TYPES(ET) \ + ET(ET_UTYPE) \ + ET(ET_BOOL) \ + ET(ET_CHAR) \ + ET(ET_UCHAR) \ + ET(ET_SHORT) \ + ET(ET_USHORT) \ + ET(ET_INT) \ + ET(ET_UINT) \ + ET(ET_LONG) \ + ET(ET_ULONG) \ + ET(ET_FLOAT) \ + ET(ET_DOUBLE) \ + ET(ET_STRING) \ + ET(ET_SEQUENCE) // See SequenceType. + +enum ElementaryType { + #define FLATBUFFERS_ET(E) E, + FLATBUFFERS_GEN_ELEMENTARY_TYPES(FLATBUFFERS_ET) + #undef FLATBUFFERS_ET +}; + +inline const char * const *ElementaryTypeNames() { + static const char * const names[] = { + #define FLATBUFFERS_ET(E) #E, + FLATBUFFERS_GEN_ELEMENTARY_TYPES(FLATBUFFERS_ET) + #undef FLATBUFFERS_ET + }; + return names; +} +// clang-format on + +// Basic type info cost just 16bits per field! +// We're explicitly defining the signedness since the signedness of integer +// bitfields is otherwise implementation-defined and causes warnings on older +// GCC compilers. +struct TypeCode { + // ElementaryType + unsigned short base_type : 4; + // Either vector (in table) or array (in struct) + unsigned short is_repeating : 1; + // Index into type_refs below, or -1 for none. + signed short sequence_ref : 11; +}; + +static_assert(sizeof(TypeCode) == 2, "TypeCode"); + +struct TypeTable; + +// Signature of the static method present in each type. +typedef const TypeTable *(*TypeFunction)(); + +struct TypeTable { + SequenceType st; + size_t num_elems; // of type_codes, values, names (but not type_refs). + const TypeCode *type_codes; // num_elems count + const TypeFunction *type_refs; // less than num_elems entries (see TypeCode). + const int16_t *array_sizes; // less than num_elems entries (see TypeCode). + const int64_t *values; // Only set for non-consecutive enum/union or structs. + const char *const *names; // Only set if compiled with --reflect-names. +}; + +// String which identifies the current version of FlatBuffers. +inline const char *flatbuffers_version_string() { + return "FlatBuffers " FLATBUFFERS_STRING(FLATBUFFERS_VERSION_MAJOR) "." + FLATBUFFERS_STRING(FLATBUFFERS_VERSION_MINOR) "." + FLATBUFFERS_STRING(FLATBUFFERS_VERSION_REVISION); +} + +// clang-format off +#define FLATBUFFERS_DEFINE_BITMASK_OPERATORS(E, T)\ + inline E operator | (E lhs, E rhs){\ + return E(T(lhs) | T(rhs));\ + }\ + inline E operator & (E lhs, E rhs){\ + return E(T(lhs) & T(rhs));\ + }\ + inline E operator ^ (E lhs, E rhs){\ + return E(T(lhs) ^ T(rhs));\ + }\ + inline E operator ~ (E lhs){\ + return E(~T(lhs));\ + }\ + inline E operator |= (E &lhs, E rhs){\ + lhs = lhs | rhs;\ + return lhs;\ + }\ + inline E operator &= (E &lhs, E rhs){\ + lhs = lhs & rhs;\ + return lhs;\ + }\ + inline E operator ^= (E &lhs, E rhs){\ + lhs = lhs ^ rhs;\ + return lhs;\ + }\ + inline bool operator !(E rhs) \ + {\ + return !bool(T(rhs)); \ + } +/// @endcond +} // namespace flatbuffers +} // namespace mapserver + +// clang-format on + +#endif // FLATBUFFERS_H_ diff --git a/src/flatgeobuf/include/flatbuffers/flatc.h b/src/flatgeobuf/include/flatbuffers/flatc.h new file mode 100644 index 0000000000..c6dced3d56 --- /dev/null +++ b/src/flatgeobuf/include/flatbuffers/flatc.h @@ -0,0 +1,118 @@ +/* + * Copyright 2017 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLATBUFFERS_FLATC_H_ +#define FLATBUFFERS_FLATC_H_ + +#include +#include +#include + +#include "flatbuffers/bfbs_generator.h" +#include "flatbuffers/flatbuffers.h" +#include "flatbuffers/idl.h" +#include "flatbuffers/util.h" + +namespace mapserver { +namespace flatbuffers { + +extern void LogCompilerWarn(const std::string &warn); +extern void LogCompilerError(const std::string &err); + +struct FlatCOption { + std::string short_opt; + std::string long_opt; + std::string parameter; + std::string description; +}; + +class FlatCompiler { + public: + // Output generator for the various programming languages and formats we + // support. + struct Generator { + typedef bool (*GenerateFn)(const flatbuffers::Parser &parser, + const std::string &path, + const std::string &file_name); + typedef std::string (*MakeRuleFn)(const flatbuffers::Parser &parser, + const std::string &path, + const std::string &file_name); + typedef bool (*ParsingCompletedFn)(const flatbuffers::Parser &parser, + const std::string &output_path); + + GenerateFn generate; + const char *lang_name; + bool schema_only; + GenerateFn generateGRPC; + flatbuffers::IDLOptions::Language lang; + FlatCOption option; + MakeRuleFn make_rule; + BfbsGenerator *bfbs_generator; + ParsingCompletedFn parsing_completed; + }; + + typedef void (*WarnFn)(const FlatCompiler *flatc, const std::string &warn, + bool show_exe_name); + + typedef void (*ErrorFn)(const FlatCompiler *flatc, const std::string &err, + bool usage, bool show_exe_name); + + // Parameters required to initialize the FlatCompiler. + struct InitParams { + InitParams() + : generators(nullptr), + num_generators(0), + warn_fn(nullptr), + error_fn(nullptr) {} + + const Generator *generators; + size_t num_generators; + WarnFn warn_fn; + ErrorFn error_fn; + }; + + explicit FlatCompiler(const InitParams ¶ms) : params_(params) {} + + int Compile(int argc, const char **argv); + + std::string GetShortUsageString(const char *program_name) const; + std::string GetUsageString(const char *program_name) const; + + private: + void ParseFile(flatbuffers::Parser &parser, const std::string &filename, + const std::string &contents, + std::vector &include_directories) const; + + void LoadBinarySchema(Parser &parser, const std::string &filename, + const std::string &contents); + + void Warn(const std::string &warn, bool show_exe_name = true) const; + + void Error(const std::string &err, bool usage = true, + bool show_exe_name = true) const; + + void AnnotateBinaries(const uint8_t *binary_schema, + uint64_t binary_schema_size, + const std::string & schema_filename, + const std::vector &binary_files); + + InitParams params_; +}; + +} // namespace flatbuffers +} // namespace mapserver + +#endif // FLATBUFFERS_FLATC_H_ diff --git a/src/flatgeobuf/include/flatbuffers/flex_flat_util.h b/src/flatgeobuf/include/flatbuffers/flex_flat_util.h new file mode 100644 index 0000000000..020957ebe4 --- /dev/null +++ b/src/flatgeobuf/include/flatbuffers/flex_flat_util.h @@ -0,0 +1,36 @@ +/* + * Copyright 2022 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLATBUFFERS_FLEX_FLAT_UTIL_H_ +#define FLATBUFFERS_FLEX_FLAT_UTIL_H_ + +#include "flatbuffers/flatbuffers.h" +#include "flatbuffers/flexbuffers.h" + +namespace flexbuffers { + +// Verifies the `nested` flexbuffer within a flatbuffer vector is valid. +inline bool VerifyNestedFlexBuffer( + const flatbuffers::Vector *const nested, + flatbuffers::Verifier &verifier) { + if (!nested) return true; + return verifier.Check(flexbuffers::VerifyBuffer( + nested->data(), nested->size(), verifier.GetFlexReuseTracker())); +} + +} // namespace flexbuffers + +#endif // FLATBUFFERS_FLEX_FLAT_UTIL_H_ diff --git a/src/flatgeobuf/include/flatbuffers/flexbuffers.h b/src/flatgeobuf/include/flatbuffers/flexbuffers.h new file mode 100644 index 0000000000..b4d365e869 --- /dev/null +++ b/src/flatgeobuf/include/flatbuffers/flexbuffers.h @@ -0,0 +1,1888 @@ +/* + * Copyright 2017 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLATBUFFERS_FLEXBUFFERS_H_ +#define FLATBUFFERS_FLEXBUFFERS_H_ + +#include +// Used to select STL variant. +#include "flatbuffers/base.h" +// We use the basic binary writing functions from the regular FlatBuffers. +#include "flatbuffers/util.h" + +#ifdef _MSC_VER +# include +#endif + +#if defined(_MSC_VER) +# pragma warning(push) +# pragma warning(disable : 4127) // C4127: conditional expression is constant +#endif + +namespace flexbuffers { + +class Reference; +class Map; + +// These are used in the lower 2 bits of a type field to determine the size of +// the elements (and or size field) of the item pointed to (e.g. vector). +enum BitWidth { + BIT_WIDTH_8 = 0, + BIT_WIDTH_16 = 1, + BIT_WIDTH_32 = 2, + BIT_WIDTH_64 = 3, +}; + +// These are used as the upper 6 bits of a type field to indicate the actual +// type. +enum Type { + FBT_NULL = 0, + FBT_INT = 1, + FBT_UINT = 2, + FBT_FLOAT = 3, + // Types above stored inline, types below (except FBT_BOOL) store an offset. + FBT_KEY = 4, + FBT_STRING = 5, + FBT_INDIRECT_INT = 6, + FBT_INDIRECT_UINT = 7, + FBT_INDIRECT_FLOAT = 8, + FBT_MAP = 9, + FBT_VECTOR = 10, // Untyped. + FBT_VECTOR_INT = 11, // Typed any size (stores no type table). + FBT_VECTOR_UINT = 12, + FBT_VECTOR_FLOAT = 13, + FBT_VECTOR_KEY = 14, + // DEPRECATED, use FBT_VECTOR or FBT_VECTOR_KEY instead. + // Read test.cpp/FlexBuffersDeprecatedTest() for details on why. + FBT_VECTOR_STRING_DEPRECATED = 15, + FBT_VECTOR_INT2 = 16, // Typed tuple (no type table, no size field). + FBT_VECTOR_UINT2 = 17, + FBT_VECTOR_FLOAT2 = 18, + FBT_VECTOR_INT3 = 19, // Typed triple (no type table, no size field). + FBT_VECTOR_UINT3 = 20, + FBT_VECTOR_FLOAT3 = 21, + FBT_VECTOR_INT4 = 22, // Typed quad (no type table, no size field). + FBT_VECTOR_UINT4 = 23, + FBT_VECTOR_FLOAT4 = 24, + FBT_BLOB = 25, + FBT_BOOL = 26, + FBT_VECTOR_BOOL = + 36, // To Allow the same type of conversion of type to vector type + + FBT_MAX_TYPE = 37 +}; + +inline bool IsInline(Type t) { return t <= FBT_FLOAT || t == FBT_BOOL; } + +inline bool IsTypedVectorElementType(Type t) { + return (t >= FBT_INT && t <= FBT_STRING) || t == FBT_BOOL; +} + +inline bool IsTypedVector(Type t) { + return (t >= FBT_VECTOR_INT && t <= FBT_VECTOR_STRING_DEPRECATED) || + t == FBT_VECTOR_BOOL; +} + +inline bool IsFixedTypedVector(Type t) { + return t >= FBT_VECTOR_INT2 && t <= FBT_VECTOR_FLOAT4; +} + +inline Type ToTypedVector(Type t, size_t fixed_len = 0) { + FLATBUFFERS_ASSERT(IsTypedVectorElementType(t)); + switch (fixed_len) { + case 0: return static_cast(t - FBT_INT + FBT_VECTOR_INT); + case 2: return static_cast(t - FBT_INT + FBT_VECTOR_INT2); + case 3: return static_cast(t - FBT_INT + FBT_VECTOR_INT3); + case 4: return static_cast(t - FBT_INT + FBT_VECTOR_INT4); + default: FLATBUFFERS_ASSERT(0); return FBT_NULL; + } +} + +inline Type ToTypedVectorElementType(Type t) { + FLATBUFFERS_ASSERT(IsTypedVector(t)); + return static_cast(t - FBT_VECTOR_INT + FBT_INT); +} + +inline Type ToFixedTypedVectorElementType(Type t, uint8_t *len) { + FLATBUFFERS_ASSERT(IsFixedTypedVector(t)); + auto fixed_type = t - FBT_VECTOR_INT2; + *len = static_cast(fixed_type / 3 + + 2); // 3 types each, starting from length 2. + return static_cast(fixed_type % 3 + FBT_INT); +} + +// TODO: implement proper support for 8/16bit floats, or decide not to +// support them. +typedef int16_t half; +typedef int8_t quarter; + +// TODO: can we do this without conditionals using intrinsics or inline asm +// on some platforms? Given branch prediction the method below should be +// decently quick, but it is the most frequently executed function. +// We could do an (unaligned) 64-bit read if we ifdef out the platforms for +// which that doesn't work (or where we'd read into un-owned memory). +template +R ReadSizedScalar(const uint8_t *data, uint8_t byte_width) { + return byte_width < 4 + ? (byte_width < 2 + ? static_cast(flatbuffers::ReadScalar(data)) + : static_cast(flatbuffers::ReadScalar(data))) + : (byte_width < 8 + ? static_cast(flatbuffers::ReadScalar(data)) + : static_cast(flatbuffers::ReadScalar(data))); +} + +inline int64_t ReadInt64(const uint8_t *data, uint8_t byte_width) { + return ReadSizedScalar( + data, byte_width); +} + +inline uint64_t ReadUInt64(const uint8_t *data, uint8_t byte_width) { + // This is the "hottest" function (all offset lookups use this), so worth + // optimizing if possible. + // TODO: GCC apparently replaces memcpy by a rep movsb, but only if count is a + // constant, which here it isn't. Test if memcpy is still faster than + // the conditionals in ReadSizedScalar. Can also use inline asm. + + // clang-format off + #if defined(_MSC_VER) && defined(_M_X64) && !defined(_M_ARM64EC) + // This is 64-bit Windows only, __movsb does not work on 32-bit Windows. + uint64_t u = 0; + __movsb(reinterpret_cast(&u), + reinterpret_cast(data), byte_width); + return flatbuffers::EndianScalar(u); + #else + return ReadSizedScalar( + data, byte_width); + #endif + // clang-format on +} + +inline double ReadDouble(const uint8_t *data, uint8_t byte_width) { + return ReadSizedScalar(data, + byte_width); +} + +inline const uint8_t *Indirect(const uint8_t *offset, uint8_t byte_width) { + return offset - ReadUInt64(offset, byte_width); +} + +template const uint8_t *Indirect(const uint8_t *offset) { + return offset - flatbuffers::ReadScalar(offset); +} + +inline BitWidth WidthU(uint64_t u) { +#define FLATBUFFERS_GET_FIELD_BIT_WIDTH(value, width) \ + { \ + if (!((u) & ~((1ULL << (width)) - 1ULL))) return BIT_WIDTH_##width; \ + } + FLATBUFFERS_GET_FIELD_BIT_WIDTH(u, 8); + FLATBUFFERS_GET_FIELD_BIT_WIDTH(u, 16); + FLATBUFFERS_GET_FIELD_BIT_WIDTH(u, 32); +#undef FLATBUFFERS_GET_FIELD_BIT_WIDTH + return BIT_WIDTH_64; +} + +inline BitWidth WidthI(int64_t i) { + auto u = static_cast(i) << 1; + return WidthU(i >= 0 ? u : ~u); +} + +inline BitWidth WidthF(double f) { + return static_cast(static_cast(f)) == f ? BIT_WIDTH_32 + : BIT_WIDTH_64; +} + +// Base class of all types below. +// Points into the data buffer and allows access to one type. +class Object { + public: + Object(const uint8_t *data, uint8_t byte_width) + : data_(data), byte_width_(byte_width) {} + + protected: + const uint8_t *data_; + uint8_t byte_width_; +}; + +// Object that has a size, obtained either from size prefix, or elsewhere. +class Sized : public Object { + public: + // Size prefix. + Sized(const uint8_t *data, uint8_t byte_width) + : Object(data, byte_width), size_(read_size()) {} + // Manual size. + Sized(const uint8_t *data, uint8_t byte_width, size_t sz) + : Object(data, byte_width), size_(sz) {} + size_t size() const { return size_; } + // Access size stored in `byte_width_` bytes before data_ pointer. + size_t read_size() const { + return static_cast(ReadUInt64(data_ - byte_width_, byte_width_)); + } + + protected: + size_t size_; +}; + +class String : public Sized { + public: + // Size prefix. + String(const uint8_t *data, uint8_t byte_width) : Sized(data, byte_width) {} + // Manual size. + String(const uint8_t *data, uint8_t byte_width, size_t sz) + : Sized(data, byte_width, sz) {} + + size_t length() const { return size(); } + const char *c_str() const { return reinterpret_cast(data_); } + std::string str() const { return std::string(c_str(), size()); } + + static String EmptyString() { + static const char *empty_string = ""; + return String(reinterpret_cast(empty_string), 1, 0); + } + bool IsTheEmptyString() const { return data_ == EmptyString().data_; } +}; + +class Blob : public Sized { + public: + Blob(const uint8_t *data_buf, uint8_t byte_width) + : Sized(data_buf, byte_width) {} + + static Blob EmptyBlob() { + static const uint8_t empty_blob[] = { 0 /*len*/ }; + return Blob(empty_blob + 1, 1); + } + bool IsTheEmptyBlob() const { return data_ == EmptyBlob().data_; } + const uint8_t *data() const { return data_; } +}; + +class Vector : public Sized { + public: + Vector(const uint8_t *data, uint8_t byte_width) : Sized(data, byte_width) {} + + Reference operator[](size_t i) const; + + static Vector EmptyVector() { + static const uint8_t empty_vector[] = { 0 /*len*/ }; + return Vector(empty_vector + 1, 1); + } + bool IsTheEmptyVector() const { return data_ == EmptyVector().data_; } +}; + +class TypedVector : public Sized { + public: + TypedVector(const uint8_t *data, uint8_t byte_width, Type element_type) + : Sized(data, byte_width), type_(element_type) {} + + Reference operator[](size_t i) const; + + static TypedVector EmptyTypedVector() { + static const uint8_t empty_typed_vector[] = { 0 /*len*/ }; + return TypedVector(empty_typed_vector + 1, 1, FBT_INT); + } + bool IsTheEmptyVector() const { + return data_ == TypedVector::EmptyTypedVector().data_; + } + + Type ElementType() { return type_; } + + friend Reference; + + private: + Type type_; + + friend Map; +}; + +class FixedTypedVector : public Object { + public: + FixedTypedVector(const uint8_t *data, uint8_t byte_width, Type element_type, + uint8_t len) + : Object(data, byte_width), type_(element_type), len_(len) {} + + Reference operator[](size_t i) const; + + static FixedTypedVector EmptyFixedTypedVector() { + static const uint8_t fixed_empty_vector[] = { 0 /* unused */ }; + return FixedTypedVector(fixed_empty_vector, 1, FBT_INT, 0); + } + bool IsTheEmptyFixedTypedVector() const { + return data_ == FixedTypedVector::EmptyFixedTypedVector().data_; + } + + Type ElementType() const { return type_; } + uint8_t size() const { return len_; } + + private: + Type type_; + uint8_t len_; +}; + +class Map : public Vector { + public: + Map(const uint8_t *data, uint8_t byte_width) : Vector(data, byte_width) {} + + Reference operator[](const char *key) const; + Reference operator[](const std::string &key) const; + + Vector Values() const { return Vector(data_, byte_width_); } + + TypedVector Keys() const { + const size_t num_prefixed_fields = 3; + auto keys_offset = data_ - byte_width_ * num_prefixed_fields; + return TypedVector(Indirect(keys_offset, byte_width_), + static_cast( + ReadUInt64(keys_offset + byte_width_, byte_width_)), + FBT_KEY); + } + + static Map EmptyMap() { + static const uint8_t empty_map[] = { + 0 /*keys_len*/, 0 /*keys_offset*/, 1 /*keys_width*/, 0 /*len*/ + }; + return Map(empty_map + 4, 1); + } + + bool IsTheEmptyMap() const { return data_ == EmptyMap().data_; } +}; + +template +void AppendToString(std::string &s, T &&v, bool keys_quoted) { + s += "[ "; + for (size_t i = 0; i < v.size(); i++) { + if (i) s += ", "; + v[i].ToString(true, keys_quoted, s); + } + s += " ]"; +} + +class Reference { + public: + Reference() + : data_(nullptr), parent_width_(0), byte_width_(0), type_(FBT_NULL) {} + + Reference(const uint8_t *data, uint8_t parent_width, uint8_t byte_width, + Type type) + : data_(data), + parent_width_(parent_width), + byte_width_(byte_width), + type_(type) {} + + Reference(const uint8_t *data, uint8_t parent_width, uint8_t packed_type) + : data_(data), parent_width_(parent_width) { + byte_width_ = 1U << static_cast(packed_type & 3); + type_ = static_cast(packed_type >> 2); + } + + Type GetType() const { return type_; } + + bool IsNull() const { return type_ == FBT_NULL; } + bool IsBool() const { return type_ == FBT_BOOL; } + bool IsInt() const { return type_ == FBT_INT || type_ == FBT_INDIRECT_INT; } + bool IsUInt() const { + return type_ == FBT_UINT || type_ == FBT_INDIRECT_UINT; + } + bool IsIntOrUint() const { return IsInt() || IsUInt(); } + bool IsFloat() const { + return type_ == FBT_FLOAT || type_ == FBT_INDIRECT_FLOAT; + } + bool IsNumeric() const { return IsIntOrUint() || IsFloat(); } + bool IsString() const { return type_ == FBT_STRING; } + bool IsKey() const { return type_ == FBT_KEY; } + bool IsVector() const { return type_ == FBT_VECTOR || type_ == FBT_MAP; } + bool IsUntypedVector() const { return type_ == FBT_VECTOR; } + bool IsTypedVector() const { return flexbuffers::IsTypedVector(type_); } + bool IsFixedTypedVector() const { + return flexbuffers::IsFixedTypedVector(type_); + } + bool IsAnyVector() const { + return (IsTypedVector() || IsFixedTypedVector() || IsVector()); + } + bool IsMap() const { return type_ == FBT_MAP; } + bool IsBlob() const { return type_ == FBT_BLOB; } + bool AsBool() const { + return (type_ == FBT_BOOL ? ReadUInt64(data_, parent_width_) + : AsUInt64()) != 0; + } + + // Reads any type as a int64_t. Never fails, does most sensible conversion. + // Truncates floats, strings are attempted to be parsed for a number, + // vectors/maps return their size. Returns 0 if all else fails. + int64_t AsInt64() const { + if (type_ == FBT_INT) { + // A fast path for the common case. + return ReadInt64(data_, parent_width_); + } else + switch (type_) { + case FBT_INDIRECT_INT: return ReadInt64(Indirect(), byte_width_); + case FBT_UINT: return ReadUInt64(data_, parent_width_); + case FBT_INDIRECT_UINT: return ReadUInt64(Indirect(), byte_width_); + case FBT_FLOAT: + return static_cast(ReadDouble(data_, parent_width_)); + case FBT_INDIRECT_FLOAT: + return static_cast(ReadDouble(Indirect(), byte_width_)); + case FBT_NULL: return 0; + case FBT_STRING: return flatbuffers::StringToInt(AsString().c_str()); + case FBT_VECTOR: return static_cast(AsVector().size()); + case FBT_BOOL: return ReadInt64(data_, parent_width_); + default: + // Convert other things to int. + return 0; + } + } + + // TODO: could specialize these to not use AsInt64() if that saves + // extension ops in generated code, and use a faster op than ReadInt64. + int32_t AsInt32() const { return static_cast(AsInt64()); } + int16_t AsInt16() const { return static_cast(AsInt64()); } + int8_t AsInt8() const { return static_cast(AsInt64()); } + + uint64_t AsUInt64() const { + if (type_ == FBT_UINT) { + // A fast path for the common case. + return ReadUInt64(data_, parent_width_); + } else + switch (type_) { + case FBT_INDIRECT_UINT: return ReadUInt64(Indirect(), byte_width_); + case FBT_INT: return ReadInt64(data_, parent_width_); + case FBT_INDIRECT_INT: return ReadInt64(Indirect(), byte_width_); + case FBT_FLOAT: + return static_cast(ReadDouble(data_, parent_width_)); + case FBT_INDIRECT_FLOAT: + return static_cast(ReadDouble(Indirect(), byte_width_)); + case FBT_NULL: return 0; + case FBT_STRING: return flatbuffers::StringToUInt(AsString().c_str()); + case FBT_VECTOR: return static_cast(AsVector().size()); + case FBT_BOOL: return ReadUInt64(data_, parent_width_); + default: + // Convert other things to uint. + return 0; + } + } + + uint32_t AsUInt32() const { return static_cast(AsUInt64()); } + uint16_t AsUInt16() const { return static_cast(AsUInt64()); } + uint8_t AsUInt8() const { return static_cast(AsUInt64()); } + + double AsDouble() const { + if (type_ == FBT_FLOAT) { + // A fast path for the common case. + return ReadDouble(data_, parent_width_); + } else + switch (type_) { + case FBT_INDIRECT_FLOAT: return ReadDouble(Indirect(), byte_width_); + case FBT_INT: + return static_cast(ReadInt64(data_, parent_width_)); + case FBT_UINT: + return static_cast(ReadUInt64(data_, parent_width_)); + case FBT_INDIRECT_INT: + return static_cast(ReadInt64(Indirect(), byte_width_)); + case FBT_INDIRECT_UINT: + return static_cast(ReadUInt64(Indirect(), byte_width_)); + case FBT_NULL: return 0.0; + case FBT_STRING: { + double d; + flatbuffers::StringToNumber(AsString().c_str(), &d); + return d; + } + case FBT_VECTOR: return static_cast(AsVector().size()); + case FBT_BOOL: + return static_cast(ReadUInt64(data_, parent_width_)); + default: + // Convert strings and other things to float. + return 0; + } + } + + float AsFloat() const { return static_cast(AsDouble()); } + + const char *AsKey() const { + if (type_ == FBT_KEY || type_ == FBT_STRING) { + return reinterpret_cast(Indirect()); + } else { + return ""; + } + } + + // This function returns the empty string if you try to read something that + // is not a string or key. + String AsString() const { + if (type_ == FBT_STRING) { + return String(Indirect(), byte_width_); + } else if (type_ == FBT_KEY) { + auto key = Indirect(); + return String(key, byte_width_, + strlen(reinterpret_cast(key))); + } else { + return String::EmptyString(); + } + } + + // Unlike AsString(), this will convert any type to a std::string. + std::string ToString() const { + std::string s; + ToString(false, false, s); + return s; + } + + // Convert any type to a JSON-like string. strings_quoted determines if + // string values at the top level receive "" quotes (inside other values + // they always do). keys_quoted determines if keys are quoted, at any level. + // TODO(wvo): add further options to have indentation/newlines. + void ToString(bool strings_quoted, bool keys_quoted, std::string &s) const { + if (type_ == FBT_STRING) { + String str(Indirect(), byte_width_); + if (strings_quoted) { + flatbuffers::EscapeString(str.c_str(), str.length(), &s, true, false); + } else { + s.append(str.c_str(), str.length()); + } + } else if (IsKey()) { + auto str = AsKey(); + if (keys_quoted) { + flatbuffers::EscapeString(str, strlen(str), &s, true, false); + } else { + s += str; + } + } else if (IsInt()) { + s += flatbuffers::NumToString(AsInt64()); + } else if (IsUInt()) { + s += flatbuffers::NumToString(AsUInt64()); + } else if (IsFloat()) { + s += flatbuffers::NumToString(AsDouble()); + } else if (IsNull()) { + s += "null"; + } else if (IsBool()) { + s += AsBool() ? "true" : "false"; + } else if (IsMap()) { + s += "{ "; + auto m = AsMap(); + auto keys = m.Keys(); + auto vals = m.Values(); + for (size_t i = 0; i < keys.size(); i++) { + bool kq = keys_quoted; + if (!kq) { + // FlexBuffers keys may contain arbitrary characters, only allow + // unquoted if it looks like an "identifier": + const char *p = keys[i].AsKey(); + if (!flatbuffers::is_alpha(*p) && *p != '_') { + kq = true; + } else { + while (*++p) { + if (!flatbuffers::is_alnum(*p) && *p != '_') { + kq = true; + break; + } + } + } + } + keys[i].ToString(true, kq, s); + s += ": "; + vals[i].ToString(true, keys_quoted, s); + if (i < keys.size() - 1) s += ", "; + } + s += " }"; + } else if (IsVector()) { + AppendToString(s, AsVector(), keys_quoted); + } else if (IsTypedVector()) { + AppendToString(s, AsTypedVector(), keys_quoted); + } else if (IsFixedTypedVector()) { + AppendToString(s, AsFixedTypedVector(), keys_quoted); + } else if (IsBlob()) { + auto blob = AsBlob(); + flatbuffers::EscapeString(reinterpret_cast(blob.data()), + blob.size(), &s, true, false); + } else { + s += "(?)"; + } + } + + // This function returns the empty blob if you try to read a not-blob. + // Strings can be viewed as blobs too. + Blob AsBlob() const { + if (type_ == FBT_BLOB || type_ == FBT_STRING) { + return Blob(Indirect(), byte_width_); + } else { + return Blob::EmptyBlob(); + } + } + + // This function returns the empty vector if you try to read a not-vector. + // Maps can be viewed as vectors too. + Vector AsVector() const { + if (type_ == FBT_VECTOR || type_ == FBT_MAP) { + return Vector(Indirect(), byte_width_); + } else { + return Vector::EmptyVector(); + } + } + + TypedVector AsTypedVector() const { + if (IsTypedVector()) { + auto tv = + TypedVector(Indirect(), byte_width_, ToTypedVectorElementType(type_)); + if (tv.type_ == FBT_STRING) { + // These can't be accessed as strings, since we don't know the bit-width + // of the size field, see the declaration of + // FBT_VECTOR_STRING_DEPRECATED above for details. + // We change the type here to be keys, which are a subtype of strings, + // and will ignore the size field. This will truncate strings with + // embedded nulls. + tv.type_ = FBT_KEY; + } + return tv; + } else { + return TypedVector::EmptyTypedVector(); + } + } + + FixedTypedVector AsFixedTypedVector() const { + if (IsFixedTypedVector()) { + uint8_t len = 0; + auto vtype = ToFixedTypedVectorElementType(type_, &len); + return FixedTypedVector(Indirect(), byte_width_, vtype, len); + } else { + return FixedTypedVector::EmptyFixedTypedVector(); + } + } + + Map AsMap() const { + if (type_ == FBT_MAP) { + return Map(Indirect(), byte_width_); + } else { + return Map::EmptyMap(); + } + } + + template T As() const; + + // Experimental: Mutation functions. + // These allow scalars in an already created buffer to be updated in-place. + // Since by default scalars are stored in the smallest possible space, + // the new value may not fit, in which case these functions return false. + // To avoid this, you can construct the values you intend to mutate using + // Builder::ForceMinimumBitWidth. + bool MutateInt(int64_t i) { + if (type_ == FBT_INT) { + return Mutate(data_, i, parent_width_, WidthI(i)); + } else if (type_ == FBT_INDIRECT_INT) { + return Mutate(Indirect(), i, byte_width_, WidthI(i)); + } else if (type_ == FBT_UINT) { + auto u = static_cast(i); + return Mutate(data_, u, parent_width_, WidthU(u)); + } else if (type_ == FBT_INDIRECT_UINT) { + auto u = static_cast(i); + return Mutate(Indirect(), u, byte_width_, WidthU(u)); + } else { + return false; + } + } + + bool MutateBool(bool b) { + return type_ == FBT_BOOL && Mutate(data_, b, parent_width_, BIT_WIDTH_8); + } + + bool MutateUInt(uint64_t u) { + if (type_ == FBT_UINT) { + return Mutate(data_, u, parent_width_, WidthU(u)); + } else if (type_ == FBT_INDIRECT_UINT) { + return Mutate(Indirect(), u, byte_width_, WidthU(u)); + } else if (type_ == FBT_INT) { + auto i = static_cast(u); + return Mutate(data_, i, parent_width_, WidthI(i)); + } else if (type_ == FBT_INDIRECT_INT) { + auto i = static_cast(u); + return Mutate(Indirect(), i, byte_width_, WidthI(i)); + } else { + return false; + } + } + + bool MutateFloat(float f) { + if (type_ == FBT_FLOAT) { + return MutateF(data_, f, parent_width_, BIT_WIDTH_32); + } else if (type_ == FBT_INDIRECT_FLOAT) { + return MutateF(Indirect(), f, byte_width_, BIT_WIDTH_32); + } else { + return false; + } + } + + bool MutateFloat(double d) { + if (type_ == FBT_FLOAT) { + return MutateF(data_, d, parent_width_, WidthF(d)); + } else if (type_ == FBT_INDIRECT_FLOAT) { + return MutateF(Indirect(), d, byte_width_, WidthF(d)); + } else { + return false; + } + } + + bool MutateString(const char *str, size_t len) { + auto s = AsString(); + if (s.IsTheEmptyString()) return false; + // This is very strict, could allow shorter strings, but that creates + // garbage. + if (s.length() != len) return false; + memcpy(const_cast(s.c_str()), str, len); + return true; + } + bool MutateString(const char *str) { return MutateString(str, strlen(str)); } + bool MutateString(const std::string &str) { + return MutateString(str.data(), str.length()); + } + + private: + const uint8_t *Indirect() const { + return flexbuffers::Indirect(data_, parent_width_); + } + + template + bool Mutate(const uint8_t *dest, T t, size_t byte_width, + BitWidth value_width) { + auto fits = static_cast(static_cast(1U) << value_width) <= + byte_width; + if (fits) { + t = flatbuffers::EndianScalar(t); + memcpy(const_cast(dest), &t, byte_width); + } + return fits; + } + + template + bool MutateF(const uint8_t *dest, T t, size_t byte_width, + BitWidth value_width) { + if (byte_width == sizeof(double)) + return Mutate(dest, static_cast(t), byte_width, value_width); + if (byte_width == sizeof(float)) + return Mutate(dest, static_cast(t), byte_width, value_width); + FLATBUFFERS_ASSERT(false); + return false; + } + + friend class Verifier; + + const uint8_t *data_; + uint8_t parent_width_; + uint8_t byte_width_; + Type type_; +}; + +// Template specialization for As(). +template<> inline bool Reference::As() const { return AsBool(); } + +template<> inline int8_t Reference::As() const { return AsInt8(); } +template<> inline int16_t Reference::As() const { return AsInt16(); } +template<> inline int32_t Reference::As() const { return AsInt32(); } +template<> inline int64_t Reference::As() const { return AsInt64(); } + +template<> inline uint8_t Reference::As() const { return AsUInt8(); } +template<> inline uint16_t Reference::As() const { + return AsUInt16(); +} +template<> inline uint32_t Reference::As() const { + return AsUInt32(); +} +template<> inline uint64_t Reference::As() const { + return AsUInt64(); +} + +template<> inline double Reference::As() const { return AsDouble(); } +template<> inline float Reference::As() const { return AsFloat(); } + +template<> inline String Reference::As() const { return AsString(); } +template<> inline std::string Reference::As() const { + return AsString().str(); +} + +template<> inline Blob Reference::As() const { return AsBlob(); } +template<> inline Vector Reference::As() const { return AsVector(); } +template<> inline TypedVector Reference::As() const { + return AsTypedVector(); +} +template<> inline FixedTypedVector Reference::As() const { + return AsFixedTypedVector(); +} +template<> inline Map Reference::As() const { return AsMap(); } + +inline uint8_t PackedType(BitWidth bit_width, Type type) { + return static_cast(bit_width | (type << 2)); +} + +inline uint8_t NullPackedType() { return PackedType(BIT_WIDTH_8, FBT_NULL); } + +// Vector accessors. +// Note: if you try to access outside of bounds, you get a Null value back +// instead. Normally this would be an assert, but since this is "dynamically +// typed" data, you may not want that (someone sends you a 2d vector and you +// wanted 3d). +// The Null converts seamlessly into a default value for any other type. +// TODO(wvo): Could introduce an #ifdef that makes this into an assert? +inline Reference Vector::operator[](size_t i) const { + auto len = size(); + if (i >= len) return Reference(nullptr, 1, NullPackedType()); + auto packed_type = (data_ + len * byte_width_)[i]; + auto elem = data_ + i * byte_width_; + return Reference(elem, byte_width_, packed_type); +} + +inline Reference TypedVector::operator[](size_t i) const { + auto len = size(); + if (i >= len) return Reference(nullptr, 1, NullPackedType()); + auto elem = data_ + i * byte_width_; + return Reference(elem, byte_width_, 1, type_); +} + +inline Reference FixedTypedVector::operator[](size_t i) const { + if (i >= len_) return Reference(nullptr, 1, NullPackedType()); + auto elem = data_ + i * byte_width_; + return Reference(elem, byte_width_, 1, type_); +} + +template int KeyCompare(const void *key, const void *elem) { + auto str_elem = reinterpret_cast( + Indirect(reinterpret_cast(elem))); + auto skey = reinterpret_cast(key); + return strcmp(skey, str_elem); +} + +inline Reference Map::operator[](const char *key) const { + auto keys = Keys(); + // We can't pass keys.byte_width_ to the comparison function, so we have + // to pick the right one ahead of time. + int (*comp)(const void *, const void *) = nullptr; + switch (keys.byte_width_) { + case 1: comp = KeyCompare; break; + case 2: comp = KeyCompare; break; + case 4: comp = KeyCompare; break; + case 8: comp = KeyCompare; break; + default: FLATBUFFERS_ASSERT(false); return Reference(); + } + auto res = std::bsearch(key, keys.data_, keys.size(), keys.byte_width_, comp); + if (!res) return Reference(nullptr, 1, NullPackedType()); + auto i = (reinterpret_cast(res) - keys.data_) / keys.byte_width_; + return (*static_cast(this))[i]; +} + +inline Reference Map::operator[](const std::string &key) const { + return (*this)[key.c_str()]; +} + +inline Reference GetRoot(const uint8_t *buffer, size_t size) { + // See Finish() below for the serialization counterpart of this. + // The root starts at the end of the buffer, so we parse backwards from there. + auto end = buffer + size; + auto byte_width = *--end; + auto packed_type = *--end; + end -= byte_width; // The root data item. + return Reference(end, byte_width, packed_type); +} + +inline Reference GetRoot(const std::vector &buffer) { + return GetRoot(buffer.data(), buffer.size()); +} + +// Flags that configure how the Builder behaves. +// The "Share" flags determine if the Builder automatically tries to pool +// this type. Pooling can reduce the size of serialized data if there are +// multiple maps of the same kind, at the expense of slightly slower +// serialization (the cost of lookups) and more memory use (std::set). +// By default this is on for keys, but off for strings. +// Turn keys off if you have e.g. only one map. +// Turn strings on if you expect many non-unique string values. +// Additionally, sharing key vectors can save space if you have maps with +// identical field populations. +enum BuilderFlag { + BUILDER_FLAG_NONE = 0, + BUILDER_FLAG_SHARE_KEYS = 1, + BUILDER_FLAG_SHARE_STRINGS = 2, + BUILDER_FLAG_SHARE_KEYS_AND_STRINGS = 3, + BUILDER_FLAG_SHARE_KEY_VECTORS = 4, + BUILDER_FLAG_SHARE_ALL = 7, +}; + +class Builder FLATBUFFERS_FINAL_CLASS { + public: + Builder(size_t initial_size = 256, + BuilderFlag flags = BUILDER_FLAG_SHARE_KEYS) + : buf_(initial_size), + finished_(false), + has_duplicate_keys_(false), + flags_(flags), + force_min_bit_width_(BIT_WIDTH_8), + key_pool(KeyOffsetCompare(buf_)), + string_pool(StringOffsetCompare(buf_)) { + buf_.clear(); + } + +#ifdef FLATBUFFERS_DEFAULT_DECLARATION + Builder(Builder &&) = default; + Builder &operator=(Builder &&) = default; +#endif + + /// @brief Get the serialized buffer (after you call `Finish()`). + /// @return Returns a vector owned by this class. + const std::vector &GetBuffer() const { + Finished(); + return buf_; + } + + // Size of the buffer. Does not include unfinished values. + size_t GetSize() const { return buf_.size(); } + + // Reset all state so we can re-use the buffer. + void Clear() { + buf_.clear(); + stack_.clear(); + finished_ = false; + // flags_ remains as-is; + force_min_bit_width_ = BIT_WIDTH_8; + key_pool.clear(); + string_pool.clear(); + } + + // All value constructing functions below have two versions: one that + // takes a key (for placement inside a map) and one that doesn't (for inside + // vectors and elsewhere). + + void Null() { stack_.push_back(Value()); } + void Null(const char *key) { + Key(key); + Null(); + } + + void Int(int64_t i) { stack_.push_back(Value(i, FBT_INT, WidthI(i))); } + void Int(const char *key, int64_t i) { + Key(key); + Int(i); + } + + void UInt(uint64_t u) { stack_.push_back(Value(u, FBT_UINT, WidthU(u))); } + void UInt(const char *key, uint64_t u) { + Key(key); + UInt(u); + } + + void Float(float f) { stack_.push_back(Value(f)); } + void Float(const char *key, float f) { + Key(key); + Float(f); + } + + void Double(double f) { stack_.push_back(Value(f)); } + void Double(const char *key, double d) { + Key(key); + Double(d); + } + + void Bool(bool b) { stack_.push_back(Value(b)); } + void Bool(const char *key, bool b) { + Key(key); + Bool(b); + } + + void IndirectInt(int64_t i) { PushIndirect(i, FBT_INDIRECT_INT, WidthI(i)); } + void IndirectInt(const char *key, int64_t i) { + Key(key); + IndirectInt(i); + } + + void IndirectUInt(uint64_t u) { + PushIndirect(u, FBT_INDIRECT_UINT, WidthU(u)); + } + void IndirectUInt(const char *key, uint64_t u) { + Key(key); + IndirectUInt(u); + } + + void IndirectFloat(float f) { + PushIndirect(f, FBT_INDIRECT_FLOAT, BIT_WIDTH_32); + } + void IndirectFloat(const char *key, float f) { + Key(key); + IndirectFloat(f); + } + + void IndirectDouble(double f) { + PushIndirect(f, FBT_INDIRECT_FLOAT, WidthF(f)); + } + void IndirectDouble(const char *key, double d) { + Key(key); + IndirectDouble(d); + } + + size_t Key(const char *str, size_t len) { + auto sloc = buf_.size(); + WriteBytes(str, len + 1); + if (flags_ & BUILDER_FLAG_SHARE_KEYS) { + auto it = key_pool.find(sloc); + if (it != key_pool.end()) { + // Already in the buffer. Remove key we just serialized, and use + // existing offset instead. + buf_.resize(sloc); + sloc = *it; + } else { + key_pool.insert(sloc); + } + } + stack_.push_back(Value(static_cast(sloc), FBT_KEY, BIT_WIDTH_8)); + return sloc; + } + + size_t Key(const char *str) { return Key(str, strlen(str)); } + size_t Key(const std::string &str) { return Key(str.c_str(), str.size()); } + + size_t String(const char *str, size_t len) { + auto reset_to = buf_.size(); + auto sloc = CreateBlob(str, len, 1, FBT_STRING); + if (flags_ & BUILDER_FLAG_SHARE_STRINGS) { + StringOffset so(sloc, len); + auto it = string_pool.find(so); + if (it != string_pool.end()) { + // Already in the buffer. Remove string we just serialized, and use + // existing offset instead. + buf_.resize(reset_to); + sloc = it->first; + stack_.back().u_ = sloc; + } else { + string_pool.insert(so); + } + } + return sloc; + } + size_t String(const char *str) { return String(str, strlen(str)); } + size_t String(const std::string &str) { + return String(str.c_str(), str.size()); + } + void String(const flexbuffers::String &str) { + String(str.c_str(), str.length()); + } + + void String(const char *key, const char *str) { + Key(key); + String(str); + } + void String(const char *key, const std::string &str) { + Key(key); + String(str); + } + void String(const char *key, const flexbuffers::String &str) { + Key(key); + String(str); + } + + size_t Blob(const void *data, size_t len) { + return CreateBlob(data, len, 0, FBT_BLOB); + } + size_t Blob(const std::vector &v) { + return CreateBlob(v.data(), v.size(), 0, FBT_BLOB); + } + + void Blob(const char *key, const void *data, size_t len) { + Key(key); + Blob(data, len); + } + void Blob(const char *key, const std::vector &v) { + Key(key); + Blob(v); + } + + // TODO(wvo): support all the FlexBuffer types (like flexbuffers::String), + // e.g. Vector etc. Also in overloaded versions. + // Also some FlatBuffers types? + + size_t StartVector() { return stack_.size(); } + size_t StartVector(const char *key) { + Key(key); + return stack_.size(); + } + size_t StartMap() { return stack_.size(); } + size_t StartMap(const char *key) { + Key(key); + return stack_.size(); + } + + // TODO(wvo): allow this to specify an alignment greater than the natural + // alignment. + size_t EndVector(size_t start, bool typed, bool fixed) { + auto vec = CreateVector(start, stack_.size() - start, 1, typed, fixed); + // Remove temp elements and return vector. + stack_.resize(start); + stack_.push_back(vec); + return static_cast(vec.u_); + } + + size_t EndMap(size_t start) { + // We should have interleaved keys and values on the stack. + // Make sure it is an even number: + auto len = stack_.size() - start; + FLATBUFFERS_ASSERT(!(len & 1)); + len /= 2; + // Make sure keys are all strings: + for (auto key = start; key < stack_.size(); key += 2) { + FLATBUFFERS_ASSERT(stack_[key].type_ == FBT_KEY); + } + // Now sort values, so later we can do a binary search lookup. + // We want to sort 2 array elements at a time. + struct TwoValue { + Value key; + Value val; + }; + // TODO(wvo): strict aliasing? + // TODO(wvo): allow the caller to indicate the data is already sorted + // for maximum efficiency? With an assert to check sortedness to make sure + // we're not breaking binary search. + // Or, we can track if the map is sorted as keys are added which would be + // be quite cheap (cheaper than checking it here), so we can skip this + // step automatically when appliccable, and encourage people to write in + // sorted fashion. + // std::sort is typically already a lot faster on sorted data though. + auto dict = reinterpret_cast(stack_.data() + start); + std::sort( + dict, dict + len, [&](const TwoValue &a, const TwoValue &b) -> bool { + auto as = reinterpret_cast(buf_.data() + a.key.u_); + auto bs = reinterpret_cast(buf_.data() + b.key.u_); + auto comp = strcmp(as, bs); + // We want to disallow duplicate keys, since this results in a + // map where values cannot be found. + // But we can't assert here (since we don't want to fail on + // random JSON input) or have an error mechanism. + // Instead, we set has_duplicate_keys_ in the builder to + // signal this. + // TODO: Have to check for pointer equality, as some sort + // implementation apparently call this function with the same + // element?? Why? + if (!comp && &a != &b) has_duplicate_keys_ = true; + return comp < 0; + }); + // First create a vector out of all keys. + // TODO(wvo): if kBuilderFlagShareKeyVectors is true, see if we can share + // the first vector. + auto keys = CreateVector(start, len, 2, true, false); + auto vec = CreateVector(start + 1, len, 2, false, false, &keys); + // Remove temp elements and return map. + stack_.resize(start); + stack_.push_back(vec); + return static_cast(vec.u_); + } + + // Call this after EndMap to see if the map had any duplicate keys. + // Any map with such keys won't be able to retrieve all values. + bool HasDuplicateKeys() const { return has_duplicate_keys_; } + + template size_t Vector(F f) { + auto start = StartVector(); + f(); + return EndVector(start, false, false); + } + template size_t Vector(F f, T &state) { + auto start = StartVector(); + f(state); + return EndVector(start, false, false); + } + template size_t Vector(const char *key, F f) { + auto start = StartVector(key); + f(); + return EndVector(start, false, false); + } + template + size_t Vector(const char *key, F f, T &state) { + auto start = StartVector(key); + f(state); + return EndVector(start, false, false); + } + + template void Vector(const T *elems, size_t len) { + if (flatbuffers::is_scalar::value) { + // This path should be a lot quicker and use less space. + ScalarVector(elems, len, false); + } else { + auto start = StartVector(); + for (size_t i = 0; i < len; i++) Add(elems[i]); + EndVector(start, false, false); + } + } + template + void Vector(const char *key, const T *elems, size_t len) { + Key(key); + Vector(elems, len); + } + template void Vector(const std::vector &vec) { + Vector(vec.data(), vec.size()); + } + + template size_t TypedVector(F f) { + auto start = StartVector(); + f(); + return EndVector(start, true, false); + } + template size_t TypedVector(F f, T &state) { + auto start = StartVector(); + f(state); + return EndVector(start, true, false); + } + template size_t TypedVector(const char *key, F f) { + auto start = StartVector(key); + f(); + return EndVector(start, true, false); + } + template + size_t TypedVector(const char *key, F f, T &state) { + auto start = StartVector(key); + f(state); + return EndVector(start, true, false); + } + + template size_t FixedTypedVector(const T *elems, size_t len) { + // We only support a few fixed vector lengths. Anything bigger use a + // regular typed vector. + FLATBUFFERS_ASSERT(len >= 2 && len <= 4); + // And only scalar values. + static_assert(flatbuffers::is_scalar::value, "Unrelated types"); + return ScalarVector(elems, len, true); + } + + template + size_t FixedTypedVector(const char *key, const T *elems, size_t len) { + Key(key); + return FixedTypedVector(elems, len); + } + + template size_t Map(F f) { + auto start = StartMap(); + f(); + return EndMap(start); + } + template size_t Map(F f, T &state) { + auto start = StartMap(); + f(state); + return EndMap(start); + } + template size_t Map(const char *key, F f) { + auto start = StartMap(key); + f(); + return EndMap(start); + } + template size_t Map(const char *key, F f, T &state) { + auto start = StartMap(key); + f(state); + return EndMap(start); + } + template void Map(const std::map &map) { + auto start = StartMap(); + for (auto it = map.begin(); it != map.end(); ++it) + Add(it->first.c_str(), it->second); + EndMap(start); + } + + // If you wish to share a value explicitly (a value not shared automatically + // through one of the BUILDER_FLAG_SHARE_* flags) you can do so with these + // functions. Or if you wish to turn those flags off for performance reasons + // and still do some explicit sharing. For example: + // builder.IndirectDouble(M_PI); + // auto id = builder.LastValue(); // Remember where we stored it. + // .. more code goes here .. + // builder.ReuseValue(id); // Refers to same double by offset. + // LastValue works regardless of whether the value has a key or not. + // Works on any data type. + struct Value; + Value LastValue() { return stack_.back(); } + void ReuseValue(Value v) { stack_.push_back(v); } + void ReuseValue(const char *key, Value v) { + Key(key); + ReuseValue(v); + } + + // Overloaded Add that tries to call the correct function above. + void Add(int8_t i) { Int(i); } + void Add(int16_t i) { Int(i); } + void Add(int32_t i) { Int(i); } + void Add(int64_t i) { Int(i); } + void Add(uint8_t u) { UInt(u); } + void Add(uint16_t u) { UInt(u); } + void Add(uint32_t u) { UInt(u); } + void Add(uint64_t u) { UInt(u); } + void Add(float f) { Float(f); } + void Add(double d) { Double(d); } + void Add(bool b) { Bool(b); } + void Add(const char *str) { String(str); } + void Add(const std::string &str) { String(str); } + void Add(const flexbuffers::String &str) { String(str); } + + template void Add(const std::vector &vec) { Vector(vec); } + + template void Add(const char *key, const T &t) { + Key(key); + Add(t); + } + + template void Add(const std::map &map) { + Map(map); + } + + template void operator+=(const T &t) { Add(t); } + + // This function is useful in combination with the Mutate* functions above. + // It forces elements of vectors and maps to have a minimum size, such that + // they can later be updated without failing. + // Call with no arguments to reset. + void ForceMinimumBitWidth(BitWidth bw = BIT_WIDTH_8) { + force_min_bit_width_ = bw; + } + + void Finish() { + // If you hit this assert, you likely have objects that were never included + // in a parent. You need to have exactly one root to finish a buffer. + // Check your Start/End calls are matched, and all objects are inside + // some other object. + FLATBUFFERS_ASSERT(stack_.size() == 1); + + // Write root value. + auto byte_width = Align(stack_[0].ElemWidth(buf_.size(), 0)); + WriteAny(stack_[0], byte_width); + // Write root type. + Write(stack_[0].StoredPackedType(), 1); + // Write root size. Normally determined by parent, but root has no parent :) + Write(byte_width, 1); + + finished_ = true; + } + + private: + void Finished() const { + // If you get this assert, you're attempting to get access a buffer + // which hasn't been finished yet. Be sure to call + // Builder::Finish with your root object. + FLATBUFFERS_ASSERT(finished_); + } + + // Align to prepare for writing a scalar with a certain size. + uint8_t Align(BitWidth alignment) { + auto byte_width = 1U << alignment; + buf_.insert(buf_.end(), flatbuffers::PaddingBytes(buf_.size(), byte_width), + 0); + return static_cast(byte_width); + } + + void WriteBytes(const void *val, size_t size) { + buf_.insert(buf_.end(), reinterpret_cast(val), + reinterpret_cast(val) + size); + } + + template void Write(T val, size_t byte_width) { + FLATBUFFERS_ASSERT(sizeof(T) >= byte_width); + val = flatbuffers::EndianScalar(val); + WriteBytes(&val, byte_width); + } + + void WriteDouble(double f, uint8_t byte_width) { + switch (byte_width) { + case 8: Write(f, byte_width); break; + case 4: Write(static_cast(f), byte_width); break; + // case 2: Write(static_cast(f), byte_width); break; + // case 1: Write(static_cast(f), byte_width); break; + default: FLATBUFFERS_ASSERT(0); + } + } + + void WriteOffset(uint64_t o, uint8_t byte_width) { + auto reloff = buf_.size() - o; + FLATBUFFERS_ASSERT(byte_width == 8 || reloff < 1ULL << (byte_width * 8)); + Write(reloff, byte_width); + } + + template void PushIndirect(T val, Type type, BitWidth bit_width) { + auto byte_width = Align(bit_width); + auto iloc = buf_.size(); + Write(val, byte_width); + stack_.push_back(Value(static_cast(iloc), type, bit_width)); + } + + static BitWidth WidthB(size_t byte_width) { + switch (byte_width) { + case 1: return BIT_WIDTH_8; + case 2: return BIT_WIDTH_16; + case 4: return BIT_WIDTH_32; + case 8: return BIT_WIDTH_64; + default: FLATBUFFERS_ASSERT(false); return BIT_WIDTH_64; + } + } + + template static Type GetScalarType() { + static_assert(flatbuffers::is_scalar::value, "Unrelated types"); + return flatbuffers::is_floating_point::value + ? FBT_FLOAT + : flatbuffers::is_same::value + ? FBT_BOOL + : (flatbuffers::is_unsigned::value ? FBT_UINT + : FBT_INT); + } + + public: + // This was really intended to be private, except for LastValue/ReuseValue. + struct Value { + union { + int64_t i_; + uint64_t u_; + double f_; + }; + + Type type_; + + // For scalars: of itself, for vector: of its elements, for string: length. + BitWidth min_bit_width_; + + Value() : i_(0), type_(FBT_NULL), min_bit_width_(BIT_WIDTH_8) {} + + Value(bool b) + : u_(static_cast(b)), + type_(FBT_BOOL), + min_bit_width_(BIT_WIDTH_8) {} + + Value(int64_t i, Type t, BitWidth bw) + : i_(i), type_(t), min_bit_width_(bw) {} + Value(uint64_t u, Type t, BitWidth bw) + : u_(u), type_(t), min_bit_width_(bw) {} + + Value(float f) + : f_(static_cast(f)), + type_(FBT_FLOAT), + min_bit_width_(BIT_WIDTH_32) {} + Value(double f) : f_(f), type_(FBT_FLOAT), min_bit_width_(WidthF(f)) {} + + uint8_t StoredPackedType(BitWidth parent_bit_width_ = BIT_WIDTH_8) const { + return PackedType(StoredWidth(parent_bit_width_), type_); + } + + BitWidth ElemWidth(size_t buf_size, size_t elem_index) const { + if (IsInline(type_)) { + return min_bit_width_; + } else { + // We have an absolute offset, but want to store a relative offset + // elem_index elements beyond the current buffer end. Since whether + // the relative offset fits in a certain byte_width depends on + // the size of the elements before it (and their alignment), we have + // to test for each size in turn. + for (size_t byte_width = 1; + byte_width <= sizeof(flatbuffers::largest_scalar_t); + byte_width *= 2) { + // Where are we going to write this offset? + auto offset_loc = buf_size + + flatbuffers::PaddingBytes(buf_size, byte_width) + + elem_index * byte_width; + // Compute relative offset. + auto offset = offset_loc - u_; + // Does it fit? + auto bit_width = WidthU(offset); + if (static_cast(static_cast(1U) << bit_width) == + byte_width) + return bit_width; + } + FLATBUFFERS_ASSERT(false); // Must match one of the sizes above. + return BIT_WIDTH_64; + } + } + + BitWidth StoredWidth(BitWidth parent_bit_width_ = BIT_WIDTH_8) const { + if (IsInline(type_)) { + return (std::max)(min_bit_width_, parent_bit_width_); + } else { + return min_bit_width_; + } + } + }; + + private: + void WriteAny(const Value &val, uint8_t byte_width) { + switch (val.type_) { + case FBT_NULL: + case FBT_INT: Write(val.i_, byte_width); break; + case FBT_BOOL: + case FBT_UINT: Write(val.u_, byte_width); break; + case FBT_FLOAT: WriteDouble(val.f_, byte_width); break; + default: WriteOffset(val.u_, byte_width); break; + } + } + + size_t CreateBlob(const void *data, size_t len, size_t trailing, Type type) { + auto bit_width = WidthU(len); + auto byte_width = Align(bit_width); + Write(len, byte_width); + auto sloc = buf_.size(); + WriteBytes(data, len + trailing); + stack_.push_back(Value(static_cast(sloc), type, bit_width)); + return sloc; + } + + template + size_t ScalarVector(const T *elems, size_t len, bool fixed) { + auto vector_type = GetScalarType(); + auto byte_width = sizeof(T); + auto bit_width = WidthB(byte_width); + // If you get this assert, you're trying to write a vector with a size + // field that is bigger than the scalars you're trying to write (e.g. a + // byte vector > 255 elements). For such types, write a "blob" instead. + // TODO: instead of asserting, could write vector with larger elements + // instead, though that would be wasteful. + FLATBUFFERS_ASSERT(WidthU(len) <= bit_width); + Align(bit_width); + if (!fixed) Write(len, byte_width); + auto vloc = buf_.size(); + for (size_t i = 0; i < len; i++) Write(elems[i], byte_width); + stack_.push_back(Value(static_cast(vloc), + ToTypedVector(vector_type, fixed ? len : 0), + bit_width)); + return vloc; + } + + Value CreateVector(size_t start, size_t vec_len, size_t step, bool typed, + bool fixed, const Value *keys = nullptr) { + FLATBUFFERS_ASSERT( + !fixed || + typed); // typed=false, fixed=true combination is not supported. + // Figure out smallest bit width we can store this vector with. + auto bit_width = (std::max)(force_min_bit_width_, WidthU(vec_len)); + auto prefix_elems = 1; + if (keys) { + // If this vector is part of a map, we will pre-fix an offset to the keys + // to this vector. + bit_width = (std::max)(bit_width, keys->ElemWidth(buf_.size(), 0)); + prefix_elems += 2; + } + Type vector_type = FBT_KEY; + // Check bit widths and types for all elements. + for (size_t i = start; i < stack_.size(); i += step) { + auto elem_width = + stack_[i].ElemWidth(buf_.size(), i - start + prefix_elems); + bit_width = (std::max)(bit_width, elem_width); + if (typed) { + if (i == start) { + vector_type = stack_[i].type_; + } else { + // If you get this assert, you are writing a typed vector with + // elements that are not all the same type. + FLATBUFFERS_ASSERT(vector_type == stack_[i].type_); + } + } + } + // If you get this assert, your typed types are not one of: + // Int / UInt / Float / Key. + FLATBUFFERS_ASSERT(!typed || IsTypedVectorElementType(vector_type)); + auto byte_width = Align(bit_width); + // Write vector. First the keys width/offset if available, and size. + if (keys) { + WriteOffset(keys->u_, byte_width); + Write(1ULL << keys->min_bit_width_, byte_width); + } + if (!fixed) Write(vec_len, byte_width); + // Then the actual data. + auto vloc = buf_.size(); + for (size_t i = start; i < stack_.size(); i += step) { + WriteAny(stack_[i], byte_width); + } + // Then the types. + if (!typed) { + for (size_t i = start; i < stack_.size(); i += step) { + buf_.push_back(stack_[i].StoredPackedType(bit_width)); + } + } + return Value(static_cast(vloc), + keys ? FBT_MAP + : (typed ? ToTypedVector(vector_type, fixed ? vec_len : 0) + : FBT_VECTOR), + bit_width); + } + + // You shouldn't really be copying instances of this class. + Builder(const Builder &); + Builder &operator=(const Builder &); + + std::vector buf_; + std::vector stack_; + + bool finished_; + bool has_duplicate_keys_; + + BuilderFlag flags_; + + BitWidth force_min_bit_width_; + + struct KeyOffsetCompare { + explicit KeyOffsetCompare(const std::vector &buf) : buf_(&buf) {} + bool operator()(size_t a, size_t b) const { + auto stra = reinterpret_cast(buf_->data() + a); + auto strb = reinterpret_cast(buf_->data() + b); + return strcmp(stra, strb) < 0; + } + const std::vector *buf_; + }; + + typedef std::pair StringOffset; + struct StringOffsetCompare { + explicit StringOffsetCompare(const std::vector &buf) + : buf_(&buf) {} + bool operator()(const StringOffset &a, const StringOffset &b) const { + auto stra = buf_->data() + a.first; + auto strb = buf_->data() + b.first; + auto cr = memcmp(stra, strb, (std::min)(a.second, b.second) + 1); + return cr < 0 || (cr == 0 && a.second < b.second); + } + const std::vector *buf_; + }; + + typedef std::set KeyOffsetMap; + typedef std::set StringOffsetMap; + + KeyOffsetMap key_pool; + StringOffsetMap string_pool; + + friend class Verifier; +}; + +// Helper class to verify the integrity of a FlexBuffer +class Verifier FLATBUFFERS_FINAL_CLASS { + public: + Verifier(const uint8_t *buf, size_t buf_len, + // Supplying this vector likely results in faster verification + // of larger buffers with many shared keys/strings, but + // comes at the cost of using additional memory the same size of + // the buffer being verified, so it is by default off. + std::vector *reuse_tracker = nullptr, + bool _check_alignment = true, size_t max_depth = 64) + : buf_(buf), + size_(buf_len), + depth_(0), + max_depth_(max_depth), + num_vectors_(0), + max_vectors_(buf_len), + check_alignment_(_check_alignment), + reuse_tracker_(reuse_tracker) { + FLATBUFFERS_ASSERT(size_ < FLATBUFFERS_MAX_BUFFER_SIZE); + if (reuse_tracker_) { + reuse_tracker_->clear(); + reuse_tracker_->resize(size_, PackedType(BIT_WIDTH_8, FBT_NULL)); + } + } + + private: + // Central location where any verification failures register. + bool Check(bool ok) const { + // clang-format off + #ifdef FLATBUFFERS_DEBUG_VERIFICATION_FAILURE + FLATBUFFERS_ASSERT(ok); + #endif + // clang-format on + return ok; + } + + // Verify any range within the buffer. + bool VerifyFrom(size_t elem, size_t elem_len) const { + return Check(elem_len < size_ && elem <= size_ - elem_len); + } + bool VerifyBefore(size_t elem, size_t elem_len) const { + return Check(elem_len <= elem); + } + + bool VerifyFromPointer(const uint8_t *p, size_t len) { + auto o = static_cast(p - buf_); + return VerifyFrom(o, len); + } + bool VerifyBeforePointer(const uint8_t *p, size_t len) { + auto o = static_cast(p - buf_); + return VerifyBefore(o, len); + } + + bool VerifyByteWidth(size_t width) { + return Check(width == 1 || width == 2 || width == 4 || width == 8); + } + + bool VerifyType(int type) { return Check(type >= 0 && type < FBT_MAX_TYPE); } + + bool VerifyOffset(uint64_t off, const uint8_t *p) { + return Check(off <= static_cast(size_)) && + off <= static_cast(p - buf_); + } + + bool VerifyAlignment(const uint8_t *p, size_t size) const { + auto o = static_cast(p - buf_); + return Check((o & (size - 1)) == 0 || !check_alignment_); + } + +// Macro, since we want to escape from parent function & use lazy args. +#define FLEX_CHECK_VERIFIED(P, PACKED_TYPE) \ + if (reuse_tracker_) { \ + auto packed_type = PACKED_TYPE; \ + auto existing = (*reuse_tracker_)[P - buf_]; \ + if (existing == packed_type) return true; \ + /* Fail verification if already set with different type! */ \ + if (!Check(existing == 0)) return false; \ + (*reuse_tracker_)[P - buf_] = packed_type; \ + } + + bool VerifyVector(Reference r, const uint8_t *p, Type elem_type) { + // Any kind of nesting goes thru this function, so guard against that + // here, both with simple nesting checks, and the reuse tracker if on. + depth_++; + num_vectors_++; + if (!Check(depth_ <= max_depth_ && num_vectors_ <= max_vectors_)) + return false; + auto size_byte_width = r.byte_width_; + FLEX_CHECK_VERIFIED(p, + PackedType(Builder::WidthB(size_byte_width), r.type_)); + if (!VerifyBeforePointer(p, size_byte_width)) return false; + auto sized = Sized(p, size_byte_width); + auto num_elems = sized.size(); + auto elem_byte_width = r.type_ == FBT_STRING || r.type_ == FBT_BLOB + ? uint8_t(1) + : r.byte_width_; + auto max_elems = SIZE_MAX / elem_byte_width; + if (!Check(num_elems < max_elems)) + return false; // Protect against byte_size overflowing. + auto byte_size = num_elems * elem_byte_width; + if (!VerifyFromPointer(p, byte_size)) return false; + if (elem_type == FBT_NULL) { + // Verify type bytes after the vector. + if (!VerifyFromPointer(p + byte_size, num_elems)) return false; + auto v = Vector(p, size_byte_width); + for (size_t i = 0; i < num_elems; i++) + if (!VerifyRef(v[i])) return false; + } else if (elem_type == FBT_KEY) { + auto v = TypedVector(p, elem_byte_width, FBT_KEY); + for (size_t i = 0; i < num_elems; i++) + if (!VerifyRef(v[i])) return false; + } else { + FLATBUFFERS_ASSERT(IsInline(elem_type)); + } + depth_--; + return true; + } + + bool VerifyKeys(const uint8_t *p, uint8_t byte_width) { + // The vector part of the map has already been verified. + const size_t num_prefixed_fields = 3; + if (!VerifyBeforePointer(p, byte_width * num_prefixed_fields)) return false; + p -= byte_width * num_prefixed_fields; + auto off = ReadUInt64(p, byte_width); + if (!VerifyOffset(off, p)) return false; + auto key_byte_with = + static_cast(ReadUInt64(p + byte_width, byte_width)); + if (!VerifyByteWidth(key_byte_with)) return false; + return VerifyVector(Reference(p, byte_width, key_byte_with, FBT_VECTOR_KEY), + p - off, FBT_KEY); + } + + bool VerifyKey(const uint8_t *p) { + FLEX_CHECK_VERIFIED(p, PackedType(BIT_WIDTH_8, FBT_KEY)); + while (p < buf_ + size_) + if (*p++) return true; + return false; + } + +#undef FLEX_CHECK_VERIFIED + + bool VerifyTerminator(const String &s) { + return VerifyFromPointer(reinterpret_cast(s.c_str()), + s.size() + 1); + } + + bool VerifyRef(Reference r) { + // r.parent_width_ and r.data_ already verified. + if (!VerifyByteWidth(r.byte_width_) || !VerifyType(r.type_)) { + return false; + } + if (IsInline(r.type_)) { + // Inline scalars, don't require further verification. + return true; + } + // All remaining types are an offset. + auto off = ReadUInt64(r.data_, r.parent_width_); + if (!VerifyOffset(off, r.data_)) return false; + auto p = r.Indirect(); + if (!VerifyAlignment(p, r.byte_width_)) return false; + switch (r.type_) { + case FBT_INDIRECT_INT: + case FBT_INDIRECT_UINT: + case FBT_INDIRECT_FLOAT: return VerifyFromPointer(p, r.byte_width_); + case FBT_KEY: return VerifyKey(p); + case FBT_MAP: + return VerifyVector(r, p, FBT_NULL) && VerifyKeys(p, r.byte_width_); + case FBT_VECTOR: return VerifyVector(r, p, FBT_NULL); + case FBT_VECTOR_INT: return VerifyVector(r, p, FBT_INT); + case FBT_VECTOR_BOOL: + case FBT_VECTOR_UINT: return VerifyVector(r, p, FBT_UINT); + case FBT_VECTOR_FLOAT: return VerifyVector(r, p, FBT_FLOAT); + case FBT_VECTOR_KEY: return VerifyVector(r, p, FBT_KEY); + case FBT_VECTOR_STRING_DEPRECATED: + // Use of FBT_KEY here intentional, see elsewhere. + return VerifyVector(r, p, FBT_KEY); + case FBT_BLOB: return VerifyVector(r, p, FBT_UINT); + case FBT_STRING: + return VerifyVector(r, p, FBT_UINT) && + VerifyTerminator(String(p, r.byte_width_)); + case FBT_VECTOR_INT2: + case FBT_VECTOR_UINT2: + case FBT_VECTOR_FLOAT2: + case FBT_VECTOR_INT3: + case FBT_VECTOR_UINT3: + case FBT_VECTOR_FLOAT3: + case FBT_VECTOR_INT4: + case FBT_VECTOR_UINT4: + case FBT_VECTOR_FLOAT4: { + uint8_t len = 0; + auto vtype = ToFixedTypedVectorElementType(r.type_, &len); + if (!VerifyType(vtype)) return false; + return VerifyFromPointer(p, r.byte_width_ * len); + } + default: return false; + } + } + + public: + bool VerifyBuffer() { + if (!Check(size_ >= 3)) return false; + auto end = buf_ + size_; + auto byte_width = *--end; + auto packed_type = *--end; + return VerifyByteWidth(byte_width) && Check(end - buf_ >= byte_width) && + VerifyRef(Reference(end - byte_width, byte_width, packed_type)); + } + + private: + const uint8_t *buf_; + size_t size_; + size_t depth_; + const size_t max_depth_; + size_t num_vectors_; + const size_t max_vectors_; + bool check_alignment_; + std::vector *reuse_tracker_; +}; + +// Utility function that constructs the Verifier for you, see above for +// parameters. +inline bool VerifyBuffer(const uint8_t *buf, size_t buf_len, + std::vector *reuse_tracker = nullptr) { + Verifier verifier(buf, buf_len, reuse_tracker); + return verifier.VerifyBuffer(); +} + +} // namespace flexbuffers + +#if defined(_MSC_VER) +# pragma warning(pop) +#endif + +#endif // FLATBUFFERS_FLEXBUFFERS_H_ diff --git a/src/flatgeobuf/include/flatbuffers/grpc.h b/src/flatgeobuf/include/flatbuffers/grpc.h new file mode 100644 index 0000000000..02c0ad7cf5 --- /dev/null +++ b/src/flatgeobuf/include/flatbuffers/grpc.h @@ -0,0 +1,302 @@ +/* + * Copyright 2014 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLATBUFFERS_GRPC_H_ +#define FLATBUFFERS_GRPC_H_ + +// Helper functionality to glue FlatBuffers and GRPC. + +#include "flatbuffers/flatbuffers.h" +#include "grpc/byte_buffer_reader.h" +#include "grpcpp/support/byte_buffer.h" +#include "grpcpp/support/slice.h" + +namespace mapserver { +namespace flatbuffers { +namespace grpc { + +// Message is a typed wrapper around a buffer that manages the underlying +// `grpc_slice` and also provides flatbuffers-specific helpers such as `Verify` +// and `GetRoot`. Since it is backed by a `grpc_slice`, the underlying buffer +// is refcounted and ownership is be managed automatically. +template class Message { + public: + Message() {} + + Message(::grpc::Slice slice) : slice_(slice) {} + + Message &operator=(const Message &other) = delete; + + Message(Message &&other) = default; + + Message(const Message &other) = delete; + + Message &operator=(Message &&other) = default; + + const uint8_t *mutable_data() const { return slice_.begin(); } + + const uint8_t *data() const { return slice_.begin(); } + + size_t size() const { return slice_.size(); } + + bool Verify() const { + Verifier verifier(data(), size()); + return verifier.VerifyBuffer(nullptr); + } + + T *GetMutableRoot() { return flatbuffers::GetMutableRoot(mutable_data()); } + + const T *GetRoot() const { return flatbuffers::GetRoot(data()); } + + // This is only intended for serializer use, or if you know what you're doing + const ::grpc::Slice &BorrowSlice() const { return slice_; } + + private: + ::grpc::Slice slice_; +}; + +class MessageBuilder; + +// SliceAllocator is a gRPC-specific allocator that uses the `grpc_slice` +// refcounted slices to manage memory ownership. This makes it easy and +// efficient to transfer buffers to gRPC. +class SliceAllocator : public Allocator { + public: + SliceAllocator() {} + + SliceAllocator(const SliceAllocator &other) = delete; + SliceAllocator &operator=(const SliceAllocator &other) = delete; + + SliceAllocator(SliceAllocator &&other) { + // default-construct and swap idiom + swap(other); + } + + SliceAllocator &operator=(SliceAllocator &&other) { + // move-construct and swap idiom + SliceAllocator temp(std::move(other)); + swap(temp); + return *this; + } + + void swap(SliceAllocator &other) { + using std::swap; + swap(slice_, other.slice_); + } + + virtual ~SliceAllocator() {} + + virtual uint8_t *allocate(size_t size) override { + FLATBUFFERS_ASSERT(slice_.size() == 0); + slice_ = ::grpc::Slice(size); + return const_cast(slice_.begin()); + } + + virtual void deallocate(uint8_t *p, size_t size) override { + FLATBUFFERS_ASSERT(p == slice_.begin()); + FLATBUFFERS_ASSERT(size == slice_.size()); + slice_ = ::grpc::Slice(); + } + + virtual uint8_t *reallocate_downward(uint8_t *old_p, size_t old_size, + size_t new_size, size_t in_use_back, + size_t in_use_front) override { + FLATBUFFERS_ASSERT(old_p == slice_.begin()); + FLATBUFFERS_ASSERT(old_size == slice_.size()); + FLATBUFFERS_ASSERT(new_size > old_size); + ::grpc::Slice old_slice = slice_; + ::grpc::Slice new_slice = ::grpc::Slice(new_size); + uint8_t *new_p = const_cast(new_slice.begin()); + memcpy_downward(old_p, old_size, new_p, new_size, in_use_back, + in_use_front); + slice_ = new_slice; + return new_p; + } + + private: + ::grpc::Slice &get_slice(uint8_t *p, size_t size) { + FLATBUFFERS_ASSERT(p == slice_.begin()); + FLATBUFFERS_ASSERT(size == slice_.size()); + return slice_; + } + + ::grpc::Slice slice_; + + friend class MessageBuilder; +}; + +// SliceAllocatorMember is a hack to ensure that the MessageBuilder's +// slice_allocator_ member is constructed before the FlatBufferBuilder, since +// the allocator is used in the FlatBufferBuilder ctor. +namespace detail { +struct SliceAllocatorMember { + SliceAllocator slice_allocator_; +}; +} // namespace detail + +// MessageBuilder is a gRPC-specific FlatBufferBuilder that uses SliceAllocator +// to allocate gRPC buffers. +class MessageBuilder : private detail::SliceAllocatorMember, + public FlatBufferBuilder { + public: + explicit MessageBuilder(uoffset_t initial_size = 1024) + : FlatBufferBuilder(initial_size, &slice_allocator_, false) {} + + MessageBuilder(const MessageBuilder &other) = delete; + MessageBuilder &operator=(const MessageBuilder &other) = delete; + + MessageBuilder(MessageBuilder &&other) + : FlatBufferBuilder(1024, &slice_allocator_, false) { + // Default construct and swap idiom. + Swap(other); + } + + /// Create a MessageBuilder from a FlatBufferBuilder. + explicit MessageBuilder(FlatBufferBuilder &&src, + void (*dealloc)(void *, + size_t) = &DefaultAllocator::dealloc) + : FlatBufferBuilder(1024, &slice_allocator_, false) { + src.Swap(*this); + src.SwapBufAllocator(*this); + if (buf_.capacity()) { + uint8_t *buf = buf_.scratch_data(); // pointer to memory + size_t capacity = buf_.capacity(); // size of memory + slice_allocator_.slice_ = ::grpc::Slice(buf, capacity, dealloc); + } else { + slice_allocator_.slice_ = ::grpc::Slice(); + } + } + + /// Move-assign a FlatBufferBuilder to a MessageBuilder. + /// Only FlatBufferBuilder with default allocator (basically, nullptr) is + /// supported. + MessageBuilder &operator=(FlatBufferBuilder &&src) { + // Move construct a temporary and swap + MessageBuilder temp(std::move(src)); + Swap(temp); + return *this; + } + + MessageBuilder &operator=(MessageBuilder &&other) { + // Move construct a temporary and swap + MessageBuilder temp(std::move(other)); + Swap(temp); + return *this; + } + + void Swap(MessageBuilder &other) { + slice_allocator_.swap(other.slice_allocator_); + FlatBufferBuilder::Swap(other); + // After swapping the FlatBufferBuilder, we swap back the allocator, which + // restores the original allocator back in place. This is necessary because + // MessageBuilder's allocator is its own member (SliceAllocatorMember). The + // allocator passed to FlatBufferBuilder::vector_downward must point to this + // member. + buf_.swap_allocator(other.buf_); + } + + // Releases the ownership of the buffer pointer. + // Returns the size, offset, and the original grpc_slice that + // allocated the buffer. Also see grpc_slice_unref(). + uint8_t *ReleaseRaw(size_t &size, size_t &offset, ::grpc::Slice &slice) { + uint8_t *buf = FlatBufferBuilder::ReleaseRaw(size, offset); + slice = slice_allocator_.slice_; + slice_allocator_.slice_ = ::grpc::Slice(); + return buf; + } + + ~MessageBuilder() {} + + // GetMessage extracts the subslice of the buffer corresponding to the + // flatbuffers-encoded region and wraps it in a `Message` to handle buffer + // ownership. + template Message GetMessage() { + auto buf_data = buf_.scratch_data(); // pointer to memory + auto buf_size = buf_.capacity(); // size of memory + auto msg_data = buf_.data(); // pointer to msg + auto msg_size = buf_.size(); // size of msg + // Do some sanity checks on data/size + FLATBUFFERS_ASSERT(msg_data); + FLATBUFFERS_ASSERT(msg_size); + FLATBUFFERS_ASSERT(msg_data >= buf_data); + FLATBUFFERS_ASSERT(msg_data + msg_size <= buf_data + buf_size); + // Calculate offsets from the buffer start + auto begin = msg_data - buf_data; + auto end = begin + msg_size; + // Get the slice we are working with (no refcount change) + ::grpc::Slice slice = slice_allocator_.get_slice(buf_data, buf_size); + // Extract a subslice of the existing slice (increment refcount) + ::grpc::Slice subslice = slice.sub(begin, end); + // Wrap the subslice in a `Message`, but don't increment refcount + Message msg(subslice); + return msg; + } + + template Message ReleaseMessage() { + Message msg = GetMessage(); + Reset(); + return msg; + } + + private: + // SliceAllocator slice_allocator_; // part of SliceAllocatorMember +}; + +} // namespace grpc +} // namespace flatbuffers +} // namespace mapserver + +namespace grpc { + +template class SerializationTraits> { + public: + static grpc::Status Serialize(const flatbuffers::grpc::Message &msg, + ByteBuffer *buffer, bool *own_buffer) { + // Package the single slice into a `ByteBuffer`, + // incrementing the refcount in the process. + *buffer = ByteBuffer(&msg.BorrowSlice(), 1); + *own_buffer = true; + return grpc::Status::OK; + } + + // Deserialize by pulling the + static grpc::Status Deserialize(ByteBuffer *buf, + flatbuffers::grpc::Message *msg) { + Slice slice; + if (!buf->TrySingleSlice(&slice).ok()) { + if (!buf->DumpToSingleSlice(&slice).ok()) { + buf->Clear(); + return ::grpc::Status(::grpc::StatusCode::INTERNAL, "No payload"); + } + } + *msg = flatbuffers::grpc::Message(slice); + buf->Clear(); +#if FLATBUFFERS_GRPC_DISABLE_AUTO_VERIFICATION + return ::grpc::Status::OK; +#else + if (msg->Verify()) { + return ::grpc::Status::OK; + } else { + return ::grpc::Status(::grpc::StatusCode::INTERNAL, + "Message verification failed"); + } +#endif + } +}; + +} // namespace grpc + +#endif // FLATBUFFERS_GRPC_H_ diff --git a/src/flatgeobuf/include/flatbuffers/hash.h b/src/flatgeobuf/include/flatbuffers/hash.h new file mode 100644 index 0000000000..7e24b20c04 --- /dev/null +++ b/src/flatgeobuf/include/flatbuffers/hash.h @@ -0,0 +1,129 @@ +/* + * Copyright 2015 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLATBUFFERS_HASH_H_ +#define FLATBUFFERS_HASH_H_ + +#include +#include + +#include "flatbuffers/flatbuffers.h" + +namespace mapserver { +namespace flatbuffers { + +template struct FnvTraits { + static const T kFnvPrime; + static const T kOffsetBasis; +}; + +template<> struct FnvTraits { + static const uint32_t kFnvPrime = 0x01000193; + static const uint32_t kOffsetBasis = 0x811C9DC5; +}; + +template<> struct FnvTraits { + static const uint64_t kFnvPrime = 0x00000100000001b3ULL; + static const uint64_t kOffsetBasis = 0xcbf29ce484222645ULL; +}; + +template T HashFnv1(const char *input) { + T hash = FnvTraits::kOffsetBasis; + for (const char *c = input; *c; ++c) { + hash *= FnvTraits::kFnvPrime; + hash ^= static_cast(*c); + } + return hash; +} + +template T HashFnv1a(const char *input) { + T hash = FnvTraits::kOffsetBasis; + for (const char *c = input; *c; ++c) { + hash ^= static_cast(*c); + hash *= FnvTraits::kFnvPrime; + } + return hash; +} + +template<> inline uint16_t HashFnv1(const char *input) { + uint32_t hash = HashFnv1(input); + return (hash >> 16) ^ (hash & 0xffff); +} + +template<> inline uint16_t HashFnv1a(const char *input) { + uint32_t hash = HashFnv1a(input); + return (hash >> 16) ^ (hash & 0xffff); +} + +template struct NamedHashFunction { + const char *name; + + typedef T (*HashFunction)(const char *); + HashFunction function; +}; + +const NamedHashFunction kHashFunctions16[] = { + { "fnv1_16", HashFnv1 }, + { "fnv1a_16", HashFnv1a }, +}; + +const NamedHashFunction kHashFunctions32[] = { + { "fnv1_32", HashFnv1 }, + { "fnv1a_32", HashFnv1a }, +}; + +const NamedHashFunction kHashFunctions64[] = { + { "fnv1_64", HashFnv1 }, + { "fnv1a_64", HashFnv1a }, +}; + +inline NamedHashFunction::HashFunction FindHashFunction16( + const char *name) { + std::size_t size = sizeof(kHashFunctions16) / sizeof(kHashFunctions16[0]); + for (std::size_t i = 0; i < size; ++i) { + if (std::strcmp(name, kHashFunctions16[i].name) == 0) { + return kHashFunctions16[i].function; + } + } + return nullptr; +} + +inline NamedHashFunction::HashFunction FindHashFunction32( + const char *name) { + std::size_t size = sizeof(kHashFunctions32) / sizeof(kHashFunctions32[0]); + for (std::size_t i = 0; i < size; ++i) { + if (std::strcmp(name, kHashFunctions32[i].name) == 0) { + return kHashFunctions32[i].function; + } + } + return nullptr; +} + +inline NamedHashFunction::HashFunction FindHashFunction64( + const char *name) { + std::size_t size = sizeof(kHashFunctions64) / sizeof(kHashFunctions64[0]); + for (std::size_t i = 0; i < size; ++i) { + if (std::strcmp(name, kHashFunctions64[i].name) == 0) { + return kHashFunctions64[i].function; + } + } + return nullptr; +} + +} // namespace flatbuffers +} // namespace mapserver + +#endif // FLATBUFFERS_HASH_H_ diff --git a/src/flatgeobuf/include/flatbuffers/idl.h b/src/flatgeobuf/include/flatbuffers/idl.h new file mode 100644 index 0000000000..d4a4e7f0f0 --- /dev/null +++ b/src/flatgeobuf/include/flatbuffers/idl.h @@ -0,0 +1,1234 @@ +/* + * Copyright 2014 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLATBUFFERS_IDL_H_ +#define FLATBUFFERS_IDL_H_ + +#include +#include +#include +#include + +#include "flatbuffers/base.h" +#include "flatbuffers/flatbuffers.h" +#include "flatbuffers/flexbuffers.h" +#include "flatbuffers/hash.h" +#include "flatbuffers/reflection.h" + +// This file defines the data types representing a parsed IDL (Interface +// Definition Language) / schema file. + +// Limits maximum depth of nested objects. +// Prevents stack overflow while parse scheme, or json, or flexbuffer. +#if !defined(FLATBUFFERS_MAX_PARSING_DEPTH) +# define FLATBUFFERS_MAX_PARSING_DEPTH 64 +#endif + +namespace mapserver { +namespace flatbuffers { + +// The order of these matters for Is*() functions below. +// Additionally, Parser::ParseType assumes bool..string is a contiguous range +// of type tokens. +// clang-format off +#define FLATBUFFERS_GEN_TYPES_SCALAR(TD) \ + TD(NONE, "", uint8_t, byte, byte, byte, uint8, u8, UByte, UInt8) \ + TD(UTYPE, "", uint8_t, byte, byte, byte, uint8, u8, UByte, UInt8) /* begin scalar/int */ \ + TD(BOOL, "bool", uint8_t, boolean,bool, bool, bool, bool, Boolean, Bool) \ + TD(CHAR, "byte", int8_t, byte, int8, sbyte, int8, i8, Byte, Int8) \ + TD(UCHAR, "ubyte", uint8_t, byte, byte, byte, uint8, u8, UByte, UInt8) \ + TD(SHORT, "short", int16_t, short, int16, short, int16, i16, Short, Int16) \ + TD(USHORT, "ushort", uint16_t, short, uint16, ushort, uint16, u16, UShort, UInt16) \ + TD(INT, "int", int32_t, int, int32, int, int32, i32, Int, Int32) \ + TD(UINT, "uint", uint32_t, int, uint32, uint, uint32, u32, UInt, UInt32) \ + TD(LONG, "long", int64_t, long, int64, long, int64, i64, Long, Int64) \ + TD(ULONG, "ulong", uint64_t, long, uint64, ulong, uint64, u64, ULong, UInt64) /* end int */ \ + TD(FLOAT, "float", float, float, float32, float, float32, f32, Float, Float32) /* begin float */ \ + TD(DOUBLE, "double", double, double, float64, double, float64, f64, Double, Double) /* end float/scalar */ +#define FLATBUFFERS_GEN_TYPES_POINTER(TD) \ + TD(STRING, "string", Offset, int, int, StringOffset, int, unused, Int, Offset) \ + TD(VECTOR, "", Offset, int, int, VectorOffset, int, unused, Int, Offset) \ + TD(STRUCT, "", Offset, int, int, int, int, unused, Int, Offset) \ + TD(UNION, "", Offset, int, int, int, int, unused, Int, Offset) +#define FLATBUFFERS_GEN_TYPE_ARRAY(TD) \ + TD(ARRAY, "", int, int, int, int, int, unused, Int, Offset) +// The fields are: +// - enum +// - FlatBuffers schema type. +// - C++ type. +// - Java type. +// - Go type. +// - C# / .Net type. +// - Python type. +// - Kotlin type. +// - Rust type. + +// using these macros, we can now write code dealing with types just once, e.g. + +/* +switch (type) { + #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, \ + RTYPE, KTYPE) \ + case BASE_TYPE_ ## ENUM: \ + // do something specific to CTYPE here + FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) + #undef FLATBUFFERS_TD +} +*/ + +// If not all FLATBUFFERS_GEN_() arguments are necessary for implementation +// of FLATBUFFERS_TD, you can use a variadic macro (with __VA_ARGS__ if needed). +// In the above example, only CTYPE is used to generate the code, it can be rewritten: + +/* +switch (type) { + #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \ + case BASE_TYPE_ ## ENUM: \ + // do something specific to CTYPE here + FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) + #undef FLATBUFFERS_TD +} +*/ + +#define FLATBUFFERS_GEN_TYPES(TD) \ + FLATBUFFERS_GEN_TYPES_SCALAR(TD) \ + FLATBUFFERS_GEN_TYPES_POINTER(TD) \ + FLATBUFFERS_GEN_TYPE_ARRAY(TD) + +// Create an enum for all the types above. +#ifdef __GNUC__ +__extension__ // Stop GCC complaining about trailing comma with -Wpendantic. +#endif +enum BaseType { + #define FLATBUFFERS_TD(ENUM, ...) \ + BASE_TYPE_ ## ENUM, + FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) + #undef FLATBUFFERS_TD +}; + +#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \ + static_assert(sizeof(CTYPE) <= sizeof(largest_scalar_t), \ + "define largest_scalar_t as " #CTYPE); + FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) +#undef FLATBUFFERS_TD + +inline bool IsScalar (BaseType t) { return t >= BASE_TYPE_UTYPE && + t <= BASE_TYPE_DOUBLE; } +inline bool IsInteger(BaseType t) { return t >= BASE_TYPE_UTYPE && + t <= BASE_TYPE_ULONG; } +inline bool IsFloat (BaseType t) { return t == BASE_TYPE_FLOAT || + t == BASE_TYPE_DOUBLE; } +inline bool IsLong (BaseType t) { return t == BASE_TYPE_LONG || + t == BASE_TYPE_ULONG; } +inline bool IsBool (BaseType t) { return t == BASE_TYPE_BOOL; } +inline bool IsOneByte(BaseType t) { return t >= BASE_TYPE_UTYPE && + t <= BASE_TYPE_UCHAR; } + +inline bool IsUnsigned(BaseType t) { + return (t == BASE_TYPE_UTYPE) || (t == BASE_TYPE_UCHAR) || + (t == BASE_TYPE_USHORT) || (t == BASE_TYPE_UINT) || + (t == BASE_TYPE_ULONG); +} + +// clang-format on + +extern const char *const kTypeNames[]; +extern const char kTypeSizes[]; + +inline size_t SizeOf(BaseType t) { return kTypeSizes[t]; } + +struct StructDef; +struct EnumDef; +class Parser; + +// Represents any type in the IDL, which is a combination of the BaseType +// and additional information for vectors/structs_. +struct Type { + explicit Type(BaseType _base_type = BASE_TYPE_NONE, StructDef *_sd = nullptr, + EnumDef *_ed = nullptr, uint16_t _fixed_length = 0) + : base_type(_base_type), + element(BASE_TYPE_NONE), + struct_def(_sd), + enum_def(_ed), + fixed_length(_fixed_length) {} + + bool operator==(const Type &o) { + return base_type == o.base_type && element == o.element && + struct_def == o.struct_def && enum_def == o.enum_def; + } + + Type VectorType() const { + return Type(element, struct_def, enum_def, fixed_length); + } + + Offset Serialize(FlatBufferBuilder *builder) const; + + bool Deserialize(const Parser &parser, const reflection::Type *type); + + BaseType base_type; + BaseType element; // only set if t == BASE_TYPE_VECTOR + StructDef *struct_def; // only set if t or element == BASE_TYPE_STRUCT + EnumDef *enum_def; // set if t == BASE_TYPE_UNION / BASE_TYPE_UTYPE, + // or for an integral type derived from an enum. + uint16_t fixed_length; // only set if t == BASE_TYPE_ARRAY +}; + +// Represents a parsed scalar value, it's type, and field offset. +struct Value { + Value() + : constant("0"), + offset(static_cast(~(static_cast(0U)))) {} + Type type; + std::string constant; + voffset_t offset; +}; + +// Helper class that retains the original order of a set of identifiers and +// also provides quick lookup. +template class SymbolTable { + public: + ~SymbolTable() { + for (auto it = vec.begin(); it != vec.end(); ++it) { delete *it; } + } + + bool Add(const std::string &name, T *e) { + vec.emplace_back(e); + auto it = dict.find(name); + if (it != dict.end()) return true; + dict[name] = e; + return false; + } + + void Move(const std::string &oldname, const std::string &newname) { + auto it = dict.find(oldname); + if (it != dict.end()) { + auto obj = it->second; + dict.erase(it); + dict[newname] = obj; + } else { + FLATBUFFERS_ASSERT(false); + } + } + + T *Lookup(const std::string &name) const { + auto it = dict.find(name); + return it == dict.end() ? nullptr : it->second; + } + + public: + std::map dict; // quick lookup + std::vector vec; // Used to iterate in order of insertion +}; + +// A name space, as set in the schema. +struct Namespace { + Namespace() : from_table(0) {} + + // Given a (potentially unqualified) name, return the "fully qualified" name + // which has a full namespaced descriptor. + // With max_components you can request less than the number of components + // the current namespace has. + std::string GetFullyQualifiedName(const std::string &name, + size_t max_components = 1000) const; + + std::vector components; + size_t from_table; // Part of the namespace corresponds to a message/table. +}; + +inline bool operator<(const Namespace &a, const Namespace &b) { + size_t min_size = std::min(a.components.size(), b.components.size()); + for (size_t i = 0; i < min_size; ++i) { + if (a.components[i] != b.components[i]) + return a.components[i] < b.components[i]; + } + return a.components.size() < b.components.size(); +} + +// Base class for all definition types (fields, structs_, enums_). +struct Definition { + Definition() + : generated(false), + defined_namespace(nullptr), + serialized_location(0), + index(-1), + refcount(1), + declaration_file(nullptr) {} + + flatbuffers::Offset< + flatbuffers::Vector>> + SerializeAttributes(FlatBufferBuilder *builder, const Parser &parser) const; + + bool DeserializeAttributes(Parser &parser, + const Vector> *attrs); + + std::string name; + std::string file; + std::vector doc_comment; + SymbolTable attributes; + bool generated; // did we already output code for this definition? + Namespace *defined_namespace; // Where it was defined. + + // For use with Serialize() + uoffset_t serialized_location; + int index; // Inside the vector it is stored. + int refcount; + const std::string *declaration_file; +}; + +struct FieldDef : public Definition { + FieldDef() + : deprecated(false), + key(false), + shared(false), + native_inline(false), + flexbuffer(false), + presence(kDefault), + nested_flatbuffer(NULL), + padding(0) {} + + Offset Serialize(FlatBufferBuilder *builder, uint16_t id, + const Parser &parser) const; + + bool Deserialize(Parser &parser, const reflection::Field *field); + + bool IsScalarOptional() const { + return IsScalar(value.type.base_type) && IsOptional(); + } + bool IsOptional() const { return presence == kOptional; } + bool IsRequired() const { return presence == kRequired; } + bool IsDefault() const { return presence == kDefault; } + + Value value; + bool deprecated; // Field is allowed to be present in old data, but can't be. + // written in new data nor accessed in new code. + bool key; // Field functions as a key for creating sorted vectors. + bool shared; // Field will be using string pooling (i.e. CreateSharedString) + // as default serialization behavior if field is a string. + bool native_inline; // Field will be defined inline (instead of as a pointer) + // for native tables if field is a struct. + bool flexbuffer; // This field contains FlexBuffer data. + + enum Presence { + // Field must always be present. + kRequired, + // Non-presence should be signalled to and controlled by users. + kOptional, + // Non-presence is hidden from users. + // Implementations may omit writing default values. + kDefault, + }; + Presence static MakeFieldPresence(bool optional, bool required) { + FLATBUFFERS_ASSERT(!(required && optional)); + // clang-format off + return required ? FieldDef::kRequired + : optional ? FieldDef::kOptional + : FieldDef::kDefault; + // clang-format on + } + Presence presence; + + StructDef *nested_flatbuffer; // This field contains nested FlatBuffer data. + size_t padding; // Bytes to always pad after this field. +}; + +struct StructDef : public Definition { + StructDef() + : fixed(false), + predecl(true), + sortbysize(true), + has_key(false), + minalign(1), + bytesize(0) {} + + void PadLastField(size_t min_align) { + auto padding = PaddingBytes(bytesize, min_align); + bytesize += padding; + if (fields.vec.size()) fields.vec.back()->padding = padding; + } + + Offset Serialize(FlatBufferBuilder *builder, + const Parser &parser) const; + + bool Deserialize(Parser &parser, const reflection::Object *object); + + SymbolTable fields; + + bool fixed; // If it's struct, not a table. + bool predecl; // If it's used before it was defined. + bool sortbysize; // Whether fields come in the declaration or size order. + bool has_key; // It has a key field. + size_t minalign; // What the whole object needs to be aligned to. + size_t bytesize; // Size if fixed. + + flatbuffers::unique_ptr original_location; +}; + +struct EnumDef; +struct EnumValBuilder; + +struct EnumVal { + Offset Serialize(FlatBufferBuilder *builder, + const Parser &parser) const; + + bool Deserialize(const Parser &parser, const reflection::EnumVal *val); + + uint64_t GetAsUInt64() const { return static_cast(value); } + int64_t GetAsInt64() const { return value; } + bool IsZero() const { return 0 == value; } + bool IsNonZero() const { return !IsZero(); } + + std::string name; + std::vector doc_comment; + Type union_type; + + private: + friend EnumDef; + friend EnumValBuilder; + friend bool operator==(const EnumVal &lhs, const EnumVal &rhs); + + EnumVal(const std::string &_name, int64_t _val) : name(_name), value(_val) {} + EnumVal() : value(0) {} + + int64_t value; +}; + +struct EnumDef : public Definition { + EnumDef() : is_union(false), uses_multiple_type_instances(false) {} + + Offset Serialize(FlatBufferBuilder *builder, + const Parser &parser) const; + + bool Deserialize(Parser &parser, const reflection::Enum *values); + + template void ChangeEnumValue(EnumVal *ev, T new_val); + void SortByValue(); + void RemoveDuplicates(); + + std::string AllFlags() const; + const EnumVal *MinValue() const; + const EnumVal *MaxValue() const; + // Returns the number of integer steps from v1 to v2. + uint64_t Distance(const EnumVal *v1, const EnumVal *v2) const; + // Returns the number of integer steps from Min to Max. + uint64_t Distance() const { return Distance(MinValue(), MaxValue()); } + + EnumVal *ReverseLookup(int64_t enum_idx, + bool skip_union_default = false) const; + EnumVal *FindByValue(const std::string &constant) const; + + std::string ToString(const EnumVal &ev) const { + return IsUInt64() ? NumToString(ev.GetAsUInt64()) + : NumToString(ev.GetAsInt64()); + } + + size_t size() const { return vals.vec.size(); } + + const std::vector &Vals() const { return vals.vec; } + + const EnumVal *Lookup(const std::string &enum_name) const { + return vals.Lookup(enum_name); + } + + bool is_union; + // Type is a union which uses type aliases where at least one type is + // available under two different names. + bool uses_multiple_type_instances; + Type underlying_type; + + private: + bool IsUInt64() const { + return (BASE_TYPE_ULONG == underlying_type.base_type); + } + + friend EnumValBuilder; + SymbolTable vals; +}; + +inline bool IsString(const Type &type) { + return type.base_type == BASE_TYPE_STRING; +} + +inline bool IsStruct(const Type &type) { + return type.base_type == BASE_TYPE_STRUCT && type.struct_def->fixed; +} + +inline bool IsUnion(const Type &type) { + return type.enum_def != nullptr && type.enum_def->is_union; +} + +inline bool IsUnionType(const Type &type) { + return IsUnion(type) && IsInteger(type.base_type); +} + +inline bool IsVector(const Type &type) { + return type.base_type == BASE_TYPE_VECTOR; +} + +inline bool IsArray(const Type &type) { + return type.base_type == BASE_TYPE_ARRAY; +} + +inline bool IsSeries(const Type &type) { + return IsVector(type) || IsArray(type); +} + +inline bool IsEnum(const Type &type) { + return type.enum_def != nullptr && IsInteger(type.base_type); +} + +inline size_t InlineSize(const Type &type) { + return IsStruct(type) + ? type.struct_def->bytesize + : (IsArray(type) + ? InlineSize(type.VectorType()) * type.fixed_length + : SizeOf(type.base_type)); +} + +inline size_t InlineAlignment(const Type &type) { + if (IsStruct(type)) { + return type.struct_def->minalign; + } else if (IsArray(type)) { + return IsStruct(type.VectorType()) ? type.struct_def->minalign + : SizeOf(type.element); + } else { + return SizeOf(type.base_type); + } +} +inline bool operator==(const EnumVal &lhs, const EnumVal &rhs) { + return lhs.value == rhs.value; +} +inline bool operator!=(const EnumVal &lhs, const EnumVal &rhs) { + return !(lhs == rhs); +} + +inline bool EqualByName(const Type &a, const Type &b) { + return a.base_type == b.base_type && a.element == b.element && + (a.struct_def == b.struct_def || + a.struct_def->name == b.struct_def->name) && + (a.enum_def == b.enum_def || a.enum_def->name == b.enum_def->name); +} + +struct RPCCall : public Definition { + Offset Serialize(FlatBufferBuilder *builder, + const Parser &parser) const; + + bool Deserialize(Parser &parser, const reflection::RPCCall *call); + + StructDef *request, *response; +}; + +struct ServiceDef : public Definition { + Offset Serialize(FlatBufferBuilder *builder, + const Parser &parser) const; + bool Deserialize(Parser &parser, const reflection::Service *service); + + SymbolTable calls; +}; + +// Container of options that may apply to any of the source/text generators. +struct IDLOptions { + // field case style options for C++ + enum CaseStyle { CaseStyle_Unchanged = 0, CaseStyle_Upper, CaseStyle_Lower }; + + bool gen_jvmstatic; + // Use flexbuffers instead for binary and text generation + bool use_flexbuffers; + bool strict_json; + bool output_default_scalars_in_json; + int indent_step; + bool output_enum_identifiers; + bool prefixed_enums; + bool scoped_enums; + bool swift_implementation_only; + bool include_dependence_headers; + bool mutable_buffer; + bool one_file; + bool proto_mode; + bool proto_oneof_union; + bool generate_all; + bool skip_unexpected_fields_in_json; + bool generate_name_strings; + bool generate_object_based_api; + bool gen_compare; + std::string cpp_object_api_pointer_type; + std::string cpp_object_api_string_type; + bool cpp_object_api_string_flexible_constructor; + CaseStyle cpp_object_api_field_case_style; + bool cpp_direct_copy; + bool gen_nullable; + bool java_checkerframework; + bool gen_generated; + bool gen_json_coders; + std::string object_prefix; + std::string object_suffix; + bool union_value_namespacing; + bool allow_non_utf8; + bool natural_utf8; + std::string include_prefix; + bool keep_include_path; + bool binary_schema_comments; + bool binary_schema_builtins; + bool binary_schema_gen_embed; + std::string go_import; + std::string go_namespace; + bool protobuf_ascii_alike; + bool size_prefixed; + std::string root_type; + bool force_defaults; + bool java_primitive_has_method; + bool cs_gen_json_serializer; + std::vector cpp_includes; + std::string cpp_std; + bool cpp_static_reflection; + std::string proto_namespace_suffix; + std::string filename_suffix; + std::string filename_extension; + bool no_warnings; + bool warnings_as_errors; + std::string project_root; + bool cs_global_alias; + bool json_nested_flatbuffers; + bool json_nested_flexbuffers; + bool json_nested_legacy_flatbuffers; + bool ts_flat_file; + + // Possible options for the more general generator below. + enum Language { + kJava = 1 << 0, + kCSharp = 1 << 1, + kGo = 1 << 2, + kCpp = 1 << 3, + kPython = 1 << 5, + kPhp = 1 << 6, + kJson = 1 << 7, + kBinary = 1 << 8, + kTs = 1 << 9, + kJsonSchema = 1 << 10, + kDart = 1 << 11, + kLua = 1 << 12, + kLobster = 1 << 13, + kRust = 1 << 14, + kKotlin = 1 << 15, + kSwift = 1 << 16, + kMAX + }; + + enum MiniReflect { kNone, kTypes, kTypesAndNames }; + + MiniReflect mini_reflect; + + // If set, require all fields in a table to be explicitly numbered. + bool require_explicit_ids; + + // If set, implement serde::Serialize for generated Rust types + bool rust_serialize; + + // If set, generate rust types in individual files with a root module file. + bool rust_module_root_file; + + // The corresponding language bit will be set if a language is included + // for code generation. + unsigned long lang_to_generate; + + // If set (default behavior), empty string fields will be set to nullptr to + // make the flatbuffer more compact. + bool set_empty_strings_to_null; + + // If set (default behavior), empty vector fields will be set to nullptr to + // make the flatbuffer more compact. + bool set_empty_vectors_to_null; + + IDLOptions() + : gen_jvmstatic(false), + use_flexbuffers(false), + strict_json(false), + output_default_scalars_in_json(false), + indent_step(2), + output_enum_identifiers(true), + prefixed_enums(true), + scoped_enums(false), + swift_implementation_only(false), + include_dependence_headers(true), + mutable_buffer(false), + one_file(false), + proto_mode(false), + proto_oneof_union(false), + generate_all(false), + skip_unexpected_fields_in_json(false), + generate_name_strings(false), + generate_object_based_api(false), + gen_compare(false), + cpp_object_api_pointer_type("std::unique_ptr"), + cpp_object_api_string_flexible_constructor(false), + cpp_object_api_field_case_style(CaseStyle_Unchanged), + cpp_direct_copy(true), + gen_nullable(false), + java_checkerframework(false), + gen_generated(false), + gen_json_coders(false), + object_suffix("T"), + union_value_namespacing(true), + allow_non_utf8(false), + natural_utf8(false), + keep_include_path(false), + binary_schema_comments(false), + binary_schema_builtins(false), + binary_schema_gen_embed(false), + protobuf_ascii_alike(false), + size_prefixed(false), + force_defaults(false), + java_primitive_has_method(false), + cs_gen_json_serializer(false), + cpp_static_reflection(false), + filename_suffix("_generated"), + filename_extension(), + no_warnings(false), + warnings_as_errors(false), + project_root(""), + cs_global_alias(false), + json_nested_flatbuffers(true), + json_nested_flexbuffers(true), + json_nested_legacy_flatbuffers(false), + ts_flat_file(false), + mini_reflect(IDLOptions::kNone), + require_explicit_ids(false), + rust_serialize(false), + rust_module_root_file(false), + lang_to_generate(0), + set_empty_strings_to_null(true), + set_empty_vectors_to_null(true) {} +}; + +// This encapsulates where the parser is in the current source file. +struct ParserState { + ParserState() + : cursor_(nullptr), + line_start_(nullptr), + line_(0), + token_(-1), + attr_is_trivial_ascii_string_(true) {} + + protected: + void ResetState(const char *source) { + cursor_ = source; + line_ = 0; + MarkNewLine(); + } + + void MarkNewLine() { + line_start_ = cursor_; + line_ += 1; + } + + int64_t CursorPosition() const { + FLATBUFFERS_ASSERT(cursor_ && line_start_ && cursor_ >= line_start_); + return static_cast(cursor_ - line_start_); + } + + const char *cursor_; + const char *line_start_; + int line_; // the current line being parsed + int token_; + + // Flag: text in attribute_ is true ASCII string without escape + // sequences. Only printable ASCII (without [\t\r\n]). + // Used for number-in-string (and base64 string in future). + bool attr_is_trivial_ascii_string_; + std::string attribute_; + std::vector doc_comment_; +}; + +// A way to make error propagation less error prone by requiring values to be +// checked. +// Once you create a value of this type you must either: +// - Call Check() on it. +// - Copy or assign it to another value. +// Failure to do so leads to an assert. +// This guarantees that this as return value cannot be ignored. +class CheckedError { + public: + explicit CheckedError(bool error) + : is_error_(error), has_been_checked_(false) {} + + CheckedError &operator=(const CheckedError &other) { + is_error_ = other.is_error_; + has_been_checked_ = false; + other.has_been_checked_ = true; + return *this; + } + + CheckedError(const CheckedError &other) { + *this = other; // Use assignment operator. + } + + ~CheckedError() { FLATBUFFERS_ASSERT(has_been_checked_); } + + bool Check() { + has_been_checked_ = true; + return is_error_; + } + + private: + bool is_error_; + mutable bool has_been_checked_; +}; + +// Additionally, in GCC we can get these errors statically, for additional +// assurance: +// clang-format off +#ifdef __GNUC__ +#define FLATBUFFERS_CHECKED_ERROR CheckedError \ + __attribute__((warn_unused_result)) +#else +#define FLATBUFFERS_CHECKED_ERROR CheckedError +#endif +// clang-format on + +class Parser : public ParserState { + public: + explicit Parser(const IDLOptions &options = IDLOptions()) + : current_namespace_(nullptr), + empty_namespace_(nullptr), + flex_builder_(256, flexbuffers::BUILDER_FLAG_SHARE_ALL), + root_struct_def_(nullptr), + opts(options), + uses_flexbuffers_(false), + has_warning_(false), + advanced_features_(0), + source_(nullptr), + anonymous_counter_(0), + parse_depth_counter_(0) { + if (opts.force_defaults) { builder_.ForceDefaults(true); } + // Start out with the empty namespace being current. + empty_namespace_ = new Namespace(); + namespaces_.push_back(empty_namespace_); + current_namespace_ = empty_namespace_; + known_attributes_["deprecated"] = true; + known_attributes_["required"] = true; + known_attributes_["key"] = true; + known_attributes_["shared"] = true; + known_attributes_["hash"] = true; + known_attributes_["id"] = true; + known_attributes_["force_align"] = true; + known_attributes_["bit_flags"] = true; + known_attributes_["original_order"] = true; + known_attributes_["nested_flatbuffer"] = true; + known_attributes_["csharp_partial"] = true; + known_attributes_["streaming"] = true; + known_attributes_["idempotent"] = true; + known_attributes_["cpp_type"] = true; + known_attributes_["cpp_ptr_type"] = true; + known_attributes_["cpp_ptr_type_get"] = true; + known_attributes_["cpp_str_type"] = true; + known_attributes_["cpp_str_flex_ctor"] = true; + known_attributes_["native_inline"] = true; + known_attributes_["native_custom_alloc"] = true; + known_attributes_["native_type"] = true; + known_attributes_["native_type_pack_name"] = true; + known_attributes_["native_default"] = true; + known_attributes_["flexbuffer"] = true; + known_attributes_["private"] = true; + } + + ~Parser() { + for (auto it = namespaces_.begin(); it != namespaces_.end(); ++it) { + delete *it; + } + } + + // Parse the string containing either schema or JSON data, which will + // populate the SymbolTable's or the FlatBufferBuilder above. + // include_paths is used to resolve any include statements, and typically + // should at least include the project path (where you loaded source_ from). + // include_paths must be nullptr terminated if specified. + // If include_paths is nullptr, it will attempt to load from the current + // directory. + // If the source was loaded from a file and isn't an include file, + // supply its name in source_filename. + // All paths specified in this call must be in posix format, if you accept + // paths from user input, please call PosixPath on them first. + bool Parse(const char *_source, const char **include_paths = nullptr, + const char *source_filename = nullptr); + + bool ParseJson(const char *json, const char *json_filename = nullptr); + + // Set the root type. May override the one set in the schema. + bool SetRootType(const char *name); + + // Mark all definitions as already having code generated. + void MarkGenerated(); + + // Get the files recursively included by the given file. The returned + // container will have at least the given file. + std::set GetIncludedFilesRecursive( + const std::string &file_name) const; + + // Fills builder_ with a binary version of the schema parsed. + // See reflection/reflection.fbs + void Serialize(); + + // Deserialize a schema buffer + bool Deserialize(const uint8_t *buf, const size_t size); + + // Fills internal structure as if the schema passed had been loaded by parsing + // with Parse except that included filenames will not be populated. + bool Deserialize(const reflection::Schema *schema); + + Type *DeserializeType(const reflection::Type *type); + + // Checks that the schema represented by this parser is a safe evolution + // of the schema provided. Returns non-empty error on any problems. + std::string ConformTo(const Parser &base); + + // Similar to Parse(), but now only accepts JSON to be parsed into a + // FlexBuffer. + bool ParseFlexBuffer(const char *source, const char *source_filename, + flexbuffers::Builder *builder); + + StructDef *LookupStruct(const std::string &id) const; + StructDef *LookupStructThruParentNamespaces(const std::string &id) const; + + std::string UnqualifiedName(const std::string &fullQualifiedName); + + FLATBUFFERS_CHECKED_ERROR Error(const std::string &msg); + + // @brief Verify that any of 'opts.lang_to_generate' supports Optional scalars + // in a schema. + // @param opts Options used to parce a schema and generate code. + static bool SupportsOptionalScalars(const flatbuffers::IDLOptions &opts); + + private: + class ParseDepthGuard; + + void Message(const std::string &msg); + void Warning(const std::string &msg); + FLATBUFFERS_CHECKED_ERROR ParseHexNum(int nibbles, uint64_t *val); + FLATBUFFERS_CHECKED_ERROR Next(); + FLATBUFFERS_CHECKED_ERROR SkipByteOrderMark(); + bool Is(int t) const; + bool IsIdent(const char *id) const; + FLATBUFFERS_CHECKED_ERROR Expect(int t); + std::string TokenToStringId(int t) const; + EnumDef *LookupEnum(const std::string &id); + FLATBUFFERS_CHECKED_ERROR ParseNamespacing(std::string *id, + std::string *last); + FLATBUFFERS_CHECKED_ERROR ParseTypeIdent(Type &type); + FLATBUFFERS_CHECKED_ERROR ParseType(Type &type); + FLATBUFFERS_CHECKED_ERROR AddField(StructDef &struct_def, + const std::string &name, const Type &type, + FieldDef **dest); + FLATBUFFERS_CHECKED_ERROR ParseField(StructDef &struct_def); + FLATBUFFERS_CHECKED_ERROR ParseString(Value &val, bool use_string_pooling); + FLATBUFFERS_CHECKED_ERROR ParseComma(); + FLATBUFFERS_CHECKED_ERROR ParseAnyValue(Value &val, FieldDef *field, + size_t parent_fieldn, + const StructDef *parent_struct_def, + uoffset_t count, + bool inside_vector = false); + template + FLATBUFFERS_CHECKED_ERROR ParseTableDelimiters(size_t &fieldn, + const StructDef *struct_def, + F body); + FLATBUFFERS_CHECKED_ERROR ParseTable(const StructDef &struct_def, + std::string *value, uoffset_t *ovalue); + void SerializeStruct(const StructDef &struct_def, const Value &val); + void SerializeStruct(FlatBufferBuilder &builder, const StructDef &struct_def, + const Value &val); + template + FLATBUFFERS_CHECKED_ERROR ParseVectorDelimiters(uoffset_t &count, F body); + FLATBUFFERS_CHECKED_ERROR ParseVector(const Type &type, uoffset_t *ovalue, + FieldDef *field, size_t fieldn); + FLATBUFFERS_CHECKED_ERROR ParseArray(Value &array); + FLATBUFFERS_CHECKED_ERROR ParseNestedFlatbuffer( + Value &val, FieldDef *field, size_t fieldn, + const StructDef *parent_struct_def); + FLATBUFFERS_CHECKED_ERROR ParseMetaData(SymbolTable *attributes); + FLATBUFFERS_CHECKED_ERROR TryTypedValue(const std::string *name, int dtoken, + bool check, Value &e, BaseType req, + bool *destmatch); + FLATBUFFERS_CHECKED_ERROR ParseHash(Value &e, FieldDef *field); + FLATBUFFERS_CHECKED_ERROR TokenError(); + FLATBUFFERS_CHECKED_ERROR ParseSingleValue(const std::string *name, Value &e, + bool check_now); + FLATBUFFERS_CHECKED_ERROR ParseFunction(const std::string *name, Value &e); + FLATBUFFERS_CHECKED_ERROR ParseEnumFromString(const Type &type, + std::string *result); + StructDef *LookupCreateStruct(const std::string &name, + bool create_if_new = true, + bool definition = false); + FLATBUFFERS_CHECKED_ERROR ParseEnum(bool is_union, EnumDef **dest, + const char *filename); + FLATBUFFERS_CHECKED_ERROR ParseNamespace(); + FLATBUFFERS_CHECKED_ERROR StartStruct(const std::string &name, + StructDef **dest); + FLATBUFFERS_CHECKED_ERROR StartEnum(const std::string &name, bool is_union, + EnumDef **dest); + FLATBUFFERS_CHECKED_ERROR ParseDecl(const char *filename); + FLATBUFFERS_CHECKED_ERROR ParseService(const char *filename); + FLATBUFFERS_CHECKED_ERROR ParseProtoFields(StructDef *struct_def, + bool isextend, bool inside_oneof); + FLATBUFFERS_CHECKED_ERROR ParseProtoOption(); + FLATBUFFERS_CHECKED_ERROR ParseProtoKey(); + FLATBUFFERS_CHECKED_ERROR ParseProtoDecl(); + FLATBUFFERS_CHECKED_ERROR ParseProtoCurliesOrIdent(); + FLATBUFFERS_CHECKED_ERROR ParseTypeFromProtoType(Type *type); + FLATBUFFERS_CHECKED_ERROR SkipAnyJsonValue(); + FLATBUFFERS_CHECKED_ERROR ParseFlexBufferNumericConstant( + flexbuffers::Builder *builder); + FLATBUFFERS_CHECKED_ERROR ParseFlexBufferValue(flexbuffers::Builder *builder); + FLATBUFFERS_CHECKED_ERROR StartParseFile(const char *source, + const char *source_filename); + FLATBUFFERS_CHECKED_ERROR ParseRoot(const char *_source, + const char **include_paths, + const char *source_filename); + FLATBUFFERS_CHECKED_ERROR DoParse(const char *_source, + const char **include_paths, + const char *source_filename, + const char *include_filename); + FLATBUFFERS_CHECKED_ERROR DoParseJson(); + FLATBUFFERS_CHECKED_ERROR CheckClash(std::vector &fields, + StructDef *struct_def, + const char *suffix, BaseType baseType); + FLATBUFFERS_CHECKED_ERROR ParseAlignAttribute( + const std::string &align_constant, size_t min_align, size_t *align); + + bool SupportsAdvancedUnionFeatures() const; + bool SupportsAdvancedArrayFeatures() const; + bool SupportsOptionalScalars() const; + bool SupportsDefaultVectorsAndStrings() const; + Namespace *UniqueNamespace(Namespace *ns); + + FLATBUFFERS_CHECKED_ERROR RecurseError(); + template CheckedError Recurse(F f); + + const std::string &GetPooledString(const std::string &s) const; + + public: + SymbolTable types_; + SymbolTable structs_; + SymbolTable enums_; + SymbolTable services_; + std::vector namespaces_; + Namespace *current_namespace_; + Namespace *empty_namespace_; + std::string error_; // User readable error_ if Parse() == false + + FlatBufferBuilder builder_; // any data contained in the file + flexbuffers::Builder flex_builder_; + flexbuffers::Reference flex_root_; + StructDef *root_struct_def_; + std::string file_identifier_; + std::string file_extension_; + + std::map included_files_; + std::map> files_included_per_file_; + std::vector native_included_files_; + + std::map known_attributes_; + + IDLOptions opts; + bool uses_flexbuffers_; + bool has_warning_; + + uint64_t advanced_features_; + + private: + const char *source_; + + std::string file_being_parsed_; + + std::vector> field_stack_; + + // TODO(cneo): Refactor parser to use string_cache more often to save + // on memory usage. + mutable std::set string_cache_; + + int anonymous_counter_; + int parse_depth_counter_; // stack-overflow guard +}; + +// Utility functions for multiple generators: + +// Generate text (JSON) from a given FlatBuffer, and a given Parser +// object that has been populated with the corresponding schema. +// If ident_step is 0, no indentation will be generated. Additionally, +// if it is less than 0, no linefeeds will be generated either. +// See idl_gen_text.cpp. +// strict_json adds "quotes" around field names if true. +// If the flatbuffer cannot be encoded in JSON (e.g., it contains non-UTF-8 +// byte arrays in String values), returns false. +extern bool GenerateTextFromTable(const Parser &parser, const void *table, + const std::string &tablename, + std::string *text); +extern bool GenerateText(const Parser &parser, const void *flatbuffer, + std::string *text); +extern bool GenerateTextFile(const Parser &parser, const std::string &path, + const std::string &file_name); + +// Generate Json schema to string +// See idl_gen_json_schema.cpp. +extern bool GenerateJsonSchema(const Parser &parser, std::string *json); + +// Generate binary files from a given FlatBuffer, and a given Parser +// object that has been populated with the corresponding schema. +// See code_generators.cpp. +extern bool GenerateBinary(const Parser &parser, const std::string &path, + const std::string &file_name); + +// Generate a C++ header from the definitions in the Parser object. +// See idl_gen_cpp. +extern bool GenerateCPP(const Parser &parser, const std::string &path, + const std::string &file_name); + +// Generate C# files from the definitions in the Parser object. +// See idl_gen_csharp.cpp. +extern bool GenerateCSharp(const Parser &parser, const std::string &path, + const std::string &file_name); + +extern bool GenerateDart(const Parser &parser, const std::string &path, + const std::string &file_name); + +// Generate Java files from the definitions in the Parser object. +// See idl_gen_java.cpp. +extern bool GenerateJava(const Parser &parser, const std::string &path, + const std::string &file_name); + +// Generate JavaScript or TypeScript code from the definitions in the Parser +// object. See idl_gen_js. +extern bool GenerateTS(const Parser &parser, const std::string &path, + const std::string &file_name); + +// Generate Go files from the definitions in the Parser object. +// See idl_gen_go.cpp. +extern bool GenerateGo(const Parser &parser, const std::string &path, + const std::string &file_name); + +// Generate Php code from the definitions in the Parser object. +// See idl_gen_php. +extern bool GeneratePhp(const Parser &parser, const std::string &path, + const std::string &file_name); + +// Generate Python files from the definitions in the Parser object. +// See idl_gen_python.cpp. +extern bool GeneratePython(const Parser &parser, const std::string &path, + const std::string &file_name); + +// Generate Lobster files from the definitions in the Parser object. +// See idl_gen_lobster.cpp. +extern bool GenerateLobster(const Parser &parser, const std::string &path, + const std::string &file_name); + +// Generate Lua files from the definitions in the Parser object. +// See idl_gen_lua.cpp. +extern bool GenerateLua(const Parser &parser, const std::string &path, + const std::string &file_name); + +// Generate Rust files from the definitions in the Parser object. +// See idl_gen_rust.cpp. +extern bool GenerateRust(const Parser &parser, const std::string &path, + const std::string &file_name); + +// Generate Json schema file +// See idl_gen_json_schema.cpp. +extern bool GenerateJsonSchema(const Parser &parser, const std::string &path, + const std::string &file_name); + +extern bool GenerateKotlin(const Parser &parser, const std::string &path, + const std::string &file_name); + +// Generate Swift classes. +// See idl_gen_swift.cpp +extern bool GenerateSwift(const Parser &parser, const std::string &path, + const std::string &file_name); + +// Generate a schema file from the internal representation, useful after +// parsing a .proto schema. +extern std::string GenerateFBS(const Parser &parser, + const std::string &file_name); +extern bool GenerateFBS(const Parser &parser, const std::string &path, + const std::string &file_name); + +// Generate a make rule for the generated TypeScript code. +// See idl_gen_ts.cpp. +extern std::string TSMakeRule(const Parser &parser, const std::string &path, + const std::string &file_name); + +// Generate a make rule for the generated C++ header. +// See idl_gen_cpp.cpp. +extern std::string CPPMakeRule(const Parser &parser, const std::string &path, + const std::string &file_name); + +// Generate a make rule for the generated Dart code +// see idl_gen_dart.cpp +extern std::string DartMakeRule(const Parser &parser, const std::string &path, + const std::string &file_name); + +// Generate a make rule for the generated Rust code. +// See idl_gen_rust.cpp. +extern std::string RustMakeRule(const Parser &parser, const std::string &path, + const std::string &file_name); + +// Generate a make rule for generated Java or C# files. +// See code_generators.cpp. +extern std::string CSharpMakeRule(const Parser &parser, const std::string &path, + const std::string &file_name); +extern std::string JavaMakeRule(const Parser &parser, const std::string &path, + const std::string &file_name); + +// Generate a make rule for the generated text (JSON) files. +// See idl_gen_text.cpp. +extern std::string TextMakeRule(const Parser &parser, const std::string &path, + const std::string &file_names); + +// Generate a make rule for the generated binary files. +// See code_generators.cpp. +extern std::string BinaryMakeRule(const Parser &parser, const std::string &path, + const std::string &file_name); + +// Generate GRPC Cpp interfaces. +// See idl_gen_grpc.cpp. +bool GenerateCppGRPC(const Parser &parser, const std::string &path, + const std::string &file_name); + +// Generate GRPC Go interfaces. +// See idl_gen_grpc.cpp. +bool GenerateGoGRPC(const Parser &parser, const std::string &path, + const std::string &file_name); + +// Generate GRPC Java classes. +// See idl_gen_grpc.cpp +bool GenerateJavaGRPC(const Parser &parser, const std::string &path, + const std::string &file_name); + +// Generate GRPC Python interfaces. +// See idl_gen_grpc.cpp. +bool GeneratePythonGRPC(const Parser &parser, const std::string &path, + const std::string &file_name); + +// Generate GRPC Swift interfaces. +// See idl_gen_grpc.cpp. +extern bool GenerateSwiftGRPC(const Parser &parser, const std::string &path, + const std::string &file_name); + +extern bool GenerateTSGRPC(const Parser &parser, const std::string &path, + const std::string &file_name); + +extern bool GenerateRustModuleRootFile(const Parser &parser, + const std::string &path); +} // namespace flatbuffers +} // namespace mapserver + +#endif // FLATBUFFERS_IDL_H_ diff --git a/src/flatgeobuf/include/flatbuffers/minireflect.h b/src/flatgeobuf/include/flatbuffers/minireflect.h new file mode 100644 index 0000000000..cb935f9d86 --- /dev/null +++ b/src/flatgeobuf/include/flatbuffers/minireflect.h @@ -0,0 +1,421 @@ +/* + * Copyright 2017 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLATBUFFERS_MINIREFLECT_H_ +#define FLATBUFFERS_MINIREFLECT_H_ + +#include "flatbuffers/flatbuffers.h" +#include "flatbuffers/util.h" + +namespace mapserver { +namespace flatbuffers { + +// Utilities that can be used with the "mini reflection" tables present +// in generated code with --reflect-types (only types) or --reflect-names +// (also names). +// This allows basic reflection functionality such as pretty-printing +// that does not require the use of the schema parser or loading of binary +// schema files at runtime (reflection.h). + +// For any of the functions below that take `const TypeTable *`, you pass +// `FooTypeTable()` if the type of the root is `Foo`. + +// First, a generic iterator that can be used by multiple algorithms. + +struct IterationVisitor { + // These mark the scope of a table or struct. + virtual void StartSequence() {} + virtual void EndSequence() {} + // Called for each field regardless of whether it is present or not. + // If not present, val == nullptr. set_idx is the index of all set fields. + virtual void Field(size_t /*field_idx*/, size_t /*set_idx*/, + ElementaryType /*type*/, bool /*is_vector*/, + const TypeTable * /*type_table*/, const char * /*name*/, + const uint8_t * /*val*/) {} + // Called for a value that is actually present, after a field, or as part + // of a vector. + virtual void UType(uint8_t, const char *) {} + virtual void Bool(bool) {} + virtual void Char(int8_t, const char *) {} + virtual void UChar(uint8_t, const char *) {} + virtual void Short(int16_t, const char *) {} + virtual void UShort(uint16_t, const char *) {} + virtual void Int(int32_t, const char *) {} + virtual void UInt(uint32_t, const char *) {} + virtual void Long(int64_t) {} + virtual void ULong(uint64_t) {} + virtual void Float(float) {} + virtual void Double(double) {} + virtual void String(const String *) {} + virtual void Unknown(const uint8_t *) {} // From a future version. + // These mark the scope of a vector. + virtual void StartVector() {} + virtual void EndVector() {} + virtual void Element(size_t /*i*/, ElementaryType /*type*/, + const TypeTable * /*type_table*/, + const uint8_t * /*val*/) {} + virtual ~IterationVisitor() {} +}; + +inline size_t InlineSize(ElementaryType type, const TypeTable *type_table) { + switch (type) { + case ET_UTYPE: + case ET_BOOL: + case ET_CHAR: + case ET_UCHAR: return 1; + case ET_SHORT: + case ET_USHORT: return 2; + case ET_INT: + case ET_UINT: + case ET_FLOAT: + case ET_STRING: return 4; + case ET_LONG: + case ET_ULONG: + case ET_DOUBLE: return 8; + case ET_SEQUENCE: + switch (type_table->st) { + case ST_TABLE: + case ST_UNION: return 4; + case ST_STRUCT: + return static_cast(type_table->values[type_table->num_elems]); + default: FLATBUFFERS_ASSERT(false); return 1; + } + default: FLATBUFFERS_ASSERT(false); return 1; + } +} + +inline int64_t LookupEnum(int64_t enum_val, const int64_t *values, + size_t num_values) { + if (!values) return enum_val; + for (size_t i = 0; i < num_values; i++) { + if (enum_val == values[i]) return static_cast(i); + } + return -1; // Unknown enum value. +} + +template const char *EnumName(T tval, const TypeTable *type_table) { + if (!type_table || !type_table->names) return nullptr; + auto i = LookupEnum(static_cast(tval), type_table->values, + type_table->num_elems); + if (i >= 0 && i < static_cast(type_table->num_elems)) { + return type_table->names[i]; + } + return nullptr; +} + +void IterateObject(const uint8_t *obj, const TypeTable *type_table, + IterationVisitor *visitor); + +inline void IterateValue(ElementaryType type, const uint8_t *val, + const TypeTable *type_table, const uint8_t *prev_val, + soffset_t vector_index, IterationVisitor *visitor) { + switch (type) { + case ET_UTYPE: { + auto tval = ReadScalar(val); + visitor->UType(tval, EnumName(tval, type_table)); + break; + } + case ET_BOOL: { + visitor->Bool(ReadScalar(val) != 0); + break; + } + case ET_CHAR: { + auto tval = ReadScalar(val); + visitor->Char(tval, EnumName(tval, type_table)); + break; + } + case ET_UCHAR: { + auto tval = ReadScalar(val); + visitor->UChar(tval, EnumName(tval, type_table)); + break; + } + case ET_SHORT: { + auto tval = ReadScalar(val); + visitor->Short(tval, EnumName(tval, type_table)); + break; + } + case ET_USHORT: { + auto tval = ReadScalar(val); + visitor->UShort(tval, EnumName(tval, type_table)); + break; + } + case ET_INT: { + auto tval = ReadScalar(val); + visitor->Int(tval, EnumName(tval, type_table)); + break; + } + case ET_UINT: { + auto tval = ReadScalar(val); + visitor->UInt(tval, EnumName(tval, type_table)); + break; + } + case ET_LONG: { + visitor->Long(ReadScalar(val)); + break; + } + case ET_ULONG: { + visitor->ULong(ReadScalar(val)); + break; + } + case ET_FLOAT: { + visitor->Float(ReadScalar(val)); + break; + } + case ET_DOUBLE: { + visitor->Double(ReadScalar(val)); + break; + } + case ET_STRING: { + val += ReadScalar(val); + visitor->String(reinterpret_cast(val)); + break; + } + case ET_SEQUENCE: { + switch (type_table->st) { + case ST_TABLE: + val += ReadScalar(val); + IterateObject(val, type_table, visitor); + break; + case ST_STRUCT: IterateObject(val, type_table, visitor); break; + case ST_UNION: { + val += ReadScalar(val); + FLATBUFFERS_ASSERT(prev_val); + auto union_type = *prev_val; // Always a uint8_t. + if (vector_index >= 0) { + auto type_vec = reinterpret_cast *>(prev_val); + union_type = type_vec->Get(static_cast(vector_index)); + } + auto type_code_idx = + LookupEnum(union_type, type_table->values, type_table->num_elems); + if (type_code_idx >= 0 && + type_code_idx < static_cast(type_table->num_elems)) { + auto type_code = type_table->type_codes[type_code_idx]; + switch (type_code.base_type) { + case ET_SEQUENCE: { + auto ref = type_table->type_refs[type_code.sequence_ref](); + IterateObject(val, ref, visitor); + break; + } + case ET_STRING: + visitor->String(reinterpret_cast(val)); + break; + default: visitor->Unknown(val); + } + } else { + visitor->Unknown(val); + } + break; + } + case ST_ENUM: FLATBUFFERS_ASSERT(false); break; + } + break; + } + default: { + visitor->Unknown(val); + break; + } + } +} + +inline void IterateObject(const uint8_t *obj, const TypeTable *type_table, + IterationVisitor *visitor) { + visitor->StartSequence(); + const uint8_t *prev_val = nullptr; + size_t set_idx = 0; + size_t array_idx = 0; + for (size_t i = 0; i < type_table->num_elems; i++) { + auto type_code = type_table->type_codes[i]; + auto type = static_cast(type_code.base_type); + auto is_repeating = type_code.is_repeating != 0; + auto ref_idx = type_code.sequence_ref; + const TypeTable *ref = nullptr; + if (ref_idx >= 0) { ref = type_table->type_refs[ref_idx](); } + auto name = type_table->names ? type_table->names[i] : nullptr; + const uint8_t *val = nullptr; + if (type_table->st == ST_TABLE) { + val = reinterpret_cast(obj)->GetAddressOf( + FieldIndexToOffset(static_cast(i))); + } else { + val = obj + type_table->values[i]; + } + visitor->Field(i, set_idx, type, is_repeating, ref, name, val); + if (val) { + set_idx++; + if (is_repeating) { + auto elem_ptr = val; + size_t size = 0; + if (type_table->st == ST_TABLE) { + // variable length vector + val += ReadScalar(val); + auto vec = reinterpret_cast *>(val); + elem_ptr = vec->Data(); + size = vec->size(); + } else { + // otherwise fixed size array + size = type_table->array_sizes[array_idx]; + ++array_idx; + } + visitor->StartVector(); + for (size_t j = 0; j < size; j++) { + visitor->Element(j, type, ref, elem_ptr); + IterateValue(type, elem_ptr, ref, prev_val, static_cast(j), + visitor); + elem_ptr += InlineSize(type, ref); + } + visitor->EndVector(); + } else { + IterateValue(type, val, ref, prev_val, -1, visitor); + } + } + prev_val = val; + } + visitor->EndSequence(); +} + +inline void IterateFlatBuffer(const uint8_t *buffer, + const TypeTable *type_table, + IterationVisitor *callback) { + IterateObject(GetRoot(buffer), type_table, callback); +} + +// Outputting a Flatbuffer to a string. Tries to conform as close to JSON / +// the output generated by idl_gen_text.cpp. + +struct ToStringVisitor : public IterationVisitor { + std::string s; + std::string d; + bool q; + std::string in; + size_t indent_level; + bool vector_delimited; + ToStringVisitor(std::string delimiter, bool quotes, std::string indent, + bool vdelimited = true) + : d(delimiter), + q(quotes), + in(indent), + indent_level(0), + vector_delimited(vdelimited) {} + ToStringVisitor(std::string delimiter) + : d(delimiter), + q(false), + in(""), + indent_level(0), + vector_delimited(true) {} + + void append_indent() { + for (size_t i = 0; i < indent_level; i++) { s += in; } + } + + void StartSequence() { + s += "{"; + s += d; + indent_level++; + } + void EndSequence() { + s += d; + indent_level--; + append_indent(); + s += "}"; + } + void Field(size_t /*field_idx*/, size_t set_idx, ElementaryType /*type*/, + bool /*is_vector*/, const TypeTable * /*type_table*/, + const char *name, const uint8_t *val) { + if (!val) return; + if (set_idx) { + s += ","; + s += d; + } + append_indent(); + if (name) { + if (q) s += "\""; + s += name; + if (q) s += "\""; + s += ": "; + } + } + template void Named(T x, const char *name) { + if (name) { + if (q) s += "\""; + s += name; + if (q) s += "\""; + } else { + s += NumToString(x); + } + } + void UType(uint8_t x, const char *name) { Named(x, name); } + void Bool(bool x) { s += x ? "true" : "false"; } + void Char(int8_t x, const char *name) { Named(x, name); } + void UChar(uint8_t x, const char *name) { Named(x, name); } + void Short(int16_t x, const char *name) { Named(x, name); } + void UShort(uint16_t x, const char *name) { Named(x, name); } + void Int(int32_t x, const char *name) { Named(x, name); } + void UInt(uint32_t x, const char *name) { Named(x, name); } + void Long(int64_t x) { s += NumToString(x); } + void ULong(uint64_t x) { s += NumToString(x); } + void Float(float x) { s += NumToString(x); } + void Double(double x) { s += NumToString(x); } + void String(const struct String *str) { + EscapeString(str->c_str(), str->size(), &s, true, false); + } + void Unknown(const uint8_t *) { s += "(?)"; } + void StartVector() { + s += "["; + if (vector_delimited) { + s += d; + indent_level++; + append_indent(); + } else { + s += " "; + } + } + void EndVector() { + if (vector_delimited) { + s += d; + indent_level--; + append_indent(); + } else { + s += " "; + } + s += "]"; + } + void Element(size_t i, ElementaryType /*type*/, + const TypeTable * /*type_table*/, const uint8_t * /*val*/) { + if (i) { + s += ","; + if (vector_delimited) { + s += d; + append_indent(); + } else { + s += " "; + } + } + } +}; + +inline std::string FlatBufferToString(const uint8_t *buffer, + const TypeTable *type_table, + bool multi_line = false, + bool vector_delimited = true) { + ToStringVisitor tostring_visitor(multi_line ? "\n" : " ", false, "", + vector_delimited); + IterateFlatBuffer(buffer, type_table, &tostring_visitor); + return tostring_visitor.s; +} + +} // namespace flatbuffers +} // namespace mapserver + +#endif // FLATBUFFERS_MINIREFLECT_H_ diff --git a/src/flatgeobuf/include/flatbuffers/pch/flatc_pch.h b/src/flatgeobuf/include/flatbuffers/pch/flatc_pch.h new file mode 100644 index 0000000000..77132790b6 --- /dev/null +++ b/src/flatgeobuf/include/flatbuffers/pch/flatc_pch.h @@ -0,0 +1,39 @@ +/* + * Copyright 2017 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLATBUFFERS_FLATC_PCH_H_ +#define FLATBUFFERS_FLATC_PCH_H_ + +// stl +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// flatbuffers +#include "flatbuffers/pch/pch.h" +#include "flatbuffers/code_generators.h" +#include "flatbuffers/flatbuffers.h" +#include "flatbuffers/flexbuffers.h" +#include "flatbuffers/idl.h" + +#endif // FLATBUFFERS_FLATC_PCH_H_ diff --git a/src/flatgeobuf/include/flatbuffers/pch/pch.h b/src/flatgeobuf/include/flatbuffers/pch/pch.h new file mode 100644 index 0000000000..804e99ed04 --- /dev/null +++ b/src/flatgeobuf/include/flatbuffers/pch/pch.h @@ -0,0 +1,38 @@ +/* + * Copyright 2017 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLATBUFFERS_PCH_H_ +#define FLATBUFFERS_PCH_H_ + +// stl +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// flatbuffers +#include "flatbuffers/util.h" + +#endif // FLATBUFFERS_PCH_H_ diff --git a/src/flatgeobuf/include/flatbuffers/reflection.h b/src/flatgeobuf/include/flatbuffers/reflection.h new file mode 100644 index 0000000000..4ddd6f5f9f --- /dev/null +++ b/src/flatgeobuf/include/flatbuffers/reflection.h @@ -0,0 +1,524 @@ +/* + * Copyright 2015 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLATBUFFERS_REFLECTION_H_ +#define FLATBUFFERS_REFLECTION_H_ + +// This is somewhat of a circular dependency because flatc (and thus this +// file) is needed to generate this header in the first place. +// Should normally not be a problem since it can be generated by the +// previous version of flatc whenever this code needs to change. +// See scripts/generate_code.py for generation. +#include "flatbuffers/reflection_generated.h" + +// Helper functionality for reflection. + +namespace mapserver { +namespace flatbuffers { + +// ------------------------- GETTERS ------------------------- + +inline bool IsScalar(reflection::BaseType t) { + return t >= reflection::UType && t <= reflection::Double; +} +inline bool IsInteger(reflection::BaseType t) { + return t >= reflection::UType && t <= reflection::ULong; +} +inline bool IsFloat(reflection::BaseType t) { + return t == reflection::Float || t == reflection::Double; +} +inline bool IsLong(reflection::BaseType t) { + return t == reflection::Long || t == reflection::ULong; +} + +// Size of a basic type, don't use with structs. +inline size_t GetTypeSize(reflection::BaseType base_type) { + // This needs to correspond to the BaseType enum. + static size_t sizes[] = { + 0, // None + 1, // UType + 1, // Bool + 1, // Byte + 1, // UByte + 2, // Short + 2, // UShort + 4, // Int + 4, // UInt + 8, // Long + 8, // ULong + 4, // Float + 8, // Double + 4, // String + 4, // Vector + 4, // Obj + 4, // Union + 0, // Array. Only used in structs. 0 was chosen to prevent out-of-bounds + // errors. + + 0 // MaxBaseType. This must be kept the last entry in this array. + }; + static_assert(sizeof(sizes) / sizeof(size_t) == reflection::MaxBaseType + 1, + "Size of sizes[] array does not match the count of BaseType " + "enum values."); + return sizes[base_type]; +} + +// Same as above, but now correctly returns the size of a struct if +// the field (or vector element) is a struct. +inline size_t GetTypeSizeInline(reflection::BaseType base_type, int type_index, + const reflection::Schema &schema) { + if (base_type == reflection::Obj && + schema.objects()->Get(type_index)->is_struct()) { + return schema.objects()->Get(type_index)->bytesize(); + } else { + return GetTypeSize(base_type); + } +} + +// Get the root, regardless of what type it is. +inline Table *GetAnyRoot(uint8_t *const flatbuf) { + return GetMutableRoot(flatbuf); +} + +inline const Table *GetAnyRoot(const uint8_t *const flatbuf) { + return GetRoot
(flatbuf); +} + +inline Table *GetAnySizePrefixedRoot(uint8_t *const flatbuf) { + return GetMutableSizePrefixedRoot
(flatbuf); +} + +inline const Table *GetAnySizePrefixedRoot(const uint8_t *const flatbuf) { + return GetSizePrefixedRoot
(flatbuf); +} + +// Get a field's default, if you know it's an integer, and its exact type. +template T GetFieldDefaultI(const reflection::Field &field) { + FLATBUFFERS_ASSERT(sizeof(T) == GetTypeSize(field.type()->base_type())); + return static_cast(field.default_integer()); +} + +// Get a field's default, if you know it's floating point and its exact type. +template T GetFieldDefaultF(const reflection::Field &field) { + FLATBUFFERS_ASSERT(sizeof(T) == GetTypeSize(field.type()->base_type())); + return static_cast(field.default_real()); +} + +// Get a field, if you know it's an integer, and its exact type. +template +T GetFieldI(const Table &table, const reflection::Field &field) { + FLATBUFFERS_ASSERT(sizeof(T) == GetTypeSize(field.type()->base_type())); + return table.GetField(field.offset(), + static_cast(field.default_integer())); +} + +// Get a field, if you know it's floating point and its exact type. +template +T GetFieldF(const Table &table, const reflection::Field &field) { + FLATBUFFERS_ASSERT(sizeof(T) == GetTypeSize(field.type()->base_type())); + return table.GetField(field.offset(), + static_cast(field.default_real())); +} + +// Get a field, if you know it's a string. +inline const String *GetFieldS(const Table &table, + const reflection::Field &field) { + FLATBUFFERS_ASSERT(field.type()->base_type() == reflection::String); + return table.GetPointer(field.offset()); +} + +// Get a field, if you know it's a vector. +template +Vector *GetFieldV(const Table &table, const reflection::Field &field) { + FLATBUFFERS_ASSERT(field.type()->base_type() == reflection::Vector && + sizeof(T) == GetTypeSize(field.type()->element())); + return table.GetPointer *>(field.offset()); +} + +// Get a field, if you know it's a vector, generically. +// To actually access elements, use the return value together with +// field.type()->element() in any of GetAnyVectorElemI below etc. +inline VectorOfAny *GetFieldAnyV(const Table &table, + const reflection::Field &field) { + return table.GetPointer(field.offset()); +} + +// Get a field, if you know it's a table. +inline Table *GetFieldT(const Table &table, const reflection::Field &field) { + FLATBUFFERS_ASSERT(field.type()->base_type() == reflection::Obj || + field.type()->base_type() == reflection::Union); + return table.GetPointer
(field.offset()); +} + +// Get a field, if you know it's a struct. +inline const Struct *GetFieldStruct(const Table &table, + const reflection::Field &field) { + // TODO: This does NOT check if the field is a table or struct, but we'd need + // access to the schema to check the is_struct flag. + FLATBUFFERS_ASSERT(field.type()->base_type() == reflection::Obj); + return table.GetStruct(field.offset()); +} + +// Get a structure's field, if you know it's a struct. +inline const Struct *GetFieldStruct(const Struct &structure, + const reflection::Field &field) { + FLATBUFFERS_ASSERT(field.type()->base_type() == reflection::Obj); + return structure.GetStruct(field.offset()); +} + +// Raw helper functions used below: get any value in memory as a 64bit int, a +// double or a string. +// All scalars get static_cast to an int64_t, strings use strtoull, every other +// data type returns 0. +int64_t GetAnyValueI(reflection::BaseType type, const uint8_t *data); +// All scalars static cast to double, strings use strtod, every other data +// type is 0.0. +double GetAnyValueF(reflection::BaseType type, const uint8_t *data); +// All scalars converted using stringstream, strings as-is, and all other +// data types provide some level of debug-pretty-printing. +std::string GetAnyValueS(reflection::BaseType type, const uint8_t *data, + const reflection::Schema *schema, int type_index); + +// Get any table field as a 64bit int, regardless of what type it is. +inline int64_t GetAnyFieldI(const Table &table, + const reflection::Field &field) { + auto field_ptr = table.GetAddressOf(field.offset()); + return field_ptr ? GetAnyValueI(field.type()->base_type(), field_ptr) + : field.default_integer(); +} + +// Get any table field as a double, regardless of what type it is. +inline double GetAnyFieldF(const Table &table, const reflection::Field &field) { + auto field_ptr = table.GetAddressOf(field.offset()); + return field_ptr ? GetAnyValueF(field.type()->base_type(), field_ptr) + : field.default_real(); +} + +// Get any table field as a string, regardless of what type it is. +// You may pass nullptr for the schema if you don't care to have fields that +// are of table type pretty-printed. +inline std::string GetAnyFieldS(const Table &table, + const reflection::Field &field, + const reflection::Schema *schema) { + auto field_ptr = table.GetAddressOf(field.offset()); + return field_ptr ? GetAnyValueS(field.type()->base_type(), field_ptr, schema, + field.type()->index()) + : ""; +} + +// Get any struct field as a 64bit int, regardless of what type it is. +inline int64_t GetAnyFieldI(const Struct &st, const reflection::Field &field) { + return GetAnyValueI(field.type()->base_type(), + st.GetAddressOf(field.offset())); +} + +// Get any struct field as a double, regardless of what type it is. +inline double GetAnyFieldF(const Struct &st, const reflection::Field &field) { + return GetAnyValueF(field.type()->base_type(), + st.GetAddressOf(field.offset())); +} + +// Get any struct field as a string, regardless of what type it is. +inline std::string GetAnyFieldS(const Struct &st, + const reflection::Field &field) { + return GetAnyValueS(field.type()->base_type(), + st.GetAddressOf(field.offset()), nullptr, -1); +} + +// Get any vector element as a 64bit int, regardless of what type it is. +inline int64_t GetAnyVectorElemI(const VectorOfAny *vec, + reflection::BaseType elem_type, size_t i) { + return GetAnyValueI(elem_type, vec->Data() + GetTypeSize(elem_type) * i); +} + +// Get any vector element as a double, regardless of what type it is. +inline double GetAnyVectorElemF(const VectorOfAny *vec, + reflection::BaseType elem_type, size_t i) { + return GetAnyValueF(elem_type, vec->Data() + GetTypeSize(elem_type) * i); +} + +// Get any vector element as a string, regardless of what type it is. +inline std::string GetAnyVectorElemS(const VectorOfAny *vec, + reflection::BaseType elem_type, size_t i) { + return GetAnyValueS(elem_type, vec->Data() + GetTypeSize(elem_type) * i, + nullptr, -1); +} + +// Get a vector element that's a table/string/vector from a generic vector. +// Pass Table/String/VectorOfAny as template parameter. +// Warning: does no typechecking. +template +T *GetAnyVectorElemPointer(const VectorOfAny *vec, size_t i) { + auto elem_ptr = vec->Data() + sizeof(uoffset_t) * i; + return reinterpret_cast(elem_ptr + ReadScalar(elem_ptr)); +} + +// Get the inline-address of a vector element. Useful for Structs (pass Struct +// as template arg), or being able to address a range of scalars in-line. +// Get elem_size from GetTypeSizeInline(). +// Note: little-endian data on all platforms, use EndianScalar() instead of +// raw pointer access with scalars). +template +T *GetAnyVectorElemAddressOf(const VectorOfAny *vec, size_t i, + size_t elem_size) { + return reinterpret_cast(vec->Data() + elem_size * i); +} + +// Similarly, for elements of tables. +template +T *GetAnyFieldAddressOf(const Table &table, const reflection::Field &field) { + return reinterpret_cast(table.GetAddressOf(field.offset())); +} + +// Similarly, for elements of structs. +template +T *GetAnyFieldAddressOf(const Struct &st, const reflection::Field &field) { + return reinterpret_cast(st.GetAddressOf(field.offset())); +} + +// Loop over all the fields of the provided `object` and call `func` on each one +// in increasing order by their field->id(). If `reverse` is true, `func` is +// called in descending order +void ForAllFields(const reflection::Object *object, bool reverse, + std::function func); + +// ------------------------- SETTERS ------------------------- + +// Set any scalar field, if you know its exact type. +template +bool SetField(Table *table, const reflection::Field &field, T val) { + reflection::BaseType type = field.type()->base_type(); + if (!IsScalar(type)) { return false; } + FLATBUFFERS_ASSERT(sizeof(T) == GetTypeSize(type)); + T def; + if (IsInteger(type)) { + def = GetFieldDefaultI(field); + } else { + FLATBUFFERS_ASSERT(IsFloat(type)); + def = GetFieldDefaultF(field); + } + return table->SetField(field.offset(), val, def); +} + +// Raw helper functions used below: set any value in memory as a 64bit int, a +// double or a string. +// These work for all scalar values, but do nothing for other data types. +// To set a string, see SetString below. +void SetAnyValueI(reflection::BaseType type, uint8_t *data, int64_t val); +void SetAnyValueF(reflection::BaseType type, uint8_t *data, double val); +void SetAnyValueS(reflection::BaseType type, uint8_t *data, const char *val); + +// Set any table field as a 64bit int, regardless of type what it is. +inline bool SetAnyFieldI(Table *table, const reflection::Field &field, + int64_t val) { + auto field_ptr = table->GetAddressOf(field.offset()); + if (!field_ptr) return val == GetFieldDefaultI(field); + SetAnyValueI(field.type()->base_type(), field_ptr, val); + return true; +} + +// Set any table field as a double, regardless of what type it is. +inline bool SetAnyFieldF(Table *table, const reflection::Field &field, + double val) { + auto field_ptr = table->GetAddressOf(field.offset()); + if (!field_ptr) return val == GetFieldDefaultF(field); + SetAnyValueF(field.type()->base_type(), field_ptr, val); + return true; +} + +// Set any table field as a string, regardless of what type it is. +inline bool SetAnyFieldS(Table *table, const reflection::Field &field, + const char *val) { + auto field_ptr = table->GetAddressOf(field.offset()); + if (!field_ptr) return false; + SetAnyValueS(field.type()->base_type(), field_ptr, val); + return true; +} + +// Set any struct field as a 64bit int, regardless of type what it is. +inline void SetAnyFieldI(Struct *st, const reflection::Field &field, + int64_t val) { + SetAnyValueI(field.type()->base_type(), st->GetAddressOf(field.offset()), + val); +} + +// Set any struct field as a double, regardless of type what it is. +inline void SetAnyFieldF(Struct *st, const reflection::Field &field, + double val) { + SetAnyValueF(field.type()->base_type(), st->GetAddressOf(field.offset()), + val); +} + +// Set any struct field as a string, regardless of type what it is. +inline void SetAnyFieldS(Struct *st, const reflection::Field &field, + const char *val) { + SetAnyValueS(field.type()->base_type(), st->GetAddressOf(field.offset()), + val); +} + +// Set any vector element as a 64bit int, regardless of type what it is. +inline void SetAnyVectorElemI(VectorOfAny *vec, reflection::BaseType elem_type, + size_t i, int64_t val) { + SetAnyValueI(elem_type, vec->Data() + GetTypeSize(elem_type) * i, val); +} + +// Set any vector element as a double, regardless of type what it is. +inline void SetAnyVectorElemF(VectorOfAny *vec, reflection::BaseType elem_type, + size_t i, double val) { + SetAnyValueF(elem_type, vec->Data() + GetTypeSize(elem_type) * i, val); +} + +// Set any vector element as a string, regardless of type what it is. +inline void SetAnyVectorElemS(VectorOfAny *vec, reflection::BaseType elem_type, + size_t i, const char *val) { + SetAnyValueS(elem_type, vec->Data() + GetTypeSize(elem_type) * i, val); +} + +// ------------------------- RESIZING SETTERS ------------------------- + +// "smart" pointer for use with resizing vectors: turns a pointer inside +// a vector into a relative offset, such that it is not affected by resizes. +template class pointer_inside_vector { + public: + pointer_inside_vector(T *ptr, std::vector &vec) + : offset_(reinterpret_cast(ptr) - + reinterpret_cast(vec.data())), + vec_(vec) {} + + T *operator*() const { + return reinterpret_cast(reinterpret_cast(vec_.data()) + + offset_); + } + T *operator->() const { return operator*(); } + + private: + size_t offset_; + std::vector &vec_; +}; + +// Helper to create the above easily without specifying template args. +template +pointer_inside_vector piv(T *ptr, std::vector &vec) { + return pointer_inside_vector(ptr, vec); +} + +inline const char *UnionTypeFieldSuffix() { return "_type"; } + +// Helper to figure out the actual table type a union refers to. +inline const reflection::Object &GetUnionType( + const reflection::Schema &schema, const reflection::Object &parent, + const reflection::Field &unionfield, const Table &table) { + auto enumdef = schema.enums()->Get(unionfield.type()->index()); + // TODO: this is clumsy and slow, but no other way to find it? + auto type_field = parent.fields()->LookupByKey( + (unionfield.name()->str() + UnionTypeFieldSuffix()).c_str()); + FLATBUFFERS_ASSERT(type_field); + auto union_type = GetFieldI(table, *type_field); + auto enumval = enumdef->values()->LookupByKey(union_type); + return *schema.objects()->Get(enumval->union_type()->index()); +} + +// Changes the contents of a string inside a FlatBuffer. FlatBuffer must +// live inside a std::vector so we can resize the buffer if needed. +// "str" must live inside "flatbuf" and may be invalidated after this call. +// If your FlatBuffer's root table is not the schema's root table, you should +// pass in your root_table type as well. +void SetString(const reflection::Schema &schema, const std::string &val, + const String *str, std::vector *flatbuf, + const reflection::Object *root_table = nullptr); + +// Resizes a flatbuffers::Vector inside a FlatBuffer. FlatBuffer must +// live inside a std::vector so we can resize the buffer if needed. +// "vec" must live inside "flatbuf" and may be invalidated after this call. +// If your FlatBuffer's root table is not the schema's root table, you should +// pass in your root_table type as well. +uint8_t *ResizeAnyVector(const reflection::Schema &schema, uoffset_t newsize, + const VectorOfAny *vec, uoffset_t num_elems, + uoffset_t elem_size, std::vector *flatbuf, + const reflection::Object *root_table = nullptr); + +template +void ResizeVector(const reflection::Schema &schema, uoffset_t newsize, T val, + const Vector *vec, std::vector *flatbuf, + const reflection::Object *root_table = nullptr) { + auto delta_elem = static_cast(newsize) - static_cast(vec->size()); + auto newelems = ResizeAnyVector( + schema, newsize, reinterpret_cast(vec), vec->size(), + static_cast(sizeof(T)), flatbuf, root_table); + // Set new elements to "val". + for (int i = 0; i < delta_elem; i++) { + auto loc = newelems + i * sizeof(T); + auto is_scalar = flatbuffers::is_scalar::value; + if (is_scalar) { + WriteScalar(loc, val); + } else { // struct + *reinterpret_cast(loc) = val; + } + } +} + +// Adds any new data (in the form of a new FlatBuffer) to an existing +// FlatBuffer. This can be used when any of the above methods are not +// sufficient, in particular for adding new tables and new fields. +// This is potentially slightly less efficient than a FlatBuffer constructed +// in one piece, since the new FlatBuffer doesn't share any vtables with the +// existing one. +// The return value can now be set using Vector::MutateOffset or SetFieldT +// below. +const uint8_t *AddFlatBuffer(std::vector &flatbuf, + const uint8_t *newbuf, size_t newlen); + +inline bool SetFieldT(Table *table, const reflection::Field &field, + const uint8_t *val) { + FLATBUFFERS_ASSERT(sizeof(uoffset_t) == + GetTypeSize(field.type()->base_type())); + return table->SetPointer(field.offset(), val); +} + +// ------------------------- COPYING ------------------------- + +// Generic copying of tables from a FlatBuffer into a FlatBuffer builder. +// Can be used to do any kind of merging/selecting you may want to do out +// of existing buffers. Also useful to reconstruct a whole buffer if the +// above resizing functionality has introduced garbage in a buffer you want +// to remove. +// Note: this does not deal with DAGs correctly. If the table passed forms a +// DAG, the copy will be a tree instead (with duplicates). Strings can be +// shared however, by passing true for use_string_pooling. + +Offset CopyTable(FlatBufferBuilder &fbb, + const reflection::Schema &schema, + const reflection::Object &objectdef, + const Table &table, + bool use_string_pooling = false); + +// Verifies the provided flatbuffer using reflection. +// root should point to the root type for this flatbuffer. +// buf should point to the start of flatbuffer data. +// length specifies the size of the flatbuffer data. +bool Verify(const reflection::Schema &schema, const reflection::Object &root, + const uint8_t *buf, size_t length, uoffset_t max_depth = 64, + uoffset_t max_tables = 1000000); + +bool VerifySizePrefixed(const reflection::Schema &schema, + const reflection::Object &root, const uint8_t *buf, + size_t length, uoffset_t max_depth = 64, + uoffset_t max_tables = 1000000); + +} // namespace flatbuffers +} // namespace mapserver + +#endif // FLATBUFFERS_REFLECTION_H_ diff --git a/src/flatgeobuf/include/flatbuffers/reflection_generated.h b/src/flatgeobuf/include/flatbuffers/reflection_generated.h new file mode 100644 index 0000000000..1ec414d30b --- /dev/null +++ b/src/flatgeobuf/include/flatbuffers/reflection_generated.h @@ -0,0 +1,1456 @@ +// automatically generated by the FlatBuffers compiler, do not modify + + +#ifndef FLATBUFFERS_GENERATED_REFLECTION_REFLECTION_H_ +#define FLATBUFFERS_GENERATED_REFLECTION_REFLECTION_H_ + +#include "flatbuffers/flatbuffers.h" + +// Ensure the included flatbuffers.h is the same version as when this file was +// generated, otherwise it may not be compatible. +static_assert(FLATBUFFERS_VERSION_MAJOR == 2 && + FLATBUFFERS_VERSION_MINOR == 0 && + FLATBUFFERS_VERSION_REVISION == 6, + "Non-compatible flatbuffers version included"); + +namespace reflection { + +struct Type; +struct TypeBuilder; + +struct KeyValue; +struct KeyValueBuilder; + +struct EnumVal; +struct EnumValBuilder; + +struct Enum; +struct EnumBuilder; + +struct Field; +struct FieldBuilder; + +struct Object; +struct ObjectBuilder; + +struct RPCCall; +struct RPCCallBuilder; + +struct Service; +struct ServiceBuilder; + +struct SchemaFile; +struct SchemaFileBuilder; + +struct Schema; +struct SchemaBuilder; + +enum BaseType { + None = 0, + UType = 1, + Bool = 2, + Byte = 3, + UByte = 4, + Short = 5, + UShort = 6, + Int = 7, + UInt = 8, + Long = 9, + ULong = 10, + Float = 11, + Double = 12, + String = 13, + Vector = 14, + Obj = 15, + Union = 16, + Array = 17, + MaxBaseType = 18 +}; + +inline const BaseType (&EnumValuesBaseType())[19] { + static const BaseType values[] = { + None, + UType, + Bool, + Byte, + UByte, + Short, + UShort, + Int, + UInt, + Long, + ULong, + Float, + Double, + String, + Vector, + Obj, + Union, + Array, + MaxBaseType + }; + return values; +} + +inline const char * const *EnumNamesBaseType() { + static const char * const names[20] = { + "None", + "UType", + "Bool", + "Byte", + "UByte", + "Short", + "UShort", + "Int", + "UInt", + "Long", + "ULong", + "Float", + "Double", + "String", + "Vector", + "Obj", + "Union", + "Array", + "MaxBaseType", + nullptr + }; + return names; +} + +inline const char *EnumNameBaseType(BaseType e) { + if (flatbuffers::IsOutRange(e, None, MaxBaseType)) return ""; + const size_t index = static_cast(e); + return EnumNamesBaseType()[index]; +} + +/// New schema language features that are not supported by old code generators. +enum AdvancedFeatures { + AdvancedArrayFeatures = 1ULL, + AdvancedUnionFeatures = 2ULL, + OptionalScalars = 4ULL, + DefaultVectorsAndStrings = 8ULL +}; + +inline const AdvancedFeatures (&EnumValuesAdvancedFeatures())[4] { + static const AdvancedFeatures values[] = { + AdvancedArrayFeatures, + AdvancedUnionFeatures, + OptionalScalars, + DefaultVectorsAndStrings + }; + return values; +} + +inline const char * const *EnumNamesAdvancedFeatures() { + static const char * const names[9] = { + "AdvancedArrayFeatures", + "AdvancedUnionFeatures", + "", + "OptionalScalars", + "", + "", + "", + "DefaultVectorsAndStrings", + nullptr + }; + return names; +} + +inline const char *EnumNameAdvancedFeatures(AdvancedFeatures e) { + if (flatbuffers::IsOutRange(e, AdvancedArrayFeatures, DefaultVectorsAndStrings)) return ""; + const size_t index = static_cast(e) - static_cast(AdvancedArrayFeatures); + return EnumNamesAdvancedFeatures()[index]; +} + +struct Type FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef TypeBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_BASE_TYPE = 4, + VT_ELEMENT = 6, + VT_INDEX = 8, + VT_FIXED_LENGTH = 10, + VT_BASE_SIZE = 12, + VT_ELEMENT_SIZE = 14 + }; + reflection::BaseType base_type() const { + return static_cast(GetField(VT_BASE_TYPE, 0)); + } + reflection::BaseType element() const { + return static_cast(GetField(VT_ELEMENT, 0)); + } + int32_t index() const { + return GetField(VT_INDEX, -1); + } + uint16_t fixed_length() const { + return GetField(VT_FIXED_LENGTH, 0); + } + /// The size (octets) of the `base_type` field. + uint32_t base_size() const { + return GetField(VT_BASE_SIZE, 4); + } + /// The size (octets) of the `element` field, if present. + uint32_t element_size() const { + return GetField(VT_ELEMENT_SIZE, 0); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_BASE_TYPE, 1) && + VerifyField(verifier, VT_ELEMENT, 1) && + VerifyField(verifier, VT_INDEX, 4) && + VerifyField(verifier, VT_FIXED_LENGTH, 2) && + VerifyField(verifier, VT_BASE_SIZE, 4) && + VerifyField(verifier, VT_ELEMENT_SIZE, 4) && + verifier.EndTable(); + } +}; + +struct TypeBuilder { + typedef Type Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_base_type(reflection::BaseType base_type) { + fbb_.AddElement(Type::VT_BASE_TYPE, static_cast(base_type), 0); + } + void add_element(reflection::BaseType element) { + fbb_.AddElement(Type::VT_ELEMENT, static_cast(element), 0); + } + void add_index(int32_t index) { + fbb_.AddElement(Type::VT_INDEX, index, -1); + } + void add_fixed_length(uint16_t fixed_length) { + fbb_.AddElement(Type::VT_FIXED_LENGTH, fixed_length, 0); + } + void add_base_size(uint32_t base_size) { + fbb_.AddElement(Type::VT_BASE_SIZE, base_size, 4); + } + void add_element_size(uint32_t element_size) { + fbb_.AddElement(Type::VT_ELEMENT_SIZE, element_size, 0); + } + explicit TypeBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateType( + flatbuffers::FlatBufferBuilder &_fbb, + reflection::BaseType base_type = reflection::None, + reflection::BaseType element = reflection::None, + int32_t index = -1, + uint16_t fixed_length = 0, + uint32_t base_size = 4, + uint32_t element_size = 0) { + TypeBuilder builder_(_fbb); + builder_.add_element_size(element_size); + builder_.add_base_size(base_size); + builder_.add_index(index); + builder_.add_fixed_length(fixed_length); + builder_.add_element(element); + builder_.add_base_type(base_type); + return builder_.Finish(); +} + +struct KeyValue FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef KeyValueBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_KEY = 4, + VT_VALUE = 6 + }; + const flatbuffers::String *key() const { + return GetPointer(VT_KEY); + } + bool KeyCompareLessThan(const KeyValue *o) const { + return *key() < *o->key(); + } + int KeyCompareWithValue(const char *_key) const { + return strcmp(key()->c_str(), _key); + } + const flatbuffers::String *value() const { + return GetPointer(VT_VALUE); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffsetRequired(verifier, VT_KEY) && + verifier.VerifyString(key()) && + VerifyOffset(verifier, VT_VALUE) && + verifier.VerifyString(value()) && + verifier.EndTable(); + } +}; + +struct KeyValueBuilder { + typedef KeyValue Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_key(flatbuffers::Offset key) { + fbb_.AddOffset(KeyValue::VT_KEY, key); + } + void add_value(flatbuffers::Offset value) { + fbb_.AddOffset(KeyValue::VT_VALUE, value); + } + explicit KeyValueBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + fbb_.Required(o, KeyValue::VT_KEY); + return o; + } +}; + +inline flatbuffers::Offset CreateKeyValue( + flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset key = 0, + flatbuffers::Offset value = 0) { + KeyValueBuilder builder_(_fbb); + builder_.add_value(value); + builder_.add_key(key); + return builder_.Finish(); +} + +inline flatbuffers::Offset CreateKeyValueDirect( + flatbuffers::FlatBufferBuilder &_fbb, + const char *key = nullptr, + const char *value = nullptr) { + auto key__ = key ? _fbb.CreateString(key) : 0; + auto value__ = value ? _fbb.CreateString(value) : 0; + return reflection::CreateKeyValue( + _fbb, + key__, + value__); +} + +struct EnumVal FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef EnumValBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_NAME = 4, + VT_VALUE = 6, + VT_UNION_TYPE = 10, + VT_DOCUMENTATION = 12 + }; + const flatbuffers::String *name() const { + return GetPointer(VT_NAME); + } + int64_t value() const { + return GetField(VT_VALUE, 0); + } + bool KeyCompareLessThan(const EnumVal *o) const { + return value() < o->value(); + } + int KeyCompareWithValue(int64_t _value) const { + return static_cast(value() > _value) - static_cast(value() < _value); + } + const reflection::Type *union_type() const { + return GetPointer(VT_UNION_TYPE); + } + const flatbuffers::Vector> *documentation() const { + return GetPointer> *>(VT_DOCUMENTATION); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffsetRequired(verifier, VT_NAME) && + verifier.VerifyString(name()) && + VerifyField(verifier, VT_VALUE, 8) && + VerifyOffset(verifier, VT_UNION_TYPE) && + verifier.VerifyTable(union_type()) && + VerifyOffset(verifier, VT_DOCUMENTATION) && + verifier.VerifyVector(documentation()) && + verifier.VerifyVectorOfStrings(documentation()) && + verifier.EndTable(); + } +}; + +struct EnumValBuilder { + typedef EnumVal Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_name(flatbuffers::Offset name) { + fbb_.AddOffset(EnumVal::VT_NAME, name); + } + void add_value(int64_t value) { + fbb_.AddElement(EnumVal::VT_VALUE, value, 0); + } + void add_union_type(flatbuffers::Offset union_type) { + fbb_.AddOffset(EnumVal::VT_UNION_TYPE, union_type); + } + void add_documentation(flatbuffers::Offset>> documentation) { + fbb_.AddOffset(EnumVal::VT_DOCUMENTATION, documentation); + } + explicit EnumValBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + fbb_.Required(o, EnumVal::VT_NAME); + return o; + } +}; + +inline flatbuffers::Offset CreateEnumVal( + flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset name = 0, + int64_t value = 0, + flatbuffers::Offset union_type = 0, + flatbuffers::Offset>> documentation = 0) { + EnumValBuilder builder_(_fbb); + builder_.add_value(value); + builder_.add_documentation(documentation); + builder_.add_union_type(union_type); + builder_.add_name(name); + return builder_.Finish(); +} + +inline flatbuffers::Offset CreateEnumValDirect( + flatbuffers::FlatBufferBuilder &_fbb, + const char *name = nullptr, + int64_t value = 0, + flatbuffers::Offset union_type = 0, + const std::vector> *documentation = nullptr) { + auto name__ = name ? _fbb.CreateString(name) : 0; + auto documentation__ = documentation ? _fbb.CreateVector>(*documentation) : 0; + return reflection::CreateEnumVal( + _fbb, + name__, + value, + union_type, + documentation__); +} + +struct Enum FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef EnumBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_NAME = 4, + VT_VALUES = 6, + VT_IS_UNION = 8, + VT_UNDERLYING_TYPE = 10, + VT_ATTRIBUTES = 12, + VT_DOCUMENTATION = 14, + VT_DECLARATION_FILE = 16 + }; + const flatbuffers::String *name() const { + return GetPointer(VT_NAME); + } + bool KeyCompareLessThan(const Enum *o) const { + return *name() < *o->name(); + } + int KeyCompareWithValue(const char *_name) const { + return strcmp(name()->c_str(), _name); + } + const flatbuffers::Vector> *values() const { + return GetPointer> *>(VT_VALUES); + } + bool is_union() const { + return GetField(VT_IS_UNION, 0) != 0; + } + const reflection::Type *underlying_type() const { + return GetPointer(VT_UNDERLYING_TYPE); + } + const flatbuffers::Vector> *attributes() const { + return GetPointer> *>(VT_ATTRIBUTES); + } + const flatbuffers::Vector> *documentation() const { + return GetPointer> *>(VT_DOCUMENTATION); + } + /// File that this Enum is declared in. + const flatbuffers::String *declaration_file() const { + return GetPointer(VT_DECLARATION_FILE); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffsetRequired(verifier, VT_NAME) && + verifier.VerifyString(name()) && + VerifyOffsetRequired(verifier, VT_VALUES) && + verifier.VerifyVector(values()) && + verifier.VerifyVectorOfTables(values()) && + VerifyField(verifier, VT_IS_UNION, 1) && + VerifyOffsetRequired(verifier, VT_UNDERLYING_TYPE) && + verifier.VerifyTable(underlying_type()) && + VerifyOffset(verifier, VT_ATTRIBUTES) && + verifier.VerifyVector(attributes()) && + verifier.VerifyVectorOfTables(attributes()) && + VerifyOffset(verifier, VT_DOCUMENTATION) && + verifier.VerifyVector(documentation()) && + verifier.VerifyVectorOfStrings(documentation()) && + VerifyOffset(verifier, VT_DECLARATION_FILE) && + verifier.VerifyString(declaration_file()) && + verifier.EndTable(); + } +}; + +struct EnumBuilder { + typedef Enum Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_name(flatbuffers::Offset name) { + fbb_.AddOffset(Enum::VT_NAME, name); + } + void add_values(flatbuffers::Offset>> values) { + fbb_.AddOffset(Enum::VT_VALUES, values); + } + void add_is_union(bool is_union) { + fbb_.AddElement(Enum::VT_IS_UNION, static_cast(is_union), 0); + } + void add_underlying_type(flatbuffers::Offset underlying_type) { + fbb_.AddOffset(Enum::VT_UNDERLYING_TYPE, underlying_type); + } + void add_attributes(flatbuffers::Offset>> attributes) { + fbb_.AddOffset(Enum::VT_ATTRIBUTES, attributes); + } + void add_documentation(flatbuffers::Offset>> documentation) { + fbb_.AddOffset(Enum::VT_DOCUMENTATION, documentation); + } + void add_declaration_file(flatbuffers::Offset declaration_file) { + fbb_.AddOffset(Enum::VT_DECLARATION_FILE, declaration_file); + } + explicit EnumBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + fbb_.Required(o, Enum::VT_NAME); + fbb_.Required(o, Enum::VT_VALUES); + fbb_.Required(o, Enum::VT_UNDERLYING_TYPE); + return o; + } +}; + +inline flatbuffers::Offset CreateEnum( + flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset name = 0, + flatbuffers::Offset>> values = 0, + bool is_union = false, + flatbuffers::Offset underlying_type = 0, + flatbuffers::Offset>> attributes = 0, + flatbuffers::Offset>> documentation = 0, + flatbuffers::Offset declaration_file = 0) { + EnumBuilder builder_(_fbb); + builder_.add_declaration_file(declaration_file); + builder_.add_documentation(documentation); + builder_.add_attributes(attributes); + builder_.add_underlying_type(underlying_type); + builder_.add_values(values); + builder_.add_name(name); + builder_.add_is_union(is_union); + return builder_.Finish(); +} + +inline flatbuffers::Offset CreateEnumDirect( + flatbuffers::FlatBufferBuilder &_fbb, + const char *name = nullptr, + std::vector> *values = nullptr, + bool is_union = false, + flatbuffers::Offset underlying_type = 0, + std::vector> *attributes = nullptr, + const std::vector> *documentation = nullptr, + const char *declaration_file = nullptr) { + auto name__ = name ? _fbb.CreateString(name) : 0; + auto values__ = values ? _fbb.CreateVectorOfSortedTables(values) : 0; + auto attributes__ = attributes ? _fbb.CreateVectorOfSortedTables(attributes) : 0; + auto documentation__ = documentation ? _fbb.CreateVector>(*documentation) : 0; + auto declaration_file__ = declaration_file ? _fbb.CreateString(declaration_file) : 0; + return reflection::CreateEnum( + _fbb, + name__, + values__, + is_union, + underlying_type, + attributes__, + documentation__, + declaration_file__); +} + +struct Field FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef FieldBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_NAME = 4, + VT_TYPE = 6, + VT_ID = 8, + VT_OFFSET = 10, + VT_DEFAULT_INTEGER = 12, + VT_DEFAULT_REAL = 14, + VT_DEPRECATED = 16, + VT_REQUIRED = 18, + VT_KEY = 20, + VT_ATTRIBUTES = 22, + VT_DOCUMENTATION = 24, + VT_OPTIONAL = 26, + VT_PADDING = 28 + }; + const flatbuffers::String *name() const { + return GetPointer(VT_NAME); + } + bool KeyCompareLessThan(const Field *o) const { + return *name() < *o->name(); + } + int KeyCompareWithValue(const char *_name) const { + return strcmp(name()->c_str(), _name); + } + const reflection::Type *type() const { + return GetPointer(VT_TYPE); + } + uint16_t id() const { + return GetField(VT_ID, 0); + } + uint16_t offset() const { + return GetField(VT_OFFSET, 0); + } + int64_t default_integer() const { + return GetField(VT_DEFAULT_INTEGER, 0); + } + double default_real() const { + return GetField(VT_DEFAULT_REAL, 0.0); + } + bool deprecated() const { + return GetField(VT_DEPRECATED, 0) != 0; + } + bool required() const { + return GetField(VT_REQUIRED, 0) != 0; + } + bool key() const { + return GetField(VT_KEY, 0) != 0; + } + const flatbuffers::Vector> *attributes() const { + return GetPointer> *>(VT_ATTRIBUTES); + } + const flatbuffers::Vector> *documentation() const { + return GetPointer> *>(VT_DOCUMENTATION); + } + bool optional() const { + return GetField(VT_OPTIONAL, 0) != 0; + } + /// Number of padding octets to always add after this field. Structs only. + uint16_t padding() const { + return GetField(VT_PADDING, 0); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffsetRequired(verifier, VT_NAME) && + verifier.VerifyString(name()) && + VerifyOffsetRequired(verifier, VT_TYPE) && + verifier.VerifyTable(type()) && + VerifyField(verifier, VT_ID, 2) && + VerifyField(verifier, VT_OFFSET, 2) && + VerifyField(verifier, VT_DEFAULT_INTEGER, 8) && + VerifyField(verifier, VT_DEFAULT_REAL, 8) && + VerifyField(verifier, VT_DEPRECATED, 1) && + VerifyField(verifier, VT_REQUIRED, 1) && + VerifyField(verifier, VT_KEY, 1) && + VerifyOffset(verifier, VT_ATTRIBUTES) && + verifier.VerifyVector(attributes()) && + verifier.VerifyVectorOfTables(attributes()) && + VerifyOffset(verifier, VT_DOCUMENTATION) && + verifier.VerifyVector(documentation()) && + verifier.VerifyVectorOfStrings(documentation()) && + VerifyField(verifier, VT_OPTIONAL, 1) && + VerifyField(verifier, VT_PADDING, 2) && + verifier.EndTable(); + } +}; + +struct FieldBuilder { + typedef Field Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_name(flatbuffers::Offset name) { + fbb_.AddOffset(Field::VT_NAME, name); + } + void add_type(flatbuffers::Offset type) { + fbb_.AddOffset(Field::VT_TYPE, type); + } + void add_id(uint16_t id) { + fbb_.AddElement(Field::VT_ID, id, 0); + } + void add_offset(uint16_t offset) { + fbb_.AddElement(Field::VT_OFFSET, offset, 0); + } + void add_default_integer(int64_t default_integer) { + fbb_.AddElement(Field::VT_DEFAULT_INTEGER, default_integer, 0); + } + void add_default_real(double default_real) { + fbb_.AddElement(Field::VT_DEFAULT_REAL, default_real, 0.0); + } + void add_deprecated(bool deprecated) { + fbb_.AddElement(Field::VT_DEPRECATED, static_cast(deprecated), 0); + } + void add_required(bool required) { + fbb_.AddElement(Field::VT_REQUIRED, static_cast(required), 0); + } + void add_key(bool key) { + fbb_.AddElement(Field::VT_KEY, static_cast(key), 0); + } + void add_attributes(flatbuffers::Offset>> attributes) { + fbb_.AddOffset(Field::VT_ATTRIBUTES, attributes); + } + void add_documentation(flatbuffers::Offset>> documentation) { + fbb_.AddOffset(Field::VT_DOCUMENTATION, documentation); + } + void add_optional(bool optional) { + fbb_.AddElement(Field::VT_OPTIONAL, static_cast(optional), 0); + } + void add_padding(uint16_t padding) { + fbb_.AddElement(Field::VT_PADDING, padding, 0); + } + explicit FieldBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + fbb_.Required(o, Field::VT_NAME); + fbb_.Required(o, Field::VT_TYPE); + return o; + } +}; + +inline flatbuffers::Offset CreateField( + flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset name = 0, + flatbuffers::Offset type = 0, + uint16_t id = 0, + uint16_t offset = 0, + int64_t default_integer = 0, + double default_real = 0.0, + bool deprecated = false, + bool required = false, + bool key = false, + flatbuffers::Offset>> attributes = 0, + flatbuffers::Offset>> documentation = 0, + bool optional = false, + uint16_t padding = 0) { + FieldBuilder builder_(_fbb); + builder_.add_default_real(default_real); + builder_.add_default_integer(default_integer); + builder_.add_documentation(documentation); + builder_.add_attributes(attributes); + builder_.add_type(type); + builder_.add_name(name); + builder_.add_padding(padding); + builder_.add_offset(offset); + builder_.add_id(id); + builder_.add_optional(optional); + builder_.add_key(key); + builder_.add_required(required); + builder_.add_deprecated(deprecated); + return builder_.Finish(); +} + +inline flatbuffers::Offset CreateFieldDirect( + flatbuffers::FlatBufferBuilder &_fbb, + const char *name = nullptr, + flatbuffers::Offset type = 0, + uint16_t id = 0, + uint16_t offset = 0, + int64_t default_integer = 0, + double default_real = 0.0, + bool deprecated = false, + bool required = false, + bool key = false, + std::vector> *attributes = nullptr, + const std::vector> *documentation = nullptr, + bool optional = false, + uint16_t padding = 0) { + auto name__ = name ? _fbb.CreateString(name) : 0; + auto attributes__ = attributes ? _fbb.CreateVectorOfSortedTables(attributes) : 0; + auto documentation__ = documentation ? _fbb.CreateVector>(*documentation) : 0; + return reflection::CreateField( + _fbb, + name__, + type, + id, + offset, + default_integer, + default_real, + deprecated, + required, + key, + attributes__, + documentation__, + optional, + padding); +} + +struct Object FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef ObjectBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_NAME = 4, + VT_FIELDS = 6, + VT_IS_STRUCT = 8, + VT_MINALIGN = 10, + VT_BYTESIZE = 12, + VT_ATTRIBUTES = 14, + VT_DOCUMENTATION = 16, + VT_DECLARATION_FILE = 18 + }; + const flatbuffers::String *name() const { + return GetPointer(VT_NAME); + } + bool KeyCompareLessThan(const Object *o) const { + return *name() < *o->name(); + } + int KeyCompareWithValue(const char *_name) const { + return strcmp(name()->c_str(), _name); + } + const flatbuffers::Vector> *fields() const { + return GetPointer> *>(VT_FIELDS); + } + bool is_struct() const { + return GetField(VT_IS_STRUCT, 0) != 0; + } + int32_t minalign() const { + return GetField(VT_MINALIGN, 0); + } + int32_t bytesize() const { + return GetField(VT_BYTESIZE, 0); + } + const flatbuffers::Vector> *attributes() const { + return GetPointer> *>(VT_ATTRIBUTES); + } + const flatbuffers::Vector> *documentation() const { + return GetPointer> *>(VT_DOCUMENTATION); + } + /// File that this Object is declared in. + const flatbuffers::String *declaration_file() const { + return GetPointer(VT_DECLARATION_FILE); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffsetRequired(verifier, VT_NAME) && + verifier.VerifyString(name()) && + VerifyOffsetRequired(verifier, VT_FIELDS) && + verifier.VerifyVector(fields()) && + verifier.VerifyVectorOfTables(fields()) && + VerifyField(verifier, VT_IS_STRUCT, 1) && + VerifyField(verifier, VT_MINALIGN, 4) && + VerifyField(verifier, VT_BYTESIZE, 4) && + VerifyOffset(verifier, VT_ATTRIBUTES) && + verifier.VerifyVector(attributes()) && + verifier.VerifyVectorOfTables(attributes()) && + VerifyOffset(verifier, VT_DOCUMENTATION) && + verifier.VerifyVector(documentation()) && + verifier.VerifyVectorOfStrings(documentation()) && + VerifyOffset(verifier, VT_DECLARATION_FILE) && + verifier.VerifyString(declaration_file()) && + verifier.EndTable(); + } +}; + +struct ObjectBuilder { + typedef Object Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_name(flatbuffers::Offset name) { + fbb_.AddOffset(Object::VT_NAME, name); + } + void add_fields(flatbuffers::Offset>> fields) { + fbb_.AddOffset(Object::VT_FIELDS, fields); + } + void add_is_struct(bool is_struct) { + fbb_.AddElement(Object::VT_IS_STRUCT, static_cast(is_struct), 0); + } + void add_minalign(int32_t minalign) { + fbb_.AddElement(Object::VT_MINALIGN, minalign, 0); + } + void add_bytesize(int32_t bytesize) { + fbb_.AddElement(Object::VT_BYTESIZE, bytesize, 0); + } + void add_attributes(flatbuffers::Offset>> attributes) { + fbb_.AddOffset(Object::VT_ATTRIBUTES, attributes); + } + void add_documentation(flatbuffers::Offset>> documentation) { + fbb_.AddOffset(Object::VT_DOCUMENTATION, documentation); + } + void add_declaration_file(flatbuffers::Offset declaration_file) { + fbb_.AddOffset(Object::VT_DECLARATION_FILE, declaration_file); + } + explicit ObjectBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + fbb_.Required(o, Object::VT_NAME); + fbb_.Required(o, Object::VT_FIELDS); + return o; + } +}; + +inline flatbuffers::Offset CreateObject( + flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset name = 0, + flatbuffers::Offset>> fields = 0, + bool is_struct = false, + int32_t minalign = 0, + int32_t bytesize = 0, + flatbuffers::Offset>> attributes = 0, + flatbuffers::Offset>> documentation = 0, + flatbuffers::Offset declaration_file = 0) { + ObjectBuilder builder_(_fbb); + builder_.add_declaration_file(declaration_file); + builder_.add_documentation(documentation); + builder_.add_attributes(attributes); + builder_.add_bytesize(bytesize); + builder_.add_minalign(minalign); + builder_.add_fields(fields); + builder_.add_name(name); + builder_.add_is_struct(is_struct); + return builder_.Finish(); +} + +inline flatbuffers::Offset CreateObjectDirect( + flatbuffers::FlatBufferBuilder &_fbb, + const char *name = nullptr, + std::vector> *fields = nullptr, + bool is_struct = false, + int32_t minalign = 0, + int32_t bytesize = 0, + std::vector> *attributes = nullptr, + const std::vector> *documentation = nullptr, + const char *declaration_file = nullptr) { + auto name__ = name ? _fbb.CreateString(name) : 0; + auto fields__ = fields ? _fbb.CreateVectorOfSortedTables(fields) : 0; + auto attributes__ = attributes ? _fbb.CreateVectorOfSortedTables(attributes) : 0; + auto documentation__ = documentation ? _fbb.CreateVector>(*documentation) : 0; + auto declaration_file__ = declaration_file ? _fbb.CreateString(declaration_file) : 0; + return reflection::CreateObject( + _fbb, + name__, + fields__, + is_struct, + minalign, + bytesize, + attributes__, + documentation__, + declaration_file__); +} + +struct RPCCall FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef RPCCallBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_NAME = 4, + VT_REQUEST = 6, + VT_RESPONSE = 8, + VT_ATTRIBUTES = 10, + VT_DOCUMENTATION = 12 + }; + const flatbuffers::String *name() const { + return GetPointer(VT_NAME); + } + bool KeyCompareLessThan(const RPCCall *o) const { + return *name() < *o->name(); + } + int KeyCompareWithValue(const char *_name) const { + return strcmp(name()->c_str(), _name); + } + const reflection::Object *request() const { + return GetPointer(VT_REQUEST); + } + const reflection::Object *response() const { + return GetPointer(VT_RESPONSE); + } + const flatbuffers::Vector> *attributes() const { + return GetPointer> *>(VT_ATTRIBUTES); + } + const flatbuffers::Vector> *documentation() const { + return GetPointer> *>(VT_DOCUMENTATION); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffsetRequired(verifier, VT_NAME) && + verifier.VerifyString(name()) && + VerifyOffsetRequired(verifier, VT_REQUEST) && + verifier.VerifyTable(request()) && + VerifyOffsetRequired(verifier, VT_RESPONSE) && + verifier.VerifyTable(response()) && + VerifyOffset(verifier, VT_ATTRIBUTES) && + verifier.VerifyVector(attributes()) && + verifier.VerifyVectorOfTables(attributes()) && + VerifyOffset(verifier, VT_DOCUMENTATION) && + verifier.VerifyVector(documentation()) && + verifier.VerifyVectorOfStrings(documentation()) && + verifier.EndTable(); + } +}; + +struct RPCCallBuilder { + typedef RPCCall Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_name(flatbuffers::Offset name) { + fbb_.AddOffset(RPCCall::VT_NAME, name); + } + void add_request(flatbuffers::Offset request) { + fbb_.AddOffset(RPCCall::VT_REQUEST, request); + } + void add_response(flatbuffers::Offset response) { + fbb_.AddOffset(RPCCall::VT_RESPONSE, response); + } + void add_attributes(flatbuffers::Offset>> attributes) { + fbb_.AddOffset(RPCCall::VT_ATTRIBUTES, attributes); + } + void add_documentation(flatbuffers::Offset>> documentation) { + fbb_.AddOffset(RPCCall::VT_DOCUMENTATION, documentation); + } + explicit RPCCallBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + fbb_.Required(o, RPCCall::VT_NAME); + fbb_.Required(o, RPCCall::VT_REQUEST); + fbb_.Required(o, RPCCall::VT_RESPONSE); + return o; + } +}; + +inline flatbuffers::Offset CreateRPCCall( + flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset name = 0, + flatbuffers::Offset request = 0, + flatbuffers::Offset response = 0, + flatbuffers::Offset>> attributes = 0, + flatbuffers::Offset>> documentation = 0) { + RPCCallBuilder builder_(_fbb); + builder_.add_documentation(documentation); + builder_.add_attributes(attributes); + builder_.add_response(response); + builder_.add_request(request); + builder_.add_name(name); + return builder_.Finish(); +} + +inline flatbuffers::Offset CreateRPCCallDirect( + flatbuffers::FlatBufferBuilder &_fbb, + const char *name = nullptr, + flatbuffers::Offset request = 0, + flatbuffers::Offset response = 0, + std::vector> *attributes = nullptr, + const std::vector> *documentation = nullptr) { + auto name__ = name ? _fbb.CreateString(name) : 0; + auto attributes__ = attributes ? _fbb.CreateVectorOfSortedTables(attributes) : 0; + auto documentation__ = documentation ? _fbb.CreateVector>(*documentation) : 0; + return reflection::CreateRPCCall( + _fbb, + name__, + request, + response, + attributes__, + documentation__); +} + +struct Service FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef ServiceBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_NAME = 4, + VT_CALLS = 6, + VT_ATTRIBUTES = 8, + VT_DOCUMENTATION = 10, + VT_DECLARATION_FILE = 12 + }; + const flatbuffers::String *name() const { + return GetPointer(VT_NAME); + } + bool KeyCompareLessThan(const Service *o) const { + return *name() < *o->name(); + } + int KeyCompareWithValue(const char *_name) const { + return strcmp(name()->c_str(), _name); + } + const flatbuffers::Vector> *calls() const { + return GetPointer> *>(VT_CALLS); + } + const flatbuffers::Vector> *attributes() const { + return GetPointer> *>(VT_ATTRIBUTES); + } + const flatbuffers::Vector> *documentation() const { + return GetPointer> *>(VT_DOCUMENTATION); + } + /// File that this Service is declared in. + const flatbuffers::String *declaration_file() const { + return GetPointer(VT_DECLARATION_FILE); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffsetRequired(verifier, VT_NAME) && + verifier.VerifyString(name()) && + VerifyOffset(verifier, VT_CALLS) && + verifier.VerifyVector(calls()) && + verifier.VerifyVectorOfTables(calls()) && + VerifyOffset(verifier, VT_ATTRIBUTES) && + verifier.VerifyVector(attributes()) && + verifier.VerifyVectorOfTables(attributes()) && + VerifyOffset(verifier, VT_DOCUMENTATION) && + verifier.VerifyVector(documentation()) && + verifier.VerifyVectorOfStrings(documentation()) && + VerifyOffset(verifier, VT_DECLARATION_FILE) && + verifier.VerifyString(declaration_file()) && + verifier.EndTable(); + } +}; + +struct ServiceBuilder { + typedef Service Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_name(flatbuffers::Offset name) { + fbb_.AddOffset(Service::VT_NAME, name); + } + void add_calls(flatbuffers::Offset>> calls) { + fbb_.AddOffset(Service::VT_CALLS, calls); + } + void add_attributes(flatbuffers::Offset>> attributes) { + fbb_.AddOffset(Service::VT_ATTRIBUTES, attributes); + } + void add_documentation(flatbuffers::Offset>> documentation) { + fbb_.AddOffset(Service::VT_DOCUMENTATION, documentation); + } + void add_declaration_file(flatbuffers::Offset declaration_file) { + fbb_.AddOffset(Service::VT_DECLARATION_FILE, declaration_file); + } + explicit ServiceBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + fbb_.Required(o, Service::VT_NAME); + return o; + } +}; + +inline flatbuffers::Offset CreateService( + flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset name = 0, + flatbuffers::Offset>> calls = 0, + flatbuffers::Offset>> attributes = 0, + flatbuffers::Offset>> documentation = 0, + flatbuffers::Offset declaration_file = 0) { + ServiceBuilder builder_(_fbb); + builder_.add_declaration_file(declaration_file); + builder_.add_documentation(documentation); + builder_.add_attributes(attributes); + builder_.add_calls(calls); + builder_.add_name(name); + return builder_.Finish(); +} + +inline flatbuffers::Offset CreateServiceDirect( + flatbuffers::FlatBufferBuilder &_fbb, + const char *name = nullptr, + std::vector> *calls = nullptr, + std::vector> *attributes = nullptr, + const std::vector> *documentation = nullptr, + const char *declaration_file = nullptr) { + auto name__ = name ? _fbb.CreateString(name) : 0; + auto calls__ = calls ? _fbb.CreateVectorOfSortedTables(calls) : 0; + auto attributes__ = attributes ? _fbb.CreateVectorOfSortedTables(attributes) : 0; + auto documentation__ = documentation ? _fbb.CreateVector>(*documentation) : 0; + auto declaration_file__ = declaration_file ? _fbb.CreateString(declaration_file) : 0; + return reflection::CreateService( + _fbb, + name__, + calls__, + attributes__, + documentation__, + declaration_file__); +} + +/// File specific information. +/// Symbols declared within a file may be recovered by iterating over all +/// symbols and examining the `declaration_file` field. +struct SchemaFile FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef SchemaFileBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_FILENAME = 4, + VT_INCLUDED_FILENAMES = 6 + }; + /// Filename, relative to project root. + const flatbuffers::String *filename() const { + return GetPointer(VT_FILENAME); + } + bool KeyCompareLessThan(const SchemaFile *o) const { + return *filename() < *o->filename(); + } + int KeyCompareWithValue(const char *_filename) const { + return strcmp(filename()->c_str(), _filename); + } + /// Names of included files, relative to project root. + const flatbuffers::Vector> *included_filenames() const { + return GetPointer> *>(VT_INCLUDED_FILENAMES); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffsetRequired(verifier, VT_FILENAME) && + verifier.VerifyString(filename()) && + VerifyOffset(verifier, VT_INCLUDED_FILENAMES) && + verifier.VerifyVector(included_filenames()) && + verifier.VerifyVectorOfStrings(included_filenames()) && + verifier.EndTable(); + } +}; + +struct SchemaFileBuilder { + typedef SchemaFile Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_filename(flatbuffers::Offset filename) { + fbb_.AddOffset(SchemaFile::VT_FILENAME, filename); + } + void add_included_filenames(flatbuffers::Offset>> included_filenames) { + fbb_.AddOffset(SchemaFile::VT_INCLUDED_FILENAMES, included_filenames); + } + explicit SchemaFileBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + fbb_.Required(o, SchemaFile::VT_FILENAME); + return o; + } +}; + +inline flatbuffers::Offset CreateSchemaFile( + flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset filename = 0, + flatbuffers::Offset>> included_filenames = 0) { + SchemaFileBuilder builder_(_fbb); + builder_.add_included_filenames(included_filenames); + builder_.add_filename(filename); + return builder_.Finish(); +} + +inline flatbuffers::Offset CreateSchemaFileDirect( + flatbuffers::FlatBufferBuilder &_fbb, + const char *filename = nullptr, + const std::vector> *included_filenames = nullptr) { + auto filename__ = filename ? _fbb.CreateString(filename) : 0; + auto included_filenames__ = included_filenames ? _fbb.CreateVector>(*included_filenames) : 0; + return reflection::CreateSchemaFile( + _fbb, + filename__, + included_filenames__); +} + +struct Schema FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef SchemaBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_OBJECTS = 4, + VT_ENUMS = 6, + VT_FILE_IDENT = 8, + VT_FILE_EXT = 10, + VT_ROOT_TABLE = 12, + VT_SERVICES = 14, + VT_ADVANCED_FEATURES = 16, + VT_FBS_FILES = 18 + }; + const flatbuffers::Vector> *objects() const { + return GetPointer> *>(VT_OBJECTS); + } + const flatbuffers::Vector> *enums() const { + return GetPointer> *>(VT_ENUMS); + } + const flatbuffers::String *file_ident() const { + return GetPointer(VT_FILE_IDENT); + } + const flatbuffers::String *file_ext() const { + return GetPointer(VT_FILE_EXT); + } + const reflection::Object *root_table() const { + return GetPointer(VT_ROOT_TABLE); + } + const flatbuffers::Vector> *services() const { + return GetPointer> *>(VT_SERVICES); + } + reflection::AdvancedFeatures advanced_features() const { + return static_cast(GetField(VT_ADVANCED_FEATURES, 0)); + } + /// All the files used in this compilation. Files are relative to where + /// flatc was invoked. + const flatbuffers::Vector> *fbs_files() const { + return GetPointer> *>(VT_FBS_FILES); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffsetRequired(verifier, VT_OBJECTS) && + verifier.VerifyVector(objects()) && + verifier.VerifyVectorOfTables(objects()) && + VerifyOffsetRequired(verifier, VT_ENUMS) && + verifier.VerifyVector(enums()) && + verifier.VerifyVectorOfTables(enums()) && + VerifyOffset(verifier, VT_FILE_IDENT) && + verifier.VerifyString(file_ident()) && + VerifyOffset(verifier, VT_FILE_EXT) && + verifier.VerifyString(file_ext()) && + VerifyOffset(verifier, VT_ROOT_TABLE) && + verifier.VerifyTable(root_table()) && + VerifyOffset(verifier, VT_SERVICES) && + verifier.VerifyVector(services()) && + verifier.VerifyVectorOfTables(services()) && + VerifyField(verifier, VT_ADVANCED_FEATURES, 8) && + VerifyOffset(verifier, VT_FBS_FILES) && + verifier.VerifyVector(fbs_files()) && + verifier.VerifyVectorOfTables(fbs_files()) && + verifier.EndTable(); + } +}; + +struct SchemaBuilder { + typedef Schema Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_objects(flatbuffers::Offset>> objects) { + fbb_.AddOffset(Schema::VT_OBJECTS, objects); + } + void add_enums(flatbuffers::Offset>> enums) { + fbb_.AddOffset(Schema::VT_ENUMS, enums); + } + void add_file_ident(flatbuffers::Offset file_ident) { + fbb_.AddOffset(Schema::VT_FILE_IDENT, file_ident); + } + void add_file_ext(flatbuffers::Offset file_ext) { + fbb_.AddOffset(Schema::VT_FILE_EXT, file_ext); + } + void add_root_table(flatbuffers::Offset root_table) { + fbb_.AddOffset(Schema::VT_ROOT_TABLE, root_table); + } + void add_services(flatbuffers::Offset>> services) { + fbb_.AddOffset(Schema::VT_SERVICES, services); + } + void add_advanced_features(reflection::AdvancedFeatures advanced_features) { + fbb_.AddElement(Schema::VT_ADVANCED_FEATURES, static_cast(advanced_features), 0); + } + void add_fbs_files(flatbuffers::Offset>> fbs_files) { + fbb_.AddOffset(Schema::VT_FBS_FILES, fbs_files); + } + explicit SchemaBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + fbb_.Required(o, Schema::VT_OBJECTS); + fbb_.Required(o, Schema::VT_ENUMS); + return o; + } +}; + +inline flatbuffers::Offset CreateSchema( + flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset>> objects = 0, + flatbuffers::Offset>> enums = 0, + flatbuffers::Offset file_ident = 0, + flatbuffers::Offset file_ext = 0, + flatbuffers::Offset root_table = 0, + flatbuffers::Offset>> services = 0, + reflection::AdvancedFeatures advanced_features = static_cast(0), + flatbuffers::Offset>> fbs_files = 0) { + SchemaBuilder builder_(_fbb); + builder_.add_advanced_features(advanced_features); + builder_.add_fbs_files(fbs_files); + builder_.add_services(services); + builder_.add_root_table(root_table); + builder_.add_file_ext(file_ext); + builder_.add_file_ident(file_ident); + builder_.add_enums(enums); + builder_.add_objects(objects); + return builder_.Finish(); +} + +inline flatbuffers::Offset CreateSchemaDirect( + flatbuffers::FlatBufferBuilder &_fbb, + std::vector> *objects = nullptr, + std::vector> *enums = nullptr, + const char *file_ident = nullptr, + const char *file_ext = nullptr, + flatbuffers::Offset root_table = 0, + std::vector> *services = nullptr, + reflection::AdvancedFeatures advanced_features = static_cast(0), + std::vector> *fbs_files = nullptr) { + auto objects__ = objects ? _fbb.CreateVectorOfSortedTables(objects) : 0; + auto enums__ = enums ? _fbb.CreateVectorOfSortedTables(enums) : 0; + auto file_ident__ = file_ident ? _fbb.CreateString(file_ident) : 0; + auto file_ext__ = file_ext ? _fbb.CreateString(file_ext) : 0; + auto services__ = services ? _fbb.CreateVectorOfSortedTables(services) : 0; + auto fbs_files__ = fbs_files ? _fbb.CreateVectorOfSortedTables(fbs_files) : 0; + return reflection::CreateSchema( + _fbb, + objects__, + enums__, + file_ident__, + file_ext__, + root_table, + services__, + advanced_features, + fbs_files__); +} + +inline const reflection::Schema *GetSchema(const void *buf) { + return flatbuffers::GetRoot(buf); +} + +inline const reflection::Schema *GetSizePrefixedSchema(const void *buf) { + return flatbuffers::GetSizePrefixedRoot(buf); +} + +inline const char *SchemaIdentifier() { + return "BFBS"; +} + +inline bool SchemaBufferHasIdentifier(const void *buf) { + return flatbuffers::BufferHasIdentifier( + buf, SchemaIdentifier()); +} + +inline bool SizePrefixedSchemaBufferHasIdentifier(const void *buf) { + return flatbuffers::BufferHasIdentifier( + buf, SchemaIdentifier(), true); +} + +inline bool VerifySchemaBuffer( + flatbuffers::Verifier &verifier) { + return verifier.VerifyBuffer(SchemaIdentifier()); +} + +inline bool VerifySizePrefixedSchemaBuffer( + flatbuffers::Verifier &verifier) { + return verifier.VerifySizePrefixedBuffer(SchemaIdentifier()); +} + +inline const char *SchemaExtension() { + return "bfbs"; +} + +inline void FinishSchemaBuffer( + flatbuffers::FlatBufferBuilder &fbb, + flatbuffers::Offset root) { + fbb.Finish(root, SchemaIdentifier()); +} + +inline void FinishSizePrefixedSchemaBuffer( + flatbuffers::FlatBufferBuilder &fbb, + flatbuffers::Offset root) { + fbb.FinishSizePrefixed(root, SchemaIdentifier()); +} + +} // namespace reflection + +#endif // FLATBUFFERS_GENERATED_REFLECTION_REFLECTION_H_ diff --git a/src/flatgeobuf/include/flatbuffers/registry.h b/src/flatgeobuf/include/flatbuffers/registry.h new file mode 100644 index 0000000000..b3cc3b78ce --- /dev/null +++ b/src/flatgeobuf/include/flatbuffers/registry.h @@ -0,0 +1,130 @@ +/* + * Copyright 2017 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLATBUFFERS_REGISTRY_H_ +#define FLATBUFFERS_REGISTRY_H_ + +#include "flatbuffers/base.h" +#include "flatbuffers/idl.h" + +namespace mapserver { +namespace flatbuffers { + +// Convenience class to easily parse or generate text for arbitrary FlatBuffers. +// Simply pre-populate it with all schema filenames that may be in use, and +// This class will look them up using the file_identifier declared in the +// schema. +class Registry { + public: + // Call this for all schemas that may be in use. The identifier has + // a function in the generated code, e.g. MonsterIdentifier(). + void Register(const char *file_identifier, const char *schema_path) { + Schema schema; + schema.path_ = schema_path; + schemas_[file_identifier] = schema; + } + + // Generate text from an arbitrary FlatBuffer by looking up its + // file_identifier in the registry. + bool FlatBufferToText(const uint8_t *flatbuf, size_t len, std::string *dest) { + // Get the identifier out of the buffer. + // If the buffer is truncated, exit. + if (len < sizeof(uoffset_t) + kFileIdentifierLength) { + lasterror_ = "buffer truncated"; + return false; + } + std::string ident( + reinterpret_cast(flatbuf) + sizeof(uoffset_t), + kFileIdentifierLength); + // Load and parse the schema. + Parser parser; + if (!LoadSchema(ident, &parser)) return false; + // Now we're ready to generate text. + if (!GenerateText(parser, flatbuf, dest)) { + lasterror_ = "unable to generate text for FlatBuffer binary"; + return false; + } + return true; + } + + // Converts a binary buffer to text using one of the schemas in the registry, + // use the file_identifier to indicate which. + // If DetachedBuffer::data() is null then parsing failed. + DetachedBuffer TextToFlatBuffer(const char *text, + const char *file_identifier) { + // Load and parse the schema. + Parser parser; + if (!LoadSchema(file_identifier, &parser)) return DetachedBuffer(); + // Parse the text. + if (!parser.Parse(text)) { + lasterror_ = parser.error_; + return DetachedBuffer(); + } + // We have a valid FlatBuffer. Detach it from the builder and return. + return parser.builder_.Release(); + } + + // Modify any parsing / output options used by the other functions. + void SetOptions(const IDLOptions &opts) { opts_ = opts; } + + // If schemas used contain include statements, call this function for every + // directory the parser should search them for. + void AddIncludeDirectory(const char *path) { include_paths_.push_back(path); } + + // Returns a human readable error if any of the above functions fail. + const std::string &GetLastError() { return lasterror_; } + + private: + bool LoadSchema(const std::string &ident, Parser *parser) { + // Find the schema, if not, exit. + auto it = schemas_.find(ident); + if (it == schemas_.end()) { + // Don't attach the identifier, since it may not be human readable. + lasterror_ = "identifier for this buffer not in the registry"; + return false; + } + auto &schema = it->second; + // Load the schema from disk. If not, exit. + std::string schematext; + if (!LoadFile(schema.path_.c_str(), false, &schematext)) { + lasterror_ = "could not load schema: " + schema.path_; + return false; + } + // Parse schema. + parser->opts = opts_; + if (!parser->Parse(schematext.c_str(), include_paths_.data(), + schema.path_.c_str())) { + lasterror_ = parser->error_; + return false; + } + return true; + } + + struct Schema { + std::string path_; + // TODO(wvo) optionally cache schema file or parsed schema here. + }; + + std::string lasterror_; + IDLOptions opts_; + std::vector include_paths_; + std::map schemas_; +}; + +} // namespace flatbuffers +} // namespace mapserver + +#endif // FLATBUFFERS_REGISTRY_H_ diff --git a/src/flatgeobuf/include/flatbuffers/stl_emulation.h b/src/flatgeobuf/include/flatbuffers/stl_emulation.h new file mode 100644 index 0000000000..b93a6fccfd --- /dev/null +++ b/src/flatgeobuf/include/flatbuffers/stl_emulation.h @@ -0,0 +1,515 @@ +/* + * Copyright 2017 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLATBUFFERS_STL_EMULATION_H_ +#define FLATBUFFERS_STL_EMULATION_H_ + +// clang-format off +#include "flatbuffers/base.h" + +#include +#include +#include +#include +#include + +#ifndef FLATBUFFERS_USE_STD_OPTIONAL + // Detect C++17 compatible compiler. + // __cplusplus >= 201703L - a compiler has support of 'static inline' variables. + #if (defined(__cplusplus) && __cplusplus >= 201703L) \ + || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) + #define FLATBUFFERS_USE_STD_OPTIONAL 1 + #else + #define FLATBUFFERS_USE_STD_OPTIONAL 0 + #endif // (defined(__cplusplus) && __cplusplus >= 201703L) ... +#endif // FLATBUFFERS_USE_STD_OPTIONAL + +#if FLATBUFFERS_USE_STD_OPTIONAL + #include +#endif + +// The __cpp_lib_span is the predefined feature macro. +#if defined(FLATBUFFERS_USE_STD_SPAN) + #include +#elif defined(__cpp_lib_span) && defined(__has_include) + #if __has_include() + #include + #define FLATBUFFERS_USE_STD_SPAN + #endif +#else + // Disable non-trivial ctors if FLATBUFFERS_SPAN_MINIMAL defined. + #if !defined(FLATBUFFERS_TEMPLATES_ALIASES) + #define FLATBUFFERS_SPAN_MINIMAL + #else + // Enable implicit construction of a span from a std::array. + #include + #endif +#endif // defined(FLATBUFFERS_USE_STD_SPAN) + +// This header provides backwards compatibility for older versions of the STL. +namespace mapserver { +namespace flatbuffers { + +#if defined(FLATBUFFERS_TEMPLATES_ALIASES) + template + using numeric_limits = std::numeric_limits; +#else + template class numeric_limits : + public std::numeric_limits {}; +#endif // defined(FLATBUFFERS_TEMPLATES_ALIASES) + +#if defined(FLATBUFFERS_TEMPLATES_ALIASES) + template using is_scalar = std::is_scalar; + template using is_same = std::is_same; + template using is_floating_point = std::is_floating_point; + template using is_unsigned = std::is_unsigned; + template using is_enum = std::is_enum; + template using make_unsigned = std::make_unsigned; + template + using conditional = std::conditional; + template + using integral_constant = std::integral_constant; + template + using bool_constant = integral_constant; + using true_type = std::true_type; + using false_type = std::false_type; +#else + // MSVC 2010 doesn't support C++11 aliases. + template struct is_scalar : public std::is_scalar {}; + template struct is_same : public std::is_same {}; + template struct is_floating_point : + public std::is_floating_point {}; + template struct is_unsigned : public std::is_unsigned {}; + template struct is_enum : public std::is_enum {}; + template struct make_unsigned : public std::make_unsigned {}; + template + struct conditional : public std::conditional {}; + template + struct integral_constant : public std::integral_constant {}; + template + struct bool_constant : public integral_constant {}; + typedef bool_constant true_type; + typedef bool_constant false_type; +#endif // defined(FLATBUFFERS_TEMPLATES_ALIASES) + +#if defined(FLATBUFFERS_TEMPLATES_ALIASES) + template using unique_ptr = std::unique_ptr; +#else + // MSVC 2010 doesn't support C++11 aliases. + // We're manually "aliasing" the class here as we want to bring unique_ptr + // into the flatbuffers namespace. We have unique_ptr in the flatbuffers + // namespace we have a completely independent implementation (see below) + // for C++98 STL implementations. + template class unique_ptr : public std::unique_ptr { + public: + unique_ptr() {} + explicit unique_ptr(T* p) : std::unique_ptr(p) {} + unique_ptr(std::unique_ptr&& u) { *this = std::move(u); } + unique_ptr(unique_ptr&& u) { *this = std::move(u); } + unique_ptr& operator=(std::unique_ptr&& u) { + std::unique_ptr::reset(u.release()); + return *this; + } + unique_ptr& operator=(unique_ptr&& u) { + std::unique_ptr::reset(u.release()); + return *this; + } + unique_ptr& operator=(T* p) { + return std::unique_ptr::operator=(p); + } + }; +#endif // defined(FLATBUFFERS_TEMPLATES_ALIASES) + +#if FLATBUFFERS_USE_STD_OPTIONAL +template +using Optional = std::optional; +using nullopt_t = std::nullopt_t; +inline constexpr nullopt_t nullopt = std::nullopt; + +#else +// Limited implementation of Optional type for a scalar T. +// This implementation limited by trivial types compatible with +// std::is_arithmetic or std::is_enum type traits. + +// A tag to indicate an empty flatbuffers::optional. +struct nullopt_t { + explicit FLATBUFFERS_CONSTEXPR_CPP11 nullopt_t(int) {} +}; + +#if defined(FLATBUFFERS_CONSTEXPR_DEFINED) + namespace internal { + template struct nullopt_holder { + static constexpr nullopt_t instance_ = nullopt_t(0); + }; + template + constexpr nullopt_t nullopt_holder::instance_; + } + static constexpr const nullopt_t &nullopt = internal::nullopt_holder::instance_; + +#else + namespace internal { + template struct nullopt_holder { + static const nullopt_t instance_; + }; + template + const nullopt_t nullopt_holder::instance_ = nullopt_t(0); + } + static const nullopt_t &nullopt = internal::nullopt_holder::instance_; + +#endif + +template +class Optional FLATBUFFERS_FINAL_CLASS { + // Non-scalar 'T' would extremely complicated Optional. + // Use is_scalar checking because flatbuffers flatbuffers::is_arithmetic + // isn't implemented. + static_assert(flatbuffers::is_scalar::value, "unexpected type T"); + + public: + ~Optional() {} + + FLATBUFFERS_CONSTEXPR_CPP11 Optional() FLATBUFFERS_NOEXCEPT + : value_(), has_value_(false) {} + + FLATBUFFERS_CONSTEXPR_CPP11 Optional(nullopt_t) FLATBUFFERS_NOEXCEPT + : value_(), has_value_(false) {} + + FLATBUFFERS_CONSTEXPR_CPP11 Optional(T val) FLATBUFFERS_NOEXCEPT + : value_(val), has_value_(true) {} + + FLATBUFFERS_CONSTEXPR_CPP11 Optional(const Optional &other) FLATBUFFERS_NOEXCEPT + : value_(other.value_), has_value_(other.has_value_) {} + + FLATBUFFERS_CONSTEXPR_CPP14 Optional &operator=(const Optional &other) FLATBUFFERS_NOEXCEPT { + value_ = other.value_; + has_value_ = other.has_value_; + return *this; + } + + FLATBUFFERS_CONSTEXPR_CPP14 Optional &operator=(nullopt_t) FLATBUFFERS_NOEXCEPT { + value_ = T(); + has_value_ = false; + return *this; + } + + FLATBUFFERS_CONSTEXPR_CPP14 Optional &operator=(T val) FLATBUFFERS_NOEXCEPT { + value_ = val; + has_value_ = true; + return *this; + } + + void reset() FLATBUFFERS_NOEXCEPT { + *this = nullopt; + } + + void swap(Optional &other) FLATBUFFERS_NOEXCEPT { + std::swap(value_, other.value_); + std::swap(has_value_, other.has_value_); + } + + FLATBUFFERS_CONSTEXPR_CPP11 FLATBUFFERS_EXPLICIT_CPP11 operator bool() const FLATBUFFERS_NOEXCEPT { + return has_value_; + } + + FLATBUFFERS_CONSTEXPR_CPP11 bool has_value() const FLATBUFFERS_NOEXCEPT { + return has_value_; + } + + FLATBUFFERS_CONSTEXPR_CPP11 const T& operator*() const FLATBUFFERS_NOEXCEPT { + return value_; + } + + const T& value() const { + FLATBUFFERS_ASSERT(has_value()); + return value_; + } + + T value_or(T default_value) const FLATBUFFERS_NOEXCEPT { + return has_value() ? value_ : default_value; + } + + private: + T value_; + bool has_value_; +}; + +template +FLATBUFFERS_CONSTEXPR_CPP11 bool operator==(const Optional& opt, nullopt_t) FLATBUFFERS_NOEXCEPT { + return !opt; +} +template +FLATBUFFERS_CONSTEXPR_CPP11 bool operator==(nullopt_t, const Optional& opt) FLATBUFFERS_NOEXCEPT { + return !opt; +} + +template +FLATBUFFERS_CONSTEXPR_CPP11 bool operator==(const Optional& lhs, const U& rhs) FLATBUFFERS_NOEXCEPT { + return static_cast(lhs) && (*lhs == rhs); +} + +template +FLATBUFFERS_CONSTEXPR_CPP11 bool operator==(const T& lhs, const Optional& rhs) FLATBUFFERS_NOEXCEPT { + return static_cast(rhs) && (lhs == *rhs); +} + +template +FLATBUFFERS_CONSTEXPR_CPP11 bool operator==(const Optional& lhs, const Optional& rhs) FLATBUFFERS_NOEXCEPT { + return static_cast(lhs) != static_cast(rhs) + ? false + : !static_cast(lhs) ? false : (*lhs == *rhs); +} +#endif // FLATBUFFERS_USE_STD_OPTIONAL + + +// Very limited and naive partial implementation of C++20 std::span. +#if defined(FLATBUFFERS_USE_STD_SPAN) + inline constexpr std::size_t dynamic_extent = std::dynamic_extent; + template + using span = std::span; + +#else // !defined(FLATBUFFERS_USE_STD_SPAN) +FLATBUFFERS_CONSTEXPR std::size_t dynamic_extent = static_cast(-1); + +// Exclude this code if MSVC2010 or non-STL Android is active. +// The non-STL Android doesn't have `std::is_convertible` required for SFINAE. +#if !defined(FLATBUFFERS_SPAN_MINIMAL) +namespace internal { + // This is SFINAE helper class for checking of a common condition: + // > This overload only participates in overload resolution + // > Check whether a pointer to an array of U can be converted + // > to a pointer to an array of E. + // This helper is used for checking of 'U -> const U'. + template + struct is_span_convertable { + using type = + typename std::conditional::value + && (Extent == dynamic_extent || N == Extent), + int, void>::type; + }; + + template + struct SpanIterator { + // TODO: upgrade to std::random_access_iterator_tag. + using iterator_category = std::forward_iterator_tag; + using difference_type = std::ptrdiff_t; + using value_type = typename std::remove_cv::type; + using reference = T&; + using pointer = T*; + + // Convince MSVC compiler that this iterator is trusted (it is verified). + #ifdef _MSC_VER + using _Unchecked_type = pointer; + #endif // _MSC_VER + + SpanIterator(pointer ptr) : ptr_(ptr) {} + reference operator*() const { return *ptr_; } + pointer operator->() { return ptr_; } + SpanIterator& operator++() { ptr_++; return *this; } + SpanIterator operator++(int) { auto tmp = *this; ++(*this); return tmp; } + + friend bool operator== (const SpanIterator& lhs, const SpanIterator& rhs) { return lhs.ptr_ == rhs.ptr_; } + friend bool operator!= (const SpanIterator& lhs, const SpanIterator& rhs) { return lhs.ptr_ != rhs.ptr_; } + + private: + pointer ptr_; + }; +} // namespace internal +#endif // !defined(FLATBUFFERS_SPAN_MINIMAL) + +// T - element type; must be a complete type that is not an abstract +// class type. +// Extent - the number of elements in the sequence, or dynamic. +template +class span FLATBUFFERS_FINAL_CLASS { + public: + typedef T element_type; + typedef T& reference; + typedef const T& const_reference; + typedef T* pointer; + typedef const T* const_pointer; + typedef std::size_t size_type; + + static FLATBUFFERS_CONSTEXPR size_type extent = Extent; + + // Returns the number of elements in the span. + FLATBUFFERS_CONSTEXPR_CPP11 size_type size() const FLATBUFFERS_NOEXCEPT { + return count_; + } + + // Returns the size of the sequence in bytes. + FLATBUFFERS_CONSTEXPR_CPP11 + size_type size_bytes() const FLATBUFFERS_NOEXCEPT { + return size() * sizeof(element_type); + } + + // Checks if the span is empty. + FLATBUFFERS_CONSTEXPR_CPP11 bool empty() const FLATBUFFERS_NOEXCEPT { + return size() == 0; + } + + // Returns a pointer to the beginning of the sequence. + FLATBUFFERS_CONSTEXPR_CPP11 pointer data() const FLATBUFFERS_NOEXCEPT { + return data_; + } + + #if !defined(FLATBUFFERS_SPAN_MINIMAL) + using Iterator = internal::SpanIterator; + using ConstIterator = internal::SpanIterator; + + Iterator begin() const { return Iterator(data()); } + Iterator end() const { return Iterator(data() + size()); } + + ConstIterator cbegin() const { return ConstIterator(data()); } + ConstIterator cend() const { return ConstIterator(data() + size()); } + #endif + + // Returns a reference to the idx-th element of the sequence. + // The behavior is undefined if the idx is greater than or equal to size(). + FLATBUFFERS_CONSTEXPR_CPP11 reference operator[](size_type idx) const { + return data()[idx]; + } + + FLATBUFFERS_CONSTEXPR_CPP11 span(const span &other) FLATBUFFERS_NOEXCEPT + : data_(other.data_), count_(other.count_) {} + + FLATBUFFERS_CONSTEXPR_CPP14 span &operator=(const span &other) + FLATBUFFERS_NOEXCEPT { + data_ = other.data_; + count_ = other.count_; + } + + // Limited implementation of + // `template constexpr std::span(It first, size_type count);`. + // + // Constructs a span that is a view over the range [first, first + count); + // the resulting span has: data() == first and size() == count. + // The behavior is undefined if [first, first + count) is not a valid range, + // or if (extent != flatbuffers::dynamic_extent && count != extent). + FLATBUFFERS_CONSTEXPR_CPP11 + explicit span(pointer first, size_type count) FLATBUFFERS_NOEXCEPT + : data_ (Extent == dynamic_extent ? first : (Extent == count ? first : nullptr)), + count_(Extent == dynamic_extent ? count : (Extent == count ? Extent : 0)) { + // Make span empty if the count argument is incompatible with span. + } + + // Exclude this code if MSVC2010 is active. The MSVC2010 isn't C++11 + // compliant, it doesn't support default template arguments for functions. + #if defined(FLATBUFFERS_SPAN_MINIMAL) + FLATBUFFERS_CONSTEXPR_CPP11 span() FLATBUFFERS_NOEXCEPT : data_(nullptr), + count_(0) { + static_assert(extent == 0 || extent == dynamic_extent, "invalid span"); + } + + #else + // Constructs an empty span whose data() == nullptr and size() == 0. + // This overload only participates in overload resolution if + // extent == 0 || extent == flatbuffers::dynamic_extent. + // A dummy template argument N is need dependency for SFINAE. + template::type = 0> + FLATBUFFERS_CONSTEXPR_CPP11 span() FLATBUFFERS_NOEXCEPT : data_(nullptr), + count_(0) { + static_assert(extent == 0 || extent == dynamic_extent, "invalid span"); + } + + // Constructs a span that is a view over the array arr; the resulting span + // has size() == N and data() == std::data(arr). These overloads only + // participate in overload resolution if + // extent == std::dynamic_extent || N == extent is true and + // std::remove_pointer_t(*)[] + // is convertible to element_type (*)[]. + template::type = 0> + FLATBUFFERS_CONSTEXPR_CPP11 span(element_type (&arr)[N]) FLATBUFFERS_NOEXCEPT + : data_(arr), count_(N) {} + + template::type = 0> + FLATBUFFERS_CONSTEXPR_CPP11 span(std::array &arr) FLATBUFFERS_NOEXCEPT + : data_(arr.data()), count_(N) {} + + //template + //FLATBUFFERS_CONSTEXPR_CPP11 span(std::array &arr) FLATBUFFERS_NOEXCEPT + // : data_(arr.data()), count_(N) {} + + template::type = 0> + FLATBUFFERS_CONSTEXPR_CPP11 span(const std::array &arr) FLATBUFFERS_NOEXCEPT + : data_(arr.data()), count_(N) {} + + // Converting constructor from another span s; + // the resulting span has size() == s.size() and data() == s.data(). + // This overload only participates in overload resolution + // if extent == std::dynamic_extent || N == extent is true and U (*)[] + // is convertible to element_type (*)[]. + template::type = 0> + FLATBUFFERS_CONSTEXPR_CPP11 span(const flatbuffers::span &s) FLATBUFFERS_NOEXCEPT + : span(s.data(), s.size()) { + } + + #endif // !defined(FLATBUFFERS_SPAN_MINIMAL) + + private: + // This is a naive implementation with 'count_' member even if (Extent != dynamic_extent). + pointer const data_; + size_type count_; +}; +#endif // defined(FLATBUFFERS_USE_STD_SPAN) + +#if !defined(FLATBUFFERS_SPAN_MINIMAL) +template +FLATBUFFERS_CONSTEXPR_CPP11 +flatbuffers::span make_span(U(&arr)[N]) FLATBUFFERS_NOEXCEPT { + return span(arr); +} + +template +FLATBUFFERS_CONSTEXPR_CPP11 +flatbuffers::span make_span(const U(&arr)[N]) FLATBUFFERS_NOEXCEPT { + return span(arr); +} + +template +FLATBUFFERS_CONSTEXPR_CPP11 +flatbuffers::span make_span(std::array &arr) FLATBUFFERS_NOEXCEPT { + return span(arr); +} + +template +FLATBUFFERS_CONSTEXPR_CPP11 +flatbuffers::span make_span(const std::array &arr) FLATBUFFERS_NOEXCEPT { + return span(arr); +} + +template +FLATBUFFERS_CONSTEXPR_CPP11 +flatbuffers::span make_span(U *first, std::size_t count) FLATBUFFERS_NOEXCEPT { + return span(first, count); +} + +template +FLATBUFFERS_CONSTEXPR_CPP11 +flatbuffers::span make_span(const U *first, std::size_t count) FLATBUFFERS_NOEXCEPT { + return span(first, count); +} +#endif // !defined(FLATBUFFERS_SPAN_MINIMAL) + +} // namespace flatbuffers +} // namespace mapserver + +#endif // FLATBUFFERS_STL_EMULATION_H_ diff --git a/src/flatgeobuf/include/flatbuffers/string.h b/src/flatgeobuf/include/flatbuffers/string.h new file mode 100644 index 0000000000..2c69d6a3bc --- /dev/null +++ b/src/flatgeobuf/include/flatbuffers/string.h @@ -0,0 +1,66 @@ +/* + * Copyright 2021 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLATBUFFERS_STRING_H_ +#define FLATBUFFERS_STRING_H_ + +#include "flatbuffers/base.h" +#include "flatbuffers/vector.h" + +namespace mapserver { +namespace flatbuffers { + +struct String : public Vector { + const char *c_str() const { return reinterpret_cast(Data()); } + std::string str() const { return std::string(c_str(), size()); } + + // clang-format off + #ifdef FLATBUFFERS_HAS_STRING_VIEW + flatbuffers::string_view string_view() const { + return flatbuffers::string_view(c_str(), size()); + } + #endif // FLATBUFFERS_HAS_STRING_VIEW + // clang-format on + + bool operator<(const String &o) const { + return StringLessThan(this->data(), this->size(), o.data(), o.size()); + } +}; + +// Convenience function to get std::string from a String returning an empty +// string on null pointer. +static inline std::string GetString(const String *str) { + return str ? str->str() : ""; +} + +// Convenience function to get char* from a String returning an empty string on +// null pointer. +static inline const char *GetCstring(const String *str) { + return str ? str->c_str() : ""; +} + +#ifdef FLATBUFFERS_HAS_STRING_VIEW +// Convenience function to get string_view from a String returning an empty +// string_view on null pointer. +static inline flatbuffers::string_view GetStringView(const String *str) { + return str ? str->string_view() : flatbuffers::string_view(); +} +#endif // FLATBUFFERS_HAS_STRING_VIEW + +} // namespace flatbuffers +} // namespace mapserver + +#endif // FLATBUFFERS_STRING_H_ \ No newline at end of file diff --git a/src/flatgeobuf/include/flatbuffers/struct.h b/src/flatgeobuf/include/flatbuffers/struct.h new file mode 100644 index 0000000000..7a93c5dcc0 --- /dev/null +++ b/src/flatgeobuf/include/flatbuffers/struct.h @@ -0,0 +1,55 @@ +/* + * Copyright 2021 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLATBUFFERS_STRUCT_H_ +#define FLATBUFFERS_STRUCT_H_ + +#include "flatbuffers/base.h" + +namespace mapserver { +namespace flatbuffers { + +// "structs" are flat structures that do not have an offset table, thus +// always have all members present and do not support forwards/backwards +// compatible extensions. + +class Struct FLATBUFFERS_FINAL_CLASS { + public: + template T GetField(uoffset_t o) const { + return ReadScalar(&data_[o]); + } + + template T GetStruct(uoffset_t o) const { + return reinterpret_cast(&data_[o]); + } + + const uint8_t *GetAddressOf(uoffset_t o) const { return &data_[o]; } + uint8_t *GetAddressOf(uoffset_t o) { return &data_[o]; } + + private: + // private constructor & copy constructor: you obtain instances of this + // class by pointing to existing data only + Struct(); + Struct(const Struct &); + Struct &operator=(const Struct &); + + uint8_t data_[1]; +}; + +} // namespace flatbuffers +} // namespace mapserver + +#endif // FLATBUFFERS_STRUCT_H_ \ No newline at end of file diff --git a/src/flatgeobuf/include/flatbuffers/table.h b/src/flatgeobuf/include/flatbuffers/table.h new file mode 100644 index 0000000000..67850e3bed --- /dev/null +++ b/src/flatgeobuf/include/flatbuffers/table.h @@ -0,0 +1,170 @@ +/* + * Copyright 2021 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLATBUFFERS_TABLE_H_ +#define FLATBUFFERS_TABLE_H_ + +#include "flatbuffers/base.h" +#include "flatbuffers/verifier.h" + +namespace mapserver { +namespace flatbuffers { + +// "tables" use an offset table (possibly shared) that allows fields to be +// omitted and added at will, but uses an extra indirection to read. +class Table { + public: + const uint8_t *GetVTable() const { + return data_ - ReadScalar(data_); + } + + // This gets the field offset for any of the functions below it, or 0 + // if the field was not present. + voffset_t GetOptionalFieldOffset(voffset_t field) const { + // The vtable offset is always at the start. + auto vtable = GetVTable(); + // The first element is the size of the vtable (fields + type id + itself). + auto vtsize = ReadScalar(vtable); + // If the field we're accessing is outside the vtable, we're reading older + // data, so it's the same as if the offset was 0 (not present). + return field < vtsize ? ReadScalar(vtable + field) : 0; + } + + template T GetField(voffset_t field, T defaultval) const { + auto field_offset = GetOptionalFieldOffset(field); + return field_offset ? ReadScalar(data_ + field_offset) : defaultval; + } + + template P GetPointer(voffset_t field) { + auto field_offset = GetOptionalFieldOffset(field); + auto p = data_ + field_offset; + return field_offset ? reinterpret_cast

(p + ReadScalar(p)) + : nullptr; + } + template P GetPointer(voffset_t field) const { + return const_cast

(this)->GetPointer

(field); + } + + template P GetStruct(voffset_t field) const { + auto field_offset = GetOptionalFieldOffset(field); + auto p = const_cast(data_ + field_offset); + return field_offset ? reinterpret_cast

(p) : nullptr; + } + + template + flatbuffers::Optional GetOptional(voffset_t field) const { + auto field_offset = GetOptionalFieldOffset(field); + auto p = data_ + field_offset; + return field_offset ? Optional(static_cast(ReadScalar(p))) + : Optional(); + } + + template bool SetField(voffset_t field, T val, T def) { + auto field_offset = GetOptionalFieldOffset(field); + if (!field_offset) return IsTheSameAs(val, def); + WriteScalar(data_ + field_offset, val); + return true; + } + template bool SetField(voffset_t field, T val) { + auto field_offset = GetOptionalFieldOffset(field); + if (!field_offset) return false; + WriteScalar(data_ + field_offset, val); + return true; + } + + bool SetPointer(voffset_t field, const uint8_t *val) { + auto field_offset = GetOptionalFieldOffset(field); + if (!field_offset) return false; + WriteScalar(data_ + field_offset, + static_cast(val - (data_ + field_offset))); + return true; + } + + uint8_t *GetAddressOf(voffset_t field) { + auto field_offset = GetOptionalFieldOffset(field); + return field_offset ? data_ + field_offset : nullptr; + } + const uint8_t *GetAddressOf(voffset_t field) const { + return const_cast

(this)->GetAddressOf(field); + } + + bool CheckField(voffset_t field) const { + return GetOptionalFieldOffset(field) != 0; + } + + // Verify the vtable of this table. + // Call this once per table, followed by VerifyField once per field. + bool VerifyTableStart(Verifier &verifier) const { + return verifier.VerifyTableStart(data_); + } + + // Verify a particular field. + template + bool VerifyField(const Verifier &verifier, voffset_t field, + size_t align) const { + // Calling GetOptionalFieldOffset should be safe now thanks to + // VerifyTable(). + auto field_offset = GetOptionalFieldOffset(field); + // Check the actual field. + return !field_offset || verifier.VerifyField(data_, field_offset, align); + } + + // VerifyField for required fields. + template + bool VerifyFieldRequired(const Verifier &verifier, voffset_t field, + size_t align) const { + auto field_offset = GetOptionalFieldOffset(field); + return verifier.Check(field_offset != 0) && + verifier.VerifyField(data_, field_offset, align); + } + + // Versions for offsets. + bool VerifyOffset(const Verifier &verifier, voffset_t field) const { + auto field_offset = GetOptionalFieldOffset(field); + return !field_offset || verifier.VerifyOffset(data_, field_offset); + } + + bool VerifyOffsetRequired(const Verifier &verifier, voffset_t field) const { + auto field_offset = GetOptionalFieldOffset(field); + return verifier.Check(field_offset != 0) && + verifier.VerifyOffset(data_, field_offset); + } + + private: + // private constructor & copy constructor: you obtain instances of this + // class by pointing to existing data only + Table(); + Table(const Table &other); + Table &operator=(const Table &); + + uint8_t data_[1]; +}; + +// This specialization allows avoiding warnings like: +// MSVC C4800: type: forcing value to bool 'true' or 'false'. +template<> +inline flatbuffers::Optional Table::GetOptional( + voffset_t field) const { + auto field_offset = GetOptionalFieldOffset(field); + auto p = data_ + field_offset; + return field_offset ? Optional(ReadScalar(p) != 0) + : Optional(); +} + +} // namespace flatbuffers +} // namespace mapserver + +#endif // FLATBUFFERS_TABLE_H_ diff --git a/src/flatgeobuf/include/flatbuffers/util.h b/src/flatgeobuf/include/flatbuffers/util.h new file mode 100644 index 0000000000..205366bdbe --- /dev/null +++ b/src/flatgeobuf/include/flatbuffers/util.h @@ -0,0 +1,718 @@ +/* + * Copyright 2014 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLATBUFFERS_UTIL_H_ +#define FLATBUFFERS_UTIL_H_ + +#include +#include + +#include "flatbuffers/base.h" +#include "flatbuffers/stl_emulation.h" + +#ifndef FLATBUFFERS_PREFER_PRINTF +# include +# include +#else // FLATBUFFERS_PREFER_PRINTF +# include +# include +#endif // FLATBUFFERS_PREFER_PRINTF + +#include + +namespace mapserver { +namespace flatbuffers { + +// @locale-independent functions for ASCII characters set. + +// Fast checking that character lies in closed range: [a <= x <= b] +// using one compare (conditional branch) operator. +inline bool check_ascii_range(char x, char a, char b) { + FLATBUFFERS_ASSERT(a <= b); + // (Hacker's Delight): `a <= x <= b` <=> `(x-a) <={u} (b-a)`. + // The x, a, b will be promoted to int and subtracted without overflow. + return static_cast(x - a) <= static_cast(b - a); +} + +// Case-insensitive isalpha +inline bool is_alpha(char c) { + // ASCII only: alpha to upper case => reset bit 0x20 (~0x20 = 0xDF). + return check_ascii_range(c & 0xDF, 'a' & 0xDF, 'z' & 0xDF); +} + +// Check for uppercase alpha +inline bool is_alpha_upper(char c) { return check_ascii_range(c, 'A', 'Z'); } + +// Check (case-insensitive) that `c` is equal to alpha. +inline bool is_alpha_char(char c, char alpha) { + FLATBUFFERS_ASSERT(is_alpha(alpha)); + // ASCII only: alpha to upper case => reset bit 0x20 (~0x20 = 0xDF). + return ((c & 0xDF) == (alpha & 0xDF)); +} + +// https://en.cppreference.com/w/cpp/string/byte/isxdigit +// isdigit and isxdigit are the only standard narrow character classification +// functions that are not affected by the currently installed C locale. although +// some implementations (e.g. Microsoft in 1252 codepage) may classify +// additional single-byte characters as digits. +inline bool is_digit(char c) { return check_ascii_range(c, '0', '9'); } + +inline bool is_xdigit(char c) { + // Replace by look-up table. + return is_digit(c) || check_ascii_range(c & 0xDF, 'a' & 0xDF, 'f' & 0xDF); +} + +// Case-insensitive isalnum +inline bool is_alnum(char c) { return is_alpha(c) || is_digit(c); } + +inline char CharToUpper(char c) { + return static_cast(::toupper(static_cast(c))); +} + +inline char CharToLower(char c) { + return static_cast(::tolower(static_cast(c))); +} + +// @end-locale-independent functions for ASCII character set + +#ifdef FLATBUFFERS_PREFER_PRINTF +template size_t IntToDigitCount(T t) { + size_t digit_count = 0; + // Count the sign for negative numbers + if (t < 0) digit_count++; + // Count a single 0 left of the dot for fractional numbers + if (-1 < t && t < 1) digit_count++; + // Count digits until fractional part + T eps = std::numeric_limits::epsilon(); + while (t <= (-1 + eps) || (1 - eps) <= t) { + t /= 10; + digit_count++; + } + return digit_count; +} + +template size_t NumToStringWidth(T t, int precision = 0) { + size_t string_width = IntToDigitCount(t); + // Count the dot for floating point numbers + if (precision) string_width += (precision + 1); + return string_width; +} + +template +std::string NumToStringImplWrapper(T t, const char *fmt, int precision = 0) { + size_t string_width = NumToStringWidth(t, precision); + std::string s(string_width, 0x00); + // Allow snprintf to use std::string trailing null to detect buffer overflow + snprintf(const_cast(s.data()), (s.size() + 1), fmt, string_width, t); + return s; +} +#endif // FLATBUFFERS_PREFER_PRINTF + +// Convert an integer or floating point value to a string. +// In contrast to std::stringstream, "char" values are +// converted to a string of digits, and we don't use scientific notation. +template std::string NumToString(T t) { + // clang-format off + + #ifndef FLATBUFFERS_PREFER_PRINTF + std::stringstream ss; + ss << t; + return ss.str(); + #else // FLATBUFFERS_PREFER_PRINTF + auto v = static_cast(t); + return NumToStringImplWrapper(v, "%.*lld"); + #endif // FLATBUFFERS_PREFER_PRINTF + // clang-format on +} +// Avoid char types used as character data. +template<> inline std::string NumToString(signed char t) { + return NumToString(static_cast(t)); +} +template<> inline std::string NumToString(unsigned char t) { + return NumToString(static_cast(t)); +} +template<> inline std::string NumToString(char t) { + return NumToString(static_cast(t)); +} + +// Special versions for floats/doubles. +template std::string FloatToString(T t, int precision) { + // clang-format off + + #ifndef FLATBUFFERS_PREFER_PRINTF + // to_string() prints different numbers of digits for floats depending on + // platform and isn't available on Android, so we use stringstream + std::stringstream ss; + // Use std::fixed to suppress scientific notation. + ss << std::fixed; + // Default precision is 6, we want that to be higher for doubles. + ss << std::setprecision(precision); + ss << t; + auto s = ss.str(); + #else // FLATBUFFERS_PREFER_PRINTF + auto v = static_cast(t); + auto s = NumToStringImplWrapper(v, "%0.*f", precision); + #endif // FLATBUFFERS_PREFER_PRINTF + // clang-format on + // Sadly, std::fixed turns "1" into "1.00000", so here we undo that. + auto p = s.find_last_not_of('0'); + if (p != std::string::npos) { + // Strip trailing zeroes. If it is a whole number, keep one zero. + s.resize(p + (s[p] == '.' ? 2 : 1)); + } + return s; +} + +template<> inline std::string NumToString(double t) { + return FloatToString(t, 12); +} +template<> inline std::string NumToString(float t) { + return FloatToString(t, 6); +} + +// Convert an integer value to a hexadecimal string. +// The returned string length is always xdigits long, prefixed by 0 digits. +// For example, IntToStringHex(0x23, 8) returns the string "00000023". +inline std::string IntToStringHex(int i, int xdigits) { + FLATBUFFERS_ASSERT(i >= 0); + // clang-format off + + #ifndef FLATBUFFERS_PREFER_PRINTF + std::stringstream ss; + ss << std::setw(xdigits) << std::setfill('0') << std::hex << std::uppercase + << i; + return ss.str(); + #else // FLATBUFFERS_PREFER_PRINTF + return NumToStringImplWrapper(i, "%.*X", xdigits); + #endif // FLATBUFFERS_PREFER_PRINTF + // clang-format on +} + +// clang-format off +// Use locale independent functions {strtod_l, strtof_l, strtoll_l, strtoull_l}. +#if defined(FLATBUFFERS_LOCALE_INDEPENDENT) && (FLATBUFFERS_LOCALE_INDEPENDENT > 0) + class ClassicLocale { + #ifdef _MSC_VER + typedef _locale_t locale_type; + #else + typedef locale_t locale_type; // POSIX.1-2008 locale_t type + #endif + ClassicLocale(); + ~ClassicLocale(); + locale_type locale_; + static ClassicLocale instance_; + public: + static locale_type Get() { return instance_.locale_; } + }; + + #ifdef _MSC_VER + #define __strtoull_impl(s, pe, b) _strtoui64_l(s, pe, b, ClassicLocale::Get()) + #define __strtoll_impl(s, pe, b) _strtoi64_l(s, pe, b, ClassicLocale::Get()) + #define __strtod_impl(s, pe) _strtod_l(s, pe, ClassicLocale::Get()) + #define __strtof_impl(s, pe) _strtof_l(s, pe, ClassicLocale::Get()) + #else + #define __strtoull_impl(s, pe, b) strtoull_l(s, pe, b, ClassicLocale::Get()) + #define __strtoll_impl(s, pe, b) strtoll_l(s, pe, b, ClassicLocale::Get()) + #define __strtod_impl(s, pe) strtod_l(s, pe, ClassicLocale::Get()) + #define __strtof_impl(s, pe) strtof_l(s, pe, ClassicLocale::Get()) + #endif +#else + #define __strtod_impl(s, pe) strtod(s, pe) + #define __strtof_impl(s, pe) static_cast(strtod(s, pe)) + #ifdef _MSC_VER + #define __strtoull_impl(s, pe, b) _strtoui64(s, pe, b) + #define __strtoll_impl(s, pe, b) _strtoi64(s, pe, b) + #else + #define __strtoull_impl(s, pe, b) strtoull(s, pe, b) + #define __strtoll_impl(s, pe, b) strtoll(s, pe, b) + #endif +#endif + +inline void strtoval_impl(int64_t *val, const char *str, char **endptr, + int base) { + *val = __strtoll_impl(str, endptr, base); +} + +inline void strtoval_impl(uint64_t *val, const char *str, char **endptr, + int base) { + *val = __strtoull_impl(str, endptr, base); +} + +inline void strtoval_impl(double *val, const char *str, char **endptr) { + *val = __strtod_impl(str, endptr); +} + +// UBSAN: double to float is safe if numeric_limits::is_iec559 is true. +__supress_ubsan__("float-cast-overflow") +inline void strtoval_impl(float *val, const char *str, char **endptr) { + *val = __strtof_impl(str, endptr); +} +#undef __strtoull_impl +#undef __strtoll_impl +#undef __strtod_impl +#undef __strtof_impl +// clang-format on + +// Adaptor for strtoull()/strtoll(). +// Flatbuffers accepts numbers with any count of leading zeros (-009 is -9), +// while strtoll with base=0 interprets first leading zero as octal prefix. +// In future, it is possible to add prefixed 0b0101. +// 1) Checks errno code for overflow condition (out of range). +// 2) If base <= 0, function try to detect base of number by prefix. +// +// Return value (like strtoull and strtoll, but reject partial result): +// - If successful, an integer value corresponding to the str is returned. +// - If full string conversion can't be performed, 0 is returned. +// - If the converted value falls out of range of corresponding return type, a +// range error occurs. In this case value MAX(T)/MIN(T) is returned. +template +inline bool StringToIntegerImpl(T *val, const char *const str, + const int base = 0, + const bool check_errno = true) { + // T is int64_t or uint64_T + FLATBUFFERS_ASSERT(str); + if (base <= 0) { + auto s = str; + while (*s && !is_digit(*s)) s++; + if (s[0] == '0' && is_alpha_char(s[1], 'X')) + return StringToIntegerImpl(val, str, 16, check_errno); + // if a prefix not match, try base=10 + return StringToIntegerImpl(val, str, 10, check_errno); + } else { + if (check_errno) errno = 0; // clear thread-local errno + auto endptr = str; + strtoval_impl(val, str, const_cast(&endptr), base); + if ((*endptr != '\0') || (endptr == str)) { + *val = 0; // erase partial result + return false; // invalid string + } + // errno is out-of-range, return MAX/MIN + if (check_errno && errno) return false; + return true; + } +} + +template +inline bool StringToFloatImpl(T *val, const char *const str) { + // Type T must be either float or double. + FLATBUFFERS_ASSERT(str && val); + auto end = str; + strtoval_impl(val, str, const_cast(&end)); + auto done = (end != str) && (*end == '\0'); + if (!done) *val = 0; // erase partial result + return done; +} + +// Convert a string to an instance of T. +// Return value (matched with StringToInteger64Impl and strtod): +// - If successful, a numeric value corresponding to the str is returned. +// - If full string conversion can't be performed, 0 is returned. +// - If the converted value falls out of range of corresponding return type, a +// range error occurs. In this case value MAX(T)/MIN(T) is returned. +template inline bool StringToNumber(const char *s, T *val) { + // Assert on `unsigned long` and `signed long` on LP64. + // If it is necessary, it could be solved with flatbuffers::enable_if. + static_assert(sizeof(T) < sizeof(int64_t), "unexpected type T"); + FLATBUFFERS_ASSERT(s && val); + int64_t i64; + // The errno check isn't needed, will return MAX/MIN on overflow. + if (StringToIntegerImpl(&i64, s, 0, false)) { + const int64_t max = (flatbuffers::numeric_limits::max)(); + const int64_t min = flatbuffers::numeric_limits::lowest(); + if (i64 > max) { + *val = static_cast(max); + return false; + } + if (i64 < min) { + // For unsigned types return max to distinguish from + // "no conversion can be performed" when 0 is returned. + *val = static_cast(flatbuffers::is_unsigned::value ? max : min); + return false; + } + *val = static_cast(i64); + return true; + } + *val = 0; + return false; +} + +template<> inline bool StringToNumber(const char *str, int64_t *val) { + return StringToIntegerImpl(val, str); +} + +template<> +inline bool StringToNumber(const char *str, uint64_t *val) { + if (!StringToIntegerImpl(val, str)) return false; + // The strtoull accepts negative numbers: + // If the minus sign was part of the input sequence, the numeric value + // calculated from the sequence of digits is negated as if by unary minus + // in the result type, which applies unsigned integer wraparound rules. + // Fix this behavior (except -0). + if (*val) { + auto s = str; + while (*s && !is_digit(*s)) s++; + s = (s > str) ? (s - 1) : s; // step back to one symbol + if (*s == '-') { + // For unsigned types return the max to distinguish from + // "no conversion can be performed". + *val = (flatbuffers::numeric_limits::max)(); + return false; + } + } + return true; +} + +template<> inline bool StringToNumber(const char *s, float *val) { + return StringToFloatImpl(val, s); +} + +template<> inline bool StringToNumber(const char *s, double *val) { + return StringToFloatImpl(val, s); +} + +inline int64_t StringToInt(const char *s, int base = 10) { + int64_t val; + return StringToIntegerImpl(&val, s, base) ? val : 0; +} + +inline uint64_t StringToUInt(const char *s, int base = 10) { + uint64_t val; + return StringToIntegerImpl(&val, s, base) ? val : 0; +} + +typedef bool (*LoadFileFunction)(const char *filename, bool binary, + std::string *dest); +typedef bool (*FileExistsFunction)(const char *filename); + +LoadFileFunction SetLoadFileFunction(LoadFileFunction load_file_function); + +FileExistsFunction SetFileExistsFunction( + FileExistsFunction file_exists_function); + +// Check if file "name" exists. +bool FileExists(const char *name); + +// Check if "name" exists and it is also a directory. +bool DirExists(const char *name); + +// Load file "name" into "buf" returning true if successful +// false otherwise. If "binary" is false data is read +// using ifstream's text mode, otherwise data is read with +// no transcoding. +bool LoadFile(const char *name, bool binary, std::string *buf); + +// Save data "buf" of length "len" bytes into a file +// "name" returning true if successful, false otherwise. +// If "binary" is false data is written using ifstream's +// text mode, otherwise data is written with no +// transcoding. +bool SaveFile(const char *name, const char *buf, size_t len, bool binary); + +// Save data "buf" into file "name" returning true if +// successful, false otherwise. If "binary" is false +// data is written using ifstream's text mode, otherwise +// data is written with no transcoding. +inline bool SaveFile(const char *name, const std::string &buf, bool binary) { + return SaveFile(name, buf.c_str(), buf.size(), binary); +} + +// Functionality for minimalistic portable path handling. + +// The functions below behave correctly regardless of whether posix ('/') or +// Windows ('/' or '\\') separators are used. + +// Any new separators inserted are always posix. +FLATBUFFERS_CONSTEXPR char kPathSeparator = '/'; + +// Returns the path with the extension, if any, removed. +std::string StripExtension(const std::string &filepath); + +// Returns the extension, if any. +std::string GetExtension(const std::string &filepath); + +// Return the last component of the path, after the last separator. +std::string StripPath(const std::string &filepath); + +// Strip the last component of the path + separator. +std::string StripFileName(const std::string &filepath); + +// Concatenates a path with a filename, regardless of whether the path +// ends in a separator or not. +std::string ConCatPathFileName(const std::string &path, + const std::string &filename); + +// Replaces any '\\' separators with '/' +std::string PosixPath(const char *path); +std::string PosixPath(const std::string &path); + +// This function ensure a directory exists, by recursively +// creating dirs for any parts of the path that don't exist yet. +void EnsureDirExists(const std::string &filepath); + +// Obtains the absolute path from any other path. +// Returns the input path if the absolute path couldn't be resolved. +std::string AbsolutePath(const std::string &filepath); + +// Returns files relative to the --project_root path, prefixed with `//`. +std::string RelativeToRootPath(const std::string &project, + const std::string &filepath); + +// To and from UTF-8 unicode conversion functions + +// Convert a unicode code point into a UTF-8 representation by appending it +// to a string. Returns the number of bytes generated. +inline int ToUTF8(uint32_t ucc, std::string *out) { + FLATBUFFERS_ASSERT(!(ucc & 0x80000000)); // Top bit can't be set. + // 6 possible encodings: http://en.wikipedia.org/wiki/UTF-8 + for (int i = 0; i < 6; i++) { + // Max bits this encoding can represent. + uint32_t max_bits = 6 + i * 5 + static_cast(!i); + if (ucc < (1u << max_bits)) { // does it fit? + // Remaining bits not encoded in the first byte, store 6 bits each + uint32_t remain_bits = i * 6; + // Store first byte: + (*out) += static_cast((0xFE << (max_bits - remain_bits)) | + (ucc >> remain_bits)); + // Store remaining bytes: + for (int j = i - 1; j >= 0; j--) { + (*out) += static_cast(((ucc >> (j * 6)) & 0x3F) | 0x80); + } + return i + 1; // Return the number of bytes added. + } + } + FLATBUFFERS_ASSERT(0); // Impossible to arrive here. + return -1; +} + +// Converts whatever prefix of the incoming string corresponds to a valid +// UTF-8 sequence into a unicode code. The incoming pointer will have been +// advanced past all bytes parsed. +// returns -1 upon corrupt UTF-8 encoding (ignore the incoming pointer in +// this case). +inline int FromUTF8(const char **in) { + int len = 0; + // Count leading 1 bits. + for (int mask = 0x80; mask >= 0x04; mask >>= 1) { + if (**in & mask) { + len++; + } else { + break; + } + } + if ((static_cast(**in) << len) & 0x80) + return -1; // Bit after leading 1's must be 0. + if (!len) return *(*in)++; + // UTF-8 encoded values with a length are between 2 and 4 bytes. + if (len < 2 || len > 4) { return -1; } + // Grab initial bits of the code. + int ucc = *(*in)++ & ((1 << (7 - len)) - 1); + for (int i = 0; i < len - 1; i++) { + if ((**in & 0xC0) != 0x80) return -1; // Upper bits must 1 0. + ucc <<= 6; + ucc |= *(*in)++ & 0x3F; // Grab 6 more bits of the code. + } + // UTF-8 cannot encode values between 0xD800 and 0xDFFF (reserved for + // UTF-16 surrogate pairs). + if (ucc >= 0xD800 && ucc <= 0xDFFF) { return -1; } + // UTF-8 must represent code points in their shortest possible encoding. + switch (len) { + case 2: + // Two bytes of UTF-8 can represent code points from U+0080 to U+07FF. + if (ucc < 0x0080 || ucc > 0x07FF) { return -1; } + break; + case 3: + // Three bytes of UTF-8 can represent code points from U+0800 to U+FFFF. + if (ucc < 0x0800 || ucc > 0xFFFF) { return -1; } + break; + case 4: + // Four bytes of UTF-8 can represent code points from U+10000 to U+10FFFF. + if (ucc < 0x10000 || ucc > 0x10FFFF) { return -1; } + break; + } + return ucc; +} + +#ifndef FLATBUFFERS_PREFER_PRINTF +// Wraps a string to a maximum length, inserting new lines where necessary. Any +// existing whitespace will be collapsed down to a single space. A prefix or +// suffix can be provided, which will be inserted before or after a wrapped +// line, respectively. +inline std::string WordWrap(const std::string in, size_t max_length, + const std::string wrapped_line_prefix, + const std::string wrapped_line_suffix) { + std::istringstream in_stream(in); + std::string wrapped, line, word; + + in_stream >> word; + line = word; + + while (in_stream >> word) { + if ((line.length() + 1 + word.length() + wrapped_line_suffix.length()) < + max_length) { + line += " " + word; + } else { + wrapped += line + wrapped_line_suffix + "\n"; + line = wrapped_line_prefix + word; + } + } + wrapped += line; + + return wrapped; +} +#endif // !FLATBUFFERS_PREFER_PRINTF + +inline bool EscapeString(const char *s, size_t length, std::string *_text, + bool allow_non_utf8, bool natural_utf8) { + std::string &text = *_text; + text += "\""; + for (uoffset_t i = 0; i < length; i++) { + char c = s[i]; + switch (c) { + case '\n': text += "\\n"; break; + case '\t': text += "\\t"; break; + case '\r': text += "\\r"; break; + case '\b': text += "\\b"; break; + case '\f': text += "\\f"; break; + case '\"': text += "\\\""; break; + case '\\': text += "\\\\"; break; + default: + if (c >= ' ' && c <= '~') { + text += c; + } else { + // Not printable ASCII data. Let's see if it's valid UTF-8 first: + const char *utf8 = s + i; + int ucc = FromUTF8(&utf8); + if (ucc < 0) { + if (allow_non_utf8) { + text += "\\x"; + text += IntToStringHex(static_cast(c), 2); + } else { + // There are two cases here: + // + // 1) We reached here by parsing an IDL file. In that case, + // we previously checked for non-UTF-8, so we shouldn't reach + // here. + // + // 2) We reached here by someone calling GenerateText() + // on a previously-serialized flatbuffer. The data might have + // non-UTF-8 Strings, or might be corrupt. + // + // In both cases, we have to give up and inform the caller + // they have no JSON. + return false; + } + } else { + if (natural_utf8) { + // utf8 points to past all utf-8 bytes parsed + text.append(s + i, static_cast(utf8 - s - i)); + } else if (ucc <= 0xFFFF) { + // Parses as Unicode within JSON's \uXXXX range, so use that. + text += "\\u"; + text += IntToStringHex(ucc, 4); + } else if (ucc <= 0x10FFFF) { + // Encode Unicode SMP values to a surrogate pair using two \u + // escapes. + uint32_t base = ucc - 0x10000; + auto high_surrogate = (base >> 10) + 0xD800; + auto low_surrogate = (base & 0x03FF) + 0xDC00; + text += "\\u"; + text += IntToStringHex(high_surrogate, 4); + text += "\\u"; + text += IntToStringHex(low_surrogate, 4); + } + // Skip past characters recognized. + i = static_cast(utf8 - s - 1); + } + } + break; + } + } + text += "\""; + return true; +} + +inline std::string BufferToHexText(const void *buffer, size_t buffer_size, + size_t max_length, + const std::string &wrapped_line_prefix, + const std::string &wrapped_line_suffix) { + std::string text = wrapped_line_prefix; + size_t start_offset = 0; + const char *s = reinterpret_cast(buffer); + for (size_t i = 0; s && i < buffer_size; i++) { + // Last iteration or do we have more? + bool have_more = i + 1 < buffer_size; + text += "0x"; + text += IntToStringHex(static_cast(s[i]), 2); + if (have_more) { text += ','; } + // If we have more to process and we reached max_length + if (have_more && + text.size() + wrapped_line_suffix.size() >= start_offset + max_length) { + text += wrapped_line_suffix; + text += '\n'; + start_offset = text.size(); + text += wrapped_line_prefix; + } + } + text += wrapped_line_suffix; + return text; +} + +// Remove paired quotes in a string: "text"|'text' -> text. +std::string RemoveStringQuotes(const std::string &s); + +// Change th global C-locale to locale with name . +// Returns an actual locale name in <_value>, useful if locale_name is "" or +// null. +bool SetGlobalTestLocale(const char *locale_name, + std::string *_value = nullptr); + +// Read (or test) a value of environment variable. +bool ReadEnvironmentVariable(const char *var_name, + std::string *_value = nullptr); + +// MSVC specific: Send all assert reports to STDOUT to prevent CI hangs. +void SetupDefaultCRTReportMode(); + +enum class Case { + kUnknown = 0, + // TheQuickBrownFox + kUpperCamel = 1, + // theQuickBrownFox + kLowerCamel = 2, + // the_quick_brown_fox + kSnake = 3, + // THE_QUICK_BROWN_FOX + kScreamingSnake = 4, + // THEQUICKBROWNFOX + kAllUpper = 5, + // thequickbrownfox + kAllLower = 6, + // the-quick-brown-fox + kDasher = 7, + // THEQuiCKBr_ownFox (or whatever you want, we won't change it) + kKeep = 8, + // the_quick_brown_fox123 (as opposed to the_quick_brown_fox_123) + kSnake2 = 9, +}; + +// Convert the `input` string of case `input_case` to the specified `output_case`. +std::string ConvertCase(const std::string &input, Case output_case, + Case input_case = Case::kSnake); + +} // namespace flatbuffers +} // namespace mapserver + +#endif // FLATBUFFERS_UTIL_H_ diff --git a/src/flatgeobuf/include/flatbuffers/vector.h b/src/flatgeobuf/include/flatbuffers/vector.h new file mode 100644 index 0000000000..9fe59fe023 --- /dev/null +++ b/src/flatgeobuf/include/flatbuffers/vector.h @@ -0,0 +1,373 @@ +/* + * Copyright 2021 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLATBUFFERS_VECTOR_H_ +#define FLATBUFFERS_VECTOR_H_ + +#include "flatbuffers/base.h" +#include "flatbuffers/buffer.h" +#include "flatbuffers/stl_emulation.h" + +namespace mapserver { +namespace flatbuffers { + +struct String; + +// An STL compatible iterator implementation for Vector below, effectively +// calling Get() for every element. +template struct VectorIterator { + typedef std::random_access_iterator_tag iterator_category; + typedef IT value_type; + typedef ptrdiff_t difference_type; + typedef IT *pointer; + typedef IT &reference; + + VectorIterator(const uint8_t *data, uoffset_t i) + : data_(data + IndirectHelper::element_stride * i) {} + VectorIterator(const VectorIterator &other) : data_(other.data_) {} + VectorIterator() : data_(nullptr) {} + + VectorIterator &operator=(const VectorIterator &other) { + data_ = other.data_; + return *this; + } + + VectorIterator &operator=(VectorIterator &&other) { + data_ = other.data_; + return *this; + } + + bool operator==(const VectorIterator &other) const { + return data_ == other.data_; + } + + bool operator<(const VectorIterator &other) const { + return data_ < other.data_; + } + + bool operator!=(const VectorIterator &other) const { + return data_ != other.data_; + } + + difference_type operator-(const VectorIterator &other) const { + return (data_ - other.data_) / IndirectHelper::element_stride; + } + + // Note: return type is incompatible with the standard + // `reference operator*()`. + IT operator*() const { return IndirectHelper::Read(data_, 0); } + + // Note: return type is incompatible with the standard + // `pointer operator->()`. + IT operator->() const { return IndirectHelper::Read(data_, 0); } + + VectorIterator &operator++() { + data_ += IndirectHelper::element_stride; + return *this; + } + + VectorIterator operator++(int) { + VectorIterator temp(data_, 0); + data_ += IndirectHelper::element_stride; + return temp; + } + + VectorIterator operator+(const uoffset_t &offset) const { + return VectorIterator(data_ + offset * IndirectHelper::element_stride, + 0); + } + + VectorIterator &operator+=(const uoffset_t &offset) { + data_ += offset * IndirectHelper::element_stride; + return *this; + } + + VectorIterator &operator--() { + data_ -= IndirectHelper::element_stride; + return *this; + } + + VectorIterator operator--(int) { + VectorIterator temp(data_, 0); + data_ -= IndirectHelper::element_stride; + return temp; + } + + VectorIterator operator-(const uoffset_t &offset) const { + return VectorIterator(data_ - offset * IndirectHelper::element_stride, + 0); + } + + VectorIterator &operator-=(const uoffset_t &offset) { + data_ -= offset * IndirectHelper::element_stride; + return *this; + } + + private: + const uint8_t *data_; +}; + +template +struct VectorReverseIterator : public std::reverse_iterator { + explicit VectorReverseIterator(Iterator iter) + : std::reverse_iterator(iter) {} + + // Note: return type is incompatible with the standard + // `reference operator*()`. + typename Iterator::value_type operator*() const { + auto tmp = std::reverse_iterator::current; + return *--tmp; + } + + // Note: return type is incompatible with the standard + // `pointer operator->()`. + typename Iterator::value_type operator->() const { + auto tmp = std::reverse_iterator::current; + return *--tmp; + } +}; + +// This is used as a helper type for accessing vectors. +// Vector::data() assumes the vector elements start after the length field. +template class Vector { + public: + typedef VectorIterator::mutable_return_type> + iterator; + typedef VectorIterator::return_type> + const_iterator; + typedef VectorReverseIterator reverse_iterator; + typedef VectorReverseIterator const_reverse_iterator; + + typedef typename flatbuffers::bool_constant::value> + scalar_tag; + + static FLATBUFFERS_CONSTEXPR bool is_span_observable = + scalar_tag::value && (FLATBUFFERS_LITTLEENDIAN || sizeof(T) == 1); + + uoffset_t size() const { return EndianScalar(length_); } + + // Deprecated: use size(). Here for backwards compatibility. + FLATBUFFERS_ATTRIBUTE([[deprecated("use size() instead")]]) + uoffset_t Length() const { return size(); } + + typedef typename IndirectHelper::return_type return_type; + typedef typename IndirectHelper::mutable_return_type mutable_return_type; + typedef return_type value_type; + + return_type Get(uoffset_t i) const { + FLATBUFFERS_ASSERT(i < size()); + return IndirectHelper::Read(Data(), i); + } + + return_type operator[](uoffset_t i) const { return Get(i); } + + // If this is a Vector of enums, T will be its storage type, not the enum + // type. This function makes it convenient to retrieve value with enum + // type E. + template E GetEnum(uoffset_t i) const { + return static_cast(Get(i)); + } + + // If this a vector of unions, this does the cast for you. There's no check + // to make sure this is the right type! + template const U *GetAs(uoffset_t i) const { + return reinterpret_cast(Get(i)); + } + + // If this a vector of unions, this does the cast for you. There's no check + // to make sure this is actually a string! + const String *GetAsString(uoffset_t i) const { + return reinterpret_cast(Get(i)); + } + + const void *GetStructFromOffset(size_t o) const { + return reinterpret_cast(Data() + o); + } + + iterator begin() { return iterator(Data(), 0); } + const_iterator begin() const { return const_iterator(Data(), 0); } + + iterator end() { return iterator(Data(), size()); } + const_iterator end() const { return const_iterator(Data(), size()); } + + reverse_iterator rbegin() { return reverse_iterator(end()); } + const_reverse_iterator rbegin() const { + return const_reverse_iterator(end()); + } + + reverse_iterator rend() { return reverse_iterator(begin()); } + const_reverse_iterator rend() const { + return const_reverse_iterator(begin()); + } + + const_iterator cbegin() const { return begin(); } + + const_iterator cend() const { return end(); } + + const_reverse_iterator crbegin() const { return rbegin(); } + + const_reverse_iterator crend() const { return rend(); } + + // Change elements if you have a non-const pointer to this object. + // Scalars only. See reflection.h, and the documentation. + void Mutate(uoffset_t i, const T &val) { + FLATBUFFERS_ASSERT(i < size()); + WriteScalar(data() + i, val); + } + + // Change an element of a vector of tables (or strings). + // "val" points to the new table/string, as you can obtain from + // e.g. reflection::AddFlatBuffer(). + void MutateOffset(uoffset_t i, const uint8_t *val) { + FLATBUFFERS_ASSERT(i < size()); + static_assert(sizeof(T) == sizeof(uoffset_t), "Unrelated types"); + WriteScalar(data() + i, + static_cast(val - (Data() + i * sizeof(uoffset_t)))); + } + + // Get a mutable pointer to tables/strings inside this vector. + mutable_return_type GetMutableObject(uoffset_t i) const { + FLATBUFFERS_ASSERT(i < size()); + return const_cast(IndirectHelper::Read(Data(), i)); + } + + // The raw data in little endian format. Use with care. + const uint8_t *Data() const { + return reinterpret_cast(&length_ + 1); + } + + uint8_t *Data() { return reinterpret_cast(&length_ + 1); } + + // Similarly, but typed, much like std::vector::data + const T *data() const { return reinterpret_cast(Data()); } + T *data() { return reinterpret_cast(Data()); } + + template return_type LookupByKey(K key) const { + void *search_result = std::bsearch( + &key, Data(), size(), IndirectHelper::element_stride, KeyCompare); + + if (!search_result) { + return nullptr; // Key not found. + } + + const uint8_t *element = reinterpret_cast(search_result); + + return IndirectHelper::Read(element, 0); + } + + template mutable_return_type MutableLookupByKey(K key) { + return const_cast(LookupByKey(key)); + } + + protected: + // This class is only used to access pre-existing data. Don't ever + // try to construct these manually. + Vector(); + + uoffset_t length_; + + private: + // This class is a pointer. Copying will therefore create an invalid object. + // Private and unimplemented copy constructor. + Vector(const Vector &); + Vector &operator=(const Vector &); + + template static int KeyCompare(const void *ap, const void *bp) { + const K *key = reinterpret_cast(ap); + const uint8_t *data = reinterpret_cast(bp); + auto table = IndirectHelper::Read(data, 0); + + // std::bsearch compares with the operands transposed, so we negate the + // result here. + return -table->KeyCompareWithValue(*key); + } +}; + +template +FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span make_span(Vector &vec) + FLATBUFFERS_NOEXCEPT { + static_assert(Vector::is_span_observable, + "wrong type U, only LE-scalar, or byte types are allowed"); + return span(vec.data(), vec.size()); +} + +template +FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span make_span( + const Vector &vec) FLATBUFFERS_NOEXCEPT { + static_assert(Vector::is_span_observable, + "wrong type U, only LE-scalar, or byte types are allowed"); + return span(vec.data(), vec.size()); +} + +template +FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span make_bytes_span( + Vector &vec) FLATBUFFERS_NOEXCEPT { + static_assert(Vector::scalar_tag::value, + "wrong type U, only LE-scalar, or byte types are allowed"); + return span(vec.Data(), vec.size() * sizeof(U)); +} + +template +FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span make_bytes_span( + const Vector &vec) FLATBUFFERS_NOEXCEPT { + static_assert(Vector::scalar_tag::value, + "wrong type U, only LE-scalar, or byte types are allowed"); + return span(vec.Data(), vec.size() * sizeof(U)); +} + +// Represent a vector much like the template above, but in this case we +// don't know what the element types are (used with reflection.h). +class VectorOfAny { + public: + uoffset_t size() const { return EndianScalar(length_); } + + const uint8_t *Data() const { + return reinterpret_cast(&length_ + 1); + } + uint8_t *Data() { return reinterpret_cast(&length_ + 1); } + + protected: + VectorOfAny(); + + uoffset_t length_; + + private: + VectorOfAny(const VectorOfAny &); + VectorOfAny &operator=(const VectorOfAny &); +}; + +template +Vector> *VectorCast(Vector> *ptr) { + static_assert(std::is_base_of::value, "Unrelated types"); + return reinterpret_cast> *>(ptr); +} + +template +const Vector> *VectorCast(const Vector> *ptr) { + static_assert(std::is_base_of::value, "Unrelated types"); + return reinterpret_cast> *>(ptr); +} + +// Convenient helper function to get the length of any vector, regardless +// of whether it is null or not (the field is not set). +template static inline size_t VectorLength(const Vector *v) { + return v ? v->size() : 0; +} + +} // namespace flatbuffers +} // namespace mapserver + +#endif // FLATBUFFERS_VERIFIER_H_ diff --git a/src/flatgeobuf/include/flatbuffers/vector_downward.h b/src/flatgeobuf/include/flatbuffers/vector_downward.h new file mode 100644 index 0000000000..94e7562ec8 --- /dev/null +++ b/src/flatgeobuf/include/flatbuffers/vector_downward.h @@ -0,0 +1,273 @@ +/* + * Copyright 2021 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLATBUFFERS_VECTOR_DOWNWARD_H_ +#define FLATBUFFERS_VECTOR_DOWNWARD_H_ + +#include "flatbuffers/base.h" +#include "flatbuffers/default_allocator.h" +#include "flatbuffers/detached_buffer.h" + +namespace mapserver { +namespace flatbuffers { + +// This is a minimal replication of std::vector functionality, +// except growing from higher to lower addresses. i.e push_back() inserts data +// in the lowest address in the vector. +// Since this vector leaves the lower part unused, we support a "scratch-pad" +// that can be stored there for temporary data, to share the allocated space. +// Essentially, this supports 2 std::vectors in a single buffer. +class vector_downward { + public: + explicit vector_downward(size_t initial_size, Allocator *allocator, + bool own_allocator, size_t buffer_minalign) + : allocator_(allocator), + own_allocator_(own_allocator), + initial_size_(initial_size), + buffer_minalign_(buffer_minalign), + reserved_(0), + size_(0), + buf_(nullptr), + cur_(nullptr), + scratch_(nullptr) {} + + vector_downward(vector_downward &&other) + // clang-format on + : allocator_(other.allocator_), + own_allocator_(other.own_allocator_), + initial_size_(other.initial_size_), + buffer_minalign_(other.buffer_minalign_), + reserved_(other.reserved_), + size_(other.size_), + buf_(other.buf_), + cur_(other.cur_), + scratch_(other.scratch_) { + // No change in other.allocator_ + // No change in other.initial_size_ + // No change in other.buffer_minalign_ + other.own_allocator_ = false; + other.reserved_ = 0; + other.buf_ = nullptr; + other.cur_ = nullptr; + other.scratch_ = nullptr; + } + + vector_downward &operator=(vector_downward &&other) { + // Move construct a temporary and swap idiom + vector_downward temp(std::move(other)); + swap(temp); + return *this; + } + + ~vector_downward() { + clear_buffer(); + clear_allocator(); + } + + void reset() { + clear_buffer(); + clear(); + } + + void clear() { + if (buf_) { + cur_ = buf_ + reserved_; + } else { + reserved_ = 0; + cur_ = nullptr; + } + size_ = 0; + clear_scratch(); + } + + void clear_scratch() { scratch_ = buf_; } + + void clear_allocator() { + if (own_allocator_ && allocator_) { delete allocator_; } + allocator_ = nullptr; + own_allocator_ = false; + } + + void clear_buffer() { + if (buf_) Deallocate(allocator_, buf_, reserved_); + buf_ = nullptr; + } + + // Relinquish the pointer to the caller. + uint8_t *release_raw(size_t &allocated_bytes, size_t &offset) { + auto *buf = buf_; + allocated_bytes = reserved_; + offset = static_cast(cur_ - buf_); + + // release_raw only relinquishes the buffer ownership. + // Does not deallocate or reset the allocator. Destructor will do that. + buf_ = nullptr; + clear(); + return buf; + } + + // Relinquish the pointer to the caller. + DetachedBuffer release() { + // allocator ownership (if any) is transferred to DetachedBuffer. + DetachedBuffer fb(allocator_, own_allocator_, buf_, reserved_, cur_, + size()); + if (own_allocator_) { + allocator_ = nullptr; + own_allocator_ = false; + } + buf_ = nullptr; + clear(); + return fb; + } + + size_t ensure_space(size_t len) { + FLATBUFFERS_ASSERT(cur_ >= scratch_ && scratch_ >= buf_); + if (len > static_cast(cur_ - scratch_)) { reallocate(len); } + // Beyond this, signed offsets may not have enough range: + // (FlatBuffers > 2GB not supported). + FLATBUFFERS_ASSERT(size() < FLATBUFFERS_MAX_BUFFER_SIZE); + return len; + } + + inline uint8_t *make_space(size_t len) { + if (len) { + ensure_space(len); + cur_ -= len; + size_ += static_cast(len); + } + return cur_; + } + + // Returns nullptr if using the DefaultAllocator. + Allocator *get_custom_allocator() { return allocator_; } + + inline uoffset_t size() const { return size_; } + + uoffset_t scratch_size() const { + return static_cast(scratch_ - buf_); + } + + size_t capacity() const { return reserved_; } + + uint8_t *data() const { + FLATBUFFERS_ASSERT(cur_); + return cur_; + } + + uint8_t *scratch_data() const { + FLATBUFFERS_ASSERT(buf_); + return buf_; + } + + uint8_t *scratch_end() const { + FLATBUFFERS_ASSERT(scratch_); + return scratch_; + } + + uint8_t *data_at(size_t offset) const { return buf_ + reserved_ - offset; } + + void push(const uint8_t *bytes, size_t num) { + if (num > 0) { memcpy(make_space(num), bytes, num); } + } + + // Specialized version of push() that avoids memcpy call for small data. + template void push_small(const T &little_endian_t) { + make_space(sizeof(T)); + *reinterpret_cast(cur_) = little_endian_t; + } + + template void scratch_push_small(const T &t) { + ensure_space(sizeof(T)); + *reinterpret_cast(scratch_) = t; + scratch_ += sizeof(T); + } + + // fill() is most frequently called with small byte counts (<= 4), + // which is why we're using loops rather than calling memset. + void fill(size_t zero_pad_bytes) { + make_space(zero_pad_bytes); + for (size_t i = 0; i < zero_pad_bytes; i++) cur_[i] = 0; + } + + // Version for when we know the size is larger. + // Precondition: zero_pad_bytes > 0 + void fill_big(size_t zero_pad_bytes) { + memset(make_space(zero_pad_bytes), 0, zero_pad_bytes); + } + + void pop(size_t bytes_to_remove) { + cur_ += bytes_to_remove; + size_ -= static_cast(bytes_to_remove); + } + + void scratch_pop(size_t bytes_to_remove) { scratch_ -= bytes_to_remove; } + + void swap(vector_downward &other) { + using std::swap; + swap(allocator_, other.allocator_); + swap(own_allocator_, other.own_allocator_); + swap(initial_size_, other.initial_size_); + swap(buffer_minalign_, other.buffer_minalign_); + swap(reserved_, other.reserved_); + swap(size_, other.size_); + swap(buf_, other.buf_); + swap(cur_, other.cur_); + swap(scratch_, other.scratch_); + } + + void swap_allocator(vector_downward &other) { + using std::swap; + swap(allocator_, other.allocator_); + swap(own_allocator_, other.own_allocator_); + } + + private: + // You shouldn't really be copying instances of this class. + FLATBUFFERS_DELETE_FUNC(vector_downward(const vector_downward &)); + FLATBUFFERS_DELETE_FUNC(vector_downward &operator=(const vector_downward &)); + + Allocator *allocator_; + bool own_allocator_; + size_t initial_size_; + size_t buffer_minalign_; + size_t reserved_; + uoffset_t size_; + uint8_t *buf_; + uint8_t *cur_; // Points at location between empty (below) and used (above). + uint8_t *scratch_; // Points to the end of the scratchpad in use. + + void reallocate(size_t len) { + auto old_reserved = reserved_; + auto old_size = size(); + auto old_scratch_size = scratch_size(); + reserved_ += + (std::max)(len, old_reserved ? old_reserved / 2 : initial_size_); + reserved_ = (reserved_ + buffer_minalign_ - 1) & ~(buffer_minalign_ - 1); + if (buf_) { + buf_ = ReallocateDownward(allocator_, buf_, old_reserved, reserved_, + old_size, old_scratch_size); + } else { + buf_ = Allocate(allocator_, reserved_); + } + cur_ = buf_ + reserved_ - old_size; + scratch_ = buf_ + old_scratch_size; + } +}; + +} // namespace flatbuffers +} // namespace mapserver + +#endif // FLATBUFFERS_VECTOR_DOWNWARD_H_ diff --git a/src/flatgeobuf/include/flatbuffers/verifier.h b/src/flatgeobuf/include/flatbuffers/verifier.h new file mode 100644 index 0000000000..f3e38f22e9 --- /dev/null +++ b/src/flatgeobuf/include/flatbuffers/verifier.h @@ -0,0 +1,284 @@ +/* + * Copyright 2021 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLATBUFFERS_VERIFIER_H_ +#define FLATBUFFERS_VERIFIER_H_ + +#include "flatbuffers/base.h" +#include "flatbuffers/vector.h" + +namespace mapserver { +namespace flatbuffers { + +// Helper class to verify the integrity of a FlatBuffer +class Verifier FLATBUFFERS_FINAL_CLASS { + public: + Verifier(const uint8_t *buf, size_t buf_len, uoffset_t _max_depth = 64, + uoffset_t _max_tables = 1000000, bool _check_alignment = true) + : buf_(buf), + size_(buf_len), + depth_(0), + max_depth_(_max_depth), + num_tables_(0), + max_tables_(_max_tables), + upper_bound_(0), + check_alignment_(_check_alignment), + flex_reuse_tracker_(nullptr) { + FLATBUFFERS_ASSERT(size_ < FLATBUFFERS_MAX_BUFFER_SIZE); + } + + // Central location where any verification failures register. + bool Check(bool ok) const { + // clang-format off + #ifdef FLATBUFFERS_DEBUG_VERIFICATION_FAILURE + FLATBUFFERS_ASSERT(ok); + #endif + #ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE + if (!ok) + upper_bound_ = 0; + #endif + // clang-format on + return ok; + } + + // Verify any range within the buffer. + bool Verify(size_t elem, size_t elem_len) const { + // clang-format off + #ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE + auto upper_bound = elem + elem_len; + if (upper_bound_ < upper_bound) + upper_bound_ = upper_bound; + #endif + // clang-format on + return Check(elem_len < size_ && elem <= size_ - elem_len); + } + + bool VerifyAlignment(size_t elem, size_t align) const { + return Check((elem & (align - 1)) == 0 || !check_alignment_); + } + + // Verify a range indicated by sizeof(T). + template bool Verify(size_t elem) const { + return VerifyAlignment(elem, sizeof(T)) && Verify(elem, sizeof(T)); + } + + bool VerifyFromPointer(const uint8_t *p, size_t len) { + auto o = static_cast(p - buf_); + return Verify(o, len); + } + + // Verify relative to a known-good base pointer. + bool VerifyFieldStruct(const uint8_t *base, voffset_t elem_off, + size_t elem_len, size_t align) const { + auto f = static_cast(base - buf_) + elem_off; + return VerifyAlignment(f, align) && Verify(f, elem_len); + } + + template + bool VerifyField(const uint8_t *base, voffset_t elem_off, + size_t align) const { + auto f = static_cast(base - buf_) + elem_off; + return VerifyAlignment(f, align) && Verify(f, sizeof(T)); + } + + // Verify a pointer (may be NULL) of a table type. + template bool VerifyTable(const T *table) { + return !table || table->Verify(*this); + } + + // Verify a pointer (may be NULL) of any vector type. + template bool VerifyVector(const Vector *vec) const { + return !vec || VerifyVectorOrString(reinterpret_cast(vec), + sizeof(T)); + } + + // Verify a pointer (may be NULL) of a vector to struct. + template bool VerifyVector(const Vector *vec) const { + return VerifyVector(reinterpret_cast *>(vec)); + } + + // Verify a pointer (may be NULL) to string. + bool VerifyString(const String *str) const { + size_t end; + return !str || (VerifyVectorOrString(reinterpret_cast(str), + 1, &end) && + Verify(end, 1) && // Must have terminator + Check(buf_[end] == '\0')); // Terminating byte must be 0. + } + + // Common code between vectors and strings. + bool VerifyVectorOrString(const uint8_t *vec, size_t elem_size, + size_t *end = nullptr) const { + auto veco = static_cast(vec - buf_); + // Check we can read the size field. + if (!Verify(veco)) return false; + // Check the whole array. If this is a string, the byte past the array + // must be 0. + auto size = ReadScalar(vec); + auto max_elems = FLATBUFFERS_MAX_BUFFER_SIZE / elem_size; + if (!Check(size < max_elems)) + return false; // Protect against byte_size overflowing. + auto byte_size = sizeof(size) + elem_size * size; + if (end) *end = veco + byte_size; + return Verify(veco, byte_size); + } + + // Special case for string contents, after the above has been called. + bool VerifyVectorOfStrings(const Vector> *vec) const { + if (vec) { + for (uoffset_t i = 0; i < vec->size(); i++) { + if (!VerifyString(vec->Get(i))) return false; + } + } + return true; + } + + // Special case for table contents, after the above has been called. + template bool VerifyVectorOfTables(const Vector> *vec) { + if (vec) { + for (uoffset_t i = 0; i < vec->size(); i++) { + if (!vec->Get(i)->Verify(*this)) return false; + } + } + return true; + } + + __supress_ubsan__("unsigned-integer-overflow") bool VerifyTableStart( + const uint8_t *table) { + // Check the vtable offset. + auto tableo = static_cast(table - buf_); + if (!Verify(tableo)) return false; + // This offset may be signed, but doing the subtraction unsigned always + // gives the result we want. + auto vtableo = tableo - static_cast(ReadScalar(table)); + // Check the vtable size field, then check vtable fits in its entirety. + return VerifyComplexity() && Verify(vtableo) && + VerifyAlignment(ReadScalar(buf_ + vtableo), + sizeof(voffset_t)) && + Verify(vtableo, ReadScalar(buf_ + vtableo)); + } + + template + bool VerifyBufferFromStart(const char *identifier, size_t start) { + if (identifier && !Check((size_ >= 2 * sizeof(flatbuffers::uoffset_t) && + BufferHasIdentifier(buf_ + start, identifier)))) { + return false; + } + + // Call T::Verify, which must be in the generated code for this type. + auto o = VerifyOffset(start); + return o && reinterpret_cast(buf_ + start + o)->Verify(*this) + // clang-format off + #ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE + && GetComputedSize() + #endif + ; + // clang-format on + } + + template + bool VerifyNestedFlatBuffer(const Vector *buf, + const char *identifier) { + if (!buf) return true; + Verifier nested_verifier(buf->data(), buf->size()); + return nested_verifier.VerifyBuffer(identifier); + } + + // Verify this whole buffer, starting with root type T. + template bool VerifyBuffer() { return VerifyBuffer(nullptr); } + + template bool VerifyBuffer(const char *identifier) { + return VerifyBufferFromStart(identifier, 0); + } + + template bool VerifySizePrefixedBuffer(const char *identifier) { + return Verify(0U) && + ReadScalar(buf_) == size_ - sizeof(uoffset_t) && + VerifyBufferFromStart(identifier, sizeof(uoffset_t)); + } + + uoffset_t VerifyOffset(size_t start) const { + if (!Verify(start)) return 0; + auto o = ReadScalar(buf_ + start); + // May not point to itself. + if (!Check(o != 0)) return 0; + // Can't wrap around / buffers are max 2GB. + if (!Check(static_cast(o) >= 0)) return 0; + // Must be inside the buffer to create a pointer from it (pointer outside + // buffer is UB). + if (!Verify(start + o, 1)) return 0; + return o; + } + + uoffset_t VerifyOffset(const uint8_t *base, voffset_t start) const { + return VerifyOffset(static_cast(base - buf_) + start); + } + + // Called at the start of a table to increase counters measuring data + // structure depth and amount, and possibly bails out with false if + // limits set by the constructor have been hit. Needs to be balanced + // with EndTable(). + bool VerifyComplexity() { + depth_++; + num_tables_++; + return Check(depth_ <= max_depth_ && num_tables_ <= max_tables_); + } + + // Called at the end of a table to pop the depth count. + bool EndTable() { + depth_--; + return true; + } + + // Returns the message size in bytes + size_t GetComputedSize() const { + // clang-format off + #ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE + uintptr_t size = upper_bound_; + // Align the size to uoffset_t + size = (size - 1 + sizeof(uoffset_t)) & ~(sizeof(uoffset_t) - 1); + return (size > size_) ? 0 : size; + #else + // Must turn on FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE for this to work. + (void)upper_bound_; + FLATBUFFERS_ASSERT(false); + return 0; + #endif + // clang-format on + } + + std::vector *GetFlexReuseTracker() { return flex_reuse_tracker_; } + + void SetFlexReuseTracker(std::vector *rt) { + flex_reuse_tracker_ = rt; + } + + private: + const uint8_t *buf_; + size_t size_; + uoffset_t depth_; + uoffset_t max_depth_; + uoffset_t num_tables_; + uoffset_t max_tables_; + mutable size_t upper_bound_; + bool check_alignment_; + std::vector *flex_reuse_tracker_; +}; + +} // namespace flatbuffers +} // namespace mapserver + +#endif // FLATBUFFERS_VERIFIER_H_ diff --git a/src/flatgeobuf/packedrtree.cpp b/src/flatgeobuf/packedrtree.cpp new file mode 100644 index 0000000000..490967bb90 --- /dev/null +++ b/src/flatgeobuf/packedrtree.cpp @@ -0,0 +1,413 @@ +/****************************************************************************** + * + * Project: FlatGeobuf + * Purpose: Packed RTree management + * Author: Björn Harrtell + * + ****************************************************************************** + * Copyright (c) 2018-2020, Björn Harrtell + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + ****************************************************************************/ + +// NOTE: The upstream of this file is in https://github.com/bjornharrtell/flatgeobuf/tree/master/src/cpp + +#ifdef GDAL_COMPILATION +#include "cpl_port.h" +#else +#define CPL_IS_LSB 1 +#endif + +#include "packedrtree.h" + +#include +#include +#include + +namespace mapserver +{ +namespace FlatGeobuf +{ + +const NodeItem &NodeItem::expand(const NodeItem &r) +{ + if (r.minX < minX) minX = r.minX; + if (r.minY < minY) minY = r.minY; + if (r.maxX > maxX) maxX = r.maxX; + if (r.maxY > maxY) maxY = r.maxY; + return *this; +} + +NodeItem NodeItem::create(uint64_t offset) +{ + return { + std::numeric_limits::infinity(), + std::numeric_limits::infinity(), + -1 * std::numeric_limits::infinity(), + -1 * std::numeric_limits::infinity(), + offset + }; +} + +bool NodeItem::intersects(const NodeItem &r) const +{ + if (maxX < r.minX) return false; + if (maxY < r.minY) return false; + if (minX > r.maxX) return false; + if (minY > r.maxY) return false; + return true; +} + +std::vector NodeItem::toVector() +{ + return std::vector { minX, minY, maxX, maxY }; +} + +// Based on public domain code at https://github.com/rawrunprotected/hilbert_curves +uint32_t hilbert(uint32_t x, uint32_t y) +{ + uint32_t a = x ^ y; + uint32_t b = 0xFFFF ^ a; + uint32_t c = 0xFFFF ^ (x | y); + uint32_t d = x & (y ^ 0xFFFF); + + uint32_t A = a | (b >> 1); + uint32_t B = (a >> 1) ^ a; + uint32_t C = ((c >> 1) ^ (b & (d >> 1))) ^ c; + uint32_t D = ((a & (c >> 1)) ^ (d >> 1)) ^ d; + + a = A; b = B; c = C; d = D; + A = ((a & (a >> 2)) ^ (b & (b >> 2))); + B = ((a & (b >> 2)) ^ (b & ((a ^ b) >> 2))); + C ^= ((a & (c >> 2)) ^ (b & (d >> 2))); + D ^= ((b & (c >> 2)) ^ ((a ^ b) & (d >> 2))); + + a = A; b = B; c = C; d = D; + A = ((a & (a >> 4)) ^ (b & (b >> 4))); + B = ((a & (b >> 4)) ^ (b & ((a ^ b) >> 4))); + C ^= ((a & (c >> 4)) ^ (b & (d >> 4))); + D ^= ((b & (c >> 4)) ^ ((a ^ b) & (d >> 4))); + + a = A; b = B; c = C; d = D; + C ^= ((a & (c >> 8)) ^ (b & (d >> 8))); + D ^= ((b & (c >> 8)) ^ ((a ^ b) & (d >> 8))); + + a = C ^ (C >> 1); + b = D ^ (D >> 1); + + uint32_t i0 = x ^ y; + uint32_t i1 = b | (0xFFFF ^ (i0 | a)); + + i0 = (i0 | (i0 << 8)) & 0x00FF00FF; + i0 = (i0 | (i0 << 4)) & 0x0F0F0F0F; + i0 = (i0 | (i0 << 2)) & 0x33333333; + i0 = (i0 | (i0 << 1)) & 0x55555555; + + i1 = (i1 | (i1 << 8)) & 0x00FF00FF; + i1 = (i1 | (i1 << 4)) & 0x0F0F0F0F; + i1 = (i1 | (i1 << 2)) & 0x33333333; + i1 = (i1 | (i1 << 1)) & 0x55555555; + + uint32_t value = ((i1 << 1) | i0); + + return value; +} + +uint32_t hilbert(const NodeItem &r, uint32_t hilbertMax, const double minX, const double minY, const double width, const double height) +{ + uint32_t x = 0; + uint32_t y = 0; + uint32_t v; + if (width != 0.0) + x = static_cast(floor(hilbertMax * ((r.minX + r.maxX) / 2 - minX) / width)); + if (height != 0.0) + y = static_cast(floor(hilbertMax * ((r.minY + r.maxY) / 2 - minY) / height)); + v = hilbert(x, y); + return v; +} + +const uint32_t hilbertMax = (1 << 16) - 1; + +void hilbertSort(std::vector> &items) +{ + NodeItem extent = calcExtent(items); + const double minX = extent.minX; + const double minY = extent.minY; + const double width = extent.width(); + const double height = extent.height(); + std::sort(items.begin(), items.end(), [minX, minY, width, height] (std::shared_ptr a, std::shared_ptr b) { + uint32_t ha = hilbert(a->nodeItem, hilbertMax, minX, minY, width, height); + uint32_t hb = hilbert(b->nodeItem, hilbertMax, minX, minY, width, height); + return ha > hb; + }); +} + +void hilbertSort(std::vector &items) +{ + NodeItem extent = calcExtent(items); + const double minX = extent.minX; + const double minY = extent.minY; + const double width = extent.width(); + const double height = extent.height(); + std::sort(items.begin(), items.end(), [minX, minY, width, height] (const NodeItem &a, const NodeItem &b) { + uint32_t ha = hilbert(a, hilbertMax, minX, minY, width, height); + uint32_t hb = hilbert(b, hilbertMax, minX, minY, width, height); + return ha > hb; + }); +} + +NodeItem calcExtent(const std::vector> &items) +{ + return std::accumulate(items.begin(), items.end(), NodeItem::create(0), [] (NodeItem a, const std::shared_ptr& b) { + return a.expand(b->nodeItem); + }); +} + +NodeItem calcExtent(const std::vector &nodes) +{ + return std::accumulate(nodes.begin(), nodes.end(), NodeItem::create(0), [] (NodeItem a, const NodeItem &b) { + return a.expand(b); + }); +} + +void PackedRTree::init(const uint16_t nodeSize) +{ + if (nodeSize < 2) + throw std::invalid_argument("Node size must be at least 2"); + if (_numItems == 0) + throw std::invalid_argument("Cannot create empty tree"); + _nodeSize = std::min(std::max(nodeSize, static_cast(2)), static_cast(65535)); + _levelBounds = generateLevelBounds(_numItems, _nodeSize); + _numNodes = _levelBounds.front().second; + _nodeItems = new NodeItem[static_cast(_numNodes)]; +} + +std::vector> PackedRTree::generateLevelBounds(const uint64_t numItems, const uint16_t nodeSize) { + if (nodeSize < 2) + throw std::invalid_argument("Node size must be at least 2"); + if (numItems == 0) + throw std::invalid_argument("Number of items must be greater than 0"); + if (numItems > std::numeric_limits::max() - ((numItems / nodeSize) * 2)) + throw std::overflow_error("Number of items too large"); + + // number of nodes per level in bottom-up order + std::vector levelNumNodes; + uint64_t n = numItems; + uint64_t numNodes = n; + levelNumNodes.push_back(n); + do { + n = (n + nodeSize - 1) / nodeSize; + numNodes += n; + levelNumNodes.push_back(n); + } while (n != 1); + + // bounds per level in reversed storage order (top-down) + std::vector levelOffsets; + n = numNodes; + for (auto size : levelNumNodes) + levelOffsets.push_back(n -= size); + std::reverse(levelOffsets.begin(), levelOffsets.end()); + std::reverse(levelNumNodes.begin(), levelNumNodes.end()); + std::vector> levelBounds; + for (size_t i = 0; i < levelNumNodes.size(); i++) + levelBounds.push_back(std::pair(levelOffsets[i], levelOffsets[i] + levelNumNodes[i])); + std::reverse(levelBounds.begin(), levelBounds.end()); + return levelBounds; +} + +void PackedRTree::generateNodes() +{ + for (uint32_t i = 0; i < _levelBounds.size() - 1; i++) { + auto pos = _levelBounds[i].first; + auto end = _levelBounds[i].second; + auto newpos = _levelBounds[i + 1].first; + while (pos < end) { + NodeItem node = NodeItem::create(pos); + for (uint32_t j = 0; j < _nodeSize && pos < end; j++) + node.expand(_nodeItems[pos++]); + _nodeItems[newpos++] = node; + } + } +} + +void PackedRTree::fromData(const void *data) +{ + auto buf = reinterpret_cast(data); + const NodeItem *pn = reinterpret_cast(buf); + for (uint64_t i = 0; i < _numNodes; i++) { + NodeItem n = *pn++; + _nodeItems[i] = n; + _extent.expand(n); + } +} + +PackedRTree::PackedRTree(const std::vector> &items, const NodeItem &extent, const uint16_t nodeSize) : + _extent(extent), + _numItems(items.size()) +{ + init(nodeSize); + for (size_t i = 0; i < _numItems; i++) + _nodeItems[_numNodes - _numItems + i] = items[i]->nodeItem; + generateNodes(); +} + +PackedRTree::PackedRTree(const std::vector &nodes, const NodeItem &extent, const uint16_t nodeSize) : + _extent(extent), + _numItems(nodes.size()) +{ + init(nodeSize); + for (size_t i = 0; i < _numItems; i++) + _nodeItems[_numNodes - _numItems + i] = nodes[i]; + generateNodes(); +} + +PackedRTree::PackedRTree(const void *data, const uint64_t numItems, const uint16_t nodeSize) : + _extent(NodeItem::create(0)), + _numItems(numItems) +{ + init(nodeSize); + fromData(data); +} + +std::vector PackedRTree::search(double minX, double minY, double maxX, double maxY) const +{ + uint64_t leafNodesOffset = _levelBounds.front().first; + NodeItem n { minX, minY, maxX, maxY, 0 }; + std::vector results; + std::unordered_map queue; + queue.insert(std::pair(0, _levelBounds.size() - 1)); + while(queue.size() != 0) { + auto next = queue.begin(); + uint64_t nodeIndex = next->first; + uint64_t level = next->second; + queue.erase(next); + bool isLeafNode = nodeIndex >= _numNodes - _numItems; + // find the end index of the node + uint64_t end = std::min(static_cast(nodeIndex + _nodeSize), _levelBounds[static_cast(level)].second); + // search through child nodes + for (uint64_t pos = nodeIndex; pos < end; pos++) { + auto nodeItem = _nodeItems[static_cast(pos)]; + if (!n.intersects(nodeItem)) + continue; + if (isLeafNode) + results.push_back({ nodeItem.offset, pos - leafNodesOffset }); + else + queue.insert(std::pair(nodeItem.offset, level - 1)); + } + } + return results; +} + +std::vector PackedRTree::streamSearch( + const uint64_t numItems, const uint16_t nodeSize, const NodeItem &item, + const std::function &readNode) +{ + auto levelBounds = generateLevelBounds(numItems, nodeSize); + uint64_t leafNodesOffset = levelBounds.front().first; + uint64_t numNodes = levelBounds.front().second; + auto nodeItems = std::vector(nodeSize); + uint8_t *nodesBuf = reinterpret_cast(nodeItems.data()); + // use ordered search queue to make index traversal in sequential order + std::map queue; + std::vector results; + queue.insert(std::pair(0, levelBounds.size() - 1)); + while(queue.size() != 0) { + auto next = queue.begin(); + uint64_t nodeIndex = next->first; + uint64_t level = next->second; + queue.erase(next); + bool isLeafNode = nodeIndex >= numNodes - numItems; + // find the end index of the node + uint64_t end = std::min(static_cast(nodeIndex + nodeSize), levelBounds[static_cast(level)].second); + uint64_t length = end - nodeIndex; + readNode(nodesBuf, static_cast(nodeIndex * sizeof(NodeItem)), static_cast(length * sizeof(NodeItem))); +#if !CPL_IS_LSB + for( size_t i = 0; i < static_cast(length); i++ ) + { + CPL_LSBPTR64(&nodeItems[i].minX); + CPL_LSBPTR64(&nodeItems[i].minY); + CPL_LSBPTR64(&nodeItems[i].maxX); + CPL_LSBPTR64(&nodeItems[i].maxY); + CPL_LSBPTR64(&nodeItems[i].offset); + } +#endif + // search through child nodes + for (uint64_t pos = nodeIndex; pos < end; pos++) { + uint64_t nodePos = pos - nodeIndex; + auto nodeItem = nodeItems[static_cast(nodePos)]; + if (!item.intersects(nodeItem)) + continue; + if (isLeafNode) + results.push_back({ nodeItem.offset, pos - leafNodesOffset }); + else + queue.insert(std::pair(nodeItem.offset, level - 1)); + } + } + return results; +} + +uint64_t PackedRTree::size() const { return _numNodes * sizeof(NodeItem); } + +uint64_t PackedRTree::size(const uint64_t numItems, const uint16_t nodeSize) +{ + if (nodeSize < 2) + throw std::invalid_argument("Node size must be at least 2"); + if (numItems == 0) + throw std::invalid_argument("Number of items must be greater than 0"); + const uint16_t nodeSizeMin = std::min(std::max(nodeSize, static_cast(2)), static_cast(65535)); + // limit so that resulting size in bytes can be represented by uint64_t + if (numItems > static_cast(1) << 56) + throw std::overflow_error("Number of items must be less than 2^56"); + uint64_t n = numItems; + uint64_t numNodes = n; + do { + n = (n + nodeSizeMin - 1) / nodeSizeMin; + numNodes += n; + } while (n != 1); + return numNodes * sizeof(NodeItem); +} + +void PackedRTree::streamWrite(const std::function &writeData) { +#if !CPL_IS_LSB + for( size_t i = 0; i < static_cast(_numNodes); i++ ) + { + CPL_LSBPTR64(&_nodeItems[i].minX); + CPL_LSBPTR64(&_nodeItems[i].minY); + CPL_LSBPTR64(&_nodeItems[i].maxX); + CPL_LSBPTR64(&_nodeItems[i].maxY); + CPL_LSBPTR64(&_nodeItems[i].offset); + } +#endif + writeData(reinterpret_cast(_nodeItems), static_cast(_numNodes * sizeof(NodeItem))); +#if !CPL_IS_LSB + for( size_t i = 0; i < static_cast(_numNodes); i++ ) + { + CPL_LSBPTR64(&_nodeItems[i].minX); + CPL_LSBPTR64(&_nodeItems[i].minY); + CPL_LSBPTR64(&_nodeItems[i].maxX); + CPL_LSBPTR64(&_nodeItems[i].maxY); + CPL_LSBPTR64(&_nodeItems[i].offset); + } +#endif +} + +NodeItem PackedRTree::getExtent() const { return _extent; } + +} +} \ No newline at end of file diff --git a/src/flatgeobuf/packedrtree.h b/src/flatgeobuf/packedrtree.h new file mode 100644 index 0000000000..e16cee9335 --- /dev/null +++ b/src/flatgeobuf/packedrtree.h @@ -0,0 +1,113 @@ +/****************************************************************************** + * + * Project: FlatGeobuf + * Purpose: Packed RTree management + * Author: Björn Harrtell + * + ****************************************************************************** + * Copyright (c) 2018-2020, Björn Harrtell + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + ****************************************************************************/ + +// NOTE: The upstream of this file is in https://github.com/bjornharrtell/flatgeobuf/tree/master/src/cpp + +#ifndef FLATGEOBUF_PACKEDRTREE_H_ +#define FLATGEOBUF_PACKEDRTREE_H_ + +#include +#include + +#include "flatbuffers/flatbuffers.h" + +namespace mapserver { +namespace FlatGeobuf { + +struct NodeItem { + double minX; + double minY; + double maxX; + double maxY; + uint64_t offset; + double width() const { return maxX - minX; } + double height() const { return maxY - minY; } + static NodeItem sum(NodeItem a, const NodeItem &b) { + a.expand(b); + return a; + } + static NodeItem create(uint64_t offset = 0); + const NodeItem &expand(const NodeItem &r); + bool intersects(const NodeItem &r) const; + std::vector toVector(); +}; + +struct Item { + NodeItem nodeItem; +}; + +struct SearchResultItem { + uint64_t offset; + uint64_t index; +}; + +std::ostream& operator << (std::ostream& os, NodeItem const& value); + +uint32_t hilbert(uint32_t x, uint32_t y); +uint32_t hilbert(const NodeItem &n, uint32_t hilbertMax, const double minX, const double minY, const double width, const double height); +void hilbertSort(std::vector> &items); +void hilbertSort(std::vector &items); +NodeItem calcExtent(const std::vector> &items); +NodeItem calcExtent(const std::vector &rects); + +/** + * Packed R-Tree + * Based on https://github.com/mourner/flatbush + */ +class PackedRTree { + NodeItem _extent; + NodeItem *_nodeItems = nullptr; + uint64_t _numItems; + uint64_t _numNodes; + uint16_t _nodeSize; + std::vector> _levelBounds; + void init(const uint16_t nodeSize); + void generateNodes(); + void fromData(const void *data); +public: + ~PackedRTree() { + if (_nodeItems != nullptr) + delete[] _nodeItems; + } + PackedRTree(const std::vector> &items, const NodeItem &extent, const uint16_t nodeSize = 16); + PackedRTree(const std::vector &nodes, const NodeItem &extent, const uint16_t nodeSize = 16); + PackedRTree(const void *data, const uint64_t numItems, const uint16_t nodeSize = 16); + std::vector search(double minX, double minY, double maxX, double maxY) const; + static std::vector streamSearch( + const uint64_t numItems, const uint16_t nodeSize, const NodeItem &item, + const std::function &readNode); + static std::vector> generateLevelBounds(const uint64_t numItems, const uint16_t nodeSize); + uint64_t size() const; + static uint64_t size(const uint64_t numItems, const uint16_t nodeSize = 16); + NodeItem getExtent() const; + void streamWrite(const std::function &writeData); +}; + +} } + +#endif diff --git a/src/fontcache.c b/src/fontcache.c new file mode 100644 index 0000000000..9e1e7fb104 --- /dev/null +++ b/src/fontcache.c @@ -0,0 +1,406 @@ +/****************************************************************************** + * + * Project: MapServer + * Purpose: Freetype Font helper functions + * Author: Thomas Bonfort and the MapServer team. + * + ****************************************************************************** + * Copyright (c) 1996-2013 Regents of the University of Minnesota. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + *****************************************************************************/ + +#include "mapserver.h" +#include "mapthread.h" +#include "fontcache.h" +#include "dejavu-sans-condensed.h" + +#include "cpl_conv.h" + +typedef struct { + FT_Library library; + face_element *face_cache; + glyph_element *bitmap_glyph_cache; +} ft_cache; + +#ifdef USE_THREAD +typedef struct ft_thread_cache ft_thread_cache; +struct ft_thread_cache { + void *thread_id; + ft_thread_cache *next; + ft_cache cache; +}; +ft_thread_cache *ft_caches; +int use_global_ft_cache; +#else +ft_cache global_ft_cache; +#endif + +void msInitFontCache(ft_cache *c) { + memset(c, 0, sizeof(ft_cache)); + FT_Init_FreeType(&c->library); +} + +void msFreeFontCache(ft_cache *c) { + /* ... TODO ... */ + face_element *cur_face, *tmp_face; + glyph_element *cur_bitmap, *tmp_bitmap; + UT_HASH_ITER(hh, c->face_cache, cur_face, tmp_face) { + index_element *cur_index, *tmp_index; + outline_element *cur_outline, *tmp_outline; + glyph_element *cur_glyph, *tmp_glyph; + UT_HASH_ITER(hh, cur_face->index_cache, cur_index, tmp_index) { + UT_HASH_DEL(cur_face->index_cache, cur_index); + free(cur_index); + } + UT_HASH_ITER(hh, cur_face->outline_cache, cur_outline, tmp_outline) { + UT_HASH_DEL(cur_face->outline_cache, cur_outline); + FT_Outline_Done(c->library, &cur_outline->outline); + free(cur_outline); + } + UT_HASH_ITER(hh, cur_face->glyph_cache, cur_glyph, tmp_glyph) { + UT_HASH_DEL(cur_face->glyph_cache, cur_glyph); + free(cur_glyph); + } +#ifdef USE_HARFBUZZ + if (cur_face->hbfont) { + hb_font_destroy(cur_face->hbfont->hbfont); + hb_font_destroy(cur_face->hbfont->hbparentfont); + hb_font_funcs_destroy(cur_face->hbfont->funcs); + free(cur_face->hbfont); + } +#endif + FT_Done_Face(cur_face->face); + free(cur_face->font); + UT_HASH_DEL(c->face_cache, cur_face); + free(cur_face); + } + FT_Done_FreeType(c->library); + + UT_HASH_ITER(hh, c->bitmap_glyph_cache, cur_bitmap, tmp_bitmap) { + UT_HASH_DEL(c->bitmap_glyph_cache, cur_bitmap); + free(cur_bitmap); + } + memset(c, 0, sizeof(ft_cache)); +} + +ft_cache *msGetFontCache() { +#ifndef USE_THREAD + return &global_ft_cache; +#else + void *nThreadId = 0; + ft_thread_cache *prev = NULL, *cur = ft_caches; + + if (!use_global_ft_cache) + nThreadId = msGetThreadId(); + + if (cur != NULL && cur->thread_id == nThreadId) + return &cur->cache; + + /* -------------------------------------------------------------------- */ + /* Search for cache for this thread */ + /* -------------------------------------------------------------------- */ + msAcquireLock(TLOCK_TTF); + + cur = ft_caches; + while (cur != NULL && cur->thread_id != nThreadId) { + prev = cur; + cur = cur->next; + } + + /* -------------------------------------------------------------------- */ + /* If we found it, make sure it is pushed to the front of the */ + /* link for faster finding next time, and return it. */ + /* -------------------------------------------------------------------- */ + if (cur != NULL) { + if (prev != NULL) { + prev->next = cur->next; + cur->next = ft_caches; + ft_caches = cur; + } + + msReleaseLock(TLOCK_TTF); + return &cur->cache; + } + + /* -------------------------------------------------------------------- */ + /* Create a new context group for this thread. */ + /* -------------------------------------------------------------------- */ + cur = msSmallMalloc(sizeof(ft_thread_cache)); + cur->next = NULL; + cur->thread_id = nThreadId; + msInitFontCache(&cur->cache); + cur->next = ft_caches; + ft_caches = cur; + + msReleaseLock(TLOCK_TTF); + + return &cur->cache; +#endif +} + +void msFontCacheSetup() { +#ifndef USE_THREAD + ft_cache *c = msGetFontCache(); + msInitFontCache(c); +#else + const char *use_global_cache = + CPLGetConfigOption("MS_USE_GLOBAL_FT_CACHE", NULL); + if (use_global_cache) + use_global_ft_cache = atoi(use_global_cache); + else + use_global_ft_cache = 0; + + ft_caches = NULL; +#endif +} + +void msFontCacheCleanup() { +#ifndef USE_THREAD + ft_cache *c = msGetFontCache(); + msFreeFontCache(c); +#else + ft_thread_cache *cur, *next; + msAcquireLock(TLOCK_TTF); + cur = ft_caches; + while (cur != NULL) { + msFreeFontCache(&cur->cache); + next = cur->next; + free(cur); + cur = next; + } + ft_caches = NULL; + msReleaseLock(TLOCK_TTF); +#endif +} + +unsigned int msGetGlyphIndex(face_element *face, unsigned int unicode) { + index_element *ic; + if (face->face->charmap && + face->face->charmap->encoding == FT_ENCODING_MS_SYMBOL) { + unicode |= 0xf000; /* why? */ + } +#ifdef USE_THREAD + if (use_global_ft_cache) + msAcquireLock(TLOCK_TTF); +#endif + UT_HASH_FIND_INT(face->index_cache, &unicode, ic); + if (!ic) { + ic = msSmallMalloc(sizeof(index_element)); + ic->codepoint = FT_Get_Char_Index(face->face, unicode); + ic->unicode = unicode; + UT_HASH_ADD_INT(face->index_cache, unicode, ic); + } +#ifdef USE_THREAD + if (use_global_ft_cache) + msReleaseLock(TLOCK_TTF); +#endif + return ic->codepoint; +} + +#define MS_DEFAULT_FONT_KEY "_ms_default_" + +face_element *msGetFontFace(const char *key, fontSetObj *fontset) { + face_element *fc; + int error; + ft_cache *cache = msGetFontCache(); + if (!key) { + key = MS_DEFAULT_FONT_KEY; + } +#ifdef USE_THREAD + if (use_global_ft_cache) + msAcquireLock(TLOCK_TTF); +#endif + UT_HASH_FIND_STR(cache->face_cache, key, fc); + if (!fc) { + const char *fontfile = NULL; + fc = msSmallCalloc(1, sizeof(face_element)); + if (fontset && strcmp(key, MS_DEFAULT_FONT_KEY)) { + fontfile = msLookupHashTable(&(fontset->fonts), key); + if (!fontfile) { + msSetError(MS_MISCERR, "Could not find font with key \"%s\" in fontset", + "msGetFontFace()", key); + free(fc); +#ifdef USE_THREAD + if (use_global_ft_cache) + msReleaseLock(TLOCK_TTF); +#endif + return NULL; + } + error = FT_New_Face(cache->library, fontfile, 0, &(fc->face)); + } else { + error = FT_New_Memory_Face(cache->library, dejavu_sans_condensed_ttf, + dejavu_sans_condensed_ttf_len, 0, &(fc->face)); + } + if (error) { + msSetError(MS_MISCERR, + "Freetype was unable to load font file \"%s\" for key \"%s\"", + "msGetFontFace()", fontfile, key); + free(fc); +#ifdef USE_THREAD + if (use_global_ft_cache) + msReleaseLock(TLOCK_TTF); +#endif + return NULL; + } + if (!fc->face->charmap) { + /* The font file has no unicode charmap, select an alternate one */ + if (FT_Select_Charmap(fc->face, FT_ENCODING_MS_SYMBOL)) + FT_Select_Charmap(fc->face, FT_ENCODING_APPLE_ROMAN); + /* the previous calls may have failed, we ignore as there's nothing much + * left to do */ + } + fc->font = msStrdup(key); + UT_HASH_ADD_KEYPTR(hh, cache->face_cache, fc->font, strlen(key), fc); + } +#ifdef USE_THREAD + if (use_global_ft_cache) + msReleaseLock(TLOCK_TTF); +#endif + return fc; +} + +glyph_element *msGetGlyphByIndex(face_element *face, unsigned int size, + unsigned int codepoint) { + glyph_element *gc; + glyph_element_key key; + memset(&key, 0, sizeof(glyph_element_key)); + key.codepoint = codepoint; + key.size = size; +#ifdef USE_THREAD + if (use_global_ft_cache) + msAcquireLock(TLOCK_TTF); +#endif + UT_HASH_FIND(hh, face->glyph_cache, &key, sizeof(glyph_element_key), gc); + if (!gc) { + FT_Error error; + gc = msSmallMalloc(sizeof(glyph_element)); + if (MS_NINT(size * 96.0 / 72.0) != face->face->size->metrics.x_ppem) { + FT_Set_Pixel_Sizes(face->face, 0, MS_NINT(size * 96 / 72.0)); + } + error = + FT_Load_Glyph(face->face, key.codepoint, + FT_LOAD_DEFAULT | FT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING | + FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH); + if (error) { + msDebug("Unable to load glyph %u for font \"%s\". Using ? as fallback.\n", + key.codepoint, face->font); + // If we can't find a glyph then try to fallback to a question mark. + unsigned int fallbackCodepoint = msGetGlyphIndex(face, 0x3F); + error = FT_Load_Glyph(face->face, fallbackCodepoint, + FT_LOAD_DEFAULT | FT_LOAD_NO_BITMAP | + FT_LOAD_NO_HINTING | + FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH); + } + if (error) { + msSetError(MS_MISCERR, "unable to load glyph %u for font \"%s\"", + "msGetGlyphByIndex()", key.codepoint, face->font); + free(gc); +#ifdef USE_THREAD + if (use_global_ft_cache) + msReleaseLock(TLOCK_TTF); +#endif + return NULL; + } + gc->metrics.minx = face->face->glyph->metrics.horiBearingX / 64.0; + gc->metrics.maxx = + gc->metrics.minx + face->face->glyph->metrics.width / 64.0; + gc->metrics.maxy = face->face->glyph->metrics.horiBearingY / 64.0; + gc->metrics.miny = + gc->metrics.maxy - face->face->glyph->metrics.height / 64.0; + gc->metrics.advance = face->face->glyph->metrics.horiAdvance / 64.0; + gc->key = key; + UT_HASH_ADD(hh, face->glyph_cache, key, sizeof(glyph_element_key), gc); + } +#ifdef USE_THREAD + if (use_global_ft_cache) + msReleaseLock(TLOCK_TTF); +#endif + return gc; +} + +outline_element *msGetGlyphOutline(face_element *face, glyph_element *glyph) { + outline_element *oc; + outline_element_key key; + ft_cache *cache = msGetFontCache(); + memset(&key, 0, sizeof(outline_element_key)); + key.glyph = glyph; +#ifdef USE_THREAD + if (use_global_ft_cache) + msAcquireLock(TLOCK_TTF); +#endif + UT_HASH_FIND(hh, face->outline_cache, &key, sizeof(outline_element_key), oc); + if (!oc) { + FT_Matrix matrix; + FT_Vector pen; + FT_Error error; + oc = msSmallMalloc(sizeof(outline_element)); + if (MS_NINT(glyph->key.size * 96.0 / 72.0) != + face->face->size->metrics.x_ppem) { + FT_Set_Pixel_Sizes(face->face, 0, MS_NINT(glyph->key.size * 96 / 72.0)); + } + matrix.xx = matrix.yy = 0x10000L; + matrix.xy = matrix.yx = 0x00000L; + pen.x = pen.y = 0; + FT_Set_Transform(face->face, &matrix, &pen); + error = FT_Load_Glyph( + face->face, glyph->key.codepoint, + FT_LOAD_DEFAULT | FT_LOAD_NO_BITMAP /*|FT_LOAD_IGNORE_TRANSFORM*/ | + FT_LOAD_NO_HINTING | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH); + if (error) { + msDebug("Unable to load glyph %u for font \"%s\". Using ? as fallback.\n", + glyph->key.codepoint, face->font); + // If we can't find a glyph then try to fallback to a question mark. + unsigned int fallbackCodepoint = msGetGlyphIndex(face, 0x3F); + error = FT_Load_Glyph( + face->face, fallbackCodepoint, + FT_LOAD_DEFAULT | FT_LOAD_NO_BITMAP /*|FT_LOAD_IGNORE_TRANSFORM*/ | + FT_LOAD_NO_HINTING | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH); + } + if (error) { + msSetError(MS_MISCERR, "unable to load glyph %u for font \"%s\"", + "msGetGlyphOutline()", glyph->key.codepoint, face->font); +#ifdef USE_THREAD + if (use_global_ft_cache) + msReleaseLock(TLOCK_TTF); +#endif + return NULL; + } + error = FT_Outline_New(cache->library, face->face->glyph->outline.n_points, + face->face->glyph->outline.n_contours, &oc->outline); + (void)error; + FT_Outline_Copy(&face->face->glyph->outline, &oc->outline); + oc->key = key; + UT_HASH_ADD(hh, face->outline_cache, key, sizeof(outline_element_key), oc); + } +#ifdef USE_THREAD + if (use_global_ft_cache) + msReleaseLock(TLOCK_TTF); +#endif + return oc; +} + +int msIsGlyphASpace(glyphObj *glyph) { + /* space or tab, for now */ + unsigned int space, tab; + space = msGetGlyphIndex(glyph->face, 0x20); + tab = msGetGlyphIndex(glyph->face, 0x9); + return glyph->glyph->key.codepoint == space || + glyph->glyph->key.codepoint == tab; +} diff --git a/src/fontcache.h b/src/fontcache.h new file mode 100644 index 0000000000..6ca558c899 --- /dev/null +++ b/src/fontcache.h @@ -0,0 +1,87 @@ +#include "mapserver.h" +#include "uthash.h" + +#include +#include FT_FREETYPE_H +#include FT_GLYPH_H +#include FT_OUTLINE_H + +#ifdef USE_FRIBIDI +#if (defined(_WIN32) && !defined(__CYGWIN__)) || defined(HAVE_FRIBIDI2) +#include "fribidi.h" +#else +#include +#endif +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { /* this one can remain private */ + unsigned int unicode; + unsigned int codepoint; + UT_hash_handle hh; +} index_element; + +typedef struct { + void *hbparentfont; + void *hbfont; + void *funcs; + int cursize; +} hb_font_element; + +typedef struct { + unsigned int codepoint; + unsigned int size; +} glyph_element_key; + +struct glyph_element { + glyph_element_key key; + glyph_metrics metrics; + UT_hash_handle hh; +}; + +typedef struct { + glyph_element *glyph; +} outline_element_key; + +typedef struct { + outline_element_key key; + FT_Outline outline; + UT_hash_handle hh; +} outline_element; + +typedef struct { + glyph_element *glyph; +} bitmap_element_key; + +typedef struct { + bitmap_element_key key; + void *bitmap; + UT_hash_handle hh; +} bitmap_element; + +struct face_element { + char *font; + FT_Face face; + index_element *index_cache; + glyph_element *glyph_cache; + outline_element *outline_cache; + hb_font_element *hbfont; + UT_hash_handle hh; +}; + +face_element *msGetFontFace(const char *key, fontSetObj *fontset); +outline_element *msGetGlyphOutline(face_element *face, glyph_element *glyph); +glyph_element *msGetBitmapGlyph(rendererVTableObj *renderer, unsigned int size, + unsigned int unicode); +unsigned int msGetGlyphIndex(face_element *face, unsigned int unicode); +glyph_element *msGetGlyphByIndex(face_element *face, unsigned int size, + unsigned int codepoint); +int msIsGlyphASpace(glyphObj *glyph); + +#ifdef __cplusplus +} +#endif diff --git a/src/generate_cql2text_parser.cmake b/src/generate_cql2text_parser.cmake new file mode 100644 index 0000000000..370704aaf7 --- /dev/null +++ b/src/generate_cql2text_parser.cmake @@ -0,0 +1,12 @@ +message("Generating cql2textparser.cpp") + +if (NOT BISON_FOUND) + message(FATAL_ERROR "Bison not found") +endif() + +execute_process(COMMAND "${BISON_EXECUTABLE}" "--no-lines" "-d" "-p" "cql2text" "-ocql2textparser.cpp" "cql2textparser.y" + RESULT_VARIABLE STATUS) + +if(STATUS AND NOT STATUS EQUAL 0) + message(FATAL_ERROR "bison failed") +endif() diff --git a/src/hittest.c b/src/hittest.c new file mode 100644 index 0000000000..5f4db013c2 --- /dev/null +++ b/src/hittest.c @@ -0,0 +1,317 @@ +/***************************************************************************** + * + * Project: MapServer + * Purpose: Content Dependent Legend rendering support + * Author: Thomas Bonfort (tbonfort@terriscope.fr) + * + ****************************************************************************** + * Copyright (c) 1996-2013 Regents of the University of Minnesota. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + ****************************************************************************/ + +#include "mapserver.h" + +void initStyleHitTests(styleObj *s, style_hittest *sh, int default_status) { + (void)s; + sh->status = default_status; +} + +void initLabelHitTests(labelObj *l, label_hittest *lh, int default_status) { + int i; + lh->stylehits = msSmallCalloc(l->numstyles, sizeof(style_hittest)); + lh->status = default_status; + for (i = 0; i < l->numstyles; i++) { + initStyleHitTests(l->styles[i], &lh->stylehits[i], default_status); + } +} + +void initClassHitTests(classObj *c, class_hittest *ch, int default_status) { + int i; + ch->stylehits = msSmallCalloc(c->numstyles, sizeof(style_hittest)); + ch->labelhits = msSmallCalloc(c->numlabels, sizeof(label_hittest)); + ch->status = default_status; + for (i = 0; i < c->numstyles; i++) { + initStyleHitTests(c->styles[i], &ch->stylehits[i], default_status); + } + for (i = 0; i < c->numlabels; i++) { + initLabelHitTests(c->labels[i], &ch->labelhits[i], default_status); + } +} + +void initLayerHitTests(layerObj *l, layer_hittest *lh) { + int i, default_status; + lh->classhits = msSmallCalloc(l->numclasses, sizeof(class_hittest)); + + switch (l->type) { + case MS_LAYER_POLYGON: + case MS_LAYER_POINT: + case MS_LAYER_LINE: + case MS_LAYER_ANNOTATION: + default_status = 0; /* needs testing */ + break; + default: + default_status = 1; /* no hittesting needed, use traditional mode */ + break; + } + lh->status = default_status; + for (i = 0; i < l->numclasses; i++) { + initClassHitTests(l->class[i], &lh -> classhits[i], default_status); + } +} +void initMapHitTests(mapObj *map, map_hittest *mh) { + int i; + mh->layerhits = msSmallCalloc(map->numlayers, sizeof(layer_hittest)); + for (i = 0; i < map->numlayers; i++) { + initLayerHitTests(GET_LAYER(map, i), &mh->layerhits[i]); + } +} + +void freeLabelHitTests(labelObj *l, label_hittest *lh) { + (void)l; + free(lh->stylehits); +} + +void freeClassHitTests(classObj *c, class_hittest *ch) { + int i; + for (i = 0; i < c->numlabels; i++) { + freeLabelHitTests(c->labels[i], &ch->labelhits[i]); + } + free(ch->stylehits); + free(ch->labelhits); +} +void freeLayerHitTests(layerObj *l, layer_hittest *lh) { + int i; + for (i = 0; i < l->numclasses; i++) { + freeClassHitTests(l->class[i], &lh -> classhits[i]); + } + free(lh->classhits); +} +void freeMapHitTests(mapObj *map, map_hittest *mh) { + int i; + for (i = 0; i < map->numlayers; i++) { + freeLayerHitTests(GET_LAYER(map, i), &mh->layerhits[i]); + } + free(mh->layerhits); +} + +int msHitTestShape(mapObj *map, layerObj *layer, shapeObj *shape, int drawmode, + class_hittest *hittest) { + int i; + classObj *cp = layer->class[shape->classindex]; + if (MS_DRAW_FEATURES(drawmode)) { + for (i = 0; i < cp->numstyles; i++) { + styleObj *sp = cp->styles[i]; + if (msScaleInBounds(map->scaledenom, sp->minscaledenom, + sp->maxscaledenom)) { + hittest->stylehits[i].status = 1; + } + } + } + if (MS_DRAW_LABELS(drawmode)) { + for (i = 0; i < cp->numlabels; i++) { + labelObj *l = cp->labels[i]; + if (msGetLabelStatus(map, layer, shape, l) == MS_ON) { + int s; + hittest->labelhits[i].status = 1; + for (s = 0; s < l->numstyles; s++) { + hittest->labelhits[i].stylehits[s].status = 1; + } + } + } + } + return MS_SUCCESS; +} + +int msHitTestLayer(mapObj *map, layerObj *layer, layer_hittest *hittest) { + int status; +#ifdef USE_GEOS + shapeObj searchpoly; +#endif + if (!msLayerIsVisible(map, layer)) { + hittest->status = 0; + return MS_SUCCESS; + } + if (layer->type == MS_LAYER_LINE || layer->type == MS_LAYER_POLYGON || + layer->type == MS_LAYER_POINT || layer->type == MS_LAYER_ANNOTATION) { + int maxfeatures = msLayerGetMaxFeaturesToDraw(layer, NULL); + int annotate = msEvalContext(map, layer, layer->labelrequires); + shapeObj shape; + int nclasses, featuresdrawn = 0; + int *classgroup; + rectObj searchrect; + int minfeaturesize = -1; + if (map->scaledenom > 0) { + if ((layer->labelmaxscaledenom != -1) && + (map->scaledenom >= layer->labelmaxscaledenom)) + annotate = MS_FALSE; + if ((layer->labelminscaledenom != -1) && + (map->scaledenom < layer->labelminscaledenom)) + annotate = MS_FALSE; + } + + status = msLayerOpen(layer); + if (status != MS_SUCCESS) + return MS_FAILURE; + + /* build item list */ + status = msLayerWhichItems(layer, MS_FALSE, NULL); + + if (status != MS_SUCCESS) { + msLayerClose(layer); + return MS_FAILURE; + } + + /* identify target shapes */ + if (layer->transform == MS_TRUE) { + searchrect = map->extent; + if ((map->projection.numargs > 0) && (layer->projection.numargs > 0)) + msProjectRect( + &map->projection, &layer->projection, + &searchrect); /* project the searchrect to source coords */ + } else { + searchrect.minx = searchrect.miny = 0; + searchrect.maxx = map->width - 1; + searchrect.maxy = map->height - 1; + } +#ifdef USE_GEOS + msInitShape(&searchpoly); + msRectToPolygon(searchrect, &searchpoly); +#endif + + status = msLayerWhichShapes(layer, searchrect, MS_FALSE); + if (status == MS_DONE) { /* no overlap */ +#ifdef USE_GEOS + msFreeShape(&searchpoly); +#endif + msLayerClose(layer); + hittest->status = 0; + return MS_SUCCESS; + } else if (status != MS_SUCCESS) { +#ifdef USE_GEOS + msFreeShape(&searchpoly); +#endif + msLayerClose(layer); + return MS_FAILURE; + } + + /* step through the target shapes */ + msInitShape(&shape); + + nclasses = 0; + classgroup = NULL; + if (layer->classgroup && layer->numclasses > 0) + classgroup = msAllocateValidClassGroups(layer, &nclasses); + + if (layer->minfeaturesize > 0) + minfeaturesize = Pix2LayerGeoref(map, layer, layer->minfeaturesize); + + while ((status = msLayerNextShape(layer, &shape)) == MS_SUCCESS) { + int drawmode = MS_DRAWMODE_FEATURES; +#ifdef USE_GEOS + if (!msGEOSIntersects(&shape, &searchpoly)) { + msFreeShape(&shape); + continue; + } +#else + if (shape.type == MS_SHAPE_POLYGON) { + msClipPolygonRect(&shape, map->extent); + } else { + msClipPolylineRect(&shape, map->extent); + } + if (shape.numlines == 0) { + msFreeShape(&shape); + continue; + } +#endif + /* Check if the shape size is ok to be drawn, we need to clip */ + if ((shape.type == MS_SHAPE_LINE || shape.type == MS_SHAPE_POLYGON) && + (minfeaturesize > 0)) { + msTransformShape(&shape, map->extent, map->cellsize, NULL); + msComputeBounds(&shape); + if (msShapeCheckSize(&shape, minfeaturesize) == MS_FALSE) { + msFreeShape(&shape); + continue; + } + } + + shape.classindex = + msShapeGetClass(layer, map, &shape, classgroup, nclasses); + if ((shape.classindex == -1) || + (layer->class[shape.classindex] -> status == MS_OFF)) { + msFreeShape(&shape); + continue; + } + hittest->classhits[shape.classindex].status = 1; + hittest->status = 1; + + if (maxfeatures >= 0 && featuresdrawn >= maxfeatures) { + msFreeShape(&shape); + status = MS_DONE; + break; + } + featuresdrawn++; + + if (annotate && layer->class[shape.classindex] -> numlabels > 0) { + drawmode |= MS_DRAWMODE_LABELS; + } + + status = msHitTestShape( + map, layer, &shape, drawmode, + &hittest->classhits[shape.classindex]); /* all styles */ + msFreeShape(&shape); + } + +#ifdef USE_GEOS + msFreeShape(&searchpoly); +#endif + + if (classgroup) + msFree(classgroup); + + if (status != MS_DONE) { + msLayerClose(layer); + return MS_FAILURE; + } + msLayerClose(layer); + return MS_SUCCESS; + + } else { + /* we don't hittest these layers, skip as they already have been initialized + */ + return MS_SUCCESS; + } +} +int msHitTestMap(mapObj *map, map_hittest *hittest) { + int i, status; + map->cellsize = msAdjustExtent(&(map->extent), map->width, map->height); + status = msCalculateScale(map->extent, map->units, map->width, map->height, + map->resolution, &map->scaledenom); + if (status != MS_SUCCESS) { + return MS_FAILURE; + } + for (i = 0; i < map->numlayers; i++) { + layerObj *lp = map->layers[i]; + status = msHitTestLayer(map, lp, &hittest->layerhits[i]); + if (status != MS_SUCCESS) { + return MS_FAILURE; + } + } + return MS_SUCCESS; +} diff --git a/hittest.h b/src/hittest.h similarity index 96% rename from hittest.h rename to src/hittest.h index c4ab89c03a..ce49dfd21e 100644 --- a/hittest.h +++ b/src/hittest.h @@ -1,7 +1,7 @@ /***************************************************************************** * * Project: MapServer - * Purpose: Content Dependant Legend rendering support + * Purpose: Content Dependent Legend rendering support * Author: Thomas Bonfort (tbonfort@terriscope.fr) * ****************************************************************************** @@ -26,7 +26,6 @@ * DEALINGS IN THE SOFTWARE. ****************************************************************************/ - #ifndef HITTEST_H #define HITTEST_H @@ -50,7 +49,7 @@ typedef struct { int status; } layer_hittest; -typedef struct map_hittest{ +typedef struct map_hittest { layer_hittest *layerhits; } map_hittest; diff --git a/src/idw.c b/src/idw.c new file mode 100644 index 0000000000..35ae199460 --- /dev/null +++ b/src/idw.c @@ -0,0 +1,82 @@ +/****************************************************************************** + * + * Project: MapServer + * Purpose: Inverse Distance Weighted layer interpolation. + * Author: Hermes L. Herrera Martinez and the MapServer team. + * Thanks: Thomas Bonfort + * + ****************************************************************************** + * Copyright (c) 2014 Regents of the University of Minnesota. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + *****************************************************************************/ + +#include "mapserver.h" +#include +#define EPSILON 0.000000001 +#include + +void msIdw(float *xyz, int width, int height, int npoints, + interpolationProcessingParams *interpParams, + unsigned char *iValues) { + int i, j, index; + int radius = interpParams->radius; + float power = interpParams->power; + for (j = 0; j < height; j++) { + for (i = 0; i < width; i++) { + double den = EPSILON, num = 0; + for (index = 0; index < npoints * 3; index += 3) { + double d = (xyz[index] - i) * (xyz[index] - i) + + (xyz[index + 1] - j) * (xyz[index + 1] - j); + if (radius * radius > d) { + double w = 1.0 / (pow(d, power) + EPSILON); + num += w * xyz[index + 2]; + den += w; + } + } + iValues[j * width + i] = num / den; + } + } +} + +void msIdwProcessing(layerObj *layer, + interpolationProcessingParams *interpParams) { + const char *interpParamsProcessing = + msLayerGetProcessingKey(layer, "IDW_POWER"); + if (interpParamsProcessing) { + interpParams->power = atof(interpParamsProcessing); + } else { + interpParams->power = 1.0; + } + + interpParamsProcessing = msLayerGetProcessingKey(layer, "IDW_RADIUS"); + if (interpParamsProcessing) { + interpParams->radius = atof(interpParamsProcessing); + } else { + interpParams->radius = MS_MAX(layer->map->width, layer->map->height); + } + + interpParamsProcessing = + msLayerGetProcessingKey(layer, "IDW_COMPUTE_BORDERS"); + if (interpParamsProcessing && strcasecmp(interpParamsProcessing, "OFF")) { + interpParams->expand_searchrect = 1; + } else { + interpParams->expand_searchrect = 0; + } +} diff --git a/src/interpolation.c b/src/interpolation.c new file mode 100644 index 0000000000..38647d58d8 --- /dev/null +++ b/src/interpolation.c @@ -0,0 +1,313 @@ +/****************************************************************************** + * + * Project: MapServer + * Purpose: KernelDensity layer implementation and related functions. + * Author: Hermes L. Herrera and the MapServer team. + * + ****************************************************************************** + * Copyright (c) 2014 Regents of the University of Minnesota. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + *****************************************************************************/ + +#include "mapserver.h" +#include + +#include "gdal.h" +#include "cpl_string.h" + +/****************************************************************************** + * kernel density. + ******************************************************************************/ +void msKernelDensity(imageObj *image, float *values, int width, int height, + int npoints, interpolationProcessingParams *interpParams, + unsigned char *iValues); +void msKernelDensityProcessing(layerObj *layer, + interpolationProcessingParams *interpParams); + +/****************************************************************************** + * kernel density. + ******************************************************************************/ +void msIdw(float *xyz, int width, int height, int npoints, + interpolationProcessingParams *interpParams, unsigned char *iValues); +void msIdwProcessing(layerObj *layer, + interpolationProcessingParams *interpParams); + +//---------------------------------------------------------------------------// +int msInterpolationDataset(mapObj *map, imageObj *image, + layerObj *interpolation_layer, void **hDSvoid, + void **cleanup_ptr) { + + int status, layer_idx, i, npoints = 0, length = 0; + rectObj searchrect; + shapeObj shape; + layerObj *layer = NULL; + float *values = NULL, *xyz_values = NULL; + int im_width = image->width, im_height = image->height; + double invcellsize = 1.0 / map->cellsize, georadius = 0; + unsigned char *iValues; + GDALDatasetH hDS; + interpolationProcessingParams interpParams; + + memset(&interpParams, 0, sizeof(interpParams)); + + assert(interpolation_layer->connectiontype == MS_KERNELDENSITY || + interpolation_layer->connectiontype == MS_IDW); + *cleanup_ptr = NULL; + + if (!interpolation_layer->connection || !*interpolation_layer->connection) { + msSetError(MS_MISCERR, "msInterpolationDataset()", + "Interpolation layer has no CONNECTION defined"); + return MS_FAILURE; + } + + if (interpolation_layer->connectiontype == MS_KERNELDENSITY) { + msKernelDensityProcessing(interpolation_layer, &interpParams); + } else if (interpolation_layer->connectiontype == MS_IDW) { + msIdwProcessing(interpolation_layer, &interpParams); + } + + layer_idx = msGetLayerIndex(map, interpolation_layer->connection); + if (layer_idx == -1) { + int nLayers, *aLayers; + aLayers = + msGetLayersIndexByGroup(map, interpolation_layer->connection, &nLayers); + if (!aLayers || !nLayers) { + msSetError(MS_MISCERR, + "Interpolation layer (%s) references unknown layer (%s)", + "msInterpolationDataset()", interpolation_layer->name, + interpolation_layer->connection); + return (MS_FAILURE); + } + for (i = 0; i < nLayers; i++) { + layer_idx = aLayers[i]; + layer = GET_LAYER(map, layer_idx); + if (msScaleInBounds(map->scaledenom, layer->minscaledenom, + layer->maxscaledenom)) + break; + } + free(aLayers); + if (i == nLayers) { + msSetError( + MS_MISCERR, + "Interpolation layer (%s) references no layer for current scale", + "msInterpolationDataset()", interpolation_layer->name); + return (MS_FAILURE); + } + } else { + layer = GET_LAYER(map, layer_idx); + } + /* open the linked layer */ + status = msLayerOpen(layer); + if (status != MS_SUCCESS) + return MS_FAILURE; + + status = msLayerWhichItems(layer, MS_FALSE, NULL); + if (status != MS_SUCCESS) { + msLayerClose(layer); + return MS_FAILURE; + } + + /* identify target shapes */ + if (layer->transform == MS_TRUE) { + searchrect = map->extent; + if (interpParams.expand_searchrect) { + georadius = interpParams.radius * map->cellsize; + searchrect.minx -= georadius; + searchrect.miny -= georadius; + searchrect.maxx += georadius; + searchrect.maxy += georadius; + im_width += 2 * interpParams.radius; + im_height += 2 * interpParams.radius; + } + } else { + searchrect.minx = searchrect.miny = 0; + searchrect.maxx = map->width - 1; + searchrect.maxy = map->height - 1; + } + + layer->project = + msProjectionsDiffer(&(layer->projection), &(map->projection)); + if (layer->project) + msProjectRect(&map->projection, &layer->projection, + &searchrect); /* project the searchrect to source coords */ + + status = msLayerWhichShapes(layer, searchrect, MS_FALSE); + /* nothing to do */ + if (status == MS_SUCCESS) { /* at least one sample may have overlapped */ + + int nclasses = 0; + int *classgroup = NULL; + if (layer->classgroup && layer->numclasses > 0) + classgroup = msAllocateValidClassGroups(layer, &nclasses); + + msInitShape(&shape); + while ((status = msLayerNextShape(layer, &shape)) == MS_SUCCESS) { + int l, p, s, c; + double weight = 1.0; + if (!values) { /* defer allocation until we effectively have a feature */ + values = (float *)msSmallCalloc(((size_t)im_width) * im_height, + sizeof(float)); + xyz_values = (float *)msSmallCalloc(((size_t)im_width) * im_height, + sizeof(float)); + } + if (layer->project) + msProjectShape(&layer->projection, &map->projection, &shape); + + /* the weight for the sample is set to 1.0 by default. If the + * layer has some classes defined, we will read the weight from + * the class->style->size (which can be binded to an attribute) + */ + if (layer->numclasses > 0) { + c = msShapeGetClass(layer, map, &shape, classgroup, nclasses); + if ((c == -1) || (layer->class[c] -> status == MS_OFF)) { + goto nextshape; /* no class matched, skip */ + } + for (s = 0; s < layer->class[c] -> numstyles; s++) { + if (msScaleInBounds( + map->scaledenom, + layer->class[c] -> styles[s] -> minscaledenom, + layer -> class[c] -> styles[s] -> maxscaledenom)) { + if (layer->class[c] -> styles[s] + -> bindings[MS_STYLE_BINDING_SIZE].index != -1) { + weight = + atof(shape.values[layer->class[c] -> styles[s] + -> bindings[MS_STYLE_BINDING_SIZE].index]); + } else { + weight = layer->class[c]->styles[s]->size; + } + break; + } + } + if (s == layer->class[c] -> numstyles) { + /* no style in scale bounds */ + goto nextshape; + } + } + for (l = 0; l < shape.numlines; l++) { + for (p = 0; p < shape.line[l].numpoints; p++) { + int x = + MS_MAP2IMAGE_XCELL_IC(shape.line[l].point[p].x, + map->extent.minx - georadius, invcellsize); + int y = + MS_MAP2IMAGE_YCELL_IC(shape.line[l].point[p].y, + map->extent.maxy + georadius, invcellsize); + if (x >= 0 && y >= 0 && x < im_width && y < im_height) { + float *value = values + y * im_width + x; + (*value) += weight; + xyz_values[length++] = x; + xyz_values[length++] = y; + xyz_values[length++] = (*value); + } + } + } + + nextshape: + msFreeShape(&shape); + } + + msFree(classgroup); + + // number of layer points. + npoints = length / 3; + } else if (status != MS_DONE) { + msLayerClose(layer); + return MS_FAILURE; + } + + /* status == MS_DONE */ + msLayerClose(layer); + status = MS_SUCCESS; + + if (npoints > 0 && interpParams.expand_searchrect) { + iValues = + msSmallMalloc(sizeof(unsigned char) * image->width * image->height); + } else { + iValues = + msSmallCalloc(1, sizeof(unsigned char) * image->width * image->height); + } + + if (npoints > + 0) { /* no use applying the filtering kernel if we have no samples */ + if (interpolation_layer->connectiontype == MS_KERNELDENSITY) { + msKernelDensity(image, values, im_width, im_height, npoints, + &interpParams, iValues); + } else if (interpolation_layer->connectiontype == MS_IDW) { + msIdw(xyz_values, image->width, image->height, npoints, &interpParams, + iValues); + } + } + + free(values); + free(xyz_values); + + GDALDriverH hMemDRV = GDALGetDriverByName("MEM"); + if (!hMemDRV) { + msSetError(MS_IOERR, "GDAL MEM driver not available", + "msInterpolationDataset()"); + free(iValues); + return MS_FAILURE; + } + + hDS = GDALCreate(hMemDRV, "", image->width, image->height, 0, 0, NULL); + if (hDS == NULL) { + msSetError(MS_IMGERR, "Unable to create GDAL Memory dataset.", + "msInterpolationDataset()"); + free(iValues); + return MS_FAILURE; + } + + char pointer[64]; + memset(pointer, 0, sizeof(pointer)); + CPLPrintPointer(pointer, iValues, sizeof(pointer)); + + char **papszOptions = CSLSetNameValue(NULL, "DATAPOINTER", pointer); + CPLErr eErr = GDALAddBand(hDS, GDT_Byte, papszOptions); + CSLDestroy(papszOptions); + if (eErr != CE_None) { + msSetError(MS_IMGERR, "Unable to add band to GDAL Memory dataset.", + "msInterpolationDataset()"); + free(iValues); + GDALClose(hDS); + return MS_FAILURE; + } + + double adfGeoTransform[6]; + adfGeoTransform[0] = map->extent.minx - map->cellsize * 0.5; /* top left x */ + adfGeoTransform[1] = map->cellsize; /* w-e pixel resolution */ + adfGeoTransform[2] = 0; /* 0 */ + adfGeoTransform[3] = map->extent.maxy + map->cellsize * 0.5; /* top left y */ + adfGeoTransform[4] = 0; /* 0 */ + adfGeoTransform[5] = + -map->cellsize; /* n-s pixel resolution (negative value) */ + GDALSetGeoTransform(hDS, adfGeoTransform); + *hDSvoid = hDS; + *cleanup_ptr = (void *)iValues; + + return status; +} + +int msCleanupInterpolationDataset(mapObj *map, imageObj *image, layerObj *layer, + void *cleanup_ptr) { + (void)map; + (void)image; + (void)layer; + free(cleanup_ptr); + return MS_SUCCESS; +} diff --git a/src/kerneldensity.c b/src/kerneldensity.c new file mode 100644 index 0000000000..f63e379c33 --- /dev/null +++ b/src/kerneldensity.c @@ -0,0 +1,169 @@ + +/****************************************************************************** + * + * Project: MapServer + * Purpose: KernelDensity layer implementation and related functions. + * Author: Thomas Bonfort and the MapServer team. + * + ****************************************************************************** + * Copyright (c) 2014 Regents of the University of Minnesota. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + *****************************************************************************/ + +#include "mapserver.h" +#include + +#include "gdal.h" + +static void gaussian_blur(float *values, int width, int height, int radius) { + float *tmp = (float *)msSmallMalloc(sizeof(float) * width * height); + int length = radius * 2 + 1; + float *kernel = (float *)msSmallMalloc(length * sizeof(float)); + float sigma = radius / 3.0; + float a = 1.0 / sqrt(2.0 * M_PI * sigma * sigma); + float den = 2.0 * sigma * sigma; + int i, x, y; + + for (i = 0; i < length; i++) { + float x = i - radius; + float v = a * exp(-(x * x) / den); + kernel[i] = v; + } + memset(tmp, 0, sizeof(float) * width * height); + + for (y = 0; y < height; y++) { + float *src_row = values + width * y; + float *dst_row = tmp + width * y; + + for (x = radius; x < width - radius; x++) { + float accum = 0; + for (i = 0; i < length; i++) { + accum += src_row[x + i - radius] * kernel[i]; + } + dst_row[x] = accum; + } + } + + for (x = 0; x < width; x++) { + float *src_col = tmp + x; + float *dst_col = values + x; + + for (y = radius; y < height - radius; y++) { + float accum = 0; + for (i = 0; i < length; i++) { + accum += src_col[width * (y + i - radius)] * kernel[i]; + } + dst_col[y * width] = accum; + } + } + free(tmp); + free(kernel); +} + +void msKernelDensityProcessing(layerObj *layer, + interpolationProcessingParams *interpParams) { + const char *interpParamsProcessing = + msLayerGetProcessingKey(layer, "KERNELDENSITY_RADIUS"); + if (interpParamsProcessing) { + interpParams->radius = atoi(interpParamsProcessing); + } else { + interpParams->radius = 10; + } + + interpParamsProcessing = + msLayerGetProcessingKey(layer, "KERNELDENSITY_COMPUTE_BORDERS"); + if (interpParamsProcessing && strcasecmp(interpParamsProcessing, "OFF")) { + interpParams->expand_searchrect = 1; + } else { + interpParams->expand_searchrect = 0; + } + + interpParamsProcessing = + msLayerGetProcessingKey(layer, "KERNELDENSITY_NORMALIZATION"); + if (!interpParamsProcessing || !strcasecmp(interpParamsProcessing, "AUTO")) { + interpParams->normalization_scale = 0.0; + } else { + interpParams->normalization_scale = atof(interpParamsProcessing); + if (interpParams->normalization_scale != 0) { + interpParams->normalization_scale = + 1.0 / interpParams->normalization_scale; + } else { + interpParams->normalization_scale = 1.0; + } + } +} + +void msKernelDensity(imageObj *image, float *values, int width, int height, + int npoints, interpolationProcessingParams *interpParams, + unsigned char *iValues) { + int i, j; + float valmax = FLT_MIN, valmin = FLT_MAX; + int radius = interpParams->radius; + float normalization_scale = interpParams->normalization_scale; + int expand_searchrect = interpParams->expand_searchrect; + + gaussian_blur(values, width, height, radius); + + if (normalization_scale == 0.0) { /* auto normalization */ + for (j = radius; j < height - radius; j++) { + for (i = radius; i < width - radius; i++) { + float val = values[j * width + i]; + if (val > 0 && val > valmax) { + valmax = val; + } + if (val > 0 && val < valmin) { + valmin = val; + } + } + } + } else { + valmin = 0; + valmax = normalization_scale; + } + + if (expand_searchrect) { + for (j = 0; j < image->height; j++) { + for (i = 0; i < image->width; i++) { + float norm = + (values[(j + radius) * width + i + radius] - valmin) / valmax; + int v = 255 * norm; + if (v < 0) + v = 0; + else if (v > 255) + v = 255; + iValues[j * image->width + i] = v; + } + } + } else { + if (npoints > 0) { + for (j = radius; j < image->height - radius; j++) { + for (i = radius; i < image->width - radius; i++) { + float norm = (values[j * width + i] - valmin) / valmax; + int v = 255 * norm; + if (v < 0) + v = 0; + else if (v > 255) + v = 255; + iValues[j * image->width + i] = v; + } + } + } + } +} diff --git a/src/layerobject.c b/src/layerobject.c new file mode 100644 index 0000000000..2a0c147acb --- /dev/null +++ b/src/layerobject.c @@ -0,0 +1,197 @@ +/****************************************************************************** + * $Id$ + * + * Project: MapServer + * Purpose: Functions for operating on a layerObj that don't belong in a + * more specific file such as mapfile.c. + * Adapted from mapobject.c. + * Author: Sean Gillies, sgillies@frii.com + * + ****************************************************************************** + * Copyright (c) 2004, Sean Gillies + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + ****************************************************************************/ + +#include "mapserver.h" + +/* =========================================================================== + msInsertClass + + Returns the index at which the class was inserted. + ======================================================================== */ + +int msInsertClass(layerObj *layer, classObj *classobj, int nIndex) { + int i; + + if (!classobj) { + msSetError(MS_CHILDERR, "Cannot insert NULL class", "msInsertClass()"); + return -1; + } + + /* Ensure there is room for a new class */ + if (msGrowLayerClasses(layer) == NULL) { + return -1; + } + /* Catch attempt to insert past end of styles array */ + else if (nIndex >= layer->numclasses) { + msSetError(MS_CHILDERR, "Cannot insert class beyond index %d", + "msInsertClass()", layer->numclasses - 1); + return -1; + } else if (nIndex < 0) { /* Insert at the end by default */ +#ifndef __cplusplus + layer->class[layer->numclasses] = classobj; +#else + layer->_class[layer->numclasses] = classobj; +#endif + /* set parent pointer */ + classobj->layer = layer; + MS_REFCNT_INCR(classobj); + layer->numclasses++; + return layer->numclasses - 1; + } else { + + /* Copy classes existing at the specified nIndex or greater */ + /* to an index one higher */ + +#ifndef __cplusplus + for (i = layer->numclasses - 1; i >= nIndex; i--) + layer->class[i + 1] = layer->class[i]; + layer->class[nIndex] = classobj; +#else + for (i = layer->numclasses - 1; i >= nIndex; i--) + layer->_class[i + 1] = layer->_class[i]; + layer->_class[nIndex] = classobj; +#endif + + /* set parent pointer */ + classobj->layer = layer; + MS_REFCNT_INCR(classobj); + /* increment number of classes and return */ + layer->numclasses++; + return nIndex; + } +} + +/* =========================================================================== + msRemoveClass + + remove the class at an index from a layer, returning a copy + ======================================================================== */ + +classObj *msRemoveClass(layerObj *layer, int nIndex) { + int i; + classObj *classobj; + + if (nIndex < 0 || nIndex >= layer->numclasses) { + msSetError(MS_CHILDERR, "Cannot remove class, invalid index %d", + "removeClass()", nIndex); + return NULL; + } else { +#ifndef __cplusplus + classobj = layer->class[nIndex]; +#else + classobj = layer->_class[nIndex]; +#endif + classobj->layer = NULL; + MS_REFCNT_DECR(classobj); + + /* Iteratively copy the higher index classes down one index */ + for (i = nIndex; i < layer->numclasses - 1; i++) { +#ifndef __cplusplus + layer->class[i] = layer->class[i + 1]; +#else + layer->_class[i] = layer->_class[i + 1]; +#endif + } +#ifndef __cplusplus + layer->class[i] = NULL; +#else + layer->_class[i] = NULL; +#endif + + /* decrement number of layers and return copy of removed layer */ + layer->numclasses--; + return classobj; + } +} + +/** + * Move the class up inside the array of classes. + */ +int msMoveClassUp(layerObj *layer, int nClassIndex) { + classObj *psTmpClass = NULL; + if (layer && nClassIndex < layer->numclasses && nClassIndex > 0) { + psTmpClass = layer->class[nClassIndex]; + + layer->class[nClassIndex] = layer->class[nClassIndex - 1]; + + layer->class[nClassIndex - 1] = psTmpClass; + + return (MS_SUCCESS); + } + msSetError(MS_CHILDERR, "Invalid index: %d", "msMoveClassUp()", nClassIndex); + return (MS_FAILURE); +} + +/** + * Move the class down inside the array of classes. + */ +int msMoveClassDown(layerObj *layer, int nClassIndex) { + classObj *psTmpClass = NULL; + if (layer && nClassIndex < layer->numclasses - 1 && nClassIndex >= 0) { + psTmpClass = layer->class[nClassIndex]; + + layer->class[nClassIndex] = layer->class[nClassIndex + 1]; + + layer->class[nClassIndex + 1] = psTmpClass; + + return (MS_SUCCESS); + } + msSetError(MS_CHILDERR, "Invalid index: %d", "msMoveClassDown()", + nClassIndex); + return (MS_FAILURE); +} + +/** + * Set the extent of a layer. + */ + +int msLayerSetExtent(layerObj *layer, double minx, double miny, double maxx, + double maxy) { + + layer->extent.minx = minx; + layer->extent.miny = miny; + layer->extent.maxx = maxx; + layer->extent.maxy = maxy; + + if (minx == -1.0 && miny == -1.0 && maxx == -1.0 && maxy == -1.0) + return (MS_SUCCESS); + + if (!MS_VALID_EXTENT(layer->extent)) { + msSetError(MS_MISCERR, + "Given layer extent is invalid. minx=%lf, miny=%lf, maxx=%lf, " + "maxy=%lf.", + "msLayerSetExtent()", layer->extent.minx, layer->extent.miny, + layer->extent.maxx, layer->extent.maxy); + return (MS_FAILURE); + } + + return (MS_SUCCESS); +} diff --git a/src/mapagg.cpp b/src/mapagg.cpp new file mode 100644 index 0000000000..21f78d6f79 --- /dev/null +++ b/src/mapagg.cpp @@ -0,0 +1,1455 @@ +/****************************************************************************** + * $Id$ + * + * Project: MapServer + * Purpose: AGG rendering and other AGG related functions. + * Author: Thomas Bonfort and the MapServer team. + * + ****************************************************************************** + * Copyright (c) 1996-2007 Regents of the University of Minnesota. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + *****************************************************************************/ + +#include "mapserver.h" +#include "fontcache.h" +#include "mapagg.h" +#include +#include "renderers/agg/include/agg_color_rgba.h" +#include "renderers/agg/include/agg_pixfmt_rgba.h" +#include "renderers/agg/include/agg_renderer_base.h" +#include "renderers/agg/include/agg_renderer_scanline.h" +#include "renderers/agg/include/agg_math_stroke.h" +#include "renderers/agg/include/agg_scanline_p.h" +#include "renderers/agg/include/agg_scanline_u.h" +#include "renderers/agg/include/agg_rasterizer_scanline_aa.h" +#include "renderers/agg/include/agg_span_pattern_rgba.h" +#include "renderers/agg/include/agg_span_allocator.h" +#include "renderers/agg/include/agg_span_interpolator_linear.h" +#include "renderers/agg/include/agg_pattern_filters_rgba.h" +#include "renderers/agg/include/agg_image_accessors.h" +#include "renderers/agg/include/agg_conv_stroke.h" +#include "renderers/agg/include/agg_conv_dash.h" +#include "renderers/agg/include/agg_font_freetype.h" +#include "renderers/agg/include/agg_conv_contour.h" +#include "renderers/agg/include/agg_ellipse.h" +#include "renderers/agg/include/agg_gamma_functions.h" +#include "renderers/agg/include/agg_blur.h" + +#include "renderers/agg/include/agg_rasterizer_outline_aa.h" +#include "renderers/agg/include/agg_renderer_outline_aa.h" +#include "renderers/agg/include/agg_renderer_outline_image.h" +#include "renderers/agg/include/agg_span_pattern_rgba.h" +#include "renderers/agg/include/agg_span_image_filter_rgba.h" +#include "renderers/agg/include/agg_glyph_raster_bin.h" +#include "renderers/agg/include/agg_renderer_raster_text.h" +#include "renderers/agg/include/agg_path_storage_integer.h" + +#include "renderers/agg/include/agg_conv_clipper.h" + +#include "cpl_conv.h" // CPLGetConfigOption +#include "cpl_string.h" // CPLTestBool + +#ifdef USE_PIXMAN +#include +#endif + +#include +#include +#include +#include + +typedef mapserver::order_bgra band_order; + +#define AGG_LINESPACE 1.33 + +typedef mapserver::int8u band_type; +typedef mapserver::rgba8 color_type; +typedef mapserver::pixel32_type pixel_type; + +typedef mapserver::blender_rgba_pre blender_pre; +typedef mapserver::comp_op_adaptor_rgba_pre + compop_blender_pre; + +typedef mapserver::pixfmt_alpha_blend_rgba< + blender_pre, mapserver::rendering_buffer, pixel_type> + pixel_format; +typedef mapserver::pixfmt_custom_blend_rgba + compop_pixel_format; +typedef mapserver::rendering_buffer rendering_buffer; +typedef mapserver::renderer_base renderer_base; +typedef mapserver::renderer_base compop_renderer_base; +typedef mapserver::renderer_scanline_aa_solid renderer_scanline; +typedef mapserver::renderer_scanline_bin_solid + renderer_scanline_aliased; +typedef mapserver::rasterizer_scanline_aa<> rasterizer_scanline; +typedef mapserver::font_engine_freetype_int16 font_engine_type; +typedef mapserver::font_cache_manager font_manager_type; +typedef mapserver::conv_curve + font_curve_type; +typedef mapserver::glyph_raster_bin glyph_gen; + +static const color_type AGG_NO_COLOR = color_type(0, 0, 0, 0); + +#define aggColor(c) \ + mapserver::rgba8_pre((c)->red, (c)->green, (c)->blue, (c)->alpha) + +class aggRendererCache { +public: + font_engine_type m_feng; + font_manager_type m_fman; + aggRendererCache() : m_fman(m_feng) {} +}; + +class AGG2Renderer { +public: + std::vector buffer{}; + rendering_buffer m_rendering_buffer; + pixel_format m_pixel_format; + compop_pixel_format m_compop_pixel_format; + renderer_base m_renderer_base; + compop_renderer_base m_compop_renderer_base; + renderer_scanline m_renderer_scanline; + renderer_scanline_aliased m_renderer_scanline_aliased; + rasterizer_scanline m_rasterizer_aa; + rasterizer_scanline m_rasterizer_aa_gamma; + mapserver::scanline_p8 sl_poly; /*packed scanlines, works faster when the area + is larger than the perimeter, in number of pixels*/ + mapserver::scanline_u8 sl_line; /*unpacked scanlines, works faster if the area + is roughly equal to the perimeter, in number of pixels*/ + bool use_alpha = false; + std::unique_ptr> stroke{}; + std::unique_ptr> dash{}; + std::unique_ptr>> + stroke_dash{}; + double default_gamma = 0.0; + mapserver::gamma_linear gamma_function; +}; + +#define AGG_RENDERER(image) ((AGG2Renderer *)(image)->img.plugin) + +template +static void applyCJC(VertexSource &stroke, int caps, int joins) { + switch (joins) { + case MS_CJC_ROUND: + stroke.line_join(mapserver::round_join); + break; + case MS_CJC_MITER: + stroke.line_join(mapserver::miter_join); + break; + case MS_CJC_BEVEL: + case MS_CJC_NONE: + stroke.line_join(mapserver::bevel_join); + break; + } + switch (caps) { + case MS_CJC_BUTT: + case MS_CJC_NONE: + stroke.line_cap(mapserver::butt_cap); + break; + case MS_CJC_ROUND: + stroke.line_cap(mapserver::round_cap); + break; + case MS_CJC_SQUARE: + stroke.line_cap(mapserver::square_cap); + break; + } +} + +int agg2RenderLine(imageObj *img, shapeObj *p, strokeStyleObj *style) { + + AGG2Renderer *r = AGG_RENDERER(img); + line_adaptor lines = line_adaptor(p); + + r->m_rasterizer_aa.reset(); + r->m_rasterizer_aa.filling_rule(mapserver::fill_non_zero); + if (style->antialiased == MS_FALSE) { + r->m_renderer_scanline_aliased.color(aggColor(style->color)); + } else { + r->m_renderer_scanline.color(aggColor(style->color)); + } + + if (style->patternlength <= 0) { + if (!r->stroke) { + r->stroke.reset(new mapserver::conv_stroke(lines)); + } else { + r->stroke->attach(lines); + } + r->stroke->width(style->width); + if (style->width > 1) { + applyCJC(*r->stroke, style->linecap, style->linejoin); + } else { + r->stroke->inner_join(mapserver::inner_bevel); + r->stroke->line_join(mapserver::bevel_join); + } + r->m_rasterizer_aa.add_path(*r->stroke); + } else { + if (!r->dash) { + r->dash.reset(new mapserver::conv_dash(lines)); + } else { + r->dash->remove_all_dashes(); + r->dash->dash_start(0.0); + r->dash->attach(lines); + } + if (!r->stroke_dash) { + r->stroke_dash.reset( + new mapserver::conv_stroke>( + *r->dash)); + } else { + r->stroke_dash->attach(*r->dash); + } + int patt_length = 0; + for (int i = 0; i < style->patternlength; i += 2) { + if (i < style->patternlength - 1) { + r->dash->add_dash(MS_MAX(1, MS_NINT(style->pattern[i])), + MS_MAX(1, MS_NINT(style->pattern[i + 1]))); + if (style->patternoffset) { + patt_length += MS_MAX(1, MS_NINT(style->pattern[i])) + + MS_MAX(1, MS_NINT(style->pattern[i + 1])); + } + } + } + if (style->patternoffset > 0) { + r->dash->dash_start(patt_length - style->patternoffset); + } + r->stroke_dash->width(style->width); + if (style->width > 1) { + applyCJC(*r->stroke_dash, style->linecap, style->linejoin); + } else { + r->stroke_dash->inner_join(mapserver::inner_bevel); + r->stroke_dash->line_join(mapserver::bevel_join); + } + r->m_rasterizer_aa.add_path(*r->stroke_dash); + } + if (style->antialiased == MS_FALSE) + mapserver::render_scanlines(r->m_rasterizer_aa, r->sl_line, + r->m_renderer_scanline_aliased); + else + mapserver::render_scanlines(r->m_rasterizer_aa, r->sl_line, + r->m_renderer_scanline); + return MS_SUCCESS; +} + +int agg2RenderLineTiled(imageObj *img, shapeObj *p, imageObj *tile) { + + mapserver::pattern_filter_bilinear_rgba8 fltr; + typedef mapserver::line_image_pattern< + mapserver::pattern_filter_bilinear_rgba8> + pattern_type; + typedef mapserver::renderer_outline_image + renderer_img_type; + typedef mapserver::rasterizer_outline_aa + rasterizer_img_type; + pattern_type patt(fltr); + + AGG2Renderer *r = AGG_RENDERER(img); + AGG2Renderer *tileRenderer = AGG_RENDERER(tile); + + line_adaptor lines(p); + + patt.create(tileRenderer->m_pixel_format); + renderer_img_type ren_img(r->m_renderer_base, patt); + rasterizer_img_type ras_img(ren_img); + ras_img.add_path(lines); + return MS_SUCCESS; +} + +int agg2RenderPolygon(imageObj *img, shapeObj *p, colorObj *color) { + AGG2Renderer *r = AGG_RENDERER(img); + polygon_adaptor polygons(p); + r->m_rasterizer_aa_gamma.reset(); + r->m_rasterizer_aa_gamma.filling_rule(mapserver::fill_even_odd); + r->m_rasterizer_aa_gamma.add_path(polygons); + r->m_renderer_scanline.color(aggColor(color)); + mapserver::render_scanlines(r->m_rasterizer_aa_gamma, r->sl_poly, + r->m_renderer_scanline); + return MS_SUCCESS; +} + +static inline double int26p6_to_dbl(int p) { return double(p) / 64.0; } + +template +bool decompose_ft_outline(const FT_Outline &outline, bool flip_y, + const mapserver::trans_affine &mtx, + PathStorage &path) { + double x1, y1, x2, y2, x3, y3; + + FT_Vector *point; + FT_Vector *limit; + + unsigned n; // index of contour in outline + unsigned first; // index of first point in contour + char tag; // current point's state + + first = 0; + + for (n = 0; n < (unsigned)outline.n_contours; n++) { + int last; // index of last point in contour + + last = outline.contours[n]; + limit = outline.points + last; + + FT_Vector v_start = outline.points[first]; + + FT_Vector v_control = v_start; + + point = outline.points + first; + auto tags = outline.tags + first; + tag = FT_CURVE_TAG(tags[0]); + + // A contour cannot start with a cubic control point! + if (tag == FT_CURVE_TAG_CUBIC) + return false; + + // check first point to determine origin + if (tag == FT_CURVE_TAG_CONIC) { + const FT_Vector v_last = outline.points[last]; + + // first point is conic control. Yes, this happens. + if (FT_CURVE_TAG(outline.tags[last]) == FT_CURVE_TAG_ON) { + // start at last point if it is on the curve + v_start = v_last; + limit--; + } else { + // if both first and last points are conic, + // start at their middle and record its position + // for closure + v_start.x = (v_start.x + v_last.x) / 2; + v_start.y = (v_start.y + v_last.y) / 2; + } + point--; + tags--; + } + + x1 = int26p6_to_dbl(v_start.x); + y1 = int26p6_to_dbl(v_start.y); + if (flip_y) + y1 = -y1; + mtx.transform(&x1, &y1); + path.move_to(x1, y1); + + while (point < limit) { + point++; + tags++; + + tag = FT_CURVE_TAG(tags[0]); + switch (tag) { + case FT_CURVE_TAG_ON: // emit a single line_to + { + x1 = int26p6_to_dbl(point->x); + y1 = int26p6_to_dbl(point->y); + if (flip_y) + y1 = -y1; + mtx.transform(&x1, &y1); + path.line_to(x1, y1); + // path.line_to(conv(point->x), flip_y ? -conv(point->y) : + // conv(point->y)); + continue; + } + + case FT_CURVE_TAG_CONIC: // consume conic arcs + { + v_control.x = point->x; + v_control.y = point->y; + + Do_Conic: + if (point < limit) { + FT_Vector vec; + FT_Vector v_middle; + + point++; + tags++; + tag = FT_CURVE_TAG(tags[0]); + + vec.x = point->x; + vec.y = point->y; + + if (tag == FT_CURVE_TAG_ON) { + x1 = int26p6_to_dbl(v_control.x); + y1 = int26p6_to_dbl(v_control.y); + x2 = int26p6_to_dbl(vec.x); + y2 = int26p6_to_dbl(vec.y); + if (flip_y) { + y1 = -y1; + y2 = -y2; + } + mtx.transform(&x1, &y1); + mtx.transform(&x2, &y2); + path.curve3(x1, y1, x2, y2); + continue; + } + + if (tag != FT_CURVE_TAG_CONIC) + return false; + + v_middle.x = (v_control.x + vec.x) / 2; + v_middle.y = (v_control.y + vec.y) / 2; + + x1 = int26p6_to_dbl(v_control.x); + y1 = int26p6_to_dbl(v_control.y); + x2 = int26p6_to_dbl(v_middle.x); + y2 = int26p6_to_dbl(v_middle.y); + if (flip_y) { + y1 = -y1; + y2 = -y2; + } + mtx.transform(&x1, &y1); + mtx.transform(&x2, &y2); + path.curve3(x1, y1, x2, y2); + + // path.curve3(conv(v_control.x), + // flip_y ? -conv(v_control.y) : conv(v_control.y), + // conv(v_middle.x), + // flip_y ? -conv(v_middle.y) : conv(v_middle.y)); + + v_control = vec; + goto Do_Conic; + } + + x1 = int26p6_to_dbl(v_control.x); + y1 = int26p6_to_dbl(v_control.y); + x2 = int26p6_to_dbl(v_start.x); + y2 = int26p6_to_dbl(v_start.y); + if (flip_y) { + y1 = -y1; + y2 = -y2; + } + mtx.transform(&x1, &y1); + mtx.transform(&x2, &y2); + path.curve3(x1, y1, x2, y2); + + // path.curve3(conv(v_control.x), + // flip_y ? -conv(v_control.y) : conv(v_control.y), + // conv(v_start.x), + // flip_y ? -conv(v_start.y) : conv(v_start.y)); + goto Close; + } + + default: // FT_CURVE_TAG_CUBIC + { + FT_Vector vec1, vec2; + + if (point + 1 > limit || FT_CURVE_TAG(tags[1]) != FT_CURVE_TAG_CUBIC) { + return false; + } + + vec1.x = point[0].x; + vec1.y = point[0].y; + vec2.x = point[1].x; + vec2.y = point[1].y; + + point += 2; + tags += 2; + + if (point <= limit) { + FT_Vector vec; + + vec.x = point->x; + vec.y = point->y; + + x1 = int26p6_to_dbl(vec1.x); + y1 = int26p6_to_dbl(vec1.y); + x2 = int26p6_to_dbl(vec2.x); + y2 = int26p6_to_dbl(vec2.y); + x3 = int26p6_to_dbl(vec.x); + y3 = int26p6_to_dbl(vec.y); + if (flip_y) { + y1 = -y1; + y2 = -y2; + y3 = -y3; + } + mtx.transform(&x1, &y1); + mtx.transform(&x2, &y2); + mtx.transform(&x3, &y3); + path.curve4(x1, y1, x2, y2, x3, y3); + + // path.curve4(conv(vec1.x), + // flip_y ? -conv(vec1.y) : conv(vec1.y), + // conv(vec2.x), + // flip_y ? -conv(vec2.y) : conv(vec2.y), + // conv(vec.x), + // flip_y ? -conv(vec.y) : conv(vec.y)); + continue; + } + + x1 = int26p6_to_dbl(vec1.x); + y1 = int26p6_to_dbl(vec1.y); + x2 = int26p6_to_dbl(vec2.x); + y2 = int26p6_to_dbl(vec2.y); + x3 = int26p6_to_dbl(v_start.x); + y3 = int26p6_to_dbl(v_start.y); + if (flip_y) { + y1 = -y1; + y2 = -y2; + y3 = -y3; + } + mtx.transform(&x1, &y1); + mtx.transform(&x2, &y2); + mtx.transform(&x3, &y3); + path.curve4(x1, y1, x2, y2, x3, y3); + + // path.curve4(conv(vec1.x), + // flip_y ? -conv(vec1.y) : conv(vec1.y), + // conv(vec2.x), + // flip_y ? -conv(vec2.y) : conv(vec2.y), + // conv(v_start.x), + // flip_y ? -conv(v_start.y) : conv(v_start.y)); + goto Close; + } + } + } + + path.close_polygon(); + + Close: + first = last + 1; + } + + return true; +} + +int agg2RenderPolygonTiled(imageObj *img, shapeObj *p, imageObj *tile) { + assert(img->format->renderer == tile->format->renderer); + + AGG2Renderer *r = AGG_RENDERER(img); + AGG2Renderer *tileRenderer = AGG_RENDERER(tile); + polygon_adaptor polygons(p); + typedef mapserver::wrap_mode_repeat wrap_type; + typedef mapserver::image_accessor_wrap + img_source_type; + typedef mapserver::span_pattern_rgba span_gen_type; + mapserver::span_allocator sa; + r->m_rasterizer_aa.reset(); + r->m_rasterizer_aa.filling_rule(mapserver::fill_even_odd); + img_source_type img_src(tileRenderer->m_pixel_format); + span_gen_type sg(img_src, 0, 0); + r->m_rasterizer_aa.add_path(polygons); + mapserver::render_scanlines_aa(r->m_rasterizer_aa, r->sl_poly, + r->m_renderer_base, sa, sg); + return MS_SUCCESS; +} + +int agg2RenderGlyphsPath(imageObj *img, const textSymbolObj *ts, colorObj *c, + colorObj *oc, int ow, int /*isMarker*/) { + + const textPathObj *tp = ts->textpath; + mapserver::path_storage glyphs; + mapserver::trans_affine trans; + AGG2Renderer *r = AGG_RENDERER(img); + r->m_rasterizer_aa.filling_rule(mapserver::fill_non_zero); + for (int i = 0; i < tp->numglyphs; i++) { + glyphObj *gl = tp->glyphs + i; + trans.reset(); + trans.rotate(-gl->rot); + trans.translate(gl->pnt.x, gl->pnt.y); + outline_element *ol = msGetGlyphOutline(gl->face, gl->glyph); + if (!ol) { + return MS_FAILURE; + } + decompose_ft_outline(ol->outline, true, trans, glyphs); + } + mapserver::conv_curve m_curves(glyphs); + if (oc) { + r->m_rasterizer_aa.reset(); + r->m_rasterizer_aa.filling_rule(mapserver::fill_non_zero); + mapserver::conv_contour> cc( + m_curves); + cc.width(ow + 1); + r->m_rasterizer_aa.add_path(cc); + r->m_renderer_scanline.color(aggColor(oc)); + mapserver::render_scanlines(r->m_rasterizer_aa, r->sl_line, + r->m_renderer_scanline); + } + if (c) { + r->m_rasterizer_aa.reset(); + r->m_rasterizer_aa.filling_rule(mapserver::fill_non_zero); + r->m_rasterizer_aa.add_path(m_curves); + r->m_renderer_scanline.color(aggColor(c)); + mapserver::render_scanlines(r->m_rasterizer_aa, r->sl_line, + r->m_renderer_scanline); + } + return MS_SUCCESS; +} + +mapserver::path_storage imageVectorSymbol(symbolObj *symbol) { + mapserver::path_storage path; + int is_new = 1; + + for (int i = 0; i < symbol->numpoints; i++) { + if ((symbol->points[i].x == -99) && (symbol->points[i].y == -99)) + is_new = 1; + + else { + if (is_new) { + path.move_to(symbol->points[i].x, symbol->points[i].y); + is_new = 0; + } else { + path.line_to(symbol->points[i].x, symbol->points[i].y); + } + } + } + return path; +} + +int agg2RenderVectorSymbol(imageObj *img, double x, double y, symbolObj *symbol, + symbolStyleObj *style) { + AGG2Renderer *r = AGG_RENDERER(img); + double ox = symbol->sizex * 0.5; + double oy = symbol->sizey * 0.5; + + mapserver::path_storage path = imageVectorSymbol(symbol); + mapserver::trans_affine mtx; + mtx *= mapserver::trans_affine_translation(-ox, -oy); + mtx *= mapserver::trans_affine_scaling(style->scale); + mtx *= mapserver::trans_affine_rotation(-style->rotation); + mtx *= mapserver::trans_affine_translation(x, y); + path.transform(mtx); + if (style->color) { + r->m_rasterizer_aa.reset(); + r->m_rasterizer_aa.filling_rule(mapserver::fill_even_odd); + r->m_rasterizer_aa.add_path(path); + r->m_renderer_scanline.color(aggColor(style->color)); + mapserver::render_scanlines(r->m_rasterizer_aa, r->sl_poly, + r->m_renderer_scanline); + } + if (style->outlinecolor) { + r->m_rasterizer_aa.reset(); + r->m_rasterizer_aa.filling_rule(mapserver::fill_non_zero); + r->m_renderer_scanline.color(aggColor(style->outlinecolor)); + mapserver::conv_stroke stroke(path); + stroke.width(style->outlinewidth); + r->m_rasterizer_aa.add_path(stroke); + mapserver::render_scanlines(r->m_rasterizer_aa, r->sl_poly, + r->m_renderer_scanline); + } + return MS_SUCCESS; +} + +int agg2RenderPixmapSymbol(imageObj *img, double x, double y, symbolObj *symbol, + symbolStyleObj *style) { + AGG2Renderer *r = AGG_RENDERER(img); + rasterBufferObj *pixmap = symbol->pixmap_buffer; + assert(pixmap->type == MS_BUFFER_BYTE_RGBA); + rendering_buffer b(pixmap->data.rgba.pixels, pixmap->width, pixmap->height, + pixmap->data.rgba.row_step); + pixel_format pf(b); + + r->m_rasterizer_aa.reset(); + r->m_rasterizer_aa.filling_rule(mapserver::fill_non_zero); + if ((style->rotation != 0 && style->rotation != MS_PI * 2.) || + style->scale != 1) { + mapserver::trans_affine image_mtx; + image_mtx *= mapserver::trans_affine_translation(-(pf.width() / 2.), + -(pf.height() / 2.)); + /*agg angles are antitrigonometric*/ + image_mtx *= mapserver::trans_affine_rotation(-style->rotation); + image_mtx *= mapserver::trans_affine_scaling(style->scale); + + image_mtx *= mapserver::trans_affine_translation(x, y); + image_mtx.invert(); + typedef mapserver::span_interpolator_linear<> interpolator_type; + interpolator_type interpolator(image_mtx); + mapserver::span_allocator sa; + + // "hardcoded" bilinear filter + //------------------------------------------ + typedef mapserver::span_image_filter_rgba_bilinear_clip + span_gen_type; + span_gen_type sg(pf, mapserver::rgba(0, 0, 0, 0), interpolator); + mapserver::path_storage pixmap_bbox; + int ims_2 = + MS_NINT(MS_MAX(pixmap->width, pixmap->height) * style->scale * 1.415) / + 2 + + 1; + + pixmap_bbox.move_to(x - ims_2, y - ims_2); + pixmap_bbox.line_to(x + ims_2, y - ims_2); + pixmap_bbox.line_to(x + ims_2, y + ims_2); + pixmap_bbox.line_to(x - ims_2, y + ims_2); + + r->m_rasterizer_aa.add_path(pixmap_bbox); + mapserver::render_scanlines_aa(r->m_rasterizer_aa, r->sl_poly, + r->m_renderer_base, sa, sg); + } else { + // just copy the image at the correct location (we place the pixmap on + // the nearest integer pixel to avoid blurring) + unsigned alpha = mapserver::cover_full; + if (style && style->color) { + alpha = style->color->alpha; + } + r->m_renderer_base.blend_from(pf, 0, MS_NINT(x - pixmap->width / 2.), + MS_NINT(y - pixmap->height / 2.), alpha); + } + return MS_SUCCESS; +} + +int agg2RenderEllipseSymbol(imageObj *image, double x, double y, + symbolObj *symbol, symbolStyleObj *style) { + AGG2Renderer *r = AGG_RENDERER(image); + mapserver::path_storage path; + mapserver::ellipse ellipse(x, y, symbol->sizex * style->scale / 2, + symbol->sizey * style->scale / 2); + path.concat_path(ellipse); + if (style->rotation != 0) { + mapserver::trans_affine mtx; + mtx *= mapserver::trans_affine_translation(-x, -y); + /*agg angles are antitrigonometric*/ + mtx *= mapserver::trans_affine_rotation(-style->rotation); + mtx *= mapserver::trans_affine_translation(x, y); + path.transform(mtx); + } + + if (style->color) { + r->m_rasterizer_aa.reset(); + r->m_rasterizer_aa.filling_rule(mapserver::fill_even_odd); + r->m_rasterizer_aa.add_path(path); + r->m_renderer_scanline.color(aggColor(style->color)); + mapserver::render_scanlines(r->m_rasterizer_aa, r->sl_line, + r->m_renderer_scanline); + } + if (style->outlinewidth) { + r->m_rasterizer_aa.reset(); + r->m_rasterizer_aa.filling_rule(mapserver::fill_non_zero); + mapserver::conv_stroke stroke(path); + stroke.width(style->outlinewidth); + r->m_rasterizer_aa.add_path(stroke); + r->m_renderer_scanline.color(aggColor(style->outlinecolor)); + mapserver::render_scanlines(r->m_rasterizer_aa, r->sl_poly, + r->m_renderer_scanline); + } + return MS_SUCCESS; +} + +int agg2RenderTile(imageObj * /*img*/, imageObj * /*tile*/, double /*x*/, + double /*y*/) { + /* + AGG2Renderer *imgRenderer = agg2GetRenderer(img); + AGG2Renderer *tileRenderer = agg2GetRenderer(tile); + */ + return MS_FAILURE; +} + +int aggInitializeRasterBuffer(rasterBufferObj *rb, int width, int height, + int mode) { + rb->type = MS_BUFFER_BYTE_RGBA; + rb->data.rgba.pixel_step = 4; + rb->data.rgba.row_step = rb->data.rgba.pixel_step * width; + rb->width = width; + rb->height = height; + int nBytes = rb->data.rgba.row_step * height; + rb->data.rgba.pixels = (band_type *)msSmallCalloc(nBytes, sizeof(band_type)); + rb->data.rgba.r = &(rb->data.rgba.pixels[band_order::R]); + rb->data.rgba.g = &(rb->data.rgba.pixels[band_order::G]); + rb->data.rgba.b = &(rb->data.rgba.pixels[band_order::B]); + if (mode == MS_IMAGEMODE_RGBA) { + rb->data.rgba.a = &(rb->data.rgba.pixels[band_order::A]); + } + return MS_SUCCESS; +} + +int aggGetRasterBufferHandle(imageObj *img, rasterBufferObj *rb) { + AGG2Renderer *r = AGG_RENDERER(img); + rb->type = MS_BUFFER_BYTE_RGBA; + rb->data.rgba.pixels = r->buffer.data(); + rb->data.rgba.row_step = r->m_rendering_buffer.stride(); + rb->data.rgba.pixel_step = 4; + rb->width = r->m_rendering_buffer.width(); + rb->height = r->m_rendering_buffer.height(); + rb->data.rgba.r = &(r->buffer[band_order::R]); + rb->data.rgba.g = &(r->buffer[band_order::G]); + rb->data.rgba.b = &(r->buffer[band_order::B]); + if (r->use_alpha) + rb->data.rgba.a = &(r->buffer[band_order::A]); + else + rb->data.rgba.a = NULL; + return MS_SUCCESS; +} + +int aggGetRasterBufferCopy(imageObj *img, rasterBufferObj *rb) { + AGG2Renderer *r = AGG_RENDERER(img); + aggInitializeRasterBuffer(rb, img->width, img->height, MS_IMAGEMODE_RGBA); + int nBytes = r->m_rendering_buffer.stride() * r->m_rendering_buffer.height(); + memcpy(rb->data.rgba.pixels, r->buffer.data(), nBytes); + return MS_SUCCESS; +} + +int agg2MergeRasterBuffer(imageObj *dest, rasterBufferObj *overlay, + double opacity, int srcX, int srcY, int dstX, + int dstY, int width, int height) { + assert(overlay->type == MS_BUFFER_BYTE_RGBA); + rendering_buffer b(overlay->data.rgba.pixels, overlay->width, overlay->height, + overlay->data.rgba.row_step); + pixel_format pf(b); + AGG2Renderer *r = AGG_RENDERER(dest); + mapserver::rect_base src_rect(srcX, srcY, srcX + width, srcY + height); + r->m_renderer_base.blend_from(pf, &src_rect, dstX - srcX, dstY - srcY, + unsigned(opacity * 255)); + return MS_SUCCESS; +} + +/* image i/o */ +imageObj *agg2CreateImage(int width, int height, outputFormatObj *format, + colorObj *bg) { + imageObj *image = NULL; + if (format->imagemode != MS_IMAGEMODE_RGB && + format->imagemode != MS_IMAGEMODE_RGBA) { + msSetError(MS_MISCERR, + "AGG2 driver only supports RGB or RGBA pixel models.", + "agg2CreateImage()"); + return image; + } + if (width > 0 && height > 0) { + image = (imageObj *)calloc(1, sizeof(imageObj)); + MS_CHECK_ALLOC(image, sizeof(imageObj), NULL); + AGG2Renderer *r = new AGG2Renderer(); + + /* Compute size on 64bit and check that it is compatible of the platform + * size_t */ + const AGG_INT64U bufSize64 = + (AGG_INT64U)width * height * 4 * sizeof(band_type); + if (bufSize64 > std::numeric_limits::max() / 2) { + msSetError(MS_MEMERR, + "%s: %d: Out of memory allocating " AGG_INT64U_FRMT + " bytes.\n", + "agg2CreateImage()", __FILE__, __LINE__, bufSize64); + free(image); + delete r; + return NULL; + } + + const size_t bufSize = (size_t)bufSize64; + try { + r->buffer.resize(bufSize / sizeof(band_type)); + } catch (const std::bad_alloc &) { + msSetError(MS_MEMERR, + "%s: %d: Out of memory allocating " AGG_INT64U_FRMT + " bytes.\n", + "agg2CreateImage()", __FILE__, __LINE__, bufSize64); + free(image); + delete r; + return NULL; + } + r->m_rendering_buffer.attach(r->buffer.data(), width, height, width * 4); + r->m_pixel_format.attach(r->m_rendering_buffer); + r->m_compop_pixel_format.attach(r->m_rendering_buffer); + r->m_renderer_base.attach(r->m_pixel_format); + r->m_compop_renderer_base.attach(r->m_compop_pixel_format); + r->m_renderer_scanline.attach(r->m_renderer_base); + r->m_renderer_scanline_aliased.attach(r->m_renderer_base); + r->default_gamma = atof(msGetOutputFormatOption(format, "GAMMA", "0.75")); + if (r->default_gamma <= 0.0 || r->default_gamma >= 1.0) { + r->default_gamma = 0.75; + } + r->gamma_function.set(0, r->default_gamma); + r->m_rasterizer_aa_gamma.gamma(r->gamma_function); + if (bg && !format->transparent) + r->m_renderer_base.clear(aggColor(bg)); + else + r->m_renderer_base.clear(AGG_NO_COLOR); + + if (!bg || format->transparent || format->imagemode == MS_IMAGEMODE_RGBA) { + r->use_alpha = true; + } else { + r->use_alpha = false; + } + image->img.plugin = (void *)r; + } else { + msSetError(MS_RENDERERERR, "Cannot create cairo image of size %dx%d.", + "msImageCreateCairo()", width, height); + } + + return image; +} + +int agg2SaveImage(imageObj * /*img*/, mapObj * /*map*/, FILE * /*fp*/, + outputFormatObj * /*format*/) { + + return MS_FAILURE; +} + +int agg2StartNewLayer(imageObj *img, mapObj * /*map*/, layerObj *layer) { + AGG2Renderer *r = AGG_RENDERER(img); + const char *sgamma = msLayerGetProcessingKey(layer, "GAMMA"); + double gamma; + if (sgamma) { + gamma = atof(sgamma); + if (gamma <= 0 || gamma >= 1) + gamma = 0.75; + } else { + gamma = r->default_gamma; + } + if (r->gamma_function.end() != gamma) { + r->gamma_function.end(gamma); + r->m_rasterizer_aa_gamma.gamma(r->gamma_function); + } + return MS_SUCCESS; +} + +int agg2CloseNewLayer(imageObj * /*img*/, mapObj * /*map*/, + layerObj * /*layer*/) { + return MS_SUCCESS; +} + +int agg2FreeImage(imageObj *image) { + AGG2Renderer *r = AGG_RENDERER(image); + delete r; + image->img.plugin = NULL; + return MS_SUCCESS; +} + +int agg2FreeSymbol(symbolObj * /*symbol*/) { return MS_SUCCESS; } + +int agg2InitCache(void **vcache) { + aggRendererCache *cache = new aggRendererCache(); + *vcache = (void *)cache; + return MS_SUCCESS; +} + +int agg2Cleanup(void *vcache) { + aggRendererCache *cache = (aggRendererCache *)vcache; + delete cache; + return MS_SUCCESS; +} + +// ------------------------------------------------------------------------ +// Function to create a custom hatch symbol based on an arbitrary angle. +// ------------------------------------------------------------------------ +static mapserver::path_storage createHatch(double ox, double oy, double rx, + double ry, int sx, int sy, + double angle, double step) { + mapserver::path_storage path; + // restrict the angle to [0 180[, i.e ]-pi/2,pi/2] in radians + angle = fmod(angle, 360.0); + if (angle < 0) + angle += 360; + if (angle >= 180) + angle -= 180; + + // treat 2 easy cases which would cause divide by 0 in generic case + if (angle == 0) { + double y0 = step - fmod(oy - ry, step); + if ((oy - ry) < 0) { + y0 -= step; + } + for (double y = y0; y < sy; y += step) { + path.move_to(0, y); + path.line_to(sx, y); + } + return path; + } + if (angle == 90) { + double x0 = step - fmod(ox - rx, step); + if ((ox - rx) < 0) { + x0 -= step; + } + for (double x = x0; x < sx; x += step) { + path.move_to(x, 0); + path.line_to(x, sy); + } + return path; + } + + double theta = (90 - angle) * MS_DEG_TO_RAD; /* theta in ]-pi/2 , pi/2] */ + double ct = cos(theta); + double st = sin(theta); + double invct = 1.0 / ct; + double invst = 1.0 / st; + double + r0; /* distance from first hatch line to the top-left (if angle in 0,pi/2) + or bottom-left (if angle in -pi/2,0) corner of the hatch bbox */ + double rmax = sqrt(( + double)(sx * sx + + sy * + sy)); /* distance to the furthest hatch we will have to create +TODO: this could be optimized for bounding boxes where width is very different +than height for certain hatch angles */ + double rref = + rx * ct + ry * st; /* distance to the line passing through the refpoint, + origin is (0,0) of the imageObj */ + double + rcorner; /* distance to the line passing through the topleft or bottomleft + corner of the hatch bbox (origin is (0,0) of imageObj) */ + + /* calculate the distance from the refpoint to the top right of the path */ + if (angle < 90) { + rcorner = ox * ct + oy * st; + r0 = step - fmod(rcorner - rref, step); + if (rcorner - rref < 0) + r0 -= step; + } else { + rcorner = ox * ct + (oy + sy) * st; + r0 = step - fmod(rcorner - rref, step); + if (rcorner - rref < 0) + r0 -= step; + st = -st; + invst = -invst; + } + + // parametrize each line as r = x.cos(theta) + y.sin(theta) + for (double r = r0; r < rmax; r += step) { + int inter = 0; + double x, y; + double pt[4]; // array to store the coordinates of intersection of the line + // with the sides + // in the general case there will only be two intersections + // so pt[4] should be sufficient to store the coordinates of the + // intersection, but we allocate pt[8] to treat the special and + // rare/unfortunate case when the line is a perfect diagonal (and therefore + // intersects all four sides) note that the order for testing is important + // in this case so that the first two intersection points actually + // correspond to the diagonal and not a degenerate line + + // test for intersection with each side + + y = r * invst; + x = 0; // test for intersection with left of image + if (y >= 0 && y <= sy) { + pt[2 * inter] = x; + pt[2 * inter + 1] = y; + inter++; + } + x = sx; + y = (r - sx * ct) * invst; // test for intersection with right of image + if (y >= 0 && y <= sy) { + pt[2 * inter] = x; + pt[2 * inter + 1] = y; + inter++; + } + if (inter < 2) { + y = 0; + x = r * invct; // test for intersection with top of image + if (x >= 0 && x <= sx) { + pt[2 * inter] = x; + pt[2 * inter + 1] = y; + inter++; + } + } + if (inter < 2) { + y = sy; + x = (r - sy * st) * invct; // test for intersection with bottom of image + if (x >= 0 && x <= sx) { + pt[2 * inter] = x; + pt[2 * inter + 1] = y; + inter++; + } + } + if (inter == 2 && (pt[0] != pt[2] || pt[1] != pt[3])) { + // the line intersects with two sides of the image, it should therefore be + // drawn + if (angle < 90) { + path.move_to(pt[0], pt[1]); + path.line_to(pt[2], pt[3]); + } else { + path.move_to(pt[0], sy - pt[1]); + path.line_to(pt[2], sy - pt[3]); + } + } + } + return path; +} + +template +int renderPolygonHatches(imageObj *img, VertexSource &clipper, + colorObj *color) { + if (img->format->renderer == MS_RENDER_WITH_AGG) { + AGG2Renderer *r = AGG_RENDERER(img); + r->m_rasterizer_aa_gamma.reset(); + r->m_rasterizer_aa_gamma.filling_rule(mapserver::fill_non_zero); + r->m_rasterizer_aa_gamma.add_path(clipper); + r->m_renderer_scanline.color(aggColor(color)); + mapserver::render_scanlines(r->m_rasterizer_aa_gamma, r->sl_poly, + r->m_renderer_scanline); + } else { + shapeObj shape; + msInitShape(&shape); + int allocated = 20; + lineObj line; + shape.line = &line; + shape.numlines = 1; + shape.line[0].point = + (pointObj *)msSmallCalloc(allocated, sizeof(pointObj)); + shape.line[0].numpoints = 0; + double x = 0, y = 0; + unsigned int cmd; + clipper.rewind(0); + while ((cmd = clipper.vertex(&x, &y)) != mapserver::path_cmd_stop) { + switch (cmd) { + case mapserver::path_cmd_line_to: + if (shape.line[0].numpoints == allocated) { + allocated *= 2; + shape.line[0].point = (pointObj *)msSmallRealloc( + shape.line[0].point, allocated * sizeof(pointObj)); + } + shape.line[0].point[shape.line[0].numpoints].x = x; + shape.line[0].point[shape.line[0].numpoints].y = y; + shape.line[0].numpoints++; + break; + case mapserver::path_cmd_move_to: + shape.line[0].point[0].x = x; + shape.line[0].point[0].y = y; + shape.line[0].numpoints = 1; + break; + case mapserver::path_cmd_end_poly | mapserver::path_flags_close: + if (shape.line[0].numpoints > 2) { + if (MS_UNLIKELY(MS_FAILURE == MS_IMAGE_RENDERER(img)->renderPolygon( + img, &shape, color))) { + free(shape.line[0].point); + shape.numlines = 0; + shape.line = nullptr; + return MS_FAILURE; + } + } + break; + default: + assert(0); // WTF? + } + } + free(shape.line[0].point); + shape.numlines = 0; + shape.line = nullptr; + } + return MS_SUCCESS; +} + +int msHatchPolygon(imageObj *img, shapeObj *poly, double spacing, double width, + double *pattern, int patternlength, double angle, + colorObj *color) { + assert(MS_RENDERER_PLUGIN(img->format)); + msComputeBounds(poly); + + /* amount we should expand the bounding box by */ + double exp = width * 0.7072; + + /* width and height of the bounding box we will be creating the hatch in */ + int pw = (int)(poly->bounds.maxx - poly->bounds.minx + exp * 2) + 1; + int ph = (int)(poly->bounds.maxy - poly->bounds.miny + exp * 2) + 1; + + /* position of the top-left corner of the bounding box */ + double ox = poly->bounds.minx - exp; + double oy = poly->bounds.miny - exp; + + // create a rectangular hatch of size pw,ph starting at 0,0 + // the created hatch is of the size of the shape's bounding box + mapserver::path_storage hatch = + createHatch(ox, oy, img->refpt.x, img->refpt.y, pw, ph, angle, spacing); + if (hatch.total_vertices() <= 0) + return MS_SUCCESS; + + // translate the hatch so it overlaps the current shape + hatch.transform(mapserver::trans_affine_translation(ox, oy)); + + polygon_adaptor polygons(poly); + + if (patternlength > 1) { + // dash the color-hatch and render it clipped by the shape + mapserver::conv_dash dash(hatch); + mapserver::conv_stroke> + stroke(dash); + for (int i = 0; i < patternlength; i += 2) { + if (i < patternlength - 1) { + dash.add_dash(pattern[i], pattern[i + 1]); + } + } + stroke.width(width); + stroke.line_cap(mapserver::butt_cap); + mapserver::conv_clipper< + polygon_adaptor, + mapserver::conv_stroke>> + clipper(polygons, stroke, mapserver::clipper_and); + renderPolygonHatches(img, clipper, color); + } else { + // render the hatch clipped by the shape + mapserver::conv_stroke stroke(hatch); + stroke.width(width); + stroke.line_cap(mapserver::butt_cap); + mapserver::conv_clipper> + clipper(polygons, stroke, mapserver::clipper_and); + renderPolygonHatches(img, clipper, color); + } + + // assert(prevCmd == mapserver::path_cmd_line_to); + // delete lines; + return MS_SUCCESS; +} + +#ifdef USE_PIXMAN +static pixman_op_t ms2pixman_compop(CompositingOperation c) { + switch (c) { + case MS_COMPOP_CLEAR: + return PIXMAN_OP_CLEAR; + case MS_COMPOP_SRC: + return PIXMAN_OP_SRC; + case MS_COMPOP_DST: + return PIXMAN_OP_DST; + case MS_COMPOP_SRC_OVER: + return PIXMAN_OP_OVER; + case MS_COMPOP_DST_OVER: + return PIXMAN_OP_OVER_REVERSE; + case MS_COMPOP_SRC_IN: + return PIXMAN_OP_IN; + case MS_COMPOP_DST_IN: + return PIXMAN_OP_IN_REVERSE; + case MS_COMPOP_SRC_OUT: + return PIXMAN_OP_OUT; + case MS_COMPOP_DST_OUT: + return PIXMAN_OP_OUT_REVERSE; + case MS_COMPOP_SRC_ATOP: + return PIXMAN_OP_ATOP; + case MS_COMPOP_DST_ATOP: + return PIXMAN_OP_ATOP_REVERSE; + case MS_COMPOP_XOR: + return PIXMAN_OP_XOR; + case MS_COMPOP_PLUS: + return PIXMAN_OP_ADD; + case MS_COMPOP_MULTIPLY: + return PIXMAN_OP_MULTIPLY; + case MS_COMPOP_SCREEN: + return PIXMAN_OP_SCREEN; + case MS_COMPOP_OVERLAY: + return PIXMAN_OP_OVERLAY; + case MS_COMPOP_DARKEN: + return PIXMAN_OP_DARKEN; + case MS_COMPOP_LIGHTEN: + return PIXMAN_OP_LIGHTEN; + case MS_COMPOP_COLOR_DODGE: + return PIXMAN_OP_COLOR_DODGE; + case MS_COMPOP_COLOR_BURN: + return PIXMAN_OP_COLOR_DODGE; + case MS_COMPOP_HARD_LIGHT: + return PIXMAN_OP_HARD_LIGHT; + case MS_COMPOP_SOFT_LIGHT: + return PIXMAN_OP_SOFT_LIGHT; + case MS_COMPOP_DIFFERENCE: + return PIXMAN_OP_DIFFERENCE; + case MS_COMPOP_EXCLUSION: + return PIXMAN_OP_EXCLUSION; + case MS_COMPOP_HSL_HUE: + return PIXMAN_OP_HSL_HUE; + case MS_COMPOP_HSL_LUMINOSITY: + return PIXMAN_OP_HSL_LUMINOSITY; + case MS_COMPOP_HSL_SATURATION: + return PIXMAN_OP_HSL_SATURATION; + case MS_COMPOP_HSL_COLOR: + return PIXMAN_OP_HSL_COLOR; + case MS_COMPOP_INVERT: + case MS_COMPOP_INVERT_RGB: + case MS_COMPOP_MINUS: + case MS_COMPOP_CONTRAST: + default: + return PIXMAN_OP_OVER; + } +} +#endif + +static mapserver::comp_op_e ms2agg_compop(CompositingOperation c) { + switch (c) { + case MS_COMPOP_CLEAR: + return mapserver::comp_op_clear; + case MS_COMPOP_SRC: + return mapserver::comp_op_src; + case MS_COMPOP_DST: + return mapserver::comp_op_dst; + case MS_COMPOP_SRC_OVER: + return mapserver::comp_op_src_over; + case MS_COMPOP_DST_OVER: + return mapserver::comp_op_dst_over; + case MS_COMPOP_SRC_IN: + return mapserver::comp_op_src_in; + case MS_COMPOP_DST_IN: + return mapserver::comp_op_dst_in; + case MS_COMPOP_SRC_OUT: + return mapserver::comp_op_src_out; + case MS_COMPOP_DST_OUT: + return mapserver::comp_op_dst_out; + case MS_COMPOP_SRC_ATOP: + return mapserver::comp_op_src_atop; + case MS_COMPOP_DST_ATOP: + return mapserver::comp_op_dst_atop; + case MS_COMPOP_XOR: + return mapserver::comp_op_xor; + case MS_COMPOP_PLUS: + return mapserver::comp_op_plus; + case MS_COMPOP_MINUS: + return mapserver::comp_op_minus; + case MS_COMPOP_MULTIPLY: + return mapserver::comp_op_multiply; + case MS_COMPOP_SCREEN: + return mapserver::comp_op_screen; + case MS_COMPOP_OVERLAY: + return mapserver::comp_op_overlay; + case MS_COMPOP_DARKEN: + return mapserver::comp_op_darken; + case MS_COMPOP_LIGHTEN: + return mapserver::comp_op_lighten; + case MS_COMPOP_COLOR_DODGE: + return mapserver::comp_op_color_dodge; + case MS_COMPOP_COLOR_BURN: + return mapserver::comp_op_color_burn; + case MS_COMPOP_HARD_LIGHT: + return mapserver::comp_op_hard_light; + case MS_COMPOP_SOFT_LIGHT: + return mapserver::comp_op_soft_light; + case MS_COMPOP_DIFFERENCE: + return mapserver::comp_op_difference; + case MS_COMPOP_EXCLUSION: + return mapserver::comp_op_exclusion; + case MS_COMPOP_CONTRAST: + return mapserver::comp_op_contrast; + case MS_COMPOP_INVERT: + return mapserver::comp_op_invert; + case MS_COMPOP_INVERT_RGB: + return mapserver::comp_op_invert_rgb; + case MS_COMPOP_HSL_HUE: + return mapserver::comp_op_hsl_hue; + case MS_COMPOP_HSL_LUMINOSITY: + return mapserver::comp_op_hsl_luminosity; + case MS_COMPOP_HSL_SATURATION: + return mapserver::comp_op_hsl_saturation; + case MS_COMPOP_HSL_COLOR: + return mapserver::comp_op_hsl_color; + default: + return mapserver::comp_op_src_over; + } +} + +#ifdef USE_PIXMAN +static int aggCompositeRasterBufferPixman(imageObj *dest, + rasterBufferObj *overlay, + CompositingOperation comp, + int opacity) { + assert(overlay->type == MS_BUFFER_BYTE_RGBA); + AGG2Renderer *r = AGG_RENDERER(dest); + pixman_image_t *si = pixman_image_create_bits( + PIXMAN_a8r8g8b8, overlay->width, overlay->height, + (uint32_t *)overlay->data.rgba.pixels, overlay->data.rgba.row_step); + pixman_image_t *bi = pixman_image_create_bits( + PIXMAN_a8r8g8b8, dest->width, dest->height, + reinterpret_cast(&(r->buffer[0])), dest->width * 4); + pixman_image_t *alpha_mask_i = NULL, *alpha_mask_i_ptr; + pixman_image_set_filter(si, PIXMAN_FILTER_NEAREST, NULL, 0); + unsigned char *alpha_mask = NULL; + if (opacity > 0) { + if (opacity == 100) { + alpha_mask_i_ptr = NULL; + } else { + unsigned char alpha = (unsigned char)(MS_NINT(opacity * 2.55)); + if (!alpha_mask_i) { + alpha_mask = (unsigned char *)msSmallMalloc(dest->width * dest->height); + alpha_mask_i = + pixman_image_create_bits(PIXMAN_a8, dest->width, dest->height, + (uint32_t *)alpha_mask, dest->width); + } + memset(alpha_mask, alpha, dest->width * dest->height); + alpha_mask_i_ptr = alpha_mask_i; + } + pixman_image_composite(ms2pixman_compop(comp), si, alpha_mask_i_ptr, bi, 0, + 0, 0, 0, 0, 0, dest->width, dest->height); + } + pixman_image_unref(si); + pixman_image_unref(bi); + if (alpha_mask_i) { + pixman_image_unref(alpha_mask_i); + msFree(alpha_mask); + } + return MS_SUCCESS; +} +#endif + +static int aggCompositeRasterBufferNoPixman(imageObj *dest, + rasterBufferObj *overlay, + CompositingOperation comp, + int opacity) { + assert(overlay->type == MS_BUFFER_BYTE_RGBA); + AGG2Renderer *r = AGG_RENDERER(dest); + rendering_buffer b(overlay->data.rgba.pixels, overlay->width, overlay->height, + overlay->data.rgba.row_step); + pixel_format pf(b); + mapserver::comp_op_e comp_op = ms2agg_compop(comp); + if (comp_op == mapserver::comp_op_src_over) { + r->m_renderer_base.blend_from(pf, 0, 0, 0, + unsigned(MS_NINT(opacity * 2.55))); + } else { + compop_pixel_format pixf(r->m_rendering_buffer); + compop_renderer_base ren(pixf); + pixf.comp_op(comp_op); + ren.blend_from(pf, 0, 0, 0, unsigned(MS_NINT(opacity * 2.55))); + } + return MS_SUCCESS; +} + +void msApplyBlurringCompositingFilter(rasterBufferObj *rb, + unsigned int radius) { + rendering_buffer b(rb->data.rgba.pixels, rb->width, rb->height, + rb->data.rgba.row_step); + pixel_format pf(b); + mapserver::stack_blur_rgba32(pf, radius, radius); +} + +int msPopulateRendererVTableAGG(rendererVTableObj *renderer) { + renderer->compositeRasterBuffer = &aggCompositeRasterBufferNoPixman; +#ifdef USE_PIXMAN + const char *pszUsePixman = CPLGetConfigOption("MS_USE_PIXMAN", "YES"); + if (CPLTestBool(pszUsePixman)) { + renderer->compositeRasterBuffer = &aggCompositeRasterBufferPixman; + } +#endif + renderer->supports_pixel_buffer = 1; + renderer->use_imagecache = 0; + renderer->supports_clipping = 0; + renderer->supports_svg = 0; + renderer->default_transform_mode = MS_TRANSFORM_SIMPLIFY; + agg2InitCache(&(MS_RENDERER_CACHE(renderer))); + renderer->cleanup = agg2Cleanup; + renderer->renderLine = &agg2RenderLine; + + renderer->renderPolygon = &agg2RenderPolygon; + renderer->renderPolygonTiled = &agg2RenderPolygonTiled; + renderer->renderLineTiled = &agg2RenderLineTiled; + + renderer->renderGlyphs = &agg2RenderGlyphsPath; + + renderer->renderVectorSymbol = &agg2RenderVectorSymbol; + + renderer->renderPixmapSymbol = &agg2RenderPixmapSymbol; + + renderer->renderEllipseSymbol = &agg2RenderEllipseSymbol; + + renderer->renderTile = &agg2RenderTile; + + renderer->getRasterBufferHandle = &aggGetRasterBufferHandle; + renderer->getRasterBufferCopy = aggGetRasterBufferCopy; + renderer->initializeRasterBuffer = aggInitializeRasterBuffer; + + renderer->mergeRasterBuffer = &agg2MergeRasterBuffer; + renderer->loadImageFromFile = msLoadMSRasterBufferFromFile; + renderer->createImage = &agg2CreateImage; + renderer->saveImage = &agg2SaveImage; + + renderer->startLayer = &agg2StartNewLayer; + renderer->endLayer = &agg2CloseNewLayer; + + renderer->freeImage = &agg2FreeImage; + renderer->freeSymbol = &agg2FreeSymbol; + + return MS_SUCCESS; +} diff --git a/src/mapagg.h b/src/mapagg.h new file mode 100644 index 0000000000..37c25a852b --- /dev/null +++ b/src/mapagg.h @@ -0,0 +1,157 @@ +/****************************************************************************** + * $Id$ + * + * Project: MapServer + * Purpose: AGG template library types. + * Author: John Novak (jnovak@novacell.com) + * Author: Thomas Bonfort (tbonfort@terriscope.fr) + * + ****************************************************************************** + * Copyright (c) 1996-2007 Regents of the University of Minnesota. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + ******************************************************************************/ + +#include "renderers/agg/include/agg_path_storage.h" + +/* + * interface to a shapeObj representing lines, providing the functions + * needed by the agg rasterizer. treats shapeObjs with multiple linestrings. + */ +class line_adaptor { +public: + explicit line_adaptor(shapeObj *shape) : s(shape) { + m_line = s->line; /*first line*/ + m_point = m_line->point; /*current vertex is first vertex of first line*/ + m_lend = &(s->line[s->numlines]); /*pointer to after last line*/ + m_pend = &(m_line->point[m_line->numpoints]); /*pointer to after last vertex + of first line*/ + } + + /* a class with virtual functions should also provide a virtual destructor */ + virtual ~line_adaptor() {} + + void rewind(unsigned) { + m_line = s->line; /*first line*/ + m_point = m_line->point; /*current vertex is first vertex of first line*/ + m_pend = &(m_line->point[m_line->numpoints]); /*pointer to after last vertex + of first line*/ + } + + virtual unsigned vertex(double *x, double *y) { + if (m_point < m_pend) { + /*here we treat the case where a real vertex is returned*/ + bool first = + m_point == m_line->point; /*is this the first vertex of a line*/ + *x = m_point->x; + *y = m_point->y; + m_point++; + return first ? mapserver::path_cmd_move_to : mapserver::path_cmd_line_to; + } + /*if here, we're at the end of a line*/ + m_line++; + *x = *y = 0.0; + if (m_line >= m_lend) /*is this the last line of the shapObj. normally, + (m_line==m_lend) should be a sufficient test, as the caller should + not call this function if a previous call returned path_cmd_stop.*/ + return mapserver::path_cmd_stop; /*no more points to process*/ + + /*if here, there are more lines in the shapeObj, continue with next one*/ + m_point = m_line->point; /*pointer to first point of next line*/ + m_pend = &(m_line->point[m_line->numpoints]); /*pointer to after last point + of next line*/ + + return vertex(x, y); /*this will return the first point of the next line*/ + } + +protected: + shapeObj *s; + lineObj *m_line, /*current line pointer*/ + *m_lend; /*points to after the last line*/ + pointObj *m_point, /*current point*/ + *m_pend; /*points to after last point of current line*/ +}; + +class polygon_adaptor { +public: + explicit polygon_adaptor(shapeObj *shape) : s(shape) { + m_line = s->line; /*first lines*/ + m_point = m_line->point; /*first vertex of first line*/ + m_lend = &(s->line[s->numlines]); /*pointer to after last line*/ + m_pend = &(m_line->point[m_line->numpoints]); /*pointer to after last vertex + of first line*/ + } + + /* a class with virtual functions should also provide a virtual destructor */ + virtual ~polygon_adaptor() {} + + void rewind(unsigned) { + /*reset pointers*/ + m_stop = false; + m_line = s->line; + m_point = m_line->point; + m_pend = &(m_line->point[m_line->numpoints]); + } + + virtual unsigned vertex(double *x, double *y) { + if (m_point < m_pend) { + /*if here, we have a real vertex*/ + bool first = m_point == m_line->point; + *x = m_point->x; + *y = m_point->y; + m_point++; + return first ? mapserver::path_cmd_move_to : mapserver::path_cmd_line_to; + } + *x = *y = 0.0; + if (!m_stop) { + /*if here, we're after the last vertex of the current line + * we return the command to close the current polygon*/ + m_line++; + if (m_line >= m_lend) { + /*if here, we've finished all the vertices of the shape. + * we still return the command to close the current polygon, + * but set m_stop so the subsequent call to vertex() will return + * the stop command*/ + m_stop = true; + return mapserver::path_cmd_end_poly; + } + /*if here, there's another line in the shape, so we set the pointers + * accordingly and return the command to close the current polygon*/ + m_point = m_line->point; /*first vertex of next line*/ + m_pend = &(m_line->point[m_line->numpoints]); /*pointer to after last + vertex of next line*/ + return mapserver::path_cmd_end_poly; + } + /*if here, a previous call to vertex informed us that we'd consumed all the + * vertices of the shape. return the command to stop processing this shape*/ + return mapserver::path_cmd_stop; + } + +protected: + shapeObj *s; + double ox = 0.0; + double oy = 0.0; + lineObj *m_line, /*pointer to current line*/ + *m_lend; /*pointer to after last line of the shape*/ + pointObj *m_point, /*pointer to current vertex*/ + *m_pend; /*pointer to after last vertex of current line*/ + bool m_stop = false; /*should next call return stop command*/ +}; + +mapserver::path_storage imageVectorSymbol(symbolObj *); diff --git a/src/mapaxisorder.h b/src/mapaxisorder.h new file mode 100644 index 0000000000..505232a563 --- /dev/null +++ b/src/mapaxisorder.h @@ -0,0 +1,4135 @@ +/****************************************************************************** + * $Id: $ + * + * Project: MapServer + * Purpose: Axis lookup table + * + ****************************************************************************** + * Copyright (c) 1996-2005 Regents of the University of Minnesota. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + ****************************************************************************/ +/* + * Generated file + * + * This file was generated from by means of a script. Do not edit manually. + */ +#ifdef __cplusplus +extern "C" { +#endif +static const unsigned char axisOrientationEpsgCodes[] = { + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 1 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 1 << 5 | 1 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 1 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 1 << 6 | 1 << 5 | 0 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 1 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 0 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 1 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 1 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 0 << 5 | 0 << 4 | 1 << 3 | 1 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 1 << 3 | 1 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 1 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 0 << 5 | 0 << 4 | 1 << 3 | 1 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 1 << 5 | 1 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 1 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 1 << 0, + 0 << 7 | 1 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 1 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 1 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 1 << 4 | 1 << 3 | 0 << 2 | 1 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 0 << 6 | 1 << 5 | 0 << 4 | 1 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 1 << 6 | 0 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 1 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 1 << 3 | 1 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 0 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 0 << 3 | 0 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 0 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 0 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 0 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 0 << 5 | 1 << 4 | 0 << 3 | 1 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 1 << 1 | 0 << 0, + 1 << 7 | 0 << 6 | 1 << 5 | 0 << 4 | 1 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 0 << 6 | 1 << 5 | 0 << 4 | 1 << 3 | 0 << 2 | 1 << 1 | 0 << 0, + 1 << 7 | 0 << 6 | 1 << 5 | 0 << 4 | 1 << 3 | 0 << 2 | 1 << 1 | 0 << 0, + 1 << 7 | 0 << 6 | 1 << 5 | 0 << 4 | 1 << 3 | 0 << 2 | 1 << 1 | 0 << 0, + 1 << 7 | 0 << 6 | 1 << 5 | 0 << 4 | 1 << 3 | 0 << 2 | 1 << 1 | 0 << 0, + 1 << 7 | 0 << 6 | 1 << 5 | 0 << 4 | 1 << 3 | 0 << 2 | 1 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 1 << 4 | 0 << 3 | 1 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 1 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 1 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 1 << 6 | 1 << 5 | 0 << 4 | 0 << 3 | 1 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 1 << 3 | 0 << 2 | 0 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 1 << 3 | 1 << 2 | 0 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 1 << 6 | 1 << 5 | 0 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 1 << 0, + 1 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 0 << 6 | 1 << 5 | 0 << 4 | 1 << 3 | 0 << 2 | 0 << 1 | 1 << 0, + 1 << 7 | 0 << 6 | 1 << 5 | 0 << 4 | 1 << 3 | 0 << 2 | 1 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 0 << 3 | 1 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 1 << 5 | 0 << 4 | 1 << 3 | 0 << 2 | 0 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 0 << 6 | 1 << 5 | 0 << 4 | 1 << 3 | 0 << 2 | 1 << 1 | 0 << 0, + 1 << 7 | 0 << 6 | 1 << 5 | 0 << 4 | 1 << 3 | 0 << 2 | 1 << 1 | 0 << 0, + 1 << 7 | 0 << 6 | 1 << 5 | 0 << 4 | 1 << 3 | 0 << 2 | 1 << 1 | 0 << 0, + 1 << 7 | 0 << 6 | 1 << 5 | 0 << 4 | 1 << 3 | 0 << 2 | 1 << 1 | 0 << 0, + 1 << 7 | 0 << 6 | 1 << 5 | 0 << 4 | 1 << 3 | 0 << 2 | 1 << 1 | 0 << 0, + 1 << 7 | 0 << 6 | 1 << 5 | 0 << 4 | 1 << 3 | 0 << 2 | 1 << 1 | 0 << 0, + 1 << 7 | 0 << 6 | 1 << 5 | 0 << 4 | 1 << 3 | 0 << 2 | 1 << 1 | 0 << 0, + 1 << 7 | 0 << 6 | 1 << 5 | 0 << 4 | 1 << 3 | 0 << 2 | 1 << 1 | 0 << 0, + 1 << 7 | 0 << 6 | 1 << 5 | 0 << 4 | 1 << 3 | 0 << 2 | 1 << 1 | 0 << 0, + 1 << 7 | 0 << 6 | 1 << 5 | 0 << 4 | 1 << 3 | 0 << 2 | 1 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 1 << 5 | 1 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 1 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 1 << 4 | 0 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 1 << 5 | 1 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 1 << 1 | 0 << 0, + 0 << 7 | 1 << 6 | 1 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 1 << 4 | 1 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 0 << 5 | 1 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 1 << 2 | 1 << 1 | 0 << 0, + 1 << 7 | 0 << 6 | 1 << 5 | 1 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 1 << 5 | 1 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 1 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 1 << 3 | 0 << 2 | 0 << 1 | 1 << 0, + 1 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 0 << 5 | 0 << 4 | 1 << 3 | 0 << 2 | 1 << 1 | 0 << 0, + 1 << 7 | 0 << 6 | 0 << 5 | 1 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 1 << 2 | 1 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 1 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 1 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 1 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 1 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 1 << 6 | 1 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 1 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 1 << 5 | 1 << 4 | 0 << 3 | 1 << 2 | 1 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 1 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 1 << 5 | 1 << 4 | 0 << 3 | 1 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 1 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 1 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 1 << 4 | 0 << 3 | 0 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 1 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 1 << 4 | 1 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 0 << 0, + 0 << 7 | 1 << 6 | 0 << 5 | 1 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 1 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 1 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 0 << 5 | 1 << 4 | 1 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 1 << 6 | 1 << 5 | 0 << 4 | 1 << 3 | 1 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 1 << 3 | 1 << 2 | 0 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 1 << 5 | 1 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 1 << 6 | 0 << 5 | 1 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 1 << 0, + 0 << 7 | 1 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 1 << 2 | 1 << 1 | 0 << 0, + 1 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 0 << 6 | 1 << 5 | 0 << 4 | 1 << 3 | 0 << 2 | 1 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 1 << 1 | 0 << 0, + 0 << 7 | 1 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 1 << 6 | 1 << 5 | 0 << 4 | 1 << 3 | 1 << 2 | 0 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 1 << 4 | 1 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 1 << 6 | 1 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 0 << 6 | 1 << 5 | 0 << 4 | 1 << 3 | 0 << 2 | 0 << 1 | 1 << 0, + 1 << 7 | 0 << 6 | 1 << 5 | 0 << 4 | 1 << 3 | 0 << 2 | 1 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 1 << 3 | 0 << 2 | 1 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 1 << 6 | 1 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 0 << 6 | 1 << 5 | 0 << 4 | 1 << 3 | 0 << 2 | 0 << 1 | 1 << 0, + 0 << 7 | 1 << 6 | 0 << 5 | 1 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 0 << 5 | 1 << 4 | 1 << 3 | 0 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 1 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 0 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 1 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 1 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 1 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 1 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 1 << 5 | 1 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 1 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 1 << 3 | 1 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 1 << 2 | 1 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 1 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 1 << 4 | 1 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 1 << 3 | 1 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 1 << 6 | 0 << 5 | 1 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 1 << 6 | 0 << 5 | 1 << 4 | 0 << 3 | 1 << 2 | 0 << 1 | 1 << 0, + 0 << 7 | 1 << 6 | 0 << 5 | 1 << 4 | 0 << 3 | 1 << 2 | 0 << 1 | 1 << 0, + 0 << 7 | 1 << 6 | 0 << 5 | 1 << 4 | 0 << 3 | 1 << 2 | 0 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 1 << 5 | 1 << 4 | 0 << 3 | 1 << 2 | 0 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 1 << 6 | 1 << 5 | 0 << 4 | 1 << 3 | 1 << 2 | 0 << 1 | 1 << 0, + 0 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 0 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 0 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 0 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 1 << 3 | 1 << 2 | 0 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 1 << 4 | 1 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 1 << 4 | 1 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 1 << 6 | 1 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 1 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 1 << 6 | 1 << 5 | 0 << 4 | 0 << 3 | 1 << 2 | 1 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 1 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 1 << 5 | 1 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 1 << 5 | 1 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 1 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 1 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 1 << 4 | 1 << 3 | 0 << 2 | 1 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 1 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 1 << 5 | 1 << 4 | 0 << 3 | 1 << 2 | 1 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 1 << 6 | 1 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 1 << 3 | 1 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 0 << 3 | 1 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 1 << 3 | 1 << 2 | 0 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 1 << 6 | 1 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 1 << 3 | 0 << 2 | 1 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 1 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 1 << 6 | 0 << 5 | 0 << 4 | 1 << 3 | 1 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 1 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 1 << 6 | 1 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 1 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 1 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 1 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 0 << 6 | 1 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 1 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 1 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 1 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 1 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 1 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 1 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 1 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 1 << 6 | 1 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 1 << 2 | 1 << 1 | 0 << 0, + 1 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 1 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 1 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 1 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 1 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 1 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 1 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 1 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 1 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 1 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 1 << 4 | 0 << 3 | 0 << 2 | 1 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 1 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 1 << 4 | 0 << 3 | 0 << 2 | 1 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 1 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 1 << 0, + 0 << 7 | 1 << 6 | 0 << 5 | 1 << 4 | 1 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 1 << 5 | 0 << 4 | 0 << 3 | 1 << 2 | 0 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 1 << 3 | 1 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 1 << 6 | 1 << 5 | 0 << 4 | 0 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 1 << 2 | 1 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 1 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 1 << 6 | 1 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 1 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 1 << 3 | 1 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 1 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 1 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 1 << 3 | 1 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 1 << 6 | 1 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 1 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 0 << 3 | 0 << 2 | 1 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 1 << 6 | 1 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 1 << 6 | 1 << 5 | 0 << 4 | 1 << 3 | 0 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 1 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 1 << 6 | 1 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 1 << 7 | 1 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 1 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 1 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0, + 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0 << 3 | 0 << 2 | 1 << 1 | 0 << 0}; +#ifdef __cplusplus +} +#endif diff --git a/src/mapbits.c b/src/mapbits.c new file mode 100644 index 0000000000..42b4a5607c --- /dev/null +++ b/src/mapbits.c @@ -0,0 +1,111 @@ +/****************************************************************************** + * $Id$ + * + * Project: MapServer + * Purpose: Implementation of bit array functions. + * Author: Steve Lime and the MapServer team. + * + * Notes: Derived from code placed in the public domain by Bob Stout, for more + * information see http://c.snippets.org/snip_lister.php?fname=bitarray.c. + * + ****************************************************************************** + * Copyright (c) 1996-2005 Regents of the University of Minnesota. + + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + ****************************************************************************/ + +#include "mapserver.h" + +#include + +/* + * Hardcoded size of our bit array. + * See function msGetNextBit for another hardcoded value. + */ + +/* #define msGetBit(array, index) (*((array) + (index)/MS_ARRAY_BIT) & ( 1 << + * ((index) % MS_ARRAY_BIT))) */ + +size_t msGetBitArraySize(int numbits) { + return ((numbits + MS_ARRAY_BIT - 1) / MS_ARRAY_BIT); +} + +ms_bitarray msAllocBitArray(int numbits) { + ms_bitarray array = + calloc((numbits + MS_ARRAY_BIT - 1) / MS_ARRAY_BIT, MS_ARRAY_BIT); + + return (array); +} + +int msGetBit(ms_const_bitarray array, int index) { + array += index / MS_ARRAY_BIT; + return (*array & (1U << (index % MS_ARRAY_BIT))) != 0; /* 0 or 1 */ +} + +/* +** msGetNextBit( status, start, size) +** +** Quickly find the next bit set. If start == 0 and 0 is set, will return 0. +** If hits end of bitmap without finding set bit, will return -1. +** +*/ +int msGetNextBit(ms_const_bitarray array, int i, int size) { + + register ms_uint32 b; + + while (i < size) { + b = *(array + (i / MS_ARRAY_BIT)); + if (b && (b >> (i % MS_ARRAY_BIT))) { + /* There is something in this byte */ + /* And it is not to the right of us */ + if (b & (1U << (i % MS_ARRAY_BIT))) { + /* There is something at this bit! */ + return i; + } else { + i++; + } + } else { + /* Nothing in this byte, move to start of next byte */ + i += MS_ARRAY_BIT - (i % MS_ARRAY_BIT); + } + } + + /* Got to the last byte with no hits! */ + return -1; +} + +void msSetBit(ms_bitarray array, int index, int value) { + array += index / MS_ARRAY_BIT; + if (value) + *array |= 1U << (index % MS_ARRAY_BIT); /* set bit */ + else + *array &= ~(1U << (index % MS_ARRAY_BIT)); /* clear bit */ +} + +void msSetAllBits(ms_bitarray array, int numbits, int value) { + if (value) + memset(array, 0xff, ((numbits + 7) / 8)); /* set bit */ + else + memset(array, 0x0, ((numbits + 7) / 8)); /* clear bit */ +} + +void msFlipBit(ms_bitarray array, int index) { + array += index / MS_ARRAY_BIT; + *array ^= 1U << (index % MS_ARRAY_BIT); /* flip bit */ +} diff --git a/src/mapcairo.c b/src/mapcairo.c new file mode 100644 index 0000000000..f2854b7a0d --- /dev/null +++ b/src/mapcairo.c @@ -0,0 +1,1262 @@ +/****************************************************************************** + * $Id$ + * + * Project: MapServer + * Purpose: Cairo Rendering functions + * Author: Thomas Bonfort + * + ****************************************************************************** + * Copyright (c) 1996-2009 Regents of the University of Minnesota. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + *****************************************************************************/ +#include "mapserver.h" + +#ifdef USE_CAIRO + +#include +#if defined(_WIN32) && !defined(__CYGWIN__) +#include +#include +#include +#else +#include +#include +#endif + +#ifdef USE_SVG_CAIRO +#include +#else +#ifdef USE_RSVG +#include +#ifndef LIBRSVG_CHECK_VERSION +#include +#endif +#ifndef RSVG_CAIRO_H +#include +#endif +#include +#endif +#endif + +#include +#include "cpl_conv.h" +#include + +#include "fontcache.h" + +#include +/* +#include +#include +*/ +#include +/* +#include +#include FT_FREETYPE_H +*/ + +typedef struct cairoFaceCache cairoFaceCache; +struct cairoFaceCache { + cairo_font_face_t *face; + FT_Face ftface; + cairo_font_options_t *options; + cairoFaceCache *next; +}; + +void freeCairoFaceCache(cairoFaceCache *fc) { + cairo_font_face_destroy(fc->face); + cairo_font_options_destroy(fc->options); +} + +typedef struct { + cairoFaceCache *cairofacecache; + /* dummy surface and context */ + unsigned char dummydata[4]; + cairo_surface_t *dummysurface; + cairo_t *dummycr; +} cairoCacheData; + +void initializeCache(void **vcache) { + cairoCacheData *cache = (cairoCacheData *)malloc(sizeof(cairoCacheData)); + *vcache = cache; + + cache->cairofacecache = NULL; + /* dummy surface and context */ + cache->dummysurface = cairo_image_surface_create_for_data( + cache->dummydata, CAIRO_FORMAT_ARGB32, 1, 1, 4); + cache->dummycr = cairo_create(cache->dummysurface); +} + +int cleanupCairo(void *cache) { + cairoCacheData *ccache = (cairoCacheData *)cache; + + if (ccache->dummycr) { + cairo_destroy(ccache->dummycr); + } + if (ccache->dummysurface) { + cairo_surface_destroy(ccache->dummysurface); + } + if (ccache->cairofacecache) { + cairoFaceCache *next, *cur; + cur = ccache->cairofacecache; + do { + next = cur->next; + freeCairoFaceCache(cur); + free(cur); + cur = next; + } while (cur); + } + + free(ccache); + return MS_SUCCESS; +} + +typedef struct { + cairo_surface_t *surface; + cairo_t *cr; + bufferObj *outputStream; + int use_alpha; +} cairo_renderer; + +#define CAIRO_RENDERER(im) ((cairo_renderer *)(im->img.plugin)) + +int freeImageCairo(imageObj *img) { + cairo_renderer *r = CAIRO_RENDERER(img); + if (r) { + cairo_destroy(r->cr); + cairo_surface_finish(r->surface); + cairo_surface_destroy(r->surface); + if (r->outputStream) { + msBufferFree(r->outputStream); + free(r->outputStream); + } + free(r); + } + return MS_SUCCESS; +} + +static cairoFaceCache *getCairoFontFace(cairoCacheData *cache, FT_Face ftface) { + cairoFaceCache *cur = cache->cairofacecache; + while (cur) { + if (cur->ftface == ftface) + return cur; + cur = cur->next; + } + cur = msSmallMalloc(sizeof(cairoFaceCache)); + cur->next = cache->cairofacecache; + cache->cairofacecache = cur; + cur->ftface = ftface; + cur->face = cairo_ft_font_face_create_for_ft_face(ftface, 0); + cur->options = cairo_font_options_create(); + cairo_font_options_set_hint_style(cur->options, CAIRO_HINT_STYLE_NONE); + return cur; +} + +#define msCairoSetSourceColor(cr, c) \ + cairo_set_source_rgba((cr), (c)->red / 255.0, (c)->green / 255.0, \ + (c)->blue / 255.0, (c)->alpha / 255.0); + +int renderLineCairo(imageObj *img, shapeObj *p, strokeStyleObj *stroke) { + int i, j; + cairo_renderer *r = CAIRO_RENDERER(img); + assert(stroke->color); + cairo_new_path(r->cr); + msCairoSetSourceColor(r->cr, stroke->color); + for (i = 0; i < p->numlines; i++) { + lineObj *l = &(p->line[i]); + if (l->numpoints == 0) + continue; + cairo_move_to(r->cr, l->point[0].x, l->point[0].y); + for (j = 1; j < l->numpoints; j++) { + cairo_line_to(r->cr, l->point[j].x, l->point[j].y); + } + } + if (stroke->patternlength > 0) { + cairo_set_dash(r->cr, stroke->pattern, stroke->patternlength, + -stroke->patternoffset); + } + switch (stroke->linecap) { + case MS_CJC_BUTT: + cairo_set_line_cap(r->cr, CAIRO_LINE_CAP_BUTT); + break; + case MS_CJC_SQUARE: + cairo_set_line_cap(r->cr, CAIRO_LINE_CAP_SQUARE); + break; + case MS_CJC_ROUND: + case MS_CJC_NONE: + default: + cairo_set_line_cap(r->cr, CAIRO_LINE_CAP_ROUND); + } + cairo_set_line_width(r->cr, stroke->width); + cairo_stroke(r->cr); + if (stroke->patternlength > 0) { + cairo_set_dash(r->cr, stroke->pattern, 0, 0); + } + return MS_SUCCESS; +} + +int renderPolygonCairo(imageObj *img, shapeObj *p, colorObj *c) { + cairo_renderer *r = CAIRO_RENDERER(img); + int i, j; + cairo_new_path(r->cr); + cairo_set_fill_rule(r->cr, CAIRO_FILL_RULE_EVEN_ODD); + msCairoSetSourceColor(r->cr, c); + for (i = 0; i < p->numlines; i++) { + lineObj *l = &(p->line[i]); + cairo_move_to(r->cr, l->point[0].x, l->point[0].y); + for (j = 1; j < l->numpoints; j++) { + cairo_line_to(r->cr, l->point[j].x, l->point[j].y); + } + cairo_close_path(r->cr); + } + cairo_fill(r->cr); + return MS_SUCCESS; +} + +int renderPolygonTiledCairo(imageObj *img, shapeObj *p, imageObj *tile) { + int i, j; + cairo_renderer *r = CAIRO_RENDERER(img); + cairo_renderer *tileRenderer = CAIRO_RENDERER(tile); + cairo_pattern_t *pattern = + cairo_pattern_create_for_surface(tileRenderer->surface); + cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT); + + cairo_set_source(r->cr, pattern); + for (i = 0; i < p->numlines; i++) { + lineObj *l = &(p->line[i]); + cairo_move_to(r->cr, l->point[0].x, l->point[0].y); + for (j = 1; j < l->numpoints; j++) { + cairo_line_to(r->cr, l->point[j].x, l->point[j].y); + } + /* cairo_close_path(r->cr); */ + } + cairo_fill(r->cr); + cairo_pattern_destroy(pattern); + return MS_SUCCESS; +} + +cairo_surface_t *createSurfaceFromBuffer(rasterBufferObj *b) { + assert(b->type == MS_BUFFER_BYTE_RGBA); + return cairo_image_surface_create_for_data(b->data.rgba.pixels, + CAIRO_FORMAT_ARGB32, b->width, + b->height, b->data.rgba.row_step); +} + +int renderPixmapSymbolCairo(imageObj *img, double x, double y, + symbolObj *symbol, symbolStyleObj *style) { + cairo_renderer *r = CAIRO_RENDERER(img); + cairo_surface_t *im; + rasterBufferObj *b = symbol->pixmap_buffer; + assert(b); + if (!symbol->renderer_cache) { + symbol->renderer_cache = (void *)createSurfaceFromBuffer(b); + } + assert(symbol->renderer_cache); + im = (cairo_surface_t *)symbol->renderer_cache; + cairo_save(r->cr); + if (style->rotation != 0 || style->scale != 1) { + cairo_translate(r->cr, x, y); + cairo_rotate(r->cr, -style->rotation); + cairo_scale(r->cr, style->scale, style->scale); + cairo_translate(r->cr, -0.5 * b->width, -0.5 * b->height); + } else { + cairo_translate(r->cr, MS_NINT(x - 0.5 * b->width), + MS_NINT(y - 0.5 * b->height)); + } + cairo_set_source_surface(r->cr, im, 0, 0); + cairo_paint(r->cr); + cairo_restore(r->cr); + return MS_SUCCESS; +} + +int renderVectorSymbolCairo(imageObj *img, double x, double y, + symbolObj *symbol, symbolStyleObj *style) { + cairo_renderer *r = CAIRO_RENDERER(img); + double ox = symbol->sizex * 0.5, oy = symbol->sizey * 0.5; + int is_new = 1, i; + cairo_new_path(r->cr); + cairo_save(r->cr); + cairo_translate(r->cr, x, y); + cairo_scale(r->cr, style->scale, style->scale); + cairo_rotate(r->cr, -style->rotation); + cairo_translate(r->cr, -ox, -oy); + for (i = 0; i < symbol->numpoints; i++) { + if ((symbol->points[i].x == -99) && + (symbol->points[i].y == -99)) { /* (PENUP) */ + is_new = 1; + } else { + if (is_new) { + cairo_move_to(r->cr, symbol->points[i].x, symbol->points[i].y); + is_new = 0; + } else { + cairo_line_to(r->cr, symbol->points[i].x, symbol->points[i].y); + } + } + } + cairo_restore(r->cr); + if (style->color) { + msCairoSetSourceColor(r->cr, style->color); + cairo_fill_preserve(r->cr); + } + if (style->outlinewidth > 0) { + msCairoSetSourceColor(r->cr, style->outlinecolor); + cairo_set_line_width(r->cr, style->outlinewidth); + cairo_stroke_preserve(r->cr); + } + cairo_new_path(r->cr); + return MS_SUCCESS; +} + +#if defined(USE_SVG_CAIRO) || defined(USE_RSVG) +struct svg_symbol_cache { + rasterBufferObj *pixmap_buffer; +#ifdef USE_RSVG + RsvgHandle *svgc; +#else + svg_cairo_t *svgc; +#endif + double scale, rotation; +}; +#endif + +int renderSVGSymbolCairo(imageObj *img, double x, double y, symbolObj *symbol, + symbolStyleObj *style) { +#if defined(USE_SVG_CAIRO) || defined(USE_RSVG) + struct svg_symbol_cache *cache; + cairo_renderer *r = CAIRO_RENDERER(img); + + msPreloadSVGSymbol(symbol); + assert(symbol->renderer_cache); + cache = symbol->renderer_cache; + + cairo_save(r->cr); + cairo_translate(r->cr, x, y); + cairo_scale(r->cr, style->scale, style->scale); + + if (style->rotation != 0) { + cairo_rotate(r->cr, -style->rotation); + cairo_translate(r->cr, -(int)(symbol->sizex / 2), + -(int)(symbol->sizey / 2)); + } else + cairo_translate(r->cr, -(int)(symbol->sizex / 2), + -(int)(symbol->sizey / 2)); + +#ifdef USE_SVG_CAIRO + { + svg_cairo_status_t status; + status = svg_cairo_render(cache->svgc, r->cr); + if (status != SVG_CAIRO_STATUS_SUCCESS) { + cairo_restore(r->cr); + return MS_FAILURE; + } + } +#else + RsvgRectangle viewport = {0, 0, symbol->sizex, symbol->sizey}; + rsvg_handle_render_document(cache->svgc, r->cr, &viewport, NULL); +#endif + + cairo_restore(r->cr); + + return MS_SUCCESS; + +#else + (void)img; + (void)x; + (void)y; + (void)symbol; + (void)style; + msSetError(MS_MISCERR, + "SVG Symbols requested but is not built with libsvgcairo", + "renderSVGSymbolCairo()"); + return MS_FAILURE; +#endif +} + +int renderTileCairo(imageObj *img, imageObj *tile, double x, double y) { + cairo_renderer *r = CAIRO_RENDERER(img); + cairo_surface_t *im = CAIRO_RENDERER(tile)->surface; + int w = cairo_image_surface_get_width(im); + int h = cairo_image_surface_get_height(im); + cairo_save(r->cr); + cairo_translate(r->cr, MS_NINT(x - 0.5 * w), MS_NINT(y - 0.5 * h)); + cairo_set_source_surface(r->cr, im, 0, 0); + cairo_pattern_set_filter(cairo_get_source(r->cr), CAIRO_FILTER_NEAREST); + cairo_paint(r->cr); + cairo_restore(r->cr); + return MS_SUCCESS; +} + +int renderGlyphs2Cairo(imageObj *img, const textSymbolObj *ts, colorObj *c, + colorObj *oc, int ow, int isMarker) { + const textPathObj *tp = ts->textpath; + cairo_renderer *r = CAIRO_RENDERER(img); + cairoCacheData *cache = MS_IMAGE_RENDERER_CACHE(img); + cairoFaceCache *cairo_face = NULL; + FT_Face prevface = NULL; + int g; + (void)isMarker; + + cairo_set_font_size(r->cr, MS_NINT(tp->glyph_size * 96.0 / 72.0)); + for (g = 0; g < tp->numglyphs; g++) { + glyphObj *gl = &tp->glyphs[g]; + cairo_glyph_t glyph; + /* load the glyph's face into cairo, if not already present */ + if (gl->face->face != prevface) { + cairo_face = getCairoFontFace(cache, gl->face->face); + cairo_set_font_face(r->cr, cairo_face->face); + cairo_set_font_options(r->cr, cairo_face->options); + prevface = gl->face->face; + cairo_set_font_size(r->cr, MS_NINT(tp->glyph_size * 96.0 / 72.0)); + } + cairo_save(r->cr); + cairo_translate(r->cr, gl->pnt.x, gl->pnt.y); + if (gl->rot != 0.0) + cairo_rotate(r->cr, -gl->rot); + glyph.x = glyph.y = 0; + glyph.index = gl->glyph->key.codepoint; + cairo_glyph_path(r->cr, &glyph, 1); + cairo_restore(r->cr); + } + if (oc) { + cairo_save(r->cr); + msCairoSetSourceColor(r->cr, oc); + cairo_set_line_width(r->cr, ow + 1); + cairo_stroke_preserve(r->cr); + cairo_restore(r->cr); + } + if (c) { + msCairoSetSourceColor(r->cr, c); + cairo_fill(r->cr); + } + cairo_new_path(r->cr); + return MS_SUCCESS; +} + +cairo_status_t _stream_write_fn(void *b, const unsigned char *data, + unsigned int length) { + msBufferAppend((bufferObj *)b, (void *)data, length); + return CAIRO_STATUS_SUCCESS; +} + +imageObj *createImageCairo(int width, int height, outputFormatObj *format, + colorObj *bg) { + imageObj *image = NULL; + cairo_renderer *r = NULL; + if (format->imagemode != MS_IMAGEMODE_RGB && + format->imagemode != MS_IMAGEMODE_RGBA) { + msSetError(MS_MISCERR, + "Cairo driver only supports RGB or RGBA pixel models.", + "msImageCreateCairo()"); + return image; + } + if (width > 0 && height > 0) { + image = (imageObj *)calloc(1, sizeof(imageObj)); + r = (cairo_renderer *)calloc(1, sizeof(cairo_renderer)); + if (!strcasecmp(format->driver, "cairo/pdf")) { + r->outputStream = (bufferObj *)malloc(sizeof(bufferObj)); + msBufferInit(r->outputStream); + r->surface = cairo_pdf_surface_create_for_stream( + _stream_write_fn, r->outputStream, width, height); +#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 15, 10) + { + const char *msPDFCreationDate = + CPLGetConfigOption("MS_PDF_CREATION_DATE", NULL); + if (msPDFCreationDate) { + cairo_pdf_surface_set_metadata( + r->surface, CAIRO_PDF_METADATA_CREATE_DATE, msPDFCreationDate); + } + } +#endif + } else if (!strcasecmp(format->driver, "cairo/svg")) { + r->outputStream = (bufferObj *)malloc(sizeof(bufferObj)); + msBufferInit(r->outputStream); + r->surface = cairo_svg_surface_create_for_stream( + _stream_write_fn, r->outputStream, width, height); + } else if (!strcasecmp(format->driver, "cairo/winGDI") && format->device) { +#if CAIRO_HAS_WIN32_SURFACE + r->outputStream = NULL; + r->surface = cairo_win32_surface_create(format->device); +#else + msSetError(MS_RENDERERERR, + "Cannot create cairo image. Cairo was not compiled with " + "support for the win32 backend.", + "msImageCreateCairo()"); +#endif + } else if (!strcasecmp(format->driver, "cairo/winGDIPrint") && + format->device) { +#if CAIRO_HAS_WIN32_SURFACE + r->outputStream = NULL; + r->surface = cairo_win32_printing_surface_create(format->device); +#else + msSetError(MS_RENDERERERR, + "Cannot create cairo image. Cairo was not compiled with " + "support for the win32 backend.", + "msImageCreateCairo()"); +#endif + } else { + r->outputStream = NULL; + r->surface = + cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); + } + r->cr = cairo_create(r->surface); + if (format->transparent || !bg || !MS_VALID_COLOR(*bg)) { + r->use_alpha = 1; + cairo_set_source_rgba(r->cr, 0, 0, 0, 0); + } else { + r->use_alpha = 0; + msCairoSetSourceColor(r->cr, bg); + } + cairo_save(r->cr); + cairo_set_operator(r->cr, CAIRO_OPERATOR_SOURCE); + cairo_paint(r->cr); + cairo_restore(r->cr); + + cairo_set_line_cap(r->cr, CAIRO_LINE_CAP_ROUND); + cairo_set_line_join(r->cr, CAIRO_LINE_JOIN_ROUND); + image->img.plugin = (void *)r; + } else { + msSetError(MS_RENDERERERR, "Cannot create cairo image of size %dx%d.", + "msImageCreateCairo()", width, height); + } + return image; +} + +/* msSaveImagePostPDFProcessing() will call the GDAL PDF driver to add + * geospatial */ +/* information to the regular PDF generated by cairo. This is only triggered if + * the */ +/* GEO_ENCODING outputformat option is set (to ISO32000 or OGC_BP). Additional + */ +/* options can be provided by specifying outputformat options starting with */ +/* METADATA_ITEM: prefix. For example METADATA_ITEM:PRODUCER=MapServer */ +/* Those options are AUTHOR, CREATOR, CREATION_DATE, KEYWORDS, PRODUCER, + * SUBJECT, TITLE */ +/* See http://gdal.org/frmt_pdf.html documentation. */ + +static void msTransformToGeospatialPDF(imageObj *img, mapObj *map, + cairo_renderer *r) { + GDALDatasetH hDS = NULL; + const char *pszGEO_ENCODING = NULL; + GDALDriverH hPDFDriver = NULL; + const char *pszVirtualIO = NULL; + int bVirtualIO = FALSE; + char *pszTmpFilename = NULL; + VSILFILE *fp = NULL; + + if (map == NULL) + return; + + pszGEO_ENCODING = msGetOutputFormatOption(img->format, "GEO_ENCODING", NULL); + if (pszGEO_ENCODING == NULL) + return; + + msGDALInitialize(); + + hPDFDriver = GDALGetDriverByName("PDF"); + if (hPDFDriver == NULL) + return; + + /* When compiled against libpoppler, the PDF driver is VirtualIO capable */ + /* but not, when it is compiled against libpodofo. */ + pszVirtualIO = GDALGetMetadataItem(hPDFDriver, GDAL_DCAP_VIRTUALIO, NULL); + if (pszVirtualIO) + bVirtualIO = CSLTestBoolean(pszVirtualIO); + + if (bVirtualIO) + pszTmpFilename = msTmpFile(map, NULL, "/vsimem/mscairopdf/", "pdf"); + else + pszTmpFilename = msTmpFile(map, map->mappath, NULL, "pdf"); + + /* Copy content of outputStream buffer into file */ + fp = VSIFOpenL(pszTmpFilename, "wb"); + if (fp == NULL) { + msFree(pszTmpFilename); + return; + } + VSIFWriteL(r->outputStream->data, 1, r->outputStream->size, fp); + VSIFCloseL(fp); + fp = NULL; + + hDS = GDALOpen(pszTmpFilename, GA_Update); + if (hDS != NULL) { + char *pszWKT = msProjectionObj2OGCWKT(&(map->projection)); + if (pszWKT != NULL) { + double adfGeoTransform[6]; + int i; + + /* Add user-specified options */ + for (i = 0; i < img->format->numformatoptions; i++) { + const char *pszOption = img->format->formatoptions[i]; + if (strncasecmp(pszOption, "METADATA_ITEM:", 14) == 0) { + char *pszKey = NULL; + const char *pszValue = CPLParseNameValue(pszOption + 14, &pszKey); + if (pszKey != NULL) { + GDALSetMetadataItem(hDS, pszKey, pszValue, NULL); + CPLFree(pszKey); + } + } + } + + /* We need to rescale the geotransform because GDAL will not necessary */ + /* open the PDF with the DPI that was used to generate it */ + memcpy(adfGeoTransform, map->gt.geotransform, 6 * sizeof(double)); + adfGeoTransform[1] = + adfGeoTransform[1] * map->width / GDALGetRasterXSize(hDS); + adfGeoTransform[5] = + adfGeoTransform[5] * map->height / GDALGetRasterYSize(hDS); + GDALSetGeoTransform(hDS, adfGeoTransform); + GDALSetProjection(hDS, pszWKT); + + msFree(pszWKT); + pszWKT = NULL; + + CPLSetThreadLocalConfigOption("GDAL_PDF_GEO_ENCODING", pszGEO_ENCODING); + + GDALClose(hDS); + hDS = NULL; + + CPLSetThreadLocalConfigOption("GDAL_PDF_GEO_ENCODING", NULL); + + /* We need to replace the buffer with the content of the GDAL file */ + fp = VSIFOpenL(pszTmpFilename, "rb"); + if (fp != NULL) { + int nFileSize; + + VSIFSeekL(fp, 0, SEEK_END); + nFileSize = (int)VSIFTellL(fp); + + msBufferResize(r->outputStream, nFileSize); + + VSIFSeekL(fp, 0, SEEK_SET); + r->outputStream->size = + VSIFReadL(r->outputStream->data, 1, nFileSize, fp); + + VSIFCloseL(fp); + fp = NULL; + } + } + } + + if (hDS != NULL) + GDALClose(hDS); + + VSIUnlink(pszTmpFilename); + + msFree(pszTmpFilename); +} + +int saveImageCairo(imageObj *img, mapObj *map, FILE *fp, + outputFormatObj *format_unused) { + (void)format_unused; + cairo_renderer *r = CAIRO_RENDERER(img); + if (!strcasecmp(img->format->driver, "cairo/pdf") || + !strcasecmp(img->format->driver, "cairo/svg")) { + cairo_surface_finish(r->surface); + + if (map != NULL && !strcasecmp(img->format->driver, "cairo/pdf")) + msTransformToGeospatialPDF(img, map, r); + + msIO_fwrite(r->outputStream->data, r->outputStream->size, 1, fp); + } else { + /* not supported */ + } + return MS_SUCCESS; +} + +unsigned char *saveImageBufferCairo(imageObj *img, int *size_ptr, + outputFormatObj *format_unused) { + (void)format_unused; + cairo_renderer *r = CAIRO_RENDERER(img); + unsigned char *data; + assert(!strcasecmp(img->format->driver, "cairo/pdf") || + !strcasecmp(img->format->driver, "cairo/svg")); + cairo_surface_finish(r->surface); + data = msSmallMalloc(r->outputStream->size); + memcpy(data, r->outputStream->data, r->outputStream->size); + *size_ptr = (int)r->outputStream->size; + return data; +} + +int renderEllipseSymbolCairo(imageObj *img, double x, double y, + symbolObj *symbol, symbolStyleObj *style) { + cairo_renderer *r = CAIRO_RENDERER(img); + + cairo_save(r->cr); + cairo_set_line_cap(r->cr, CAIRO_LINE_CAP_BUTT); + cairo_set_line_join(r->cr, CAIRO_LINE_JOIN_MITER); + cairo_translate(r->cr, x, y); + cairo_rotate(r->cr, -style->rotation); + cairo_scale(r->cr, symbol->sizex * style->scale / 2, + symbol->sizey * style->scale / 2); + cairo_arc(r->cr, 0, 0, 1, 0, 2 * MS_PI); + cairo_restore(r->cr); + if (style->color) { + msCairoSetSourceColor(r->cr, style->color); + cairo_fill_preserve(r->cr); + } + if (style->outlinewidth > 0) { + cairo_set_line_width(r->cr, style->outlinewidth); + msCairoSetSourceColor(r->cr, style->outlinecolor); + cairo_stroke_preserve(r->cr); + } + cairo_new_path(r->cr); + return MS_SUCCESS; +} + +int startLayerVectorCairo(imageObj *img, mapObj *map, layerObj *layer) { + (void)map; + if (layer->compositer && layer->compositer->opacity < 100) { + cairo_renderer *r = CAIRO_RENDERER(img); + cairo_push_group(r->cr); + } + return MS_SUCCESS; +} + +int closeLayerVectorCairo(imageObj *img, mapObj *map, layerObj *layer) { + (void)map; + if (layer->compositer && layer->compositer->opacity < 100) { + cairo_renderer *r = CAIRO_RENDERER(img); + cairo_pop_group_to_source(r->cr); + cairo_paint_with_alpha(r->cr, layer->compositer->opacity * 0.01); + } + return MS_SUCCESS; +} + +int startLayerRasterCairo(imageObj *img, mapObj *map, layerObj *layer) { + (void)img; + (void)map; + (void)layer; + return MS_SUCCESS; +} + +int closeLayerRasterCairo(imageObj *img, mapObj *map, layerObj *layer) { + (void)img; + (void)map; + (void)layer; + return MS_SUCCESS; +} + +int getRasterBufferHandleCairo(imageObj *img, rasterBufferObj *rb) { + unsigned char *pb; + cairo_renderer *r = CAIRO_RENDERER(img); + rb->type = MS_BUFFER_BYTE_RGBA; + pb = cairo_image_surface_get_data(r->surface); + rb->data.rgba.pixels = pb; + rb->data.rgba.row_step = cairo_image_surface_get_stride(r->surface); + rb->data.rgba.pixel_step = 4; + rb->width = cairo_image_surface_get_width(r->surface); + rb->height = cairo_image_surface_get_height(r->surface); + rb->data.rgba.r = &(pb[2]); + rb->data.rgba.g = &(pb[1]); + rb->data.rgba.b = &(pb[0]); + if (r->use_alpha) + rb->data.rgba.a = &(pb[3]); + else + rb->data.rgba.a = NULL; + return MS_SUCCESS; +} + +int getRasterBufferCopyCairo(imageObj *img, rasterBufferObj *rb) { + cairo_renderer *r = CAIRO_RENDERER(img); + unsigned char *pb; + rb->type = MS_BUFFER_BYTE_RGBA; + rb->data.rgba.row_step = cairo_image_surface_get_stride(r->surface); + rb->data.rgba.pixel_step = 4; + rb->width = cairo_image_surface_get_width(r->surface); + rb->height = cairo_image_surface_get_height(r->surface); + pb = (unsigned char *)malloc(sizeof(unsigned char) * rb->height * + rb->data.rgba.row_step); + memcpy(pb, cairo_image_surface_get_data(r->surface), + ((size_t)rb->height) * rb->data.rgba.row_step); + rb->data.rgba.pixels = pb; + rb->data.rgba.r = &(pb[2]); + rb->data.rgba.g = &(pb[1]); + rb->data.rgba.b = &(pb[0]); + if (r->use_alpha) + rb->data.rgba.a = &(pb[3]); + else + rb->data.rgba.a = NULL; + return MS_SUCCESS; +} + +static cairo_operator_t ms2cairo_compop(CompositingOperation op) { + switch (op) { + case MS_COMPOP_CLEAR: + return CAIRO_OPERATOR_CLEAR; + case MS_COMPOP_SRC: + return CAIRO_OPERATOR_SOURCE; + case MS_COMPOP_DST: + return CAIRO_OPERATOR_DEST; + case MS_COMPOP_SRC_OVER: + return CAIRO_OPERATOR_OVER; + case MS_COMPOP_DST_OVER: + return CAIRO_OPERATOR_DEST_OVER; + case MS_COMPOP_SRC_IN: + return CAIRO_OPERATOR_IN; + case MS_COMPOP_DST_IN: + return CAIRO_OPERATOR_DEST_IN; + case MS_COMPOP_SRC_OUT: + return CAIRO_OPERATOR_OUT; + case MS_COMPOP_DST_OUT: + return CAIRO_OPERATOR_DEST_OUT; + case MS_COMPOP_SRC_ATOP: + return CAIRO_OPERATOR_ATOP; + case MS_COMPOP_DST_ATOP: + return CAIRO_OPERATOR_DEST_ATOP; + case MS_COMPOP_XOR: + return CAIRO_OPERATOR_XOR; + case MS_COMPOP_PLUS: + return CAIRO_OPERATOR_ADD; + case MS_COMPOP_MULTIPLY: + return CAIRO_OPERATOR_MULTIPLY; + case MS_COMPOP_SCREEN: + return CAIRO_OPERATOR_SCREEN; + case MS_COMPOP_OVERLAY: + return CAIRO_OPERATOR_OVERLAY; + case MS_COMPOP_DARKEN: + return CAIRO_OPERATOR_DARKEN; + case MS_COMPOP_LIGHTEN: + return CAIRO_OPERATOR_LIGHTEN; + case MS_COMPOP_COLOR_DODGE: + return CAIRO_OPERATOR_COLOR_DODGE; + case MS_COMPOP_COLOR_BURN: + return CAIRO_OPERATOR_COLOR_BURN; + case MS_COMPOP_HARD_LIGHT: + return CAIRO_OPERATOR_HARD_LIGHT; + case MS_COMPOP_SOFT_LIGHT: + return CAIRO_OPERATOR_SOFT_LIGHT; + case MS_COMPOP_DIFFERENCE: + return CAIRO_OPERATOR_DIFFERENCE; + case MS_COMPOP_EXCLUSION: + return CAIRO_OPERATOR_EXCLUSION; + case MS_COMPOP_HSL_HUE: + return CAIRO_OPERATOR_HSL_HUE; + case MS_COMPOP_HSL_LUMINOSITY: + return CAIRO_OPERATOR_HSL_LUMINOSITY; + case MS_COMPOP_HSL_SATURATION: + return CAIRO_OPERATOR_HSL_SATURATION; + case MS_COMPOP_HSL_COLOR: + return CAIRO_OPERATOR_HSL_COLOR; + case MS_COMPOP_INVERT: + case MS_COMPOP_INVERT_RGB: + case MS_COMPOP_MINUS: + case MS_COMPOP_CONTRAST: + default: + return CAIRO_OPERATOR_OVER; + } +} + +int cairoCompositeRasterBuffer(imageObj *img, rasterBufferObj *rb, + CompositingOperation comp, int opacity) { + cairo_surface_t *src; + cairo_renderer *r; + if (rb->type != MS_BUFFER_BYTE_RGBA) { + return MS_FAILURE; + } + r = CAIRO_RENDERER(img); + + src = cairo_image_surface_create_for_data(rb->data.rgba.pixels, + CAIRO_FORMAT_ARGB32, rb->width, + rb->height, rb->data.rgba.row_step); + + cairo_set_source_surface(r->cr, src, 0, 0); + cairo_set_operator(r->cr, ms2cairo_compop(comp)); + cairo_paint_with_alpha(r->cr, opacity / 100.0); + cairo_surface_finish(src); + cairo_surface_destroy(src); + cairo_set_operator(r->cr, CAIRO_OPERATOR_OVER); + return MS_SUCCESS; +} + +int mergeRasterBufferCairo(imageObj *img, rasterBufferObj *rb, double opacity, + int srcX, int srcY, int dstX, int dstY, int width, + int height) { + cairo_surface_t *src; + cairo_renderer *r; + /* not implemented for src,dst,width and height */ + if (rb->type != MS_BUFFER_BYTE_RGBA) { + return MS_FAILURE; + } + r = CAIRO_RENDERER(img); + + src = cairo_image_surface_create_for_data(rb->data.rgba.pixels, + CAIRO_FORMAT_ARGB32, rb->width, + rb->height, rb->data.rgba.row_step); + + if (dstX || dstY || srcX || srcY || width != img->width || + height != img->height) { + cairo_set_source_surface(r->cr, src, dstX - srcX, dstY - srcY); + cairo_rectangle(r->cr, dstX, dstY, width, height); + cairo_fill(r->cr); + } else { + cairo_set_source_surface(r->cr, src, 0, 0); + cairo_paint_with_alpha(r->cr, opacity); + } + cairo_surface_finish(src); + cairo_surface_destroy(src); + return MS_SUCCESS; +} + +void freeSVGCache(symbolObj *s) { +#if defined(USE_SVG_CAIRO) || defined(USE_RSVG) + struct svg_symbol_cache *cache = s->renderer_cache; + if (!cache) + return; + assert(cache->svgc); +#ifdef USE_SVG_CAIRO + svg_cairo_destroy(cache->svgc); +#else +#if LIBRSVG_CHECK_VERSION(2, 35, 0) + g_object_unref(cache->svgc); +#else + rsvg_handle_free(cache->svgc); +#endif +#endif + if (cache->pixmap_buffer) { + msFreeRasterBuffer(cache->pixmap_buffer); + free(cache->pixmap_buffer); + } + msFree(s->renderer_cache); + s->renderer_cache = NULL; +#else + (void)s; +#endif +} + +int freeSymbolCairo(symbolObj *s) { + if (!s->renderer_cache) + return MS_SUCCESS; + switch (s->type) { + case MS_SYMBOL_VECTOR: + cairo_path_destroy(s->renderer_cache); + break; + case MS_SYMBOL_PIXMAP: + cairo_surface_destroy(s->renderer_cache); + break; + case MS_SYMBOL_SVG: + freeSVGCache(s); + break; + } + s->renderer_cache = NULL; + return MS_SUCCESS; +} + +int initializeRasterBufferCairo(rasterBufferObj *rb, int width, int height, + int mode) { + (void)mode; + rb->type = MS_BUFFER_BYTE_RGBA; + rb->width = width; + rb->height = height; + rb->data.rgba.pixel_step = 4; + rb->data.rgba.row_step = width * 4; + rb->data.rgba.pixels = (unsigned char *)calloc(((size_t)width) * height * 4, + sizeof(unsigned char)); + rb->data.rgba.r = &(rb->data.rgba.pixels[2]); + rb->data.rgba.g = &(rb->data.rgba.pixels[1]); + rb->data.rgba.b = &(rb->data.rgba.pixels[0]); + rb->data.rgba.a = &(rb->data.rgba.pixels[3]); + return MS_SUCCESS; +} + +int msPreloadSVGSymbol(symbolObj *symbol) { +#if defined(USE_SVG_CAIRO) || defined(USE_RSVG) + struct svg_symbol_cache *cache; + + if (!symbol->renderer_cache) { + cache = msSmallCalloc(1, sizeof(struct svg_symbol_cache)); + symbol->renderer_free_func = &freeSVGCache; + } else { + cache = symbol->renderer_cache; + } + if (cache->svgc) + return MS_SUCCESS; + +#ifdef USE_SVG_CAIRO + { + unsigned int svg_width, svg_height; + int status; + status = svg_cairo_create(&cache->svgc); + if (status) { + msSetError(MS_RENDERERERR, "problem creating cairo svg", + "msPreloadSVGSymbol()"); + return MS_FAILURE; + } + status = svg_cairo_parse(cache->svgc, symbol->full_pixmap_path); + if (status) { + msSetError(MS_RENDERERERR, "problem parsing svg symbol", + "msPreloadSVGSymbol()"); + return MS_FAILURE; + } + svg_cairo_get_size(cache->svgc, &svg_width, &svg_height); + if (svg_width == 0 || svg_height == 0) { + msSetError(MS_RENDERERERR, "problem parsing svg symbol", + "msPreloadSVGSymbol()"); + return MS_FAILURE; + } + + symbol->sizex = svg_width; + symbol->sizey = svg_height; + } +#else + { + cache->svgc = rsvg_handle_new_from_file(symbol->full_pixmap_path, NULL); + if (!cache->svgc) { + msSetError(MS_RENDERERERR, "failed to load svg file %s", + "msPreloadSVGSymbol()", symbol->full_pixmap_path); + return MS_FAILURE; + } +#if LIBRSVG_CHECK_VERSION(2, 46, 0) + /* rsvg_handle_get_dimensions_sub() is deprecated since librsvg 2.46 */ + /* It seems rsvg_handle_get_intrinsic_dimensions() is the best equivalent */ + /* when the root node includes a width and height attributes in pixels + */ + gboolean has_width = FALSE; + RsvgLength width = {0, RSVG_UNIT_PX}; + gboolean has_height = FALSE; + RsvgLength height = {0, RSVG_UNIT_PX}; + gboolean has_viewbox = FALSE; + RsvgRectangle viewbox; + rsvg_handle_get_intrinsic_dimensions(cache->svgc, &has_width, &width, + &has_height, &height, &has_viewbox, + &viewbox); + if (has_width && width.unit == RSVG_UNIT_PX && has_height && + height.unit == RSVG_UNIT_PX) { + symbol->sizex = width.length; + symbol->sizey = height.length; + } else if (!has_viewbox) { + RsvgRectangle ink_rect = {0, 0, 0, 0}; + rsvg_handle_get_geometry_for_element(cache->svgc, NULL, &ink_rect, NULL, + NULL); + symbol->sizex = ink_rect.width; + symbol->sizey = ink_rect.height; + } else { + symbol->sizex = viewbox.width; + symbol->sizey = viewbox.height; + } +#else + RsvgDimensionData dim; + rsvg_handle_get_dimensions_sub(cache->svgc, &dim, NULL); + symbol->sizex = dim.width; + symbol->sizey = dim.height; +#endif + } +#endif + + symbol->renderer_cache = cache; + + return MS_SUCCESS; + +#else + (void)symbol; + msSetError(MS_MISCERR, + "SVG Symbols requested but is not built with libsvgcairo", + "msPreloadSVGSymbol()"); + return MS_FAILURE; +#endif +} + +int msRenderRasterizedSVGSymbol(imageObj *img, double x, double y, + symbolObj *symbol, symbolStyleObj *style) { + +#if defined(USE_SVG_CAIRO) || defined(USE_RSVG) + struct svg_symbol_cache *svg_cache; + symbolStyleObj pixstyle; + symbolObj pixsymbol; + int status; + + if (MS_SUCCESS != msPreloadSVGSymbol(symbol)) + return MS_FAILURE; + svg_cache = (struct svg_symbol_cache *)symbol->renderer_cache; + + // already rendered at the right size and scale? return + if (svg_cache->scale != style->scale || + svg_cache->rotation != style->rotation) { + cairo_t *cr; + cairo_surface_t *surface; + unsigned char *pb; + int width, height, surface_w, surface_h; + /* need to recompute the pixmap */ + if (svg_cache->pixmap_buffer) { + msFreeRasterBuffer(svg_cache->pixmap_buffer); + } else { + svg_cache->pixmap_buffer = msSmallCalloc(1, sizeof(rasterBufferObj)); + } + + // increase pixmap size to accommodate scaling/rotation + if (style->scale != 1.0) { + width = surface_w = (symbol->sizex * style->scale + 0.5); + height = surface_h = (symbol->sizey * style->scale + 0.5); + } else { + width = surface_w = symbol->sizex; + height = surface_h = symbol->sizey; + } + if (style->rotation != 0) { + surface_w = surface_h = MS_NINT(MS_MAX(height, width) * 1.415); + } + + surface = + cairo_image_surface_create(CAIRO_FORMAT_ARGB32, surface_w, surface_h); + cr = cairo_create(surface); + + if (style->rotation != 0) { + cairo_translate(cr, surface_w / 2, surface_h / 2); + cairo_rotate(cr, -style->rotation); + cairo_translate(cr, -width / 2, -height / 2); + } + if (style->scale != 1.0) { + cairo_scale(cr, style->scale, style->scale); + } +#ifdef USE_SVG_CAIRO + if (svg_cairo_render(svg_cache->svgc, cr) != SVG_CAIRO_STATUS_SUCCESS) { + return MS_FAILURE; + } +#else + RsvgRectangle viewport = {0, 0, width, height}; + rsvg_handle_render_document(svg_cache->svgc, cr, &viewport, NULL); +#endif + pb = cairo_image_surface_get_data(surface); + + // set up raster + initializeRasterBufferCairo(svg_cache->pixmap_buffer, surface_w, surface_h, + 0); + memcpy(svg_cache->pixmap_buffer->data.rgba.pixels, pb, + sizeof(unsigned char) * surface_w * surface_h * 4); + svg_cache->scale = style->scale; + svg_cache->rotation = style->rotation; + cairo_destroy(cr); + cairo_surface_destroy(surface); + } + + pixstyle = *style; + pixstyle.rotation = 0.0; + pixstyle.scale = 1.0; + + pixsymbol.pixmap_buffer = svg_cache->pixmap_buffer; + pixsymbol.type = MS_SYMBOL_PIXMAP; + + if (svg_cache->pixmap_buffer->height && svg_cache->pixmap_buffer->width) + status = MS_IMAGE_RENDERER(img)->renderPixmapSymbol(img, x, y, &pixsymbol, + &pixstyle); + else { + msDebug("SVG symbol with too small size to be rendered"); + status = MS_SUCCESS; + } + MS_IMAGE_RENDERER(img)->freeSymbol(&pixsymbol); + return status; +#else + (void)img; + (void)x; + (void)y; + (void)symbol; + (void)style; + msSetError( + MS_MISCERR, + "SVG Symbols requested but MapServer is not built with libsvgcairo", + "renderSVGSymbolCairo()"); + return MS_FAILURE; +#endif +} + +void msCairoCleanup() { cairo_debug_reset_static_data(); } + +#endif /*USE_CAIRO*/ + +int msPopulateRendererVTableCairoRaster(rendererVTableObj *renderer) { +#ifdef USE_CAIRO + renderer->supports_pixel_buffer = 1; + renderer->compositeRasterBuffer = cairoCompositeRasterBuffer; + renderer->supports_svg = 1; + renderer->default_transform_mode = MS_TRANSFORM_SIMPLIFY; + initializeCache(&MS_RENDERER_CACHE(renderer)); + renderer->startLayer = startLayerRasterCairo; + renderer->endLayer = closeLayerRasterCairo; + renderer->renderLineTiled = NULL; + renderer->renderLine = &renderLineCairo; + renderer->createImage = &createImageCairo; + renderer->saveImage = &saveImageCairo; + renderer->getRasterBufferHandle = &getRasterBufferHandleCairo; + renderer->getRasterBufferCopy = &getRasterBufferCopyCairo; + renderer->renderPolygon = &renderPolygonCairo; + renderer->renderGlyphs = &renderGlyphs2Cairo; + renderer->freeImage = &freeImageCairo; + renderer->renderEllipseSymbol = &renderEllipseSymbolCairo; + renderer->renderVectorSymbol = &renderVectorSymbolCairo; + renderer->renderSVGSymbol = &renderSVGSymbolCairo; + renderer->renderPixmapSymbol = &renderPixmapSymbolCairo; + renderer->mergeRasterBuffer = &mergeRasterBufferCairo; + renderer->renderTile = &renderTileCairo; + renderer->loadImageFromFile = &msLoadMSRasterBufferFromFile; + renderer->renderPolygonTiled = &renderPolygonTiledCairo; + renderer->freeSymbol = &freeSymbolCairo; + renderer->cleanup = &cleanupCairo; + return MS_SUCCESS; +#else + (void)renderer; + msSetError(MS_MISCERR, "Cairo Driver requested but MapServer is not built in", + "msPopulateRendererVTableCairoRaster()"); + return MS_FAILURE; +#endif +} + +int populateRendererVTableCairoVector(rendererVTableObj *renderer) { +#ifdef USE_CAIRO + renderer->use_imagecache = 0; + renderer->supports_pixel_buffer = 0; + renderer->compositeRasterBuffer = NULL; + renderer->supports_svg = 1; + renderer->default_transform_mode = MS_TRANSFORM_SIMPLIFY; + initializeCache(&MS_RENDERER_CACHE(renderer)); + renderer->startLayer = startLayerVectorCairo; + renderer->endLayer = closeLayerVectorCairo; + renderer->renderLine = &renderLineCairo; + renderer->renderLineTiled = NULL; + renderer->createImage = &createImageCairo; + renderer->saveImage = &saveImageCairo; + renderer->saveImageBuffer = &saveImageBufferCairo; + renderer->getRasterBufferHandle = &getRasterBufferHandleCairo; + renderer->renderPolygon = &renderPolygonCairo; + renderer->renderGlyphs = &renderGlyphs2Cairo; + renderer->freeImage = &freeImageCairo; + renderer->renderEllipseSymbol = &renderEllipseSymbolCairo; + renderer->renderVectorSymbol = &renderVectorSymbolCairo; + renderer->renderSVGSymbol = &renderSVGSymbolCairo; + renderer->renderPixmapSymbol = &renderPixmapSymbolCairo; + renderer->loadImageFromFile = &msLoadMSRasterBufferFromFile; + renderer->mergeRasterBuffer = &mergeRasterBufferCairo; + renderer->initializeRasterBuffer = initializeRasterBufferCairo; + renderer->renderTile = &renderTileCairo; + renderer->renderPolygonTiled = &renderPolygonTiledCairo; + renderer->freeSymbol = &freeSymbolCairo; + renderer->cleanup = &cleanupCairo; + return MS_SUCCESS; +#else + (void)renderer; + msSetError(MS_MISCERR, "Cairo Driver requested but MapServer is not built in", + "msPopulateRendererVTableCairoRaster()"); + return MS_FAILURE; +#endif +} + +int msPopulateRendererVTableCairoSVG(rendererVTableObj *renderer) { + return populateRendererVTableCairoVector(renderer); +} +int msPopulateRendererVTableCairoPDF(rendererVTableObj *renderer) { + return populateRendererVTableCairoVector(renderer); +} diff --git a/src/mapchart.c b/src/mapchart.c new file mode 100644 index 0000000000..97042c9de8 --- /dev/null +++ b/src/mapchart.c @@ -0,0 +1,731 @@ +/****************************************************************************** + * $Id$ + * + * Project: MapServer + * Purpose: Implementation of dynamic charting (MS-RFC-29) + * Author: Thomas Bonfort ( thomas.bonfort[at]gmail.com ) + * + ****************************************************************************** + * Copyright (c) 1996-2007 Regents of the University of Minnesota. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + ****************************************************************************/ + +#include "mapserver.h" + +#define MS_CHART_TYPE_PIE 1 +#define MS_CHART_TYPE_BAR 2 +#define MS_CHART_TYPE_VBAR 3 + +/* +** check if an object of width w and height h placed at point x,y can fit in an +*image of width mw and height mh +*/ +#define MS_CHART_FITS(x, y, w, h, mw, mh) \ + (((x) - (w) / 2. > 0.) && ((x) + (w) / 2. < (mw)) && \ + ((y) - (h) / 2. > 0.) && ((y) + (h) / 2.) < (mh)) + +/* +** find a point on a shape. check if it fits in image +** returns +** MS_SUCCESS and point coordinates in 'p' if chart fits in image +** MS_FAILURE if no point could be found +*/ +int findChartPoint(mapObj *map, shapeObj *shape, int width, int height, + pointObj *center) { + int middle, numpoints; + double invcellsize = 1.0 / map->cellsize; /*speed up MAP2IMAGE_X/Y_IC_DBL*/ + switch (shape->type) { + case MS_SHAPE_POINT: + center->x = MS_MAP2IMAGE_X_IC_DBL(shape->line[0].point[0].x, + map->extent.minx, invcellsize); + center->y = MS_MAP2IMAGE_Y_IC_DBL(shape->line[0].point[0].y, + map->extent.maxy, invcellsize); + + if (MS_CHART_FITS(center->x, center->y, width, height, map->width, + map->height)) + return MS_SUCCESS; + else + return MS_FAILURE; + break; + case MS_SHAPE_LINE: + /*loop through line segments starting from middle (alternate between before + *and after middle point) *first segment that fits is chosen + */ + middle = shape->line[0].numpoints / 2; /*start with middle segment of line*/ + numpoints = shape->line[0].numpoints; + if (1 <= middle) { + int idx = middle + 1; + if (idx < numpoints) { + center->x = + (shape->line[0].point[idx - 1].x + shape->line[0].point[idx].x) / + 2.; + center->y = + (shape->line[0].point[idx - 1].y + shape->line[0].point[idx].y) / + 2.; + center->x = + MS_MAP2IMAGE_X_IC_DBL(center->x, map->extent.minx, invcellsize); + center->y = + MS_MAP2IMAGE_Y_IC_DBL(center->y, map->extent.maxy, invcellsize); + + if (MS_CHART_FITS(center->x, center->y, width, height, map->width, + map->height)) + return MS_SUCCESS; + + return MS_FAILURE; + } + idx = middle - 1; + center->x = + (shape->line[0].point[idx].x + shape->line[0].point[idx + 1].x) / 2; + center->y = + (shape->line[0].point[idx].y + shape->line[0].point[idx + 1].y) / 2; + center->x = + MS_MAP2IMAGE_X_IC_DBL(center->x, map->extent.minx, invcellsize); + center->y = + MS_MAP2IMAGE_Y_IC_DBL(center->y, map->extent.maxy, invcellsize); + + if (MS_CHART_FITS(center->x, center->y, width, height, map->width, + map->height)) + return MS_SUCCESS; + return MS_FAILURE; + } + return MS_FAILURE; + break; + case MS_SHAPE_POLYGON: + msPolygonLabelPoint(shape, center, -1); + center->x = MS_MAP2IMAGE_X_IC_DBL(center->x, map->extent.minx, invcellsize); + center->y = MS_MAP2IMAGE_Y_IC_DBL(center->y, map->extent.maxy, invcellsize); + + if (MS_CHART_FITS(center->x, center->y, width, height, map->width, + map->height)) + return MS_SUCCESS; + else + return MS_FAILURE; + break; + default: + return MS_FAILURE; + } +} + +int WARN_UNUSED drawRectangle(mapObj *map, imageObj *image, double mx, + double my, double Mx, double My, + styleObj *style) { + shapeObj shape; + lineObj line; + pointObj point[5]; + line.point = point; + line.numpoints = 5; + shape.line = &line; + shape.numlines = 1; + + point[0].x = point[4].x = point[3].x = mx; + point[0].y = point[4].y = point[1].y = my; + /* cppcheck-suppress unreadVariable */ + point[1].x = point[2].x = Mx; + /* cppcheck-suppress unreadVariable */ + point[2].y = point[3].y = My; + + return msDrawShadeSymbol(map, image, &shape, style, 1.0); +} + +int WARN_UNUSED msDrawVBarChart(mapObj *map, imageObj *image, pointObj *center, + double *values, styleObj **styles, + int numvalues, double barWidth) { + + int c; + double left, cur; /*shortcut to pixel boundaries of the chart*/ + double height = 0; + + for (c = 0; c < numvalues; c++) { + height += values[c]; + } + + cur = center->y + height / 2.; + left = center->x - barWidth / 2.; + + for (c = 0; c < numvalues; c++) { + if (MS_UNLIKELY(MS_FAILURE == drawRectangle(map, image, left, cur, + left + barWidth, + cur - values[c], styles[c]))) + return MS_FAILURE; + cur -= values[c]; + } + return MS_SUCCESS; +} + +int msDrawBarChart(mapObj *map, imageObj *image, pointObj *center, + double *values, styleObj **styles, int numvalues, + double width, double height, double *maxVal, double *minVal, + double barWidth) { + + double upperLimit, lowerLimit; + double shapeMaxVal, shapeMinVal, pixperval; + int c; + double vertOrigin, vertOriginClipped, horizStart, y; + double left, top, bottom; /*shortcut to pixel boundaries of the chart*/ + + top = center->y - height / 2.; + bottom = center->y + height / 2.; + left = center->x - width / 2.; + + shapeMaxVal = shapeMinVal = values[0]; + for (c = 1; c < numvalues; c++) { + if (maxVal == NULL || minVal == NULL) { /*compute bounds if not specified*/ + if (values[c] > shapeMaxVal) + shapeMaxVal = values[c]; + if (values[c] < shapeMinVal) + shapeMinVal = values[c]; + } + } + + /* + * use specified bounds if wanted + * if not, always show the origin + */ + upperLimit = (maxVal != NULL) ? *maxVal : MS_MAX(shapeMaxVal, 0); + lowerLimit = (minVal != NULL) ? *minVal : MS_MIN(shapeMinVal, 0); + if (upperLimit == lowerLimit) { + /* treat the case where we would have an unspecified behavior */ + upperLimit += 0.5; + lowerLimit -= 0.5; + } + + pixperval = height / (upperLimit - lowerLimit); + vertOrigin = bottom + lowerLimit * pixperval; + vertOriginClipped = (vertOrigin < top) ? top + : (vertOrigin > bottom) ? bottom + : vertOrigin; + horizStart = left; + + for (c = 0; c < numvalues; c++) { + double barHeight = values[c] * pixperval; + /*clip bars*/ + y = ((vertOrigin - barHeight) < top) ? top + : (vertOrigin - barHeight > bottom) ? bottom + : vertOrigin - barHeight; + if (y != vertOriginClipped) { /*don't draw bars of height == 0 (i.e. either + values==0, or clipped)*/ + if (values[c] > 0) { + if (MS_UNLIKELY(MS_FAILURE == drawRectangle(map, image, horizStart, y, + horizStart + barWidth - 1, + vertOriginClipped, + styles[c]))) + return MS_FAILURE; + } else { + if (MS_UNLIKELY(MS_FAILURE == + drawRectangle(map, image, horizStart, vertOriginClipped, + horizStart + barWidth - 1, y, styles[c]))) + return MS_FAILURE; + } + } + horizStart += barWidth; + } + return MS_SUCCESS; +} + +int WARN_UNUSED msDrawPieChart(mapObj *map, imageObj *image, pointObj *center, + double diameter, double *values, + styleObj **styles, int numvalues) { + int i; + double dTotal = 0., start = 0; + + for (i = 0; i < numvalues; i++) { + if (values[i] < 0.) { + msSetError(MS_MISCERR, "cannot draw pie charts for negative values", + "msDrawPieChart()"); + return MS_FAILURE; + } + dTotal += values[i]; + } + + for (i = 0; i < numvalues; i++) { + double angle = values[i]; + if (angle == 0) + continue; /*no need to draw. causes artifacts with outlines*/ + angle *= 360.0 / dTotal; + if (MS_UNLIKELY(MS_FAILURE == msDrawPieSlice(map, image, center, styles[i], + diameter / 2., start, + start + angle))) + return MS_FAILURE; + + start += angle; + } + return MS_SUCCESS; +} + +int getNextShape(mapObj *map, layerObj *layer, double *values, int *nvalues, + styleObj **styles, shapeObj *shape) { + int status; + int c; + status = msLayerNextShape(layer, shape); + if (status == MS_SUCCESS) { + + if (layer->project) { + if (layer->reprojectorLayerToMap == NULL) { + layer->reprojectorLayerToMap = + msProjectCreateReprojector(&layer->projection, &map->projection); + if (layer->reprojectorLayerToMap == NULL) { + return MS_FAILURE; + } + } + msProjectShapeEx(layer->reprojectorLayerToMap, shape); + } + + if (msBindLayerToShape(layer, shape, + MS_DRAWMODE_FEATURES | MS_DRAWMODE_LABELS) != + MS_SUCCESS) + return MS_FAILURE; /* error message is set in msBindLayerToShape() */ + + *nvalues = 0; + for (c = 0; c < layer->numclasses; c++) { + if (msEvalExpression(layer, shape, &(layer->class[c] -> expression), + layer->classitemindex) == MS_TRUE) { + values[*nvalues] = (layer->class[c] -> styles[0] -> size); + styles[*nvalues] = layer->class[c]->styles[0]; + (*nvalues)++; + } + } + } + return status; +} + +/* eventually add a class to the layer to get the diameter from an attribute */ +int pieLayerProcessDynamicDiameter(layerObj *layer) { + const char *chartRangeProcessingKey = NULL; + char *attrib; + double mindiameter = -1, maxdiameter, minvalue, maxvalue; + classObj *newclass; + styleObj *newstyle; + const char *chartSizeProcessingKey = + msLayerGetProcessingKey(layer, "CHART_SIZE"); + if (chartSizeProcessingKey != NULL) + return MS_FALSE; + chartRangeProcessingKey = msLayerGetProcessingKey(layer, "CHART_SIZE_RANGE"); + if (chartRangeProcessingKey == NULL) + return MS_FALSE; + attrib = msStrdup(chartRangeProcessingKey); + char *space = strchr(attrib, ' '); + if (space) { + *space = '\0'; + if (sscanf(space + 1, "%lf %lf %lf %lf", &mindiameter, &maxdiameter, + &minvalue, &maxvalue) != 4) { + /*we don't have the attribute and the four range values*/ + free(attrib); + msSetError(MS_MISCERR, + "Chart Layer format error for processing key \"CHART_RANGE\"", + "msDrawChartLayer()"); + return MS_FAILURE; + } + } + + /*create a new class in the layer containing the wanted attribute + * as the SIZE of its first STYLE*/ + newclass = msGrowLayerClasses(layer); + if (newclass == NULL) { + free(attrib); + return MS_FAILURE; + } + initClass(newclass); + layer->numclasses++; + + /*create and attach a new styleObj to our temp class + * and bind the wanted attribute to its SIZE + */ + newstyle = msGrowClassStyles(newclass); + if (newstyle == NULL) { + free(attrib); + return MS_FAILURE; + } + initStyle(newstyle); + newclass->numstyles++; + newclass->name = (char *)msStrdup("__MS_SIZE_ATTRIBUTE_"); + newstyle->bindings[MS_STYLE_BINDING_SIZE].item = msStrdup(attrib); + newstyle->numbindings++; + free(attrib); + + return MS_TRUE; +} + +/* clean up the class added temporarily */ +static void pieLayerCleanupDynamicDiameter(layerObj *layer) { + if (layer->numclasses > 0 && + EQUALN(layer->class[layer->numclasses - 1] -> name, + "__MS_SIZE_ATTRIBUTE_", 20)) { + classObj *c = msRemoveClass(layer, layer->numclasses - 1); + freeClass(c); + msFree(c); + } +} + +int msDrawPieChartLayer(mapObj *map, layerObj *layer, imageObj *image) { + shapeObj shape; + int status = MS_SUCCESS; + const char *chartRangeProcessingKey = NULL; + const char *chartSizeProcessingKey = + msLayerGetProcessingKey(layer, "CHART_SIZE"); + double diameter = 0, mindiameter = -1, maxdiameter = 0, minvalue = 0, + maxvalue = 0, exponent = 0; + double *values; + styleObj **styles; + pointObj center; + int numvalues = + layer->numclasses; /* the number of classes to represent in the graph */ + int numvalues_for_shape = 0; + + if (chartSizeProcessingKey == NULL) { + chartRangeProcessingKey = + msLayerGetProcessingKey(layer, "CHART_SIZE_RANGE"); + if (chartRangeProcessingKey == NULL) + diameter = 20; + else { + const int nvalues = + sscanf(chartRangeProcessingKey, "%*s %lf %lf %lf %lf %lf", + &mindiameter, &maxdiameter, &minvalue, &maxvalue, &exponent); + if (nvalues != 4 && nvalues != 5) { + msSetError( + MS_MISCERR, + "msDrawChart format error for processing key \"CHART_SIZE_RANGE\": " + "itemname minsize maxsize minval maxval [exponent] is expected", + "msDrawPieChartLayer()"); + return MS_FAILURE; + } + } + } else { + if (sscanf(chartSizeProcessingKey, "%lf", &diameter) != 1) { + msSetError(MS_MISCERR, + "msDrawChart format error for processing key \"CHART_SIZE\"", + "msDrawPieChartLayer()"); + return MS_FAILURE; + } + } + + layer->project = + msProjectionsDiffer(&(layer->projection), &(map->projection)); + + /* step through the target shapes */ + msInitShape(&shape); + + values = (double *)calloc(numvalues, sizeof(double)); + MS_CHECK_ALLOC(values, numvalues * sizeof(double), MS_FAILURE); + styles = (styleObj **)malloc((numvalues) * sizeof(styleObj *)); + if (styles == NULL) { + msSetError(MS_MEMERR, "%s: %d: Out of memory allocating %u bytes.\n", + "msDrawPieChartLayer()", __FILE__, __LINE__, + (unsigned int)(numvalues * sizeof(styleObj *))); + free(values); + return MS_FAILURE; + } + + while (MS_SUCCESS == getNextShape(map, layer, values, &numvalues_for_shape, + styles, &shape)) { + if (chartRangeProcessingKey != NULL) + numvalues_for_shape--; + if (numvalues_for_shape == 0) { + msFreeShape(&shape); + continue; + } + msDrawStartShape(map, layer, image, &shape); + if (chartRangeProcessingKey != NULL) { + diameter = values[numvalues_for_shape]; + if (mindiameter >= 0) { + if (diameter <= minvalue) + diameter = mindiameter; + else if (diameter >= maxvalue) + diameter = maxdiameter; + else { + if (exponent <= 0) + diameter = MS_NINT(mindiameter + + ((diameter - minvalue) / (maxvalue - minvalue)) * + (maxdiameter - mindiameter)); + else + diameter = MS_NINT( + mindiameter + pow((diameter - minvalue) / (maxvalue - minvalue), + 1.0 / exponent) * + (maxdiameter - mindiameter)); + } + } + } + if (findChartPoint(map, &shape, diameter, diameter, ¢er) == + MS_SUCCESS) { + status = msDrawPieChart(map, image, ¢er, diameter, values, styles, + numvalues_for_shape); + } + msDrawEndShape(map, layer, image, &shape); + msFreeShape(&shape); + } + free(values); + free(styles); + return status; +} + +int msDrawVBarChartLayer(mapObj *map, layerObj *layer, imageObj *image) { + shapeObj shape; + int status = MS_SUCCESS; + const char *chartSizeProcessingKey = + msLayerGetProcessingKey(layer, "CHART_SIZE"); + const char *chartScaleProcessingKey = + msLayerGetProcessingKey(layer, "CHART_SCALE"); + double barWidth, scale = 1.0; + double *values; + styleObj **styles; + pointObj center; + int numvalues = layer->numclasses; + int numvalues_for_shape; + if (chartSizeProcessingKey == NULL) { + barWidth = 20; + } else { + if (sscanf(chartSizeProcessingKey, "%lf", &barWidth) != 1) { + msSetError(MS_MISCERR, + "msDrawChart format error for processing key \"CHART_SIZE\"", + "msDrawVBarChartLayer()"); + return MS_FAILURE; + } + } + + if (chartScaleProcessingKey) { + if (sscanf(chartScaleProcessingKey, "%lf", &scale) != 1) { + msSetError(MS_MISCERR, + "Error reading value for processing key \"CHART_SCALE\"", + "msDrawVBarChartLayer()"); + return MS_FAILURE; + } + } + msInitShape(&shape); + + values = (double *)calloc(numvalues, sizeof(double)); + MS_CHECK_ALLOC(values, numvalues * sizeof(double), MS_FAILURE); + styles = (styleObj **)malloc(numvalues * sizeof(styleObj *)); + if (styles == NULL) { + msSetError(MS_MEMERR, "%s: %d: Out of memory allocating %u bytes.\n", + "msDrawVBarChartLayer()", __FILE__, __LINE__, + (unsigned int)(numvalues * sizeof(styleObj *))); + free(values); + return MS_FAILURE; + } + + while (MS_SUCCESS == getNextShape(map, layer, values, &numvalues_for_shape, + styles, &shape)) { + int i; + double h = 0; + if (numvalues_for_shape == 0) { + continue; + } + for (i = 0; i < numvalues_for_shape; i++) { + values[i] *= scale; + h += values[i]; + } + msDrawStartShape(map, layer, image, &shape); + if (findChartPoint(map, &shape, barWidth, h, ¢er) == MS_SUCCESS) { + status = msDrawVBarChart(map, image, ¢er, values, styles, + numvalues_for_shape, barWidth); + } + msDrawEndShape(map, layer, image, &shape); + msFreeShape(&shape); + } + free(values); + free(styles); + return status; +} + +int msDrawBarChartLayer(mapObj *map, layerObj *layer, imageObj *image) { + shapeObj shape; + int status = MS_SUCCESS; + const char *chartSizeProcessingKey = + msLayerGetProcessingKey(layer, "CHART_SIZE"); + const char *barMax = msLayerGetProcessingKey(layer, "CHART_BAR_MAXVAL"); + const char *barMin = msLayerGetProcessingKey(layer, "CHART_BAR_MINVAL"); + double width, height; + double barWidth; + double *values; + styleObj **styles; + pointObj center; + double barMaxVal = 0.0, barMinVal = 0.0; + int numvalues = layer->numclasses; + int numvalues_for_shape; + if (chartSizeProcessingKey == NULL) { + width = height = 20; + } else { + const int ret = sscanf(chartSizeProcessingKey, "%lf %lf", &width, &height); + if (ret == 1) { + height = width; + } else if (ret != 2) { + msSetError(MS_MISCERR, + "msDrawChart format error for processing key \"CHART_SIZE\"", + "msDrawBarChartLayer()"); + return MS_FAILURE; + } + } + + if (barMax) { + if (sscanf(barMax, "%lf", &barMaxVal) != 1) { + msSetError(MS_MISCERR, + "Error reading value for processing key \"CHART_BAR_MAXVAL\"", + "msDrawBarChartLayer()"); + return MS_FAILURE; + } + } + if (barMin) { + if (sscanf(barMin, "%lf", &barMinVal) != 1) { + msSetError(MS_MISCERR, + "Error reading value for processing key \"CHART_BAR_MINVAL\"", + "msDrawBarChartLayer()"); + return MS_FAILURE; + } + } + if (barMin && barMax && barMinVal >= barMaxVal) { + msSetError(MS_MISCERR, + "\"CHART_BAR_MINVAL\" must be less than \"CHART_BAR_MAXVAL\"", + "msDrawBarChartLayer()"); + return MS_FAILURE; + } + barWidth = (double)width / (double)layer->numclasses; + if (!barWidth) { + msSetError( + MS_MISCERR, + "Specified width of chart too small to fit given number of classes", + "msDrawBarChartLayer()"); + return MS_FAILURE; + } + + msInitShape(&shape); + + values = (double *)calloc(numvalues, sizeof(double)); + MS_CHECK_ALLOC(values, numvalues * sizeof(double), MS_FAILURE); + styles = (styleObj **)malloc(numvalues * sizeof(styleObj *)); + if (styles == NULL) { + msSetError(MS_MEMERR, "%s: %d: Out of memory allocating %u bytes.\n", + "msDrawBarChartLayer()", __FILE__, __LINE__, + (unsigned int)(numvalues * sizeof(styleObj *))); + free(values); + return MS_FAILURE; + } + + while (MS_SUCCESS == getNextShape(map, layer, values, &numvalues_for_shape, + styles, &shape)) { + if (numvalues_for_shape == 0) + continue; + msDrawStartShape(map, layer, image, &shape); + if (findChartPoint(map, &shape, width, height, ¢er) == MS_SUCCESS) { + status = msDrawBarChart(map, image, ¢er, values, styles, + numvalues_for_shape, width, height, + (barMax != NULL) ? &barMaxVal : NULL, + (barMin != NULL) ? &barMinVal : NULL, barWidth); + } + msDrawEndShape(map, layer, image, &shape); + msFreeShape(&shape); + } + free(values); + free(styles); + return status; +} + +/** + * Generic function to render chart layers. + */ +int msDrawChartLayer(mapObj *map, layerObj *layer, imageObj *image) { + + rectObj searchrect; + const char *chartTypeProcessingKey = + msLayerGetProcessingKey(layer, "CHART_TYPE"); + int chartType = MS_CHART_TYPE_PIE; + int status = MS_FAILURE; + + if (image && map) { + if (!(MS_RENDERER_PLUGIN(image->format))) { + msSetError(MS_MISCERR, + "chart drawing currently only supports GD and AGG renderers", + "msDrawChartLayer()"); + return MS_FAILURE; + } + + if (chartTypeProcessingKey != NULL) { + if (strcasecmp(chartTypeProcessingKey, "PIE") == 0) { + chartType = MS_CHART_TYPE_PIE; + } else if (strcasecmp(chartTypeProcessingKey, "BAR") == 0) { + chartType = MS_CHART_TYPE_BAR; + } else if (strcasecmp(chartTypeProcessingKey, "VBAR") == 0) { + chartType = MS_CHART_TYPE_VBAR; + } else { + msSetError(MS_MISCERR, + "unknown chart type for processing key \"CHART_TYPE\", must " + "be one of \"PIE\" or \"BAR\"", + "msDrawChartLayer()"); + return MS_FAILURE; + } + } + if (chartType == MS_CHART_TYPE_PIE) { + pieLayerProcessDynamicDiameter(layer); + } + + /* open this layer */ + status = msLayerOpen(layer); + if (status != MS_SUCCESS) + return MS_FAILURE; + + status = msLayerWhichItems(layer, MS_FALSE, NULL); + if (status != MS_SUCCESS) { + msLayerClose(layer); + return MS_FAILURE; + } + /* identify target shapes */ + if (layer->transform == MS_TRUE) + searchrect = map->extent; + else { + searchrect.minx = searchrect.miny = 0; + searchrect.maxx = map->width - 1; + searchrect.maxy = map->height - 1; + } + + if ((map->projection.numargs > 0) && (layer->projection.numargs > 0)) + msProjectRect(&map->projection, &layer->projection, + &searchrect); /* project the searchrect to source coords */ + + status = msLayerWhichShapes(layer, searchrect, MS_FALSE); + if (status == MS_DONE) { /* no overlap */ + msLayerClose(layer); + if (chartType == MS_CHART_TYPE_PIE) + pieLayerCleanupDynamicDiameter(layer); + return MS_SUCCESS; + } else if (status != MS_SUCCESS) { + msLayerClose(layer); + if (chartType == MS_CHART_TYPE_PIE) + pieLayerCleanupDynamicDiameter(layer); + return MS_FAILURE; + } + switch (chartType) { + case MS_CHART_TYPE_PIE: + status = msDrawPieChartLayer(map, layer, image); + break; + case MS_CHART_TYPE_BAR: + status = msDrawBarChartLayer(map, layer, image); + break; + case MS_CHART_TYPE_VBAR: + status = msDrawVBarChartLayer(map, layer, image); + break; + default: + return MS_FAILURE; /*shouldn't be here anyways*/ + } + + msLayerClose(layer); + + if (chartType == MS_CHART_TYPE_PIE) + pieLayerCleanupDynamicDiameter(layer); + } + return status; +} diff --git a/src/mapcluster.c b/src/mapcluster.c new file mode 100644 index 0000000000..ca34369b56 --- /dev/null +++ b/src/mapcluster.c @@ -0,0 +1,1873 @@ +/****************************************************************************** + * $Id$ + * + * Project: MapServer + * Purpose: Implementation of the cluster layer data provider (RFC-69). + * Author: Tamas Szekeres (szekerest@gmail.com). + * + ****************************************************************************** + * Copyright (c) 1996-2005 Regents of the University of Minnesota. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + ****************************************************************************/ + +#define _CRT_SECURE_NO_WARNINGS 1 + +/* $Id$ */ +#include +#include "mapserver.h" + +#ifdef USE_CLUSTER_PLUGIN +#define USE_CLUSTER_EXTERNAL +#endif + +/* custom attributes provided by this layer data source */ +#define MSCLUSTER_NUMITEMS 3 +#define MSCLUSTER_FEATURECOUNT "Cluster_FeatureCount" +#define MSCLUSTER_FEATURECOUNTINDEX -100 +#define MSCLUSTER_GROUP "Cluster_Group" +#define MSCLUSTER_GROUPINDEX -101 +#define MSCLUSTER_BASEFID "Cluster_BaseFID" +#define MSCLUSTER_BASEFIDINDEX -102 + +typedef struct cluster_tree_node clusterTreeNode; +typedef struct cluster_info clusterInfo; +typedef struct cluster_layer_info msClusterLayerInfo; + +/* forward declarations */ +void msClusterLayerCopyVirtualTable(layerVTableObj *vtable); +static void clusterTreeNodeDestroy(msClusterLayerInfo *layerinfo, + clusterTreeNode *node); + +/* cluster compare func */ +typedef int (*clusterCompareRegionFunc)(clusterInfo *current, + clusterInfo *other); + +/* quadtree constants */ +#define SPLITRATIO 0.55 +#define TREE_MAX_DEPTH 10 + +/* cluster algorithm */ +#define MSCLUSTER_ALGORITHM_FULL 0 +#define MSCLUSTER_ALGORITHM_SIMPLE 1 + +/* cluster data */ +struct cluster_info { + double x; /* x position of the current point */ + double y; /* y position of the current point */ + double avgx; /* average x positions of this cluster */ + double avgy; /* average y positions of this cluster */ + double varx; /* variance of the x positions of this cluster */ + double vary; /* variance of the y positions of this cluster */ + shapeObj shape; /* current shape */ + rectObj bounds; /* clustering region */ + /* number of the neighbouring shapes */ + int numsiblings; + /* diagnostics */ + int numcollected; + int numremoved; + int index; + clusterTreeNode *node; + /* collection of the siblings */ + clusterInfo *siblings; + /* next shape in the linked list */ + clusterInfo *next; + /* current group */ + char *group; + int filter; +}; + +/* quadtree node */ +struct cluster_tree_node { + /* area covered by this node */ + rectObj rect; + /* linked list of the shapes stored at this node. */ + int numshapes; + int index; + int position; + clusterInfo *shapes; + /* quad tree subnodes */ + clusterTreeNode *subnode[4]; +}; + +/* layerinfo */ +struct cluster_layer_info { + /* array of features (finalized clusters) */ + clusterInfo *finalized; + clusterInfo *finalizedSiblings; + clusterInfo *filtered; + int numFeatures; + int numFinalized; + int numFinalizedSiblings; + int numFiltered; + /* variables for collecting the best cluster and iterating with NextShape */ + clusterInfo *current; + /* check whether all shapes should be returned behind a cluster */ + int get_all_shapes; + /* check whether the location of the shapes should be preserved (no averaging) + */ + int keep_locations; + /* the maxdistance and the buffer parameters are specified in map units (scale + * independent clustering) */ + int use_map_units; + double rank; + /* root node of the quad tree */ + clusterTreeNode *root; + int numNodes; + clusterTreeNode *finalizedNodes; + int numFinalizedNodes; + /* map extent used for building cluster data */ + rectObj searchRect; + /* source layer parameters */ + layerObj srcLayer; + /* distance comparator function */ + clusterCompareRegionFunc fnCompare; + /* diagnostics */ + int depth; + /* processing algorithm */ + int algorithm; +}; + +extern int yyparse(parseObj *p); + +/* evaluate the filter expression */ +int msClusterEvaluateFilter(expressionObj *expression, shapeObj *shape) { + if (expression->type == MS_EXPRESSION) { + int status; + parseObj p; + + p.shape = shape; + p.expr = expression; + p.expr->curtoken = p.expr->tokens; /* reset */ + p.type = MS_PARSE_TYPE_BOOLEAN; + + status = yyparse(&p); + + if (status != 0) { + msSetError(MS_PARSEERR, "Failed to parse expression: %s", + "msClusterEvaluateFilter", expression->string); + return 0; + } + + return p.result.intval; + } + + return 0; +} + +/* get the group text when creating the clusters */ +char *msClusterGetGroupText(expressionObj *expression, shapeObj *shape) { + char *tmpstr = NULL; + + if (expression->string) { + switch (expression->type) { + case (MS_STRING): + tmpstr = msStrdup(expression->string); + break; + case (MS_EXPRESSION): { + int status; + parseObj p; + + p.shape = shape; + p.expr = expression; + p.expr->curtoken = p.expr->tokens; /* reset */ + p.type = MS_PARSE_TYPE_STRING; + + status = yyparse(&p); + + if (status != 0) { + msSetError(MS_PARSEERR, "Failed to process text expression: %s", + "msClusterGetGroupText", expression->string); + return NULL; + } + + tmpstr = p.result.strval; + break; + } + default: + break; + } + } + + return (tmpstr); +} + +int CompareEllipseRegion(clusterInfo *current, clusterInfo *other) { + if (current->group && other->group && !EQUAL(current->group, other->group)) + return MS_FALSE; + + if ((other->x - current->x) * (other->x - current->x) / + ((current->bounds.maxx - current->x) * + (current->bounds.maxx - current->x)) + + (other->y - current->y) * (other->y - current->y) / + ((current->bounds.maxy - current->y) * + (current->bounds.maxy - current->y)) > + 1) + return MS_FALSE; + + return MS_TRUE; +} + +int CompareRectangleRegion(clusterInfo *current, clusterInfo *other) { + if (current->group && other->group && !EQUAL(current->group, other->group)) + return MS_FALSE; + + if (other->x < current->bounds.minx) + return MS_FALSE; + if (other->x > current->bounds.maxx) + return MS_FALSE; + if (other->y < current->bounds.miny) + return MS_FALSE; + if (other->y > current->bounds.maxy) + return MS_FALSE; + + return MS_TRUE; +} + +static void treeSplitBounds(rectObj *in, rectObj *out1, rectObj *out2) { + double range; + + /* -------------------------------------------------------------------- */ + /* The output bounds will be very similar to the input bounds, */ + /* so just copy over to start. */ + /* -------------------------------------------------------------------- */ + memcpy(out1, in, sizeof(rectObj)); + memcpy(out2, in, sizeof(rectObj)); + + /* -------------------------------------------------------------------- */ + /* Split in X direction. */ + /* -------------------------------------------------------------------- */ + if ((in->maxx - in->minx) > (in->maxy - in->miny)) { + range = in->maxx - in->minx; + + out1->maxx = in->minx + range * SPLITRATIO; + out2->minx = in->maxx - range * SPLITRATIO; + } + + /* -------------------------------------------------------------------- */ + /* Otherwise split in Y direction. */ + /* -------------------------------------------------------------------- */ + else { + range = in->maxy - in->miny; + + out1->maxy = in->miny + range * SPLITRATIO; + out2->miny = in->maxy - range * SPLITRATIO; + } +} + +/* alloc memory for a new tentative cluster */ +static clusterInfo *clusterInfoCreate(msClusterLayerInfo *layerinfo) { + clusterInfo *feature = (clusterInfo *)msSmallMalloc(sizeof(clusterInfo)); + msInitShape(&feature->shape); + feature->numsiblings = 0; + feature->numcollected = 0; + feature->numremoved = 0; + feature->next = NULL; + feature->group = NULL; + feature->node = NULL; + feature->siblings = NULL; + feature->index = layerinfo->numFeatures; + feature->filter = -1; /* not yet calculated */ + ++layerinfo->numFeatures; + return feature; +} + +/* destroy memory of the cluster list */ +static void clusterInfoDestroyList(msClusterLayerInfo *layerinfo, + clusterInfo *feature) { + clusterInfo *s = feature; + clusterInfo *next; + /* destroy the shapes added to this node */ + while (s) { + next = s->next; + if (s->siblings) { + clusterInfoDestroyList(layerinfo, s->siblings); + } + msFreeShape(&s->shape); + msFree(s->group); + msFree(s); + --layerinfo->numFeatures; + s = next; + } +} + +/* alloc memory for a new treenode */ +static clusterTreeNode *clusterTreeNodeCreate(msClusterLayerInfo *layerinfo, + rectObj rect) { + clusterTreeNode *node = + (clusterTreeNode *)msSmallMalloc(sizeof(clusterTreeNode)); + node->rect = rect; + node->numshapes = 0; + node->shapes = NULL; + node->subnode[0] = node->subnode[1] = node->subnode[2] = node->subnode[3] = + NULL; + node->index = layerinfo->numNodes; + node->position = 0; + ++layerinfo->numNodes; + return node; +} + +/* traverse the quadtree and destroy all sub elements */ +static void clusterTreeNodeDestroy(msClusterLayerInfo *layerinfo, + clusterTreeNode *node) { + int i; + /* destroy the shapes added to this node */ + clusterInfoDestroyList(layerinfo, node->shapes); + + /* Recurse to subnodes if they exist */ + for (i = 0; i < 4; i++) { + if (node->subnode[i]) + clusterTreeNodeDestroy(layerinfo, node->subnode[i]); + } + + msFree(node); + --layerinfo->numNodes; +} + +/* destroy memory of the cluster finalized list (without recursion) */ +static void clusterTreeNodeDestroyList(msClusterLayerInfo *layerinfo, + clusterTreeNode *node) { + clusterTreeNode *n = node; + clusterTreeNode *next; + /* destroy the list of nodes */ + while (n) { + next = n->subnode[0]; + n->subnode[0] = NULL; + clusterTreeNodeDestroy(layerinfo, n); + --layerinfo->numFinalizedNodes; + n = next; + } +} + +void clusterDestroyData(msClusterLayerInfo *layerinfo) { + if (layerinfo->finalized) { + clusterInfoDestroyList(layerinfo, layerinfo->finalized); + layerinfo->finalized = NULL; + } + layerinfo->numFinalized = 0; + + if (layerinfo->finalizedSiblings) { + clusterInfoDestroyList(layerinfo, layerinfo->finalizedSiblings); + layerinfo->finalizedSiblings = NULL; + } + layerinfo->numFinalizedSiblings = 0; + + if (layerinfo->filtered) { + clusterInfoDestroyList(layerinfo, layerinfo->filtered); + layerinfo->filtered = NULL; + } + layerinfo->numFiltered = 0; + + if (layerinfo->finalizedNodes) { + clusterTreeNodeDestroyList(layerinfo, layerinfo->finalizedNodes); + layerinfo->finalizedNodes = NULL; + } + + layerinfo->numFinalizedNodes = 0; + + if (layerinfo->root) { + clusterTreeNodeDestroy(layerinfo, layerinfo->root); + layerinfo->root = NULL; + } + + layerinfo->numNodes = 0; +} + +/* traverse the quadtree to find the neighbouring shapes and update some data +on the related shapes (when adding a new feature)*/ +static void findRelatedShapes(msClusterLayerInfo *layerinfo, + clusterTreeNode *node, clusterInfo *current) { + int i; + clusterInfo *s; + + /* -------------------------------------------------------------------- */ + /* Does this node overlap the area of interest at all? If not, */ + /* return without adding to the list at all. */ + /* -------------------------------------------------------------------- */ + if (!msRectOverlap(&node->rect, ¤t->bounds)) + return; + + /* Modify the feature count of the related shapes */ + s = node->shapes; + while (s) { + if (layerinfo->fnCompare(current, s)) { + ++current->numsiblings; + /* calculating the average positions */ + current->avgx = (current->avgx * current->numsiblings + s->x) / + (current->numsiblings + 1); + current->avgy = (current->avgy * current->numsiblings + s->y) / + (current->numsiblings + 1); + /* calculating the variance */ + current->varx = + current->varx * current->numsiblings / (current->numsiblings + 1) + + (s->x - current->avgx) * (s->x - current->avgx) / + (current->numsiblings + 1); + current->vary = + current->vary * current->numsiblings / (current->numsiblings + 1) + + (s->y - current->avgy) * (s->y - current->avgy) / + (current->numsiblings + 1); + + if (layerinfo->fnCompare(s, current)) { + /* this feature falls into the region of the other as well */ + ++s->numsiblings; + /* calculating the average positions */ + s->avgx = + (s->avgx * s->numsiblings + current->x) / (s->numsiblings + 1); + s->avgy = + (s->avgy * s->numsiblings + current->y) / (s->numsiblings + 1); + /* calculating the variance */ + s->varx = s->varx * s->numsiblings / (s->numsiblings + 1) + + (current->x - s->avgx) * (current->x - s->avgx) / + (s->numsiblings + 1); + s->vary = s->vary * s->numsiblings / (s->numsiblings + 1) + + (current->y - s->avgy) * (current->y - s->avgy) / + (s->numsiblings + 1); + } + } + s = s->next; + } + + if (node->subnode[0] == NULL) + return; + + /* Recurse to subnodes if they exist */ + for (i = 0; i < 4; i++) { + if (node->subnode[i]) + findRelatedShapes(layerinfo, node->subnode[i], current); + } +} + +/* traverse the quadtree to find the neighbouring clusters and update data on + * the cluster*/ +static void findRelatedShapes2(msClusterLayerInfo *layerinfo, + clusterTreeNode *node, clusterInfo *current) { + int i; + clusterInfo *s; + + /* -------------------------------------------------------------------- */ + /* Does this node overlap the area of interest at all? If not, */ + /* return without adding to the list at all. */ + /* -------------------------------------------------------------------- */ + if (!msRectOverlap(&node->rect, ¤t->bounds)) + return; + + /* Modify the feature count of the related shapes */ + s = node->shapes; + while (s) { + if (layerinfo->fnCompare(s, current)) { + if (layerinfo->rank > 0) { + double r = (current->x - s->x) * (current->x - s->x) + + (current->y - s->y) * (current->y - s->y); + if (r < layerinfo->rank) { + layerinfo->current = s; + layerinfo->rank = r; + } + } else { + /* no rank was specified, return immediately */ + layerinfo->current = s; + return; + } + } + s = s->next; + } + + if (node->subnode[0] == NULL) + return; + + /* Recurse to subnodes if they exist */ + for (i = 0; i < 4; i++) { + if (node->subnode[i]) + findRelatedShapes2(layerinfo, node->subnode[i], current); + } +} + +/* traverse the quadtree to find the neighbouring shapes and update some data +on the related shapes (when removing a feature) */ +static void findRelatedShapesRemove(msClusterLayerInfo *layerinfo, + clusterTreeNode *node, + clusterInfo *current) { + int i; + clusterInfo *s; + + /* -------------------------------------------------------------------- */ + /* Does this node overlap the area of interest at all? If not, */ + /* return without adding to the list at all. */ + /* -------------------------------------------------------------------- */ + if (!msRectOverlap(&node->rect, ¤t->bounds)) + return; + + /* Modify the feature count of the related shapes */ + s = node->shapes; + while (s) { + if (layerinfo->fnCompare(current, s)) { + if (s->numsiblings > 0) { + /* calculating the average positions */ + s->avgx = + (s->avgx * (s->numsiblings + 1) - current->x) / s->numsiblings; + s->avgy = + (s->avgy * (s->numsiblings + 1) - current->y) / s->numsiblings; + /* calculating the variance */ + s->varx = (s->varx - (current->x - s->avgx) * (current->x - s->avgx) / + s->numsiblings) * + (s->numsiblings + 1) / s->numsiblings; + s->vary = (s->vary - (current->y - s->avgy) * (current->y - s->avgy) / + s->numsiblings) * + (s->numsiblings + 1) / s->numsiblings; + --s->numsiblings; + ++s->numremoved; + } + } + s = s->next; + } + + /* Recurse to subnodes if they exist */ + for (i = 0; i < 4; i++) { + if (node->subnode[i]) + findRelatedShapesRemove(layerinfo, node->subnode[i], current); + } +} + +/* setting the aggregated attributes */ +static void InitShapeAttributes(layerObj *layer, clusterInfo *base) { + int i; + int *itemindexes = layer->iteminfo; + + for (i = 0; i < layer->numitems; i++) { + if (base->shape.numvalues <= i) + break; + + if (itemindexes[i] == MSCLUSTER_FEATURECOUNTINDEX) { + if (base->shape.values[i]) + msFree(base->shape.values[i]); + + base->shape.values[i] = msIntToString(base->numsiblings + 1); + } else if (itemindexes[i] == MSCLUSTER_GROUPINDEX) { + if (base->shape.values[i]) + msFree(base->shape.values[i]); + + if (base->group) + base->shape.values[i] = msStrdup(base->group); + else + base->shape.values[i] = msStrdup(""); + } else if (itemindexes[i] == MSCLUSTER_BASEFIDINDEX) { + if (base->shape.values[i]) + msFree(base->shape.values[i]); + + base->shape.values[i] = msIntToString(base->shape.index); + } else if (EQUALN(layer->items[i], "Count:", 6)) { + if (base->shape.values[i]) + msFree(base->shape.values[i]); + + base->shape.values[i] = msStrdup("1"); /* initial count */ + } + } +} + +/* update the shape attributes (aggregate) */ +static void UpdateShapeAttributes(layerObj *layer, clusterInfo *base, + clusterInfo *current) { + int i; + int *itemindexes = layer->iteminfo; + + for (i = 0; i < layer->numitems; i++) { + if (base->shape.numvalues <= i) + break; + + if (itemindexes[i] == MSCLUSTER_FEATURECOUNTINDEX || + itemindexes[i] == MSCLUSTER_GROUPINDEX) + continue; + + if (current->shape.numvalues <= i) + break; + + /* setting the base feature index for each cluster member */ + if (itemindexes[i] == MSCLUSTER_BASEFIDINDEX) { + msFree(current->shape.values[i]); + current->shape.values[i] = msIntToString(base->shape.index); + } + + if (current->shape.values[i]) { + if (EQUALN(layer->items[i], "Min:", 4)) { + if (strcasecmp(base->shape.values[i], current->shape.values[i]) > 0) { + msFree(base->shape.values[i]); + base->shape.values[i] = msStrdup(current->shape.values[i]); + } + } else if (EQUALN(layer->items[i], "Max:", 4)) { + if (strcasecmp(base->shape.values[i], current->shape.values[i]) < 0) { + msFree(base->shape.values[i]); + base->shape.values[i] = msStrdup(current->shape.values[i]); + } + } else if (EQUALN(layer->items[i], "Sum:", 4)) { + double sum = + atof(base->shape.values[i]) + atof(current->shape.values[i]); + msFree(base->shape.values[i]); + base->shape.values[i] = msDoubleToString(sum, MS_FALSE); + } else if (EQUALN(layer->items[i], "Count:", 6)) { + int count = atoi(base->shape.values[i]) + 1; + msFree(base->shape.values[i]); + base->shape.values[i] = msIntToString(count); + } + } + } +} + +static int BuildFeatureAttributes(layerObj *layer, + msClusterLayerInfo *layerinfo, + shapeObj *shape) { + char **values; + int i; + int *itemindexes = layer->iteminfo; + + if (layer->numitems == layerinfo->srcLayer.numitems) + return MS_SUCCESS; /* we don't have custom attributes, no need to + reconstruct the array */ + + values = msSmallMalloc(sizeof(char *) * (layer->numitems)); + + for (i = 0; i < layer->numitems; i++) { + if (itemindexes[i] == MSCLUSTER_FEATURECOUNTINDEX) { + values[i] = NULL; /* not yet assigned */ + } else if (itemindexes[i] == MSCLUSTER_GROUPINDEX) { + values[i] = NULL; /* not yet assigned */ + } else if (itemindexes[i] == MSCLUSTER_BASEFIDINDEX) { + values[i] = NULL; /* not yet assigned */ + } else if (shape->values[itemindexes[i]]) + values[i] = msStrdup(shape->values[itemindexes[i]]); + else + values[i] = msStrdup(""); + } + + if (shape->values) + msFreeCharArray(shape->values, shape->numvalues); + + shape->values = values; + shape->numvalues = layer->numitems; + + return MS_SUCCESS; +} + +/* traverse the quadtree to find the best renking cluster */ +static void findBestCluster(layerObj *layer, msClusterLayerInfo *layerinfo, + clusterTreeNode *node) { + int i; + double rank; + clusterInfo *s = node->shapes; + while (s) { + if (s->filter < 0 && layer->cluster.filter.string != NULL) { + InitShapeAttributes(layer, s); + s->filter = msClusterEvaluateFilter(&layer->cluster.filter, &s->shape); + } + + if (s->numsiblings == 0 || s->filter == 0) { + /* individual or filtered shapes must be removed for sure */ + layerinfo->current = s; + return; + } + + /* calculating the rank */ + rank = (s->x - s->avgx) * (s->x - s->avgx) + + (s->y - s->avgy) * (s->y - s->avgy) /*+ s->varx + s->vary*/ + + (double)1 / (1 + s->numsiblings); + + if (rank < layerinfo->rank) { + layerinfo->current = s; + layerinfo->rank = rank; + } + s = s->next; + } + + /* Recurse to subnodes if they exist */ + for (i = 0; i < 4; i++) { + if (node->subnode[i]) + findBestCluster(layer, layerinfo, node->subnode[i]); + } +} + +/* adding the shape based on the shape bounds (point) */ +static int treeNodeAddShape(msClusterLayerInfo *layerinfo, + clusterTreeNode *node, clusterInfo *shape, + int depth) { + int i; + + /* -------------------------------------------------------------------- */ + /* If there are subnodes, then consider whether this object */ + /* will fit in them. */ + /* -------------------------------------------------------------------- */ + if (depth > 1 && node->subnode[0] != NULL) { + for (i = 0; i < 4; i++) { + if (msRectContained(&shape->shape.bounds, &node->subnode[i]->rect)) { + return treeNodeAddShape(layerinfo, node->subnode[i], shape, depth - 1); + } + } + } + + /* -------------------------------------------------------------------- */ + /* Otherwise, consider creating four subnodes if could fit into */ + /* them, and adding to the appropriate subnode. */ + /* -------------------------------------------------------------------- */ + else if (depth > 1 && node->subnode[0] == NULL) { + rectObj half1, half2, quad1, quad2, quad3, quad4; + int subnode = -1; + + treeSplitBounds(&node->rect, &half1, &half2); + treeSplitBounds(&half1, &quad1, &quad2); + treeSplitBounds(&half2, &quad3, &quad4); + + if (msRectContained(&shape->shape.bounds, &quad1)) + subnode = 0; + else if (msRectContained(&shape->shape.bounds, &quad2)) + subnode = 1; + else if (msRectContained(&shape->shape.bounds, &quad3)) + subnode = 2; + else if (msRectContained(&shape->shape.bounds, &quad4)) + subnode = 3; + + if (subnode >= 0) { + if ((node->subnode[0] = clusterTreeNodeCreate(layerinfo, quad1)) == NULL) + return MS_FAILURE; + node->subnode[0]->position = node->position * 4; + + if ((node->subnode[1] = clusterTreeNodeCreate(layerinfo, quad2)) == NULL) + return MS_FAILURE; + node->subnode[1]->position = node->position * 4 + 1; + + if ((node->subnode[2] = clusterTreeNodeCreate(layerinfo, quad3)) == NULL) + return MS_FAILURE; + node->subnode[2]->position = node->position * 4 + 2; + + if ((node->subnode[3] = clusterTreeNodeCreate(layerinfo, quad4)) == NULL) + return MS_FAILURE; + node->subnode[3]->position = node->position * 4 + 3; + + /* add to subnode */ + return treeNodeAddShape(layerinfo, node->subnode[subnode], shape, + depth - 1); + } + } + + /* found the right place, add this shape to the node */ + node->numshapes++; + shape->next = node->shapes; + node->shapes = shape; + shape->node = node; + + return MS_SUCCESS; +} + +/* collecting the cluster shapes, returns true if this subnode must be removed + */ +static int collectClusterShapes(msClusterLayerInfo *layerinfo, + clusterTreeNode *node, clusterInfo *current) { + int i; + clusterInfo *prev = NULL; + clusterInfo *s = node->shapes; + + if (!msRectOverlap(&node->rect, ¤t->bounds)) + return (!node->shapes && !node->subnode[0] && !node->subnode[1] && + !node->subnode[2] && !node->subnode[3]); + + /* removing the shapes from this node if overlap with the cluster */ + while (s) { + if (s == current || layerinfo->fnCompare(current, s)) { + if (s != current && current->filter == 0) { + /* skip siblings of the filtered shapes */ + prev = s; + s = prev->next; + continue; + } + + /* removing from the list */ + if (!prev) + node->shapes = s->next; + else + prev->next = s->next; + + ++current->numcollected; + + /* adding the shape to the finalization list */ + if (s == current) { + if (s->filter) { + s->next = layerinfo->finalized; + layerinfo->finalized = s; + ++layerinfo->numFinalized; + } else { + /* this shape is filtered */ + s->next = layerinfo->filtered; + layerinfo->filtered = s; + ++layerinfo->numFiltered; + } + } else { + s->next = layerinfo->finalizedSiblings; + layerinfo->finalizedSiblings = s; + ++layerinfo->numFinalizedSiblings; + } + + if (!prev) + s = node->shapes; + else + s = prev->next; + } else { + prev = s; + s = prev->next; + } + } + + /* Recurse to subnodes if they exist */ + for (i = 0; i < 4; i++) { + if (node->subnode[i] && + collectClusterShapes(layerinfo, node->subnode[i], current)) { + /* placing this empty node to the finalization queue */ + node->subnode[i]->subnode[0] = layerinfo->finalizedNodes; + layerinfo->finalizedNodes = node->subnode[i]; + node->subnode[i] = NULL; + ++layerinfo->numFinalizedNodes; + } + } + + /* returns true is this subnode must be removed */ + return (!node->shapes && !node->subnode[0] && !node->subnode[1] && + !node->subnode[2] && !node->subnode[3]); +} + +/* collecting the cluster shapes, returns true if this subnode must be removed + */ +static int collectClusterShapes2(layerObj *layer, msClusterLayerInfo *layerinfo, + clusterTreeNode *node) { + int i; + clusterInfo *current = NULL; + clusterInfo *s; + + while (node->shapes) { + s = node->shapes; + /* removing from the list */ + node->shapes = s->next; + + InitShapeAttributes(layer, s); + + if (s->filter) { + s->next = layerinfo->finalized; + layerinfo->finalized = s; + ++layerinfo->numFinalized; + } else { + /* this shape is filtered */ + s->next = layerinfo->filtered; + layerinfo->filtered = s; + ++layerinfo->numFiltered; + } + + /* update the parameters of the related shapes if any */ + if (s->siblings) { + current = s->siblings; + while (current) { + UpdateShapeAttributes(layer, s, current); + + /* setting the average position to the cluster position */ + current->avgx = s->x; + current->avgy = s->y; + + if (current->next == NULL) { + if (layerinfo->get_all_shapes == MS_TRUE) { + /* insert the siblings into the finalization list */ + current->next = layerinfo->finalized; + layerinfo->finalized = s->siblings; + s->siblings = NULL; + } + break; + } + + current = current->next; + } + } + } + + /* Recurse to subnodes if they exist */ + for (i = 0; i < 4; i++) { + if (node->subnode[i] && + collectClusterShapes2(layer, layerinfo, node->subnode[i])) { + /* placing this empty node to the finalization queue */ + node->subnode[i]->subnode[0] = layerinfo->finalizedNodes; + layerinfo->finalizedNodes = node->subnode[i]; + node->subnode[i] = NULL; + ++layerinfo->numFinalizedNodes; + } + } + + /* returns true is this subnode must be removed */ + return (!node->shapes && !node->subnode[0] && !node->subnode[1] && + !node->subnode[2] && !node->subnode[3]); +} + +int selectClusterShape(layerObj *layer, long shapeindex) { + int i; + clusterInfo *current; + msClusterLayerInfo *layerinfo = (msClusterLayerInfo *)layer->layerinfo; + + if (!layerinfo) { + msSetError(MS_MISCERR, "Layer not open: %s", "selectClusterShape()", + layer->name); + return MS_FAILURE; + } + + i = 0; + current = layerinfo->finalized; + while (current && i < shapeindex) { + ++i; + current = current->next; + } + assert(current); + + current->next = current->siblings; + layerinfo->current = current; + + if (layerinfo->keep_locations == MS_FALSE) { + current->shape.line[0].point[0].x = current->shape.bounds.minx = + current->shape.bounds.maxx = current->avgx; + current->shape.line[0].point[0].y = current->shape.bounds.miny = + current->shape.bounds.maxy = current->avgy; + } + + return MS_SUCCESS; +} + +/* update the parameters from the related shapes */ +#ifdef ms_notused +static void UpdateClusterParameters(msClusterLayerInfo *layerinfo, + clusterTreeNode *node, clusterInfo *shape) { + int i; + clusterInfo *s = node->shapes; + + while (s) { + if (layerinfo->fnCompare(shape, s)) { + shape->avgx += s->x; + shape->avgy += s->y; + ++shape->numsiblings; + } + s = s->next; + } + + /* Recurse to subnodes if they exist */ + for (i = 0; i < 4; i++) { + if (node->subnode[i]) + UpdateClusterParameters(layerinfo, node->subnode[i], shape); + } +} + +/* check for the validity of the clusters added to the tree (for debug purposes) + */ +static int ValidateTree(msClusterLayerInfo *layerinfo, clusterTreeNode *node) { + int i; + int isValid = MS_TRUE; + + clusterInfo *s = node->shapes; + while (s) { + double avgx = s->avgx; + double avgy = s->avgy; + int numsiblings = s->numsiblings; + + s->avgx = 0; + s->avgy = 0; + s->numsiblings = 0; + + UpdateClusterParameters(layerinfo, layerinfo->root, s); + + if (numsiblings + 1 != s->numsiblings) + isValid = MS_FALSE; + else if ((avgx * s->numsiblings - s->avgx) / s->avgx > 0.000001) + isValid = MS_FALSE; + else if ((avgy * s->numsiblings - s->avgy) / s->avgy > 0.000001) + isValid = MS_FALSE; + + s->avgx = avgx; + s->avgy = avgy; + s->numsiblings = numsiblings; + + if (isValid == MS_FALSE) + return MS_FALSE; + + s = s->next; + } + + /* Recurse to subnodes if they exist */ + for (i = 0; i < 4; i++) { + if (node->subnode[i] && + ValidateTree(layerinfo, node->subnode[i]) == MS_FALSE) + return MS_FALSE; + } + + /* returns true if this node contains only valid clusters */ + return MS_TRUE; +} +#endif + +/* rebuild the clusters according to the current extent */ +int RebuildClusters(layerObj *layer, int isQuery) { + mapObj *map; + layerObj *srcLayer; + double distance, maxDistanceX, maxDistanceY, cellSizeX, cellSizeY; + rectObj searchrect; + int status; + clusterInfo *current; + int depth; + const char *pszProcessing; +#ifdef USE_CLUSTER_EXTERNAL + int layerIndex; +#endif + reprojectionObj *reprojector = NULL; + + msClusterLayerInfo *layerinfo = layer->layerinfo; + + if (!layerinfo) { + msSetError(MS_MISCERR, "Layer is not open: %s", "RebuildClusters()", + layer->name); + return MS_FAILURE; + } + + if (!layer->map) { + msSetError(MS_MISCERR, "No map associated with this layer: %s", + "RebuildClusters()", layer->name); + return MS_FAILURE; + } + + if (layer->debug >= MS_DEBUGLEVEL_VVV) + msDebug("Clustering started.\n"); + + map = layer->map; + + layerinfo->current = layerinfo->finalized; /* restart */ + + /* check whether the simplified algorithm was selected */ + pszProcessing = msLayerGetProcessingKey(layer, "CLUSTER_ALGORITHM"); + if (pszProcessing && !strncasecmp(pszProcessing, "SIMPLE", 6)) + layerinfo->algorithm = MSCLUSTER_ALGORITHM_SIMPLE; + else + layerinfo->algorithm = MSCLUSTER_ALGORITHM_FULL; + + /* check whether all shapes should be returned from a query */ + if (msLayerGetProcessingKey(layer, "CLUSTER_GET_ALL_SHAPES") != NULL) + layerinfo->get_all_shapes = MS_TRUE; + else + layerinfo->get_all_shapes = MS_FALSE; + + /* check whether the location of the shapes should be preserved */ + if (msLayerGetProcessingKey(layer, "CLUSTER_KEEP_LOCATIONS") != NULL) + layerinfo->keep_locations = MS_TRUE; + else + layerinfo->keep_locations = MS_FALSE; + + /* check whether the maxdistance and the buffer parameters + are specified in map units (scale independent clustering) */ + if (msLayerGetProcessingKey(layer, "CLUSTER_USE_MAP_UNITS") != NULL) + layerinfo->use_map_units = MS_TRUE; + else + layerinfo->use_map_units = MS_FALSE; + + /* identify the current extent */ + if (layer->transform == MS_TRUE) + searchrect = map->extent; + else { + searchrect.minx = searchrect.miny = 0; + searchrect.maxx = map->width - 1; + searchrect.maxy = map->height - 1; + } + + if (searchrect.minx == layerinfo->searchRect.minx && + searchrect.miny == layerinfo->searchRect.miny && + searchrect.maxx == layerinfo->searchRect.maxx && + searchrect.maxy == layerinfo->searchRect.maxy) { + /* already built */ + return MS_SUCCESS; + } + + /* destroy previous data*/ + clusterDestroyData(layerinfo); + + layerinfo->searchRect = searchrect; + + /* reproject the rectangle to layer coordinates */ + if ((map->projection.numargs > 0) && (layer->projection.numargs > 0)) + msProjectRect(&map->projection, &layer->projection, + &searchrect); /* project the searchrect to source coords */ + + /* determine the compare method */ + layerinfo->fnCompare = CompareRectangleRegion; + if (layer->cluster.region) { + if (EQUAL(layer->cluster.region, "ellipse")) + layerinfo->fnCompare = CompareEllipseRegion; + } + + /* trying to find a reasonable quadtree depth */ + depth = 0; + distance = layer->cluster.maxdistance; + if (layerinfo->use_map_units == MS_TRUE) { + while ((distance < (searchrect.maxx - searchrect.minx) || + distance < (searchrect.maxy - searchrect.miny)) && + depth <= TREE_MAX_DEPTH) { + distance *= 2; + ++depth; + } + cellSizeX = 1; + cellSizeY = 1; + } else { + while ((distance < map->width || distance < map->height) && + depth <= TREE_MAX_DEPTH) { + distance *= 2; + ++depth; + } + cellSizeX = MS_CELLSIZE(searchrect.minx, searchrect.maxx, map->width); + cellSizeY = MS_CELLSIZE(searchrect.miny, searchrect.maxy, map->height); + } + + layerinfo->depth = depth; + + maxDistanceX = layer->cluster.maxdistance * cellSizeX; + maxDistanceY = layer->cluster.maxdistance * cellSizeY; + + /* increase the search rectangle so that the neighbouring shapes are also + * retrieved */ + searchrect.minx -= layer->cluster.buffer * cellSizeX; + searchrect.maxx += layer->cluster.buffer * cellSizeX; + searchrect.miny -= layer->cluster.buffer * cellSizeY; + searchrect.maxy += layer->cluster.buffer * cellSizeY; + + /* create the root node */ + if (layerinfo->root) + clusterTreeNodeDestroy(layerinfo, layerinfo->root); + layerinfo->root = clusterTreeNodeCreate(layerinfo, searchrect); + + srcLayer = &layerinfo->srcLayer; + + /* start retrieving the shapes */ + status = msLayerWhichShapes(srcLayer, searchrect, isQuery); + if (status == MS_DONE) { + /* no overlap */ + return MS_SUCCESS; + } else if (status != MS_SUCCESS) { + return MS_FAILURE; + } + + /* step through the source shapes and populate the quadtree with the tentative + * clusters */ + if ((current = clusterInfoCreate(layerinfo)) == NULL) + return MS_FAILURE; + +#if defined(USE_CLUSTER_EXTERNAL) + if (srcLayer->transform == MS_TRUE && srcLayer->project && + layer->transform == MS_TRUE && layer->project && + msProjectionsDiffer(&(srcLayer->projection), &(layer->projection))) { + reprojector = + msProjectCreateReprojector(&srcLayer->projection, &layer->projection); + } +#endif + + while ((status = msLayerNextShape(srcLayer, ¤t->shape)) == MS_SUCCESS) { +#if defined(USE_CLUSTER_EXTERNAL) + /* transform the shape to the projection of this layer */ + if (reprojector) + msProjectShapeEx(reprojector, ¤t->shape); +#endif + /* set up positions and variance */ + current->avgx = current->x = current->shape.bounds.minx; + current->avgy = current->y = current->shape.bounds.miny; + current->varx = current->vary = 0; + /* set up the area of interest when searching for the neighboring shapes */ + current->bounds.minx = current->x - maxDistanceX; + current->bounds.miny = current->y - maxDistanceY; + current->bounds.maxx = current->x + maxDistanceX; + current->bounds.maxy = current->y + maxDistanceY; + + /* if the shape doesn't overlap we must skip it to avoid further issues */ + if (!msRectOverlap(&searchrect, ¤t->bounds)) { + msFreeShape(¤t->shape); + msInitShape(¤t->shape); + + msDebug( + "Skipping an invalid shape falling outside of the given extent\n"); + continue; + } + + /* construct the item array */ + if (layer->iteminfo) + BuildFeatureAttributes(layer, layerinfo, ¤t->shape); + + /* evaluate the group expression */ + if (layer->cluster.group.string) + current->group = + msClusterGetGroupText(&layer->cluster.group, ¤t->shape); + + if (layerinfo->algorithm == MSCLUSTER_ALGORITHM_FULL) { + /*start a query for the related shapes */ + findRelatedShapes(layerinfo, layerinfo->root, current); + + /* add this shape to the tree */ + if (treeNodeAddShape(layerinfo, layerinfo->root, current, depth) != + MS_SUCCESS) { + clusterInfoDestroyList(layerinfo, current); + msProjectDestroyReprojector(reprojector); + return MS_FAILURE; + } + } else if (layerinfo->algorithm == MSCLUSTER_ALGORITHM_SIMPLE) { + /* find a related cluster and try to assign */ + layerinfo->rank = 0; + layerinfo->current = NULL; + findRelatedShapes2(layerinfo, layerinfo->root, current); + if (layerinfo->current) { + /* store these points until all clusters are created */ + current->next = layerinfo->finalizedSiblings; + layerinfo->finalizedSiblings = current; + } else { + /* if not found add this shape as a new cluster */ + if (treeNodeAddShape(layerinfo, layerinfo->root, current, depth) != + MS_SUCCESS) { + clusterInfoDestroyList(layerinfo, current); + msProjectDestroyReprojector(reprojector); + return MS_FAILURE; + } + } + } + + if ((current = clusterInfoCreate(layerinfo)) == NULL) { + clusterInfoDestroyList(layerinfo, current); + msProjectDestroyReprojector(reprojector); + return MS_FAILURE; + } + } + + msProjectDestroyReprojector(reprojector); + + clusterInfoDestroyList(layerinfo, current); + + if (layerinfo->algorithm == MSCLUSTER_ALGORITHM_FULL) { + while (layerinfo->root) { +#ifdef TESTCOUNT + int n; + double avgx, avgy; +#endif + + /* pick up the best cluster from the tree and do the finalization */ + /* the initial rank must be big enough */ + layerinfo->rank = (searchrect.maxx - searchrect.minx) * + (searchrect.maxx - searchrect.minx) + + (searchrect.maxy - searchrect.miny) * + (searchrect.maxy - searchrect.miny) + + 1; + + layerinfo->current = NULL; + findBestCluster(layer, layerinfo, layerinfo->root); + + if (layerinfo->current == NULL) { + if (layer->debug >= MS_DEBUGLEVEL_VVV) + msDebug("Clustering terminated.\n"); + break; /* completed */ + } + + /* Update the feature count of the shape */ + InitShapeAttributes(layer, layerinfo->current); + + /* collecting the shapes of the cluster */ + collectClusterShapes(layerinfo, layerinfo->root, layerinfo->current); + + if (layer->debug >= MS_DEBUGLEVEL_VVV) { + msDebug( + "processing cluster %p: rank=%lf fcount=%d ncoll=%d nfin=%d " + "nfins=%d nflt=%d bounds={%lf %lf %lf %lf}\n", + layerinfo->current, layerinfo->rank, + layerinfo->current->numsiblings + 1, + layerinfo->current->numcollected, layerinfo->numFinalized, + layerinfo->numFinalizedSiblings, layerinfo->numFiltered, + layerinfo->current->bounds.minx, layerinfo->current->bounds.miny, + layerinfo->current->bounds.maxx, layerinfo->current->bounds.maxy); + if (layerinfo->current->node) { + char pszBuffer[TREE_MAX_DEPTH + 1]; + clusterTreeNode *node = layerinfo->current->node; + int position = node->position; + int i = 1; + while (position > 0 && i <= TREE_MAX_DEPTH) { + pszBuffer[TREE_MAX_DEPTH - i] = '0' + (position % 4); + position = position >> 2; + ++i; + } + pszBuffer[TREE_MAX_DEPTH] = 0; + + msDebug(" ->node %p: count=%d index=%d pos=%s subn={%p %p %p %p} " + "rect={%lf %lf %lf %lf}\n", + node, node->numshapes, node->index, + pszBuffer + TREE_MAX_DEPTH - i + 1, node->subnode[0], + node->subnode[1], node->subnode[2], node->subnode[3], + node->rect.minx, node->rect.miny, node->rect.maxx, + node->rect.maxy); + } + } + +#ifdef TESTCOUNT + avgx = layerinfo->current->x; + avgy = layerinfo->current->y; + n = 0; +#endif + + if (layerinfo->current->numsiblings > 0) { + /* update the parameters due to the shape removal */ + findRelatedShapesRemove(layerinfo, layerinfo->root, layerinfo->current); + + if (layerinfo->current->filter == 0) { + /* filtered shapes has no siblings */ + layerinfo->current->numsiblings = 0; + layerinfo->current->avgx = layerinfo->current->x; + layerinfo->current->avgy = layerinfo->current->y; + } + + /* update the parameters of the related shapes if any */ + if (layerinfo->finalizedSiblings) { + current = layerinfo->finalizedSiblings; + while (current) { + /* update the parameters due to the shape removal */ + findRelatedShapesRemove(layerinfo, layerinfo->root, current); + UpdateShapeAttributes(layer, layerinfo->current, current); +#ifdef TESTCOUNT + avgx += current->x; + avgy += current->y; + ++n; +#endif + /* setting the average position to the same value */ + current->avgx = layerinfo->current->avgx; + current->avgy = layerinfo->current->avgy; + + if (current->next == NULL) { + if (layerinfo->get_all_shapes == MS_TRUE) { + /* insert the siblings into the finalization list */ + current->next = layerinfo->finalized; + layerinfo->finalized = layerinfo->finalizedSiblings; + } else { + /* preserve the clustered siblings for later use */ + layerinfo->current->siblings = layerinfo->finalizedSiblings; + } + break; + } + + current = current->next; + } + + layerinfo->finalizedSiblings = NULL; + } + } + +#ifdef TESTCOUNT + avgx /= (n + 1); + avgy /= (n + 1); + + if (layerinfo->current->numsiblings != n) + layerinfo->current->numsiblings = n; + + if (fabs(layerinfo->current->avgx - avgx) / avgx > 0.000000001 || + fabs(layerinfo->current->avgy - avgy) / avgy > 0.000000001) { + layerinfo->current->avgx = avgx; + layerinfo->current->avgy = avgy; + } +#endif + } + } else if (layerinfo->algorithm == MSCLUSTER_ALGORITHM_SIMPLE) { + /* assingn stired points to clusters */ + while (layerinfo->finalizedSiblings) { + current = layerinfo->finalizedSiblings; + layerinfo->rank = + maxDistanceX * maxDistanceX + maxDistanceY * maxDistanceY; + layerinfo->current = NULL; + findRelatedShapes2(layerinfo, layerinfo->root, current); + if (layerinfo->current) { + clusterInfo *s = layerinfo->current; + /* found a matching cluster */ + ++s->numsiblings; + /* assign to cluster */ + layerinfo->finalizedSiblings = current->next; + current->next = s->siblings; + s->siblings = current; + } else { + /* this appears to be a bug */ + layerinfo->finalizedSiblings = current->next; + current->next = layerinfo->filtered; + layerinfo->filtered = current; + ++layerinfo->numFiltered; + } + } + + /* collecting the shapes of the cluster */ + collectClusterShapes2(layer, layerinfo, layerinfo->root); + } + + /* set the pointer to the first shape */ + layerinfo->current = layerinfo->finalized; + + return MS_SUCCESS; +} + +/* Close the combined layer */ +int msClusterLayerClose(layerObj *layer) { + msClusterLayerInfo *layerinfo = (msClusterLayerInfo *)layer->layerinfo; + + if (!layerinfo) + return MS_SUCCESS; + + clusterDestroyData(layerinfo); + + msLayerClose(&layerinfo->srcLayer); + freeLayer(&layerinfo->srcLayer); + + msFree(layerinfo); + layer->layerinfo = NULL; + +#ifndef USE_CLUSTER_EXTERNAL + /* switch back to the source layer vtable */ + if (msInitializeVirtualTable(layer) != MS_SUCCESS) + return MS_FAILURE; +#endif + + return MS_SUCCESS; +} + +/* Return MS_TRUE if layer is open, MS_FALSE otherwise. */ +int msClusterLayerIsOpen(layerObj *layer) { + if (layer->layerinfo) + return (MS_TRUE); + else + return (MS_FALSE); +} + +/* Free the itemindexes array in a layer. */ +void msClusterLayerFreeItemInfo(layerObj *layer) { + msFree(layer->iteminfo); + layer->iteminfo = NULL; +} + +/* allocate the iteminfo index array - same order as the item list */ +int msClusterLayerInitItemInfo(layerObj *layer) { + int i, numitems; + int *itemindexes; + + msClusterLayerInfo *layerinfo = (msClusterLayerInfo *)layer->layerinfo; + + if (layer->numitems == 0) { + return MS_SUCCESS; + } + + if (!layerinfo) + return MS_FAILURE; + + /* Cleanup any previous item selection */ + msClusterLayerFreeItemInfo(layer); + + layer->iteminfo = (int *)msSmallMalloc(sizeof(int) * layer->numitems); + + itemindexes = layer->iteminfo; + + /* check whether we require attributes from the source layers also */ + numitems = 0; + for (i = 0; i < layer->numitems; i++) { + if (EQUAL(layer->items[i], MSCLUSTER_FEATURECOUNT)) + itemindexes[i] = MSCLUSTER_FEATURECOUNTINDEX; + else if (EQUAL(layer->items[i], MSCLUSTER_GROUP)) + itemindexes[i] = MSCLUSTER_GROUPINDEX; + else if (EQUAL(layer->items[i], MSCLUSTER_BASEFID)) + itemindexes[i] = MSCLUSTER_BASEFIDINDEX; + else + itemindexes[i] = numitems++; + } + + msLayerFreeItemInfo(&layerinfo->srcLayer); + if (layerinfo->srcLayer.items) { + msFreeCharArray(layerinfo->srcLayer.items, layerinfo->srcLayer.numitems); + layerinfo->srcLayer.items = NULL; + layerinfo->srcLayer.numitems = 0; + } + + if (numitems > 0) { + /* now allocate and set the layer item parameters */ + layerinfo->srcLayer.items = + (char **)msSmallMalloc(sizeof(char *) * numitems); + layerinfo->srcLayer.numitems = numitems; + + for (i = 0; i < layer->numitems; i++) { + if (itemindexes[i] >= 0) { + if (EQUALN(layer->items[i], "Min:", 4)) + layerinfo->srcLayer.items[itemindexes[i]] = + msStrdup(layer->items[i] + 4); + else if (EQUALN(layer->items[i], "Max:", 4)) + layerinfo->srcLayer.items[itemindexes[i]] = + msStrdup(layer->items[i] + 4); + else if (EQUALN(layer->items[i], "Sum:", 4)) + layerinfo->srcLayer.items[itemindexes[i]] = + msStrdup(layer->items[i] + 4); + else if (EQUALN(layer->items[i], "Count:", 6)) + layerinfo->srcLayer.items[itemindexes[i]] = + msStrdup(layer->items[i] + 6); + else + layerinfo->srcLayer.items[itemindexes[i]] = msStrdup(layer->items[i]); + } + } + + if (msLayerInitItemInfo(&layerinfo->srcLayer) != MS_SUCCESS) + return MS_FAILURE; + } + + return MS_SUCCESS; +} + +/* Execute a query for this layer */ +int msClusterLayerWhichShapes(layerObj *layer, rectObj rect, int isQuery) { + (void)rect; + /* rebuild the cluster database */ + return RebuildClusters(layer, isQuery); +} + +static int prepareShape(layerObj *layer, msClusterLayerInfo *layerinfo, + clusterInfo *current, shapeObj *shape) { + (void)layer; + if (msCopyShape(&(current->shape), shape) != MS_SUCCESS) { + msSetError( + MS_SHPERR, + "Cannot retrieve inline shape. There some problem with the shape", + "msClusterLayerNextShape()"); + return MS_FAILURE; + } + + /* update the positions of the cluster shape */ + if (layerinfo->keep_locations == MS_FALSE) { + shape->line[0].point[0].x = shape->bounds.minx = shape->bounds.maxx = + current->avgx; + shape->line[0].point[0].y = shape->bounds.miny = shape->bounds.maxy = + current->avgy; + } + + return MS_SUCCESS; +} + +/* Execute a query on the DB based on fid. */ +int msClusterLayerGetShape(layerObj *layer, shapeObj *shape, + resultObj *record) { + clusterInfo *current; + msClusterLayerInfo *layerinfo = (msClusterLayerInfo *)layer->layerinfo; + + if (!layerinfo) { + msSetError(MS_MISCERR, "Layer not open: %s", "msClusterLayerGetShape()", + layer->name); + return MS_FAILURE; + } + + current = layerinfo->finalized; + while (current) { + if (record->shapeindex == current->shape.index && + record->tileindex == current->shape.tileindex) + break; + current = current->next; + } + + if (current == NULL) { + msSetError(MS_SHPERR, "No feature with this index.", + "msClusterLayerGetShape()"); + return MS_FAILURE; + } + + return prepareShape(layer, layerinfo, current, shape); +} + +int msClusterLayerGetExtent(layerObj *layer, rectObj *extent) { + + msClusterLayerInfo *layerinfo = (msClusterLayerInfo *)layer->layerinfo; + + if (!layerinfo) { + msSetError(MS_MISCERR, "Layer not open: %s", "msClusterLayerGetExtent()", + layer->name); + return MS_FAILURE; + } + + int status = + layerinfo->srcLayer.vtable->LayerGetExtent(&layerinfo->srcLayer, extent); + return status; +} + +/* find the next shape with the appropriate shape type */ +/* also, load in the attribute data */ +/* MS_DONE => no more data */ +int msClusterLayerNextShape(layerObj *layer, shapeObj *shape) { + int rv; + msClusterLayerInfo *layerinfo = (msClusterLayerInfo *)layer->layerinfo; + + if (!layerinfo) { + msSetError(MS_MISCERR, "Layer not open: %s", "msClusterLayerNextShape()", + layer->name); + return MS_FAILURE; + } + + if (!layerinfo->current) + return MS_DONE; + + rv = prepareShape(layer, layerinfo, layerinfo->current, shape); + + layerinfo->current = layerinfo->current->next; + + return rv; +} + +/* Query for the items collection */ +int msClusterLayerGetItems(layerObj *layer) { + /* we support certain built in attributes */ + layer->numitems = MSCLUSTER_NUMITEMS; + layer->items = msSmallMalloc(sizeof(char *) * (layer->numitems)); + layer->items[0] = msStrdup(MSCLUSTER_FEATURECOUNT); + layer->items[1] = msStrdup(MSCLUSTER_GROUP); + layer->items[2] = msStrdup(MSCLUSTER_BASEFID); + + return msClusterLayerInitItemInfo(layer); +} + +int msClusterLayerGetNumFeatures(layerObj *layer) { + msClusterLayerInfo *layerinfo = (msClusterLayerInfo *)layer->layerinfo; + + if (!layerinfo) + return -1; + + return layerinfo->numFinalized; +} + +static int msClusterLayerGetAutoStyle(mapObj *map, layerObj *layer, classObj *c, + shapeObj *shape) { + (void)map; + (void)layer; + (void)c; + (void)shape; + /* TODO */ + return MS_SUCCESS; +} + +msClusterLayerInfo *msClusterInitialize(layerObj *layer) { + msClusterLayerInfo *layerinfo = + (msClusterLayerInfo *)msSmallMalloc(sizeof(msClusterLayerInfo)); + + layer->layerinfo = layerinfo; + + layerinfo->searchRect.minx = -1; + layerinfo->searchRect.miny = -1; + layerinfo->searchRect.maxx = -1; + layerinfo->searchRect.maxy = -1; + + layerinfo->root = NULL; + + layerinfo->get_all_shapes = MS_FALSE; + + layerinfo->numFeatures = 0; + layerinfo->numNodes = 0; + + layerinfo->finalized = NULL; + layerinfo->numFinalized = 0; + layerinfo->finalizedSiblings = NULL; + layerinfo->numFinalizedSiblings = 0; + layerinfo->filtered = NULL; + layerinfo->numFiltered = 0; + + layerinfo->finalizedNodes = NULL; + layerinfo->numFinalizedNodes = 0; + + return layerinfo; +} + +int msClusterLayerOpen(layerObj *layer) { + msClusterLayerInfo *layerinfo; + + if (layer->type != MS_LAYER_POINT) { + msSetError(MS_MISCERR, "Only point layers are supported for clustering: %s", + "msClusterLayerOpen()", layer->name); + return MS_FAILURE; + } + + if (!layer->map) + return MS_FAILURE; + + if (layer->layerinfo) { + if (layer->vtable->LayerOpen != msClusterLayerOpen) + msLayerClose(layer); + else + return MS_SUCCESS; /* already open */ + } + + layerinfo = msClusterInitialize(layer); + + if (!layer->layerinfo) + return MS_FAILURE; + + /* prepare the source layer */ + if (initLayer(&layerinfo->srcLayer, layer->map) == -1) + return MS_FAILURE; + +#ifdef USE_CLUSTER_EXTERNAL + if (!layer->map) + return MS_FAILURE; + + layerIndex = msGetLayerIndex(layer->map, layer->connection); + + if (layerIndex < 0 && layerIndex >= layer->map->numlayers) { + msSetError(MS_MISCERR, "No source layers specified in layer: %s", + "msClusterLayerOpen()", layer->name); + return MS_FAILURE; + } + + if (layer->map->layers[layerIndex]->type != MS_LAYER_POINT) { + msSetError(MS_MISCERR, + "Only point layers are supported for cluster data source: %s", + "msClusterLayerOpen()", layer->name); + return MS_FAILURE; + } + + if (msCopyLayer(&layerinfo->srcLayer, layer->map->layers[layerIndex]) != + MS_SUCCESS) + return (MS_FAILURE); +#else + /* hook the vtable to this driver, will be restored in LayerClose*/ + if (!layer->vtable) { + if (msInitializeVirtualTable(layer) != MS_SUCCESS) + return MS_FAILURE; + } + assert(layer->vtable); + msClusterLayerCopyVirtualTable(layer->vtable); + + if (msCopyLayer(&layerinfo->srcLayer, layer) != MS_SUCCESS) + return (MS_FAILURE); +#endif + + /* disable the connection pool for this layer */ + msLayerSetProcessingKey(&layerinfo->srcLayer, "CLOSE_CONNECTION", "ALWAYS"); + + /* open the source layer */ + if (!layerinfo->srcLayer.vtable) { + if (msInitializeVirtualTable(&layerinfo->srcLayer) != MS_SUCCESS) + return MS_FAILURE; + } + + if (layerinfo->srcLayer.vtable->LayerOpen(&layerinfo->srcLayer) != + MS_SUCCESS) { + return MS_FAILURE; + } + + return MS_SUCCESS; +} + +int msClusterLayerTranslateFilter(layerObj *layer, expressionObj *filter, + char *filteritem) { + (void)filter; + msClusterLayerInfo *layerinfo = layer->layerinfo; + + if (!layerinfo) { + msSetError(MS_MISCERR, "Layer is not open: %s", + "msClusterLayerTranslateFilter()", layer->name); + return MS_FAILURE; + } + + if (layerinfo->srcLayer.filter.type == MS_EXPRESSION && + layerinfo->srcLayer.filter.tokens == NULL) + msTokenizeExpression(&(layerinfo->srcLayer.filter), layer->items, + &(layer->numitems)); + + return layerinfo->srcLayer.vtable->LayerTranslateFilter( + &layerinfo->srcLayer, &layerinfo->srcLayer.filter, filteritem); +} + +char *msClusterLayerEscapeSQLParam(layerObj *layer, const char *pszString) { + msClusterLayerInfo *layerinfo = layer->layerinfo; + + if (!layerinfo) { + msSetError(MS_MISCERR, "Layer is not open: %s", + "msClusterLayerEscapeSQLParam()", layer->name); + return msStrdup(""); + } + + return layerinfo->srcLayer.vtable->LayerEscapeSQLParam(&layerinfo->srcLayer, + pszString); +} + +int msClusterLayerGetAutoProjection(layerObj *layer, + projectionObj *projection) { + msClusterLayerInfo *layerinfo = layer->layerinfo; + + if (!layerinfo) { + msSetError(MS_MISCERR, "Layer is not open: %s", + "msClusterLayerGetAutoProjection()", layer->name); + return MS_FAILURE; + } + + return layerinfo->srcLayer.vtable->LayerGetAutoProjection( + &layerinfo->srcLayer, projection); +} + +int msClusterLayerGetPaging(layerObj *layer) { + (void)layer; + return MS_FALSE; +} + +void msClusterLayerEnablePaging(layerObj *layer, int value) { + (void)layer; + (void)value; +} + +void msClusterLayerCopyVirtualTable(layerVTableObj *vtable) { + vtable->LayerInitItemInfo = msClusterLayerInitItemInfo; + vtable->LayerFreeItemInfo = msClusterLayerFreeItemInfo; + vtable->LayerOpen = msClusterLayerOpen; + vtable->LayerIsOpen = msClusterLayerIsOpen; + vtable->LayerWhichShapes = msClusterLayerWhichShapes; + vtable->LayerNextShape = msClusterLayerNextShape; + vtable->LayerGetShape = msClusterLayerGetShape; + vtable->LayerGetExtent = msClusterLayerGetExtent; + /* layer->vtable->LayerGetShapeCount, use default */ + + vtable->LayerClose = msClusterLayerClose; + + vtable->LayerGetItems = msClusterLayerGetItems; + vtable->LayerCloseConnection = msClusterLayerClose; + + vtable->LayerGetNumFeatures = msClusterLayerGetNumFeatures; + vtable->LayerGetAutoStyle = msClusterLayerGetAutoStyle; + vtable->LayerTranslateFilter = msClusterLayerTranslateFilter; + /* vtable->LayerSupportsCommonFilters, use driver implementation */ + vtable->LayerEscapeSQLParam = msClusterLayerEscapeSQLParam; + /* vtable->LayerEscapePropertyName, use driver implementation */ + + vtable->LayerEnablePaging = msClusterLayerEnablePaging; + vtable->LayerGetPaging = msClusterLayerGetPaging; + vtable->LayerGetAutoProjection = msClusterLayerGetAutoProjection; +} + +#ifdef USE_CLUSTER_PLUGIN + +MS_DLL_EXPORT int PluginInitializeVirtualTable(layerVTableObj *vtable, + layerObj *layer) { + assert(layer != NULL); + assert(vtable != NULL); + + msClusterLayerCopyVirtualTable(vtable); + + return MS_SUCCESS; +} + +#endif + +int msClusterLayerInitializeVirtualTable(layerObj *layer) { + assert(layer != NULL); + assert(layer->vtable != NULL); + + msClusterLayerCopyVirtualTable(layer->vtable); + + return MS_SUCCESS; +} diff --git a/src/mapcompositingfilter.c b/src/mapcompositingfilter.c new file mode 100644 index 0000000000..aff90b3f46 --- /dev/null +++ b/src/mapcompositingfilter.c @@ -0,0 +1,240 @@ +/****************************************************************************** + * + * Project: MapServer + * Purpose: RFC 113 Layer compositing + * Author: Thomas Bonfort and the MapServer team. + * + ****************************************************************************** + * Copyright (c) 1996-2015 Regents of the University of Minnesota. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + *****************************************************************************/ +#include "mapserver.h" + +#ifdef USE_PCRE2 +#include +#else +#include +#endif + +#define pixmove(rb, srcx, srcy, dstx, dsty) \ + memcpy(rb->data.rgba.pixels + dsty * rb->data.rgba.row_step + dstx * 4, \ + rb->data.rgba.pixels + srcy * rb->data.rgba.row_step + srcx * 4, 4) +#define pixerase(rb, x, y) \ + memset(rb->data.rgba.pixels + y * rb->data.rgba.row_step + x * 4, 0, 4) + +void msApplyTranslationCompositingFilter(rasterBufferObj *rb, int xtrans, + int ytrans) { + int src_sx, src_sy, dst_sx, dst_sy; + if ((unsigned)abs(xtrans) >= rb->width || + (unsigned)abs(ytrans) >= rb->height) { + for (unsigned y = 0; y < rb->height; y++) + for (unsigned x = 0; x < rb->width; x++) + pixerase(rb, x, y); + } + if (xtrans == 0 && ytrans == 0) + return; + if (xtrans >= 0) { + if (ytrans >= 0) { + src_sx = rb->width - xtrans - 1; + src_sy = rb->height - ytrans - 1; + dst_sx = rb->width - 1; + dst_sy = rb->height - 1; + for (int y = src_sy, dst_y = dst_sy; y >= 0; y--, dst_y--) { + for (int x = src_sx, dst_x = dst_sx; x >= 0; x--, dst_x--) { + pixmove(rb, x, y, dst_x, dst_y); + } + } + for (int y = 0; y < ytrans; y++) + for (unsigned x = 0; x < rb->width; x++) + pixerase(rb, x, y); + for (unsigned y = ytrans; y < rb->height; y++) + for (int x = 0; x < xtrans; x++) + pixerase(rb, x, y); + } else { + src_sx = rb->width - xtrans - 1; + src_sy = -ytrans; + dst_sx = rb->width - 1; + dst_sy = 0; + for (unsigned y = src_sy, dst_y = dst_sy; y < rb->height; y++, dst_y++) { + for (int x = src_sx, dst_x = dst_sx; x >= 0; x--, dst_x--) { + pixmove(rb, x, y, dst_x, dst_y); + } + } + for (unsigned y = 0; y < rb->height + ytrans; y++) + for (int x = 0; x < xtrans; x++) + pixerase(rb, x, y); + for (unsigned y = rb->height + ytrans; y < rb->height; y++) + for (unsigned x = 0; x < rb->width; x++) + pixerase(rb, x, y); + } + } else { + if (ytrans >= 0) { + src_sx = -xtrans; + src_sy = rb->height - ytrans - 1; + dst_sx = 0; + dst_sy = rb->height - 1; + for (int y = src_sy, dst_y = dst_sy; y >= 0; y--, dst_y--) { + for (unsigned x = src_sx, dst_x = dst_sx; x < rb->width; x++, dst_x++) { + pixmove(rb, x, y, dst_x, dst_y); + } + } + for (int y = 0; y < ytrans; y++) + for (unsigned x = 0; x < rb->width; x++) + pixerase(rb, x, y); + for (unsigned y = ytrans; y < rb->height; y++) + for (unsigned x = rb->width + xtrans; x < rb->width; x++) + pixerase(rb, x, y); + } else { + src_sx = -xtrans; + src_sy = -ytrans; + dst_sx = 0; + dst_sy = 0; + for (unsigned y = src_sy, dst_y = dst_sy; y < rb->height; y++, dst_y++) { + for (unsigned x = src_sx, dst_x = dst_sx; x < rb->width; x++, dst_x++) { + pixmove(rb, x, y, dst_x, dst_y); + } + } + for (unsigned y = 0; y < rb->height + ytrans; y++) + for (unsigned x = rb->width + xtrans; x < rb->width; x++) + pixerase(rb, x, y); + for (unsigned y = rb->height + ytrans; y < rb->height; y++) + for (unsigned x = 0; x < rb->width; x++) + pixerase(rb, x, y); + } + } +} + +void msApplyBlackeningCompositingFilter(rasterBufferObj *rb) { + unsigned char *r, *g, *b; + for (unsigned row = 0; row < rb->height; row++) { + r = rb->data.rgba.r + row * rb->data.rgba.row_step; + g = rb->data.rgba.g + row * rb->data.rgba.row_step; + b = rb->data.rgba.b + row * rb->data.rgba.row_step; + for (unsigned col = 0; col < rb->width; col++) { + *r = *g = *b = 0; + r += 4; + g += 4; + b += 4; + } + } +} + +void msApplyWhiteningCompositingFilter(rasterBufferObj *rb) { + unsigned char *r, *g, *b, *a; + for (unsigned row = 0; row < rb->height; row++) { + r = rb->data.rgba.r + row * rb->data.rgba.row_step; + g = rb->data.rgba.g + row * rb->data.rgba.row_step; + b = rb->data.rgba.b + row * rb->data.rgba.row_step; + a = rb->data.rgba.a + row * rb->data.rgba.row_step; + for (unsigned col = 0; col < rb->width; col++) { + *r = *g = *b = *a; + r += 4; + g += 4; + b += 4; + a += 4; + } + } +} + +void msApplyGrayscaleCompositingFilter(rasterBufferObj *rb) { + unsigned char *r, *g, *b; + for (unsigned row = 0; row < rb->height; row++) { + r = rb->data.rgba.r + row * rb->data.rgba.row_step; + g = rb->data.rgba.g + row * rb->data.rgba.row_step; + b = rb->data.rgba.b + row * rb->data.rgba.row_step; + for (unsigned col = 0; col < rb->width; col++) { + unsigned int mix = (unsigned int)*r + (unsigned int)*g + (unsigned int)*b; + mix /= 3; + *r = *g = *b = (unsigned char)mix; + r += 4; + g += 4; + b += 4; + } + } +} + +int msApplyCompositingFilter(mapObj *map, rasterBufferObj *rb, + CompositingFilter *filter) { + int rstatus; + regex_t regex; + regmatch_t pmatch[3]; + + /* test for blurring filter */ + regcomp(®ex, "blur\\(([0-9]+)\\)", REG_EXTENDED); + rstatus = regexec(®ex, filter->filter, 2, pmatch, 0); + regfree(®ex); + if (!rstatus) { + char *rad = malloc(pmatch[1].rm_eo - pmatch[1].rm_so + 1); + unsigned int irad; + strncpy(rad, filter->filter + pmatch[1].rm_so, + pmatch[1].rm_eo - pmatch[1].rm_so); + rad[pmatch[1].rm_eo - pmatch[1].rm_so] = 0; + // msDebug("got blur filter with radius %s\n",rad); + irad = atoi(rad); + free(rad); + irad = MS_NINT(irad * map->resolution / map->defresolution); + msApplyBlurringCompositingFilter(rb, irad); + return MS_SUCCESS; + } + + /* test for translation filter */ + regcomp(®ex, "translate\\((-?[0-9]+),(-?[0-9]+)\\)", REG_EXTENDED); + rstatus = regexec(®ex, filter->filter, 3, pmatch, 0); + regfree(®ex); + if (!rstatus) { + char *num; + int xtrans, ytrans; + num = malloc(pmatch[1].rm_eo - pmatch[1].rm_so + 1); + strncpy(num, filter->filter + pmatch[1].rm_so, + pmatch[1].rm_eo - pmatch[1].rm_so); + num[pmatch[1].rm_eo - pmatch[1].rm_so] = 0; + xtrans = atoi(num); + free(num); + num = malloc(pmatch[2].rm_eo - pmatch[2].rm_so + 1); + strncpy(num, filter->filter + pmatch[2].rm_so, + pmatch[2].rm_eo - pmatch[2].rm_so); + num[pmatch[2].rm_eo - pmatch[2].rm_so] = 0; + ytrans = atoi(num); + free(num); + // msDebug("got translation filter of radius %d,%d\n",xtrans,ytrans); + xtrans = MS_NINT(xtrans * map->resolution / map->defresolution); + ytrans = MS_NINT(ytrans * map->resolution / map->defresolution); + msApplyTranslationCompositingFilter(rb, xtrans, ytrans); + return MS_SUCCESS; + } + + /* test for grayscale filter */ + if (!strncmp(filter->filter, "grayscale()", strlen("grayscale()"))) { + msApplyGrayscaleCompositingFilter(rb); + return MS_SUCCESS; + } + if (!strncmp(filter->filter, "blacken()", strlen("blacken()"))) { + msApplyBlackeningCompositingFilter(rb); + return MS_SUCCESS; + } + if (!strncmp(filter->filter, "whiten()", strlen("whiten()"))) { + msApplyWhiteningCompositingFilter(rb); + return MS_SUCCESS; + } + + msSetError(MS_MISCERR, "unknown compositing filter (%s)", + "msApplyCompositingFilter()", filter->filter); + return MS_FAILURE; +} diff --git a/src/mapcontext.c b/src/mapcontext.c new file mode 100644 index 0000000000..258346aa3b --- /dev/null +++ b/src/mapcontext.c @@ -0,0 +1,1951 @@ +/********************************************************************** + * $Id$ + * + * Project: MapServer + * Purpose: OGC Web Map Context implementation + * Author: Julien-Samuel Lacroix, DM Solutions Group (lacroix@dmsolutions.ca) + * + ********************************************************************** + * Copyright (c) 2002-2003, Julien-Samuel Lacroix, DM Solutions Group Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + ****************************************************************************/ + +#include "mapserver.h" +#include "mapows.h" + +#include "cpl_vsi.h" +#include "cpl_conv.h" + +#if defined(USE_WMS_LYR) + +/* There is a dependency to GDAL/OGR for the GML driver and MiniXML parser */ +#include "cpl_minixml.h" + +#endif + +/* msGetMapContextFileText() +** +** Read a file and return is content +** +** Take the filename in argument +** Return value must be freed by caller +*/ +static char *msGetMapContextFileText(const char *filename) { + char *pszBuffer; + VSILFILE *stream; + vsi_l_offset nLength; + + /* open file */ + if (filename != NULL && strlen(filename) > 0) { + stream = VSIFOpenL(filename, "rb"); + if (!stream) { + msSetError(MS_IOERR, "(%s)", "msGetMapContextFileText()", filename); + return NULL; + } + } else { + msSetError(MS_IOERR, "(%s)", "msGetMapContextFileText()", filename); + return NULL; + } + + VSIFSeekL(stream, 0, SEEK_END); + nLength = VSIFTellL(stream); + VSIFSeekL(stream, 0, SEEK_SET); + if (nLength > 100 * 1024 * 1024U) { + msSetError(MS_MEMERR, "(%s): too big file", "msGetMapContextFileText()", + filename); + VSIFCloseL(stream); + return NULL; + } + + pszBuffer = (char *)malloc((size_t)nLength + 1); + if (pszBuffer == NULL) { + msSetError(MS_MEMERR, "(%s)", "msGetMapContextFileText()", filename); + VSIFCloseL(stream); + return NULL; + } + + if (VSIFReadL(pszBuffer, nLength, 1, stream) == 0) { + free(pszBuffer); + VSIFCloseL(stream); + msSetError(MS_IOERR, "(%s)", "msGetMapContextFileText()", filename); + return NULL; + } + pszBuffer[nLength] = '\0'; + + VSIFCloseL(stream); + + return pszBuffer; +} + +#if defined(USE_WMS_LYR) + +/* +**msGetMapContextXMLHashValue() +** +**Get the xml value and put it in the hash table +** +*/ +int msGetMapContextXMLHashValue(CPLXMLNode *psRoot, const char *pszXMLPath, + hashTableObj *metadata, char *pszMetadata) { + char *pszValue; + + pszValue = (char *)CPLGetXMLValue(psRoot, pszXMLPath, NULL); + if (pszValue != NULL) { + if (metadata != NULL) { + msInsertHashTable(metadata, pszMetadata, pszValue); + } else { + return MS_FAILURE; + } + } else { + return MS_FAILURE; + } + + return MS_SUCCESS; +} + +/* +**msGetMapContextXMLHashValue() +** +**Get the xml value and put it in the hash table +** +*/ +int msGetMapContextXMLHashValueDecode(CPLXMLNode *psRoot, + const char *pszXMLPath, + hashTableObj *metadata, + char *pszMetadata) { + char *pszValue; + + pszValue = (char *)CPLGetXMLValue(psRoot, pszXMLPath, NULL); + if (pszValue != NULL) { + if (metadata != NULL) { + msDecodeHTMLEntities(pszValue); + msInsertHashTable(metadata, pszMetadata, pszValue); + } else { + return MS_FAILURE; + } + } else { + return MS_FAILURE; + } + + return MS_SUCCESS; +} + +/* +**msGetMapContextXMLStringValue() +** +**Get the xml value and put it in the string field +** +*/ +int msGetMapContextXMLStringValue(CPLXMLNode *psRoot, char *pszXMLPath, + char **pszField) { + char *pszValue; + + pszValue = (char *)CPLGetXMLValue(psRoot, pszXMLPath, NULL); + if (pszValue != NULL) { + if (pszField != NULL) { + *pszField = msStrdup(pszValue); + } else { + return MS_FAILURE; + } + } else { + return MS_FAILURE; + } + + return MS_SUCCESS; +} + +/* +**msGetMapContextXMLStringValue() +** +**Get the xml value and put it in the string field +** +*/ +int msGetMapContextXMLStringValueDecode(CPLXMLNode *psRoot, char *pszXMLPath, + char **pszField) { + char *pszValue; + + pszValue = (char *)CPLGetXMLValue(psRoot, pszXMLPath, NULL); + if (pszValue != NULL) { + if (pszField != NULL) { + msDecodeHTMLEntities(pszValue); + *pszField = msStrdup(pszValue); + } else { + return MS_FAILURE; + } + } else { + return MS_FAILURE; + } + + return MS_SUCCESS; +} + +/* +**msGetMapContextXMLFloatValue() +** +**Get the xml value and put it in the string field +** +*/ +int msGetMapContextXMLFloatValue(CPLXMLNode *psRoot, char *pszXMLPath, + double *pszField) { + char *pszValue; + + pszValue = (char *)CPLGetXMLValue(psRoot, pszXMLPath, NULL); + if (pszValue != NULL) { + if (pszField != NULL) { + *pszField = atof(pszValue); + } else { + return MS_FAILURE; + } + } else { + return MS_FAILURE; + } + + return MS_SUCCESS; +} + +/* +** msLoadMapContextURLELements +** +** Take a Node and get the width, height, format and href from it. +** Then put this info in metadatas. +*/ +int msLoadMapContextURLELements(CPLXMLNode *psRoot, hashTableObj *metadata, + const char *pszMetadataRoot) { + char *pszMetadataName; + + if (psRoot == NULL || metadata == NULL || pszMetadataRoot == NULL) + return MS_FAILURE; + + pszMetadataName = (char *)malloc(strlen(pszMetadataRoot) + 10); + + sprintf(pszMetadataName, "%s_width", pszMetadataRoot); + msGetMapContextXMLHashValue(psRoot, "width", metadata, pszMetadataName); + + sprintf(pszMetadataName, "%s_height", pszMetadataRoot); + msGetMapContextXMLHashValue(psRoot, "height", metadata, pszMetadataName); + + sprintf(pszMetadataName, "%s_format", pszMetadataRoot); + msGetMapContextXMLHashValue(psRoot, "format", metadata, pszMetadataName); + + sprintf(pszMetadataName, "%s_href", pszMetadataRoot); + msGetMapContextXMLHashValue(psRoot, "OnlineResource.xlink:href", metadata, + pszMetadataName); + + free(pszMetadataName); + + return MS_SUCCESS; +} + +/* msLoadMapContextKeyword +** +** Put the keywords from a XML node and put them in a metadata. +** psRoot should be set to keywordlist +*/ +int msLoadMapContextListInMetadata(CPLXMLNode *psRoot, hashTableObj *metadata, + char *pszXMLName, char *pszMetadataName, + char *pszHashDelimiter) { + const char *pszHash, *pszXMLValue; + char *pszMetadata; + + if (psRoot == NULL || psRoot->psChild == NULL || metadata == NULL || + pszMetadataName == NULL || pszXMLName == NULL) + return MS_FAILURE; + + /* Pass from KeywordList to Keyword level */ + psRoot = psRoot->psChild; + + /* Loop on all elements and append keywords to the hash table */ + while (psRoot) { + if (psRoot->psChild && strcasecmp(psRoot->pszValue, pszXMLName) == 0) { + pszXMLValue = psRoot->psChild->pszValue; + pszHash = msLookupHashTable(metadata, pszMetadataName); + if (pszHash != NULL) { + pszMetadata = (char *)malloc(strlen(pszHash) + strlen(pszXMLValue) + 2); + if (pszHashDelimiter == NULL) + sprintf(pszMetadata, "%s%s", pszHash, pszXMLValue); + else + sprintf(pszMetadata, "%s%s%s", pszHash, pszHashDelimiter, + pszXMLValue); + msInsertHashTable(metadata, pszMetadataName, pszMetadata); + free(pszMetadata); + } else + msInsertHashTable(metadata, pszMetadataName, pszXMLValue); + } + psRoot = psRoot->psNext; + } + + return MS_SUCCESS; +} + +/* msLoadMapContextContactInfo +** +** Put the Contact information from a XML node and put them in a metadata. +** +*/ +int msLoadMapContextContactInfo(CPLXMLNode *psRoot, hashTableObj *metadata) { + if (psRoot == NULL || metadata == NULL) + return MS_FAILURE; + + /* Contact Person primary */ + msGetMapContextXMLHashValue(psRoot, "ContactPersonPrimary.ContactPerson", + metadata, "wms_contactperson"); + msGetMapContextXMLHashValue(psRoot, + "ContactPersonPrimary.ContactOrganization", + metadata, "wms_contactorganization"); + /* Contact Position */ + msGetMapContextXMLHashValue(psRoot, "ContactPosition", metadata, + "wms_contactposition"); + /* Contact Address */ + msGetMapContextXMLHashValue(psRoot, "ContactAddress.AddressType", metadata, + "wms_addresstype"); + msGetMapContextXMLHashValue(psRoot, "ContactAddress.Address", metadata, + "wms_address"); + msGetMapContextXMLHashValue(psRoot, "ContactAddress.City", metadata, + "wms_city"); + msGetMapContextXMLHashValue(psRoot, "ContactAddress.StateOrProvince", + metadata, "wms_stateorprovince"); + msGetMapContextXMLHashValue(psRoot, "ContactAddress.PostCode", metadata, + "wms_postcode"); + msGetMapContextXMLHashValue(psRoot, "ContactAddress.Country", metadata, + "wms_country"); + + /* Others */ + msGetMapContextXMLHashValue(psRoot, "ContactVoiceTelephone", metadata, + "wms_contactvoicetelephone"); + msGetMapContextXMLHashValue(psRoot, "ContactFacsimileTelephone", metadata, + "wms_contactfacsimiletelephone"); + msGetMapContextXMLHashValue(psRoot, "ContactElectronicMailAddress", metadata, + "wms_contactelectronicmailaddress"); + + return MS_SUCCESS; +} + +/* +** msLoadMapContextLayerFormat +** +** +*/ +int msLoadMapContextLayerFormat(CPLXMLNode *psFormat, layerObj *layer) { + const char *pszValue; + char *pszValue1; + const char *pszHash; + + if (psFormat->psChild != NULL && + strcasecmp(psFormat->pszValue, "Format") == 0) { + if (psFormat->psChild->psNext == NULL) + pszValue = psFormat->psChild->pszValue; + else + pszValue = psFormat->psChild->psNext->pszValue; + } else + pszValue = NULL; + + if (pszValue != NULL && strcasecmp(pszValue, "") != 0) { + /* wms_format */ + pszValue1 = (char *)CPLGetXMLValue(psFormat, "current", NULL); + if (pszValue1 != NULL && + (strcasecmp(pszValue1, "1") == 0 || strcasecmp(pszValue1, "true") == 0)) + msInsertHashTable(&(layer->metadata), "wms_format", pszValue); + /* wms_formatlist */ + pszHash = msLookupHashTable(&(layer->metadata), "wms_formatlist"); + if (pszHash != NULL) { + pszValue1 = (char *)malloc(strlen(pszHash) + strlen(pszValue) + 2); + sprintf(pszValue1, "%s,%s", pszHash, pszValue); + msInsertHashTable(&(layer->metadata), "wms_formatlist", pszValue1); + free(pszValue1); + } else + msInsertHashTable(&(layer->metadata), "wms_formatlist", pszValue); + } + + /* Make sure selected format is supported or select another + * supported format. Note that we can efficiently do this + * only for GIF/PNG/JPEG, can't try to handle all GDAL + * formats. + */ + pszValue = msLookupHashTable(&(layer->metadata), "wms_format"); + + if (pszValue && ( +#if !(defined USE_PNG) + strcasecmp(pszValue, "image/png") == 0 || + strcasecmp(pszValue, "PNG") == 0 || +#endif +#if !(defined USE_JPEG) + strcasecmp(pszValue, "image/jpeg") == 0 || + strcasecmp(pszValue, "JPEG") == 0 || +#endif + 0)) { + char **papszList = NULL; + int i, numformats = 0; + + pszValue = msLookupHashTable(&(layer->metadata), "wms_formatlist"); + + papszList = msStringSplit(pszValue, ',', &numformats); + for (i = 0; i < numformats; i++) { + if ( +#if (defined USE_PNG) + strcasecmp(papszList[i], "image/png") == 0 || + strcasecmp(papszList[i], "PNG") == 0 || +#endif +#if (defined USE_JPEG) + strcasecmp(papszList[i], "image/jpeg") == 0 || + strcasecmp(papszList[i], "JPEG") == 0 || +#endif +#ifdef USE_GD_GIF + strcasecmp(papszList[i], "image/gif") == 0 || + strcasecmp(papszList[i], "GIF") == 0 || +#endif + 0) { + /* Found a match */ + msInsertHashTable(&(layer->metadata), "wms_format", papszList[i]); + break; + } + } + if (papszList) + msFreeCharArray(papszList, numformats); + + } /* end if unsupported format */ + + return MS_SUCCESS; +} + +int msLoadMapContextLayerStyle(CPLXMLNode *psStyle, layerObj *layer, + int nStyle) { + char *pszValue, *pszValue1, *pszValue2; + const char *pszHash; + char *pszStyle = NULL; + char *pszStyleName; + CPLXMLNode *psStyleSLDBody; + + pszStyleName = (char *)CPLGetXMLValue(psStyle, "Name", NULL); + if (pszStyleName == NULL) { + pszStyleName = (char *)malloc(20); + sprintf(pszStyleName, "Style{%d}", nStyle); + } else + pszStyleName = msStrdup(pszStyleName); + + /* wms_style */ + pszValue = (char *)CPLGetXMLValue(psStyle, "current", NULL); + if (pszValue != NULL && + (strcasecmp(pszValue, "1") == 0 || strcasecmp(pszValue, "true") == 0)) + msInsertHashTable(&(layer->metadata), "wms_style", pszStyleName); + /* wms_stylelist */ + pszHash = msLookupHashTable(&(layer->metadata), "wms_stylelist"); + if (pszHash != NULL) { + pszValue1 = (char *)malloc(strlen(pszHash) + strlen(pszStyleName) + 2); + sprintf(pszValue1, "%s,%s", pszHash, pszStyleName); + msInsertHashTable(&(layer->metadata), "wms_stylelist", pszValue1); + free(pszValue1); + } else + msInsertHashTable(&(layer->metadata), "wms_stylelist", pszStyleName); + + /* Title */ + pszStyle = (char *)malloc(strlen(pszStyleName) + 20); + sprintf(pszStyle, "wms_style_%s_title", pszStyleName); + + if (msGetMapContextXMLHashValue(psStyle, "Title", &(layer->metadata), + pszStyle) == MS_FAILURE) + msInsertHashTable(&(layer->metadata), pszStyle, layer->name); + + free(pszStyle); + + /* SLD */ + pszStyle = (char *)malloc(strlen(pszStyleName) + 15); + sprintf(pszStyle, "wms_style_%s_sld", pszStyleName); + + msGetMapContextXMLHashValueDecode(psStyle, "SLD.OnlineResource.xlink:href", + &(layer->metadata), pszStyle); + free(pszStyle); + + /* SLDBODY */ + pszStyle = (char *)malloc(strlen(pszStyleName) + 20); + sprintf(pszStyle, "wms_style_%s_sld_body", pszStyleName); + + psStyleSLDBody = CPLGetXMLNode(psStyle, "SLD.StyledLayerDescriptor"); + /*some clients such as OpenLayers add a name space, which I believe is wrong + but added this additional test for compatibility #3115*/ + if (psStyleSLDBody == NULL) + psStyleSLDBody = CPLGetXMLNode(psStyle, "SLD.sld:StyledLayerDescriptor"); + + if (psStyleSLDBody != NULL) { + pszValue = CPLSerializeXMLTree(psStyleSLDBody); + if (pszValue != NULL) { + /* Before including SLDBody in the mapfile, we must replace the */ + /* double quote for single quote. This is to prevent having this: */ + /* "metadata" "" */ + char *c; + for (c = pszValue; *c != '\0'; c++) + if (*c == '"') + *c = '\''; + msInsertHashTable(&(layer->metadata), pszStyle, pszValue); + msFree(pszValue); + } + } + + free(pszStyle); + + /* LegendURL */ + pszStyle = (char *)malloc(strlen(pszStyleName) + 25); + + sprintf(pszStyle, "wms_style_%s_legendurl", pszStyleName); + msLoadMapContextURLELements(CPLGetXMLNode(psStyle, "LegendURL"), + &(layer->metadata), pszStyle); + + free(pszStyle); + + free(pszStyleName); + + /* */ + /* Add the stylelist to the layer connection */ + /* */ + if (msLookupHashTable(&(layer->metadata), "wms_stylelist") == NULL) { + if (layer->connection) + pszValue = msStrdup(layer->connection); + else + pszValue = msStrdup(""); + pszValue1 = strstr(pszValue, "STYLELIST="); + if (pszValue1 != NULL) { + pszValue1 += 10; + pszValue2 = strchr(pszValue, '&'); + if (pszValue2 != NULL) + pszValue1[pszValue2 - pszValue1] = '\0'; + msInsertHashTable(&(layer->metadata), "wms_stylelist", pszValue1); + } + free(pszValue); + } + + /* */ + /* Add the style to the layer connection */ + /* */ + if (msLookupHashTable(&(layer->metadata), "wms_style") == NULL) { + if (layer->connection) + pszValue = msStrdup(layer->connection); + else + pszValue = msStrdup(""); + pszValue1 = strstr(pszValue, "STYLE="); + if (pszValue1 != NULL) { + pszValue1 += 6; + pszValue2 = strchr(pszValue, '&'); + if (pszValue2 != NULL) + pszValue1[pszValue2 - pszValue1] = '\0'; + msInsertHashTable(&(layer->metadata), "wms_style", pszValue1); + } + free(pszValue); + } + + return MS_SUCCESS; +} + +int msLoadMapContextLayerDimension(CPLXMLNode *psDimension, layerObj *layer) { + char *pszValue; + const char *pszHash; + char *pszDimension = NULL, *pszDimensionName = NULL; + + pszDimensionName = (char *)CPLGetXMLValue(psDimension, "name", NULL); + if (pszDimensionName == NULL) { + return MS_FALSE; + } else + pszDimensionName = msStrdup(pszDimensionName); + + pszDimension = (char *)malloc(strlen(pszDimensionName) + 50); + + /* wms_dimension: This is the current dimension */ + pszValue = (char *)CPLGetXMLValue(psDimension, "current", NULL); + if (pszValue != NULL && + (strcasecmp(pszValue, "1") == 0 || strcasecmp(pszValue, "true") == 0)) + msInsertHashTable(&(layer->metadata), "wms_dimension", pszDimensionName); + /* wms_dimensionlist */ + pszHash = msLookupHashTable(&(layer->metadata), "wms_dimensionlist"); + if (pszHash != NULL) { + pszValue = (char *)malloc(strlen(pszHash) + strlen(pszDimensionName) + 2); + sprintf(pszValue, "%s,%s", pszHash, pszDimensionName); + msInsertHashTable(&(layer->metadata), "wms_dimensionlist", pszValue); + free(pszValue); + } else + msInsertHashTable(&(layer->metadata), "wms_dimensionlist", + pszDimensionName); + + /* Units */ + sprintf(pszDimension, "wms_dimension_%s_units", pszDimensionName); + msGetMapContextXMLHashValue(psDimension, "units", &(layer->metadata), + pszDimension); + + /* UnitSymbol */ + sprintf(pszDimension, "wms_dimension_%s_unitsymbol", pszDimensionName); + msGetMapContextXMLHashValue(psDimension, "unitSymbol", &(layer->metadata), + pszDimension); + + /* userValue */ + sprintf(pszDimension, "wms_dimension_%s_uservalue", pszDimensionName); + msGetMapContextXMLHashValue(psDimension, "userValue", &(layer->metadata), + pszDimension); + if (strcasecmp(pszDimensionName, "time") == 0) + msGetMapContextXMLHashValue(psDimension, "userValue", &(layer->metadata), + "wms_time"); + + /* default */ + sprintf(pszDimension, "wms_dimension_%s_default", pszDimensionName); + msGetMapContextXMLHashValue(psDimension, "default", &(layer->metadata), + pszDimension); + + /* multipleValues */ + sprintf(pszDimension, "wms_dimension_%s_multiplevalues", pszDimensionName); + msGetMapContextXMLHashValue(psDimension, "multipleValues", &(layer->metadata), + pszDimension); + + /* nearestValue */ + sprintf(pszDimension, "wms_dimension_%s_nearestvalue", pszDimensionName); + msGetMapContextXMLHashValue(psDimension, "nearestValue", &(layer->metadata), + pszDimension); + + free(pszDimension); + + free(pszDimensionName); + + return MS_SUCCESS; +} + +/* +** msLoadMapContextGeneral +** +** Load the General block of the mapcontext document +*/ +int msLoadMapContextGeneral(mapObj *map, CPLXMLNode *psGeneral, + CPLXMLNode *psMapContext, int nVersion, + const char *filename) { + + char *pszProj = NULL; + char *pszValue, *pszValue1, *pszValue2; + int nTmp; + + /* Projection */ + pszValue = (char *)CPLGetXMLValue(psGeneral, "BoundingBox.SRS", NULL); + if (pszValue != NULL && !EQUAL(pszValue, "(null)")) { + if (strncasecmp(pszValue, "AUTO:", 5) == 0) { + pszProj = msStrdup(pszValue); + } else { + pszProj = (char *)malloc(sizeof(char) * (strlen(pszValue) + 10)); + sprintf(pszProj, "init=epsg:%s", pszValue + 5); + } + + msFreeProjection(&map->projection); + msInitProjection(&map->projection); + map->projection.args[map->projection.numargs] = msStrdup(pszProj); + map->projection.numargs++; + msProcessProjection(&map->projection); + + if ((nTmp = GetMapserverUnitUsingProj(&(map->projection))) == -1) { + msSetError(MS_MAPCONTEXTERR, "Unable to set units for projection '%s'", + "msLoadMapContext()", pszProj); + free(pszProj); + return MS_FAILURE; + } else { + map->units = nTmp; + } + free(pszProj); + } else { + msDebug("Mandatory data General.BoundingBox.SRS missing in %s.", filename); + } + + /* Extent */ + if (msGetMapContextXMLFloatValue(psGeneral, "BoundingBox.minx", + &(map->extent.minx)) == MS_FAILURE) { + msDebug("Mandatory data General.BoundingBox.minx missing in %s.", filename); + } + if (msGetMapContextXMLFloatValue(psGeneral, "BoundingBox.miny", + &(map->extent.miny)) == MS_FAILURE) { + msDebug("Mandatory data General.BoundingBox.miny missing in %s.", filename); + } + if (msGetMapContextXMLFloatValue(psGeneral, "BoundingBox.maxx", + &(map->extent.maxx)) == MS_FAILURE) { + msDebug("Mandatory data General.BoundingBox.maxx missing in %s.", filename); + } + if (msGetMapContextXMLFloatValue(psGeneral, "BoundingBox.maxy", + &(map->extent.maxy)) == MS_FAILURE) { + msDebug("Mandatory data General.BoundingBox.maxy missing in %s.", filename); + } + + /* Title */ + if (msGetMapContextXMLHashValue(psGeneral, "Title", &(map->web.metadata), + "wms_title") == MS_FAILURE) { + if (nVersion >= OWS_1_0_0) + msDebug("Mandatory data General.Title missing in %s.", filename); + else { + if (msGetMapContextXMLHashValue(psGeneral, "gml:name", + &(map->web.metadata), + "wms_title") == MS_FAILURE) { + if (nVersion < OWS_0_1_7) + msDebug("Mandatory data General.Title missing in %s.", filename); + else + msDebug("Mandatory data General.gml:name missing in %s.", filename); + } + } + } + + /* Name */ + if (nVersion >= OWS_1_0_0) { + pszValue = (char *)CPLGetXMLValue(psMapContext, "id", NULL); + if (pszValue) { + msFree(map->name); + map->name = msStrdup(pszValue); + } + } else { + char *pszMapName = NULL; + if (msGetMapContextXMLStringValue(psGeneral, "Name", &pszMapName) == + MS_FAILURE) { + msGetMapContextXMLStringValue(psGeneral, "gml:name", &pszMapName); + } + if (pszMapName) { + msFree(map->name); + map->name = pszMapName; + } + } + /* Keyword */ + if (nVersion >= OWS_1_0_0) { + msLoadMapContextListInMetadata(CPLGetXMLNode(psGeneral, "KeywordList"), + &(map->web.metadata), "KEYWORD", + "wms_keywordlist", ","); + } else + msGetMapContextXMLHashValue(psGeneral, "Keywords", &(map->web.metadata), + "wms_keywordlist"); + + /* Window */ + pszValue1 = (char *)CPLGetXMLValue(psGeneral, "Window.width", NULL); + pszValue2 = (char *)CPLGetXMLValue(psGeneral, "Window.height", NULL); + if (pszValue1 != NULL && pszValue2 != NULL) { + map->width = atoi(pszValue1); + map->height = atoi(pszValue2); + } + + /* Abstract */ + if (msGetMapContextXMLHashValue(psGeneral, "Abstract", &(map->web.metadata), + "wms_abstract") == MS_FAILURE) { + msGetMapContextXMLHashValue(psGeneral, "gml:description", + &(map->web.metadata), "wms_abstract"); + } + + /* DataURL */ + msGetMapContextXMLHashValueDecode(psGeneral, + "DataURL.OnlineResource.xlink:href", + &(map->web.metadata), "wms_dataurl"); + + /* LogoURL */ + /* The logourl have a width, height, format and an URL */ + msLoadMapContextURLELements(CPLGetXMLNode(psGeneral, "LogoURL"), + &(map->web.metadata), "wms_logourl"); + + /* DescriptionURL */ + /* The descriptionurl have a width, height, format and an URL */ + msLoadMapContextURLELements(CPLGetXMLNode(psGeneral, "DescriptionURL"), + &(map->web.metadata), "wms_descriptionurl"); + + /* Contact Info */ + msLoadMapContextContactInfo(CPLGetXMLNode(psGeneral, "ContactInformation"), + &(map->web.metadata)); + + return MS_SUCCESS; +} + +/* +** msLoadMapContextLayer +** +** Load a Layer block from a MapContext document +*/ +int msLoadMapContextLayer(mapObj *map, CPLXMLNode *psLayer, int nVersion, + const char *filename, int unique_layer_names) { + char *pszValue; + const char *pszHash; + char *pszName = NULL; + CPLXMLNode *psFormatList, *psFormat, *psStyleList, *psStyle, *psExtension; + CPLXMLNode *psDimensionList, *psDimension; + int nStyle; + layerObj *layer; + + /* Init new layer */ + if (msGrowMapLayers(map) == NULL) + return MS_FAILURE; + + layer = (GET_LAYER(map, map->numlayers)); + initLayer(layer, map); + layer->map = (mapObj *)map; + layer->type = MS_LAYER_RASTER; + /* save the index */ + GET_LAYER(map, map->numlayers)->index = map->numlayers; + map->layerorder[map->numlayers] = map->numlayers; + map->numlayers++; + + /* Status */ + pszValue = (char *)CPLGetXMLValue(psLayer, "hidden", "1"); + if ((pszValue != NULL) && + (atoi(pszValue) == 0 && strcasecmp(pszValue, "true") != 0)) + layer->status = MS_ON; + else + layer->status = MS_OFF; + + /* Queryable */ + pszValue = (char *)CPLGetXMLValue(psLayer, "queryable", "0"); + if (pszValue != NULL && + (atoi(pszValue) == 1 || strcasecmp(pszValue, "true") == 0)) + layer->template = msStrdup("ttt"); + + /* Name and Title */ + pszValue = (char *)CPLGetXMLValue(psLayer, "Name", NULL); + if (pszValue != NULL) { + msInsertHashTable(&(layer->metadata), "wms_name", pszValue); + + if (unique_layer_names) { + pszName = (char *)malloc(sizeof(char) * (strlen(pszValue) + 15)); + sprintf(pszName, "l%d:%s", layer->index, pszValue); + layer->name = msStrdup(pszName); + free(pszName); + } else + layer->name = msStrdup(pszValue); + } else { + pszName = (char *)malloc(sizeof(char) * 15); + sprintf(pszName, "l%d:", layer->index); + layer->name = msStrdup(pszName); + free(pszName); + } + + if (msGetMapContextXMLHashValue(psLayer, "Title", &(layer->metadata), + "wms_title") == MS_FAILURE) { + if (msGetMapContextXMLHashValue(psLayer, "Server.title", &(layer->metadata), + "wms_title") == MS_FAILURE) { + msDebug("Mandatory data Layer.Title missing in %s.", filename); + } + } + + /* Server Title */ + msGetMapContextXMLHashValue(psLayer, "Server.title", &(layer->metadata), + "wms_server_title"); + + /* Abstract */ + msGetMapContextXMLHashValue(psLayer, "Abstract", &(layer->metadata), + "wms_abstract"); + + /* DataURL */ + if (nVersion <= OWS_0_1_4) { + msGetMapContextXMLHashValueDecode(psLayer, + "DataURL.OnlineResource.xlink:href", + &(layer->metadata), "wms_dataurl"); + } else { + /* The DataURL have a width, height, format and an URL */ + /* Width and height are not used, but they are included to */ + /* be consistent with the spec. */ + msLoadMapContextURLELements(CPLGetXMLNode(psLayer, "DataURL"), + &(layer->metadata), "wms_dataurl"); + } + + /* The MetadataURL have a width, height, format and an URL */ + /* Width and height are not used, but they are included to */ + /* be consistent with the spec. */ + msLoadMapContextURLELements(CPLGetXMLNode(psLayer, "MetadataURL"), + &(layer->metadata), "wms_metadataurl"); + + /* MinScale && MaxScale */ + pszValue = (char *)CPLGetXMLValue(psLayer, "sld:MinScaleDenominator", NULL); + if (pszValue != NULL) { + layer->minscaledenom = atof(pszValue); + } + + pszValue = (char *)CPLGetXMLValue(psLayer, "sld:MaxScaleDenominator", NULL); + if (pszValue != NULL) { + layer->maxscaledenom = atof(pszValue); + } + + /* */ + /* Server */ + /* */ + if (nVersion >= OWS_0_1_4) { + if (msGetMapContextXMLStringValueDecode( + psLayer, "Server.OnlineResource.xlink:href", + &(layer->connection)) == MS_FAILURE) { + msSetError( + MS_MAPCONTEXTERR, + "Mandatory data Server.OnlineResource.xlink:href missing in %s.", + "msLoadMapContext()", filename); + return MS_FAILURE; + } else { + msGetMapContextXMLHashValueDecode( + psLayer, "Server.OnlineResource.xlink:href", &(layer->metadata), + "wms_onlineresource"); + layer->connectiontype = MS_WMS; + } + } else { + if (msGetMapContextXMLStringValueDecode(psLayer, "Server.onlineResource", + &(layer->connection)) == + MS_FAILURE) { + msSetError(MS_MAPCONTEXTERR, + "Mandatory data Server.onlineResource missing in %s.", + "msLoadMapContext()", filename); + return MS_FAILURE; + } else { + msGetMapContextXMLHashValueDecode(psLayer, "Server.onlineResource", + &(layer->metadata), + "wms_onlineresource"); + layer->connectiontype = MS_WMS; + } + } + + if (nVersion >= OWS_0_1_4) { + if (msGetMapContextXMLHashValue(psLayer, "Server.version", + &(layer->metadata), + "wms_server_version") == MS_FAILURE) { + msSetError(MS_MAPCONTEXTERR, + "Mandatory data Server.version missing in %s.", + "msLoadMapContext()", filename); + return MS_FAILURE; + } + } else { + if (msGetMapContextXMLHashValue(psLayer, "Server.wmtver", + &(layer->metadata), + "wms_server_version") == MS_FAILURE) { + msSetError(MS_MAPCONTEXTERR, + "Mandatory data Server.wmtver missing in %s.", + "msLoadMapContext()", filename); + return MS_FAILURE; + } + } + + /* Projection */ + msLoadMapContextListInMetadata(psLayer, &(layer->metadata), "SRS", "wms_srs", + " "); + + pszHash = msLookupHashTable(&(layer->metadata), "wms_srs"); + if (((pszHash == NULL) || (strcasecmp(pszHash, "") == 0)) && + map->projection.numargs != 0) { + const char *pszLastProjArg = + map->projection.args[map->projection.numargs - 1]; + + if (pszLastProjArg != NULL) { + if (strncasecmp(pszLastProjArg, "AUTO:", 5) == 0) { + msInsertHashTable(&(layer->metadata), "wms_srs", pszLastProjArg); + } else { + if (strncasecmp(pszLastProjArg, "+init=epsg:", strlen("+init=epsg:")) == + 0) { + const size_t nSRSSize = + strlen("EPSG:") + strlen(pszLastProjArg + strlen("+init=epsg:")) + + 1; + char *pszSRS = (char *)malloc(nSRSSize); + snprintf(pszSRS, nSRSSize, "EPSG:%s", + pszLastProjArg + strlen("+init=epsg:")); + msInsertHashTable(&(layer->metadata), "wms_srs", pszSRS); + msFree(pszSRS); + } else { + msDebug("Unable to set data for layer wms_srs from this" + " value %s.", + pszLastProjArg); + } + } + } + } + + /* */ + /* Format */ + /* */ + if (nVersion >= OWS_0_1_4) { + psFormatList = CPLGetXMLNode(psLayer, "FormatList"); + } else { + psFormatList = psLayer; + } + + if (psFormatList != NULL) { + for (psFormat = psFormatList->psChild; psFormat != NULL; + psFormat = psFormat->psNext) { + msLoadMapContextLayerFormat(psFormat, layer); + } + + } /* end FormatList parsing */ + + /* Style */ + if (nVersion >= OWS_0_1_4) { + psStyleList = CPLGetXMLNode(psLayer, "StyleList"); + } else { + psStyleList = psLayer; + } + + if (psStyleList != NULL) { + nStyle = 0; + for (psStyle = psStyleList->psChild; psStyle != NULL; + psStyle = psStyle->psNext) { + if (strcasecmp(psStyle->pszValue, "Style") == 0) { + nStyle++; + msLoadMapContextLayerStyle(psStyle, layer, nStyle); + } + } + } + + /* Dimension */ + psDimensionList = CPLGetXMLNode(psLayer, "DimensionList"); + if (psDimensionList != NULL) { + for (psDimension = psDimensionList->psChild; psDimension != NULL; + psDimension = psDimension->psNext) { + if (strcasecmp(psDimension->pszValue, "Dimension") == 0) { + msLoadMapContextLayerDimension(psDimension, layer); + } + } + } + + /* Extension */ + psExtension = CPLGetXMLNode(psLayer, "Extension"); + if (psExtension != NULL) { + pszValue = (char *)CPLGetXMLValue(psExtension, "ol:opacity", NULL); + if (pszValue != NULL) { + if (!layer->compositer) { + layer->compositer = msSmallMalloc(sizeof(LayerCompositer)); + initLayerCompositer(layer->compositer); + } + layer->compositer->opacity = atof(pszValue) * 100; + } + } + + return MS_SUCCESS; +} + +#endif + +/* msLoadMapContextURL() +** +** load an OGC Web Map Context format from an URL +** +** Take a map object and a URL to a connect file in arguments +*/ + +int msLoadMapContextURL(mapObj *map, char *urlfilename, + int unique_layer_names) { +#if defined(USE_WMS_LYR) + char *pszTmpFile = NULL; + int status = 0; + + if (!map || !urlfilename) { + msSetError(MS_MAPCONTEXTERR, "Invalid map or url given.", + "msGetMapContextURL()"); + return MS_FAILURE; + } + + pszTmpFile = msTmpFile(map, map->mappath, NULL, "context.xml"); + if (msHTTPGetFile(urlfilename, pszTmpFile, &status, -1, 0, 0, 0) == + MS_SUCCESS) { + return msLoadMapContext(map, pszTmpFile, unique_layer_names); + } else { + msSetError(MS_MAPCONTEXTERR, "Could not open context file %s.", + "msGetMapContextURL()", urlfilename); + return MS_FAILURE; + } + +#else + msSetError(MS_MAPCONTEXTERR, + "Not implemented since Map Context is not enabled.", + "msGetMapContextURL()"); + return MS_FAILURE; +#endif +} +/* msLoadMapContext() +** +** Get a mapfile from a OGC Web Map Context format +** +** Take as first map object and a file in arguments +** If The 2nd aregument unique_layer_names is set to MS_TRUE, the layer +** name created would be unique and be prefixed with an l plus the layers's +*index +** (eg l:1:park. l:2:road ...). If It is set to MS_FALSE, the layer name +** would be the same name as the layer name in the context +*/ +int msLoadMapContext(mapObj *map, const char *filename, + int unique_layer_names) { +#if defined(USE_WMS_LYR) + char *pszWholeText, *pszValue; + CPLXMLNode *psRoot, *psMapContext, *psLayer, *psLayerList, *psChild; + char szPath[MS_MAXPATHLEN]; + int nVersion = -1; + char szVersionBuf[OWS_VERSION_MAXLEN]; + + const char *ms_contextfile_pattern = CPLGetConfigOption( + "MS_CONTEXTFILE_PATTERN", MS_DEFAULT_CONTEXTFILE_PATTERN); + if (msEvalRegex(ms_contextfile_pattern, filename) != MS_TRUE) { + msSetError(MS_REGEXERR, "Filename validation failed.", + "msLoadMapContext()"); + return MS_FAILURE; + } + + /* */ + /* Load the raw XML file */ + /* */ + + pszWholeText = + msGetMapContextFileText(msBuildPath(szPath, map->mappath, filename)); + if (pszWholeText == NULL) { + msSetError(MS_MAPCONTEXTERR, "Unable to read %s", "msLoadMapContext()", + filename); + return MS_FAILURE; + } + + if ((strstr(pszWholeText, "eType == CXT_Element && + (EQUAL(psChild->pszValue, "WMS_Viewer_Context") || + EQUAL(psChild->pszValue, "View_Context") || + EQUAL(psChild->pszValue, "ViewContext"))) { + psMapContext = psChild; + break; + } else { + psChild = psChild->psNext; + } + } + + if (psMapContext == NULL) { + CPLDestroyXMLNode(psRoot); + msSetError(MS_MAPCONTEXTERR, "Invalid Map Context File (%s)", + "msLoadMapContext()", filename); + return MS_FAILURE; + } + + /* Fetch document version number */ + pszValue = (char *)CPLGetXMLValue(psMapContext, "version", NULL); + if (!pszValue) { + msDebug("msLoadMapContext(): Mandatory data version missing in %s, " + "assuming 0.1.4.", + filename); + pszValue = "0.1.4"; + } + + nVersion = msOWSParseVersionString(pszValue); + + /* Make sure this is a supported version */ + switch (nVersion) { + case OWS_0_1_2: + case OWS_0_1_4: + case OWS_0_1_7: + case OWS_1_0_0: + case OWS_1_1_0: + /* All is good, this is a supported version. */ + break; + default: + /* Not a supported version */ + msSetError(MS_MAPCONTEXTERR, + "This version of Map Context is not supported (%s).", + "msLoadMapContext()", pszValue); + CPLDestroyXMLNode(psRoot); + return MS_FAILURE; + } + + /* Reformat and save Version in metadata */ + msInsertHashTable(&(map->web.metadata), "wms_context_version", + msOWSGetVersionString(nVersion, szVersionBuf)); + + if (nVersion >= OWS_0_1_7 && nVersion < OWS_1_0_0) { + if (msGetMapContextXMLHashValue(psMapContext, "fid", &(map->web.metadata), + "wms_context_fid") == MS_FAILURE) { + msDebug("Mandatory data fid missing in %s.", filename); + } + } + + /* */ + /* Load the General bloc */ + /* */ + psChild = CPLGetXMLNode(psMapContext, "General"); + if (psChild == NULL) { + CPLDestroyXMLNode(psRoot); + msSetError(MS_MAPCONTEXTERR, + "The Map Context document provided (%s) does not contain any " + "General elements.", + "msLoadMapContext()", filename); + return MS_FAILURE; + } + + if (msLoadMapContextGeneral(map, psChild, psMapContext, nVersion, filename) == + MS_FAILURE) { + CPLDestroyXMLNode(psRoot); + return MS_FAILURE; + } + + /* */ + /* Load the bloc LayerList */ + /* */ + psLayerList = CPLGetXMLNode(psMapContext, "LayerList"); + if (psLayerList != NULL) { + for (psLayer = psLayerList->psChild; psLayer != NULL; + psLayer = psLayer->psNext) { + if (EQUAL(psLayer->pszValue, "Layer")) { + if (msLoadMapContextLayer(map, psLayer, nVersion, filename, + unique_layer_names) == MS_FAILURE) { + CPLDestroyXMLNode(psRoot); + return MS_FAILURE; + } + } /* end Layer parsing */ + } /* for */ + } + + CPLDestroyXMLNode(psRoot); + + return MS_SUCCESS; + +#else + msSetError(MS_MAPCONTEXTERR, + "Not implemented since Map Context is not enabled.", + "msGetMapContext()"); + return MS_FAILURE; +#endif +} + +/* msSaveMapContext() +** +** Save a mapfile into the OGC Web Map Context format +** +** Take a map object and a file in arguments +*/ +int msSaveMapContext(mapObj *map, char *filename) { +#if defined(USE_WMS_LYR) + FILE *stream; + char szPath[MS_MAXPATHLEN]; + int nStatus; + + /* open file */ + if (filename != NULL && strlen(filename) > 0) { + stream = fopen(msBuildPath(szPath, map->mappath, filename), "wb"); + if (!stream) { + msSetError(MS_IOERR, "(%s)", "msSaveMapContext()", filename); + return (MS_FAILURE); + } + } else { + msSetError(MS_IOERR, "Filename is undefined.", "msSaveMapContext()"); + return MS_FAILURE; + } + + nStatus = msWriteMapContext(map, stream); + + fclose(stream); + + return nStatus; +#else + msSetError(MS_MAPCONTEXTERR, + "Not implemented since Map Context is not enabled.", + "msSaveMapContext()"); + return MS_FAILURE; +#endif +} + +int msWriteMapContext(mapObj *map, FILE *stream) { +#if defined(USE_WMS_LYR) + const char *version; + char *pszEPSG; + char *tabspace = NULL, *pszChar, *pszSLD = NULL, *pszSLD2 = NULL; + char *pszStyleItem, *pszSLDBody; + char *pszEncodedVal; + int i, nValue, nVersion = OWS_VERSION_NOTSET; + /* Dimension element */ + char *pszDimension; + const char *pszDimUserValue = NULL, *pszDimUnits = NULL, + *pszDimDefault = NULL; + const char *pszDimNearValue = NULL, *pszDimUnitSymbol = NULL; + const char *pszDimMultiValue = NULL; + int bDimensionList = 0; + + /* Decide which version we're going to return... */ + version = msLookupHashTable(&(map->web.metadata), "wms_context_version"); + if (version == NULL) + version = "1.1.0"; + + nVersion = msOWSParseVersionString(version); + if (nVersion == OWS_VERSION_BADFORMAT) + return MS_FAILURE; /* msSetError() already called. */ + + /* Make sure this is a supported version */ + /* Note that we don't write 0.1.2 even if we read it. */ + switch (nVersion) { + case OWS_0_1_4: + case OWS_0_1_7: + case OWS_1_0_0: + case OWS_1_1_0: + /* All is good, this is a supported version. */ + break; + default: + /* Not a supported version */ + msSetError(MS_MAPCONTEXTERR, + "This version of Map Context is not supported (%s).", + "msSaveMapContext()", version); + return MS_FAILURE; + } + + /* file header */ + msIO_fprintf(stream, + "\n"); + + /* set the WMS_Viewer_Context information */ + pszEncodedVal = msEncodeHTMLEntities(version); + if (nVersion >= OWS_1_0_0) { + msIO_fprintf(stream, "= OWS_0_1_7) { + msIO_fprintf(stream, "= OWS_0_1_7 && nVersion < OWS_1_0_0) { + msOWSPrintEncodeMetadata(stream, &(map->web.metadata), NULL, + "wms_context_fid", OWS_NOERR, " fid=\"%s\"", "0"); + } + if (nVersion >= OWS_1_0_0) + msOWSPrintEncodeParam(stream, "MAP.NAME", map->name, OWS_NOERR, + " id=\"%s\"", NULL); + + msIO_fprintf(stream, + " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""); + msIO_fprintf(stream, " xmlns:ogc=\"http://www.opengis.net/ogc\""); + + if (nVersion >= OWS_0_1_7 && nVersion < OWS_1_0_0) { + msIO_fprintf(stream, " xmlns:gml=\"http://www.opengis.net/gml\""); + } + if (nVersion >= OWS_1_0_0) { + msIO_fprintf(stream, " xmlns:xlink=\"http://www.w3.org/1999/xlink\""); + msIO_fprintf(stream, " xmlns=\"http://www.opengis.net/context\""); + msIO_fprintf(stream, " xmlns:sld=\"http://www.opengis.net/sld\""); + pszEncodedVal = msEncodeHTMLEntities(msOWSGetSchemasLocation(map)); + if (nVersion >= OWS_1_1_0) + msIO_fprintf(stream, + " xsi:schemaLocation=\"http://www.opengis.net/context " + "%s/context/1.1.0/context.xsd\">\n", + pszEncodedVal); + else + msIO_fprintf(stream, + " xsi:schemaLocation=\"http://www.opengis.net/context " + "%s/context/1.0.0/context.xsd\">\n", + pszEncodedVal); + msFree(pszEncodedVal); + } else { + msIO_fprintf(stream, " xmlns:xlink=\"http://www.w3.org/TR/xlink\""); + + pszEncodedVal = msEncodeHTMLEntities(msOWSGetSchemasLocation(map)); + msIO_fprintf(stream, " xsi:noNamespaceSchemaLocation=\"%s/contexts/", + pszEncodedVal); + msFree(pszEncodedVal); + pszEncodedVal = msEncodeHTMLEntities(msOWSGetSchemasLocation(map)); + msIO_fprintf(stream, "%s/context.xsd\">\n", pszEncodedVal); + msFree(pszEncodedVal); + } + + /* set the General information */ + msIO_fprintf(stream, " \n"); + + /* Window */ + if (map->width != -1 || map->height != -1) + msIO_fprintf(stream, " \n", + map->width, map->height); + + /* Bounding box corners and spatial reference system */ + if (tabspace) + free(tabspace); + tabspace = msStrdup(" "); + msOWSGetEPSGProj(&(map->projection), &(map->web.metadata), "MO", MS_TRUE, + &pszEPSG); + msIO_fprintf(stream, + "%s\n", + tabspace); + if (!pszEPSG || (strcasecmp(pszEPSG, "(null)") == 0)) + msIO_fprintf(stream, "\n"); + + pszEncodedVal = msEncodeHTMLEntities(pszEPSG); + msIO_fprintf(stream, + "%s\n", + tabspace, pszEncodedVal, map->extent.minx, map->extent.miny, + map->extent.maxx, map->extent.maxy); + msFree(pszEncodedVal); + msFree(pszEPSG); + + /* Title, name */ + if (nVersion >= OWS_0_1_7 && nVersion < OWS_1_0_0) { + msOWSPrintEncodeParam(stream, "MAP.NAME", map->name, OWS_NOERR, + " %s\n", NULL); + } else { + if (nVersion < OWS_0_1_7) + msOWSPrintEncodeParam(stream, "MAP.NAME", map->name, OWS_NOERR, + " %s\n", NULL); + + msIO_fprintf(stream, "%s\n", tabspace); + msOWSPrintEncodeMetadata(stream, &(map->web.metadata), NULL, "wms_title", + OWS_WARN, " %s\n", map->name); + } + + /* keyword */ + if (nVersion >= OWS_1_0_0) { + if (msLookupHashTable(&(map->web.metadata), "wms_keywordlist") != NULL) { + char **papszKeywords; + int nKeywords, iKey; + + const char *pszValue = + msLookupHashTable(&(map->web.metadata), "wms_keywordlist"); + papszKeywords = msStringSplit(pszValue, ',', &nKeywords); + if (nKeywords > 0 && papszKeywords) { + msIO_fprintf(stream, " \n"); + for (iKey = 0; iKey < nKeywords; iKey++) { + pszEncodedVal = msEncodeHTMLEntities(papszKeywords[iKey]); + msIO_fprintf(stream, " %s\n", pszEncodedVal); + msFree(pszEncodedVal); + } + msIO_fprintf(stream, " \n"); + } + } + } else + msOWSPrintEncodeMetadataList(stream, &(map->web.metadata), NULL, + "wms_keywordlist", " \n", + " \n", " %s\n", NULL); + + /* abstract */ + if (nVersion >= OWS_0_1_7 && nVersion < OWS_1_0_0) { + msOWSPrintEncodeMetadata( + stream, &(map->web.metadata), NULL, "wms_abstract", OWS_NOERR, + " %s\n", NULL); + } else { + msOWSPrintEncodeMetadata(stream, &(map->web.metadata), NULL, "wms_abstract", + OWS_NOERR, " %s\n", NULL); + } + + /* LogoURL */ + /* The LogoURL have a width, height, format and an URL */ + msOWSPrintURLType( + stream, &(map->web.metadata), "MO", "logourl", OWS_NOERR, NULL, "LogoURL", + NULL, " width=\"%s\"", " height=\"%s\"", " format=\"%s\"", + " \n", + MS_FALSE, MS_FALSE, MS_FALSE, MS_FALSE, MS_TRUE, NULL, NULL, NULL, NULL, + NULL, " "); + + /* DataURL */ + msOWSPrintEncodeMetadata( + stream, &(map->web.metadata), NULL, "wms_dataurl", OWS_NOERR, + " \n \n \n", + NULL); + + /* DescriptionURL */ + /* The DescriptionURL have a width, height, format and an URL */ + /* The metadata is structured like this: "width height format url" */ + msOWSPrintURLType( + stream, &(map->web.metadata), "MO", "descriptionurl", OWS_NOERR, NULL, + "DescriptionURL", NULL, " width=\"%s\"", " height=\"%s\"", + " format=\"%s\"", + " \n", + MS_FALSE, MS_FALSE, MS_FALSE, MS_FALSE, MS_TRUE, NULL, NULL, NULL, NULL, + NULL, " "); + + /* Contact Info */ + msOWSPrintContactInfo(stream, tabspace, OWS_1_1_0, &(map->web.metadata), + "MO"); + + /* Close General */ + msIO_fprintf(stream, " \n"); + free(tabspace); + + /* Set the layer list */ + msIO_fprintf(stream, " \n"); + + /* Loop on all layer */ + for (i = 0; i < map->numlayers; i++) { + if (GET_LAYER(map, i)->status != MS_DELETE && + GET_LAYER(map, i)->connectiontype == MS_WMS) { + const char *pszValue; + char *pszValueMod; + const char *pszCurrent; + if (GET_LAYER(map, i)->status == MS_OFF) + nValue = 1; + else + nValue = 0; + msIO_fprintf(stream, " \n"); + } + } + + /* Close layer list */ + msIO_fprintf(stream, " \n"); + /* Close Map Context */ + + if (nVersion >= OWS_1_0_0) { + msIO_fprintf(stream, "\n"); + } else if (nVersion >= OWS_0_1_7) { + msIO_fprintf(stream, "\n"); + } else { /* 0.1.4 */ + msIO_fprintf(stream, "\n"); + } + + return MS_SUCCESS; +#else + msSetError(MS_MAPCONTEXTERR, + "Not implemented since Map Context is not enabled.", + "msWriteMapContext()"); + return MS_FAILURE; +#endif +} diff --git a/src/mapcontour.c b/src/mapcontour.c new file mode 100644 index 0000000000..53a7352eed --- /dev/null +++ b/src/mapcontour.c @@ -0,0 +1,1081 @@ +/********************************************************************** + * $Id: mapcontour.c 12629 2011-10-06 18:06:34Z aboudreault $ + * + * Project: MapServer + * Purpose: Contour Layer + * Author: Alan Boudreault (aboudreault@mapgears.com) + * Author: Daniel Morissette (dmorissette@mapgears.com) + * + ********************************************************************** + * Copyright (c) 2011, Alan Boudreault, MapGears + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + **********************************************************************/ + +#include "mapserver.h" +#include "mapcopy.h" +#include "mapresample.h" + +#include "ogr_api.h" +#include "ogr_srs_api.h" +#include "gdal.h" +#include "gdal_alg.h" + +#include "mapows.h" +#include "mapthread.h" +#include "mapraster.h" +#include "cpl_string.h" + +#define GEO_TRANS(tr, x, y) ((tr)[0] + (tr)[1] * (x) + (tr)[2] * (y)) + +extern int InvGeoTransform(double *gt_in, double *gt_out); + +typedef struct { + + /* OGR DataSource */ + layerObj ogrLayer; + + /* internal use */ + GDALDatasetH hOrigDS; + GDALDatasetH hDS; + double *buffer; /* memory dataset buffer */ + rectObj extent; /* original dataset extent */ + OGRDataSourceH hOGRDS; + double cellsize; + + /* set if the map->extent and map->projection are + valid in msContourLayerWhichShapes() */ + mapObj *mapToUseForWhichShapes; + +} contourLayerInfo; + +static int msContourLayerInitItemInfo(layerObj *layer) { + contourLayerInfo *clinfo = (contourLayerInfo *)layer->layerinfo; + + if (clinfo == NULL) { + msSetError(MS_MISCERR, "Assertion failed: Contour layer not opened!!!", + "msContourLayerInitItemInfo()"); + return MS_FAILURE; + } + + return msLayerInitItemInfo(&clinfo->ogrLayer); +} + +static void msContourLayerFreeItemInfo(layerObj *layer) { + contourLayerInfo *clinfo = (contourLayerInfo *)layer->layerinfo; + + if (clinfo == NULL) { + msSetError(MS_MISCERR, "Assertion failed: Contour layer not opened!!!", + "msContourLayerFreeItemInfo()"); + return; + } + + msLayerFreeItemInfo(&clinfo->ogrLayer); +} + +static void msContourLayerInfoInitialize(layerObj *layer) { + contourLayerInfo *clinfo = (contourLayerInfo *)layer->layerinfo; + + if (clinfo != NULL) + return; + + clinfo = (contourLayerInfo *)msSmallCalloc(1, sizeof(contourLayerInfo)); + layer->layerinfo = clinfo; + clinfo->hOrigDS = NULL; + clinfo->hDS = NULL; + clinfo->extent.minx = -1.0; + clinfo->extent.miny = -1.0; + clinfo->extent.maxx = -1.0; + clinfo->extent.maxy = -1.0; + + initLayer(&clinfo->ogrLayer, layer->map); + clinfo->ogrLayer.type = layer->type; + clinfo->ogrLayer.debug = layer->debug; + clinfo->ogrLayer.connectiontype = MS_OGR; + clinfo->ogrLayer.name = msStrdup(layer->name); + clinfo->ogrLayer.connection = + (char *)msSmallMalloc(strlen(clinfo->ogrLayer.name) + 13); + sprintf(clinfo->ogrLayer.connection, "__%s_CONTOUR__", clinfo->ogrLayer.name); + clinfo->ogrLayer.units = layer->units; + + if (msOWSLookupMetadata(&(layer->metadata), "OFG", "ID_type") == NULL) { + msInsertHashTable(&(layer->metadata), "gml_ID_type", "Integer"); + } + { + const char *elevItem = CSLFetchNameValue(layer->processing, "CONTOUR_ITEM"); + if (elevItem && strlen(elevItem) > 0) { + char szTmp[100]; + snprintf(szTmp, sizeof(szTmp), "%s_type", elevItem); + if (msOWSLookupMetadata(&(layer->metadata), "OFG", szTmp) == NULL) { + snprintf(szTmp, sizeof(szTmp), "gml_%s_type", elevItem); + msInsertHashTable(&(layer->metadata), szTmp, "Real"); + } + } + } +} + +static void msContourLayerInfoFree(layerObj *layer) { + contourLayerInfo *clinfo = (contourLayerInfo *)layer->layerinfo; + + if (clinfo == NULL) + return; + + freeLayer(&clinfo->ogrLayer); + free(clinfo); + + layer->layerinfo = NULL; +} + +static int msContourLayerReadRaster(layerObj *layer, rectObj rect) { + mapObj *map = layer->map; + char **bands; + int band = 1; + double adfGeoTransform[6], adfInvGeoTransform[6]; + double llx, lly, urx, ury; + rectObj copyRect, mapRect; + int dst_xsize, dst_ysize; + int virtual_grid_step_x, virtual_grid_step_y; + int src_xoff, src_yoff, src_xsize, src_ysize; + double map_cellsize_x, map_cellsize_y, dst_cellsize_x, dst_cellsize_y; + GDALRasterBandH hBand = NULL; + CPLErr eErr; + + contourLayerInfo *clinfo = (contourLayerInfo *)layer->layerinfo; + + if (layer->debug) + msDebug("Entering msContourLayerReadRaster().\n"); + + if (clinfo == NULL || clinfo->hOrigDS == NULL) { + msSetError(MS_MISCERR, "Assertion failed: Contour layer not opened!!!", + "msContourLayerReadRaster()"); + return MS_FAILURE; + } + + bands = CSLTokenizeStringComplex( + CSLFetchNameValue(layer->processing, "BANDS"), " ,", FALSE, FALSE); + if (CSLCount(bands) > 0) { + band = atoi(bands[0]); + if (band < 1 || band > GDALGetRasterCount(clinfo->hOrigDS)) { + msSetError(MS_IMGERR, + "BANDS PROCESSING directive includes illegal band '%d', " + "should be from 1 to %d.", + "msContourLayerReadRaster()", band, + GDALGetRasterCount(clinfo->hOrigDS)); + CSLDestroy(bands); + return MS_FAILURE; + } + } + CSLDestroy(bands); + + hBand = GDALGetRasterBand(clinfo->hOrigDS, band); + if (hBand == NULL) { + msSetError(MS_IMGERR, "Band %d does not exist on dataset.", + "msContourLayerReadRaster()", band); + return MS_FAILURE; + } + + if (layer->projection.numargs > 0 && + EQUAL(layer->projection.args[0], "auto")) { + const char *wkt; + wkt = GDALGetProjectionRef(clinfo->hOrigDS); + if (wkt != NULL && strlen(wkt) > 0) { + if (msOGCWKT2ProjectionObj(wkt, &(layer->projection), layer->debug) != + MS_SUCCESS) { + char msg[MESSAGELENGTH * 2]; + errorObj *ms_error = msGetErrorObj(); + + snprintf(msg, sizeof(msg), + "%s\n" + "PROJECTION AUTO cannot be used for this " + "GDAL raster (`%s').", + ms_error->message, layer->data); + msg[MESSAGELENGTH - 1] = '\0'; + + msSetError(MS_OGRERR, "%s", "msDrawRasterLayer()", msg); + return MS_FAILURE; + } + } + } + + /* + * Compute the georeferenced window of overlap, and read the source data + * downsampled to match output resolution, or at full resolution if + * output resolution is lower than the source resolution. + * + * A large portion of this overlap calculation code was borrowed from + * msDrawRasterLayerGDAL(). + * Would be possible to move some of this to a reusable function? + * + * Note: This code works only if no reprojection is involved. It would + * need rework to support cases where output projection differs from source + * data file projection. + */ + + src_xsize = GDALGetRasterXSize(clinfo->hOrigDS); + src_ysize = GDALGetRasterYSize(clinfo->hOrigDS); + + msGetGDALGeoTransform(clinfo->hOrigDS, map, layer, adfGeoTransform); + + if (layer->transform) { + if (layer->debug) + msDebug("msContourLayerReadRaster(): Entering transform.\n"); + + InvGeoTransform(adfGeoTransform, adfInvGeoTransform); + + mapRect = rect; + + /* if necessary, project the searchrect to source coords */ + if (msProjectionsDiffer(&(map->projection), &(layer->projection))) { + + /* Deal with request in WebMercator, overlapping the anti-meridian, + * and raster in geographic coordinates within (approximately) + * [-180,180] longitude range. + */ + double map_cellsize_x_override = 0; + if (clinfo->mapToUseForWhichShapes) { + mapRect = clinfo->mapToUseForWhichShapes->extent; + const double WEB_MERCATOR_MAX_X = 20037508.34; + if (clinfo->mapToUseForWhichShapes->projection.numargs == 1 && + strcmp(clinfo->mapToUseForWhichShapes->projection.args[0], + "init=epsg:3857") == 0 && + (clinfo->mapToUseForWhichShapes->extent.minx < + -WEB_MERCATOR_MAX_X || + clinfo->mapToUseForWhichShapes->extent.maxx > + WEB_MERCATOR_MAX_X) && + msProjIsGeographicCRS(&layer->projection) && + clinfo->extent.minx > -180 - 2 * adfGeoTransform[1] && + clinfo->extent.maxx < 180 + 2 * adfGeoTransform[1]) { + + // First do a reprojection with +over to compute cellsize_x + msProjectRect(&map->projection, &layer->projection, &mapRect); + map_cellsize_x_override = + MS_CELLSIZE(mapRect.minx, mapRect.maxx, map->width); + + // Then clamp to +/- 180 deg + mapRect = clinfo->mapToUseForWhichShapes->extent; + mapRect.minx = MS_MAX(mapRect.minx, -WEB_MERCATOR_MAX_X); + mapRect.maxx = MS_MIN(mapRect.maxx, WEB_MERCATOR_MAX_X); + } + } + + if (msProjectRect(&map->projection, &layer->projection, &mapRect) != + MS_SUCCESS) { + msDebug("msContourLayerReadRaster(%s): unable to reproject map request " + "rectangle into layer projection, canceling.\n", + layer->name); + return MS_FAILURE; + } + + map_cellsize_x = + map_cellsize_x_override != 0 + ? map_cellsize_x_override + : MS_CELLSIZE(mapRect.minx, mapRect.maxx, map->width); + map_cellsize_y = MS_CELLSIZE(mapRect.miny, mapRect.maxy, map->height); + + /* if the projection failed to project the extent requested, we need to + calculate the cellsize to preserve the initial map cellsize ratio */ + if ((mapRect.minx < GEO_TRANS(adfGeoTransform, 0, src_ysize)) || + (mapRect.maxx > GEO_TRANS(adfGeoTransform, src_xsize, 0)) || + (mapRect.miny < GEO_TRANS(adfGeoTransform + 3, 0, src_ysize)) || + (mapRect.maxy > GEO_TRANS(adfGeoTransform + 3, src_xsize, 0))) { + + int src_unit, dst_unit; + src_unit = GetMapserverUnitUsingProj(&map->projection); + dst_unit = GetMapserverUnitUsingProj(&layer->projection); + if (src_unit == -1 || dst_unit == -1) { + msDebug("msContourLayerReadRaster(%s): unable to reproject map " + "request rectangle into layer projection, canceling.\n", + layer->name); + return MS_FAILURE; + } + + map_cellsize_x = MS_CONVERT_UNIT( + src_unit, dst_unit, MS_CELLSIZE(rect.minx, rect.maxx, map->width)); + map_cellsize_y = MS_CONVERT_UNIT( + src_unit, dst_unit, MS_CELLSIZE(rect.miny, rect.maxy, map->height)); + } + } else { + if (map->cellsize == 0) { + map->cellsize = msAdjustExtent(&mapRect, map->width, map->height); + } + map_cellsize_x = map_cellsize_y = map->cellsize; + } + + if (map_cellsize_x == 0 || map_cellsize_y == 0) { + if (layer->debug) + msDebug("msContourLayerReadRaster(): Cellsize can't be 0.\n"); + return MS_FAILURE; + } + + /* Adjust MapServer pixel model to GDAL pixel model */ + mapRect.minx -= map_cellsize_x * 0.5; + mapRect.maxx += map_cellsize_x * 0.5; + mapRect.miny -= map_cellsize_y * 0.5; + mapRect.maxy += map_cellsize_y * 0.5; + + /* + * If raw data cellsize (from geotransform) is larger than output + * map_cellsize then we want to extract only enough data to match the output + * map resolution which means that GDAL will automatically sample the data + * on read. + * + * To prevent bad contour effects on tile edges, we adjust the target + * cellsize to align the extracted window with a virtual grid based on the + * origin of the raw data and a virtual grid step size corresponding to an + * integer sampling step. + * + * If source data has a greater cellsize (i.e. lower res) that requested + * output map then we use the raw data cellsize as target cellsize since + * there is no point in interpolating the data for contours in this case. + */ + + virtual_grid_step_x = + (int)floor(map_cellsize_x / MS_ABS(adfGeoTransform[1])); + if (virtual_grid_step_x < 1) + virtual_grid_step_x = + 1; /* Do not interpolate data if grid sampling step < 1 */ + + virtual_grid_step_y = + (int)floor(map_cellsize_y / MS_ABS(adfGeoTransform[5])); + if (virtual_grid_step_y < 1) + virtual_grid_step_y = + 1; /* Do not interpolate data if grid sampling step < 1 */ + + /* target cellsize is a multiple of raw data cellsize based on grid step*/ + dst_cellsize_x = MS_ABS(adfGeoTransform[1]) * virtual_grid_step_x; + dst_cellsize_y = MS_ABS(adfGeoTransform[5]) * virtual_grid_step_y; + + /* Compute overlap between source and target views */ + + copyRect = mapRect; + + if (copyRect.minx < GEO_TRANS(adfGeoTransform, 0, src_ysize)) + copyRect.minx = GEO_TRANS(adfGeoTransform, 0, src_ysize); + if (copyRect.maxx > GEO_TRANS(adfGeoTransform, src_xsize, 0)) + copyRect.maxx = GEO_TRANS(adfGeoTransform, src_xsize, 0); + if (copyRect.miny < GEO_TRANS(adfGeoTransform + 3, 0, src_ysize)) + copyRect.miny = GEO_TRANS(adfGeoTransform + 3, 0, src_ysize); + if (copyRect.maxy > GEO_TRANS(adfGeoTransform + 3, src_xsize, 0)) + copyRect.maxy = GEO_TRANS(adfGeoTransform + 3, src_xsize, 0); + + if (copyRect.minx >= copyRect.maxx || copyRect.miny >= copyRect.maxy) { + if (layer->debug) + msDebug("msContourLayerReadRaster(): No overlap.\n"); + return MS_SUCCESS; + } + + /* + * Convert extraction window to raster coordinates + */ + llx = GEO_TRANS(adfInvGeoTransform + 0, copyRect.minx, copyRect.miny); + lly = GEO_TRANS(adfInvGeoTransform + 3, copyRect.minx, copyRect.miny); + urx = GEO_TRANS(adfInvGeoTransform + 0, copyRect.maxx, copyRect.maxy); + ury = GEO_TRANS(adfInvGeoTransform + 3, copyRect.maxx, copyRect.maxy); + + /* + * Align extraction window with virtual grid + * (keep in mind raster coordinates origin is at upper-left) + * We also add an extra buffer to fix tile boundarie issues when zoomed + */ + llx = floor(llx / virtual_grid_step_x) * virtual_grid_step_x - + (virtual_grid_step_x * 5); + urx = ceil(urx / virtual_grid_step_x) * virtual_grid_step_x + + (virtual_grid_step_x * 5); + ury = floor(ury / virtual_grid_step_y) * virtual_grid_step_y - + (virtual_grid_step_x * 5); + lly = ceil(lly / virtual_grid_step_y) * virtual_grid_step_y + + (virtual_grid_step_x * 5); + + src_xoff = MS_MAX(0, (int)floor(llx + 0.5)); + src_yoff = MS_MAX(0, (int)floor(ury + 0.5)); + src_xsize = MS_MIN(MS_MAX(0, (int)(urx - llx + 0.5)), + GDALGetRasterXSize(clinfo->hOrigDS) - src_xoff); + src_ysize = MS_MIN(MS_MAX(0, (int)(lly - ury + 0.5)), + GDALGetRasterYSize(clinfo->hOrigDS) - src_yoff); + + /* Update the geographic extent (buffer added) */ + /* TODO: a better way to go the geo_trans */ + copyRect.minx = GEO_TRANS(adfGeoTransform + 0, src_xoff, 0); + copyRect.maxx = GEO_TRANS(adfGeoTransform + 0, src_xoff + src_xsize, 0); + copyRect.miny = GEO_TRANS(adfGeoTransform + 3, 0, src_yoff + src_ysize); + copyRect.maxy = GEO_TRANS(adfGeoTransform + 3, 0, src_yoff); + + /* + * If input window is to small then stop here + */ + if (src_xsize < 2 || src_ysize < 2) { + if (layer->debug) + msDebug("msContourLayerReadRaster(): input window too small, or no " + "apparent overlap between map view and this window(1).\n"); + return MS_SUCCESS; + } + + /* Target buffer size */ + dst_xsize = (int)ceil((copyRect.maxx - copyRect.minx) / dst_cellsize_x); + dst_ysize = (int)ceil((copyRect.maxy - copyRect.miny) / dst_cellsize_y); + + if (dst_xsize == 0 || dst_ysize == 0) { + if (layer->debug) + msDebug("msContourLayerReadRaster(): no apparent overlap between map " + "view and this window(2).\n"); + return MS_SUCCESS; + } + + if (layer->debug) + msDebug("msContourLayerReadRaster(): src=%d,%d,%d,%d, dst=%d,%d,%d,%d\n", + src_xoff, src_yoff, src_xsize, src_ysize, 0, 0, dst_xsize, + dst_ysize); + } else { + src_xoff = 0; + src_yoff = 0; + dst_xsize = src_xsize = MS_MIN(map->width, src_xsize); + dst_ysize = src_ysize = MS_MIN(map->height, src_ysize); + copyRect.minx = 0; + copyRect.miny = 0; + (void)copyRect.miny; + copyRect.maxx = map->width; + copyRect.maxy = map->height; + (void)copyRect.maxx; + dst_cellsize_y = dst_cellsize_x = 1; + } + + /* -------------------------------------------------------------------- */ + /* Allocate buffer, and read data into it. */ + /* -------------------------------------------------------------------- */ + + clinfo->buffer = (double *)malloc(sizeof(double) * dst_xsize * dst_ysize); + if (clinfo->buffer == NULL) { + msSetError(MS_MEMERR, "Malloc(): Out of memory.", + "msContourLayerReadRaster()"); + return MS_FAILURE; + } + + eErr = GDALRasterIO(hBand, GF_Read, src_xoff, src_yoff, src_xsize, src_ysize, + clinfo->buffer, dst_xsize, dst_ysize, GDT_Float64, 0, 0); + + if (eErr != CE_None) { + msSetError(MS_IOERR, "GDALRasterIO() failed: %s", + "msContourLayerReadRaster()", CPLGetLastErrorMsg()); + free(clinfo->buffer); + clinfo->buffer = NULL; + return MS_FAILURE; + } + + GDALDriverH hMemDRV = GDALGetDriverByName("MEM"); + if (!hMemDRV) { + msSetError(MS_IOERR, "GDAL MEM driver not available", + "msContourLayerReadRaster()"); + free(clinfo->buffer); + clinfo->buffer = NULL; + return MS_FAILURE; + } + + char pointer[64]; + memset(pointer, 0, sizeof(pointer)); + CPLPrintPointer(pointer, clinfo->buffer, sizeof(pointer)); + + clinfo->hDS = GDALCreate(hMemDRV, "", dst_xsize, dst_ysize, 0, 0, NULL); + if (clinfo->hDS == NULL) { + msSetError(MS_IMGERR, "Unable to create GDAL Memory dataset.", + "msContourLayerReadRaster()"); + free(clinfo->buffer); + clinfo->buffer = NULL; + return MS_FAILURE; + } + + char **papszOptions = CSLSetNameValue(NULL, "DATAPOINTER", pointer); + eErr = GDALAddBand(clinfo->hDS, GDT_Float64, papszOptions); + CSLDestroy(papszOptions); + if (eErr != CE_None) { + msSetError(MS_IMGERR, "Unable to add band to GDAL Memory dataset.", + "msContourLayerReadRaster()"); + free(clinfo->buffer); + clinfo->buffer = NULL; + return MS_FAILURE; + } + + { + // Copy nodata value from source dataset to memory dataset + int bHasNoData = FALSE; + double dfNoDataValue = GDALGetRasterNoDataValue(hBand, &bHasNoData); + if (bHasNoData) { + GDALSetRasterNoDataValue(GDALGetRasterBand(clinfo->hDS, 1), + dfNoDataValue); + } + } + + adfGeoTransform[0] = copyRect.minx; + adfGeoTransform[1] = dst_cellsize_x; + adfGeoTransform[2] = 0; + adfGeoTransform[3] = copyRect.maxy; + adfGeoTransform[4] = 0; + adfGeoTransform[5] = -dst_cellsize_y; + + clinfo->cellsize = MS_MAX(dst_cellsize_x, dst_cellsize_y); + { + char buf[64]; + sprintf(buf, "%lf", clinfo->cellsize); + msInsertHashTable(&layer->metadata, "__data_cellsize__", buf); + } + + GDALSetGeoTransform(clinfo->hDS, adfGeoTransform); + return MS_SUCCESS; +} + +static void msContourOGRCloseConnection(void *conn_handle) { + OGRDataSourceH hDS = (OGRDataSourceH)conn_handle; + + msAcquireLock(TLOCK_OGR); + OGR_DS_Destroy(hDS); + msReleaseLock(TLOCK_OGR); +} + +/* Function that parses multiple options in the a list. It also supports + min/maxscaledenom checks. ie. "CONTOUR_INTERVAL=0,3842942:10" */ +static char *msContourGetOption(layerObj *layer, const char *name) { + int c, i, found = MS_FALSE; + char **values, **tmp, **options; + double maxscaledenom, minscaledenom; + char *value = NULL; + + options = CSLFetchNameValueMultiple(layer->processing, name); + c = CSLCount(options); + + /* First pass to find the value among options that have min/maxscaledenom */ + /* specified */ + for (i = 0; i < c && found == MS_FALSE; ++i) { + values = CSLTokenizeStringComplex(options[i], ":", FALSE, FALSE); + if (CSLCount(values) == 2) { + tmp = CSLTokenizeStringComplex(values[0], ",", FALSE, FALSE); + if (CSLCount(tmp) == 2) { + minscaledenom = atof(tmp[0]); + maxscaledenom = atof(tmp[1]); + if (layer->map->scaledenom <= 0 || + (((maxscaledenom <= 0) || + (layer->map->scaledenom <= maxscaledenom)) && + ((minscaledenom <= 0) || + (layer->map->scaledenom > minscaledenom)))) { + value = msStrdup(values[1]); + found = MS_TRUE; + } + } + CSLDestroy(tmp); + } + CSLDestroy(values); + } + + /* Second pass to find the value among options that do NOT have */ + /* min/maxscaledenom specified */ + for (i = 0; i < c && found == MS_FALSE; ++i) { + values = CSLTokenizeStringComplex(options[i], ":", FALSE, FALSE); + if (CSLCount(values) == 1) { + value = msStrdup(values[0]); + found = MS_TRUE; + } + CSLDestroy(values); + } + + CSLDestroy(options); + + return value; +} + +static int msContourLayerGenerateContour(layerObj *layer) { + OGRSFDriverH hDriver; + OGRFieldDefnH hFld; + OGRLayerH hLayer; + const char *elevItem; + char *option; + double interval = 1.0, levels[1000]; + int levelCount = 0; + GDALRasterBandH hBand = NULL; + CPLErr eErr; + int bHasNoData = FALSE; + double dfNoDataValue; + + contourLayerInfo *clinfo = (contourLayerInfo *)layer->layerinfo; + + OGRRegisterAll(); + + if (clinfo == NULL) { + msSetError(MS_MISCERR, "Assertion failed: Contour layer not opened!!!", + "msContourLayerCreateOGRDataSource()"); + return MS_FAILURE; + } + + if (!clinfo->hDS) { /* no overlap */ + return MS_SUCCESS; + } + + hBand = GDALGetRasterBand(clinfo->hDS, 1); + if (hBand == NULL) { + msSetError(MS_IMGERR, "Band %d does not exist on dataset.", + "msContourLayerGenerateContour()", 1); + return MS_FAILURE; + } + + /* Create the OGR DataSource */ +#if GDAL_VERSION_MAJOR > 3 || \ + (GDAL_VERSION_MAJOR == 3 && GDAL_VERSION_MINOR >= 11) + const char *pszDrvName = "MEM"; +#else + const char *pszDrvName = "Memory"; +#endif + hDriver = OGRGetDriverByName(pszDrvName); + if (hDriver == NULL) { + msSetError(MS_OGRERR, "Unable to get OGR driver '%s'.", + "msContourLayerCreateOGRDataSource()", pszDrvName); + return MS_FAILURE; + } + + clinfo->hOGRDS = OGR_Dr_CreateDataSource(hDriver, "", NULL); + if (clinfo->hOGRDS == NULL) { + msSetError(MS_OGRERR, "Unable to create OGR DataSource.", + "msContourLayerCreateOGRDataSource()"); + return MS_FAILURE; + } + + hLayer = OGR_DS_CreateLayer(clinfo->hOGRDS, clinfo->ogrLayer.name, NULL, + wkbLineString, NULL); + + hFld = OGR_Fld_Create("ID", OFTInteger); + OGR_Fld_SetWidth(hFld, 8); + OGR_L_CreateField(hLayer, hFld, FALSE); + OGR_Fld_Destroy(hFld); + + /* Check if we have a coutour item specified */ + elevItem = CSLFetchNameValue(layer->processing, "CONTOUR_ITEM"); + if (elevItem && strlen(elevItem) > 0) { + hFld = OGR_Fld_Create(elevItem, OFTReal); + OGR_Fld_SetWidth(hFld, 12); + OGR_Fld_SetPrecision(hFld, 3); + OGR_L_CreateField(hLayer, hFld, FALSE); + OGR_Fld_Destroy(hFld); + } else { + elevItem = NULL; + } + + option = msContourGetOption(layer, "CONTOUR_INTERVAL"); + if (option) { + interval = atof(option); + free(option); + } + + option = msContourGetOption(layer, "CONTOUR_LEVELS"); + if (option) { + int i, c; + char **levelsTmp; + levelsTmp = CSLTokenizeStringComplex(option, ",", FALSE, FALSE); + c = CSLCount(levelsTmp); + for (i = 0; i < c && i < (int)(sizeof(levels) / sizeof(double)); ++i) + levels[levelCount++] = atof(levelsTmp[i]); + + CSLDestroy(levelsTmp); + free(option); + } + + dfNoDataValue = GDALGetRasterNoDataValue(hBand, &bHasNoData); + + eErr = GDALContourGenerate( + hBand, interval, 0.0, levelCount, levels, bHasNoData, dfNoDataValue, + hLayer, OGR_FD_GetFieldIndex(OGR_L_GetLayerDefn(hLayer), "ID"), + (elevItem == NULL) + ? -1 + : OGR_FD_GetFieldIndex(OGR_L_GetLayerDefn(hLayer), elevItem), + NULL, NULL); + + if (eErr != CE_None) { + msSetError(MS_IOERR, "GDALContourGenerate() failed: %s", + "msContourLayerGenerateContour()", CPLGetLastErrorMsg()); + return MS_FAILURE; + } + + msConnPoolRegister(&clinfo->ogrLayer, clinfo->hOGRDS, + msContourOGRCloseConnection); + + return MS_SUCCESS; +} + +int msContourLayerOpen(layerObj *layer) { + char *decrypted_path; + char szPath[MS_MAXPATHLEN]; + contourLayerInfo *clinfo; + + if (layer->debug) + msDebug("Entering msContourLayerOpen().\n"); + + /* If we don't have info, initialize an empty one now */ + if (layer->layerinfo == NULL) + msContourLayerInfoInitialize(layer); + + clinfo = (contourLayerInfo *)layer->layerinfo; + if (layer->data == NULL && layer->tileindex == NULL) { + msSetError(MS_MISCERR, "Layer %s has neither DATA nor TILEINDEX defined.", + "msContourLayerOpen()", layer->name); + return MS_FAILURE; + } + + if (layer->tileindex != NULL) { + char szTilename[MS_MAXPATHLEN]; + int status; + int tilelayerindex, tileitemindex, tilesrsindex; + rectObj searchrect; + layerObj *tlp; + shapeObj tshp; + char tilesrsname[1]; + + msInitShape(&tshp); + searchrect = layer->map->extent; + + status = msDrawRasterSetupTileLayer(layer->map, layer, &searchrect, + MS_FALSE, &tilelayerindex, + &tileitemindex, &tilesrsindex, &tlp); + if (status == MS_FAILURE) { + return MS_FAILURE; + } + + status = msDrawRasterIterateTileIndex(layer, tlp, &tshp, tileitemindex, -1, + szTilename, sizeof(szTilename), + tilesrsname, sizeof(tilesrsname)); + if (status == MS_FAILURE || status == MS_DONE) { + if (status == MS_DONE) { + if (layer->debug) + msDebug("No raster matching filter.\n"); + } + msDrawRasterCleanupTileLayer(tlp, tilelayerindex); + return MS_FAILURE; + } + + msDrawRasterCleanupTileLayer(tlp, tilelayerindex); + + msDrawRasterBuildRasterPath(layer->map, layer, szTilename, szPath); + decrypted_path = msStrdup(szPath); + + /* Cancel the time filter that might have been set on ours in case of */ + /* a inline tileindex */ + msFreeExpression(&layer->filter); + msInitExpression(&layer->filter); + } else { + msTryBuildPath3(szPath, layer->map->mappath, layer->map->shapepath, + layer->data); + decrypted_path = msDecryptStringTokens(layer->map, szPath); + } + + GDALAllRegister(); + + /* Open the original Dataset */ + + msAcquireLock(TLOCK_GDAL); + if (decrypted_path) { + clinfo->hOrigDS = GDALOpen(decrypted_path, GA_ReadOnly); + msFree(decrypted_path); + } else + clinfo->hOrigDS = NULL; + + if (clinfo->hOrigDS) { + const int src_xsize = GDALGetRasterXSize(clinfo->hOrigDS); + const int src_ysize = GDALGetRasterYSize(clinfo->hOrigDS); + + /* set the Dataset extent */ + double adfGeoTransform[6]; + msGetGDALGeoTransform(clinfo->hOrigDS, layer->map, layer, adfGeoTransform); + clinfo->extent.minx = adfGeoTransform[0]; + clinfo->extent.maxy = adfGeoTransform[3]; + clinfo->extent.maxx = adfGeoTransform[0] + src_xsize * adfGeoTransform[1]; + clinfo->extent.miny = adfGeoTransform[3] + src_ysize * adfGeoTransform[5]; + } + + msReleaseLock(TLOCK_GDAL); + + if (clinfo->hOrigDS == NULL) { + msSetError(MS_IMGERR, "Unable to open GDAL dataset.", + "msContourLayerOpen()"); + return MS_FAILURE; + } + + return MS_SUCCESS; +} + +int msContourLayerIsOpen(layerObj *layer) { + if (layer->layerinfo) + return MS_TRUE; + return MS_FALSE; +} + +int msContourLayerClose(layerObj *layer) { + contourLayerInfo *clinfo = (contourLayerInfo *)layer->layerinfo; + + if (layer->debug) + msDebug("Entering msContourLayerClose().\n"); + + if (clinfo) { + if (clinfo->hOGRDS) + msConnPoolRelease(&clinfo->ogrLayer, clinfo->hOGRDS); + + msLayerClose(&clinfo->ogrLayer); + + if (clinfo->hDS) { + GDALClose(clinfo->hDS); + clinfo->hDS = NULL; + free(clinfo->buffer); + } + + if (clinfo->hOrigDS) { + GDALClose(clinfo->hOrigDS); + clinfo->hOrigDS = NULL; + } + + msContourLayerInfoFree(layer); + } + + return MS_SUCCESS; +} + +int msContourLayerGetItems(layerObj *layer) { + const char *elevItem; + contourLayerInfo *clinfo = (contourLayerInfo *)layer->layerinfo; + + if (clinfo == NULL) { + msSetError(MS_MISCERR, "Assertion failed: Contour layer not opened!!!", + "msContourLayerGetItems()"); + return MS_FAILURE; + } + + layer->numitems = 0; + layer->items = (char **)msSmallCalloc(sizeof(char *), 2); + + layer->items[layer->numitems++] = msStrdup("ID"); + elevItem = CSLFetchNameValue(layer->processing, "CONTOUR_ITEM"); + if (elevItem && strlen(elevItem) > 0) { + layer->items[layer->numitems++] = msStrdup(elevItem); + } + + return MS_SUCCESS; +} + +void msContourLayerUseMapExtentAndProjectionForNextWhichShapes(layerObj *layer, + mapObj *map) { + contourLayerInfo *clinfo = (contourLayerInfo *)layer->layerinfo; + clinfo->mapToUseForWhichShapes = map; +} + +int msContourLayerWhichShapes(layerObj *layer, rectObj rect, int isQuery) { + int i; + rectObj newRect; + contourLayerInfo *clinfo = (contourLayerInfo *)layer->layerinfo; + + if (layer->debug) + msDebug("Entering msContourLayerWhichShapes().\n"); + + if (clinfo == NULL) { + msSetError(MS_MISCERR, "Assertion failed: Contour layer not opened!!!", + "msContourLayerWhichShapes()"); + return MS_FAILURE; + } + + if (isQuery) { + newRect = layer->map->extent; + } else { + newRect = rect; + /* if necessary, project the searchrect to source coords */ + if (msProjectionsDiffer(&(layer->map->projection), &(layer->projection))) { + if (msProjectRect(&layer->projection, &layer->map->projection, + &newRect) != MS_SUCCESS) { + msDebug("msContourLayerWhichShapes(%s): unable to reproject map " + "request rectangle into layer projection, canceling.\n", + layer->name); + return MS_FAILURE; + } + } + } + + /* regenerate the raster io */ + if (clinfo->hOGRDS) + msConnPoolRelease(&clinfo->ogrLayer, clinfo->hOGRDS); + + msLayerClose(&clinfo->ogrLayer); + + /* Open the raster source */ + if (msContourLayerReadRaster(layer, newRect) != MS_SUCCESS) + return MS_FAILURE; + + /* Generate Contour Dataset */ + if (msContourLayerGenerateContour(layer) != MS_SUCCESS) + return MS_FAILURE; + + if (clinfo->hDS) { + GDALClose(clinfo->hDS); + clinfo->hDS = NULL; + free(clinfo->buffer); + } + + if (!clinfo->hOGRDS) /* no overlap */ + return MS_DONE; + + /* Open our virtual ogr layer */ + if (msLayerOpen(&clinfo->ogrLayer) != MS_SUCCESS) + return MS_FAILURE; + + clinfo->ogrLayer.numitems = layer->numitems; + clinfo->ogrLayer.items = + (char **)msSmallMalloc(sizeof(char *) * layer->numitems); + for (i = 0; i < layer->numitems; ++i) { + clinfo->ogrLayer.items[i] = msStrdup(layer->items[i]); + } + + const rectObj invalid_rect = MS_INIT_INVALID_RECT; + return msLayerWhichShapes(&clinfo->ogrLayer, invalid_rect, isQuery); +} + +int msContourLayerGetShape(layerObj *layer, shapeObj *shape, + resultObj *record) { + contourLayerInfo *clinfo = (contourLayerInfo *)layer->layerinfo; + + if (layer->debug) + msDebug("Entering msContourLayerGetShape().\n"); + + if (clinfo == NULL) { + msSetError(MS_MISCERR, "Assertion failed: Contour layer not opened!!!", + "msContourLayerGetShape()"); + return MS_FAILURE; + } + + return msLayerGetShape(&clinfo->ogrLayer, shape, record); +} + +int msContourLayerNextShape(layerObj *layer, shapeObj *shape) { + contourLayerInfo *clinfo = (contourLayerInfo *)layer->layerinfo; + + if (layer->debug) + msDebug("Entering msContourLayerNextShape().\n"); + + if (clinfo == NULL) { + msSetError(MS_MISCERR, "Assertion failed: Contour layer not opened!!!", + "msContourLayerNextShape()"); + return MS_FAILURE; + } + + return msLayerNextShape(&clinfo->ogrLayer, shape); +} + +/************************************************************************/ +/* msContourLayerGetExtent() */ +/* Simple copy of the maprasterquery.c file. might change in the future */ +/************************************************************************/ + +int msContourLayerGetExtent(layerObj *layer, rectObj *extent) { + contourLayerInfo *clinfo = (contourLayerInfo *)layer->layerinfo; + + if (layer->debug) + msDebug("Entering msContourLayerGetExtent().\n"); + + if (clinfo == NULL) { + msSetError(MS_MISCERR, "Assertion failed: Contour layer not opened!!!", + "msContourLayerGetExtent()"); + return MS_FAILURE; + } + + MS_COPYRECT(extent, &clinfo->extent); + + return MS_SUCCESS; +} + +/************************************************************************/ +/* msContourLayerSetTimeFilter() */ +/* */ +/* This function is actually just used in the context of */ +/* setting a filter on the tileindex for time based queries. */ +/* For instance via WMS requests. */ +/* */ +/* If a local shapefile tileindex is in use, we will set a */ +/* backtics filter (shapefile compatible). If another layer is */ +/* being used as the tileindex then we will forward the */ +/* SetTimeFilter call to it. If there is no tileindex in */ +/* place, we do nothing. */ +/************************************************************************/ + +int msContourLayerSetTimeFilter(layerObj *layer, const char *timestring, + const char *timefield) { + int tilelayerindex; + + if (layer->debug) + msDebug("msContourLayerSetTimeFilter(%s,%s).\n", timestring, timefield); + + /* -------------------------------------------------------------------- */ + /* If we don't have a tileindex the time filter has no effect. */ + /* -------------------------------------------------------------------- */ + if (layer->tileindex == NULL) { + if (layer->debug) + msDebug("msContourLayerSetTimeFilter(): time filter without effect on " + "layers without tileindex.\n"); + return MS_SUCCESS; + } + + /* -------------------------------------------------------------------- */ + /* Find the tileindex layer. */ + /* -------------------------------------------------------------------- */ + tilelayerindex = msGetLayerIndex(layer->map, layer->tileindex); + + /* -------------------------------------------------------------------- */ + /* If we are using a local shapefile as our tileindex (that is */ + /* to say, the tileindex name is not of another layer), then we */ + /* just install a backtics style filter on the current layer. */ + /* -------------------------------------------------------------------- */ + if (tilelayerindex == -1) + return msLayerMakeBackticsTimeFilter(layer, timestring, timefield); + + /* -------------------------------------------------------------------- */ + /* Otherwise we invoke the tileindex layers SetTimeFilter */ + /* method. */ + /* -------------------------------------------------------------------- */ + if (msCheckParentPointer(layer->map, "map") == MS_FAILURE) + return MS_FAILURE; + return msLayerSetTimeFilter(layer->GET_LAYER(map, tilelayerindex), timestring, + timefield); +} + +/************************************************************************/ +/* msContourLayerInitializeVirtualTable() */ +/************************************************************************/ + +int msContourLayerInitializeVirtualTable(layerObj *layer) { + assert(layer != NULL); + assert(layer->vtable != NULL); + + layer->vtable->LayerInitItemInfo = msContourLayerInitItemInfo; + layer->vtable->LayerFreeItemInfo = msContourLayerFreeItemInfo; + layer->vtable->LayerOpen = msContourLayerOpen; + layer->vtable->LayerIsOpen = msContourLayerIsOpen; + layer->vtable->LayerWhichShapes = msContourLayerWhichShapes; + layer->vtable->LayerNextShape = msContourLayerNextShape; + layer->vtable->LayerGetShape = msContourLayerGetShape; + /* layer->vtable->LayerGetShapeCount, use default */ + layer->vtable->LayerClose = msContourLayerClose; + layer->vtable->LayerGetItems = msContourLayerGetItems; + layer->vtable->LayerGetExtent = msContourLayerGetExtent; + /* layer->vtable->LayerGetAutoStyle, use default */ + /* layer->vtable->LayerApplyFilterToLayer, use default */ + /*layer->vtable->LayerCloseConnection = msContourLayerClose;*/ + /* we use backtics for proper tileindex shapefile functioning */ + layer->vtable->LayerSetTimeFilter = msContourLayerSetTimeFilter; + /* layer->vtable->LayerCreateItems, use default */ + /* layer->vtable->LayerGetNumFeatures, use default */ + + return MS_SUCCESS; +} diff --git a/mapcopy.c b/src/mapcopy.c similarity index 81% rename from mapcopy.c rename to src/mapcopy.c index 20fc4fb53a..2d1a32485e 100644 --- a/mapcopy.c +++ b/src/mapcopy.c @@ -47,27 +47,27 @@ #include "mapcopy.h" +#include "cpl_string.h" + /*********************************************************************** - * msCopyProjectioExtended() * + * msCopyProjectionExtended() * * * * Copy a projectionObj while adding additional arguments * **********************************************************************/ -int msCopyProjectionExtended(projectionObj *dst, projectionObj *src, char ** args, int num_args) -{ - - int i; - +int msCopyProjectionExtended(projectionObj *dst, const projectionObj *src, + const char *const *args, int num_args) { MS_COPYSTELEM(numargs); MS_COPYSTELEM(gt); - MS_COPYSTELEM(automatic); - for (i = 0; i < dst->numargs; i++) { + for (int i = 0; i < dst->numargs; i++) { /* Our destination consists of unallocated pointers */ dst->args[i] = msStrdup(src->args[i]); } - for(i=0 ; i< num_args; i++) { - dst->args[dst->numargs++] = msStrdup(args[i]); + if (args) { + for (int i = 0; i < num_args; i++) { + dst->args[dst->numargs++] = msStrdup(args[i]); + } } msProjectionInheritContextFrom(dst, src); if (dst->numargs != 0) { @@ -84,9 +84,8 @@ int msCopyProjectionExtended(projectionObj *dst, projectionObj *src, char ** arg * Copy a projectionObj * **********************************************************************/ -int msCopyProjection(projectionObj *dst, projectionObj *src) -{ - return msCopyProjectionExtended(dst,src,NULL,0); +int msCopyProjection(projectionObj *dst, const projectionObj *src) { + return msCopyProjectionExtended(dst, src, NULL, 0); } /*********************************************************************** @@ -94,8 +93,7 @@ int msCopyProjection(projectionObj *dst, projectionObj *src) * * * Copy a lineObj, using msCopyPoint() * **********************************************************************/ -int msCopyLine(lineObj *dst, lineObj *src) -{ +int msCopyLine(lineObj *dst, const lineObj *src) { int i; @@ -141,8 +139,7 @@ int msCopyShapeObj(shapeObj *dst, shapeObj *src) { * Copy an itemObj * **********************************************************************/ -int msCopyItem(itemObj *dst, itemObj *src) -{ +int msCopyItem(itemObj *dst, const itemObj *src) { MS_COPYSTRING(dst->name, src->name); MS_COPYSTELEM(type); @@ -159,9 +156,8 @@ int msCopyItem(itemObj *dst, itemObj *src) * Copy a hashTableObj, using msInsertHashTable() * **********************************************************************/ -int msCopyHashTable(hashTableObj *dst, hashTableObj *src) -{ - const char *key=NULL; +int msCopyHashTable(hashTableObj *dst, const hashTableObj *src) { + const char *key = NULL; while (1) { key = msNextKeyFromHashTable(src, key); if (!key) @@ -178,17 +174,12 @@ int msCopyHashTable(hashTableObj *dst, hashTableObj *src) * Copy a fontSetObj, using msCreateHashTable() and msCopyHashTable() * **********************************************************************/ -int msCopyFontSet(fontSetObj *dst, fontSetObj *src, mapObj *map) -{ +int msCopyFontSet(fontSetObj *dst, const fontSetObj *src, mapObj *map) { MS_COPYSTRING(dst->filename, src->filename); MS_COPYSTELEM(numfonts); - if (&(src->fonts)) { - /* if (!dst->fonts) */ - /* dst->fonts = msCreateHashTable(); */ - if (msCopyHashTable(&(dst->fonts), &(src->fonts)) != MS_SUCCESS) - return MS_FAILURE; - } + if (msCopyHashTable(&(dst->fonts), &(src->fonts)) != MS_SUCCESS) + return MS_FAILURE; dst->map = map; @@ -201,9 +192,9 @@ int msCopyFontSet(fontSetObj *dst, fontSetObj *src, mapObj *map) * Copy an expressionObj, but only its string, type and flags * **********************************************************************/ -int msCopyExpression(expressionObj *dst, expressionObj *src) -{ - if((dst->type == MS_REGEX) && dst->compiled) ms_regfree(&(dst->regex)); +int msCopyExpression(expressionObj *dst, const expressionObj *src) { + if ((dst->type == MS_REGEX) && dst->compiled) + ms_regfree(&(dst->regex)); dst->compiled = MS_FALSE; MS_COPYSTRING(dst->string, src->string); @@ -219,8 +210,7 @@ int msCopyExpression(expressionObj *dst, expressionObj *src) * Copy a joinObj * **********************************************************************/ -int msCopyJoin(joinObj *dst, joinObj *src) -{ +int msCopyJoin(joinObj *dst, const joinObj *src) { MS_COPYSTRING(dst->name, src->name); /* makes no sense to copy the items or values @@ -253,8 +243,7 @@ int msCopyJoin(joinObj *dst, joinObj *src) * Copy a queryMapObj, using msCopyColor() * **********************************************************************/ -int msCopyQueryMap(queryMapObj *dst, queryMapObj *src) -{ +int msCopyQueryMap(queryMapObj *dst, const queryMapObj *src) { MS_COPYSTELEM(height); MS_COPYSTELEM(width); MS_COPYSTELEM(status); @@ -264,15 +253,13 @@ int msCopyQueryMap(queryMapObj *dst, queryMapObj *src) return MS_SUCCESS; } - /*********************************************************************** * msCopyLeader() * * * * Copy a labelLeaderObj, using msCopyStyle() * **********************************************************************/ -int msCopyLabelLeader(labelLeaderObj *dst, labelLeaderObj *src) -{ +int msCopyLabelLeader(labelLeaderObj *dst, const labelLeaderObj *src) { int i; assert(dst && src); MS_COPYSTELEM(gridstep); @@ -282,9 +269,10 @@ int msCopyLabelLeader(labelLeaderObj *dst, labelLeaderObj *src) */ /* free any previous styles on the dst label */ - for(i=0; inumstyles; i++) { /* each style */ - if (dst->styles[i]!=NULL) { - if( freeStyle(dst->styles[i]) == MS_SUCCESS ) msFree(dst->styles[i]); + for (i = 0; i < dst->numstyles; i++) { /* each style */ + if (dst->styles[i] != NULL) { + if (freeStyle(dst->styles[i]) == MS_SUCCESS) + msFree(dst->styles[i]); } } dst->numstyles = 0; @@ -311,13 +299,13 @@ int msCopyLabelLeader(labelLeaderObj *dst, labelLeaderObj *src) * Copy a labelObj, using msCopyColor() and msCopyStyle() * **********************************************************************/ -int msCopyLabel(labelObj *dst, labelObj *src) -{ +int msCopyLabel(labelObj *dst, const labelObj *src) { int i; - for(i=0; ibindings[i].item, src->bindings[i].item); - dst->bindings[i].index = src->bindings[i].index; /* no way to use the macros */ + dst->bindings[i].index = + src->bindings[i].index; /* no way to use the macros */ MS_COPYSTRING(dst->exprBindings[i].string, src->exprBindings[i].string); dst->exprBindings[i].type = src->exprBindings[i].type; } @@ -360,7 +348,6 @@ int msCopyLabel(labelObj *dst, labelObj *src) MS_COPYSTELEM(repeatdistance); MS_COPYSTELEM(maxoverlapangle); - MS_COPYSTRING(dst->encoding, src->encoding); MS_COPYSTELEM(outlinewidth); @@ -381,9 +368,10 @@ int msCopyLabel(labelObj *dst, labelObj *src) */ /* free any previous styles on the dst label */ - for(i=0; inumstyles; i++) { /* each style */ - if (dst->styles[i]!=NULL) { - if( freeStyle(dst->styles[i]) == MS_SUCCESS ) msFree(dst->styles[i]); + for (i = 0; i < dst->numstyles; i++) { /* each style */ + if (dst->styles[i] != NULL) { + if (freeStyle(dst->styles[i]) == MS_SUCCESS) + msFree(dst->styles[i]); } } dst->numstyles = 0; @@ -402,12 +390,12 @@ int msCopyLabel(labelObj *dst, labelObj *src) dst->numstyles++; } - if(src->leader) { + if (src->leader) { dst->leader = msSmallMalloc(sizeof(labelLeaderObj)); initLeader(dst->leader); - msCopyLabelLeader(dst->leader,src->leader); + msCopyLabelLeader(dst->leader, src->leader); } else { - if(dst->leader) { + if (dst->leader) { freeLabelLeader(dst->leader); msFree(dst->leader); } @@ -427,10 +415,8 @@ int msCopyLabel(labelObj *dst, labelObj *src) * msCopyHashTable() * **********************************************************************/ -int msCopyWeb(webObj *dst, webObj *src, mapObj *map) -{ +int msCopyWeb(webObj *dst, const webObj *src, mapObj *map) { - MS_COPYSTRING(dst->log, src->log); MS_COPYSTRING(dst->imagepath, src->imagepath); MS_COPYSTRING(dst->imageurl, src->imageurl); dst->map = map; @@ -444,25 +430,20 @@ int msCopyWeb(webObj *dst, webObj *src, mapObj *map) MS_COPYSTRING(dst->empty, src->empty); MS_COPYSTRING(dst->error, src->error); - MS_COPYRECT(&(dst->extent), &(src->extent)); - MS_COPYSTELEM(minscaledenom); MS_COPYSTELEM(maxscaledenom); MS_COPYSTRING(dst->mintemplate, src->mintemplate); MS_COPYSTRING(dst->maxtemplate, src->maxtemplate); - if (&(src->metadata)) { - /* dst->metadata = msCreateHashTable(); */ - if (msCopyHashTable(&(dst->metadata), &(src->metadata)) != MS_SUCCESS) - return MS_FAILURE; - } - msCopyHashTable(&dst->validation,&src->validation); + if (msCopyHashTable(&(dst->metadata), &(src->metadata)) != MS_SUCCESS) + return MS_FAILURE; + msCopyHashTable(&dst->validation, &src->validation); MS_COPYSTRING(dst->queryformat, src->queryformat); MS_COPYSTRING(dst->legendformat, src->legendformat); MS_COPYSTRING(dst->browseformat, src->browseformat); - return MS_SUCCESS ; + return MS_SUCCESS; } /*********************************************************************** @@ -471,13 +452,13 @@ int msCopyWeb(webObj *dst, webObj *src, mapObj *map) * Copy a styleObj, using msCopyColor() * **********************************************************************/ -int msCopyStyle(styleObj *dst, styleObj *src) -{ +int msCopyStyle(styleObj *dst, const styleObj *src) { int i; - for(i=0; ibindings[i].item, src->bindings[i].item); - dst->bindings[i].index = src->bindings[i].index; /* no way to use the macros */ + dst->bindings[i].index = + src->bindings[i].index; /* no way to use the macros */ MS_COPYSTRING(dst->exprBindings[i].string, src->exprBindings[i].string); dst->exprBindings[i].type = src->exprBindings[i].type; } @@ -485,20 +466,20 @@ int msCopyStyle(styleObj *dst, styleObj *src) MS_COPYSTELEM(nexprbindings); MS_COPYCOLOR(&(dst->color), &(src->color)); - MS_COPYCOLOR(&(dst->outlinecolor),&(src->outlinecolor)); - MS_COPYCOLOR(&(dst->backgroundcolor), &(src->backgroundcolor)); + MS_COPYCOLOR(&(dst->outlinecolor), &(src->outlinecolor)); MS_COPYCOLOR(&(dst->mincolor), &(src->mincolor)); MS_COPYCOLOR(&(dst->maxcolor), &(src->maxcolor)); MS_COPYSTRING(dst->symbolname, src->symbolname); MS_COPYSTELEM(patternlength); - for(i=0; ipatternlength; i++) - dst->pattern[i]=src->pattern[i]; + for (i = 0; i < src->patternlength; i++) + dst->pattern[i] = src->pattern[i]; MS_COPYSTELEM(initialgap); MS_COPYSTELEM(gap); MS_COPYSTELEM(linejoin); MS_COPYSTELEM(linejoinmaxsize); + MS_COPYSTELEM(antialiased); MS_COPYSTELEM(linecap); MS_COPYSTELEM(symbol); MS_COPYSTELEM(size); @@ -536,11 +517,11 @@ int msCopyStyle(styleObj *dst, styleObj *src) * msCopyLabel(), msCreateHashTable(), msCopyHashTable() * **********************************************************************/ -int msCopyClass(classObj *dst, classObj *src, layerObj *layer) -{ +int msCopyClass(classObj *dst, const classObj *src, layerObj *layer_unused) { int i, return_value; + (void)layer_unused; - return_value = msCopyExpression(&(dst->expression),&(src->expression)); + return_value = msCopyExpression(&(dst->expression), &(src->expression)); if (return_value != MS_SUCCESS) { msSetError(MS_MEMERR, "Failed to copy expression.", "msCopyClass()"); return MS_FAILURE; @@ -550,9 +531,9 @@ int msCopyClass(classObj *dst, classObj *src, layerObj *layer) MS_COPYSTELEM(isfallback); /* free any previous styles on the dst layer */ - for(i=0; inumstyles; i++) { /* each style */ - if (dst->styles[i]!=NULL) { - if( freeStyle(dst->styles[i]) == MS_SUCCESS ) { + for (i = 0; i < dst->numstyles; i++) { /* each style */ + if (dst->styles[i] != NULL) { + if (freeStyle(dst->styles[i]) == MS_SUCCESS) { msFree(dst->styles[i]); } } @@ -574,7 +555,7 @@ int msCopyClass(classObj *dst, classObj *src, layerObj *layer) dst->numstyles++; } - for (i=0; inumlabels; i++) { + for (i = 0; i < src->numlabels; i++) { if (msGrowClassLabels(dst) == NULL) return MS_FAILURE; initLabel(dst->labels[i]); @@ -587,15 +568,15 @@ int msCopyClass(classObj *dst, classObj *src, layerObj *layer) } MS_COPYSTELEM(numlabels); - if(src->leader) { - if(dst->leader) { + if (src->leader) { + if (dst->leader) { freeLabelLeader(dst->leader); } - if(!dst->leader) { + if (!dst->leader) { dst->leader = msSmallMalloc(sizeof(labelLeaderObj)); initLeader(dst->leader); } - msCopyLabelLeader(dst->leader,src->leader); + msCopyLabelLeader(dst->leader, src->leader); } MS_COPYSTRING(dst->keyimage, src->keyimage); @@ -614,11 +595,8 @@ int msCopyClass(classObj *dst, classObj *src, layerObj *layer) MS_COPYSTRING(dst->_template, src->_template); #endif - if (&(src->metadata) != NULL) { - /* dst->metadata = msCreateHashTable(); */ - msCopyHashTable(&(dst->metadata), &(src->metadata)); - } - msCopyHashTable(&dst->validation,&src->validation); + msCopyHashTable(&(dst->metadata), &(src->metadata)); + msCopyHashTable(&dst->validation, &src->validation); MS_COPYSTELEM(minscaledenom); MS_COPYSTELEM(maxscaledenom); @@ -631,21 +609,20 @@ int msCopyClass(classObj *dst, classObj *src, layerObj *layer) return MS_SUCCESS; } -int msCopyCluster(clusterObj *dst, clusterObj *src) -{ +int msCopyCluster(clusterObj *dst, const clusterObj *src) { int return_value; MS_COPYSTELEM(maxdistance); MS_COPYSTELEM(buffer); MS_COPYSTRING(dst->region, src->region); - return_value = msCopyExpression(&(dst->group),&(src->group)); + return_value = msCopyExpression(&(dst->group), &(src->group)); if (return_value != MS_SUCCESS) { msSetError(MS_MEMERR, "Failed to copy cluster group.", "msCopyCluster()"); return MS_FAILURE; } - return_value = msCopyExpression(&(dst->filter),&(src->filter)); + return_value = msCopyExpression(&(dst->filter), &(src->filter)); if (return_value != MS_SUCCESS) { msSetError(MS_MEMERR, "Failed to copy cluster filter.", "msCopyCluster()"); return MS_FAILURE; @@ -658,8 +635,7 @@ int msCopyCluster(clusterObj *dst, clusterObj *src) * msCopyGrid() * **********************************************************************/ -int msCopyGrid(graticuleObj *dst, graticuleObj *src) -{ +int msCopyGrid(graticuleObj *dst, const graticuleObj *src) { MS_COPYSTELEM(dwhichlatitude); MS_COPYSTELEM(dwhichlongitude); MS_COPYSTELEM(dstartlatitude); @@ -680,7 +656,7 @@ int msCopyGrid(graticuleObj *dst, graticuleObj *src) MS_COPYSTELEM(ilabeltype); MS_COPYRECT(&(dst->extent), &(src->extent)); MS_COPYSTRING(dst->labelformat, src->labelformat); - + return MS_SUCCESS; } @@ -695,8 +671,8 @@ int msCopyGrid(graticuleObj *dst, graticuleObj *src) * make exact copies, this method might not get much use. * **********************************************************************/ -int msCopyLabelCacheMember(labelCacheMemberObj *dst, labelCacheMemberObj *src) -{ +int msCopyLabelCacheMember(labelCacheMemberObj *dst, + const labelCacheMemberObj *src) { int i; MS_COPYSTELEM(featuresize); @@ -707,7 +683,7 @@ int msCopyLabelCacheMember(labelCacheMemberObj *dst, labelCacheMemberObj *src) } MS_COPYSTELEM(numlabels); - dst->labels = (labelObj *) msSmallMalloc(sizeof(labelObj)*dst->numlabels); + dst->labels = (labelObj *)msSmallMalloc(sizeof(labelObj) * dst->numlabels); for (i = 0; i < dst->numlabels; i++) { msCopyLabel(&(dst->labels[i]), &(src->labels[i])); } @@ -730,8 +706,7 @@ int msCopyLabelCacheMember(labelCacheMemberObj *dst, labelCacheMemberObj *src) **********************************************************************/ int msCopyMarkerCacheMember(markerCacheMemberObj *dst, - markerCacheMemberObj *src) -{ + const markerCacheMemberObj *src) { MS_COPYSTELEM(id); /* msCopyShape(&(dst->poly), &(src->poly)); */ @@ -742,8 +717,7 @@ int msCopyMarkerCacheMember(markerCacheMemberObj *dst, * msCopyLabelCacheSlot() * **********************************************************************/ -int msCopyLabelCacheSlot(labelCacheSlotObj *dst, labelCacheSlotObj *src) -{ +int msCopyLabelCacheSlot(labelCacheSlotObj *dst, const labelCacheSlotObj *src) { int i; for (i = 0; i < dst->numlabels; i++) { @@ -763,12 +737,11 @@ int msCopyLabelCacheSlot(labelCacheSlotObj *dst, labelCacheSlotObj *src) * msCopyLabelCache() * **********************************************************************/ -int msCopyLabelCache(labelCacheObj *dst, labelCacheObj *src) -{ +int msCopyLabelCache(labelCacheObj *dst, const labelCacheObj *src) { int p; MS_COPYSTELEM(numlabels); - for (p=0; pslots[p]), &(src->slots[p])); } @@ -781,8 +754,7 @@ int msCopyLabelCache(labelCacheObj *dst, labelCacheObj *src) * msCopyResult() * **********************************************************************/ -int msCopyResult(resultObj *dst, resultObj *src) -{ +int msCopyResult(resultObj *dst, const resultObj *src) { MS_COPYSTELEM(shapeindex); MS_COPYSTELEM(tileindex); MS_COPYSTELEM(classindex); @@ -795,8 +767,7 @@ int msCopyResult(resultObj *dst, resultObj *src) * msCopyResultCache() * **********************************************************************/ -int msCopyResultCache(resultCacheObj *dst, resultCacheObj *src) -{ +int msCopyResultCache(resultCacheObj *dst, const resultCacheObj *src) { int i; MS_COPYSTELEM(cachesize); MS_COPYSTELEM(numresults); @@ -815,9 +786,8 @@ int msCopyResultCache(resultCacheObj *dst, resultCacheObj *src) * msCopyRect(), msCopyColor() * **********************************************************************/ -int msCopyReferenceMap(referenceMapObj *dst, referenceMapObj *src, - mapObj *map) -{ +int msCopyReferenceMap(referenceMapObj *dst, const referenceMapObj *src, + mapObj *map) { initReferenceMap(dst); @@ -826,9 +796,8 @@ int msCopyReferenceMap(referenceMapObj *dst, referenceMapObj *src, MS_COPYSTELEM(height); MS_COPYSTELEM(width); - MS_COPYCOLOR(&(dst->color), &(src->color)); - MS_COPYCOLOR(&(dst->outlinecolor),&(src->outlinecolor)); + MS_COPYCOLOR(&(dst->outlinecolor), &(src->outlinecolor)); MS_COPYSTRING(dst->image, src->image); MS_COPYSTELEM(status); @@ -849,8 +818,7 @@ int msCopyReferenceMap(referenceMapObj *dst, referenceMapObj *src, * and msCopyLabel() * **********************************************************************/ -int msCopyScalebar(scalebarObj *dst, scalebarObj *src) -{ +int msCopyScalebar(scalebarObj *dst, const scalebarObj *src) { initScalebar(dst); @@ -861,7 +829,7 @@ int msCopyScalebar(scalebarObj *dst, scalebarObj *src) MS_COPYSTELEM(intervals); if (msCopyLabel(&(dst->label), &(src->label)) != MS_SUCCESS) { - msSetError(MS_MEMERR, "Failed to copy label.","msCopyScalebar()"); + msSetError(MS_MEMERR, "Failed to copy label.", "msCopyScalebar()"); return MS_FAILURE; } @@ -874,7 +842,6 @@ int msCopyScalebar(scalebarObj *dst, scalebarObj *src) MS_COPYSTELEM(status); MS_COPYSTELEM(position); MS_COPYSTELEM(transparent); - MS_COPYSTELEM(interlace); MS_COPYSTELEM(postlabelcache); MS_COPYSTELEM(align); @@ -887,16 +854,14 @@ int msCopyScalebar(scalebarObj *dst, scalebarObj *src) * Copy a legendObj, using msCopyColor() * **********************************************************************/ -int msCopyLegend(legendObj *dst, legendObj *src, mapObj *map) -{ +int msCopyLegend(legendObj *dst, const legendObj *src, mapObj *map) { int return_value; MS_COPYCOLOR(&(dst->imagecolor), &(src->imagecolor)); return_value = msCopyLabel(&(dst->label), &(src->label)); if (return_value != MS_SUCCESS) { - msSetError(MS_MEMERR, "Failed to copy label.", - "msCopyLegend()"); + msSetError(MS_MEMERR, "Failed to copy label.", "msCopyLegend()"); return MS_FAILURE; } @@ -905,14 +870,13 @@ int msCopyLegend(legendObj *dst, legendObj *src, mapObj *map) MS_COPYSTELEM(keyspacingx); MS_COPYSTELEM(keyspacingy); - MS_COPYCOLOR(&(dst->outlinecolor),&(src->outlinecolor)); + MS_COPYCOLOR(&(dst->outlinecolor), &(src->outlinecolor)); MS_COPYSTELEM(status); MS_COPYSTELEM(height); MS_COPYSTELEM(width); MS_COPYSTELEM(position); MS_COPYSTELEM(transparent); - MS_COPYSTELEM(interlace); MS_COPYSTELEM(postlabelcache); #ifndef __cplusplus @@ -925,32 +889,35 @@ int msCopyLegend(legendObj *dst, legendObj *src, mapObj *map) return MS_SUCCESS; } -int msCopyScaleTokenEntry(scaleTokenEntryObj *src, scaleTokenEntryObj *dst) { - MS_COPYSTRING(dst->value,src->value); +int msCopyScaleTokenEntry(const scaleTokenEntryObj *src, + scaleTokenEntryObj *dst) { + MS_COPYSTRING(dst->value, src->value); MS_COPYSTELEM(minscale); MS_COPYSTELEM(maxscale); return MS_SUCCESS; } -int msCopyScaleToken(scaleTokenObj *src, scaleTokenObj *dst) { +int msCopyScaleToken(const scaleTokenObj *src, scaleTokenObj *dst) { int i; - MS_COPYSTRING(dst->name,src->name); + MS_COPYSTRING(dst->name, src->name); MS_COPYSTELEM(n_entries); - dst->tokens = (scaleTokenEntryObj*)msSmallCalloc(src->n_entries,sizeof(scaleTokenEntryObj)); - for(i=0;in_entries;i++) { - msCopyScaleTokenEntry(&src->tokens[i],&dst->tokens[i]); + dst->tokens = (scaleTokenEntryObj *)msSmallCalloc(src->n_entries, + sizeof(scaleTokenEntryObj)); + for (i = 0; i < src->n_entries; i++) { + msCopyScaleTokenEntry(&src->tokens[i], &dst->tokens[i]); } return MS_SUCCESS; } -int msCopyCompositingFilter(CompositingFilter **pdst, CompositingFilter *src) { +int msCopyCompositingFilter(CompositingFilter **pdst, + const CompositingFilter *src) { CompositingFilter *dst = NULL; - if(!src) { + if (!src) { *pdst = NULL; return MS_SUCCESS; } - while(src) { - if(!dst) { + while (src) { + if (!dst) { dst = *pdst = msSmallMalloc(sizeof(CompositingFilter)); } else { dst->next = msSmallMalloc(sizeof(CompositingFilter)); @@ -963,15 +930,15 @@ int msCopyCompositingFilter(CompositingFilter **pdst, CompositingFilter *src) { return MS_SUCCESS; } -int msCopyCompositer(LayerCompositer **ldst, LayerCompositer *src) { +int msCopyCompositer(LayerCompositer **ldst, const LayerCompositer *src) { LayerCompositer *dst = NULL; - if(!src) { + if (!src) { *ldst = NULL; return MS_SUCCESS; } - while(src) { - if(!dst) { + while (src) { + if (!dst) { dst = *ldst = msSmallMalloc(sizeof(LayerCompositer)); } else { dst->next = msSmallMalloc(sizeof(LayerCompositer)); @@ -996,8 +963,7 @@ int msCopyCompositer(LayerCompositer **ldst, LayerCompositer *src) { * As it stands, we are not copying a layer's resultcache * **********************************************************************/ -int msCopyLayer(layerObj *dst, layerObj *src) -{ +int msCopyLayer(layerObj *dst, const layerObj *src) { int i, return_value; featureListNodeObjPtr current; @@ -1006,11 +972,11 @@ int msCopyLayer(layerObj *dst, layerObj *src) MS_COPYSTELEM(classitemindex); - for(i = 0; i < src->numscaletokens; i++) { - if(msGrowLayerScaletokens(dst) == NULL) + for (i = 0; i < src->numscaletokens; i++) { + if (msGrowLayerScaletokens(dst) == NULL) return MS_FAILURE; initScaleToken(&dst->scaletokens[i]); - msCopyScaleToken(&src->scaletokens[i],&dst->scaletokens[i]); + msCopyScaleToken(&src->scaletokens[i], &dst->scaletokens[i]); dst->numscaletokens++; } @@ -1019,7 +985,7 @@ int msCopyLayer(layerObj *dst, layerObj *src) return MS_FAILURE; #ifndef __cplusplus initClass(dst->class[i]); - return_value = msCopyClass(dst->class[i], src->class[i], dst); + return_value = msCopyClass(dst->class[i], src -> class[i], dst); #else initClass(dst->_class[i]); return_value = msCopyClass(dst->_class[i], src->_class[i], dst); @@ -1048,6 +1014,8 @@ int msCopyLayer(layerObj *dst, layerObj *src) MS_COPYSTELEM(type); MS_COPYSTELEM(tolerance); MS_COPYSTELEM(toleranceunits); + MS_COPYSTELEM(identificationclassauto); + MS_COPYSTRING(dst->identificationclassgroup, src->identificationclassgroup); MS_COPYSTELEM(symbolscaledenom); MS_COPYSTELEM(scalefactor); MS_COPYSTELEM(minscaledenom); @@ -1077,13 +1045,13 @@ int msCopyLayer(layerObj *dst, layerObj *src) MS_COPYSTRING(dst->tileindex, src->tileindex); - return_value = msCopyProjection(&(dst->projection),&(src->projection)); + return_value = msCopyProjection(&(dst->projection), &(src->projection)); if (return_value != MS_SUCCESS) { msSetError(MS_MEMERR, "Failed to copy projection.", "msCopyLayer()"); return MS_FAILURE; } - return_value = msCopyCluster(&(dst->cluster),&(src->cluster)); + return_value = msCopyCluster(&(dst->cluster), &(src->cluster)); if (return_value != MS_SUCCESS) { return MS_FAILURE; } @@ -1092,7 +1060,7 @@ int msCopyLayer(layerObj *dst, layerObj *src) MS_COPYSTELEM(units); current = src->features; - while(current != NULL) { + while (current != NULL) { insertFeatureList(&(dst->features), &(current->shape)); current = current->next; } @@ -1121,19 +1089,13 @@ int msCopyLayer(layerObj *dst, layerObj *src) MS_COPYSTRING(dst->requires, src->requires); MS_COPYSTRING(dst->labelrequires, src->labelrequires); - if (&(src->metadata)) { - msCopyHashTable(&(dst->metadata), &(src->metadata)); - } - msCopyHashTable(&dst->validation,&src->validation); + msCopyHashTable(&(dst->metadata), &(src->metadata)); + msCopyHashTable(&dst->validation, &src->validation); + msCopyHashTable(&dst->connectionoptions, &src->connectionoptions); - MS_COPYSTELEM(dump); MS_COPYSTELEM(debug); - /* No need to copy the numprocessing member, as it is incremented by - msLayerAddProcessing */ - for (i = 0; i < src->numprocessing; i++) { - msLayerAddProcessing(dst, msLayerGetProcessing(src, i)); - } + dst->processing = CSLDuplicate(src->processing); MS_COPYSTELEM(numjoins); @@ -1154,13 +1116,13 @@ int msCopyLayer(layerObj *dst, layerObj *src) freeGrid(dst->grid); msFree(dst->grid); } - dst->grid = (void *) malloc(sizeof(graticuleObj)); + dst->grid = (void *)malloc(sizeof(graticuleObj)); MS_CHECK_ALLOC(dst->grid, sizeof(graticuleObj), -1); initGrid(dst->grid); msCopyGrid(dst->grid, src->grid); } - if(src->compositer) { + if (src->compositer) { msCopyCompositer(&dst->compositer, src->compositer); } @@ -1176,8 +1138,7 @@ int msCopyLayer(layerObj *dst, layerObj *src) * msCopyOutputFormat(), msCopyWeb(), msCopyReferenceMap() * **********************************************************************/ -int msCopyMap(mapObj *dst, mapObj *src) -{ +int msCopyMap(mapObj *dst, const mapObj *src) { int i, return_value; outputFormatObj *format; @@ -1207,16 +1168,12 @@ int msCopyMap(mapObj *dst, mapObj *src) } return_value = msCopySymbolSet(&(dst->symbolset), &(src->symbolset), dst); - if(return_value != MS_SUCCESS) { + if (return_value != MS_SUCCESS) { msSetError(MS_MEMERR, "Failed to copy symbolset.", "msCopyMap()"); return MS_FAILURE; } /* msCopyLabelCache(&(dst->labelcache), &(src->labelcache)); */ - MS_COPYSTELEM(transparent); - MS_COPYSTELEM(interlace); - MS_COPYSTELEM(imagequality); - MS_COPYRECT(&(dst->extent), &(src->extent)); MS_COPYSTELEM(cellsize); @@ -1231,32 +1188,30 @@ int msCopyMap(mapObj *dst, mapObj *src) MS_COPYCOLOR(&(dst->imagecolor), &(src->imagecolor)); /* clear existing destination format list */ - if( dst->outputformat && --dst->outputformat->refcount < 1 ) { - msFreeOutputFormat( dst->outputformat ); + if (dst->outputformat && --dst->outputformat->refcount < 1) { + msFreeOutputFormat(dst->outputformat); dst->outputformat = NULL; } - for(i=0; i < dst->numoutputformats; i++ ) { - if( --dst->outputformatlist[i]->refcount < 1 ) - msFreeOutputFormat( dst->outputformatlist[i] ); + for (i = 0; i < dst->numoutputformats; i++) { + if (--dst->outputformatlist[i]->refcount < 1) + msFreeOutputFormat(dst->outputformatlist[i]); } - if( dst->outputformatlist != NULL ) - msFree( dst->outputformatlist ); + if (dst->outputformatlist != NULL) + msFree(dst->outputformatlist); dst->outputformatlist = NULL; dst->outputformat = NULL; dst->numoutputformats = 0; for (i = 0; i < src->numoutputformats; i++) - msAppendOutputFormat( dst, - msCloneOutputFormat( src->outputformatlist[i]) ); + msAppendOutputFormat(dst, msCloneOutputFormat(src->outputformatlist[i])); /* set the active output format */ MS_COPYSTRING(dst->imagetype, src->imagetype); - format = msSelectOutputFormat( dst, dst->imagetype ); - msApplyOutputFormat(&(dst->outputformat), format, MS_NOOVERRIDE, - MS_NOOVERRIDE, MS_NOOVERRIDE ); + format = msSelectOutputFormat(dst, dst->imagetype); + msApplyOutputFormat(&(dst->outputformat), format, MS_NOOVERRIDE); - return_value = msCopyProjection(&(dst->projection),&(src->projection)); + return_value = msCopyProjection(&(dst->projection), &(src->projection)); if (return_value != MS_SUCCESS) { msSetError(MS_MEMERR, "Failed to copy projection.", "msCopyMap()"); return MS_FAILURE; @@ -1264,8 +1219,7 @@ int msCopyMap(mapObj *dst, mapObj *src) /* No need to copy latlon projection */ - return_value = msCopyReferenceMap(&(dst->reference),&(src->reference), - dst); + return_value = msCopyReferenceMap(&(dst->reference), &(src->reference), dst); if (return_value != MS_SUCCESS) { msSetError(MS_MEMERR, "Failed to copy reference.", "msCopyMap()"); return MS_FAILURE; @@ -1277,7 +1231,7 @@ int msCopyMap(mapObj *dst, mapObj *src) return MS_FAILURE; } - return_value = msCopyLegend(&(dst->legend), &(src->legend),dst); + return_value = msCopyLegend(&(dst->legend), &(src->legend), dst); if (return_value != MS_SUCCESS) { msSetError(MS_MEMERR, "Failed to copy legend.", "msCopyMap()"); return MS_FAILURE; @@ -1295,16 +1249,17 @@ int msCopyMap(mapObj *dst, mapObj *src) return MS_FAILURE; } - if( src->layerorder ) { + if (src->layerorder) { for (i = 0; i < dst->numlayers; i++) { - MS_COPYSTELEM(layerorder[i]); + MS_COPYSTELEM(layerorder[i]); } } MS_COPYSTELEM(debug); MS_COPYSTRING(dst->datapattern, src->datapattern); MS_COPYSTRING(dst->templatepattern, src->templatepattern); - if( msCopyHashTable( &(dst->configoptions), &(src->configoptions) ) != MS_SUCCESS ) + if (msCopyHashTable(&(dst->configoptions), &(src->configoptions)) != + MS_SUCCESS) return MS_FAILURE; return MS_SUCCESS; @@ -1312,19 +1267,24 @@ int msCopyMap(mapObj *dst, mapObj *src) int msCopyRasterBuffer(rasterBufferObj *dst, const rasterBufferObj *src) { *dst = *src; - if(src->type == MS_BUFFER_BYTE_RGBA) { + if (src->type == MS_BUFFER_BYTE_RGBA) { dst->data.rgba = src->data.rgba; - dst->data.rgba.pixels = msSmallMalloc(src->height * src->data.rgba.row_step); - memcpy(dst->data.rgba.pixels, src->data.rgba.pixels, src->data.rgba.row_step*src->height); - dst->data.rgba.r = dst->data.rgba.pixels + (src->data.rgba.r - src->data.rgba.pixels); - dst->data.rgba.g = dst->data.rgba.pixels + (src->data.rgba.g - src->data.rgba.pixels); - dst->data.rgba.b = dst->data.rgba.pixels + (src->data.rgba.b - src->data.rgba.pixels); - if(src->data.rgba.a) { - dst->data.rgba.a = dst->data.rgba.pixels + (src->data.rgba.a - src->data.rgba.pixels); + dst->data.rgba.pixels = + msSmallMalloc(((size_t)src->height) * src->data.rgba.row_step); + memcpy(dst->data.rgba.pixels, src->data.rgba.pixels, + ((size_t)src->data.rgba.row_step) * src->height); + dst->data.rgba.r = + dst->data.rgba.pixels + (src->data.rgba.r - src->data.rgba.pixels); + dst->data.rgba.g = + dst->data.rgba.pixels + (src->data.rgba.g - src->data.rgba.pixels); + dst->data.rgba.b = + dst->data.rgba.pixels + (src->data.rgba.b - src->data.rgba.pixels); + if (src->data.rgba.a) { + dst->data.rgba.a = + dst->data.rgba.pixels + (src->data.rgba.a - src->data.rgba.pixels); } else { dst->data.rgba.a = NULL; } } return MS_SUCCESS; } - diff --git a/src/mapcopy.h b/src/mapcopy.h new file mode 100644 index 0000000000..1ed5990eda --- /dev/null +++ b/src/mapcopy.h @@ -0,0 +1,70 @@ +/****************************************************************************** + * $Id$ + * + * Project: MapServer + * Purpose: Declarations related to copyng mapObjs. Provided by Mladen Turk + * for resolution of bug 701 + * http://mapserver.gis.umn.edu/bugs/show_bug.cgi?id=701. + * Author: Mladen Turk (and Sean Gilles?) + * + ****************************************************************************** + * Copyright (c) 1996-2005 Regents of the University of Minnesota. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + ****************************************************************************/ + +/* Following works for GCC and MSVC. That's ~98% of our users, if Tyler + * Mitchell's survey is correct + */ +#define MS_COPYSTELEM(_name) (dst)->/**/ _name = (src)->/**/ _name + +#define MS_MACROBEGIN do { +#define MS_MACROEND \ + } \ + while (0) + +#define MS_COPYRECT(_dst, _src) \ + MS_MACROBEGIN(_dst)->minx = (_src)->minx; \ + (_dst)->miny = (_src)->miny; \ + (_dst)->maxx = (_src)->maxx; \ + (_dst)->maxy = (_src)->maxy; \ + MS_MACROEND + +#define MS_COPYPOINT(_dst, _src) \ + MS_MACROBEGIN(_dst)->x = (_src)->x; \ + (_dst)->y = (_src)->y; \ + (_dst)->m = (_src)->m; \ + MS_MACROEND + +#define MS_COPYCOLOR(_dst, _src) \ + MS_MACROBEGIN(_dst)->red = (_src)->red; \ + (_dst)->green = (_src)->green; \ + (_dst)->blue = (_src)->blue; \ + (_dst)->alpha = (_src)->alpha; \ + MS_MACROEND + +#define MS_COPYSTRING(_dst, _src) \ + MS_MACROBEGIN \ + if ((_dst) != NULL) \ + msFree((_dst)); \ + if ((_src)) \ + (_dst) = msStrdup((_src)); \ + else \ + (_dst) = NULL; \ + MS_MACROEND diff --git a/mapcpl.c b/src/mapcpl.c similarity index 80% rename from mapcpl.c rename to src/mapcpl.c index 1e09a244c5..bad88c940d 100644 --- a/mapcpl.c +++ b/src/mapcpl.c @@ -41,27 +41,24 @@ #include #include "mapserver.h" - - /* should be size of largest possible filename */ #define MS_PATH_BUF_SIZE 2048 -static char szStaticResult[MS_PATH_BUF_SIZE]; - +static char szStaticResult[MS_PATH_BUF_SIZE]; /************************************************************************/ /* msFindFilenameStart() */ /************************************************************************/ -static int msFindFilenameStart( const char * pszFilename ) +static int msFindFilenameStart(const char *pszFilename) { - int iFileStart; + int iFileStart; - for( iFileStart = strlen(pszFilename); - iFileStart > 0 - && pszFilename[iFileStart-1] != '/' - && pszFilename[iFileStart-1] != '\\'; - iFileStart-- ) {} + for (iFileStart = strlen(pszFilename); + iFileStart > 0 && pszFilename[iFileStart - 1] != '/' && + pszFilename[iFileStart - 1] != '\\'; + iFileStart--) { + } return iFileStart; } @@ -90,24 +87,25 @@ static int msFindFilenameStart( const char * pszFilename ) * may be destroyed by the next ms filename handling call. */ -const char *msGetBasename( const char *pszFullFilename ) +const char *msGetBasename(const char *pszFullFilename) { - int iFileStart = msFindFilenameStart( pszFullFilename ); + int iFileStart = msFindFilenameStart(pszFullFilename); int iExtStart, nLength; - for( iExtStart = strlen(pszFullFilename); + for (iExtStart = strlen(pszFullFilename); iExtStart > iFileStart && pszFullFilename[iExtStart] != '.'; - iExtStart-- ) {} + iExtStart--) { + } - if( iExtStart == iFileStart ) + if (iExtStart == iFileStart) iExtStart = strlen(pszFullFilename); nLength = iExtStart - iFileStart; - assert( nLength < MS_PATH_BUF_SIZE ); + assert(nLength < MS_PATH_BUF_SIZE); - strlcpy( szStaticResult, pszFullFilename + iFileStart, nLength+1 ); + strlcpy(szStaticResult, pszFullFilename + iFileStart, nLength + 1); return szStaticResult; } @@ -159,43 +157,42 @@ const char *msGetBasename( const char *pszFullFilename ) * found, or the shared library can't be loaded. */ -void *msGetSymbol( const char * pszLibrary, const char * pszSymbolName ) -{ - void *pLibrary; - void *pSymbol; +void *msGetSymbol(const char *pszLibrary, const char *pszSymbolName) { + void *pLibrary; + void *pSymbol; pLibrary = dlopen(pszLibrary, RTLD_LAZY); - if( pLibrary == NULL ) { - msSetError(MS_MISCERR, - "Dynamic loading failed: %s", - "msGetSymbol()", dlerror()); + if (pLibrary == NULL) { + msSetError(MS_MISCERR, "Dynamic loading failed: %s", "msGetSymbol()", + dlerror()); return NULL; } - pSymbol = dlsym( pLibrary, pszSymbolName ); + pSymbol = dlsym(pLibrary, pszSymbolName); #if (defined(__APPLE__) && defined(__MACH__)) /* On mach-o systems, C symbols have a leading underscore and depending * on how dlcompat is configured it may or may not add the leading * underscore. So if dlsym() fails add an underscore and try again. */ - if( pSymbol == NULL ) { + if (pSymbol == NULL) { char withUnder[strlen(pszSymbolName) + 2]; withUnder[0] = '_'; withUnder[1] = 0; strcat(withUnder, pszSymbolName); - pSymbol = dlsym( pLibrary, withUnder ); + pSymbol = dlsym(pLibrary, withUnder); } #endif - if( pSymbol == NULL ) { - msSetError(MS_MISCERR, - "Dynamic loading failed: %s", - "msGetSymbol()", dlerror()); + if (pSymbol == NULL) { + msSetError(MS_MISCERR, "Dynamic loading failed: %s", "msGetSymbol()", + dlerror()); return NULL; } - return( pSymbol ); + /* We accept leakage of pLibrary */ + /* coverity[leaked_storage] */ + return (pSymbol); } #endif /* def __unix__ && defined(HAVE_DLFCN_H) */ @@ -213,29 +210,26 @@ void *msGetSymbol( const char * pszLibrary, const char * pszSymbolName ) /* msGetSymbol() */ /************************************************************************/ -void *msGetSymbol( const char * pszLibrary, const char * pszSymbolName ) -{ - void *pLibrary; - void *pSymbol; +void *msGetSymbol(const char *pszLibrary, const char *pszSymbolName) { + void *pLibrary; + void *pSymbol; pLibrary = LoadLibrary(pszLibrary); - if( pLibrary == NULL ) { - msSetError(MS_MISCERR, - "Can't load requested dynamic library: %s", + if (pLibrary == NULL) { + msSetError(MS_MISCERR, "Can't load requested dynamic library: %s", "msGetSymbol()", pszLibrary); return NULL; } - pSymbol = (void *) GetProcAddress( (HINSTANCE) pLibrary, pszSymbolName ); + pSymbol = (void *)GetProcAddress((HINSTANCE)pLibrary, pszSymbolName); - if( pSymbol == NULL ) { - msSetError(MS_MISCERR, - "Can't find requested entry point: %s in lib %s", + if (pSymbol == NULL) { + msSetError(MS_MISCERR, "Can't find requested entry point: %s in lib %s", "msGetSymbol()", pszSymbolName, pLibrary); return NULL; } - return( pSymbol ); + return (pSymbol); } #endif /* def _WIN32 */ @@ -252,11 +246,11 @@ void *msGetSymbol( const char * pszLibrary, const char * pszSymbolName ) /* Dummy implementation. */ /************************************************************************/ -void *msGetSymbol(const char *pszLibrary, const char *pszEntryPoint) -{ - msSetError(MS_MISCERR, - "msGetSymbol(%s,%s) called. Failed as this is stub implementation.", - "msGetSymbol()", pszLibrary, pszEntryPoint); +void *msGetSymbol(const char *pszLibrary, const char *pszEntryPoint) { + msSetError( + MS_MISCERR, + "msGetSymbol(%s,%s) called. Failed as this is stub implementation.", + "msGetSymbol()", pszLibrary, pszEntryPoint); return NULL; } #endif diff --git a/mapcrypto.c b/src/mapcrypto.c similarity index 78% rename from mapcrypto.c rename to src/mapcrypto.c index 0e665c947a..67e2ec7481 100644 --- a/mapcrypto.c +++ b/src/mapcrypto.c @@ -28,14 +28,13 @@ ****************************************************************************/ #include -#include /* isxdigit() */ -#include /* rand() */ -#include /* time() */ +#include /* isxdigit() */ +#include /* rand() */ +#include /* time() */ #include "mapserver.h" - - +#include "cpl_conv.h" /********************************************************************** * encipher() and decipher() from the Tiny Encryption Algorithm (TEA) @@ -86,35 +85,34 @@ **********************************************************************/ static void encipher(const ms_uint32 *const v, ms_uint32 *const w, - const ms_uint32 *const k) -{ - register ms_uint32 y=v[0],z=v[1],sum=0,delta=0x9E3779B9,n=32; + const ms_uint32 *const k) { + register ms_uint32 y = v[0], z = v[1], sum = 0, delta = 0x9E3779B9, n = 32; - while(n-->0) { - y += ((z << 4 ^ z >> 5) + z) ^ (sum + k[sum&3]); + while (n-- > 0) { + y += ((z << 4 ^ z >> 5) + z) ^ (sum + k[sum & 3]); sum += delta; - z += ((y << 4 ^ y >> 5) + y) ^ (sum + k[sum>>11 & 3]); + z += ((y << 4 ^ y >> 5) + y) ^ (sum + k[sum >> 11 & 3]); } - w[0]=y; - w[1]=z; + w[0] = y; + w[1] = z; } static void decipher(const ms_uint32 *const v, ms_uint32 *const w, - const ms_uint32 *const k) -{ - register ms_uint32 y=v[0],z=v[1],sum=0xC6EF3720, delta=0x9E3779B9,n=32; + const ms_uint32 *const k) { + register ms_uint32 y = v[0], z = v[1], sum = 0xC6EF3720, delta = 0x9E3779B9, + n = 32; /* sum = delta<<5, in general sum = delta * n */ - while(n-->0) { - z -= ((y << 4 ^ y >> 5) + y) ^ (sum + k[sum>>11 & 3]); + while (n-- > 0) { + z -= ((y << 4 ^ y >> 5) + y) ^ (sum + k[sum >> 11 & 3]); sum -= delta; - y -= ((z << 4 ^ z >> 5) + z) ^ (sum + k[sum&3]); + y -= ((z << 4 ^ z >> 5) + z) ^ (sum + k[sum & 3]); } - w[0]=y; - w[1]=z; + w[0] = y; + w[1] = z; } /********************************************************************** @@ -125,13 +123,12 @@ static void decipher(const ms_uint32 *const v, ms_uint32 *const w, * out[] should be preallocated by the caller to be at least 2*numbytes+1 * (+1 for the terminating '\0') **********************************************************************/ -void msHexEncode(const unsigned char *in, char *out, int numbytes) -{ +void msHexEncode(const unsigned char *in, char *out, int numbytes) { char *hex = "0123456789ABCDEF"; while (numbytes-- > 0) { - *out++ = hex[*in/16]; - *out++ = hex[*in%16]; + *out++ = hex[*in / 16]; + *out++ = hex[*in % 16]; in++; } *out = '\0'; @@ -151,20 +148,19 @@ void msHexEncode(const unsigned char *in, char *out, int numbytes) * Returns the number of bytes written to out[] which may be different from * numchars/2 if an error or a '\0' is encountered. **********************************************************************/ -int msHexDecode(const char *in, unsigned char *out, int numchars) -{ +int msHexDecode(const char *in, unsigned char *out, int numchars) { int numbytes_out = 0; /* Make sure numchars is even */ - numchars = (numchars/2) * 2; + numchars = (numchars / 2) * 2; if (numchars < 2) numchars = -1; /* Will result in this value being ignored in the loop*/ - while (*in != '\0' && *(in+1) != '\0' && numchars != 0) { - *out = 0x10 * (*in >= 'A' ? ((*in & 0xdf) - 'A')+10 : (*in - '0')); + while (*in != '\0' && *(in + 1) != '\0' && numchars != 0) { + *out = 0x10 * (*in >= 'A' ? ((*in & 0xdf) - 'A') + 10 : (*in - '0')); in++; - *out += (*in >= 'A' ? ((*in & 0xdf) - 'A')+10 : (*in - '0')); + *out += (*in >= 'A' ? ((*in & 0xdf) - 'A') + 10 : (*in - '0')); in++; out++; @@ -176,7 +172,6 @@ int msHexDecode(const char *in, unsigned char *out, int numchars) return numbytes_out; } - /********************************************************************** * msGenerateEncryptionKey() * @@ -185,15 +180,16 @@ int msHexDecode(const char *in, unsigned char *out, int numchars) * The output buffer should be at least MS_ENCRYPTION_KEY_SIZE bytes. **********************************************************************/ -int msGenerateEncryptionKey(unsigned char *k) -{ +int msGenerateEncryptionKey(unsigned char *k) { int i; /* Use current time as seed for rand() */ - srand( (unsigned int) time( NULL )); + srand((unsigned int)time(NULL)); - for(i=0; iencryption_key_loaded) - return MS_SUCCESS; /* Already loaded */ + return MS_SUCCESS; /* Already loaded */ keyfile = msGetConfigOption(map, "MS_ENCRYPTION_KEY"); + if (!keyfile) + keyfile = CPLGetConfigOption("MS_ENCRYPTION_KEY", NULL); - if (keyfile == NULL) - keyfile = getenv("MS_ENCRYPTION_KEY"); - - if (keyfile && - msReadEncryptionKeyFromFile(keyfile,map->encryption_key) == MS_SUCCESS) { + if (keyfile && msReadEncryptionKeyFromFile(keyfile, map->encryption_key, + map->mappath) == MS_SUCCESS) { map->encryption_key_loaded = MS_TRUE; } else { - msSetError(MS_MISCERR, "Failed reading encryption key. Make sure " + msSetError(MS_MISCERR, + "Failed reading encryption key. Make sure " "MS_ENCRYPTION_KEY is set and points to a valid key file.", "msLoadEncryptionKey()"); return MS_FAILURE; @@ -293,8 +296,8 @@ static int msLoadEncryptionKey(mapObj *map) * **********************************************************************/ -void msEncryptStringWithKey(const unsigned char *key, const char *in, char *out) -{ +void msEncryptStringWithKey(const unsigned char *key, const char *in, + char *out) { ms_uint32 v[4], w[4]; const ms_uint32 *k; int last_block = MS_FALSE; @@ -302,9 +305,9 @@ void msEncryptStringWithKey(const unsigned char *key, const char *in, char *out) /* Casting the key this way is safe only as long as longs are 4 bytes * on this platform */ assert(sizeof(ms_uint32) == 4); - k = (const ms_uint32 *) key; + k = (const ms_uint32 *)key; - while(!last_block) { + while (!last_block) { int i, j; /* encipher() takes v[2] (64 bits) as input. * Copy bytes from in[] to the v[2] input array (pair of 4 bytes) @@ -312,14 +315,14 @@ void msEncryptStringWithKey(const unsigned char *key, const char *in, char *out) */ v[0] = 0; v[1] = 0; - for(i=0; !last_block && i<2; i++) { - for(j=0; j<4; j++) { + for (i = 0; !last_block && i < 2; i++) { + for (j = 0; j < 4; j++) { if (*in == '\0') { last_block = MS_TRUE; break; } - v[i] |= *in << (j*8); + v[i] |= *in << (j * 8); in++; } } @@ -333,9 +336,8 @@ void msEncryptStringWithKey(const unsigned char *key, const char *in, char *out) /* Append hex-encoded bytes to output, 4 bytes at a time */ msHexEncode((unsigned char *)w, out, 4); out += 8; - msHexEncode((unsigned char *)(w+1), out, 4); + msHexEncode((unsigned char *)(w + 1), out, 4); out += 8; - } /* Make sure output is 0-terminated */ @@ -351,8 +353,8 @@ void msEncryptStringWithKey(const unsigned char *key, const char *in, char *out) * **********************************************************************/ -void msDecryptStringWithKey(const unsigned char *key, const char *in, char *out) -{ +void msDecryptStringWithKey(const unsigned char *key, const char *in, + char *out) { ms_uint32 v[4], w[4]; const ms_uint32 *k; int last_block = MS_FALSE; @@ -360,9 +362,9 @@ void msDecryptStringWithKey(const unsigned char *key, const char *in, char *out) /* Casting the key this way is safe only as long as longs are 4 bytes * on this platform */ assert(sizeof(ms_uint32) == 4); - k = (const ms_uint32 *) key; + k = (const ms_uint32 *)key; - while(!last_block) { + while (!last_block) { int i; /* decipher() takes v[2] (64 bits) as input. * Copy bytes from in[] to the v[2] input array (pair of 4 bytes) @@ -375,7 +377,7 @@ void msDecryptStringWithKey(const unsigned char *key, const char *in, char *out) last_block = MS_TRUE; else { in += 8; - if (msHexDecode(in, (unsigned char *)(v+1), 8) != 4) + if (msHexDecode(in, (unsigned char *)(v + 1), 8) != 4) last_block = MS_TRUE; else in += 8; @@ -385,7 +387,7 @@ void msDecryptStringWithKey(const unsigned char *key, const char *in, char *out) decipher(v, w, k); /* Copy the results to out[] */ - for(i=0; i<2; i++) { + for (i = 0; i < 2; i++) { *out++ = (w[i] & 0x000000ff); *out++ = (w[i] & 0x0000ff00) >> 8; *out++ = (w[i] & 0x00ff0000) >> 16; @@ -404,13 +406,12 @@ void msDecryptStringWithKey(const unsigned char *key, const char *in, char *out) * msDecryptStringTokens() * * Returns a newly allocated string (to be msFree'd by the caller) in - * which all occurences of encrypted strings delimited by {...} have + * which all occurrences of encrypted strings delimited by {...} have * been decrypted. * **********************************************************************/ -char *msDecryptStringTokens(mapObj *map, const char *in) -{ +char *msDecryptStringTokens(mapObj *map, const char *in) { char *outbuf, *out; if (map == NULL) { @@ -420,13 +421,13 @@ char *msDecryptStringTokens(mapObj *map, const char *in) /* Start with a copy of the string. Decryption can only result in * a string with the same or shorter length */ - if ((outbuf = (char *)malloc((strlen(in)+1)*sizeof(char))) == NULL) { + if ((outbuf = (char *)malloc((strlen(in) + 1) * sizeof(char))) == NULL) { msSetError(MS_MEMERR, NULL, "msDecryptStringTokens()"); return NULL; } out = outbuf; - while(*in != '\0') { + while (*in != '\0') { if (*in == '{') { /* Possibly beginning of a token, look for closing bracket ** and make sure all chars in between are valid hex encoding chars @@ -434,12 +435,11 @@ char *msDecryptStringTokens(mapObj *map, const char *in) const char *pszStart, *pszEnd; int valid_token = MS_FALSE; - pszStart = in+1; - if ( (pszEnd = strchr(pszStart, '}')) != NULL && - pszEnd - pszStart > 1) { + pszStart = in + 1; + if ((pszEnd = strchr(pszStart, '}')) != NULL && pszEnd - pszStart > 1) { const char *pszTmp; valid_token = MS_TRUE; - for(pszTmp = pszStart; pszTmp < pszEnd; pszTmp++) { + for (pszTmp = pszStart; pszTmp < pszEnd; pszTmp++) { if (!isxdigit(*pszTmp)) { valid_token = MS_FALSE; break; @@ -459,13 +459,13 @@ char *msDecryptStringTokens(mapObj *map, const char *in) if (msLoadEncryptionKey(map) != MS_SUCCESS) return NULL; - pszTmp = (char*)malloc( (pszEnd-pszStart+1)*sizeof(char)); - strlcpy(pszTmp, pszStart, (pszEnd-pszStart)+1); + pszTmp = (char *)malloc((pszEnd - pszStart + 1) * sizeof(char)); + strlcpy(pszTmp, pszStart, (pszEnd - pszStart) + 1); msDecryptStringWithKey(map->encryption_key, pszTmp, out); out += strlen(out); - in = pszEnd+1; + in = pszEnd + 1; free(pszTmp); } else { /* Not a valid token, just copy the '{' and keep going */ @@ -481,7 +481,6 @@ char *msDecryptStringTokens(mapObj *map, const char *in) return outbuf; } - #ifdef TEST_MAPCRYPTO /* Test for mapcrypto.c functions. To run these tests, use the following @@ -492,10 +491,9 @@ test_mapcrypto: $(LIBMAP_STATIC) mapcrypto.c ** */ -int main(int argc, char *argv[]) -{ +int main(int argc, char *argv[]) { const unsigned char bytes_in[] = {0x12, 0x34, 0xff, 0x00, 0x44, 0x22}; - unsigned char bytes_out[8], encryption_key[MS_ENCRYPTION_KEY_SIZE*2+1]; + unsigned char bytes_out[8], encryption_key[MS_ENCRYPTION_KEY_SIZE * 2 + 1]; char string_buf[256], string_buf2[256]; int numbytes = 0; @@ -510,29 +508,30 @@ int main(int argc, char *argv[]) */ memset(bytes_out, 0, 8); numbytes = msHexDecode(string_buf, bytes_out, -1); - printf("msHexDecode(%s, -1) = %d, bytes_out = %x, %x, %x, %x, %x, %x, %x, %x\n", - string_buf, numbytes, - bytes_out[0], bytes_out[1], bytes_out[2], bytes_out[3], - bytes_out[4], bytes_out[5], bytes_out[6], bytes_out[7]); + printf( + "msHexDecode(%s, -1) = %d, bytes_out = %x, %x, %x, %x, %x, %x, %x, %x\n", + string_buf, numbytes, bytes_out[0], bytes_out[1], bytes_out[2], + bytes_out[3], bytes_out[4], bytes_out[5], bytes_out[6], bytes_out[7]); memset(bytes_out, 0, 8); numbytes = msHexDecode(string_buf, bytes_out, 4); - printf("msHexDecode(%s, 4) = %d, bytes_out = %x, %x, %x, %x, %x, %x, %x, %x\n", - string_buf, numbytes, - bytes_out[0], bytes_out[1], bytes_out[2], bytes_out[3], - bytes_out[4], bytes_out[5], bytes_out[6], bytes_out[7]); + printf( + "msHexDecode(%s, 4) = %d, bytes_out = %x, %x, %x, %x, %x, %x, %x, %x\n", + string_buf, numbytes, bytes_out[0], bytes_out[1], bytes_out[2], + bytes_out[3], bytes_out[4], bytes_out[5], bytes_out[6], bytes_out[7]); memset(bytes_out, 0, 8); numbytes = msHexDecode(string_buf, bytes_out, 20); - printf("msHexDecode(%s, 20) = %d, bytes_out = %x, %x, %x, %x, %x, %x, %x, %x\n", - string_buf, numbytes, - bytes_out[0], bytes_out[1], bytes_out[2], bytes_out[3], - bytes_out[4], bytes_out[5], bytes_out[6], bytes_out[7]); + printf( + "msHexDecode(%s, 20) = %d, bytes_out = %x, %x, %x, %x, %x, %x, %x, %x\n", + string_buf, numbytes, bytes_out[0], bytes_out[1], bytes_out[2], + bytes_out[3], bytes_out[4], bytes_out[5], bytes_out[6], bytes_out[7]); /* ** Test loading encryption key */ - if (msReadEncryptionKeyFromFile("/tmp/test.key", encryption_key) != MS_SUCCESS) { + if (msReadEncryptionKeyFromFile("/tmp/test.key", encryption_key, NULL) != + MS_SUCCESS) { printf("msReadEncryptionKeyFromFile() = MS_FAILURE\n"); printf("Aborting tests!\n"); msWriteError(stderr); @@ -551,21 +550,24 @@ int main(int argc, char *argv[]) printf("msEncryptStringWithKey('test1234') returned '%s'\n", string_buf); msDecryptStringWithKey(encryption_key, string_buf, string_buf2); - printf("msDecryptStringWithKey('%s') returned '%s'\n", string_buf, string_buf2); + printf("msDecryptStringWithKey('%s') returned '%s'\n", string_buf, + string_buf2); /* Next with an 1 byte input string */ msEncryptStringWithKey(encryption_key, "t", string_buf); printf("msEncryptStringWithKey('t') returned '%s'\n", string_buf); msDecryptStringWithKey(encryption_key, string_buf, string_buf2); - printf("msDecryptStringWithKey('%s') returned '%s'\n", string_buf, string_buf2); + printf("msDecryptStringWithKey('%s') returned '%s'\n", string_buf, + string_buf2); /* Next with an 12 bytes input string */ msEncryptStringWithKey(encryption_key, "test123456", string_buf); printf("msEncryptStringWithKey('test123456') returned '%s'\n", string_buf); msDecryptStringWithKey(encryption_key, string_buf, string_buf2); - printf("msDecryptStringWithKey('%s') returned '%s'\n", string_buf, string_buf2); + printf("msDecryptStringWithKey('%s') returned '%s'\n", string_buf, + string_buf2); /* ** Test decryption with tokens @@ -585,8 +587,8 @@ int main(int argc, char *argv[]) msWriteError(stderr); return -1; } else { - printf("msDecryptStringTokens('%s') returned '%s'\n", - string_buf2, pszBuf); + printf("msDecryptStringTokens('%s') returned '%s'\n", string_buf2, + pszBuf); } msFree(pszBuf); msFreeMap(map); @@ -595,5 +597,4 @@ int main(int argc, char *argv[]) return 0; } - #endif /* TEST_MAPCRYPTO */ diff --git a/mapdebug.c b/src/mapdebug.c similarity index 76% rename from mapdebug.c rename to src/mapdebug.c index 2043a99502..407c1de3df 100644 --- a/mapdebug.c +++ b/src/mapdebug.c @@ -27,12 +27,13 @@ * DEALINGS IN THE SOFTWARE. ****************************************************************************/ - #include "mapserver.h" #include "maperror.h" #include "mapthread.h" #include "maptime.h" +#include "cpl_conv.h" + #include #ifndef _WIN32 #include @@ -48,16 +49,11 @@ #include /* OutputDebugStringA() */ #endif - - - #ifndef USE_THREAD -debugInfoObj *msGetDebugInfoObj() -{ - static debugInfoObj debuginfo = {MS_DEBUGLEVEL_ERRORSONLY, - MS_DEBUGMODE_OFF, NULL, NULL - }; +debugInfoObj *msGetDebugInfoObj() { + static debugInfoObj debuginfo = { + MS_DEBUGLEVEL_ERRORSONLY, MS_DEBUGMODE_OFF, NULL, NULL, 0, NULL}; return &debuginfo; } @@ -65,32 +61,32 @@ debugInfoObj *msGetDebugInfoObj() static debugInfoObj *debuginfo_list = NULL; -debugInfoObj *msGetDebugInfoObj() -{ +debugInfoObj *msGetDebugInfoObj() { debugInfoObj *link; - void* thread_id; + void *thread_id; debugInfoObj *ret_obj; - msAcquireLock( TLOCK_DEBUGOBJ ); + msAcquireLock(TLOCK_DEBUGOBJ); thread_id = msGetThreadId(); /* find link for this thread */ - for( link = debuginfo_list; - link != NULL && link->thread_id != thread_id - && link->next != NULL && link->next->thread_id != thread_id; - link = link->next ) {} + for (link = debuginfo_list; + link != NULL && link->thread_id != thread_id && link->next != NULL && + link->next->thread_id != thread_id; + link = link->next) { + } /* If the target thread link is already at the head of the list were ok */ - if( debuginfo_list != NULL && debuginfo_list->thread_id == thread_id ) { + if (debuginfo_list != NULL && debuginfo_list->thread_id == thread_id) { } /* We don't have one ... initialize one. */ - else if( link == NULL || link->next == NULL ) { + else if (link == NULL || link->next == NULL) { debugInfoObj *new_link; - new_link = (debugInfoObj *) msSmallMalloc(sizeof(debugInfoObj)); + new_link = (debugInfoObj *)msSmallMalloc(sizeof(debugInfoObj)); new_link->next = debuginfo_list; new_link->thread_id = thread_id; new_link->global_debug_level = MS_DEBUGLEVEL_ERRORSONLY; @@ -101,7 +97,7 @@ debugInfoObj *msGetDebugInfoObj() } /* If the link is not already at the head of the list, promote it */ - else if( link != NULL && link->next != NULL ) { + else { debugInfoObj *target = link->next; link->next = link->next->next; @@ -111,13 +107,12 @@ debugInfoObj *msGetDebugInfoObj() ret_obj = debuginfo_list; - msReleaseLock( TLOCK_DEBUGOBJ ); + msReleaseLock(TLOCK_DEBUGOBJ); return ret_obj; } #endif - /* msSetErrorFile() ** ** Set output target, ready to write to it, open file if necessary @@ -128,8 +123,7 @@ debugInfoObj *msGetDebugInfoObj() ** ** Returns MS_SUCCESS/MS_FAILURE */ -int msSetErrorFile(const char *pszErrorFile, const char *pszRelToPath) -{ +int msSetErrorFile(const char *pszErrorFile, const char *pszRelToPath) { char extended_path[MS_MAXPATHLEN]; debugInfoObj *debuginfo = msGetDebugInfoObj(); @@ -137,7 +131,7 @@ int msSetErrorFile(const char *pszErrorFile, const char *pszRelToPath) strcmp(pszErrorFile, "stdout") != 0 && strcmp(pszErrorFile, "windowsdebug") != 0) { /* Try to make the path relative */ - if(msBuildPath(extended_path, pszRelToPath, pszErrorFile) == NULL) + if (msBuildPath(extended_path, pszRelToPath, pszErrorFile) == NULL) return MS_FAILURE; pszErrorFile = extended_path; } @@ -169,13 +163,17 @@ int msSetErrorFile(const char *pszErrorFile, const char *pszRelToPath) debuginfo->fp = NULL; debuginfo->debug_mode = MS_DEBUGMODE_WINDOWSDEBUG; #else - msSetError(MS_MISCERR, "'MS_ERRORFILE windowsdebug' is available only on Windows platforms.", "msSetErrorFile()"); + msSetError( + MS_MISCERR, + "'MS_ERRORFILE windowsdebug' is available only on Windows platforms.", + "msSetErrorFile()"); return MS_FAILURE; #endif } else { debuginfo->fp = fopen(pszErrorFile, "a"); if (debuginfo->fp == NULL) { - msSetError(MS_MISCERR, "Failed to open MS_ERRORFILE %s", "msSetErrorFile()", pszErrorFile); + msSetError(MS_MISCERR, "Failed to open MS_ERRORFILE %s", + "msSetErrorFile()", pszErrorFile); return MS_FAILURE; } debuginfo->errorfile = msStrdup(pszErrorFile); @@ -189,8 +187,7 @@ int msSetErrorFile(const char *pszErrorFile, const char *pszRelToPath) ** ** Close current output file (if one is open) and reset related members */ -void msCloseErrorFile() -{ +void msCloseErrorFile() { debugInfoObj *debuginfo = msGetDebugInfoObj(); if (debuginfo && debuginfo->debug_mode != MS_DEBUGMODE_OFF) { @@ -210,16 +207,13 @@ void msCloseErrorFile() } } - - /* msGetErrorFile() ** ** Returns name of current error file ** ** Returns NULL if not set. */ -const char *msGetErrorFile() -{ +const char *msGetErrorFile() { debugInfoObj *debuginfo = msGetDebugInfoObj(); if (debuginfo) @@ -233,16 +227,14 @@ const char *msGetErrorFile() ** the context of mapObj or layerObj. ** */ -void msSetGlobalDebugLevel(int level) -{ +void msSetGlobalDebugLevel(int level) { debugInfoObj *debuginfo = msGetDebugInfoObj(); if (debuginfo) debuginfo->global_debug_level = (debugLevel)level; } -debugLevel msGetGlobalDebugLevel() -{ +debugLevel msGetGlobalDebugLevel() { debugInfoObj *debuginfo = msGetDebugInfoObj(); if (debuginfo) @@ -251,67 +243,63 @@ debugLevel msGetGlobalDebugLevel() return MS_DEBUGLEVEL_ERRORSONLY; } - /* msDebugInitFromEnv() ** ** Init debug state from MS_ERRORFILE and MS_DEBUGLEVEL env vars if set ** ** Returns MS_SUCCESS/MS_FAILURE */ -int msDebugInitFromEnv() -{ +int msDebugInitFromEnv() { const char *val; - if( (val=getenv( "MS_ERRORFILE" )) != NULL ) { - if ( msSetErrorFile(val, NULL) != MS_SUCCESS ) + if ((val = CPLGetConfigOption("MS_ERRORFILE", NULL)) != NULL) { + if (msSetErrorFile(val, NULL) != MS_SUCCESS) return MS_FAILURE; } - if( (val=getenv( "MS_DEBUGLEVEL" )) != NULL ) + if ((val = CPLGetConfigOption("MS_DEBUGLEVEL", NULL)) != NULL) msSetGlobalDebugLevel(atoi(val)); return MS_SUCCESS; } - /* msDebugCleanup() ** ** Called by msCleanup to remove info related to this thread. */ -void msDebugCleanup() -{ +void msDebugCleanup() { /* make sure file is closed */ msCloseErrorFile(); #ifdef USE_THREAD { - void* thread_id = msGetThreadId(); + void *thread_id = msGetThreadId(); debugInfoObj *link; - msAcquireLock( TLOCK_DEBUGOBJ ); + msAcquireLock(TLOCK_DEBUGOBJ); /* find link for this thread */ - for( link = debuginfo_list; - link != NULL && link->thread_id != thread_id - && link->next != NULL && link->next->thread_id != thread_id; - link = link->next ) {} + for (link = debuginfo_list; + link != NULL && link->thread_id != thread_id && link->next != NULL && + link->next->thread_id != thread_id; + link = link->next) { + } - if( link->thread_id == thread_id ) { + if (link->thread_id == thread_id) { /* presumably link is at head of list. */ - if( debuginfo_list == link ) + if (debuginfo_list == link) debuginfo_list = link->next; - free( link ); - } else if( link->next != NULL && link->next->thread_id == thread_id ) { + free(link); + } else if (link->next != NULL && link->next->thread_id == thread_id) { debugInfoObj *next_link = link->next; link->next = link->next->next; - free( next_link ); + free(next_link); } - msReleaseLock( TLOCK_DEBUGOBJ ); + msReleaseLock(TLOCK_DEBUGOBJ); } #endif - } /* msDebug() @@ -320,13 +308,20 @@ void msDebugCleanup() ** (see msSetErrorFile()) ** */ -void msDebug( const char * pszFormat, ... ) -{ +void msDebug(const char *pszFormat, ...) { va_list args; debugInfoObj *debuginfo = msGetDebugInfoObj(); + char szMessage[MESSAGELENGTH]; if (debuginfo == NULL || debuginfo->debug_mode == MS_DEBUGMODE_OFF) - return; /* Don't waste time here! */ + return; /* Don't waste time here! */ + + va_start(args, pszFormat); + vsnprintf(szMessage, MESSAGELENGTH, pszFormat, args); + va_end(args); + szMessage[MESSAGELENGTH - 1] = '\0'; + + msRedactCredentials(szMessage); if (debuginfo->fp) { /* Writing to a stdio file handle */ @@ -341,37 +336,23 @@ void msDebug( const char * pszFormat, ... ) time_t t; msGettimeofday(&tv, NULL); t = tv.tv_sec; - msIO_fprintf(debuginfo->fp, "[%s].%ld ", - msStringChop(ctime(&t)), (long)tv.tv_usec); + msIO_fprintf(debuginfo->fp, "[%s].%ld ", msStringChop(ctime(&t)), + (long)tv.tv_usec); } - va_start(args, pszFormat); - msIO_vfprintf(debuginfo->fp, pszFormat, args); - va_end(args); + msIO_fprintf(debuginfo->fp, "%s", szMessage); } #ifdef _WIN32 else if (debuginfo->debug_mode == MS_DEBUGMODE_WINDOWSDEBUG) { /* Writing to Windows Debug Console */ - - char szMessage[MESSAGELENGTH]; - - va_start(args, pszFormat); - vsnprintf( szMessage, MESSAGELENGTH, pszFormat, args ); - va_end(args); - - szMessage[MESSAGELENGTH-1] = '\0'; OutputDebugStringA(szMessage); } #endif - } - /* msDebug2() ** ** Variadic function with no operation ** */ -void msDebug2( int level, ... ) -{ -} +void msDebug2(int level, ...) { (void)level; } diff --git a/src/mapdraw.c b/src/mapdraw.c new file mode 100644 index 0000000000..ec1083f3e6 --- /dev/null +++ b/src/mapdraw.c @@ -0,0 +1,4352 @@ +/****************************************************************************** + * $Id$ + * + * Project: MapServer + * Purpose: High level msDrawMap() implementation and related functions. + * Author: Steve Lime and the MapServer team. + * + ****************************************************************************** + * Copyright (c) 1996-2005 Regents of the University of Minnesota. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + *****************************************************************************/ + +#include +#include +#include "mapserver.h" +#include "maptime.h" +#include "mapcopy.h" +#include "mapfile.h" +#include "mapows.h" +#include "cpl_port.h" + +/* msGetGeoCellSize + * + * A helper function to get the first parameter for msUpdateClassScaleFactor() + */ +double msGetGeoCellSize(const mapObj *map) { + double geo_cellsize; + + /* We will need a cellsize that represents a real georeferenced */ + /* coordinate cellsize here, so compute it from saved extents. */ + + geo_cellsize = map->cellsize; + if (map->gt.need_geotransform == MS_TRUE) { + double cellsize_x = + (map->saved_extent.maxx - map->saved_extent.minx) / map->width; + double cellsize_y = + (map->saved_extent.maxy - map->saved_extent.miny) / map->height; + + geo_cellsize = + sqrt(cellsize_x * cellsize_x + cellsize_y * cellsize_y) / sqrt(2.0); + } + return geo_cellsize; +} + +/* msUpdateClassScaleFactor + * + * Provides correct scale factor inheritance for Class and all of its + * styles and labels. + */ +void msUpdateClassScaleFactor(double geo_cellsize, const mapObj *map, + const layerObj *layer, classObj *c) { + if (c->sizeunits == MS_INHERIT) + c->scalefactor = layer->scalefactor; + else if (c->sizeunits != MS_PIXELS) + c->scalefactor = + (msInchesPerUnit(c->sizeunits, 0) / msInchesPerUnit(map->units, 0)) / + geo_cellsize; + else if (layer->symbolscaledenom > 0 && map->scaledenom > 0) + c->scalefactor = layer->symbolscaledenom / map->scaledenom * + map->resolution / map->defresolution; + else + c->scalefactor = map->resolution / map->defresolution; + for (int sid = 0; sid < c->numstyles; sid++) { + styleObj *style = c->styles[sid]; + if (style->sizeunits == MS_INHERIT) + style->scalefactor = c->scalefactor; + else if (style->sizeunits != MS_PIXELS) + style->scalefactor = (msInchesPerUnit(style->sizeunits, 0) / + msInchesPerUnit(map->units, 0)) / + geo_cellsize; + else if (layer->symbolscaledenom > 0 && map->scaledenom > 0) + style->scalefactor = layer->symbolscaledenom / map->scaledenom * + map->resolution / map->defresolution; + else + style->scalefactor = map->resolution / map->defresolution; + } + for (int sid = 0; sid < c->numlabels; sid++) { + labelObj *label = c->labels[sid]; + if (label->sizeunits == MS_INHERIT) + label->scalefactor = c->scalefactor; + else if (label->sizeunits != MS_PIXELS) + label->scalefactor = (msInchesPerUnit(label->sizeunits, 0) / + msInchesPerUnit(map->units, 0)) / + geo_cellsize; + else if (layer->symbolscaledenom > 0 && map->scaledenom > 0) + label->scalefactor = layer->symbolscaledenom / map->scaledenom * + map->resolution / map->defresolution; + else + label->scalefactor = map->resolution / map->defresolution; + for (int lsid = 0; lsid < label->numstyles; lsid++) { + styleObj *lstyle = label->styles[lsid]; + if (lstyle->sizeunits == MS_INHERIT) + lstyle->scalefactor = label->scalefactor; + else if (lstyle->sizeunits != MS_PIXELS) + lstyle->scalefactor = (msInchesPerUnit(lstyle->sizeunits, 0) / + msInchesPerUnit(map->units, 0)) / + geo_cellsize; + else if (layer->symbolscaledenom > 0 && map->scaledenom > 0) + lstyle->scalefactor = layer->symbolscaledenom / map->scaledenom * + map->resolution / map->defresolution; + else + lstyle->scalefactor = map->resolution / map->defresolution; + } + } +} + +/* msPrepareImage() + * + * Returns a new imageObj ready for rendering the current map. + * + * If allow_nonsquare is set to MS_TRUE then the caller should call + * msMapRestoreRealExtent() once they are done with the image. + * This should be set to MS_TRUE only when called from msDrawMap(), see bug 945. + */ +imageObj *msPrepareImage(mapObj *map, int allow_nonsquare) { + int i, status; + imageObj *image = NULL; + double geo_cellsize; + + if (map->width == -1 || map->height == -1) { + msSetError(MS_MISCERR, "Image dimensions not specified.", + "msPrepareImage()"); + return (NULL); + } + + msFreeLabelCache(&(map->labelcache)); + msInitLabelCache( + &(map->labelcache)); /* this clears any previously allocated cache */ + + /* clear any previously created mask layer images */ + for (i = 0; i < map->numlayers; i++) { + if (GET_LAYER(map, i)->maskimage) { + msFreeImage(GET_LAYER(map, i)->maskimage); + GET_LAYER(map, i)->maskimage = NULL; + } + } + + status = msValidateContexts(map); /* make sure there are no recursive REQUIRES + or LABELREQUIRES expressions */ + if (status != MS_SUCCESS) + return NULL; + + if (!map->outputformat) { + msSetError(MS_IMGERR, "Map outputformat not set!", "msPrepareImage()"); + return (NULL); + } else if (MS_RENDERER_PLUGIN(map->outputformat)) { + rendererVTableObj *renderer = map->outputformat->vtable; + colorObj *bg = &map->imagecolor; + map->imagecolor.alpha = 255; + + image = + renderer->createImage(map->width, map->height, map->outputformat, bg); + if (image == NULL) + return (NULL); + image->format = map->outputformat; + image->format->refcount++; + image->width = map->width; + image->height = map->height; + + image->resolution = map->resolution; + image->resolutionfactor = map->resolution / map->defresolution; + if (map->web.imagepath) + image->imagepath = msStrdup(map->web.imagepath); + if (map->web.imageurl) + image->imageurl = msStrdup(map->web.imageurl); + + } else if (MS_RENDERER_IMAGEMAP(map->outputformat)) { + image = msImageCreateIM(map->width, map->height, map->outputformat, + map->web.imagepath, map->web.imageurl, + map->resolution, map->defresolution); + } else if (MS_RENDERER_RAWDATA(map->outputformat)) { + image = + msImageCreate(map->width, map->height, map->outputformat, + map->web.imagepath, map->web.imageurl, map->resolution, + map->defresolution, &map->imagecolor); + } else { + image = NULL; + } + + if (!image) { + msSetError(MS_IMGERR, "Unable to initialize image.", "msPrepareImage()"); + return (NULL); + } + + image->map = map; + + /* + * If we want to support nonsquare pixels, note that now, otherwise + * adjust the extent size to have square pixels. + * + * If allow_nonsquare is set to MS_TRUE then the caller should call + * msMapRestoreRealExtent() once they are done with the image. + * This should be set to MS_TRUE only when called from msDrawMap(), see bug + * 945. + */ + if (allow_nonsquare && msTestConfigOption(map, "MS_NONSQUARE", MS_FALSE)) { + double cellsize_x = (map->extent.maxx - map->extent.minx) / map->width; + double cellsize_y = (map->extent.maxy - map->extent.miny) / map->height; + + if (cellsize_y != 0.0 && (fabs(cellsize_x / cellsize_y) > 1.00001 || + fabs(cellsize_x / cellsize_y) < 0.99999)) { + map->gt.need_geotransform = MS_TRUE; + if (map->debug) + msDebug( + "msDrawMap(): kicking into non-square pixel preserving mode.\n"); + } + map->cellsize = (cellsize_x * 0.5 + cellsize_y * 0.5); + } else + map->cellsize = msAdjustExtent(&(map->extent), map->width, map->height); + + status = msCalculateScale(map->extent, map->units, map->width, map->height, + map->resolution, &map->scaledenom); + if (status != MS_SUCCESS) { + msFreeImage(image); + return (NULL); + } + + /* update geotransform based on adjusted extent. */ + msMapComputeGeotransform(map); + + /* Do we need to fake out stuff for rotated support? */ + if (map->gt.need_geotransform) + msMapSetFakedExtent(map); + + geo_cellsize = msGetGeoCellSize(map); + + /* compute layer/class/style/label scale factors now */ + for (int lid = 0; lid < map->numlayers; lid++) { + layerObj *layer = GET_LAYER(map, lid); + if (layer->sizeunits != MS_PIXELS) + layer->scalefactor = (msInchesPerUnit(layer->sizeunits, 0) / + msInchesPerUnit(map->units, 0)) / + geo_cellsize; + else if (layer->symbolscaledenom > 0 && map->scaledenom > 0) + layer->scalefactor = layer->symbolscaledenom / map->scaledenom * + map->resolution / map->defresolution; + else + layer->scalefactor = map->resolution / map->defresolution; + for (int cid = 0; cid < layer->numclasses; cid++) { + classObj *class = GET_CLASS(map, lid, cid); + msUpdateClassScaleFactor(geo_cellsize, map, layer, class); + } + } + + image->refpt.x = + MS_MAP2IMAGE_X_IC_DBL(0, map->extent.minx, 1.0 / map->cellsize); + image->refpt.y = + MS_MAP2IMAGE_Y_IC_DBL(0, map->extent.maxy, 1.0 / map->cellsize); + + return image; +} + +static int msCompositeRasterBuffer(mapObj *map, imageObj *img, + rasterBufferObj *rb, LayerCompositer *comp) { + int ret = MS_SUCCESS; + if (MS_IMAGE_RENDERER(img)->compositeRasterBuffer) { + while (comp && ret == MS_SUCCESS) { + rasterBufferObj *rb_ptr = rb; + CompositingFilter *filter = comp->filter; + if (filter && comp->next) { + /* if we have another compositor to apply, then we need to copy the + * rasterBufferObj. Otherwise we can work on it directly */ + rb_ptr = (rasterBufferObj *)msSmallCalloc(sizeof(rasterBufferObj), 1); + msCopyRasterBuffer(rb_ptr, rb); + } + while (filter && ret == MS_SUCCESS) { + ret = msApplyCompositingFilter(map, rb_ptr, filter); + filter = filter->next; + } + if (ret == MS_SUCCESS) + ret = MS_IMAGE_RENDERER(img)->compositeRasterBuffer( + img, rb_ptr, comp->comp_op, comp->opacity); + if (rb_ptr != rb) { + msFreeRasterBuffer(rb_ptr); + msFree(rb_ptr); + } + comp = comp->next; + } + } else { + ret = MS_FAILURE; + } + return ret; +} + +/* + * Generic function to render the map file. + * The type of the image created is based on the imagetype parameter in the map + * file. + * + * mapObj *map - map object loaded in MapScript or via a mapfile to use + * int querymap - is this map the result of a query operation, MS_TRUE|MS_FALSE + */ +imageObj *msDrawMap(mapObj *map, int querymap) { + int i; + layerObj *lp = NULL; + int status = MS_FAILURE; + imageObj *image = NULL; + struct mstimeval mapstarttime = {0}, mapendtime = {0}; + struct mstimeval starttime = {0}, endtime = {0}; + +#if defined(USE_WMS_LYR) || defined(USE_WFS_LYR) + enum MS_CONNECTION_TYPE lastconnectiontype; + httpRequestObj *pasOWSReqInfo = NULL; + int numOWSLayers = 0; + int numOWSRequests = 0; + wmsParamsObj sLastWMSParams; +#endif + + if (map->debug >= MS_DEBUGLEVEL_TUNING) + msGettimeofday(&mapstarttime, NULL); + + if (querymap) { /* use queryMapObj image dimensions */ + if (map->querymap.width > 0 && map->querymap.width <= map->maxsize) + map->width = map->querymap.width; + if (map->querymap.height > 0 && map->querymap.height <= map->maxsize) + map->height = map->querymap.height; + } + + msApplyMapConfigOptions(map); + image = msPrepareImage(map, MS_TRUE); + + if (!image) { + msSetError(MS_IMGERR, "Unable to initialize image.", "msDrawMap()"); + return (NULL); + } + + if (map->debug >= MS_DEBUGLEVEL_DEBUG) + msDebug("msDrawMap(): rendering using outputformat named %s (%s).\n", + map->outputformat->name, map->outputformat->driver); + +#if defined(USE_WMS_LYR) || defined(USE_WFS_LYR) + + /* Time the OWS query phase */ + if (map->debug >= MS_DEBUGLEVEL_TUNING) + msGettimeofday(&starttime, NULL); + + /* How many OWS (WMS/WFS) layers do we have to draw? + * Note: numOWSLayers is the number of actual layers and numOWSRequests is + * the number of HTTP requests which could be lower if multiple layers + * are merged into the same request. + */ + numOWSLayers = 0; + for (i = 0; i < map->numlayers; i++) { + if (map->layerorder[i] == -1) + continue; + + lp = GET_LAYER(map, map->layerorder[i]); + if (lp->connectiontype != MS_WMS && lp->connectiontype != MS_WFS) { + continue; + } + numOWSLayers++; + } + + if (numOWSLayers > 0) { + + /* Alloc and init pasOWSReqInfo... + */ + pasOWSReqInfo = + (httpRequestObj *)malloc(numOWSLayers * sizeof(httpRequestObj)); + if (pasOWSReqInfo == NULL) { + msSetError(MS_MEMERR, "Allocation of httpRequestObj failed.", + "msDrawMap()"); + return NULL; + } + msHTTPInitRequestObj(pasOWSReqInfo, numOWSLayers); + msInitWmsParamsObj(&sLastWMSParams); + + /* Pre-download all WMS/WFS layers in parallel before starting to draw map + */ + lastconnectiontype = MS_SHAPEFILE; + for (i = 0; i < map->numlayers; i++) { + if (map->layerorder[i] == -1) + continue; + + lp = GET_LAYER(map, map->layerorder[i]); + if (lp->connectiontype != MS_WMS && lp->connectiontype != MS_WFS) { + continue; + } + + if (!msLayerIsVisible(map, lp)) + continue; + +#ifdef USE_WMS_LYR + if (lp->connectiontype == MS_WMS) { + if (msPrepareWMSLayerRequest(map->layerorder[i], map, lp, 1, + lastconnectiontype, &sLastWMSParams, 0, 0, + 0, NULL, pasOWSReqInfo, + &numOWSRequests) == MS_FAILURE) { + msFreeWmsParamsObj(&sLastWMSParams); + msFreeImage(image); + msFree(pasOWSReqInfo); + return NULL; + } + } +#endif + +#ifdef USE_WFS_LYR + if (lp->connectiontype == MS_WFS) { + if (msPrepareWFSLayerRequest(map->layerorder[i], map, lp, pasOWSReqInfo, + &numOWSRequests) == MS_FAILURE) { + msFreeWmsParamsObj(&sLastWMSParams); + msFreeImage(image); + msFree(pasOWSReqInfo); + return NULL; + } + } +#endif + + lastconnectiontype = lp->connectiontype; + } + + msFreeWmsParamsObj(&sLastWMSParams); + } /* if numOWSLayers > 0 */ + + if (numOWSRequests && msOWSExecuteRequests(pasOWSReqInfo, numOWSRequests, map, + MS_TRUE) == MS_FAILURE) { + msFreeImage(image); + msFree(pasOWSReqInfo); + return NULL; + } + + if (map->debug >= MS_DEBUGLEVEL_TUNING) { + msGettimeofday(&endtime, NULL); + msDebug("msDrawMap(): WMS/WFS set-up and query, %.3fs\n", + (endtime.tv_sec + endtime.tv_usec / 1.0e6) - + (starttime.tv_sec + starttime.tv_usec / 1.0e6)); + } + +#endif /* USE_WMS_LYR || USE_WFS_LYR */ + + /* OK, now we can start drawing */ + for (i = 0; i < map->numlayers; i++) { + + if (map->layerorder[i] != -1) { + const char *force_draw_label_cache = NULL; + + lp = (GET_LAYER(map, map->layerorder[i])); + + if (lp->postlabelcache) /* wait to draw */ + continue; + + if (map->debug >= MS_DEBUGLEVEL_TUNING || + lp->debug >= MS_DEBUGLEVEL_TUNING) + msGettimeofday(&starttime, NULL); + + if (!msLayerIsVisible(map, lp)) + continue; + + if (lp->connectiontype == MS_WMS) { +#ifdef USE_WMS_LYR + if (MS_RENDERER_PLUGIN(image->format) || + MS_RENDERER_RAWDATA(image->format)) { + assert(pasOWSReqInfo); + status = msDrawWMSLayerLow(map->layerorder[i], pasOWSReqInfo, + numOWSRequests, map, lp, image); + } else { + msSetError(MS_WMSCONNERR, + "Output format '%s' doesn't support WMS layers.", + "msDrawMap()", image->format->name); + status = MS_FAILURE; + } + + if (status == MS_FAILURE) { + msSetError(MS_WMSCONNERR, + "Failed to draw WMS layer named '%s'. This most likely " + "happened because " + "the remote WMS server returned an invalid image, and XML " + "exception " + "or another unexpected result in response to the GetMap " + "request. Also check " + "and make sure that the layer's connection URL is valid.", + "msDrawMap()", lp->name); + msFreeImage(image); + msHTTPFreeRequestObj(pasOWSReqInfo, numOWSRequests); + msFree(pasOWSReqInfo); + return (NULL); + } + +#else /* ndef USE_WMS_LYR */ + msSetError(MS_WMSCONNERR, + "MapServer not built with WMS Client support, unable to " + "render layer '%s'.", + "msDrawMap()", lp->name); + msFreeImage(image); + return (NULL); +#endif + } else { /* Default case: anything but WMS layers */ + if (querymap) + status = msDrawQueryLayer(map, lp, image); + else + status = msDrawLayer(map, lp, image); + if (status == MS_FAILURE) { + msSetError(MS_IMGERR, "Failed to draw layer named '%s'.", + "msDrawMap()", lp->name); + msFreeImage(image); +#if defined(USE_WMS_LYR) || defined(USE_WFS_LYR) + if (pasOWSReqInfo) { + msHTTPFreeRequestObj(pasOWSReqInfo, numOWSRequests); + msFree(pasOWSReqInfo); + } +#endif /* USE_WMS_LYR || USE_WFS_LYR */ + return (NULL); + } + } + if (map->debug >= MS_DEBUGLEVEL_TUNING || + lp->debug >= MS_DEBUGLEVEL_TUNING) { + msGettimeofday(&endtime, NULL); + msDebug("msDrawMap(): Layer %d (%s), %.3fs\n", map->layerorder[i], + lp->name ? lp->name : "(null)", + (endtime.tv_sec + endtime.tv_usec / 1.0e6) - + (starttime.tv_sec + starttime.tv_usec / 1.0e6)); + } + + /* Flush layer cache in-between layers if requested by PROCESSING + * directive*/ + force_draw_label_cache = + msLayerGetProcessingKey(lp, "FORCE_DRAW_LABEL_CACHE"); + if (force_draw_label_cache && + strncasecmp(force_draw_label_cache, "FLUSH", 5) == 0) { + if (map->debug >= MS_DEBUGLEVEL_V) + msDebug( + "msDrawMap(): PROCESSING FORCE_DRAW_LABEL_CACHE=FLUSH found.\n"); + if (msDrawLabelCache(map, image) != MS_SUCCESS) { + msFreeImage(image); +#if defined(USE_WMS_LYR) || defined(USE_WFS_LYR) + if (pasOWSReqInfo) { + msHTTPFreeRequestObj(pasOWSReqInfo, numOWSRequests); + msFree(pasOWSReqInfo); + } +#endif /* USE_WMS_LYR || USE_WFS_LYR */ + return (NULL); + } + msFreeLabelCache(&(map->labelcache)); + msInitLabelCache(&(map->labelcache)); + } /* PROCESSING FORCE_DRAW_LABEL_CACHE */ + } + } + + if (map->scalebar.status == MS_EMBED && !map->scalebar.postlabelcache) { + + /* We need to temporarily restore the original extent for drawing */ + /* the scalebar as it uses the extent to recompute cellsize. */ + if (map->gt.need_geotransform) + msMapRestoreRealExtent(map); + + if (MS_SUCCESS != msEmbedScalebar(map, image)) { + msFreeImage(image); +#if defined(USE_WMS_LYR) || defined(USE_WFS_LYR) + /* Cleanup WMS/WFS Request stuff */ + if (pasOWSReqInfo) { + msHTTPFreeRequestObj(pasOWSReqInfo, numOWSRequests); + msFree(pasOWSReqInfo); + } +#endif + return NULL; + } + + if (map->gt.need_geotransform) + msMapSetFakedExtent(map); + } + + if (map->legend.status == MS_EMBED && !map->legend.postlabelcache) { + if (msEmbedLegend(map, image) != MS_SUCCESS) { + msFreeImage(image); +#if defined(USE_WMS_LYR) || defined(USE_WFS_LYR) + /* Cleanup WMS/WFS Request stuff */ + if (pasOWSReqInfo) { + msHTTPFreeRequestObj(pasOWSReqInfo, numOWSRequests); + msFree(pasOWSReqInfo); + } +#endif + return NULL; + } + } + + if (msDrawLabelCache(map, image) != MS_SUCCESS) { + msFreeImage(image); +#if defined(USE_WMS_LYR) || defined(USE_WFS_LYR) + if (pasOWSReqInfo) { + msHTTPFreeRequestObj(pasOWSReqInfo, numOWSRequests); + msFree(pasOWSReqInfo); + } +#endif /* USE_WMS_LYR || USE_WFS_LYR */ + return (NULL); + } + + for (i = 0; i < map->numlayers; + i++) { /* for each layer, check for postlabelcache layers */ + + lp = (GET_LAYER(map, map->layerorder[i])); + + if (!lp->postlabelcache) + continue; + if (!msLayerIsVisible(map, lp)) + continue; + + if (map->debug >= MS_DEBUGLEVEL_TUNING || lp->debug >= MS_DEBUGLEVEL_TUNING) + msGettimeofday(&starttime, NULL); + + if (lp->connectiontype == MS_WMS) { +#ifdef USE_WMS_LYR + if (MS_RENDERER_PLUGIN(image->format) || + MS_RENDERER_RAWDATA(image->format)) { + assert(pasOWSReqInfo); + status = msDrawWMSLayerLow(map->layerorder[i], pasOWSReqInfo, + numOWSRequests, map, lp, image); + } + +#else + status = MS_FAILURE; +#endif + } else { + if (querymap) + status = msDrawQueryLayer(map, lp, image); + else + status = msDrawLayer(map, lp, image); + } + + if (status == MS_FAILURE) { + msFreeImage(image); +#if defined(USE_WMS_LYR) || defined(USE_WFS_LYR) + if (pasOWSReqInfo) { + msHTTPFreeRequestObj(pasOWSReqInfo, numOWSRequests); + msFree(pasOWSReqInfo); + } +#endif /* USE_WMS_LYR || USE_WFS_LYR */ + return (NULL); + } + + if (map->debug >= MS_DEBUGLEVEL_TUNING || + lp->debug >= MS_DEBUGLEVEL_TUNING) { + msGettimeofday(&endtime, NULL); + msDebug("msDrawMap(): Layer %d (%s), %.3fs\n", map->layerorder[i], + lp->name ? lp->name : "(null)", + (endtime.tv_sec + endtime.tv_usec / 1.0e6) - + (starttime.tv_sec + starttime.tv_usec / 1.0e6)); + } + } + + /* Do we need to fake out stuff for rotated support? */ + /* This really needs to be done on every preceding exit point too... */ + if (map->gt.need_geotransform) + msMapRestoreRealExtent(map); + + if (map->legend.status == MS_EMBED && map->legend.postlabelcache) + if (MS_UNLIKELY(MS_FAILURE == msEmbedLegend(map, image))) { + msFreeImage(image); +#if defined(USE_WMS_LYR) || defined(USE_WFS_LYR) + /* Cleanup WMS/WFS Request stuff */ + if (pasOWSReqInfo) { + msHTTPFreeRequestObj(pasOWSReqInfo, numOWSRequests); + msFree(pasOWSReqInfo); + } +#endif + return NULL; + } + + if (map->scalebar.status == MS_EMBED && map->scalebar.postlabelcache) { + + /* We need to temporarily restore the original extent for drawing */ + /* the scalebar as it uses the extent to recompute cellsize. */ + if (map->gt.need_geotransform) + msMapRestoreRealExtent(map); + + if (MS_SUCCESS != msEmbedScalebar(map, image)) { + msFreeImage(image); +#if defined(USE_WMS_LYR) || defined(USE_WFS_LYR) + /* Cleanup WMS/WFS Request stuff */ + if (pasOWSReqInfo) { + msHTTPFreeRequestObj(pasOWSReqInfo, numOWSRequests); + msFree(pasOWSReqInfo); + } +#endif + return NULL; + } + + if (map->gt.need_geotransform) + msMapSetFakedExtent(map); + } + +#if defined(USE_WMS_LYR) || defined(USE_WFS_LYR) + /* Cleanup WMS/WFS Request stuff */ + if (pasOWSReqInfo) { + msHTTPFreeRequestObj(pasOWSReqInfo, numOWSRequests); + msFree(pasOWSReqInfo); + } +#endif + + if (map->debug >= MS_DEBUGLEVEL_TUNING) { + msGettimeofday(&mapendtime, NULL); + msDebug("msDrawMap() total time: %.3fs\n", + (mapendtime.tv_sec + mapendtime.tv_usec / 1.0e6) - + (mapstarttime.tv_sec + mapstarttime.tv_usec / 1.0e6)); + } + + return (image); +} + +/* + * Test whether a layer should be drawn or not in the current map view and + * at the current scale. + * Returns TRUE if layer is visible, FALSE if not. + */ +int msLayerIsVisible(mapObj *map, layerObj *layer) { + int i; + + if (!layer->data && !layer->tileindex && !layer->connection && + !layer->features && !layer->grid) + return (MS_FALSE); /* no data associated with this layer, not an error since + layer may be used as a template from MapScript */ + + if (layer->type == MS_LAYER_QUERY || layer->type == MS_LAYER_TILEINDEX) + return (MS_FALSE); + if ((layer->status != MS_ON) && (layer->status != MS_DEFAULT)) + return (MS_FALSE); + + /* Do comparisons of layer scale vs map scale now, since msExtentsOverlap() */ + /* can be slow */ + if (map->scaledenom > 0) { + + /* layer scale boundaries should be checked first */ + if ((layer->maxscaledenom > 0) && + (map->scaledenom > layer->maxscaledenom)) { + if (layer->debug >= MS_DEBUGLEVEL_V) { + msDebug("msLayerIsVisible(): Skipping layer (%s) because " + "LAYER.MAXSCALE is too small for this MAP scale\n", + layer->name); + } + return (MS_FALSE); + } + if (/*(layer->minscaledenom > 0) &&*/ (map->scaledenom <= + layer->minscaledenom)) { + if (layer->debug >= MS_DEBUGLEVEL_V) { + msDebug("msLayerIsVisible(): Skipping layer (%s) because " + "LAYER.MINSCALE is too large for this MAP scale\n", + layer->name); + } + return (MS_FALSE); + } + } + + /* Only return MS_FALSE if it is definitely false. Sometimes it will return + *MS_UNKNOWN, which we + ** consider true, for this use case (it might be visible, try and draw it, + *see what happens). */ + if (msExtentsOverlap(map, layer) == MS_FALSE) { + if (layer->debug >= MS_DEBUGLEVEL_V) { + msDebug("msLayerIsVisible(): Skipping layer (%s) because LAYER.EXTENT " + "does not intersect MAP.EXTENT\n", + layer->name); + } + return (MS_FALSE); + } + + if (msEvalContext(map, layer, layer->requires) == MS_FALSE) + return (MS_FALSE); + + if (map->scaledenom > 0) { + + /* now check class scale boundaries (all layers *must* pass these tests) */ + if (layer->numclasses > 0) { + for (i = 0; i < layer->numclasses; i++) { + if ((layer->class[i] -> maxscaledenom > 0) && + (map->scaledenom > layer->class[i] -> maxscaledenom)) + continue; /* can skip this one, next class */ + if ((layer->class[i] -> minscaledenom > 0) && + (map->scaledenom <= layer->class[i] -> minscaledenom)) + continue; /* can skip this one, next class */ + + break; /* can't skip this class (or layer for that matter) */ + } + if (i == layer->numclasses) { + if (layer->debug >= MS_DEBUGLEVEL_V) { + msDebug("msLayerIsVisible(): Skipping layer (%s) because no CLASS in " + "the layer is in-scale for this MAP scale\n", + layer->name); + } + return (MS_FALSE); + } + } + } + + if (layer->maxscaledenom <= 0 && layer->minscaledenom <= 0) { + if ((layer->maxgeowidth > 0) && + ((map->extent.maxx - map->extent.minx) > layer->maxgeowidth)) { + if (layer->debug >= MS_DEBUGLEVEL_V) { + msDebug("msLayerIsVisible(): Skipping layer (%s) because LAYER width " + "is much smaller than map width\n", + layer->name); + } + return (MS_FALSE); + } + if ((layer->mingeowidth > 0) && + ((map->extent.maxx - map->extent.minx) < layer->mingeowidth)) { + if (layer->debug >= MS_DEBUGLEVEL_V) { + msDebug("msLayerIsVisible(): Skipping layer (%s) because LAYER width " + "is much larger than map width\n", + layer->name); + } + return (MS_FALSE); + } + } + + return MS_TRUE; /* All tests passed. Layer is visible. */ +} + +#define LAYER_NEEDS_COMPOSITING(layer) \ + (((layer)->compositer != NULL) && \ + ((layer)->compositer->next || (layer)->compositor->opacity < 100 || \ + (layer)->compositor->compop != MS_COMPOP_SRC_OVER || \ + (layer)->compositer->filter)) +/* + * Generic function to render a layer object. + */ +int msDrawLayer(mapObj *map, layerObj *layer, imageObj *image) { + imageObj *image_draw = image; + outputFormatObj *altFormat = NULL; + int retcode = MS_SUCCESS; + const char *alternativeFormatString = NULL; + layerObj *maskLayer = NULL; + + if (!msLayerIsVisible(map, layer)) + return MS_SUCCESS; + + if (layer->compositer && !layer->compositer->next && + layer->compositer->opacity == 0) + return MS_SUCCESS; /* layer is completely transparent, skip it */ + + /* conditions may have changed since this layer last drawn, so retest + layer->project (Bug #673) */ + layer->project = + msProjectionsDiffer(&(layer->projection), &(map->projection)); + + /* make sure labelcache setting is set correctly if postlabelcache is set. + This is done by the parser but may have been altered by a mapscript. see + #5142 */ + if (layer->postlabelcache) { + layer->labelcache = MS_FALSE; + } + + if (layer->mask) { + int maskLayerIdx; + /* render the mask layer in its own imageObj */ + if (!MS_IMAGE_RENDERER(image)->supports_pixel_buffer) { + msSetError(MS_MISCERR, + "Layer (%s) references references a mask layer, but the " + "selected renderer does not support them", + "msDrawLayer()", layer->name); + return (MS_FAILURE); + } + maskLayerIdx = msGetLayerIndex(map, layer->mask); + if (maskLayerIdx == -1) { + msSetError(MS_MISCERR, "Layer (%s) references unknown mask layer (%s)", + "msDrawLayer()", layer->name, layer->mask); + return (MS_FAILURE); + } + maskLayer = GET_LAYER(map, maskLayerIdx); + if (!maskLayer->maskimage) { + int i; + int origstatus, origlabelcache; + altFormat = msSelectOutputFormat(map, "png24"); + msInitializeRendererVTable(altFormat); + /* TODO: check the png24 format hasn't been tampered with, i.e. it's agg + */ + maskLayer->maskimage = msImageCreate( + image->width, image->height, altFormat, image->imagepath, + image->imageurl, map->resolution, map->defresolution, NULL); + if (!maskLayer->maskimage) { + msSetError(MS_MISCERR, "Unable to initialize mask image.", + "msDrawLayer()"); + return (MS_FAILURE); + } + + /* + * force the masked layer to status on, and turn off the labelcache so + * that eventual labels are added to the temporary image instead of being + * added to the labelcache + */ + origstatus = maskLayer->status; + origlabelcache = maskLayer->labelcache; + maskLayer->status = MS_ON; + maskLayer->labelcache = MS_OFF; + + /* draw the mask layer in the temporary image */ + retcode = msDrawLayer(map, maskLayer, maskLayer->maskimage); + maskLayer->status = origstatus; + maskLayer->labelcache = origlabelcache; + if (retcode != MS_SUCCESS) { + return MS_FAILURE; + } + /* + * hack to work around bug #3834: if we have use an alternate renderer, + * the symbolset may contain symbols that reference it. We want to remove + * those references before the altFormat is destroyed to avoid a segfault + * and/or a leak, and so the the main renderer doesn't pick the cache up + * thinking it's for him. + */ + for (i = 0; i < map->symbolset.numsymbols; i++) { + if (map->symbolset.symbol[i] != NULL) { + symbolObj *s = map->symbolset.symbol[i]; + if (s->renderer == MS_IMAGE_RENDERER(maskLayer->maskimage)) { + MS_IMAGE_RENDERER(maskLayer->maskimage)->freeSymbol(s); + s->renderer = NULL; + } + } + } + /* set the imagetype from the original outputformat back (it was removed + * by msSelectOutputFormat() */ + msFree(map->imagetype); + map->imagetype = msStrdup(image->format->name); + } + } + altFormat = NULL; + /* inform the rendering device that layer draw is starting. */ + msImageStartLayer(map, layer, image); + + /*check if an alternative renderer should be used for this layer*/ + alternativeFormatString = msLayerGetProcessingKey(layer, "RENDERER"); + if (MS_RENDERER_PLUGIN(image_draw->format) && + alternativeFormatString != NULL && + (altFormat = msSelectOutputFormat(map, alternativeFormatString))) { + rendererVTableObj *renderer = NULL; + msInitializeRendererVTable(altFormat); + + image_draw = msImageCreate( + image->width, image->height, altFormat, image->imagepath, + image->imageurl, map->resolution, map->defresolution, &map->imagecolor); + renderer = MS_IMAGE_RENDERER(image_draw); + renderer->startLayer(image_draw, map, layer); + } else if (MS_RENDERER_PLUGIN(image_draw->format)) { + rendererVTableObj *renderer = MS_IMAGE_RENDERER(image_draw); + if ((layer->mask && layer->connectiontype != MS_WMS && + layer->type != MS_LAYER_RASTER) || + layer->compositer) { + /* masking occurs at the pixel/layer level for raster images, so we don't + need to create a temporary image in these cases + */ + if (layer->mask || renderer->compositeRasterBuffer) { + image_draw = msImageCreate(image->width, image->height, image->format, + image->imagepath, image->imageurl, + map->resolution, map->defresolution, NULL); + if (!image_draw) { + msSetError(MS_MISCERR, + "Unable to initialize temporary transparent image.", + "msDrawLayer()"); + return (MS_FAILURE); + } + image_draw->map = map; + renderer->startLayer(image_draw, map, layer); + } + } + } + /* + ** redirect processing of some layer types. + */ + if (layer->connectiontype == MS_WMS) { +#ifdef USE_WMS_LYR + retcode = msDrawWMSLayer(map, layer, image_draw); +#else + retcode = MS_FAILURE; +#endif + } else if (layer->type == MS_LAYER_RASTER) { + retcode = msDrawRasterLayer(map, layer, image_draw); + } else if (layer->type == MS_LAYER_CHART) { + retcode = msDrawChartLayer(map, layer, image_draw); + } else { /* must be a Vector layer */ + retcode = msDrawVectorLayer(map, layer, image_draw); + } + + if (altFormat) { + rendererVTableObj *renderer = MS_IMAGE_RENDERER(image); + rendererVTableObj *altrenderer = MS_IMAGE_RENDERER(image_draw); + rasterBufferObj rb; + int i; + memset(&rb, 0, sizeof(rasterBufferObj)); + + altrenderer->endLayer(image_draw, map, layer); + + retcode = altrenderer->getRasterBufferHandle(image_draw, &rb); + if (MS_UNLIKELY(retcode == MS_FAILURE)) { + goto altformat_cleanup; + } + retcode = renderer->mergeRasterBuffer( + image, &rb, + ((layer->compositer) ? (layer->compositer->opacity * 0.01) : (1.0)), 0, + 0, 0, 0, rb.width, rb.height); + if (MS_UNLIKELY(retcode == MS_FAILURE)) { + goto altformat_cleanup; + } + + altformat_cleanup: + /* + * hack to work around bug #3834: if we have use an alternate renderer, the + * symbolset may contain symbols that reference it. We want to remove those + * references before the altFormat is destroyed to avoid a segfault and/or a + * leak, and so the main renderer doesn't pick the cache up thinking + * it's for him. + */ + for (i = 0; i < map->symbolset.numsymbols; i++) { + if (map->symbolset.symbol[i] != NULL) { + symbolObj *s = map->symbolset.symbol[i]; + if (s->renderer == altrenderer) { + altrenderer->freeSymbol(s); + s->renderer = NULL; + } + } + } + msFreeImage(image_draw); + /* set the imagetype from the original outputformat back (it was removed by + * msSelectOutputFormat() */ + msFree(map->imagetype); + map->imagetype = msStrdup(image->format->name); + } else if (image != image_draw) { + rendererVTableObj *renderer = MS_IMAGE_RENDERER(image_draw); + rasterBufferObj rb; + memset(&rb, 0, sizeof(rasterBufferObj)); + + renderer->endLayer(image_draw, map, layer); + + retcode = renderer->getRasterBufferHandle(image_draw, &rb); + if (MS_UNLIKELY(retcode == MS_FAILURE)) { + goto imagedraw_cleanup; + } + if (maskLayer && maskLayer->maskimage) { + rasterBufferObj mask; + unsigned int row, col; + memset(&mask, 0, sizeof(rasterBufferObj)); + retcode = MS_IMAGE_RENDERER(maskLayer->maskimage) + ->getRasterBufferHandle(maskLayer->maskimage, &mask); + if (MS_UNLIKELY(retcode == MS_FAILURE)) { + goto imagedraw_cleanup; + } + /* modify the pixels of the overlay */ + + if (rb.type == MS_BUFFER_BYTE_RGBA) { + for (row = 0; row < rb.height; row++) { + unsigned char *ma, *a, *r, *g, *b; + r = rb.data.rgba.r + row * rb.data.rgba.row_step; + g = rb.data.rgba.g + row * rb.data.rgba.row_step; + b = rb.data.rgba.b + row * rb.data.rgba.row_step; + a = rb.data.rgba.a + row * rb.data.rgba.row_step; + ma = mask.data.rgba.a + row * mask.data.rgba.row_step; + for (col = 0; col < rb.width; col++) { + if (*ma == 0) { + *a = *r = *g = *b = 0; + } + a += rb.data.rgba.pixel_step; + r += rb.data.rgba.pixel_step; + g += rb.data.rgba.pixel_step; + b += rb.data.rgba.pixel_step; + ma += mask.data.rgba.pixel_step; + } + } + } + } + if (!layer->compositer) { + /*we have a mask layer with no composition configured, do a nomral blend + */ + retcode = renderer->mergeRasterBuffer(image, &rb, 1.0, 0, 0, 0, 0, + rb.width, rb.height); + } else { + retcode = msCompositeRasterBuffer(map, image, &rb, layer->compositer); + } + if (MS_UNLIKELY(retcode == MS_FAILURE)) { + goto imagedraw_cleanup; + } + + imagedraw_cleanup: + msFreeImage(image_draw); + } + + msImageEndLayer(map, layer, image); + return (retcode); +} + +int msDrawVectorLayer(mapObj *map, layerObj *layer, imageObj *image) { + int status, retcode = MS_SUCCESS; + int drawmode = MS_DRAWMODE_FEATURES; + char annotate = MS_TRUE; + shapeObj shape; + shapeObj savedShape; + rectObj searchrect; + char cache = MS_FALSE; + int maxnumstyles = 1; + featureListNodeObjPtr shpcache = NULL, current = NULL; + int nclasses = 0; + int *classgroup = NULL; + double minfeaturesize = -1; + int maxfeatures = -1; + int featuresdrawn = 0; + + if (image) + maxfeatures = msLayerGetMaxFeaturesToDraw(layer, image->format); + + /* TODO TBT: draw as raster layer in vector renderers */ + + annotate = msEvalContext(map, layer, layer->labelrequires); + if (map->scaledenom > 0) { + if ((layer->labelmaxscaledenom != -1) && + (map->scaledenom >= layer->labelmaxscaledenom)) + annotate = MS_FALSE; + if ((layer->labelminscaledenom != -1) && + (map->scaledenom < layer->labelminscaledenom)) + annotate = MS_FALSE; + } + + /* open this layer */ + status = msLayerOpen(layer); + if (status != MS_SUCCESS) + return MS_FAILURE; + + /* build item list. STYLEITEM javascript needs the shape attributes */ + if (layer->styleitem && (STARTS_WITH_CI(layer->styleitem, "javascript://") || + STARTS_WITH_CI(layer->styleitem, "sld://"))) { + status = msLayerWhichItems(layer, MS_TRUE, NULL); + } else { + status = msLayerWhichItems(layer, MS_FALSE, NULL); + } + + if (status != MS_SUCCESS) { + msLayerClose(layer); + return MS_FAILURE; + } + + /* identify target shapes */ + if (layer->transform == MS_TRUE) { + searchrect = map->extent; + + if ((map->projection.numargs > 0) && (layer->projection.numargs > 0)) { + int bDone = MS_FALSE; + + if (layer->connectiontype == MS_UVRASTER) { + /* Nasty hack to make msUVRASTERLayerWhichShapes() aware that the */ + /* original area of interest is (map->extent, map->projection)... */ + /* Useful when dealing with UVRASTER that extend beyond 180 deg */ + msUVRASTERLayerUseMapExtentAndProjectionForNextWhichShapes(layer, map); + + searchrect = msUVRASTERGetSearchRect(layer, map); + bDone = MS_TRUE; + } else if (layer->connectiontype == MS_RASTER_LABEL) { + /* Nasty hack to make msRasterLabelLayerWhichShapes() aware that the */ + /* original area of interest is (map->extent, map->projection)... */ + /* Useful when dealing with RasterLabel that extend beyond 180 deg */ + msRasterLabelLayerUseMapExtentAndProjectionForNextWhichShapes(layer, + map); + + searchrect = msUVRASTERGetSearchRect(layer, map); + bDone = MS_TRUE; + } else if (layer->connectiontype == MS_CONTOUR) { + msContourLayerUseMapExtentAndProjectionForNextWhichShapes(layer, map); + } + + if (!bDone) + msProjectRect( + &map->projection, &layer->projection, + &searchrect); /* project the searchrect to source coords */ + } + + } else { + searchrect.minx = searchrect.miny = 0; + searchrect.maxx = map->width - 1; + searchrect.maxy = map->height - 1; + } + + status = msLayerWhichShapes(layer, searchrect, MS_FALSE); + + if (layer->connectiontype == MS_UVRASTER) { + msUVRASTERLayerUseMapExtentAndProjectionForNextWhichShapes(layer, NULL); + } else if (layer->connectiontype == MS_RASTER_LABEL) { + msRasterLabelLayerUseMapExtentAndProjectionForNextWhichShapes(layer, NULL); + } else if (layer->connectiontype == MS_CONTOUR) { + msContourLayerUseMapExtentAndProjectionForNextWhichShapes(layer, NULL); + } + + if (status == MS_DONE) { /* no overlap */ + msLayerClose(layer); + return MS_SUCCESS; + } else if (status != MS_SUCCESS) { + msLayerClose(layer); + return MS_FAILURE; + } + + nclasses = 0; + classgroup = NULL; + if (layer->classgroup && layer->numclasses > 0) + classgroup = msAllocateValidClassGroups(layer, &nclasses); + + if (layer->minfeaturesize > 0) + minfeaturesize = Pix2LayerGeoref(map, layer, layer->minfeaturesize); + + // Select how to render classes + // MS_FIRST_MATCHING_CLASS: Default and historic MapServer behavior + // MS_ALL_MATCHING_CLASSES: SLD behavior + int ref_rendermode; + const char *rendermodestr = msLayerGetProcessingKey(layer, "RENDERMODE"); + if (layer->rendermode == MS_ALL_MATCHING_CLASSES) { + // SLD takes precedence + ref_rendermode = MS_ALL_MATCHING_CLASSES; + } else if (!rendermodestr) { + // Default Mapfile + ref_rendermode = MS_FIRST_MATCHING_CLASS; + } else if (!strcmp(rendermodestr, "FIRST_MATCHING_CLASS")) { + // Explicit default Mapfile + ref_rendermode = MS_FIRST_MATCHING_CLASS; + } else if (!strcmp(rendermodestr, "ALL_MATCHING_CLASSES")) { + // SLD-like Mapfile + ref_rendermode = MS_ALL_MATCHING_CLASSES; + } else { + msLayerClose(layer); + msSetError(MS_MISCERR, + "Unknown RENDERMODE: %s, should be one of: " + "FIRST_MATCHING_CLASS, ALL_MATCHING_CLASSES.", + "msDrawVectorLayer()", rendermodestr); + return MS_FAILURE; + } + + /* step through the target shapes and their classes */ + msInitShape(&shape); + int classindex = -1; + int classcount = 0; + for (;;) { + int rendermode; + if (classindex == -1) { + msFreeShape(&shape); + status = msLayerNextShape(layer, &shape); + if (status != MS_SUCCESS) { + break; + } + + /* Check if the shape size is ok to be drawn */ + if ((shape.type == MS_SHAPE_LINE || shape.type == MS_SHAPE_POLYGON) && + (minfeaturesize > 0) && + (msShapeCheckSize(&shape, minfeaturesize) == MS_FALSE)) { + if (layer->debug >= MS_DEBUGLEVEL_V) + msDebug("msDrawVectorLayer(): Skipping shape (%ld) because " + "LAYER::MINFEATURESIZE is bigger than shape size\n", + shape.index); + continue; + } + classcount = 0; + } + + classindex = msShapeGetNextClass(classindex, layer, map, &shape, classgroup, + nclasses); + if ((classindex == -1) || (layer->class[classindex] -> status == MS_OFF)) { + continue; + } + shape.classindex = classindex; + + // When only one class is applicable, rendering mode is forced to its + // default, i.e. only the first applicable class is actually applied. As a + // consequence, cache can be enabled when relevant. + classcount++; + rendermode = ref_rendermode; + if ((classcount == 1) && + (msShapeGetNextClass(classindex, layer, map, &shape, classgroup, + nclasses) == -1)) { + rendermode = MS_FIRST_MATCHING_CLASS; + } + + if (rendermode == MS_FIRST_MATCHING_CLASS) { + classindex = -1; + } + + if (maxfeatures >= 0 && featuresdrawn >= maxfeatures) { + status = MS_DONE; + break; + } + featuresdrawn++; + + cache = MS_FALSE; + if (layer->type == MS_LAYER_LINE && + (layer->class[shape.classindex] + -> numstyles > 1 || + (layer->class[shape.classindex] + -> numstyles == 1 && + (layer->class[shape.classindex] -> styles[0] + -> outlinewidth > 0 || + layer -> class[shape.classindex] -> styles[0] + -> bindings[MS_STYLE_BINDING_OUTLINEWIDTH].index != + -1)))) { + cache = MS_TRUE; /* only line layers with multiple styles need be cached + (I don't think POLYLINE layers need caching - SDL) */ + // we also cache line layers with outlinewidths + } + + /* With 'STYLEITEM AUTO', we will have the datasource fill the class' */ + /* style parameters for this shape. */ + if (layer->styleitem) { + if (strcasecmp(layer->styleitem, "AUTO") == 0) { + if (msLayerGetAutoStyle(map, layer, layer->class[shape.classindex], + &shape) != MS_SUCCESS) { + retcode = MS_FAILURE; + break; + } + } else { + /* Generic feature style handling as per RFC-61 */ + if (msLayerGetFeatureStyle(map, layer, layer->class[shape.classindex], + &shape) != MS_SUCCESS) { + retcode = MS_FAILURE; + break; + } + } + + /* __TODO__ For now, we can't cache features with 'AUTO' style */ + cache = MS_FALSE; + } + + if (rendermode == MS_ALL_MATCHING_CLASSES) { + // Cache is designed to handle only one class. Therefore it is + // disabled when using SLD "painters model" rendering mode. + cache = MS_FALSE; + } + + /* RFC77 TODO: check return value, may need a more sophisticated if-then + * test. */ + if (annotate && layer->class[shape.classindex] -> numlabels > 0) { + drawmode |= MS_DRAWMODE_LABELS; + if (msLayerGetProcessingKey(layer, "LABEL_NO_CLIP")) { + drawmode |= MS_DRAWMODE_UNCLIPPEDLABELS; + } + } + + if (layer->type == MS_LAYER_LINE && + msLayerGetProcessingKey(layer, "POLYLINE_NO_CLIP")) { + drawmode |= MS_DRAWMODE_UNCLIPPEDLINES; + } + + if (rendermode == MS_ALL_MATCHING_CLASSES) { + // In SLD "painters model" rendering mode, all applicable classes are + // actually applied. Coordinates stored in the shape must keep their + // original values for the shape to be drawn multiple times. Here the + // original shape is saved. + msInitShape(&savedShape); + msCopyShape(&shape, &savedShape); + } + + if (cache) { + styleObj *pStyle = layer->class[shape.classindex]->styles[0]; + + // first ensure the style properties are bound to the shape + // any outlinewidth bindings will then be set + if (msBindLayerToShape(layer, &shape, drawmode) != MS_SUCCESS) { + retcode = MS_FAILURE; + break; + } + + if (pStyle->outlinewidth > 0) { + /* + * RFC 49 implementation + * if an outlinewidth is used: + * - augment the style's width to account for the outline width + * - swap the style color and outlinecolor + * - draw the shape (the outline) in the first pass of the + * caching mechanism + */ + msOutlineRenderingPrepareStyle(pStyle, map, layer, image); + } + /* draw a single style */ + status = msDrawShape(map, layer, &shape, image, 0, + drawmode | MS_DRAWMODE_SINGLESTYLE); + + if (pStyle->outlinewidth > 0) { + /* + * RFC 49 implementation: switch back the styleobj to its + * original state, so the line fill will be drawn in the + * second pass of the caching mechanism + */ + msOutlineRenderingRestoreStyle(pStyle, map, layer, image); + } + } else { + status = + msDrawShape(map, layer, &shape, image, -1, drawmode); /* all styles */ + } + + if (rendermode == MS_ALL_MATCHING_CLASSES) { + // In SLD "painters model" rendering mode, all applicable classes are + // actually applied. Coordinates stored in the shape must keep their + // original values for the shape to be drawn multiple times. Here the + // original shape is restored. + msFreeShape(&shape); + msCopyShape(&savedShape, &shape); + msFreeShape(&savedShape); + } + + if (status != MS_SUCCESS) { + retcode = MS_FAILURE; + break; + } + + if (shape.numlines == + 0) { /* once clipped the shape didn't need to be drawn */ + continue; + } + + if (cache) { + if (insertFeatureList(&shpcache, &shape) == NULL) { + retcode = MS_FAILURE; /* problem adding to the cache */ + break; + } + } + + maxnumstyles = + MS_MAX(maxnumstyles, layer->class[shape.classindex] -> numstyles); + } + msFreeShape(&shape); + + if (classgroup) + msFree(classgroup); + + if (status != MS_DONE || retcode == MS_FAILURE) { + msLayerClose(layer); + if (shpcache) { + freeFeatureList(shpcache); + shpcache = NULL; + } + return MS_FAILURE; + } + + if (shpcache && MS_DRAW_FEATURES(drawmode)) { + int s; + for (s = 0; s < maxnumstyles; s++) { + for (current = shpcache; current; current = current->next) { + if (layer->class[current->shape.classindex] -> numstyles > s) { + styleObj *pStyle = layer->class[current->shape.classindex]->styles[s]; + if (pStyle->_geomtransform.type != MS_GEOMTRANSFORM_NONE) + continue; /*skip this as it has already been rendered*/ + if (map->scaledenom > 0) { + if ((pStyle->maxscaledenom != -1) && + (map->scaledenom >= pStyle->maxscaledenom)) + continue; + if ((pStyle->minscaledenom != -1) && + (map->scaledenom < pStyle->minscaledenom)) + continue; + } + if (s == 0 && + (pStyle->outlinewidth > 0 || + pStyle->bindings[MS_STYLE_BINDING_OUTLINEWIDTH].index != -1) && + MS_VALID_COLOR(pStyle->color)) { + if (MS_UNLIKELY(MS_FAILURE == + msDrawLineSymbol(map, image, ¤t->shape, + pStyle, pStyle->scalefactor))) { + return MS_FAILURE; + } + } else if (s > 0) { + if ((pStyle->outlinewidth > 0 || + pStyle->bindings[MS_STYLE_BINDING_OUTLINEWIDTH].index != -1) && + MS_VALID_COLOR(pStyle->outlinecolor)) { + /* + * RFC 49 implementation + * if an outlinewidth is used: + * - augment the style's width to account for the outline width + * - swap the style color and outlinecolor + * - draw the shape (the outline) in the first pass of the + * caching mechanism + */ + msOutlineRenderingPrepareStyle(pStyle, map, layer, image); + if (MS_UNLIKELY(MS_FAILURE == + msDrawLineSymbol(map, image, ¤t->shape, + pStyle, pStyle->scalefactor))) { + return MS_FAILURE; + } + /* + * RFC 49 implementation: switch back the styleobj to its + * original state, so the line fill will be drawn in the + * second pass of the caching mechanism + */ + msOutlineRenderingRestoreStyle(pStyle, map, layer, image); + } + /* draw a valid line, i.e. one with a color defined or of type + * pixmap*/ + if (MS_VALID_COLOR(pStyle->color) || + (pStyle->symbol < map->symbolset.numsymbols && + (map->symbolset.symbol[pStyle->symbol]->type == + MS_SYMBOL_PIXMAP || + map->symbolset.symbol[pStyle->symbol]->type == + MS_SYMBOL_SVG))) { + if (MS_UNLIKELY(MS_FAILURE == + msDrawLineSymbol(map, image, ¤t->shape, + pStyle, pStyle->scalefactor))) + return MS_FAILURE; + } + } + } + } + } + + freeFeatureList(shpcache); + shpcache = NULL; + } + + msLayerClose(layer); + return MS_SUCCESS; +} + +/* +** Function to draw a layer IF it already has a result cache associated with it. +*Called by msDrawMap and via MapScript. +*/ +int msDrawQueryLayer(mapObj *map, layerObj *layer, imageObj *image) { + int i, status; + char annotate = MS_TRUE, cache = MS_FALSE; + int drawmode = MS_DRAWMODE_FEATURES; + shapeObj shape; + int maxnumstyles = 1; + + featureListNodeObjPtr shpcache = NULL, current = NULL; + + colorObj *colorbuffer = NULL; + int *mindistancebuffer = NULL; + + if (!layer->resultcache) + return (msDrawLayer(map, layer, image)); + + if (!msLayerIsVisible(map, layer)) + return (MS_SUCCESS); /* not an error, just nothing to do */ + + /* conditions may have changed since this layer last drawn, so reset + layer->project to recheck projection needs (Bug #673) */ + layer->project = + msProjectionsDiffer(&(layer->projection), &(map->projection)); + + /* set annotation status */ + annotate = msEvalContext(map, layer, layer->labelrequires); + if (map->scaledenom > 0) { + if ((layer->labelmaxscaledenom != -1) && + (map->scaledenom >= layer->labelmaxscaledenom)) + annotate = MS_FALSE; + if ((layer->labelminscaledenom != -1) && + (map->scaledenom < layer->labelminscaledenom)) + annotate = MS_FALSE; + } + + /* + ** Certain query map styles require us to render all features only (MS_NORMAL) + *or first (MS_HILITE). With + ** single-pass queries we have to make a copy of the layer and work from it + *instead. + */ + if (map->querymap.style == MS_NORMAL || map->querymap.style == MS_HILITE) { + layerObj tmp_layer; + + if (initLayer(&tmp_layer, map) == -1) + return (MS_FAILURE); + + if (msCopyLayer(&tmp_layer, layer) != MS_SUCCESS) + return (MS_FAILURE); + + /* disable the connection pool for this layer */ + msLayerSetProcessingKey(&tmp_layer, "CLOSE_CONNECTION", "ALWAYS"); + + status = msDrawLayer(map, &tmp_layer, image); + + freeLayer(&tmp_layer); + + if (map->querymap.style == MS_NORMAL || status != MS_SUCCESS) + return (status); + } + + /* if MS_HILITE, alter the one style (always at least 1 style), and set a + * MINDISTANCE for the labelObj to avoid duplicates */ + if (map->querymap.style == MS_HILITE) { + + drawmode |= MS_DRAWMODE_QUERY; + + if (layer->numclasses > 0) { + colorbuffer = + (colorObj *)msSmallMalloc(layer->numclasses * sizeof(colorObj)); + mindistancebuffer = (int *)msSmallMalloc(layer->numclasses * sizeof(int)); + } + + for (i = 0; i < layer->numclasses; i++) { + if (layer->type == MS_LAYER_POLYGON && + layer->class[i] -> numstyles > + 0) { /* alter BOTTOM style since that's + almost always the fill */ + if (layer->class[i] -> styles == NULL) { + msSetError(MS_MISCERR, + "Don't know how to draw class %s of layer %s without a " + "style definition.", + "msDrawQueryLayer()", layer->class[i] -> name, + layer -> name); + msFree(colorbuffer); + msFree(mindistancebuffer); + return (MS_FAILURE); + } + if (MS_VALID_COLOR(layer->class[i] -> styles[0] -> color)) { + colorbuffer[i] = + layer->class[i] + ->styles[0] + ->color; /* save the color from the BOTTOM style */ + layer->class[i]->styles[0]->color = map->querymap.color; + } else if (MS_VALID_COLOR( + layer->class[i] -> styles[0] -> outlinecolor)) { + colorbuffer[i] = + layer->class[i] + ->styles[0] + ->outlinecolor; /* if no color, save the outlinecolor from the + BOTTOM style */ + layer->class[i]->styles[0]->outlinecolor = map->querymap.color; + } + } else if (layer->type == MS_LAYER_LINE && + layer->class[i] -> numstyles > 0 && + layer -> class[i] -> styles[0] + -> outlinewidth > + 0) { /* alter BOTTOM style for lines with outlines */ + if (MS_VALID_COLOR(layer->class[i] -> styles[0] -> color)) { + colorbuffer[i] = + layer->class[i] + ->styles[0] + ->color; /* save the color from the BOTTOM style */ + layer->class[i]->styles[0]->color = map->querymap.color; + } /* else ??? */ + } else if (layer->class[i] -> numstyles > 0) { + if (MS_VALID_COLOR( + layer->class[i] -> styles[layer->class[i] -> numstyles - 1] + -> color)) { + colorbuffer[i] = layer->class[i] + ->styles[layer->class[i] -> numstyles - 1] + ->color; /* save the color from the TOP style */ + layer->class[i]->styles[layer->class[i] -> numstyles - 1]->color = + map->querymap.color; + } else if (MS_VALID_COLOR(layer->class[i] + -> styles[layer->class[i] -> numstyles - 1] + -> outlinecolor)) { + colorbuffer[i] = + layer->class[i] + ->styles[layer->class[i] -> numstyles - 1] + ->outlinecolor; /* if no color, save the outlinecolor from the + TOP style */ + layer->class[i] + ->styles[layer->class[i] -> numstyles - 1] + ->outlinecolor = map->querymap.color; + } + } else if (layer->class[i] -> numlabels > 0) { + colorbuffer[i] = layer->class[i]->labels[0]->color; + layer->class[i]->labels[0]->color = map->querymap.color; + } /* else ??? */ + + mindistancebuffer[i] = + -1; /* RFC77 TODO: only using the first label, is that cool? */ + if (layer->class[i] -> numlabels > 0) { + mindistancebuffer[i] = layer->class[i]->labels[0]->mindistance; + layer->class[i]->labels[0]->mindistance = + MS_MAX(0, layer->class[i] -> labels[0] -> mindistance); + } + } + } + + /* + ** Layer was opened as part of the query process, msLayerWhichItems() has also + *been run, shapes have been classified - start processing! + */ + + msInitShape(&shape); + + for (i = 0; i < layer->resultcache->numresults; i++) { + status = msLayerGetShape(layer, &shape, &(layer->resultcache->results[i])); + if (status != MS_SUCCESS) { + msFree(colorbuffer); + msFree(mindistancebuffer); + return (MS_FAILURE); + } + + shape.classindex = layer->resultcache->results[i].classindex; + /* classindex may be -1 here if there was a template at the top level + * in this layer and the current shape selected even if it didn't + * match any class + * + * FrankW: classindex is also sometimes 0 even if there are no classes, so + * we are careful not to use out of range class values as an index. + */ + if (shape.classindex == -1 || shape.classindex >= layer->numclasses || + layer->class[shape.classindex] -> status == MS_OFF) { + msFreeShape(&shape); + continue; + } + + cache = MS_FALSE; + if (layer->type == MS_LAYER_LINE && + (layer->class[shape.classindex] + -> numstyles > 1 || + (layer->class[shape.classindex] + -> numstyles == 1 && + (layer->class[shape.classindex] -> styles[0] + -> outlinewidth > 0 || + layer -> class[shape.classindex] -> styles[0] + -> bindings[MS_STYLE_BINDING_OUTLINEWIDTH].index != + -1)))) { + cache = MS_TRUE; /* only line layers with multiple styles need be cached + (I don't think POLYLINE layers need caching - SDL) */ + } + + if (annotate && layer->class[shape.classindex] -> numlabels > 0) { + drawmode |= MS_DRAWMODE_LABELS; + } + + if (cache) { + styleObj *pStyle = layer->class[shape.classindex]->styles[0]; + + if (msBindLayerToShape(layer, &shape, drawmode) == MS_SUCCESS) { + if (pStyle->outlinewidth > 0) { + msOutlineRenderingPrepareStyle(pStyle, map, layer, image); + } + /* draw only the first style */ + status = msDrawShape(map, layer, &shape, image, 0, + drawmode | MS_DRAWMODE_SINGLESTYLE); + if (pStyle->outlinewidth > 0) { + msOutlineRenderingRestoreStyle(pStyle, map, layer, image); + } + } + } else { + /* all styles */ + status = msDrawShape(map, layer, &shape, image, -1, drawmode); + } + + if (status != MS_SUCCESS) { + msLayerClose(layer); + msFree(colorbuffer); + msFree(mindistancebuffer); + return (MS_FAILURE); + } + + if (shape.numlines == + 0) { /* once clipped the shape didn't need to be drawn */ + msFreeShape(&shape); + continue; + } + + if (cache) { + if (insertFeatureList(&shpcache, &shape) == NULL) { + msFree(colorbuffer); + msFree(mindistancebuffer); + return (MS_FAILURE); /* problem adding to the cache */ + } + } + + maxnumstyles = + MS_MAX(maxnumstyles, layer->class[shape.classindex] -> numstyles); + msFreeShape(&shape); + } + + if (shpcache) { + int s; + for (s = 0; s < maxnumstyles; s++) { + for (current = shpcache; current; current = current->next) { + if (layer->class[current->shape.classindex] -> numstyles > s) { + styleObj *pStyle = layer->class[current->shape.classindex]->styles[s]; + if (pStyle->_geomtransform.type != MS_GEOMTRANSFORM_NONE) + continue; /* skip this as it has already been rendered */ + if (map->scaledenom > 0) { + if ((pStyle->maxscaledenom != -1) && + (map->scaledenom >= pStyle->maxscaledenom)) + continue; + if ((pStyle->minscaledenom != -1) && + (map->scaledenom < pStyle->minscaledenom)) + continue; + } + if (s == 0 && pStyle->outlinewidth > 0 && + MS_VALID_COLOR(pStyle->color)) { + if (MS_UNLIKELY(MS_FAILURE == + msDrawLineSymbol(map, image, ¤t->shape, + pStyle, pStyle->scalefactor))) { + return MS_FAILURE; + } + } else if (s > 0) { + if (pStyle->outlinewidth > 0 && + MS_VALID_COLOR(pStyle->outlinecolor)) { + msOutlineRenderingPrepareStyle(pStyle, map, layer, image); + if (MS_UNLIKELY(MS_FAILURE == + msDrawLineSymbol(map, image, ¤t->shape, + pStyle, pStyle->scalefactor))) { + return MS_FAILURE; + } + msOutlineRenderingRestoreStyle(pStyle, map, layer, image); + } + /* draw a valid line, i.e. one with a color defined or of type + * pixmap */ + if (MS_VALID_COLOR(pStyle->color) || + (pStyle->symbol < map->symbolset.numsymbols && + (map->symbolset.symbol[pStyle->symbol]->type == + MS_SYMBOL_PIXMAP || + map->symbolset.symbol[pStyle->symbol]->type == + MS_SYMBOL_SVG))) { + if (MS_UNLIKELY(MS_FAILURE == + msDrawLineSymbol(map, image, ¤t->shape, + pStyle, pStyle->scalefactor))) + return MS_FAILURE; + } + } + } + } + } + + freeFeatureList(shpcache); + shpcache = NULL; + } + + /* if MS_HILITE, restore color and mindistance values */ + if (map->querymap.style == MS_HILITE) { + for (i = 0; i < layer->numclasses; i++) { + if (layer->type == MS_LAYER_POLYGON && layer->class[i] -> numstyles > 0) { + if (MS_VALID_COLOR(layer->class[i] -> styles[0] -> color)) + layer->class[i]->styles[0]->color = colorbuffer[i]; + else if (MS_VALID_COLOR(layer->class[i] -> styles[0] -> outlinecolor)) + layer->class[i]->styles[0]->outlinecolor = + colorbuffer[i]; /* if no color, restore outlinecolor for the + BOTTOM style */ + } else if (layer->type == MS_LAYER_LINE && + layer->class[i] -> numstyles > 0 && layer -> class[i] + -> styles[0] -> outlinewidth > 0) { + if (MS_VALID_COLOR(layer->class[i] -> styles[0] -> color)) + layer->class[i]->styles[0]->color = colorbuffer[i]; + } else if (layer->class[i] -> numstyles > 0) { + if (MS_VALID_COLOR( + layer->class[i] -> styles[layer->class[i] -> numstyles - 1] + -> color)) + layer->class[i]->styles[layer->class[i] -> numstyles - 1]->color = + colorbuffer[i]; + else if (MS_VALID_COLOR( + layer->class[i] -> styles[layer->class[i] -> numstyles - 1] + -> outlinecolor)) + layer->class[i] + ->styles[layer->class[i] -> numstyles - 1] + ->outlinecolor = + colorbuffer[i]; /* if no color, restore outlinecolor for the TOP + style */ + } else if (layer->class[i] -> numlabels > 0) { + if (MS_VALID_COLOR(layer->class[i] -> labels[0] -> color)) + layer->class[i]->labels[0]->color = colorbuffer[i]; + } + + if (layer->class[i] -> numlabels > 0) + layer->class[i]->labels[0]->mindistance = + mindistancebuffer[i]; /* RFC77 TODO: again, only using the first + label, is that cool? */ + } + + msFree(colorbuffer); + msFree(mindistancebuffer); + } + + return (MS_SUCCESS); +} + +/** + * msDrawRasterLayerPlugin() + */ + +static int msDrawRasterLayerPlugin(mapObj *map, layerObj *layer, + imageObj *image) + +{ + rendererVTableObj *renderer = MS_IMAGE_RENDERER(image); + rasterBufferObj *rb = msSmallCalloc(1, sizeof(rasterBufferObj)); + int ret; + if (renderer->supports_pixel_buffer) { + if (MS_SUCCESS != renderer->getRasterBufferHandle(image, rb)) { + msSetError(MS_MISCERR, "renderer failed to extract raster buffer", + "msDrawRasterLayer()"); + return MS_FAILURE; + } + ret = msDrawRasterLayerLow(map, layer, image, rb); + } else { + if (MS_SUCCESS != renderer->initializeRasterBuffer( + rb, image->width, image->height, MS_IMAGEMODE_RGBA)) { + msSetError(MS_MISCERR, "renderer failed to create raster buffer", + "msDrawRasterLayer()"); + return MS_FAILURE; + } + + ret = msDrawRasterLayerLow(map, layer, image, rb); + + if (ret == 0) { + ret = renderer->mergeRasterBuffer(image, rb, 1.0, 0, 0, 0, 0, rb->width, + rb->height); + } + + msFreeRasterBuffer(rb); + } +#define RB_GET_R(rb, x, y) \ + *((rb)->data.rgba.r + (x) * (rb)->data.rgba.pixel_step + \ + (y) * (rb)->data.rgba.row_step) +#define RB_GET_G(rb, x, y) \ + *((rb)->data.rgba.g + (x) * (rb)->data.rgba.pixel_step + \ + (y) * (rb)->data.rgba.row_step) +#define RB_GET_B(rb, x, y) \ + *((rb)->data.rgba.b + (x) * (rb)->data.rgba.pixel_step + \ + (y) * (rb)->data.rgba.row_step) +#define RB_GET_A(rb, x, y) \ + *((rb)->data.rgba.a + (x) * (rb)->data.rgba.pixel_step + \ + (y) * (rb)->data.rgba.row_step) + + free(rb); + + return ret; +} + +/** + * Generic function to render raster layers. + */ +int msDrawRasterLayer(mapObj *map, layerObj *layer, imageObj *image) { + + int rv = MS_FAILURE; + if (!image || !map || !layer) { + return rv; + } + + /* RFC-86 Scale dependent token replacements*/ + rv = msLayerApplyScaletokens(layer, + (layer->map) ? layer->map->scaledenom : -1); + if (rv != MS_SUCCESS) + return rv; + if (MS_RENDERER_PLUGIN(image->format)) + rv = msDrawRasterLayerPlugin(map, layer, image); + else if (MS_RENDERER_RAWDATA(image->format)) + rv = msDrawRasterLayerLow(map, layer, image, NULL); + msLayerRestoreFromScaletokens(layer); + return rv; +} + +/** + * msDrawWMSLayer() + * + * Draw a single WMS layer. + * Multiple WMS layers in a map are preloaded and then drawn using + * msDrawWMSLayerLow() + */ + +#ifdef USE_WMS_LYR +int msDrawWMSLayer(mapObj *map, layerObj *layer, imageObj *image) { + int nStatus = MS_FAILURE; + + if (image && map && layer) { + /* ------------------------------------------------------------------ + * Start by downloading the layer + * ------------------------------------------------------------------ */ + httpRequestObj asReqInfo[2]; + int numReq = 0; + + msHTTPInitRequestObj(asReqInfo, 2); + + if (msPrepareWMSLayerRequest(1, map, layer, 1, 0, NULL, 0, 0, 0, NULL, + asReqInfo, &numReq) == MS_FAILURE || + msOWSExecuteRequests(asReqInfo, numReq, map, MS_TRUE) == MS_FAILURE) { + return MS_FAILURE; + } + + /* ------------------------------------------------------------------ + * Then draw layer based on output format + * ------------------------------------------------------------------ */ + if (MS_RENDERER_PLUGIN(image->format)) + nStatus = msDrawWMSLayerLow(1, asReqInfo, numReq, map, layer, image); + else if (MS_RENDERER_RAWDATA(image->format)) + nStatus = msDrawWMSLayerLow(1, asReqInfo, numReq, map, layer, image); + + else { + msSetError(MS_WMSCONNERR, + "Output format '%s' doesn't support WMS layers.", + "msDrawWMSLayer()", image->format->name); + nStatus = MS_SUCCESS; /* Should we fail if output doesn't support WMS? */ + } + /* Cleanup */ + msHTTPFreeRequestObj(asReqInfo, numReq); + } + + return nStatus; +} +#endif + +int circleLayerDrawShape(mapObj *map, imageObj *image, layerObj *layer, + shapeObj *shape) { + pointObj center; + double r; + int s; + int c = shape->classindex; + + if (shape->numlines != 1) + return (MS_SUCCESS); /* invalid shape */ + if (shape->line[0].numpoints != 2) + return (MS_SUCCESS); /* invalid shape */ + + center.x = (shape->line[0].point[0].x + shape->line[0].point[1].x) / 2.0; + center.y = (shape->line[0].point[0].y + shape->line[0].point[1].y) / 2.0; + r = MS_ABS(center.x - shape->line[0].point[0].x); + if (r == 0) + r = MS_ABS(center.y - shape->line[0].point[0].y); + if (r == 0) + return (MS_SUCCESS); + + if (layer->transform == MS_TRUE) { + + if (layer->project) + msProjectPoint(&layer->projection, &map->projection, ¢er); + + center.x = MS_MAP2IMAGE_X(center.x, map->extent.minx, map->cellsize); + center.y = MS_MAP2IMAGE_Y(center.y, map->extent.maxy, map->cellsize); + r /= map->cellsize; + } else + msOffsetPointRelativeTo(¢er, layer); + + for (s = 0; s < layer->class[c] -> numstyles; s++) { + if (msScaleInBounds(map->scaledenom, + layer->class[c] -> styles[s] -> minscaledenom, + layer -> class[c] -> styles[s] -> maxscaledenom)) + if (MS_UNLIKELY(MS_FAILURE == + msCircleDrawShadeSymbol( + map, image, ¢er, r, layer->class[c] -> styles[s], + layer -> class[c] -> styles[s] -> scalefactor))) { + return MS_FAILURE; + } + } + return MS_SUCCESS; + /* TODO: need to handle circle annotation */ +} + +static int pointLayerDrawShape(mapObj *map, imageObj *image, layerObj *layer, + shapeObj *shape, int drawmode) { + int l, c = shape->classindex, j, i, s; + pointObj *point; + int ret = MS_FAILURE; + + if (layer->project && layer->transform == MS_TRUE) { + reprojectionObj *reprojector = msLayerGetReprojectorToMap(layer, map); + if (reprojector == NULL) { + return MS_FAILURE; + } + msProjectShapeEx(reprojector, shape); + } + + // Only take into account map rotation if the label and style angles are + // non-zero. + if (map->gt.rotation_angle) { + for (l = 0; l < layer->class[c] -> numlabels; l++) { + if (layer->class[c] -> labels[l] -> angle != 0) + layer->class[c]->labels[l]->angle -= map->gt.rotation_angle; + } + + for (s = 0; s < layer->class[c] -> numstyles; s++) { + if (layer->class[c] -> styles[s] -> angle != 0) + layer->class[c]->styles[s]->angle -= map->gt.rotation_angle; + } + } + + for (j = 0; j < shape->numlines; j++) { + for (i = 0; i < shape->line[j].numpoints; i++) { + point = &(shape->line[j].point[i]); + if (layer->transform == MS_TRUE) { + if (!msPointInRect(point, &map->extent)) + continue; /* next point */ + msTransformPoint(point, &map->extent, map->cellsize, image); + } else + msOffsetPointRelativeTo(point, layer); + + if (MS_DRAW_FEATURES(drawmode)) { + for (s = 0; s < layer->class[c] -> numstyles; s++) { + if (msScaleInBounds(map->scaledenom, + layer->class[c] -> styles[s] -> minscaledenom, + layer -> class[c] -> styles[s] -> maxscaledenom)) + if (MS_UNLIKELY( + MS_FAILURE == + msDrawMarkerSymbol( + map, image, point, layer->class[c] -> styles[s], + layer -> class[c] -> styles[s] -> scalefactor))) { + goto end; + } + } + } + if (MS_DRAW_LABELS(drawmode)) { + if (layer->labelcache) { + if (msAddLabelGroup(map, image, layer, c, shape, point, -1) != + MS_SUCCESS) + goto end; + } else { + for (l = 0; l < layer->class[c] -> numlabels; l++) + if (msGetLabelStatus(map, layer, shape, + layer->class[c] -> labels[l]) == MS_ON) { + char *annotext = msShapeGetLabelAnnotation( + layer, shape, layer->class[c] -> labels[l]); + if (MS_UNLIKELY(MS_FAILURE == + msDrawLabel(map, image, *point, annotext, + layer->class[c] -> labels[l], + layer -> class[c] -> labels[l] + -> scalefactor))) { + goto end; + } + } + } + } + } + } + ret = MS_SUCCESS; + +end: + if (map->gt.rotation_angle) { + for (l = 0; l < layer->class[c] -> numlabels; l++) { + if (layer->class[c] -> labels[l] -> angle != 0) + layer->class[c]->labels[l]->angle += map->gt.rotation_angle; + } + + for (s = 0; s < layer->class[c] -> numstyles; s++) { + if (layer->class[c] -> styles[s] -> angle != 0) + layer->class[c]->styles[s]->angle += map->gt.rotation_angle; + } + } + + return ret; +} + +int lineLayerDrawShape(mapObj *map, imageObj *image, layerObj *layer, + shapeObj *shape, shapeObj *anno_shape, + shapeObj *unclipped_shape, int style, int drawmode) { + int c = shape->classindex; + int ret = MS_SUCCESS; + + /* RFC48: loop through the styles, and pass off to the type-specific + function if the style has an appropriate type */ + if (MS_DRAW_FEATURES(drawmode)) { + for (int s = 0; s < layer->class[c] -> numstyles; s++) { + if (msScaleInBounds(map->scaledenom, + layer->class[c] -> styles[s] -> minscaledenom, + layer -> class[c] -> styles[s] -> maxscaledenom)) { + if (layer->class[c] -> styles[s] -> _geomtransform.type != + MS_GEOMTRANSFORM_NONE) { + if (MS_UNLIKELY(MS_FAILURE == + msDrawTransformedShape( + map, image, unclipped_shape, + layer->class[c] -> styles[s], + layer -> class[c] -> styles[s] -> scalefactor))) { + return MS_FAILURE; + } + } else if (!MS_DRAW_SINGLESTYLE(drawmode) || s == style) { + if (MS_UNLIKELY(MS_FAILURE == + msDrawLineSymbol( + map, image, shape, layer->class[c] -> styles[s], + layer -> class[c] -> styles[s] -> scalefactor))) { + return MS_FAILURE; + } + } + } + } + } + + if (MS_DRAW_LABELS(drawmode)) { + for (int l = 0; l < layer->class[c] -> numlabels; l++) { + labelObj *label = layer->class[c]->labels[l]; + textSymbolObj ts; + char *annotext; + if (!msGetLabelStatus(map, layer, shape, label)) { + continue; + } + + annotext = msShapeGetLabelAnnotation(layer, anno_shape, label); + if (!annotext) + continue; + initTextSymbol(&ts); + msPopulateTextSymbolForLabelAndString( + &ts, label, annotext, label->scalefactor, image->resolutionfactor, + layer->labelcache); + + if (label->anglemode == MS_FOLLOW) { /* bug #1620 implementation */ + struct label_follow_result lfr; + + if (!layer->labelcache) { + msSetError(MS_MISCERR, + "Angle mode 'FOLLOW' is supported only with labelcache on", + "msDrawShape()"); + ret = MS_FAILURE; + goto line_cleanup; + } + + memset(&lfr, 0, sizeof(lfr)); + msPolylineLabelPath(map, image, anno_shape, &ts, label, &lfr); + + for (int i = 0; i < lfr.num_follow_labels; i++) { + if (msAddLabel(map, image, label, layer->index, c, anno_shape, NULL, + -1, lfr.follow_labels[i]) != MS_SUCCESS) { + ret = MS_FAILURE; + goto line_cleanup; + } + } + free(lfr.follow_labels); + for (int i = 0; i < lfr.lar.num_label_points; i++) { + textSymbolObj *ts_auto = msSmallMalloc(sizeof(textSymbolObj)); + initTextSymbol(ts_auto); + msCopyTextSymbol(ts_auto, &ts); + ts_auto->rotation = lfr.lar.angles[i]; + { + if (msAddLabel(map, image, label, layer->index, c, anno_shape, + &lfr.lar.label_points[i], -1, + ts_auto) != MS_SUCCESS) { + ret = MS_FAILURE; + free(lfr.lar.angles); + free(lfr.lar.label_points); + goto line_cleanup; + } + } + } + free(lfr.lar.angles); + free(lfr.lar.label_points); + } else { + struct label_auto_result lar; + memset(&lar, 0, sizeof(struct label_auto_result)); + ret = msPolylineLabelPoint(map, anno_shape, &ts, label, &lar, + image->resolutionfactor); + if (MS_UNLIKELY(MS_FAILURE == ret)) + goto line_cleanup; + + if (label->angle != 0) + label->angle -= map->gt.rotation_angle; /* apply rotation angle */ + + for (int i = 0; i < lar.num_label_points; i++) { + textSymbolObj *ts_auto = msSmallMalloc(sizeof(textSymbolObj)); + initTextSymbol(ts_auto); + msCopyTextSymbol(ts_auto, &ts); + ts_auto->rotation = lar.angles[i]; + if (layer->labelcache) { + if (msAddLabel(map, image, label, layer->index, c, anno_shape, + &lar.label_points[i], -1, ts_auto) != MS_SUCCESS) { + ret = MS_FAILURE; + free(lar.angles); + free(lar.label_points); + freeTextSymbol(ts_auto); + free(ts_auto); + goto line_cleanup; + } + } else { + if (!ts_auto->textpath) { + if (MS_UNLIKELY(MS_FAILURE == msComputeTextPath(map, ts_auto))) { + ret = MS_FAILURE; + free(lar.angles); + free(lar.label_points); + freeTextSymbol(ts_auto); + free(ts_auto); + goto line_cleanup; + } + } + ret = msDrawTextSymbol(map, image, lar.label_points[i], ts_auto); + freeTextSymbol(ts_auto); + free(ts_auto); /* TODO RFC98: could we not re-use the original ts + * instead of duplicating into ts_auto ? we cannot + * for now, as the rendering code will modify the + * glyph positions to apply the labelpoint and + * rotation offsets */ + ts_auto = NULL; + if (MS_UNLIKELY(MS_FAILURE == ret)) + goto line_cleanup; + } + } + free(lar.angles); + free(lar.label_points); + } + + line_cleanup: + /* clean up and reset */ + if (ret == MS_FAILURE) { + break; /* from the label looping */ + } + freeTextSymbol(&ts); + } /* next label */ + } + + return ret; +} + +int polygonLayerDrawShape(mapObj *map, imageObj *image, layerObj *layer, + shapeObj *shape, shapeObj *anno_shape, + shapeObj *unclipped_shape, int drawmode) { + + int c = shape->classindex; + pointObj annopnt = {0}; // initialize + int i; + + if (MS_DRAW_FEATURES(drawmode)) { + for (i = 0; i < layer->class[c] -> numstyles; i++) { + if (msScaleInBounds(map->scaledenom, + layer->class[c] -> styles[i] -> minscaledenom, + layer -> class[c] -> styles[i] -> maxscaledenom)) { + if (layer->class[c] -> styles[i] -> _geomtransform.type == + MS_GEOMTRANSFORM_NONE) { + if (MS_UNLIKELY(MS_FAILURE == + msDrawShadeSymbol( + map, image, shape, layer->class[c] -> styles[i], + layer -> class[c] -> styles[i] -> scalefactor))) { + return MS_FAILURE; + } + } else { + if (MS_UNLIKELY(MS_FAILURE == + msDrawTransformedShape( + map, image, unclipped_shape, + layer->class[c] -> styles[i], + layer -> class[c] -> styles[i] -> scalefactor))) { + return MS_FAILURE; + } + } + } + } + } + + if (MS_DRAW_LABELS(drawmode)) { + if (layer->class[c] -> numlabels > 0) { + double minfeaturesize = + layer->class[c]->labels[0]->minfeaturesize * image->resolutionfactor; + if (msPolygonLabelPoint(anno_shape, &annopnt, minfeaturesize) == + MS_SUCCESS) { + for (i = 0; i < layer->class[c] -> numlabels; i++) + if (layer->class[c] -> labels[i] -> angle != 0) + layer->class[c]->labels[i]->angle -= + map->gt.rotation_angle; /* TODO: is this correct ??? */ + if (layer->labelcache) { + if (msAddLabelGroup(map, image, layer, c, anno_shape, &annopnt, + MS_MIN(shape->bounds.maxx - shape->bounds.minx, + shape->bounds.maxy - + shape->bounds.miny)) != MS_SUCCESS) { + return MS_FAILURE; + } + } else { + for (i = 0; i < layer->class[c] -> numlabels; i++) + if (msGetLabelStatus(map, layer, shape, + layer->class[c] -> labels[i]) == MS_ON) { + char *annotext = msShapeGetLabelAnnotation( + layer, shape, + layer->class[c] + -> labels[i]); /*ownership taken by msDrawLabel, no need to + free */ + if (MS_UNLIKELY(MS_FAILURE == + msDrawLabel(map, image, annopnt, annotext, + layer->class[c] -> labels[i], + layer -> class[c] -> labels[i] + -> scalefactor))) { + return MS_FAILURE; + } + } + } + } + } + } + return MS_SUCCESS; +} + +/* +** Function to render an individual shape, the style variable enables/disables +*the drawing of a single style +** versus a single style. This is necessary when drawing entire layers as proper +*overlay can only be achieved +** through caching. "querymapMode" parameter is used to tell msBindLayerToShape +*to not override the +** QUERYMAP HILITE color. +*/ +int msDrawShape(mapObj *map, layerObj *layer, shapeObj *shape, imageObj *image, + int style, int drawmode) { + int c, s, ret = MS_SUCCESS; + shapeObj *anno_shape, *unclipped_shape = shape; + int bNeedUnclippedShape = MS_FALSE; + int bNeedUnclippedAnnoShape = MS_FALSE; + int bShapeNeedsClipping = MS_TRUE; + + if (shape->numlines == 0 || shape->type == MS_SHAPE_NULL) + return MS_SUCCESS; + + c = shape->classindex; + + /* Before we do anything else, we will check for a rangeitem. + If its there, we need to change the style's color to map + the range to the shape */ + for (s = 0; s < layer->class[c] -> numstyles; s++) { + styleObj *style = layer->class[c]->styles[s]; + if (style->rangeitem != NULL) + msShapeToRange((layer->class[c] -> styles[s]), shape); + } + + /* circle and point layers go through their own treatment */ + if (layer->type == MS_LAYER_CIRCLE) { + if (msBindLayerToShape(layer, shape, drawmode) != MS_SUCCESS) + return MS_FAILURE; + msDrawStartShape(map, layer, image, shape); + ret = circleLayerDrawShape(map, image, layer, shape); + msDrawEndShape(map, layer, image, shape); + return ret; + } else if (layer->type == MS_LAYER_POINT || layer->type == MS_LAYER_RASTER) { + if (msBindLayerToShape(layer, shape, drawmode) != MS_SUCCESS) + return MS_FAILURE; + msDrawStartShape(map, layer, image, shape); + ret = pointLayerDrawShape(map, image, layer, shape, drawmode); + msDrawEndShape(map, layer, image, shape); + return ret; + } + + if (layer->type == MS_LAYER_POLYGON && shape->type != MS_SHAPE_POLYGON) { + msSetError( + MS_MISCERR, + "Only polygon shapes can be drawn using a polygon layer definition.", + "polygonLayerDrawShape()"); + return (MS_FAILURE); + } + if (layer->type == MS_LAYER_LINE && shape->type != MS_SHAPE_POLYGON && + shape->type != MS_SHAPE_LINE) { + msSetError(MS_MISCERR, + "Only polygon or line shapes can be drawn using a line layer " + "definition.", + "msDrawShape()"); + return (MS_FAILURE); + } + + if (layer->project && layer->transform == MS_TRUE) { + reprojectionObj *reprojector = msLayerGetReprojectorToMap(layer, map); + if (reprojector == NULL) { + return MS_FAILURE; + } + msProjectShapeEx(reprojector, shape); + } + + /* check if we'll need the unclipped shape */ + if (shape->type != MS_SHAPE_POINT) { + if (MS_DRAW_FEATURES(drawmode)) { + for (s = 0; s < layer->class[c] -> numstyles; s++) { + styleObj *style = layer->class[c]->styles[s]; + if (style->_geomtransform.type != MS_GEOMTRANSFORM_NONE) + bNeedUnclippedShape = MS_TRUE; + } + } + /* check if we need to clip the shape */ + if (shape->bounds.minx < map->extent.minx || + shape->bounds.miny < map->extent.miny || + shape->bounds.maxx > map->extent.maxx || + shape->bounds.maxy > map->extent.maxy) { + bShapeNeedsClipping = MS_TRUE; + } + + if (MS_DRAW_LABELS(drawmode) && MS_DRAW_UNCLIPPED_LABELS(drawmode)) { + bNeedUnclippedAnnoShape = MS_TRUE; + bNeedUnclippedShape = MS_TRUE; + } + + if (MS_DRAW_UNCLIPPED_LINES(drawmode)) { + bShapeNeedsClipping = MS_FALSE; + } + } else { + bShapeNeedsClipping = MS_FALSE; + } + + if (layer->transform == MS_TRUE && bShapeNeedsClipping) { + /* compute the size of the clipping buffer, in pixels. This buffer must + account for the size of symbols drawn to avoid artifacts around the image + edges */ + int clip_buf = 0; + int s; + rectObj cliprect; + for (s = 0; s < layer->class[c] -> numstyles; s++) { + double maxsize, maxunscaledsize; + symbolObj *symbol; + styleObj *style = layer->class[c]->styles[s]; + if (!MS_IS_VALID_ARRAY_INDEX(style->symbol, map->symbolset.numsymbols)) { + msSetError(MS_SYMERR, "Invalid symbol index: %d", "msDrawShape()", + style->symbol); + return MS_FAILURE; + } + symbol = map->symbolset.symbol[style->symbol]; + if (symbol->type == MS_SYMBOL_PIXMAP) { + if (MS_SUCCESS != msPreloadImageSymbol(MS_MAP_RENDERER(map), symbol)) + return MS_FAILURE; + } else if (symbol->type == MS_SYMBOL_SVG) { +#if defined(USE_SVG_CAIRO) || defined(USE_RSVG) + if (MS_SUCCESS != msPreloadSVGSymbol(symbol)) + return MS_FAILURE; +#else + msSetError(MS_SYMERR, "SVG symbol support is not enabled.", + "msDrawShape()"); + return MS_FAILURE; +#endif + } + maxsize = MS_MAX(msSymbolGetDefaultSize(symbol), + MS_MAX(style->size, style->width)); + maxunscaledsize = MS_MAX(style->minsize * image->resolutionfactor, + style->minwidth * image->resolutionfactor); + if (shape->type == MS_SHAPE_POLYGON && + !IS_PARALLEL_OFFSET(style->offsety)) { + maxsize += MS_MAX(fabs(style->offsety), fabs(style->offsetx)); + } + clip_buf = MS_MAX( + clip_buf, + MS_NINT(MS_MAX(maxsize * style->scalefactor, maxunscaledsize) + 1)); + } + + /* if we need a copy of the unclipped shape, transform first, then clip to + * avoid transforming twice */ + if (bNeedUnclippedShape) { + msTransformShape(shape, map->extent, map->cellsize, image); + if (shape->numlines == 0) + return MS_SUCCESS; + msComputeBounds(shape); + + /* TODO: there's an optimization here that can be implemented: + - no need to allocate unclipped_shape for each call to this function + - the calls to msClipXXXRect will discard the original lineObjs, + whereas we have just copied them because they where needed. These two + functions could be changed so they are instructed not to free the + original lineObjs. */ + unclipped_shape = (shapeObj *)msSmallMalloc(sizeof(shapeObj)); + msInitShape(unclipped_shape); + msCopyShape(shape, unclipped_shape); + if (shape->type == MS_SHAPE_POLYGON) { + /* #179: additional buffer for polygons */ + clip_buf += 2; + } + + cliprect.minx = cliprect.miny = -clip_buf; + cliprect.maxx = image->width + clip_buf; + cliprect.maxy = image->height + clip_buf; + if (shape->type == MS_SHAPE_POLYGON) { + msClipPolygonRect(shape, cliprect); + } else { + assert(shape->type == MS_SHAPE_LINE); + msClipPolylineRect(shape, cliprect); + } + if (bNeedUnclippedAnnoShape) { + anno_shape = unclipped_shape; + } else { + anno_shape = shape; + } + } else { + /* clip first, then transform. This means we are clipping in geographical + * space */ + double clip_buf_d; + if (shape->type == MS_SHAPE_POLYGON) { + /* + * add a small buffer around the cliping rectangle to + * avoid lines around the edges : #179 + */ + clip_buf += 2; + } + clip_buf_d = clip_buf * map->cellsize; + cliprect.minx = map->extent.minx - clip_buf_d; + cliprect.miny = map->extent.miny - clip_buf_d; + cliprect.maxx = map->extent.maxx + clip_buf_d; + cliprect.maxy = map->extent.maxy + clip_buf_d; + if (shape->type == MS_SHAPE_POLYGON) { + msClipPolygonRect(shape, cliprect); + } else { + assert(shape->type == MS_SHAPE_LINE); + msClipPolylineRect(shape, cliprect); + } + msTransformShape(shape, map->extent, map->cellsize, image); + msComputeBounds(shape); + anno_shape = shape; + } + + } else { + /* the shape is fully in the map extent, + * or is a point type layer where out of bounds points are treated + * differently*/ + if (layer->transform == MS_TRUE) { + msTransformShape(shape, map->extent, map->cellsize, image); + msComputeBounds(shape); + } else { + msOffsetShapeRelativeTo(shape, layer); + } + anno_shape = shape; + } + if (shape->numlines == 0) { + ret = MS_SUCCESS; /* error message is set in msBindLayerToShape() */ + goto draw_shape_cleanup; + } + + // if we are only drawing a single style then it may have been modified + // outside this function by msOutlineRenderingPrepareStyle and we don't want + // to rebind the style to the layer + if (style != 0) { + if (msBindLayerToShape(layer, shape, drawmode) != MS_SUCCESS) { + ret = MS_FAILURE; /* error message is set in msBindLayerToShape() */ + goto draw_shape_cleanup; + } + } + + switch (layer->type) { + case MS_LAYER_LINE: + msDrawStartShape(map, layer, image, shape); + ret = lineLayerDrawShape(map, image, layer, shape, anno_shape, + unclipped_shape, style, drawmode); + break; + case MS_LAYER_POLYGON: + msDrawStartShape(map, layer, image, shape); + ret = polygonLayerDrawShape(map, image, layer, shape, anno_shape, + unclipped_shape, drawmode); + break; + case MS_LAYER_POINT: + case MS_LAYER_RASTER: + assert(0); // bug ! + default: + msSetError(MS_MISCERR, "Unknown layer type.", "msDrawShape()"); + ret = MS_FAILURE; + } + +draw_shape_cleanup: + msDrawEndShape(map, layer, image, shape); + if (unclipped_shape != shape) { + msFreeShape(unclipped_shape); + msFree(unclipped_shape); + } + return ret; +} + +/* +** Function to render an individual point, used as a helper function for +*mapscript only. Since a point +** can't carry attributes you can't do attribute based font size or angle. +*/ +int msDrawPoint(mapObj *map, layerObj *layer, pointObj *point, imageObj *image, + int classindex, char *labeltext) { + int s, ret; + classObj *theclass = NULL; + labelObj *label = NULL; + + if (layer->transform == MS_TRUE && layer->project && + msProjectionsDiffer(&(layer->projection), &(map->projection))) { + msProjectPoint(&(layer->projection), &(map->projection), point); + } + + if (classindex > layer->numclasses) { + msSetError(MS_MISCERR, "Invalid classindex (%d)", "msDrawPoint()", + classindex); + return MS_FAILURE; + } + theclass = layer->class[classindex]; + + if (labeltext && theclass->numlabels > 0) { + label = theclass->labels[0]; + } + + switch (layer->type) { + case MS_LAYER_POINT: + if (layer->transform == MS_TRUE) { + if (!msPointInRect(point, &map->extent)) + return (0); + point->x = MS_MAP2IMAGE_X(point->x, map->extent.minx, map->cellsize); + point->y = MS_MAP2IMAGE_Y(point->y, map->extent.maxy, map->cellsize); + } else + msOffsetPointRelativeTo(point, layer); + + for (s = 0; s < theclass->numstyles; s++) { + if (msScaleInBounds(map->scaledenom, theclass->styles[s]->minscaledenom, + theclass->styles[s]->maxscaledenom)) + if (MS_UNLIKELY(MS_FAILURE == + msDrawMarkerSymbol(map, image, point, + theclass->styles[s], + theclass->styles[s]->scalefactor))) { + return MS_FAILURE; + } + } + if (label && labeltext && *labeltext) { + textSymbolObj *ts = msSmallMalloc(sizeof(textSymbolObj)); + initTextSymbol(ts); + msPopulateTextSymbolForLabelAndString( + ts, label, msStrdup(labeltext), label->scalefactor, + image->resolutionfactor, layer->labelcache); + if (layer->labelcache) { + if (msAddLabel(map, image, label, layer->index, classindex, NULL, point, + -1, ts) != MS_SUCCESS) { + return (MS_FAILURE); + } + } else { + if (MS_UNLIKELY(MS_FAILURE == msComputeTextPath(map, ts))) { + freeTextSymbol(ts); + free(ts); + return MS_FAILURE; + } + ret = msDrawTextSymbol(map, image, *point, ts); + freeTextSymbol(ts); + free(ts); + if (MS_UNLIKELY(ret == MS_FAILURE)) + return MS_FAILURE; + } + } + break; + default: + break; /* don't do anything with layer of other types */ + } + + return (MS_SUCCESS); /* all done, no cleanup */ +} + +/* +** Draws a single label independently of the label cache. No collision avoidance +*is performed. +*/ +int msDrawLabel(mapObj *map, imageObj *image, pointObj labelPnt, char *string, + labelObj *label, double scalefactor) { + shapeObj labelPoly; + label_bounds lbounds = {0}; + lineObj labelPolyLine; + pointObj labelPolyPoints[5]; + textSymbolObj ts = {0}; + int needLabelPoly = MS_TRUE; + int needLabelPoint = MS_TRUE; + int haveLabelText = MS_TRUE; + + if (!string || !*string) + haveLabelText = MS_FALSE; + + if (haveLabelText) { + initTextSymbol(&ts); + msPopulateTextSymbolForLabelAndString(&ts, label, string, scalefactor, + image->resolutionfactor, 0); + if (MS_UNLIKELY(MS_FAILURE == msComputeTextPath(map, &ts))) { + freeTextSymbol(&ts); + return MS_FAILURE; + } + } + + labelPoly.line = &labelPolyLine; /* setup the label polygon structure */ + labelPoly.numlines = 1; + lbounds.poly = &labelPolyLine; /* setup the label polygon structure */ + labelPoly.line->point = labelPolyPoints; + labelPoly.line->numpoints = 5; + + if (label->position != MS_XY) { + pointObj p = {0}; + + if (label->numstyles > 0) { + int i; + + for (i = 0; i < label->numstyles; i++) { + if (label->styles[i]->_geomtransform.type == + MS_GEOMTRANSFORM_LABELPOINT || + label->styles[i]->_geomtransform.type == MS_GEOMTRANSFORM_NONE) { + if (MS_UNLIKELY(MS_FAILURE == + msDrawMarkerSymbol(map, image, &labelPnt, + label->styles[i], scalefactor))) { + if (haveLabelText) + freeTextSymbol(&ts); + return MS_FAILURE; + } + } else if (haveLabelText && (label->styles[i]->_geomtransform.type == + MS_GEOMTRANSFORM_LABELPOLY || + label->styles[i]->_geomtransform.type == + MS_GEOMTRANSFORM_LABELCENTER)) { + if (needLabelPoly) { + p = get_metrics(&labelPnt, label->position, ts.textpath, + label->offsetx * ts.scalefactor, + label->offsety * ts.scalefactor, ts.rotation, 1, + &lbounds); + if (!lbounds.poly) { + /* we need the full shape to draw the label background */ + labelPolyPoints[0].x = labelPolyPoints[4].x = lbounds.bbox.minx; + labelPolyPoints[0].y = labelPolyPoints[4].y = lbounds.bbox.miny; + labelPolyPoints[1].x = lbounds.bbox.minx; + labelPolyPoints[1].y = lbounds.bbox.maxy; + labelPolyPoints[2].x = lbounds.bbox.maxx; + labelPolyPoints[2].y = lbounds.bbox.maxy; + labelPolyPoints[3].x = lbounds.bbox.maxx; + labelPolyPoints[3].y = lbounds.bbox.miny; + } + needLabelPoint = MS_FALSE; /* don't re-compute */ + needLabelPoly = MS_FALSE; + } + if (label->styles[i]->_geomtransform.type == + MS_GEOMTRANSFORM_LABELPOLY) { + if (MS_UNLIKELY(MS_FAILURE == msDrawShadeSymbol(map, image, + &labelPoly, + label->styles[i], + ts.scalefactor))) { + freeTextSymbol(&ts); + return MS_FAILURE; + } + } else { + pointObj labelCenter; + labelCenter.x = (lbounds.bbox.maxx + lbounds.bbox.minx) / 2; + labelCenter.y = (lbounds.bbox.maxy + lbounds.bbox.miny) / 2; + if (MS_UNLIKELY(MS_FAILURE == msDrawMarkerSymbol( + map, image, &labelCenter, + label->styles[i], scalefactor))) { + freeTextSymbol(&ts); + return MS_FAILURE; + } + } + } else { + msSetError(MS_MISCERR, "Unknown label geomtransform %s", + "msDrawLabel()", label->styles[i]->_geomtransform.string); + if (haveLabelText) + freeTextSymbol(&ts); + return MS_FAILURE; + } + } + } + + if (haveLabelText) { + if (needLabelPoint) + p = get_metrics(&labelPnt, label->position, ts.textpath, + label->offsetx * ts.scalefactor, + label->offsety * ts.scalefactor, ts.rotation, 0, + &lbounds); + + /* draw the label text */ + if (MS_UNLIKELY(MS_FAILURE == msDrawTextSymbol(map, image, p, &ts))) { + freeTextSymbol(&ts); + return MS_FAILURE; + } + } + } else { + labelPnt.x += label->offsetx * ts.scalefactor; + labelPnt.y += label->offsety * ts.scalefactor; + + if (label->numstyles > 0) { + int i; + + for (i = 0; i < label->numstyles; i++) { + if (label->styles[i]->_geomtransform.type == + MS_GEOMTRANSFORM_LABELPOINT || + label->styles[i]->_geomtransform.type == MS_GEOMTRANSFORM_NONE) { + if (MS_UNLIKELY(MS_FAILURE == + msDrawMarkerSymbol(map, image, &labelPnt, + label->styles[i], scalefactor))) { + freeTextSymbol(&ts); + return MS_FAILURE; + } + } else if (haveLabelText && (label->styles[i]->_geomtransform.type == + MS_GEOMTRANSFORM_LABELPOLY || + label->styles[i]->_geomtransform.type == + MS_GEOMTRANSFORM_LABELCENTER)) { + if (needLabelPoly) { + get_metrics(&labelPnt, label->position, ts.textpath, + label->offsetx * ts.scalefactor, + label->offsety * ts.scalefactor, ts.rotation, 1, + &lbounds); + needLabelPoly = MS_FALSE; /* don't re-compute */ + if (!lbounds.poly) { + /* we need the full shape to draw the label background */ + labelPolyPoints[0].x = labelPolyPoints[4].x = lbounds.bbox.minx; + labelPolyPoints[0].y = labelPolyPoints[4].y = lbounds.bbox.miny; + labelPolyPoints[1].x = lbounds.bbox.minx; + labelPolyPoints[1].y = lbounds.bbox.maxy; + labelPolyPoints[2].x = lbounds.bbox.maxx; + labelPolyPoints[2].y = lbounds.bbox.maxy; + labelPolyPoints[3].x = lbounds.bbox.maxx; + labelPolyPoints[3].y = lbounds.bbox.miny; + } + } + if (label->styles[i]->_geomtransform.type == + MS_GEOMTRANSFORM_LABELPOLY) { + if (MS_UNLIKELY(MS_FAILURE == + msDrawShadeSymbol(map, image, &labelPoly, + label->styles[i], scalefactor))) { + freeTextSymbol(&ts); + return MS_FAILURE; + } + } else { + pointObj labelCenter; + labelCenter.x = (lbounds.bbox.maxx + lbounds.bbox.minx) / 2; + labelCenter.y = (lbounds.bbox.maxy + lbounds.bbox.miny) / 2; + if (MS_UNLIKELY(MS_FAILURE == msDrawMarkerSymbol( + map, image, &labelCenter, + label->styles[i], scalefactor))) { + freeTextSymbol(&ts); + return MS_FAILURE; + } + } + } else { + msSetError(MS_MISCERR, "Unknown label geomtransform %s", + "msDrawLabel()", label->styles[i]->_geomtransform.string); + if (haveLabelText) + freeTextSymbol(&ts); + return MS_FAILURE; + } + } + } + + if (haveLabelText) { + /* draw the label text */ + if (MS_UNLIKELY(MS_FAILURE == + msDrawTextSymbol(map, image, labelPnt, &ts))) { + freeTextSymbol(&ts); + return MS_FAILURE; + } + } + } + if (haveLabelText) + freeTextSymbol(&ts); + + return MS_SUCCESS; +} + +static inline void offset_bbox(const rectObj *from, rectObj *to, double ox, + double oy) { + to->minx = from->minx + ox; + to->miny = from->miny + oy; + to->maxx = from->maxx + ox; + to->maxy = from->maxy + oy; +} + +static inline void offset_label_bounds(const label_bounds *from, + label_bounds *to, double ox, double oy) { + if (from->poly) { + int i; + for (i = 0; i < from->poly->numpoints; i++) { + to->poly->point[i].x = from->poly->point[i].x + ox; + to->poly->point[i].y = from->poly->point[i].y + oy; + } + to->poly->numpoints = from->poly->numpoints; + } else { + to->poly = NULL; + } + offset_bbox(&from->bbox, &to->bbox, ox, oy); +} + +/* private shortcut function to try a leader offsetted label + * the caller must ensure that scratch->poly->points has been sufficiently + * allocated to hold the points from the cachePtr's label_bounds */ +void offsetAndTest(mapObj *map, labelCacheMemberObj *cachePtr, double ox, + double oy, int priority, int label_idx, + label_bounds *scratch) { + int i, j, status; + pointObj leaderpt; + lineObj *scratch_line = scratch->poly; + + for (i = 0; i < cachePtr->numtextsymbols; i++) { + textSymbolObj *ts = cachePtr->textsymbols[i]; + if (ts->textpath) { + offset_label_bounds(&ts->textpath->bounds, scratch, ox, oy); + status = msTestLabelCacheCollisions(map, cachePtr, scratch, priority, + label_idx); + if (!status) { + return; + } + } + for (j = 0; j < ts->label->numstyles; j++) { + if (ts->label->styles[j]->_geomtransform.type == + MS_GEOMTRANSFORM_LABELPOINT) { + scratch->poly = scratch_line; + offset_label_bounds(ts->style_bounds[j], scratch, ox, oy); + status = msTestLabelCacheCollisions(map, cachePtr, scratch, priority, + label_idx); + if (!status) { + return; + } + } + } + } + + leaderpt.x = cachePtr->point.x + ox; + leaderpt.y = cachePtr->point.y + oy; + leaderpt.z = 0; + leaderpt.m = 0; + + status = msTestLabelCacheLeaderCollision(map, &cachePtr->point, &leaderpt); + if (!status) { + return; + } + + /* the current offset is ok */ + cachePtr->leaderbbox = msSmallMalloc(sizeof(rectObj)); + cachePtr->leaderline = msSmallMalloc(sizeof(lineObj)); + cachePtr->leaderline->point = msSmallMalloc(2 * sizeof(pointObj)); + cachePtr->leaderline->numpoints = 2; + cachePtr->leaderline->point[0] = cachePtr->point; + cachePtr->leaderline->point[1] = leaderpt; + cachePtr->leaderbbox->minx = MS_MIN(leaderpt.x, cachePtr->point.x); + cachePtr->leaderbbox->maxx = MS_MAX(leaderpt.x, cachePtr->point.x); + cachePtr->leaderbbox->miny = MS_MIN(leaderpt.y, cachePtr->point.y); + cachePtr->leaderbbox->maxy = MS_MAX(leaderpt.y, cachePtr->point.y); + cachePtr->status = MS_ON; + + offset_bbox(&cachePtr->bbox, &cachePtr->bbox, ox, oy); + + for (i = 0; i < cachePtr->numtextsymbols; i++) { + textSymbolObj *ts = cachePtr->textsymbols[i]; + if (ts->textpath) { + offset_label_bounds(&ts->textpath->bounds, &ts->textpath->bounds, ox, oy); + ts->annopoint.x += ox; + ts->annopoint.y += oy; + } + if (ts->style_bounds) { + for (j = 0; j < ts->label->numstyles; j++) { + if (ts->label->styles[j]->_geomtransform.type != MS_GEOMTRANSFORM_NONE) + offset_label_bounds(ts->style_bounds[j], ts->style_bounds[j], ox, oy); + } + } + } +} + +int msDrawOffsettedLabels(imageObj *image, mapObj *map, int priority) { + int retval = MS_SUCCESS; + int l; + labelCacheObj *labelcache = &(map->labelcache); + labelCacheSlotObj *cacheslot; + labelCacheMemberObj *cachePtr; + label_bounds scratch; + lineObj scratch_line; + pointObj *scratch_points = NULL; + int num_allocated_scratch_points = 0; + assert(MS_RENDERER_PLUGIN(image->format)); + cacheslot = &(labelcache->slots[priority]); + scratch.poly = &scratch_line; + + for (l = cacheslot->numlabels - 1; l >= 0; l--) { + cachePtr = + &(cacheslot->labels[l]); /* point to right spot in the label cache */ + if (cachePtr->status == MS_OFF) { + /* only test regular labels that have had their bounding box computed + and that haven't been rendered */ + classObj *classPtr = + (GET_CLASS(map, cachePtr->layerindex, cachePtr->classindex)); + layerObj *layerPtr = (GET_LAYER(map, cachePtr->layerindex)); + int steps, i, num_scratch_points_to_allocate = 0; + + assert(classPtr->leader); /* cachePtrs that don't need to be tested have + been marked as status on or delete */ + + if (cachePtr->point.x < labelcache->gutter || + cachePtr->point.y < labelcache->gutter || + cachePtr->point.x >= image->width - labelcache->gutter || + cachePtr->point.y >= image->height - labelcache->gutter) { + /* don't look for leaders if point is in edge buffer as the leader line + * would end up chopped off */ + continue; + } + + for (i = 0; i < cachePtr->numtextsymbols; i++) { + int j; + textSymbolObj *ts = cachePtr->textsymbols[i]; + if (ts->textpath && ts->textpath->bounds.poly) { + num_scratch_points_to_allocate = + MS_MAX(num_scratch_points_to_allocate, + ts->textpath->bounds.poly->numpoints); + } + if (ts->style_bounds) { + for (j = 0; j < ts->label->numstyles; j++) { + if (ts->label->styles[j]->_geomtransform.type == + MS_GEOMTRANSFORM_LABELPOINT && + ts->style_bounds[j]->poly) { + num_scratch_points_to_allocate = + MS_MAX(num_scratch_points_to_allocate, + ts->style_bounds[j]->poly->numpoints); + } + } + } + } + if (num_scratch_points_to_allocate > num_allocated_scratch_points) { + scratch_points = msSmallRealloc( + scratch_points, num_scratch_points_to_allocate * sizeof(pointObj)); + num_allocated_scratch_points = num_scratch_points_to_allocate; + } + + steps = classPtr->leader->maxdistance / classPtr->leader->gridstep; + +#define x0 (cachePtr->point.x) +#define y0 (cachePtr->point.y) +#define gridstepsc (classPtr->leader->gridstep) + +#define otest(ox, oy) \ + if ((x0 + (ox)) >= labelcache->gutter && \ + (y0 + (oy)) >= labelcache->gutter && \ + (x0 + (ox)) < image->width - labelcache->gutter && \ + (y0 + (oy)) < image->height - labelcache->gutter) { \ + scratch_line.point = scratch_points; \ + scratch.poly = &scratch_line; \ + offsetAndTest(map, cachePtr, (ox), (oy), priority, l, &scratch); \ + if (cachePtr->status == MS_ON) \ + break; \ + } + + /* loop through possible offsetted positions */ + for (i = 1; i <= steps; i++) { + + /* test the intermediate points on the ring */ + + /* (points marked "0" are the ones being tested) + + X00X00X + 0XXXXX0 + 0XXXXX0 + XXX.XXX + 0XXXXX0 + 0XXXXX0 + X00X00X + */ + int j; + for (j = 1; j < i - 1; j++) { + /* test the right positions */ + otest(i * gridstepsc, j * gridstepsc); + otest(i * gridstepsc, -j * gridstepsc); + /* test the left positions */ + otest(-i * gridstepsc, j * gridstepsc); + otest(-i * gridstepsc, -j * gridstepsc); + /* test the top positions */ + otest(j * gridstepsc, -i * gridstepsc); + otest(-j * gridstepsc, -i * gridstepsc); + /* test the bottom positions */ + otest(j * gridstepsc, i * gridstepsc); + otest(-j * gridstepsc, i * gridstepsc); + } + if (j < (i - 1)) + break; + + otest(i * gridstepsc, i * gridstepsc); + otest(-i * gridstepsc, -i * gridstepsc); + otest(i * gridstepsc, -i * gridstepsc); + otest(-i * gridstepsc, i * gridstepsc); + + /* test the intermediate points on the ring */ + + /* (points marked "0" are the ones being tested) + + X00X00X + 0XXXXX0 + 0XXXXX0 + XXX.XXX + 0XXXXX0 + 0XXXXX0 + X00X00X + + */ + + /* test the extreme diagonal points */ + + /* (points marked "0" are the ones being tested) + + 0XXXXX0 + XXXXXXX + XXXXXXX + XXX.XXX + XXXXXXX + XXXXXXX + 0XXXXX0 + + (x0+i*gridstep, y0+i*gridstep), pos lr + (x0-i*gridstep, y0-i*gridstep), pos ul + (x0+i*gridstep, y0-i*gridstep), pos ur + (x0-i*gridstep, y0+i*gridstep), pos ll + + */ + + /* test the 4 cardinal points on the ring */ + + /* (points marked "0" are the ones being tested) + + XXX0XXX + XXXXXXX + XXXXXXX + 0XX.XX0 + XXXXXXX + XXXXXXX + XXX0XXX + + * (x0+i*gridtep,y0), pos cr + + * (x0-i*gridstep,y0), pos cl + * (x0,y0-i*gridstep), pos uc + * (x0,y0+i*gridstep), pos lc + */ + otest(i * gridstepsc, 0); + otest(-i * gridstepsc, 0); + otest(0, -i * gridstepsc); + otest(0, i * gridstepsc); + } + if (cachePtr->status == MS_ON) { + int ll; + shapeObj + labelLeader; /* label polygon (bounding box, possibly rotated) */ + labelLeader.line = + cachePtr->leaderline; /* setup the label polygon structure */ + labelLeader.numlines = 1; + insertRenderedLabelMember(map, cachePtr); + + for (ll = 0; ll < classPtr->leader->numstyles; ll++) { + retval = msDrawLineSymbol(map, image, &labelLeader, + classPtr->leader->styles[ll], + layerPtr->scalefactor); + if (MS_UNLIKELY(retval == MS_FAILURE)) { + goto offset_cleanup; + } + } + for (ll = 0; ll < cachePtr->numtextsymbols; ll++) { + textSymbolObj *ts = cachePtr->textsymbols[ll]; + + if (ts->style_bounds) { + /* here's where we draw the label styles */ + for (i = 0; i < ts->label->numstyles; i++) { + if (ts->label->styles[i]->_geomtransform.type == + MS_GEOMTRANSFORM_LABELPOINT) { + retval = msDrawMarkerSymbol( + map, image, &(labelLeader.line->point[1]), + ts->label->styles[i], layerPtr->scalefactor); + if (MS_UNLIKELY(retval == MS_FAILURE)) { + goto offset_cleanup; + } + } else if (ts->label->styles[i]->_geomtransform.type == + MS_GEOMTRANSFORM_LABELPOLY) { + retval = + msDrawLabelBounds(map, image, ts->style_bounds[i], + ts->label->styles[i], ts->scalefactor); + if (MS_UNLIKELY(retval == MS_FAILURE)) { + goto offset_cleanup; + } + } else if (ts->label->styles[i]->_geomtransform.type == + MS_GEOMTRANSFORM_LABELCENTER) { + pointObj labelCenter; + labelCenter.x = (ts->style_bounds[i]->bbox.maxx + + ts->style_bounds[i]->bbox.minx) / + 2; + labelCenter.y = (ts->style_bounds[i]->bbox.maxy + + ts->style_bounds[i]->bbox.miny) / + 2; + retval = msDrawMarkerSymbol(map, image, &labelCenter, + ts->label->styles[i], + layerPtr->scalefactor); + if (MS_UNLIKELY(retval == MS_FAILURE)) { + goto offset_cleanup; + } + } else { + msSetError(MS_MISCERR, + "Labels only support LABELPNT, LABELPOLY and " + "LABELCENTER GEOMTRANSFORMS", + "msDrawOffsettedLabels()"); + retval = MS_FAILURE; + } + } + } + if (ts->annotext) { + retval = msDrawTextSymbol(map, image, ts->annopoint, ts); + if (MS_UNLIKELY(retval == MS_FAILURE)) { + goto offset_cleanup; + } + } + } + /* TODO: draw cachePtr->marker, but where ? */ + + /* + styleObj tstyle; + static int foo =0; + if(!foo) { + srand(time(NULL)); + foo = 1; + initStyle(&tstyle); + tstyle.width = 1; + tstyle.color.alpha = 255; + } + tstyle.color.red = random()%255; + tstyle.color.green = random()%255; + tstyle.color.blue =random()%255; + msDrawLineSymbol(&map->symbolset, image, cachePtr->poly, &tstyle, + layerPtr->scalefactor); + */ + } + } + } + +offset_cleanup: + + free(scratch_points); + + return retval; +} + +void fastComputeBounds(lineObj *line, rectObj *bounds) { + int j; + bounds->minx = bounds->maxx = line->point[0].x; + bounds->miny = bounds->maxy = line->point[0].y; + + for (j = 0; j < line->numpoints; j++) { + bounds->minx = MS_MIN(bounds->minx, line->point[j].x); + bounds->maxx = MS_MAX(bounds->maxx, line->point[j].x); + bounds->miny = MS_MIN(bounds->miny, line->point[j].y); + bounds->maxy = MS_MAX(bounds->maxy, line->point[j].y); + } +} + +int computeMarkerBounds(mapObj *map, pointObj *annopoint, textSymbolObj *ts, + label_bounds *poly) { + int i; + for (i = 0; i < ts->label->numstyles; i++) { + styleObj *style = ts->label->styles[i]; + if (style->_geomtransform.type == MS_GEOMTRANSFORM_LABELPOINT && + style->symbol < map->symbolset.numsymbols && style->symbol >= 0) { + double sx, sy; + int p; + double aox, aoy; + symbolObj *symbol = map->symbolset.symbol[style->symbol]; + if (msGetMarkerSize(map, style, &sx, &sy, ts->scalefactor) != MS_SUCCESS) + return -1; /* real error, different from MS_FALSE, return -1 so we can + trap it */ + if (style->angle) { + pointObj *point = poly->poly->point; + point[0].x = sx / 2.0; + point[0].y = sy / 2.0; + point[1].x = point[0].x; + point[1].y = -point[0].y; + point[2].x = -point[0].x; + point[2].y = -point[0].y; + point[3].x = -point[0].x; + point[3].y = point[0].y; + point[4].x = point[0].x; + point[4].y = point[0].y; + if (symbol->anchorpoint_x != 0.5 || symbol->anchorpoint_y != 0.5) { + aox = (0.5 - symbol->anchorpoint_x) * sx; + aoy = (0.5 - symbol->anchorpoint_y) * sy; + for (p = 0; p < 5; p++) { + point[p].x += aox; + point[p].y += aoy; + } + } + { + double rot = -style->angle * MS_DEG_TO_RAD; + double sina = sin(rot); + double cosa = cos(rot); + for (p = 0; p < 5; p++) { + double tmpx = point[p].x; + point[p].x = point[p].x * cosa - point[p].y * sina; + point[p].y = tmpx * sina + point[p].y * cosa; + } + } + aox = annopoint->x + style->offsetx * ts->scalefactor; + aoy = annopoint->y + style->offsety * ts->scalefactor; + for (p = 0; p < 5; p++) { + point[p].x += aox; + point[p].y += aoy; + } + fastComputeBounds(poly->poly, &poly->bbox); + } else { + double aox = (0.5 - symbol->anchorpoint_x) * sx + annopoint->x + + style->offsetx * ts->scalefactor; + double aoy = (0.5 - symbol->anchorpoint_y) * sy + annopoint->y + + style->offsety * ts->scalefactor; + poly->poly = NULL; + poly->bbox.maxx = sx / 2.0 + aox; + poly->bbox.minx = -sx / 2.0 + aox; + poly->bbox.maxy = sy / 2.0 + aoy; + poly->bbox.miny = -sy / 2.0 + aoy; + } + break; + } + } + if (i == ts->label->numstyles) + return MS_FALSE; /* the label has no marker styles */ + else + return MS_TRUE; +} + +/* check that the current entry does not fall close to a label with identical + * text, if configured so. Currently only checks the first label/text */ + +int msCheckLabelMinDistance(mapObj *map, labelCacheMemberObj *lc) { + int i; + textSymbolObj *s; /* shortcut */ + textSymbolObj *ts; + rectObj buffered; + if (lc->numtextsymbols == 0) + return MS_FALSE; /* no label with text */ + s = lc->textsymbols[0]; + + if (!s->annotext || s->label->mindistance <= 0.0 || + s->label->force == MS_TRUE) + return MS_FALSE; /* min distance is not checked */ + + /* we buffer the label and check for intersection instead of calculating + the distance of two textpaths. we also buffer only the bbox of lc for + faster computation (it is still compared to the full textpath + of the label cache members). + */ + buffered = lc->bbox; + buffered.minx -= s->label->mindistance * s->resolutionfactor; + buffered.miny -= s->label->mindistance * s->resolutionfactor; + buffered.maxx += s->label->mindistance * s->resolutionfactor; + buffered.maxy += s->label->mindistance * s->resolutionfactor; + + for (i = 0; i < map->labelcache.num_rendered_members; i++) { + labelCacheMemberObj *ilc = map->labelcache.rendered_text_symbols[i]; + if (ilc->numtextsymbols == 0 || !ilc->textsymbols[0]->annotext) + continue; + + ts = ilc->textsymbols[0]; + if (strcmp(s->annotext, ts->annotext) != 0) { + /* only check min distance against same label */ + continue; + } + + if (msPointInRect(&ilc->point, &buffered) == MS_TRUE) { + return MS_TRUE; + } + + if (ts->textpath && ts->textpath->absolute) { + if (intersectLabelPolygons(ts->textpath->bounds.poly, &ilc->bbox, NULL, + &buffered) == MS_TRUE) { + return MS_TRUE; + } + continue; + } + + if (intersectLabelPolygons(NULL, &ilc->bbox, NULL, &buffered) == MS_TRUE) { + return MS_TRUE; + } + } + return MS_FALSE; +} + +void copyLabelBounds(label_bounds *dst, label_bounds *src) { + *dst = *src; + if (src->poly) { + int i; + dst->poly = msSmallMalloc(sizeof(lineObj)); + dst->poly->numpoints = src->poly->numpoints; + dst->poly->point = msSmallMalloc(dst->poly->numpoints * sizeof(pointObj)); + for (i = 0; i < dst->poly->numpoints; i++) { + dst->poly->point[i] = src->poly->point[i]; + } + } +} + +static int getLabelPositionFromString(char *pszString) { + if (strcasecmp(pszString, "UL") == 0) + return MS_UL; + else if (strcasecmp(pszString, "LR") == 0) + return MS_LR; + else if (strcasecmp(pszString, "UR") == 0) + return MS_UR; + else if (strcasecmp(pszString, "LL") == 0) + return MS_LL; + else if (strcasecmp(pszString, "CR") == 0) + return MS_CR; + else if (strcasecmp(pszString, "CL") == 0) + return MS_CL; + else if (strcasecmp(pszString, "UC") == 0) + return MS_UC; + else if (strcasecmp(pszString, "LC") == 0) + return MS_LC; + else + return MS_CC; +} + +int msDrawLabelCache(mapObj *map, imageObj *image) { + int nReturnVal = MS_SUCCESS; + struct mstimeval starttime = {0}, endtime = {0}; + + if (map->debug >= MS_DEBUGLEVEL_TUNING) + msGettimeofday(&starttime, NULL); + + if (image) { + if (MS_RENDERER_PLUGIN(image->format)) { + int i, l, ll, priority, its; + + double marker_offset_x, marker_offset_y; + int label_offset_x, label_offset_y; + const char *value; + + labelCacheMemberObj *cachePtr = NULL; + layerObj *layerPtr = NULL; + classObj *classPtr = NULL; + textSymbolObj *textSymbolPtr = NULL; + + /* + * some statically allocated containers for storing label bounds before + * copying them into the cachePtr: we avoid allocating these structures + * at runtime, except for the labels that are actually rendered. + */ + lineObj labelpoly_line; + pointObj labelpoly_points[5]; + label_bounds labelpoly_bounds = {0}; + lineObj label_marker_line; + pointObj label_marker_points[5]; + label_bounds label_marker_bounds; + lineObj metrics_line; + pointObj metrics_points[5]; + label_bounds metrics_bounds; + + label_marker_line.point = label_marker_points; + label_marker_line.numpoints = 5; + metrics_line.point = metrics_points; + metrics_line.numpoints = 5; + labelpoly_line.point = labelpoly_points; + labelpoly_line.numpoints = 5; + + /* Look for labelcache_map_edge_buffer map metadata + * If set then the value defines a buffer (in pixels) along the edge of + * the map image where labels can't fall + */ + if ((value = msLookupHashTable(&(map->web.metadata), + "labelcache_map_edge_buffer")) != NULL) { + map->labelcache.gutter = MS_ABS(atoi(value)); + if (map->debug) + msDebug("msDrawLabelCache(): labelcache_map_edge_buffer = %d\n", + map->labelcache.gutter); + } + + for (priority = MS_MAX_LABEL_PRIORITY - 1; priority >= 0; priority--) { + labelCacheSlotObj *cacheslot; + cacheslot = &(map->labelcache.slots[priority]); + + for (l = cacheslot->numlabels - 1; l >= 0; l--) { + cachePtr = + &(cacheslot + ->labels[l]); /* point to right spot in the label cache */ + + layerPtr = (GET_LAYER( + map, cachePtr->layerindex)); /* set a couple of other pointers, + avoids nasty references */ + classPtr = + (GET_CLASS(map, cachePtr->layerindex, cachePtr->classindex)); + + if (cachePtr->textsymbols[0]->textpath && + cachePtr->textsymbols[0]->textpath->absolute) { + /* we have an angle follow label */ + cachePtr->bbox = cachePtr->textsymbols[0]->textpath->bounds.bbox; + + /* before going any further, check that mindistance is respected */ + if (cachePtr->numtextsymbols && + cachePtr->textsymbols[0]->label->mindistance > 0.0 && + cachePtr->textsymbols[0]->annotext) { + if (msCheckLabelMinDistance(map, cachePtr) == MS_TRUE) { + cachePtr->status = MS_DELETE; + MS_DEBUG(MS_DEBUGLEVEL_DEVDEBUG, map, + "Skipping labelgroup %d \"%s\" in layer \"%s\": too " + "close to an identical label (mindistance)\n", + l, cachePtr->textsymbols[0]->annotext, layerPtr->name); + continue; /* move on to next entry, this one is too close to an + already placed one */ + } + } + + if (!cachePtr->textsymbols[0]->label->force) + cachePtr->status = msTestLabelCacheCollisions( + map, cachePtr, &cachePtr->textsymbols[0]->textpath->bounds, + priority, l); + else + cachePtr->status = MS_ON; + if (cachePtr->status) { + + if (MS_UNLIKELY( + MS_FAILURE == + msDrawTextSymbol( + map, image, + cachePtr->textsymbols[0]->annopoint /*not used*/, + cachePtr->textsymbols[0]))) { + return MS_FAILURE; + } + insertRenderedLabelMember(map, cachePtr); + } else { + MS_DEBUG(MS_DEBUGLEVEL_DEVDEBUG, map, + "Skipping follow labelgroup %d \"%s\" in layer \"%s\": " + "text collided\n", + l, cachePtr->textsymbols[0]->annotext, layerPtr->name); + } + cachePtr->status = + MS_DELETE; /* we're done with this label, it won't even have a + second chance in the leader phase */ + } else { + marker_offset_x = marker_offset_y = 0; /* assume no marker */ + + if (layerPtr->type == MS_LAYER_POINT && + cachePtr->markerid != + -1) { /* there is a marker already in the image that we need + to account for */ + markerCacheMemberObj *markerPtr = &( + cacheslot + ->markers[cachePtr->markerid]); /* point to the right spot + in the marker cache*/ + marker_offset_x = + (markerPtr->bounds.maxx - markerPtr->bounds.minx) / 2.0; + marker_offset_y = + (markerPtr->bounds.maxy - markerPtr->bounds.miny) / 2.0; + } + + /* + ** all other cases *could* have multiple labels defined + */ + cachePtr->status = + MS_ON; /* assume this cache element can be placed */ + for (ll = 0; ll < cachePtr->numtextsymbols; + ll++) { /* RFC 77 TODO: Still may want to step through + backwards... */ + int label_marker_status = MS_ON, have_label_marker, + metrics_status = MS_ON; + int need_labelpoly = 0; + + /* reset the lineObj which may have been unset by a previous call + * to get_metrics() */ + label_marker_bounds.poly = &label_marker_line; + labelpoly_bounds.poly = &labelpoly_line; + + textSymbolPtr = cachePtr->textsymbols[ll]; + for (i = 0; i < textSymbolPtr->label->numstyles; i++) { + if (textSymbolPtr->label->styles[i]->_geomtransform.type == + MS_GEOMTRANSFORM_LABELPOLY || + textSymbolPtr->label->styles[i]->_geomtransform.type == + MS_GEOMTRANSFORM_LABELCENTER) { + need_labelpoly = 1; + break; + } + } + + /* compute the poly of the label styles */ + if ((have_label_marker = + computeMarkerBounds(map, &cachePtr->point, textSymbolPtr, + &label_marker_bounds)) == MS_TRUE) { + if (cachePtr->numtextsymbols > + 1) { /* FIXME this test doesn't seem right, should probably + check if we have an annotation layer with a regular + style defined */ + marker_offset_x = (label_marker_bounds.bbox.maxx - + label_marker_bounds.bbox.minx) / + 2.0; + marker_offset_y = (label_marker_bounds.bbox.maxy - + label_marker_bounds.bbox.miny) / + 2.0; + } else { + /* we might be using an old style behavior with a markerPtr */ + marker_offset_x = + MS_MAX(marker_offset_x, (label_marker_bounds.bbox.maxx - + label_marker_bounds.bbox.minx) / + 2.0); + marker_offset_y = + MS_MAX(marker_offset_y, (label_marker_bounds.bbox.maxy - + label_marker_bounds.bbox.miny) / + 2.0); + } + /* add marker to cachePtr->poly */ + if (textSymbolPtr->label->force != MS_TRUE) { + label_marker_status = msTestLabelCacheCollisions( + map, cachePtr, &label_marker_bounds, priority, l); + } + if (label_marker_status == MS_OFF && + !(textSymbolPtr->label->force == MS_ON || + classPtr->leader)) { + cachePtr->status = MS_DELETE; + MS_DEBUG(MS_DEBUGLEVEL_DEVDEBUG, map, + "Skipping label %d of labelgroup %d of class %d in " + "layer \"%s\": marker collided\n", + ll, l, cachePtr->classindex, layerPtr->name); + break; /* the marker collided, break from multi-label loop */ + } + } + if (have_label_marker == -1) + return MS_FAILURE; /* error occurred (symbol not found, etc...) + */ + + if (textSymbolPtr->annotext) { + /* + * if we don't have an offset defined, first check that the + * labelpoint itself does not collide this helps speed things up + * in dense labeling, as if the labelpoint collides there's no + * use in computing the labeltext bounds (i.e. going into + * shaping+freetype). We do however skip collision testing + * against the marker cache, as we want to allow rendering a + * label for points that overlap each other: this is done by + * setting priority to MAX_PRIORITY in the call to + * msTestLabelCacheCollisions (which is a hack!!) + */ + if (!have_label_marker && + textSymbolPtr->label->force != MS_TRUE && + !classPtr->leader && !textSymbolPtr->label->offsetx && + !textSymbolPtr->label->offsety) { + label_bounds labelpoint_bounds; + labelpoint_bounds.poly = NULL; + labelpoint_bounds.bbox.minx = cachePtr->point.x - 0.1; + labelpoint_bounds.bbox.maxx = cachePtr->point.x + 0.1; + labelpoint_bounds.bbox.miny = cachePtr->point.y - 0.1; + labelpoint_bounds.bbox.maxy = cachePtr->point.y + 0.1; + if (MS_OFF == msTestLabelCacheCollisions( + map, cachePtr, &labelpoint_bounds, + MS_MAX_LABEL_PRIORITY, l)) { + cachePtr->status = + MS_DELETE; /* we won't check for leader offsetted + positions, as the anchor point colided */ + MS_DEBUG(MS_DEBUGLEVEL_DEVDEBUG, map, + "Skipping label %d \"%s\" of labelgroup %d of " + "class %d in layer \"%s\": labelpoint collided\n", + ll, textSymbolPtr->annotext, l, + cachePtr->classindex, layerPtr->name); + break; + } + } + + /* compute label size */ + if (!textSymbolPtr->textpath) { + if (MS_UNLIKELY(MS_FAILURE == + msComputeTextPath(map, textSymbolPtr))) { + return MS_FAILURE; + } + } + + /* if our label has an outline, adjust the marker offset so the + * outlinecolor does not bleed into the marker */ + if (marker_offset_x && + MS_VALID_COLOR(textSymbolPtr->label->outlinecolor)) { + marker_offset_x += textSymbolPtr->label->outlinewidth / 2.0 * + textSymbolPtr->scalefactor; + marker_offset_y += textSymbolPtr->label->outlinewidth / 2.0 * + textSymbolPtr->scalefactor; + } + + /* apply offset and buffer settings */ + if (textSymbolPtr->label->anglemode != MS_FOLLOW) { + label_offset_x = textSymbolPtr->label->offsetx * + textSymbolPtr->scalefactor; + label_offset_y = textSymbolPtr->label->offsety * + textSymbolPtr->scalefactor; + } else { + label_offset_x = 0; + label_offset_y = 0; + } + + if (textSymbolPtr->label->position == MS_AUTO) { + /* no point in using auto positioning if the marker cannot be + * placed */ + int positions[MS_POSITIONS_LENGTH], npositions = 0; + + /* + ** (Note: might be able to re-order this for more speed.) + */ + if (msLayerGetProcessingKey(layerPtr, "LABEL_POSITIONS")) { + int p, ncustom_positions = 0; + char **custom_positions = msStringSplitComplex( + msLayerGetProcessingKey(layerPtr, "LABEL_POSITIONS"), + ",", &ncustom_positions, + MS_STRIPLEADSPACES | MS_STRIPENDSPACES); + for (p = 0; p < MS_MIN(9, ncustom_positions); p++) + positions[p] = + getLabelPositionFromString(custom_positions[p]); + npositions = p; + msFree(custom_positions); + } else if (layerPtr->type == MS_LAYER_POLYGON && + marker_offset_x == 0) { + positions[0] = MS_CC; + positions[1] = MS_UC; + positions[2] = MS_LC; + positions[3] = MS_CL; + positions[4] = MS_CR; + npositions = 5; + } else if (layerPtr->type == MS_LAYER_LINE && + marker_offset_x == 0) { + positions[0] = MS_UC; + positions[1] = MS_LC; + positions[2] = MS_CC; + npositions = 3; + } else { + positions[0] = MS_UL; + positions[1] = MS_LR; + positions[2] = MS_UR; + positions[3] = MS_LL; + positions[4] = MS_CR; + positions[5] = MS_CL; + positions[6] = MS_UC; + positions[7] = MS_LC; + npositions = 8; + } + + for (i = 0; i < npositions; i++) { + // RFC 77 TODO: take label_marker_offset_x/y into account + metrics_bounds.poly = &metrics_line; + textSymbolPtr->annopoint = + get_metrics(&(cachePtr->point), positions[i], + textSymbolPtr->textpath, + marker_offset_x + label_offset_x, + marker_offset_y + label_offset_y, + textSymbolPtr->rotation, + textSymbolPtr->label->buffer * + textSymbolPtr->scalefactor, + &metrics_bounds); + if (textSymbolPtr->label->force == MS_OFF) { + for (its = 0; its < ll; its++) { + /* check for collisions inside the label group */ + if (intersectTextSymbol(cachePtr->textsymbols[its], + &metrics_bounds) == MS_TRUE) { + /* there was a self intersection */ + break; /* next position, will break out to next + position in containing loop*/ + } + if (its != ll) + continue; /* goto next position, this one had an + intersection with our own label group */ + } + } + + metrics_status = msTestLabelCacheCollisions( + map, cachePtr, &metrics_bounds, priority, l); + + /* found a suitable place for this label */ + if (metrics_status == MS_TRUE || + (i == (npositions - 1) && + textSymbolPtr->label->force == MS_ON)) { + metrics_status = + MS_TRUE; /* set to true in case we are forcing it */ + /* compute anno poly for label background if needed */ + if (need_labelpoly) + get_metrics(&(cachePtr->point), positions[i], + textSymbolPtr->textpath, + marker_offset_x + label_offset_x, + marker_offset_y + label_offset_y, + textSymbolPtr->rotation, 1, + &labelpoly_bounds); + + break; /* ...out of position loop */ + } + } /* next position */ + + /* if position auto didn't manage to find a position, but we + * have leader configured for the class, then we want to + * compute the label poly anyway, placed as MS_CC */ + if (classPtr->leader && metrics_status == MS_FALSE) { + metrics_bounds.poly = &metrics_line; + textSymbolPtr->annopoint = get_metrics( + &(cachePtr->point), MS_CC, textSymbolPtr->textpath, + label_offset_x, label_offset_y, textSymbolPtr->rotation, + textSymbolPtr->label->buffer * + textSymbolPtr->scalefactor, + &metrics_bounds); + if (need_labelpoly) + get_metrics(&(cachePtr->point), MS_CC, + textSymbolPtr->textpath, label_offset_x, + label_offset_y, textSymbolPtr->rotation, 1, + &labelpoly_bounds); + } + } else { /* explicit position */ + if (textSymbolPtr->label->position == + MS_CC) { /* don't need the marker_offset */ + metrics_bounds.poly = &metrics_line; + textSymbolPtr->annopoint = get_metrics( + &(cachePtr->point), MS_CC, textSymbolPtr->textpath, + label_offset_x, label_offset_y, textSymbolPtr->rotation, + textSymbolPtr->label->buffer * + textSymbolPtr->scalefactor, + &metrics_bounds); + if (need_labelpoly) + get_metrics(&(cachePtr->point), MS_CC, + textSymbolPtr->textpath, label_offset_x, + label_offset_y, textSymbolPtr->rotation, 1, + &labelpoly_bounds); + } else { + metrics_bounds.poly = &metrics_line; + textSymbolPtr->annopoint = get_metrics( + &(cachePtr->point), textSymbolPtr->label->position, + textSymbolPtr->textpath, + marker_offset_x + label_offset_x, + marker_offset_y + label_offset_y, + textSymbolPtr->rotation, + textSymbolPtr->label->buffer * + textSymbolPtr->scalefactor, + &metrics_bounds); + if (need_labelpoly) + get_metrics( + &(cachePtr->point), textSymbolPtr->label->position, + textSymbolPtr->textpath, + marker_offset_x + label_offset_x, + marker_offset_y + label_offset_y, + textSymbolPtr->rotation, 1, &labelpoly_bounds); + } + + if (textSymbolPtr->label->force == MS_ON) { + metrics_status = MS_ON; + } else { + if (textSymbolPtr->label->force == MS_OFF) { + /* check for collisions inside the label group unless the + * label is FORCE GROUP */ + for (its = 0; its < ll; its++) { + /* check for collisions inside the label group */ + if (intersectTextSymbol(cachePtr->textsymbols[its], + &metrics_bounds) == MS_TRUE) { + /* there was a self intersection */ + break; /* will break out to next position in + containing loop*/ + } + if (its != ll) { + cachePtr->status = MS_DELETE; /* TODO RFC98: check if + this is correct */ + MS_DEBUG( + MS_DEBUGLEVEL_DEVDEBUG, map, + "Skipping label %d (\"%s\") of labelgroup %d of " + "class %d in layer \"%s\": intercollision with " + "label text inside labelgroup\n", + ll, textSymbolPtr->annotext, l, + cachePtr->classindex, layerPtr->name); + break; /* collision within the group, break out of + textSymbol loop */ + } + } + } + /* TODO: in case we have leader lines and multiple labels, + * there's no use in testing for labelcache collisions once + * a first collision has been found. we only need to know + * that the label group has collided, and the poly of the + * whole label group: if(label_group) + * testLabelCacheCollisions */ + metrics_status = msTestLabelCacheCollisions( + map, cachePtr, &metrics_bounds, priority, l); + } + } /* end POSITION AUTO vs Fixed POSITION */ + + if (!metrics_status && classPtr->leader == 0) { + cachePtr->status = MS_DELETE; + MS_DEBUG(MS_DEBUGLEVEL_DEVDEBUG, map, + "Skipping label %d \"%s\" of labelgroup %d of class " + "%d in layer \"%s\": text collided\n", + ll, textSymbolPtr->annotext, l, cachePtr->classindex, + layerPtr->name); + break; /* no point looking at more labels, unless their is a + leader defined */ + } + } + + /* if we're here, we can either fit the label directly, or we need + * to put it in the leader queue */ + assert((metrics_status && label_marker_status) || + classPtr->leader); + + if (textSymbolPtr->annotext) { + copyLabelBounds(&textSymbolPtr->textpath->bounds, + &metrics_bounds); + } + if (have_label_marker) { + if (!textSymbolPtr->style_bounds) + textSymbolPtr->style_bounds = msSmallCalloc( + textSymbolPtr->label->numstyles, sizeof(label_bounds *)); + for (its = 0; its < textSymbolPtr->label->numstyles; its++) { + if (textSymbolPtr->label->styles[its]->_geomtransform.type == + MS_GEOMTRANSFORM_LABELPOINT) { + textSymbolPtr->style_bounds[its] = + msSmallMalloc(sizeof(label_bounds)); + copyLabelBounds(textSymbolPtr->style_bounds[its], + &label_marker_bounds); + } + } + } + if (!label_marker_status || !metrics_status) { + MS_DEBUG(MS_DEBUGLEVEL_DEVDEBUG, map, + "Putting label %d of labelgroup %d of class %d , " + "layer \"%s\" in leader queue\n", + ll, l, cachePtr->classindex, layerPtr->name); + cachePtr->status = + MS_OFF; /* we have a collision, but this entry is a + candidate for leader testing */ + } + + /* do we need to copy the labelpoly, or can we use the static one + * ?*/ + if (cachePtr->numtextsymbols > 1 || + (cachePtr->status == MS_OFF && classPtr->leader)) { + /* + * if we have more than one label, or if we have a single one + * which didn't fit but needs to go through leader offset + * testing + */ + if (!textSymbolPtr->style_bounds) + textSymbolPtr->style_bounds = msSmallCalloc( + textSymbolPtr->label->numstyles, sizeof(label_bounds *)); + for (its = 0; its < textSymbolPtr->label->numstyles; its++) { + if (textSymbolPtr->label->styles[its]->_geomtransform.type == + MS_GEOMTRANSFORM_LABELPOLY || + textSymbolPtr->label->styles[its]->_geomtransform.type == + MS_GEOMTRANSFORM_LABELCENTER) { + textSymbolPtr->style_bounds[its] = + msSmallMalloc(sizeof(label_bounds)); + copyLabelBounds(textSymbolPtr->style_bounds[its], + &labelpoly_bounds); + } + } + + } /* else: we'll use labelpoly_bounds directly below */ + } /* next label in the group */ + + if (cachePtr->status != MS_DELETE) { + /* compute the global label bbox */ + int inited = 0, s; + for (its = 0; its < cachePtr->numtextsymbols; its++) { + if (cachePtr->textsymbols[its]->annotext) { + if (inited == 0) { + cachePtr->bbox = + cachePtr->textsymbols[its]->textpath->bounds.bbox; + inited = 1; + } else { + cachePtr->bbox.minx = MS_MIN( + cachePtr->bbox.minx, + cachePtr->textsymbols[its]->textpath->bounds.bbox.minx); + cachePtr->bbox.miny = MS_MIN( + cachePtr->bbox.miny, + cachePtr->textsymbols[its]->textpath->bounds.bbox.miny); + cachePtr->bbox.maxx = MS_MAX( + cachePtr->bbox.maxx, + cachePtr->textsymbols[its]->textpath->bounds.bbox.maxx); + cachePtr->bbox.maxy = MS_MAX( + cachePtr->bbox.maxy, + cachePtr->textsymbols[its]->textpath->bounds.bbox.maxy); + } + } + for (s = 0; s < cachePtr->textsymbols[its]->label->numstyles; + s++) { + if (cachePtr->textsymbols[its] + ->label->styles[s] + ->_geomtransform.type == + MS_GEOMTRANSFORM_LABELPOINT) { + if (inited == 0) { + cachePtr->bbox = + cachePtr->textsymbols[its]->style_bounds[s]->bbox; + inited = 1; + break; + } else { + cachePtr->bbox.minx = + MS_MIN(cachePtr->bbox.minx, cachePtr->textsymbols[its] + ->style_bounds[s] + ->bbox.minx); + cachePtr->bbox.miny = + MS_MIN(cachePtr->bbox.miny, cachePtr->textsymbols[its] + ->style_bounds[s] + ->bbox.miny); + cachePtr->bbox.maxx = + MS_MAX(cachePtr->bbox.maxx, cachePtr->textsymbols[its] + ->style_bounds[s] + ->bbox.maxx); + cachePtr->bbox.maxy = + MS_MAX(cachePtr->bbox.maxy, cachePtr->textsymbols[its] + ->style_bounds[s] + ->bbox.maxy); + break; + } + } + } + } + } + + /* check that mindistance is respected */ + if (cachePtr->numtextsymbols && + cachePtr->textsymbols[0]->label->mindistance > 0.0 && + cachePtr->textsymbols[0]->annotext) { + if (msCheckLabelMinDistance(map, cachePtr) == MS_TRUE) { + cachePtr->status = MS_DELETE; + MS_DEBUG(MS_DEBUGLEVEL_DEVDEBUG, map, + "Skipping labelgroup %d \"%s\" in layer \"%s\": too " + "close to an identical label (mindistance)\n", + l, cachePtr->textsymbols[0]->annotext, layerPtr->name); + } + } + + if (cachePtr->status == MS_OFF || cachePtr->status == MS_DELETE) + continue; /* next labelCacheMemberObj, as we had a collision */ + + /* insert the rendered label */ + insertRenderedLabelMember(map, cachePtr); + + for (ll = 0; ll < cachePtr->numtextsymbols; ll++) { + textSymbolPtr = cachePtr->textsymbols[ll]; + + /* here's where we draw the label styles */ + for (i = 0; i < textSymbolPtr->label->numstyles; i++) { + if (textSymbolPtr->label->styles[i]->_geomtransform.type == + MS_GEOMTRANSFORM_LABELPOINT) { + if (MS_UNLIKELY( + MS_FAILURE == + msDrawMarkerSymbol(map, image, &(cachePtr->point), + textSymbolPtr->label->styles[i], + textSymbolPtr->scalefactor))) { + return MS_FAILURE; + } + } else if (textSymbolPtr->annotext && + textSymbolPtr->label->styles[i] + ->_geomtransform.type == + MS_GEOMTRANSFORM_LABELPOLY) { + if (textSymbolPtr->style_bounds && + textSymbolPtr->style_bounds[i]) { + if (MS_UNLIKELY( + MS_FAILURE == + msDrawLabelBounds(map, image, + textSymbolPtr->style_bounds[i], + textSymbolPtr->label->styles[i], + textSymbolPtr->scalefactor))) { + return MS_FAILURE; + } + } else { + if (MS_UNLIKELY( + MS_FAILURE == + msDrawLabelBounds(map, image, &labelpoly_bounds, + textSymbolPtr->label->styles[i], + textSymbolPtr->scalefactor))) { + return MS_FAILURE; + } + } + } else if (textSymbolPtr->annotext && + textSymbolPtr->label->styles[i] + ->_geomtransform.type == + MS_GEOMTRANSFORM_LABELCENTER) { + pointObj labelCenter; + + if (textSymbolPtr->style_bounds && + textSymbolPtr->style_bounds[i]) { + labelCenter.x = + (textSymbolPtr->style_bounds[i]->bbox.maxx + + textSymbolPtr->style_bounds[i]->bbox.minx) / + 2; + labelCenter.y = + (textSymbolPtr->style_bounds[i]->bbox.maxy + + textSymbolPtr->style_bounds[i]->bbox.miny) / + 2; + if (MS_UNLIKELY( + MS_FAILURE == + msDrawMarkerSymbol(map, image, &labelCenter, + textSymbolPtr->label->styles[i], + textSymbolPtr->scalefactor))) { + return MS_FAILURE; + } + } else { + labelCenter.x = (labelpoly_bounds.bbox.maxx + + labelpoly_bounds.bbox.minx) / + 2; + labelCenter.y = (labelpoly_bounds.bbox.maxy + + labelpoly_bounds.bbox.miny) / + 2; + if (MS_UNLIKELY( + MS_FAILURE == + msDrawMarkerSymbol(map, image, &labelCenter, + textSymbolPtr->label->styles[i], + textSymbolPtr->scalefactor))) { + return MS_FAILURE; + } + } + + } else { + msSetError(MS_MISCERR, + "Labels only support LABELPNT, LABELPOLY and " + "LABELCENTER GEOMTRANSFORMS", + "msDrawLabelCache()"); + return MS_FAILURE; + } + } + + if (textSymbolPtr->annotext) { + if (MS_UNLIKELY(MS_FAILURE == + msDrawTextSymbol(map, image, + textSymbolPtr->annopoint, + textSymbolPtr))) { + return MS_FAILURE; + } + } + } + } + } /* next label(group) from cacheslot */ + if (MS_UNLIKELY(MS_FAILURE == + msDrawOffsettedLabels(image, map, priority))) { + return MS_FAILURE; + } + } /* next priority */ +#ifdef TBDEBUG + styleObj tstyle; + initStyle(&tstyle); + tstyle.width = 1; + tstyle.color.alpha = 255; + tstyle.color.red = 255; + tstyle.color.green = 0; + tstyle.color.blue = 0; + for (priority = MS_MAX_LABEL_PRIORITY - 1; priority >= 0; priority--) { + labelCacheSlotObj *cacheslot; + cacheslot = &(map->labelcache.slots[priority]); + + for (l = cacheslot->numlabels - 1; l >= 0; l--) { + cachePtr = + &(cacheslot + ->labels[l]); /* point to right spot in the label cache */ + /* + assert((cachePtr->poly == NULL && cachePtr->status == MS_OFF) || + (cachePtr->poly && (cachePtr->status == MS_ON)); + */ + if (cachePtr->status) { + msDrawLineSymbol(map, image, cachePtr->poly, &tstyle, + layerPtr->scalefactor); + } + } + } +#endif + + nReturnVal = MS_SUCCESS; /* necessary? */ + } + } + + if (map->debug >= MS_DEBUGLEVEL_TUNING) { + msGettimeofday(&endtime, NULL); + msDebug("msDrawMap(): Drawing Label Cache, %.3fs\n", + (endtime.tv_sec + endtime.tv_usec / 1.0e6) - + (starttime.tv_sec + starttime.tv_usec / 1.0e6)); + } + + return nReturnVal; +} + +/** + * Generic function to tell the underline device that layer + * drawing is stating + */ + +void msImageStartLayer(mapObj *map, layerObj *layer, imageObj *image) { + if (image) { + if (MS_RENDERER_PLUGIN(image->format)) { + const char *approximation_scale = + msLayerGetProcessingKey(layer, "APPROXIMATION_SCALE"); + if (approximation_scale) { + if (!strncasecmp(approximation_scale, "ROUND", 5)) { + MS_IMAGE_RENDERER(image)->transform_mode = MS_TRANSFORM_ROUND; + } else if (!strncasecmp(approximation_scale, "FULL", 4)) { + MS_IMAGE_RENDERER(image)->transform_mode = + MS_TRANSFORM_FULLRESOLUTION; + } else if (!strncasecmp(approximation_scale, "SIMPLIFY", 8)) { + MS_IMAGE_RENDERER(image)->transform_mode = MS_TRANSFORM_SIMPLIFY; + } else { + MS_IMAGE_RENDERER(image)->transform_mode = MS_TRANSFORM_SNAPTOGRID; + MS_IMAGE_RENDERER(image)->approximation_scale = + atof(approximation_scale); + } + } else { + MS_IMAGE_RENDERER(image)->transform_mode = + MS_IMAGE_RENDERER(image)->default_transform_mode; + MS_IMAGE_RENDERER(image)->approximation_scale = + MS_IMAGE_RENDERER(image)->default_approximation_scale; + } + MS_IMAGE_RENDERER(image)->startLayer(image, map, layer); + } else if (MS_RENDERER_IMAGEMAP(image->format)) + msImageStartLayerIM(map, layer, image); + } +} + +/** + * Generic function to tell the underline device that layer + * drawing is ending + */ + +void msImageEndLayer(mapObj *map, layerObj *layer, imageObj *image) { + if (image) { + if (MS_RENDERER_PLUGIN(image->format)) { + MS_IMAGE_RENDERER(image)->endLayer(image, map, layer); + } + } +} + +/** + * Generic function to tell the underline device that shape + * drawing is starting + */ + +void msDrawStartShape(mapObj *map, layerObj *layer, imageObj *image, + shapeObj *shape) { + (void)map; + (void)layer; + if (image) { + if (MS_RENDERER_PLUGIN(image->format)) { + if (image->format->vtable->startShape) + image->format->vtable->startShape(image, shape); + } + } +} + +/** + * Generic function to tell the underline device that shape + * drawing is ending + */ + +void msDrawEndShape(mapObj *map, layerObj *layer, imageObj *image, + shapeObj *shape) { + (void)map; + (void)layer; + if (MS_RENDERER_PLUGIN(image->format)) { + if (image->format->vtable->endShape) + image->format->vtable->endShape(image, shape); + } +} +/** + * take the value from the shape and use it to change the + * color in the style to match the range map + */ +int msShapeToRange(styleObj *style, shapeObj *shape) { + /*first, get the value of the rangeitem, which should*/ + /*evaluate to a double*/ + const char *fieldStr = shape->values[style->rangeitemindex]; + if (fieldStr == NULL) { /*if there's not value, bail*/ + return MS_FAILURE; + } + double fieldVal = atof(fieldStr); /*faith that it's ok -- */ + /*should switch to strtod*/ + return msValueToRange(style, fieldVal, MS_COLORSPACE_RGB); +} + +/** + * Allow direct mapping of a value so that mapscript can use the + * Ranges. The styls passed in is updated to reflect the right color + * based on the fieldVal + */ +int msValueToRange(styleObj *style, double fieldVal, colorspace cs) { + double range; + double scaledVal; + + range = style->maxvalue - style->minvalue; + scaledVal = (fieldVal - style->minvalue) / range; + + if (cs == MS_COLORSPACE_RGB) { + /*At this point, we know where on the range we need to be*/ + /*However, we don't know how to map it yet, since RGB(A) can */ + /*Go up or down*/ + style->color.red = (int)(MS_MAX( + 0, (MS_MIN(255, (style->mincolor.red + + ((style->maxcolor.red - style->mincolor.red) * + scaledVal)))))); + style->color.green = (int)(MS_MAX( + 0, (MS_MIN(255, (style->mincolor.green + + ((style->maxcolor.green - style->mincolor.green) * + scaledVal)))))); + style->color.blue = (int)(MS_MAX( + 0, (MS_MIN(255, (style->mincolor.blue + + ((style->maxcolor.blue - style->mincolor.blue) * + scaledVal)))))); + style->color.alpha = (int)(MS_MAX( + 0, (MS_MIN(255, (style->mincolor.alpha + + ((style->maxcolor.alpha - style->mincolor.alpha) * + scaledVal)))))); + } else { + /* HSL */ + assert(cs == MS_COLORSPACE_HSL); + if (fieldVal <= style->minvalue) + style->color = style->mincolor; + else if (fieldVal >= style->maxvalue) + style->color = style->maxcolor; + else { + double mh, ms, ml, Mh, Ms, Ml; + msRGBtoHSL(&style->mincolor, &mh, &ms, &ml); + msRGBtoHSL(&style->maxcolor, &Mh, &Ms, &Ml); + mh += (Mh - mh) * scaledVal; + ms += (Ms - ms) * scaledVal; + ml += (Ml - ml) * scaledVal; + msHSLtoRGB(mh, ms, ml, &style->color); + style->color.alpha = + style->mincolor.alpha + + (style->maxcolor.alpha - style->mincolor.alpha) * scaledVal; + } + } + /*( "msMapRange(): %i %i %i", style->color.red , style->color.green, + * style->color.blue);*/ + +#if ALPHACOLOR_ENABLED + /*NO ALPHA RANGE YET style->color.alpha = style->mincolor.alpha + + * ((style->maxcolor.alpha - style->mincolor.alpha) * scaledVal);*/ +#endif + + return MS_SUCCESS; +} diff --git a/src/mapdrawgdal.c b/src/mapdrawgdal.c new file mode 100644 index 0000000000..5dcba57cd5 --- /dev/null +++ b/src/mapdrawgdal.c @@ -0,0 +1,2382 @@ +/****************************************************************************** + * $Id$ + * + * Project: MapServer + * Purpose: Code for drawing GDAL raster layers. Called from + * msDrawRasterLayerLow() in mapraster.c. + * Author: Frank Warmerdam, warmerdam@pobox.com + * + ****************************************************************************** + * Copyright (c) 1996-2005 Regents of the University of Minnesota. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + *****************************************************************************/ + +#include +#include +#include "mapserver.h" +#include "mapresample.h" +#include "mapthread.h" +#include "maptime.h" + +extern int InvGeoTransform(double *gt_in, double *gt_out); + +#define MAXCOLORS 256 +#define GEO_TRANS(tr, x, y) ((tr)[0] + (tr)[1] * (x) + (tr)[2] * (y)) +#define SKIP_MASK(x, y) \ + (mask_rb && !*(mask_rb->data.rgba.a + (y)*mask_rb->data.rgba.row_step + \ + (x)*mask_rb->data.rgba.pixel_step)) + +#include "gdal.h" +#include "cpl_string.h" + +#include "gdal_alg.h" + +static bool IsNoData(double dfValue, double dfNoDataValue); + +static int LoadGDALImages(GDALDatasetH hDS, int band_numbers[4], int band_count, + layerObj *layer, int src_xoff, int src_yoff, + int src_xsize, int src_ysize, GByte *pabyBuffer, + int dst_xsize, int dst_ysize, int *pbHaveRGBNoData, + int *pnNoData1, int *pnNoData2, int *pnNoData3, + bool *pbScaled, double *pdfScaleMin, + double *pdfScaleRatio, bool **ppbIsNoDataBuffer); +static int msDrawRasterLayerGDAL_RawMode(mapObj *map, layerObj *layer, + imageObj *image, GDALDatasetH hDS, + int src_xoff, int src_yoff, + int src_xsize, int src_ysize, + int dst_xoff, int dst_yoff, + int dst_xsize, int dst_ysize); + +static int msDrawRasterLayerGDAL_16BitClassification( + mapObj *map, layerObj *layer, rasterBufferObj *rb, GDALRasterBandH hBand, + int src_xoff, int src_yoff, int src_xsize, int src_ysize, int dst_xoff, + int dst_yoff, int dst_xsize, int dst_ysize); + +/* + * rasterBufferObj setting macros. + */ + +#define GAMMA_CORRECT(color, gamma) \ + (int)(0.5 + 255 * pow((color) / 255.0, (gamma))) + +/************************************************************************/ +/* msDrawRasterLayerGDAL() */ +/************************************************************************/ + +int msDrawRasterLayerGDAL(mapObj *map, layerObj *layer, imageObj *image, + rasterBufferObj *rb, void *hDSVoid) + +{ + int i; /* loop counters */ + int cmap[MAXCOLORS]; +#ifndef NDEBUG + int cmap_set = FALSE; +#endif + unsigned char rb_cmap[4][MAXCOLORS]; + double adfGeoTransform[6], adfInvGeoTransform[6]; + int dst_xoff, dst_yoff, dst_xsize, dst_ysize; + int src_xoff, src_yoff, src_xsize, src_ysize; + double llx, lly, urx, ury; + rectObj copyRect, mapRect; + unsigned char *pabyRaw1 = NULL, *pabyRaw2 = NULL, *pabyRaw3 = NULL, + *pabyRawAlpha = NULL; + int classified = FALSE; + int red_band = 0, green_band = 0, blue_band = 0, alpha_band = 0; + int band_count, band_numbers[4]; + GDALDatasetH hDS = hDSVoid; + GDALColorTableH hColorMap = NULL; + GDALRasterBandH hBand1 = NULL, hBand2 = NULL, hBand3 = NULL, + hBandAlpha = NULL; + int bHaveRGBNoData = FALSE; + int nNoData1 = -1, nNoData2 = -1, nNoData3 = -1; + rasterBufferObj *mask_rb = NULL; + rasterBufferObj s_mask_rb; + + if (layer->mask) { + int ret; + layerObj *maskLayer = GET_LAYER(map, msGetLayerIndex(map, layer->mask)); + mask_rb = &s_mask_rb; + memset(mask_rb, 0, sizeof(s_mask_rb)); + ret = MS_IMAGE_RENDERER(maskLayer->maskimage) + ->getRasterBufferHandle(maskLayer->maskimage, mask_rb); + if (ret != MS_SUCCESS) + return -1; + } + + /*only support rawdata and pluggable renderers*/ + assert(MS_RENDERER_RAWDATA(image->format) || + (MS_RENDERER_PLUGIN(image->format) && rb)); + + memset(cmap, 0xff, MAXCOLORS * sizeof(int)); + memset(rb_cmap, 0, sizeof(rb_cmap)); + + /* -------------------------------------------------------------------- */ + /* Test the image format instead of the map format. */ + /* Normally the map format and the image format should be the */ + /* same but In some cases like swf and pdf support, a temporary */ + /* GD image object is created and used to render raster layers */ + /* and then dumped into the SWF or the PDF file. */ + /* -------------------------------------------------------------------- */ + + src_xsize = GDALGetRasterXSize(hDS); + src_ysize = GDALGetRasterYSize(hDS); + + /* + * If the RAW_WINDOW attribute is set, use that to establish what to + * load. This is normally just set by the mapresample.c module to avoid + * problems with rotated maps. + */ + + if (CSLFetchNameValue(layer->processing, "RAW_WINDOW") != NULL) { + char **papszTokens = + CSLTokenizeString(CSLFetchNameValue(layer->processing, "RAW_WINDOW")); + + if (layer->debug) + msDebug("msDrawGDAL(%s): using RAW_WINDOW=%s, dst=0,0,%d,%d\n", + layer->name, CSLFetchNameValue(layer->processing, "RAW_WINDOW"), + image->width, image->height); + + if (CSLCount(papszTokens) != 4) { + CSLDestroy(papszTokens); + msSetError(MS_IMGERR, "RAW_WINDOW PROCESSING directive corrupt.", + "msDrawGDAL()"); + return -1; + } + + src_xoff = atoi(papszTokens[0]); + src_yoff = atoi(papszTokens[1]); + src_xsize = atoi(papszTokens[2]); + src_ysize = atoi(papszTokens[3]); + + dst_xoff = 0; + dst_yoff = 0; + dst_xsize = image->width; + dst_ysize = image->height; + + CSLDestroy(papszTokens); + } + + /* + * Compute the georeferenced window of overlap, and do nothing if there + * is no overlap between the map extents, and the file we are operating on. + */ + else if (layer->transform) { + int dst_lrx, dst_lry; + + if (layer->debug) + msDebug("msDrawRasterLayerGDAL(): Entering transform.\n"); + + msGetGDALGeoTransform(hDS, map, layer, adfGeoTransform); + InvGeoTransform(adfGeoTransform, adfInvGeoTransform); + + mapRect = map->extent; + + mapRect.minx -= map->cellsize * 0.5; + mapRect.maxx += map->cellsize * 0.5; + mapRect.miny -= map->cellsize * 0.5; + mapRect.maxy += map->cellsize * 0.5; + + copyRect = mapRect; + + if (copyRect.minx < GEO_TRANS(adfGeoTransform, 0, src_ysize)) + copyRect.minx = GEO_TRANS(adfGeoTransform, 0, src_ysize); + if (copyRect.maxx > GEO_TRANS(adfGeoTransform, src_xsize, 0)) + copyRect.maxx = GEO_TRANS(adfGeoTransform, src_xsize, 0); + + if (copyRect.miny < GEO_TRANS(adfGeoTransform + 3, 0, src_ysize)) + copyRect.miny = GEO_TRANS(adfGeoTransform + 3, 0, src_ysize); + if (copyRect.maxy > GEO_TRANS(adfGeoTransform + 3, src_xsize, 0)) + copyRect.maxy = GEO_TRANS(adfGeoTransform + 3, src_xsize, 0); + + if (copyRect.minx >= copyRect.maxx || copyRect.miny >= copyRect.maxy) { + if (layer->debug) + msDebug("msDrawRasterLayerGDAL(): Error in overlap calculation.\n"); + return 0; + } + + /* + * Copy the source and destination raster coordinates. + */ + llx = GEO_TRANS(adfInvGeoTransform + 0, copyRect.minx, copyRect.miny); + lly = GEO_TRANS(adfInvGeoTransform + 3, copyRect.minx, copyRect.miny); + urx = GEO_TRANS(adfInvGeoTransform + 0, copyRect.maxx, copyRect.maxy); + ury = GEO_TRANS(adfInvGeoTransform + 3, copyRect.maxx, copyRect.maxy); + + src_xoff = MS_MAX(0, (int)floor(llx + 0.5)); + src_yoff = MS_MAX(0, (int)floor(ury + 0.5)); + src_xsize = MS_MIN(MS_MAX(0, (int)(urx - llx + 0.5)), + GDALGetRasterXSize(hDS) - src_xoff); + src_ysize = MS_MIN(MS_MAX(0, (int)(lly - ury + 0.5)), + GDALGetRasterYSize(hDS) - src_yoff); + + /* We want very small windows to use at least one source pixel (#4172) */ + if (src_xsize == 0 && (urx - llx) > 0.0) { + src_xsize = 1; + src_xoff = MS_MIN(src_xoff, GDALGetRasterXSize(hDS) - 1); + } + if (src_ysize == 0 && (lly - ury) > 0.0) { + src_ysize = 1; + src_yoff = MS_MIN(src_yoff, GDALGetRasterYSize(hDS) - 1); + } + + if (src_xsize == 0 || src_ysize == 0) { + if (layer->debug) + msDebug("msDrawRasterLayerGDAL(): no apparent overlap between map view " + "and this window(1).\n"); + return 0; + } + + if (map->cellsize == 0) { + if (layer->debug) + msDebug("msDrawRasterLayerGDAL(): Cellsize can't be 0.\n"); + return 0; + } + + dst_xoff = (int)((copyRect.minx - mapRect.minx) / map->cellsize); + dst_yoff = (int)((mapRect.maxy - copyRect.maxy) / map->cellsize); + + dst_lrx = (int)((copyRect.maxx - mapRect.minx) / map->cellsize + 0.5); + dst_lry = (int)((mapRect.maxy - copyRect.miny) / map->cellsize + 0.5); + dst_lrx = MS_MAX(0, MS_MIN(image->width, dst_lrx)); + dst_lry = MS_MAX(0, MS_MIN(image->height, dst_lry)); + + dst_xsize = MS_MAX(0, MS_MIN(image->width, dst_lrx - dst_xoff)); + dst_ysize = MS_MAX(0, MS_MIN(image->height, dst_lry - dst_yoff)); + + if (dst_xsize == 0 || dst_ysize == 0) { + if (layer->debug) + msDebug("msDrawRasterLayerGDAL(): no apparent overlap between map view " + "and this window(2).\n"); + return 0; + } + + if (layer->debug) + msDebug("msDrawRasterLayerGDAL(): src=%d,%d,%d,%d, dst=%d,%d,%d,%d\n", + src_xoff, src_yoff, src_xsize, src_ysize, dst_xoff, dst_yoff, + dst_xsize, dst_ysize); +#ifndef notdef + if (layer->debug) { + double d_src_xoff, d_src_yoff, geo_x, geo_y; + + geo_x = mapRect.minx + dst_xoff * map->cellsize; + geo_y = mapRect.maxy - dst_yoff * map->cellsize; + + d_src_xoff = (geo_x - adfGeoTransform[0]) / adfGeoTransform[1]; + d_src_yoff = (geo_y - adfGeoTransform[3]) / adfGeoTransform[5]; + + msDebug("msDrawRasterLayerGDAL(): source raster PL (%.3f,%.3f) for dst " + "PL (%d,%d).\n", + d_src_xoff, d_src_yoff, dst_xoff, dst_yoff); + } +#endif + } + + /* + * If layer transforms are turned off, just map 1:1. + */ + else { + dst_xoff = src_xoff = 0; + dst_yoff = src_yoff = 0; + dst_xsize = src_xsize = MS_MIN(image->width, src_xsize); + dst_ysize = src_ysize = MS_MIN(image->height, src_ysize); + } + + /* + * In RAWDATA mode we don't fool with colors. Do the raw processing, + * and return from the function early. + */ + if (MS_RENDERER_RAWDATA(image->format)) { + return msDrawRasterLayerGDAL_RawMode( + map, layer, image, hDS, src_xoff, src_yoff, src_xsize, src_ysize, + dst_xoff, dst_yoff, dst_xsize, dst_ysize); + } + + /* + * Is this image classified? We consider it classified if there are + * classes with an expression string *or* a color range. We don't want + * to treat the raster as classified if there is just a bogus class here + * to force inclusion in the legend. + */ + for (i = 0; i < layer->numclasses; i++) { + int s; + + /* change colour based on colour range? */ + for (s = 0; s < layer->class[i] -> numstyles; s++) { + if (MS_VALID_COLOR(layer->class[i] -> styles[s] -> mincolor) && + MS_VALID_COLOR(layer->class[i] -> styles[s] -> maxcolor)) { + classified = TRUE; + break; + } + } + + if (layer->class[i] -> expression.string != NULL) { + classified = TRUE; + break; + } + } + + /* + * Set up the band selection. We look for a BANDS directive in the + * the PROCESSING options. If not found we default to grey=1, grey=1,alpha=2, + * red=1,green=2,blue=3 or red=1,green=2,blue=3,alpha>=4. + */ + + if (CSLFetchNameValue(layer->processing, "BANDS") == NULL) { + const int gdal_band_count = GDALGetRasterCount(hDS); + red_band = 1; + + if (gdal_band_count >= 4) { + /* The alpha band is not necessarily the 4th one */ + for (i = 4; i <= gdal_band_count; i++) { + if (GDALGetRasterColorInterpretation(GDALGetRasterBand(hDS, i)) == + GCI_AlphaBand) { + alpha_band = i; + break; + } + } + } + + if (gdal_band_count >= 3) { + green_band = 2; + blue_band = 3; + } + + if (gdal_band_count == 2 && GDALGetRasterColorInterpretation( + GDALGetRasterBand(hDS, 2)) == GCI_AlphaBand) + alpha_band = 2; + + hBand1 = GDALGetRasterBand(hDS, red_band); + if (classified || GDALGetRasterColorTable(hBand1) != NULL) { + alpha_band = 0; + green_band = 0; + blue_band = 0; + } + } else { + int *band_list; + + band_list = msGetGDALBandList(layer, hDS, 4, &band_count); + if (band_list == NULL) + return -1; + + if (band_count > 0) + red_band = band_list[0]; + else + red_band = 0; + if (band_count > 2) { + green_band = band_list[1]; + blue_band = band_list[2]; + } else { + green_band = 0; + blue_band = 0; + } + + if (band_count > 3) + alpha_band = band_list[3]; + else + alpha_band = 0; + + free(band_list); + } + + band_numbers[0] = red_band; + band_numbers[1] = green_band; + band_numbers[2] = blue_band; + band_numbers[3] = 0; + + if (blue_band != 0 && alpha_band != 0) { + band_numbers[3] = alpha_band; + band_count = 4; + } else if (blue_band != 0 && alpha_band == 0) + band_count = 3; + else if (alpha_band != 0) { + band_numbers[1] = alpha_band; + band_count = 2; + } else + band_count = 1; + + if (layer->debug > 1 || (layer->debug > 0 && green_band != 0)) { + msDebug( + "msDrawRasterLayerGDAL(): red,green,blue,alpha bands = %d,%d,%d,%d\n", + red_band, green_band, blue_band, alpha_band); + } + + /* + * Get band handles for PC256, RGB or RGBA cases. + */ + hBand1 = GDALGetRasterBand(hDS, red_band); + if (hBand1 == NULL) + return -1; + + hBand2 = hBand3 = hBandAlpha = NULL; + + if (green_band != 0) { + hBand1 = GDALGetRasterBand(hDS, red_band); + hBand2 = GDALGetRasterBand(hDS, green_band); + hBand3 = GDALGetRasterBand(hDS, blue_band); + if (hBand1 == NULL || hBand2 == NULL || hBand3 == NULL) + return -1; + } + + if (alpha_band != 0) + hBandAlpha = GDALGetRasterBand(hDS, alpha_band); + + /* + * The logic for a classification rendering of non-8bit raster bands + * is sufficiently different than the normal mechanism of loading + * into an 8bit buffer, that we isolate it into it's own subfunction. + */ + if (classified && hBand1 != NULL && + GDALGetRasterDataType(hBand1) != GDT_Byte) { + return msDrawRasterLayerGDAL_16BitClassification( + map, layer, rb, hBand1, src_xoff, src_yoff, src_xsize, src_ysize, + dst_xoff, dst_yoff, dst_xsize, dst_ysize); + } + + /* + * Get colormap for this image. If there isn't one, and we have only + * one band create a greyscale colormap. + */ + bool isDefaultGreyscale = false; + + if (hBand2 != NULL) + hColorMap = NULL; + else { + hColorMap = GDALGetRasterColorTable(hBand1); + if (hColorMap != NULL) + hColorMap = GDALCloneColorTable(hColorMap); + else { + hColorMap = GDALCreateColorTable(GPI_RGB); + isDefaultGreyscale = true; + + for (i = 0; i < 256; i++) { + colorObj pixel = {i, i, i, 0}; + GDALColorEntry sEntry; + + if (MS_COMPARE_COLORS(pixel, layer->offsite)) { + sEntry.c1 = 0; + sEntry.c2 = 0; + sEntry.c3 = 0; + sEntry.c4 = 0; /* alpha set to zero */ + } else { + sEntry.c1 = i; + sEntry.c2 = i; + sEntry.c3 = i; + sEntry.c4 = 255; + } + + GDALSetColorEntry(hColorMap, i, &sEntry); + } + } + + /* + ** If we have a known NODATA value, mark it now as transparent. + */ + { + int bGotNoData; + double dfNoDataValue = msGetGDALNoDataValue(layer, hBand1, &bGotNoData); + + if (bGotNoData && dfNoDataValue >= 0 && + dfNoDataValue < GDALGetColorEntryCount(hColorMap)) { + GDALColorEntry sEntry; + + memcpy(&sEntry, GDALGetColorEntry(hColorMap, (int)dfNoDataValue), + sizeof(GDALColorEntry)); + + sEntry.c4 = 0; + GDALSetColorEntry(hColorMap, (int)dfNoDataValue, &sEntry); + } + } + } + + /* + * Allocate imagery buffers. + */ + pabyRaw1 = + (unsigned char *)malloc(((size_t)dst_xsize) * dst_ysize * band_count); + if (pabyRaw1 == NULL) { + msSetError(MS_MEMERR, "Allocating work image of size %dx%dx%d failed.", + "msDrawRasterLayerGDAL()", dst_xsize, dst_ysize, band_count); + return -1; + } + + if (hBand2 != NULL && hBand3 != NULL) { + pabyRaw2 = pabyRaw1 + dst_xsize * dst_ysize * 1; + pabyRaw3 = pabyRaw1 + dst_xsize * dst_ysize * 2; + } + + if (hBandAlpha != NULL) { + if (hBand2 != NULL) + pabyRawAlpha = pabyRaw1 + dst_xsize * dst_ysize * 3; + else + pabyRawAlpha = pabyRaw1 + dst_xsize * dst_ysize * 1; + } + + /* + * Load image data into buffers with scaling, etc. + */ + bool bScaled = false; + double dfScaleMin = 0; + double dfScaleRatio = 0; + bool *pbIsNoDataBuffer = NULL; + if (LoadGDALImages(hDS, band_numbers, band_count, layer, src_xoff, src_yoff, + src_xsize, src_ysize, pabyRaw1, dst_xsize, dst_ysize, + &bHaveRGBNoData, &nNoData1, &nNoData2, &nNoData3, &bScaled, + &dfScaleMin, &dfScaleRatio, &pbIsNoDataBuffer) == -1) { + free(pabyRaw1); + free(pbIsNoDataBuffer); + return -1; + } + + const char *sgamma = msLayerGetProcessingKey(layer, "GAMMA"); + const double gamma = sgamma ? CPLAtof(sgamma) : 1.0; + + /* + * Setup the mapping between source eight bit pixel values, and the + * output images color table. There are two general cases, where the + * class colors are provided by the MAP file, or where we use the native + * color table. + */ + if (classified) { + int c; + const char *pszRangeColorspace = + msLayerGetProcessingKey(layer, "RANGE_COLORSPACE"); + colorspace iRangeColorspace; + +#ifndef NDEBUG + cmap_set = TRUE; +#endif + + if (hColorMap == NULL) { + msSetError(MS_IOERR, + "Attempt to classify 24bit image, this is unsupported.", + "drawGDAL()"); + free(pabyRaw1); + free(pbIsNoDataBuffer); + return -1; + } + + if (!pszRangeColorspace || !strcasecmp(pszRangeColorspace, "RGB")) { + iRangeColorspace = MS_COLORSPACE_RGB; + } else if (!strcasecmp(pszRangeColorspace, "HSL")) { + iRangeColorspace = MS_COLORSPACE_HSL; + } else { + msSetError(MS_MISCERR, + "Unknown RANGE_COLORSPACE \"%s\", expecting RGB or HSL", + "drawGDAL()", pszRangeColorspace); + GDALDestroyColorTable(hColorMap); + free(pabyRaw1); + free(pbIsNoDataBuffer); + return -1; + } + + int color_count = GDALGetColorEntryCount(hColorMap); + const bool bScaleColors = bScaled && !isDefaultGreyscale; + + if (!bScaleColors && color_count > 256) + color_count = 256; + + for (i = 0; i < color_count; i++) { + colorObj pixel; + int colormap_index; + GDALColorEntry sEntry; + + GDALGetColorEntryAsRGB(hColorMap, i, &sEntry); + + const int j = + bScaleColors + ? MS_MAX(0, MS_MIN(255, (int)((i - dfScaleMin) * dfScaleRatio))) + : i; + + pixel.red = sEntry.c1; + pixel.green = sEntry.c2; + pixel.blue = sEntry.c3; + colormap_index = i; + + if (!MS_COMPARE_COLORS(pixel, layer->offsite)) { + c = msGetClass(layer, &pixel, colormap_index); + + if (c != -1) { /* belongs to any class */ + int s; + + /* change colour based on colour range? Currently we + only address the greyscale case properly. */ + + if (MS_VALID_COLOR(layer->class[c] -> styles[0] -> mincolor)) { + for (s = 0; s < layer->class[c] -> numstyles; s++) { + if (MS_VALID_COLOR(layer->class[c] -> styles[s] -> mincolor) && + MS_VALID_COLOR(layer->class[c] -> styles[s] -> maxcolor)) { + if (sEntry.c1 >= layer->class[c] -> styles[s] + -> minvalue && + sEntry.c1 <= + layer->class[c] -> styles[s] -> maxvalue) { + msValueToRange(layer->class[c] -> styles[s], sEntry.c1, + iRangeColorspace); + if (MS_VALID_COLOR(layer->class[c] -> styles[s] -> color)) { + rb_cmap[0][j] = layer->class[c]->styles[s]->color.red; + rb_cmap[1][j] = layer->class[c]->styles[s]->color.green; + rb_cmap[2][j] = layer->class[c]->styles[s]->color.blue; + rb_cmap[3][j] = + (layer->class[c] -> styles[s] -> color.alpha != 255) + ? (layer->class[c] -> styles[s] -> color.alpha) + : (255 * layer->class[c] -> styles[0] -> opacity / + 100); + break; + } + } + } + } + } else if (MS_TRANSPARENT_COLOR( + layer->class[c] -> styles[0] -> color)) + /* leave it transparent */; + + else if (MS_VALID_COLOR(layer->class[c] -> styles[0] -> color)) { + rb_cmap[0][j] = layer->class[c]->styles[0]->color.red; + rb_cmap[1][j] = layer->class[c]->styles[0]->color.green; + rb_cmap[2][j] = layer->class[c]->styles[0]->color.blue; + rb_cmap[3][j] = + (255 * layer->class[c] -> styles[0] -> opacity / 100); + } + + else { /* Use raster color */ + rb_cmap[0][j] = pixel.red; + rb_cmap[1][j] = pixel.green; + rb_cmap[2][j] = pixel.blue; + rb_cmap[3][j] = 255; + } + + if (gamma != 1.0) { + rb_cmap[0][j] = GAMMA_CORRECT(rb_cmap[0][j], gamma); + rb_cmap[1][j] = GAMMA_CORRECT(rb_cmap[1][j], gamma); + rb_cmap[2][j] = GAMMA_CORRECT(rb_cmap[2][j], gamma); + } + } + } + } + } else if (hBand2 == NULL && hColorMap != NULL && + rb->type == MS_BUFFER_BYTE_RGBA) { + int color_count; +#ifndef NDEBUG + cmap_set = TRUE; +#endif + + color_count = MS_MIN(256, GDALGetColorEntryCount(hColorMap)); + const bool bScaleColors = bScaled && !isDefaultGreyscale; + + for (i = 0; i < color_count; i++) { + GDALColorEntry sEntry; + + GDALGetColorEntryAsRGB(hColorMap, i, &sEntry); + const int j = + bScaleColors + ? MS_MAX(0, MS_MIN(255, (int)((i - dfScaleMin) * dfScaleRatio))) + : i; + + if (sEntry.c4 != 0 && + (!MS_VALID_COLOR(layer->offsite) || layer->offsite.red != sEntry.c1 || + layer->offsite.green != sEntry.c2 || + layer->offsite.blue != sEntry.c3)) { + rb_cmap[0][j] = sEntry.c1; + rb_cmap[1][j] = sEntry.c2; + rb_cmap[2][j] = sEntry.c3; + rb_cmap[3][j] = sEntry.c4; + if (gamma != 1.0) { + rb_cmap[0][j] = GAMMA_CORRECT(rb_cmap[0][j], gamma); + rb_cmap[1][j] = GAMMA_CORRECT(rb_cmap[1][j], gamma); + rb_cmap[2][j] = GAMMA_CORRECT(rb_cmap[2][j], gamma); + } + } + } + } + + if (bHaveRGBNoData && layer->debug) + msDebug("msDrawGDAL(): using RGB nodata values from GDAL dataset.\n"); + + /* -------------------------------------------------------------------- */ + /* If there was no alpha band, but we have a dataset level mask */ + /* load it as massage it so it will function as our alpha for */ + /* transparency purposes. */ + /* -------------------------------------------------------------------- */ + if (hBandAlpha == NULL) { + int nMaskFlags = GDALGetMaskFlags(hBand1); + + if (CSLTestBoolean( + CSLFetchNameValueDef(layer->processing, "USE_MASK_BAND", "YES")) && + (nMaskFlags & GMF_PER_DATASET) != 0 && + (nMaskFlags & (GMF_NODATA | GMF_ALL_VALID)) == 0) { + CPLErr eErr; + unsigned char *pabyOrig = pabyRaw1; + + if (layer->debug) + msDebug("msDrawGDAL(): using GDAL mask band for alpha.\n"); + + band_count++; + + pabyRaw1 = (unsigned char *)realloc(pabyOrig, ((size_t)dst_xsize) * + dst_ysize * band_count); + + if (pabyRaw1 == NULL) { + msSetError(MS_MEMERR, "Allocating work image of size %dx%dx%d failed.", + "msDrawRasterLayerGDAL()", dst_xsize, dst_ysize, band_count); + free(pabyOrig); + if (hColorMap != NULL) + GDALDestroyColorTable(hColorMap); + free(pbIsNoDataBuffer); + return -1; + } + + if (hBand2 != NULL) { + pabyRaw2 = pabyRaw1 + dst_xsize * dst_ysize * 1; + pabyRaw3 = pabyRaw1 + dst_xsize * dst_ysize * 2; + pabyRawAlpha = pabyRaw1 + dst_xsize * dst_ysize * 3; + } else { + pabyRawAlpha = pabyRaw1 + dst_xsize * dst_ysize * 1; + } + + hBandAlpha = GDALGetMaskBand(hBand1); + + eErr = GDALRasterIO(hBandAlpha, GF_Read, src_xoff, src_yoff, src_xsize, + src_ysize, pabyRawAlpha, dst_xsize, dst_ysize, + GDT_Byte, 0, 0); + + if (eErr != CE_None) { + msSetError(MS_IOERR, "GDALRasterIO() failed: %s", "drawGDAL()", + CPLGetLastErrorMsg()); + if (hColorMap != NULL) + GDALDestroyColorTable(hColorMap); + free(pabyRaw1); + free(pbIsNoDataBuffer); + return -1; + } + + /* In case the mask is not an alpha channel, expand values of 1 to 255, */ + /* so we can deal as it was an alpha band afterwards */ + if ((nMaskFlags & GMF_ALPHA) == 0) { + for (i = 0; i < dst_xsize * dst_ysize; i++) + if (pabyRawAlpha[i]) + pabyRawAlpha[i] = 255; + } + } + } + + /* -------------------------------------------------------------------- */ + /* Single band plus colormap and alpha to truecolor. (RB) */ + /* -------------------------------------------------------------------- */ + if (hBand2 == NULL && rb->type == MS_BUFFER_BYTE_RGBA && hBandAlpha != NULL) { + assert(cmap_set); + + int k = 0; + for (i = dst_yoff; i < dst_yoff + dst_ysize; i++) { + for (int j = dst_xoff; j < dst_xoff + dst_xsize; j++, k++) { + int src_pixel, src_alpha, cmap_alpha, merged_alpha; + if (SKIP_MASK(j, i) || (pbIsNoDataBuffer && pbIsNoDataBuffer[k])) + continue; + + src_pixel = pabyRaw1[k]; + src_alpha = pabyRawAlpha[k]; + cmap_alpha = rb_cmap[3][src_pixel]; + + merged_alpha = (src_alpha * cmap_alpha) / 255; + + if (merged_alpha < 2) + /* do nothing - transparent */; + else if (merged_alpha > 253) { + RB_SET_PIXEL(rb, j, i, rb_cmap[0][src_pixel], rb_cmap[1][src_pixel], + rb_cmap[2][src_pixel], cmap_alpha); + } else { + RB_MIX_PIXEL(rb, j, i, rb_cmap[0][src_pixel], rb_cmap[1][src_pixel], + rb_cmap[2][src_pixel], merged_alpha); + } + } + } + } + + /* -------------------------------------------------------------------- */ + /* Single band plus colormap (no alpha) to truecolor (RB) */ + /* -------------------------------------------------------------------- */ + else if (hBand2 == NULL && rb->type == MS_BUFFER_BYTE_RGBA) { + assert(cmap_set); + + int k = 0; + for (i = dst_yoff; i < dst_yoff + dst_ysize; i++) { + for (int j = dst_xoff; j < dst_xoff + dst_xsize; j++, k++) { + int src_pixel = pabyRaw1[k]; + if (SKIP_MASK(j, i) || (pbIsNoDataBuffer && pbIsNoDataBuffer[k])) + continue; + + if (rb_cmap[3][src_pixel] > 253) { + RB_SET_PIXEL(rb, j, i, rb_cmap[0][src_pixel], rb_cmap[1][src_pixel], + rb_cmap[2][src_pixel], rb_cmap[3][src_pixel]); + } else if (rb_cmap[3][src_pixel] > 1) { + RB_MIX_PIXEL(rb, j, i, rb_cmap[0][src_pixel], rb_cmap[1][src_pixel], + rb_cmap[2][src_pixel], rb_cmap[3][src_pixel]); + } + } + } + } + + /* -------------------------------------------------------------------- */ + /* Input is 3 band RGB. Alpha blending is mixed into the loop */ + /* since this case is less commonly used and has lots of other */ + /* overhead. (RB) */ + /* -------------------------------------------------------------------- */ + else if (hBand3 != NULL && rb->type == MS_BUFFER_BYTE_RGBA) { + int k = 0; + for (i = dst_yoff; i < dst_yoff + dst_ysize; i++) { + for (int j = dst_xoff; j < dst_xoff + dst_xsize; j++, k++) { + if (SKIP_MASK(j, i) || (pbIsNoDataBuffer && pbIsNoDataBuffer[k])) + continue; + int red = pabyRaw1[k]; + int green = pabyRaw2[k]; + int blue = pabyRaw3[k]; + if (MS_VALID_COLOR(layer->offsite) && red == layer->offsite.red && + green == layer->offsite.green && blue == layer->offsite.blue) + continue; + + if (bHaveRGBNoData && red == nNoData1 && green == nNoData2 && + blue == nNoData3) + continue; + + if (pabyRawAlpha == NULL || pabyRawAlpha[k] == 255) { + if (gamma != 1.0) { + red = GAMMA_CORRECT(red, gamma); + green = GAMMA_CORRECT(green, gamma); + blue = GAMMA_CORRECT(blue, gamma); + } + + RB_SET_PIXEL(rb, j, i, red, green, blue, 255); + } else if (pabyRawAlpha[k] != 0) { + if (gamma != 1.0) { + red = GAMMA_CORRECT(red, gamma); + green = GAMMA_CORRECT(green, gamma); + blue = GAMMA_CORRECT(blue, gamma); + } + + RB_MIX_PIXEL(rb, j, i, red, green, blue, pabyRawAlpha[k]); + } + } + } + } + + /* + ** Cleanup + */ + free(pabyRaw1); + free(pbIsNoDataBuffer); + + if (hColorMap != NULL) + GDALDestroyColorTable(hColorMap); + + return 0; +} + +/************************************************************************/ +/* ParseDefaultLUT() */ +/************************************************************************/ + +static int ParseDefaultLUT(const char *lut_def, GByte *lut, int nMaxValIn) + +{ + const char *lut_read; + int last_in = 0, last_out = 0, all_done = FALSE; + + /* -------------------------------------------------------------------- */ + /* Parse definition, applying to lut on the fly. */ + /* -------------------------------------------------------------------- */ + lut_read = lut_def; + while (!all_done) { + int this_in = 0, this_out = 0; + int lut_i; + + while (isspace(*lut_read)) + lut_read++; + + /* if we are at end, assume nMaxValIn:255 */ + if (*lut_read == '\0') { + all_done = TRUE; + if (last_in != nMaxValIn) { + this_in = nMaxValIn; + this_out = 255; + } + } + + /* otherwise read "in:out", and skip past */ + else { + this_in = atoi(lut_read); + while (*lut_read != ':' && *lut_read) + lut_read++; + if (*lut_read == ':') + lut_read++; + while (isspace(*lut_read)) + lut_read++; + this_out = atoi(lut_read); + while (*lut_read && *lut_read != ',' && *lut_read != '\n') + lut_read++; + if (*lut_read == ',' || *lut_read == '\n') + lut_read++; + while (isspace(*lut_read)) + lut_read++; + } + + this_in = MS_MAX(0, MS_MIN(nMaxValIn, this_in)); + this_out = MS_MAX(0, MS_MIN(255, this_out)); + + /* apply linear values from last in:out to this in:out */ + for (lut_i = last_in; lut_i <= this_in; lut_i++) { + double ratio; + + if (last_in == this_in) + ratio = 1.0; + else + ratio = (lut_i - last_in) / (double)(this_in - last_in); + + lut[lut_i] = + (int)floor(((1.0 - ratio) * last_out + ratio * this_out) + 0.5); + } + + last_in = this_in; + last_out = this_out; + } + + return 0; +} + +/************************************************************************/ +/* LutFromGimpLine() */ +/************************************************************************/ + +static int LutFromGimpLine(char *lut_line, GByte *lut) + +{ + char wrkLUTDef[1000]; + int i, count = 0; + char **tokens; + + /* cleanup white space at end of line (DOS LF, etc) */ + i = strlen(lut_line) - 1; + while (i > 0 && isspace(lut_line[i])) + lut_line[i--] = '\0'; + + while (*lut_line == 10 || *lut_line == 13) + lut_line++; + + /* tokenize line */ + tokens = CSLTokenizeString(lut_line); + if (CSLCount(tokens) != 17 * 2) { + CSLDestroy(tokens); + msSetError(MS_MISCERR, "GIMP curve file appears corrupt.", + "LutFromGimpLine()"); + return -1; + } + + /* Convert to our own format */ + wrkLUTDef[0] = '\0'; + for (i = 0; i < 17; i++) { + if (atoi(tokens[i * 2]) >= 0) { + if (count++ > 0) + strlcat(wrkLUTDef, ",", sizeof(wrkLUTDef)); + + snprintf(wrkLUTDef + strlen(wrkLUTDef), + sizeof(wrkLUTDef) - strlen(wrkLUTDef), "%s:%s", tokens[i * 2], + tokens[i * 2 + 1]); + } + } + + CSLDestroy(tokens); + + return ParseDefaultLUT(wrkLUTDef, lut, 255); +} + +/************************************************************************/ +/* ParseGimpLUT() */ +/* */ +/* Parse a Gimp style LUT. */ +/************************************************************************/ + +static int ParseGimpLUT(const char *lut_def, GByte *lut, int iColorIndex) + +{ + int i; + GByte lutValue[256]; + GByte lutColorBand[256]; + char **lines = CSLTokenizeStringComplex(lut_def, "\n", FALSE, FALSE); + + if (!EQUALN(lines[0], "# GIMP Curves File", 18) || CSLCount(lines) < 6) { + msSetError(MS_MISCERR, "GIMP curve file appears corrupt.", + "ParseGimpLUT()"); + CSLDestroy(lines); + return -1; + } + + /* + * Convert the overall curve, and the color band specific curve into LUTs. + */ + if (LutFromGimpLine(lines[1], lutValue) != 0 || + LutFromGimpLine(lines[iColorIndex + 1], lutColorBand) != 0) { + CSLDestroy(lines); + return -1; + } + CSLDestroy(lines); + + /* + * Compose the two luts as if the raw value passed through the color band + * specific lut, and then the general value lut. Usually one or the + * other will be the identity mapping, but not always. + */ + + for (i = 0; i < 256; i++) { + lut[i] = lutValue[lutColorBand[i]]; + } + + return 0; +} + +/************************************************************************/ +/* LoadLUT() */ +/* */ +/* Load a LUT according to RFC 21. */ +/************************************************************************/ + +static int LoadLUT(layerObj *layer, int iColorIndex, char **ppszLutDef) + +{ + const char *lut_def; + char key[20], lut_def_fromfile[2500]; + + *ppszLutDef = NULL; + + /* -------------------------------------------------------------------- */ + /* Get lut specifier from processing directives. Do nothing if */ + /* none are found. */ + /* -------------------------------------------------------------------- */ + sprintf(key, "LUT_%d", iColorIndex); + lut_def = msLayerGetProcessingKey(layer, key); + if (lut_def == NULL) + lut_def = msLayerGetProcessingKey(layer, "LUT"); + if (lut_def == NULL) + return 0; + + /* -------------------------------------------------------------------- */ + /* Does this look like a file? If so, read it into memory. */ + /* -------------------------------------------------------------------- */ + if (strspn(lut_def, "0123456789:, ") != strlen(lut_def)) { + FILE *fp; + char path[MS_MAXPATHLEN]; + int len; + msBuildPath(path, layer->map->mappath, lut_def); + fp = fopen(path, "rb"); + if (fp == NULL) { + msSetError(MS_IOERR, "Failed to open LUT file '%s'.", "drawGDAL()", path); + return -1; + } + + len = fread(lut_def_fromfile, 1, sizeof(lut_def_fromfile), fp); + fclose(fp); + + if (len == sizeof(lut_def_fromfile)) { + msSetError(MS_IOERR, + "LUT definition from file %s longer than maximum buffer size " + "(%d bytes).", + "drawGDAL()", path, (int)sizeof(lut_def_fromfile)); + return -1; + } + + lut_def_fromfile[len] = '\0'; + + lut_def = lut_def_fromfile; + } + + *ppszLutDef = msStrdup(lut_def); + + return 0; +} + +/************************************************************************/ +/* FreeLUTs() */ +/************************************************************************/ + +static void FreeLUTs(char **apszLUTs) { + int i; + for (i = 0; i < 4; i++) + msFree(apszLUTs[i]); + msFree(apszLUTs); +} + +/************************************************************************/ +/* LoadLUTs() */ +/* */ +/* Return an array of 4 strings (some possibly NULL) with loaded LUTs */ +/* or NULL in case of failure. */ +/************************************************************************/ + +static char **LoadLUTs(layerObj *layer, int band_count) { + int i; + char **apszLUTs; + + assert(band_count <= 4); + + apszLUTs = (char **)msSmallCalloc(4, sizeof(char *)); + for (i = 0; i < band_count; i++) { + if (LoadLUT(layer, i + 1, &apszLUTs[i]) != 0) { + FreeLUTs(apszLUTs); + return NULL; + } + } + + return apszLUTs; +} + +/************************************************************************/ +/* GetDataTypeAppropriateForLUTS() */ +/* */ +/* This does a quick examination of the LUT strings to determine */ +/* if they have input values > 255, in which case the raster data */ +/* must be queries on 16-bits. */ +/************************************************************************/ + +static GDALDataType GetDataTypeAppropriateForLUTS(char **apszLUTs) { + GDALDataType eDT = GDT_Byte; + int i; + for (i = 0; i < 4; i++) { + const char *pszLastTuple; + int nLastInValue; + if (apszLUTs[i] == NULL) + continue; + if (EQUALN(apszLUTs[i], "# GIMP", 6)) + continue; + /* Find last in:out tuple in string */ + pszLastTuple = strrchr(apszLUTs[i], ','); + if (pszLastTuple == NULL) + pszLastTuple = apszLUTs[i]; + else + pszLastTuple++; + while (*pszLastTuple == ' ') + pszLastTuple++; + nLastInValue = atoi(pszLastTuple); + if (nLastInValue > 255) { + eDT = GDT_UInt16; + break; + } + } + return eDT; +} + +/************************************************************************/ +/* ApplyLUT() */ +/************************************************************************/ + +static int ApplyLUT(int iColorIndex, const char *lut_def, const void *pInBuffer, + GDALDataType eDT, GByte *pabyOutBuffer, int nPixelCount) { + int i, err; + GByte byteLut[256]; + GByte *uint16Lut = NULL; + + assert(eDT == GDT_Byte || eDT == GDT_UInt16); + + if (lut_def == NULL) { + if (pInBuffer != pabyOutBuffer) { + GDALCopyWords(pInBuffer, eDT, GDALGetDataTypeSizeBytes(eDT), + pabyOutBuffer, GDT_Byte, 1, nPixelCount); + } + return 0; + } + + /* -------------------------------------------------------------------- */ + /* Parse the LUT description. */ + /* -------------------------------------------------------------------- */ + if (EQUALN(lut_def, "# GIMP", 6)) { + if (eDT != GDT_Byte) { + msSetError(MS_MISCERR, "Cannot apply a GIMP LUT on a 16-bit buffer", + "ApplyLUT()"); + return -1; + } + err = ParseGimpLUT(lut_def, byteLut, iColorIndex); + } else { + if (eDT == GDT_Byte) + err = ParseDefaultLUT(lut_def, byteLut, 255); + else { + uint16Lut = (GByte *)malloc(65536); + if (uint16Lut == NULL) { + msSetError(MS_MEMERR, "Cannot allocate 16-bit LUT", "ApplyLUT()"); + return -1; + } + err = ParseDefaultLUT(lut_def, uint16Lut, 65535); + } + } + + /* -------------------------------------------------------------------- */ + /* Apply LUT. */ + /* -------------------------------------------------------------------- */ + if (eDT == GDT_Byte) { + for (i = 0; i < nPixelCount; i++) + pabyOutBuffer[i] = byteLut[((GByte *)pInBuffer)[i]]; + } else { + for (i = 0; i < nPixelCount; i++) + pabyOutBuffer[i] = uint16Lut[((GUInt16 *)pInBuffer)[i]]; + free(uint16Lut); + } + + return err; +} + +/************************************************************************/ +/* LoadGDALImages() */ +/* */ +/* This call will load and process 1-4 bands of input for the */ +/* selected rectangle, loading the result into the passed 8bit */ +/* buffer. The processing options include scaling. */ +/************************************************************************/ + +static int LoadGDALImages(GDALDatasetH hDS, int band_numbers[4], int band_count, + layerObj *layer, int src_xoff, int src_yoff, + int src_xsize, int src_ysize, GByte *pabyWholeBuffer, + int dst_xsize, int dst_ysize, int *pbHaveRGBNoData, + int *pnNoData1, int *pnNoData2, int *pnNoData3, + bool *pbScaled, double *pdfScaleMin, + double *pdfScaleRatio, bool **ppbIsNoDataBuffer) + +{ + int iColorIndex, result_code = 0; + CPLErr eErr; + float *pafWholeRawData; + char **papszLUTs; + + *pbScaled = false; + *pdfScaleMin = 0; + *pdfScaleRatio = 0; + *ppbIsNoDataBuffer = NULL; + + /* -------------------------------------------------------------------- */ + /* If we have no alpha band, but we do have three input */ + /* bands, then check for nodata values. If we only have one */ + /* input band, then nodata will already have been adderssed as */ + /* part of the real or manufactured color table. */ + /* -------------------------------------------------------------------- */ + if (band_count == 3) { + *pnNoData1 = (int)msGetGDALNoDataValue( + layer, GDALGetRasterBand(hDS, band_numbers[0]), pbHaveRGBNoData); + + if (*pbHaveRGBNoData) + *pnNoData2 = (int)msGetGDALNoDataValue( + layer, GDALGetRasterBand(hDS, band_numbers[1]), pbHaveRGBNoData); + if (*pbHaveRGBNoData) + *pnNoData3 = (int)msGetGDALNoDataValue( + layer, GDALGetRasterBand(hDS, band_numbers[2]), pbHaveRGBNoData); + } + + /* -------------------------------------------------------------------- */ + /* Are we doing a simple, non-scaling case? If so, read directly */ + /* and return. */ + /* -------------------------------------------------------------------- */ + if (CSLFetchNameValue(layer->processing, "SCALE") == NULL && + CSLFetchNameValue(layer->processing, "SCALE_1") == NULL && + CSLFetchNameValue(layer->processing, "SCALE_2") == NULL && + CSLFetchNameValue(layer->processing, "SCALE_3") == NULL && + CSLFetchNameValue(layer->processing, "SCALE_4") == NULL) { + + GDALDataType eDT; + GUInt16 *panBuffer = NULL; + void *pBuffer; + + papszLUTs = LoadLUTs(layer, band_count); + if (papszLUTs == NULL) { + return -1; + } + + eDT = GetDataTypeAppropriateForLUTS(papszLUTs); + if (eDT == GDT_UInt16) { + panBuffer = (GUInt16 *)malloc(sizeof(GUInt16) * dst_xsize * dst_ysize * + band_count); + + if (panBuffer == NULL) { + msSetError(MS_MEMERR, + "Allocating work uint16 image of size %dx%dx%d failed.", + "msDrawRasterLayerGDAL()", dst_xsize, dst_ysize, band_count); + FreeLUTs(papszLUTs); + return -1; + } + pBuffer = panBuffer; + } else + pBuffer = pabyWholeBuffer; + + eErr = GDALDatasetRasterIO(hDS, GF_Read, src_xoff, src_yoff, src_xsize, + src_ysize, pBuffer, dst_xsize, dst_ysize, eDT, + band_count, band_numbers, 0, 0, 0); + + if (eErr != CE_None) { + msSetError(MS_IOERR, "GDALDatasetRasterIO() failed: %s", "drawGDAL()", + CPLGetLastErrorMsg()); + FreeLUTs(papszLUTs); + msFree(panBuffer); + return -1; + } + + for (iColorIndex = 0; iColorIndex < band_count && result_code == 0; + iColorIndex++) { + result_code = + ApplyLUT(iColorIndex + 1, papszLUTs[iColorIndex], + (GByte *)pBuffer + dst_xsize * dst_ysize * iColorIndex * + GDALGetDataTypeSizeBytes(eDT), + eDT, pabyWholeBuffer + dst_xsize * dst_ysize * iColorIndex, + dst_xsize * dst_ysize); + } + + FreeLUTs(papszLUTs); + msFree(panBuffer); + return result_code; + } + + /* -------------------------------------------------------------------- */ + /* Disable use of nodata if we are doing scaling. */ + /* -------------------------------------------------------------------- */ + *pbHaveRGBNoData = FALSE; + + /* -------------------------------------------------------------------- */ + /* We need to do some scaling. Will load into either a 16bit */ + /* unsigned or a floating point buffer depending on the source */ + /* data. We offer a special case for 16U data because it is */ + /* common and it is a substantial win to avoid a lot of floating */ + /* point operations on it. */ + /* -------------------------------------------------------------------- */ + /* TODO */ + + /* -------------------------------------------------------------------- */ + /* Allocate the raw imagery buffer, and load into it (band */ + /* interleaved). */ + /* -------------------------------------------------------------------- */ + pafWholeRawData = + (float *)malloc(sizeof(float) * dst_xsize * dst_ysize * band_count); + + if (pafWholeRawData == NULL) { + msSetError(MS_MEMERR, + "Allocating work float image of size %dx%dx%d failed.", + "msDrawRasterLayerGDAL()", dst_xsize, dst_ysize, band_count); + return -1; + } + + eErr = GDALDatasetRasterIO(hDS, GF_Read, src_xoff, src_yoff, src_xsize, + src_ysize, pafWholeRawData, dst_xsize, dst_ysize, + GDT_Float32, band_count, band_numbers, 0, 0, 0); + + if (eErr != CE_None) { + msSetError(MS_IOERR, "GDALDatasetRasterIO() failed: %s", "drawGDAL()", + CPLGetLastErrorMsg()); + + free(pafWholeRawData); + return -1; + } + + papszLUTs = LoadLUTs(layer, band_count); + if (papszLUTs == NULL) { + free(pafWholeRawData); + return -1; + } + + if (GetDataTypeAppropriateForLUTS(papszLUTs) != GDT_Byte) { + msDebug("LoadGDALImage(%s): One of the LUT contains a input value > 255.\n" + "This is not properly supported in combination with SCALE\n", + layer->name); + } + + /* -------------------------------------------------------------------- */ + /* Fetch the scale processing option. */ + /* -------------------------------------------------------------------- */ + for (iColorIndex = 0; iColorIndex < band_count; iColorIndex++) { + unsigned char *pabyBuffer; + double dfScaleMin = 0.0, dfScaleMax = 255.0, dfScaleRatio = 0, + dfNoDataValue; + const char *pszScaleInfo; + float *pafRawData; + int nPixelCount = dst_xsize * dst_ysize, i, bGotNoData = FALSE; + GDALRasterBandH hBand = GDALGetRasterBand(hDS, band_numbers[iColorIndex]); + pszScaleInfo = CSLFetchNameValue(layer->processing, "SCALE"); + const bool bIsAllBandScale = pszScaleInfo != NULL; + if (pszScaleInfo == NULL) { + char szBandScalingName[20]; + + sprintf(szBandScalingName, "SCALE_%d", iColorIndex + 1); + pszScaleInfo = CSLFetchNameValue(layer->processing, szBandScalingName); + } + + if (pszScaleInfo != NULL) { + char **papszTokens; + + papszTokens = CSLTokenizeStringComplex(pszScaleInfo, " ,", FALSE, FALSE); + if (CSLCount(papszTokens) == 1 && EQUAL(papszTokens[0], "AUTO")) { + if (bIsAllBandScale && + GDALGetRasterColorInterpretation(hBand) == GCI_AlphaBand && + GDALGetRasterDataType(hBand) == GDT_Byte) { + // Do not try to scale the alpha band, as it is going to produce + // wrong results + dfScaleMin = 0.0; + dfScaleMax = 255.0; + dfScaleRatio = 1.0; + } else { + dfScaleMin = dfScaleMax = 0.0; + } + } else if (CSLCount(papszTokens) != 2) { + free(pafWholeRawData); + CSLDestroy(papszTokens); + FreeLUTs(papszLUTs); + msSetError(MS_MISCERR, + "SCALE PROCESSING option unparsable for layer %s.", + "msDrawGDAL()", layer->name); + return -1; + } else { + dfScaleMin = atof(papszTokens[0]); + dfScaleMax = atof(papszTokens[1]); + } + CSLDestroy(papszTokens); + } + + /* -------------------------------------------------------------------- */ + /* If we are using autoscaling, then compute the max and min */ + /* now. Perhaps we should eventually honour the offsite value */ + /* as a nodata value, or get it from GDAL. */ + /* -------------------------------------------------------------------- */ + pafRawData = pafWholeRawData + iColorIndex * dst_xsize * dst_ysize; + + dfNoDataValue = msGetGDALNoDataValue(layer, hBand, &bGotNoData); + + /* we force assignment to a float rather than letting pafRawData[i] + get promoted to double later to avoid float precision issues. */ + float fNoDataValue = (float)dfNoDataValue; + + if (dfScaleMin == dfScaleMax) { + int bMinMaxSet = 0; + + /* we force assignment to a float rather than letting pafRawData[i] + get promoted to double later to avoid float precision issues. */ + float fNoDataValue = (float)dfNoDataValue; + + for (i = 0; i < nPixelCount; i++) { + if (bGotNoData && IsNoData(pafRawData[i], fNoDataValue)) + continue; + + if (CPLIsNan(pafRawData[i])) + continue; + + if (!bMinMaxSet) { + dfScaleMin = dfScaleMax = pafRawData[i]; + bMinMaxSet = TRUE; + } + + dfScaleMin = MS_MIN(dfScaleMin, pafRawData[i]); + dfScaleMax = MS_MAX(dfScaleMax, pafRawData[i]); + } + + if (dfScaleMin == dfScaleMax) + dfScaleMax = dfScaleMin + 1.0; + } + + if (layer->debug > 0) + msDebug("msDrawGDAL(%s): scaling to 8bit, src range=%g,%g\n", layer->name, + dfScaleMin, dfScaleMax); + + /* -------------------------------------------------------------------- */ + /* Now process the data. */ + /* -------------------------------------------------------------------- */ + if (dfScaleRatio == 0.0) + dfScaleRatio = 256.0 / (dfScaleMax - dfScaleMin); + pabyBuffer = pabyWholeBuffer + iColorIndex * nPixelCount; + + if (iColorIndex == 0 && bGotNoData) + *ppbIsNoDataBuffer = (bool *)calloc(nPixelCount, sizeof(bool)); + + for (i = 0; i < nPixelCount; i++) { + float fScaledValue; + + if (bGotNoData && IsNoData(pafRawData[i], fNoDataValue)) { + if (iColorIndex == 0) + (*ppbIsNoDataBuffer)[i] = true; + continue; + } + + fScaledValue = (float)((pafRawData[i] - dfScaleMin) * dfScaleRatio); + + if (fScaledValue < 0.0) + pabyBuffer[i] = 0; + else if (fScaledValue > 255.0) + pabyBuffer[i] = 255; + else + pabyBuffer[i] = (int)fScaledValue; + } + + if (iColorIndex == 0) { + *pbScaled = true; + *pdfScaleMin = dfScaleMin; + *pdfScaleRatio = dfScaleRatio; + } + + /* -------------------------------------------------------------------- */ + /* Report a warning if NODATA keyword was applied. We are */ + /* unable to utilize it since we can't return any pixels marked */ + /* as nodata from this function. Need to fix someday. */ + /* -------------------------------------------------------------------- */ + if (bGotNoData) + msDebug("LoadGDALImage(%s): NODATA value %g in GDAL\n" + "file or PROCESSING directive largely ignored. Not yet fully " + "supported for\n" + "unclassified scaled data. The NODATA value is excluded from " + "auto-scaling\n" + "min/max computation, but will not be transparent.\n", + layer->name, dfNoDataValue); + + /* -------------------------------------------------------------------- */ + /* Apply LUT if there is one. */ + /* -------------------------------------------------------------------- */ + result_code = ApplyLUT(iColorIndex + 1, papszLUTs[iColorIndex], pabyBuffer, + GDT_Byte, pabyBuffer, dst_xsize * dst_ysize); + if (result_code == -1) { + free(pafWholeRawData); + FreeLUTs(papszLUTs); + return result_code; + } + } + + free(pafWholeRawData); + FreeLUTs(papszLUTs); + + return result_code; +} + +/************************************************************************/ +/* msGetGDALGeoTransform() */ +/* */ +/* Cover function that tries GDALGetGeoTransform(), a world */ +/* file or OWS extents. It is assumed that TLOCK_GDAL is held */ +/* before this function is called. */ +/************************************************************************/ + +int msGetGDALGeoTransform(GDALDatasetH hDS, mapObj *map, layerObj *layer, + double *padfGeoTransform) + +{ + const char *extent_priority = NULL; + const char *value; + const char *gdalDesc; + const char *fullPath; + char *fileExtension = NULL; + char szPath[MS_MAXPATHLEN]; + int fullPathLen; + int success = 0; + rectObj rect; + + /* -------------------------------------------------------------------- */ + /* some GDAL drivers (ie. GIF) don't set geotransform on failure. */ + /* -------------------------------------------------------------------- */ + padfGeoTransform[0] = 0.0; + padfGeoTransform[1] = 1.0; + padfGeoTransform[2] = 0.0; + padfGeoTransform[3] = GDALGetRasterYSize(hDS); + padfGeoTransform[4] = 0.0; + padfGeoTransform[5] = -1.0; + + /* -------------------------------------------------------------------- */ + /* Do we want to override GDAL with a worldfile if one is present? */ + /* -------------------------------------------------------------------- */ + extent_priority = CSLFetchNameValue(layer->processing, "EXTENT_PRIORITY"); + + if (extent_priority != NULL && EQUALN(extent_priority, "WORLD", 5)) { + /* is there a user configured worldfile? */ + value = CSLFetchNameValue(layer->processing, "WORLDFILE"); + + if (value != NULL) { + /* at this point, fullPath may be a filePath or path only */ + fullPath = msBuildPath(szPath, map->mappath, value); + + /* fullPath is a path only, so let's append the dataset filename */ + if (strrchr(szPath, '.') == NULL) { + fullPathLen = strlen(fullPath); + gdalDesc = msStripPath((char *)GDALGetDescription(hDS)); + + if ((fullPathLen + strlen(gdalDesc)) < MS_MAXPATHLEN) { + strcpy((char *)(fullPath + fullPathLen), gdalDesc); + } else { + msDebug( + "Path length to alternative worldfile exceeds MS_MAXPATHLEN.\n"); + fullPath = NULL; + } + } + /* fullPath has a filename included, so get the extension */ + else { + fileExtension = msStrdup(strrchr(szPath, '.') + 1); + } + } + /* common behavior with worldfile generated from basename + .wld */ + else { + fullPath = GDALGetDescription(hDS); + fileExtension = msStrdup("wld"); + } + + if (fullPath) + success = GDALReadWorldFile(fullPath, fileExtension, padfGeoTransform); + + if (success && layer->debug >= MS_DEBUGLEVEL_VVV) { + msDebug("Worldfile location: %s.\n", fullPath); + } else if (layer->debug >= MS_DEBUGLEVEL_VVV) { + msDebug("Failed using worldfile location: %s.\n", + fullPath ? fullPath : "(null)"); + } + + msFree(fileExtension); + + if (success) + return MS_SUCCESS; + } + + /* -------------------------------------------------------------------- */ + /* Try GDAL. */ + /* */ + /* Make sure that ymax is always at the top, and ymin at the */ + /* bottom ... that is flip any files without the usual */ + /* orientation. This is intended to enable display of "raw" */ + /* files with no coordinate system otherwise they break down in */ + /* many ways. */ + /* -------------------------------------------------------------------- */ + if (GDALGetGeoTransform(hDS, padfGeoTransform) == CE_None) { + if (padfGeoTransform[5] == 1.0 && padfGeoTransform[3] == 0.0) { + padfGeoTransform[5] = -1.0; + padfGeoTransform[3] = GDALGetRasterYSize(hDS); + } + + return MS_SUCCESS; + } + + /* -------------------------------------------------------------------- */ + /* Try worldfile. */ + /* -------------------------------------------------------------------- */ + if (GDALGetDescription(hDS) != NULL && + GDALReadWorldFile(GDALGetDescription(hDS), "wld", padfGeoTransform)) { + return MS_SUCCESS; + } + + /* -------------------------------------------------------------------- */ + /* Do we have the extent keyword on the layer? We only use */ + /* this if we have a single raster associated with the layer as */ + /* opposed to a tile index. */ + /* */ + /* Arguably this ought to take priority over all the other */ + /* stuff. */ + /* -------------------------------------------------------------------- */ + if (MS_VALID_EXTENT(layer->extent) && layer->data != NULL) { + rect = layer->extent; + + padfGeoTransform[0] = rect.minx; + padfGeoTransform[1] = + (rect.maxx - rect.minx) / (double)GDALGetRasterXSize(hDS); + padfGeoTransform[2] = 0; + padfGeoTransform[3] = rect.maxy; + padfGeoTransform[4] = 0; + padfGeoTransform[5] = + (rect.miny - rect.maxy) / (double)GDALGetRasterYSize(hDS); + + return MS_SUCCESS; + } + + /* -------------------------------------------------------------------- */ + /* We didn't find any info ... use the default. */ + /* Reset our default geotransform. GDALGetGeoTransform() may */ + /* have altered it even if GDALGetGeoTransform() failed. */ + /* -------------------------------------------------------------------- */ + padfGeoTransform[0] = 0.0; + padfGeoTransform[1] = 1.0; + padfGeoTransform[2] = 0.0; + padfGeoTransform[3] = GDALGetRasterYSize(hDS); + padfGeoTransform[4] = 0.0; + padfGeoTransform[5] = -1.0; + + return MS_FAILURE; +} + +/************************************************************************/ +/* msDrawRasterLayerGDAL_RawMode() */ +/* */ +/* Handle the loading and application of data in rawmode. */ +/************************************************************************/ + +static int +msDrawRasterLayerGDAL_RawMode(mapObj *map, layerObj *layer, imageObj *image, + GDALDatasetH hDS, int src_xoff, int src_yoff, + int src_xsize, int src_ysize, int dst_xoff, + int dst_yoff, int dst_xsize, int dst_ysize) + +{ + void *pBuffer; + GDALDataType eDataType; + int *band_list, band_count; + int i, j, k, band; + CPLErr eErr; + double *d_nodatas = NULL; + unsigned char *b_nodatas = NULL; + GInt16 *i_nodatas = NULL; + int got_nodata = FALSE; + rasterBufferObj *mask_rb = NULL; + rasterBufferObj s_mask_rb; + if (layer->mask) { + int ret; + layerObj *maskLayer = GET_LAYER(map, msGetLayerIndex(map, layer->mask)); + mask_rb = &s_mask_rb; + memset(mask_rb, 0, sizeof(s_mask_rb)); + ret = MS_IMAGE_RENDERER(maskLayer->maskimage) + ->getRasterBufferHandle(maskLayer->maskimage, mask_rb); + if (ret != MS_SUCCESS) + return -1; + } + + if (image->format->bands > 256) { + msSetError(MS_IMGERR, "Too many bands (more than 256).", + "msDrawRasterLayerGDAL_RawMode()"); + return -1; + } + + /* -------------------------------------------------------------------- */ + /* What data type do we need? */ + /* -------------------------------------------------------------------- */ + if (image->format->imagemode == MS_IMAGEMODE_INT16) + eDataType = GDT_Int16; + else if (image->format->imagemode == MS_IMAGEMODE_FLOAT32) + eDataType = GDT_Float32; + else if (image->format->imagemode == MS_IMAGEMODE_FLOAT64) + eDataType = GDT_Float64; + else if (image->format->imagemode == MS_IMAGEMODE_BYTE) + eDataType = GDT_Byte; + else + return -1; + + /* -------------------------------------------------------------------- */ + /* Work out the band list. */ + /* -------------------------------------------------------------------- */ + band_list = msGetGDALBandList(layer, hDS, image->format->bands, &band_count); + if (band_list == NULL) + return -1; + + if (band_count != image->format->bands) { + free(band_list); + msSetError(MS_IMGERR, + "BANDS PROCESSING directive has wrong number of bands, expected " + "%d, got %d.", + "msDrawRasterLayerGDAL_RawMode()", image->format->bands, + band_count); + return -1; + } + + /* -------------------------------------------------------------------- */ + /* Do we have nodata values? */ + /* -------------------------------------------------------------------- */ + + d_nodatas = (double *)calloc(band_count, sizeof(double)); + if (d_nodatas == NULL) { + msSetError(MS_MEMERR, "%s: %d: Out of memory allocating %u bytes.\n", + "msDrawRasterLayerGDAL_RawMode()", __FILE__, __LINE__, + (unsigned int)(sizeof(double) * band_count)); + free(band_list); + return -1; + } + + if (band_count <= 3 && + (layer->offsite.red != -1 || layer->offsite.green != -1 || + layer->offsite.blue != -1)) { + if (band_count > 0) + d_nodatas[0] = layer->offsite.red; + if (band_count > 1) + d_nodatas[1] = layer->offsite.green; + if (band_count > 2) + d_nodatas[2] = layer->offsite.blue; + got_nodata = TRUE; + } + + if (!got_nodata) { + got_nodata = TRUE; + for (band = 0; band < band_count && got_nodata; band++) { + d_nodatas[band] = msGetGDALNoDataValue( + layer, GDALGetRasterBand(hDS, band_list[band]), &got_nodata); + } + } + + if (!got_nodata) { + free(d_nodatas); + d_nodatas = NULL; + } else if (eDataType == GDT_Byte) { + b_nodatas = (unsigned char *)d_nodatas; + for (band = 0; band < band_count; band++) + b_nodatas[band] = (unsigned char)d_nodatas[band]; + } else if (eDataType == GDT_Int16) { + i_nodatas = (GInt16 *)d_nodatas; + for (band = 0; band < band_count; band++) + i_nodatas[band] = (GInt16)d_nodatas[band]; + } + + /* -------------------------------------------------------------------- */ + /* Allocate buffer, and read data into it. */ + /* -------------------------------------------------------------------- */ + pBuffer = malloc(((size_t)dst_xsize) * dst_ysize * image->format->bands * + GDALGetDataTypeSizeBytes(eDataType)); + if (pBuffer == NULL) { + msSetError(MS_MEMERR, "Allocating work image of size %dx%d failed.", + "msDrawRasterLayerGDAL()", dst_xsize, dst_ysize); + free(band_list); + free(d_nodatas); + return -1; + } + + eErr = + GDALDatasetRasterIO(hDS, GF_Read, src_xoff, src_yoff, src_xsize, + src_ysize, pBuffer, dst_xsize, dst_ysize, eDataType, + image->format->bands, band_list, 0, 0, 0); + free(band_list); + + if (eErr != CE_None) { + msSetError(MS_IOERR, "GDALRasterIO() failed: %s", + "msDrawRasterLayerGDAL_RawMode()", CPLGetLastErrorMsg()); + free(pBuffer); + free(d_nodatas); + return -1; + } + + /* -------------------------------------------------------------------- */ + /* Transfer the data to the imageObj. */ + /* -------------------------------------------------------------------- */ + k = 0; + for (band = 0; band < image->format->bands; band++) { + for (i = dst_yoff; i < dst_yoff + dst_ysize; i++) { + if (image->format->imagemode == MS_IMAGEMODE_INT16) { + for (j = dst_xoff; j < dst_xoff + dst_xsize; j++) { + int off = j + i * image->width + band * image->width * image->height; + int off_mask = j + i * image->width; + + if ((i_nodatas && ((GInt16 *)pBuffer)[k] == i_nodatas[band]) || + SKIP_MASK(j, i)) { + k++; + continue; + } + + image->img.raw_16bit[off] = ((GInt16 *)pBuffer)[k++]; + MS_SET_BIT(image->img_mask, off_mask); + } + } else if (image->format->imagemode == MS_IMAGEMODE_FLOAT32) { + for (j = dst_xoff; j < dst_xoff + dst_xsize; j++) { + int off = j + i * image->width + band * image->width * image->height; + int off_mask = j + i * image->width; + + if ((d_nodatas && ((float *)pBuffer)[k] == d_nodatas[band]) || + SKIP_MASK(j, i)) { + k++; + continue; + } + + image->img.raw_float[off] = ((float *)pBuffer)[k++]; + MS_SET_BIT(image->img_mask, off_mask); + } + } else if (image->format->imagemode == MS_IMAGEMODE_FLOAT64) { + for (j = dst_xoff; j < dst_xoff + dst_xsize; j++) { + int off = j + i * image->width + band * image->width * image->height; + int off_mask = j + i * image->width; + + if ((d_nodatas && ((double *)pBuffer)[k] == d_nodatas[band]) || + SKIP_MASK(j, i)) { + k++; + continue; + } + + image->img.raw_double[off] = ((double *)pBuffer)[k++]; + MS_SET_BIT(image->img_mask, off_mask); + } + } else if (image->format->imagemode == MS_IMAGEMODE_BYTE) { + for (j = dst_xoff; j < dst_xoff + dst_xsize; j++) { + int off = j + i * image->width + band * image->width * image->height; + int off_mask = j + i * image->width; + + if ((b_nodatas && ((unsigned char *)pBuffer)[k] == b_nodatas[band]) || + SKIP_MASK(j, i)) { + k++; + continue; + } + + image->img.raw_byte[off] = ((unsigned char *)pBuffer)[k++]; + MS_SET_BIT(image->img_mask, off_mask); + } + } + } + } + + free(pBuffer); + free(d_nodatas); + + return 0; +} + +/************************************************************************/ +/* msDrawRasterLayerGDAL_16BitClassifcation() */ +/* */ +/* Handle the rendering of rasters going through a 16bit */ +/* classification lookup instead of the more common 8bit one. */ +/* */ +/* Currently we are using one data path where we load the */ +/* raster into a floating point buffer, and then scale to */ +/* 16bit. Eventually we could add optimizations for some of */ +/* the 16bit cases at the cost of some complication. */ +/************************************************************************/ + +static int msDrawRasterLayerGDAL_16BitClassification( + mapObj *map, layerObj *layer, rasterBufferObj *rb, GDALRasterBandH hBand, + int src_xoff, int src_yoff, int src_xsize, int src_ysize, int dst_xoff, + int dst_yoff, int dst_xsize, int dst_ysize) + +{ + float *pafRawData; + double dfScaleMin = 0.0, dfScaleMax = 0.0, dfScaleRatio; + int nPixelCount = dst_xsize * dst_ysize, i, nBucketCount = 0; + GDALDataType eDataType; + float fDataMin = 0.0, fDataMax = 255.0, fNoDataValue; + const char *pszScaleInfo; + const char *pszBuckets; + int *cmap, c, j, k, bGotNoData = FALSE, bGotFirstValue; + unsigned char *rb_cmap[4]; + CPLErr eErr; + rasterBufferObj *mask_rb = NULL; + rasterBufferObj s_mask_rb; + int lastC; + struct mstimeval starttime = {0}, endtime = {0}; + + const char *pszClassifyScaled; + int bClassifyScaled = FALSE; + + if (layer->mask) { + int ret; + layerObj *maskLayer = GET_LAYER(map, msGetLayerIndex(map, layer->mask)); + mask_rb = &s_mask_rb; + memset(mask_rb, 0, sizeof(s_mask_rb)); + ret = MS_IMAGE_RENDERER(maskLayer->maskimage) + ->getRasterBufferHandle(maskLayer->maskimage, mask_rb); + if (ret != MS_SUCCESS) + return -1; + } + + assert(rb->type == MS_BUFFER_BYTE_RGBA); + + /* ==================================================================== */ + /* Read the requested data in one gulp into a floating point */ + /* buffer. */ + /* ==================================================================== */ + pafRawData = (float *)malloc(sizeof(float) * dst_xsize * dst_ysize); + if (pafRawData == NULL) { + msSetError(MS_MEMERR, "Out of memory allocating working buffer.", + "msDrawRasterLayerGDAL_16BitClassification()"); + return -1; + } + + eErr = GDALRasterIO(hBand, GF_Read, src_xoff, src_yoff, src_xsize, src_ysize, + pafRawData, dst_xsize, dst_ysize, GDT_Float32, 0, 0); + + if (eErr != CE_None) { + free(pafRawData); + msSetError(MS_IOERR, "GDALRasterIO() failed: %s", + "msDrawRasterLayerGDAL_16BitClassification()", + CPLGetLastErrorMsg()); + return -1; + } + + fNoDataValue = (float)msGetGDALNoDataValue(layer, hBand, &bGotNoData); + + /* ==================================================================== */ + /* Determine scaling. */ + /* ==================================================================== */ + eDataType = GDALGetRasterDataType(hBand); + + /* -------------------------------------------------------------------- */ + /* Scan for absolute min/max of this block. */ + /* -------------------------------------------------------------------- */ + bGotFirstValue = FALSE; + + for (i = 1; i < nPixelCount; i++) { + if (bGotNoData && IsNoData(pafRawData[i], fNoDataValue)) + continue; + + if (CPLIsNan(pafRawData[i])) + continue; + + if (!bGotFirstValue) { + fDataMin = fDataMax = pafRawData[i]; + bGotFirstValue = TRUE; + } else { + fDataMin = MS_MIN(fDataMin, pafRawData[i]); + fDataMax = MS_MAX(fDataMax, pafRawData[i]); + } + } + + /* -------------------------------------------------------------------- */ + /* Fetch the scale classification option. */ + /* -------------------------------------------------------------------- */ + pszClassifyScaled = CSLFetchNameValue(layer->processing, "CLASSIFY_SCALED"); + if (pszClassifyScaled != NULL) + bClassifyScaled = CSLTestBoolean(pszClassifyScaled); + + /* -------------------------------------------------------------------- */ + /* Fetch the scale processing option. */ + /* -------------------------------------------------------------------- */ + pszBuckets = CSLFetchNameValue(layer->processing, "SCALE_BUCKETS"); + pszScaleInfo = CSLFetchNameValue(layer->processing, "SCALE"); + + if (pszScaleInfo != NULL) { + char **papszTokens; + + papszTokens = CSLTokenizeStringComplex(pszScaleInfo, " ,", FALSE, FALSE); + if (CSLCount(papszTokens) == 1 && EQUAL(papszTokens[0], "AUTO")) { + dfScaleMin = dfScaleMax = 0.0; + } else if (CSLCount(papszTokens) != 2) { + free(pafRawData); + CSLDestroy(papszTokens); + msSetError(MS_MISCERR, "SCALE PROCESSING option unparsable for layer %s.", + "msDrawGDAL()", layer->name); + return -1; + } else { + dfScaleMin = atof(papszTokens[0]); + dfScaleMax = atof(papszTokens[1]); + } + CSLDestroy(papszTokens); + } + + /* -------------------------------------------------------------------- */ + /* Special integer cases for scaling. */ + /* */ + /* TODO: Treat Int32 and UInt32 case the same way *if* the min */ + /* and max are less than 65536 apart. */ + /* -------------------------------------------------------------------- */ + if (eDataType == GDT_Byte || eDataType == GDT_Int16 || + eDataType == GDT_UInt16) { + if (pszScaleInfo == NULL) { + dfScaleMin = fDataMin - 0.5; + dfScaleMax = fDataMax + 0.5; + } + + if (pszBuckets == NULL) { + nBucketCount = (int)floor(fDataMax - fDataMin + 1.1); + } + } + + /* -------------------------------------------------------------------- */ + /* General case if no scaling values provided in mapfile. */ + /* -------------------------------------------------------------------- */ + else if (dfScaleMin == 0.0 && dfScaleMax == 0.0) { + double dfEpsilon = (fDataMax - fDataMin) / (65536 * 2); + dfScaleMin = fDataMin - dfEpsilon; + dfScaleMax = fDataMax + dfEpsilon; + } + + /* -------------------------------------------------------------------- */ + /* How many buckets? Only set if we don't already have a value. */ + /* -------------------------------------------------------------------- */ + if (pszBuckets == NULL) { + if (nBucketCount == 0) + nBucketCount = 65536; + } else { + nBucketCount = atoi(pszBuckets); + if (nBucketCount < 2) { + free(pafRawData); + msSetError( + MS_MISCERR, + "SCALE_BUCKETS PROCESSING option is not a value of 2 or more: %s.", + "msDrawRasterLayerGDAL_16BitClassification()", pszBuckets); + return -1; + } + } + + /* -------------------------------------------------------------------- */ + /* Compute scaling ratio. */ + /* -------------------------------------------------------------------- */ + if (dfScaleMax == dfScaleMin) + dfScaleMax = dfScaleMin + 1.0; + + dfScaleRatio = nBucketCount / (dfScaleMax - dfScaleMin); + + if (layer->debug > 0) + msDebug("msDrawRasterGDAL_16BitClassification(%s):\n" + " scaling to %d buckets from range=%g,%g.\n", + layer->name, nBucketCount, dfScaleMin, dfScaleMax); + + /* ==================================================================== */ + /* Compute classification lookup table. */ + /* ==================================================================== */ + + cmap = (int *)msSmallCalloc(sizeof(int), nBucketCount); + rb_cmap[0] = (unsigned char *)msSmallCalloc(1, nBucketCount); + rb_cmap[1] = (unsigned char *)msSmallCalloc(1, nBucketCount); + rb_cmap[2] = (unsigned char *)msSmallCalloc(1, nBucketCount); + rb_cmap[3] = (unsigned char *)msSmallCalloc(1, nBucketCount); + + if (layer->debug >= MS_DEBUGLEVEL_TUNING) { + msGettimeofday(&starttime, NULL); + } + + const char *sgamma = msLayerGetProcessingKey(layer, "GAMMA"); + const double gamma = sgamma ? CPLAtof(sgamma) : 1.0; + + lastC = -1; + for (i = 0; i < nBucketCount; i++) { + double dfOriginalValue; + + cmap[i] = -1; + + // i = (int) ((dfOriginalValue - dfScaleMin) * dfScaleRatio+1)-1; + dfOriginalValue = (i + 0.5) / dfScaleRatio + dfScaleMin; + + /* The creation of buckets takes a significant time when they are many, and + many classes as well. When iterating over buckets, a faster strategy is + to reuse first the last used class index. */ + if (bClassifyScaled == TRUE) + c = msGetClass_FloatRGB_WithFirstClassToTry(layer, (float)i, -1, -1, -1, + lastC); + else + c = msGetClass_FloatRGB_WithFirstClassToTry(layer, (float)dfOriginalValue, + -1, -1, -1, lastC); + + lastC = c; + if (c != -1) { + int s; + int styleindex = 0; + + /* change colour based on colour range? */ + if (MS_VALID_COLOR(layer->class[c] -> styles[0] -> mincolor)) { + styleindex = -1; + for (s = 0; s < layer->class[c] -> numstyles; s++) { + if (MS_VALID_COLOR(layer->class[c] -> styles[s] -> mincolor) && + MS_VALID_COLOR(layer->class[c] -> styles[s] -> maxcolor) && + dfOriginalValue + 0.5 / dfScaleRatio >= + layer->class[c] -> styles[s] + -> minvalue && dfOriginalValue - 0.5 / dfScaleRatio <= + layer -> class[c] -> styles[s] -> maxvalue) { + msValueToRange(layer->class[c] -> styles[s], dfOriginalValue, + MS_COLORSPACE_RGB); + styleindex = s; + break; + } + } + } + if (styleindex >= 0) { + if (MS_TRANSPARENT_COLOR( + layer->class[c] -> styles[styleindex] -> color)) { + /* leave it transparent */ + } else if (MS_VALID_COLOR( + layer->class[c] -> styles[styleindex] -> color)) { + /* use class color */ + rb_cmap[0][i] = layer->class[c]->styles[styleindex]->color.red; + rb_cmap[1][i] = layer->class[c]->styles[styleindex]->color.green; + rb_cmap[2][i] = layer->class[c]->styles[styleindex]->color.blue; + rb_cmap[3][i] = + (255 * layer->class[c] -> styles[styleindex] -> opacity / 100); + + if (gamma != 1.0) { + rb_cmap[0][i] = GAMMA_CORRECT(rb_cmap[0][i], gamma); + rb_cmap[1][i] = GAMMA_CORRECT(rb_cmap[1][i], gamma); + rb_cmap[2][i] = GAMMA_CORRECT(rb_cmap[2][i], gamma); + } + } + } + } + } + + if (layer->debug >= MS_DEBUGLEVEL_TUNING) { + msGettimeofday(&endtime, NULL); + msDebug( + "msDrawRasterGDAL_16BitClassification() bucket creation time: %.3fs\n", + (endtime.tv_sec + endtime.tv_usec / 1.0e6) - + (starttime.tv_sec + starttime.tv_usec / 1.0e6)); + } + + /* ==================================================================== */ + /* Now process the data, applying to the working imageObj. */ + /* ==================================================================== */ + k = 0; + + for (i = dst_yoff; i < dst_yoff + dst_ysize; i++) { + for (j = dst_xoff; j < dst_xoff + dst_xsize; j++) { + float fRawValue = pafRawData[k++]; + int iMapIndex; + + /* + * Skip nodata pixels ... no processing. + */ + if (bGotNoData && IsNoData(fRawValue, fNoDataValue)) + continue; + + if (CPLIsNan(fRawValue)) + continue; + + if (SKIP_MASK(j, i)) + continue; + + /* + * The funny +1/-1 is to avoid odd rounding around zero. + * We could use floor() but sometimes it is expensive. + */ + iMapIndex = (int)((fRawValue - dfScaleMin) * dfScaleRatio + 1) - 1; + + if (iMapIndex >= nBucketCount || iMapIndex < 0) { + continue; + } + /* currently we never have partial alpha so keep simple */ + if (rb_cmap[3][iMapIndex] > 0) + RB_SET_PIXEL(rb, j, i, rb_cmap[0][iMapIndex], rb_cmap[1][iMapIndex], + rb_cmap[2][iMapIndex], rb_cmap[3][iMapIndex]); + } + } + + /* -------------------------------------------------------------------- */ + /* Cleanup */ + /* -------------------------------------------------------------------- */ + free(pafRawData); + free(cmap); + free(rb_cmap[0]); + free(rb_cmap[1]); + free(rb_cmap[2]); + free(rb_cmap[3]); + + assert(k == dst_xsize * dst_ysize); + + return 0; +} + +/************************************************************************/ +/* IsNoData() */ +/************************************************************************/ +static bool IsNoData(double dfValue, double dfNoDataValue) { + return isnan(dfValue) || dfValue == dfNoDataValue; +} + +/************************************************************************/ +/* msGetGDALNoDataValue() */ +/************************************************************************/ +double msGetGDALNoDataValue(layerObj *layer, void *hBand, int *pbGotNoData) + +{ + const char *pszNODATAOpt; + + *pbGotNoData = FALSE; + + /* -------------------------------------------------------------------- */ + /* Check for a NODATA setting in the .map file. */ + /* -------------------------------------------------------------------- */ + pszNODATAOpt = CSLFetchNameValue(layer->processing, "NODATA"); + if (pszNODATAOpt != NULL) { + if (EQUAL(pszNODATAOpt, "OFF") || strlen(pszNODATAOpt) == 0) + return -1234567.0; + if (!EQUAL(pszNODATAOpt, "AUTO")) { + *pbGotNoData = TRUE; + return atof(pszNODATAOpt); + } + } + + /* -------------------------------------------------------------------- */ + /* Check for a NODATA setting on the raw file. */ + /* -------------------------------------------------------------------- */ + if (hBand == NULL) + return -1234567.0; + else + return GDALGetRasterNoDataValue(hBand, pbGotNoData); +} + +/************************************************************************/ +/* msGetGDALBandList() */ +/* */ +/* max_bands - pass zero for no limit. */ +/* band_count - location in which length of the return band */ +/* list is placed. */ +/* */ +/* returns malloc() list of band numbers (*band_count long). */ +/************************************************************************/ + +int *msGetGDALBandList(layerObj *layer, void *hDS, int max_bands, + int *band_count) + +{ + int i, file_bands; + int *band_list = NULL; + + file_bands = GDALGetRasterCount(hDS); + if (file_bands == 0) { + msSetError(MS_IMGERR, + "Attempt to operate on GDAL file with no bands, layer=%s.", + "msGetGDALBandList()", layer->name); + + return NULL; + } + + /* -------------------------------------------------------------------- */ + /* Use all (or first) bands. */ + /* -------------------------------------------------------------------- */ + if (CSLFetchNameValue(layer->processing, "BANDS") == NULL) { + if (max_bands > 0) + *band_count = MS_MIN(file_bands, max_bands); + else + *band_count = file_bands; + + band_list = (int *)malloc(sizeof(int) * *band_count); + + /* FIXME MS_CHECK_ALLOC leaks papszItems */ + MS_CHECK_ALLOC(band_list, sizeof(int) * *band_count, NULL); + + for (i = 0; i < *band_count; i++) + band_list[i] = i + 1; + return band_list; + } + + /* -------------------------------------------------------------------- */ + /* get bands from BANDS processing directive. */ + /* -------------------------------------------------------------------- */ + else { + char **papszItems = CSLTokenizeStringComplex( + CSLFetchNameValue(layer->processing, "BANDS"), " ,", FALSE, FALSE); + + if (CSLCount(papszItems) == 0) { + CSLDestroy(papszItems); + msSetError(MS_IMGERR, "BANDS PROCESSING directive has no items.", + "msGetGDALBandList()"); + return NULL; + } else if (max_bands != 0 && CSLCount(papszItems) > max_bands) { + msSetError(MS_IMGERR, + "BANDS PROCESSING directive has wrong number of bands, " + "expected at most %d, got %d.", + "msGetGDALBandList()", max_bands, CSLCount(papszItems)); + CSLDestroy(papszItems); + return NULL; + } + + *band_count = CSLCount(papszItems); + band_list = (int *)malloc(sizeof(int) * *band_count); + MS_CHECK_ALLOC(band_list, sizeof(int) * *band_count, NULL); + + for (i = 0; i < *band_count; i++) { + band_list[i] = atoi(papszItems[i]); + if (band_list[i] < 1 || band_list[i] > GDALGetRasterCount(hDS)) { + msSetError(MS_IMGERR, + "BANDS PROCESSING directive includes illegal band '%s', " + "should be from 1 to %d.", + "msGetGDALBandList()", papszItems[i], + GDALGetRasterCount(hDS)); + CSLDestroy(papszItems); + free(band_list); + return NULL; + } + } + CSLDestroy(papszItems); + + return band_list; + } +} diff --git a/src/mapdummyrenderer.c b/src/mapdummyrenderer.c new file mode 100644 index 0000000000..e4d967f63d --- /dev/null +++ b/src/mapdummyrenderer.c @@ -0,0 +1,388 @@ +/****************************************************************************** + * $Id$ + * + * Project: MapServer + * Purpose: Dummy functions to implement when using a pluggable renderer + * Author: Thomas Bonfort, thomas.bonfort@gmail.com + * + ****************************************************************************** + * Copyright (c) 2010, Thomas Bonfort + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + *****************************************************************************/ + +#include "mapserver.h" + +int renderLineDummy(imageObj *img, shapeObj *p, strokeStyleObj *style) { + (void)img; + (void)p; + (void)style; + msSetError(MS_RENDERERERR, "renderLine not implemented", "renderLine()"); + return MS_FAILURE; +} + +int renderPolygonDummy(imageObj *img, shapeObj *p, colorObj *color) { + (void)img; + (void)p; + (void)color; + msSetError(MS_RENDERERERR, "renderPolygon not implemented", + "renderPolygon()"); + return MS_FAILURE; +} + +int renderPolygonTiledDummy(imageObj *img, shapeObj *p, imageObj *tile) { + (void)img; + (void)p; + (void)tile; + msSetError(MS_RENDERERERR, "renderPolygonTiled not implemented", + "renderPolygonTiled()"); + return MS_FAILURE; +} + +int renderLineTiledDummy(imageObj *img, shapeObj *p, imageObj *tile) { + (void)img; + (void)p; + (void)tile; + msSetError(MS_RENDERERERR, "renderLineTiled not implemented", + "renderLineTiled()"); + return MS_FAILURE; +} + +int renderRasterGlyphsDummy(imageObj *img, double x, double y, int fontIndex, + colorObj *color, char *text) { + (void)img; + (void)x; + (void)y; + (void)fontIndex; + (void)color; + (void)text; + msSetError(MS_RENDERERERR, "renderRasterGlyphs not implemented", + "renderRasterGlyphs()"); + return MS_FAILURE; +} + +int renderGlyphsLineDummy(imageObj *img, labelPathObj *labelpath, + labelStyleObj *style, char *text) { + (void)img; + (void)labelpath; + (void)style; + (void)text; + msSetError(MS_RENDERERERR, "renderGlyphsLine not implemented", + "renderGlyphsLine()"); + return MS_FAILURE; +} + +int renderVectorSymbolDummy(imageObj *img, double x, double y, + symbolObj *symbol, symbolStyleObj *style) { + (void)img; + (void)x; + (void)y; + (void)symbol; + (void)style; + msSetError(MS_RENDERERERR, "renderVectorSymbol not implemented", + "renderVectorSymbol()"); + return MS_FAILURE; +} + +void *createVectorSymbolTileDummy(int width, int height, symbolObj *symbol, + symbolStyleObj *style) { + (void)width; + (void)height; + (void)symbol; + (void)style; + msSetError(MS_RENDERERERR, "createVectorSymbolTile not implemented", + "createVectorSymbolTile()"); + return NULL; +} + +int renderPixmapSymbolDummy(imageObj *img, double x, double y, + symbolObj *symbol, symbolStyleObj *style) { + (void)img; + (void)x; + (void)y; + (void)symbol; + (void)style; + msSetError(MS_RENDERERERR, "renderPixmapSymbol not implemented", + "renderPixmapSymbol()"); + return MS_FAILURE; +} + +void *createPixmapSymbolTileDummy(int width, int height, symbolObj *symbol, + symbolStyleObj *style) { + (void)width; + (void)height; + (void)symbol; + (void)style; + msSetError(MS_RENDERERERR, "createPixmapSymbolTile not implemented", + "createPixmapSymbolTile()"); + return NULL; +} + +int renderEllipseSymbolDummy(imageObj *image, double x, double y, + symbolObj *symbol, symbolStyleObj *style) { + (void)image; + (void)x; + (void)y; + (void)symbol; + (void)style; + msSetError(MS_RENDERERERR, "renderEllipseSymbol not implemented", + "renderEllipseSymbol()"); + return MS_FAILURE; +} + +void *createEllipseSymbolTileDummy(int width, int height, symbolObj *symbol, + symbolStyleObj *style) { + (void)width; + (void)height; + (void)symbol; + (void)style; + msSetError(MS_RENDERERERR, "createEllipseSymbolTile not implemented", + "createEllipseSymbolTile()"); + return NULL; +} + +int renderTruetypeSymbolDummy(imageObj *img, double x, double y, + symbolObj *symbol, symbolStyleObj *style) { + (void)img; + (void)x; + (void)y; + (void)symbol; + (void)style; + msSetError(MS_RENDERERERR, "renderTruetypeSymbol not implemented", + "renderTruetypeSymbol()"); + return MS_FAILURE; +} + +void *createTruetypeSymbolTileDummy(int width, int height, symbolObj *symbol, + symbolStyleObj *style) { + (void)width; + (void)height; + (void)symbol; + (void)style; + msSetError(MS_RENDERERERR, "createTruetypeSymbolTile not implemented", + "createTruetypeSymbolTile()"); + return NULL; +} + +int renderTileDummy(imageObj *img, imageObj *tile, double x, double y) { + (void)img; + (void)tile; + (void)x; + (void)y; + msSetError(MS_RENDERERERR, "renderTile not implemented", "renderTile()"); + return MS_FAILURE; +} + +rasterBufferObj *loadImageFromFileDummy(char *path) { + (void)path; + msSetError(MS_RENDERERERR, "loadImageFromFile not implemented", + "loadImageFromFile()"); + return NULL; +} + +int getRasterBufferHandleDummy(imageObj *img, rasterBufferObj *rb) { + (void)img; + (void)rb; + msSetError(MS_RENDERERERR, "getRasterBufferHandle not implemented", + "getRasterBufferHandle()"); + return MS_FAILURE; +} + +int getRasterBufferCopyDummy(imageObj *img, rasterBufferObj *rb) { + (void)img; + (void)rb; + msSetError(MS_RENDERERERR, "getRasterBufferCopy not implemented", + "getRasterBufferCopy()"); + return MS_FAILURE; +} + +rasterBufferObj *createRasterBufferDummy(int width, int height) { + (void)width; + (void)height; + msSetError(MS_RENDERERERR, "createRasterBuffer not implemented", + "createRasterBuffer()"); + return NULL; +} + +int mergeRasterBufferDummy(imageObj *dest, rasterBufferObj *overlay, + double opacity, int srcX, int srcY, int dstX, + int dstY, int width, int height) { + (void)dest; + (void)overlay; + (void)opacity; + (void)srcX; + (void)srcY; + (void)dstX; + (void)dstY; + (void)width; + (void)height; + msSetError(MS_RENDERERERR, "mergeRasterBuffer not implemented", + "mergeRasterBuffer()"); + return MS_FAILURE; +} + +int initializeRasterBufferDummy(rasterBufferObj *rb, int width, int height, + int mode) { + (void)rb; + (void)width; + (void)height; + (void)mode; + msSetError(MS_RENDERERERR, "initializeRasterBuffer not implemented", + "initializeRasterBuffer()"); + return MS_FAILURE; +} + +/* image i/o */ +imageObj *createImageDummy(int width, int height, outputFormatObj *format, + colorObj *bg) { + (void)width; + (void)height; + (void)format; + (void)bg; + msSetError(MS_RENDERERERR, "createImage not implemented", "createImage()"); + return NULL; +} + +int saveImageDummy(imageObj *img, mapObj *map, FILE *fp, + outputFormatObj *format) { + (void)img; + (void)map; + (void)fp; + (void)format; + msSetError(MS_RENDERERERR, "saveImage not implemented", "saveImage()"); + return MS_FAILURE; +} +/*...*/ + +/* helper functions */ +int getTruetypeTextBBoxDummy(rendererVTableObj *renderer, char **fonts, + int numfonts, double size, char *string, + rectObj *rect, double **advances, + int bAdjustBaseline) { + (void)renderer; + (void)fonts; + (void)numfonts; + (void)size; + (void)string; + (void)rect; + (void)advances; + (void)bAdjustBaseline; + msSetError(MS_RENDERERERR, "getTruetypeTextBBox not implemented", + "getTruetypeTextBBox()"); + return MS_FAILURE; +} + +int startLayerDummy(imageObj *img, mapObj *map, layerObj *layer) { + (void)img; + (void)map; + (void)layer; + msSetError(MS_RENDERERERR, "startLayer not implemented", "startLayer()"); + return MS_FAILURE; +} + +int endLayerDummy(imageObj *img, mapObj *map, layerObj *layer) { + (void)img; + (void)map; + (void)layer; + msSetError(MS_RENDERERERR, "endLayer not implemented", "endLayer()"); + return MS_FAILURE; +} + +int startShapeDummy(imageObj *img, shapeObj *shape) { + (void)img; + (void)shape; + msSetError(MS_RENDERERERR, "startShape not implemented", "startShape()"); + return MS_FAILURE; +} + +int endShapeDummy(imageObj *img, shapeObj *shape) { + (void)img; + (void)shape; + msSetError(MS_RENDERERERR, "endShape not implemented", "endShape()"); + return MS_FAILURE; +} + +int setClipDummy(imageObj *img, rectObj clipRect) { + (void)img; + (void)clipRect; + msSetError(MS_RENDERERERR, "setClip not implemented", "setClip()"); + return MS_FAILURE; +} +int resetClipDummy(imageObj *img) { + (void)img; + msSetError(MS_RENDERERERR, "resetClip not implemented", "resetClip()"); + return MS_FAILURE; +} + +int freeImageDummy(imageObj *image) { + (void)image; + msSetError(MS_RENDERERERR, "freeImage not implemented", "freeImage()"); + return MS_FAILURE; +} + +int freeTileDummy(imageObj *tile) { + (void)tile; + msSetError(MS_RENDERERERR, "freeTile not implemented", "freeTile()"); + return MS_FAILURE; +} + +int freeSymbolDummy(symbolObj *symbol) { + (void)symbol; + msSetError(MS_RENDERERERR, "freeSymbol not implemented", "freeSymbol()"); + return MS_FAILURE; +} + +int cleanupDummy(void *renderer_data) { + (void)renderer_data; + return MS_SUCCESS; +} + +int msInitializeDummyRenderer(rendererVTableObj *renderer) { + + renderer->use_imagecache = 0; + renderer->supports_pixel_buffer = 0; + renderer->compositeRasterBuffer = NULL; + renderer->supports_clipping = 0; + renderer->supports_svg = 0; + renderer->renderer_data = NULL; + renderer->transform_mode = MS_TRANSFORM_SIMPLIFY; + renderer->startLayer = &startLayerDummy; + renderer->endLayer = &endLayerDummy; + renderer->renderLine = &renderLineDummy; + renderer->renderLineTiled = NULL; + renderer->createImage = &createImageDummy; + renderer->saveImage = &saveImageDummy; + renderer->getRasterBufferHandle = &getRasterBufferHandleDummy; + renderer->getRasterBufferCopy = getRasterBufferCopyDummy; + renderer->initializeRasterBuffer = initializeRasterBufferDummy; + renderer->renderPolygon = &renderPolygonDummy; + renderer->freeImage = &freeImageDummy; + renderer->renderEllipseSymbol = &renderEllipseSymbolDummy; + renderer->renderVectorSymbol = &renderVectorSymbolDummy; + renderer->renderPixmapSymbol = &renderPixmapSymbolDummy; + renderer->mergeRasterBuffer = &mergeRasterBufferDummy; + renderer->renderTile = &renderTileDummy; + renderer->renderPolygonTiled = &renderPolygonTiledDummy; + renderer->freeSymbol = &freeSymbolDummy; + renderer->cleanup = &cleanupDummy; + renderer->startShape = NULL; + renderer->endShape = NULL; + renderer->renderGlyphs = NULL; + return MS_SUCCESS; +} diff --git a/src/mapentities.h b/src/mapentities.h new file mode 100644 index 0000000000..b1283f2b64 --- /dev/null +++ b/src/mapentities.h @@ -0,0 +1,118 @@ +/****************************************************************************** + * $Id$ + * + * Project: MapServer + * Purpose: HTML entity to unicode lookup table + * Author: Thomas Bonfort + * + ****************************************************************************** + * Copyright (c) 1996-2005 Regents of the University of Minnesota. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + ****************************************************************************/ + +/* + * Generated file + * + * This file was generated from: + * http://www.w3.org/TR/REC-html40/sgml/entities.html + * by means of the libgd script: + * entities.tcl + * and modified to avoid namespace collisions + */ + +#ifdef __cplusplus +extern "C" { +#endif + +static const struct mapentities_s { + const char *name; + int value; +} mapentities[] = { + {"AElig", 198}, {"Aacute", 193}, {"Acirc", 194}, {"Agrave", 192}, + {"Alpha", 913}, {"Aring", 197}, {"Atilde", 195}, {"Auml", 196}, + {"Beta", 914}, {"Ccedil", 199}, {"Chi", 935}, {"Dagger", 8225}, + {"Delta", 916}, {"ETH", 208}, {"Eacute", 201}, {"Ecirc", 202}, + {"Egrave", 200}, {"Epsilon", 917}, {"Eta", 919}, {"Euml", 203}, + {"Gamma", 915}, {"Iacute", 205}, {"Icirc", 206}, {"Igrave", 204}, + {"Iota", 921}, {"Iuml", 207}, {"Kappa", 922}, {"Lambda", 923}, + {"Mu", 924}, {"Ntilde", 209}, {"Nu", 925}, {"OElig", 338}, + {"Oacute", 211}, {"Ocirc", 212}, {"Ograve", 210}, {"Omega", 937}, + {"Omicron", 927}, {"Oslash", 216}, {"Otilde", 213}, {"Ouml", 214}, + {"Phi", 934}, {"Pi", 928}, {"Prime", 8243}, {"Psi", 936}, + {"Rho", 929}, {"Scaron", 352}, {"Sigma", 931}, {"THORN", 222}, + {"Tau", 932}, {"Theta", 920}, {"Uacute", 218}, {"Ucirc", 219}, + {"Ugrave", 217}, {"Upsilon", 933}, {"Uuml", 220}, {"Xi", 926}, + {"Yacute", 221}, {"Yuml", 376}, {"Zeta", 918}, {"aacute", 225}, + {"acirc", 226}, {"acute", 180}, {"aelig", 230}, {"agrave", 224}, + {"alefsym", 8501}, {"alpha", 945}, {"amp", 38}, {"and", 8743}, + {"ang", 8736}, {"aring", 229}, {"asymp", 8776}, {"atilde", 227}, + {"auml", 228}, {"bdquo", 8222}, {"beta", 946}, {"brvbar", 166}, + {"bull", 8226}, {"cap", 8745}, {"ccedil", 231}, {"cedil", 184}, + {"cent", 162}, {"chi", 967}, {"circ", 710}, {"clubs", 9827}, + {"cong", 8773}, {"copy", 169}, {"crarr", 8629}, {"cup", 8746}, + {"curren", 164}, {"dArr", 8659}, {"dagger", 8224}, {"darr", 8595}, + {"deg", 176}, {"delta", 948}, {"diams", 9830}, {"divide", 247}, + {"eacute", 233}, {"ecirc", 234}, {"egrave", 232}, {"empty", 8709}, + {"emsp", 8195}, {"ensp", 8194}, {"epsilon", 949}, {"equiv", 8801}, + {"eta", 951}, {"eth", 240}, {"euml", 235}, {"euro", 8364}, + {"exist", 8707}, {"fnof", 402}, {"forall", 8704}, {"frac12", 189}, + {"frac14", 188}, {"frac34", 190}, {"frasl", 8260}, {"gamma", 947}, + {"ge", 8805}, {"gt", 62}, {"hArr", 8660}, {"harr", 8596}, + {"hearts", 9829}, {"hellip", 8230}, {"iacute", 237}, {"icirc", 238}, + {"iexcl", 161}, {"igrave", 236}, {"image", 8465}, {"infin", 8734}, + {"int", 8747}, {"iota", 953}, {"iquest", 191}, {"isin", 8712}, + {"iuml", 239}, {"kappa", 954}, {"lArr", 8656}, {"lambda", 955}, + {"lang", 9001}, {"laquo", 171}, {"larr", 8592}, {"lceil", 8968}, + {"ldquo", 8220}, {"le", 8804}, {"lfloor", 8970}, {"lowast", 8727}, + {"loz", 9674}, {"lrm", 8206}, {"lsaquo", 8249}, {"lsquo", 8216}, + {"lt", 60}, {"macr", 175}, {"mdash", 8212}, {"micro", 181}, + {"middot", 183}, {"minus", 8722}, {"mu", 956}, {"nabla", 8711}, + {"nbsp", 160}, {"ndash", 8211}, {"ne", 8800}, {"ni", 8715}, + {"not", 172}, {"notin", 8713}, {"nsub", 8836}, {"ntilde", 241}, + {"nu", 957}, {"oacute", 243}, {"ocirc", 244}, {"oelig", 339}, + {"ograve", 242}, {"oline", 8254}, {"omega", 969}, {"omicron", 959}, + {"oplus", 8853}, {"or", 8744}, {"ordf", 170}, {"ordm", 186}, + {"oslash", 248}, {"otilde", 245}, {"otimes", 8855}, {"ouml", 246}, + {"para", 182}, {"part", 8706}, {"permil", 8240}, {"perp", 8869}, + {"phi", 966}, {"pi", 960}, {"piv", 982}, {"plusmn", 177}, + {"pound", 163}, {"prime", 8242}, {"prod", 8719}, {"prop", 8733}, + {"psi", 968}, {"quot", 34}, {"rArr", 8658}, {"radic", 8730}, + {"rang", 9002}, {"raquo", 187}, {"rarr", 8594}, {"rceil", 8969}, + {"rdquo", 8221}, {"real", 8476}, {"reg", 174}, {"rfloor", 8971}, + {"rho", 961}, {"rlm", 8207}, {"rsaquo", 8250}, {"rsquo", 8217}, + {"sbquo", 8218}, {"scaron", 353}, {"sdot", 8901}, {"sect", 167}, + {"shy", 173}, {"sigma", 963}, {"sigmaf", 962}, {"sim", 8764}, + {"spades", 9824}, {"sub", 8834}, {"sube", 8838}, {"sum", 8721}, + {"sup", 8835}, {"sup1", 185}, {"sup2", 178}, {"sup3", 179}, + {"supe", 8839}, {"szlig", 223}, {"tau", 964}, {"there4", 8756}, + {"theta", 952}, {"thetasym", 977}, {"thinsp", 8201}, {"thorn", 254}, + {"tilde", 732}, {"times", 215}, {"trade", 8482}, {"uArr", 8657}, + {"uacute", 250}, {"uarr", 8593}, {"ucirc", 251}, {"ugrave", 249}, + {"uml", 168}, {"upsih", 978}, {"upsilon", 965}, {"uuml", 252}, + {"weierp", 8472}, {"xi", 958}, {"yacute", 253}, {"yen", 165}, + {"yuml", 255}, {"zeta", 950}, {"zwj", 8205}, {"zwnj", 8204}, +}; + +#define MAP_ENTITY_NAME_LENGTH_MAX 8 +#define MAP_NR_OF_ENTITIES 252 + +#ifdef __cplusplus +} +#endif diff --git a/src/maperror.c b/src/maperror.c new file mode 100644 index 0000000000..afd2db5711 --- /dev/null +++ b/src/maperror.c @@ -0,0 +1,740 @@ +/****************************************************************************** + * $Id$ + * + * Project: MapServer + * Purpose: Implementation of msSetError(), msDebug() and related functions. + * Author: Steve Lime and the MapServer team. + * + ****************************************************************************** + * Copyright (c) 1996-2005 Regents of the University of Minnesota. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + ****************************************************************************/ + +#include "mapserver.h" +#include "maperror.h" +#include "mapthread.h" +#include "maptime.h" + +#include +#ifndef _WIN32 +#include +#include +#endif +#include + +#include "cpl_conv.h" +#include "cpl_string.h" + +static char *const ms_errorCodes[MS_NUMERRORCODES] = { + "", + "Unable to access file.", + "Memory allocation error.", + "Incorrect data type.", + "Symbol definition error.", + "Regular expression error.", + "TrueType Font error.", + "DBASE file error.", + "GD library error.", + "Unknown identifier.", + "Premature End-of-File.", + "Projection library error.", + "General error message.", + "CGI error.", + "Web application error.", + "Image handling error.", + "Hash table error.", + "Join error.", + "Search returned no results.", + "Shapefile error.", + "Expression parser error.", + "SDE error.", + "OGR error.", + "Query error.", + "WMS server error.", + "WMS connection error.", + "OracleSpatial error.", + "WFS server error.", + "WFS connection error.", + "WMS Map Context error.", + "HTTP request error.", + "Child array error.", + "WCS server error.", + "GEOS library error.", + "Invalid rectangle.", + "Date/time error.", + "GML encoding error.", + "SOS server error.", + "NULL parent pointer error.", + "AGG library error.", + "OWS error.", + "OpenGL renderer error.", + "Renderer error.", + "V8 engine error.", + "OCG API error.", + "Flatgeobuf error."}; + +#ifndef USE_THREAD + +// Get the MapServer error object +errorObj *msGetErrorObj() { + static errorObj ms_error = {MS_NOERR, "", "", "", MS_FALSE, 0, NULL, 0}; + return &ms_error; +} +#endif + +#ifdef USE_THREAD + +typedef struct te_info { + struct te_info *next; + void *thread_id; + errorObj ms_error; +} te_info_t; + +static te_info_t *error_list = NULL; + +errorObj *msGetErrorObj() { + te_info_t *link; + void *thread_id; + errorObj *ret_obj; + + msAcquireLock(TLOCK_ERROROBJ); + + thread_id = msGetThreadId(); + + /* find link for this thread */ + + for (link = error_list; + link != NULL && link->thread_id != thread_id && link->next != NULL && + link->next->thread_id != thread_id; + link = link->next) { + } + + /* If the target thread link is already at the head of the list were ok */ + if (error_list != NULL && error_list->thread_id == thread_id) { + } + + /* We don't have one ... initialize one. */ + else if (link == NULL || link->next == NULL) { + te_info_t *new_link; + errorObj error_obj = {MS_NOERR, "", "", "", 0, 0, NULL, 0}; + + new_link = (te_info_t *)malloc(sizeof(te_info_t)); + new_link->next = error_list; + new_link->thread_id = thread_id; + new_link->ms_error = error_obj; + + error_list = new_link; + } + + /* If the link is not already at the head of the list, promote it */ + else { + te_info_t *target = link->next; + + link->next = link->next->next; + target->next = error_list; + error_list = target; + } + + ret_obj = &(error_list->ms_error); + + msReleaseLock(TLOCK_ERROROBJ); + + return ret_obj; +} +#endif + +/* msInsertErrorObj() +** +** We maintain a chained list of errorObj in which the first errorObj is +** the most recent (i.e. a stack). msErrorReset() should be used to clear +** the list. +** +** Note that since some code in MapServer will fetch the head of the list and +** keep a handle on it for a while, the head of the chained list is static +** and never changes. +** A new errorObj is always inserted after the head, and only if the +** head of the list already contains some information. i.e. If the static +** errorObj at the head of the list is empty then it is returned directly, +** otherwise a new object is inserted after the head and the data that was in +** the head is moved to the new errorObj, freeing the head errorObj to receive +** the new error information. +*/ +static errorObj *msInsertErrorObj(void) { + errorObj *ms_error; + ms_error = msGetErrorObj(); + + if (ms_error->code != MS_NOERR && ms_error->totalerrorcount < 100) { + /* Head of the list already in use, insert a new errorObj after the head + * and move head contents to this new errorObj, freeing the errorObj + * for reuse. + */ + errorObj *new_error; + new_error = (errorObj *)malloc(sizeof(errorObj)); + + /* Note: if malloc() failed then we simply do nothing and the head will + * be overwritten by the caller... we cannot produce an error here + * since we are already inside a msSetError() call. + */ + if (new_error) { + new_error->next = ms_error->next; + new_error->code = ms_error->code; + new_error->isreported = ms_error->isreported; + strlcpy(new_error->routine, ms_error->routine, + sizeof(new_error->routine)); + strlcpy(new_error->message, ms_error->message, + sizeof(new_error->message)); + new_error->errorcount = ms_error->errorcount; + + ms_error->next = new_error; + ms_error->code = MS_NOERR; + ms_error->isreported = MS_FALSE; + ms_error->routine[0] = '\0'; + ms_error->message[0] = '\0'; + ms_error->errorcount = 0; + } + ms_error->totalerrorcount++; + } + + return ms_error; +} + +/* msResetErrorList() +** +** Clear the list of error objects. +*/ +void msResetErrorList() { + errorObj *ms_error, *this_error; + ms_error = msGetErrorObj(); + + this_error = ms_error->next; + while (this_error != NULL) { + errorObj *next_error; + + next_error = this_error->next; + msFree(this_error); + this_error = next_error; + } + + ms_error->next = NULL; + ms_error->code = MS_NOERR; + ms_error->isreported = MS_FALSE; + ms_error->routine[0] = '\0'; + ms_error->message[0] = '\0'; + ms_error->errorcount = 0; + ms_error->totalerrorcount = 0; + + /* -------------------------------------------------------------------- */ + /* Cleanup our entry in the thread list. This is mainly */ + /* imprortant when msCleanup() calls msResetErrorList(). */ + /* -------------------------------------------------------------------- */ +#ifdef USE_THREAD + { + void *thread_id = msGetThreadId(); + te_info_t *link; + + msAcquireLock(TLOCK_ERROROBJ); + + /* find link for this thread */ + + for (link = error_list; + link != NULL && link->thread_id != thread_id && link->next != NULL && + link->next->thread_id != thread_id; + link = link->next) { + } + + if (link->thread_id == thread_id) { + /* presumably link is at head of list. */ + if (error_list == link) + error_list = link->next; + + free(link); + } else if (link->next != NULL && link->next->thread_id == thread_id) { + te_info_t *next_link = link->next; + link->next = link->next->next; + free(next_link); + } + msReleaseLock(TLOCK_ERROROBJ); + } +#endif +} + +char *msGetErrorCodeString(int code) { + + if (code < 0 || code > MS_NUMERRORCODES - 1) + return ("Invalid error code."); + + return (ms_errorCodes[code]); +} + +/* -------------------------------------------------------------------- */ +/* Adding the displayable error string to a given string */ +/* and reallocates the memory enough to hold the characters. */ +/* If source is null returns a newly allocated string */ +/* -------------------------------------------------------------------- */ +char *msAddErrorDisplayString(char *source, errorObj *error) { + if ((source = msStringConcatenate(source, error->routine)) == NULL) + return (NULL); + if ((source = msStringConcatenate(source, ": ")) == NULL) + return (NULL); + if ((source = msStringConcatenate(source, ms_errorCodes[error->code])) == + NULL) + return (NULL); + if ((source = msStringConcatenate(source, " ")) == NULL) + return (NULL); + if ((source = msStringConcatenate(source, error->message)) == NULL) + return (NULL); + if (error->errorcount > 0) { + char *pszTmp; + if ((source = msStringConcatenate(source, " (message repeated ")) == NULL) + return (NULL); + pszTmp = msIntToString(error->errorcount); + if ((source = msStringConcatenate(source, pszTmp)) == NULL) { + msFree(pszTmp); + return (NULL); + } + msFree(pszTmp); + if ((source = msStringConcatenate(source, " times)")) == NULL) + return (NULL); + } + + return source; +} + +char *msGetErrorString(const char *delimiter) { + char *errstr = NULL; + + errorObj *error = msGetErrorObj(); + + if (!delimiter || !error) + return (NULL); + + while (error && error->code != MS_NOERR) { + if ((errstr = msAddErrorDisplayString(errstr, error)) == NULL) + return (NULL); + + if (error->next && + error->next->code != + MS_NOERR) { /* (peek ahead) more errors, use delimiter */ + if ((errstr = msStringConcatenate(errstr, delimiter)) == NULL) + return (NULL); + } + error = error->next; + } + + return (errstr); +} + +static void msRedactString(char *str, const char *keyword) { + + char *password = strstr(str, keyword); + if (password != NULL) { + const char chOptionDelimiter = password - str > 0 ? password[-1] : 0; + char *ptr = password + strlen(keyword); + char chStringSep = *ptr; + if (chStringSep == '\'' || chStringSep == '"') { + ++ptr; + } else if (chOptionDelimiter == ';' && chStringSep == '{' && + strcmp(keyword, "pwd=") == 0) { + // Handle cases like "\\SQL2019;DATABASE=msautotest;Driver={ODBC Driver 17 + // for SQL Server};pwd={Password;12!};uid=sa;" + ++ptr; + chStringSep = '}'; + } else { + chStringSep = '\0'; + } + /* Replace all characters from after equal sign to end of line, end of + * string, or end of quoted string. + */ + char *ptr_first_redacted_char = NULL; + while (*ptr != '\0' && *ptr != '\r' && *ptr != '\n') { + if (chStringSep == '\0') { + if (*ptr == chOptionDelimiter) + break; + } else { + if (*ptr == chStringSep) { + break; + } + if (*ptr == '\\' && ptr[1] == chStringSep) { + ptr++; + } + } + if (!ptr_first_redacted_char) { + ptr_first_redacted_char = ptr; + *ptr = '*'; + } + ptr++; + } + if (ptr_first_redacted_char) { + memmove(ptr_first_redacted_char + 1, ptr, strlen(ptr) + 1); + } + } +} + +void msRedactCredentials(char *str) { + + // postgres or mssql formats + msRedactString(str, "password="); + // ODBC connections can use pwd rather than password + msRedactString(str, "pwd="); +} + +static void msSetErrorInternal(int ms_errcode, const char *http_status, + const char *message, const char *routine) { + + errorObj *ms_error = msGetErrorObj(); + + /* Insert the error to the list if it is not the same as the previous error*/ + if (ms_error->code != ms_errcode || !EQUAL(message, ms_error->message) || + !EQUAL(routine, ms_error->routine)) { + ms_error = msInsertErrorObj(); + if (!routine) + strcpy(ms_error->routine, ""); + else { + strlcpy(ms_error->routine, routine, sizeof(ms_error->routine)); + } + + if (!http_status) + strcpy(ms_error->http_status, ""); + else { + strlcpy(ms_error->http_status, http_status, + sizeof(ms_error->http_status)); + } + + strlcpy(ms_error->message, message, sizeof(ms_error->message)); + ms_error->code = ms_errcode; + ms_error->errorcount = 0; + } else + ++ms_error->errorcount; + + msRedactCredentials(ms_error->message); + + /* Log a copy of errors to MS_ERRORFILE if set (handled automatically inside + * msDebug()) */ + msDebug("%s: %s %s\n", ms_error->routine, ms_errorCodes[ms_error->code], + ms_error->message); +} + +void msSetError(int code, const char *message_fmt, const char *routine, ...) { + va_list args; + char message[MESSAGELENGTH]; + + if (!message_fmt) + strcpy(message, ""); + else { + va_start(args, routine); + vsnprintf(message, MESSAGELENGTH, message_fmt, args); + va_end(args); + } + msSetErrorInternal(code, NULL, message, routine); +} + +#ifdef _MSC_VER +__declspec(thread) int gIsWMS = MS_FALSE; +#else +static _Thread_local int gIsWMS = MS_FALSE; +#endif + +void msSetErrorSetIsWMS(int is_wms) { gIsWMS = is_wms; } + +void msSetErrorWithStatus(int ms_errcode, const char *http_status, + const char *message_fmt, const char *routine, ...) { + va_list args; + char message[MESSAGELENGTH]; + + if (!message_fmt) + strcpy(message, ""); + else { + va_start(args, routine); + vsnprintf(message, MESSAGELENGTH, message_fmt, args); + va_end(args); + } + if (http_status) { + if (gIsWMS) { + if (!CPLTestBoolean( + CPLGetConfigOption("MS_WMS_ERROR_STATUS_CODE", "OFF"))) + http_status = NULL; + } else { + http_status = NULL; + } + } + msSetErrorInternal(ms_errcode, http_status, message, routine); +} + +void msWriteError(FILE *stream) { + errorObj *ms_error = msGetErrorObj(); + + while (ms_error && ms_error->code != MS_NOERR) { + msIO_fprintf(stream, "%s: %s %s
\n", ms_error->routine, + ms_errorCodes[ms_error->code], ms_error->message); + ms_error->isreported = MS_TRUE; + ms_error = ms_error->next; + } +} + +void msWriteErrorXML(FILE *stream) { + char *message; + errorObj *ms_error = msGetErrorObj(); + + while (ms_error && ms_error->code != MS_NOERR) { + message = msEncodeHTMLEntities(ms_error->message); + + msIO_fprintf(stream, "%s: %s %s\n", ms_error->routine, + ms_errorCodes[ms_error->code], message); + ms_error->isreported = MS_TRUE; + ms_error = ms_error->next; + + msFree(message); + } +} + +void msWriteErrorImage(mapObj *map, char *filename, int blank) { + imageObj *img; + int width = 400, height = 300; + const int nMargin = 5; + + char **papszLines = NULL; + pointObj pnt = {0}; + outputFormatObj *format = NULL; + char *errormsg = msGetErrorString("; "); + errorObj *error = msGetErrorObj(); + char *imagepath = NULL, *imageurl = NULL; + colorObj imagecolor, *imagecolorptr = NULL; + textSymbolObj ts; + labelObj label; + int charWidth = 5, + charHeight = 8; /* hardcoded, should be looked up from ft face */ + if (!errormsg) { + errormsg = msStrdup("No error found sorry. This is likely a bug"); + } + + if (map) { + if (map->width > 0 && map->height > 0) { + width = map->width; + height = map->height; + } + format = map->outputformat; + imagepath = map->web.imagepath; + imageurl = map->web.imageurl; + } + + /* Default to GIF if no suitable GD output format set */ + if (format == NULL || !MS_RENDERER_PLUGIN(format)) + format = msCreateDefaultOutputFormat(NULL, "AGG/PNG8", "png", NULL); + + if (!format->transparent) { + if (map && MS_VALID_COLOR(map->imagecolor)) { + imagecolorptr = &map->imagecolor; + } else { + MS_INIT_COLOR(imagecolor, 255, 255, 255, 255); + imagecolorptr = &imagecolor; + } + } + + img = msImageCreate(width, height, format, imagepath, imageurl, + MS_DEFAULT_RESOLUTION, MS_DEFAULT_RESOLUTION, + imagecolorptr); + + const int nTextLength = strlen(errormsg); + const int nWidthTxt = nTextLength * charWidth; + const int nUsableWidth = width - (nMargin * 2); + + /* Check to see if it all fits on one line. If not, split the text on several + * lines. */ + if (!blank) { + int nLines; + if (nWidthTxt > nUsableWidth) { + const int nMaxCharsPerLine = nUsableWidth / charWidth; + nLines = (int)ceil((double)nTextLength / (double)nMaxCharsPerLine); + if (nLines > 0) { + papszLines = (char **)malloc(nLines * sizeof(char *)); + for (int i = 0; i < nLines; i++) { + papszLines[i] = (char *)malloc((nMaxCharsPerLine + 1) * sizeof(char)); + papszLines[i][0] = '\0'; + } + } + for (int i = 0; i < nLines; i++) { + const int nStart = i * nMaxCharsPerLine; + int nEnd = nStart + nMaxCharsPerLine; + if (nStart < nTextLength) { + if (nEnd > nTextLength) + nEnd = nTextLength; + const int nLength = nEnd - nStart; + + strncpy(papszLines[i], errormsg + nStart, nLength); + papszLines[i][nLength] = '\0'; + } + } + } else { + nLines = 1; + papszLines = (char **)malloc(nLines * sizeof(char *)); + papszLines[0] = msStrdup(errormsg); + } + initLabel(&label); + MS_INIT_COLOR(label.color, 0, 0, 0, 255); + MS_INIT_COLOR(label.outlinecolor, 255, 255, 255, 255); + label.outlinewidth = 1; + + label.size = MS_SMALL; + MS_REFCNT_INCR((&label)); + for (int i = 0; i < nLines; i++) { + pnt.y = charHeight * ((i * 2) + 1); + pnt.x = charWidth; + initTextSymbol(&ts); + msPopulateTextSymbolForLabelAndString(&ts, &label, papszLines[i], 1, 1, + 0); + if (MS_LIKELY(MS_SUCCESS == msComputeTextPath(map, &ts))) { + if (MS_SUCCESS != msDrawTextSymbol(NULL, img, pnt, &ts)) { + /* an error occurred, but there's nothing much we can do about it here + * as we are already handling an error condition */ + } + freeTextSymbol(&ts); + } + } + if (papszLines) { + free(papszLines); + } + } + + /* actually write the image */ + if (!filename) { + msIO_setHeader("Content-Type", "%s", MS_IMAGE_MIME_TYPE(format)); + msIO_sendHeaders(); + } + msSaveImage(NULL, img, filename); + msFreeImage(img); + + /* the errors are reported */ + while (error && error->code != MS_NOERR) { + error->isreported = MS_TRUE; + error = error->next; + } + + if (format->refcount == 0) + msFreeOutputFormat(format); + msFree(errormsg); +} + +char *msGetVersion() { + static char version[2048]; + + sprintf(version, "MapServer version %s", MS_VERSION); + + // add versions of required dependencies + static char PROJVersion[20]; + sprintf(PROJVersion, " PROJ version %d.%d", PROJ_VERSION_MAJOR, + PROJ_VERSION_MINOR); + strcat(version, PROJVersion); + + static char GDALVersion[20]; + sprintf(GDALVersion, " GDAL version %d.%d", GDAL_VERSION_MAJOR, + GDAL_VERSION_MINOR); + strcat(version, GDALVersion); + +#if (defined USE_PNG) + strcat(version, " OUTPUT=PNG"); +#endif +#if (defined USE_JPEG) + strcat(version, " OUTPUT=JPEG"); +#endif +#ifdef USE_KML + strcat(version, " OUTPUT=KML"); +#endif + strcat(version, " SUPPORTS=PROJ"); + strcat(version, " SUPPORTS=AGG"); + strcat(version, " SUPPORTS=FREETYPE"); +#ifdef USE_CAIRO + strcat(version, " SUPPORTS=CAIRO"); +#endif +#if defined(USE_SVG_CAIRO) || defined(USE_RSVG) + strcat(version, " SUPPORTS=SVG_SYMBOLS"); +#ifdef USE_SVG_CAIRO + strcat(version, " SUPPORTS=SVGCAIRO"); +#else + strcat(version, " SUPPORTS=RSVG"); +#endif +#endif +#ifdef USE_OGL + strcat(version, " SUPPORTS=OPENGL"); +#endif +#ifdef USE_ICONV + strcat(version, " SUPPORTS=ICONV"); +#endif +#ifdef USE_EXEMPI + strcat(version, " SUPPORTS=XMP"); +#endif +#ifdef USE_FRIBIDI + strcat(version, " SUPPORTS=FRIBIDI"); +#endif +#ifdef USE_WMS_SVR + strcat(version, " SUPPORTS=WMS_SERVER"); +#endif +#ifdef USE_WMS_LYR + strcat(version, " SUPPORTS=WMS_CLIENT"); +#endif +#ifdef USE_WFS_SVR + strcat(version, " SUPPORTS=WFS_SERVER"); +#endif +#ifdef USE_WFS_LYR + strcat(version, " SUPPORTS=WFS_CLIENT"); +#endif +#ifdef USE_WCS_SVR + strcat(version, " SUPPORTS=WCS_SERVER"); +#endif +#ifdef USE_SOS_SVR + strcat(version, " SUPPORTS=SOS_SERVER"); +#endif +#ifdef USE_OGCAPI_SVR + strcat(version, " SUPPORTS=OGCAPI_SERVER"); +#endif +#ifdef USE_FASTCGI + strcat(version, " SUPPORTS=FASTCGI"); +#endif +#ifdef USE_THREAD + strcat(version, " SUPPORTS=THREADS"); +#endif +#ifdef USE_GEOS + strcat(version, " SUPPORTS=GEOS"); +#endif +#ifdef USE_V8_MAPSCRIPT + strcat(version, " SUPPORTS=V8"); +#endif +#ifdef USE_PBF + strcat(version, " SUPPORTS=PBF"); +#endif +#ifdef USE_JPEG + strcat(version, " INPUT=JPEG"); +#endif +#ifdef USE_SDE + strcat(version, " INPUT=SDE"); +#endif +#ifdef USE_POSTGIS + strcat(version, " INPUT=POSTGIS"); +#endif +#ifdef USE_ORACLESPATIAL + strcat(version, " INPUT=ORACLESPATIAL"); +#endif + strcat(version, " INPUT=OGR"); + strcat(version, " INPUT=GDAL"); + strcat(version, " INPUT=SHAPEFILE"); + strcat(version, " INPUT=FLATGEOBUF"); + return (version); +} + +int msGetVersionInt() { return MS_VERSION_NUM; } diff --git a/src/maperror.h b/src/maperror.h new file mode 100644 index 0000000000..4b0f5e41c0 --- /dev/null +++ b/src/maperror.h @@ -0,0 +1,237 @@ +/****************************************************************************** + * $Id$ + * + * Project: MapServer + * Purpose: Declarations for Error and Debug functions. + * Author: Steve Lime and the MapServer team. + * + ****************************************************************************** + * Copyright (c) 1996-2005 Regents of the University of Minnesota. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + ****************************************************************************/ + +#ifndef MAPERROR_H +#define MAPERROR_H + +#include "mapthread.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*==================================================================== + * maperror.c + *====================================================================*/ + +#define MS_NOERR 0 /* general error codes */ +#define MS_IOERR 1 +#define MS_MEMERR 2 +#define MS_TYPEERR 3 +#define MS_SYMERR 4 +#define MS_REGEXERR 5 +#define MS_TTFERR 6 +#define MS_DBFERR 7 +#define MS_IDENTERR 9 +#define MS_EOFERR 10 +#define MS_PROJERR 11 +#define MS_MISCERR 12 +#define MS_CGIERR 13 +#define MS_WEBERR 14 +#define MS_IMGERR 15 +#define MS_HASHERR 16 +#define MS_JOINERR 17 +#define MS_NOTFOUND 18 /* empty search results */ +#define MS_SHPERR 19 +#define MS_PARSEERR 20 +#define MS_UNUSEDERR 21 +#define MS_OGRERR 22 +#define MS_QUERYERR 23 +#define MS_WMSERR 24 /* WMS server error */ +#define MS_WMSCONNERR 25 /* WMS connectiontype error */ +#define MS_ORACLESPATIALERR 26 +#define MS_WFSERR 27 /* WFS server error */ +#define MS_WFSCONNERR 28 /* WFS connectiontype error */ +#define MS_MAPCONTEXTERR 29 /* Map Context error */ +#define MS_HTTPERR 30 +#define MS_CHILDERR 31 /* Errors involving arrays of child objects */ +#define MS_WCSERR 32 +#define MS_GEOSERR 33 +#define MS_RECTERR 34 +#define MS_TIMEERR 35 +#define MS_GMLERR 36 +#define MS_SOSERR 37 +#define MS_NULLPARENTERR 38 +#define MS_AGGERR 39 +#define MS_OWSERR 40 +#define MS_OGLERR 41 +#define MS_RENDERERERR 42 +#define MS_V8ERR 43 +#define MS_OGCAPIERR 44 +#define MS_FGBERR 45 +/* NOTE to developers: if adding a new constant, increment MS_NUMERRORCODES and + * add a new string in ms_errorCodes[] */ +#define MS_NUMERRORCODES 46 + +#define MESSAGELENGTH 2048 +#define ROUTINELENGTH 64 +#define HTTPSTATUSLENGTH 128 + +#define MS_ERROR_LANGUAGE "en-US" + +#define MS_HTTP_400_BAD_REQUEST "400 Bad Request" +#define MS_HTTP_500_INTERNAL_SERVER_ERROR "500 Internal Server Error" + +#if defined(_WIN32) && !defined(__CYGWIN__) +#define MS_DLL_EXPORT __declspec(dllexport) +#else +#define MS_DLL_EXPORT +#endif + +#ifndef MS_PRINT_FUNC_FORMAT +#if defined(__GNUC__) && __GNUC__ >= 3 && !defined(DOXYGEN_SKIP) +#define MS_PRINT_FUNC_FORMAT(format_idx, arg_idx) \ + __attribute__((__format__(__printf__, format_idx, arg_idx))) +#else +#define MS_PRINT_FUNC_FORMAT(format_idx, arg_idx) +#endif +#endif + +/** +This class allows inspection of the MapServer error stack. +Instances of errorObj are created internally by MapServer as errors happen. +Errors are managed as a chained list with the first item being the most recent +error. +*/ +typedef struct errorObj { + int code; ///< MapServer error code such as :data:`MS_IMGERR` + char + routine[ROUTINELENGTH]; ///< MapServer function in which the error was set + char message[MESSAGELENGTH]; ///< Context-dependent error message + char http_status[HTTPSTATUSLENGTH]; ////< HTTP status + int isreported; ///< :data:`MS_TRUE` or :data:`MS_FALSE` flag indicating if + ///< the error has been output + int errorcount; ///< Number of subsequent errors +#ifndef SWIG + struct errorObj *next; + int totalerrorcount; +#endif +} errorObj; + +/* +** Function prototypes +*/ + +/** +Get the MapServer error object +*/ +MS_DLL_EXPORT errorObj *msGetErrorObj(void); +/** +Clear the list of error objects +*/ +MS_DLL_EXPORT void msResetErrorList(void); +/** +Returns a string containing MapServer version information, and details on what +optional components are built in - the same report as produced by ``mapserv -v`` +*/ +MS_DLL_EXPORT char *msGetVersion(void); +/** +Returns the MapServer version number (x.y.z) as an integer (x*10000 + y*100 + z) +e.g. V7.4.2 would return 70402 +*/ +MS_DLL_EXPORT int msGetVersionInt(void); +/** +Return a string of all errors +*/ +MS_DLL_EXPORT char *msGetErrorString(const char *delimiter); + +#ifndef SWIG +MS_DLL_EXPORT void msRedactCredentials(char *str); +MS_DLL_EXPORT void msSetError(int code, const char *message, + const char *routine, ...) + MS_PRINT_FUNC_FORMAT(2, 4); +void msSetErrorSetIsWMS(int is_wms); +void msSetErrorWithStatus(int ms_errcode, const char *http_status, + const char *message, const char *routine, ...) + MS_PRINT_FUNC_FORMAT(3, 5); +MS_DLL_EXPORT void msWriteError(FILE *stream); +MS_DLL_EXPORT void msWriteErrorXML(FILE *stream); +MS_DLL_EXPORT char *msGetErrorCodeString(int code); +MS_DLL_EXPORT char *msAddErrorDisplayString(char *source, errorObj *error); + +struct mapObj; +MS_DLL_EXPORT void msWriteErrorImage(struct mapObj *map, char *filename, + int blank); + +#endif /* SWIG */ + +/*==================================================================== + * mapdebug.c (See also MS-RFC-28) + *====================================================================*/ + +typedef enum { + MS_DEBUGLEVEL_ERRORSONLY = 0, /* DEBUG OFF, log fatal errors */ + MS_DEBUGLEVEL_DEBUG = 1, /* DEBUG ON */ + MS_DEBUGLEVEL_TUNING = 2, /* Reports timing info */ + MS_DEBUGLEVEL_V = 3, /* Verbose */ + MS_DEBUGLEVEL_VV = 4, /* Very verbose */ + MS_DEBUGLEVEL_VVV = 5, /* Very very verbose */ + MS_DEBUGLEVEL_DEVDEBUG = 20, /* Undocumented, will trigger debug messages only + useful for developers */ +} debugLevel; + +#ifndef SWIG + +typedef enum { + MS_DEBUGMODE_OFF, + MS_DEBUGMODE_FILE, + MS_DEBUGMODE_STDERR, + MS_DEBUGMODE_STDOUT, + MS_DEBUGMODE_WINDOWSDEBUG +} debugMode; + +typedef struct debug_info_obj { + debugLevel global_debug_level; + debugMode debug_mode; + char *errorfile; + FILE *fp; + /* The following 2 members are used only with USE_THREAD (but we won't #ifndef + * them) */ + void *thread_id; + struct debug_info_obj *next; +} debugInfoObj; + +MS_DLL_EXPORT void msDebug(const char *pszFormat, ...) + MS_PRINT_FUNC_FORMAT(1, 2); +MS_DLL_EXPORT int msSetErrorFile(const char *pszErrorFile, + const char *pszRelToPath); +MS_DLL_EXPORT void msCloseErrorFile(void); +MS_DLL_EXPORT const char *msGetErrorFile(void); +MS_DLL_EXPORT void msSetGlobalDebugLevel(int level); +MS_DLL_EXPORT debugLevel msGetGlobalDebugLevel(void); +MS_DLL_EXPORT int msDebugInitFromEnv(void); +MS_DLL_EXPORT void msDebugCleanup(void); + +#endif /* SWIG */ + +#ifdef __cplusplus +} +#endif + +#endif /* MAPERROR_H */ diff --git a/src/mapfile.c b/src/mapfile.c new file mode 100644 index 0000000000..4afe033170 --- /dev/null +++ b/src/mapfile.c @@ -0,0 +1,7677 @@ +/****************************************************************************** + * $id: mapfile.c 7854 2008-08-14 19:22:48Z dmorissette $ + * + * Project: MapServer + * Purpose: High level Map file parsing code. + * Author: Steve Lime and the MapServer team. + * + ****************************************************************************** + * Copyright (c) 1996-2005 Regents of the University of Minnesota. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + ****************************************************************************/ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include +#include +#include +#include + +#include "mapserver.h" +#include "mapfile.h" +#include "mapthread.h" +#include "maptime.h" +#include "mapogcsld.h" + +#include "cpl_conv.h" +#include "cpl_port.h" +#include "cpl_string.h" + +extern int msyylex(void); +extern void msyyrestart(FILE *); +extern int msyylex_destroy(void); +extern void msyycleanup_includes(); + +extern double msyynumber; +extern int msyylineno; +extern FILE *msyyin; + +extern int msyysource; +extern int msyystate; +extern const char *msyystring; +extern char *msyybasepath; +extern int msyyreturncomments; +extern char *msyystring_buffer; +extern int msyystring_icase; + +extern int loadSymbol(symbolObj *s, char *symbolpath); /* in mapsymbol.c */ +extern void writeSymbol(symbolObj *s, FILE *stream); /* in mapsymbol.c */ +static int loadGrid(layerObj *pLayer); +static int loadStyle(styleObj *style); +static void writeStyle(FILE *stream, int indent, styleObj *style); +static int resolveSymbolNames(mapObj *map); +static int loadExpression(expressionObj *exp); +static void writeExpression(FILE *stream, int indent, const char *name, + expressionObj *exp); + +/* +** Symbol to string static arrays needed for writing map files. +** Must be kept in sync with enumerations and defines found in mapserver.h. +*/ +/* static char *msUnits[9]={"INCHES", "FEET", "MILES", "METERS", "KILOMETERS", + * "DD", "PIXELS", "PERCENTAGES", "NAUTICALMILES"}; */ +/* static char *msLayerTypes[10]={"POINT", "LINE", "POLYGON", "RASTER", + * "ANNOTATION", "QUERY", "CIRCLE", "TILEINDEX","CHART"}; */ +char *msPositionsText[MS_POSITIONS_LENGTH] = { + "UL", "LR", "UR", "LL", "CR", "CL", "UC", + "LC", "CC", "AUTO", "XY", "FOLLOW"}; /* msLabelPositions[] also used in + mapsymbols.c (not static) */ +/* static char *msBitmapFontSizes[5]={"TINY", "SMALL", "MEDIUM", "LARGE", + * "GIANT"}; */ +/* static char *msQueryMapStyles[4]={"NORMAL", "HILITE", "SELECTED", + * "INVERTED"}; */ +/* static char *msStatus[4]={"OFF", "ON", "DEFAULT", "EMBED"}; */ +/* static char *msOnOff[2]={"OFF", "ON"}; */ +/* static char *msTrueFalse[2]={"FALSE", "TRUE"}; */ +/* static char *msYesNo[2]={"NO", "YES"}; */ +/* static char *msJoinType[2]={"ONE-TO-ONE", "ONE-TO-MANY"}; */ +/* static char *msAlignValue[3]={"LEFT","CENTER","RIGHT"}; */ + +/* +** Validates a string (value) against a series of patterns. We support up to +*four to allow cascading from classObj to +** layerObj to webObj plus a legacy pattern like TEMPLATEPATTERN. +*/ +int msValidateParameter(const char *value, const char *pattern1, + const char *pattern2, const char *pattern3, + const char *pattern4) { + if (msEvalRegex(pattern1, value) == MS_TRUE) + return MS_SUCCESS; + if (msEvalRegex(pattern2, value) == MS_TRUE) + return MS_SUCCESS; + if (msEvalRegex(pattern3, value) == MS_TRUE) + return MS_SUCCESS; + if (msEvalRegex(pattern4, value) == MS_TRUE) + return MS_SUCCESS; + + return (MS_FAILURE); +} + +int msIsValidRegex(const char *e) { + ms_regex_t re; + int errcode = ms_regcomp(&re, e, MS_REG_EXTENDED | MS_REG_NOSUB); + if (errcode != 0) { + char szErrbuf[256]; + ms_regerror(errcode, &re, szErrbuf, sizeof(szErrbuf)); + msSetError(MS_REGEXERR, "Failed to compile expression (%s): %s.", + "msIsValidRegex()", e, szErrbuf); + return (MS_FALSE); + } + ms_regfree(&re); + return MS_TRUE; +} + +int msEvalRegex(const char *e, const char *s) { + ms_regex_t re; + + if (!e || !s) + return (MS_FALSE); + + int errcode = ms_regcomp(&re, e, MS_REG_EXTENDED | MS_REG_NOSUB); + if (errcode != 0) { + char szErrbuf[256]; + ms_regerror(errcode, &re, szErrbuf, sizeof(szErrbuf)); + msSetError(MS_REGEXERR, "Failed to compile expression (%s): %s.", + "msEvalRegex()", e, szErrbuf); + return (MS_FALSE); + } + + if (ms_regexec(&re, s, 0, NULL, 0) != 0) { /* no match */ + ms_regfree(&re); + return (MS_FALSE); + } + ms_regfree(&re); + + return (MS_TRUE); +} + +int msCaseEvalRegex(const char *e, const char *s) { + ms_regex_t re; + + if (!e || !s) + return (MS_FALSE); + + if (ms_regcomp(&re, e, MS_REG_EXTENDED | MS_REG_ICASE | MS_REG_NOSUB) != 0) { + msSetError(MS_REGEXERR, "Failed to compile expression (%s).", + "msEvalRegex()", e); + return (MS_FALSE); + } + + if (ms_regexec(&re, s, 0, NULL, 0) != 0) { /* no match */ + ms_regfree(&re); + return (MS_FALSE); + } + ms_regfree(&re); + + return (MS_TRUE); +} + +#ifdef USE_MSFREE +void msFree(void *p) { + if (p) + free(p); +} +#endif + +/* +** Free memory allocated for a character array +*/ +void msFreeCharArray(char **array, int num_items) { + int i; + if (!array) + return; + for (i = 0; i < num_items; i++) + msFree(array[i]); + msFree(array); +} + +/* +** Checks symbol from lexer against variable length list of +** legal symbols. +*/ +int getSymbol(int n, ...) { + int symbol; + va_list argp; + int i = 0; + + symbol = msyylex(); + + va_start(argp, n); + while (i < n) { /* check each symbol in the list */ + if (symbol == va_arg(argp, int)) { + va_end(argp); + return (symbol); + } + i++; + } + + va_end(argp); + + msSetError(MS_SYMERR, "Parsing error near (%s):(line %d)", "getSymbol()", + msyystring_buffer, msyylineno); + return (-1); +} + +/* +** Same as getSymbol, except no error message is set on failure +*/ +int getSymbol2(int n, ...) { + int symbol; + va_list argp; + int i = 0; + + symbol = msyylex(); + + va_start(argp, n); + while (i < n) { /* check each symbol in the list */ + if (symbol == va_arg(argp, int)) { + va_end(argp); + return (symbol); + } + i++; + } + + va_end(argp); + return (-1); +} + +/* +** Get a string or symbol as a string. Operates like getString(), but also +** supports symbols. +*/ +static char *getToken(void) { + msyylex(); + return msStrdup(msyystring_buffer); +} + +/* +** Load a string from the map file. A "string" is defined in lexer.l. +*/ +int getString(char **s) { + /* if (*s) + msSetError(MS_SYMERR, "Duplicate item (%s):(line %d)", "getString()", + msyystring_buffer, msyylineno); return(MS_FAILURE); } else */ + if (msyylex() == MS_STRING) { + if (*s) + free(*s); /* avoid leak */ + *s = msStrdup(msyystring_buffer); + return (MS_SUCCESS); + } + + msSetError(MS_SYMERR, "Parsing error near (%s):(line %d)", "getString()", + msyystring_buffer, msyylineno); + return (MS_FAILURE); +} + +int msCheckNumber(double number, int num_check_type, double value1, + double value2) { + if (num_check_type == MS_NUM_CHECK_NONE) { + return MS_SUCCESS; + } else if (num_check_type == MS_NUM_CHECK_RANGE && number >= value1 && + number <= value2) { + return MS_SUCCESS; + } else if (num_check_type == MS_NUM_CHECK_GT && number > value1) { + return MS_SUCCESS; + } else if (num_check_type == MS_NUM_CHECK_GTE && number >= value1) { + return MS_SUCCESS; + } + + return MS_FAILURE; +} + +/* +** Load a floating point number from the map file. (see lexer.l) +*/ +int getDouble(double *d, int num_check_type, double value1, double value2) { + if (msyylex() == MS_NUMBER) { + if (msCheckNumber(msyynumber, num_check_type, value1, value2) == + MS_SUCCESS) { + *d = msyynumber; + return (0); + } + } + + msSetError(MS_SYMERR, "Parsing error near (%s):(line %d)", "getDouble()", + msyystring_buffer, msyylineno); + return (-1); +} + +/* +** Load a integer from the map file. (see lexer.l) +*/ +int getInteger(int *i, int num_check_type, int value1, int value2) { + if (msyylex() == MS_NUMBER) { + if (msCheckNumber(msyynumber, num_check_type, value1, value2) == + MS_SUCCESS) { + *i = (int)msyynumber; + return (0); + } + } + + msSetError(MS_SYMERR, "Parsing error near (%s):(line %d)", "getInteger()", + msyystring_buffer, msyylineno); + return (-1); +} + +int getCharacter(char *c) { + if (msyylex() == MS_STRING) { + *c = msyystring_buffer[0]; + return (0); + } + + msSetError(MS_SYMERR, "Parsing error near (%s):(line %d)", "getCharacter()", + msyystring_buffer, msyylineno); + return (-1); +} + +/* +** Try to load as an integer, then try as a named symbol. +** Part of work on bug 490. +*/ +int getIntegerOrSymbol(int *i, int n, ...) { + int symbol; + va_list argp; + int j = 0; + + symbol = msyylex(); + + if (symbol == MS_NUMBER) { + *i = (int)msyynumber; + return MS_SUCCESS; /* success */ + } + + va_start(argp, n); + while (j < n) { /* check each symbol in the list */ + if (symbol == va_arg(argp, int)) { + va_end(argp); + *i = symbol; + return MS_SUCCESS; + } + j++; + } + va_end(argp); + + msSetError(MS_SYMERR, "Parsing error near (%s):(line %d)", + "getIntegerOrSymbol()", msyystring_buffer, msyylineno); + return (-1); +} + +/* +** msBuildPluginLibraryPath +** +** This function builds a path to be used dynamically to load plugin library. +*/ +int msBuildPluginLibraryPath(char **dest, const char *lib_str, mapObj *map) { + char szLibPath[MS_MAXPATHLEN] = {'\0'}; + char szLibPathExt[MS_MAXPATHLEN] = {'\0'}; + const char *plugin_dir = NULL; + + if (map) + plugin_dir = msLookupHashTable(&(map->configoptions), "MS_PLUGIN_DIR"); + + /* do nothing on windows, filename without .dll will be loaded by default*/ +#if !defined(_WIN32) + if (lib_str) { + size_t len = strlen(lib_str); + if (3 < len && strcmp(lib_str + len - 3, ".so")) { + strlcpy(szLibPathExt, lib_str, MS_MAXPATHLEN); + strlcat(szLibPathExt, ".so", MS_MAXPATHLEN); + lib_str = szLibPathExt; + } + } +#endif /* !defined(_WIN32) */ + if (NULL == msBuildPath(szLibPath, plugin_dir, lib_str)) { + return MS_FAILURE; + } + msFree(*dest); + *dest = msStrdup(szLibPath); + + return MS_SUCCESS; +} + +/* +** Returns the index of specified symbol or -1 if not found. +** +** If try_addimage_if_notfound==MS_TRUE then msAddImageSymbol() will be called +** to try to allocate the symbol as an image symbol. +*/ +int msGetSymbolIndex(symbolSetObj *symbols, const char *name, + int try_addimage_if_notfound) { + int i; + + if (!symbols || !name) + return (-1); + + /* symbol 0 has no name */ + for (i = 1; i < symbols->numsymbols; i++) { + if (symbols->symbol[i]->name) + if (strcasecmp(symbols->symbol[i]->name, name) == 0) + return (i); + } + + if (try_addimage_if_notfound) + return ( + msAddImageSymbol(symbols, name)); /* make sure it's not a filename */ + + return (-1); +} + +/* +** Return the index number for a given layer based on its name. +*/ +int msGetLayerIndex(mapObj *map, const char *name) { + int i; + + if (!name) + return (-1); + + for (i = 0; i < map->numlayers; i++) { + if (!GET_LAYER(map, i)->name) /* skip it */ + continue; + if (strcmp(name, GET_LAYER(map, i)->name) == 0) + return (i); + } + return (-1); +} + +int loadColor(colorObj *color, attributeBindingObj *binding) { + int symbol; + char hex[2]; + + /* + ** Note that negative color values can be used to suppress or change behavior. + *For example, referenceObj uses + ** a negative color component to suppress rectangle fills. + */ + + if (binding) { + if ((symbol = getSymbol(3, MS_NUMBER, MS_BINDING, MS_STRING)) == -1) + return MS_FAILURE; + } else { + if ((symbol = getSymbol(2, MS_NUMBER, MS_STRING)) == -1) + return MS_FAILURE; + } + + color->alpha = 255; + if (symbol == MS_NUMBER) { + if (msyynumber >= -255 && msyynumber <= 255) { + color->red = (int)msyynumber; + } else { + return MS_FAILURE; + } + if (getInteger(&(color->green), MS_NUM_CHECK_RANGE, -255, 255) == -1) + return MS_FAILURE; + if (getInteger(&(color->blue), MS_NUM_CHECK_RANGE, -255, 255) == -1) + return MS_FAILURE; + } else if (symbol == MS_STRING) { + int len = strlen(msyystring_buffer); + if (msyystring_buffer[0] == '#' && + (len == 7 || len == 9)) { /* got a hex color w/optional alpha */ + hex[0] = msyystring_buffer[1]; + hex[1] = msyystring_buffer[2]; + color->red = msHexToInt(hex); + hex[0] = msyystring_buffer[3]; + hex[1] = msyystring_buffer[4]; + color->green = msHexToInt(hex); + hex[0] = msyystring_buffer[5]; + hex[1] = msyystring_buffer[6]; + color->blue = msHexToInt(hex); + if (len == 9) { + hex[0] = msyystring_buffer[7]; + hex[1] = msyystring_buffer[8]; + color->alpha = msHexToInt(hex); + } + } else { + /* TODO: consider named colors here */ + msSetError(MS_SYMERR, "Invalid hex color (%s):(line %d)", "loadColor()", + msyystring_buffer, msyylineno); + return MS_FAILURE; + } + } else { + assert(binding); + msFree(binding->item); + binding->item = msStrdup(msyystring_buffer); + binding->index = -1; + } + + return MS_SUCCESS; +} + +#if ALPHACOLOR_ENABLED +int loadColorWithAlpha(colorObj *color) { + char hex[2]; + + /* + ** Note that negative color values can be used to suppress or change behavior. + *For example, referenceObj uses + ** a negative color component to suppress rectangle fills. + */ + + if (getInteger(&(color->red), MS_NUM_CHECK_RANGE, -255, 255) == -1) { + if (msyystring_buffer[0] == '#' && + strlen(msyystring_buffer) == 7) { /* got a hex color */ + hex[0] = msyystring_buffer[1]; + hex[1] = msyystring_buffer[2]; + color->red = msHexToInt(hex); + hex[0] = msyystring_buffer[3]; + hex[1] = msyystring_buffer[4]; + color->green = msHexToInt(hex); + hex[0] = msyystring_buffer[5]; + hex[1] = msyystring_buffer[6]; + color->blue = msHexToInt(hex); + color->alpha = 0; + + return (MS_SUCCESS); + } else if (msyystring_buffer[0] == '#' && + strlen(msyystring_buffer) == + 9) { /* got a hex color with alpha */ + hex[0] = msyystring_buffer[1]; + hex[1] = msyystring_buffer[2]; + color->red = msHexToInt(hex); + hex[0] = msyystring_buffer[3]; + hex[1] = msyystring_buffer[4]; + color->green = msHexToInt(hex); + hex[0] = msyystring_buffer[5]; + hex[1] = msyystring_buffer[6]; + color->blue = msHexToInt(hex); + hex[0] = msyystring_buffer[7]; + hex[1] = msyystring_buffer[8]; + color->alpha = msHexToInt(hex); + return (MS_SUCCESS); + } + return (MS_FAILURE); + } + if (getInteger(&(color->green), MS_NUM_CHECK_RANGE, -255, 255) == -1) + return (MS_FAILURE); + if (getInteger(&(color->blue), MS_NUM_CHECK_RANGE, -255, 255) == -1) + return (MS_FAILURE); + if (getInteger(&(color->alpha), MS_NUM_CHECK_RANGE, 0, 255) == -1) + return (MS_FAILURE); + + return (MS_SUCCESS); +} +#endif + +/* +** Helper functions for writing mapfiles. +*/ +static void writeLineFeed(FILE *stream) { msIO_fprintf(stream, "\n"); } + +static void writeIndent(FILE *stream, int indent) { + const char *str = " "; /* change this string to define the indent */ + int i; + for (i = 0; i < indent; i++) + msIO_fprintf(stream, "%s", str); +} + +static void writeBlockBegin(FILE *stream, int indent, const char *name) { + writeIndent(stream, indent); + msIO_fprintf(stream, "%s\n", name); +} + +static void writeBlockEnd(FILE *stream, int indent, const char *name) { + writeIndent(stream, indent); + msIO_fprintf(stream, "END # %s\n", name); +} + +static void writeKeyword(FILE *stream, int indent, const char *name, int value, + int size, ...) { + va_list argp; + int i, j = 0; + const char *s; + + va_start(argp, size); + while (j < size) { /* check each value/keyword mapping in the list, values + with no match are ignored */ + i = va_arg(argp, int); + s = va_arg(argp, const char *); + if (value == i) { + writeIndent(stream, ++indent); + msIO_fprintf(stream, "%s %s\n", name, s); + va_end(argp); + return; + } + j++; + } + va_end(argp); +} + +static void writeDimension(FILE *stream, int indent, const char *name, double x, + double y, char *bind_x, char *bind_y) { + writeIndent(stream, ++indent); + if (bind_x) + msIO_fprintf(stream, "%s [%s] ", name, bind_x); + else + msIO_fprintf(stream, "%s %.15g ", name, x); + if (bind_y) + msIO_fprintf(stream, "[%s]\n", bind_y); + else + msIO_fprintf(stream, "%.15g\n", y); +} + +static void writeDoubleRange(FILE *stream, int indent, const char *name, + double x, double y) { + writeIndent(stream, ++indent); + msIO_fprintf(stream, "%s %f %f\n", name, x, y); +} + +static void writeExtent(FILE *stream, int indent, const char *name, + rectObj extent) { + if (!MS_VALID_EXTENT(extent)) + return; + writeIndent(stream, ++indent); + msIO_fprintf(stream, "%s %.15g %.15g %.15g %.15g\n", name, extent.minx, + extent.miny, extent.maxx, extent.maxy); +} + +static void writeNumber(FILE *stream, int indent, const char *name, + double defaultNumber, double number) { + if (number == defaultNumber) + return; /* don't output default */ + writeIndent(stream, ++indent); + msIO_fprintf(stream, "%s %.15g\n", name, number); +} + +static void writeCharacter(FILE *stream, int indent, const char *name, + const char defaultCharacter, char character) { + if (defaultCharacter == character) + return; + writeIndent(stream, ++indent); + msIO_fprintf(stream, "%s '%c'\n", name, character); +} + +static void writeStringElement(FILE *stream, const char *string) { + char *string_to_free = NULL; + const char *string_escaped; + + if (strchr(string, '\\')) { + string_to_free = msStrdup(string); + string_to_free = msReplaceSubstring(string_to_free, "\\", "\\\\"); + string_escaped = string_to_free; + } else { + string_escaped = string; + } + if ((strchr(string_escaped, '\'') == NULL) && + (strchr(string_escaped, '\"') == NULL)) + msIO_fprintf(stream, "\"%s\"", string_escaped); + else if ((strchr(string_escaped, '\"') != NULL) && + (strchr(string_escaped, '\'') == NULL)) + msIO_fprintf(stream, "'%s'", string_escaped); + else if ((strchr(string_escaped, '\'') != NULL) && + (strchr(string_escaped, '\"') == NULL)) + msIO_fprintf(stream, "\"%s\"", string_escaped); + else { + char *string_tmp = msStringEscape(string_escaped); + msIO_fprintf(stream, "\"%s\"", string_tmp); + if (string_escaped != string_tmp) + free(string_tmp); + } + if (string_to_free) + free(string_to_free); +} + +static void writeString(FILE *stream, int indent, const char *name, + const char *defaultString, const char *string) { + if (!string) + return; + if (defaultString && strcmp(string, defaultString) == 0) + return; + writeIndent(stream, ++indent); + if (name) + msIO_fprintf(stream, "%s ", name); + writeStringElement(stream, string); + writeLineFeed(stream); +} + +static void writeNumberOrString(FILE *stream, int indent, const char *name, + double defaultNumber, double number, + char *string) { + if (string) + writeString(stream, indent, name, NULL, string); + else + writeNumber(stream, indent, name, defaultNumber, number); +} + +static void writeNumberOrKeyword(FILE *stream, int indent, const char *name, + double defaultNumber, double number, int value, + int size, ...) { + va_list argp; + int i, j = 0; + const char *s; + + va_start(argp, size); + while (j < size) { /* check each value/keyword mapping in the list */ + i = va_arg(argp, int); + s = va_arg(argp, const char *); + if (value == i) { + writeIndent(stream, ++indent); + msIO_fprintf(stream, "%s %s\n", name, s); + va_end(argp); + return; + } + j++; + } + va_end(argp); + + writeNumber(stream, indent, name, defaultNumber, number); +} + +static void writeNameValuePair(FILE *stream, int indent, const char *name, + const char *value) { + if (!name || !value) + return; + writeIndent(stream, ++indent); + + writeStringElement(stream, (char *)name); + msIO_fprintf(stream, "\t"); + writeStringElement(stream, (char *)value); + writeLineFeed(stream); +} + +static void writeAttributeBinding(FILE *stream, int indent, const char *name, + attributeBindingObj *binding) { + if (!binding || !binding->item) + return; + writeIndent(stream, ++indent); + msIO_fprintf(stream, "%s [%s]\n", name, binding->item); +} + +static void writeColor(FILE *stream, int indent, const char *name, + colorObj *defaultColor, colorObj *color) { + if (!defaultColor && !MS_VALID_COLOR(*color)) + return; + else if (defaultColor && MS_COMPARE_COLOR(*defaultColor, *color)) + return; /* if defaultColor has the same value than the color, return.*/ + + writeIndent(stream, ++indent); +#if ALPHACOLOR_ENABLED + msIO_fprintf(stream, "%s %d %d %d\n", name, color->red, color->green, + color->blue, color->alpha); +#else + if (color->alpha != 255) { + char buffer[9]; + sprintf(buffer, "%02x", color->red); + sprintf(buffer + 2, "%02x", color->green); + sprintf(buffer + 4, "%02x", color->blue); + sprintf(buffer + 6, "%02x", color->alpha); + *(buffer + 8) = 0; + msIO_fprintf(stream, "%s \"#%s\"\n", name, buffer); + } else { + msIO_fprintf(stream, "%s %d %d %d\n", name, color->red, color->green, + color->blue); + } +#endif +} + +/* todo: deal with alpha's... */ +static void writeColorRange(FILE *stream, int indent, const char *name, + colorObj *mincolor, colorObj *maxcolor) { + if (!MS_VALID_COLOR(*mincolor) || !MS_VALID_COLOR(*maxcolor)) + return; + writeIndent(stream, ++indent); + msIO_fprintf(stream, "%s %d %d %d %d %d %d\n", name, mincolor->red, + mincolor->green, mincolor->blue, maxcolor->red, maxcolor->green, + maxcolor->blue); +} + +/* +** Initialize, load and free a single join +*/ +void initJoin(joinObj *join) { + join->numitems = 0; + + join->name = NULL; /* unique join name, used for variable substitution */ + + join->items = NULL; /* array to hold item names for the joined table */ + join->values = NULL; /* arrays of strings to holds one record worth of data */ + + join->table = NULL; + + join->joininfo = NULL; + + join->from = NULL; /* join items */ + join->to = NULL; + + join->header = NULL; + join->template = NULL; /* only html type templates are supported */ + join->footer = NULL; + + join->type = MS_JOIN_ONE_TO_ONE; + + join->connection = NULL; + join->connectiontype = MS_DB_XBASE; +} + +void freeJoin(joinObj *join) { + msFree(join->name); + msFree(join->table); + msFree(join->from); + msFree(join->to); + + msFree(join->header); + msFree(join->template); + msFree(join->footer); + + msFreeCharArray(join->items, + join->numitems); /* these may have been free'd elsewhere */ + msFreeCharArray(join->values, join->numitems); + join->numitems = 0; + + msJoinClose(join); + msFree(join->connection); +} + +int loadJoin(joinObj *join) { + int nTmp; + initJoin(join); + + for (;;) { + switch (msyylex()) { + case (CONNECTION): + if (getString(&join->connection) == MS_FAILURE) + return (-1); + break; + case (CONNECTIONTYPE): + if ((nTmp = getSymbol(5, MS_DB_XBASE, MS_DB_MYSQL, MS_DB_ORACLE, + MS_DB_POSTGRES, MS_DB_CSV)) == -1) + return (-1); + join->connectiontype = nTmp; + break; + case (EOF): + msSetError(MS_EOFERR, NULL, "loadJoin()"); + return (-1); + case (END): + if ((join->from == NULL) || (join->to == NULL) || (join->table == NULL)) { + msSetError(MS_EOFERR, + "Join must define table, name, from and to properties.", + "loadJoin()"); + return (-1); + } + if ((join->type == MS_MULTIPLE) && + ((join->template == NULL) || (join->name == NULL))) { + msSetError( + MS_EOFERR, + "One-to-many joins must define template and name properties.", + "loadJoin()"); + return (-1); + } + return (0); + case (FOOTER): + if (getString(&join->footer) == MS_FAILURE) + return (-1); + break; + case (FROM): + if (getString(&join->from) == MS_FAILURE) + return (-1); + break; + case (HEADER): + if (getString(&join->header) == MS_FAILURE) + return (-1); + break; + case (JOIN): + break; /* for string loads */ + case (NAME): + if (getString(&join->name) == MS_FAILURE) + return (-1); + break; + case (TABLE): + if (getString(&join->table) == MS_FAILURE) + return (-1); + break; + case (TEMPLATE): + if (getString(&join->template) == MS_FAILURE) + return (-1); + break; + case (TO): + if (getString(&join->to) == MS_FAILURE) + return (-1); + break; + case (TYPE): + if ((nTmp = getSymbol(2, MS_JOIN_ONE_TO_ONE, MS_JOIN_ONE_TO_MANY)) == -1) + return (-1); + join->type = nTmp; + break; + default: + msSetError(MS_IDENTERR, "Parsing error near (%s):(line %d)", "loadJoin()", + msyystring_buffer, msyylineno); + return (-1); + } + } /* next token */ +} + +static void writeScaleToken(FILE *stream, int indent, scaleTokenObj *token) { + int i; + indent++; + writeBlockBegin(stream, indent, "SCALETOKEN"); + writeString(stream, indent, "NAME", NULL, token->name); + indent++; + writeBlockBegin(stream, indent, "VALUES"); + for (i = 0; i < token->n_entries; i++) { + char minscale[32]; + sprintf(minscale, "%g", token->tokens[i].minscale); + writeNameValuePair(stream, indent, minscale, token->tokens[i].value); + } + writeBlockEnd(stream, indent, "VALUES"); + indent--; + writeBlockEnd(stream, indent, "SCALETOKEN"); +} + +static void writeJoin(FILE *stream, int indent, joinObj *join) { + indent++; + writeBlockBegin(stream, indent, "JOIN"); + writeString(stream, indent, "FOOTER", NULL, join->footer); + writeString(stream, indent, "FROM", NULL, join->from); + writeString(stream, indent, "HEADER", NULL, join->header); + writeString(stream, indent, "NAME", NULL, join->name); + writeString(stream, indent, "TABLE", NULL, join->table); + writeString(stream, indent, "TEMPLATE", NULL, join->template); + writeString(stream, indent, "TO", NULL, join->to); + writeKeyword(stream, indent, "CONNECTIONTYPE", join->connectiontype, 3, + MS_DB_CSV, "CSV", MS_DB_POSTGRES, "POSTGRESQL", MS_DB_MYSQL, + "MYSQL"); + writeKeyword(stream, indent, "TYPE", join->type, 1, MS_JOIN_ONE_TO_MANY, + "ONE-TO-MANY"); + writeBlockEnd(stream, indent, "JOIN"); +} + +/* inserts a feature at the end of the list, can create a new list */ +featureListNodeObjPtr insertFeatureList(featureListNodeObjPtr *list, + shapeObj *shape) { + featureListNodeObjPtr node; + + node = (featureListNodeObjPtr)msSmallMalloc(sizeof(featureListNodeObj)); + + msInitShape(&(node->shape)); + if (msCopyShape(shape, &(node->shape)) == -1) { + msFree(node); + return (NULL); + } + + /* AJS - alans@wunderground.com O(n^2) -> O(n) conversion, keep a pointer to + * the end */ + + /* set the tailifhead to NULL, since it is only set for the head of the list + */ + node->tailifhead = NULL; + node->next = NULL; + + /* if we are at the head of the list, we need to set the list to node, before + * pointing tailifhead somewhere */ + if (*list == NULL) { + *list = node; + } else { + if ((*list)->tailifhead != + NULL) /* this should never be NULL, but just in case */ + (*list)->tailifhead->next = + node; /* put the node at the end of the list */ + } + + /* repoint the head of the list to the end - our new element + this causes a loop if we are at the head, be careful not to + walk in a loop */ + (*list)->tailifhead = node; + + return (node); /* a pointer to last object in the list */ +} + +void freeFeatureList(featureListNodeObjPtr list) { + featureListNodeObjPtr listNext = NULL; + while (list != NULL) { + listNext = list->next; + msFreeShape(&(list->shape)); + msFree(list); + list = listNext; + } +} + +/* lineObj = multipointObj */ +static int loadFeaturePoints(lineObj *points) { + int ret = -1; + int buffer_size = 0; + + points->point = (pointObj *)malloc(sizeof(pointObj) * MS_FEATUREINITSIZE); + MS_CHECK_ALLOC(points->point, sizeof(pointObj) * MS_FEATUREINITSIZE, + MS_FAILURE); + points->numpoints = 0; + buffer_size = MS_FEATUREINITSIZE; + + while (ret < 0) { + switch (msyylex()) { + case (EOF): + msSetError(MS_EOFERR, NULL, "loadFeaturePoints()"); + ret = MS_FAILURE; + break; + case (END): + ret = MS_SUCCESS; + break; + case (MS_NUMBER): + if (points->numpoints == buffer_size) { /* just add it to the end */ + pointObj *newPoints = (pointObj *)realloc( + points->point, + sizeof(pointObj) * (buffer_size + MS_FEATUREINCREMENT)); + if (newPoints == NULL) { + msSetError(MS_MEMERR, "%s: %d: Out of memory allocating %u bytes.\n", + __FUNCTION__, __FILE__, __LINE__, + (unsigned int)(sizeof(pointObj) * + (buffer_size + MS_FEATUREINCREMENT))); + ret = MS_FAILURE; + break; + } + points->point = newPoints; + buffer_size += MS_FEATUREINCREMENT; + } + + points->point[points->numpoints].x = atof(msyystring_buffer); + if (getDouble(&(points->point[points->numpoints].y), MS_NUM_CHECK_NONE, + -1, -1) == -1) { + ret = MS_FAILURE; + break; + } + points->numpoints++; + break; + default: + msSetError(MS_IDENTERR, "Parsing error near (%s):(line %d)", + "loadFeaturePoints()", msyystring_buffer, msyylineno); + ret = MS_FAILURE; + break; + } + } + + if (ret == MS_FAILURE) { + msFree(points->point); /* clean up */ + points->point = NULL; + points->numpoints = 0; + } + return ret; +} + +static int loadFeature(layerObj *player, int type) { + int status = MS_SUCCESS; + featureListNodeObjPtr *list = &(player->features); + multipointObj points = {0, NULL}; + shapeObj *shape = NULL; + + shape = (shapeObj *)malloc(sizeof(shapeObj)); + MS_CHECK_ALLOC(shape, sizeof(shapeObj), MS_FAILURE); + + msInitShape(shape); + shape->type = type; + + for (;;) { + switch (msyylex()) { + case (EOF): + msSetError(MS_EOFERR, NULL, "loadFeature()"); + msFreeShape(shape); /* clean up */ + msFree(shape); + return (MS_FAILURE); + case (END): + if (player->features != NULL && player->features->tailifhead != NULL) + shape->index = player->features->tailifhead->shape.index + 1; + else + shape->index = 0; + if (insertFeatureList(list, shape) == NULL) + status = MS_FAILURE; + + msFreeShape(shape); /* clean up */ + msFree(shape); + + return (status); + case (FEATURE): + break; /* for string loads */ + case (POINTS): + if (loadFeaturePoints(&points) == MS_FAILURE) { + msFreeShape(shape); /* clean up */ + msFree(shape); + return (MS_FAILURE); + } + status = msAddLine(shape, &points); + + msFree(points.point); /* clean up */ + points.numpoints = 0; + + if (status == MS_FAILURE) { + msFreeShape(shape); /* clean up */ + msFree(shape); + return (MS_FAILURE); + } + break; + case (ITEMS): { + char *string = NULL; + if (getString(&string) == MS_FAILURE) { + msFreeShape(shape); /* clean up */ + msFree(shape); + return (MS_FAILURE); + } + if (string) { + if (shape->values) + msFreeCharArray(shape->values, shape->numvalues); + shape->values = msStringSplitComplex(string, ";", &shape->numvalues, + MS_ALLOWEMPTYTOKENS); + msFree(string); /* clean up */ + } + break; + } + case (TEXT): + if (getString(&shape->text) == MS_FAILURE) { + msFreeShape(shape); /* clean up */ + msFree(shape); + return (MS_FAILURE); + } + break; + case (WKT): { + char *string = NULL; + + /* todo, what do we do with multiple WKT property occurrences? */ + + msFreeShape(shape); + msFree(shape); + if (getString(&string) == MS_FAILURE) + return (MS_FAILURE); + + if ((shape = msShapeFromWKT(string)) == NULL) + status = MS_FAILURE; + + msFree(string); /* clean up */ + + if (status == MS_FAILURE) { + msFreeShape(shape); /* clean up */ + msFree(shape); + return (MS_FAILURE); + } + break; + } + default: + msSetError(MS_IDENTERR, "Parsing error near (%s):(line %d)", + "loadfeature()", msyystring_buffer, msyylineno); + msFreeShape(shape); /* clean up */ + msFree(shape); + return (MS_FAILURE); + } + } /* next token */ +} + +static void writeFeature(FILE *stream, int indent, shapeObj *feature) { + int i, j; + + indent++; + writeBlockBegin(stream, indent, "FEATURE"); + + indent++; + for (i = 0; i < feature->numlines; i++) { + writeBlockBegin(stream, indent, "POINTS"); + for (j = 0; j < feature->line[i].numpoints; j++) { + writeIndent(stream, indent); + msIO_fprintf(stream, "%.15g %.15g\n", feature->line[i].point[j].x, + feature->line[i].point[j].y); + } + writeBlockEnd(stream, indent, "POINTS"); + } + indent--; + + if (feature->numvalues) { + writeIndent(stream, indent); + msIO_fprintf(stream, "ITEMS \""); + for (i = 0; i < feature->numvalues; i++) { + if (i == 0) + msIO_fprintf(stream, "%s", feature->values[i]); + else + msIO_fprintf(stream, ";%s", feature->values[i]); + } + msIO_fprintf(stream, "\"\n"); + } + + writeString(stream, indent, "TEXT", NULL, feature->text); + writeBlockEnd(stream, indent, "FEATURE"); +} + +void initGrid(graticuleObj *pGraticule) { + memset(pGraticule, 0, sizeof(graticuleObj)); +} + +void freeGrid(graticuleObj *pGraticule) { + msFree(pGraticule->labelformat); + msFree(pGraticule->pboundingpoints); + msFree(pGraticule->pboundinglines); +} + +static int loadGrid(layerObj *pLayer) { + for (;;) { + switch (msyylex()) { + case (EOF): + msSetError(MS_EOFERR, NULL, "loadGrid()"); + return (-1); + case (END): + return (0); + case (GRID): + break; /* for string loads */ + case (LABELFORMAT): + if (getString(&(pLayer->grid->labelformat)) == MS_FAILURE) { + if (strcasecmp(msyystring_buffer, "DD") == + 0) /* DD triggers a symbol to be returned instead of a string so + check for this special case */ + { + msFree(pLayer->grid->labelformat); + pLayer->grid->labelformat = msStrdup("DD"); + } else + return (-1); + } + break; + case (MINARCS): + if (getDouble(&(pLayer->grid->minarcs), MS_NUM_CHECK_GT, 0, -1) == -1) + return (-1); + break; + case (MAXARCS): + if (getDouble(&(pLayer->grid->maxarcs), MS_NUM_CHECK_GT, 0, -1) == -1) + return (-1); + break; + case (MININTERVAL): + if (getDouble(&(pLayer->grid->minincrement), MS_NUM_CHECK_GT, 0, -1) == + -1) + return (-1); + break; + case (MAXINTERVAL): + if (getDouble(&(pLayer->grid->maxincrement), MS_NUM_CHECK_GT, 0, -1) == + -1) + return (-1); + break; + case (MINSUBDIVIDE): + if (getDouble(&(pLayer->grid->minsubdivides), MS_NUM_CHECK_GT, 0, -1) == + -1) + return (-1); + break; + case (MAXSUBDIVIDE): + if (getDouble(&(pLayer->grid->maxsubdivides), MS_NUM_CHECK_GT, 0, -1) == + -1) + return (-1); + break; + default: + msSetError(MS_IDENTERR, "Parsing error near (%s):(line %d)", "loadGrid()", + msyystring_buffer, msyylineno); + return (-1); + } + } +} + +static void writeGrid(FILE *stream, int indent, graticuleObj *pGraticule) { + if (!pGraticule) + return; + + indent++; + writeBlockBegin(stream, indent, "GRID"); + writeString(stream, indent, "LABELFORMAT", NULL, pGraticule->labelformat); + writeNumber(stream, indent, "MAXARCS", 0, pGraticule->maxarcs); + writeNumber(stream, indent, "MAXSUBDIVIDE", 0, pGraticule->maxsubdivides); + writeNumber(stream, indent, "MAXINTERVAL", 0, pGraticule->maxincrement); + writeNumber(stream, indent, "MINARCS", 0, pGraticule->minarcs); + writeNumber(stream, indent, "MININTERVAL", 0, pGraticule->minincrement); + writeNumber(stream, indent, "MINSUBDIVIDE", 0, pGraticule->minsubdivides); + writeBlockEnd(stream, indent, "GRID"); +} + +static int loadProjection(projectionObj *p, mapObj *map) { + p->gt.need_geotransform = MS_FALSE; + + if (p->proj != NULL || p->numargs != 0) { + msSetError(MS_MISCERR, + "Projection is already initialized. Multiple projection " + "definitions are not allowed in this object. (line %d)", + "loadProjection()", msyylineno); + return (-1); + } + + for (;;) { + switch (msyylex()) { + case (EOF): + msSetError(MS_EOFERR, NULL, "loadProjection()"); + return (-1); + case (END): + if (p->numargs == 1 && strstr(p->args[0], "+") != NULL) { + char *one_line_def = p->args[0]; + int result; + + p->args[0] = NULL; + p->numargs = 0; + result = msLoadProjectionString(p, one_line_def); + free(one_line_def); + return result; + } else { + if (p->numargs != 0) { + if (map && map->numlayers > 0) { + layerObj *prevLayer = GET_LAYER(map, map->numlayers - 1); + if (prevLayer->projection.numargs == p->numargs) { + bool same = true; + for (int i = 0; i < p->numargs; ++i) { + if (strcmp(p->args[i], prevLayer->projection.args[i]) != 0) { + same = false; + break; + } + } + if (same) { + return msCloneProjectionFrom(p, &(prevLayer->projection)); + } + } + } + + return msProcessProjection(p); + } else + return 0; + } + break; + case (MS_STRING): + case (MS_AUTO): + if (p->numargs == MS_MAXPROJARGS) { + msSetError(MS_MISCERR, + "Parsing error near (%s):(line %d): Too many arguments in " + "projection string", + "loadProjection()", msyystring_buffer, msyylineno); + return -1; + } + p->args[p->numargs] = msStrdup(msyystring_buffer); + p->numargs++; + break; + default: + msSetError(MS_IDENTERR, "Parsing error near (%s):(line %d)", + "loadProjection()", msyystring_buffer, msyylineno); + return (-1); + } + } /* next token */ +} + +/************************************************************************/ +/* msLoadProjectionStringEPSGLike */ +/************************************************************************/ + +static int msLoadProjectionStringEPSGLike(projectionObj *p, const char *value, + const char *pszPrefix, + int bFollowEPSGAxisOrder) { + size_t buffer_size = 0; + char *init_string = NULL; + const char *code; + const char *next_sep; + size_t prefix_len; + + prefix_len = strlen(pszPrefix); + if (strncasecmp(value, pszPrefix, prefix_len) != 0) + return -1; + + code = value + prefix_len; + next_sep = strchr(code, pszPrefix[prefix_len - 1]); + if (next_sep != NULL) + code = next_sep + 1; + + buffer_size = 10 + strlen(code) + 1; + init_string = (char *)msSmallMalloc(buffer_size); + + /* translate into PROJ.4 format. */ + snprintf(init_string, buffer_size, "init=epsg:%s", code); + + p->args = (char **)msSmallMalloc(sizeof(char *) * 2); + p->args[0] = init_string; + p->numargs = 1; + + if (bFollowEPSGAxisOrder && msIsAxisInverted(atoi(code))) { + p->args[1] = msStrdup("+epsgaxis=ne"); + p->numargs = 2; + } + + return 0; +} + +/************************************************************************/ +/* msLoadProjectionStringCRSLike */ +/************************************************************************/ + +static int msLoadProjectionStringCRSLike(projectionObj *p, const char *value, + const char *pszPrefix) { + char init_string[100]; + const char *id; + const char *next_sep; + size_t prefix_len; + + prefix_len = strlen(pszPrefix); + if (strncasecmp(value, pszPrefix, prefix_len) != 0) + return -1; + + id = value + prefix_len; + next_sep = strchr(id, pszPrefix[prefix_len - 1]); + if (next_sep != NULL) + id = next_sep + 1; + + init_string[0] = '\0'; + + if (strcasecmp(id, "84") == 0 || strcasecmp(id, "CRS84") == 0) + strncpy(init_string, "init=epsg:4326", sizeof(init_string)); + else if (strcasecmp(id, "83") == 0 || strcasecmp(id, "CRS83") == 0) + strncpy(init_string, "init=epsg:4269", sizeof(init_string)); + else if (strcasecmp(id, "27") == 0 || strcasecmp(id, "CRS27") == 0) + strncpy(init_string, "init=epsg:4267", sizeof(init_string)); + else { + msSetError(MS_PROJERR, "Unrecognised OGC CRS def '%s'.", + "msLoadProjectionString()", value); + return -1; + } + + p->args = (char **)msSmallMalloc(sizeof(char *) * 2); + p->args[0] = msStrdup(init_string); + p->numargs = 1; + + return 0; +} + +/************************************************************************/ +/* msLoadProjectionStringEPSG */ +/* */ +/* Checks for EPSG type projection and set the axes for a */ +/* certain code ranges. */ +/* Use for now in WMS 1.3.0 and WFS >= 1.1.0 */ +/************************************************************************/ +int msLoadProjectionStringEPSG(projectionObj *p, const char *value) { + assert(p); + + msFreeProjectionExceptContext(p); + + p->gt.need_geotransform = MS_FALSE; +#ifdef USE_PROJ_FASTPATHS + if (strcasestr(value, "epsg:4326")) { + p->wellknownprojection = wkp_lonlat; + } else if (strcasestr(value, "epsg:3857")) { + p->wellknownprojection = wkp_gmerc; + } else { + p->wellknownprojection = wkp_none; + } +#endif + + if (msLoadProjectionStringEPSGLike(p, value, "EPSG:", MS_TRUE) == 0) { + return msProcessProjection(p); + } + + return msLoadProjectionString(p, value); +} + +/* Extract AUTHORITYversionCODE from a string, to +** create AUTHORITY:CODE and pas this to msLoadProjectionString(). +** For example: +** ESRI/0/53009 to ESRI:53009 +** ESRI::53009 to ESRI:53009 +** sep_char is '/' for URIs and ':' for URNs. +** Returns 0 on success, -1 if the string could not be parsed. */ +static int msLoadProjectionStringGenericCRS(projectionObj *p, + const char *p_auth, char sep_char) { + const char *sep = strchr(p_auth, sep_char); + if (sep == NULL) + return -1; + + char auth[64] = {0}; + size_t authlen = sep - p_auth; + if (authlen == 0 || authlen >= sizeof(auth)) + return -1; + + strlcpy(auth, p_auth, authlen + 1); + + /* skip version field (as it may be empty, e.g. ESRI::53009 or ESRI/0/53009) + */ + const char *p_code = sep + 1; + sep = strchr(p_code, sep_char); + if (sep != NULL) + p_code = sep + 1; + + if (*p_code == '\0') + return -1; + + char authcode[128] = {0}; + snprintf(authcode, sizeof(authcode), "%s:%s", auth, p_code); + return msLoadProjectionString(p, authcode); +} + +int msLoadProjectionString(projectionObj *p, const char *value) { + assert(p); + p->gt.need_geotransform = MS_FALSE; + + msFreeProjectionExceptContext(p); + + /* Known OGC/ISO authorities that PROJ 6+ supports directly without + ** init= prefix. Anything not in this list (e.g. custom init files + ** like epsg2, nad27) will use the init= prefix instead. */ + static const char *const validAuthorities[] = { + "EPSG", "ESRI", "IAU_2015", "IGNF", "NKG", "OGC", NULL}; + + if (value[0] == '+') { + /* Handle new style definitions e.g. "+proj=utm +zone=11 +ellps=WGS84" */ + char *trimmed; + int i, i_out = 0; + + trimmed = msStrdup(value + 1); + for (i = 1; value[i] != '\0'; i++) { + if (!isspace(value[i])) + trimmed[i_out++] = value[i]; + } + trimmed[i_out] = '\0'; + + p->args = msStringSplit(trimmed, '+', &p->numargs); + free(trimmed); + } else if (strncasecmp(value, "AUTO:", 5) == 0 || + strncasecmp(value, "AUTO2:", 6) == 0) { + /* WMS/WFS AUTO projection: "AUTO:proj_id,units_id,lon0,lat0" */ + /* WMS 1.3.0 projection: "AUTO2:auto_crs_id,factor,lon0,lat0" */ + /* Keep the projection defn into a single token for writeProjection() */ + /* to work fine. */ + p->args = (char **)msSmallMalloc(sizeof(char *)); + p->args[0] = msStrdup(value); + p->numargs = 1; + } else if (msLoadProjectionStringEPSGLike(p, value, "EPSG:", MS_FALSE) == 0) { + /* Assume long/lat ordering. Use msLoadProjectionStringEPSG() if wanting to + * follow EPSG axis */ + } else if (msLoadProjectionStringEPSGLike( + p, value, "urn:ogc:def:crs:EPSG:", MS_TRUE) == 0) { + } else if (msLoadProjectionStringEPSGLike( + p, value, "urn:EPSG:geographicCRS:", MS_TRUE) == 0) { + } else if (msLoadProjectionStringEPSGLike( + p, value, "urn:x-ogc:def:crs:EPSG:", MS_TRUE) == 0) { + /*this case is to account for OGC CITE tests where x-ogc was used + before the ogc name became an official NID. Note also we also account + for the fact that a space for the version of the espg is not used with + CITE tests. (Syntax used could be urn:ogc:def:objectType:authority:code)*/ + } else if (msLoadProjectionStringCRSLike(p, value, "urn:ogc:def:crs:OGC:") == + 0) { + } else if (msLoadProjectionStringEPSGLike( + p, value, "http://www.opengis.net/def/crs/EPSG/", MS_TRUE) == + 0) { + /* URI projection support. Kept separate from the generic URI handler + ** below because MS_TRUE enforces correct EPSG axis ordering. */ + } else if (msLoadProjectionStringCRSLike( + p, value, "http://www.opengis.net/def/crs/OGC/") == 0) { + /* Mandatory support for this URI format specified in WFS1.1 (also in 1.0?) + */ + } else if (strncasecmp(value, "http://www.opengis.net/def/crs/", 31) == 0) { + /* Generic URI handler for non-EPSG/OGC authorities + ** in the format http://www.opengis.net/def/crs/AUTHORITY/version/CODE + ** e.g. http://www.opengis.net/def/crs/ESRI/0/53009 + ** EPSG and OGC are handled above due to axis order and CRS identifier + ** special cases. + */ + return msLoadProjectionStringGenericCRS(p, value + 31, '/'); + } else if (msLoadProjectionStringEPSGLike( + p, value, "http://www.opengis.net/gml/srs/epsg.xml#", + MS_FALSE) == 0) { + /* We assume always long/lat ordering, as that is what GeoServer does... */ + } else if (msLoadProjectionStringCRSLike(p, value, "CRS:") == 0) { + } else if (strncasecmp(value, "urn:ogc:def:crs:", 16) == 0) { + /* Generic URN handler for non-EPSG/OGC authorities e.g. + *urn:ogc:def:crs:ESRI::53009 + ** Format is urn:ogc:def:crs:AUTHORITY:version:CODE where version may be + *empty + */ + return msLoadProjectionStringGenericCRS(p, value + 16, ':'); + } else if (strchr(value, ':') != NULL && + strncasecmp(value, "init=", 5) != 0) { + /* Handle AUTHORITY:CODE pattern e.g. ESRI:54030, IAU:2015:30100, + ** epsg2:42304. Check if authority is in the known list - if so pass + ** directly to PROJ 6+, otherwise prepend init= for file-based + ** references and legacy PROJ 4. */ + const char *sep = strchr(value, ':'); + char authUpper[64] = {0}; + size_t authlen = sep - value; + bool knownAuthority = false; + if (authlen < sizeof(authUpper)) { + strlcpy(authUpper, value, authlen + 1); + for (size_t i = 0; authUpper[i]; i++) + authUpper[i] = (char)toupper((unsigned char)authUpper[i]); + for (int i = 0; validAuthorities[i] != NULL; i++) { + if (strcmp(authUpper, validAuthorities[i]) == 0) { + knownAuthority = true; + break; + } + } + } + if (knownAuthority) { + /* PROJ 6+ handles known authorities directly */ + p->args = (char **)msSmallMalloc(sizeof(char *)); + p->args[0] = msStrdup(value); + p->numargs = 1; + } else { + /* Prepend init= for file-based or legacy PROJ 4 references */ + const size_t buffer_size = strlen("init=") + strlen(value) + 1; + char *init_string = (char *)msSmallMalloc(buffer_size); + snprintf(init_string, buffer_size, "init=%s", value); + p->args = (char **)msSmallMalloc(sizeof(char *)); + p->args[0] = init_string; + p->numargs = 1; + } + } else { + /* Handle old style comma delimited e.g. "proj=utm,zone=11,ellps=WGS84" */ + p->args = msStringSplit(value, ',', &p->numargs); + } + + return msProcessProjection(p); +} + +static void writeProjection(FILE *stream, int indent, projectionObj *p) { + int i; + + if (!p || p->numargs <= 0) + return; + indent++; + writeBlockBegin(stream, indent, "PROJECTION"); + for (i = 0; i < p->numargs; i++) + writeString(stream, indent, NULL, NULL, p->args[i]); + writeBlockEnd(stream, indent, "PROJECTION"); +} + +void initLeader(labelLeaderObj *leader) { + leader->gridstep = 5; + leader->maxdistance = 0; + + /* Set maxstyles = 0, styles[] will be allocated as needed on first call + * to msGrowLabelLeaderStyles() + */ + leader->numstyles = leader->maxstyles = 0; + leader->styles = NULL; +} + +/* +** Initialize, load and free a labelObj structure +*/ +void initLabel(labelObj *label) { + int i; + + MS_REFCNT_INIT(label); + + label->align = MS_ALIGN_DEFAULT; + MS_INIT_COLOR(label->color, 0, 0, 0, 255); + MS_INIT_COLOR(label->outlinecolor, -1, -1, -1, 255); /* don't use it */ + label->outlinewidth = 1; + + MS_INIT_COLOR(label->shadowcolor, -1, -1, -1, 255); /* don't use it */ + label->shadowsizex = label->shadowsizey = 1; + + label->font = NULL; + label->size = MS_MEDIUM; + + label->position = MS_CC; + label->angle = 0; + label->anglemode = MS_NONE; + label->minsize = MS_MINFONTSIZE; + label->maxsize = MS_MAXFONTSIZE; + label->buffer = 0; + label->offsetx = label->offsety = 0; + label->minscaledenom = -1; + label->maxscaledenom = -1; + label->minfeaturesize = -1; /* no limit */ + label->autominfeaturesize = MS_FALSE; + label->mindistance = -1; /* no limit */ + label->repeatdistance = 0; /* no repeat */ + label->maxoverlapangle = 22.5; /* default max overlap angle */ + label->partials = MS_FALSE; + label->wrap = '\0'; + label->maxlength = 0; + label->space_size_10 = 0.0; + + label->encoding = NULL; + + label->force = MS_OFF; + label->priority = MS_DEFAULT_LABEL_PRIORITY; + + /* Set maxstyles = 0, styles[] will be allocated as needed on first call + * to msGrowLabelStyles() + */ + label->numstyles = label->maxstyles = 0; + label->styles = NULL; + + label->numbindings = 0; + label->nexprbindings = 0; + for (i = 0; i < MS_LABEL_BINDING_LENGTH; i++) { + label->bindings[i].item = NULL; + label->bindings[i].index = -1; + msInitExpression(&(label->exprBindings[i])); + } + + msInitExpression(&(label->expression)); + msInitExpression(&(label->text)); + + label->leader = NULL; + + label->sizeunits = MS_INHERIT; + label->scalefactor = 1.0; + + return; +} + +int freeLabelLeader(labelLeaderObj *leader) { + int i; + for (i = 0; i < leader->numstyles; i++) { + if (freeStyle(leader->styles[i]) == MS_SUCCESS) { + msFree(leader->styles[i]); + } + } + msFree(leader->styles); + + return MS_SUCCESS; +} +int freeLabel(labelObj *label) { + int i; + + if (MS_REFCNT_DECR_IS_NOT_ZERO(label)) { + return MS_FAILURE; + } + + msFree(label->font); + msFree(label->encoding); + + for (i = 0; i < label->numstyles; i++) { /* each style */ + if (label->styles[i] != NULL) { + if (freeStyle(label->styles[i]) == MS_SUCCESS) { + msFree(label->styles[i]); + } + } + } + msFree(label->styles); + + for (i = 0; i < MS_LABEL_BINDING_LENGTH; i++) { + msFree(label->bindings[i].item); + msFreeExpression(&(label->exprBindings[i])); + } + + msFreeExpression(&(label->expression)); + msFreeExpression(&(label->text)); + + if (label->leader) { + freeLabelLeader(label->leader); + msFree(label->leader); + label->leader = NULL; + } + + return MS_SUCCESS; +} + +static int loadLeader(labelLeaderObj *leader) { + for (;;) { + switch (msyylex()) { + case (END): + return (0); + break; + case (EOF): + msSetError(MS_EOFERR, NULL, "loadLeader()"); + return (-1); + case GRIDSTEP: + if (getInteger(&(leader->gridstep), MS_NUM_CHECK_GT, 0, -1) == -1) + return (-1); + break; + case MAXDISTANCE: + if (getInteger(&(leader->maxdistance), MS_NUM_CHECK_GT, 0, -1) == -1) + return (-1); + break; + case STYLE: + if (msGrowLeaderStyles(leader) == NULL) + return (-1); + initStyle(leader->styles[leader->numstyles]); + if (loadStyle(leader->styles[leader->numstyles]) != MS_SUCCESS) { + freeStyle(leader->styles[leader->numstyles]); + free(leader->styles[leader->numstyles]); + leader->styles[leader->numstyles] = NULL; + return -1; + } + leader->numstyles++; + break; + default: + if (strlen(msyystring_buffer) > 0) { + msSetError(MS_IDENTERR, "Parsing error near (%s):(line %d)", + "loadLeader()", msyystring_buffer, msyylineno); + return (-1); + } else { + return (0); /* end of a string, not an error */ + } + } + } +} + +static int loadLabel(labelObj *label) { + int symbol; + + for (;;) { + switch (msyylex()) { + case (ANGLE): + if ((symbol = getSymbol(5, MS_NUMBER, MS_AUTO, MS_AUTO2, MS_FOLLOW, + MS_BINDING)) == -1) + return (-1); + + if (symbol == MS_NUMBER) { + if (msCheckNumber(msyynumber, MS_NUM_CHECK_RANGE, -360.0, 360.0) == + MS_FAILURE) { + msSetError(MS_MISCERR, + "Invalid ANGLE, must be between -360 and 360 (line %d)", + "loadLabel()", msyylineno); + return (MS_FAILURE); + } + label->angle = (double)msyynumber; + } else if (symbol == MS_BINDING) { + if (label->bindings[MS_LABEL_BINDING_ANGLE].item != NULL) + msFree(label->bindings[MS_LABEL_BINDING_ANGLE].item); + label->bindings[MS_LABEL_BINDING_ANGLE].item = + msStrdup(msyystring_buffer); + label->numbindings++; + } else { + label->anglemode = symbol; + } + break; + case (ALIGN): + if ((symbol = getSymbol(4, MS_ALIGN_LEFT, MS_ALIGN_CENTER, MS_ALIGN_RIGHT, + MS_BINDING)) == -1) + return (-1); + if ((symbol == MS_ALIGN_LEFT) || (symbol == MS_ALIGN_CENTER) || + (symbol == MS_ALIGN_RIGHT)) { + label->align = symbol; + } else { + if (label->bindings[MS_LABEL_BINDING_ALIGN].item != NULL) + msFree(label->bindings[MS_LABEL_BINDING_ALIGN].item); + label->bindings[MS_LABEL_BINDING_ALIGN].item = + msStrdup(msyystring_buffer); + label->numbindings++; + } + break; + case (ANTIALIAS): /*ignore*/ + msyylex(); + break; + case (BUFFER): + if (getInteger(&(label->buffer), MS_NUM_CHECK_NONE, -1, -1) == -1) + return (-1); + break; + case (COLOR): + if (loadColor(&(label->color), + &(label->bindings[MS_LABEL_BINDING_COLOR])) != MS_SUCCESS) + return (-1); + if (label->bindings[MS_LABEL_BINDING_COLOR].item) + label->numbindings++; + break; + case (ENCODING): + if ((getString(&label->encoding)) == MS_FAILURE) + return (-1); + break; + case (END): + return (0); + break; + case (EOF): + msSetError(MS_EOFERR, NULL, "loadLabel()"); + return (-1); + case (EXPRESSION): + if (loadExpression(&(label->expression)) == -1) + return (-1); /* loadExpression() cleans up previously allocated + expression */ + break; + case (FONT): + if ((symbol = getSymbol(2, MS_STRING, MS_BINDING)) == -1) + return (-1); + + if (symbol == MS_STRING) { + if (label->font != NULL) + msFree(label->font); + label->font = msStrdup(msyystring_buffer); + } else { + if (label->bindings[MS_LABEL_BINDING_FONT].item != NULL) + msFree(label->bindings[MS_LABEL_BINDING_FONT].item); + label->bindings[MS_LABEL_BINDING_FONT].item = + msStrdup(msyystring_buffer); + label->numbindings++; + } + break; + case (FORCE): + switch (msyylex()) { + case MS_ON: + label->force = MS_ON; + break; + case MS_OFF: + label->force = MS_OFF; + break; + case GROUP: + label->force = MS_LABEL_FORCE_GROUP; + break; + default: + msSetError(MS_MISCERR, + "Invalid FORCE, must be ON,OFF,or GROUP (line %d)", + "loadLabel()", msyylineno); + return (-1); + } + break; + case (LABEL): + break; /* for string loads */ + case (LEADER): + msSetError(MS_MISCERR, + "LABEL LEADER not implemented. LEADER goes at the CLASS level " + "(line %d)", + "loadLabel()", msyylineno); + return (-1); + case (MAXSIZE): + if (getInteger(&(label->maxsize), MS_NUM_CHECK_GT, 0, -1) == -1) + return (-1); + break; + case (MAXSCALEDENOM): + if (getDouble(&(label->maxscaledenom), MS_NUM_CHECK_GTE, 0, -1) == -1) + return (-1); + break; + case (MAXLENGTH): + if (getInteger(&(label->maxlength), MS_NUM_CHECK_GT, 0, -1) == -1) + return (-1); + break; + case (MINDISTANCE): + if (getInteger(&(label->mindistance), MS_NUM_CHECK_GT, 0, -1) == -1) + return (-1); + break; + case (REPEATDISTANCE): + if (getInteger(&(label->repeatdistance), MS_NUM_CHECK_GT, 0, -1) == -1) + return (-1); + break; + case (MAXOVERLAPANGLE): + if (getDouble(&(label->maxoverlapangle), MS_NUM_CHECK_RANGE, 0, 360) == + -1) + return (-1); + break; + case (MINFEATURESIZE): + if ((symbol = getSymbol(2, MS_NUMBER, MS_AUTO)) == -1) + return (-1); + if (symbol == MS_NUMBER) { + if (msCheckNumber(msyynumber, MS_NUM_CHECK_GT, 0, -1) == MS_FAILURE) { + msSetError(MS_MISCERR, + "Invalid MINFEATURESIZE, must be greater than 0 (line %d)", + "loadLabel()", msyylineno); + return (MS_FAILURE); + } + label->minfeaturesize = (int)msyynumber; + } else + label->autominfeaturesize = MS_TRUE; + break; + case (MINSCALEDENOM): + if (getDouble(&(label->minscaledenom), MS_NUM_CHECK_GTE, 0, -1) == -1) + return (-1); + break; + case (MINSIZE): + if (getInteger(&(label->minsize), MS_NUM_CHECK_GT, 0, -1) == -1) + return (-1); + break; + case (OFFSET): + if ((symbol = getSymbol(2, MS_NUMBER, MS_BINDING)) == -1) + return (MS_FAILURE); + if (symbol == MS_NUMBER) + label->offsetx = (int)msyynumber; // any integer ok + else { + if (label->bindings[MS_LABEL_BINDING_OFFSET_X].item != NULL) + msFree(label->bindings[MS_LABEL_BINDING_OFFSET_X].item); + label->bindings[MS_LABEL_BINDING_OFFSET_X].item = + msStrdup(msyystring_buffer); + label->numbindings++; + } + + if ((symbol = getSymbol(2, MS_NUMBER, MS_BINDING)) == -1) + return (MS_FAILURE); + if (symbol == MS_NUMBER) + label->offsety = (int)msyynumber; // any integer ok + else { + if (label->bindings[MS_LABEL_BINDING_OFFSET_Y].item != NULL) + msFree(label->bindings[MS_LABEL_BINDING_OFFSET_Y].item); + label->bindings[MS_LABEL_BINDING_OFFSET_Y].item = + msStrdup(msyystring_buffer); + label->numbindings++; + } + break; + case (OUTLINECOLOR): + if (loadColor(&(label->outlinecolor), + &(label->bindings[MS_LABEL_BINDING_OUTLINECOLOR])) != + MS_SUCCESS) + return (-1); + if (label->bindings[MS_LABEL_BINDING_OUTLINECOLOR].item) + label->numbindings++; + break; + case (OUTLINEWIDTH): + if (getInteger(&(label->outlinewidth), MS_NUM_CHECK_GT, 0, -1) == -1) + return (-1); + break; + case (PARTIALS): + if ((label->partials = getSymbol(2, MS_TRUE, MS_FALSE)) == -1) + return (-1); + break; + case (POSITION): + if ((label->position = + getSymbol(11, MS_UL, MS_UC, MS_UR, MS_CL, MS_CC, MS_CR, MS_LL, + MS_LC, MS_LR, MS_AUTO, MS_BINDING)) == -1) + return (-1); + if (label->position == MS_BINDING) { + if (label->bindings[MS_LABEL_BINDING_POSITION].item != NULL) + msFree(label->bindings[MS_LABEL_BINDING_POSITION].item); + label->bindings[MS_LABEL_BINDING_POSITION].item = + msStrdup(msyystring_buffer); + label->numbindings++; + } + break; + case (PRIORITY): + if (label->exprBindings[MS_LABEL_BINDING_PRIORITY].string) { + msFreeExpression(&label->exprBindings[MS_LABEL_BINDING_PRIORITY]); + label->nexprbindings--; + } + + if ((symbol = getSymbol(3, MS_EXPRESSION, MS_NUMBER, MS_BINDING)) == -1) + return (-1); + if (symbol == MS_NUMBER) { + if (msCheckNumber(msyynumber, MS_NUM_CHECK_RANGE, 1, + MS_MAX_LABEL_PRIORITY) == MS_FAILURE) { + msSetError( + MS_MISCERR, + "Invalid PRIORITY, must be an integer between 1 and %d (line %d)", + "loadLabel()", MS_MAX_LABEL_PRIORITY, msyylineno); + return (-1); + } + label->priority = (int)msyynumber; + } else if (symbol == MS_EXPRESSION) { + msFree(label->exprBindings[MS_LABEL_BINDING_PRIORITY].string); + label->exprBindings[MS_LABEL_BINDING_PRIORITY].string = + msStrdup(msyystring_buffer); + label->exprBindings[MS_LABEL_BINDING_PRIORITY].type = MS_EXPRESSION; + label->nexprbindings++; + } else { + if (label->bindings[MS_LABEL_BINDING_PRIORITY].item != NULL) + msFree(label->bindings[MS_LABEL_BINDING_PRIORITY].item); + label->bindings[MS_LABEL_BINDING_PRIORITY].item = + msStrdup(msyystring_buffer); + label->numbindings++; + } + break; + case (SHADOWCOLOR): + if (loadColor(&(label->shadowcolor), NULL) != MS_SUCCESS) + return (-1); + break; + case (SHADOWSIZE): + if ((symbol = getSymbol(2, MS_NUMBER, MS_BINDING)) == -1) + return (-1); + if (symbol == MS_NUMBER) { + label->shadowsizex = (int)msyynumber; // x offset, any int ok + } else { + if (label->bindings[MS_LABEL_BINDING_SHADOWSIZEX].item != NULL) + msFree(label->bindings[MS_LABEL_BINDING_SHADOWSIZEX].item); + label->bindings[MS_LABEL_BINDING_SHADOWSIZEX].item = + msStrdup(msyystring_buffer); + label->numbindings++; + } + + if ((symbol = getSymbol(2, MS_NUMBER, MS_BINDING)) == -1) + return (-1); + if (symbol == MS_NUMBER) { + label->shadowsizey = (int)msyynumber; // y offset, any int ok + } else { + if (label->bindings[MS_LABEL_BINDING_SHADOWSIZEY].item != NULL) + msFree(label->bindings[MS_LABEL_BINDING_SHADOWSIZEY].item); + label->bindings[MS_LABEL_BINDING_SHADOWSIZEY].item = + msStrdup(msyystring_buffer); + label->numbindings++; + } + break; + case (SIZE): + if (label->bindings[MS_LABEL_BINDING_SIZE].item) { + msFree(label->bindings[MS_LABEL_BINDING_SIZE].item); + label->bindings[MS_LABEL_BINDING_SIZE].item = NULL; + label->numbindings--; + } + if (label->exprBindings[MS_LABEL_BINDING_SIZE].string) { + msFreeExpression(&label->exprBindings[MS_LABEL_BINDING_SIZE]); + label->nexprbindings--; + } + + if ((symbol = getSymbol(8, MS_EXPRESSION, MS_NUMBER, MS_BINDING, MS_TINY, + MS_SMALL, MS_MEDIUM, MS_LARGE, MS_GIANT)) == -1) + return (-1); + + if (symbol == MS_NUMBER) { + if (msCheckNumber(msyynumber, MS_NUM_CHECK_GT, 0, -1) == MS_FAILURE) { + msSetError(MS_MISCERR, + "Invalid SIZE, must be greater than 0 (line %d)", + "loadLabel()", msyylineno); + return (-1); + } + label->size = (double)msyynumber; + } else if (symbol == MS_BINDING) { + label->bindings[MS_LABEL_BINDING_SIZE].item = + msStrdup(msyystring_buffer); + label->numbindings++; + } else if (symbol == MS_EXPRESSION) { + msFree(label->exprBindings[MS_LABEL_BINDING_SIZE].string); + label->exprBindings[MS_LABEL_BINDING_SIZE].string = + msStrdup(msyystring_buffer); + label->exprBindings[MS_LABEL_BINDING_SIZE].type = MS_EXPRESSION; + label->nexprbindings++; + } else + label->size = symbol; + break; + case (STYLE): + if (msGrowLabelStyles(label) == NULL) + return (-1); + initStyle(label->styles[label->numstyles]); + if (loadStyle(label->styles[label->numstyles]) != MS_SUCCESS) { + freeStyle(label->styles[label->numstyles]); + free(label->styles[label->numstyles]); + label->styles[label->numstyles] = NULL; + return (-1); + } + if (label->styles[label->numstyles]->_geomtransform.type == + MS_GEOMTRANSFORM_NONE) + label->styles[label->numstyles]->_geomtransform.type = + MS_GEOMTRANSFORM_LABELPOINT; /* set a default, a marker? */ + label->numstyles++; + break; + case (TEXT): + if (loadExpression(&(label->text)) == -1) + return (-1); /* loadExpression() cleans up previously allocated + expression */ + if ((label->text.type != MS_STRING) && + (label->text.type != MS_EXPRESSION)) { + msSetError( + MS_MISCERR, + "Text expressions support constant or tagged replacement strings.", + "loadLabel()"); + return (-1); + } + break; + case (TYPE): + if (getSymbol(2, MS_TRUETYPE, MS_BITMAP) == -1) + return (-1); /* ignore TYPE */ + break; + case (WRAP): + if (getCharacter(&(label->wrap)) == -1) + return (-1); + break; + default: + if (strlen(msyystring_buffer) > 0) { + msSetError(MS_IDENTERR, "Parsing error near (%s):(line %d)", + "loadLabel()", msyystring_buffer, msyylineno); + return (-1); + } else { + return (0); /* end of a string, not an error */ + } + } + } /* next token */ +} + +int msUpdateLabelFromString(labelObj *label, char *string) { + if (!label || !string) + return MS_FAILURE; + + msAcquireLock(TLOCK_PARSER); + + msyystate = MS_TOKENIZE_STRING; + msyystring = string; + msyylex(); /* sets things up, but doesn't process any tokens */ + + msyylineno = 1; /* start at line 1 */ + + if (loadLabel(label) == -1) { + msReleaseLock(TLOCK_PARSER); + return MS_FAILURE; /* parse error */ + ; + } + + msyylex_destroy(); + msReleaseLock(TLOCK_PARSER); + return MS_SUCCESS; +} + +static void writeLeader(FILE *stream, int indent, labelLeaderObj *leader) { + int i; + if (leader->maxdistance == 0 && leader->numstyles == 0) { + return; + } + indent++; + writeBlockBegin(stream, indent, "LEADER"); + writeNumber(stream, indent, "MAXDISTANCE", 0, leader->maxdistance); + writeNumber(stream, indent, "GRIDSTEP", 5, leader->gridstep); + for (i = 0; i < leader->numstyles; i++) + writeStyle(stream, indent, leader->styles[i]); + + writeBlockEnd(stream, indent, "LEADER"); +} + +static void writeLabel(FILE *stream, int indent, labelObj *label) { + int i; + colorObj c; + + if (label->size == -1) + return; /* there is no default label anymore */ + + indent++; + writeBlockBegin(stream, indent, "LABEL"); + + if (label->numbindings > 0 && label->bindings[MS_LABEL_BINDING_ANGLE].item) + writeAttributeBinding(stream, indent, "ANGLE", + &(label->bindings[MS_LABEL_BINDING_ANGLE])); + else + writeNumberOrKeyword(stream, indent, "ANGLE", 0, label->angle, + label->anglemode, 3, MS_FOLLOW, "FOLLOW", MS_AUTO, + "AUTO", MS_AUTO2, "AUTO2"); + + writeExpression(stream, indent, "EXPRESSION", &(label->expression)); + + if (label->numbindings > 0 && label->bindings[MS_LABEL_BINDING_FONT].item) + writeAttributeBinding(stream, indent, "FONT", + &(label->bindings[MS_LABEL_BINDING_FONT])); + else + writeString(stream, indent, "FONT", NULL, label->font); + + writeNumber(stream, indent, "MAXSIZE", MS_MAXFONTSIZE, label->maxsize); + writeNumber(stream, indent, "MINSIZE", MS_MINFONTSIZE, label->minsize); + + if (label->numbindings > 0 && label->bindings[MS_LABEL_BINDING_SIZE].item) + writeAttributeBinding(stream, indent, "SIZE", + &(label->bindings[MS_LABEL_BINDING_SIZE])); + else + writeNumber(stream, indent, "SIZE", -1, label->size); + + writeKeyword(stream, indent, "ALIGN", label->align, 3, MS_ALIGN_LEFT, "LEFT", + MS_ALIGN_CENTER, "CENTER", MS_ALIGN_RIGHT, "RIGHT"); + writeNumber(stream, indent, "BUFFER", 0, label->buffer); + + if (label->numbindings > 0 && label->bindings[MS_LABEL_BINDING_COLOR].item) + writeAttributeBinding(stream, indent, "COLOR", + &(label->bindings[MS_LABEL_BINDING_COLOR])); + else { + MS_INIT_COLOR(c, 0, 0, 0, 255); + writeColor(stream, indent, "COLOR", &c, &(label->color)); + } + + writeString(stream, indent, "ENCODING", NULL, label->encoding); + if (label->leader) + writeLeader(stream, indent, label->leader); + writeKeyword(stream, indent, "FORCE", label->force, 2, MS_TRUE, "TRUE", + MS_LABEL_FORCE_GROUP, "GROUP"); + writeNumber(stream, indent, "MAXLENGTH", 0, label->maxlength); + writeNumber(stream, indent, "MAXSCALEDENOM", -1, label->maxscaledenom); + writeNumber(stream, indent, "MINDISTANCE", -1, label->mindistance); + writeNumberOrKeyword(stream, indent, "MINFEATURESIZE", -1, + label->minfeaturesize, 1, label->autominfeaturesize, + MS_TRUE, "AUTO"); + writeNumber(stream, indent, "MINSCALEDENOM", -1, label->minscaledenom); + writeDimension(stream, indent, "OFFSET", label->offsetx, label->offsety, NULL, + NULL); + + if (label->numbindings > 0 && + label->bindings[MS_LABEL_BINDING_OUTLINECOLOR].item) + writeAttributeBinding(stream, indent, "OUTLINECOLOR", + &(label->bindings[MS_LABEL_BINDING_OUTLINECOLOR])); + else + writeColor(stream, indent, "OUTLINECOLOR", NULL, &(label->outlinecolor)); + + writeNumber(stream, indent, "OUTLINEWIDTH", 1, label->outlinewidth); + writeKeyword(stream, indent, "PARTIALS", label->partials, 1, MS_TRUE, "TRUE"); + + if (label->numbindings > 0 && label->bindings[MS_LABEL_BINDING_POSITION].item) + writeAttributeBinding(stream, indent, "POSITION", + &(label->bindings[MS_LABEL_BINDING_POSITION])); + else + writeKeyword(stream, indent, "POSITION", label->position, 10, MS_UL, "UL", + MS_UC, "UC", MS_UR, "UR", MS_CL, "CL", MS_CC, "CC", MS_CR, + "CR", MS_LL, "LL", MS_LC, "LC", MS_LR, "LR", MS_AUTO, "AUTO"); + + if (label->numbindings > 0 && label->bindings[MS_LABEL_BINDING_PRIORITY].item) + writeAttributeBinding(stream, indent, "PRIORITY", + &(label->bindings[MS_LABEL_BINDING_PRIORITY])); + else if (label->nexprbindings > 0 && + label->exprBindings[MS_LABEL_BINDING_PRIORITY].string) + writeExpression(stream, indent, "PRIORITY", + &(label->exprBindings[MS_LABEL_BINDING_PRIORITY])); + else + writeNumber(stream, indent, "PRIORITY", MS_DEFAULT_LABEL_PRIORITY, + label->priority); + + writeNumber(stream, indent, "REPEATDISTANCE", 0, label->repeatdistance); + writeColor(stream, indent, "SHADOWCOLOR", NULL, &(label->shadowcolor)); + writeDimension(stream, indent, "SHADOWSIZE", label->shadowsizex, + label->shadowsizey, + label->bindings[MS_LABEL_BINDING_SHADOWSIZEX].item, + label->bindings[MS_LABEL_BINDING_SHADOWSIZEY].item); + + writeNumber(stream, indent, "MAXOVERLAPANGLE", 22.5, label->maxoverlapangle); + for (i = 0; i < label->numstyles; i++) + writeStyle(stream, indent, label->styles[i]); + + writeExpression(stream, indent, "TEXT", &(label->text)); + + writeCharacter(stream, indent, "WRAP", '\0', label->wrap); + writeBlockEnd(stream, indent, "LABEL"); +} + +char *msWriteLabelToString(labelObj *label) { + msIOContext context; + msIOBuffer buffer; + + context.label = NULL; + context.write_channel = MS_TRUE; + context.readWriteFunc = msIO_bufferWrite; + context.cbData = &buffer; + buffer.data = NULL; + buffer.data_len = 0; + buffer.data_offset = 0; + + msIO_installHandlers(NULL, &context, NULL); + + writeLabel(stdout, -1, label); + msIO_bufferWrite(&buffer, "", 1); + + msIO_installHandlers(NULL, NULL, NULL); + + return (char *)buffer.data; +} + +void msInitExpression(expressionObj *exp) { + memset(exp, 0, sizeof(*exp)); + exp->type = MS_STRING; +} + +void msFreeExpressionTokens(expressionObj *exp) { + tokenListNodeObjPtr node = NULL; + tokenListNodeObjPtr nextNode = NULL; + + if (!exp) + return; + + if (exp->tokens) { + node = exp->tokens; + while (node != NULL) { + nextNode = node->next; + + msFree(node->tokensrc); /* not set very often */ + + switch (node->token) { + case MS_TOKEN_BINDING_DOUBLE: + case MS_TOKEN_BINDING_INTEGER: + case MS_TOKEN_BINDING_STRING: + case MS_TOKEN_BINDING_TIME: + msFree(node->tokenval.bindval.item); + break; + case MS_TOKEN_LITERAL_TIME: + /* anything to do? */ + break; + case MS_TOKEN_LITERAL_STRING: + msFree(node->tokenval.strval); + break; + case MS_TOKEN_LITERAL_SHAPE: + msFreeShape(node->tokenval.shpval); + free(node->tokenval.shpval); + break; + } + + msFree(node); + node = nextNode; + } + exp->tokens = exp->curtoken = NULL; + } +} + +void msFreeExpression(expressionObj *exp) { + if (!exp) + return; + msFree(exp->string); + msFree(exp->native_string); + if ((exp->type == MS_REGEX) && exp->compiled) + ms_regfree(&(exp->regex)); + msFreeExpressionTokens(exp); + msInitExpression(exp); /* re-initialize */ +} + +int loadExpression(expressionObj *exp) { + /* TODO: should we call msFreeExpression if exp->string != NULL? We do some + * checking to avoid a leak but is it enough... */ + + msyystring_icase = MS_TRUE; + if ((exp->type = getSymbol(6, MS_STRING, MS_EXPRESSION, MS_REGEX, MS_ISTRING, + MS_IREGEX, MS_LIST)) == -1) + return (-1); + if (exp->string != NULL) { + msFree(exp->string); + msFree(exp->native_string); + } + exp->string = msStrdup(msyystring_buffer); + exp->native_string = NULL; + + if (exp->type == MS_ISTRING) { + exp->flags = exp->flags | MS_EXP_INSENSITIVE; + exp->type = MS_STRING; + } else if (exp->type == MS_IREGEX) { + exp->flags = exp->flags | MS_EXP_INSENSITIVE; + exp->type = MS_REGEX; + } + + return (0); +} + +/* --------------------------------------------------------------------------- + msLoadExpressionString and loadExpressionString + + msLoadExpressionString wraps call to loadExpressionString with mutex + acquisition and release. This function should be used everywhere outside + the mapfile loading phase of an application. loadExpressionString does + not check for a mutex! It should be used only within code that has + properly acquired a mutex. + + See bug 339 for more details -- SG. + ------------------------------------------------------------------------ */ + +int msLoadExpressionString(expressionObj *exp, const char *value) { + int retval = MS_FAILURE; + + msAcquireLock(TLOCK_PARSER); + retval = loadExpressionString(exp, value); + msReleaseLock(TLOCK_PARSER); + + return retval; +} + +int loadExpressionString(expressionObj *exp, const char *value) { + msyystate = MS_TOKENIZE_STRING; + msyystring = value; + msyylex(); /* sets things up but processes no tokens */ + + msFreeExpression(exp); /* we're totally replacing the old expression so free + (which re-inits) to start over */ + + msyystring_icase = MS_TRUE; + if ((exp->type = getSymbol2(5, MS_EXPRESSION, MS_REGEX, MS_IREGEX, MS_ISTRING, + MS_LIST)) != -1) { + exp->string = msStrdup(msyystring_buffer); + + if (exp->type == MS_ISTRING) { + exp->type = MS_STRING; + exp->flags = exp->flags | MS_EXP_INSENSITIVE; + } else if (exp->type == MS_IREGEX) { + exp->type = MS_REGEX; + exp->flags = exp->flags | MS_EXP_INSENSITIVE; + } + } else { + /* failure above is not an error since we'll consider anything not matching + * (like an unquoted number) as a STRING) */ + exp->type = MS_STRING; + if ((strlen(value) - strlen(msyystring_buffer)) == 2) + exp->string = msStrdup(msyystring_buffer); /* value was quoted */ + else + exp->string = msStrdup(value); /* use the whole value */ + } + + return (0); +} + +/* msGetExpressionString() + * + * Returns the string representation of this expression, including delimiters + * and any flags (e.g. i = case-insensitive). + * + * Returns a newly allocated buffer that should be freed by the caller or NULL. + */ +char *msGetExpressionString(expressionObj *exp) { + if (exp->string) { + char *exprstring; + size_t buffer_size; + const char *case_insensitive = ""; + + if (exp->flags & MS_EXP_INSENSITIVE) + case_insensitive = "i"; + + /* Alloc buffer big enough for string + 2 delimiters + 'i' + \0 */ + buffer_size = strlen(exp->string) + 4; + exprstring = (char *)msSmallMalloc(buffer_size); + + switch (exp->type) { + case (MS_REGEX): + snprintf(exprstring, buffer_size, "/%s/%s", exp->string, + case_insensitive); + return exprstring; + case (MS_STRING): + snprintf(exprstring, buffer_size, "\"%s\"%s", exp->string, + case_insensitive); + return exprstring; + case (MS_EXPRESSION): + snprintf(exprstring, buffer_size, "(%s)", exp->string); + return exprstring; + case (MS_LIST): + snprintf(exprstring, buffer_size, "{%s}", exp->string); + return exprstring; + default: + /* We should never get to here really! */ + free(exprstring); + return NULL; + } + } + return NULL; +} + +static void writeExpression(FILE *stream, int indent, const char *name, + expressionObj *exp) { + if (!exp || !exp->string) + return; + + writeIndent(stream, ++indent); + switch (exp->type) { + case (MS_LIST): + fprintf(stream, "%s {%s}", name, exp->string); + break; + case (MS_REGEX): + msIO_fprintf(stream, "%s /%s/", name, exp->string); + break; + case (MS_STRING): + msIO_fprintf(stream, "%s ", name); + writeStringElement(stream, exp->string); + break; + case (MS_EXPRESSION): + msIO_fprintf(stream, "%s (%s)", name, exp->string); + break; + } + if ((exp->type == MS_STRING || exp->type == MS_REGEX) && + (exp->flags & MS_EXP_INSENSITIVE)) + msIO_fprintf(stream, "i"); + writeLineFeed(stream); +} + +int loadHashTable(hashTableObj *ptable) { + assert(ptable); + + for (;;) { + switch (msyylex()) { + case (EOF): + msSetError(MS_EOFERR, NULL, "loadHashTable()"); + return (MS_FAILURE); + case (END): + return (MS_SUCCESS); + case (MS_STRING): { + char *data = NULL; + char *key = + msStrdup(msyystring_buffer); /* the key is *always* a string */ + if (getString(&data) == MS_FAILURE) { + free(key); + return (MS_FAILURE); + } + msInsertHashTable(ptable, key, data); + + free(key); + free(data); + break; + } + default: + msSetError(MS_IDENTERR, "Parsing error near (%s):(line %d)", + "loadHashTable()", msyystring_buffer, msyylineno); + return (MS_FAILURE); + } + } + + return (MS_SUCCESS); +} + +static void writeHashTable(FILE *stream, int indent, const char *title, + hashTableObj *table) { + struct hashObj *tp; + int i; + + if (!table) + return; + if (msHashIsEmpty(table)) + return; + + indent++; + writeBlockBegin(stream, indent, title); + for (i = 0; i < MS_HASHSIZE; i++) { + if (table->items[i] != NULL) { + for (tp = table->items[i]; tp != NULL; tp = tp->next) + writeNameValuePair(stream, indent, tp->key, tp->data); + } + } + writeBlockEnd(stream, indent, title); +} + +static void writeHashTableInline(FILE *stream, int indent, char *name, + hashTableObj *table) { + struct hashObj *tp = NULL; + int i; + + if (!table) + return; + if (msHashIsEmpty(table)) + return; + + ++indent; + for (i = 0; i < MS_HASHSIZE; ++i) { + if (table->items[i] != NULL) { + for (tp = table->items[i]; tp != NULL; tp = tp->next) { + writeIndent(stream, indent); + msIO_fprintf(stream, "%s ", name); + writeStringElement(stream, tp->key); + msIO_fprintf(stream, " "); + writeStringElement(stream, tp->data); + writeLineFeed(stream); + } + } + } +} + +/* +** Initialize, load and free a cluster object +*/ +void initCluster(clusterObj *cluster) { + cluster->maxdistance = 10; + cluster->buffer = 0; + cluster->region = NULL; + msInitExpression(&(cluster->group)); + msInitExpression(&(cluster->filter)); +} + +void freeCluster(clusterObj *cluster) { + msFree(cluster->region); + msFreeExpression(&(cluster->group)); + msFreeExpression(&(cluster->filter)); +} + +int loadCluster(clusterObj *cluster) { + for (;;) { + switch (msyylex()) { + case (CLUSTER): + break; /* for string loads */ + case (MAXDISTANCE): + if (getDouble(&(cluster->maxdistance), MS_NUM_CHECK_GT, 0, -1) == -1) + return (-1); + break; + case (BUFFER): + if (getDouble(&(cluster->buffer), MS_NUM_CHECK_GT, 0, -1) == -1) + return (-1); + break; + case (REGION): + if (getString(&cluster->region) == MS_FAILURE) + return (-1); + break; + case (END): + return (0); + break; + case (GROUP): + if (loadExpression(&(cluster->group)) == -1) + return (-1); + break; + case (FILTER): + if (loadExpression(&(cluster->filter)) == -1) + return (-1); + break; + default: + if (strlen(msyystring_buffer) > 0) { + msSetError(MS_IDENTERR, "Parsing error near (%s):(line %d)", + "loadCluster()", msyystring_buffer, msyylineno); + return (-1); + } else { + return (0); /* end of a string, not an error */ + } + } + } + return (MS_SUCCESS); +} + +int msUpdateClusterFromString(clusterObj *cluster, char *string) { + if (!cluster || !string) + return MS_FAILURE; + + msAcquireLock(TLOCK_PARSER); + + msyystate = MS_TOKENIZE_STRING; + msyystring = string; + msyylex(); /* sets things up, but doesn't process any tokens */ + + msyylineno = 1; /* start at line 1 */ + + if (loadCluster(cluster) == -1) { + msReleaseLock(TLOCK_PARSER); + return MS_FAILURE; /* parse error */ + ; + } + + msyylex_destroy(); + msReleaseLock(TLOCK_PARSER); + return MS_SUCCESS; +} + +static void writeCluster(FILE *stream, int indent, clusterObj *cluster) { + + if (cluster->maxdistance == 10 && cluster->buffer == 0.0 && + cluster->region == NULL && cluster->group.string == NULL && + cluster->filter.string == NULL) + return; /* Nothing to write */ + + indent++; + writeBlockBegin(stream, indent, "CLUSTER"); + writeNumber(stream, indent, "MAXDISTANCE", 10, cluster->maxdistance); + writeNumber(stream, indent, "BUFFER", 0, cluster->buffer); + writeString(stream, indent, "REGION", NULL, cluster->region); + writeExpression(stream, indent, "GROUP", &(cluster->group)); + writeExpression(stream, indent, "FILTER", &(cluster->filter)); + writeBlockEnd(stream, indent, "CLUSTER"); +} + +char *msWriteClusterToString(clusterObj *cluster) { + msIOContext context; + msIOBuffer buffer; + + context.label = NULL; + context.write_channel = MS_TRUE; + context.readWriteFunc = msIO_bufferWrite; + context.cbData = &buffer; + buffer.data = NULL; + buffer.data_len = 0; + buffer.data_offset = 0; + + msIO_installHandlers(NULL, &context, NULL); + + writeCluster(stdout, -1, cluster); + msIO_bufferWrite(&buffer, "", 1); + + msIO_installHandlers(NULL, NULL, NULL); + + return (char *)buffer.data; +} + +/* +** Initialize, load and free a single style +*/ +int initStyle(styleObj *style) { + int i; + MS_REFCNT_INIT(style); + MS_INIT_COLOR(style->color, -1, -1, -1, 255); /* must explicitly set colors */ + MS_INIT_COLOR(style->outlinecolor, -1, -1, -1, 255); + /* New Color Range fields*/ + MS_INIT_COLOR(style->mincolor, -1, -1, -1, 255); + MS_INIT_COLOR(style->maxcolor, -1, -1, -1, 255); + style->minvalue = 0.0; + style->maxvalue = 1.0; + style->rangeitem = NULL; + /* End Color Range fields*/ + style->symbol = 0; /* there is always a default symbol*/ + style->symbolname = NULL; + style->size = -1; /* in SIZEUNITS (layerObj) */ + style->minsize = MS_MINSYMBOLSIZE; + style->maxsize = MS_MAXSYMBOLSIZE; + style->width = 1; /* in pixels */ + style->outlinewidth = 0; /* in pixels */ + style->minwidth = MS_MINSYMBOLWIDTH; + style->maxwidth = MS_MAXSYMBOLWIDTH; + style->minscaledenom = style->maxscaledenom = -1.0; + style->offsetx = style->offsety = 0; /* no offset */ + style->polaroffsetpixel = style->polaroffsetangle = 0; /* no polar offset */ + style->angle = 0; + style->autoangle = MS_FALSE; + style->antialiased = MS_TRUE; + style->opacity = 100; /* fully opaque */ + + msInitExpression(&(style->_geomtransform)); + style->_geomtransform.type = MS_GEOMTRANSFORM_NONE; + + style->patternlength = 0; /* solid line */ + style->gap = 0; + style->initialgap = -1; + style->linecap = MS_CJC_DEFAULT_CAPS; + style->linejoin = MS_CJC_DEFAULT_JOINS; + style->linejoinmaxsize = MS_CJC_DEFAULT_JOIN_MAXSIZE; + + style->numbindings = 0; + style->nexprbindings = 0; + for (i = 0; i < MS_STYLE_BINDING_LENGTH; i++) { + style->bindings[i].item = NULL; + style->bindings[i].index = -1; + msInitExpression(&(style->exprBindings[i])); + } + + style->sizeunits = MS_INHERIT; + style->scalefactor = 1.0; + + return MS_SUCCESS; +} + +int loadStyle(styleObj *style) { + int symbol; + + for (;;) { + switch (msyylex()) { + /* New Color Range fields*/ + case (COLORRANGE): + /*These are both in one line now*/ + if (loadColor(&(style->mincolor), NULL) != MS_SUCCESS) + return (MS_FAILURE); + if (loadColor(&(style->maxcolor), NULL) != MS_SUCCESS) + return (MS_FAILURE); + break; + case (DATARANGE): + /*These are both in one line now*/ + if (getDouble(&(style->minvalue), MS_NUM_CHECK_NONE, -1, -1) == -1) + return (MS_FAILURE); + if (getDouble(&(style->maxvalue), MS_NUM_CHECK_NONE, -1, -1) == -1) + return (MS_FAILURE); + break; + case (RANGEITEM): + if (getString(&style->rangeitem) == MS_FAILURE) + return (MS_FAILURE); + break; + /* End Range fields*/ + case (ANGLE): + if ((symbol = getSymbol(3, MS_NUMBER, MS_BINDING, MS_AUTO)) == -1) + return (MS_FAILURE); + + if (symbol == MS_NUMBER) { + if (msCheckNumber(msyynumber, MS_NUM_CHECK_RANGE, -360.0, 360.0) == + MS_FAILURE) { + msSetError(MS_MISCERR, + "Invalid ANGLE, must be between -360 and 360 (line %d)", + "loadStyle()", msyylineno); + return (MS_FAILURE); + } + style->angle = (double)msyynumber; + } else if (symbol == MS_BINDING) { + if (style->bindings[MS_STYLE_BINDING_ANGLE].item != NULL) + msFree(style->bindings[MS_STYLE_BINDING_ANGLE].item); + style->bindings[MS_STYLE_BINDING_ANGLE].item = + msStrdup(msyystring_buffer); + style->numbindings++; + } else { + style->autoangle = MS_TRUE; + } + break; + case (ANTIALIAS): + if ((symbol = getSymbol(2, MS_TRUE, MS_FALSE)) == -1) + return (MS_FAILURE); + if (symbol == MS_FALSE) { + style->antialiased = MS_FALSE; + } + break; + case (COLOR): + if (loadColor(&(style->color), + &(style->bindings[MS_STYLE_BINDING_COLOR])) != MS_SUCCESS) + return (MS_FAILURE); + if (style->bindings[MS_STYLE_BINDING_COLOR].item) + style->numbindings++; + break; + case (EOF): + msSetError(MS_EOFERR, NULL, "loadStyle()"); + return (MS_FAILURE); /* missing END (probably) */ + case (END): { + int alpha; + + /* apply opacity as the alpha channel color(s) */ + if (style->opacity < 100) { + alpha = MS_NINT(style->opacity * 2.55); + + style->color.alpha = alpha; + style->outlinecolor.alpha = alpha; + + style->mincolor.alpha = alpha; + style->maxcolor.alpha = alpha; + } + + return (MS_SUCCESS); + } break; + case (GAP): + if (getDouble(&(style->gap), MS_NUM_CHECK_NONE, -1, -1) == -1) + return (MS_FAILURE); + break; + case (INITIALGAP): + if (getDouble(&(style->initialgap), MS_NUM_CHECK_GTE, 0, -1) == + -1) { // zero is ok + msSetError(MS_MISCERR, + "INITIALGAP requires a positive values (line %d)", + "loadStyle()", msyylineno); + return (MS_FAILURE); + } + break; + case (MAXSCALEDENOM): + if (getDouble(&(style->maxscaledenom), MS_NUM_CHECK_GTE, 0, -1) == -1) + return (MS_FAILURE); + break; + case (MINSCALEDENOM): + if (getDouble(&(style->minscaledenom), MS_NUM_CHECK_GTE, 0, -1) == -1) + return (MS_FAILURE); + break; + case (GEOMTRANSFORM): { + int s; + if ((s = getSymbol(2, MS_STRING, MS_EXPRESSION)) == -1) + return (MS_FAILURE); + if (s == MS_STRING) + msStyleSetGeomTransform(style, msyystring_buffer); + else { + /* handle expression case here for the moment */ + msFree(style->_geomtransform.string); + style->_geomtransform.string = msStrdup(msyystring_buffer); + style->_geomtransform.type = MS_GEOMTRANSFORM_EXPRESSION; + } + } break; + case (LINECAP): + if ((style->linecap = getSymbol(4, MS_CJC_BUTT, MS_CJC_ROUND, + MS_CJC_SQUARE, MS_CJC_TRIANGLE)) == -1) + return (MS_FAILURE); + break; + case (LINEJOIN): + if ((style->linejoin = getSymbol(4, MS_CJC_NONE, MS_CJC_ROUND, + MS_CJC_MITER, MS_CJC_BEVEL)) == -1) + return (MS_FAILURE); + break; + case (LINEJOINMAXSIZE): + if (getDouble(&(style->linejoinmaxsize), MS_NUM_CHECK_GT, 0, -1) == -1) + return (MS_FAILURE); + break; + case (MAXSIZE): + if (getDouble(&(style->maxsize), MS_NUM_CHECK_GT, 0, -1) == -1) + return (MS_FAILURE); + break; + case (MINSIZE): + if (getDouble(&(style->minsize), MS_NUM_CHECK_GTE, 0, -1) == -1) + return (MS_FAILURE); + break; + case (MAXWIDTH): + if (getDouble(&(style->maxwidth), MS_NUM_CHECK_GT, 0, -1) == -1) + return (MS_FAILURE); + break; + case (MINWIDTH): + if (getDouble(&(style->minwidth), MS_NUM_CHECK_GTE, 0, -1) == -1) + return (MS_FAILURE); + break; + case (OFFSET): + if ((symbol = getSymbol(2, MS_NUMBER, MS_BINDING)) == -1) + return (MS_FAILURE); + if (symbol == MS_NUMBER) + style->offsetx = (double)msyynumber; // any double ok + else { + if (style->bindings[MS_STYLE_BINDING_OFFSET_X].item != NULL) + msFree(style->bindings[MS_STYLE_BINDING_OFFSET_X].item); + style->bindings[MS_STYLE_BINDING_OFFSET_X].item = + msStrdup(msyystring_buffer); + style->numbindings++; + } + + if ((symbol = getSymbol(2, MS_NUMBER, MS_BINDING)) == -1) + return (MS_FAILURE); + if (symbol == MS_NUMBER) + style->offsety = (double)msyynumber; // any double ok + else { + if (style->bindings[MS_STYLE_BINDING_OFFSET_Y].item != NULL) + msFree(style->bindings[MS_STYLE_BINDING_OFFSET_Y].item); + style->bindings[MS_STYLE_BINDING_OFFSET_Y].item = + msStrdup(msyystring_buffer); + style->numbindings++; + } + break; + case (OPACITY): + if ((symbol = getSymbol(2, MS_NUMBER, MS_BINDING)) == -1) + return (MS_FAILURE); + if (symbol == MS_NUMBER) + style->opacity = MS_MAX(MS_MIN((int)msyynumber, 100), + 0); /* force opacity to between 0 and 100 */ + else { + if (style->bindings[MS_STYLE_BINDING_OPACITY].item != NULL) + msFree(style->bindings[MS_STYLE_BINDING_OPACITY].item); + style->bindings[MS_STYLE_BINDING_OPACITY].item = + msStrdup(msyystring_buffer); + style->numbindings++; + } + break; + case (OUTLINECOLOR): + if (loadColor(&(style->outlinecolor), + &(style->bindings[MS_STYLE_BINDING_OUTLINECOLOR])) != + MS_SUCCESS) + return (MS_FAILURE); + if (style->bindings[MS_STYLE_BINDING_OUTLINECOLOR].item) + style->numbindings++; + break; + case (PATTERN): { + int done = MS_FALSE; + for (;;) { /* read till the next END */ + switch (msyylex()) { + case (END): + if (style->patternlength < 2) { + msSetError(MS_SYMERR, + "Not enough pattern elements. A minimum of 2 are " + "required (line %d)", + "loadStyle()", msyylineno); + return (MS_FAILURE); + } + done = MS_TRUE; + break; + case (MS_NUMBER): /* read the pattern values */ + if (style->patternlength == MS_MAXPATTERNLENGTH) { + msSetError(MS_SYMERR, "Pattern too long.", "loadStyle()"); + return (MS_FAILURE); + } + style->pattern[style->patternlength] = + atof(msyystring_buffer); // good enough? + style->patternlength++; + break; + default: + msSetError(MS_TYPEERR, "Parsing error near (%s):(line %d)", + "loadStyle()", msyystring_buffer, msyylineno); + return (MS_FAILURE); + } + if (done == MS_TRUE) + break; + } + break; + } + case (OUTLINEWIDTH): + if ((symbol = getSymbol(2, MS_NUMBER, MS_BINDING)) == -1) + return (MS_FAILURE); + if (symbol == MS_NUMBER) { + if (msCheckNumber(msyynumber, MS_NUM_CHECK_GTE, 0, -1) == MS_FAILURE) { + msSetError(MS_MISCERR, + "Invalid OUTLINEWIDTH, must be greater then or equal to 0 " + "(line %d)", + "loadStyle()", msyylineno); + return (MS_FAILURE); + } + style->outlinewidth = (double)msyynumber; + } else { + if (style->bindings[MS_STYLE_BINDING_OUTLINEWIDTH].item != NULL) + msFree(style->bindings[MS_STYLE_BINDING_OUTLINEWIDTH].item); + style->bindings[MS_STYLE_BINDING_OUTLINEWIDTH].item = + msStrdup(msyystring_buffer); + style->numbindings++; + } + break; + case (SIZE): + if (style->exprBindings[MS_STYLE_BINDING_SIZE].string) { + msFreeExpression(&style->exprBindings[MS_STYLE_BINDING_SIZE]); + style->nexprbindings--; + } + + if ((symbol = getSymbol(3, MS_EXPRESSION, MS_NUMBER, MS_BINDING)) == -1) + return (MS_FAILURE); + if (symbol == MS_NUMBER) { + if (msCheckNumber(msyynumber, MS_NUM_CHECK_GT, 0, -1) == MS_FAILURE) { + msSetError(MS_MISCERR, + "Invalid SIZE, must be greater than 0 (line %d)", + "loadStyle()", msyylineno); + return (MS_FAILURE); + } + style->size = (double)msyynumber; + } else if (symbol == MS_EXPRESSION) { + msFree(style->exprBindings[MS_STYLE_BINDING_SIZE].string); + style->exprBindings[MS_STYLE_BINDING_SIZE].string = + msStrdup(msyystring_buffer); + style->exprBindings[MS_STYLE_BINDING_SIZE].type = MS_EXPRESSION; + style->nexprbindings++; + } else { + if (style->bindings[MS_STYLE_BINDING_SIZE].item != NULL) + msFree(style->bindings[MS_STYLE_BINDING_SIZE].item); + style->bindings[MS_STYLE_BINDING_SIZE].item = + msStrdup(msyystring_buffer); + style->numbindings++; + } + break; + case (STYLE): + break; /* for string loads */ + case (SYMBOL): + if ((symbol = getSymbol(3, MS_NUMBER, MS_STRING, MS_BINDING)) == -1) + return (MS_FAILURE); + if (symbol == MS_NUMBER) { + if (msCheckNumber(msyynumber, MS_NUM_CHECK_GTE, 0, -1) == MS_FAILURE) { + msSetError( + MS_MISCERR, + "Invalid SYMBOL id, must be greater than or equal to 0 (line %d)", + "loadStyle()", msyylineno); + return (MS_FAILURE); + } + if (style->symbolname != NULL) { + msFree(style->symbolname); + style->symbolname = NULL; + } + style->symbol = (int)msyynumber; + } else if (symbol == MS_STRING) { + if (style->symbolname != NULL) + msFree(style->symbolname); + style->symbolname = msStrdup(msyystring_buffer); + } else { + if (style->bindings[MS_STYLE_BINDING_SYMBOL].item != NULL) + msFree(style->bindings[MS_STYLE_BINDING_SYMBOL].item); + style->bindings[MS_STYLE_BINDING_SYMBOL].item = + msStrdup(msyystring_buffer); + style->numbindings++; + } + break; + case (WIDTH): + if ((symbol = getSymbol(2, MS_NUMBER, MS_BINDING)) == -1) + return (MS_FAILURE); + if (symbol == MS_NUMBER) { + if (msCheckNumber(msyynumber, MS_NUM_CHECK_GTE, 0, -1) == MS_FAILURE) { + msSetError( + MS_MISCERR, + "Invalid WIDTH, must be greater than or equal to 0 (line %d)", + "loadStyle()", msyylineno); + return (MS_FAILURE); + } + style->width = (double)msyynumber; + } else { + if (style->bindings[MS_STYLE_BINDING_WIDTH].item != NULL) + msFree(style->bindings[MS_STYLE_BINDING_WIDTH].item); + style->bindings[MS_STYLE_BINDING_WIDTH].item = + msStrdup(msyystring_buffer); + style->numbindings++; + } + break; + case (POLAROFFSET): + if ((symbol = getSymbol(2, MS_NUMBER, MS_BINDING)) == -1) + return (MS_FAILURE); + if (symbol == MS_NUMBER) { + style->polaroffsetpixel = (double)msyynumber; // ok? + } else { + if (style->bindings[MS_STYLE_BINDING_POLAROFFSET_PIXEL].item != NULL) + msFree(style->bindings[MS_STYLE_BINDING_POLAROFFSET_PIXEL].item); + style->bindings[MS_STYLE_BINDING_POLAROFFSET_PIXEL].item = + msStrdup(msyystring_buffer); + style->numbindings++; + } + + if ((symbol = getSymbol(2, MS_NUMBER, MS_BINDING)) == -1) + return (MS_FAILURE); + if (symbol == MS_NUMBER) { + style->polaroffsetangle = (double)msyynumber; // ok? + } else { + if (style->bindings[MS_STYLE_BINDING_POLAROFFSET_ANGLE].item != NULL) + msFree(style->bindings[MS_STYLE_BINDING_POLAROFFSET_ANGLE].item); + style->bindings[MS_STYLE_BINDING_POLAROFFSET_ANGLE].item = + msStrdup(msyystring_buffer); + style->numbindings++; + } + break; + default: + if (strlen(msyystring_buffer) > 0) { + msSetError(MS_IDENTERR, "Parsing error near (%s):(line %d)", + "loadStyle()", msyystring_buffer, msyylineno); + return (MS_FAILURE); + } else { + return (MS_SUCCESS); /* end of a string, not an error */ + } + } + } +} + +int msUpdateStyleFromString(styleObj *style, char *string) { + if (!style || !string) + return MS_FAILURE; + + msAcquireLock(TLOCK_PARSER); + + msyystate = MS_TOKENIZE_STRING; + msyystring = string; + msyylex(); /* sets things up, but doesn't process any tokens */ + + msyylineno = 1; /* start at line 1 */ + + if (loadStyle(style) == -1) { + msReleaseLock(TLOCK_PARSER); + return MS_FAILURE; /* parse error */ + ; + } + + msyylex_destroy(); + msReleaseLock(TLOCK_PARSER); + return MS_SUCCESS; +} + +int freeStyle(styleObj *style) { + int i; + + if (MS_REFCNT_DECR_IS_NOT_ZERO(style)) { + return MS_FAILURE; + } + + msFree(style->symbolname); + msFreeExpression(&style->_geomtransform); + msFree(style->rangeitem); + + for (i = 0; i < MS_STYLE_BINDING_LENGTH; i++) { + msFree(style->bindings[i].item); + msFreeExpression(&(style->exprBindings[i])); + } + + return MS_SUCCESS; +} + +void writeStyle(FILE *stream, int indent, styleObj *style) { + + indent++; + writeBlockBegin(stream, indent, "STYLE"); + + if (style->numbindings > 0 && style->bindings[MS_STYLE_BINDING_ANGLE].item) + writeAttributeBinding(stream, indent, "ANGLE", + &(style->bindings[MS_STYLE_BINDING_ANGLE])); + else + writeNumberOrKeyword(stream, indent, "ANGLE", 0, style->angle, + style->autoangle, 1, MS_TRUE, "AUTO"); + + if (style->numbindings > 0 && style->bindings[MS_STYLE_BINDING_COLOR].item) + writeAttributeBinding(stream, indent, "COLOR", + &(style->bindings[MS_STYLE_BINDING_COLOR])); + else + writeColor(stream, indent, "COLOR", NULL, &(style->color)); + + writeNumber(stream, indent, "GAP", 0, style->gap); + writeNumber(stream, indent, "INITIALGAP", -1, style->initialgap); + + if (style->_geomtransform.type == MS_GEOMTRANSFORM_EXPRESSION) { + writeIndent(stream, indent + 1); + msIO_fprintf(stream, "GEOMTRANSFORM (%s)\n", style->_geomtransform.string); + } else if (style->_geomtransform.type != MS_GEOMTRANSFORM_NONE) { + writeKeyword(stream, indent, "GEOMTRANSFORM", style->_geomtransform.type, 8, + MS_GEOMTRANSFORM_BBOX, "\"bbox\"", MS_GEOMTRANSFORM_END, + "\"end\"", MS_GEOMTRANSFORM_LABELPOINT, "\"labelpnt\"", + MS_GEOMTRANSFORM_LABELPOLY, "\"labelpoly\"", + MS_GEOMTRANSFORM_LABELCENTER, "\"labelcenter\"", + MS_GEOMTRANSFORM_START, "\"start\"", MS_GEOMTRANSFORM_VERTICES, + "\"vertices\"", MS_GEOMTRANSFORM_CENTROID, "\"centroid\""); + } + + if (style->linecap != MS_CJC_DEFAULT_CAPS) { + writeKeyword(stream, indent, "LINECAP", (int)style->linecap, 5, MS_CJC_NONE, + "NONE", MS_CJC_ROUND, "ROUND", MS_CJC_SQUARE, "SQUARE", + MS_CJC_BUTT, "BUTT", MS_CJC_TRIANGLE, "TRIANGLE"); + } + if (style->linejoin != MS_CJC_DEFAULT_JOINS) { + writeKeyword(stream, indent, "LINEJOIN", (int)style->linejoin, 5, + MS_CJC_NONE, "NONE", MS_CJC_ROUND, "ROUND", MS_CJC_BEVEL, + "BEVEL", MS_CJC_MITER, "MITER"); + } + writeNumber(stream, indent, "LINEJOINMAXSIZE", MS_CJC_DEFAULT_JOIN_MAXSIZE, + style->linejoinmaxsize); + + writeNumber(stream, indent, "MAXSCALEDENOM", -1, style->maxscaledenom); + writeNumber(stream, indent, "MAXSIZE", MS_MAXSYMBOLSIZE, style->maxsize); + writeNumber(stream, indent, "MAXWIDTH", MS_MAXSYMBOLWIDTH, style->maxwidth); + writeNumber(stream, indent, "MINSCALEDENOM", -1, style->minscaledenom); + writeNumber(stream, indent, "MINSIZE", MS_MINSYMBOLSIZE, style->minsize); + writeNumber(stream, indent, "MINWIDTH", MS_MINSYMBOLWIDTH, style->minwidth); + if ((style->numbindings > 0 && + (style->bindings[MS_STYLE_BINDING_OFFSET_X].item || + style->bindings[MS_STYLE_BINDING_OFFSET_Y].item)) || + style->offsetx != 0 || style->offsety != 0) + writeDimension(stream, indent, "OFFSET", style->offsetx, style->offsety, + style->bindings[MS_STYLE_BINDING_OFFSET_X].item, + style->bindings[MS_STYLE_BINDING_OFFSET_Y].item); + if ((style->numbindings > 0 && + (style->bindings[MS_STYLE_BINDING_POLAROFFSET_PIXEL].item || + style->bindings[MS_STYLE_BINDING_POLAROFFSET_ANGLE].item)) || + style->polaroffsetangle != 0 || style->polaroffsetpixel != 0) + writeDimension(stream, indent, "POLAROFFSET", style->polaroffsetpixel, + style->polaroffsetangle, + style->bindings[MS_STYLE_BINDING_POLAROFFSET_PIXEL].item, + style->bindings[MS_STYLE_BINDING_POLAROFFSET_ANGLE].item); + + if (style->numbindings > 0 && style->bindings[MS_STYLE_BINDING_OPACITY].item) + writeAttributeBinding(stream, indent, "OPACITY", + &(style->bindings[MS_STYLE_BINDING_OPACITY])); + else + writeNumber(stream, indent, "OPACITY", 100, style->opacity); + + if (style->numbindings > 0 && + style->bindings[MS_STYLE_BINDING_OUTLINECOLOR].item) + writeAttributeBinding(stream, indent, "OUTLINECOLOR", + &(style->bindings[MS_STYLE_BINDING_OUTLINECOLOR])); + else + writeColor(stream, indent, "OUTLINECOLOR", NULL, &(style->outlinecolor)); + + if (style->numbindings > 0 && + style->bindings[MS_STYLE_BINDING_OUTLINEWIDTH].item) + writeAttributeBinding(stream, indent, "OUTLINEWIDTH", + &(style->bindings[MS_STYLE_BINDING_OUTLINEWIDTH])); + else + writeNumber(stream, indent, "OUTLINEWIDTH", 0, style->outlinewidth); + + /* PATTERN */ + if (style->patternlength != 0) { + int i; + indent++; + writeBlockBegin(stream, indent, "PATTERN"); + writeIndent(stream, indent); + for (i = 0; i < style->patternlength; i++) + msIO_fprintf(stream, " %.2f", style->pattern[i]); + msIO_fprintf(stream, "\n"); + writeBlockEnd(stream, indent, "PATTERN"); + indent--; + } + + if (style->numbindings > 0 && style->bindings[MS_STYLE_BINDING_SIZE].item) + writeAttributeBinding(stream, indent, "SIZE", + &(style->bindings[MS_STYLE_BINDING_SIZE])); + else + writeNumber(stream, indent, "SIZE", -1, style->size); + + if (style->numbindings > 0 && style->bindings[MS_STYLE_BINDING_SYMBOL].item) + writeAttributeBinding(stream, indent, "SYMBOL", + &(style->bindings[MS_STYLE_BINDING_SYMBOL])); + else + writeNumberOrString(stream, indent, "SYMBOL", 0, style->symbol, + style->symbolname); + + if (style->numbindings > 0 && style->bindings[MS_STYLE_BINDING_WIDTH].item) + writeAttributeBinding(stream, indent, "WIDTH", + &(style->bindings[MS_STYLE_BINDING_WIDTH])); + else + writeNumber(stream, indent, "WIDTH", 1, style->width); + + writeString(stream, indent, "RANGEITEM", NULL, style->rangeitem); + /* If COLORRANGE is valid, assume DATARANGE also needs to be written */ + if (MS_VALID_COLOR(style->mincolor) && MS_VALID_COLOR(style->maxcolor)) { + writeColorRange(stream, indent, "COLORRANGE", &(style->mincolor), + &(style->maxcolor)); + writeDoubleRange(stream, indent, "DATARANGE", style->minvalue, + style->maxvalue); + } + + writeBlockEnd(stream, indent, "STYLE"); +} + +char *msWriteStyleToString(styleObj *style) { + msIOContext context; + msIOBuffer buffer; + + context.label = NULL; + context.write_channel = MS_TRUE; + context.readWriteFunc = msIO_bufferWrite; + context.cbData = &buffer; + buffer.data = NULL; + buffer.data_len = 0; + buffer.data_offset = 0; + + msIO_installHandlers(NULL, &context, NULL); + + writeStyle(stdout, -1, style); + msIO_bufferWrite(&buffer, "", 1); + + msIO_installHandlers(NULL, NULL, NULL); + + return (char *)buffer.data; +} + +/* +** Initialize, load and free a single class +*/ +int initClass(classObj *class) { + class->status = MS_ON; + class->debug = MS_OFF; + MS_REFCNT_INIT(class); + class->isfallback = FALSE; + + msInitExpression(&(class->expression)); + class->name = NULL; + class->title = NULL; + msInitExpression(&(class->text)); + + class->template = NULL; + + initHashTable(&(class->metadata)); + initHashTable(&(class->validation)); + + class->maxscaledenom = class->minscaledenom = -1.0; + class->minfeaturesize = -1; /* no limit */ + + /* Set maxstyles = 0, styles[] will be allocated as needed on first call + * to msGrowClassStyles() + */ + class->numstyles = class->maxstyles = 0; + class->styles = NULL; + + class->numlabels = class->maxlabels = 0; + class->labels = NULL; + + class->keyimage = NULL; + + class->group = NULL; + + class->leader = NULL; + + class->sizeunits = MS_INHERIT; + class->scalefactor = 1.0; + + return (0); +} + +int freeClass(classObj *class) { + int i; + + if (MS_REFCNT_DECR_IS_NOT_ZERO(class)) { + return MS_FAILURE; + } + + msFreeExpression(&(class->expression)); + msFreeExpression(&(class->text)); + msFree(class->name); + msFree(class->title); + msFree(class->template); + msFree(class->group); + + msFreeHashItems(&(class->metadata)); + msFreeHashItems(&(class->validation)); + + for (i = 0; i < class->numstyles; i++) { /* each style */ + if (class->styles[i] != NULL) { + if (freeStyle(class->styles[i]) == MS_SUCCESS) { + msFree(class->styles[i]); + } + } + } + msFree(class->styles); + + for (i = 0; i < class->numlabels; i++) { /* each label */ + if (class->labels[i] != NULL) { + if (freeLabel(class->labels[i]) == MS_SUCCESS) { + msFree(class->labels[i]); + } + } + } + msFree(class->labels); + + msFree(class->keyimage); + + if (class->leader) { + freeLabelLeader(class->leader); + msFree(class->leader); + class->leader = NULL; + } + + return MS_SUCCESS; +} + +/* +** Ensure there is at least one free entry in the sttyles array of this +** classObj. Grow the allocated styles array if necessary and allocate +** a new style for styles[numstyles] if there is not already one, +** setting its contents to all zero bytes (i.e. does not call initStyle() +** on it). +** +** This function is safe to use for the initial allocation of the styles[] +** array as well (i.e. when maxstyles==0 and styles==NULL) +** +** Returns a reference to the new styleObj on success, NULL on error. +*/ +styleObj *msGrowClassStyles(classObj *class) { + /* Do we need to increase the size of styles[] by MS_STYLE_ALLOCSIZE? + */ + if (class->numstyles == class->maxstyles) { + styleObj **newStylePtr; + int i, newsize; + + newsize = class->maxstyles + MS_STYLE_ALLOCSIZE; + + /* Alloc/realloc styles */ + newStylePtr = + (styleObj **)realloc(class->styles, newsize * sizeof(styleObj *)); + MS_CHECK_ALLOC(newStylePtr, newsize * sizeof(styleObj *), NULL); + + class->styles = newStylePtr; + class->maxstyles = newsize; + for (i = class->numstyles; i < class->maxstyles; i++) { + class->styles[i] = NULL; + } + } + + if (class->styles[class->numstyles] == NULL) { + class->styles[class->numstyles] = (styleObj *)calloc(1, sizeof(styleObj)); + MS_CHECK_ALLOC(class->styles[class->numstyles], sizeof(styleObj), NULL); + } + + return class->styles[class->numstyles]; +} + +/* exactly the same as for a classObj */ +styleObj *msGrowLabelStyles(labelObj *label) { + /* Do we need to increase the size of styles[] by MS_STYLE_ALLOCSIZE? + */ + if (label->numstyles == label->maxstyles) { + styleObj **newStylePtr; + int i, newsize; + + newsize = label->maxstyles + MS_STYLE_ALLOCSIZE; + + /* Alloc/realloc styles */ + newStylePtr = + (styleObj **)realloc(label->styles, newsize * sizeof(styleObj *)); + MS_CHECK_ALLOC(newStylePtr, newsize * sizeof(styleObj *), NULL); + + label->styles = newStylePtr; + label->maxstyles = newsize; + for (i = label->numstyles; i < label->maxstyles; i++) { + label->styles[i] = NULL; + } + } + + if (label->styles[label->numstyles] == NULL) { + label->styles[label->numstyles] = (styleObj *)calloc(1, sizeof(styleObj)); + MS_CHECK_ALLOC(label->styles[label->numstyles], sizeof(styleObj), NULL); + } + + return label->styles[label->numstyles]; +} + +/* exactly the same as for a labelLeaderObj, needs refactoring */ +styleObj *msGrowLeaderStyles(labelLeaderObj *leader) { + /* Do we need to increase the size of styles[] by MS_STYLE_ALLOCSIZE? + */ + if (leader->numstyles == leader->maxstyles) { + styleObj **newStylePtr; + int i, newsize; + + newsize = leader->maxstyles + MS_STYLE_ALLOCSIZE; + + /* Alloc/realloc styles */ + newStylePtr = + (styleObj **)realloc(leader->styles, newsize * sizeof(styleObj *)); + MS_CHECK_ALLOC(newStylePtr, newsize * sizeof(styleObj *), NULL); + + leader->styles = newStylePtr; + leader->maxstyles = newsize; + for (i = leader->numstyles; i < leader->maxstyles; i++) { + leader->styles[i] = NULL; + } + } + + if (leader->styles[leader->numstyles] == NULL) { + leader->styles[leader->numstyles] = (styleObj *)calloc(1, sizeof(styleObj)); + MS_CHECK_ALLOC(leader->styles[leader->numstyles], sizeof(styleObj), NULL); + } + + return leader->styles[leader->numstyles]; +} + +/* msMaybeAllocateClassStyle() +** +** Ensure that requested style index exists and has been initialized. +** +** Returns MS_SUCCESS/MS_FAILURE. +*/ +int msMaybeAllocateClassStyle(classObj *c, int idx) { + if (c == NULL) + return MS_FAILURE; + + if (idx < 0) { + msSetError(MS_MISCERR, "Invalid style index: %d", + "msMaybeAllocateClassStyle()", idx); + return MS_FAILURE; + } + + /* Alloc empty styles as needed up to idx. + * Nothing to do if requested style already exists + */ + while (c->numstyles <= idx) { + if (msGrowClassStyles(c) == NULL) + return MS_FAILURE; + + if (initStyle(c->styles[c->numstyles]) == MS_FAILURE) { + msSetError(MS_MISCERR, "Failed to init new styleObj", + "msMaybeAllocateClassStyle()"); + freeStyle(c->styles[c->numstyles]); + free(c->styles[c->numstyles]); + c->styles[c->numstyles] = NULL; + return (MS_FAILURE); + } + c->numstyles++; + } + return MS_SUCCESS; +} + +/* + * Reset style info in the class to defaults + * the only members we don't touch are name, expression, and join/query stuff + * This is used with STYLEITEM before overwriting the contents of a class. + */ +void resetClassStyle(classObj *class) { + int i; + + /* reset labels */ + for (i = 0; i < class->numlabels; i++) { + if (class->labels[i] != NULL) { + if (freeLabel(class->labels[i]) == MS_SUCCESS) { + msFree(class->labels[i]); + } + class->labels[i] = NULL; + } + } + class->numlabels = 0; + + msFreeExpression(&(class->text)); + msInitExpression(&(class->text)); + + /* reset styles */ + for (i = 0; i < class->numstyles; i++) { + if (class->styles[i] != NULL) { + if (freeStyle(class->styles[i]) == MS_SUCCESS) { + msFree(class->styles[i]); + } + class->styles[i] = NULL; + } + } + class->numstyles = 0; + + class->layer = NULL; +} + +labelObj *msGrowClassLabels(classObj *class) { + + /* Do we need to increase the size of labels[] by MS_LABEL_ALLOCSIZE? + */ + if (class->numlabels == class->maxlabels) { + labelObj **newLabelPtr; + int i, newsize; + + newsize = class->maxlabels + MS_LABEL_ALLOCSIZE; + + /* Alloc/realloc labels */ + newLabelPtr = + (labelObj **)realloc(class->labels, newsize * sizeof(labelObj *)); + MS_CHECK_ALLOC(newLabelPtr, newsize * sizeof(labelObj *), NULL); + + class->labels = newLabelPtr; + class->maxlabels = newsize; + for (i = class->numlabels; i < class->maxlabels; i++) { + class->labels[i] = NULL; + } + } + + if (class->labels[class->numlabels] == NULL) { + class->labels[class->numlabels] = (labelObj *)calloc(1, sizeof(labelObj)); + MS_CHECK_ALLOC(class->labels[class->numlabels], sizeof(labelObj), NULL); + } + + return class->labels[class->numlabels]; +} + +int loadClass(classObj *class, layerObj *layer) { + if (!class || !layer) + return (-1); + + class->layer = (layerObj *)layer; + + for (;;) { + switch (msyylex()) { + case (CLASS): + break; /* for string loads */ + case (DEBUG): + if ((class->debug = getSymbol(3, MS_ON, MS_OFF, MS_NUMBER)) == -1) + return (-1); + if (class->debug == MS_NUMBER) { + if (msCheckNumber(msyynumber, MS_NUM_CHECK_RANGE, 0, 5) == MS_FAILURE) { + msSetError(MS_MISCERR, + "Invalid DEBUG level, must be between 0 and 5 (line %d)", + "loadClass()", msyylineno); + return (-1); + } + class->debug = (int)msyynumber; + } + break; + case (EOF): + msSetError(MS_EOFERR, NULL, "loadClass()"); + return (-1); + case (END): + return (0); + break; + case (EXPRESSION): + if (loadExpression(&(class->expression)) == -1) + return (-1); /* loadExpression() cleans up previously allocated + expression */ + break; + case (GROUP): + if (getString(&class->group) == MS_FAILURE) + return (-1); /* getString() cleans up previously allocated string */ + break; + case (KEYIMAGE): + if (getString(&class->keyimage) == MS_FAILURE) + return (-1); /* getString() cleans up previously allocated string */ + break; + case (LABEL): + if (msGrowClassLabels(class) == NULL) + return (-1); + initLabel(class->labels[class->numlabels]); + class->labels[class->numlabels]->size = + MS_MEDIUM; /* only set a default if the LABEL section is present */ + if (loadLabel(class->labels[class->numlabels]) == -1) { + freeLabel(class->labels[class->numlabels]); + free(class->labels[class->numlabels]); + class->labels[class->numlabels] = NULL; + return (-1); + } + class->numlabels++; + break; + case (LEADER): + if (!class->leader) { + class->leader = msSmallMalloc(sizeof(labelLeaderObj)); + initLeader(class->leader); + } + if (loadLeader(class->leader) == -1) + return (-1); + break; + case (MAXSCALE): + case (MAXSCALEDENOM): + if (getDouble(&(class->maxscaledenom), MS_NUM_CHECK_GTE, 0, -1) == -1) + return (-1); + break; + case (METADATA): + if (loadHashTable(&(class->metadata)) != MS_SUCCESS) + return (-1); + break; + case (MINSCALE): + case (MINSCALEDENOM): + if (getDouble(&(class->minscaledenom), MS_NUM_CHECK_GTE, 0, -1) == -1) + return (-1); + break; + case (MINFEATURESIZE): + if (getInteger(&(class->minfeaturesize), MS_NUM_CHECK_GT, 0, -1) == -1) + return (-1); + break; + case (NAME): + if (getString(&class->name) == MS_FAILURE) + return (-1); + break; + case (STATUS): + if ((class->status = getSymbol(2, MS_ON, MS_OFF)) == -1) + return (-1); + break; + case (STYLE): + if (msGrowClassStyles(class) == NULL) + return (-1); + initStyle(class->styles[class->numstyles]); + if (loadStyle(class->styles[class->numstyles]) != MS_SUCCESS) { + freeStyle(class->styles[class->numstyles]); + free(class->styles[class->numstyles]); + class->styles[class->numstyles] = NULL; + return (-1); + } + class->numstyles++; + break; + case (TEMPLATE): + if (getString(&class->template) == MS_FAILURE) + return (-1); /* getString() cleans up previously allocated string */ + break; + case (TEXT): + if (loadExpression(&(class->text)) == -1) + return (-1); /* loadExpression() cleans up previously allocated + expression */ + if ((class->text.type != MS_STRING) && + (class->text.type != MS_EXPRESSION)) { + msSetError( + MS_MISCERR, + "Text expressions support constant or tagged replacement strings.", + "loadClass()"); + return (-1); + } + break; + case (TITLE): + if (getString(&class->title) == MS_FAILURE) + return (-1); /* getString() cleans up previously allocated string */ + break; + case (VALIDATION): + if (loadHashTable(&(class->validation)) != MS_SUCCESS) + return (-1); + break; + case (FALLBACK): + if ((class->isfallback = getSymbol(2, MS_TRUE, MS_FALSE)) == -1) + return (-1); + break; + default: + if (strlen(msyystring_buffer) > 0) { + msSetError(MS_IDENTERR, "Parsing error near (%s):(line %d)", + "loadClass()", msyystring_buffer, msyylineno); + return (-1); + } else { + return (0); /* end of a string, not an error */ + } + } + } +} + +static int classResolveSymbolNames(classObj *class) { + int i, j; + int try_addimage_if_notfound = MS_TRUE; + + /* step through styles and labels to resolve symbol names */ + /* class styles */ + for (i = 0; i < class->numstyles; i++) { + if (class->styles[i]->symbolname) { + if ((class->styles[i]->symbol = msGetSymbolIndex( + &(class->layer->map->symbolset), class->styles[i]->symbolname, + try_addimage_if_notfound)) == -1) { + msSetError(MS_MISCERR, + "Undefined symbol \"%s\" in class, style %d of layer %s.", + "classResolveSymbolNames()", class->styles[i]->symbolname, i, + class->layer->name); + return MS_FAILURE; + } + } + } + + /* label styles */ + for (i = 0; i < class->numlabels; i++) { + for (j = 0; j < class->labels[i]->numstyles; j++) { + if (class->labels[i]->styles[j]->symbolname) { + if ((class->labels[i]->styles[j]->symbol = + msGetSymbolIndex(&(class->layer->map->symbolset), + class->labels[i]->styles[j]->symbolname, + try_addimage_if_notfound)) == -1) { + msSetError( + MS_MISCERR, + "Undefined symbol \"%s\" in class, label style %d of layer %s.", + "classResolveSymbolNames()", + class->labels[i]->styles[j]->symbolname, j, class->layer->name); + return MS_FAILURE; + } + } + } + } + + return MS_SUCCESS; +} + +int msUpdateClassFromString(classObj *class, char *string) { + if (!class || !string) + return MS_FAILURE; + + msAcquireLock(TLOCK_PARSER); + + msyystate = MS_TOKENIZE_STRING; + msyystring = string; + msyylex(); /* sets things up, but doesn't process any tokens */ + + msyylineno = 1; /* start at line 1 */ + + if (loadClass(class, class->layer) == -1) { + msReleaseLock(TLOCK_PARSER); + return MS_FAILURE; /* parse error */ + ; + } + + msyylex_destroy(); + msReleaseLock(TLOCK_PARSER); + + if (classResolveSymbolNames(class) != MS_SUCCESS) + return MS_FAILURE; + + return MS_SUCCESS; +} + +static void writeClass(FILE *stream, int indent, classObj *class) { + int i; + + if (class->status == MS_DELETE) + return; + + indent++; + writeBlockBegin(stream, indent, "CLASS"); + writeString(stream, indent, "NAME", NULL, class->name); + writeString(stream, indent, "GROUP", NULL, class->group); + writeNumber(stream, indent, "DEBUG", 0, class->debug); + writeExpression(stream, indent, "EXPRESSION", &(class->expression)); + writeString(stream, indent, "KEYIMAGE", NULL, class->keyimage); + for (i = 0; i < class->numlabels; i++) + writeLabel(stream, indent, class->labels[i]); + if (class->leader) + writeLeader(stream, indent, class->leader); + writeNumber(stream, indent, "MAXSCALEDENOM", -1, class->maxscaledenom); + writeHashTable(stream, indent, "METADATA", &(class->metadata)); + writeNumber(stream, indent, "MINSCALEDENOM", -1, class->minscaledenom); + writeNumber(stream, indent, "MINFEATURESIZE", -1, class->minfeaturesize); + writeKeyword(stream, indent, "STATUS", class->status, 1, MS_OFF, "OFF"); + for (i = 0; i < class->numstyles; i++) + writeStyle(stream, indent, class->styles[i]); + writeString(stream, indent, "TEMPLATE", NULL, class->template); + writeExpression(stream, indent, "TEXT", &(class->text)); + writeString(stream, indent, "TITLE", NULL, class->title); + writeHashTable(stream, indent, "VALIDATION", &(class->validation)); + writeKeyword(stream, indent, "FALLBACK", class->isfallback, 1, MS_TRUE, + "TRUE"); + writeBlockEnd(stream, indent, "CLASS"); +} + +static void writeIdentify(FILE *stream, int indent, layerObj *layer) { + if (layer->identificationclassauto || layer->identificationclassgroup) { + indent++; + writeBlockBegin(stream, indent, "IDENTIFY"); + if (layer->identificationclassauto) { + writeIndent(stream, indent + 1); + msIO_fprintf(stream, "CLASSAUTO\n"); + } + if (layer->identificationclassgroup) + writeString(stream, indent, "CLASSGROUP", NULL, + layer->identificationclassgroup); + writeBlockEnd(stream, indent, "IDENTIFY"); + } +} + +char *msWriteClassToString(classObj *class) { + msIOContext context; + msIOBuffer buffer; + + context.label = NULL; + context.write_channel = MS_TRUE; + context.readWriteFunc = msIO_bufferWrite; + context.cbData = &buffer; + buffer.data = NULL; + buffer.data_len = 0; + buffer.data_offset = 0; + + msIO_installHandlers(NULL, &context, NULL); + + writeClass(stdout, -1, class); + msIO_bufferWrite(&buffer, "", 1); + + msIO_installHandlers(NULL, NULL, NULL); + + return (char *)buffer.data; +} + +int initCompositingFilter(CompositingFilter *filter) { + filter->filter = NULL; + filter->next = NULL; + return MS_SUCCESS; +} + +void freeCompositingFilter(CompositingFilter *filter) { + if (!filter) + return; + if (filter->next) + freeCompositingFilter(filter->next); + free(filter->filter); + free(filter); +} + +int initLayerCompositer(LayerCompositer *compositer) { + compositer->comp_op = MS_COMPOP_SRC_OVER; + compositer->opacity = 100; + compositer->next = NULL; + compositer->filter = NULL; + return MS_SUCCESS; +} + +void freeLayerCompositer(LayerCompositer *compositer) { + if (!compositer) + return; + if (compositer->next) + freeLayerCompositer(compositer->next); + freeCompositingFilter(compositer->filter); + free(compositer); +} + +/* +** Initialize, load and free a single layer structure +*/ +int initLayer(layerObj *layer, mapObj *map) { + if (layer == NULL) { + msSetError(MS_MEMERR, "Layer is null", "initLayer()"); + return (-1); + } + layer->debug = (int)msGetGlobalDebugLevel(); + MS_REFCNT_INIT(layer); + + /* Set maxclasses = 0, class[] will be allocated as needed on first call + * to msGrowLayerClasses() + */ + layer->numclasses = 0; + layer->maxclasses = 0; + layer->class = NULL; + + layer->name = NULL; + layer->group = NULL; + layer->status = MS_OFF; + layer->data = NULL; + layer->rendermode = MS_FIRST_MATCHING_CLASS; + + layer->map = map; /* point back to the encompassing structure */ + + layer->type = -1; + + layer->toleranceunits = MS_PIXELS; + layer->tolerance = + -1; /* perhaps this should have a different value based on type */ + layer->identificationclassauto = MS_FALSE; + layer->identificationclassgroup = NULL; + + layer->symbolscaledenom = -1.0; /* -1 means nothing is set */ + layer->scalefactor = 1.0; + layer->maxscaledenom = -1.0; + layer->minscaledenom = -1.0; + layer->minfeaturesize = -1; /* no limit */ + layer->maxgeowidth = -1.0; + layer->mingeowidth = -1.0; + + layer->sizeunits = MS_PIXELS; + + layer->maxfeatures = -1; /* no quota */ + layer->startindex = -1; /*used for pagination*/ + + layer->scaletokens = NULL; + layer->numscaletokens = 0; + + layer->template = layer->header = layer->footer = NULL; + + layer->transform = MS_TRUE; + + layer->classitem = NULL; + layer->classitemindex = -1; + + layer->units = MS_METERS; + if (msInitProjection(&(layer->projection)) == -1) + return (-1); + + if (map) { + msProjectionInheritContextFrom(&(layer->projection), &(map->projection)); + } + + layer->project = MS_TRUE; + layer->reprojectorLayerToMap = NULL; + layer->reprojectorMapToLayer = NULL; + + initCluster(&layer->cluster); + + MS_INIT_COLOR(layer->offsite, -1, -1, -1, 255); + + layer->labelcache = MS_ON; + layer->postlabelcache = MS_FALSE; + + layer->labelitem = NULL; + layer->labelitemindex = -1; + + layer->labelmaxscaledenom = -1; + layer->labelminscaledenom = -1; + + layer->tileitem = msStrdup("location"); + layer->tileitemindex = -1; + layer->tileindex = NULL; + layer->tilesrs = NULL; + + layer->bandsitem = NULL; + layer->bandsitemindex = -1; + + layer->currentfeature = layer->features = NULL; + + layer->connection = NULL; + layer->plugin_library = NULL; + layer->plugin_library_original = NULL; + layer->connectiontype = MS_SHAPEFILE; + layer->vtable = NULL; + layer->classgroup = NULL; + + layer->layerinfo = NULL; + layer->wfslayerinfo = NULL; + + layer->items = NULL; + layer->iteminfo = NULL; + layer->numitems = 0; + + layer->resultcache = NULL; + + msInitExpression(&(layer->filter)); + layer->filteritem = NULL; + layer->filteritemindex = -1; + + layer-> + requires + = layer->labelrequires = NULL; + + initHashTable(&(layer->metadata)); + initHashTable(&(layer->bindvals)); + initHashTable(&(layer->validation)); + + layer->styleitem = NULL; + layer->styleitemindex = -1; + + layer->processing = NULL; + layer->numjoins = 0; + layer->joins = (joinObj *)malloc(MS_MAXJOINS * sizeof(joinObj)); + MS_CHECK_ALLOC(layer->joins, MS_MAXJOINS * sizeof(joinObj), -1); + + layer->extent.minx = -1.0; + layer->extent.miny = -1.0; + layer->extent.maxx = -1.0; + layer->extent.maxy = -1.0; + + layer->mask = NULL; + layer->maskimage = NULL; + layer->grid = NULL; + + msInitExpression(&(layer->_geomtransform)); + layer->_geomtransform.type = MS_GEOMTRANSFORM_NONE; + + msInitExpression(&(layer->utfdata)); + layer->utfitem = NULL; + layer->utfitemindex = -1; + + layer->encoding = NULL; + + layer->sortBy.nProperties = 0; + layer->sortBy.properties = NULL; + layer->orig_st = NULL; + + layer->compositer = NULL; + + initHashTable(&(layer->connectionoptions)); + + return (0); +} + +int initScaleToken(scaleTokenObj *token) { + token->n_entries = 0; + token->name = NULL; + token->tokens = NULL; + return MS_SUCCESS; +} + +int freeScaleTokenEntry(scaleTokenEntryObj *token) { + msFree(token->value); + return MS_SUCCESS; +} + +int freeScaleToken(scaleTokenObj *scaletoken) { + int i; + msFree(scaletoken->name); + for (i = 0; i < scaletoken->n_entries; i++) { + freeScaleTokenEntry(&scaletoken->tokens[i]); + } + msFree(scaletoken->tokens); + return MS_SUCCESS; +} + +int freeLayer(layerObj *layer) { + int i; + if (!layer) + return MS_FAILURE; + if (MS_REFCNT_DECR_IS_NOT_ZERO(layer)) { + return MS_FAILURE; + } + + if (layer->debug >= MS_DEBUGLEVEL_VVV) + msDebug("freeLayer(): freeing layer at %p.\n", layer); + + if (msLayerIsOpen(layer)) + msLayerClose(layer); + + msFree(layer->name); + msFree(layer->encoding); + msFree(layer->group); + msFree(layer->data); + msFree(layer->classitem); + msFree(layer->labelitem); + msFree(layer->header); + msFree(layer->footer); + msFree(layer->template); + msFree(layer->tileindex); + msFree(layer->tileitem); + msFree(layer->tilesrs); + msFree(layer->bandsitem); + msFree(layer->plugin_library); + msFree(layer->plugin_library_original); + msFree(layer->connection); + msFree(layer->vtable); + msFree(layer->classgroup); + + msProjectDestroyReprojector(layer->reprojectorLayerToMap); + msProjectDestroyReprojector(layer->reprojectorMapToLayer); + msFreeProjection(&(layer->projection)); + msFreeExpression(&layer->_geomtransform); + + freeCluster(&layer->cluster); + + for (i = 0; i < layer->maxclasses; i++) { + if (layer->class[i] != NULL) { + layer->class[i]->layer = NULL; + if (freeClass(layer->class[i]) == MS_SUCCESS) { + msFree(layer->class[i]); + } + } + } + msFree(layer->class); + + if (layer->numscaletokens > 0) { + for (i = 0; i < layer->numscaletokens; i++) { + freeScaleToken(&layer->scaletokens[i]); + } + msFree(layer->scaletokens); + } + + if (layer->features) + freeFeatureList(layer->features); + + if (layer->resultcache) { + cleanupResultCache(layer->resultcache); + msFree(layer->resultcache); + } + + msFree(layer->identificationclassgroup); + + msFree(layer->styleitem); + + msFree(layer->filteritem); + msFreeExpression(&(layer->filter)); + + msFree(layer->requires); + msFree(layer->labelrequires); + + msFreeHashItems(&(layer->metadata)); + msFreeHashItems(&(layer->validation)); + msFreeHashItems(&layer->bindvals); + + CSLDestroy(layer->processing); + + for (i = 0; i < layer->numjoins; i++) /* each join */ + freeJoin(&(layer->joins[i])); + msFree(layer->joins); + layer->numjoins = 0; + + layer->classgroup = NULL; + + msFree(layer->mask); + if (layer->maskimage) { + msFreeImage(layer->maskimage); + } + + if (layer->compositer) { + freeLayerCompositer(layer->compositer); + } + + if (layer->grid) { + freeGrid(layer->grid); + msFree(layer->grid); + } + + msFreeExpression(&(layer->utfdata)); + msFree(layer->utfitem); + + for (i = 0; i < layer->sortBy.nProperties; i++) + msFree(layer->sortBy.properties[i].item); + msFree(layer->sortBy.properties); + + msFreeHashItems(&layer->connectionoptions); + + return MS_SUCCESS; +} + +/* +** Ensure there is at least one free entry in the class array of this +** layerObj. Grow the allocated class array if necessary and allocate +** a new class for class[numclasses] if there is not already one, +** setting its contents to all zero bytes (i.e. does not call initClass() +** on it). +** +** This function is safe to use for the initial allocation of the class[] +** array as well (i.e. when maxclasses==0 and class==NULL) +** +** Returns a reference to the new classObj on success, NULL on error. +*/ +classObj *msGrowLayerClasses(layerObj *layer) { + /* Do we need to increase the size of class[] by MS_CLASS_ALLOCSIZE? + */ + if (layer->numclasses == layer->maxclasses) { + classObj **newClassPtr; + int i, newsize; + + newsize = layer->maxclasses + MS_CLASS_ALLOCSIZE; + + /* Alloc/realloc classes */ + newClassPtr = + (classObj **)realloc(layer->class, newsize * sizeof(classObj *)); + MS_CHECK_ALLOC(newClassPtr, newsize * sizeof(classObj *), NULL); + + layer->class = newClassPtr; + layer->maxclasses = newsize; + for (i = layer->numclasses; i < layer->maxclasses; i++) { + layer->class[i] = NULL; + } + } + + if (layer->class[layer->numclasses] == NULL) { + layer->class[layer->numclasses] = (classObj *)calloc(1, sizeof(classObj)); + MS_CHECK_ALLOC(layer->class[layer->numclasses], sizeof(classObj), NULL); + } + + return layer->class[layer->numclasses]; +} + +scaleTokenObj *msGrowLayerScaletokens(layerObj *layer) { + layer->scaletokens = msSmallRealloc( + layer->scaletokens, (layer->numscaletokens + 1) * sizeof(scaleTokenObj)); + memset(&layer->scaletokens[layer->numscaletokens], 0, sizeof(scaleTokenObj)); + return &layer->scaletokens[layer->numscaletokens]; +} + +int loadScaletoken(scaleTokenObj *token, layerObj *layer) { + (void)layer; + for (;;) { + int stop = 0; + switch (msyylex()) { + case (EOF): + msSetError(MS_EOFERR, NULL, "loadScaletoken()"); + return (MS_FAILURE); + case (NAME): + if (getString(&token->name) == MS_FAILURE) + return (MS_FAILURE); + break; + case (VALUES): + for (;;) { + if (stop) + break; + switch (msyylex()) { + case (EOF): + msSetError(MS_EOFERR, NULL, "loadScaletoken()"); + return (MS_FAILURE); + case (END): + stop = 1; + if (token->n_entries == 0) { + msSetError(MS_PARSEERR, + "Scaletoken (line:%d) has no VALUES defined", + "loadScaleToken()", msyylineno); + return (MS_FAILURE); + } + token->tokens[token->n_entries - 1].maxscale = DBL_MAX; + break; + case (MS_STRING): + /* we have a key */ + token->tokens = + msSmallRealloc(token->tokens, (token->n_entries + 1) * + sizeof(scaleTokenEntryObj)); + + if (1 != sscanf(msyystring_buffer, "%lf", + &token->tokens[token->n_entries].minscale)) { + msSetError(MS_PARSEERR, + "failed to parse SCALETOKEN VALUE (%s):(line %d), " + "expecting \"minscale\"", + "loadScaletoken()", msyystring_buffer, msyylineno); + return (MS_FAILURE); + } + if (token->n_entries == 0) { + /* check supplied value was 0*/ + if (token->tokens[0].minscale != 0) { + msSetError(MS_PARSEERR, + "First SCALETOKEN VALUE (%s):(line %d) must be zero, " + "expecting \"0\"", + "loadScaletoken()", msyystring_buffer, msyylineno); + return (MS_FAILURE); + } + } else { + /* set max scale of previous token */ + token->tokens[token->n_entries - 1].maxscale = + token->tokens[token->n_entries].minscale; + } + token->tokens[token->n_entries].value = NULL; + if (getString(&(token->tokens[token->n_entries].value)) == MS_FAILURE) + return (MS_FAILURE); + token->n_entries++; + break; + default: + msSetError(MS_IDENTERR, "Parsing error near (%s):(line %d)", + "loadScaletoken()", msyystring_buffer, msyylineno); + return (MS_FAILURE); + } + } + break; + case (END): + if (!token->name || !*(token->name)) { + msSetError(MS_PARSEERR, + "ScaleToken missing mandatory NAME entry (line %d)", + "loadScaleToken()", msyylineno); + return MS_FAILURE; + } + if (token->n_entries == 0) { + msSetError(MS_PARSEERR, + "ScaleToken missing at least one VALUES entry (line %d)", + "loadScaleToken()", msyylineno); + return MS_FAILURE; + } + return MS_SUCCESS; + default: + msSetError(MS_IDENTERR, "Parsing error 2 near (%s):(line %d)", + "loadScaletoken()", msyystring_buffer, msyylineno); + return (MS_FAILURE); + } + } /* next token*/ +} + +static const struct { + CompositingOperation eOp; + const char *pszName; +} CompOps[] = { + {MS_COMPOP_CLEAR, "clear"}, + {MS_COMPOP_COLOR_BURN, "color-burn"}, + {MS_COMPOP_COLOR_DODGE, "color-dodge"}, + {MS_COMPOP_CONTRAST, "contrast"}, + {MS_COMPOP_DARKEN, "darken"}, + {MS_COMPOP_DIFFERENCE, "difference"}, + {MS_COMPOP_DST, "dst"}, + {MS_COMPOP_DST_ATOP, "dst-atop"}, + {MS_COMPOP_DST_IN, "dst-in"}, + {MS_COMPOP_DST_OUT, "dst-out"}, + {MS_COMPOP_DST_OVER, "dst-over"}, + {MS_COMPOP_EXCLUSION, "exclusion"}, + {MS_COMPOP_HARD_LIGHT, "hard-light"}, + {MS_COMPOP_HSL_COLOR, "hsl-color"}, + {MS_COMPOP_HSL_HUE, "hsl-hue"}, + {MS_COMPOP_HSL_LUMINOSITY, "hsl-luminosity"}, + {MS_COMPOP_HSL_SATURATION, "hsl-saturation"}, + {MS_COMPOP_INVERT, "invert"}, + {MS_COMPOP_INVERT_RGB, "invert-rgb"}, + {MS_COMPOP_LIGHTEN, "lighten"}, + {MS_COMPOP_MINUS, "minus"}, + {MS_COMPOP_MULTIPLY, "multiply"}, + {MS_COMPOP_OVERLAY, "overlay"}, + {MS_COMPOP_PLUS, "plus"}, + {MS_COMPOP_SCREEN, "screen"}, + {MS_COMPOP_SOFT_LIGHT, "soft-light"}, + {MS_COMPOP_SRC, "src"}, + {MS_COMPOP_SRC_ATOP, "src-atop"}, + {MS_COMPOP_SRC_IN, "src-in"}, + {MS_COMPOP_SRC_OUT, "src-out"}, + {MS_COMPOP_SRC_OVER, "src-over"}, + {MS_COMPOP_XOR, "xor"}, +}; + +#define SIZEOF_COMP_OPS ((int)(sizeof(CompOps) / sizeof(CompOps[0]))) + +int loadLayerCompositer(LayerCompositer *compositer) { + for (;;) { + switch (msyylex()) { + case COMPFILTER: { + CompositingFilter **filter = &compositer->filter; + while (*filter) { + filter = &((*filter)->next); + } + *filter = msSmallMalloc(sizeof(CompositingFilter)); + initCompositingFilter(*filter); + if (getString(&((*filter)->filter)) == MS_FAILURE) + return (MS_FAILURE); + } break; + case COMPOP: { + char *compop = NULL; + if (getString(&compop) == MS_FAILURE) + return (MS_FAILURE); + + bool bFound = false; + for (int i = 0; i < SIZEOF_COMP_OPS; ++i) { + if (strcmp(compop, CompOps[i].pszName) == 0) { + bFound = true; + compositer->comp_op = CompOps[i].eOp; + break; + } + } + if (!bFound) { + msSetError(MS_PARSEERR, "Unknown COMPOP \"%s\"", + "loadLayerCompositer()", compop); + free(compop); + return MS_FAILURE; + } + free(compop); + } break; + case END: + return MS_SUCCESS; + case OPACITY: + if (getInteger(&(compositer->opacity), MS_NUM_CHECK_RANGE, 0, 100) == + -1) { + msSetError(MS_PARSEERR, "OPACITY must be between 0 and 100 (line %d)", + "loadLayerCompositer()", msyylineno); + return MS_FAILURE; + } + break; + default: + msSetError(MS_IDENTERR, "Parsing error 2 near (%s):(line %d)", + "loadLayerCompositer()", msyystring_buffer, msyylineno); + return (MS_FAILURE); + } + } +} + +static int loadIdentification(layerObj *layer) { + for (;;) { + switch (msyylex()) { + case TOLERANCE: + if (getDouble(&(layer->tolerance), MS_NUM_CHECK_GTE, 0, -1) == -1) + return (-1); + break; + + case TOLERANCEUNITS: + if ((layer->toleranceunits = getSymbol( + 8, MS_INCHES, MS_FEET, MS_MILES, MS_METERS, MS_KILOMETERS, + MS_NAUTICALMILES, MS_DD, MS_PIXELS)) == -1) + return (-1); + break; + + case CLASSGROUP: + if (getString(&layer->identificationclassgroup) == MS_FAILURE) + return (-1); + break; + + case CLASSAUTO: + layer->identificationclassauto = MS_TRUE; + break; + + case END: + return MS_SUCCESS; + + default: + msSetError(MS_IDENTERR, "Parsing error 2 near (%s):(line %d)", + "loadIdentification()", msyystring_buffer, msyylineno); + return (MS_FAILURE); + } + } +} + +int loadLayer(layerObj *layer, mapObj *map) { + int type; + + layer->map = (mapObj *)map; + + for (;;) { + switch (msyylex()) { + case (BINDVALS): + if (loadHashTable(&(layer->bindvals)) != MS_SUCCESS) + return (-1); + break; + case (CLASS): + if (msGrowLayerClasses(layer) == NULL) + return (-1); + initClass(layer->class[layer->numclasses]); + if (loadClass(layer->class[layer->numclasses], layer) == -1) { + freeClass(layer->class[layer->numclasses]); + free(layer->class[layer->numclasses]); + layer->class[layer->numclasses] = NULL; + return (-1); + } + layer->numclasses++; + break; + case (CLUSTER): + if (loadCluster(&layer->cluster) == -1) + return (-1); + break; + case (CLASSGROUP): + if (getString(&layer->classgroup) == MS_FAILURE) + return (-1); /* getString() cleans up previously allocated string */ + break; + case (CLASSITEM): + if (getString(&layer->classitem) == MS_FAILURE) + return (-1); /* getString() cleans up previously allocated string */ + break; + case (COMPOSITE): { + LayerCompositer *compositer = msSmallMalloc(sizeof(LayerCompositer)); + initLayerCompositer(compositer); + if (MS_FAILURE == loadLayerCompositer(compositer)) { + freeLayerCompositer(compositer); + return -1; + } + if (!layer->compositer) { + layer->compositer = compositer; + } else { + LayerCompositer *lctmp = layer->compositer; + while (lctmp->next) + lctmp = lctmp->next; + lctmp->next = compositer; + } + break; + } + case (CONNECTION): + if (getString(&layer->connection) == MS_FAILURE) + return (-1); /* getString() cleans up previously allocated string */ + break; + case (CONNECTIONTYPE): + if ((type = getSymbol(14, MS_OGR, MS_POSTGIS, MS_WMS, MS_ORACLESPATIAL, + MS_WFS, MS_GRATICULE, MS_PLUGIN, MS_UNION, + MS_UVRASTER, MS_CONTOUR, MS_KERNELDENSITY, MS_IDW, + MS_FLATGEOBUF, MS_RASTER_LABEL)) == -1) + return (-1); + layer->connectiontype = type; + break; + case (DATA): + if (getString(&layer->data) == MS_FAILURE) + return (-1); /* getString() cleans up previously allocated string */ + break; + case (DEBUG): + if ((layer->debug = getSymbol(3, MS_ON, MS_OFF, MS_NUMBER)) == -1) + return (-1); + if (layer->debug == MS_NUMBER) { + if (msCheckNumber(msyynumber, MS_NUM_CHECK_RANGE, 0, 5) == MS_FAILURE) { + msSetError(MS_MISCERR, + "Invalid DEBUG level, must be between 0 and 5 (line %d)", + "loadLayer()", msyylineno); + return (-1); + } + layer->debug = (int)msyynumber; + } + break; + case (EOF): + msSetError(MS_EOFERR, NULL, "loadLayer()"); + return (-1); + break; + case (ENCODING): + if (getString(&layer->encoding) == MS_FAILURE) + return (-1); + break; + case (END): + if ((int)layer->type == -1) { + msSetError(MS_MISCERR, "Layer type not set.", "loadLayer()"); + return (-1); + } + + return (0); + break; + case (EXTENT): { + if (getDouble(&(layer->extent.minx), MS_NUM_CHECK_NONE, -1, -1) == -1) + return (-1); + if (getDouble(&(layer->extent.miny), MS_NUM_CHECK_NONE, -1, -1) == -1) + return (-1); + if (getDouble(&(layer->extent.maxx), MS_NUM_CHECK_NONE, -1, -1) == -1) + return (-1); + if (getDouble(&(layer->extent.maxy), MS_NUM_CHECK_NONE, -1, -1) == -1) + return (-1); + if (!MS_VALID_EXTENT(layer->extent)) { + msSetError(MS_MISCERR, + "Given layer extent is invalid. Check that it is in the " + "form: minx, miny, maxx, maxy", + "loadLayer()"); + return (-1); + } + break; + } + case (FEATURE): + if ((int)layer->type == -1) { + msSetError(MS_MISCERR, + "Layer type must be set before defining inline features.", + "loadLayer()"); + return (-1); + } + + if (layer->type == MS_LAYER_POLYGON) + type = MS_SHAPE_POLYGON; + else if (layer->type == MS_LAYER_LINE) + type = MS_SHAPE_LINE; + else + type = MS_SHAPE_POINT; + + layer->connectiontype = MS_INLINE; + + if (loadFeature(layer, type) == MS_FAILURE) + return (-1); + break; + case (FILTER): + if (loadExpression(&(layer->filter)) == -1) + return (-1); /* loadExpression() cleans up previously allocated + expression */ + break; + case (FILTERITEM): + if (getString(&layer->filteritem) == MS_FAILURE) + return (-1); /* getString() cleans up previously allocated string */ + break; + case (FOOTER): + if (getString(&layer->footer) == MS_FAILURE) + return (-1); /* getString() cleans up previously allocated string */ + break; + case (GRID): + layer->connectiontype = MS_GRATICULE; + if (layer->grid) { + freeGrid(layer->grid); + msFree(layer->grid); + } + layer->grid = (void *)malloc(sizeof(graticuleObj)); + MS_CHECK_ALLOC(layer->grid, sizeof(graticuleObj), -1); + + initGrid(layer->grid); + loadGrid(layer); + break; + case (GROUP): + if (getString(&layer->group) == MS_FAILURE) + return (-1); /* getString() cleans up previously allocated string */ + break; + case (GEOMTRANSFORM): { + if (getSymbol(1, MS_EXPRESSION) == -1) + return (MS_FAILURE); + /* handle expression case here for the moment */ + msFree(layer->_geomtransform.string); + layer->_geomtransform.string = msStrdup(msyystring_buffer); + layer->_geomtransform.type = MS_GEOMTRANSFORM_EXPRESSION; + } break; + case (HEADER): + if (getString(&layer->header) == MS_FAILURE) + return (-1); /* getString() cleans up previously allocated string */ + break; + case (JOIN): + if (layer->numjoins == MS_MAXJOINS) { /* no room */ + msSetError(MS_IDENTERR, "Maximum number of joins reached.", + "loadLayer()"); + return (-1); + } + + if (loadJoin(&(layer->joins[layer->numjoins])) == -1) { + freeJoin(&(layer->joins[layer->numjoins])); + return (-1); + } + layer->numjoins++; + break; + case (LABELCACHE): + if ((layer->labelcache = getSymbol(2, MS_ON, MS_OFF)) == -1) + return (-1); + break; + case (LABELITEM): + if (getString(&layer->labelitem) == MS_FAILURE) + return (-1); /* getString() cleans up previously allocated string */ + break; + case (LABELMAXSCALE): + case (LABELMAXSCALEDENOM): + if (getDouble(&(layer->labelmaxscaledenom), MS_NUM_CHECK_GTE, 0, -1) == + -1) + return (-1); + break; + case (LABELMINSCALE): + case (LABELMINSCALEDENOM): + if (getDouble(&(layer->labelminscaledenom), MS_NUM_CHECK_GTE, 0, -1) == + -1) + return (-1); + break; + case (LABELREQUIRES): + if (getString(&layer->labelrequires) == MS_FAILURE) + return (-1); /* getString() cleans up previously allocated string */ + break; + case (LAYER): + break; /* for string loads */ + case (MASK): + if (getString(&layer->mask) == MS_FAILURE) + return (-1); /* getString() cleans up previously allocated string */ + break; + case (MAXFEATURES): + if (getInteger(&(layer->maxfeatures), MS_NUM_CHECK_GT, 0, -1) == -1) + return (-1); + break; + case (MAXSCALE): + case (MAXSCALEDENOM): + if (getDouble(&(layer->maxscaledenom), MS_NUM_CHECK_GTE, 0, -1) == -1) + return (-1); + break; + case (MAXGEOWIDTH): + if (getDouble(&(layer->maxgeowidth), MS_NUM_CHECK_GT, 0, -1) == -1) + return (-1); + break; + case (METADATA): + if (loadHashTable(&(layer->metadata)) != MS_SUCCESS) + return (-1); + break; + case (MINSCALE): + case (MINSCALEDENOM): + if (getDouble(&(layer->minscaledenom), MS_NUM_CHECK_GTE, 0, -1) == -1) + return (-1); + break; + case (MINGEOWIDTH): + if (getDouble(&(layer->mingeowidth), MS_NUM_CHECK_GT, 0, -1) == -1) + return (-1); + break; + case (MINFEATURESIZE): + if (getInteger(&(layer->minfeaturesize), MS_NUM_CHECK_GT, 0, -1) == -1) + return (-1); + break; + case (NAME): + if (getString(&layer->name) == MS_FAILURE) + return (-1); + break; + case (OFFSITE): + if (loadColor(&(layer->offsite), NULL) != MS_SUCCESS) + return (-1); + break; + + case (CONNECTIONOPTIONS): + if (loadHashTable(&(layer->connectionoptions)) != MS_SUCCESS) + return (-1); + break; + case (MS_PLUGIN): { + int rv; + if (map->config) { // value *must* represent a config key + char *value = NULL; + const char *plugin_library = NULL; + + if (getString(&value) == MS_FAILURE) + return (-1); + plugin_library = msConfigGetPlugin(map->config, value); + msFree(value); + if (!plugin_library) { + msSetError(MS_MISCERR, + "Plugin value not found in config file. See " + "mapserver.org/mapfile/config.html for more information.", + "loadLayer()"); + return (-1); + } + msFree(layer->plugin_library_original); + layer->plugin_library_original = strdup(plugin_library); + } else { + if (getString(&layer->plugin_library_original) == MS_FAILURE) + return (-1); + } + rv = msBuildPluginLibraryPath(&layer->plugin_library, + layer->plugin_library_original, map); + if (rv == MS_FAILURE) + return (-1); + } break; + case (PROCESSING): { + /* NOTE: processing array maintained as size+1 with NULL terminator. + This ensure that CSL (GDAL string list) functions can be + used on the list for easy processing. */ + char *value = NULL; + if (getString(&value) == MS_FAILURE) + return (-1); + msLayerAddProcessing(layer, value); + free(value); + value = NULL; + } break; + case (POSTLABELCACHE): + if ((layer->postlabelcache = getSymbol(2, MS_TRUE, MS_FALSE)) == -1) + return (-1); + if (layer->postlabelcache) + layer->labelcache = MS_OFF; + break; + case (PROJECTION): + if (loadProjection(&(layer->projection), map) == -1) + return (-1); + layer->project = MS_TRUE; + break; + case (REQUIRES): + if (getString(&layer->requires) == MS_FAILURE) + return (-1); /* getString() cleans up previously allocated string */ + break; + case (SCALETOKEN): + if (msGrowLayerScaletokens(layer) == NULL) + return (-1); + initScaleToken(&layer->scaletokens[layer->numscaletokens]); + if (loadScaletoken(&layer->scaletokens[layer->numscaletokens], layer) == + -1) { + freeScaleToken(&layer->scaletokens[layer->numscaletokens]); + return (-1); + } + layer->numscaletokens++; + break; + case (SIZEUNITS): + if ((layer->sizeunits = getSymbol( + 8, MS_INCHES, MS_FEET, MS_MILES, MS_METERS, MS_KILOMETERS, + MS_NAUTICALMILES, MS_DD, MS_PIXELS)) == -1) + return (-1); + break; + case (STATUS): + if ((layer->status = getSymbol(3, MS_ON, MS_OFF, MS_DEFAULT)) == -1) + return (-1); + break; + case (STYLEITEM): + if (getString(&layer->styleitem) == MS_FAILURE) + return (-1); /* getString() cleans up previously allocated string */ + break; + case (SYMBOLSCALE): + case (SYMBOLSCALEDENOM): + if (getDouble(&(layer->symbolscaledenom), MS_NUM_CHECK_GTE, 1, -1) == -1) + return (-1); + break; + case (TEMPLATE): + if (getString(&layer->template) == MS_FAILURE) + return (-1); /* getString() cleans up previously allocated string */ + break; + case (TILEINDEX): + if (getString(&layer->tileindex) == MS_FAILURE) + return (-1); /* getString() cleans up previously allocated string */ + break; + case (TILEITEM): + if (getString(&layer->tileitem) == MS_FAILURE) + return (-1); /* getString() cleans up previously allocated string */ + break; + case (TILESRS): + if (getString(&layer->tilesrs) == MS_FAILURE) + return (-1); /* getString() cleans up previously allocated string */ + break; + case (IDENTIFY): + if (loadIdentification(layer) == MS_FAILURE) + return (-1); + break; + case (TOLERANCE): + if (getDouble(&(layer->tolerance), MS_NUM_CHECK_GTE, 0, -1) == -1) + return (-1); + break; + case (TOLERANCEUNITS): + if ((layer->toleranceunits = getSymbol( + 8, MS_INCHES, MS_FEET, MS_MILES, MS_METERS, MS_KILOMETERS, + MS_NAUTICALMILES, MS_DD, MS_PIXELS)) == -1) + return (-1); + break; + case (TRANSFORM): + if ((layer->transform = + getSymbol(11, MS_TRUE, MS_FALSE, MS_UL, MS_UC, MS_UR, MS_CL, + MS_CC, MS_CR, MS_LL, MS_LC, MS_LR)) == -1) + return (-1); + break; + case (TYPE): + if ((type = + getSymbol(9, MS_LAYER_POINT, MS_LAYER_LINE, MS_LAYER_RASTER, + MS_LAYER_POLYGON, MS_LAYER_ANNOTATION, MS_LAYER_QUERY, + MS_LAYER_CIRCLE, MS_LAYER_CHART, TILEINDEX)) == -1) + return (-1); + if (type == TILEINDEX) + type = MS_LAYER_TILEINDEX; /* TILEINDEX is also a parameter */ + if (type == MS_LAYER_ANNOTATION) { + msSetError(MS_IDENTERR, + "Annotation Layers have been removed. To obtain same " + "functionality, use a layer with label->styles and no " + "class->styles", + "loadLayer()"); + return -1; + } + layer->type = type; + break; + case (UNITS): + if ((layer->units = getSymbol(9, MS_INCHES, MS_FEET, MS_MILES, MS_METERS, + MS_KILOMETERS, MS_NAUTICALMILES, MS_DD, + MS_PIXELS, MS_PERCENTAGES)) == -1) + return (-1); + break; + case (UTFDATA): + if (loadExpression(&(layer->utfdata)) == -1) + return (-1); /* loadExpression() cleans up previously allocated + expression */ + break; + case (UTFITEM): + if (getString(&layer->utfitem) == MS_FAILURE) + return (-1); + break; + case (VALIDATION): + if (loadHashTable(&(layer->validation)) != MS_SUCCESS) + return (-1); + break; + default: + if (strlen(msyystring_buffer) > 0) { + msSetError(MS_IDENTERR, "Parsing error near (%s):(line %d)", + "loadLayer()", msyystring_buffer, msyylineno); + return (-1); + } else { + return (0); /* end of a string, not an error */ + } + } + } /* next token */ +} + +int msUpdateLayerFromString(layerObj *layer, char *string) { + int i; + + if (!layer || !string) + return MS_FAILURE; + + msAcquireLock(TLOCK_PARSER); + + msyystate = MS_TOKENIZE_STRING; + msyystring = string; + msyylex(); /* sets things up, but doesn't process any tokens */ + + msyylineno = 1; /* start at line 1 */ + + if (loadLayer(layer, layer->map) == -1) { + msReleaseLock(TLOCK_PARSER); + return MS_FAILURE; /* parse error */ + ; + } + + msyylex_destroy(); + msReleaseLock(TLOCK_PARSER); + + /* step through classes to resolve symbol names */ + for (i = 0; i < layer->numclasses; i++) { + if (classResolveSymbolNames(layer->class[i]) != MS_SUCCESS) + return MS_FAILURE; + } + + return MS_SUCCESS; +} + +static void writeCompositingFilter(FILE *stream, int indent, + CompositingFilter *filter) { + while (filter) { + writeString(stream, indent, "COMPFILTER", "", filter->filter); + filter = filter->next; + } +} + +static void writeLayerCompositer(FILE *stream, int indent, + LayerCompositer *compositor) { + indent++; + while (compositor) { + writeBlockBegin(stream, indent, "COMPOSITE"); + writeCompositingFilter(stream, indent, compositor->filter); + if (compositor->comp_op != MS_COMPOP_SRC_OVER) { + + bool bFound = false; + for (int i = 0; i < SIZEOF_COMP_OPS; ++i) { + if (compositor->comp_op == CompOps[i].eOp) { + bFound = true; + writeString(stream, indent, "COMPOP", NULL, CompOps[i].pszName); + break; + } + } + if (!bFound) { + assert(0); + } + } + writeNumber(stream, indent, "OPACITY", 100, compositor->opacity); + writeBlockEnd(stream, indent, "COMPOSITE"); + compositor = compositor->next; + } +} +static void writeLayer(FILE *stream, int indent, layerObj *layer) { + int i; + featureListNodeObjPtr current = NULL; + + if (layer->status == MS_DELETE) + return; + + indent++; + writeBlockBegin(stream, indent, "LAYER"); + writeHashTable(stream, indent, "BINDVALS", &(layer->bindvals)); + /* class - see below */ + writeString(stream, indent, "CLASSGROUP", NULL, layer->classgroup); + writeString(stream, indent, "CLASSITEM", NULL, layer->classitem); + writeCluster(stream, indent, &(layer->cluster)); + writeLayerCompositer(stream, indent, layer->compositer); + writeString(stream, indent, "CONNECTION", NULL, layer->connection); + writeKeyword(stream, indent, "CONNECTIONTYPE", layer->connectiontype, 12, + MS_OGR, "OGR", MS_POSTGIS, "POSTGIS", MS_WMS, "WMS", + MS_ORACLESPATIAL, "ORACLESPATIAL", MS_WFS, "WFS", MS_PLUGIN, + "PLUGIN", MS_UNION, "UNION", MS_UVRASTER, "UVRASTER", MS_CONTOUR, + "CONTOUR", MS_KERNELDENSITY, "KERNELDENSITY", MS_IDW, "IDW", + MS_FLATGEOBUF, "FLATGEOBUF"); + writeHashTable(stream, indent, "CONNECTIONOPTIONS", + &(layer->connectionoptions)); + writeString(stream, indent, "DATA", NULL, layer->data); + writeNumber(stream, indent, "DEBUG", 0, + layer->debug); /* is this right? see loadLayer() */ + writeString(stream, indent, "ENCODING", NULL, layer->encoding); + writeExtent(stream, indent, "EXTENT", layer->extent); + writeExpression(stream, indent, "FILTER", &(layer->filter)); + writeString(stream, indent, "FILTERITEM", NULL, layer->filteritem); + writeString(stream, indent, "FOOTER", NULL, layer->footer); + writeString(stream, indent, "GROUP", NULL, layer->group); + + if (layer->_geomtransform.type == MS_GEOMTRANSFORM_EXPRESSION) { + writeIndent(stream, indent + 1); + fprintf(stream, "GEOMTRANSFORM (%s)\n", layer->_geomtransform.string); + } + + writeString(stream, indent, "HEADER", NULL, layer->header); + /* join - see below */ + writeKeyword(stream, indent, "LABELCACHE", layer->labelcache, 1, MS_OFF, + "OFF"); + writeString(stream, indent, "LABELITEM", NULL, layer->labelitem); + writeNumber(stream, indent, "LABELMAXSCALEDENOM", -1, + layer->labelmaxscaledenom); + writeNumber(stream, indent, "LABELMINSCALEDENOM", -1, + layer->labelminscaledenom); + writeString(stream, indent, "LABELREQUIRES", NULL, layer->labelrequires); + writeNumber(stream, indent, "MAXFEATURES", -1, layer->maxfeatures); + writeNumber(stream, indent, "MAXGEOWIDTH", -1, layer->maxgeowidth); + writeNumber(stream, indent, "MAXSCALEDENOM", -1, layer->maxscaledenom); + writeString(stream, indent, "MASK", NULL, layer->mask); + writeHashTable(stream, indent, "METADATA", &(layer->metadata)); + writeNumber(stream, indent, "MINGEOWIDTH", -1, layer->mingeowidth); + writeNumber(stream, indent, "MINSCALEDENOM", -1, layer->minscaledenom); + writeNumber(stream, indent, "MINFEATURESIZE", -1, layer->minfeaturesize); + writeString(stream, indent, "NAME", NULL, layer->name); + writeColor(stream, indent, "OFFSITE", NULL, &(layer->offsite)); + writeString(stream, indent, "PLUGIN", NULL, layer->plugin_library_original); + writeKeyword(stream, indent, "POSTLABELCACHE", layer->postlabelcache, 1, + MS_TRUE, "TRUE"); + for (i = 0; layer->processing && layer->processing[i]; i++) + writeString(stream, indent, "PROCESSING", NULL, layer->processing[i]); + writeKeyword(stream, indent, "PROCESSING", layer->rendermode, 1, + MS_ALL_MATCHING_CLASSES, "\"RENDERMODE=ALL_MATCHING_CLASSES\""); + writeProjection(stream, indent, &(layer->projection)); + writeString(stream, indent, "REQUIRES", NULL, layer->requires); + writeKeyword(stream, indent, "SIZEUNITS", layer->sizeunits, 7, MS_INCHES, + "INCHES", MS_FEET, "FEET", MS_MILES, "MILES", MS_METERS, + "METERS", MS_KILOMETERS, "KILOMETERS", MS_NAUTICALMILES, + "NAUTICALMILES", MS_DD, "DD"); + writeKeyword(stream, indent, "STATUS", layer->status, 3, MS_ON, "ON", MS_OFF, + "OFF", MS_DEFAULT, "DEFAULT"); + writeString(stream, indent, "STYLEITEM", NULL, layer->styleitem); + writeNumber(stream, indent, "SYMBOLSCALEDENOM", -1, layer->symbolscaledenom); + writeString(stream, indent, "TEMPLATE", NULL, layer->template); + writeString(stream, indent, "TILEINDEX", NULL, layer->tileindex); + writeString(stream, indent, "TILEITEM", NULL, layer->tileitem); + writeString(stream, indent, "TILESRS", NULL, layer->tilesrs); + writeNumber(stream, indent, "TOLERANCE", -1, layer->tolerance); + writeKeyword(stream, indent, "TOLERANCEUNITS", layer->toleranceunits, 7, + MS_INCHES, "INCHES", MS_FEET, "FEET", MS_MILES, "MILES", + MS_METERS, "METERS", MS_KILOMETERS, "KILOMETERS", + MS_NAUTICALMILES, "NAUTICALMILES", MS_DD, "DD"); + writeIdentify(stream, indent, layer); + writeKeyword(stream, indent, "TRANSFORM", layer->transform, 10, MS_FALSE, + "FALSE", MS_UL, "UL", MS_UC, "UC", MS_UR, "UR", MS_CL, "CL", + MS_CC, "CC", MS_CR, "CR", MS_LL, "LL", MS_LC, "LC", MS_LR, "LR"); + writeKeyword(stream, indent, "TYPE", layer->type, 9, MS_LAYER_POINT, "POINT", + MS_LAYER_LINE, "LINE", MS_LAYER_POLYGON, "POLYGON", + MS_LAYER_RASTER, "RASTER", MS_LAYER_ANNOTATION, "ANNOTATION", + MS_LAYER_QUERY, "QUERY", MS_LAYER_CIRCLE, "CIRCLE", + MS_LAYER_TILEINDEX, "TILEINDEX", MS_LAYER_CHART, "CHART"); + writeKeyword(stream, indent, "UNITS", layer->units, 9, MS_INCHES, "INCHES", + MS_FEET, "FEET", MS_MILES, "MILES", MS_METERS, "METERS", + MS_KILOMETERS, "KILOMETERS", MS_NAUTICALMILES, "NAUTICALMILES", + MS_DD, "DD", MS_PIXELS, "PIXELS", MS_PERCENTAGES, + "PERCENTATGES"); + writeExpression(stream, indent, "UTFDATA", &(layer->utfdata)); + writeString(stream, indent, "UTFITEM", NULL, layer->utfitem); + writeHashTable(stream, indent, "VALIDATION", &(layer->validation)); + + /* write potentially multiply occurring objects last */ + for (i = 0; i < layer->numscaletokens; i++) + writeScaleToken(stream, indent, &(layer->scaletokens[i])); + for (i = 0; i < layer->numjoins; i++) + writeJoin(stream, indent, &(layer->joins[i])); + for (i = 0; i < layer->numclasses; i++) + writeClass(stream, indent, layer->class[i]); + + if (layer->grid && layer->connectiontype == MS_GRATICULE) + writeGrid(stream, indent, layer->grid); + else { + current = layer->features; + while (current != NULL) { + writeFeature(stream, indent, &(current->shape)); + current = current->next; + } + } + + writeBlockEnd(stream, indent, "LAYER"); + writeLineFeed(stream); +} + +char *msWriteLayerToString(layerObj *layer) { + msIOContext context; + msIOBuffer buffer; + + context.label = NULL; + context.write_channel = MS_TRUE; + context.readWriteFunc = msIO_bufferWrite; + context.cbData = &buffer; + buffer.data = NULL; + buffer.data_len = 0; + buffer.data_offset = 0; + + msIO_installHandlers(NULL, &context, NULL); + + writeLayer(stdout, -1, layer); + msIO_bufferWrite(&buffer, "", 1); + + msIO_installHandlers(NULL, NULL, NULL); + + return (char *)buffer.data; +} + +/* +** Initialize, load and free a referenceMapObj structure +*/ +void initReferenceMap(referenceMapObj *ref) { + ref->height = ref->width = 0; + ref->extent.minx = ref->extent.miny = ref->extent.maxx = ref->extent.maxy = + -1.0; + ref->image = NULL; + MS_INIT_COLOR(ref->color, 255, 0, 0, 255); + MS_INIT_COLOR(ref->outlinecolor, 0, 0, 0, 255); + ref->status = MS_OFF; + ref->marker = 0; + ref->markername = NULL; + ref->markersize = 0; + ref->minboxsize = 3; + ref->maxboxsize = 0; + ref->map = NULL; +} + +void freeReferenceMap(referenceMapObj *ref) { + msFree(ref->image); + msFree(ref->markername); +} + +int loadReferenceMap(referenceMapObj *ref, mapObj *map) { + int state; + + ref->map = (mapObj *)map; + + for (;;) { + switch (msyylex()) { + case (EOF): + msSetError(MS_EOFERR, NULL, "loadReferenceMap()"); + return (-1); + case (END): + if (!ref->image) { + msSetError(MS_MISCERR, "No image defined for the reference map.", + "loadReferenceMap()"); + return (-1); + } + if (ref->width == 0 || ref->height == 0) { + msSetError(MS_MISCERR, "No image size defined for the reference map.", + "loadReferenceMap()"); + return (-1); + } + return (0); + break; + case (COLOR): + if (loadColor(&(ref->color), NULL) != MS_SUCCESS) + return (-1); + break; + case (EXTENT): + if (getDouble(&(ref->extent.minx), MS_NUM_CHECK_NONE, -1, -1) == -1) + return (-1); + if (getDouble(&(ref->extent.miny), MS_NUM_CHECK_NONE, -1, -1) == -1) + return (-1); + if (getDouble(&(ref->extent.maxx), MS_NUM_CHECK_NONE, -1, -1) == -1) + return (-1); + if (getDouble(&(ref->extent.maxy), MS_NUM_CHECK_NONE, -1, -1) == -1) + return (-1); + if (!MS_VALID_EXTENT(ref->extent)) { + msSetError(MS_MISCERR, + "Given reference extent is invalid. Check that it " + "is in the form: minx, miny, maxx, maxy", + "loadReferenceMap()"); + return (-1); + } + break; + case (IMAGE): + if (getString(&ref->image) == MS_FAILURE) + return (-1); + break; + case (OUTLINECOLOR): + if (loadColor(&(ref->outlinecolor), NULL) != MS_SUCCESS) + return (-1); + break; + case (SIZE): + if (getInteger(&(ref->width), MS_NUM_CHECK_RANGE, 5, ref->map->maxsize) == + -1) + return (-1); // is 5 reasonable? + if (getInteger(&(ref->height), MS_NUM_CHECK_RANGE, 5, + ref->map->maxsize) == -1) + return (-1); + break; + case (STATUS): + if ((ref->status = getSymbol(2, MS_ON, MS_OFF)) == -1) + return (-1); + break; + case (MARKER): + if ((state = getSymbol(2, MS_NUMBER, MS_STRING)) == -1) + return (-1); + + if (state == MS_NUMBER) { + if (msCheckNumber(msyynumber, MS_NUM_CHECK_GTE, 0, -1) == MS_FAILURE) { + msSetError(MS_MISCERR, + "Invalid MARKER, must be greater than 0 (line %d)", + "loadReferenceMap()", msyylineno); + return (-1); + } + ref->marker = (int)msyynumber; + } else { + if (ref->markername != NULL) + msFree(ref->markername); + ref->markername = msStrdup(msyystring_buffer); + } + break; + case (MARKERSIZE): + if (getInteger(&(ref->markersize), MS_NUM_CHECK_GT, 0, -1) == -1) + return (-1); + break; + case (MINBOXSIZE): + if (getInteger(&(ref->minboxsize), MS_NUM_CHECK_GT, 0, -1) == -1) + return (-1); + break; + case (MAXBOXSIZE): + if (getInteger(&(ref->maxboxsize), MS_NUM_CHECK_GT, 0, -1) == -1) + return (-1); + break; + case (REFERENCE): + break; /* for string loads */ + default: + if (strlen(msyystring_buffer) > 0) { + msSetError(MS_IDENTERR, "Parsing error near (%s):(line %d)", + "loadReferenceMap()", msyystring_buffer, msyylineno); + return (-1); + } else { + return (0); /* end of a string, not an error */ + } + } + } /* next token */ +} + +int msUpdateReferenceMapFromString(referenceMapObj *ref, char *string) { + if (!ref || !string) + return MS_FAILURE; + + msAcquireLock(TLOCK_PARSER); + + msyystate = MS_TOKENIZE_STRING; + msyystring = string; + msyylex(); /* sets things up, but doesn't process any tokens */ + + msyylineno = 1; /* start at line 1 */ + + if (loadReferenceMap(ref, ref->map) == -1) { + msReleaseLock(TLOCK_PARSER); + return MS_FAILURE; /* parse error */ + ; + } + + msyylex_destroy(); + msReleaseLock(TLOCK_PARSER); + return MS_SUCCESS; +} + +static void writeReferenceMap(FILE *stream, int indent, referenceMapObj *ref) { + colorObj c; + + if (!ref->image) + return; + + indent++; + writeBlockBegin(stream, indent, "REFERENCE"); + MS_INIT_COLOR(c, 255, 0, 0, 255); + writeColor(stream, indent, "COLOR", &c, &(ref->color)); + writeExtent(stream, indent, "EXTENT", ref->extent); + writeString(stream, indent, "IMAGE", NULL, ref->image); + MS_INIT_COLOR(c, 0, 0, 0, 255); + writeColor(stream, indent, "OUTLINECOLOR", &c, &(ref->outlinecolor)); + writeDimension(stream, indent, "SIZE", ref->width, ref->height, NULL, NULL); + writeKeyword(stream, indent, "STATUS", ref->status, 2, MS_ON, "ON", MS_OFF, + "OFF"); + writeNumberOrString(stream, indent, "MARKER", 0, ref->marker, + ref->markername); + writeNumber(stream, indent, "MARKERSIZE", -1, ref->markersize); + writeNumber(stream, indent, "MAXBOXSIZE", -1, ref->maxboxsize); + writeNumber(stream, indent, "MINBOXSIZE", -1, ref->minboxsize); + writeBlockEnd(stream, indent, "REFERENCE"); + writeLineFeed(stream); +} + +char *msWriteReferenceMapToString(referenceMapObj *ref) { + msIOContext context; + msIOBuffer buffer; + + context.label = NULL; + context.write_channel = MS_TRUE; + context.readWriteFunc = msIO_bufferWrite; + context.cbData = &buffer; + buffer.data = NULL; + buffer.data_len = 0; + buffer.data_offset = 0; + + msIO_installHandlers(NULL, &context, NULL); + + writeReferenceMap(stdout, -1, ref); + msIO_bufferWrite(&buffer, "", 1); + + msIO_installHandlers(NULL, NULL, NULL); + + return (char *)buffer.data; +} + +#define MAX_FORMATOPTIONS 100 + +static int loadOutputFormat(mapObj *map) { + char *name = NULL; + char *mimetype = NULL; + char *driver = NULL; + char *extension = NULL; + int imagemode = MS_NOOVERRIDE; + int transparent = MS_NOOVERRIDE; + char *formatoptions[MAX_FORMATOPTIONS]; + int numformatoptions = 0; + char *value = NULL; + + for (;;) { + switch (msyylex()) { + case (EOF): + msSetError(MS_EOFERR, NULL, "loadOutputFormat()"); + goto load_output_error; + + case (END): { + outputFormatObj *format; + + if (driver == NULL) { + msSetError(MS_MISCERR, + "OUTPUTFORMAT clause lacks DRIVER keyword near (%s):(%d)", + "loadOutputFormat()", msyystring_buffer, msyylineno); + goto load_output_error; + } + + format = msCreateDefaultOutputFormat(map, driver, name, NULL); + if (format == NULL) { + msSetError(MS_MISCERR, + "OUTPUTFORMAT (%s) clause references driver (%s), but this " + "driver isn't configured.", + "loadOutputFormat()", name, driver); + goto load_output_error; + } + msFree(name); + name = NULL; + msFree(driver); + driver = NULL; + + if (transparent != MS_NOOVERRIDE) + format->transparent = transparent; + if (extension != NULL) { + msFree(format->extension); + format->extension = extension; + extension = NULL; + } + if (mimetype != NULL) { + msFree(format->mimetype); + format->mimetype = mimetype; + mimetype = NULL; + } + if (imagemode != MS_NOOVERRIDE) { + if (format->renderer != MS_RENDER_WITH_AGG || + imagemode != MS_IMAGEMODE_PC256) { + /* don't force to PC256 with agg, this can happen when using mapfile + * defined GD outputformats that are now falling back to agg/png8 + */ + format->imagemode = imagemode; + } + + if (transparent == MS_NOOVERRIDE) { + if (imagemode == MS_IMAGEMODE_RGB) + format->transparent = MS_FALSE; + else if (imagemode == MS_IMAGEMODE_RGBA) + format->transparent = MS_TRUE; + } + if (format->imagemode == MS_IMAGEMODE_INT16 || + format->imagemode == MS_IMAGEMODE_FLOAT32 || + format->imagemode == MS_IMAGEMODE_BYTE) + format->renderer = MS_RENDER_WITH_RAWDATA; + } + while (numformatoptions--) { + char *key = strchr(formatoptions[numformatoptions], '='); + if (!key || !*(key + 1)) { + msSetError( + MS_MISCERR, + "Failed to parse FORMATOPTION, expecting \"KEY=VALUE\" syntax.", + "loadOutputFormat()"); + goto load_output_error; + } + *key = 0; + key++; + msSetOutputFormatOption(format, formatoptions[numformatoptions], key); + free(formatoptions[numformatoptions]); + } + + format->inmapfile = MS_TRUE; + + msOutputFormatValidate(format, MS_FALSE); + return (0); + } + case (NAME): + msFree(name); + if ((name = getToken()) == NULL) + goto load_output_error; + break; + case (MIMETYPE): + if (getString(&mimetype) == MS_FAILURE) + goto load_output_error; + break; + case (DRIVER): { + int s; + if ((s = getSymbol(2, MS_STRING, TEMPLATE)) == + -1) /* allow the template to be quoted or not in the mapfile */ + goto load_output_error; + free(driver); + if (s == MS_STRING) + driver = msStrdup(msyystring_buffer); + else + driver = msStrdup("TEMPLATE"); + } break; + case (EXTENSION): + if (getString(&extension) == MS_FAILURE) + goto load_output_error; + if (extension[0] == '.') { + char *temp = msStrdup(extension + 1); + free(extension); + extension = temp; + } + break; + case (FORMATOPTION): + if (getString(&value) == MS_FAILURE) + goto load_output_error; + if (numformatoptions < MAX_FORMATOPTIONS) + formatoptions[numformatoptions++] = value; + value = NULL; + break; + case (IMAGEMODE): + value = getToken(); + if (strcasecmp(value, "PC256") == 0) + imagemode = MS_IMAGEMODE_PC256; + else if (strcasecmp(value, "RGB") == 0) + imagemode = MS_IMAGEMODE_RGB; + else if (strcasecmp(value, "RGBA") == 0) + imagemode = MS_IMAGEMODE_RGBA; + else if (strcasecmp(value, "INT16") == 0) + imagemode = MS_IMAGEMODE_INT16; + else if (strcasecmp(value, "FLOAT32") == 0) + imagemode = MS_IMAGEMODE_FLOAT32; + else if (strcasecmp(value, "BYTE") == 0) + imagemode = MS_IMAGEMODE_BYTE; + else if (strcasecmp(value, "FEATURE") == 0) + imagemode = MS_IMAGEMODE_FEATURE; + else { + msSetError(MS_IDENTERR, + "Parsing error near (%s):(line %d), expected PC256, RGB, " + "RGBA, FEATURE, BYTE, INT16, or FLOAT32 for IMAGEMODE.", + "loadOutputFormat()", msyystring_buffer, msyylineno); + goto load_output_error; + } + free(value); + value = NULL; + break; + case (TRANSPARENT): + if ((transparent = getSymbol(2, MS_ON, MS_OFF)) == -1) + goto load_output_error; + break; + default: + msSetError(MS_IDENTERR, "Parsing error near (%s):(line %d)", + "loadOutputFormat()", msyystring_buffer, msyylineno); + goto load_output_error; + } + } /* next token */ +load_output_error: + msFree(driver); + msFree(extension); + msFree(mimetype); + msFree(name); + msFree(value); + return -1; +} + +/* +** utility function to write an output format structure to file +*/ +static void writeOutputformatobject(FILE *stream, int indent, + outputFormatObj *outputformat) { + int i = 0; + if (!outputformat) + return; + + indent++; + writeBlockBegin(stream, indent, "OUTPUTFORMAT"); + writeString(stream, indent, "NAME", NULL, outputformat->name); + writeString(stream, indent, "MIMETYPE", NULL, outputformat->mimetype); + writeString(stream, indent, "DRIVER", NULL, outputformat->driver); + writeString(stream, indent, "EXTENSION", NULL, outputformat->extension); + writeKeyword(stream, indent, "IMAGEMODE", outputformat->imagemode, 7, + MS_IMAGEMODE_PC256, "PC256", MS_IMAGEMODE_RGB, "RGB", + MS_IMAGEMODE_RGBA, "RGBA", MS_IMAGEMODE_INT16, "INT16", + MS_IMAGEMODE_FLOAT32, "FLOAT32", MS_IMAGEMODE_BYTE, "BYTE", + MS_IMAGEMODE_FEATURE, "FEATURE"); + writeKeyword(stream, indent, "TRANSPARENT", outputformat->transparent, 2, + MS_TRUE, "TRUE", MS_FALSE, "FALSE"); + for (i = 0; i < outputformat->numformatoptions; i++) + writeString(stream, indent, "FORMATOPTION", NULL, + outputformat->formatoptions[i]); + writeBlockEnd(stream, indent, "OUTPUTFORMAT"); + writeLineFeed(stream); +} + +/* +** Write the output formats to file +*/ +static void writeOutputformat(FILE *stream, int indent, mapObj *map) { + int i = 0; + if (!map->outputformat) + return; + + writeOutputformatobject(stream, indent, map->outputformat); + for (i = 0; i < map->numoutputformats; i++) { + if (map->outputformatlist[i]->inmapfile == MS_TRUE && + strcmp(map->outputformatlist[i]->name, map->outputformat->name) != 0) + writeOutputformatobject(stream, indent, map->outputformatlist[i]); + } +} + +/* +** Initialize, load and free a legendObj structure +*/ +void initLegend(legendObj *legend) { + legend->height = legend->width = 0; + MS_INIT_COLOR(legend->imagecolor, 255, 255, 255, 255); /* white */ + MS_INIT_COLOR(legend->outlinecolor, -1, -1, -1, 255); + initLabel(&legend->label); + legend->label.position = MS_XY; /* override */ + legend->keysizex = 20; + legend->keysizey = 10; + legend->keyspacingx = 5; + legend->keyspacingy = 5; + legend->status = MS_OFF; + legend->transparent = MS_NOOVERRIDE; + legend->position = MS_LL; + legend->postlabelcache = MS_FALSE; /* draw with labels */ + legend->template = NULL; + legend->map = NULL; +} + +void freeLegend(legendObj *legend) { + if (legend->template) + free(legend->template); + freeLabel(&(legend->label)); +} + +int loadLegend(legendObj *legend, mapObj *map) { + legend->map = (mapObj *)map; + + for (;;) { + switch (msyylex()) { + case (EOF): + msSetError(MS_EOFERR, NULL, "loadLegend()"); + return (-1); + case (END): + legend->label.position = MS_XY; /* overrides go here */ + return (0); + break; + case (IMAGECOLOR): + if (loadColor(&(legend->imagecolor), NULL) != MS_SUCCESS) + return (-1); + break; + case (KEYSIZE): + if (getInteger(&(legend->keysizex), MS_NUM_CHECK_RANGE, + MS_LEGEND_KEYSIZE_MIN, MS_LEGEND_KEYSIZE_MAX) == -1) + return (-1); + if (getInteger(&(legend->keysizey), MS_NUM_CHECK_RANGE, + MS_LEGEND_KEYSIZE_MIN, MS_LEGEND_KEYSIZE_MAX) == -1) + return (-1); + break; + case (KEYSPACING): + if (getInteger(&(legend->keyspacingx), MS_NUM_CHECK_RANGE, + MS_LEGEND_KEYSPACING_MIN, MS_LEGEND_KEYSPACING_MAX) == -1) + return (-1); + if (getInteger(&(legend->keyspacingy), MS_NUM_CHECK_RANGE, + MS_LEGEND_KEYSPACING_MIN, MS_LEGEND_KEYSPACING_MAX) == -1) + return (-1); + break; + case (LABEL): + if (loadLabel(&(legend->label)) == -1) + return (-1); + legend->label.angle = 0; /* force */ + break; + case (LEGEND): + break; /* for string loads */ + case (OUTLINECOLOR): + if (loadColor(&(legend->outlinecolor), NULL) != MS_SUCCESS) + return (-1); + break; + case (POSITION): + if ((legend->position = + getSymbol(6, MS_UL, MS_UR, MS_LL, MS_LR, MS_UC, MS_LC)) == -1) + return (-1); + break; + case (POSTLABELCACHE): + if ((legend->postlabelcache = getSymbol(2, MS_TRUE, MS_FALSE)) == -1) + return (-1); + break; + case (STATUS): + if ((legend->status = getSymbol(3, MS_ON, MS_OFF, MS_EMBED)) == -1) + return (-1); + break; + case (TRANSPARENT): + if ((legend->transparent = getSymbol(2, MS_ON, MS_OFF)) == -1) + return (-1); + break; + case (TEMPLATE): + if (getString(&legend->template) == MS_FAILURE) + return (-1); + break; + default: + if (strlen(msyystring_buffer) > 0) { + msSetError(MS_IDENTERR, "Parsing error near (%s):(line %d)", + "loadLegend()", msyystring_buffer, msyylineno); + return (-1); + } else { + return (0); /* end of a string, not an error */ + } + } + } /* next token */ +} + +int msUpdateLegendFromString(legendObj *legend, char *string) { + if (!legend || !string) + return MS_FAILURE; + + msAcquireLock(TLOCK_PARSER); + + msyystate = MS_TOKENIZE_STRING; + msyystring = string; + msyylex(); /* sets things up, but doesn't process any tokens */ + + msyylineno = 1; /* start at line 1 */ + + if (loadLegend(legend, legend->map) == -1) { + msReleaseLock(TLOCK_PARSER); + return MS_FAILURE; /* parse error */ + ; + } + + msyylex_destroy(); + msReleaseLock(TLOCK_PARSER); + return MS_SUCCESS; +} + +static void writeLegend(FILE *stream, int indent, legendObj *legend) { + colorObj c; + + indent++; + writeBlockBegin(stream, indent, "LEGEND"); + MS_INIT_COLOR(c, 255, 255, 255, 255); + writeColor(stream, indent, "IMAGECOLOR", &c, &(legend->imagecolor)); + writeDimension(stream, indent, "KEYSIZE", legend->keysizex, legend->keysizey, + NULL, NULL); + writeDimension(stream, indent, "KEYSPACING", legend->keyspacingx, + legend->keyspacingy, NULL, NULL); + writeLabel(stream, indent, &(legend->label)); + writeColor(stream, indent, "OUTLINECOLOR", NULL, &(legend->outlinecolor)); + if (legend->status == MS_EMBED) + writeKeyword(stream, indent, "POSITION", legend->position, 6, MS_LL, "LL", + MS_UL, "UL", MS_UR, "UR", MS_LR, "LR", MS_UC, "UC", MS_LC, + "LC"); + writeKeyword(stream, indent, "POSTLABELCACHE", legend->postlabelcache, 1, + MS_TRUE, "TRUE"); + writeKeyword(stream, indent, "STATUS", legend->status, 3, MS_ON, "ON", MS_OFF, + "OFF", MS_EMBED, "EMBED"); + writeKeyword(stream, indent, "TRANSPARENT", legend->transparent, 2, MS_TRUE, + "TRUE", MS_FALSE, "FALSE"); + writeString(stream, indent, "TEMPLATE", NULL, legend->template); + writeBlockEnd(stream, indent, "LEGEND"); + writeLineFeed(stream); +} + +char *msWriteLegendToString(legendObj *legend) { + msIOContext context; + msIOBuffer buffer; + + context.label = NULL; + context.write_channel = MS_TRUE; + context.readWriteFunc = msIO_bufferWrite; + context.cbData = &buffer; + buffer.data = NULL; + buffer.data_len = 0; + buffer.data_offset = 0; + + msIO_installHandlers(NULL, &context, NULL); + + writeLegend(stdout, -1, legend); + msIO_bufferWrite(&buffer, "", 1); + + msIO_installHandlers(NULL, NULL, NULL); + + return (char *)buffer.data; +} + +/* +** Initialize, load and free a scalebarObj structure +*/ +void initScalebar(scalebarObj *scalebar) { + MS_INIT_COLOR(scalebar->imagecolor, -1, -1, -1, 255); + scalebar->width = 200; + scalebar->height = 3; + scalebar->style = 0; /* only 2 styles at this point */ + scalebar->intervals = 4; + initLabel(&scalebar->label); + scalebar->label.position = MS_XY; /* override */ + MS_INIT_COLOR(scalebar->backgroundcolor, -1, -1, -1, + 255); /* if not set, scalebar creation needs to set this to + match the background color */ + MS_INIT_COLOR(scalebar->color, 0, 0, 0, 255); /* default to black */ + MS_INIT_COLOR(scalebar->outlinecolor, -1, -1, -1, 255); + scalebar->units = MS_MILES; + scalebar->status = MS_OFF; + scalebar->position = MS_LL; + scalebar->transparent = MS_NOOVERRIDE; /* no transparency */ + scalebar->postlabelcache = MS_FALSE; /* draw with labels */ + scalebar->align = MS_ALIGN_CENTER; + scalebar->offsetx = 0; + scalebar->offsety = 0; +} + +void freeScalebar(scalebarObj *scalebar) { freeLabel(&(scalebar->label)); } + +int loadScalebar(scalebarObj *scalebar) { + for (;;) { + switch (msyylex()) { + case (ALIGN): + if ((scalebar->align = getSymbol(3, MS_ALIGN_LEFT, MS_ALIGN_CENTER, + MS_ALIGN_RIGHT)) == -1) + return (-1); + break; + case (BACKGROUNDCOLOR): + if (loadColor(&(scalebar->backgroundcolor), NULL) != MS_SUCCESS) + return (-1); + break; + case (COLOR): + if (loadColor(&(scalebar->color), NULL) != MS_SUCCESS) + return (-1); + break; + case (EOF): + msSetError(MS_EOFERR, NULL, "loadScalebar()"); + return (-1); + case (END): + return (0); + break; + case (IMAGECOLOR): + if (loadColor(&(scalebar->imagecolor), NULL) != MS_SUCCESS) + return (-1); + break; + case (INTERVALS): + if (getInteger(&(scalebar->intervals), MS_NUM_CHECK_RANGE, + MS_SCALEBAR_INTERVALS_MIN, + MS_SCALEBAR_INTERVALS_MAX) == -1) + return (-1); + break; + case (LABEL): + if (loadLabel(&(scalebar->label)) == -1) + return (-1); + scalebar->label.angle = 0; + break; + case (OUTLINECOLOR): + if (loadColor(&(scalebar->outlinecolor), NULL) != MS_SUCCESS) + return (-1); + break; + case (POSITION): + if ((scalebar->position = + getSymbol(6, MS_UL, MS_UR, MS_LL, MS_LR, MS_UC, MS_LC)) == -1) + return (-1); + break; + case (POSTLABELCACHE): + if ((scalebar->postlabelcache = getSymbol(2, MS_TRUE, MS_FALSE)) == -1) + return (-1); + break; + case (SCALEBAR): + break; /* for string loads */ + case (SIZE): + if (getInteger(&(scalebar->width), MS_NUM_CHECK_RANGE, + MS_SCALEBAR_WIDTH_MIN, MS_SCALEBAR_WIDTH_MAX) == -1) + return (-1); + if (getInteger(&(scalebar->height), MS_NUM_CHECK_RANGE, + MS_SCALEBAR_HEIGHT_MIN, MS_SCALEBAR_HEIGHT_MAX) == -1) + return (-1); + break; + case (STATUS): + if ((scalebar->status = getSymbol(3, MS_ON, MS_OFF, MS_EMBED)) == -1) + return (-1); + break; + case (STYLE): + if (getInteger(&(scalebar->style), MS_NUM_CHECK_RANGE, 0, 1) == -1) + return (-1); // only 2 styles: 0 and 1 + break; + case (TRANSPARENT): + if ((scalebar->transparent = getSymbol(2, MS_ON, MS_OFF)) == -1) + return (-1); + break; + case (UNITS): + if ((scalebar->units = + getSymbol(6, MS_INCHES, MS_FEET, MS_MILES, MS_METERS, + MS_KILOMETERS, MS_NAUTICALMILES)) == -1) + return (-1); + break; + case (OFFSET): + if (getInteger(&(scalebar->offsetx), MS_NUM_CHECK_RANGE, + MS_SCALEBAR_OFFSET_MIN, MS_SCALEBAR_OFFSET_MAX) == -1) + return (-1); + if (getInteger(&(scalebar->offsety), MS_NUM_CHECK_RANGE, + MS_SCALEBAR_OFFSET_MIN, MS_SCALEBAR_OFFSET_MAX) == -1) + return (-1); + break; + default: + if (strlen(msyystring_buffer) > 0) { + msSetError(MS_IDENTERR, "Parsing error near (%s):(line %d)", + "loadScalebar()", msyystring_buffer, msyylineno); + return (-1); + } else { + return (0); /* end of a string, not an error */ + } + } + } /* next token */ +} + +int msUpdateScalebarFromString(scalebarObj *scalebar, char *string) { + if (!scalebar || !string) + return MS_FAILURE; + + msAcquireLock(TLOCK_PARSER); + + msyystate = MS_TOKENIZE_STRING; + msyystring = string; + msyylex(); /* sets things up, but doesn't process any tokens */ + + msyylineno = 1; /* start at line 1 */ + + if (loadScalebar(scalebar) == -1) { + msReleaseLock(TLOCK_PARSER); + return MS_FAILURE; /* parse error */ + ; + } + + msyylex_destroy(); + msReleaseLock(TLOCK_PARSER); + return MS_SUCCESS; +} + +static void writeScalebar(FILE *stream, int indent, scalebarObj *scalebar) { + colorObj c; + + indent++; + writeBlockBegin(stream, indent, "SCALEBAR"); + writeKeyword(stream, indent, "ALIGN", scalebar->align, 2, MS_ALIGN_LEFT, + "LEFT", MS_ALIGN_RIGHT, "RIGHT"); + writeColor(stream, indent, "BACKGROUNDCOLOR", NULL, + &(scalebar->backgroundcolor)); + MS_INIT_COLOR(c, 0, 0, 0, 255); + writeColor(stream, indent, "COLOR", &c, &(scalebar->color)); + writeColor(stream, indent, "IMAGECOLOR", NULL, &(scalebar->imagecolor)); + writeNumber(stream, indent, "INTERVALS", -1, scalebar->intervals); + writeLabel(stream, indent, &(scalebar->label)); + writeColor(stream, indent, "OUTLINECOLOR", NULL, &(scalebar->outlinecolor)); + if (scalebar->status == MS_EMBED) + writeKeyword(stream, indent, "POSITION", scalebar->position, 6, MS_LL, "LL", + MS_UL, "UL", MS_UR, "UR", MS_LR, "LR", MS_UC, "UC", MS_LC, + "LC"); + writeKeyword(stream, indent, "POSTLABELCACHE", scalebar->postlabelcache, 1, + MS_TRUE, "TRUE"); + writeDimension(stream, indent, "SIZE", scalebar->width, scalebar->height, + NULL, NULL); + writeKeyword(stream, indent, "STATUS", scalebar->status, 3, MS_ON, "ON", + MS_OFF, "OFF", MS_EMBED, "EMBED"); + writeNumber(stream, indent, "STYLE", 0, scalebar->style); + writeKeyword(stream, indent, "TRANSPARENT", scalebar->transparent, 2, MS_TRUE, + "TRUE", MS_FALSE, "FALSE"); + writeKeyword(stream, indent, "UNITS", scalebar->units, 6, MS_INCHES, "INCHES", + MS_FEET, "FEET", MS_MILES, "MILES", MS_METERS, "METERS", + MS_KILOMETERS, "KILOMETERS", MS_NAUTICALMILES, "NAUTICALMILES"); + writeBlockEnd(stream, indent, "SCALEBAR"); + writeLineFeed(stream); +} + +char *msWriteScalebarToString(scalebarObj *scalebar) { + msIOContext context; + msIOBuffer buffer; + + context.label = NULL; + context.write_channel = MS_TRUE; + context.readWriteFunc = msIO_bufferWrite; + context.cbData = &buffer; + buffer.data = NULL; + buffer.data_len = 0; + buffer.data_offset = 0; + + msIO_installHandlers(NULL, &context, NULL); + + writeScalebar(stdout, -1, scalebar); + msIO_bufferWrite(&buffer, "", 1); + + msIO_installHandlers(NULL, NULL, NULL); + + return (char *)buffer.data; +} + +/* +** Initialize a queryMapObj structure +*/ +void initQueryMap(queryMapObj *querymap) { + querymap->width = querymap->height = -1; + querymap->style = MS_HILITE; + querymap->status = MS_OFF; + MS_INIT_COLOR(querymap->color, 255, 255, 0, 255); /* yellow */ +} + +int loadQueryMap(queryMapObj *querymap, mapObj *map) { + querymap->map = (mapObj *)map; + + for (;;) { + switch (msyylex()) { + case (QUERYMAP): + break; /* for string loads */ + case (COLOR): + if (loadColor(&(querymap->color), NULL) != MS_SUCCESS) + return MS_FAILURE; + break; + case (EOF): + msSetError(MS_EOFERR, NULL, "loadQueryMap()"); + return (-1); + case (END): + return (0); + break; + case (SIZE): + /* + ** we do -1 (and avoid 0) here to maintain backwards compatibility as + *older versions write "SIZE -1 -1" when saving a mapfile + */ + if (getInteger(&(querymap->width), MS_NUM_CHECK_RANGE, -1, + querymap->map->maxsize) == -1 || + querymap->width == 0) { + msSetError(MS_MISCERR, "Invalid SIZE value (line %d)", "loadQueryMap()", + msyylineno); + return (-1); + } + if (getInteger(&(querymap->height), MS_NUM_CHECK_RANGE, -1, + querymap->map->maxsize) == -1 || + querymap->height == 0) { + msSetError(MS_MISCERR, "Invalid SIZE value (line %d)", "loadQueryMap()", + msyylineno); + return (-1); + } + break; + case (STATUS): + if ((querymap->status = getSymbol(2, MS_ON, MS_OFF)) == -1) + return (-1); + break; + case (STYLE): + case (TYPE): + if ((querymap->style = getSymbol(3, MS_NORMAL, MS_HILITE, MS_SELECTED)) == + -1) + return (-1); + break; + default: + if (strlen(msyystring_buffer) > 0) { + msSetError(MS_IDENTERR, "Parsing error near (%s):(line %d)", + "loadQueryMap()", msyystring_buffer, msyylineno); + return (-1); + } else { + return (0); /* end of a string, not an error */ + } + } + } +} + +int msUpdateQueryMapFromString(queryMapObj *querymap, char *string) { + if (!querymap || !string) + return MS_FAILURE; + + msAcquireLock(TLOCK_PARSER); + + msyystate = MS_TOKENIZE_STRING; + msyystring = string; + msyylex(); /* sets things up, but doesn't process any tokens */ + + msyylineno = 1; /* start at line 1 */ + + if (loadQueryMap(querymap, querymap->map) == -1) { + msReleaseLock(TLOCK_PARSER); + return MS_FAILURE; /* parse error */ + ; + } + + msyylex_destroy(); + msReleaseLock(TLOCK_PARSER); + return MS_SUCCESS; +} + +static void writeQueryMap(FILE *stream, int indent, queryMapObj *querymap) { + colorObj c; + + indent++; + writeBlockBegin(stream, indent, "QUERYMAP"); + MS_INIT_COLOR(c, 255, 255, 0, 255); + writeColor(stream, indent, "COLOR", &c, &(querymap->color)); + if (querymap->width != -1 && + querymap->height != -1) // don't write SIZE if not explicitly set + writeDimension(stream, indent, "SIZE", querymap->width, querymap->height, + NULL, NULL); + writeKeyword(stream, indent, "STATUS", querymap->status, 2, MS_ON, "ON", + MS_OFF, "OFF"); + writeKeyword(stream, indent, "STYLE", querymap->style, 3, MS_NORMAL, "NORMAL", + MS_HILITE, "HILITE", MS_SELECTED, "SELECTED"); + writeBlockEnd(stream, indent, "QUERYMAP"); + writeLineFeed(stream); +} + +char *msWriteQueryMapToString(queryMapObj *querymap) { + msIOContext context; + msIOBuffer buffer; + + context.label = NULL; + context.write_channel = MS_TRUE; + context.readWriteFunc = msIO_bufferWrite; + context.cbData = &buffer; + buffer.data = NULL; + buffer.data_len = 0; + buffer.data_offset = 0; + + msIO_installHandlers(NULL, &context, NULL); + + writeQueryMap(stdout, -1, querymap); + msIO_bufferWrite(&buffer, "", 1); + + msIO_installHandlers(NULL, NULL, NULL); + + return (char *)buffer.data; +} + +/* +** Initialize a webObj structure +*/ +void initWeb(webObj *web) { + web->template = NULL; + web->header = web->footer = NULL; + web->error = web->empty = NULL; + web->mintemplate = web->maxtemplate = NULL; + web->minscaledenom = web->maxscaledenom = -1; + web->imagepath = msStrdup(""); + web->temppath = NULL; + web->imageurl = msStrdup(""); + + initHashTable(&(web->metadata)); + initHashTable(&(web->validation)); + + web->map = NULL; + web->queryformat = msStrdup("text/html"); + web->legendformat = msStrdup("text/html"); + web->browseformat = msStrdup("text/html"); +} + +void freeWeb(webObj *web) { + msFree(web->template); + msFree(web->header); + msFree(web->footer); + msFree(web->error); + msFree(web->empty); + msFree(web->maxtemplate); + msFree(web->mintemplate); + msFree(web->imagepath); + msFree(web->temppath); + msFree(web->imageurl); + msFree(web->queryformat); + msFree(web->legendformat); + msFree(web->browseformat); + msFreeHashItems(&(web->metadata)); + msFreeHashItems(&(web->validation)); +} + +static void writeWeb(FILE *stream, int indent, webObj *web) { + indent++; + writeBlockBegin(stream, indent, "WEB"); + writeString(stream, indent, "BROWSEFORMAT", "text/html", web->browseformat); + writeString(stream, indent, "EMPTY", NULL, web->empty); + writeString(stream, indent, "ERROR", NULL, web->error); + writeString(stream, indent, "FOOTER", NULL, web->footer); + writeString(stream, indent, "HEADER", NULL, web->header); + writeString(stream, indent, "IMAGEPATH", "", web->imagepath); + writeString(stream, indent, "TEMPPATH", NULL, web->temppath); + writeString(stream, indent, "IMAGEURL", "", web->imageurl); + writeString(stream, indent, "LEGENDFORMAT", "text/html", web->legendformat); + writeNumber(stream, indent, "MAXSCALEDENOM", -1, web->maxscaledenom); + writeString(stream, indent, "MAXTEMPLATE", NULL, web->maxtemplate); + writeHashTable(stream, indent, "METADATA", &(web->metadata)); + writeNumber(stream, indent, "MINSCALEDENOM", -1, web->minscaledenom); + writeString(stream, indent, "MINTEMPLATE", NULL, web->mintemplate); + writeString(stream, indent, "QUERYFORMAT", "text/html", web->queryformat); + writeString(stream, indent, "TEMPLATE", NULL, web->template); + writeHashTable(stream, indent, "VALIDATION", &(web->validation)); + writeBlockEnd(stream, indent, "WEB"); + writeLineFeed(stream); +} + +char *msWriteWebToString(webObj *web) { + msIOContext context; + msIOBuffer buffer; + + context.label = NULL; + context.write_channel = MS_TRUE; + context.readWriteFunc = msIO_bufferWrite; + context.cbData = &buffer; + buffer.data = NULL; + buffer.data_len = 0; + buffer.data_offset = 0; + + msIO_installHandlers(NULL, &context, NULL); + + writeWeb(stdout, -1, web); + msIO_bufferWrite(&buffer, "", 1); + + msIO_installHandlers(NULL, NULL, NULL); + + return (char *)buffer.data; +} + +int loadWeb(webObj *web, mapObj *map) { + web->map = (mapObj *)map; + + for (;;) { + switch (msyylex()) { + case (BROWSEFORMAT): /* change to use validation in 6.0 */ + free(web->browseformat); + web->browseformat = NULL; /* there is a default */ + if (getString(&web->browseformat) == MS_FAILURE) + return (-1); + break; + case (EMPTY): + if (getString(&web->empty) == MS_FAILURE) + return (-1); + break; + case (WEB): + break; /* for string loads */ + case (EOF): + msSetError(MS_EOFERR, NULL, "loadWeb()"); + return (-1); + case (END): + return (0); + break; + case (ERROR): + if (getString(&web->error) == MS_FAILURE) + return (-1); + break; + case (FOOTER): + if (getString(&web->footer) == MS_FAILURE) + return (-1); /* getString() cleans up previously allocated string */ + break; + case (HEADER): + if (getString(&web->header) == MS_FAILURE) + return (-1); /* getString() cleans up previously allocated string */ + break; + case (IMAGEPATH): + if (getString(&web->imagepath) == MS_FAILURE) + return (-1); + break; + case (TEMPPATH): + if (getString(&web->temppath) == MS_FAILURE) + return (-1); + break; + case (IMAGEURL): + if (getString(&web->imageurl) == MS_FAILURE) + return (-1); + break; + case (LEGENDFORMAT): /* change to use validation in 6.0 */ + free(web->legendformat); + web->legendformat = NULL; /* there is a default */ + if (getString(&web->legendformat) == MS_FAILURE) + return (-1); + break; + case (MAXSCALEDENOM): + if (getDouble(&web->maxscaledenom, MS_NUM_CHECK_GTE, 0, -1) == -1) + return (-1); + break; + case (MAXTEMPLATE): + if (getString(&web->maxtemplate) == MS_FAILURE) + return (-1); + break; + case (METADATA): + if (loadHashTable(&(web->metadata)) != MS_SUCCESS) + return (-1); + break; + case (MINSCALEDENOM): + if (getDouble(&web->minscaledenom, MS_NUM_CHECK_GTE, 0, -1) == -1) + return (-1); + break; + case (MINTEMPLATE): + if (getString(&web->mintemplate) == MS_FAILURE) + return (-1); + break; + case (QUERYFORMAT): /* change to use validation in 6.0 */ + free(web->queryformat); + web->queryformat = NULL; /* there is a default */ + if (getString(&web->queryformat) == MS_FAILURE) + return (-1); + break; + case (TEMPLATE): + if (getString(&web->template) == MS_FAILURE) + return (-1); /* getString() cleans up previously allocated string */ + break; + case (VALIDATION): + if (loadHashTable(&(web->validation)) != MS_SUCCESS) + return (-1); + break; + default: + if (strlen(msyystring_buffer) > 0) { + msSetError(MS_IDENTERR, "Parsing error near (%s):(line %d)", + "loadWeb()", msyystring_buffer, msyylineno); + return (-1); + } else { + return (0); /* end of a string, not an error */ + } + } + } +} + +int msUpdateWebFromString(webObj *web, char *string) { + if (!web || !string) + return MS_FAILURE; + + msAcquireLock(TLOCK_PARSER); + + msyystate = MS_TOKENIZE_STRING; + msyystring = string; + msyylex(); /* sets things up, but doesn't process any tokens */ + + msyylineno = 1; /* start at line 1 */ + + if (loadWeb(web, web->map) == -1) { + msReleaseLock(TLOCK_PARSER); + return MS_FAILURE; /* parse error */ + ; + } + + msyylex_destroy(); + msReleaseLock(TLOCK_PARSER); + return MS_SUCCESS; +} + +/* +** Initialize, load and free a mapObj structure +** +** This really belongs in mapobject.c, but currently it also depends on +** lots of other init methods in this file. +*/ + +int initMap(mapObj *map) { + int i = 0; + MS_REFCNT_INIT(map); + + map->debug = (int)msGetGlobalDebugLevel(); + + /* Set maxlayers = 0, layers[] and layerorder[] will be allocated as needed, + * on the first call to msGrowMapLayers() + */ + map->numlayers = 0; + map->maxlayers = 0; + map->layers = NULL; + map->layerorder = + NULL; /* used to modify the order in which the layers are drawn */ + + map->status = MS_ON; + map->name = msStrdup("MS"); + map->extent.minx = map->extent.miny = map->extent.maxx = map->extent.maxy = + -1.0; + + map->scaledenom = -1.0; + map->resolution = MS_DEFAULT_RESOLUTION; /* pixels per inch */ + map->defresolution = MS_DEFAULT_RESOLUTION; /* pixels per inch */ + + map->height = map->width = -1; + map->maxsize = MS_MAXIMAGESIZE_DEFAULT; + + map->gt.need_geotransform = MS_FALSE; + map->gt.rotation_angle = 0.0; + + map->units = MS_METERS; + map->cellsize = 0; + map->shapepath = NULL; + map->mappath = NULL; + map->sldurl = NULL; + + MS_INIT_COLOR(map->imagecolor, 255, 255, 255, 255); /* white */ + + map->numoutputformats = 0; + map->outputformatlist = NULL; + map->outputformat = NULL; + + /* map->configoptions = msCreateHashTable();; */ + initHashTable(&(map->configoptions)); + + map->imagetype = NULL; + + map->palette.numcolors = 0; + + for (i = 0; i < MS_MAX_LABEL_PRIORITY; i++) { + map->labelcache.slots[i].labels = + NULL; /* cache is initialize at draw time */ + map->labelcache.slots[i].cachesize = 0; + map->labelcache.slots[i].numlabels = 0; + map->labelcache.slots[i].markers = NULL; + map->labelcache.slots[i].markercachesize = 0; + map->labelcache.slots[i].nummarkers = 0; + } + + map->fontset.filename = NULL; + map->fontset.numfonts = 0; + + /* map->fontset.fonts = NULL; */ + initHashTable(&(map->fontset.fonts)); + + msInitSymbolSet(&map->symbolset); + map->symbolset.fontset = &(map->fontset); + map->symbolset.map = map; + + initLegend(&map->legend); + initScalebar(&map->scalebar); + initWeb(&map->web); + initReferenceMap(&map->reference); + initQueryMap(&map->querymap); + + map->projContext = msProjectionContextGetFromPool(); + + if (msInitProjection(&(map->projection)) == -1) + return (-1); + if (msInitProjection(&(map->latlon)) == -1) + return (-1); + + msProjectionSetContext(&(map->projection), map->projContext); + msProjectionSetContext(&(map->latlon), map->projContext); + + /* initialize a default "geographic" projection */ + map->latlon.numargs = 2; + map->latlon.args[0] = msStrdup("proj=latlong"); + map->latlon.args[1] = + msStrdup("ellps=WGS84"); /* probably want a different ellipsoid */ + if (msProcessProjection(&(map->latlon)) == -1) + return (-1); + + map->templatepattern = map->datapattern = NULL; + + /* Encryption key information - see mapcrypto.c */ + map->encryption_key_loaded = MS_FALSE; + + msInitQuery(&(map->query)); + +#ifdef USE_V8_MAPSCRIPT + map->v8context = NULL; +#endif + + map->config = NULL; + + return (0); +} + +/* +** Ensure there is at least one free entry in the layers and layerorder +** arrays of this mapObj. Grow the allocated layers/layerorder arrays if +** necessary and allocate a new layer for layers[numlayers] if there is +** not already one, setting its contents to all zero bytes (i.e. does not +** call initLayer() on it). +** +** This function is safe to use for the initial allocation of the layers[] +** and layerorder[] arrays as well (i.e. when maxlayers==0 and layers==NULL) +** +** Returns a reference to the new layerObj on success, NULL on error. +*/ +layerObj *msGrowMapLayers(mapObj *map) { + /* Do we need to increase the size of layers/layerorder by + * MS_LAYER_ALLOCSIZE? + */ + if (map->numlayers == map->maxlayers) { + layerObj **newLayersPtr; + int *newLayerorderPtr; + int i, newsize; + + newsize = map->maxlayers + MS_LAYER_ALLOCSIZE; + + /* Alloc/realloc layers */ + newLayersPtr = + (layerObj **)realloc(map->layers, newsize * sizeof(layerObj *)); + MS_CHECK_ALLOC(newLayersPtr, newsize * sizeof(layerObj *), NULL); + + map->layers = newLayersPtr; + + /* Alloc/realloc layerorder */ + newLayerorderPtr = (int *)realloc(map->layerorder, newsize * sizeof(int)); + MS_CHECK_ALLOC(newLayerorderPtr, newsize * sizeof(int), NULL); + + map->layerorder = newLayerorderPtr; + + map->maxlayers = newsize; + for (i = map->numlayers; i < map->maxlayers; i++) { + map->layers[i] = NULL; + map->layerorder[i] = 0; + } + } + + if (map->layers[map->numlayers] == NULL) { + map->layers[map->numlayers] = (layerObj *)calloc(1, sizeof(layerObj)); + MS_CHECK_ALLOC(map->layers[map->numlayers], sizeof(layerObj), NULL); + } + + return map->layers[map->numlayers]; +} + +int msFreeLabelCacheSlot(labelCacheSlotObj *cacheslot) { + int i, j; + + /* free the labels */ + if (cacheslot->labels) { + for (i = 0; i < cacheslot->numlabels; i++) { + + for (j = 0; j < cacheslot->labels[i].numtextsymbols; j++) { + freeTextSymbol(cacheslot->labels[i].textsymbols[j]); + free(cacheslot->labels[i].textsymbols[j]); + } + msFree(cacheslot->labels[i].textsymbols); + + if (cacheslot->labels[i].leaderline) { + msFree(cacheslot->labels[i].leaderline->point); + msFree(cacheslot->labels[i].leaderline); + msFree(cacheslot->labels[i].leaderbbox); + } + } + } + msFree(cacheslot->labels); + cacheslot->labels = NULL; + cacheslot->cachesize = 0; + cacheslot->numlabels = 0; + + msFree(cacheslot->markers); + cacheslot->markers = NULL; + cacheslot->markercachesize = 0; + cacheslot->nummarkers = 0; + + return (MS_SUCCESS); +} + +int msFreeLabelCache(labelCacheObj *cache) { + int p; + + for (p = 0; p < MS_MAX_LABEL_PRIORITY; p++) { + if (msFreeLabelCacheSlot(&(cache->slots[p])) != MS_SUCCESS) + return MS_FAILURE; + } + + cache->num_allocated_rendered_members = cache->num_rendered_members = 0; + msFree(cache->rendered_text_symbols); + + return MS_SUCCESS; +} + +int msInitLabelCacheSlot(labelCacheSlotObj *cacheslot) { + + if (cacheslot->labels || cacheslot->markers) + msFreeLabelCacheSlot(cacheslot); + + cacheslot->labels = (labelCacheMemberObj *)malloc( + sizeof(labelCacheMemberObj) * MS_LABELCACHEINITSIZE); + MS_CHECK_ALLOC(cacheslot->labels, + sizeof(labelCacheMemberObj) * MS_LABELCACHEINITSIZE, + MS_FAILURE); + + cacheslot->cachesize = MS_LABELCACHEINITSIZE; + cacheslot->numlabels = 0; + + cacheslot->markers = (markerCacheMemberObj *)malloc( + sizeof(markerCacheMemberObj) * MS_LABELCACHEINITSIZE); + MS_CHECK_ALLOC(cacheslot->markers, + sizeof(markerCacheMemberObj) * MS_LABELCACHEINITSIZE, + MS_FAILURE); + + cacheslot->markercachesize = MS_LABELCACHEINITSIZE; + cacheslot->nummarkers = 0; + + return (MS_SUCCESS); +} + +int msInitLabelCache(labelCacheObj *cache) { + int p; + + for (p = 0; p < MS_MAX_LABEL_PRIORITY; p++) { + if (msInitLabelCacheSlot(&(cache->slots[p])) != MS_SUCCESS) + return MS_FAILURE; + } + cache->gutter = 0; + cache->num_allocated_rendered_members = cache->num_rendered_members = 0; + cache->rendered_text_symbols = NULL; + + return MS_SUCCESS; +} + +static void writeMap(FILE *stream, int indent, mapObj *map) { + int i; + colorObj c; + + writeBlockBegin(stream, indent, "MAP"); + writeNumber(stream, indent, "ANGLE", 0, map->gt.rotation_angle); + writeHashTableInline(stream, indent, "CONFIG", &(map->configoptions)); + writeNumber(stream, indent, "DEBUG", 0, map->debug); + writeNumber(stream, indent, "DEFRESOLUTION", 72.0, map->defresolution); + writeExtent(stream, indent, "EXTENT", map->extent); + writeString(stream, indent, "FONTSET", NULL, map->fontset.filename); + MS_INIT_COLOR(c, 255, 255, 255, 255); + writeColor(stream, indent, "IMAGECOLOR", &c, &(map->imagecolor)); + writeString(stream, indent, "IMAGETYPE", NULL, map->imagetype); + writeNumber(stream, indent, "MAXSIZE", MS_MAXIMAGESIZE_DEFAULT, map->maxsize); + writeString(stream, indent, "NAME", NULL, map->name); + writeNumber(stream, indent, "RESOLUTION", 72.0, map->resolution); + writeString(stream, indent, "SHAPEPATH", NULL, map->shapepath); + writeDimension(stream, indent, "SIZE", map->width, map->height, NULL, NULL); + writeKeyword(stream, indent, "STATUS", map->status, 2, MS_ON, "ON", MS_OFF, + "OFF"); + writeString(stream, indent, "SYMBOLSET", NULL, map->symbolset.filename); + writeKeyword(stream, indent, "UNITS", map->units, 7, MS_INCHES, "INCHES", + MS_FEET, "FEET", MS_MILES, "MILES", MS_METERS, "METERS", + MS_KILOMETERS, "KILOMETERS", MS_NAUTICALMILES, "NAUTICALMILES", + MS_DD, "DD"); + writeLineFeed(stream); + + writeOutputformat(stream, indent, map); + + /* write symbol with INLINE tag in mapfile */ + for (i = 0; i < map->symbolset.numsymbols; i++) { + if (map->symbolset.symbol[i]->inmapfile) + writeSymbol(map->symbolset.symbol[i], stream); + } + + writeProjection(stream, indent, &(map->projection)); + + writeLegend(stream, indent, &(map->legend)); + writeQueryMap(stream, indent, &(map->querymap)); + writeReferenceMap(stream, indent, &(map->reference)); + writeScalebar(stream, indent, &(map->scalebar)); + writeWeb(stream, indent, &(map->web)); + + for (i = 0; i < map->numlayers; i++) + writeLayer(stream, indent, GET_LAYER(map, map->layerorder[i])); + + writeBlockEnd(stream, indent, "MAP"); +} + +char *msWriteMapToString(mapObj *map) { + msIOContext context; + msIOBuffer buffer; + + context.label = NULL; + context.write_channel = MS_TRUE; + context.readWriteFunc = msIO_bufferWrite; + context.cbData = &buffer; + buffer.data = NULL; + buffer.data_len = 0; + buffer.data_offset = 0; + + msIO_installHandlers(NULL, &context, NULL); + + writeMap(stdout, 0, map); + msIO_bufferWrite(&buffer, "", 1); + + msIO_installHandlers(NULL, NULL, NULL); + + return (char *)buffer.data; +} + +int msSaveMap(mapObj *map, char *filename) { + FILE *stream; + char szPath[MS_MAXPATHLEN]; + + if (!map) { + msSetError(MS_MISCERR, "Map is undefined.", "msSaveMap()"); + return (-1); + } + + if (!filename) { + msSetError(MS_MISCERR, "Filename is undefined.", "msSaveMap()"); + return (-1); + } + + stream = fopen(msBuildPath(szPath, map->mappath, filename), "w"); + if (!stream) { + msSetErrorWithStatus(MS_IOERR, MS_HTTP_500_INTERNAL_SERVER_ERROR, "(%s)", + "msSaveMap()", filename); + return (-1); + } + + writeMap(stream, 0, map); + fclose(stream); + + return (0); +} + +static void writeConfig(FILE *stream, int indent, configObj *config) { + writeBlockBegin(stream, indent, "CONFIG"); + writeHashTable(stream, indent, "ENV", &(config->env)); + writeHashTable(stream, indent, "MAPS", &(config->maps)); + writeBlockEnd(stream, indent, "CONFIG"); +} + +int msSaveConfig(configObj *config, const char *filename) { + FILE *stream; + + if (!config) { + msSetError(MS_MISCERR, "Config is undefined.", "msSaveConfigMap()"); + return (-1); + } + + if (!filename) { + msSetError(MS_MISCERR, "Filename is undefined.", "msSaveConfigMap()"); + return (-1); + } + + stream = fopen(filename, "w"); + if (!stream) { + msSetErrorWithStatus(MS_IOERR, MS_HTTP_500_INTERNAL_SERVER_ERROR, "(%s)", + "msSaveConfig()", filename); + return (-1); + } + + writeConfig(stream, 0, config); + fclose(stream); + + return (0); +} + +static int loadMapInternal(mapObj *map) { + int foundMapToken = MS_FALSE; + int foundBomToken = MS_FALSE; + int token; + + for (;;) { + + token = msyylex(); + + if (!foundBomToken && token == BOM) { + foundBomToken = MS_TRUE; + if (!foundMapToken) { + continue; /*skip a leading bom*/ + } + } + if (!foundMapToken && token != MAP) { + msSetError(MS_IDENTERR, + "First token must be MAP, this doesn't look like a mapfile.", + "msLoadMap()"); + return (MS_FAILURE); + } + + switch (token) { + + case (CONFIG): { + char *key = NULL, *value = NULL; + + if (getString(&key) == MS_FAILURE) + return MS_FAILURE; + + if (getString(&value) == MS_FAILURE) { + free(key); + return MS_FAILURE; + } + + if (msSetConfigOption(map, key, value) == MS_FAILURE) { + free(key); + free(value); + return MS_FAILURE; + } + + free(key); + free(value); + } break; + case (DEBUG): + if ((map->debug = getSymbol(3, MS_ON, MS_OFF, MS_NUMBER)) == -1) + return MS_FAILURE; + if (map->debug == MS_NUMBER) { + if (msCheckNumber(msyynumber, MS_NUM_CHECK_RANGE, 0, 5) == MS_FAILURE) { + msSetError(MS_MISCERR, + "Invalid DEBUG level, must be between 0 and 5 (line %d)", + "msLoadMap()", msyylineno); + return (-1); + } + map->debug = (int)msyynumber; + } + break; + case (END): + if (msyyin) { + fclose(msyyin); + msyyin = NULL; + } + + /*** Make config options current ***/ + msApplyMapConfigOptions(map); + + /*** Compute rotated extent info if applicable ***/ + msMapComputeGeotransform(map); + + /*** OUTPUTFORMAT related setup ***/ + if (msPostMapParseOutputFormatSetup(map) == MS_FAILURE) + return MS_FAILURE; + + if (loadSymbolSet(&(map->symbolset), map) == -1) + return MS_FAILURE; + + if (resolveSymbolNames(map) == MS_FAILURE) + return MS_FAILURE; + + if (msLoadFontSet(&(map->fontset), map) == -1) + return MS_FAILURE; + + return MS_SUCCESS; + break; + case (EOF): + msSetError(MS_EOFERR, NULL, "msLoadMap()"); + return MS_FAILURE; + case (EXTENT): { + if (getDouble(&(map->extent.minx), MS_NUM_CHECK_NONE, -1, -1) == -1) + return MS_FAILURE; + if (getDouble(&(map->extent.miny), MS_NUM_CHECK_NONE, -1, -1) == -1) + return MS_FAILURE; + if (getDouble(&(map->extent.maxx), MS_NUM_CHECK_NONE, -1, -1) == -1) + return MS_FAILURE; + if (getDouble(&(map->extent.maxy), MS_NUM_CHECK_NONE, -1, -1) == -1) + return MS_FAILURE; + if (!MS_VALID_EXTENT(map->extent)) { + msSetError(MS_MISCERR, + "Given map extent is invalid. Check that it " + "is in the form: minx, miny, maxx, maxy", + "loadMapInternal()"); + return MS_FAILURE; + } + } break; + case (ANGLE): { + double rotation_angle; + if (getDouble(&(rotation_angle), MS_NUM_CHECK_RANGE, -360, 360) == -1) + return MS_FAILURE; + msMapSetRotation(map, rotation_angle); + } break; + case (FONTSET): + if (getString(&map->fontset.filename) == MS_FAILURE) + return MS_FAILURE; + break; + case (IMAGECOLOR): + if (loadColor(&(map->imagecolor), NULL) != MS_SUCCESS) + return MS_FAILURE; + break; + case (IMAGETYPE): + msFree(map->imagetype); + map->imagetype = getToken(); + break; + case (LATLON): + if (loadProjection(&map->latlon, map) == -1) + return MS_FAILURE; + break; + case (LAYER): + if (msGrowMapLayers(map) == NULL) + return MS_FAILURE; + if (initLayer((GET_LAYER(map, map->numlayers)), map) == -1) + return MS_FAILURE; + if (loadLayer((GET_LAYER(map, map->numlayers)), map) == -1) + return MS_FAILURE; + GET_LAYER(map, map->numlayers)->index = + map->numlayers; /* save the index */ + /* Update the layer order list with the layer's index. */ + map->layerorder[map->numlayers] = map->numlayers; + map->numlayers++; + break; + case (OUTPUTFORMAT): + if (loadOutputFormat(map) == -1) + return MS_FAILURE; + break; + case (LEGEND): + if (loadLegend(&(map->legend), map) == -1) + return MS_FAILURE; + break; + case (MAP): + foundMapToken = MS_TRUE; + break; + case (MAXSIZE): + if (getInteger(&(map->maxsize), MS_NUM_CHECK_GT, 0, -1) == -1) + return MS_FAILURE; + break; + case (NAME): + free(map->name); + map->name = NULL; /* erase default */ + if (getString(&map->name) == MS_FAILURE) + return MS_FAILURE; + break; + case (PROJECTION): + if (loadProjection(&map->projection, map) == -1) + return MS_FAILURE; + break; + case (QUERYMAP): + if (loadQueryMap(&(map->querymap), map) == -1) + return MS_FAILURE; + break; + case (REFERENCE): + if (loadReferenceMap(&(map->reference), map) == -1) + return MS_FAILURE; + break; + case (RESOLUTION): + if (getDouble(&(map->resolution), MS_NUM_CHECK_RANGE, MS_RESOLUTION_MIN, + MS_RESOLUTION_MAX) == -1) + return MS_FAILURE; + break; + case (DEFRESOLUTION): + if (getDouble(&(map->defresolution), MS_NUM_CHECK_RANGE, + MS_RESOLUTION_MIN, MS_RESOLUTION_MAX) == -1) + return MS_FAILURE; + break; + case (SCALE): + case (SCALEDENOM): + if (getDouble(&(map->scaledenom), MS_NUM_CHECK_GTE, 1, -1) == -1) + return MS_FAILURE; + break; + case (SCALEBAR): + if (loadScalebar(&(map->scalebar)) == -1) + return MS_FAILURE; + break; + case (SHAPEPATH): + if (getString(&map->shapepath) == MS_FAILURE) + return MS_FAILURE; + break; + case (SIZE): + if (getInteger(&(map->width), MS_NUM_CHECK_RANGE, 1, map->maxsize) == -1) + return MS_FAILURE; + if (getInteger(&(map->height), MS_NUM_CHECK_RANGE, 1, map->maxsize) == -1) + return MS_FAILURE; + break; + case (STATUS): + if ((map->status = getSymbol(2, MS_ON, MS_OFF)) == -1) + return MS_FAILURE; + break; + case (SYMBOL): + if (msGrowSymbolSet(&(map->symbolset)) == NULL) + return MS_FAILURE; + if ((loadSymbol(map->symbolset.symbol[map->symbolset.numsymbols], + map->mappath) == -1)) { + msFreeSymbol(map->symbolset.symbol[map->symbolset.numsymbols]); + free(map->symbolset.symbol[map->symbolset.numsymbols]); + map->symbolset.symbol[map->symbolset.numsymbols] = NULL; + return MS_FAILURE; + } + map->symbolset.symbol[map->symbolset.numsymbols]->inmapfile = MS_TRUE; + map->symbolset.numsymbols++; + break; + case (SYMBOLSET): + if (getString(&map->symbolset.filename) == MS_FAILURE) + return MS_FAILURE; + break; + case (UNITS): + if ((int)(map->units = + getSymbol(7, MS_INCHES, MS_FEET, MS_MILES, MS_METERS, + MS_KILOMETERS, MS_NAUTICALMILES, MS_DD)) == -1) + return MS_FAILURE; + break; + case (WEB): + if (loadWeb(&(map->web), map) == -1) + return MS_FAILURE; + break; + default: + msSetError(MS_IDENTERR, "Parsing error near (%s):(line %d)", + "msLoadMap()", msyystring_buffer, msyylineno); + return MS_FAILURE; + } + } /* next token */ +} + +static bool msGetCWD(char *szBuffer, size_t nBufferSize, + const char *pszFunctionName) { + if (NULL == getcwd(szBuffer, nBufferSize)) { +#ifndef _WIN32 + if (errno == EACCES) + msSetError(MS_MISCERR, + "getcwd() failed with EACCES: you may need to force the " + "current directory in the mapserver launcher " + "(e.g -d option of spawn-fcgi)", + pszFunctionName); + else if (errno == ENAMETOOLONG) + msSetError(MS_MISCERR, "getcwd() returned a too long path", + pszFunctionName); + else + msSetError(MS_MISCERR, "getcwd() failed with errno code %d", + pszFunctionName, errno); +#else + msSetError(MS_MISCERR, "getcwd() returned a too long path", + pszFunctionName); +#endif + return FALSE; + } + return TRUE; +} + +/* + * Apply any SLD styles referenced in a LAYER's STYLEITEM + */ +static void applyStyleItemToLayer(mapObj *map) { + + // applying SLD can create cloned layers so store the original layer count + int layerCount = map->numlayers; + + for (int i = 0; i < layerCount; i++) { + layerObj *layer = GET_LAYER(map, i); + + if (layer->styleitem && STARTS_WITH_CI(layer->styleitem, "sld://")) { + const char *filename = layer->styleitem + strlen("sld://"); + + if (*filename == '\0') { + msSetErrorWithStatus(MS_IOERR, MS_HTTP_500_INTERNAL_SERVER_ERROR, + "Empty SLD filename: \"%s\".", + "applyLayerDefaultSubstitutions()", + layer->styleitem); + } else { + msSLDApplyFromFile(map, layer, filename); + } + } + } +} + +/* +** Sets up string-based mapfile loading and calls loadMapInternal to do the +*work. +*/ +mapObj *msLoadMapFromString(char *buffer, char *new_mappath, + const configObj *config) { + mapObj *map; + struct mstimeval starttime = {0}, endtime = {0}; + char szPath[MS_MAXPATHLEN], szCWDPath[MS_MAXPATHLEN]; + char *mappath = NULL; + int debuglevel; + + debuglevel = (int)msGetGlobalDebugLevel(); + + if (debuglevel >= MS_DEBUGLEVEL_TUNING) { + /* In debug mode, track time spent loading/parsing mapfile. */ + msGettimeofday(&starttime, NULL); + } + + if (!buffer) { + msSetError(MS_MISCERR, "No buffer to load.", "msLoadMapFromString()"); + return (NULL); + } + + /* + ** Allocate mapObj structure + */ + map = (mapObj *)calloc(1, sizeof(mapObj)); + MS_CHECK_ALLOC(map, sizeof(mapObj), NULL); + + if (initMap(map) == -1) { /* initialize this map */ + msFreeMap(map); + return (NULL); + } + + map->config = config; // create a read-only reference + + msAcquireLock(TLOCK_PARSER); /* might need to move this lock a bit higher, yup + (bug 2108) */ + + msyystate = MS_TOKENIZE_STRING; + msyystring = buffer; + msyylex(); /* sets things up, but doesn't process any tokens */ + + msyylineno = 1; /* start at line 1 (do lines mean anything here?) */ + + /* If new_mappath is provided then use it, otherwise use the CWD */ + if (!msGetCWD(szCWDPath, MS_MAXPATHLEN, "msLoadMapFromString()")) { + msFreeMap(map); + msReleaseLock(TLOCK_PARSER); + return (NULL); + } + if (new_mappath) { + mappath = msStrdup(new_mappath); + map->mappath = msStrdup(msBuildPath(szPath, szCWDPath, mappath)); + } else + map->mappath = msStrdup(szCWDPath); + + msyybasepath = map->mappath; /* for INCLUDEs */ + + if (loadMapInternal(map) != MS_SUCCESS) { + msFreeMap(map); + msReleaseLock(TLOCK_PARSER); + if (mappath != NULL) + free(mappath); + return NULL; + } + + if (mappath != NULL) + free(mappath); + msyylex_destroy(); + + msReleaseLock(TLOCK_PARSER); + + applyStyleItemToLayer(map); + + if (debuglevel >= MS_DEBUGLEVEL_TUNING) { + /* In debug mode, report time spent loading/parsing mapfile. */ + msGettimeofday(&endtime, NULL); + msDebug("msLoadMapFromString(): %.3fs\n", + (endtime.tv_sec + endtime.tv_usec / 1.0e6) - + (starttime.tv_sec + starttime.tv_usec / 1.0e6)); + } + + if (resolveSymbolNames(map) == MS_FAILURE) + return NULL; + + return map; +} + +/* +** Sets up file-based mapfile loading and calls loadMapInternal to do the work. +*/ +mapObj *msLoadMap(const char *filename, const char *new_mappath, + const configObj *config) { + mapObj *map; + struct mstimeval starttime = {0}, endtime = {0}; + char szPath[MS_MAXPATHLEN], szCWDPath[MS_MAXPATHLEN]; + int debuglevel; + + debuglevel = (int)msGetGlobalDebugLevel(); + + if (debuglevel >= MS_DEBUGLEVEL_TUNING) { + /* In debug mode, track time spent loading/parsing mapfile. */ + msGettimeofday(&starttime, NULL); + } + + if (!filename) { + msSetError(MS_MISCERR, "Filename is undefined.", "msLoadMap()"); + return (NULL); + } + + const char *ms_mapfile_pattern = + CPLGetConfigOption("MS_MAPFILE_PATTERN", MS_DEFAULT_MAPFILE_PATTERN); + if (msEvalRegex(ms_mapfile_pattern, filename) != MS_TRUE) { + msSetError(MS_REGEXERR, "Filename validation failed.", "msLoadMap()"); + return (NULL); + } + + /* + ** Allocate mapObj structure + */ + map = (mapObj *)calloc(1, sizeof(mapObj)); + MS_CHECK_ALLOC(map, sizeof(mapObj), NULL); + + if (initMap(map) == -1) { /* initialize this map */ + msFreeMap(map); + return (NULL); + } + + map->config = config; // create a read-only reference + + msAcquireLock(TLOCK_PARSER); /* Steve: might need to move this lock a bit + higher; Umberto: done */ + +#ifdef USE_XMLMAPFILE + /* If the mapfile is an xml mapfile, transform it */ + const char *ms_xmlmapfile_xslt = + CPLGetConfigOption("MS_XMLMAPFILE_XSLT", NULL); + if (ms_xmlmapfile_xslt && + (msEvalRegex(MS_DEFAULT_XMLMAPFILE_PATTERN, filename) == MS_TRUE)) { + + msyyin = tmpfile(); + if (msyyin == NULL) { + msSetErrorWithStatus(MS_IOERR, MS_HTTP_500_INTERNAL_SERVER_ERROR, + "tmpfile() failed to create temporary file", + "msLoadMap()"); + msReleaseLock(TLOCK_PARSER); + msFreeMap(map); + return NULL; + } + + if (msTransformXmlMapfile(ms_xmlmapfile_xslt, filename, msyyin) != + MS_SUCCESS) { + fclose(msyyin); + msFreeMap(map); + return NULL; + } + fseek(msyyin, 0, SEEK_SET); + } else { +#endif + if ((msyyin = fopen(filename, "r")) == NULL) { + msSetErrorWithStatus(MS_IOERR, MS_HTTP_500_INTERNAL_SERVER_ERROR, "(%s)", + "msLoadMap()", filename); + msReleaseLock(TLOCK_PARSER); + msFreeMap(map); + return NULL; + } +#ifdef USE_XMLMAPFILE + } +#endif + + msyystate = MS_TOKENIZE_FILE; + msyylex(); /* sets things up, but doesn't process any tokens */ + + msyyrestart(msyyin); /* start at line beginning, line 1 */ + msyylineno = 1; + + /* If new_mappath is provided then use it, otherwise use the location */ + /* of the mapfile as the default path */ + if (!msGetCWD(szCWDPath, MS_MAXPATHLEN, "msLoadMap()")) { + msReleaseLock(TLOCK_PARSER); + msFreeMap(map); + return NULL; + } + + if (new_mappath) + map->mappath = msStrdup(msBuildPath(szPath, szCWDPath, new_mappath)); + else { + char *path = msGetPath(filename); + map->mappath = msStrdup(msBuildPath(szPath, szCWDPath, path)); + free(path); + } + + msyybasepath = map->mappath; /* for INCLUDEs */ + + if (loadMapInternal(map) != MS_SUCCESS) { + msFreeMap(map); + if (msyyin) { + msyycleanup_includes(); + fclose(msyyin); + msyyin = NULL; + } + msReleaseLock(TLOCK_PARSER); + return NULL; + } + msReleaseLock(TLOCK_PARSER); + + applyStyleItemToLayer(map); + + if (debuglevel >= MS_DEBUGLEVEL_TUNING) { + /* In debug mode, report time spent loading/parsing mapfile. */ + msGettimeofday(&endtime, NULL); + msDebug("msLoadMap(): %.3fs\n", + (endtime.tv_sec + endtime.tv_usec / 1.0e6) - + (starttime.tv_sec + starttime.tv_usec / 1.0e6)); + } + + return map; +} + +static void hashTableSubstituteString(hashTableObj *hash, const char *from, + const char *to) { + const char *key, *val; + char *new_val; + key = msFirstKeyFromHashTable(hash); + while (key != NULL) { + val = msLookupHashTable(hash, key); + if (strcasestr(val, from)) { + new_val = msCaseReplaceSubstring(msStrdup(val), from, to); + msInsertHashTable(hash, key, new_val); + msFree(new_val); + } + key = msNextKeyFromHashTable(hash, key); + } +} + +static void classSubstituteString(classObj *class, const char *from, + const char *to) { + if (class->expression.string) + class->expression.string = + msCaseReplaceSubstring(class->expression.string, from, to); + if (class->text.string) + class->text.string = msCaseReplaceSubstring(class->text.string, from, to); + if (class->title) + class->title = msCaseReplaceSubstring(class->title, from, to); +} + +static void layerSubstituteString(layerObj *layer, const char *from, + const char *to) { + int c; + if (layer->data) + layer->data = msCaseReplaceSubstring(layer->data, from, to); + if (layer->tileindex) + layer->tileindex = msCaseReplaceSubstring(layer->tileindex, from, to); + if (layer->connection) + layer->connection = msCaseReplaceSubstring(layer->connection, from, to); + if (layer->filter.string) + layer->filter.string = + msCaseReplaceSubstring(layer->filter.string, from, to); + if (layer->mask) + layer->mask = msCaseReplaceSubstring(layer->mask, from, to); // new for 8.0 + + /* The bindvalues are most useful when able to substitute values from the URL + */ + hashTableSubstituteString(&layer->bindvals, from, to); + hashTableSubstituteString(&layer->metadata, from, to); + msLayerSubstituteProcessing(layer, from, to); + for (c = 0; c < layer->numclasses; c++) { + classSubstituteString(layer->class[c], from, to); + } +} + +static void mapSubstituteString(mapObj *map, const char *from, const char *to) { + int l; + for (l = 0; l < map->numlayers; l++) { + layerSubstituteString(GET_LAYER(map, l), from, to); + } + + /* output formats (#3751) */ + for (l = 0; l < map->numoutputformats; l++) { + int o; + for (o = 0; o < map->outputformatlist[l]->numformatoptions; o++) { + map->outputformatlist[l]->formatoptions[o] = msCaseReplaceSubstring( + map->outputformatlist[l]->formatoptions[o], from, to); + } + } + + hashTableSubstituteString(&map->web.metadata, from, to); + if (map->web.template) + map->web.template = msCaseReplaceSubstring(map->web.template, from, to); +} + +static void applyOutputFormatDefaultSubstitutions(outputFormatObj *format, + const char *option, + hashTableObj *table) { + const char *filename; + + filename = msGetOutputFormatOption(format, option, NULL); + if (filename && strlen(filename) > 0) { + char *tmpfilename = msStrdup(filename); + const char *default_key = msFirstKeyFromHashTable(table); + while (default_key) { + if (!strncasecmp(default_key, "default_", 8)) { + char *new_filename = NULL; + size_t buffer_size = (strlen(default_key) - 5); + char *tag = (char *)msSmallMalloc(buffer_size); + snprintf(tag, buffer_size, "%%%s%%", &(default_key[8])); + + new_filename = msStrdup(tmpfilename); + new_filename = msCaseReplaceSubstring( + new_filename, tag, msLookupHashTable(table, default_key)); + free(tag); + + msSetOutputFormatOption(format, option, new_filename); + free(new_filename); + } + default_key = msNextKeyFromHashTable(table, default_key); + } + msFree(tmpfilename); + } + return; +} + +static void applyClassDefaultSubstitutions(classObj *class, + hashTableObj *table) { + const char *default_key = msFirstKeyFromHashTable(table); + while (default_key) { + if (!strncasecmp(default_key, "default_", 8)) { + size_t buffer_size = (strlen(default_key) - 5); + char *tag = (char *)msSmallMalloc(buffer_size); + snprintf(tag, buffer_size, "%%%s%%", &(default_key[8])); + + classSubstituteString(class, tag, msLookupHashTable(table, default_key)); + free(tag); + } + default_key = msNextKeyFromHashTable(table, default_key); + } + return; +} + +static void applyLayerDefaultSubstitutions(layerObj *layer, + hashTableObj *table) { + int i; + const char *default_key = msFirstKeyFromHashTable(table); + while (default_key) { + if (!strncasecmp(default_key, "default_", 8)) { + size_t buffer_size = (strlen(default_key) - 5); + const char *to = msLookupHashTable(table, default_key); + char *tag = (char *)msSmallMalloc(buffer_size); + snprintf(tag, buffer_size, "%%%s%%", &(default_key[8])); + + for (i = 0; i < layer->numclasses; i++) { + classSubstituteString(layer->class[i], tag, to); + } + layerSubstituteString(layer, tag, to); + free(tag); + } + default_key = msNextKeyFromHashTable(table, default_key); + } + + return; +} + +static void applyHashTableDefaultSubstitutions(hashTableObj *hashTab, + hashTableObj *table) { + const char *default_key = msFirstKeyFromHashTable(table); + while (default_key) { + if (!strncasecmp(default_key, "default_", 8)) { + size_t buffer_size = (strlen(default_key) - 5); + const char *to = msLookupHashTable(table, default_key); + char *tag = (char *)msSmallMalloc(buffer_size); + snprintf(tag, buffer_size, "%%%s%%", &(default_key[8])); + + hashTableSubstituteString(hashTab, tag, to); + free(tag); + } + default_key = msNextKeyFromHashTable(table, default_key); + } + return; +} + +/* +** Loop through layer metadata for keys that have a default_%key% pattern to +*replace +** remaining %key% entries by their default value. +*/ +void msApplyDefaultSubstitutions(mapObj *map) { + int i, j; + + /* output formats (#3751) */ + for (i = 0; i < map->numoutputformats; i++) { + applyOutputFormatDefaultSubstitutions(map->outputformatlist[i], "filename", + &(map->web.validation)); + applyOutputFormatDefaultSubstitutions(map->outputformatlist[i], "JSONP", + &(map->web.validation)); + } + + for (i = 0; i < map->numlayers; i++) { + layerObj *layer = GET_LAYER(map, i); + + for (j = 0; j < layer->numclasses; + j++) { /* class settings take precedence... */ + classObj *class = GET_CLASS(map, i, j); + applyClassDefaultSubstitutions(class, &(class->validation)); + } + + applyLayerDefaultSubstitutions( + layer, &(layer->validation)); /* ...then layer settings... */ + applyLayerDefaultSubstitutions( + layer, &(map->web.validation)); /* ...and finally web settings */ + } + applyHashTableDefaultSubstitutions(&map->web.metadata, + &(map->web.validation)); +} + +char *_get_param_value(const char *key, char **names, char **values, + int npairs) { + if (npairs <= 0) + return NULL; // bail, no point searching + + if (getenv(key)) { /* environment override */ + return getenv(key); + } + while (npairs) { + npairs--; + if (strcasecmp(key, names[npairs]) == 0) { + return values[npairs]; + } + } + return NULL; +} + +void msApplySubstitutions(mapObj *map, char **names, char **values, + int npairs) { + int l; + const char *key, *value, *validation; + char *tag; + for (l = 0; l < map->numlayers; l++) { + int c; + layerObj *lp = GET_LAYER(map, l); + for (c = 0; c < lp->numclasses; c++) { + classObj *cp = lp->class[c]; + key = NULL; + while ((key = msNextKeyFromHashTable(&cp->validation, key))) { + value = _get_param_value(key, names, values, npairs); + if (!value) + continue; /*parameter was not in url*/ + validation = msLookupHashTable(&cp->validation, key); + if (msEvalRegex(validation, value)) { + /* we've found a substitution and it validates correctly, now let's + * apply it */ + tag = msSmallMalloc(strlen(key) + 3); + sprintf(tag, "%%%s%%", key); + classSubstituteString(cp, tag, value); + free(tag); + } else { + msSetError(MS_REGEXERR, "Parameter pattern validation failed.", + "msApplySubstitutions()"); + if (map->debug || lp->debug) { + msDebug("layer (%s), class %d: failed to validate (%s=%s) for " + "regex (%s)\n", + lp->name, c, key, value, validation); + } + } + } + } + key = NULL; + while ((key = msNextKeyFromHashTable(&lp->validation, key))) { + value = _get_param_value(key, names, values, npairs); + if (!value) + continue; /*parameter was not in url*/ + validation = msLookupHashTable(&lp->validation, key); + if (msEvalRegex(validation, value)) { + /* we've found a substitution and it validates correctly, now let's + * apply it */ + tag = msSmallMalloc(strlen(key) + 3); + sprintf(tag, "%%%s%%", key); + layerSubstituteString(lp, tag, value); + free(tag); + } else { + msSetError(MS_REGEXERR, "Parameter pattern validation failed.", + "msApplySubstitutions()"); + if (map->debug || lp->debug) { + msDebug("layer (%s): failed to validate (%s=%s) for regex (%s)\n", + lp->name, key, value, validation); + } + } + } + } + key = NULL; + while ((key = msNextKeyFromHashTable(&map->web.validation, key))) { + value = _get_param_value(key, names, values, npairs); + if (!value) + continue; /*parameter was not in url*/ + validation = msLookupHashTable(&map->web.validation, key); + if (msEvalRegex(validation, value)) { + /* we've found a substitution and it validates correctly, now let's apply + * it */ + tag = msSmallMalloc(strlen(key) + 3); + sprintf(tag, "%%%s%%", key); + mapSubstituteString(map, tag, value); + free(tag); + } else { + msSetError(MS_REGEXERR, "Parameter pattern validation failed.", + "msApplySubstitutions()"); + if (map->debug) { + msDebug("failed to validate (%s=%s) for regex (%s)\n", key, value, + validation); + } + } + } +} + +/* +** Returns an array with one entry per mapfile token. Useful to manipulate +** mapfiles in MapScript. +** +** The returned array should be freed using msFreeCharArray(). +*/ +static char **tokenizeMapInternal(char *filename, int *ret_numtokens) { + char **tokens = NULL; + int numtokens = 0, numtokens_allocated = 0; + size_t buffer_size = 0; + + *ret_numtokens = 0; + + if (!filename) { + msSetError(MS_MISCERR, "Filename is undefined.", "msTokenizeMap()"); + return NULL; + } + + /* + ** Check map filename to make sure it's legal + */ + const char *ms_mapfile_pattern = + CPLGetConfigOption("MS_MAPFILE_PATTERN", MS_DEFAULT_MAPFILE_PATTERN); + if (msEvalRegex(ms_mapfile_pattern, filename) != MS_TRUE) { + msSetError(MS_REGEXERR, "Filename validation failed.", "msTokenizeMap()"); + return (NULL); + } + + if ((msyyin = fopen(filename, "r")) == NULL) { + msSetErrorWithStatus(MS_IOERR, MS_HTTP_500_INTERNAL_SERVER_ERROR, "(%s)", + "msTokenizeMap()", filename); + return NULL; + } + + msyystate = MS_TOKENIZE_FILE; /* restore lexer state to INITIAL, and do return + comments */ + msyylex(); + msyyreturncomments = 1; /* want all tokens, including comments */ + + msyyrestart(msyyin); /* start at line beginning, line 1 */ + msyylineno = 1; + + numtokens = 0; + numtokens_allocated = 256; + tokens = (char **)malloc(numtokens_allocated * sizeof(char *)); + if (tokens == NULL) { + msSetError(MS_MEMERR, NULL, "msTokenizeMap()"); + fclose(msyyin); + return NULL; + } + + for (;;) { + + if (numtokens_allocated <= numtokens) { + numtokens_allocated *= + 2; /* double size of the array every time we reach the limit */ + char **tokensNew = + (char **)realloc(tokens, numtokens_allocated * sizeof(char *)); + if (tokensNew == NULL) { + msSetError(MS_MEMERR, "Realloc() error.", "msTokenizeMap()"); + fclose(msyyin); + for (int i = 0; i < numtokens; i++) + msFree(tokens[i]); + msFree(tokens); + return NULL; + } + tokens = tokensNew; + } + + switch (msyylex()) { + case (EOF): /* This is the normal way out... cleanup and exit */ + fclose(msyyin); + *ret_numtokens = numtokens; + return (tokens); + break; + case (MS_STRING): + buffer_size = strlen(msyystring_buffer) + 2 + 1; + tokens[numtokens] = (char *)msSmallMalloc(buffer_size); + snprintf(tokens[numtokens], buffer_size, "\"%s\"", msyystring_buffer); + break; + case (MS_EXPRESSION): + buffer_size = strlen(msyystring_buffer) + 2 + 1; + tokens[numtokens] = (char *)msSmallMalloc(buffer_size); + snprintf(tokens[numtokens], buffer_size, "(%s)", msyystring_buffer); + break; + case (MS_REGEX): + buffer_size = strlen(msyystring_buffer) + 2 + 1; + tokens[numtokens] = (char *)msSmallMalloc(buffer_size); + snprintf(tokens[numtokens], buffer_size, "/%s/", msyystring_buffer); + break; + default: + tokens[numtokens] = msStrdup(msyystring_buffer); + break; + } + + if (tokens[numtokens] == NULL) { + int i; + msSetError(MS_MEMERR, NULL, "msTokenizeMap()"); + fclose(msyyin); + for (i = 0; i < numtokens; i++) + msFree(tokens[i]); + msFree(tokens); + return NULL; + } + + numtokens++; + } + + return NULL; /* should never get here */ +} + +/* +** Wraps tokenizeMapInternal +*/ +char **msTokenizeMap(char *filename, int *numtokens) { + char **tokens; + + msAcquireLock(TLOCK_PARSER); + tokens = tokenizeMapInternal(filename, numtokens); + msReleaseLock(TLOCK_PARSER); + + return tokens; +} + +void msCloseConnections(mapObj *map) { + int i; + layerObj *lp; + + for (i = 0; i < map->numlayers; i++) { + lp = (GET_LAYER(map, i)); + + /* If the vtable is null, then the layer is never accessed or used -> skip + * it + */ + if (lp->vtable) { + lp->vtable->LayerCloseConnection(lp); + } + } +} + +void initResultCache(resultCacheObj *resultcache) { + if (resultcache) { + resultcache->results = NULL; + resultcache->numresults = 0; + resultcache->hasnext = MS_UNKNOWN; + resultcache->cachesize = 0; + resultcache->bounds.minx = resultcache->bounds.miny = + resultcache->bounds.maxx = resultcache->bounds.maxy = -1; + resultcache->previousBounds = resultcache->bounds; + } +} + +void cleanupResultCache(resultCacheObj *resultcache) { + if (resultcache) { + if (resultcache->results) { + int i; + for (i = 0; i < resultcache->numresults; i++) { + if (resultcache->results[i].shape) { + msFreeShape(resultcache->results[i].shape); + msFree(resultcache->results[i].shape); + } + } + free(resultcache->results); + } + resultcache->results = NULL; + initResultCache(resultcache); + } +} + +static int resolveSymbolNames(mapObj *map) { + int i, j; + + /* step through layers and classes to resolve symbol names */ + for (i = 0; i < map->numlayers; i++) { + for (j = 0; j < GET_LAYER(map, i)->numclasses; j++) { + if (classResolveSymbolNames(GET_LAYER(map, i)->class[j]) != MS_SUCCESS) + return MS_FAILURE; + } + } + + return MS_SUCCESS; +} diff --git a/mapfile.dtd b/src/mapfile.dtd similarity index 99% rename from mapfile.dtd rename to src/mapfile.dtd index 1535dfd8d6..1066f1b41f 100644 --- a/mapfile.dtd +++ b/src/mapfile.dtd @@ -130,7 +130,6 @@ NAME NMTOKEN #REQUIRED STATUS (ON|OFF|DEFAULT) "OFF" TYPE (ANNOTATION|POINT|LINE|POLYGON|POLYLINE|QUERY|RASTER) #REQUIRED - DUMP (TRUE|FALSE) "FALSE" > @@ -241,4 +240,4 @@ - \ No newline at end of file + diff --git a/mapfile.h b/src/mapfile.h similarity index 90% rename from mapfile.h rename to src/mapfile.h index 72c27d2323..f6ed8abbbb 100644 --- a/mapfile.h +++ b/src/mapfile.h @@ -27,12 +27,19 @@ * DEALINGS IN THE SOFTWARE. ****************************************************************************/ - #ifndef MAPFILE_H #define MAPFILE_H -enum MS_LEXER_STATES {MS_TOKENIZE_DEFAULT=0, MS_TOKENIZE_FILE, MS_TOKENIZE_STRING, MS_TOKENIZE_EXPRESSION, MS_TOKENIZE_URL_VARIABLE, MS_TOKENIZE_URL_STRING, MS_TOKENIZE_VALUE, MS_TOKENIZE_NAME}; -enum MS_TOKEN_SOURCES {MS_FILE_TOKENS=0, MS_STRING_TOKENS, MS_URL_TOKENS}; +enum MS_LEXER_STATES { + MS_TOKENIZE_DEFAULT = 0, + MS_TOKENIZE_FILE, + MS_TOKENIZE_STRING, + MS_TOKENIZE_EXPRESSION, + MS_TOKENIZE_VALUE, + MS_TOKENIZE_NAME, + MS_TOKENIZE_CONFIG +}; +enum MS_TOKEN_SOURCES { MS_FILE_TOKENS = 0, MS_STRING_TOKENS }; /* ** Keyword definitions for the mapfiles and symbolfiles (used by lexer) @@ -81,7 +88,6 @@ enum MS_TOKEN_SOURCES {MS_FILE_TOKENS=0, MS_STRING_TOKENS, MS_URL_TOKENS}; #define LOG 1043 #define MAP 1044 - #define MAXFEATURES 1047 #define MAXSCALE 1048 #define MAXSIZE 1049 @@ -136,6 +142,8 @@ enum MS_TOKEN_SOURCES {MS_FILE_TOKENS=0, MS_STRING_TOKENS, MS_URL_TOKENS}; #define FORCE 1098 #define TOLERANCEUNITS 1099 +#define IDENTIFY 1103 +#define CLASSAUTO 1104 #define CHARACTER 1100 #define CONNECTION 1101 @@ -143,14 +151,6 @@ enum MS_TOKEN_SOURCES {MS_FILE_TOKENS=0, MS_STRING_TOKENS, MS_URL_TOKENS}; #define SYMBOLSET 1105 -#define OVERLAYBACKGROUNDCOLOR 1106 -#define OVERLAYCOLOR 1107 -#define OVERLAYMAXSIZE 1108 -#define OVERLAYMINSIZE 1109 -#define OVERLAYOUTLINECOLOR 1110 -#define OVERLAYSIZE 1111 -#define OVERLAYSYMBOL 1112 - #define IMAGETYPE 1113 #define IMAGEQUALITY 1114 @@ -171,7 +171,7 @@ enum MS_TOKEN_SOURCES {MS_FILE_TOKENS=0, MS_STRING_TOKENS, MS_URL_TOKENS}; #define STYLEITEM 1124 -#define DUMP 1125 +#define FALLBACK 1125 #define TITLE 1126 @@ -200,14 +200,10 @@ enum MS_TOKEN_SOURCES {MS_FILE_TOKENS=0, MS_STRING_TOKENS, MS_URL_TOKENS}; #define MAXINTERVAL 1144 #define MININTERVAL 1145 #define MAXSUBDIVIDE 1146 -#define MINSUBDIVIDE 1147 -#define LABELFORMAT 1148 +#define MINSUBDIVIDE 1147 +#define LABELFORMAT 1148 -#define DATAPATTERN 1150 -#define FILEPATTERN 1151 -#define TEMPLATEPATTERN 1152 - -#define PROCESSING 1153 +#define PROCESSING 1153 /* The DEBUG macro is also used to request debugging output. Redefine for keyword purposes. */ @@ -269,7 +265,6 @@ enum MS_TOKEN_SOURCES {MS_FILE_TOKENS=0, MS_STRING_TOKENS, MS_URL_TOKENS}; /* rfc40 label wrapping */ #define MAXLENGTH 1210 -#define MINLENGTH 1211 /* rfc44 URL configuration support */ #define VALIDATION 1212 @@ -323,7 +318,6 @@ enum MS_TOKEN_SOURCES {MS_FILE_TOKENS=0, MS_STRING_TOKENS, MS_URL_TOKENS}; #define COMPOP 1291 #define COMPFILTER 1292 - #define BOM 1300 /* rfc59 bindvals objects */ diff --git a/src/mapflatgeobuf.c b/src/mapflatgeobuf.c new file mode 100644 index 0000000000..3b73df1de5 --- /dev/null +++ b/src/mapflatgeobuf.c @@ -0,0 +1,368 @@ +/****************************************************************************** + * $Id$ + * + * Project: MapServer + * Purpose: Implements support for FlatGeobuf access. + * Authors: Björn Harrtell + * + ****************************************************************************** + * Copyright (c) 1996-2005 Regents of the University of Minnesota. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + ****************************************************************************/ + +#define NEED_IGNORE_RET_VAL + +#include +#include +#include "mapserver.h" +#include "mapows.h" + +#include "flatgeobuf/flatgeobuf_c.h" + +#include +#include + +static void msFGBPassThroughFieldDefinitions(layerObj *layer, + flatgeobuf_ctx *ctx) { + for (int i = 0; i < ctx->columns_len; i++) { + char item[255]; + char gml_width[32], gml_precision[32]; + const char *gml_type = NULL; + + const flatgeobuf_column *column = &(ctx->columns[i]); + strncpy(item, column->name, 255 - 1); + + gml_width[0] = '\0'; + gml_precision[0] = '\0'; + + switch (column->type) { + case flatgeobuf_column_type_byte: + case flatgeobuf_column_type_ubyte: + case flatgeobuf_column_type_bool: + case flatgeobuf_column_type_short: + case flatgeobuf_column_type_ushort: + case flatgeobuf_column_type_int: + case flatgeobuf_column_type_uint: + gml_type = "Integer"; + sprintf(gml_width, "%d", 4); + break; + case flatgeobuf_column_type_long: + case flatgeobuf_column_type_ulong: + gml_type = "Long"; + sprintf(gml_width, "%d", 8); + break; + case flatgeobuf_column_type_float: + case flatgeobuf_column_type_double: + gml_type = "Real"; + sprintf(gml_width, "%d", 8); + sprintf(gml_precision, "%d", 15); + break; + case flatgeobuf_column_type_string: + case flatgeobuf_column_type_json: + case flatgeobuf_column_type_datetime: + default: + gml_type = "Character"; + sprintf(gml_width, "%d", 4096); + break; + } + + msUpdateGMLFieldMetadata(layer, item, gml_type, gml_width, gml_precision, + 0); + } +} + +void msFlatGeobufLayerFreeItemInfo(layerObj *layer) { + if (layer->iteminfo) { + free(layer->iteminfo); + layer->iteminfo = NULL; + } +} + +int msFlatGeobufLayerInitItemInfo(layerObj *layer) { + if (!layer->layerinfo) { + msSetError(MS_FGBERR, "FlatGeobuf layer has not been opened.", + "msFlatGeobufLayerInitItemInfo()"); + return MS_FAILURE; + } + + msFlatGeobufLayerFreeItemInfo(layer); + + flatgeobuf_ctx *ctx; + ctx = layer->layerinfo; + if (!ctx) + return MS_FAILURE; + + for (int j = 0; j < ctx->columns_len; j++) { + ctx->columns[j].itemindex = -1; + for (int i = 0; i < layer->numitems; i++) { + if (strcasecmp(layer->items[i], ctx->columns[j].name) == 0) { + ctx->columns[j].itemindex = i; + break; + } + } + } + + return MS_SUCCESS; +} + +int msFlatGeobufLayerOpen(layerObj *layer) { + char szPath[MS_MAXPATHLEN]; + int ret; + + if (layer->layerinfo) + return MS_SUCCESS; + + if (msCheckParentPointer(layer->map, "map") == MS_FAILURE) + return MS_FAILURE; + + flatgeobuf_ctx *ctx = flatgeobuf_init_ctx(); + layer->layerinfo = ctx; + + ctx->file = + VSIFOpenL(msBuildPath(szPath, layer->map->mappath, layer->data), "rb"); + if (!ctx->file) + ctx->file = VSIFOpenL(msBuildPath3(szPath, layer->map->mappath, + layer->map->shapepath, layer->data), + "rb"); + if (!ctx->file) { + layer->layerinfo = NULL; + flatgeobuf_free_ctx(ctx); + return MS_FAILURE; + } + + ret = flatgeobuf_check_magicbytes(ctx); + if (ret == -1) { + layer->layerinfo = NULL; + flatgeobuf_free_ctx(ctx); + return MS_FAILURE; + } + + ret = flatgeobuf_decode_header(ctx); + if (ret == -1) { + layer->layerinfo = NULL; + flatgeobuf_free_ctx(ctx); + return MS_FAILURE; + } + + if (layer->projection.numargs > 0 && + EQUAL(layer->projection.args[0], "auto")) { + OGRSpatialReferenceH hSRS = OSRNewSpatialReference(NULL); + char *pszWKT = NULL; + if (ctx->srid > 0) { + if (OSRImportFromEPSG(hSRS, ctx->srid) != OGRERR_NONE) { + OSRDestroySpatialReference(hSRS); + flatgeobuf_free_ctx(ctx); + return MS_FAILURE; + } + if (OSRExportToWkt(hSRS, &pszWKT) != OGRERR_NONE) { + OSRDestroySpatialReference(hSRS); + flatgeobuf_free_ctx(ctx); + return MS_FAILURE; + } + } else if (ctx->wkt == NULL) { + OSRDestroySpatialReference(hSRS); + return MS_SUCCESS; + } + int bOK = MS_FALSE; + if (msOGCWKT2ProjectionObj(ctx->wkt ? ctx->wkt : pszWKT, + &(layer->projection), + layer->debug) == MS_SUCCESS) + bOK = MS_TRUE; + CPLFree(pszWKT); + OSRDestroySpatialReference(hSRS); + if (bOK != MS_TRUE) + if (layer->debug || layer->map->debug) + msDebug("Unable to get SRS from FlatGeobuf '%s' for layer '%s'.\n", + szPath, layer->name); + } + + return MS_SUCCESS; +} + +int msFlatGeobufLayerIsOpen(layerObj *layer) { + if (layer->layerinfo) + return MS_TRUE; + else + return MS_FALSE; +} + +int msFlatGeobufLayerWhichShapes(layerObj *layer, rectObj rect, int isQuery) { + (void)isQuery; + flatgeobuf_ctx *ctx; + ctx = layer->layerinfo; + if (!ctx) + return MS_FAILURE; + + if (!ctx->has_extent || !ctx->index_node_size) + return MS_SUCCESS; + + if (msRectOverlap(&ctx->bounds, &rect) != MS_TRUE) + return MS_DONE; + + if (msRectContained(&ctx->bounds, &rect) == MS_FALSE && + ctx->index_node_size > 0) { + flatgeobuf_index_search(ctx, &rect); + if (ctx->search_result_len == 0) + return MS_DONE; + } else { + flatgeobuf_index_skip(ctx); + } + + return MS_SUCCESS; +} + +int msFlatGeobufLayerNextShape(layerObj *layer, shapeObj *shape) { + flatgeobuf_ctx *ctx; + ctx = layer->layerinfo; + if (!ctx) + return MS_FAILURE; + + do { + if (ctx->search_result) { + if (ctx->search_index >= ctx->search_result_len) + return MS_DONE; + flatgeobuf_search_item item = ctx->search_result[ctx->search_index]; + if (VSIFSeekL(ctx->file, ctx->feature_offset + item.offset, SEEK_SET) == + -1) { + msSetError(MS_FGBERR, "Unable to seek in file", + "msFlatGeobufLayerNextShape"); + return MS_FAILURE; + } + ctx->offset = ctx->feature_offset + item.offset; + ctx->search_index++; + ctx->feature_index = item.index; + } + int ret = flatgeobuf_decode_feature(ctx, layer, shape); + if (ret == -1) + return MS_FAILURE; + shape->index = ctx->feature_index; + if (!ctx->search_result) + ctx->feature_index++; + if (ctx->done) + return MS_DONE; + if (ctx->is_null_geom) { + msFreeCharArray(shape->values, shape->numvalues); + shape->values = NULL; + } + } while (ctx->is_null_geom); + + return MS_SUCCESS; +} + +int msFlatGeobufLayerGetShape(layerObj *layer, shapeObj *shape, + resultObj *record) { + + (void)shape; + (void)record; + flatgeobuf_ctx *ctx; + ctx = layer->layerinfo; + if (!ctx) + return MS_FAILURE; + long i = record->shapeindex; + if (i < 0 || (uint64_t)i >= ctx->features_count) { + msSetError(MS_MISCERR, "Invalid feature id", "msFlatGeobufLayerGetShape"); + return MS_FAILURE; + } + uint64_t offset; + flatgeobuf_read_feature_offset(ctx, i, &offset); + if (VSIFSeekL(ctx->file, ctx->feature_offset + offset, SEEK_SET) == -1) { + msSetError(MS_FGBERR, "Unable to seek in file", + "msFlatGeobufLayerGetShape"); + return MS_FAILURE; + } + int ret = flatgeobuf_decode_feature(ctx, layer, shape); + if (ret == -1) + return MS_FAILURE; + return MS_SUCCESS; +} + +int msFlatGeobufLayerClose(layerObj *layer) { + flatgeobuf_ctx *ctx; + ctx = layer->layerinfo; + if (!ctx) + return MS_SUCCESS; + VSIFCloseL(ctx->file); + flatgeobuf_free_ctx(ctx); + layer->layerinfo = NULL; + return MS_SUCCESS; +} + +int msFlatGeobufLayerGetItems(layerObj *layer) { + const char *value; + flatgeobuf_ctx *ctx; + ctx = layer->layerinfo; + if (!ctx) + return MS_FAILURE; + layer->numitems = ctx->columns_len; + + char **items = (char **)malloc(sizeof(char *) * ctx->columns_len); + for (int i = 0; i < ctx->columns_len; i++) + items[i] = msStrdup(ctx->columns[i].name); + layer->items = items; + + if ((value = msOWSLookupMetadata(&(layer->metadata), "G", "types")) != NULL && + strcasecmp(value, "auto") == 0) + msFGBPassThroughFieldDefinitions(layer, ctx); + + return msLayerInitItemInfo(layer); +} + +int msFlatGeobufLayerGetExtent(layerObj *layer, rectObj *extent) { + flatgeobuf_ctx *ctx; + ctx = layer->layerinfo; + extent->minx = ctx->xmin; + extent->miny = ctx->ymin; + extent->maxx = ctx->xmax; + extent->maxy = ctx->ymax; + return MS_SUCCESS; +} + +int msFlatGeobufLayerSupportsCommonFilters(layerObj *layer) { + (void)layer; + return MS_TRUE; +} + +int msFlatGeobufLayerInitializeVirtualTable(layerObj *layer) { + assert(layer != NULL); + assert(layer->vtable != NULL); + + layer->vtable->LayerSupportsCommonFilters = + msFlatGeobufLayerSupportsCommonFilters; + layer->vtable->LayerInitItemInfo = msFlatGeobufLayerInitItemInfo; + layer->vtable->LayerFreeItemInfo = msFlatGeobufLayerFreeItemInfo; + layer->vtable->LayerOpen = msFlatGeobufLayerOpen; + layer->vtable->LayerIsOpen = msFlatGeobufLayerIsOpen; + layer->vtable->LayerWhichShapes = msFlatGeobufLayerWhichShapes; + layer->vtable->LayerNextShape = msFlatGeobufLayerNextShape; + layer->vtable->LayerGetShape = msFlatGeobufLayerGetShape; + /* layer->vtable->LayerGetShapeCount, use default */ + layer->vtable->LayerClose = msFlatGeobufLayerClose; + layer->vtable->LayerGetItems = msFlatGeobufLayerGetItems; + layer->vtable->LayerGetExtent = msFlatGeobufLayerGetExtent; + /* layer->vtable->LayerGetAutoStyle, use default */ + /* layer->vtable->LayerCloseConnection, use default */ + layer->vtable->LayerSetTimeFilter = msLayerMakeBackticsTimeFilter; + /* layer->vtable->LayerTranslateFilter, use default */ + /* layer->vtable->LayerApplyFilterToLayer, use default */ + /* layer->vtable->LayerCreateItems, use default */ + /* layer->vtable->LayerGetNumFeatures, use default */ + + return MS_SUCCESS; +} diff --git a/src/mapflatgeobuf.h b/src/mapflatgeobuf.h new file mode 100644 index 0000000000..a5575d68fc --- /dev/null +++ b/src/mapflatgeobuf.h @@ -0,0 +1,47 @@ +/****************************************************************************** + * $Id$ + * + * Project: MapServer + * Purpose: FlatGeobuf access API + * Author: Björn Harrtell. + * + ****************************************************************************** + * Copyright (c) 1996-2005 Regents of the University of Minnesota. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + ****************************************************************************/ + +#ifndef MAPFLATGEOBUF_H +#define MAPFLATGEOBUF_H + +#include +#include "mapprimitive.h" +#include "mapproject.h" + +#include "cpl_vsi.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* MAPFLATGEOBUF_H */ diff --git a/src/mapgdal.cpp b/src/mapgdal.cpp new file mode 100644 index 0000000000..71c27251d4 --- /dev/null +++ b/src/mapgdal.cpp @@ -0,0 +1,699 @@ +/****************************************************************************** + * $Id$ + * + * Project: MapServer + * Purpose: Implementation of support for output using GDAL. + * Author: Frank Warmerdam, warmerdam@pobox.com + * + ****************************************************************************** + * Copyright (c) 2002, Frank Warmerdam + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + ****************************************************************************/ + +#include "mapserver.h" +#include "mapthread.h" +#include "mapgdal.h" +#include + +#include "cpl_conv.h" +#include "cpl_string.h" +#include "ogr_srs_api.h" + +#include "gdal.h" + +static int bGDALInitialized = 0; + +/************************************************************************/ +/* msGDALInitialize() */ +/************************************************************************/ + +void msGDALInitialize(void) + +{ + if (!bGDALInitialized) { + msAcquireLock(TLOCK_GDAL); + + GDALAllRegister(); + CPLPushErrorHandler(CPLQuietErrorHandler); + msReleaseLock(TLOCK_GDAL); + + bGDALInitialized = 1; + } +} + +/************************************************************************/ +/* msGDALCleanup() */ +/************************************************************************/ + +void msGDALCleanup(void) + +{ + if (bGDALInitialized) { + int iRepeat = 5; + + /* + ** Cleanup any unreferenced but open datasets as will tend + ** to exist due to deferred close requests. We are careful + ** to only close one file at a time before reflecting the + ** list as closing some datasets may cause others to be + ** closed (subdatasets in a VRT for instance). + */ + GDALDatasetH *pahDSList = NULL; + int nDSCount = 0; + int bDidSomething; + + msAcquireLock(TLOCK_GDAL); + + do { + int i; + GDALGetOpenDatasets(&pahDSList, &nDSCount); + bDidSomething = FALSE; + for (i = 0; i < nDSCount && !bDidSomething; i++) { + if (GDALReferenceDataset(pahDSList[i]) == 1) { + GDALClose(pahDSList[i]); + bDidSomething = TRUE; + } else + GDALDereferenceDataset(pahDSList[i]); + } + } while (bDidSomething); + + while (iRepeat--) + CPLPopErrorHandler(); + + msReleaseLock(TLOCK_GDAL); + + bGDALInitialized = 0; + } +} + +/************************************************************************/ +/* msCleanVSIDir() */ +/* */ +/* For the temporary /vsimem/msout directory we need to be sure */ +/* things are clean before we start, and after we are done. */ +/************************************************************************/ + +void msCleanVSIDir(const char *pszDir) + +{ + char **papszFiles = CPLReadDir(pszDir); + int i, nFileCount = CSLCount(papszFiles); + + for (i = 0; i < nFileCount; i++) { + if (strcasecmp(papszFiles[i], ".") == 0 || + strcasecmp(papszFiles[i], "..") == 0) + continue; + + VSIUnlink(CPLFormFilename(pszDir, papszFiles[i], NULL)); + } + + CSLDestroy(papszFiles); +} + +/************************************************************************/ +/* msSaveImageGDAL() */ +/************************************************************************/ + +int msSaveImageGDAL(mapObj *map, imageObj *image, const char *filenameIn) + +{ + int bFileIsTemporary = MS_FALSE; + GDALDatasetH hMemDS, hOutputDS; + GDALDriverH hMemDriver, hOutputDriver; + int nBands = 1; + int iLine; + outputFormatObj *format = image->format; + rasterBufferObj rb; + GDALDataType eDataType = GDT_Byte; + int bUseXmp = MS_FALSE; + const char *filename = NULL; + char *filenameToFree = NULL; + const char *gdal_driver_shortname = format->driver + 5; + + msGDALInitialize(); + memset(&rb, 0, sizeof(rasterBufferObj)); + +#ifdef USE_EXEMPI + if (map != NULL) { + bUseXmp = msXmpPresent(map); + } +#endif + + /* -------------------------------------------------------------------- */ + /* Identify the proposed output driver. */ + /* -------------------------------------------------------------------- */ + msAcquireLock(TLOCK_GDAL); + hOutputDriver = GDALGetDriverByName(gdal_driver_shortname); + if (hOutputDriver == NULL) { + msReleaseLock(TLOCK_GDAL); + msSetError(MS_MISCERR, "Failed to find %s driver.", "msSaveImageGDAL()", + gdal_driver_shortname); + return MS_FAILURE; + } + + /* -------------------------------------------------------------------- */ + /* We will need to write the output to a temporary file and */ + /* then stream to stdout if no filename is passed. If the */ + /* driver supports virtualio then we hold the temporary file in */ + /* memory, otherwise we try to put it in a reasonable temporary */ + /* file location. */ + /* -------------------------------------------------------------------- */ + if (filenameIn == NULL) { + const char *pszExtension = format->extension; + if (pszExtension == NULL) + pszExtension = "img.tmp"; + + if (bUseXmp == MS_FALSE && + msGDALDriverSupportsVirtualIOOutput(hOutputDriver)) { + msCleanVSIDir("/vsimem/msout"); + filenameToFree = msTmpFile(map, NULL, "/vsimem/msout/", pszExtension); + } + + if (filenameToFree == NULL && map != NULL) + filenameToFree = msTmpFile(map, map->mappath, NULL, pszExtension); + else if (filenameToFree == NULL) { + filenameToFree = msTmpFile(map, NULL, NULL, pszExtension); + } + filename = filenameToFree; + + bFileIsTemporary = MS_TRUE; + } else { + filename = filenameIn; + } + + /* -------------------------------------------------------------------- */ + /* Establish the characteristics of our memory, and final */ + /* dataset. */ + /* -------------------------------------------------------------------- */ + + if (format->imagemode == MS_IMAGEMODE_RGB) { + nBands = 3; + assert(MS_RENDERER_PLUGIN(format) && format->vtable->supports_pixel_buffer); + if (MS_UNLIKELY(MS_FAILURE == + format->vtable->getRasterBufferHandle(image, &rb))) { + msReleaseLock(TLOCK_GDAL); + msFree(filenameToFree); + return MS_FAILURE; + } + } else if (format->imagemode == MS_IMAGEMODE_RGBA) { + nBands = 4; + assert(MS_RENDERER_PLUGIN(format) && format->vtable->supports_pixel_buffer); + if (MS_UNLIKELY(MS_FAILURE == + format->vtable->getRasterBufferHandle(image, &rb))) { + msReleaseLock(TLOCK_GDAL); + msFree(filenameToFree); + return MS_FAILURE; + } + } else if (format->imagemode == MS_IMAGEMODE_INT16) { + nBands = format->bands; + eDataType = GDT_Int16; + } else if (format->imagemode == MS_IMAGEMODE_FLOAT32) { + nBands = format->bands; + eDataType = GDT_Float32; + } else if (format->imagemode == MS_IMAGEMODE_BYTE) { + nBands = format->bands; + eDataType = GDT_Byte; + } else { + msReleaseLock(TLOCK_GDAL); + msSetError(MS_MEMERR, "Unknown format. This is a bug.", + "msSaveImageGDAL()"); + msFree(filenameToFree); + return MS_FAILURE; + } + + /* -------------------------------------------------------------------- */ + /* Create a memory dataset which we can use as a source for a */ + /* CreateCopy(). */ + /* -------------------------------------------------------------------- */ + hMemDriver = GDALGetDriverByName("MEM"); + if (hMemDriver == NULL) { + msReleaseLock(TLOCK_GDAL); + msSetError(MS_MISCERR, "Failed to find MEM driver.", "msSaveImageGDAL()"); + msFree(filenameToFree); + return MS_FAILURE; + } + + hMemDS = GDALCreate(hMemDriver, "msSaveImageGDAL_temp", image->width, + image->height, nBands, eDataType, NULL); + if (hMemDS == NULL) { + msReleaseLock(TLOCK_GDAL); + msSetError(MS_MISCERR, "Failed to create MEM dataset.", + "msSaveImageGDAL()"); + msFree(filenameToFree); + return MS_FAILURE; + } + + /* -------------------------------------------------------------------- */ + /* Copy the gd image into the memory dataset. */ + /* -------------------------------------------------------------------- */ + for (iLine = 0; iLine < image->height; iLine++) { + int iBand; + + for (iBand = 0; iBand < nBands; iBand++) { + CPLErr eErr; + GDALRasterBandH hBand = GDALGetRasterBand(hMemDS, iBand + 1); + + if (format->imagemode == MS_IMAGEMODE_INT16) { + eErr = GDALRasterIO(hBand, GF_Write, 0, iLine, image->width, 1, + image->img.raw_16bit + iLine * image->width + + iBand * image->width * image->height, + image->width, 1, GDT_Int16, 2, 0); + + } else if (format->imagemode == MS_IMAGEMODE_FLOAT32) { + eErr = GDALRasterIO(hBand, GF_Write, 0, iLine, image->width, 1, + image->img.raw_float + iLine * image->width + + iBand * image->width * image->height, + image->width, 1, GDT_Float32, 4, 0); + } else if (format->imagemode == MS_IMAGEMODE_BYTE) { + eErr = GDALRasterIO(hBand, GF_Write, 0, iLine, image->width, 1, + image->img.raw_byte + iLine * image->width + + iBand * image->width * image->height, + image->width, 1, GDT_Byte, 1, 0); + } else { + GByte *pabyData; + unsigned char *pixptr = NULL; + assert(rb.type == MS_BUFFER_BYTE_RGBA); + switch (iBand) { + case 0: + pixptr = rb.data.rgba.r; + break; + case 1: + pixptr = rb.data.rgba.g; + break; + case 2: + pixptr = rb.data.rgba.b; + break; + case 3: + pixptr = rb.data.rgba.a; + break; + } + assert(pixptr); + if (pixptr == NULL) { + msReleaseLock(TLOCK_GDAL); + msSetError(MS_MISCERR, "Missing RGB or A buffer.\n", + "msSaveImageGDAL()"); + GDALClose(hMemDS); + msFree(filenameToFree); + return MS_FAILURE; + } + + pabyData = (GByte *)(pixptr + iLine * rb.data.rgba.row_step); + + if (rb.data.rgba.a == NULL || iBand == 3) { + eErr = GDALRasterIO(hBand, GF_Write, 0, iLine, image->width, 1, + pabyData, image->width, 1, GDT_Byte, + rb.data.rgba.pixel_step, 0); + } else { /* We need to un-pre-multiple RGB by alpha. */ + GByte *pabyUPM = (GByte *)malloc(image->width); + GByte *pabyAlpha = + (GByte *)(rb.data.rgba.a + iLine * rb.data.rgba.row_step); + int i; + + for (i = 0; i < image->width; i++) { + int alpha = pabyAlpha[i * rb.data.rgba.pixel_step]; + + if (alpha == 0) + pabyUPM[i] = 0; + else { + int result = + (pabyData[i * rb.data.rgba.pixel_step] * 255) / alpha; + + if (result > 255) + result = 255; + + pabyUPM[i] = result; + } + } + + eErr = GDALRasterIO(hBand, GF_Write, 0, iLine, image->width, 1, + pabyUPM, image->width, 1, GDT_Byte, 1, 0); + free(pabyUPM); + } + } + if (eErr != CE_None) { + msReleaseLock(TLOCK_GDAL); + msSetError(MS_MISCERR, "GDALRasterIO() failed.\n", "msSaveImageGDAL()"); + GDALClose(hMemDS); + msFree(filenameToFree); + return MS_FAILURE; + } + } + } + + /* -------------------------------------------------------------------- */ + /* Attach the palette if appropriate. */ + /* -------------------------------------------------------------------- */ + if (format->imagemode == MS_IMAGEMODE_RGB) { + GDALSetRasterColorInterpretation(GDALGetRasterBand(hMemDS, 1), GCI_RedBand); + GDALSetRasterColorInterpretation(GDALGetRasterBand(hMemDS, 2), + GCI_GreenBand); + GDALSetRasterColorInterpretation(GDALGetRasterBand(hMemDS, 3), + GCI_BlueBand); + } else if (format->imagemode == MS_IMAGEMODE_RGBA) { + GDALSetRasterColorInterpretation(GDALGetRasterBand(hMemDS, 1), GCI_RedBand); + GDALSetRasterColorInterpretation(GDALGetRasterBand(hMemDS, 2), + GCI_GreenBand); + GDALSetRasterColorInterpretation(GDALGetRasterBand(hMemDS, 3), + GCI_BlueBand); + GDALSetRasterColorInterpretation(GDALGetRasterBand(hMemDS, 4), + GCI_AlphaBand); + } + + /* -------------------------------------------------------------------- */ + /* Assign the projection and coordinate system to the memory */ + /* dataset. */ + /* -------------------------------------------------------------------- */ + + if (map != NULL) { + char *pszWKT; + + GDALSetGeoTransform(hMemDS, map->gt.geotransform); + + pszWKT = msProjectionObj2OGCWKT(&(map->projection)); + if (pszWKT != NULL) { + GDALSetProjection(hMemDS, pszWKT); + msFree(pszWKT); + } + } + + /* -------------------------------------------------------------------- */ + /* Possibly assign a nodata value. */ + /* -------------------------------------------------------------------- */ + const char *nullvalue = msGetOutputFormatOption(format, "NULLVALUE", NULL); + if (nullvalue != NULL) { + const double dfNullValue = atof(nullvalue); + for (int iBand = 0; iBand < nBands; iBand++) { + GDALRasterBandH hBand = GDALGetRasterBand(hMemDS, iBand + 1); + GDALSetRasterNoDataValue(hBand, dfNullValue); + } + } + + /* -------------------------------------------------------------------- */ + /* Try to save resolution in the output file. */ + /* -------------------------------------------------------------------- */ + if (image->resolution > 0) { + char res[30]; + + snprintf(res, sizeof(res), "%lf", image->resolution); + GDALSetMetadataItem(hMemDS, "TIFFTAG_XRESOLUTION", res, NULL); + GDALSetMetadataItem(hMemDS, "TIFFTAG_YRESOLUTION", res, NULL); + GDALSetMetadataItem(hMemDS, "TIFFTAG_RESOLUTIONUNIT", "2", NULL); + } + + /* -------------------------------------------------------------------- */ + /* Separate creation options from metadata items. */ + /* -------------------------------------------------------------------- */ + std::vector apszCreationOptions; + for (int i = 0; i < format->numformatoptions; i++) { + char *option = format->formatoptions[i]; + + // MDI stands for MetaDataItem + if (STARTS_WITH(option, "mdi_")) { + const char *option_without_band = option + strlen("mdi_"); + GDALMajorObjectH hObject = (GDALMajorObjectH)hMemDS; + if (STARTS_WITH(option_without_band, "BAND_")) { + int nBandNumber = atoi(option_without_band + strlen("BAND_")); + if (nBandNumber > 0 && nBandNumber <= nBands) { + const char *pszAfterBand = + strchr(option_without_band + strlen("BAND_"), '_'); + if (pszAfterBand != NULL) { + hObject = (GDALMajorObjectH)GDALGetRasterBand(hMemDS, nBandNumber); + option_without_band = pszAfterBand + 1; + } + } else { + msDebug("Invalid band number %d in metadata item option %s", + nBandNumber, option); + } + } + if (hObject) { + std::string osDomain(option_without_band); + size_t nUnderscorePos = osDomain.find('_'); + if (nUnderscorePos != std::string::npos) { + std::string osKeyValue = osDomain.substr(nUnderscorePos + 1); + osDomain.resize(nUnderscorePos); + if (osDomain == "default") + osDomain.clear(); + size_t nEqualPos = osKeyValue.find('='); + if (nEqualPos != std::string::npos) { + GDALSetMetadataItem( + hObject, osKeyValue.substr(0, nEqualPos).c_str(), + osKeyValue.substr(nEqualPos + 1).c_str(), osDomain.c_str()); + } + } else { + msDebug("Invalid format in metadata item option %s", option); + } + } + } else { + apszCreationOptions.emplace_back(option); + } + } + apszCreationOptions.emplace_back(nullptr); + + /* -------------------------------------------------------------------- */ + /* Create a disk image in the selected output format from the */ + /* memory image. */ + /* -------------------------------------------------------------------- */ + hOutputDS = GDALCreateCopy(hOutputDriver, filename, hMemDS, FALSE, + &apszCreationOptions[0], NULL, NULL); + + if (hOutputDS == NULL) { + GDALClose(hMemDS); + msReleaseLock(TLOCK_GDAL); + msSetError(MS_MISCERR, "Failed to create output %s file.\n%s", + "msSaveImageGDAL()", format->driver + 5, CPLGetLastErrorMsg()); + msFree(filenameToFree); + return MS_FAILURE; + } + + /* closing the memory DS also frees all associated resources. */ + GDALClose(hMemDS); + + GDALClose(hOutputDS); + msReleaseLock(TLOCK_GDAL); + + /* -------------------------------------------------------------------- */ + /* Are we writing license info into the image? */ + /* If so, add it to the temp file on disk now. */ + /* -------------------------------------------------------------------- */ +#ifdef USE_EXEMPI + if (bUseXmp == MS_TRUE) { + if (msXmpWrite(map, filename) == MS_FAILURE) { + /* Something bad happened. */ + msSetError(MS_MISCERR, "XMP write to %s failed.\n", "msSaveImageGDAL()", + filename); + msFree(filenameToFree); + return MS_FAILURE; + } + } +#endif + + /* -------------------------------------------------------------------- */ + /* Is this supposed to be a temporary file? If so, stream to */ + /* stdout and delete the file. */ + /* -------------------------------------------------------------------- */ + if (bFileIsTemporary) { + VSILFILE *fp; + unsigned char block[4000]; + int bytes_read; + + if (msIO_needBinaryStdout() == MS_FAILURE) { + msFree(filenameToFree); + return MS_FAILURE; + } + + /* We aren't sure how far back GDAL exports the VSI*L API, so + we only use it if we suspect we need it. But we do need it if + holding temporary file in memory. */ + fp = VSIFOpenL(filename, "rb"); + if (fp == NULL) { + msSetError(MS_MISCERR, "Failed to open %s for streaming to stdout.", + "msSaveImageGDAL()", filename); + msFree(filenameToFree); + return MS_FAILURE; + } + + while ((bytes_read = VSIFReadL(block, 1, sizeof(block), fp)) > 0) + msIO_fwrite(block, 1, bytes_read, stdout); + + VSIFCloseL(fp); + + VSIUnlink(filename); + msCleanVSIDir("/vsimem/msout"); + } + msFree(filenameToFree); + + return MS_SUCCESS; +} + +/************************************************************************/ +/* msInitGDALOutputFormat() */ +/************************************************************************/ + +int msInitDefaultGDALOutputFormat(outputFormatObj *format) + +{ + GDALDriverH hDriver; + + msGDALInitialize(); + + /* -------------------------------------------------------------------- */ + /* check that this driver exists. Note visiting drivers should */ + /* be pretty threadsafe so don't bother acquiring the GDAL */ + /* lock. */ + /* -------------------------------------------------------------------- */ + hDriver = GDALGetDriverByName(format->driver + 5); + if (hDriver == NULL) { + msSetError(MS_MISCERR, "No GDAL driver named `%s' available.", + "msInitGDALOutputFormat()", format->driver + 5); + return MS_FAILURE; + } + + if (GDALGetMetadataItem(hDriver, GDAL_DCAP_CREATE, NULL) == NULL && + GDALGetMetadataItem(hDriver, GDAL_DCAP_CREATECOPY, NULL) == NULL) { + msSetError(MS_MISCERR, "GDAL `%s' driver does not support output.", + "msInitGDALOutputFormat()", format->driver + 5); + return MS_FAILURE; + } + + /* -------------------------------------------------------------------- */ + /* Initialize the object. */ + /* -------------------------------------------------------------------- */ + format->imagemode = MS_IMAGEMODE_RGB; + format->renderer = MS_RENDER_WITH_AGG; + + if (GDALGetMetadataItem(hDriver, GDAL_DMD_MIMETYPE, NULL) != NULL) + format->mimetype = + msStrdup(GDALGetMetadataItem(hDriver, GDAL_DMD_MIMETYPE, NULL)); + if (GDALGetMetadataItem(hDriver, GDAL_DMD_EXTENSION, NULL) != NULL) + format->extension = + msStrdup(GDALGetMetadataItem(hDriver, GDAL_DMD_EXTENSION, NULL)); + + return MS_SUCCESS; +} + +char **msGetStringListFromHashTable(hashTableObj *table) { + struct hashObj *tp = NULL; + int i; + char **papszRet = NULL; + + if (!table) + return NULL; + if (msHashIsEmpty(table)) + return NULL; + + for (i = 0; i < MS_HASHSIZE; ++i) { + if (table->items[i] != NULL) { + for (tp = table->items[i]; tp != NULL; tp = tp->next) { + papszRet = CSLSetNameValue(papszRet, tp->key, tp->data); + } + } + } + return papszRet; +} + +/************************************************************************/ +/* msProjectionObj2OGCWKT() */ +/* */ +/* We stick to the C API for OGRSpatialReference object access */ +/* to allow MapServer+GDAL to be built without C++ */ +/* complications. */ +/* */ +/* Note that this function will return NULL on failure, and the */ +/* returned string should be freed with msFree(). */ +/************************************************************************/ + +char *msProjectionObj2OGCWKT(projectionObj *projection) + +{ + OGRSpatialReferenceH hSRS; + char *pszWKT = NULL, *pszProj4, *pszInitEpsg = NULL; + int nLength = 0, i; + OGRErr eErr; + + if (projection->proj == NULL) + return NULL; + + hSRS = OSRNewSpatialReference(NULL); + /* -------------------------------------------------------------------- */ + /* Look for an EPSG-like projection argument */ + /* -------------------------------------------------------------------- */ + if ((projection->numargs == 1 || + (projection->numargs == 2 && + strstr(projection->args[1], "epsgaxis=") != NULL)) && + (pszInitEpsg = strcasestr(projection->args[0], "init=epsg:"))) { + const int nEpsgCode = atoi(pszInitEpsg + strlen("init=epsg:")); + eErr = OSRImportFromEPSG(hSRS, nEpsgCode); + if (eErr != OGRERR_NONE) { + // In case this is a pseudo EPSG code only defined in a text 'epsg' + // file and not in proj.db + eErr = OSRSetFromUserInput( + hSRS, std::string("+").append(projection->args[0]).c_str()); + } + } else { + /* -------------------------------------------------------------------- */ + /* Form arguments into a full Proj.4 definition string. */ + /* -------------------------------------------------------------------- */ + for (i = 0; i < projection->numargs; i++) + nLength += strlen(projection->args[i]) + 2; + + pszProj4 = (char *)CPLMalloc(nLength + 2); + pszProj4[0] = '\0'; + + for (i = 0; i < projection->numargs; i++) { + strcat(pszProj4, "+"); + strcat(pszProj4, projection->args[i]); + strcat(pszProj4, " "); + } + + /* -------------------------------------------------------------------- */ + /* Ingest the string into OGRSpatialReference. */ + /* -------------------------------------------------------------------- */ + eErr = OSRImportFromProj4(hSRS, pszProj4); + CPLFree(pszProj4); + } + + /* -------------------------------------------------------------------- */ + /* Export as a WKT string. */ + /* -------------------------------------------------------------------- */ + if (eErr == OGRERR_NONE) + OSRExportToWkt(hSRS, &pszWKT); + + OSRDestroySpatialReference(hSRS); + + if (pszWKT) { + char *pszWKT2 = msStrdup(pszWKT); + CPLFree(pszWKT); + + return pszWKT2; + } else + return NULL; +} + +/************************************************************************/ +/* msGDALDriverSupportsVirtualIOOutput() */ +/************************************************************************/ + +int msGDALDriverSupportsVirtualIOOutput(GDALDriverH hDriver) { + /* We need special testing here for the netCDF driver, since recent */ + /* GDAL versions advertise VirtualIO support, but this is only for the */ + /* read-side of the driver, not the write-side. */ + return GDALGetMetadataItem(hDriver, GDAL_DCAP_VIRTUALIO, NULL) != NULL && + !EQUAL(GDALGetDescription(hDriver), "netCDF"); +} diff --git a/src/mapgdal.h b/src/mapgdal.h new file mode 100644 index 0000000000..211b90c2ff --- /dev/null +++ b/src/mapgdal.h @@ -0,0 +1,46 @@ +/****************************************************************************** + * $Id$ + * + * Project: MapServer + * Purpose: GDAL interface + * Author: Even Rouault + * + ****************************************************************************** + * Copyright (c) 2020, Even Rouault + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + ****************************************************************************/ + +#ifndef MAPGDAL_H +#define MAPGDAL_H + +#include "mapserver.h" +#include "gdal.h" + +#ifdef __cplusplus +extern "C" { +#endif + +int msGDALDriverSupportsVirtualIOOutput(GDALDriverH hDriver); + +#ifdef __cplusplus +} +#endif + +#endif /* MAPGDAL_H */ diff --git a/src/mapgeomtransform.c b/src/mapgeomtransform.c new file mode 100644 index 0000000000..5afa68bdc6 --- /dev/null +++ b/src/mapgeomtransform.c @@ -0,0 +1,323 @@ +/****************************************************************************** + * $Id$ + * + * Project: MapServer + * Purpose: RFC48 implementation of geometry transformations for styling + * Author: Thomas Bonfort , Camptocamp (thomas.bonfort at camptocamp.com) + * + ****************************************************************************** + * Copyright (c) 1996-2005 Regents of the University of Minnesota. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + *****************************************************************************/ + +#include "mapserver.h" +#include "mapthread.h" + +extern int yyparse(parseObj *p); + +void msStyleSetGeomTransform(styleObj *s, const char *transform) { + if (!transform) { + msFree(s->_geomtransform.string); + s->_geomtransform.string = NULL; + s->_geomtransform.type = MS_GEOMTRANSFORM_NONE; + return; + } + if (!strncasecmp("start", transform, 5)) { + s->_geomtransform.type = MS_GEOMTRANSFORM_START; + } else if (!strncasecmp("end", transform, 3)) { + s->_geomtransform.type = MS_GEOMTRANSFORM_END; + } else if (!strncasecmp("vertices", transform, 8)) { + s->_geomtransform.type = MS_GEOMTRANSFORM_VERTICES; + } else if (!strncasecmp("bbox", transform, 4)) { + s->_geomtransform.type = MS_GEOMTRANSFORM_BBOX; + } else if (!strncasecmp("labelpnt", transform, 8)) { + s->_geomtransform.type = MS_GEOMTRANSFORM_LABELPOINT; + } else if (!strncasecmp("labelpoly", transform, 9)) { + s->_geomtransform.type = MS_GEOMTRANSFORM_LABELPOLY; + } else if (!strncasecmp("labelcenter", transform, 11)) { + s->_geomtransform.type = MS_GEOMTRANSFORM_LABELCENTER; + } else if (!strncasecmp("centroid", transform, 8)) { + s->_geomtransform.type = MS_GEOMTRANSFORM_CENTROID; + } else { + s->_geomtransform.type = MS_GEOMTRANSFORM_NONE; + msSetError(MS_MISCERR, "unknown transform expression", + "msStyleSetGeomTransform()"); + msFree(s->_geomtransform.string); + s->_geomtransform.string = NULL; + return; + } + + msFree(s->_geomtransform.string); + s->_geomtransform.string = msStrdup(transform); +} + +/* + * return a copy of the geometry transform expression + * returned char* must be freed by the caller + */ +char *msStyleGetGeomTransform(styleObj *s) { + return msStrdup(s->_geomtransform.string); +} + +double calcOrientation(pointObj *p1, pointObj *p2) { + double theta; + theta = atan2(p2->x - p1->x, p2->y - p1->y); + return MS_RAD_TO_DEG * (theta - MS_PI2); +} + +double calcMidAngle(pointObj *p1, pointObj *p2, pointObj *p3) { + pointObj p1n; + double dx12, dy12, dx23, dy23, l12, l23; + + /* We treat both segments as vector 1-2 and vector 2-3 and + * compute their dx,dy and length + */ + dx12 = p2->x - p1->x; + dy12 = p2->y - p1->y; + l12 = sqrt(dx12 * dx12 + dy12 * dy12); + dx23 = p3->x - p2->x; + dy23 = p3->y - p2->y; + l23 = sqrt(dx23 * dx23 + dy23 * dy23); + + /* Normalize length of vector 1-2 to same as length of vector 2-3 */ + if (l12 > 0.0) { + p1n.x = p2->x - dx12 * (l23 / l12); + p1n.y = p2->y - dy12 * (l23 / l12); + } else + p1n = *p2; /* segment 1-2 is 0-length, use segment 2-3 for orientation */ + + /* Return the orientation defined by the sum of the normalized vectors */ + return calcOrientation(&p1n, p3); +} + +/* + * RFC48 implementation: + * - transform the original shapeobj + * - use the styleObj to render the transformed shapeobj + */ +int msDrawTransformedShape(mapObj *map, imageObj *image, shapeObj *shape, + styleObj *style, double scalefactor) { + int type = style->_geomtransform.type; + int i, j, status = MS_SUCCESS; + switch (type) { + case MS_GEOMTRANSFORM_END: /*render point on last vertex only*/ + for (j = 0; j < shape->numlines; j++) { + lineObj *line = &(shape->line[j]); + pointObj *p = &(line->point[line->numpoints - 1]); + if (p->x < 0 || p->x > image->width || p->y < 0 || p->y > image->height) + continue; + if (style->autoangle == MS_TRUE && line->numpoints > 1) { + style->angle = calcOrientation(&(line->point[line->numpoints - 2]), p); + } + status = msDrawMarkerSymbol(map, image, p, style, scalefactor); + } + break; + case MS_GEOMTRANSFORM_START: /*render point on first vertex only*/ + for (j = 0; j < shape->numlines; j++) { + lineObj *line = &(shape->line[j]); + pointObj *p = &(line->point[0]); + /*skip if outside image*/ + if (p->x < 0 || p->x > image->width || p->y < 0 || p->y > image->height) + continue; + if (style->autoangle == MS_TRUE && line->numpoints > 1) { + style->angle = calcOrientation(p, &(line->point[1])); + } + status = msDrawMarkerSymbol(map, image, p, style, scalefactor); + } + break; + case MS_GEOMTRANSFORM_VERTICES: + for (j = 0; j < shape->numlines; j++) { + lineObj *line = &(shape->line[j]); + for (i = 1; i < line->numpoints - 1; i++) { + pointObj *p = &(line->point[i]); + /*skip points outside image*/ + if (p->x < 0 || p->x > image->width || p->y < 0 || p->y > image->height) + continue; + if (style->autoangle == MS_TRUE) { + style->angle = calcMidAngle(&(line->point[i - 1]), &(line->point[i]), + &(line->point[i + 1])); + } + status = msDrawMarkerSymbol(map, image, p, style, scalefactor); + } + } + break; + case MS_GEOMTRANSFORM_BBOX: { + shapeObj bbox; + lineObj bbox_line; + pointObj bbox_points[5]; + int padding = MS_MAX(style->width, style->size) + + 3; /* so clipped shape does not extent into image */ + + /*create a shapeObj representing the bounding box (clipped by the image + * size)*/ + bbox.numlines = 1; + bbox.line = &bbox_line; + bbox.line->numpoints = 5; + bbox.line->point = bbox_points; + + msComputeBounds(shape); + bbox_points[0].x = bbox_points[4].x = bbox_points[1].x = + (shape->bounds.minx < -padding) ? -padding : shape->bounds.minx; + /* cppcheck-suppress unreadVariable */ + bbox_points[2].x = bbox_points[3].x = + (shape->bounds.maxx > image->width + padding) ? image->width + padding + : shape->bounds.maxx; + bbox_points[0].y = bbox_points[4].y = bbox_points[3].y = + (shape->bounds.miny < -padding) ? -padding : shape->bounds.miny; + /* cppcheck-suppress unreadVariable */ + bbox_points[1].y = bbox_points[2].y = + (shape->bounds.maxy > image->height + padding) ? image->height + padding + : shape->bounds.maxy; + status = msDrawShadeSymbol(map, image, &bbox, style, scalefactor); + } break; + case MS_GEOMTRANSFORM_CENTROID: { + double unused; /*used by centroid function*/ + pointObj centroid; + if (MS_SUCCESS == + msGetPolygonCentroid(shape, ¢roid, &unused, &unused)) { + status = msDrawMarkerSymbol(map, image, ¢roid, style, scalefactor); + } + } break; + case MS_GEOMTRANSFORM_EXPRESSION: { + int status; + shapeObj *tmpshp; + parseObj p; + + p.shape = shape; /* set a few parser globals (hence the lock) */ + p.expr = &(style->_geomtransform); + + if (p.expr->tokens == NULL) { /* this could happen if drawing originates + from legend code (#5193) */ + status = msTokenizeExpression(p.expr, NULL, NULL); + if (status != MS_SUCCESS) { + msSetError(MS_MISCERR, "Unable to tokenize expression.", + "msDrawTransformedShape()"); + return MS_FAILURE; + } + } + + p.expr->curtoken = p.expr->tokens; /* reset */ + p.type = MS_PARSE_TYPE_SHAPE; + + status = yyparse(&p); + if (status != 0) { + msSetError(MS_PARSEERR, "Failed to process shape expression: %s", + "msDrawTransformedShape", style->_geomtransform.string); + return MS_FAILURE; + } + tmpshp = p.result.shpval; + + switch (tmpshp->type) { + case MS_SHAPE_POINT: + case MS_SHAPE_POLYGON: + /* cppcheck-suppress unreadVariable */ + status = msDrawShadeSymbol(map, image, tmpshp, style, scalefactor); + break; + case MS_SHAPE_LINE: + /* cppcheck-suppress unreadVariable */ + status = msDrawLineSymbol(map, image, tmpshp, style, scalefactor); + break; + } + + msFreeShape(tmpshp); + msFree(tmpshp); + } break; + case MS_GEOMTRANSFORM_LABELPOINT: + case MS_GEOMTRANSFORM_LABELPOLY: + break; + default: + msSetError(MS_MISCERR, "unknown geomtransform", "msDrawTransformedShape()"); + return MS_FAILURE; + } + return status; +} + +/* + * RFC89 implementation: + * - transform directly the shapeobj + */ +int msGeomTransformShape(mapObj *map, layerObj *layer, shapeObj *shape) { + int i; + expressionObj *e = &layer->_geomtransform; + +#ifdef USE_V8_MAPSCRIPT + if (!map->v8context) { + msV8CreateContext(map); + if (!map->v8context) { + msSetError(MS_V8ERR, "Unable to create v8 context.", + "msGeomTransformShape()"); + return MS_FAILURE; + } + } + + msV8ContextSetLayer(map, layer); +#endif + + switch (e->type) { + case MS_GEOMTRANSFORM_EXPRESSION: { + int status; + shapeObj *tmpshp; + parseObj p; + + p.shape = shape; /* set a few parser globals (hence the lock) */ + p.expr = e; + p.expr->curtoken = p.expr->tokens; /* reset */ + p.type = MS_PARSE_TYPE_SHAPE; + p.dblval = map->cellsize * (msInchesPerUnit(map->units, 0) / + msInchesPerUnit(layer->units, 0)); + p.dblval2 = 0; + /* data_cellsize is only set with contour layer */ + if (layer->connectiontype == MS_CONTOUR) { + const char *value = + msLookupHashTable(&layer->metadata, "__data_cellsize__"); + if (value) + p.dblval2 = atof(value); + } + + status = yyparse(&p); + if (status != 0) { + msSetError(MS_PARSEERR, "Failed to process shape expression: %s", + "msGeomTransformShape()", e->string); + return MS_FAILURE; + } + + tmpshp = p.result.shpval; + + for (i = 0; i < shape->numlines; i++) + free(shape->line[i].point); + shape->numlines = 0; + if (shape->line) + free(shape->line); + shape->line = NULL; + shape->type = tmpshp->type; /* might have been a change (e.g. centerline) */ + + for (i = 0; i < tmpshp->numlines; i++) + msAddLine(shape, &(tmpshp->line[i])); /* copy each line */ + + msFreeShape(tmpshp); + msFree(tmpshp); + } break; + default: + msSetError(MS_MISCERR, "unknown geomtransform", "msGeomTransformShape()"); + return MS_FAILURE; + } + + return MS_SUCCESS; +} diff --git a/src/mapgeomutil.cpp b/src/mapgeomutil.cpp new file mode 100644 index 0000000000..b4f0bfa014 --- /dev/null +++ b/src/mapgeomutil.cpp @@ -0,0 +1,108 @@ +/****************************************************************************** + * $Id$ + * + * Project: MapServer + * Purpose: Rendering utility functions + * Author: Thomas Bonfort and the MapServer team. + * + ****************************************************************************** + * Copyright (c) 1996-2011 Regents of the University of Minnesota. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + *****************************************************************************/ + +#include "mapserver.h" +#include "renderers/agg/include/agg_arc.h" +#include "renderers/agg/include/agg_basics.h" + +shapeObj *msRasterizeArc(double x0, double y0, double radius, double startAngle, + double endAngle, int isSlice) { + static int allocated_size = 100; + shapeObj *shape = (shapeObj *)calloc(1, sizeof(shapeObj)); + MS_CHECK_ALLOC(shape, sizeof(shapeObj), NULL); + mapserver::arc arc(x0, y0, radius, radius, startAngle * MS_DEG_TO_RAD, + endAngle * MS_DEG_TO_RAD, true); + arc.approximation_scale(1); + arc.rewind(1); + msInitShape(shape); + + lineObj *line = (lineObj *)calloc(1, sizeof(lineObj)); + if (!line) { + msSetError(MS_MEMERR, "%s: %d: Out of memory allocating %u bytes.\n", + "msRasterizeArc()", __FILE__, __LINE__, + (unsigned int)sizeof(lineObj)); + free(shape); + return NULL; + } + shape->line = line; + shape->numlines = 1; + line->point = (pointObj *)calloc(allocated_size, sizeof(pointObj)); + if (!line->point) { + msSetError(MS_MEMERR, "%s: %d: Out of memory allocating %u bytes.\n", + "msRasterizeArc()", __FILE__, __LINE__, + (unsigned int)(allocated_size * sizeof(pointObj))); + free(line); + free(shape); + return NULL; + } + + line->numpoints = 0; + + double x, y; + + // first segment from center to first point of arc + if (isSlice) { + line->point[0].x = x0; + line->point[0].y = y0; + line->numpoints = 1; + } + while (arc.vertex(&x, &y) != mapserver::path_cmd_stop) { + if (line->numpoints == allocated_size) { + allocated_size *= 2; + line->point = + (pointObj *)realloc(line->point, allocated_size * sizeof(pointObj)); + if (!line->point) { + msSetError(MS_MEMERR, "%s: %d: Out of memory allocating %u bytes.\n", + "msRasterizeArc()", __FILE__, __LINE__, + (unsigned int)(allocated_size * sizeof(pointObj))); + free(line); + free(shape); + return NULL; + } + } + line->point[line->numpoints].x = x; + line->point[line->numpoints].y = y; + line->numpoints++; + } + + // make sure the shape is closed + if (line->point[line->numpoints - 1].x != line->point[0].x || + line->point[line->numpoints - 1].y != line->point[0].y) { + if (line->numpoints == allocated_size) { + allocated_size *= 2; + line->point = (pointObj *)msSmallRealloc( + line->point, allocated_size * sizeof(pointObj)); + } + line->point[line->numpoints].x = line->point[0].x; + line->point[line->numpoints].y = line->point[0].y; + line->numpoints++; + } + + return shape; +} diff --git a/src/mapgeos.c b/src/mapgeos.c new file mode 100644 index 0000000000..d3603f8b15 --- /dev/null +++ b/src/mapgeos.c @@ -0,0 +1,1777 @@ +/****************************************************************************** + * $Id$ + * + * Project: MapServer + * Purpose: MapServer-GEOS integration. + * Author: Steve Lime and the MapServer team. + * + ****************************************************************************** + * Copyright (c) 1996-2005 Regents of the University of Minnesota. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + *****************************************************************************/ + +#include "mapserver.h" +#include "mapgraph.h" + +#ifdef USE_GEOS + +// To avoid accidental use of non reentrant GEOS API. +// (check only effective in GEOS >= 3.5) +#define GEOS_USE_ONLY_R_API + +#include + +/* +** Error handling... +*/ +static void msGEOSError(const char *format, ...) { + va_list args; + + va_start(args, format); + msSetError(MS_GEOSERR, format, "msGEOSError()", + args); /* just pass along to MapServer error handling */ + va_end(args); + + return; +} + +static void msGEOSNotice(const char *fmt, ...) { + (void)fmt; /* do nothing with notices at this point */ +} + +#ifndef USE_THREAD +static GEOSContextHandle_t geos_handle; + +static inline GEOSContextHandle_t msGetGeosContextHandle() { + return geos_handle; +} + +#else +#include "mapthread.h" +typedef struct geos_thread_info { + struct geos_thread_info *next; + void *thread_id; + GEOSContextHandle_t geos_handle; +} geos_thread_info_t; + +static geos_thread_info_t *geos_list = NULL; + +static GEOSContextHandle_t msGetGeosContextHandle() { + geos_thread_info_t *link; + GEOSContextHandle_t ret_obj; + void *thread_id; + + msAcquireLock(TLOCK_GEOS); + + thread_id = msGetThreadId(); + + /* find link for this thread */ + + for (link = geos_list; + link != NULL && link->thread_id != thread_id && link->next != NULL && + link->next->thread_id != thread_id; + link = link->next) { + } + + /* If the target thread link is already at the head of the list were ok */ + if (geos_list != NULL && geos_list->thread_id == thread_id) { + } + + /* We don't have one ... initialize one. */ + else if (link == NULL || link->next == NULL) { + geos_thread_info_t *new_link; + new_link = (geos_thread_info_t *)malloc(sizeof(geos_thread_info_t)); + new_link->next = geos_list; + new_link->thread_id = thread_id; + new_link->geos_handle = initGEOS_r(msGEOSNotice, msGEOSError); + + geos_list = new_link; + } + + /* If the link is not already at the head of the list, promote it */ + else { + geos_thread_info_t *target = link->next; + + link->next = link->next->next; + target->next = geos_list; + geos_list = target; + } + + ret_obj = geos_list->geos_handle; + + msReleaseLock(TLOCK_GEOS); + + return ret_obj; +} +#endif + +/* +** Setup/Cleanup wrappers +*/ +void msGEOSSetup() { +#ifndef USE_THREAD + geos_handle = initGEOS_r(msGEOSNotice, msGEOSError); +#endif +} + +void msGEOSCleanup() { +#ifndef USE_THREAD + finishGEOS_r(geos_handle); + geos_handle = NULL; +#else + geos_thread_info_t *link; + msAcquireLock(TLOCK_GEOS); + for (link = geos_list; link != NULL;) { + geos_thread_info_t *cur = link; + link = link->next; + finishGEOS_r(cur->geos_handle); + free(cur); + } + geos_list = NULL; + msReleaseLock(TLOCK_GEOS); +#endif +} + +/* +** Translation functions +*/ +static GEOSGeom msGEOSShape2Geometry_point(pointObj *point) { + GEOSCoordSeq coords; + GEOSGeom g; + GEOSContextHandle_t handle = msGetGeosContextHandle(); + + if (!point) + return NULL; + + coords = GEOSCoordSeq_create_r(handle, 1, 2); /* todo handle z's */ + if (!coords) + return NULL; + + GEOSCoordSeq_setX_r(handle, coords, 0, point->x); + GEOSCoordSeq_setY_r(handle, coords, 0, point->y); + /* GEOSCoordSeq_setY(coords, 0, point->z); */ + + g = GEOSGeom_createPoint_r(handle, + coords); /* g owns the coordinate in coords */ + + return g; +} + +static GEOSGeom msGEOSShape2Geometry_multipoint(lineObj *multipoint) { + int i; + GEOSGeom g; + GEOSGeom *points; + GEOSContextHandle_t handle = msGetGeosContextHandle(); + + if (!multipoint) + return NULL; + + points = malloc(multipoint->numpoints * sizeof(GEOSGeom)); + if (!points) + return NULL; + + for (i = 0; i < multipoint->numpoints; i++) + points[i] = msGEOSShape2Geometry_point(&(multipoint->point[i])); + + g = GEOSGeom_createCollection_r(handle, GEOS_MULTIPOINT, points, + multipoint->numpoints); + + free(points); + + return g; +} + +static GEOSGeom msGEOSShape2Geometry_line(lineObj *line) { + int i; + GEOSGeom g; + GEOSCoordSeq coords; + GEOSContextHandle_t handle = msGetGeosContextHandle(); + + if (!line) + return NULL; + + coords = + GEOSCoordSeq_create_r(handle, line->numpoints, 2); /* todo handle z's */ + if (!coords) + return NULL; + + for (i = 0; i < line->numpoints; i++) { + GEOSCoordSeq_setX_r(handle, coords, i, line->point[i].x); + GEOSCoordSeq_setY_r(handle, coords, i, line->point[i].y); + /* GEOSCoordSeq_setZ(coords, i, line->point[i].z); */ + } + + g = GEOSGeom_createLineString_r( + handle, coords); /* g owns the coordinates in coords */ + + return g; +} + +static GEOSGeom msGEOSShape2Geometry_multiline(shapeObj *multiline) { + int i; + GEOSGeom g; + GEOSGeom *lines; + GEOSContextHandle_t handle = msGetGeosContextHandle(); + + if (!multiline) + return NULL; + + lines = malloc(multiline->numlines * sizeof(GEOSGeom)); + if (!lines) + return NULL; + + for (i = 0; i < multiline->numlines; i++) + lines[i] = msGEOSShape2Geometry_line(&(multiline->line[i])); + + g = GEOSGeom_createCollection_r(handle, GEOS_MULTILINESTRING, lines, + multiline->numlines); + + free(lines); + + return g; +} + +static GEOSGeom msGEOSShape2Geometry_simplepolygon(shapeObj *shape, int r, + int *outerList) { + int i, j, k; + GEOSCoordSeq coords; + GEOSGeom g; + GEOSGeom outerRing; + GEOSGeom *innerRings = NULL; + int numInnerRings = 0, *innerList; + GEOSContextHandle_t handle = msGetGeosContextHandle(); + + if (!shape || !outerList) + return NULL; + + /* build the outer shell */ + coords = GEOSCoordSeq_create_r(handle, shape->line[r].numpoints, + 2); /* todo handle z's */ + if (!coords) + return NULL; + + for (i = 0; i < shape->line[r].numpoints; i++) { + GEOSCoordSeq_setX_r(handle, coords, i, shape->line[r].point[i].x); + GEOSCoordSeq_setY_r(handle, coords, i, shape->line[r].point[i].y); + /* GEOSCoordSeq_setZ(coords, i, shape->line[r].point[i].z); */ + } + + outerRing = GEOSGeom_createLinearRing_r( + handle, coords); /* outerRing owns the coordinates in coords */ + + /* build the holes */ + innerList = msGetInnerList(shape, r, outerList); + for (j = 0; j < shape->numlines; j++) + if (innerList[j] == MS_TRUE) + numInnerRings++; + + if (numInnerRings > 0) { + k = 0; /* inner ring counter */ + + innerRings = msSmallMalloc(numInnerRings * sizeof(GEOSGeom)); + + for (j = 0; j < shape->numlines; j++) { + if (innerList[j] == MS_FALSE) + continue; + + coords = GEOSCoordSeq_create_r(handle, shape->line[j].numpoints, + 2); /* todo handle z's */ + if (!coords) { + free(innerRings); + free(innerList); + return NULL; /* todo, this will leak memory (shell + allocated holes) */ + } + + for (i = 0; i < shape->line[j].numpoints; i++) { + GEOSCoordSeq_setX_r(handle, coords, i, shape->line[j].point[i].x); + GEOSCoordSeq_setY_r(handle, coords, i, shape->line[j].point[i].y); + /* GEOSCoordSeq_setZ(coords, i, shape->line[j].point[i].z); */ + } + + innerRings[k] = GEOSGeom_createLinearRing_r( + handle, coords); /* innerRings[k] owns the coordinates in coords */ + k++; + } + } + + g = GEOSGeom_createPolygon_r(handle, outerRing, innerRings, numInnerRings); + + free(innerList); /* clean up */ + free(innerRings); /* clean up */ + + return g; +} + +static GEOSGeom msGEOSShape2Geometry_polygon(shapeObj *shape) { + int i, j; + GEOSGeom *polygons; + int *outerList, numOuterRings = 0, lastOuterRing = 0; + GEOSGeom g; + GEOSContextHandle_t handle = msGetGeosContextHandle(); + + outerList = msGetOuterList(shape); + for (i = 0; i < shape->numlines; i++) { + if (outerList[i] == MS_TRUE) { + numOuterRings++; + lastOuterRing = i; /* save for the simple case */ + } + } + + if (numOuterRings == 1) { + g = msGEOSShape2Geometry_simplepolygon(shape, lastOuterRing, outerList); + } else { /* a true multipolygon */ + polygons = msSmallMalloc(numOuterRings * sizeof(GEOSGeom)); + + j = 0; /* part counter */ + for (i = 0; i < shape->numlines; i++) { + if (outerList[i] == MS_FALSE) + continue; + polygons[j] = msGEOSShape2Geometry_simplepolygon( + shape, i, outerList); /* TODO: account for NULL return values */ + j++; + } + + g = GEOSGeom_createCollection_r(handle, GEOS_MULTIPOLYGON, polygons, + numOuterRings); + free(polygons); + } + + free(outerList); + return g; +} + +GEOSGeom msGEOSShape2Geometry(shapeObj *shape) { + if (!shape) + return NULL; /* a NULL shape generates a NULL geometry */ + + switch (shape->type) { + case MS_SHAPE_POINT: + if (shape->numlines == 0 || + shape->line[0].numpoints == 0) /* not enough info for a point */ + return NULL; + + if (shape->line[0].numpoints == 1) /* simple point */ + return msGEOSShape2Geometry_point(&(shape->line[0].point[0])); + else /* multi-point */ + return msGEOSShape2Geometry_multipoint(&(shape->line[0])); + break; + case MS_SHAPE_LINE: + if (shape->numlines == 0 || + shape->line[0].numpoints < 2) /* not enough info for a line */ + return NULL; + + if (shape->numlines == 1) /* simple line */ + return msGEOSShape2Geometry_line(&(shape->line[0])); + else /* multi-line */ + return msGEOSShape2Geometry_multiline(shape); + break; + case MS_SHAPE_POLYGON: + if (shape->numlines == 0 || + shape->line[0].numpoints < + 4) /* not enough info for a polygon (first=last) */ + return NULL; + + return msGEOSShape2Geometry_polygon( + shape); /* simple and multipolygon cases are addressed */ + break; + default: + break; + } + + return NULL; /* should not get here */ +} + +static shapeObj *msGEOSGeometry2Shape_point(GEOSGeom g) { + GEOSCoordSeq coords; + shapeObj *shape = NULL; + GEOSContextHandle_t handle = msGetGeosContextHandle(); + + if (!g) + return NULL; + + shape = (shapeObj *)malloc(sizeof(shapeObj)); + msInitShape(shape); + + shape->type = MS_SHAPE_POINT; + shape->line = (lineObj *)malloc(sizeof(lineObj)); + shape->numlines = 1; + shape->line[0].point = (pointObj *)malloc(sizeof(pointObj)); + shape->line[0].numpoints = 1; + shape->geometry = (GEOSGeom)g; + + coords = (GEOSCoordSeq)GEOSGeom_getCoordSeq_r(handle, g); + + GEOSCoordSeq_getX_r(handle, coords, 0, &(shape->line[0].point[0].x)); + GEOSCoordSeq_getY_r(handle, coords, 0, &(shape->line[0].point[0].y)); + /* GEOSCoordSeq_getZ(coords, 0, &(shape->line[0].point[0].z)); */ + + shape->bounds.minx = shape->bounds.maxx = shape->line[0].point[0].x; + shape->bounds.miny = shape->bounds.maxy = shape->line[0].point[0].y; + + return shape; +} + +static shapeObj *msGEOSGeometry2Shape_multipoint(GEOSGeom g) { + int i; + int numPoints; + GEOSCoordSeq coords; + GEOSGeom point; + + shapeObj *shape = NULL; + GEOSContextHandle_t handle = msGetGeosContextHandle(); + + if (!g) + return NULL; + numPoints = GEOSGetNumGeometries_r(handle, g); /* each geometry has 1 point */ + + shape = (shapeObj *)malloc(sizeof(shapeObj)); + msInitShape(shape); + + shape->type = MS_SHAPE_POINT; + shape->line = (lineObj *)malloc(sizeof(lineObj)); + shape->numlines = 1; + shape->line[0].point = (pointObj *)malloc(sizeof(pointObj) * numPoints); + shape->line[0].numpoints = numPoints; + shape->geometry = (GEOSGeom)g; + + for (i = 0; i < numPoints; i++) { + point = (GEOSGeom)GEOSGetGeometryN_r(handle, g, i); + coords = (GEOSCoordSeq)GEOSGeom_getCoordSeq_r(handle, point); + + GEOSCoordSeq_getX_r(handle, coords, 0, &(shape->line[0].point[i].x)); + GEOSCoordSeq_getY_r(handle, coords, 0, &(shape->line[0].point[i].y)); + /* GEOSCoordSeq_getZ(coords, 0, &(shape->line[0].point[i].z)); */ + } + + msComputeBounds(shape); + + return shape; +} + +static shapeObj *msGEOSGeometry2Shape_line(GEOSGeom g) { + shapeObj *shape = NULL; + GEOSContextHandle_t handle = msGetGeosContextHandle(); + + int i; + int numPoints; + GEOSCoordSeq coords; + + if (!g) + return NULL; + numPoints = GEOSGetNumCoordinates_r(handle, g); + coords = (GEOSCoordSeq)GEOSGeom_getCoordSeq_r(handle, g); + + shape = (shapeObj *)malloc(sizeof(shapeObj)); + msInitShape(shape); + + shape->type = MS_SHAPE_LINE; + shape->line = (lineObj *)malloc(sizeof(lineObj)); + shape->numlines = 1; + shape->line[0].point = (pointObj *)malloc(sizeof(pointObj) * numPoints); + shape->line[0].numpoints = numPoints; + shape->geometry = (GEOSGeom)g; + + for (i = 0; i < numPoints; i++) { + GEOSCoordSeq_getX_r(handle, coords, i, &(shape->line[0].point[i].x)); + GEOSCoordSeq_getY_r(handle, coords, i, &(shape->line[0].point[i].y)); + /* GEOSCoordSeq_getZ(coords, i, &(shape->line[0].point[i].z)); */ + } + + msComputeBounds(shape); + + return shape; +} + +static void msGEOSGeometry2Shape_multiline_part(GEOSContextHandle_t handle, + GEOSGeom part, + shapeObj *shape) { + int i; + int type, numGeometries, numPoints; + GEOSCoordSeq coords; + lineObj line; + + type = GEOSGeomTypeId_r(handle, part); + if (type == GEOS_MULTILINESTRING) { + numGeometries = GEOSGetNumGeometries_r(handle, part); + + for (i = 0; i < numGeometries; i++) { + GEOSGeom subPart = (GEOSGeom)GEOSGetGeometryN_r(handle, part, i); + msGEOSGeometry2Shape_multiline_part(handle, subPart, shape); + } + } else { + numPoints = GEOSGetNumCoordinates_r(handle, part); + coords = (GEOSCoordSeq)GEOSGeom_getCoordSeq_r(handle, part); + line.point = (pointObj *)malloc(sizeof(pointObj) * numPoints); + line.numpoints = numPoints; + + for (i = 0; i < numPoints; i++) { + GEOSCoordSeq_getX_r(handle, coords, i, &(line.point[i].x)); + GEOSCoordSeq_getY_r(handle, coords, i, &(line.point[i].y)); + /* GEOSCoordSeq_getZ(coords, i, &(line.point[i].z)); */ + } + + msAddLineDirectly(shape, &line); + } +} + +static shapeObj *msGEOSGeometry2Shape_multiline(GEOSGeom g) { + int i; + int numGeometries; + GEOSGeom part; + + shapeObj *shape = NULL; + GEOSContextHandle_t handle = msGetGeosContextHandle(); + + if (!g) + return NULL; + numGeometries = GEOSGetNumGeometries_r(handle, g); + + shape = (shapeObj *)malloc(sizeof(shapeObj)); + msInitShape(shape); + + shape->type = MS_SHAPE_LINE; + shape->geometry = (GEOSGeom)g; + + for (i = 0; i < numGeometries; i++) { + part = (GEOSGeom)GEOSGetGeometryN_r(handle, g, i); + msGEOSGeometry2Shape_multiline_part(handle, part, shape); + } + + msComputeBounds(shape); + + return shape; +} + +static shapeObj *msGEOSGeometry2Shape_polygon(GEOSGeom g) { + shapeObj *shape = NULL; + lineObj line; + int numPoints, numRings; + int i, j; + + GEOSCoordSeq coords; + GEOSGeom ring; + GEOSContextHandle_t handle = msGetGeosContextHandle(); + + if (!g) + return NULL; + + shape = (shapeObj *)malloc(sizeof(shapeObj)); + msInitShape(shape); + shape->type = MS_SHAPE_POLYGON; + shape->geometry = (GEOSGeom)g; + + /* exterior ring */ + ring = (GEOSGeom)GEOSGetExteriorRing_r(handle, g); + numPoints = GEOSGetNumCoordinates_r(handle, ring); + coords = (GEOSCoordSeq)GEOSGeom_getCoordSeq_r(handle, ring); + + line.point = (pointObj *)malloc(sizeof(pointObj) * numPoints); + line.numpoints = numPoints; + + for (i = 0; i < numPoints; i++) { + GEOSCoordSeq_getX_r(handle, coords, i, &(line.point[i].x)); + GEOSCoordSeq_getY_r(handle, coords, i, &(line.point[i].y)); + /* GEOSCoordSeq_getZ(coords, i, &(line.point[i].z)); */ + } + msAddLineDirectly(shape, &line); + + /* interior rings */ + numRings = GEOSGetNumInteriorRings_r(handle, g); + for (j = 0; j < numRings; j++) { + ring = (GEOSGeom)GEOSGetInteriorRingN_r(handle, g, j); + if (GEOSisRing_r(handle, ring) != 1) + continue; /* skip it */ + + numPoints = GEOSGetNumCoordinates_r(handle, ring); + coords = (GEOSCoordSeq)GEOSGeom_getCoordSeq_r(handle, ring); + + line.point = (pointObj *)malloc(sizeof(pointObj) * numPoints); + line.numpoints = numPoints; + + for (i = 0; i < numPoints; i++) { + GEOSCoordSeq_getX_r(handle, coords, i, &(line.point[i].x)); + GEOSCoordSeq_getY_r(handle, coords, i, &(line.point[i].y)); + /* GEOSCoordSeq_getZ(coords, i, &(line.point[i].z)); */ + } + msAddLineDirectly(shape, &line); + } + + msComputeBounds(shape); + + return shape; +} + +static shapeObj *msGEOSGeometry2Shape_multipolygon(GEOSGeom g) { + int i, j, k; + shapeObj *shape = NULL; + lineObj line; + int numPoints, numRings, numPolygons; + + GEOSCoordSeq coords; + GEOSGeom polygon, ring; + GEOSContextHandle_t handle = msGetGeosContextHandle(); + + if (!g) + return NULL; + numPolygons = GEOSGetNumGeometries_r(handle, g); + + shape = (shapeObj *)malloc(sizeof(shapeObj)); + msInitShape(shape); + shape->type = MS_SHAPE_POLYGON; + shape->geometry = (GEOSGeom)g; + + for (k = 0; k < numPolygons; k++) { /* for each polygon */ + polygon = (GEOSGeom)GEOSGetGeometryN_r(handle, g, k); + + /* exterior ring */ + ring = (GEOSGeom)GEOSGetExteriorRing_r(handle, polygon); + numPoints = GEOSGetNumCoordinates_r(handle, ring); + coords = (GEOSCoordSeq)GEOSGeom_getCoordSeq_r(handle, ring); + + line.point = (pointObj *)malloc(sizeof(pointObj) * numPoints); + line.numpoints = numPoints; + + for (i = 0; i < numPoints; i++) { + GEOSCoordSeq_getX_r(handle, coords, i, &(line.point[i].x)); + GEOSCoordSeq_getY_r(handle, coords, i, &(line.point[i].y)); + /* GEOSCoordSeq_getZ(coords, i, &(line.point[i].z)); */ + } + msAddLineDirectly(shape, &line); + + /* interior rings */ + numRings = GEOSGetNumInteriorRings_r(handle, polygon); + + for (j = 0; j < numRings; j++) { + ring = (GEOSGeom)GEOSGetInteriorRingN_r(handle, polygon, j); + if (GEOSisRing_r(handle, ring) != 1) + continue; /* skip it */ + + numPoints = GEOSGetNumCoordinates_r(handle, ring); + coords = (GEOSCoordSeq)GEOSGeom_getCoordSeq_r(handle, ring); + + line.point = (pointObj *)malloc(sizeof(pointObj) * numPoints); + line.numpoints = numPoints; + + for (i = 0; i < numPoints; i++) { + GEOSCoordSeq_getX_r(handle, coords, i, &(line.point[i].x)); + GEOSCoordSeq_getY_r(handle, coords, i, &(line.point[i].y)); + /* GEOSCoordSeq_getZ(coords, i, &(line.point[i].z)); */ + } + msAddLineDirectly(shape, &line); + } + } /* next polygon */ + + msComputeBounds(shape); + + return shape; +} + +shapeObj *msGEOSGeometry2Shape(GEOSGeom g) { + int type; + GEOSContextHandle_t handle = msGetGeosContextHandle(); + + if (!g) + return NULL; /* a NULL geometry generates a NULL shape */ + + type = GEOSGeomTypeId_r(handle, g); + switch (type) { + case GEOS_POINT: + return msGEOSGeometry2Shape_point(g); + break; + case GEOS_MULTIPOINT: + return msGEOSGeometry2Shape_multipoint(g); + break; + case GEOS_LINESTRING: + return msGEOSGeometry2Shape_line(g); + break; + case GEOS_MULTILINESTRING: + return msGEOSGeometry2Shape_multiline(g); + break; + case GEOS_POLYGON: + return msGEOSGeometry2Shape_polygon(g); + break; + case GEOS_MULTIPOLYGON: + return msGEOSGeometry2Shape_multipolygon(g); + break; + case GEOS_GEOMETRYCOLLECTION: + if (!GEOSisEmpty_r(handle, g)) { + shapeObj *shape = (shapeObj *)malloc(sizeof(shapeObj)); + msInitShape(shape); + shape->type = MS_SHAPE_LINE; + shape->geometry = (GEOSGeom)g; + + const int numGeoms = GEOSGetNumGeometries_r(handle, g); + for (int i = 0; i < numGeoms; i++) { /* for each geometry */ + shapeObj *shape2 = + msGEOSGeometry2Shape((GEOSGeom)GEOSGetGeometryN_r(handle, g, i)); + if (shape2) { + for (int j = 0; j < shape2->numlines; j++) + msAddLineDirectly(shape, &shape2->line[j]); + shape2->numlines = 0; + shape2->geometry = NULL; /* not owned */ + msFreeShape(shape2); + } + } + msComputeBounds(shape); + return shape; + } + break; + default: + msSetError(MS_GEOSERR, "Unsupported GEOS geometry type (%d).", + "msGEOSGeometry2Shape()", type); + } + return NULL; +} +#endif + +/* +** Maintenance functions exposed to MapServer/MapScript. +*/ + +void msGEOSFreeGeometry(shapeObj *shape) { +#ifdef USE_GEOS + GEOSGeom g = NULL; + GEOSContextHandle_t handle = msGetGeosContextHandle(); + + if (!shape || !shape->geometry) + return; + + g = (GEOSGeom)shape->geometry; + GEOSGeom_destroy_r(handle, g); + shape->geometry = NULL; +#else + msSetError(MS_GEOSERR, "GEOS support is not available.", + "msGEOSFreeGEOSGeom()"); + return; +#endif +} + +/* +** WKT input and output functions +*/ +shapeObj *msGEOSShapeFromWKT(const char *wkt) { +#ifdef USE_GEOS + GEOSGeom g; + GEOSContextHandle_t handle = msGetGeosContextHandle(); + + if (!wkt) + return NULL; + + g = GEOSGeomFromWKT_r(handle, wkt); + if (!g) { + msSetError(MS_GEOSERR, "Error reading WKT geometry \"%s\".", + "msGEOSShapeFromWKT()", wkt); + return NULL; + } else { + return msGEOSGeometry2Shape(g); + } + +#else + msSetError(MS_GEOSERR, "GEOS support is not available.", + "msGEOSShapeFromWKT()"); + return NULL; +#endif +} + +/* Return should be freed with msGEOSFreeWKT */ +char *msGEOSShapeToWKT(shapeObj *shape) { +#ifdef USE_GEOS + GEOSGeom g; + GEOSContextHandle_t handle = msGetGeosContextHandle(); + + if (!shape) + return NULL; + + /* if we have a geometry, we should update it*/ + msGEOSFreeGeometry(shape); + + shape->geometry = (GEOSGeom)msGEOSShape2Geometry(shape); + g = (GEOSGeom)shape->geometry; + if (!g) + return NULL; + + return GEOSGeomToWKT_r(handle, g); +#else + msSetError(MS_GEOSERR, "GEOS support is not available.", + "msGEOSShapeToWKT()"); + return NULL; +#endif +} + +void msGEOSFreeWKT(char *pszGEOSWKT) { +#ifdef USE_GEOS + GEOSContextHandle_t handle = msGetGeosContextHandle(); +#if GEOS_VERSION_MAJOR > 3 || \ + (GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR >= 2) + GEOSFree_r(handle, pszGEOSWKT); +#endif +#else + msSetError(MS_GEOSERR, "GEOS support is not available.", "msGEOSFreeWKT()"); +#endif +} + +shapeObj *msGEOSOffsetCurve(shapeObj *p, double offset) { +#if defined USE_GEOS && (GEOS_VERSION_MAJOR > 3 || \ + (GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR >= 3)) + int typeChanged = 0; + GEOSGeom g1, g2 = NULL; + GEOSContextHandle_t handle = msGetGeosContextHandle(); + + if (!p) + return NULL; + + /* + * GEOSOffsetCurve_r() uses BufferBuilder.bufferLineSingleSided(), which + * works with lines, naturally. In order to allow offsets for a MapServer + * polygonObj, it has to be processed as line and afterwards reverted. + */ + if (p->type == MS_SHAPE_POLYGON) { + p->type = MS_SHAPE_LINE; + typeChanged = 1; + msGEOSFreeGeometry(p); + } + + if (typeChanged || !p->geometry) + p->geometry = (GEOSGeom)msGEOSShape2Geometry(p); + + g1 = (GEOSGeom)p->geometry; + if (!g1) + return NULL; + + if (GEOSGeomTypeId_r(handle, g1) == GEOS_MULTILINESTRING) { + GEOSGeom *lines = malloc(p->numlines * sizeof(GEOSGeom)); + if (!lines) + return NULL; + for (int i = 0; i < p->numlines; i++) { + lines[i] = + GEOSOffsetCurve_r(handle, GEOSGetGeometryN_r(handle, g1, i), offset, + 4, GEOSBUF_JOIN_MITRE, fabs(offset * 1.5)); + } + g2 = GEOSGeom_createCollection_r(handle, GEOS_MULTILINESTRING, lines, + p->numlines); + free(lines); + } else { + g2 = GEOSOffsetCurve_r(handle, g1, offset, 4, GEOSBUF_JOIN_MITRE, + fabs(offset * 1.5)); + } + + /* + * Undo change of geometry type. We won't re-create the geos gemotry here, + * it's up to each geos function to create it. + */ + if (typeChanged) { + msGEOSFreeGeometry(p); + p->type = MS_SHAPE_POLYGON; + } + + if (g2) + return msGEOSGeometry2Shape(g2); + + return NULL; +#else + msSetError(MS_GEOSERR, "GEOS Offset Curve support is not available.", + "msGEOSingleSidedBuffer()"); + return NULL; +#endif +} + +/* +** Analytical functions exposed to MapServer/MapScript. +*/ + +shapeObj *msGEOSBuffer(shapeObj *shape, double width) { +#ifdef USE_GEOS + GEOSGeom g1, g2; + GEOSContextHandle_t handle = msGetGeosContextHandle(); + + if (!shape) + return NULL; + + if (!shape->geometry) /* if no geometry for the shape then build one */ + shape->geometry = (GEOSGeom)msGEOSShape2Geometry(shape); + + g1 = (GEOSGeom)shape->geometry; + if (!g1) + return NULL; + + g2 = GEOSBuffer_r(handle, g1, width, 30); + return msGEOSGeometry2Shape(g2); +#else + msSetError(MS_GEOSERR, "GEOS support is not available.", "msGEOSBuffer()"); + return NULL; +#endif +} + +shapeObj *msGEOSSimplify(shapeObj *shape, double tolerance) { +#ifdef USE_GEOS + GEOSGeom g1, g2; + GEOSContextHandle_t handle = msGetGeosContextHandle(); + + if (!shape) + return NULL; + + if (!shape->geometry) /* if no geometry for the shape then build one */ + shape->geometry = (GEOSGeom)msGEOSShape2Geometry(shape); + + g1 = (GEOSGeom)shape->geometry; + if (!g1) + return NULL; + + g2 = GEOSSimplify_r(handle, g1, tolerance); + return msGEOSGeometry2Shape(g2); +#else + msSetError(MS_GEOSERR, "GEOS Simplify support is not available.", + "msGEOSSimplify()"); + return NULL; +#endif +} + +shapeObj *msGEOSTopologyPreservingSimplify(shapeObj *shape, double tolerance) { +#ifdef USE_GEOS + GEOSGeom g1, g2; + GEOSContextHandle_t handle = msGetGeosContextHandle(); + + if (!shape) + return NULL; + + if (!shape->geometry) /* if no geometry for the shape then build one */ + shape->geometry = (GEOSGeom)msGEOSShape2Geometry(shape); + + g1 = (GEOSGeom)shape->geometry; + if (!g1) + return NULL; + + g2 = GEOSTopologyPreserveSimplify_r(handle, g1, tolerance); + return msGEOSGeometry2Shape(g2); +#else + msSetError(MS_GEOSERR, "GEOS Simplify support is not available.", + "msGEOSTopologyPreservingSimplify()"); + return NULL; +#endif +} + +shapeObj *msGEOSConvexHull(shapeObj *shape) { +#ifdef USE_GEOS + GEOSGeom g1, g2; + GEOSContextHandle_t handle = msGetGeosContextHandle(); + + if (!shape) + return NULL; + + if (!shape->geometry) /* if no geometry for the shape then build one */ + shape->geometry = (GEOSGeom)msGEOSShape2Geometry(shape); + g1 = (GEOSGeom)shape->geometry; + if (!g1) + return NULL; + + g2 = GEOSConvexHull_r(handle, g1); + return msGEOSGeometry2Shape(g2); +#else + msSetError(MS_GEOSERR, "GEOS support is not available.", + "msGEOSConvexHull()"); + return NULL; +#endif +} + +shapeObj *msGEOSBoundary(shapeObj *shape) { +#ifdef USE_GEOS + GEOSGeom g1, g2; + GEOSContextHandle_t handle = msGetGeosContextHandle(); + + if (!shape) + return NULL; + + if (!shape->geometry) /* if no geometry for the shape then build one */ + shape->geometry = (GEOSGeom)msGEOSShape2Geometry(shape); + g1 = (GEOSGeom)shape->geometry; + if (!g1) + return NULL; + + g2 = GEOSBoundary_r(handle, g1); + return msGEOSGeometry2Shape(g2); +#else + msSetError(MS_GEOSERR, "GEOS support is not available.", "msGEOSBoundary()"); + return NULL; +#endif +} + +pointObj *msGEOSGetCentroid(shapeObj *shape) { +#ifdef USE_GEOS + GEOSGeom g1, g2; + GEOSCoordSeq coords; + pointObj *point; + GEOSContextHandle_t handle = msGetGeosContextHandle(); + + if (!shape) + return NULL; + + if (!shape->geometry) /* if no geometry for the shape then build one */ + shape->geometry = (GEOSGeom)msGEOSShape2Geometry(shape); + g1 = (GEOSGeom)shape->geometry; + if (!g1) + return NULL; + + g2 = GEOSGetCentroid_r(handle, g1); + if (!g2) + return NULL; + + point = (pointObj *)malloc(sizeof(pointObj)); + + coords = (GEOSCoordSeq)GEOSGeom_getCoordSeq_r(handle, g2); + + GEOSCoordSeq_getX_r(handle, coords, 0, &(point->x)); + GEOSCoordSeq_getY_r(handle, coords, 0, &(point->y)); + /* GEOSCoordSeq_getZ(coords, 0, &(point->z)); */ + + GEOSGeom_destroy_r(handle, g2); + + return point; +#else + msSetError(MS_GEOSERR, "GEOS support is not available.", + "msGEOSGetCentroid()"); + return NULL; +#endif +} + +shapeObj *msGEOSUnion(shapeObj *shape1, shapeObj *shape2) { +#ifdef USE_GEOS + GEOSGeom g1, g2, g3; + GEOSContextHandle_t handle = msGetGeosContextHandle(); + + if (!shape1 || !shape2) + return NULL; + + if (!shape1->geometry) /* if no geometry for the shape then build one */ + shape1->geometry = (GEOSGeom)msGEOSShape2Geometry(shape1); + g1 = (GEOSGeom)shape1->geometry; + if (!g1) + return NULL; + + if (!shape2->geometry) /* if no geometry for the shape then build one */ + shape2->geometry = (GEOSGeom)msGEOSShape2Geometry(shape2); + g2 = (GEOSGeom)shape2->geometry; + if (!g2) + return NULL; + + g3 = GEOSUnion_r(handle, g1, g2); + return msGEOSGeometry2Shape(g3); +#else + msSetError(MS_GEOSERR, "GEOS support is not available.", "msGEOSUnion()"); + return NULL; +#endif +} + +shapeObj *msGEOSIntersection(shapeObj *shape1, shapeObj *shape2) { +#ifdef USE_GEOS + GEOSGeom g1, g2, g3; + GEOSContextHandle_t handle = msGetGeosContextHandle(); + + if (!shape1 || !shape2) + return NULL; + + if (!shape1->geometry) /* if no geometry for the shape then build one */ + shape1->geometry = (GEOSGeom)msGEOSShape2Geometry(shape1); + g1 = (GEOSGeom)shape1->geometry; + if (!g1) + return NULL; + + if (!shape2->geometry) /* if no geometry for the shape then build one */ + shape2->geometry = (GEOSGeom)msGEOSShape2Geometry(shape2); + g2 = (GEOSGeom)shape2->geometry; + if (!g2) + return NULL; + + g3 = GEOSIntersection_r(handle, g1, g2); + return msGEOSGeometry2Shape(g3); +#else + msSetError(MS_GEOSERR, "GEOS support is not available.", + "msGEOSIntersection()"); + return NULL; +#endif +} + +shapeObj *msGEOSDifference(shapeObj *shape1, shapeObj *shape2) { +#ifdef USE_GEOS + GEOSGeom g1, g2, g3; + GEOSContextHandle_t handle = msGetGeosContextHandle(); + + if (!shape1 || !shape2) + return NULL; + + if (!shape1->geometry) /* if no geometry for the shape then build one */ + shape1->geometry = (GEOSGeom)msGEOSShape2Geometry(shape1); + g1 = (GEOSGeom)shape1->geometry; + if (!g1) + return NULL; + + if (!shape2->geometry) /* if no geometry for the shape then build one */ + shape2->geometry = (GEOSGeom)msGEOSShape2Geometry(shape2); + g2 = (GEOSGeom)shape2->geometry; + if (!g2) + return NULL; + + g3 = GEOSDifference_r(handle, g1, g2); + return msGEOSGeometry2Shape(g3); +#else + msSetError(MS_GEOSERR, "GEOS support is not available.", + "msGEOSDifference()"); + return NULL; +#endif +} + +shapeObj *msGEOSSymDifference(shapeObj *shape1, shapeObj *shape2) { +#ifdef USE_GEOS + GEOSGeom g1, g2, g3; + GEOSContextHandle_t handle = msGetGeosContextHandle(); + + if (!shape1 || !shape2) + return NULL; + + if (!shape1->geometry) /* if no geometry for the shape then build one */ + shape1->geometry = (GEOSGeom)msGEOSShape2Geometry(shape1); + g1 = (GEOSGeom)shape1->geometry; + if (!g1) + return NULL; + + if (!shape2->geometry) /* if no geometry for the shape then build one */ + shape2->geometry = (GEOSGeom)msGEOSShape2Geometry(shape2); + g2 = (GEOSGeom)shape2->geometry; + if (!g2) + return NULL; + + g3 = GEOSSymDifference_r(handle, g1, g2); + return msGEOSGeometry2Shape(g3); +#else + msSetError(MS_GEOSERR, "GEOS support is not available.", + "msGEOSSymDifference()"); + return NULL; +#endif +} + +shapeObj *msGEOSLineMerge(shapeObj *shape) { +#ifdef USE_GEOS + GEOSGeom g1, g2; + GEOSContextHandle_t handle = msGetGeosContextHandle(); + + if (!shape) + return NULL; + if (shape->type != MS_SHAPE_LINE) + return NULL; + + if (!shape->geometry) /* if no geometry for the shape then build one */ + shape->geometry = (GEOSGeom)msGEOSShape2Geometry(shape); + g1 = (GEOSGeom)shape->geometry; + if (!g1) + return NULL; + + g2 = GEOSLineMerge_r(handle, g1); + return msGEOSGeometry2Shape(g2); +#else + msSetError(MS_GEOSERR, "GEOS support is not available.", "msGEOSLineMerge()"); + return NULL; +#endif +} + +shapeObj *msGEOSVoronoiDiagram(shapeObj *shape, double tolerance, + int onlyEdges) { +#if defined(USE_GEOS) && \ + (GEOS_VERSION_MAJOR > 3 || \ + (GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR >= 5)) + GEOSGeom g1, g2; + GEOSContextHandle_t handle = msGetGeosContextHandle(); + + if (!shape) + return NULL; + + if (!shape->geometry) /* if no geometry for the shape then build one */ + shape->geometry = (GEOSGeom)msGEOSShape2Geometry(shape); + g1 = (GEOSGeom)shape->geometry; + if (!g1) + return NULL; + + g2 = GEOSVoronoiDiagram_r(handle, g1, NULL, tolerance, onlyEdges); + return msGEOSGeometry2Shape(g2); +#else + msSetError( + MS_GEOSERR, + "GEOS support is not available or GEOS version is not 3.5 or higher.", + "msGEOSVoronoiDiagram()"); + return NULL; +#endif +} + +static int keepEdge(lineObj *segment, shapeObj *polygon) { + int i, j; + + if (segment->numpoints < 2) + return MS_FALSE; + if (msIntersectPointPolygon(&segment->point[0], polygon) != MS_TRUE) + return MS_FALSE; + if (msIntersectPointPolygon(&segment->point[1], polygon) != MS_TRUE) + return MS_FALSE; + + for (i = 0; i < polygon->numlines; i++) + for (j = 1; j < polygon->line[i].numpoints; j++) + if (msIntersectSegments(&(segment->point[0]), &(segment->point[1]), + &(polygon->line[i].point[j - 1]), + &(polygon->line[i].point[j])) == MS_TRUE) + return (MS_FALSE); + + return (MS_TRUE); +} + +#define ARE_SAME_POINTS(a, b) \ + (((a).x != (b).x || (a).y != (b).y) ? MS_FALSE : MS_TRUE) + +// returns the index of the node, we use z to store a count of points at the +// same coordinate +static int buildNodes(multipointObj *nodes, pointObj *point) { + int i; + + for (i = 0; i < nodes->numpoints; i++) { + if (ARE_SAME_POINTS(nodes->point[i], *point)) { // found it + nodes->point[i].z++; + return i; + } + } + + // not found, add it + nodes->point[i].x = point->x; + nodes->point[i].y = point->y; + nodes->point[i].z = 1; + nodes->numpoints++; + + return i; +} + +shapeObj *msGEOSCenterline(shapeObj *shape) { +#if defined(USE_GEOS) && \ + (GEOS_VERSION_MAJOR > 3 || \ + (GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR >= 5)) + int i; + shapeObj *shape2 = NULL; + + multipointObj nodes; + graphObj *graph; + + int *path = NULL; // array of node indexes + int path_size = 0; + double path_dist = -1, max_path_dist = -1; + + if (!shape) + return NULL; + if (shape->type != MS_SHAPE_POLYGON) { + msSetError(MS_GEOSERR, + "Centerlines can only be computed for polygon shapes.", + "msGEOSCenterline()"); + return NULL; + } + + shape2 = msGEOSVoronoiDiagram(shape, 0.0, MS_TRUE); + if (!shape2) { + msSetError(MS_GEOSERR, "Voronoi diagram generation failed.", + "msGEOSCenterline()"); + return NULL; + } + + // process the edges and build a graph representation + nodes.point = (pointObj *)malloc(shape2->numlines * sizeof(pointObj) * 2); + nodes.numpoints = 0; + if (!nodes.point) { + msFreeShape(shape2); + free(shape2); + return NULL; + } + + graph = msCreateGraph(shape2->numlines * 2); + if (!graph) { + msFreeShape(shape2); + free(shape2); + free(nodes.point); + return NULL; + } + + for (i = 0; i < shape2->numlines; i++) { + if (keepEdge(&shape2->line[i], shape) == MS_TRUE) { + int src = buildNodes(&nodes, &shape2->line[i].point[0]); + int dest = buildNodes(&nodes, &shape2->line[i].point[1]); + msGraphAddEdge(graph, src, dest, + msDistancePointToPoint(&shape2->line[i].point[0], + &shape2->line[i].point[1])); + } + } + msFreeShape(shape2); // done with voronoi geometry, shape2 is still allocated + // though, just empty + shape2->type = MS_SHAPE_LINE; // will fill with centerline + + if (nodes.numpoints == 0) { + msSetError(MS_GEOSERR, + "Centerline generation failed, try densifying the shapes.", + "msGEOSCenterline()"); + free(shape2); + msFreeGraph(graph); + free(nodes.point); + return NULL; + } + + // step through edge nodes (z=1) + for (i = 0; i < nodes.numpoints; i++) { + if (nodes.point[i].z != 1) + continue; // skip + + if (!path) { // first one, keep this path + path = msGraphGetLongestShortestPath(graph, i, &path_size, &path_dist); + max_path_dist = path_dist; + } else { + int *tmp_path = NULL; + int tmp_path_size = 0; + double tmp_path_dist = -1; + + if (i == path[path_size - 1]) + continue; // skip, graph is bi-directional so it can't be any longer + tmp_path = msGraphGetLongestShortestPath(graph, i, &tmp_path_size, + &tmp_path_dist); + if (tmp_path_dist > max_path_dist) { + free(path); + path = tmp_path; + path_size = tmp_path_size; + path_dist = tmp_path_dist; + max_path_dist = tmp_path_dist; + } else { // skip path + msFree(tmp_path); + } + } + } + msFreeGraph(graph); // done with graph + + // transform the path into a shape + if (!path) { + msSetError(MS_GEOSERR, "Centerline generation failed.", + "msGEOSCenterline()"); + free(shape2); + free(nodes.point); + return NULL; + } else { + lineObj line; + line.point = (pointObj *)malloc(path_size * sizeof(pointObj)); + if (!line.point) { + free(shape2); + free(path); + free(nodes.point); + return NULL; + } + line.numpoints = path_size; + + for (i = 0; i < path_size; i++) { + line.point[i].x = nodes.point[path[i]].x; + line.point[i].y = nodes.point[path[i]].y; + } + msAddLineDirectly(shape2, &line); + } + + free(path); // clean up + free(nodes.point); + + return shape2; +#else + msSetError( + MS_GEOSERR, + "GEOS support is not available or GEOS version is not 3.5 or higher.", + "msGEOSCenterline()"); + return NULL; +#endif +} + +/* +** Binary predicates exposed to MapServer/MapScript +*/ + +/* +** Does shape1 contain shape2, returns MS_TRUE/MS_FALSE or -1 for an error. +*/ +int msGEOSContains(shapeObj *shape1, shapeObj *shape2) { +#ifdef USE_GEOS + GEOSGeom g1, g2; + int result; + GEOSContextHandle_t handle = msGetGeosContextHandle(); + + if (!shape1 || !shape2) + return -1; + + if (!shape1->geometry) /* if no geometry for shape1 then build one */ + shape1->geometry = (GEOSGeom)msGEOSShape2Geometry(shape1); + g1 = shape1->geometry; + if (!g1) + return -1; + + if (!shape2->geometry) /* if no geometry for shape2 then build one */ + shape2->geometry = (GEOSGeom)msGEOSShape2Geometry(shape2); + g2 = shape2->geometry; + if (!g2) + return -1; + + result = GEOSContains_r(handle, g1, g2); + return ((result == 2) ? -1 : result); +#else + msSetError(MS_GEOSERR, "GEOS support is not available.", "msGEOSContains()"); + return -1; +#endif +} + +/* +** Does shape1 overlap shape2, returns MS_TRUE/MS_FALSE or -1 for an error. +*/ +int msGEOSOverlaps(shapeObj *shape1, shapeObj *shape2) { +#ifdef USE_GEOS + GEOSGeom g1, g2; + int result; + GEOSContextHandle_t handle = msGetGeosContextHandle(); + + if (!shape1 || !shape2) + return -1; + + if (!shape1->geometry) /* if no geometry for shape1 then build one */ + shape1->geometry = (GEOSGeom)msGEOSShape2Geometry(shape1); + g1 = shape1->geometry; + if (!g1) + return -1; + + if (!shape2->geometry) /* if no geometry for shape2 then build one */ + shape2->geometry = (GEOSGeom)msGEOSShape2Geometry(shape2); + g2 = shape2->geometry; + if (!g2) + return -1; + + result = GEOSOverlaps_r(handle, g1, g2); + return ((result == 2) ? -1 : result); +#else + msSetError(MS_GEOSERR, "GEOS support is not available.", "msGEOSOverlaps()"); + return -1; +#endif +} + +/* +** Is shape1 within shape2, returns MS_TRUE/MS_FALSE or -1 for an error. +*/ +int msGEOSWithin(shapeObj *shape1, shapeObj *shape2) { +#ifdef USE_GEOS + GEOSGeom g1, g2; + int result; + GEOSContextHandle_t handle = msGetGeosContextHandle(); + + if (!shape1 || !shape2) + return -1; + + if (!shape1->geometry) /* if no geometry for shape1 then build one */ + shape1->geometry = (GEOSGeom)msGEOSShape2Geometry(shape1); + g1 = shape1->geometry; + if (!g1) + return -1; + + if (!shape2->geometry) /* if no geometry for shape2 then build one */ + shape2->geometry = (GEOSGeom)msGEOSShape2Geometry(shape2); + g2 = shape2->geometry; + if (!g2) + return -1; + + result = GEOSWithin_r(handle, g1, g2); + return ((result == 2) ? -1 : result); +#else + msSetError(MS_GEOSERR, "GEOS support is not available.", "msGEOSWithin()"); + return -1; +#endif +} + +/* +** Does shape1 cross shape2, returns MS_TRUE/MS_FALSE or -1 for an error. +*/ +int msGEOSCrosses(shapeObj *shape1, shapeObj *shape2) { +#ifdef USE_GEOS + GEOSGeom g1, g2; + int result; + GEOSContextHandle_t handle = msGetGeosContextHandle(); + + if (!shape1 || !shape2) + return -1; + + if (!shape1->geometry) /* if no geometry for shape1 then build one */ + shape1->geometry = (GEOSGeom)msGEOSShape2Geometry(shape1); + g1 = shape1->geometry; + if (!g1) + return -1; + + if (!shape2->geometry) /* if no geometry for shape2 then build one */ + shape2->geometry = (GEOSGeom)msGEOSShape2Geometry(shape2); + g2 = shape2->geometry; + if (!g2) + return -1; + + result = GEOSCrosses_r(handle, g1, g2); + return ((result == 2) ? -1 : result); +#else + msSetError(MS_GEOSERR, "GEOS support is not available.", "msGEOSCrosses()"); + return -1; +#endif +} + +/* +** Does shape1 intersect shape2, returns MS_TRUE/MS_FALSE or -1 for an error. +*/ +int msGEOSIntersects(shapeObj *shape1, shapeObj *shape2) { +#ifdef USE_GEOS + GEOSGeom g1, g2; + int result; + GEOSContextHandle_t handle = msGetGeosContextHandle(); + + if (!shape1 || !shape2) + return -1; + + if (!shape1->geometry) /* if no geometry for shape1 then build one */ + shape1->geometry = (GEOSGeom)msGEOSShape2Geometry(shape1); + g1 = (GEOSGeom)shape1->geometry; + if (!g1) + return -1; + + if (!shape2->geometry) /* if no geometry for shape2 then build one */ + shape2->geometry = (GEOSGeom)msGEOSShape2Geometry(shape2); + g2 = (GEOSGeom)shape2->geometry; + if (!g2) + return -1; + + result = GEOSIntersects_r(handle, g1, g2); + return ((result == 2) ? -1 : result); +#else + if (!shape1 || !shape2) + return -1; + + switch (shape1->type) { /* todo: deal with point shapes */ + case (MS_SHAPE_LINE): + switch (shape2->type) { + case (MS_SHAPE_LINE): + return msIntersectPolylines(shape1, shape2); + case (MS_SHAPE_POLYGON): + return msIntersectPolylinePolygon(shape1, shape2); + } + break; + case (MS_SHAPE_POLYGON): + switch (shape2->type) { + case (MS_SHAPE_LINE): + return msIntersectPolylinePolygon(shape2, shape1); + case (MS_SHAPE_POLYGON): + return msIntersectPolygons(shape1, shape2); + } + break; + } + + return -1; +#endif +} + +/* +** Does shape1 touch shape2, returns MS_TRUE/MS_FALSE or -1 for an error. +*/ +int msGEOSTouches(shapeObj *shape1, shapeObj *shape2) { +#ifdef USE_GEOS + GEOSGeom g1, g2; + int result; + GEOSContextHandle_t handle = msGetGeosContextHandle(); + + if (!shape1 || !shape2) + return -1; + + if (!shape1->geometry) /* if no geometry for shape1 then build one */ + shape1->geometry = (GEOSGeom)msGEOSShape2Geometry(shape1); + g1 = (GEOSGeom)shape1->geometry; + if (!g1) + return -1; + + if (!shape2->geometry) /* if no geometry for shape2 then build one */ + shape2->geometry = (GEOSGeom)msGEOSShape2Geometry(shape2); + g2 = (GEOSGeom)shape2->geometry; + if (!g2) + return -1; + + result = GEOSTouches_r(handle, g1, g2); + return ((result == 2) ? -1 : result); +#else + msSetError(MS_GEOSERR, "GEOS support is not available.", "msGEOSTouches()"); + return -1; +#endif +} + +/* +** Does shape1 equal shape2, returns MS_TRUE/MS_FALSE or -1 for an error. +*/ +int msGEOSEquals(shapeObj *shape1, shapeObj *shape2) { +#ifdef USE_GEOS + GEOSGeom g1, g2; + int result; + GEOSContextHandle_t handle = msGetGeosContextHandle(); + + if (!shape1 || !shape2) + return -1; + + if (!shape1->geometry) /* if no geometry for shape1 then build one */ + shape1->geometry = (GEOSGeom)msGEOSShape2Geometry(shape1); + g1 = (GEOSGeom)shape1->geometry; + if (!g1) + return -1; + + if (!shape2->geometry) /* if no geometry for shape2 then build one */ + shape2->geometry = (GEOSGeom)msGEOSShape2Geometry(shape2); + g2 = (GEOSGeom)shape2->geometry; + if (!g2) + return -1; + + result = GEOSEquals_r(handle, g1, g2); + return ((result == 2) ? -1 : result); +#else + msSetError(MS_GEOSERR, "GEOS support is not available.", "msGEOSEquals()"); + return -1; +#endif +} + +/* +** Are shape1 and shape2 disjoint, returns MS_TRUE/MS_FALSE or -1 for an error. +*/ +int msGEOSDisjoint(shapeObj *shape1, shapeObj *shape2) { +#ifdef USE_GEOS + GEOSGeom g1, g2; + int result; + GEOSContextHandle_t handle = msGetGeosContextHandle(); + + if (!shape1 || !shape2) + return -1; + + if (!shape1->geometry) /* if no geometry for shape1 then build one */ + shape1->geometry = (GEOSGeom)msGEOSShape2Geometry(shape1); + g1 = (GEOSGeom)shape1->geometry; + if (!g1) + return -1; + + if (!shape2->geometry) /* if no geometry for shape2 then build one */ + shape2->geometry = (GEOSGeom)msGEOSShape2Geometry(shape2); + g2 = (GEOSGeom)shape2->geometry; + if (!g2) + return -1; + + result = GEOSDisjoint_r(handle, g1, g2); + return ((result == 2) ? -1 : result); +#else + msSetError(MS_GEOSERR, "GEOS support is not available.", "msGEOSDisjoint()"); + return -1; +#endif +} + +/* +** Useful misc. functions that return -1 on failure. +*/ +double msGEOSArea(shapeObj *shape) { +#if defined(USE_GEOS) && defined(GEOS_CAPI_VERSION_MAJOR) && \ + defined(GEOS_CAPI_VERSION_MINOR) && \ + (GEOS_CAPI_VERSION_MAJOR > 1 || GEOS_CAPI_VERSION_MINOR >= 1) + GEOSGeom g; + double area; + int result; + GEOSContextHandle_t handle = msGetGeosContextHandle(); + + if (!shape) + return -1; + + if (!shape->geometry) /* if no geometry for the shape then build one */ + shape->geometry = (GEOSGeom)msGEOSShape2Geometry(shape); + g = (GEOSGeom)shape->geometry; + if (!g) + return -1; + + result = GEOSArea_r(handle, g, &area); + return ((result == 0) ? -1 : area); +#elif defined(USE_GEOS) + msSetError(MS_GEOSERR, + "GEOS support enabled, but old version lacks GEOSArea().", + "msGEOSArea()"); + return -1; +#else + msSetError(MS_GEOSERR, "GEOS support is not available.", "msGEOSArea()"); + return -1; +#endif +} + +double msGEOSLength(shapeObj *shape) { +#if defined(USE_GEOS) && defined(GEOS_CAPI_VERSION_MAJOR) && \ + defined(GEOS_CAPI_VERSION_MINOR) && \ + (GEOS_CAPI_VERSION_MAJOR > 1 || GEOS_CAPI_VERSION_MINOR >= 1) + + GEOSGeom g; + double length; + int result; + GEOSContextHandle_t handle = msGetGeosContextHandle(); + + if (!shape) + return -1; + + if (!shape->geometry) /* if no geometry for the shape then build one */ + shape->geometry = (GEOSGeom)msGEOSShape2Geometry(shape); + g = (GEOSGeom)shape->geometry; + if (!g) + return -1; + + result = GEOSLength_r(handle, g, &length); + return ((result == 0) ? -1 : length); +#elif defined(USE_GEOS) + msSetError(MS_GEOSERR, + "GEOS support enabled, but old version lacks GEOSLength().", + "msGEOSLength()"); + return -1; +#else + msSetError(MS_GEOSERR, "GEOS support is not available.", "msGEOSLength()"); + return -1; +#endif +} + +double msGEOSDistance(shapeObj *shape1, shapeObj *shape2) { +#ifdef USE_GEOS + GEOSGeom g1, g2; + double distance; + int result; + GEOSContextHandle_t handle = msGetGeosContextHandle(); + + if (!shape1 || !shape2) + return -1; + + if (!shape1->geometry) /* if no geometry for shape1 then build one */ + shape1->geometry = (GEOSGeom)msGEOSShape2Geometry(shape1); + g1 = (GEOSGeom)shape1->geometry; + if (!g1) + return -1; + + if (!shape2->geometry) /* if no geometry for shape2 then build one */ + shape2->geometry = (GEOSGeom)msGEOSShape2Geometry(shape2); + g2 = (GEOSGeom)shape2->geometry; + if (!g2) + return -1; + + result = GEOSDistance_r(handle, g1, g2, &distance); + return ((result == 0) ? -1 : distance); +#else + return msDistanceShapeToShape( + shape1, shape2); /* fall back on brute force method (for MapScript) */ +#endif +} diff --git a/src/mapgml.c b/src/mapgml.c new file mode 100644 index 0000000000..4c4b8290c3 --- /dev/null +++ b/src/mapgml.c @@ -0,0 +1,2546 @@ +/****************************************************************************** + * $Id$ + * + * Project: MapServer + * Purpose: shapeObj to GML output via MapServer queries. + * Author: Steve Lime and the MapServer team. + * + ****************************************************************************** + * Copyright (c) 1996-2005 Regents of the University of Minnesota. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + ****************************************************************************/ + +#include "mapserver.h" +#include "maperror.h" +#include "mapows.h" +#include "mapgml.h" +#include "maptime.h" + +/* Use only mapgml.c if WMS or WFS is available (with minor exceptions at end) + */ + +#if defined(USE_WMS_SVR) || defined(USE_WFS_SVR) + +static int msGMLGeometryLookup(gmlGeometryListObj *geometryList, + const char *type); + +/* +** Functions that write the feature boundary geometry (i.e. a rectObj). +*/ + +/* GML 2.1.2 */ +static int gmlWriteBounds_GML2(FILE *stream, rectObj *rect, const char *srsname, + const char *tab, const char *pszTopPrefix) { + char *srsname_encoded; + + if (!stream) + return (MS_FAILURE); + if (!rect) + return (MS_FAILURE); + if (!tab) + return (MS_FAILURE); + + msIO_fprintf(stream, "%s<%s:boundedBy>\n", tab, pszTopPrefix); + if (srsname) { + srsname_encoded = msEncodeHTMLEntities(srsname); + msIO_fprintf(stream, "%s\t\n", tab, + srsname_encoded); + msFree(srsname_encoded); + } else + msIO_fprintf(stream, "%s\t\n", tab); + + msIO_fprintf(stream, "%s\t\t", tab); + msIO_fprintf(stream, "%.6f,%.6f %.6f,%.6f", rect->minx, rect->miny, + rect->maxx, rect->maxy); + msIO_fprintf(stream, "\n"); + msIO_fprintf(stream, "%s\t\n", tab); + msIO_fprintf(stream, "%s\n", tab, pszTopPrefix); + + return MS_SUCCESS; +} + +/* GML 3.1 or GML 3.2 (MapServer limits GML encoding to the level 0 profile) */ +static int gmlWriteBounds_GML3(FILE *stream, rectObj *rect, const char *srsname, + const char *tab, const char *pszTopPrefix) { + char *srsname_encoded; + + if (!stream) + return (MS_FAILURE); + if (!rect) + return (MS_FAILURE); + if (!tab) + return (MS_FAILURE); + + msIO_fprintf(stream, "%s<%s:boundedBy>\n", tab, pszTopPrefix); + if (srsname) { + srsname_encoded = msEncodeHTMLEntities(srsname); + msIO_fprintf(stream, "%s\t\n", tab, + srsname_encoded); + msFree(srsname_encoded); + } else + msIO_fprintf(stream, "%s\t\n", tab); + + msIO_fprintf(stream, "%s\t\t%.6f %.6f\n", + tab, rect->minx, rect->miny); + msIO_fprintf(stream, "%s\t\t%.6f %.6f\n", + tab, rect->maxx, rect->maxy); + + msIO_fprintf(stream, "%s\t\n", tab); + msIO_fprintf(stream, "%s\n", tab, pszTopPrefix); + + return MS_SUCCESS; +} + +static void gmlStartGeometryContainer(FILE *stream, const char *name, + const char *namespace, const char *tab) { + const char *tag_name = OWS_GML_DEFAULT_GEOMETRY_NAME; + + if (name) + tag_name = name; + + if (namespace) + msIO_fprintf(stream, "%s<%s:%s>\n", tab, namespace, tag_name); + else + msIO_fprintf(stream, "%s<%s>\n", tab, tag_name); +} + +static void gmlEndGeometryContainer(FILE *stream, const char *name, + const char *namespace, const char *tab) { + const char *tag_name = OWS_GML_DEFAULT_GEOMETRY_NAME; + + if (name) + tag_name = name; + + if (namespace) + msIO_fprintf(stream, "%s\n", tab, namespace, tag_name); + else + msIO_fprintf(stream, "%s\n", tab, tag_name); +} + +/* GML 2.1.2 */ +static int gmlWriteGeometry_GML2(FILE *stream, gmlGeometryListObj *geometryList, + shapeObj *shape, const char *srsname, + const char *namespace, const char *tab, + int nSRSDimension, int geometry_precision) { + int i, j, k; + int *innerlist, *outerlist = NULL, numouters; + char *srsname_encoded = NULL; + + int geometry_aggregate_index, geometry_simple_index; + char *geometry_aggregate_name = NULL, *geometry_simple_name = NULL; + + if (!stream) + return (MS_FAILURE); + if (!shape) + return (MS_FAILURE); + if (!tab) + return (MS_FAILURE); + if (!geometryList) + return (MS_FAILURE); + + if (shape->numlines <= 0) + return (MS_SUCCESS); /* empty shape, nothing to output */ + + if (srsname) + srsname_encoded = msEncodeHTMLEntities(srsname); + + /* feature geometry */ + switch (shape->type) { + case (MS_SHAPE_POINT): + geometry_simple_index = msGMLGeometryLookup(geometryList, "point"); + geometry_aggregate_index = msGMLGeometryLookup(geometryList, "multipoint"); + if (geometry_simple_index >= 0) + geometry_simple_name = + geometryList->geometries[geometry_simple_index].name; + if (geometry_aggregate_index >= 0) + geometry_aggregate_name = + geometryList->geometries[geometry_aggregate_index].name; + + if ((geometry_simple_index != -1 && shape->line[0].numpoints == 1 && + shape->numlines == 1) || + (geometry_simple_index != -1 && geometry_aggregate_index == -1) || + (geometryList->numgeometries == 0 && shape->line[0].numpoints == 1 && + shape->numlines == 1)) { /* write a Point(s) */ + + for (i = 0; i < shape->numlines; i++) { + for (j = 0; j < shape->line[i].numpoints; j++) { + gmlStartGeometryContainer(stream, geometry_simple_name, namespace, + tab); + + /* Point */ + if (srsname_encoded) + msIO_fprintf(stream, "%s\n", tab, + srsname_encoded); + else + msIO_fprintf(stream, "%s\n", tab); + + if (nSRSDimension == 3) + msIO_fprintf( + stream, + "%s %.*f,%.*f,%.*f\n", tab, + geometry_precision, shape->line[i].point[j].x, + geometry_precision, shape->line[i].point[j].y, + geometry_precision, shape->line[i].point[j].z); + else + /* fall-through */ + + msIO_fprintf(stream, + "%s %.*f,%.*f\n", + tab, geometry_precision, shape->line[i].point[j].x, + geometry_precision, shape->line[i].point[j].y); + + msIO_fprintf(stream, "%s\n", tab); + + gmlEndGeometryContainer(stream, geometry_simple_name, namespace, tab); + } + } + } else if ((geometry_aggregate_index != -1) || + (geometryList->numgeometries == 0)) { /* write a MultiPoint */ + gmlStartGeometryContainer(stream, geometry_aggregate_name, namespace, + tab); + + /* MultiPoint */ + if (srsname_encoded) + msIO_fprintf(stream, "%s\n", tab, + srsname_encoded); + else + msIO_fprintf(stream, "%s\n", tab); + + for (i = 0; i < shape->numlines; i++) { + for (j = 0; j < shape->line[i].numpoints; j++) { + msIO_fprintf(stream, "%s \n", tab); + msIO_fprintf(stream, "%s \n", tab); + if (nSRSDimension == 3) + msIO_fprintf( + stream, + "%s %.*f,%.*f,%.*f\n", + tab, geometry_precision, shape->line[i].point[j].x, + geometry_precision, shape->line[i].point[j].y, + geometry_precision, shape->line[i].point[j].z); + else + /* fall-through */ + msIO_fprintf( + stream, "%s %f,%f\n", + tab, shape->line[i].point[j].x, shape->line[i].point[j].y); + msIO_fprintf(stream, "%s \n", tab); + msIO_fprintf(stream, "%s \n", tab); + } + } + + msIO_fprintf(stream, "%s\n", tab); + + gmlEndGeometryContainer(stream, geometry_aggregate_name, namespace, tab); + } else { + msIO_fprintf(stream, "\n"); + } + + break; + case (MS_SHAPE_LINE): + geometry_simple_index = msGMLGeometryLookup(geometryList, "line"); + geometry_aggregate_index = msGMLGeometryLookup(geometryList, "multiline"); + if (geometry_simple_index >= 0) + geometry_simple_name = + geometryList->geometries[geometry_simple_index].name; + if (geometry_aggregate_index >= 0) + geometry_aggregate_name = + geometryList->geometries[geometry_aggregate_index].name; + + if ((geometry_simple_index != -1 && shape->numlines == 1) || + (geometry_simple_index != -1 && geometry_aggregate_index == -1) || + (geometryList->numgeometries == 0 && + shape->numlines == 1)) { /* write a LineStrings(s) */ + for (i = 0; i < shape->numlines; i++) { + gmlStartGeometryContainer(stream, geometry_simple_name, namespace, tab); + + /* LineString */ + if (srsname_encoded) + msIO_fprintf(stream, "%s\n", tab, + srsname_encoded); + else + msIO_fprintf(stream, "%s\n", tab); + + msIO_fprintf(stream, "%s ", tab); + for (j = 0; j < shape->line[i].numpoints; j++) { + if (nSRSDimension == 3) + msIO_fprintf(stream, "%.*f,%.*f,%.*f ", geometry_precision, + shape->line[i].point[j].x, geometry_precision, + shape->line[i].point[j].y, geometry_precision, + shape->line[i].point[j].z); + else + /* fall-through */ + msIO_fprintf(stream, "%.*f,%.*f ", geometry_precision, + shape->line[i].point[j].x, geometry_precision, + shape->line[i].point[j].y); + } + msIO_fprintf(stream, "\n"); + + msIO_fprintf(stream, "%s\n", tab); + + gmlEndGeometryContainer(stream, geometry_simple_name, namespace, tab); + } + } else if (geometry_aggregate_index != -1 || + (geometryList->numgeometries == 0)) { /* write a MultiCurve */ + gmlStartGeometryContainer(stream, geometry_aggregate_name, namespace, + tab); + + /* MultiLineString */ + if (srsname_encoded) + msIO_fprintf(stream, "%s\n", tab, + srsname_encoded); + else + msIO_fprintf(stream, "%s\n", tab); + + for (j = 0; j < shape->numlines; j++) { + msIO_fprintf(stream, "%s \n", + tab); /* no srsname at this point */ + msIO_fprintf(stream, "%s \n", + tab); /* no srsname at this point */ + + msIO_fprintf(stream, "%s ", tab); + for (i = 0; i < shape->line[j].numpoints; i++) { + if (nSRSDimension == 3) + msIO_fprintf(stream, "%.*f,%.*f,%.*f ", geometry_precision, + shape->line[j].point[i].x, geometry_precision, + shape->line[j].point[i].y, geometry_precision, + shape->line[j].point[i].z); + else + /* fall-through */ + msIO_fprintf(stream, "%.*f,%.*f ", geometry_precision, + shape->line[j].point[i].x, geometry_precision, + shape->line[j].point[i].y); + } + msIO_fprintf(stream, "\n"); + msIO_fprintf(stream, "%s \n", tab); + msIO_fprintf(stream, "%s \n", tab); + } + + msIO_fprintf(stream, "%s\n", tab); + + gmlEndGeometryContainer(stream, geometry_aggregate_name, namespace, tab); + } else { + msIO_fprintf(stream, "\n"); + } + + break; + case ( + MS_SHAPE_POLYGON): /* this gets nasty, since our shapes are so flexible */ + geometry_simple_index = msGMLGeometryLookup(geometryList, "polygon"); + geometry_aggregate_index = + msGMLGeometryLookup(geometryList, "multipolygon"); + if (geometry_simple_index >= 0) + geometry_simple_name = + geometryList->geometries[geometry_simple_index].name; + if (geometry_aggregate_index >= 0) + geometry_aggregate_name = + geometryList->geometries[geometry_aggregate_index].name; + + /* get a list of outer rings for this polygon */ + outerlist = msGetOuterList(shape); + + numouters = 0; + for (i = 0; i < shape->numlines; i++) + if (outerlist[i] == MS_TRUE) + numouters++; + + if ((geometry_simple_index != -1 && numouters == 1) || + (geometry_simple_index != -1 && geometry_aggregate_index == -1) || + (geometryList->numgeometries == 0 && + shape->numlines == 1)) { /* write a Polygon(s) */ + for (i = 0; i < shape->numlines; i++) { + if (outerlist[i] == MS_FALSE) + break; /* skip non-outer rings, each outer ring is a new polygon */ + + /* get a list of inner rings for this polygon */ + innerlist = msGetInnerList(shape, i, outerlist); + + gmlStartGeometryContainer(stream, geometry_simple_name, namespace, tab); + + /* Polygon */ + if (srsname_encoded) + msIO_fprintf(stream, "%s\n", tab, + srsname_encoded); + else + msIO_fprintf(stream, "%s\n", tab); + + msIO_fprintf(stream, "%s \n", tab); + msIO_fprintf(stream, "%s \n", tab); + + msIO_fprintf(stream, "%s ", tab); + for (j = 0; j < shape->line[i].numpoints; j++) { + if (nSRSDimension == 3) + msIO_fprintf(stream, "%.*f,%.*f,%.*f ", geometry_precision, + shape->line[i].point[j].x, geometry_precision, + shape->line[i].point[j].y, geometry_precision, + shape->line[i].point[j].z); + else + /* fall-through */ + msIO_fprintf(stream, "%.*f,%.*f ", geometry_precision, + shape->line[i].point[j].x, geometry_precision, + shape->line[i].point[j].y); + } + msIO_fprintf(stream, "\n"); + + msIO_fprintf(stream, "%s \n", tab); + msIO_fprintf(stream, "%s \n", tab); + + for (k = 0; k < shape->numlines; + k++) { /* now step through all the inner rings */ + if (innerlist[k] == MS_TRUE) { + msIO_fprintf(stream, "%s \n", tab); + msIO_fprintf(stream, "%s \n", tab); + + msIO_fprintf(stream, "%s ", tab); + for (j = 0; j < shape->line[k].numpoints; j++) { + if (nSRSDimension == 3) + msIO_fprintf(stream, "%.*f,%.*f,%.*f ", geometry_precision, + shape->line[k].point[j].x, geometry_precision, + shape->line[k].point[j].y, geometry_precision, + shape->line[k].point[j].z); + else + /* fall-through */ + msIO_fprintf(stream, "%.*f,%.*f ", geometry_precision, + shape->line[k].point[j].x, geometry_precision, + shape->line[k].point[j].y); + } + msIO_fprintf(stream, "\n"); + + msIO_fprintf(stream, "%s \n", tab); + msIO_fprintf(stream, "%s \n", tab); + } + } + + msIO_fprintf(stream, "%s\n", tab); + free(innerlist); + + gmlEndGeometryContainer(stream, geometry_simple_name, namespace, tab); + } + free(outerlist); + outerlist = NULL; + } else if (geometry_aggregate_index != -1 || + (geometryList->numgeometries == 0)) { /* write a MultiPolygon */ + gmlStartGeometryContainer(stream, geometry_aggregate_name, namespace, + tab); + + /* MultiPolygon */ + if (srsname_encoded) + msIO_fprintf(stream, "%s\n", tab, + srsname_encoded); + else + msIO_fprintf(stream, "%s\n", tab); + + for (i = 0; i < shape->numlines; i++) { /* step through the outer rings */ + if (outerlist[i] == MS_TRUE) { + innerlist = msGetInnerList(shape, i, outerlist); + + msIO_fprintf(stream, "%s\n", tab); + msIO_fprintf(stream, "%s \n", tab); + + msIO_fprintf(stream, "%s \n", tab); + msIO_fprintf(stream, "%s \n", tab); + + msIO_fprintf(stream, "%s ", tab); + for (j = 0; j < shape->line[i].numpoints; j++) { + if (nSRSDimension == 3) + msIO_fprintf(stream, "%.*f,%.*f,%.*f ", geometry_precision, + shape->line[i].point[j].x, geometry_precision, + shape->line[i].point[j].y, geometry_precision, + shape->line[i].point[j].z); + else + /* fall-through */ + msIO_fprintf(stream, "%.*f,%.*f ", geometry_precision, + shape->line[i].point[j].x, geometry_precision, + shape->line[i].point[j].y); + } + msIO_fprintf(stream, "\n"); + + msIO_fprintf(stream, "%s \n", tab); + msIO_fprintf(stream, "%s \n", tab); + + for (k = 0; k < shape->numlines; + k++) { /* now step through all the inner rings */ + if (innerlist[k] == MS_TRUE) { + msIO_fprintf(stream, "%s \n", tab); + msIO_fprintf(stream, "%s \n", tab); + + msIO_fprintf(stream, "%s ", tab); + for (j = 0; j < shape->line[k].numpoints; j++) { + if (nSRSDimension == 3) + msIO_fprintf(stream, "%.*f,%.*f,%.*f ", geometry_precision, + shape->line[k].point[j].x, geometry_precision, + shape->line[k].point[j].y, geometry_precision, + shape->line[k].point[j].z); + else + /* fall-through */ + msIO_fprintf(stream, "%.*f,%.*f ", geometry_precision, + shape->line[k].point[j].x, geometry_precision, + shape->line[k].point[j].y); + } + msIO_fprintf(stream, "\n"); + + msIO_fprintf(stream, "%s \n", tab); + msIO_fprintf(stream, "%s \n", tab); + } + } + + msIO_fprintf(stream, "%s \n", tab); + msIO_fprintf(stream, "%s\n", tab); + + free(innerlist); + } + } + msIO_fprintf(stream, "%s\n", tab); + + free(outerlist); + outerlist = NULL; + + gmlEndGeometryContainer(stream, geometry_aggregate_name, namespace, tab); + } else { + msIO_fprintf(stream, "\n"); + } + + break; + default: + break; + } + + /* clean-up */ + msFree(srsname_encoded); + msFree(outerlist); + + return (MS_SUCCESS); +} + +static char *gmlCreateGeomId(OWSGMLVersion nGMLVersion, const char *pszFID, + int *p_id) { + char *pszGMLId; + if (nGMLVersion == OWS_GML32) { + pszGMLId = + (char *)msSmallMalloc(strlen(pszFID) + 1 + strlen(" gml:id=\"\"") + 10); + sprintf(pszGMLId, " gml:id=\"%s.%d\"", pszFID, *p_id); + (*p_id)++; + } else + pszGMLId = msStrdup(""); + return pszGMLId; +} + +/* GML 3.1 or GML 3.2 (MapServer limits GML encoding to the level 0 profile) */ +static int gmlWriteGeometry_GML3(FILE *stream, gmlGeometryListObj *geometryList, + shapeObj *shape, const char *srsname, + const char *namespace, const char *tab, + const char *pszFID, OWSGMLVersion nGMLVersion, + int nSRSDimension, int geometry_precision) { + int i, j, k, id = 1; + int *innerlist, *outerlist = NULL, numouters; + char *srsname_encoded = NULL; + char *pszGMLId; + + int geometry_aggregate_index, geometry_simple_index; + char *geometry_aggregate_name = NULL, *geometry_simple_name = NULL; + + if (!stream) + return (MS_FAILURE); + if (!shape) + return (MS_FAILURE); + if (!tab) + return (MS_FAILURE); + if (!geometryList) + return (MS_FAILURE); + + if (shape->numlines <= 0) + return (MS_SUCCESS); /* empty shape, nothing to output */ + + if (srsname) + srsname_encoded = msEncodeHTMLEntities(srsname); + + /* feature geometry */ + switch (shape->type) { + case (MS_SHAPE_POINT): + geometry_simple_index = msGMLGeometryLookup(geometryList, "point"); + geometry_aggregate_index = msGMLGeometryLookup(geometryList, "multipoint"); + if (geometry_simple_index >= 0) + geometry_simple_name = + geometryList->geometries[geometry_simple_index].name; + if (geometry_aggregate_index >= 0) + geometry_aggregate_name = + geometryList->geometries[geometry_aggregate_index].name; + + if ((geometry_simple_index != -1 && shape->line[0].numpoints == 1 && + shape->numlines == 1) || + (geometry_simple_index != -1 && geometry_aggregate_index == -1) || + (geometryList->numgeometries == 0 && shape->line[0].numpoints == 1 && + shape->numlines == 1)) { /* write a Point(s) */ + + for (i = 0; i < shape->numlines; i++) { + for (j = 0; j < shape->line[i].numpoints; j++) { + gmlStartGeometryContainer(stream, geometry_simple_name, namespace, + tab); + + /* Point */ + pszGMLId = gmlCreateGeomId(nGMLVersion, pszFID, &id); + if (srsname_encoded) + msIO_fprintf(stream, "%s \n", tab, + pszGMLId, srsname_encoded); + else + msIO_fprintf(stream, "%s \n", tab, pszGMLId); + + if (nSRSDimension == 3) + msIO_fprintf( + stream, + "%s %.*f %.*f %.*f\n", + tab, geometry_precision, shape->line[i].point[j].x, + geometry_precision, shape->line[i].point[j].y, + geometry_precision, shape->line[i].point[j].z); + else + /* fall-through */ + msIO_fprintf(stream, "%s %.*f %.*f\n", tab, + geometry_precision, shape->line[i].point[j].x, + geometry_precision, shape->line[i].point[j].y); + + msIO_fprintf(stream, "%s \n", tab); + + gmlEndGeometryContainer(stream, geometry_simple_name, namespace, tab); + msFree(pszGMLId); + } + } + } else if ((geometry_aggregate_index != -1) || + (geometryList->numgeometries == 0)) { /* write a MultiPoint */ + pszGMLId = gmlCreateGeomId(nGMLVersion, pszFID, &id); + gmlStartGeometryContainer(stream, geometry_aggregate_name, namespace, + tab); + + /* MultiPoint */ + if (srsname_encoded) + msIO_fprintf(stream, "%s \n", tab, + pszGMLId, srsname_encoded); + else + msIO_fprintf(stream, "%s \n", tab, pszGMLId); + + msFree(pszGMLId); + + for (i = 0; i < shape->numlines; i++) { + for (j = 0; j < shape->line[i].numpoints; j++) { + msIO_fprintf(stream, "%s \n", tab); + pszGMLId = gmlCreateGeomId(nGMLVersion, pszFID, &id); + msIO_fprintf(stream, "%s \n", tab, pszGMLId); + if (nSRSDimension == 3) + msIO_fprintf(stream, + "%s %.*f %.*f " + "%.*f\n", + tab, geometry_precision, shape->line[i].point[j].x, + geometry_precision, shape->line[i].point[j].y, + geometry_precision, shape->line[i].point[j].z); + else + /* fall-through */ + msIO_fprintf(stream, "%s %.*f %.*f\n", + tab, geometry_precision, shape->line[i].point[j].x, + geometry_precision, shape->line[i].point[j].y); + msIO_fprintf(stream, "%s \n", tab); + msFree(pszGMLId); + msIO_fprintf(stream, "%s \n", tab); + } + } + + msIO_fprintf(stream, "%s \n", tab); + + gmlEndGeometryContainer(stream, geometry_aggregate_name, namespace, tab); + } else { + msIO_fprintf(stream, "\n"); + } + + break; + case (MS_SHAPE_LINE): + geometry_simple_index = msGMLGeometryLookup(geometryList, "line"); + geometry_aggregate_index = msGMLGeometryLookup(geometryList, "multiline"); + if (geometry_simple_index >= 0) + geometry_simple_name = + geometryList->geometries[geometry_simple_index].name; + if (geometry_aggregate_index >= 0) + geometry_aggregate_name = + geometryList->geometries[geometry_aggregate_index].name; + + if ((geometry_simple_index != -1 && shape->numlines == 1) || + (geometry_simple_index != -1 && geometry_aggregate_index == -1) || + (geometryList->numgeometries == 0 && + shape->numlines == 1)) { /* write a LineStrings(s) */ + for (i = 0; i < shape->numlines; i++) { + gmlStartGeometryContainer(stream, geometry_simple_name, namespace, tab); + + /* LineString (should be Curve?) */ + pszGMLId = gmlCreateGeomId(nGMLVersion, pszFID, &id); + if (srsname_encoded) + msIO_fprintf(stream, "%s \n", tab, + pszGMLId, srsname_encoded); + else + msIO_fprintf(stream, "%s \n", tab, pszGMLId); + msFree(pszGMLId); + + msIO_fprintf(stream, "%s ", tab, + nSRSDimension); + for (j = 0; j < shape->line[i].numpoints; j++) { + if (nSRSDimension == 3) + msIO_fprintf(stream, "%.*f %.*f %.*f ", geometry_precision, + shape->line[i].point[j].x, geometry_precision, + shape->line[i].point[j].y, geometry_precision, + shape->line[i].point[j].z); + else + /* fall-through */ + msIO_fprintf(stream, "%.*f %.*f ", geometry_precision, + shape->line[i].point[j].x, geometry_precision, + shape->line[i].point[j].y); + } + msIO_fprintf(stream, "\n"); + + msIO_fprintf(stream, "%s \n", tab); + + gmlEndGeometryContainer(stream, geometry_simple_name, namespace, tab); + } + } else if (geometry_aggregate_index != -1 || + (geometryList->numgeometries == 0)) { /* write a MultiCurve */ + gmlStartGeometryContainer(stream, geometry_aggregate_name, namespace, + tab); + + /* MultiCurve */ + pszGMLId = gmlCreateGeomId(nGMLVersion, pszFID, &id); + if (srsname_encoded) + msIO_fprintf(stream, "%s \n", tab, + pszGMLId, srsname_encoded); + else + msIO_fprintf(stream, "%s \n", tab, pszGMLId); + msFree(pszGMLId); + + for (i = 0; i < shape->numlines; i++) { + msIO_fprintf(stream, "%s \n", tab); + pszGMLId = gmlCreateGeomId(nGMLVersion, pszFID, &id); + msIO_fprintf(stream, "%s \n", tab, + pszGMLId); /* no srsname at this point */ + msFree(pszGMLId); + + msIO_fprintf(stream, "%s ", tab, + nSRSDimension); + for (j = 0; j < shape->line[i].numpoints; j++) { + if (nSRSDimension == 3) + msIO_fprintf(stream, "%.*f %.*f %.*f ", geometry_precision, + shape->line[i].point[j].x, geometry_precision, + shape->line[i].point[j].y, geometry_precision, + shape->line[i].point[j].z); + else + /* fall-through */ + msIO_fprintf(stream, "%.*f %.*f ", geometry_precision, + shape->line[i].point[j].x, geometry_precision, + shape->line[i].point[j].y); + } + + msIO_fprintf(stream, "\n"); + msIO_fprintf(stream, "%s \n", tab); + msIO_fprintf(stream, "%s \n", tab); + } + + msIO_fprintf(stream, "%s \n", tab); + + gmlEndGeometryContainer(stream, geometry_aggregate_name, namespace, tab); + } else { + msIO_fprintf(stream, "\n"); + } + + break; + case ( + MS_SHAPE_POLYGON): /* this gets nasty, since our shapes are so flexible */ + geometry_simple_index = msGMLGeometryLookup(geometryList, "polygon"); + geometry_aggregate_index = + msGMLGeometryLookup(geometryList, "multipolygon"); + if (geometry_simple_index >= 0) + geometry_simple_name = + geometryList->geometries[geometry_simple_index].name; + if (geometry_aggregate_index >= 0) + geometry_aggregate_name = + geometryList->geometries[geometry_aggregate_index].name; + + /* get a list of outer rings for this polygon */ + outerlist = msGetOuterList(shape); + + numouters = 0; + for (i = 0; i < shape->numlines; i++) + if (outerlist[i] == MS_TRUE) + numouters++; + + if ((geometry_simple_index != -1 && numouters == 1) || + (geometry_simple_index != -1 && geometry_aggregate_index == -1) || + (geometryList->numgeometries == 0 && + shape->numlines == 1)) { /* write a Polygon(s) */ + for (i = 0; i < shape->numlines; i++) { + if (outerlist[i] == MS_FALSE) + break; /* skip non-outer rings, each outer ring is a new polygon */ + + /* get a list of inner rings for this polygon */ + innerlist = msGetInnerList(shape, i, outerlist); + + gmlStartGeometryContainer(stream, geometry_simple_name, namespace, tab); + + pszGMLId = gmlCreateGeomId(nGMLVersion, pszFID, &id); + + /* Polygon (should be Surface?) */ + if (srsname_encoded) + msIO_fprintf(stream, "%s \n", tab, + pszGMLId, srsname_encoded); + else + msIO_fprintf(stream, "%s \n", tab, pszGMLId); + msFree(pszGMLId); + + msIO_fprintf(stream, "%s \n", tab); + msIO_fprintf(stream, "%s \n", tab); + + msIO_fprintf(stream, "%s ", tab, + nSRSDimension); + for (j = 0; j < shape->line[i].numpoints; j++) { + if (nSRSDimension == 3) + msIO_fprintf(stream, "%.*f %.*f %.*f ", geometry_precision, + shape->line[i].point[j].x, geometry_precision, + shape->line[i].point[j].y, geometry_precision, + shape->line[i].point[j].z); + else + /* fall-through */ + msIO_fprintf(stream, "%.*f %.*f ", geometry_precision, + shape->line[i].point[j].x, geometry_precision, + shape->line[i].point[j].y); + } + + msIO_fprintf(stream, "\n"); + + msIO_fprintf(stream, "%s \n", tab); + msIO_fprintf(stream, "%s \n", tab); + + for (k = 0; k < shape->numlines; + k++) { /* now step through all the inner rings */ + if (innerlist[k] == MS_TRUE) { + msIO_fprintf(stream, "%s \n", tab); + msIO_fprintf(stream, "%s \n", tab); + + msIO_fprintf(stream, "%s ", + tab, nSRSDimension); + for (j = 0; j < shape->line[k].numpoints; j++) { + if (nSRSDimension == 3) + msIO_fprintf(stream, "%.*f %.*f %.*f ", geometry_precision, + shape->line[k].point[j].x, geometry_precision, + shape->line[k].point[j].y, geometry_precision, + shape->line[k].point[j].z); + else + /* fall-through */ + msIO_fprintf(stream, "%.*f %.*f ", geometry_precision, + shape->line[k].point[j].x, geometry_precision, + shape->line[k].point[j].y); + } + + msIO_fprintf(stream, "\n"); + + msIO_fprintf(stream, "%s \n", tab); + msIO_fprintf(stream, "%s \n", tab); + } + } + + msIO_fprintf(stream, "%s \n", tab); + free(innerlist); + + gmlEndGeometryContainer(stream, geometry_simple_name, namespace, tab); + } + free(outerlist); + outerlist = NULL; + } else if (geometry_aggregate_index != -1 || + (geometryList->numgeometries == 0)) { /* write a MultiSurface */ + gmlStartGeometryContainer(stream, geometry_aggregate_name, namespace, + tab); + + pszGMLId = gmlCreateGeomId(nGMLVersion, pszFID, &id); + + /* MultiSurface */ + if (srsname_encoded) + msIO_fprintf(stream, "%s \n", tab, + pszGMLId, srsname_encoded); + else + msIO_fprintf(stream, "%s \n", tab, pszGMLId); + msFree(pszGMLId); + + for (i = 0; i < shape->numlines; i++) { /* step through the outer rings */ + if (outerlist[i] == MS_TRUE) { + msIO_fprintf(stream, "%s \n", tab); + + /* get a list of inner rings for this polygon */ + innerlist = msGetInnerList(shape, i, outerlist); + + pszGMLId = gmlCreateGeomId(nGMLVersion, pszFID, &id); + + msIO_fprintf(stream, "%s \n", tab, pszGMLId); + msFree(pszGMLId); + + msIO_fprintf(stream, "%s \n", tab); + msIO_fprintf(stream, "%s \n", tab); + + msIO_fprintf(stream, + "%s ", tab, + nSRSDimension); + for (j = 0; j < shape->line[i].numpoints; j++) { + if (nSRSDimension == 3) + msIO_fprintf(stream, "%.*f %.*f %.*f ", geometry_precision, + shape->line[i].point[j].x, geometry_precision, + shape->line[i].point[j].y, geometry_precision, + shape->line[i].point[j].z); + else + /* fall-through */ + msIO_fprintf(stream, "%.*f %.*f ", geometry_precision, + shape->line[i].point[j].x, geometry_precision, + shape->line[i].point[j].y); + } + + msIO_fprintf(stream, "\n"); + + msIO_fprintf(stream, "%s \n", tab); + msIO_fprintf(stream, "%s \n", tab); + + for (k = 0; k < shape->numlines; + k++) { /* now step through all the inner rings */ + if (innerlist[k] == MS_TRUE) { + msIO_fprintf(stream, "%s \n", tab); + msIO_fprintf(stream, "%s \n", tab); + + msIO_fprintf(stream, + "%s ", + tab, nSRSDimension); + for (j = 0; j < shape->line[k].numpoints; j++) { + if (nSRSDimension == 3) + msIO_fprintf(stream, "%.*f %.*f %.*f ", geometry_precision, + shape->line[k].point[j].x, geometry_precision, + shape->line[k].point[j].y, geometry_precision, + shape->line[k].point[j].z); + else + /* fall-through */ + msIO_fprintf(stream, "%.*f %.*f ", geometry_precision, + shape->line[k].point[j].x, geometry_precision, + shape->line[k].point[j].y); + } + msIO_fprintf(stream, "\n"); + + msIO_fprintf(stream, "%s \n", tab); + msIO_fprintf(stream, "%s \n", tab); + } + } + + msIO_fprintf(stream, "%s \n", tab); + + free(innerlist); + msIO_fprintf(stream, "%s \n", tab); + } + } + msIO_fprintf(stream, "%s \n", tab); + + free(outerlist); + outerlist = NULL; + + gmlEndGeometryContainer(stream, geometry_aggregate_name, namespace, tab); + } else { + msIO_fprintf(stream, "\n"); + } + + break; + default: + break; + } + + /* clean-up */ + msFree(outerlist); + msFree(srsname_encoded); + + return (MS_SUCCESS); +} + +/* +** Wrappers for the format specific encoding functions. +*/ +static int gmlWriteBounds(FILE *stream, OWSGMLVersion format, rectObj *rect, + const char *srsname, const char *tab, + const char *pszTopPrefix) { + switch (format) { + case (OWS_GML2): + return gmlWriteBounds_GML2(stream, rect, srsname, tab, pszTopPrefix); + break; + case (OWS_GML3): + case (OWS_GML32): + return gmlWriteBounds_GML3(stream, rect, srsname, tab, pszTopPrefix); + break; + default: + msSetError(MS_IOERR, "Unsupported GML format.", "gmlWriteBounds()"); + } + + return (MS_FAILURE); +} + +static int gmlWriteGeometry(FILE *stream, gmlGeometryListObj *geometryList, + OWSGMLVersion format, shapeObj *shape, + const char *srsname, const char *namespace, + const char *tab, const char *pszFID, + int nSRSDimension, int geometry_precision) { + switch (format) { + case (OWS_GML2): + return gmlWriteGeometry_GML2(stream, geometryList, shape, srsname, + namespace, tab, nSRSDimension, + geometry_precision); + break; + case (OWS_GML3): + case (OWS_GML32): + return gmlWriteGeometry_GML3(stream, geometryList, shape, srsname, + namespace, tab, pszFID, format, nSRSDimension, + geometry_precision); + break; + default: + msSetError(MS_IOERR, "Unsupported GML format.", "gmlWriteGeometry()"); + } + + return (MS_FAILURE); +} + +/* +** GML specific metadata handling functions. +*/ + +int msItemInGroups(const char *name, gmlGroupListObj *groupList) { + int i, j; + gmlGroupObj *group; + + if (!groupList) + return MS_FALSE; /* no groups */ + + for (i = 0; i < groupList->numgroups; i++) { + group = &(groupList->groups[i]); + for (j = 0; j < group->numitems; j++) { + if (strcasecmp(name, group->items[j]) == 0) + return MS_TRUE; + } + } + + return MS_FALSE; +} + +static int msGMLGeometryLookup(gmlGeometryListObj *geometryList, + const char *type) { + int i; + + if (!geometryList || !type) + return -1; /* nothing to look for */ + + for (i = 0; i < geometryList->numgeometries; i++) + if (geometryList->geometries[i].type && + (strcasecmp(geometryList->geometries[i].type, type) == 0)) + return i; + + if (geometryList->numgeometries == 1 && + geometryList->geometries[0].type == NULL) + return 0; + + return -1; /* not found */ +} + +gmlGeometryListObj *msGMLGetGeometries(layerObj *layer, + const char *metadata_namespaces, + int bWithDefaultGeom) { + int i; + + const char *value = NULL; + char tag[64]; + + char **names = NULL; + int numnames = 0; + + gmlGeometryListObj *geometryList = NULL; + gmlGeometryObj *geometry = NULL; + + /* allocate memory and initialize the item collection */ + geometryList = (gmlGeometryListObj *)malloc(sizeof(gmlGeometryListObj)); + MS_CHECK_ALLOC(geometryList, sizeof(gmlGeometryListObj), NULL); + geometryList->geometries = NULL; + geometryList->numgeometries = 0; + + if ((value = msOWSLookupMetadata(&(layer->metadata), metadata_namespaces, + "geometries")) != NULL) { + names = msStringSplit(value, ',', &numnames); + + /* allocation an array of gmlGeometryObj's */ + geometryList->numgeometries = numnames; + geometryList->geometries = (gmlGeometryObj *)malloc( + sizeof(gmlGeometryObj) * geometryList->numgeometries); + if (geometryList->geometries == NULL) { + msSetError( + MS_MEMERR, "Out of memory allocating %u bytes.\n", + "msGMLGetGeometries()", + (unsigned int)(sizeof(gmlGeometryObj) * geometryList->numgeometries)); + free(geometryList); + return NULL; + } + + for (i = 0; i < geometryList->numgeometries; i++) { + geometry = &(geometryList->geometries[i]); + + geometry->name = msStrdup(names[i]); /* initialize a few things */ + geometry->type = NULL; + geometry->occurmin = 0; + geometry->occurmax = 1; + + snprintf(tag, 64, "%s_type", names[i]); + if ((value = msOWSLookupMetadata(&(layer->metadata), metadata_namespaces, + tag)) != NULL) + geometry->type = msStrdup(value); /* TODO: validate input value */ + + snprintf(tag, 64, "%s_occurances", names[i]); + if ((value = msOWSLookupMetadata(&(layer->metadata), metadata_namespaces, + tag)) != NULL) { + char **occur; + int numoccur; + + occur = msStringSplit(value, ',', &numoccur); + if (numoccur == 2) { /* continue (TODO: throw an error if != 2) */ + geometry->occurmin = atof(occur[0]); + if (strcasecmp(occur[1], "UNBOUNDED") == 0) + geometry->occurmax = OWS_GML_OCCUR_UNBOUNDED; + else + geometry->occurmax = atof(occur[1]); + } + msFreeCharArray(occur, numoccur); + } + } + + msFreeCharArray(names, numnames); + } else if (bWithDefaultGeom) { + geometryList->numgeometries = 1; + geometryList->geometries = + (gmlGeometryObj *)calloc(1, sizeof(gmlGeometryObj)); + geometryList->geometries[0].name = msStrdup(OWS_GML_DEFAULT_GEOMETRY_NAME); + geometryList->geometries[0].type = NULL; + geometryList->geometries[0].occurmin = 0; + geometryList->geometries[0].occurmax = 1; + } + + return geometryList; +} + +void msGMLFreeGeometries(gmlGeometryListObj *geometryList) { + int i; + + if (!geometryList) + return; + + for (i = 0; i < geometryList->numgeometries; i++) { + msFree(geometryList->geometries[i].name); + msFree(geometryList->geometries[i].type); + } + free(geometryList->geometries); + + free(geometryList); +} + +static void msGMLWriteItem(FILE *stream, gmlItemObj *item, const char *value, + const char *namespace, const char *tab, + OWSGMLVersion outputformat, const char *pszFID) { + char *encoded_value = NULL, *tag_name; + int add_namespace = MS_TRUE; + char gmlid[256]; + gmlid[0] = 0; + + if (!stream || !item) + return; + if (!item->visible) + return; + + if (!namespace) + add_namespace = MS_FALSE; + + if (item->alias) + tag_name = item->alias; + else + tag_name = item->name; + if (strchr(tag_name, ':') != NULL) + add_namespace = MS_FALSE; + + if (item->type && + (EQUAL(item->type, "Date") || EQUAL(item->type, "DateTime") || + EQUAL(item->type, "Time"))) { + struct tm tm; + if (msParseTime(value, &tm) == MS_TRUE) { + const char *pszStartTag = ""; + const char *pszEndTag = ""; + + encoded_value = (char *)msSmallMalloc(256); + if (outputformat == OWS_GML32) { + if (pszFID != NULL) + snprintf(gmlid, 256, " gml:id=\"%s.%s\"", pszFID, tag_name); + pszStartTag = ""; + pszEndTag = ""; + } + + if (EQUAL(item->type, "Date")) + snprintf(encoded_value, 256, "%s%04d-%02d-%02d%s", pszStartTag, + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, pszEndTag); + else if (EQUAL(item->type, "Time")) + snprintf(encoded_value, 256, "%s%02d:%02d:%02dZ%s", pszStartTag, + tm.tm_hour, tm.tm_min, tm.tm_sec, pszEndTag); + else { + // Detected date time already formatted as YYYY-MM-DDTHH:mm:SS+ab:cd + // because msParseTime() can't handle time zones. + if (strlen(value) == + 4 + 1 + 2 + 1 + 2 + 1 + 2 + 1 + 2 + 1 + 2 + 1 + 2 + 1 + 2 && + value[4] == '-' && value[7] == '-' && value[10] == 'T' && + value[13] == ':' && value[16] == ':' && + (value[19] == '+' || value[19] == '-') && value[22] == ':') { + snprintf(encoded_value, 256, "%s%s%s", pszStartTag, value, pszEndTag); + } else { + snprintf(encoded_value, 256, "%s%04d-%02d-%02dT%02d:%02d:%02dZ%s", + pszStartTag, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec, pszEndTag); + } + } + } + } + + if (encoded_value == NULL) { + if (item->encode == MS_TRUE) + encoded_value = msEncodeHTMLEntities(value); + else + encoded_value = msStrdup(value); + } + + if (!item->template) { /* build the tag from pieces */ + + if (add_namespace == MS_TRUE && msIsXMLTagValid(tag_name) == MS_FALSE) + msIO_fprintf(stream, + "\n", + tag_name); + + if (add_namespace == MS_TRUE) + msIO_fprintf(stream, "%s<%s:%s%s>%s\n", tab, namespace, tag_name, + gmlid, encoded_value, namespace, tag_name); + else + msIO_fprintf(stream, "%s<%s%s>%s\n", tab, tag_name, gmlid, + encoded_value, tag_name); + } else { + char *tag = NULL; + + tag = msStrdup(item->template); + tag = msReplaceSubstring(tag, "$value", encoded_value); + if (namespace) + tag = msReplaceSubstring(tag, "$namespace", namespace); + msIO_fprintf(stream, "%s%s\n", tab, tag); + free(tag); + } + + free(encoded_value); + + return; +} + +gmlNamespaceListObj *msGMLGetNamespaces(webObj *web, + const char *metadata_namespaces) { + int i; + const char *value = NULL; + char tag[64]; + + char **prefixes = NULL; + int numprefixes = 0; + + gmlNamespaceListObj *namespaceList = NULL; + gmlNamespaceObj *namespace = NULL; + + /* allocate the collection */ + namespaceList = (gmlNamespaceListObj *)malloc(sizeof(gmlNamespaceListObj)); + MS_CHECK_ALLOC(namespaceList, sizeof(gmlNamespaceListObj), NULL); + namespaceList->namespaces = NULL; + namespaceList->numnamespaces = 0; + + /* list of namespaces (TODO: make this automatic by parsing metadata) */ + if ((value = msOWSLookupMetadata(&(web->metadata), metadata_namespaces, + "external_namespace_prefixes")) != NULL) { + prefixes = msStringSplit(value, ',', &numprefixes); + + /* allocation an array of gmlNamespaceObj's */ + namespaceList->numnamespaces = numprefixes; + namespaceList->namespaces = (gmlNamespaceObj *)malloc( + sizeof(gmlNamespaceObj) * namespaceList->numnamespaces); + if (namespaceList->namespaces == NULL) { + msSetError(MS_MEMERR, "Out of memory allocating %u bytes.\n", + "msGMLGetNamespaces()", + (unsigned int)(sizeof(gmlNamespaceObj) * + namespaceList->numnamespaces)); + free(namespaceList); + return NULL; + } + + for (i = 0; i < namespaceList->numnamespaces; i++) { + namespace = &(namespaceList->namespaces[i]); + + namespace->prefix = msStrdup(prefixes[i]); /* initialize a few things */ + namespace->uri = NULL; + namespace->schemalocation = NULL; + + snprintf(tag, 64, "%s_uri", namespace->prefix); + if ((value = msOWSLookupMetadata(&(web->metadata), metadata_namespaces, + tag)) != NULL) + namespace->uri = msStrdup(value); + + snprintf(tag, 64, "%s_schema_location", namespace->prefix); + if ((value = msOWSLookupMetadata(&(web->metadata), metadata_namespaces, + tag)) != NULL) + namespace->schemalocation = msStrdup(value); + } + + msFreeCharArray(prefixes, numprefixes); + } + + return namespaceList; +} + +void msGMLFreeNamespaces(gmlNamespaceListObj *namespaceList) { + int i; + + if (!namespaceList) + return; + + for (i = 0; i < namespaceList->numnamespaces; i++) { + msFree(namespaceList->namespaces[i].prefix); + msFree(namespaceList->namespaces[i].uri); + msFree(namespaceList->namespaces[i].schemalocation); + } + + free(namespaceList); +} + +gmlConstantListObj *msGMLGetConstants(layerObj *layer, + const char *metadata_namespaces) { + int i; + const char *value = NULL; + char tag[64]; + + char **names = NULL; + int numnames = 0; + + gmlConstantListObj *constantList = NULL; + gmlConstantObj *constant = NULL; + + /* allocate the collection */ + constantList = (gmlConstantListObj *)malloc(sizeof(gmlConstantListObj)); + MS_CHECK_ALLOC(constantList, sizeof(gmlConstantListObj), NULL); + constantList->constants = NULL; + constantList->numconstants = 0; + + /* list of constants (TODO: make this automatic by parsing metadata) */ + if ((value = msOWSLookupMetadata(&(layer->metadata), metadata_namespaces, + "constants")) != NULL) { + names = msStringSplit(value, ',', &numnames); + + /* allocation an array of gmlConstantObj's */ + constantList->numconstants = numnames; + constantList->constants = (gmlConstantObj *)malloc( + sizeof(gmlConstantObj) * constantList->numconstants); + if (constantList->constants == NULL) { + msSetError( + MS_MEMERR, "Out of memory allocating %u bytes.\n", + "msGMLGetConstants()", + (unsigned int)(sizeof(gmlConstantObj) * constantList->numconstants)); + free(constantList); + return NULL; + } + + for (i = 0; i < constantList->numconstants; i++) { + constant = &(constantList->constants[i]); + + constant->name = msStrdup(names[i]); /* initialize a few things */ + constant->value = NULL; + constant->type = NULL; + + snprintf(tag, 64, "%s_value", constant->name); + if ((value = msOWSLookupMetadata(&(layer->metadata), metadata_namespaces, + tag)) != NULL) + constant->value = msStrdup(value); + + snprintf(tag, 64, "%s_type", constant->name); + if ((value = msOWSLookupMetadata(&(layer->metadata), metadata_namespaces, + tag)) != NULL) + constant->type = msStrdup(value); + } + + msFreeCharArray(names, numnames); + } + + return constantList; +} + +void msGMLFreeConstants(gmlConstantListObj *constantList) { + int i; + + if (!constantList) + return; + + for (i = 0; i < constantList->numconstants; i++) { + msFree(constantList->constants[i].name); + msFree(constantList->constants[i].value); + msFree(constantList->constants[i].type); + } + + free(constantList); +} + +static void msGMLWriteConstant(FILE *stream, gmlConstantObj *constant, + const char *namespace, const char *tab) { + int add_namespace = MS_TRUE; + + if (!stream || !constant) + return; + if (!constant->value) + return; + + if (!namespace) + add_namespace = MS_FALSE; + if (strchr(constant->name, ':') != NULL) + add_namespace = MS_FALSE; + + if (add_namespace == MS_TRUE && msIsXMLTagValid(constant->name) == MS_FALSE) + msIO_fprintf( + stream, + "\n", + constant->name); + + if (add_namespace == MS_TRUE) + msIO_fprintf(stream, "%s<%s:%s>%s\n", tab, namespace, + constant->name, constant->value, namespace, constant->name); + else + msIO_fprintf(stream, "%s<%s>%s\n", tab, constant->name, + constant->value, constant->name); + + return; +} + +static void msGMLWriteGroup(FILE *stream, gmlGroupObj *group, shapeObj *shape, + gmlItemListObj *itemList, + gmlConstantListObj *constantList, + const char *namespace, const char *tab, + OWSGMLVersion outputformat, const char *pszFID) { + int i, j; + int add_namespace = MS_TRUE; + char *itemtab; + + gmlItemObj *item = NULL; + gmlConstantObj *constant = NULL; + + if (!stream || !group) + return; + + /* setup the item/constant tab */ + itemtab = (char *)msSmallMalloc(sizeof(char) * strlen(tab) + 3); + + sprintf(itemtab, "%s ", tab); + + if (!namespace || strchr(group->name, ':') != NULL) + add_namespace = MS_FALSE; + + /* start the group */ + if (add_namespace == MS_TRUE) + msIO_fprintf(stream, "%s<%s:%s>\n", tab, namespace, group->name); + else + msIO_fprintf(stream, "%s<%s>\n", tab, group->name); + + /* now the items/constants in the group */ + for (i = 0; i < group->numitems; i++) { + for (j = 0; j < constantList->numconstants; j++) { + constant = &(constantList->constants[j]); + if (strcasecmp(constant->name, group->items[i]) == 0) { + msGMLWriteConstant(stream, constant, namespace, itemtab); + break; + } + } + if (j != constantList->numconstants) + continue; /* found this one */ + for (j = 0; j < itemList->numitems; j++) { + item = &(itemList->items[j]); + if (strcasecmp(item->name, group->items[i]) == 0) { + /* the number of items matches the number of values exactly */ + msGMLWriteItem(stream, item, shape->values[j], namespace, itemtab, + outputformat, pszFID); + break; + } + } + } + + /* end the group */ + if (add_namespace == MS_TRUE) + msIO_fprintf(stream, "%s\n", tab, namespace, group->name); + else + msIO_fprintf(stream, "%s\n", tab, group->name); + + msFree(itemtab); + + return; +} +#endif + +gmlGroupListObj *msGMLGetGroups(layerObj *layer, + const char *metadata_namespaces) { + int i; + const char *value = NULL; + char tag[64]; + + char **names = NULL; + int numnames = 0; + + gmlGroupListObj *groupList = NULL; + gmlGroupObj *group = NULL; + + /* allocate the collection */ + groupList = (gmlGroupListObj *)malloc(sizeof(gmlGroupListObj)); + MS_CHECK_ALLOC(groupList, sizeof(gmlGroupListObj), NULL); + groupList->groups = NULL; + groupList->numgroups = 0; + + /* list of groups (TODO: make this automatic by parsing metadata) */ + if ((value = msOWSLookupMetadata(&(layer->metadata), metadata_namespaces, + "groups")) != NULL && + value[0] != '\0') { + names = msStringSplit(value, ',', &numnames); + + /* allocation an array of gmlGroupObj's */ + groupList->numgroups = numnames; + groupList->groups = + (gmlGroupObj *)malloc(sizeof(gmlGroupObj) * groupList->numgroups); + if (groupList->groups == NULL) { + msSetError(MS_MEMERR, "Out of memory allocating %u bytes.\n", + "msGMLGetGroups()", + (unsigned int)(sizeof(gmlGroupObj) * groupList->numgroups)); + free(groupList); + return NULL; + } + + for (i = 0; i < groupList->numgroups; i++) { + group = &(groupList->groups[i]); + + group->name = msStrdup(names[i]); /* initialize a few things */ + group->items = NULL; + group->numitems = 0; + group->type = NULL; + + snprintf(tag, 64, "%s_group", group->name); + if ((value = msOWSLookupMetadata(&(layer->metadata), metadata_namespaces, + tag)) != NULL) + group->items = msStringSplit(value, ',', &group->numitems); + + snprintf(tag, 64, "%s_type", group->name); + if ((value = msOWSLookupMetadata(&(layer->metadata), metadata_namespaces, + tag)) != NULL) + group->type = msStrdup(value); + } + + msFreeCharArray(names, numnames); + } + + return groupList; +} + +void msGMLFreeGroups(gmlGroupListObj *groupList) { + int i; + + if (!groupList) + return; + + for (i = 0; i < groupList->numgroups; i++) { + msFree(groupList->groups[i].name); + msFreeCharArray(groupList->groups[i].items, groupList->groups[i].numitems); + msFree(groupList->groups[i].type); + } + msFree(groupList->groups); + + free(groupList); +} + +/* Dump GML query results for WMS GetFeatureInfo */ +int msGMLWriteQuery(mapObj *map, char *filename, const char *namespaces) { +#if defined(USE_WMS_SVR) + int status; + int i, j, k; + layerObj *lp = NULL; + shapeObj shape; + FILE *stream_to_free = NULL; + FILE *stream = stdout; /* defaults to stdout */ + char szPath[MS_MAXPATHLEN]; + char *value; + char *pszMapSRS = NULL; + + gmlGroupListObj *groupList = NULL; + gmlItemListObj *itemList = NULL; + gmlConstantListObj *constantList = NULL; + gmlGeometryListObj *geometryList = NULL; + gmlItemObj *item = NULL; + gmlConstantObj *constant = NULL; + + msInitShape(&shape); + + if (filename && + strlen(filename) > 0) { /* deal with the filename if present */ + stream_to_free = fopen(msBuildPath(szPath, map->mappath, filename), "w"); + if (!stream_to_free) { + msSetError(MS_IOERR, "(%s)", "msGMLWriteQuery()", filename); + return (MS_FAILURE); + } + stream = stream_to_free; + } + + msIO_fprintf(stream, "\n\n"); + msOWSPrintValidateMetadata(stream, &(map->web.metadata), namespaces, + "rootname", OWS_NOERR, "<%s ", "msGMLOutput"); + + msOWSPrintEncodeMetadata(stream, &(map->web.metadata), namespaces, "uri", + OWS_NOERR, "xmlns=\"%s\"", NULL); + msIO_fprintf(stream, "\n\t xmlns:gml=\"http://www.opengis.net/gml\""); + msIO_fprintf(stream, "\n\t xmlns:xlink=\"http://www.w3.org/1999/xlink\""); + msIO_fprintf(stream, + "\n\t xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""); + msOWSPrintEncodeMetadata(stream, &(map->web.metadata), namespaces, "schema", + OWS_NOERR, "\n\t xsi:schemaLocation=\"%s\"", NULL); + msIO_fprintf(stream, ">\n"); + + /* a schema *should* be required */ + msOWSPrintEncodeMetadata(stream, &(map->web.metadata), namespaces, + "description", OWS_NOERR, + "\t%s\n", NULL); + + /* Look up map SRS. We need an EPSG code for GML, if not then we get null and + * we'll fall back on the layer's SRS */ + msOWSGetEPSGProj(&(map->projection), NULL, namespaces, MS_TRUE, &pszMapSRS); + + /* step through the layers looking for query results */ + for (i = 0; i < map->numlayers; i++) { + char *pszOutputSRS = NULL; + int nSRSDimension = 2; + const char *geomtype; + lp = (GET_LAYER(map, map->layerorder[i])); + + if (lp->resultcache && + lp->resultcache->numresults > 0) { /* found results */ + + reprojectionObj *reprojector = NULL; + + /* Determine output SRS, if map has none, then try using layer's native + * SRS */ + if ((pszOutputSRS = pszMapSRS) == NULL) { + msOWSGetEPSGProj(&(lp->projection), NULL, namespaces, MS_TRUE, + &pszOutputSRS); + if (pszOutputSRS == NULL) { + msSetError( + MS_WMSERR, + "No valid EPSG code in map or layer projection for GML output", + "msGMLWriteQuery()"); + continue; /* No EPSG code, cannot output this layer */ + } + } + + /* start this collection (layer) */ + /* if no layer name provided fall back on the layer name + "_layer" */ + value = (char *)msSmallMalloc(strlen(lp->name) + 7); + sprintf(value, "%s_layer", lp->name); + msOWSPrintValidateMetadata(stream, &(lp->metadata), namespaces, + "layername", OWS_NOERR, "\t<%s>\n", value); + msFree(value); + + value = (char *)msOWSLookupMetadata(&(lp->metadata), "OM", "title"); + if (value) { + msOWSPrintEncodeMetadata(stream, &(lp->metadata), namespaces, "title", + OWS_NOERR, "\t%s\n", + value); + } + + geomtype = msOWSLookupMetadata(&(lp->metadata), "OFG", "geomtype"); + if (geomtype != NULL && (strstr(geomtype, "25d") != NULL || + strstr(geomtype, "25D") != NULL)) { + nSRSDimension = 3; + } + + /* populate item and group metadata structures */ + itemList = msGMLGetItems(lp, namespaces); + constantList = msGMLGetConstants(lp, namespaces); + groupList = msGMLGetGroups(lp, namespaces); + geometryList = msGMLGetGeometries(lp, namespaces, MS_FALSE); + if (itemList == NULL || constantList == NULL || groupList == NULL || + geometryList == NULL) { + msSetError(MS_MISCERR, + "Unable to populate item and group metadata structures", + "msGMLWriteQuery()"); + if (stream_to_free != NULL) + fclose(stream_to_free); + return MS_FAILURE; + } + + if (pszOutputSRS == pszMapSRS && + msProjectionsDiffer(&(lp->projection), &(map->projection))) { + reprojector = + msProjectCreateReprojector(&(lp->projection), &(map->projection)); + if (reprojector == NULL) { + msGMLFreeGroups(groupList); + msGMLFreeConstants(constantList); + msGMLFreeItems(itemList); + msGMLFreeGeometries(geometryList); + msFree(pszOutputSRS); + if (stream_to_free != NULL) + fclose(stream_to_free); + return MS_FAILURE; + } + } + + for (j = 0; j < lp->resultcache->numresults; j++) { + status = msLayerGetShape(lp, &shape, &(lp->resultcache->results[j])); + if (status != MS_SUCCESS) { + msGMLFreeGroups(groupList); + msGMLFreeConstants(constantList); + msGMLFreeItems(itemList); + msGMLFreeGeometries(geometryList); + msProjectDestroyReprojector(reprojector); + msFree(pszOutputSRS); + if (stream_to_free != NULL) + fclose(stream_to_free); + return MS_FAILURE; + } + + /* project the shape into the map projection (if necessary), note that + * this projects the bounds as well */ + if (reprojector) { + status = msProjectShapeEx(reprojector, &shape); + if (status != MS_SUCCESS) { + msIO_fprintf(stream, + "\n", + msGetErrorString(",")); + msFreeShape(&shape); + continue; + } + } + + /* start this feature */ + /* specify a feature name, if nothing provided fall back on the layer + * name + "_feature" */ + value = (char *)msSmallMalloc(strlen(lp->name) + 9); + sprintf(value, "%s_feature", lp->name); + msOWSPrintValidateMetadata(stream, &(lp->metadata), namespaces, + "featurename", OWS_NOERR, "\t\t<%s>\n", + value); + msFree(value); + + /* Write the feature geometry and bounding box unless 'none' was + * requested. */ + /* Default to bbox only if nothing specified and output full geometry + * only if explicitly requested */ + if (!(geometryList && geometryList->numgeometries == 1 && + strcasecmp(geometryList->geometries[0].name, "none") == 0)) { + gmlWriteBounds(stream, OWS_GML2, &(shape.bounds), pszOutputSRS, + "\t\t\t", "gml"); + if (geometryList && geometryList->numgeometries > 0) + gmlWriteGeometry(stream, geometryList, OWS_GML2, &(shape), + pszOutputSRS, NULL, "\t\t\t", "", nSRSDimension, + 6); + } + + /* write any item/values */ + for (k = 0; k < itemList->numitems; k++) { + item = &(itemList->items[k]); + if (msItemInGroups(item->name, groupList) == MS_FALSE) + msGMLWriteItem(stream, item, shape.values[k], NULL, "\t\t\t", + OWS_GML2, NULL); + } + + /* write any constants */ + for (k = 0; k < constantList->numconstants; k++) { + constant = &(constantList->constants[k]); + if (msItemInGroups(constant->name, groupList) == MS_FALSE) + msGMLWriteConstant(stream, constant, NULL, "\t\t\t"); + } + + /* write any groups */ + for (k = 0; k < groupList->numgroups; k++) + msGMLWriteGroup(stream, &(groupList->groups[k]), &shape, itemList, + constantList, NULL, "\t\t\t", OWS_GML2, NULL); + + /* end this feature */ + /* specify a feature name if nothing provided */ + /* fall back on the layer name + "Feature" */ + value = (char *)msSmallMalloc(strlen(lp->name) + 9); + sprintf(value, "%s_feature", lp->name); + msOWSPrintValidateMetadata(stream, &(lp->metadata), namespaces, + "featurename", OWS_NOERR, "\t\t\n", + value); + msFree(value); + + msFreeShape(&shape); /* init too */ + } + + msProjectDestroyReprojector(reprojector); + + /* end this collection (layer) */ + /* if no layer name provided fall back on the layer name + "_layer" */ + value = (char *)msSmallMalloc(strlen(lp->name) + 7); + sprintf(value, "%s_layer", lp->name); + msOWSPrintValidateMetadata(stream, &(lp->metadata), namespaces, + "layername", OWS_NOERR, "\t\n", value); + msFree(value); + + msGMLFreeGroups(groupList); + msGMLFreeConstants(constantList); + msGMLFreeItems(itemList); + msGMLFreeGeometries(geometryList); + + /* msLayerClose(lp); */ + } + if (pszOutputSRS != pszMapSRS) { + msFree(pszOutputSRS); + } + } /* next layer */ + + /* end this document */ + msOWSPrintValidateMetadata(stream, &(map->web.metadata), namespaces, + "rootname", OWS_NOERR, "\n", "msGMLOutput"); + + if (stream_to_free != NULL) + fclose(stream_to_free); + msFree(pszMapSRS); + + return (MS_SUCCESS); + +#else /* Stub for mapscript */ + msSetError(MS_MISCERR, "WMS server support not enabled", "msGMLWriteQuery()"); + return MS_FAILURE; +#endif +} + +#ifdef USE_WFS_SVR +void msGMLWriteWFSBounds(mapObj *map, FILE *stream, const char *tab, + OWSGMLVersion outputformat, int nWFSVersion, + int bUseURN) { + rectObj resultBounds = {-1.0, -1.0, -1.0, -1.0}; + + /*add a check to see if the map projection is set to be north-east*/ + int bSwapAxis = msIsAxisInvertedProj(&(map->projection)); + + /* Need to start with BBOX of the whole resultset */ + if (msGetQueryResultBounds(map, &resultBounds) > 0) { + char *srs = NULL; + if (bSwapAxis) { + double tmp; + + tmp = resultBounds.minx; + resultBounds.minx = resultBounds.miny; + resultBounds.miny = tmp; + + tmp = resultBounds.maxx; + resultBounds.maxx = resultBounds.maxy; + resultBounds.maxy = tmp; + } + if (bUseURN) { + srs = msOWSGetProjURN(&(map->projection), NULL, "FGO", MS_TRUE); + if (!srs) + srs = msOWSGetProjURN(&(map->projection), &(map->web.metadata), "FGO", + MS_TRUE); + } else { + msOWSGetEPSGProj(&(map->projection), NULL, "FGO", MS_TRUE, &srs); + if (!srs) + msOWSGetEPSGProj(&(map->projection), &(map->web.metadata), "FGO", + MS_TRUE, &srs); + } + + gmlWriteBounds(stream, outputformat, &resultBounds, srs, tab, + (nWFSVersion == OWS_2_0_0) ? "wfs" : "gml"); + msFree(srs); + } +} + +#endif + +/* +** msGMLWriteWFSQuery() +** +** Similar to msGMLWriteQuery() but tuned for use with WFS +*/ +int msGMLWriteWFSQuery(mapObj *map, FILE *stream, + const char *default_namespace_prefix, + OWSGMLVersion outputformat, int nWFSVersion, int bUseURN, + int bGetPropertyValueRequest) { +#ifdef USE_WFS_SVR + int status; + int i, j, k; + layerObj *lp = NULL; + shapeObj shape; + + gmlGroupListObj *groupList = NULL; + gmlItemListObj *itemList = NULL; + gmlConstantListObj *constantList = NULL; + gmlGeometryListObj *geometryList = NULL; + gmlItemObj *item = NULL; + gmlConstantObj *constant = NULL; + + const char *namespace_prefix = NULL; + int bSwapAxis; + + msInitShape(&shape); + + /*add a check to see if the map projection is set to be north-east*/ + bSwapAxis = msIsAxisInvertedProj(&(map->projection)); + + /* Need to start with BBOX of the whole resultset */ + if (!bGetPropertyValueRequest) { + msGMLWriteWFSBounds(map, stream, " ", outputformat, nWFSVersion, + bUseURN); + } + /* step through the layers looking for query results */ + for (i = 0; i < map->numlayers; i++) { + + lp = GET_LAYER(map, map->layerorder[i]); + + if (lp->resultcache && + lp->resultcache->numresults > 0) { /* found results */ + char *layerName; + const char *value; + int featureIdIndex = -1; /* no feature id */ + char *srs = NULL; + int bOutputGMLIdOnly = MS_FALSE; + int nSRSDimension = 2; + const char *geomtype; + reprojectionObj *reprojector = NULL; + int geometry_precision = 6; + + /* setup namespace, a layer can override the default */ + namespace_prefix = + msOWSLookupMetadata(&(lp->metadata), "OFG", "namespace_prefix"); + if (!namespace_prefix) + namespace_prefix = default_namespace_prefix; + + geomtype = msOWSLookupMetadata(&(lp->metadata), "OFG", "geomtype"); + if (geomtype != NULL && (strstr(geomtype, "25d") != NULL || + strstr(geomtype, "25D") != NULL)) { + nSRSDimension = 3; + } + + value = msOWSLookupMetadata(&(lp->metadata), "OFG", "featureid"); + if (value) { /* find the featureid amongst the items for this layer */ + for (j = 0; j < lp->numitems; j++) { + if (strcasecmp(lp->items[j], value) == 0) { /* found it */ + featureIdIndex = j; + break; + } + } + + /* Produce a warning if a featureid was set but the corresponding item + * is not found. */ + if (featureIdIndex == -1) + msIO_fprintf(stream, + "\n", + value, lp->name); + } else if (outputformat == OWS_GML32) + msIO_fprintf(stream, + "\n", + lp->name); + + /* populate item and group metadata structures */ + itemList = msGMLGetItems(lp, "G"); + constantList = msGMLGetConstants(lp, "G"); + groupList = msGMLGetGroups(lp, "G"); + geometryList = msGMLGetGeometries(lp, "GFO", MS_FALSE); + if (itemList == NULL || constantList == NULL || groupList == NULL || + geometryList == NULL) { + msSetError(MS_MISCERR, + "Unable to populate item and group metadata structures", + "msGMLWriteWFSQuery()"); + return MS_FAILURE; + } + + if (bGetPropertyValueRequest) { + const char *value = + msOWSLookupMetadata(&(lp->metadata), "G", "include_items"); + if (value != NULL && strcmp(value, "@gml:id") == 0) + bOutputGMLIdOnly = MS_TRUE; + } + + if (namespace_prefix) { + layerName = (char *)msSmallMalloc(strlen(namespace_prefix) + + strlen(lp->name) + 2); + sprintf(layerName, "%s:%s", namespace_prefix, lp->name); + } else { + layerName = msStrdup(lp->name); + } + + if (bUseURN) { + srs = msOWSGetProjURN(&(map->projection), NULL, "FGO", MS_TRUE); + if (!srs) + srs = msOWSGetProjURN(&(map->projection), &(map->web.metadata), "FGO", + MS_TRUE); + if (!srs) + srs = msOWSGetProjURN(&(lp->projection), &(lp->metadata), "FGO", + MS_TRUE); + } else { + msOWSGetEPSGProj(&(map->projection), NULL, "FGO", MS_TRUE, &srs); + if (!srs) + msOWSGetEPSGProj(&(map->projection), &(map->web.metadata), "FGO", + MS_TRUE, &srs); + if (!srs) + msOWSGetEPSGProj(&(lp->projection), &(lp->metadata), "FGO", MS_TRUE, + &srs); + } + + if (msProjectionsDiffer(&(lp->projection), &(map->projection))) { + reprojector = + msProjectCreateReprojector(&(lp->projection), &(map->projection)); + if (reprojector == NULL) { + msGMLFreeGroups(groupList); + msGMLFreeConstants(constantList); + msGMLFreeItems(itemList); + msGMLFreeGeometries(geometryList); + msFree(layerName); + msFree(srs); + return MS_FAILURE; + } + } + + for (j = 0; j < lp->resultcache->numresults; j++) { + char *pszFID; + + if (lp->resultcache->results[j].shape) { + /* msDebug("Using cached shape %ld\n", + * lp->resultcache->results[j].shapeindex); */ + msCopyShape(lp->resultcache->results[j].shape, &shape); + } else { + status = msLayerGetShape(lp, &shape, &(lp->resultcache->results[j])); + if (status != MS_SUCCESS) { + msGMLFreeGroups(groupList); + msGMLFreeConstants(constantList); + msGMLFreeItems(itemList); + msGMLFreeGeometries(geometryList); + msFree(layerName); + msProjectDestroyReprojector(reprojector); + msFree(srs); + return (status); + } + } + + /* project the shape into the map projection (if necessary), note that + * this projects the bounds as well */ + if (reprojector) + msProjectShapeEx(reprojector, &shape); + + if (featureIdIndex != -1) { + pszFID = (char *)msSmallMalloc( + strlen(lp->name) + 1 + strlen(shape.values[featureIdIndex]) + 1); + sprintf(pszFID, "%s.%s", lp->name, shape.values[featureIdIndex]); + } else + pszFID = msStrdup(""); + + if (bOutputGMLIdOnly) { + msIO_fprintf(stream, " %s\n", pszFID); + msFree(pszFID); + msFreeShape(&shape); /* init too */ + continue; + } + + /* + ** start this feature + */ + if (nWFSVersion == OWS_2_0_0) + msIO_fprintf(stream, " \n"); + else + msIO_fprintf(stream, " \n"); + if (msIsXMLTagValid(layerName) == MS_FALSE) + msIO_fprintf(stream, + "\n", + layerName); + if (featureIdIndex != -1) { + if (!bGetPropertyValueRequest) { + if (outputformat == OWS_GML2) + msIO_fprintf(stream, " <%s fid=\"%s\">\n", layerName, + pszFID); + else /* OWS_GML3 or OWS_GML32 */ + msIO_fprintf(stream, " <%s gml:id=\"%s\">\n", layerName, + pszFID); + } + } else { + if (!bGetPropertyValueRequest) + msIO_fprintf(stream, " <%s>\n", layerName); + } + + if (bSwapAxis) + msAxisSwapShape(&shape); + + /* write the feature geometry and bounding box */ + if (!(geometryList && geometryList->numgeometries == 1 && + strcasecmp(geometryList->geometries[0].name, "none") == 0)) { + if (!bGetPropertyValueRequest) + gmlWriteBounds(stream, outputformat, &(shape.bounds), srs, + " ", "gml"); + + if (msOWSLookupMetadata(&(lp->metadata), "F", "geometry_precision")) { + geometry_precision = atoi(msOWSLookupMetadata( + &(lp->metadata), "F", "geometry_precision")); + } else if (msOWSLookupMetadata(&map->web.metadata, "F", + "geometry_precision")) { + geometry_precision = atoi(msOWSLookupMetadata( + &map->web.metadata, "F", "geometry_precision")); + } + + gmlWriteGeometry(stream, geometryList, outputformat, &(shape), srs, + namespace_prefix, " ", pszFID, nSRSDimension, + geometry_precision); + } + + /* write any item/values */ + for (k = 0; k < itemList->numitems; k++) { + item = &(itemList->items[k]); + if (msItemInGroups(item->name, groupList) == MS_FALSE) + msGMLWriteItem(stream, item, shape.values[k], namespace_prefix, + " ", outputformat, pszFID); + } + + /* write any constants */ + for (k = 0; k < constantList->numconstants; k++) { + constant = &(constantList->constants[k]); + if (msItemInGroups(constant->name, groupList) == MS_FALSE) + msGMLWriteConstant(stream, constant, namespace_prefix, " "); + } + + /* write any groups */ + for (k = 0; k < groupList->numgroups; k++) + msGMLWriteGroup(stream, &(groupList->groups[k]), &shape, itemList, + constantList, namespace_prefix, " ", + outputformat, pszFID); + + if (!bGetPropertyValueRequest) + /* end this feature */ + msIO_fprintf(stream, " \n", layerName); + + if (nWFSVersion == OWS_2_0_0) + msIO_fprintf(stream, " \n"); + else + msIO_fprintf(stream, " \n"); + + msFree(pszFID); + pszFID = NULL; + msFreeShape(&shape); /* init too */ + } + + msProjectDestroyReprojector(reprojector); + + msFree(srs); + + /* done with this layer, do a little clean-up */ + msFree(layerName); + + msGMLFreeGroups(groupList); + msGMLFreeConstants(constantList); + msGMLFreeItems(itemList); + msGMLFreeGeometries(geometryList); + + /* msLayerClose(lp); */ + } + + } /* next layer */ + + return (MS_SUCCESS); + +#else /* Stub for mapscript */ + (void)map; + (void)stream; + (void)default_namespace_prefix; + (void)outputformat; + (void)nWFSVersion; + (void)bUseURN; + (void)bGetPropertyValueRequest; + msSetError(MS_MISCERR, "WFS server support not enabled", + "msGMLWriteWFSQuery()"); + return MS_FAILURE; +#endif /* USE_WFS_SVR */ +} + +#ifdef USE_LIBXML2 + +/** + * msGML3BoundedBy() + * + * returns an object of BoundedBy as per GML 3 + * + * @param xmlNsPtr psNs the namespace object + * @param minx minx + * @param miny miny + * @param maxx maxx + * @param mayy mayy + * @param psEpsg epsg code + * @param dimension number of dimensions + * + * @return psNode xmlNodePtr of XML construct + * + */ + +xmlNodePtr msGML3BoundedBy(xmlNsPtr psNs, double minx, double miny, double maxx, + double maxy, const char *psEpsg) { + xmlNodePtr psNode = NULL, psSubNode = NULL; + char *pszTmp = NULL; + char *pszTmp2 = NULL; + char *pszEpsg = NULL; + + psNode = xmlNewNode(psNs, BAD_CAST "boundedBy"); + psSubNode = xmlNewChild(psNode, NULL, BAD_CAST "Envelope", NULL); + + if (psEpsg) { + const size_t bufferSize = strlen(psEpsg) + 1; + pszEpsg = (char *)msSmallMalloc(bufferSize); + snprintf(pszEpsg, bufferSize, "%s", psEpsg); + msStringToLower(pszEpsg); + pszTmp = msStringConcatenate(pszTmp, "urn:ogc:crs:"); + pszTmp = msStringConcatenate(pszTmp, pszEpsg); + xmlNewProp(psSubNode, BAD_CAST "srsName", BAD_CAST pszTmp); + free(pszEpsg); + free(pszTmp); + pszTmp = msIntToString(2); + xmlNewProp(psSubNode, BAD_CAST "srsDimension", BAD_CAST pszTmp); + free(pszTmp); + } + + pszTmp = msDoubleToString(minx, MS_TRUE); + pszTmp = msStringConcatenate(pszTmp, " "); + pszTmp2 = msDoubleToString(miny, MS_TRUE); + pszTmp = msStringConcatenate(pszTmp, pszTmp2); + xmlNewChild(psSubNode, NULL, BAD_CAST "lowerCorner", BAD_CAST pszTmp); + free(pszTmp); + free(pszTmp2); + + pszTmp = msDoubleToString(maxx, MS_TRUE); + pszTmp = msStringConcatenate(pszTmp, " "); + pszTmp2 = msDoubleToString(maxy, MS_TRUE); + pszTmp = msStringConcatenate(pszTmp, pszTmp2); + xmlNewChild(psSubNode, NULL, BAD_CAST "upperCorner", BAD_CAST pszTmp); + free(pszTmp); + free(pszTmp2); + return psNode; +} + +/** + *msGML3Point() + * + * returns an object of Point as per GML 3 + * + * @param xmlNsPtr psNs the gml namespace object + * @param pszSrsName EPSG code of geometry + * @param id + * @param x x coordinate + * @param y y coordinate + * @param z z coordinate + * + * @return psNode xmlNodePtr of XML construct + * + */ + +xmlNodePtr msGML3Point(xmlNsPtr psNs, const char *psSrsName, const char *id, + double x, double y) { + + xmlNodePtr psNode = xmlNewNode(psNs, BAD_CAST "Point"); + + if (id) { + xmlNewNsProp(psNode, psNs, BAD_CAST "id", BAD_CAST id); + } + + if (psSrsName) { + const size_t bufferSize = strlen(psSrsName) + 1; + char *pszSrsName = (char *)msSmallMalloc(bufferSize); + snprintf(pszSrsName, bufferSize, "%s", psSrsName); + msStringToLower(pszSrsName); + char *pszTmp = NULL; + pszTmp = msStringConcatenate(pszTmp, "urn:ogc:crs:"); + pszTmp = msStringConcatenate(pszTmp, pszSrsName); + xmlNewProp(psNode, BAD_CAST "srsName", BAD_CAST pszTmp); + free(pszSrsName); + free(pszTmp); + const int dimension = 2; + pszTmp = msIntToString(dimension); + xmlNewProp(psNode, BAD_CAST "srsDimension", BAD_CAST pszTmp); + free(pszTmp); + } + + char *pszTmp = msDoubleToString(x, MS_TRUE); + pszTmp = msStringConcatenate(pszTmp, " "); + char *pszTmp2 = msDoubleToString(y, MS_TRUE); + pszTmp = msStringConcatenate(pszTmp, pszTmp2); + xmlNewChild(psNode, NULL, BAD_CAST "pos", BAD_CAST pszTmp); + + free(pszTmp); + free(pszTmp2); + return psNode; +} + +/** + * msGML3TimePeriod() + * + * returns an object of TimePeriod as per GML 3 + * + * @param xmlNsPtr psNs the gml namespace object + * @param pszStart start time + * @param pszEnd end time + * + * @return psNode xmlNodePtr of XML construct + * + */ + +xmlNodePtr msGML3TimePeriod(xmlNsPtr psNs, char *pszStart, char *pszEnd) { + xmlNodePtr psNode = NULL; + + psNode = xmlNewNode(psNs, BAD_CAST "TimePeriod"); + xmlNewChild(psNode, NULL, BAD_CAST "beginPosition", BAD_CAST pszStart); + if (pszEnd) + xmlNewChild(psNode, NULL, BAD_CAST "endPosition", BAD_CAST pszEnd); + else { + xmlNewChild(psNode, NULL, BAD_CAST "endPosition", NULL); + xmlNewProp(psNode, BAD_CAST "indeterminatePosition", BAD_CAST "now"); + } + return psNode; +} + +/** + * msGML3TimeInstant() + * + * returns an object of TimeInstant as per GML 3 + * + * @param xmlNsPtr psNs the gml namespace object + * @param timeInstant time instant + * + * @return psNode xmlNodePtr of XML construct + * + */ + +xmlNodePtr msGML3TimeInstant(xmlNsPtr psNs, char *pszTime) { + xmlNodePtr psNode = NULL; + + psNode = xmlNewNode(psNs, BAD_CAST "TimeInstant"); + xmlNewChild(psNode, NULL, BAD_CAST "timePosition", BAD_CAST pszTime); + return psNode; +} + +#endif /* USE_LIBXML2 */ + +/************************************************************************/ +/* The following functions are enabled in all cases, even if */ +/* WMS and WFS are not available. */ +/************************************************************************/ + +gmlItemListObj *msGMLGetItems(layerObj *layer, + const char *metadata_namespaces) { + int i, j; + + char **xmlitems = NULL; + int numxmlitems = 0; + + char **incitems = NULL; + int numincitems = 0; + + char **excitems = NULL; + int numexcitems = 0; + + char **optionalitems = NULL; + int numoptionalitems = 0; + + char **mandatoryitems = NULL; + int nummandatoryitems = 0; + + char **defaultitems = NULL; + int numdefaultitems = 0; + + const char *value = NULL; + char tag[64]; + + gmlItemListObj *itemList = NULL; + gmlItemObj *item = NULL; + + /* get a list of items that might be included in output */ + if ((value = msOWSLookupMetadata(&(layer->metadata), metadata_namespaces, + "include_items")) != NULL) + incitems = msStringSplit(value, ',', &numincitems); + + /* get a list of items that should be excluded in output */ + if ((value = msOWSLookupMetadata(&(layer->metadata), metadata_namespaces, + "exclude_items")) != NULL) + excitems = msStringSplit(value, ',', &numexcitems); + + /* get a list of items that should not be XML encoded */ + if ((value = msOWSLookupMetadata(&(layer->metadata), metadata_namespaces, + "xml_items")) != NULL) + xmlitems = msStringSplit(value, ',', &numxmlitems); + + /* get a list of items that should be indicated as optional in + * DescribeFeatureType */ + if ((value = msOWSLookupMetadata(&(layer->metadata), metadata_namespaces, + "optional_items")) != NULL) + optionalitems = msStringSplit(value, ',', &numoptionalitems); + + /* get a list of items that should be indicated as mandatory in + * DescribeFeatureType */ + if ((value = msOWSLookupMetadata(&(layer->metadata), metadata_namespaces, + "mandatory_items")) != NULL) + mandatoryitems = msStringSplit(value, ',', &nummandatoryitems); + + /* get a list of items that should be presented by default in GetFeature */ + if ((value = msOWSLookupMetadata(&(layer->metadata), metadata_namespaces, + "default_items")) != NULL) + defaultitems = msStringSplit(value, ',', &numdefaultitems); + + /* allocate memory and initialize the item collection */ + itemList = (gmlItemListObj *)malloc(sizeof(gmlItemListObj)); + if (itemList == NULL) { + msSetError(MS_MEMERR, "Error allocating a collection GML item structures.", + "msGMLGetItems()"); + return NULL; + } + + itemList->numitems = layer->numitems; + itemList->items = + (gmlItemObj *)malloc(sizeof(gmlItemObj) * itemList->numitems); + if (!itemList->items) { + msSetError(MS_MEMERR, "Error allocating a collection GML item structures.", + "msGMLGetItems()"); + free(itemList); + return NULL; + } + + for (i = 0; i < layer->numitems; i++) { + item = &(itemList->items[i]); + + item->name = msStrdup(layer->items[i]); /* initialize the item */ + item->alias = NULL; + item->type = NULL; + item->template = NULL; + item->encode = MS_TRUE; + item->visible = MS_FALSE; + item->width = 0; + item->precision = 0; + item->outputByDefault = (numdefaultitems == 0); + item->minOccurs = 0; + + /* check visibility, included items first... */ + if (numincitems == 1 && strcasecmp("all", incitems[0]) == 0) { + item->visible = MS_TRUE; + } else { + for (j = 0; j < numincitems; j++) { + if (strcasecmp(layer->items[i], incitems[j]) == 0) + item->visible = MS_TRUE; + } + } + + /* ...and now excluded items */ + for (j = 0; j < numexcitems; j++) { + if (strcasecmp(layer->items[i], excitems[j]) == 0) + item->visible = MS_FALSE; + } + + /* check encoding */ + for (j = 0; j < numxmlitems; j++) { + if (strcasecmp(layer->items[i], xmlitems[j]) == 0) + item->encode = MS_FALSE; + } + + /* check optional */ + if (numoptionalitems == 1 && strcasecmp("all", optionalitems[0]) == 0) { + item->minOccurs = 0; + } else if (numoptionalitems > 0) { + item->minOccurs = 1; + for (j = 0; j < numoptionalitems; j++) { + if (strcasecmp(layer->items[i], optionalitems[j]) == 0) + item->minOccurs = 0; + } + } + + /* check mandatory */ + if (nummandatoryitems == 1 && strcasecmp("all", mandatoryitems[0]) == 0) { + item->minOccurs = 1; + } else if (nummandatoryitems > 0) { + item->minOccurs = 0; + for (j = 0; j < nummandatoryitems; j++) { + if (strcasecmp(layer->items[i], mandatoryitems[j]) == 0) + item->minOccurs = 1; + } + } + + /* check default */ + for (j = 0; j < numdefaultitems; j++) { + if (strcasecmp(layer->items[i], defaultitems[j]) == 0) + item->outputByDefault = 1; + } + + snprintf(tag, sizeof(tag), "%s_alias", layer->items[i]); + if ((value = msOWSLookupMetadata(&(layer->metadata), metadata_namespaces, + tag)) != NULL) + item->alias = msStrdup(value); + + snprintf(tag, sizeof(tag), "%s_type", layer->items[i]); + if ((value = msOWSLookupMetadata(&(layer->metadata), metadata_namespaces, + tag)) != NULL) + item->type = msStrdup(value); + + snprintf(tag, sizeof(tag), "%s_template", layer->items[i]); + if ((value = msOWSLookupMetadata(&(layer->metadata), metadata_namespaces, + tag)) != NULL) + item->template = msStrdup(value); + + snprintf(tag, sizeof(tag), "%s_width", layer->items[i]); + if ((value = msOWSLookupMetadata(&(layer->metadata), metadata_namespaces, + tag)) != NULL) + item->width = atoi(value); + + snprintf(tag, sizeof(tag), "%s_precision", layer->items[i]); + if ((value = msOWSLookupMetadata(&(layer->metadata), metadata_namespaces, + tag)) != NULL) + item->precision = atoi(value); + } + + msFreeCharArray(incitems, numincitems); + msFreeCharArray(excitems, numexcitems); + msFreeCharArray(xmlitems, numxmlitems); + msFreeCharArray(optionalitems, numoptionalitems); + msFreeCharArray(mandatoryitems, nummandatoryitems); + msFreeCharArray(defaultitems, numdefaultitems); + + return itemList; +} + +void msGMLFreeItems(gmlItemListObj *itemList) { + int i; + + if (!itemList) + return; + + for (i = 0; i < itemList->numitems; i++) { + msFree(itemList->items[i].name); + msFree(itemList->items[i].alias); + msFree(itemList->items[i].type); + msFree(itemList->items[i].template); + } + + if (itemList->items != NULL) + free(itemList->items); + + free(itemList); +} diff --git a/mapgml.h b/src/mapgml.h similarity index 91% rename from mapgml.h rename to src/mapgml.h index 1bff8db780..c5cebd83d9 100644 --- a/mapgml.h +++ b/src/mapgml.h @@ -28,18 +28,19 @@ * DEALINGS IN THE SOFTWARE. ****************************************************************************/ - #ifndef MAPGML_H #define MAPGML_H #ifdef USE_LIBXML2 -#include -#include +#include +#include -xmlNodePtr msGML3BoundedBy(xmlNsPtr psNs, double minx, double miny, double maxx, double maxy, const char *psEpsg); +xmlNodePtr msGML3BoundedBy(xmlNsPtr psNs, double minx, double miny, double maxx, + double maxy, const char *psEpsg); xmlNodePtr msGML3TimePeriod(xmlNsPtr psNs, char *pszStart, char *pszEnd); xmlNodePtr msGML3TimeInstant(xmlNsPtr psNs, char *timeInstant); -xmlNodePtr msGML3Point(xmlNsPtr psNs, const char *psSrsName, const char *id, double x, double y); +xmlNodePtr msGML3Point(xmlNsPtr psNs, const char *psSrsName, const char *id, + double x, double y); #endif /* USE_LIBXML2 */ diff --git a/src/mapgraph.cpp b/src/mapgraph.cpp new file mode 100644 index 0000000000..e578bd951b --- /dev/null +++ b/src/mapgraph.cpp @@ -0,0 +1,378 @@ +/****************************************************************************** + * $Id$ + * + * Project: MapServer + * Purpose: Functions for basic undirected, weighted graph support. + * Author: Steve Lime and the MapServer team. + * + ****************************************************************************** + * Copyright (c) 1996-2005 Regents of the University of Minnesota. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + ****************************************************************************/ + +#include "mapserver.h" +#include "mapgraph.h" +#include // for std::swap + +graphObj *msCreateGraph(signed int numnodes) { + graphObj *graph = nullptr; + + if (numnodes <= 0) + return nullptr; + + graph = (graphObj *)malloc(sizeof(graphObj)); + if (!graph) + return nullptr; + + graph->head = (graphNodeObj **)calloc(numnodes, sizeof(graphNodeObj *)); + if (!graph->head) { + free(graph); + return nullptr; + } + graph->numnodes = numnodes; + + return graph; +} + +void msFreeGraph(graphObj *graph) { + if (!graph) + return; + + graphNodeObj *tmp = nullptr; + + for (int i = 0; i < graph->numnodes; i++) { + while (graph->head[i] != nullptr) { + tmp = graph->head[i]; + graph->head[i] = graph->head[i]->next; + free(tmp); + } + } + + free(graph->head); + free(graph); +} + +int msGraphAddEdge(graphObj *graph, int src, int dest, double weight) { + graphNodeObj *node = nullptr; + + if (!graph) + return MS_FAILURE; + + // src -> dest + node = (graphNodeObj *)malloc(sizeof(graphNodeObj)); + if (!node) + return MS_FAILURE; + + node->dest = dest; + node->weight = weight; + node->next = graph->head[src]; + graph->head[src] = node; + + // dest -> src + node = (graphNodeObj *)malloc(sizeof(graphNodeObj)); + if (!node) + return MS_FAILURE; + + node->dest = src; + node->weight = weight; + node->next = graph->head[dest]; + graph->head[dest] = node; + + return MS_SUCCESS; +} + +void msPrintGraph(graphObj *graph) { + int i; + + if (!graph) + return; + + for (i = 0; i < graph->numnodes; i++) { + graphNodeObj *node = graph->head[i]; + if (node != nullptr) { + do { + msDebug("%d -> %d (%.6f)\t", i, node->dest, node->weight); + node = node->next; + } while (node != nullptr); + msDebug("\n"); + } + } +} + +/* +** Derived from an number web resources including: +** +** +*https://www.geeksforgeeks.org/dijkstras-algorithm-for-adjacency-list-representation-greedy-algo-8/ +** https://youtube.com/watch?v=pSqmAO-m7Lk +** https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm +** +** Much of the bulk here is for min-heap (key,value) management. +*/ + +typedef struct { + int idx; + double dist; +} minHeapNodeObj; + +typedef struct { + int size; + int capacity; + int *pos; + minHeapNodeObj **nodes; +} minHeapObj; + +static minHeapNodeObj *newMinHeapNode(int idx, double dist) { + minHeapNodeObj *node = (minHeapNodeObj *)malloc(sizeof(minHeapNodeObj)); + if (!node) + return nullptr; + node->idx = idx; + node->dist = dist; + return node; +} + +static void freeMinHeap(minHeapObj *minHeap) { + if (!minHeap) + return; + + free(minHeap->pos); + for (int i = 0; i < minHeap->size; i++) { + free(minHeap->nodes[i]); + } + free(minHeap->nodes); + free(minHeap); +} + +static minHeapObj *createMinHeap(signed int capacity) { + minHeapObj *minHeap = (minHeapObj *)malloc(sizeof(minHeapObj)); + if (!minHeap) + return nullptr; + + minHeap->pos = (int *)malloc(capacity * sizeof(int)); + if (!minHeap->pos) { + free(minHeap); + return nullptr; + } + minHeap->size = 0; + minHeap->capacity = capacity; + minHeap->nodes = + (minHeapNodeObj **)malloc(capacity * sizeof(minHeapNodeObj *)); + if (!minHeap->nodes) { + free(minHeap->pos); + free(minHeap); + return nullptr; + } + return minHeap; +} + +static void minHeapify(minHeapObj *minHeap, int idx) { + int smallest = idx; + const int left = 2 * idx + 1; + const int right = 2 * idx + 2; + + if (left < minHeap->size && + minHeap->nodes[left]->dist < minHeap->nodes[smallest]->dist) + smallest = left; + + if (right < minHeap->size && + minHeap->nodes[right]->dist < minHeap->nodes[smallest]->dist) + smallest = right; + + if (smallest != idx) { + minHeapNodeObj *smallestNode = minHeap->nodes[smallest]; + minHeapNodeObj *idxNode = minHeap->nodes[idx]; + + minHeap->pos[smallestNode->idx] = idx; // swap positions + minHeap->pos[idxNode->idx] = smallest; + + std::swap(minHeap->nodes[smallest], minHeap->nodes[idx]); // swap nodes + minHeapify(minHeap, smallest); + } +} + +static bool isEmpty(const minHeapObj *minHeap) { return minHeap->size == 0; } + +static minHeapNodeObj *extractMin(minHeapObj *minHeap) { + if (isEmpty(minHeap)) + return nullptr; + + // store root node + minHeapNodeObj *root = minHeap->nodes[0]; + + // replace root node with last node + minHeapNodeObj *lastNode = minHeap->nodes[minHeap->size - 1]; + minHeap->nodes[0] = lastNode; + + // update position of last node + minHeap->pos[root->idx] = minHeap->size - 1; + minHeap->pos[lastNode->idx] = 0; + + // Reduce heap size and heapify root + --minHeap->size; + minHeapify(minHeap, 0); + + return root; +} + +static void decreaseKey(minHeapObj *minHeap, int idx, int dist) { + // get the index of idx in min heap nodes + int i = minHeap->pos[idx]; + + // get the node and update its dist value + minHeap->nodes[i]->dist = dist; + + // travel up while the complete tree is not hepified (this is a O(Logn) loop) + while (i && minHeap->nodes[i]->dist < minHeap->nodes[(i - 1) / 2]->dist) { + // swap this node with its parent + minHeap->pos[minHeap->nodes[i]->idx] = (i - 1) / 2; + minHeap->pos[minHeap->nodes[(i - 1) / 2]->idx] = i; + std::swap(minHeap->nodes[i], minHeap->nodes[(i - 1) / 2]); + + // move to parent index + i = (i - 1) / 2; + } +} + +static bool isInMinHeap(const minHeapObj *minHeap, int idx) { + return minHeap->pos[idx] < minHeap->size; +} + +typedef struct { + double *dist; + int *prev; +} dijkstraOutputObj; + +static dijkstraOutputObj *dijkstra(graphObj *graph, int src) { + int n = graph->numnodes; + + minHeapObj *minHeap = + createMinHeap(n); // priority queue implemented as a min heap structure + if (!minHeap) + return nullptr; + + dijkstraOutputObj *output = nullptr; + output = (dijkstraOutputObj *)malloc(sizeof(dijkstraOutputObj)); + output->dist = (double *)malloc(n * sizeof(double)); + output->prev = (int *)malloc(n * sizeof(int)); + if (!output->dist || !output->prev) { + msFree(output->dist); + msFree(output->prev); + free(output); + freeMinHeap(minHeap); + return nullptr; + } + + // initialize + for (int i = 0; i < n; i++) { + output->dist[i] = HUGE_VAL; + output->prev[i] = -1; + minHeap->nodes[i] = newMinHeapNode( + i, output->dist[i]); // allocate a min heap node for each graph node + minHeap->pos[i] = i; + } + + // make dist value of src vertex as 0 so that it is extracted first + minHeap->pos[src] = src; + output->dist[src] = 0; + decreaseKey(minHeap, src, output->dist[src]); + + // initially size of min heap is equal to graph->numnodes (n) + minHeap->size = n; + + // In the following loop, minHeap contains all nodes + // whose shortest distance is not yet finalized. + while (!isEmpty(minHeap)) { + + // extract the vertex with minimum distance value and store the node index + minHeapNodeObj *minHeapNode = extractMin(minHeap); + int u = minHeapNode->idx; + free(minHeapNode); // done with this node + + // traverse through all adjacent nodes of u and update their distance values + graphNodeObj *node = graph->head[u]; + while (node != nullptr) { + int v = node->dest; + + // if shortest distance to v is not finalized yet, and distance to v + // through u is less than its previously calculated distance + if (isInMinHeap(minHeap, v) && output->dist[u] != HUGE_VAL && + node->weight + output->dist[u] < output->dist[v]) { + output->dist[v] = output->dist[u] + node->weight; + output->prev[v] = u; + decreaseKey(minHeap, v, output->dist[v]); + } + node = node->next; + } + } + + freeMinHeap(minHeap); + + return output; +} + +int *msGraphGetLongestShortestPath(graphObj *graph, int src, int *path_size, + double *path_dist) { + if (!graph || src < 0 || src > graph->numnodes) + return nullptr; + + int *path = + (int *)malloc((graph->numnodes) * + sizeof(int)); // worst case is path traverses all nodes + if (!path) + return nullptr; + + dijkstraOutputObj *output = dijkstra(graph, src); + if (!output) { + free(path); + return nullptr; // algorithm failed for some reason + } + + // get longest shortest distance from src to another node (our dest) + *path_dist = -1; + int dest = -1; + for (int i = 0; i < graph->numnodes; i++) { + if (output->dist[i] != HUGE_VAL && *path_dist < output->dist[i]) { + *path_dist = output->dist[i]; + dest = i; + } + } + + if (dest == -1) { // unable to determine destination node + free(path); + free(output->dist); + free(output->prev); + free(output); + return nullptr; + } + + // construct the path from src to dest + int j = 0; + for (int i = dest; i != -1; i = output->prev[i], j++) + path[j] = i; + std::reverse(path, path + j); + *path_size = j; + + // clean up dijkstra output + free(output->dist); + free(output->prev); + free(output); + + return path; +} diff --git a/src/mapgraph.h b/src/mapgraph.h new file mode 100644 index 0000000000..f1752d5065 --- /dev/null +++ b/src/mapgraph.h @@ -0,0 +1,60 @@ +/****************************************************************************** + * $Id$ + * + * Project: MapServer + * Purpose: Declarations for basic undirected, weighted graph support. + * Author: Steve Lime and the MapServer team. + * + ****************************************************************************** + * Copyright (c) 1996-2005 Regents of the University of Minnesota. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + ****************************************************************************/ + +#ifndef MAPGRAPH_H +#define MAPGRAPH_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct graphNodeObj { + int dest; + double weight; + struct graphNodeObj *next; +} graphNodeObj; + +typedef struct { + int numnodes; + struct graphNodeObj **head; +} graphObj; + +graphObj *msCreateGraph(int numnodes); +void msFreeGraph(graphObj *graph); +int msGraphAddEdge(graphObj *graph, int src, int dest, double weight); +void msPrintGraph(graphObj *graph); + +int *msGraphGetLongestShortestPath(graphObj *graph, int src, int *path_size, + double *path_dist); + +#ifdef __cplusplus +} +#endif + +#endif /* MAPGRAPH_H */ diff --git a/src/mapgraticule.c b/src/mapgraticule.c new file mode 100644 index 0000000000..20184fca1b --- /dev/null +++ b/src/mapgraticule.c @@ -0,0 +1,1336 @@ +/********************************************************************** + * $Id$ + * + * Project: MapServer + * Purpose: Graticule Renderer + * Author: John Novak, Novacell Technologies (jnovak@novacell.com) + * + ********************************************************************** + * Copyright (c) 2003, John Novak, Novacell Technologies + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + ****************************************************************************/ + +#include "mapserver.h" +#include +#include "mapproject.h" + +/********************************************************************************************************************** + * + */ +typedef enum { posBottom = 1, posTop, posLeft, posRight } msGraticulePosition; + +typedef enum { + lpDefault = 0, + lpDDMMSS = 1, + lpDDMM, + lpDD +} msLabelProcessingType; + +void DefineAxis(int iTickCountTarget, double *Min, double *Max, double *Inc); +static int _AdjustLabelPosition(layerObj *pLayer, shapeObj *pShape, + msGraticulePosition ePosition); +static void _FormatLabel(layerObj *pLayer, shapeObj *pShape, + double dDataToFormat); + +int msGraticuleLayerInitItemInfo(layerObj *layer); + +#define MAPGRATICULE_ARC_SUBDIVISION_DEFAULT (256) +#define MAPGRATICULE_ARC_MINIMUM (16) +#define MAPGRATICULE_FORMAT_STRING_DEFAULT "%5.2g" +#define MAPGRATICULE_FORMAT_STRING_DDMMSS "%3d %02d %02d" +#define MAPGRATICULE_FORMAT_STRING_DDMM "%3d %02d" +#define MAPGRATICULE_FORMAT_STRING_DD "%3d" + +/********************************************************************************************************************** + * + */ +int msGraticuleLayerOpen(layerObj *layer) { + graticuleObj *pInfo = layer->grid; + + if (pInfo == NULL) + return MS_FAILURE; + + pInfo->dincrementlatitude = 15.0; + pInfo->dincrementlongitude = 15.0; + pInfo->dwhichlatitude = -90.0; + pInfo->dwhichlongitude = -180.0; + pInfo->bvertical = 1; + + if (layer->numclasses == 0) + msDebug("GRID layer has no classes, nothing will be rendered.\n"); + + if (layer->numclasses > 0 && layer->class[0] -> numlabels > 0) + pInfo->blabelaxes = 1; + else + pInfo->blabelaxes = 0; + + if (pInfo->labelformat == NULL) { + pInfo->labelformat = + (char *)msSmallMalloc(strlen(MAPGRATICULE_FORMAT_STRING_DEFAULT) + 1); + pInfo->ilabeltype = (int)lpDefault; + strcpy(pInfo->labelformat, MAPGRATICULE_FORMAT_STRING_DEFAULT); + } else if (strcmp(pInfo->labelformat, "DDMMSS") == 0) { + msFree(pInfo->labelformat); + pInfo->labelformat = + (char *)msSmallMalloc(strlen(MAPGRATICULE_FORMAT_STRING_DDMMSS) + 1); + pInfo->ilabeltype = (int)lpDDMMSS; + strcpy(pInfo->labelformat, MAPGRATICULE_FORMAT_STRING_DDMMSS); + } else if (strcmp(pInfo->labelformat, "DDMM") == 0) { + msFree(pInfo->labelformat); + pInfo->labelformat = + (char *)msSmallMalloc(strlen(MAPGRATICULE_FORMAT_STRING_DDMM) + 1); + pInfo->ilabeltype = (int)lpDDMM; + strcpy(pInfo->labelformat, MAPGRATICULE_FORMAT_STRING_DDMM); + } else if (strcmp(pInfo->labelformat, "DD") == 0) { + msFree(pInfo->labelformat); + pInfo->labelformat = + (char *)msSmallMalloc(strlen(MAPGRATICULE_FORMAT_STRING_DD) + 1); + pInfo->ilabeltype = (int)lpDD; + strcpy(pInfo->labelformat, MAPGRATICULE_FORMAT_STRING_DD); + } + + return MS_SUCCESS; +} + +/********************************************************************************************************************** + * Return MS_TRUE if layer is open, MS_FALSE otherwise. + */ +int msGraticuleLayerIsOpen(layerObj *layer) { + if (layer->grid) + return MS_TRUE; + + return MS_FALSE; +} + +/********************************************************************************************************************** + * + */ +int msGraticuleLayerClose(layerObj *layer) { + (void)layer; + return MS_SUCCESS; +} + +/********************************************************************************************************************** + * + */ +int msGraticuleLayerWhichShapes(layerObj *layer, rectObj rect, int isQuery) { + (void)isQuery; + graticuleObj *pInfo = layer->grid; + int iAxisTickCount = 0; + rectObj rectMapCoordinates; + + if (msCheckParentPointer(layer->map, "map") == MS_FAILURE) + return MS_FAILURE; + + pInfo->dstartlatitude = rect.miny; + pInfo->dstartlongitude = rect.minx; + pInfo->dendlatitude = rect.maxy; + pInfo->dendlongitude = rect.maxx; + pInfo->bvertical = 1; + pInfo->extent = rect; + + if (pInfo->minincrement > 0.0) { + pInfo->dincrementlongitude = pInfo->minincrement; + pInfo->dincrementlatitude = pInfo->minincrement; + } else if (pInfo->maxincrement > 0.0) { + pInfo->dincrementlongitude = pInfo->maxincrement; + pInfo->dincrementlatitude = pInfo->maxincrement; + } else { + pInfo->dincrementlongitude = 0; + pInfo->dincrementlatitude = 0; + } + + if (pInfo->maxarcs > 0) + iAxisTickCount = (int)pInfo->maxarcs; + else if (pInfo->minarcs > 0) + iAxisTickCount = (int)pInfo->minarcs; + + DefineAxis(iAxisTickCount, &pInfo->dstartlongitude, &pInfo->dendlongitude, + &pInfo->dincrementlongitude); + DefineAxis(iAxisTickCount, &pInfo->dstartlatitude, &pInfo->dendlatitude, + &pInfo->dincrementlatitude); + + pInfo->dwhichlatitude = pInfo->dstartlatitude; + pInfo->dwhichlongitude = pInfo->dstartlongitude; + + if (pInfo->minincrement > 0.0 && pInfo->maxincrement > 0.0 && + pInfo->minincrement == pInfo->maxincrement) { + pInfo->dincrementlongitude = pInfo->minincrement; + pInfo->dincrementlatitude = pInfo->minincrement; + } else if (pInfo->minincrement > 0.0) { + pInfo->dincrementlongitude = pInfo->minincrement; + pInfo->dincrementlatitude = pInfo->minincrement; + } else if (pInfo->maxincrement > 0.0) { + pInfo->dincrementlongitude = pInfo->maxincrement; + pInfo->dincrementlatitude = pInfo->maxincrement; + } + + /* + * If using PROJ, project rect back into map system, and generate rect corner + * points in native system. These lines will be used when generating labels to + * get correct placement at arc/rect edge intersections. + */ + rectMapCoordinates = layer->map->extent; + + layer->project = + msProjectionsDiffer(&(layer->projection), &(layer->map->projection)); + if (layer->project && strstr(layer->map->projection.args[0], "epsg:3857") && + msProjIsGeographicCRS(&(layer->projection))) { + if (rectMapCoordinates.minx < -20037508) + rectMapCoordinates.minx = -20037508; + if (rectMapCoordinates.maxx > 20037508) + rectMapCoordinates.maxx = 20037508; + } + + msFree(pInfo->pboundinglines); + pInfo->pboundinglines = (lineObj *)msSmallMalloc(sizeof(lineObj) * 4); + msFree(pInfo->pboundingpoints); + pInfo->pboundingpoints = (pointObj *)msSmallMalloc(sizeof(pointObj) * 8); + + { + + /* + * top + */ + pInfo->pboundinglines[0].numpoints = 2; + pInfo->pboundinglines[0].point = &pInfo->pboundingpoints[0]; + pInfo->pboundinglines[0].point[0].x = rectMapCoordinates.minx; + pInfo->pboundinglines[0].point[0].y = rectMapCoordinates.maxy; + pInfo->pboundinglines[0].point[1].x = rectMapCoordinates.maxx; + pInfo->pboundinglines[0].point[1].y = rectMapCoordinates.maxy; + + if (layer->project) + msProjectLine(&layer->map->projection, &layer->projection, + &pInfo->pboundinglines[0]); + + /* + * bottom + */ + pInfo->pboundinglines[1].numpoints = 2; + pInfo->pboundinglines[1].point = &pInfo->pboundingpoints[2]; + pInfo->pboundinglines[1].point[0].x = rectMapCoordinates.minx; + pInfo->pboundinglines[1].point[0].y = rectMapCoordinates.miny; + pInfo->pboundinglines[1].point[1].x = rectMapCoordinates.maxx; + pInfo->pboundinglines[1].point[1].y = rectMapCoordinates.miny; + + if (layer->project) + msProjectLine(&layer->map->projection, &layer->projection, + &pInfo->pboundinglines[1]); + + /* + * left + */ + pInfo->pboundinglines[2].numpoints = 2; + pInfo->pboundinglines[2].point = &pInfo->pboundingpoints[4]; + pInfo->pboundinglines[2].point[0].x = rectMapCoordinates.minx; + pInfo->pboundinglines[2].point[0].y = rectMapCoordinates.miny; + pInfo->pboundinglines[2].point[1].x = rectMapCoordinates.minx; + pInfo->pboundinglines[2].point[1].y = rectMapCoordinates.maxy; + + if (layer->project) + msProjectLine(&layer->map->projection, &layer->projection, + &pInfo->pboundinglines[2]); + + /* + * right + */ + pInfo->pboundinglines[3].numpoints = 2; + pInfo->pboundinglines[3].point = &pInfo->pboundingpoints[6]; + pInfo->pboundinglines[3].point[0].x = rectMapCoordinates.maxx; + pInfo->pboundinglines[3].point[0].y = rectMapCoordinates.miny; + pInfo->pboundinglines[3].point[1].x = rectMapCoordinates.maxx; + pInfo->pboundinglines[3].point[1].y = rectMapCoordinates.maxy; + + if (layer->project) + msProjectLine(&layer->map->projection, &layer->projection, + &pInfo->pboundinglines[3]); + } + + return MS_SUCCESS; +} + +/********************************************************************************************************************** + * + */ +int msGraticuleLayerNextShape(layerObj *layer, shapeObj *shape) { + graticuleObj *pInfo = layer->grid; + + if (pInfo->minsubdivides <= 0.0 || pInfo->maxsubdivides <= 0.0) + pInfo->minsubdivides = pInfo->maxsubdivides = + MAPGRATICULE_ARC_SUBDIVISION_DEFAULT; + + shape->numlines = 1; + shape->type = MS_SHAPE_LINE; + shape->line = (lineObj *)msSmallMalloc(sizeof(lineObj)); + shape->line->numpoints = (int)pInfo->maxsubdivides; + shape->line->point = NULL; + + /* + * Subdivide and draw current arc, rendering the arc labels first + */ + if (pInfo->bvertical) { + int iPointIndex; + double dArcDelta = (pInfo->dendlatitude - pInfo->dstartlatitude) / + (double)shape->line->numpoints; + double dArcPosition = pInfo->dstartlatitude + dArcDelta; + double dStartY, dDeltaX; + + switch (pInfo->ilabelstate) { + case 0: + if (!pInfo->blabelaxes) { /* Bottom */ + pInfo->ilabelstate++; + msFreeShape(shape); + return MS_SUCCESS; + } + + dDeltaX = (pInfo->dwhichlongitude - pInfo->pboundinglines[1].point[0].x) / + (pInfo->pboundinglines[1].point[1].x - + pInfo->pboundinglines[1].point[0].x); + if (dDeltaX < 0) + dDeltaX = dDeltaX * -1; + + dStartY = (pInfo->pboundinglines[1].point[1].y - + pInfo->pboundinglines[1].point[0].y) * + dDeltaX + + pInfo->pboundinglines[1].point[0].y; + shape->line->numpoints = (int)2; + shape->line->point = (pointObj *)msSmallMalloc(sizeof(pointObj) * 2); + + shape->line->point[0].x = pInfo->dwhichlongitude; + shape->line->point[0].y = dStartY; + shape->line->point[1].x = pInfo->dwhichlongitude; + shape->line->point[1].y = dStartY + dArcDelta; + + _FormatLabel(layer, shape, shape->line->point[0].x); + if (_AdjustLabelPosition(layer, shape, posBottom) != MS_SUCCESS) { + msFreeShape(shape); + pInfo->ilabelstate++; + return MS_SUCCESS; + } + + pInfo->ilabelstate++; + return MS_SUCCESS; + + case 1: + if (!pInfo->blabelaxes) { /* Top */ + pInfo->ilabelstate++; + msFreeShape(shape); + return MS_SUCCESS; + } + + dDeltaX = (pInfo->dwhichlongitude - pInfo->pboundinglines[0].point[0].x) / + (pInfo->pboundinglines[0].point[1].x - + pInfo->pboundinglines[0].point[0].x); + if (dDeltaX < 0) + dDeltaX = dDeltaX * -1; + + dStartY = (pInfo->pboundinglines[0].point[1].y - + pInfo->pboundinglines[0].point[0].y) * + dDeltaX + + pInfo->pboundinglines[0].point[1].y; + shape->line->numpoints = (int)2; + shape->line->point = (pointObj *)msSmallMalloc(sizeof(pointObj) * 2); + + shape->line->point[0].x = pInfo->dwhichlongitude; + shape->line->point[0].y = dStartY - dArcDelta; + shape->line->point[1].x = pInfo->dwhichlongitude; + shape->line->point[1].y = dStartY; + + _FormatLabel(layer, shape, shape->line->point[0].x); + if (_AdjustLabelPosition(layer, shape, posTop) != MS_SUCCESS) { + msFreeShape(shape); + pInfo->ilabelstate++; + return MS_SUCCESS; + } + + pInfo->ilabelstate++; + return MS_SUCCESS; + + case 2: + shape->line->numpoints = (int)shape->line->numpoints + 1; + shape->line->point = + (pointObj *)msSmallMalloc(sizeof(pointObj) * shape->line->numpoints); + + shape->line->point[0].x = pInfo->dwhichlongitude; + shape->line->point[0].y = pInfo->dstartlatitude; + + for (iPointIndex = 1; iPointIndex < shape->line->numpoints; + iPointIndex++) { + shape->line->point[iPointIndex].x = pInfo->dwhichlongitude; + shape->line->point[iPointIndex].y = dArcPosition; + + dArcPosition += dArcDelta; + } + + pInfo->ilabelstate = 0; + + pInfo->dwhichlongitude += pInfo->dincrementlongitude; + break; + + default: + pInfo->ilabelstate = 0; + break; + } + + } else { /*horizontal*/ + int iPointIndex; + double dArcDelta = (pInfo->dendlongitude - pInfo->dstartlongitude) / + (double)shape->line->numpoints; + double dArcPosition = pInfo->dstartlongitude + dArcDelta; + double dStartX, dDeltaY; + + switch (pInfo->ilabelstate) { + case 0: + if (!pInfo->blabelaxes) { /* Left side */ + pInfo->ilabelstate++; + msFreeShape(shape); + return MS_SUCCESS; + } + + dDeltaY = (pInfo->dwhichlatitude - pInfo->pboundinglines[2].point[0].y) / + (pInfo->pboundinglines[2].point[1].y - + pInfo->pboundinglines[2].point[0].y); + if (dDeltaY < 0) + dDeltaY = dDeltaY * -1; + + dStartX = (pInfo->pboundinglines[2].point[1].x - + pInfo->pboundinglines[2].point[0].x) * + dDeltaY + + pInfo->pboundinglines[2].point[0].x; + shape->line->numpoints = (int)2; + shape->line->point = (pointObj *)msSmallMalloc(sizeof(pointObj) * 2); + + shape->line->point[0].x = dStartX; + shape->line->point[0].y = pInfo->dwhichlatitude; + shape->line->point[1].x = dStartX + dArcDelta; + shape->line->point[1].y = pInfo->dwhichlatitude; + + _FormatLabel(layer, shape, shape->line->point[0].y); + if (_AdjustLabelPosition(layer, shape, posLeft) != MS_SUCCESS) { + msFreeShape(shape); + pInfo->ilabelstate++; + return MS_SUCCESS; + } + + pInfo->ilabelstate++; + return MS_SUCCESS; + + case 1: + if (!pInfo->blabelaxes) { /* Right side */ + pInfo->ilabelstate++; + msFreeShape(shape); + return MS_SUCCESS; + } + + dDeltaY = (pInfo->dwhichlatitude - pInfo->pboundinglines[3].point[0].y) / + (pInfo->pboundinglines[3].point[1].y - + pInfo->pboundinglines[3].point[0].y); + if (dDeltaY < 0) + dDeltaY = dDeltaY * -1; + + dStartX = (pInfo->pboundinglines[3].point[1].x - + pInfo->pboundinglines[3].point[0].x) * + dDeltaY + + pInfo->pboundinglines[3].point[0].x; + shape->line->numpoints = (int)2; + shape->line->point = (pointObj *)msSmallMalloc(sizeof(pointObj) * 2); + + shape->line->point[0].x = dStartX - dArcDelta; + shape->line->point[0].y = pInfo->dwhichlatitude; + shape->line->point[1].x = dStartX; + shape->line->point[1].y = pInfo->dwhichlatitude; + + _FormatLabel(layer, shape, shape->line->point[0].y); + if (_AdjustLabelPosition(layer, shape, posRight) != MS_SUCCESS) { + msFreeShape(shape); + pInfo->ilabelstate++; + return MS_SUCCESS; + } + + pInfo->ilabelstate++; + return MS_SUCCESS; + + case 2: + shape->line->numpoints = (int)shape->line->numpoints + 1; + shape->line->point = + (pointObj *)msSmallMalloc(sizeof(pointObj) * shape->line->numpoints); + + shape->line->point[0].x = pInfo->dstartlongitude; + shape->line->point[0].y = pInfo->dwhichlatitude; + + for (iPointIndex = 1; iPointIndex < shape->line->numpoints; + iPointIndex++) { + shape->line->point[iPointIndex].x = dArcPosition; + shape->line->point[iPointIndex].y = pInfo->dwhichlatitude; + + dArcPosition += dArcDelta; + } + + pInfo->ilabelstate = 0; + pInfo->dwhichlatitude += pInfo->dincrementlatitude; + break; + + default: + pInfo->ilabelstate = 0; + break; + } + } + + /* + * Increment and move to next arc + */ + + if (pInfo->bvertical && pInfo->dwhichlongitude > pInfo->dendlongitude) { + pInfo->dwhichlatitude = pInfo->dstartlatitude; + pInfo->bvertical = 0; + } + + if (pInfo->dwhichlatitude > pInfo->dendlatitude) { + /* free the lineObj and pointObj that have been erroneously allocated + * beforehand */ + msFreeShape(shape); + return MS_DONE; + } + + return MS_SUCCESS; +} + +/********************************************************************************************************************** + * + */ +int msGraticuleLayerGetItems(layerObj *layer) { + char **ppItemName = (char **)msSmallMalloc(sizeof(char *)); + + *ppItemName = (char *)msSmallMalloc(64); /* why is this necessary? */ + strcpy(*ppItemName, "Graticule"); + + layer->numitems = 1; + layer->items = ppItemName; + + return MS_SUCCESS; +} + +/********************************************************************************************************************** + * + */ +int msGraticuleLayerInitItemInfo(layerObj *layer) { + (void)layer; + return MS_SUCCESS; +} + +/********************************************************************************************************************** + * + */ +void msGraticuleLayerFreeItemInfo(layerObj *layer) { (void)layer; } + +/********************************************************************************************************************** + * + */ +int msGraticuleLayerGetShape(layerObj *layer, shapeObj *shape, + resultObj *record) { + (void)layer; + (void)shape; + (void)record; + return MS_FAILURE; +} + +/********************************************************************************************************************** + * + */ +int msGraticuleLayerGetExtent(layerObj *layer, rectObj *extent) { + graticuleObj *pInfo = layer->grid; + + if (pInfo) { + *extent = pInfo->extent; + return MS_SUCCESS; + } + + return MS_FAILURE; +} + +/********************************************************************************************************************** + * + */ +int msGraticuleLayerGetAutoStyle(mapObj *map, layerObj *layer, classObj *c, + shapeObj *shape) { + (void)map; + (void)layer; + (void)c; + (void)shape; + return MS_SUCCESS; +} + +/************************************************************************/ +/* msGraticuleLayerFreeIntersectionPoints */ +/* */ +/* Free intersection object. */ +/************************************************************************/ +void msGraticuleLayerFreeIntersectionPoints(graticuleIntersectionObj *psValue) { + if (psValue) { + for (int i = 0; i < psValue->nTop; i++) + msFree(psValue->papszTopLabels[i]); + msFree(psValue->papszTopLabels); + msFree(psValue->pasTop); + + for (int i = 0; i < psValue->nBottom; i++) + msFree(psValue->papszBottomLabels[i]); + msFree(psValue->papszBottomLabels); + msFree(psValue->pasBottom); + + for (int i = 0; i < psValue->nLeft; i++) + msFree(psValue->papszLeftLabels[i]); + msFree(psValue->papszLeftLabels); + msFree(psValue->pasLeft); + + for (int i = 0; i < psValue->nRight; i++) + msFree(psValue->papszRightLabels[i]); + msFree(psValue->papszRightLabels); + msFree(psValue->pasRight); + + msFree(psValue); + } +} + +/************************************************************************/ +/* msGraticuleLayerInitIntersectionPoints */ +/* */ +/* init intersection object. */ +/************************************************************************/ +static void +msGraticuleLayerInitIntersectionPoints(graticuleIntersectionObj *psValue) { + if (psValue) { + psValue->nTop = 0; + psValue->pasTop = NULL; + psValue->papszTopLabels = NULL; + psValue->nBottom = 0; + psValue->pasBottom = NULL; + psValue->papszBottomLabels = NULL; + psValue->nLeft = 0; + psValue->pasLeft = NULL; + psValue->papszLeftLabels = NULL; + psValue->nRight = 0; + psValue->pasRight = NULL; + psValue->papszRightLabels = NULL; + } +} + +/************************************************************************/ +/* msGraticuleLayerGetIntersectionPoints */ +/* */ +/* Utility function thar returns all intersection positions and */ +/* labels (4 sides of the map) for a grid layer. */ +/************************************************************************/ +graticuleIntersectionObj * +msGraticuleLayerGetIntersectionPoints(mapObj *map, layerObj *layer) { + + shapeObj shapegrid, tmpshape; + rectObj searchrect; + int status; + pointObj oFirstPoint; + pointObj oLastPoint; + lineObj oLineObj; + rectObj cliprect; + graticuleObj *pInfo = NULL; + double dfTmp; + int i = 0; + + if (layer->connectiontype != MS_GRATICULE) + return NULL; + + pInfo = layer->grid; + + /*set cellsize if bnot already set*/ + if (map->cellsize == 0) + map->cellsize = msAdjustExtent(&(map->extent), map->width, map->height); + + if (layer->transform == MS_TRUE) + searchrect = map->extent; + else { + searchrect.minx = searchrect.miny = 0; + searchrect.maxx = map->width - 1; + searchrect.maxy = map->height - 1; + } + + if ((map->projection.numargs > 0) && (layer->projection.numargs > 0)) + msProjectRect(&map->projection, &layer->projection, + &searchrect); /* project the searchrect to source coords */ + + status = msLayerOpen(layer); + if (status != MS_SUCCESS) + return NULL; + + status = msLayerWhichShapes(layer, searchrect, MS_FALSE); + if (status == MS_DONE) { /* no overlap */ + msLayerClose(layer); + return NULL; + } else if (status != MS_SUCCESS) { + msLayerClose(layer); + return NULL; + } + + /* step through the target shapes */ + msInitShape(&shapegrid); + cliprect.minx = map->extent.minx - map->cellsize; + cliprect.miny = map->extent.miny - map->cellsize; + cliprect.maxx = map->extent.maxx + map->cellsize; + cliprect.maxy = map->extent.maxy + map->cellsize; + + /* clip using the layer projection */ + /* msProjectRect(&map->projection , &layer->projection, &cliprect); */ + + graticuleIntersectionObj *psValues = + (graticuleIntersectionObj *)msSmallMalloc( + sizeof(graticuleIntersectionObj)); + msGraticuleLayerInitIntersectionPoints(psValues); + + while ((status = msLayerNextShape(layer, &shapegrid)) == MS_SUCCESS) { + /*don't really need a class here*/ + /* + shapegrid.classindex = msShapeGetClass(layer, &shapegrid, map->scaledenom, + NULL, 0); if((shapegrid.classindex == -1) || + (layer->class[shapegrid.classindex]->status == MS_OFF)) { + msFreeShape(&shapegrid); + continue; + } + */ + + msInitShape(&tmpshape); + msCopyShape(&shapegrid, &tmpshape); + /* status = msDrawShape(map, layer, &tmpshape, image, -1); */ + + if (layer->project) { + if (layer->reprojectorLayerToMap == NULL) { + layer->reprojectorLayerToMap = + msProjectCreateReprojector(&layer->projection, &map->projection); + } + if (layer->reprojectorLayerToMap) + msProjectShapeEx(layer->reprojectorLayerToMap, &shapegrid); + } + + msClipPolylineRect(&shapegrid, cliprect); + + msTransformShapeToPixelRound(&shapegrid, map->extent, map->cellsize); + + if (shapegrid.numlines <= 0 || + shapegrid.line[0].numpoints < + 2) { /* once clipped the shape didn't need to be drawn */ + msFreeShape(&shapegrid); + msFreeShape(&tmpshape); + continue; + } + + { + int iTmpLine = 0; + int nNumPoints = 0; + /*grid code seems to return lines that can double cross the extenst??*/ + /*creating a more than one clipped shape. Take the shape that has the most + points, which should be the most likley to be correct*/ + + if (shapegrid.numlines > 1) { + for (i = 0; i < shapegrid.numlines; i++) { + if (shapegrid.line[i].numpoints > nNumPoints) { + nNumPoints = shapegrid.line[i].numpoints; + iTmpLine = i; + } + } + } + /* get the first and last point*/ + oFirstPoint.x = shapegrid.line[iTmpLine].point[0].x; + oFirstPoint.y = shapegrid.line[iTmpLine].point[0].y; + oLineObj = shapegrid.line[iTmpLine]; + oLastPoint.x = oLineObj.point[oLineObj.numpoints - 1].x; + oLastPoint.y = oLineObj.point[oLineObj.numpoints - 1].y; + + if (pInfo->bvertical) { /*vertical*/ + /*SHAPES ARE DRAWN FROM BOTTOM TO TOP.*/ + /*Normally lines are drawn FROM BOTTOM TO TOP but not always for some + reason, so make sure that firstpoint < lastpoint in y, We are in pixel + coordinates so y increases as we we go down*/ + if (oFirstPoint.y < oLastPoint.y) { + dfTmp = oFirstPoint.x; + oFirstPoint.x = oLastPoint.x; + oLastPoint.x = dfTmp; + dfTmp = oFirstPoint.y; + oFirstPoint.y = oLastPoint.y; + oLastPoint.y = dfTmp; + } + + /*first point should cross the BOTTOM base where y== map->height*/ + + if (abs((int)oFirstPoint.y - map->height) <= 1) { + char *pszLabel = NULL; + oFirstPoint.y = map->height; + + /*validate point is in map width/height*/ + if (oFirstPoint.x < 0 || oFirstPoint.x > map->width) + continue; + + /*validate point is in map width/height*/ + if (oLastPoint.x < 0 || oLastPoint.x > map->width) + continue; + + if (shapegrid.text) + pszLabel = msStrdup(shapegrid.text); + else { + _FormatLabel( + layer, &tmpshape, + tmpshape.line[0].point[tmpshape.line[0].numpoints - 1].x); + if (tmpshape.text) + pszLabel = msStrdup(tmpshape.text); + else + pszLabel = msStrdup("unknown"); + } + /*validate that the value is not already in the array*/ + if (psValues->nBottom > 0) { + /* if (psValues->pasBottom[psValues->nBottom-1].x == oFirstPoint.x) + continue; */ + + for (i = 0; i < psValues->nBottom; i++) { + if (psValues->pasBottom[i].x == oFirstPoint.x) + break; + } + if (i < psValues->nBottom) { + msFree(pszLabel); + continue; + } + } + if (psValues->pasBottom == NULL) { + psValues->pasBottom = (pointObj *)msSmallMalloc(sizeof(pointObj)); + psValues->papszBottomLabels = + (char **)msSmallMalloc(sizeof(char *)); + psValues->nBottom = 1; + } else { + psValues->nBottom++; + psValues->pasBottom = (pointObj *)msSmallRealloc( + psValues->pasBottom, sizeof(pointObj) * psValues->nBottom); + psValues->papszBottomLabels = + (char **)msSmallRealloc(psValues->papszBottomLabels, + sizeof(char *) * psValues->nBottom); + } + + psValues->pasBottom[psValues->nBottom - 1].x = oFirstPoint.x; + psValues->pasBottom[psValues->nBottom - 1].y = oFirstPoint.y; + psValues->papszBottomLabels[psValues->nBottom - 1] = pszLabel; + } + /*first point should cross the TOP base where y==0*/ + if (abs((int)oLastPoint.y) <= 1) { + char *pszLabel = NULL; + oLastPoint.y = 0; + + /*validate point is in map width/height*/ + if (oLastPoint.x < 0 || oLastPoint.x > map->width) + continue; + + if (shapegrid.text) + pszLabel = msStrdup(shapegrid.text); + else { + _FormatLabel( + layer, &tmpshape, + tmpshape.line[0].point[tmpshape.line[0].numpoints - 1].x); + if (tmpshape.text) + pszLabel = msStrdup(tmpshape.text); + else + pszLabel = msStrdup("unknown"); + } + /*validate if same value is not already there*/ + if (psValues->nTop > 0) { + /* if (psValues->pasTop[psValues->nTop-1].x == oLastPoint.x) + continue; */ + + for (i = 0; i < psValues->nTop; i++) { + if (psValues->pasTop[i].x == oLastPoint.x || + strcasecmp(pszLabel, psValues->papszTopLabels[i]) == 0) + break; + } + if (i < psValues->nTop) { + msFree(pszLabel); + continue; + } + } + + if (psValues->pasTop == NULL) { + psValues->pasTop = (pointObj *)msSmallMalloc(sizeof(pointObj)); + psValues->papszTopLabels = (char **)msSmallMalloc(sizeof(char *)); + psValues->nTop = 1; + } else { + psValues->nTop++; + psValues->pasTop = (pointObj *)msSmallRealloc( + psValues->pasTop, sizeof(pointObj) * psValues->nTop); + psValues->papszTopLabels = (char **)msSmallRealloc( + psValues->papszTopLabels, sizeof(char *) * psValues->nTop); + } + + psValues->pasTop[psValues->nTop - 1].x = oLastPoint.x; + psValues->pasTop[psValues->nTop - 1].y = oLastPoint.y; + psValues->papszTopLabels[psValues->nTop - 1] = pszLabel; + } + } else { /*horizontal*/ + /*Normally lines are drawn from left to right but not always for some + reason, so make sure that firstpoint < lastpoint in x*/ + if (oFirstPoint.x > oLastPoint.x) { + + dfTmp = oFirstPoint.x; + oFirstPoint.x = oLastPoint.x; + oLastPoint.x = dfTmp; + dfTmp = oFirstPoint.y; + oFirstPoint.y = oLastPoint.y; + oLastPoint.y = dfTmp; + } + /*first point should cross the LEFT base where x=0 axis*/ + if (abs((int)oFirstPoint.x) <= 1) { + char *pszLabel = NULL; + oFirstPoint.x = 0; + + /*validate point is in map width/height*/ + if (oFirstPoint.y < 0 || oFirstPoint.y > map->height) + continue; + + if (shapegrid.text) + pszLabel = msStrdup(shapegrid.text); + else { + _FormatLabel( + layer, &tmpshape, + tmpshape.line[0].point[tmpshape.line[0].numpoints - 1].y); + if (tmpshape.text) + pszLabel = msStrdup(tmpshape.text); + else + pszLabel = msStrdup("unknown"); + } + + /*validate that the previous value is not the same*/ + if (psValues->nLeft > 0) { + /* if (psValues->pasLeft[psValues->nLeft-1].y == oFirstPoint.y) + continue; */ + + for (i = 0; i < psValues->nLeft; i++) { + if (psValues->pasLeft[i].y == oFirstPoint.y) + break; + } + if (i < psValues->nLeft) { + msFree(pszLabel); + continue; + } + } + if (psValues->pasLeft == NULL) { + psValues->pasLeft = (pointObj *)msSmallMalloc(sizeof(pointObj)); + psValues->papszLeftLabels = (char **)msSmallMalloc(sizeof(char *)); + psValues->nLeft = 1; + } else { + psValues->nLeft++; + psValues->pasLeft = (pointObj *)msSmallRealloc( + psValues->pasLeft, sizeof(pointObj) * psValues->nLeft); + psValues->papszLeftLabels = (char **)msSmallRealloc( + psValues->papszLeftLabels, sizeof(char *) * psValues->nLeft); + } + + psValues->pasLeft[psValues->nLeft - 1].x = oFirstPoint.x; + psValues->pasLeft[psValues->nLeft - 1].y = oFirstPoint.y; + psValues->papszLeftLabels[psValues->nLeft - 1] = + pszLabel; /* takes ownership of allocated pszLabel */ + } + /*first point should cross the RIGHT base where x=map=>width axis*/ + if (abs((int)oLastPoint.x - map->width) <= 1) { + char *pszLabel = NULL; + oLastPoint.x = map->width; + + /*validate point is in map width/height*/ + if (oLastPoint.y < 0 || oLastPoint.y > map->height) + continue; + + if (shapegrid.text) + pszLabel = msStrdup(shapegrid.text); + else { + _FormatLabel( + layer, &tmpshape, + tmpshape.line[0].point[tmpshape.line[0].numpoints - 1].y); + if (tmpshape.text) + pszLabel = msStrdup(tmpshape.text); + else + pszLabel = msStrdup("unknown"); + } + + /*validate that the previous value is not the same*/ + if (psValues->nRight > 0) { + /* if (psValues->pasRight[psValues->nRight-1].y == oLastPoint.y) + continue; */ + for (i = 0; i < psValues->nRight; i++) { + if (psValues->pasRight[i].y == oLastPoint.y) + break; + } + if (i < psValues->nRight) { + msFree(pszLabel); + continue; + } + } + if (psValues->pasRight == NULL) { + psValues->pasRight = (pointObj *)msSmallMalloc(sizeof(pointObj)); + psValues->papszRightLabels = (char **)msSmallMalloc(sizeof(char *)); + psValues->nRight = 1; + } else { + psValues->nRight++; + psValues->pasRight = (pointObj *)msSmallRealloc( + psValues->pasRight, sizeof(pointObj) * psValues->nRight); + psValues->papszRightLabels = (char **)msSmallRealloc( + psValues->papszRightLabels, sizeof(char *) * psValues->nRight); + } + + psValues->pasRight[psValues->nRight - 1].x = oLastPoint.x; + psValues->pasRight[psValues->nRight - 1].y = oLastPoint.y; + psValues->papszRightLabels[psValues->nRight - 1] = pszLabel; + } + } + msFreeShape(&shapegrid); + msFreeShape(&tmpshape); + } + msInitShape(&shapegrid); + } + msLayerClose(layer); + return psValues; +} + +/********************************************************************************************************************** + * + */ +int msGraticuleLayerInitializeVirtualTable(layerObj *layer) { + assert(layer != NULL); + assert(layer->vtable != NULL); + + layer->vtable->LayerInitItemInfo = + msGraticuleLayerInitItemInfo; /* should use defaults for item info + functions */ + layer->vtable->LayerFreeItemInfo = msGraticuleLayerFreeItemInfo; + layer->vtable->LayerOpen = msGraticuleLayerOpen; + layer->vtable->LayerIsOpen = msGraticuleLayerIsOpen; + layer->vtable->LayerWhichShapes = msGraticuleLayerWhichShapes; + layer->vtable->LayerNextShape = msGraticuleLayerNextShape; + /* layer->vtable->LayerResultsGetShape, use default */ + layer->vtable->LayerGetShape = msGraticuleLayerGetShape; + /* layer->vtable->LayerGetShapeCount, use default */ + layer->vtable->LayerClose = msGraticuleLayerClose; + layer->vtable->LayerGetItems = msGraticuleLayerGetItems; + layer->vtable->LayerGetExtent = msGraticuleLayerGetExtent; + layer->vtable->LayerGetAutoStyle = msGraticuleLayerGetAutoStyle; + /* layer->vtable->LayerCloseConnection, use default */; + layer->vtable->LayerSetTimeFilter = msLayerMakePlainTimeFilter; + /* layer->vtable->LayerApplyFilterToLayer, use default */ + /* layer->vtable->LayerCreateItems, use default */ + /* layer->vtable->LayerGetNumFeatures, use default */ + + return MS_SUCCESS; +} + +/********************************************************************************************************************** + * + */ +static void _FormatLabel(layerObj *pLayer, shapeObj *pShape, + double dDataToFormat) { + graticuleObj *pInfo = pLayer->grid; + char cBuffer[32]; + int iDegrees, iMinutes; + + switch (pInfo->ilabeltype) { + case lpDDMMSS: + iDegrees = (int)dDataToFormat; + dDataToFormat = fabs(dDataToFormat - (double)iDegrees); + iMinutes = (int)(dDataToFormat * 60.0); + dDataToFormat = dDataToFormat - (((double)iMinutes) / 60.0); + sprintf(cBuffer, pInfo->labelformat, iDegrees, iMinutes, + (int)(dDataToFormat * 3600.0)); + break; + case lpDDMM: + iDegrees = (int)dDataToFormat; + dDataToFormat = fabs(dDataToFormat - (double)iDegrees); + sprintf(cBuffer, pInfo->labelformat, iDegrees, (int)(dDataToFormat * 60.0)); + break; + case lpDD: + iDegrees = (int)dDataToFormat; + sprintf(cBuffer, pInfo->labelformat, iDegrees); + break; + case lpDefault: + default: + sprintf(cBuffer, pInfo->labelformat, dDataToFormat); + } + + pShape->text = msStrdup(cBuffer); +} + +/********************************************************************************************************************** + * + * Move label position into display area by adjusting underlying shape line. + */ +static int _AdjustLabelPosition(layerObj *pLayer, shapeObj *pShape, + msGraticulePosition ePosition) { + graticuleObj *pInfo = pLayer->grid; + rectObj rectLabel; + pointObj ptPoint; + double size = -1; + char *labeltxt; + + if (pInfo == NULL || pShape == NULL) { + msSetError(MS_MISCERR, + "Assertion failed: Null shape or non-configured grid!, ", + "_AdjustLabelPosition()"); + return MS_FAILURE; + } + + assert(pLayer->class[0] -> numlabels >= 1); + + if (msCheckParentPointer(pLayer->map, "map") == MS_FAILURE) + return MS_FAILURE; + + ptPoint = pShape->line->point[0]; + + if (pLayer->project) { + if (pLayer->reprojectorLayerToMap == NULL) { + pLayer->reprojectorLayerToMap = msProjectCreateReprojector( + &pLayer->projection, &pLayer->map->projection); + } + if (pLayer->reprojectorLayerToMap) + msProjectShapeEx(pLayer->reprojectorLayerToMap, pShape); + + /* Poor man detection of reprojection failure */ + if (msProjIsGeographicCRS(&(pLayer->projection)) != + msProjIsGeographicCRS(&(pLayer->map->projection))) { + if (ptPoint.x == pShape->line->point[0].x && + ptPoint.y == pShape->line->point[0].y) { + return MS_FAILURE; + } + } + } + + if (pLayer->transform) { + msTransformShapeToPixelRound(pShape, pLayer->map->extent, + pLayer->map->cellsize); + } + + size = pLayer->class[0] + ->labels[0] + ->size; /* TODO someday: adjust minsize/maxsize/resolution*/ + /* We only use the first label as there's no use (yet) in defining multiple + labels for GRID layers, as the only label to represent is the longitude or + latitude */ + labeltxt = + msShapeGetLabelAnnotation(pLayer, pShape, pLayer->class[0] -> labels[0]); + assert(labeltxt); + if (msGetStringSize(pLayer->map, pLayer->class[0] -> labels[0], size, + labeltxt, &rectLabel) != MS_SUCCESS) { + free(labeltxt); + return MS_FAILURE; /* msSetError already called */ + } + free(labeltxt); + + switch (ePosition) { + case posBottom: + pShape->line->point[1].y = pLayer->map->height; + pShape->line->point[0].y = + pLayer->map->height - (fabs(rectLabel.maxy - rectLabel.miny) * 2 + 5); + break; + case posTop: + pShape->line->point[1].y = 0; + pShape->line->point[0].y = fabs(rectLabel.maxy - rectLabel.miny) * 2 + 5; + break; + case posLeft: + pShape->line->point[0].x = 0; + pShape->line->point[1].x = fabs(rectLabel.maxx - rectLabel.minx) * 2 + 5; + break; + case posRight: + pShape->line->point[1].x = pLayer->map->width; + pShape->line->point[0].x = + pLayer->map->width - (fabs(rectLabel.maxx - rectLabel.minx) * 2 + 5); + break; + } + + if (pLayer->transform) + msTransformPixelToShape(pShape, pLayer->map->extent, pLayer->map->cellsize); + + if (pLayer->project) { + /* Clamp coordinates into the validity area of the projection, in the */ + /* particular case of EPSG:3857 (WebMercator) to longlat reprojection */ + if (strstr(pLayer->map->projection.args[0], "epsg:3857") && + msProjIsGeographicCRS(&(pLayer->projection))) { + if (!pLayer->map->projection.gt.need_geotransform && + ePosition == posLeft && pShape->line->point[0].x < -20037508) { + pShape->line->point[1].x = + -20037508 + (pShape->line->point[1].x - pShape->line->point[0].x); + pShape->line->point[0].x = -20037508; + } else if (pLayer->map->projection.gt.need_geotransform && + ePosition == posLeft && + pLayer->map->projection.gt.geotransform[0] + + pShape->line->point[0].x * + pLayer->map->projection.gt.geotransform[1] + + pShape->line->point[0].y * + pLayer->map->projection.gt.geotransform[2] < + -20037508) { + double y_tmp; + double width = pShape->line->point[1].x - pShape->line->point[0].x; + + y_tmp = pLayer->map->projection.gt.geotransform[3] + + pShape->line->point[0].x * + pLayer->map->projection.gt.geotransform[4] + + pShape->line->point[0].y * + pLayer->map->projection.gt.geotransform[5]; + pShape->line->point[0].x = + pLayer->map->projection.gt.invgeotransform[0] + + -20037508 * pLayer->map->projection.gt.invgeotransform[1] + + y_tmp * pLayer->map->projection.gt.invgeotransform[2]; + pShape->line->point[1].x = pShape->line->point[0].x + width; + } + + if (!pLayer->map->projection.gt.need_geotransform && + ePosition == posRight && pShape->line->point[1].x > 20037508) { + pShape->line->point[0].x = + 20037508 - (pShape->line->point[1].x - pShape->line->point[0].x); + pShape->line->point[1].x = 20037508; + } else if (pLayer->map->projection.gt.need_geotransform && + ePosition == posRight && + pLayer->map->projection.gt.geotransform[0] + + pShape->line->point[1].x * + pLayer->map->projection.gt.geotransform[1] + + pShape->line->point[1].y * + pLayer->map->projection.gt.geotransform[2] > + 20037508) { + double y_tmp; + double width = pShape->line->point[1].x - pShape->line->point[0].x; + + y_tmp = pLayer->map->projection.gt.geotransform[3] + + pShape->line->point[1].x * + pLayer->map->projection.gt.geotransform[4] + + pShape->line->point[1].y * + pLayer->map->projection.gt.geotransform[5]; + pShape->line->point[1].x = + pLayer->map->projection.gt.invgeotransform[0] + + 20037508 * pLayer->map->projection.gt.invgeotransform[1] + + y_tmp * pLayer->map->projection.gt.invgeotransform[2]; + pShape->line->point[0].x = pShape->line->point[1].x - width; + } + } + + if (pLayer->reprojectorMapToLayer == NULL) { + pLayer->reprojectorMapToLayer = msProjectCreateReprojector( + &pLayer->map->projection, &pLayer->projection); + } + if (pLayer->reprojectorMapToLayer) + msProjectShapeEx(pLayer->reprojectorMapToLayer, pShape); + } + + switch (ePosition) { + case posBottom: + case posTop: + pShape->line->point[1].x = ptPoint.x; + pShape->line->point[0].x = ptPoint.x; + break; + case posLeft: + case posRight: + pShape->line->point[1].y = ptPoint.y; + pShape->line->point[0].y = ptPoint.y; + break; + } + + return MS_SUCCESS; +} + +/********************************************************************************************************************** + ********************************************************************************************************************** + * DefineAxes - Copyright (c) 2000, Michael P.D. Bramley. + * + * Permission is granted to use this code without restriction as long as + * this copyright notice appears in all source files. + * + * Minor tweaks to increment calculations - jnovak + */ +void DefineAxis(int iTickCountTarget, double *Min, double *Max, double *Inc) { + /* define local variables... */ + + double Test_inc, /* candidate increment value */ + Test_min, /* minimum scale value */ + Test_max, /* maximum scale value */ + Range = *Max - *Min; /* range of data */ + + int i = 0; /* counter */ + + /* don't create problems -- solve them */ + + if (Range < 0) { + *Inc = 0; + return; + } + + /* handle special case of repeated values */ + + else if (Range == 0) { + *Min = ceil(*Max) - 1; + *Max = *Min + 1; + *Inc = 1; + return; + } + + /* compute candidate for increment */ + + Test_inc = pow(10.0, ceil(log10(Range / 10))); + if (*Inc > 0 && (Test_inc < *Inc || Test_inc > *Inc)) + Test_inc = *Inc; + + /* establish maximum scale value... */ + Test_max = ((long)(*Max / Test_inc)) * Test_inc; + + if (Test_max < *Max) + Test_max += Test_inc; + + /* establish minimum scale value... */ + Test_min = Test_max; + do { + ++i; + Test_min -= Test_inc; + } while (Test_min > *Min); + + /* subtracting small values can screw up the scale limits, */ + /* eg: if DefineAxis is called with (min,max)=(0.01, 0.1), */ + /* then the calculated scale is 1.0408E17 TO 0.05 BY 0.01. */ + /* the following if statement corrects for this... */ + + /* if(fabs(Test_min) < 1E-10) */ + /* Test_min = 0 ; */ + + /* adjust for too few tick marks */ + + if (iTickCountTarget <= 0) + iTickCountTarget = MAPGRATICULE_ARC_MINIMUM; + + while (i < iTickCountTarget) { + Test_inc /= 2; + i *= 2; + } + + if (i < 6 && 0) { + Test_inc /= 2; + if ((Test_min + Test_inc) <= *Min) + Test_min += Test_inc; + if ((Test_max - Test_inc) >= *Max) + Test_max -= Test_inc; + } + + /* pass back axis definition to caller */ + + *Min = Test_min; + *Max = Test_max; + *Inc = Test_inc; +} + +/********************************************************************************************************************** + **********************************************************************************************************************/ diff --git a/src/maphash.c b/src/maphash.c new file mode 100644 index 0000000000..c11f47dd6a --- /dev/null +++ b/src/maphash.c @@ -0,0 +1,246 @@ +/****************************************************************************** + * $Id$ + * + * Project: MapServer + * Purpose: Implement hashTableObj class. + * Author: Sean Gillies, sgillies@frii.com + * + ****************************************************************************** + * Copyright (c) 1996-2005 Regents of the University of Minnesota. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + ****************************************************************************/ + +#include + +#include "mapserver.h" +#include "maphash.h" + +static unsigned hash(const char *key) { + unsigned hashval; + + for (hashval = 0; *key != '\0'; key++) + hashval = tolower(*key) + 31 * hashval; + + return (hashval % MS_HASHSIZE); +} + +hashTableObj *msCreateHashTable() { + int i; + hashTableObj *table; + + table = (hashTableObj *)msSmallMalloc(sizeof(hashTableObj)); + table->items = + (struct hashObj **)msSmallMalloc(sizeof(struct hashObj *) * MS_HASHSIZE); + + for (i = 0; i < MS_HASHSIZE; i++) + table->items[i] = NULL; + table->numitems = 0; + + return table; +} + +int initHashTable(hashTableObj *table) { + int i; + + table->items = + (struct hashObj **)malloc(sizeof(struct hashObj *) * MS_HASHSIZE); + MS_CHECK_ALLOC(table->items, sizeof(struct hashObj *) * MS_HASHSIZE, + MS_FAILURE); + + for (i = 0; i < MS_HASHSIZE; i++) + table->items[i] = NULL; + table->numitems = 0; + return MS_SUCCESS; +} + +void msFreeHashTable(hashTableObj *table) { + if (table != NULL) { + msFreeHashItems(table); + free(table); + } +} + +int msHashIsEmpty(const hashTableObj *table) { + if (table->numitems == 0) + return MS_TRUE; + else + return MS_FALSE; +} + +void msFreeHashItems(hashTableObj *table) { + int i; + struct hashObj *tp = NULL; + struct hashObj *prev_tp = NULL; + + if (table) { + if (table->items) { + for (i = 0; i < MS_HASHSIZE; i++) { + if (table->items[i] != NULL) { + for (tp = table->items[i]; tp != NULL; + prev_tp = tp, tp = tp->next, free(prev_tp)) { + msFree(tp->key); + msFree(tp->data); + } + } + } + free(table->items); + table->items = NULL; + } else { + msSetError(MS_HASHERR, "No items allocated.", "msFreeHashItems()"); + } + } else { + msSetError(MS_HASHERR, "Can't free NULL table", "msFreeHashItems()"); + } +} + +struct hashObj *msInsertHashTable(hashTableObj *table, const char *key, + const char *value) { + struct hashObj *tp; + unsigned hashval; + + if (!table || !key || !value) { + msSetError(MS_HASHERR, "Invalid hash table or key", "msInsertHashTable"); + return NULL; + } + + for (tp = table->items[hash(key)]; tp != NULL; tp = tp->next) + if (strcasecmp(key, tp->key) == 0) + break; + + if (tp == NULL) { /* not found */ + tp = (struct hashObj *)malloc(sizeof(*tp)); + MS_CHECK_ALLOC(tp, sizeof(*tp), NULL); + tp->key = msStrdup(key); + hashval = hash(key); + tp->next = table->items[hashval]; + table->items[hashval] = tp; + table->numitems++; + } else { + free(tp->data); + } + + if ((tp->data = msStrdup(value)) == NULL) + return NULL; + + return tp; +} + +const char *msLookupHashTable(const hashTableObj *table, const char *key) { + struct hashObj *tp; + + if (!table || !key) { + return (NULL); + } + + for (tp = table->items[hash(key)]; tp != NULL; tp = tp->next) + if (strcasecmp(key, tp->key) == 0) + return (tp->data); + + return NULL; +} + +int msRemoveHashTable(hashTableObj *table, const char *key) { + struct hashObj *tp; + struct hashObj *prev_tp = NULL; + int status = MS_FAILURE; + + if (!table || !key) { + msSetError(MS_HASHERR, "No hash table", "msRemoveHashTable"); + return MS_FAILURE; + } + + tp = table->items[hash(key)]; + if (!tp) { + msSetError(MS_HASHERR, "No such hash entry", "msRemoveHashTable"); + return MS_FAILURE; + } + + prev_tp = NULL; + while (tp != NULL) { + if (strcasecmp(key, tp->key) == 0) { + status = MS_SUCCESS; + if (prev_tp) { + prev_tp->next = tp->next; + msFree(tp->key); + msFree(tp->data); + free(tp); + break; + } else { + table->items[hash(key)] = tp->next; + msFree(tp->key); + msFree(tp->data); + free(tp); + break; + } + } + prev_tp = tp; + tp = tp->next; + } + + if (status == MS_SUCCESS) + table->numitems--; + + return status; +} + +const char *msFirstKeyFromHashTable(const hashTableObj *table) { + int hash_index; + + if (!table) { + msSetError(MS_HASHERR, "No hash table", "msFirstKeyFromHashTable"); + return NULL; + } + + for (hash_index = 0; hash_index < MS_HASHSIZE; hash_index++) { + if (table->items[hash_index] != NULL) + return table->items[hash_index]->key; + } + + return NULL; +} + +const char *msNextKeyFromHashTable(const hashTableObj *table, + const char *lastKey) { + int hash_index; + struct hashObj *link; + + if (!table) { + msSetError(MS_HASHERR, "No hash table", "msNextKeyFromHashTable"); + return NULL; + } + + if (lastKey == NULL) + return msFirstKeyFromHashTable(table); + + hash_index = hash(lastKey); + for (link = table->items[hash_index]; + link != NULL && strcasecmp(lastKey, link->key) != 0; link = link->next) { + } + + if (link != NULL && link->next != NULL) + return link->next->key; + + while (++hash_index < MS_HASHSIZE) { + if (table->items[hash_index] != NULL) + return table->items[hash_index]->key; + } + + return NULL; +} diff --git a/src/maphash.h b/src/maphash.h new file mode 100644 index 0000000000..06dc46df66 --- /dev/null +++ b/src/maphash.h @@ -0,0 +1,166 @@ +/****************************************************************************** + * $Id$ + * + * Project: MapServer + * Purpose: Declarations for the hashTableObj and related stuff. + * Author: Sean Gillies, sgillies@frii.com + * + ****************************************************************************** + * Copyright (c) 1996-2005 Regents of the University of Minnesota. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + ****************************************************************************/ + +#ifndef MAPHASH__H +#define MAPHASH__H + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(_WIN32) && !defined(__CYGWIN__) +#define MS_DLL_EXPORT __declspec(dllexport) +#else +#define MS_DLL_EXPORT +#endif + +#define MS_HASHSIZE 41 + +/* ========================================================================= + * Structs + * ========================================================================= */ + +#ifndef SWIG +struct hashObj { + struct hashObj *next; /* pointer to next item */ + char *key; /* string key that is hashed */ + char *data; /* string stored in this item */ +}; +#endif /*SWIG*/ + +/** + * An object to store key-value pairs + * + */ +typedef struct { +#ifndef SWIG + struct hashObj **items; /* the hash table */ +#endif +#ifdef SWIG + %immutable; +#endif /*SWIG*/ + int numitems; ///< \**immutable** number of items +#ifdef SWIG + %mutable; +#endif /*SWIG*/ +} hashTableObj; + +/* ========================================================================= + * Functions + * ========================================================================= */ + +#ifndef SWIG +/* msCreateHashTable - create a hash table + * ARGS: + * None + * RETURNS: + * New hash table + */ +MS_DLL_EXPORT hashTableObj *msCreateHashTable(void); + +/* For use in mapfile.c with hashTableObj structure members */ +MS_DLL_EXPORT int initHashTable(hashTableObj *table); + +/* msFreeHashTable - free allocated memory + * ARGS: + * table - target hash table + * RETURNS: + * None + */ +MS_DLL_EXPORT void msFreeHashTable(hashTableObj *table); + +/* Free only the items for hashTableObj structure members (metadata, &c) */ +MS_DLL_EXPORT void msFreeHashItems(hashTableObj *table); + +/* msInsertHashTable - insert new item + * ARGS: + * table - the target hash table + * key - key string for new item + * value - data string for new item + * RETURNS: + * pointer to the new item or NULL + * EXCEPTIONS: + * raise MS_HASHERR on failure + */ +MS_DLL_EXPORT struct hashObj * +msInsertHashTable(hashTableObj *table, const char *key, const char *value); + +/* msLookupHashTable - get the value of an item by its key + * ARGS: + * table - the target hash table + * key - key string of item + * RETURNS: + * string value of item + */ +MS_DLL_EXPORT const char *msLookupHashTable(const hashTableObj *table, + const char *key); + +/* msRemoveHashTable - remove item from table at key + * ARGS: + * table - target hash table + * key - key string + * RETURNS: + * MS_SUCCESS or MS_FAILURE + */ +MS_DLL_EXPORT int msRemoveHashTable(hashTableObj *table, const char *key); + +/* msFirstKeyFromHashTable - get key of first item + * ARGS: + * table - target hash table + * RETURNS: + * first key as a string + */ +MS_DLL_EXPORT const char *msFirstKeyFromHashTable(const hashTableObj *table); + +/* msNextKeyFromHashTable - get next key + * ARGS: + * table - target hash table + * prevkey - the previous key + * RETURNS: + * the key of the item of following prevkey as a string + */ +MS_DLL_EXPORT const char *msNextKeyFromHashTable(const hashTableObj *table, + const char *prevkey); + +/* msHashIsEmpty - get next key + * ARGS: + * table - target hash table + * RETURNS: + * MS_TRUE if the table is empty and MS_FALSE if the table has items + */ + +MS_DLL_EXPORT int msHashIsEmpty(const hashTableObj *table); + +#endif /*SWIG*/ + +#ifdef __cplusplus +} +#endif + +#endif /* MAPHASH__H */ diff --git a/src/maphttp.c b/src/maphttp.c new file mode 100644 index 0000000000..7c85e7334b --- /dev/null +++ b/src/maphttp.c @@ -0,0 +1,977 @@ +/********************************************************************** + * $Id$ + * + * Project: MapServer + * Purpose: Utility functions to access files via HTTP (requires libcurl) + * Author: Daniel Morissette, DM Solutions Group (morissette@dmsolutions.ca) + * + ********************************************************************** + * Copyright (c) 2001-2003, Daniel Morissette, DM Solutions Group Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + ****************************************************************************/ + +#define NEED_IGNORE_RET_VAL + +/* For now this code is enabled only when WMS/WFS client is enabled. + * This should be changed to a test on the presence of libcurl which + * is really what the real dependency is. + */ +#include "mapserver-config.h" +#if defined(USE_CURL) + +#include "mapserver.h" +#include "maphttp.h" +#include "maperror.h" +#include "mapthread.h" +#include "mapows.h" + +#include "cpl_conv.h" + +#include +#ifndef _WIN32 +#include +#include + +#endif + +/* + * Note: This code uses libcurl to access remote files via the HTTP protocol. + * Requires libcurl v 7.10 or more recent. + * See http://curl.haxx.se/libcurl/c/ for the lib source code and docs. + */ +#include + +#ifndef CURL_AT_LEAST_VERSION +#define CURL_VERSION_BITS(x, y, z) ((x) << 16 | (y) << 8 | z) +#define CURL_AT_LEAST_VERSION(x, y, z) \ + (LIBCURL_VERSION_NUM >= CURL_VERSION_BITS(x, y, z)) +#endif // #ifndef CURL_AT_LEAST_VERSION + +#define unchecked_curl_easy_setopt(handle, opt, param) \ + IGNORE_RET_VAL(curl_easy_setopt(handle, opt, param)) + +/********************************************************************** + * msHTTPInit() + * + * This function is called to init libcurl before the first HTTP request + * in this process is executed. + * On further calls (when gbCurlInitialized = MS_TRUE) it simply doest nothing. + * + * Returns MS_SUCCESS/MS_FAILURE. + * + * msHTTPCleanup() will have to be called in msCleanup() when this process + * exits. + **********************************************************************/ +static int gbCurlInitialized = MS_FALSE; + +int msHTTPInit() { + /* curl_global_init() should only be called once (no matter how + * many threads or libcurl sessions that'll be used) by every + * application that uses libcurl. + */ + + msAcquireLock(TLOCK_OWS); + if (!gbCurlInitialized && curl_global_init(CURL_GLOBAL_ALL) != 0) { + msReleaseLock(TLOCK_OWS); + msSetError(MS_HTTPERR, "Libcurl initialization failed.", "msHTTPInit()"); + return MS_FAILURE; + } + + gbCurlInitialized = MS_TRUE; + + msReleaseLock(TLOCK_OWS); + return MS_SUCCESS; +} + +/********************************************************************** + * msHTTPCleanup() + * + **********************************************************************/ +void msHTTPCleanup() { + msAcquireLock(TLOCK_OWS); + if (gbCurlInitialized) + curl_global_cleanup(); + + gbCurlInitialized = MS_FALSE; + msReleaseLock(TLOCK_OWS); +} + +/********************************************************************** + * msHTTPInitRequestObj() + * + * Should be called on a new array of httpRequestObj to initialize them + * for use with msHTTPExecuteRequest(), etc. + * + **********************************************************************/ +void msHTTPInitRequestObj(httpRequestObj *pasReqInfo, int numRequests) { + int i; + + for (i = 0; i < numRequests; i++) { + pasReqInfo[i].pszGetUrl = NULL; + pasReqInfo[i].pszPostRequest = NULL; + pasReqInfo[i].pszPostContentType = NULL; + pasReqInfo[i].pszOutputFile = NULL; + pasReqInfo[i].pszEPSG = NULL; + pasReqInfo[i].nLayerId = 0; + pasReqInfo[i].nTimeout = 0; + pasReqInfo[i].nMaxBytes = 0; + pasReqInfo[i].nStatus = 0; + pasReqInfo[i].pszContentType = NULL; + pasReqInfo[i].pszErrBuf = NULL; + pasReqInfo[i].pszUserAgent = NULL; + pasReqInfo[i].pszHTTPCookieData = NULL; + pasReqInfo[i].pszProxyAddress = NULL; + pasReqInfo[i].pszProxyUsername = NULL; + pasReqInfo[i].pszProxyPassword = NULL; + pasReqInfo[i].pszHttpUsername = NULL; + pasReqInfo[i].pszHttpPassword = NULL; + + pasReqInfo[i].debug = MS_FALSE; + + pasReqInfo[i].curl_handle = NULL; + pasReqInfo[i].fp = NULL; + pasReqInfo[i].result_data = NULL; + pasReqInfo[i].result_size = 0; + pasReqInfo[i].result_buf_size = 0; + } +} + +/********************************************************************** + * msHTTPFreeRequestObj() + * + **********************************************************************/ +void msHTTPFreeRequestObj(httpRequestObj *pasReqInfo, int numRequests) { + int i; + for (i = 0; i < numRequests; i++) { + if (pasReqInfo[i].pszGetUrl) + free(pasReqInfo[i].pszGetUrl); + pasReqInfo[i].pszGetUrl = NULL; + + if (pasReqInfo[i].pszPostRequest) + free(pasReqInfo[i].pszPostRequest); + pasReqInfo[i].pszPostRequest = NULL; + + if (pasReqInfo[i].pszPostContentType) + free(pasReqInfo[i].pszPostContentType); + pasReqInfo[i].pszPostContentType = NULL; + + if (pasReqInfo[i].pszOutputFile) + free(pasReqInfo[i].pszOutputFile); + pasReqInfo[i].pszOutputFile = NULL; + + if (pasReqInfo[i].pszEPSG) + free(pasReqInfo[i].pszEPSG); + pasReqInfo[i].pszEPSG = NULL; + + if (pasReqInfo[i].pszContentType) + free(pasReqInfo[i].pszContentType); + pasReqInfo[i].pszContentType = NULL; + + if (pasReqInfo[i].pszErrBuf) + free(pasReqInfo[i].pszErrBuf); + pasReqInfo[i].pszErrBuf = NULL; + + if (pasReqInfo[i].pszUserAgent) + free(pasReqInfo[i].pszUserAgent); + pasReqInfo[i].pszUserAgent = NULL; + + if (pasReqInfo[i].pszHTTPCookieData) + free(pasReqInfo[i].pszHTTPCookieData); + pasReqInfo[i].pszHTTPCookieData = NULL; + + pasReqInfo[i].curl_handle = NULL; + + free(pasReqInfo[i].result_data); + pasReqInfo[i].result_data = NULL; + pasReqInfo[i].result_size = 0; + pasReqInfo[i].result_buf_size = 0; + } +} + +/********************************************************************** + * msHTTPWriteFct() + * + * CURL_OPTWRITEFUNCTION, called to write blocks of data to the file we + * are downloading. Should return the number of bytes that were taken + * care of. If that amount differs from the amount passed to it + * it'll signal an error to the library and it will abort the transfer + * and produce a CURLE_WRITE_ERROR. + * + **********************************************************************/ +static size_t msHTTPWriteFct(void *buffer, size_t size, size_t nmemb, + void *reqInfo) { + httpRequestObj *psReq; + + psReq = (httpRequestObj *)reqInfo; + + if (psReq->debug) { + msDebug("msHTTPWriteFct(id=%d, %d bytes)\n", psReq->nLayerId, + (int)(size * nmemb)); + } + + if (psReq->nMaxBytes > 0 && + (psReq->result_size + size * nmemb) > (size_t)psReq->nMaxBytes) { + msSetError(MS_HTTPERR, + "Requested transfer larger than configured maximum %d.", + "msHTTPWriteFct()", psReq->nMaxBytes); + return -1; + } + /* Case where we are writing to a disk file. */ + if (psReq->fp != NULL) { + psReq->result_size += size * nmemb; + return fwrite(buffer, size, nmemb, psReq->fp); + } + + /* Case where we build up the result in memory */ + else { + if (psReq->result_data == NULL) { + psReq->result_buf_size = size * nmemb + 10000; + psReq->result_data = (char *)msSmallMalloc(psReq->result_buf_size); + } else if (psReq->result_size + nmemb * size > + (size_t)psReq->result_buf_size) { + psReq->result_buf_size = psReq->result_size + nmemb * size + 10000; + psReq->result_data = + (char *)msSmallRealloc(psReq->result_data, psReq->result_buf_size); + } + + if (psReq->result_data == NULL) { + msSetError(MS_HTTPERR, "Unable to grow HTTP result buffer to size %d.", + "msHTTPWriteFct()", psReq->result_buf_size); + psReq->result_buf_size = 0; + psReq->result_size = 0; + return -1; + } + + memcpy(psReq->result_data + psReq->result_size, buffer, size * nmemb); + psReq->result_size += size * nmemb; + + return size * nmemb; + } +} + +/********************************************************************** + * msGetCURLAuthType() + * + * Returns the equivalent CURL CURLAUTH_ constant given a + * MS_HTTP_AUTH_TYPE, or CURLAUTH_BASIC if no match is found. + **********************************************************************/ +long msGetCURLAuthType(enum MS_HTTP_AUTH_TYPE authType) { + switch (authType) { + case MS_BASIC: + return CURLAUTH_BASIC; + case MS_DIGEST: + return CURLAUTH_DIGEST; + case MS_NTLM: + return CURLAUTH_NTLM; + case MS_ANY: + return CURLAUTH_ANY; + case MS_ANYSAFE: + return CURLAUTH_ANYSAFE; + default: + return CURLAUTH_BASIC; + } +} + +/********************************************************************** + * msHTTPAuthProxySetup() + * + * Common code used by msPrepareWFSLayerRequest() and + * msPrepareWMSLayerRequest() to handle proxy / http auth for requests + * + * Return value: + * MS_SUCCESS if all requests completed successfully. + * MS_FAILURE if a fatal error happened + **********************************************************************/ +int msHTTPAuthProxySetup(hashTableObj *mapmd, hashTableObj *lyrmd, + httpRequestObj *pasReqInfo, int numRequests, + mapObj *map, const char *namespaces) { + + const char *pszTmp; + char *pszProxyHost = NULL; + long nProxyPort = 0; + char *pszProxyUsername = NULL, *pszProxyPassword = NULL; + char *pszHttpAuthUsername = NULL, *pszHttpAuthPassword = NULL; + enum MS_HTTP_AUTH_TYPE eHttpAuthType = MS_BASIC; + enum MS_HTTP_AUTH_TYPE eProxyAuthType = MS_BASIC; + enum MS_HTTP_PROXY_TYPE eProxyType = MS_HTTP; + + /* ------------------------------------------------------------------ + * Check for authentication and proxying metadata. If the metadata is not + * found in the layer metadata, check the map-level metadata. + * ------------------------------------------------------------------ */ + if ((pszTmp = msOWSLookupMetadata2(lyrmd, mapmd, namespaces, "proxy_host")) != + NULL) { + pszProxyHost = msStrdup(pszTmp); + } + + if ((pszTmp = msOWSLookupMetadata2(lyrmd, mapmd, namespaces, "proxy_port")) != + NULL) { + nProxyPort = atol(pszTmp); + } + + if ((pszTmp = msOWSLookupMetadata2(lyrmd, mapmd, namespaces, "proxy_type")) != + NULL) { + + if (strcasecmp(pszTmp, "HTTP") == 0) + eProxyType = MS_HTTP; + else if (strcasecmp(pszTmp, "SOCKS5") == 0) + eProxyType = MS_SOCKS5; + else { + msSetError(MS_WMSERR, "Invalid proxy_type metadata '%s' specified", + "msHTTPAuthProxySetup()", pszTmp); + return MS_FAILURE; + } + } + + if ((pszTmp = msOWSLookupMetadata2(lyrmd, mapmd, namespaces, + "proxy_auth_type")) != NULL) { + if (strcasecmp(pszTmp, "BASIC") == 0) + eProxyAuthType = MS_BASIC; + else if (strcasecmp(pszTmp, "DIGEST") == 0) + eProxyAuthType = MS_DIGEST; + else if (strcasecmp(pszTmp, "NTLM") == 0) + eProxyAuthType = MS_NTLM; + else if (strcasecmp(pszTmp, "ANY") == 0) + eProxyAuthType = MS_ANY; + else if (strcasecmp(pszTmp, "ANYSAFE") == 0) + eProxyAuthType = MS_ANYSAFE; + else { + msSetError(MS_WMSERR, "Invalid proxy_auth_type metadata '%s' specified", + "msHTTPAuthProxySetup()", pszTmp); + return MS_FAILURE; + } + } + + if ((pszTmp = msOWSLookupMetadata2(lyrmd, mapmd, namespaces, + "proxy_username")) != NULL) { + pszProxyUsername = msStrdup(pszTmp); + } + + if ((pszTmp = msOWSLookupMetadata2(lyrmd, mapmd, namespaces, + "proxy_password")) != NULL) { + pszProxyPassword = msDecryptStringTokens(map, pszTmp); + if (pszProxyPassword == NULL) { + msFree(pszProxyHost); + msFree(pszProxyUsername); + return (MS_FAILURE); /* An error should already have been produced */ + } + } + + if ((pszTmp = msOWSLookupMetadata2(lyrmd, mapmd, namespaces, "auth_type")) != + NULL) { + if (strcasecmp(pszTmp, "BASIC") == 0) + eHttpAuthType = MS_BASIC; + else if (strcasecmp(pszTmp, "DIGEST") == 0) + eHttpAuthType = MS_DIGEST; + else if (strcasecmp(pszTmp, "NTLM") == 0) + eHttpAuthType = MS_NTLM; + else if (strcasecmp(pszTmp, "ANY") == 0) + eHttpAuthType = MS_ANY; + else if (strcasecmp(pszTmp, "ANYSAFE") == 0) + eHttpAuthType = MS_ANYSAFE; + else { + msSetError(MS_WMSERR, "Invalid auth_type metadata '%s' specified", + "msHTTPAuthProxySetup()", pszTmp); + return MS_FAILURE; + } + } + + if ((pszTmp = msOWSLookupMetadata2(lyrmd, mapmd, namespaces, + "auth_username")) != NULL) { + pszHttpAuthUsername = msStrdup(pszTmp); + } + + if ((pszTmp = msOWSLookupMetadata2(lyrmd, mapmd, namespaces, + "auth_password")) != NULL) { + pszHttpAuthPassword = msDecryptStringTokens(map, pszTmp); + if (pszHttpAuthPassword == NULL) { + msFree(pszHttpAuthUsername); + msFree(pszProxyHost); + msFree(pszProxyUsername); + msFree(pszProxyPassword); + return (MS_FAILURE); /* An error should already have been produced */ + } + } + + pasReqInfo[numRequests].pszProxyAddress = pszProxyHost; + pasReqInfo[numRequests].nProxyPort = nProxyPort; + pasReqInfo[numRequests].eProxyType = eProxyType; + pasReqInfo[numRequests].eProxyAuthType = eProxyAuthType; + pasReqInfo[numRequests].pszProxyUsername = pszProxyUsername; + pasReqInfo[numRequests].pszProxyPassword = pszProxyPassword; + pasReqInfo[numRequests].eHttpAuthType = eHttpAuthType; + pasReqInfo[numRequests].pszHttpUsername = pszHttpAuthUsername; + pasReqInfo[numRequests].pszHttpPassword = pszHttpAuthPassword; + + return MS_SUCCESS; +} + +/********************************************************************** + * msHTTPExecuteRequests() + * + * Fetch a map slide via HTTP request and save to specified temp file. + * + * If bCheckLocalCache==MS_TRUE then if the pszOutputfile already exists + * then it is not downloaded again, and status 242 is returned. + * + * Return value: + * MS_SUCCESS if all requests completed successfully. + * MS_FAILURE if a fatal error happened + * MS_DONE if some requests failed with 40x status for instance (not fatal) + **********************************************************************/ +int msHTTPExecuteRequests(httpRequestObj *pasReqInfo, int numRequests, + int bCheckLocalCache) { + int i, nStatus = MS_SUCCESS, nTimeout, still_running = 0, num_msgs = 0; + CURLM *multi_handle; + CURLMsg *curl_msg; + char debug = MS_FALSE; + const char *pszCurlCABundle = NULL; + + if (numRequests == 0) + return MS_SUCCESS; /* Nothing to do */ + + if (!gbCurlInitialized) + msHTTPInit(); + + /* Establish the timeout (seconds) for how long we are going to wait + * for a response. + * We use the longest timeout value in the array of requests + */ + nTimeout = pasReqInfo[0].nTimeout; + for (i = 0; i < numRequests; i++) { + if (pasReqInfo[i].nTimeout > nTimeout) + nTimeout = pasReqInfo[i].nTimeout; + + if (pasReqInfo[i].debug) + debug = MS_TRUE; /* For the download loop */ + } + + if (nTimeout <= 0) + nTimeout = 30; + + /* Check if we've got a CURL_CA_BUNDLE env. var. + * If set then the value is the full path to the ca-bundle.crt file + * e.g. CURL_CA_BUNDLE=/usr/local/share/curl/curl-ca-bundle.crt + */ + pszCurlCABundle = CPLGetConfigOption("CURL_CA_BUNDLE", NULL); + + if (debug) { + msDebug("HTTP: Starting to prepare HTTP requests.\n"); + if (pszCurlCABundle) + msDebug("Using CURL_CA_BUNDLE=%s\n", pszCurlCABundle); + } + + const char *pszHttpVersion = CPLGetConfigOption("CURL_HTTP_VERSION", NULL); + + /* Alloc a curl-multi handle, and add a curl-easy handle to it for each + * file to download. + */ + multi_handle = curl_multi_init(); + if (multi_handle == NULL) { + msSetError(MS_HTTPERR, "curl_multi_init() failed.", + "msHTTPExecuteRequests()"); + return (MS_FAILURE); + } + + for (i = 0; i < numRequests; i++) { + CURL *http_handle; + FILE *fp; + + if (pasReqInfo[i].pszGetUrl == NULL) { + msSetError(MS_HTTPERR, "URL or output file parameter missing.", + "msHTTPExecuteRequests()"); + return (MS_FAILURE); + } + + if (pasReqInfo[i].debug) { + msDebug("HTTP request: id=%d, %s\n", pasReqInfo[i].nLayerId, + pasReqInfo[i].pszGetUrl); + } + + /* Reset some members */ + pasReqInfo[i].nStatus = 0; + if (pasReqInfo[i].pszContentType) + free(pasReqInfo[i].pszContentType); + pasReqInfo[i].pszContentType = NULL; + + /* Check local cache if requested */ + if (bCheckLocalCache && pasReqInfo[i].pszOutputFile != NULL) { + fp = fopen(pasReqInfo[i].pszOutputFile, "r"); + if (fp) { + /* File already there, don't download again. */ + if (pasReqInfo[i].debug) + msDebug("HTTP request: id=%d, found in cache, skipping.\n", + pasReqInfo[i].nLayerId); + fclose(fp); + pasReqInfo[i].nStatus = 242; + pasReqInfo[i].pszContentType = msStrdup("unknown/cached"); + continue; + } + } + + /* Alloc curl handle */ + http_handle = curl_easy_init(); + if (http_handle == NULL) { + msSetError(MS_HTTPERR, "curl_easy_init() failed.", + "msHTTPExecuteRequests()"); + return (MS_FAILURE); + } + + pasReqInfo[i].curl_handle = http_handle; + + /* set URL, note that curl keeps only a ref to our string buffer */ + unchecked_curl_easy_setopt(http_handle, CURLOPT_URL, + pasReqInfo[i].pszGetUrl); + +#if CURL_AT_LEAST_VERSION(7, 85, 0) + unchecked_curl_easy_setopt(http_handle, CURLOPT_PROTOCOLS_STR, + "http,https"); +#else + unchecked_curl_easy_setopt(http_handle, CURLOPT_PROTOCOLS, + CURLPROTO_HTTP | CURLPROTO_HTTPS); +#endif + + if (pszHttpVersion && strcmp(pszHttpVersion, "1.0") == 0) + unchecked_curl_easy_setopt(http_handle, CURLOPT_HTTP_VERSION, + CURL_HTTP_VERSION_1_0); + else if (pszHttpVersion && strcmp(pszHttpVersion, "1.1") == 0) + unchecked_curl_easy_setopt(http_handle, CURLOPT_HTTP_VERSION, + CURL_HTTP_VERSION_1_1); + + /* Set User-Agent (auto-generate if not set by caller */ + if (pasReqInfo[i].pszUserAgent == NULL) { + curl_version_info_data *psCurlVInfo; + + psCurlVInfo = curl_version_info(CURLVERSION_NOW); + + pasReqInfo[i].pszUserAgent = (char *)msSmallMalloc(100 * sizeof(char)); + + if (pasReqInfo[i].pszUserAgent) { + sprintf(pasReqInfo[i].pszUserAgent, "MapServer/%s libcurl/%d.%d.%d", + MS_VERSION, psCurlVInfo->version_num / 0x10000 & 0xff, + psCurlVInfo->version_num / 0x100 & 0xff, + psCurlVInfo->version_num & 0xff); + } + } + if (pasReqInfo[i].pszUserAgent) { + unchecked_curl_easy_setopt(http_handle, CURLOPT_USERAGENT, + pasReqInfo[i].pszUserAgent); + } + + /* Enable following redirections. Requires libcurl 7.10.1 at least */ + unchecked_curl_easy_setopt(http_handle, CURLOPT_FOLLOWLOCATION, 1); + unchecked_curl_easy_setopt(http_handle, CURLOPT_MAXREDIRS, 10); + + /* Set timeout.*/ + unchecked_curl_easy_setopt(http_handle, CURLOPT_TIMEOUT, nTimeout); + + /* Pass CURL_CA_BUNDLE if set */ + if (pszCurlCABundle) + unchecked_curl_easy_setopt(http_handle, CURLOPT_CAINFO, pszCurlCABundle); + + /* Set proxying settings */ + if (pasReqInfo[i].pszProxyAddress != NULL && + strlen(pasReqInfo[i].pszProxyAddress) > 0) { + long nProxyType = CURLPROXY_HTTP; + + unchecked_curl_easy_setopt(http_handle, CURLOPT_PROXY, + pasReqInfo[i].pszProxyAddress); + + if (pasReqInfo[i].nProxyPort > 0 && pasReqInfo[i].nProxyPort < 65535) { + unchecked_curl_easy_setopt(http_handle, CURLOPT_PROXYPORT, + pasReqInfo[i].nProxyPort); + } + + switch (pasReqInfo[i].eProxyType) { + case MS_HTTP: + nProxyType = CURLPROXY_HTTP; + break; + case MS_SOCKS5: + nProxyType = CURLPROXY_SOCKS5; + break; + } + unchecked_curl_easy_setopt(http_handle, CURLOPT_PROXYTYPE, nProxyType); + + /* If there is proxy authentication information, set it */ + if (pasReqInfo[i].pszProxyUsername != NULL && + pasReqInfo[i].pszProxyPassword != NULL && + strlen(pasReqInfo[i].pszProxyUsername) > 0 && + strlen(pasReqInfo[i].pszProxyPassword) > 0) { + char szUsernamePasswd[128]; +#if LIBCURL_VERSION_NUM >= 0x070a07 + long nProxyAuthType = CURLAUTH_BASIC; + /* CURLOPT_PROXYAUTH available only in Curl 7.10.7 and up */ + nProxyAuthType = msGetCURLAuthType(pasReqInfo[i].eProxyAuthType); + unchecked_curl_easy_setopt(http_handle, CURLOPT_PROXYAUTH, + nProxyAuthType); +#else + /* We log an error but don't abort processing */ + msSetError(MS_HTTPERR, + "CURLOPT_PROXYAUTH not supported. Requires Curl 7.10.7 and " + "up. *_proxy_auth_type setting ignored.", + "msHTTPExecuteRequests()"); +#endif /* LIBCURL_VERSION_NUM */ + + snprintf(szUsernamePasswd, 127, "%s:%s", pasReqInfo[i].pszProxyUsername, + pasReqInfo[i].pszProxyPassword); + unchecked_curl_easy_setopt(http_handle, CURLOPT_PROXYUSERPWD, + szUsernamePasswd); + } + } + + /* Set HTTP Authentication settings */ + if (pasReqInfo[i].pszHttpUsername != NULL && + pasReqInfo[i].pszHttpPassword != NULL && + strlen(pasReqInfo[i].pszHttpUsername) > 0 && + strlen(pasReqInfo[i].pszHttpPassword) > 0) { + char szUsernamePasswd[128]; + long nHttpAuthType = CURLAUTH_BASIC; + + snprintf(szUsernamePasswd, 127, "%s:%s", pasReqInfo[i].pszHttpUsername, + pasReqInfo[i].pszHttpPassword); + unchecked_curl_easy_setopt(http_handle, CURLOPT_USERPWD, + szUsernamePasswd); + + nHttpAuthType = msGetCURLAuthType(pasReqInfo[i].eHttpAuthType); + unchecked_curl_easy_setopt(http_handle, CURLOPT_HTTPAUTH, nHttpAuthType); + } + + /* NOSIGNAL should be set to true for timeout to work in multithread + * environments on Unix, requires libcurl 7.10 or more recent. + * (this force avoiding the use of sgnal handlers) + */ +#ifdef CURLOPT_NOSIGNAL + unchecked_curl_easy_setopt(http_handle, CURLOPT_NOSIGNAL, 1); +#endif + + /* If we are writing file to disk, open the file now. */ + if (pasReqInfo[i].pszOutputFile != NULL) { + if ((fp = fopen(pasReqInfo[i].pszOutputFile, "wb")) == NULL) { + msSetError(MS_HTTPERR, "Can't open output file %s.", + "msHTTPExecuteRequests()", pasReqInfo[i].pszOutputFile); + return (MS_FAILURE); + } + + pasReqInfo[i].fp = fp; + } + + /* coverity[bad_sizeof] */ + unchecked_curl_easy_setopt(http_handle, CURLOPT_WRITEDATA, + &(pasReqInfo[i])); + unchecked_curl_easy_setopt(http_handle, CURLOPT_WRITEFUNCTION, + msHTTPWriteFct); + + /* Provide a buffer where libcurl can write human readable error msgs + */ + if (pasReqInfo[i].pszErrBuf == NULL) + pasReqInfo[i].pszErrBuf = + (char *)msSmallMalloc((CURL_ERROR_SIZE + 1) * sizeof(char)); + pasReqInfo[i].pszErrBuf[0] = '\0'; + + unchecked_curl_easy_setopt(http_handle, CURLOPT_ERRORBUFFER, + pasReqInfo[i].pszErrBuf); + + pasReqInfo[i].curl_headers = NULL; + + if (pasReqInfo[i].pszPostRequest != NULL) { + char szBuf[100]; + + snprintf(szBuf, 100, "Content-Type: %s", + pasReqInfo[i].pszPostContentType); + pasReqInfo[i].curl_headers = curl_slist_append(NULL, szBuf); + + unchecked_curl_easy_setopt(http_handle, CURLOPT_POST, 1); + unchecked_curl_easy_setopt(http_handle, CURLOPT_POSTFIELDS, + pasReqInfo[i].pszPostRequest); + if (debug) { + msDebug("HTTP: POST = %s", pasReqInfo[i].pszPostRequest); + } + unchecked_curl_easy_setopt(http_handle, CURLOPT_HTTPHEADER, + pasReqInfo[i].curl_headers); + } + + /* Added by RFC-42 HTTP Cookie Forwarding */ + if (pasReqInfo[i].pszHTTPCookieData != NULL) { + /* Check if there's no end of line in the Cookie string */ + /* This could break the HTTP Header */ + for (size_t nPos = 0; nPos < strlen(pasReqInfo[i].pszHTTPCookieData); + nPos++) { + if (pasReqInfo[i].pszHTTPCookieData[nPos] == '\n') { + msSetError(MS_HTTPERR, + "Can't use cookie containing a newline character.", + "msHTTPExecuteRequests()"); + return (MS_FAILURE); + } + } + + /* Set the Curl option to send Cookie */ + unchecked_curl_easy_setopt(http_handle, CURLOPT_COOKIE, + pasReqInfo[i].pszHTTPCookieData); + } + + /* Add to multi handle */ + curl_multi_add_handle(multi_handle, http_handle); + } + + if (debug) { + msDebug("HTTP: Before download loop\n"); + } + + /* DOWNLOAD LOOP ... inspired from multi-double.c example */ + + /* we start some action by calling perform right away */ + while (CURLM_CALL_MULTI_PERFORM == + curl_multi_perform(multi_handle, &still_running)) + ; + + while (still_running) { + struct timeval timeout; + int rc; /* select() return code */ + + fd_set fdread; + fd_set fdwrite; + fd_set fdexcep; + int maxfd; + + FD_ZERO(&fdread); + FD_ZERO(&fdwrite); + FD_ZERO(&fdexcep); + + /* set a suitable timeout to play around with */ + timeout.tv_sec = 0; + timeout.tv_usec = 100000; + + /* get file descriptors from the transfers */ + curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd); + + rc = select(maxfd + 1, &fdread, &fdwrite, &fdexcep, &timeout); + + switch (rc) { + case -1: + /* select error */ + + /* ==================================================================== */ + /* On Windows the select function (just above) returns -1 when */ + /* it is called the second time and all the calls after */ + /* that. This causes an infinite loop. */ + /* I do not really know why. */ + /* To solve the problem the break from case -1 has been removed. */ + /* ==================================================================== */ +#ifndef _WIN32 + break; +#endif + case 0: + default: + /* timeout or readable/writable sockets */ + curl_multi_perform(multi_handle, &still_running); + break; + } + } + + if (debug) + msDebug("HTTP: After download loop\n"); + + /* Scan message stack from CURL and report fatal errors*/ + + while ((curl_msg = curl_multi_info_read(multi_handle, &num_msgs)) != NULL) { + httpRequestObj *psReq = NULL; + + if (curl_msg->msg == CURLMSG_DONE && curl_msg->data.result != CURLE_OK) { + /* Something went wrong with this transfer... report error */ + + for (i = 0; i < numRequests; i++) { + if (pasReqInfo[i].curl_handle == curl_msg->easy_handle) { + psReq = &(pasReqInfo[i]); + break; + } + } + + if (psReq != NULL) { + /* Record error code in nStatus as a negative value */ + psReq->nStatus = -curl_msg->data.result; + } + } + } + + if (debug) { + /* Print a msDebug header for timings reported in the loop below */ + msDebug("msHTTPExecuteRequests() timing summary per layer (connect_time + " + "time_to_first_packet + download_time = total_time in seconds)\n"); + } + + /* Check status of all requests, close files, report errors and cleanup + * handles + */ + for (i = 0; i < numRequests; i++) { + httpRequestObj *psReq; + CURL *http_handle; + long lVal = 0; + + psReq = &(pasReqInfo[i]); + + if (psReq->nStatus == 242) + continue; /* Nothing to do here, this file was in cache already */ + + if (psReq->fp) + fclose(psReq->fp); + psReq->fp = NULL; + + http_handle = (CURL *)(psReq->curl_handle); + + if (psReq->nStatus == 0 && + curl_easy_getinfo(http_handle, CURLINFO_HTTP_CODE, &lVal) == CURLE_OK) { + char *pszContentType = NULL; + + psReq->nStatus = lVal; + + /* Fetch content type of response */ + if (curl_easy_getinfo(http_handle, CURLINFO_CONTENT_TYPE, + &pszContentType) == CURLE_OK && + pszContentType != NULL) { + psReq->pszContentType = msStrdup(pszContentType); + } + } + + if (!MS_HTTP_SUCCESS(psReq->nStatus)) { + /* Set status to MS_DONE to indicate that transfers were */ + /* completed but may not be successful */ + nStatus = MS_DONE; + + if (psReq->nStatus == -(CURLE_OPERATION_TIMEOUTED)) { + /* Timeout isn't a fatal error */ + if (psReq->debug) + msDebug("HTTP: TIMEOUT of %d seconds exceeded for %s\n", nTimeout, + psReq->pszGetUrl); + + msSetError(MS_HTTPERR, "HTTP: TIMEOUT of %d seconds exceeded for %s\n", + "msHTTPExecuteRequests()", nTimeout, psReq->pszGetUrl); + + /* Rewrite error message, the curl timeout message isn't + * of much use to our users. + */ + sprintf(psReq->pszErrBuf, "TIMEOUT of %d seconds exceeded.", nTimeout); + } else if (psReq->nStatus > 0) { + /* Got an HTTP Error, e.g. 404, etc. */ + + if (psReq->debug) + msDebug("HTTP: HTTP GET request failed with status %d (%s)" + " for %s\n", + psReq->nStatus, psReq->pszErrBuf, psReq->pszGetUrl); + + msSetError(MS_HTTPERR, + "HTTP GET request failed with status %d (%s) " + "for %s", + "msHTTPExecuteRequests()", psReq->nStatus, psReq->pszErrBuf, + psReq->pszGetUrl); + } else { + /* Got a curl error */ + + errorObj *error = msGetErrorObj(); + if (psReq->debug) + msDebug("HTTP: request failed with curl error " + "code %d (%s) for %s", + -psReq->nStatus, psReq->pszErrBuf, psReq->pszGetUrl); + + if (!error || + error->code == + MS_NOERR) /* only set error if one hasn't already been set */ + msSetError(MS_HTTPERR, + "HTTP: request failed with curl error " + "code %d (%s) for %s", + "msHTTPExecuteRequests()", -psReq->nStatus, + psReq->pszErrBuf, psReq->pszGetUrl); + } + } + + /* Report download times foreach handle, in debug mode */ + if (psReq->debug) { + double dConnectTime = 0.0, dTotalTime = 0.0, dStartTfrTime = 0.0; + + curl_easy_getinfo(http_handle, CURLINFO_CONNECT_TIME, &dConnectTime); + curl_easy_getinfo(http_handle, CURLINFO_STARTTRANSFER_TIME, + &dStartTfrTime); + curl_easy_getinfo(http_handle, CURLINFO_TOTAL_TIME, &dTotalTime); + /* STARTTRANSFER_TIME includes CONNECT_TIME, but TOTAL_TIME + * doesn't, so we need to add it. + */ + dTotalTime += dConnectTime; + + msDebug("Layer %d: %.3f + %.3f + %.3f = %.3fs\n", psReq->nLayerId, + dConnectTime, dStartTfrTime - dConnectTime, + dTotalTime - dStartTfrTime, dTotalTime); + } + + /* Cleanup this handle */ + unchecked_curl_easy_setopt(http_handle, CURLOPT_URL, ""); + curl_multi_remove_handle(multi_handle, http_handle); + curl_easy_cleanup(http_handle); + psReq->curl_handle = NULL; + curl_slist_free_all(psReq->curl_headers); // free the header list + } + + /* Cleanup multi handle, each handle had to be cleaned up individually */ + curl_multi_cleanup(multi_handle); + + return nStatus; +} + +/********************************************************************** + * msHTTPGetFile() + * + * Wrapper to call msHTTPExecuteRequests() for a single file. + **********************************************************************/ +int msHTTPGetFile(const char *pszGetUrl, const char *pszOutputFile, + int *pnHTTPStatus, int nTimeout, int bCheckLocalCache, + int bDebug, int nMaxBytes) { + httpRequestObj *pasReqInfo; + + /* Alloc httpRequestInfo structs through which status of each request + * will be returned. + * We need to alloc 2 instance of requestobj so that the last + * object in the array can be set to NULL. + */ + pasReqInfo = (httpRequestObj *)calloc(2, sizeof(httpRequestObj)); + MS_CHECK_ALLOC(pasReqInfo, 2 * sizeof(httpRequestObj), MS_FAILURE); + + msHTTPInitRequestObj(pasReqInfo, 2); + + pasReqInfo[0].pszGetUrl = msStrdup(pszGetUrl); + pasReqInfo[0].pszOutputFile = msStrdup(pszOutputFile); + pasReqInfo[0].debug = (char)bDebug; + pasReqInfo[0].nTimeout = nTimeout; + pasReqInfo[0].nMaxBytes = nMaxBytes; + + if (msHTTPExecuteRequests(pasReqInfo, 1, bCheckLocalCache) != MS_SUCCESS) { + *pnHTTPStatus = pasReqInfo[0].nStatus; + if (pasReqInfo[0].debug) + msDebug("HTTP request failed for %s.\n", pszGetUrl); + msHTTPFreeRequestObj(pasReqInfo, 2); + free(pasReqInfo); + return MS_FAILURE; + } + + *pnHTTPStatus = pasReqInfo[0].nStatus; + + msHTTPFreeRequestObj(pasReqInfo, 2); + free(pasReqInfo); + + return MS_SUCCESS; +} + +#endif /* defined(USE_WMS_LYR) || defined(USE_WMS_SVR) */ diff --git a/src/maphttp.h b/src/maphttp.h new file mode 100644 index 0000000000..b44b7b5eac --- /dev/null +++ b/src/maphttp.h @@ -0,0 +1,111 @@ +/****************************************************************************** + * $Id$ + * + * Project: MapServer + * Purpose: http requests related functions + * Author: MapServer team. + * + ****************************************************************************** + * Copyright (c) 1996-2005 Regents of the University of Minnesota. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + ****************************************************************************/ + +#ifndef MAPHTTP_H +#define MAPHTTP_H + +#include "mapprimitive.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define MS_HTTP_SUCCESS(status) (status == 200 || status == 242) + +enum MS_HTTP_PROXY_TYPE { MS_HTTP, MS_SOCKS5 }; + +enum MS_HTTP_AUTH_TYPE { MS_BASIC, MS_DIGEST, MS_NTLM, MS_ANY, MS_ANYSAFE }; + +typedef struct http_request_info { + int nLayerId; + char *pszGetUrl; + char *pszOutputFile; + char *pszEPSG; + int nTimeout; + int nMaxBytes; + rectObj bbox; + int width; + int height; + int nStatus; /* 200=success, value < 0 if request failed */ + char *pszContentType; /* Content-Type of the response */ + char *pszErrBuf; /* Buffer where curl can write errors */ + char *pszPostRequest; /* post request content (NULL for GET) */ + char *pszPostContentType; /* post request MIME type */ + char *pszUserAgent; /* User-Agent, auto-generated if not set */ + char *pszHTTPCookieData; /* HTTP Cookie data */ + + char *pszProxyAddress; /* The address (IP or hostname) of proxy svr */ + long nProxyPort; /* The proxy's port */ + enum MS_HTTP_PROXY_TYPE eProxyType; /* The type of proxy */ + enum MS_HTTP_AUTH_TYPE eProxyAuthType; /* Auth method against proxy */ + char *pszProxyUsername; /* Proxy authentication username */ + char *pszProxyPassword; /* Proxy authentication password */ + + enum MS_HTTP_AUTH_TYPE eHttpAuthType; /* HTTP Authentication type */ + char *pszHttpUsername; /* HTTP Authentication username */ + char *pszHttpPassword; /* HTTP Authentication password */ + + /* For debugging/profiling */ + int debug; /* Debug mode? MS_TRUE/MS_FALSE */ + + /* Private members */ + void *curl_headers; /* property to store a curl_slist handle */ + void *curl_handle; /* CURLM * handle */ + FILE *fp; /* FILE * used during download */ + + char *result_data; /* output if pszOutputFile is NULL */ + int result_size; + int result_buf_size; + +} httpRequestObj; + +#ifdef USE_CURL + +int msHTTPInit(void); +void msHTTPCleanup(void); + +void msHTTPInitRequestObj(httpRequestObj *pasReqInfo, int numRequests); +void msHTTPFreeRequestObj(httpRequestObj *pasReqInfo, int numRequests); +int msHTTPExecuteRequests(httpRequestObj *pasReqInfo, int numRequests, + int bCheckLocalCache); +int msHTTPGetFile(const char *pszGetUrl, const char *pszOutputFile, + int *pnHTTPStatus, int nTimeout, int bCheckLocalCache, + int bDebug, int nMaxBytes); + +int msHTTPAuthProxySetup(hashTableObj *mapmd, hashTableObj *lyrmd, + httpRequestObj *pasReqInfo, int numRequests, + mapObj *map, const char *namespaces); +#endif /*USE_CURL*/ + +#ifdef __cplusplus +} +#endif + +#endif /* MAPHTTP_H */ diff --git a/mapiconv.c b/src/mapiconv.c similarity index 88% rename from mapiconv.c rename to src/mapiconv.c index b0d9de7430..96512e4c2c 100644 --- a/mapiconv.c +++ b/src/mapiconv.c @@ -28,9 +28,7 @@ #include "mapiconv.h" -size_t msIconv(iconv_t cd, - char **inbuf, size_t *inbytesleft, - char **outbuf, size_t *outbytesleft) -{ - return iconv(cd, inbuf, inbytesleft, outbuf, outbytesleft); +size_t msIconv(iconv_t cd, char **inbuf, size_t *inbytesleft, char **outbuf, + size_t *outbytesleft) { + return iconv(cd, inbuf, inbytesleft, outbuf, outbytesleft); } diff --git a/mapiconv.h b/src/mapiconv.h similarity index 92% rename from mapiconv.h rename to src/mapiconv.h index cbc25b5dff..4eb752c74e 100644 --- a/mapiconv.h +++ b/src/mapiconv.h @@ -36,9 +36,8 @@ extern "C" { #include /* Wrapper of iconv() to be used from C++ */ -size_t msIconv(iconv_t cd, - char **inbuf, size_t *inbytesleft, - char **outbuf, size_t *outbytesleft); +size_t msIconv(iconv_t cd, char **inbuf, size_t *inbytesleft, char **outbuf, + size_t *outbytesleft); #ifdef __cplusplus } diff --git a/src/mapimageio.c b/src/mapimageio.c new file mode 100644 index 0000000000..bc3c02e6eb --- /dev/null +++ b/src/mapimageio.c @@ -0,0 +1,1163 @@ +/****************************************************************************** + * $Id$ + * + * Project: MapServer + * Purpose: Low level PNG/JPEG/GIF image io native functions + * Author: Thomas Bonfort (tbonfort) + * + ****************************************************************************** + * Copyright (c) 2009 Thomas Bonfort + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + ****************************************************************************/ + +#include "mapserver.h" +#include +#include +#include +#include +#include + +#ifdef USE_GIF +#include +#endif + +typedef struct _streamInfo { + FILE *fp; + bufferObj *buffer; +} streamInfo; + +static void png_write_data_to_stream(png_structp png_ptr, png_bytep data, + png_size_t length) { + FILE *fp = ((streamInfo *)png_get_io_ptr(png_ptr))->fp; + msIO_fwrite(data, length, 1, fp); +} + +static void png_write_data_to_buffer(png_structp png_ptr, png_bytep data, + png_size_t length) { + bufferObj *buffer = ((streamInfo *)png_get_io_ptr(png_ptr))->buffer; + msBufferAppend(buffer, data, length); +} + +static void png_flush_data(png_structp png_ptr) { + (void)png_ptr; + /* do nothing */ +} + +typedef struct { + struct jpeg_destination_mgr pub; + unsigned char *data; +} ms_destination_mgr; + +typedef struct { + ms_destination_mgr mgr; + FILE *stream; +} ms_stream_destination_mgr; + +typedef struct { + ms_destination_mgr mgr; + bufferObj *buffer; +} ms_buffer_destination_mgr; + +#define OUTPUT_BUF_SIZE 4096 + +static void jpeg_init_destination(j_compress_ptr cinfo) { + ms_destination_mgr *dest = (ms_destination_mgr *)cinfo->dest; + + /* Allocate the output buffer --- it will be released when done with image */ + dest->data = (unsigned char *)(*cinfo->mem->alloc_small)( + (j_common_ptr)cinfo, JPOOL_IMAGE, + OUTPUT_BUF_SIZE * sizeof(unsigned char)); + + dest->pub.next_output_byte = dest->data; + dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; +} + +static void jpeg_stream_term_destination(j_compress_ptr cinfo) { + ms_stream_destination_mgr *dest = (ms_stream_destination_mgr *)cinfo->dest; + msIO_fwrite(dest->mgr.data, OUTPUT_BUF_SIZE - dest->mgr.pub.free_in_buffer, 1, + dest->stream); + dest->mgr.pub.next_output_byte = dest->mgr.data; + dest->mgr.pub.free_in_buffer = OUTPUT_BUF_SIZE; +} + +static void jpeg_buffer_term_destination(j_compress_ptr cinfo) { + ms_buffer_destination_mgr *dest = (ms_buffer_destination_mgr *)cinfo->dest; + msBufferAppend(dest->buffer, dest->mgr.data, + OUTPUT_BUF_SIZE - dest->mgr.pub.free_in_buffer); + dest->mgr.pub.next_output_byte = dest->mgr.data; + dest->mgr.pub.free_in_buffer = OUTPUT_BUF_SIZE; +} + +static boolean jpeg_stream_empty_output_buffer(j_compress_ptr cinfo) { + ms_stream_destination_mgr *dest = (ms_stream_destination_mgr *)cinfo->dest; + msIO_fwrite(dest->mgr.data, OUTPUT_BUF_SIZE, 1, dest->stream); + dest->mgr.pub.next_output_byte = dest->mgr.data; + dest->mgr.pub.free_in_buffer = OUTPUT_BUF_SIZE; + return TRUE; +} + +static boolean jpeg_buffer_empty_output_buffer(j_compress_ptr cinfo) { + ms_buffer_destination_mgr *dest = (ms_buffer_destination_mgr *)cinfo->dest; + msBufferAppend(dest->buffer, dest->mgr.data, OUTPUT_BUF_SIZE); + dest->mgr.pub.next_output_byte = dest->mgr.data; + dest->mgr.pub.free_in_buffer = OUTPUT_BUF_SIZE; + return TRUE; +} + +static void msJPEGErrorExit(j_common_ptr cinfo) { + jmp_buf *pJmpBuffer = (jmp_buf *)cinfo->client_data; + char buffer[JMSG_LENGTH_MAX]; + + /* Create the message */ + (*cinfo->err->format_message)(cinfo, buffer); + + msSetError(MS_MISCERR, "libjpeg: %s", "jpeg_ErrorExit()", buffer); + + /* Return control to the setjmp point */ + longjmp(*pJmpBuffer, 1); +} + +int saveAsJPEG(mapObj *map, rasterBufferObj *rb, streamInfo *info, + outputFormatObj *format) { + struct jpeg_compress_struct cinfo; + struct jpeg_error_mgr jerr; + int quality; + const char *pszOptimized; + int optimized; + int arithmetic; + ms_destination_mgr *dest; + JSAMPLE *rowdata = NULL; + unsigned int row; + jmp_buf setjmp_buffer; + + quality = atoi(msGetOutputFormatOption(format, "QUALITY", "75")); + pszOptimized = msGetOutputFormatOption(format, "OPTIMIZED", "YES"); + optimized = EQUAL(pszOptimized, "YES") || EQUAL(pszOptimized, "ON") || + EQUAL(pszOptimized, "TRUE"); + arithmetic = EQUAL(pszOptimized, "ARITHMETIC"); + + if (setjmp(setjmp_buffer)) { + jpeg_destroy_compress(&cinfo); + free(rowdata); + return MS_FAILURE; + } + + cinfo.err = jpeg_std_error(&jerr); + jerr.error_exit = msJPEGErrorExit; + cinfo.client_data = (void *)&(setjmp_buffer); + jpeg_create_compress(&cinfo); + + if (cinfo.dest == NULL) { + if (info->fp) { + cinfo.dest = (struct jpeg_destination_mgr *)(*cinfo.mem->alloc_small)( + (j_common_ptr)&cinfo, JPOOL_PERMANENT, + sizeof(ms_stream_destination_mgr)); + ((ms_stream_destination_mgr *)cinfo.dest)->mgr.pub.empty_output_buffer = + jpeg_stream_empty_output_buffer; + ((ms_stream_destination_mgr *)cinfo.dest)->mgr.pub.term_destination = + jpeg_stream_term_destination; + ((ms_stream_destination_mgr *)cinfo.dest)->stream = info->fp; + } else { + + cinfo.dest = (struct jpeg_destination_mgr *)(*cinfo.mem->alloc_small)( + (j_common_ptr)&cinfo, JPOOL_PERMANENT, + sizeof(ms_buffer_destination_mgr)); + ((ms_buffer_destination_mgr *)cinfo.dest)->mgr.pub.empty_output_buffer = + jpeg_buffer_empty_output_buffer; + ((ms_buffer_destination_mgr *)cinfo.dest)->mgr.pub.term_destination = + jpeg_buffer_term_destination; + ((ms_buffer_destination_mgr *)cinfo.dest)->buffer = info->buffer; + } + } + dest = (ms_destination_mgr *)cinfo.dest; + dest->pub.init_destination = jpeg_init_destination; + + cinfo.image_width = rb->width; + cinfo.image_height = rb->height; + cinfo.input_components = 3; + cinfo.in_color_space = JCS_RGB; + jpeg_set_defaults(&cinfo); + jpeg_set_quality(&cinfo, quality, TRUE); + if (arithmetic) + cinfo.arith_code = TRUE; + else if (optimized) + cinfo.optimize_coding = TRUE; + + if (arithmetic || optimized) { + /* libjpeg turbo 1.5.2 honours max_memory_to_use, but has no backing */ + /* store implementation, so better not set max_memory_to_use ourselves. */ + /* See https://github.com/libjpeg-turbo/libjpeg-turbo/issues/162 */ + if (cinfo.mem->max_memory_to_use > 0) { + if (map == NULL || msGetConfigOption(map, "JPEGMEM") == NULL) { + /* If the user doesn't provide a value for JPEGMEM, we want to be sure + */ + /* that at least the image size will be used before creating the + * temporary file */ + cinfo.mem->max_memory_to_use = + MS_MAX(cinfo.mem->max_memory_to_use, + cinfo.input_components * rb->width * rb->height); + } + } + } + + jpeg_start_compress(&cinfo, TRUE); + rowdata = + (JSAMPLE *)malloc(sizeof(JSAMPLE) * rb->width * cinfo.input_components); + + for (row = 0; row < rb->height; row++) { + JSAMPLE *pixptr = rowdata; + unsigned char *r, *g, *b; + r = rb->data.rgba.r + row * rb->data.rgba.row_step; + g = rb->data.rgba.g + row * rb->data.rgba.row_step; + b = rb->data.rgba.b + row * rb->data.rgba.row_step; + for (unsigned col = 0; col < rb->width; col++) { + *(pixptr++) = *r; + *(pixptr++) = *g; + *(pixptr++) = *b; + r += rb->data.rgba.pixel_step; + g += rb->data.rgba.pixel_step; + b += rb->data.rgba.pixel_step; + } + (void)jpeg_write_scanlines(&cinfo, &rowdata, 1); + } + + /* Step 6: Finish compression */ + + jpeg_finish_compress(&cinfo); + jpeg_destroy_compress(&cinfo); + free(rowdata); + return MS_SUCCESS; +} + +/* + * sort a given list of rgba entries so that all the opaque pixels are at the + * end + */ +int remapPaletteForPNG(rasterBufferObj *rb, rgbPixel *rgb, unsigned char *a, + int *num_a) { + int bot_idx, top_idx; + unsigned x; + int remap[256]; + unsigned int maxval = rb->data.palette.scaling_maxval; + + assert(rb->type == MS_BUFFER_BYTE_PALETTE); + + /* + ** remap the palette colors so that all entries with + ** the maximal alpha value (i.e., fully opaque) are at the end and can + ** therefore be omitted from the tRNS chunk. Note that the ordering of + ** opaque entries is reversed from how they were previously arranged + ** --not that this should matter to anyone. + */ + + for (top_idx = (int)rb->data.palette.num_entries - 1, bot_idx = x = 0; + x < rb->data.palette.num_entries; ++x) { + if (rb->data.palette.palette[x].a == maxval) + remap[x] = top_idx--; + else + remap[x] = bot_idx++; + } + /* sanity check: top and bottom indices should have just crossed paths */ + if (bot_idx != top_idx + 1) { + msSetError(MS_MISCERR, "quantization sanity check failed", + "createPNGPalette()"); + return MS_FAILURE; + } + + *num_a = bot_idx; + + for (x = 0; x < rb->width * rb->height; x++) + rb->data.palette.pixels[x] = remap[rb->data.palette.pixels[x]]; + + for (x = 0; x < rb->data.palette.num_entries; ++x) { + if (maxval == 255) { + a[remap[x]] = rb->data.palette.palette[x].a; + rgb[remap[x]].r = rb->data.palette.palette[x].r; + rgb[remap[x]].g = rb->data.palette.palette[x].g; + rgb[remap[x]].b = rb->data.palette.palette[x].b; + } else { + /* rescale palette */ + rgb[remap[x]].r = + (rb->data.palette.palette[x].r * 255 + (maxval >> 1)) / maxval; + rgb[remap[x]].g = + (rb->data.palette.palette[x].g * 255 + (maxval >> 1)) / maxval; + rgb[remap[x]].b = + (rb->data.palette.palette[x].b * 255 + (maxval >> 1)) / maxval; + a[remap[x]] = + (rb->data.palette.palette[x].a * 255 + (maxval >> 1)) / maxval; + } + if (a[remap[x]] != 255) { + /* un-premultiply pixels */ + double da = 255.0 / a[remap[x]]; + rgb[remap[x]].r *= da; + rgb[remap[x]].g *= da; + rgb[remap[x]].b *= da; + } + } + + return MS_SUCCESS; +} + +int savePalettePNG(rasterBufferObj *rb, streamInfo *info, int compression) { + png_infop info_ptr; + rgbPixel rgb[256]; + unsigned char a[256]; + int num_a; + int sample_depth; + png_structp png_ptr = + png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + + assert(rb->type == MS_BUFFER_BYTE_PALETTE); + + if (!png_ptr) + return (MS_FAILURE); + + png_set_compression_level(png_ptr, compression); + png_set_filter(png_ptr, 0, PNG_FILTER_NONE); + + info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) { + png_destroy_write_struct(&png_ptr, (png_infopp)NULL); + return (MS_FAILURE); + } + + if (setjmp(png_jmpbuf(png_ptr))) { + png_destroy_write_struct(&png_ptr, &info_ptr); + return (MS_FAILURE); + } + if (info->fp) + png_set_write_fn(png_ptr, info, png_write_data_to_stream, png_flush_data); + else + png_set_write_fn(png_ptr, info, png_write_data_to_buffer, png_flush_data); + + if (rb->data.palette.num_entries <= 2) + sample_depth = 1; + else if (rb->data.palette.num_entries <= 4) + sample_depth = 2; + else if (rb->data.palette.num_entries <= 16) + sample_depth = 4; + else + sample_depth = 8; + + png_set_IHDR(png_ptr, info_ptr, rb->width, rb->height, sample_depth, + PNG_COLOR_TYPE_PALETTE, 0, PNG_COMPRESSION_TYPE_DEFAULT, + PNG_FILTER_TYPE_DEFAULT); + + remapPaletteForPNG(rb, rgb, a, &num_a); + + png_set_PLTE(png_ptr, info_ptr, (png_colorp)(rgb), + rb->data.palette.num_entries); + if (num_a) + png_set_tRNS(png_ptr, info_ptr, a, num_a, NULL); + + png_write_info(png_ptr, info_ptr); + png_set_packing(png_ptr); + + for (unsigned row = 0; row < rb->height; row++) { + unsigned char *rowptr = &(rb->data.palette.pixels[row * rb->width]); + png_write_row(png_ptr, rowptr); + } + png_write_end(png_ptr, info_ptr); + png_destroy_write_struct(&png_ptr, &info_ptr); + return MS_SUCCESS; +} + +int readPalette(const char *palette, rgbaPixel *entries, unsigned int *nEntries, + int useAlpha) { + FILE *stream = NULL; + char buffer[MS_BUFFER_LENGTH]; + *nEntries = 0; + + stream = fopen(palette, "r"); + if (!stream) { + msSetError(MS_IOERR, "Error opening palette file %s.", "readPalette()", + palette); + return MS_FAILURE; + } + + while (fgets(buffer, MS_BUFFER_LENGTH, stream) && *nEntries < 256) { + int r, g, b, a = 0; + /* while there are colors to load */ + if (buffer[0] == '#' || buffer[0] == '\n' || buffer[0] == '\r') + continue; /* skip comments and blank lines */ + if (!useAlpha) { + if (3 != sscanf(buffer, "%d,%d,%d\n", &r, &g, &b)) { + fclose(stream); + msSetError(MS_MISCERR, + "failed to parse color %d r,g,b triplet in line \"%s\" from " + "file %s", + "readPalette()", *nEntries + 1, buffer, palette); + return MS_FAILURE; + } + } else { + if (4 != sscanf(buffer, "%d,%d,%d,%d\n", &r, &g, &b, &a)) { + fclose(stream); + msSetError(MS_MISCERR, + "failed to parse color %d r,g,b,a quadruplet in line \"%s\" " + "from file %s", + "readPalette()", *nEntries + 1, buffer, palette); + return MS_FAILURE; + } + } + if (useAlpha && a != 255) { + double da = a / 255.0; + entries[*nEntries].r = r * da; + entries[*nEntries].g = g * da; + entries[*nEntries].b = b * da; + entries[*nEntries].a = a; + } else { + entries[*nEntries].r = r; + entries[*nEntries].g = g; + entries[*nEntries].b = b; + entries[*nEntries].a = 255; + } + (*nEntries)++; + } + fclose(stream); + return MS_SUCCESS; +} + +int saveAsPNG(mapObj *map, rasterBufferObj *rb, streamInfo *info, + outputFormatObj *format) { + int force_pc256 = MS_FALSE; + int force_palette = MS_FALSE; + + const char *force_string, *zlib_compression; + int compression = -1; + + zlib_compression = msGetOutputFormatOption(format, "COMPRESSION", NULL); + if (zlib_compression && *zlib_compression) { + char *endptr; + compression = strtol(zlib_compression, &endptr, 10); + if (*endptr || compression < -1 || compression > 9) { + msSetError(MS_MISCERR, + "failed to parse FORMATOPTION \"COMPRESSION=%s\", expecting " + "integer from 0 to 9.", + "saveAsPNG()", zlib_compression); + return MS_FAILURE; + } + } + + force_string = msGetOutputFormatOption(format, "QUANTIZE_FORCE", NULL); + if (force_string && (strcasecmp(force_string, "on") == 0 || + strcasecmp(force_string, "yes") == 0 || + strcasecmp(force_string, "true") == 0)) + force_pc256 = MS_TRUE; + + force_string = msGetOutputFormatOption(format, "PALETTE_FORCE", NULL); + if (force_string && (strcasecmp(force_string, "on") == 0 || + strcasecmp(force_string, "yes") == 0 || + strcasecmp(force_string, "true") == 0)) + force_palette = MS_TRUE; + + if (force_pc256 || force_palette) { + rasterBufferObj qrb; + rgbaPixel palette[256], paletteGiven[256]; + unsigned int numPaletteGivenEntries; + memset(&qrb, 0, sizeof(rasterBufferObj)); + qrb.type = MS_BUFFER_BYTE_PALETTE; + qrb.width = rb->width; + qrb.height = rb->height; + qrb.data.palette.pixels = + (unsigned char *)malloc(sizeof(unsigned char) * qrb.width * qrb.height); + qrb.data.palette.scaling_maxval = 255; + int ret; + if (force_pc256) { + qrb.data.palette.palette = palette; + qrb.data.palette.num_entries = + atoi(msGetOutputFormatOption(format, "QUANTIZE_COLORS", "256")); + ret = msQuantizeRasterBuffer(rb, &(qrb.data.palette.num_entries), + qrb.data.palette.palette, NULL, 0, + &qrb.data.palette.scaling_maxval); + } else { + unsigned colorsWanted = (unsigned)atoi( + msGetOutputFormatOption(format, "QUANTIZE_COLORS", "0")); + const char *palettePath = + msGetOutputFormatOption(format, "PALETTE", "palette.txt"); + char szPath[MS_MAXPATHLEN]; + if (map) { + msBuildPath(szPath, map->mappath, palettePath); + palettePath = szPath; + } + if (readPalette(palettePath, paletteGiven, &numPaletteGivenEntries, + format->transparent) != MS_SUCCESS) { + msFree(qrb.data.palette.pixels); + return MS_FAILURE; + } + + if (numPaletteGivenEntries == 256 || colorsWanted == 0) { + qrb.data.palette.palette = paletteGiven; + qrb.data.palette.num_entries = numPaletteGivenEntries; + ret = MS_SUCCESS; + + /* we have a full palette and don't want an additional quantization step + */ + } else { + /* quantize the image, and mix our colours in the resulting palette */ + qrb.data.palette.palette = palette; + qrb.data.palette.num_entries = + MS_MAX(colorsWanted, numPaletteGivenEntries); + ret = msQuantizeRasterBuffer(rb, &(qrb.data.palette.num_entries), + qrb.data.palette.palette, paletteGiven, + numPaletteGivenEntries, + &qrb.data.palette.scaling_maxval); + } + } + if (ret != MS_FAILURE) { + msClassifyRasterBuffer(rb, &qrb); + ret = savePalettePNG(&qrb, info, compression); + } + msFree(qrb.data.palette.pixels); + return ret; + } else if (rb->type == MS_BUFFER_BYTE_RGBA) { + png_infop info_ptr; + int color_type; + unsigned int *rowdata; + png_structp png_ptr = + png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + + if (!png_ptr) + return (MS_FAILURE); + + png_set_compression_level(png_ptr, compression); + png_set_filter(png_ptr, 0, PNG_FILTER_NONE); + + info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) { + png_destroy_write_struct(&png_ptr, (png_infopp)NULL); + return (MS_FAILURE); + } + + if (setjmp(png_jmpbuf(png_ptr))) { + png_destroy_write_struct(&png_ptr, &info_ptr); + return (MS_FAILURE); + } + if (info->fp) + png_set_write_fn(png_ptr, info, png_write_data_to_stream, png_flush_data); + else + png_set_write_fn(png_ptr, info, png_write_data_to_buffer, png_flush_data); + + if (rb->data.rgba.a) + color_type = PNG_COLOR_TYPE_RGB_ALPHA; + else + color_type = PNG_COLOR_TYPE_RGB; + + png_set_IHDR(png_ptr, info_ptr, rb->width, rb->height, 8, color_type, + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, + PNG_FILTER_TYPE_DEFAULT); + + png_write_info(png_ptr, info_ptr); + + if (!rb->data.rgba.a && rb->data.rgba.pixel_step == 4) + png_set_filler(png_ptr, 0, PNG_FILLER_AFTER); + + rowdata = (unsigned int *)malloc(rb->width * sizeof(unsigned int)); + for (unsigned row = 0; row < rb->height; row++) { + unsigned int *pixptr = rowdata; + unsigned char *a, *r, *g, *b; + r = rb->data.rgba.r + row * rb->data.rgba.row_step; + g = rb->data.rgba.g + row * rb->data.rgba.row_step; + b = rb->data.rgba.b + row * rb->data.rgba.row_step; + if (rb->data.rgba.a) { + a = rb->data.rgba.a + row * rb->data.rgba.row_step; + for (unsigned col = 0; col < rb->width; col++) { + if (*a) { + double da = *a / 255.0; + unsigned char *pix = (unsigned char *)pixptr; + pix[0] = *r / da; + pix[1] = *g / da; + pix[2] = *b / da; + pix[3] = *a; + } else { + *pixptr = 0; + } + pixptr++; + a += rb->data.rgba.pixel_step; + r += rb->data.rgba.pixel_step; + g += rb->data.rgba.pixel_step; + b += rb->data.rgba.pixel_step; + } + } else { + for (unsigned col = 0; col < rb->width; col++) { + unsigned char *pix = (unsigned char *)pixptr; + pix[0] = *r; + pix[1] = *g; + pix[2] = *b; + pixptr++; + r += rb->data.rgba.pixel_step; + g += rb->data.rgba.pixel_step; + b += rb->data.rgba.pixel_step; + } + } + + png_write_row(png_ptr, (png_bytep)rowdata); + } + png_write_end(png_ptr, info_ptr); + free(rowdata); + png_destroy_write_struct(&png_ptr, &info_ptr); + return MS_SUCCESS; + } else { + msSetError(MS_MISCERR, "Unknown buffer type", "saveAsPNG()"); + return MS_FAILURE; + } +} + +/* For platforms with incomplete ANSI defines. Fortunately, + SEEK_SET is defined to be zero by the standard. */ + +#ifndef SEEK_SET +#define SEEK_SET 0 +#endif /* SEEK_SET */ + +int readPNG(char *path, rasterBufferObj *rb) { + png_uint_32 width, height; + unsigned char *a, *r, *g, *b; + int bit_depth, color_type; + unsigned char **row_pointers; + png_structp png_ptr = NULL; + png_infop info_ptr = NULL; + + FILE *stream = fopen(path, "rb"); + if (!stream) + return MS_FAILURE; + + /* could pass pointers to user-defined error handlers instead of NULLs: */ + png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (!png_ptr) { + fclose(stream); + return MS_FAILURE; /* out of memory */ + } + + info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) { + png_destroy_read_struct(&png_ptr, NULL, NULL); + fclose(stream); + return MS_FAILURE; /* out of memory */ + } + + if (setjmp(png_jmpbuf(png_ptr))) { + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + fclose(stream); + return MS_FAILURE; + } + + png_init_io(png_ptr, stream); + png_read_info(png_ptr, info_ptr); + png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, + NULL, NULL, NULL); + + rb->width = width; + rb->height = height; + rb->type = MS_BUFFER_BYTE_RGBA; + rb->data.rgba.pixels = + (unsigned char *)malloc(sizeof(unsigned char) * width * height * 4); + row_pointers = (unsigned char **)malloc(height * sizeof(unsigned char *)); + rb->data.rgba.pixel_step = 4; + rb->data.rgba.row_step = width * 4; + b = rb->data.rgba.b = &rb->data.rgba.pixels[0]; + g = rb->data.rgba.g = &rb->data.rgba.pixels[1]; + r = rb->data.rgba.r = &rb->data.rgba.pixels[2]; + a = rb->data.rgba.a = &rb->data.rgba.pixels[3]; + + for (unsigned i = 0; i < height; i++) { + row_pointers[i] = &(rb->data.rgba.pixels[i * rb->data.rgba.row_step]); + } + + if (color_type == PNG_COLOR_TYPE_PALETTE) + /* expand palette images to RGB */ + png_set_expand(png_ptr); + if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) + /* expand low bit-depth grayscale to 8bits */ + png_set_expand(png_ptr); + if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) + /* expand transparency chunks to full alpha */ + png_set_expand(png_ptr); + if (bit_depth == 16) + /* scale 16bits down to 8 */ + png_set_strip_16(png_ptr); + if (color_type == PNG_COLOR_TYPE_GRAY || + color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + /* convert grayscale to rgba */ + png_set_gray_to_rgb(png_ptr); + + png_set_bgr(png_ptr); + if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_GRAY || + color_type == PNG_COLOR_TYPE_PALETTE) + png_set_add_alpha(png_ptr, 0xff, PNG_FILLER_AFTER); + + png_read_update_info(png_ptr, info_ptr); + assert(png_get_rowbytes(png_ptr, info_ptr) == rb->data.rgba.row_step); + + png_read_image(png_ptr, row_pointers); + free(row_pointers); + row_pointers = NULL; + png_read_end(png_ptr, NULL); + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + + /*premultiply data*/ + for (unsigned i = 0; i < width * height; i++) { + if (*a < 255) { + if (*a == 0) { + *r = *g = *b = 0; + } else { + *r = (*r * *a + 255) >> 8; + *g = (*g * *a + 255) >> 8; + *b = (*b * *a + 255) >> 8; + } + } + a += 4; + b += 4; + g += 4; + r += 4; + } + + fclose(stream); + return MS_SUCCESS; +} + +int msSaveRasterBuffer(mapObj *map, rasterBufferObj *rb, FILE *stream, + outputFormatObj *format) { + if (strcasestr(format->driver, "/png")) { + streamInfo info; + info.fp = stream; + info.buffer = NULL; + + return saveAsPNG(map, rb, &info, format); + } else if (strcasestr(format->driver, "/jpeg")) { + streamInfo info; + info.fp = stream; + info.buffer = NULL; + + return saveAsJPEG(map, rb, &info, format); + } else { + msSetError(MS_MISCERR, "unsupported image format\n", + "msSaveRasterBuffer()"); + return MS_FAILURE; + } +} + +int msSaveRasterBufferToBuffer(rasterBufferObj *data, bufferObj *buffer, + outputFormatObj *format) { + if (strcasestr(format->driver, "/png")) { + streamInfo info; + info.fp = NULL; + info.buffer = buffer; + return saveAsPNG(NULL, data, &info, format); + } else if (strcasestr(format->driver, "/jpeg")) { + streamInfo info; + info.fp = NULL; + info.buffer = buffer; + return saveAsJPEG(NULL, data, &info, format); + } else { + msSetError(MS_MISCERR, "unsupported image format\n", + "msSaveRasterBuffer()"); + return MS_FAILURE; + } +} + +#ifdef USE_GIF +#if defined GIFLIB_MAJOR && GIFLIB_MAJOR >= 5 +static char const *gif_error_msg(int code) +#else +static char const *gif_error_msg() +#endif +{ + static char msg[80]; + +#if (!defined GIFLIB_MAJOR) || (GIFLIB_MAJOR < 5) + int code = GifLastError(); +#endif + switch (code) { + case E_GIF_ERR_OPEN_FAILED: /* should not see this */ + return "Failed to open given file"; + + case E_GIF_ERR_WRITE_FAILED: + return "Write failed"; + + case E_GIF_ERR_HAS_SCRN_DSCR: /* should not see this */ + return "Screen descriptor already passed to giflib"; + + case E_GIF_ERR_HAS_IMAG_DSCR: /* should not see this */ + return "Image descriptor already passed to giflib"; + + case E_GIF_ERR_NO_COLOR_MAP: /* should not see this */ + return "Neither global nor local color map set"; + + case E_GIF_ERR_DATA_TOO_BIG: /* should not see this */ + return "Too much pixel data passed to giflib"; + + case E_GIF_ERR_NOT_ENOUGH_MEM: + return "Out of memory"; + + case E_GIF_ERR_DISK_IS_FULL: + return "Disk is full"; + + case E_GIF_ERR_CLOSE_FAILED: /* should not see this */ + return "File close failed"; + + case E_GIF_ERR_NOT_WRITEABLE: /* should not see this */ + return "File not writable"; + + case D_GIF_ERR_OPEN_FAILED: + return "Failed to open file"; + + case D_GIF_ERR_READ_FAILED: + return "Failed to read from file"; + + case D_GIF_ERR_NOT_GIF_FILE: + return "File is not a GIF file"; + + case D_GIF_ERR_NO_SCRN_DSCR: + return "No screen descriptor detected - invalid file"; + + case D_GIF_ERR_NO_IMAG_DSCR: + return "No image descriptor detected - invalid file"; + + case D_GIF_ERR_NO_COLOR_MAP: + return "No global or local color map found"; + + case D_GIF_ERR_WRONG_RECORD: + return "Wrong record type detected - invalid file?"; + + case D_GIF_ERR_DATA_TOO_BIG: + return "Data in file too big for image"; + + case D_GIF_ERR_NOT_ENOUGH_MEM: + return "Out of memory"; + + case D_GIF_ERR_CLOSE_FAILED: + return "Close failed"; + + case D_GIF_ERR_NOT_READABLE: + return "File not opened for read"; + + case D_GIF_ERR_IMAGE_DEFECT: + return "Defective image"; + + case D_GIF_ERR_EOF_TOO_SOON: + return "Unexpected EOF - invalid file"; + + default: + sprintf(msg, "Unknown giflib error code %d", code); + return msg; + } +} + +/* not fully implemented and tested */ +/* missing: set the first pointer to a,r,g,b */ +int readGIF(char *path, rasterBufferObj *rb) { + int codeSize, extCode, firstImageRead = MS_FALSE; + unsigned char *r, *g, *b, *a; + int transIdx = -1; + GifFileType *image; + GifPixelType *line; + GifRecordType recordType; + GifByteType *codeBlock, *extension; + ColorMapObject *cmap; + int interlacedOffsets[] = {0, 4, 2, 1}; + int interlacedJumps[] = {8, 8, 4, 2}; +#if defined GIFLIB_MAJOR && GIFLIB_MAJOR >= 5 + int errcode; +#endif + + rb->type = MS_BUFFER_BYTE_RGBA; +#if defined GIFLIB_MAJOR && GIFLIB_MAJOR >= 5 + image = DGifOpenFileName(path, &errcode); + if (image == NULL) { + msSetError(MS_MISCERR, "failed to load gif image: %s", "readGIF()", + gif_error_msg(errcode)); + return MS_FAILURE; + } +#else + image = DGifOpenFileName(path); + if (image == NULL) { + msSetError(MS_MISCERR, "failed to load gif image: %s", "readGIF()", + gif_error_msg()); + return MS_FAILURE; + } +#endif + rb->width = image->SWidth; + rb->height = image->SHeight; + rb->data.rgba.row_step = rb->width * 4; + rb->data.rgba.pixel_step = 4; + rb->data.rgba.pixels = (unsigned char *)malloc(sizeof(unsigned char) * + rb->width * rb->height * 4); + b = rb->data.rgba.b = &rb->data.rgba.pixels[0]; + g = rb->data.rgba.g = &rb->data.rgba.pixels[1]; + r = rb->data.rgba.r = &rb->data.rgba.pixels[2]; + a = rb->data.rgba.a = &rb->data.rgba.pixels[3]; + + cmap = (image->Image.ColorMap) ? image->Image.ColorMap : image->SColorMap; + for (unsigned i = 0; i < rb->width * rb->height; i++) { + *a = 255; + *r = cmap->Colors[image->SBackGroundColor].Red; + *g = cmap->Colors[image->SBackGroundColor].Green; + *b = cmap->Colors[image->SBackGroundColor].Blue; + a += rb->data.rgba.pixel_step; + r += rb->data.rgba.pixel_step; + g += rb->data.rgba.pixel_step; + b += rb->data.rgba.pixel_step; + } + + do { + if (DGifGetRecordType(image, &recordType) == GIF_ERROR) { +#if defined GIFLIB_MAJOR && GIFLIB_MAJOR >= 5 + msSetError(MS_MISCERR, "corrupted gif image?: %s", "readGIF()", + gif_error_msg(image->Error)); +#else + msSetError(MS_MISCERR, "corrupted gif image?: %s", "readGIF()", + gif_error_msg()); +#endif + return MS_FAILURE; + } + + switch (recordType) { + case SCREEN_DESC_RECORD_TYPE: + DGifGetScreenDesc(image); + break; + case IMAGE_DESC_RECORD_TYPE: + if (DGifGetImageDesc(image) == GIF_ERROR) { +#if defined GIFLIB_MAJOR && GIFLIB_MAJOR >= 5 + msSetError(MS_MISCERR, "corrupted gif image?: %s", "readGIF()", + gif_error_msg(image->Error)); +#else + msSetError(MS_MISCERR, "corrupted gif image?: %s", "readGIF()", + gif_error_msg()); +#endif + return MS_FAILURE; + } + if (!firstImageRead) { + + unsigned row = image->Image.Top; + unsigned col = image->Image.Left; + unsigned width = image->Image.Width; + unsigned height = image->Image.Height; + + /* sanity check: */ + if (col + width > rb->width || row + height > rb->height) { + msSetError(MS_MISCERR, + "corrupted gif image, img size exceeds screen size", + "readGIF()"); + return MS_FAILURE; + } + + line = (GifPixelType *)malloc(width * sizeof(GifPixelType)); + if (image->Image.Interlace) { + int count; + for (count = 0; count < 4; count++) { + for (unsigned i = row + interlacedOffsets[count]; i < row + height; + i += interlacedJumps[count]) { + int offset = + i * rb->data.rgba.row_step + col * rb->data.rgba.pixel_step; + a = rb->data.rgba.a + offset; + r = rb->data.rgba.r + offset; + g = rb->data.rgba.g + offset; + b = rb->data.rgba.b + offset; + if (DGifGetLine(image, line, width) == GIF_ERROR) { +#if defined GIFLIB_MAJOR && GIFLIB_MAJOR >= 5 + msSetError(MS_MISCERR, "corrupted gif image?: %s", "readGIF()", + gif_error_msg(image->Error)); +#else + msSetError(MS_MISCERR, "corrupted gif image?: %s", "readGIF()", + gif_error_msg()); +#endif + return MS_FAILURE; + } + + for (unsigned j = 0; j < width; j++) { + GifPixelType pix = line[j]; + if (transIdx == -1 || pix != transIdx) { + *a = 255; + *r = cmap->Colors[pix].Red; + *g = cmap->Colors[pix].Green; + *b = cmap->Colors[pix].Blue; + } else { + *a = *r = *g = *b = 0; + } + a += rb->data.rgba.pixel_step; + r += rb->data.rgba.pixel_step; + g += rb->data.rgba.pixel_step; + b += rb->data.rgba.pixel_step; + } + } + } + } else { + for (unsigned i = 0; i < height; i++) { + int offset = + i * rb->data.rgba.row_step + col * rb->data.rgba.pixel_step; + a = rb->data.rgba.a + offset; + r = rb->data.rgba.r + offset; + g = rb->data.rgba.g + offset; + b = rb->data.rgba.b + offset; + if (DGifGetLine(image, line, width) == GIF_ERROR) { +#if defined GIFLIB_MAJOR && GIFLIB_MAJOR >= 5 + msSetError(MS_MISCERR, "corrupted gif image?: %s", "readGIF()", + gif_error_msg(image->Error)); +#else + msSetError(MS_MISCERR, "corrupted gif image?: %s", "readGIF()", + gif_error_msg()); +#endif + return MS_FAILURE; + } + for (unsigned j = 0; j < width; j++) { + GifPixelType pix = line[j]; + if (transIdx == -1 || pix != transIdx) { + *a = 255; + *r = cmap->Colors[pix].Red; + *g = cmap->Colors[pix].Green; + *b = cmap->Colors[pix].Blue; + } else { + *a = *r = *g = *b = 0; + } + a += rb->data.rgba.pixel_step; + r += rb->data.rgba.pixel_step; + g += rb->data.rgba.pixel_step; + b += rb->data.rgba.pixel_step; + } + } + } + free((char *)line); + firstImageRead = MS_TRUE; + } else { + /* Skip all next images */ + if (DGifGetCode(image, &codeSize, &codeBlock) == GIF_ERROR) { +#if defined GIFLIB_MAJOR && GIFLIB_MAJOR >= 5 + msSetError(MS_MISCERR, "corrupted gif image?: %s", "readGIF()", + gif_error_msg(image->Error)); +#else + msSetError(MS_MISCERR, "corrupted gif image?: %s", "readGIF()", + gif_error_msg()); +#endif + return MS_FAILURE; + } + while (codeBlock != NULL) { + if (DGifGetCodeNext(image, &codeBlock) == GIF_ERROR) { +#if defined GIFLIB_MAJOR && GIFLIB_MAJOR >= 5 + msSetError(MS_MISCERR, "corrupted gif image?: %s", "readGIF()", + gif_error_msg(image->Error)); +#else + msSetError(MS_MISCERR, "corrupted gif image?: %s", "readGIF()", + gif_error_msg()); +#endif + return MS_FAILURE; + } + } + } + break; + case EXTENSION_RECORD_TYPE: + /* skip all extension blocks */ + if (DGifGetExtension(image, &extCode, &extension) == GIF_ERROR) { +#if defined GIFLIB_MAJOR && GIFLIB_MAJOR >= 5 + msSetError(MS_MISCERR, "corrupted gif image?: %s", "readGIF()", + gif_error_msg(image->Error)); +#else + msSetError(MS_MISCERR, "corrupted gif image?: %s", "readGIF()", + gif_error_msg()); +#endif + return MS_FAILURE; + } + if (extCode == 249 && (extension[1] & 1)) + transIdx = extension[4]; + for (;;) { + if (DGifGetExtensionNext(image, &extension) == GIF_ERROR) { +#if defined GIFLIB_MAJOR && GIFLIB_MAJOR >= 5 + msSetError(MS_MISCERR, "corrupted gif image?: %s", "readGIF()", + gif_error_msg(image->Error)); +#else + msSetError(MS_MISCERR, "corrupted gif image?: %s", "readGIF()", + gif_error_msg()); +#endif + return MS_FAILURE; + } + if (extension == NULL) + break; + if (extension[1] & 1) + transIdx = extension[4]; + } + break; + case UNDEFINED_RECORD_TYPE: + break; + case TERMINATE_RECORD_TYPE: + break; + default: + break; + } + + } while (recordType != TERMINATE_RECORD_TYPE); + +#if defined GIFLIB_MAJOR && GIFLIB_MINOR && \ + ((GIFLIB_MAJOR == 5 && GIFLIB_MINOR >= 1) || (GIFLIB_MAJOR > 5)) + if (DGifCloseFile(image, &errcode) == GIF_ERROR) { + msSetError(MS_MISCERR, "failed to close gif after loading: %s", "readGIF()", + gif_error_msg(errcode)); + return MS_FAILURE; + } +#else + if (DGifCloseFile(image) == GIF_ERROR) { +#if defined GIFLIB_MAJOR && GIFLIB_MAJOR >= 5 + msSetError(MS_MISCERR, "failed to close gif after loading: %s", "readGIF()", + gif_error_msg(image->Error)); +#else + msSetError(MS_MISCERR, "failed to close gif after loading: %s", "readGIF()", + gif_error_msg()); +#endif + return MS_FAILURE; + } +#endif + + return MS_SUCCESS; +} +#endif + +int msLoadMSRasterBufferFromFile(char *path, rasterBufferObj *rb) { + FILE *stream; + unsigned char signature[8]; + int ret = MS_FAILURE; + stream = fopen(path, "rb"); + if (!stream) { + msSetError(MS_MISCERR, "unable to open file %s for reading", + "msLoadMSRasterBufferFromFile()", path); + return MS_FAILURE; + } + if (1 != fread(signature, 8, 1, stream)) { + fclose(stream); + msSetError(MS_MISCERR, "Unable to read header from image file %s", + "msLoadMSRasterBufferFromFile()", path); + return MS_FAILURE; + } + fclose(stream); + if (png_sig_cmp(signature, 0, 8) == 0) { + ret = readPNG(path, rb); + } else if (!strncmp((char *)signature, "GIF", 3)) { +#ifdef USE_GIF + ret = readGIF(path, rb); +#else + msSetError(MS_MISCERR, + "pixmap %s seems to be GIF formatted, but this server is " + "compiled without GIF support", + "readImage()", path); + return MS_FAILURE; +#endif + } else { + msSetError(MS_MISCERR, "unsupported pixmap format", "readImage()"); + return MS_FAILURE; + } + return ret; +} diff --git a/src/mapimagemap.c b/src/mapimagemap.c new file mode 100644 index 0000000000..1b4c37088a --- /dev/null +++ b/src/mapimagemap.c @@ -0,0 +1,745 @@ +/****************************************************************************** + * $Id$ + * + * Project: MapServer + * Purpose: Implements imagemap outputformat support. + * Author: Attila Csipa + * + ****************************************************************************** + * Copyright (c) 1996-2005 Regents of the University of Minnesota. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + ****************************************************************************/ + +#include "mapserver.h" +#include "dxfcolor.h" + +#include +#include + +#ifdef _WIN32 +#include +#include +#endif + +#define MYDEBUG 0 +#define DEBUG_IF if (MYDEBUG > 2) + +/* + * Client-side imagemap support was originally written by + * Attila Csipa (http://prometheus.org.yu/me.php). C. Scott Ananian + * (http://cscott.net) cleaned up the code somewhat and made it more flexible: + * you can now customize the generated HREFs and create mouseover and + * mouseout attributes. + * + * Use + * IMAGETYPE imagemap + * to select this driver. + * + * The following FORMATOPTIONs are available. If any are set to the empty + * string the associated attribute will be suppressed. + * POLYHREF the href string to use for the elements. + * use a %s to interpolate the area title. + * default: "javascript:Clicked('%s');" + * POLYMOUSEOVER the onMouseOver string to use for the elements. + * use a %s to interpolate the area title. + * default: "" (ie the attribute is suppressed) + * POLYMOUSEOUT the onMouseOut string to use for the elements. + * use a %s to interpolate the area title. + * default: "" (ie the attribute is suppressed) + * SYMBOLMOUSEOVER and SYMBOLMOUSEOUT are equivalent properties for + * tags representing symbols, with the same defaults. + * MAPNAME the string which will be used in the name attribute + * of the tag. There is no %s interpolation. + * default: "map1" + * SUPPRESS if "yes", then we will suppress area declarations with + * no title. + * default: "NO" + * + * For example, http://vevo.verifiedvoting.org/verifier contains this + * .map file fragment: + * OUTPUTFORMAT + * NAME imagemap + * DRIVER imagemap + * FORMATOPTION "POLYHREF=/verifier/map.php?state=%s" + * FORMATOPTION "SYMBOLHREF=#" + * FORMATOPTION "SUPPRESS=YES" + * FORMATOPTION "MAPNAME=map-48" + * FORMATOPTION "POLYMOUSEOUT=return nd();" + * FORMATOPTION "POLYMOUSEOVER=return overlib('%s');" + * END + */ + +/*-------------------------------------------------------------------------*/ + +/* A pString is a variable-length (appendable) string, stored as a triple: + * character pointer, allocated length, and used length. The one wrinkle + * is that we use pointers to the allocated size and character pointer, + * in order to support referring to fields declared elsewhere (ie in the + * 'image' data structure) for these. The 'iprintf' function appends + * to a pString. */ +typedef struct pString { + /* these two fields are somewhere else */ + char **string; + int *alloc_size; + /* this field is stored locally. */ + int string_len; +} pString; +/* These are the pStrings we declare statically. One is the 'output' + * imagemap/dxf file; parts of this live in another data structure and + * are only referenced indirectly here. The other contains layer-specific + * information for the dxf output. */ +static char *layerlist = NULL; +static int layersize = 0; +static pString imgStr, layerStr = {&layerlist, &layersize, 0}; + +/* Format strings for the various bits of a client-side imagemap. */ +static const char *polyHrefFmt, *polyMOverFmt, *polyMOutFmt; +static const char *symbolHrefFmt, *symbolMOverFmt, *symbolMOutFmt; +static const char *mapName; +/* Should we suppress AREA declarations in imagemaps with no title? */ +static int suppressEmpty = 0; + +/* Prevent buffer-overrun and format-string attacks by "sanitizing" any + * provided format string to fit the number of expected string arguments + * (MAX) exactly. */ +static const char *makeFmtSafe(const char *fmt, int MAX) { + /* format string should have exactly 'MAX' %s */ + + char *result = msSmallMalloc(strlen(fmt) + 1 + 3 * MAX), *cp; + int numstr = 0, saw_percent = 0; + + strcpy(result, fmt); + for (cp = result; *cp; cp++) { + if (saw_percent) { + if (*cp == '%') { + /* safe */ + } else if (*cp == 's' && numstr < MAX) { + numstr++; /* still safe */ + } else { + /* disable this unsafe format string! */ + *(cp - 1) = ' '; + } + saw_percent = 0; + } else if (*cp == '%') + saw_percent = 1; + } + /* fixup format strings without enough %s in them */ + while (numstr < MAX) { + strcpy(cp, "%.s"); /* print using zero-length precision */ + cp += 3; + numstr++; + } + return result; +} + +/* Append the given printf-style formatted string to the pString 'ps'. + * This is much cleaner (and faster) than the technique this file + * used to use! */ +static void im_iprintf(pString *ps, const char *fmt, ...) { + int n, remaining; + va_list ap; + do { + remaining = *(ps->alloc_size) - ps->string_len; + va_start(ap, fmt); +#if defined(HAVE_VSNPRINTF) + n = vsnprintf((*(ps->string)) + ps->string_len, remaining, fmt, ap); +#else + /* If vsnprintf() is not available then require a minimum + * of 512 bytes of free space to prevent a buffer overflow + * This is not fully bulletproof but should help, see bug 1613 + */ + if (remaining < 512) + n = -1; + else + n = vsprintf((*(ps->string)) + ps->string_len, fmt, ap); +#endif + va_end(ap); + /* if that worked, we're done! */ + if (-1 < n && n < remaining) { + ps->string_len += n; + return; + } else { /* double allocated string size */ + *(ps->alloc_size) *= 2; /* these keeps realloc linear.*/ + if (*(ps->alloc_size) < 1024) + /* careful: initial size can be 0 */ + *(ps->alloc_size) = 1024; + if (n > -1 && *(ps->alloc_size) <= (n + ps->string_len)) + /* ensure at least as much as what is needed */ + *(ps->alloc_size) = n + ps->string_len + 1; + *(ps->string) = (char *)msSmallRealloc(*(ps->string), *(ps->alloc_size)); + /* if realloc doesn't work, we're screwed! */ + } + } while (1); /* go back and try again. */ +} + +static int lastcolor = -1; +static int matchdxfcolor(colorObj col) { + int best = 7; + int delta = 128 * 255; + int tcolor = 0; + if (lastcolor != -1) + return lastcolor; + while (tcolor < 256 && + (ctable[tcolor].r != col.red || ctable[tcolor].g != col.green || + ctable[tcolor].b != col.blue)) { + const int dr = ctable[tcolor].r - col.red; + const int dg = ctable[tcolor].g - col.green; + const int db = ctable[tcolor].b - col.blue; + const int newdelta = dr * dr + dg * dg + db * db; + if (newdelta < delta) { + best = tcolor; + delta = newdelta; + } + tcolor++; + } + if (tcolor >= 256) + tcolor = best; + /* DEBUG_IF printf("%d/%d/%d (%d/%d - %d), %d : %d/%d/%d
\n", + * ctable[tcolor].r, ctable[tcolor].g, ctable[tcolor].b, tcolor, best, delta, + * lastcolor, col.red, col.green, col.blue); */ + lastcolor = tcolor; + return tcolor; +} + +static char *lname; +static int dxf; + +void msImageStartLayerIM(mapObj *map, layerObj *layer, imageObj *image) { + (void)map; + (void)image; + DEBUG_IF printf("ImageStartLayerIM\n
"); + free(lname); + if (layer->name) + lname = msStrdup(layer->name); + else + lname = msStrdup("NONE"); + if (dxf == 2) { + im_iprintf(&layerStr, "LAYER\n%s\n", lname); + } else if (dxf) { + im_iprintf(&layerStr, + " 0\nLAYER\n 2\n%s\n" + " 70\n 64\n 6\nCONTINUOUS\n", + lname); + } + lastcolor = -1; +} + +/* + * Utility function to create a IM image. Returns + * a pointer to an imageObj structure. + */ +imageObj *msImageCreateIM(int width, int height, outputFormatObj *format, + char *imagepath, char *imageurl, double resolution, + double defresolution) { + imageObj *image = NULL; + if (setvbuf(stdout, NULL, _IONBF, 0)) { + printf("Whoops..."); + }; + DEBUG_IF printf("msImageCreateIM
\n"); + if (width > 0 && height > 0) { + image = (imageObj *)msSmallCalloc(1, sizeof(imageObj)); + imgStr.string = &(image->img.imagemap); + imgStr.alloc_size = &(image->size); + + image->format = format; + format->refcount++; + + image->width = width; + image->height = height; + image->imagepath = NULL; + image->imageurl = NULL; + image->resolution = resolution; + image->resolutionfactor = resolution / defresolution; + + if (strcasecmp("ON", msGetOutputFormatOption(format, "DXF", "OFF")) == 0) { + dxf = 1; + im_iprintf(&layerStr, " 2\nLAYER\n 70\n 10\n"); + } else + dxf = 0; + + if (strcasecmp("ON", msGetOutputFormatOption(format, "SCRIPT", "OFF")) == + 0) { + dxf = 2; + im_iprintf(&layerStr, ""); + } + + /* get href formation string options */ + polyHrefFmt = + makeFmtSafe(msGetOutputFormatOption(format, "POLYHREF", + "javascript:Clicked('%s');"), + 1); + polyMOverFmt = + makeFmtSafe(msGetOutputFormatOption(format, "POLYMOUSEOVER", ""), 1); + polyMOutFmt = + makeFmtSafe(msGetOutputFormatOption(format, "POLYMOUSEOUT", ""), 1); + symbolHrefFmt = + makeFmtSafe(msGetOutputFormatOption(format, "SYMBOLHREF", + "javascript:SymbolClicked();"), + 1); + symbolMOverFmt = + makeFmtSafe(msGetOutputFormatOption(format, "SYMBOLMOUSEOVER", ""), 1); + symbolMOutFmt = + makeFmtSafe(msGetOutputFormatOption(format, "SYMBOLMOUSEOUT", ""), 1); + /* get name of client-side image map */ + mapName = msGetOutputFormatOption(format, "MAPNAME", "map1"); + /* should we suppress area declarations with no title? */ + if (strcasecmp("YES", msGetOutputFormatOption(format, "SUPPRESS", "NO")) == + 0) { + suppressEmpty = 1; + } + + lname = msStrdup("NONE"); + *(imgStr.string) = msStrdup(""); + if (*(imgStr.string)) { + *(imgStr.alloc_size) = imgStr.string_len = strlen(*(imgStr.string)); + } else { + *(imgStr.alloc_size) = imgStr.string_len = 0; + } + if (imagepath) { + image->imagepath = msStrdup(imagepath); + } + if (imageurl) { + image->imageurl = msStrdup(imageurl); + } + + return image; + } else { + msSetError(MS_IMGERR, "Cannot create IM image of size %d x %d.", + "msImageCreateIM()", width, height); + } + return image; +} + +/* ------------------------------------------------------------------------- */ +/* Draw a single marker symbol of the specified size and color */ +/* ------------------------------------------------------------------------- */ +void msDrawMarkerSymbolIM(mapObj *map, imageObj *img, pointObj *p, + styleObj *style, double scalefactor) { + symbolObj *symbol; + int ox, oy; + double size; + + DEBUG_IF printf("msDrawMarkerSymbolIM\n
"); + + /* skip this, we don't do text */ + + if (!p) + return; + + if (style->symbol > map->symbolset.numsymbols || style->symbol < 0) + return; /* no such symbol, 0 is OK */ + symbol = map->symbolset.symbol[style->symbol]; + ox = style->offsetx * scalefactor; + oy = style->offsety * scalefactor; + if (style->size == -1) { + size = msSymbolGetDefaultSize(symbol); + size = MS_NINT(size * scalefactor); + } else + size = MS_NINT(style->size * scalefactor); + size = MS_MAX(size, style->minsize * img->resolutionfactor); + size = MS_MIN(size, style->maxsize * img->resolutionfactor); + + if (size < 1) + return; /* size too small */ + + /* DEBUG_IF printf(".%d.%d.%d.", symbol->type, style->symbol, fc); */ + if (style->symbol == + 0) { /* simply draw a single pixel of the specified color */ + + if (dxf) { + if (dxf == 2) + im_iprintf(&imgStr, "POINT\n%.0f %.0f\n%d\n", p->x + ox, p->y + oy, + matchdxfcolor(style->color)); + else + im_iprintf(&imgStr, + " 0\nPOINT\n 10\n%f\n 20\n%f\n 30\n0.0\n" + " 62\n%6d\n 8\n%s\n", + p->x + ox, p->y + oy, matchdxfcolor(style->color), lname); + } else { + im_iprintf(&imgStr, "\n", + p->x + ox, p->y + oy); + } + + /* point2 = &( p->line[j].point[i] ); */ + /* if(point1->y == point2->y) {} */ + return; + } + DEBUG_IF printf("A"); + switch (symbol->type) { + case (MS_SYMBOL_TRUETYPE): + DEBUG_IF printf("T"); + break; + case (MS_SYMBOL_PIXMAP): + DEBUG_IF printf("P"); + break; + case (MS_SYMBOL_VECTOR): + DEBUG_IF printf("V"); + { + double d, offset_x, offset_y; + + d = size / symbol->sizey; + offset_x = MS_NINT(p->x - d * .5 * symbol->sizex + ox); + offset_y = MS_NINT(p->y - d * .5 * symbol->sizey + oy); + + /* For now I only render filled vector symbols in imagemap, and no */ + /* dxf support available yet. */ + if (symbol->filled && !dxf /* && fc >= 0 */) { + /* char *title=(p->numvalues) ? p->values[0] : ""; */ + char *title = ""; + int j; + + im_iprintf(&imgStr, "numpoints; j++) { + im_iprintf(&imgStr, "%s %d,%d", j == 0 ? "" : ",", + (int)MS_NINT(d * symbol->points[j].x + offset_x), + (int)MS_NINT(d * symbol->points[j].y + offset_y)); + } + im_iprintf(&imgStr, "\" />\n"); + } /* end of imagemap, filled case. */ + } + break; + + default: + DEBUG_IF printf("DEF"); + break; + } /* end switch statement */ + + return; +} + +/* ------------------------------------------------------------------------- */ +/* Draw a line symbol of the specified size and color */ +/* ------------------------------------------------------------------------- */ +void msDrawLineSymbolIM(mapObj *map, imageObj *img, shapeObj *p, + styleObj *style, double scalefactor_ignored) { + (void)img; + (void)scalefactor_ignored; + symbolObj *symbol; + int i, j, l; + char first = 1; + DEBUG_IF printf("msDrawLineSymbolIM
\n"); + + if (!p) + return; + if (p->numlines <= 0) + return; + + if (style->symbol > map->symbolset.numsymbols || style->symbol < 0) + return; /* no such symbol, 0 is OK */ + symbol = map->symbolset.symbol[style->symbol]; + + if (suppressEmpty && p->numvalues == 0) + return; /* suppress area with empty title */ + if (style->symbol == 0) { /* just draw a single width line */ + for (l = 0, j = 0; j < p->numlines; j++) { + if (dxf == 2) { + im_iprintf(&imgStr, "LINE\n%d\n", matchdxfcolor(style->color)); + } else if (dxf) { + im_iprintf(&imgStr, " 0\nPOLYLINE\n 70\n 0\n 62\n%6d\n 8\n%s\n", + matchdxfcolor(style->color), lname); + } else { + char *title; + + first = 1; + title = (p->numvalues) ? p->values[0] : ""; + im_iprintf(&imgStr, "line[j].point[p->line[j].numpoints-1] ); */ + for (i = 0; i < p->line[j].numpoints; i++, l++) { + if (dxf == 2) { + im_iprintf(&imgStr, "%.0f %.0f\n", p->line[j].point[i].x, + p->line[j].point[i].y); + } else if (dxf) { + im_iprintf(&imgStr, " 0\nVERTEX\n 10\n%f\n 20\n%f\n 30\n%f\n", + p->line[j].point[i].x, p->line[j].point[i].y, 0.0); + } else { + im_iprintf(&imgStr, "%s %.0f,%.0f", first ? "" : ",", + p->line[j].point[i].x, p->line[j].point[i].y); + } + first = 0; + + /* point2 = &( p->line[j].point[i] ); */ + /* if(point1->y == point2->y) {} */ + } + im_iprintf(&imgStr, dxf ? (dxf == 2 ? "" : " 0\nSEQEND\n") : "\" />\n"); + } + + /* DEBUG_IF printf ("%d, ",strlen(img->img.imagemap) ); */ + return; + } + + DEBUG_IF printf("-%d-", symbol->type); + + return; +} + +/* ------------------------------------------------------------------------- */ +/* Draw a shade symbol of the specified size and color */ +/* ------------------------------------------------------------------------- */ +void msDrawShadeSymbolIM(mapObj *map, imageObj *img, shapeObj *p, + styleObj *style, double scalefactor_ignored) { + (void)img; + (void)scalefactor_ignored; + symbolObj *symbol; + int i, j, l; + char first = 1; + + DEBUG_IF printf("msDrawShadeSymbolIM\n
"); + if (!p) + return; + if (p->numlines <= 0) + return; + + symbol = map->symbolset.symbol[style->symbol]; + + if (suppressEmpty && p->numvalues == 0) + return; /* suppress area with empty title */ + if (style->symbol == + 0) { /* simply draw a single pixel of the specified color // */ + for (l = 0, j = 0; j < p->numlines; j++) { + if (dxf == 2) { + im_iprintf(&imgStr, "POLY\n%d\n", matchdxfcolor(style->color)); + } else if (dxf) { + im_iprintf(&imgStr, " 0\nPOLYLINE\n 73\n 1\n 62\n%6d\n 8\n%s\n", + matchdxfcolor(style->color), lname); + } else { + char *title = (p->numvalues) ? p->values[0] : ""; + first = 1; + im_iprintf(&imgStr, "line[j].point[p->line[j].numpoints-1] ); */ + for (i = 0; i < p->line[j].numpoints; i++, l++) { + if (dxf == 2) { + im_iprintf(&imgStr, "%.0f %.0f\n", p->line[j].point[i].x, + p->line[j].point[i].y); + } else if (dxf) { + im_iprintf(&imgStr, " 0\nVERTEX\n 10\n%f\n 20\n%f\n 30\n%f\n", + p->line[j].point[i].x, p->line[j].point[i].y, 0.0); + } else { + im_iprintf(&imgStr, "%s %.0f,%.0f", first ? "" : ",", + p->line[j].point[i].x, p->line[j].point[i].y); + } + first = 0; + + /* point2 = &( p->line[j].point[i] ); */ + /* if(point1->y == point2->y) {} */ + } + im_iprintf(&imgStr, dxf ? (dxf == 2 ? "" : " 0\nSEQEND\n") : "\" />\n"); + } + + return; + } + /* DEBUG_IF printf ("d"); */ + DEBUG_IF printf("-%d-", symbol->type); + return; +} + +/* + * Simply draws a label based on the label point and the supplied label object. + */ +int msDrawTextIM(mapObj *map, imageObj *img, pointObj labelPnt, char *string, + labelObj *label, double scalefactor) { + (void)map; + (void)img; + DEBUG_IF printf("msDrawText
\n"); + if (!string) + return (0); /* not errors, just don't want to do anything */ + if (strlen(string) == 0) + return (0); + if (!dxf) + return (0); + + if (dxf == 2) { + im_iprintf(&imgStr, "TEXT\n%d\n%s\n%.0f\n%.0f\n%.0f\n", + matchdxfcolor(label->color), string, labelPnt.x, labelPnt.y, + -label->angle); + } else { + im_iprintf(&imgStr, + " 0\nTEXT\n 1\n%s\n 10\n%f\n 20\n%f\n 30\n0.0\n 40\n%f\n " + "50\n%f\n 62\n%6d\n 8\n%s\n 73\n 2\n 72\n 1\n", + string, labelPnt.x, labelPnt.y, label->size * scalefactor * 100, + -label->angle, matchdxfcolor(label->color), lname); + } + return (0); +} + +/* + * Save an image to a file named filename, if filename is NULL it goes to stdout + */ + +int msSaveImageIM(imageObj *img, const char *filename, outputFormatObj *format) + +{ + FILE *stream_to_free = NULL; + FILE *stream; + char workbuffer[5000]; + + DEBUG_IF printf("msSaveImageIM\n
"); + + if (filename != NULL && strlen(filename) > 0) { + stream_to_free = fopen(filename, "wb"); + if (!stream_to_free) { + msSetError(MS_IOERR, "(%s)", "msSaveImage()", filename); + return (MS_FAILURE); + } + stream = stream_to_free; + } else { /* use stdout */ + +#ifdef _WIN32 + /* + * Change stdout mode to binary on win32 platforms + */ + if (_setmode(_fileno(stdout), _O_BINARY) == -1) { + msSetError(MS_IOERR, "Unable to change stdout to binary mode.", + "msSaveImage()"); + return (MS_FAILURE); + } +#endif + stream = stdout; + } + + if (strcasecmp(format->driver, "imagemap") == 0) { + DEBUG_IF printf("ALLOCD %d
\n", img->size); + /* DEBUG_IF printf("F %s
\n", img->img.imagemap); */ + DEBUG_IF printf("FLEN %d
\n", (int)strlen(img->img.imagemap)); + if (dxf == 2) { + msIO_fprintf(stream, "%s", layerlist); + } else if (dxf) { + msIO_fprintf( + stream, + " 0\nSECTION\n 2\nHEADER\n 9\n$ACADVER\n 1\nAC1009\n0\nENDSEC\n " + "0\nSECTION\n 2\nTABLES\n 0\nTABLE\n%s0\nENDTAB\n0\nENDSEC\n " + "0\nSECTION\n 2\nBLOCKS\n0\nENDSEC\n 0\nSECTION\n 2\nENTITIES\n", + layerlist); + } else { + msIO_fprintf(stream, "\n", + mapName, img->width, img->height); + } + const int nSize = sizeof(workbuffer); + + const int size = strlen(img->img.imagemap); + if (size > nSize) { + int iIndice = 0; + while ((iIndice + nSize) <= size) { + snprintf(workbuffer, sizeof(workbuffer), "%s", + img->img.imagemap + iIndice); + workbuffer[nSize - 1] = '\0'; + msIO_fwrite(workbuffer, strlen(workbuffer), 1, stream); + iIndice += nSize - 1; + } + if (iIndice < size) { + sprintf(workbuffer, "%s", img->img.imagemap + iIndice); + msIO_fprintf(stream, "%s", workbuffer); + } + } else + msIO_fwrite(img->img.imagemap, size, 1, stream); + if (strcasecmp("OFF", + msGetOutputFormatOption(format, "SKIPENDTAG", "OFF")) == 0) { + if (dxf == 2) + msIO_fprintf(stream, "END"); + else if (dxf) + msIO_fprintf(stream, "0\nENDSEC\n0\nEOF\n"); + else + msIO_fprintf(stream, ""); + } + } else { + msSetError(MS_MISCERR, "Unknown output image type driver: %s.", + "msSaveImage()", format->driver); + if (stream_to_free != NULL) + fclose(stream_to_free); + return (MS_FAILURE); + } + + if (stream_to_free != NULL) + fclose(stream_to_free); + return (MS_SUCCESS); +} + +/* + * Free gdImagePtr + */ +void msFreeImageIM(imageObj *img) { free(img->img.imagemap); } diff --git a/src/mapio.c b/src/mapio.c new file mode 100644 index 0000000000..705992f3e7 --- /dev/null +++ b/src/mapio.c @@ -0,0 +1,1066 @@ +/****************************************************************************** + * $Id$ + * + * Project: MapServer + * Purpose: Implementations for MapServer IO redirection capability. + * Author: Frank Warmerdam, warmerdam@pobox.com + * + ****************************************************************************** + * Copyright (c) 2004, Frank Warmerdam + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + ****************************************************************************/ + +#include + +#include "mapserver.h" +#include "mapthread.h" + +#ifdef _WIN32 +#include +#include +#endif + +#ifdef MOD_WMS_ENABLED +#include "httpd.h" +#include "apr_strings.h" +#endif + +static int is_msIO_initialized = MS_FALSE; +static int is_msIO_header_enabled = MS_TRUE; + +typedef struct msIOContextGroup_t { + msIOContext stdin_context; + msIOContext stdout_context; + msIOContext stderr_context; + + void *thread_id; + struct msIOContextGroup_t *next; +} msIOContextGroup; + +static msIOContextGroup default_contexts; +static msIOContextGroup *io_context_list = NULL; +static void msIO_Initialize(void); + +#ifdef msIO_printf +#undef msIO_printf +#undef msIO_fprintf +#undef msIO_fwrite +#undef msIO_fread +#undef msIO_vfprintf +#endif + +/************************************************************************/ +/* msIO_Cleanup() */ +/************************************************************************/ + +void msIO_Cleanup() + +{ + if (is_msIO_initialized) + + { + is_msIO_initialized = MS_FALSE; + while (io_context_list != NULL) { + msIOContextGroup *last = io_context_list; + io_context_list = io_context_list->next; + free(last); + } + } +} + +/************************************************************************/ +/* msIO_GetContextGroup() */ +/************************************************************************/ + +static msIOContextGroup *msIO_GetContextGroup() + +{ + void *nThreadId = msGetThreadId(); + msIOContextGroup *prev = NULL, *group = io_context_list; + + if (group != NULL && group->thread_id == nThreadId) + return group; + + /* -------------------------------------------------------------------- */ + /* Search for group for this thread */ + /* -------------------------------------------------------------------- */ + msAcquireLock(TLOCK_IOCONTEXT); + msIO_Initialize(); + + group = io_context_list; + while (group != NULL && group->thread_id != nThreadId) { + prev = group; + group = group->next; + } + + /* -------------------------------------------------------------------- */ + /* If we found it, make sure it is pushed to the front of the */ + /* link for faster finding next time, and return it. */ + /* -------------------------------------------------------------------- */ + if (group != NULL) { + if (prev != NULL) { + prev->next = group->next; + group->next = io_context_list; + io_context_list = group; + } + + msReleaseLock(TLOCK_IOCONTEXT); + return group; + } + + /* -------------------------------------------------------------------- */ + /* Create a new context group for this thread. */ + /* -------------------------------------------------------------------- */ + group = (msIOContextGroup *)calloc(1, sizeof(msIOContextGroup)); + + group->stdin_context = default_contexts.stdin_context; + group->stdout_context = default_contexts.stdout_context; + group->stderr_context = default_contexts.stderr_context; + group->thread_id = nThreadId; + + group->next = io_context_list; + io_context_list = group; + + msReleaseLock(TLOCK_IOCONTEXT); + + return group; +} + +/* returns MS_TRUE if the msIO standard output hasn't been redirected */ +int msIO_isStdContext() { + msIOContextGroup *group = io_context_list; + void *nThreadId = msGetThreadId(); + if (!group || group->thread_id != nThreadId) { + group = msIO_GetContextGroup(); + if (!group) { + return MS_FALSE; /* probably a bug */ + } + } + if (group->stderr_context.cbData == (void *)stderr && + group->stdin_context.cbData == (void *)stdin && + group->stdout_context.cbData == (void *)stdout) + return MS_TRUE; + return MS_FALSE; +} + +/************************************************************************/ +/* msIO_getHandler() */ +/************************************************************************/ + +msIOContext *msIO_getHandler(FILE *fp) + +{ + void *nThreadId = msGetThreadId(); + msIOContextGroup *group = io_context_list; + + msIO_Initialize(); + + if (group == NULL || group->thread_id != nThreadId) { + group = msIO_GetContextGroup(); + if (group == NULL) + return NULL; + } + + if (fp == stdin || fp == NULL || strcmp((const char *)fp, "stdin") == 0) + return &(group->stdin_context); + else if (fp == stdout || strcmp((const char *)fp, "stdout") == 0) + return &(group->stdout_context); + else if (fp == stderr || strcmp((const char *)fp, "stderr") == 0) + return &(group->stderr_context); + else + return NULL; +} + +/************************************************************************/ +/* msIO_setHeaderEnabled() */ +/************************************************************************/ + +void msIO_setHeaderEnabled(int bFlag) { is_msIO_header_enabled = bFlag; } + +/************************************************************************/ +/* msIO_setHeader() */ +/************************************************************************/ + +void msIO_setHeader(const char *header, const char *value, ...) { + va_list args; + va_start(args, value); +#ifdef MOD_WMS_ENABLED + msIOContext *ioctx = msIO_getHandler(stdout); + if (ioctx && !strcmp(ioctx->label, "apache")) { + + request_rec *r = (request_rec *)(ioctx->cbData); + char *fullvalue = apr_pvsprintf(r->pool, value, args); + if (strcasecmp(header, "Content-Type") == 0) { + r->content_type = fullvalue; + } else if (strcasecmp(header, "Status") == 0) { + r->status = atoi(fullvalue); + } else { + apr_table_setn(r->headers_out, apr_pstrdup(r->pool, header), fullvalue); + } + } else { +#endif // MOD_WMS_ENABLED + if (is_msIO_header_enabled) { + msIO_fprintf(stdout, "%s: ", header); + msIO_vfprintf(stdout, value, args); + msIO_fprintf(stdout, "\r\n"); + } +#ifdef MOD_WMS_ENABLED + } +#endif + va_end(args); +} + +void msIO_sendHeaders() { +#ifdef MOD_WMS_ENABLED + msIOContext *ioctx = msIO_getHandler(stdout); + if (ioctx && !strcmp(ioctx->label, "apache")) + return; +#endif // !MOD_WMS_ENABLED + if (is_msIO_header_enabled) { + msIO_printf("\r\n"); + fflush(stdout); + } +} + +/************************************************************************/ +/* msIO_installHandlers() */ +/************************************************************************/ + +int msIO_installHandlers(msIOContext *stdin_context, + msIOContext *stdout_context, + msIOContext *stderr_context) + +{ + msIOContextGroup *group; + + msIO_Initialize(); + + group = msIO_GetContextGroup(); + + if (stdin_context == NULL) + group->stdin_context = default_contexts.stdin_context; + else if (stdin_context != &group->stdin_context) + group->stdin_context = *stdin_context; + + if (stdout_context == NULL) + group->stdout_context = default_contexts.stdout_context; + else if (stdout_context != &group->stdout_context) + group->stdout_context = *stdout_context; + + if (stderr_context == NULL) + group->stderr_context = default_contexts.stderr_context; + else if (stderr_context != &group->stderr_context) + group->stderr_context = *stderr_context; + + return MS_TRUE; +} + +/************************************************************************/ +/* msIO_contextRead() */ +/************************************************************************/ + +int msIO_contextRead(msIOContext *context, void *data, int byteCount) + +{ + if (context->write_channel == MS_TRUE) + return 0; + else + return context->readWriteFunc(context->cbData, data, byteCount); +} + +/************************************************************************/ +/* msIO_contextWrite() */ +/************************************************************************/ + +int msIO_contextWrite(msIOContext *context, const void *data, int byteCount) + +{ + if (context->write_channel == MS_FALSE) + return 0; + else + return context->readWriteFunc(context->cbData, (void *)data, byteCount); +} + +/* ==================================================================== */ +/* ==================================================================== */ +/* Stdio-like cover functions. */ +/* ==================================================================== */ +/* ==================================================================== */ + +/************************************************************************/ +/* _ms_vsprintf() */ +/************************************************************************/ + +static int _ms_vsprintf(char **workBufPtr, const char *format, va_list ap) + +{ + int ret_val; + int workBufSize = 16000; + + *workBufPtr = (char *)malloc(workBufSize * sizeof(char)); + if (*workBufPtr == NULL) { + msSetError(MS_MEMERR, NULL, "_ms_vsprintf()"); + return -1; + } + +#if defined(HAVE_VSNPRINTF) + /* This should grow a big enough buffer to hold any formatted result. */ + { + va_list wrk_args; + +#ifdef va_copy + va_copy(wrk_args, ap); +#else + wrk_args = ap; +#endif + + while ((ret_val = vsnprintf(*workBufPtr, workBufSize, format, wrk_args)) >= + workBufSize - 1 || + ret_val == -1) { + workBufSize *= 4; + *workBufPtr = (char *)realloc(*workBufPtr, workBufSize); + if (*workBufPtr == NULL) { + msSetError(MS_MEMERR, NULL, "_ms_vsprintf()"); + va_end(wrk_args); + return -1; + } +#ifdef va_copy + va_end(wrk_args); + va_copy(wrk_args, ap); +#else + wrk_args = ap; +#endif + } + va_end(wrk_args); + } +#else + /* We do not have vsnprintf()... there is a risk of buffer overrun */ + ret_val = vsprintf(*workBufPtr, format, ap); + + if (ret_val < 0 || ret_val >= workBufSize) { + msSetError(MS_MISCERR, "Possible buffer overrun.", "_ms_vsprintf()"); + msFree(*workBufPtr); + *workBufPtr = NULL; + return -1; + } +#endif + + return ret_val; +} + +/************************************************************************/ +/* msIO_printf() */ +/************************************************************************/ + +int msIO_printf(const char *format, ...) + +{ + va_list args; + int ret; + va_start(args, format); + ret = msIO_vfprintf(stdout, format, args); + va_end(args); + return ret; +} + +/************************************************************************/ +/* msIO_fprintf() */ +/************************************************************************/ + +int msIO_fprintf(FILE *fp, const char *format, ...) + +{ + va_list args; + int ret; + va_start(args, format); + ret = msIO_vfprintf(fp, format, args); + va_end(args); + return ret; +} + +/************************************************************************/ +/* msIO_vfprintf() */ +/************************************************************************/ + +int msIO_vfprintf(FILE *fp, const char *format, va_list ap) + +{ + int return_val; + msIOContext *context; + char workBuf[8000]; + +#if !defined(HAVE_VSNPRINTF) + return_val = vsprintf(workBuf, format, ap); + + if (return_val < 0 || return_val >= sizeof(workBuf)) { + msSetError(MS_MISCERR, "Possible buffer overrun.", "msIO_vfprintf()"); + return -1; + } + + char *outbuf = workBuf; + +#else + + va_list args_copy; +#ifdef va_copy + va_copy(args_copy, ap); +#else + args_copy = ap; +#endif /* va_copy */ + + char *largerBuf = NULL; + return_val = vsnprintf(workBuf, sizeof(workBuf), format, ap); + if (return_val == -1 || return_val >= (int)sizeof(workBuf) - 1) { + return_val = _ms_vsprintf(&largerBuf, format, args_copy); + } + va_end(args_copy); + + if (return_val < 0) + return -1; + + char *outbuf = largerBuf ? largerBuf : workBuf; + +#endif /* HAVE_VSNPRINTF */ + + context = msIO_getHandler(fp); + if (context == NULL) + return_val = fwrite(outbuf, 1, return_val, fp); + else + return_val = msIO_contextWrite(context, outbuf, return_val); + +#if defined(HAVE_VSNPRINTF) + msFree(largerBuf); +#endif + + return return_val; +} + +/************************************************************************/ +/* msIO_fwrite() */ +/************************************************************************/ + +int msIO_fwrite(const void *data, size_t size, size_t nmemb, FILE *fp) + +{ + msIOContext *context; + + if (size == 0 || nmemb == 0) + return 0; + + context = msIO_getHandler(fp); + if (context == NULL) + return fwrite(data, size, nmemb, fp); + else + return msIO_contextWrite(context, data, size * nmemb) / size; +} + +/************************************************************************/ +/* msIO_fread() */ +/************************************************************************/ + +int msIO_fread(void *data, size_t size, size_t nmemb, FILE *fp) + +{ + msIOContext *context; + + if (size == 0 || nmemb == 0) + return 0; + + context = msIO_getHandler(fp); + if (context == NULL) + return fread(data, size, nmemb, fp); + else + return msIO_contextRead(context, data, size * nmemb) / size; +} + +/* ==================================================================== */ +/* ==================================================================== */ +/* Internal default callbacks implementing stdio reading and */ +/* writing. */ +/* ==================================================================== */ +/* ==================================================================== */ + +/************************************************************************/ +/* msIO_stdioRead() */ +/* */ +/* This is the default implementation via stdio. */ +/************************************************************************/ + +static int msIO_stdioRead(void *cbData, void *data, int byteCount) + +{ + return fread(data, 1, byteCount, (FILE *)cbData); +} + +/************************************************************************/ +/* msIO_stdioWrite() */ +/* */ +/* This is the default implementation via stdio. */ +/************************************************************************/ + +static int msIO_stdioWrite(void *cbData, void *data, int byteCount) + +{ + return fwrite(data, 1, byteCount, (FILE *)cbData); +} + +/************************************************************************/ +/* msIO_Initialize() */ +/************************************************************************/ + +static void msIO_Initialize(void) + +{ + if (is_msIO_initialized == MS_TRUE) + return; + + default_contexts.stdin_context.label = "stdio"; + default_contexts.stdin_context.write_channel = MS_FALSE; + default_contexts.stdin_context.readWriteFunc = msIO_stdioRead; + default_contexts.stdin_context.cbData = (void *)stdin; + + default_contexts.stdout_context.label = "stdio"; + default_contexts.stdout_context.write_channel = MS_TRUE; + default_contexts.stdout_context.readWriteFunc = msIO_stdioWrite; + default_contexts.stdout_context.cbData = (void *)stdout; + + default_contexts.stderr_context.label = "stdio"; + default_contexts.stderr_context.write_channel = MS_TRUE; + default_contexts.stderr_context.readWriteFunc = msIO_stdioWrite; + default_contexts.stderr_context.cbData = (void *)stderr; + + default_contexts.next = NULL; + default_contexts.thread_id = 0; + + is_msIO_initialized = MS_TRUE; +} + +/* ==================================================================== */ +/* ==================================================================== */ +/* FastCGI output redirection functions. */ +/* ==================================================================== */ +/* ==================================================================== */ + +/************************************************************************/ +/* msIO_needBinaryStdout() */ +/* */ +/* This function is intended to ensure that stdout is in binary */ +/* mode. */ +/* */ +/* But don't do it we are using FastCGI. We will take care of */ +/* doing it in the libfcgi library in that case for the normal */ +/* cgi case, and for the fastcgi case the _setmode() call */ +/* causes a crash. */ +/************************************************************************/ + +int msIO_needBinaryStdout() + +{ +#if defined(_WIN32) && !defined(USE_FASTCGI) + if (_setmode(_fileno(stdout), _O_BINARY) == -1) { + msSetError(MS_IOERR, "Unable to change stdout to binary mode.", + "msIO_needBinaryStdout()"); + return (MS_FAILURE); + } +#endif + + return MS_SUCCESS; +} + +/************************************************************************/ +/* msIO_needBinaryStdin() */ +/* */ +/* This function is intended to ensure that stdin is in binary */ +/* mode. */ +/* */ +/* But don't do it we are using FastCGI. We will take care of */ +/* doing it in the libfcgi library in that case for the normal */ +/* cgi case, and for the fastcgi case the _setmode() call */ +/* causes a crash. */ +/************************************************************************/ + +int msIO_needBinaryStdin() + +{ +#if defined(_WIN32) && !defined(USE_FASTCGI) + if (_setmode(_fileno(stdin), _O_BINARY) == -1) { + msSetError(MS_IOERR, "Unable to change stdin to binary mode.", + "msIO_needBinaryStdin()"); + return (MS_FAILURE); + } +#endif + + return MS_SUCCESS; +} + +/* ==================================================================== */ +/* memory buffer io handling functions. */ +/* ==================================================================== */ + +/************************************************************************/ +/* msIO_resetHandlers() */ +/************************************************************************/ + +void msIO_resetHandlers() + +{ + msIOContextGroup *group = msIO_GetContextGroup(); + + if (group == NULL) + return; + + if (strcmp(group->stdin_context.label, "buffer") == 0) { + msIOBuffer *buf = (msIOBuffer *)group->stdin_context.cbData; + + if (buf->data != NULL) + free(buf->data); + free(buf); + } + + if (strcmp(group->stdout_context.label, "buffer") == 0) { + msIOBuffer *buf = (msIOBuffer *)group->stdout_context.cbData; + + if (buf->data != NULL) + free(buf->data); + free(buf); + } + + if (strcmp(group->stderr_context.label, "buffer") == 0) { + msIOBuffer *buf = (msIOBuffer *)group->stderr_context.cbData; + + if (buf->data != NULL) + free(buf->data); + free(buf); + } + + msIO_installHandlers(NULL, NULL, NULL); +} + +/************************************************************************/ +/* msIO_installStdoutToBuffer() */ +/************************************************************************/ + +void msIO_installStdoutToBuffer() + +{ + msIOContextGroup *group = msIO_GetContextGroup(); + msIOContext context; + + context.label = "buffer"; + context.write_channel = MS_TRUE; + context.readWriteFunc = msIO_bufferWrite; + context.cbData = calloc(1, sizeof(msIOBuffer)); + + msIO_installHandlers(&group->stdin_context, &context, &group->stderr_context); +} + +/************************************************************************/ +/* msIO_pushStdoutToBufferAndGetOldContext() */ +/* */ +/* This function installs a temporary buffer I/O context and returns */ +/* previously installed stdout handler. This previous stdout handler */ +/* should later be restored with msIO_restoreOldStdoutContext(). */ +/* This function can be for example used when wanting to ingest into */ +/* libxml objects XML generated by msIO_fprintf() */ +/************************************************************************/ + +msIOContext *msIO_pushStdoutToBufferAndGetOldContext() + +{ + msIOContextGroup *group = msIO_GetContextGroup(); + msIOContext *old_context; + + /* Backup current context */ + old_context = (msIOContext *)msSmallMalloc(sizeof(msIOContext)); + memcpy(old_context, &group->stdout_context, sizeof(msIOContext)); + + msIO_installStdoutToBuffer(); + + return old_context; +} + +/************************************************************************/ +/* msIO_restoreOldStdoutContext() */ +/************************************************************************/ + +void msIO_restoreOldStdoutContext(msIOContext *context_to_restore) { + msIOContextGroup *group = msIO_GetContextGroup(); + msIOContext *prev_context = &group->stdout_context; + msIOBuffer *buffer; + + /* Free memory associated to our temporary context */ + assert(strcmp(prev_context->label, "buffer") == 0); + + buffer = (msIOBuffer *)prev_context->cbData; + msFree(buffer->data); + msFree(buffer); + + /* Restore old context */ + msIO_installHandlers(&group->stdin_context, context_to_restore, + &group->stderr_context); + + msFree(context_to_restore); +} + +/************************************************************************/ +/* msIO_installStdinFromBuffer() */ +/************************************************************************/ + +void msIO_installStdinFromBuffer() + +{ + msIOContextGroup *group = msIO_GetContextGroup(); + msIOContext context; + + context.label = "buffer"; + context.write_channel = MS_FALSE; + context.readWriteFunc = msIO_bufferRead; + context.cbData = calloc(1, sizeof(msIOBuffer)); + + msIO_installHandlers(&context, &group->stdout_context, + &group->stderr_context); +} + +/************************************************************************/ +/* msIO_getAndStripStdoutBufferMimeHeaders() */ +/* */ +/************************************************************************/ + +hashTableObj *msIO_getAndStripStdoutBufferMimeHeaders() { + /* -------------------------------------------------------------------- */ + /* Find stdout buffer. */ + /* -------------------------------------------------------------------- */ + msIOContext *ctx = msIO_getHandler((FILE *)"stdout"); + msIOBuffer *buf; + int start_of_mime_header, current_pos; + hashTableObj *hashTable; + + if (ctx == NULL || ctx->write_channel == MS_FALSE || + strcmp(ctx->label, "buffer") != 0) { + msSetError(MS_MISCERR, "Can't identify msIO buffer.", + "msIO_getAndStripStdoutBufferMimeHeaders"); + return NULL; + } + + buf = (msIOBuffer *)ctx->cbData; + + hashTable = msCreateHashTable(); + + /* -------------------------------------------------------------------- */ + /* Loop over all headers. */ + /* -------------------------------------------------------------------- */ + current_pos = 0; + while (MS_TRUE) { + int pos_of_column = -1; + char *key, *value; + + start_of_mime_header = current_pos; + while (current_pos < buf->data_offset) { + if (buf->data[current_pos] == '\r') { + if (current_pos + 1 == buf->data_offset || + buf->data[current_pos + 1] != '\n') { + pos_of_column = -1; + break; + } + break; + } + if (buf->data[current_pos] == ':') { + pos_of_column = current_pos; + if (current_pos + 1 == buf->data_offset || + buf->data[current_pos + 1] != ' ') { + pos_of_column = -1; + break; + } + } + current_pos++; + } + + if (pos_of_column < 0 || current_pos == buf->data_offset) { + msSetError(MS_MISCERR, "Corrupt mime headers.", + "msIO_getAndStripStdoutBufferMimeHeaders"); + msFreeHashTable(hashTable); + return NULL; + } + + key = (char *)malloc(pos_of_column - start_of_mime_header + 1); + memcpy(key, buf->data + start_of_mime_header, + pos_of_column - start_of_mime_header); + key[pos_of_column - start_of_mime_header] = '\0'; + + value = (char *)malloc(current_pos - (pos_of_column + 2) + 1); + memcpy(value, buf->data + pos_of_column + 2, + current_pos - (pos_of_column + 2)); + value[current_pos - (pos_of_column + 2)] = '\0'; + + msInsertHashTable(hashTable, key, value); + + msFree(key); + msFree(value); + + /* -------------------------------------------------------------------- */ + /* Go to next line. */ + /* -------------------------------------------------------------------- */ + current_pos += 2; + if (current_pos == buf->data_offset) { + msSetError(MS_MISCERR, "Corrupt mime headers.", + "msIO_getAndStripStdoutBufferMimeHeaders"); + msFreeHashTable(hashTable); + return NULL; + } + + /* If next line is a '\r', this is the end of mime headers. */ + if (buf->data[current_pos] == '\r') { + current_pos++; + if (current_pos == buf->data_offset || buf->data[current_pos] != '\n') { + msSetError(MS_MISCERR, "Corrupt mime headers.", + "msIO_getAndStripStdoutBufferMimeHeaders"); + msFreeHashTable(hashTable); + return NULL; + } + current_pos++; + break; + } + } + + /* -------------------------------------------------------------------- */ + /* Move data to front of buffer, and reset length. */ + /* -------------------------------------------------------------------- */ + memmove(buf->data, buf->data + current_pos, buf->data_offset - current_pos); + buf->data[buf->data_offset - current_pos] = '\0'; + buf->data_offset -= current_pos; + + return hashTable; +} + +/************************************************************************/ +/* msIO_stripStdoutBufferContentType() */ +/* */ +/* Strip off Content-Type header from buffer, and return to */ +/* caller. Returned string is the callers responsibility to */ +/* call msFree() on to deallocate. This function will return */ +/* NULL if there is no Content-Type header. */ +/************************************************************************/ + +char *msIO_stripStdoutBufferContentType() + +{ + /* -------------------------------------------------------------------- */ + /* Find stdout buffer. */ + /* -------------------------------------------------------------------- */ + msIOContext *ctx = msIO_getHandler((FILE *)"stdout"); + msIOBuffer *buf; + char *content_type = NULL; + int end_of_ct, start_of_data; + + if (ctx == NULL || ctx->write_channel == MS_FALSE || + strcmp(ctx->label, "buffer") != 0) { + msSetError(MS_MISCERR, "Can't identify msIO buffer.", + "msIO_stripStdoutBufferContentType"); + return NULL; + } + + buf = (msIOBuffer *)ctx->cbData; + + /* -------------------------------------------------------------------- */ + /* Return NULL if we don't have a Content-Type header. */ + /* -------------------------------------------------------------------- */ + if (buf->data_offset < 14 || + strncasecmp((const char *)buf->data, "Content-Type: ", 14) != 0) + return NULL; + + /* -------------------------------------------------------------------- */ + /* Find newline marker at end of content type argument. */ + /* -------------------------------------------------------------------- */ + end_of_ct = 13; + while (end_of_ct + 1 < buf->data_offset && buf->data[end_of_ct + 1] != '\r') + end_of_ct++; + + if (end_of_ct + 1 == buf->data_offset) { + msSetError(MS_MISCERR, "Corrupt Content-Type header.", + "msIO_stripStdoutBufferContentType"); + return NULL; + } + + /* -------------------------------------------------------------------- */ + /* Continue on to the start of data ... */ + /* Go to next line and skip if empty. */ + /* -------------------------------------------------------------------- */ + start_of_data = end_of_ct + 3; + if (start_of_data < buf->data_offset && buf->data[start_of_data] == '\r') + start_of_data += 2; + + if (start_of_data == buf->data_offset) { + msSetError(MS_MISCERR, "Corrupt Content-Type header.", + "msIO_stripStdoutBufferContentType"); + return NULL; + } + + /* -------------------------------------------------------------------- */ + /* Copy out content type. Note we go against the coding guidelines */ + /* here and use strncpy() instead of strlcpy() as the source */ + /* buffer may not be NULL terminated - strlcpy() requires NULL */ + /* terminated sources (see issue #4672). */ + /* -------------------------------------------------------------------- */ + content_type = (char *)malloc(end_of_ct - 14 + 2); + strncpy(content_type, (const char *)buf->data + 14, end_of_ct - 14 + 2); + content_type[end_of_ct - 14 + 1] = '\0'; + + /* -------------------------------------------------------------------- */ + /* Move data to front of buffer, and reset length. */ + /* -------------------------------------------------------------------- */ + memmove(buf->data, buf->data + start_of_data, + buf->data_offset - start_of_data); + buf->data[buf->data_offset - start_of_data] = '\0'; + buf->data_offset -= start_of_data; + + return content_type; +} + +/************************************************************************/ +/* msIO_stripStdoutBufferContentHeaders() */ +/* */ +/* Strip off Content-* headers from buffer. */ +/************************************************************************/ + +void msIO_stripStdoutBufferContentHeaders() { + /* -------------------------------------------------------------------- */ + /* Find stdout buffer. */ + /* -------------------------------------------------------------------- */ + msIOContext *ctx = msIO_getHandler((FILE *)"stdout"); + msIOBuffer *buf; + int start_of_data; + + if (ctx == NULL || ctx->write_channel == MS_FALSE || + strcmp(ctx->label, "buffer") != 0) { + msSetError(MS_MISCERR, "Can't identify msIO buffer.", + "msIO_stripStdoutBufferContentHeaders"); + return; + } + + buf = (msIOBuffer *)ctx->cbData; + + /* -------------------------------------------------------------------- */ + /* Exit if we don't have any content-* header. */ + /* -------------------------------------------------------------------- */ + if (buf->data_offset < 8 || + strncasecmp((const char *)buf->data, "Content-", 8) != 0) + return; + + /* -------------------------------------------------------------------- */ + /* Loop over all content-* headers. */ + /* -------------------------------------------------------------------- */ + start_of_data = 0; + while (buf->data_offset > start_of_data && + strncasecmp((const char *)buf->data + start_of_data, "Content-", 8) == + 0) { + /* -------------------------------------------------------------------- */ + /* Find newline marker at end of content-* header argument. */ + /* -------------------------------------------------------------------- */ + start_of_data += 7; + while (start_of_data + 1 < buf->data_offset && + buf->data[start_of_data + 1] != '\r') + start_of_data++; + + if (start_of_data + 1 == buf->data_offset) { + msSetError(MS_MISCERR, "Corrupt Content-* header.", + "msIO_stripStdoutBufferContentHeaders"); + return; + } + /* -------------------------------------------------------------------- */ + /* Go to next line. */ + /* -------------------------------------------------------------------- */ + start_of_data += 3; + } + + /* -------------------------------------------------------------------- */ + /* Continue on to the start of data ... */ + /* Skip next line if empty. */ + /* -------------------------------------------------------------------- */ + if (start_of_data < buf->data_offset && buf->data[start_of_data] == '\r') + start_of_data += 2; + + if (start_of_data == buf->data_offset) { + msSetError(MS_MISCERR, "Corrupt Content-* header.", + "msIO_stripStdoutBufferContentHeaders"); + return; + } + + /* -------------------------------------------------------------------- */ + /* Move data to front of buffer, and reset length. */ + /* -------------------------------------------------------------------- */ + memmove(buf->data, buf->data + start_of_data, + buf->data_offset - start_of_data); + buf->data[buf->data_offset - start_of_data] = '\0'; + buf->data_offset -= start_of_data; + + return; +} + +/************************************************************************/ +/* msIO_bufferWrite() */ +/************************************************************************/ + +int msIO_bufferWrite(void *cbData, void *data, int byteCount) + +{ + msIOBuffer *buf = (msIOBuffer *)cbData; + + /* + ** Grow buffer if needed (reserve one extra byte to put nul character) + */ + if (buf->data_offset + byteCount >= buf->data_len) { + buf->data_len = buf->data_len * 2 + byteCount + 100; + if (buf->data == NULL) + buf->data = (unsigned char *)malloc(buf->data_len); + else + buf->data = (unsigned char *)realloc(buf->data, buf->data_len); + + if (buf->data == NULL) { + msSetError(MS_MEMERR, "Failed to allocate %d bytes for capture buffer.", + "msIO_bufferWrite()", buf->data_len); + buf->data_len = 0; + return 0; + } + } + + /* + ** Copy result into buffer. + */ + + memcpy(buf->data + buf->data_offset, data, byteCount); + buf->data_offset += byteCount; + buf->data[buf->data_offset] = '\0'; + + return byteCount; +} + +/************************************************************************/ +/* msIO_bufferRead() */ +/************************************************************************/ + +int msIO_bufferRead(void *cbData, void *data, int byteCount) + +{ + (void)cbData; + (void)data; + (void)byteCount; + /* not implemented yet. */ + return 0; +} diff --git a/src/mapio.h b/src/mapio.h new file mode 100644 index 0000000000..2e45d376d4 --- /dev/null +++ b/src/mapio.h @@ -0,0 +1,132 @@ +/****************************************************************************** + * $Id$ + * + * Project: MapServer + * Purpose: Definitions for MapServer IO redirection capability. + * Author: Frank Warmerdam, warmerdam@pobox.com + * + ****************************************************************************** + * Copyright (c) 2004, Frank Warmerdam + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + ****************************************************************************/ + +#ifndef MAPIO_H +#define MAPIO_H + +/* +** We deliberately emulate stdio functions in the msIO cover functions. +** This makes it easy for folks to understand the semantics, and means we +** can just #define things to use stdio in the simplest case. +*/ + +#include +#include "maphash.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef MS_PRINT_FUNC_FORMAT +#if defined(__GNUC__) && __GNUC__ >= 3 && !defined(DOXYGEN_SKIP) +#define MS_PRINT_FUNC_FORMAT(format_idx, arg_idx) \ + __attribute__((__format__(__printf__, format_idx, arg_idx))) +#else +#define MS_PRINT_FUNC_FORMAT(format_idx, arg_idx) +#endif +#endif + +/* stdio analogs */ +int MS_DLL_EXPORT msIO_printf(const char *format, ...) + MS_PRINT_FUNC_FORMAT(1, 2); +int MS_DLL_EXPORT msIO_fprintf(FILE *stream, const char *format, ...) + MS_PRINT_FUNC_FORMAT(2, 3); +int MS_DLL_EXPORT msIO_fwrite(const void *ptr, size_t size, size_t nmemb, + FILE *stream); +int MS_DLL_EXPORT msIO_fread(void *ptr, size_t size, size_t nmemb, + FILE *stream); +int MS_DLL_EXPORT msIO_vfprintf(FILE *fp, const char *format, va_list ap) + MS_PRINT_FUNC_FORMAT(2, 0); + +/* +** Definitions for the callback function and the details of the IO +** channel contexts. +*/ + +typedef int (*msIO_llReadWriteFunc)(void *cbData, void *data, int byteCount); + +typedef struct msIOContext_t { + const char *label; + int write_channel; /* 1 for stdout/stderr, 0 for stdin */ + msIO_llReadWriteFunc readWriteFunc; + void *cbData; +} msIOContext; + +int MS_DLL_EXPORT msIO_installHandlers(msIOContext *stdin_context, + msIOContext *stdout_context, + msIOContext *stderr_context); +msIOContext MS_DLL_EXPORT *msIO_getHandler(FILE *); +void MS_DLL_EXPORT msIO_setHeaderEnabled(int bFlag); +void msIO_setHeader(const char *header, const char *value, ...) + MS_PRINT_FUNC_FORMAT(2, 3); +void msIO_sendHeaders(void); + +/* +** These can be used instead of the stdio style functions if you have +** msIOContext's for the channel in question. +*/ +int msIO_contextRead(msIOContext *context, void *data, int byteCount); +int msIO_contextWrite(msIOContext *context, const void *data, int byteCount); + +/* +** For redirecting IO to a memory buffer. +*/ + +typedef struct { + unsigned char *data; + int data_len; /* really buffer length */ + int data_offset; /* really buffer used */ +} msIOBuffer; + +int MS_DLL_EXPORT msIO_bufferRead(void *, void *, int); +int MS_DLL_EXPORT msIO_bufferWrite(void *, void *, int); + +void MS_DLL_EXPORT msIO_resetHandlers(void); +void MS_DLL_EXPORT msIO_installStdoutToBuffer(void); +void MS_DLL_EXPORT msIO_installStdinFromBuffer(void); +void MS_DLL_EXPORT msIO_Cleanup(void); +char MS_DLL_EXPORT *msIO_stripStdoutBufferContentType(void); +void MS_DLL_EXPORT msIO_stripStdoutBufferContentHeaders(void); +hashTableObj MS_DLL_EXPORT *msIO_getAndStripStdoutBufferMimeHeaders(void); + +msIOContext *msIO_pushStdoutToBufferAndGetOldContext(void); +void msIO_restoreOldStdoutContext(msIOContext *context_to_restore); + +int MS_DLL_EXPORT msIO_isStdContext(void); + +/* this is just for setting normal stdout's to binary mode on windows */ + +int msIO_needBinaryStdout(void); +int msIO_needBinaryStdin(void); + +#ifdef __cplusplus +} +#endif + +#endif /* nef MAPIO_H */ diff --git a/src/mapjoin.c b/src/mapjoin.c new file mode 100644 index 0000000000..bc3a7643b3 --- /dev/null +++ b/src/mapjoin.c @@ -0,0 +1,902 @@ +/****************************************************************************** + * $Id$ + * + * Project: MapServer + * Purpose: Implements MapServer joins. + * Author: Steve Lime and the MapServer team. + * + ****************************************************************************** + * Copyright (c) 1996-2005 Regents of the University of Minnesota. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + ****************************************************************************/ + +#include "mapserver.h" + +#define ROW_ALLOCATION_SIZE 10 + +/* DBF/XBase function prototypes */ +int msDBFJoinConnect(layerObj *layer, joinObj *join); +int msDBFJoinPrepare(joinObj *join, shapeObj *shape); +int msDBFJoinNext(joinObj *join); +int msDBFJoinClose(joinObj *join); +int msDBFJoinTable(layerObj *layer, joinObj *join, shapeObj *shape); + +/* CSV (comma delimited text file) function prototypes */ +int msCSVJoinConnect(layerObj *layer, joinObj *join); +int msCSVJoinPrepare(joinObj *join, shapeObj *shape); +int msCSVJoinNext(joinObj *join); +int msCSVJoinClose(joinObj *join); +int msCSVJoinTable(layerObj *layer, joinObj *join, shapeObj *shape); + +/* MySQL function prototypes */ +int msMySQLJoinConnect(layerObj *layer, joinObj *join); +int msMySQLJoinPrepare(joinObj *join, shapeObj *shape); +int msMySQLJoinNext(joinObj *join); +int msMySQLJoinClose(joinObj *join); +int msMySQLJoinTable(layerObj *layer, joinObj *join, shapeObj *shape); + +/* PostgreSQL function prototypes */ +int msPOSTGRESQLJoinConnect(layerObj *layer, joinObj *join); +int msPOSTGRESQLJoinPrepare(joinObj *join, shapeObj *shape); +int msPOSTGRESQLJoinNext(joinObj *join); +int msPOSTGRESQLJoinClose(joinObj *join); + +/* wrapper function for DB specific join functions */ +int msJoinConnect(layerObj *layer, joinObj *join) { + switch (join->connectiontype) { + case (MS_DB_XBASE): + return msDBFJoinConnect(layer, join); + break; + case (MS_DB_CSV): + return msCSVJoinConnect(layer, join); + break; + case (MS_DB_MYSQL): + return msMySQLJoinConnect(layer, join); + break; + case (MS_DB_POSTGRES): + return msPOSTGRESQLJoinConnect(layer, join); + break; + default: + break; + } + + msSetError(MS_JOINERR, "Unsupported join connection type.", + "msJoinConnect()"); + return MS_FAILURE; +} + +int msJoinPrepare(joinObj *join, shapeObj *shape) { + switch (join->connectiontype) { + case (MS_DB_XBASE): + return msDBFJoinPrepare(join, shape); + break; + case (MS_DB_CSV): + return msCSVJoinPrepare(join, shape); + break; + case (MS_DB_MYSQL): + return msMySQLJoinPrepare(join, shape); + break; + case (MS_DB_POSTGRES): + return msPOSTGRESQLJoinPrepare(join, shape); + break; + default: + break; + } + + msSetError(MS_JOINERR, "Unsupported join connection type.", + "msJoinPrepare()"); + return MS_FAILURE; +} + +int msJoinNext(joinObj *join) { + switch (join->connectiontype) { + case (MS_DB_XBASE): + return msDBFJoinNext(join); + break; + case (MS_DB_CSV): + return msCSVJoinNext(join); + break; + case (MS_DB_MYSQL): + return msMySQLJoinNext(join); + break; + case (MS_DB_POSTGRES): + return msPOSTGRESQLJoinNext(join); + break; + default: + break; + } + + msSetError(MS_JOINERR, "Unsupported join connection type.", "msJoinNext()"); + return MS_FAILURE; +} + +int msJoinClose(joinObj *join) { + switch (join->connectiontype) { + case (MS_DB_XBASE): + return msDBFJoinClose(join); + break; + case (MS_DB_CSV): + return msCSVJoinClose(join); + break; + case (MS_DB_MYSQL): + return msMySQLJoinClose(join); + break; + case (MS_DB_POSTGRES): + return msPOSTGRESQLJoinClose(join); + break; + default: + break; + } + + msSetError(MS_JOINERR, "Unsupported join connection type.", "msJoinClose()"); + return MS_FAILURE; +} + +/* */ +/* XBASE join functions */ +/* */ +typedef struct { + DBFHandle hDBF; + int fromindex, toindex; + char *target; + int nextrecord; +} msDBFJoinInfo; + +int msDBFJoinConnect(layerObj *layer, joinObj *join) { + int i; + char szPath[MS_MAXPATHLEN]; + msDBFJoinInfo *joininfo; + + if (join->joininfo) + return (MS_SUCCESS); /* already open */ + + if (msCheckParentPointer(layer->map, "map") == MS_FAILURE) + return MS_FAILURE; + + /* allocate a msDBFJoinInfo struct */ + joininfo = (msDBFJoinInfo *)malloc(sizeof(msDBFJoinInfo)); + if (!joininfo) { + msSetError(MS_MEMERR, "Error allocating XBase table info structure.", + "msDBFJoinConnect()"); + return (MS_FAILURE); + } + + /* initialize any members that won't get set later on in this function */ + joininfo->target = NULL; + joininfo->nextrecord = 0; + + join->joininfo = joininfo; + + /* open the XBase file */ + if ((joininfo->hDBF = + msDBFOpen(msBuildPath3(szPath, layer->map->mappath, + layer->map->shapepath, join->table), + "rb")) == NULL) { + if ((joininfo->hDBF = + msDBFOpen(msBuildPath(szPath, layer->map->mappath, join->table), + "rb")) == NULL) { + msSetError(MS_IOERR, "(%s)", "msDBFJoinConnect()", join->table); + return (MS_FAILURE); + } + } + + /* get "to" item index */ + if ((joininfo->toindex = msDBFGetItemIndex(joininfo->hDBF, join->to)) == -1) { + msSetError(MS_DBFERR, "Item %s not found in table %s.", + "msDBFJoinConnect()", join->to, join->table); + return (MS_FAILURE); + } + + /* get "from" item index */ + for (i = 0; i < layer->numitems; i++) { + if (strcasecmp(layer->items[i], join->from) == 0) { /* found it */ + joininfo->fromindex = i; + break; + } + } + + if (i == layer->numitems) { + msSetError(MS_JOINERR, "Item %s not found in layer %s.", + "msDBFJoinConnect()", join->from, layer->name); + return (MS_FAILURE); + } + + /* finally store away the item names in the XBase table */ + join->numitems = msDBFGetFieldCount(joininfo->hDBF); + join->items = msDBFGetItems(joininfo->hDBF); + if (!join->items) + return (MS_FAILURE); + + return (MS_SUCCESS); +} + +int msDBFJoinPrepare(joinObj *join, shapeObj *shape) { + msDBFJoinInfo *joininfo = join->joininfo; + + if (!joininfo) { + msSetError(MS_JOINERR, "Join connection has not be created.", + "msDBFJoinPrepare()"); + return (MS_FAILURE); + } + + if (!shape) { + msSetError(MS_JOINERR, "Shape to be joined is empty.", + "msDBFJoinPrepare()"); + return (MS_FAILURE); + } + + if (!shape->values) { + msSetError(MS_JOINERR, "Shape to be joined has no attributes.", + "msDBFJoinPrepare()"); + return (MS_FAILURE); + } + + joininfo->nextrecord = 0; /* starting with the first record */ + + if (joininfo->target) + free(joininfo->target); /* clear last target */ + joininfo->target = msStrdup(shape->values[joininfo->fromindex]); + + return (MS_SUCCESS); +} + +int msDBFJoinNext(joinObj *join) { + int i, n; + msDBFJoinInfo *joininfo = join->joininfo; + + if (!joininfo) { + msSetError(MS_JOINERR, "Join connection has not be created.", + "msDBFJoinNext()"); + return (MS_FAILURE); + } + + if (!joininfo->target) { + msSetError(MS_JOINERR, "No target specified, run msDBFJoinPrepare() first.", + "msDBFJoinNext()"); + return (MS_FAILURE); + } + + /* clear any old data */ + if (join->values) { + msFreeCharArray(join->values, join->numitems); + join->values = NULL; + } + + n = msDBFGetRecordCount(joininfo->hDBF); + + for (i = joininfo->nextrecord; i < n; i++) { /* find a match */ + if (strcmp(joininfo->target, msDBFReadStringAttribute(joininfo->hDBF, i, + joininfo->toindex)) == + 0) + break; + } + + if (i == n) { /* unable to do the join */ + if ((join->values = (char **)malloc(sizeof(char *) * join->numitems)) == + NULL) { + msSetError(MS_MEMERR, NULL, "msDBFJoinNext()"); + return (MS_FAILURE); + } + for (i = 0; i < join->numitems; i++) + join->values[i] = msStrdup("\0"); /* initialize to zero length strings */ + + joininfo->nextrecord = n; + return (MS_DONE); + } + + if ((join->values = msDBFGetValues(joininfo->hDBF, i)) == NULL) + return (MS_FAILURE); + + joininfo->nextrecord = + i + 1; /* so we know where to start looking next time through */ + + return (MS_SUCCESS); +} + +int msDBFJoinClose(joinObj *join) { + msDBFJoinInfo *joininfo = join->joininfo; + + if (!joininfo) + return (MS_SUCCESS); /* already closed */ + + if (joininfo->hDBF) + msDBFClose(joininfo->hDBF); + if (joininfo->target) + free(joininfo->target); + free(joininfo); + joininfo = NULL; + + return (MS_SUCCESS); +} + +/* */ +/* CSV (comma separated value) join functions */ +/* */ +typedef struct { + int fromindex, toindex; + char *target; + char ***rows; + int numrows; + int nextrow; +} msCSVJoinInfo; + +int msCSVJoinConnect(layerObj *layer, joinObj *join) { + int i; + FILE *stream; + char szPath[MS_MAXPATHLEN]; + msCSVJoinInfo *joininfo; + char buffer[MS_BUFFER_LENGTH]; + + if (join->joininfo) + return (MS_SUCCESS); /* already open */ + if (msCheckParentPointer(layer->map, "map") == MS_FAILURE) + return MS_FAILURE; + + /* allocate a msCSVJoinInfo struct */ + if ((joininfo = (msCSVJoinInfo *)malloc(sizeof(msCSVJoinInfo))) == NULL) { + msSetError(MS_MEMERR, "Error allocating CSV table info structure.", + "msCSVJoinConnect()"); + return (MS_FAILURE); + } + + /* initialize any members that won't get set later on in this function */ + joininfo->target = NULL; + joininfo->nextrow = 0; + + join->joininfo = joininfo; + + /* open the CSV file */ + if ((stream = fopen(msBuildPath3(szPath, layer->map->mappath, + layer->map->shapepath, join->table), + "r")) == NULL) { + if ((stream = fopen(msBuildPath(szPath, layer->map->mappath, join->table), + "r")) == NULL) { + msSetError(MS_IOERR, "(%s)", "msCSVJoinConnect()", join->table); + return (MS_FAILURE); + } + } + + /* once through to get the number of rows */ + joininfo->numrows = 0; + while (fgets(buffer, MS_BUFFER_LENGTH, stream) != NULL) + joininfo->numrows++; + rewind(stream); + + if ((joininfo->rows = + (char ***)malloc(joininfo->numrows * sizeof(char **))) == NULL) { + fclose(stream); + msSetError(MS_MEMERR, "Error allocating rows.", "msCSVJoinConnect()"); + return (MS_FAILURE); + } + + /* load the rows */ + i = 0; + while (fgets(buffer, MS_BUFFER_LENGTH, stream) != NULL) { + msStringTrimEOL(buffer); + joininfo->rows[i] = msStringSplitComplex(buffer, ",", &(join->numitems), + MS_ALLOWEMPTYTOKENS); + i++; + } + fclose(stream); + + /* get "from" item index */ + for (i = 0; i < layer->numitems; i++) { + if (strcasecmp(layer->items[i], join->from) == 0) { /* found it */ + joininfo->fromindex = i; + break; + } + } + + if (i == layer->numitems) { + msSetError(MS_JOINERR, "Item %s not found in layer %s.", + "msCSVJoinConnect()", join->from, layer->name); + return (MS_FAILURE); + } + + /* get "to" index (for now the user tells us which column, 1..n) */ + joininfo->toindex = atoi(join->to) - 1; + if (joininfo->toindex < 0 || joininfo->toindex > join->numitems) { + msSetError(MS_JOINERR, "Invalid column index %s.", "msCSVJoinConnect()", + join->to); + return (MS_FAILURE); + } + + /* store away the column names (1..n) */ + if ((join->items = (char **)malloc(sizeof(char *) * join->numitems)) == + NULL) { + msSetError(MS_MEMERR, "Error allocating space for join item names.", + "msCSVJoinConnect()"); + return (MS_FAILURE); + } + for (i = 0; i < join->numitems; i++) { + join->items[i] = (char *)malloc(12); /* plenty of space */ + sprintf(join->items[i], "%d", i + 1); + } + + return (MS_SUCCESS); +} + +int msCSVJoinPrepare(joinObj *join, shapeObj *shape) { + msCSVJoinInfo *joininfo = join->joininfo; + + if (!joininfo) { + msSetError(MS_JOINERR, "Join connection has not be created.", + "msCSVJoinPrepare()"); + return (MS_FAILURE); + } + + if (!shape) { + msSetError(MS_JOINERR, "Shape to be joined is empty.", + "msCSVJoinPrepare()"); + return (MS_FAILURE); + } + + if (!shape->values) { + msSetError(MS_JOINERR, "Shape to be joined has no attributes.", + "msCSVJoinPrepare()"); + return (MS_FAILURE); + } + + joininfo->nextrow = 0; /* starting with the first record */ + + if (joininfo->target) + free(joininfo->target); /* clear last target */ + joininfo->target = msStrdup(shape->values[joininfo->fromindex]); + + return (MS_SUCCESS); +} + +int msCSVJoinNext(joinObj *join) { + int i, j; + msCSVJoinInfo *joininfo = join->joininfo; + + if (!joininfo) { + msSetError(MS_JOINERR, "Join connection has not be created.", + "msCSVJoinNext()"); + return (MS_FAILURE); + } + + /* clear any old data */ + if (join->values) { + msFreeCharArray(join->values, join->numitems); + join->values = NULL; + } + + for (i = joininfo->nextrow; i < joininfo->numrows; i++) { /* find a match */ + if (strcmp(joininfo->target, joininfo->rows[i][joininfo->toindex]) == 0) + break; + } + + if ((join->values = (char **)malloc(sizeof(char *) * join->numitems)) == + NULL) { + msSetError(MS_MEMERR, NULL, "msCSVJoinNext()"); + return (MS_FAILURE); + } + + if (i == joininfo->numrows) { /* unable to do the join */ + for (j = 0; j < join->numitems; j++) + join->values[j] = msStrdup("\0"); /* initialize to zero length strings */ + + joininfo->nextrow = joininfo->numrows; + return (MS_DONE); + } + + for (j = 0; j < join->numitems; j++) + join->values[j] = msStrdup(joininfo->rows[i][j]); + + joininfo->nextrow = + i + 1; /* so we know where to start looking next time through */ + + return (MS_SUCCESS); +} + +int msCSVJoinClose(joinObj *join) { + int i; + msCSVJoinInfo *joininfo = join->joininfo; + + if (!joininfo) + return (MS_SUCCESS); /* already closed */ + + for (i = 0; i < joininfo->numrows; i++) + msFreeCharArray(joininfo->rows[i], join->numitems); + free(joininfo->rows); + if (joininfo->target) + free(joininfo->target); + free(joininfo); + joininfo = NULL; + + return (MS_SUCCESS); +} + +#ifdef USE_MYSQL + +#ifndef _mysql_h +#include +#endif + +char *DB_HOST = NULL; +char *DB_USER = NULL; +char *DB_PASSWD = NULL; +char *DB_DATABASE = NULL; +char *delim; + +#define MYDEBUG if (0) + +MYSQL_RES *msMySQLQuery(char *q, MYSQL *conn) { + MYSQL_RES *qresult = NULL; + if (mysql_query(conn, q) < 0) { + mysql_close(conn); + msSetError(MS_QUERYERR, "Bad mysql query (%s)", "msMySQLQuery()", q); + return qresult; + } + if (!(qresult = mysql_store_result(conn))) { + mysql_close(conn); + msSetError(MS_QUERYERR, "mysql query failed (%s)", "msMySQLQuery()", q); + return qresult; + } + return qresult; +} + +/* */ +/* mysql join functions */ +/* */ +typedef struct { + MYSQL mysql, *conn; + MYSQL_RES *qresult; + MYSQL_ROW row; + int rows; + int fromindex; + char *tocolumn; + char *target; + int nextrecord; +} msMySQLJoinInfo; +#endif + +int msMySQLJoinConnect(layerObj *layer, joinObj *join) { + (void)layer; + (void)join; +#ifndef USE_MYSQL + msSetError(MS_QUERYERR, + "MySQL support not available (compile with --with-mysql)", + "msMySQLJoinConnect()"); + return (MS_FAILURE); +#else + int i; + char qbuf[4000]; + char *conn_decrypted; + msMySQLJoinInfo *joininfo; + + MYDEBUG if (setvbuf(stdout, NULL, _IONBF, 0)) { printf("Whoops..."); }; + if (join->joininfo) + return (MS_SUCCESS); /* already open */ + + /* allocate a msMySQLJoinInfo struct */ + joininfo = (msMySQLJoinInfo *)malloc(sizeof(msMySQLJoinInfo)); + if (!joininfo) { + msSetError(MS_MEMERR, "Error allocating mysql table info structure.", + "msMySQLJoinConnect()"); + return (MS_FAILURE); + } + + /* initialize any members that won't get set later on in this function */ + joininfo->qresult = NULL; + joininfo->target = NULL; + joininfo->nextrecord = 0; + + join->joininfo = joininfo; + + /* open the mysql connection */ + + if (join->connection == NULL) { + msSetError( + MS_QUERYERR, + "Error parsing MYSQL JOIN: nothing specified in CONNECTION statement.", + "msMySQLJoinConnect()"); + + return (MS_FAILURE); + } + + conn_decrypted = msDecryptStringTokens(layer->map, join->connection); + if (conn_decrypted == NULL) { + msSetError( + MS_QUERYERR, + "Error parsing MYSQL JOIN: unable to decrypt CONNECTION statement.", + "msMySQLJoinConnect()"); + return (MS_FAILURE); + } + + delim = msStrdup(":"); + DB_HOST = msStrdup(strtok(conn_decrypted, delim)); + DB_USER = msStrdup(strtok(NULL, delim)); + DB_PASSWD = msStrdup(strtok(NULL, delim)); + DB_DATABASE = msStrdup(strtok(NULL, delim)); + free(conn_decrypted); + + if (DB_HOST == NULL || DB_USER == NULL || DB_PASSWD == NULL || + DB_DATABASE == NULL) { + msSetError(MS_QUERYERR, + "DB param error: at least one of HOST, USER, PASSWD or DATABASE " + "is null!", + "msMySQLJoinConnect()"); + return MS_FAILURE; + } + if (strcmp(DB_PASSWD, "none") == 0) + strcpy(DB_PASSWD, ""); + +#if MYSQL_VERSION_ID >= 40000 + mysql_init(&(joininfo->mysql)); + if (!(joininfo->conn = mysql_real_connect( + &(joininfo->mysql), DB_HOST, DB_USER, DB_PASSWD, NULL, 0, NULL, 0))) +#else + if (!(joininfo->conn = + mysql_connect(&(joininfo->mysql), DB_HOST, DB_USER, DB_PASSWD))) +#endif + { + char tmp[4000]; + snprintf(tmp, sizeof(tmp), + "Failed to connect to SQL server: Error: %s\nHost: " + "%s\nUsername:%s\nPassword:%s\n", + mysql_error(joininfo->conn), DB_HOST, DB_USER, DB_PASSWD); + msSetError(MS_QUERYERR, "%s", "msMYSQLLayerOpen()", tmp); + free(joininfo); + return MS_FAILURE; + } + + MYDEBUG printf("msMYSQLLayerOpen2 called
\n"); + if (mysql_select_db(joininfo->conn, DB_DATABASE) < 0) { + mysql_close(joininfo->conn); + } + MYDEBUG printf("msMYSQLLayerOpen3 called
\n"); + if (joininfo->qresult != NULL) { /* query leftover */ + MYDEBUG printf("msMYSQLLayerOpen4 called
\n"); + mysql_free_result(joininfo->qresult); + } + MYDEBUG printf("msMYSQLLayerOpen5 called
\n"); + snprintf(qbuf, sizeof(qbuf), "SELECT count(%s) FROM %s", join->to, + join->table); + MYDEBUG printf("%s
\n", qbuf); + if ((joininfo->qresult = + msMySQLQuery(qbuf, joininfo->conn))) { /* There were some rows found, + write 'em out for debug */ + int numrows = mysql_affected_rows(joininfo->conn); + MYDEBUG printf("%d rows
\n", numrows); + for (i = 0; i < numrows; i++) { + MYSQL_ROW row = mysql_fetch_row(joininfo->qresult); + MYDEBUG printf("(%s)
\n", row[0]); + joininfo->rows = atoi(row[0]); + } + } else { + msSetError(MS_DBFERR, "Item %s not found in table %s.", + "msMySQLJoinConnect()", join->to, join->table); + return (MS_FAILURE); + } + snprintf(qbuf, sizeof(qbuf), "EXPLAIN %s", join->table); + if ((joininfo->qresult = + msMySQLQuery(qbuf, joininfo->conn))) { /* There were some rows found, + write 'em out for debug */ + join->numitems = mysql_affected_rows(joininfo->conn); + if ((join->items = (char **)malloc(sizeof(char *) * join->numitems)) == + NULL) { + msSetError(MS_MEMERR, NULL, "msMySQLJoinConnect()"); + return (MS_FAILURE); + } + MYDEBUG printf("%d rows
\n", join->numitems); + for (i = 0; i < join->numitems; i++) { + MYSQL_ROW row = mysql_fetch_row(joininfo->qresult); + MYDEBUG printf("(%s)
\n", row[0]); + join->items[i] = msStrdup(row[0]); + } + } else { + msSetError(MS_DBFERR, "Item %s not found in table %s.", + "msMySQLJoinConnect()", join->to, join->table); + return (MS_FAILURE); + } + joininfo->tocolumn = msStrdup(join->to); + + /* get "from" item index */ + for (i = 0; i < layer->numitems; i++) { + if (strcasecmp(layer->items[i], join->from) == 0) { /* found it */ + joininfo->fromindex = i; + break; + } + } + + if (i == layer->numitems) { + msSetError(MS_JOINERR, "Item %s not found in layer %s.", + "msMySQLJoinConnect()", join->from, layer->name); + return (MS_FAILURE); + } + + /* finally store away the item names in the XBase table */ + if (!join->items) + return (MS_FAILURE); + + return (MS_SUCCESS); +#endif +} + +int msMySQLJoinPrepare(joinObj *join, shapeObj *shape) { + (void)join; + (void)shape; +#ifndef USE_MYSQL + msSetError(MS_QUERYERR, + "MySQL support not available (compile with --with-mysql)", + "msMySQLJoinPrepare()"); + return (MS_FAILURE); +#else + msMySQLJoinInfo *joininfo = join->joininfo; + + if (!joininfo) { + msSetError(MS_JOINERR, "Join connection has not be created.", + "msMySQLJoinPrepare()"); + return (MS_FAILURE); + } + + if (!shape) { + msSetError(MS_JOINERR, "Shape to be joined is empty.", + "msMySQLJoinPrepare()"); + return (MS_FAILURE); + } + + if (!shape->values) { + msSetError(MS_JOINERR, "Shape to be joined has no attributes.", + "msMySQLJoinPrepare()"); + return (MS_FAILURE); + } + + joininfo->nextrecord = 0; /* starting with the first record */ + + if (joininfo->target) + free(joininfo->target); /* clear last target */ + joininfo->target = msStrdup(shape->values[joininfo->fromindex]); + + return (MS_SUCCESS); +#endif +} + +int msMySQLJoinNext(joinObj *join) { + (void)join; +#ifndef USE_MYSQL + msSetError(MS_QUERYERR, + "MySQL support not available (compile with --with-mysql)", + "msMySQLJoinNext()"); + return (MS_FAILURE); +#else + int i; + char qbuf[4000]; + msMySQLJoinInfo *joininfo = join->joininfo; + + if (!joininfo) { + msSetError(MS_JOINERR, "Join connection has not be created.", + "msMySQLJoinNext()"); + return (MS_FAILURE); + } + + if (!joininfo->target) { + msSetError(MS_JOINERR, + "No target specified, run msMySQLJoinPrepare() first.", + "msMySQLJoinNext()"); + return (MS_FAILURE); + } + + /* clear any old data */ + if (join->values) { + msFreeCharArray(join->values, join->numitems); + join->values = NULL; + } + + /* int n = joininfo->rows; */ + + /* for(i=joininfo->nextrecord; itarget, msMySQLReadStringAttribute(joininfo->conn, i, + * joininfo->toindex)) == 0) break; */ + /* } */ + snprintf(qbuf, sizeof(qbuf), "SELECT * FROM %s WHERE %s = %s", join->table, + joininfo->tocolumn, joininfo->target); + MYDEBUG printf("%s
\n", qbuf); + if ((joininfo->qresult = + msMySQLQuery(qbuf, joininfo->conn))) { /* There were some rows found, + write 'em out for debug */ + int numrows = mysql_affected_rows(joininfo->conn); + int numfields = mysql_field_count(joininfo->conn); + MYDEBUG printf("%d rows
\n", numrows); + if (numrows > 0) { + MYSQL_ROW row = mysql_fetch_row(joininfo->qresult); + for (i = 0; i < numfields; i++) { + MYDEBUG printf("%s,", row[i]); + } + MYDEBUG printf("
\n"); + free(join->values); + if ((join->values = (char **)malloc(sizeof(char *) * join->numitems)) == + NULL) { + msSetError(MS_MEMERR, NULL, "msMySQLJoinNext()"); + return (MS_FAILURE); + } + for (i = 0; i < join->numitems; i++) { + /* join->values[i] = msStrdup("\0"); */ /* initialize to zero length + strings */ + join->values[i] = + msStrdup(row[i]); /* initialize to zero length strings */ + /* rows = atoi(row[0]); */ + } + } else { + if ((join->values = (char **)malloc(sizeof(char *) * join->numitems)) == + NULL) { + msSetError(MS_MEMERR, NULL, "msMySQLJoinNext()"); + return (MS_FAILURE); + } + for (i = 0; i < join->numitems; i++) + join->values[i] = + msStrdup("\0"); /* initialize to zero length strings */ + + return (MS_DONE); + } + } else { + msSetError(MS_QUERYERR, "Query error (%s)", "msMySQLJoinNext()", qbuf); + return (MS_FAILURE); + } + +#ifdef __NOTDEF__ + if (i == n) { /* unable to do the join */ + if ((join->values = (char **)malloc(sizeof(char *) * join->numitems)) == + NULL) { + msSetError(MS_MEMERR, NULL, "msMySQLJoinNext()"); + return (MS_FAILURE); + } + for (i = 0; i < join->numitems; i++) + join->values[i] = msStrdup("\0"); /* initialize to zero length strings */ + + joininfo->nextrecord = n; + return (MS_DONE); + } + + if ((join->values = msMySQLGetValues(joininfo->conn, i)) == NULL) + return (MS_FAILURE); + + joininfo->nextrecord = + i + 1; /* so we know where to start looking next time through */ +#endif /* __NOTDEF__ */ + + return (MS_SUCCESS); +#endif +} + +int msMySQLJoinClose(joinObj *join) { + (void)join; +#ifndef USE_MYSQL + msSetError(MS_QUERYERR, + "MySQL support not available (compile with --with-mysql)", + "msMySQLJoinClose()"); + return (MS_FAILURE); +#else + msMySQLJoinInfo *joininfo = join->joininfo; + + if (!joininfo) + return (MS_SUCCESS); /* already closed */ + + mysql_close(joininfo->conn); + if (joininfo->target) + free(joininfo->target); + free(joininfo); + joininfo = NULL; + + return (MS_SUCCESS); +#endif +} diff --git a/src/mapkml.cpp b/src/mapkml.cpp new file mode 100644 index 0000000000..97c3392024 --- /dev/null +++ b/src/mapkml.cpp @@ -0,0 +1,236 @@ +/****************************************************************************** + * $Id$ + * + * Project: MapServer + * Purpose: Headers for mapkml.cpp Google Earth KML output + * Author: David Kana and the MapServer team + * + ****************************************************************************** + * Copyright (c) 1996-2009 Regents of the University of Minnesota. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + *****************************************************************************/ +#include "mapserver.h" + +#ifdef USE_KML + +#include "mapkmlrenderer.h" + +#ifdef __cplusplus +extern "C" { +#endif + +KmlRenderer *getKmlRenderer(imageObj *img) { + return (KmlRenderer *)img->img.plugin; +} + +imageObj *msCreateImageKml(int width, int height, outputFormatObj *format, + colorObj *bg) { + imageObj *image = NULL; + + image = (imageObj *)malloc(sizeof(imageObj)); + MS_CHECK_ALLOC(image, sizeof(imageObj), NULL); + memset(image, 0, sizeof(imageObj)); + + KmlRenderer *ren = new KmlRenderer(width, height, format, bg); + image->img.plugin = (void *)ren; + + return image; +} + +int msSaveImageKml(imageObj *img, mapObj * /*map*/, FILE *fp, + outputFormatObj *format) { + KmlRenderer *renderer = getKmlRenderer(img); + return renderer->saveImage(img, fp, format); +} + +int msRenderLineKml(imageObj *img, shapeObj *p, strokeStyleObj *style) { + KmlRenderer *renderer = getKmlRenderer(img); + renderer->renderLine(img, p, style); + return MS_SUCCESS; +} + +int msRenderPolygonKml(imageObj *img, shapeObj *p, colorObj *color) { + KmlRenderer *renderer = getKmlRenderer(img); + renderer->renderPolygon(img, p, color); + return MS_SUCCESS; +} + +int msRenderPolygonTiledKml(imageObj * /*img*/, shapeObj * /*p*/, + imageObj * /*tile*/) { + /*KmlRenderer* renderer = getKmlRenderer(img);*/ + return MS_SUCCESS; +} + +int msRenderLineTiledKml(imageObj * /*img*/, shapeObj * /*p*/, + imageObj * /*tile*/) { + return MS_SUCCESS; +} + +int msRenderGlyphsKml(imageObj *img, const textSymbolObj *ts, colorObj *c, + colorObj *oc, int ow, int /*isMarker*/) { + KmlRenderer *renderer = getKmlRenderer(img); + renderer->renderGlyphs(img, ts, c, oc, ow); + return MS_SUCCESS; +} + +int msRenderVectorSymbolKml(imageObj *img, double x, double y, + symbolObj *symbol, symbolStyleObj *style) { + KmlRenderer *renderer = getKmlRenderer(img); + renderer->renderVectorSymbol(img, x, y, symbol, style); + return MS_SUCCESS; +} + +int msRenderPixmapSymbolKml(imageObj *img, double x, double y, + symbolObj *symbol, symbolStyleObj *style) { + KmlRenderer *renderer = getKmlRenderer(img); + renderer->renderPixmapSymbol(img, x, y, symbol, style); + return MS_SUCCESS; +} + +int msRenderEllipseSymbolKml(imageObj *image, double x, double y, + symbolObj *symbol, symbolStyleObj *style) { + KmlRenderer *renderer = getKmlRenderer(image); + renderer->renderEllipseSymbol(image, x, y, symbol, style); + return MS_SUCCESS; +} + +int msRenderTruetypeSymbolKml(imageObj *image, double x, double y, + symbolObj *symbol, symbolStyleObj *style) { + KmlRenderer *renderer = getKmlRenderer(image); + renderer->renderTruetypeSymbol(image, x, y, symbol, style); + return MS_SUCCESS; +} + +int msRenderTileKml(imageObj * /*img*/, imageObj * /*tile*/, double /*x*/, + double /*y*/) { + return MS_SUCCESS; +} + +int msGetRasterBufferKml(imageObj * /*img*/, rasterBufferObj * /*rb*/) { + return MS_FAILURE; // not supported for kml +} + +int msGetTruetypeTextBBoxKml(rendererVTableObj * /*r*/, char ** /*fonts*/, + int /*numfonts*/, double size, char *string, + rectObj *rect, double **advances, + int /*bAdjustBaseline*/) { + rect->minx = 0.0; + rect->maxx = 0.0; + rect->miny = 0.0; + rect->maxy = 0.0; + if (advances) { + int numglyphs = msGetNumGlyphs(string); + *advances = (double *)msSmallMalloc(numglyphs * sizeof(double)); + for (int i = 0; i < numglyphs; i++) { + (*advances)[i] = size; + } + } + return MS_SUCCESS; +} + +int msStartNewLayerKml(imageObj *img, mapObj * /*map*/, layerObj *layer) { + KmlRenderer *renderer = getKmlRenderer(img); + return renderer->startNewLayer(img, layer); +} + +int msCloseNewLayerKml(imageObj *img, mapObj * /*map*/, layerObj *layer) { + KmlRenderer *renderer = getKmlRenderer(img); + return renderer->closeNewLayer(img, layer); +} + +int msFreeImageKml(imageObj *image) { + KmlRenderer *renderer = getKmlRenderer(image); + if (renderer) { + delete renderer; + } + image->img.plugin = NULL; + return MS_SUCCESS; +} + +int msFreeSymbolKml(symbolObj * /*symbol*/) { return MS_SUCCESS; } + +int msStartShapeKml(imageObj *img, shapeObj *shape) { + KmlRenderer *renderer = getKmlRenderer(img); + renderer->startShape(img, shape); + return MS_SUCCESS; +} + +int msEndShapeKml(imageObj *img, shapeObj *shape) { + KmlRenderer *renderer = getKmlRenderer(img); + renderer->endShape(img, shape); + return MS_SUCCESS; +} + +int msMergeRasterBufferKml(imageObj *dest, rasterBufferObj *overlay, + double /*opacity*/, int /*srcX*/, int /*srcY*/, + int /*dstX*/, int /*dstY*/, int /*width*/, + int /*height*/) { + KmlRenderer *renderer = getKmlRenderer(dest); + return renderer->mergeRasterBuffer(dest, overlay); +} + +#ifdef __cplusplus +} +#endif + +#endif /*USE_KML*/ + +int aggInitializeRasterBuffer(rasterBufferObj *rb, int width, int height, + int mode); + +int msPopulateRendererVTableKML(rendererVTableObj *renderer) { +#ifdef USE_KML + renderer->supports_pixel_buffer = 0; + renderer->supports_clipping = 0; + renderer->use_imagecache = 0; + renderer->default_transform_mode = MS_TRANSFORM_NONE; + + renderer->startLayer = msStartNewLayerKml; + renderer->endLayer = msCloseNewLayerKml; + renderer->renderLine = &msRenderLineKml; + renderer->createImage = &msCreateImageKml; + renderer->saveImage = &msSaveImageKml; + renderer->renderPolygon = &msRenderPolygonKml; + renderer->renderGlyphs = &msRenderGlyphsKml; + renderer->renderEllipseSymbol = &msRenderEllipseSymbolKml; + renderer->renderVectorSymbol = &msRenderVectorSymbolKml; + renderer->renderPixmapSymbol = &msRenderPixmapSymbolKml; + renderer->mergeRasterBuffer = &msMergeRasterBufferKml; + renderer->loadImageFromFile = msLoadMSRasterBufferFromFile; + renderer->initializeRasterBuffer = aggInitializeRasterBuffer; + renderer->renderTile = &msRenderTileKml; + renderer->renderPolygonTiled = &msRenderPolygonTiledKml; + renderer->renderLineTiled = NULL; + renderer->freeSymbol = &msFreeSymbolKml; + renderer->freeImage = &msFreeImageKml; + renderer->mergeRasterBuffer = msMergeRasterBufferKml; + renderer->compositeRasterBuffer = NULL; + + renderer->startShape = &msStartShapeKml; + renderer->endShape = &msEndShapeKml; + + return MS_SUCCESS; +#else + (void)renderer; + msSetError(MS_MISCERR, "KML Driver requested but is not built in", + "msPopulateRendererVTableKML()"); + return MS_FAILURE; +#endif +} diff --git a/src/mapkmlrenderer.cpp b/src/mapkmlrenderer.cpp new file mode 100644 index 0000000000..12b54c58a8 --- /dev/null +++ b/src/mapkmlrenderer.cpp @@ -0,0 +1,1330 @@ +/****************************************************************************** + * $Id$ + * + * Project: MapServer + * Purpose: Google Earth KML output + * Author: David Kana and the MapServer team + * + ****************************************************************************** + * Copyright (c) 1996-2009 Regents of the University of Minnesota. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + *****************************************************************************/ + +#include "mapserver-config.h" +#ifdef USE_KML + +#include "mapserver.h" +#include "maperror.h" +#include "mapkmlrenderer.h" +#include "mapio.h" +#include "mapows.h" + +#include "cpl_conv.h" +#include "cpl_vsi.h" +#include "cpl_string.h" + +#define KML_MAXFEATURES_TODRAW 1000 + +KmlRenderer::KmlRenderer(int width, int height, outputFormatObj * /*format*/, + colorObj * /*color*/) + : Width(width), Height(height), MapCellsize(1.0), XmlDoc(NULL), + LayerNode(NULL), GroundOverlayNode(NULL), PlacemarkNode(NULL), + GeomNode(NULL), Items(NULL), NumItems(0), FirstLayer(MS_TRUE), map(NULL), + currentLayer(NULL), mElevationFromAttribute(false), + mElevationAttributeIndex(-1), mCurrentElevationValue(0.0) + +{ + /*private variables*/ + pszLayerDescMetadata = NULL; + papszLayerIncludeItems = NULL; + nIncludeItems = 0; + papszLayerExcludeItems = NULL; + nExcludeItems = 0; + pszLayerNameAttributeMetadata = + NULL; /*metadata to use for a name for each feature*/ + + LineStyle = NULL; + numLineStyle = 0; + + xmlNodePtr styleNode; + xmlNodePtr listStyleNode; + /* Create document.*/ + XmlDoc = xmlNewDoc(BAD_CAST "1.0"); + + xmlNodePtr rootNode = xmlNewNode(NULL, BAD_CAST "kml"); + + /* Name spaces*/ + xmlSetNs(rootNode, + xmlNewNs(rootNode, BAD_CAST "http://www.opengis.net/kml/2.2", NULL)); + + xmlDocSetRootElement(XmlDoc, rootNode); + + DocNode = xmlNewChild(rootNode, NULL, BAD_CAST "Document", NULL); + + styleNode = xmlNewChild(DocNode, NULL, BAD_CAST "Style", NULL); + xmlNewProp(styleNode, BAD_CAST "id", BAD_CAST "LayerFolder_check"); + listStyleNode = xmlNewChild(styleNode, NULL, BAD_CAST "ListStyle", NULL); + xmlNewChild(listStyleNode, NULL, BAD_CAST "listItemType", BAD_CAST "check"); + + styleNode = xmlNewChild(DocNode, NULL, BAD_CAST "Style", NULL); + xmlNewProp(styleNode, BAD_CAST "id", + BAD_CAST "LayerFolder_checkHideChildren"); + listStyleNode = xmlNewChild(styleNode, NULL, BAD_CAST "ListStyle", NULL); + xmlNewChild(listStyleNode, NULL, BAD_CAST "listItemType", + BAD_CAST "checkHideChildren"); + + styleNode = xmlNewChild(DocNode, NULL, BAD_CAST "Style", NULL); + xmlNewProp(styleNode, BAD_CAST "id", BAD_CAST "LayerFolder_checkOffOnly"); + listStyleNode = xmlNewChild(styleNode, NULL, BAD_CAST "ListStyle", NULL); + xmlNewChild(listStyleNode, NULL, BAD_CAST "listItemType", + BAD_CAST "checkOffOnly"); + + styleNode = xmlNewChild(DocNode, NULL, BAD_CAST "Style", NULL); + xmlNewProp(styleNode, BAD_CAST "id", BAD_CAST "LayerFolder_radioFolder"); + listStyleNode = xmlNewChild(styleNode, NULL, BAD_CAST "ListStyle", NULL); + xmlNewChild(listStyleNode, NULL, BAD_CAST "listItemType", + BAD_CAST "radioFolder"); + + StyleHashTable = msCreateHashTable(); +} + +KmlRenderer::~KmlRenderer() { + if (XmlDoc) + xmlFreeDoc(XmlDoc); + + if (StyleHashTable) + msFreeHashTable(StyleHashTable); + + if (LineStyle) + msFree(LineStyle); + + xmlCleanupParser(); +} + +imageObj *KmlRenderer::createImage(int, int, outputFormatObj *, colorObj *) { + return NULL; +} + +int KmlRenderer::saveImage(imageObj *, FILE *fp, outputFormatObj *format) { + /* -------------------------------------------------------------------- */ + /* Write out the document. */ + /* -------------------------------------------------------------------- */ + + int bufSize = 0; + xmlChar *buf = NULL; + msIOContext *context = NULL; + int chunkSize = 4096; + int bZip = MS_FALSE; + + if (msIO_needBinaryStdout() == MS_FAILURE) + return MS_FAILURE; + + xmlDocDumpFormatMemoryEnc(XmlDoc, &buf, &bufSize, "UTF-8", 1); + + if (format && format->driver && strcasecmp(format->driver, "kmz") == 0) { + bZip = MS_TRUE; + } + + if (bZip) { + VSILFILE *fpZip; + int bytes_read; + char buffer[1024]; + char *zip_filename = NULL; + void *hZip = NULL; + + const char *timestamp; + timestamp = msGetOutputFormatOption(format, "TIMESTAMP", "NOW"); + char **papszOptions = nullptr; + papszOptions = CSLAddNameValue(papszOptions, "TIMESTAMP", timestamp); + + zip_filename = msTmpFile(NULL, NULL, "/vsimem/kmlzip/", "kmz"); + hZip = CPLCreateZip(zip_filename, NULL); + CPLCreateFileInZip(hZip, "mapserver.kml", papszOptions); + for (int i = 0; i < bufSize; i += chunkSize) { + int size = chunkSize; + if (i + size > bufSize) + size = bufSize - i; + CPLWriteFileInZip(hZip, buf + i, size); + } + CPLCloseFileInZip(hZip); + CPLCloseZip(hZip); + CSLDestroy(papszOptions); + + context = msIO_getHandler(fp); + fpZip = VSIFOpenL(zip_filename, "r"); + + while ((bytes_read = VSIFReadL(buffer, 1, sizeof(buffer), fpZip)) > 0) { + if (context) + msIO_contextWrite(context, buffer, bytes_read); + else + msIO_fwrite(buffer, 1, bytes_read, fp); + } + VSIFCloseL(fpZip); + msFree(zip_filename); + xmlFree(buf); + return (MS_SUCCESS); + } + + context = msIO_getHandler(fp); + + for (int i = 0; i < bufSize; i += chunkSize) { + int size = chunkSize; + if (i + size > bufSize) + size = bufSize - i; + + if (context) + msIO_contextWrite(context, buf + i, size); + else + msIO_fwrite(buf + i, 1, size, fp); + } + + xmlFree(buf); + + return (MS_SUCCESS); +} + +/************************************************************************/ +/* processLayer */ +/* */ +/* Set parameters that make sense to a kml output. */ +/************************************************************************/ +void KmlRenderer::processLayer(layerObj *layer, outputFormatObj *format) { + int i; + const char *asRaster = NULL; + int nMaxFeatures = -1; + const char *pszTmp; + char szTmp[10]; + + if (!layer) + return; + + /*turn of labelcache*/ + layer->labelcache = MS_OFF; + + /*if there are labels we want the coordinates to + be the center of the element.*/ + for (i = 0; i < layer->numclasses; i++) + if (layer->_class[i]->numlabels > 0) + layer->_class[i]->labels[0]->position = MS_XY; + + /*we do not want to draw multiple styles. + the new rendering architecture does not allow + to know if we are dealing with a multi-style. + So here we remove all styles beside the first one*/ + + for (i = 0; i < layer->numclasses; i++) { + while (layer->_class[i]->numstyles > 1) + msDeleteStyle(layer->_class[i], layer->_class[i]->numstyles - 1); + } + + /*if layer has a metadata KML_OUTPUTASRASTER set to true, add a processing + directive to use an agg driver*/ + asRaster = msLookupHashTable(&layer->metadata, "kml_outputasraster"); + if (!asRaster) + asRaster = + msLookupHashTable(&(layer->map->web.metadata), "kml_outputasraster"); + if (asRaster && + (strcasecmp(asRaster, "true") == 0 || strcasecmp(asRaster, "yes") == 0)) + msLayerAddProcessing(layer, "RENDERER=png24"); + + /*set a maxfeaturestodraw, if not already set*/ + + pszTmp = msLookupHashTable(&layer->metadata, "maxfeaturestodraw"); + if (pszTmp) + nMaxFeatures = atoi(pszTmp); + else { + pszTmp = msLookupHashTable(&layer->map->web.metadata, "maxfeaturestodraw"); + if (pszTmp) + nMaxFeatures = atoi(pszTmp); + } + if (nMaxFeatures < 0 && format) + nMaxFeatures = + atoi(msGetOutputFormatOption(format, "maxfeaturestodraw", "-1")); + + if (nMaxFeatures < 0 && format) { + snprintf(szTmp, sizeof(szTmp), "%d", KML_MAXFEATURES_TODRAW); + msSetOutputFormatOption(format, "maxfeaturestodraw", szTmp); + } +} + +/************************************************************************/ +/* getLayerName */ +/* */ +/* Internal utility function to build name used for the layer. */ +/************************************************************************/ +char *KmlRenderer::getLayerName(layerObj *layer) { + char stmp[20]; + const char *name = NULL; + ; + + if (!layer) + return NULL; + + name = msLookupHashTable(&layer->metadata, "ows_name"); + if (name && strlen(name) > 0) + return msStrdup(name); + + if (layer->name && strlen(layer->name) > 0) + return msStrdup(layer->name); + + sprintf(stmp, "Layer%d", layer->index); + return msStrdup(stmp); +} + +const char *KmlRenderer::getAliasName(layerObj *lp, char *pszItemName, + const char *namespaces) { + const char *pszAlias = NULL; + if (lp && pszItemName && strlen(pszItemName) > 0) { + char szTmp[256]; + snprintf(szTmp, sizeof(szTmp), "%s_alias", pszItemName); + pszAlias = msOWSLookupMetadata(&(lp->metadata), namespaces, szTmp); + } + return pszAlias; +} + +int KmlRenderer::startNewLayer(imageObj *img, layerObj *layer) { + char *layerName = NULL; + const char *value = NULL; + + LayerNode = xmlNewNode(NULL, BAD_CAST "Folder"); + + layerName = getLayerName(layer); + xmlNewChild(LayerNode, NULL, BAD_CAST "name", BAD_CAST layerName); + msFree(layerName); + + const char *layerVisibility = layer->status != MS_OFF ? "1" : "0"; + xmlNewChild(LayerNode, NULL, BAD_CAST "visibility", BAD_CAST layerVisibility); + + const char *layerDsiplayFolder = + msLookupHashTable(&(layer->metadata), "kml_folder_display"); + if (layerDsiplayFolder == NULL) + layerDsiplayFolder = + msLookupHashTable(&(layer->map->web.metadata), "kml_folder_display"); + if (!layerDsiplayFolder || strlen(layerDsiplayFolder) <= 0) { + xmlNewChild(LayerNode, NULL, BAD_CAST "styleUrl", + BAD_CAST "#LayerFolder_check"); + } + + else { + if (strcasecmp(layerDsiplayFolder, "checkHideChildren") == 0) + xmlNewChild(LayerNode, NULL, BAD_CAST "styleUrl", + BAD_CAST "#LayerFolder_checkHideChildren"); + else if (strcasecmp(layerDsiplayFolder, "checkOffOnly") == 0) + xmlNewChild(LayerNode, NULL, BAD_CAST "styleUrl", + BAD_CAST "#LayerFolder_checkOffOnly"); + else if (strcasecmp(layerDsiplayFolder, "radioFolder") == 0) + xmlNewChild(LayerNode, NULL, BAD_CAST "styleUrl", + BAD_CAST "#LayerFolder_radioFolder"); + else + xmlNewChild(LayerNode, NULL, BAD_CAST "styleUrl", + BAD_CAST "#LayerFolder_check"); + } + + /*Init few things on the first layer*/ + if (FirstLayer) { + FirstLayer = MS_FALSE; + map = layer->map; + + if (layer->map->mappath) + snprintf(MapPath, sizeof(MapPath), "%s", layer->map->mappath); + + /*First rendered layer - check mapfile projection*/ + checkProjection(layer->map); + + /*check for image path and image url*/ + if (layer->map->debug && + (layer->map->web.imageurl == NULL || layer->map->web.imagepath == NULL)) + msDebug("KmlRenderer::startNewLayer: imagepath and imageurl should be " + "set in the web object\n"); + + /*map rect for ground overlay*/ + MapExtent = layer->map->extent; + MapCellsize = layer->map->cellsize; + BgColor = layer->map->imagecolor; + + xmlNewChild(DocNode, NULL, BAD_CAST "name", BAD_CAST layer->map->name); + aggFormat = msSelectOutputFormat(layer->map, "png24"); + aggFormat->transparent = MS_TRUE; + } + + currentLayer = layer; + + if (!msLayerIsOpen(layer)) { + if (msLayerOpen(layer) != MS_SUCCESS) { + msSetError(MS_MISCERR, "msLayerOpen failed", + "KmlRenderer::startNewLayer"); + return MS_FAILURE; + } + } + + /*pre process the layer to set things that make sense for kml output*/ + if (img) + processLayer(layer, img->format); + else + processLayer(layer, NULL); + + if (msLookupHashTable(&layer->metadata, "kml_description")) + pszLayerDescMetadata = + msLookupHashTable(&layer->metadata, "kml_description"); + else if (msLookupHashTable(&layer->metadata, "ows_description")) + pszLayerDescMetadata = + msLookupHashTable(&layer->metadata, "ows_description"); + + value = msLookupHashTable(&layer->metadata, "kml_include_items"); + if (!value) + value = msLookupHashTable(&layer->metadata, "ows_include_items"); + if (value) + papszLayerIncludeItems = msStringSplit(value, ',', &nIncludeItems); + + value = msLookupHashTable(&layer->metadata, "kml_exclude_items"); + if (!value) + value = msLookupHashTable(&layer->metadata, "ows_exclude_items"); + if (value) + papszLayerExcludeItems = msStringSplit(value, ',', &nExcludeItems); + + if (msLookupHashTable(&layer->metadata, "kml_name_item")) + pszLayerNameAttributeMetadata = + msLookupHashTable(&layer->metadata, "kml_name_item"); + + /*get all attributes*/ + if (msLayerWhichItems(layer, MS_TRUE, NULL) != MS_SUCCESS) { + return MS_FAILURE; + } + + NumItems = layer->numitems; + if (NumItems) { + Items = (char **)msSmallCalloc(NumItems, sizeof(char *)); + for (int i = 0; i < NumItems; i++) + Items[i] = msStrdup(layer->items[i]); + } + + const char *elevationAttribute = + msLookupHashTable(&layer->metadata, "kml_elevation_attribute"); + if (elevationAttribute) { + mElevationFromAttribute = true; + for (int i = 0; i < layer->numitems; ++i) { + if (strcasecmp(layer->items[i], elevationAttribute) == 0) { + mElevationAttributeIndex = i; + } + } + } + + setupRenderingParams(&layer->metadata); + return MS_SUCCESS; +} + +int KmlRenderer::closeNewLayer(imageObj *, layerObj *) { + flushPlacemark(); + + xmlAddChild(DocNode, LayerNode); + + if (Items) { + msFreeCharArray(Items, NumItems); + Items = NULL; + NumItems = 0; + } + + if (pszLayerDescMetadata) + pszLayerDescMetadata = NULL; + if (pszLayerNameAttributeMetadata) + pszLayerNameAttributeMetadata = NULL; + + if (papszLayerIncludeItems && nIncludeItems > 0) + msFreeCharArray(papszLayerIncludeItems, nIncludeItems); + papszLayerIncludeItems = NULL; + + if (papszLayerExcludeItems && nExcludeItems > 0) + msFreeCharArray(papszLayerExcludeItems, nExcludeItems); + papszLayerExcludeItems = NULL; + + return MS_SUCCESS; +} + +int KmlRenderer::mergeRasterBuffer(imageObj *image, rasterBufferObj *rb) { + assert(rb && rb->type == MS_BUFFER_BYTE_RGBA); + char *tmpFileName = NULL; + char *tmpUrl = NULL; + FILE *tmpFile = NULL; + + tmpFileName = msTmpFile(NULL, MapPath, image->imagepath, "png"); + tmpFile = fopen(tmpFileName, "wb"); + if (tmpFile) { + + if (!aggFormat->vtable) + msInitializeRendererVTable(aggFormat); + + msSaveRasterBuffer(map, rb, tmpFile, aggFormat); + tmpUrl = msStrdup(image->imageurl); + tmpUrl = msStringConcatenate(tmpUrl, (char *)(msGetBasename(tmpFileName))); + tmpUrl = msStringConcatenate(tmpUrl, ".png"); + + createGroundOverlayNode(LayerNode, tmpUrl, currentLayer); + msFree(tmpFileName); + msFree(tmpUrl); + fclose(tmpFile); + return MS_SUCCESS; + } else { + msSetError(MS_IOERR, "Failed to create file for kml overlay", + "KmlRenderer::mergeRasterBuffer()"); + return MS_FAILURE; + } +} + +void KmlRenderer::setupRenderingParams(hashTableObj *layerMetadata) { + AltitudeMode = 0; + Extrude = 0; + Tessellate = 0; + + const char *altitudeModeVal = + msLookupHashTable(layerMetadata, "kml_altitudeMode"); + if (altitudeModeVal) { + if (strcasecmp(altitudeModeVal, "absolute") == 0) + AltitudeMode = absolute; + else if (strcasecmp(altitudeModeVal, "relativeToGround") == 0) + AltitudeMode = relativeToGround; + else if (strcasecmp(altitudeModeVal, "clampToGround") == 0) + AltitudeMode = clampToGround; + } + + const char *extrudeVal = msLookupHashTable(layerMetadata, "kml_extrude"); + if (altitudeModeVal) { + Extrude = atoi(extrudeVal); + } + + const char *tessellateVal = + msLookupHashTable(layerMetadata, "kml_tessellate"); + if (tessellateVal) { + Tessellate = atoi(tessellateVal); + } +} + +int KmlRenderer::checkProjection(mapObj *map) { + projectionObj *projection = &map->projection; + if (projection && projection->numargs > 0 && + msProjIsGeographicCRS(projection)) { + return MS_SUCCESS; + } else { + char epsg_string[100]; + rectObj sRect; + projectionObj out; + + /* for layer the do not have any projection set, set them with the current + map projection*/ + if (projection && projection->numargs > 0) { + layerObj *lp = NULL; + int i = 0; + char *pszMapProjectString = msGetProjectionString(projection); + if (pszMapProjectString) { + for (i = 0; i < map->numlayers; i++) { + lp = GET_LAYER(map, i); + if (lp->projection.numargs == 0 && lp->transform == MS_TRUE) { + msFreeProjection(&lp->projection); + msLoadProjectionString(&lp->projection, pszMapProjectString); + } + } + msFree(pszMapProjectString); + } + } + strcpy(epsg_string, "epsg:4326"); + msInitProjection(&out); + msProjectionInheritContextFrom(&out, projection); + msLoadProjectionString(&out, epsg_string); + + sRect = map->extent; + msProjectRect(projection, &out, &sRect); + msFreeProjectionExceptContext(projection); + msLoadProjectionString(projection, epsg_string); + + /*change also units and extents*/ + map->extent = sRect; + map->units = MS_DD; + + if (map->debug) + msDebug("KmlRenderer::checkProjection: Mapfile projection set to " + "epsg:4326\n"); + + return MS_SUCCESS; + } +} + +xmlNodePtr KmlRenderer::createPlacemarkNode(xmlNodePtr parentNode, + char *styleUrl) { + xmlNodePtr placemarkNode = + xmlNewChild(parentNode, NULL, BAD_CAST "Placemark", NULL); + /*always add a name. It will be replaced by a text value if available*/ + char tmpid[100]; + char *stmp = NULL, *layerName = NULL; + if (CurrentShapeName && strlen(CurrentShapeName) > 0) { + xmlNewChild(placemarkNode, NULL, BAD_CAST "name", + BAD_CAST CurrentShapeName); + } else { + sprintf(tmpid, ".%d", CurrentShapeIndex); + layerName = getLayerName(currentLayer); + stmp = msStringConcatenate(stmp, layerName); + stmp = msStringConcatenate(stmp, tmpid); + xmlNewChild(placemarkNode, NULL, BAD_CAST "name", BAD_CAST stmp); + } + msFree(layerName); + msFree(stmp); + if (styleUrl) + xmlNewChild(placemarkNode, NULL, BAD_CAST "styleUrl", BAD_CAST styleUrl); + + return placemarkNode; +} + +void KmlRenderer::renderLine(imageObj *, shapeObj *p, strokeStyleObj *style) { + if (p->numlines == 0) + return; + + if (PlacemarkNode == NULL) + PlacemarkNode = createPlacemarkNode(LayerNode, NULL); + + if (!PlacemarkNode) + return; + + addLineStyleToList(style); + SymbologyFlag[Line] = 1; + + /*p->index > CurrentDrawnShapeIndexneed to be reviewd. Added since the height + level code caches shapes when rendering lines*/ + if (CurrentDrawnShapeIndex == -1 || p->index > CurrentDrawnShapeIndex) { + xmlNodePtr geomNode = getGeomParentNode("LineString"); + addAddRenderingSpecifications(geomNode); + addCoordsNode(geomNode, p->line[0].point, p->line[0].numpoints); + + /* more than one line => MultiGeometry*/ + if (p->numlines > 1) { + geomNode = getGeomParentNode("LineString"); // returns MultiGeom Node + for (int i = 1; i < p->numlines; i++) { + xmlNodePtr lineStringNode = + xmlNewChild(geomNode, NULL, BAD_CAST "LineString", NULL); + addAddRenderingSpecifications(lineStringNode); + addCoordsNode(lineStringNode, p->line[i].point, p->line[i].numpoints); + } + } + + CurrentDrawnShapeIndex = p->index; + } +} + +void KmlRenderer::renderPolygon(imageObj *, shapeObj *p, colorObj *color) { + if (PlacemarkNode == NULL) + PlacemarkNode = createPlacemarkNode(LayerNode, NULL); + + if (!PlacemarkNode) + return; + + memcpy(&PolygonColor, color, sizeof(colorObj)); + SymbologyFlag[Polygon] = 1; + + if (p->index != CurrentDrawnShapeIndex) { + + xmlNodePtr geomParentNode = getGeomParentNode("Polygon"); + + for (int i = 0; i < p->numlines; i++) { + xmlNodePtr bdryNode = NULL; + + if (i == 0) /* __TODO__ check ring order*/ + bdryNode = + xmlNewChild(geomParentNode, NULL, BAD_CAST "outerBoundaryIs", NULL); + else + bdryNode = + xmlNewChild(geomParentNode, NULL, BAD_CAST "innerBoundaryIs", NULL); + + xmlNodePtr ringNode = + xmlNewChild(bdryNode, NULL, BAD_CAST "LinearRing", NULL); + addAddRenderingSpecifications(ringNode); + addCoordsNode(ringNode, p->line[i].point, p->line[i].numpoints); + } + + CurrentDrawnShapeIndex = p->index; + } +} + +void KmlRenderer::addCoordsNode(xmlNodePtr parentNode, pointObj *pts, + int numPts) { + char lineBuf[128]; + + xmlNodePtr coordsNode = + xmlNewChild(parentNode, NULL, BAD_CAST "coordinates", NULL); + xmlNodeAddContent(coordsNode, BAD_CAST "\n"); + + for (int i = 0; i < numPts; i++) { + if (mElevationFromAttribute) { + sprintf(lineBuf, "\t%.8f,%.8f,%.8f\n", pts[i].x, pts[i].y, + mCurrentElevationValue); + } else if (AltitudeMode == relativeToGround || AltitudeMode == absolute) { + sprintf(lineBuf, "\t%.8f,%.8f,%.8f\n", pts[i].x, pts[i].y, pts[i].z); + } else + sprintf(lineBuf, "\t%.8f,%.8f\n", pts[i].x, pts[i].y); + + xmlNodeAddContent(coordsNode, BAD_CAST lineBuf); + } + xmlNodeAddContent(coordsNode, BAD_CAST "\t"); +} + +void KmlRenderer::renderGlyphs(imageObj *, const textSymbolObj *ts, + colorObj *clr, colorObj * /*oc*/, int /*ow*/) { + if (ts->annotext == NULL || ts->textpath->numglyphs == 0) + return; + + if (PlacemarkNode == NULL) + PlacemarkNode = createPlacemarkNode(LayerNode, NULL); + + if (!PlacemarkNode) + return; + + memcpy(&LabelColor, clr, sizeof(colorObj)); + SymbologyFlag[Label] = 1; + + /*there is alaws a default name (layer.shapeid). Replace it*/ + for (xmlNodePtr node = PlacemarkNode->children; node; node = node->next) { + if (node->type != XML_ELEMENT_NODE) + continue; + + if (strcmp((char *)node->name, "name") == 0) { + xmlNodeSetContent(node, BAD_CAST ts->annotext); + break; + } + } + + /*xmlNewChild(PlacemarkNode, NULL, BAD_CAST "name", BAD_CAST text);*/ + + xmlNodePtr geomNode = getGeomParentNode("Point"); + addAddRenderingSpecifications(geomNode); + + pointObj pt; + pt.x = ts->textpath->glyphs[0].pnt.x; + pt.y = ts->textpath->glyphs[0].pnt.y; + pt.z = 0.0; + addCoordsNode(geomNode, &pt, 1); +} + +void KmlRenderer::addAddRenderingSpecifications(xmlNodePtr node) { + /* + 0 + 0 + clampToGround + */ + + if (Extrude) + xmlNewChild(node, NULL, BAD_CAST "extrude", BAD_CAST "1"); + + if (Tessellate) + xmlNewChild(node, NULL, BAD_CAST "tessellate", BAD_CAST "1"); + + if (AltitudeMode == absolute) + xmlNewChild(node, NULL, BAD_CAST "altitudeMode", BAD_CAST "absolute"); + else if (AltitudeMode == relativeToGround) + xmlNewChild(node, NULL, BAD_CAST "altitudeMode", + BAD_CAST "relativeToGround"); + else if (AltitudeMode == clampToGround) + xmlNewChild(node, NULL, BAD_CAST "altitudeMode", BAD_CAST "clampToGround"); +} + +imageObj *agg2CreateImage(int width, int height, outputFormatObj *format, + colorObj *bg); + +int KmlRenderer::createIconImage(char *fileName, symbolObj *symbol, + symbolStyleObj *symstyle) { + pointObj p; + int status; + + imageObj *tmpImg = NULL; + + tmpImg = + agg2CreateImage((int)(symbol->sizex * symstyle->scale), + (int)(symbol->sizey * symstyle->scale), aggFormat, NULL); + tmpImg->format = aggFormat; + if (!aggFormat->vtable) + msInitializeRendererVTable(aggFormat); + + p.x = symbol->sizex * symstyle->scale / 2; + p.y = symbol->sizey * symstyle->scale / 2; + p.z = 0.0; + + status = msDrawMarkerSymbol(map, tmpImg, &p, symstyle->style, 1); + if (status != MS_SUCCESS) + return status; + + return msSaveImage(map, tmpImg, fileName); +} + +void KmlRenderer::renderSymbol(imageObj *img, double x, double y, + symbolObj *symbol, symbolStyleObj *style) { + if (PlacemarkNode == NULL) + PlacemarkNode = createPlacemarkNode(LayerNode, NULL); + + if (!PlacemarkNode) + return; + + snprintf(SymbolUrl, sizeof(SymbolUrl), "%s", + lookupSymbolUrl(img, symbol, style)); + SymbologyFlag[Symbol] = 1; + + xmlNodePtr geomNode = getGeomParentNode("Point"); + addAddRenderingSpecifications(geomNode); + + pointObj pt; + pt.x = x; + pt.y = y; + pt.z = 0.0; + addCoordsNode(geomNode, &pt, 1); +} + +void KmlRenderer::renderPixmapSymbol(imageObj *img, double x, double y, + symbolObj *symbol, symbolStyleObj *style) { + renderSymbol(img, x, y, symbol, style); +} + +void KmlRenderer::renderVectorSymbol(imageObj *img, double x, double y, + symbolObj *symbol, symbolStyleObj *style) { + renderSymbol(img, x, y, symbol, style); +} + +void KmlRenderer::renderEllipseSymbol(imageObj *img, double x, double y, + symbolObj *symbol, + symbolStyleObj *style) { + renderSymbol(img, x, y, symbol, style); +} + +void KmlRenderer::renderTruetypeSymbol(imageObj *img, double x, double y, + symbolObj *symbol, + symbolStyleObj *style) { + renderSymbol(img, x, y, symbol, style); +} + +xmlNodePtr KmlRenderer::createGroundOverlayNode(xmlNodePtr parentNode, + char *imageHref, + layerObj *layer) { + /* + + + + GroundOverlay.kml + 7fffffff + 1 + + http://www.google.com/intl/en/images/logo.gif + onInterval + 86400 + 0.75 + + + 37.83234 + 37.832122 + -122.373033 + -122.373724 + 45 + + + + */ + char layerHexColor[32]; + xmlNodePtr groundOverlayNode = + xmlNewChild(parentNode, NULL, BAD_CAST "GroundOverlay", NULL); + char *layerName = getLayerName(layer); + xmlNewChild(groundOverlayNode, NULL, BAD_CAST "name", BAD_CAST layerName); + if (layer->compositer && layer->compositer->opacity > 0 && + layer->compositer->opacity < 100) { + sprintf(layerHexColor, "%02xffffff", + (unsigned int)MS_NINT(layer->compositer->opacity * 2.55)); + xmlNewChild(groundOverlayNode, NULL, BAD_CAST "color", + BAD_CAST layerHexColor); + } else + xmlNewChild(groundOverlayNode, NULL, BAD_CAST "color", BAD_CAST "ffffffff"); + char stmp[20]; + sprintf(stmp, "%d", layer->index); + xmlNewChild(groundOverlayNode, NULL, BAD_CAST "drawOrder", BAD_CAST stmp); + + if (imageHref) { + xmlNodePtr iconNode = + xmlNewChild(groundOverlayNode, NULL, BAD_CAST "Icon", NULL); + xmlNewChild(iconNode, NULL, BAD_CAST "href", BAD_CAST imageHref); + } + + char crdStr[64]; + rectObj mapextent; + if (map->gt.need_geotransform == MS_TRUE) + mapextent = currentLayer->map->saved_extent; + else + mapextent = currentLayer->map->extent; + + xmlNodePtr latLonBoxNode = + xmlNewChild(groundOverlayNode, NULL, BAD_CAST "LatLonBox", NULL); + sprintf(crdStr, "%.8f", mapextent.maxy); + xmlNewChild(latLonBoxNode, NULL, BAD_CAST "north", BAD_CAST crdStr); + + sprintf(crdStr, "%.8f", mapextent.miny); + xmlNewChild(latLonBoxNode, NULL, BAD_CAST "south", BAD_CAST crdStr); + + sprintf(crdStr, "%.8f", mapextent.minx); + xmlNewChild(latLonBoxNode, NULL, BAD_CAST "west", BAD_CAST crdStr); + + sprintf(crdStr, "%.8f", mapextent.maxx); + xmlNewChild(latLonBoxNode, NULL, BAD_CAST "east", BAD_CAST crdStr); + + xmlNewChild(latLonBoxNode, NULL, BAD_CAST "rotation", BAD_CAST "0.0"); + + return groundOverlayNode; +} + +void KmlRenderer::startShape(imageObj *, shapeObj *shape) { + if (PlacemarkNode) + flushPlacemark(); + + CurrentShapeIndex = -1; + CurrentDrawnShapeIndex = -1; + CurrentShapeName = NULL; + + /*should be done at endshape but the plugin architecture does not call + * endshape yet*/ + if (LineStyle) { + msFree(LineStyle); + + LineStyle = NULL; + numLineStyle = 0; + } + + CurrentShapeIndex = shape->index; + if (pszLayerNameAttributeMetadata) { + for (int i = 0; i < currentLayer->numitems; i++) { + if (strcasecmp(currentLayer->items[i], pszLayerNameAttributeMetadata) == + 0 && + shape->values[i]) { + CurrentShapeName = msStrdup(shape->values[i]); + break; + } + } + } + PlacemarkNode = NULL; + GeomNode = NULL; + + DescriptionNode = createDescriptionNode(shape); + + if (mElevationFromAttribute && shape->numvalues > mElevationAttributeIndex && + mElevationAttributeIndex >= 0 && + shape->values[mElevationAttributeIndex]) { + mCurrentElevationValue = atof(shape->values[mElevationAttributeIndex]); + } + + memset(SymbologyFlag, 0, NumSymbologyFlag); +} + +void KmlRenderer::endShape(imageObj *, shapeObj *) { + CurrentShapeIndex = -1; + if (CurrentShapeName) + msFree(CurrentShapeName); + CurrentShapeName = NULL; +} + +xmlNodePtr KmlRenderer::getGeomParentNode(const char *geomName) { + /*we do not need a multi-geometry for point layers*/ + if (currentLayer->type != MS_LAYER_POINT && + currentLayer->type != MS_LAYER_ANNOTATION && GeomNode) { + /*placemark geometry already defined, we need multigeometry node*/ + xmlNodePtr multiGeomNode = xmlNewNode(NULL, BAD_CAST "MultiGeometry"); + xmlAddChild(multiGeomNode, GeomNode); + GeomNode = multiGeomNode; + + xmlNodePtr geomNode = + xmlNewChild(multiGeomNode, NULL, BAD_CAST geomName, NULL); + return geomNode; + } else { + GeomNode = xmlNewNode(NULL, BAD_CAST geomName); + return GeomNode; + } +} + +const char *KmlRenderer::lookupSymbolUrl(imageObj *img, symbolObj *symbol, + symbolStyleObj *symstyle) { + char symbolHexColor[32]; + /* + + */ + + sprintf(symbolHexColor, "%02x%02x%02x%02x", symstyle->style->color.alpha, + symstyle->style->color.blue, symstyle->style->color.green, + symstyle->style->color.red); + snprintf(SymbolName, sizeof(SymbolName), "symbol_%s_%.1f_%s", symbol->name, + symstyle->scale, symbolHexColor); + + const char *symbolUrl = msLookupHashTable(StyleHashTable, SymbolName); + if (!symbolUrl) { + char iconFileName[MS_MAXPATHLEN]; + char iconUrl[MS_MAXPATHLEN]; + + if (img->imagepath) { + char *tmpFileName = msTmpFile(NULL, MapPath, img->imagepath, "png"); + snprintf(iconFileName, sizeof(iconFileName), "%s", tmpFileName); + msFree(tmpFileName); + } else { + sprintf(iconFileName, "symbol_%s_%.1f.%s", symbol->name, symstyle->scale, + "png"); + } + + if (createIconImage(iconFileName, symbol, symstyle) != MS_SUCCESS) { + msSetError(MS_IOERR, "Error creating icon file '%s'", + "KmlRenderer::lookupSymbolStyle()", iconFileName); + return NULL; + } + + if (img->imageurl) + sprintf(iconUrl, "%s%s.%s", img->imageurl, msGetBasename(iconFileName), + "png"); + else + snprintf(iconUrl, sizeof(iconUrl), "%s", iconFileName); + + hashObj *hash = msInsertHashTable(StyleHashTable, SymbolName, iconUrl); + symbolUrl = hash->data; + } + + return symbolUrl; +} + +const char *KmlRenderer::lookupPlacemarkStyle() { + char lineHexColor[32]; + char polygonHexColor[32]; + char labelHexColor[32]; + char *styleName = NULL; + + styleName = msStringConcatenate(styleName, "style"); + + if (SymbologyFlag[Line]) { + /* + + + ffffffff + normal + + + 1 + + */ + + for (int i = 0; i < numLineStyle; i++) { + if (currentLayer && currentLayer->compositer && + currentLayer->compositer->opacity > 0 && + currentLayer->compositer->opacity < 100 && + LineStyle[i].color->alpha == 255) + LineStyle[i].color->alpha = + MS_NINT(currentLayer->compositer->opacity * 2.55); + + sprintf(lineHexColor, "%02x%02x%02x%02x", LineStyle[i].color->alpha, + LineStyle[0].color->blue, LineStyle[i].color->green, + LineStyle[i].color->red); + + char lineStyleName[64]; + snprintf(lineStyleName, sizeof(lineStyleName), "_line_%s_w%.1f", + lineHexColor, LineStyle[i].width); + styleName = msStringConcatenate(styleName, lineStyleName); + } + } + + if (SymbologyFlag[Polygon]) { + /* + + + ffffffff + normal + + + 1 + 1 + + */ + + if (currentLayer && currentLayer->compositer && + currentLayer->compositer->opacity > 0 && + currentLayer->compositer->opacity < 100 && PolygonColor.alpha == 255) + PolygonColor.alpha = MS_NINT(currentLayer->compositer->opacity * 2.55); + sprintf(polygonHexColor, "%02x%02x%02x%02x", PolygonColor.alpha, + PolygonColor.blue, PolygonColor.green, PolygonColor.red); + + char polygonStyleName[64]; + sprintf(polygonStyleName, "_polygon_%s", polygonHexColor); + styleName = msStringConcatenate(styleName, polygonStyleName); + } + + if (SymbologyFlag[Label]) { + /* + + + ffffffff + normal + + + 1 + + */ + + if (currentLayer && currentLayer->compositer && + currentLayer->compositer->opacity > 0 && + currentLayer->compositer->opacity < 100 && LabelColor.alpha == 255) + LabelColor.alpha = MS_NINT(currentLayer->compositer->opacity * 2.55); + sprintf(labelHexColor, "%02x%02x%02x%02x", LabelColor.alpha, + LabelColor.blue, LabelColor.green, LabelColor.red); + + // __TODO__ add label scale + + char labelStyleName[64]; + sprintf(labelStyleName, "_label_%s", labelHexColor); + styleName = msStringConcatenate(styleName, labelStyleName); + } + + if (SymbologyFlag[Symbol]) { + /* + + */ + + /* __TODO__ add label scale */ + + styleName = msStringConcatenate(styleName, "_"); + styleName = msStringConcatenate(styleName, SymbolName); + } + + const char *styleUrl = msLookupHashTable(StyleHashTable, styleName); + if (!styleUrl) { + char *styleValue = NULL; + styleValue = msStringConcatenate(styleValue, "#"); + styleValue = msStringConcatenate(styleValue, styleName); + hashObj *hash = msInsertHashTable(StyleHashTable, styleName, styleValue); + styleUrl = hash->data; + msFree(styleValue); + + /* Insert new Style node into Document node*/ + xmlNodePtr styleNode = xmlNewChild(DocNode, NULL, BAD_CAST "Style", NULL); + xmlNewProp(styleNode, BAD_CAST "id", BAD_CAST styleName); + + if (SymbologyFlag[Polygon]) { + xmlNodePtr polyStyleNode = + xmlNewChild(styleNode, NULL, BAD_CAST "PolyStyle", NULL); + xmlNewChild(polyStyleNode, NULL, BAD_CAST "color", + BAD_CAST polygonHexColor); + } + + if (SymbologyFlag[Line]) { + for (int i = 0; i < numLineStyle; i++) { + xmlNodePtr lineStyleNode = + xmlNewChild(styleNode, NULL, BAD_CAST "LineStyle", NULL); + sprintf(lineHexColor, "%02x%02x%02x%02x", LineStyle[i].color->alpha, + LineStyle[i].color->blue, LineStyle[i].color->green, + LineStyle[i].color->red); + xmlNewChild(lineStyleNode, NULL, BAD_CAST "color", + BAD_CAST lineHexColor); + + char width[16]; + sprintf(width, "%.1f", LineStyle[i].width); + xmlNewChild(lineStyleNode, NULL, BAD_CAST "width", BAD_CAST width); + } + } + + if (SymbologyFlag[Symbol]) { + xmlNodePtr iconStyleNode = + xmlNewChild(styleNode, NULL, BAD_CAST "IconStyle", NULL); + + xmlNodePtr iconNode = + xmlNewChild(iconStyleNode, NULL, BAD_CAST "Icon", NULL); + xmlNewChild(iconNode, NULL, BAD_CAST "href", BAD_CAST SymbolUrl); + + /*char scale[16]; + sprintf(scale, "%.1f", style->scale); + xmlNewChild(iconStyleNode, NULL, BAD_CAST "scale", BAD_CAST scale);*/ + } else { + const char *value = + msLookupHashTable(¤tLayer->metadata, "kml_default_symbol_href"); + if (value && strlen(value) > 0) { + xmlNodePtr iconStyleNode = + xmlNewChild(styleNode, NULL, BAD_CAST "IconStyle", NULL); + + xmlNodePtr iconNode = + xmlNewChild(iconStyleNode, NULL, BAD_CAST "Icon", NULL); + xmlNewChild(iconNode, NULL, BAD_CAST "href", BAD_CAST value); + } + } + + if (SymbologyFlag[Label]) { + xmlNodePtr labelStyleNode = + xmlNewChild(styleNode, NULL, BAD_CAST "LabelStyle", NULL); + xmlNewChild(labelStyleNode, NULL, BAD_CAST "color", + BAD_CAST labelHexColor); + + /*char scale[16]; + sprintf(scale, "%.1f", style->scale); + xmlNewChild(iconStyleNode, NULL, BAD_CAST "scale", BAD_CAST scale);*/ + } + } + + if (styleName) + msFree(styleName); + + return styleUrl; +} + +void KmlRenderer::flushPlacemark() { + if (PlacemarkNode) { + const char *styleUrl = lookupPlacemarkStyle(); + xmlNewChild(PlacemarkNode, NULL, BAD_CAST "styleUrl", BAD_CAST styleUrl); + + if (DescriptionNode) + xmlAddChild(PlacemarkNode, DescriptionNode); + + if (GeomNode) + xmlAddChild(PlacemarkNode, GeomNode); + } +} + +xmlNodePtr KmlRenderer::createDescriptionNode(shapeObj *shape) { + /* + + + + */ + + /*description nodes for vector layers: + - if kml_description is set, use it + - if not, dump the attributes */ + + if (pszLayerDescMetadata) { + char *pszTmp = NULL; + char *pszTmpDesc = NULL; + size_t bufferSize = 0; + pszTmpDesc = msStrdup(pszLayerDescMetadata); + + for (int i = 0; i < currentLayer->numitems; i++) { + bufferSize = strlen(currentLayer->items[i]) + 3; + pszTmp = (char *)msSmallMalloc(bufferSize); + snprintf(pszTmp, bufferSize, "%%%s%%", currentLayer->items[i]); + if (strcasestr(pszTmpDesc, pszTmp)) + pszTmpDesc = + msCaseReplaceSubstring(pszTmpDesc, pszTmp, shape->values[i]); + msFree(pszTmp); + } + xmlNodePtr descriptionNode = xmlNewNode(NULL, BAD_CAST "description"); + xmlNodeAddContent(descriptionNode, BAD_CAST pszTmpDesc); + msFree(pszTmpDesc); + return descriptionNode; + } else if ((papszLayerIncludeItems && nIncludeItems > 0) || + (papszLayerExcludeItems && nExcludeItems > 0)) { + /* -------------------------------------------------------------------- */ + /* preferred way is to use the ExtendedData tag (#3728) */ + /* http://code.google.com/apis/kml/documentation/extendeddata.html */ + /* -------------------------------------------------------------------- */ + + xmlNodePtr extendedDataNode = xmlNewNode(NULL, BAD_CAST "ExtendedData"); + xmlNodePtr dataNode = NULL; + const char *pszAlias = NULL; + int bIncludeAll = MS_FALSE; + + if (papszLayerIncludeItems && nIncludeItems == 1 && + strcasecmp(papszLayerIncludeItems[0], "all") == 0) + bIncludeAll = MS_TRUE; + + for (int i = 0; i < currentLayer->numitems; i++) { + int j = 0, k = 0; + + /*TODO optimize to calculate this only once per layer*/ + for (j = 0; j < nIncludeItems; j++) { + if (strcasecmp(currentLayer->items[i], papszLayerIncludeItems[j]) == 0) + break; + } + if (j < nIncludeItems || bIncludeAll) { + if (papszLayerExcludeItems && nExcludeItems > 0) { + for (k = 0; k < nExcludeItems; k++) { + if (strcasecmp(currentLayer->items[i], papszLayerExcludeItems[k]) == + 0) + break; + } + } + if (nExcludeItems == 0 || k == nExcludeItems) { + dataNode = xmlNewNode(NULL, BAD_CAST "Data"); + xmlNewProp(dataNode, BAD_CAST "name", + BAD_CAST currentLayer->items[i]); + pszAlias = getAliasName(currentLayer, currentLayer->items[i], "GO"); + if (pszAlias) + xmlNewChild(dataNode, NULL, BAD_CAST "displayName", + BAD_CAST pszAlias); + else + xmlNewChild(dataNode, NULL, BAD_CAST "displayName", + BAD_CAST currentLayer->items[i]); + if (shape->values[i] && strlen(shape->values[i])) + xmlNewChild(dataNode, NULL, BAD_CAST "value", + BAD_CAST shape->values[i]); + else + xmlNewChild(dataNode, NULL, BAD_CAST "value", NULL); + xmlAddChild(extendedDataNode, dataNode); + } + } + } + + return extendedDataNode; + } + + return NULL; +} + +void KmlRenderer::addLineStyleToList(strokeStyleObj *style) { + /*actually this is not necessary. kml only uses the last LineStyle + so we should not bother keeping them all*/ + int i = 0; + for (i = 0; i < numLineStyle; i++) { + if (style->width == LineStyle[i].width && + LineStyle[i].color->alpha == style->color->alpha && + LineStyle[i].color->red == style->color->red && + LineStyle[i].color->green == style->color->green && + LineStyle[i].color->blue == style->color->blue) + break; + } + if (i == numLineStyle) { + numLineStyle++; + if (LineStyle == NULL) + LineStyle = (strokeStyleObj *)msSmallMalloc(sizeof(strokeStyleObj)); + else + LineStyle = (strokeStyleObj *)msSmallRealloc( + LineStyle, sizeof(strokeStyleObj) * numLineStyle); + + memcpy(&LineStyle[numLineStyle - 1], style, sizeof(strokeStyleObj)); + } +} + +#endif diff --git a/src/mapkmlrenderer.h b/src/mapkmlrenderer.h new file mode 100644 index 0000000000..ded9df9f11 --- /dev/null +++ b/src/mapkmlrenderer.h @@ -0,0 +1,186 @@ +/****************************************************************************** + * $Id$ + * + * Project: MapServer + * Purpose: Headers for mapkmlrenderer.cpp Google Earth KML output + * Author: David Kana and the MapServer team + * + ****************************************************************************** + * Copyright (c) 1996-2009 Regents of the University of Minnesota. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + *****************************************************************************/ + +#ifndef MAPKMLRENDERER_H +#define MAPKMLRENDERER_H + +#include "mapserver-config.h" +#if defined(USE_KML) + +#include "mapserver.h" +#include "maplibxml2.h" + +class KmlRenderer { +private: + const char *pszLayerDescMetadata = nullptr; /*if the kml_description is set*/ + char **papszLayerIncludeItems = nullptr; + int nIncludeItems = 0; + char **papszLayerExcludeItems = nullptr; + int nExcludeItems = 0; + const char *pszLayerNameAttributeMetadata = nullptr; + +protected: + // map properties + int Width = 0, Height = 0; + rectObj MapExtent = {0, 0, 0, 0}; + double MapCellsize = 0; + colorObj BgColor = {0, 0, 0, 0}; + char MapPath[MS_MAXPATHLEN] = {0}; + + // xml nodes pointers + xmlDocPtr XmlDoc = nullptr; + xmlNodePtr DocNode = nullptr; + xmlNodePtr LayerNode = nullptr; + xmlNodePtr GroundOverlayNode = nullptr; + + xmlNodePtr PlacemarkNode = nullptr; + xmlNodePtr GeomNode = nullptr; + xmlNodePtr DescriptionNode = nullptr; + + int CurrentShapeIndex = 0; + int CurrentDrawnShapeIndex = 0; + char *CurrentShapeName = nullptr; + char **Items = nullptr; + int NumItems = 0; + int DumpAttributes = 0; + + // placemark symbology + hashTableObj *StyleHashTable = nullptr; + + colorObj LabelColor = {0, 0, 0, 0}; + strokeStyleObj *LineStyle = nullptr; + int numLineStyle = 0; + colorObj PolygonColor = {0, 0, 0, 0}; + + char SymbolName[128] = {0}; + char SymbolUrl[128] = {0}; + + enum { NumSymbologyFlag = 4 }; + char SymbologyFlag[NumSymbologyFlag] = {0, 0, 0, 0}; + + enum symbFlagsEnum { Label, Line, Polygon, Symbol }; + + int FirstLayer = 0; + + mapObj *map = nullptr; + layerObj *currentLayer = nullptr; + + int AltitudeMode = 0; + int Tessellate = 0; + int Extrude = 0; + + enum altitudeModeEnum { + undefined, + clampToGround, + relativeToGround, + absolute + }; + /**True if elevation is taken from a feature attribute*/ + bool mElevationFromAttribute = false; + /**Attribute index of elevation (or -1 if elevation is not attribute driven*/ + int mElevationAttributeIndex = 0; + double mCurrentElevationValue = 0; + + outputFormatObj *aggFormat = nullptr; + +protected: + imageObj *createInternalImage(); + xmlNodePtr createPlacemarkNode(xmlNodePtr parentNode, char *styleUrl); + xmlNodePtr createGroundOverlayNode(xmlNodePtr parentNode, char *imageHref, + layerObj *layer); + xmlNodePtr createDescriptionNode(shapeObj *shape); + + const char *lookupSymbolUrl(imageObj *img, symbolObj *symbol, + symbolStyleObj *style); + + void addCoordsNode(xmlNodePtr parentNode, pointObj *pts, int numPts); + + void setupRenderingParams(hashTableObj *layerMetadata); + void addAddRenderingSpecifications(xmlNodePtr node); + + int checkProjection(mapObj *map); + + int createIconImage(char *fileName, symbolObj *symbol, symbolStyleObj *style); + + void renderSymbol(imageObj *img, double x, double y, symbolObj *symbol, + symbolStyleObj *style); + + ////////////////////////////////////////////////////////////////////////////// + + void renderLineVector(imageObj *img, shapeObj *p, strokeStyleObj *style); + void renderPolygonVector(imageObj *img, shapeObj *p, colorObj *color); + + const char *lookupPlacemarkStyle(); + void flushPlacemark(); + xmlNodePtr getGeomParentNode(const char *geomName); + char *getLayerName(layerObj *layer); + void processLayer(layerObj *layer, outputFormatObj *format); + void addLineStyleToList(strokeStyleObj *style); + const char *getAliasName(layerObj *lp, char *pszItemName, + const char *namespaces); + +public: + KmlRenderer(int width, int height, outputFormatObj *format, + colorObj *color = NULL); + virtual ~KmlRenderer(); + + imageObj *createImage(int width, int height, outputFormatObj *format, + colorObj *bg); + int saveImage(imageObj *img, FILE *fp, outputFormatObj *format); + + int startNewLayer(imageObj *img, layerObj *layer); + int closeNewLayer(imageObj *img, layerObj *layer); + + void startShape(imageObj *img, shapeObj *shape); + void endShape(imageObj *img, shapeObj *shape); + + void renderLine(imageObj *img, shapeObj *p, strokeStyleObj *style); + void renderPolygon(imageObj *img, shapeObj *p, colorObj *color); + + void renderGlyphs(imageObj *img, const textSymbolObj *ts, colorObj *c, + colorObj *oc, int ow); + + // Symbols + void renderPixmapSymbol(imageObj *img, double x, double y, symbolObj *symbol, + symbolStyleObj *style); + void renderVectorSymbol(imageObj *img, double x, double y, symbolObj *symbol, + symbolStyleObj *style); + void renderEllipseSymbol(imageObj *img, double x, double y, symbolObj *symbol, + symbolStyleObj *style); + void renderTruetypeSymbol(imageObj *img, double x, double y, + symbolObj *symbol, symbolStyleObj *style); + + int getTruetypeTextBBox(imageObj *img, char **fonts, int numfonts, + double size, char *string, rectObj *rect, + double **advances); + int mergeRasterBuffer(imageObj *image, rasterBufferObj *rb); +}; + +#endif /* USE_KML */ +#endif diff --git a/src/maplabel.c b/src/maplabel.c new file mode 100644 index 0000000000..35c50844fd --- /dev/null +++ b/src/maplabel.c @@ -0,0 +1,1348 @@ +/****************************************************************************** + * $Id$ + * + * Project: MapServer + * Purpose: Labeling Implementation. + * Author: Steve Lime and the MapServer team. + * + ****************************************************************************** + * Copyright (c) 1996-2005 Regents of the University of Minnesota. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + ****************************************************************************/ + +/* +** maplabel.c: Routines to enable text drawing, BITMAP or TRUETYPE. +*/ + +#include +#include + +#include "mapserver.h" +#include "fontcache.h" + +#include "cpl_vsi.h" +#include "cpl_string.h" + +void initTextPath(textPathObj *ts) { memset(ts, 0, sizeof(*ts)); } + +int WARN_UNUSED msLayoutTextSymbol(mapObj *map, textSymbolObj *ts, + textPathObj *tgret); + +#if defined(USE_EXTENDED_DEBUG) && 0 +static void msDebugTextPath(textSymbolObj *ts) { + int i; + msDebug("text: %s\n", ts->annotext); + if (ts->textpath) { + for (i = 0; i < ts->textpath->numglyphs; i++) { + glyphObj *g = &ts->textpath->glyphs[i]; + msDebug("glyph %d: pos: %f %f\n", g->glyph->key.codepoint, g->pnt.x, + g->pnt.y); + } + } else { + msDebug("no glyphs\n"); + } + msDebug("\n=========================================\n"); +} +#endif + +int msComputeTextPath(mapObj *map, textSymbolObj *ts) { + textPathObj *tgret = msSmallMalloc(sizeof(textPathObj)); + assert(ts->annotext && *ts->annotext); + initTextPath(tgret); + ts->textpath = tgret; + tgret->absolute = 0; + tgret->glyph_size = ts->label->size * ts->scalefactor; + tgret->glyph_size = + MS_MAX(tgret->glyph_size, ts->label->minsize * ts->resolutionfactor); + tgret->glyph_size = MS_NINT( + MS_MIN(tgret->glyph_size, ts->label->maxsize * ts->resolutionfactor)); + tgret->line_height = ceil(tgret->glyph_size * 1.33); + return msLayoutTextSymbol(map, ts, tgret); +} + +void initTextSymbol(textSymbolObj *ts) { memset(ts, 0, sizeof(*ts)); } + +void freeTextPath(textPathObj *tp) { + free(tp->glyphs); + if (tp->bounds.poly) { + free(tp->bounds.poly->point); + free(tp->bounds.poly); + } +} + +void freeTextSymbol(textSymbolObj *ts) { freeTextSymbolEx(ts, MS_TRUE); } + +void freeTextSymbolEx(textSymbolObj *ts, int doFreeLabel) { + if (ts->textpath) { + freeTextPath(ts->textpath); + free(ts->textpath); + } + if (ts->label->numstyles) { + if (ts->style_bounds) { + int i; + for (i = 0; i < ts->label->numstyles; i++) { + if (ts->style_bounds[i]) { + if (ts->style_bounds[i]->poly) { + free(ts->style_bounds[i]->poly->point); + free(ts->style_bounds[i]->poly); + } + free(ts->style_bounds[i]); + } + } + free(ts->style_bounds); + } + } + free(ts->annotext); + if (doFreeLabel && freeLabel(ts->label) == MS_SUCCESS) { + free(ts->label); + } +} + +void msCopyTextPath(textPathObj *dst, textPathObj *src) { + int i; + *dst = *src; + if (src->bounds.poly) { + dst->bounds.poly = msSmallMalloc(sizeof(lineObj)); + dst->bounds.poly->numpoints = src->bounds.poly->numpoints; + dst->bounds.poly->point = + msSmallMalloc(src->bounds.poly->numpoints * sizeof(pointObj)); + for (i = 0; i < src->bounds.poly->numpoints; i++) { + dst->bounds.poly->point[i] = src->bounds.poly->point[i]; + } + } else { + dst->bounds.poly = NULL; + } + if (dst->numglyphs > 0) { + dst->glyphs = msSmallMalloc(dst->numglyphs * sizeof(glyphObj)); + for (i = 0; i < dst->numglyphs; i++) + dst->glyphs[i] = src->glyphs[i]; + } +} + +void msCopyTextSymbol(textSymbolObj *dst, textSymbolObj *src) { + *dst = *src; + MS_REFCNT_INCR(src->label); + dst->annotext = msStrdup(src->annotext); + if (src->textpath) { + dst->textpath = msSmallMalloc(sizeof(textPathObj)); + msCopyTextPath(dst->textpath, src->textpath); + } + if (src->style_bounds) { + int i; + dst->style_bounds = + msSmallCalloc(src->label->numstyles, sizeof(label_bounds *)); + for (i = 0; i < src->label->numstyles; i++) { + if (src->style_bounds[i]) { + dst->style_bounds[i] = msSmallMalloc(sizeof(label_bounds)); + copyLabelBounds(dst->style_bounds[i], src->style_bounds[i]); + } + } + } +} + +static int labelNeedsDeepCopy(labelObj *label) { + int i; + if (label->numbindings > 0) + return MS_TRUE; + for (i = 0; i < label->numstyles; i++) { + if (label->styles[i]->numbindings > 0) { + return MS_TRUE; + } + } + return MS_FALSE; +} + +void msPopulateTextSymbolForLabelAndString(textSymbolObj *ts, labelObj *l, + char *string, double scalefactor, + double resolutionfactor, + label_cache_mode cache) { + if (cache == duplicate_always) { + ts->label = msSmallMalloc(sizeof(labelObj)); + initLabel(ts->label); + msCopyLabel(ts->label, l); + } else if (cache == duplicate_never) { + ts->label = l; + MS_REFCNT_INCR(l); + } else if (cache == duplicate_if_needed && labelNeedsDeepCopy(l)) { + ts->label = msSmallMalloc(sizeof(labelObj)); + initLabel(ts->label); + msCopyLabel(ts->label, l); + } else { + ts->label = l; + MS_REFCNT_INCR(l); + } + ts->resolutionfactor = resolutionfactor; + ts->scalefactor = scalefactor; + ts->annotext = string; /* we take the ownership of the annotation text */ + ts->rotation = l->angle * MS_DEG_TO_RAD; +} + +int msAddLabelGroup(mapObj *map, imageObj *image, layerObj *layer, + int classindex, shapeObj *shape, pointObj *point, + double featuresize) { + int l, s, priority; + labelCacheSlotObj *cacheslot; + + labelCacheMemberObj *cachePtr = NULL; + layerObj *layerPtr = NULL; + classObj *classPtr = NULL; + int numtextsymbols = 0; + textSymbolObj **textsymbols, *ts; + int layerindex = layer->index; + + // We cannot use GET_LAYER here because in drawQuery the drawing may happen + // on a temp layer only. + layerPtr = layer; + classPtr = layer->class[classindex]; + + if (classPtr->numlabels == 0) + return MS_SUCCESS; /* not an error just nothing to do */ + + /* check that the label intersects the layer mask */ + if (layerPtr->mask) { + int maskLayerIdx = msGetLayerIndex(map, layerPtr->mask); + layerObj *maskLayer = GET_LAYER(map, maskLayerIdx); + unsigned char *alphapixptr; + if (maskLayer->maskimage && + MS_IMAGE_RENDERER(maskLayer->maskimage)->supports_pixel_buffer) { + rasterBufferObj rb; + int x, y; + memset(&rb, 0, sizeof(rasterBufferObj)); + if (MS_UNLIKELY(MS_FAILURE == + MS_IMAGE_RENDERER(maskLayer->maskimage) + ->getRasterBufferHandle(maskLayer->maskimage, &rb))) { + return MS_FAILURE; + } + x = MS_NINT(point->x); + y = MS_NINT(point->y); + /* Using label repeatdistance, we might have a point with x/y below 0. See + * #4764 */ + if (x >= 0 && x < (int)rb.width && y >= 0 && y < (int)rb.height) { + assert(rb.type == MS_BUFFER_BYTE_RGBA); + alphapixptr = rb.data.rgba.a + rb.data.rgba.row_step * y + + rb.data.rgba.pixel_step * x; + if (!*alphapixptr) { + /* label point does not intersect mask */ + return MS_SUCCESS; + } + } else { + return MS_SUCCESS; /* label point does not intersect image extent, we + cannot know if it intersects mask, so we discard it + (#5237)*/ + } + } else { + msSetError(MS_MISCERR, + "Layer (%s) references references a mask layer, but the " + "selected renderer does not support them", + "msAddLabelGroup()", layerPtr->name); + return (MS_FAILURE); + } + } + + textsymbols = msSmallMalloc(classPtr->numlabels * sizeof(textSymbolObj *)); + + for (l = 0; l < classPtr->numlabels; l++) { + labelObj *lbl = classPtr->labels[l]; + char *annotext; + if (msGetLabelStatus(map, layerPtr, shape, lbl) == MS_OFF) { + continue; + } + annotext = msShapeGetLabelAnnotation(layerPtr, shape, lbl); + if (!annotext) { + for (s = 0; s < lbl->numstyles; s++) { + if (lbl->styles[s]->_geomtransform.type == MS_GEOMTRANSFORM_LABELPOINT) + break; /* we have a "symbol only label, so we shouldn't skip this + label */ + } + if (s == lbl->numstyles) { + continue; /* no anno text, and no label symbols */ + } + } + ts = msSmallMalloc(sizeof(textSymbolObj)); + initTextSymbol(ts); + msPopulateTextSymbolForLabelAndString( + ts, lbl, annotext, layerPtr->scalefactor, image->resolutionfactor, 1); + + if (annotext && *annotext && lbl->autominfeaturesize && featuresize > 0) { + if (MS_UNLIKELY(MS_FAILURE == msComputeTextPath(map, ts))) { + freeTextSymbol(ts); + free(ts); + return MS_FAILURE; + } + if (featuresize < + (ts->textpath->bounds.bbox.maxx - ts->textpath->bounds.bbox.minx)) { + /* feature is too big to be drawn, skip it */ + freeTextSymbol(ts); + free(ts); + continue; + } + } + textsymbols[numtextsymbols] = ts; + numtextsymbols++; + } + + if (numtextsymbols == 0) { + free(textsymbols); + return MS_SUCCESS; + } + + /* Validate label priority value and get ref on label cache for it */ + priority = + classPtr->labels[0]->priority; /* take priority from the first label */ + if (priority < 1) + priority = 1; + else if (priority > MS_MAX_LABEL_PRIORITY) + priority = MS_MAX_LABEL_PRIORITY; + + cacheslot = &(map->labelcache.slots[priority - 1]); + + if (cacheslot->numlabels == + cacheslot->cachesize) { /* just add it to the end */ + cacheslot->labels = (labelCacheMemberObj *)realloc( + cacheslot->labels, sizeof(labelCacheMemberObj) * + (cacheslot->cachesize + MS_LABELCACHEINCREMENT)); + MS_CHECK_ALLOC(cacheslot->labels, + sizeof(labelCacheMemberObj) * + (cacheslot->cachesize + MS_LABELCACHEINCREMENT), + MS_FAILURE); + cacheslot->cachesize += MS_LABELCACHEINCREMENT; + } + + cachePtr = &(cacheslot->labels[cacheslot->numlabels]); + + cachePtr->layerindex = + layerindex; /* so we can get back to this *raw* data if necessary */ + + cachePtr->classindex = classindex; + + cachePtr->point = *point; /* the actual label point */ + + cachePtr->leaderline = NULL; + cachePtr->leaderbbox = NULL; + + cachePtr->markerid = -1; + + cachePtr->status = MS_FALSE; + + if (layerPtr->type == MS_LAYER_POINT && classPtr->numstyles > 0) { + /* cache the marker placement, it's already on the map */ + /* TO DO: at the moment only checks the bottom style, perhaps should check + * all of them */ + /* #2347: after RFC-24 classPtr->styles could be NULL so we check it */ + double w, h; + if (msGetMarkerSize(map, classPtr->styles[0], &w, &h, + layerPtr->scalefactor) != MS_SUCCESS) + return (MS_FAILURE); + + if (cacheslot->nummarkers == + cacheslot->markercachesize) { /* just add it to the end */ + cacheslot->markers = (markerCacheMemberObj *)realloc( + cacheslot->markers, + sizeof(markerCacheMemberObj) * + (cacheslot->cachesize + MS_LABELCACHEINCREMENT)); + MS_CHECK_ALLOC(cacheslot->markers, + sizeof(markerCacheMemberObj) * + (cacheslot->cachesize + MS_LABELCACHEINCREMENT), + MS_FAILURE); + cacheslot->markercachesize += MS_LABELCACHEINCREMENT; + } + + cacheslot->markers[cacheslot->nummarkers].bounds.minx = (point->x - .5 * w); + cacheslot->markers[cacheslot->nummarkers].bounds.miny = (point->y - .5 * h); + cacheslot->markers[cacheslot->nummarkers].bounds.maxx = + cacheslot->markers[cacheslot->nummarkers].bounds.minx + (w - 1); + cacheslot->markers[cacheslot->nummarkers].bounds.maxy = + cacheslot->markers[cacheslot->nummarkers].bounds.miny + (h - 1); + cacheslot->markers[cacheslot->nummarkers].id = cacheslot->numlabels; + + cachePtr->markerid = cacheslot->nummarkers; + cacheslot->nummarkers++; + } + cachePtr->textsymbols = textsymbols; + cachePtr->numtextsymbols = numtextsymbols; + + cacheslot->numlabels++; + + return (MS_SUCCESS); +} + +int msAddLabel(mapObj *map, imageObj *image, labelObj *label, int layerindex, + int classindex, shapeObj *shape, pointObj *point, + double featuresize, textSymbolObj *ts) { + int i; + labelCacheSlotObj *cacheslot; + labelCacheMemberObj *cachePtr = NULL; + const char *annotext = NULL; + char *annotextToFree = NULL; + layerObj *layerPtr; + classObj *classPtr; + + layerPtr = GET_LAYER(map, layerindex); + assert(layerPtr); + + assert(classindex < layerPtr->numclasses); + classPtr = layerPtr->class[classindex]; + + assert(label); + + if (ts) + annotext = ts->annotext; + else if (shape) { + annotextToFree = msShapeGetLabelAnnotation(layerPtr, shape, label); + annotext = annotextToFree; + } + + if (!annotext) { + /* check if we have a labelpnt style */ + for (i = 0; i < label->numstyles; i++) { + if (label->styles[i]->_geomtransform.type == MS_GEOMTRANSFORM_LABELPOINT) + break; + } + if (i == label->numstyles) { + /* label has no text or marker symbols */ + if (ts) { + freeTextSymbol(ts); + free(ts); + } + return MS_SUCCESS; + } + } + + if (classPtr->leader) { + if (ts && ts->textpath && ts->textpath->absolute) { + msSetError(MS_MISCERR, "LEADERs are not supported on ANGLE FOLLOW labels", + "msAddLabel()"); + return MS_FAILURE; + } + } + /* check that the label intersects the layer mask */ + + if (layerPtr->mask) { + int maskLayerIdx = msGetLayerIndex(map, layerPtr->mask); + layerObj *maskLayer = GET_LAYER(map, maskLayerIdx); + unsigned char *alphapixptr; + if (maskLayer->maskimage && + MS_IMAGE_RENDERER(maskLayer->maskimage)->supports_pixel_buffer) { + rasterBufferObj rb; + memset(&rb, 0, sizeof(rasterBufferObj)); + if (MS_UNLIKELY(MS_FAILURE == + MS_IMAGE_RENDERER(maskLayer->maskimage) + ->getRasterBufferHandle(maskLayer->maskimage, &rb))) { + msFree(annotextToFree); + return MS_FAILURE; + } + assert(rb.type == MS_BUFFER_BYTE_RGBA); + if (point) { + int x = MS_NINT(point->x); + int y = MS_NINT(point->y); + /* Using label repeatdistance, we might have a point with x/y below 0. + * See #4764 */ + if (x >= 0 && x < (int)rb.width && y >= 0 && y < (int)rb.height) { + alphapixptr = rb.data.rgba.a + rb.data.rgba.row_step * y + + rb.data.rgba.pixel_step * x; + if (!*alphapixptr) { + /* label point does not intersect mask */ + if (ts) { + freeTextSymbol(ts); + free(ts); + } + msFree(annotextToFree); + return MS_SUCCESS; + } + } else { + msFree(annotextToFree); + return MS_SUCCESS; /* label point does not intersect image extent, we + cannot know if it intersects mask, so we discard + it (#5237)*/ + } + } else if (ts && ts->textpath) { + int i = 0; + for (i = 0; i < ts->textpath->numglyphs; i++) { + int x = MS_NINT(ts->textpath->glyphs[i].pnt.x); + int y = MS_NINT(ts->textpath->glyphs[i].pnt.y); + if (x >= 0 && x < (int)rb.width && y >= 0 && y < (int)rb.height) { + alphapixptr = rb.data.rgba.a + rb.data.rgba.row_step * y + + rb.data.rgba.pixel_step * x; + if (!*alphapixptr) { + freeTextSymbol(ts); + free(ts); + msFree(annotextToFree); + return MS_SUCCESS; + } + } else { + freeTextSymbol(ts); + free(ts); + msFree(annotextToFree); + return MS_SUCCESS; /* label point does not intersect image extent, + we cannot know if it intersects mask, so we + discard it (#5237)*/ + } + } + } + } else { + msSetError(MS_MISCERR, + "Layer (%s) references references a mask layer, but the " + "selected renderer does not support them", + "msAddLabel()", layerPtr->name); + msFree(annotextToFree); + return (MS_FAILURE); + } + } + + if (!ts) { + ts = msSmallMalloc(sizeof(textSymbolObj)); + initTextSymbol(ts); + msPopulateTextSymbolForLabelAndString(ts, label, annotextToFree, + layerPtr->scalefactor, + image->resolutionfactor, 1); + // annotextToFree = NULL; + } + + if (annotext && label->autominfeaturesize && featuresize > 0) { + if (!ts->textpath) { + if (MS_UNLIKELY(MS_FAILURE == msComputeTextPath(map, ts))) + return MS_FAILURE; + } + if (!ts->textpath) { + return MS_FAILURE; + } + if (featuresize > + (ts->textpath->bounds.bbox.maxx - ts->textpath->bounds.bbox.minx)) { + /* feature is too big to be drawn, skip it */ + freeTextSymbol(ts); + free(ts); + return MS_SUCCESS; + } + } + + /* Validate label priority value and get ref on label cache for it */ + if (label->priority < 1) + label->priority = 1; + else if (label->priority > MS_MAX_LABEL_PRIORITY) + label->priority = MS_MAX_LABEL_PRIORITY; + + cacheslot = &(map->labelcache.slots[label->priority - 1]); + + if (cacheslot->numlabels == + cacheslot->cachesize) { /* just add it to the end */ + cacheslot->labels = (labelCacheMemberObj *)realloc( + cacheslot->labels, sizeof(labelCacheMemberObj) * + (cacheslot->cachesize + MS_LABELCACHEINCREMENT)); + MS_CHECK_ALLOC(cacheslot->labels, + sizeof(labelCacheMemberObj) * + (cacheslot->cachesize + MS_LABELCACHEINCREMENT), + MS_FAILURE); + cacheslot->cachesize += MS_LABELCACHEINCREMENT; + } + + cachePtr = &(cacheslot->labels[cacheslot->numlabels]); + + cachePtr->layerindex = + layerindex; /* so we can get back to this *raw* data if necessary */ + cachePtr->classindex = classindex; + cachePtr->leaderline = NULL; + cachePtr->leaderbbox = NULL; + + /* Store the label point or the label path (Bug #1620) */ + if (point) { + cachePtr->point = *point; /* the actual label point */ + } else { + assert(ts && ts->textpath && ts->textpath->absolute && + ts->textpath->numglyphs > 0); + /* Use the middle point of the labelpath for mindistance calculations */ + cachePtr->point = ts->textpath->glyphs[ts->textpath->numglyphs / 2].pnt; + } + + /* copy the label */ + cachePtr->numtextsymbols = 1; + cachePtr->textsymbols = + (textSymbolObj **)msSmallMalloc(sizeof(textSymbolObj *)); + cachePtr->textsymbols[0] = ts; + cachePtr->markerid = -1; + + cachePtr->status = MS_FALSE; + + if (layerPtr->type == MS_LAYER_POINT && + classPtr->numstyles > + 0) { /* cache the marker placement, it's already on the map */ + double w, h; + + if (cacheslot->nummarkers == + cacheslot->markercachesize) { /* just add it to the end */ + cacheslot->markers = (markerCacheMemberObj *)realloc( + cacheslot->markers, + sizeof(markerCacheMemberObj) * + (cacheslot->cachesize + MS_LABELCACHEINCREMENT)); + MS_CHECK_ALLOC(cacheslot->markers, + sizeof(markerCacheMemberObj) * + (cacheslot->cachesize + MS_LABELCACHEINCREMENT), + MS_FAILURE); + cacheslot->markercachesize += MS_LABELCACHEINCREMENT; + } + + i = cacheslot->nummarkers; + + /* TO DO: at the moment only checks the bottom style, perhaps should check + * all of them */ + /* #2347: after RFC-24 classPtr->styles could be NULL so we check it */ + if (classPtr->styles != NULL) { + if (msGetMarkerSize(map, classPtr->styles[0], &w, &h, + layerPtr->scalefactor) != MS_SUCCESS) + return (MS_FAILURE); + assert(point); + cacheslot->markers[cacheslot->nummarkers].bounds.minx = + (point->x - .5 * w); + cacheslot->markers[cacheslot->nummarkers].bounds.miny = + (point->y - .5 * h); + cacheslot->markers[cacheslot->nummarkers].bounds.maxx = + cacheslot->markers[cacheslot->nummarkers].bounds.minx + (w - 1); + cacheslot->markers[cacheslot->nummarkers].bounds.maxy = + cacheslot->markers[cacheslot->nummarkers].bounds.miny + (h - 1); + cacheslot->markers[i].id = cacheslot->numlabels; + + cachePtr->markerid = i; + + cacheslot->nummarkers++; + } + } + + cacheslot->numlabels++; + + return (MS_SUCCESS); +} + +/* +** Is a label completely in the image, reserving a gutter (in pixels) inside +** image for no labels (effectively making image larger. The gutter can be +** negative in cases where a label has a buffer around it. +*/ +static int labelInImage(int width, int height, lineObj *lpoly, rectObj *bounds, + int gutter) { + int j; + + /* do a bbox test first */ + if (bounds->minx >= gutter && bounds->miny >= gutter && + bounds->maxx < width - gutter && bounds->maxy < height - gutter) { + return MS_TRUE; + } + + if (lpoly) { + for (j = 1; j < lpoly->numpoints; j++) { + if (lpoly->point[j].x < gutter) + return (MS_FALSE); + if (lpoly->point[j].x >= width - gutter) + return (MS_FALSE); + if (lpoly->point[j].y < gutter) + return (MS_FALSE); + if (lpoly->point[j].y >= height - gutter) + return (MS_FALSE); + } + } else { + /* if no poly, then return false as the boundong box intersected */ + return MS_FALSE; + } + + return (MS_TRUE); +} + +void insertRenderedLabelMember(mapObj *map, labelCacheMemberObj *cachePtr) { + if (map->labelcache.num_rendered_members == + map->labelcache.num_allocated_rendered_members) { + if (map->labelcache.num_rendered_members == 0) { + map->labelcache.num_allocated_rendered_members = 50; + } else { + map->labelcache.num_allocated_rendered_members *= 2; + } + map->labelcache.rendered_text_symbols = + msSmallRealloc(map->labelcache.rendered_text_symbols, + map->labelcache.num_allocated_rendered_members * + sizeof(labelCacheMemberObj *)); + } + map->labelcache + .rendered_text_symbols[map->labelcache.num_rendered_members++] = cachePtr; +} + +static inline int testSegmentLabelBBoxIntersection(const rectObj *leaderbbox, + const pointObj *lp1, + const pointObj *lp2, + const label_bounds *test) { + if (msRectOverlap(leaderbbox, &test->bbox)) { + if (test->poly) { + int pp; + for (pp = 1; pp < test->poly->numpoints; pp++) { + if (msIntersectSegments(&(test->poly->point[pp - 1]), + &(test->poly->point[pp]), lp1, + lp2) == MS_TRUE) { + return (MS_FALSE); + } + } + } else { + pointObj tp1 = {0}, tp2 = {0}; + tp1.x = test->bbox.minx; + tp1.y = test->bbox.miny; + tp2.x = test->bbox.minx; + tp2.y = test->bbox.maxy; + if (msIntersectSegments(lp1, lp2, &tp1, &tp2)) + return MS_FALSE; + tp2.x = test->bbox.maxx; + tp2.y = test->bbox.miny; + if (msIntersectSegments(lp1, lp2, &tp1, &tp2)) + return MS_FALSE; + tp1.x = test->bbox.maxx; + tp1.y = test->bbox.maxy; + tp2.x = test->bbox.minx; + tp2.y = test->bbox.maxy; + if (msIntersectSegments(lp1, lp2, &tp1, &tp2)) + return MS_FALSE; + tp2.x = test->bbox.maxx; + tp2.y = test->bbox.miny; + if (msIntersectSegments(lp1, lp2, &tp1, &tp2)) + return MS_FALSE; + } + } + return MS_TRUE; +} + +int msTestLabelCacheLeaderCollision(mapObj *map, pointObj *lp1, pointObj *lp2) { + int p; + rectObj leaderbbox; + leaderbbox.minx = MS_MIN(lp1->x, lp2->x); + leaderbbox.maxx = MS_MAX(lp1->x, lp2->x); + leaderbbox.miny = MS_MIN(lp1->y, lp2->y); + leaderbbox.maxy = MS_MAX(lp1->y, lp2->y); + for (p = 0; p < map->labelcache.num_rendered_members; p++) { + labelCacheMemberObj *curCachePtr = map->labelcache.rendered_text_symbols[p]; + if (msRectOverlap(&leaderbbox, &(curCachePtr->bbox))) { + /* leaderbbox intersects with the curCachePtr's global bbox */ + int t; + for (t = 0; t < curCachePtr->numtextsymbols; t++) { + int s; + textSymbolObj *ts = curCachePtr->textsymbols[t]; + /* check for intersect with textpath */ + if (ts->textpath && + testSegmentLabelBBoxIntersection( + &leaderbbox, lp1, lp2, &ts->textpath->bounds) == MS_FALSE) { + return MS_FALSE; + } + /* check for intersect with label's labelpnt styles */ + if (ts->style_bounds) { + for (s = 0; s < ts->label->numstyles; s++) { + if (ts->label->styles[s]->_geomtransform.type == + MS_GEOMTRANSFORM_LABELPOINT) { + if (testSegmentLabelBBoxIntersection( + &leaderbbox, lp1, lp2, ts->style_bounds[s]) == MS_FALSE) { + return MS_FALSE; + } + } + } + } + } + if (curCachePtr->leaderbbox) { + if (msIntersectSegments(lp1, lp2, &(curCachePtr->leaderline->point[0]), + &(curCachePtr->leaderline->point[1])) == + MS_TRUE) { + return MS_FALSE; + } + } + } + } + return MS_TRUE; +} + +/* msTestLabelCacheCollisions() +** +** Compares label bounds (in *bounds) against labels already drawn and markers +from cache and +** returns MS_FALSE if it collides with another label, or collides with a +marker. +** +** This function is used by the various msDrawLabelCacheXX() implementations. + +int msTestLabelCacheCollisions(mapObj *map, labelCacheMemberObj *cachePtr, +label_bounds *bounds, int current_priority, int current_label); +*/ +int msTestLabelCacheCollisions(mapObj *map, labelCacheMemberObj *cachePtr, + label_bounds *lb, int current_priority, + int current_label) { + labelCacheObj *labelcache = &(map->labelcache); + int i, p, ll; + + /* + * Check against image bounds first + */ + if (!cachePtr->textsymbols[0]->label->partials) { + if (labelInImage(map->width, map->height, lb->poly, &lb->bbox, + labelcache->gutter) == MS_FALSE) { + return MS_FALSE; + } + } + + /* Compare against all rendered markers from this priority level and higher. + ** Labels can overlap their own marker and markers from lower priority levels + */ + for (p = current_priority; p < MS_MAX_LABEL_PRIORITY; p++) { + labelCacheSlotObj *markerslot; + markerslot = &(labelcache->slots[p]); + + for (ll = 0; ll < markerslot->nummarkers; ll++) { + if (!(p == current_priority && + current_label == + markerslot->markers[ll] + .id)) { /* labels can overlap their own marker */ + if (intersectLabelPolygons(NULL, &markerslot->markers[ll].bounds, + lb->poly, &lb->bbox) == MS_TRUE) { + return MS_FALSE; + } + } + } + } + + for (p = 0; p < labelcache->num_rendered_members; p++) { + labelCacheMemberObj *curCachePtr = labelcache->rendered_text_symbols[p]; + if (msRectOverlap(&curCachePtr->bbox, &lb->bbox)) { + for (i = 0; i < curCachePtr->numtextsymbols; i++) { + int j; + textSymbolObj *ts = curCachePtr->textsymbols[i]; + if (ts->textpath && + intersectLabelPolygons(ts->textpath->bounds.poly, + &ts->textpath->bounds.bbox, lb->poly, + &lb->bbox) == MS_TRUE) { + return MS_FALSE; + } + if (ts->style_bounds) { + for (j = 0; j < ts->label->numstyles; j++) { + if (ts->style_bounds[j] && + ts->label->styles[j]->_geomtransform.type == + MS_GEOMTRANSFORM_LABELPOINT) { + if (intersectLabelPolygons(ts->style_bounds[j]->poly, + &ts->style_bounds[j]->bbox, lb->poly, + &lb->bbox)) { + return MS_FALSE; + } + } + } + } + } + } + if (curCachePtr->leaderline) { + if (testSegmentLabelBBoxIntersection( + curCachePtr->leaderbbox, &curCachePtr->leaderline->point[0], + &curCachePtr->leaderline->point[1], lb) == MS_FALSE) { + return MS_FALSE; + } + } + } + return MS_TRUE; +} + +/* utility function to get the rect of a string outside of a rendering loop, + i.e. without going through textpath layouts */ +int msGetStringSize(mapObj *map, labelObj *label, int size, char *string, + rectObj *r) { + textSymbolObj ts; + double lsize = label->size; + initTextSymbol(&ts); + label->size = size; + msPopulateTextSymbolForLabelAndString(&ts, label, msStrdup(string), 1, 1, 0); + if (MS_UNLIKELY(MS_FAILURE == msGetTextSymbolSize(map, &ts, r))) + return MS_FAILURE; + label->size = lsize; + freeTextSymbol(&ts); + return MS_SUCCESS; +} + +int msInitFontSet(fontSetObj *fontset) { + fontset->filename = NULL; + + /* fontset->fonts = NULL; */ + initHashTable(&(fontset->fonts)); + + fontset->numfonts = 0; + fontset->map = NULL; + return (0); +} + +int msFreeFontSet(fontSetObj *fontset) { + if (fontset->filename) + free(fontset->filename); + fontset->filename = NULL; + msFreeHashItems(&(fontset->fonts)); + /* fontset->fonts = NULL; */ + fontset->numfonts = 0; + + return (0); +} + +int msLoadFontSet(fontSetObj *fontset, mapObj *map) { + VSILFILE *stream; + const char *line; + char *path; + char szPath[MS_MAXPATHLEN]; + int i; + int bFullPath = 0; + const char *realpath; + + if (fontset->numfonts != 0) /* already initialized */ + return (0); + + if (!fontset->filename) + return (0); + + fontset->map = (mapObj *)map; + + path = msGetPath(fontset->filename); + + /* fontset->fonts = msCreateHashTable(); // create font hash */ + /* if(!fontset->fonts) { */ + /* msSetError(MS_HASHERR, "Error initializing font hash.", "msLoadFontSet()"); + */ + /* return(-1); */ + /* } */ + + realpath = msBuildPath(szPath, fontset->map->mappath, fontset->filename); + if (!realpath) { + free(path); + return -1; + } + stream = VSIFOpenL(realpath, "rb"); + if (!stream) { + msSetError(MS_IOERR, "Error opening fontset %s.", "msLoadFontset()", + fontset->filename); + free(path); + return (-1); + } + + i = 0; + while ((line = CPLReadLineL(stream)) != + NULL) { /* while there's something to load */ + + if (line[0] == '#' || line[0] == '\n' || line[0] == '\r' || line[0] == ' ') + continue; /* skip comments and blank lines */ + + char alias[64]; + snprintf(alias, sizeof(alias), "%s", line); + char *ptr = strpbrk(alias, " \t"); + if (!ptr) + continue; + *ptr = '\0'; + + const char *file1StartPtr = line + (ptr - alias); + file1StartPtr++; + /* Skip leading spaces */ + while (isspace((int)*file1StartPtr)) + file1StartPtr++; + + if (!(*file1StartPtr) || !(*alias)) + continue; + + char file1[MS_PATH_LENGTH]; + snprintf(file1, sizeof(file1), "%s", file1StartPtr); + /* Remove trailing spaces */ + ptr = file1 + strlen(file1) - 1; + while (ptr >= file1 && isspace((int)*ptr)) { + *ptr = '\0'; + --ptr; + } + + bFullPath = 0; +#if defined(_WIN32) && !defined(__CYGWIN__) + if (file1[0] == '\\' || (strlen(file1) > 1 && (file1[1] == ':'))) + bFullPath = 1; +#else + if (file1[0] == '/') + bFullPath = 1; +#endif + + if (bFullPath) { /* already full path */ + msInsertHashTable(&(fontset->fonts), alias, file1); + } else { + char file2[MS_PATH_LENGTH]; + snprintf(file2, sizeof(file2), "%s%s", path, file1); + /* msInsertHashTable(fontset->fonts, alias, file2); */ + + /* + ** msBuildPath is use here, but if we have to save the fontset file + ** the msBuildPath must be done everywhere the fonts are used and + ** removed here. + */ + msInsertHashTable(&(fontset->fonts), alias, + msBuildPath(szPath, fontset->map->mappath, file2)); + } + + i++; + } + + fontset->numfonts = i; + VSIFCloseL(stream); /* close the file */ + free(path); + + return (0); +} + +int msGetTextSymbolSize(mapObj *map, textSymbolObj *ts, rectObj *r) { + if (!ts->textpath) { + if (MS_UNLIKELY(MS_FAILURE == msComputeTextPath(map, ts))) + return MS_FAILURE; + } + if (!ts->textpath) + return MS_FAILURE; + *r = ts->textpath->bounds.bbox; + return MS_SUCCESS; +} +/* +** Note: All these routines assume a reference point at the LL corner of the +*text. GD's +** bitmapped fonts use UL and this is compensated for. Note the rect is relative +*to the +** LL corner of the text to be rendered, this is first line for TrueType fonts. +*/ + +#define MARKER_SLOP 2 + +pointObj get_metrics(pointObj *p, int position, textPathObj *tp, int ox, int oy, + double rotation, int buffer, label_bounds *bounds) { + pointObj q = {0}; // initialize + double x1 = 0, y1 = 0, x2 = 0, y2 = 0; + double sin_a, cos_a; + double w, h, x, y; + + w = tp->bounds.bbox.maxx - tp->bounds.bbox.minx; + h = tp->bounds.bbox.maxy - tp->bounds.bbox.miny; + + switch (position) { + case MS_UL: + x1 = -w - ox; + y1 = -oy; + break; + case MS_UC: + x1 = -(w / 2.0); + y1 = -oy - MARKER_SLOP; + break; + case MS_UR: + x1 = ox; + y1 = -oy; + break; + case MS_CL: + x1 = -w - ox - MARKER_SLOP; + if (oy > 0 && tp->numlines == 1) + y1 = oy; + else + y1 = (h / 2.0); + break; + case MS_CC: + x1 = -(w / 2.0) + ox; + y1 = (h / 2.0) + oy; + break; + case MS_CR: + x1 = ox + MARKER_SLOP; + if (oy > 0 && tp->numlines == 1) + y1 = oy; + else + y1 = (h / 2.0); + break; + case MS_LL: + x1 = -w - ox; + y1 = h + oy; + break; + case MS_LC: + x1 = -(w / 2.0); + y1 = h + oy + MARKER_SLOP; + break; + case MS_LR: + x1 = ox; + y1 = h + oy; + break; + } + + if (rotation) { + sin_a = sin(rotation); + cos_a = cos(rotation); + + x = x1 - tp->bounds.bbox.minx; + y = tp->bounds.bbox.maxy - y1; + q.x = p->x + (x * cos_a - (y)*sin_a); + q.y = p->y - (x * sin_a + (y)*cos_a); + + if (bounds) { + x2 = x1 - buffer; /* ll */ + y2 = y1 + buffer; + bounds->poly->point[0].x = p->x + (x2 * cos_a - (-y2) * sin_a); + bounds->poly->point[0].y = p->y - (x2 * sin_a + (-y2) * cos_a); + + x2 = x1 - buffer; /* ul */ + y2 = y1 - h - buffer; + bounds->poly->point[1].x = p->x + (x2 * cos_a - (-y2) * sin_a); + bounds->poly->point[1].y = p->y - (x2 * sin_a + (-y2) * cos_a); + + x2 = x1 + w + buffer; /* ur */ + y2 = y1 - h - buffer; + bounds->poly->point[2].x = p->x + (x2 * cos_a - (-y2) * sin_a); + bounds->poly->point[2].y = p->y - (x2 * sin_a + (-y2) * cos_a); + + x2 = x1 + w + buffer; /* lr */ + y2 = y1 + buffer; + bounds->poly->point[3].x = p->x + (x2 * cos_a - (-y2) * sin_a); + bounds->poly->point[3].y = p->y - (x2 * sin_a + (-y2) * cos_a); + + bounds->poly->point[4].x = bounds->poly->point[0].x; + bounds->poly->point[4].y = bounds->poly->point[0].y; + fastComputeBounds(bounds->poly, &bounds->bbox); + } + } else { + q.x = p->x + x1 - tp->bounds.bbox.minx; + q.y = p->y + y1 - tp->bounds.bbox.maxy; + + if (bounds) { + /* no rotation, we only need to return a bbox */ + bounds->poly = NULL; + + bounds->bbox.minx = q.x - buffer; + bounds->bbox.maxy = q.y + buffer + tp->bounds.bbox.maxy; + bounds->bbox.maxx = q.x + w + buffer; + bounds->bbox.miny = bounds->bbox.maxy - h - buffer * 2; + } + } + return (q); +} + +int intersectTextSymbol(textSymbolObj *ts, label_bounds *lb) { + if (ts->textpath && ts->textpath->absolute) { + if (intersectLabelPolygons(lb->poly, &lb->bbox, ts->textpath->bounds.poly, + &ts->textpath->bounds.bbox)) + return MS_TRUE; + } + if (ts->style_bounds) { + int s; + for (s = 0; s < ts->label->numstyles; s++) { + if (ts->style_bounds[s] && + ts->label->styles[s]->_geomtransform.type == + MS_GEOMTRANSFORM_LABELPOINT && + intersectLabelPolygons(lb->poly, &lb->bbox, ts->style_bounds[s]->poly, + &ts->style_bounds[s]->bbox)) + return MS_TRUE; + } + } + return MS_FALSE; +} + +/* +** Variation on msIntersectPolygons. Label polygons aren't like shapefile +*polygons. They +** have no holes, and often do have overlapping parts (i.e. road symbols). +*/ +int intersectLabelPolygons(lineObj *l1, rectObj *r1, lineObj *l2, rectObj *r2) { + int v1, v2; + pointObj *point; + lineObj *p1, *p2, sp1, sp2; + pointObj pnts1[5], pnts2[5]; + + /* STEP 0: check bounding boxes */ + if (!msRectOverlap(r1, r2)) { /* from alans@wunderground.com */ + return (MS_FALSE); + } + if (!l1 && !l2) + return MS_TRUE; + + if (!l1) { + p1 = &sp1; + p1->numpoints = 5; + p1->point = pnts1; + pnts1[0].x = pnts1[1].x = pnts1[4].x = r1->minx; + pnts1[2].x = pnts1[3].x = r1->maxx; + pnts1[0].y = pnts1[3].y = pnts1[4].y = r1->miny; + pnts1[1].y = pnts1[2].y = r1->maxy; + } else { + p1 = l1; + } + if (!l2) { + p2 = &sp2; + p2->numpoints = 5; + p2->point = pnts2; + pnts2[0].x = pnts2[1].x = pnts2[4].x = r2->minx; + pnts2[2].x = pnts2[3].x = r2->maxx; + pnts2[0].y = pnts2[3].y = pnts2[4].y = r2->miny; + pnts2[1].y = pnts2[2].y = r2->maxy; + } else { + p2 = l2; + } + (void)pnts1[0].x; + (void)pnts1[0].y; + (void)pnts1[1].x; + (void)pnts1[1].y; + (void)pnts1[2].x; + (void)pnts1[2].y; + (void)pnts1[3].x; + (void)pnts1[3].y; + (void)pnts1[4].x; + (void)pnts1[4].y; + (void)pnts2[0].x; + (void)pnts2[0].y; + (void)pnts2[1].x; + (void)pnts2[1].y; + (void)pnts2[2].x; + (void)pnts2[2].y; + (void)pnts2[3].x; + (void)pnts2[3].y; + (void)pnts2[4].x; + (void)pnts2[4].y; + + /* STEP 1: look for intersecting line segments */ + for (v1 = 1; v1 < p1->numpoints; v1++) + for (v2 = 1; v2 < p2->numpoints; v2++) + if (msIntersectSegments(&(p1->point[v1 - 1]), &(p1->point[v1]), + &(p2->point[v2 - 1]), + &(p2->point[v2])) == MS_TRUE) { + return (MS_TRUE); + } + + /* STEP 2: polygon one completely contains two (only need to check one point + * from each part) */ + point = &(p2->point[0]); + if (msPointInPolygon(point, p1) == + MS_TRUE) /* ok, the point is in a polygon */ + return (MS_TRUE); + + /* STEP 3: polygon two completely contains one (only need to check one point + * from each part) */ + point = &(p1->point[0]); + if (msPointInPolygon(point, p2) == + MS_TRUE) /* ok, the point is in a polygon */ + return (MS_TRUE); + + return (MS_FALSE); +} + +/* For MapScript, exactly the same the msInsertStyle */ +int msInsertLabelStyle(labelObj *label, styleObj *style, int nStyleIndex) { + if (!style) { + msSetError(MS_CHILDERR, "Can't insert a NULL Style", + "msInsertLabelStyle()"); + return -1; + } + + /* Ensure there is room for a new style */ + if (msGrowLabelStyles(label) == NULL) { + return -1; + } + /* Catch attempt to insert past end of styles array */ + else if (nStyleIndex >= label->numstyles) { + msSetError(MS_CHILDERR, "Cannot insert style beyond index %d", + "insertLabelStyle()", label->numstyles - 1); + return -1; + } else if (nStyleIndex < 0) { /* Insert at the end by default */ + label->styles[label->numstyles] = style; + MS_REFCNT_INCR(style); + label->numstyles++; + return label->numstyles - 1; + } else { + /* Move styles existing at the specified nStyleIndex or greater */ + /* to a higher nStyleIndex */ + for (int i = label->numstyles - 1; i >= nStyleIndex; i--) { + label->styles[i + 1] = label->styles[i]; + } + label->styles[nStyleIndex] = style; + MS_REFCNT_INCR(style); + label->numstyles++; + return nStyleIndex; + } +} + +/** + * Move the style up inside the array of styles. + */ +int msMoveLabelStyleUp(labelObj *label, int nStyleIndex) { + if (label && nStyleIndex < label->numstyles && nStyleIndex > 0) { + styleObj *psTmpStyle = (styleObj *)malloc(sizeof(styleObj)); + initStyle(psTmpStyle); + + msCopyStyle(psTmpStyle, label->styles[nStyleIndex]); + + msCopyStyle(label->styles[nStyleIndex], label->styles[nStyleIndex - 1]); + + msCopyStyle(label->styles[nStyleIndex - 1], psTmpStyle); + + return (MS_SUCCESS); + } + msSetError(MS_CHILDERR, "Invalid index: %d", "msMoveLabelStyleUp()", + nStyleIndex); + return (MS_FAILURE); +} + +/** + * Move the style down inside the array of styles. + */ +int msMoveLabelStyleDown(labelObj *label, int nStyleIndex) { + styleObj *psTmpStyle = NULL; + + if (label && nStyleIndex < label->numstyles - 1 && nStyleIndex >= 0) { + psTmpStyle = (styleObj *)malloc(sizeof(styleObj)); + initStyle(psTmpStyle); + + msCopyStyle(psTmpStyle, label->styles[nStyleIndex]); + + msCopyStyle(label->styles[nStyleIndex], label->styles[nStyleIndex + 1]); + + msCopyStyle(label->styles[nStyleIndex + 1], psTmpStyle); + + return (MS_SUCCESS); + } + msSetError(MS_CHILDERR, "Invalid index: %d", "msMoveLabelStyleDown()", + nStyleIndex); + return (MS_FAILURE); +} + +/** + * Delete the style identified by the index and shift + * styles that follows the deleted style. + */ +int msDeleteLabelStyle(labelObj *label, int nStyleIndex) { + if (label && nStyleIndex < label->numstyles && nStyleIndex >= 0) { + if (freeStyle(label->styles[nStyleIndex]) == MS_SUCCESS) + msFree(label->styles[nStyleIndex]); + for (int i = nStyleIndex; i < label->numstyles - 1; i++) { + label->styles[i] = label->styles[i + 1]; + } + label->styles[label->numstyles - 1] = NULL; + label->numstyles--; + return (MS_SUCCESS); + } + msSetError(MS_CHILDERR, "Invalid index: %d", "msDeleteLabelStyle()", + nStyleIndex); + return (MS_FAILURE); +} + +styleObj *msRemoveLabelStyle(labelObj *label, int nStyleIndex) { + int i; + styleObj *style; + if (nStyleIndex < 0 || nStyleIndex >= label->numstyles) { + msSetError(MS_CHILDERR, "Cannot remove style, invalid nStyleIndex %d", + "removeLabelStyle()", nStyleIndex); + return NULL; + } else { + style = label->styles[nStyleIndex]; + for (i = nStyleIndex; i < label->numstyles - 1; i++) { + label->styles[i] = label->styles[i + 1]; + } + label->styles[label->numstyles - 1] = NULL; + label->numstyles--; + MS_REFCNT_DECR(style); + return style; + } +} diff --git a/src/maplayer.c b/src/maplayer.c new file mode 100644 index 0000000000..6130e1f41c --- /dev/null +++ b/src/maplayer.c @@ -0,0 +1,2652 @@ +/****************************************************************************** + * $Id$ + * + * Project: MapServer + * Purpose: Implementation of most layerObj functions. + * Author: Steve Lime and the MapServer team. + * + ****************************************************************************** + * Copyright (c) 1996-2005 Regents of the University of Minnesota. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + ****************************************************************************/ + +#include "mapserver.h" +#include "maptime.h" +#include "mapogcfilter.h" +#include "mapthread.h" +#include "mapfile.h" +#include "mapows.h" +#include "mapparser.h" +#include "mapogcsld.h" + +#include "cpl_string.h" + +#include + +#ifndef cppcheck_assert +#define cppcheck_assert(x) \ + do { \ + } while (0) +#endif + +static int populateVirtualTable(layerVTableObj *vtable); + +/* +** Iteminfo is a layer parameter that holds information necessary to retrieve an +*individual item for +** a particular source. It is an array built from a list of items. The type of +*iteminfo will vary by +** source. For shapefiles and OGR it is simply an array of integers where each +*value is an index for +** the item. For SDE it's a ESRI specific type that contains index and column +*type information. Two +** helper functions below initialize and free that structure member which is +*used locally by layer +** specific functions. +*/ +int msLayerInitItemInfo(layerObj *layer) { + if (!layer->vtable) { + int rv = msInitializeVirtualTable(layer); + if (rv != MS_SUCCESS) + return rv; + } + cppcheck_assert(layer->vtable); + return layer->vtable->LayerInitItemInfo(layer); +} + +void msLayerFreeItemInfo(layerObj *layer) { + if (!layer->vtable) { + int rv = msInitializeVirtualTable(layer); + if (rv != MS_SUCCESS) + return; + } + cppcheck_assert(layer->vtable); + layer->vtable->LayerFreeItemInfo(layer); + + /* + * Layer expressions with attribute binding hold a numeric index pointing + * to an iteminfo (node->tokenval.bindval.index). If iteminfo changes, + * an expression may be no longer valid. (#5161) + */ + msLayerFreeExpressions(layer); +} + +int msLayerRestoreFromScaletokens(layerObj *layer) { + if (!layer->scaletokens || !layer->orig_st) { + return MS_SUCCESS; + } + if (layer->orig_st->data) { + msFree(layer->data); + layer->data = layer->orig_st->data; + } + if (layer->orig_st->tileindex) { + msFree(layer->tileindex); + layer->tileindex = layer->orig_st->tileindex; + } + if (layer->orig_st->tileitem) { + msFree(layer->tileitem); + layer->tileitem = layer->orig_st->tileitem; + } + if (layer->orig_st->filter) { + if (layer->filter.type == MS_EXPRESSION) { + const size_t tmpval_size = strlen(layer->filter.string) + 3; + char *tmpval = (char *)msSmallMalloc(tmpval_size); + snprintf(tmpval, tmpval_size, "(%s)", layer->filter.string); + msLoadExpressionString(&(layer->filter), tmpval); + msFree(tmpval); + } else { + msLoadExpressionString(&(layer->filter), layer->orig_st->filter); + } + msFree(layer->orig_st->filter); + } + if (layer->orig_st->filteritem) { + msFree(layer->filteritem); + layer->filteritem = layer->orig_st->filteritem; + } + if (layer->orig_st->processing) { + CSLDestroy(layer->processing); + layer->processing = layer->orig_st->processing; + layer->orig_st->processing = NULL; + } + msFree(layer->orig_st); + layer->orig_st = NULL; + return MS_SUCCESS; +} + +#define check_st_alloc(l) \ + if (!l->orig_st) \ + l->orig_st = msSmallCalloc(1, sizeof(originalScaleTokenStrings)); +int msLayerApplyScaletokens(layerObj *layer, double scale) { + int i, p; + if (!layer->scaletokens) { + return MS_SUCCESS; + } + msLayerRestoreFromScaletokens(layer); + for (i = 0; i < layer->numscaletokens; i++) { + scaleTokenObj *st = &layer->scaletokens[i]; + scaleTokenEntryObj *ste = NULL; + if (scale <= 0) { + ste = &(st->tokens[0]); + /* no scale defined, use first entry */ + } else { + int tokenindex = 0; + while (tokenindex < st->n_entries) { + ste = &(st->tokens[tokenindex]); + if (scale < ste->maxscale && scale >= ste->minscale) + break; /* current token is the correct one */ + tokenindex++; + ste = NULL; + } + } + assert(ste); + if (layer->data && strstr(layer->data, st->name)) { + if (layer->debug >= MS_DEBUGLEVEL_DEBUG) { + msDebug("replacing scaletoken (%s) with (%s) in layer->data (%s) for " + "scale=%f\n", + st->name, ste->value, layer->name, scale); + } + check_st_alloc(layer); + layer->orig_st->data = layer->data; + layer->data = msStrdup(layer->data); + layer->data = msReplaceSubstring(layer->data, st->name, ste->value); + } + if (layer->tileindex && strstr(layer->tileindex, st->name)) { + if (layer->debug >= MS_DEBUGLEVEL_DEBUG) { + msDebug("replacing scaletoken (%s) with (%s) in layer->tileindex (%s) " + "for scale=%f\n", + st->name, ste->value, layer->name, scale); + } + check_st_alloc(layer); + layer->orig_st->tileindex = layer->tileindex; + layer->tileindex = msStrdup(layer->tileindex); + layer->tileindex = + msReplaceSubstring(layer->tileindex, st->name, ste->value); + } + if (layer->tileitem && strstr(layer->tileitem, st->name)) { + if (layer->debug >= MS_DEBUGLEVEL_DEBUG) { + msDebug("replacing scaletoken (%s) with (%s) in layer->tileitem (%s) " + "for scale=%f\n", + st->name, ste->value, layer->name, scale); + } + check_st_alloc(layer); + layer->orig_st->tileitem = layer->tileitem; + layer->tileitem = msStrdup(layer->tileitem); + layer->tileitem = + msReplaceSubstring(layer->tileitem, st->name, ste->value); + } + if (layer->filteritem && strstr(layer->filteritem, st->name)) { + if (layer->debug >= MS_DEBUGLEVEL_DEBUG) { + msDebug("replacing scaletoken (%s) with (%s) in layer->filteritem (%s) " + "for scale=%f\n", + st->name, ste->value, layer->name, scale); + } + check_st_alloc(layer); + layer->orig_st->filteritem = layer->filteritem; + layer->filteritem = msStrdup(layer->filteritem); + layer->filteritem = + msReplaceSubstring(layer->filteritem, st->name, ste->value); + } + if (layer->filter.string && strstr(layer->filter.string, st->name)) { + if (layer->debug >= MS_DEBUGLEVEL_DEBUG) { + msDebug("replacing scaletoken (%s) with (%s) in layer->filter (%s) for " + "scale=%f\n", + st->name, ste->value, layer->name, scale); + } + check_st_alloc(layer); + layer->orig_st->filter = msStrdup(layer->filter.string); + + char *tmpval = NULL; + if (layer->filter.type == MS_EXPRESSION) { + const size_t tmpval_size = strlen(layer->filter.string) + 3; + tmpval = (char *)msSmallMalloc(tmpval_size); + snprintf(tmpval, tmpval_size, "(%s)", layer->filter.string); + } else { + tmpval = msStrdup(layer->filter.string); + } + + tmpval = msReplaceSubstring(tmpval, st->name, ste->value); + + if (msLoadExpressionString(&(layer->filter), tmpval) == -1) { + msFree(tmpval); + return (MS_FAILURE); /* msLoadExpressionString() cleans up previously + allocated expression */ + } + msFree(tmpval); + } + + for (p = 0; layer->processing && layer->processing[p]; p++) { + if (strstr(layer->processing[p], st->name)) { + check_st_alloc(layer); + if (!layer->orig_st->processing) { + layer->orig_st->processing = CSLDuplicate(layer->processing); + } + char *newVal = msStrdup(layer->processing[p]); + newVal = msReplaceSubstring(newVal, st->name, ste->value); + CPLFree(layer->processing[p]); + layer->processing[p] = CPLStrdup(newVal); + msFree(newVal); + } + } + } + return MS_SUCCESS; +} + +/* +** Does exactly what it implies, readies a layer for processing. +*/ +int msLayerOpen(layerObj *layer) { + int rv; + + /* RFC-86 Scale dependent token replacements*/ + rv = msLayerApplyScaletokens(layer, + (layer->map) ? layer->map->scaledenom : -1); + if (rv != MS_SUCCESS) + return rv; + + /* RFC-69 clustering support */ + if (layer->cluster.region) + return msClusterLayerOpen(layer); + + if (layer->features && layer->connectiontype != MS_GRATICULE) + layer->connectiontype = MS_INLINE; + + if (layer->tileindex && layer->connectiontype == MS_SHAPEFILE) + layer->connectiontype = MS_TILED_SHAPEFILE; + + if (layer->type == MS_LAYER_RASTER && layer->connectiontype != MS_WMS && + layer->connectiontype != MS_KERNELDENSITY) + layer->connectiontype = MS_RASTER; + + if (!layer->vtable) { + rv = msInitializeVirtualTable(layer); + if (rv != MS_SUCCESS) + return rv; + } + cppcheck_assert(layer->vtable); + return layer->vtable->LayerOpen(layer); +} + +/* +** Returns MS_TRUE if layer has been opened using msLayerOpen(), MS_FALSE +*otherwise +*/ +int msLayerIsOpen(layerObj *layer) { + if (!layer->vtable) { + int rv = msInitializeVirtualTable(layer); + if (rv != MS_SUCCESS) + return rv; + } + cppcheck_assert(layer->vtable); + return layer->vtable->LayerIsOpen(layer); +} + +/* +** msLayerPropertyIsCharacter() +** +** Check if a field in a layer is a Character type +*/ +bool msLayerPropertyIsCharacter(layerObj *layer, const char *property) { + if (!property) { + return false; + } + + char md_item_name[256]; + snprintf(md_item_name, sizeof(md_item_name), "gml_%s_type", property); + + const char *type = msLookupHashTable(&(layer->metadata), md_item_name); + + return (type != NULL && (EQUAL(type, "Character"))); +} + +/* +** msLayerPropertyIsNumeric() +** +** Check if a field in a layer is numeric - an Integer, Long, or Real +*/ +bool msLayerPropertyIsNumeric(layerObj *layer, const char *property) { + if (!property) { + return false; + } + + char md_item_name[256]; + snprintf(md_item_name, sizeof(md_item_name), "gml_%s_type", property); + + const char *type = msLookupHashTable(&(layer->metadata), md_item_name); + + return (type != NULL && (EQUAL(type, "Integer") || EQUAL(type, "Long") || + EQUAL(type, "Real"))); +} + +/* +** Returns MS_TRUE is a layer supports the common expression/filter syntax (RFC +*64) and MS_FALSE otherwise. +*/ +int msLayerSupportsCommonFilters(layerObj *layer) { + if (!layer->vtable) { + int rv = msInitializeVirtualTable(layer); + if (rv != MS_SUCCESS) + return rv; + } + cppcheck_assert(layer->vtable); + return layer->vtable->LayerSupportsCommonFilters(layer); +} + +int msLayerTranslateFilter(layerObj *layer, expressionObj *filter, + char *filteritem) { + if (!layer->vtable) { + int rv = msInitializeVirtualTable(layer); + if (rv != MS_SUCCESS) + return rv; + } + cppcheck_assert(layer->vtable); + return layer->vtable->LayerTranslateFilter(layer, filter, filteritem); +} + +/* +** Performs a spatial, and optionally an attribute based feature search. The +*function basically +** prepares things so that candidate features can be accessed by query or +*drawing functions. For +** OGR and shapefiles this sets an internal bit vector that indicates whether a +*particular feature +** is to processed. For SDE it executes an SQL statement on the SDE server. Once +*run the msLayerNextShape +** function should be called to actually access the shapes. +** +** Note that for shapefiles we apply any maxfeatures constraint at this point. +*That may be the only +** connection type where this is feasible. +*/ +int msLayerWhichShapes(layerObj *layer, rectObj rect, int isQuery) { + if (!msLayerSupportsCommonFilters(layer)) + msLayerTranslateFilter(layer, &layer->filter, layer->filteritem); + + if (!layer->vtable) { + int rv = msInitializeVirtualTable(layer); + if (rv != MS_SUCCESS) + return rv; + } + cppcheck_assert(layer->vtable); + return layer->vtable->LayerWhichShapes(layer, rect, isQuery); +} + +/* +** Called after msWhichShapes has been called to actually retrieve shapes within +*a given area +** and matching a vendor specific filter (i.e. layer FILTER attribute). +** +** Shapefiles: NULL shapes (shapes with attributes but NO vertices are skipped) +*/ +int msLayerNextShape(layerObj *layer, shapeObj *shape) { + int rv, filter_passed; + + if (!layer->vtable) { + rv = msInitializeVirtualTable(layer); + if (rv != MS_SUCCESS) + return rv; + } + cppcheck_assert(layer->vtable); + +#ifdef USE_V8_MAPSCRIPT + /* we need to force the GetItems for the geomtransform attributes */ + if (!layer->items && + layer->_geomtransform.type == MS_GEOMTRANSFORM_EXPRESSION && + strstr(layer->_geomtransform.string, "javascript")) + msLayerGetItems(layer); +#endif + + /* At the end of switch case (default -> break; -> return MS_FAILURE), + * was following TODO ITEM: + * + * TO DO! This is where dynamic joins will happen. Joined attributes will be + * tagged on to the main attributes with the naming scheme [join name].[item + * name]. We need to leverage the iteminfo (I think) at this point + */ + + /* RFC 91: MapServer-based filtering is done at a more general level. */ + do { + rv = layer->vtable->LayerNextShape(layer, shape); + if (rv != MS_SUCCESS) + return rv; + + /* attributes need to be iconv'd to UTF-8 before any filter logic is applied + */ + if (layer->encoding) { + rv = msLayerEncodeShapeAttributes(layer, shape); + if (rv != MS_SUCCESS) + return rv; + } + + filter_passed = msEvalExpression(layer, shape, &(layer->filter), + layer->filteritemindex); + + if (!filter_passed) + msFreeShape(shape); + } while (!filter_passed); + + /* RFC89 Apply Layer GeomTransform */ + if (layer->_geomtransform.type != MS_GEOMTRANSFORM_NONE && rv == MS_SUCCESS) { + rv = msGeomTransformShape(layer->map, layer, shape); + if (rv != MS_SUCCESS) + return rv; + } + + return rv; +} + +/* +** Used to retrieve a shape from a result set by index. Result sets are created +*by the various +** msQueryBy...() functions. The index is assigned by the data source. +*/ +/* int msLayerResultsGetShape(layerObj *layer, shapeObj *shape, int tile, long +record) +{ + if ( ! layer->vtable) { + int rv = msInitializeVirtualTable(layer); + if (rv != MS_SUCCESS) + return rv; + } + + return layer->vtable->LayerResultsGetShape(layer, shape, tile, record); +} */ + +/* +** Used to retrieve a shape by index. All data sources must be capable of random +*access using +** a record number(s) of some sort. +*/ +int msLayerGetShape(layerObj *layer, shapeObj *shape, resultObj *record) { + int rv; + + if (!layer->vtable) { + rv = msInitializeVirtualTable(layer); + if (rv != MS_SUCCESS) + return rv; + } + cppcheck_assert(layer->vtable); + + /* + ** TODO: This is where dynamic joins could happen. Joined attributes would be + ** tagged on to the main attributes with the naming scheme [join name].[item + *name]. + */ + + rv = layer->vtable->LayerGetShape(layer, shape, record); + if (rv != MS_SUCCESS) + return rv; + + /* RFC89 Apply Layer GeomTransform */ + if (layer->_geomtransform.type != MS_GEOMTRANSFORM_NONE) { + rv = msGeomTransformShape(layer->map, layer, shape); + if (rv != MS_SUCCESS) + return rv; + } + + if (layer->encoding) { + rv = msLayerEncodeShapeAttributes(layer, shape); + if (rv != MS_SUCCESS) + return rv; + } + + return rv; +} + +/* +** Returns the number of shapes that match the potential filter and extent. +* rectProjection is the projection in which rect is expressed, or can be NULL if +* rect should be considered in the layer projection. +* This should be equivalent to calling msLayerWhichShapes() and counting the +* number of shapes returned by msLayerNextShape(), honouring layer->maxfeatures +* limitation if layer->maxfeatures>=0, and honouring layer->startindex if +* layer->startindex >= 1 and paging is enabled. +* Returns -1 in case of failure. +*/ +int msLayerGetShapeCount(layerObj *layer, rectObj rect, + projectionObj *rectProjection) { + int rv; + + if (!layer->vtable) { + rv = msInitializeVirtualTable(layer); + if (rv != MS_SUCCESS) + return -1; + } + cppcheck_assert(layer->vtable); + + return layer->vtable->LayerGetShapeCount(layer, rect, rectProjection); +} + +/* +** Closes resources used by a particular layer. +*/ +void msLayerClose(layerObj *layer) { + /* no need for items once the layer is closed */ + msLayerFreeItemInfo(layer); + if (layer->items) { + msFreeCharArray(layer->items, layer->numitems); + layer->items = NULL; + layer->numitems = 0; + } + + /* clear out items used as part of expressions (bug #2702) -- what about the + * layer filter? */ + msLayerFreeExpressions(layer); + + if (layer->vtable) { + layer->vtable->LayerClose(layer); + } + msLayerRestoreFromScaletokens(layer); +} + +/* +** Clear out items used as part of expressions. +*/ +void msLayerFreeExpressions(layerObj *layer) { + int i, j, k; + + msFreeExpressionTokens(&(layer->filter)); + msFreeExpressionTokens(&(layer->cluster.group)); + msFreeExpressionTokens(&(layer->cluster.filter)); + for (i = 0; i < layer->numclasses; i++) { + msFreeExpressionTokens(&(layer->class[i] -> expression)); + msFreeExpressionTokens(&(layer->class[i] -> text)); + for (j = 0; j < layer->class[i] -> numstyles; j++) + msFreeExpressionTokens(&(layer->class[i] -> styles[j] -> _geomtransform)); + for (k = 0; k < layer->class[i] -> numlabels; k++) { + msFreeExpressionTokens(&(layer->class[i] -> labels[k] -> expression)); + msFreeExpressionTokens(&(layer->class[i] -> labels[k] -> text)); + } + } +} + +/* +** Retrieves a list of attributes available for this layer. Most sources also +*set the iteminfo array +** at this point. This function is used when processing query results to expose +*attributes to query +** templates. At that point all attributes are fair game. +*/ +int msLayerGetItems(layerObj *layer) { + const char *itemNames; + /* clean up any previously allocated instances */ + msLayerFreeItemInfo(layer); + if (layer->items) { + msFreeCharArray(layer->items, layer->numitems); + layer->items = NULL; + layer->numitems = 0; + } + + if (!layer->vtable) { + int rv = msInitializeVirtualTable(layer); + if (rv != MS_SUCCESS) + return rv; + } + cppcheck_assert(layer->vtable); + + /* At the end of switch case (default -> break; -> return MS_FAILURE), + * was following TODO ITEM: + */ + /* TO DO! Need to add any joined items on to the core layer items, one long + * list! */ + itemNames = msLayerGetProcessingKey(layer, "ITEMS"); + if (itemNames) { + layer->items = msStringSplit(itemNames, ',', &layer->numitems); + /* populate the iteminfo array */ + return (msLayerInitItemInfo(layer)); + } else + return layer->vtable->LayerGetItems(layer); +} + +/* +** Returns extent of spatial coverage for a layer. +** +** If layer->extent is set then this value is used, otherwise the +** driver-specific implementation is called (this can be expensive). +** +** If layer is not already opened then it is opened and closed (so this +** function can be called on both opened or closed layers). +** +** Returns MS_SUCCESS/MS_FAILURE. +*/ +int msLayerGetExtent(layerObj *layer, rectObj *extent) { + int need_to_close = MS_FALSE, status = MS_SUCCESS; + + if (MS_VALID_EXTENT(layer->extent)) { + *extent = layer->extent; + return MS_SUCCESS; + } + + if (!msLayerIsOpen(layer)) { + if (msLayerOpen(layer) != MS_SUCCESS) + return MS_FAILURE; + need_to_close = MS_TRUE; + } + + if (!layer->vtable) { + int rv = msInitializeVirtualTable(layer); + if (rv != MS_SUCCESS) { + if (need_to_close) + msLayerClose(layer); + return rv; + } + } + cppcheck_assert(layer->vtable); + status = layer->vtable->LayerGetExtent(layer, extent); + + if (status == MS_SUCCESS) { + layer->extent = *extent; + } + + if (need_to_close) + msLayerClose(layer); + + return (status); +} + +int msLayerGetItemIndex(layerObj *layer, char *item) { + int i; + + for (i = 0; i < layer->numitems; i++) { + if (strcasecmp(layer->items[i], item) == 0) + return (i); + } + + return -1; /* item not found */ +} + +static int string2list(char **list, int *listsize, char *string) { + int i; + + for (i = 0; i < (*listsize); i++) { + if (strcasecmp(list[i], string) == 0) { + /* printf("string2list (duplicate): %s %d\n", string, i); */ + return (i); + } + } + + list[i] = msStrdup(string); + (*listsize)++; + + /* printf("string2list: %s %d\n", string, i); */ + + return (i); +} + +extern int msyylex(void); +extern int msyylex_destroy(void); + +extern int msyystate; +extern char *msyystring; /* string to tokenize */ + +extern double msyynumber; /* token containers */ +extern char *msyystring_buffer; + +const char *msExpressionTokenToString(int token) { + switch (token) { + case '(': + return "("; + case ')': + return ")"; + case ',': + return ","; + case '+': + return "+"; + case '-': + return "-"; + case '/': + return "/"; + case '*': + return "*"; + case '%': + return "%"; + + case MS_TOKEN_LOGICAL_AND: + return " and "; + case MS_TOKEN_LOGICAL_OR: + return " or "; + case MS_TOKEN_LOGICAL_NOT: + return " not "; + + case MS_TOKEN_COMPARISON_EQ: + return " = "; + case MS_TOKEN_COMPARISON_NE: + return " != "; + case MS_TOKEN_COMPARISON_GT: + return " > "; + case MS_TOKEN_COMPARISON_GE: + return " >= "; + case MS_TOKEN_COMPARISON_LT: + return " < "; + case MS_TOKEN_COMPARISON_LE: + return " <= "; + case MS_TOKEN_COMPARISON_IEQ: + return ""; + case MS_TOKEN_COMPARISON_RE: + return " ~ "; + case MS_TOKEN_COMPARISON_IRE: + return " ~* "; + case MS_TOKEN_COMPARISON_IN: + return " in "; + + case MS_TOKEN_COMPARISON_INTERSECTS: + return "intersects"; + case MS_TOKEN_COMPARISON_DISJOINT: + return "disjoint"; + case MS_TOKEN_COMPARISON_TOUCHES: + return "touches"; + case MS_TOKEN_COMPARISON_OVERLAPS: + return "overlaps"; + case MS_TOKEN_COMPARISON_CROSSES: + return "crosses"; + case MS_TOKEN_COMPARISON_WITHIN: + return "within"; + case MS_TOKEN_COMPARISON_CONTAINS: + return "contains"; + case MS_TOKEN_COMPARISON_EQUALS: + return "equals"; + case MS_TOKEN_COMPARISON_BEYOND: + return "beyond"; + case MS_TOKEN_COMPARISON_DWITHIN: + return "dwithin"; + + case MS_TOKEN_FUNCTION_LENGTH: + return "length"; + case MS_TOKEN_FUNCTION_TOSTRING: + return "tostring"; + case MS_TOKEN_FUNCTION_COMMIFY: + return "commify"; + case MS_TOKEN_FUNCTION_AREA: + return "area"; + case MS_TOKEN_FUNCTION_ROUND: + return "round"; + case MS_TOKEN_FUNCTION_BUFFER: + return "buffer"; + case MS_TOKEN_FUNCTION_DIFFERENCE: + return "difference"; + case MS_TOKEN_FUNCTION_SIMPLIFY: + return "simplify"; + // case MS_TOKEN_FUNCTION_SIMPLIFYPT: + case MS_TOKEN_FUNCTION_GENERALIZE: + return "generalize"; + default: + return NULL; + } +} + +int msTokenizeExpression(expressionObj *expression, char **list, + int *listsize) { + tokenListNodeObjPtr node; + int token; + + /* TODO: make sure the constants can't somehow reference invalid expression + * types */ + /* if(expression->type != MS_EXPRESSION && expression->type != + * MS_GEOMTRANSFORM_EXPRESSION) return MS_SUCCESS; */ + + msAcquireLock(TLOCK_PARSER); + msyystate = MS_TOKENIZE_EXPRESSION; + msyystring = expression->string; /* the thing we're tokenizing */ + + while ((token = msyylex()) != + 0) { /* keep processing tokens until the end of the string (\0) */ + + if ((node = (tokenListNodeObjPtr)malloc(sizeof(tokenListNodeObj))) == + NULL) { + msSetError(MS_MEMERR, NULL, "msTokenizeExpression()"); + goto parse_error; + } + + node->tokensrc = NULL; + + node->tailifhead = NULL; + node->next = NULL; + + switch (token) { + case MS_TOKEN_LITERAL_BOOLEAN: + case MS_TOKEN_LITERAL_NUMBER: + node->token = token; + node->tokenval.dblval = msyynumber; + break; + case MS_TOKEN_LITERAL_STRING: + node->token = token; + node->tokenval.strval = msStrdup(msyystring_buffer); + break; + case MS_TOKEN_LITERAL_TIME: + node->tokensrc = msStrdup(msyystring_buffer); + node->token = token; + msTimeInit(&(node->tokenval.tmval)); + if (msParseTime(msyystring_buffer, &(node->tokenval.tmval)) != MS_TRUE) { + msSetError(MS_PARSEERR, "Parsing time value failed.", + "msTokenizeExpression()"); + free(node); + goto parse_error; + } + break; + case MS_TOKEN_BINDING_DOUBLE: /* we've encountered an attribute (binding) + reference */ + case MS_TOKEN_BINDING_INTEGER: + case MS_TOKEN_BINDING_STRING: + case MS_TOKEN_BINDING_TIME: + node->token = token; /* binding type */ + node->tokenval.bindval.item = msStrdup(msyystring_buffer); + if (list) + node->tokenval.bindval.index = + string2list(list, listsize, msyystring_buffer); + break; + case MS_TOKEN_BINDING_SHAPE: + node->token = token; + break; + case MS_TOKEN_BINDING_MAP_CELLSIZE: + node->token = token; + break; + case MS_TOKEN_BINDING_DATA_CELLSIZE: + node->token = token; + break; + case MS_TOKEN_FUNCTION_FROMTEXT: /* we want to process a shape from WKT once + and not for every feature being + evaluated */ + if ((token = msyylex()) != 40) { /* ( */ + msSetError(MS_PARSEERR, "Parsing fromText function failed.", + "msTokenizeExpression()"); + free(node); + goto parse_error; + } + + if ((token = msyylex()) != MS_TOKEN_LITERAL_STRING) { + msSetError(MS_PARSEERR, "Parsing fromText function failed.", + "msTokenizeExpression()"); + free(node); + goto parse_error; + } + + node->token = MS_TOKEN_LITERAL_SHAPE; + node->tokenval.shpval = msShapeFromWKT(msyystring_buffer); + + if (!node->tokenval.shpval) { + msSetError(MS_PARSEERR, + "Parsing fromText function failed, WKT processing failed.", + "msTokenizeExpression()"); + free(node); + goto parse_error; + } + + /* todo: perhaps process optional args (e.g. projection) */ + + if ((token = msyylex()) != 41) { /* ) */ + msSetError(MS_PARSEERR, "Parsing fromText function failed.", + "msTokenizeExpression()"); + msFreeShape(node->tokenval.shpval); + free(node->tokenval.shpval); + free(node); + goto parse_error; + } + break; + default: + node->token = token; /* for everything else */ + break; + } + + /* add node to token list */ + if (expression->tokens == NULL) { + expression->tokens = node; + } else { + if (expression->tokens->tailifhead != + NULL) /* this should never be NULL, but just in case */ + expression->tokens->tailifhead->next = + node; /* put the node at the end of the list */ + } + + /* repoint the head of the list to the end - our new element + this causes a loop if we are at the head, be careful not to + walk in a loop */ + expression->tokens->tailifhead = node; + } + + expression->curtoken = expression->tokens; /* point at the first token */ + + msReleaseLock(TLOCK_PARSER); + return MS_SUCCESS; + +parse_error: + msReleaseLock(TLOCK_PARSER); + return MS_FAILURE; +} + +static void buildLayerItemList(layerObj *layer) { + int i, j, k, l; + /* + ** build layer item list, compute item indexes for explicitly item references + *(e.g. classitem) or item bindings + */ + + /* layer items */ + if (layer->classitem) + layer->classitemindex = + string2list(layer->items, &(layer->numitems), layer->classitem); + if (layer->filteritem) + layer->filteritemindex = + string2list(layer->items, &(layer->numitems), layer->filteritem); + if (layer->styleitem && (strcasecmp(layer->styleitem, "AUTO") != 0) && + !STARTS_WITH_CI(layer->styleitem, "javascript://") && + !STARTS_WITH_CI(layer->styleitem, "sld://")) + layer->styleitemindex = + string2list(layer->items, &(layer->numitems), layer->styleitem); + if (layer->labelitem) + layer->labelitemindex = + string2list(layer->items, &(layer->numitems), layer->labelitem); + if (layer->utfitem) + layer->utfitemindex = + string2list(layer->items, &(layer->numitems), layer->utfitem); + + /* layer classes */ + for (i = 0; i < layer->numclasses; i++) { + + // if classgroup has been set we can ignore any fields required + // for rendering unused classes + if (layer->class[i] -> group && layer -> classgroup &&strcasecmp( + layer->class[i] -> group, + layer -> classgroup) != 0) + continue; + + if (layer->class[i] -> expression.type == + MS_EXPRESSION) /* class expression */ + msTokenizeExpression(&(layer->class[i] -> expression), layer->items, + &(layer->numitems)); + + /* class styles (items, bindings, geomtransform) */ + for (j = 0; j < layer->class[i] -> numstyles; j++) { + if (layer->class[i] -> styles[j] -> rangeitem) + layer->class[i]->styles[j]->rangeitemindex = + string2list(layer->items, &(layer->numitems), + layer->class[i] -> styles[j] -> rangeitem); + for (k = 0; k < MS_STYLE_BINDING_LENGTH; k++) { + if (layer->class[i] -> styles[j] -> bindings[k].item) + layer->class[i]->styles[j]->bindings[k].index = + string2list(layer->items, &(layer->numitems), + layer->class[i] -> styles[j] -> bindings[k].item); + if (layer->class[i] -> styles[j] -> exprBindings[k].type == + MS_EXPRESSION) { + msTokenizeExpression( + &(layer->class[i] -> styles[j] -> exprBindings[k]), layer->items, + &(layer->numitems)); + } + } + if (layer->class[i] -> styles[j] -> _geomtransform.type == + MS_GEOMTRANSFORM_EXPRESSION) + msTokenizeExpression(&(layer->class[i] -> styles[j] -> _geomtransform), + layer->items, &(layer->numitems)); + } + + /* class labels and label styles (items, bindings, geomtransform) */ + for (l = 0; l < layer->class[i] -> numlabels; l++) { + for (j = 0; j < layer->class[i] -> labels[l] -> numstyles; j++) { + if (layer->class[i] -> labels[l] -> styles[j] -> rangeitem) + layer->class[i]->labels[l]->styles[j]->rangeitemindex = string2list( + layer->items, &(layer->numitems), + layer->class[i] -> labels[l] -> styles[j] -> rangeitem); + for (k = 0; k < MS_STYLE_BINDING_LENGTH; k++) { + if (layer->class[i] -> labels[l] -> styles[j] -> bindings[k].item) + layer->class[i]->labels[l]->styles[j]->bindings[k].index = + string2list(layer->items, &(layer->numitems), + layer->class[i] -> labels[l] -> styles[j] + -> bindings[k].item); + if (layer->class[i] -> labels[l] -> styles[j] + -> _geomtransform.type == MS_GEOMTRANSFORM_EXPRESSION) + msTokenizeExpression( + &(layer->class[i] -> labels[l] -> styles[j] -> _geomtransform), + layer->items, &(layer->numitems)); + } + } + for (k = 0; k < MS_LABEL_BINDING_LENGTH; k++) { + if (layer->class[i] -> labels[l] -> bindings[k].item) + layer->class[i]->labels[l]->bindings[k].index = + string2list(layer->items, &(layer->numitems), + layer->class[i] -> labels[l] -> bindings[k].item); + if (layer->class[i] -> labels[l] -> exprBindings[k].type == + MS_EXPRESSION) { + msTokenizeExpression( + &(layer->class[i] -> labels[l] -> exprBindings[k]), layer->items, + &(layer->numitems)); + } + } + + /* label expression */ + if (layer->class[i] -> labels[l] -> expression.type == MS_EXPRESSION) + msTokenizeExpression(&(layer->class[i] -> labels[l] -> expression), + layer->items, &(layer->numitems)); + + /* label text */ + if (layer->class[i] -> labels[l] + -> text.type == MS_EXPRESSION || + (layer->class[i] -> labels[l] + -> text.string &&strchr( + layer->class[i] -> labels[l] -> text.string, '[') != + NULL && + strchr(layer->class[i] -> labels[l] -> text.string, + ']') != NULL)) + msTokenizeExpression(&(layer->class[i] -> labels[l] -> text), + layer->items, &(layer->numitems)); + } + + /* class text */ + if (layer->class[i] + -> text.type == MS_EXPRESSION || + (layer->class[i] + -> text.string &&strchr(layer->class[i] -> text.string, '[') != + NULL && + strchr(layer->class[i] -> text.string, ']') != NULL)) + msTokenizeExpression(&(layer->class[i] -> text), layer->items, + &(layer->numitems)); + } + + /* layer filter */ + if (layer->filter.type == MS_EXPRESSION) + msTokenizeExpression(&(layer->filter), layer->items, &(layer->numitems)); + + /* cluster expressions */ + if (layer->cluster.group.type == MS_EXPRESSION) + msTokenizeExpression(&(layer->cluster.group), layer->items, + &(layer->numitems)); + if (layer->cluster.filter.type == MS_EXPRESSION) + msTokenizeExpression(&(layer->cluster.filter), layer->items, + &(layer->numitems)); + + /* utfdata */ + if (layer->utfdata.type == MS_EXPRESSION || + (layer->utfdata.string && strchr(layer->utfdata.string, '[') != NULL && + strchr(layer->utfdata.string, ']') != NULL)) { + msTokenizeExpression(&(layer->utfdata), layer->items, &(layer->numitems)); + } +} + +/* +** This function builds a list of items necessary to draw or query a particular +*layer by +** examining the contents of the various xxxxitem parameters and expressions. +*That list is +** then used to set the iteminfo variable. +*/ +int msLayerWhichItems(layerObj *layer, int get_all, const char *metadata) { + int i, j, k, l, rv; + int nt = 0; + + if (!layer->vtable) { + rv = msInitializeVirtualTable(layer); + if (rv != MS_SUCCESS) + return rv; + } + cppcheck_assert(layer->vtable); + + /* Cleanup any previous item selection */ + msLayerFreeItemInfo(layer); + if (layer->items) { + msFreeCharArray(layer->items, layer->numitems); + layer->items = NULL; + layer->numitems = 0; + } + + /* + ** need a count of potential items/attributes needed + */ + + /* layer level counts */ + layer->classitemindex = -1; + layer->filteritemindex = -1; + layer->styleitemindex = -1; + layer->labelitemindex = -1; + layer->utfitemindex = -1; + + if (layer->classitem) + nt++; + if (layer->filteritem) + nt++; + if (layer->styleitem && (strcasecmp(layer->styleitem, "AUTO") != 0) && + !STARTS_WITH_CI(layer->styleitem, "javascript://") && + !STARTS_WITH_CI(layer->styleitem, "sld://")) + nt++; + + if (layer->filter.type == MS_EXPRESSION) + nt += msCountChars(layer->filter.string, '['); + + if (layer->cluster.group.type == MS_EXPRESSION) + nt += msCountChars(layer->cluster.group.string, '['); + + if (layer->cluster.filter.type == MS_EXPRESSION) + nt += msCountChars(layer->cluster.filter.string, '['); + + if (layer->labelitem) + nt++; + if (layer->utfitem) + nt++; + + if (layer->_geomtransform.type == MS_GEOMTRANSFORM_EXPRESSION) + msTokenizeExpression(&layer->_geomtransform, layer->items, + &(layer->numitems)); + + /* class level counts */ + for (i = 0; i < layer->numclasses; i++) { + + for (j = 0; j < layer->class[i] -> numstyles; j++) { + if (layer->class[i] -> styles[j] -> rangeitem) + nt++; + nt += layer->class[i]->styles[j]->numbindings; + if (layer->class[i] -> styles[j] -> _geomtransform.type == + MS_GEOMTRANSFORM_EXPRESSION) + nt += msCountChars( + layer->class[i] -> styles[j] -> _geomtransform.string, '['); + for (k = 0; k < MS_STYLE_BINDING_LENGTH; k++) { + if (layer->class[i] -> styles[j] -> exprBindings[k].type == + MS_EXPRESSION) { + nt += msCountChars( + layer->class[i] -> styles[j] -> exprBindings[k].string, '['); + } + } + } + + if (layer->class[i] -> expression.type == MS_EXPRESSION) + nt += msCountChars(layer->class[i] -> expression.string, '['); + + for (l = 0; l < layer->class[i] -> numlabels; l++) { + nt += layer->class[i]->labels[l]->numbindings; + for (j = 0; j < layer->class[i] -> labels[l] -> numstyles; j++) { + if (layer->class[i] -> labels[l] -> styles[j] -> rangeitem) + nt++; + nt += layer->class[i]->labels[l]->styles[j]->numbindings; + if (layer->class[i] -> labels[l] -> styles[j] + -> _geomtransform.type == MS_GEOMTRANSFORM_EXPRESSION) + nt += msCountChars(layer->class[i] -> labels[l] -> styles[j] + -> _geomtransform.string, + '['); + } + for (k = 0; k < MS_LABEL_BINDING_LENGTH; k++) { + if (layer->class[i] -> labels[l] -> exprBindings[k].type == + MS_EXPRESSION) { + nt += msCountChars( + layer->class[i] -> labels[l] -> exprBindings[k].string, '['); + } + } + + if (layer->class[i] -> labels[l] -> expression.type == MS_EXPRESSION) + nt += msCountChars(layer->class[i] -> labels[l] -> expression.string, + '['); + if (layer->class[i] -> labels[l] + -> text.type == MS_EXPRESSION || + (layer->class[i] -> labels[l] + -> text.string &&strchr( + layer->class[i] -> labels[l] -> text.string, '[') != + NULL && + strchr(layer->class[i] -> labels[l] -> text.string, + ']') != NULL)) + nt += msCountChars(layer->class[i] -> labels[l] -> text.string, '['); + } + + if (layer->class[i] + -> text.type == MS_EXPRESSION || + (layer->class[i] + -> text.string &&strchr(layer->class[i] -> text.string, '[') != + NULL && + strchr(layer->class[i] -> text.string, ']') != NULL)) + nt += msCountChars(layer->class[i] -> text.string, '['); + } + + /* utfgrid count */ + if (layer->utfdata.type == MS_EXPRESSION || + (layer->utfdata.string && strchr(layer->utfdata.string, '[') != NULL && + strchr(layer->utfdata.string, ']') != NULL)) + nt += msCountChars(layer->utfdata.string, '['); + + // if we are using a GetMap request with a WMS filter we don't need to return + // all items + if (msOWSLookupMetadata(&(layer->metadata), "G", "wmsfilter_flag") != NULL) { + get_all = MS_FALSE; + } + + if (metadata == NULL) { + // check item set by mapwfs.cpp to restrict the number of columns selected + metadata = msOWSLookupMetadata(&(layer->metadata), "G", "select_items"); + if (metadata) { + /* get only selected items */ + get_all = MS_FALSE; + } + } + + /* always retrieve all items in some cases */ + if (layer->connectiontype == MS_INLINE || + (layer->map->outputformat && + layer->map->outputformat->renderer == MS_RENDER_WITH_KML)) { + get_all = MS_TRUE; + } + + /* + ** allocate space for the item list (worse case size) + */ + if (get_all) { + rv = msLayerGetItems(layer); + if (nt > 0) /* need to realloc the array to accept the possible new items*/ + layer->items = (char **)msSmallRealloc( + layer->items, sizeof(char *) * (layer->numitems + nt)); + } else { + rv = layer->vtable->LayerCreateItems(layer, nt); + } + if (rv != MS_SUCCESS) + return rv; + + buildLayerItemList(layer); + + if (metadata) { + char **tokens; + int n = 0; + int j; + + tokens = msStringSplit(metadata, ',', &n); + if (tokens) { + for (i = 0; i < n; i++) { + int bFound = 0; + for (j = 0; j < layer->numitems; j++) { + if (strcasecmp(tokens[i], layer->items[j]) == 0) { + bFound = 1; + break; + } + } + + if (!bFound) { + layer->numitems++; + layer->items = (char **)msSmallRealloc( + layer->items, sizeof(char *) * (layer->numitems)); + layer->items[layer->numitems - 1] = msStrdup(tokens[i]); + } + } + msFreeCharArray(tokens, n); + } + + /* If we didn't retrieve all items of the layer, then do it, so that the */ + /* order of the layer->items array is consistent with it. This is */ + /* important so that WFS DescribeFeatureType and GetFeature requests */ + /* return items in the same order */ + if (!get_all && layer->numitems) { + char **unsorted_items = layer->items; + int numitems = layer->numitems; + + /* Retrieve all items */ + layer->items = NULL; + layer->numitems = 0; + rv = msLayerGetItems(layer); + if (rv != MS_SUCCESS) { + msFreeCharArray(unsorted_items, numitems); + return rv; + } + + /* Sort unsorted_items in the order of layer->items */ + char **sorted_items = (char **)msSmallMalloc(sizeof(char *) * numitems); + int num_sorted_items = 0; + for (i = 0; i < layer->numitems; i++) { + if (layer->items[i]) { + for (j = 0; j < numitems; j++) { + if (unsorted_items[j] && + strcasecmp(layer->items[i], unsorted_items[j]) == 0) { + sorted_items[num_sorted_items] = layer->items[i]; + num_sorted_items++; + + layer->items[i] = NULL; + msFree(unsorted_items[j]); + unsorted_items[j] = NULL; + break; + } + } + } + } + + /* Add items that are not returned by msLayerGetItems() (not sure if that + * can happen) */ + for (j = 0; j < numitems; j++) { + if (unsorted_items[j]) { + sorted_items[num_sorted_items] = unsorted_items[j]; + num_sorted_items++; + } + } + + if (layer->numitems > 0) { + msFreeCharArray(layer->items, layer->numitems); + } + msFreeCharArray(unsorted_items, numitems); + + layer->items = sorted_items; + layer->numitems = numitems; + + /* Re-run buildLayerItemList() with the now correctly sorted items */ + buildLayerItemList(layer); + } + } + + /* populate the iteminfo array */ + if (layer->numitems == 0) + return (MS_SUCCESS); + + return (msLayerInitItemInfo(layer)); +} + +/* +** A helper function to set the items to be retrieved with a particular shape. +*Unused at the moment but will be used +** from within MapScript. Should not need modification. +*/ +int msLayerSetItems(layerObj *layer, char **items, int numitems) { + int i; + /* Cleanup any previous item selection */ + msLayerFreeItemInfo(layer); + if (layer->items) { + msFreeCharArray(layer->items, layer->numitems); + layer->items = NULL; + layer->numitems = 0; + } + + /* now allocate and set the layer item parameters */ + layer->items = (char **)malloc(sizeof(char *) * numitems); + MS_CHECK_ALLOC(layer->items, sizeof(char *) * numitems, MS_FAILURE); + + for (i = 0; i < numitems; i++) + layer->items[i] = msStrdup(items[i]); + layer->numitems = numitems; + + /* populate the iteminfo array */ + return (msLayerInitItemInfo(layer)); +} + +/* +** Fills a classObj with style info from the specified shape. This is used +** with STYLEITEM AUTO when rendering shapes. +** For optimal results, this should be called immediately after +** GetNextShape() or GetShape() so that the shape doesn't have to be read +** twice. +** +*/ +int msLayerGetAutoStyle(mapObj *map, layerObj *layer, classObj *c, + shapeObj *shape) { + if (!layer->vtable) { + int rv = msInitializeVirtualTable(layer); + if (rv != MS_SUCCESS) + return rv; + } + cppcheck_assert(layer->vtable); + return layer->vtable->LayerGetAutoStyle(map, layer, c, shape); +} + +/* +** Fills a classObj with style info from the specified attribute. This is used +** with STYLEITEM "attribute" when rendering shapes. +** +*/ +int msLayerGetFeatureStyle(mapObj *map, layerObj *layer, classObj *c, + shapeObj *shape) { + char *stylestring = NULL; + if (layer->styleitem && layer->styleitemindex >= 0) { + stylestring = msStrdup(shape->values[layer->styleitemindex]); + } else if (layer->styleitem && + strncasecmp(layer->styleitem, "javascript://", 13) == 0) { +#ifdef USE_V8_MAPSCRIPT + char *filename = layer->styleitem + 13; + + if (!map->v8context) { + msV8CreateContext(map); + if (!map->v8context) { + msSetError(MS_V8ERR, "Unable to create v8 context.", + "msLayerGetFeatureStyle()"); + return MS_FAILURE; + } + } + + if (*filename == '\0') { + msSetError(MS_V8ERR, "Invalid javascript filename: \"%s\".", + "msLayerGetFeatureStyle()", layer->styleitem); + return MS_FAILURE; + } + + stylestring = msV8GetFeatureStyle(map, filename, layer, shape); +#else + msSetError(MS_V8ERR, "V8 Javascript support is not available.", + "msLayerGetFeatureStyle()"); + return MS_FAILURE; +#endif + } else if (layer->styleitem && STARTS_WITH_CI(layer->styleitem, "sld://")) { + // ignore the SLD styleitem + return MS_SUCCESS; + } else { /* unknown styleitem */ + return MS_FAILURE; + } + + /* try to find out the current style format */ + if (!stylestring) + return MS_FAILURE; + + if (strncasecmp(stylestring, "style", 5) == 0) { + resetClassStyle(c); + c->layer = layer; + if (msMaybeAllocateClassStyle(c, 0)) { + free(stylestring); + return (MS_FAILURE); + } + + msUpdateStyleFromString(c->styles[0], stylestring); + double geo_cellsize = msGetGeoCellSize(map); + msUpdateClassScaleFactor(geo_cellsize, map, layer, c); + + if (c->styles[0]->symbolname) { + if ((c->styles[0]->symbol = msGetSymbolIndex( + &(map->symbolset), c->styles[0]->symbolname, MS_TRUE)) == -1) { + msSetError(MS_MISCERR, "Undefined symbol \"%s\" in class of layer %s.", + "msLayerGetFeatureStyle()", c->styles[0]->symbolname, + layer->name); + free(stylestring); + return MS_FAILURE; + } + } + } else if (strncasecmp(stylestring, "class", 5) == 0) { + if (strcasestr(stylestring, " style ") != NULL) { + /* reset style if stylestring contains style definitions */ + resetClassStyle(c); + c->layer = layer; + } + msUpdateClassFromString(c, stylestring); + double geo_cellsize = msGetGeoCellSize(map); + msUpdateClassScaleFactor(geo_cellsize, map, layer, c); + } else if (strncasecmp(stylestring, "pen", 3) == 0 || + strncasecmp(stylestring, "brush", 5) == 0 || + strncasecmp(stylestring, "symbol", 6) == 0 || + strncasecmp(stylestring, "label", 5) == 0) { + msOGRUpdateStyleFromString(map, layer, c, stylestring); + } else if (strcasestr(stylestring, "StyledLayerDescriptor>") != NULL) { + // check for the closing tag of an SLD document or + // with a namespace e.g. + msSLDApplySLD(map, stylestring, layer->index, NULL, NULL); + } else { + resetClassStyle(c); + } + + free(stylestring); + return MS_SUCCESS; +} + +/* +Returns the number of inline feature of a layer +*/ +int msLayerGetNumFeatures(layerObj *layer) { + int need_to_close = MS_FALSE, result = -1; + + if (!msLayerIsOpen(layer)) { + if (msLayerOpen(layer) != MS_SUCCESS) + return result; + need_to_close = MS_TRUE; + } + + if (!layer->vtable) { + int rv = msInitializeVirtualTable(layer); + if (rv != MS_SUCCESS) + return result; + } + cppcheck_assert(layer->vtable); + + result = layer->vtable->LayerGetNumFeatures(layer); + + if (need_to_close) + msLayerClose(layer); + + return (result); +} + +void msLayerSetProcessingKey(layerObj *layer, const char *key, + const char *value) + +{ + layer->processing = CSLSetNameValue(layer->processing, key, value); +} + +void msLayerSubstituteProcessing(layerObj *layer, const char *from, + const char *to) { + int i; + for (i = 0; layer->processing && layer->processing[i]; i++) { + char *newVal = + msCaseReplaceSubstring(msStrdup(layer->processing[i]), from, to); + CPLFree(layer->processing[i]); + layer->processing[i] = CPLStrdup(newVal); + msFree(newVal); + } +} + +void msLayerAddProcessing(layerObj *layer, const char *directive) + +{ + layer->processing = CSLAddString(layer->processing, directive); +} + +int msLayerGetNumProcessing(const layerObj *layer) { + return CSLCount(layer->processing); +} + +const char *msLayerGetProcessing(const layerObj *layer, int proc_index) { + if (proc_index < 0 || proc_index >= msLayerGetNumProcessing(layer)) { + msSetError(MS_CHILDERR, "Invalid processing index.", + "msLayerGetProcessing()"); + return NULL; + } else { + return layer->processing[proc_index]; + } +} + +const char *msLayerGetProcessingKey(const layerObj *layer, const char *key) { + return CSLFetchNameValue(layer->processing, key); +} + +/************************************************************************/ +/* msLayerGetMaxFeaturesToDraw */ +/* */ +/* Check to see if maxfeaturestodraw is set as a metadata or an */ +/* output format option. Used for vector layers to limit the */ +/* number of fatures rendered. */ +/************************************************************************/ +int msLayerGetMaxFeaturesToDraw(layerObj *layer, outputFormatObj *format) { + int nMaxFeatures = -1; + const char *pszTmp = NULL; + if (layer) { + nMaxFeatures = layer->maxfeatures; + pszTmp = msLookupHashTable(&layer->metadata, "maxfeaturestodraw"); + if (pszTmp) + nMaxFeatures = atoi(pszTmp); + else { + pszTmp = + msLookupHashTable(&layer->map->web.metadata, "maxfeaturestodraw"); + if (pszTmp) + nMaxFeatures = atoi(pszTmp); + } + } + if (format) { + if (nMaxFeatures < 0) + nMaxFeatures = + atoi(msGetOutputFormatOption(format, "maxfeaturestodraw", "-1")); + } + + return nMaxFeatures; +} + +int msLayerClearProcessing(layerObj *layer) { + CSLDestroy(layer->processing); + layer->processing = 0; + return 0; +} + +int makeTimeFilter(layerObj *lp, const char *timestring, const char *timefield, + const int addtimebacktics) { + + char **atimes, **tokens = NULL; + int numtimes, i, ntmp = 0; + char *pszBuffer = NULL; + int bOnlyExistingFilter = 0; + + if (!lp || !timestring || !timefield) + return MS_FALSE; + + /* parse the time string. We support discrete times (eg 2004-09-21), */ + /* multiple times (2004-09-21, 2004-09-22, ...) */ + /* and range(s) (2004-09-21/2004-09-25, 2004-09-27/2004-09-29) */ + + if (strstr(timestring, ",") == NULL && + strstr(timestring, "/") == NULL) { /* discrete time */ + /* + if(lp->filteritem) free(lp->filteritem); + lp->filteritem = msStrdup(timefield); + if (&lp->filter) + msFreeExpression(&lp->filter); + */ + + /* if the filter is set and it's a sting type, concatenate it with + the time. If not just free it */ + if (lp->filter.string && lp->filter.type == MS_STRING) { + pszBuffer = msStringConcatenate(pszBuffer, "(("); + pszBuffer = msStringConcatenate(pszBuffer, lp->filter.string); + pszBuffer = msStringConcatenate(pszBuffer, ") and "); + } else if (lp->filter.string && lp->filter.type == MS_EXPRESSION) { + char *pszExpressionString = msGetExpressionString(&(lp->filter)); + pszBuffer = msStringConcatenate(pszBuffer, "("); + pszBuffer = msStringConcatenate(pszBuffer, pszExpressionString); + pszBuffer = msStringConcatenate(pszBuffer, " and "); + msFree(pszExpressionString); + } else { + msFreeExpression(&lp->filter); + } + + pszBuffer = msStringConcatenate(pszBuffer, "("); + if (addtimebacktics) + pszBuffer = msStringConcatenate(pszBuffer, "`"); + + if (addtimebacktics) + pszBuffer = msStringConcatenate(pszBuffer, "["); + pszBuffer = msStringConcatenate(pszBuffer, (char *)timefield); + if (addtimebacktics) + pszBuffer = msStringConcatenate(pszBuffer, "]"); + if (addtimebacktics) + pszBuffer = msStringConcatenate(pszBuffer, "`"); + + pszBuffer = msStringConcatenate(pszBuffer, " = "); + if (addtimebacktics) + pszBuffer = msStringConcatenate(pszBuffer, "`"); + else + pszBuffer = msStringConcatenate(pszBuffer, "'"); + + pszBuffer = msStringConcatenate(pszBuffer, (char *)timestring); + if (addtimebacktics) + pszBuffer = msStringConcatenate(pszBuffer, "`"); + else + pszBuffer = msStringConcatenate(pszBuffer, "'"); + + pszBuffer = msStringConcatenate(pszBuffer, ")"); + + /* if there was a filter, It was concatenate with an And ans should be + * closed*/ + if (lp->filter.string && + (lp->filter.type == MS_STRING || lp->filter.type == MS_EXPRESSION)) + pszBuffer = msStringConcatenate(pszBuffer, ")"); + + msLoadExpressionString(&lp->filter, pszBuffer); + + if (pszBuffer) + msFree(pszBuffer); + return MS_TRUE; + } + + atimes = msStringSplit(timestring, ',', &numtimes); + if (atimes == NULL || numtimes < 1) { + msFreeCharArray(atimes, numtimes); + return MS_FALSE; + } + + if (lp->filter.string && lp->filter.type == MS_STRING) { + pszBuffer = msStringConcatenate(pszBuffer, "(("); + pszBuffer = msStringConcatenate(pszBuffer, lp->filter.string); + pszBuffer = msStringConcatenate(pszBuffer, ") and "); + /*this flag is used to indicate that the buffer contains only the + existing filter. It is set to 0 when time filter parts are + added to the buffer */ + bOnlyExistingFilter = 1; + } else if (lp->filter.string && lp->filter.type == MS_EXPRESSION) { + char *pszExpressionString = msGetExpressionString(&(lp->filter)); + pszBuffer = msStringConcatenate(pszBuffer, "("); + pszBuffer = msStringConcatenate(pszBuffer, pszExpressionString); + pszBuffer = msStringConcatenate(pszBuffer, " and "); + msFree(pszExpressionString); + bOnlyExistingFilter = 1; + } else + msFreeExpression(&lp->filter); + + /* check to see if we have ranges by parsing the first entry */ + tokens = msStringSplit(atimes[0], '/', &ntmp); + if (ntmp == 2) { /* ranges */ + msFreeCharArray(tokens, ntmp); + for (i = 0; i < numtimes; i++) { + tokens = msStringSplit(atimes[i], '/', &ntmp); + if (ntmp == 2) { + if (pszBuffer && strlen(pszBuffer) > 0 && bOnlyExistingFilter == 0) + pszBuffer = msStringConcatenate(pszBuffer, " OR "); + else + pszBuffer = msStringConcatenate(pszBuffer, "("); + + bOnlyExistingFilter = 0; + + pszBuffer = msStringConcatenate(pszBuffer, "("); + if (addtimebacktics) + pszBuffer = msStringConcatenate(pszBuffer, "`"); + + if (addtimebacktics) + pszBuffer = msStringConcatenate(pszBuffer, "["); + pszBuffer = msStringConcatenate(pszBuffer, (char *)timefield); + if (addtimebacktics) + pszBuffer = msStringConcatenate(pszBuffer, "]"); + + if (addtimebacktics) + pszBuffer = msStringConcatenate(pszBuffer, "`"); + + pszBuffer = msStringConcatenate(pszBuffer, " >= "); + if (addtimebacktics) + pszBuffer = msStringConcatenate(pszBuffer, "`"); + else + pszBuffer = msStringConcatenate(pszBuffer, "'"); + + pszBuffer = msStringConcatenate(pszBuffer, tokens[0]); + if (addtimebacktics) + pszBuffer = msStringConcatenate(pszBuffer, "`"); + else + pszBuffer = msStringConcatenate(pszBuffer, "'"); + pszBuffer = msStringConcatenate(pszBuffer, " AND "); + + if (addtimebacktics) + pszBuffer = msStringConcatenate(pszBuffer, "`"); + + if (addtimebacktics) + pszBuffer = msStringConcatenate(pszBuffer, "["); + pszBuffer = msStringConcatenate(pszBuffer, (char *)timefield); + if (addtimebacktics) + pszBuffer = msStringConcatenate(pszBuffer, "]"); + if (addtimebacktics) + pszBuffer = msStringConcatenate(pszBuffer, "`"); + + pszBuffer = msStringConcatenate(pszBuffer, " <= "); + + if (addtimebacktics) + pszBuffer = msStringConcatenate(pszBuffer, "`"); + else + pszBuffer = msStringConcatenate(pszBuffer, "'"); + pszBuffer = msStringConcatenate(pszBuffer, tokens[1]); + if (addtimebacktics) + pszBuffer = msStringConcatenate(pszBuffer, "`"); + else + pszBuffer = msStringConcatenate(pszBuffer, "'"); + pszBuffer = msStringConcatenate(pszBuffer, ")"); + } + + msFreeCharArray(tokens, ntmp); + } + if (pszBuffer && strlen(pszBuffer) > 0 && bOnlyExistingFilter == 0) + pszBuffer = msStringConcatenate(pszBuffer, ")"); + } else if (ntmp == 1) { /* multiple times */ + msFreeCharArray(tokens, ntmp); + pszBuffer = msStringConcatenate(pszBuffer, "("); + for (i = 0; i < numtimes; i++) { + if (i > 0) + pszBuffer = msStringConcatenate(pszBuffer, " OR "); + + pszBuffer = msStringConcatenate(pszBuffer, "("); + if (addtimebacktics) + pszBuffer = msStringConcatenate(pszBuffer, "`"); + + if (addtimebacktics) + pszBuffer = msStringConcatenate(pszBuffer, "["); + pszBuffer = msStringConcatenate(pszBuffer, (char *)timefield); + if (addtimebacktics) + pszBuffer = msStringConcatenate(pszBuffer, "]"); + + if (addtimebacktics) + pszBuffer = msStringConcatenate(pszBuffer, "`"); + + pszBuffer = msStringConcatenate(pszBuffer, " = "); + + if (addtimebacktics) + pszBuffer = msStringConcatenate(pszBuffer, "`"); + else + pszBuffer = msStringConcatenate(pszBuffer, "'"); + pszBuffer = msStringConcatenate(pszBuffer, atimes[i]); + if (addtimebacktics) + pszBuffer = msStringConcatenate(pszBuffer, "`"); + else + pszBuffer = msStringConcatenate(pszBuffer, "'"); + pszBuffer = msStringConcatenate(pszBuffer, ")"); + } + pszBuffer = msStringConcatenate(pszBuffer, ")"); + } else { + msFreeCharArray(tokens, ntmp); + msFreeCharArray(atimes, numtimes); + msFree(pszBuffer); + return MS_FALSE; + } + + msFreeCharArray(atimes, numtimes); + + /* load the string to the filter */ + if (pszBuffer && strlen(pszBuffer) > 0) { + if (lp->filter.string && + (lp->filter.type == MS_STRING || lp->filter.type == MS_EXPRESSION)) + pszBuffer = msStringConcatenate(pszBuffer, ")"); + /* + if(lp->filteritem) + free(lp->filteritem); + lp->filteritem = msStrdup(timefield); + */ + + msLoadExpressionString(&lp->filter, pszBuffer); + } + msFree(pszBuffer); + return MS_TRUE; +} + +/** + set the filter parameter for a time filter +**/ + +int msLayerSetTimeFilter(layerObj *layer, const char *timestring, + const char *timefield) { + if (!layer->vtable) { + int rv = msInitializeVirtualTable(layer); + if (rv != MS_SUCCESS) + return rv; + } + cppcheck_assert(layer->vtable); + return layer->vtable->LayerSetTimeFilter(layer, timestring, timefield); +} + +int msLayerMakeBackticsTimeFilter(layerObj *lp, const char *timestring, + const char *timefield) { + return makeTimeFilter(lp, timestring, timefield, MS_TRUE); +} + +int msLayerMakePlainTimeFilter(layerObj *lp, const char *timestring, + const char *timefield) { + return makeTimeFilter(lp, timestring, timefield, MS_FALSE); +} + +/* + * Dummies / default actions for layers + */ +int LayerDefaultInitItemInfo(layerObj *layer) { + (void)layer; + return MS_SUCCESS; +} + +void LayerDefaultFreeItemInfo(layerObj *layer) { (void)layer; } + +int LayerDefaultOpen(layerObj *layer) { + (void)layer; + return MS_FAILURE; +} + +int LayerDefaultIsOpen(layerObj *layer) { + (void)layer; + return MS_FALSE; +} + +int LayerDefaultWhichShapes(layerObj *layer, rectObj rect, int isQuery) { + (void)layer; + (void)rect; + (void)isQuery; + return MS_SUCCESS; +} + +int LayerDefaultNextShape(layerObj *layer, shapeObj *shape) { + (void)layer; + (void)shape; + return MS_FAILURE; +} + +int LayerDefaultGetShape(layerObj *layer, shapeObj *shape, resultObj *record) { + (void)layer; + (void)shape; + (void)record; + return MS_FAILURE; +} + +int LayerDefaultGetShapeCount(layerObj *layer, rectObj rect, + projectionObj *rectProjection) { + int status; + shapeObj shape, searchshape; + int nShapeCount = 0; + rectObj searchrect = rect; + reprojectionObj *reprojector = NULL; + + msInitShape(&searchshape); + msRectToPolygon(searchrect, &searchshape); + + if (rectProjection != NULL) { + if (layer->project && + msProjectionsDiffer(&(layer->projection), rectProjection)) + msProjectRect(rectProjection, &(layer->projection), + &searchrect); /* project the searchrect to source coords */ + else + layer->project = MS_FALSE; + } + + status = msLayerWhichShapes(layer, searchrect, MS_TRUE); + if (status == MS_FAILURE) { + msFreeShape(&searchshape); + return -1; + } else if (status == MS_DONE) { + msFreeShape(&searchshape); + return 0; + } + + msInitShape(&shape); + while ((status = msLayerNextShape(layer, &shape)) == MS_SUCCESS) { + if (rectProjection != NULL) { + if (layer->project && + msProjectionsDiffer(&(layer->projection), rectProjection)) { + if (reprojector == NULL) + reprojector = + msProjectCreateReprojector(&(layer->projection), rectProjection); + if (reprojector) + msProjectShapeEx(reprojector, &shape); + } else + layer->project = MS_FALSE; + + if (msRectContained(&shape.bounds, &rect) == + MS_TRUE) { /* if the whole shape is in, don't intersect */ + status = MS_TRUE; + } else { + switch (shape.type) { /* make sure shape actually intersects the qrect + (ADD FUNCTIONS SPECIFIC TO RECTOBJ) */ + case MS_SHAPE_POINT: + status = msIntersectMultipointPolygon(&shape, &searchshape); + break; + case MS_SHAPE_LINE: + status = msIntersectPolylinePolygon(&shape, &searchshape); + break; + case MS_SHAPE_POLYGON: + status = msIntersectPolygons(&shape, &searchshape); + break; + default: + break; + } + } + } else + status = MS_TRUE; + + if (status == MS_TRUE) + nShapeCount++; + msFreeShape(&shape); + if (layer->maxfeatures > 0 && layer->maxfeatures == nShapeCount) + break; + } + + msFreeShape(&searchshape); + msProjectDestroyReprojector(reprojector); + + return nShapeCount; +} + +int LayerDefaultClose(layerObj *layer) { + (void)layer; + return MS_SUCCESS; +} + +int LayerDefaultGetItems(layerObj *layer) { + (void)layer; + return MS_SUCCESS; /* returning no items is legit */ +} + +int msLayerSupportsPaging(layerObj *layer) { + if (layer && ((layer->connectiontype == MS_ORACLESPATIAL) || + (layer->connectiontype == MS_POSTGIS))) + return MS_TRUE; + + return MS_FALSE; +} + +/* + * msLayerSupportsSorting() + * + * Returns MS_TRUE if the layer supports sorting/ordering. + */ +int msLayerSupportsSorting(layerObj *layer) { + if (layer && + ((layer->connectiontype == MS_OGR) || + (layer->connectiontype == MS_POSTGIS) || + (layer->connectiontype == MS_ORACLESPATIAL) || + ((layer->connectiontype == MS_PLUGIN) && + (strstr(layer->plugin_library, "msplugin_oracle") != NULL)) || + ((layer->connectiontype == MS_PLUGIN) && + (strstr(layer->plugin_library, "msplugin_mssql2008") != NULL)))) + return MS_TRUE; + + return MS_FALSE; +} + +static void msLayerFreeSortBy(layerObj *layer) { + for (int i = 0; i < layer->sortBy.nProperties; i++) + msFree(layer->sortBy.properties[i].item); + msFree(layer->sortBy.properties); + layer->sortBy.properties = NULL; + layer->sortBy.nProperties = 0; +} + +/* + * msLayerSetSort() + * + * Copy the sortBy clause passed as an argument into the layer sortBy member. + */ +void msLayerSetSort(layerObj *layer, const sortByClause *sortBy) { + + sortByProperties *newProperties = (sortByProperties *)msSmallMalloc( + sortBy->nProperties * sizeof(sortByProperties)); + for (int i = 0; i < sortBy->nProperties; i++) { + newProperties[i].item = msStrdup(sortBy->properties[i].item); + newProperties[i].sortOrder = sortBy->properties[i].sortOrder; + } + + msLayerFreeSortBy(layer); + layer->sortBy.nProperties = sortBy->nProperties; + layer->sortBy.properties = newProperties; +} + +/* + * msLayerBuildSQLOrderBy() + * + * Returns the content of a SQL ORDER BY clause from the sortBy member of + * the layer. The string does not contain the "ORDER BY" keywords itself. + */ +char *msLayerBuildSQLOrderBy(layerObj *layer) { + char *strOrderBy = NULL; + if (layer->sortBy.nProperties > 0) { + int i; + for (i = 0; i < layer->sortBy.nProperties; i++) { + char *escaped = + msLayerEscapePropertyName(layer, layer->sortBy.properties[i].item); + if (i > 0) + strOrderBy = msStringConcatenate(strOrderBy, ", "); + strOrderBy = msStringConcatenate(strOrderBy, escaped); + if (layer->sortBy.properties[i].sortOrder == SORT_DESC) + strOrderBy = msStringConcatenate(strOrderBy, " DESC"); + msFree(escaped); + } + } + return strOrderBy; +} + +int msLayerGetPaging(layerObj *layer) { + if (!layer->vtable) { + int rv = msInitializeVirtualTable(layer); + if (rv != MS_SUCCESS) { + msSetError(MS_MISCERR, "Unable to initialize virtual table", + "msLayerGetPaging()"); + return MS_FAILURE; + } + } + cppcheck_assert(layer->vtable); + return layer->vtable->LayerGetPaging(layer); +} + +void msLayerEnablePaging(layerObj *layer, int value) { + if (!layer->vtable) { + int rv = msInitializeVirtualTable(layer); + if (rv != MS_SUCCESS) { + msSetError(MS_MISCERR, "Unable to initialize virtual table", + "msLayerEnablePaging()"); + return; + } + } + cppcheck_assert(layer->vtable); + layer->vtable->LayerEnablePaging(layer, value); +} + +/** Returns a cached reprojector from the layer projection to the map projection + */ +reprojectionObj *msLayerGetReprojectorToMap(layerObj *layer, mapObj *map) { + if (layer->reprojectorLayerToMap != NULL && + !msProjectIsReprojectorStillValid(layer->reprojectorLayerToMap)) { + msProjectDestroyReprojector(layer->reprojectorLayerToMap); + layer->reprojectorLayerToMap = NULL; + } + + if (layer->reprojectorLayerToMap == NULL) { + layer->reprojectorLayerToMap = + msProjectCreateReprojector(&layer->projection, &map->projection); + } + return layer->reprojectorLayerToMap; +} + +int LayerDefaultGetExtent(layerObj *layer, rectObj *extent) { + (void)layer; + (void)extent; + return MS_FAILURE; +} + +int LayerDefaultGetAutoStyle(mapObj *map, layerObj *layer, classObj *c, + shapeObj *shape) { + (void)map; + (void)layer; + (void)c; + (void)shape; + msSetError(MS_MISCERR, "'STYLEITEM AUTO' not supported for this data source.", + "msLayerGetAutoStyle()"); + return MS_FAILURE; +} + +int LayerDefaultCloseConnection(layerObj *layer) { + (void)layer; + return MS_SUCCESS; +} + +int LayerDefaultCreateItems(layerObj *layer, const int nt) { + if (nt > 0) { + layer->items = (char **)calloc( + nt, sizeof(char *)); /* should be more than enough space */ + MS_CHECK_ALLOC(layer->items, sizeof(char *), MS_FAILURE); + + layer->numitems = 0; + } + return MS_SUCCESS; +} + +int LayerDefaultGetNumFeatures(layerObj *layer) { + rectObj extent; + int status; + int result; + shapeObj shape; + + /* calculate layer extent */ + if (!MS_VALID_EXTENT(layer->extent)) { + if (msLayerGetExtent(layer, &extent) != MS_SUCCESS) { + msSetError(MS_MISCERR, "Unable to get layer extent", + "LayerDefaultGetNumFeatures()"); + return -1; + } + } else + extent = layer->extent; + + /* Cleanup any previous item selection */ + msLayerFreeItemInfo(layer); + if (layer->items) { + msFreeCharArray(layer->items, layer->numitems); + layer->items = NULL; + layer->numitems = 0; + } + + status = msLayerWhichShapes(layer, extent, MS_FALSE); + if (status == MS_DONE) { /* no overlap */ + return 0; + } else if (status != MS_SUCCESS) { + return -1; + } + + result = 0; + while ((status = msLayerNextShape(layer, &shape)) == MS_SUCCESS) { + ++result; + msFreeShape(&shape); + } + + return result; +} + +int LayerDefaultAutoProjection(layerObj *layer, projectionObj *projection) { + (void)layer; + (void)projection; + msSetError(MS_MISCERR, + "This data driver does not implement AUTO projection support", + "LayerDefaultAutoProjection()"); + return MS_FAILURE; +} + +int LayerDefaultSupportsCommonFilters(layerObj *layer) { + (void)layer; + return MS_FALSE; +} + +int LayerDefaultTranslateFilter(layerObj *layer, expressionObj *filter, + char *filteritem) { + (void)layer; + (void)filteritem; + if (!filter->string) + return MS_SUCCESS; /* nothing to do, not an error */ + + msSetError(MS_MISCERR, + "This data driver does not implement filter translation support", + "LayerDefaultTranslateFilter()"); + return MS_FAILURE; +} + +int msLayerDefaultGetPaging(layerObj *layer) { + (void)layer; + return MS_FALSE; +} + +void msLayerDefaultEnablePaging(layerObj *layer, int value) { + (void)layer; + (void)value; +} + +/************************************************************************/ +/* LayerDefaultEscapeSQLParam */ +/* */ +/* Default function used to escape strings and avoid sql */ +/* injection. Specific drivers should redefine if an escaping */ +/* function is available in the driver. */ +/************************************************************************/ +char *LayerDefaultEscapeSQLParam(layerObj *layer, const char *pszString) { + (void)layer; + char *pszEscapedStr = NULL; + if (pszString) { + int nSrcLen; + char c; + int i = 0, j = 0; + nSrcLen = (int)strlen(pszString); + pszEscapedStr = (char *)msSmallMalloc(2 * nSrcLen + 1); + for (i = 0, j = 0; i < nSrcLen; i++) { + c = pszString[i]; + if (c == '\'') { + pszEscapedStr[j++] = '\''; + pszEscapedStr[j++] = '\''; + } else if (c == '\\') { + pszEscapedStr[j++] = '\\'; + pszEscapedStr[j++] = '\\'; + } else + pszEscapedStr[j++] = c; + } + pszEscapedStr[j] = 0; + } + return pszEscapedStr; +} + +/************************************************************************/ +/* LayerDefaultEscapePropertyName */ +/* */ +/* Return the property name in a properly escaped and quoted form. */ +/************************************************************************/ +char *LayerDefaultEscapePropertyName(layerObj *layer, const char *pszString) { + char *pszEscapedStr = NULL; + int i, j = 0; + + if (layer && pszString && strlen(pszString) > 0) { + int nLength = strlen(pszString); + + pszEscapedStr = (char *)msSmallMalloc(1 + 2 * nLength + 1 + 1); + pszEscapedStr[j++] = '"'; + + for (i = 0; i < nLength; i++) { + char c = pszString[i]; + if (c == '"') { + pszEscapedStr[j++] = '"'; + pszEscapedStr[j++] = '"'; + } else if (c == '\\') { + pszEscapedStr[j++] = '\\'; + pszEscapedStr[j++] = '\\'; + } else + pszEscapedStr[j++] = c; + } + pszEscapedStr[j++] = '"'; + pszEscapedStr[j++] = 0; + } + return pszEscapedStr; +} + +/* + * msConnectLayer + * + * This will connect layer object to the new layer type. + * Caller is responsible to close previous layer correctly. + * For Internal types the library_str is ignored, for PLUGIN it's + * define what plugin to use. Returns MS_FAILURE or MS_SUCCESS. + */ +int msConnectLayer(layerObj *layer, const int connectiontype, + const char *library_str) { + layer->connectiontype = connectiontype; + /* For internal types, library_str is ignored */ + if (connectiontype == MS_PLUGIN) { + int rv; + + msFree(layer->plugin_library_original); + layer->plugin_library_original = msStrdup(library_str); + + rv = msBuildPluginLibraryPath(&layer->plugin_library, + layer->plugin_library_original, layer->map); + if (rv != MS_SUCCESS) { + return rv; + } + } + return msInitializeVirtualTable(layer); +} + +static int populateVirtualTable(layerVTableObj *vtable) { + assert(vtable != NULL); + + vtable->LayerSupportsCommonFilters = LayerDefaultSupportsCommonFilters; + vtable->LayerTranslateFilter = LayerDefaultTranslateFilter; + + vtable->LayerInitItemInfo = LayerDefaultInitItemInfo; + vtable->LayerFreeItemInfo = LayerDefaultFreeItemInfo; + vtable->LayerOpen = LayerDefaultOpen; + vtable->LayerIsOpen = LayerDefaultIsOpen; + vtable->LayerWhichShapes = LayerDefaultWhichShapes; + + vtable->LayerNextShape = LayerDefaultNextShape; + /* vtable->LayerResultsGetShape = LayerDefaultResultsGetShape; */ + vtable->LayerGetShape = LayerDefaultGetShape; + vtable->LayerGetShapeCount = LayerDefaultGetShapeCount; + vtable->LayerClose = LayerDefaultClose; + vtable->LayerGetItems = LayerDefaultGetItems; + vtable->LayerGetExtent = LayerDefaultGetExtent; + + vtable->LayerGetAutoStyle = LayerDefaultGetAutoStyle; + vtable->LayerCloseConnection = LayerDefaultCloseConnection; + vtable->LayerSetTimeFilter = msLayerMakePlainTimeFilter; + + vtable->LayerApplyFilterToLayer = FLTLayerApplyPlainFilterToLayer; + + vtable->LayerCreateItems = LayerDefaultCreateItems; + + vtable->LayerGetNumFeatures = LayerDefaultGetNumFeatures; + + vtable->LayerGetAutoProjection = LayerDefaultAutoProjection; + + vtable->LayerEscapeSQLParam = LayerDefaultEscapeSQLParam; + + vtable->LayerEscapePropertyName = LayerDefaultEscapePropertyName; + + vtable->LayerEnablePaging = msLayerDefaultEnablePaging; + vtable->LayerGetPaging = msLayerDefaultGetPaging; + + return MS_SUCCESS; +} + +static int createVirtualTable(layerVTableObj **vtable) { + *vtable = malloc(sizeof(**vtable)); + MS_CHECK_ALLOC(*vtable, sizeof(**vtable), MS_FAILURE); + + return populateVirtualTable(*vtable); +} + +static int destroyVirtualTable(layerVTableObj **vtable) { + memset(*vtable, 0, sizeof(**vtable)); + msFree(*vtable); + *vtable = NULL; + return MS_SUCCESS; +} + +int msInitializeVirtualTable(layerObj *layer) { + if (layer->vtable) { + destroyVirtualTable(&layer->vtable); + } + createVirtualTable(&layer->vtable); + + if (layer->features && layer->connectiontype != MS_GRATICULE) + layer->connectiontype = MS_INLINE; + + if (layer->tileindex && layer->connectiontype == MS_SHAPEFILE) + layer->connectiontype = MS_TILED_SHAPEFILE; + + if (layer->type == MS_LAYER_RASTER && layer->connectiontype != MS_WMS && + layer->connectiontype != MS_KERNELDENSITY) + layer->connectiontype = MS_RASTER; + + switch (layer->connectiontype) { + case (MS_INLINE): + return (msINLINELayerInitializeVirtualTable(layer)); + break; + case (MS_SHAPEFILE): + return (msSHPLayerInitializeVirtualTable(layer)); + break; + case (MS_TILED_SHAPEFILE): + return (msTiledSHPLayerInitializeVirtualTable(layer)); + break; + case (MS_OGR): + return (msOGRLayerInitializeVirtualTable(layer)); + break; + case (MS_FLATGEOBUF): + return (msFlatGeobufLayerInitializeVirtualTable(layer)); + break; + case (MS_POSTGIS): + return (msPostGISLayerInitializeVirtualTable(layer)); + break; + case (MS_WMS): + /* WMS should be treated as a raster layer */ + return (msRASTERLayerInitializeVirtualTable(layer)); + break; + case (MS_KERNELDENSITY): + /* KERNELDENSITY should be treated as a raster layer */ + return (msRASTERLayerInitializeVirtualTable(layer)); + break; + case (MS_ORACLESPATIAL): + return (msOracleSpatialLayerInitializeVirtualTable(layer)); + break; + case (MS_WFS): + return (msWFSLayerInitializeVirtualTable(layer)); + break; + case (MS_GRATICULE): + return (msGraticuleLayerInitializeVirtualTable(layer)); + break; + case (MS_RASTER): + return (msRASTERLayerInitializeVirtualTable(layer)); + break; + case (MS_PLUGIN): + return (msPluginLayerInitializeVirtualTable(layer)); + break; + case (MS_UNION): + return (msUnionLayerInitializeVirtualTable(layer)); + break; + case (MS_UVRASTER): + return (msUVRASTERLayerInitializeVirtualTable(layer)); + break; + case (MS_CONTOUR): + return (msContourLayerInitializeVirtualTable(layer)); + break; + case (MS_RASTER_LABEL): + return (msRasterLabelLayerInitializeVirtualTable(layer)); + break; + default: + msSetError(MS_MISCERR, "Unknown connectiontype, it was %d", + "msInitializeVirtualTable()", layer->connectiontype); + return MS_FAILURE; + break; + } + + /* not reached */ + return MS_FAILURE; +} + +/* + * INLINE: Virtual table functions + */ + +typedef struct { + rectObj searchrect; + int is_relative; /* relative coordinates? */ +} msINLINELayerInfo; + +int msINLINELayerIsOpen(layerObj *layer) { + if (layer->layerinfo) + return (MS_TRUE); + else + return (MS_FALSE); +} + +msINLINELayerInfo *msINLINECreateLayerInfo(void) { + msINLINELayerInfo *layerinfo = msSmallMalloc(sizeof(msINLINELayerInfo)); + layerinfo->searchrect.minx = -1.0; + layerinfo->searchrect.miny = -1.0; + layerinfo->searchrect.maxx = -1.0; + layerinfo->searchrect.maxy = -1.0; + layerinfo->is_relative = MS_FALSE; + return layerinfo; +} + +int msINLINELayerOpen(layerObj *layer) { + msINLINELayerInfo *layerinfo; + + if (layer->layerinfo) { + if (layer->debug) { + msDebug("msINLINELayerOpen: Layer is already open!\n"); + } + return MS_SUCCESS; /* already open */ + } + + /* + ** Initialize the layerinfo + **/ + layerinfo = msINLINECreateLayerInfo(); + + layer->currentfeature = + layer->features; /* point to the beginning of the feature list */ + + layer->layerinfo = (void *)layerinfo; + + return (MS_SUCCESS); +} + +int msINLINELayerClose(layerObj *layer) { + if (layer->layerinfo) { + free(layer->layerinfo); + layer->layerinfo = NULL; + } + + return MS_SUCCESS; +} + +int msINLINELayerWhichShapes(layerObj *layer, rectObj rect, int isQuery) { + (void)isQuery; + msINLINELayerInfo *layerinfo = NULL; + layerinfo = (msINLINELayerInfo *)layer->layerinfo; + + layerinfo->searchrect = rect; + layerinfo->is_relative = + (layer->transform != MS_FALSE && layer->transform != MS_TRUE); + + return MS_SUCCESS; +} + +/* Author: Cristoph Spoerri and Sean Gillies */ +int msINLINELayerGetShape(layerObj *layer, shapeObj *shape, resultObj *record) { + int i = 0; + featureListNodeObjPtr current; + + int shapeindex = record->shapeindex; /* only index necessary */ + + current = layer->features; + while (current != NULL && i != shapeindex) { + i++; + current = current->next; + } + if (current == NULL) { + msSetError(MS_SHPERR, "No inline feature with this index.", + "msINLINELayerGetShape()"); + return MS_FAILURE; + } + + if (msCopyShape(&(current->shape), shape) != MS_SUCCESS) { + msSetError( + MS_SHPERR, + "Cannot retrieve inline shape. There some problem with the shape", + "msINLINELayerGetShape()"); + return MS_FAILURE; + } + /* check for the expected size of the values array */ + if (layer->numitems > shape->numvalues) { + shape->values = (char **)msSmallRealloc(shape->values, + sizeof(char *) * (layer->numitems)); + for (i = shape->numvalues; i < layer->numitems; i++) + shape->values[i] = msStrdup(""); + } + msComputeBounds(shape); + return MS_SUCCESS; +} + +int msINLINELayerNextShape(layerObj *layer, shapeObj *shape) { + msINLINELayerInfo *layerinfo = NULL; + shapeObj *s; + + layerinfo = (msINLINELayerInfo *)layer->layerinfo; + + while (1) { + + if (!(layer->currentfeature)) { + /* out of features */ + return (MS_DONE); + } + + s = &(layer->currentfeature->shape); + layer->currentfeature = layer->currentfeature->next; + msComputeBounds(s); + + if (layerinfo->is_relative || + msRectOverlap(&s->bounds, &layerinfo->searchrect)) { + + msCopyShape(s, shape); + + /* check for the expected size of the values array */ + if (layer->numitems > shape->numvalues) { + int i; + shape->values = (char **)msSmallRealloc( + shape->values, sizeof(char *) * (layer->numitems)); + for (i = shape->numvalues; i < layer->numitems; i++) + shape->values[i] = msStrdup(""); + shape->numvalues = layer->numitems; + } + + break; + } + } + + return (MS_SUCCESS); +} + +int msINLINELayerGetNumFeatures(layerObj *layer) { + int i = 0; + featureListNodeObjPtr current; + + current = layer->features; + while (current != NULL) { + i++; + current = current->next; + } + return i; +} + +/* +Returns an escaped string +*/ +char *msLayerEscapeSQLParam(layerObj *layer, const char *pszString) { + if (!layer->vtable) { + int rv = msInitializeVirtualTable(layer); + if (rv != MS_SUCCESS) + return ""; + } + cppcheck_assert(layer->vtable); + return layer->vtable->LayerEscapeSQLParam(layer, pszString); +} + +char *msLayerEscapePropertyName(layerObj *layer, const char *pszString) { + if (!layer->vtable) { + int rv = msInitializeVirtualTable(layer); + if (rv != MS_SUCCESS) + return ""; + } + cppcheck_assert(layer->vtable); + return layer->vtable->LayerEscapePropertyName(layer, pszString); +} + +int msINLINELayerInitializeVirtualTable(layerObj *layer) { + assert(layer != NULL); + assert(layer->vtable != NULL); + + /* layer->vtable->LayerInitItemInfo, use default */ + /* layer->vtable->LayerFreeItemInfo, use default */ + layer->vtable->LayerOpen = msINLINELayerOpen; + layer->vtable->LayerIsOpen = msINLINELayerIsOpen; + layer->vtable->LayerWhichShapes = msINLINELayerWhichShapes; + layer->vtable->LayerNextShape = msINLINELayerNextShape; + /* layer->vtable->LayerGetShapeCount, use default */ + layer->vtable->LayerGetShape = msINLINELayerGetShape; + layer->vtable->LayerClose = msINLINELayerClose; + /* layer->vtable->LayerGetItems, use default */ + + /* + * Original code contained following + * TODO: need to compute extents + */ + /* layer->vtable->LayerGetExtent, use default */ + + /* layer->vtable->LayerGetAutoStyle, use default */ + /* layer->vtable->LayerCloseConnection, use default */ + layer->vtable->LayerSetTimeFilter = msLayerMakeBackticsTimeFilter; + + /* layer->vtable->LayerApplyFilterToLayer, use default */ + + /* layer->vtable->LayerCreateItems, use default */ + layer->vtable->LayerGetNumFeatures = msINLINELayerGetNumFeatures; + + /*layer->vtable->LayerEscapeSQLParam, use default*/ + /*layer->vtable->LayerEscapePropertyName, use default*/ + + /* layer->vtable->LayerEnablePaging, use default */ + /* layer->vtable->LayerGetPaging, use default */ + + return MS_SUCCESS; +} diff --git a/src/maplegend.c b/src/maplegend.c new file mode 100644 index 0000000000..b8227c32d4 --- /dev/null +++ b/src/maplegend.c @@ -0,0 +1,1089 @@ +/****************************************************************************** + * $Id$ + * + * Project: MapServer + * Purpose: Legend generation. + * Author: Steve Lime and the MapServer team. + * + ****************************************************************************** + * Copyright (c) 1996-2005 Regents of the University of Minnesota. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + *****************************************************************************/ + +#include "mapserver.h" + +#define PSF .8 +#define VMARGIN 5 /* margin at top and bottom of legend graphic */ +#define HMARGIN 5 /* margin at left and right of legend graphic */ + +static int msDrawGradientSymbol(rendererVTableObj *renderer, + imageObj *image_draw, double x_center, + double y_center, int width, int height, + styleObj *style) { + unsigned char *r, *g, *b, *a; + symbolObj symbol; + rasterBufferObj *rb; + symbolStyleObj symbolStyle; + int ret; + + initSymbol(&symbol); + rb = (rasterBufferObj *)calloc(1, sizeof(rasterBufferObj)); + symbol.pixmap_buffer = rb; + rb->type = MS_BUFFER_BYTE_RGBA; + rb->width = width; + rb->height = height; + rb->data.rgba.row_step = rb->width * 4; + rb->data.rgba.pixel_step = 4; + rb->data.rgba.pixels = (unsigned char *)malloc(sizeof(unsigned char) * + rb->width * rb->height * 4); + b = rb->data.rgba.b = &rb->data.rgba.pixels[0]; + g = rb->data.rgba.g = &rb->data.rgba.pixels[1]; + r = rb->data.rgba.r = &rb->data.rgba.pixels[2]; + a = rb->data.rgba.a = &rb->data.rgba.pixels[3]; + for (unsigned j = 0; j < rb->height; j++) { + for (unsigned i = 0; i < rb->width; i++) { + msValueToRange(style, + style->minvalue + (double)i / rb->width * + (style->maxvalue - style->minvalue), + MS_COLORSPACE_RGB); + b[4 * (j * rb->width + i)] = style->color.blue; + g[4 * (j * rb->width + i)] = style->color.green; + r[4 * (j * rb->width + i)] = style->color.red; + if (strncasecmp(image_draw->format->driver, "AGG/", 4) == 0) { + a[4 * (j * rb->width + i)] = 255; // Apply alpha later + } else { + a[4 * (j * rb->width + i)] = style->color.alpha; + } + } + } + INIT_SYMBOL_STYLE(symbolStyle); + symbolStyle.color = &style->color; + ret = renderer->renderPixmapSymbol(image_draw, x_center, y_center, &symbol, + &symbolStyle); + msFreeSymbol(&symbol); + return ret; +} + +/* + * generic function for drawing a legend icon. (added for bug #2348) + * renderer specific drawing functions shouldn't be called directly, but through + * this function + */ +int msDrawLegendIcon(mapObj *map, layerObj *lp, classObj *theclass, int width, + int height, imageObj *image, int dstX, int dstY, + int scale_independant, class_hittest *hittest) { + int i, type, hasmarkersymbol, ret = MS_SUCCESS; + double offset; + double polygon_contraction = + 0.5; /* used to account for the width of a polygon's outline */ + shapeObj box, zigzag; + lineObj box_line, zigzag_line; + pointObj box_point[5], zigzag_point[4]; + pointObj marker; + char szPath[MS_MAXPATHLEN]; + styleObj outline_style; + imageObj *image_draw = image; + rendererVTableObj *renderer; + outputFormatObj *transFormat = NULL, *altFormat = NULL; + const char *alternativeFormatString = NULL; + + if (!MS_RENDERER_PLUGIN(image->format)) { + msSetError(MS_MISCERR, "unsupported image format", "msDrawLegendIcon()"); + return MS_FAILURE; + } + + alternativeFormatString = msLayerGetProcessingKey(lp, "RENDERER"); + if (MS_RENDERER_PLUGIN(image_draw->format) && + alternativeFormatString != NULL && + (altFormat = msSelectOutputFormat(map, alternativeFormatString))) { + msInitializeRendererVTable(altFormat); + + image_draw = msImageCreate( + image->width, image->height, altFormat, image->imagepath, + image->imageurl, map->resolution, map->defresolution, &map->imagecolor); + image_draw->map = map; + renderer = MS_IMAGE_RENDERER(image_draw); + } else { + renderer = MS_IMAGE_RENDERER(image_draw); + if (lp->compositer && renderer->compositeRasterBuffer) { + image_draw = msImageCreate(image->width, image->height, image->format, + image->imagepath, image->imageurl, + map->resolution, map->defresolution, NULL); + if (!image_draw) { + msSetError(MS_MISCERR, + "Unable to initialize temporary transparent image.", + "msDrawLegendIcon()"); + return (MS_FAILURE); + } + image_draw->map = map; + } + } + + if (renderer->supports_clipping && MS_VALID_COLOR(map->legend.outlinecolor)) { + /* keep GD specific code here for now as it supports clipping */ + rectObj clip; + clip.maxx = dstX + width - 1; + clip.maxy = dstY + height - 1; + clip.minx = dstX; + clip.miny = dstY; + renderer->setClip(image_draw, clip); + } + + /* if the class has a keyimage, treat it as a point layer + * (the keyimage will be treated there) */ + if (theclass->keyimage != NULL) { + type = MS_LAYER_POINT; + } else { + /* some polygon layers may be better drawn using zigzag if there is no fill + */ + type = lp->type; + if (type == MS_LAYER_POLYGON) { + type = MS_LAYER_LINE; + for (i = 0; i < theclass->numstyles; i++) { + if (MS_VALID_COLOR(theclass->styles[i]->color)) { /* there is a fill */ + type = MS_LAYER_POLYGON; + } + if (MS_VALID_COLOR( + theclass->styles[i]->outlinecolor)) { /* there is an outline */ + polygon_contraction = + MS_MAX(polygon_contraction, theclass->styles[i]->width / 2.0); + } + } + } + } + + /* initialize the box used for polygons and for outlines */ + msInitShape(&box); + box.line = &box_line; + box.numlines = 1; + box.line[0].point = box_point; + box.line[0].numpoints = 5; + box.type = MS_SHAPE_POLYGON; + + box.line[0].point[0].x = dstX + polygon_contraction; + box.line[0].point[0].y = dstY + polygon_contraction; + box.line[0].point[1].x = dstX + width - polygon_contraction; + box.line[0].point[1].y = dstY + polygon_contraction; + box.line[0].point[2].x = dstX + width - polygon_contraction; + box.line[0].point[2].y = dstY + height - polygon_contraction; + box.line[0].point[3].x = dstX + polygon_contraction; + box.line[0].point[3].y = dstY + height - polygon_contraction; + box.line[0].point[4].x = box.line[0].point[0].x; + box.line[0].point[4].y = box.line[0].point[0].y; + + /* + ** now draw the appropriate color/symbol/size combination + */ + + /* Scalefactor will be infinity when SIZEUNITS is set in LAYER */ + if (lp->sizeunits != MS_PIXELS) { + lp->scalefactor = 1.0; + } + + switch (type) { + case MS_LAYER_POINT: + marker.x = dstX + MS_NINT(width / 2.0); + marker.y = dstY + MS_NINT(height / 2.0); + if (theclass->keyimage != NULL) { + int symbolNum; + styleObj imgStyle; + symbolObj *symbol = NULL; + symbolNum = + msAddImageSymbol(&(map->symbolset), msBuildPath(szPath, map->mappath, + theclass->keyimage)); + if (symbolNum == -1) { + msSetError(MS_IMGERR, "Failed to open legend key image", + "msCreateLegendIcon()"); + return (MS_FAILURE); + } + + symbol = map->symbolset.symbol[symbolNum]; + + initStyle(&imgStyle); + /*set size so that symbol will be scaled properly #3296*/ + if (width / symbol->sizex < height / symbol->sizey) + imgStyle.size = symbol->sizey * (width / symbol->sizex); + else + imgStyle.size = symbol->sizey * (height / symbol->sizey); + + if (imgStyle.size > imgStyle.maxsize) + imgStyle.maxsize = imgStyle.size; + + imgStyle.symbol = symbolNum; + ret = msDrawMarkerSymbol(map, image_draw, &marker, &imgStyle, 1.0); + if (MS_UNLIKELY(ret == MS_FAILURE)) + goto legend_icon_cleanup; + /* TO DO: we may want to handle this differently depending on the relative + * size of the keyimage */ + } else { + for (i = 0; i < theclass->numstyles; i++) { + if (!scale_independant && map->scaledenom > 0) { + styleObj *lp = theclass->styles[i]; + if ((lp->maxscaledenom > 0) && (map->scaledenom > lp->maxscaledenom)) + continue; + if ((lp->minscaledenom > 0) && (map->scaledenom <= lp->minscaledenom)) + continue; + } + if (hittest && hittest->stylehits[i].status == 0) + continue; + ret = msDrawMarkerSymbol(map, image_draw, &marker, theclass->styles[i], + lp->scalefactor * image->resolutionfactor); + if (MS_UNLIKELY(ret == MS_FAILURE)) + goto legend_icon_cleanup; + } + } + break; + case MS_LAYER_LINE: + offset = 1; + /* To set the offset, we only check the size/width parameter of the first + * style */ + if (theclass->numstyles > 0) { + if (theclass->styles[0]->symbol > 0 && + theclass->styles[0]->symbol < map->symbolset.numsymbols && + map->symbolset.symbol[theclass->styles[0]->symbol]->type != + MS_SYMBOL_SIMPLE) + offset = theclass->styles[0]->size / 2; + else + offset = theclass->styles[0]->width / 2; + } + msInitShape(&zigzag); + zigzag.line = &zigzag_line; + zigzag.numlines = 1; + zigzag.line[0].point = zigzag_point; + zigzag.line[0].numpoints = 4; + zigzag.type = MS_SHAPE_LINE; + + zigzag.line[0].point[0].x = dstX + offset; + zigzag.line[0].point[0].y = dstY + height - offset; + zigzag.line[0].point[1].x = dstX + MS_NINT(width / 3.0) - 1; + zigzag.line[0].point[1].y = dstY + offset; + zigzag.line[0].point[2].x = dstX + MS_NINT(2.0 * width / 3.0) - 1; + zigzag.line[0].point[2].y = dstY + height - offset; + zigzag.line[0].point[3].x = dstX + width - offset; + zigzag.line[0].point[3].y = dstY + offset; + + for (i = 0; i < theclass->numstyles; i++) { + if (!scale_independant && map->scaledenom > 0) { + styleObj *lp = theclass->styles[i]; + if ((lp->maxscaledenom > 0) && (map->scaledenom > lp->maxscaledenom)) + continue; + if ((lp->minscaledenom > 0) && (map->scaledenom <= lp->minscaledenom)) + continue; + } + if (hittest && hittest->stylehits[i].status == 0) + continue; + if (theclass->styles[i]->_geomtransform.type == MS_GEOMTRANSFORM_NONE || + theclass->styles[i]->_geomtransform.type == + MS_GEOMTRANSFORM_LABELPOINT || + theclass->styles[i]->_geomtransform.type == + MS_GEOMTRANSFORM_LABELPOLY) { + if (theclass->styles[i]->outlinewidth > 0) { + /* Swap the style contents to render the outline first, + * and then restore the style to render the interior of the line + */ + msOutlineRenderingPrepareStyle(theclass->styles[i], map, lp, image); + ret = + msDrawLineSymbol(map, image_draw, &zigzag, theclass->styles[i], + lp->scalefactor * image_draw->resolutionfactor); + msOutlineRenderingRestoreStyle(theclass->styles[i], map, lp, image); + if (MS_UNLIKELY(ret == MS_FAILURE)) + goto legend_icon_cleanup; + } + ret = msDrawLineSymbol(map, image_draw, &zigzag, theclass->styles[i], + lp->scalefactor * image_draw->resolutionfactor); + if (MS_UNLIKELY(ret == MS_FAILURE)) + goto legend_icon_cleanup; + } else { + if (theclass->styles[i]->outlinewidth > 0) { + /* Swap the style contents to render the outline first, + * and then restore the style to render the interior of the line + */ + msOutlineRenderingPrepareStyle(theclass->styles[i], map, lp, image); + ret = msDrawTransformedShape( + map, image_draw, &zigzag, theclass->styles[i], + lp->scalefactor * image_draw->resolutionfactor); + msOutlineRenderingRestoreStyle(theclass->styles[i], map, lp, image); + if (MS_UNLIKELY(ret == MS_FAILURE)) + goto legend_icon_cleanup; + } + ret = msDrawTransformedShape( + map, image_draw, &zigzag, theclass->styles[i], + lp->scalefactor * image_draw->resolutionfactor); + if (MS_UNLIKELY(ret == MS_FAILURE)) + goto legend_icon_cleanup; + } + } + + break; + case MS_LAYER_CIRCLE: + case MS_LAYER_RASTER: + case MS_LAYER_CHART: + case MS_LAYER_POLYGON: + for (i = 0; i < theclass->numstyles; i++) { + if (!scale_independant && map->scaledenom > 0) { + styleObj *lp = theclass->styles[i]; + if ((lp->maxscaledenom > 0) && (map->scaledenom > lp->maxscaledenom)) + continue; + if ((lp->minscaledenom > 0) && (map->scaledenom <= lp->minscaledenom)) + continue; + } + if (hittest && hittest->stylehits[i].status == 0) + continue; + if (theclass->styles[i]->_geomtransform.type == MS_GEOMTRANSFORM_NONE || + theclass->styles[i]->_geomtransform.type == + MS_GEOMTRANSFORM_LABELPOINT || + theclass->styles[i]->_geomtransform.type == + MS_GEOMTRANSFORM_LABELPOLY) { + + if (MS_VALID_COLOR(theclass->styles[i]->mincolor)) { + ret = msDrawGradientSymbol( + renderer, image_draw, dstX + width / 2., dstY + height / 2.0, + width - 2 * polygon_contraction, height - 2 * polygon_contraction, + theclass->styles[i]); + } else { + ret = + msDrawShadeSymbol(map, image_draw, &box, theclass->styles[i], + lp->scalefactor * image_draw->resolutionfactor); + } + if (MS_UNLIKELY(ret == MS_FAILURE)) + goto legend_icon_cleanup; + } else { + ret = msDrawTransformedShape(map, image_draw, &box, theclass->styles[i], + lp->scalefactor); + if (MS_UNLIKELY(ret == MS_FAILURE)) + goto legend_icon_cleanup; + } + } + break; + default: + return MS_FAILURE; + break; + } /* end symbol drawing */ + + /* handle label styles */ + for (i = 0; i < theclass->numlabels; i++) { + labelObj *l = theclass->labels[i]; + if (!scale_independant && map->scaledenom > 0) { + if (msScaleInBounds(map->scaledenom, l->minscaledenom, + l->maxscaledenom)) { + int j; + for (j = 0; j < l->numstyles; j++) { + styleObj *s = l->styles[j]; + marker.x = dstX + MS_NINT(width / 2.0); + marker.y = dstY + MS_NINT(height / 2.0); + if (s->_geomtransform.type == MS_GEOMTRANSFORM_LABELPOINT) { + ret = msDrawMarkerSymbol(map, image_draw, &marker, s, + lp->scalefactor); + if (MS_UNLIKELY(ret == MS_FAILURE)) + goto legend_icon_cleanup; + } + } + } + } + } + + /* handle "pure" text layers, i.e. layers with no symbology */ + hasmarkersymbol = 0; + if (theclass->numstyles == 0) { + for (i = 0; i < theclass->numlabels; i++) { + labelObj *l = theclass->labels[i]; + if (!scale_independant && map->scaledenom > 0) { + if (msScaleInBounds(map->scaledenom, l->minscaledenom, + l->maxscaledenom)) { + int j; + for (j = 0; j < l->numstyles; j++) { + styleObj *s = l->styles[j]; + if (s->_geomtransform.type == MS_GEOMTRANSFORM_LABELPOINT) { + hasmarkersymbol = 1; + } + } + } + } + } + } else { + hasmarkersymbol = 1; + } + + if (!hasmarkersymbol && theclass->numlabels > 0) { + textSymbolObj ts; + pointObj textstartpt; + marker.x = dstX + MS_NINT(width / 2.0); + marker.y = dstY + MS_NINT(height / 2.0); + initTextSymbol(&ts); + msPopulateTextSymbolForLabelAndString( + &ts, theclass->labels[0], msStrdup("Az"), + lp->scalefactor * image_draw->resolutionfactor, + image_draw->resolutionfactor, duplicate_always); + ts.label->size = height - 1; + ts.rotation = 0; + ret = msComputeTextPath(map, &ts); + if (MS_UNLIKELY(ret == MS_FAILURE)) + goto legend_icon_cleanup; + textstartpt = get_metrics(&marker, MS_CC, ts.textpath, 0, 0, 0, 0, NULL); + ret = msDrawTextSymbol(map, image_draw, textstartpt, &ts); + freeTextSymbol(&ts); + if (MS_UNLIKELY(ret == MS_FAILURE)) + goto legend_icon_cleanup; + } + + /* handle an outline if necessary */ + if (MS_VALID_COLOR(map->legend.outlinecolor)) { + initStyle(&outline_style); + outline_style.color = map->legend.outlinecolor; + ret = msDrawLineSymbol(map, image_draw, &box, &outline_style, + image_draw->resolutionfactor); + if (MS_UNLIKELY(ret == MS_FAILURE)) + goto legend_icon_cleanup; + /* reset clipping rectangle */ + if (renderer->supports_clipping) + renderer->resetClip(image_draw); + } + + if (altFormat) { + rendererVTableObj *renderer = MS_IMAGE_RENDERER(image); + rendererVTableObj *altrenderer = MS_IMAGE_RENDERER(image_draw); + rasterBufferObj rb; + memset(&rb, 0, sizeof(rasterBufferObj)); + + ret = altrenderer->getRasterBufferHandle(image_draw, &rb); + if (MS_UNLIKELY(ret == MS_FAILURE)) + goto legend_icon_cleanup; + ret = renderer->mergeRasterBuffer( + image, &rb, ((lp->compositer) ? lp->compositer->opacity * 0.01 : 1.0), + 0, 0, 0, 0, rb.width, rb.height); + if (MS_UNLIKELY(ret == MS_FAILURE)) + goto legend_icon_cleanup; + /* + * hack to work around bug #3834: if we have use an alternate renderer, the + * symbolset may contain symbols that reference it. We want to remove those + * references before the altFormat is destroyed to avoid a segfault and/or a + * leak, and so the the main renderer doesn't pick the cache up thinking + * it's for him. + */ + for (i = 0; i < map->symbolset.numsymbols; i++) { + if (map->symbolset.symbol[i] != NULL) { + symbolObj *s = map->symbolset.symbol[i]; + if (s->renderer == altrenderer) { + altrenderer->freeSymbol(s); + s->renderer = NULL; + } + } + } + + } else if (image != image_draw) { + rendererVTableObj *renderer = MS_IMAGE_RENDERER(image_draw); + rasterBufferObj rb; + memset(&rb, 0, sizeof(rasterBufferObj)); + + ret = renderer->getRasterBufferHandle(image_draw, &rb); + if (MS_UNLIKELY(ret == MS_FAILURE)) + goto legend_icon_cleanup; + ret = renderer->mergeRasterBuffer( + image, &rb, ((lp->compositer) ? lp->compositer->opacity * 0.01 : 1.0), + 0, 0, 0, 0, rb.width, rb.height); + if (MS_UNLIKELY(ret == MS_FAILURE)) + goto legend_icon_cleanup; + + /* deref and possibly free temporary transparent output format. */ + msApplyOutputFormat(&transFormat, NULL, MS_NOOVERRIDE); + } + +legend_icon_cleanup: + if (image != image_draw) { + msFreeImage(image_draw); + } + return ret; +} + +imageObj *msCreateLegendIcon(mapObj *map, layerObj *lp, classObj *class, + int width, int height, int scale_independant) { + imageObj *image; + outputFormatObj *format = NULL; + + rendererVTableObj *renderer = MS_MAP_RENDERER(map); + + if (!renderer) { + msSetError(MS_MISCERR, "invalid map outputformat", "msCreateLegendIcon()"); + return (NULL); + } + + /* ensure we have an image format representing the options for the legend */ + msApplyOutputFormat(&format, map->outputformat, map->legend.transparent); + + image = msImageCreate(width, height, format, map->web.imagepath, + map->web.imageurl, map->resolution, map->defresolution, + &(map->legend.imagecolor)); + + /* drop this reference to output format */ + msApplyOutputFormat(&format, NULL, MS_NOOVERRIDE); + + if (image == NULL) { + msSetError(MS_IMGERR, "Unable to initialize image.", + "msCreateLegendIcon()"); + return (NULL); + } + image->map = map; + + /* Call drawLegendIcon with destination (0, 0) */ + /* Return an empty image if lp==NULL || class=NULL */ + /* (If class is NULL draw the legend for all classes. Modifications done */ + /* Fev 2004 by AY) */ + if (lp) { + if (class) { + if (MS_UNLIKELY(MS_FAILURE == + msDrawLegendIcon(map, lp, class, width, height, image, 0, + 0, scale_independant, NULL))) { + msFreeImage(image); + return NULL; + } + } else { + for (int i = 0; i < lp->numclasses; i++) { + if (MS_UNLIKELY(MS_FAILURE == msDrawLegendIcon(map, lp, lp->class[i], + width, height, image, 0, + 0, scale_independant, + NULL))) { + msFreeImage(image); + return NULL; + } + } + } + } + return image; +} + +/* + * Calculates the optimal size for the legend. If the optional layerObj + * argument is given, the legend size will be calculated for only that + * layer. Otherwise, the legend size is calculated for all layers that + * are not MS_OFF or of MS_LAYER_QUERY type. + * + * Returns one of: + * MS_SUCCESS + * MS_FAILURE + */ +int msLegendCalcSize(mapObj *map, int scale_independent, int *size_x, + int *size_y, int *layer_index, int num_layers, + map_hittest *hittest, double resolutionfactor) { + int i, j; + int status, maxwidth = 0, nLegendItems = 0; + char *text; + layerObj *lp; + rectObj rect; + int current_layers = 0; + + /* reset sizes */ + *size_x = 0; + *size_y = 0; + + /* enable scale-dependent calculations */ + if (!scale_independent) { + map->cellsize = msAdjustExtent(&(map->extent), map->width, map->height); + status = msCalculateScale(map->extent, map->units, map->width, map->height, + map->resolution, &map->scaledenom); + if (status != MS_SUCCESS) + return MS_FAILURE; + } + + /* + * step through all map classes, and for each one that will be displayed + * calculate the label size + */ + if (layer_index != NULL && num_layers > 0) + current_layers = num_layers; + else + current_layers = map->numlayers; + + for (i = 0; i < current_layers; i++) { + int layerindex; + if (layer_index != NULL && num_layers > 0) + layerindex = layer_index[i]; + else + layerindex = map->layerorder[i]; + + lp = (GET_LAYER(map, layerindex)); + + if ((lp->status == MS_OFF && (layer_index == NULL || num_layers <= 0)) || + (lp->type == MS_LAYER_QUERY)) /* skip it */ + continue; + + if (hittest && hittest->layerhits[layerindex].status == 0) + continue; + + if (!scale_independent && map->scaledenom > 0) { + if ((lp->maxscaledenom > 0) && (map->scaledenom > lp->maxscaledenom)) + continue; + if ((lp->minscaledenom > 0) && (map->scaledenom <= lp->minscaledenom)) + continue; + } + + for (j = lp->numclasses - 1; j >= 0; j--) { + textSymbolObj ts; + text = lp->class[j]->title + ? lp->class[j]->title + : lp->class[j]->name; /* point to the right legend text, title + takes precedence */ + if (!text) + continue; /* skip it */ + + /* skip the class if the classgroup is defined */ + if (lp->classgroup && + (lp->class[j] -> group == NULL || strcasecmp(lp->class[j] -> group, + lp -> classgroup) != 0)) + continue; + + /* verify class scale */ + if (!scale_independent && map->scaledenom > 0) { + if ((lp->class[j] -> maxscaledenom > 0) && + (map->scaledenom > lp->class[j] -> maxscaledenom)) + continue; + if ((lp->class[j] -> minscaledenom > 0) && + (map->scaledenom <= lp->class[j] -> minscaledenom)) + continue; + } + if (hittest && hittest->layerhits[layerindex].classhits[j].status == 0) + continue; + + if (*text) { + initTextSymbol(&ts); + msPopulateTextSymbolForLabelAndString(&ts, &map->legend.label, + msStrdup(text), resolutionfactor, + resolutionfactor, 0); + if (MS_UNLIKELY(MS_FAILURE == msGetTextSymbolSize(map, &ts, &rect))) { + freeTextSymbol(&ts); + return MS_FAILURE; + } + freeTextSymbol(&ts); + + maxwidth = MS_MAX(maxwidth, MS_NINT(rect.maxx - rect.minx)); + *size_y += MS_MAX(MS_NINT(rect.maxy - rect.miny), map->legend.keysizey); + } else { + *size_y += map->legend.keysizey; + } + nLegendItems++; + } + } + + /* Calculate the size of the legend: */ + /* - account for the Y keyspacing */ + *size_y += (2 * VMARGIN) + ((nLegendItems - 1) * map->legend.keyspacingy); + /* - determine the legend width */ + *size_x = + (2 * HMARGIN) + maxwidth + map->legend.keyspacingx + map->legend.keysizex; + + if (*size_y <= 0 || *size_x <= 0) + return MS_FAILURE; + + return MS_SUCCESS; +} + +/* +** Creates a GD image of a legend for a specific map. msDrawLegend() +** respects the current scale, and classes without a name are not +** added to the legend. +** +** scale_independent is used for WMS GetLegendGraphic. It should be set to +** MS_FALSE in most cases. If it is set to MS_TRUE then the layers' minscale +** and maxscale are ignored and layers that are currently out of scale still +** show up in the legend. +*/ +imageObj *msDrawLegend(mapObj *map, int scale_independent, + map_hittest *hittest) { + int i, j, ret = MS_SUCCESS; /* loop counters */ + pointObj pnt; + int size_x, size_y = 0; + layerObj *lp; + rectObj rect; + imageObj *image = NULL; + outputFormatObj *format = NULL; + char *text; + + struct legend_struct { + int height; + textSymbolObj ts; + int layerindex, classindex; + struct legend_struct *pred; + }; + typedef struct legend_struct legendlabel; + legendlabel *head = NULL; + + if (!MS_RENDERER_PLUGIN(map->outputformat)) { + msSetError(MS_MISCERR, "unsupported output format", "msDrawLegend()"); + return NULL; + } + if (msValidateContexts(map) != MS_SUCCESS) + return NULL; /* make sure there are no recursive REQUIRES or LABELREQUIRES + expressions */ + if (msLegendCalcSize(map, scale_independent, &size_x, &size_y, NULL, 0, + hittest, + map->resolution / map->defresolution) != MS_SUCCESS) + return NULL; + + /* + * step through all map classes, and for each one that will be displayed + * keep a reference to its label size and text + */ + + for (i = 0; i < map->numlayers; i++) { + lp = (GET_LAYER(map, map->layerorder[i])); + + if ((lp->status == MS_OFF) || (lp->type == MS_LAYER_QUERY)) /* skip it */ + continue; + + if (hittest && hittest->layerhits[map->layerorder[i]].status == 0) + continue; + + if (!scale_independent && map->scaledenom > 0) { + if ((lp->maxscaledenom > 0) && (map->scaledenom > lp->maxscaledenom)) + continue; + if ((lp->minscaledenom > 0) && (map->scaledenom <= lp->minscaledenom)) + continue; + } + + if (!scale_independent && lp->maxscaledenom <= 0 && + lp->minscaledenom <= 0) { + if ((lp->maxgeowidth > 0) && + ((map->extent.maxx - map->extent.minx) > lp->maxgeowidth)) + continue; + if ((lp->mingeowidth > 0) && + ((map->extent.maxx - map->extent.minx) < lp->mingeowidth)) + continue; + } + + /* set the scale factor so that scale dependent symbols are drawn in the + * legend with their default size */ + if (lp->sizeunits != MS_PIXELS) { + map->cellsize = msAdjustExtent(&(map->extent), map->width, map->height); + lp->scalefactor = + (msInchesPerUnit(lp->sizeunits, 0) / msInchesPerUnit(map->units, 0)) / + map->cellsize; + } + + for (j = lp->numclasses - 1; j >= 0; j--) { + text = lp->class[j]->title + ? lp->class[j]->title + : lp->class[j]->name; /* point to the right legend text, title + takes precedence */ + if (!text) + continue; /* skip it */ + + /* skip the class if the classgroup is defined */ + if (lp->classgroup && + (lp->class[j] -> group == NULL || strcasecmp(lp->class[j] -> group, + lp -> classgroup) != 0)) + continue; + + if (!scale_independent && + map->scaledenom > 0) { /* verify class scale here */ + if ((lp->class[j] -> maxscaledenom > 0) && + (map->scaledenom > lp->class[j] -> maxscaledenom)) + continue; + if ((lp->class[j] -> minscaledenom > 0) && + (map->scaledenom <= lp->class[j] -> minscaledenom)) + continue; + } + + if (hittest && + hittest->layerhits[map->layerorder[i]].classhits[j].status == 0) { + continue; + } + + legendlabel *cur = (legendlabel *)msSmallMalloc(sizeof(legendlabel)); + initTextSymbol(&cur->ts); + if (*text) { + msPopulateTextSymbolForLabelAndString( + &cur->ts, &map->legend.label, msStrdup(text), + map->resolution / map->defresolution, + map->resolution / map->defresolution, 0); + if (MS_UNLIKELY(MS_FAILURE == msComputeTextPath(map, &cur->ts))) { + ret = MS_FAILURE; + goto cleanup; + } + if (MS_UNLIKELY(MS_FAILURE == + msGetTextSymbolSize(map, &cur->ts, &rect))) { + ret = MS_FAILURE; + goto cleanup; + } + cur->height = + MS_MAX(MS_NINT(rect.maxy - rect.miny), map->legend.keysizey); + } else { + cur->height = map->legend.keysizey; + } + + cur->classindex = j; + cur->layerindex = map->layerorder[i]; + cur->pred = head; + head = cur; + } + } + + /* ensure we have an image format representing the options for the legend. */ + msApplyOutputFormat(&format, map->outputformat, map->legend.transparent); + + /* initialize the legend image */ + image = msImageCreate(size_x, size_y, format, map->web.imagepath, + map->web.imageurl, map->resolution, map->defresolution, + &map->legend.imagecolor); + if (!image) { + msSetError(MS_MISCERR, "Unable to initialize image.", "msDrawLegend()"); + return NULL; + } + image->map = map; + + /* image = + * renderer->createImage(size_x,size_y,format,&(map->legend.imagecolor)); */ + + /* drop this reference to output format */ + msApplyOutputFormat(&format, NULL, MS_NOOVERRIDE); + + pnt.y = VMARGIN; + pnt.x = HMARGIN + map->legend.keysizex + map->legend.keyspacingx; + + while (head) { /* head initially points on the last legend item, i.e. the one + that should be at the top */ + legendlabel *cur = head; + class_hittest *ch = NULL; + + /* set the scale factor so that scale dependent symbols are drawn in the + * legend with their default size */ + if (map->layers[cur->layerindex]->sizeunits != MS_PIXELS) { + map->cellsize = msAdjustExtent(&(map->extent), map->width, map->height); + map->layers[cur->layerindex]->scalefactor = + (msInchesPerUnit(map->layers[cur->layerindex]->sizeunits, 0) / + msInchesPerUnit(map->units, 0)) / + map->cellsize; + } + if (hittest) { + ch = &hittest->layerhits[cur->layerindex].classhits[cur->classindex]; + } + ret = msDrawLegendIcon(map, map->layers[cur->layerindex], + map->layers[cur->layerindex]->class[cur->classindex], + map -> legend.keysizex, map->legend.keysizey, image, + HMARGIN, (int)pnt.y, scale_independent, ch); + if (MS_UNLIKELY(ret != MS_SUCCESS)) + goto cleanup; + + pnt.y += cur->height; + + if (cur->ts.annotext) { + pointObj textPnt = pnt; + textPnt.y -= cur->ts.textpath->bounds.bbox.maxy; + textPnt.y += map->legend.label.offsety; + textPnt.x += map->legend.label.offsetx; + ret = msDrawTextSymbol(map, image, textPnt, &cur->ts); + if (MS_UNLIKELY(ret == MS_FAILURE)) + goto cleanup; + /* Coverity Scan is confused by label refcount, and wrongly believe we */ + /* might free &map->legend.label, so make it clear we won't */ + freeTextSymbolEx(&cur->ts, MS_FALSE); + MS_REFCNT_DECR(cur->ts.label); + } + + pnt.y += map->legend.keyspacingy; /* bump y for next label */ + + /* clean up */ + head = cur->pred; + free(cur); + } /* next legend */ + +cleanup: + while (head) { + legendlabel *cur = head; + /* Coverity Scan is confused by label refcount, and wrongly believe we */ + /* might free &map->legend.label, so make it clear we won't */ + freeTextSymbolEx(&cur->ts, MS_FALSE); + MS_REFCNT_DECR(cur->ts.label); + head = cur->pred; + free(cur); + } + if (MS_UNLIKELY(ret != MS_SUCCESS)) { + if (image) + msFreeImage(image); + return NULL; + } + return (image); +} + +/* TODO */ +int msEmbedLegend(mapObj *map, imageObj *img) { + pointObj point; + imageObj *image = NULL; + symbolObj *legendSymbol; + char *imageType = NULL; + const char *const LEGEND_SYMBOL_NAME = "legend"; + + rendererVTableObj *renderer; + + int symbolIdx = + msGetSymbolIndex(&(map->symbolset), LEGEND_SYMBOL_NAME, MS_FALSE); + if (symbolIdx != -1) + msRemoveSymbol(&(map->symbolset), + symbolIdx); /* solves some caching issues in AGG with + long-running processes */ + + if (msGrowSymbolSet(&map->symbolset) == NULL) + return -1; + symbolIdx = map->symbolset.numsymbols; + legendSymbol = map->symbolset.symbol[symbolIdx]; + map->symbolset.numsymbols++; + initSymbol(legendSymbol); + + if (!MS_RENDERER_PLUGIN(map->outputformat) || + !MS_MAP_RENDERER(map)->supports_pixel_buffer) { + imageType = msStrdup(map->imagetype); /* save format */ + if MS_DRIVER_CAIRO (map->outputformat) + map->outputformat = msSelectOutputFormat(map, "cairopng"); + else + map->outputformat = msSelectOutputFormat(map, "png"); + + msInitializeRendererVTable(map->outputformat); + } + renderer = MS_MAP_RENDERER(map); + + /* render the legend. */ + image = msDrawLegend(map, MS_FALSE, NULL); + if (image == NULL) { + msFree(imageType); + return MS_FAILURE; + } + + if (imageType) { + map->outputformat = + msSelectOutputFormat(map, imageType); /* restore format */ + msFree(imageType); + } + + /* copy renderered legend image into symbol */ + legendSymbol->pixmap_buffer = calloc(1, sizeof(rasterBufferObj)); + MS_CHECK_ALLOC(legendSymbol->pixmap_buffer, sizeof(rasterBufferObj), + MS_FAILURE); + + if (MS_SUCCESS != + renderer->getRasterBufferCopy(image, legendSymbol->pixmap_buffer)) + return MS_FAILURE; + legendSymbol->renderer = renderer; + + msFreeImage(image); + + if (!legendSymbol->pixmap_buffer) + return (MS_FAILURE); /* something went wrong creating scalebar */ + + legendSymbol->type = MS_SYMBOL_PIXMAP; /* initialize a few things */ + legendSymbol->name = msStrdup(LEGEND_SYMBOL_NAME); + legendSymbol->sizex = legendSymbol->pixmap_buffer->width; + legendSymbol->sizey = legendSymbol->pixmap_buffer->height; + + /* I'm not too sure this test is sufficient ... NFW. */ + /* if(map->legend.transparent == MS_ON) */ + /* gdImageColorTransparent(legendSymbol->img_deprecated, 0); */ + + switch (map->legend.position) { + case (MS_LL): + point.x = MS_NINT(legendSymbol->sizex / 2.0); + point.y = map->height - MS_NINT(legendSymbol->sizey / 2.0); + break; + case (MS_LR): + point.x = map->width - MS_NINT(legendSymbol->sizex / 2.0); + point.y = map->height - MS_NINT(legendSymbol->sizey / 2.0); + break; + case (MS_LC): + point.x = MS_NINT(map->width / 2.0); + point.y = map->height - MS_NINT(legendSymbol->sizey / 2.0); + break; + case (MS_UR): + point.x = map->width - MS_NINT(legendSymbol->sizex / 2.0); + point.y = MS_NINT(legendSymbol->sizey / 2.0); + break; + case (MS_UL): + point.x = MS_NINT(legendSymbol->sizex / 2.0); + point.y = MS_NINT(legendSymbol->sizey / 2.0); + break; + case (MS_UC): + point.x = MS_NINT(map->width / 2.0); + point.y = MS_NINT(legendSymbol->sizey / 2.0); + break; + } + + const char *const EMBED_LEGEND_LAYER_NAME = "__embed__legend"; + int layerIdx = msGetLayerIndex(map, EMBED_LEGEND_LAYER_NAME); + if (layerIdx == -1) { + if (msGrowMapLayers(map) == NULL) + return (-1); + layerIdx = map->numlayers; + map->numlayers++; + layerObj *layer = GET_LAYER(map, layerIdx); + if (initLayer(layer, map) == -1) + return (-1); + layer->name = msStrdup(EMBED_LEGEND_LAYER_NAME); + layer->type = MS_LAYER_POINT; + + if (msGrowLayerClasses(layer) == NULL) + return (-1); + if (initClass(layer->class[0]) == -1) + return (-1); + layer->numclasses = 1; /* so we make sure to free it */ + + /* update the layer order list with the layer's index. */ + map->layerorder[layerIdx] = layerIdx; + } + + layerObj *layer = GET_LAYER(map, layerIdx); + + layer->status = MS_ON; + + classObj *klass = layer->class[0]; + if (map->legend.postlabelcache) { /* add it directly to the image */ + if (MS_UNLIKELY(msMaybeAllocateClassStyle(klass, 0) == MS_FAILURE)) + return MS_FAILURE; + klass->styles[0]->symbol = symbolIdx; + if (MS_UNLIKELY(MS_FAILURE == msDrawMarkerSymbol(map, img, &point, + klass->styles[0], 1.0))) + return MS_FAILURE; + } else { + if (!klass->labels) { + if (msGrowClassLabels(klass) == NULL) + return MS_FAILURE; + labelObj *label = klass->labels[0]; + initLabel(label); + klass->numlabels = 1; + label->force = MS_TRUE; + label->size = + MS_MEDIUM; /* must set a size to have a valid label definition */ + label->priority = MS_MAX_LABEL_PRIORITY; + } + labelObj *label = klass->labels[0]; + if (label->numstyles == 0) { + if (msGrowLabelStyles(label) == NULL) + return (MS_FAILURE); + label->numstyles = 1; + initStyle(label->styles[0]); + label->styles[0]->_geomtransform.type = MS_GEOMTRANSFORM_LABELPOINT; + } + label->styles[0]->symbol = symbolIdx; + if (MS_UNLIKELY(MS_FAILURE == msAddLabel(map, img, label, layerIdx, 0, NULL, + &point, -1, NULL))) + return MS_FAILURE; + } + + /* Mark layer as deleted so that it doesn't interfere with html legends or + * with saving maps */ + layer->status = MS_DELETE; + + return MS_SUCCESS; +} diff --git a/src/maplexer.c b/src/maplexer.c new file mode 100644 index 0000000000..87c289deaf --- /dev/null +++ b/src/maplexer.c @@ -0,0 +1,5608 @@ +#line 2 "src/maplexer.c" + +#line 4 "src/maplexer.c" + +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + +#define yy_create_buffer msyy_create_buffer +#define yy_delete_buffer msyy_delete_buffer +#define yy_scan_buffer msyy_scan_buffer +#define yy_scan_string msyy_scan_string +#define yy_scan_bytes msyy_scan_bytes +#define yy_init_buffer msyy_init_buffer +#define yy_flush_buffer msyy_flush_buffer +#define yy_load_buffer_state msyy_load_buffer_state +#define yy_switch_to_buffer msyy_switch_to_buffer +#define yypush_buffer_state msyypush_buffer_state +#define yypop_buffer_state msyypop_buffer_state +#define yyensure_buffer_stack msyyensure_buffer_stack +#define yy_flex_debug msyy_flex_debug +#define yyin msyyin +#define yyleng msyyleng +#define yylex msyylex +#define yylineno msyylineno +#define yyout msyyout +#define yyrestart msyyrestart +#define yytext msyytext +#define yywrap msyywrap +#define yyalloc msyyalloc +#define yyrealloc msyyrealloc +#define yyfree msyyfree + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 6 +#define YY_FLEX_SUBMINOR_VERSION 4 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + +#ifdef yy_create_buffer +#define msyy_create_buffer_ALREADY_DEFINED +#else +#define yy_create_buffer msyy_create_buffer +#endif + +#ifdef yy_delete_buffer +#define msyy_delete_buffer_ALREADY_DEFINED +#else +#define yy_delete_buffer msyy_delete_buffer +#endif + +#ifdef yy_scan_buffer +#define msyy_scan_buffer_ALREADY_DEFINED +#else +#define yy_scan_buffer msyy_scan_buffer +#endif + +#ifdef yy_scan_string +#define msyy_scan_string_ALREADY_DEFINED +#else +#define yy_scan_string msyy_scan_string +#endif + +#ifdef yy_scan_bytes +#define msyy_scan_bytes_ALREADY_DEFINED +#else +#define yy_scan_bytes msyy_scan_bytes +#endif + +#ifdef yy_init_buffer +#define msyy_init_buffer_ALREADY_DEFINED +#else +#define yy_init_buffer msyy_init_buffer +#endif + +#ifdef yy_flush_buffer +#define msyy_flush_buffer_ALREADY_DEFINED +#else +#define yy_flush_buffer msyy_flush_buffer +#endif + +#ifdef yy_load_buffer_state +#define msyy_load_buffer_state_ALREADY_DEFINED +#else +#define yy_load_buffer_state msyy_load_buffer_state +#endif + +#ifdef yy_switch_to_buffer +#define msyy_switch_to_buffer_ALREADY_DEFINED +#else +#define yy_switch_to_buffer msyy_switch_to_buffer +#endif + +#ifdef yypush_buffer_state +#define msyypush_buffer_state_ALREADY_DEFINED +#else +#define yypush_buffer_state msyypush_buffer_state +#endif + +#ifdef yypop_buffer_state +#define msyypop_buffer_state_ALREADY_DEFINED +#else +#define yypop_buffer_state msyypop_buffer_state +#endif + +#ifdef yyensure_buffer_stack +#define msyyensure_buffer_stack_ALREADY_DEFINED +#else +#define yyensure_buffer_stack msyyensure_buffer_stack +#endif + +#ifdef yylex +#define msyylex_ALREADY_DEFINED +#else +#define yylex msyylex +#endif + +#ifdef yyrestart +#define msyyrestart_ALREADY_DEFINED +#else +#define yyrestart msyyrestart +#endif + +#ifdef yylex_init +#define msyylex_init_ALREADY_DEFINED +#else +#define yylex_init msyylex_init +#endif + +#ifdef yylex_init_extra +#define msyylex_init_extra_ALREADY_DEFINED +#else +#define yylex_init_extra msyylex_init_extra +#endif + +#ifdef yylex_destroy +#define msyylex_destroy_ALREADY_DEFINED +#else +#define yylex_destroy msyylex_destroy +#endif + +#ifdef yyget_debug +#define msyyget_debug_ALREADY_DEFINED +#else +#define yyget_debug msyyget_debug +#endif + +#ifdef yyset_debug +#define msyyset_debug_ALREADY_DEFINED +#else +#define yyset_debug msyyset_debug +#endif + +#ifdef yyget_extra +#define msyyget_extra_ALREADY_DEFINED +#else +#define yyget_extra msyyget_extra +#endif + +#ifdef yyset_extra +#define msyyset_extra_ALREADY_DEFINED +#else +#define yyset_extra msyyset_extra +#endif + +#ifdef yyget_in +#define msyyget_in_ALREADY_DEFINED +#else +#define yyget_in msyyget_in +#endif + +#ifdef yyset_in +#define msyyset_in_ALREADY_DEFINED +#else +#define yyset_in msyyset_in +#endif + +#ifdef yyget_out +#define msyyget_out_ALREADY_DEFINED +#else +#define yyget_out msyyget_out +#endif + +#ifdef yyset_out +#define msyyset_out_ALREADY_DEFINED +#else +#define yyset_out msyyset_out +#endif + +#ifdef yyget_leng +#define msyyget_leng_ALREADY_DEFINED +#else +#define yyget_leng msyyget_leng +#endif + +#ifdef yyget_text +#define msyyget_text_ALREADY_DEFINED +#else +#define yyget_text msyyget_text +#endif + +#ifdef yyget_lineno +#define msyyget_lineno_ALREADY_DEFINED +#else +#define yyget_lineno msyyget_lineno +#endif + +#ifdef yyset_lineno +#define msyyset_lineno_ALREADY_DEFINED +#else +#define yyset_lineno msyyset_lineno +#endif + +#ifdef yywrap +#define msyywrap_ALREADY_DEFINED +#else +#define yywrap msyywrap +#endif + +#ifdef yyalloc +#define msyyalloc_ALREADY_DEFINED +#else +#define yyalloc msyyalloc +#endif + +#ifdef yyrealloc +#define msyyrealloc_ALREADY_DEFINED +#else +#define yyrealloc msyyrealloc +#endif + +#ifdef yyfree +#define msyyfree_ALREADY_DEFINED +#else +#define yyfree msyyfree +#endif + +#ifdef yytext +#define msyytext_ALREADY_DEFINED +#else +#define yytext msyytext +#endif + +#ifdef yyleng +#define msyyleng_ALREADY_DEFINED +#else +#define yyleng msyyleng +#endif + +#ifdef yyin +#define msyyin_ALREADY_DEFINED +#else +#define yyin msyyin +#endif + +#ifdef yyout +#define msyyout_ALREADY_DEFINED +#else +#define yyout msyyout +#endif + +#ifdef yy_flex_debug +#define msyy_flex_debug_ALREADY_DEFINED +#else +#define yy_flex_debug msyy_flex_debug +#endif + +#ifdef yylineno +#define msyylineno_ALREADY_DEFINED +#else +#define yylineno msyylineno +#endif + +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +#include +#include +#include +#include + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have . Non-C99 systems may or may not. */ + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#ifndef SIZE_MAX +#define SIZE_MAX (~(size_t)0) +#endif + +#endif /* ! C99 */ + +#endif /* ! FLEXINT_H */ + +/* begin standard C++ headers. */ + +/* TODO: this is always defined, so inline it */ +#define yyconst const + +#if defined(__GNUC__) && __GNUC__ >= 3 +#define yynoreturn __attribute__((__noreturn__)) +#else +#define yynoreturn +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an + * integer in range [0..255] for use as an array index. + */ +#define YY_SC_TO_UI(c) ((YY_CHAR) (c)) + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN (yy_start) = 1 + 2 * +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START (((yy_start) - 1) / 2) +#define YYSTATE YY_START +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE yyrestart( yyin ) +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#ifndef YY_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k. + * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. + * Ditto for the __ia64__ case accordingly. + */ +#define YY_BUF_SIZE 32768 +#else +#define YY_BUF_SIZE 16384 +#endif /* __ia64__ */ +#endif + +/* The state buf must be large enough to hold one state per character in the main buffer. + */ +#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef size_t yy_size_t; +#endif + +extern int yyleng; + +extern FILE *yyin, *yyout; + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + + #define YY_LESS_LINENO(n) + #define YY_LINENO_REWIND_TO(ptr) + +/* Return all but the first "n" matched characters back to the input stream. */ +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + *yy_cp = (yy_hold_char); \ + YY_RESTORE_YY_MORE_OFFSET \ + (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) +#define unput(c) yyunput( c, (yytext_ptr) ) + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + int yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; + +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via yyrestart()), so that the user can continue scanning by + * just pointing yyin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +/* Stack of input buffers. */ +static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */ +static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */ +static YY_BUFFER_STATE * yy_buffer_stack = NULL; /**< Stack as an array. */ + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + * + * Returns the top of the stack, or NULL. + */ +#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \ + ? (yy_buffer_stack)[(yy_buffer_stack_top)] \ + : NULL) +/* Same as previous macro, but useful when we know that the buffer stack is not + * NULL or when we need an lvalue. For internal use only. + */ +#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)] + +/* yy_hold_char holds the character lost when yytext is formed. */ +static char yy_hold_char; +static int yy_n_chars; /* number of characters read into yy_ch_buf */ +int yyleng; + +/* Points to current character in buffer. */ +static char *yy_c_buf_p = NULL; +static int yy_init = 0; /* whether we need to initialize */ +static int yy_start = 0; /* start state number */ + +/* Flag which is used to allow yywrap()'s to do buffer switches + * instead of setting up a fresh yyin. A bit of a hack ... + */ +static int yy_did_buffer_switch_on_eof; + +void yyrestart ( FILE *input_file ); +void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer ); +YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size ); +void yy_delete_buffer ( YY_BUFFER_STATE b ); +void yy_flush_buffer ( YY_BUFFER_STATE b ); +void yypush_buffer_state ( YY_BUFFER_STATE new_buffer ); +void yypop_buffer_state ( void ); + +static void yyensure_buffer_stack ( void ); +static void yy_load_buffer_state ( void ); +static void yy_init_buffer ( YY_BUFFER_STATE b, FILE *file ); +#define YY_FLUSH_BUFFER yy_flush_buffer( YY_CURRENT_BUFFER ) + +YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size ); +YY_BUFFER_STATE yy_scan_string ( const char *yy_str ); +YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len ); + +void *yyalloc ( yy_size_t ); +void *yyrealloc ( void *, yy_size_t ); +void yyfree ( void * ); + +#define yy_new_buffer yy_create_buffer +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! YY_CURRENT_BUFFER ){ \ + yyensure_buffer_stack (); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer( yyin, YY_BUF_SIZE ); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ + } +#define yy_set_bol(at_bol) \ + { \ + if ( ! YY_CURRENT_BUFFER ){\ + yyensure_buffer_stack (); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer( yyin, YY_BUF_SIZE ); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ + } +#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) + +/* Begin user sect3 */ +typedef flex_uint8_t YY_CHAR; + +FILE *yyin = NULL, *yyout = NULL; + +typedef int yy_state_type; + +extern int yylineno; +int yylineno = 1; + +extern char *yytext; +#ifdef yytext_ptr +#undef yytext_ptr +#endif +#define yytext_ptr yytext + +static yy_state_type yy_get_previous_state ( void ); +static yy_state_type yy_try_NUL_trans ( yy_state_type current_state ); +static int yy_get_next_buffer ( void ); +static void yynoreturn yy_fatal_error ( const char* msg ); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up yytext. + */ +#define YY_DO_BEFORE_ACTION \ + (yytext_ptr) = yy_bp; \ + yyleng = (int) (yy_cp - yy_bp); \ + (yy_hold_char) = *yy_cp; \ + *yy_cp = '\0'; \ + (yy_c_buf_p) = yy_cp; +#define YY_NUM_RULES 348 +#define YY_END_OF_BUFFER 349 +/* This struct is not used in this scanner, + but its presence is necessary. */ +struct yy_trans_info + { + flex_int32_t yy_verify; + flex_int32_t yy_nxt; + }; +static const flex_int16_t yy_accept[1760] = + { 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 349, 346, 1, 344, 337, 2, 346, 346, + 330, 343, 330, 343, 343, 343, 343, 343, 343, 343, + 343, 343, 343, 343, 343, 343, 343, 343, 343, 343, + 343, 343, 343, 343, 343, 343, 343, 346, 346, 346, + 347, 1, 345, 1, 14, 342, 347, 342, 347, 331, + 331, 18, 15, 17, 347, 347, 347, 347, 347, 347, + 347, 347, 347, 347, 347, 347, 347, 347, 347, 347, + 347, 347, 347, 345, 21, 345, 348, 1, 348, 348, + 340, 338, 338, 339, 5, 7, 6, 343, 343, 343, + + 343, 343, 1, 2, 0, 335, 330, 330, 343, 330, + 343, 0, 3, 343, 2, 330, 0, 343, 343, 343, + 343, 343, 343, 343, 343, 247, 343, 343, 343, 251, + 343, 252, 343, 343, 257, 343, 343, 343, 343, 343, + 343, 343, 343, 343, 343, 343, 343, 343, 343, 343, + 343, 343, 343, 343, 343, 343, 343, 343, 343, 343, + 343, 343, 343, 271, 343, 343, 274, 275, 343, 343, + 343, 343, 343, 343, 343, 343, 343, 287, 343, 343, + 343, 343, 343, 343, 343, 343, 343, 343, 343, 343, + 343, 343, 343, 343, 343, 343, 343, 343, 343, 343, + + 343, 343, 343, 343, 224, 343, 343, 314, 315, 343, + 316, 343, 343, 343, 343, 343, 343, 343, 343, 343, + 343, 0, 323, 0, 336, 0, 16, 0, 13, 0, + 331, 331, 331, 0, 331, 0, 20, 22, 15, 19, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 15, 0, 0, 0, 19, 17, 24, 0, 20, 0, + 18, 0, 12, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 327, 0, 0, 332, + 23, 0, 341, 0, 340, 338, 338, 339, 5, 4, + 2, 343, 343, 343, 343, 330, 0, 0, 343, 330, + + 0, 334, 343, 334, 2, 2, 2, 330, 0, 0, + 330, 343, 343, 343, 343, 343, 343, 343, 343, 343, + 343, 343, 343, 343, 343, 343, 343, 343, 343, 343, + 343, 343, 343, 253, 343, 343, 343, 343, 343, 343, + 343, 343, 88, 343, 343, 343, 343, 343, 343, 343, + 343, 343, 343, 343, 343, 343, 104, 343, 343, 343, + 343, 343, 343, 343, 343, 343, 266, 343, 343, 343, + 343, 343, 343, 343, 343, 343, 343, 343, 343, 343, + 343, 343, 343, 343, 343, 143, 343, 343, 343, 343, + 343, 343, 343, 343, 343, 343, 343, 343, 343, 343, + + 343, 284, 285, 343, 343, 343, 343, 343, 343, 343, + 343, 343, 343, 343, 343, 343, 343, 343, 343, 343, + 343, 343, 343, 343, 343, 343, 343, 343, 343, 343, + 343, 343, 343, 343, 343, 343, 343, 343, 308, 343, + 343, 343, 343, 343, 343, 343, 343, 343, 343, 343, + 343, 343, 343, 343, 343, 343, 237, 321, 343, 239, + 322, 343, 68, 0, 0, 0, 0, 0, 0, 0, + 331, 331, 0, 0, 331, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 332, 2, 343, 9, 343, 343, 330, + 333, 333, 2, 2, 0, 330, 343, 343, 343, 343, + 343, 242, 343, 343, 343, 343, 343, 343, 343, 246, + 343, 343, 343, 343, 343, 343, 343, 343, 343, 343, + 83, 343, 343, 343, 343, 343, 343, 343, 343, 343, + 343, 343, 343, 343, 343, 261, 343, 343, 343, 343, + 99, 343, 343, 343, 103, 343, 343, 343, 106, 343, + 343, 343, 343, 343, 343, 343, 343, 343, 343, 343, + 343, 122, 343, 343, 343, 343, 343, 343, 343, 343, + + 343, 272, 343, 273, 343, 146, 343, 343, 343, 343, + 343, 343, 343, 343, 343, 343, 343, 343, 343, 343, + 343, 343, 343, 343, 343, 343, 343, 343, 343, 343, + 343, 343, 343, 343, 176, 343, 282, 343, 343, 343, + 343, 343, 343, 343, 343, 343, 343, 343, 343, 343, + 343, 343, 343, 343, 343, 343, 343, 343, 343, 343, + 343, 343, 343, 343, 343, 343, 343, 343, 343, 343, + 343, 343, 343, 343, 343, 208, 343, 343, 343, 343, + 343, 343, 343, 219, 343, 310, 343, 343, 343, 343, + 312, 231, 343, 343, 343, 343, 343, 343, 343, 343, + + 343, 240, 328, 328, 0, 331, 25, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 56, 0, 0, 0, 0, + 0, 329, 0, 343, 10, 343, 2, 61, 343, 63, + 343, 343, 243, 343, 343, 244, 343, 343, 343, 343, + 343, 343, 249, 343, 72, 343, 76, 343, 343, 343, + 343, 343, 343, 84, 343, 343, 343, 343, 259, 86, + 343, 89, 343, 343, 343, 260, 343, 343, 343, 343, + 343, 343, 343, 101, 343, 343, 263, 343, 343, 109, + + 264, 343, 343, 343, 111, 343, 343, 119, 343, 343, + 187, 343, 343, 343, 343, 343, 126, 270, 343, 136, + 343, 343, 343, 343, 343, 343, 343, 343, 343, 343, + 343, 343, 343, 343, 343, 343, 343, 343, 343, 343, + 343, 279, 343, 343, 343, 343, 343, 343, 343, 343, + 343, 343, 343, 343, 280, 343, 255, 343, 343, 343, + 343, 343, 343, 343, 343, 343, 343, 343, 343, 343, + 343, 343, 294, 343, 343, 343, 343, 343, 343, 343, + 343, 298, 343, 343, 343, 343, 343, 343, 343, 343, + 301, 302, 201, 343, 343, 343, 343, 343, 343, 306, + + 343, 343, 211, 343, 217, 343, 343, 343, 343, 223, + 343, 343, 343, 343, 317, 232, 343, 343, 343, 343, + 343, 343, 238, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 57, 0, 0, 0, 0, 43, + 0, 0, 0, 31, 42, 0, 29, 0, 0, 0, + 0, 30, 0, 0, 0, 0, 0, 0, 343, 343, + 343, 343, 343, 343, 343, 343, 245, 343, 70, 248, + 343, 250, 343, 343, 343, 343, 343, 343, 79, 343, + 80, 343, 343, 343, 343, 343, 85, 343, 343, 343, + 343, 91, 343, 343, 95, 96, 343, 262, 343, 98, + + 343, 343, 343, 343, 110, 267, 343, 343, 343, 343, + 343, 343, 268, 343, 343, 343, 343, 343, 343, 343, + 343, 343, 343, 343, 343, 343, 135, 137, 138, 343, + 343, 144, 343, 343, 343, 343, 343, 343, 343, 343, + 343, 343, 343, 343, 343, 276, 343, 277, 343, 343, + 343, 343, 343, 343, 343, 343, 343, 343, 343, 343, + 343, 343, 283, 177, 343, 343, 343, 343, 343, 343, + 343, 343, 343, 293, 292, 297, 186, 343, 343, 343, + 343, 343, 343, 343, 343, 343, 343, 343, 343, 299, + 343, 196, 343, 343, 343, 343, 343, 343, 343, 343, + + 343, 343, 304, 305, 343, 307, 210, 343, 213, 343, + 343, 343, 343, 343, 343, 343, 343, 343, 343, 343, + 343, 343, 343, 236, 320, 53, 34, 0, 0, 0, + 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, + 0, 0, 26, 0, 0, 0, 0, 0, 50, 0, + 0, 0, 329, 8, 343, 343, 343, 343, 343, 343, + 343, 343, 343, 343, 343, 343, 75, 343, 343, 343, + 343, 319, 343, 256, 343, 258, 343, 343, 343, 343, + 94, 343, 343, 100, 343, 343, 343, 343, 343, 343, + 343, 343, 343, 343, 118, 343, 343, 343, 343, 124, + + 343, 343, 343, 343, 343, 343, 343, 343, 343, 140, + 343, 343, 147, 343, 343, 343, 343, 343, 343, 343, + 343, 156, 343, 343, 343, 343, 343, 162, 343, 343, + 343, 343, 343, 343, 172, 343, 343, 343, 343, 343, + 178, 343, 179, 343, 343, 343, 343, 185, 343, 343, + 295, 343, 296, 343, 343, 343, 343, 343, 343, 343, + 343, 343, 343, 343, 343, 343, 343, 343, 343, 343, + 343, 343, 343, 343, 343, 343, 343, 343, 343, 343, + 343, 222, 343, 343, 343, 343, 343, 233, 234, 343, + 343, 0, 28, 0, 49, 41, 0, 0, 54, 0, + + 0, 0, 32, 0, 0, 0, 0, 0, 0, 47, + 0, 0, 324, 11, 343, 343, 343, 343, 343, 67, + 343, 343, 343, 343, 343, 343, 343, 343, 343, 343, + 343, 87, 343, 343, 93, 343, 343, 343, 343, 343, + 107, 227, 343, 343, 343, 343, 117, 343, 343, 343, + 123, 343, 343, 343, 343, 343, 343, 343, 343, 343, + 141, 343, 343, 343, 343, 343, 343, 343, 343, 152, + 343, 343, 159, 160, 161, 343, 343, 343, 343, 343, + 169, 343, 343, 175, 281, 343, 343, 343, 343, 343, + 343, 343, 184, 343, 343, 188, 343, 343, 190, 343, + + 343, 343, 194, 343, 343, 343, 343, 343, 198, 343, + 203, 343, 343, 303, 343, 343, 343, 343, 343, 343, + 343, 218, 116, 343, 221, 343, 343, 343, 311, 313, + 318, 343, 0, 51, 0, 46, 33, 55, 0, 0, + 0, 48, 36, 0, 27, 0, 0, 343, 343, 64, + 343, 66, 343, 71, 228, 343, 73, 343, 343, 78, + 343, 59, 343, 343, 92, 343, 343, 343, 343, 108, + 343, 114, 115, 113, 343, 121, 343, 343, 343, 343, + 343, 129, 343, 343, 343, 343, 343, 343, 343, 343, + 343, 343, 343, 155, 343, 343, 343, 343, 343, 343, + + 343, 343, 343, 343, 343, 343, 343, 343, 343, 343, + 343, 343, 343, 343, 343, 343, 343, 343, 343, 343, + 60, 343, 195, 343, 343, 343, 343, 343, 343, 343, + 207, 209, 212, 343, 216, 220, 225, 230, 343, 343, + 0, 0, 0, 0, 0, 0, 39, 0, 0, 343, + 241, 343, 343, 74, 58, 77, 81, 343, 90, 97, + 286, 343, 343, 112, 120, 343, 125, 269, 127, 343, + 343, 343, 343, 343, 343, 145, 148, 343, 343, 343, + 343, 343, 343, 343, 343, 163, 343, 343, 343, 343, + 343, 343, 343, 343, 343, 288, 343, 343, 343, 343, + + 343, 343, 254, 343, 191, 192, 343, 343, 197, 343, + 199, 202, 204, 343, 206, 343, 343, 343, 235, 40, + 35, 38, 45, 44, 37, 0, 0, 62, 343, 343, + 343, 343, 343, 343, 343, 343, 128, 343, 343, 343, + 343, 343, 149, 150, 154, 151, 343, 343, 343, 158, + 164, 343, 171, 168, 343, 343, 174, 343, 289, 343, + 343, 343, 343, 291, 309, 343, 193, 300, 343, 205, + 214, 343, 229, 0, 0, 343, 69, 343, 343, 343, + 102, 343, 343, 343, 343, 343, 139, 343, 343, 343, + 157, 343, 343, 173, 343, 343, 181, 182, 183, 343, + + 343, 343, 343, 0, 0, 343, 343, 343, 200, 105, + 265, 130, 132, 134, 343, 343, 153, 343, 170, 278, + 290, 343, 343, 343, 343, 0, 0, 343, 343, 82, + 343, 343, 343, 343, 167, 189, 165, 343, 226, 0, + 325, 65, 343, 343, 343, 142, 166, 343, 326, 343, + 343, 343, 215, 180, 343, 343, 131, 133, 0 + } ; + +static const YY_CHAR yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, + 1, 1, 4, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 5, 6, 7, 1, 1, 8, 9, 10, + 11, 12, 13, 1, 14, 15, 16, 17, 17, 18, + 17, 17, 17, 17, 17, 17, 17, 1, 1, 19, + 20, 21, 1, 1, 22, 23, 24, 25, 26, 27, + 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 1, 51, 52, 53, 54, 55, 56, + + 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, + 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, + 77, 78, 79, 80, 81, 82, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 83, 1, 1, 1, + 84, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 85, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +static const YY_CHAR yy_meta[87] = + { 0, + 1, 1, 2, 1, 1, 3, 1, 1, 3, 1, + 1, 4, 1, 5, 5, 5, 5, 5, 1, 5, + 1, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 1, 3, 1, + 5, 1, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 1, 1, + 1, 1, 1, 1, 1, 1 + } ; + +static const flex_int16_t yy_base[1785] = + { 0, + 0, 0, 86, 0, 171, 172, 173, 177, 181, 182, + 226, 0, 1410, 3994, 185, 3994, 3994, 0, 1398, 173, + 296, 353, 310, 304, 353, 416, 359, 354, 421, 436, + 356, 467, 156, 290, 474, 473, 354, 483, 532, 275, + 533, 579, 585, 540, 374, 631, 0, 1333, 1301, 1276, + 3994, 193, 3994, 194, 1261, 1223, 1200, 1146, 184, 314, + 611, 183, 188, 1170, 424, 479, 521, 615, 280, 644, + 575, 284, 299, 628, 624, 636, 306, 637, 355, 343, + 367, 678, 157, 1009, 1007, 3994, 3994, 208, 1008, 1000, + 0, 411, 418, 475, 0, 3994, 910, 824, 473, 477, + + 492, 484, 209, 0, 769, 748, 690, 704, 0, 706, + 201, 732, 3994, 763, 849, 720, 203, 531, 759, 525, + 649, 524, 645, 551, 686, 0, 685, 703, 687, 756, + 755, 0, 686, 690, 0, 727, 725, 758, 769, 771, + 754, 760, 766, 781, 769, 782, 836, 769, 771, 774, + 841, 851, 823, 852, 843, 852, 855, 895, 853, 850, + 844, 849, 899, 0, 915, 849, 0, 0, 907, 898, + 924, 852, 846, 907, 925, 866, 909, 929, 939, 940, + 922, 943, 927, 936, 943, 968, 969, 961, 967, 1007, + 972, 964, 988, 978, 995, 1015, 998, 979, 1000, 995, + + 990, 1002, 1023, 1026, 994, 1042, 1006, 0, 0, 1030, + 0, 1036, 1030, 1037, 1049, 1056, 1042, 1058, 1044, 1046, + 1065, 695, 3994, 652, 618, 603, 3994, 522, 3994, 573, + 1079, 1094, 1104, 316, 1106, 451, 3994, 3994, 3994, 3994, + 1077, 1080, 1061, 1081, 1084, 1091, 1091, 1093, 1102, 1101, + 1092, 1102, 1101, 1105, 1108, 3994, 1114, 1102, 1111, 1103, + 3994, 1107, 3994, 1111, 1127, 1112, 1130, 1131, 1128, 1127, + 1144, 1141, 632, 1165, 1166, 1160, 585, 575, 274, 3994, + 3994, 613, 3994, 575, 0, 3994, 3994, 3994, 0, 3994, + 1220, 1157, 1192, 1166, 1163, 1220, 722, 189, 207, 326, + + 564, 1179, 1306, 1181, 627, 1392, 1478, 1226, 1236, 559, + 724, 1186, 1218, 1218, 1219, 1226, 1221, 1226, 1234, 1234, + 1236, 1228, 1219, 1237, 1224, 1226, 1258, 1296, 1281, 1286, + 1293, 1293, 1304, 0, 1310, 1291, 1314, 1291, 1305, 1311, + 1297, 1304, 0, 1305, 1303, 1317, 1374, 1303, 1305, 1379, + 1306, 1315, 1308, 1309, 1382, 1381, 0, 1383, 1383, 1378, + 1396, 1380, 1399, 1399, 1395, 1391, 0, 1399, 1399, 1403, + 1389, 1405, 1399, 1399, 1400, 1462, 1400, 1413, 1441, 1448, + 1467, 1469, 1457, 1475, 1477, 0, 1472, 1473, 1543, 1476, + 1485, 1483, 1484, 1597, 1487, 1473, 1477, 1490, 1476, 1492, + + 1485, 1480, 0, 560, 1497, 1498, 1541, 1513, 1514, 1543, + 1543, 1544, 1540, 1570, 1587, 1544, 1602, 1542, 1554, 1549, + 1603, 1600, 1609, 1606, 1592, 1599, 1607, 1604, 1607, 1616, + 1649, 1607, 1617, 1620, 1616, 1630, 1613, 1645, 0, 1656, + 1648, 1645, 1643, 1661, 1642, 1656, 1664, 1656, 1670, 1667, + 1668, 1659, 1671, 1675, 1669, 1657, 0, 0, 1661, 0, + 0, 1666, 3994, 627, 564, 643, 1695, 528, 1697, 735, + 799, 1718, 1262, 849, 871, 1685, 1672, 1710, 1699, 1707, + 1702, 1706, 1708, 1722, 1719, 1710, 1730, 1713, 1714, 1721, + 1730, 1716, 1732, 1733, 1738, 1733, 1736, 3994, 1737, 1725, + + 1730, 1729, 1731, 1728, 1746, 1747, 1750, 1749, 1758, 1765, + 1781, 976, 1141, 464, 1775, 1779, 0, 1770, 1783, 874, + 3994, 0, 1782, 1783, 986, 1179, 1779, 1780, 1791, 1777, + 1797, 452, 1792, 1781, 1789, 1780, 1802, 1785, 1800, 0, + 1801, 1818, 1796, 1792, 1794, 1799, 1834, 1816, 1836, 1828, + 1826, 1839, 1826, 1846, 1847, 1837, 1850, 1830, 1853, 1840, + 1854, 1846, 1859, 1857, 1842, 0, 1859, 1860, 1859, 1852, + 1849, 1865, 1868, 1875, 0, 1859, 1861, 1878, 1881, 1886, + 1895, 1900, 1886, 1888, 1904, 1906, 1892, 1890, 1906, 1898, + 1898, 0, 1914, 1907, 1912, 1909, 1911, 1919, 1910, 1908, + + 1922, 0, 1915, 1958, 1927, 0, 1917, 1923, 1932, 1938, + 1944, 1948, 1959, 1943, 1964, 1965, 1962, 1954, 1972, 1959, + 1959, 1959, 1963, 1967, 1974, 1979, 1981, 1973, 2002, 1983, + 1980, 1972, 1982, 1982, 0, 1988, 0, 1999, 2021, 1983, + 2015, 2015, 2020, 2011, 2024, 2030, 2032, 2026, 2038, 2031, + 2021, 2025, 2037, 2025, 2039, 2029, 2043, 2044, 2025, 2047, + 2048, 2038, 2044, 2042, 2064, 2058, 2061, 2065, 2082, 2083, + 2086, 2076, 2087, 2082, 2083, 2076, 2087, 2082, 2080, 2097, + 2088, 2100, 2094, 0, 2099, 0, 2102, 2091, 2092, 2098, + 2093, 0, 2100, 2096, 2120, 2104, 2108, 2125, 2130, 2132, + + 2140, 0, 461, 452, 1189, 1256, 3994, 2136, 2146, 2148, + 2145, 2155, 2138, 2150, 2156, 2147, 2155, 2152, 2160, 2147, + 2148, 2151, 2167, 2153, 2154, 2154, 2154, 2157, 2158, 2165, + 2176, 2171, 2166, 2171, 2183, 3994, 2179, 2200, 2209, 1234, + 2196, 401, 1152, 2204, 0, 2206, 0, 0, 2198, 0, + 2217, 2207, 0, 2203, 2214, 0, 2223, 2210, 2222, 2211, + 2212, 2228, 0, 2227, 2244, 2228, 2216, 2226, 2220, 2230, + 2239, 2227, 2255, 0, 2247, 2250, 2253, 2253, 0, 0, + 2265, 0, 2256, 2258, 2279, 0, 2263, 2279, 2267, 2281, + 2265, 2284, 2273, 0, 2272, 2275, 0, 2291, 2275, 0, + + 0, 2278, 2292, 2289, 2318, 2280, 2297, 0, 2303, 2288, + 0, 2301, 2314, 2292, 2332, 2331, 2342, 0, 2323, 0, + 2322, 2338, 2342, 2332, 2332, 2350, 2330, 2337, 2356, 2343, + 2339, 2347, 2358, 2365, 2346, 2373, 2364, 2376, 2370, 2392, + 2376, 0, 2371, 2395, 2375, 2381, 2400, 2387, 2384, 2404, + 2381, 2407, 2397, 2408, 0, 2397, 0, 2412, 2404, 2397, + 2398, 2404, 2400, 2416, 2408, 2403, 2424, 2410, 2420, 2418, + 2423, 2428, 2426, 2440, 2442, 2449, 2451, 2460, 2453, 2444, + 2461, 2461, 2457, 2453, 2467, 2461, 2468, 2458, 2461, 2459, + 0, 0, 2479, 2462, 2461, 2469, 2482, 2485, 2482, 0, + + 2496, 2485, 2498, 2505, 0, 2518, 2519, 2508, 2505, 0, + 2523, 2520, 2518, 2504, 0, 0, 2511, 2528, 2514, 2536, + 2520, 2522, 0, 2537, 2524, 2525, 2538, 2536, 2541, 2541, + 2531, 2543, 2549, 2542, 3994, 2560, 2561, 2568, 2578, 3994, + 2562, 2579, 2576, 3994, 3994, 2584, 3994, 2577, 2579, 2579, + 2585, 3994, 2577, 1273, 2595, 2591, 1539, 398, 2588, 2585, + 2585, 2582, 2594, 2589, 2585, 2594, 0, 2601, 0, 0, + 2588, 0, 2588, 2593, 2594, 2605, 2624, 2616, 0, 2622, + 0, 2621, 2625, 2630, 2626, 2632, 0, 2643, 2635, 2631, + 2642, 0, 2649, 2648, 0, 2646, 2642, 0, 2638, 0, + + 2645, 2660, 2642, 2659, 0, 0, 2659, 2651, 2652, 2667, + 2644, 2652, 0, 2666, 2661, 2675, 2681, 2680, 2685, 2690, + 2683, 2704, 2691, 2688, 2708, 2705, 0, 0, 2705, 2696, + 2704, 2695, 2696, 2700, 2700, 2702, 2700, 2720, 2719, 2709, + 2716, 2724, 2726, 2715, 2712, 0, 2713, 0, 2719, 2719, + 2728, 2729, 2732, 2732, 2760, 2755, 2763, 2766, 2755, 2752, + 2761, 2773, 0, 0, 2770, 430, 2751, 2758, 2774, 2775, + 2770, 2770, 2765, 0, 0, 0, 0, 2781, 2774, 2774, + 2771, 2786, 2790, 2773, 2775, 2775, 2782, 2799, 2789, 2799, + 2800, 0, 2795, 2823, 2824, 2810, 2831, 2828, 2819, 2830, + + 2833, 2836, 0, 0, 2829, 0, 0, 2819, 2822, 2823, + 2824, 2842, 2842, 2830, 2836, 2836, 2852, 2842, 2839, 2855, + 2844, 2854, 2842, 0, 0, 3994, 3994, 2859, 2848, 2862, + 2860, 2864, 2886, 2878, 2880, 3994, 2894, 2872, 2885, 2882, + 2894, 2882, 3994, 2885, 2897, 2886, 2892, 2889, 3994, 2906, + 2909, 358, 352, 0, 2892, 2897, 2904, 2914, 2895, 2912, + 2899, 2904, 2916, 2904, 2918, 2936, 0, 2937, 2933, 2934, + 2947, 0, 2950, 0, 2946, 0, 2952, 2951, 2946, 2951, + 0, 2943, 2963, 0, 2950, 2953, 2956, 2953, 2945, 2959, + 2969, 2954, 2959, 2964, 0, 2970, 2966, 2974, 2975, 0, + + 2972, 2978, 2983, 2977, 2998, 2989, 3001, 2999, 3003, 0, + 3005, 3011, 0, 3012, 3021, 3002, 3015, 3007, 3007, 3016, + 3024, 0, 3021, 3019, 3024, 3032, 3030, 0, 3027, 3036, + 3017, 3030, 3022, 3036, 0, 3033, 3031, 3037, 3043, 3045, + 0, 3062, 0, 3049, 3075, 3065, 3062, 0, 3081, 3077, + 0, 3070, 0, 3066, 3081, 3062, 3080, 3081, 3073, 3076, + 3088, 3093, 3092, 3092, 3090, 3081, 3092, 3084, 3089, 3093, + 3101, 3092, 3101, 3099, 3107, 3132, 3137, 3134, 3135, 3139, + 3132, 0, 3143, 3129, 3130, 3144, 3146, 0, 0, 3134, + 3144, 3145, 3994, 3136, 3994, 3994, 3142, 3137, 3994, 3143, + + 3140, 3152, 3994, 3159, 3154, 3145, 3140, 3157, 3160, 3994, + 3176, 3160, 295, 0, 3160, 3184, 3182, 3188, 3191, 0, + 3188, 3189, 3193, 3188, 3197, 3204, 3208, 3209, 3200, 3211, + 3196, 0, 3203, 3205, 0, 3215, 3200, 3202, 3204, 3219, + 0, 0, 3210, 3221, 3219, 3223, 0, 3228, 3212, 3220, + 0, 3222, 3225, 3253, 3250, 3251, 3247, 3249, 3248, 3252, + 3258, 3246, 3247, 3261, 3258, 3273, 3256, 3271, 3279, 3277, + 3260, 3282, 0, 0, 0, 3258, 3271, 3268, 3283, 3266, + 3285, 3268, 3290, 0, 0, 3280, 3295, 3284, 3304, 3308, + 3316, 3308, 0, 3321, 3311, 0, 3314, 3320, 0, 3319, + + 3319, 3322, 0, 3324, 3336, 3334, 3320, 3322, 0, 3327, + 0, 3328, 3339, 0, 3333, 3320, 3339, 3329, 3336, 3349, + 3331, 0, 0, 3328, 0, 3348, 3342, 3353, 0, 0, + 0, 3345, 3353, 3994, 3382, 3994, 3994, 3994, 3361, 3368, + 3374, 3994, 3376, 3392, 3994, 3382, 3383, 3382, 3383, 0, + 3395, 0, 3387, 0, 0, 3385, 0, 3397, 3385, 0, + 3390, 0, 3385, 3392, 0, 3394, 3402, 3400, 3404, 0, + 3395, 0, 0, 0, 3398, 0, 3396, 3410, 3401, 3417, + 3428, 0, 3439, 3440, 3438, 3436, 3449, 3447, 3449, 3452, + 3451, 3437, 3457, 0, 3443, 3456, 3453, 3443, 3459, 3462, + + 3461, 3447, 3467, 3464, 3461, 3451, 3463, 3461, 3471, 3457, + 3467, 3478, 3471, 3486, 3499, 3493, 3506, 3504, 3498, 3513, + 0, 3511, 0, 3502, 3498, 3505, 3507, 3507, 3508, 3519, + 0, 0, 0, 3513, 0, 0, 3505, 0, 3513, 3514, + 3524, 3525, 3526, 3513, 3513, 3514, 3994, 3541, 3547, 3517, + 0, 3535, 3540, 0, 0, 0, 3558, 3535, 0, 0, + 0, 3531, 3552, 0, 0, 3562, 0, 0, 0, 3554, + 3578, 3579, 3563, 3581, 3559, 0, 0, 3580, 3567, 3579, + 3576, 3588, 3576, 3587, 3587, 0, 3588, 3575, 3587, 3584, + 3585, 3596, 3596, 3591, 3581, 0, 3598, 3593, 3595, 3627, + + 3610, 3613, 0, 3634, 0, 0, 3616, 3628, 0, 3640, + 0, 0, 0, 3624, 0, 3638, 3630, 3625, 0, 3994, + 3994, 3994, 3994, 3994, 3994, 3628, 3639, 0, 3634, 3630, + 3635, 3627, 3638, 3640, 3637, 3636, 0, 3646, 3649, 3657, + 3643, 3646, 0, 0, 0, 0, 3655, 3655, 3672, 0, + 0, 3679, 0, 0, 3675, 3686, 0, 3690, 0, 3696, + 3680, 3691, 3682, 0, 0, 3700, 0, 0, 3690, 0, + 3701, 3697, 0, 3698, 3683, 3698, 0, 3691, 3697, 3700, + 0, 3702, 3691, 3712, 3713, 3701, 0, 3714, 3717, 3712, + 0, 3705, 3719, 0, 3720, 3731, 0, 0, 0, 3742, + + 3749, 3748, 3737, 3732, 3761, 3745, 3755, 3760, 0, 0, + 0, 3763, 3764, 0, 3743, 3759, 0, 3767, 0, 0, + 0, 3768, 3770, 3762, 3758, 3780, 291, 3761, 3765, 0, + 3777, 3781, 3782, 3787, 0, 0, 0, 3778, 0, 288, + 285, 0, 3780, 3787, 3791, 0, 0, 3799, 273, 3795, + 3800, 3804, 0, 0, 3807, 3808, 0, 0, 3994, 3873, + 3878, 3883, 3888, 3893, 310, 3898, 3903, 3908, 3913, 3918, + 3923, 3928, 3933, 3938, 3943, 3948, 3953, 3958, 3963, 3968, + 3973, 3978, 3983, 3988 + } ; + +static const flex_int16_t yy_def[1785] = + { 0, + 1759, 1, 1759, 3, 1760, 1760, 1761, 1761, 1762, 1762, + 1759, 11, 1759, 1759, 1759, 1759, 1759, 1763, 1764, 1759, + 1765, 1766, 1759, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1767, 1768, 1759, + 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, + 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, + 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, + 1759, 1769, 1770, 1759, 1759, 1759, 1759, 1759, 1771, 1772, + 1773, 1759, 1759, 1759, 1774, 1759, 1759, 1765, 1765, 1765, + + 1765, 1765, 1759, 1763, 1764, 1764, 1759, 1759, 1765, 1765, + 1765, 1775, 1759, 1776, 1777, 1759, 1759, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1767, 1759, 1768, 1768, 1759, 1759, 1778, 1759, 1779, + 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, + 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, + 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, + 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, + 1759, 1759, 1769, 1769, 1769, 1769, 1759, 1770, 1780, 1759, + 1759, 1771, 1759, 1772, 1773, 1759, 1759, 1759, 1774, 1759, + 1781, 1765, 1765, 1765, 1765, 1759, 1759, 1759, 1765, 1765, + + 1775, 1759, 1776, 1765, 1782, 1777, 1781, 1759, 1759, 1759, + 1759, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1759, 1778, 1759, 1778, 1779, 1759, 1779, 1759, + 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, + 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, + 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, + + 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1769, 1769, + 1769, 1780, 1780, 1759, 307, 1765, 1765, 1765, 1765, 1759, + 1759, 1765, 1783, 307, 1759, 1759, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + + 1765, 1765, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, + 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, + 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, + 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1769, 1769, + 1769, 1759, 1784, 1765, 1765, 1765, 1783, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1759, 1759, 1759, 1759, 1759, 1759, 1759, + 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, + 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, + 1759, 1759, 1759, 1769, 1769, 1769, 1784, 1759, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1759, 1759, 1759, 1759, 1759, + 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, + 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1769, + 1769, 1769, 1759, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, + + 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, + 1769, 1769, 1759, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, + 1759, 1759, 1759, 1759, 1759, 1769, 1769, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1769, 1769, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1759, + 1759, 1759, 1759, 1759, 1759, 1769, 1769, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1769, 1769, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + + 1765, 1765, 1765, 1769, 1769, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1769, 1769, 1765, 1765, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1769, + 1759, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1759, 1765, + 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 0, 1759, + 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, + 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, + 1759, 1759, 1759, 1759 + } ; + +static const flex_int16_t yy_nxt[4081] = + { 0, + 14, 15, 16, 15, 14, 17, 18, 14, 17, 19, + 14, 14, 14, 20, 21, 22, 23, 23, 14, 14, + 14, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, + 43, 44, 45, 46, 47, 47, 47, 48, 14, 14, + 14, 14, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 47, 47, 47, 49, 14, + 14, 14, 14, 14, 50, 14, 51, 52, 53, 54, + 55, 56, 51, 57, 58, 51, 51, 51, 51, 59, + + 60, 51, 61, 61, 62, 63, 64, 65, 66, 67, + 68, 69, 70, 71, 51, 72, 73, 51, 74, 51, + 75, 76, 51, 51, 77, 78, 79, 80, 51, 81, + 51, 51, 51, 82, 51, 51, 51, 83, 65, 66, + 67, 68, 69, 70, 71, 51, 72, 73, 51, 74, + 51, 75, 76, 51, 51, 77, 78, 79, 80, 51, + 81, 51, 51, 51, 51, 84, 51, 85, 51, 51, + 51, 86, 88, 88, 88, 88, 89, 89, 92, 90, + 90, 93, 92, 96, 96, 93, 103, 107, 103, 108, + 108, 160, 97, 97, 103, 103, 103, 103, 231, 238, + + 232, 232, 237, 227, 279, 520, 520, 239, 280, 103, + 103, 103, 103, 298, 299, 310, 310, 300, 300, 311, + 311, 94, 160, 300, 300, 94, 14, 15, 16, 15, + 14, 17, 18, 14, 17, 14, 14, 14, 14, 14, + 47, 98, 14, 14, 14, 14, 14, 47, 47, 99, + 47, 100, 47, 47, 47, 47, 47, 47, 47, 101, + 47, 47, 102, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 14, 14, 14, 14, 14, 47, 47, + 99, 47, 100, 47, 47, 47, 47, 47, 47, 47, + 101, 47, 47, 102, 47, 47, 47, 47, 47, 47, + + 47, 47, 47, 47, 14, 14, 14, 14, 14, 14, + 14, 14, 110, 110, 109, 161, 188, 251, 257, 162, + 258, 111, 273, 513, 116, 514, 108, 108, 470, 470, + 233, 233, 471, 471, 273, 117, 118, 1749, 119, 234, + 1741, 266, 300, 300, 273, 120, 161, 188, 251, 257, + 162, 258, 111, 112, 112, 112, 112, 112, 112, 112, + 112, 112, 112, 112, 113, 112, 117, 118, 115, 119, + 234, 112, 266, 112, 121, 174, 120, 153, 122, 271, + 134, 154, 123, 135, 136, 155, 138, 139, 140, 175, + 269, 124, 141, 270, 125, 214, 272, 137, 142, 215, + + 112, 112, 112, 743, 112, 121, 174, 1313, 153, 122, + 271, 134, 154, 123, 135, 136, 155, 138, 139, 140, + 175, 269, 124, 141, 270, 125, 214, 272, 137, 142, + 215, 112, 112, 112, 112, 112, 112, 112, 112, 126, + 286, 127, 143, 1242, 128, 129, 144, 287, 130, 743, + 145, 131, 743, 146, 132, 133, 147, 149, 241, 148, + 467, 150, 242, 474, 474, 151, 464, 475, 475, 753, + 126, 286, 127, 143, 152, 128, 129, 144, 287, 130, + 288, 145, 131, 288, 146, 132, 133, 147, 149, 241, + 148, 156, 150, 242, 169, 163, 151, 164, 170, 165, + + 157, 158, 171, 166, 243, 152, 167, 159, 292, 176, + 177, 293, 168, 294, 172, 743, 295, 178, 173, 179, + 244, 180, 156, 288, 181, 169, 163, 465, 164, 170, + 165, 157, 158, 171, 166, 243, 467, 167, 159, 292, + 176, 177, 293, 168, 294, 172, 245, 295, 178, 173, + 179, 244, 180, 182, 189, 181, 246, 183, 190, 247, + 312, 184, 191, 208, 185, 317, 320, 186, 192, 464, + 187, 466, 209, 640, 210, 311, 311, 245, 211, 302, + 212, 468, 213, 283, 182, 189, 323, 246, 183, 190, + 247, 312, 184, 191, 208, 185, 317, 320, 186, 192, + + 255, 187, 193, 209, 194, 210, 202, 195, 196, 211, + 203, 212, 197, 213, 204, 256, 198, 323, 283, 199, + 205, 200, 469, 206, 201, 235, 280, 232, 232, 301, + 207, 255, 465, 193, 273, 194, 236, 202, 195, 196, + 248, 203, 523, 197, 249, 204, 256, 198, 703, 227, + 199, 205, 200, 259, 206, 201, 216, 217, 250, 262, + 218, 207, 219, 260, 220, 252, 267, 236, 261, 221, + 268, 248, 318, 253, 263, 249, 466, 264, 265, 321, + 227, 277, 254, 319, 259, 322, 463, 216, 217, 250, + 262, 218, 466, 219, 260, 220, 252, 267, 225, 261, + + 221, 268, 274, 318, 253, 263, 296, 296, 264, 265, + 321, 275, 324, 254, 319, 297, 322, 276, 116, 326, + 108, 108, 110, 110, 327, 328, 325, 277, 334, 117, + 335, 111, 225, 274, 298, 298, 308, 308, 520, 520, + 311, 311, 275, 324, 223, 309, 297, 302, 276, 336, + 326, 471, 471, 337, 338, 327, 328, 325, 106, 334, + 117, 335, 111, 301, 301, 301, 301, 301, 301, 301, + 301, 301, 301, 301, 301, 301, 309, 329, 304, 106, + 336, 301, 313, 301, 337, 338, 314, 331, 332, 333, + 339, 340, 344, 315, 342, 343, 345, 330, 347, 316, + + 346, 350, 348, 351, 356, 341, 349, 357, 329, 358, + 301, 301, 301, 313, 301, 471, 471, 314, 331, 332, + 333, 339, 340, 344, 315, 342, 343, 345, 330, 347, + 316, 346, 350, 348, 351, 356, 341, 349, 357, 291, + 358, 301, 301, 301, 301, 301, 301, 301, 301, 305, + 305, 301, 305, 305, 305, 305, 305, 305, 305, 305, + 305, 305, 359, 363, 307, 475, 475, 305, 352, 305, + 353, 354, 360, 364, 355, 365, 368, 366, 373, 374, + 361, 377, 375, 385, 396, 397, 362, 475, 475, 376, + 520, 520, 402, 359, 363, 367, 305, 305, 305, 352, + + 305, 353, 354, 360, 364, 355, 365, 368, 366, 373, + 374, 361, 377, 375, 385, 396, 397, 362, 369, 370, + 376, 378, 390, 402, 371, 290, 367, 305, 305, 305, + 305, 305, 305, 305, 305, 372, 382, 379, 391, 380, + 398, 383, 384, 386, 381, 387, 388, 403, 399, 369, + 370, 389, 378, 390, 404, 371, 392, 393, 394, 400, + 405, 406, 407, 401, 395, 410, 372, 382, 379, 391, + 380, 398, 383, 384, 386, 381, 387, 388, 403, 399, + 411, 408, 389, 409, 412, 404, 418, 392, 393, 394, + 400, 405, 406, 407, 401, 395, 410, 413, 416, 427, + + 414, 419, 526, 526, 417, 428, 420, 415, 283, 429, + 430, 411, 408, 283, 409, 412, 431, 418, 281, 435, + 436, 437, 439, 440, 441, 513, 447, 514, 413, 416, + 427, 414, 419, 421, 422, 417, 428, 420, 415, 423, + 429, 430, 451, 424, 425, 438, 426, 431, 432, 433, + 435, 436, 437, 439, 440, 441, 442, 447, 444, 452, + 445, 434, 453, 448, 421, 422, 446, 443, 454, 455, + 423, 449, 456, 451, 424, 425, 438, 426, 457, 432, + 433, 458, 459, 450, 460, 461, 462, 442, 263, 444, + 452, 445, 434, 453, 448, 233, 233, 446, 443, 454, + + 455, 229, 449, 456, 234, 476, 477, 478, 235, 457, + 232, 232, 458, 459, 450, 460, 461, 462, 479, 236, + 233, 233, 472, 472, 480, 481, 482, 483, 484, 234, + 486, 473, 229, 487, 488, 234, 476, 477, 478, 489, + 490, 485, 491, 492, 495, 496, 497, 498, 493, 479, + 236, 499, 500, 501, 494, 480, 481, 482, 483, 484, + 234, 486, 473, 502, 487, 488, 503, 504, 506, 505, + 489, 490, 485, 491, 492, 495, 496, 497, 498, 493, + 507, 508, 499, 500, 501, 494, 509, 510, 511, 240, + 513, 516, 742, 230, 502, 526, 526, 503, 504, 506, + + 505, 957, 518, 958, 519, 706, 706, 229, 521, 277, + 522, 507, 508, 527, 277, 277, 343, 509, 510, 511, + 104, 104, 516, 104, 104, 104, 104, 104, 104, 104, + 104, 104, 104, 518, 517, 519, 296, 296, 104, 521, + 104, 522, 308, 308, 527, 297, 528, 343, 525, 525, + 529, 309, 526, 526, 530, 531, 532, 533, 534, 535, + 536, 537, 538, 539, 540, 517, 541, 104, 104, 104, + 228, 104, 706, 706, 705, 705, 297, 528, 706, 706, + 227, 529, 309, 277, 955, 530, 531, 532, 533, 534, + 535, 536, 537, 538, 539, 540, 542, 541, 104, 104, + + 104, 104, 104, 104, 104, 104, 301, 301, 301, 301, + 301, 301, 301, 301, 301, 301, 301, 301, 301, 543, + 544, 304, 277, 1150, 301, 545, 301, 542, 546, 547, + 548, 551, 552, 555, 556, 553, 557, 558, 549, 559, + 560, 561, 562, 565, 550, 566, 569, 570, 571, 572, + 543, 544, 554, 301, 301, 301, 545, 301, 226, 546, + 547, 548, 551, 552, 555, 556, 553, 557, 558, 549, + 559, 560, 561, 562, 565, 550, 566, 569, 570, 571, + 572, 225, 223, 554, 301, 301, 301, 301, 301, 301, + 301, 301, 305, 305, 301, 305, 305, 305, 305, 305, + + 305, 305, 305, 305, 305, 573, 563, 307, 106, 1759, + 305, 567, 305, 564, 575, 574, 576, 577, 578, 568, + 579, 580, 581, 582, 583, 584, 585, 586, 588, 589, + 590, 587, 591, 592, 593, 596, 573, 563, 597, 305, + 305, 305, 567, 305, 564, 575, 574, 576, 577, 578, + 568, 579, 580, 581, 582, 583, 584, 585, 586, 588, + 589, 590, 587, 591, 592, 593, 596, 1759, 598, 597, + 305, 305, 305, 305, 305, 305, 305, 305, 104, 104, + 599, 104, 104, 104, 104, 104, 104, 104, 104, 104, + 104, 594, 600, 601, 1759, 1759, 104, 602, 104, 598, + + 603, 595, 604, 605, 606, 618, 619, 524, 621, 622, + 620, 599, 632, 633, 634, 635, 636, 637, 638, 639, + 641, 642, 594, 600, 601, 104, 104, 104, 602, 104, + 1759, 603, 595, 604, 605, 606, 618, 619, 524, 621, + 622, 620, 1759, 632, 633, 634, 635, 636, 637, 638, + 639, 641, 642, 645, 646, 1759, 104, 104, 104, 104, + 104, 104, 104, 104, 607, 608, 647, 609, 648, 610, + 611, 650, 612, 643, 651, 613, 649, 644, 614, 656, + 659, 660, 615, 616, 645, 646, 617, 1759, 957, 661, + 1153, 652, 1759, 1759, 1759, 607, 608, 647, 609, 648, + + 610, 611, 650, 612, 643, 651, 613, 649, 644, 614, + 656, 659, 660, 615, 616, 653, 654, 617, 623, 624, + 661, 625, 652, 626, 627, 657, 628, 655, 662, 663, + 664, 665, 658, 666, 667, 668, 629, 630, 669, 670, + 631, 671, 1759, 674, 675, 676, 653, 654, 677, 623, + 624, 678, 625, 679, 626, 627, 657, 628, 655, 662, + 663, 664, 665, 658, 666, 667, 668, 629, 630, 669, + 670, 631, 671, 672, 674, 675, 676, 680, 681, 677, + 682, 683, 678, 684, 679, 673, 685, 686, 687, 688, + 689, 690, 691, 692, 693, 695, 697, 700, 698, 694, + + 696, 701, 702, 468, 672, 704, 707, 708, 680, 681, + 699, 682, 683, 1759, 684, 1759, 673, 685, 686, 687, + 688, 689, 690, 691, 692, 693, 695, 697, 700, 698, + 694, 696, 701, 702, 472, 472, 709, 707, 708, 710, + 711, 699, 712, 473, 469, 713, 469, 714, 715, 716, + 717, 718, 719, 720, 721, 722, 723, 724, 725, 726, + 727, 728, 729, 730, 731, 732, 733, 709, 734, 735, + 710, 711, 736, 712, 473, 737, 713, 738, 714, 715, + 716, 717, 718, 719, 720, 721, 722, 723, 724, 725, + 726, 727, 728, 729, 730, 731, 732, 733, 739, 734, + + 735, 740, 741, 736, 515, 744, 737, 277, 738, 745, + 746, 747, 515, 748, 277, 749, 750, 751, 752, 754, + 755, 756, 757, 758, 759, 760, 761, 1759, 764, 739, + 277, 765, 740, 741, 766, 515, 744, 767, 1759, 762, + 745, 746, 747, 515, 748, 770, 749, 750, 751, 752, + 754, 755, 756, 757, 758, 759, 760, 761, 763, 764, + 768, 771, 765, 772, 773, 766, 774, 775, 767, 769, + 762, 776, 777, 778, 779, 780, 770, 781, 782, 783, + 784, 785, 786, 787, 788, 789, 790, 791, 792, 763, + 793, 768, 771, 794, 772, 773, 795, 774, 775, 796, + + 769, 797, 776, 777, 778, 779, 780, 798, 781, 782, + 783, 784, 785, 786, 787, 788, 789, 790, 791, 792, + 799, 793, 800, 801, 794, 802, 803, 795, 804, 805, + 796, 806, 797, 807, 808, 809, 810, 811, 798, 812, + 813, 814, 816, 817, 818, 819, 820, 821, 815, 822, + 1759, 799, 825, 800, 801, 826, 802, 803, 827, 804, + 805, 828, 806, 829, 807, 808, 809, 810, 811, 830, + 812, 813, 814, 816, 817, 818, 819, 820, 821, 815, + 822, 823, 831, 825, 832, 833, 826, 834, 824, 827, + 837, 838, 828, 835, 829, 839, 840, 841, 842, 843, + + 830, 844, 845, 846, 847, 836, 848, 849, 853, 854, + 855, 856, 823, 831, 857, 832, 833, 858, 834, 824, + 859, 837, 838, 862, 835, 850, 839, 840, 841, 842, + 843, 851, 844, 845, 846, 847, 836, 848, 849, 853, + 854, 855, 856, 852, 863, 857, 860, 864, 858, 865, + 861, 859, 866, 867, 862, 868, 850, 869, 870, 871, + 872, 873, 851, 874, 875, 876, 877, 879, 880, 881, + 882, 878, 883, 884, 852, 863, 885, 860, 864, 886, + 865, 861, 887, 866, 867, 888, 868, 889, 869, 870, + 871, 872, 873, 890, 874, 875, 876, 877, 879, 880, + + 881, 882, 878, 883, 884, 891, 892, 885, 893, 894, + 886, 895, 896, 887, 897, 898, 888, 899, 889, 900, + 901, 902, 903, 904, 890, 905, 906, 910, 908, 911, + 907, 912, 913, 914, 915, 916, 891, 892, 909, 893, + 894, 917, 895, 896, 918, 897, 898, 919, 899, 920, + 900, 901, 902, 903, 904, 921, 905, 906, 910, 908, + 911, 907, 912, 913, 914, 915, 916, 922, 923, 909, + 924, 925, 917, 926, 927, 918, 928, 929, 919, 930, + 920, 931, 932, 933, 934, 935, 921, 936, 937, 938, + 939, 940, 941, 942, 943, 944, 945, 946, 922, 923, + + 947, 924, 925, 948, 926, 927, 949, 928, 929, 950, + 930, 951, 931, 932, 933, 934, 935, 952, 936, 937, + 938, 939, 940, 941, 942, 943, 944, 945, 946, 953, + 954, 947, 956, 959, 948, 960, 961, 949, 962, 963, + 950, 964, 951, 965, 966, 277, 967, 968, 952, 969, + 970, 971, 972, 976, 977, 978, 979, 981, 277, 980, + 953, 954, 982, 956, 959, 973, 960, 961, 983, 962, + 963, 974, 964, 975, 965, 966, 984, 967, 968, 985, + 969, 970, 971, 972, 976, 977, 978, 979, 981, 986, + 980, 987, 988, 982, 989, 990, 973, 991, 992, 983, + + 993, 994, 974, 995, 975, 996, 997, 984, 998, 999, + 985, 1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1013, + 986, 1014, 987, 988, 1015, 989, 990, 1759, 991, 992, + 1016, 993, 994, 1017, 995, 1018, 996, 997, 1019, 998, + 999, 1008, 1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, + 1013, 1009, 1014, 1020, 1010, 1015, 1021, 1027, 1011, 1012, + 1028, 1016, 1029, 1030, 1017, 1022, 1018, 1031, 1023, 1019, + 1032, 1024, 1008, 1033, 1034, 1025, 1035, 1036, 1037, 1038, + 1026, 1039, 1009, 1040, 1020, 1010, 1041, 1021, 1027, 1011, + 1012, 1028, 1042, 1029, 1030, 1043, 1022, 1044, 1031, 1023, + + 1045, 1032, 1024, 1046, 1033, 1034, 1025, 1035, 1036, 1037, + 1038, 1026, 1039, 1047, 1040, 1048, 1049, 1041, 1050, 1051, + 1052, 1053, 1054, 1042, 1055, 1056, 1043, 1057, 1044, 1058, + 1059, 1045, 1060, 1061, 1046, 1062, 1063, 1064, 1065, 1066, + 1067, 1068, 1069, 1070, 1047, 1071, 1048, 1049, 1072, 1050, + 1051, 1052, 1053, 1054, 1073, 1055, 1056, 1074, 1057, 1075, + 1058, 1059, 1076, 1060, 1061, 1077, 1062, 1063, 1064, 1065, + 1066, 1067, 1068, 1069, 1070, 1078, 1071, 1079, 1080, 1072, + 1081, 1083, 1084, 1085, 1086, 1073, 1089, 1087, 1074, 1082, + 1075, 1090, 1091, 1076, 1088, 1092, 1077, 1093, 1094, 1095, + + 1096, 1097, 1100, 1098, 1101, 1102, 1078, 1103, 1079, 1080, + 1104, 1081, 1083, 1084, 1085, 1086, 1105, 1089, 1087, 1099, + 1082, 1106, 1090, 1091, 1107, 1088, 1092, 1108, 1093, 1094, + 1095, 1096, 1097, 1100, 1098, 1101, 1102, 1109, 1103, 1110, + 1111, 1104, 1112, 1114, 1115, 1118, 1116, 1105, 1113, 1119, + 1099, 1120, 1106, 1121, 1122, 1107, 1117, 1123, 1108, 1124, + 1125, 1126, 1127, 1128, 1129, 1130, 1131, 1132, 1109, 1133, + 1110, 1111, 1134, 1112, 1114, 1115, 1118, 1116, 1135, 1113, + 1119, 1136, 1120, 1137, 1121, 1122, 1138, 1117, 1123, 1139, + 1124, 1125, 1126, 1127, 1128, 1129, 1130, 1131, 1132, 1140, + + 1133, 1141, 1142, 1134, 1143, 1144, 1145, 1146, 1147, 1135, + 1148, 1149, 1136, 1759, 1137, 1154, 1152, 1138, 1151, 1155, + 1139, 1156, 1157, 1158, 1159, 1160, 1161, 1162, 1163, 1164, + 1140, 1165, 1141, 1142, 1166, 1143, 1144, 1145, 1146, 1147, + 277, 1148, 1149, 1167, 277, 1168, 1154, 1152, 1169, 1151, + 1155, 1170, 1156, 1157, 1158, 1159, 1160, 1161, 1162, 1163, + 1164, 1171, 1165, 1172, 1173, 1166, 1174, 1175, 1176, 1177, + 1178, 1179, 1180, 1181, 1167, 1182, 1168, 1183, 1184, 1169, + 1185, 1186, 1170, 1187, 1188, 1189, 1190, 1191, 1192, 1193, + 1194, 1195, 1171, 1196, 1172, 1173, 1197, 1174, 1175, 1176, + + 1177, 1178, 1179, 1180, 1181, 1198, 1182, 1199, 1183, 1184, + 1200, 1185, 1186, 1201, 1187, 1188, 1189, 1190, 1191, 1192, + 1193, 1194, 1195, 1202, 1196, 1203, 1204, 1197, 1205, 1206, + 1208, 1209, 1210, 1211, 1212, 1213, 1198, 1207, 1199, 1214, + 1215, 1200, 1216, 1217, 1201, 1218, 1219, 1220, 1221, 1222, + 1223, 1224, 1225, 1226, 1202, 1227, 1203, 1204, 1228, 1205, + 1206, 1208, 1209, 1210, 1211, 1212, 1213, 1229, 1207, 1230, + 1214, 1215, 1231, 1216, 1217, 1232, 1218, 1219, 1220, 1221, + 1222, 1223, 1224, 1225, 1226, 1233, 1227, 1234, 1235, 1228, + 1236, 1237, 1238, 1239, 1240, 1241, 1243, 1244, 1229, 1245, + + 1230, 1246, 1247, 1231, 1248, 1249, 1232, 1250, 1251, 1252, + 1253, 1254, 1255, 1256, 1257, 1258, 1233, 1259, 1234, 1235, + 1260, 1236, 1237, 1238, 1239, 1240, 1241, 1243, 1244, 1261, + 1245, 1262, 1246, 1247, 1263, 1248, 1249, 1264, 1250, 1251, + 1252, 1253, 1254, 1255, 1256, 1257, 1258, 1265, 1259, 1266, + 1267, 1260, 1268, 1269, 1270, 1271, 1272, 1274, 1275, 1276, + 1261, 1277, 1262, 1278, 1279, 1263, 1280, 1281, 1264, 1282, + 1283, 1284, 1273, 1285, 1286, 1287, 1288, 1289, 1265, 1290, + 1266, 1267, 1291, 1268, 1269, 1270, 1271, 1272, 1274, 1275, + 1276, 1292, 1277, 1293, 1278, 1279, 1294, 1280, 1281, 1295, + + 1282, 1283, 1284, 1273, 1285, 1286, 1287, 1288, 1289, 1296, + 1290, 1297, 1298, 1291, 1299, 1300, 1301, 1302, 1303, 1304, + 1305, 1306, 1292, 1307, 1293, 1308, 1309, 1294, 1310, 1311, + 1295, 1314, 1315, 1316, 1312, 1317, 1318, 1319, 1320, 1321, + 1296, 1322, 1297, 1298, 1323, 1299, 1300, 1301, 1302, 1303, + 1304, 1305, 1306, 1324, 1307, 277, 1308, 1309, 277, 1310, + 1311, 1325, 1314, 1315, 1316, 1312, 1317, 1318, 1319, 1320, + 1321, 1326, 1322, 1327, 1328, 1323, 1329, 1330, 1331, 1332, + 1333, 1334, 1335, 1336, 1324, 1337, 1338, 1339, 1340, 1341, + 1342, 1343, 1325, 1344, 1345, 1346, 1347, 1348, 1349, 1350, + + 1351, 1352, 1326, 1353, 1327, 1328, 1354, 1329, 1330, 1331, + 1332, 1333, 1334, 1335, 1336, 1355, 1337, 1338, 1339, 1340, + 1341, 1342, 1343, 1356, 1344, 1345, 1346, 1347, 1348, 1349, + 1350, 1351, 1352, 1357, 1353, 1358, 1359, 1354, 1360, 1361, + 1362, 1363, 1364, 1365, 1366, 1367, 1355, 1368, 1369, 1370, + 1371, 1372, 1373, 1374, 1356, 1375, 1376, 1377, 1378, 1379, + 1380, 1381, 1382, 1383, 1357, 1384, 1358, 1359, 1385, 1360, + 1361, 1362, 1363, 1364, 1365, 1366, 1367, 1386, 1368, 1369, + 1370, 1371, 1372, 1373, 1374, 1389, 1375, 1376, 1377, 1378, + 1379, 1380, 1381, 1382, 1383, 1387, 1384, 1388, 1390, 1385, + + 1392, 1393, 1394, 1395, 1396, 1397, 1398, 1399, 1386, 1400, + 1401, 1402, 1403, 1404, 1405, 1406, 1389, 1407, 1391, 1408, + 1409, 1410, 1411, 1412, 1413, 1414, 1387, 1415, 1388, 1390, + 1416, 1392, 1393, 1394, 1395, 1396, 1397, 1398, 1399, 1417, + 1400, 1401, 1402, 1403, 1404, 1405, 1406, 1418, 1407, 1391, + 1408, 1409, 1410, 1411, 1412, 1413, 1414, 1419, 1415, 1422, + 1420, 1416, 1421, 1423, 1424, 1425, 1426, 1427, 1428, 1429, + 1417, 1430, 1431, 1432, 1433, 1434, 1435, 1436, 1418, 1437, + 1438, 1439, 1440, 1441, 1442, 1443, 1444, 1445, 1419, 1448, + 1422, 1420, 1447, 1421, 1423, 1424, 1425, 1426, 1427, 1428, + + 1429, 1446, 1430, 1431, 1432, 1433, 1434, 1435, 1436, 277, + 1437, 1438, 1439, 1440, 1441, 1442, 1443, 1444, 1445, 1449, + 1448, 1450, 1451, 1447, 1452, 277, 1453, 1454, 1455, 1456, + 1457, 1458, 1446, 1459, 1460, 1461, 1462, 1463, 1464, 1465, + 1466, 1467, 1468, 1469, 1470, 1471, 1472, 1473, 1474, 1475, + 1449, 1476, 1450, 1451, 1477, 1452, 1478, 1453, 1454, 1455, + 1456, 1457, 1458, 1479, 1459, 1460, 1461, 1462, 1463, 1464, + 1465, 1466, 1467, 1468, 1469, 1470, 1471, 1472, 1473, 1474, + 1475, 1480, 1476, 1481, 1482, 1477, 1483, 1478, 1484, 1485, + 1486, 1487, 1488, 1489, 1479, 1490, 1491, 1492, 1493, 1494, + + 1495, 1496, 1497, 1498, 1499, 1500, 1501, 1502, 1503, 1504, + 1505, 1506, 1480, 1507, 1481, 1482, 1508, 1483, 1509, 1484, + 1485, 1486, 1487, 1488, 1489, 1510, 1490, 1491, 1492, 1493, + 1494, 1495, 1496, 1497, 1498, 1499, 1500, 1501, 1502, 1503, + 1504, 1505, 1506, 1511, 1507, 1512, 1513, 1508, 1514, 1509, + 1515, 1516, 1517, 1518, 1519, 1520, 1510, 1521, 1522, 1523, + 1524, 1525, 1526, 1527, 1528, 1529, 1530, 1531, 1532, 1533, + 1534, 1535, 1536, 1537, 1511, 1538, 1512, 1513, 1539, 1514, + 1540, 1515, 1516, 1517, 1518, 1519, 1520, 1541, 1521, 1522, + 1523, 1524, 1525, 1526, 1527, 1528, 1529, 1530, 1531, 1532, + + 1533, 1534, 1535, 1536, 1537, 1542, 1538, 1543, 1544, 1539, + 1545, 1540, 1546, 1547, 1548, 1549, 1550, 1551, 1541, 1552, + 1553, 1554, 1555, 1556, 1557, 1558, 1559, 1560, 1561, 1562, + 1563, 277, 277, 1564, 1565, 1566, 1542, 1567, 1543, 1544, + 1568, 1545, 1569, 1546, 1547, 1548, 1549, 1550, 1551, 1570, + 1552, 1553, 1554, 1555, 1556, 1557, 1558, 1559, 1560, 1561, + 1562, 1563, 1571, 1572, 1564, 1565, 1566, 1573, 1567, 1574, + 1575, 1568, 1576, 1569, 1577, 1578, 1579, 1580, 1581, 1582, + 1570, 1583, 1584, 1585, 1586, 1587, 1588, 1589, 1590, 1591, + 1592, 1593, 1594, 1571, 1572, 1595, 1596, 1597, 1573, 1598, + + 1574, 1575, 1599, 1576, 1600, 1577, 1578, 1579, 1580, 1581, + 1582, 1601, 1583, 1584, 1585, 1586, 1587, 1588, 1589, 1590, + 1591, 1592, 1593, 1594, 1602, 1603, 1595, 1596, 1597, 1604, + 1598, 1605, 1606, 1599, 1607, 1600, 1608, 1609, 1610, 1611, + 1612, 1613, 1601, 1614, 1615, 1616, 1617, 1618, 1619, 1620, + 1621, 1622, 1623, 1624, 1625, 1602, 1603, 1628, 1629, 1759, + 1604, 1630, 1605, 1606, 1633, 1607, 1634, 1608, 1609, 1610, + 1611, 1612, 1613, 1626, 1614, 1615, 1616, 1617, 1618, 1619, + 1620, 1621, 1622, 1623, 1624, 1625, 1627, 1635, 1628, 1629, + 277, 1636, 1630, 1631, 1637, 1633, 277, 1634, 1632, 1638, + + 1639, 1640, 1641, 1642, 1626, 1643, 1644, 1645, 1646, 1647, + 1648, 1649, 1650, 1651, 1652, 1653, 1654, 1627, 1635, 1655, + 1656, 1657, 1636, 1658, 1631, 1637, 1659, 1660, 1661, 1632, + 1638, 1639, 1640, 1641, 1642, 1662, 1643, 1644, 1645, 1646, + 1647, 1648, 1649, 1650, 1651, 1652, 1653, 1654, 1663, 1664, + 1655, 1656, 1657, 1665, 1658, 1666, 1667, 1659, 1660, 1661, + 1668, 1669, 1670, 1671, 1672, 1673, 1662, 1674, 1675, 1676, + 1677, 1678, 1679, 1680, 1681, 1682, 1683, 277, 1684, 1663, + 1664, 1685, 1686, 1687, 1665, 1688, 1666, 1667, 277, 1689, + 1690, 1668, 1669, 1670, 1671, 1672, 1673, 1691, 1674, 1675, + + 1676, 1677, 1678, 1679, 1680, 1681, 1682, 1683, 1692, 1684, + 1693, 1694, 1685, 1686, 1687, 1695, 1688, 1696, 1697, 1698, + 1689, 1690, 1699, 1700, 1701, 1702, 1703, 1704, 1691, 1705, + 1706, 1707, 277, 1708, 1709, 1710, 1711, 1712, 1713, 1692, + 1714, 1693, 1694, 1715, 1716, 1717, 1695, 277, 1696, 1697, + 1698, 1718, 1719, 1699, 1700, 1701, 1702, 1703, 1704, 1720, + 1705, 1706, 1707, 1721, 1708, 1709, 1710, 1711, 1712, 1713, + 1722, 1714, 1723, 1724, 1715, 1716, 1717, 1725, 1726, 1759, + 1728, 277, 1718, 1719, 1729, 1730, 1727, 1731, 1732, 1733, + 1720, 1734, 1735, 1736, 1721, 1737, 1738, 1739, 1759, 1742, + + 1743, 1722, 1744, 1723, 1724, 1740, 1745, 1746, 1725, 1726, + 277, 1728, 1747, 1748, 1750, 1729, 1730, 1727, 1731, 1732, + 1733, 1751, 1734, 1735, 1736, 1752, 1737, 1738, 1739, 277, + 1742, 1743, 1753, 1744, 1754, 1755, 1740, 1745, 1746, 1756, + 1757, 1758, 1759, 1747, 1748, 1750, 1759, 1759, 1759, 1759, + 1759, 1759, 1751, 1759, 1759, 1759, 1752, 1759, 1759, 1759, + 1759, 1759, 1759, 1753, 1759, 1754, 1755, 1759, 1759, 1759, + 1756, 1757, 1758, 87, 87, 87, 87, 87, 91, 91, + 91, 91, 91, 95, 95, 95, 95, 95, 104, 1759, + 104, 104, 104, 105, 1759, 105, 105, 105, 114, 114, + + 114, 114, 114, 222, 222, 222, 222, 222, 224, 1759, + 224, 224, 224, 273, 273, 273, 273, 273, 278, 278, + 278, 278, 278, 282, 282, 282, 282, 282, 284, 284, + 284, 284, 284, 285, 285, 1759, 285, 285, 289, 1759, + 289, 1759, 289, 301, 301, 301, 301, 301, 303, 303, + 303, 303, 303, 306, 306, 306, 306, 306, 464, 464, + 464, 464, 464, 467, 467, 467, 467, 467, 512, 512, + 512, 512, 512, 515, 1759, 515, 515, 515, 305, 305, + 305, 305, 305, 104, 1759, 104, 104, 104, 743, 743, + 743, 743, 743, 13, 1759, 1759, 1759, 1759, 1759, 1759, + + 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, + 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, + 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, + 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, + 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, + 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, + 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, + 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759 + } ; + +static const flex_int16_t yy_chk[4081] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 5, 6, 5, 6, 5, 6, 7, 5, + 6, 7, 8, 9, 10, 8, 15, 20, 15, 20, + 20, 33, 9, 10, 52, 54, 52, 54, 59, 63, + + 59, 59, 62, 62, 83, 298, 298, 63, 83, 88, + 103, 88, 103, 111, 111, 117, 117, 111, 111, 117, + 117, 7, 33, 299, 299, 8, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 21, 21, 1765, 34, 40, 69, 72, 34, + 73, 21, 1749, 279, 23, 279, 23, 23, 234, 234, + 60, 60, 234, 234, 1741, 23, 24, 1740, 24, 60, + 1727, 77, 300, 300, 1313, 24, 34, 40, 69, 72, + 34, 73, 21, 22, 22, 22, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 22, 23, 24, 22, 24, + 60, 22, 77, 22, 25, 37, 24, 31, 25, 80, + 27, 31, 25, 27, 27, 31, 28, 28, 28, 37, + 79, 25, 28, 79, 25, 45, 81, 27, 28, 45, + + 22, 22, 22, 1153, 22, 25, 37, 1152, 31, 25, + 80, 27, 31, 25, 27, 27, 31, 28, 28, 28, + 37, 79, 25, 28, 79, 25, 45, 81, 27, 28, + 45, 22, 22, 22, 22, 22, 22, 22, 22, 26, + 92, 26, 29, 1066, 26, 26, 29, 93, 26, 958, + 29, 26, 742, 29, 26, 26, 29, 30, 65, 29, + 704, 30, 65, 236, 236, 30, 703, 236, 236, 532, + 26, 92, 26, 29, 30, 26, 26, 29, 93, 26, + 94, 29, 26, 94, 29, 26, 26, 29, 30, 65, + 29, 32, 30, 65, 36, 35, 30, 35, 36, 35, + + 32, 32, 36, 35, 66, 30, 35, 32, 99, 38, + 38, 100, 35, 101, 36, 514, 102, 38, 36, 38, + 66, 38, 32, 94, 38, 36, 35, 228, 35, 36, + 35, 32, 32, 36, 35, 66, 468, 35, 32, 99, + 38, 38, 100, 35, 101, 36, 67, 102, 38, 36, + 38, 66, 38, 39, 41, 38, 67, 39, 41, 67, + 118, 39, 41, 44, 39, 120, 122, 39, 41, 465, + 39, 228, 44, 404, 44, 310, 310, 67, 44, 301, + 44, 230, 44, 284, 39, 41, 124, 67, 39, 41, + 67, 118, 39, 41, 44, 39, 120, 122, 39, 41, + + 71, 39, 42, 44, 42, 44, 43, 42, 42, 44, + 43, 44, 42, 44, 43, 71, 42, 124, 282, 42, + 43, 42, 230, 43, 42, 61, 278, 61, 61, 305, + 43, 71, 464, 42, 277, 42, 61, 43, 42, 42, + 68, 43, 305, 42, 68, 43, 71, 42, 466, 75, + 42, 43, 42, 74, 43, 42, 46, 46, 68, 75, + 46, 43, 46, 74, 46, 70, 78, 61, 74, 46, + 78, 68, 121, 70, 76, 68, 464, 76, 76, 123, + 75, 273, 70, 121, 74, 123, 226, 46, 46, 68, + 75, 46, 466, 46, 74, 46, 70, 78, 225, 74, + + 46, 78, 82, 121, 70, 76, 107, 107, 76, 76, + 123, 82, 125, 70, 121, 107, 123, 82, 108, 127, + 108, 108, 110, 110, 128, 129, 125, 82, 133, 108, + 134, 110, 224, 82, 297, 297, 116, 116, 297, 297, + 311, 311, 82, 125, 222, 116, 107, 112, 82, 136, + 127, 470, 470, 136, 137, 128, 129, 125, 106, 133, + 108, 134, 110, 114, 114, 114, 114, 114, 114, 114, + 114, 114, 114, 114, 114, 114, 116, 130, 114, 105, + 136, 114, 119, 114, 136, 137, 119, 131, 131, 131, + 138, 139, 141, 119, 140, 140, 142, 130, 143, 119, + + 142, 145, 144, 146, 148, 139, 144, 149, 130, 150, + 114, 114, 114, 119, 114, 471, 471, 119, 131, 131, + 131, 138, 139, 141, 119, 140, 140, 142, 130, 143, + 119, 142, 145, 144, 146, 148, 139, 144, 149, 98, + 150, 114, 114, 114, 114, 114, 114, 114, 114, 115, + 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, + 115, 115, 151, 153, 115, 474, 474, 115, 147, 115, + 147, 147, 152, 154, 147, 155, 157, 156, 159, 160, + 152, 162, 161, 166, 172, 173, 152, 475, 475, 161, + 520, 520, 176, 151, 153, 156, 115, 115, 115, 147, + + 115, 147, 147, 152, 154, 147, 155, 157, 156, 159, + 160, 152, 162, 161, 166, 172, 173, 152, 158, 158, + 161, 163, 170, 176, 158, 97, 156, 115, 115, 115, + 115, 115, 115, 115, 115, 158, 165, 163, 170, 163, + 174, 165, 165, 169, 163, 169, 169, 177, 174, 158, + 158, 169, 163, 170, 178, 158, 171, 171, 171, 175, + 179, 180, 181, 175, 171, 183, 158, 165, 163, 170, + 163, 174, 165, 165, 169, 163, 169, 169, 177, 174, + 184, 182, 169, 182, 185, 178, 188, 171, 171, 171, + 175, 179, 180, 181, 175, 171, 183, 186, 187, 191, + + 186, 189, 525, 525, 187, 192, 189, 186, 90, 193, + 194, 184, 182, 89, 182, 185, 195, 188, 85, 197, + 198, 199, 200, 201, 202, 512, 205, 512, 186, 187, + 191, 186, 189, 190, 190, 187, 192, 189, 186, 190, + 193, 194, 207, 190, 190, 199, 190, 195, 196, 196, + 197, 198, 199, 200, 201, 202, 203, 205, 204, 210, + 204, 196, 212, 206, 190, 190, 204, 203, 213, 214, + 190, 206, 215, 207, 190, 190, 199, 190, 216, 196, + 196, 217, 218, 206, 219, 220, 221, 203, 84, 204, + 210, 204, 196, 212, 206, 231, 231, 204, 203, 213, + + 214, 241, 206, 215, 231, 242, 243, 244, 232, 216, + 232, 232, 217, 218, 206, 219, 220, 221, 245, 232, + 233, 233, 235, 235, 246, 246, 247, 248, 249, 233, + 250, 235, 241, 251, 252, 231, 242, 243, 244, 253, + 254, 249, 255, 257, 258, 259, 260, 262, 257, 245, + 232, 264, 265, 266, 257, 246, 246, 247, 248, 249, + 233, 250, 235, 267, 251, 252, 268, 269, 270, 269, + 253, 254, 249, 255, 257, 258, 259, 260, 262, 257, + 271, 272, 264, 265, 266, 257, 274, 275, 276, 64, + 513, 292, 513, 58, 267, 526, 526, 268, 269, 270, + + 269, 743, 294, 743, 295, 705, 705, 57, 302, 276, + 304, 271, 272, 312, 274, 275, 293, 274, 275, 276, + 291, 291, 292, 291, 291, 291, 291, 291, 291, 291, + 291, 291, 291, 294, 293, 295, 296, 296, 291, 302, + 291, 304, 308, 308, 312, 296, 313, 293, 309, 309, + 314, 308, 309, 309, 315, 316, 317, 318, 319, 320, + 321, 322, 323, 324, 325, 293, 326, 291, 291, 291, + 56, 291, 706, 706, 473, 473, 296, 313, 473, 473, + 55, 314, 308, 740, 740, 315, 316, 317, 318, 319, + 320, 321, 322, 323, 324, 325, 327, 326, 291, 291, + + 291, 291, 291, 291, 291, 291, 303, 303, 303, 303, + 303, 303, 303, 303, 303, 303, 303, 303, 303, 328, + 329, 303, 954, 954, 303, 330, 303, 327, 331, 332, + 333, 335, 336, 338, 339, 337, 340, 341, 333, 342, + 344, 345, 346, 348, 333, 349, 351, 352, 353, 354, + 328, 329, 337, 303, 303, 303, 330, 303, 50, 331, + 332, 333, 335, 336, 338, 339, 337, 340, 341, 333, + 342, 344, 345, 346, 348, 333, 349, 351, 352, 353, + 354, 49, 48, 337, 303, 303, 303, 303, 303, 303, + 303, 303, 306, 306, 306, 306, 306, 306, 306, 306, + + 306, 306, 306, 306, 306, 355, 347, 306, 19, 13, + 306, 350, 306, 347, 356, 355, 358, 359, 360, 350, + 361, 362, 363, 364, 365, 366, 368, 369, 370, 371, + 372, 369, 373, 374, 375, 377, 355, 347, 378, 306, + 306, 306, 350, 306, 347, 356, 355, 358, 359, 360, + 350, 361, 362, 363, 364, 365, 366, 368, 369, 370, + 371, 372, 369, 373, 374, 375, 377, 0, 379, 378, + 306, 306, 306, 306, 306, 306, 306, 306, 307, 307, + 380, 307, 307, 307, 307, 307, 307, 307, 307, 307, + 307, 376, 381, 382, 0, 0, 307, 383, 307, 379, + + 384, 376, 385, 387, 388, 390, 391, 307, 392, 393, + 391, 380, 395, 396, 397, 398, 399, 400, 401, 402, + 405, 406, 376, 381, 382, 307, 307, 307, 383, 307, + 0, 384, 376, 385, 387, 388, 390, 391, 307, 392, + 393, 391, 0, 395, 396, 397, 398, 399, 400, 401, + 402, 405, 406, 408, 409, 0, 307, 307, 307, 307, + 307, 307, 307, 307, 389, 389, 410, 389, 411, 389, + 389, 412, 389, 407, 413, 389, 411, 407, 389, 416, + 418, 419, 389, 389, 408, 409, 389, 0, 957, 420, + 957, 414, 0, 0, 0, 389, 389, 410, 389, 411, + + 389, 389, 412, 389, 407, 413, 389, 411, 407, 389, + 416, 418, 419, 389, 389, 414, 415, 389, 394, 394, + 420, 394, 414, 394, 394, 417, 394, 415, 421, 422, + 423, 424, 417, 425, 426, 427, 394, 394, 428, 429, + 394, 430, 0, 432, 433, 434, 414, 415, 435, 394, + 394, 436, 394, 437, 394, 394, 417, 394, 415, 421, + 422, 423, 424, 417, 425, 426, 427, 394, 394, 428, + 429, 394, 430, 431, 432, 433, 434, 438, 440, 435, + 441, 442, 436, 443, 437, 431, 444, 445, 446, 447, + 448, 449, 450, 451, 452, 453, 454, 456, 455, 452, + + 453, 459, 462, 467, 431, 469, 476, 477, 438, 440, + 455, 441, 442, 0, 443, 0, 431, 444, 445, 446, + 447, 448, 449, 450, 451, 452, 453, 454, 456, 455, + 452, 453, 459, 462, 472, 472, 478, 476, 477, 479, + 480, 455, 481, 472, 467, 482, 469, 483, 484, 485, + 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, + 496, 497, 499, 500, 501, 502, 503, 478, 504, 505, + 479, 480, 506, 481, 472, 507, 482, 508, 483, 484, + 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, + 495, 496, 497, 499, 500, 501, 502, 503, 509, 504, + + 505, 510, 511, 506, 515, 516, 507, 509, 508, 518, + 519, 523, 524, 527, 510, 528, 529, 530, 531, 533, + 534, 535, 536, 537, 538, 539, 541, 0, 543, 509, + 511, 544, 510, 511, 545, 515, 516, 546, 0, 542, + 518, 519, 523, 524, 527, 548, 528, 529, 530, 531, + 533, 534, 535, 536, 537, 538, 539, 541, 542, 543, + 547, 549, 544, 550, 551, 545, 552, 553, 546, 547, + 542, 554, 555, 556, 557, 558, 548, 559, 560, 561, + 562, 563, 564, 565, 567, 568, 569, 570, 571, 542, + 572, 547, 549, 573, 550, 551, 574, 552, 553, 576, + + 547, 577, 554, 555, 556, 557, 558, 578, 559, 560, + 561, 562, 563, 564, 565, 567, 568, 569, 570, 571, + 579, 572, 580, 581, 573, 582, 583, 574, 584, 585, + 576, 586, 577, 587, 588, 589, 590, 591, 578, 593, + 594, 595, 596, 597, 598, 599, 600, 601, 595, 603, + 0, 579, 605, 580, 581, 607, 582, 583, 608, 584, + 585, 609, 586, 610, 587, 588, 589, 590, 591, 611, + 593, 594, 595, 596, 597, 598, 599, 600, 601, 595, + 603, 604, 612, 605, 613, 614, 607, 615, 604, 608, + 616, 617, 609, 615, 610, 618, 619, 620, 621, 622, + + 611, 623, 624, 625, 626, 615, 627, 628, 630, 631, + 632, 633, 604, 612, 634, 613, 614, 636, 615, 604, + 638, 616, 617, 640, 615, 629, 618, 619, 620, 621, + 622, 629, 623, 624, 625, 626, 615, 627, 628, 630, + 631, 632, 633, 629, 641, 634, 639, 642, 636, 643, + 639, 638, 644, 645, 640, 646, 629, 647, 648, 649, + 650, 651, 629, 652, 653, 654, 655, 656, 657, 658, + 659, 655, 660, 661, 629, 641, 662, 639, 642, 663, + 643, 639, 664, 644, 645, 665, 646, 666, 647, 648, + 649, 650, 651, 667, 652, 653, 654, 655, 656, 657, + + 658, 659, 655, 660, 661, 668, 669, 662, 670, 671, + 663, 672, 673, 664, 674, 675, 665, 676, 666, 677, + 678, 679, 680, 681, 667, 682, 683, 687, 685, 688, + 683, 689, 690, 691, 693, 694, 668, 669, 685, 670, + 671, 695, 672, 673, 696, 674, 675, 697, 676, 698, + 677, 678, 679, 680, 681, 699, 682, 683, 687, 685, + 688, 683, 689, 690, 691, 693, 694, 700, 701, 685, + 708, 709, 695, 710, 711, 696, 712, 713, 697, 714, + 698, 715, 716, 717, 718, 719, 699, 720, 721, 722, + 723, 724, 725, 726, 727, 728, 729, 730, 700, 701, + + 731, 708, 709, 732, 710, 711, 733, 712, 713, 734, + 714, 735, 715, 716, 717, 718, 719, 737, 720, 721, + 722, 723, 724, 725, 726, 727, 728, 729, 730, 738, + 739, 731, 741, 744, 732, 746, 749, 733, 751, 752, + 734, 754, 735, 755, 757, 741, 758, 759, 737, 760, + 761, 762, 764, 766, 767, 768, 769, 770, 739, 769, + 738, 739, 771, 741, 744, 765, 746, 749, 772, 751, + 752, 765, 754, 765, 755, 757, 773, 758, 759, 775, + 760, 761, 762, 764, 766, 767, 768, 769, 770, 776, + 769, 777, 778, 771, 781, 783, 765, 784, 784, 772, + + 785, 787, 765, 788, 765, 789, 790, 773, 791, 792, + 775, 793, 795, 796, 798, 799, 802, 803, 804, 806, + 776, 807, 777, 778, 809, 781, 783, 0, 784, 784, + 810, 785, 787, 812, 788, 813, 789, 790, 814, 791, + 792, 805, 793, 795, 796, 798, 799, 802, 803, 804, + 806, 805, 807, 815, 805, 809, 816, 819, 805, 805, + 821, 810, 822, 823, 812, 817, 813, 824, 817, 814, + 825, 817, 805, 826, 827, 817, 828, 829, 830, 831, + 817, 832, 805, 833, 815, 805, 834, 816, 819, 805, + 805, 821, 835, 822, 823, 836, 817, 837, 824, 817, + + 838, 825, 817, 839, 826, 827, 817, 828, 829, 830, + 831, 817, 832, 840, 833, 841, 843, 834, 844, 845, + 846, 847, 848, 835, 849, 850, 836, 851, 837, 852, + 853, 838, 854, 856, 839, 858, 859, 860, 861, 862, + 863, 864, 865, 866, 840, 867, 841, 843, 868, 844, + 845, 846, 847, 848, 869, 849, 850, 870, 851, 871, + 852, 853, 872, 854, 856, 873, 858, 859, 860, 861, + 862, 863, 864, 865, 866, 874, 867, 875, 876, 868, + 877, 878, 879, 880, 881, 869, 883, 882, 870, 877, + 871, 884, 885, 872, 882, 886, 873, 887, 888, 889, + + 890, 893, 894, 893, 895, 896, 874, 897, 875, 876, + 898, 877, 878, 879, 880, 881, 899, 883, 882, 893, + 877, 901, 884, 885, 902, 882, 886, 903, 887, 888, + 889, 890, 893, 894, 893, 895, 896, 904, 897, 906, + 907, 898, 908, 909, 911, 913, 912, 899, 908, 914, + 893, 917, 901, 918, 919, 902, 912, 920, 903, 921, + 922, 924, 925, 926, 927, 928, 929, 930, 904, 931, + 906, 907, 932, 908, 909, 911, 913, 912, 933, 908, + 914, 934, 917, 936, 918, 919, 937, 912, 920, 938, + 921, 922, 924, 925, 926, 927, 928, 929, 930, 939, + + 931, 941, 942, 932, 943, 946, 948, 949, 950, 933, + 951, 953, 934, 0, 936, 959, 956, 937, 955, 960, + 938, 961, 962, 963, 964, 965, 966, 968, 971, 973, + 939, 974, 941, 942, 975, 943, 946, 948, 949, 950, + 956, 951, 953, 976, 955, 977, 959, 956, 978, 955, + 960, 980, 961, 962, 963, 964, 965, 966, 968, 971, + 973, 982, 974, 983, 984, 975, 985, 986, 988, 989, + 990, 991, 993, 994, 976, 996, 977, 997, 999, 978, + 1001, 1002, 980, 1003, 1004, 1007, 1008, 1009, 1010, 1011, + 1012, 1014, 982, 1015, 983, 984, 1016, 985, 986, 988, + + 989, 990, 991, 993, 994, 1017, 996, 1018, 997, 999, + 1019, 1001, 1002, 1020, 1003, 1004, 1007, 1008, 1009, 1010, + 1011, 1012, 1014, 1021, 1015, 1022, 1023, 1016, 1024, 1025, + 1026, 1029, 1030, 1031, 1032, 1033, 1017, 1025, 1018, 1034, + 1035, 1019, 1036, 1037, 1020, 1038, 1039, 1040, 1041, 1042, + 1043, 1044, 1045, 1047, 1021, 1049, 1022, 1023, 1050, 1024, + 1025, 1026, 1029, 1030, 1031, 1032, 1033, 1051, 1025, 1052, + 1034, 1035, 1053, 1036, 1037, 1054, 1038, 1039, 1040, 1041, + 1042, 1043, 1044, 1045, 1047, 1055, 1049, 1056, 1057, 1050, + 1058, 1059, 1060, 1061, 1062, 1065, 1067, 1068, 1051, 1069, + + 1052, 1070, 1071, 1053, 1072, 1073, 1054, 1078, 1079, 1080, + 1081, 1082, 1083, 1084, 1085, 1086, 1055, 1087, 1056, 1057, + 1088, 1058, 1059, 1060, 1061, 1062, 1065, 1067, 1068, 1089, + 1069, 1090, 1070, 1071, 1091, 1072, 1073, 1093, 1078, 1079, + 1080, 1081, 1082, 1083, 1084, 1085, 1086, 1094, 1087, 1095, + 1096, 1088, 1097, 1098, 1099, 1100, 1101, 1102, 1105, 1108, + 1089, 1109, 1090, 1110, 1111, 1091, 1112, 1113, 1093, 1114, + 1115, 1116, 1101, 1117, 1118, 1119, 1120, 1121, 1094, 1122, + 1095, 1096, 1123, 1097, 1098, 1099, 1100, 1101, 1102, 1105, + 1108, 1128, 1109, 1129, 1110, 1111, 1130, 1112, 1113, 1131, + + 1114, 1115, 1116, 1101, 1117, 1118, 1119, 1120, 1121, 1132, + 1122, 1133, 1134, 1123, 1135, 1137, 1138, 1139, 1140, 1141, + 1142, 1144, 1128, 1145, 1129, 1146, 1147, 1130, 1148, 1150, + 1131, 1155, 1156, 1157, 1151, 1158, 1159, 1160, 1161, 1162, + 1132, 1163, 1133, 1134, 1164, 1135, 1137, 1138, 1139, 1140, + 1141, 1142, 1144, 1165, 1145, 1150, 1146, 1147, 1151, 1148, + 1150, 1166, 1155, 1156, 1157, 1151, 1158, 1159, 1160, 1161, + 1162, 1168, 1163, 1169, 1170, 1164, 1171, 1173, 1175, 1177, + 1178, 1179, 1180, 1182, 1165, 1183, 1185, 1186, 1187, 1188, + 1189, 1190, 1166, 1191, 1192, 1193, 1194, 1196, 1197, 1198, + + 1199, 1201, 1168, 1202, 1169, 1170, 1203, 1171, 1173, 1175, + 1177, 1178, 1179, 1180, 1182, 1204, 1183, 1185, 1186, 1187, + 1188, 1189, 1190, 1205, 1191, 1192, 1193, 1194, 1196, 1197, + 1198, 1199, 1201, 1206, 1202, 1207, 1208, 1203, 1209, 1211, + 1212, 1214, 1215, 1216, 1217, 1218, 1204, 1219, 1220, 1221, + 1223, 1224, 1225, 1226, 1205, 1227, 1229, 1230, 1231, 1232, + 1233, 1234, 1236, 1237, 1206, 1238, 1207, 1208, 1239, 1209, + 1211, 1212, 1214, 1215, 1216, 1217, 1218, 1240, 1219, 1220, + 1221, 1223, 1224, 1225, 1226, 1244, 1227, 1229, 1230, 1231, + 1232, 1233, 1234, 1236, 1237, 1242, 1238, 1242, 1245, 1239, + + 1246, 1247, 1249, 1250, 1252, 1254, 1255, 1256, 1240, 1257, + 1258, 1259, 1260, 1261, 1262, 1263, 1244, 1264, 1245, 1265, + 1266, 1267, 1268, 1269, 1270, 1271, 1242, 1272, 1242, 1245, + 1273, 1246, 1247, 1249, 1250, 1252, 1254, 1255, 1256, 1274, + 1257, 1258, 1259, 1260, 1261, 1262, 1263, 1275, 1264, 1245, + 1265, 1266, 1267, 1268, 1269, 1270, 1271, 1276, 1272, 1278, + 1277, 1273, 1277, 1279, 1280, 1281, 1283, 1284, 1285, 1286, + 1274, 1287, 1290, 1291, 1292, 1294, 1297, 1298, 1275, 1300, + 1301, 1302, 1304, 1305, 1306, 1307, 1308, 1309, 1276, 1315, + 1278, 1277, 1312, 1277, 1279, 1280, 1281, 1283, 1284, 1285, + + 1286, 1311, 1287, 1290, 1291, 1292, 1294, 1297, 1298, 1312, + 1300, 1301, 1302, 1304, 1305, 1306, 1307, 1308, 1309, 1316, + 1315, 1317, 1318, 1312, 1319, 1311, 1321, 1322, 1323, 1324, + 1325, 1326, 1311, 1327, 1328, 1329, 1330, 1331, 1333, 1334, + 1336, 1337, 1338, 1339, 1340, 1343, 1344, 1345, 1346, 1348, + 1316, 1349, 1317, 1318, 1350, 1319, 1352, 1321, 1322, 1323, + 1324, 1325, 1326, 1353, 1327, 1328, 1329, 1330, 1331, 1333, + 1334, 1336, 1337, 1338, 1339, 1340, 1343, 1344, 1345, 1346, + 1348, 1354, 1349, 1355, 1356, 1350, 1357, 1352, 1358, 1359, + 1360, 1361, 1362, 1363, 1353, 1364, 1365, 1366, 1367, 1368, + + 1369, 1370, 1371, 1372, 1376, 1377, 1378, 1379, 1380, 1381, + 1382, 1383, 1354, 1386, 1355, 1356, 1387, 1357, 1388, 1358, + 1359, 1360, 1361, 1362, 1363, 1389, 1364, 1365, 1366, 1367, + 1368, 1369, 1370, 1371, 1372, 1376, 1377, 1378, 1379, 1380, + 1381, 1382, 1383, 1390, 1386, 1391, 1392, 1387, 1394, 1388, + 1395, 1397, 1398, 1400, 1401, 1402, 1389, 1404, 1405, 1406, + 1407, 1408, 1410, 1412, 1413, 1415, 1416, 1417, 1418, 1419, + 1420, 1421, 1424, 1426, 1390, 1427, 1391, 1392, 1428, 1394, + 1432, 1395, 1397, 1398, 1400, 1401, 1402, 1433, 1404, 1405, + 1406, 1407, 1408, 1410, 1412, 1413, 1415, 1416, 1417, 1418, + + 1419, 1420, 1421, 1424, 1426, 1435, 1427, 1439, 1440, 1428, + 1441, 1432, 1443, 1444, 1446, 1447, 1448, 1449, 1433, 1451, + 1453, 1456, 1458, 1459, 1461, 1463, 1464, 1466, 1467, 1468, + 1469, 1446, 1447, 1471, 1475, 1477, 1435, 1478, 1439, 1440, + 1479, 1441, 1480, 1443, 1444, 1446, 1447, 1448, 1449, 1481, + 1451, 1453, 1456, 1458, 1459, 1461, 1463, 1464, 1466, 1467, + 1468, 1469, 1483, 1484, 1471, 1475, 1477, 1485, 1478, 1486, + 1487, 1479, 1488, 1480, 1489, 1490, 1491, 1492, 1493, 1495, + 1481, 1496, 1497, 1498, 1499, 1500, 1501, 1502, 1503, 1504, + 1505, 1506, 1507, 1483, 1484, 1508, 1509, 1510, 1485, 1511, + + 1486, 1487, 1512, 1488, 1513, 1489, 1490, 1491, 1492, 1493, + 1495, 1514, 1496, 1497, 1498, 1499, 1500, 1501, 1502, 1503, + 1504, 1505, 1506, 1507, 1515, 1516, 1508, 1509, 1510, 1517, + 1511, 1518, 1519, 1512, 1520, 1513, 1522, 1524, 1525, 1526, + 1527, 1528, 1514, 1529, 1530, 1534, 1537, 1539, 1540, 1541, + 1542, 1543, 1544, 1545, 1546, 1515, 1516, 1550, 1552, 0, + 1517, 1553, 1518, 1519, 1558, 1520, 1562, 1522, 1524, 1525, + 1526, 1527, 1528, 1548, 1529, 1530, 1534, 1537, 1539, 1540, + 1541, 1542, 1543, 1544, 1545, 1546, 1549, 1563, 1550, 1552, + 1548, 1566, 1553, 1557, 1570, 1558, 1549, 1562, 1557, 1571, + + 1572, 1573, 1574, 1575, 1548, 1578, 1579, 1580, 1581, 1582, + 1583, 1584, 1585, 1587, 1588, 1589, 1590, 1549, 1563, 1591, + 1592, 1593, 1566, 1594, 1557, 1570, 1595, 1597, 1598, 1557, + 1571, 1572, 1573, 1574, 1575, 1599, 1578, 1579, 1580, 1581, + 1582, 1583, 1584, 1585, 1587, 1588, 1589, 1590, 1600, 1601, + 1591, 1592, 1593, 1602, 1594, 1604, 1607, 1595, 1597, 1598, + 1608, 1610, 1614, 1616, 1617, 1618, 1599, 1626, 1627, 1629, + 1630, 1631, 1632, 1633, 1634, 1635, 1636, 1626, 1638, 1600, + 1601, 1639, 1640, 1641, 1602, 1642, 1604, 1607, 1627, 1647, + 1648, 1608, 1610, 1614, 1616, 1617, 1618, 1649, 1626, 1627, + + 1629, 1630, 1631, 1632, 1633, 1634, 1635, 1636, 1652, 1638, + 1655, 1656, 1639, 1640, 1641, 1658, 1642, 1660, 1661, 1662, + 1647, 1648, 1663, 1666, 1669, 1671, 1672, 1674, 1649, 1675, + 1676, 1678, 1675, 1679, 1680, 1682, 1683, 1684, 1685, 1652, + 1686, 1655, 1656, 1688, 1689, 1690, 1658, 1674, 1660, 1661, + 1662, 1692, 1693, 1663, 1666, 1669, 1671, 1672, 1674, 1695, + 1675, 1676, 1678, 1696, 1679, 1680, 1682, 1683, 1684, 1685, + 1700, 1686, 1701, 1702, 1688, 1689, 1690, 1703, 1704, 0, + 1706, 1704, 1692, 1693, 1707, 1708, 1705, 1712, 1713, 1715, + 1695, 1716, 1718, 1722, 1696, 1723, 1724, 1725, 0, 1728, + + 1729, 1700, 1731, 1701, 1702, 1726, 1732, 1733, 1703, 1704, + 1705, 1706, 1734, 1738, 1743, 1707, 1708, 1705, 1712, 1713, + 1715, 1744, 1716, 1718, 1722, 1745, 1723, 1724, 1725, 1726, + 1728, 1729, 1748, 1731, 1750, 1751, 1726, 1732, 1733, 1752, + 1755, 1756, 0, 1734, 1738, 1743, 0, 0, 0, 0, + 0, 0, 1744, 0, 0, 0, 1745, 0, 0, 0, + 0, 0, 0, 1748, 0, 1750, 1751, 0, 0, 0, + 1752, 1755, 1756, 1760, 1760, 1760, 1760, 1760, 1761, 1761, + 1761, 1761, 1761, 1762, 1762, 1762, 1762, 1762, 1763, 0, + 1763, 1763, 1763, 1764, 0, 1764, 1764, 1764, 1766, 1766, + + 1766, 1766, 1766, 1767, 1767, 1767, 1767, 1767, 1768, 0, + 1768, 1768, 1768, 1769, 1769, 1769, 1769, 1769, 1770, 1770, + 1770, 1770, 1770, 1771, 1771, 1771, 1771, 1771, 1772, 1772, + 1772, 1772, 1772, 1773, 1773, 0, 1773, 1773, 1774, 0, + 1774, 0, 1774, 1775, 1775, 1775, 1775, 1775, 1776, 1776, + 1776, 1776, 1776, 1777, 1777, 1777, 1777, 1777, 1778, 1778, + 1778, 1778, 1778, 1779, 1779, 1779, 1779, 1779, 1780, 1780, + 1780, 1780, 1780, 1781, 0, 1781, 1781, 1781, 1782, 1782, + 1782, 1782, 1782, 1783, 0, 1783, 1783, 1783, 1784, 1784, + 1784, 1784, 1784, 1759, 1759, 1759, 1759, 1759, 1759, 1759, + + 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, + 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, + 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, + 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, + 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, + 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, + 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, + 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759, 1759 + } ; + +static yy_state_type yy_last_accepting_state; +static char *yy_last_accepting_cpos; + +extern int yy_flex_debug; +int yy_flex_debug = 0; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +char *yytext; +#line 1 "src/maplexer.l" +#line 4 "src/maplexer.l" +/* +** READ ME FIRST! +** +** When this file is altered, it is necessary to do "make lexer". Due to +** problems detailed in #2310 the lexer is no longer automatically rebuilt +** when maplexer.l is altered. +*/ + +#define YY_NO_INPUT + +/* C declarations */ +#include +#include +#include +#include + +#include + +#include "mapserver.h" +#include "maperror.h" +#include "mapfile.h" +#include "maptime.h" +#include "mapsymbol.h" +#include "mapparser.h" +#include "mapprimitive.h" + +/* msyylineno is required for flex 2.5.4 and older, but is already defined by + * flex 2.5.31 (bug 975). + * Unfortunately there is no clean way to differentiate the two versions, + * so we use the symbol YY_CURRENT_BUFFER_LVALUE to base our test since it + * was not present in 2.5.4 and is present in 2.5.31. Hopefully that won't + * put us in trouble with other versions. If that happens then we can + * switch to using autoconf to detect the version. + */ +#ifndef YY_CURRENT_BUFFER_LVALUE +int msyylineno = 1; +#endif + +#define YY_NO_INPUT + +/* Below is a redefinition of the default YY_INPUT() macro but replacing the + * YY_FATAL_ERROR() macro with a call to msSetError(). + */ +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#define YY_INPUT(buf,result,max_size) \ + if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ + { \ + int c = '*'; \ + int n; \ + for ( n = 0; n < max_size && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( yyin ) ) \ + msSetError(MS_PARSEERR, "%s", "msyyparse()", "input in flex scanner failed"); \ + result = n; \ + } \ + else \ + { \ + errno=0; \ + while ( (result = (int) fread(buf, 1, (yy_size_t) max_size, yyin)) == 0 && ferror(yyin)) \ + { \ + if( errno != EINTR) \ + { \ + msSetError(MS_PARSEERR, "%s", "msyyparse()", "input in flex scanner failed"); \ + break; \ + } \ + errno=0; \ + clearerr(yyin); \ + } \ + } + +int msyysource=MS_STRING_TOKENS; +double msyynumber; +int msyystate=MS_TOKENIZE_DEFAULT; +const char *msyystring=NULL; +char *msyybasepath=NULL; +int msyystring_buffer_size = 0; +int msyystring_size; +char msyystring_begin; +char *msyystring_buffer = NULL; +int msyystring_icase = MS_FALSE; +int msyystring_return_state; +int msyystring_begin_state; + +int msyyreturncomments = 0; + +#define MS_LEXER_STRING_REALLOC(string, string_size, max_size) \ + do { \ + const int string_size_macro = (int)(string_size); \ + if (string_size_macro >= (int)(max_size)) { \ + max_size = (((int)(max_size)*2) > string_size_macro) ? ((int)(max_size))*2 : string_size_macro+1; \ + string = (char *) msSmallRealloc(string, sizeof(char *) * (max_size)); \ + } \ + } while(0) + +#define MS_LEXER_RETURN_TOKEN(token) \ + MS_LEXER_STRING_REALLOC(msyystring_buffer, strlen(msyytext), \ + msyystring_buffer_size); \ + strcpy(msyystring_buffer, msyytext); \ + return(token); + +#define MAX_INCLUDE_DEPTH 5 +YY_BUFFER_STATE include_stack[MAX_INCLUDE_DEPTH]; +int include_lineno[MAX_INCLUDE_DEPTH]; +int include_stack_ptr = 0; +char path[MS_MAXPATHLEN]; + +#line 2297 "src/maplexer.c" + +#line 2299 "src/maplexer.c" + +#define INITIAL 0 +#define EXPRESSION_STRING 1 +#define INCLUDE 2 +#define MSSTRING 3 +#define MULTILINE_COMMENT 4 +#define CONFIG_FILE 5 + +#ifndef YY_EXTRA_TYPE +#define YY_EXTRA_TYPE void * +#endif + +static int yy_init_globals ( void ); + +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +int yylex_destroy ( void ); + +int yyget_debug ( void ); + +void yyset_debug ( int debug_flag ); + +YY_EXTRA_TYPE yyget_extra ( void ); + +void yyset_extra ( YY_EXTRA_TYPE user_defined ); + +FILE *yyget_in ( void ); + +void yyset_in ( FILE * _in_str ); + +FILE *yyget_out ( void ); + +void yyset_out ( FILE * _out_str ); + + int yyget_leng ( void ); + +char *yyget_text ( void ); + +int yyget_lineno ( void ); + +void yyset_lineno ( int _line_number ); + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int yywrap ( void ); +#else +extern int yywrap ( void ); +#endif +#endif + +#ifndef YY_NO_UNPUT + + static void yyunput ( int c, char *buf_ptr ); + +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy ( char *, const char *, int ); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen ( const char * ); +#endif + +#ifndef YY_NO_INPUT +#ifdef __cplusplus +static int yyinput ( void ); +#else +static int input ( void ); +#endif + +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k */ +#define YY_READ_BUF_SIZE 16384 +#else +#define YY_READ_BUF_SIZE 8192 +#endif /* __ia64__ */ +#endif + +/* Copy whatever the last rule matched to the standard output. */ +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO do { if (fwrite( yytext, (size_t) yyleng, 1, yyout )) {} } while (0) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ + { \ + int c = '*'; \ + int n; \ + for ( n = 0; n < max_size && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + } \ + else \ + { \ + errno=0; \ + while ( (result = (int) fread(buf, 1, (yy_size_t) max_size, yyin)) == 0 && ferror(yyin)) \ + { \ + if( errno != EINTR) \ + { \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + break; \ + } \ + errno=0; \ + clearerr(yyin); \ + } \ + }\ +\ + +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) +#endif + +/* end tables serialization structures and prototypes */ + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 + +extern int yylex (void); + +#define YY_DECL int yylex (void) +#endif /* !YY_DECL */ + +/* Code executed at the beginning of each rule, after yytext and yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK /*LINTED*/break; +#endif + +#define YY_RULE_SETUP \ + YY_USER_ACTION + +/** The main scanner function which does all the work. + */ +YY_DECL +{ + yy_state_type yy_current_state; + char *yy_cp, *yy_bp; + int yy_act; + + if ( !(yy_init) ) + { + (yy_init) = 1; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! (yy_start) ) + (yy_start) = 1; /* first start state */ + + if ( ! yyin ) + yyin = stdin; + + if ( ! yyout ) + yyout = stdout; + + if ( ! YY_CURRENT_BUFFER ) { + yyensure_buffer_stack (); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer( yyin, YY_BUF_SIZE ); + } + + yy_load_buffer_state( ); + } + + { +#line 123 "src/maplexer.l" + +#line 125 "src/maplexer.l" + if (msyystring_buffer == NULL) + { + msyystring_buffer_size = 256; + msyystring_buffer = (char*) msSmallMalloc(sizeof(char) * msyystring_buffer_size); + } + + msyystring_buffer[0] = '\0'; + switch(msyystate) { + case(MS_TOKENIZE_DEFAULT): + (void) yyunput; /* just to avoid warning about it being unrefed */ + break; + case(MS_TOKENIZE_FILE): + BEGIN(INITIAL); + msyystring_begin_state = INITIAL; + msyysource=MS_FILE_TOKENS; + msyystate=MS_TOKENIZE_DEFAULT; + msyystring=NULL; + msyyreturncomments=0; + include_stack_ptr=0; + return(0); + break; + case(MS_TOKENIZE_STRING): + BEGIN(INITIAL); + msyystring_begin_state = INITIAL; + msyy_delete_buffer(YY_CURRENT_BUFFER); + msyy_scan_string(msyystring); + msyysource=MS_STRING_TOKENS; + msyystate=MS_TOKENIZE_DEFAULT; + msyyin=NULL; + msyyreturncomments=0; + include_stack_ptr=0; + return(0); + break; + case(MS_TOKENIZE_EXPRESSION): + BEGIN(EXPRESSION_STRING); + msyystring_begin_state = EXPRESSION_STRING; + msyy_delete_buffer(YY_CURRENT_BUFFER); + msyy_scan_string(msyystring); + msyystate=MS_TOKENIZE_DEFAULT; + msyyreturncomments=0; + break; + case(MS_TOKENIZE_CONFIG): + BEGIN(CONFIG_FILE); + msyystring_begin_state = CONFIG_FILE; + msyysource=MS_FILE_TOKENS; + msyystate=MS_TOKENIZE_DEFAULT; + msyystring=NULL; + msyyreturncomments=0; + return(0); + break; + case(99): + BEGIN(INITIAL); /* may not need this one */ + msyystring_begin_state = INITIAL; + msyy_delete_buffer(YY_CURRENT_BUFFER); + msyystate=MS_TOKENIZE_DEFAULT; + msyystring=NULL; + msyyreturncomments=0; + return(0); + break; + default: + break; + } + +#line 2579 "src/maplexer.c" + + while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */ + { + yy_cp = (yy_c_buf_p); + + /* Support of yytext. */ + *yy_cp = (yy_hold_char); + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = (yy_start); +yy_match: + do + { + YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ; + if ( yy_accept[yy_current_state] ) + { + (yy_last_accepting_state) = yy_current_state; + (yy_last_accepting_cpos) = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 1760 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + ++yy_cp; + } + while ( yy_current_state != 1759 ); + yy_cp = (yy_last_accepting_cpos); + yy_current_state = (yy_last_accepting_state); + +yy_find_action: + yy_act = yy_accept[yy_current_state]; + + YY_DO_BEFORE_ACTION; + +do_action: /* This label is used only to access EOF actions. */ + + switch ( yy_act ) + { /* beginning of action switch */ + case 0: /* must back up */ + /* undo the effects of YY_DO_BEFORE_ACTION */ + *yy_cp = (yy_hold_char); + yy_cp = (yy_last_accepting_cpos); + yy_current_state = (yy_last_accepting_state); + goto yy_find_action; + +case 1: +YY_RULE_SETUP +#line 188 "src/maplexer.l" +; + YY_BREAK +case 2: +YY_RULE_SETUP +#line 190 "src/maplexer.l" +{ if (msyyreturncomments) return(MS_COMMENT); } + YY_BREAK +case 3: +YY_RULE_SETUP +#line 192 "src/maplexer.l" +{ BEGIN(MULTILINE_COMMENT); } + YY_BREAK +case 4: +YY_RULE_SETUP +#line 193 "src/maplexer.l" +{ BEGIN(INITIAL); } + YY_BREAK +case 5: +YY_RULE_SETUP +#line 194 "src/maplexer.l" +; + YY_BREAK +case 6: +YY_RULE_SETUP +#line 195 "src/maplexer.l" +; + YY_BREAK +case 7: +/* rule 7 can match eol */ +YY_RULE_SETUP +#line 196 "src/maplexer.l" +{ msyylineno++; } + YY_BREAK +case 8: +YY_RULE_SETUP +#line 198 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_CONFIG_SECTION); } + YY_BREAK +case 9: +YY_RULE_SETUP +#line 199 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_CONFIG_SECTION_ENV); } + YY_BREAK +case 10: +YY_RULE_SETUP +#line 200 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_CONFIG_SECTION_MAPS); } + YY_BREAK +case 11: +YY_RULE_SETUP +#line 201 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_CONFIG_SECTION_PLUGINS) } + YY_BREAK +case 12: +YY_RULE_SETUP +#line 203 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_TOKEN_LOGICAL_OR); } + YY_BREAK +case 13: +YY_RULE_SETUP +#line 204 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_TOKEN_LOGICAL_AND); } + YY_BREAK +case 14: +YY_RULE_SETUP +#line 205 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_TOKEN_LOGICAL_NOT); } + YY_BREAK +case 15: +YY_RULE_SETUP +#line 206 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_TOKEN_COMPARISON_EQ); } + YY_BREAK +case 16: +YY_RULE_SETUP +#line 207 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_TOKEN_COMPARISON_NE); } + YY_BREAK +case 17: +YY_RULE_SETUP +#line 208 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_TOKEN_COMPARISON_GT); } + YY_BREAK +case 18: +YY_RULE_SETUP +#line 209 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_TOKEN_COMPARISON_LT); } + YY_BREAK +case 19: +YY_RULE_SETUP +#line 210 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_TOKEN_COMPARISON_GE); } + YY_BREAK +case 20: +YY_RULE_SETUP +#line 211 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_TOKEN_COMPARISON_LE); } + YY_BREAK +case 21: +YY_RULE_SETUP +#line 212 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_TOKEN_COMPARISON_RE); } + YY_BREAK +case 22: +YY_RULE_SETUP +#line 214 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_TOKEN_COMPARISON_IEQ); } + YY_BREAK +case 23: +YY_RULE_SETUP +#line 215 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_TOKEN_COMPARISON_IRE); } + YY_BREAK +case 24: +YY_RULE_SETUP +#line 217 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_TOKEN_COMPARISON_IN); /* was IN */ } + YY_BREAK +case 25: +YY_RULE_SETUP +#line 219 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_TOKEN_FUNCTION_AREA); } + YY_BREAK +case 26: +YY_RULE_SETUP +#line 220 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_TOKEN_FUNCTION_LENGTH); } + YY_BREAK +case 27: +YY_RULE_SETUP +#line 221 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_TOKEN_FUNCTION_TOSTRING); } + YY_BREAK +case 28: +YY_RULE_SETUP +#line 222 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_TOKEN_FUNCTION_COMMIFY); } + YY_BREAK +case 29: +YY_RULE_SETUP +#line 223 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_TOKEN_FUNCTION_ROUND); } + YY_BREAK +case 30: +YY_RULE_SETUP +#line 224 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_TOKEN_FUNCTION_UPPER); } + YY_BREAK +case 31: +YY_RULE_SETUP +#line 225 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_TOKEN_FUNCTION_LOWER); } + YY_BREAK +case 32: +YY_RULE_SETUP +#line 226 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_TOKEN_FUNCTION_INITCAP); } + YY_BREAK +case 33: +YY_RULE_SETUP +#line 227 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_TOKEN_FUNCTION_FIRSTCAP); } + YY_BREAK +case 34: +YY_RULE_SETUP +#line 229 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_TOKEN_FUNCTION_BUFFER); } + YY_BREAK +case 35: +YY_RULE_SETUP +#line 230 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_TOKEN_FUNCTION_DIFFERENCE); } + YY_BREAK +case 36: +YY_RULE_SETUP +#line 231 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_TOKEN_FUNCTION_SIMPLIFY); } + YY_BREAK +case 37: +YY_RULE_SETUP +#line 232 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_TOKEN_FUNCTION_SIMPLIFYPT); } + YY_BREAK +case 38: +YY_RULE_SETUP +#line 233 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_TOKEN_FUNCTION_GENERALIZE); } + YY_BREAK +case 39: +YY_RULE_SETUP +#line 234 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_TOKEN_FUNCTION_SMOOTHSIA); } + YY_BREAK +case 40: +YY_RULE_SETUP +#line 235 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_TOKEN_FUNCTION_CENTERLINE); } + YY_BREAK +case 41: +YY_RULE_SETUP +#line 236 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_TOKEN_FUNCTION_DENSIFY); } + YY_BREAK +case 42: +YY_RULE_SETUP +#line 237 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_TOKEN_FUNCTION_OUTER); } + YY_BREAK +case 43: +YY_RULE_SETUP +#line 238 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_TOKEN_FUNCTION_INNER); } + YY_BREAK +case 44: +YY_RULE_SETUP +#line 239 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_TOKEN_FUNCTION_JAVASCRIPT); } + YY_BREAK +case 45: +YY_RULE_SETUP +#line 241 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_TOKEN_COMPARISON_INTERSECTS); } + YY_BREAK +case 46: +YY_RULE_SETUP +#line 242 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_TOKEN_COMPARISON_DISJOINT); } + YY_BREAK +case 47: +YY_RULE_SETUP +#line 243 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_TOKEN_COMPARISON_TOUCHES); } + YY_BREAK +case 48: +YY_RULE_SETUP +#line 244 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_TOKEN_COMPARISON_OVERLAPS); } + YY_BREAK +case 49: +YY_RULE_SETUP +#line 245 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_TOKEN_COMPARISON_CROSSES); } + YY_BREAK +case 50: +YY_RULE_SETUP +#line 246 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_TOKEN_COMPARISON_WITHIN); } + YY_BREAK +case 51: +YY_RULE_SETUP +#line 247 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_TOKEN_COMPARISON_CONTAINS); } + YY_BREAK +case 52: +YY_RULE_SETUP +#line 248 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_TOKEN_COMPARISON_EQUALS); } + YY_BREAK +case 53: +YY_RULE_SETUP +#line 249 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_TOKEN_COMPARISON_BEYOND); } + YY_BREAK +case 54: +YY_RULE_SETUP +#line 250 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_TOKEN_COMPARISON_DWITHIN); } + YY_BREAK +case 55: +YY_RULE_SETUP +#line 252 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_TOKEN_FUNCTION_FROMTEXT); } + YY_BREAK +case 56: +YY_RULE_SETUP +#line 254 "src/maplexer.l" +{ msyynumber=MS_TRUE; return(MS_TOKEN_LITERAL_BOOLEAN); } + YY_BREAK +case 57: +YY_RULE_SETUP +#line 255 "src/maplexer.l" +{ msyynumber=MS_FALSE; return(MS_TOKEN_LITERAL_BOOLEAN); } + YY_BREAK +case 58: +YY_RULE_SETUP +#line 257 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(COLORRANGE); } + YY_BREAK +case 59: +YY_RULE_SETUP +#line 258 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(DATARANGE); } + YY_BREAK +case 60: +YY_RULE_SETUP +#line 259 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(RANGEITEM); } + YY_BREAK +case 61: +YY_RULE_SETUP +#line 261 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(ALIGN); } + YY_BREAK +case 62: +YY_RULE_SETUP +#line 262 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(ANCHORPOINT); } + YY_BREAK +case 63: +YY_RULE_SETUP +#line 263 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(ANGLE); } + YY_BREAK +case 64: +YY_RULE_SETUP +#line 264 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(ANTIALIAS); } + YY_BREAK +case 65: +YY_RULE_SETUP +#line 265 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(BACKGROUNDCOLOR); } + YY_BREAK +case 66: +YY_RULE_SETUP +#line 266 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(BANDSITEM); } + YY_BREAK +case 67: +YY_RULE_SETUP +#line 267 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(BINDVALS); } + YY_BREAK +case 68: +YY_RULE_SETUP +#line 268 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(BOM); } + YY_BREAK +case 69: +YY_RULE_SETUP +#line 269 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(BROWSEFORMAT); } + YY_BREAK +case 70: +YY_RULE_SETUP +#line 270 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(BUFFER); } + YY_BREAK +case 71: +YY_RULE_SETUP +#line 271 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(CHARACTER); } + YY_BREAK +case 72: +YY_RULE_SETUP +#line 272 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(CLASS); } + YY_BREAK +case 73: +YY_RULE_SETUP +#line 273 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(CLASSITEM); } + YY_BREAK +case 74: +YY_RULE_SETUP +#line 274 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(CLASSGROUP); } + YY_BREAK +case 75: +YY_RULE_SETUP +#line 275 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(CLUSTER); } + YY_BREAK +case 76: +YY_RULE_SETUP +#line 276 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(COLOR); } + YY_BREAK +case 77: +YY_RULE_SETUP +#line 277 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(COMPFILTER); } + YY_BREAK +case 78: +YY_RULE_SETUP +#line 278 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(COMPOSITE); } + YY_BREAK +case 79: +YY_RULE_SETUP +#line 279 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(COMPOP); } + YY_BREAK +case 80: +YY_RULE_SETUP +#line 280 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(CONFIG); } + YY_BREAK +case 81: +YY_RULE_SETUP +#line 281 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(CONNECTION); } + YY_BREAK +case 82: +YY_RULE_SETUP +#line 282 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(CONNECTIONTYPE); } + YY_BREAK +case 83: +YY_RULE_SETUP +#line 283 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(DATA); } + YY_BREAK +case 84: +YY_RULE_SETUP +#line 284 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(DEBUG); } + YY_BREAK +case 85: +YY_RULE_SETUP +#line 285 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(DRIVER); } + YY_BREAK +case 86: +YY_RULE_SETUP +#line 286 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(EMPTY); } + YY_BREAK +case 87: +YY_RULE_SETUP +#line 287 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(ENCODING); } + YY_BREAK +case 88: +YY_RULE_SETUP +#line 288 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(END); } + YY_BREAK +case 89: +YY_RULE_SETUP +#line 289 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(ERROR); } + YY_BREAK +case 90: +YY_RULE_SETUP +#line 290 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(EXPRESSION); } + YY_BREAK +case 91: +YY_RULE_SETUP +#line 291 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(EXTENT); } + YY_BREAK +case 92: +YY_RULE_SETUP +#line 292 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(EXTENSION); } + YY_BREAK +case 93: +YY_RULE_SETUP +#line 293 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(FALLBACK); } + YY_BREAK +case 94: +YY_RULE_SETUP +#line 294 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(FEATURE); } + YY_BREAK +case 95: +YY_RULE_SETUP +#line 295 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(FILLED); } + YY_BREAK +case 96: +YY_RULE_SETUP +#line 296 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(FILTER); } + YY_BREAK +case 97: +YY_RULE_SETUP +#line 297 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(FILTERITEM); } + YY_BREAK +case 98: +YY_RULE_SETUP +#line 298 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(FOOTER); } + YY_BREAK +case 99: +YY_RULE_SETUP +#line 299 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(FONT); } + YY_BREAK +case 100: +YY_RULE_SETUP +#line 300 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(FONTSET); } + YY_BREAK +case 101: +YY_RULE_SETUP +#line 301 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(FORCE); } + YY_BREAK +case 102: +YY_RULE_SETUP +#line 302 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(FORMATOPTION); } + YY_BREAK +case 103: +YY_RULE_SETUP +#line 303 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(FROM); } + YY_BREAK +case 104: +YY_RULE_SETUP +#line 304 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(GAP); } + YY_BREAK +case 105: +YY_RULE_SETUP +#line 305 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(GEOMTRANSFORM); } + YY_BREAK +case 106: +YY_RULE_SETUP +#line 306 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(GRID); } + YY_BREAK +case 107: +YY_RULE_SETUP +#line 307 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(GRIDSTEP); } + YY_BREAK +case 108: +YY_RULE_SETUP +#line 308 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(GRATICULE); } + YY_BREAK +case 109: +YY_RULE_SETUP +#line 309 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(GROUP); } + YY_BREAK +case 110: +YY_RULE_SETUP +#line 310 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(HEADER); } + YY_BREAK +case 111: +YY_RULE_SETUP +#line 311 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(IMAGE); } + YY_BREAK +case 112: +YY_RULE_SETUP +#line 312 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(IMAGECOLOR); } + YY_BREAK +case 113: +YY_RULE_SETUP +#line 313 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(IMAGETYPE); } + YY_BREAK +case 114: +YY_RULE_SETUP +#line 314 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(IMAGEMODE); } + YY_BREAK +case 115: +YY_RULE_SETUP +#line 315 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(IMAGEPATH); } + YY_BREAK +case 116: +YY_RULE_SETUP +#line 316 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(TEMPPATH); } + YY_BREAK +case 117: +YY_RULE_SETUP +#line 317 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(IMAGEURL); } + YY_BREAK +case 118: +YY_RULE_SETUP +#line 318 "src/maplexer.l" +{ BEGIN(INCLUDE); } + YY_BREAK +case 119: +YY_RULE_SETUP +#line 319 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(INDEX); } + YY_BREAK +case 120: +YY_RULE_SETUP +#line 320 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(INITIALGAP); } + YY_BREAK +case 121: +YY_RULE_SETUP +#line 321 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(INTERVALS); } + YY_BREAK +case 122: +YY_RULE_SETUP +#line 322 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(JOIN); } + YY_BREAK +case 123: +YY_RULE_SETUP +#line 323 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(KEYIMAGE); } + YY_BREAK +case 124: +YY_RULE_SETUP +#line 324 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(KEYSIZE); } + YY_BREAK +case 125: +YY_RULE_SETUP +#line 325 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(KEYSPACING); } + YY_BREAK +case 126: +YY_RULE_SETUP +#line 326 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(LABEL); } + YY_BREAK +case 127: +YY_RULE_SETUP +#line 327 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(LABELCACHE); } + YY_BREAK +case 128: +YY_RULE_SETUP +#line 328 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(LABELFORMAT); } + YY_BREAK +case 129: +YY_RULE_SETUP +#line 329 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(LABELITEM); } + YY_BREAK +case 130: +YY_RULE_SETUP +#line 330 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(LABELMAXSCALE); } + YY_BREAK +case 131: +YY_RULE_SETUP +#line 331 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(LABELMAXSCALEDENOM); } + YY_BREAK +case 132: +YY_RULE_SETUP +#line 332 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(LABELMINSCALE); } + YY_BREAK +case 133: +YY_RULE_SETUP +#line 333 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(LABELMINSCALEDENOM); } + YY_BREAK +case 134: +YY_RULE_SETUP +#line 334 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(LABELREQUIRES); } + YY_BREAK +case 135: +YY_RULE_SETUP +#line 335 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(LATLON); } + YY_BREAK +case 136: +YY_RULE_SETUP +#line 336 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(LAYER); } + YY_BREAK +case 137: +YY_RULE_SETUP +#line 337 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(LEADER); } + YY_BREAK +case 138: +YY_RULE_SETUP +#line 338 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(LEGEND); } + YY_BREAK +case 139: +YY_RULE_SETUP +#line 339 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(LEGENDFORMAT); } + YY_BREAK +case 140: +YY_RULE_SETUP +#line 340 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(LINECAP); } + YY_BREAK +case 141: +YY_RULE_SETUP +#line 341 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(LINEJOIN); } + YY_BREAK +case 142: +YY_RULE_SETUP +#line 342 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(LINEJOINMAXSIZE); } + YY_BREAK +case 143: +YY_RULE_SETUP +#line 343 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MAP); } + YY_BREAK +case 144: +YY_RULE_SETUP +#line 344 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MARKER); } + YY_BREAK +case 145: +YY_RULE_SETUP +#line 345 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MARKERSIZE); } + YY_BREAK +case 146: +YY_RULE_SETUP +#line 346 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MASK); } + YY_BREAK +case 147: +YY_RULE_SETUP +#line 347 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MAXARCS); } + YY_BREAK +case 148: +YY_RULE_SETUP +#line 348 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MAXBOXSIZE); } + YY_BREAK +case 149: +YY_RULE_SETUP +#line 349 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MAXDISTANCE); } + YY_BREAK +case 150: +YY_RULE_SETUP +#line 350 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MAXFEATURES); } + YY_BREAK +case 151: +YY_RULE_SETUP +#line 351 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MAXINTERVAL); } + YY_BREAK +case 152: +YY_RULE_SETUP +#line 352 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MAXSCALE); } + YY_BREAK +case 153: +YY_RULE_SETUP +#line 353 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MAXSCALEDENOM); } + YY_BREAK +case 154: +YY_RULE_SETUP +#line 354 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MAXGEOWIDTH); } + YY_BREAK +case 155: +YY_RULE_SETUP +#line 355 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MAXLENGTH); } + YY_BREAK +case 156: +YY_RULE_SETUP +#line 356 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MAXSIZE); } + YY_BREAK +case 157: +YY_RULE_SETUP +#line 357 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MAXSUBDIVIDE); } + YY_BREAK +case 158: +YY_RULE_SETUP +#line 358 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MAXTEMPLATE); } + YY_BREAK +case 159: +YY_RULE_SETUP +#line 359 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MAXWIDTH); } + YY_BREAK +case 160: +YY_RULE_SETUP +#line 360 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(METADATA); } + YY_BREAK +case 161: +YY_RULE_SETUP +#line 361 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MIMETYPE); } + YY_BREAK +case 162: +YY_RULE_SETUP +#line 362 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MINARCS); } + YY_BREAK +case 163: +YY_RULE_SETUP +#line 363 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MINBOXSIZE); } + YY_BREAK +case 164: +YY_RULE_SETUP +#line 364 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MINDISTANCE); } + YY_BREAK +case 165: +YY_RULE_SETUP +#line 365 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(REPEATDISTANCE); } + YY_BREAK +case 166: +YY_RULE_SETUP +#line 366 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MAXOVERLAPANGLE); } + YY_BREAK +case 167: +YY_RULE_SETUP +#line 367 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MINFEATURESIZE); } + YY_BREAK +case 168: +YY_RULE_SETUP +#line 368 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MININTERVAL); } + YY_BREAK +case 169: +YY_RULE_SETUP +#line 369 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MINSCALE); } + YY_BREAK +case 170: +YY_RULE_SETUP +#line 370 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MINSCALEDENOM); } + YY_BREAK +case 171: +YY_RULE_SETUP +#line 371 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MINGEOWIDTH); } + YY_BREAK +case 172: +YY_RULE_SETUP +#line 372 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MINSIZE); } + YY_BREAK +case 173: +YY_RULE_SETUP +#line 373 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MINSUBDIVIDE); } + YY_BREAK +case 174: +YY_RULE_SETUP +#line 374 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MINTEMPLATE); } + YY_BREAK +case 175: +YY_RULE_SETUP +#line 375 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MINWIDTH); } + YY_BREAK +case 176: +YY_RULE_SETUP +#line 376 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(NAME); } + YY_BREAK +case 177: +YY_RULE_SETUP +#line 377 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(OFFSET); } + YY_BREAK +case 178: +YY_RULE_SETUP +#line 378 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(OFFSITE); } + YY_BREAK +case 179: +YY_RULE_SETUP +#line 379 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(OPACITY); } + YY_BREAK +case 180: +YY_RULE_SETUP +#line 380 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(CONNECTIONOPTIONS); } + YY_BREAK +case 181: +YY_RULE_SETUP +#line 381 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(OUTLINECOLOR); } + YY_BREAK +case 182: +YY_RULE_SETUP +#line 382 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(OUTLINEWIDTH); } + YY_BREAK +case 183: +YY_RULE_SETUP +#line 383 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(OUTPUTFORMAT); } + YY_BREAK +case 184: +YY_RULE_SETUP +#line 384 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(PARTIALS); } + YY_BREAK +case 185: +YY_RULE_SETUP +#line 385 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(PATTERN); } + YY_BREAK +case 186: +YY_RULE_SETUP +#line 386 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(POINTS); } + YY_BREAK +case 187: +YY_RULE_SETUP +#line 387 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(ITEMS); } + YY_BREAK +case 188: +YY_RULE_SETUP +#line 388 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(POSITION); } + YY_BREAK +case 189: +YY_RULE_SETUP +#line 389 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(POSTLABELCACHE); } + YY_BREAK +case 190: +YY_RULE_SETUP +#line 390 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(PRIORITY); } + YY_BREAK +case 191: +YY_RULE_SETUP +#line 391 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(PROCESSING); } + YY_BREAK +case 192: +YY_RULE_SETUP +#line 392 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(PROJECTION); } + YY_BREAK +case 193: +YY_RULE_SETUP +#line 393 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(QUERYFORMAT); } + YY_BREAK +case 194: +YY_RULE_SETUP +#line 394 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(QUERYMAP); } + YY_BREAK +case 195: +YY_RULE_SETUP +#line 395 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(REFERENCE); } + YY_BREAK +case 196: +YY_RULE_SETUP +#line 396 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(REGION); } + YY_BREAK +case 197: +YY_RULE_SETUP +#line 397 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(RELATIVETO); } + YY_BREAK +case 198: +YY_RULE_SETUP +#line 398 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(REQUIRES); } + YY_BREAK +case 199: +YY_RULE_SETUP +#line 399 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(RESOLUTION); } + YY_BREAK +case 200: +YY_RULE_SETUP +#line 400 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(DEFRESOLUTION); } + YY_BREAK +case 201: +YY_RULE_SETUP +#line 401 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(SCALE); } + YY_BREAK +case 202: +YY_RULE_SETUP +#line 402 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(SCALEDENOM); } + YY_BREAK +case 203: +YY_RULE_SETUP +#line 403 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(SCALEBAR); } + YY_BREAK +case 204: +YY_RULE_SETUP +#line 404 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(SCALETOKEN); } + YY_BREAK +case 205: +YY_RULE_SETUP +#line 405 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(SHADOWCOLOR); } + YY_BREAK +case 206: +YY_RULE_SETUP +#line 406 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(SHADOWSIZE); } + YY_BREAK +case 207: +YY_RULE_SETUP +#line 407 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(SHAPEPATH); } + YY_BREAK +case 208: +YY_RULE_SETUP +#line 408 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(SIZE); } + YY_BREAK +case 209: +YY_RULE_SETUP +#line 409 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(SIZEUNITS); } + YY_BREAK +case 210: +YY_RULE_SETUP +#line 410 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(STATUS); } + YY_BREAK +case 211: +YY_RULE_SETUP +#line 411 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(STYLE); } + YY_BREAK +case 212: +YY_RULE_SETUP +#line 412 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(STYLEITEM); } + YY_BREAK +case 213: +YY_RULE_SETUP +#line 413 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(SYMBOL); } + YY_BREAK +case 214: +YY_RULE_SETUP +#line 414 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(SYMBOLSCALE); } + YY_BREAK +case 215: +YY_RULE_SETUP +#line 415 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(SYMBOLSCALEDENOM); } + YY_BREAK +case 216: +YY_RULE_SETUP +#line 416 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(SYMBOLSET); } + YY_BREAK +case 217: +YY_RULE_SETUP +#line 417 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(TABLE); } + YY_BREAK +case 218: +YY_RULE_SETUP +#line 418 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(TEMPLATE); } + YY_BREAK +case 219: +YY_RULE_SETUP +#line 419 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(TEXT); } + YY_BREAK +case 220: +YY_RULE_SETUP +#line 420 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(TILEINDEX); } + YY_BREAK +case 221: +YY_RULE_SETUP +#line 421 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(TILEITEM); } + YY_BREAK +case 222: +YY_RULE_SETUP +#line 422 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(TILESRS); } + YY_BREAK +case 223: +YY_RULE_SETUP +#line 423 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(TITLE); } + YY_BREAK +case 224: +YY_RULE_SETUP +#line 424 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(TO); } + YY_BREAK +case 225: +YY_RULE_SETUP +#line 425 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(TOLERANCE); } + YY_BREAK +case 226: +YY_RULE_SETUP +#line 426 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(TOLERANCEUNITS); } + YY_BREAK +case 227: +YY_RULE_SETUP +#line 427 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(IDENTIFY); } + YY_BREAK +case 228: +YY_RULE_SETUP +#line 428 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(CLASSAUTO); } + YY_BREAK +case 229: +YY_RULE_SETUP +#line 429 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(TRANSPARENT); } + YY_BREAK +case 230: +YY_RULE_SETUP +#line 430 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(TRANSFORM); } + YY_BREAK +case 231: +YY_RULE_SETUP +#line 431 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(TYPE); } + YY_BREAK +case 232: +YY_RULE_SETUP +#line 432 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(UNITS); } + YY_BREAK +case 233: +YY_RULE_SETUP +#line 433 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(UTFDATA); } + YY_BREAK +case 234: +YY_RULE_SETUP +#line 434 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(UTFITEM); } + YY_BREAK +case 235: +YY_RULE_SETUP +#line 435 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(VALIDATION); } + YY_BREAK +case 236: +YY_RULE_SETUP +#line 436 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(VALUES); } + YY_BREAK +case 237: +YY_RULE_SETUP +#line 437 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(WEB); } + YY_BREAK +case 238: +YY_RULE_SETUP +#line 438 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(WIDTH); } + YY_BREAK +case 239: +YY_RULE_SETUP +#line 439 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(WKT); } + YY_BREAK +case 240: +YY_RULE_SETUP +#line 440 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(WRAP); } + YY_BREAK +case 241: +YY_RULE_SETUP +#line 442 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_LAYER_ANNOTATION); } + YY_BREAK +case 242: +YY_RULE_SETUP +#line 443 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_AUTO); } + YY_BREAK +case 243: +YY_RULE_SETUP +#line 444 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_AUTO2); } + YY_BREAK +case 244: +YY_RULE_SETUP +#line 445 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_CJC_BEVEL); } + YY_BREAK +case 245: +YY_RULE_SETUP +#line 446 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_BITMAP); } + YY_BREAK +case 246: +YY_RULE_SETUP +#line 447 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_CJC_BUTT); } + YY_BREAK +case 247: +YY_RULE_SETUP +#line 448 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_CC); } + YY_BREAK +case 248: +YY_RULE_SETUP +#line 449 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_ALIGN_CENTER); } + YY_BREAK +case 249: +YY_RULE_SETUP +#line 450 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_LAYER_CHART); } + YY_BREAK +case 250: +YY_RULE_SETUP +#line 451 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_LAYER_CIRCLE); } + YY_BREAK +case 251: +YY_RULE_SETUP +#line 452 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_CL); } + YY_BREAK +case 252: +YY_RULE_SETUP +#line 453 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_CR); } + YY_BREAK +case 253: +YY_RULE_SETUP +#line 454 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_DB_CSV); } + YY_BREAK +case 254: +YY_RULE_SETUP +#line 455 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_DB_POSTGRES); } + YY_BREAK +case 255: +YY_RULE_SETUP +#line 456 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_DB_MYSQL); } + YY_BREAK +case 256: +YY_RULE_SETUP +#line 457 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_DEFAULT); } + YY_BREAK +case 257: +YY_RULE_SETUP +#line 458 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_DD); } + YY_BREAK +case 258: +YY_RULE_SETUP +#line 459 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_SYMBOL_ELLIPSE); } + YY_BREAK +case 259: +YY_RULE_SETUP +#line 460 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_EMBED); } + YY_BREAK +case 260: +YY_RULE_SETUP +#line 461 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_FALSE); } + YY_BREAK +case 261: +YY_RULE_SETUP +#line 462 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_FEET); } + YY_BREAK +case 262: +YY_RULE_SETUP +#line 463 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_FOLLOW); } + YY_BREAK +case 263: +YY_RULE_SETUP +#line 464 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_GIANT); } + YY_BREAK +case 264: +YY_RULE_SETUP +#line 465 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_SYMBOL_HATCH); } + YY_BREAK +case 265: +YY_RULE_SETUP +#line 466 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_KERNELDENSITY); } + YY_BREAK +case 266: +YY_RULE_SETUP +#line 467 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_IDW); } + YY_BREAK +case 267: +YY_RULE_SETUP +#line 468 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_HILITE); } + YY_BREAK +case 268: +YY_RULE_SETUP +#line 469 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_INCHES); } + YY_BREAK +case 269: +YY_RULE_SETUP +#line 470 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_KILOMETERS); } + YY_BREAK +case 270: +YY_RULE_SETUP +#line 471 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_LARGE); } + YY_BREAK +case 271: +YY_RULE_SETUP +#line 472 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_LC); } + YY_BREAK +case 272: +YY_RULE_SETUP +#line 473 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_ALIGN_LEFT); } + YY_BREAK +case 273: +YY_RULE_SETUP +#line 474 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_LAYER_LINE); } + YY_BREAK +case 274: +YY_RULE_SETUP +#line 475 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_LL); } + YY_BREAK +case 275: +YY_RULE_SETUP +#line 476 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_LR); } + YY_BREAK +case 276: +YY_RULE_SETUP +#line 477 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_MEDIUM); } + YY_BREAK +case 277: +YY_RULE_SETUP +#line 478 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_METERS); } + YY_BREAK +case 278: +YY_RULE_SETUP +#line 479 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_NAUTICALMILES); } + YY_BREAK +case 279: +YY_RULE_SETUP +#line 480 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_MILES); } + YY_BREAK +case 280: +YY_RULE_SETUP +#line 481 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_CJC_MITER); } + YY_BREAK +case 281: +YY_RULE_SETUP +#line 482 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_MULTIPLE); } + YY_BREAK +case 282: +YY_RULE_SETUP +#line 483 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_CJC_NONE); } + YY_BREAK +case 283: +YY_RULE_SETUP +#line 484 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_NORMAL); } + YY_BREAK +case 284: +YY_RULE_SETUP +#line 485 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_OFF); } + YY_BREAK +case 285: +YY_RULE_SETUP +#line 486 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_OGR); } + YY_BREAK +case 286: +YY_RULE_SETUP +#line 487 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_FLATGEOBUF); } + YY_BREAK +case 287: +YY_RULE_SETUP +#line 488 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_ON); } + YY_BREAK +case 288: +YY_RULE_SETUP +#line 489 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_JOIN_ONE_TO_ONE); } + YY_BREAK +case 289: +YY_RULE_SETUP +#line 490 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_JOIN_ONE_TO_MANY); } + YY_BREAK +case 290: +YY_RULE_SETUP +#line 491 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_ORACLESPATIAL); } + YY_BREAK +case 291: +YY_RULE_SETUP +#line 492 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_PERCENTAGES); } + YY_BREAK +case 292: +YY_RULE_SETUP +#line 493 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_SYMBOL_PIXMAP); } + YY_BREAK +case 293: +YY_RULE_SETUP +#line 494 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_PIXELS); } + YY_BREAK +case 294: +YY_RULE_SETUP +#line 495 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_LAYER_POINT); } + YY_BREAK +case 295: +YY_RULE_SETUP +#line 496 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_LAYER_POLYGON); } + YY_BREAK +case 296: +YY_RULE_SETUP +#line 497 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_POSTGIS); } + YY_BREAK +case 297: +YY_RULE_SETUP +#line 498 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_PLUGIN); } + YY_BREAK +case 298: +YY_RULE_SETUP +#line 499 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_LAYER_QUERY); } + YY_BREAK +case 299: +YY_RULE_SETUP +#line 500 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_LAYER_RASTER); } + YY_BREAK +case 300: +YY_RULE_SETUP +#line 501 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_RASTER_LABEL); } + YY_BREAK +case 301: +YY_RULE_SETUP +#line 502 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_ALIGN_RIGHT); } + YY_BREAK +case 302: +YY_RULE_SETUP +#line 503 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_CJC_ROUND); } + YY_BREAK +case 303: +YY_RULE_SETUP +#line 504 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_SELECTED); } + YY_BREAK +case 304: +YY_RULE_SETUP +#line 505 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_SYMBOL_SIMPLE); } + YY_BREAK +case 305: +YY_RULE_SETUP +#line 506 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_SINGLE); } + YY_BREAK +case 306: +YY_RULE_SETUP +#line 507 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_SMALL); } + YY_BREAK +case 307: +YY_RULE_SETUP +#line 508 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_CJC_SQUARE); } + YY_BREAK +case 308: +YY_RULE_SETUP +#line 509 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_SYMBOL_SVG); } + YY_BREAK +case 309: +YY_RULE_SETUP +#line 510 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(POLAROFFSET); } + YY_BREAK +case 310: +YY_RULE_SETUP +#line 511 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_TINY); } + YY_BREAK +case 311: +YY_RULE_SETUP +#line 512 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_CJC_TRIANGLE); } + YY_BREAK +case 312: +YY_RULE_SETUP +#line 513 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_TRUE); } + YY_BREAK +case 313: +YY_RULE_SETUP +#line 514 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_TRUETYPE); } + YY_BREAK +case 314: +YY_RULE_SETUP +#line 515 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_UC); } + YY_BREAK +case 315: +YY_RULE_SETUP +#line 516 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_UL); } + YY_BREAK +case 316: +YY_RULE_SETUP +#line 517 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_UR); } + YY_BREAK +case 317: +YY_RULE_SETUP +#line 518 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_UNION); } + YY_BREAK +case 318: +YY_RULE_SETUP +#line 519 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_UVRASTER); } + YY_BREAK +case 319: +YY_RULE_SETUP +#line 520 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_CONTOUR); } + YY_BREAK +case 320: +YY_RULE_SETUP +#line 521 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_SYMBOL_VECTOR); } + YY_BREAK +case 321: +YY_RULE_SETUP +#line 522 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_WFS); } + YY_BREAK +case 322: +YY_RULE_SETUP +#line 523 "src/maplexer.l" +{ MS_LEXER_RETURN_TOKEN(MS_WMS); } + YY_BREAK +case 323: +/* rule 323 can match eol */ +YY_RULE_SETUP +#line 525 "src/maplexer.l" +{ + msyytext++; + msyytext[msyyleng-1-1] = '\0'; + MS_LEXER_STRING_REALLOC(msyystring_buffer, msyyleng, + msyystring_buffer_size); + strcpy(msyystring_buffer,msyytext); + return(MS_BINDING); + } + YY_BREAK +case 324: +YY_RULE_SETUP +#line 534 "src/maplexer.l" +{ + /* attribute binding - shape (fixed value) */ + return(MS_TOKEN_BINDING_SHAPE); +} + YY_BREAK +case 325: +YY_RULE_SETUP +#line 538 "src/maplexer.l" +{ + /* attribute binding - map cellsize */ + return(MS_TOKEN_BINDING_MAP_CELLSIZE); +} + YY_BREAK +case 326: +YY_RULE_SETUP +#line 542 "src/maplexer.l" +{ + /* attribute binding - data cellsize */ + return(MS_TOKEN_BINDING_DATA_CELLSIZE); +} + YY_BREAK +case 327: +/* rule 327 can match eol */ +YY_RULE_SETUP +#line 546 "src/maplexer.l" +{ + /* attribute binding - numeric (no quotes) */ + msyytext++; + msyytext[msyyleng-1-1] = '\0'; + MS_LEXER_STRING_REALLOC(msyystring_buffer, msyyleng, + msyystring_buffer_size); + strcpy(msyystring_buffer, msyytext); + msStringUnescape(msyystring_buffer, ']'); + return(MS_TOKEN_BINDING_DOUBLE); +} + YY_BREAK +case 328: +/* rule 328 can match eol */ +YY_RULE_SETUP +#line 556 "src/maplexer.l" +{ + /* attribute binding - string (single or double quotes) */ + msyytext[msyyleng-2] = '\0'; + MS_LEXER_STRING_REALLOC(msyystring_buffer, msyyleng, + msyystring_buffer_size); + strcpy(msyystring_buffer, msyytext + 2); + msStringUnescape(msyystring_buffer, msyytext[0]); + return(MS_TOKEN_BINDING_STRING); +} + YY_BREAK +case 329: +/* rule 329 can match eol */ +YY_RULE_SETUP +#line 565 "src/maplexer.l" +{ + /* attribute binding - time */ + msyytext+=2; + msyytext[msyyleng-2-2] = '\0'; + MS_LEXER_STRING_REALLOC(msyystring_buffer, msyyleng, + msyystring_buffer_size); + strcpy(msyystring_buffer, msyytext); + msStringUnescape(msyystring_buffer, '`'); + return(MS_TOKEN_BINDING_TIME); +} + YY_BREAK +case 330: +YY_RULE_SETUP +#line 576 "src/maplexer.l" +{ + MS_LEXER_STRING_REALLOC(msyystring_buffer, msyyleng, + msyystring_buffer_size); + strcpy(msyystring_buffer,msyytext); + msyynumber = atof(msyytext); + return(MS_NUMBER); +} + YY_BREAK +case 331: +YY_RULE_SETUP +#line 584 "src/maplexer.l" +{ + MS_LEXER_STRING_REALLOC(msyystring_buffer, msyyleng, + msyystring_buffer_size); + strcpy(msyystring_buffer,msyytext); + msyynumber = atof(msyytext); + return(MS_TOKEN_LITERAL_NUMBER); +} + YY_BREAK +case 332: +/* rule 332 can match eol */ +YY_RULE_SETUP +#line 592 "src/maplexer.l" +{ + msyytext++; + msyytext[msyyleng-1-1] = '\0'; + MS_LEXER_STRING_REALLOC(msyystring_buffer, msyyleng, + msyystring_buffer_size); + strcpy(msyystring_buffer, msyytext); + return(MS_TOKEN_LITERAL_TIME); +} + YY_BREAK +case 333: +/* rule 333 can match eol */ +YY_RULE_SETUP +#line 601 "src/maplexer.l" +{ + msyytext++; + msyytext[msyyleng-1-2] = '\0'; + MS_LEXER_STRING_REALLOC(msyystring_buffer, msyyleng, + msyystring_buffer_size); + strcpy(msyystring_buffer, msyytext); + return(MS_IREGEX); + } + YY_BREAK +case 334: +/* rule 334 can match eol */ +YY_RULE_SETUP +#line 610 "src/maplexer.l" +{ + msyytext++; + msyytext[msyyleng-1-1] = '\0'; + MS_LEXER_STRING_REALLOC(msyystring_buffer, msyyleng, + msyystring_buffer_size); + strcpy(msyystring_buffer, msyytext); + return(MS_REGEX); + } + YY_BREAK +case 335: +YY_RULE_SETUP +#line 619 "src/maplexer.l" +{ + msyytext++; + msyytext[msyyleng-1-1] = '\0'; + MS_LEXER_STRING_REALLOC(msyystring_buffer, msyyleng, + msyystring_buffer_size); + strcpy(msyystring_buffer, msyytext); + return(MS_EXPRESSION); + } + YY_BREAK +case 336: +YY_RULE_SETUP +#line 628 "src/maplexer.l" +{ + msyytext++; + msyytext[msyyleng-1-1] = '\0'; + MS_LEXER_STRING_REALLOC(msyystring_buffer, msyyleng, + msyystring_buffer_size); + strcpy(msyystring_buffer, msyytext); + return(MS_LIST); + } + YY_BREAK +case 337: +YY_RULE_SETUP +#line 637 "src/maplexer.l" +{ + msyystring_return_state = MS_STRING; + msyystring_begin = msyytext[0]; + msyystring_size = 0; + msyystring_buffer[0] = '\0'; + BEGIN(MSSTRING); + } + YY_BREAK +case 338: +YY_RULE_SETUP +#line 645 "src/maplexer.l" +{ + if (msyystring_begin == msyytext[0]) { + BEGIN(msyystring_begin_state); + if (msyystring_return_state == MS_STRING) { + if (msyystring_icase && msyyleng==2) { + msyystring_icase = MS_FALSE; // reset + return MS_ISTRING; + } else + return MS_STRING; + } + return msyystring_return_state; + + } + else { + int old_size = msyystring_size; + msyystring_size += (msyyleng==2) ? 2 : 1; + MS_LEXER_STRING_REALLOC(msyystring_buffer, msyystring_size, + msyystring_buffer_size); + msyystring_buffer[old_size] = *msyytext; + if (msyyleng==2) { + msyystring_buffer[old_size+1] = msyytext[1]; + } + msyystring_buffer[msyystring_size] = '\0'; + } + } + YY_BREAK +case 339: +YY_RULE_SETUP +#line 671 "src/maplexer.l" +{ + ++msyystring_size; + MS_LEXER_STRING_REALLOC(msyystring_buffer, msyystring_size, + msyystring_buffer_size); + + if (msyyleng == 2) + msyystring_buffer[msyystring_size-1] = msyytext[1]; + else + msyystring_buffer[msyystring_size-1] = msyytext[0]; + msyystring_buffer[msyystring_size] = '\0'; + } + YY_BREAK +case 340: +/* rule 340 can match eol */ +YY_RULE_SETUP +#line 683 "src/maplexer.l" +{ + int old_size = msyystring_size; + msyystring_size += msyyleng; + MS_LEXER_STRING_REALLOC(msyystring_buffer, msyystring_size, + msyystring_buffer_size); + memcpy(msyystring_buffer + old_size, msyytext, msyyleng + 1); + } + YY_BREAK +case 341: +/* rule 341 can match eol */ +YY_RULE_SETUP +#line 691 "src/maplexer.l" +{ + msyytext++; + msyytext[msyyleng-1-1] = '\0'; + + if(include_stack_ptr >= MAX_INCLUDE_DEPTH) { + msSetError(MS_IOERR, "Includes nested to deeply.", "msyylex()"); + return(-1); + } + + msyyin = fopen(msBuildPath(path, msyybasepath, msyytext), "r"); + if(!msyyin) { + msSetError(MS_IOERR, "Error opening included file \"%s\".", "msyylex()", msyytext); + msyyin = YY_CURRENT_BUFFER->yy_input_file; + return(-1); + } + + include_stack[include_stack_ptr] = YY_CURRENT_BUFFER; /* save state */ + include_lineno[include_stack_ptr] = msyylineno; + include_stack_ptr++; + + msyy_switch_to_buffer( msyy_create_buffer(msyyin, YY_BUF_SIZE) ); + msyylineno = 1; + + BEGIN(INITIAL); + } + YY_BREAK +case 342: +YY_RULE_SETUP +#line 717 "src/maplexer.l" +{ + msyystring_return_state = MS_TOKEN_LITERAL_STRING; + msyystring_begin = msyytext[0]; + msyystring_size = 0; + msyystring_buffer[0] = '\0'; + BEGIN(MSSTRING); + } + YY_BREAK +case 343: +YY_RULE_SETUP +#line 725 "src/maplexer.l" +{ + MS_LEXER_STRING_REALLOC(msyystring_buffer, msyyleng, + msyystring_buffer_size); + strcpy(msyystring_buffer, msyytext); + return(MS_STRING); + } + YY_BREAK +case 344: +/* rule 344 can match eol */ +YY_RULE_SETUP +#line 732 "src/maplexer.l" +{ msyylineno++; } + YY_BREAK +case YY_STATE_EOF(INITIAL): +case YY_STATE_EOF(CONFIG_FILE): +#line 734 "src/maplexer.l" +{ + if( --include_stack_ptr < 0 ) + return(EOF); /* end of main file */ + else { + fclose(YY_CURRENT_BUFFER->yy_input_file); + msyy_delete_buffer( YY_CURRENT_BUFFER ); + msyy_switch_to_buffer(include_stack[include_stack_ptr]); + msyylineno = include_lineno[include_stack_ptr]; + } + } + YY_BREAK +case 345: +/* rule 345 can match eol */ +YY_RULE_SETUP +#line 745 "src/maplexer.l" +{ + return(0); +} + YY_BREAK +case 346: +YY_RULE_SETUP +#line 749 "src/maplexer.l" +{ + MS_LEXER_STRING_REALLOC(msyystring_buffer, msyyleng, + msyystring_buffer_size); + strcpy(msyystring_buffer, msyytext); + return(0); + } + YY_BREAK +case 347: +YY_RULE_SETUP +#line 755 "src/maplexer.l" +{ return(msyytext[0]); } + YY_BREAK +case 348: +YY_RULE_SETUP +#line 756 "src/maplexer.l" +ECHO; + YY_BREAK +#line 4575 "src/maplexer.c" +case YY_STATE_EOF(EXPRESSION_STRING): +case YY_STATE_EOF(INCLUDE): +case YY_STATE_EOF(MSSTRING): +case YY_STATE_EOF(MULTILINE_COMMENT): + yyterminate(); + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = (yy_hold_char); + YY_RESTORE_YY_MORE_OFFSET + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed yyin at a new source and called + * yylex(). If so, then we have to assure + * consistency between YY_CURRENT_BUFFER and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( ); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state ); + + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++(yy_c_buf_p); + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = (yy_last_accepting_cpos); + yy_current_state = (yy_last_accepting_state); + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer( ) ) + { + case EOB_ACT_END_OF_FILE: + { + (yy_did_buffer_switch_on_eof) = 0; + + if ( yywrap( ) ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * yytext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! (yy_did_buffer_switch_on_eof) ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + (yy_c_buf_p) = + (yytext_ptr) + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( ); + + yy_cp = (yy_c_buf_p); + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + (yy_c_buf_p) = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)]; + + yy_current_state = yy_get_previous_state( ); + + yy_cp = (yy_c_buf_p); + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ + } /* end of user's declarations */ +} /* end of yylex */ + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ +static int yy_get_next_buffer (void) +{ + char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + char *source = (yytext_ptr); + int number_to_move, i; + int ret_val; + + if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr) - 1); + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0; + + else + { + int num_to_read = + YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE; + + int yy_c_buf_p_offset = + (int) ((yy_c_buf_p) - b->yy_ch_buf); + + if ( b->yy_is_our_buffer ) + { + int new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; + else + b->yy_buf_size *= 2; + + b->yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + yyrealloc( (void *) b->yy_ch_buf, + (yy_size_t) (b->yy_buf_size + 2) ); + } + else + /* Can't grow it, we don't own it. */ + b->yy_ch_buf = NULL; + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset]; + + num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - + number_to_move - 1; + + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), + (yy_n_chars), num_to_read ); + + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + if ( (yy_n_chars) == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + yyrestart( yyin ); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + if (((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { + /* Extend the array by 50%, plus the number we really need. */ + int new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1); + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc( + (void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf, (yy_size_t) new_size ); + if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); + /* "- 2" to take care of EOB's */ + YY_CURRENT_BUFFER_LVALUE->yy_buf_size = (int) (new_size - 2); + } + + (yy_n_chars) += number_to_move; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR; + + (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; + + return ret_val; +} + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + + static yy_state_type yy_get_previous_state (void) +{ + yy_state_type yy_current_state; + char *yy_cp; + + yy_current_state = (yy_start); + + for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp ) + { + YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 86); + if ( yy_accept[yy_current_state] ) + { + (yy_last_accepting_state) = yy_current_state; + (yy_last_accepting_cpos) = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 1760 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + } + + return yy_current_state; +} + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state ) +{ + int yy_is_jam; + char *yy_cp = (yy_c_buf_p); + + YY_CHAR yy_c = 86; + if ( yy_accept[yy_current_state] ) + { + (yy_last_accepting_state) = yy_current_state; + (yy_last_accepting_cpos) = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 1760 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + yy_is_jam = (yy_current_state == 1759); + + return yy_is_jam ? 0 : yy_current_state; +} + +#ifndef YY_NO_UNPUT + + static void yyunput (int c, char * yy_bp ) +{ + char *yy_cp; + + yy_cp = (yy_c_buf_p); + + /* undo effects of setting up yytext */ + *yy_cp = (yy_hold_char); + + if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) + { /* need to shift things up to make room */ + /* +2 for EOB chars. */ + int number_to_move = (yy_n_chars) + 2; + char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[ + YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2]; + char *source = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]; + + while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + *--dest = *--source; + + yy_cp += (int) (dest - source); + yy_bp += (int) (dest - source); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = + (yy_n_chars) = (int) YY_CURRENT_BUFFER_LVALUE->yy_buf_size; + + if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) + YY_FATAL_ERROR( "flex scanner push-back overflow" ); + } + + *--yy_cp = (char) c; + + (yytext_ptr) = yy_bp; + (yy_hold_char) = *yy_cp; + (yy_c_buf_p) = yy_cp; +} + +#endif + +#ifndef YY_NO_INPUT +#ifdef __cplusplus + static int yyinput (void) +#else + static int input (void) +#endif + +{ + int c; + + *(yy_c_buf_p) = (yy_hold_char); + + if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) + /* This was really a NUL. */ + *(yy_c_buf_p) = '\0'; + + else + { /* need more input */ + int offset = (int) ((yy_c_buf_p) - (yytext_ptr)); + ++(yy_c_buf_p); + + switch ( yy_get_next_buffer( ) ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + yyrestart( yyin ); + + /*FALLTHROUGH*/ + + case EOB_ACT_END_OF_FILE: + { + if ( yywrap( ) ) + return 0; + + if ( ! (yy_did_buffer_switch_on_eof) ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(); +#else + return input(); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + (yy_c_buf_p) = (yytext_ptr) + offset; + break; + } + } + } + + c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */ + *(yy_c_buf_p) = '\0'; /* preserve yytext */ + (yy_hold_char) = *++(yy_c_buf_p); + + return c; +} +#endif /* ifndef YY_NO_INPUT */ + +/** Immediately switch to a different input stream. + * @param input_file A readable stream. + * + * @note This function does not reset the start condition to @c INITIAL . + */ + void yyrestart (FILE * input_file ) +{ + + if ( ! YY_CURRENT_BUFFER ){ + yyensure_buffer_stack (); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer( yyin, YY_BUF_SIZE ); + } + + yy_init_buffer( YY_CURRENT_BUFFER, input_file ); + yy_load_buffer_state( ); +} + +/** Switch to a different input buffer. + * @param new_buffer The new input buffer. + * + */ + void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ) +{ + + /* TODO. We should be able to replace this entire function body + * with + * yypop_buffer_state(); + * yypush_buffer_state(new_buffer); + */ + yyensure_buffer_stack (); + if ( YY_CURRENT_BUFFER == new_buffer ) + return; + + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *(yy_c_buf_p) = (yy_hold_char); + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + YY_CURRENT_BUFFER_LVALUE = new_buffer; + yy_load_buffer_state( ); + + /* We don't actually know whether we did this switch during + * EOF (yywrap()) processing, but the only time this flag + * is looked at is after yywrap() is called, so it's safe + * to go ahead and always set it. + */ + (yy_did_buffer_switch_on_eof) = 1; +} + +static void yy_load_buffer_state (void) +{ + (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; + yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; + (yy_hold_char) = *(yy_c_buf_p); +} + +/** Allocate and initialize an input buffer state. + * @param file A readable stream. + * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. + * + * @return the allocated buffer state. + */ + YY_BUFFER_STATE yy_create_buffer (FILE * file, int size ) +{ + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) yyalloc( (yy_size_t) (b->yy_buf_size + 2) ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_is_our_buffer = 1; + + yy_init_buffer( b, file ); + + return b; +} + +/** Destroy the buffer. + * @param b a buffer created with yy_create_buffer() + * + */ + void yy_delete_buffer (YY_BUFFER_STATE b ) +{ + + if ( ! b ) + return; + + if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ + YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + yyfree( (void *) b->yy_ch_buf ); + + yyfree( (void *) b ); +} + +/* Initializes or reinitializes a buffer. + * This function is sometimes called more than once on the same buffer, + * such as during a yyrestart() or at EOF. + */ + static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file ) + +{ + int oerrno = errno; + + yy_flush_buffer( b ); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + + /* If b is the current buffer, then yy_init_buffer was _probably_ + * called from yyrestart() or through yy_get_next_buffer. + * In that case, we don't want to reset the lineno or column. + */ + if (b != YY_CURRENT_BUFFER){ + b->yy_bs_lineno = 1; + b->yy_bs_column = 0; + } + + b->yy_is_interactive = 0; + + errno = oerrno; +} + +/** Discard all buffered characters. On the next scan, YY_INPUT will be called. + * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. + * + */ + void yy_flush_buffer (YY_BUFFER_STATE b ) +{ + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == YY_CURRENT_BUFFER ) + yy_load_buffer_state( ); +} + +/** Pushes the new state onto the stack. The new state becomes + * the current state. This function will allocate the stack + * if necessary. + * @param new_buffer The new state. + * + */ +void yypush_buffer_state (YY_BUFFER_STATE new_buffer ) +{ + if (new_buffer == NULL) + return; + + yyensure_buffer_stack(); + + /* This block is copied from yy_switch_to_buffer. */ + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *(yy_c_buf_p) = (yy_hold_char); + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + /* Only push if top exists. Otherwise, replace top. */ + if (YY_CURRENT_BUFFER) + (yy_buffer_stack_top)++; + YY_CURRENT_BUFFER_LVALUE = new_buffer; + + /* copied from yy_switch_to_buffer. */ + yy_load_buffer_state( ); + (yy_did_buffer_switch_on_eof) = 1; +} + +/** Removes and deletes the top of the stack, if present. + * The next element becomes the new top. + * + */ +void yypop_buffer_state (void) +{ + if (!YY_CURRENT_BUFFER) + return; + + yy_delete_buffer(YY_CURRENT_BUFFER ); + YY_CURRENT_BUFFER_LVALUE = NULL; + if ((yy_buffer_stack_top) > 0) + --(yy_buffer_stack_top); + + if (YY_CURRENT_BUFFER) { + yy_load_buffer_state( ); + (yy_did_buffer_switch_on_eof) = 1; + } +} + +/* Allocates the stack if it does not exist. + * Guarantees space for at least one push. + */ +static void yyensure_buffer_stack (void) +{ + yy_size_t num_to_alloc; + + if (!(yy_buffer_stack)) { + + /* First allocation is just for 2 elements, since we don't know if this + * scanner will even need a stack. We use 2 instead of 1 to avoid an + * immediate realloc on the next call. + */ + num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */ + (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc + (num_to_alloc * sizeof(struct yy_buffer_state*) + ); + if ( ! (yy_buffer_stack) ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*)); + + (yy_buffer_stack_max) = num_to_alloc; + (yy_buffer_stack_top) = 0; + return; + } + + if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){ + + /* Increase the buffer to prepare for a possible push. */ + yy_size_t grow_size = 8 /* arbitrary grow size */; + + num_to_alloc = (yy_buffer_stack_max) + grow_size; + (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc + ((yy_buffer_stack), + num_to_alloc * sizeof(struct yy_buffer_state*) + ); + if ( ! (yy_buffer_stack) ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + /* zero only the new slots.*/ + memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*)); + (yy_buffer_stack_max) = num_to_alloc; + } +} + +/** Setup the input buffer state to scan directly from a user-specified character buffer. + * @param base the character buffer + * @param size the size in bytes of the character buffer + * + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size ) +{ + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return NULL; + + b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); + + b->yy_buf_size = (int) (size - 2); /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = NULL; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + yy_switch_to_buffer( b ); + + return b; +} + +/** Setup the input buffer state to scan a string. The next call to yylex() will + * scan from a @e copy of @a str. + * @param yystr a NUL-terminated string to scan + * + * @return the newly allocated buffer state object. + * @note If you want to scan bytes that may contain NUL values, then use + * yy_scan_bytes() instead. + */ +YY_BUFFER_STATE yy_scan_string (const char * yystr ) +{ + + return yy_scan_bytes( yystr, (int) strlen(yystr) ); +} + +/** Setup the input buffer state to scan the given bytes. The next call to yylex() will + * scan from a @e copy of @a bytes. + * @param yybytes the byte buffer to scan + * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. + * + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_bytes (const char * yybytes, int _yybytes_len ) +{ + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = (yy_size_t) (_yybytes_len + 2); + buf = (char *) yyalloc( n ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); + + for ( i = 0; i < _yybytes_len; ++i ) + buf[i] = yybytes[i]; + + buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; + + b = yy_scan_buffer( buf, n ); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; +} + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +static void yynoreturn yy_fatal_error (const char* msg ) +{ + fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); +} + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + yytext[yyleng] = (yy_hold_char); \ + (yy_c_buf_p) = yytext + yyless_macro_arg; \ + (yy_hold_char) = *(yy_c_buf_p); \ + *(yy_c_buf_p) = '\0'; \ + yyleng = yyless_macro_arg; \ + } \ + while ( 0 ) + +/* Accessor methods (get/set functions) to struct members. */ + +/** Get the current line number. + * + */ +int yyget_lineno (void) +{ + + return yylineno; +} + +/** Get the input stream. + * + */ +FILE *yyget_in (void) +{ + return yyin; +} + +/** Get the output stream. + * + */ +FILE *yyget_out (void) +{ + return yyout; +} + +/** Get the length of the current token. + * + */ +int yyget_leng (void) +{ + return yyleng; +} + +/** Get the current token. + * + */ + +char *yyget_text (void) +{ + return yytext; +} + +/** Set the current line number. + * @param _line_number line number + * + */ +void yyset_lineno (int _line_number ) +{ + + yylineno = _line_number; +} + +/** Set the input stream. This does not discard the current + * input buffer. + * @param _in_str A readable stream. + * + * @see yy_switch_to_buffer + */ +void yyset_in (FILE * _in_str ) +{ + yyin = _in_str ; +} + +void yyset_out (FILE * _out_str ) +{ + yyout = _out_str ; +} + +int yyget_debug (void) +{ + return yy_flex_debug; +} + +void yyset_debug (int _bdebug ) +{ + yy_flex_debug = _bdebug ; +} + +static int yy_init_globals (void) +{ + /* Initialization is the same as for the non-reentrant scanner. + * This function is called from yylex_destroy(), so don't allocate here. + */ + + (yy_buffer_stack) = NULL; + (yy_buffer_stack_top) = 0; + (yy_buffer_stack_max) = 0; + (yy_c_buf_p) = NULL; + (yy_init) = 0; + (yy_start) = 0; + +/* Defined in main.c */ +#ifdef YY_STDINIT + yyin = stdin; + yyout = stdout; +#else + yyin = NULL; + yyout = NULL; +#endif + + /* For future reference: Set errno on error, since we are called by + * yylex_init() + */ + return 0; +} + +/* yylex_destroy is for both reentrant and non-reentrant scanners. */ +int yylex_destroy (void) +{ + + /* Pop the buffer stack, destroying each element. */ + while(YY_CURRENT_BUFFER){ + yy_delete_buffer( YY_CURRENT_BUFFER ); + YY_CURRENT_BUFFER_LVALUE = NULL; + yypop_buffer_state(); + } + + /* Destroy the stack itself. */ + yyfree((yy_buffer_stack) ); + (yy_buffer_stack) = NULL; + + /* Reset the globals. This is important in a non-reentrant scanner so the next time + * yylex() is called, initialization will occur. */ + yy_init_globals( ); + + return 0; +} + +/* + * Internal utility routines. + */ + +#ifndef yytext_ptr +static void yy_flex_strncpy (char* s1, const char * s2, int n ) +{ + + int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; +} +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (const char * s ) +{ + int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; +} +#endif + +void *yyalloc (yy_size_t size ) +{ + return malloc(size); +} + +void *yyrealloc (void * ptr, yy_size_t size ) +{ + + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return realloc(ptr, size); +} + +void yyfree (void * ptr ) +{ + free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ +} + +#define YYTABLES_NAME "yytables" + +#line 756 "src/maplexer.l" + + +/* +** Any extra C functions +*/ + +int msyywrap() /* override */ +{ + return(1); +} + +int msyyerror(char *s) { + msSetError(MS_PARSEERR, "%s", "msyyparse()", s); + return(0); +} + +/* cleanup any open includes */ +void msyycleanup_includes() { + while( --include_stack_ptr >= 0 ) { + fclose(YY_CURRENT_BUFFER->yy_input_file); + msyy_delete_buffer( YY_CURRENT_BUFFER ); + msyy_switch_to_buffer(include_stack[include_stack_ptr]); + } +} + diff --git a/src/maplexer.l b/src/maplexer.l new file mode 100644 index 0000000000..87e642ffbb --- /dev/null +++ b/src/maplexer.l @@ -0,0 +1,778 @@ +%option never-interactive + +%{ +/* +** READ ME FIRST! +** +** When this file is altered, it is necessary to do "make lexer". Due to +** problems detailed in #2310 the lexer is no longer automatically rebuilt +** when maplexer.l is altered. +*/ + +#define YY_NO_INPUT + +/* C declarations */ +#include +#include +#include +#include + +#include + +#include "mapserver.h" +#include "maperror.h" +#include "mapfile.h" +#include "maptime.h" +#include "mapsymbol.h" +#include "mapparser.h" +#include "mapprimitive.h" + +/* msyylineno is required for flex 2.5.4 and older, but is already defined by + * flex 2.5.31 (bug 975). + * Unfortunately there is no clean way to differentiate the two versions, + * so we use the symbol YY_CURRENT_BUFFER_LVALUE to base our test since it + * was not present in 2.5.4 and is present in 2.5.31. Hopefully that won't + * put us in trouble with other versions. If that happens then we can + * switch to using autoconf to detect the version. + */ +#ifndef YY_CURRENT_BUFFER_LVALUE +int msyylineno = 1; +#endif + +#define YY_NO_INPUT + +/* Below is a redefinition of the default YY_INPUT() macro but replacing the + * YY_FATAL_ERROR() macro with a call to msSetError(). + */ +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#define YY_INPUT(buf,result,max_size) \ + if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ + { \ + int c = '*'; \ + int n; \ + for ( n = 0; n < max_size && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( yyin ) ) \ + msSetError(MS_PARSEERR, "%s", "msyyparse()", "input in flex scanner failed"); \ + result = n; \ + } \ + else \ + { \ + errno=0; \ + while ( (result = (int) fread(buf, 1, (yy_size_t) max_size, yyin)) == 0 && ferror(yyin)) \ + { \ + if( errno != EINTR) \ + { \ + msSetError(MS_PARSEERR, "%s", "msyyparse()", "input in flex scanner failed"); \ + break; \ + } \ + errno=0; \ + clearerr(yyin); \ + } \ + } + +int msyysource=MS_STRING_TOKENS; +double msyynumber; +int msyystate=MS_TOKENIZE_DEFAULT; +const char *msyystring=NULL; +char *msyybasepath=NULL; +int msyystring_buffer_size = 0; +int msyystring_size; +char msyystring_begin; +char *msyystring_buffer = NULL; +int msyystring_icase = MS_FALSE; +int msyystring_return_state; +int msyystring_begin_state; + +int msyyreturncomments = 0; + +#define MS_LEXER_STRING_REALLOC(string, string_size, max_size) \ + do { \ + const int string_size_macro = (int)(string_size); \ + if (string_size_macro >= (int)(max_size)) { \ + max_size = (((int)(max_size)*2) > string_size_macro) ? ((int)(max_size))*2 : string_size_macro+1; \ + string = (char *) msSmallRealloc(string, sizeof(char *) * (max_size)); \ + } \ + } while(0) + +#define MS_LEXER_RETURN_TOKEN(token) \ + MS_LEXER_STRING_REALLOC(msyystring_buffer, strlen(msyytext), \ + msyystring_buffer_size); \ + strcpy(msyystring_buffer, msyytext); \ + return(token); + +#define MAX_INCLUDE_DEPTH 5 +YY_BUFFER_STATE include_stack[MAX_INCLUDE_DEPTH]; +int include_lineno[MAX_INCLUDE_DEPTH]; +int include_stack_ptr = 0; +char path[MS_MAXPATHLEN]; + +%} + +%s EXPRESSION_STRING +%s INCLUDE +%s MSSTRING +%s MULTILINE_COMMENT +%s CONFIG_FILE + +%% + if (msyystring_buffer == NULL) + { + msyystring_buffer_size = 256; + msyystring_buffer = (char*) msSmallMalloc(sizeof(char) * msyystring_buffer_size); + } + + msyystring_buffer[0] = '\0'; + switch(msyystate) { + case(MS_TOKENIZE_DEFAULT): + (void) yyunput; /* just to avoid warning about it being unrefed */ + break; + case(MS_TOKENIZE_FILE): + BEGIN(INITIAL); + msyystring_begin_state = INITIAL; + msyysource=MS_FILE_TOKENS; + msyystate=MS_TOKENIZE_DEFAULT; + msyystring=NULL; + msyyreturncomments=0; + include_stack_ptr=0; + return(0); + break; + case(MS_TOKENIZE_STRING): + BEGIN(INITIAL); + msyystring_begin_state = INITIAL; + msyy_delete_buffer(YY_CURRENT_BUFFER); + msyy_scan_string(msyystring); + msyysource=MS_STRING_TOKENS; + msyystate=MS_TOKENIZE_DEFAULT; + msyyin=NULL; + msyyreturncomments=0; + include_stack_ptr=0; + return(0); + break; + case(MS_TOKENIZE_EXPRESSION): + BEGIN(EXPRESSION_STRING); + msyystring_begin_state = EXPRESSION_STRING; + msyy_delete_buffer(YY_CURRENT_BUFFER); + msyy_scan_string(msyystring); + msyystate=MS_TOKENIZE_DEFAULT; + msyyreturncomments=0; + break; + case(MS_TOKENIZE_CONFIG): + BEGIN(CONFIG_FILE); + msyystring_begin_state = CONFIG_FILE; + msyysource=MS_FILE_TOKENS; + msyystate=MS_TOKENIZE_DEFAULT; + msyystring=NULL; + msyyreturncomments=0; + return(0); + break; + case(99): + BEGIN(INITIAL); /* may not need this one */ + msyystring_begin_state = INITIAL; + msyy_delete_buffer(YY_CURRENT_BUFFER); + msyystate=MS_TOKENIZE_DEFAULT; + msyystring=NULL; + msyyreturncomments=0; + return(0); + break; + default: + break; + } + +[ \t\r]+ ; + +(\/\/|#).* { if (msyyreturncomments) return(MS_COMMENT); } + +\/\* { BEGIN(MULTILINE_COMMENT); } +\*\/ { BEGIN(INITIAL); } +[^*\n]+ ; +\* ; +\n { msyylineno++; } + +config { MS_LEXER_RETURN_TOKEN(MS_CONFIG_SECTION); } +env { MS_LEXER_RETURN_TOKEN(MS_CONFIG_SECTION_ENV); } +maps { MS_LEXER_RETURN_TOKEN(MS_CONFIG_SECTION_MAPS); } +plugins { MS_LEXER_RETURN_TOKEN(MS_CONFIG_SECTION_PLUGINS) } + +or|\|\| { MS_LEXER_RETURN_TOKEN(MS_TOKEN_LOGICAL_OR); } +and|&& { MS_LEXER_RETURN_TOKEN(MS_TOKEN_LOGICAL_AND); } +not|! { MS_LEXER_RETURN_TOKEN(MS_TOKEN_LOGICAL_NOT); } +eq|=|== { MS_LEXER_RETURN_TOKEN(MS_TOKEN_COMPARISON_EQ); } +ne|!=|<> { MS_LEXER_RETURN_TOKEN(MS_TOKEN_COMPARISON_NE); } +gt|> { MS_LEXER_RETURN_TOKEN(MS_TOKEN_COMPARISON_GT); } +lt|< { MS_LEXER_RETURN_TOKEN(MS_TOKEN_COMPARISON_LT); } +ge|>= { MS_LEXER_RETURN_TOKEN(MS_TOKEN_COMPARISON_GE); } +le|<= { MS_LEXER_RETURN_TOKEN(MS_TOKEN_COMPARISON_LE); } +~ { MS_LEXER_RETURN_TOKEN(MS_TOKEN_COMPARISON_RE); } + +=\* { MS_LEXER_RETURN_TOKEN(MS_TOKEN_COMPARISON_IEQ); } +~\* { MS_LEXER_RETURN_TOKEN(MS_TOKEN_COMPARISON_IRE); } + +in { MS_LEXER_RETURN_TOKEN(MS_TOKEN_COMPARISON_IN); /* was IN */ } + +area { MS_LEXER_RETURN_TOKEN(MS_TOKEN_FUNCTION_AREA); } +length { MS_LEXER_RETURN_TOKEN(MS_TOKEN_FUNCTION_LENGTH); } +tostring { MS_LEXER_RETURN_TOKEN(MS_TOKEN_FUNCTION_TOSTRING); } +commify { MS_LEXER_RETURN_TOKEN(MS_TOKEN_FUNCTION_COMMIFY); } +round { MS_LEXER_RETURN_TOKEN(MS_TOKEN_FUNCTION_ROUND); } +upper { MS_LEXER_RETURN_TOKEN(MS_TOKEN_FUNCTION_UPPER); } +lower { MS_LEXER_RETURN_TOKEN(MS_TOKEN_FUNCTION_LOWER); } +initcap { MS_LEXER_RETURN_TOKEN(MS_TOKEN_FUNCTION_INITCAP); } +firstcap { MS_LEXER_RETURN_TOKEN(MS_TOKEN_FUNCTION_FIRSTCAP); } + +buffer { MS_LEXER_RETURN_TOKEN(MS_TOKEN_FUNCTION_BUFFER); } +difference { MS_LEXER_RETURN_TOKEN(MS_TOKEN_FUNCTION_DIFFERENCE); } +simplify { MS_LEXER_RETURN_TOKEN(MS_TOKEN_FUNCTION_SIMPLIFY); } +simplifypt { MS_LEXER_RETURN_TOKEN(MS_TOKEN_FUNCTION_SIMPLIFYPT); } +generalize { MS_LEXER_RETURN_TOKEN(MS_TOKEN_FUNCTION_GENERALIZE); } +smoothsia { MS_LEXER_RETURN_TOKEN(MS_TOKEN_FUNCTION_SMOOTHSIA); } +centerline { MS_LEXER_RETURN_TOKEN(MS_TOKEN_FUNCTION_CENTERLINE); } +densify { MS_LEXER_RETURN_TOKEN(MS_TOKEN_FUNCTION_DENSIFY); } +outer { MS_LEXER_RETURN_TOKEN(MS_TOKEN_FUNCTION_OUTER); } +inner { MS_LEXER_RETURN_TOKEN(MS_TOKEN_FUNCTION_INNER); } +javascript { MS_LEXER_RETURN_TOKEN(MS_TOKEN_FUNCTION_JAVASCRIPT); } + +intersects { MS_LEXER_RETURN_TOKEN(MS_TOKEN_COMPARISON_INTERSECTS); } +disjoint { MS_LEXER_RETURN_TOKEN(MS_TOKEN_COMPARISON_DISJOINT); } +touches { MS_LEXER_RETURN_TOKEN(MS_TOKEN_COMPARISON_TOUCHES); } +overlaps { MS_LEXER_RETURN_TOKEN(MS_TOKEN_COMPARISON_OVERLAPS); } +crosses { MS_LEXER_RETURN_TOKEN(MS_TOKEN_COMPARISON_CROSSES); } +within { MS_LEXER_RETURN_TOKEN(MS_TOKEN_COMPARISON_WITHIN); } +contains { MS_LEXER_RETURN_TOKEN(MS_TOKEN_COMPARISON_CONTAINS); } +equals { MS_LEXER_RETURN_TOKEN(MS_TOKEN_COMPARISON_EQUALS); } +beyond { MS_LEXER_RETURN_TOKEN(MS_TOKEN_COMPARISON_BEYOND); } +dwithin { MS_LEXER_RETURN_TOKEN(MS_TOKEN_COMPARISON_DWITHIN); } + +fromtext { MS_LEXER_RETURN_TOKEN(MS_TOKEN_FUNCTION_FROMTEXT); } + +true { msyynumber=MS_TRUE; return(MS_TOKEN_LITERAL_BOOLEAN); } +false { msyynumber=MS_FALSE; return(MS_TOKEN_LITERAL_BOOLEAN); } + +colorrange { MS_LEXER_RETURN_TOKEN(COLORRANGE); } +datarange { MS_LEXER_RETURN_TOKEN(DATARANGE); } +rangeitem { MS_LEXER_RETURN_TOKEN(RANGEITEM); } + +align { MS_LEXER_RETURN_TOKEN(ALIGN); } +anchorpoint { MS_LEXER_RETURN_TOKEN(ANCHORPOINT); } +angle { MS_LEXER_RETURN_TOKEN(ANGLE); } +antialias { MS_LEXER_RETURN_TOKEN(ANTIALIAS); } +backgroundcolor { MS_LEXER_RETURN_TOKEN(BACKGROUNDCOLOR); } +bandsitem { MS_LEXER_RETURN_TOKEN(BANDSITEM); } +bindvals { MS_LEXER_RETURN_TOKEN(BINDVALS); } +\xEF\xBB\xBF { MS_LEXER_RETURN_TOKEN(BOM); } +browseformat { MS_LEXER_RETURN_TOKEN(BROWSEFORMAT); } +buffer { MS_LEXER_RETURN_TOKEN(BUFFER); } +character { MS_LEXER_RETURN_TOKEN(CHARACTER); } +class { MS_LEXER_RETURN_TOKEN(CLASS); } +classitem { MS_LEXER_RETURN_TOKEN(CLASSITEM); } +classgroup { MS_LEXER_RETURN_TOKEN(CLASSGROUP); } +cluster { MS_LEXER_RETURN_TOKEN(CLUSTER); } +color { MS_LEXER_RETURN_TOKEN(COLOR); } +compfilter { MS_LEXER_RETURN_TOKEN(COMPFILTER); } +composite { MS_LEXER_RETURN_TOKEN(COMPOSITE); } +compop { MS_LEXER_RETURN_TOKEN(COMPOP); } +config { MS_LEXER_RETURN_TOKEN(CONFIG); } +connection { MS_LEXER_RETURN_TOKEN(CONNECTION); } +connectiontype { MS_LEXER_RETURN_TOKEN(CONNECTIONTYPE); } +data { MS_LEXER_RETURN_TOKEN(DATA); } +debug { MS_LEXER_RETURN_TOKEN(DEBUG); } +driver { MS_LEXER_RETURN_TOKEN(DRIVER); } +empty { MS_LEXER_RETURN_TOKEN(EMPTY); } +encoding { MS_LEXER_RETURN_TOKEN(ENCODING); } +end { MS_LEXER_RETURN_TOKEN(END); } +error { MS_LEXER_RETURN_TOKEN(ERROR); } +expression { MS_LEXER_RETURN_TOKEN(EXPRESSION); } +extent { MS_LEXER_RETURN_TOKEN(EXTENT); } +extension { MS_LEXER_RETURN_TOKEN(EXTENSION); } +fallback { MS_LEXER_RETURN_TOKEN(FALLBACK); } +feature { MS_LEXER_RETURN_TOKEN(FEATURE); } +filled { MS_LEXER_RETURN_TOKEN(FILLED); } +filter { MS_LEXER_RETURN_TOKEN(FILTER); } +filteritem { MS_LEXER_RETURN_TOKEN(FILTERITEM); } +footer { MS_LEXER_RETURN_TOKEN(FOOTER); } +font { MS_LEXER_RETURN_TOKEN(FONT); } +fontset { MS_LEXER_RETURN_TOKEN(FONTSET); } +force { MS_LEXER_RETURN_TOKEN(FORCE); } +formatoption { MS_LEXER_RETURN_TOKEN(FORMATOPTION); } +from { MS_LEXER_RETURN_TOKEN(FROM); } +gap { MS_LEXER_RETURN_TOKEN(GAP); } +geomtransform { MS_LEXER_RETURN_TOKEN(GEOMTRANSFORM); } +grid { MS_LEXER_RETURN_TOKEN(GRID); } +gridstep { MS_LEXER_RETURN_TOKEN(GRIDSTEP); } +graticule { MS_LEXER_RETURN_TOKEN(GRATICULE); } +group { MS_LEXER_RETURN_TOKEN(GROUP); } +header { MS_LEXER_RETURN_TOKEN(HEADER); } +image { MS_LEXER_RETURN_TOKEN(IMAGE); } +imagecolor { MS_LEXER_RETURN_TOKEN(IMAGECOLOR); } +imagetype { MS_LEXER_RETURN_TOKEN(IMAGETYPE); } +imagemode { MS_LEXER_RETURN_TOKEN(IMAGEMODE); } +imagepath { MS_LEXER_RETURN_TOKEN(IMAGEPATH); } +temppath { MS_LEXER_RETURN_TOKEN(TEMPPATH); } +imageurl { MS_LEXER_RETURN_TOKEN(IMAGEURL); } +include { BEGIN(INCLUDE); } +index { MS_LEXER_RETURN_TOKEN(INDEX); } +initialgap { MS_LEXER_RETURN_TOKEN(INITIALGAP); } +intervals { MS_LEXER_RETURN_TOKEN(INTERVALS); } +join { MS_LEXER_RETURN_TOKEN(JOIN); } +keyimage { MS_LEXER_RETURN_TOKEN(KEYIMAGE); } +keysize { MS_LEXER_RETURN_TOKEN(KEYSIZE); } +keyspacing { MS_LEXER_RETURN_TOKEN(KEYSPACING); } +label { MS_LEXER_RETURN_TOKEN(LABEL); } +labelcache { MS_LEXER_RETURN_TOKEN(LABELCACHE); } +labelformat { MS_LEXER_RETURN_TOKEN(LABELFORMAT); } +labelitem { MS_LEXER_RETURN_TOKEN(LABELITEM); } +labelmaxscale { MS_LEXER_RETURN_TOKEN(LABELMAXSCALE); } +labelmaxscaledenom { MS_LEXER_RETURN_TOKEN(LABELMAXSCALEDENOM); } +labelminscale { MS_LEXER_RETURN_TOKEN(LABELMINSCALE); } +labelminscaledenom { MS_LEXER_RETURN_TOKEN(LABELMINSCALEDENOM); } +labelrequires { MS_LEXER_RETURN_TOKEN(LABELREQUIRES); } +latlon { MS_LEXER_RETURN_TOKEN(LATLON); } +layer { MS_LEXER_RETURN_TOKEN(LAYER); } +leader { MS_LEXER_RETURN_TOKEN(LEADER); } +legend { MS_LEXER_RETURN_TOKEN(LEGEND); } +legendformat { MS_LEXER_RETURN_TOKEN(LEGENDFORMAT); } +linecap { MS_LEXER_RETURN_TOKEN(LINECAP); } +linejoin { MS_LEXER_RETURN_TOKEN(LINEJOIN); } +linejoinmaxsize { MS_LEXER_RETURN_TOKEN(LINEJOINMAXSIZE); } +map { MS_LEXER_RETURN_TOKEN(MAP); } +marker { MS_LEXER_RETURN_TOKEN(MARKER); } +markersize { MS_LEXER_RETURN_TOKEN(MARKERSIZE); } +mask { MS_LEXER_RETURN_TOKEN(MASK); } +maxarcs { MS_LEXER_RETURN_TOKEN(MAXARCS); } +maxboxsize { MS_LEXER_RETURN_TOKEN(MAXBOXSIZE); } +maxdistance { MS_LEXER_RETURN_TOKEN(MAXDISTANCE); } +maxfeatures { MS_LEXER_RETURN_TOKEN(MAXFEATURES); } +maxinterval { MS_LEXER_RETURN_TOKEN(MAXINTERVAL); } +maxscale { MS_LEXER_RETURN_TOKEN(MAXSCALE); } +maxscaledenom { MS_LEXER_RETURN_TOKEN(MAXSCALEDENOM); } +maxgeowidth { MS_LEXER_RETURN_TOKEN(MAXGEOWIDTH); } +maxlength { MS_LEXER_RETURN_TOKEN(MAXLENGTH); } +maxsize { MS_LEXER_RETURN_TOKEN(MAXSIZE); } +maxsubdivide { MS_LEXER_RETURN_TOKEN(MAXSUBDIVIDE); } +maxtemplate { MS_LEXER_RETURN_TOKEN(MAXTEMPLATE); } +maxwidth { MS_LEXER_RETURN_TOKEN(MAXWIDTH); } +metadata { MS_LEXER_RETURN_TOKEN(METADATA); } +mimetype { MS_LEXER_RETURN_TOKEN(MIMETYPE); } +minarcs { MS_LEXER_RETURN_TOKEN(MINARCS); } +minboxsize { MS_LEXER_RETURN_TOKEN(MINBOXSIZE); } +mindistance { MS_LEXER_RETURN_TOKEN(MINDISTANCE); } +repeatdistance { MS_LEXER_RETURN_TOKEN(REPEATDISTANCE); } +maxoverlapangle { MS_LEXER_RETURN_TOKEN(MAXOVERLAPANGLE); } +minfeaturesize { MS_LEXER_RETURN_TOKEN(MINFEATURESIZE); } +mininterval { MS_LEXER_RETURN_TOKEN(MININTERVAL); } +minscale { MS_LEXER_RETURN_TOKEN(MINSCALE); } +minscaledenom { MS_LEXER_RETURN_TOKEN(MINSCALEDENOM); } +mingeowidth { MS_LEXER_RETURN_TOKEN(MINGEOWIDTH); } +minsize { MS_LEXER_RETURN_TOKEN(MINSIZE); } +minsubdivide { MS_LEXER_RETURN_TOKEN(MINSUBDIVIDE); } +mintemplate { MS_LEXER_RETURN_TOKEN(MINTEMPLATE); } +minwidth { MS_LEXER_RETURN_TOKEN(MINWIDTH); } +name { MS_LEXER_RETURN_TOKEN(NAME); } +offset { MS_LEXER_RETURN_TOKEN(OFFSET); } +offsite { MS_LEXER_RETURN_TOKEN(OFFSITE); } +opacity { MS_LEXER_RETURN_TOKEN(OPACITY); } +connectionoptions { MS_LEXER_RETURN_TOKEN(CONNECTIONOPTIONS); } +outlinecolor { MS_LEXER_RETURN_TOKEN(OUTLINECOLOR); } +outlinewidth { MS_LEXER_RETURN_TOKEN(OUTLINEWIDTH); } +outputformat { MS_LEXER_RETURN_TOKEN(OUTPUTFORMAT); } +partials { MS_LEXER_RETURN_TOKEN(PARTIALS); } +pattern { MS_LEXER_RETURN_TOKEN(PATTERN); } +points { MS_LEXER_RETURN_TOKEN(POINTS); } +items { MS_LEXER_RETURN_TOKEN(ITEMS); } +position { MS_LEXER_RETURN_TOKEN(POSITION); } +postlabelcache { MS_LEXER_RETURN_TOKEN(POSTLABELCACHE); } +priority { MS_LEXER_RETURN_TOKEN(PRIORITY); } +processing { MS_LEXER_RETURN_TOKEN(PROCESSING); } +projection { MS_LEXER_RETURN_TOKEN(PROJECTION); } +queryformat { MS_LEXER_RETURN_TOKEN(QUERYFORMAT); } +querymap { MS_LEXER_RETURN_TOKEN(QUERYMAP); } +reference { MS_LEXER_RETURN_TOKEN(REFERENCE); } +region { MS_LEXER_RETURN_TOKEN(REGION); } +relativeto { MS_LEXER_RETURN_TOKEN(RELATIVETO); } +requires { MS_LEXER_RETURN_TOKEN(REQUIRES); } +resolution { MS_LEXER_RETURN_TOKEN(RESOLUTION); } +defresolution { MS_LEXER_RETURN_TOKEN(DEFRESOLUTION); } +scale { MS_LEXER_RETURN_TOKEN(SCALE); } +scaledenom { MS_LEXER_RETURN_TOKEN(SCALEDENOM); } +scalebar { MS_LEXER_RETURN_TOKEN(SCALEBAR); } +scaletoken { MS_LEXER_RETURN_TOKEN(SCALETOKEN); } +shadowcolor { MS_LEXER_RETURN_TOKEN(SHADOWCOLOR); } +shadowsize { MS_LEXER_RETURN_TOKEN(SHADOWSIZE); } +shapepath { MS_LEXER_RETURN_TOKEN(SHAPEPATH); } +size { MS_LEXER_RETURN_TOKEN(SIZE); } +sizeunits { MS_LEXER_RETURN_TOKEN(SIZEUNITS); } +status { MS_LEXER_RETURN_TOKEN(STATUS); } +style { MS_LEXER_RETURN_TOKEN(STYLE); } +styleitem { MS_LEXER_RETURN_TOKEN(STYLEITEM); } +symbol { MS_LEXER_RETURN_TOKEN(SYMBOL); } +symbolscale { MS_LEXER_RETURN_TOKEN(SYMBOLSCALE); } +symbolscaledenom { MS_LEXER_RETURN_TOKEN(SYMBOLSCALEDENOM); } +symbolset { MS_LEXER_RETURN_TOKEN(SYMBOLSET); } +table { MS_LEXER_RETURN_TOKEN(TABLE); } +template { MS_LEXER_RETURN_TOKEN(TEMPLATE); } +text { MS_LEXER_RETURN_TOKEN(TEXT); } +tileindex { MS_LEXER_RETURN_TOKEN(TILEINDEX); } +tileitem { MS_LEXER_RETURN_TOKEN(TILEITEM); } +tilesrs { MS_LEXER_RETURN_TOKEN(TILESRS); } +title { MS_LEXER_RETURN_TOKEN(TITLE); } +to { MS_LEXER_RETURN_TOKEN(TO); } +tolerance { MS_LEXER_RETURN_TOKEN(TOLERANCE); } +toleranceunits { MS_LEXER_RETURN_TOKEN(TOLERANCEUNITS); } +identify { MS_LEXER_RETURN_TOKEN(IDENTIFY); } +classauto { MS_LEXER_RETURN_TOKEN(CLASSAUTO); } +transparent { MS_LEXER_RETURN_TOKEN(TRANSPARENT); } +transform { MS_LEXER_RETURN_TOKEN(TRANSFORM); } +type { MS_LEXER_RETURN_TOKEN(TYPE); } +units { MS_LEXER_RETURN_TOKEN(UNITS); } +utfdata { MS_LEXER_RETURN_TOKEN(UTFDATA); } +utfitem { MS_LEXER_RETURN_TOKEN(UTFITEM); } +validation { MS_LEXER_RETURN_TOKEN(VALIDATION); } +values { MS_LEXER_RETURN_TOKEN(VALUES); } +web { MS_LEXER_RETURN_TOKEN(WEB); } +width { MS_LEXER_RETURN_TOKEN(WIDTH); } +wkt { MS_LEXER_RETURN_TOKEN(WKT); } +wrap { MS_LEXER_RETURN_TOKEN(WRAP); } + +annotation { MS_LEXER_RETURN_TOKEN(MS_LAYER_ANNOTATION); } +auto { MS_LEXER_RETURN_TOKEN(MS_AUTO); } +auto2 { MS_LEXER_RETURN_TOKEN(MS_AUTO2); } +bevel { MS_LEXER_RETURN_TOKEN(MS_CJC_BEVEL); } +bitmap { MS_LEXER_RETURN_TOKEN(MS_BITMAP); } +butt { MS_LEXER_RETURN_TOKEN(MS_CJC_BUTT); } +cc { MS_LEXER_RETURN_TOKEN(MS_CC); } +center { MS_LEXER_RETURN_TOKEN(MS_ALIGN_CENTER); } +chart { MS_LEXER_RETURN_TOKEN(MS_LAYER_CHART); } +circle { MS_LEXER_RETURN_TOKEN(MS_LAYER_CIRCLE); } +cl { MS_LEXER_RETURN_TOKEN(MS_CL); } +cr { MS_LEXER_RETURN_TOKEN(MS_CR); } +csv { MS_LEXER_RETURN_TOKEN(MS_DB_CSV); } +postgresql { MS_LEXER_RETURN_TOKEN(MS_DB_POSTGRES); } +mysql { MS_LEXER_RETURN_TOKEN(MS_DB_MYSQL); } +default { MS_LEXER_RETURN_TOKEN(MS_DEFAULT); } +dd { MS_LEXER_RETURN_TOKEN(MS_DD); } +ellipse { MS_LEXER_RETURN_TOKEN(MS_SYMBOL_ELLIPSE); } +embed { MS_LEXER_RETURN_TOKEN(MS_EMBED); } +false { MS_LEXER_RETURN_TOKEN(MS_FALSE); } +feet { MS_LEXER_RETURN_TOKEN(MS_FEET); } +follow { MS_LEXER_RETURN_TOKEN(MS_FOLLOW); } +giant { MS_LEXER_RETURN_TOKEN(MS_GIANT); } +hatch { MS_LEXER_RETURN_TOKEN(MS_SYMBOL_HATCH); } +kerneldensity { MS_LEXER_RETURN_TOKEN(MS_KERNELDENSITY); } +idw { MS_LEXER_RETURN_TOKEN(MS_IDW); } +hilite { MS_LEXER_RETURN_TOKEN(MS_HILITE); } +inches { MS_LEXER_RETURN_TOKEN(MS_INCHES); } +kilometers { MS_LEXER_RETURN_TOKEN(MS_KILOMETERS); } +large { MS_LEXER_RETURN_TOKEN(MS_LARGE); } +lc { MS_LEXER_RETURN_TOKEN(MS_LC); } +left { MS_LEXER_RETURN_TOKEN(MS_ALIGN_LEFT); } +line { MS_LEXER_RETURN_TOKEN(MS_LAYER_LINE); } +ll { MS_LEXER_RETURN_TOKEN(MS_LL); } +lr { MS_LEXER_RETURN_TOKEN(MS_LR); } +medium { MS_LEXER_RETURN_TOKEN(MS_MEDIUM); } +meters { MS_LEXER_RETURN_TOKEN(MS_METERS); } +nauticalmiles { MS_LEXER_RETURN_TOKEN(MS_NAUTICALMILES); } +miles { MS_LEXER_RETURN_TOKEN(MS_MILES); } +miter { MS_LEXER_RETURN_TOKEN(MS_CJC_MITER); } +multiple { MS_LEXER_RETURN_TOKEN(MS_MULTIPLE); } +none { MS_LEXER_RETURN_TOKEN(MS_CJC_NONE); } +normal { MS_LEXER_RETURN_TOKEN(MS_NORMAL); } +off { MS_LEXER_RETURN_TOKEN(MS_OFF); } +ogr { MS_LEXER_RETURN_TOKEN(MS_OGR); } +flatgeobuf { MS_LEXER_RETURN_TOKEN(MS_FLATGEOBUF); } +on { MS_LEXER_RETURN_TOKEN(MS_ON); } +one-to-one { MS_LEXER_RETURN_TOKEN(MS_JOIN_ONE_TO_ONE); } +one-to-many { MS_LEXER_RETURN_TOKEN(MS_JOIN_ONE_TO_MANY); } +oraclespatial { MS_LEXER_RETURN_TOKEN(MS_ORACLESPATIAL); } +percentages { MS_LEXER_RETURN_TOKEN(MS_PERCENTAGES); } +pixmap { MS_LEXER_RETURN_TOKEN(MS_SYMBOL_PIXMAP); } +pixels { MS_LEXER_RETURN_TOKEN(MS_PIXELS); } +point { MS_LEXER_RETURN_TOKEN(MS_LAYER_POINT); } +polygon { MS_LEXER_RETURN_TOKEN(MS_LAYER_POLYGON); } +postgis { MS_LEXER_RETURN_TOKEN(MS_POSTGIS); } +plugin { MS_LEXER_RETURN_TOKEN(MS_PLUGIN); } +query { MS_LEXER_RETURN_TOKEN(MS_LAYER_QUERY); } +raster { MS_LEXER_RETURN_TOKEN(MS_LAYER_RASTER); } +rasterlabel { MS_LEXER_RETURN_TOKEN(MS_RASTER_LABEL); } +right { MS_LEXER_RETURN_TOKEN(MS_ALIGN_RIGHT); } +round { MS_LEXER_RETURN_TOKEN(MS_CJC_ROUND); } +selected { MS_LEXER_RETURN_TOKEN(MS_SELECTED); } +simple { MS_LEXER_RETURN_TOKEN(MS_SYMBOL_SIMPLE); } +single { MS_LEXER_RETURN_TOKEN(MS_SINGLE); } +small { MS_LEXER_RETURN_TOKEN(MS_SMALL); } +square { MS_LEXER_RETURN_TOKEN(MS_CJC_SQUARE); } +svg { MS_LEXER_RETURN_TOKEN(MS_SYMBOL_SVG); } +polaroffset { MS_LEXER_RETURN_TOKEN(POLAROFFSET); } +tiny { MS_LEXER_RETURN_TOKEN(MS_TINY); } +triangle { MS_LEXER_RETURN_TOKEN(MS_CJC_TRIANGLE); } +true { MS_LEXER_RETURN_TOKEN(MS_TRUE); } +truetype { MS_LEXER_RETURN_TOKEN(MS_TRUETYPE); } +uc { MS_LEXER_RETURN_TOKEN(MS_UC); } +ul { MS_LEXER_RETURN_TOKEN(MS_UL); } +ur { MS_LEXER_RETURN_TOKEN(MS_UR); } +union { MS_LEXER_RETURN_TOKEN(MS_UNION); } +uvraster { MS_LEXER_RETURN_TOKEN(MS_UVRASTER); } +contour { MS_LEXER_RETURN_TOKEN(MS_CONTOUR); } +vector { MS_LEXER_RETURN_TOKEN(MS_SYMBOL_VECTOR); } +wfs { MS_LEXER_RETURN_TOKEN(MS_WFS); } +wms { MS_LEXER_RETURN_TOKEN(MS_WMS); } + +\[[^\]]*\] { + msyytext++; + msyytext[msyyleng-1-1] = '\0'; + MS_LEXER_STRING_REALLOC(msyystring_buffer, msyyleng, + msyystring_buffer_size); + strcpy(msyystring_buffer,msyytext); + return(MS_BINDING); + } + +\[shape\] { + /* attribute binding - shape (fixed value) */ + return(MS_TOKEN_BINDING_SHAPE); +} +\[map_cellsize\] { + /* attribute binding - map cellsize */ + return(MS_TOKEN_BINDING_MAP_CELLSIZE); +} +\[data_cellsize\] { + /* attribute binding - data cellsize */ + return(MS_TOKEN_BINDING_DATA_CELLSIZE); +} +\[(?:\]\]|[^\]])*\] { + /* attribute binding - numeric (no quotes) */ + msyytext++; + msyytext[msyyleng-1-1] = '\0'; + MS_LEXER_STRING_REALLOC(msyystring_buffer, msyyleng, + msyystring_buffer_size); + strcpy(msyystring_buffer, msyytext); + msStringUnescape(msyystring_buffer, ']'); + return(MS_TOKEN_BINDING_DOUBLE); +} +\"\[(?:\"\"|[^\"])*\]\"|\'\[(?:\'\'|[^\'])*\]\' { + /* attribute binding - string (single or double quotes) */ + msyytext[msyyleng-2] = '\0'; + MS_LEXER_STRING_REALLOC(msyystring_buffer, msyyleng, + msyystring_buffer_size); + strcpy(msyystring_buffer, msyytext + 2); + msStringUnescape(msyystring_buffer, msyytext[0]); + return(MS_TOKEN_BINDING_STRING); +} +\`\[(?:\`\`|[^\`])*\]\` { + /* attribute binding - time */ + msyytext+=2; + msyytext[msyyleng-2-2] = '\0'; + MS_LEXER_STRING_REALLOC(msyystring_buffer, msyyleng, + msyystring_buffer_size); + strcpy(msyystring_buffer, msyytext); + msStringUnescape(msyystring_buffer, '`'); + return(MS_TOKEN_BINDING_TIME); +} + +-?[0-9]+|-?[0-9]+\.[0-9]*|-?\.[0-9]*|-?[0-9]+[eE][+-]?[0-9]+|-?[0-9]+\.[0-9]*[eE][+-]?[0-9]+|-?\.[0-9]*[eE][+-]?[0-9]+ { + MS_LEXER_STRING_REALLOC(msyystring_buffer, msyyleng, + msyystring_buffer_size); + strcpy(msyystring_buffer,msyytext); + msyynumber = atof(msyytext); + return(MS_NUMBER); +} + +-?[0-9]+|-?[0-9]+\.[0-9]*|-?\.[0-9]*|-?[0-9]+[eE][+-]?[0-9]+|-?[0-9]+\.[0-9]*[eE][+-]?[0-9]+|-?\.[0-9]*[eE][+-]?[0-9]+ { + MS_LEXER_STRING_REALLOC(msyystring_buffer, msyyleng, + msyystring_buffer_size); + strcpy(msyystring_buffer,msyytext); + msyynumber = atof(msyytext); + return(MS_TOKEN_LITERAL_NUMBER); +} + +\`[^\`]*\` { + msyytext++; + msyytext[msyyleng-1-1] = '\0'; + MS_LEXER_STRING_REALLOC(msyystring_buffer, msyyleng, + msyystring_buffer_size); + strcpy(msyystring_buffer, msyytext); + return(MS_TOKEN_LITERAL_TIME); +} + +\/[^*]{1}[^\/]*\/i { + msyytext++; + msyytext[msyyleng-1-2] = '\0'; + MS_LEXER_STRING_REALLOC(msyystring_buffer, msyyleng, + msyystring_buffer_size); + strcpy(msyystring_buffer, msyytext); + return(MS_IREGEX); + } + +\/[^*]{1}[^\/]*\/ { + msyytext++; + msyytext[msyyleng-1-1] = '\0'; + MS_LEXER_STRING_REALLOC(msyystring_buffer, msyyleng, + msyystring_buffer_size); + strcpy(msyystring_buffer, msyytext); + return(MS_REGEX); + } + +\(.*\) { + msyytext++; + msyytext[msyyleng-1-1] = '\0'; + MS_LEXER_STRING_REALLOC(msyystring_buffer, msyyleng, + msyystring_buffer_size); + strcpy(msyystring_buffer, msyytext); + return(MS_EXPRESSION); + } + +\{.*\} { + msyytext++; + msyytext[msyyleng-1-1] = '\0'; + MS_LEXER_STRING_REALLOC(msyystring_buffer, msyyleng, + msyystring_buffer_size); + strcpy(msyystring_buffer, msyytext); + return(MS_LIST); + } + +\'|\" { + msyystring_return_state = MS_STRING; + msyystring_begin = msyytext[0]; + msyystring_size = 0; + msyystring_buffer[0] = '\0'; + BEGIN(MSSTRING); + } + +\'|\"|\"i|\'i { + if (msyystring_begin == msyytext[0]) { + BEGIN(msyystring_begin_state); + if (msyystring_return_state == MS_STRING) { + if (msyystring_icase && msyyleng==2) { + msyystring_icase = MS_FALSE; // reset + return MS_ISTRING; + } else + return MS_STRING; + } + return msyystring_return_state; + + } + else { + int old_size = msyystring_size; + msyystring_size += (msyyleng==2) ? 2 : 1; + MS_LEXER_STRING_REALLOC(msyystring_buffer, msyystring_size, + msyystring_buffer_size); + msyystring_buffer[old_size] = *msyytext; + if (msyyleng==2) { + msyystring_buffer[old_size+1] = msyytext[1]; + } + msyystring_buffer[msyystring_size] = '\0'; + } + } + +\\\'|\\\"|\\\\|\\ { + ++msyystring_size; + MS_LEXER_STRING_REALLOC(msyystring_buffer, msyystring_size, + msyystring_buffer_size); + + if (msyyleng == 2) + msyystring_buffer[msyystring_size-1] = msyytext[1]; + else + msyystring_buffer[msyystring_size-1] = msyytext[0]; + msyystring_buffer[msyystring_size] = '\0'; + } + +[^\\\'\\\"]+ { + int old_size = msyystring_size; + msyystring_size += msyyleng; + MS_LEXER_STRING_REALLOC(msyystring_buffer, msyystring_size, + msyystring_buffer_size); + memcpy(msyystring_buffer + old_size, msyytext, msyyleng + 1); + } + +\"[^\"]*\"|\'[^\']*\' { + msyytext++; + msyytext[msyyleng-1-1] = '\0'; + + if(include_stack_ptr >= MAX_INCLUDE_DEPTH) { + msSetError(MS_IOERR, "Includes nested to deeply.", "msyylex()"); + return(-1); + } + + msyyin = fopen(msBuildPath(path, msyybasepath, msyytext), "r"); + if(!msyyin) { + msSetError(MS_IOERR, "Error opening included file \"%s\".", "msyylex()", msyytext); + msyyin = YY_CURRENT_BUFFER->yy_input_file; + return(-1); + } + + include_stack[include_stack_ptr] = YY_CURRENT_BUFFER; /* save state */ + include_lineno[include_stack_ptr] = msyylineno; + include_stack_ptr++; + + msyy_switch_to_buffer( msyy_create_buffer(msyyin, YY_BUF_SIZE) ); + msyylineno = 1; + + BEGIN(INITIAL); + } + +\'|\" { + msyystring_return_state = MS_TOKEN_LITERAL_STRING; + msyystring_begin = msyytext[0]; + msyystring_size = 0; + msyystring_buffer[0] = '\0'; + BEGIN(MSSTRING); + } + +[a-z/\.][a-z0-9/\._\-\=]* { + MS_LEXER_STRING_REALLOC(msyystring_buffer, msyyleng, + msyystring_buffer_size); + strcpy(msyystring_buffer, msyytext); + return(MS_STRING); + } + +\n { msyylineno++; } + +<> { + if( --include_stack_ptr < 0 ) + return(EOF); /* end of main file */ + else { + fclose(YY_CURRENT_BUFFER->yy_input_file); + msyy_delete_buffer( YY_CURRENT_BUFFER ); + msyy_switch_to_buffer(include_stack[include_stack_ptr]); + msyylineno = include_lineno[include_stack_ptr]; + } + } + +[\r|\n|\0] { + return(0); +} + +. { + MS_LEXER_STRING_REALLOC(msyystring_buffer, msyyleng, + msyystring_buffer_size); + strcpy(msyystring_buffer, msyytext); + return(0); + } +. { return(msyytext[0]); } +%% + +/* +** Any extra C functions +*/ + +int msyywrap() /* override */ +{ + return(1); +} + +int msyyerror(char *s) { + msSetError(MS_PARSEERR, "%s", "msyyparse()", s); + return(0); +} + +/* cleanup any open includes */ +void msyycleanup_includes() { + while( --include_stack_ptr >= 0 ) { + fclose(YY_CURRENT_BUFFER->yy_input_file); + msyy_delete_buffer( YY_CURRENT_BUFFER ); + msyy_switch_to_buffer(include_stack[include_stack_ptr]); + } +} diff --git a/maplibxml2.c b/src/maplibxml2.c similarity index 85% rename from maplibxml2.c rename to src/maplibxml2.c index cd3fcfa18a..8ef7132618 100644 --- a/maplibxml2.c +++ b/src/maplibxml2.c @@ -31,17 +31,16 @@ #ifdef USE_LIBXML2 -#include -#include -#include -#include - - +#include +#include +#include +#include /** * msLibXml2GenerateList() * - * Convenience function to produce a series of XML elements from a delimited list + * Convenience function to produce a series of XML elements from a delimited + * list * * @param xmlNodePtr psParent the encompassing node * @param xmlNsPtr psNs the namespace object @@ -51,16 +50,17 @@ * */ -void msLibXml2GenerateList(xmlNodePtr psParent, xmlNsPtr psNs, const char *elname, const char *values, char delim) -{ +void msLibXml2GenerateList(xmlNodePtr psParent, xmlNsPtr psNs, + const char *elname, const char *values, char delim) { char **tokens = NULL; int n = 0; int i = 0; tokens = msStringSplit(values, delim, &n); - for (i=0; inodesetval)) { + if (xmlXPathNodeSetIsEmpty(result->nodesetval)) { xmlXPathFreeObject(result); return NULL; } @@ -107,8 +108,7 @@ xmlXPathObjectPtr msLibXml2GetXPath(xmlDocPtr doc, xmlXPathContextPtr context, x * */ -char *msLibXml2GetXPathTree(xmlDocPtr doc, xmlXPathObjectPtr xpath) -{ +char *msLibXml2GetXPathTree(xmlDocPtr doc, xmlXPathObjectPtr xpath) { xmlBufferPtr xbuf; char *result = NULL; diff --git a/maplibxml2.h b/src/maplibxml2.h similarity index 85% rename from maplibxml2.h rename to src/maplibxml2.h index 904eb97070..2307bbf863 100644 --- a/maplibxml2.h +++ b/src/maplibxml2.h @@ -32,10 +32,10 @@ #ifdef USE_LIBXML2 -#include -#include -#include -#include +#include +#include +#include +#include #include #include @@ -43,9 +43,11 @@ extern "C" { #endif -xmlXPathObjectPtr msLibXml2GetXPath(xmlDocPtr doc, xmlXPathContextPtr context, xmlChar *xpath); +xmlXPathObjectPtr msLibXml2GetXPath(xmlDocPtr doc, xmlXPathContextPtr context, + xmlChar *xpath); -void msLibXml2GenerateList(xmlNodePtr psParent, xmlNsPtr psNs, const char *elname, const char *values, char delim); +void msLibXml2GenerateList(xmlNodePtr psParent, xmlNsPtr psNs, + const char *elname, const char *values, char delim); char *msLibXml2GetXPathTree(xmlDocPtr doc, xmlXPathObjectPtr xpath); diff --git a/src/mapmetadata.c b/src/mapmetadata.c new file mode 100644 index 0000000000..578fe99469 --- /dev/null +++ b/src/mapmetadata.c @@ -0,0 +1,1001 @@ +/********************************************************************** + * $Id$ + * + * Project: MapServer + * Purpose: Metadata implementation + * Author: Tom Kralidis (tomkralidis@gmail.com) + * + ********************************************************************** + * Copyright (c) 2017, Tom Kralidis + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + ****************************************************************************/ + +#include "mapserver.h" +#include "mapows.h" +#include "mapowscommon.h" +#include "maplibxml2.h" + +#if defined(USE_WMS_SVR) || defined(USE_WFS_SVR) || defined(USE_WCS_SVR) || \ + defined(USE_SOS_SVR) || defined(USE_WMS_LYR) || defined(USE_WFS_LYR) + +#ifdef USE_LIBXML2 + +static int msMetadataParseRequest(cgiRequestObj *request, + metadataParamsObj *metadataparams); + +/************************************************************************/ +/* _msMetadataGetCharacterString */ +/* */ +/* Create a gmd:name/gmd:CharacterString element pattern */ +/************************************************************************/ + +static xmlNodePtr _msMetadataGetCharacterString(xmlNsPtr namespace, + const char *name, + const char *value, + xmlNsPtr *ppsNsGco) { + + if (*ppsNsGco == NULL) + *ppsNsGco = xmlNewNs(NULL, BAD_CAST "http://www.isotc211.org/2005/gmd", + BAD_CAST "gco"); + + xmlNodePtr psNode = xmlNewNode(namespace, BAD_CAST name); + + if (!value) + xmlNewNsProp(psNode, *ppsNsGco, BAD_CAST "nilReason", BAD_CAST "missing"); + else + xmlNewChild(psNode, *ppsNsGco, BAD_CAST "CharacterString", BAD_CAST value); + return psNode; +} + +/************************************************************************/ +/* _msMetadataGetURL */ +/* */ +/* Create a gmd:name/gmd:URL element pattern */ +/************************************************************************/ + +static xmlNodePtr _msMetadataGetURL(xmlNsPtr namespace, const char *name, + const char *value, xmlNsPtr *ppsNsGco) { + + if (*ppsNsGco == NULL) + *ppsNsGco = xmlNewNs(NULL, BAD_CAST "http://www.isotc211.org/2005/gmd", + BAD_CAST "gco"); + + xmlNodePtr psNode = xmlNewNode(namespace, BAD_CAST name); + + if (!value) + xmlNewNsProp(psNode, *ppsNsGco, BAD_CAST "nilReason", BAD_CAST "missing"); + else + xmlNewChild(psNode, namespace, BAD_CAST "URL", BAD_CAST value); + return psNode; +} + +/************************************************************************/ +/* _msMetadataGetOnline */ +/* */ +/* Create a gmd:onLine element pattern */ +/************************************************************************/ + +static char *_stringConcatenateAndEncodeHTML(char *str, const char *appendStr) { + char *pszTmp = msEncodeHTMLEntities(appendStr); + str = msStringConcatenate(str, pszTmp); + msFree(pszTmp); + return str; +} + +static xmlNodePtr _msMetadataGetOnline(xmlNsPtr namespace, layerObj *layer, + const char *service, const char *format, + const char *desc, const char *url_in, + xmlNsPtr *ppsNsGco) { + + int status; + const char *link_protocol = "unknown protocol"; + + xmlNodePtr psNode = xmlNewNode(namespace, BAD_CAST "onLine"); + xmlNodePtr psORNode = + xmlNewChild(psNode, namespace, BAD_CAST "CI_OnlineResource", NULL); + + char *url = msStrdup(url_in); + + if (strcasecmp(service, "M") == 0) { + url = _stringConcatenateAndEncodeHTML( + url, "service=WMS&version=1.3.0&request=GetMap&width=500&height=300&" + "styles=&layers="); + url = _stringConcatenateAndEncodeHTML(url, layer->name); + url = _stringConcatenateAndEncodeHTML(url, "&format="); + url = _stringConcatenateAndEncodeHTML(url, format); + url = _stringConcatenateAndEncodeHTML(url, "&crs="); + { + char *epsg_str = NULL; + msOWSGetEPSGProj(&(layer->projection), &(layer->metadata), "MFCSGO", + MS_TRUE, &epsg_str); + url = _stringConcatenateAndEncodeHTML(url, epsg_str); + msFree(epsg_str); + } + link_protocol = "WWW:DOWNLOAD-1.0-http-get-map"; + + rectObj rect; + status = msLayerGetExtent(layer, &rect); + + if (status == 0) { + char buffer[32]; + url = _stringConcatenateAndEncodeHTML(url, "&bbox="); + sprintf(buffer, "%f", rect.miny); + url = msStringConcatenate(url, buffer); + url = msStringConcatenate(url, ","); + sprintf(buffer, "%f", rect.minx); + url = msStringConcatenate(url, buffer); + url = msStringConcatenate(url, ","); + sprintf(buffer, "%f", rect.maxy); + url = msStringConcatenate(url, buffer); + url = msStringConcatenate(url, ","); + sprintf(buffer, "%f", rect.maxx); + url = msStringConcatenate(url, buffer); + } + } else if (strcasecmp(service, "F") == 0) { + link_protocol = "WWW:DOWNLOAD-1.0-http--download"; + url = _stringConcatenateAndEncodeHTML( + url, "service=WFS&version=1.1.0&request=GetFeature&typename="); + url = _stringConcatenateAndEncodeHTML(url, layer->name); + url = _stringConcatenateAndEncodeHTML(url, "&outputformat="); + url = _stringConcatenateAndEncodeHTML(url, format); + } else if (strcasecmp(service, "C") == 0) { + link_protocol = "WWW:DOWNLOAD-1.0-http--download"; + url = _stringConcatenateAndEncodeHTML( + url, "service=WCS&version=2.0.1&request=GetCoverage&coverageid="); + url = _stringConcatenateAndEncodeHTML(url, layer->name); + url = _stringConcatenateAndEncodeHTML(url, "&format="); + url = _stringConcatenateAndEncodeHTML(url, format); + } + + xmlAddChild(psORNode, _msMetadataGetURL(namespace, "linkage", url, ppsNsGco)); + msFree(url); + + xmlAddChild(psORNode, _msMetadataGetCharacterString(namespace, "protocol", + link_protocol, ppsNsGco)); + xmlAddChild(psORNode, _msMetadataGetCharacterString(namespace, "name", + layer->name, ppsNsGco)); + + xmlAddChild(psORNode, _msMetadataGetCharacterString(namespace, "description", + desc, ppsNsGco)); + + return psNode; +} + +/************************************************************************/ +/* _msMetadataGetInteger */ +/* */ +/* Create a gmd:name/gmd:Integer element pattern */ +/************************************************************************/ + +static xmlNodePtr _msMetadataGetInteger(xmlNsPtr namespace, const char *name, + int value, xmlNsPtr *ppsNsGco) { + char buffer[8]; + sprintf(buffer, "%d", value); + + if (*ppsNsGco == NULL) + *ppsNsGco = xmlNewNs(NULL, BAD_CAST "http://www.isotc211.org/2005/gmd", + BAD_CAST "gco"); + + xmlNodePtr psNode = xmlNewNode(namespace, BAD_CAST name); + + if (!value) + xmlNewNsProp(psNode, *ppsNsGco, BAD_CAST "nilReason", BAD_CAST "missing"); + else + xmlNewChild(psNode, *ppsNsGco, BAD_CAST "Integer", BAD_CAST buffer); + return psNode; +} + +/************************************************************************/ +/* _msMetadataGetDecimal */ +/* */ +/* Create a gmd:name/gmd:Decimal element pattern */ +/************************************************************************/ + +static xmlNodePtr _msMetadataGetDecimal(xmlNsPtr namespace, const char *name, + double value, xmlNsPtr *ppsNsGco) { + char buffer[32]; + snprintf(buffer, sizeof(buffer), "%.6f", value); + + if (*ppsNsGco == NULL) + *ppsNsGco = xmlNewNs(NULL, BAD_CAST "http://www.isotc211.org/2005/gmd", + BAD_CAST "gco"); + + xmlNodePtr psNode = xmlNewNode(namespace, BAD_CAST name); + + if (!value) + xmlNewNsProp(psNode, *ppsNsGco, BAD_CAST "nilReason", BAD_CAST "missing"); + else + xmlNewChild(psNode, *ppsNsGco, BAD_CAST "Decimal", BAD_CAST buffer); + return psNode; +} + +/************************************************************************/ +/* _msMetadataGetCodeList */ +/* */ +/* Create a gmd:name/gmd:* code list element pattern */ +/************************************************************************/ + +xmlNodePtr _msMetadataGetCodeList(xmlNsPtr namespace, + const char *parent_element, const char *name, + const char *value) { + char *codelist = NULL; + codelist = msStrdup( + "http://www.isotc211.org/2005/resources/Codelist/gmxCodelists.xml#"); + codelist = msStringConcatenate(codelist, name); + + xmlNodePtr psNode = xmlNewNode(namespace, BAD_CAST parent_element); + xmlNodePtr psCodeNode = + xmlNewChild(psNode, namespace, BAD_CAST name, BAD_CAST value); + xmlNewProp(psCodeNode, BAD_CAST "codeSpace", BAD_CAST "ISOTC211/19115"); + xmlNewProp(psCodeNode, BAD_CAST "codeList", BAD_CAST codelist); + xmlNewProp(psCodeNode, BAD_CAST "codeListValue", BAD_CAST value); + msFree(codelist); + return psNode; +} + +/************************************************************************/ +/* _msMetadataGetGMLTimePeriod */ +/* */ +/* Create a gml:TimePeriod element pattern */ +/************************************************************************/ + +static xmlNodePtr _msMetadataGetGMLTimePeriod(char **temporal) { + xmlNsPtr psNsGml = + xmlNewNs(NULL, BAD_CAST "http://www.opengis.net/gml", BAD_CAST "gml"); + xmlNodePtr psNode = xmlNewNode(psNsGml, BAD_CAST "TimePeriod"); + xmlNewNsProp(psNode, psNsGml, BAD_CAST "id", BAD_CAST "T001"); + xmlNewNs(psNode, BAD_CAST "http://www.opengis.net/gml", BAD_CAST "gml"); + xmlSetNs(psNode, psNsGml); + xmlNewChild(psNode, psNsGml, BAD_CAST "beginPosition", BAD_CAST temporal[0]); + xmlNewChild(psNode, psNsGml, BAD_CAST "endPosition", BAD_CAST temporal[1]); + + return psNode; +} + +/************************************************************************/ +/* _msMetadataGetExtent */ +/* */ +/* Create a gmd:extent element pattern */ +/************************************************************************/ + +static xmlNodePtr _msMetadataGetExtent(xmlNsPtr namespace, layerObj *layer, + xmlNsPtr *ppsNsGco) { + int n = 0; + int status; + char **temporal = NULL; + + rectObj rect; + + xmlNodePtr psNode = xmlNewNode(namespace, BAD_CAST "extent"); + xmlNodePtr psEXNode = + xmlNewChild(psNode, namespace, BAD_CAST "EX_Extent", NULL); + + /* scan for geospatial extent */ + status = msLayerGetExtent(layer, &rect); + + if (status == 0) { + /* always project to lat long */ + msOWSProjectToWGS84(&layer->projection, &rect); + + xmlNodePtr psGNode = + xmlNewChild(psEXNode, namespace, BAD_CAST "geographicElement", NULL); + xmlNodePtr psGNode2 = xmlNewChild( + psGNode, namespace, BAD_CAST "EX_GeographicBoundingBox", NULL); + xmlAddChild(psGNode2, _msMetadataGetDecimal(namespace, "westBoundLongitude", + rect.minx, ppsNsGco)); + xmlAddChild(psGNode2, _msMetadataGetDecimal(namespace, "eastBoundLongitude", + rect.maxx, ppsNsGco)); + xmlAddChild(psGNode2, _msMetadataGetDecimal(namespace, "southBoundLatitude", + rect.miny, ppsNsGco)); + xmlAddChild(psGNode2, _msMetadataGetDecimal(namespace, "northBoundLatitude", + rect.maxy, ppsNsGco)); + } + + /* scan for temporal extent */ + const char *value = + msOWSLookupMetadata(&(layer->metadata), "MO", "timeextent"); + if (value) { /* WMS */ + temporal = msStringSplit(value, '/', &n); + } else { /* WCS */ + value = msOWSLookupMetadata(&(layer->metadata), "CO", "timeposition"); + if (value) { + /* split extent */ + temporal = msStringSplit(value, ',', &n); + } + } + if (!value) { /* SOS */ + value = + msOWSLookupMetadata(&(layer->metadata), "SO", "offering_timeextent"); + if (value) + temporal = msStringSplit(value, '/', &n); + } + if (value) { + if (temporal && n > 0) { + xmlNodePtr psTNode = + xmlNewChild(psEXNode, namespace, BAD_CAST "temporalElement", NULL); + xmlNodePtr psTNode2 = + xmlNewChild(psTNode, namespace, BAD_CAST "EX_TemporalExtent", NULL); + xmlNodePtr psENode = + xmlNewChild(psTNode2, namespace, BAD_CAST "extent", NULL); + xmlAddChild(psENode, _msMetadataGetGMLTimePeriod(temporal)); + } + } + msFreeCharArray(temporal, n); + + return psNode; +} + +/************************************************************************/ +/* _msMetadataGetReferenceSystemInfo */ +/* */ +/* Create a gmd:referenceSystemInfo element pattern */ +/************************************************************************/ + +static xmlNodePtr _msMetadataGetReferenceSystemInfo(xmlNsPtr namespace, + layerObj *layer, + xmlNsPtr *ppsNsGco) { + xmlNodePtr psNode = xmlNewNode(namespace, BAD_CAST "referenceSystemInfo"); + xmlNodePtr psRSNode = + xmlNewChild(psNode, namespace, BAD_CAST "MD_ReferenceSystem", NULL); + xmlNodePtr psRSINode = xmlNewChild( + psRSNode, namespace, BAD_CAST "referenceSystemIdentifier", NULL); + xmlNodePtr psRSINode2 = + xmlNewChild(psRSINode, namespace, BAD_CAST "RS_Identifier", NULL); + + char *epsg_str = NULL; + msOWSGetEPSGProj(&(layer->projection), &(layer->metadata), "MFCSGO", MS_TRUE, + &epsg_str); + xmlAddChild(psRSINode2, _msMetadataGetCharacterString(namespace, "code", + epsg_str, ppsNsGco)); + xmlAddChild(psRSINode2, _msMetadataGetCharacterString( + namespace, "codeSpace", + "http://www.epsg-registry.org", ppsNsGco)); + xmlAddChild(psRSINode2, _msMetadataGetCharacterString(namespace, "version", + "6.14", ppsNsGco)); + msFree(epsg_str); + + return psNode; +} + +/************************************************************************/ +/* _msMetadataGetContact */ +/* */ +/* Create a gmd:contact element pattern */ +/************************************************************************/ + +xmlNodePtr _msMetadataGetContact(xmlNsPtr namespace, char *contact_element, + mapObj *map, xmlNsPtr *ppsNsGco) { + xmlNodePtr psNode = xmlNewNode(namespace, BAD_CAST contact_element); + xmlNodePtr psCNode = + xmlNewChild(psNode, namespace, BAD_CAST "CI_ResponsibleParty", NULL); + xmlNewProp(psCNode, BAD_CAST "id", BAD_CAST contact_element); + + const char *value = + msOWSLookupMetadata(&(map->web.metadata), "MCFO", "contactperson"); + if (value) + xmlAddChild(psCNode, _msMetadataGetCharacterString( + namespace, "individualName", value, ppsNsGco)); + + value = + msOWSLookupMetadata(&(map->web.metadata), "MCFO", "contactorganization"); + if (value) + xmlAddChild(psCNode, _msMetadataGetCharacterString( + namespace, "organisationName", value, ppsNsGco)); + + value = msOWSLookupMetadata(&(map->web.metadata), "MCFO", "contactposition"); + if (value) + xmlAddChild(psCNode, _msMetadataGetCharacterString( + namespace, "positionName", value, ppsNsGco)); + + xmlNodePtr psCINode = + xmlNewChild(psCNode, namespace, BAD_CAST "contactInfo", NULL); + xmlNodePtr psCINode2 = + xmlNewChild(psCINode, namespace, BAD_CAST "CI_Contact", NULL); + xmlNodePtr psPhoneNode = + xmlNewChild(psCINode2, namespace, BAD_CAST "phone", NULL); + xmlNodePtr psCIPhoneNode = + xmlNewChild(psPhoneNode, namespace, BAD_CAST "CI_Telephone", NULL); + + value = msOWSLookupMetadata(&(map->web.metadata), "MCFO", + "contactvoicetelephone"); + if (value) + xmlAddChild(psCIPhoneNode, _msMetadataGetCharacterString(namespace, "voice", + value, ppsNsGco)); + + value = msOWSLookupMetadata(&(map->web.metadata), "MCFO", + "contactfacsimiletelephone"); + if (value) + xmlAddChild(psCIPhoneNode, _msMetadataGetCharacterString( + namespace, "facsimile", value, ppsNsGco)); + + xmlNodePtr psAddressNode = + xmlNewChild(psCINode2, namespace, BAD_CAST "address", NULL); + xmlNodePtr psCIAddressNode = + xmlNewChild(psAddressNode, namespace, BAD_CAST "CI_Address", NULL); + + value = msOWSLookupMetadata(&(map->web.metadata), "MCFO", "address"); + if (value) + xmlAddChild(psCIAddressNode, + _msMetadataGetCharacterString(namespace, "deliveryPoint", value, + ppsNsGco)); + + value = msOWSLookupMetadata(&(map->web.metadata), "MCFO", "city"); + if (value) + xmlAddChild(psCIAddressNode, _msMetadataGetCharacterString( + namespace, "city", value, ppsNsGco)); + + value = msOWSLookupMetadata(&(map->web.metadata), "MCFO", "stateorprovince"); + if (value) + xmlAddChild(psCIAddressNode, + _msMetadataGetCharacterString(namespace, "administrativeArea", + value, ppsNsGco)); + + value = msOWSLookupMetadata(&(map->web.metadata), "MCFO", "postcode"); + if (value) + xmlAddChild(psCIAddressNode, _msMetadataGetCharacterString( + namespace, "postalCode", value, ppsNsGco)); + + value = msOWSLookupMetadata(&(map->web.metadata), "MCFO", "country"); + if (value) + xmlAddChild(psCIAddressNode, _msMetadataGetCharacterString( + namespace, "country", value, ppsNsGco)); + + value = msOWSLookupMetadata(&(map->web.metadata), "MCFO", + "contactelectronicmailaddress"); + if (value) + xmlAddChild(psCIAddressNode, + _msMetadataGetCharacterString( + namespace, "electronicMailAddress", value, ppsNsGco)); + + value = msOWSLookupMetadata(&(map->web.metadata), "MCFO", "onlineresource"); + if (value) { + xmlNodePtr psORNode = + xmlNewChild(psCINode2, namespace, BAD_CAST "onlineResource", NULL); + xmlNodePtr psORNode2 = + xmlNewChild(psORNode, namespace, BAD_CAST "CI_OnlineResource", NULL); + xmlAddChild(psORNode2, + _msMetadataGetURL(namespace, "linkage", value, ppsNsGco)); + } + + xmlAddChild(psCNode, _msMetadataGetCodeList(namespace, "role", "CI_RoleCode", + "pointOfContact")); + + return psNode; +} + +/************************************************************************/ +/* _msMetadataGetIdentificationInfo */ +/* */ +/* Create a gmd:identificationInfo element pattern */ +/************************************************************************/ + +static xmlNodePtr _msMetadataGetIdentificationInfo(xmlNsPtr namespace, + mapObj *map, layerObj *layer, + xmlNsPtr *ppsNsGco) { + xmlNodePtr psNode = xmlNewNode(namespace, BAD_CAST "identificationInfo"); + + xmlNodePtr psDINode = + xmlNewChild(psNode, namespace, BAD_CAST "MD_DataIdentification", NULL); + xmlNewProp(psDINode, BAD_CAST "id", BAD_CAST layer->name); + xmlNodePtr psCNode = + xmlNewChild(psDINode, namespace, BAD_CAST "citation", NULL); + xmlNodePtr psCINode = + xmlNewChild(psCNode, namespace, BAD_CAST "CI_Citation", NULL); + + const char *value = msOWSLookupMetadata(&(layer->metadata), "MCFGO", "title"); + if (!value) + value = msOWSLookupMetadata(&(layer->metadata), "S", "offering_name"); + xmlAddChild(psCINode, _msMetadataGetCharacterString(namespace, "title", value, + ppsNsGco)); + + xmlNodePtr psDNode = xmlNewChild(psCINode, namespace, BAD_CAST "date", NULL); + xmlNewNsProp(psDNode, *ppsNsGco, BAD_CAST "nilReason", BAD_CAST "missing"); + + value = msOWSLookupMetadata(&(layer->metadata), "MCFGO", "attribution_title"); + if (value) { + xmlAddChild(psCINode, + _msMetadataGetCharacterString(namespace, "otherCitationDetails", + value, ppsNsGco)); + } + + value = msOWSLookupMetadata(&(layer->metadata), "MCFGO", "abstract"); + if (!value) + value = + msOWSLookupMetadata(&(layer->metadata), "S", "offering_description"); + xmlAddChild(psDINode, _msMetadataGetCharacterString(namespace, "abstract", + value, ppsNsGco)); + + value = msOWSLookupMetadata(&(layer->metadata), "MCFSGO", "keywordlist"); + + if (value) { + xmlNodePtr psKWNode = + xmlNewChild(psDINode, namespace, BAD_CAST "descriptiveKeywords", NULL); + xmlNodePtr psMDKNode = + xmlNewChild(psKWNode, namespace, BAD_CAST "MD_Keywords", NULL); + + int n = 0; + char **tokens = msStringSplit(value, ',', &n); + if (tokens && n > 0) { + for (int i = 0; i < n; i++) { + xmlAddChild(psMDKNode, _msMetadataGetCharacterString( + namespace, "keyword", tokens[i], ppsNsGco)); + } + } + msFreeCharArray(tokens, n); + } + + xmlAddChild(psDINode, + _msMetadataGetCharacterString( + namespace, "language", + (char *)msOWSGetLanguage(map, "exception"), ppsNsGco)); + xmlAddChild(psDINode, _msMetadataGetExtent(namespace, layer, ppsNsGco)); + + return psNode; +} + +/************************************************************************/ +/* _msMetadataGetSpatialRepresentationInfo */ +/* */ +/* Create a gmd:spatialRepresentationInfo element pattern */ +/************************************************************************/ + +static xmlNodePtr _msMetadataGetSpatialRepresentationInfo(xmlNsPtr namespace, + layerObj *layer, + xmlNsPtr *ppsNsGco) { + xmlNodePtr psNode = + xmlNewNode(namespace, BAD_CAST "spatialRepresentationInfo"); + + if (layer->type == MS_LAYER_RASTER) { + xmlNodePtr psSRNode = xmlNewChild( + psNode, namespace, BAD_CAST "MD_GridSpatialRepresentation", NULL); + xmlAddChild(psSRNode, _msMetadataGetInteger(namespace, "numberOfDimensions", + 2, ppsNsGco)); + xmlAddChild(psSRNode, + _msMetadataGetCodeList(namespace, "cellGeometry", + "MD_CellGeometryCode", "area")); + } else { + xmlNodePtr psSRNode = xmlNewChild( + psNode, namespace, BAD_CAST "MD_VectorSpatialRepresentation", NULL); + xmlAddChild(psSRNode, + _msMetadataGetCodeList(namespace, "topologyLevel", + "MD_TopologyLevelCode", "geometryOnly")); + xmlNodePtr psGONode = + xmlNewChild(psSRNode, namespace, BAD_CAST "geometricObjects", NULL); + xmlNodePtr psGONode2 = + xmlNewChild(psGONode, namespace, BAD_CAST "MD_GeometricObjects", NULL); + const char *value; + if (layer->type == MS_LAYER_POINT) + value = "point"; + else if (layer->type == MS_LAYER_LINE) + value = "curve"; + else if (layer->type == MS_LAYER_POLYGON) + value = "surface"; + else + value = "complex"; + xmlAddChild(psGONode2, + _msMetadataGetCodeList(namespace, "geometricObjectType", + "MD_GeometricObjectTypeCode", value)); + // TODO: find way to get feature count in a fast way + /* xmlAddChild(psGONode2, _msMetadataGetInteger(namespace, + * "geometricObjectCount", msLayerGetNumFeatures(layer))); */ + } + + return psNode; +} + +/************************************************************************/ +/* _msMetadataGetDistributionInfo */ +/* */ +/* Create a gmd:identificationInfo element pattern */ +/************************************************************************/ + +static xmlNodePtr _msMetadataGetDistributionInfo(xmlNsPtr namespace, + mapObj *map, layerObj *layer, + cgiRequestObj *cgi_request, + xmlNsPtr *ppsNsGco) { + char *url = NULL; + + xmlNodePtr psNode = xmlNewNode(namespace, BAD_CAST "distributionInfo"); + xmlNodePtr psMDNode = + xmlNewChild(psNode, namespace, BAD_CAST "MD_Distribution", NULL); + + { + char *pszTmp = + msOWSGetOnlineResource(map, "MFCSGO", "onlineresource", cgi_request); + url = msEncodeHTMLEntities(pszTmp); + msFree(pszTmp); + } + + /* gmd:distributor */ + xmlNodePtr psDNode = + xmlNewChild(psMDNode, namespace, BAD_CAST "distributor", NULL); + xmlNodePtr psDNode2 = + xmlNewChild(psDNode, namespace, BAD_CAST "MD_Distributor", NULL); + xmlAddChild(psDNode2, _msMetadataGetContact(namespace, "distributorContact", + map, ppsNsGco)); + + /* gmd:transferOptions */ + xmlNodePtr psTONode = + xmlNewChild(psMDNode, namespace, BAD_CAST "transferOptions", NULL); + xmlNodePtr psDTONode = xmlNewChild( + psTONode, namespace, BAD_CAST "MD_DigitalTransferOptions", NULL); + xmlAddChild(psDTONode, _msMetadataGetCharacterString( + namespace, "unitsOfDistribution", "KB", ppsNsGco)); + + /* links */ + + /* WMS */ + xmlAddChild(psDTONode, + _msMetadataGetOnline(namespace, layer, "M", "image/png", + "PNG Format", url, ppsNsGco)); + xmlAddChild(psDTONode, + _msMetadataGetOnline(namespace, layer, "M", "image/jpeg", + "JPEG Format", url, ppsNsGco)); + + /* WCS */ + if (layer->type == MS_LAYER_RASTER) { + xmlAddChild(psDTONode, + _msMetadataGetOnline(namespace, layer, "C", "image/tiff", + "GeoTIFF Format", url, ppsNsGco)); + } + /* WFS */ + else { + xmlAddChild(psDTONode, _msMetadataGetOnline(namespace, layer, "F", "GML2", + "GML2 Format", url, ppsNsGco)); + xmlAddChild(psDTONode, _msMetadataGetOnline(namespace, layer, "F", "GML3", + "GML3 Format", url, ppsNsGco)); + } + + msFree(url); + + return psNode; +} + +/************************************************************************/ +/* msMetadataGetExceptionReport */ +/* */ +/* Generate an OWS Common Exception Report */ +/************************************************************************/ + +static xmlNodePtr msMetadataGetExceptionReport(mapObj *map, char *code, + char *locator, char *message, + xmlNsPtr *ppsNsOws) { + char *schemas_location = NULL; + + xmlNodePtr psRootNode = NULL; + + schemas_location = msEncodeHTMLEntities(msOWSGetSchemasLocation(map)); + *ppsNsOws = + xmlNewNs(NULL, BAD_CAST "http://www.opengis.net/ows/1.1", BAD_CAST "ows"); + + psRootNode = msOWSCommonExceptionReport( + *ppsNsOws, OWS_1_1_0, schemas_location, "1.1.0", + msOWSGetLanguage(map, "exception"), code, locator, message); + msFree(schemas_location); + + xmlNewNs(psRootNode, BAD_CAST "http://www.opengis.net/ows/1.1", + BAD_CAST "ows"); + + return psRootNode; +} + +/************************************************************************/ +/* msMetadataGetLayerMetadata */ +/* */ +/* Generate an ISO 19139-1:2019 representation of layer metadata */ +/************************************************************************/ + +static xmlNodePtr +msMetadataGetLayerMetadata(mapObj *map, metadataParamsObj *paramsObj, + cgiRequestObj *cgi_request, xmlNsPtr *ppsNsOws, + xmlNsPtr *ppsNsXsi, xmlNsPtr *ppsNsGmd, + xmlNsPtr *ppsNsGco) { + int i; + int layer_found = MS_FALSE; + + xmlNodePtr psRootNode = NULL; + + layerObj *layer = NULL; + + /* Check that layer requested exists in mapfile */ + for (i = 0; i < map->numlayers; i++) { + if (strcasecmp(GET_LAYER(map, i)->name, paramsObj->pszLayer) == 0) { + layer_found = MS_TRUE; + layer = GET_LAYER(map, i); + // when checking a layer with clustering msLayerGetExtent does not have + // access to the source layer, so remove clustering first + if (layer->cluster.region) { + layer->cluster.region = NULL; + } + break; + } + } + + if (layer_found == MS_FALSE) { + psRootNode = msMetadataGetExceptionReport( + map, "InvalidParameterValue", "layer", "Layer not found", ppsNsOws); + } + + /* Check that outputschema is valid */ + else if (paramsObj->pszOutputSchema && + strcasecmp(paramsObj->pszOutputSchema, + "http://www.isotc211.org/2005/gmd") != 0) { + psRootNode = msMetadataGetExceptionReport( + map, "InvalidParameterValue", "outputschema", + "OUTPUTSCHEMA must be \"http://www.isotc211.org/2005/gmd\"", ppsNsOws); + } + + else { + *ppsNsXsi = + xmlNewNs(NULL, BAD_CAST "http://www.w3.org/2001/XMLSchema-instance", + BAD_CAST "xsi"); + *ppsNsGmd = xmlNewNs(NULL, BAD_CAST "http://www.isotc211.org/2005/gmd", + BAD_CAST "gmd"); + /* root element */ + psRootNode = xmlNewNode(NULL, BAD_CAST "MD_Metadata"); + xmlNewNs(psRootNode, BAD_CAST "http://www.isotc211.org/2005/gmd", + BAD_CAST "gmd"); + xmlNewNs(psRootNode, BAD_CAST "http://www.isotc211.org/2005/gco", + BAD_CAST "gco"); + xmlNewNs(psRootNode, BAD_CAST "http://www.w3.org/2001/XMLSchema-instance", + BAD_CAST "xsi"); + xmlSetNs(psRootNode, *ppsNsGmd); + + xmlNewNsProp(psRootNode, *ppsNsXsi, BAD_CAST "schemaLocation", + BAD_CAST "http://www.isotc211.org/2005/gmd " + "http://www.isotc211.org/2005/gmd/gmd.xsd"); + + /* gmd:identifier */ + xmlAddChild(psRootNode, + _msMetadataGetCharacterString(*ppsNsGmd, "fileIdentifier", + layer->name, ppsNsGco)); + + /* gmd:language */ + xmlAddChild(psRootNode, + _msMetadataGetCharacterString( + *ppsNsGmd, "language", + (char *)msOWSGetLanguage(map, "exception"), ppsNsGco)); + + /* gmd:hierarchyLevel */ + xmlAddChild(psRootNode, _msMetadataGetCodeList(*ppsNsGmd, "hierarchyLevel", + "MD_ScopeCode", "dataset")); + + /* gmd:contact */ + xmlAddChild(psRootNode, + _msMetadataGetContact(*ppsNsGmd, "contact", map, ppsNsGco)); + + /* gmd:dateStamp */ + /* TODO: nil for now, find way to derive this automagically */ + xmlAddChild(psRootNode, _msMetadataGetCharacterString( + *ppsNsGmd, "dateStamp", NULL, ppsNsGco)); + + /* gmd:metadataStandardName */ + xmlAddChild(psRootNode, + _msMetadataGetCharacterString( + *ppsNsGmd, "metadataStandardName", + "ISO 19115:2003 - Geographic information - Metadata", + ppsNsGco)); + + /* gmd:metadataStandardVersion */ + xmlAddChild(psRootNode, _msMetadataGetCharacterString( + *ppsNsGmd, "metadataStandardVersion", + "ISO 19115:2003", ppsNsGco)); + + /* gmd:spatialRepresentationInfo */ + xmlAddChild(psRootNode, _msMetadataGetSpatialRepresentationInfo( + *ppsNsGmd, layer, ppsNsGco)); + + /* gmd:referenceSystemInfo */ + xmlAddChild(psRootNode, + _msMetadataGetReferenceSystemInfo(*ppsNsGmd, layer, ppsNsGco)); + + /* gmd:identificationInfo */ + xmlAddChild(psRootNode, _msMetadataGetIdentificationInfo(*ppsNsGmd, map, + layer, ppsNsGco)); + + /* gmd:distributionInfo */ + xmlAddChild(psRootNode, _msMetadataGetDistributionInfo( + *ppsNsGmd, map, layer, cgi_request, ppsNsGco)); + } + + return psRootNode; +} + +/************************************************************************/ +/* msMetadataDispatch */ +/* */ +/* Entry point for metadata requests. */ +/* */ +/* - If this is a valid request then it is processed and MS_SUCCESS */ +/* is returned on success, or MS_FAILURE on failure. */ +/* */ +/* - If this does not appear to be a valid WFS request then MS_DONE */ +/* is returned and MapServer is expected to process this as a regular */ +/* MapServer request. */ +/************************************************************************/ + +int msMetadataDispatch(mapObj *map, cgiRequestObj *cgi_request) { + int i; + int status = MS_SUCCESS; + xmlNodePtr psRootNode = NULL; + xmlDocPtr xml_document; + metadataParamsObj *paramsObj; + layerObj *layer = NULL; + xmlNsPtr psNsOws = NULL; + xmlNsPtr psNsXsi = NULL; + xmlNsPtr psNsGmd = NULL; + xmlNsPtr psNsGco = NULL; + + /* Populate the Params object based on the request */ + + paramsObj = msMetadataCreateParamsObj(); + + xml_document = xmlNewDoc(BAD_CAST "1.0"); + + if (msMetadataParseRequest(cgi_request, paramsObj) == MS_FAILURE) { + psRootNode = msMetadataGetExceptionReport( + map, "InvalidRequest", "layer", "Request parsing failed", &psNsOws); + status = MS_FAILURE; + } + + /* if layer= is not specified, */ + if (paramsObj->pszLayer == NULL || strlen(paramsObj->pszLayer) == 0) { + psRootNode = + msMetadataGetExceptionReport(map, "MissingParameterValue", "layer", + "Missing layer parameter", &psNsOws); + status = MS_FAILURE; + } + + if (status == MS_SUCCESS) { /* Start dispatching request */ + /* Check that layer requested exists in mapfile */ + for (i = 0; i < map->numlayers; i++) { + if (strcasecmp(GET_LAYER(map, i)->name, paramsObj->pszLayer) == 0) { + layer = GET_LAYER(map, i); + break; + } + } + if (layer != NULL && + msOWSLookupMetadata(&(layer->metadata), "MFCO", "metadataurl_href")) { + msIO_setHeader("Status", "301 Moved Permanently"); + msIO_setHeader( + "Location", "%s", + msOWSLookupMetadata(&(layer->metadata), "MFCO", "metadataurl_href")); + msIO_sendHeaders(); + } else { + psRootNode = msMetadataGetLayerMetadata( + map, paramsObj, cgi_request, &psNsOws, &psNsXsi, &psNsGmd, &psNsGco); + } + } + + if (psRootNode != NULL) { + xmlChar *xml_buffer = NULL; + int buffersize = 0; + xmlDocSetRootElement(xml_document, psRootNode); + + msIO_setHeader("Content-type", "text/xml; charset=UTF-8"); + msIO_sendHeaders(); + + msIOContext *context = NULL; + + context = msIO_getHandler(stdout); + + xmlDocDumpFormatMemoryEnc(xml_document, &xml_buffer, &buffersize, "UTF-8", + 1); + msIO_contextWrite(context, xml_buffer, buffersize); + + xmlFree(xml_buffer); + } + xmlFreeDoc(xml_document); + if (psNsOws) + xmlFreeNs(psNsOws); + if (psNsXsi) + xmlFreeNs(psNsXsi); + if (psNsGmd) + xmlFreeNs(psNsGmd); + if (psNsGco) + xmlFreeNs(psNsGco); + + msMetadataFreeParamsObj(paramsObj); + + return status; +} + +#endif /* USE_LIBXML2 */ + +/************************************************************************/ +/* msMetadataCreateParamsObj */ +/* */ +/* Create a parameter object, initialize it. */ +/* The caller should free the object using msMetadataFreeParamsObj. */ +/************************************************************************/ + +metadataParamsObj *msMetadataCreateParamsObj() { + metadataParamsObj *paramsObj = + (metadataParamsObj *)calloc(1, sizeof(metadataParamsObj)); + MS_CHECK_ALLOC(paramsObj, sizeof(metadataParamsObj), NULL); + + paramsObj->pszLayer = NULL; + paramsObj->pszOutputSchema = NULL; + return paramsObj; +} + +/************************************************************************/ +/* msMetadataFreeParmsObj */ +/* */ +/* Free params object. */ +/************************************************************************/ + +void msMetadataFreeParamsObj(metadataParamsObj *metadataparams) { + if (metadataparams) { + free(metadataparams->pszRequest); + free(metadataparams->pszLayer); + free(metadataparams->pszOutputSchema); + free(metadataparams); + } +} + +/************************************************************************/ +/* msMetadataParseRequest */ +/* */ +/* Parse request into the params object. */ +/************************************************************************/ + +static int msMetadataParseRequest(cgiRequestObj *request, + metadataParamsObj *metadataparams) { + if (!request || !metadataparams) + return MS_FAILURE; + + if (request->NumParams > 0) { + for (int i = 0; i < request->NumParams; i++) { + if (request->ParamNames[i] && request->ParamValues[i]) { + if (strcasecmp(request->ParamNames[i], "LAYER") == 0) + metadataparams->pszLayer = msStrdup(request->ParamValues[i]); + if (strcasecmp(request->ParamNames[i], "OUTPUTSCHEMA") == 0) + metadataparams->pszOutputSchema = msStrdup(request->ParamValues[i]); + } + } + } + return MS_SUCCESS; +} + +/************************************************************************/ +/* msMetadataSetGetMetadataURL */ +/* */ +/* Parse request into the params object. */ +/************************************************************************/ + +void msMetadataSetGetMetadataURL(layerObj *lp, const char *url) { + char *pszMetadataURL = NULL; + + pszMetadataURL = msStrdup(url); + msDecodeHTMLEntities(pszMetadataURL); + pszMetadataURL = + msStringConcatenate(pszMetadataURL, "request=GetMetadata&layer="); + pszMetadataURL = msStringConcatenate(pszMetadataURL, lp->name); + + msInsertHashTable(&(lp->metadata), "ows_metadataurl_href", pszMetadataURL); + msInsertHashTable(&(lp->metadata), "ows_metadataurl_type", "TC211"); + msInsertHashTable(&(lp->metadata), "ows_metadataurl_format", "text/xml"); + msInsertHashTable(&(lp->metadata), "ows_metadatalink_href", pszMetadataURL); + msInsertHashTable(&(lp->metadata), "ows_metadatalink_type", "TC211"); + msInsertHashTable(&(lp->metadata), "ows_metadatalink_format", "text/xml"); + msFree(pszMetadataURL); +} + +#endif diff --git a/src/mapmssql2008.c b/src/mapmssql2008.c new file mode 100644 index 0000000000..7f5350aa9b --- /dev/null +++ b/src/mapmssql2008.c @@ -0,0 +1,4175 @@ +/****************************************************************************** + * $Id$ + * + * Project: MapServer + * Purpose: MS SQL Server Layer Connector + * Author: Richard Hillman - based on PostGIS and SpatialDB connectors + * Tamas Szekeres - maintenance + * + ****************************************************************************** + * Copyright (c) 2007 IS Consulting (www.mapdotnet.com) + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + ****************************************************************************** + * + * Revision 1.0 2007/7/1 + * Created. + * + */ +#ifndef _WIN32 +#define _GNU_SOURCE +#endif + +#define _CRT_SECURE_NO_WARNINGS 1 + +/* $Id$ */ +#include +#include "mapserver.h" +#include "maptime.h" +#include "mapows.h" + +#ifdef USE_MSSQL2008 + +#ifdef _WIN32 +#include +#endif +#include +#include +#include + +#include +#include /* tolower() */ + +/* SqlGeometry/SqlGeography serialization format + +Simple Point (SerializationProps & IsSinglePoint) + [SRID][0x01][SerializationProps][Point][z][m] + +Simple Line Segment (SerializationProps & IsSingleLineSegment) + [SRID][0x01][SerializationProps][Point1][Point2][z1][z2][m1][m2] + +Complex Geometries + [SRID][VersionAttribute][SerializationProps][NumPoints][Point1]..[PointN][z1]..[zN][m1]..[mN] + [NumFigures][Figure]..[Figure][NumShapes][Shape]..[Shape] + +Complex Geometries (FigureAttribute == Curve) + [SRID][VersionAttribute][SerializationProps][NumPoints][Point1]..[PointN][z1]..[zN][m1]..[mN] + [NumFigures][Figure]..[Figure][NumShapes][Shape]..[Shape][NumSegments][SegmentType]..[SegmentType] + +VersionAttribute (1 byte) + 0x01 = Katmai (MSSQL2008+) + 0x02 = Denali (MSSQL2012+) + +SRID + Spatial Reference Id (4 bytes) + +SerializationProps (bitmask) 1 byte + 0x01 = HasZValues + 0x02 = HasMValues + 0x04 = IsValid + 0x08 = IsSinglePoint + 0x10 = IsSingleLineSegment + 0x20 = IsLargerThanAHemisphere + +Point (2-4)x8 bytes, size depends on SerializationProps & HasZValues & +HasMValues [x][y] - SqlGeometry [latitude][longitude] - +SqlGeography + +Figure + [FigureAttribute][PointOffset] + +FigureAttribute - Katmai (1 byte) + 0x00 = Interior Ring + 0x01 = Stroke + 0x02 = Exterior Ring + +FigureAttribute - Denali (1 byte) + 0x00 = None + 0x01 = Line + 0x02 = Arc + 0x03 = Curve + +Shape + [ParentFigureOffset][FigureOffset][ShapeType] + +ShapeType (1 byte) + 0x00 = Unknown + 0x01 = Point + 0x02 = LineString + 0x03 = Polygon + 0x04 = MultiPoint + 0x05 = MultiLineString + 0x06 = MultiPolygon + 0x07 = GeometryCollection + -- Denali + 0x08 = CircularString + 0x09 = CompoundCurve + 0x0A = CurvePolygon + 0x0B = FullGlobe + +SegmentType (1 byte) + 0x00 = Line + 0x01 = Arc + 0x02 = FirstLine + 0x03 = FirstArc + +*/ + +/* Native geometry parser macros */ + +/* parser error codes */ +#define NOERROR 0 +#define NOT_ENOUGH_DATA 1 +#define CORRUPT_DATA 2 +#define UNSUPPORTED_GEOMETRY_TYPE 3 + +/* geometry format to transfer geometry column */ +#define MSSQLGEOMETRY_NATIVE 0 +#define MSSQLGEOMETRY_WKB 1 +#define MSSQLGEOMETRY_WKT 2 + +/* geometry column types */ +#define MSSQLCOLTYPE_GEOMETRY 0 +#define MSSQLCOLTYPE_GEOGRAPHY 1 +#define MSSQLCOLTYPE_BINARY 2 +#define MSSQLCOLTYPE_TEXT 3 + +#define SP_NONE 0 +#define SP_HASZVALUES 1 +#define SP_HASMVALUES 2 +#define SP_ISVALID 4 +#define SP_ISSINGLEPOINT 8 +#define SP_ISSINGLELINESEGMENT 0x10 +#define SP_ISLARGERTHANAHEMISPHERE 0x20 + +#define ST_UNKNOWN 0 +#define ST_POINT 1 +#define ST_LINESTRING 2 +#define ST_POLYGON 3 +#define ST_MULTIPOINT 4 +#define ST_MULTILINESTRING 5 +#define ST_MULTIPOLYGON 6 +#define ST_GEOMETRYCOLLECTION 7 +#define ST_CIRCULARSTRING 8 +#define ST_COMPOUNDCURVE 9 +#define ST_CURVEPOLYGON 10 +#define ST_FULLGLOBE 11 + +#define SMT_LINE 0 +#define SMT_ARC 1 +#define SMT_FIRSTLINE 2 +#define SMT_FIRSTARC 3 + +#define ReadInt32(nPos) (*((unsigned int *)(gpi->pszData + (nPos)))) + +#define ReadByte(nPos) (gpi->pszData[nPos]) + +#define ReadDouble(nPos) (*((double *)(gpi->pszData + (nPos)))) + +#define ParentOffset(iShape) (ReadInt32(gpi->nShapePos + (iShape)*9)) +#define FigureOffset(iShape) (ReadInt32(gpi->nShapePos + (iShape)*9 + 4)) +#define ShapeType(iShape) (ReadByte(gpi->nShapePos + (iShape)*9 + 8)) +#define SegmentType(iSegment) (ReadByte(gpi->nSegmentPos + (iSegment))) + +#define NextFigureOffset(iShape) \ + (iShape + 1 < gpi->nNumShapes ? FigureOffset((iShape) + 1) : gpi->nNumFigures) + +#define FigureAttribute(iFigure) (ReadByte(gpi->nFigurePos + (iFigure)*5)) +#define PointOffset(iFigure) (ReadInt32(gpi->nFigurePos + (iFigure)*5 + 1)) +#define NextPointOffset(iFigure) \ + (iFigure + 1 < gpi->nNumFigures ? PointOffset((iFigure) + 1) \ + : (unsigned)gpi->nNumPoints) + +#define ReadX(iPoint) (ReadDouble(gpi->nPointPos + 16 * (iPoint))) +#define ReadY(iPoint) (ReadDouble(gpi->nPointPos + 16 * (iPoint) + 8)) +#define ReadZ(iPoint) \ + (ReadDouble(gpi->nPointPos + 16 * gpi->nNumPoints + 8 * (iPoint))) +#define ReadM(iPoint) \ + (ReadDouble(gpi->nPointPos + 24 * gpi->nNumPoints + 8 * (iPoint))) + +#define FP_EPSILON 1e-12 +#define SEGMENT_ANGLE 5.0 +#define SEGMENT_MINPOINTS 10 + +/* Native geometry parser struct */ +typedef struct msGeometryParserInfo_t { + unsigned char *pszData; + int nLen; + /* version */ + char chVersion; + /* serialization properties */ + char chProps; + /* point array */ + int nPointSize; + int nPointPos; + int nNumPoints; + int nNumPointsRead; + /* figure array */ + int nFigurePos; + int nNumFigures; + /* shape array */ + int nShapePos; + int nNumShapes; + int nSRSId; + /* segment array */ + int nSegmentPos; + int nNumSegments; + /* geometry or geography */ + int nColType; + /* bounds */ + double minx; + double miny; + double maxx; + double maxy; +} msGeometryParserInfo; + +/* Structure for connection to an ODBC database (Microsoft preferred way to + * connect to SQL Server 2005 from c/c++) */ +typedef struct msODBCconn_t { + SQLHENV henv; /* ODBC HENV */ + SQLHDBC hdbc; /* ODBC HDBC */ + SQLHSTMT hstmt; /* ODBC HSTMNT */ + char errorMessage[1024]; /* Last error message if any */ + +} msODBCconn; + +typedef struct ms_MSSQL2008_layer_info_t { + char *sql; /* sql query to send to DB */ + long row_num; /* what row is the NEXT to be read (for random access) */ + char *geom_column; /* name of the actual geometry column parsed from the + LAYER's DATA field */ + char *geom_column_type; /* the type of the geometry column */ + char *geom_table; /* the table name or sub-select declared in the LAYER's DATA + field */ + char *urid_name; /* name of user-specified unique identifier or OID */ + char * + user_srid; /* zero length = calculate, non-zero means using this value! */ + char *index_name; /* hopefully this isn't necessary - but if the optimizer + ain't cuttin' it... */ + char *sort_spec; /* the sort by specification which should be applied to the + generated select statement */ + int mssqlversion_major; /* the sql server major version number */ + int paging; /* Driver handling of pagination, enabled by default */ + SQLSMALLINT + *itemtypes; /* storing the sql field types for further reference */ + + msODBCconn *conn; /* Connection to db */ + msGeometryParserInfo gpi; /* struct for the geometry parser */ + int geometry_format; /* Geometry format to be retrieved from the database */ + tokenListNodeObjPtr current_node; /* filter expression translation */ +} msMSSQL2008LayerInfo; + +#define SQL_COLUMN_NAME_MAX_LENGTH 128 +#define SQL_TABLE_NAME_MAX_LENGTH 128 + +#define DATA_ERROR_MESSAGE \ + "%s" \ + "Error with MSSQL2008 data variable. You specified '%s'.
\n" \ + "Standard ways of specifying are :
\n(1) 'geometry_column from " \ + "geometry_table'
\n(2) 'geometry_column from (<sub query>) as " \ + "foo using unique <column name> using SRID=<srid#>' " \ + "

\n\n" \ + "Make sure you utilize the 'using unique <column name>' and 'using " \ + "with <index name>' clauses in.\n\n

" \ + "For more help, please see http://www.mapdotnet.com \n\n

" \ + "mapmssql2008.c - version of 2007/7/1.\n" + +/* Native geometry parser code */ +void ReadPoint(msGeometryParserInfo *gpi, pointObj *p, int iPoint) { + if (gpi->nColType == MSSQLCOLTYPE_GEOGRAPHY) { + p->x = ReadY(iPoint); + p->y = ReadX(iPoint); + } else { + p->x = ReadX(iPoint); + p->y = ReadY(iPoint); + } + /* calculate bounds */ + if (gpi->nNumPointsRead++ == 0) { + gpi->minx = gpi->maxx = p->x; + gpi->miny = gpi->maxy = p->y; + } else { + if (gpi->minx > p->x) + gpi->minx = p->x; + else if (gpi->maxx < p->x) + gpi->maxx = p->x; + if (gpi->miny > p->y) + gpi->miny = p->y; + else if (gpi->maxy < p->y) + gpi->maxy = p->y; + } + + if ((gpi->chProps & SP_HASZVALUES) && (gpi->chProps & SP_HASMVALUES)) { + p->z = ReadZ(iPoint); + p->m = ReadM(iPoint); + } else if (gpi->chProps & SP_HASZVALUES) { + p->z = ReadZ(iPoint); + p->m = 0.0; + } else if (gpi->chProps & SP_HASMVALUES) { + p->z = 0.0; + p->m = ReadZ(iPoint); + } else { + p->z = 0.0; + p->m = 0.0; + } +} + +int StrokeArcToLine(msGeometryParserInfo *gpi, lineObj *line, int index) { + if (index > 1) { + double x, y, x1, y1, x2, y2, x3, y3, dxa, dya, sxa, sya, dxb, dyb; + double d, sxb, syb, ox, oy, a1, a3, sa, da, a, radius; + int numpoints; + double z; + z = line->point[index].z; /* must be equal for arc segments */ + /* first point */ + x1 = line->point[index - 2].x; + y1 = line->point[index - 2].y; + /* second point */ + x2 = line->point[index - 1].x; + y2 = line->point[index - 1].y; + /* third point */ + x3 = line->point[index].x; + y3 = line->point[index].y; + + sxa = (x1 + x2); + sya = (y1 + y2); + dxa = x2 - x1; + dya = y2 - y1; + + sxb = (x2 + x3); + syb = (y2 + y3); + dxb = x3 - x2; + dyb = y3 - y2; + + d = (dxa * dyb - dya * dxb) * 2; + + if (fabs(d) < FP_EPSILON) { + /* points are colinear, nothing to do here */ + return index; + } + + /* calculating the center of circle */ + ox = ((sya - syb) * dya * dyb + sxa * dyb * dxa - sxb * dya * dxb) / d; + oy = ((sxb - sxa) * dxa * dxb + syb * dyb * dxa - sya * dya * dxb) / d; + + radius = sqrt((x1 - ox) * (x1 - ox) + (y1 - oy) * (y1 - oy)); + + /* calculating the angle to be used */ + a1 = atan2(y1 - oy, x1 - ox); + a3 = atan2(y3 - oy, x3 - ox); + + if (d > 0) { + /* draw counterclockwise */ + if (a3 > a1) /* Wrapping past 180? */ + sa = a3 - a1; + else + sa = a3 - a1 + 2.0 * M_PI; + } else { + if (a3 > a1) /* Wrapping past 180? */ + sa = a3 - a1 + 2.0 * M_PI; + else + sa = a3 - a1; + } + + numpoints = (int)floor(fabs(sa) * 180 / SEGMENT_ANGLE / M_PI); + if (numpoints < SEGMENT_MINPOINTS) + numpoints = SEGMENT_MINPOINTS; + + da = sa / numpoints; + + /* extend the point array */ + line->numpoints += numpoints - 2; + line->point = + msSmallRealloc(line->point, sizeof(pointObj) * line->numpoints); + --index; + + a = a1 + da; + while (numpoints > 1) { + line->point[index].x = x = ox + radius * cos(a); + line->point[index].y = y = oy + radius * sin(a); + line->point[index].z = z; + + /* calculate bounds */ + if (gpi->minx > x) + gpi->minx = x; + else if (gpi->maxx < x) + gpi->maxx = x; + if (gpi->miny > y) + gpi->miny = y; + else if (gpi->maxy < y) + gpi->maxy = y; + + a += da; + ++index; + --numpoints; + } + /* set last point */ + line->point[index].x = x3; + line->point[index].y = y3; + line->point[index].z = z; + } + return index; +} + +int ParseSqlGeometry(msMSSQL2008LayerInfo *layerinfo, shapeObj *shape) { + msGeometryParserInfo *gpi = &layerinfo->gpi; + + gpi->nNumPointsRead = 0; + + if (gpi->nLen < 10) { + msDebug("ParseSqlGeometry NOT_ENOUGH_DATA\n"); + return NOT_ENOUGH_DATA; + } + + /* store the SRS id for further use */ + gpi->nSRSId = ReadInt32(0); + + gpi->chVersion = ReadByte(4); + + if (gpi->chVersion > 2) { + msDebug("ParseSqlGeometry CORRUPT_DATA\n"); + return CORRUPT_DATA; + } + + gpi->chProps = ReadByte(5); + + gpi->nPointSize = 16; + + if (gpi->chProps & SP_HASMVALUES) + gpi->nPointSize += 8; + + if (gpi->chProps & SP_HASZVALUES) + gpi->nPointSize += 8; + + if (gpi->chProps & SP_ISSINGLEPOINT) { + // single point geometry + gpi->nNumPoints = 1; + if (gpi->nLen < 6 + gpi->nPointSize) { + msDebug("ParseSqlGeometry NOT_ENOUGH_DATA\n"); + return NOT_ENOUGH_DATA; + } + + shape->type = MS_SHAPE_POINT; + shape->line = (lineObj *)msSmallMalloc(sizeof(lineObj)); + shape->numlines = 1; + shape->line[0].point = (pointObj *)msSmallMalloc(sizeof(pointObj)); + shape->line[0].numpoints = 1; + gpi->nPointPos = 6; + + ReadPoint(gpi, &shape->line[0].point[0], 0); + } else if (gpi->chProps & SP_ISSINGLELINESEGMENT) { + // single line segment with 2 points + gpi->nNumPoints = 2; + if (gpi->nLen < 6 + 2 * gpi->nPointSize) { + msDebug("ParseSqlGeometry NOT_ENOUGH_DATA\n"); + return NOT_ENOUGH_DATA; + } + + shape->type = MS_SHAPE_LINE; + shape->line = (lineObj *)msSmallMalloc(sizeof(lineObj)); + shape->numlines = 1; + shape->line[0].point = (pointObj *)msSmallMalloc(sizeof(pointObj) * 2); + shape->line[0].numpoints = 2; + gpi->nPointPos = 6; + + ReadPoint(gpi, &shape->line[0].point[0], 0); + ReadPoint(gpi, &shape->line[0].point[1], 1); + } else { + int iShape, iFigure, iSegment = 0; + // complex geometries + gpi->nNumPoints = ReadInt32(6); + + if (gpi->nNumPoints <= 0) { + return NOERROR; + } + + // position of the point array + gpi->nPointPos = 10; + + // position of the figures + gpi->nFigurePos = gpi->nPointPos + gpi->nPointSize * gpi->nNumPoints + 4; + + if (gpi->nLen < gpi->nFigurePos) { + msDebug("ParseSqlGeometry NOT_ENOUGH_DATA\n"); + return NOT_ENOUGH_DATA; + } + + gpi->nNumFigures = ReadInt32(gpi->nFigurePos - 4); + + if (gpi->nNumFigures <= 0) { + return NOERROR; + } + + // position of the shapes + gpi->nShapePos = gpi->nFigurePos + 5 * gpi->nNumFigures + 4; + + if (gpi->nLen < gpi->nShapePos) { + msDebug("ParseSqlGeometry NOT_ENOUGH_DATA\n"); + return NOT_ENOUGH_DATA; + } + + gpi->nNumShapes = ReadInt32(gpi->nShapePos - 4); + + if (gpi->nLen < gpi->nShapePos + 9 * gpi->nNumShapes) { + msDebug("ParseSqlGeometry NOT_ENOUGH_DATA\n"); + return NOT_ENOUGH_DATA; + } + + if (gpi->nNumShapes <= 0) { + return NOERROR; + } + + // pick up the root shape + if (ParentOffset(0) != 0xFFFFFFFF) { + msDebug("ParseSqlGeometry CORRUPT_DATA\n"); + return CORRUPT_DATA; + } + + // determine the shape type + for (iShape = 0; iShape < gpi->nNumShapes; iShape++) { + unsigned char shapeType = ShapeType(iShape); + if (shapeType == ST_POINT || shapeType == ST_MULTIPOINT) { + shape->type = MS_SHAPE_POINT; + break; + } else if (shapeType == ST_LINESTRING || + shapeType == ST_MULTILINESTRING || + shapeType == ST_CIRCULARSTRING || + shapeType == ST_COMPOUNDCURVE) { + shape->type = MS_SHAPE_LINE; + break; + } else if (shapeType == ST_POLYGON || shapeType == ST_MULTIPOLYGON || + shapeType == ST_CURVEPOLYGON) { + shape->type = MS_SHAPE_POLYGON; + break; + } + } + + shape->line = (lineObj *)msSmallMalloc(sizeof(lineObj) * gpi->nNumFigures); + shape->numlines = gpi->nNumFigures; + gpi->nNumSegments = 0; + + // read figures + for (iFigure = 0; iFigure < gpi->nNumFigures; iFigure++) { + int iPoint, iNextPoint, i; + iPoint = PointOffset(iFigure); + iNextPoint = NextPointOffset(iFigure); + + shape->line[iFigure].point = + (pointObj *)msSmallMalloc(sizeof(pointObj) * (iNextPoint - iPoint)); + shape->line[iFigure].numpoints = iNextPoint - iPoint; + i = 0; + + if (gpi->chVersion == 0x02 && FigureAttribute(iFigure) >= 0x02) { + int nPointPrepared = 0; + lineObj *line = &shape->line[iFigure]; + if (FigureAttribute(iFigure) == 0x03) { + if (gpi->nNumSegments == 0) { + /* position of the segment types */ + gpi->nSegmentPos = gpi->nShapePos + 9 * gpi->nNumShapes + 4; + gpi->nNumSegments = ReadInt32(gpi->nSegmentPos - 4); + if (gpi->nLen < gpi->nSegmentPos + gpi->nNumSegments) { + msDebug("ParseSqlGeometry NOT_ENOUGH_DATA\n"); + return NOT_ENOUGH_DATA; + } + iSegment = 0; + } + + while (iPoint < iNextPoint && iSegment < gpi->nNumSegments) { + ReadPoint(gpi, &line->point[i], iPoint); + ++iPoint; + ++nPointPrepared; + + if (nPointPrepared == 2 && + (SegmentType(iSegment) == SMT_FIRSTLINE || + SegmentType(iSegment) == SMT_LINE)) { + ++iSegment; + nPointPrepared = 1; + } else if (nPointPrepared == 3 && + (SegmentType(iSegment) == SMT_FIRSTARC || + SegmentType(iSegment) == SMT_ARC)) { + i = StrokeArcToLine(gpi, line, i); + ++iSegment; + nPointPrepared = 1; + } + ++i; + } + } else { + while (iPoint < iNextPoint) { + ReadPoint(gpi, &line->point[i], iPoint); + ++iPoint; + ++nPointPrepared; + if (nPointPrepared == 3) { + i = StrokeArcToLine(gpi, line, i); + nPointPrepared = 1; + } + ++i; + } + } + } else { + while (iPoint < iNextPoint) { + ReadPoint(gpi, &shape->line[iFigure].point[i], iPoint); + ++iPoint; + ++i; + } + } + } + } + + /* set bounds */ + shape->bounds.minx = gpi->minx; + shape->bounds.miny = gpi->miny; + shape->bounds.maxx = gpi->maxx; + shape->bounds.maxy = gpi->maxy; + + return NOERROR; +} + +/* MS SQL driver code*/ + +msMSSQL2008LayerInfo *getMSSQL2008LayerInfo(const layerObj *layer) { + return layer->layerinfo; +} + +void setMSSQL2008LayerInfo(layerObj *layer, + msMSSQL2008LayerInfo *MSSQL2008layerinfo) { + layer->layerinfo = (void *)MSSQL2008layerinfo; +} + +void handleSQLError(layerObj *layer) { + SQLCHAR SqlState[6], Msg[SQL_MAX_MESSAGE_LENGTH]; + SQLINTEGER NativeError; + SQLSMALLINT i, MsgLen; + SQLRETURN rc; + msMSSQL2008LayerInfo *layerinfo = getMSSQL2008LayerInfo(layer); + + if (layerinfo == NULL) + return; + + // Get the status records. + i = 1; + while ((rc = SQLGetDiagRec(SQL_HANDLE_STMT, layerinfo->conn->hstmt, i, + SqlState, &NativeError, Msg, sizeof(Msg), + &MsgLen)) != SQL_NO_DATA) { + if (layer->debug) { + msDebug("SQLError: %s\n", Msg); + } + i++; + } +} + +/* TODO Take a look at glibc's strcasestr */ +static char *strstrIgnoreCase(const char *haystack, const char *needle) { + char *hay_lower; + char *needle_lower; + size_t len_hay, len_need, match; + int found = MS_FALSE; + char *loc; + + len_hay = strlen(haystack); + len_need = strlen(needle); + + hay_lower = (char *)msSmallMalloc(len_hay + 1); + needle_lower = (char *)msSmallMalloc(len_need + 1); + + size_t t; + for (t = 0; t < len_hay; t++) { + hay_lower[t] = (char)tolower(haystack[t]); + } + hay_lower[t] = 0; + + for (t = 0; t < len_need; t++) { + needle_lower[t] = (char)tolower(needle[t]); + } + needle_lower[t] = 0; + + loc = strstr(hay_lower, needle_lower); + if (loc) { + match = loc - hay_lower; + found = MS_TRUE; + } + + msFree(hay_lower); + msFree(needle_lower); + + return (char *)(found == MS_FALSE ? NULL : haystack + match); +} + +static int msMSSQL2008LayerParseData(layerObj *layer, char **geom_column_name, + char **geom_column_type, char **table_name, + char **urid_name, char **user_srid, + char **index_name, char **sort_spec, + int debug); + +/* Close connection and handles */ +static void msMSSQL2008CloseConnection(void *conn_handle) { + msODBCconn *conn = (msODBCconn *)conn_handle; + if (!conn) { + return; + } + + if (conn->hstmt) { + SQLFreeHandle(SQL_HANDLE_STMT, conn->hstmt); + } + if (conn->hdbc) { + SQLDisconnect(conn->hdbc); + SQLFreeHandle(SQL_HANDLE_DBC, conn->hdbc); + } + if (conn->henv) { + SQLFreeHandle(SQL_HANDLE_ENV, conn->henv); + } + msFree(conn); +} + +/* Set the error string for the connection */ +static void setConnError(msODBCconn *conn) { + SQLSMALLINT len; + + SQLGetDiagField(SQL_HANDLE_DBC, conn->hdbc, 1, SQL_DIAG_MESSAGE_TEXT, + (SQLPOINTER)conn->errorMessage, sizeof(conn->errorMessage), + &len); + + conn->errorMessage[len] = 0; +} + +#if defined(_WIN32) && defined(USE_ICONV) +static SQLWCHAR *convertCwchartToSQLWCHAR(const wchar_t *inStr) { + SQLWCHAR *outStr; + int i, len; + for (len = 0; inStr[len] != 0; ++len) { + /* do nothing */ + } + outStr = (SQLWCHAR *)msSmallMalloc(sizeof(SQLWCHAR) * (len + 1)); + for (i = 0; i <= len; i++) { + outStr[i] = (SQLWCHAR)inStr[i]; + } + return outStr; +} +#endif + +/* Connect to db */ +static msODBCconn *mssql2008Connect(const char *connString) { + SQLSMALLINT outConnStringLen; + SQLRETURN rc; + msODBCconn *conn = msSmallMalloc(sizeof(msODBCconn)); + char fullConnString[1024]; + + memset(conn, 0, sizeof(*conn)); + + SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &conn->henv); + + SQLSetEnvAttr(conn->henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, 0); + + SQLAllocHandle(SQL_HANDLE_DBC, conn->henv, &conn->hdbc); + + if (strcasestr(connString, "DRIVER=") == 0) { + snprintf(fullConnString, sizeof(fullConnString), "DRIVER={SQL Server};%s", + connString); + + connString = fullConnString; + } + + { +#if defined(_WIN32) && defined(USE_ICONV) + wchar_t *decodedConnString = + msConvertWideStringFromUTF8(connString, "UCS-2LE"); + SQLWCHAR outConnString[1024]; + SQLWCHAR *decodedConnStringSQLWCHAR = + convertCwchartToSQLWCHAR(decodedConnString); + rc = SQLDriverConnectW(conn->hdbc, NULL, decodedConnStringSQLWCHAR, SQL_NTS, + outConnString, 1024, &outConnStringLen, + SQL_DRIVER_NOPROMPT); + msFree(decodedConnString); + msFree(decodedConnStringSQLWCHAR); +#else + SQLCHAR outConnString[1024]; + rc = SQLDriverConnect(conn->hdbc, NULL, (SQLCHAR *)connString, SQL_NTS, + outConnString, 1024, &outConnStringLen, + SQL_DRIVER_NOPROMPT); +#endif + } + + if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { + setConnError(conn); + + return conn; + } + + SQLAllocHandle(SQL_HANDLE_STMT, conn->hdbc, &conn->hstmt); + + return conn; +} + +/* Set the error string for the statement execution */ +static void setStmntError(msODBCconn *conn) { + SQLSMALLINT len; + + SQLGetDiagField(SQL_HANDLE_STMT, conn->hstmt, 1, SQL_DIAG_MESSAGE_TEXT, + (SQLPOINTER)conn->errorMessage, sizeof(conn->errorMessage), + &len); + + conn->errorMessage[len] = 0; +} + +/* Execute SQL against connection. Set error string if failed */ +static int executeSQL(msODBCconn *conn, const char *sql) { + SQLRETURN rc; + + SQLCloseCursor(conn->hstmt); + +#if defined(_WIN32) && defined(USE_ICONV) + { + wchar_t *decodedSql = msConvertWideStringFromUTF8(sql, "UCS-2LE"); + SQLWCHAR *decodedSqlSQLWCHAR = convertCwchartToSQLWCHAR(decodedSql); + rc = SQLExecDirectW(conn->hstmt, decodedSqlSQLWCHAR, SQL_NTS); + msFree(decodedSql); + msFree(decodedSqlSQLWCHAR); + } +#else + rc = SQLExecDirect(conn->hstmt, (SQLCHAR *)sql, SQL_NTS); +#endif + + if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO) { + return 1; + } else { + setStmntError(conn); + return 0; + } +} + +/* Get columns name from query results */ +static int columnName(msODBCconn *conn, int index, char *buffer, + int bufferLength, layerObj *layer, char pass_field_def, + SQLSMALLINT *itemType) { + SQLRETURN rc; + + SQLCHAR columnName[SQL_COLUMN_NAME_MAX_LENGTH + 1]; + SQLSMALLINT columnNameLen; + SQLSMALLINT dataType; + SQLULEN columnSize; + SQLSMALLINT decimalDigits; + SQLSMALLINT nullable; + + rc = SQLDescribeCol(conn->hstmt, (SQLUSMALLINT)index, columnName, + SQL_COLUMN_NAME_MAX_LENGTH, &columnNameLen, &dataType, + &columnSize, &decimalDigits, &nullable); + + if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO) { + if (bufferLength < SQL_COLUMN_NAME_MAX_LENGTH + 1) + strlcpy(buffer, (const char *)columnName, bufferLength); + else + strlcpy(buffer, (const char *)columnName, SQL_COLUMN_NAME_MAX_LENGTH + 1); + + *itemType = dataType; + + if (pass_field_def) { + char gml_width[32], gml_precision[32]; + const char *gml_type = NULL; + + gml_width[0] = '\0'; + gml_precision[0] = '\0'; + + switch (dataType) { + case SQL_INTEGER: + case SQL_SMALLINT: + case SQL_TINYINT: + gml_type = "Integer"; + break; + + case SQL_BIGINT: + gml_type = "Long"; + break; + + case SQL_REAL: + case SQL_FLOAT: + case SQL_DOUBLE: + case SQL_DECIMAL: + case SQL_NUMERIC: + gml_type = "Real"; + if (decimalDigits > 0) + sprintf(gml_precision, "%d", decimalDigits); + break; + + case SQL_TYPE_DATE: + gml_type = "Date"; + break; + case SQL_TYPE_TIME: + gml_type = "Time"; + break; + case SQL_TYPE_TIMESTAMP: + gml_type = "DateTime"; + break; + + case SQL_BIT: + gml_type = "Boolean"; + break; + + default: + gml_type = "Character"; + break; + } + + if (columnSize > 0) + sprintf(gml_width, "%u", (unsigned int)columnSize); + + msUpdateGMLFieldMetadata(layer, buffer, gml_type, gml_width, + gml_precision, (const short)nullable); + } + return 1; + } else { + setStmntError(conn); + return 0; + } +} + +/* open up a connection to the MS SQL 2008 database using the connection string + * in layer->connection */ +/* ie. "driver=;server=;database=;integrated + * security=?;user id=;password=" */ +int msMSSQL2008LayerOpen(layerObj *layer) { + msMSSQL2008LayerInfo *layerinfo; + char *conn_decrypted = NULL; + + if (layer->debug) { + msDebug("msMSSQL2008LayerOpen called datastatement: %s\n", layer->data); + } + + if (getMSSQL2008LayerInfo(layer)) { + if (layer->debug) { + msDebug("msMSSQL2008LayerOpen :: layer is already open!!\n"); + } + return MS_SUCCESS; /* already open */ + } + + if (!layer->data) { + msSetError(MS_QUERYERR, DATA_ERROR_MESSAGE, "msMSSQL2008LayerOpen()", "", + "Error parsing MSSQL2008 data variable: nothing specified in " + "DATA statement.

\n\nMore Help:

\n\n"); + + return MS_FAILURE; + } + + if (!layer->connection) { + msSetError(MS_QUERYERR, "MSSQL connection parameter not specified.", + "msMSSQL2008LayerOpen()"); + return MS_FAILURE; + } + + /* have to setup a connection to the database */ + + layerinfo = + (msMSSQL2008LayerInfo *)msSmallMalloc(sizeof(msMSSQL2008LayerInfo)); + + layerinfo->sql = NULL; /* calc later */ + layerinfo->row_num = 0; + layerinfo->geom_column = NULL; + layerinfo->geom_column_type = NULL; + layerinfo->geom_table = NULL; + layerinfo->urid_name = NULL; + layerinfo->user_srid = NULL; + layerinfo->index_name = NULL; + layerinfo->sort_spec = NULL; + layerinfo->conn = NULL; + layerinfo->itemtypes = NULL; + layerinfo->mssqlversion_major = 0; + layerinfo->paging = MS_TRUE; + + layerinfo->conn = (msODBCconn *)msConnPoolRequest(layer); + + if (!layerinfo->conn) { + if (layer->debug) { + msDebug("MSMSSQL2008LayerOpen -- shared connection not available.\n"); + } + + /* Decrypt any encrypted token in connection and attempt to connect */ + conn_decrypted = msDecryptStringTokens(layer->map, layer->connection); + if (conn_decrypted == NULL) { + return (MS_FAILURE); /* An error should already have been produced */ + } + + layerinfo->conn = mssql2008Connect(conn_decrypted); + + msFree(conn_decrypted); + conn_decrypted = NULL; + + if (!layerinfo->conn || layerinfo->conn->errorMessage[0]) { + char *errMess = "Out of memory"; + + if (layer->debug) + msDebug("MSMSSQL2008LayerOpen: Connection failure.\n"); + + if (layerinfo->conn) { + errMess = layerinfo->conn->errorMessage; + } + + msDebug( + "Couldn't make connection to MS SQL Server with connect string " + "'%s'.\n" + "Error reported was '%s'.\n\n" + "This error occurred when trying to make a connection to the " + "specified SQL server.\n" + "Most commonly this is caused by: \n" + "(1) incorrect connection string \n" + "(2) you didn't specify a 'user id=...' in your connection string \n" + "(3) SQL server isn't running \n" + "(4) TCPIP not enabled for SQL Client or server \n\n", + layer->connection, errMess); + msSetError(MS_QUERYERR, + "Database connection failed. Check server logs for more " + "details. Is SQL Server running? Is it allowing connections? " + "Does the specified user exist? Is the password valid? Is the " + "database on the standard port?", + "MSMSSQL2008LayerOpen()"); + + msMSSQL2008CloseConnection(layerinfo->conn); + msFree(layerinfo); + return MS_FAILURE; + } + + msConnPoolRegister(layer, layerinfo->conn, msMSSQL2008CloseConnection); + } + + setMSSQL2008LayerInfo(layer, layerinfo); + + if (msMSSQL2008LayerParseData( + layer, &layerinfo->geom_column, &layerinfo->geom_column_type, + &layerinfo->geom_table, &layerinfo->urid_name, &layerinfo->user_srid, + &layerinfo->index_name, &layerinfo->sort_spec, + layer->debug) != MS_SUCCESS) { + msSetError(MS_QUERYERR, "Could not parse the layer data", + "msMSSQL2008LayerOpen()"); + return MS_FAILURE; + } + + /* identify the geometry transfer type */ + if (msLayerGetProcessingKey(layer, "MSSQL_READ_WKB") != NULL) + layerinfo->geometry_format = MSSQLGEOMETRY_WKB; + else { + layerinfo->geometry_format = MSSQLGEOMETRY_NATIVE; + if (strcasecmp(layerinfo->geom_column_type, "geography") == 0) + layerinfo->gpi.nColType = MSSQLCOLTYPE_GEOGRAPHY; + else + layerinfo->gpi.nColType = MSSQLCOLTYPE_GEOMETRY; + } + + return MS_SUCCESS; +} + +/* Return MS_TRUE if layer is open, MS_FALSE otherwise. */ +int msMSSQL2008LayerIsOpen(layerObj *layer) { + return getMSSQL2008LayerInfo(layer) ? MS_TRUE : MS_FALSE; +} + +/* Free the itemindexes array in a layer. */ +void msMSSQL2008LayerFreeItemInfo(layerObj *layer) { + if (layer->debug) { + msDebug("msMSSQL2008LayerFreeItemInfo called\n"); + } + + if (layer->iteminfo) { + msFree(layer->iteminfo); + } + + layer->iteminfo = NULL; +} + +/* allocate the iteminfo index array - same order as the item list */ +int msMSSQL2008LayerInitItemInfo(layerObj *layer) { + int i; + int *itemindexes; + + if (layer->debug) { + msDebug("msMSSQL2008LayerInitItemInfo called\n"); + } + + if (layer->numitems == 0) { + return MS_SUCCESS; + } + + msFree(layer->iteminfo); + + layer->iteminfo = (int *)msSmallMalloc(sizeof(int) * layer->numitems); + + itemindexes = (int *)layer->iteminfo; + + for (i = 0; i < layer->numitems; i++) { + itemindexes[i] = + i; /* last one is always the geometry one - the rest are non-geom */ + } + + return MS_SUCCESS; +} + +static int getMSSQLMajorVersion(layerObj *layer) { + msMSSQL2008LayerInfo *layerinfo = getMSSQL2008LayerInfo(layer); + if (layerinfo == NULL) + return 0; + + if (layerinfo->mssqlversion_major == 0) { + const char *mssqlversion_major = + msLayerGetProcessingKey(layer, "MSSQL_VERSION_MAJOR"); + if (mssqlversion_major != NULL) { + layerinfo->mssqlversion_major = atoi(mssqlversion_major); + } else { + /* need to query from database */ + if (executeSQL(layerinfo->conn, + "SELECT SERVERPROPERTY('ProductVersion')")) { + SQLRETURN rc = SQLFetch(layerinfo->conn->hstmt); + if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO) { + /* process results */ + char result_data[256]; + SQLLEN retLen = 0; + + rc = SQLGetData(layerinfo->conn->hstmt, 1, SQL_C_CHAR, result_data, + sizeof(result_data), &retLen); + + if (rc != SQL_ERROR) { + result_data[retLen] = 0; + layerinfo->mssqlversion_major = atoi(result_data); + } + } + } + } + } + + return layerinfo->mssqlversion_major; +} + +static int addFilter(layerObj *layer, char **query) { + if (layer->filter.native_string) { + (*query) = msStringConcatenate(*query, " WHERE ("); + (*query) = msStringConcatenate(*query, layer->filter.native_string); + (*query) = msStringConcatenate(*query, ")"); + return MS_TRUE; + } else if (msLayerGetProcessingKey(layer, "NATIVE_FILTER") != NULL) { + (*query) = msStringConcatenate(*query, " WHERE ("); + (*query) = msStringConcatenate( + *query, msLayerGetProcessingKey(layer, "NATIVE_FILTER")); + (*query) = msStringConcatenate(*query, ")"); + return MS_TRUE; + } + + return MS_FALSE; +} + +/* Get the layer extent as specified in the mapfile or a largest area */ +/* covering all features */ +int msMSSQL2008LayerGetExtent(layerObj *layer, rectObj *extent) { + msMSSQL2008LayerInfo *layerinfo; + char *query = 0; + char result_data[256]; + SQLLEN retLen; + SQLRETURN rc; + + if (layer->debug) { + msDebug("msMSSQL2008LayerGetExtent called\n"); + } + + if (!(layer->extent.minx == -1.0 && layer->extent.miny == -1.0 && + layer->extent.maxx == -1.0 && layer->extent.maxy == -1.0)) { + /* extent was already set */ + extent->minx = layer->extent.minx; + extent->miny = layer->extent.miny; + extent->maxx = layer->extent.maxx; + extent->maxy = layer->extent.maxy; + } + + layerinfo = getMSSQL2008LayerInfo(layer); + + if (!layerinfo) { + msSetError(MS_QUERYERR, "GetExtent called with layerinfo = NULL", + "msMSSQL2008LayerGetExtent()"); + return MS_FAILURE; + } + + /* set up statement */ + if (getMSSQLMajorVersion(layer) >= 11) { + if (strcasecmp(layerinfo->geom_column_type, "geography") == 0) { + query = msStringConcatenate( + query, "WITH extent(extentcol) AS (SELECT " + "geometry::EnvelopeAggregate(geometry::STGeomFromWKB("); + query = msStringConcatenate(query, layerinfo->geom_column); + query = msStringConcatenate(query, ".STAsBinary(), "); + query = msStringConcatenate(query, layerinfo->geom_column); + query = msStringConcatenate(query, ".STSrid)"); + } else { + query = msStringConcatenate( + query, + "WITH extent(extentcol) AS (SELECT geometry::EnvelopeAggregate("); + query = msStringConcatenate(query, layerinfo->geom_column); + } + query = msStringConcatenate(query, ") AS extentcol FROM "); + query = msStringConcatenate(query, layerinfo->geom_table); + + /* adding attribute filter */ + addFilter(layer, &query); + + query = msStringConcatenate( + query, + ") SELECT extentcol.STPointN(1).STX, extentcol.STPointN(1).STY, " + "extentcol.STPointN(3).STX, extentcol.STPointN(3).STY FROM extent"); + } else { + if (strcasecmp(layerinfo->geom_column_type, "geography") == 0) { + query = msStringConcatenate( + query, "WITH ENVELOPE as (SELECT geometry::STGeomFromWKB("); + query = msStringConcatenate(query, layerinfo->geom_column); + query = msStringConcatenate(query, ".STAsBinary(), "); + query = msStringConcatenate(query, layerinfo->geom_column); + query = msStringConcatenate(query, ".STSrid)"); + } else { + query = msStringConcatenate(query, "WITH ENVELOPE as (SELECT "); + query = msStringConcatenate(query, layerinfo->geom_column); + } + query = msStringConcatenate(query, ".STEnvelope() as envelope from "); + query = msStringConcatenate(query, layerinfo->geom_table); + + /* adding attribute filter */ + addFilter(layer, &query); + + query = msStringConcatenate( + query, "), CORNERS as (SELECT envelope.STPointN(1) as point from " + "ENVELOPE UNION ALL select envelope.STPointN(3) from ENVELOPE) " + "SELECT MIN(point.STX), MIN(point.STY), MAX(point.STX), " + "MAX(point.STY) FROM CORNERS"); + } + + if (!executeSQL(layerinfo->conn, query)) { + msFree(query); + return MS_FAILURE; + } + + msFree(query); + + /* process results */ + rc = SQLFetch(layerinfo->conn->hstmt); + + if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { + if (layer->debug) { + msDebug("msMSSQL2008LayerGetExtent: No results found.\n"); + } + return MS_FAILURE; + } + + rc = SQLGetData(layerinfo->conn->hstmt, 1, SQL_C_CHAR, result_data, + sizeof(result_data), &retLen); + if (rc == SQL_ERROR || retLen < 0) { + msSetError(MS_QUERYERR, "Failed to get MinX value", + "msMSSQL2008LayerGetExtent()"); + return MS_FAILURE; + } + + result_data[retLen] = 0; + + extent->minx = atof(result_data); + + rc = SQLGetData(layerinfo->conn->hstmt, 2, SQL_C_CHAR, result_data, + sizeof(result_data), &retLen); + if (rc == SQL_ERROR || retLen < 0) { + msSetError(MS_QUERYERR, "Failed to get MinY value", + "msMSSQL2008LayerGetExtent()"); + return MS_FAILURE; + } + + result_data[retLen] = 0; + + extent->miny = atof(result_data); + + rc = SQLGetData(layerinfo->conn->hstmt, 3, SQL_C_CHAR, result_data, + sizeof(result_data), &retLen); + if (rc == SQL_ERROR || retLen < 0) { + msSetError(MS_QUERYERR, "Failed to get MaxX value", + "msMSSQL2008LayerGetExtent()"); + return MS_FAILURE; + } + + result_data[retLen] = 0; + + extent->maxx = atof(result_data); + + rc = SQLGetData(layerinfo->conn->hstmt, 4, SQL_C_CHAR, result_data, + sizeof(result_data), &retLen); + if (rc == SQL_ERROR || retLen < 0) { + msSetError(MS_QUERYERR, "Failed to get MaxY value", + "msMSSQL2008LayerGetExtent()"); + return MS_FAILURE; + } + + result_data[retLen] = 0; + + extent->maxy = atof(result_data); + + return MS_SUCCESS; +} + +/* Get the layer feature count */ +int msMSSQL2008LayerGetNumFeatures(layerObj *layer) { + msMSSQL2008LayerInfo *layerinfo; + char *query = 0; + char result_data[256]; + SQLLEN retLen; + SQLRETURN rc; + + if (layer->debug) { + msDebug("msMSSQL2008LayerGetNumFeatures called\n"); + } + + layerinfo = getMSSQL2008LayerInfo(layer); + + if (!layerinfo) { + msSetError(MS_QUERYERR, "GetNumFeatures called with layerinfo = NULL", + "msMSSQL2008LayerGetNumFeatures()"); + return -1; + } + + /* set up statement */ + query = msStringConcatenate(query, "SELECT count(*) FROM "); + query = msStringConcatenate(query, layerinfo->geom_table); + + /* adding attribute filter */ + addFilter(layer, &query); + + if (!executeSQL(layerinfo->conn, query)) { + msFree(query); + return -1; + } + + msFree(query); + + rc = SQLFetch(layerinfo->conn->hstmt); + + if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { + if (layer->debug) { + msDebug("msMSSQL2008LayerGetNumFeatures: No results found.\n"); + } + + return -1; + } + + rc = SQLGetData(layerinfo->conn->hstmt, 1, SQL_C_CHAR, result_data, + sizeof(result_data), &retLen); + + if (rc == SQL_ERROR) { + msSetError(MS_QUERYERR, "Failed to get feature count", + "msMSSQL2008LayerGetNumFeatures()"); + return -1; + } + + result_data[retLen] = 0; + + return atoi(result_data); +} + +/* Prepare and execute the SQL statement for this layer */ +static int prepare_database(layerObj *layer, rectObj rect, char **query_string, + int isQuery) { + msMSSQL2008LayerInfo *layerinfo; + char *query = 0; + char *data_source = 0; + char *f_table_name = 0; + char *geom_table = 0; + char *tmp = 0; + char *paging_query = 0; + /* + "Geometry::STGeomFromText('POLYGON(())',)" + terminator = 40 chars + Plus 10 formatted doubles (15 digits of precision, a decimal point, a + space/comma delimiter each = 17 chars each) Plus SRID + comma - if SRID is a + long...we'll be safe with 10 chars + + or for geography columns + + "Geography::STGeomFromText('CURVEPOLYGON(())',)" + terminator = 46 chars + Plus 18 formatted doubles (15 digits of precision, a decimal point, a + space/comma delimiter each = 17 chars each) Plus SRID + comma - if SRID is a + long...we'll be safe with 10 chars + */ + char box3d[46 + 18 * 22 + 11]; + int t; + + char *pos_from, *pos_ftab, *pos_space, *pos_paren; + int hasFilter = MS_FALSE; + const rectObj rectInvalid = MS_INIT_INVALID_RECT; + const int bIsValidRect = memcmp(&rect, &rectInvalid, sizeof(rect)) != 0; + + layerinfo = getMSSQL2008LayerInfo(layer); + + /* Extract the proper f_table_name from the geom_table string. + * We are expecting the geom_table to be either a single word + * or a sub-select clause that possibly includes a join -- + * + * (select column[,column[,...]] from ftab[ natural join table2]) as foo + * + * We are expecting whitespace or a ')' after the ftab name. + * + */ + + geom_table = msStrdup(layerinfo->geom_table); + pos_from = strstrIgnoreCase(geom_table, " from "); + + if (!pos_from) { + f_table_name = (char *)msSmallMalloc(strlen(geom_table) + 1); + strcpy(f_table_name, geom_table); + } else { /* geom_table is a sub-select clause */ + pos_ftab = pos_from + 6; /* This should be the start of the ftab name */ + pos_space = strstr(pos_ftab, " "); /* First space */ + + /* TODO strrchr is POSIX and C99, rindex is neither */ +#if defined(_WIN32) && !defined(__CYGWIN__) + pos_paren = strrchr(pos_ftab, ')'); +#else + pos_paren = rindex(pos_ftab, ')'); +#endif + + if (!pos_space || !pos_paren) { + msSetError( + MS_QUERYERR, DATA_ERROR_MESSAGE, "prepare_database()", geom_table, + "Error parsing MSSQL2008 data variable: Something is wrong with your " + "subselect statement.

\n\nMore Help:

\n\n"); + + return MS_FAILURE; + } + + if (pos_paren < pos_space) { /* closing parenthesis precedes any space */ + f_table_name = (char *)msSmallMalloc(pos_paren - pos_ftab + 1); + strlcpy(f_table_name, pos_ftab, pos_paren - pos_ftab + 1); + } else { + f_table_name = (char *)msSmallMalloc(pos_space - pos_ftab + 1); + strlcpy(f_table_name, pos_ftab, pos_space - pos_ftab + 1); + } + } + + if (rect.minx == rect.maxx || rect.miny == rect.maxy) { + /* create point shape for rectangles with zero area */ + sprintf(box3d, + "%s::STGeomFromText('POINT(%.15g %.15g)',%s)", /* %s.STSrid)", */ + layerinfo->geom_column_type, rect.minx, rect.miny, + layerinfo->user_srid); + } else if (strcasecmp(layerinfo->geom_column_type, "geography") == 0) { + /* SQL Server has a problem when x is -180 or 180 */ + double minx = rect.minx <= -180 ? -179.999 : rect.minx; + double maxx = rect.maxx >= 180 ? 179.999 : rect.maxx; + double miny = rect.miny < -90 ? -90 : rect.miny; + double maxy = rect.maxy > 90 ? 90 : rect.maxy; + sprintf(box3d, + "Geography::STGeomFromText('CURVEPOLYGON((%.15g %.15g,%.15g " + "%.15g,%.15g %.15g,%.15g %.15g,%.15g %.15g,%.15g %.15g,%.15g " + "%.15g,%.15g %.15g,%.15g %.15g))',%s)", /* %s.STSrid)", */ + minx, miny, minx + (maxx - minx) / 2, miny, maxx, miny, maxx, + miny + (maxy - miny) / 2, maxx, maxy, minx + (maxx - minx) / 2, + maxy, minx, maxy, minx, miny + (maxy - miny) / 2, minx, miny, + layerinfo->user_srid); + } else { + sprintf(box3d, + "Geometry::STGeomFromText('POLYGON((%.15g %.15g,%.15g %.15g,%.15g " + "%.15g,%.15g %.15g,%.15g %.15g))',%s)", /* %s.STSrid)", */ + rect.minx, rect.miny, rect.maxx, rect.miny, rect.maxx, rect.maxy, + rect.minx, rect.maxy, rect.minx, rect.miny, layerinfo->user_srid); + } + + /* substitute token '!BOX!' in geom_table with the box3d - do an unlimited # + * of subs */ + /* to not undo the work here, we need to make sure that data_source is + * malloc'd here */ + + if (!strstr(geom_table, "!BOX!")) { + data_source = (char *)msSmallMalloc(strlen(geom_table) + 1); + strcpy(data_source, geom_table); + } else { + char *result = NULL; + + while (strstr(geom_table, "!BOX!")) { + /* need to do a substitution */ + char *start, *end; + char *oldresult = result; + start = strstr(geom_table, "!BOX!"); + end = start + 5; + + result = (char *)msSmallMalloc((start - geom_table) + strlen(box3d) + + strlen(end) + 1); + + strlcpy(result, geom_table, start - geom_table + 1); + strcpy(result + (start - geom_table), box3d); + strcat(result, end); + + geom_table = result; + msFree(oldresult); + } + + /* if we're here, this will be a malloc'd string, so no need to copy it */ + data_source = (char *)geom_table; + } + + /* start creating the query */ + + query = msStringConcatenate(query, "SELECT "); + if (layerinfo->paging && (layer->maxfeatures >= 0 || layer->startindex > 0)) + paging_query = msStringConcatenate(paging_query, "SELECT "); + + /* adding items to the select list */ + for (t = 0; t < layer->numitems; t++) { + int sqlType = (layerinfo->itemtypes != NULL) ? layerinfo->itemtypes[t] : 0; + int use256 = 0; + + /* Definitely small types: numeric, bit, date/time */ + switch (sqlType) { + case SQL_INTEGER: + case SQL_SMALLINT: + case SQL_TINYINT: + case SQL_BIGINT: + case SQL_DECIMAL: + case SQL_NUMERIC: + case SQL_FLOAT: + case SQL_REAL: + case SQL_DOUBLE: + case SQL_BIT: + case SQL_GUID: + case SQL_TYPE_DATE: + case SQL_TYPE_TIME: + case SQL_TYPE_TIMESTAMP: + use256 = 1; + break; + /* Everything else is potentially large, use MAX */ + } +#if defined(_WIN32) && defined(USE_ICONV) + if (use256) + query = msStringConcatenate(query, "convert(nvarchar(256), ["); + else + query = msStringConcatenate(query, "convert(nvarchar(max), ["); +#else + if (use256) + query = msStringConcatenate(query, "convert(varchar(256), ["); + else + query = msStringConcatenate(query, "convert(varchar(max), ["); +#endif + query = msStringConcatenate(query, layer->items[t]); + query = msStringConcatenate(query, "]) '"); + tmp = msIntToString(t); + query = msStringConcatenate(query, tmp); + if (paging_query) { + paging_query = msStringConcatenate(paging_query, "["); + paging_query = msStringConcatenate(paging_query, tmp); + paging_query = msStringConcatenate(paging_query, "], "); + } + msFree(tmp); + query = msStringConcatenate(query, "',"); + } + + /* adding geometry column */ + query = msStringConcatenate(query, "["); + query = msStringConcatenate(query, layerinfo->geom_column); + if (layerinfo->geometry_format == MSSQLGEOMETRY_NATIVE) + query = msStringConcatenate(query, "] 'geom',"); + else { + query = msStringConcatenate(query, "].STAsBinary() 'geom',"); + } + + /* adding id column */ + query = msStringConcatenate(query, "convert(varchar(36), ["); + query = msStringConcatenate(query, layerinfo->urid_name); + if (paging_query) { + paging_query = msStringConcatenate(paging_query, "[geom], [id] FROM ("); + query = msStringConcatenate(query, "]) 'id', row_number() over ("); + if (layerinfo->sort_spec) { + query = msStringConcatenate(query, layerinfo->sort_spec); + } + + if (layer->sortBy.nProperties > 0) { + tmp = msLayerBuildSQLOrderBy(layer); + if (layerinfo->sort_spec) { + query = msStringConcatenate(query, ", "); + } else { + query = msStringConcatenate(query, " ORDER BY "); + } + query = msStringConcatenate(query, tmp); + msFree(tmp); + } else { + if (!layerinfo->sort_spec) { + // use the unique Id as the default sort for paging + query = msStringConcatenate(query, "ORDER BY "); + query = msStringConcatenate(query, layerinfo->urid_name); + } + } + query = msStringConcatenate(query, ") 'rownum' FROM "); + } else { + query = msStringConcatenate(query, "]) 'id' FROM "); + } + + /* adding the source */ + query = msStringConcatenate(query, data_source); + msFree(data_source); + msFree(f_table_name); + + /* use the index hint if provided */ + if (layerinfo->index_name) { + query = msStringConcatenate(query, " WITH (INDEX("); + query = msStringConcatenate(query, layerinfo->index_name); + query = msStringConcatenate(query, "))"); + } + + /* adding attribute filter */ + hasFilter = addFilter(layer, &query); + + if (bIsValidRect) { + /* adding spatial filter */ + if (hasFilter == MS_FALSE) + query = msStringConcatenate(query, " WHERE "); + else + query = msStringConcatenate(query, " AND "); + + query = msStringConcatenate(query, layerinfo->geom_column); + query = msStringConcatenate(query, ".STIntersects("); + query = msStringConcatenate(query, box3d); + query = msStringConcatenate(query, ") = 1 "); + } + + if (paging_query) { + paging_query = msStringConcatenate(paging_query, query); + paging_query = msStringConcatenate(paging_query, ") tbl where [rownum] "); + if (layer->startindex > 0) { + tmp = msIntToString(layer->startindex); + paging_query = msStringConcatenate(paging_query, ">= "); + paging_query = msStringConcatenate(paging_query, tmp); + if (layer->maxfeatures >= 0) { + msFree(tmp); + // startindex already has 1 added to it, so we need to subtract 1 here + // to get the correct last rownum value + // WFS requests add an additional +1 (extrafeature) to check if there + // are more features beyond the requested page + // the additional feature is removed from the response in + // msWFSRetrieveFeatures + tmp = msIntToString(layer->startindex + layer->maxfeatures - 1); + paging_query = msStringConcatenate(paging_query, " and [rownum] <= "); + paging_query = msStringConcatenate(paging_query, tmp); + } + } else { + tmp = msIntToString(layer->maxfeatures); + paging_query = msStringConcatenate(paging_query, "<= "); + paging_query = msStringConcatenate(paging_query, tmp); + } + msFree(tmp); + msFree(query); + query = paging_query; + } else { + if (layerinfo->sort_spec) { + query = msStringConcatenate(query, layerinfo->sort_spec); + } + + /* Add extra sort by */ + if (layer->sortBy.nProperties > 0) { + char *pszTmp = msLayerBuildSQLOrderBy(layer); + if (layerinfo->sort_spec) + query = msStringConcatenate(query, ", "); + else + query = msStringConcatenate(query, " ORDER BY "); + query = msStringConcatenate(query, pszTmp); + msFree(pszTmp); + } else if (isQuery && !layerinfo->sort_spec) { + /* Add orderby to make the result set order deterministic */ + query = msStringConcatenate(query, " ORDER BY ["); + query = msStringConcatenate(query, layerinfo->urid_name); + query = msStringConcatenate(query, "]"); + } + } + + if (layer->debug) { + msDebug("query:%s\n", query); + } + + if (executeSQL(layerinfo->conn, query)) { + char pass_field_def = 0; + int t; + const char *value; + *query_string = query; + /* collect result information */ + if ((value = msOWSLookupMetadata(&(layer->metadata), "G", "types")) != + NULL && + strcasecmp(value, "auto") == 0) + pass_field_def = 1; + + msFree(layerinfo->itemtypes); + layerinfo->itemtypes = + msSmallMalloc(sizeof(SQLSMALLINT) * (layer->numitems + 1)); + for (t = 0; t < layer->numitems; t++) { + char colBuff[256]; + SQLSMALLINT itemType = 0; + + columnName(layerinfo->conn, t + 1, colBuff, sizeof(colBuff), layer, + pass_field_def, &itemType); + layerinfo->itemtypes[t] = itemType; + } + + return MS_SUCCESS; + } else { + msSetError( + MS_QUERYERR, "Error executing MSSQL2008 SQL statement: %s\n-%s\n", + "msMSSQL2008LayerGetShape()", query, layerinfo->conn->errorMessage); + + msFree(query); + + return MS_FAILURE; + } +} + +/* Execute SQL query for this layer */ +int msMSSQL2008LayerWhichShapes(layerObj *layer, rectObj rect, int isQuery) { + (void)isQuery; + msMSSQL2008LayerInfo *layerinfo = 0; + char *query_str = 0; + int set_up_result; + + if (layer->debug) { + msDebug("msMSSQL2008LayerWhichShapes called\n"); + } + + layerinfo = getMSSQL2008LayerInfo(layer); + + if (!layerinfo) { + /* layer not opened yet */ + msSetError(MS_QUERYERR, + "msMSSQL2008LayerWhichShapes called on unopened layer " + "(layerinfo = NULL)", + "msMSSQL2008LayerWhichShapes()"); + + return MS_FAILURE; + } + + if (!layer->data) { + msSetError(MS_QUERYERR, + "Missing DATA clause in MSSQL2008 Layer definition. DATA " + "statement must contain 'geometry_column from table_name' or " + "'geometry_column from (sub-query) as foo'.", + "msMSSQL2008LayerWhichShapes()"); + + return MS_FAILURE; + } + + set_up_result = prepare_database(layer, rect, &query_str, isQuery); + + if (set_up_result != MS_SUCCESS) { + msFree(query_str); + + return set_up_result; /* relay error */ + } + + msFree(layerinfo->sql); + layerinfo->sql = query_str; + layerinfo->row_num = 0; + + return MS_SUCCESS; +} + +/* Close the MSSQL2008 record set and connection */ +int msMSSQL2008LayerClose(layerObj *layer) { + msMSSQL2008LayerInfo *layerinfo; + + layerinfo = getMSSQL2008LayerInfo(layer); + + if (layer->debug) { + char *data = ""; + + if (layer->data) { + data = layer->data; + } + + msDebug("msMSSQL2008LayerClose datastatement: %s\n", data); + } + + if (layer->debug && !layerinfo) { + msDebug("msMSSQL2008LayerClose -- layerinfo is NULL\n"); + } + + if (layerinfo) { + msConnPoolRelease(layer, layerinfo->conn); + + layerinfo->conn = NULL; + + if (layerinfo->user_srid) { + msFree(layerinfo->user_srid); + layerinfo->user_srid = NULL; + } + + if (layerinfo->urid_name) { + msFree(layerinfo->urid_name); + layerinfo->urid_name = NULL; + } + + if (layerinfo->index_name) { + msFree(layerinfo->index_name); + layerinfo->index_name = NULL; + } + + if (layerinfo->sort_spec) { + msFree(layerinfo->sort_spec); + layerinfo->sort_spec = NULL; + } + + if (layerinfo->sql) { + msFree(layerinfo->sql); + layerinfo->sql = NULL; + } + + if (layerinfo->geom_column) { + msFree(layerinfo->geom_column); + layerinfo->geom_column = NULL; + } + + if (layerinfo->geom_column_type) { + msFree(layerinfo->geom_column_type); + layerinfo->geom_column_type = NULL; + } + + if (layerinfo->geom_table) { + msFree(layerinfo->geom_table); + layerinfo->geom_table = NULL; + } + + if (layerinfo->itemtypes) { + msFree(layerinfo->itemtypes); + layerinfo->itemtypes = NULL; + } + + setMSSQL2008LayerInfo(layer, NULL); + msFree(layerinfo); + } + + return MS_SUCCESS; +} + +/* ******************************************************* */ +/* wkb is assumed to be 2d (force_2d) */ +/* and wkb is a GEOMETRYCOLLECTION (force_collection) */ +/* and wkb is in the endian of this computer (asbinary(...,'[XN]DR')) */ +/* each of the sub-geom inside the collection are point,linestring, or polygon + */ +/* */ +/* also, int is 32bits long */ +/* double is 64bits long */ +/* ******************************************************* */ + +/* convert the wkb into points */ +/* points -> pass through */ +/* lines-> constituent points */ +/* polys-> treat ring like line and pull out the constituent points */ + +static int force_to_points(char *wkb, shapeObj *shape) { + /* we're going to make a 'line' for each entity (point, line or ring) in the + * geom collection */ + + int offset = 0; + int ngeoms; + int t, u, v; + int type, nrings, npoints; + lineObj line = {0, NULL}; + + shape->type = MS_SHAPE_NULL; /* nothing in it */ + + memcpy(&ngeoms, &wkb[5], 4); + offset = 9; /* were the first geometry is */ + for (t = 0; t < ngeoms; t++) { + memcpy(&type, &wkb[offset + 1], 4); /* type of this geometry */ + + if (type == 1) { + /* Point */ + shape->type = MS_SHAPE_POINT; + line.numpoints = 1; + line.point = (pointObj *)msSmallMalloc(sizeof(pointObj)); + + memcpy(&line.point[0].x, &wkb[offset + 5], 8); + memcpy(&line.point[0].y, &wkb[offset + 5 + 8], 8); + offset += 5 + 16; + msAddLine(shape, &line); + msFree(line.point); + } else if (type == 2) { + /* Linestring */ + shape->type = MS_SHAPE_POINT; + + memcpy(&line.numpoints, &wkb[offset + 5], 4); /* num points */ + line.point = (pointObj *)msSmallMalloc(sizeof(pointObj) * line.numpoints); + for (u = 0; u < line.numpoints; u++) { + memcpy(&line.point[u].x, &wkb[offset + 9 + (16 * u)], 8); + memcpy(&line.point[u].y, &wkb[offset + 9 + (16 * u) + 8], 8); + } + offset += 9 + 16 * line.numpoints; /* length of object */ + msAddLine(shape, &line); + msFree(line.point); + } else if (type == 3) { + /* Polygon */ + shape->type = MS_SHAPE_POINT; + + memcpy(&nrings, &wkb[offset + 5], 4); /* num rings */ + /* add a line for each polygon ring */ + offset += 9; /* now points at 1st linear ring */ + for (u = 0; u < nrings; u++) { + /* for each ring, make a line */ + memcpy(&npoints, &wkb[offset], 4); /* num points */ + line.numpoints = npoints; + line.point = (pointObj *)msSmallMalloc(sizeof(pointObj) * npoints); + /* point struct */ + for (v = 0; v < npoints; v++) { + memcpy(&line.point[v].x, &wkb[offset + 4 + (16 * v)], 8); + memcpy(&line.point[v].y, &wkb[offset + 4 + (16 * v) + 8], 8); + } + /* make offset point to next linear ring */ + msAddLine(shape, &line); + msFree(line.point); + offset += 4 + 16 * npoints; + } + } + } + + return MS_SUCCESS; +} + +/* convert the wkb into lines */ +/* points-> remove */ +/* lines -> pass through */ +/* polys -> treat rings as lines */ + +static int force_to_lines(char *wkb, shapeObj *shape) { + int offset = 0; + int ngeoms; + int t, u, v; + int type, nrings, npoints; + lineObj line = {0, NULL}; + + shape->type = MS_SHAPE_NULL; /* nothing in it */ + + memcpy(&ngeoms, &wkb[5], 4); + offset = 9; /* were the first geometry is */ + for (t = 0; t < ngeoms; t++) { + memcpy(&type, &wkb[offset + 1], 4); /* type of this geometry */ + + /* cannot do anything with a point */ + + if (type == 2) { + /* Linestring */ + shape->type = MS_SHAPE_LINE; + + memcpy(&line.numpoints, &wkb[offset + 5], 4); + line.point = (pointObj *)msSmallMalloc(sizeof(pointObj) * line.numpoints); + for (u = 0; u < line.numpoints; u++) { + memcpy(&line.point[u].x, &wkb[offset + 9 + (16 * u)], 8); + memcpy(&line.point[u].y, &wkb[offset + 9 + (16 * u) + 8], 8); + } + offset += 9 + 16 * line.numpoints; /* length of object */ + msAddLine(shape, &line); + msFree(line.point); + } else if (type == 3) { + /* polygon */ + shape->type = MS_SHAPE_LINE; + + memcpy(&nrings, &wkb[offset + 5], 4); /* num rings */ + /* add a line for each polygon ring */ + offset += 9; /* now points at 1st linear ring */ + for (u = 0; u < nrings; u++) { + /* for each ring, make a line */ + memcpy(&npoints, &wkb[offset], 4); + line.numpoints = npoints; + line.point = (pointObj *)msSmallMalloc(sizeof(pointObj) * npoints); + /* point struct */ + for (v = 0; v < npoints; v++) { + memcpy(&line.point[v].x, &wkb[offset + 4 + (16 * v)], 8); + memcpy(&line.point[v].y, &wkb[offset + 4 + (16 * v) + 8], 8); + } + /* make offset point to next linear ring */ + msAddLine(shape, &line); + msFree(line.point); + offset += 4 + 16 * npoints; + } + } + } + + return MS_SUCCESS; +} + +/* point -> reject */ +/* line -> reject */ +/* polygon -> lines of linear rings */ +static int force_to_polygons(char *wkb, shapeObj *shape) { + int offset = 0; + int ngeoms; + int t, u, v; + int type, nrings, npoints; + lineObj line = {0, NULL}; + + shape->type = MS_SHAPE_NULL; /* nothing in it */ + + memcpy(&ngeoms, &wkb[5], 4); + offset = 9; /* were the first geometry is */ + for (t = 0; t < ngeoms; t++) { + memcpy(&type, &wkb[offset + 1], 4); /* type of this geometry */ + + if (type == 3) { + /* polygon */ + shape->type = MS_SHAPE_POLYGON; + + memcpy(&nrings, &wkb[offset + 5], 4); /* num rings */ + /* add a line for each polygon ring */ + offset += 9; /* now points at 1st linear ring */ + for (u = 0; u < nrings; u++) { + /* for each ring, make a line */ + memcpy(&npoints, &wkb[offset], 4); /* num points */ + line.numpoints = npoints; + line.point = (pointObj *)msSmallMalloc(sizeof(pointObj) * npoints); + for (v = 0; v < npoints; v++) { + memcpy(&line.point[v].x, &wkb[offset + 4 + (16 * v)], 8); + memcpy(&line.point[v].y, &wkb[offset + 4 + (16 * v) + 8], 8); + } + /* make offset point to next linear ring */ + msAddLine(shape, &line); + msFree(line.point); + offset += 4 + 16 * npoints; + } + } + } + + return MS_SUCCESS; +} + +/* if there is any polygon in wkb, return force_polygon */ +/* if there is any line in wkb, return force_line */ +/* otherwise return force_point */ + +static int dont_force(char *wkb, shapeObj *shape) { + int offset = 0; + int ngeoms; + int type, t; + int best_type; + + best_type = MS_SHAPE_NULL; /* nothing in it */ + + memcpy(&ngeoms, &wkb[5], 4); + offset = 9; /* were the first geometry is */ + for (t = 0; t < ngeoms; t++) { + memcpy(&type, &wkb[offset + 1], 4); /* type of this geometry */ + + if (type == 3) { + best_type = MS_SHAPE_POLYGON; + } else if (type == 2 && best_type != MS_SHAPE_POLYGON) { + best_type = MS_SHAPE_LINE; + } else if (type == 1 && best_type == MS_SHAPE_NULL) { + best_type = MS_SHAPE_POINT; + } + } + + if (best_type == MS_SHAPE_POINT) { + return force_to_points(wkb, shape); + } + if (best_type == MS_SHAPE_LINE) { + return force_to_lines(wkb, shape); + } + if (best_type == MS_SHAPE_POLYGON) { + return force_to_polygons(wkb, shape); + } + + return MS_FAILURE; /* unknown type */ +} + +#if 0 +/* ******************************************************* */ +/* wkb assumed to be same endian as this machine. */ +/* Should be in little endian (default if created by Microsoft platforms) */ +/* ******************************************************* */ +/* convert the wkb into points */ +/* points -> pass through */ +/* lines-> constituent points */ +/* polys-> treat ring like line and pull out the constituent points */ +static int force_to_shapeType(char *wkb, shapeObj *shape, int msShapeType) +{ + int offset = 0; + int ngeoms = 1; + int u, v; + int type, nrings, npoints; + lineObj line = {0, NULL}; + + shape->type = MS_SHAPE_NULL; /* nothing in it */ + + do { + ngeoms--; + + memcpy(&type, &wkb[offset + 1], 4); /* type of this geometry */ + + if (type == 1) { + /* Point */ + shape->type = msShapeType; + line.numpoints = 1; + line.point = (pointObj *) msSmallMalloc(sizeof(pointObj)); + + memcpy(&line.point[0].x, &wkb[offset + 5], 8); + memcpy(&line.point[0].y, &wkb[offset + 5 + 8], 8); + offset += 5 + 16; + + if (msShapeType == MS_SHAPE_POINT) { + msAddLine(shape, &line); + } + + msFree(line.point); + } else if(type == 2) { + /* Linestring */ + shape->type = msShapeType; + + memcpy(&line.numpoints, &wkb[offset+5], 4); /* num points */ + line.point = (pointObj *) msSmallMalloc(sizeof(pointObj) * line.numpoints); + for(u = 0; u < line.numpoints; u++) { + memcpy( &line.point[u].x, &wkb[offset+9 + (16 * u)], 8); + memcpy( &line.point[u].y, &wkb[offset+9 + (16 * u)+8], 8); + } + offset += 9 + 16 * line.numpoints; /* length of object */ + + if ((msShapeType == MS_SHAPE_POINT) || (msShapeType == MS_SHAPE_LINE)) { + msAddLine(shape, &line); + } + + msFree(line.point); + } else if(type == 3) { + /* Polygon */ + shape->type = msShapeType; + + memcpy(&nrings, &wkb[offset+5],4); /* num rings */ + /* add a line for each polygon ring */ + offset += 9; /* now points at 1st linear ring */ + for(u = 0; u < nrings; u++) { + /* for each ring, make a line */ + memcpy(&npoints, &wkb[offset], 4); /* num points */ + line.numpoints = npoints; + line.point = (pointObj *) msSmallMalloc(sizeof(pointObj)* npoints); + /* point struct */ + for(v = 0; v < npoints; v++) { + memcpy(&line.point[v].x, &wkb[offset + 4 + (16 * v)], 8); + memcpy(&line.point[v].y, &wkb[offset + 4 + (16 * v) + 8], 8); + } + /* make offset point to next linear ring */ + msAddLine(shape, &line); + msFree(line.point); + offset += 4 + 16 *npoints; + } + } else if(type >= 4 && type <= 7) { + int cnt = 0; + + offset += 5; + + memcpy(&cnt, &wkb[offset], 4); + offset += 4; /* were the first geometry is */ + + ngeoms += cnt; + } + } while (ngeoms > 0); + + return MS_SUCCESS; +} +#endif + +///* if there is any polygon in wkb, return force_polygon */ +///* if there is any line in wkb, return force_line */ +///* otherwise return force_point */ +// static int dont_force(char *wkb, shapeObj *shape) +//{ +// int offset =0; +// int ngeoms = 1; +// int type; +// int best_type; +// int u; +// int nrings, npoints; +// +// best_type = MS_SHAPE_NULL; /* nothing in it */ +// +// do +// { +// ngeoms--; +// +// memcpy(&type, &wkb[offset + 1], 4); /* type of this geometry */ +// +// if(type == 3) { +// best_type = MS_SHAPE_POLYGON; +// } else if(type ==2 && best_type != MS_SHAPE_POLYGON) { +// best_type = MS_SHAPE_LINE; +// } else if(type == 1 && best_type == MS_SHAPE_NULL) { +// best_type = MS_SHAPE_POINT; +// } +// +// if (type == 1) +// { +// /* Point */ +// offset += 5 + 16; +// } +// else if(type == 2) +// { +// int numPoints; +// +// memcpy(&numPoints, &wkb[offset+5], 4); /* num points */ +// /* Linestring */ +// offset += 9 + 16 * numPoints; /* length of object */ +// } +// else if(type == 3) +// { +// /* Polygon */ +// memcpy(&nrings, &wkb[offset+5],4); /* num rings */ +// offset += 9; /* now points at 1st linear ring */ +// for(u = 0; u < nrings; u++) { +// /* for each ring, make a line */ +// memcpy(&npoints, &wkb[offset], 4); /* num points */ +// offset += 4 + 16 *npoints; +// } +// } +// else if(type >= 4 && type <= 7) +// { +// int cnt = 0; +// +// offset += 5; +// +// memcpy(&cnt, &wkb[offset], 4); +// offset += 4; /* were the first geometry is */ +// +// ngeoms += cnt; +// } +// } +// while (ngeoms > 0); +// +// return force_to_shapeType(wkb, shape, best_type); +// } +// +/* find the bounds of the shape */ +static void find_bounds(shapeObj *shape) { + int t, u; + int first_one = 1; + + for (t = 0; t < shape->numlines; t++) { + for (u = 0; u < shape->line[t].numpoints; u++) { + if (first_one) { + shape->bounds.minx = shape->line[t].point[u].x; + shape->bounds.maxx = shape->line[t].point[u].x; + + shape->bounds.miny = shape->line[t].point[u].y; + shape->bounds.maxy = shape->line[t].point[u].y; + first_one = 0; + } else { + if (shape->line[t].point[u].x < shape->bounds.minx) { + shape->bounds.minx = shape->line[t].point[u].x; + } + if (shape->line[t].point[u].x > shape->bounds.maxx) { + shape->bounds.maxx = shape->line[t].point[u].x; + } + + if (shape->line[t].point[u].y < shape->bounds.miny) { + shape->bounds.miny = shape->line[t].point[u].y; + } + if (shape->line[t].point[u].y > shape->bounds.maxy) { + shape->bounds.maxy = shape->line[t].point[u].y; + } + } + } + } +} + +/* Used by NextShape() to access a shape in the query set */ +int msMSSQL2008LayerGetShapeRandom(layerObj *layer, shapeObj *shape, + long *record) { + msMSSQL2008LayerInfo *layerinfo; + SQLLEN needLen = 0; + SQLLEN retLen = 0; + char dummyBuffer[1]; + char *wkbBuffer; + char *valueBuffer; + char oidBuffer[16]; /* assuming the OID will always be a long this should be + enough */ + long record_oid; + int t; + + /* for coercing single types into geometry collections */ + char *wkbTemp; + int geomType; + + layerinfo = getMSSQL2008LayerInfo(layer); + + if (!layerinfo) { + msSetError(MS_QUERYERR, "GetShape called with layerinfo = NULL", + "msMSSQL2008LayerGetShape()"); + return MS_FAILURE; + } + + if (!layerinfo->conn) { + msSetError(MS_QUERYERR, + "NextShape called on MSSQL2008 layer with no connection to DB.", + "msMSSQL2008LayerGetShape()"); + return MS_FAILURE; + } + + shape->type = MS_SHAPE_NULL; + + while (shape->type == MS_SHAPE_NULL) { + /* SQLRETURN rc = SQLFetchScroll(layerinfo->conn->hstmt, SQL_FETCH_ABSOLUTE, + * (SQLLEN) (*record) + 1); */ + + /* We only do forward fetches. the parameter 'record' is ignored, but is + * incremented */ + SQLRETURN rc = SQLFetch(layerinfo->conn->hstmt); + + /* Any error assume out of recordset bounds */ + if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { + handleSQLError(layer); + return MS_DONE; + } + + /* retrieve an item */ + + { + /* have to retrieve shape attributes */ + shape->values = (char **)msSmallMalloc(sizeof(char *) * layer->numitems); + shape->numvalues = layer->numitems; + + for (t = 0; t < layer->numitems; t++) { + /* Startwith a 64 character long buffer. This may need to be increased + * after calling SQLGetData. */ + SQLLEN emptyLen = 64; + valueBuffer = (char *)msSmallMalloc(emptyLen); + if (valueBuffer == NULL) { + msSetError(MS_QUERYERR, "Could not allocate value buffer.", + "msMSSQL2008LayerGetShapeRandom()"); + return MS_FAILURE; + } + +#if defined(_WIN32) && defined(USE_ICONV) + SQLSMALLINT targetType = SQL_WCHAR; +#else + SQLSMALLINT targetType = SQL_CHAR; +#endif + SQLLEN totalLen = 0; + char *bufferLocation = valueBuffer; + int r = 0; + while (r < 20) { + rc = SQLGetData(layerinfo->conn->hstmt, (SQLUSMALLINT)(t + 1), + targetType, bufferLocation, emptyLen, &retLen); + + if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO) + totalLen += + retLen > emptyLen || retLen == SQL_NO_TOTAL ? emptyLen : retLen; + + if (rc == SQL_SUCCESS_WITH_INFO && rc != SQL_NO_DATA) { + /* We must compensate for the last null termination that SQLGetData + * include */ + /* If we get SQL_NO_TOTAL we do not know how big buffer we need so + * we increase it with 512. */ +#if defined(_WIN32) && defined(USE_ICONV) + totalLen -= sizeof(wchar_t); + emptyLen = retLen != SQL_NO_TOTAL + ? retLen - emptyLen + 2 * sizeof(wchar_t) + : 512; +#else + totalLen -= sizeof(char); + emptyLen = retLen != SQL_NO_TOTAL + ? retLen - emptyLen + 2 * sizeof(char) + : 512; +#endif + + valueBuffer = + (char *)msSmallRealloc(valueBuffer, totalLen + emptyLen); + bufferLocation = valueBuffer + totalLen; + } else + break; + + r++; + } + + if (rc == SQL_ERROR) + handleSQLError(layer); + + if (totalLen > 0) { + /* Pop the value into the shape's value array */ +#if defined(_WIN32) && defined(USE_ICONV) + shape->values[t] = + msConvertWideStringToUTF8((wchar_t *)valueBuffer, "UCS-2LE"); + msFree(valueBuffer); +#else + shape->values[t] = valueBuffer; +#endif + } else { + /* Copy empty sting for NULL values */ + shape->values[t] = msStrdup(""); + msFree(valueBuffer); + } + } + + /* Get shape geometry */ + { + /* Set up to request the size of the buffer needed */ + rc = SQLGetData(layerinfo->conn->hstmt, + (SQLUSMALLINT)(layer->numitems + 1), SQL_C_BINARY, + dummyBuffer, 0, &needLen); + if (rc == SQL_ERROR) + handleSQLError(layer); + + /* allow space for coercion to geometry collection if needed*/ + wkbTemp = (char *)msSmallMalloc(needLen + 9); + + /* write data above space allocated for geometry collection coercion */ + wkbBuffer = wkbTemp + 9; + + if (wkbBuffer == NULL) { + msSetError(MS_QUERYERR, "Could not allocate value buffer.", + "msMSSQL2008LayerGetShapeRandom()"); + return MS_FAILURE; + } + + /* Grab the WKB */ + rc = SQLGetData(layerinfo->conn->hstmt, + (SQLUSMALLINT)(layer->numitems + 1), SQL_C_BINARY, + wkbBuffer, needLen, &retLen); + if (rc == SQL_ERROR || rc == SQL_SUCCESS_WITH_INFO) + handleSQLError(layer); + + if (layerinfo->geometry_format == MSSQLGEOMETRY_NATIVE) { + layerinfo->gpi.pszData = (unsigned char *)wkbBuffer; + layerinfo->gpi.nLen = (int)retLen; + + if (!ParseSqlGeometry(layerinfo, shape)) { + switch (layer->type) { + case MS_LAYER_POINT: + shape->type = MS_SHAPE_POINT; + break; + + case MS_LAYER_LINE: + shape->type = MS_SHAPE_LINE; + break; + + case MS_LAYER_POLYGON: + shape->type = MS_SHAPE_POLYGON; + break; + + default: + break; + } + } + } else { + memcpy(&geomType, wkbBuffer + 1, 4); + + /* is this a single type? */ + if (geomType < 4) { + /* copy byte order marker (although we don't check it) */ + wkbTemp[0] = wkbBuffer[0]; + wkbBuffer = wkbTemp; + + /* indicate type is geometry collection (although geomType + 3 would + * also work) */ + wkbBuffer[1] = (char)7; + wkbBuffer[2] = (char)0; + wkbBuffer[3] = (char)0; + wkbBuffer[4] = (char)0; + + /* indicate 1 shape */ + wkbBuffer[5] = (char)1; + wkbBuffer[6] = (char)0; + wkbBuffer[7] = (char)0; + wkbBuffer[8] = (char)0; + } + + switch (layer->type) { + case MS_LAYER_POINT: + /*result =*/force_to_points(wkbBuffer, shape); + break; + + case MS_LAYER_LINE: + /*result =*/force_to_lines(wkbBuffer, shape); + break; + + case MS_LAYER_POLYGON: + /*result =*/force_to_polygons(wkbBuffer, shape); + break; + + case MS_LAYER_QUERY: + case MS_LAYER_CHART: + /*result =*/dont_force(wkbBuffer, shape); + break; + + case MS_LAYER_RASTER: + msDebug("Ignoring MS_LAYER_RASTER in mapMSSQL2008.c\n"); + break; + + case MS_LAYER_CIRCLE: + msDebug("Ignoring MS_LAYER_CIRCLE in mapMSSQL2008.c\n"); + break; + + default: + msDebug("Unsupported layer type in msMSSQL2008LayerNextShape()!"); + break; + } + find_bounds(shape); + } + + // free(wkbBuffer); + msFree(wkbTemp); + } + + /* Next get unique id for row - since the OID shouldn't be larger than a + * long we'll assume billions as a limit */ + rc = SQLGetData(layerinfo->conn->hstmt, + (SQLUSMALLINT)(layer->numitems + 2), SQL_C_BINARY, + oidBuffer, sizeof(oidBuffer) - 1, &retLen); + if (rc == SQL_ERROR || rc == SQL_SUCCESS_WITH_INFO) + handleSQLError(layer); + + if (retLen > 0 && retLen < (int)sizeof(oidBuffer)) { + oidBuffer[retLen] = 0; + record_oid = strtol(oidBuffer, NULL, 10); + shape->index = record_oid; + } else { + /* non integer fid column, use single pass */ + shape->index = -1; + } + + shape->resultindex = (*record); + + (*record)++; /* move to next shape */ + + if (shape->type != MS_SHAPE_NULL) { + return MS_SUCCESS; + } else { + msDebug("msMSSQL2008LayerGetShapeRandom bad shape: %ld\n", *record); + } + /* if (layer->type == MS_LAYER_POINT) {return MS_DONE;} */ + } + } + + msFreeShape(shape); + + return MS_FAILURE; +} + +/* find the next shape with the appropriate shape type (convert it if necessary) + */ +/* also, load in the attribute data */ +/* MS_DONE => no more data */ +int msMSSQL2008LayerNextShape(layerObj *layer, shapeObj *shape) { + int result; + + msMSSQL2008LayerInfo *layerinfo; + + layerinfo = getMSSQL2008LayerInfo(layer); + + if (!layerinfo) { + msSetError(MS_QUERYERR, "NextShape called with layerinfo = NULL", + "msMSSQL2008LayerNextShape()"); + return MS_FAILURE; + } + + result = msMSSQL2008LayerGetShapeRandom(layer, shape, &(layerinfo->row_num)); + /* getshaperandom will increment the row_num */ + /* layerinfo->row_num ++; */ + + return result; +} + +/* Execute a query on the DB based on the query result. */ +int msMSSQL2008LayerGetShape(layerObj *layer, shapeObj *shape, + resultObj *record) { + char *query_str; + char *columns_wanted = 0; + + msMSSQL2008LayerInfo *layerinfo; + int t; + char buffer[32000] = ""; + long shapeindex = record->shapeindex; + long resultindex = record->resultindex; + + if (layer->debug) { + msDebug("msMSSQL2008LayerGetShape called for shapeindex = %ld\n", + shapeindex); + } + + layerinfo = getMSSQL2008LayerInfo(layer); + + if (!layerinfo) { + /* Layer not open */ + msSetError( + MS_QUERYERR, + "msMSSQL2008LayerGetShape called on unopened layer (layerinfo = NULL)", + "msMSSQL2008LayerGetShape()"); + + return MS_FAILURE; + } + + if (resultindex >= 0 && layerinfo->sql) { + /* trying to provide the result from the current resultset (single-pass + * query) */ + if (resultindex < layerinfo->row_num) { + /* re-issue the query */ + if (!executeSQL(layerinfo->conn, layerinfo->sql)) { + msSetError(MS_QUERYERR, + "Error executing MSSQL2008 SQL statement: %s\n-%s\n", + "msMSSQL2008LayerGetShape()", layerinfo->sql, + layerinfo->conn->errorMessage); + + return MS_FAILURE; + } + layerinfo->row_num = 0; + } + while (layerinfo->row_num < resultindex) { + /* move forward until we reach the desired index */ + if (msMSSQL2008LayerGetShapeRandom(layer, shape, &(layerinfo->row_num)) != + MS_SUCCESS) + return MS_FAILURE; + } + + return msMSSQL2008LayerGetShapeRandom(layer, shape, &(layerinfo->row_num)); + } + + /* non single-pass case, fetch the record from the database */ + + if (layer->numitems == 0) { + if (layerinfo->geometry_format == MSSQLGEOMETRY_NATIVE) + snprintf(buffer, sizeof(buffer), "%s, convert(varchar(36), %s)", + layerinfo->geom_column, layerinfo->urid_name); + else + snprintf(buffer, sizeof(buffer), + "%s.STAsBinary(), convert(varchar(36), %s)", + layerinfo->geom_column, layerinfo->urid_name); + columns_wanted = msStrdup(buffer); + } else { + for (t = 0; t < layer->numitems; t++) { + snprintf(buffer + strlen(buffer), sizeof(buffer) - strlen(buffer), + "convert(varchar(max), %s),", layer->items[t]); + } + + if (layerinfo->geometry_format == MSSQLGEOMETRY_NATIVE) + snprintf(buffer + strlen(buffer), sizeof(buffer) - strlen(buffer), + "%s, convert(varchar(36), %s)", layerinfo->geom_column, + layerinfo->urid_name); + else + snprintf(buffer + strlen(buffer), sizeof(buffer) - strlen(buffer), + "%s.STAsBinary(), convert(varchar(36), %s)", + layerinfo->geom_column, layerinfo->urid_name); + + columns_wanted = msStrdup(buffer); + } + + /* index_name is ignored here since the hint should be for the spatial index, + * not the PK index */ + snprintf(buffer, sizeof(buffer), "select %s from %s where %s = %ld", + columns_wanted, layerinfo->geom_table, layerinfo->urid_name, + shapeindex); + + query_str = msStrdup(buffer); + + if (layer->debug) { + msDebug("msMSSQL2008LayerGetShape: %s \n", query_str); + } + + msFree(columns_wanted); + + if (!executeSQL(layerinfo->conn, query_str)) { + msSetError( + MS_QUERYERR, "Error executing MSSQL2008 SQL statement: %s\n-%s\n", + "msMSSQL2008LayerGetShape()", query_str, layerinfo->conn->errorMessage); + + msFree(query_str); + + return MS_FAILURE; + } + + /* we don't preserve the query string in this case (cannot be re-used) */ + msFree(query_str); + layerinfo->row_num = 0; + + return msMSSQL2008LayerGetShapeRandom(layer, shape, &(layerinfo->row_num)); +} + +/* +** Returns the number of shapes that match the potential filter and extent. +* rectProjection is the projection in which rect is expressed, or can be NULL if +* rect should be considered in the layer projection. +* This should be equivalent to calling msLayerWhichShapes() and counting the +* number of shapes returned by msLayerNextShape(), honouring layer->maxfeatures +* limitation if layer->maxfeatures>=0, and honouring layer->startindex if +* layer->startindex >= 1 and paging is enabled. +* Returns -1 in case of failure. +*/ +int msMSSQL2008LayerGetShapeCount(layerObj *layer, rectObj rect, + projectionObj *rectProjection) { + msMSSQL2008LayerInfo *layerinfo; + char *query = 0; + char result_data[256]; + char box3d[40 + 10 * 22 + 11]; + SQLLEN retLen; + SQLRETURN rc; + int hasFilter = MS_FALSE; + const rectObj rectInvalid = MS_INIT_INVALID_RECT; + const int bIsValidRect = memcmp(&rect, &rectInvalid, sizeof(rect)) != 0; + + rectObj searchrectInLayerProj = rect; + + if (layer->debug) { + msDebug("msMSSQL2008LayerGetShapeCount called.\n"); + } + + layerinfo = getMSSQL2008LayerInfo(layer); + + if (!layerinfo) { + /* Layer not open */ + msSetError(MS_QUERYERR, + "msMSSQL2008LayerGetShapeCount called on unopened layer " + "(layerinfo = NULL)", + "msMSSQL2008LayerGetShapeCount()"); + + return MS_FAILURE; + } + + // Special processing if the specified projection for the rect is different + // from the layer projection We want to issue a WHERE that includes + // ((the_geom && rect_reprojected_in_layer_SRID) AND NOT + // ST_Disjoint(ST_Transform(the_geom, rect_SRID), rect)) + if (rectProjection != NULL && layer->project && + msProjectionsDiffer(&(layer->projection), rectProjection)) { + // If we cannot guess the EPSG code of the rectProjection, fallback on slow + // implementation + if (rectProjection->numargs < 1 || + strncasecmp(rectProjection->args[0], + "init=epsg:", (int)strlen("init=epsg:")) != 0) { + if (layer->debug) { + msDebug("msMSSQL2008LayerGetShapeCount(): cannot find EPSG code of " + "rectProjection. Falling back on client-side feature count.\n"); + } + return LayerDefaultGetShapeCount(layer, rect, rectProjection); + } + + // Reproject the passed rect into the layer projection and get + // the SRID from the rectProjection + msProjectRect( + rectProjection, &(layer->projection), + &searchrectInLayerProj); /* project the searchrect to source coords */ + } + + if (searchrectInLayerProj.minx == searchrectInLayerProj.maxx || + searchrectInLayerProj.miny == searchrectInLayerProj.maxy) { + /* create point shape for rectangles with zero area */ + snprintf(box3d, sizeof(box3d), + "%s::STGeomFromText('POINT(%.15g %.15g)',%s)", /* %s.STSrid)", */ + layerinfo->geom_column_type, searchrectInLayerProj.minx, + searchrectInLayerProj.miny, layerinfo->user_srid); + } else { + snprintf(box3d, sizeof(box3d), + "%s::STGeomFromText('POLYGON((%.15g %.15g,%.15g %.15g,%.15g " + "%.15g,%.15g %.15g,%.15g %.15g))',%s)", /* %s.STSrid)", */ + layerinfo->geom_column_type, searchrectInLayerProj.minx, + searchrectInLayerProj.miny, searchrectInLayerProj.maxx, + searchrectInLayerProj.miny, searchrectInLayerProj.maxx, + searchrectInLayerProj.maxy, searchrectInLayerProj.minx, + searchrectInLayerProj.maxy, searchrectInLayerProj.minx, + searchrectInLayerProj.miny, layerinfo->user_srid); + } + + msLayerTranslateFilter(layer, &layer->filter, layer->filteritem); + + /* set up statement */ + query = msStringConcatenate(query, "SELECT count(*) FROM "); + query = msStringConcatenate(query, layerinfo->geom_table); + + /* adding attribute filter */ + hasFilter = addFilter(layer, &query); + + if (bIsValidRect) { + /* adding spatial filter */ + if (hasFilter == MS_FALSE) + query = msStringConcatenate(query, " WHERE "); + else + query = msStringConcatenate(query, " AND "); + + query = msStringConcatenate(query, layerinfo->geom_column); + query = msStringConcatenate(query, ".STIntersects("); + query = msStringConcatenate(query, box3d); + query = msStringConcatenate(query, ") = 1 "); + } + + if (layer->debug) { + msDebug("query:%s\n", query); + } + + if (!executeSQL(layerinfo->conn, query)) { + msFree(query); + return -1; + } + + msFree(query); + + rc = SQLFetch(layerinfo->conn->hstmt); + + if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { + if (layer->debug) { + msDebug("msMSSQL2008LayerGetShapeCount: No results found.\n"); + } + + return -1; + } + + rc = SQLGetData(layerinfo->conn->hstmt, 1, SQL_C_CHAR, result_data, + sizeof(result_data), &retLen); + + if (rc == SQL_ERROR) { + msSetError(MS_QUERYERR, "Failed to get feature count", + "msMSSQL2008LayerGetShapeCount()"); + return -1; + } + + result_data[retLen] = 0; + + return atoi(result_data); +} + +/* Query the DB for info about the requested table */ +int msMSSQL2008LayerGetItems(layerObj *layer) { + msMSSQL2008LayerInfo *layerinfo; + char *sql = NULL; + size_t sqlSize; + char found_geom = 0; + int t, item_num; + SQLSMALLINT cols = 0; + const char *value; + /* + * Pass the field definitions through to the layer metadata in the + * "gml_[item]_{type,width,precision}" set of metadata items for + * defining fields. + */ + char pass_field_def = 0; + + if (layer->debug) { + msDebug("in msMSSQL2008LayerGetItems (find column names)\n"); + } + + layerinfo = getMSSQL2008LayerInfo(layer); + + if (!layerinfo) { + /* layer not opened yet */ + msSetError(MS_QUERYERR, "msMSSQL2008LayerGetItems called on unopened layer", + "msMSSQL2008LayerGetItems()"); + + return MS_FAILURE; + } + + if (!layerinfo->conn) { + msSetError(MS_QUERYERR, + "msMSSQL2008LayerGetItems called on MSSQL2008 layer with no " + "connection to DB.", + "msMSSQL2008LayerGetItems()"); + + return MS_FAILURE; + } + + sqlSize = strlen(layerinfo->geom_table) + 30; + sql = msSmallMalloc(sizeof(char *) * sqlSize); + + snprintf(sql, sqlSize, "SELECT top 0 * FROM %s", layerinfo->geom_table); + + if (!executeSQL(layerinfo->conn, sql)) { + msFree(sql); + return MS_FAILURE; + } + + SQLNumResultCols(layerinfo->conn->hstmt, &cols); + + layer->numitems = cols - 1; /* don't include the geometry column */ + + layer->items = msSmallMalloc( + sizeof(char *) * + (layer->numitems + + 1)); /* +1 in case there is a problem finding goeometry column */ + layerinfo->itemtypes = + msSmallMalloc(sizeof(SQLSMALLINT) * (layer->numitems + 1)); + /* it will return an error if there is no geometry column found, */ + /* so this isn't a problem */ + + found_geom = 0; /* haven't found the geom field */ + item_num = 0; + + /* consider populating the field definitions in metadata */ + if ((value = msOWSLookupMetadata(&(layer->metadata), "G", "types")) != NULL && + strcasecmp(value, "auto") == 0) + pass_field_def = 1; + + for (t = 0; t < cols; t++) { + char colBuff[256]; + SQLSMALLINT itemType = 0; + + columnName(layerinfo->conn, t + 1, colBuff, sizeof(colBuff), layer, + pass_field_def, &itemType); + + if (strcmp(colBuff, layerinfo->geom_column) != 0) { + /* this isn't the geometry column */ + layer->items[item_num] = (char *)msSmallMalloc(strlen(colBuff) + 1); + strcpy(layer->items[item_num], colBuff); + layerinfo->itemtypes[item_num] = itemType; + item_num++; + } else { + found_geom = 1; + } + } + + if (!found_geom) { + msFree(sql); + msSetError(MS_QUERYERR, + "msMSSQL2008LayerGetItems: tried to find the geometry column in " + "the results from the database, but couldn't find it. Is it " + "miss-capitialized? '%s'", + "msMSSQL2008LayerGetItems()", layerinfo->geom_column); + return MS_FAILURE; + } + + return msMSSQL2008LayerInitItemInfo(layer); +} + +/* Get primary key column of table */ +int msMSSQL2008LayerRetrievePK(layerObj *layer, char **urid_name, + char *table_name, int debug) { + + char sql[1024]; + msMSSQL2008LayerInfo *layerinfo = 0; + SQLRETURN rc; + + snprintf(sql, sizeof(sql), + "SELECT convert(varchar(50), sys.columns.name) AS ColumnName, " + "sys.indexes.name " + "FROM sys.columns INNER JOIN " + " sys.indexes INNER JOIN " + " sys.tables ON sys.indexes.object_id = " + "sys.tables.object_id INNER JOIN " + " sys.index_columns ON sys.indexes.object_id = " + "sys.index_columns.object_id AND sys.indexes.index_id = " + "sys.index_columns.index_id ON " + " sys.columns.object_id = " + "sys.index_columns.object_id AND sys.columns.column_id = " + "sys.index_columns.column_id " + "WHERE (sys.indexes.is_primary_key = 1) AND (sys.tables.name = " + "N'%s') ", + table_name); + + if (debug) { + msDebug("msMSSQL2008LayerRetrievePK: query = %s\n", sql); + } + + layerinfo = (msMSSQL2008LayerInfo *)layer->layerinfo; + + if (layerinfo->conn == NULL) { + + msSetError(MS_QUERYERR, "Layer does not have a MSSQL2008 connection.", + "msMSSQL2008LayerRetrievePK()"); + + return (MS_FAILURE); + } + + /* error somewhere above here in this method */ + + if (!executeSQL(layerinfo->conn, sql)) { + char *tmp1; + char *tmp2 = NULL; + + tmp1 = "Error executing MSSQL2008 statement (msMSSQL2008LayerRetrievePK():"; + tmp2 = + (char *)msSmallMalloc(sizeof(char) * (strlen(tmp1) + strlen(sql) + 1)); + strcpy(tmp2, tmp1); + strcat(tmp2, sql); + msSetError(MS_QUERYERR, "%s", "msMSSQL2008LayerRetrievePK()", tmp2); + msFree(tmp2); + return (MS_FAILURE); + } + + rc = SQLFetch(layerinfo->conn->hstmt); + + if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { + if (debug) { + msDebug("msMSSQL2008LayerRetrievePK: No results found.\n"); + } + + return MS_FAILURE; + } + + { + char buff[100]; + SQLLEN retLen; + rc = SQLGetData(layerinfo->conn->hstmt, 1, SQL_C_BINARY, buff, sizeof(buff), + &retLen); + + rc = SQLFetch(layerinfo->conn->hstmt); + + if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO) { + if (debug) { + msDebug("msMSSQL2008LayerRetrievePK: Multiple primary key columns are " + "not supported in MapServer\n"); + } + + return MS_FAILURE; + } + + buff[retLen] = 0; + + *urid_name = msStrdup(buff); + } + + return MS_SUCCESS; +} + +/* Function to parse the Mapserver DATA parameter for geometry + * column name, table name and name of a column to serve as a + * unique record id + */ +static int msMSSQL2008LayerParseData(layerObj *layer, char **geom_column_name, + char **geom_column_type, char **table_name, + char **urid_name, char **user_srid, + char **index_name, char **sort_spec, + int debug) { + char *pos_opt, *pos_scn, *tmp, *pos_srid, *pos_urid, *pos_geomtype, + *pos_geomtype2, *pos_indexHint, *data, *pos_order; + size_t slength; + + data = msStrdup(layer->data); + /* replace tabs with spaces */ + msReplaceChar(data, '\t', ' '); + + /* given a string of the from 'geom from ctivalues' or 'geom from () as foo' + * return geom_column_name as 'geom' + * and table name as 'ctivalues' or 'geom from () as foo' + */ + + /* First look for the optional ' using unique ID' string */ + pos_urid = strstrIgnoreCase(data, " using unique "); + + if (pos_urid) { + /* CHANGE - protect the trailing edge for thing like 'using unique ftab_id + * using srid=33' */ + tmp = strstr(pos_urid + 14, " "); + if (!tmp) { + tmp = pos_urid + strlen(pos_urid); + } + *urid_name = (char *)msSmallMalloc((tmp - (pos_urid + 14)) + 1); + strlcpy(*urid_name, pos_urid + 14, (tmp - (pos_urid + 14)) + 1); + } + + /* Find the srid */ + pos_srid = strstrIgnoreCase(data, " using SRID="); + if (!pos_srid) { + *user_srid = (char *)msSmallMalloc(2); + (*user_srid)[0] = '0'; + (*user_srid)[1] = 0; + } else { + slength = strspn(pos_srid + 12, "-0123456789"); + if (!slength) { + msSetError( + MS_QUERYERR, DATA_ERROR_MESSAGE, "msMSSQL2008LayerParseData()", + "Error parsing MSSQL2008 data variable: You specified 'using SRID=#' " + "but didn't have any numbers!

\n\nMore Help:

\n\n", + data); + + msFree(data); + return MS_FAILURE; + } else { + *user_srid = (char *)msSmallMalloc(slength + 1); + strlcpy(*user_srid, pos_srid + 12, slength + 1); + } + } + + pos_indexHint = strstrIgnoreCase(data, " using index "); + if (pos_indexHint) { + /* CHANGE - protect the trailing edge for thing like 'using unique ftab_id + * using srid=33' */ + tmp = strstr(pos_indexHint + 13, " "); + if (!tmp) { + tmp = pos_indexHint + strlen(pos_indexHint); + } + *index_name = (char *)msSmallMalloc((tmp - (pos_indexHint + 13)) + 1); + strlcpy(*index_name, pos_indexHint + 13, tmp - (pos_indexHint + 13) + 1); + } + + /* this is a little hack so the rest of the code works. If the ' using SRID=' + * comes before */ + /* the ' using unique ', then make sure pos_opt points to where the ' using + * SRID' starts! */ + pos_opt = pos_urid; + if (!pos_opt || (pos_srid && pos_srid < pos_opt)) + pos_opt = pos_srid; + if (!pos_opt || (pos_indexHint && pos_indexHint < pos_opt)) + pos_opt = pos_indexHint; + if (!pos_opt) + pos_opt = data + strlen(data); + + /* Scan for the table or sub-select clause */ + pos_scn = strstrIgnoreCase(data, " from "); + if (!pos_scn) { + msSetError(MS_QUERYERR, DATA_ERROR_MESSAGE, "msMSSQL2008LayerParseData()", + "Error parsing MSSQL2008 data variable. Must contain " + "'geometry_column from table_name' or 'geom from (subselect) as " + "foo' (couldn't find ' from '). More help:

\n\n", + data); + + msFree(data); + return MS_FAILURE; + } + + /* Scanning the geometry column type */ + pos_geomtype = data; + while (pos_geomtype < pos_scn && *pos_geomtype != '(' && *pos_geomtype != 0) + ++pos_geomtype; + + if (*pos_geomtype == '(') { + pos_geomtype2 = pos_geomtype; + while (pos_geomtype2 < pos_scn && *pos_geomtype2 != ')' && + *pos_geomtype2 != 0) + ++pos_geomtype2; + if (*pos_geomtype2 != ')' || pos_geomtype2 == pos_geomtype) { + msSetError(MS_QUERYERR, DATA_ERROR_MESSAGE, "msMSSQL2008LayerParseData()", + "Error parsing MSSQL2008 data variable. Invalid syntax near " + "geometry column type.", + data); + msFree(data); + return MS_FAILURE; + } + + *geom_column_name = (char *)msSmallMalloc((pos_geomtype - data) + 1); + strlcpy(*geom_column_name, data, pos_geomtype - data + 1); + + *geom_column_type = (char *)msSmallMalloc(pos_geomtype2 - pos_geomtype); + strlcpy(*geom_column_type, pos_geomtype + 1, pos_geomtype2 - pos_geomtype); + } else { + /* Copy the geometry column name */ + *geom_column_name = (char *)msSmallMalloc((pos_scn - data) + 1); + strlcpy(*geom_column_name, data, pos_scn - data + 1); + *geom_column_type = msStrdup("geometry"); + } + + /* Copy out the table name or sub-select clause */ + *table_name = (char *)msSmallMalloc((pos_opt - (pos_scn + 6)) + 1); + strlcpy(*table_name, pos_scn + 6, pos_opt - (pos_scn + 6) + 1); + + if (strlen(*table_name) < 1 || strlen(*geom_column_name) < 1) { + msSetError( + MS_QUERYERR, DATA_ERROR_MESSAGE, "msMSSQL2008LayerParseData()", + "Error parsing MSSQL2008 data variable. Must contain 'geometry_column " + "from table_name' or 'geom from (subselect) as foo' (couldn't find a " + "geometry_column or table/subselect). More help:

\n\n", + data); + + msFree(data); + return MS_FAILURE; + } + + if (!pos_urid) { + if (msMSSQL2008LayerRetrievePK(layer, urid_name, *table_name, debug) != + MS_SUCCESS) { + msSetError(MS_QUERYERR, DATA_ERROR_MESSAGE, "msMSSQL2008LayerParseData()", + "No primary key defined for table, or primary key contains " + "more that one column\n\n", + *table_name); + + msFree(data); + return MS_FAILURE; + } + } + + /* Find the order by */ + pos_order = strstrIgnoreCase(pos_opt, " order by "); + + if (pos_order) { + *sort_spec = msStrdup(pos_order); + } + + if (debug) { + msDebug("msMSSQL2008LayerParseData: unique column = %s, srid='%s', " + "geom_column_name = %s, table_name=%s\n", + *urid_name, *user_srid, *geom_column_name, *table_name); + } + + msFree(data); + return MS_SUCCESS; +} + +char *msMSSQL2008LayerEscapePropertyName(layerObj *layer, + const char *pszString) { + (void)layer; + char *pszEscapedStr = NULL; + int j = 0; + + if (pszString && strlen(pszString) > 0) { + size_t nLength = strlen(pszString); + + pszEscapedStr = (char *)msSmallMalloc(1 + nLength + 1 + 1); + pszEscapedStr[j++] = '['; + + for (size_t i = 0; i < nLength; i++) + pszEscapedStr[j++] = pszString[i]; + + pszEscapedStr[j++] = ']'; + pszEscapedStr[j++] = 0; + } + return pszEscapedStr; +} + +char *msMSSQL2008LayerEscapeSQLParam(layerObj *layer, const char *pszString) { + (void)layer; + char *pszEscapedStr = NULL; + if (pszString) { + int nSrcLen; + char c; + int i = 0, j = 0; + nSrcLen = (int)strlen(pszString); + pszEscapedStr = (char *)msSmallMalloc(2 * nSrcLen + 1); + for (i = 0, j = 0; i < nSrcLen; i++) { + c = pszString[i]; + if (c == '\'') { + pszEscapedStr[j++] = '\''; + pszEscapedStr[j++] = '\''; + } else + pszEscapedStr[j++] = c; + } + pszEscapedStr[j] = 0; + } + return pszEscapedStr; +} + +int msMSSQL2008GetPaging(layerObj *layer) { + msMSSQL2008LayerInfo *layerinfo = NULL; + + if (!msMSSQL2008LayerIsOpen(layer)) + return MS_TRUE; + + assert(layer->layerinfo != NULL); + layerinfo = (msMSSQL2008LayerInfo *)layer->layerinfo; + + return layerinfo->paging; +} + +void msMSSQL2008EnablePaging(layerObj *layer, int value) { + msMSSQL2008LayerInfo *layerinfo = NULL; + + if (!msMSSQL2008LayerIsOpen(layer)) { + if (msMSSQL2008LayerOpen(layer) != MS_SUCCESS) { + return; + } + } + + assert(layer->layerinfo != NULL); + layerinfo = (msMSSQL2008LayerInfo *)layer->layerinfo; + + layerinfo->paging = value; +} + +int process_node(layerObj *layer, expressionObj *filter) { + char *snippet = NULL; + char *strtmpl = NULL; + char *stresc = NULL; + msMSSQL2008LayerInfo *layerinfo = (msMSSQL2008LayerInfo *)layer->layerinfo; + + if (!layerinfo->current_node) { + msSetError(MS_MISCERR, "Unecpected end of expression", + "msMSSQL2008LayerTranslateFilter()"); + return 0; + } + + switch (layerinfo->current_node->token) { + case '(': + filter->native_string = msStringConcatenate(filter->native_string, "("); + /* process subexpression */ + layerinfo->current_node = layerinfo->current_node->next; + while (layerinfo->current_node != NULL) { + if (!process_node(layer, filter)) + return 0; + if (!layerinfo->current_node) + break; + if (layerinfo->current_node->token == ')') + break; + layerinfo->current_node = layerinfo->current_node->next; + } + break; + case ')': + filter->native_string = msStringConcatenate(filter->native_string, ")"); + break; + /* argument separator */ + case ',': + break; + /* literal tokens */ + case MS_TOKEN_LITERAL_BOOLEAN: + if (layerinfo->current_node->tokenval.dblval == MS_TRUE) + filter->native_string = msStringConcatenate(filter->native_string, "1"); + else + filter->native_string = msStringConcatenate(filter->native_string, "0"); + break; + case MS_TOKEN_LITERAL_NUMBER: { + char buffer[32]; + snprintf(buffer, sizeof(buffer), "%.18g", + layerinfo->current_node->tokenval.dblval); + filter->native_string = msStringConcatenate(filter->native_string, buffer); + break; + } + case MS_TOKEN_LITERAL_STRING: + strtmpl = "'%s'"; + stresc = msMSSQL2008LayerEscapeSQLParam( + layer, layerinfo->current_node->tokenval.strval); + snippet = (char *)msSmallMalloc(strlen(strtmpl) + strlen(stresc)); + sprintf(snippet, strtmpl, stresc); + filter->native_string = msStringConcatenate(filter->native_string, snippet); + msFree(snippet); + msFree(stresc); + break; + case MS_TOKEN_LITERAL_TIME: { + int resolution = msTimeGetResolution(layerinfo->current_node->tokensrc); + snippet = (char *)msSmallMalloc(128); + switch (resolution) { + case TIME_RESOLUTION_YEAR: + sprintf(snippet, "'%d'", + (layerinfo->current_node->tokenval.tmval.tm_year + 1900)); + break; + case TIME_RESOLUTION_MONTH: + sprintf(snippet, "'%d-%02d-01'", + (layerinfo->current_node->tokenval.tmval.tm_year + 1900), + (layerinfo->current_node->tokenval.tmval.tm_mon + 1)); + break; + case TIME_RESOLUTION_DAY: + sprintf(snippet, "'%d-%02d-%02d'", + (layerinfo->current_node->tokenval.tmval.tm_year + 1900), + (layerinfo->current_node->tokenval.tmval.tm_mon + 1), + layerinfo->current_node->tokenval.tmval.tm_mday); + break; + case TIME_RESOLUTION_HOUR: + sprintf(snippet, "'%d-%02d-%02d %02d:00'", + (layerinfo->current_node->tokenval.tmval.tm_year + 1900), + (layerinfo->current_node->tokenval.tmval.tm_mon + 1), + layerinfo->current_node->tokenval.tmval.tm_mday, + layerinfo->current_node->tokenval.tmval.tm_hour); + break; + case TIME_RESOLUTION_MINUTE: + sprintf(snippet, "%d-%02d-%02d %02d:%02d'", + (layerinfo->current_node->tokenval.tmval.tm_year + 1900), + (layerinfo->current_node->tokenval.tmval.tm_mon + 1), + layerinfo->current_node->tokenval.tmval.tm_mday, + layerinfo->current_node->tokenval.tmval.tm_hour, + layerinfo->current_node->tokenval.tmval.tm_min); + break; + case TIME_RESOLUTION_SECOND: + sprintf(snippet, "'%d-%02d-%02d %02d:%02d:%02d'", + (layerinfo->current_node->tokenval.tmval.tm_year + 1900), + (layerinfo->current_node->tokenval.tmval.tm_mon + 1), + layerinfo->current_node->tokenval.tmval.tm_mday, + layerinfo->current_node->tokenval.tmval.tm_hour, + layerinfo->current_node->tokenval.tmval.tm_min, + layerinfo->current_node->tokenval.tmval.tm_sec); + break; + } + filter->native_string = msStringConcatenate(filter->native_string, snippet); + msFree(snippet); + } break; + case MS_TOKEN_LITERAL_SHAPE: + if (strcasecmp(layerinfo->geom_column_type, "geography") == 0) + filter->native_string = msStringConcatenate( + filter->native_string, "geography::STGeomFromText('"); + else + filter->native_string = msStringConcatenate(filter->native_string, + "geometry::STGeomFromText('"); + filter->native_string = msStringConcatenate( + filter->native_string, + msShapeToWKT(layerinfo->current_node->tokenval.shpval)); + filter->native_string = msStringConcatenate(filter->native_string, "'"); + if (layerinfo->user_srid && strcmp(layerinfo->user_srid, "") != 0) { + filter->native_string = msStringConcatenate(filter->native_string, ", "); + filter->native_string = + msStringConcatenate(filter->native_string, layerinfo->user_srid); + } + filter->native_string = msStringConcatenate(filter->native_string, ")"); + break; + case MS_TOKEN_BINDING_TIME: + case MS_TOKEN_BINDING_DOUBLE: + case MS_TOKEN_BINDING_INTEGER: + case MS_TOKEN_BINDING_STRING: + if (layerinfo->current_node->next->token == MS_TOKEN_COMPARISON_IRE) + strtmpl = "LOWER(%s)"; + else + strtmpl = "%s"; + + stresc = msMSSQL2008LayerEscapePropertyName( + layer, layerinfo->current_node->tokenval.bindval.item); + snippet = (char *)msSmallMalloc(strlen(strtmpl) + strlen(stresc)); + sprintf(snippet, strtmpl, stresc); + filter->native_string = msStringConcatenate(filter->native_string, snippet); + msFree(snippet); + msFree(stresc); + break; + case MS_TOKEN_BINDING_SHAPE: + filter->native_string = + msStringConcatenate(filter->native_string, layerinfo->geom_column); + break; + case MS_TOKEN_BINDING_MAP_CELLSIZE: { + char buffer[32]; + snprintf(buffer, sizeof(buffer), "%.18g", layer->map->cellsize); + filter->native_string = msStringConcatenate(filter->native_string, buffer); + break; + } + + /* comparisons */ + case MS_TOKEN_COMPARISON_IN: + filter->native_string = msStringConcatenate(filter->native_string, " IN "); + break; + case MS_TOKEN_COMPARISON_RE: + case MS_TOKEN_COMPARISON_IRE: { + /* process regexp */ + size_t i = 0, j = 0; + char c; + char c_next; + int bCaseInsensitive = + (layerinfo->current_node->token == MS_TOKEN_COMPARISON_IRE); + int nEscapeLen = 0; + if (bCaseInsensitive) + filter->native_string = + msStringConcatenate(filter->native_string, " LIKE LOWER("); + else + filter->native_string = + msStringConcatenate(filter->native_string, " LIKE "); + + layerinfo->current_node = layerinfo->current_node->next; + if (layerinfo->current_node->token != MS_TOKEN_LITERAL_STRING) + return 0; + + strtmpl = msStrdup(layerinfo->current_node->tokenval.strval); + if (strtmpl[0] == '/') { + stresc = strtmpl + 1; + strtmpl[strlen(strtmpl) - 1] = '\0'; + } else if (strtmpl[0] == '^') + stresc = strtmpl + 1; + else + stresc = strtmpl; + + while (*stresc) { + c = stresc[i]; + if (c == '%' || c == '_' || c == '[' || c == ']' || c == '^') { + nEscapeLen++; + } + stresc++; + } + snippet = (char *)msSmallMalloc(strlen(strtmpl) + nEscapeLen + 3); + snippet[j++] = '\''; + while (i < strlen(strtmpl)) { + c = strtmpl[i]; + c_next = strtmpl[i + 1]; + + if (i == 0 && c == '^') { + i++; + continue; + } + if (c == '$' && c_next == 0 && strtmpl[0] == '^') + break; + + if (c == '\\') { + i++; + c = c_next; + } + + if (c == '%' || c == '_' || c == '[' || c == ']' || c == '^') { + snippet[j++] = '\\'; + } + + if (c == '.' && c_next == '*') { + i++; + c = '%'; + } else if (c == '.') + c = '_'; + + snippet[j++] = c; + i++; + } + snippet[j++] = '\''; + snippet[j] = '\0'; + + filter->native_string = msStringConcatenate(filter->native_string, snippet); + msFree(strtmpl); + msFree(snippet); + + if (bCaseInsensitive) + filter->native_string = msStringConcatenate(filter->native_string, ")"); + + if (nEscapeLen > 0) + filter->native_string = + msStringConcatenate(filter->native_string, " ESCAPE '\\'"); + } break; + case MS_TOKEN_COMPARISON_EQ: + filter->native_string = msStringConcatenate(filter->native_string, " = "); + break; + case MS_TOKEN_COMPARISON_NE: + filter->native_string = msStringConcatenate(filter->native_string, " != "); + break; + case MS_TOKEN_COMPARISON_GT: + filter->native_string = msStringConcatenate(filter->native_string, " > "); + break; + case MS_TOKEN_COMPARISON_GE: + filter->native_string = msStringConcatenate(filter->native_string, " >= "); + break; + case MS_TOKEN_COMPARISON_LT: + filter->native_string = msStringConcatenate(filter->native_string, " < "); + break; + case MS_TOKEN_COMPARISON_LE: + filter->native_string = msStringConcatenate(filter->native_string, " <= "); + break; + + /* logical ops */ + case MS_TOKEN_LOGICAL_AND: + filter->native_string = msStringConcatenate(filter->native_string, " AND "); + break; + case MS_TOKEN_LOGICAL_OR: + filter->native_string = msStringConcatenate(filter->native_string, " OR "); + break; + case MS_TOKEN_LOGICAL_NOT: + filter->native_string = msStringConcatenate(filter->native_string, " NOT "); + break; + + /* spatial comparison tokens */ + case MS_TOKEN_COMPARISON_INTERSECTS: + if (layerinfo->current_node->next) + layerinfo->current_node = layerinfo->current_node->next; + else + return 0; + if (layerinfo->current_node->next) + layerinfo->current_node = layerinfo->current_node->next; + else + return 0; + if (!process_node(layer, filter)) + return 0; + if (layerinfo->current_node->next) + layerinfo->current_node = layerinfo->current_node->next; + else + return 0; + if (layerinfo->current_node->next) + layerinfo->current_node = layerinfo->current_node->next; + else + return 0; + filter->native_string = + msStringConcatenate(filter->native_string, ".STIntersects("); + if (!process_node(layer, filter)) + return 0; + break; + + case MS_TOKEN_COMPARISON_DISJOINT: + if (layerinfo->current_node->next) + layerinfo->current_node = layerinfo->current_node->next; + else + return 0; + if (layerinfo->current_node->next) + layerinfo->current_node = layerinfo->current_node->next; + else + return 0; + if (!process_node(layer, filter)) + return 0; + if (layerinfo->current_node->next) + layerinfo->current_node = layerinfo->current_node->next; + else + return 0; + if (layerinfo->current_node->next) + layerinfo->current_node = layerinfo->current_node->next; + else + return 0; + filter->native_string = + msStringConcatenate(filter->native_string, ".STDisjoint("); + if (!process_node(layer, filter)) + return 0; + break; + + case MS_TOKEN_COMPARISON_TOUCHES: + if (layerinfo->current_node->next) + layerinfo->current_node = layerinfo->current_node->next; + else + return 0; + if (layerinfo->current_node->next) + layerinfo->current_node = layerinfo->current_node->next; + else + return 0; + if (!process_node(layer, filter)) + return 0; + if (layerinfo->current_node->next) + layerinfo->current_node = layerinfo->current_node->next; + else + return 0; + if (layerinfo->current_node->next) + layerinfo->current_node = layerinfo->current_node->next; + else + return 0; + filter->native_string = + msStringConcatenate(filter->native_string, ".STTouches("); + if (!process_node(layer, filter)) + return 0; + break; + + case MS_TOKEN_COMPARISON_OVERLAPS: + if (layerinfo->current_node->next) + layerinfo->current_node = layerinfo->current_node->next; + else + return 0; + if (layerinfo->current_node->next) + layerinfo->current_node = layerinfo->current_node->next; + else + return 0; + if (!process_node(layer, filter)) + return 0; + if (layerinfo->current_node->next) + layerinfo->current_node = layerinfo->current_node->next; + else + return 0; + if (layerinfo->current_node->next) + layerinfo->current_node = layerinfo->current_node->next; + else + return 0; + filter->native_string = + msStringConcatenate(filter->native_string, ".STOverlaps("); + if (!process_node(layer, filter)) + return 0; + break; + + case MS_TOKEN_COMPARISON_CROSSES: + if (layerinfo->current_node->next) + layerinfo->current_node = layerinfo->current_node->next; + else + return 0; + if (layerinfo->current_node->next) + layerinfo->current_node = layerinfo->current_node->next; + else + return 0; + if (!process_node(layer, filter)) + return 0; + if (layerinfo->current_node->next) + layerinfo->current_node = layerinfo->current_node->next; + else + return 0; + if (layerinfo->current_node->next) + layerinfo->current_node = layerinfo->current_node->next; + else + return 0; + filter->native_string = + msStringConcatenate(filter->native_string, ".STCrosses("); + if (!process_node(layer, filter)) + return 0; + break; + + case MS_TOKEN_COMPARISON_WITHIN: + if (layerinfo->current_node->next) + layerinfo->current_node = layerinfo->current_node->next; + else + return 0; + if (layerinfo->current_node->next) + layerinfo->current_node = layerinfo->current_node->next; + else + return 0; + if (!process_node(layer, filter)) + return 0; + if (layerinfo->current_node->next) + layerinfo->current_node = layerinfo->current_node->next; + else + return 0; + if (layerinfo->current_node->next) + layerinfo->current_node = layerinfo->current_node->next; + else + return 0; + filter->native_string = + msStringConcatenate(filter->native_string, ".STWithin("); + if (!process_node(layer, filter)) + return 0; + break; + + case MS_TOKEN_COMPARISON_CONTAINS: + if (layerinfo->current_node->next) + layerinfo->current_node = layerinfo->current_node->next; + else + return 0; + if (layerinfo->current_node->next) + layerinfo->current_node = layerinfo->current_node->next; + else + return 0; + if (!process_node(layer, filter)) + return 0; + if (layerinfo->current_node->next) + layerinfo->current_node = layerinfo->current_node->next; + else + return 0; + if (layerinfo->current_node->next) + layerinfo->current_node = layerinfo->current_node->next; + else + return 0; + filter->native_string = + msStringConcatenate(filter->native_string, ".STContains("); + if (!process_node(layer, filter)) + return 0; + break; + + case MS_TOKEN_COMPARISON_EQUALS: + if (layerinfo->current_node->next) + layerinfo->current_node = layerinfo->current_node->next; + else + return 0; + if (layerinfo->current_node->next) + layerinfo->current_node = layerinfo->current_node->next; + else + return 0; + if (!process_node(layer, filter)) + return 0; + if (layerinfo->current_node->next) + layerinfo->current_node = layerinfo->current_node->next; + else + return 0; + if (layerinfo->current_node->next) + layerinfo->current_node = layerinfo->current_node->next; + else + return 0; + filter->native_string = + msStringConcatenate(filter->native_string, ".STEquals("); + if (!process_node(layer, filter)) + return 0; + break; + + case MS_TOKEN_COMPARISON_BEYOND: + msSetError(MS_MISCERR, "Beyond operator is unsupported.", + "msMSSQL2008LayerTranslateFilter()"); + return 0; + + case MS_TOKEN_COMPARISON_DWITHIN: + msSetError(MS_MISCERR, "DWithin operator is unsupported.", + "msMSSQL2008LayerTranslateFilter()"); + return 0; + + /* spatial functions */ + case MS_TOKEN_FUNCTION_AREA: + if (layerinfo->current_node->next) + layerinfo->current_node = layerinfo->current_node->next; + else + return 0; + if (layerinfo->current_node->next) + layerinfo->current_node = layerinfo->current_node->next; + else + return 0; + if (!process_node(layer, filter)) + return 0; + filter->native_string = + msStringConcatenate(filter->native_string, ".STArea()"); + break; + + case MS_TOKEN_FUNCTION_BUFFER: + if (layerinfo->current_node->next) + layerinfo->current_node = layerinfo->current_node->next; + else + return 0; + if (layerinfo->current_node->next) + layerinfo->current_node = layerinfo->current_node->next; + else + return 0; + if (!process_node(layer, filter)) + return 0; + if (layerinfo->current_node->next) + layerinfo->current_node = layerinfo->current_node->next; + else + return 0; + if (layerinfo->current_node->next) + layerinfo->current_node = layerinfo->current_node->next; + else + return 0; + filter->native_string = + msStringConcatenate(filter->native_string, ".STBuffer("); + if (!process_node(layer, filter)) + return 0; + filter->native_string = msStringConcatenate(filter->native_string, ")"); + break; + + case MS_TOKEN_FUNCTION_DIFFERENCE: + if (layerinfo->current_node->next) + layerinfo->current_node = layerinfo->current_node->next; + else + return 0; + if (layerinfo->current_node->next) + layerinfo->current_node = layerinfo->current_node->next; + else + return 0; + if (!process_node(layer, filter)) + return 0; + if (layerinfo->current_node->next) + layerinfo->current_node = layerinfo->current_node->next; + else + return 0; + if (layerinfo->current_node->next) + layerinfo->current_node = layerinfo->current_node->next; + else + return 0; + filter->native_string = + msStringConcatenate(filter->native_string, ".STDifference("); + if (!process_node(layer, filter)) + return 0; + filter->native_string = msStringConcatenate(filter->native_string, ")"); + break; + + case MS_TOKEN_FUNCTION_FROMTEXT: + if (strcasecmp(layerinfo->geom_column_type, "geography") == 0) + filter->native_string = msStringConcatenate(filter->native_string, + "geography::STGeomFromText"); + else + filter->native_string = msStringConcatenate(filter->native_string, + "geometry::STGeomFromText"); + break; + + case MS_TOKEN_FUNCTION_LENGTH: + filter->native_string = msStringConcatenate(filter->native_string, "len"); + break; + + case MS_TOKEN_FUNCTION_ROUND: + filter->native_string = msStringConcatenate(filter->native_string, "round"); + break; + + case MS_TOKEN_FUNCTION_TOSTRING: + break; + + case MS_TOKEN_FUNCTION_COMMIFY: + break; + + case MS_TOKEN_FUNCTION_SIMPLIFY: + filter->native_string = + msStringConcatenate(filter->native_string, ".Reduce"); + break; + case MS_TOKEN_FUNCTION_SIMPLIFYPT: + break; + case MS_TOKEN_FUNCTION_GENERALIZE: + filter->native_string = + msStringConcatenate(filter->native_string, ".Reduce"); + break; + + default: + msSetError(MS_MISCERR, "Translation to native SQL failed.", + "msMSSQL2008LayerTranslateFilter()"); + if (layer->debug) { + msDebug("Token not caught, exiting: Token is %i\n", + layerinfo->current_node->token); + } + return 0; + } + return 1; +} + +/* Translate filter expression to native msssql filter */ +int msMSSQL2008LayerTranslateFilter(layerObj *layer, expressionObj *filter, + char *filteritem) { + char *snippet = NULL; + char *strtmpl = NULL; + char *stresc = NULL; + msMSSQL2008LayerInfo *layerinfo = (msMSSQL2008LayerInfo *)layer->layerinfo; + + if (!filter->string) + return MS_SUCCESS; + + msFree(filter->native_string); + filter->native_string = NULL; + + if (filter->type == MS_STRING && filter->string && + filteritem) { /* item/value pair */ + stresc = msMSSQL2008LayerEscapePropertyName(layer, filteritem); + if (filter->flags & MS_EXP_INSENSITIVE) { + filter->native_string = + msStringConcatenate(filter->native_string, "upper("); + filter->native_string = + msStringConcatenate(filter->native_string, stresc); + filter->native_string = + msStringConcatenate(filter->native_string, ") = upper("); + } else { + filter->native_string = + msStringConcatenate(filter->native_string, stresc); + filter->native_string = msStringConcatenate(filter->native_string, " = "); + } + msFree(stresc); + + strtmpl = "'%s'"; /* don't have a type for the righthand literal so assume + it's a string and we quote */ + snippet = (char *)msSmallMalloc(strlen(strtmpl) + strlen(filter->string)); + sprintf(snippet, strtmpl, filter->string); // TODO: escape filter->string + filter->native_string = msStringConcatenate(filter->native_string, snippet); + free(snippet); + + if (filter->flags & MS_EXP_INSENSITIVE) + filter->native_string = msStringConcatenate(filter->native_string, ")"); + + } else if (filter->type == MS_REGEX && filter->string && + filteritem) { /* item/regex pair */ + /* NOTE: regex is not supported by MSSQL natively. We should install it in + CLR UDF according to + https://msdn.microsoft.com/en-us/magazine/cc163473.aspx*/ + filter->native_string = + msStringConcatenate(filter->native_string, "dbo.RegexMatch("); + if (filter->flags & MS_EXP_INSENSITIVE) { + filter->native_string = + msStringConcatenate(filter->native_string, "'(?i)"); + } + filter->native_string = msStrdup(filteritem); + filter->native_string = msStringConcatenate(filter->native_string, ", "); + strtmpl = "'%s'"; + snippet = (char *)msSmallMalloc(strlen(strtmpl) + strlen(filter->string)); + sprintf(snippet, strtmpl, filter->string); // TODO: escape filter->string + filter->native_string = msStringConcatenate(filter->native_string, snippet); + + filter->native_string = msStringConcatenate(filter->native_string, "')"); + free(snippet); + } else if (filter->type == MS_EXPRESSION) { + + if (layer->debug >= 2) + msDebug("msMSSQL2008LayerTranslateFilter. String: %s.\n", filter->string); + + if (!filter->tokens) { + if (layer->debug >= 2) + msDebug("msMSSQL2008LayerTranslateFilter. There are tokens to " + "process... \n"); + return MS_SUCCESS; + } + + /* start processing nodes */ + layerinfo->current_node = filter->tokens; + while (layerinfo->current_node != NULL) { + if (!process_node(layer, filter)) { + msFree(filter->native_string); + filter->native_string = 0; + return MS_FAILURE; + } + + if (!layerinfo->current_node) + break; + + layerinfo->current_node = layerinfo->current_node->next; + } + } + + return MS_SUCCESS; +} + +#else + +/* prototypes if MSSQL2008 isn't supposed to be compiled */ + +int msMSSQL2008LayerOpen(layerObj *layer) { + msSetError(MS_QUERYERR, + "msMSSQL2008LayerOpen called but unimplemented! (mapserver not " + "compiled with MSSQL2008 support)", + "msMSSQL2008LayerOpen()"); + return MS_FAILURE; +} + +int msMSSQL2008LayerIsOpen(layerObj *layer) { + msSetError(MS_QUERYERR, + "msMSSQL2008IsLayerOpen called but unimplemented! (mapserver not " + "compiled with MSSQL2008 support)", + "msMSSQL2008LayerIsOpen()"); + return MS_FALSE; +} + +void msMSSQL2008LayerFreeItemInfo(layerObj *layer) { + msSetError(MS_QUERYERR, + "msMSSQL2008LayerFreeItemInfo called but unimplemented!(mapserver " + "not compiled with MSSQL2008 support)", + "msMSSQL2008LayerFreeItemInfo()"); +} + +int msMSSQL2008LayerInitItemInfo(layerObj *layer) { + msSetError(MS_QUERYERR, + "msMSSQL2008LayerInitItemInfo called but unimplemented!(mapserver " + "not compiled with MSSQL2008 support)", + "msMSSQL2008LayerInitItemInfo()"); + return MS_FAILURE; +} + +int msMSSQL2008LayerWhichShapes(layerObj *layer, rectObj rect, int isQuery) { + msSetError(MS_QUERYERR, + "msMSSQL2008LayerWhichShapes called but unimplemented!(mapserver " + "not compiled with MSSQL2008 support)", + "msMSSQL2008LayerWhichShapes()"); + return MS_FAILURE; +} + +int msMSSQL2008LayerClose(layerObj *layer) { + msSetError(MS_QUERYERR, + "msMSSQL2008LayerClose called but unimplemented!(mapserver not " + "compiled with MSSQL2008 support)", + "msMSSQL2008LayerClose()"); + return MS_FAILURE; +} + +int msMSSQL2008LayerNextShape(layerObj *layer, shapeObj *shape) { + msSetError(MS_QUERYERR, + "msMSSQL2008LayerNextShape called but unimplemented!(mapserver " + "not compiled with MSSQL2008 support)", + "msMSSQL2008LayerNextShape()"); + return MS_FAILURE; +} + +int msMSSQL2008LayerGetShape(layerObj *layer, shapeObj *shape, long record) { + msSetError(MS_QUERYERR, + "msMSSQL2008LayerGetShape called but unimplemented!(mapserver not " + "compiled with MSSQL2008 support)", + "msMSSQL2008LayerGetShape()"); + return MS_FAILURE; +} + +int msMSSQL2008LayerGetShapeCount(layerObj *layer, rectObj rect, + projectionObj *rectProjection) { + msSetError(MS_QUERYERR, + "msMSSQL2008LayerGetShapeCount called but " + "unimplemented!(mapserver not compiled with MSSQL2008 support)", + "msMSSQL2008LayerGetShapeCount()"); + return MS_FAILURE; +} + +int msMSSQL2008LayerGetExtent(layerObj *layer, rectObj *extent) { + msSetError(MS_QUERYERR, + "msMSSQL2008LayerGetExtent called but unimplemented!(mapserver " + "not compiled with MSSQL2008 support)", + "msMSSQL2008LayerGetExtent()"); + return MS_FAILURE; +} + +int msMSSQL2008LayerGetNumFeatures(layerObj *layer) { + msSetError(MS_QUERYERR, + "msMSSQL2008LayerGetNumFeatures called but " + "unimplemented!(mapserver not compiled with MSSQL2008 support)", + "msMSSQL2008LayerGetNumFeatures()"); + return -1; +} + +int msMSSQL2008LayerGetShapeRandom(layerObj *layer, shapeObj *shape, + long *record) { + msSetError(MS_QUERYERR, + "msMSSQL2008LayerGetShapeRandom called but " + "unimplemented!(mapserver not compiled with MSSQL2008 support)", + "msMSSQL2008LayerGetShapeRandom()"); + return MS_FAILURE; +} + +int msMSSQL2008LayerGetItems(layerObj *layer) { + msSetError(MS_QUERYERR, + "msMSSQL2008LayerGetItems called but unimplemented!(mapserver not " + "compiled with MSSQL2008 support)", + "msMSSQL2008LayerGetItems()"); + return MS_FAILURE; +} + +void msMSSQL2008EnablePaging(layerObj *layer, int value) { + msSetError(MS_QUERYERR, + "msMSSQL2008EnablePaging called but unimplemented!(mapserver not " + "compiled with MSSQL2008 support)", + "msMSSQL2008EnablePaging()"); + return; +} + +int msMSSQL2008GetPaging(layerObj *layer) { + msSetError(MS_QUERYERR, + "msMSSQL2008GetPaging called but unimplemented!(mapserver not " + "compiled with MSSQL2008 support)", + "msMSSQL2008GetPaging()"); + return MS_FAILURE; +} + +int msMSSQL2008LayerTranslateFilter(layerObj *layer, expressionObj *filter, + char *filteritem) { + msSetError(MS_QUERYERR, + "msMSSQL2008LayerTranslateFilter called but " + "unimplemented!(mapserver not compiled with MSSQL2008 support)", + "msMSSQL2008LayerTranslateFilter()"); + return MS_FAILURE; +} + +char *msMSSQL2008LayerEscapeSQLParam(layerObj *layer, const char *pszString) { + msSetError(MS_QUERYERR, + "msMSSQL2008EscapeSQLParam called but unimplemented!(mapserver " + "not compiled with MSSQL2008 support)", + "msMSSQL2008LayerEscapeSQLParam()"); + return NULL; +} + +char *msMSSQL2008LayerEscapePropertyName(layerObj *layer, + const char *pszString) { + msSetError(MS_QUERYERR, + "msMSSQL2008LayerEscapePropertyName called but " + "unimplemented!(mapserver not compiled with MSSQL2008 support)", + "msMSSQL2008LayerEscapePropertyName()"); + return NULL; +} + +/* end above's #ifdef USE_MSSQL2008 */ +#endif + +#ifdef USE_MSSQL2008_PLUGIN + +MS_DLL_EXPORT int PluginInitializeVirtualTable(layerVTableObj *vtable, + layerObj *layer) { + assert(layer != NULL); + assert(vtable != NULL); + + vtable->LayerEnablePaging = msMSSQL2008EnablePaging; + vtable->LayerGetPaging = msMSSQL2008GetPaging; + vtable->LayerTranslateFilter = msMSSQL2008LayerTranslateFilter; + vtable->LayerEscapeSQLParam = msMSSQL2008LayerEscapeSQLParam; + vtable->LayerEscapePropertyName = msMSSQL2008LayerEscapePropertyName; + + vtable->LayerInitItemInfo = msMSSQL2008LayerInitItemInfo; + vtable->LayerFreeItemInfo = msMSSQL2008LayerFreeItemInfo; + vtable->LayerOpen = msMSSQL2008LayerOpen; + vtable->LayerIsOpen = msMSSQL2008LayerIsOpen; + vtable->LayerWhichShapes = msMSSQL2008LayerWhichShapes; + vtable->LayerNextShape = msMSSQL2008LayerNextShape; + vtable->LayerGetShape = msMSSQL2008LayerGetShape; + vtable->LayerGetShapeCount = msMSSQL2008LayerGetShapeCount; + + vtable->LayerClose = msMSSQL2008LayerClose; + + vtable->LayerGetItems = msMSSQL2008LayerGetItems; + vtable->LayerGetExtent = msMSSQL2008LayerGetExtent; + + /* vtable->LayerApplyFilterToLayer, use default */ + + /* vtable->LayerGetAutoStyle, not supported for this layer */ + vtable->LayerCloseConnection = msMSSQL2008LayerClose; + + vtable->LayerSetTimeFilter = msLayerMakeBackticsTimeFilter; + /* vtable->LayerCreateItems, use default */ + vtable->LayerGetNumFeatures = msMSSQL2008LayerGetNumFeatures; + /* layer->vtable->LayerGetAutoProjection, use default*/ + + return MS_SUCCESS; +} + +#endif + +int msMSSQL2008LayerInitializeVirtualTable(layerObj *layer) { + assert(layer != NULL); + assert(layer->vtable != NULL); + + layer->vtable->LayerEnablePaging = msMSSQL2008EnablePaging; + layer->vtable->LayerGetPaging = msMSSQL2008GetPaging; + layer->vtable->LayerTranslateFilter = msMSSQL2008LayerTranslateFilter; + layer->vtable->LayerEscapeSQLParam = msMSSQL2008LayerEscapeSQLParam; + layer->vtable->LayerEscapePropertyName = msMSSQL2008LayerEscapePropertyName; + + layer->vtable->LayerInitItemInfo = msMSSQL2008LayerInitItemInfo; + layer->vtable->LayerFreeItemInfo = msMSSQL2008LayerFreeItemInfo; + layer->vtable->LayerOpen = msMSSQL2008LayerOpen; + layer->vtable->LayerIsOpen = msMSSQL2008LayerIsOpen; + layer->vtable->LayerWhichShapes = msMSSQL2008LayerWhichShapes; + layer->vtable->LayerNextShape = msMSSQL2008LayerNextShape; + layer->vtable->LayerGetShape = msMSSQL2008LayerGetShape; + layer->vtable->LayerGetShapeCount = msMSSQL2008LayerGetShapeCount; + + layer->vtable->LayerClose = msMSSQL2008LayerClose; + + layer->vtable->LayerGetItems = msMSSQL2008LayerGetItems; + layer->vtable->LayerGetExtent = msMSSQL2008LayerGetExtent; + + /* layer->vtable->LayerApplyFilterToLayer, use default */ + + /* layer->vtable->LayerGetAutoStyle, not supported for this layer */ + layer->vtable->LayerCloseConnection = msMSSQL2008LayerClose; + + layer->vtable->LayerSetTimeFilter = msLayerMakeBackticsTimeFilter; + /* layer->vtable->LayerCreateItems, use default */ + layer->vtable->LayerGetNumFeatures = msMSSQL2008LayerGetNumFeatures; + + return MS_SUCCESS; +} diff --git a/src/mapmvt.c b/src/mapmvt.c new file mode 100644 index 0000000000..1607a59935 --- /dev/null +++ b/src/mapmvt.c @@ -0,0 +1,679 @@ +/****************************************************************************** + * $Id$ + * + * Project: MapServer + * Purpose: MapBox Vector Tile rendering. + * Author: Thomas Bonfort and the MapServer team. + * + ****************************************************************************** + * Copyright (c) 1996-2015 Regents of the University of Minnesota. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + *****************************************************************************/ + +#include "mapserver.h" +#include "maptile.h" + +#ifdef USE_PBF +#include "vector_tile.pb-c.h" +#include "mapows.h" +#include "uthash.h" +#include + +#define MOVETO 1 +#define LINETO 2 +#define CLOSEPATH 7 + +#define FEATURES_INCREMENT_SIZE 5 + +enum MS_RING_DIRECTION { + MS_DIRECTION_INVALID_RING, + MS_DIRECTION_CLOCKWISE, + MS_DIRECTION_COUNTERCLOCKWISE +}; + +typedef struct { + char *value; + unsigned int index; + UT_hash_handle hh; +} value_lookup; + +typedef struct { + value_lookup *cache; +} value_lookup_table; + +#define COMMAND(id, count) (((id)&0x7) | ((count) << 3)) +#define PARAMETER(n) (((n) << 1) ^ ((n) >> 31)) + +static double getTriangleHeight(lineObj *ring) { + int i; + double s = 0, b = 0; + + if (ring->numpoints != 4) + return -1; /* not a triangle */ + + for (i = 0; i < ring->numpoints - 1; i++) { + s += (ring->point[i].x * ring->point[i + 1].y - + ring->point[i + 1].x * ring->point[i].y); + b = MS_MAX(b, msDistancePointToPoint(&ring->point[i], &ring->point[i + 1])); + } + + return (MS_ABS(s / b)); +} + +static enum MS_RING_DIRECTION mvtGetRingDirection(lineObj *ring) { + int i, sum = 0; + + if (ring->numpoints < 4) + return MS_DIRECTION_INVALID_RING; + + /* step through the edges */ + for (i = 0; i < ring->numpoints - 1; i++) { + sum += ring->point[i].x * ring->point[i + 1].y - + ring->point[i + 1].x * ring->point[i].y; + } + + return sum > 0 ? MS_DIRECTION_CLOCKWISE + : sum < 0 ? MS_DIRECTION_COUNTERCLOCKWISE + : MS_DIRECTION_INVALID_RING; +} + +static void mvtReverseRingDirection(lineObj *ring) { + pointObj temp; + int start = 1, end = ring->numpoints - + 2; /* first and last points are the same so skip 'em */ + + while (start < end) { + temp.x = ring->point[start].x; + temp.y = ring->point[start].y; + ring->point[start].x = ring->point[end].x; + ring->point[start].y = ring->point[end].y; + ring->point[end].x = temp.x; + ring->point[end].y = temp.y; + start++; + end--; + } +} + +static void mvtReorderRings(shapeObj *shape, int *outers) { + int i, j; + int t1; + lineObj t2; + + for (i = 0; i < (shape->numlines - 1); i++) { + for (j = 0; j < (shape->numlines - i - 1); j++) { + if (outers[j] < outers[j + 1]) { + /* swap */ + t1 = outers[j]; + outers[j] = outers[j + 1]; + outers[j + 1] = t1; + + t2 = shape->line[j]; + shape->line[j] = shape->line[j + 1]; + shape->line[j + 1] = t2; + } + } + } +} + +static int mvtTransformShape(shapeObj *shape, rectObj *extent, int layer_type, + int mvt_layer_extent) { + double scale_x, scale_y; + int i, j, outj; + + int *outers = NULL, ring_direction; + + scale_x = (double)mvt_layer_extent / (extent->maxx - extent->minx); + scale_y = (double)mvt_layer_extent / (extent->maxy - extent->miny); + + if (layer_type == MS_LAYER_POLYGON) { + outers = msGetOuterList(shape); /* compute before we muck with the shape */ + if (outers[0] == 0) /* first ring must be an outer */ + mvtReorderRings(shape, outers); + } + + for (i = 0; i < shape->numlines; i++) { + for (j = 0, outj = 0; j < shape->line[i].numpoints; j++) { + + shape->line[i].point[outj].x = + (int)((shape->line[i].point[j].x - extent->minx) * scale_x); + shape->line[i].point[outj].y = + mvt_layer_extent - + (int)((shape->line[i].point[j].y - extent->miny) * scale_y); + + if (!outj || + shape->line[i].point[outj].x != shape->line[i].point[outj - 1].x || + shape->line[i].point[outj].y != shape->line[i].point[outj - 1].y) + outj++; /* add the point to the shape only if it's the first one or if + it's different than the previous one */ + } + shape->line[i].numpoints = outj; + + if (layer_type == MS_LAYER_POLYGON) { + if (shape->line[i].numpoints == 4 && + getTriangleHeight(&shape->line[i]) < 1) { + shape->line[i].numpoints = 0; /* so it's not considered anymore */ + continue; /* next ring */ + } + + ring_direction = mvtGetRingDirection(&shape->line[i]); + if (ring_direction == MS_DIRECTION_INVALID_RING) + shape->line[i].numpoints = 0; /* so it's not considered anymore */ + else if ((outers[i] && ring_direction != MS_DIRECTION_CLOCKWISE) || + (!outers[i] && ring_direction != MS_DIRECTION_COUNTERCLOCKWISE)) + mvtReverseRingDirection(&shape->line[i]); + } + } + + msComputeBounds( + shape); /* TODO: might need to limit this to just valid parts... */ + msFree(outers); + + return (shape->numlines == 0) ? MS_FAILURE + : MS_SUCCESS; /* success if at least one line */ +} + +static int mvtClipShape(shapeObj *shape, int layer_type, int buffer, + int mvt_layer_extent) { + rectObj tile_rect; + tile_rect.minx = tile_rect.miny = -buffer * 16; + tile_rect.maxx = tile_rect.maxy = mvt_layer_extent + buffer * 16; + + if (layer_type == MS_LAYER_POLYGON) { + msClipPolygonRect(shape, tile_rect); + } else if (layer_type == MS_LAYER_LINE) { + msClipPolylineRect(shape, tile_rect); + } + + /* success if at least one line and not a degenerate bounding box */ + if (shape->numlines > 0 && (layer_type == MS_LAYER_POINT || + (shape->bounds.minx != shape->bounds.maxx || + shape->bounds.miny != shape->bounds.maxy))) + return MS_SUCCESS; + else + return MS_FAILURE; +} + +static void freeMvtFeature(VectorTile__Tile__Feature *mvt_feature) { + if (mvt_feature->tags) + msFree(mvt_feature->tags); + if (mvt_feature->geometry) + msFree(mvt_feature->geometry); +} + +static void freeMvtValue(VectorTile__Tile__Value *mvt_value) { + if (mvt_value->string_value) + msFree(mvt_value->string_value); +} + +static void freeMvtLayer(VectorTile__Tile__Layer *mvt_layer) { + if (mvt_layer->keys) { + for (unsigned i = 0; i < mvt_layer->n_keys; i++) { + msFree(mvt_layer->keys[i]); + } + msFree(mvt_layer->keys); + } + if (mvt_layer->values) { + for (unsigned i = 0; i < mvt_layer->n_values; i++) { + freeMvtValue(mvt_layer->values[i]); + msFree(mvt_layer->values[i]); + } + msFree(mvt_layer->values); + } + if (mvt_layer->features) { + for (unsigned i = 0; i < mvt_layer->n_features; i++) { + freeMvtFeature(mvt_layer->features[i]); + msFree(mvt_layer->features[i]); + } + msFree(mvt_layer->features); + } +} + +int mvtWriteShape(layerObj *layer, shapeObj *shape, + VectorTile__Tile__Layer *mvt_layer, gmlItemListObj *item_list, + value_lookup_table *value_lookup_cache, + rectObj *unbuffered_bbox, int buffer) { + VectorTile__Tile__Feature *mvt_feature; + int i, j, iout; + value_lookup *value; + long int n_geometry; + + /* could consider an intersection test here */ + + if (mvtTransformShape(shape, unbuffered_bbox, layer->type, + mvt_layer->extent) != MS_SUCCESS) { + return MS_SUCCESS; /* degenerate shape */ + } + if (mvtClipShape(shape, layer->type, buffer, mvt_layer->extent) != + MS_SUCCESS) { + return MS_SUCCESS; /* no features left after clipping */ + } + + n_geometry = 0; + if (layer->type == MS_LAYER_POINT) { + for (i = 0; i < shape->numlines; i++) + n_geometry += shape->line[i].numpoints * 2; + if (n_geometry) + n_geometry++; /* one MOVETO */ + } else if (layer->type == MS_LAYER_LINE) { + for (i = 0; i < shape->numlines; i++) + if (shape->line[i].numpoints >= 2) + n_geometry += + 2 + shape->line[i].numpoints * 2; /* one MOVETO, one LINETO */ + } else { /* MS_LAYER_POLYGON */ + for (i = 0; i < shape->numlines; i++) + if (shape->line[i].numpoints >= 4) + n_geometry += 3 + (shape->line[i].numpoints - 1) * + 2; /* one MOVETO, one LINETO, one CLOSEPATH (don't + consider last duplicate point) */ + } + + if (n_geometry == 0) + return MS_SUCCESS; + + mvt_layer->features[mvt_layer->n_features++] = + msSmallMalloc(sizeof(VectorTile__Tile__Feature)); + mvt_feature = mvt_layer->features[mvt_layer->n_features - 1]; + vector_tile__tile__feature__init(mvt_feature); + mvt_feature->n_tags = mvt_layer->n_keys * 2; + mvt_feature->tags = msSmallMalloc(mvt_feature->n_tags * sizeof(uint32_t)); + mvt_feature->id = shape->index; + mvt_feature->has_id = 1; + + if (layer->type == MS_LAYER_POLYGON) + mvt_feature->type = VECTOR_TILE__TILE__GEOM_TYPE__POLYGON; + else if (layer->type == MS_LAYER_LINE) + mvt_feature->type = VECTOR_TILE__TILE__GEOM_TYPE__LINESTRING; + else + mvt_feature->type = VECTOR_TILE__TILE__GEOM_TYPE__POINT; + mvt_feature->has_type = 1; + + /* output values */ + for (i = 0, iout = 0; i < item_list->numitems; i++) { + gmlItemObj *item = item_list->items + i; + + if (!item->visible) + continue; + + UT_HASH_FIND_STR(value_lookup_cache->cache, shape->values[i], value); + if (!value) { + VectorTile__Tile__Value *mvt_value; + value = msSmallMalloc(sizeof(value_lookup)); + value->value = msStrdup(shape->values[i]); + value->index = mvt_layer->n_values; + mvt_layer->values = msSmallRealloc(mvt_layer->values, + (++mvt_layer->n_values) * + sizeof(VectorTile__Tile__Value *)); + mvt_layer->values[mvt_layer->n_values - 1] = + msSmallMalloc(sizeof(VectorTile__Tile__Value)); + mvt_value = mvt_layer->values[mvt_layer->n_values - 1]; + vector_tile__tile__value__init(mvt_value); + + if (item->type && EQUAL(item->type, "Integer")) { + mvt_value->int_value = atoi(value->value); + mvt_value->has_int_value = 1; + } else if (item->type && EQUAL(item->type, "Long")) { /* signed */ + mvt_value->sint_value = atol(value->value); + mvt_value->has_sint_value = 1; + } else if (item->type && EQUAL(item->type, "Real")) { + mvt_value->float_value = atof(value->value); + mvt_value->has_float_value = 1; + } else if (item->type && EQUAL(item->type, "Boolean")) { + if (EQUAL(value->value, "0") || EQUAL(value->value, "false")) + mvt_value->bool_value = 0; + else + mvt_value->bool_value = 1; + mvt_value->has_bool_value = 1; + } else { + mvt_value->string_value = msStrdup(value->value); + } + UT_HASH_ADD_KEYPTR(hh, value_lookup_cache->cache, value->value, + strlen(value->value), value); + } + mvt_feature->tags[iout * 2] = iout; + mvt_feature->tags[iout * 2 + 1] = value->index; + + iout++; + } + + /* output geom */ + mvt_feature->n_geometry = n_geometry; + mvt_feature->geometry = + msSmallMalloc(mvt_feature->n_geometry * sizeof(uint32_t)); + + if (layer->type == MS_LAYER_POINT) { + int idx = 0, lastx = 0, lasty = 0; + mvt_feature->geometry[idx++] = + COMMAND(MOVETO, (mvt_feature->n_geometry - 1) / 2); + for (i = 0; i < shape->numlines; i++) { + for (j = 0; j < shape->line[i].numpoints; j++) { + mvt_feature->geometry[idx++] = + PARAMETER(MS_NINT(shape->line[i].point[j].x) - lastx); + mvt_feature->geometry[idx++] = + PARAMETER(MS_NINT(shape->line[i].point[j].y) - lasty); + lastx = MS_NINT(shape->line[i].point[j].x); + lasty = MS_NINT(shape->line[i].point[j].y); + } + } + } else { /* MS_LAYER_LINE or MS_LAYER_POLYGON */ + int numpoints; + int idx = 0, lastx = 0, lasty = 0; + for (i = 0; i < shape->numlines; i++) { + + if ((layer->type == MS_LAYER_LINE && !(shape->line[i].numpoints >= 2)) || + (layer->type == MS_LAYER_POLYGON && + !(shape->line[i].numpoints >= 4))) { + continue; /* skip malformed parts */ + } + + numpoints = (layer->type == MS_LAYER_LINE) + ? shape->line[i].numpoints + : (shape->line[i].numpoints - + 1); /* don't consider last point for polygons */ + for (j = 0; j < numpoints; j++) { + if (j == 0) { + mvt_feature->geometry[idx++] = COMMAND(MOVETO, 1); + } else if (j == 1) { + mvt_feature->geometry[idx++] = COMMAND(LINETO, numpoints - 1); + } + mvt_feature->geometry[idx++] = + PARAMETER(MS_NINT(shape->line[i].point[j].x) - lastx); + mvt_feature->geometry[idx++] = + PARAMETER(MS_NINT(shape->line[i].point[j].y) - lasty); + lastx = MS_NINT(shape->line[i].point[j].x); + lasty = MS_NINT(shape->line[i].point[j].y); + } + if (layer->type == MS_LAYER_POLYGON) { + mvt_feature->geometry[idx++] = COMMAND(CLOSEPATH, 1); + } + } + } + + return MS_SUCCESS; +} + +static void freeMvtTile(VectorTile__Tile *mvt_tile) { + for (unsigned iLayer = 0; iLayer < mvt_tile->n_layers; iLayer++) { + freeMvtLayer(mvt_tile->layers[iLayer]); + msFree(mvt_tile->layers[iLayer]); + } + msFree(mvt_tile->layers); +} + +int msMVTWriteTile(mapObj *map, int sendheaders) { + int iLayer, retcode = MS_SUCCESS; + unsigned len; + void *buf; + const char *mvt_extent = + msGetOutputFormatOption(map->outputformat, "EXTENT", "4096"); + const char *mvt_buffer = + msGetOutputFormatOption(map->outputformat, "EDGE_BUFFER", "10"); + int buffer = MS_ABS(atoi(mvt_buffer)); + VectorTile__Tile mvt_tile = VECTOR_TILE__TILE__INIT; + mvt_tile.layers = + msSmallCalloc(map->numlayers, sizeof(VectorTile__Tile__Layer *)); + + /* make sure we have a scale and cellsize computed */ + map->cellsize = MS_CELLSIZE(map->extent.minx, map->extent.maxx, map->width); + msCalculateScale(map->extent, map->units, map->width, map->height, + map->resolution, &map->scaledenom); + + /* expand the map->extent so it goes from pixel center (MapServer) to pixel + * edge (OWS) */ + map->extent.minx -= map->cellsize * 0.5; + map->extent.maxx += map->cellsize * 0.5; + map->extent.miny -= map->cellsize * 0.5; + map->extent.maxy += map->cellsize * 0.5; + + for (iLayer = 0; iLayer < map->numlayers; iLayer++) { + int status = MS_SUCCESS; + layerObj *layer = GET_LAYER(map, iLayer); + int i; + shapeObj shape; + gmlItemListObj *item_list = NULL; + VectorTile__Tile__Layer *mvt_layer; + value_lookup_table value_lookup_cache = {NULL}; + value_lookup *cur_value_lookup, *tmp_value_lookup; + rectObj rect; + + int nclasses = 0; + int *classgroup = NULL; + + unsigned features_size = 0; + + if (!msLayerIsVisible(map, layer)) + continue; + + if (layer->type != MS_LAYER_POINT && layer->type != MS_LAYER_POLYGON && + layer->type != MS_LAYER_LINE) + continue; + + status = msLayerOpen(layer); + if (status != MS_SUCCESS) { + retcode = status; + goto layer_cleanup; + } + + status = msLayerWhichItems( + layer, MS_TRUE, + NULL); /* we want all items - behaves like a query in that sense */ + if (status != MS_SUCCESS) { + retcode = status; + goto layer_cleanup; + } + + /* -------------------------------------------------------------------- */ + /* Will we need to reproject? */ + /* -------------------------------------------------------------------- */ + layer->project = + msProjectionsDiffer(&(layer->projection), &(map->projection)); + + rect = map->extent; + if (layer->project) + msProjectRect(&(map->projection), &(layer->projection), &rect); + + status = msLayerWhichShapes(layer, rect, MS_TRUE); + if (status == MS_DONE) { /* no overlap - that's ok */ + retcode = MS_SUCCESS; + goto layer_cleanup; + } else if (status != MS_SUCCESS) { + retcode = status; + goto layer_cleanup; + } + + mvt_tile.layers[mvt_tile.n_layers++] = + msSmallMalloc(sizeof(VectorTile__Tile__Layer)); + mvt_layer = mvt_tile.layers[mvt_tile.n_layers - 1]; + vector_tile__tile__layer__init(mvt_layer); + mvt_layer->version = 2; + mvt_layer->name = layer->name; + + mvt_layer->extent = MS_ABS(atoi(mvt_extent)); + mvt_layer->has_extent = 1; + + /* -------------------------------------------------------------------- */ + /* Create appropriate attributes on this layer. */ + /* -------------------------------------------------------------------- */ + item_list = msGMLGetItems(layer, "G"); + assert(item_list->numitems == layer->numitems); + + mvt_layer->keys = msSmallMalloc(layer->numitems * sizeof(char *)); + + for (i = 0; i < layer->numitems; i++) { + gmlItemObj *item = item_list->items + i; + + if (!item->visible) + continue; + + if (item->alias) + mvt_layer->keys[mvt_layer->n_keys++] = msStrdup(item->alias); + else + mvt_layer->keys[mvt_layer->n_keys++] = msStrdup(item->name); + } + + /* -------------------------------------------------------------------- */ + /* Setup joins if needed. This is likely untested. */ + /* -------------------------------------------------------------------- */ + if (layer->numjoins > 0) { + int j; + for (j = 0; j < layer->numjoins; j++) { + status = msJoinConnect(layer, &(layer->joins[j])); + if (status != MS_SUCCESS) { + retcode = status; + goto layer_cleanup; + } + } + } + + /* -------------------------------------------------------------------- */ + /* Setup classgroup if needed. */ + /* -------------------------------------------------------------------- */ + if (layer->classgroup && layer->numclasses > 0) + classgroup = msAllocateValidClassGroups(layer, &nclasses); + + mvt_layer->features = msSmallCalloc(FEATURES_INCREMENT_SIZE, + sizeof(VectorTile__Tile__Feature *)); + features_size = FEATURES_INCREMENT_SIZE; + + msInitShape(&shape); + i = 0; + for (;;) { + if (layer->resultcache) { + status = (i < layer->resultcache->numresults) + ? msLayerGetShape(layer, &shape, + &(layer->resultcache->results[i])) + : MS_DONE; + i++; + } else { + status = msLayerNextShape(layer, &shape); + } + + if (status != MS_SUCCESS) + goto feature_cleanup; + + if (layer->numclasses > 0) { + /* Should be equivalent to shape.classindex = + * layer->resultcache->results[i].classindex; */ + shape.classindex = + msShapeGetClass(layer, map, &shape, classgroup, + nclasses); /* Perform classification, and some + annotation related magic. */ + + if (shape.classindex < 0) + goto feature_cleanup; /* no matching CLASS found, skip this feature */ + } + + /* + ** prepare any necessary JOINs here (one-to-one only) + */ + if (layer->numjoins > 0) { + int j; + + for (j = 0; j < layer->numjoins; j++) { + if (layer->joins[j].type == MS_JOIN_ONE_TO_ONE) { + msJoinPrepare(&(layer->joins[j]), &shape); + msJoinNext(&(layer->joins[j])); /* fetch the first row */ + } + } + } + + if (mvt_layer->n_features == + features_size) { /* need to allocate more space */ + features_size += FEATURES_INCREMENT_SIZE; + mvt_layer->features = msSmallRealloc( + mvt_layer->features, + sizeof(VectorTile__Tile__Feature *) * (features_size)); + } + + if (layer->project) { + if (layer->reprojectorLayerToMap == NULL) { + layer->reprojectorLayerToMap = + msProjectCreateReprojector(&layer->projection, &map->projection); + } + if (layer->reprojectorLayerToMap) + status = msProjectShapeEx(layer->reprojectorLayerToMap, &shape); + else + status = MS_FAILURE; + } + if (status == MS_SUCCESS) { + status = mvtWriteShape(layer, &shape, mvt_layer, item_list, + &value_lookup_cache, &map->extent, buffer); + } + + feature_cleanup: + msFreeShape(&shape); + if (status != MS_SUCCESS) + goto layer_cleanup; + } /* next shape */ + layer_cleanup: + if (classgroup) + msFree(classgroup); + msLayerClose(layer); + msGMLFreeItems(item_list); + UT_HASH_ITER(hh, value_lookup_cache.cache, cur_value_lookup, + tmp_value_lookup) { + msFree(cur_value_lookup->value); + UT_HASH_DEL(value_lookup_cache.cache, cur_value_lookup); + msFree(cur_value_lookup); + } + if (retcode != MS_SUCCESS) + goto cleanup; + } /* next layer */ + + len = vector_tile__tile__get_packed_size( + &mvt_tile); // This is the calculated packing length + + buf = msSmallMalloc(len); // Allocate memory + vector_tile__tile__pack(&mvt_tile, buf); + if (sendheaders) { + msIO_fprintf(stdout, + "Content-Length: %d\r\n" + "Content-Type: %s\r\n\r\n", + len, MS_IMAGE_MIME_TYPE(map->outputformat)); + } + msIO_fwrite(buf, len, 1, stdout); + msFree(buf); + +cleanup: + freeMvtTile(&mvt_tile); + + return retcode; +} + +int msPopulateRendererVTableMVT(rendererVTableObj *renderer) { + (void)renderer; + return MS_SUCCESS; +} +#else +int msPopulateRendererVTableMVT(rendererVTableObj *renderer) { + (void)renderer; + msSetError(MS_MISCERR, + "Vector Tile Driver requested but support is not compiled in", + "msPopulateRendererVTableMVT()"); + return MS_FAILURE; +} + +int msMVTWriteTile(mapObj *map, int sendheaders) { + (void)map; + (void)sendheaders; + msSetError(MS_MISCERR, "Vector Tile support is not available.", + "msMVTWriteTile()"); + return MS_FAILURE; +} +#endif diff --git a/src/mapobject.c b/src/mapobject.c new file mode 100644 index 0000000000..aa01b99c49 --- /dev/null +++ b/src/mapobject.c @@ -0,0 +1,782 @@ +/****************************************************************************** + * $Id$ + * + * Project: MapServer + * Purpose: Functions for operating on a mapObj that don't belong in a + * more specific file such as mapfile.c, or mapdraw.c. + * Author: Frank Warmerdam, warmerdam@pobox.com + * + ****************************************************************************** + * Copyright (c) 2004, Frank Warmerdam + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + ****************************************************************************/ + +#include "mapserver.h" +#include "mapows.h" + +#include "gdal.h" +#include "cpl_conv.h" + +void freeWeb(webObj *web); +void freeScalebar(scalebarObj *scalebar); +void freeReferenceMap(referenceMapObj *ref); +void freeLegend(legendObj *legend); + +/************************************************************************/ +/* msNewMapObj() */ +/* */ +/* Create a new initialized map object. */ +/************************************************************************/ + +mapObj *msNewMapObj() { + mapObj *map = NULL; + + /* create an empty map, no layers etc... */ + map = (mapObj *)calloc(1, sizeof(mapObj)); + + if (!map) { + msSetError(MS_MEMERR, NULL, "msCreateMap()"); + return NULL; + } + + if (initMap(map) == -1) { + msFreeMap(map); + return NULL; + } + + if (msPostMapParseOutputFormatSetup(map) == MS_FAILURE) { + msFreeMap(map); + return NULL; + } + + return map; +} + +/************************************************************************/ +/* msFreeMap() */ +/************************************************************************/ + +void msFreeMap(mapObj *map) { + int i; + + if (!map) + return; + + /* printf("msFreeMap(): maybe freeing map at %p count=%d.\n",map, + * map->refcount); */ + if (MS_REFCNT_DECR_IS_NOT_ZERO(map)) { + return; + } + if (map->debug >= MS_DEBUGLEVEL_VV) + msDebug("msFreeMap(): freeing map at %p.\n", map); + + msCloseConnections(map); + + msFree(map->name); + msFree(map->shapepath); + msFree(map->mappath); + + msFreeProjection(&(map->projection)); + msFreeProjection(&(map->latlon)); + msProjectionContextReleaseToPool(map->projContext); + + msFreeLabelCache(&(map->labelcache)); + + msFree(map->imagetype); + + msFreeFontSet(&(map->fontset)); + + msFreeSymbolSet(&map->symbolset); /* free symbols */ + msFree(map->symbolset.filename); + + freeWeb(&(map->web)); + + freeScalebar(&(map->scalebar)); + freeReferenceMap(&(map->reference)); + freeLegend(&(map->legend)); + + for (i = 0; i < map->maxlayers; i++) { + if (GET_LAYER(map, i) != NULL) { + GET_LAYER(map, i)->map = NULL; + if (freeLayer((GET_LAYER(map, i))) == MS_SUCCESS) + free(GET_LAYER(map, i)); + } + } + msFree(map->layers); + + if (map->layerorder) + free(map->layerorder); + + msFree(map->templatepattern); + msFree(map->datapattern); + msFreeHashItems(&(map->configoptions)); + if (map->outputformat && map->outputformat->refcount > 0 && + --map->outputformat->refcount < 1) + msFreeOutputFormat(map->outputformat); + + for (i = 0; i < map->numoutputformats; i++) { + if (map->outputformatlist[i]->refcount > 0 && + --map->outputformatlist[i]->refcount < 1) + msFreeOutputFormat(map->outputformatlist[i]); + } + if (map->outputformatlist != NULL) + msFree(map->outputformatlist); + + msFreeQuery(&(map->query)); + +#ifdef USE_V8_MAPSCRIPT + if (map->v8context) + msV8FreeContext(map); +#endif + + msFree(map); +} + +/************************************************************************/ +/* msGetConfigOption() */ +/************************************************************************/ + +const char *msGetConfigOption(mapObj *map, const char *key) + +{ + return msLookupHashTable(&(map->configoptions), key); +} + +/************************************************************************/ +/* msSetConfigOption() */ +/************************************************************************/ + +int msSetConfigOption(mapObj *map, const char *key, const char *value) + +{ + /* We have special "early" handling of this so that it will be */ + /* in effect when the projection blocks are parsed and pj_init is called. */ + if (strcasecmp(key, "PROJ_DATA") == 0 || strcasecmp(key, "PROJ_LIB") == 0) { + /* value may be relative to map path */ + msSetPROJ_DATA(value, map->mappath); + } + + /* Same for MS_ERRORFILE, we want it to kick in as early as possible + * to catch parsing errors. + * Value can be relative to mapfile, unless it's already absolute + */ + if (strcasecmp(key, "MS_ERRORFILE") == 0) { + if (msSetErrorFile(value, map->mappath) != MS_SUCCESS) + return MS_FAILURE; + } + + if (msLookupHashTable(&(map->configoptions), key) != NULL) + msRemoveHashTable(&(map->configoptions), key); + msInsertHashTable(&(map->configoptions), key, value); + + return MS_SUCCESS; +} + +/************************************************************************/ +/* msTestConfigOption() */ +/************************************************************************/ + +int msTestConfigOption(mapObj *map, const char *key, int default_result) + +{ + const char *result = msGetConfigOption(map, key); + + if (result == NULL) + return default_result; + + if (strcasecmp(result, "YES") == 0 || strcasecmp(result, "ON") == 0 || + strcasecmp(result, "TRUE") == 0) + return MS_TRUE; + else + return MS_FALSE; +} + +/************************************************************************/ +/* msApplyMapConfigOptions() */ +/************************************************************************/ + +void msApplyMapConfigOptions(mapObj *map) + +{ + const char *key; + + for (key = msFirstKeyFromHashTable(&(map->configoptions)); key != NULL; + key = msNextKeyFromHashTable(&(map->configoptions), key)) { + const char *value = msLookupHashTable(&(map->configoptions), key); + if (strcasecmp(key, "PROJ_DATA") == 0 || strcasecmp(key, "PROJ_LIB") == 0) { + msSetPROJ_DATA(value, map->mappath); + } else if (strcasecmp(key, "MS_ERRORFILE") == 0) { + msSetErrorFile(value, map->mappath); + } else { + CPLSetConfigOption(key, value); + } + } +} + +/************************************************************************/ +/* msMapIgnoreMissingData() */ +/************************************************************************/ + +int msMapIgnoreMissingData(mapObj *map) { + const char *result = msGetConfigOption(map, "ON_MISSING_DATA"); + const int default_result = +#ifndef IGNORE_MISSING_DATA + MS_MISSING_DATA_FAIL; +#else + MS_MISSING_DATA_LOG; +#endif + + if (result == NULL) + return default_result; + + if (strcasecmp(result, "FAIL") == 0) + return MS_MISSING_DATA_FAIL; + else if (strcasecmp(result, "LOG") == 0) + return MS_MISSING_DATA_LOG; + else if (strcasecmp(result, "IGNORE") == 0) + return MS_MISSING_DATA_IGNORE; + + return default_result; +} + +/************************************************************************/ +/* msMapSetExtent() */ +/************************************************************************/ + +int msMapSetExtent(mapObj *map, double minx, double miny, double maxx, + double maxy) { + + map->extent.minx = minx; + map->extent.miny = miny; + map->extent.maxx = maxx; + map->extent.maxy = maxy; + + if (!MS_VALID_EXTENT(map->extent)) { + msSetError(MS_MISCERR, + "Given map extent is invalid. Check that it " + "is in the form: minx, miny, maxx, maxy", + "setExtent()"); + return MS_FAILURE; + } + + map->cellsize = msAdjustExtent(&(map->extent), map->width, map->height); + + /* if the map size is also set, recompute scale, ignore errors? */ + if (map->width != -1 || map->height != -1) + msCalculateScale(map->extent, map->units, map->width, map->height, + map->resolution, &(map->scaledenom)); + + return msMapComputeGeotransform(map); +} + +/************************************************************************/ +/* msMapOffsetExtent() */ +/************************************************************************/ + +int msMapOffsetExtent(mapObj *map, double x, double y) { + return msMapSetExtent(map, map->extent.minx + x, map->extent.miny + y, + map->extent.maxx + x, map->extent.maxy + y); +} + +/************************************************************************/ +/* msMapScaleExtent() */ +/************************************************************************/ + +int msMapScaleExtent(mapObj *map, double zoomfactor, double minscaledenom, + double maxscaledenom) { + double geo_width, geo_height, center_x, center_y, md; + + if (zoomfactor <= 0.0) { + msSetError(MS_MISCERR, "The given zoomfactor is invalid", + "msMapScaleExtent()"); + } + + geo_width = map->extent.maxx - map->extent.minx; + geo_height = map->extent.maxy - map->extent.miny; + + center_x = map->extent.minx + geo_width * 0.5; + center_y = map->extent.miny + geo_height * 0.5; + + geo_width *= zoomfactor; + + if (minscaledenom > 0 || maxscaledenom > 0) { + /* ensure we are within the valid scale domain */ + md = (map->width - 1) / + (map->resolution * msInchesPerUnit(map->units, center_y)); + if (minscaledenom > 0 && geo_width < minscaledenom * md) + geo_width = minscaledenom * md; + if (maxscaledenom > 0 && geo_width > maxscaledenom * md) + geo_width = maxscaledenom * md; + } + + geo_width *= 0.5; + geo_height = geo_width * map->height / map->width; + + return msMapSetExtent(map, center_x - geo_width, center_y - geo_height, + center_x + geo_width, center_y + geo_height); +} + +/************************************************************************/ +/* msMapSetCenter() */ +/************************************************************************/ + +int msMapSetCenter(mapObj *map, pointObj *center) { + return msMapOffsetExtent( + map, center->x - (map->extent.minx + map->extent.maxx) * 0.5, + center->y - (map->extent.miny + map->extent.maxy) * 0.5); +} + +/************************************************************************/ +/* msMapSetRotation() */ +/************************************************************************/ + +int msMapSetRotation(mapObj *map, double rotation_angle) + +{ + map->gt.rotation_angle = rotation_angle; + if (map->gt.rotation_angle != 0.0) + map->gt.need_geotransform = MS_TRUE; + else + map->gt.need_geotransform = MS_FALSE; + + return msMapComputeGeotransform(map); +} + +/************************************************************************/ +/* msMapSetSize() */ +/************************************************************************/ + +int msMapSetSize(mapObj *map, int width, int height) + +{ + map->width = width; + map->height = height; + + return msMapComputeGeotransform(map); /* like SetRotation -- sean */ +} + +/************************************************************************/ +/* msMapComputeGeotransform() */ +/************************************************************************/ + +extern int InvGeoTransform(double *gt_in, double *gt_out); + +int msMapComputeGeotransformEx(mapObj *map, double resolutionX, + double resolutionY) + +{ + double rot_angle; + double geo_width, geo_height, center_x, center_y; + + map->saved_extent = map->extent; + + rot_angle = map->gt.rotation_angle * MS_PI / 180.0; + + geo_width = map->extent.maxx - map->extent.minx; + geo_height = map->extent.maxy - map->extent.miny; + + center_x = map->extent.minx + geo_width * 0.5; + center_y = map->extent.miny + geo_height * 0.5; + + /* + ** Per bug 1916 we have to adjust for the fact that map extents + ** are based on the center of the edge pixels, not the outer + ** edges as is expected in a geotransform. + */ + map->gt.geotransform[1] = cos(rot_angle) * resolutionX; + map->gt.geotransform[2] = sin(rot_angle) * resolutionY; + map->gt.geotransform[0] = center_x - + (map->width * 0.5) * map->gt.geotransform[1] - + (map->height * 0.5) * map->gt.geotransform[2]; + + map->gt.geotransform[4] = sin(rot_angle) * resolutionX; + map->gt.geotransform[5] = -cos(rot_angle) * resolutionY; + map->gt.geotransform[3] = center_y - + (map->width * 0.5) * map->gt.geotransform[4] - + (map->height * 0.5) * map->gt.geotransform[5]; + + if (InvGeoTransform(map->gt.geotransform, map->gt.invgeotransform)) + return MS_SUCCESS; + else + return MS_FAILURE; +} + +int msMapComputeGeotransform(mapObj *map) + +{ + /* Do we have all required parameters? */ + if (map->extent.minx == map->extent.maxx || map->width <= 1 || + map->height <= 1) + return MS_FAILURE; + + const double geo_width = map->extent.maxx - map->extent.minx; + const double geo_height = map->extent.maxy - map->extent.miny; + return msMapComputeGeotransformEx(map, geo_width / (map->width - 1), + geo_height / (map->height - 1)); +} + +/************************************************************************/ +/* msMapPixelToGeoref() */ +/************************************************************************/ + +void msMapPixelToGeoref(mapObj *map, double *x, double *y) + +{ + (void)map; + (void)x; + (void)y; + msSetError(MS_MISCERR, NULL, "msMapPixelToGeoref() not yet implemented"); +} + +/************************************************************************/ +/* msMapGeorefToPixel() */ +/************************************************************************/ + +void msMapGeorefToPixel(mapObj *map, double *x, double *y) + +{ + (void)map; + (void)x; + (void)y; + msSetError(MS_MISCERR, NULL, "msMapGeorefToPixel() not yet implemented"); +} + +/************************************************************************/ +/* msMapSetFakedExtent() */ +/************************************************************************/ + +int msMapSetFakedExtent(mapObj *map) + +{ + int i; + /* -------------------------------------------------------------------- */ + /* Remember the original map extents so we can restore them */ + /* later. */ + /* -------------------------------------------------------------------- */ + map->saved_extent = map->extent; + + /* -------------------------------------------------------------------- */ + /* Set extents such that the bottom left corner is 0,0 and the */ + /* top right is width,height. Note this is upside down from */ + /* the normal sense of pixel/line coordinates, but we do this */ + /* so that the normal "extent" concept of coordinates */ + /* increasing to the right, and up is maintained (like in */ + /* georeferenced coordinate systems). */ + /* -------------------------------------------------------------------- */ + map->extent.minx = 0; + map->extent.maxx = map->width; + map->extent.miny = 0; + map->extent.maxy = map->height; + map->cellsize = 1.0; + + /* -------------------------------------------------------------------- */ + /* When we copy the geotransform into the projection object we */ + /* have to flip it to account for the preceding upside-down */ + /* coordinate system. */ + /* -------------------------------------------------------------------- */ + map->projection.gt = map->gt; + + map->projection.gt.geotransform[0] += map->height * map->gt.geotransform[2]; + map->projection.gt.geotransform[3] += map->height * map->gt.geotransform[5]; + + map->projection.gt.geotransform[2] *= -1; + map->projection.gt.geotransform[5] *= -1; + + for (i = 0; i < map->numlayers; i++) + GET_LAYER(map, i)->project = MS_TRUE; + + return InvGeoTransform(map->projection.gt.geotransform, + map->projection.gt.invgeotransform); +} + +/************************************************************************/ +/* msMapRestoreRealExtent() */ +/************************************************************************/ + +int msMapRestoreRealExtent(mapObj *map) + +{ + map->projection.gt.need_geotransform = MS_FALSE; + map->extent = map->saved_extent; + map->cellsize = msAdjustExtent(&(map->extent), map->width, map->height); + + return MS_SUCCESS; +} + +/************************************************************************/ +/* msInsertLayer() */ +/************************************************************************/ +/* Returns the index at which the layer was inserted + */ + +int msInsertLayer(mapObj *map, layerObj *layer, int nIndex) { + if (!layer) { + msSetError(MS_CHILDERR, "Can't insert a NULL Layer", "msInsertLayer()"); + return -1; + } + + /* Ensure there is room for a new layer */ + if (map->numlayers == map->maxlayers) { + if (msGrowMapLayers(map) == NULL) + return -1; + } + + /* msGrowMapLayers allocates the new layer which we don't need to do since we + have 1 that we are inserting not sure if it is possible for this to be non + null otherwise, but better to check since this function replaces the value + */ + if (map->layers[map->numlayers] != NULL) + free(map->layers[map->numlayers]); + + /* Catch attempt to insert past end of layers array */ + if (nIndex >= map->numlayers) { + msSetError(MS_CHILDERR, "Cannot insert layer beyond index %d", + "msInsertLayer()", map->numlayers - 1); + return -1; + } else if (nIndex < 0) { /* Insert at the end by default */ + map->layerorder[map->numlayers] = map->numlayers; + GET_LAYER(map, map->numlayers) = layer; + GET_LAYER(map, map->numlayers)->index = map->numlayers; + GET_LAYER(map, map->numlayers)->map = map; + MS_REFCNT_INCR(layer); + map->numlayers++; + return map->numlayers - 1; + } else { + /* Move existing layers at the specified nIndex or greater */ + /* to an index one higher */ + int i; + for (i = map->numlayers; i > nIndex; i--) { + GET_LAYER(map, i) = GET_LAYER(map, i - 1); + GET_LAYER(map, i)->index = i; + } + + /* assign new layer to specified index */ + GET_LAYER(map, nIndex) = layer; + GET_LAYER(map, nIndex)->index = nIndex; + GET_LAYER(map, nIndex)->map = map; + + /* adjust layers drawing order */ + for (i = map->numlayers; i > nIndex; i--) { + map->layerorder[i] = map->layerorder[i - 1]; + if (map->layerorder[i] >= nIndex) + map->layerorder[i]++; + } + for (i = 0; i < nIndex; i++) { + if (map->layerorder[i] >= nIndex) + map->layerorder[i]++; + } + map->layerorder[nIndex] = nIndex; + + /* increment number of layers and return */ + MS_REFCNT_INCR(layer); + map->numlayers++; + return nIndex; + } +} + +/************************************************************************/ +/* msRemoveLayer() */ +/************************************************************************/ +layerObj *msRemoveLayer(mapObj *map, int nIndex) { + int i; + int order_index; + layerObj *layer; + + if (nIndex < 0 || nIndex >= map->numlayers) { + msSetError(MS_CHILDERR, "Cannot remove Layer, invalid index %d", + "msRemoveLayer()", nIndex); + return NULL; + } else { + layer = GET_LAYER(map, nIndex); + /* msCopyLayer(layer, (GET_LAYER(map, nIndex))); */ + + /* Iteratively copy the higher index layers down one index */ + for (i = nIndex; i < map->numlayers - 1; i++) { + /* freeLayer((GET_LAYER(map, i))); */ + /* initLayer((GET_LAYER(map, i)), map); */ + /* msCopyLayer(GET_LAYER(map, i), GET_LAYER(map, i+1)); */ + GET_LAYER(map, i) = GET_LAYER(map, i + 1); + GET_LAYER(map, i)->index = i; + } + /* Free the extra layer at the end */ + /* freeLayer((GET_LAYER(map, map->numlayers-1))); */ + GET_LAYER(map, map->numlayers - 1) = NULL; + + /* Adjust drawing order */ + order_index = 0; + for (i = 0; i < map->numlayers; i++) { + if (map->layerorder[i] > nIndex) + map->layerorder[i]--; + if (map->layerorder[i] == nIndex) { + order_index = i; + break; + } + } + for (i = order_index; i < map->numlayers - 1; i++) { + map->layerorder[i] = map->layerorder[i + 1]; + if (map->layerorder[i] > nIndex) + map->layerorder[i]--; + } + + /* decrement number of layers and return copy of removed layer */ + map->numlayers--; + layer->map = NULL; + MS_REFCNT_DECR(layer); + return layer; + } +} + +/* +** Move the layer's order for drawing purpose. Moving it up here +** will have the effect of drawing the layer earlier. +*/ +int msMoveLayerUp(mapObj *map, int nLayerIndex) { + int iCurrentIndex = -1; + if (map && nLayerIndex < map->numlayers && nLayerIndex >= 0) { + for (int i = 0; i < map->numlayers; i++) { + if (map->layerorder[i] == nLayerIndex) { + iCurrentIndex = i; + break; + } + } + if (iCurrentIndex >= 0) { + /* we do not need to promote if it is the first one. */ + if (iCurrentIndex == 0) + return MS_FAILURE; + + map->layerorder[iCurrentIndex] = map->layerorder[iCurrentIndex - 1]; + map->layerorder[iCurrentIndex - 1] = nLayerIndex; + + return MS_SUCCESS; + } + } + msSetError(MS_CHILDERR, "Invalid index: %d", "msMoveLayerUp()", nLayerIndex); + return MS_FAILURE; +} + +/* +** Move the layer's order for drawing purpose. Moving it down here +** will have the effect of drawing the layer later. +*/ +int msMoveLayerDown(mapObj *map, int nLayerIndex) { + int iCurrentIndex = -1; + if (map && nLayerIndex < map->numlayers && nLayerIndex >= 0) { + for (int i = 0; i < map->numlayers; i++) { + if (map->layerorder[i] == nLayerIndex) { + iCurrentIndex = i; + break; + } + } + if (iCurrentIndex >= 0) { + /* we do not need to demote if it is the last one. */ + if (iCurrentIndex == map->numlayers - 1) + return MS_FAILURE; + + map->layerorder[iCurrentIndex] = map->layerorder[iCurrentIndex + 1]; + map->layerorder[iCurrentIndex + 1] = nLayerIndex; + + return MS_SUCCESS; + } + } + msSetError(MS_CHILDERR, "Invalid index: %d", "msMoveLayerDown()", + nLayerIndex); + return MS_FAILURE; +} + +/* +** Set the array used for the drawing order. The array passed must contain +** all the layer's index ordered by the drawing priority. +** Ex : for 3 layers in the map file, if +** panIndexes[0] = 2 +** panIndexes[1] = 0 +** panIndexes[2] = 1 +** will set the darwing order to layer 2, layer 0, +** and then layer 1. +** +** Note : It is assumed that the index panIndexes has the same number of +** of elements as the number of layers in the map. +** Return TRUE on success else FALSE. +*/ +int msSetLayersdrawingOrder(mapObj *self, int *panIndexes) { + if (self && panIndexes) { + const int nElements = self->numlayers; + for (int i = 0; i < nElements; i++) { + int bFound = 0; + for (int j = 0; j < nElements; j++) { + if (panIndexes[j] == i) { + bFound = 1; + break; + } + } + if (!bFound) + return 0; + } + /* -------------------------------------------------------------------- */ + /* At this point the array is valid so update the layers order array.*/ + /* -------------------------------------------------------------------- */ + for (int i = 0; i < nElements; i++) { + self->layerorder[i] = panIndexes[i]; + } + return 1; + } + return 0; +} + +/* ========================================================================= + msMapLoadOWSParameters + + Function to support mapscript mapObj::loadOWSParameters + ========================================================================= */ + +int msMapLoadOWSParameters(mapObj *map, cgiRequestObj *request, + const char *wmtver) { +#ifdef USE_WMS_SVR + int version; + char *wms_exception_format = NULL; + const char *wms_request = NULL; + int result, i = 0; + owsRequestObj ows_request; + + msOWSInitRequestObj(&ows_request); + + version = msOWSParseVersionString(wmtver); + for (i = 0; i < request->NumParams; i++) { + if (strcasecmp(request->ParamNames[i], "EXCEPTIONS") == 0) + wms_exception_format = request->ParamValues[i]; + else if (strcasecmp(request->ParamNames[i], "REQUEST") == 0) + wms_request = request->ParamValues[i]; + } + + msOWSRequestLayersEnabled(map, "M", wms_request, &ows_request); + + result = msWMSLoadGetMapParams( + map, version, request->ParamNames, request->ParamValues, + request->NumParams, wms_exception_format, wms_request, &ows_request); + + msOWSClearRequestObj(&ows_request); + + return result; + +#else + msSetError(MS_WMSERR, "WMS server support is not available.", + "msMapLoadOWSParameters()"); + return MS_FAILURE; +#endif +} diff --git a/src/mapogcapi.cpp b/src/mapogcapi.cpp new file mode 100644 index 0000000000..8119e57ee8 --- /dev/null +++ b/src/mapogcapi.cpp @@ -0,0 +1,3128 @@ +/********************************************************************** + * $id$ + * + * Project: MapServer + * Purpose: OGCAPI Implementation + * Author: Steve Lime and the MapServer team. + * + ********************************************************************** + * Copyright (c) 1996-2005 Regents of the University of Minnesota. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + ****************************************************************************/ +#include "mapserver.h" +#include "mapogcapi.h" +#include "mapows.h" +#include "mapgml.h" +#include "maptime.h" +#include "mapogcfilter.h" +#include "cql2json.h" +#include "cql2text.h" + +#include "cpl_conv.h" + +#include "third-party/include_nlohmann_json.hpp" +#include "third-party/include_pantor_inja.hpp" + +#include +#include +#include +#include +#include +#include + +using namespace inja; +using json = nlohmann::json; + +#define OGCAPI_DEFAULT_TITLE "MapServer OGC API" + +/* +** HTML Templates +*/ +#define OGCAPI_TEMPLATE_HTML_LANDING "landing.html" +#define OGCAPI_TEMPLATE_HTML_CONFORMANCE "conformance.html" +#define OGCAPI_TEMPLATE_HTML_COLLECTION "collection.html" +#define OGCAPI_TEMPLATE_HTML_COLLECTIONS "collections.html" +#define OGCAPI_TEMPLATE_HTML_COLLECTION_ITEMS "collection-items.html" +#define OGCAPI_TEMPLATE_HTML_COLLECTION_ITEM "collection-item.html" +#define OGCAPI_TEMPLATE_HTML_COLLECTION_QUERYABLES "collection-queryables.html" +#define OGCAPI_TEMPLATE_HTML_COLLECTION_SORTABLES "collection-sortables.html" +#define OGCAPI_TEMPLATE_HTML_COLLECTION_SCHEMA "collection-schema.html" +#define OGCAPI_TEMPLATE_HTML_OPENAPI "openapi.html" + +#define OGCAPI_DEFAULT_LIMIT 10 // by specification +#define OGCAPI_MAX_LIMIT 10000 + +#define OGCAPI_DEFAULT_GEOMETRY_PRECISION 6 + +constexpr const char *EPSG_PREFIX_URL = + "http://www.opengis.net/def/crs/EPSG/0/"; +constexpr const char *CRS84_URL = + "http://www.opengis.net/def/crs/OGC/1.3/CRS84"; + +#ifdef USE_OGCAPI_SVR + +/** Returns whether we enforce compliance mode. Defaults to true */ +static bool msOGCAPIComplianceMode(const mapObj *map) { + const char *compliance_mode = + msOWSLookupMetadata(&(map->web.metadata), "A", "compliance_mode"); + return compliance_mode == NULL || strcasecmp(compliance_mode, "true") == 0; +} + +/* +** Returns a JSON object using and a description. +*/ +void msOGCAPIOutputError(OGCAPIErrorType errorType, + const std::string &description) { + const char *code = ""; + const char *status = ""; + switch (errorType) { + case OGCAPI_SERVER_ERROR: { + code = "ServerError"; + status = "500"; + break; + } + case OGCAPI_CONFIG_ERROR: { + code = "ConfigError"; + status = "500"; + break; + } + case OGCAPI_PARAM_ERROR: { + code = "InvalidParameterValue"; + status = "400"; + break; + } + case OGCAPI_NOT_FOUND_ERROR: { + code = "NotFound"; + status = "404"; + break; + } + } + + json j = {{"code", code}, {"description", description}}; + + msIO_setHeader("Content-Type", "%s", OGCAPI_MIMETYPE_JSON); + msIO_setHeader("Status", "%s", status); + msIO_sendHeaders(); + msIO_printf("%s\n", j.dump().c_str()); +} + +static int includeLayer(mapObj *map, layerObj *layer) { + if (!msOWSRequestIsEnabled(map, layer, "AO", "OGCAPI", MS_FALSE) || + !msIsLayerSupportedForWFSOrOAPIF(layer) || !msIsLayerQueryable(layer)) { + return MS_FALSE; + } else { + return MS_TRUE; + } +} + +/* +** Get stuff... +*/ + +/* +** Returns the value associated with an item from the request's query string and +*NULL if the item was not found. +*/ +static const char *getRequestParameter(const cgiRequestObj *request, + const char *item) { + for (int i = 0; i < request->NumParams; i++) { + if (strcmp(item, request->ParamNames[i]) == 0) + return request->ParamValues[i]; + } + + return nullptr; +} + +static int getMaxLimit(mapObj *map, layerObj *layer) { + int max_limit = OGCAPI_MAX_LIMIT; + const char *value; + + // check metadata, layer then map + value = msOWSLookupMetadata(&(layer->metadata), "A", "max_limit"); + if (value == NULL) + value = msOWSLookupMetadata(&(map->web.metadata), "A", "max_limit"); + + if (value != NULL) { + int status = msStringToInt(value, &max_limit, 10); + if (status != MS_SUCCESS) + max_limit = OGCAPI_MAX_LIMIT; // conversion failed + } + + return max_limit; +} + +static int getDefaultLimit(const mapObj *map, const layerObj *layer) { + int default_limit = OGCAPI_DEFAULT_LIMIT; + + // check metadata, layer then map + const char *value = + msOWSLookupMetadata(&(layer->metadata), "A", "default_limit"); + if (value == NULL) + value = msOWSLookupMetadata(&(map->web.metadata), "A", "default_limit"); + + if (value != NULL) { + int status = msStringToInt(value, &default_limit, 10); + if (status != MS_SUCCESS) + default_limit = OGCAPI_DEFAULT_LIMIT; // conversion failed + } + + return default_limit; +} + +static std::string getExtraParameterString(const mapObj *map, + const layerObj *layer) { + + std::string extra_params; + + // first check layer metadata if layer is not null + if (layer) { + const char *layerVal = + msOWSLookupMetadata(&(layer->metadata), "AO", "extra_params"); + if (layerVal) + extra_params = std::string("&") + layerVal; + } + + if (extra_params.empty() && map) { + const char *mapVal = + msOWSLookupMetadata(&(map->web.metadata), "AO", "extra_params"); + if (mapVal) + extra_params = std::string("&") + mapVal; + } + + return extra_params; +} + +static std::set +getExtraParameters(const char *pszExtraParameters) { + std::set ret; + for (const auto ¶m : msStringSplit(pszExtraParameters, '&')) { + const auto keyValue = msStringSplit(param.c_str(), '='); + if (!keyValue.empty()) + ret.insert(keyValue[0]); + } + return ret; +} + +static std::set getExtraParameters(const mapObj *map, + const layerObj *layer) { + + // first check layer metadata if layer is not null + if (layer) { + const char *layerVal = + msOWSLookupMetadata(&(layer->metadata), "AO", "extra_params"); + if (layerVal) + return getExtraParameters(layerVal); + } + + if (map) { + const char *mapVal = + msOWSLookupMetadata(&(map->web.metadata), "AO", "extra_params"); + if (mapVal) + return getExtraParameters(mapVal); + } + + return {}; +} + +static bool +msOOGCAPICheckQueryParameters(const mapObj *map, const cgiRequestObj *request, + const std::set &allowedParameters) { + if (msOGCAPIComplianceMode(map)) { + for (int j = 0; j < request->NumParams; j++) { + const char *paramName = request->ParamNames[j]; + if (allowedParameters.find(paramName) == allowedParameters.end()) { + msOGCAPIOutputError( + OGCAPI_PARAM_ERROR, + (std::string("Unknown query parameter: ") + paramName).c_str()); + return false; + } + } + } + return true; +} + +static std::string getItemAliasOrName(const layerObj *layer, + const std::string &item) { + std::string key = item; + key += "_alias"; + if (const char *value = + msOWSLookupMetadata(&(layer->metadata), "OGA", key.c_str())) { + return value; + } + return item; +} + +static const char *getGeometryName(const layerObj *layer) { + const char *geometryName = + msOWSLookupMetadata(&(layer->metadata), "A", "geometry_name"); + if (!geometryName) + geometryName = "geom"; + return geometryName; +} + +static const char *getGeometryFormat(const layerObj *layer) { + const char *geometryFormat = + msOWSLookupMetadata(&(layer->metadata), "A", "geometry_format"); + if (layer->type == MS_LAYER_POINT) + geometryFormat = "geometry-point-or-multipoint"; + else if (layer->type == MS_LAYER_LINE) + geometryFormat = "geometry-linestring-or-multilinestring"; + else if (layer->type == MS_LAYER_POLYGON) + geometryFormat = "geometry-polygon-or-multipolygon"; + else if (!geometryFormat) + geometryFormat = "geometry-any"; + return geometryFormat; +} + +namespace { +struct CaseInsensitiveComparator { + bool operator()(const std::string &a, const std::string &b) const { + return strcasecmp(a.c_str(), b.c_str()) < 0; + } +}; +} // namespace + +/** Return the list of queryable items */ +static std::vector msOOGCAPIGetLayerQueryables( + layerObj *layer, const std::set &reservedParams, bool &error) { + error = false; + std::vector queryableItems; + if (const char *value = + msOWSLookupMetadata(&(layer->metadata), "OGA", "queryable_items")) { + queryableItems = msStringSplit(value, ','); + if (!queryableItems.empty()) { + if (msLayerOpen(layer) != MS_SUCCESS || + msLayerGetItems(layer) != MS_SUCCESS) { + msOGCAPIOutputError(OGCAPI_SERVER_ERROR, "Cannot get layer fields"); + return {}; + } + if (queryableItems[0] == "all") { + queryableItems.clear(); + for (int i = 0; i < layer->numitems; ++i) { + if (reservedParams.find(layer->items[i]) == reservedParams.end()) { + queryableItems.push_back(layer->items[i]); + } + } + } else { + std::set validItems; + for (int i = 0; i < layer->numitems; ++i) { + validItems.insert(layer->items[i]); + } + for (const auto &item : queryableItems) { + if (validItems.find(item) == validItems.end()) { + // This is not a known field + msOGCAPIOutputError(OGCAPI_CONFIG_ERROR, + "Invalid item '" + item + + "' in queryable_items"); + error = true; + return {}; + } else if (reservedParams.find(item) != reservedParams.end()) { + // Check clashes with OGC API Features reserved keywords (bbox, + // etc.) + msOGCAPIOutputError( + OGCAPI_CONFIG_ERROR, + "Item '" + item + + "' in queryable_items is a reserved parameter name"); + error = true; + return {}; + } + } + } + } + } + return queryableItems; +} + +/** Return the list of sortable items */ +static std::vector msOOGCAPIGetLayerSortables( + layerObj *layer, const std::set &reservedParams, bool &error) { + error = false; + std::vector sortableItems; + if (const char *value = + msOWSLookupMetadata(&(layer->metadata), "OGA", "sortable_items")) { + sortableItems = msStringSplit(value, ','); + if (!sortableItems.empty()) { + if (msLayerOpen(layer) != MS_SUCCESS || + msLayerGetItems(layer) != MS_SUCCESS) { + msOGCAPIOutputError(OGCAPI_SERVER_ERROR, "Cannot get layer fields"); + return {}; + } + if (sortableItems[0] == "all") { + sortableItems.clear(); + for (int i = 0; i < layer->numitems; ++i) { + if (reservedParams.find(layer->items[i]) == reservedParams.end()) { + sortableItems.push_back(layer->items[i]); + } + } + } else { + std::set validItems; + for (int i = 0; i < layer->numitems; ++i) { + validItems.insert(layer->items[i]); + } + for (const auto &item : sortableItems) { + if (validItems.find(item) == validItems.end()) { + // This is not a known field + msOGCAPIOutputError(OGCAPI_CONFIG_ERROR, "Invalid item '" + item + + "' in sortable_items"); + error = true; + return {}; + } else if (reservedParams.find(item) != reservedParams.end()) { + // Check clashes with OGC API Features reserved keywords (bbox, + // etc.) + msOGCAPIOutputError( + OGCAPI_CONFIG_ERROR, + "Item '" + item + + "' in sortable_items is a reserved parameter name"); + error = true; + return {}; + } + } + } + } + } + return sortableItems; +} + +/* +** Returns the limit as an int - between 1 and getMaxLimit(). We always return a +*valid value... +*/ +static int getLimit(mapObj *map, cgiRequestObj *request, layerObj *layer, + int *limit) { + int status; + const char *p; + + int max_limit; + max_limit = getMaxLimit(map, layer); + + p = getRequestParameter(request, "limit"); + if (!p || (p && strlen(p) == 0)) { // missing or empty + *limit = MS_MIN(getDefaultLimit(map, layer), + max_limit); // max could be smaller than the default + } else { + status = msStringToInt(p, limit, 10); + if (status != MS_SUCCESS) + return MS_FAILURE; + + if (*limit <= 0) { + *limit = MS_MIN(getDefaultLimit(map, layer), + max_limit); // max could be smaller than the default + } else { + *limit = MS_MIN(*limit, max_limit); + } + } + + return MS_SUCCESS; +} + +// Return the content of the "crs" member of the /collections/{name} response +static json getCrsList(mapObj *map, layerObj *layer) { + char *pszSRSList = NULL; + msOWSGetEPSGProj(&(layer->projection), &(layer->metadata), "AOF", MS_FALSE, + &pszSRSList); + if (!pszSRSList) + msOWSGetEPSGProj(&(map->projection), &(map->web.metadata), "AOF", MS_FALSE, + &pszSRSList); + json jCrsList; + if (pszSRSList) { + const auto tokens = msStringSplit(pszSRSList, ' '); + for (const auto &crs : tokens) { + if (crs.find("EPSG:") == 0) { + if (jCrsList.empty()) { + jCrsList.push_back(CRS84_URL); + } + const std::string url = + std::string(EPSG_PREFIX_URL) + crs.substr(strlen("EPSG:")); + jCrsList.push_back(url); + } + } + msFree(pszSRSList); + } + return jCrsList; +} + +// Return the content of the "storageCrs" member of the /collections/{name} +// response +static std::string getStorageCrs(layerObj *layer) { + std::string storageCrs; + char *pszFirstSRS = nullptr; + msOWSGetEPSGProj(&(layer->projection), &(layer->metadata), "AOF", MS_TRUE, + &pszFirstSRS); + if (pszFirstSRS) { + if (std::string(pszFirstSRS).find("EPSG:") == 0) { + storageCrs = + std::string(EPSG_PREFIX_URL) + (pszFirstSRS + strlen("EPSG:")); + } + msFree(pszFirstSRS); + } + return storageCrs; +} + +/* +** Returns the bbox in output CRS (CRS84 by default, or "bbox-crs" request +*parameter when specified) +*/ +static bool getBbox(mapObj *map, layerObj *layer, cgiRequestObj *request, + rectObj *bbox, projectionObj *outputProj) { + int status; + + const char *bboxParam = getRequestParameter(request, "bbox"); + if (!bboxParam || strlen(bboxParam) == 0) { // missing or empty extent + rectObj rect; + if (FLTLayerSetInvalidRectIfSupported(map, layer, &rect, "AO")) { + bbox->minx = rect.minx; + bbox->miny = rect.miny; + bbox->maxx = rect.maxx; + bbox->maxy = rect.maxy; + } else { + // assign map->extent (no projection necessary) + bbox->minx = map->extent.minx; + bbox->miny = map->extent.miny; + bbox->maxx = map->extent.maxx; + bbox->maxy = map->extent.maxy; + } + } else { + const auto tokens = msStringSplit(bboxParam, ','); + if (tokens.size() != 4) { + msOGCAPIOutputError(OGCAPI_PARAM_ERROR, "Bad value for bbox."); + return false; + } + + double values[4]; + for (int i = 0; i < 4; i++) { + status = msStringToDouble(tokens[i].c_str(), &values[i]); + if (status != MS_SUCCESS) { + msOGCAPIOutputError(OGCAPI_PARAM_ERROR, "Bad value for bbox."); + return false; + } + } + + bbox->minx = values[0]; // assign + bbox->miny = values[1]; + bbox->maxx = values[2]; + bbox->maxy = values[3]; + + // validate bbox is well-formed (degenerate is ok) + if (MS_VALID_SEARCH_EXTENT(*bbox) != MS_TRUE) { + msOGCAPIOutputError(OGCAPI_PARAM_ERROR, "Bad value for bbox."); + return false; + } + + std::string bboxCrs = "EPSG:4326"; + bool axisInverted = + false; // because above EPSG:4326 is meant to be OGC:CRS84 actually + const char *bboxCrsParam = getRequestParameter(request, "bbox-crs"); + if (bboxCrsParam) { + bool isExpectedCrs = false; + for (const auto &crsItem : getCrsList(map, layer)) { + if (bboxCrsParam == crsItem.get()) { + isExpectedCrs = true; + break; + } + } + if (!isExpectedCrs) { + msOGCAPIOutputError(OGCAPI_PARAM_ERROR, "Bad value for bbox-crs."); + return false; + } + if (std::string(bboxCrsParam) != CRS84_URL) { + if (std::string(bboxCrsParam).find(EPSG_PREFIX_URL) == 0) { + const char *code = bboxCrsParam + strlen(EPSG_PREFIX_URL); + bboxCrs = std::string("EPSG:") + code; + axisInverted = msIsAxisInverted(atoi(code)); + } + } + } + if (axisInverted) { + std::swap(bbox->minx, bbox->miny); + std::swap(bbox->maxx, bbox->maxy); + } + + projectionObj bboxProj; + msInitProjection(&bboxProj); + msProjectionInheritContextFrom(&bboxProj, &(map->projection)); + if (msLoadProjectionString(&bboxProj, bboxCrs.c_str()) != 0) { + msFreeProjection(&bboxProj); + msOGCAPIOutputError(OGCAPI_SERVER_ERROR, "Cannot process bbox-crs."); + return false; + } + + status = msProjectRect(&bboxProj, outputProj, bbox); + msFreeProjection(&bboxProj); + if (status != MS_SUCCESS) { + msOGCAPIOutputError(OGCAPI_SERVER_ERROR, + "Cannot reproject bbox from bbox-crs to output CRS."); + return false; + } + } + + return true; +} + +/* +** Returns the template directory location or NULL if it isn't set. +*/ +std::string msOGCAPIGetTemplateDirectory(const mapObj *map, const char *key, + const char *envvar) { + const char *directory = NULL; + + if (map != NULL) { + directory = msOWSLookupMetadata(&(map->web.metadata), "A", key); + } + + if (directory == NULL) { + directory = CPLGetConfigOption(envvar, NULL); + } + + std::string s; + if (directory != NULL) { + s = directory; + if (!s.empty() && (s.back() != '/' && s.back() != '\\')) { + // add a trailing slash if missing + std::string slash = "/"; +#ifdef _WIN32 + slash = "\\"; +#endif + s += slash; + } + } + + return s; +} + +/* +** Returns the service title from oga_{key} and/or ows_{key} or a default value +*if not set. +*/ +static const char *getWebMetadata(const mapObj *map, const char *domain, + const char *key, const char *defaultVal) { + const char *value; + + if ((value = msOWSLookupMetadata(&(map->web.metadata), domain, key)) != NULL) + return value; + else + return defaultVal; +} + +/* +** Returns the service title from oga|ows_title or a default value if not set. +*/ +static const char *getTitle(const mapObj *map) { + return getWebMetadata(map, "OA", "title", OGCAPI_DEFAULT_TITLE); +} + +/* +** Returns the API root URL from oga_onlineresource or builds a value if not +*set. +*/ +std::string msOGCAPIGetApiRootUrl(const mapObj *map, + const cgiRequestObj *request, + const char *namespaces) { + const char *root; + if ((root = msOWSLookupMetadata(&(map->web.metadata), namespaces, + "onlineresource")) != NULL) { + return std::string(root); + } + + std::string api_root; + if (char *res = msBuildOnlineResource(NULL, request)) { + api_root = res; + free(res); + + // find last ogcapi in the string and strip the rest to get the root API + std::size_t pos = api_root.rfind("ogcapi"); + if (pos != std::string::npos) { + api_root = api_root.substr(0, pos + std::string("ogcapi").size()); + } else { + // strip trailing '?' or '/' and append "/ogcapi" + while (!api_root.empty() && + (api_root.back() == '?' || api_root.back() == '/')) { + api_root.pop_back(); + } + api_root += "/ogcapi"; + } + } + + if (api_root.empty()) { + api_root = "/ogcapi"; + } + + return api_root; +} + +static json getFeatureConstant(const gmlConstantObj *constant) { + json j; // empty (null) + + if (!constant) + throw std::runtime_error("Null constant metadata."); + if (!constant->value) + return j; + + // initialize + j = {{constant->name, constant->value}}; + + return j; +} + +static json getFeatureItem(const gmlItemObj *item, const char *value) { + json j; // empty (null) + const char *key; + + if (!item) + throw std::runtime_error("Null item metadata."); + if (!item->visible) + return j; + + if (item->alias) + key = item->alias; + else + key = item->name; + + // initialize + j = {{key, value}}; + + if (item->type && + (EQUAL(item->type, "Date") || EQUAL(item->type, "DateTime") || + EQUAL(item->type, "Time"))) { + struct tm tm; + if (msParseTime(value, &tm) == MS_TRUE) { + char tmpValue[64]; + if (EQUAL(item->type, "Date")) + snprintf(tmpValue, sizeof(tmpValue), "%04d-%02d-%02d", + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); + else if (EQUAL(item->type, "Time")) + snprintf(tmpValue, sizeof(tmpValue), "%02d:%02d:%02dZ", tm.tm_hour, + tm.tm_min, tm.tm_sec); + else + snprintf(tmpValue, sizeof(tmpValue), "%04d-%02d-%02dT%02d:%02d:%02dZ", + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, + tm.tm_min, tm.tm_sec); + + j = {{key, tmpValue}}; + } + } else if (item->type && + (EQUAL(item->type, "Integer") || EQUAL(item->type, "Long"))) { + try { + j = {{key, std::stoll(value)}}; + } catch (const std::exception &) { + } + } else if (item->type && EQUAL(item->type, "Real")) { + try { + j = {{key, std::stod(value)}}; + } catch (const std::exception &) { + } + } else if (item->type && EQUAL(item->type, "Boolean")) { + if (EQUAL(value, "0") || EQUAL(value, "false")) { + j = {{key, false}}; + } else { + j = {{key, true}}; + } + } + + return j; +} + +static double round_down(double value, int decimal_places) { + const double multiplier = std::pow(10.0, decimal_places); + return std::floor(value * multiplier) / multiplier; +} +// https://stackoverflow.com/questions/25925290/c-round-a-double-up-to-2-decimal-places +static double round_up(double value, int decimal_places) { + const double multiplier = std::pow(10.0, decimal_places); + return std::ceil(value * multiplier) / multiplier; +} + +static json getFeatureGeometry(shapeObj *shape, int precision, + bool outputCrsAxisInverted) { + json geometry; // empty (null) + int *outerList = NULL, numOuterRings = 0; + + if (!shape) + throw std::runtime_error("Null shape."); + + switch (shape->type) { + case (MS_SHAPE_POINT): + if (shape->numlines == 0 || + shape->line[0].numpoints == 0) // not enough info for a point + return geometry; + + if (shape->line[0].numpoints == 1) { + geometry["type"] = "Point"; + double x = shape->line[0].point[0].x; + double y = shape->line[0].point[0].y; + if (outputCrsAxisInverted) + std::swap(x, y); + geometry["coordinates"] = {round_up(x, precision), + round_up(y, precision)}; + } else { + geometry["type"] = "MultiPoint"; + geometry["coordinates"] = json::array(); + for (int j = 0; j < shape->line[0].numpoints; j++) { + double x = shape->line[0].point[j].x; + double y = shape->line[0].point[j].y; + if (outputCrsAxisInverted) + std::swap(x, y); + geometry["coordinates"].push_back( + {round_up(x, precision), round_up(y, precision)}); + } + } + break; + case (MS_SHAPE_LINE): + if (shape->numlines == 0 || + shape->line[0].numpoints < 2) // not enough info for a line + return geometry; + + if (shape->numlines == 1) { + geometry["type"] = "LineString"; + geometry["coordinates"] = json::array(); + for (int j = 0; j < shape->line[0].numpoints; j++) { + double x = shape->line[0].point[j].x; + double y = shape->line[0].point[j].y; + if (outputCrsAxisInverted) + std::swap(x, y); + geometry["coordinates"].push_back( + {round_up(x, precision), round_up(y, precision)}); + } + } else { + geometry["type"] = "MultiLineString"; + geometry["coordinates"] = json::array(); + for (int i = 0; i < shape->numlines; i++) { + json part = json::array(); + for (int j = 0; j < shape->line[i].numpoints; j++) { + double x = shape->line[i].point[j].x; + double y = shape->line[i].point[j].y; + if (outputCrsAxisInverted) + std::swap(x, y); + part.push_back({round_up(x, precision), round_up(y, precision)}); + } + geometry["coordinates"].push_back(part); + } + } + break; + case (MS_SHAPE_POLYGON): + if (shape->numlines == 0 || + shape->line[0].numpoints < + 4) // not enough info for a polygon (first=last) + return geometry; + + outerList = msGetOuterList(shape); + if (outerList == NULL) + throw std::runtime_error("Unable to allocate list of outer rings."); + for (int k = 0; k < shape->numlines; k++) { + if (outerList[k] == MS_TRUE) + numOuterRings++; + } + + if (numOuterRings == 1) { + geometry["type"] = "Polygon"; + geometry["coordinates"] = json::array(); + for (int i = 0; i < shape->numlines; i++) { + json part = json::array(); + for (int j = 0; j < shape->line[i].numpoints; j++) { + double x = shape->line[i].point[j].x; + double y = shape->line[i].point[j].y; + if (outputCrsAxisInverted) + std::swap(x, y); + part.push_back({round_up(x, precision), round_up(y, precision)}); + } + geometry["coordinates"].push_back(part); + } + } else { + geometry["type"] = "MultiPolygon"; + geometry["coordinates"] = json::array(); + + for (int k = 0; k < shape->numlines; k++) { + if (outerList[k] == + MS_TRUE) { // outer ring: generate polygon and add to coordinates + int *innerList = msGetInnerList(shape, k, outerList); + if (innerList == NULL) { + msFree(outerList); + throw std::runtime_error("Unable to allocate list of inner rings."); + } + + json polygon = json::array(); + for (int i = 0; i < shape->numlines; i++) { + if (i == k || + innerList[i] == + MS_TRUE) { // add outer ring (k) and any inner rings + json part = json::array(); + for (int j = 0; j < shape->line[i].numpoints; j++) { + double x = shape->line[i].point[j].x; + double y = shape->line[i].point[j].y; + if (outputCrsAxisInverted) + std::swap(x, y); + part.push_back( + {round_up(x, precision), round_up(y, precision)}); + } + polygon.push_back(part); + } + } + + msFree(innerList); + geometry["coordinates"].push_back(polygon); + } + } + } + msFree(outerList); + break; + default: + throw std::runtime_error("Invalid shape type."); + break; + } + + return geometry; +} + +/* +** Return a GeoJSON representation of a shape. +*/ +static json getFeature(layerObj *layer, shapeObj *shape, gmlItemListObj *items, + gmlConstantListObj *constants, int geometry_precision, + bool outputCrsAxisInverted) { + int i; + json feature; // empty (null) + + if (!layer || !shape) + throw std::runtime_error("Null arguments."); + + // initialize + feature = {{"type", "Feature"}, {"properties", json::object()}}; + + // id + const char *featureIdItem = + msOWSLookupMetadata(&(layer->metadata), "AGFO", "featureid"); + if (featureIdItem == NULL) + throw std::runtime_error( + "Missing required featureid metadata."); // should have been trapped + // earlier + for (i = 0; i < items->numitems; i++) { + if (strcasecmp(featureIdItem, items->items[i].name) == 0) { + feature["id"] = shape->values[i]; + break; + } + } + + if (i == items->numitems) + throw std::runtime_error("Feature id not found."); + + // properties - build from items and constants, no group support for now + + for (int i = 0; i < items->numitems; i++) { + try { + json item = getFeatureItem(&(items->items[i]), shape->values[i]); + if (!item.is_null()) + feature["properties"].insert(item.begin(), item.end()); + } catch (const std::runtime_error &) { + throw std::runtime_error("Error fetching item."); + } + } + + for (int i = 0; i < constants->numconstants; i++) { + try { + json constant = getFeatureConstant(&(constants->constants[i])); + if (!constant.is_null()) + feature["properties"].insert(constant.begin(), constant.end()); + } catch (const std::runtime_error &) { + throw std::runtime_error("Error fetching constant."); + } + } + + // geometry + try { + json geometry = + getFeatureGeometry(shape, geometry_precision, outputCrsAxisInverted); + if (!geometry.is_null()) + feature["geometry"] = std::move(geometry); + } catch (const std::runtime_error &) { + throw std::runtime_error("Error fetching geometry."); + } + + return feature; +} + +static json getLink(hashTableObj *metadata, const std::string &name) { + json link; + + const char *href = + msOWSLookupMetadata(metadata, "A", (name + "_href").c_str()); + if (!href) + throw std::runtime_error("Missing required link href property."); + + const char *title = + msOWSLookupMetadata(metadata, "A", (name + "_title").c_str()); + const char *type = + msOWSLookupMetadata(metadata, "A", (name + "_type").c_str()); + + link = {{"href", href}, + {"title", title ? title : href}, + {"type", type ? type : "text/html"}}; + + return link; +} + +static const char *getCollectionDescription(layerObj *layer) { + const char *description = + msOWSLookupMetadata(&(layer->metadata), "A", "description"); + if (!description) + description = msOWSLookupMetadata(&(layer->metadata), "OF", + "abstract"); // fallback on abstract + if (!description) + description = + ""; // finally + // a + // warning... + return description; +} + +static const char *getCollectionTitle(layerObj *layer) { + const char *title = msOWSLookupMetadata(&(layer->metadata), "AOF", "title"); + if (!title) + title = layer->name; // revert to layer name if no title found + return title; +} + +static int getGeometryPrecision(mapObj *map, layerObj *layer) { + int geometry_precision = OGCAPI_DEFAULT_GEOMETRY_PRECISION; + if (msOWSLookupMetadata(&(layer->metadata), "AF", "geometry_precision")) { + geometry_precision = atoi( + msOWSLookupMetadata(&(layer->metadata), "AF", "geometry_precision")); + } else if (msOWSLookupMetadata(&map->web.metadata, "AF", + "geometry_precision")) { + geometry_precision = atoi( + msOWSLookupMetadata(&map->web.metadata, "AF", "geometry_precision")); + } + return geometry_precision; +} + +static json getCollection(mapObj *map, layerObj *layer, OGCAPIFormat format, + const std::string &api_root) { + json collection; // empty (null) + rectObj bbox; + + if (!map || !layer) + return collection; + + if (!includeLayer(map, layer)) + return collection; + + // initialize some things + if (msOWSGetLayerExtent(map, layer, "AOF", &bbox) == MS_SUCCESS) { + if (layer->projection.numargs > 0) + msOWSProjectToWGS84(&layer->projection, &bbox); + else if (map->projection.numargs > 0) + msOWSProjectToWGS84(&map->projection, &bbox); + else + throw std::runtime_error( + "Unable to transform bounding box, no projection defined."); + } else { + throw std::runtime_error( + "Unable to get collection bounding box."); // might be too harsh since + // extent is optional + } + + const char *description = getCollectionDescription(layer); + const char *title = getCollectionTitle(layer); + + const char *id = layer->name; + char *id_encoded = msEncodeUrl(id); // free after use + + const int geometry_precision = getGeometryPrecision(map, layer); + + const std::string extra_params = getExtraParameterString(map, layer); + + // build collection object + collection = { + {"id", id}, + {"description", description}, + {"title", title}, + {"extent", + {{"spatial", + {{"bbox", + {{round_down(bbox.minx, geometry_precision), + round_down(bbox.miny, geometry_precision), + round_up(bbox.maxx, geometry_precision), + round_up(bbox.maxy, geometry_precision)}}}, + {"crs", CRS84_URL}}}}}, + {"links", + { + {{"rel", format == OGCAPIFormat::JSON ? "self" : "alternate"}, + {"type", OGCAPI_MIMETYPE_JSON}, + {"title", "This collection as JSON"}, + {"href", api_root + "/collections/" + std::string(id_encoded) + + "?f=json" + extra_params}}, + {{"rel", format == OGCAPIFormat::HTML ? "self" : "alternate"}, + {"type", OGCAPI_MIMETYPE_HTML}, + {"title", "This collection as HTML"}, + {"href", api_root + "/collections/" + std::string(id_encoded) + + "?f=html" + extra_params}}, + {{"rel", "items"}, + {"type", OGCAPI_MIMETYPE_GEOJSON}, + {"title", "Items for this collection as GeoJSON"}, + {"href", api_root + "/collections/" + std::string(id_encoded) + + "/items?f=json" + extra_params}}, + {{"rel", "items"}, + {"type", OGCAPI_MIMETYPE_HTML}, + {"title", "Items for this collection as HTML"}, + {"href", api_root + "/collections/" + std::string(id_encoded) + + "/items?f=html" + extra_params}}, + {{"rel", "http://www.opengis.net/def/rel/ogc/1.0/schema"}, + {"type", OGCAPI_MIMETYPE_JSON_SCHEMA}, + {"title", "Schema for this collection as JSON schema"}, + {"href", api_root + "/collections/" + std::string(id_encoded) + + "/schema?f=json" + extra_params}}, + {{"rel", "http://www.opengis.net/def/rel/ogc/1.0/schema"}, + {"type", OGCAPI_MIMETYPE_HTML}, + {"title", "Schema for this collection as HTML"}, + {"href", api_root + "/collections/" + std::string(id_encoded) + + "/schema?f=html" + extra_params}}, + {{"rel", "http://www.opengis.net/def/rel/ogc/1.0/queryables"}, + {"type", OGCAPI_MIMETYPE_JSON_SCHEMA}, + {"title", "Queryables for this collection as JSON schema"}, + {"href", api_root + "/collections/" + std::string(id_encoded) + + "/queryables?f=json" + extra_params}}, + {{"rel", "http://www.opengis.net/def/rel/ogc/1.0/queryables"}, + {"type", OGCAPI_MIMETYPE_HTML}, + {"title", "Queryables for this collection as HTML"}, + {"href", api_root + "/collections/" + std::string(id_encoded) + + "/queryables?f=html" + extra_params}}, + {{"rel", "http://www.opengis.net/def/rel/ogc/1.0/sortables"}, + {"type", OGCAPI_MIMETYPE_JSON_SCHEMA}, + {"title", "Sortables for this collection as JSON schema"}, + {"href", api_root + "/collections/" + std::string(id_encoded) + + "/sortables?f=json" + extra_params}}, + {{"rel", "http://www.opengis.net/def/rel/ogc/1.0/sortables"}, + {"type", OGCAPI_MIMETYPE_HTML}, + {"title", "Sortables for this collection as HTML"}, + {"href", api_root + "/collections/" + std::string(id_encoded) + + "/sortables?f=html" + extra_params}}, + }}, + {"itemType", "feature"}}; + + msFree(id_encoded); // done + + // handle optional configuration (keywords and links) + const char *value = msOWSLookupMetadata(&(layer->metadata), "A", "keywords"); + if (!value) + value = msOWSLookupMetadata(&(layer->metadata), "OF", + "keywordlist"); // fallback on keywordlist + if (value) { + std::vector keywords = msStringSplit(value, ','); + for (const std::string &keyword : keywords) { + collection["keywords"].push_back(keyword); + } + } + + value = msOWSLookupMetadata(&(layer->metadata), "A", "links"); + if (value) { + std::vector names = msStringSplit(value, ','); + for (const std::string &name : names) { + try { + json link = getLink(&(layer->metadata), name); + collection["links"].push_back(link); + } catch (const std::runtime_error &e) { + throw e; + } + } + } + + // Part 2 - CRS support + // Inspect metadata to set the "crs": [] member and "storageCrs" member + + json jCrsList = getCrsList(map, layer); + if (!jCrsList.empty()) { + collection["crs"] = std::move(jCrsList); + + std::string storageCrs = getStorageCrs(layer); + if (!storageCrs.empty()) { + collection["storageCrs"] = std::move(storageCrs); + } + } + + return collection; +} + +/* +** Output stuff... +*/ + +void msOGCAPIOutputJson( + const json &j, const char *mimetype, + const std::map> &extraHeaders) { + std::string js; + + try { + js = j.dump(); + } catch (...) { + msOGCAPIOutputError(OGCAPI_CONFIG_ERROR, + "Invalid UTF-8 data, check encoding."); + return; + } + + msIO_setHeader("Content-Type", "%s", mimetype); + for (const auto &kvp : extraHeaders) { + for (const auto &value : kvp.second) { + msIO_setHeader(kvp.first.c_str(), "%s", value.c_str()); + } + } + msIO_sendHeaders(); + msIO_printf("%s\n", js.c_str()); +} + +void msOGCAPIOutputTemplate(const char *directory, const char *filename, + const json &j, const char *mimetype) { + std::string _directory(directory); + std::string _filename(filename); + Environment env{_directory}; // catch + + // ERB-style instead of Mustache (we'll see) + // env.set_expression("<%=", "%>"); + // env.set_statement("<%", "%>"); + + // callbacks, need: + // - match (regex) + // - contains (substring) + // - URL encode + + try { + std::string js = j.dump(); + } catch (...) { + msOGCAPIOutputError(OGCAPI_CONFIG_ERROR, + "Invalid UTF-8 data, check encoding."); + return; + } + + try { + Template t = env.parse_template(_filename); // catch + std::string result = env.render(t, j); + + msIO_setHeader("Content-Type", "%s", mimetype); + msIO_sendHeaders(); + msIO_printf("%s\n", result.c_str()); + } catch (const inja::RenderError &e) { + msOGCAPIOutputError(OGCAPI_CONFIG_ERROR, "Template rendering error. " + + std::string(e.what()) + " (" + + std::string(filename) + ")."); + return; + } catch (const inja::InjaError &e) { + msOGCAPIOutputError(OGCAPI_CONFIG_ERROR, + "InjaError error. " + std::string(e.what()) + " (" + + std::string(filename) + ")." + " (" + + std::string(directory) + ")."); + return; + } catch (...) { + msOGCAPIOutputError(OGCAPI_SERVER_ERROR, + "General template handling error."); + return; + } +} + +/* +** Generic response output. +*/ +static void outputResponse( + const mapObj *map, const cgiRequestObj *request, OGCAPIFormat format, + const char *filename, const json &response, + const std::map> &extraHeaders = + std::map>()) { + std::string path; + char fullpath[MS_MAXPATHLEN]; + + if (format == OGCAPIFormat::JSON) { + msOGCAPIOutputJson(response, OGCAPI_MIMETYPE_JSON, extraHeaders); + } else if (format == OGCAPIFormat::GeoJSON) { + msOGCAPIOutputJson(response, OGCAPI_MIMETYPE_GEOJSON, extraHeaders); + } else if (format == OGCAPIFormat::OpenAPI_V3) { + msOGCAPIOutputJson(response, OGCAPI_MIMETYPE_OPENAPI_V3, extraHeaders); + } else if (format == OGCAPIFormat::JSONSchema) { + msOGCAPIOutputJson(response, OGCAPI_MIMETYPE_JSON_SCHEMA, extraHeaders); + } else if (format == OGCAPIFormat::HTML) { + path = msOGCAPIGetTemplateDirectory(map, "html_template_directory", + "OGCAPI_HTML_TEMPLATE_DIRECTORY"); + if (path.empty()) { + msOGCAPIOutputError(OGCAPI_CONFIG_ERROR, "Template directory not set."); + return; // bail + } + msBuildPath(fullpath, map->mappath, path.c_str()); + + json j; + + j["response"] = response; // nest the response so we could write the whole + // object in the template + + // extend the JSON with a few things that we need for templating + const std::string extra_params = getExtraParameterString(map, nullptr); + + j["template"] = {{"path", json::array()}, + {"params", json::object()}, + {"api_root", msOGCAPIGetApiRootUrl(map, request)}, + {"extra_params", extra_params}, + {"title", getTitle(map)}, + {"tags", json::object()}}; + + // api path + for (int i = 0; i < request->api_path_length; i++) + j["template"]["path"].push_back(request->api_path[i]); + + // parameters (optional) + for (int i = 0; i < request->NumParams; i++) { + if (request->ParamValues[i] && + strlen(request->ParamValues[i]) > 0) { // skip empty params + j["template"]["params"].update( + {{request->ParamNames[i], request->ParamValues[i]}}); + } + } + + // add custom tags (optional) + const char *tags = + msOWSLookupMetadata(&(map->web.metadata), "A", "html_tags"); + if (tags) { + std::vector names = msStringSplit(tags, ','); + for (std::string name : names) { + const char *value = msOWSLookupMetadata(&(map->web.metadata), "A", + ("tag_" + name).c_str()); + if (value) { + j["template"]["tags"].update({{name, value}}); // add object + } + } + } + + msOGCAPIOutputTemplate(fullpath, filename, j, OGCAPI_MIMETYPE_HTML); + } else { + msOGCAPIOutputError(OGCAPI_PARAM_ERROR, "Unsupported format requested."); + } +} + +/* +** Process stuff... +*/ +static int processLandingRequest(mapObj *map, cgiRequestObj *request, + OGCAPIFormat format) { + json response; + + auto allowedParameters = getExtraParameters(map, nullptr); + allowedParameters.insert("f"); + if (!msOOGCAPICheckQueryParameters(map, request, allowedParameters)) { + return MS_SUCCESS; + } + + // define ambiguous elements + const char *description = + msOWSLookupMetadata(&(map->web.metadata), "A", "description"); + if (!description) + description = + msOWSLookupMetadata(&(map->web.metadata), "OF", + "abstract"); // fallback on abstract if necessary + + const std::string extra_params = getExtraParameterString(map, nullptr); + + // define api root url + std::string api_root = msOGCAPIGetApiRootUrl(map, request); + + // build response object + // - consider conditionally excluding links for HTML format + response = { + {"title", getTitle(map)}, + {"description", description ? description : ""}, + {"links", + {{{"rel", format == OGCAPIFormat::JSON ? "self" : "alternate"}, + {"type", OGCAPI_MIMETYPE_JSON}, + {"title", "This document as JSON"}, + {"href", api_root + "?f=json" + extra_params}}, + {{"rel", format == OGCAPIFormat::HTML ? "self" : "alternate"}, + {"type", OGCAPI_MIMETYPE_HTML}, + {"title", "This document as HTML"}, + {"href", api_root + "?f=html" + extra_params}}, + {{"rel", "conformance"}, + {"type", OGCAPI_MIMETYPE_JSON}, + {"title", + "OCG API conformance classes implemented by this server (JSON)"}, + {"href", api_root + "/conformance?f=json" + extra_params}}, + {{"rel", "conformance"}, + {"type", OGCAPI_MIMETYPE_HTML}, + {"title", "OCG API conformance classes implemented by this server"}, + {"href", api_root + "/conformance?f=html" + extra_params}}, + {{"rel", "data"}, + {"type", OGCAPI_MIMETYPE_JSON}, + {"title", "Information about feature collections available from this " + "server (JSON)"}, + {"href", api_root + "/collections?f=json" + extra_params}}, + {{"rel", "data"}, + {"type", OGCAPI_MIMETYPE_HTML}, + {"title", + "Information about feature collections available from this server"}, + {"href", api_root + "/collections?f=html" + extra_params}}, + {{"rel", "service-desc"}, + {"type", OGCAPI_MIMETYPE_OPENAPI_V3}, + {"title", "OpenAPI document"}, + {"href", api_root + "/api?f=json" + extra_params}}, + {{"rel", "service-doc"}, + {"type", OGCAPI_MIMETYPE_HTML}, + {"title", "API documentation"}, + {"href", api_root + "/api?f=html" + extra_params}}}}}; + + // handle custom links (optional) + const char *links = msOWSLookupMetadata(&(map->web.metadata), "A", "links"); + if (links) { + std::vector names = msStringSplit(links, ','); + for (std::string name : names) { + try { + json link = getLink(&(map->web.metadata), name); + response["links"].push_back(link); + } catch (const std::runtime_error &e) { + msOGCAPIOutputError(OGCAPI_CONFIG_ERROR, std::string(e.what())); + return MS_SUCCESS; + } + } + } + + outputResponse(map, request, format, OGCAPI_TEMPLATE_HTML_LANDING, response); + return MS_SUCCESS; +} + +static int processConformanceRequest(mapObj *map, cgiRequestObj *request, + OGCAPIFormat format) { + json response; + + auto allowedParameters = getExtraParameters(map, nullptr); + allowedParameters.insert("f"); + if (!msOOGCAPICheckQueryParameters(map, request, allowedParameters)) { + return MS_SUCCESS; + } + + // build response object + response = { + {"conformsTo", + { + "http://www.opengis.net/spec/ogcapi-common-1/1.0/conf/core", + "http://www.opengis.net/spec/ogcapi-common-2/1.0/conf/collections", + "http://www.opengis.net/spec/ogcapi-features-1/1.0/conf/core", + "http://www.opengis.net/spec/ogcapi-features-1/1.0/conf/oas30", + "http://www.opengis.net/spec/ogcapi-features-1/1.0/conf/html", + "http://www.opengis.net/spec/ogcapi-features-1/1.0/conf/geojson", + "http://www.opengis.net/spec/ogcapi-features-2/1.0/conf/crs", + "http://www.opengis.net/spec/ogcapi-features-3/1.0/conf/queryables", + "http://www.opengis.net/spec/ogcapi-features-3/1.0/conf/" + "queryables-query-parameters", + "http://www.opengis.net/spec/ogcapi-features-3/1.0/conf/filter", + "http://www.opengis.net/spec/cql2/1.0/conf/cql2-text", + "http://www.opengis.net/spec/cql2/1.0/conf/cql2-json", + "http://www.opengis.net/spec/cql2/1.0/conf/basic-cql2", + "http://www.opengis.net/spec/cql2/1.0/conf/" + "advanced-comparison-operators", + "http://www.opengis.net/spec/cql2/1.0/conf/" + "case-insensitive-comparison", + "http://www.opengis.net/spec/cql2/1.0/conf/basic-spatial-functions", + "http://www.opengis.net/spec/cql2/1.0/conf/" + "basic-spatial-functions-plus", + "http://www.opengis.net/spec/cql2/1.0/conf/spatial-functions", + "http://www.opengis.net/spec/cql2/1.0/conf/property-property", + "http://www.opengis.net/spec/cql2/1.0/conf/arithmetic", + "http://www.opengis.net/spec/ogcapi-features-5/1.0/conf/queryables", + "http://www.opengis.net/spec/ogcapi-features-5/1.0/conf/schemas", + "http://www.opengis.net/spec/ogcapi-features-5/1.0/conf/" + "returnables-and-receivables", + "http://www.opengis.net/spec/ogcapi-features-5/1.0/conf/sortables", + }}}; + + outputResponse(map, request, format, OGCAPI_TEMPLATE_HTML_CONFORMANCE, + response); + return MS_SUCCESS; +} + +static int findLayerIndex(const mapObj *map, const char *collectionId) { + for (int i = 0; i < map->numlayers; i++) { + if (strcmp(map->layers[i]->name, collectionId) == 0) { + return i; + } + } + return -1; +} + +static int processCollectionItemsRequest(mapObj *map, cgiRequestObj *request, + const char *collectionId, + const char *featureId, + OGCAPIFormat format) { + json response; + + // find the right layer + const int iLayer = findLayerIndex(map, collectionId); + + if (iLayer < 0) { // invalid collectionId + msOGCAPIOutputError(OGCAPI_NOT_FOUND_ERROR, "Invalid collection."); + return MS_SUCCESS; + } + + layerObj *layer = map->layers[iLayer]; + layer->status = MS_ON; // force on (do we need to save and reset?) + + if (!includeLayer(map, layer)) { + msOGCAPIOutputError(OGCAPI_NOT_FOUND_ERROR, "Invalid collection."); + return MS_SUCCESS; + } + + // + // handle parameters specific to this endpoint + // + int limit = -1; + if (getLimit(map, request, layer, &limit) != MS_SUCCESS) { + msOGCAPIOutputError(OGCAPI_PARAM_ERROR, "Bad value for limit."); + return MS_SUCCESS; + } + + std::string api_root = msOGCAPIGetApiRootUrl(map, request); + const char *crs = getRequestParameter(request, "crs"); + + std::string outputCrs = "EPSG:4326"; + bool outputCrsAxisInverted = + false; // because above EPSG:4326 is meant to be OGC:CRS84 actually + std::map> extraHeaders; + if (crs) { + bool isExpectedCrs = false; + for (const auto &crsItem : getCrsList(map, layer)) { + if (crs == crsItem.get()) { + isExpectedCrs = true; + break; + } + } + if (!isExpectedCrs) { + msOGCAPIOutputError(OGCAPI_PARAM_ERROR, "Bad value for crs."); + return MS_SUCCESS; + } + extraHeaders["Content-Crs"].push_back('<' + std::string(crs) + '>'); + if (std::string(crs) != CRS84_URL) { + if (std::string(crs).find(EPSG_PREFIX_URL) == 0) { + const char *code = crs + strlen(EPSG_PREFIX_URL); + outputCrs = std::string("EPSG:") + code; + outputCrsAxisInverted = msIsAxisInverted(atoi(code)); + } + } + } else { + extraHeaders["Content-Crs"].push_back('<' + std::string(CRS84_URL) + '>'); + } + + auto reservedParameters = getExtraParameters(map, layer); + reservedParameters.insert("f"); + reservedParameters.insert("bbox"); + reservedParameters.insert("bbox-crs"); + reservedParameters.insert("datetime"); + reservedParameters.insert("limit"); + reservedParameters.insert("offset"); + reservedParameters.insert("crs"); + reservedParameters.insert("filter"); + reservedParameters.insert("filter-lang"); + reservedParameters.insert("filter-crs"); + reservedParameters.insert("sortby"); + + bool error = false; + std::vector queryableItems = + msOOGCAPIGetLayerQueryables(layer, reservedParameters, error); + if (error) { + return MS_SUCCESS; + } + + for (std::string &item : queryableItems) { + item = getItemAliasOrName(layer, item); + } + + auto allowedParameters = reservedParameters; + for (const auto &item : queryableItems) + allowedParameters.insert(item); + + if (!msOOGCAPICheckQueryParameters(map, request, allowedParameters)) { + return MS_SUCCESS; + } + + // Simple filtering like "field_name=value" + std::string filter; + std::string query_kvp; + if (!queryableItems.empty()) { + for (int i = 0; i < request->NumParams; i++) { + if (std::find(queryableItems.begin(), queryableItems.end(), + request->ParamNames[i]) != queryableItems.end()) { + + // Find actual item name from alias + const char *pszItem = nullptr; + for (int j = 0; j < layer->numitems; ++j) { + if (request->ParamNames[i] == + getItemAliasOrName(layer, layer->items[j])) { + pszItem = layer->items[j]; + break; + } + } + assert(pszItem); + + const std::string expr = FLTGetBinaryComparisonCommonExpression( + layer, pszItem, false, "=", request->ParamValues[i]); + if (!filter.empty()) + filter += " AND "; + filter += expr; + + query_kvp += '&'; + char *encoded = msEncodeUrl(request->ParamNames[i]); + query_kvp += encoded; + msFree(encoded); + query_kvp += '='; + encoded = msEncodeUrl(request->ParamValues[i]); + query_kvp += encoded; + msFree(encoded); + } + } + } + + const char *filterParam = getRequestParameter(request, "filter"); + const char *filterLang = getRequestParameter(request, "filter-lang"); + if (filterParam) { + if (filterLang && strcmp(filterLang, "cql2-text") != 0 && + strcmp(filterLang, "cql2-json") != 0) { + msOGCAPIOutputError( + OGCAPI_PARAM_ERROR, + "Only filter-lang=cql2-text or filter-lang=cql2-json is handled"); + return MS_SUCCESS; + } + + std::string osErrorMsg; + auto cql2 = (filterLang && strcmp(filterLang, "cql2-json") == 0) + ? CQL2JSONParse(filterParam, osErrorMsg) + : CQL2TextParse(filterParam, osErrorMsg); + if (!cql2) { + msOGCAPIOutputError(OGCAPI_PARAM_ERROR, + "Cannot parse filter: " + osErrorMsg); + return MS_SUCCESS; + } + + std::string filterCrs = "EPSG:4326"; + bool axisInverted = + false; // because above EPSG:4326 is meant to be OGC:CRS84 actually + const char *filterCrsParam = getRequestParameter(request, "filter-crs"); + if (filterCrsParam) { + bool isExpectedCrs = false; + for (const auto &crsItem : getCrsList(map, layer)) { + if (filterCrsParam == crsItem.get()) { + isExpectedCrs = true; + break; + } + } + if (!isExpectedCrs) { + msOGCAPIOutputError(OGCAPI_PARAM_ERROR, "Bad value for filter-crs."); + return MS_SUCCESS; + } + if (std::string(filterCrsParam) != CRS84_URL) { + if (std::string(filterCrsParam).find(EPSG_PREFIX_URL) == 0) { + const char *code = filterCrsParam + strlen(EPSG_PREFIX_URL); + filterCrs = std::string("EPSG:") + code; + axisInverted = msIsAxisInverted(atoi(code)); + } + } + } + + const char *geometryName = getGeometryName(layer); + const std::string filterFromCQL = + cql2->ToMapServerFilter(layer, queryableItems, geometryName, filterCrs, + axisInverted, osErrorMsg); + if (!osErrorMsg.empty()) { + msOGCAPIOutputError( + OGCAPI_PARAM_ERROR, + "Cannot translate CQL2 filter to MapServer expression: " + + osErrorMsg); + return MS_SUCCESS; + } + if (filter.empty()) + filter = filterFromCQL; + else { + filter = "(" + filter + ") AND (" + filterFromCQL + ")"; + } + + query_kvp += "&filter="; + char *encoded = msEncodeUrl(filterParam); + query_kvp += encoded; + msFree(encoded); + if (filterLang) { + query_kvp += "&filter-lang="; + query_kvp += filterLang; + } + if (filterCrsParam) { + query_kvp += "&filter-crs="; + encoded = msEncodeUrl(filterCrsParam); + query_kvp += encoded; + msFree(encoded); + } + } + + if (!filter.empty()) { + msDebug("filter = %s\n", filter.c_str()); + } + + const char *sortby = getRequestParameter(request, "sortby"); + if (sortby) { + query_kvp += "&sortby="; + { + char *encoded = msEncodeUrl(sortby); + query_kvp += encoded; + msFree(encoded); + } + + const auto sortables = + msOOGCAPIGetLayerSortables(layer, reservedParameters, error); + if (error) { + return MS_SUCCESS; + } + + std::vector props; + struct msFreeReleaser { + void operator()(char *s) { msFree(s); } + }; + std::vector> items; + for (const auto &item : msStringSplit(sortby, ',')) { + if (item.empty()) + continue; + sortByProperties prop; + if (item[0] == '-') { + prop.sortOrder = SORT_DESC; + items.emplace_back(msStrdup(item.c_str() + 1)); + } else if (item[0] == '+') { + prop.sortOrder = SORT_ASC; + items.emplace_back(msStrdup(item.c_str() + 1)); + } else { + prop.sortOrder = SORT_ASC; + items.emplace_back(msStrdup(item.c_str())); + } + prop.item = items.back().get(); + if (std::find_if(sortables.begin(), sortables.end(), + [&prop](const std::string &s) { + return strcasecmp(prop.item, s.c_str()) == 0; + }) == sortables.end()) { + msOGCAPIOutputError(OGCAPI_PARAM_ERROR, (std::string("'") + prop.item + + "' is not a sortable item") + .c_str()); + return MS_SUCCESS; + } + props.push_back(prop); + } + + sortByClause sortByClause; + sortByClause.nProperties = static_cast(props.size()); + sortByClause.properties = props.data(); + msLayerSetSort(layer, &sortByClause); + } + + struct ReprojectionObjects { + reprojectionObj *reprojector = NULL; + projectionObj proj; + + ReprojectionObjects() { msInitProjection(&proj); } + + ~ReprojectionObjects() { + msProjectDestroyReprojector(reprojector); + msFreeProjection(&proj); + } + + int executeQuery(mapObj *map) { + projectionObj backupMapProjection = map->projection; + map->projection = proj; + int ret = msExecuteQuery(map); + map->projection = backupMapProjection; + return ret; + } + }; + ReprojectionObjects reprObjs; + + msProjectionInheritContextFrom(&reprObjs.proj, &(map->projection)); + if (msLoadProjectionString(&reprObjs.proj, outputCrs.c_str()) != 0) { + msOGCAPIOutputError(OGCAPI_SERVER_ERROR, "Cannot instantiate output CRS."); + return MS_SUCCESS; + } + + if (layer->projection.numargs > 0) { + if (msProjectionsDiffer(&(layer->projection), &reprObjs.proj)) { + reprObjs.reprojector = + msProjectCreateReprojector(&(layer->projection), &reprObjs.proj); + if (reprObjs.reprojector == NULL) { + msOGCAPIOutputError(OGCAPI_SERVER_ERROR, + "Error creating re-projector."); + return MS_SUCCESS; + } + } + } else if (map->projection.numargs > 0) { + if (msProjectionsDiffer(&(map->projection), &reprObjs.proj)) { + reprObjs.reprojector = + msProjectCreateReprojector(&(map->projection), &reprObjs.proj); + if (reprObjs.reprojector == NULL) { + msOGCAPIOutputError(OGCAPI_SERVER_ERROR, + "Error creating re-projector."); + return MS_SUCCESS; + } + } + } else { + msOGCAPIOutputError( + OGCAPI_CONFIG_ERROR, + "Unable to transform geometries, no projection defined."); + return MS_SUCCESS; + } + + if (map->projection.numargs > 0) { + msProjectRect(&(map->projection), &reprObjs.proj, &map->extent); + } + + rectObj bbox; + if (!getBbox(map, layer, request, &bbox, &reprObjs.proj)) { + return MS_SUCCESS; + } + + int offset = 0; + int numberMatched = 0; + if (featureId) { + const char *featureIdItem = + msOWSLookupMetadata(&(layer->metadata), "AGFO", "featureid"); + if (featureIdItem == NULL) { + msOGCAPIOutputError(OGCAPI_CONFIG_ERROR, + "Missing required featureid metadata."); + return MS_SUCCESS; + } + + // TODO: does featureIdItem exist in the data? + + // optional validation + const char *featureIdValidation = + msLookupHashTable(&(layer->validation), featureIdItem); + if (featureIdValidation && + msValidateParameter(featureId, featureIdValidation, NULL, NULL, NULL) != + MS_SUCCESS) { + msOGCAPIOutputError(OGCAPI_NOT_FOUND_ERROR, "Invalid feature id."); + return MS_SUCCESS; + } + + map->query.type = MS_QUERY_BY_FILTER; + map->query.mode = MS_QUERY_SINGLE; + map->query.layer = iLayer; + map->query.rect = bbox; + map->query.filteritem = strdup(featureIdItem); + + msInitExpression(&map->query.filter); + map->query.filter.type = MS_STRING; + map->query.filter.string = strdup(featureId); + + if (reprObjs.executeQuery(map) != MS_SUCCESS) { + msOGCAPIOutputError(OGCAPI_NOT_FOUND_ERROR, + "Collection items id query failed."); + return MS_SUCCESS; + } + + if (!layer->resultcache || layer->resultcache->numresults != 1) { + msOGCAPIOutputError(OGCAPI_NOT_FOUND_ERROR, + "Collection items id query failed."); + return MS_SUCCESS; + } + } else { // bbox query + map->query.type = MS_QUERY_BY_RECT; + map->query.mode = MS_QUERY_MULTIPLE; + map->query.layer = iLayer; + map->query.rect = bbox; + map->query.only_cache_result_count = MS_TRUE; + + if (!filter.empty()) { + map->query.type = MS_QUERY_BY_FILTER; + msInitExpression(&map->query.filter); + map->query.filter.string = msStrdup(filter.c_str()); + map->query.filter.type = MS_EXPRESSION; + } + + // get number matched + if (reprObjs.executeQuery(map) != MS_SUCCESS) { + msOGCAPIOutputError(OGCAPI_NOT_FOUND_ERROR, + "Collection items query failed."); + return MS_SUCCESS; + } + + if (!layer->resultcache) { + msOGCAPIOutputError(OGCAPI_NOT_FOUND_ERROR, + "Collection items query failed."); + return MS_SUCCESS; + } + + numberMatched = layer->resultcache->numresults; + + if (numberMatched > 0) { + map->query.only_cache_result_count = MS_FALSE; + map->query.maxfeatures = limit; + + msOWSSetShapeCache(map, "AO"); + + const char *offsetStr = getRequestParameter(request, "offset"); + if (offsetStr) { + if (msStringToInt(offsetStr, &offset, 10) != MS_SUCCESS) { + msOGCAPIOutputError(OGCAPI_PARAM_ERROR, "Bad value for offset."); + return MS_SUCCESS; + } + + if (offset < 0 || offset >= numberMatched) { + msOGCAPIOutputError(OGCAPI_PARAM_ERROR, "Offset out of range."); + return MS_SUCCESS; + } + + // msExecuteQuery() use a 1-based offset convention, whereas the API + // uses a 0-based offset convention. + map->query.startindex = 1 + offset; + layer->startindex = 1 + offset; + } + + if (reprObjs.executeQuery(map) != MS_SUCCESS || !layer->resultcache) { + msOGCAPIOutputError(OGCAPI_NOT_FOUND_ERROR, + "Collection items query failed."); + return MS_SUCCESS; + } + } + } + + const std::string extra_params = getExtraParameterString(map, layer); + + // build response object + if (!featureId) { + const char *id = layer->name; + char *id_encoded = msEncodeUrl(id); // free after use + + std::string extra_kvp = "&limit=" + std::to_string(limit); + extra_kvp += "&offset=" + std::to_string(offset); + + std::string other_extra_kvp; + if (crs) + other_extra_kvp += "&crs=" + std::string(crs); + const char *bbox = getRequestParameter(request, "bbox"); + if (bbox) + other_extra_kvp += "&bbox=" + std::string(bbox); + const char *bboxCrs = getRequestParameter(request, "bbox-crs"); + if (bboxCrs) + other_extra_kvp += "&bbox-crs=" + std::string(bboxCrs); + + other_extra_kvp += query_kvp; + + response = {{"type", "FeatureCollection"}, + {"numberMatched", numberMatched}, + {"numberReturned", layer->resultcache->numresults}, + {"features", json::array()}, + {"links", + {{{"rel", format == OGCAPIFormat::JSON ? "self" : "alternate"}, + {"type", OGCAPI_MIMETYPE_GEOJSON}, + {"title", "Items for this collection as GeoJSON"}, + {"href", api_root + "/collections/" + + std::string(id_encoded) + "/items?f=json" + + extra_kvp + other_extra_kvp + extra_params}}, + {{"rel", format == OGCAPIFormat::HTML ? "self" : "alternate"}, + {"type", OGCAPI_MIMETYPE_HTML}, + {"title", "Items for this collection as HTML"}, + {"href", api_root + "/collections/" + + std::string(id_encoded) + "/items?f=html" + + extra_kvp + other_extra_kvp + extra_params}}}}}; + + if (offset + layer->resultcache->numresults < numberMatched) { + response["links"].push_back( + {{"rel", "next"}, + {"type", format == OGCAPIFormat::JSON ? OGCAPI_MIMETYPE_GEOJSON + : OGCAPI_MIMETYPE_HTML}, + {"title", "next page"}, + {"href", + api_root + "/collections/" + std::string(id_encoded) + + "/items?f=" + (format == OGCAPIFormat::JSON ? "json" : "html") + + "&limit=" + std::to_string(limit) + + "&offset=" + std::to_string(offset + limit) + other_extra_kvp + + extra_params}}); + } + + if (offset > 0) { + response["links"].push_back( + {{"rel", "prev"}, + {"type", format == OGCAPIFormat::JSON ? OGCAPI_MIMETYPE_GEOJSON + : OGCAPI_MIMETYPE_HTML}, + {"title", "previous page"}, + {"href", + api_root + "/collections/" + std::string(id_encoded) + + "/items?f=" + (format == OGCAPIFormat::JSON ? "json" : "html") + + "&limit=" + std::to_string(limit) + + "&offset=" + std::to_string(MS_MAX(0, (offset - limit))) + + other_extra_kvp + extra_params}}); + } + + extraHeaders["OGC-NumberReturned"].push_back( + std::to_string(layer->resultcache->numresults)); + extraHeaders["OGC-NumberMatched"].push_back(std::to_string(numberMatched)); + std::vector linksHeaders; + for (auto &link : response["links"]) { + linksHeaders.push_back("<" + link["href"].get() + + ">; rel=\"" + link["rel"].get() + + "\"; title=\"" + link["title"].get() + + "\"; type=\"" + link["type"].get() + + "\""); + } + extraHeaders["Link"] = std::move(linksHeaders); + + msFree(id_encoded); // done + } + + // features (items) + { + shapeObj shape; + msInitShape(&shape); + + // we piggyback on GML configuration + gmlItemListObj *items = msGMLGetItems(layer, "AG"); + gmlConstantListObj *constants = msGMLGetConstants(layer, "AG"); + + if (!items || !constants) { + msGMLFreeItems(items); + msGMLFreeConstants(constants); + msOGCAPIOutputError(OGCAPI_SERVER_ERROR, + "Error fetching layer attribute metadata."); + return MS_SUCCESS; + } + + const int geometry_precision = getGeometryPrecision(map, layer); + + for (int i = 0; i < layer->resultcache->numresults; i++) { + if (layer->resultcache->results[i].shape) { + msCopyShape(layer->resultcache->results[i].shape, &shape); + } else { + int status = + msLayerGetShape(layer, &shape, &(layer->resultcache->results[i])); + if (status != MS_SUCCESS) { + msGMLFreeItems(items); + msGMLFreeConstants(constants); + msOGCAPIOutputError(OGCAPI_SERVER_ERROR, "Error fetching feature."); + return MS_SUCCESS; + } + + if (reprObjs.reprojector) { + status = msProjectShapeEx(reprObjs.reprojector, &shape); + if (status != MS_SUCCESS) { + msGMLFreeItems(items); + msGMLFreeConstants(constants); + msFreeShape(&shape); + msOGCAPIOutputError(OGCAPI_SERVER_ERROR, + "Error reprojecting feature."); + return MS_SUCCESS; + } + } + } + + try { + json feature = getFeature(layer, &shape, items, constants, + geometry_precision, outputCrsAxisInverted); + if (featureId) { + response = std::move(feature); + } else { + response["features"].emplace_back(std::move(feature)); + } + } catch (const std::runtime_error &e) { + msGMLFreeItems(items); + msGMLFreeConstants(constants); + msFreeShape(&shape); + msOGCAPIOutputError(OGCAPI_SERVER_ERROR, + "Error getting feature. " + std::string(e.what())); + return MS_SUCCESS; + } + + msFreeShape(&shape); // next + } + + msGMLFreeItems(items); // clean up + msGMLFreeConstants(constants); + } + + // extend the response a bit for templating (HERE) + if (format == OGCAPIFormat::HTML) { + const char *title = getCollectionTitle(layer); + const char *id = layer->name; + response["collection"] = {{"id", id}, {"title", title ? title : ""}}; + } + + if (featureId) { + const char *id = layer->name; + char *id_encoded = msEncodeUrl(id); // free after use + + response["links"] = { + {{"rel", format == OGCAPIFormat::JSON ? "self" : "alternate"}, + {"type", OGCAPI_MIMETYPE_GEOJSON}, + {"title", "This document as GeoJSON"}, + {"href", api_root + "/collections/" + std::string(id_encoded) + + "/items/" + featureId + "?f=json" + extra_params}}, + {{"rel", format == OGCAPIFormat::HTML ? "self" : "alternate"}, + {"type", OGCAPI_MIMETYPE_HTML}, + {"title", "This document as HTML"}, + {"href", api_root + "/collections/" + std::string(id_encoded) + + "/items/" + featureId + "?f=html" + extra_params}}, + {{"rel", "collection"}, + {"type", OGCAPI_MIMETYPE_JSON}, + {"title", "This collection as JSON"}, + {"href", api_root + "/collections/" + std::string(id_encoded) + + "?f=json" + extra_params}}, + {{"rel", "collection"}, + {"type", OGCAPI_MIMETYPE_HTML}, + {"title", "This collection as HTML"}, + {"href", api_root + "/collections/" + std::string(id_encoded) + + "?f=html" + extra_params}}}; + + msFree(id_encoded); + + outputResponse( + map, request, + format == OGCAPIFormat::JSON ? OGCAPIFormat::GeoJSON : format, + OGCAPI_TEMPLATE_HTML_COLLECTION_ITEM, response, extraHeaders); + } else { + outputResponse( + map, request, + format == OGCAPIFormat::JSON ? OGCAPIFormat::GeoJSON : format, + OGCAPI_TEMPLATE_HTML_COLLECTION_ITEMS, response, extraHeaders); + } + return MS_SUCCESS; +} + +static std::pair +convertGmlTypeToJsonSchema(const char *gmlType) { + const char *type = "string"; + const char *format = nullptr; + if (gmlType) { + if (strcasecmp(gmlType, "Character") == 0) + type = "string"; + else if (strcasecmp(gmlType, "Date") == 0) { + type = "string"; + format = "date"; + } else if (strcasecmp(gmlType, "Time") == 0) { + type = "string"; + format = "time"; + } else if (strcasecmp(gmlType, "DateTime") == 0) { + type = "string"; + format = "date-time"; + } else if (strcasecmp(gmlType, "Integer") == 0 || + strcasecmp(gmlType, "Long") == 0) + type = "integer"; + else if (strcasecmp(gmlType, "Real") == 0) + type = "number"; + else if (strcasecmp(gmlType, "Boolean") == 0) + type = "boolean"; + } + return {type, format}; +} + +std::pair +getItemTypeAndFormat(const layerObj *layer, const std::string &item) { + const char *pszType = + msOWSLookupMetadata(&(layer->metadata), "OFG", (item + "_type").c_str()); + return convertGmlTypeToJsonSchema(pszType); +} + +static int processCollectionQueryablesRequest(mapObj *map, + const cgiRequestObj *request, + const char *collectionId, + OGCAPIFormat format) { + + // find the right layer + const int iLayer = findLayerIndex(map, collectionId); + + if (iLayer < 0) { // invalid collectionId + msOGCAPIOutputError(OGCAPI_NOT_FOUND_ERROR, "Invalid collection."); + return MS_SUCCESS; + } + + layerObj *layer = map->layers[iLayer]; + if (!includeLayer(map, layer)) { + msOGCAPIOutputError(OGCAPI_NOT_FOUND_ERROR, "Invalid collection."); + return MS_SUCCESS; + } + + auto allowedParameters = getExtraParameters(map, layer); + allowedParameters.insert("f"); + + if (!msOOGCAPICheckQueryParameters(map, request, allowedParameters)) { + return MS_SUCCESS; + } + + bool error = false; + const std::vector queryableItems = + msOOGCAPIGetLayerQueryables(layer, allowedParameters, error); + if (error) { + return MS_SUCCESS; + } + + std::unique_ptr id_encoded(msEncodeUrl(collectionId), + msFree); + + json response = { + {"$schema", "https://json-schema.org/draft/2020-12/schema"}, + {"$id", msOGCAPIGetApiRootUrl(map, request) + "/collections/" + + std::string(id_encoded.get()) + "/queryables"}, + {"type", "object"}, + {"title", getCollectionTitle(layer)}, + {"description", getCollectionDescription(layer)}, + {"properties", json::object()}, + {"additionalProperties", false}, + }; + + const char *geometryName = getGeometryName(layer); + if (geometryName[0]) { + const char *geometryFormat = getGeometryFormat(layer); + + json j = { + {"title", geometryName}, + {"description", "The geometry of the collection."}, + {"x-ogc-role", "primary-geometry"}, + {"format", geometryFormat}, + }; + response["properties"][geometryName] = j; + } + + const char *featureIdItem = + msOWSLookupMetadata(&(layer->metadata), "AGFO", "featureid"); + for (const std::string &item : queryableItems) { + json j; + const auto name = getItemAliasOrName(layer, item); + const auto [type, format] = getItemTypeAndFormat(layer, item); + j["description"] = "Queryable item '" + name + "'"; + j["type"] = type; + if (format) + j["format"] = format; + if (featureIdItem && featureIdItem == item) + j["x-ogc-role"] = "id"; + response["properties"][name] = j; + } + + std::map> extraHeaders; + outputResponse( + map, request, + format == OGCAPIFormat::JSON ? OGCAPIFormat::JSONSchema : format, + OGCAPI_TEMPLATE_HTML_COLLECTION_QUERYABLES, response, extraHeaders); + + return MS_SUCCESS; +} + +namespace { +struct Returnable { + std::string item; + std::string user_name; + std::string type; + std::string format; +}; +} // namespace + +/** Return the list of returnable items as (alias, type, format) tuples */ +static std::vector msOOGCAPIGetLayerReturnables(layerObj *layer, + bool &error) { + error = false; + std::vector returnableItems; + + // we piggyback on GML configuration + gmlItemListObj *items = msGMLGetItems(layer, "AG"); + gmlConstantListObj *constants = msGMLGetConstants(layer, "AG"); + + if (!items || !constants) { + msGMLFreeItems(items); + msGMLFreeConstants(constants); + msOGCAPIOutputError(OGCAPI_SERVER_ERROR, + "Error fetching layer attribute metadata."); + error = true; + return returnableItems; + } + + for (int i = 0; i < items->numitems; ++i) { + Returnable returnable; + returnable.item = items->items[i].name; + returnable.user_name = + items->items[i].alias ? items->items[i].alias : items->items[i].name; + const auto [type, format] = + getItemTypeAndFormat(layer, items->items[i].name); + returnable.type = type; + if (format) + returnable.format = format; + returnableItems.push_back(std::move(returnable)); + } + + for (int i = 0; i < constants->numconstants; ++i) { + Returnable returnable; + returnable.user_name = constants->constants[i].name; + const auto [type, format] = + convertGmlTypeToJsonSchema(constants->constants[i].type); + returnable.type = type; + if (format) + returnable.format = format; + returnableItems.push_back(std::move(returnable)); + } + + msGMLFreeItems(items); + msGMLFreeConstants(constants); + return returnableItems; +} + +static int processCollectionSchemaRequest(mapObj *map, + const cgiRequestObj *request, + const char *collectionId, + OGCAPIFormat format) { + + // find the right layer + const int iLayer = findLayerIndex(map, collectionId); + + if (iLayer < 0) { // invalid collectionId + msOGCAPIOutputError(OGCAPI_NOT_FOUND_ERROR, "Invalid collection."); + return MS_SUCCESS; + } + + layerObj *layer = map->layers[iLayer]; + if (!includeLayer(map, layer)) { + msOGCAPIOutputError(OGCAPI_NOT_FOUND_ERROR, "Invalid collection."); + return MS_SUCCESS; + } + + if (msLayerOpen(layer) != MS_SUCCESS || + msLayerGetItems(layer) != MS_SUCCESS) { + msOGCAPIOutputError(OGCAPI_SERVER_ERROR, "Cannot get layer fields"); + return MS_SUCCESS; + } + + auto allowedParameters = getExtraParameters(map, layer); + allowedParameters.insert("f"); + + if (!msOOGCAPICheckQueryParameters(map, request, allowedParameters)) { + return MS_SUCCESS; + } + + bool error = false; + const auto returnableItems = msOOGCAPIGetLayerReturnables(layer, error); + if (error) { + return MS_SUCCESS; + } + + std::unique_ptr id_encoded(msEncodeUrl(collectionId), + msFree); + + json response = { + {"$schema", "https://json-schema.org/draft/2020-12/schema"}, + {"$id", msOGCAPIGetApiRootUrl(map, request) + "/collections/" + + std::string(id_encoded.get()) + "/schema"}, + {"type", "object"}, + {"title", getCollectionTitle(layer)}, + {"description", getCollectionDescription(layer)}, + {"properties", json::object()}, + {"additionalProperties", false}, + }; + + const char *geometryName = getGeometryName(layer); + if (geometryName[0]) { + const char *geometryFormat = getGeometryFormat(layer); + + json j = { + {"title", geometryName}, + {"description", "The geometry of the collection."}, + {"x-ogc-role", "primary-geometry"}, + {"format", geometryFormat}, + }; + response["properties"][geometryName] = j; + } + + const char *featureIdItem = + msOWSLookupMetadata(&(layer->metadata), "AGFO", "featureid"); + for (const auto &item : returnableItems) { + json j; + j["description"] = "Returnable item '" + item.user_name + "'"; + j["type"] = item.type; + if (!item.format.empty()) + j["format"] = item.format; + if (featureIdItem && featureIdItem == item.item) + j["x-ogc-role"] = "id"; + response["properties"][item.user_name] = j; + } + + std::map> extraHeaders; + outputResponse( + map, request, + format == OGCAPIFormat::JSON ? OGCAPIFormat::JSONSchema : format, + OGCAPI_TEMPLATE_HTML_COLLECTION_SCHEMA, response, extraHeaders); + + return MS_SUCCESS; +} + +static int processCollectionSortablesRequest(mapObj *map, + const cgiRequestObj *request, + const char *collectionId, + OGCAPIFormat format) { + + // find the right layer + const int iLayer = findLayerIndex(map, collectionId); + + if (iLayer < 0) { // invalid collectionId + msOGCAPIOutputError(OGCAPI_NOT_FOUND_ERROR, "Invalid collection."); + return MS_SUCCESS; + } + + layerObj *layer = map->layers[iLayer]; + if (!includeLayer(map, layer)) { + msOGCAPIOutputError(OGCAPI_NOT_FOUND_ERROR, "Invalid collection."); + return MS_SUCCESS; + } + + if (msLayerOpen(layer) != MS_SUCCESS || + msLayerGetItems(layer) != MS_SUCCESS) { + msOGCAPIOutputError(OGCAPI_SERVER_ERROR, "Cannot get layer fields"); + return MS_SUCCESS; + } + + auto allowedParameters = getExtraParameters(map, layer); + allowedParameters.insert("f"); + + if (!msOOGCAPICheckQueryParameters(map, request, allowedParameters)) { + return MS_SUCCESS; + } + + bool error = false; + const auto sortableItems = + msOOGCAPIGetLayerSortables(layer, allowedParameters, error); + if (error) { + return MS_SUCCESS; + } + + std::unique_ptr id_encoded(msEncodeUrl(collectionId), + msFree); + + json response = { + {"$schema", "https://json-schema.org/draft/2020-12/schema"}, + {"$id", msOGCAPIGetApiRootUrl(map, request) + "/collections/" + + std::string(id_encoded.get()) + "/sortables"}, + {"type", "object"}, + {"title", getCollectionTitle(layer)}, + {"description", getCollectionDescription(layer)}, + {"properties", json::object()}, + {"additionalProperties", false}, + }; + + const char *featureIdItem = + msOWSLookupMetadata(&(layer->metadata), "AGFO", "featureid"); + for (const std::string &item : sortableItems) { + json j; + const auto name = getItemAliasOrName(layer, item); + j["description"] = "Sortable item '" + name + "'"; + const auto [type, format] = getItemTypeAndFormat(layer, item); + j["type"] = type; + if (format) + j["format"] = format; + if (featureIdItem && featureIdItem == item) + j["x-ogc-role"] = "id"; + response["properties"][name] = j; + } + + std::map> extraHeaders; + outputResponse( + map, request, + format == OGCAPIFormat::JSON ? OGCAPIFormat::JSONSchema : format, + OGCAPI_TEMPLATE_HTML_COLLECTION_SORTABLES, response, extraHeaders); + + return MS_SUCCESS; +} + +static int processCollectionRequest(mapObj *map, cgiRequestObj *request, + const char *collectionId, + OGCAPIFormat format) { + json response; + int l; + + for (l = 0; l < map->numlayers; l++) { + if (strcmp(map->layers[l]->name, collectionId) == 0) + break; // match + } + + if (l == map->numlayers) { // invalid collectionId + msOGCAPIOutputError(OGCAPI_NOT_FOUND_ERROR, "Invalid collection."); + return MS_SUCCESS; + } + + layerObj *layer = map->layers[l]; + auto allowedParameters = getExtraParameters(map, layer); + allowedParameters.insert("f"); + if (!msOOGCAPICheckQueryParameters(map, request, allowedParameters)) { + return MS_SUCCESS; + } + + try { + response = + getCollection(map, layer, format, msOGCAPIGetApiRootUrl(map, request)); + if (response.is_null()) { // same as not found + msOGCAPIOutputError(OGCAPI_NOT_FOUND_ERROR, "Invalid collection."); + return MS_SUCCESS; + } + } catch (const std::runtime_error &e) { + msOGCAPIOutputError(OGCAPI_CONFIG_ERROR, + "Error getting collection. " + std::string(e.what())); + return MS_SUCCESS; + } + + outputResponse(map, request, format, OGCAPI_TEMPLATE_HTML_COLLECTION, + response); + return MS_SUCCESS; +} + +static int processCollectionsRequest(mapObj *map, cgiRequestObj *request, + OGCAPIFormat format) { + json response; + int i; + + auto allowedParameters = getExtraParameters(map, nullptr); + allowedParameters.insert("f"); + if (!msOOGCAPICheckQueryParameters(map, request, allowedParameters)) { + return MS_SUCCESS; + } + + // define api root url + std::string api_root = msOGCAPIGetApiRootUrl(map, request); + const std::string extra_params = getExtraParameterString(map, nullptr); + + // build response object + response = {{"links", + {{{"rel", format == OGCAPIFormat::JSON ? "self" : "alternate"}, + {"type", OGCAPI_MIMETYPE_JSON}, + {"title", "This document as JSON"}, + {"href", api_root + "/collections?f=json" + extra_params}}, + {{"rel", format == OGCAPIFormat::HTML ? "self" : "alternate"}, + {"type", OGCAPI_MIMETYPE_HTML}, + {"title", "This document as HTML"}, + {"href", api_root + "/collections?f=html" + extra_params}}}}, + {"collections", json::array()}}; + + for (i = 0; i < map->numlayers; i++) { + try { + json collection = getCollection(map, map->layers[i], format, api_root); + if (!collection.is_null()) + response["collections"].push_back(collection); + } catch (const std::runtime_error &e) { + msOGCAPIOutputError(OGCAPI_CONFIG_ERROR, + "Error getting collection." + std::string(e.what())); + return MS_SUCCESS; + } + } + + outputResponse(map, request, format, OGCAPI_TEMPLATE_HTML_COLLECTIONS, + response); + return MS_SUCCESS; +} + +static int processApiRequest(mapObj *map, cgiRequestObj *request, + OGCAPIFormat format) { + // Strongly inspired from + // https://github.com/geopython/pygeoapi/blob/master/pygeoapi/openapi.py + + auto allowedParameters = getExtraParameters(map, nullptr); + allowedParameters.insert("f"); + if (!msOOGCAPICheckQueryParameters(map, request, allowedParameters)) { + return MS_SUCCESS; + } + + json response; + + response = { + {"openapi", "3.0.2"}, + {"tags", json::array()}, + }; + + response["info"] = { + {"title", getTitle(map)}, + {"version", getWebMetadata(map, "A", "version", "1.0.0")}, + }; + + for (const char *item : {"description", "termsOfService"}) { + const char *value = getWebMetadata(map, "AO", item, nullptr); + if (value) { + response["info"][item] = value; + } + } + + for (const auto &pair : { + std::make_pair("name", "contactperson"), + std::make_pair("url", "contacturl"), + std::make_pair("email", "contactelectronicmailaddress"), + }) { + const char *value = getWebMetadata(map, "AO", pair.second, nullptr); + if (value) { + response["info"]["contact"][pair.first] = value; + } + } + + for (const auto &pair : { + std::make_pair("name", "licensename"), + std::make_pair("url", "licenseurl"), + }) { + const char *value = getWebMetadata(map, "AO", pair.second, nullptr); + if (value) { + response["info"]["license"][pair.first] = value; + } + } + + { + const char *value = getWebMetadata(map, "AO", "keywords", nullptr); + if (value) { + response["info"]["x-keywords"] = value; + } + } + + json server; + server["url"] = msOGCAPIGetApiRootUrl(map, request); + + { + const char *value = + getWebMetadata(map, "AO", "server_description", nullptr); + if (value) { + server["description"] = value; + } + } + response["servers"].push_back(server); + + const std::string oapif_schema_base_url = msOWSGetSchemasLocation(map); + const std::string oapif_yaml_url = oapif_schema_base_url + + "/ogcapi/features/part1/1.0/openapi/" + "ogcapi-features-1.yaml"; + const std::string oapif_part2_yaml_url = oapif_schema_base_url + + "/ogcapi/features/part2/1.0/openapi/" + "ogcapi-features-2.yaml"; + const std::string oapif_part3_yaml_url = oapif_schema_base_url + + "/ogcapi/features/part3/1.0/openapi/" + "ogcapi-features-3.yaml"; + + json paths; + + paths["/"]["get"] = { + {"summary", "Landing page"}, + {"description", "Landing page"}, + {"tags", {"server"}}, + {"operationId", "getLandingPage"}, + {"parameters", + { + {{"$ref", "#/components/parameters/f"}}, + }}, + {"responses", + {{"200", + {{"$ref", oapif_yaml_url + "#/components/responses/LandingPage"}}}, + {"400", + {{"$ref", + oapif_yaml_url + "#/components/responses/InvalidParameter"}}}, + {"500", + {{"$ref", oapif_yaml_url + "#/components/responses/ServerError"}}}}}}; + + paths["/api"]["get"] = { + {"summary", "API documentation"}, + {"description", "API documentation"}, + {"tags", {"server"}}, + {"operationId", "getOpenapi"}, + {"parameters", + { + {{"$ref", "#/components/parameters/f"}}, + }}, + {"responses", + {{"200", {{"$ref", "#/components/responses/200"}}}, + {"400", + {{"$ref", + oapif_yaml_url + "#/components/responses/InvalidParameter"}}}, + {"default", {{"$ref", "#/components/responses/default"}}}}}}; + + paths["/conformance"]["get"] = { + {"summary", "API conformance definition"}, + {"description", "API conformance definition"}, + {"tags", {"server"}}, + {"operationId", "getConformanceDeclaration"}, + {"parameters", + { + {{"$ref", "#/components/parameters/f"}}, + }}, + {"responses", + {{"200", + {{"$ref", + oapif_yaml_url + "#/components/responses/ConformanceDeclaration"}}}, + {"400", + {{"$ref", + oapif_yaml_url + "#/components/responses/InvalidParameter"}}}, + {"500", + {{"$ref", oapif_yaml_url + "#/components/responses/ServerError"}}}}}}; + + paths["/collections"]["get"] = { + {"summary", "Collections"}, + {"description", "Collections"}, + {"tags", {"server"}}, + {"operationId", "getCollections"}, + {"parameters", + { + {{"$ref", "#/components/parameters/f"}}, + }}, + {"responses", + {{"200", + {{"$ref", oapif_yaml_url + "#/components/responses/Collections"}}}, + {"400", + {{"$ref", + oapif_yaml_url + "#/components/responses/InvalidParameter"}}}, + {"500", + {{"$ref", oapif_yaml_url + "#/components/responses/ServerError"}}}}}}; + + for (int i = 0; i < map->numlayers; i++) { + layerObj *layer = map->layers[i]; + if (!includeLayer(map, layer)) { + continue; + } + + json collection_get = { + {"summary", + std::string("Get ") + getCollectionTitle(layer) + " metadata"}, + {"description", getCollectionDescription(layer)}, + {"tags", {layer->name}}, + {"operationId", "describe" + std::string(layer->name) + "Collection"}, + {"parameters", + { + {{"$ref", "#/components/parameters/f"}}, + }}, + {"responses", + {{"200", + {{"$ref", oapif_yaml_url + "#/components/responses/Collection"}}}, + {"400", + {{"$ref", + oapif_yaml_url + "#/components/responses/InvalidParameter"}}}, + {"500", + {{"$ref", + oapif_yaml_url + "#/components/responses/ServerError"}}}}}}; + + std::string collectionNamePath("/collections/"); + collectionNamePath += layer->name; + paths[collectionNamePath]["get"] = std::move(collection_get); + + // check metadata, layer then map + const char *max_limit_str = + msOWSLookupMetadata(&(layer->metadata), "A", "max_limit"); + if (max_limit_str == nullptr) + max_limit_str = + msOWSLookupMetadata(&(map->web.metadata), "A", "max_limit"); + const int max_limit = + max_limit_str ? atoi(max_limit_str) : OGCAPI_MAX_LIMIT; + const int default_limit = getDefaultLimit(map, layer); + + json items_get = { + {"summary", std::string("Get ") + getCollectionTitle(layer) + " items"}, + {"description", getCollectionDescription(layer)}, + {"tags", {layer->name}}, + {"operationId", "get" + std::string(layer->name) + "Features"}, + {"parameters", + { + {{"$ref", "#/components/parameters/f"}}, + {{"$ref", oapif_yaml_url + "#/components/parameters/bbox"}}, + {{"$ref", oapif_yaml_url + "#/components/parameters/datetime"}}, + {{"$ref", + oapif_part2_yaml_url + "#/components/parameters/bbox-crs"}}, + {{"$ref", oapif_part2_yaml_url + "#/components/parameters/crs"}}, + {{"$ref", "#/components/parameters/offset"}}, + {{"$ref", "#/components/parameters/vendorSpecificParameters"}}, + {{"$ref", + oapif_part3_yaml_url + "#/components/parameters/filter"}}, + {{"$ref", + oapif_part3_yaml_url + "#/components/parameters/filter-lang"}}, + {{"$ref", + oapif_part3_yaml_url + "#/components/parameters/filter-crs"}}, + }}, + {"responses", + {{"200", + {{"$ref", oapif_yaml_url + "#/components/responses/Features"}}}, + {"400", + {{"$ref", + oapif_yaml_url + "#/components/responses/InvalidParameter"}}}, + {"500", + {{"$ref", + oapif_yaml_url + "#/components/responses/ServerError"}}}}}}; + + json param_limit = { + {"name", "limit"}, + {"in", "query"}, + {"description", "The optional limit parameter limits the number of " + "items that are presented in the response document."}, + {"required", false}, + {"schema", + { + {"type", "integer"}, + {"minimum", 1}, + {"maximum", max_limit}, + {"default", default_limit}, + }}, + {"style", "form"}, + {"explode", false}, + }; + items_get["parameters"].emplace_back(param_limit); + + json param_sortby = { + {"name", "sortby"}, + {"in", "query"}, + {"description", + "Optional list of properties by which to sort the items."}, + {"required", false}, + {"schema", + { + {"type", "array"}, + {"minItems", 1}, + {"items", + { + {"type", "string"}, + {"pattern", "[+|-]?[A-Za-z_].*"}, + }}, + }}, + {"style", "form"}, + {"explode", false}, + }; + items_get["parameters"].emplace_back(param_sortby); + + bool error = false; + auto reservedParams = getExtraParameters(map, layer); + reservedParams.insert("f"); + reservedParams.insert("bbox"); + reservedParams.insert("bbox-crs"); + reservedParams.insert("datetime"); + reservedParams.insert("limit"); + reservedParams.insert("offset"); + reservedParams.insert("crs"); + reservedParams.insert("filter"); + reservedParams.insert("filter-lang"); + reservedParams.insert("filter-crs"); + reservedParams.insert("sortby"); + const std::vector queryableItems = + msOOGCAPIGetLayerQueryables(layer, reservedParams, error); + for (const auto &item : queryableItems) { + const auto name = getItemAliasOrName(layer, item); + const auto [type, format] = getItemTypeAndFormat(layer, item); + json queryable_param = { + {"name", name}, + {"in", "query"}, + {"description", "Queryable item '" + name + "'"}, + {"required", false}, + {"schema", + { + {"type", type}, + }}, + {"style", "form"}, + {"explode", false}, + }; + if (format) { + queryable_param["schema"]["format"] = format; + } + items_get["parameters"].emplace_back(queryable_param); + } + + std::string itemsPath(collectionNamePath + "/items"); + paths[itemsPath]["get"] = std::move(items_get); + + json schema_get = { + {"summary", + std::string("Get ") + getCollectionTitle(layer) + " schema"}, + {"description", + std::string("Get ") + getCollectionTitle(layer) + " schema"}, + {"tags", {layer->name}}, + {"operationId", "get" + std::string(layer->name) + "Schema"}, + {"parameters", + { + {{"$ref", "#/components/parameters/f"}}, + {{"$ref", "#/components/parameters/vendorSpecificParameters"}}, + }}, + {"responses", + {{"200", + {{"description", "The returnable properties of the collection."}, + {"content", + {{"application/schema+json", + {{"schema", {{"type", "object"}}}}}}}}}, + {"400", + {{"$ref", + oapif_yaml_url + "#/components/responses/InvalidParameter"}}}, + {"500", + {{"$ref", + oapif_yaml_url + "#/components/responses/ServerError"}}}}}}; + + std::string schemaPath(collectionNamePath + "/schema"); + paths[schemaPath]["get"] = std::move(schema_get); + + json queryables_get = { + {"summary", + std::string("Get ") + getCollectionTitle(layer) + " queryables"}, + {"description", + std::string("Get ") + getCollectionTitle(layer) + " queryables"}, + {"tags", {layer->name}}, + {"operationId", "get" + std::string(layer->name) + "Queryables"}, + {"parameters", + { + {{"$ref", "#/components/parameters/f"}}, + {{"$ref", "#/components/parameters/vendorSpecificParameters"}}, + }}, + {"responses", + {{"200", + {{"description", "The queryable properties of the collection."}, + {"content", + {{"application/schema+json", + {{"schema", {{"type", "object"}}}}}}}}}, + {"400", + {{"$ref", + oapif_yaml_url + "#/components/responses/InvalidParameter"}}}, + {"500", + {{"$ref", + oapif_yaml_url + "#/components/responses/ServerError"}}}}}}; + + std::string queryablesPath(collectionNamePath + "/queryables"); + paths[queryablesPath]["get"] = std::move(queryables_get); + + json sortables_get = { + {"summary", + std::string("Get ") + getCollectionTitle(layer) + " sortables"}, + {"description", + std::string("Get ") + getCollectionTitle(layer) + " sortables"}, + {"tags", {layer->name}}, + {"operationId", "get" + std::string(layer->name) + "Sortables"}, + {"parameters", + { + {{"$ref", "#/components/parameters/f"}}, + {{"$ref", "#/components/parameters/vendorSpecificParameters"}}, + }}, + {"responses", + {{"200", + {{"description", "The sortable properties of the collection."}, + {"content", + {{"application/schema+json", + {{"schema", {{"type", "object"}}}}}}}}}, + {"400", + {{"$ref", + oapif_yaml_url + "#/components/responses/InvalidParameter"}}}, + {"500", + {{"$ref", + oapif_yaml_url + "#/components/responses/ServerError"}}}}}}; + + std::string sortablesPath(collectionNamePath + "/sortables"); + paths[sortablesPath]["get"] = std::move(sortables_get); + + json feature_id_get = { + {"summary", + std::string("Get ") + getCollectionTitle(layer) + " item by id"}, + {"description", getCollectionDescription(layer)}, + {"tags", {layer->name}}, + {"operationId", "get" + std::string(layer->name) + "Feature"}, + {"parameters", + { + {{"$ref", "#/components/parameters/f"}}, + {{"$ref", oapif_yaml_url + "#/components/parameters/featureId"}}, + }}, + {"responses", + {{"200", + {{"$ref", oapif_yaml_url + "#/components/responses/Feature"}}}, + {"400", + {{"$ref", + oapif_yaml_url + "#/components/responses/InvalidParameter"}}}, + {"404", + {{"$ref", oapif_yaml_url + "#/components/responses/NotFound"}}}, + {"500", + {{"$ref", + oapif_yaml_url + "#/components/responses/ServerError"}}}}}}; + std::string itemsFeatureIdPath(collectionNamePath + "/items/{featureId}"); + paths[itemsFeatureIdPath]["get"] = std::move(feature_id_get); + } + + response["paths"] = std::move(paths); + + json components; + components["responses"]["200"] = {{"description", "successful operation"}}; + components["responses"]["default"] = { + {"description", "unexpected error"}, + {"content", + {{"application/json", + {{"schema", + {{"$ref", "https://schemas.opengis.net/ogcapi/common/part1/1.0/" + "openapi/schemas/exception.yaml"}}}}}}}}; + + json parameters; + parameters["f"] = { + {"name", "f"}, + {"in", "query"}, + {"description", "The optional f parameter indicates the output format " + "which the server shall provide as part of the response " + "document. The default format is GeoJSON."}, + {"required", false}, + {"schema", + {{"type", "string"}, {"enum", {"json", "html"}}, {"default", "json"}}}, + {"style", "form"}, + {"explode", false}, + }; + + parameters["offset"] = { + {"name", "offset"}, + {"in", "query"}, + {"description", + "The optional offset parameter indicates the index within the result " + "set from which the server shall begin presenting results in the " + "response document. The first element has an index of 0 (default)."}, + {"required", false}, + {"schema", + { + {"type", "integer"}, + {"minimum", 0}, + {"default", 0}, + }}, + {"style", "form"}, + {"explode", false}, + }; + + parameters["vendorSpecificParameters"] = { + {"name", "vendorSpecificParameters"}, + {"in", "query"}, + {"description", + "Additional \"free-form\" parameters that are not explicitly defined"}, + {"schema", + { + {"type", "object"}, + {"additionalProperties", true}, + }}, + {"style", "form"}, + }; + + components["parameters"] = std::move(parameters); + + response["components"] = std::move(components); + + // TODO: "tags" array ? + + outputResponse(map, request, + format == OGCAPIFormat::JSON ? OGCAPIFormat::OpenAPI_V3 + : format, + OGCAPI_TEMPLATE_HTML_OPENAPI, response); + return MS_SUCCESS; +} + +#endif + +OGCAPIFormat msOGCAPIGetOutputFormat(const cgiRequestObj *request) { + OGCAPIFormat format; // all endpoints need a format + const char *p = getRequestParameter(request, "f"); + + // if f= query parameter is not specified, use HTTP Accept header if available + if (p == nullptr) { + const char *accept = getenv("HTTP_ACCEPT"); + if (accept) { + if (strcmp(accept, "*/*") == 0) + p = OGCAPI_MIMETYPE_JSON; + else + p = accept; + } + } + + if (p && + (strcmp(p, "json") == 0 || strstr(p, OGCAPI_MIMETYPE_JSON) != nullptr || + strstr(p, OGCAPI_MIMETYPE_GEOJSON) != nullptr || + strstr(p, OGCAPI_MIMETYPE_OPENAPI_V3) != nullptr)) { + format = OGCAPIFormat::JSON; + } else if (p && (strcmp(p, "html") == 0 || + strstr(p, OGCAPI_MIMETYPE_HTML) != nullptr)) { + format = OGCAPIFormat::HTML; + } else if (p) { + format = OGCAPIFormat::Invalid; + } else { + format = OGCAPIFormat::HTML; // default for now + } + + return format; +} + +int msOGCAPIDispatchRequest(mapObj *map, cgiRequestObj *request) { +#ifdef USE_OGCAPI_SVR + + // make sure ogcapi requests are enabled for this map + int status = msOWSRequestIsEnabled(map, NULL, "AO", "OGCAPI", MS_FALSE); + if (status != MS_TRUE) { + msSetError(MS_OGCAPIERR, "OGC API requests are not enabled.", + "msCGIDispatchAPIRequest()"); + return MS_FAILURE; // let normal error handling take over + } + + for (int i = 0; i < request->NumParams; i++) { + for (int j = i + 1; j < request->NumParams; j++) { + if (strcmp(request->ParamNames[i], request->ParamNames[j]) == 0) { + std::string errorMsg("Query parameter "); + errorMsg += request->ParamNames[i]; + errorMsg += " is repeated"; + msOGCAPIOutputError(OGCAPI_PARAM_ERROR, errorMsg.c_str()); + return MS_SUCCESS; + } + } + } + + const OGCAPIFormat format = msOGCAPIGetOutputFormat(request); + + if (format == OGCAPIFormat::Invalid) { + msOGCAPIOutputError(OGCAPI_PARAM_ERROR, "Unsupported format requested."); + return MS_SUCCESS; // avoid any downstream MapServer processing + } + + if (request->api_path_length == 2) { + + return processLandingRequest(map, request, format); + + } else if (request->api_path_length == 3) { + + if (strcmp(request->api_path[2], "conformance") == 0) { + return processConformanceRequest(map, request, format); + } else if (strcmp(request->api_path[2], "conformance.html") == 0) { + return processConformanceRequest(map, request, OGCAPIFormat::HTML); + } else if (strcmp(request->api_path[2], "collections") == 0) { + return processCollectionsRequest(map, request, format); + } else if (strcmp(request->api_path[2], "collections.html") == 0) { + return processCollectionsRequest(map, request, OGCAPIFormat::HTML); + } else if (strcmp(request->api_path[2], "api") == 0) { + return processApiRequest(map, request, format); + } + + } else if (request->api_path_length == 4) { + + if (strcmp(request->api_path[2], "collections") == + 0) { // next argument (3) is collectionId + return processCollectionRequest(map, request, request->api_path[3], + format); + } + + } else if (request->api_path_length == 5) { + + if (strcmp(request->api_path[2], "collections") == 0 && + strcmp(request->api_path[4], "items") == + 0) { // middle argument (3) is the collectionId + return processCollectionItemsRequest(map, request, request->api_path[3], + NULL, format); + } else if (strcmp(request->api_path[2], "collections") == 0 && + strcmp(request->api_path[4], "queryables") == 0) { + return processCollectionQueryablesRequest(map, request, + request->api_path[3], format); + } else if (strcmp(request->api_path[2], "collections") == 0 && + strcmp(request->api_path[4], "schema") == 0) { + return processCollectionSchemaRequest(map, request, request->api_path[3], + format); + } else if (strcmp(request->api_path[2], "collections") == 0 && + strcmp(request->api_path[4], "sortables") == 0) { + return processCollectionSortablesRequest(map, request, + request->api_path[3], format); + } + } else if (request->api_path_length == 6) { + + if (strcmp(request->api_path[2], "collections") == 0 && + strcmp(request->api_path[4], "items") == + 0) { // middle argument (3) is the collectionId, last argument (5) + // is featureId + return processCollectionItemsRequest(map, request, request->api_path[3], + request->api_path[5], format); + } + } + + msOGCAPIOutputError(OGCAPI_NOT_FOUND_ERROR, "Invalid API path."); + return MS_SUCCESS; // avoid any downstream MapServer processing +#else + msSetError(MS_OGCAPIERR, "OGC API server support is not enabled.", + "msOGCAPIDispatchRequest()"); + return MS_FAILURE; +#endif +} diff --git a/src/mapogcapi.h b/src/mapogcapi.h new file mode 100644 index 0000000000..0a260418e4 --- /dev/null +++ b/src/mapogcapi.h @@ -0,0 +1,91 @@ +/********************************************************************** + * $Id$ + * + * Project: MapServer + * Purpose: OGCAPI Implementation + * Author: Steve Lime and the MapServer team. + * + ********************************************************************** + * Copyright (c) 1996-2005 Regents of the University of Minnesota. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + ****************************************************************************/ + +#ifndef MAPOGCAPI_H +#define MAPOGCAPI_H + +#ifdef __cplusplus +extern "C" { +#endif + +int msOGCAPIDispatchRequest(mapObj *map, cgiRequestObj *request); + +#ifdef __cplusplus +} + +#include +#include +#include "third-party/include_nlohmann_json.hpp" +#include "third-party/include_pantor_inja.hpp" + +// Error types +typedef enum { + OGCAPI_SERVER_ERROR = 0, + OGCAPI_CONFIG_ERROR = 1, + OGCAPI_PARAM_ERROR = 2, + OGCAPI_NOT_FOUND_ERROR = 3, +} OGCAPIErrorType; + +enum class OGCAPIFormat { + JSON, + GeoJSON, + OpenAPI_V3, + JSONSchema, + HTML, + Invalid +}; + +#define OGCAPI_MIMETYPE_JSON "application/json" +#define OGCAPI_MIMETYPE_GEOJSON "application/geo+json" +#define OGCAPI_MIMETYPE_OPENAPI_V3 \ + "application/vnd.oai.openapi+json;version=3.0" +#define OGCAPI_MIMETYPE_JSON_SCHEMA "application/schema+json" +#define OGCAPI_MIMETYPE_HTML "text/html" + +std::string msOGCAPIGetTemplateDirectory(const mapObj *map, const char *key, + const char *envvar); + +OGCAPIFormat msOGCAPIGetOutputFormat(const cgiRequestObj *request); + +std::string msOGCAPIGetApiRootUrl(const mapObj *map, + const cgiRequestObj *request, + const char *namespaces = "AO"); + +void msOGCAPIOutputError(OGCAPIErrorType errorType, + const std::string &description); + +void msOGCAPIOutputJson( + const nlohmann::json &j, const char *mimetype, + const std::map> &extraHeaders); + +void msOGCAPIOutputTemplate(const char *directory, const char *filename, + const nlohmann::json &j, const char *mimetype); + +#endif + +#endif diff --git a/src/mapogcfilter.cpp b/src/mapogcfilter.cpp new file mode 100644 index 0000000000..e5e2aeca25 --- /dev/null +++ b/src/mapogcfilter.cpp @@ -0,0 +1,3204 @@ +/********************************************************************** + * $Id$ + * + * Project: MapServer + * Purpose: OGC Filter Encoding implementation + * Author: Y. Assefa, DM Solutions Group (assefa@dmsolutions.ca) + * + ********************************************************************** + * Copyright (c) 2003, Y. Assefa, DM Solutions Group Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + ****************************************************************************/ + +#include "mapserver-config.h" + +#include "cpl_minixml.h" +#include "cpl_string.h" + +#include "mapogcfilter.h" +#include "mapserver.h" +#include "mapowscommon.h" +#include "maptime.h" +#include "mapows.h" +#include + +#if 0 +static int FLTHasUniqueTopLevelDuringFilter(FilterEncodingNode *psFilterNode); +#endif + +#if !(defined(_WIN32) && !defined(__CYGWIN__)) +static inline void IGUR_double(double ignored) { + (void)ignored; +} /* Ignore GCC Unused Result */ +#endif + +int FLTIsNumeric(const char *pszValue) { + if (pszValue != NULL && *pszValue != '\0' && !isspace(*pszValue)) { + /*the regex seems to have a problem on windows when mapserver is built using + PHP regex*/ +#if defined(_WIN32) && !defined(__CYGWIN__) + int i = 0, nLength = 0, bString = 0; + + nLength = strlen(pszValue); + for (i = 0; i < nLength; i++) { + if (i == 0) { + if (!isdigit(pszValue[i]) && pszValue[i] != '-') { + bString = 1; + break; + } + } else if (!isdigit(pszValue[i]) && pszValue[i] != '.') { + bString = 1; + break; + } + } + if (!bString) + return MS_TRUE; +#else + char *p; + IGUR_double(strtod(pszValue, &p)); + if (p != pszValue && *p == '\0') + return MS_TRUE; +#endif + } + + return MS_FALSE; +} + +/* +** Apply an expression to the layer's filter element. +** +*/ +int FLTApplyExpressionToLayer(layerObj *lp, const char *pszExpression) { + char *pszFinalExpression = NULL, *pszBuffer = NULL; + /*char *escapedTextString=NULL;*/ + int bConcatWhere = 0, bHasAWhere = 0; + + if (lp && pszExpression) { + if (lp->connectiontype == MS_POSTGIS || + lp->connectiontype == MS_ORACLESPATIAL || + lp->connectiontype == MS_PLUGIN) { + pszFinalExpression = msStrdup("("); + pszFinalExpression = + msStringConcatenate(pszFinalExpression, pszExpression); + pszFinalExpression = msStringConcatenate(pszFinalExpression, ")"); + } else if (lp->connectiontype == MS_OGR) { + pszFinalExpression = msStrdup(pszExpression); + if (lp->filter.type != MS_EXPRESSION) { + bConcatWhere = 1; + } else { + if (lp->filter.string && EQUALN(lp->filter.string, "WHERE ", 6)) { + bHasAWhere = 1; + bConcatWhere = 1; + } + } + + } else + pszFinalExpression = msStrdup(pszExpression); + + if (bConcatWhere) + pszBuffer = msStringConcatenate(pszBuffer, "WHERE "); + /* if the filter is set and it's an expression type, concatenate it with + this filter. If not just free it */ + if (lp->filter.string && lp->filter.type == MS_EXPRESSION) { + pszBuffer = msStringConcatenate(pszBuffer, "(("); + if (bHasAWhere) + pszBuffer = msStringConcatenate(pszBuffer, lp->filter.string + 6); + else + pszBuffer = msStringConcatenate(pszBuffer, lp->filter.string); + pszBuffer = msStringConcatenate(pszBuffer, ") and "); + } else if (lp->filter.string) + msFreeExpression(&lp->filter); + + pszBuffer = msStringConcatenate(pszBuffer, pszFinalExpression); + + if (lp->filter.string && lp->filter.type == MS_EXPRESSION) + pszBuffer = msStringConcatenate(pszBuffer, ")"); + + /*assuming that expression was properly escaped + escapedTextString = msStringEscape(pszBuffer); + msLoadExpressionString(&lp->filter, + (char*)CPLSPrintf("%s", escapedTextString)); + msFree(escapedTextString); + */ + msLoadExpressionString(&lp->filter, pszBuffer); + + msFree(pszFinalExpression); + + if (pszBuffer) + msFree(pszBuffer); + + return MS_TRUE; + } + + return MS_FALSE; +} + +char *FLTGetExpressionForValuesRanges(layerObj *lp, const char *item, + const char *value, int forcecharcter) { + int bIscharacter; + char *pszExpression = NULL, *pszTmpExpression = NULL; + char **paszElements = NULL, **papszRangeElements = NULL; + int numelements, i, nrangeelements; + + /* double minval, maxval; */ + if (lp && item && value) { + if (strstr(value, "/") == NULL) { + /*value(s)*/ + paszElements = msStringSplit(value, ',', &numelements); + if (paszElements && numelements > 0) { + if (forcecharcter) + bIscharacter = MS_TRUE; + else + bIscharacter = !FLTIsNumeric(paszElements[0]); + + pszTmpExpression = msStringConcatenate(pszTmpExpression, "("); + for (i = 0; i < numelements; i++) { + pszTmpExpression = msStringConcatenate(pszTmpExpression, "("); + { + if (bIscharacter) + pszTmpExpression = msStringConcatenate(pszTmpExpression, "\""); + pszTmpExpression = msStringConcatenate(pszTmpExpression, "["); + pszTmpExpression = msStringConcatenate(pszTmpExpression, item); + pszTmpExpression = msStringConcatenate(pszTmpExpression, "]"); + if (bIscharacter) + pszTmpExpression = msStringConcatenate(pszTmpExpression, "\""); + } + if (bIscharacter) { + pszTmpExpression = msStringConcatenate(pszTmpExpression, " = \""); + } else + pszTmpExpression = msStringConcatenate(pszTmpExpression, " = "); + + { + char *pszEscapedStr = msLayerEscapeSQLParam(lp, paszElements[i]); + pszTmpExpression = + msStringConcatenate(pszTmpExpression, pszEscapedStr); + msFree(pszEscapedStr); + } + + if (bIscharacter) { + pszTmpExpression = msStringConcatenate(pszTmpExpression, "\""); + } + pszTmpExpression = msStringConcatenate(pszTmpExpression, ")"); + + if (pszExpression != NULL) + pszExpression = msStringConcatenate(pszExpression, " OR "); + + pszExpression = msStringConcatenate(pszExpression, pszTmpExpression); + + msFree(pszTmpExpression); + pszTmpExpression = NULL; + } + pszExpression = msStringConcatenate(pszExpression, ")"); + } + msFreeCharArray(paszElements, numelements); + } else { + /*range(s)*/ + paszElements = msStringSplit(value, ',', &numelements); + if (paszElements && numelements > 0) { + pszTmpExpression = msStringConcatenate(pszTmpExpression, "("); + for (i = 0; i < numelements; i++) { + papszRangeElements = + msStringSplit(paszElements[i], '/', &nrangeelements); + if (papszRangeElements && nrangeelements > 0) { + pszTmpExpression = msStringConcatenate(pszTmpExpression, "("); + if (nrangeelements == 2 || nrangeelements == 3) { + /* + minval = atof(papszRangeElements[0]); + maxval = atof(papszRangeElements[1]); + */ + { + pszTmpExpression = msStringConcatenate(pszTmpExpression, "["); + pszTmpExpression = msStringConcatenate(pszTmpExpression, item); + pszTmpExpression = msStringConcatenate(pszTmpExpression, "]"); + } + + pszTmpExpression = msStringConcatenate(pszTmpExpression, " >= "); + + { + char *pszEscapedStr = + msLayerEscapeSQLParam(lp, papszRangeElements[0]); + pszTmpExpression = + msStringConcatenate(pszTmpExpression, pszEscapedStr); + msFree(pszEscapedStr); + } + + pszTmpExpression = msStringConcatenate(pszTmpExpression, " AND "); + + { + pszTmpExpression = msStringConcatenate(pszTmpExpression, "["); + pszTmpExpression = msStringConcatenate(pszTmpExpression, item); + pszTmpExpression = msStringConcatenate(pszTmpExpression, "]"); + } + + pszTmpExpression = msStringConcatenate(pszTmpExpression, " <= "); + + { + char *pszEscapedStr = + msLayerEscapeSQLParam(lp, papszRangeElements[1]); + pszTmpExpression = + msStringConcatenate(pszTmpExpression, pszEscapedStr); + msFree(pszEscapedStr); + } + + pszTmpExpression = msStringConcatenate(pszTmpExpression, ")"); + } else if (nrangeelements == 1) { + pszTmpExpression = msStringConcatenate(pszTmpExpression, "("); + { + pszTmpExpression = msStringConcatenate(pszTmpExpression, "["); + pszTmpExpression = msStringConcatenate(pszTmpExpression, item); + pszTmpExpression = msStringConcatenate(pszTmpExpression, "]"); + } + + pszTmpExpression = msStringConcatenate(pszTmpExpression, " = "); + + { + char *pszEscapedStr = + msLayerEscapeSQLParam(lp, papszRangeElements[0]); + pszTmpExpression = + msStringConcatenate(pszTmpExpression, pszEscapedStr); + msFree(pszEscapedStr); + } + + pszTmpExpression = msStringConcatenate(pszTmpExpression, ")"); + } + + if (pszExpression != NULL) + pszExpression = msStringConcatenate(pszExpression, " OR "); + + pszExpression = + msStringConcatenate(pszExpression, pszTmpExpression); + msFree(pszTmpExpression); + pszTmpExpression = NULL; + } + msFreeCharArray(papszRangeElements, nrangeelements); + } + pszExpression = msStringConcatenate(pszExpression, ")"); + } + msFreeCharArray(paszElements, numelements); + } + } + msFree(pszTmpExpression); + return pszExpression; +} + +static int FLTShapeFromGMLTree(CPLXMLNode *psTree, shapeObj *psShape, + char **ppszSRS) { + const char *pszSRS = NULL; + if (psTree && psShape) { + CPLXMLNode *psNext = psTree->psNext; + OGRGeometryH hGeometry = NULL; + + psTree->psNext = NULL; + hGeometry = OGR_G_CreateFromGMLTree(psTree); + psTree->psNext = psNext; + + if (hGeometry) { + OGRwkbGeometryType nType; + nType = OGR_G_GetGeometryType(hGeometry); + if (nType == wkbPolygon25D || nType == wkbMultiPolygon25D) + nType = wkbPolygon; + else if (nType == wkbLineString25D || nType == wkbMultiLineString25D) + nType = wkbLineString; + else if (nType == wkbPoint25D || nType == wkbMultiPoint25D) + nType = wkbPoint; + msOGRGeometryToShape(hGeometry, psShape, nType); + + OGR_G_DestroyGeometry(hGeometry); + + pszSRS = CPLGetXMLValue(psTree, "srsName", NULL); + if (ppszSRS && pszSRS) + *ppszSRS = msStrdup(pszSRS); + + return MS_TRUE; + } + } + + return MS_FALSE; +} + +/************************************************************************/ +/* FLTSplitFilters */ +/* */ +/* Split filters separated by parentheses into an array of strings. */ +/************************************************************************/ +char **FLTSplitFilters(const char *pszStr, int *pnTokens) { + const char *pszTokenBegin; + char **papszRet = NULL; + int nTokens = 0; + char chStringQuote = '\0'; + int nXMLIndent = 0; + int bInBracket = FALSE; + + if (*pszStr != '(') { + *pnTokens = 0; + return NULL; + } + pszStr++; + pszTokenBegin = pszStr; + while (*pszStr != '\0') { + /* Ignore any character until end of quoted string */ + if (chStringQuote != '\0') { + if (*pszStr == chStringQuote) + chStringQuote = 0; + } + /* Detect begin of quoted string only for an XML attribute, i.e. between < + and > */ + else if (bInBracket && (*pszStr == '\'' || *pszStr == '"')) { + chStringQuote = *pszStr; + } + /* Begin of XML element */ + else if (*pszStr == '<') { + bInBracket = TRUE; + if (pszStr[1] == '/') + nXMLIndent--; + else if (pszStr[1] != '!') + nXMLIndent++; + } + /* case */ + else if (*pszStr == '/' && pszStr[1] == '>') { + bInBracket = FALSE; + nXMLIndent--; + pszStr++; + } + /* End of XML element */ + else if (*pszStr == '>') { + bInBracket = FALSE; + } + /* Only detect and of filter when XML indentation goes back to zero */ + else if (nXMLIndent == 0 && *pszStr == ')') { + papszRet = + (char **)msSmallRealloc(papszRet, sizeof(char *) * (nTokens + 1)); + papszRet[nTokens] = msStrdup(pszTokenBegin); + papszRet[nTokens][pszStr - pszTokenBegin] = '\0'; + nTokens++; + if (pszStr[1] != '(') { + break; + } + pszStr++; + pszTokenBegin = pszStr + 1; + } + pszStr++; + } + *pnTokens = nTokens; + return papszRet; +} + +/************************************************************************/ +/* FLTIsSimpleFilter */ +/* */ +/* Filter encoding with only attribute queries and only one bbox. */ +/************************************************************************/ +int FLTIsSimpleFilter(FilterEncodingNode *psNode) { + if (FLTValidForBBoxFilter(psNode)) { + if (FLTNumberOfFilterType(psNode, "DWithin") == 0 && + FLTNumberOfFilterType(psNode, "Intersect") == 0 && + FLTNumberOfFilterType(psNode, "Intersects") == 0 && + FLTNumberOfFilterType(psNode, "Equals") == 0 && + FLTNumberOfFilterType(psNode, "Disjoint") == 0 && + FLTNumberOfFilterType(psNode, "Touches") == 0 && + FLTNumberOfFilterType(psNode, "Crosses") == 0 && + FLTNumberOfFilterType(psNode, "Within") == 0 && + FLTNumberOfFilterType(psNode, "Contains") == 0 && + FLTNumberOfFilterType(psNode, "Overlaps") == 0 && + FLTNumberOfFilterType(psNode, "Beyond") == 0) + return TRUE; + } + + return FALSE; +} + +/************************************************************************/ +/* FLTApplyFilterToLayer */ +/* */ +/* Use the filter encoding node to create mapserver expressions */ +/* and apply it to the layer. */ +/************************************************************************/ +int FLTApplyFilterToLayer(FilterEncodingNode *psNode, mapObj *map, + int iLayerIndex) { + layerObj *layer = GET_LAYER(map, iLayerIndex); + + if (!layer->vtable) { + int rv = msInitializeVirtualTable(layer); + if (rv != MS_SUCCESS) + return rv; + } + if (!layer->vtable) + return MS_FAILURE; + return layer->vtable->LayerApplyFilterToLayer(psNode, map, iLayerIndex); +} + +/************************************************************************/ +/* FLTGetTopBBOX */ +/* */ +/* Return the "top" BBOX if there's a unique one. */ +/************************************************************************/ +static int FLTGetTopBBOXInternal(FilterEncodingNode *psNode, + FilterEncodingNode **ppsTopBBOX, + int *pnCount) { + if (psNode->pszValue && strcasecmp(psNode->pszValue, "BBOX") == 0) { + (*pnCount)++; + if (*pnCount == 1) { + *ppsTopBBOX = psNode; + return TRUE; + } + *ppsTopBBOX = NULL; + return FALSE; + } else if (psNode->pszValue && strcasecmp(psNode->pszValue, "AND") == 0) { + return FLTGetTopBBOXInternal(psNode->psLeftNode, ppsTopBBOX, pnCount) && + FLTGetTopBBOXInternal(psNode->psRightNode, ppsTopBBOX, pnCount); + } else { + return TRUE; + } +} + +static FilterEncodingNode *FLTGetTopBBOX(FilterEncodingNode *psNode) { + int nCount = 0; + FilterEncodingNode *psTopBBOX = NULL; + FLTGetTopBBOXInternal(psNode, &psTopBBOX, &nCount); + return psTopBBOX; +} + +/************************************************************************/ +/* FLTLayerSetInvalidRectIfSupported */ +/* */ +/* This function will set in *rect a very huge extent if the layer */ +/* wfs_use_default_extent_for_getfeature metadata item is set to false */ +/* and the layer supports such degenerate rectangle, as a hint that */ +/* they should not issue a spatial filter. */ +/************************************************************************/ + +int FLTLayerSetInvalidRectIfSupported(mapObj *map, layerObj *lp, rectObj *rect, + const char *metadata_namespaces) { + // Check LAYER metadata first, then fall back to MAP WEB metadata + const char *pszUseDefaultExtent = + msOWSLookupMetadata(&(lp->metadata), metadata_namespaces, + "use_default_extent_for_getfeature"); + if (!pszUseDefaultExtent) { + pszUseDefaultExtent = + msOWSLookupMetadata(&(map->web.metadata), metadata_namespaces, + "use_default_extent_for_getfeature"); + } + + if (pszUseDefaultExtent && !CSLTestBoolean(pszUseDefaultExtent) && + (lp->connectiontype == MS_OGR || lp->connectiontype == MS_POSTGIS || + ((lp->connectiontype == MS_PLUGIN) && + (strstr(lp->plugin_library, "msplugin_mssql2008") != NULL)))) { + const rectObj rectInvalid = MS_INIT_INVALID_RECT; + *rect = rectInvalid; + return MS_TRUE; + } + return MS_FALSE; +} + +/************************************************************************/ +/* FLTLayerApplyPlainFilterToLayer */ +/* */ +/* Helper function for layer virtual table architecture */ +/************************************************************************/ +int FLTLayerApplyPlainFilterToLayer(FilterEncodingNode *psNode, mapObj *map, + int iLayerIndex) { + char *pszExpression = NULL; + int status = MS_FALSE; + layerObj *lp = GET_LAYER(map, iLayerIndex); + + pszExpression = FLTGetCommonExpression(psNode, lp); + if (pszExpression) { + FilterEncodingNode *psTopBBOX; + rectObj rect = map->extent; + + // if this is a WMS request do not remove any BBOXes + if (msOWSLookupMetadata(&(lp->metadata), "G", "wmsfilter_flag") == NULL) { + FLTLayerSetInvalidRectIfSupported(map, lp, &rect, "OF"); + } + psTopBBOX = FLTGetTopBBOX(psNode); + if (psTopBBOX) { + int can_remove_expression = MS_TRUE; + const char *pszEPSG = FLTGetBBOX(psNode, &rect); + if (pszEPSG && map->projection.numargs > 0) { + projectionObj sProjTmp; + msInitProjection(&sProjTmp); + msProjectionInheritContextFrom(&sProjTmp, &map->projection); + /* Use the non EPSG variant since axis swapping is done in + * FLTDoAxisSwappingIfNecessary */ + if (msLoadProjectionString(&sProjTmp, pszEPSG) == 0) { + rectObj oldRect = rect; + msProjectRect(&sProjTmp, &map->projection, &rect); + /* If reprojection is involved, do not remove the expression */ + if (rect.minx != oldRect.minx || rect.miny != oldRect.miny || + rect.maxx != oldRect.maxx || rect.maxy != oldRect.maxy) { + can_remove_expression = MS_FALSE; + } + } + msFreeProjection(&sProjTmp); + } + + /* Small optimization: if the query is just a BBOX, then do a */ + /* msQueryByRect() */ + if (psTopBBOX == psNode && can_remove_expression) { + msFree(pszExpression); + pszExpression = NULL; + } + } + + if (map->debug == MS_DEBUGLEVEL_VVV) { + if (pszExpression) + msDebug("FLTLayerApplyPlainFilterToLayer(): %s, " + "rect=%.15g,%.15g,%.15g,%.15g\n", + pszExpression, rect.minx, rect.miny, rect.maxx, rect.maxy); + else + msDebug( + "FLTLayerApplyPlainFilterToLayer(): rect=%.15g,%.15g,%.15g,%.15g\n", + rect.minx, rect.miny, rect.maxx, rect.maxy); + } + + status = FLTApplyFilterToLayerCommonExpressionWithRect(map, iLayerIndex, + pszExpression, rect); + msFree(pszExpression); + } + + return status; +} + +/************************************************************************/ +/* FilterNode *FLTPaserFilterEncoding(char *szXMLString) */ +/* */ +/* Parses an Filter Encoding XML string and creates a */ +/* FilterEncodingNodes corresponding to the string. */ +/* Returns a pointer to the first node or NULL if */ +/* unsuccessful. */ +/* Calling function should use FreeFilterEncodingNode function */ +/* to free memory. */ +/************************************************************************/ +FilterEncodingNode *FLTParseFilterEncoding(const char *szXMLString) { + CPLXMLNode *psRoot = NULL, *psChild = NULL, *psFilter = NULL; + FilterEncodingNode *psFilterNode = NULL; + + if (szXMLString == NULL || strlen(szXMLString) == 0 || + (strstr(szXMLString, "Filter") == NULL)) + return NULL; + + psRoot = CPLParseXMLString(szXMLString); + + if (psRoot == NULL) + return NULL; + + /* strip namespaces. We strip all name spaces (#1350)*/ + CPLStripXMLNamespace(psRoot, NULL, 1); + + /* -------------------------------------------------------------------- */ + /* get the root element (Filter). */ + /* -------------------------------------------------------------------- */ + psFilter = CPLGetXMLNode(psRoot, "=Filter"); + if (!psFilter) { + CPLDestroyXMLNode(psRoot); + return NULL; + } + + psChild = psFilter->psChild; + while (psChild) { + if (FLTIsSupportedFilterType(psChild)) { + psFilterNode = FLTCreateFilterEncodingNode(); + FLTInsertElementInNode(psFilterNode, psChild); + break; + } else + psChild = psChild->psNext; + } + + CPLDestroyXMLNode(psRoot); + + /* -------------------------------------------------------------------- */ + /* validate the node tree to make sure that all the nodes are valid.*/ + /* -------------------------------------------------------------------- */ + if (!FLTValidFilterNode(psFilterNode)) { + FLTFreeFilterEncodingNode(psFilterNode); + return NULL; + } + + return psFilterNode; +} + +/************************************************************************/ +/* int FLTValidFilterNode(FilterEncodingNode *psFilterNode) */ +/* */ +/* Validate that all the nodes are filled properly. We could */ +/* have parts of the nodes that are correct and part which */ +/* could be incorrect if the filter string sent is corrupted */ +/* (eg missing a value :) */ +/************************************************************************/ +int FLTValidFilterNode(FilterEncodingNode *psFilterNode) { + if (!psFilterNode) + return 0; + + if (psFilterNode->eType == FILTER_NODE_TYPE_UNDEFINED) + return 0; + + if (psFilterNode->psLeftNode) { + const int bReturn = FLTValidFilterNode(psFilterNode->psLeftNode); + if (bReturn == 0) + return 0; + else if (psFilterNode->psRightNode) + return FLTValidFilterNode(psFilterNode->psRightNode); + } + + return 1; +} + +/************************************************************************/ +/* FLTIsGeometryFilterNodeType */ +/************************************************************************/ + +static int FLTIsGeometryFilterNodeType(int eType) { + return (eType == FILTER_NODE_TYPE_GEOMETRY_POINT || + eType == FILTER_NODE_TYPE_GEOMETRY_LINE || + eType == FILTER_NODE_TYPE_GEOMETRY_POLYGON); +} + +/************************************************************************/ +/* FLTFreeFilterEncodingNode */ +/* */ +/* recursive freeing of Filter Encoding nodes. */ +/************************************************************************/ +void FLTFreeFilterEncodingNode(FilterEncodingNode *psFilterNode) { + if (psFilterNode) { + if (psFilterNode->psLeftNode) { + FLTFreeFilterEncodingNode(psFilterNode->psLeftNode); + psFilterNode->psLeftNode = NULL; + } + if (psFilterNode->psRightNode) { + FLTFreeFilterEncodingNode(psFilterNode->psRightNode); + psFilterNode->psRightNode = NULL; + } + + if (psFilterNode->pszSRS) + free(psFilterNode->pszSRS); + + if (psFilterNode->pOther) { + if (psFilterNode->pszValue != NULL && + strcasecmp(psFilterNode->pszValue, "PropertyIsLike") == 0) { + FEPropertyIsLike *propIsLike = (FEPropertyIsLike *)psFilterNode->pOther; + if (propIsLike->pszWildCard) + free(propIsLike->pszWildCard); + if (propIsLike->pszSingleChar) + free(propIsLike->pszSingleChar); + if (propIsLike->pszEscapeChar) + free(propIsLike->pszEscapeChar); + } else if (FLTIsGeometryFilterNodeType(psFilterNode->eType)) { + msFreeShape((shapeObj *)(psFilterNode->pOther)); + } + /* else */ + /* TODO free pOther special fields */ + free(psFilterNode->pOther); + } + + /* Cannot free pszValue before, 'cause we are testing it above */ + if (psFilterNode->pszValue) + free(psFilterNode->pszValue); + + free(psFilterNode); + } +} + +/************************************************************************/ +/* FLTCreateFilterEncodingNode */ +/* */ +/* return a FilterEncoding node. */ +/************************************************************************/ +FilterEncodingNode *FLTCreateFilterEncodingNode(void) { + FilterEncodingNode *psFilterNode = NULL; + + psFilterNode = (FilterEncodingNode *)malloc(sizeof(FilterEncodingNode)); + psFilterNode->eType = FILTER_NODE_TYPE_UNDEFINED; + psFilterNode->pszValue = NULL; + psFilterNode->pOther = NULL; + psFilterNode->pszSRS = NULL; + psFilterNode->psLeftNode = NULL; + psFilterNode->psRightNode = NULL; + + return psFilterNode; +} + +FilterEncodingNode *FLTCreateBinaryCompFilterEncodingNode(void) { + FilterEncodingNode *psFilterNode = NULL; + + psFilterNode = FLTCreateFilterEncodingNode(); + /* used to store case sensitivity flag. Default is 0 meaning the + comparing is case sensititive */ + psFilterNode->pOther = (int *)malloc(sizeof(int)); + (*(int *)(psFilterNode->pOther)) = 0; + + return psFilterNode; +} + +/************************************************************************/ +/* FLTFindGeometryNode */ +/* */ +/************************************************************************/ + +static CPLXMLNode *FLTFindGeometryNode(CPLXMLNode *psXMLNode, int *pbPoint, + int *pbLine, int *pbPolygon) { + CPLXMLNode *psGMLElement = NULL; + + psGMLElement = CPLGetXMLNode(psXMLNode, "Point"); + if (!psGMLElement) + psGMLElement = CPLGetXMLNode(psXMLNode, "PointType"); + if (psGMLElement) + *pbPoint = 1; + else { + psGMLElement = CPLGetXMLNode(psXMLNode, "Polygon"); + if (psGMLElement) + *pbPolygon = 1; + else if ((psGMLElement = CPLGetXMLNode(psXMLNode, "MultiPolygon"))) + *pbPolygon = 1; + else if ((psGMLElement = CPLGetXMLNode(psXMLNode, "Surface"))) + *pbPolygon = 1; + else if ((psGMLElement = CPLGetXMLNode(psXMLNode, "MultiSurface"))) + *pbPolygon = 1; + else if ((psGMLElement = CPLGetXMLNode(psXMLNode, "Box"))) + *pbPolygon = 1; + else if ((psGMLElement = CPLGetXMLNode(psXMLNode, "Envelope"))) + *pbPolygon = 1; + else if ((psGMLElement = CPLGetXMLNode(psXMLNode, "LineString"))) + *pbLine = 1; + else if ((psGMLElement = CPLGetXMLNode(psXMLNode, "MultiLineString"))) + *pbLine = 1; + else if ((psGMLElement = CPLGetXMLNode(psXMLNode, "Curve"))) + *pbLine = 1; + else if ((psGMLElement = CPLGetXMLNode(psXMLNode, "MultiCurve"))) + *pbLine = 1; + else if ((psGMLElement = CPLGetXMLNode(psXMLNode, "MultiPoint"))) + *pbPoint = 1; + } + return psGMLElement; +} + +/************************************************************************/ +/* FLTGetPropertyName */ +/************************************************************************/ +static const char *FLTGetPropertyName(CPLXMLNode *psXMLNode) { + const char *pszPropertyName; + + pszPropertyName = CPLGetXMLValue(psXMLNode, "PropertyName", NULL); + if (pszPropertyName == NULL) /* FE 2.0 ? */ + pszPropertyName = CPLGetXMLValue(psXMLNode, "ValueReference", NULL); + return pszPropertyName; +} + +/************************************************************************/ +/* FLTGetFirstChildNode */ +/************************************************************************/ +static CPLXMLNode *FLTGetFirstChildNode(CPLXMLNode *psXMLNode) { + if (psXMLNode == NULL) + return NULL; + psXMLNode = psXMLNode->psChild; + while (psXMLNode != NULL) { + if (psXMLNode->eType == CXT_Element) + return psXMLNode; + psXMLNode = psXMLNode->psNext; + } + return NULL; +} + +/************************************************************************/ +/* FLTGetNextSibblingNode */ +/************************************************************************/ +static CPLXMLNode *FLTGetNextSibblingNode(CPLXMLNode *psXMLNode) { + if (psXMLNode == NULL) + return NULL; + psXMLNode = psXMLNode->psNext; + while (psXMLNode != NULL) { + if (psXMLNode->eType == CXT_Element) + return psXMLNode; + psXMLNode = psXMLNode->psNext; + } + return NULL; +} + +/************************************************************************/ +/* FLTInsertElementInNode */ +/* */ +/* Utility function to parse an XML node and transfer the */ +/* contents into the Filter Encoding node structure. */ +/************************************************************************/ +void FLTInsertElementInNode(FilterEncodingNode *psFilterNode, + CPLXMLNode *psXMLNode) { + char *pszTmp = NULL; + FilterEncodingNode *psCurFilNode = NULL; + CPLXMLNode *psCurXMLNode = NULL; + CPLXMLNode *psTmpNode = NULL; + CPLXMLNode *psFeatureIdNode = NULL; + const char *pszFeatureId = NULL; + char *pszFeatureIdList = NULL; + + if (psFilterNode && psXMLNode && psXMLNode->pszValue) { + psFilterNode->pszValue = msStrdup(psXMLNode->pszValue); + psFilterNode->psLeftNode = NULL; + psFilterNode->psRightNode = NULL; + + /* -------------------------------------------------------------------- */ + /* Logical filter. AND, OR and NOT are supported. Example of */ + /* filer using logical filters : */ + /* */ + /* */ + /* */ + /* Person/Age */ + /* 50 */ + /* */ + /* */ + /* Person/Address/City */ + /* Toronto */ + /* */ + /* */ + /* */ + /* -------------------------------------------------------------------- */ + if (FLTIsLogicalFilterType(psXMLNode->pszValue)) { + psFilterNode->eType = FILTER_NODE_TYPE_LOGICAL; + if (strcasecmp(psFilterNode->pszValue, "AND") == 0 || + strcasecmp(psFilterNode->pszValue, "OR") == 0) { + CPLXMLNode *psFirstNode = FLTGetFirstChildNode(psXMLNode); + CPLXMLNode *psSecondNode = FLTGetNextSibblingNode(psFirstNode); + if (psFirstNode && psSecondNode) { + /*2 operators */ + CPLXMLNode *psNextNode = FLTGetNextSibblingNode(psSecondNode); + if (psNextNode == NULL) { + psFilterNode->psLeftNode = FLTCreateFilterEncodingNode(); + FLTInsertElementInNode(psFilterNode->psLeftNode, psFirstNode); + psFilterNode->psRightNode = FLTCreateFilterEncodingNode(); + FLTInsertElementInNode(psFilterNode->psRightNode, psSecondNode); + } else { + psCurXMLNode = psFirstNode; + psCurFilNode = psFilterNode; + while (psCurXMLNode) { + psNextNode = FLTGetNextSibblingNode(psCurXMLNode); + if (FLTGetNextSibblingNode(psNextNode)) { + psCurFilNode->psLeftNode = FLTCreateFilterEncodingNode(); + FLTInsertElementInNode(psCurFilNode->psLeftNode, psCurXMLNode); + psCurFilNode->psRightNode = FLTCreateFilterEncodingNode(); + psCurFilNode->psRightNode->eType = FILTER_NODE_TYPE_LOGICAL; + psCurFilNode->psRightNode->pszValue = + msStrdup(psFilterNode->pszValue); + + psCurFilNode = psCurFilNode->psRightNode; + psCurXMLNode = psNextNode; + } else { /*last 2 operators*/ + psCurFilNode->psLeftNode = FLTCreateFilterEncodingNode(); + FLTInsertElementInNode(psCurFilNode->psLeftNode, psCurXMLNode); + + psCurFilNode->psRightNode = FLTCreateFilterEncodingNode(); + FLTInsertElementInNode(psCurFilNode->psRightNode, psNextNode); + break; + } + } + } + } else + psFilterNode->eType = FILTER_NODE_TYPE_UNDEFINED; + } else if (strcasecmp(psFilterNode->pszValue, "NOT") == 0) { + CPLXMLNode *psFirstNode = FLTGetFirstChildNode(psXMLNode); + if (psFirstNode) { + psFilterNode->psLeftNode = FLTCreateFilterEncodingNode(); + FLTInsertElementInNode(psFilterNode->psLeftNode, psFirstNode); + } else + psFilterNode->eType = FILTER_NODE_TYPE_UNDEFINED; + } else + psFilterNode->eType = FILTER_NODE_TYPE_UNDEFINED; + } /* end if is logical */ + /* -------------------------------------------------------------------- */ + /* Spatial Filter. */ + /* BBOX : */ + /* */ + /* */ + /* Geometry */ + /* */ + /* 13.0983,31.5899 35.5472,42.8143*/ + /* */ + /* */ + /* */ + /* */ + /* DWithin */ + /* */ + /* */ + /* */ + /* */ + /* */ + /* */ + /* */ + /* */ + /* */ + /* */ + /* */ + /* */ + /* */ + /* */ + /* */ + /* */ + /* */ + /* */ + /* Geometry */ + /* */ + /* 13.0983,31.5899 */ + /* */ + /* 10 */ + /* */ + /* */ + /* */ + /* Intersect */ + /* */ + /* type="ogc:BinarySpatialOpType" + substitutionGroup="ogc:spatialOps"/>*/ + /* */ + /* */ + /* */ + /* */ + /* */ + /* */ + /* */ + /* */ + /* */ + /* */ + /* */ + /* */ + /* */ + /* */ + /* -------------------------------------------------------------------- */ + else if (FLTIsSpatialFilterType(psXMLNode->pszValue)) { + psFilterNode->eType = FILTER_NODE_TYPE_SPATIAL; + + if (strcasecmp(psXMLNode->pszValue, "BBOX") == 0) { + char *pszSRS = NULL; + const char *pszPropertyName = NULL; + CPLXMLNode *psBox = NULL, *psEnvelope = NULL; + rectObj sBox = {0, 0, 0, 0}; + + int bCoordinatesValid = 0; + + pszPropertyName = FLTGetPropertyName(psXMLNode); + psBox = CPLGetXMLNode(psXMLNode, "Box"); + if (!psBox) + psBox = CPLGetXMLNode(psXMLNode, "BoxType"); + + /*FE 1.0 used box FE1.1 uses envelop*/ + if (psBox) + bCoordinatesValid = FLTParseGMLBox(psBox, &sBox, &pszSRS); + else if ((psEnvelope = CPLGetXMLNode(psXMLNode, "Envelope"))) + bCoordinatesValid = FLTParseGMLEnvelope(psEnvelope, &sBox, &pszSRS); + + if (bCoordinatesValid) { + /*set the srs if available*/ + if (pszSRS) + psFilterNode->pszSRS = pszSRS; + + psFilterNode->psLeftNode = FLTCreateFilterEncodingNode(); + psFilterNode->psLeftNode->eType = FILTER_NODE_TYPE_PROPERTYNAME; + /* PropertyName is optional since FE 1.1.0, in which case */ + /* the BBOX must apply to all geometry fields. As we support */ + /* currently only one geometry field, this doesn't make much */ + /* difference to further processing. */ + if (pszPropertyName != NULL) { + psFilterNode->psLeftNode->pszValue = msStrdup(pszPropertyName); + } + + /* coordinates */ + psFilterNode->psRightNode = FLTCreateFilterEncodingNode(); + psFilterNode->psRightNode->eType = FILTER_NODE_TYPE_BBOX; + psFilterNode->psRightNode->pOther = + (rectObj *)msSmallMalloc(sizeof(rectObj)); + ((rectObj *)psFilterNode->psRightNode->pOther)->minx = sBox.minx; + ((rectObj *)psFilterNode->psRightNode->pOther)->miny = sBox.miny; + ((rectObj *)psFilterNode->psRightNode->pOther)->maxx = sBox.maxx; + ((rectObj *)psFilterNode->psRightNode->pOther)->maxy = sBox.maxy; + } else { + msFree(pszSRS); + psFilterNode->eType = FILTER_NODE_TYPE_UNDEFINED; + } + } else if (strcasecmp(psXMLNode->pszValue, "DWithin") == 0 || + strcasecmp(psXMLNode->pszValue, "Beyond") == 0) + + { + shapeObj *psShape = NULL; + int bPoint = 0, bLine = 0, bPolygon = 0; + const char *pszUnits = NULL; + const char *pszDistance = NULL; + const char *pszPropertyName; + char *pszSRS = NULL; + + CPLXMLNode *psGMLElement = NULL, *psDistance = NULL; + + pszPropertyName = FLTGetPropertyName(psXMLNode); + + psGMLElement = + FLTFindGeometryNode(psXMLNode, &bPoint, &bLine, &bPolygon); + + psDistance = CPLGetXMLNode(psXMLNode, "Distance"); + if (psDistance != NULL) + pszDistance = CPLGetXMLValue(psDistance, NULL, NULL); + if (pszPropertyName != NULL && psGMLElement && psDistance != NULL) { + pszUnits = CPLGetXMLValue(psDistance, "units", NULL); + if (pszUnits == NULL) /* FE 2.0 */ + pszUnits = CPLGetXMLValue(psDistance, "uom", NULL); + psShape = (shapeObj *)msSmallMalloc(sizeof(shapeObj)); + msInitShape(psShape); + if (FLTShapeFromGMLTree(psGMLElement, psShape, &pszSRS)) { + /*set the srs if available*/ + if (pszSRS) + psFilterNode->pszSRS = pszSRS; + + psFilterNode->psLeftNode = FLTCreateFilterEncodingNode(); + psFilterNode->psLeftNode->eType = FILTER_NODE_TYPE_PROPERTYNAME; + psFilterNode->psLeftNode->pszValue = msStrdup(pszPropertyName); + + psFilterNode->psRightNode = FLTCreateFilterEncodingNode(); + if (bPoint) + psFilterNode->psRightNode->eType = + FILTER_NODE_TYPE_GEOMETRY_POINT; + else if (bLine) + psFilterNode->psRightNode->eType = FILTER_NODE_TYPE_GEOMETRY_LINE; + else if (bPolygon) + psFilterNode->psRightNode->eType = + FILTER_NODE_TYPE_GEOMETRY_POLYGON; + psFilterNode->psRightNode->pOther = (shapeObj *)psShape; + /*the value will be distance;units*/ + psFilterNode->psRightNode->pszValue = msStrdup(pszDistance); + if (pszUnits) { + psFilterNode->psRightNode->pszValue = + msStringConcatenate(psFilterNode->psRightNode->pszValue, ";"); + psFilterNode->psRightNode->pszValue = msStringConcatenate( + psFilterNode->psRightNode->pszValue, pszUnits); + } + } else { + free(psShape); + msFree(pszSRS); + psFilterNode->eType = FILTER_NODE_TYPE_UNDEFINED; + } + } else + psFilterNode->eType = FILTER_NODE_TYPE_UNDEFINED; + } else if (strcasecmp(psXMLNode->pszValue, "Intersect") == 0 || + strcasecmp(psXMLNode->pszValue, "Intersects") == 0 || + strcasecmp(psXMLNode->pszValue, "Equals") == 0 || + strcasecmp(psXMLNode->pszValue, "Disjoint") == 0 || + strcasecmp(psXMLNode->pszValue, "Touches") == 0 || + strcasecmp(psXMLNode->pszValue, "Crosses") == 0 || + strcasecmp(psXMLNode->pszValue, "Within") == 0 || + strcasecmp(psXMLNode->pszValue, "Contains") == 0 || + strcasecmp(psXMLNode->pszValue, "Overlaps") == 0) { + shapeObj *psShape = NULL; + int bLine = 0, bPolygon = 0, bPoint = 0; + char *pszSRS = NULL; + const char *pszPropertyName; + + CPLXMLNode *psGMLElement = NULL; + + pszPropertyName = FLTGetPropertyName(psXMLNode); + + psGMLElement = + FLTFindGeometryNode(psXMLNode, &bPoint, &bLine, &bPolygon); + + if (pszPropertyName != NULL && psGMLElement) { + psShape = (shapeObj *)msSmallMalloc(sizeof(shapeObj)); + msInitShape(psShape); + if (FLTShapeFromGMLTree(psGMLElement, psShape, &pszSRS)) { + /*set the srs if available*/ + if (pszSRS) + psFilterNode->pszSRS = pszSRS; + + psFilterNode->psLeftNode = FLTCreateFilterEncodingNode(); + psFilterNode->psLeftNode->eType = FILTER_NODE_TYPE_PROPERTYNAME; + psFilterNode->psLeftNode->pszValue = msStrdup(pszPropertyName); + + psFilterNode->psRightNode = FLTCreateFilterEncodingNode(); + if (bPoint) + psFilterNode->psRightNode->eType = + FILTER_NODE_TYPE_GEOMETRY_POINT; + else if (bLine) + psFilterNode->psRightNode->eType = FILTER_NODE_TYPE_GEOMETRY_LINE; + else if (bPolygon) + psFilterNode->psRightNode->eType = + FILTER_NODE_TYPE_GEOMETRY_POLYGON; + psFilterNode->psRightNode->pOther = (shapeObj *)psShape; + + } else { + free(psShape); + msFree(pszSRS); + psFilterNode->eType = FILTER_NODE_TYPE_UNDEFINED; + } + } else + psFilterNode->eType = FILTER_NODE_TYPE_UNDEFINED; + } + + } /* end of is spatial */ + + /* -------------------------------------------------------------------- */ + /* Comparison Filter */ + /* -------------------------------------------------------------------- */ + else if (FLTIsComparisonFilterType(psXMLNode->pszValue)) { + psFilterNode->eType = FILTER_NODE_TYPE_COMPARISON; + /* -------------------------------------------------------------------- */ + /* binary comaparison types. Example : */ + /* */ + /* */ + /* */ + /* SomeProperty */ + /* 100 */ + /* */ + /* */ + /* -------------------------------------------------------------------- */ + if (FLTIsBinaryComparisonFilterType(psXMLNode->pszValue)) { + const char *pszPropertyName = FLTGetPropertyName(psXMLNode); + if (pszPropertyName != NULL) { + + psFilterNode->psLeftNode = FLTCreateFilterEncodingNode(); + psFilterNode->psLeftNode->eType = FILTER_NODE_TYPE_PROPERTYNAME; + psFilterNode->psLeftNode->pszValue = msStrdup(pszPropertyName); + + psTmpNode = CPLSearchXMLNode(psXMLNode, "Literal"); + if (psTmpNode) { + const char *pszLiteral = CPLGetXMLValue(psTmpNode, NULL, NULL); + + psFilterNode->psRightNode = FLTCreateBinaryCompFilterEncodingNode(); + psFilterNode->psRightNode->eType = FILTER_NODE_TYPE_LITERAL; + + if (pszLiteral != NULL) { + const char *pszMatchCase; + + psFilterNode->psRightNode->pszValue = msStrdup(pszLiteral); + + pszMatchCase = CPLGetXMLValue(psXMLNode, "matchCase", NULL); + + /*check if the matchCase attribute is set*/ + if (pszMatchCase != NULL && + strcasecmp(pszMatchCase, "false") == 0) { + (*(int *)psFilterNode->psRightNode->pOther) = 1; + } + + } + /* special case where the user puts an empty value */ + /* for the Literal so it can end up as an empty */ + /* string query in the expression */ + else + psFilterNode->psRightNode->pszValue = NULL; + } + } + if (psFilterNode->psLeftNode == NULL || + psFilterNode->psRightNode == NULL) + psFilterNode->eType = FILTER_NODE_TYPE_UNDEFINED; + } + + /* -------------------------------------------------------------------- */ + /* PropertyIsBetween filter : extract property name and boundary */ + /* values. The boundary values are stored in the right */ + /* node. The values are separated by a semi-column (;) */ + /* Eg of Filter : */ + /* */ + /* DEPTH */ + /* 400 */ + /* 800 */ + /* */ + /* */ + /* Or */ + /* */ + /* DEPTH */ + /* 400 */ + /* 800 */ + /* */ + /* -------------------------------------------------------------------- */ + else if (strcasecmp(psXMLNode->pszValue, "PropertyIsBetween") == 0) { + const char *pszPropertyName = FLTGetPropertyName(psXMLNode); + CPLXMLNode *psLowerBoundary = CPLGetXMLNode(psXMLNode, "LowerBoundary"); + CPLXMLNode *psUpperBoundary = CPLGetXMLNode(psXMLNode, "UpperBoundary"); + const char *pszLowerNode = NULL; + const char *pszUpperNode = NULL; + if (psLowerBoundary != NULL) { + /* check if the is there */ + if (CPLGetXMLNode(psLowerBoundary, "Literal") != NULL) + pszLowerNode = CPLGetXMLValue(psLowerBoundary, "Literal", NULL); + else + pszLowerNode = CPLGetXMLValue(psLowerBoundary, NULL, NULL); + } + if (psUpperBoundary != NULL) { + if (CPLGetXMLNode(psUpperBoundary, "Literal") != NULL) + pszUpperNode = CPLGetXMLValue(psUpperBoundary, "Literal", NULL); + else + pszUpperNode = CPLGetXMLValue(psUpperBoundary, NULL, NULL); + } + if (pszPropertyName != NULL && pszLowerNode != NULL && + pszUpperNode != NULL) { + psFilterNode->psLeftNode = FLTCreateFilterEncodingNode(); + + psFilterNode->psLeftNode->eType = FILTER_NODE_TYPE_PROPERTYNAME; + psFilterNode->psLeftNode->pszValue = msStrdup(pszPropertyName); + + psFilterNode->psRightNode = FLTCreateFilterEncodingNode(); + psFilterNode->psRightNode->eType = FILTER_NODE_TYPE_BOUNDARY; + + /* adding a ; between boundary values */ + const int nStrLength = + strlen(pszLowerNode) + strlen(pszUpperNode) + 2; + + psFilterNode->psRightNode->pszValue = + (char *)malloc(sizeof(char) * (nStrLength)); + strcpy(psFilterNode->psRightNode->pszValue, pszLowerNode); + strlcat(psFilterNode->psRightNode->pszValue, ";", nStrLength); + strlcat(psFilterNode->psRightNode->pszValue, pszUpperNode, + nStrLength); + + } else + psFilterNode->eType = FILTER_NODE_TYPE_UNDEFINED; + + } /* end of PropertyIsBetween */ + /* -------------------------------------------------------------------- */ + /* PropertyIsLike */ + /* */ + /* */ + /* */ + /* LAST_NAME */ + /* JOHN* */ + /* */ + /* */ + /* -------------------------------------------------------------------- */ + else if (strcasecmp(psXMLNode->pszValue, "PropertyIsLike") == 0) { + const char *pszPropertyName = FLTGetPropertyName(psXMLNode); + const char *pszLiteral = CPLGetXMLValue(psXMLNode, "Literal", NULL); + const char *pszWildCard = CPLGetXMLValue(psXMLNode, "wildCard", NULL); + const char *pszSingleChar = + CPLGetXMLValue(psXMLNode, "singleChar", NULL); + const char *pszEscapeChar = CPLGetXMLValue(psXMLNode, "escape", NULL); + if (pszEscapeChar == NULL) + pszEscapeChar = CPLGetXMLValue(psXMLNode, "escapeChar", NULL); + if (pszPropertyName != NULL && pszLiteral != NULL && + pszWildCard != NULL && pszSingleChar != NULL && + pszEscapeChar != NULL) { + FEPropertyIsLike *propIsLike; + + propIsLike = (FEPropertyIsLike *)malloc(sizeof(FEPropertyIsLike)); + + psFilterNode->pOther = propIsLike; + propIsLike->bCaseInsensitive = 0; + propIsLike->pszWildCard = msStrdup(pszWildCard); + propIsLike->pszSingleChar = msStrdup(pszSingleChar); + propIsLike->pszEscapeChar = msStrdup(pszEscapeChar); + + pszTmp = (char *)CPLGetXMLValue(psXMLNode, "matchCase", NULL); + if (pszTmp && strcasecmp(pszTmp, "false") == 0) { + propIsLike->bCaseInsensitive = 1; + } + /* -------------------------------------------------------------------- + */ + /* Create left and right node for the attribute and the value. */ + /* -------------------------------------------------------------------- + */ + psFilterNode->psLeftNode = FLTCreateFilterEncodingNode(); + + psFilterNode->psLeftNode->pszValue = msStrdup(pszPropertyName); + psFilterNode->psLeftNode->eType = FILTER_NODE_TYPE_PROPERTYNAME; + + psFilterNode->psRightNode = FLTCreateFilterEncodingNode(); + + psFilterNode->psRightNode->pszValue = msStrdup(pszLiteral); + + psFilterNode->psRightNode->eType = FILTER_NODE_TYPE_LITERAL; + } else + psFilterNode->eType = FILTER_NODE_TYPE_UNDEFINED; + + } + + else if (strcasecmp(psXMLNode->pszValue, "PropertyIsNull") == 0) { + const char *pszPropertyName = FLTGetPropertyName(psXMLNode); + if (pszPropertyName != NULL) { + psFilterNode->psLeftNode = FLTCreateFilterEncodingNode(); + psFilterNode->psLeftNode->pszValue = msStrdup(pszPropertyName); + psFilterNode->psLeftNode->eType = FILTER_NODE_TYPE_PROPERTYNAME; + } else + psFilterNode->eType = FILTER_NODE_TYPE_UNDEFINED; + } + + else if (strcasecmp(psXMLNode->pszValue, "PropertyIsNil") == 0) { + const char *pszPropertyName = FLTGetPropertyName(psXMLNode); + if (pszPropertyName != NULL) { + psFilterNode->psLeftNode = FLTCreateFilterEncodingNode(); + psFilterNode->psLeftNode->pszValue = msStrdup(pszPropertyName); + psFilterNode->psLeftNode->eType = FILTER_NODE_TYPE_PROPERTYNAME; + } else + psFilterNode->eType = FILTER_NODE_TYPE_UNDEFINED; + } + } + /* -------------------------------------------------------------------- */ + /* FeatureId Filter */ + /* */ + /* */ + /* */ + /* */ + /* */ + /* */ + /* */ + /* */ + /* */ + /* */ + /* */ + /* Note that for FES1.1.0 the featureid has been deprecated in */ + /* favor of GmlObjectId */ + /* */ + /* */ + /* And in FES 2.0, in favor of */ + /* -------------------------------------------------------------------- */ + else if (FLTIsFeatureIdFilterType(psXMLNode->pszValue)) { + psFilterNode->eType = FILTER_NODE_TYPE_FEATUREID; + pszFeatureIdList = NULL; + + psFeatureIdNode = psXMLNode; + while (psFeatureIdNode) { + pszFeatureId = CPLGetXMLValue(psFeatureIdNode, "fid", NULL); + if (!pszFeatureId) + pszFeatureId = CPLGetXMLValue(psFeatureIdNode, "id", NULL); + if (!pszFeatureId) + pszFeatureId = CPLGetXMLValue(psFeatureIdNode, "rid", NULL); + + if (pszFeatureId) { + if (pszFeatureIdList) + pszFeatureIdList = msStringConcatenate(pszFeatureIdList, ","); + + pszFeatureIdList = + msStringConcatenate(pszFeatureIdList, pszFeatureId); + } + psFeatureIdNode = psFeatureIdNode->psNext; + } + + if (pszFeatureIdList) { + msFree(psFilterNode->pszValue); + psFilterNode->pszValue = msStrdup(pszFeatureIdList); + msFree(pszFeatureIdList); + } else + psFilterNode->eType = FILTER_NODE_TYPE_UNDEFINED; + } + + /* -------------------------------------------------------------------- */ + /* Temporal Filter. */ + /* + + gml:TimeInstant + + + + 2005-05-17T00:00:00Z + + + + + 2005-05-23T00:00:00Z + + + + + */ + /* -------------------------------------------------------------------- */ + else if (FLTIsTemporalFilterType(psXMLNode->pszValue)) { + psFilterNode->eType = FILTER_NODE_TYPE_TEMPORAL; + + if (strcasecmp(psXMLNode->pszValue, "During") == 0) { + const char *pszPropertyName = NULL; + const char *pszBeginTime; + const char *pszEndTime; + + pszPropertyName = FLTGetPropertyName(psXMLNode); + pszBeginTime = CPLGetXMLValue( + psXMLNode, "TimePeriod.begin.TimeInstant.timePosition", NULL); + if (pszBeginTime == NULL) + pszBeginTime = + CPLGetXMLValue(psXMLNode, "TimePeriod.beginPosition", NULL); + pszEndTime = CPLGetXMLValue( + psXMLNode, "TimePeriod.end.TimeInstant.timePosition", NULL); + if (pszEndTime == NULL) + pszEndTime = + CPLGetXMLValue(psXMLNode, "TimePeriod.endPosition", NULL); + + if (pszPropertyName && pszBeginTime && pszEndTime && + strchr(pszBeginTime, '\'') == NULL && + strchr(pszBeginTime, '\\') == NULL && + strchr(pszEndTime, '\'') == NULL && + strchr(pszEndTime, '\\') == NULL && + msTimeGetResolution(pszBeginTime) >= 0 && + msTimeGetResolution(pszEndTime) >= 0) { + + psFilterNode->psLeftNode = FLTCreateFilterEncodingNode(); + psFilterNode->psLeftNode->eType = FILTER_NODE_TYPE_PROPERTYNAME; + psFilterNode->psLeftNode->pszValue = msStrdup(pszPropertyName); + + psFilterNode->psRightNode = FLTCreateFilterEncodingNode(); + psFilterNode->psRightNode->eType = FILTER_NODE_TYPE_TIME_PERIOD; + const size_t nSize = strlen(pszBeginTime) + strlen(pszEndTime) + 2; + psFilterNode->psRightNode->pszValue = + static_cast(msSmallMalloc(nSize)); + snprintf(psFilterNode->psRightNode->pszValue, nSize, "%s/%s", + pszBeginTime, pszEndTime); + } else + psFilterNode->eType = FILTER_NODE_TYPE_UNDEFINED; + } else { + psFilterNode->eType = FILTER_NODE_TYPE_UNDEFINED; + } + + } /* end of is temporal */ + } +} + +/************************************************************************/ +/* int FLTIsLogicalFilterType((char *pszValue) */ +/* */ +/* return TRUE if the value of the node is of logical filter */ +/* encoding type. */ +/************************************************************************/ +int FLTIsLogicalFilterType(const char *pszValue) { + if (pszValue) { + if (strcasecmp(pszValue, "AND") == 0 || strcasecmp(pszValue, "OR") == 0 || + strcasecmp(pszValue, "NOT") == 0) + return MS_TRUE; + } + + return MS_FALSE; +} + +/************************************************************************/ +/* int FLTIsBinaryComparisonFilterType(char *pszValue) */ +/* */ +/* Binary comparison filter type. */ +/************************************************************************/ +int FLTIsBinaryComparisonFilterType(const char *pszValue) { + if (pszValue) { + if (strcasecmp(pszValue, "PropertyIsEqualTo") == 0 || + strcasecmp(pszValue, "PropertyIsNotEqualTo") == 0 || + strcasecmp(pszValue, "PropertyIsLessThan") == 0 || + strcasecmp(pszValue, "PropertyIsGreaterThan") == 0 || + strcasecmp(pszValue, "PropertyIsLessThanOrEqualTo") == 0 || + strcasecmp(pszValue, "PropertyIsGreaterThanOrEqualTo") == 0) + return MS_TRUE; + } + + return MS_FALSE; +} + +/************************************************************************/ +/* int FLTIsComparisonFilterType(char *pszValue) */ +/* */ +/* return TRUE if the value of the node is of comparison filter */ +/* encoding type. */ +/************************************************************************/ +int FLTIsComparisonFilterType(const char *pszValue) { + if (pszValue) { + if (FLTIsBinaryComparisonFilterType(pszValue) || + strcasecmp(pszValue, "PropertyIsLike") == 0 || + strcasecmp(pszValue, "PropertyIsBetween") == 0 || + strcasecmp(pszValue, "PropertyIsNull") == 0 || + strcasecmp(pszValue, "PropertyIsNil") == 0) + return MS_TRUE; + } + + return MS_FALSE; +} + +/************************************************************************/ +/* int FLTIsFeatureIdFilterType(char *pszValue) */ +/* */ +/* return TRUE if the value of the node is of featureid filter */ +/* encoding type. */ +/************************************************************************/ +int FLTIsFeatureIdFilterType(const char *pszValue) { + if (pszValue && (strcasecmp(pszValue, "FeatureId") == 0 || + strcasecmp(pszValue, "GmlObjectId") == 0 || + strcasecmp(pszValue, "ResourceId") == 0)) + + return MS_TRUE; + + return MS_FALSE; +} + +/************************************************************************/ +/* int FLTIsSpatialFilterType(char *pszValue) */ +/* */ +/* return TRUE if the value of the node is of spatial filter */ +/* encoding type. */ +/************************************************************************/ +int FLTIsSpatialFilterType(const char *pszValue) { + if (pszValue) { + if (strcasecmp(pszValue, "BBOX") == 0 || + strcasecmp(pszValue, "DWithin") == 0 || + strcasecmp(pszValue, "Intersect") == 0 || + strcasecmp(pszValue, "Intersects") == 0 || + strcasecmp(pszValue, "Equals") == 0 || + strcasecmp(pszValue, "Disjoint") == 0 || + strcasecmp(pszValue, "Touches") == 0 || + strcasecmp(pszValue, "Crosses") == 0 || + strcasecmp(pszValue, "Within") == 0 || + strcasecmp(pszValue, "Contains") == 0 || + strcasecmp(pszValue, "Overlaps") == 0 || + strcasecmp(pszValue, "Beyond") == 0) + return MS_TRUE; + } + + return MS_FALSE; +} + +/************************************************************************/ +/* int FLTIsTemportalFilterType(char *pszValue) */ +/* */ +/* return TRUE if the value of the node is of temporal filter */ +/* encoding type. */ +/************************************************************************/ +int FLTIsTemporalFilterType(const char *pszValue) { + if (pszValue) { + if (strcasecmp(pszValue, "During") == 0) + return MS_TRUE; + } + + return MS_FALSE; +} + +/************************************************************************/ +/* int FLTIsSupportedFilterType(CPLXMLNode *psXMLNode) */ +/* */ +/* Verify if the value of the node is one of the supported */ +/* filter type. */ +/************************************************************************/ +int FLTIsSupportedFilterType(CPLXMLNode *psXMLNode) { + if (psXMLNode) { + if (FLTIsLogicalFilterType(psXMLNode->pszValue) || + FLTIsSpatialFilterType(psXMLNode->pszValue) || + FLTIsComparisonFilterType(psXMLNode->pszValue) || + FLTIsFeatureIdFilterType(psXMLNode->pszValue) || + FLTIsTemporalFilterType(psXMLNode->pszValue)) + return MS_TRUE; + } + + return MS_FALSE; +} + +/************************************************************************/ +/* FLTNumberOfFilterType */ +/* */ +/* Loop trhough the nodes and return the number of nodes of */ +/* specified value. */ +/************************************************************************/ +int FLTNumberOfFilterType(FilterEncodingNode *psFilterNode, + const char *szType) { + int nCount = 0; + int nLeftNode = 0, nRightNode = 0; + + if (!psFilterNode || !szType || !psFilterNode->pszValue) + return 0; + + if (strcasecmp(psFilterNode->pszValue, (char *)szType) == 0) + nCount++; + + if (psFilterNode->psLeftNode) + nLeftNode = FLTNumberOfFilterType(psFilterNode->psLeftNode, szType); + + nCount += nLeftNode; + + if (psFilterNode->psRightNode) + nRightNode = FLTNumberOfFilterType(psFilterNode->psRightNode, szType); + nCount += nRightNode; + + return nCount; +} + +/************************************************************************/ +/* FLTValidForBBoxFilter */ +/* */ +/* Validate if there is only one BBOX filter node. Here is what */ +/* is supported (is valid) : */ +/* - one node which is a BBOX */ +/* - a logical AND with a valid BBOX */ +/* */ +/* eg 1: */ +/* */ +/* Geometry */ +/* */ +/* 13.0983,31.5899 35.5472,42.8143*/ +/* */ +/* */ +/* */ +/* */ +/* eg 2 : */ +/* */ +/* */ +/* Geometry */ +/* */ +/* 13.0983,31.5899 35.5472,42.8143*/ +/* */ +/* */ +/* */ +/* SomeProperty */ +/* 100 */ +/* */ +/* */ +/* */ +/* */ +/************************************************************************/ +int FLTValidForBBoxFilter(FilterEncodingNode *psFilterNode) { + int nCount = 0; + + if (!psFilterNode || !psFilterNode->pszValue) + return 1; + + nCount = FLTNumberOfFilterType(psFilterNode, "BBOX"); + + if (nCount > 1) + return 0; + else if (nCount == 0) + return 1; + + /* nCount ==1 */ + if (strcasecmp(psFilterNode->pszValue, "BBOX") == 0) + return 1; + + if (strcasecmp(psFilterNode->pszValue, "AND") == 0) { + return FLTValidForBBoxFilter(psFilterNode->psLeftNode) && + FLTValidForBBoxFilter(psFilterNode->psRightNode); + } + + return 0; +} + +#if 0 +static int FLTHasUniqueTopLevelDuringFilter(FilterEncodingNode *psFilterNode) +{ + int nCount = 0; + + if (!psFilterNode || !psFilterNode->pszValue) + return 1; + + nCount = FLTNumberOfFilterType(psFilterNode, "During"); + + if (nCount > 1) + return 0; + else if (nCount == 0) + return 1; + + /* nCount ==1 */ + if (strcasecmp(psFilterNode->pszValue, "During") == 0) + return 1; + + if (strcasecmp(psFilterNode->pszValue, "AND") == 0) { + return FLTHasUniqueTopLevelDuringFilter(psFilterNode->psLeftNode) && + FLTHasUniqueTopLevelDuringFilter(psFilterNode->psRightNode); + } + + return 0; +} +#endif + +int FLTIsLineFilter(FilterEncodingNode *psFilterNode) { + if (!psFilterNode || !psFilterNode->pszValue) + return 0; + + if (psFilterNode->eType == FILTER_NODE_TYPE_SPATIAL && + psFilterNode->psRightNode && + psFilterNode->psRightNode->eType == FILTER_NODE_TYPE_GEOMETRY_LINE) + return 1; + + return 0; +} + +int FLTIsPolygonFilter(FilterEncodingNode *psFilterNode) { + if (!psFilterNode || !psFilterNode->pszValue) + return 0; + + if (psFilterNode->eType == FILTER_NODE_TYPE_SPATIAL && + psFilterNode->psRightNode && + psFilterNode->psRightNode->eType == FILTER_NODE_TYPE_GEOMETRY_POLYGON) + return 1; + + return 0; +} + +int FLTIsPointFilter(FilterEncodingNode *psFilterNode) { + if (!psFilterNode || !psFilterNode->pszValue) + return 0; + + if (psFilterNode->eType == FILTER_NODE_TYPE_SPATIAL && + psFilterNode->psRightNode && + psFilterNode->psRightNode->eType == FILTER_NODE_TYPE_GEOMETRY_POINT) + return 1; + + return 0; +} + +int FLTIsBBoxFilter(FilterEncodingNode *psFilterNode) { + if (!psFilterNode || !psFilterNode->pszValue) + return 0; + + if (strcasecmp(psFilterNode->pszValue, "BBOX") == 0) + return 1; + + return 0; +} + +shapeObj *FLTGetShape(FilterEncodingNode *psFilterNode, double *pdfDistance, + int *pnUnit) { + char **tokens = NULL; + int nTokens = 0; + FilterEncodingNode *psNode = psFilterNode; + char *szUnitStr = NULL; + char *szUnit = NULL; + + if (psNode) { + if (psNode->eType == FILTER_NODE_TYPE_SPATIAL && psNode->psRightNode) + psNode = psNode->psRightNode; + + if (FLTIsGeometryFilterNodeType(psNode->eType)) { + + if (psNode->pszValue && pdfDistance) { + /* + syntax expected is "distance;unit" or just "distance" + if unit is there syntax is "URI#unit" (eg http://..../#m) + or just "unit" + */ + tokens = msStringSplit(psNode->pszValue, ';', &nTokens); + if (tokens && nTokens >= 1) { + *pdfDistance = atof(tokens[0]); + + if (nTokens == 2 && pnUnit) { + szUnitStr = msStrdup(tokens[1]); + msFreeCharArray(tokens, nTokens); + nTokens = 0; + tokens = msStringSplit(szUnitStr, '#', &nTokens); + msFree(szUnitStr); + if (tokens && nTokens >= 1) { + if (nTokens == 1) + szUnit = tokens[0]; + else + szUnit = tokens[1]; + + if (strcasecmp(szUnit, "m") == 0 || + strcasecmp(szUnit, "meters") == 0) + *pnUnit = MS_METERS; + else if (strcasecmp(szUnit, "km") == 0 || + strcasecmp(szUnit, "kilometers") == 0) + *pnUnit = MS_KILOMETERS; + else if (strcasecmp(szUnit, "NM") == 0 || + strcasecmp(szUnit, "nauticalmiles") == 0) + *pnUnit = MS_NAUTICALMILES; + else if (strcasecmp(szUnit, "mi") == 0 || + strcasecmp(szUnit, "miles") == 0) + *pnUnit = MS_MILES; + else if (strcasecmp(szUnit, "in") == 0 || + strcasecmp(szUnit, "inches") == 0) + *pnUnit = MS_INCHES; + else if (strcasecmp(szUnit, "ft") == 0 || + strcasecmp(szUnit, "feet") == 0) + *pnUnit = MS_FEET; + else if (strcasecmp(szUnit, "deg") == 0 || + strcasecmp(szUnit, "dd") == 0) + *pnUnit = MS_DD; + else if (strcasecmp(szUnit, "px") == 0) + *pnUnit = MS_PIXELS; + } + } + } + msFreeCharArray(tokens, nTokens); + } + + return (shapeObj *)psNode->pOther; + } + } + return NULL; +} + +/************************************************************************/ +/* FLTGetBBOX */ +/* */ +/* Loop through the nodes are return the coordinates of the */ +/* first bbox node found. The return value is the epsg code of */ +/* the bbox. */ +/************************************************************************/ +const char *FLTGetBBOX(FilterEncodingNode *psFilterNode, rectObj *psRect) { + const char *pszReturn = NULL; + + if (!psFilterNode || !psRect) + return NULL; + + if (psFilterNode->pszValue && + strcasecmp(psFilterNode->pszValue, "BBOX") == 0) { + if (psFilterNode->psRightNode && psFilterNode->psRightNode->pOther) { + rectObj *pRect = (rectObj *)psFilterNode->psRightNode->pOther; + psRect->minx = pRect->minx; + psRect->miny = pRect->miny; + psRect->maxx = pRect->maxx; + psRect->maxy = pRect->maxy; + + return psFilterNode->pszSRS; + } + } else { + pszReturn = FLTGetBBOX(psFilterNode->psLeftNode, psRect); + if (pszReturn) + return pszReturn; + else + return FLTGetBBOX(psFilterNode->psRightNode, psRect); + } + + return pszReturn; +} + +const char *FLTGetDuring(FilterEncodingNode *psFilterNode, + const char **ppszTimeField) { + const char *pszReturn = NULL; + + if (!psFilterNode || !ppszTimeField) + return NULL; + + if (psFilterNode->pszValue && + strcasecmp(psFilterNode->pszValue, "During") == 0) { + *ppszTimeField = psFilterNode->psLeftNode->pszValue; + return psFilterNode->psRightNode->pszValue; + } else { + pszReturn = FLTGetDuring(psFilterNode->psLeftNode, ppszTimeField); + if (pszReturn) + return pszReturn; + else + return FLTGetDuring(psFilterNode->psRightNode, ppszTimeField); + } + + return pszReturn; +} + +/************************************************************************/ +/* FLTGetSQLExpression */ +/* */ +/* Build SQL expressions from the mapserver nodes. */ +/************************************************************************/ +char *FLTGetSQLExpression(FilterEncodingNode *psFilterNode, layerObj *lp) { + char *pszExpression = NULL; + + if (psFilterNode == NULL || lp == NULL) + return NULL; + + if (psFilterNode->eType == FILTER_NODE_TYPE_COMPARISON) { + if (psFilterNode->psLeftNode && psFilterNode->psRightNode) { + if (FLTIsBinaryComparisonFilterType(psFilterNode->pszValue)) { + pszExpression = FLTGetBinaryComparisonSQLExpresssion(psFilterNode, lp); + } else if (strcasecmp(psFilterNode->pszValue, "PropertyIsBetween") == 0) { + pszExpression = + FLTGetIsBetweenComparisonSQLExpresssion(psFilterNode, lp); + } else if (strcasecmp(psFilterNode->pszValue, "PropertyIsLike") == 0) { + pszExpression = FLTGetIsLikeComparisonSQLExpression(psFilterNode, lp); + } + } + } else if (psFilterNode->eType == FILTER_NODE_TYPE_LOGICAL) { + if (strcasecmp(psFilterNode->pszValue, "AND") == 0 || + strcasecmp(psFilterNode->pszValue, "OR") == 0) { + pszExpression = FLTGetLogicalComparisonSQLExpresssion(psFilterNode, lp); + + } else if (strcasecmp(psFilterNode->pszValue, "NOT") == 0) { + pszExpression = FLTGetLogicalComparisonSQLExpresssion(psFilterNode, lp); + } + } + + else if (psFilterNode->eType == FILTER_NODE_TYPE_SPATIAL) { + /* TODO */ + } else if (psFilterNode->eType == FILTER_NODE_TYPE_FEATUREID) { +#if defined(USE_WMS_SVR) || defined(USE_WFS_SVR) || defined(USE_WCS_SVR) || \ + defined(USE_SOS_SVR) + if (psFilterNode->pszValue) { + const char *pszAttribute = + msOWSLookupMetadata(&(lp->metadata), "OFG", "featureid"); + if (pszAttribute) { + int nTokens = 0; + char **tokens = msStringSplit(psFilterNode->pszValue, ',', &nTokens); + int bString = 0; + if (tokens && nTokens > 0) { + for (int i = 0; i < nTokens; i++) { + char *pszEscapedStr = NULL; + const char *pszId = tokens[i]; + const char *pszDot = strchr(pszId, '.'); + if (pszDot) + pszId = pszDot + 1; + + if (strlen(pszId) <= 0) + continue; + + if (FLTIsNumeric(pszId) == MS_FALSE) + bString = 1; + + pszEscapedStr = msLayerEscapeSQLParam(lp, pszId); + char szTmp[256]; + if (bString) { + if (lp->connectiontype == MS_OGR || + lp->connectiontype == MS_POSTGIS) + snprintf(szTmp, sizeof(szTmp), + "(CAST(%s AS CHARACTER(255)) = '%s')", pszAttribute, + pszEscapedStr); + else + snprintf(szTmp, sizeof(szTmp), "(%s = '%s')", pszAttribute, + pszEscapedStr); + } else + snprintf(szTmp, sizeof(szTmp), "(%s = %s)", pszAttribute, + pszEscapedStr); + + msFree(pszEscapedStr); + pszEscapedStr = NULL; + + if (pszExpression != NULL) + pszExpression = msStringConcatenate(pszExpression, " OR "); + else + /*opening and closing brackets*/ + pszExpression = msStringConcatenate(pszExpression, "("); + + pszExpression = msStringConcatenate(pszExpression, szTmp); + } + } + msFreeCharArray(tokens, nTokens); + } + /*opening and closing brackets*/ + if (pszExpression) + pszExpression = msStringConcatenate(pszExpression, ")"); + } +#else + msSetError(MS_MISCERR, "OWS support is not available.", + "FLTGetSQLExpression()"); + return NULL; +#endif + + } else if (lp->connectiontype != MS_OGR && + psFilterNode->eType == FILTER_NODE_TYPE_TEMPORAL) + pszExpression = msStrdup(FLTGetTimeExpression(psFilterNode, lp).c_str()); + + return pszExpression; +} + +/************************************************************************/ +/* FLTGetLogicalComparisonSQLExpresssion */ +/* */ +/* Return the expression for logical comparison expression. */ +/************************************************************************/ +char *FLTGetLogicalComparisonSQLExpresssion(FilterEncodingNode *psFilterNode, + layerObj *lp) { + char *pszBuffer = NULL; + char *pszTmp = NULL; + + if (lp == NULL) + return NULL; + + /* ==================================================================== */ + /* special case for BBOX node. */ + /* ==================================================================== */ + if (psFilterNode->psLeftNode && psFilterNode->psRightNode && + ((strcasecmp(psFilterNode->psLeftNode->pszValue, "BBOX") == 0) || + (strcasecmp(psFilterNode->psRightNode->pszValue, "BBOX") == 0))) { + if (strcasecmp(psFilterNode->psLeftNode->pszValue, "BBOX") != 0) + pszTmp = FLTGetSQLExpression(psFilterNode->psLeftNode, lp); + else + pszTmp = FLTGetSQLExpression(psFilterNode->psRightNode, lp); + + if (!pszTmp) + return NULL; + + const size_t nSize = strlen(pszTmp) + 1; + pszBuffer = (char *)malloc(nSize); + snprintf(pszBuffer, nSize, "%s", pszTmp); + } + + /* ==================================================================== */ + /* special case for temporal filter node (OGR layer only) */ + /* ==================================================================== */ + else if (lp->connectiontype == MS_OGR && psFilterNode->psLeftNode && + psFilterNode->psRightNode && + (psFilterNode->psLeftNode->eType == FILTER_NODE_TYPE_TEMPORAL || + psFilterNode->psRightNode->eType == FILTER_NODE_TYPE_TEMPORAL)) { + if (psFilterNode->psLeftNode->eType != FILTER_NODE_TYPE_TEMPORAL) + pszTmp = FLTGetSQLExpression(psFilterNode->psLeftNode, lp); + else + pszTmp = FLTGetSQLExpression(psFilterNode->psRightNode, lp); + + if (!pszTmp) + return NULL; + + const size_t nSize = strlen(pszTmp) + 1; + pszBuffer = (char *)malloc(nSize); + snprintf(pszBuffer, nSize, "%s", pszTmp); + } + + /* -------------------------------------------------------------------- */ + /* OR and AND */ + /* -------------------------------------------------------------------- */ + else if (psFilterNode->psLeftNode && psFilterNode->psRightNode) { + pszTmp = FLTGetSQLExpression(psFilterNode->psLeftNode, lp); + if (!pszTmp) + return NULL; + + pszBuffer = (char *)malloc( + sizeof(char) * (strlen(pszTmp) + strlen(psFilterNode->pszValue) + 5)); + pszBuffer[0] = '\0'; + strcat(pszBuffer, " ("); + strcat(pszBuffer, pszTmp); + strcat(pszBuffer, " "); + strcat(pszBuffer, psFilterNode->pszValue); + strcat(pszBuffer, " "); + + free(pszTmp); + + const size_t nTmp = strlen(pszBuffer); + pszTmp = FLTGetSQLExpression(psFilterNode->psRightNode, lp); + if (!pszTmp) { + free(pszBuffer); + return NULL; + } + + pszBuffer = (char *)msSmallRealloc( + pszBuffer, sizeof(char) * (strlen(pszTmp) + nTmp + 3)); + strcat(pszBuffer, pszTmp); + strcat(pszBuffer, ") "); + } + /* -------------------------------------------------------------------- */ + /* NOT */ + /* -------------------------------------------------------------------- */ + else if (psFilterNode->psLeftNode && + strcasecmp(psFilterNode->pszValue, "NOT") == 0) { + pszTmp = FLTGetSQLExpression(psFilterNode->psLeftNode, lp); + if (!pszTmp) + return NULL; + + pszBuffer = (char *)malloc(sizeof(char) * (strlen(pszTmp) + 9)); + pszBuffer[0] = '\0'; + + strcat(pszBuffer, " (NOT "); + strcat(pszBuffer, pszTmp); + strcat(pszBuffer, ") "); + } else + return NULL; + + /* -------------------------------------------------------------------- */ + /* Cleanup. */ + /* -------------------------------------------------------------------- */ + if (pszTmp != NULL) + free(pszTmp); + return pszBuffer; +} + +/************************************************************************/ +/* FLTGetBinaryComparisonSQLExpresssion */ +/* */ +/* Return the expression for a binary comparison filter node. */ +/************************************************************************/ +char *FLTGetBinaryComparisonSQLExpresssion(FilterEncodingNode *psFilterNode, + layerObj *lp) { + const size_t bufferSize = 1024; + char szBuffer[1024]; + int bString = 0; + char szTmp[256]; + char *pszEscapedStr = NULL; + + szBuffer[0] = '\0'; + if (!psFilterNode || !FLTIsBinaryComparisonFilterType(psFilterNode->pszValue)) + return NULL; + + /* -------------------------------------------------------------------- */ + /* check if the value is a numeric value or alphanumeric. If it */ + /* is alphanumeric, add quotes around attribute and values. */ + /* -------------------------------------------------------------------- */ + bString = 0; + if (psFilterNode->psRightNode->pszValue) { + const char *pszOFGType; + snprintf(szTmp, sizeof(szTmp), "%s_type", + psFilterNode->psLeftNode->pszValue); + pszOFGType = msOWSLookupMetadata(&(lp->metadata), "OFG", szTmp); + if (pszOFGType != NULL && strcasecmp(pszOFGType, "Character") == 0) + bString = 1; + + else if (FLTIsNumeric(psFilterNode->psRightNode->pszValue) == MS_FALSE) + bString = 1; + } + + /* special case to be able to have empty strings in the expression. */ + if (psFilterNode->psRightNode->pszValue == NULL) + bString = 1; + + /*opening bracket*/ + strlcat(szBuffer, " (", bufferSize); + + pszEscapedStr = + msLayerEscapePropertyName(lp, psFilterNode->psLeftNode->pszValue); + + /* attribute */ + /*case insensitive set ? */ + if (bString && strcasecmp(psFilterNode->pszValue, "PropertyIsEqualTo") == 0 && + psFilterNode->psRightNode->pOther && + (*(int *)psFilterNode->psRightNode->pOther) == 1) { + snprintf(szTmp, sizeof(szTmp), "lower(%s) ", pszEscapedStr); + strlcat(szBuffer, szTmp, bufferSize); + } else + strlcat(szBuffer, pszEscapedStr, bufferSize); + + msFree(pszEscapedStr); + pszEscapedStr = NULL; + + /* logical operator */ + if (strcasecmp(psFilterNode->pszValue, "PropertyIsEqualTo") == 0) + strlcat(szBuffer, "=", bufferSize); + else if (strcasecmp(psFilterNode->pszValue, "PropertyIsNotEqualTo") == 0) + strlcat(szBuffer, "<>", bufferSize); + else if (strcasecmp(psFilterNode->pszValue, "PropertyIsLessThan") == 0) + strlcat(szBuffer, "<", bufferSize); + else if (strcasecmp(psFilterNode->pszValue, "PropertyIsGreaterThan") == 0) + strlcat(szBuffer, ">", bufferSize); + else if (strcasecmp(psFilterNode->pszValue, "PropertyIsLessThanOrEqualTo") == + 0) + strlcat(szBuffer, "<=", bufferSize); + else if (strcasecmp(psFilterNode->pszValue, + "PropertyIsGreaterThanOrEqualTo") == 0) + strlcat(szBuffer, ">=", bufferSize); + + strlcat(szBuffer, " ", bufferSize); + + /* value */ + + if (bString && psFilterNode->psRightNode->pszValue && + strcasecmp(psFilterNode->pszValue, "PropertyIsEqualTo") == 0 && + psFilterNode->psRightNode->pOther && + (*(int *)psFilterNode->psRightNode->pOther) == 1) { + char *pszEscapedStr; + pszEscapedStr = + msLayerEscapeSQLParam(lp, psFilterNode->psRightNode->pszValue); + snprintf(szTmp, sizeof(szTmp), "lower('%s') ", pszEscapedStr); + msFree(pszEscapedStr); + strlcat(szBuffer, szTmp, bufferSize); + } else { + if (bString) + strlcat(szBuffer, "'", bufferSize); + + if (psFilterNode->psRightNode->pszValue) { + if (bString) { + char *pszEscapedStr; + pszEscapedStr = + msLayerEscapeSQLParam(lp, psFilterNode->psRightNode->pszValue); + strlcat(szBuffer, pszEscapedStr, bufferSize); + msFree(pszEscapedStr); + pszEscapedStr = NULL; + } else + strlcat(szBuffer, psFilterNode->psRightNode->pszValue, bufferSize); + } + + if (bString) + strlcat(szBuffer, "'", bufferSize); + } + /*closing bracket*/ + strlcat(szBuffer, ") ", bufferSize); + + return msStrdup(szBuffer); +} + +/************************************************************************/ +/* FLTGetIsBetweenComparisonSQLExpresssion */ +/* */ +/* Build an SQL expression for IsBteween Filter. */ +/************************************************************************/ +char *FLTGetIsBetweenComparisonSQLExpresssion(FilterEncodingNode *psFilterNode, + layerObj *lp) { + const size_t bufferSize = 1024; + char szBuffer[1024]; + char **aszBounds = NULL; + int nBounds = 0; + int bString = 0; + char szTmp[256]; + char *pszEscapedStr; + + szBuffer[0] = '\0'; + if (!psFilterNode || + !(strcasecmp(psFilterNode->pszValue, "PropertyIsBetween") == 0)) + return NULL; + + if (!psFilterNode->psLeftNode || !psFilterNode->psRightNode) + return NULL; + + /* -------------------------------------------------------------------- */ + /* Get the bounds value which are stored like boundmin;boundmax */ + /* -------------------------------------------------------------------- */ + aszBounds = msStringSplit(psFilterNode->psRightNode->pszValue, ';', &nBounds); + if (nBounds != 2) { + msFreeCharArray(aszBounds, nBounds); + return NULL; + } + /* -------------------------------------------------------------------- */ + /* check if the value is a numeric value or alphanumeric. If it */ + /* is alphanumeric, add quotes around attribute and values. */ + /* -------------------------------------------------------------------- */ + bString = 0; + if (aszBounds[0]) { + const char *pszOFGType; + snprintf(szTmp, sizeof(szTmp), "%s_type", + psFilterNode->psLeftNode->pszValue); + pszOFGType = msOWSLookupMetadata(&(lp->metadata), "OFG", szTmp); + if (pszOFGType != NULL && strcasecmp(pszOFGType, "Character") == 0) + bString = 1; + else if (FLTIsNumeric(aszBounds[0]) == MS_FALSE) + bString = 1; + } + if (!bString) { + if (aszBounds[1]) { + if (FLTIsNumeric(aszBounds[1]) == MS_FALSE) + bString = 1; + } + } + + /* -------------------------------------------------------------------- */ + /* build expression. */ + /* -------------------------------------------------------------------- */ + /*opening parenthesis */ + strlcat(szBuffer, " (", bufferSize); + + /* attribute */ + pszEscapedStr = + msLayerEscapePropertyName(lp, psFilterNode->psLeftNode->pszValue); + + strlcat(szBuffer, pszEscapedStr, bufferSize); + msFree(pszEscapedStr); + pszEscapedStr = NULL; + + /*between*/ + strlcat(szBuffer, " BETWEEN ", bufferSize); + + /*bound 1*/ + if (bString) + strlcat(szBuffer, "'", bufferSize); + pszEscapedStr = msLayerEscapeSQLParam(lp, aszBounds[0]); + strlcat(szBuffer, pszEscapedStr, bufferSize); + msFree(pszEscapedStr); + pszEscapedStr = NULL; + + if (bString) + strlcat(szBuffer, "'", bufferSize); + + strlcat(szBuffer, " AND ", bufferSize); + + /*bound 2*/ + if (bString) + strlcat(szBuffer, "'", bufferSize); + pszEscapedStr = msLayerEscapeSQLParam(lp, aszBounds[1]); + strlcat(szBuffer, pszEscapedStr, bufferSize); + msFree(pszEscapedStr); + pszEscapedStr = NULL; + + if (bString) + strlcat(szBuffer, "'", bufferSize); + + /*closing parenthesis*/ + strlcat(szBuffer, ")", bufferSize); + + msFreeCharArray(aszBounds, nBounds); + + return msStrdup(szBuffer); +} + +/************************************************************************/ +/* FLTGetIsLikeComparisonSQLExpression */ +/* */ +/* Build an sql expression for IsLike filter. */ +/************************************************************************/ +char *FLTGetIsLikeComparisonSQLExpression(FilterEncodingNode *psFilterNode, + layerObj *lp) { + const size_t bufferSize = 1024; + char szBuffer[1024]; + char *pszValue = NULL; + + const char *pszWild = NULL; + const char *pszSingle = NULL; + const char *pszEscape = NULL; + char szTmp[4]; + + int nLength = 0, i = 0, j = 0; + int bCaseInsensitive = 0; + + char *pszEscapedStr = NULL; + FEPropertyIsLike *propIsLike; + + if (!psFilterNode || !psFilterNode->pOther || !psFilterNode->psLeftNode || + !psFilterNode->psRightNode || !psFilterNode->psRightNode->pszValue) + return NULL; + + propIsLike = (FEPropertyIsLike *)psFilterNode->pOther; + pszWild = propIsLike->pszWildCard; + pszSingle = propIsLike->pszSingleChar; + pszEscape = propIsLike->pszEscapeChar; + bCaseInsensitive = propIsLike->bCaseInsensitive; + + if (!pszWild || strlen(pszWild) == 0 || !pszSingle || + strlen(pszSingle) == 0 || !pszEscape || strlen(pszEscape) == 0) + return NULL; + + if (pszEscape[0] == '\'') { + /* This might be valid, but the risk of SQL injection is too high */ + /* and the below code is not ready for that */ + /* Someone who does this has clearly suspect intentions ! */ + msSetError( + MS_MISCERR, + "Single quote character is not allowed as an escaping character.", + "FLTGetIsLikeComparisonSQLExpression()"); + return NULL; + } + + szBuffer[0] = '\0'; + /*opening bracket*/ + strlcat(szBuffer, " (", bufferSize); + + /* attribute name */ + pszEscapedStr = + msLayerEscapePropertyName(lp, psFilterNode->psLeftNode->pszValue); + + strlcat(szBuffer, pszEscapedStr, bufferSize); + msFree(pszEscapedStr); + pszEscapedStr = NULL; + + if (lp->connectiontype == MS_POSTGIS) { + if (bCaseInsensitive == 1) + strlcat(szBuffer, "::text ilike '", bufferSize); + else + strlcat(szBuffer, "::text like '", bufferSize); + } else + strlcat(szBuffer, " like '", bufferSize); + + pszValue = psFilterNode->psRightNode->pszValue; + nLength = strlen(pszValue); + + pszEscapedStr = (char *)msSmallMalloc(3 * nLength + 1); + + for (i = 0, j = 0; i < nLength; i++) { + char c = pszValue[i]; + if (c != pszWild[0] && c != pszSingle[0] && c != pszEscape[0]) { + if (c == '\'') { + pszEscapedStr[j++] = '\''; + pszEscapedStr[j++] = '\''; + } else if (c == '\\') { + pszEscapedStr[j++] = '\\'; + pszEscapedStr[j++] = '\\'; + } else + pszEscapedStr[j++] = c; + } else if (c == pszSingle[0]) { + pszEscapedStr[j++] = '_'; + } else if (c == pszEscape[0]) { + pszEscapedStr[j++] = pszEscape[0]; + if (i + 1 < nLength) { + char nextC = pszValue[i + 1]; + i++; + if (nextC == '\'') { + pszEscapedStr[j++] = '\''; + pszEscapedStr[j++] = '\''; + } else + pszEscapedStr[j++] = nextC; + } + } else if (c == pszWild[0]) { + pszEscapedStr[j++] = '%'; + } + } + pszEscapedStr[j++] = 0; + strlcat(szBuffer, pszEscapedStr, bufferSize); + msFree(pszEscapedStr); + + strlcat(szBuffer, "'", bufferSize); + if (lp->connectiontype != MS_OGR) { + if (lp->connectiontype == MS_POSTGIS && pszEscape[0] == '\\') + strlcat(szBuffer, " escape E'", bufferSize); + else + strlcat(szBuffer, " escape '", bufferSize); + szTmp[0] = pszEscape[0]; + if (pszEscape[0] == '\\') { + szTmp[1] = '\\'; + szTmp[2] = '\''; + szTmp[3] = '\0'; + } else { + szTmp[1] = '\''; + szTmp[2] = '\0'; + } + + strlcat(szBuffer, szTmp, bufferSize); + } + strlcat(szBuffer, ") ", bufferSize); + + return msStrdup(szBuffer); +} + +/************************************************************************/ +/* FLTHasSpatialFilter */ +/* */ +/* Utility function to see if a spatial filter is included in */ +/* the node. */ +/************************************************************************/ +int FLTHasSpatialFilter(FilterEncodingNode *psNode) { + int bResult = MS_FALSE; + + if (!psNode) + return MS_FALSE; + + if (psNode->eType == FILTER_NODE_TYPE_LOGICAL) { + if (psNode->psLeftNode) + bResult = FLTHasSpatialFilter(psNode->psLeftNode); + + if (bResult) + return MS_TRUE; + + if (psNode->psRightNode) + bResult = FLTHasSpatialFilter(psNode->psRightNode); + + if (bResult) + return MS_TRUE; + } else if (FLTIsBBoxFilter(psNode) || FLTIsPointFilter(psNode) || + FLTIsLineFilter(psNode) || FLTIsPolygonFilter(psNode)) + return MS_TRUE; + + return MS_FALSE; +} + +/************************************************************************/ +/* FLTCreateFeatureIdFilterEncoding */ +/* */ +/* Utility function to create a filter node of FeatureId type. */ +/************************************************************************/ +FilterEncodingNode *FLTCreateFeatureIdFilterEncoding(const char *pszString) { + FilterEncodingNode *psFilterNode = NULL; + + if (pszString) { + psFilterNode = FLTCreateFilterEncodingNode(); + psFilterNode->eType = FILTER_NODE_TYPE_FEATUREID; + psFilterNode->pszValue = msStrdup(pszString); + return psFilterNode; + } + return NULL; +} + +/************************************************************************/ +/* FLTParseGMLBox */ +/* */ +/* Parse gml box. Used for FE 1.0 */ +/************************************************************************/ +int FLTParseGMLBox(CPLXMLNode *psBox, rectObj *psBbox, char **ppszSRS) { + int bCoordinatesValid = 0; + CPLXMLNode *psCoordinates = NULL; + CPLXMLNode *psCoord1 = NULL, *psCoord2 = NULL; + char **papszCoords = NULL, **papszMin = NULL, **papszMax = NULL; + int nCoords = 0, nCoordsMin = 0, nCoordsMax = 0; + const char *pszTmpCoord = NULL; + const char *pszSRS = NULL; + const char *pszTS = NULL; + const char *pszCS = NULL; + double minx = 0.0, miny = 0.0, maxx = 0.0, maxy = 0.0; + + if (psBox) { + pszSRS = CPLGetXMLValue(psBox, "srsName", NULL); + if (ppszSRS && pszSRS) + *ppszSRS = msStrdup(pszSRS); + + psCoordinates = CPLGetXMLNode(psBox, "coordinates"); + pszTS = CPLGetXMLValue(psCoordinates, "ts", NULL); + if (pszTS == NULL) + pszTS = " "; + pszCS = CPLGetXMLValue(psCoordinates, "cs", NULL); + if (pszCS == NULL) + pszCS = ","; + pszTmpCoord = CPLGetXMLValue(psCoordinates, NULL, NULL); + + if (pszTmpCoord) { + papszCoords = msStringSplit(pszTmpCoord, pszTS[0], &nCoords); + if (papszCoords && nCoords == 2) { + papszMin = msStringSplit(papszCoords[0], pszCS[0], &nCoordsMin); + if (papszMin && nCoordsMin == 2) { + papszMax = msStringSplit(papszCoords[1], pszCS[0], &nCoordsMax); + } + if (papszMax && nCoordsMax == 2) { + bCoordinatesValid = 1; + minx = atof(papszMin[0]); + miny = atof(papszMin[1]); + maxx = atof(papszMax[0]); + maxy = atof(papszMax[1]); + } + + msFreeCharArray(papszMin, nCoordsMin); + msFreeCharArray(papszMax, nCoordsMax); + } + + msFreeCharArray(papszCoords, nCoords); + } else { + psCoord1 = CPLGetXMLNode(psBox, "coord"); + psCoord2 = FLTGetNextSibblingNode(psCoord1); + if (psCoord1 && psCoord2 && strcmp(psCoord2->pszValue, "coord") == 0) { + const char *pszX = CPLGetXMLValue(psCoord1, "X", NULL); + const char *pszY = CPLGetXMLValue(psCoord1, "Y", NULL); + if (pszX && pszY) { + minx = atof(pszX); + miny = atof(pszY); + + pszX = CPLGetXMLValue(psCoord2, "X", NULL); + pszY = CPLGetXMLValue(psCoord2, "Y", NULL); + if (pszX && pszY) { + maxx = atof(pszX); + maxy = atof(pszY); + bCoordinatesValid = 1; + } + } + } + } + } + + if (bCoordinatesValid) { + psBbox->minx = minx; + psBbox->miny = miny; + + psBbox->maxx = maxx; + psBbox->maxy = maxy; + } + + return bCoordinatesValid; +} +/************************************************************************/ +/* FLTParseGMLEnvelope */ +/* */ +/* Utility function to parse a gml:Envelope (used for SOS and FE1.1)*/ +/************************************************************************/ +int FLTParseGMLEnvelope(CPLXMLNode *psRoot, rectObj *psBbox, char **ppszSRS) { + CPLXMLNode *psUpperCorner = NULL, *psLowerCorner = NULL; + const char *pszLowerCorner = NULL, *pszUpperCorner = NULL; + int bValid = 0; + char **tokens; + int n; + + if (psRoot && psBbox && psRoot->eType == CXT_Element && + EQUAL(psRoot->pszValue, "Envelope")) { + /*Get the srs if available*/ + if (ppszSRS) { + const char *pszSRS = CPLGetXMLValue(psRoot, "srsName", NULL); + if (pszSRS != NULL) + *ppszSRS = msStrdup(pszSRS); + } + psLowerCorner = CPLSearchXMLNode(psRoot, "lowerCorner"); + psUpperCorner = CPLSearchXMLNode(psRoot, "upperCorner"); + + if (psLowerCorner && psUpperCorner) { + pszLowerCorner = CPLGetXMLValue(psLowerCorner, NULL, NULL); + pszUpperCorner = CPLGetXMLValue(psUpperCorner, NULL, NULL); + + if (pszLowerCorner && pszUpperCorner) { + tokens = msStringSplit(pszLowerCorner, ' ', &n); + if (tokens && n >= 2) { + psBbox->minx = atof(tokens[0]); + psBbox->miny = atof(tokens[1]); + + msFreeCharArray(tokens, n); + + tokens = msStringSplit(pszUpperCorner, ' ', &n); + if (tokens && n >= 2) { + psBbox->maxx = atof(tokens[0]); + psBbox->maxy = atof(tokens[1]); + bValid = 1; + } + } + msFreeCharArray(tokens, n); + } + } + } + + return bValid; +} + +/************************************************************************/ +/* FLTNeedSRSSwapping */ +/************************************************************************/ + +static int FLTNeedSRSSwapping(mapObj *map, const char *pszSRS) { + int bNeedSwapping = MS_FALSE; + projectionObj sProjTmp; + msInitProjection(&sProjTmp); + if (map) { + msProjectionInheritContextFrom(&sProjTmp, &map->projection); + } + if (msLoadProjectionStringEPSG(&sProjTmp, pszSRS) == 0) { + bNeedSwapping = msIsAxisInvertedProj(&sProjTmp); + } + msFreeProjection(&sProjTmp); + return bNeedSwapping; +} + +/************************************************************************/ +/* FLTDoAxisSwappingIfNecessary */ +/* */ +/* Explore all geometries and BBOX to do axis swapping when the */ +/* SRS requires it. If no explicit SRS is attached to the geometry */ +/* the bDefaultSRSNeedsAxisSwapping is taken into account. The */ +/* caller will have to determine its value from a more general */ +/* context. */ +/************************************************************************/ +void FLTDoAxisSwappingIfNecessary(mapObj *map, FilterEncodingNode *psFilterNode, + int bDefaultSRSNeedsAxisSwapping) { + if (psFilterNode == NULL) + return; + + if (psFilterNode->eType == FILTER_NODE_TYPE_SPATIAL && + psFilterNode->psRightNode->eType == FILTER_NODE_TYPE_BBOX) { + rectObj *rect = (rectObj *)psFilterNode->psRightNode->pOther; + const char *pszSRS = psFilterNode->pszSRS; + if ((pszSRS != NULL && FLTNeedSRSSwapping(map, pszSRS)) || + (pszSRS == NULL && bDefaultSRSNeedsAxisSwapping)) { + double tmp; + + tmp = rect->minx; + rect->minx = rect->miny; + rect->miny = tmp; + + tmp = rect->maxx; + rect->maxx = rect->maxy; + rect->maxy = tmp; + } + } else if (psFilterNode->eType == FILTER_NODE_TYPE_SPATIAL && + FLTIsGeometryFilterNodeType(psFilterNode->psRightNode->eType)) { + shapeObj *shape = (shapeObj *)(psFilterNode->psRightNode->pOther); + const char *pszSRS = psFilterNode->pszSRS; + if ((pszSRS != NULL && FLTNeedSRSSwapping(map, pszSRS)) || + (pszSRS == NULL && bDefaultSRSNeedsAxisSwapping)) { + msAxisSwapShape(shape); + } + } else { + FLTDoAxisSwappingIfNecessary(map, psFilterNode->psLeftNode, + bDefaultSRSNeedsAxisSwapping); + FLTDoAxisSwappingIfNecessary(map, psFilterNode->psRightNode, + bDefaultSRSNeedsAxisSwapping); + } +} + +static void FLTReplacePropertyName(FilterEncodingNode *psFilterNode, + const char *pszOldName, + const char *pszNewName) { + if (psFilterNode && pszOldName && pszNewName) { + if (psFilterNode->eType == FILTER_NODE_TYPE_PROPERTYNAME) { + if (psFilterNode->pszValue && + strcasecmp(psFilterNode->pszValue, pszOldName) == 0) { + msFree(psFilterNode->pszValue); + psFilterNode->pszValue = msStrdup(pszNewName); + } + } + if (psFilterNode->psLeftNode) + FLTReplacePropertyName(psFilterNode->psLeftNode, pszOldName, pszNewName); + if (psFilterNode->psRightNode) + FLTReplacePropertyName(psFilterNode->psRightNode, pszOldName, pszNewName); + } +} + +static int FLTIsGMLDefaultProperty(const char *pszName) { + return (strcmp(pszName, "gml:name") == 0 || + strcmp(pszName, "gml:description") == 0 || + strcmp(pszName, "gml:descriptionReference") == 0 || + strcmp(pszName, "gml:identifier") == 0 || + strcmp(pszName, "gml:boundedBy") == 0 || + strcmp(pszName, "@gml:id") == 0); +} + +static void +FLTStripNameSpacesFromPropertyName(FilterEncodingNode *psFilterNode) { + char **tokens = NULL; + int n = 0; + + if (psFilterNode) { + + if (psFilterNode->eType == FILTER_NODE_TYPE_COMPARISON && + psFilterNode->psLeftNode != NULL && + psFilterNode->psLeftNode->eType == FILTER_NODE_TYPE_PROPERTYNAME && + FLTIsGMLDefaultProperty(psFilterNode->psLeftNode->pszValue)) { + return; + } + + if (psFilterNode->eType == FILTER_NODE_TYPE_PROPERTYNAME) { + if (psFilterNode->pszValue && strstr(psFilterNode->pszValue, ":")) { + tokens = msStringSplit(psFilterNode->pszValue, ':', &n); + if (tokens && n == 2) { + msFree(psFilterNode->pszValue); + psFilterNode->pszValue = msStrdup(tokens[1]); + } + msFreeCharArray(tokens, n); + } + } + if (psFilterNode->psLeftNode) + FLTStripNameSpacesFromPropertyName(psFilterNode->psLeftNode); + if (psFilterNode->psRightNode) + FLTStripNameSpacesFromPropertyName(psFilterNode->psRightNode); + } +} + +static void FLTRemoveGroupName(FilterEncodingNode *psFilterNode, + gmlGroupListObj *groupList) { + int i; + + if (psFilterNode) { + + if (psFilterNode->eType == FILTER_NODE_TYPE_PROPERTYNAME) { + if (psFilterNode->pszValue != NULL) { + const char *pszPropertyName = psFilterNode->pszValue; + const char *pszSlash = strchr(pszPropertyName, '/'); + if (pszSlash != NULL) { + const char *pszColon = strchr(pszPropertyName, ':'); + if (pszColon != NULL && pszColon < pszSlash) + pszPropertyName = pszColon + 1; + for (i = 0; i < groupList->numgroups; i++) { + const char *pszGroupName = groupList->groups[i].name; + size_t nGroupNameLen = strlen(pszGroupName); + if (strncasecmp(pszPropertyName, pszGroupName, nGroupNameLen) == + 0 && + pszPropertyName[nGroupNameLen] == '/') { + char *pszTmp; + pszPropertyName = pszPropertyName + nGroupNameLen + 1; + pszColon = strchr(pszPropertyName, ':'); + if (pszColon != NULL) + pszPropertyName = pszColon + 1; + pszTmp = msStrdup(pszPropertyName); + msFree(psFilterNode->pszValue); + psFilterNode->pszValue = pszTmp; + break; + } + } + } + } + } + + if (psFilterNode->psLeftNode) + FLTRemoveGroupName(psFilterNode->psLeftNode, groupList); + if (psFilterNode->psRightNode) + FLTRemoveGroupName(psFilterNode->psRightNode, groupList); + } +} + +/************************************************************************/ +/* FLTPreParseFilterForAliasAndGroup */ +/* */ +/* Utility function to replace aliased' and grouped attributes */ +/* with their internal name. */ +/************************************************************************/ +void FLTPreParseFilterForAliasAndGroup(FilterEncodingNode *psFilterNode, + mapObj *map, int i, + const char *namespaces) { +#if defined(USE_WMS_SVR) || defined(USE_WFS_SVR) || defined(USE_WCS_SVR) || \ + defined(USE_SOS_SVR) + if (psFilterNode && map && i >= 0 && i < map->numlayers) { + /*strip name spaces before hand*/ + FLTStripNameSpacesFromPropertyName(psFilterNode); + + layerObj *lp = GET_LAYER(map, i); + int layerWasOpened = msLayerIsOpen(lp); + if (msLayerOpen(lp) == MS_SUCCESS && msLayerGetItems(lp) == MS_SUCCESS) { + + /* Remove group names from property names if using groupname/itemname + * syntax */ + gmlGroupListObj *groupList = msGMLGetGroups(lp, namespaces); + if (groupList && groupList->numgroups > 0) + FLTRemoveGroupName(psFilterNode, groupList); + msGMLFreeGroups(groupList); + + for (i = 0; i < lp->numitems; i++) { + if (!lp->items[i] || strlen(lp->items[i]) <= 0) + continue; + char szTmp[256]; + snprintf(szTmp, sizeof(szTmp), "%s_alias", lp->items[i]); + const char *pszFullName = + msOWSLookupMetadata(&(lp->metadata), namespaces, szTmp); + if (pszFullName) { + FLTReplacePropertyName(psFilterNode, pszFullName, lp->items[i]); + } + } + if (!layerWasOpened) /* do not close the layer if it has been opened + somewhere else (paging?) */ + msLayerClose(lp); + } + } +#else + msSetError(MS_MISCERR, "OWS support is not available.", + "FLTPreParseFilterForAlias()"); + +#endif +} + +/************************************************************************/ +/* FLTCheckFeatureIdFilters */ +/* */ +/* Check that FeatureId filters match features in the active */ +/* layer. */ +/************************************************************************/ +int FLTCheckFeatureIdFilters(FilterEncodingNode *psFilterNode, mapObj *map, + int i) { + int status = MS_SUCCESS; + + if (psFilterNode->eType == FILTER_NODE_TYPE_FEATUREID) { + char **tokens; + int nTokens = 0; + layerObj *lp; + int j; + + lp = GET_LAYER(map, i); + tokens = msStringSplit(psFilterNode->pszValue, ',', &nTokens); + for (j = 0; j < nTokens; j++) { + const char *pszId = tokens[j]; + const char *pszDot = strrchr(pszId, '.'); + if (pszDot) { + if (static_cast(pszDot - pszId) != strlen(lp->name) || + strncasecmp(pszId, lp->name, strlen(lp->name)) != 0) { + msSetError(MS_MISCERR, + "Feature id %s not consistent with feature type name %s.", + "FLTPreParseFilterForAlias()", pszId, lp->name); + status = MS_FAILURE; + break; + } + } + } + msFreeCharArray(tokens, nTokens); + } + + if (psFilterNode->psLeftNode) { + status = FLTCheckFeatureIdFilters(psFilterNode->psLeftNode, map, i); + if (status == MS_SUCCESS) { + if (psFilterNode->psRightNode) + status = FLTCheckFeatureIdFilters(psFilterNode->psRightNode, map, i); + } + } + return status; +} + +/************************************************************************/ +/* FLTCheckInvalidOperand */ +/* */ +/* Check that the operand of a comparison operator is valid */ +/* Currently only detects use of boundedBy in a binary comparison */ +/************************************************************************/ +int FLTCheckInvalidOperand(FilterEncodingNode *psFilterNode) { + int status = MS_SUCCESS; + + if (psFilterNode->eType == FILTER_NODE_TYPE_COMPARISON && + psFilterNode->psLeftNode != NULL && + psFilterNode->psLeftNode->eType == FILTER_NODE_TYPE_PROPERTYNAME) { + if (strcmp(psFilterNode->psLeftNode->pszValue, "gml:boundedBy") == 0 && + strcmp(psFilterNode->pszValue, "PropertyIsNull") != 0 && + strcmp(psFilterNode->pszValue, "PropertyIsNil") != 0) { + msSetError(MS_MISCERR, "Operand '%s' is invalid in comparison.", + "FLTCheckInvalidOperand()", + psFilterNode->psLeftNode->pszValue); + return MS_FAILURE; + } + } + if (psFilterNode->psLeftNode) { + status = FLTCheckInvalidOperand(psFilterNode->psLeftNode); + if (status == MS_SUCCESS) { + if (psFilterNode->psRightNode) + status = FLTCheckInvalidOperand(psFilterNode->psRightNode); + } + } + return status; +} + +/************************************************************************/ +/* FLTProcessPropertyIsNull */ +/* */ +/* HACK for PropertyIsNull processing. PostGIS & Spatialite only */ +/* for now. */ +/************************************************************************/ +int FLTProcessPropertyIsNull(FilterEncodingNode *psFilterNode, mapObj *map, + int i) { + int status = MS_SUCCESS; + + if (psFilterNode->eType == FILTER_NODE_TYPE_COMPARISON && + psFilterNode->psLeftNode != NULL && + psFilterNode->psLeftNode->eType == FILTER_NODE_TYPE_PROPERTYNAME && + strcmp(psFilterNode->pszValue, "PropertyIsNull") == 0 && + !FLTIsGMLDefaultProperty(psFilterNode->psLeftNode->pszValue)) { + layerObj *lp; + int layerWasOpened; + + lp = GET_LAYER(map, i); + layerWasOpened = msLayerIsOpen(lp); + + /* Horrible HACK to compensate for the lack of null testing in MapServer */ + if (lp->connectiontype == MS_POSTGIS || + (lp->connectiontype == MS_OGR && msOGRSupportsIsNull(lp))) { + msFree(psFilterNode->pszValue); + psFilterNode->pszValue = msStrdup("PropertyIsEqualTo"); + psFilterNode->psRightNode = FLTCreateBinaryCompFilterEncodingNode(); + psFilterNode->psRightNode->eType = FILTER_NODE_TYPE_LITERAL; + psFilterNode->psRightNode->pszValue = msStrdup("_MAPSERVER_NULL_"); + } + + if (!layerWasOpened) /* do not close the layer if it has been opened + somewhere else (paging?) */ + msLayerClose(lp); + } + + if (psFilterNode->psLeftNode) { + status = FLTProcessPropertyIsNull(psFilterNode->psLeftNode, map, i); + if (status == MS_SUCCESS) { + if (psFilterNode->psRightNode) + status = FLTProcessPropertyIsNull(psFilterNode->psRightNode, map, i); + } + } + return status; +} + +/************************************************************************/ +/* FLTCheckInvalidProperty */ +/* */ +/* Check that property names are known */ +/************************************************************************/ +int FLTCheckInvalidProperty(FilterEncodingNode *psFilterNode, mapObj *map, + int i) { + int status = MS_SUCCESS; + + if (psFilterNode->eType == FILTER_NODE_TYPE_COMPARISON && + psFilterNode->psLeftNode != NULL && + psFilterNode->psLeftNode->eType == FILTER_NODE_TYPE_PROPERTYNAME) { + layerObj *lp; + int layerWasOpened; + int bFound = MS_FALSE; + + if ((strcmp(psFilterNode->pszValue, "PropertyIsNull") == 0 || + strcmp(psFilterNode->pszValue, "PropertyIsNil") == 0) && + FLTIsGMLDefaultProperty(psFilterNode->psLeftNode->pszValue)) { + return MS_SUCCESS; + } + + lp = GET_LAYER(map, i); + layerWasOpened = msLayerIsOpen(lp); + if ((layerWasOpened || msLayerOpen(lp) == MS_SUCCESS) && + msLayerGetItems(lp) == MS_SUCCESS) { + int i; + gmlItemListObj *items = msGMLGetItems(lp, "G"); + for (i = 0; i < items->numitems; i++) { + if (!items->items[i].name || strlen(items->items[i].name) == 0 || + !items->items[i].visible) + continue; + if (strcasecmp(items->items[i].name, + psFilterNode->psLeftNode->pszValue) == 0) { + bFound = MS_TRUE; + break; + } + } + msGMLFreeItems(items); + } + + if (!layerWasOpened) /* do not close the layer if it has been opened + somewhere else (paging?) */ + msLayerClose(lp); + + if (!bFound) { + msSetError(MS_MISCERR, "Property '%s' is unknown.", + "FLTCheckInvalidProperty()", + psFilterNode->psLeftNode->pszValue); + return MS_FAILURE; + } + } + + if (psFilterNode->psLeftNode) { + status = FLTCheckInvalidProperty(psFilterNode->psLeftNode, map, i); + if (status == MS_SUCCESS) { + if (psFilterNode->psRightNode) + status = FLTCheckInvalidProperty(psFilterNode->psRightNode, map, i); + } + } + return status; +} + +/************************************************************************/ +/* FLTSimplify */ +/* */ +/* Simplify the expression by removing parts that evaluate to */ +/* constants. */ +/* The passed psFilterNode is potentially consumed by the function */ +/* and replaced by the returned value. */ +/* If the function returns NULL, *pnEvaluation = MS_FALSE means */ +/* that the filter evaluates to FALSE, or MS_TRUE that it */ +/* evaluates to TRUE */ +/************************************************************************/ +FilterEncodingNode *FLTSimplify(FilterEncodingNode *psFilterNode, + int *pnEvaluation) { + *pnEvaluation = -1; + + /* There are no nullable or nillable property in WFS currently */ + /* except gml:name or gml:description that are null */ + if (psFilterNode->eType == FILTER_NODE_TYPE_COMPARISON && + (strcmp(psFilterNode->pszValue, "PropertyIsNull") == 0 || + strcmp(psFilterNode->pszValue, "PropertyIsNil") == 0) && + psFilterNode->psLeftNode != NULL && + psFilterNode->psLeftNode->eType == FILTER_NODE_TYPE_PROPERTYNAME) { + if (strcmp(psFilterNode->pszValue, "PropertyIsNull") == 0 && + FLTIsGMLDefaultProperty(psFilterNode->psLeftNode->pszValue) && + strcmp(psFilterNode->psLeftNode->pszValue, "@gml:id") != 0 && + strcmp(psFilterNode->psLeftNode->pszValue, "gml:boundedBy") != 0) + *pnEvaluation = MS_TRUE; + else + *pnEvaluation = MS_FALSE; + FLTFreeFilterEncodingNode(psFilterNode); + return NULL; + } + + if (psFilterNode->eType == FILTER_NODE_TYPE_LOGICAL && + strcasecmp(psFilterNode->pszValue, "NOT") == 0 && + psFilterNode->psLeftNode != NULL) { + int nEvaluation; + psFilterNode->psLeftNode = + FLTSimplify(psFilterNode->psLeftNode, &nEvaluation); + if (psFilterNode->psLeftNode == NULL) { + *pnEvaluation = 1 - nEvaluation; + FLTFreeFilterEncodingNode(psFilterNode); + return NULL; + } + } + + if (psFilterNode->eType == FILTER_NODE_TYPE_LOGICAL && + (strcasecmp(psFilterNode->pszValue, "AND") == 0 || + strcasecmp(psFilterNode->pszValue, "OR") == 0) && + psFilterNode->psLeftNode != NULL && psFilterNode->psRightNode != NULL) { + FilterEncodingNode *psOtherNode; + int nEvaluation; + int nExpectedValForFastExit; + psFilterNode->psLeftNode = + FLTSimplify(psFilterNode->psLeftNode, &nEvaluation); + + if (strcasecmp(psFilterNode->pszValue, "AND") == 0) + nExpectedValForFastExit = MS_FALSE; + else + nExpectedValForFastExit = MS_TRUE; + + if (psFilterNode->psLeftNode == NULL) { + if (nEvaluation == nExpectedValForFastExit) { + *pnEvaluation = nEvaluation; + FLTFreeFilterEncodingNode(psFilterNode); + return NULL; + } + psOtherNode = psFilterNode->psRightNode; + psFilterNode->psRightNode = NULL; + FLTFreeFilterEncodingNode(psFilterNode); + return FLTSimplify(psOtherNode, pnEvaluation); + } + + psFilterNode->psRightNode = + FLTSimplify(psFilterNode->psRightNode, &nEvaluation); + if (psFilterNode->psRightNode == NULL) { + if (nEvaluation == nExpectedValForFastExit) { + *pnEvaluation = nEvaluation; + FLTFreeFilterEncodingNode(psFilterNode); + return NULL; + } + psOtherNode = psFilterNode->psLeftNode; + psFilterNode->psLeftNode = NULL; + FLTFreeFilterEncodingNode(psFilterNode); + return FLTSimplify(psOtherNode, pnEvaluation); + } + } + + return psFilterNode; +} + +#ifdef USE_LIBXML2 + +xmlNodePtr FLTGetCapabilities(xmlNsPtr psNsParent, xmlNsPtr psNsOgc, + int bTemporal) { + xmlNodePtr psRootNode = NULL, psNode = NULL, psSubNode = NULL, + psSubSubNode = NULL; + + psRootNode = xmlNewNode(psNsParent, BAD_CAST "Filter_Capabilities"); + + psNode = + xmlNewChild(psRootNode, psNsOgc, BAD_CAST "Spatial_Capabilities", NULL); + + psSubNode = xmlNewChild(psNode, psNsOgc, BAD_CAST "GeometryOperands", NULL); + xmlNewChild(psSubNode, psNsOgc, BAD_CAST "GeometryOperand", + BAD_CAST "gml:Point"); + xmlNewChild(psSubNode, psNsOgc, BAD_CAST "GeometryOperand", + BAD_CAST "gml:LineString"); + xmlNewChild(psSubNode, psNsOgc, BAD_CAST "GeometryOperand", + BAD_CAST "gml:Polygon"); + xmlNewChild(psSubNode, psNsOgc, BAD_CAST "GeometryOperand", + BAD_CAST "gml:Envelope"); + + psSubNode = xmlNewChild(psNode, psNsOgc, BAD_CAST "SpatialOperators", NULL); +#ifdef USE_GEOS + psSubSubNode = + xmlNewChild(psSubNode, psNsOgc, BAD_CAST "SpatialOperator", NULL); + xmlNewProp(psSubSubNode, BAD_CAST "name", BAD_CAST "Equals"); + psSubSubNode = + xmlNewChild(psSubNode, psNsOgc, BAD_CAST "SpatialOperator", NULL); + xmlNewProp(psSubSubNode, BAD_CAST "name", BAD_CAST "Disjoint"); + psSubSubNode = + xmlNewChild(psSubNode, psNsOgc, BAD_CAST "SpatialOperator", NULL); + xmlNewProp(psSubSubNode, BAD_CAST "name", BAD_CAST "Touches"); + psSubSubNode = + xmlNewChild(psSubNode, psNsOgc, BAD_CAST "SpatialOperator", NULL); + xmlNewProp(psSubSubNode, BAD_CAST "name", BAD_CAST "Within"); + psSubSubNode = + xmlNewChild(psSubNode, psNsOgc, BAD_CAST "SpatialOperator", NULL); + xmlNewProp(psSubSubNode, BAD_CAST "name", BAD_CAST "Overlaps"); + psSubSubNode = + xmlNewChild(psSubNode, psNsOgc, BAD_CAST "SpatialOperator", NULL); + xmlNewProp(psSubSubNode, BAD_CAST "name", BAD_CAST "Crosses"); + psSubSubNode = + xmlNewChild(psSubNode, psNsOgc, BAD_CAST "SpatialOperator", NULL); + xmlNewProp(psSubSubNode, BAD_CAST "name", BAD_CAST "Intersects"); + psSubSubNode = + xmlNewChild(psSubNode, psNsOgc, BAD_CAST "SpatialOperator", NULL); + xmlNewProp(psSubSubNode, BAD_CAST "name", BAD_CAST "Contains"); + psSubSubNode = + xmlNewChild(psSubNode, psNsOgc, BAD_CAST "SpatialOperator", NULL); + xmlNewProp(psSubSubNode, BAD_CAST "name", BAD_CAST "DWithin"); + psSubSubNode = + xmlNewChild(psSubNode, psNsOgc, BAD_CAST "SpatialOperator", NULL); + xmlNewProp(psSubSubNode, BAD_CAST "name", BAD_CAST "Beyond"); +#endif + psSubSubNode = + xmlNewChild(psSubNode, psNsOgc, BAD_CAST "SpatialOperator", NULL); + xmlNewProp(psSubSubNode, BAD_CAST "name", BAD_CAST "BBOX"); + + if (bTemporal) { + psNode = xmlNewChild(psRootNode, psNsOgc, BAD_CAST "Temporal_Capabilities", + NULL); + psSubNode = xmlNewChild(psNode, psNsOgc, BAD_CAST "TemporalOperands", NULL); + xmlNewChild(psSubNode, psNsOgc, BAD_CAST "TemporalOperand", + BAD_CAST "gml:TimePeriod"); + xmlNewChild(psSubNode, psNsOgc, BAD_CAST "TemporalOperand", + BAD_CAST "gml:TimeInstant"); + + psSubNode = + xmlNewChild(psNode, psNsOgc, BAD_CAST "TemporalOperators", NULL); + psSubSubNode = + xmlNewChild(psSubNode, psNsOgc, BAD_CAST "TemporalOperator", NULL); + xmlNewProp(psSubSubNode, BAD_CAST "name", BAD_CAST "TM_Equals"); + } + psNode = + xmlNewChild(psRootNode, psNsOgc, BAD_CAST "Scalar_Capabilities", NULL); + xmlNewChild(psNode, psNsOgc, BAD_CAST "LogicalOperators", NULL); + psNode = xmlNewChild(psNode, psNsOgc, BAD_CAST "ComparisonOperators", NULL); + xmlNewChild(psNode, psNsOgc, BAD_CAST "ComparisonOperator", + BAD_CAST "LessThan"); + xmlNewChild(psNode, psNsOgc, BAD_CAST "ComparisonOperator", + BAD_CAST "GreaterThan"); + xmlNewChild(psNode, psNsOgc, BAD_CAST "ComparisonOperator", + BAD_CAST "LessThanEqualTo"); + xmlNewChild(psNode, psNsOgc, BAD_CAST "ComparisonOperator", + BAD_CAST "GreaterThanEqualTo"); + xmlNewChild(psNode, psNsOgc, BAD_CAST "ComparisonOperator", + BAD_CAST "EqualTo"); + xmlNewChild(psNode, psNsOgc, BAD_CAST "ComparisonOperator", + BAD_CAST "NotEqualTo"); + xmlNewChild(psNode, psNsOgc, BAD_CAST "ComparisonOperator", BAD_CAST "Like"); + xmlNewChild(psNode, psNsOgc, BAD_CAST "ComparisonOperator", + BAD_CAST "Between"); + + psNode = xmlNewChild(psRootNode, psNsOgc, BAD_CAST "Id_Capabilities", NULL); + xmlNewChild(psNode, psNsOgc, BAD_CAST "EID", NULL); + xmlNewChild(psNode, psNsOgc, BAD_CAST "FID", NULL); + return psRootNode; +} +#endif diff --git a/src/mapogcfilter.h b/src/mapogcfilter.h new file mode 100644 index 0000000000..e246d092bc --- /dev/null +++ b/src/mapogcfilter.h @@ -0,0 +1,184 @@ +/********************************************************************** + * $Id$ + * + * Project: MapServer + * Purpose: OGC Filter Encoding implementation + * Author: Y. Assefa, DM Solutions Group (assefa@dmsolutions.ca) + * + ********************************************************************** + * Copyright (c) 2003, Y. Assefa, DM Solutions Group Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + ****************************************************************************/ + +#ifndef MAPOGCFILTER_H +#define MAPOGCFILTER_H + +#include "mapserver.h" + +/* There is a dependency to OGR for the MiniXML parser */ +#include "cpl_minixml.h" + +#ifdef USE_LIBXML2 + +#include +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + char *pszWildCard; + char *pszSingleChar; + char *pszEscapeChar; + int bCaseInsensitive; +} FEPropertyIsLike; + +/* -------------------------------------------------------------------- */ +/* prototypes. */ +/* -------------------------------------------------------------------- */ +MS_DLL_EXPORT int FLTIsNumeric(const char *pszValue); +MS_DLL_EXPORT int FLTApplyExpressionToLayer(layerObj *lp, + const char *pszExpression); +MS_DLL_EXPORT char *FLTGetExpressionForValuesRanges(layerObj *lp, + const char *item, + const char *value, + int forcecharcter); + +MS_DLL_EXPORT FilterEncodingNode * +FLTParseFilterEncoding(const char *szXMLString); +MS_DLL_EXPORT FilterEncodingNode *FLTCreateFilterEncodingNode(void); +MS_DLL_EXPORT char **FLTSplitFilters(const char *pszStr, int *pnTokens); +MS_DLL_EXPORT int FLTApplyFilterToLayer(FilterEncodingNode *psNode, mapObj *map, + int iLayerIndex); + +MS_DLL_EXPORT int FLTLayerApplyPlainFilterToLayer(FilterEncodingNode *psNode, + mapObj *map, int iLayerIndex); + +MS_DLL_EXPORT void FLTFreeFilterEncodingNode(FilterEncodingNode *psFilterNode); + +MS_DLL_EXPORT int FLTValidFilterNode(FilterEncodingNode *psFilterNode); +MS_DLL_EXPORT int FLTValidForBBoxFilter(FilterEncodingNode *psFilterNode); +MS_DLL_EXPORT int FLTNumberOfFilterType(FilterEncodingNode *psFilterNode, + const char *szType); +MS_DLL_EXPORT int FLTIsBBoxFilter(FilterEncodingNode *psFilterNode); +MS_DLL_EXPORT int FLTIsPointFilter(FilterEncodingNode *psFilterNode); +MS_DLL_EXPORT int FLTIsLineFilter(FilterEncodingNode *psFilterNode); +MS_DLL_EXPORT int FLTIsPolygonFilter(FilterEncodingNode *psFilterNode); + +MS_DLL_EXPORT int +FLTValidForPropertyIsLikeFilter(FilterEncodingNode *psFilterNode); +MS_DLL_EXPORT int FLTIsOnlyPropertyIsLike(FilterEncodingNode *psFilterNode); + +MS_DLL_EXPORT void FLTInsertElementInNode(FilterEncodingNode *psFilterNode, + CPLXMLNode *psXMLNode); +MS_DLL_EXPORT int FLTIsLogicalFilterType(const char *pszValue); +MS_DLL_EXPORT int FLTIsBinaryComparisonFilterType(const char *pszValue); +MS_DLL_EXPORT int FLTIsComparisonFilterType(const char *pszValue); +MS_DLL_EXPORT int FLTIsFeatureIdFilterType(const char *pszValue); +MS_DLL_EXPORT int FLTIsSpatialFilterType(const char *pszValue); +MS_DLL_EXPORT int FLTIsTemporalFilterType(const char *pszValue); +MS_DLL_EXPORT int FLTIsSupportedFilterType(CPLXMLNode *psXMLNode); + +MS_DLL_EXPORT const char *FLTGetBBOX(FilterEncodingNode *psFilterNode, + rectObj *psRect); +const char *FLTGetDuring(FilterEncodingNode *psFilterNode, + const char **ppszTimeField); + +MS_DLL_EXPORT shapeObj *FLTGetShape(FilterEncodingNode *psFilterNode, + double *pdfDistance, int *pnUnit); + +MS_DLL_EXPORT int FLTHasSpatialFilter(FilterEncodingNode *psFilterNode); + +MS_DLL_EXPORT char *FLTGetSQLExpression(FilterEncodingNode *psFilterNode, + layerObj *lp); +MS_DLL_EXPORT char * +FLTGetBinaryComparisonSQLExpresssion(FilterEncodingNode *psFilterNode, + layerObj *lp); +MS_DLL_EXPORT char * +FLTGetIsBetweenComparisonSQLExpresssion(FilterEncodingNode *psFilterNode, + layerObj *lp); +MS_DLL_EXPORT char * +FLTGetIsLikeComparisonSQLExpression(FilterEncodingNode *psFilterNode, + layerObj *lp); + +MS_DLL_EXPORT char * +FLTGetLogicalComparisonSQLExpresssion(FilterEncodingNode *psFilterNode, + layerObj *lp); +MS_DLL_EXPORT int FLTIsSimpleFilter(FilterEncodingNode *psFilterNode); + +MS_DLL_EXPORT FilterEncodingNode * +FLTCreateFeatureIdFilterEncoding(const char *pszString); + +MS_DLL_EXPORT int FLTParseGMLEnvelope(CPLXMLNode *psRoot, rectObj *psBbox, + char **ppszSRS); +MS_DLL_EXPORT int FLTParseGMLBox(CPLXMLNode *psBox, rectObj *psBbox, + char **ppszSRS); + +/*common-expressions*/ +MS_DLL_EXPORT char *FLTGetCommonExpression(FilterEncodingNode *psFilterNode, + layerObj *lp); +MS_DLL_EXPORT int +FLTApplyFilterToLayerCommonExpression(mapObj *map, int iLayerIndex, + const char *pszExpression); + +#ifdef USE_LIBXML2 +MS_DLL_EXPORT xmlNodePtr FLTGetCapabilities(xmlNsPtr psNsParent, + xmlNsPtr psNsOgc, int bTemporal); +#endif + +void FLTDoAxisSwappingIfNecessary(mapObj *map, FilterEncodingNode *psFilterNode, + int bDefaultSRSNeedsAxisSwapping); + +void FLTPreParseFilterForAliasAndGroup(FilterEncodingNode *psFilterNode, + mapObj *map, int i, + const char *namespaces); +int FLTCheckFeatureIdFilters(FilterEncodingNode *psFilterNode, mapObj *map, + int i); +int FLTCheckInvalidOperand(FilterEncodingNode *psFilterNode); +int FLTCheckInvalidProperty(FilterEncodingNode *psFilterNode, mapObj *map, + int i); +FilterEncodingNode *FLTSimplify(FilterEncodingNode *psFilterNode, + int *pnEvaluation); +int FLTApplyFilterToLayerCommonExpressionWithRect(mapObj *map, int iLayerIndex, + const char *pszExpression, + rectObj rect); +int FLTProcessPropertyIsNull(FilterEncodingNode *psFilterNode, mapObj *map, + int i); +int FLTLayerSetInvalidRectIfSupported(mapObj *map, layerObj *lp, rectObj *rect, + const char *metadata_namespaces); + +#ifdef __cplusplus +} +std::string msGetLikePatternAsRegex(const FEPropertyIsLike *propIsLike, + const char *pszValue); + +std::string FLTGetBinaryComparisonCommonExpression(layerObj *lp, + const char *pszPropertyName, + bool bForceString, + const char *pszOp, + const char *pszValue); + +std::string FLTGetTimeExpression(FilterEncodingNode *psFilterNode, + layerObj *lp); + +#endif + +#endif diff --git a/src/mapogcfiltercommon.cpp b/src/mapogcfiltercommon.cpp new file mode 100644 index 0000000000..d72729d203 --- /dev/null +++ b/src/mapogcfiltercommon.cpp @@ -0,0 +1,747 @@ +/********************************************************************** + * $Id$ + * + * Project: MapServer + * Purpose: OGC Filter Encoding implementation + * Author: Y. Assefa, DM Solutions Group (assefa@dmsolutions.ca) + * + ********************************************************************** + * Copyright (c) 2003, Y. Assefa, DM Solutions Group Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + ****************************************************************************/ + +#include "mapogcfilter.h" +#include "mapserver.h" +#include "mapows.h" +#include "mapowscommon.h" +#include "cpl_minixml.h" + +#include + +static std::string FLTEscapePropertyName(const char *pszStr, + char chEscapeChar) { + std::string ret; + for (; *pszStr; ++pszStr) { + if (*pszStr == chEscapeChar) { + ret += chEscapeChar; + ret += chEscapeChar; + } else { + ret += *pszStr; + } + } + return ret; +} + +std::string msGetLikePatternAsRegex(const FEPropertyIsLike *propIsLike, + const char *pszValue) { + /* From + * http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap09.html#tag_09_04 + */ + /* also add double quote because we are within a string */ + const char *pszRegexSpecialCharsAndDoubleQuote = "\\^${[().*+?|\""; + + const char *pszWild = propIsLike->pszWildCard; + const char *pszSingle = propIsLike->pszSingleChar; + const char *pszEscape = propIsLike->pszEscapeChar; + + std::string expr; + const size_t nLength = strlen(pszValue); + + if (nLength > 0) { + expr += '^'; + } + for (size_t i = 0; i < nLength; i++) { + if (pszValue[i] == pszSingle[0]) { + expr += '.'; + /* The Filter escape character is supposed to only escape the single, + * wildcard and escape character */ + } else if (pszValue[i] == pszEscape[0] && + (pszValue[i + 1] == pszSingle[0] || + pszValue[i + 1] == pszWild[0] || + pszValue[i + 1] == pszEscape[0])) { + if (pszValue[i + 1] == '\\') { + /* Tricky case: \ must be escaped ncce in the regular expression context + so that the regexp matches it as an ordinary character. + But as \ is also the escape character for MapServer string, we + must escape it again. */ + expr += "\\" + "\\" + "\\" + "\\"; + } else { + /* If the escaped character is itself a regular expression special + * character */ + /* we need to regular-expression-escape-it ! */ + if (strchr(pszRegexSpecialCharsAndDoubleQuote, pszValue[i + 1])) { + expr += '\\'; + } + expr += pszValue[i + 1]; + } + i++; + } else if (pszValue[i] == pszWild[0]) { + expr += ".*"; + } + /* Escape regular expressions special characters and double quote */ + else if (strchr(pszRegexSpecialCharsAndDoubleQuote, pszValue[i])) { + if (pszValue[i] == '\\') { + /* See above explantation */ + expr += "\\" + "\\" + "\\" + "\\"; + } else { + expr += '\\'; + expr += pszValue[i]; + } + } else { + expr += pszValue[i]; + } + } + if (nLength > 0) { + expr += '$'; + } + return expr; +} + +static std::string +FLTGetIsLikeComparisonCommonExpression(const FilterEncodingNode *psFilterNode) { + + if (!psFilterNode || !psFilterNode->pOther || !psFilterNode->psLeftNode || + !psFilterNode->psRightNode || !psFilterNode->psRightNode->pszValue) + return std::string(); + + const FEPropertyIsLike *propIsLike = + (const FEPropertyIsLike *)psFilterNode->pOther; + const char *pszWild = propIsLike->pszWildCard; + const char *pszSingle = propIsLike->pszSingleChar; + const char *pszEscape = propIsLike->pszEscapeChar; + const bool bCaseInsensitive = propIsLike->bCaseInsensitive != 0; + + if (!pszWild || strlen(pszWild) == 0 || !pszSingle || + strlen(pszSingle) == 0 || !pszEscape || strlen(pszEscape) == 0) + return std::string(); + + /* -------------------------------------------------------------------- */ + /* Use operand with regular expressions. */ + /* -------------------------------------------------------------------- */ + std::string expr("(\"["); + + /* attribute */ + expr += FLTEscapePropertyName(psFilterNode->psLeftNode->pszValue, '"'); + + /* #3521 */ + if (bCaseInsensitive) + expr += "]\" ~* \""; + else + expr += "]\" ~ \""; + + expr += + msGetLikePatternAsRegex(propIsLike, psFilterNode->psRightNode->pszValue); + + expr += "\")"; + return expr; +} + +static std::string +FLTGetIsBetweenComparisonCommonExpresssion(FilterEncodingNode *psFilterNode, + layerObj *lp) { + if (psFilterNode->psLeftNode == NULL || psFilterNode->psRightNode == NULL) + return std::string(); + + /* -------------------------------------------------------------------- */ + /* Get the bounds value which are stored like boundmin;boundmax */ + /* -------------------------------------------------------------------- */ + const auto bounds = msStringSplit(psFilterNode->psRightNode->pszValue, ';'); + if (bounds.size() != 2) { + return std::string(); + } + + /* -------------------------------------------------------------------- */ + /* check if the value is a numeric value or alphanumeric. If it */ + /* is alphanumeric, add quotes around attribute and values. */ + /* -------------------------------------------------------------------- */ + bool bString = false; + bool bDateTime = false; + + const char *pszType = msOWSLookupMetadata( + &(lp->metadata), "OFG", + (std::string(psFilterNode->psLeftNode->pszValue) + "_type").c_str()); + if (pszType != NULL && (strcasecmp(pszType, "Character") == 0)) + bString = true; + else if (pszType != NULL && (strcasecmp(pszType, "Date") == 0)) + bDateTime = true; + else if (FLTIsNumeric(bounds[0].c_str()) == MS_FALSE) + bString = true; + + if (!bString && !bDateTime) { + if (FLTIsNumeric(bounds[1].c_str()) == MS_FALSE) + bString = true; + } + + std::string expr; + /* -------------------------------------------------------------------- */ + /* build expression. */ + /* -------------------------------------------------------------------- */ + /* attribute */ + if (bString) + expr += "(\"["; + else + expr += "(["; + + expr += FLTEscapePropertyName(psFilterNode->psLeftNode->pszValue, + bString ? '"' : ']'); + + if (bString) + expr += "]\" "; + else + expr += "] "; + + expr += " >= "; + + if (bString) { + expr += '\"'; + } else if (bDateTime) { + expr += '`'; + } + + expr += msStdStringEscape(bounds[0].c_str()); + + if (bString) { + expr += '\"'; + } else if (bDateTime) { + expr += '`'; + } + + expr += " AND "; + + if (bString) + expr += " \"["; + else + expr += " ["; + + /* attribute */ + expr += psFilterNode->psLeftNode->pszValue; + + if (bString) + expr += "]\" "; + else + expr += "] "; + + expr += " <= "; + + if (bString) { + expr += '\"'; + } else if (bDateTime) { + expr += '`'; + } + + expr += msStdStringEscape(bounds[1].c_str()); + + if (bString) { + expr += '\"'; + } else if (bDateTime) { + expr += '`'; + } + expr += ')'; + + return expr; +} + +std::string FLTGetBinaryComparisonCommonExpression(layerObj *lp, + const char *pszPropertyName, + bool bForceString, + const char *pszOp, + const char *pszValue) { + assert(pszPropertyName); + assert(pszOp); + + /* -------------------------------------------------------------------- */ + /* check if the value is a numeric value or alphanumeric. If it */ + /* is alphanumeric, add quotes around attribute and values. */ + /* -------------------------------------------------------------------- */ + bool bString = false; + bool bDateTime = false; + if (pszValue) { + const char *pszType = + msOWSLookupMetadata(&(lp->metadata), "OFG", + (std::string(pszPropertyName) + "_type").c_str()); + if (pszType != NULL && (strcasecmp(pszType, "Character") == 0)) + bString = true; + else if (pszType != NULL && (strcasecmp(pszType, "Date") == 0)) + bDateTime = true; + else if (FLTIsNumeric(pszValue) == MS_FALSE) + bString = true; + } + + /* special case to be able to have empty strings in the expression. */ + /* propertyislike is always treated as string */ + if (!pszValue || bForceString) + bString = true; + + /* attribute */ + std::string expr; + if (bString) + expr = "(\"["; + else + expr = "(["; + + expr += FLTEscapePropertyName(pszPropertyName, bString ? '"' : ']'); + + if (bString) + expr += "]\" "; + else + expr += "] "; + + expr += pszOp; + expr += ' '; + + /* value */ + if (bString) { + expr += "\""; + } else if (bDateTime) { + expr += "`"; + } + + if (pszValue) { + expr += msStdStringEscape(pszValue); + } + + if (bString) { + expr += "\""; + } else if (bDateTime) { + expr += "`"; + } + + expr += ")"; + + return expr; +} + +static std::string +FLTGetBinaryComparisonCommonExpression(FilterEncodingNode *psFilterNode, + layerObj *lp) { + + const char *pszPropertyName = psFilterNode->psLeftNode->pszValue; + const char *pszValue = psFilterNode->psRightNode->pszValue; + const char *pszXMLOp = psFilterNode->pszValue; + if (pszPropertyName && pszXMLOp) { + /* special case to be able to have empty strings in the expression. */ + /* propertyislike is always treated as string */ + const bool bForceString = (strcasecmp(pszXMLOp, "PropertyIsLike") == 0); + + const char *pszOp = nullptr; + if (strcasecmp(pszXMLOp, "PropertyIsEqualTo") == 0) { + /* case insensitive set ? */ + if (psFilterNode->psRightNode->pOther && + (*(int *)psFilterNode->psRightNode->pOther) == 1) + pszOp = "=*"; + else + pszOp = "="; + } else if (strcasecmp(pszXMLOp, "PropertyIsNotEqualTo") == 0) + pszOp = "!="; + else if (strcasecmp(pszXMLOp, "PropertyIsLessThan") == 0) + pszOp = "<"; + else if (strcasecmp(pszXMLOp, "PropertyIsGreaterThan") == 0) + pszOp = ">"; + else if (strcasecmp(pszXMLOp, "PropertyIsLessThanOrEqualTo") == 0) + pszOp = "<="; + else if (strcasecmp(pszXMLOp, "PropertyIsGreaterThanOrEqualTo") == 0) + pszOp = ">="; + else if (strcasecmp(pszXMLOp, "PropertyIsLike") == 0) + pszOp = "~"; + else + return std::string(); + + return FLTGetBinaryComparisonCommonExpression( + lp, pszPropertyName, bForceString, pszOp, pszValue); + } + + return std::string(); +} + +static std::string +FLTGetLogicalComparisonCommonExpression(FilterEncodingNode *psFilterNode, + layerObj *lp) { + std::string expr; + /* -------------------------------------------------------------------- */ + /* OR and AND */ + /* -------------------------------------------------------------------- */ + if (psFilterNode->psLeftNode && psFilterNode->psRightNode) { + char *pszTmp = FLTGetCommonExpression(psFilterNode->psLeftNode, lp); + if (!pszTmp) + return std::string(); + + expr = '('; + expr += pszTmp; + msFree(pszTmp); + expr += ' '; + expr += psFilterNode->pszValue; + expr += ' '; + + pszTmp = FLTGetCommonExpression(psFilterNode->psRightNode, lp); + if (!pszTmp) { + return std::string(); + } + + expr += pszTmp; + msFree(pszTmp); + expr += ')'; + } + /* -------------------------------------------------------------------- */ + /* NOT */ + /* -------------------------------------------------------------------- */ + else if (psFilterNode->psLeftNode && + strcasecmp(psFilterNode->pszValue, "NOT") == 0) { + char *pszTmp = FLTGetCommonExpression(psFilterNode->psLeftNode, lp); + if (!pszTmp) + return std::string(); + + expr = "(NOT "; + expr += pszTmp; + msFree(pszTmp); + expr += ')'; + } + + return expr; +} + +static std::string +FLTGetSpatialComparisonCommonExpression(FilterEncodingNode *psNode, + layerObj *lp) { + std::string expr; + double dfDistance = -1; + shapeObj *psTmpShape = NULL; + bool bBBoxQuery = false; + bool bAlreadyReprojected = false; + + if (lp == NULL) + return std::string(); + + /* get the shape */ + if (FLTIsBBoxFilter(psNode)) { + rectObj sQueryRect; + FLTGetBBOX(psNode, &sQueryRect); + + char szPolygon[512]; + snprintf(szPolygon, sizeof(szPolygon), + "POLYGON((%.18f %.18f,%.18f %.18f,%.18f %.18f,%.18f %.18f,%.18f " + "%.18f))", + sQueryRect.minx, sQueryRect.miny, sQueryRect.minx, sQueryRect.maxy, + sQueryRect.maxx, sQueryRect.maxy, sQueryRect.maxx, sQueryRect.miny, + sQueryRect.minx, sQueryRect.miny); + + psTmpShape = msShapeFromWKT(szPolygon); + + /* + ** This is a horrible hack to deal with world-extent requests and + ** reprojection. msProjectRect() detects if reprojection from longlat to + ** projected SRS, and in that case it transforms the bbox to + *-1e-15,-1e-15,1e15,1e15 + ** to ensure that all features are returned. + ** + ** Make wfs_200_cite_filter_bbox_world.xml and + *wfs_200_cite_postgis_bbox_world.xml pass + */ + if (fabs(sQueryRect.minx - -180.0) < 1e-5 && + fabs(sQueryRect.miny - -90.0) < 1e-5 && + fabs(sQueryRect.maxx - 180.0) < 1e-5 && + fabs(sQueryRect.maxy - 90.0) < 1e-5) { + if (lp->projection.numargs > 0) { + projectionObj sProjTmp; + if (psNode->pszSRS) { + msInitProjection(&sProjTmp); + msProjectionInheritContextFrom(&sProjTmp, &lp->projection); + } + if (psNode->pszSRS) { + /* Use the non EPSG variant since axis swapping is done in + * FLTDoAxisSwappingIfNecessary */ + if (msLoadProjectionString(&sProjTmp, psNode->pszSRS) == 0) { + msProjectRect(&sProjTmp, &lp->projection, &sQueryRect); + } + } else if (lp->map->projection.numargs > 0) + msProjectRect(&lp->map->projection, &lp->projection, &sQueryRect); + if (psNode->pszSRS) + msFreeProjection(&sProjTmp); + } + if (sQueryRect.minx <= -1e14) { + msFreeShape(psTmpShape); + msFree(psTmpShape); + psTmpShape = (shapeObj *)msSmallMalloc(sizeof(shapeObj)); + msInitShape(psTmpShape); + msRectToPolygon(sQueryRect, psTmpShape); + bAlreadyReprojected = true; + } + } + + bBBoxQuery = true; + } else { + /* other geos type operations */ + + /* project shape to layer projection. If the proj is not part of the filter + query, assume that the cooredinates are in the map projection */ + + int nUnit = -1; + shapeObj *psQueryShape = FLTGetShape(psNode, &dfDistance, &nUnit); + + if ((strcasecmp(psNode->pszValue, "DWithin") == 0 || + strcasecmp(psNode->pszValue, "Beyond") == 0) && + dfDistance > 0) { + int nLayerUnit = lp->units; + if (nLayerUnit == -1) + nLayerUnit = GetMapserverUnitUsingProj(&lp->projection); + if (nLayerUnit == -1) + nLayerUnit = lp->map->units; + if (nLayerUnit == -1) + nLayerUnit = GetMapserverUnitUsingProj(&lp->map->projection); + + if (nUnit >= 0 && nUnit != nLayerUnit) + dfDistance *= + msInchesPerUnit(nUnit, 0) / + msInchesPerUnit(nLayerUnit, 0); /* target is layer units */ + } + + psTmpShape = psQueryShape; + } + + if (psTmpShape) { + + /* + ** target is layer projection + */ + if (!bAlreadyReprojected && lp->projection.numargs > 0) { + projectionObj sProjTmp; + if (psNode->pszSRS) { + msInitProjection(&sProjTmp); + msProjectionInheritContextFrom(&sProjTmp, &lp->projection); + } + if (psNode->pszSRS) { + /* Use the non EPSG variant since axis swapping is done in + * FLTDoAxisSwappingIfNecessary */ + if (msLoadProjectionString(&sProjTmp, psNode->pszSRS) == 0) { + msProjectShape(&sProjTmp, &lp->projection, psTmpShape); + } + } else if (lp->map->projection.numargs > 0) + msProjectShape(&lp->map->projection, &lp->projection, psTmpShape); + if (psNode->pszSRS) + msFreeProjection(&sProjTmp); + } + + /* function name */ + if (bBBoxQuery) { + expr = "intersects"; + } else { + if (strncasecmp(psNode->pszValue, "intersect", 9) == 0) + expr = "intersects"; + else { + expr = msStringToLower(std::string(psNode->pszValue)); + } + } + /* geometry binding */ + expr += "([shape],fromText('"; + + /* filter geometry */ + char *pszWktText = msGEOSShapeToWKT(psTmpShape); + expr += pszWktText ? pszWktText : "Cannot translate shape to WKT"; + expr += "')"; + msGEOSFreeWKT(pszWktText); + + /* (optional) beyond/dwithin distance, always 0.0 since we apply the + * distance as a buffer earlier */ + if ((strcasecmp(psNode->pszValue, "DWithin") == 0 || + strcasecmp(psNode->pszValue, "Beyond") == 0)) { + char szBuffer[32]; + snprintf(szBuffer, sizeof(szBuffer), ",%g", dfDistance); + expr += szBuffer; + } + + /* terminate the function */ + expr += ") = TRUE"; + } + + /* + ** Cleanup + */ + if (bBBoxQuery) { + msFreeShape(psTmpShape); + msFree(psTmpShape); + } + + return expr; +} + +static std::string +FLTGetFeatureIdCommonExpression(FilterEncodingNode *psFilterNode, + layerObj *lp) { + std::string expr; + +#if defined(USE_WMS_SVR) || defined(USE_WFS_SVR) || defined(USE_WCS_SVR) || \ + defined(USE_SOS_SVR) + if (psFilterNode->pszValue) { + const char *pszAttribute = + msOWSLookupMetadata(&(lp->metadata), "OFG", "featureid"); + if (pszAttribute) { + const auto tokens = msStringSplit(psFilterNode->pszValue, ','); + if (!tokens.empty()) { + bool bString = false; + for (size_t i = 0; i < tokens.size(); i++) { + const char *pszId = tokens[i].c_str(); + const char *pszDot = strrchr(pszId, '.'); + if (pszDot) + pszId = pszDot + 1; + + if (i == 0) { + if (FLTIsNumeric(pszId) == MS_FALSE) + bString = true; + } + + if (!expr.empty()) + expr += " OR "; + else + expr = '('; + + if (bString) { + expr += "(\"["; + expr += FLTEscapePropertyName(pszAttribute, '"'); + expr += "]\" == \""; + expr += pszId; + expr += "\")"; + } else { + expr += "(["; + expr += FLTEscapePropertyName(pszAttribute, ']'); + expr += "] == "; + expr += pszId; + expr += ")"; + } + } + } + } + + /* opening and closing brackets are needed for mapserver expressions */ + if (!expr.empty()) + expr += ')'; + } +#endif + + return expr; +} + +std::string FLTGetTimeExpression(FilterEncodingNode *psFilterNode, + layerObj *lp) { + if (lp == NULL) + return std::string(); + + std::string expr; + const char *pszTimeField = nullptr; + const char *pszTimeValue = FLTGetDuring(psFilterNode, &pszTimeField); + if (pszTimeField && pszTimeValue) { + expressionObj old_filter; + msInitExpression(&old_filter); + msCopyExpression(&old_filter, &lp->filter); /* save existing filter */ + msFreeExpression(&lp->filter); + if (msLayerSetTimeFilter(lp, pszTimeValue, pszTimeField) == MS_TRUE && + lp->filter.string) { + expr = lp->filter.string; + } + msCopyExpression(&lp->filter, &old_filter); /* restore old filter */ + msFreeExpression(&old_filter); + } + return expr; +} + +char *FLTGetCommonExpression(FilterEncodingNode *psFilterNode, layerObj *lp) { + char *pszExpression = NULL; + + if (!psFilterNode) + return NULL; + + if (psFilterNode->eType == FILTER_NODE_TYPE_COMPARISON) { + if (psFilterNode->psLeftNode && psFilterNode->psRightNode) { + if (FLTIsBinaryComparisonFilterType(psFilterNode->pszValue)) + pszExpression = msStrdup( + FLTGetBinaryComparisonCommonExpression(psFilterNode, lp).c_str()); + else if (strcasecmp(psFilterNode->pszValue, "PropertyIsLike") == 0) + pszExpression = msStrdup( + FLTGetIsLikeComparisonCommonExpression(psFilterNode).c_str()); + else if (strcasecmp(psFilterNode->pszValue, "PropertyIsBetween") == 0) + pszExpression = msStrdup( + FLTGetIsBetweenComparisonCommonExpresssion(psFilterNode, lp) + .c_str()); + } + } else if (psFilterNode->eType == FILTER_NODE_TYPE_LOGICAL) { + pszExpression = msStrdup( + FLTGetLogicalComparisonCommonExpression(psFilterNode, lp).c_str()); + } else if (psFilterNode->eType == FILTER_NODE_TYPE_SPATIAL) { + pszExpression = msStrdup( + FLTGetSpatialComparisonCommonExpression(psFilterNode, lp).c_str()); + } else if (psFilterNode->eType == FILTER_NODE_TYPE_FEATUREID) { + pszExpression = + msStrdup(FLTGetFeatureIdCommonExpression(psFilterNode, lp).c_str()); + } else if (psFilterNode->eType == FILTER_NODE_TYPE_TEMPORAL) { + pszExpression = msStrdup(FLTGetTimeExpression(psFilterNode, lp).c_str()); + } + + return pszExpression; +} + +int FLTApplyFilterToLayerCommonExpression(mapObj *map, int iLayerIndex, + const char *pszExpression) { + return FLTApplyFilterToLayerCommonExpressionWithRect( + map, iLayerIndex, pszExpression, map->extent); +} + +/* rect must be in map->projection */ +int FLTApplyFilterToLayerCommonExpressionWithRect(mapObj *map, int iLayerIndex, + const char *pszExpression, + rectObj rect) { + int retval; + + const int save_startindex = map->query.startindex; + const int save_maxfeatures = map->query.maxfeatures; + const int save_only_cache_result_count = map->query.only_cache_result_count; + const int save_cache_shapes = map->query.cache_shapes; + const int save_max_cached_shape_count = map->query.max_cached_shape_count; + const int save_max_cached_shape_ram_amount = + map->query.max_cached_shape_ram_amount; + msInitQuery(&(map->query)); + map->query.startindex = save_startindex; + map->query.maxfeatures = save_maxfeatures; + map->query.only_cache_result_count = save_only_cache_result_count; + map->query.cache_shapes = save_cache_shapes; + map->query.max_cached_shape_count = save_max_cached_shape_count; + map->query.max_cached_shape_ram_amount = save_max_cached_shape_ram_amount; + + map->query.mode = MS_QUERY_MULTIPLE; + map->query.layer = iLayerIndex; + + map->query.rect = rect; + + if (pszExpression) { + map->query.type = MS_QUERY_BY_FILTER; + msInitExpression(&map->query.filter); + map->query.filter.string = msStrdup(pszExpression); + map->query.filter.type = MS_EXPRESSION; /* a logical expression */ + + retval = msQueryByFilter(map); + } else { + map->query.type = MS_QUERY_BY_RECT; + retval = msQueryByRect(map); + } + + return retval; +} diff --git a/src/mapogcsld.cpp b/src/mapogcsld.cpp new file mode 100644 index 0000000000..f7c0704c32 --- /dev/null +++ b/src/mapogcsld.cpp @@ -0,0 +1,5531 @@ +/********************************************************************** + * $Id$ + * + * Project: MapServer + * Purpose: OGC SLD implementation + * Author: Y. Assefa, DM Solutions Group (assefa@dmsolutions.ca) + * + ********************************************************************** + * Copyright (c) 2003, Y. Assefa, DM Solutions Group Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of this Software or works derived from this Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + ****************************************************************************/ + +#include "mapogcsld.h" +#include "mapogcfilter.h" +#include "mapserver.h" +#include "mapows.h" +#include "mapcopy.h" +#include "cpl_string.h" + +extern "C" { +extern int yyparse(parseObj *); +} + +static inline void IGUR_sizet(size_t ignored) { + (void)ignored; +} /* Ignore GCC Unused Result */ + +#define SLD_LINE_SYMBOL_NAME "sld_line_symbol" +#define SLD_LINE_SYMBOL_DASH_NAME "sld_line_symbol_dash" +#define SLD_MARK_SYMBOL_SQUARE "sld_mark_symbol_square" +#define SLD_MARK_SYMBOL_SQUARE_FILLED "sld_mark_symbol_square_filled" +#define SLD_MARK_SYMBOL_CIRCLE "sld_mark_symbol_circle" +#define SLD_MARK_SYMBOL_CIRCLE_FILLED "sld_mark_symbol_circle_filled" +#define SLD_MARK_SYMBOL_TRIANGLE "sld_mark_symbol_triangle" +#define SLD_MARK_SYMBOL_TRIANGLE_FILLED "sld_mark_symbol_triangle_filled" +#define SLD_MARK_SYMBOL_STAR "sld_mark_symbol_star" +#define SLD_MARK_SYMBOL_STAR_FILLED "sld_mark_symbol_star_filled" +#define SLD_MARK_SYMBOL_CROSS "sld_mark_symbol_cross" +#define SLD_MARK_SYMBOL_CROSS_FILLED "sld_mark_symbol_cross_filled" +#define SLD_MARK_SYMBOL_X "sld_mark_symbol_x" +#define SLD_MARK_SYMBOL_X_FILLED "sld_mark_symbol_x_filled" + +/************************************************************************/ +/* msSLDApplySLDURL */ +/* */ +/* Use the SLD document given through a URL and apply the SLD */ +/* on the map. Layer name and Named Layer's name parameter are */ +/* used to do the match. */ +/************************************************************************/ +int msSLDApplySLDURL(mapObj *map, const char *szURL, int iLayer, + const char *pszStyleLayerName, char **ppszLayerNames) { + /* needed for libcurl function msHTTPGetFile in maphttp.c */ +#if defined(USE_CURL) + + char *pszSLDTmpFile = NULL; + int status = 0; + char *pszSLDbuf = NULL; + FILE *fp = NULL; + int nStatus = MS_FAILURE; + + if (map && szURL) { + map->sldurl = (char *)szURL; + pszSLDTmpFile = msTmpFile(map, map->mappath, NULL, "sld.xml"); + if (pszSLDTmpFile == NULL) { + pszSLDTmpFile = msTmpFile(map, NULL, NULL, "sld.xml"); + } + if (pszSLDTmpFile == NULL) { + msSetError( + MS_WMSERR, + "Could not determine temporary file. Please make sure that the " + "temporary path is set. The temporary path can be defined for " + "example by setting TEMPPATH in the map file. Please check the " + "MapServer documentation on temporary path settings.", + "msSLDApplySLDURL()"); + } else { + int nMaxRemoteSLDBytes; + const char *pszMaxRemoteSLDBytes = msOWSLookupMetadata( + &(map->web.metadata), "MO", "remote_sld_max_bytes"); + if (!pszMaxRemoteSLDBytes) { + nMaxRemoteSLDBytes = 1024 * 1024; /* 1 megaByte */ + } else { + nMaxRemoteSLDBytes = atoi(pszMaxRemoteSLDBytes); + } + if (msHTTPGetFile(szURL, pszSLDTmpFile, &status, -1, 0, 0, + nMaxRemoteSLDBytes) == MS_SUCCESS) { + if ((fp = fopen(pszSLDTmpFile, "rb")) != NULL) { + int nBufsize = 0; + fseek(fp, 0, SEEK_END); + nBufsize = ftell(fp); + if (nBufsize > 0) { + rewind(fp); + pszSLDbuf = (char *)malloc((nBufsize + 1) * sizeof(char)); + if (pszSLDbuf == NULL) { + msSetError(MS_MEMERR, "Failed to open SLD file.", + "msSLDApplySLDURL()"); + } else { + IGUR_sizet(fread(pszSLDbuf, 1, nBufsize, fp)); + pszSLDbuf[nBufsize] = '\0'; + } + } else { + msSetError(MS_WMSERR, "Could not open SLD %s as it appears empty", + "msSLDApplySLDURL", szURL); + } + fclose(fp); + unlink(pszSLDTmpFile); + } + } else { + unlink(pszSLDTmpFile); + msSetError( + MS_WMSERR, + "Could not open SLD %s and save it in a temporary file. Please " + "make sure that the sld url is valid and that the temporary path " + "is set. The temporary path can be defined for example by setting " + "TEMPPATH in the map file. Please check the MapServer " + "documentation on temporary path settings.", + "msSLDApplySLDURL", szURL); + } + msFree(pszSLDTmpFile); + if (pszSLDbuf) + nStatus = msSLDApplySLD(map, pszSLDbuf, iLayer, pszStyleLayerName, + ppszLayerNames); + } + map->sldurl = NULL; + } + + msFree(pszSLDbuf); + + return nStatus; + +#else + msSetError(MS_MISCERR, "WMS/WFS client support is not enabled .", + "msSLDApplySLDURL()"); + return (MS_FAILURE); +#endif +} + +/************************************************************************/ +/* msSLDApplyFromFile */ +/* */ +/* Apply SLD from a file on disk to the layerObj */ +/************************************************************************/ +int msSLDApplyFromFile(mapObj *map, layerObj *layer, const char *filename) { + + FILE *fp = NULL; + + int nStatus = MS_FAILURE; + + /* open SLD file */ + char szPath[MS_MAXPATHLEN]; + char *pszSLDbuf = NULL; + const char *realpath = msBuildPath(szPath, map->mappath, filename); + + if ((fp = fopen(realpath, "rb")) != NULL) { + int nBufsize = 0; + fseek(fp, 0, SEEK_END); + nBufsize = ftell(fp); + if (nBufsize > 0) { + rewind(fp); + pszSLDbuf = (char *)malloc((nBufsize + 1) * sizeof(char)); + if (pszSLDbuf == NULL) { + msSetError(MS_MEMERR, "Failed to read SLD file.", + "msSLDApplyFromFile()"); + } else { + IGUR_sizet(fread(pszSLDbuf, 1, nBufsize, fp)); + pszSLDbuf[nBufsize] = '\0'; + } + } else { + msSetError(MS_IOERR, "Could not open SLD %s as it appears empty", + "msSLDApplyFromFile", realpath); + } + fclose(fp); + } + if (pszSLDbuf) { + // if not set, then use the first NamedStyle in the SLD file + // even if the names don't match + const char *pszMetadataName = "SLD_USE_FIRST_NAMEDLAYER"; + const char *pszValue = + msLookupHashTable(&(layer->metadata), pszMetadataName); + if (pszValue == NULL) { + msInsertHashTable(&(layer->metadata), pszMetadataName, "true"); + } + nStatus = msSLDApplySLD(map, pszSLDbuf, layer->index, NULL, NULL); + } else { + msSetError(MS_IOERR, "Invalid SLD filename: \"%s\".", + "msSLDApplyFromFile()", realpath); + } + + msFree(pszSLDbuf); + return nStatus; +} + +#if defined(USE_WMS_SVR) || defined(USE_WFS_SVR) || defined(USE_WCS_SVR) || \ + defined(USE_SOS_SVR) +/* -------------------------------------------------------------------- */ +/* If the same layer is given more that once, we need to */ +/* duplicate it. */ +/* -------------------------------------------------------------------- */ +static void msSLDApplySLD_DuplicateLayers(mapObj *map, int nSLDLayers, + layerObj *pasSLDLayers) { + int m; + for (m = 0; m < nSLDLayers; m++) { + int l; + int nIndex = msGetLayerIndex(map, pasSLDLayers[m].name); + if (pasSLDLayers[m].name == NULL) + continue; + if (nIndex < 0) + continue; + for (l = m + 1; l < nSLDLayers; l++) { + if (pasSLDLayers[l].name == NULL) + continue; + if (strcasecmp(pasSLDLayers[m].name, pasSLDLayers[l].name) == 0) { + layerObj *psTmpLayer = (layerObj *)malloc(sizeof(layerObj)); + char tmpId[128]; + + initLayer(psTmpLayer, map); + msCopyLayer(psTmpLayer, GET_LAYER(map, nIndex)); + /* open the source layer */ + if (!psTmpLayer->vtable) { + if (msInitializeVirtualTable(psTmpLayer) != MS_SUCCESS) { + MS_REFCNT_DECR(psTmpLayer); + continue; + } + } + + /*make the name unique*/ + snprintf(tmpId, sizeof(tmpId), "%lx_%x_%d", (long)time(NULL), + (int)getpid(), map->numlayers); + if (psTmpLayer->name) + msFree(psTmpLayer->name); + psTmpLayer->name = msStrdup(tmpId); + msFree(pasSLDLayers[l].name); + pasSLDLayers[l].name = msStrdup(tmpId); + msInsertLayer(map, psTmpLayer, -1); + MS_REFCNT_DECR(psTmpLayer); + } + } + } +} +#endif + +static int msApplySldLayerToMapLayer(layerObj *sldLayer, layerObj *lp) { + + if (sldLayer->numclasses > 0) { + int iClass = 0; + bool bSLDHasNamedClass = false; + + lp->type = sldLayer->type; + lp->rendermode = MS_ALL_MATCHING_CLASSES; + + for (int k = 0; k < sldLayer->numclasses; k++) { + if (sldLayer->_class[k]->group) { + bSLDHasNamedClass = true; + break; + } + } + + for (int k = 0; k < lp->numclasses; k++) { + if (lp->_class[k] != NULL) { + lp->_class[k]->layer = NULL; + if (freeClass(lp->_class[k]) == MS_SUCCESS) { + msFree(lp->_class[k]); + lp->_class[k] = NULL; + } + } + } + lp->numclasses = 0; + + if (bSLDHasNamedClass && sldLayer->classgroup) { + /* Set the class group to the class that has UserStyle.IsDefaultf + */ + msFree(lp->classgroup); + lp->classgroup = msStrdup(sldLayer->classgroup); + } else { + /*unset the classgroup on the layer if it was set. This allows the + layer to render with all the classes defined in the SLD*/ + msFree(lp->classgroup); + lp->classgroup = NULL; + } + + for (int k = 0; k < sldLayer->numclasses; k++) { + if (msGrowLayerClasses(lp) == NULL) + return MS_FAILURE; + + initClass(lp->_class[iClass]); + msCopyClass(lp->_class[iClass], sldLayer->_class[k], NULL); + lp->_class[iClass]->layer = lp; + lp->numclasses++; + + /*aliases may have been used as part of the sld text symbolizer + for label element. Try to process it if that is the case #3114*/ + + const int layerWasOpened = msLayerIsOpen(lp); + + if (layerWasOpened || (msLayerOpen(lp) == MS_SUCCESS && + msLayerGetItems(lp) == MS_SUCCESS)) { + + if (lp->_class[iClass]->text.string) { + for (int z = 0; z < lp->numitems; z++) { + if (!lp->items[z] || strlen(lp->items[z]) == 0) + continue; + + char *pszTmp1 = msStrdup(lp->_class[iClass]->text.string); + const char *pszFullName = msOWSLookupMetadata( + &(lp->metadata), "G", + std::string(lp->items[z]).append("_alias").c_str()); + + if (pszFullName != NULL && (strstr(pszTmp1, pszFullName) != NULL)) { + pszTmp1 = msReplaceSubstring(pszTmp1, pszFullName, lp->items[z]); + std::string osTmp("("); + osTmp.append(pszTmp1).append(")"); + // Silence false positive Coverity Scan warnings which wrongly + // believes that osTmp.c_str() might be used by + // msLoadExpressionString() after osTmp is destroyed. + // coverity[escape] + msLoadExpressionString(&(lp->_class[iClass]->text), + osTmp.c_str()); + } + msFree(pszTmp1); + } + } + if (!layerWasOpened) { // don't close the layer if already + // open + msLayerClose(lp); + } + } + iClass++; + } + } else { + /*this is probably an SLD that uses Named styles*/ + if (sldLayer->classgroup) { + int k; + for (k = 0; k < lp->numclasses; k++) { + if (lp->_class[k]->group && + strcasecmp(lp->_class[k]->group, sldLayer->classgroup) == 0) + break; + } + if (k < lp->numclasses) { + msFree(lp->classgroup); + lp->classgroup = msStrdup(sldLayer->classgroup); + } else { + /* TODO we throw an exception ?*/ + } + } + } + if (sldLayer->labelitem) { + if (lp->labelitem) + free(lp->labelitem); + + lp->labelitem = msStrdup(sldLayer->labelitem); + } + + if (sldLayer->classitem) { + if (lp->classitem) + free(lp->classitem); + + lp->classitem = msStrdup(sldLayer->classitem); + } + + /* opacity for sld raster */ + if (lp->type == MS_LAYER_RASTER && sldLayer->compositer && + sldLayer->compositer->opacity != 100) + msSetLayerOpacity(lp, sldLayer->compositer->opacity); + + /* mark as auto-generate SLD */ + if (lp->connectiontype == MS_WMS) + msInsertHashTable(&(lp->metadata), "wms_sld_body", "auto"); + + /* The SLD might have a FeatureTypeConstraint */ + if (sldLayer->filter.type == MS_EXPRESSION) { + if (lp->filter.string && lp->filter.type == MS_EXPRESSION) { + char *pszBuffer = msStringConcatenate(NULL, "(("); + pszBuffer = msStringConcatenate(pszBuffer, lp->filter.string); + pszBuffer = msStringConcatenate(pszBuffer, ") AND ("); + pszBuffer = msStringConcatenate(pszBuffer, sldLayer->filter.string); + pszBuffer = msStringConcatenate(pszBuffer, "))"); + msFreeExpression(&lp->filter); + msInitExpression(&lp->filter); + lp->filter.string = pszBuffer; + lp->filter.type = MS_EXPRESSION; + } else { + msFreeExpression(&lp->filter); + msInitExpression(&lp->filter); + lp->filter.string = msStrdup(sldLayer->filter.string); + lp->filter.type = MS_EXPRESSION; + } + } + + /*in some cases it would make sense to concatenate all the class + expressions and use it to set the filter on the layer. This + could increase performance. Will do it for db types layers + #2840*/ + if (lp->filter.string == NULL || + (lp->filter.string && lp->filter.type == MS_STRING && !lp->filteritem)) { + if (lp->connectiontype == MS_POSTGIS || + lp->connectiontype == MS_ORACLESPATIAL || + lp->connectiontype == MS_PLUGIN) { + if (lp->numclasses > 0) { + /* check first that all classes have an expression type. + That is the only way we can concatenate them and set the + filter expression */ + int k; + for (k = 0; k < lp->numclasses; k++) { + if (lp->_class[k]->expression.type != MS_EXPRESSION) + break; + } + if (k == lp->numclasses) { + char szTmp[512]; + char *pszBuffer = NULL; + for (k = 0; k < lp->numclasses; k++) { + if (pszBuffer == NULL) + snprintf(szTmp, sizeof(szTmp), "%s", + "(("); /* we a building a string expression, + explicitly set type below */ + else + snprintf(szTmp, sizeof(szTmp), "%s", " OR "); + + pszBuffer = msStringConcatenate(pszBuffer, szTmp); + pszBuffer = msStringConcatenate(pszBuffer, + lp->_class[k]->expression.string); + } + + snprintf(szTmp, sizeof(szTmp), "%s", "))"); + pszBuffer = msStringConcatenate(pszBuffer, szTmp); + + msFreeExpression(&lp->filter); + msInitExpression(&lp->filter); + lp->filter.string = msStrdup(pszBuffer); + lp->filter.type = MS_EXPRESSION; + + msFree(pszBuffer); + } + } + } + } + + return MS_SUCCESS; +} + +/************************************************************************/ +/* msSLDApplySLD */ +/* */ +/* Parses the SLD into array of layers. Go through the map and */ +/* compare the SLD layers and the map layers using the name. If */ +/* they have the same name, copy the classes associated with */ +/* the SLD layers onto the map layers. */ +/************************************************************************/ +int msSLDApplySLD(mapObj *map, const char *psSLDXML, int iLayer, + const char *pszStyleLayerName, char **ppszLayerNames) { +#if defined(USE_WMS_SVR) || defined(USE_WFS_SVR) || defined(USE_WCS_SVR) || \ + defined(USE_SOS_SVR) + int nSLDLayers = 0; + layerObj *pasSLDLayers = NULL; + int nStatus = MS_SUCCESS; + /*const char *pszSLDNotSupported = NULL;*/ + + pasSLDLayers = msSLDParseSLD(map, psSLDXML, &nSLDLayers); + if (pasSLDLayers == NULL) { + errorObj *psError = msGetErrorObj(); + if (psError && psError->code != MS_NOERR) + return MS_FAILURE; + } + + if (pasSLDLayers && nSLDLayers > 0) { + int i; + + msSLDApplySLD_DuplicateLayers(map, nSLDLayers, pasSLDLayers); + + for (i = 0; i < map->numlayers; i++) { + layerObj *lp = NULL; + const char *pszWMSLayerName = NULL; + int j; + int bUseSpecificLayer = 0; + + if (iLayer >= 0 && iLayer < map->numlayers) { + i = iLayer; + bUseSpecificLayer = 1; + } + + lp = GET_LAYER(map, i); + + /* compare layer name to wms_name as well */ + pszWMSLayerName = msOWSLookupMetadata(&(lp->metadata), "MO", "name"); + + bool bSldApplied = false; + + for (j = 0; j < nSLDLayers; j++) { + layerObj *sldLayer = &pasSLDLayers[j]; + + /* -------------------------------------------------------------------- + */ + /* copy : - class */ + /* - layer's labelitem */ + /* -------------------------------------------------------------------- + */ + if ((sldLayer->name && pszStyleLayerName == NULL && + ((strcasecmp(lp->name, sldLayer->name) == 0 || + (pszWMSLayerName && + strcasecmp(pszWMSLayerName, sldLayer->name) == 0)) || + (lp->group && strcasecmp(lp->group, sldLayer->name) == 0))) || + (bUseSpecificLayer && pszStyleLayerName && sldLayer->name && + strcasecmp(sldLayer->name, pszStyleLayerName) == 0)) { +#ifdef notdef + /*this is a test code if we decide to flag some layers as not + * supporting SLD*/ + pszSLDNotSupported = + msOWSLookupMetadata(&(lp->metadata), "M", "SLD_NOT_SUPPORTED"); + if (pszSLDNotSupported) { + msSetError(MS_WMSERR, "Layer %s does not support SLD", + "msSLDApplySLD", sldLayer->name); + nsStatus = MS_FAILURE; + goto sld_cleanup; + } +#endif + if (msApplySldLayerToMapLayer(sldLayer, lp) == MS_FAILURE) { + nStatus = MS_FAILURE; + goto sld_cleanup; + }; + bSldApplied = true; + break; + } + } + if (bUseSpecificLayer) { + if (!bSldApplied) { + // there was no name match between the map layer and the SLD named + // layer - check if we should apply the first SLD layer anyway + const char *pszSLDUseFirstNamedLayer = + msLookupHashTable(&(lp->metadata), "SLD_USE_FIRST_NAMEDLAYER"); + if (pszSLDUseFirstNamedLayer) { + if (strcasecmp(pszSLDUseFirstNamedLayer, "true") == 0) { + layerObj *firstSldLayer = &pasSLDLayers[0]; + if (msApplySldLayerToMapLayer(firstSldLayer, lp) == MS_FAILURE) { + nStatus = MS_FAILURE; + goto sld_cleanup; + }; + } + } + } + break; + } + } + + /* -------------------------------------------------------------------- */ + /* if needed return a comma separated list of the layers found */ + /* in the sld. */ + /* -------------------------------------------------------------------- */ + if (ppszLayerNames) { + char *pszTmp = NULL; + for (i = 0; i < nSLDLayers; i++) { + if (pasSLDLayers[i].name) { + if (pszTmp != NULL) + pszTmp = msStringConcatenate(pszTmp, ","); + pszTmp = msStringConcatenate(pszTmp, pasSLDLayers[i].name); + } + } + *ppszLayerNames = pszTmp; + } + } + + nStatus = MS_SUCCESS; + +sld_cleanup: + + if (pasSLDLayers) { + for (int i = 0; i < nSLDLayers; i++) + freeLayer(&pasSLDLayers[i]); + msFree(pasSLDLayers); + } + + if (map->debug == MS_DEBUGLEVEL_VVV) { + char *tmpfilename = msTmpFile(map, map->mappath, NULL, "_sld.map"); + if (tmpfilename == NULL) { + tmpfilename = msTmpFile(map, NULL, NULL, "_sld.map"); + } + if (tmpfilename) { + msSaveMap(map, tmpfilename); + msDebug("msApplySLD(): Map file after SLD was applied %s\n", tmpfilename); + msFree(tmpfilename); + } + } + return nStatus; + +#else + msSetError(MS_MISCERR, "OWS support is not available.", "msSLDApplySLD()"); + return (MS_FAILURE); +#endif +} + +static CPLXMLNode *FindNextChild(CPLXMLNode *psNode, const char *pszChildName) { + while (psNode) { + if (psNode->eType == CXT_Element && + strcasecmp(psNode->pszValue, pszChildName) == 0) { + return psNode; + } + psNode = psNode->psNext; + } + return NULL; +} + +#define LOOP_ON_CHILD_ELEMENT(psParent_, psChild_, pszChildName_) \ + for (psChild_ = FindNextChild(psParent_->psChild, pszChildName_); \ + psChild_ != NULL; \ + psChild_ = FindNextChild(psChild_->psNext, pszChildName_)) + +/************************************************************************/ +/* msSLDParseSLD */ +/* */ +/* Parse the sld document into layers : for each named layer */ +/* there is one mapserver layer created with appropriate */ +/* classes and styles. */ +/* Returns an array of mapserver layers. The pnLayres if */ +/* provided will indicate the size of the returned array. */ +/************************************************************************/ +layerObj *msSLDParseSLD(mapObj *map, const char *psSLDXML, int *pnLayers) { + CPLXMLNode *psRoot = NULL; + CPLXMLNode *psSLD, *psNamedLayer; + layerObj *pasLayers = NULL; + int iLayer = 0; + int nLayers = 0; + + if (map == NULL || psSLDXML == NULL || strlen(psSLDXML) == 0 || + (strstr(psSLDXML, "StyledLayerDescriptor") == NULL)) { + msSetError(MS_WMSERR, "Invalid SLD document", ""); + return NULL; + } + + psRoot = CPLParseXMLString(psSLDXML); + if (psRoot == NULL) { + msSetError(MS_WMSERR, "Invalid SLD document : %s", "", psSLDXML); + return NULL; + } + + /* strip namespaces ogc and sld and gml */ + CPLStripXMLNamespace(psRoot, "ogc", 1); + CPLStripXMLNamespace(psRoot, "sld", 1); + CPLStripXMLNamespace(psRoot, "gml", 1); + CPLStripXMLNamespace(psRoot, "se", 1); + + /* -------------------------------------------------------------------- */ + /* get the root element (StyledLayerDescriptor). */ + /* -------------------------------------------------------------------- */ + psSLD = CPLGetXMLNode(psRoot, "=StyledLayerDescriptor"); + if (!psSLD) { + msSetError(MS_WMSERR, "Invalid SLD document : %s", "", psSLDXML); + return NULL; + } + + /* -------------------------------------------------------------------- */ + /* Parse the named layers. */ + /* -------------------------------------------------------------------- */ + LOOP_ON_CHILD_ELEMENT(psSLD, psNamedLayer, "NamedLayer") { nLayers++; } + + if (nLayers > 0) + pasLayers = (layerObj *)malloc(sizeof(layerObj) * nLayers); + else + return NULL; + + LOOP_ON_CHILD_ELEMENT(psSLD, psNamedLayer, "NamedLayer") { + CPLXMLNode *psName = CPLGetXMLNode(psNamedLayer, "Name"); + initLayer(&pasLayers[iLayer], map); + + if (psName && psName->psChild && psName->psChild->pszValue) + pasLayers[iLayer].name = msStrdup(psName->psChild->pszValue); + + if (msSLDParseNamedLayer(psNamedLayer, &pasLayers[iLayer]) != MS_SUCCESS) { + int i; + for (i = 0; i <= iLayer; i++) + freeLayer(&pasLayers[i]); + msFree(pasLayers); + nLayers = 0; + pasLayers = NULL; + break; + } + + iLayer++; + } + + if (pnLayers) + *pnLayers = nLayers; + + if (psRoot) + CPLDestroyXMLNode(psRoot); + + return pasLayers; +} + +/************************************************************************/ +/* _SLDApplyRuleValues */ +/* */ +/* Utility function to set the scale, title/name for the */ +/* classes created by a Rule. */ +/************************************************************************/ +void _SLDApplyRuleValues(CPLXMLNode *psRule, layerObj *psLayer, + int nNewClasses) { + CPLXMLNode *psMinScale = NULL, *psMaxScale = NULL; + CPLXMLNode *psName = NULL, *psTitle = NULL; + double dfMinScale = 0, dfMaxScale = 0; + char *pszName = NULL, *pszTitle = NULL; + + if (psRule && psLayer && nNewClasses > 0) { + /* -------------------------------------------------------------------- */ + /* parse minscale and maxscale. */ + /* -------------------------------------------------------------------- */ + psMinScale = CPLGetXMLNode(psRule, "MinScaleDenominator"); + if (psMinScale && psMinScale->psChild && psMinScale->psChild->pszValue) + dfMinScale = atof(psMinScale->psChild->pszValue); + + psMaxScale = CPLGetXMLNode(psRule, "MaxScaleDenominator"); + if (psMaxScale && psMaxScale->psChild && psMaxScale->psChild->pszValue) + dfMaxScale = atof(psMaxScale->psChild->pszValue); + + /* -------------------------------------------------------------------- */ + /* parse name and title. */ + /* -------------------------------------------------------------------- */ + psName = CPLGetXMLNode(psRule, "Name"); + if (psName && psName->psChild && psName->psChild->pszValue) + pszName = psName->psChild->pszValue; + + psTitle = CPLGetXMLNode(psRule, "Title"); + if (psTitle && psTitle->psChild && psTitle->psChild->pszValue) + pszTitle = psTitle->psChild->pszValue; + + /* -------------------------------------------------------------------- */ + /* set the scale to all the classes created by the rule. */ + /* -------------------------------------------------------------------- */ + if (dfMinScale > 0 || dfMaxScale > 0) { + for (int i = 0; i < nNewClasses; i++) { + if (dfMinScale > 0) + psLayer->_class[psLayer->numclasses - 1 - i]->minscaledenom = + dfMinScale; + if (dfMaxScale) + psLayer->_class[psLayer->numclasses - 1 - i]->maxscaledenom = + dfMaxScale; + } + } + /* -------------------------------------------------------------------- */ + /* set name and title to the classes created by the rule. */ + /* -------------------------------------------------------------------- */ + for (int i = 0; i < nNewClasses; i++) { + if (!psLayer->_class[psLayer->numclasses - 1 - i]->name) { + if (pszName) + psLayer->_class[psLayer->numclasses - 1 - i]->name = + msStrdup(pszName); + else if (pszTitle) + psLayer->_class[psLayer->numclasses - 1 - i]->name = + msStrdup(pszTitle); + else { + // Build a name from layer and class info + char szTmp[256]; + snprintf(szTmp, sizeof(szTmp), "%s#%d", psLayer->name, + psLayer->numclasses - 1 - i); + psLayer->_class[psLayer->numclasses - 1 - i]->name = msStrdup(szTmp); + } + } + } + if (pszTitle) { + for (int i = 0; i < nNewClasses; i++) { + psLayer->_class[psLayer->numclasses - 1 - i]->title = + msStrdup(pszTitle); + } + } + } +} + +/************************************************************************/ +/* msSLDGetCommonExpressionFromFilter */ +/* */ +/* Get a common expression valid from the filter valid for the */ +/* temporary layer. */ +/************************************************************************/ +static char *msSLDGetCommonExpressionFromFilter(CPLXMLNode *psFilter, + layerObj *psLayer) { + char *pszExpression = NULL; + CPLXMLNode *psTmpNextNode = NULL; + CPLXMLNode *psTmpNode = NULL; + FilterEncodingNode *psNode = NULL; + char *pszTmpFilter = NULL; + layerObj *psCurrentLayer = NULL; + const char *pszWmsName = NULL; + const char *key = NULL; + + /* clone the tree and set the next node to null */ + /* so we only have the Filter node */ + psTmpNode = CPLCloneXMLTree(psFilter); + psTmpNextNode = psTmpNode->psNext; + psTmpNode->psNext = NULL; + pszTmpFilter = CPLSerializeXMLTree(psTmpNode); + psTmpNode->psNext = psTmpNextNode; + CPLDestroyXMLNode(psTmpNode); + + if (pszTmpFilter) { + psNode = FLTParseFilterEncoding(pszTmpFilter); + + CPLFree(pszTmpFilter); + } + + if (psNode) { + int j; + + /*preparse the filter for possible gml aliases set on the layer's metadata: + "gml_NA3DESC_alias" "alias_name" and filter could be + alias_name #3079*/ + for (j = 0; j < psLayer->map->numlayers; j++) { + psCurrentLayer = GET_LAYER(psLayer->map, j); + + pszWmsName = + msOWSLookupMetadata(&(psCurrentLayer->metadata), "MO", "name"); + + if ((psCurrentLayer->name && psLayer->name && + strcasecmp(psCurrentLayer->name, psLayer->name) == 0) || + (psCurrentLayer->group && psLayer->name && + strcasecmp(psCurrentLayer->group, psLayer->name) == 0) || + (psLayer->name && pszWmsName && + strcasecmp(pszWmsName, psLayer->name) == 0)) + break; + } + if (j < psLayer->map->numlayers) { + /*make sure that the tmp layer has all the metadata that + the original layer has, allowing to do parsing for + such things as gml_attribute_type #3052*/ + while (1) { + key = msNextKeyFromHashTable(&psCurrentLayer->metadata, key); + if (!key) + break; + else + msInsertHashTable(&psLayer->metadata, key, + msLookupHashTable(&psCurrentLayer->metadata, key)); + } + FLTPreParseFilterForAliasAndGroup(psNode, psLayer->map, j, "G"); + } + + pszExpression = FLTGetCommonExpression(psNode, psLayer); + FLTFreeFilterEncodingNode(psNode); + } + + return pszExpression; +} + +/************************************************************************/ +/* msSLDParseUserStyle */ +/* */ +/* Parse UserStyle node. */ +/************************************************************************/ + +static void msSLDParseUserStyle(CPLXMLNode *psUserStyle, layerObj *psLayer) { + CPLXMLNode *psFeatureTypeStyle; + const char *pszUserStyleName = CPLGetXMLValue(psUserStyle, "Name", NULL); + if (pszUserStyleName) { + const char *pszIsDefault = CPLGetXMLValue(psUserStyle, "IsDefault", "0"); + if (EQUAL(pszIsDefault, "true") || EQUAL(pszIsDefault, "1")) { + msFree(psLayer->classgroup); + psLayer->classgroup = msStrdup(pszUserStyleName); + } + } + + LOOP_ON_CHILD_ELEMENT(psUserStyle, psFeatureTypeStyle, "FeatureTypeStyle") { + CPLXMLNode *psRule; + + /* -------------------------------------------------------------------- */ + /* Parse rules with no Else filter. */ + /* -------------------------------------------------------------------- */ + LOOP_ON_CHILD_ELEMENT(psFeatureTypeStyle, psRule, "Rule") { + CPLXMLNode *psFilter = NULL; + CPLXMLNode *psElseFilter = NULL; + int nNewClasses = 0, nClassBeforeFilter = 0, nClassAfterFilter = 0; + int nClassAfterRule = 0, nClassBeforeRule = 0; + + /* used for scale setting */ + nClassBeforeRule = psLayer->numclasses; + + psElseFilter = CPLGetXMLNode(psRule, "ElseFilter"); + nClassBeforeFilter = psLayer->numclasses; + if (psElseFilter == NULL) + msSLDParseRule(psRule, psLayer, pszUserStyleName); + nClassAfterFilter = psLayer->numclasses; + + /* -------------------------------------------------------------------- */ + /* Parse the filter and apply it to the latest class created by */ + /* the rule. */ + /* NOTE : Spatial Filter is not supported. */ + /* -------------------------------------------------------------------- */ + psFilter = CPLGetXMLNode(psRule, "Filter"); + if (psFilter && psFilter->psChild && psFilter->psChild->pszValue) { + char *pszExpression = + msSLDGetCommonExpressionFromFilter(psFilter, psLayer); + if (pszExpression) { + int i; + nNewClasses = nClassAfterFilter - nClassBeforeFilter; + for (i = 0; i < nNewClasses; i++) { + expressionObj *exp = + &(psLayer->_class[psLayer->numclasses - 1 - i]->expression); + msFreeExpression(exp); + msInitExpression(exp); + exp->string = msStrdup(pszExpression); + exp->type = MS_EXPRESSION; + } + msFree(pszExpression); + pszExpression = NULL; + } + } + nClassAfterRule = psLayer->numclasses; + nNewClasses = nClassAfterRule - nClassBeforeRule; + + /* apply scale and title to newly created classes */ + _SLDApplyRuleValues(psRule, psLayer, nNewClasses); + + /* TODO : parse legendgraphic */ + } + /* -------------------------------------------------------------------- */ + /* First parse rules with the else filter. These rules will */ + /* create the classes that are placed at the end of class */ + /* list. (See how classes are applied to layers in function */ + /* msSLDApplySLD). */ + /* -------------------------------------------------------------------- */ + LOOP_ON_CHILD_ELEMENT(psFeatureTypeStyle, psRule, "Rule") { + CPLXMLNode *psElseFilter = CPLGetXMLNode(psRule, "ElseFilter"); + if (psElseFilter) { + const int nNumClassesBeforeRule = psLayer->numclasses; + msSLDParseRule(psRule, psLayer, pszUserStyleName); + const int nNumClassesAfterRule = psLayer->numclasses; + const int nNumClassesAdded = + nNumClassesAfterRule - nNumClassesBeforeRule; + if (nNumClassesAdded > 0) { + _SLDApplyRuleValues(psRule, psLayer, nNumClassesAdded); + for (int i = 0; i < nNumClassesAdded; ++i) { + psLayer->_class[psLayer->numclasses - 1 - i]->isfallback = TRUE; + } + } + } + } + } +} + +/************************************************************************/ +/* msSLDParseNamedLayer */ +/* */ +/* Parse NamedLayer root. */ +/************************************************************************/ +int msSLDParseNamedLayer(CPLXMLNode *psRoot, layerObj *psLayer) { + CPLXMLNode *psLayerFeatureConstraints = NULL; + + if (!psRoot || !psLayer) + return MS_FAILURE; + + if (CPLGetXMLNode(psRoot, "UserStyle")) { + CPLXMLNode *psUserStyle; + LOOP_ON_CHILD_ELEMENT(psRoot, psUserStyle, "UserStyle") { + msSLDParseUserStyle(psUserStyle, psLayer); + } + } + /* check for Named styles*/ + else { + CPLXMLNode *psNamedStyle = CPLGetXMLNode(psRoot, "NamedStyle"); + if (psNamedStyle) { + CPLXMLNode *psSLDName = CPLGetXMLNode(psNamedStyle, "Name"); + if (psSLDName && psSLDName->psChild && psSLDName->psChild->pszValue) { + msFree(psLayer->classgroup); + psLayer->classgroup = msStrdup(psSLDName->psChild->pszValue); + } + } + } + + /* Deal with LayerFeatureConstraints */ + psLayerFeatureConstraints = CPLGetXMLNode(psRoot, "LayerFeatureConstraints"); + if (psLayerFeatureConstraints != NULL) { + CPLXMLNode *psIter = psLayerFeatureConstraints->psChild; + CPLXMLNode *psFeatureTypeConstraint = NULL; + for (; psIter != NULL; psIter = psIter->psNext) { + if (psIter->eType == CXT_Element && + strcmp(psIter->pszValue, "FeatureTypeConstraint") == 0) { + if (psFeatureTypeConstraint == NULL) { + psFeatureTypeConstraint = psIter; + } else { + msSetError(MS_WMSERR, + "Only one single FeatureTypeConstraint element " + "per LayerFeatureConstraints is supported", + ""); + return MS_FAILURE; + } + } + } + if (psFeatureTypeConstraint != NULL) { + CPLXMLNode *psFilter; + if (CPLGetXMLNode(psFeatureTypeConstraint, "FeatureTypeName") != NULL) { + msSetError(MS_WMSERR, + "FeatureTypeName element is not " + "supported in FeatureTypeConstraint", + ""); + return MS_FAILURE; + } + if (CPLGetXMLNode(psFeatureTypeConstraint, "Extent") != NULL) { + msSetError(MS_WMSERR, + "Extent element is not " + "supported in FeatureTypeConstraint", + ""); + return MS_FAILURE; + } + psFilter = CPLGetXMLNode(psFeatureTypeConstraint, "Filter"); + if (psFilter && psFilter->psChild && psFilter->psChild->pszValue) { + char *pszExpression = + msSLDGetCommonExpressionFromFilter(psFilter, psLayer); + if (pszExpression) { + msFreeExpression(&psLayer->filter); + msInitExpression(&psLayer->filter); + psLayer->filter.string = pszExpression; + psLayer->filter.type = MS_EXPRESSION; + } + } + } + } + + return MS_SUCCESS; +} + +/************************************************************************/ +/* msSLDParseRule() */ +/* */ +/* Parse a Rule node into classes for a specific layer. */ +/************************************************************************/ +int msSLDParseRule(CPLXMLNode *psRoot, layerObj *psLayer, + const char *pszUserStyleName) { + CPLXMLNode *psLineSymbolizer = NULL; + CPLXMLNode *psPolygonSymbolizer = NULL; + CPLXMLNode *psPointSymbolizer = NULL; + CPLXMLNode *psTextSymbolizer = NULL; + CPLXMLNode *psRasterSymbolizer = NULL; + + int nSymbolizer = 0; + + if (!psRoot || !psLayer) + return MS_FAILURE; + + /* TODO : parse name of the rule */ + /* ==================================================================== */ + /* For each rule a new class is created. If there are more than */ + /* one symbolizer, a style is added in the same class. */ + /* ==================================================================== */ + + /* Raster symbolizer */ + LOOP_ON_CHILD_ELEMENT(psRoot, psRasterSymbolizer, "RasterSymbolizer") { + msSLDParseRasterSymbolizer(psRasterSymbolizer, psLayer, pszUserStyleName); + /* cppcheck-suppress knownConditionTrueFalse */ + if (nSymbolizer == 0) { + psLayer->type = MS_LAYER_RASTER; + } + } + + /* Polygon symbolizer */ + LOOP_ON_CHILD_ELEMENT(psRoot, psPolygonSymbolizer, "PolygonSymbolizer") { + /* cppcheck-suppress knownConditionTrueFalse */ + const int bNewClass = (nSymbolizer == 0); + msSLDParsePolygonSymbolizer(psPolygonSymbolizer, psLayer, bNewClass, + pszUserStyleName); + psLayer->type = MS_LAYER_POLYGON; + nSymbolizer++; + } + + /* line symbolizer */ + LOOP_ON_CHILD_ELEMENT(psRoot, psLineSymbolizer, "LineSymbolizer") { + const int bNewClass = (nSymbolizer == 0); + msSLDParseLineSymbolizer(psLineSymbolizer, psLayer, bNewClass, + pszUserStyleName); + if (bNewClass) { + psLayer->type = MS_LAYER_LINE; + } + if (psLayer->type == MS_LAYER_POLYGON) { + const int nClassId = psLayer->numclasses - 1; + if (nClassId >= 0) { + const int nStyleId = psLayer->_class[nClassId]->numstyles - 1; + if (nStyleId >= 0) { + styleObj *psStyle = psLayer->_class[nClassId]->styles[nStyleId]; + psStyle->outlinecolor = psStyle->color; + MS_INIT_COLOR(psStyle->color, -1, -1, -1, 255); + MS_COPYSTRING( + psStyle->exprBindings[MS_STYLE_BINDING_OUTLINECOLOR].string, + psStyle->exprBindings[MS_STYLE_BINDING_COLOR].string); + psStyle->exprBindings[MS_STYLE_BINDING_OUTLINECOLOR].type = + psStyle->exprBindings[MS_STYLE_BINDING_COLOR].type; + msFreeExpression(&(psStyle->exprBindings[MS_STYLE_BINDING_COLOR])); + msInitExpression(&(psStyle->exprBindings[MS_STYLE_BINDING_COLOR])); + } + } + } + nSymbolizer++; + } + + /* Point Symbolizer */ + LOOP_ON_CHILD_ELEMENT(psRoot, psPointSymbolizer, "PointSymbolizer") { + const int bNewClass = (nSymbolizer == 0); + msSLDParsePointSymbolizer(psPointSymbolizer, psLayer, bNewClass, + pszUserStyleName); + if (bNewClass) { + psLayer->type = MS_LAYER_POINT; + } + if (psLayer->type == MS_LAYER_POLYGON || psLayer->type == MS_LAYER_LINE || + psLayer->type == MS_LAYER_RASTER) { + const int nClassId = psLayer->numclasses - 1; + if (nClassId >= 0) { + const int nStyleId = psLayer->_class[nClassId]->numstyles - 1; + if (nStyleId >= 0) { + styleObj *psStyle = psLayer->_class[nClassId]->styles[nStyleId]; + msStyleSetGeomTransform(psStyle, "centroid"); + } + } + } + nSymbolizer++; + } + + /* Text symbolizer */ + /* ==================================================================== */ + /* For text symbolizer, here is how it is translated into */ + /* mapserver classes : */ + /* - If there are other symbolizers(line, polygon, symbol), */ + /* the label object created will be created in the same class */ + /* (the last class) as the symbolizer. This allows to have for */ + /* example of point layer with labels. */ + /* - If there are no other symbolizers, a new class will be */ + /* created to contain the label object. */ + /* ==================================================================== */ + if (psLayer->type == MS_LAYER_LINE || psLayer->type == MS_LAYER_POLYGON) + nSymbolizer++; + LOOP_ON_CHILD_ELEMENT(psRoot, psTextSymbolizer, "TextSymbolizer") { + if (nSymbolizer == 0) + psLayer->type = MS_LAYER_POINT; + msSLDParseTextSymbolizer(psTextSymbolizer, psLayer, nSymbolizer > 0, + pszUserStyleName); + } + + return MS_SUCCESS; +} + +/************************************************************************/ +/* getClassId() */ +/************************************************************************/ + +static int getClassId(layerObj *psLayer, int bNewClass, + const char *pszUserStyleName) { + int nClassId; + if (bNewClass || psLayer->numclasses <= 0) { + if (msGrowLayerClasses(psLayer) == NULL) + return -1; + initClass(psLayer->_class[psLayer->numclasses]); + nClassId = psLayer->numclasses; + if (pszUserStyleName) + psLayer->_class[nClassId]->group = msStrdup(pszUserStyleName); + psLayer->numclasses++; + } else { + nClassId = psLayer->numclasses - 1; + } + return nClassId; +} + +/************************************************************************/ +/* msSLDParseUomAttribute() */ +/************************************************************************/ + +int msSLDParseUomAttribute(CPLXMLNode *node, enum MS_UNITS *sizeunits) { + const struct { + enum MS_UNITS unit; + const char *const values[10]; + } known_uoms[] = { + {MS_INCHES, {"inch", "inches", NULL}}, + {MS_FEET, + {"foot", "feet", "http://www.opengeospatial.org/se/units/foot", NULL}}, + {MS_MILES, {"mile", "miles", NULL}}, + {MS_METERS, + {"meter", "meters", "metre", "metres", + "http://www.opengeospatial.org/se/units/metre", NULL}}, + {MS_KILOMETERS, + {"kilometer", "kilometers", "kilometre", "kilometres", NULL}}, + {MS_DD, {"dd", NULL}}, + {MS_PIXELS, + {"pixel", "pixels", "px", "http://www.opengeospatial.org/se/units/pixel", + NULL}}, + {MS_PERCENTAGES, + {"percent", "percents", "percentage", "percentages", NULL}}, + {MS_NAUTICALMILES, + {"nauticalmile", "nauticalmiles", "nautical_mile", "nautical_miles", + NULL}}, + {MS_INCHES, {NULL}}}; + + const char *uom = CPLGetXMLValue(node, "uom", NULL); + if (uom) { + for (int i = 0; known_uoms[i].values[0]; i++) + for (int j = 0; known_uoms[i].values[j]; j++) + if (strcmp(uom, known_uoms[i].values[j]) == 0) { + // Match found + *sizeunits = known_uoms[i].unit; + return MS_SUCCESS; + } + // No match was found + return MS_FAILURE; + } + // No uom was found + *sizeunits = MS_PIXELS; + return MS_SUCCESS; +} + +/************************************************************************/ +/* msSLDParseLineSymbolizer() */ +/* */ +/* Parses the LineSymbolizer rule and creates a class in the */ +/* layer. */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* Example of a rule : */ +/* ... */ +/* */ +/* */ +/* */ +/* center-line */ +/* */ +/* */ +/* #0000ff */ +/* 5.0 */ +/* 10.0 5 5 10*/ +/* */ +/* */ +/* */ +/* ... */ +/************************************************************************/ +int msSLDParseLineSymbolizer(CPLXMLNode *psRoot, layerObj *psLayer, + int bNewClass, const char *pszUserStyleName) { + CPLXMLNode *psStroke = NULL, *psOffset = NULL; + + if (!psRoot || !psLayer) + return MS_FAILURE; + + // Get uom if any, defaults to MS_PIXELS + enum MS_UNITS sizeunits = MS_PIXELS; + if (msSLDParseUomAttribute(psRoot, &sizeunits) != MS_SUCCESS) { + msSetError(MS_WMSERR, "Invalid uom attribute value.", + "msSLDParsePolygonSymbolizer()"); + return MS_FAILURE; + } + + psStroke = CPLGetXMLNode(psRoot, "Stroke"); + if (psStroke) { + int nClassId = getClassId(psLayer, bNewClass, pszUserStyleName); + if (nClassId < 0) + return MS_FAILURE; + + const int iStyle = psLayer->_class[nClassId]->numstyles; + msMaybeAllocateClassStyle(psLayer->_class[nClassId], iStyle); + psLayer->_class[nClassId]->styles[iStyle]->sizeunits = sizeunits; + + msSLDParseStroke(psStroke, psLayer->_class[nClassId]->styles[iStyle], + psLayer->map, 0); + + /*parse PerpendicularOffset SLD 1.1.10*/ + psOffset = CPLGetXMLNode(psRoot, "PerpendicularOffset"); + if (psOffset && psOffset->psChild && psOffset->psChild->pszValue) { + psLayer->_class[nClassId]->styles[iStyle]->offsetx = + atoi(psOffset->psChild->pszValue); + psLayer->_class[nClassId]->styles[iStyle]->offsety = + MS_STYLE_SINGLE_SIDED_OFFSET; + } + } + + return MS_SUCCESS; +} + +/************************************************************************/ +/* void msSLDParseStroke(CPLXMLNode *psStroke, styleObj */ +/* *psStyle, int iColorParam) */ +/* */ +/* Parse Stroke content into a style object. */ +/* The iColorParm is used to indicate which color object to use */ +/* : */ +/* 0 : for color */ +/* 1 : outlinecolor */ +/************************************************************************/ +int msSLDParseStroke(CPLXMLNode *psStroke, styleObj *psStyle, mapObj *map, + int iColorParam) { + CPLXMLNode *psCssParam = NULL, *psGraphicFill = NULL; + char *psStrkName = NULL; + char *pszDashValue = NULL; + + if (!psStroke || !psStyle) + return MS_FAILURE; + + /* parse css parameters */ + psCssParam = CPLGetXMLNode(psStroke, "CssParameter"); + /*sld 1.1 used SvgParameter*/ + if (psCssParam == NULL) + psCssParam = CPLGetXMLNode(psStroke, "SvgParameter"); + + while (psCssParam && psCssParam->pszValue && + (strcasecmp(psCssParam->pszValue, "CssParameter") == 0 || + strcasecmp(psCssParam->pszValue, "SvgParameter") == 0)) { + psStrkName = (char *)CPLGetXMLValue(psCssParam, "name", NULL); + + if (psStrkName) { + if (strcasecmp(psStrkName, "stroke") == 0) { + if (psCssParam->psChild && psCssParam->psChild->psNext) { + switch (iColorParam) { + case 0: + msSLDParseOgcExpression(psCssParam->psChild->psNext, psStyle, + MS_STYLE_BINDING_COLOR, MS_OBJ_STYLE); + break; + case 1: + msSLDParseOgcExpression(psCssParam->psChild->psNext, psStyle, + MS_STYLE_BINDING_OUTLINECOLOR, + MS_OBJ_STYLE); + break; + } + } + } else if (strcasecmp(psStrkName, "stroke-width") == 0) { + if (psCssParam->psChild && psCssParam->psChild->psNext) { + msSLDParseOgcExpression(psCssParam->psChild->psNext, psStyle, + MS_STYLE_BINDING_WIDTH, MS_OBJ_STYLE); + } + } else if (strcasecmp(psStrkName, "stroke-dasharray") == 0) { + if (psCssParam->psChild && psCssParam->psChild->psNext && + psCssParam->psChild->psNext->pszValue) { + int nDash = 0, i; + char **aszValues = NULL; + int nMaxDash; + if (pszDashValue) + free(pszDashValue); /* free previous if multiple stroke-dasharray + attributes were found */ + pszDashValue = msStrdup(psCssParam->psChild->psNext->pszValue); + aszValues = msStringSplit(pszDashValue, ' ', &nDash); + if (nDash > 0) { + nMaxDash = nDash; + if (nDash > MS_MAXPATTERNLENGTH) + nMaxDash = MS_MAXPATTERNLENGTH; + + psStyle->patternlength = nMaxDash; + for (i = 0; i < nMaxDash; i++) + psStyle->pattern[i] = atof(aszValues[i]); + + psStyle->linecap = MS_CJC_BUTT; + } + msFreeCharArray(aszValues, nDash); + } + } else if (strcasecmp(psStrkName, "stroke-opacity") == 0) { + if (psCssParam->psChild && psCssParam->psChild->psNext) { + msSLDParseOgcExpression(psCssParam->psChild->psNext, psStyle, + MS_STYLE_BINDING_OPACITY, MS_OBJ_STYLE); + } + } + } + psCssParam = psCssParam->psNext; + } + + /* parse graphic fill or stroke */ + /* graphic fill and graphic stroke pare parsed the same way : */ + /* TODO : It seems inconsistent to me since the only difference */ + /* between them seems to be fill (fill) or not fill (stroke). And */ + /* then again the fill parameter can be used inside both elements. */ + psGraphicFill = CPLGetXMLNode(psStroke, "GraphicFill"); + if (psGraphicFill) + msSLDParseGraphicFillOrStroke(psGraphicFill, pszDashValue, psStyle, map); + psGraphicFill = CPLGetXMLNode(psStroke, "GraphicStroke"); + if (psGraphicFill) + msSLDParseGraphicFillOrStroke(psGraphicFill, pszDashValue, psStyle, map); + + if (pszDashValue) + free(pszDashValue); + + return MS_SUCCESS; +} + +/************************************************************************/ +/* int msSLDParseOgcExpression(CPLXMLNode *psRoot, styleObj *psStyle, */ +/* enum MS_STYLE_BINDING_ENUM binding) */ +/* */ +/* Parse an OGC expression in a */ +/************************************************************************/ +int msSLDParseOgcExpression(CPLXMLNode *psRoot, void *psObj, int binding, + enum objType objtype) { + int status = MS_FAILURE; + const char *ops = "Add+Sub-Mul*Div/"; + styleObj *psStyle = static_cast(psObj); + labelObj *psLabel = static_cast(psObj); + int lbinding; + expressionObj *exprBindings; + int *nexprbindings; + enum { MS_STYLE_BASE = 0, MS_LABEL_BASE = 100 }; + + switch (objtype) { + case MS_OBJ_STYLE: + lbinding = binding + MS_STYLE_BASE; + exprBindings = psStyle->exprBindings; + nexprbindings = &psStyle->nexprbindings; + break; + case MS_OBJ_LABEL: + lbinding = binding + MS_LABEL_BASE; + exprBindings = psLabel->exprBindings; + nexprbindings = &psLabel->nexprbindings; + break; + default: + return MS_FAILURE; + break; + } + + switch (psRoot->eType) { + case CXT_Text: + // Parse a raw value + { + msStringBuffer *literal = msStringBufferAlloc(); + msStringBufferAppend(literal, "("); + msStringBufferAppend(literal, psRoot->pszValue); + msStringBufferAppend(literal, ")"); + msFreeExpression(&(exprBindings[binding])); + msInitExpression(&(exprBindings[binding])); + exprBindings[binding].string = + msStringBufferReleaseStringAndFree(literal); + exprBindings[binding].type = MS_STRING; + } + switch (lbinding) { + case MS_STYLE_BASE + MS_STYLE_BINDING_OFFSET_X: + psStyle->offsetx = atoi(psRoot->pszValue); + status = MS_SUCCESS; + break; + case MS_STYLE_BASE + MS_STYLE_BINDING_OFFSET_Y: + psStyle->offsety = atoi(psRoot->pszValue); + status = MS_SUCCESS; + break; + case MS_STYLE_BASE + MS_STYLE_BINDING_ANGLE: + psStyle->angle = atof(psRoot->pszValue); + status = MS_SUCCESS; + break; + case MS_STYLE_BASE + MS_STYLE_BINDING_SIZE: + psStyle->size = atof(psRoot->pszValue); + status = MS_SUCCESS; + break; + case MS_STYLE_BASE + MS_STYLE_BINDING_WIDTH: + psStyle->width = atof(psRoot->pszValue); + status = MS_SUCCESS; + break; + case MS_STYLE_BASE + MS_STYLE_BINDING_OPACITY: + psStyle->opacity = atof(psRoot->pszValue) * 100; + status = MS_SUCCESS; + // Apply opacity as the alpha channel color(s) + if (psStyle->opacity < 100) { + int alpha = MS_NINT(psStyle->opacity * 2.55); + psStyle->color.alpha = alpha; + psStyle->outlinecolor.alpha = alpha; + psStyle->mincolor.alpha = alpha; + psStyle->maxcolor.alpha = alpha; + } + break; + case MS_STYLE_BASE + MS_STYLE_BINDING_COLOR: + if (strlen(psRoot->pszValue) == 7 && psRoot->pszValue[0] == '#') { + psStyle->color.red = msHexToInt(psRoot->pszValue + 1); + psStyle->color.green = msHexToInt(psRoot->pszValue + 3); + psStyle->color.blue = msHexToInt(psRoot->pszValue + 5); + status = MS_SUCCESS; + } + break; + case MS_STYLE_BASE + MS_STYLE_BINDING_OUTLINECOLOR: + if (strlen(psRoot->pszValue) == 7 && psRoot->pszValue[0] == '#') { + psStyle->outlinecolor.red = msHexToInt(psRoot->pszValue + 1); + psStyle->outlinecolor.green = msHexToInt(psRoot->pszValue + 3); + psStyle->outlinecolor.blue = msHexToInt(psRoot->pszValue + 5); + status = MS_SUCCESS; + } + break; + + case MS_LABEL_BASE + MS_LABEL_BINDING_SIZE: + psLabel->size = atof(psRoot->pszValue); + if (psLabel->size <= 0.0) { + psLabel->size = 10.0; + } + status = MS_SUCCESS; + break; + case MS_LABEL_BASE + MS_LABEL_BINDING_ANGLE: + psLabel->angle = atof(psRoot->pszValue); + status = MS_SUCCESS; + break; + case MS_LABEL_BASE + MS_LABEL_BINDING_COLOR: + if (strlen(psRoot->pszValue) == 7 && psRoot->pszValue[0] == '#') { + psLabel->color.red = msHexToInt(psRoot->pszValue + 1); + psLabel->color.green = msHexToInt(psRoot->pszValue + 3); + psLabel->color.blue = msHexToInt(psRoot->pszValue + 5); + status = MS_SUCCESS; + } + break; + case MS_LABEL_BASE + MS_LABEL_BINDING_OUTLINECOLOR: + if (strlen(psRoot->pszValue) == 7 && psRoot->pszValue[0] == '#') { + psLabel->outlinecolor.red = msHexToInt(psRoot->pszValue + 1); + psLabel->outlinecolor.green = msHexToInt(psRoot->pszValue + 3); + psLabel->outlinecolor.blue = msHexToInt(psRoot->pszValue + 5); + status = MS_SUCCESS; + } + break; + default: + break; + } + break; + case CXT_Element: + if (strcasecmp(psRoot->pszValue, "Literal") == 0 && psRoot->psChild) { + // Parse a element + status = + msSLDParseOgcExpression(psRoot->psChild, psObj, binding, objtype); + } else if (strcasecmp(psRoot->pszValue, "PropertyName") == 0 && + psRoot->psChild) { + // Parse a element + msStringBuffer *property = msStringBufferAlloc(); + const char *strDelim = ""; + + switch (lbinding) { + case MS_STYLE_BASE + MS_STYLE_BINDING_COLOR: + case MS_STYLE_BASE + MS_STYLE_BINDING_OUTLINECOLOR: + case MS_LABEL_BASE + MS_LABEL_BINDING_COLOR: + case MS_LABEL_BASE + MS_LABEL_BINDING_OUTLINECOLOR: + strDelim = "\""; + /* FALLTHROUGH */ + default: + msStringBufferAppend(property, strDelim); + msStringBufferAppend(property, "["); + msStringBufferAppend(property, psRoot->psChild->pszValue); + msStringBufferAppend(property, "]"); + msStringBufferAppend(property, strDelim); + msInitExpression(&(exprBindings[binding])); + exprBindings[binding].string = + msStringBufferReleaseStringAndFree(property); + exprBindings[binding].type = MS_EXPRESSION; + (*nexprbindings)++; + break; + } + status = MS_SUCCESS; + } else if (strcasecmp(psRoot->pszValue, "Function") == 0 && + psRoot->psChild && CPLGetXMLValue(psRoot, "name", NULL) && + psRoot->psChild->psNext) { + // Parse a element + msStringBuffer *function = msStringBufferAlloc(); + + // Parse function name + const char *funcname = CPLGetXMLValue(psRoot, "name", NULL); + msStringBufferAppend(function, funcname); + msStringBufferAppend(function, "("); + msInitExpression(&(exprBindings[binding])); + + // Parse arguments + const char *sep = ""; + for (CPLXMLNode *argument = psRoot->psChild->psNext; argument; + argument = argument->psNext) { + status = msSLDParseOgcExpression(argument, psObj, binding, objtype); + if (status != MS_SUCCESS) + break; + msStringBufferAppend(function, sep); + msStringBufferAppend(function, exprBindings[binding].string); + msReplaceFreeableStr(&(exprBindings[binding].string), nullptr); + msInitExpression(&(exprBindings[binding])); + sep = ","; + } + msStringBufferAppend(function, ")"); + exprBindings[binding].string = + msStringBufferReleaseStringAndFree(function); + exprBindings[binding].type = MS_EXPRESSION; + (*nexprbindings)++; + status = MS_SUCCESS; + } else if (strstr(ops, psRoot->pszValue) && psRoot->psChild && + psRoot->psChild->psNext) { + // Parse an arithmetic element , , , + const char op[2] = {*(strstr(ops, psRoot->pszValue) + 3), '\0'}; + msStringBuffer *expression = msStringBufferAlloc(); + + // Parse first operand + msStringBufferAppend(expression, "("); + msInitExpression(&(exprBindings[binding])); + status = + msSLDParseOgcExpression(psRoot->psChild, psObj, binding, objtype); + + // Parse second operand + if (status == MS_SUCCESS) { + msStringBufferAppend(expression, exprBindings[binding].string); + msStringBufferAppend(expression, op); + msReplaceFreeableStr(&(exprBindings[binding].string), nullptr); + msInitExpression(&(exprBindings[binding])); + status = msSLDParseOgcExpression(psRoot->psChild->psNext, psObj, + binding, objtype); + if (status == MS_SUCCESS && exprBindings[binding].string) { + msStringBufferAppend(expression, exprBindings[binding].string); + msStringBufferAppend(expression, ")"); + msReplaceFreeableStr(&(exprBindings[binding].string), + msStringBufferReleaseStringAndFree(expression)); + expression = NULL; + exprBindings[binding].type = MS_EXPRESSION; + (*nexprbindings)++; + } + } + if (expression != NULL) { + msStringBufferFree(expression); + msInitExpression(&(exprBindings[binding])); + } + } + break; + default: + break; + } + + return status; +} + +/************************************************************************/ +/* msSLDParsePolygonSymbolizer() */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* Here, the CssParameter names are fill instead of stroke and */ +/* fill-opacity instead of stroke-opacity. None of the other + * CssParameters*/ +/* in Stroke are available for filling and the default value for the fill + * color in this context is 50% gray (value #808080).*/ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* The default if neither an ExternalGraphic nor a Mark is specified is to + * use the default*/ +/* mark of a square with a 50%-gray fill and a black outline, with a size + * of 6 pixels.*/ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* The WellKnownName element gives the well-known name of the shape of the + * mark.*/ +/* Allowed values include at least square, circle, triangle, star, cross,*/ +/* and x, though map servers may draw a different symbol instead if they + * don't have a*/ +/* shape for all of these. The default WellKnownName is square. Renderings + * of these*/ +/* marks may be made solid or hollow depending on Fill and Stroke + * elements.*/ +/* */ +/************************************************************************/ +int msSLDParsePolygonSymbolizer(CPLXMLNode *psRoot, layerObj *psLayer, + int bNewClass, const char *pszUserStyleName) { + CPLXMLNode *psFill, *psStroke; + CPLXMLNode *psDisplacement = NULL, *psDisplacementX = NULL, + *psDisplacementY = NULL; + int nOffsetX = -1, nOffsetY = -1; + + if (!psRoot || !psLayer) + return MS_FAILURE; + + // Get uom if any, defaults to MS_PIXELS + enum MS_UNITS sizeunits = MS_PIXELS; + if (msSLDParseUomAttribute(psRoot, &sizeunits) != MS_SUCCESS) { + msSetError(MS_WMSERR, "Invalid uom attribute value.", + "msSLDParsePolygonSymbolizer()"); + return MS_FAILURE; + } + + /*parse displacement for SLD 1.1.0*/ + psDisplacement = CPLGetXMLNode(psRoot, "Displacement"); + if (psDisplacement) { + psDisplacementX = CPLGetXMLNode(psDisplacement, "DisplacementX"); + psDisplacementY = CPLGetXMLNode(psDisplacement, "DisplacementY"); + /* psCssParam->psChild->psNext->pszValue) */ + if (psDisplacementX && psDisplacementX->psChild && + psDisplacementX->psChild->pszValue && psDisplacementY && + psDisplacementY->psChild && psDisplacementY->psChild->pszValue) { + nOffsetX = atoi(psDisplacementX->psChild->pszValue); + nOffsetY = atoi(psDisplacementY->psChild->pszValue); + } + } + + psFill = CPLGetXMLNode(psRoot, "Fill"); + if (psFill) { + const int nClassId = getClassId(psLayer, bNewClass, pszUserStyleName); + if (nClassId < 0) + return MS_FAILURE; + + const int iStyle = psLayer->_class[nClassId]->numstyles; + msMaybeAllocateClassStyle(psLayer->_class[nClassId], iStyle); + psLayer->_class[nClassId]->styles[iStyle]->sizeunits = sizeunits; + + msSLDParsePolygonFill(psFill, psLayer->_class[nClassId]->styles[iStyle], + psLayer->map); + + if (nOffsetX > 0 && nOffsetY > 0) { + psLayer->_class[nClassId]->styles[iStyle]->offsetx = nOffsetX; + psLayer->_class[nClassId]->styles[iStyle]->offsety = nOffsetY; + } + } + /* stroke which corresponds to the outline in mapserver */ + /* is drawn after the fill */ + psStroke = CPLGetXMLNode(psRoot, "Stroke"); + if (psStroke) { + /* -------------------------------------------------------------------- */ + /* there was a fill so add a style to the last class created */ + /* by the fill */ + /* -------------------------------------------------------------------- */ + int nClassId; + int iStyle; + if (psFill && psLayer->numclasses > 0) { + nClassId = psLayer->numclasses - 1; + iStyle = psLayer->_class[nClassId]->numstyles; + msMaybeAllocateClassStyle(psLayer->_class[nClassId], iStyle); + psLayer->_class[nClassId]->styles[iStyle]->sizeunits = sizeunits; + } else { + nClassId = getClassId(psLayer, bNewClass, pszUserStyleName); + if (nClassId < 0) + return MS_FAILURE; + + iStyle = psLayer->_class[nClassId]->numstyles; + msMaybeAllocateClassStyle(psLayer->_class[nClassId], iStyle); + psLayer->_class[nClassId]->styles[iStyle]->sizeunits = sizeunits; + } + msSLDParseStroke(psStroke, psLayer->_class[nClassId]->styles[iStyle], + psLayer->map, 1); + + if (nOffsetX > 0 && nOffsetY > 0) { + psLayer->_class[nClassId]->styles[iStyle]->offsetx = nOffsetX; + psLayer->_class[nClassId]->styles[iStyle]->offsety = nOffsetY; + } + } + + return MS_SUCCESS; +} + +/************************************************************************/ +/* void msSLDParsePolygonFill(CPLXMLNode *psFill, styleObj *psStyle, */ +/* mapObj *map) */ +/* */ +/* Parse the Fill node for a polygon into a style. */ +/************************************************************************/ +int msSLDParsePolygonFill(CPLXMLNode *psFill, styleObj *psStyle, mapObj *map) { + CPLXMLNode *psCssParam, *psGraphicFill; + char *psFillName = NULL; + + if (!psFill || !psStyle || !map) + return MS_FAILURE; + + /* sets the default fill color defined in the spec #808080 */ + psStyle->color.red = 128; + psStyle->color.green = 128; + psStyle->color.blue = 128; + + psCssParam = CPLGetXMLNode(psFill, "CssParameter"); + /*sld 1.1 used SvgParameter*/ + if (psCssParam == NULL) + psCssParam = CPLGetXMLNode(psFill, "SvgParameter"); + + while (psCssParam && psCssParam->pszValue && + (strcasecmp(psCssParam->pszValue, "CssParameter") == 0 || + strcasecmp(psCssParam->pszValue, "SvgParameter") == 0)) { + psFillName = (char *)CPLGetXMLValue(psCssParam, "name", NULL); + if (psFillName) { + if (strcasecmp(psFillName, "fill") == 0) { + if (psCssParam->psChild && psCssParam->psChild->psNext) { + msSLDParseOgcExpression(psCssParam->psChild->psNext, psStyle, + MS_STYLE_BINDING_COLOR, MS_OBJ_STYLE); + } + } else if (strcasecmp(psFillName, "fill-opacity") == 0) { + if (psCssParam->psChild && psCssParam->psChild->psNext) { + msSLDParseOgcExpression(psCssParam->psChild->psNext, psStyle, + MS_STYLE_BINDING_OPACITY, MS_OBJ_STYLE); + } + } + } + psCssParam = psCssParam->psNext; + } + + /* graphic fill and graphic stroke pare parsed the same way : */ + /* TODO : It seems inconsistent to me since the only difference */ + /* between them seems to be fill (fill) or not fill (stroke). And */ + /* then again the fill parameter can be used inside both elements. */ + psGraphicFill = CPLGetXMLNode(psFill, "GraphicFill"); + if (psGraphicFill) + msSLDParseGraphicFillOrStroke(psGraphicFill, NULL, psStyle, map); + psGraphicFill = CPLGetXMLNode(psFill, "GraphicStroke"); + if (psGraphicFill) + msSLDParseGraphicFillOrStroke(psGraphicFill, NULL, psStyle, map); + + return MS_SUCCESS; +} + +/************************************************************************/ +/* msSLDParseGraphicFillOrStroke */ +/* */ +/* Parse the GraphicFill Or GraphicStroke node : look for a */ +/* Marker symbol and set the style for that symbol. */ +/************************************************************************/ +int msSLDParseGraphicFillOrStroke(CPLXMLNode *psRoot, char *pszDashValue_unused, + styleObj *psStyle, mapObj *map) { + (void)pszDashValue_unused; + CPLXMLNode *psCssParam, *psGraphic, *psExternalGraphic, *psMark, *psSize, + *psGap, *psInitialGap; + CPLXMLNode *psWellKnownName, *psStroke, *psFill; + CPLXMLNode *psDisplacement = NULL, *psDisplacementX = NULL, + *psDisplacementY = NULL; + CPLXMLNode *psOpacity = NULL, *psRotation = NULL; + char *psName = NULL, *psValue = NULL; + char *pszSymbolName = NULL; + int bFilled = 0; + + if (!psRoot || !psStyle || !map) + return MS_FAILURE; + /* ==================================================================== */ + /* This a definition taken from the specification (11.3.2) : */ + /* Graphics can either be referenced from an external URL in a common + * format (such as*/ + /* GIF or SVG) or may be derived from a Mark. Multiple external URLs and + * marks may be*/ + /* referenced with the semantic that they all provide the equivalent + * graphic in different*/ + /* formats. */ + /* */ + /* For this reason, we only need to support one Mark and one */ + /* ExtrnalGraphic ???? */ + /* ==================================================================== */ + psGraphic = CPLGetXMLNode(psRoot, "Graphic"); + if (psGraphic) { + /* extract symbol size */ + psSize = CPLGetXMLNode(psGraphic, "Size"); + if (psSize && psSize->psChild) { + msSLDParseOgcExpression(psSize->psChild, psStyle, MS_STYLE_BINDING_SIZE, + MS_OBJ_STYLE); + } else { + /*do not set a default for external symbols #2305*/ + psExternalGraphic = CPLGetXMLNode(psGraphic, "ExternalGraphic"); + if (!psExternalGraphic) + psStyle->size = 6; /* default value */ + } + + /*SLD 1.1.0 extract opacity, rotation, displacement*/ + psOpacity = CPLGetXMLNode(psGraphic, "Opacity"); + if (psOpacity && psOpacity->psChild) { + msSLDParseOgcExpression(psOpacity->psChild, psStyle, + MS_STYLE_BINDING_OPACITY, MS_OBJ_STYLE); + } + + psRotation = CPLGetXMLNode(psGraphic, "Rotation"); + if (psRotation && psRotation->psChild) { + msSLDParseOgcExpression(psRotation->psChild, psStyle, + MS_STYLE_BINDING_ANGLE, MS_OBJ_STYLE); + } + psDisplacement = CPLGetXMLNode(psGraphic, "Displacement"); + if (psDisplacement && psDisplacement->psChild) { + psDisplacementX = CPLGetXMLNode(psDisplacement, "DisplacementX"); + if (psDisplacementX && psDisplacementX->psChild) { + msSLDParseOgcExpression(psDisplacementX->psChild, psStyle, + MS_STYLE_BINDING_OFFSET_X, MS_OBJ_STYLE); + } + psDisplacementY = CPLGetXMLNode(psDisplacement, "DisplacementY"); + if (psDisplacementY && psDisplacementY->psChild) { + msSLDParseOgcExpression(psDisplacementY->psChild, psStyle, + MS_STYLE_BINDING_OFFSET_Y, MS_OBJ_STYLE); + } + } + /* extract symbol */ + psMark = CPLGetXMLNode(psGraphic, "Mark"); + if (psMark) { + pszSymbolName = NULL; + psWellKnownName = CPLGetXMLNode(psMark, "WellKnownName"); + if (psWellKnownName && psWellKnownName->psChild && + psWellKnownName->psChild->pszValue) + pszSymbolName = msStrdup(psWellKnownName->psChild->pszValue); + + /* default symbol is square */ + + if (!pszSymbolName || !*pszSymbolName || + (strcasecmp(pszSymbolName, "square") != 0 && + strcasecmp(pszSymbolName, "circle") != 0 && + strcasecmp(pszSymbolName, "triangle") != 0 && + strcasecmp(pszSymbolName, "star") != 0 && + strcasecmp(pszSymbolName, "cross") != 0 && + strcasecmp(pszSymbolName, "x") != 0)) { + if (!pszSymbolName || !*pszSymbolName || + msGetSymbolIndex(&map->symbolset, pszSymbolName, MS_FALSE) < 0) { + msFree(pszSymbolName); + pszSymbolName = msStrdup("square"); + } + } + + /* check if the symbol should be filled or not */ + psFill = CPLGetXMLNode(psMark, "Fill"); + psStroke = CPLGetXMLNode(psMark, "Stroke"); + + if (psFill || psStroke) { + if (psFill) + bFilled = 1; + else + bFilled = 0; + + if (psFill) { + psCssParam = CPLGetXMLNode(psFill, "CssParameter"); + /*sld 1.1 used SvgParameter*/ + if (psCssParam == NULL) + psCssParam = CPLGetXMLNode(psFill, "SvgParameter"); + + while (psCssParam && psCssParam->pszValue && + (strcasecmp(psCssParam->pszValue, "CssParameter") == 0 || + strcasecmp(psCssParam->pszValue, "SvgParameter") == 0)) { + psName = (char *)CPLGetXMLValue(psCssParam, "name", NULL); + if (psName && strcasecmp(psName, "fill") == 0) { + if (psCssParam->psChild && psCssParam->psChild->psNext) { + msSLDParseOgcExpression(psCssParam->psChild->psNext, psStyle, + MS_STYLE_BINDING_COLOR, MS_OBJ_STYLE); + } + } else if (psName && strcasecmp(psName, "fill-opacity") == 0) { + if (psCssParam->psChild && psCssParam->psChild->psNext) { + psValue = psCssParam->psChild->psNext->pszValue; + if (psValue) { + psStyle->color.alpha = (int)(atof(psValue) * 255); + } + } + } + + psCssParam = psCssParam->psNext; + } + } + if (psStroke) { + psCssParam = CPLGetXMLNode(psStroke, "CssParameter"); + /*sld 1.1 used SvgParameter*/ + if (psCssParam == NULL) + psCssParam = CPLGetXMLNode(psStroke, "SvgParameter"); + + while (psCssParam && psCssParam->pszValue && + (strcasecmp(psCssParam->pszValue, "CssParameter") == 0 || + strcasecmp(psCssParam->pszValue, "SvgParameter") == 0)) { + psName = (char *)CPLGetXMLValue(psCssParam, "name", NULL); + if (psName && strcasecmp(psName, "stroke") == 0) { + if (psCssParam->psChild && psCssParam->psChild->psNext) { + if (bFilled) { + msSLDParseOgcExpression(psCssParam->psChild->psNext, psStyle, + MS_STYLE_BINDING_OUTLINECOLOR, + MS_OBJ_STYLE); + } else { + msSLDParseOgcExpression(psCssParam->psChild->psNext, psStyle, + MS_STYLE_BINDING_COLOR, MS_OBJ_STYLE); + } + } + } else if (psName && strcasecmp(psName, "stroke-opacity") == 0) { + if (psCssParam->psChild && psCssParam->psChild->psNext) { + psValue = psCssParam->psChild->psNext->pszValue; + if (psValue) { + if (bFilled) { + psStyle->outlinecolor.alpha = (int)(atof(psValue) * 255); + } else { + psStyle->color.alpha = (int)(atof(psValue) * 255); + } + } + } + } else if (psName && strcasecmp(psName, "stroke-width") == 0) { + if (psCssParam->psChild && psCssParam->psChild->psNext) { + msSLDParseOgcExpression(psCssParam->psChild->psNext, psStyle, + MS_STYLE_BINDING_WIDTH, MS_OBJ_STYLE); + } + } + + psCssParam = psCssParam->psNext; + } + } + } + /* set the default color if color is not not already set */ + if ((psStyle->color.red < 0 || psStyle->color.green == -1 || + psStyle->color.blue == -1) && + (psStyle->outlinecolor.red == -1 || + psStyle->outlinecolor.green == -1 || + psStyle->outlinecolor.blue == -1)) { + psStyle->color.red = 128; + psStyle->color.green = 128; + psStyle->color.blue = 128; + } + + /* Get the corresponding symbol id */ + psStyle->symbol = msSLDGetMarkSymbol(map, pszSymbolName, bFilled); + if (psStyle->symbol > 0 && psStyle->symbol < map->symbolset.numsymbols) + psStyle->symbolname = + msStrdup(map->symbolset.symbol[psStyle->symbol]->name); + + } else { + psExternalGraphic = CPLGetXMLNode(psGraphic, "ExternalGraphic"); + if (psExternalGraphic) + msSLDParseExternalGraphic(psExternalGraphic, psStyle, map); + } + msFree(pszSymbolName); + } + psGap = CPLGetXMLNode(psRoot, "Gap"); + if (psGap && psGap->psChild && psGap->psChild->pszValue) { + psStyle->gap = atof(psGap->psChild->pszValue); + } + psInitialGap = CPLGetXMLNode(psRoot, "InitialGap"); + if (psInitialGap && psInitialGap->psChild && + psInitialGap->psChild->pszValue) { + psStyle->initialgap = atof(psInitialGap->psChild->pszValue); + } + + return MS_SUCCESS; +} + +/************************************************************************/ +/* msSLDGetMarkSymbol */ +/* */ +/* Get a Mark symbol using the name. Mark symbols can be */ +/* square, circle, triangle, star, cross, x. */ +/* If the symbol does not exist add it to the symbol list. */ +/************************************************************************/ +int msSLDGetMarkSymbol(mapObj *map, char *pszSymbolName, int bFilled) { + int nSymbolId = 0; + symbolObj *psSymbol = NULL; + + if (!map || !pszSymbolName) + return 0; + + if (strcasecmp(pszSymbolName, "square") == 0) { + if (bFilled) + nSymbolId = msGetSymbolIndex(&map->symbolset, + SLD_MARK_SYMBOL_SQUARE_FILLED, MS_FALSE); + else + nSymbolId = + msGetSymbolIndex(&map->symbolset, SLD_MARK_SYMBOL_SQUARE, MS_FALSE); + } else if (strcasecmp(pszSymbolName, "circle") == 0) { + + if (bFilled) + nSymbolId = msGetSymbolIndex(&map->symbolset, + SLD_MARK_SYMBOL_CIRCLE_FILLED, MS_FALSE); + else + nSymbolId = + msGetSymbolIndex(&map->symbolset, SLD_MARK_SYMBOL_CIRCLE, MS_FALSE); + } else if (strcasecmp(pszSymbolName, "triangle") == 0) { + + if (bFilled) + nSymbolId = msGetSymbolIndex(&map->symbolset, + SLD_MARK_SYMBOL_TRIANGLE_FILLED, MS_FALSE); + else + nSymbolId = + msGetSymbolIndex(&map->symbolset, SLD_MARK_SYMBOL_TRIANGLE, MS_FALSE); + } else if (strcasecmp(pszSymbolName, "star") == 0) { + + if (bFilled) + nSymbolId = msGetSymbolIndex(&map->symbolset, SLD_MARK_SYMBOL_STAR_FILLED, + MS_FALSE); + else + nSymbolId = + msGetSymbolIndex(&map->symbolset, SLD_MARK_SYMBOL_STAR, MS_FALSE); + } else if (strcasecmp(pszSymbolName, "cross") == 0) { + + if (bFilled) + nSymbolId = msGetSymbolIndex(&map->symbolset, + SLD_MARK_SYMBOL_CROSS_FILLED, MS_FALSE); + else + nSymbolId = + msGetSymbolIndex(&map->symbolset, SLD_MARK_SYMBOL_CROSS, MS_FALSE); + } else if (strcasecmp(pszSymbolName, "x") == 0) { + + if (bFilled) + nSymbolId = + msGetSymbolIndex(&map->symbolset, SLD_MARK_SYMBOL_X_FILLED, MS_FALSE); + else + nSymbolId = + msGetSymbolIndex(&map->symbolset, SLD_MARK_SYMBOL_X, MS_FALSE); + } else { + nSymbolId = msGetSymbolIndex(&map->symbolset, pszSymbolName, MS_FALSE); + } + + if (nSymbolId <= 0) { + if ((psSymbol = msGrowSymbolSet(&(map->symbolset))) == NULL) + return 0; /* returns 0 for no symbol */ + + nSymbolId = map->symbolset.numsymbols; + map->symbolset.numsymbols++; + initSymbol(psSymbol); + psSymbol->inmapfile = MS_TRUE; + psSymbol->sizex = 1; + psSymbol->sizey = 1; + + if (strcasecmp(pszSymbolName, "square") == 0) { + if (bFilled) + psSymbol->name = msStrdup(SLD_MARK_SYMBOL_SQUARE_FILLED); + else + psSymbol->name = msStrdup(SLD_MARK_SYMBOL_SQUARE); + + psSymbol->type = MS_SYMBOL_VECTOR; + if (bFilled) + psSymbol->filled = MS_TRUE; + psSymbol->points[psSymbol->numpoints].x = 0; + psSymbol->points[psSymbol->numpoints].y = 1; + psSymbol->numpoints++; + psSymbol->points[psSymbol->numpoints].x = 0; + psSymbol->points[psSymbol->numpoints].y = 0; + psSymbol->numpoints++; + psSymbol->points[psSymbol->numpoints].x = 1; + psSymbol->points[psSymbol->numpoints].y = 0; + psSymbol->numpoints++; + psSymbol->points[psSymbol->numpoints].x = 1; + psSymbol->points[psSymbol->numpoints].y = 1; + psSymbol->numpoints++; + psSymbol->points[psSymbol->numpoints].x = 0; + psSymbol->points[psSymbol->numpoints].y = 1; + psSymbol->numpoints++; + } else if (strcasecmp(pszSymbolName, "circle") == 0) { + if (bFilled) + psSymbol->name = msStrdup(SLD_MARK_SYMBOL_CIRCLE_FILLED); + else + psSymbol->name = msStrdup(SLD_MARK_SYMBOL_CIRCLE); + + psSymbol->type = MS_SYMBOL_ELLIPSE; + if (bFilled) + psSymbol->filled = MS_TRUE; + + psSymbol->points[psSymbol->numpoints].x = 1; + psSymbol->points[psSymbol->numpoints].y = 1; + psSymbol->sizex = 1; + psSymbol->sizey = 1; + psSymbol->numpoints++; + } else if (strcasecmp(pszSymbolName, "triangle") == 0) { + if (bFilled) + psSymbol->name = msStrdup(SLD_MARK_SYMBOL_TRIANGLE_FILLED); + else + psSymbol->name = msStrdup(SLD_MARK_SYMBOL_TRIANGLE); + + psSymbol->type = MS_SYMBOL_VECTOR; + if (bFilled) + psSymbol->filled = MS_TRUE; + + psSymbol->points[psSymbol->numpoints].x = 0; + psSymbol->points[psSymbol->numpoints].y = 1; + psSymbol->numpoints++; + psSymbol->points[psSymbol->numpoints].x = 0.5; + psSymbol->points[psSymbol->numpoints].y = 0; + psSymbol->numpoints++; + psSymbol->points[psSymbol->numpoints].x = 1; + psSymbol->points[psSymbol->numpoints].y = 1; + psSymbol->numpoints++; + psSymbol->points[psSymbol->numpoints].x = 0; + psSymbol->points[psSymbol->numpoints].y = 1; + psSymbol->numpoints++; + + } else if (strcasecmp(pszSymbolName, "star") == 0) { + if (bFilled) + psSymbol->name = msStrdup(SLD_MARK_SYMBOL_STAR_FILLED); + else + psSymbol->name = msStrdup(SLD_MARK_SYMBOL_STAR); + + psSymbol->type = MS_SYMBOL_VECTOR; + if (bFilled) + psSymbol->filled = MS_TRUE; + + psSymbol->points[psSymbol->numpoints].x = 0; + psSymbol->points[psSymbol->numpoints].y = 0.375; + psSymbol->numpoints++; + psSymbol->points[psSymbol->numpoints].x = 0.35; + psSymbol->points[psSymbol->numpoints].y = 0.375; + psSymbol->numpoints++; + psSymbol->points[psSymbol->numpoints].x = 0.5; + psSymbol->points[psSymbol->numpoints].y = 0; + psSymbol->numpoints++; + psSymbol->points[psSymbol->numpoints].x = 0.65; + psSymbol->points[psSymbol->numpoints].y = 0.375; + psSymbol->numpoints++; + psSymbol->points[psSymbol->numpoints].x = 1; + psSymbol->points[psSymbol->numpoints].y = 0.375; + psSymbol->numpoints++; + psSymbol->points[psSymbol->numpoints].x = 0.75; + psSymbol->points[psSymbol->numpoints].y = 0.625; + psSymbol->numpoints++; + psSymbol->points[psSymbol->numpoints].x = 0.875; + psSymbol->points[psSymbol->numpoints].y = 1; + psSymbol->numpoints++; + psSymbol->points[psSymbol->numpoints].x = 0.5; + psSymbol->points[psSymbol->numpoints].y = 0.75; + psSymbol->numpoints++; + psSymbol->points[psSymbol->numpoints].x = 0.125; + psSymbol->points[psSymbol->numpoints].y = 1; + psSymbol->numpoints++; + psSymbol->points[psSymbol->numpoints].x = 0.25; + psSymbol->points[psSymbol->numpoints].y = 0.625; + psSymbol->numpoints++; + } + /* cross is like plus (+) since there is also X symbol ?? */ + else if (strcasecmp(pszSymbolName, "cross") == 0) { + /* NEVER FILL CROSS */ + /* if (bFilled) */ + /* psSymbol->name = msStrdup(SLD_MARK_SYMBOL_CROSS_FILLED); */ + /* else */ + psSymbol->name = msStrdup(SLD_MARK_SYMBOL_CROSS); + + psSymbol->type = MS_SYMBOL_VECTOR; + /* if (bFilled) */ + /* psSymbol->filled = MS_TRUE; */ + + psSymbol->points[psSymbol->numpoints].x = 0.5; + psSymbol->points[psSymbol->numpoints].y = 0; + psSymbol->numpoints++; + psSymbol->points[psSymbol->numpoints].x = 0.5; + psSymbol->points[psSymbol->numpoints].y = 1; + psSymbol->numpoints++; + psSymbol->points[psSymbol->numpoints].x = -99; + psSymbol->points[psSymbol->numpoints].y = -99; + psSymbol->numpoints++; + psSymbol->points[psSymbol->numpoints].x = 0; + psSymbol->points[psSymbol->numpoints].y = 0.5; + psSymbol->numpoints++; + psSymbol->points[psSymbol->numpoints].x = 1; + psSymbol->points[psSymbol->numpoints].y = 0.5; + psSymbol->numpoints++; + } else if (strcasecmp(pszSymbolName, "x") == 0) { + /* NEVER FILL X */ + /* if (bFilled) */ + /* psSymbol->name = msStrdup(SLD_MARK_SYMBOL_X_FILLED); */ + /* else */ + psSymbol->name = msStrdup(SLD_MARK_SYMBOL_X); + + psSymbol->type = MS_SYMBOL_VECTOR; + /* if (bFilled) */ + /* psSymbol->filled = MS_TRUE; */ + psSymbol->points[psSymbol->numpoints].x = 0; + psSymbol->points[psSymbol->numpoints].y = 0; + psSymbol->numpoints++; + psSymbol->points[psSymbol->numpoints].x = 1; + psSymbol->points[psSymbol->numpoints].y = 1; + psSymbol->numpoints++; + psSymbol->points[psSymbol->numpoints].x = -99; + psSymbol->points[psSymbol->numpoints].y = -99; + psSymbol->numpoints++; + psSymbol->points[psSymbol->numpoints].x = 0; + psSymbol->points[psSymbol->numpoints].y = 1; + psSymbol->numpoints++; + psSymbol->points[psSymbol->numpoints].x = 1; + psSymbol->points[psSymbol->numpoints].y = 0; + psSymbol->numpoints++; + } + } + + return nSymbolId; +} + +/************************************************************************/ +/* msSLDGetGraphicSymbol */ +/* */ +/* Create a symbol entry for an inmap pixmap symbol. Returns */ +/* the symbol id. */ +/************************************************************************/ +int msSLDGetGraphicSymbol(mapObj *map, char *pszFileName, char *extGraphicName, + int nGap_ignored) { + (void)nGap_ignored; + int nSymbolId = 0; + symbolObj *psSymbol = NULL; + + if (map && pszFileName) { + if ((psSymbol = msGrowSymbolSet(&(map->symbolset))) == NULL) + return 0; /* returns 0 for no symbol */ + nSymbolId = map->symbolset.numsymbols; + map->symbolset.numsymbols++; + initSymbol(psSymbol); + psSymbol->inmapfile = MS_TRUE; + psSymbol->type = MS_SYMBOL_PIXMAP; + psSymbol->name = msStrdup(extGraphicName); + psSymbol->imagepath = msStrdup(pszFileName); + psSymbol->full_pixmap_path = msStrdup(pszFileName); + } + return nSymbolId; +} + +/************************************************************************/ +/* msSLDParsePointSymbolizer */ +/* */ +/* Parse point symbolizer. */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/************************************************************************/ +int msSLDParsePointSymbolizer(CPLXMLNode *psRoot, layerObj *psLayer, + int bNewClass, const char *pszUserStyleName) { + int nClassId = 0; + int iStyle = 0; + + if (!psRoot || !psLayer) + return MS_FAILURE; + + nClassId = getClassId(psLayer, bNewClass, pszUserStyleName); + if (nClassId < 0) + return MS_FAILURE; + + // Get uom if any, defaults to MS_PIXELS + enum MS_UNITS sizeunits = MS_PIXELS; + if (msSLDParseUomAttribute(psRoot, &sizeunits) != MS_SUCCESS) { + msSetError(MS_WMSERR, "Invalid uom attribute value.", + "msSLDParsePolygonSymbolizer()"); + return MS_FAILURE; + } + + iStyle = psLayer->_class[nClassId]->numstyles; + msMaybeAllocateClassStyle(psLayer->_class[nClassId], iStyle); + psLayer->_class[nClassId]->styles[iStyle]->sizeunits = sizeunits; + + msSLDParseGraphicFillOrStroke( + psRoot, NULL, psLayer->_class[nClassId]->styles[iStyle], psLayer->map); + + return MS_SUCCESS; +} + +/************************************************************************/ +/* msSLDParseExternalGraphic */ +/* */ +/* Parse external graphic node : download the symbol referenced */ +/* by the URL and create a PIXMAP inmap symbol. Only GIF and */ +/* PNG are supported. */ +/************************************************************************/ +int msSLDParseExternalGraphic(CPLXMLNode *psExternalGraphic, styleObj *psStyle, + mapObj *map) { + char *pszFormat = NULL; + CPLXMLNode *psURL = NULL, *psFormat = NULL, *psTmp = NULL; + char *pszURL = NULL; + + if (!psExternalGraphic || !psStyle || !map) + return MS_FAILURE; + + psFormat = CPLGetXMLNode(psExternalGraphic, "Format"); + if (psFormat && psFormat->psChild && psFormat->psChild->pszValue) + pszFormat = psFormat->psChild->pszValue; + + /* supports GIF and PNG and SVG */ + if (pszFormat && (strcasecmp(pszFormat, "GIF") == 0 || + strcasecmp(pszFormat, "image/gif") == 0 || + strcasecmp(pszFormat, "PNG") == 0 || + strcasecmp(pszFormat, "image/png") == 0 || + strcasecmp(pszFormat, "image/svg+xml") == 0)) { + + /* + */ + psURL = CPLGetXMLNode(psExternalGraphic, "OnlineResource"); + if (psURL && psURL->psChild) { + psTmp = psURL->psChild; + while (psTmp != NULL && psTmp->pszValue && + strcasecmp(psTmp->pszValue, "xlink:href") != 0) { + psTmp = psTmp->psNext; + } + if (psTmp && psTmp->psChild) { + pszURL = (char *)psTmp->psChild->pszValue; + + char *symbolurl = NULL; + // Handle relative URL for ExternalGraphic + if (map->sldurl && !strstr(pszURL, "://")) { + char *baseurl = NULL; + char *relpath = NULL; + symbolurl = static_cast(malloc(sizeof(char) * MS_MAXPATHLEN)); + if (pszURL[0] != '/') { + // Symbol file is relative to SLD file + // e.g. SLD : http://example.com/path/to/sld.xml + // and symbol: assets/symbol.svg + // lead to: http://example.com/path/to/assets/symbol.svg + baseurl = msGetPath(map->sldurl); + relpath = pszURL; + } else { + // Symbol file is relative to the root of SLD server + // e.g. SLD : http://example.com/path/to/sld.xml + // and symbol: /path/to/assets/symbol.svg + // lead to: http://example.com/path/to/assets/symbol.svg + baseurl = msStrdup(map->sldurl); + relpath = pszURL + 1; + char *sep = strstr(baseurl, "://"); + if (sep) + sep += 3; + else + sep = baseurl; + sep = strchr(sep, '/'); + if (!sep) + sep = baseurl + strlen(baseurl); + sep[1] = '\0'; + } + msBuildPath(symbolurl, baseurl, relpath); + msFree(baseurl); + } else { + // Absolute URL + // e.g. symbol: http://example.com/path/to/assets/symbol.svg + symbolurl = msStrdup(pszURL); + } + + /* validate the ExternalGraphic parameter */ + if (msValidateParameter(symbolurl, + msLookupHashTable(&(map->web.validation), + "sld_external_graphic"), + NULL, NULL, NULL) != MS_SUCCESS) { + msSetError(MS_WEBERR, + "SLD ExternalGraphic OnlineResource value fails to " + "validate against sld_external_graphic VALIDATION", + "mapserv()"); + msFree(symbolurl); + return MS_FAILURE; + } + + /*external symbols using http will be automatically downloaded. The + file should be saved in a temporary directory (msAddImageSymbol) + #2305*/ + psStyle->symbol = msGetSymbolIndex(&map->symbolset, symbolurl, MS_TRUE); + msFree(symbolurl); + + if (psStyle->symbol > 0 && psStyle->symbol < map->symbolset.numsymbols) + psStyle->symbolname = + msStrdup(map->symbolset.symbol[psStyle->symbol]->name); + + /* set the color parameter if not set. Does not make sense */ + /* for pixmap but mapserver needs it. */ + if (psStyle->color.red == -1 || psStyle->color.green || + psStyle->color.blue) { + psStyle->color.red = 0; + psStyle->color.green = 0; + psStyle->color.blue = 0; + } + } + } + } + + return MS_SUCCESS; +} + +/************************************************************************/ +/* msSLDParseTextSymbolizer */ +/* */ +/* Parse text symbolizer. */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* Four types of CssParameter are allowed, font-family, font-style,*/ +/* fontweight,and font-size. */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* The coordinates are given as two floating-point numbers in */ +/* the AnchorPointX and AnchorPointY elements each with values */ +/* between 0.0 and 1.0 inclusive. The bounding box of the label */ +/* to be rendered is considered to be in a coorindate space */ +/* from 0.0 (lowerleft corner) to 1.0 (upper-right corner), and */ +/* the anchor position is specified as a point in this */ +/* space. The default point is X=0, Y=0.5, which is at the */ +/* middle height of the lefthand side of the label. */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/************************************************************************/ +int msSLDParseTextSymbolizer(CPLXMLNode *psRoot, layerObj *psLayer, + int bOtherSymboliser, + const char *pszUserStyleName) { + int nStyleId = 0, nClassId = 0; + + if (!psRoot || !psLayer) + return MS_FAILURE; + + if (!bOtherSymboliser) { + if (msGrowLayerClasses(psLayer) == NULL) + return MS_FAILURE; + initClass(psLayer->_class[psLayer->numclasses]); + nClassId = psLayer->numclasses; + if (pszUserStyleName) + psLayer->_class[nClassId]->group = msStrdup(pszUserStyleName); + psLayer->numclasses++; + msMaybeAllocateClassStyle(psLayer->_class[nClassId], 0); + nStyleId = 0; + } else { + nClassId = psLayer->numclasses - 1; + if (nClassId >= 0) /* should always be true */ + nStyleId = psLayer->_class[nClassId]->numstyles - 1; + } + + if (nStyleId >= 0 && nClassId >= 0) /* should always be true */ + msSLDParseTextParams(psRoot, psLayer, psLayer->_class[nClassId]); + + return MS_SUCCESS; +} + +/************************************************************************/ +/* msSLDParseRasterSymbolizer */ +/* */ +/* Supports the ColorMap parameter in a Raster Symbolizer. In */ +/* the ColorMap, only color and quantity are used here. */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* SLD 1.1 */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/************************************************************************/ +int msSLDParseRasterSymbolizer(CPLXMLNode *psRoot, layerObj *psLayer, + const char *pszUserStyleName) { + CPLXMLNode *psColorMap = NULL, *psColorEntry = NULL, *psOpacity = NULL; + char *pszColor = NULL, *pszQuantity = NULL; + char *pszPreviousColor = NULL, *pszPreviousQuality = NULL; + colorObj sColor; + char szExpression[100]; + double dfOpacity = 1.0; + char *pszLabel = NULL, *pszPreviousLabel = NULL; + char *pch = NULL, *pchPrevious = NULL; + + CPLXMLNode *psNode = NULL, *psCategorize = NULL; + char *pszTmp = NULL; + int nValues = 0, nThresholds = 0; + int i, nMaxValues = 100, nMaxThreshold = 100; + + if (!psRoot || !psLayer) + return MS_FAILURE; + + psOpacity = CPLGetXMLNode(psRoot, "Opacity"); + if (psOpacity) { + if (psOpacity->psChild && psOpacity->psChild->pszValue) + dfOpacity = atof(psOpacity->psChild->pszValue); + + /* values in sld goes from 0.0 (for transparent) to 1.0 (for full opacity); + */ + if (dfOpacity >= 0.0 && dfOpacity <= 1.0) + msSetLayerOpacity(psLayer, (int)(dfOpacity * 100)); + else { + msSetError(MS_WMSERR, + "Invalid opacity value. Values should be between 0.0 and 1.0", + "msSLDParseRasterSymbolizer()"); + return MS_FAILURE; + } + } + psColorMap = CPLGetXMLNode(psRoot, "ColorMap"); + if (psColorMap) { + psColorEntry = CPLGetXMLNode(psColorMap, "ColorMapEntry"); + + if (psColorEntry) { /*SLD 1.0*/ + while (psColorEntry && psColorEntry->pszValue && + strcasecmp(psColorEntry->pszValue, "ColorMapEntry") == 0) { + pszColor = (char *)CPLGetXMLValue(psColorEntry, "color", NULL); + pszQuantity = (char *)CPLGetXMLValue(psColorEntry, "quantity", NULL); + pszLabel = (char *)CPLGetXMLValue(psColorEntry, "label", NULL); + + if (pszColor && pszQuantity) { + if (pszPreviousColor && pszPreviousQuality) { + if (strlen(pszPreviousColor) == 7 && pszPreviousColor[0] == '#' && + strlen(pszColor) == 7 && pszColor[0] == '#') { + sColor.red = msHexToInt(pszPreviousColor + 1); + sColor.green = msHexToInt(pszPreviousColor + 3); + sColor.blue = msHexToInt(pszPreviousColor + 5); + + /* pszQuantity and pszPreviousQuality may be integer or float */ + pchPrevious = strchr(pszPreviousQuality, '.'); + pch = strchr(pszQuantity, '.'); + if (pchPrevious == NULL && pch == NULL) { + snprintf(szExpression, sizeof(szExpression), + "([pixel] >= %d AND [pixel] < %d)", + atoi(pszPreviousQuality), atoi(pszQuantity)); + } else if (pchPrevious != NULL && pch == NULL) { + snprintf(szExpression, sizeof(szExpression), + "([pixel] >= %f AND [pixel] < %d)", + atof(pszPreviousQuality), atoi(pszQuantity)); + } else if (pchPrevious == NULL && pch != NULL) { + snprintf(szExpression, sizeof(szExpression), + "([pixel] >= %d AND [pixel] < %f)", + atoi(pszPreviousQuality), atof(pszQuantity)); + } else { + snprintf(szExpression, sizeof(szExpression), + "([pixel] >= %f AND [pixel] < %f)", + atof(pszPreviousQuality), atof(pszQuantity)); + } + + if (msGrowLayerClasses(psLayer) == NULL) + return MS_FAILURE; + else { + initClass(psLayer->_class[psLayer->numclasses]); + psLayer->numclasses++; + const int nClassId = psLayer->numclasses - 1; + if (pszUserStyleName) + psLayer->_class[nClassId]->group = msStrdup(pszUserStyleName); + + /*set the class name using the label. If label not defined + set it with the quantity*/ + if (pszPreviousLabel) + psLayer->_class[nClassId]->name = msStrdup(pszPreviousLabel); + else + psLayer->_class[nClassId]->name = + msStrdup(pszPreviousQuality); + + msMaybeAllocateClassStyle(psLayer->_class[nClassId], 0); + + psLayer->_class[nClassId]->styles[0]->color.red = sColor.red; + psLayer->_class[nClassId]->styles[0]->color.green = + sColor.green; + psLayer->_class[nClassId]->styles[0]->color.blue = sColor.blue; + + if (!psLayer->classitem || + strcasecmp(psLayer->classitem, "[pixel]") != 0) { + free(psLayer->classitem); + psLayer->classitem = msStrdup("[pixel]"); + } + + msLoadExpressionString(&psLayer->_class[nClassId]->expression, + szExpression); + } + } else { + msSetError(MS_WMSERR, "Invalid ColorMap Entry.", + "msSLDParseRasterSymbolizer()"); + return MS_FAILURE; + } + } + + pszPreviousColor = pszColor; + pszPreviousQuality = pszQuantity; + pszPreviousLabel = pszLabel; + } + psColorEntry = psColorEntry->psNext; + } + /* do the last Color Map Entry */ + if (pszColor && pszQuantity) { + if (strlen(pszColor) == 7 && pszColor[0] == '#') { + sColor.red = msHexToInt(pszColor + 1); + sColor.green = msHexToInt(pszColor + 3); + sColor.blue = msHexToInt(pszColor + 5); + + /* pszQuantity may be integer or float */ + pch = strchr(pszQuantity, '.'); + if (pch == NULL) { + snprintf(szExpression, sizeof(szExpression), "([pixel] = %d)", + atoi(pszQuantity)); + } else { + snprintf(szExpression, sizeof(szExpression), "([pixel] = %f)", + atof(pszQuantity)); + } + + if (msGrowLayerClasses(psLayer) == NULL) + return MS_FAILURE; + else { + initClass(psLayer->_class[psLayer->numclasses]); + psLayer->numclasses++; + const int nClassId = psLayer->numclasses - 1; + if (pszUserStyleName) + psLayer->_class[nClassId]->group = msStrdup(pszUserStyleName); + + msMaybeAllocateClassStyle(psLayer->_class[nClassId], 0); + if (pszLabel) + psLayer->_class[nClassId]->name = msStrdup(pszLabel); + else + psLayer->_class[nClassId]->name = msStrdup(pszQuantity); + psLayer->_class[nClassId]->numstyles = 1; + psLayer->_class[nClassId]->styles[0]->color.red = sColor.red; + psLayer->_class[nClassId]->styles[0]->color.green = sColor.green; + psLayer->_class[nClassId]->styles[0]->color.blue = sColor.blue; + + if (!psLayer->classitem || + strcasecmp(psLayer->classitem, "[pixel]") != 0) { + free(psLayer->classitem); + psLayer->classitem = msStrdup("[pixel]"); + } + + msLoadExpressionString(&psLayer->_class[nClassId]->expression, + szExpression); + } + } + } + } else if ((psCategorize = CPLGetXMLNode(psColorMap, "Categorize"))) { + char **papszValues = (char **)msSmallMalloc(sizeof(char *) * nMaxValues); + char **papszThresholds = + (char **)msSmallMalloc(sizeof(char *) * nMaxThreshold); + psNode = CPLGetXMLNode(psCategorize, "Value"); + while (psNode && psNode->pszValue && psNode->psChild && + psNode->psChild->pszValue) + + { + if (strcasecmp(psNode->pszValue, "Value") == 0) { + papszValues[nValues] = psNode->psChild->pszValue; + nValues++; + if (nValues == nMaxValues) { + nMaxValues += 100; + papszValues = (char **)msSmallRealloc(papszValues, + sizeof(char *) * nMaxValues); + } + } else if (strcasecmp(psNode->pszValue, "Threshold") == 0) { + papszThresholds[nThresholds] = psNode->psChild->pszValue; + nThresholds++; + if (nThresholds == nMaxThreshold) { + nMaxThreshold += 100; + papszThresholds = (char **)msSmallRealloc( + papszThresholds, sizeof(char *) * nMaxThreshold); + } + } + psNode = psNode->psNext; + } + + if (nThresholds > 0 && nValues == nThresholds + 1) { + /*free existing classes*/ + for (i = 0; i < psLayer->numclasses; i++) { + if (psLayer->_class[i] != NULL) { + psLayer->_class[i]->layer = NULL; + if (freeClass(psLayer->_class[i]) == MS_SUCCESS) { + msFree(psLayer->_class[i]); + psLayer->_class[i] = NULL; + } + } + } + psLayer->numclasses = 0; + for (i = 0; i < nValues; i++) { + pszTmp = (papszValues[i]); + if (pszTmp && strlen(pszTmp) == 7 && pszTmp[0] == '#') { + sColor.red = msHexToInt(pszTmp + 1); + sColor.green = msHexToInt(pszTmp + 3); + sColor.blue = msHexToInt(pszTmp + 5); + if (i == 0) { + if (strchr(papszThresholds[i], '.')) + snprintf(szExpression, sizeof(szExpression), "([pixel] < %f)", + atof(papszThresholds[i])); + else + snprintf(szExpression, sizeof(szExpression), "([pixel] < %d)", + atoi(papszThresholds[i])); + + } else if (i < nValues - 1) { + if (strchr(papszThresholds[i], '.')) + snprintf(szExpression, sizeof(szExpression), + "([pixel] >= %f AND [pixel] < %f)", + atof(papszThresholds[i - 1]), + atof(papszThresholds[i])); + else + snprintf(szExpression, sizeof(szExpression), + "([pixel] >= %d AND [pixel] < %d)", + atoi(papszThresholds[i - 1]), + atoi(papszThresholds[i])); + } else { + if (strchr(papszThresholds[i - 1], '.')) + snprintf(szExpression, sizeof(szExpression), "([pixel] >= %f)", + atof(papszThresholds[i - 1])); + else + snprintf(szExpression, sizeof(szExpression), "([pixel] >= %d)", + atoi(papszThresholds[i - 1])); + } + if (msGrowLayerClasses(psLayer)) { + initClass(psLayer->_class[psLayer->numclasses]); + psLayer->numclasses++; + const int nClassId = psLayer->numclasses - 1; + if (pszUserStyleName) + psLayer->_class[nClassId]->group = msStrdup(pszUserStyleName); + msMaybeAllocateClassStyle(psLayer->_class[nClassId], 0); + psLayer->_class[nClassId]->numstyles = 1; + psLayer->_class[nClassId]->styles[0]->color.red = sColor.red; + psLayer->_class[nClassId]->styles[0]->color.green = sColor.green; + psLayer->_class[nClassId]->styles[0]->color.blue = sColor.blue; + if (psLayer->classitem && + strcasecmp(psLayer->classitem, "[pixel]") != 0) + free(psLayer->classitem); + psLayer->classitem = msStrdup("[pixel]"); + msLoadExpressionString(&psLayer->_class[nClassId]->expression, + szExpression); + } + } + } + } + msFree(papszValues); + msFree(papszThresholds); + + } else { + msSetError(MS_WMSERR, "Invalid SLD document. msSLDParseRaster", ""); + return MS_FAILURE; + } + } + + return MS_SUCCESS; +} +/************************************************************************/ +/* msSLDParseTextParams */ +/* */ +/* Parse text parameters like font, placement and color. */ +/************************************************************************/ +int msSLDParseTextParams(CPLXMLNode *psRoot, layerObj *psLayer, + classObj *psClass) { + char szFontName[100]; + + CPLXMLNode *psLabel = NULL, *psFont = NULL; + CPLXMLNode *psCssParam = NULL; + char *pszName = NULL, *pszFontFamily = NULL, *pszFontStyle = NULL; + char *pszFontWeight = NULL; + CPLXMLNode *psLabelPlacement = NULL, *psPointPlacement = NULL, + *psLinePlacement = NULL; + CPLXMLNode *psFill = NULL, *psHalo = NULL, *psHaloRadius = NULL, + *psHaloFill = NULL; + labelObj *psLabelObj = NULL; + szFontName[0] = '\0'; + + if (!psRoot || !psClass || !psLayer) + return MS_FAILURE; + + if (psClass->numlabels == 0) { + if (msGrowClassLabels(psClass) == NULL) + return (MS_FAILURE); + initLabel(psClass->labels[0]); + psClass->numlabels++; + } + psLabelObj = psClass->labels[0]; + + /*set the angle by default to auto. the angle can be + modified Label Placement #2806*/ + psLabelObj->anglemode = MS_AUTO; + + /* label */ + /* support literal expression and propertyname + - + - + + Bug 1857 */ + psLabel = CPLGetXMLNode(psRoot, "Label"); + if (psLabel) { + const char *sep = ""; + msStringBuffer *classtext = msStringBufferAlloc(); + msStringBufferAppend(classtext, "("); + for (CPLXMLNode *psTmpNode = psLabel->psChild; psTmpNode; + psTmpNode = psTmpNode->psNext) { + if (psTmpNode->eType == CXT_Text && psTmpNode->pszValue) { + msStringBufferAppend(classtext, sep); + msStringBufferAppend(classtext, "\""); + msStringBufferAppend(classtext, psTmpNode->pszValue); + msStringBufferAppend(classtext, "\""); + sep = "+"; + } else if (psTmpNode->eType == CXT_Element && + strcasecmp(psTmpNode->pszValue, "Literal") == 0 && + psTmpNode->psChild) { + msStringBufferAppend(classtext, sep); + msStringBufferAppend(classtext, "\""); + msStringBufferAppend(classtext, psTmpNode->psChild->pszValue); + msStringBufferAppend(classtext, "\""); + sep = "+"; + } else if (psTmpNode->eType == CXT_Element && + strcasecmp(psTmpNode->pszValue, "PropertyName") == 0 && + psTmpNode->psChild) { + msStringBufferAppend(classtext, sep); + msStringBufferAppend(classtext, "\"["); + msStringBufferAppend(classtext, psTmpNode->psChild->pszValue); + msStringBufferAppend(classtext, "]\""); + sep = "+"; + } else if (psTmpNode->eType == CXT_Element && + strcasecmp(psTmpNode->pszValue, "Function") == 0 && + psTmpNode->psChild) { + msStringBufferAppend(classtext, sep); + msStringBufferAppend(classtext, "tostring("); + + labelObj tempExpressionCollector; + initLabel(&tempExpressionCollector); + msSLDParseOgcExpression(psTmpNode, &tempExpressionCollector, + MS_LABEL_BINDING_SIZE, MS_OBJ_LABEL); + msStringBufferAppend( + classtext, + tempExpressionCollector.exprBindings[MS_LABEL_BINDING_SIZE].string); + freeLabel(&tempExpressionCollector); + + msStringBufferAppend(classtext, ",\"%g\")"); + sep = "+"; + } + } + msStringBufferAppend(classtext, ")"); + const char *expressionstring = msStringBufferGetString(classtext); + if (strlen(expressionstring) > 2) { + msLoadExpressionString(&psClass->text, (char *)expressionstring); + } + msStringBufferFree(classtext); + + { + /* font */ + psFont = CPLGetXMLNode(psRoot, "Font"); + if (psFont) { + psCssParam = CPLGetXMLNode(psFont, "CssParameter"); + /*sld 1.1 used SvgParameter*/ + if (psCssParam == NULL) + psCssParam = CPLGetXMLNode(psFont, "SvgParameter"); + + while (psCssParam && psCssParam->pszValue && + (strcasecmp(psCssParam->pszValue, "CssParameter") == 0 || + strcasecmp(psCssParam->pszValue, "SvgParameter") == 0)) { + pszName = (char *)CPLGetXMLValue(psCssParam, "name", NULL); + if (pszName) { + if (strcasecmp(pszName, "font-family") == 0) { + if (psCssParam->psChild && psCssParam->psChild->psNext && + psCssParam->psChild->psNext->pszValue) + pszFontFamily = psCssParam->psChild->psNext->pszValue; + } + /* normal, italic, oblique */ + else if (strcasecmp(pszName, "font-style") == 0) { + if (psCssParam->psChild && psCssParam->psChild->psNext && + psCssParam->psChild->psNext->pszValue) + pszFontStyle = psCssParam->psChild->psNext->pszValue; + } + /* normal or bold */ + else if (strcasecmp(pszName, "font-weight") == 0) { + if (psCssParam->psChild && psCssParam->psChild->psNext && + psCssParam->psChild->psNext->pszValue) + pszFontWeight = psCssParam->psChild->psNext->pszValue; + } + /* default is 10 pix */ + else if (strcasecmp(pszName, "font-size") == 0) { + if (psCssParam->psChild && psCssParam->psChild->psNext) { + msSLDParseOgcExpression(psCssParam->psChild->psNext, psLabelObj, + MS_LABEL_BINDING_SIZE, MS_OBJ_LABEL); + } + } + } + psCssParam = psCssParam->psNext; + } + } + + /* -------------------------------------------------------------------- */ + /* parse the label placement. */ + /* -------------------------------------------------------------------- */ + psLabelPlacement = CPLGetXMLNode(psRoot, "LabelPlacement"); + if (psLabelPlacement) { + psPointPlacement = CPLGetXMLNode(psLabelPlacement, "PointPlacement"); + psLinePlacement = CPLGetXMLNode(psLabelPlacement, "LinePlacement"); + if (psPointPlacement) + ParseTextPointPlacement(psPointPlacement, psClass); + if (psLinePlacement) + ParseTextLinePlacement(psLinePlacement, psClass); + } + + /* -------------------------------------------------------------------- */ + /* build the font name using the font font-family, font-style */ + /* and font-weight. The name building uses a - between these */ + /* parameters and the resulting name is compared to the list of */ + /* available fonts. If the name exists, it will be used else we */ + /* go to the bitmap fonts. */ + /* -------------------------------------------------------------------- */ + if (pszFontFamily) { + snprintf(szFontName, sizeof(szFontName), "%s", pszFontFamily); + if (pszFontWeight && strcasecmp(pszFontWeight, "normal") != 0) { + strlcat(szFontName, "-", sizeof(szFontName)); + strlcat(szFontName, pszFontWeight, sizeof(szFontName)); + } + if (pszFontStyle && strcasecmp(pszFontStyle, "normal") != 0) { + strlcat(szFontName, "-", sizeof(szFontName)); + strlcat(szFontName, pszFontStyle, sizeof(szFontName)); + } + + if ((msLookupHashTable(&(psLayer->map->fontset.fonts), szFontName) != + NULL)) { + psLabelObj->font = msStrdup(szFontName); + } + } + + /* -------------------------------------------------------------------- */ + /* parse the halo parameter. */ + /* -------------------------------------------------------------------- */ + psHalo = CPLGetXMLNode(psRoot, "Halo"); + if (psHalo) { + psHaloRadius = CPLGetXMLNode(psHalo, "Radius"); + if (psHaloRadius && psHaloRadius->psChild && + psHaloRadius->psChild->pszValue) + psLabelObj->outlinewidth = atoi(psHaloRadius->psChild->pszValue); + + psHaloFill = CPLGetXMLNode(psHalo, "Fill"); + if (psHaloFill) { + psCssParam = CPLGetXMLNode(psHaloFill, "CssParameter"); + /*sld 1.1 used SvgParameter*/ + if (psCssParam == NULL) + psCssParam = CPLGetXMLNode(psHaloFill, "SvgParameter"); + + while (psCssParam && psCssParam->pszValue && + (strcasecmp(psCssParam->pszValue, "CssParameter") == 0 || + strcasecmp(psCssParam->pszValue, "SvgParameter") == 0)) { + pszName = (char *)CPLGetXMLValue(psCssParam, "name", NULL); + if (pszName) { + if (strcasecmp(pszName, "fill") == 0) { + if (psCssParam->psChild && psCssParam->psChild->psNext) { + msSLDParseOgcExpression( + psCssParam->psChild->psNext, psLabelObj, + MS_LABEL_BINDING_OUTLINECOLOR, MS_OBJ_LABEL); + } + } + } + psCssParam = psCssParam->psNext; + } + } + } + /* -------------------------------------------------------------------- */ + /* Parse the color */ + /* -------------------------------------------------------------------- */ + psFill = CPLGetXMLNode(psRoot, "Fill"); + if (psFill) { + psCssParam = CPLGetXMLNode(psFill, "CssParameter"); + /*sld 1.1 used SvgParameter*/ + if (psCssParam == NULL) + psCssParam = CPLGetXMLNode(psFill, "SvgParameter"); + + while (psCssParam && psCssParam->pszValue && + (strcasecmp(psCssParam->pszValue, "CssParameter") == 0 || + strcasecmp(psCssParam->pszValue, "SvgParameter") == 0)) { + pszName = (char *)CPLGetXMLValue(psCssParam, "name", NULL); + if (pszName) { + if (strcasecmp(pszName, "fill") == 0) { + if (psCssParam->psChild && psCssParam->psChild->psNext) { + msSLDParseOgcExpression(psCssParam->psChild->psNext, psLabelObj, + MS_LABEL_BINDING_COLOR, MS_OBJ_LABEL); + } + } + } + psCssParam = psCssParam->psNext; + } + } + } + } + + return MS_SUCCESS; +} + +/************************************************************************/ +/* ParseTextPointPlacement */ +/* */ +/* point placement node for the text symbolizer. */ +/************************************************************************/ +int ParseTextPointPlacement(CPLXMLNode *psRoot, classObj *psClass) { + CPLXMLNode *psAnchor, *psAnchorX, *psAnchorY; + CPLXMLNode *psDisplacement, *psDisplacementX, *psDisplacementY; + CPLXMLNode *psRotation = NULL; + labelObj *psLabelObj = NULL; + + if (!psRoot || !psClass) + return MS_FAILURE; + if (psClass->numlabels == 0) { + if (msGrowClassLabels(psClass) == NULL) + return (MS_FAILURE); + initLabel(psClass->labels[0]); + psClass->numlabels++; + } + psLabelObj = psClass->labels[0]; + + /* init the label with the default position */ + psLabelObj->position = MS_CL; + + /* -------------------------------------------------------------------- */ + /* parse anchor point. see function msSLDParseTextSymbolizer */ + /* for documentation. */ + /* -------------------------------------------------------------------- */ + psAnchor = CPLGetXMLNode(psRoot, "AnchorPoint"); + if (psAnchor) { + psAnchorX = CPLGetXMLNode(psAnchor, "AnchorPointX"); + psAnchorY = CPLGetXMLNode(psAnchor, "AnchorPointY"); + /* psCssParam->psChild->psNext->pszValue) */ + if (psAnchorX && psAnchorX->psChild && psAnchorX->psChild->pszValue && + psAnchorY && psAnchorY->psChild && psAnchorY->psChild->pszValue) { + const double dfAnchorX = atof(psAnchorX->psChild->pszValue); + const double dfAnchorY = atof(psAnchorY->psChild->pszValue); + + if ((dfAnchorX == 0 || dfAnchorX == 0.5 || dfAnchorX == 1) && + (dfAnchorY == 0 || dfAnchorY == 0.5 || dfAnchorY == 1)) { + if (dfAnchorX == 0 && dfAnchorY == 0) + psLabelObj->position = MS_LL; + if (dfAnchorX == 0 && dfAnchorY == 0.5) + psLabelObj->position = MS_CL; + if (dfAnchorX == 0 && dfAnchorY == 1) + psLabelObj->position = MS_UL; + + if (dfAnchorX == 0.5 && dfAnchorY == 0) + psLabelObj->position = MS_LC; + if (dfAnchorX == 0.5 && dfAnchorY == 0.5) + psLabelObj->position = MS_CC; + if (dfAnchorX == 0.5 && dfAnchorY == 1) + psLabelObj->position = MS_UC; + + if (dfAnchorX == 1 && dfAnchorY == 0) + psLabelObj->position = MS_LR; + if (dfAnchorX == 1 && dfAnchorY == 0.5) + psLabelObj->position = MS_CR; + if (dfAnchorX == 1 && dfAnchorY == 1) + psLabelObj->position = MS_UR; + } + } + } + + /* -------------------------------------------------------------------- */ + /* Parse displacement */ + /* -------------------------------------------------------------------- */ + psDisplacement = CPLGetXMLNode(psRoot, "Displacement"); + if (psDisplacement) { + psDisplacementX = CPLGetXMLNode(psDisplacement, "DisplacementX"); + psDisplacementY = CPLGetXMLNode(psDisplacement, "DisplacementY"); + /* psCssParam->psChild->psNext->pszValue) */ + if (psDisplacementX && psDisplacementX->psChild && + psDisplacementX->psChild->pszValue && psDisplacementY && + psDisplacementY->psChild && psDisplacementY->psChild->pszValue) { + psLabelObj->offsetx = atoi(psDisplacementX->psChild->pszValue); + psLabelObj->offsety = atoi(psDisplacementY->psChild->pszValue); + } + } + + /* -------------------------------------------------------------------- */ + /* parse rotation. */ + /* -------------------------------------------------------------------- */ + psRotation = CPLGetXMLNode(psRoot, "Rotation"); + if (psRotation && psRotation->psChild) { + msSLDParseOgcExpression(psRotation->psChild, psLabelObj, + MS_LABEL_BINDING_ANGLE, MS_OBJ_LABEL); + } + + return MS_SUCCESS; +} + +/************************************************************************/ +/* ParseTextLinePlacement */ +/* */ +/* Lineplacement node fro the text symbolizer. */ +/************************************************************************/ +int ParseTextLinePlacement(CPLXMLNode *psRoot, classObj *psClass) { + CPLXMLNode *psOffset = NULL, *psAligned = NULL; + labelObj *psLabelObj = NULL; + + if (!psRoot || !psClass) + return MS_FAILURE; + + if (psClass->numlabels == 0) { + if (msGrowClassLabels(psClass) == NULL) + return (MS_FAILURE); + initLabel(psClass->labels[0]); + psClass->numlabels++; + } + psLabelObj = psClass->labels[0]; + + /*if there is a line placement, we will assume that the + best setting for mapserver would be for the text to follow + the line #2806*/ + psLabelObj->anglemode = MS_FOLLOW; + + /*sld 1.1.0 has a parameter IsAligned. default value is true*/ + psAligned = CPLGetXMLNode(psRoot, "IsAligned"); + if (psAligned && psAligned->psChild && psAligned->psChild->pszValue && + strcasecmp(psAligned->psChild->pszValue, "false") == 0) { + psLabelObj->anglemode = MS_NONE; + } + psOffset = CPLGetXMLNode(psRoot, "PerpendicularOffset"); + if (psOffset && psOffset->psChild && psOffset->psChild->pszValue) { + psLabelObj->offsetx = atoi(psOffset->psChild->pszValue); + psLabelObj->offsety = MS_LABEL_PERPENDICULAR_OFFSET; + + /*if there is a PerpendicularOffset, we will assume that the + best setting for mapserver would be to use angle=0 and the + the offset #2806*/ + /* since sld 1.1.0 introduces the IsAligned parameter, only + set the angles if the parameter is not set*/ + if (!psAligned) { + psLabelObj->anglemode = MS_NONE; + psLabelObj->offsety = psLabelObj->offsetx; + } + } + + return MS_SUCCESS; +} + +/************************************************************************/ +/* void msSLDSetColorObject(char *psHexColor, colorObj */ +/* *psColor) */ +/* */ +/* Utility function to extract rgb values from an hexadecimal */ +/* color string (format is : #aaff08) and set it in the color */ +/* object. */ +/************************************************************************/ +int msSLDSetColorObject(char *psHexColor, colorObj *psColor) { + if (psHexColor && psColor && strlen(psHexColor) == 7 && + psHexColor[0] == '#') { + + psColor->red = msHexToInt(psHexColor + 1); + psColor->green = msHexToInt(psHexColor + 3); + psColor->blue = msHexToInt(psHexColor + 5); + } + + return MS_SUCCESS; +} + +/* -------------------------------------------------------------------- */ +/* client sld support functions */ +/* -------------------------------------------------------------------- */ + +/************************************************************************/ +/* msSLDGenerateSLD(mapObj *map, int iLayer) */ +/* */ +/* Return an SLD document for all layers that are on or */ +/* default. The second argument should be set to -1 to generate */ +/* on all layers. Or set to the layer index to generate an SLD */ +/* for a specific layer. */ +/* */ +/* The caller should free the returned string. */ +/************************************************************************/ +char *msSLDGenerateSLD(mapObj *map, int iLayer, const char *pszVersion) { +#if defined(USE_WMS_SVR) || defined(USE_WFS_SVR) || defined(USE_WCS_SVR) || \ + defined(USE_SOS_SVR) + + char szTmp[500]; + int i = 0; + char *pszTmp = NULL; + char *pszSLD = NULL; + char *schemalocation = NULL; + int sld_version = OWS_VERSION_NOTSET; + + sld_version = msOWSParseVersionString(pszVersion); + + if (sld_version == OWS_VERSION_NOTSET || + (sld_version != OWS_1_0_0 && sld_version != OWS_1_1_0)) + sld_version = OWS_1_0_0; + + if (map) { + schemalocation = msEncodeHTMLEntities(msOWSGetSchemasLocation(map)); + if (sld_version == OWS_1_0_0) + snprintf(szTmp, sizeof(szTmp), + "\n", + schemalocation); + else + snprintf(szTmp, sizeof(szTmp), + "\n", + schemalocation); + + free(schemalocation); + + pszSLD = msStringConcatenate(pszSLD, szTmp); + if (iLayer < 0 || iLayer > map->numlayers - 1) { + for (i = 0; i < map->numlayers; i++) { + pszTmp = msSLDGenerateSLDLayer(GET_LAYER(map, i), sld_version); + if (pszTmp) { + pszSLD = msStringConcatenate(pszSLD, pszTmp); + free(pszTmp); + } + } + } else { + pszTmp = msSLDGenerateSLDLayer(GET_LAYER(map, iLayer), sld_version); + if (pszTmp) { + pszSLD = msStringConcatenate(pszSLD, pszTmp); + free(pszTmp); + } + } + snprintf(szTmp, sizeof(szTmp), "%s", "\n"); + pszSLD = msStringConcatenate(pszSLD, szTmp); + } + + return pszSLD; + +#else + msSetError(MS_MISCERR, "OWS support is not available.", + "msSLDGenerateSLDLayer()"); + return NULL; + +#endif +} + +/************************************************************************/ +/* msSLDGetGraphicSLD */ +/* */ +/* Get an SLD for a style containing a symbol (Mark or external). */ +/************************************************************************/ +char *msSLDGetGraphicSLD(styleObj *psStyle, layerObj *psLayer, + int bNeedMarkSybol, int nVersion) { +#if defined(USE_WMS_SVR) || defined(USE_WFS_SVR) || defined(USE_WCS_SVR) || \ + defined(USE_SOS_SVR) + + msStringBuffer *sldString = msStringBufferAlloc(); + int nSymbol = -1; + symbolObj *psSymbol = NULL; + char szTmp[512]; + char szFormat[4]; + int i = 0, nLength = 0; + int bColorAvailable = 0; + int bGenerateDefaultSymbol = 0; + char *pszSymbolName = NULL; + char sNameSpace[10]; + char sCssParam[30]; + + sCssParam[0] = '\0'; + if (nVersion > OWS_1_0_0) + strcpy(sCssParam, "se:SvgParameter"); + else + strcpy(sCssParam, "CssParameter"); + + sNameSpace[0] = '\0'; + if (nVersion > OWS_1_0_0) + strcpy(sNameSpace, "se:"); + + if (psStyle && psLayer && psLayer->map) { + nSymbol = -1; + if (psStyle->symbol > 0) + nSymbol = psStyle->symbol; + else if (psStyle->symbolname) + nSymbol = msGetSymbolIndex(&psLayer->map->symbolset, psStyle->symbolname, + MS_FALSE); + + bGenerateDefaultSymbol = 0; + + if (bNeedMarkSybol && + (nSymbol <= 0 || nSymbol >= psLayer->map->symbolset.numsymbols)) + bGenerateDefaultSymbol = 1; + + if (nSymbol > 0 && nSymbol < psLayer->map->symbolset.numsymbols) { + psSymbol = psLayer->map->symbolset.symbol[nSymbol]; + if (psSymbol->type == MS_SYMBOL_VECTOR || + psSymbol->type == MS_SYMBOL_ELLIPSE) { + /* Mark symbol */ + if (psSymbol->name) + + { + if (strcasecmp(psSymbol->name, "square") == 0 || + strcasecmp(psSymbol->name, "circle") == 0 || + strcasecmp(psSymbol->name, "triangle") == 0 || + strcasecmp(psSymbol->name, "star") == 0 || + strcasecmp(psSymbol->name, "cross") == 0 || + strcasecmp(psSymbol->name, "x") == 0) + pszSymbolName = msStrdup(psSymbol->name); + else if (strncasecmp(psSymbol->name, "sld_mark_symbol_square", 22) == + 0) + pszSymbolName = msStrdup("square"); + else if (strncasecmp(psSymbol->name, "sld_mark_symbol_triangle", + 24) == 0) + pszSymbolName = msStrdup("triangle"); + else if (strncasecmp(psSymbol->name, "sld_mark_symbol_circle", 22) == + 0) + pszSymbolName = msStrdup("circle"); + else if (strncasecmp(psSymbol->name, "sld_mark_symbol_star", 20) == 0) + pszSymbolName = msStrdup("star"); + else if (strncasecmp(psSymbol->name, "sld_mark_symbol_cross", 21) == + 0) + pszSymbolName = msStrdup("cross"); + else if (strncasecmp(psSymbol->name, "sld_mark_symbol_x", 17) == 0) + pszSymbolName = msStrdup("X"); + + if (pszSymbolName) { + colorObj sTmpFillColor = {128, 128, 128, 255}; + colorObj sTmpStrokeColor = {0, 0, 0, 255}; + int hasFillColor = 0; + int hasStrokeColor = 0; + + snprintf(szTmp, sizeof(szTmp), "<%sGraphic>\n", sNameSpace); + msStringBufferAppend(sldString, szTmp); + + snprintf(szTmp, sizeof(szTmp), "<%sMark>\n", sNameSpace); + msStringBufferAppend(sldString, szTmp); + + snprintf(szTmp, sizeof(szTmp), + "<%sWellKnownName>%s\n", sNameSpace, + pszSymbolName, sNameSpace); + msStringBufferAppend(sldString, szTmp); + + if (psStyle->color.red != -1 && psStyle->color.green != -1 && + psStyle->color.blue != -1) { + sTmpFillColor.red = psStyle->color.red; + sTmpFillColor.green = psStyle->color.green; + sTmpFillColor.blue = psStyle->color.blue; + sTmpFillColor.alpha = psStyle->color.alpha; + hasFillColor = 1; + } + if (psStyle->outlinecolor.red != -1 && + psStyle->outlinecolor.green != -1 && + psStyle->outlinecolor.blue != -1) { + sTmpStrokeColor.red = psStyle->outlinecolor.red; + sTmpStrokeColor.green = psStyle->outlinecolor.green; + sTmpStrokeColor.blue = psStyle->outlinecolor.blue; + sTmpStrokeColor.alpha = psStyle->outlinecolor.alpha; + hasStrokeColor = 1; + // Make defaults implicit + if (sTmpStrokeColor.red == 0 && sTmpStrokeColor.green == 0 && + sTmpStrokeColor.blue == 0 && sTmpStrokeColor.alpha == 255 && + psStyle->width == 1) { + hasStrokeColor = 0; + } + } + if (!hasFillColor && !hasStrokeColor) { + sTmpFillColor.red = 128; + sTmpFillColor.green = 128; + sTmpFillColor.blue = 128; + sTmpFillColor.alpha = 255; + hasFillColor = 1; + } + + if (hasFillColor) { + snprintf(szTmp, sizeof(szTmp), "<%sFill>\n", sNameSpace); + msStringBufferAppend(sldString, szTmp); + snprintf(szTmp, sizeof(szTmp), + "<%s name=\"fill\">#%02x%02x%02x\n", sCssParam, + sTmpFillColor.red, sTmpFillColor.green, + sTmpFillColor.blue, sCssParam); + msStringBufferAppend(sldString, szTmp); + if (sTmpFillColor.alpha != 255 && sTmpFillColor.alpha != -1) { + snprintf(szTmp, sizeof(szTmp), + "<%s name=\"fill-opacity\">%.2f\n", sCssParam, + (float)sTmpFillColor.alpha / 255.0, sCssParam); + msStringBufferAppend(sldString, szTmp); + } + snprintf(szTmp, sizeof(szTmp), "\n", sNameSpace); + msStringBufferAppend(sldString, szTmp); + } + if (hasStrokeColor) { + snprintf(szTmp, sizeof(szTmp), "<%sStroke>\n", sNameSpace); + msStringBufferAppend(sldString, szTmp); + snprintf(szTmp, sizeof(szTmp), + "<%s name=\"stroke\">#%02x%02x%02x\n", sCssParam, + sTmpStrokeColor.red, sTmpStrokeColor.green, + sTmpStrokeColor.blue, sCssParam); + msStringBufferAppend(sldString, szTmp); + if (psStyle->width > 0) { + snprintf(szTmp, sizeof(szTmp), + "<%s name=\"stroke-width\">%g\n", sCssParam, + psStyle->width, sCssParam); + msStringBufferAppend(sldString, szTmp); + } + if (sTmpStrokeColor.alpha != 255 && sTmpStrokeColor.alpha != -1) { + snprintf(szTmp, sizeof(szTmp), + "<%s name=\"stroke-opacity\">%.2f\n", sCssParam, + (float)sTmpStrokeColor.alpha / 255.0, sCssParam); + msStringBufferAppend(sldString, szTmp); + } + snprintf(szTmp, sizeof(szTmp), "\n", sNameSpace); + msStringBufferAppend(sldString, szTmp); + } + + snprintf(szTmp, sizeof(szTmp), "\n", sNameSpace); + msStringBufferAppend(sldString, szTmp); + + if (psStyle->size > 0) { + snprintf(szTmp, sizeof(szTmp), "<%sSize>%g\n", + sNameSpace, psStyle->size, sNameSpace); + msStringBufferAppend(sldString, szTmp); + } + + if (fmod(psStyle->angle, 360)) { + snprintf(szTmp, sizeof(szTmp), "<%sRotation>%g\n", + sNameSpace, psStyle->angle, sNameSpace); + msStringBufferAppend(sldString, szTmp); + } + // Style opacity is already reported to alpha channel of color and + // outlinecolor if (psStyle->opacity < 100) + // { + // snprintf(szTmp, sizeof(szTmp), "<%sOpacity>%g\n", + // sNameSpace, psStyle->opacity/100.0, sNameSpace); + // pszSLD = msStringConcatenate(pszSLD, szTmp); + // } + + if (psStyle->offsetx != 0 || psStyle->offsety != 0) { + snprintf(szTmp, sizeof(szTmp), "<%sDisplacement>\n", sNameSpace); + msStringBufferAppend(sldString, szTmp); + snprintf(szTmp, sizeof(szTmp), + "<%sDisplacementX>%g\n", sNameSpace, + psStyle->offsetx, sNameSpace); + msStringBufferAppend(sldString, szTmp); + snprintf(szTmp, sizeof(szTmp), + "<%sDisplacementY>%g\n", sNameSpace, + psStyle->offsety, sNameSpace); + msStringBufferAppend(sldString, szTmp); + snprintf(szTmp, sizeof(szTmp), "\n", sNameSpace); + msStringBufferAppend(sldString, szTmp); + } + + snprintf(szTmp, sizeof(szTmp), "\n", sNameSpace); + msStringBufferAppend(sldString, szTmp); + + if (pszSymbolName) + free(pszSymbolName); + } + } else + bGenerateDefaultSymbol = 1; + } else if (psSymbol->type == MS_SYMBOL_PIXMAP || + psSymbol->type == MS_SYMBOL_SVG) { + if (psSymbol->name) { + const char *pszURL = + msLookupHashTable(&(psLayer->metadata), "WMS_SLD_SYMBOL_URL"); + if (!pszURL) + pszURL = msLookupHashTable(&(psLayer->map->web.metadata), + "WMS_SLD_SYMBOL_URL"); + + if (pszURL) { + snprintf(szTmp, sizeof(szTmp), "<%sGraphic>\n", sNameSpace); + msStringBufferAppend(sldString, szTmp); + + snprintf(szTmp, sizeof(szTmp), "<%sExternalGraphic>\n", sNameSpace); + msStringBufferAppend(sldString, szTmp); + + snprintf(szTmp, sizeof(szTmp), + "<%sOnlineResource " + "xmlns:xlink=\"http://www.w3.org/1999/xlink\" " + "xlink:type=\"simple\" xlink:href=\"%s%s\"/>\n", + sNameSpace, pszURL, psSymbol->imagepath); + msStringBufferAppend(sldString, szTmp); + /* TODO : extract format from symbol */ + + szFormat[0] = '\0'; + nLength = strlen(psSymbol->imagepath); + if (nLength > 3) { + for (i = 0; i <= 2; i++) + szFormat[2 - i] = psSymbol->imagepath[nLength - 1 - i]; + szFormat[3] = '\0'; + } + if (strlen(szFormat) > 0 && ((strcasecmp(szFormat, "GIF") == 0) || + (strcasecmp(szFormat, "PNG") == 0))) { + if (strcasecmp(szFormat, "GIF") == 0) + snprintf(szTmp, sizeof(szTmp), + "<%sFormat>image/gif\n", sNameSpace, + sNameSpace); + else + snprintf(szTmp, sizeof(szTmp), + "<%sFormat>image/png\n", sNameSpace, + sNameSpace); + } else + snprintf(szTmp, sizeof(szTmp), "<%sFormat>%s\n", + sNameSpace, + (psSymbol->type == MS_SYMBOL_SVG) ? "image/svg+xml" + : "image/gif", + sNameSpace); + + msStringBufferAppend(sldString, szTmp); + + snprintf(szTmp, sizeof(szTmp), "\n", + sNameSpace); + msStringBufferAppend(sldString, szTmp); + + if (psStyle->size > 0) + snprintf(szTmp, sizeof(szTmp), "<%sSize>%g\n", + sNameSpace, psStyle->size, sNameSpace); + msStringBufferAppend(sldString, szTmp); + + snprintf(szTmp, sizeof(szTmp), "\n", sNameSpace); + msStringBufferAppend(sldString, szTmp); + } + } + } + } + if (bGenerateDefaultSymbol) { /* generate a default square symbol */ + snprintf(szTmp, sizeof(szTmp), "<%sGraphic>\n", sNameSpace); + msStringBufferAppend(sldString, szTmp); + + snprintf(szTmp, sizeof(szTmp), "<%sMark>\n", sNameSpace); + msStringBufferAppend(sldString, szTmp); + + snprintf(szTmp, sizeof(szTmp), "<%sWellKnownName>%s\n", + sNameSpace, "square", sNameSpace); + msStringBufferAppend(sldString, szTmp); + + bColorAvailable = 0; + if (psStyle->color.red != -1 && psStyle->color.green != -1 && + psStyle->color.blue != -1) { + snprintf(szTmp, sizeof(szTmp), "<%sFill>\n", sNameSpace); + msStringBufferAppend(sldString, szTmp); + snprintf(szTmp, sizeof(szTmp), "<%s name=\"fill\">#%02x%02x%02x\n", + sCssParam, psStyle->color.red, psStyle->color.green, + psStyle->color.blue, sCssParam); + msStringBufferAppend(sldString, szTmp); + snprintf(szTmp, sizeof(szTmp), "\n", sNameSpace); + msStringBufferAppend(sldString, szTmp); + bColorAvailable = 1; + } + if (psStyle->outlinecolor.red != -1 && + psStyle->outlinecolor.green != -1 && + psStyle->outlinecolor.blue != -1) { + snprintf(szTmp, sizeof(szTmp), "<%sStroke>\n", sNameSpace); + msStringBufferAppend(sldString, szTmp); + snprintf(szTmp, sizeof(szTmp), + "<%s name=\"Stroke\">#%02x%02x%02x\n", sCssParam, + psStyle->outlinecolor.red, psStyle->outlinecolor.green, + psStyle->outlinecolor.blue, sCssParam); + msStringBufferAppend(sldString, szTmp); + snprintf(szTmp, sizeof(szTmp), "\n", sNameSpace); + msStringBufferAppend(sldString, szTmp); + bColorAvailable = 1; + } + if (!bColorAvailable) { + /* default color */ + snprintf(szTmp, sizeof(szTmp), "<%sFill>\n", sNameSpace); + msStringBufferAppend(sldString, szTmp); + snprintf(szTmp, sizeof(szTmp), "<%s name=\"fill\">%s\n", sCssParam, + "#808080", sCssParam); + msStringBufferAppend(sldString, szTmp); + snprintf(szTmp, sizeof(szTmp), "\n", sNameSpace); + msStringBufferAppend(sldString, szTmp); + } + + snprintf(szTmp, sizeof(szTmp), "\n", sNameSpace); + msStringBufferAppend(sldString, szTmp); + + if (psStyle->size > 0) + snprintf(szTmp, sizeof(szTmp), "<%sSize>%g\n", sNameSpace, + psStyle->size, sNameSpace); + else + snprintf(szTmp, sizeof(szTmp), "<%sSize>%d\n", sNameSpace, 1, + sNameSpace); + msStringBufferAppend(sldString, szTmp); + + snprintf(szTmp, sizeof(szTmp), "\n", sNameSpace); + msStringBufferAppend(sldString, szTmp); + } + } + + return msStringBufferReleaseStringAndFree(sldString); + +#else + return NULL; + +#endif +} + +/************************************************************************/ +/* msSLDGenerateLineSLD */ +/* */ +/* Generate SLD for a Line layer. */ +/************************************************************************/ +char *msSLDGenerateLineSLD(styleObj *psStyle, layerObj *psLayer, int nVersion) { +#if defined(USE_WMS_SVR) || defined(USE_WFS_SVR) || defined(USE_WCS_SVR) || \ + defined(USE_SOS_SVR) + + char *pszSLD = NULL; + char szTmp[100]; + char szHexColor[7]; + int nSymbol = -1; + int i = 0; + double dfSize = 1.0; + char *pszDashArray = NULL; + char *pszGraphicSLD = NULL; + char sCssParam[30]; + char sNameSpace[10]; + + if (msCheckParentPointer(psLayer->map, "map") == MS_FAILURE) + return NULL; + + sCssParam[0] = '\0'; + if (nVersion > OWS_1_0_0) + strcpy(sCssParam, "se:SvgParameter"); + else + strcpy(sCssParam, "CssParameter"); + + sNameSpace[0] = '\0'; + if (nVersion > OWS_1_0_0) + strcpy(sNameSpace, "se:"); + + snprintf(szTmp, sizeof(szTmp), "<%sLineSymbolizer>\n", sNameSpace); + + pszSLD = msStringConcatenate(pszSLD, szTmp); + + snprintf(szTmp, sizeof(szTmp), "<%sStroke>\n", sNameSpace); + + pszSLD = msStringConcatenate(pszSLD, szTmp); + + pszGraphicSLD = msSLDGetGraphicSLD(psStyle, psLayer, 0, nVersion); + if (pszGraphicSLD) { + snprintf(szTmp, sizeof(szTmp), "<%sGraphicStroke>\n", sNameSpace); + + pszSLD = msStringConcatenate(pszSLD, szTmp); + + pszSLD = msStringConcatenate(pszSLD, pszGraphicSLD); + + if (nVersion >= OWS_1_1_0) { + if (psStyle->gap > 0) { + snprintf(szTmp, sizeof(szTmp), "<%sGap>%.2f\n", sNameSpace, + psStyle->gap, sNameSpace); + } + if (psStyle->initialgap > 0) { + snprintf(szTmp, sizeof(szTmp), "<%sInitialGap>%.2f\n", + sNameSpace, psStyle->initialgap, sNameSpace); + } + } + + snprintf(szTmp, sizeof(szTmp), "\n", sNameSpace); + + pszSLD = msStringConcatenate(pszSLD, szTmp); + + free(pszGraphicSLD); + pszGraphicSLD = NULL; + } + + if (psStyle->color.red != -1 && psStyle->color.green != -1 && + psStyle->color.blue != -1) + snprintf(szHexColor, sizeof(szHexColor), "%02x%02x%02x", psStyle->color.red, + psStyle->color.green, psStyle->color.blue); + else + snprintf(szHexColor, sizeof(szHexColor), "%02x%02x%02x", + psStyle->outlinecolor.red, psStyle->outlinecolor.green, + psStyle->outlinecolor.blue); + + snprintf(szTmp, sizeof(szTmp), "<%s name=\"stroke\">#%s\n", sCssParam, + szHexColor, sCssParam); + pszSLD = msStringConcatenate(pszSLD, szTmp); + + if (psStyle->color.alpha != 255 && psStyle->color.alpha != -1) { + snprintf(szTmp, sizeof(szTmp), "<%s name=\"stroke-opacity\">%.2f\n", + sCssParam, (float)psStyle->color.alpha / 255.0, sCssParam); + pszSLD = msStringConcatenate(pszSLD, szTmp); + } + + nSymbol = -1; + + if (psStyle->symbol >= 0) + nSymbol = psStyle->symbol; + else if (psStyle->symbolname) + nSymbol = msGetSymbolIndex(&psLayer->map->symbolset, psStyle->symbolname, + MS_FALSE); + + if (nSymbol < 0) + dfSize = 1.0; + else { + if (psStyle->size > 0) + dfSize = psStyle->size; + else if (psStyle->width > 0) + dfSize = psStyle->width; + else + dfSize = 1; + } + + snprintf(szTmp, sizeof(szTmp), "<%s name=\"stroke-width\">%.2f\n", + sCssParam, dfSize, sCssParam); + pszSLD = msStringConcatenate(pszSLD, szTmp); + + /* -------------------------------------------------------------------- */ + /* dash array */ + /* -------------------------------------------------------------------- */ + + if (psStyle->patternlength > 0) { + for (i = 0; i < psStyle->patternlength; i++) { + snprintf(szTmp, sizeof(szTmp), "%.2f ", psStyle->pattern[i]); + pszDashArray = msStringConcatenate(pszDashArray, szTmp); + } + // remove the final trailing space from the last pattern value + msStringTrimBlanks(pszDashArray); + + snprintf(szTmp, sizeof(szTmp), "<%s name=\"stroke-dasharray\">%s\n", + sCssParam, pszDashArray, sCssParam); + pszSLD = msStringConcatenate(pszSLD, szTmp); + msFree(pszDashArray); + } + + snprintf(szTmp, sizeof(szTmp), "\n", sNameSpace); + + pszSLD = msStringConcatenate(pszSLD, szTmp); + + snprintf(szTmp, sizeof(szTmp), "\n", sNameSpace); + + pszSLD = msStringConcatenate(pszSLD, szTmp); + + return pszSLD; + +#else + return NULL; +#endif +} + +/************************************************************************/ +/* msSLDGeneratePolygonSLD */ +/* */ +/* Generate SLD for a Polygon layer. */ +/************************************************************************/ +char *msSLDGeneratePolygonSLD(styleObj *psStyle, layerObj *psLayer, + int nVersion) { +#if defined(USE_WMS_SVR) || defined(USE_WFS_SVR) || defined(USE_WCS_SVR) || \ + defined(USE_SOS_SVR) + + char szTmp[100]; + char *pszSLD = NULL; + char szHexColor[7]; + double dfSize; + char sCssParam[30]; + char sNameSpace[10]; + + sCssParam[0] = '\0'; + if (nVersion > OWS_1_0_0) + strcpy(sCssParam, "se:SvgParameter"); + else + strcpy(sCssParam, "CssParameter"); + + sNameSpace[0] = '\0'; + if (nVersion > OWS_1_0_0) + strcpy(sNameSpace, "se:"); + + snprintf(szTmp, sizeof(szTmp), "<%sPolygonSymbolizer>\n", sNameSpace); + + pszSLD = msStringConcatenate(pszSLD, szTmp); + /* fill */ + if (psStyle->color.red != -1 && psStyle->color.green != -1 && + psStyle->color.blue != -1) { + + snprintf(szTmp, sizeof(szTmp), "<%sFill>\n", sNameSpace); + + pszSLD = msStringConcatenate(pszSLD, szTmp); + + char *pszGraphicSLD = msSLDGetGraphicSLD(psStyle, psLayer, 0, nVersion); + if (pszGraphicSLD) { + snprintf(szTmp, sizeof(szTmp), "<%sGraphicFill>\n", sNameSpace); + + pszSLD = msStringConcatenate(pszSLD, szTmp); + + pszSLD = msStringConcatenate(pszSLD, pszGraphicSLD); + + snprintf(szTmp, sizeof(szTmp), "\n", sNameSpace); + + pszSLD = msStringConcatenate(pszSLD, szTmp); + + free(pszGraphicSLD); + } + + snprintf(szHexColor, sizeof(szHexColor), "%02x%02x%02x", psStyle->color.red, + psStyle->color.green, psStyle->color.blue); + + snprintf(szTmp, sizeof(szTmp), "<%s name=\"fill\">#%s\n", sCssParam, + szHexColor, sCssParam); + pszSLD = msStringConcatenate(pszSLD, szTmp); + + if (psStyle->color.alpha != 255 && psStyle->color.alpha != -1) { + snprintf(szTmp, sizeof(szTmp), "<%s name=\"fill-opacity\">%.2f\n", + sCssParam, (float)psStyle->color.alpha / 255, sCssParam); + pszSLD = msStringConcatenate(pszSLD, szTmp); + } + + snprintf(szTmp, sizeof(szTmp), "\n", sNameSpace); + + pszSLD = msStringConcatenate(pszSLD, szTmp); + } + /* stroke */ + if (psStyle->outlinecolor.red != -1 && psStyle->outlinecolor.green != -1 && + psStyle->outlinecolor.blue != -1) { + snprintf(szTmp, sizeof(szTmp), "<%sStroke>\n", sNameSpace); + pszSLD = msStringConcatenate(pszSLD, szTmp); + + /* If there is a symbol to be used for stroke, the color in the */ + /* style should be set to -1. Else It won't apply here. */ + if (psStyle->color.red == -1 && psStyle->color.green == -1 && + psStyle->color.blue == -1) { + char *pszGraphicSLD = msSLDGetGraphicSLD(psStyle, psLayer, 0, nVersion); + if (pszGraphicSLD) { + snprintf(szTmp, sizeof(szTmp), "<%sGraphicFill>\n", sNameSpace); + pszSLD = msStringConcatenate(pszSLD, szTmp); + + pszSLD = msStringConcatenate(pszSLD, pszGraphicSLD); + snprintf(szTmp, sizeof(szTmp), "\n", sNameSpace); + pszSLD = msStringConcatenate(pszSLD, szTmp); + + free(pszGraphicSLD); + } + } + + snprintf(szHexColor, sizeof(szHexColor), "%02x%02x%02x", + psStyle->outlinecolor.red, psStyle->outlinecolor.green, + psStyle->outlinecolor.blue); + + snprintf(szTmp, sizeof(szTmp), "<%s name=\"stroke\">#%s\n", sCssParam, + szHexColor, sCssParam); + pszSLD = msStringConcatenate(pszSLD, szTmp); + + dfSize = 1.0; + if (psStyle->size > 0) + dfSize = psStyle->size; + else if (psStyle->width > 0) + dfSize = psStyle->width; + + snprintf(szTmp, sizeof(szTmp), "<%s name=\"stroke-width\">%.2f\n", + sCssParam, dfSize, sCssParam); + pszSLD = msStringConcatenate(pszSLD, szTmp); + + if (psStyle->outlinecolor.alpha != 255 && + psStyle->outlinecolor.alpha != -1) { + snprintf(szTmp, sizeof(szTmp), "<%s name=\"stroke-opacity\">%.2f\n", + sCssParam, psStyle->outlinecolor.alpha / 255.0, sCssParam); + pszSLD = msStringConcatenate(pszSLD, szTmp); + } + + snprintf(szTmp, sizeof(szTmp), "\n", sNameSpace); + pszSLD = msStringConcatenate(pszSLD, szTmp); + } + + snprintf(szTmp, sizeof(szTmp), "\n", sNameSpace); + pszSLD = msStringConcatenate(pszSLD, szTmp); + + return pszSLD; + +#else + return NULL; +#endif +} + +/************************************************************************/ +/* msSLDGeneratePointSLD */ +/* */ +/* Generate SLD for a Point layer. */ +/************************************************************************/ +char *msSLDGeneratePointSLD(styleObj *psStyle, layerObj *psLayer, + int nVersion) { +#if defined(USE_WMS_SVR) || defined(USE_WFS_SVR) || defined(USE_WCS_SVR) || \ + defined(USE_SOS_SVR) + char *pszSLD = NULL; + char *pszGraphicSLD = NULL; + char szTmp[100]; + char sNameSpace[10]; + + sNameSpace[0] = '\0'; + if (nVersion > OWS_1_0_0) + strcpy(sNameSpace, "se:"); + + snprintf(szTmp, sizeof(szTmp), "<%sPointSymbolizer>\n", sNameSpace); + pszSLD = msStringConcatenate(pszSLD, szTmp); + + pszGraphicSLD = msSLDGetGraphicSLD(psStyle, psLayer, 1, nVersion); + if (pszGraphicSLD) { + pszSLD = msStringConcatenate(pszSLD, pszGraphicSLD); + free(pszGraphicSLD); + } + + snprintf(szTmp, sizeof(szTmp), "\n", sNameSpace); + pszSLD = msStringConcatenate(pszSLD, szTmp); + + return pszSLD; + +#else + return NULL; + +#endif +} + +/************************************************************************/ +/* msSLDGenerateTextSLD */ +/* */ +/* Generate a TextSymboliser SLD xml based on the class's label */ +/* object. */ +/************************************************************************/ +char *msSLDGenerateTextSLD(classObj *psClass, layerObj *psLayer, int nVersion) { +#if defined(USE_WMS_SVR) || defined(USE_WFS_SVR) || defined(USE_WCS_SVR) || \ + defined(USE_SOS_SVR) + char *pszSLD = NULL; + + char szTmp[1000]; + char **aszFontsParts = NULL; + int nFontParts = 0; + char szHexColor[7]; + double dfAnchorX = 0.5, dfAnchorY = 0.5; + int i = 0; + int lid; + char sCssParam[30]; + char sNameSpace[10]; + labelObj *psLabelObj = NULL; + + sCssParam[0] = '\0'; + if (nVersion > OWS_1_0_0) + strcpy(sCssParam, "se:SvgParameter"); + else + strcpy(sCssParam, "CssParameter"); + + sNameSpace[0] = '\0'; + if (nVersion > OWS_1_0_0) + strcpy(sNameSpace, "se:"); + + if (!psLayer || !psClass) + return pszSLD; + + for (lid = 0; lid < psClass->numlabels; lid++) { + char *psLabelText; + expressionObj psLabelExpr; + parseObj p; + + msInitExpression(&psLabelExpr); + psLabelObj = psClass->labels[lid]; + + if (psLabelObj->text.string) { + psLabelExpr.string = msStrdup(psLabelObj->text.string); + psLabelExpr.type = psLabelObj->text.type; + } else if (psClass->text.string) { + psLabelExpr.string = msStrdup(psClass->text.string); + psLabelExpr.type = psClass->text.type; + } else if (psLayer->labelitem) { + psLabelExpr.string = msStrdup(psLayer->labelitem); + psLabelExpr.type = MS_STRING; + } else { + msFreeExpression(&psLabelExpr); + continue; // Can't find text content for this